From 74748f5a4760a4f414d2f1d6c751e43c128b2693 Mon Sep 17 00:00:00 2001 From: Andrew Savva Date: Sat, 8 Mar 2025 18:23:34 +0000 Subject: [PATCH 01/10] Add Mac Catalyst support --- Makefile | 69 +- patch/Python/Python.patch | 169793 ++++++++++++++++++++++++++- patch/Python/diff.exclude | 2 + patch/Python/sitecustomize.iOS.py | 6 +- 4 files changed, 168726 insertions(+), 1144 deletions(-) diff --git a/Makefile b/Makefile index 720461ea..5be15449 100644 --- a/Makefile +++ b/Makefile @@ -23,27 +23,28 @@ PYTHON_PKG_VERSION=$(PYTHON_VERSION) PYTHON_MICRO_VERSION=$(shell echo $(PYTHON_VERSION) | grep -Eo "\d+\.\d+\.\d+") PYTHON_PKG_MICRO_VERSION=$(shell echo $(PYTHON_PKG_VERSION) | grep -Eo "\d+\.\d+\.\d+") PYTHON_VER=$(basename $(PYTHON_VERSION)) +PYTHON_PATCHED_VERSION=$(PYTHON_VER)-patched # The binary releases of dependencies, published at: # https://github.com/beeware/cpython-apple-source-deps/releases BZIP2_VERSION=1.0.8-1 -LIBFFI_VERSION=3.4.6-1 +LIBFFI_VERSION=3.4.7-1 MPDECIMAL_VERSION=4.0.0-1 -OPENSSL_VERSION=3.0.15-1 -XZ_VERSION=5.6.2-1 +OPENSSL_VERSION=3.0.16-1 +XZ_VERSION=5.6.4-1 # Supported OS OS_LIST=macOS iOS tvOS watchOS -CURL_FLAGS=--disable --fail --location --create-dirs --progress-bar +CURL_FLAGS=--disable --fail --location --create-dirs --progress-bar -L # macOS targets TARGETS-macOS=macosx.x86_64 macosx.arm64 VERSION_MIN-macOS=11.0 # iOS targets -TARGETS-iOS=iphonesimulator.x86_64 iphonesimulator.arm64 iphoneos.arm64 -VERSION_MIN-iOS=13.0 +TARGETS-iOS=iphonesimulator.x86_64 iphonesimulator.arm64 iphoneos.arm64 maccatalyst.x86_64 maccatalyst.arm64 +VERSION_MIN-iOS=14.2 # tvOS targets TARGETS-tvOS=appletvsimulator.x86_64 appletvsimulator.arm64 appletvos.arm64 @@ -86,7 +87,7 @@ update-patch: # call if [ -z "$(PYTHON_REPO_DIR)" ]; then echo "\n\nPYTHON_REPO_DIR must be set to the root of your Python github checkout\n\n"; fi cd $(PYTHON_REPO_DIR) && \ - git diff -D v$(PYTHON_VERSION) $(PYTHON_VER)-patched \ + git diff -D v$(PYTHON_VERSION) $(PYTHON_PATCHED_VERSION) \ | PATH="/usr/local/bin:/opt/homebrew/bin:$(PATH)" filterdiff \ -X $(PROJECT_DIR)/patch/Python/diff.exclude -p 1 --clean \ > $(PROJECT_DIR)/patch/Python/Python.patch @@ -117,26 +118,44 @@ downloads/python-$(PYTHON_PKG_VERSION)-macos11.pkg: # ########################################################################### define build-target + target=$1 os=$2 OS_LOWER-$(target)=$(shell echo $(os) | tr '[:upper:]' '[:lower:]') # $(target) can be broken up into is composed of $(SDK).$(ARCH) -SDK-$(target)=$$(basename $(target)) +SDK-$(target)=$$(subst maccatalyst,macosx,$$(basename $(target))) ARCH-$(target)=$$(subst .,,$$(suffix $(target))) ifneq ($(os),macOS) - ifeq ($$(findstring simulator,$$(SDK-$(target))),) -TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-$$(OS_LOWER-$(target))$$(VERSION_MIN-$(os)) -IS_SIMULATOR-$(target)="False" - else + ifneq ($$(findstring simulator,$$(SDK-$(target))),) TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-$$(OS_LOWER-$(target))$$(VERSION_MIN-$(os))-simulator IS_SIMULATOR-$(target)="True" +TARGET_ABI-$(target)="" +TARGET_TRIPLE_SUFFIX-$(target)="" + else ifneq ($$(findstring maccatalyst,$$(target)),) +TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-ios$$(VERSION_MIN-$(os))-macabi +IS_SIMULATOR-$(target)="False" +TARGET_ABI-$(target)="macabi" +TARGET_TRIPLE_SUFFIX-$(target)="-macabi" + else +TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-$$(OS_LOWER-$(target))$$(VERSION_MIN-$(os)) +IS_SIMULATOR-$(target)="False" +TARGET_ABI-$(target)="" +TARGET_TRIPLE_SUFFIX-$(target)="" endif endif SDK_ROOT-$(target)=$$(shell xcrun --sdk $$(SDK-$(target)) --show-sdk-path) +CC-$(target)=$$(subst $$(VERSION_MIN-$(os)),,$$(TARGET_TRIPLE-$(target))-clang) +CXX-$(target)=$$(subst $$(VERSION_MIN-$(os)),,$$(TARGET_TRIPLE-$(target))-clang++) +CFLAGS-$(target)=\ + --sysroot=$$(SDK_ROOT-$(target)) \ + $$(CFLAGS-$(os)) +LDFLAGS-$(target)=\ + -isysroot $$(SDK_ROOT-$(target)) \ + $$(CFLAGS-$(os)) ########################################################################### # Target: BZip2 @@ -283,8 +302,13 @@ $$(PYTHON_SRCDIR-$(target))/Makefile: \ $$(PYTHON_SRCDIR-$(target))/configure # Configure target Python cd $$(PYTHON_SRCDIR-$(target)) && \ - PATH="$(PROJECT_DIR)/$$(PYTHON_SRCDIR-$(target))/$(os)/Resources/bin:$(PATH)" \ + PATH="$(PROJECT_DIR)/support/$(PYTHON_VER)/$(os)/Tools:$(PROJECT_DIR)/$$(PYTHON_SRCDIR-$(target))/$(os)/Resources/bin:$(PATH)" \ ./configure \ + CC="$$(CC-$(target))" \ + CXX="$$(CXX-$(target))" \ + CPP="$$(CXX-$(target)) -E" \ + CFLAGS="$$(CFLAGS-$(target))" \ + LDFLAGS="$$(LDFLAGS-$(target))" \ LIBLZMA_CFLAGS="-I$$(XZ_INSTALL-$(target))/include" \ LIBLZMA_LIBS="-L$$(XZ_INSTALL-$(target))/lib -llzma" \ BZIP2_CFLAGS="-I$$(BZIP2_INSTALL-$(target))/include" \ @@ -305,14 +329,14 @@ $$(PYTHON_SRCDIR-$(target))/Makefile: \ $$(PYTHON_SRCDIR-$(target))/python.exe: $$(PYTHON_SRCDIR-$(target))/Makefile @echo ">>> Build Python for $(target)" cd $$(PYTHON_SRCDIR-$(target)) && \ - PATH="$(PROJECT_DIR)/$$(PYTHON_SRCDIR-$(target))/$(os)/Resources/bin:$(PATH)" \ + PATH="$(PROJECT_DIR)/support/$(PYTHON_VER)/$(os)/Tools:$(PROJECT_DIR)/$$(PYTHON_SRCDIR-$(target))/$(os)/Resources/bin:$(PATH)" \ make -j8 all \ 2>&1 | tee -a ../python-$(PYTHON_VERSION).build.log $$(PYTHON_LIB-$(target)): $$(PYTHON_SRCDIR-$(target))/python.exe @echo ">>> Install Python for $(target)" cd $$(PYTHON_SRCDIR-$(target)) && \ - PATH="$(PROJECT_DIR)/$$(PYTHON_SRCDIR-$(target))/$(os)/Resources/bin:$(PATH)" \ + PATH="$(PROJECT_DIR)/support/$(PYTHON_VER)/$(os)/Tools:$(PROJECT_DIR)/$$(PYTHON_SRCDIR-$(target))/$(os)/Resources/bin:$(PATH)" \ make install \ 2>&1 | tee -a ../python-$(PYTHON_VERSION).install.log @@ -331,12 +355,14 @@ $$(PYTHON_SITECUSTOMIZE-$(target)): | sed -e "s/{{arch}}/$$(ARCH-$(target))/g" \ | sed -e "s/{{version_min}}/$$(VERSION_MIN-$(os))/g" \ | sed -e "s/{{is_simulator}}/$$(IS_SIMULATOR-$(target))/g" \ - | sed -e "s/{{multiarch}}/$$(ARCH-$(target))-$$(SDK-$(target))/g" \ - | sed -e "s/{{tag}}/$$(OS_LOWER-$(target))-$$(VERSION_MIN-$(os))-$$(ARCH-$(target))-$$(SDK-$(target))/g" \ + | sed -e "s/{{abi}}/$$(TARGET_ABI-$(target))/g" \ + | sed -e "s/{{multiarch}}/$$(ARCH-$(target))-$$(subst macosx,iphoneos,$$(SDK-$(target)))$$(TARGET_TRIPLE_SUFFIX-$(target))/g" \ + | sed -e "s/{{tag}}/$$(OS_LOWER-$(target))-$$(VERSION_MIN-$(os))-$$(ARCH-$(target))-$$(subst macosx,iphoneos-macabi,$$(SDK-$(target)))/g" \ > $$(PYTHON_SITECUSTOMIZE-$(target)) $(target): $$(PYTHON_SITECUSTOMIZE-$(target)) $$(PYTHON_LIB-$(target)) + ########################################################################### # Target: Debug ########################################################################### @@ -386,10 +412,13 @@ OS_LOWER-$(sdk)=$(shell echo $(os) | tr '[:upper:]' '[:lower:]') SDK_TARGETS-$(sdk)=$$(filter $(sdk).%,$$(TARGETS-$(os))) SDK_ARCHES-$(sdk)=$$(sort $$(subst .,,$$(suffix $$(SDK_TARGETS-$(sdk))))) -ifeq ($$(findstring simulator,$(sdk)),) -SDK_SLICE-$(sdk)=$$(OS_LOWER-$(sdk))-$$(shell echo $$(SDK_ARCHES-$(sdk)) | sed "s/ /_/g") -else +ifneq ($$(findstring simulator,$(sdk)),) SDK_SLICE-$(sdk)=$$(OS_LOWER-$(sdk))-$$(shell echo $$(SDK_ARCHES-$(sdk)) | sed "s/ /_/g")-simulator +else ifneq ($$(findstring maccatalyst,$(sdk)),) +SDK_SLICE-$(sdk)=ios-$$(shell echo $$(SDK_ARCHES-$(sdk)) | sed "s/ /_/g")-maccatalyst +sdk=macosx +else +SDK_SLICE-$(sdk)=$$(OS_LOWER-$(sdk))-$$(shell echo $$(SDK_ARCHES-$(sdk)) | sed "s/ /_/g") endif # Expand the build-target macro for target on this OS diff --git a/patch/Python/Python.patch b/patch/Python/Python.patch index 19768c8e..14d6134f 100644 --- a/patch/Python/Python.patch +++ b/patch/Python/Python.patch @@ -1,1238 +1,166886 @@ -diff --git a/Lib/platform.py b/Lib/platform.py -index 1f6baed66d3..235dd98c60a 100644 ---- a/Lib/platform.py -+++ b/Lib/platform.py -@@ -521,6 +521,54 @@ - return IOSVersionInfo(system, release, model, is_simulator) +diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml +index 107f3b25573..fb44c27704d 100644 +--- a/.pre-commit-config.yaml ++++ b/.pre-commit-config.yaml +@@ -1,6 +1,6 @@ + repos: + - repo: https://github.com/astral-sh/ruff-pre-commit +- rev: v0.8.2 ++ rev: v0.9.1 + hooks: + - id: ruff + name: Run Ruff (lint) on Doc/ +@@ -29,12 +29,10 @@ + - id: black + name: Run Black on Tools/build/check_warnings.py + files: ^Tools/build/check_warnings.py +- language_version: python3.12 + args: [--line-length=79] + - id: black + name: Run Black on Tools/jit/ + files: ^Tools/jit/ +- language_version: python3.12 + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 +@@ -51,18 +49,19 @@ + types_or: [c, inc, python, rst] -+# A namedtuple for tvOS version information. -+TVOSVersionInfo = collections.namedtuple( -+ "TVOSVersionInfo", -+ ["system", "release", "model", "is_simulator"] -+) + - repo: https://github.com/python-jsonschema/check-jsonschema +- rev: 0.30.0 ++ rev: 0.31.0 + hooks: + - id: check-dependabot + - id: check-github-workflows ++ - id: check-readthedocs + + - repo: https://github.com/rhysd/actionlint +- rev: v1.7.4 ++ rev: v1.7.7 + hooks: + - id: actionlint + + - repo: https://github.com/woodruffw/zizmor-pre-commit +- rev: v0.8.0 ++ rev: v1.1.1 + hooks: + - id: zizmor + +diff --git a/Android/android-env.sh b/Android/android-env.sh +index a0f23ef8c9f..bab4130c9e9 100644 +--- a/Android/android-env.sh ++++ b/Android/android-env.sh +@@ -1,10 +1,10 @@ + # This script must be sourced with the following variables already set: +-: ${ANDROID_HOME:?} # Path to Android SDK +-: ${HOST:?} # GNU target triplet ++: "${ANDROID_HOME:?}" # Path to Android SDK ++: "${HOST:?}" # GNU target triplet + + # You may also override the following: +-: ${api_level:=24} # Minimum Android API level the build will run on +-: ${PREFIX:-} # Path in which to find required libraries ++: "${api_level:=24}" # Minimum Android API level the build will run on ++: "${PREFIX:-}" # Path in which to find required libraries + + + # Print all messages on stderr so they're visible when running within build-wheel. +@@ -27,20 +27,20 @@ + ndk_version=27.1.12297006 + + ndk=$ANDROID_HOME/ndk/$ndk_version +-if ! [ -e $ndk ]; then ++if ! [ -e "$ndk" ]; then + log "Installing NDK - this may take several minutes" +- yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager "ndk;$ndk_version" ++ yes | "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" "ndk;$ndk_version" + fi + +-if [ $HOST = "arm-linux-androideabi" ]; then ++if [ "$HOST" = "arm-linux-androideabi" ]; then + clang_triplet=armv7a-linux-androideabi + else +- clang_triplet=$HOST ++ clang_triplet="$HOST" + fi + + # These variables are based on BuildSystemMaintainers.md above, and + # $ndk/build/cmake/android.toolchain.cmake. +-toolchain=$(echo $ndk/toolchains/llvm/prebuilt/*) ++toolchain=$(echo "$ndk"/toolchains/llvm/prebuilt/*) + export AR="$toolchain/bin/llvm-ar" + export AS="$toolchain/bin/llvm-as" + export CC="$toolchain/bin/${clang_triplet}${api_level}-clang" +@@ -72,12 +72,12 @@ + + # -mstackrealign is included where necessary in the clang launcher scripts which are + # pointed to by $CC, so we don't need to include it here. +-if [ $HOST = "arm-linux-androideabi" ]; then ++if [ "$HOST" = "arm-linux-androideabi" ]; then + CFLAGS="$CFLAGS -march=armv7-a -mthumb" + fi + + if [ -n "${PREFIX:-}" ]; then +- abs_prefix=$(realpath $PREFIX) ++ abs_prefix="$(realpath "$PREFIX")" + CFLAGS="$CFLAGS -I$abs_prefix/include" + LDFLAGS="$LDFLAGS -L$abs_prefix/lib" + +@@ -87,11 +87,13 @@ + + # When compiling C++, some build systems will combine CFLAGS and CXXFLAGS, and some will + # use CXXFLAGS alone. +-export CXXFLAGS=$CFLAGS ++export CXXFLAGS="$CFLAGS" + + # Use the same variable name as conda-build +-if [ $(uname) = "Darwin" ]; then +- export CPU_COUNT=$(sysctl -n hw.ncpu) ++if [ "$(uname)" = "Darwin" ]; then ++ CPU_COUNT="$(sysctl -n hw.ncpu)" ++ export CPU_COUNT + else +- export CPU_COUNT=$(nproc) ++ CPU_COUNT="$(nproc)" ++ export CPU_COUNT + fi +diff --git a/Include/abstract.h b/Include/abstract.h +index 7cfee1332cc..4efe4fcb014 100644 +--- a/Include/abstract.h ++++ b/Include/abstract.h +@@ -726,31 +726,6 @@ + This is equivalent to the Python expression: list(o) */ + PyAPI_FUNC(PyObject *) PySequence_List(PyObject *o); + +-/* Return the sequence 'o' as a list, unless it's already a tuple or list. +- +- Use PySequence_Fast_GET_ITEM to access the members of this list, and +- PySequence_Fast_GET_SIZE to get its length. +- +- Returns NULL on failure. If the object does not support iteration, raises a +- TypeError exception with 'm' as the message text. */ +-PyAPI_FUNC(PyObject *) PySequence_Fast(PyObject *o, const char* m); +- +-/* Return the size of the sequence 'o', assuming that 'o' was returned by +- PySequence_Fast and is not NULL. */ +-#define PySequence_Fast_GET_SIZE(o) \ +- (PyList_Check(o) ? PyList_GET_SIZE(o) : PyTuple_GET_SIZE(o)) +- +-/* Return the 'i'-th element of the sequence 'o', assuming that o was returned +- by PySequence_Fast, and that i is within bounds. */ +-#define PySequence_Fast_GET_ITEM(o, i)\ +- (PyList_Check(o) ? PyList_GET_ITEM((o), (i)) : PyTuple_GET_ITEM((o), (i))) +- +-/* Return a pointer to the underlying item array for +- an object returned by PySequence_Fast */ +-#define PySequence_Fast_ITEMS(sf) \ +- (PyList_Check(sf) ? ((PyListObject *)(sf))->ob_item \ +- : ((PyTupleObject *)(sf))->ob_item) +- + /* Return the number of occurrences on value on 'o', that is, return + the number of keys for which o[key] == value. + +diff --git a/Include/cpython/abstract.h b/Include/cpython/abstract.h +index 4e7b7a46703..8fed1d31109 100644 +--- a/Include/cpython/abstract.h ++++ b/Include/cpython/abstract.h +@@ -85,3 +85,29 @@ + need to be corrected for a negative index. */ + #define PySequence_ITEM(o, i)\ + ( Py_TYPE(o)->tp_as_sequence->sq_item((o), (i)) ) + ++/* Return the sequence 'o' as a list, unless it's already a tuple or list. + -+def tvos_ver(system="", release="", model="", is_simulator=False): -+ """Get tvOS version information, and return it as a namedtuple: -+ (system, release, model, is_simulator). ++ Use PySequence_Fast_GET_ITEM to access the members of this list, and ++ PySequence_Fast_GET_SIZE to get its length. + -+ If values can't be determined, they are set to values provided as -+ parameters. -+ """ -+ if sys.platform == "tvos": -+ # TODO: Can the iOS implementation be used here? -+ import _ios_support -+ result = _ios_support.get_platform_ios() -+ if result is not None: -+ return TVOSVersionInfo(*result) ++ Returns NULL on failure. If the object does not support iteration, raises a ++ TypeError exception with 'm' as the message text. */ ++PyAPI_FUNC(PyObject *) PySequence_Fast(PyObject *o, const char* m); + -+ return TVOSVersionInfo(system, release, model, is_simulator) ++/* Return the size of the sequence 'o', assuming that 'o' was returned by ++ PySequence_Fast and is not NULL. */ ++#define PySequence_Fast_GET_SIZE(o) \ ++ (PyList_Check(o) ? PyList_GET_SIZE(o) : PyTuple_GET_SIZE(o)) + ++/* Return the 'i'-th element of the sequence 'o', assuming that o was returned ++ by PySequence_Fast, and that i is within bounds. */ ++#define PySequence_Fast_GET_ITEM(o, i)\ ++ (PyList_Check(o) ? PyList_GET_ITEM((o), (i)) : PyTuple_GET_ITEM((o), (i))) + -+# A namedtuple for watchOS version information. -+WatchOSVersionInfo = collections.namedtuple( -+ "WatchOSVersionInfo", -+ ["system", "release", "model", "is_simulator"] -+) ++/* Return a pointer to the underlying item array for ++ an object returned by PySequence_Fast */ ++#define PySequence_Fast_ITEMS(sf) \ ++ (PyList_Check(sf) ? ((PyListObject *)(sf))->ob_item \ ++ : ((PyTupleObject *)(sf))->ob_item) + +diff --git a/Include/cpython/bytesobject.h b/Include/cpython/bytesobject.h +index cf3f0387ecf..71c133f173f 100644 +--- a/Include/cpython/bytesobject.h ++++ b/Include/cpython/bytesobject.h +@@ -34,5 +34,9 @@ + + PyAPI_FUNC(PyObject*) PyBytes_Join(PyObject *sep, PyObject *iterable); + +-// Alias kept for backward compatibility +-#define _PyBytes_Join PyBytes_Join ++// Deprecated alias kept for backward compatibility ++Py_DEPRECATED(3.14) static inline PyObject* ++_PyBytes_Join(PyObject *sep, PyObject *iterable) ++{ ++ return PyBytes_Join(sep, iterable); ++} +diff --git a/Include/cpython/code.h b/Include/cpython/code.h +index 3899d426923..2bd3e08631f 100644 +--- a/Include/cpython/code.h ++++ b/Include/cpython/code.h +@@ -11,11 +11,11 @@ + /* Total tool ids available */ + #define _PY_MONITORING_TOOL_IDS 8 + /* Count of all local monitoring events */ +-#define _PY_MONITORING_LOCAL_EVENTS 10 ++#define _PY_MONITORING_LOCAL_EVENTS 11 + /* Count of all "real" monitoring events (not derived from other events) */ +-#define _PY_MONITORING_UNGROUPED_EVENTS 15 ++#define _PY_MONITORING_UNGROUPED_EVENTS 16 + /* Count of all monitoring events */ +-#define _PY_MONITORING_EVENTS 17 ++#define _PY_MONITORING_EVENTS 19 + + /* Tables of which tools are active for each monitored event. */ + typedef struct _Py_LocalMonitors { +@@ -35,11 +35,12 @@ + } _PyCoCached; + + /* Ancillary data structure used for instrumentation. +- Line instrumentation creates an array of +- these. One entry per code unit.*/ ++ Line instrumentation creates this with sufficient ++ space for one entry per code unit. The total size ++ of the data will be `bytes_per_entry * Py_SIZE(code)` */ + typedef struct { +- uint8_t original_opcode; +- int8_t line_delta; ++ uint8_t bytes_per_entry; ++ uint8_t data[1]; + } _PyCoLineInstrumentationData; + + +@@ -199,6 +200,9 @@ + */ + #define CO_HAS_DOCSTRING 0x4000000 + ++/* A function defined in class scope */ ++#define CO_METHOD 0x8000000 + -+def watchos_ver(system="", release="", model="", is_simulator=False): -+ """Get watchOS version information, and return it as a namedtuple: -+ (system, release, model, is_simulator). + /* This should be defined if a future statement modifies the syntax. + For example, when a keyword is added. + */ +diff --git a/Include/cpython/dictobject.h b/Include/cpython/dictobject.h +index 78473e54898..df9ec7050fc 100644 +--- a/Include/cpython/dictobject.h ++++ b/Include/cpython/dictobject.h +@@ -68,7 +68,12 @@ + + PyAPI_FUNC(int) PyDict_Pop(PyObject *dict, PyObject *key, PyObject **result); + PyAPI_FUNC(int) PyDict_PopString(PyObject *dict, const char *key, PyObject **result); +-PyAPI_FUNC(PyObject *) _PyDict_Pop(PyObject *dict, PyObject *key, PyObject *default_value); + -+ If values can't be determined, they are set to values provided as -+ parameters. -+ """ -+ if sys.platform == "watchos": -+ # TODO: Can the iOS implementation be used here? -+ import _ios_support -+ result = _ios_support.get_platform_ios() -+ if result is not None: -+ return WatchOSVersionInfo(*result) ++// Use PyDict_Pop() instead ++Py_DEPRECATED(3.14) PyAPI_FUNC(PyObject *) _PyDict_Pop( ++ PyObject *dict, ++ PyObject *key, ++ PyObject *default_value); + + /* Dictionary watchers */ + +diff --git a/Include/cpython/fileutils.h b/Include/cpython/fileutils.h +index b386ad107bd..626b1ad57b3 100644 +--- a/Include/cpython/fileutils.h ++++ b/Include/cpython/fileutils.h +@@ -2,7 +2,15 @@ + # error "this header file must not be included directly" + #endif + +-// Used by _testcapi which must not use the internal C API +-PyAPI_FUNC(FILE*) _Py_fopen_obj( ++PyAPI_FUNC(FILE*) Py_fopen( + PyObject *path, + const char *mode); + -+ return WatchOSVersionInfo(system, release, model, is_simulator) ++// Deprecated alias kept for backward compatibility ++Py_DEPRECATED(3.14) static inline FILE* ++_Py_fopen_obj(PyObject *path, const char *mode) ++{ ++ return Py_fopen(path, mode); ++} + ++PyAPI_FUNC(int) Py_fclose(FILE *file); +diff --git a/Include/cpython/import.h b/Include/cpython/import.h +index 7daf0b84fcf..0ce0b1ee6cc 100644 +--- a/Include/cpython/import.h ++++ b/Include/cpython/import.h +@@ -2,8 +2,6 @@ + # error "this header file must not be included directly" + #endif + +-PyMODINIT_FUNC PyInit__imp(void); +- + struct _inittab { + const char *name; /* ASCII encoded string */ + PyObject* (*initfunc)(void); +@@ -23,3 +21,10 @@ + collection of frozen modules: */ + + PyAPI_DATA(const struct _frozen *) PyImport_FrozenModules; + - def _java_getprop(name, default): - """This private helper is deprecated in 3.13 and will be removed in 3.15""" - from java.lang import System -@@ -884,14 +932,25 @@ - csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0) - return 'Alpha' if cpu_number >= 128 else 'VAX' ++PyAPI_FUNC(PyObject*) PyImport_ImportModuleAttr( ++ PyObject *mod_name, ++ PyObject *attr_name); ++PyAPI_FUNC(PyObject*) PyImport_ImportModuleAttrString( ++ const char *mod_name, ++ const char *attr_name); +diff --git a/Include/cpython/longintrepr.h b/Include/cpython/longintrepr.h +index 357477b60d9..4b6f97a5e47 100644 +--- a/Include/cpython/longintrepr.h ++++ b/Include/cpython/longintrepr.h +@@ -76,8 +76,8 @@ + - 1: Zero + - 2: Negative -- # On the iOS simulator, os.uname returns the architecture as uname.machine. -- # On device it returns the model name for some reason; but there's only one -- # CPU architecture for iOS devices, so we know the right answer. -+ # On the iOS/tvOS/watchOS simulator, os.uname returns the architecture as -+ # uname.machine. On device it returns the model name for some reason; but -+ # there's only one CPU architecture for devices, so we know the right -+ # answer. - def get_ios(): - if sys.implementation._multiarch.endswith("simulator"): - return os.uname().machine - return 'arm64' +- The third lowest bit of lv_tag is reserved for an immortality flag, but is +- not currently used. ++ The third lowest bit of lv_tag is ++ set to 1 for the small ints. -+ def get_tvos(): -+ if sys.implementation._multiarch.endswith("simulator"): -+ return os.uname().machine -+ return 'arm64' + In a normalized number, ob_digit[ndigits-1] (the most significant + digit) is never zero. Also, in all cases, for all valid i, +@@ -100,12 +100,12 @@ + _PyLongValue long_value; + }; + +-PyAPI_FUNC(PyLongObject*) _PyLong_New(Py_ssize_t); ++Py_DEPRECATED(3.14) PyAPI_FUNC(PyLongObject*) _PyLong_New(Py_ssize_t); + + // Return a copy of src. + PyAPI_FUNC(PyObject*) _PyLong_Copy(PyLongObject *src); + +-PyAPI_FUNC(PyLongObject*) _PyLong_FromDigits( ++Py_DEPRECATED(3.14) PyAPI_FUNC(PyLongObject*) _PyLong_FromDigits( + int negative, + Py_ssize_t digit_count, + digit *digits); +diff --git a/Include/cpython/longobject.h b/Include/cpython/longobject.h +index 4d6e618f831..7f28ad60b74 100644 +--- a/Include/cpython/longobject.h ++++ b/Include/cpython/longobject.h +@@ -86,7 +86,7 @@ + - On failure, set an exception, and return -1. */ + PyAPI_FUNC(int) PyLong_GetSign(PyObject *v, int *sign); + +-PyAPI_FUNC(int) _PyLong_Sign(PyObject *v); ++Py_DEPRECATED(3.14) PyAPI_FUNC(int) _PyLong_Sign(PyObject *v); + + /* _PyLong_NumBits. Return the number of bits needed to represent the + absolute value of a long. For example, this returns 1 for 1 and -1, 2 +diff --git a/Include/cpython/monitoring.h b/Include/cpython/monitoring.h +index 797ba51246b..ce92942404c 100644 +--- a/Include/cpython/monitoring.h ++++ b/Include/cpython/monitoring.h +@@ -13,25 +13,27 @@ + #define PY_MONITORING_EVENT_LINE 5 + #define PY_MONITORING_EVENT_INSTRUCTION 6 + #define PY_MONITORING_EVENT_JUMP 7 +-#define PY_MONITORING_EVENT_BRANCH 8 +-#define PY_MONITORING_EVENT_STOP_ITERATION 9 ++#define PY_MONITORING_EVENT_BRANCH_LEFT 8 ++#define PY_MONITORING_EVENT_BRANCH_RIGHT 9 ++#define PY_MONITORING_EVENT_STOP_ITERATION 10 + + #define PY_MONITORING_IS_INSTRUMENTED_EVENT(ev) \ + ((ev) < _PY_MONITORING_LOCAL_EVENTS) + + /* Other events, mainly exceptions */ + +-#define PY_MONITORING_EVENT_RAISE 10 +-#define PY_MONITORING_EVENT_EXCEPTION_HANDLED 11 +-#define PY_MONITORING_EVENT_PY_UNWIND 12 +-#define PY_MONITORING_EVENT_PY_THROW 13 +-#define PY_MONITORING_EVENT_RERAISE 14 ++#define PY_MONITORING_EVENT_RAISE 11 ++#define PY_MONITORING_EVENT_EXCEPTION_HANDLED 12 ++#define PY_MONITORING_EVENT_PY_UNWIND 13 ++#define PY_MONITORING_EVENT_PY_THROW 14 ++#define PY_MONITORING_EVENT_RERAISE 15 + + + /* Ancillary events */ + +-#define PY_MONITORING_EVENT_C_RETURN 15 +-#define PY_MONITORING_EVENT_C_RAISE 16 ++#define PY_MONITORING_EVENT_C_RETURN 16 ++#define PY_MONITORING_EVENT_C_RAISE 17 ++#define PY_MONITORING_EVENT_BRANCH 18 + + + typedef struct _PyMonitoringState { +@@ -74,10 +76,18 @@ + _PyMonitoring_FireJumpEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, + PyObject *target_offset); + +-PyAPI_FUNC(int) ++Py_DEPRECATED(3.14) PyAPI_FUNC(int) + _PyMonitoring_FireBranchEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, + PyObject *target_offset); + ++PyAPI_FUNC(int) ++_PyMonitoring_FireBranchRightEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, ++ PyObject *target_offset); + -+ def get_watchos(): -+ if sys.implementation._multiarch.endswith("simulator"): -+ return os.uname().machine -+ return 'arm64_32' ++PyAPI_FUNC(int) ++_PyMonitoring_FireBranchLeftEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, ++ PyObject *target_offset); + - def from_subprocess(): - """ - Fall back to `uname -p` -@@ -1051,9 +1110,13 @@ - system = 'Android' - release = android_ver().release + PyAPI_FUNC(int) + _PyMonitoring_FireCReturnEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, + PyObject *retval); +@@ -174,12 +184,21 @@ + } -- # Normalize responses on iOS -+ # Normalize responses on Apple mobile platforms - if sys.platform == 'ios': - system, release, _, _ = ios_ver() -+ if sys.platform == 'tvos': -+ system, release, _, _ = tvos_ver() -+ if sys.platform == 'watchos': -+ system, release, _, _ = watchos_ver() + static inline int +-PyMonitoring_FireBranchEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, ++PyMonitoring_FireBranchRightEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, ++ PyObject *target_offset) ++{ ++ _PYMONITORING_IF_ACTIVE( ++ state, ++ _PyMonitoring_FireBranchRightEvent(state, codelike, offset, target_offset)); ++} ++ ++static inline int ++PyMonitoring_FireBranchLeftEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, + PyObject *target_offset) + { + _PYMONITORING_IF_ACTIVE( + state, +- _PyMonitoring_FireBranchEvent(state, codelike, offset, target_offset)); ++ _PyMonitoring_FireBranchLeftEvent(state, codelike, offset, target_offset)); + } - vals = system, node, release, version, machine - # Replace 'unknown' values with the more portable '' -@@ -1343,6 +1406,10 @@ - # macOS and iOS both report as a "Darwin" kernel - if sys.platform == "ios": - system, release, _, _ = ios_ver() -+ elif sys.platform == "tvos": -+ system, release, _, _ = tvos_ver() -+ elif sys.platform == "watchos": -+ system, release, _, _ = watchos_ver() - else: - macos_release = mac_ver()[0] - if macos_release: -diff --git a/Lib/sysconfig/__init__.py b/Lib/sysconfig/__init__.py -index ed7b6a335d0..322e6cf1eee 100644 ---- a/Lib/sysconfig/__init__.py -+++ b/Lib/sysconfig/__init__.py -@@ -690,6 +690,14 @@ - release = get_config_vars().get("IPHONEOS_DEPLOYMENT_TARGET", "13.0") - osname = sys.platform - machine = sys.implementation._multiarch -+ elif sys.platform == "tvos": -+ release = get_config_vars().get("TVOS_DEPLOYMENT_TARGET", "9.0") -+ osname = sys.platform -+ machine = sys.implementation._multiarch -+ elif sys.platform == "watchos": -+ release = get_config_vars().get("WATCHOS_DEPLOYMENT_TARGET", "4.0") -+ osname = sys.platform -+ machine = sys.implementation._multiarch - else: - import _osx_support - osname, release, machine = _osx_support.get_platform_osx( -diff --git a/Misc/platform_triplet.c b/Misc/platform_triplet.c -index ec0857a4a99..2350e9dc821 100644 ---- a/Misc/platform_triplet.c -+++ b/Misc/platform_triplet.c -@@ -257,6 +257,26 @@ - # else - PLATFORM_TRIPLET=arm64-iphoneos - # endif -+# elif defined(TARGET_OS_TV) && TARGET_OS_TV -+# if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR -+# if __x86_64__ -+PLATFORM_TRIPLET=x86_64-appletvsimulator -+# else -+PLATFORM_TRIPLET=arm64-appletvsimulator -+# endif -+# else -+PLATFORM_TRIPLET=arm64-appletvos -+# endif -+# elif defined(TARGET_OS_WATCH) && TARGET_OS_WATCH -+# if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR -+# if __x86_64__ -+PLATFORM_TRIPLET=x86_64-watchsimulator -+# else -+PLATFORM_TRIPLET=arm64-watchsimulator -+# endif -+# else -+PLATFORM_TRIPLET=arm64_32-watchos -+# endif - // Older macOS SDKs do not define TARGET_OS_OSX - # elif !defined(TARGET_OS_OSX) || TARGET_OS_OSX - PLATFORM_TRIPLET=darwin -diff --git a/configure b/configure -index 57be576e3ca..6d4ef3d0e01 100755 ---- a/configure -+++ b/configure -@@ -980,6 +980,8 @@ - CFLAGS - CC - HAS_XCRUN -+WATCHOS_DEPLOYMENT_TARGET -+TVOS_DEPLOYMENT_TARGET - IPHONEOS_DEPLOYMENT_TARGET - EXPORT_MACOSX_DEPLOYMENT_TARGET - CONFIGURE_MACOSX_DEPLOYMENT_TARGET -@@ -4052,6 +4054,12 @@ - *-apple-ios*) - ac_sys_system=iOS - ;; -+ *-apple-tvos*) -+ ac_sys_system=tvOS -+ ;; -+ *-apple-watchos*) -+ ac_sys_system=watchOS -+ ;; - *-*-vxworks*) - ac_sys_system=VxWorks - ;; -@@ -4129,7 +4137,7 @@ - # On cross-compile builds, configure will look for a host-specific compiler by - # prepending the user-provided host triple to the required binary name. - # --# On iOS, this results in binaries like "arm64-apple-ios13.0-simulator-gcc", -+# On iOS/tvOS/watchOS, this results in binaries like "arm64-apple-ios13.0-simulator-gcc", - # which isn't a binary that exists, and isn't very convenient, as it contains the - # iOS version. As the default cross-compiler name won't exist, configure falls - # back to gcc, which *definitely* won't work. We're providing wrapper scripts for -@@ -4144,6 +4152,14 @@ - aarch64-apple-ios*-simulator) AR=arm64-apple-ios-simulator-ar ;; - aarch64-apple-ios*) AR=arm64-apple-ios-ar ;; - x86_64-apple-ios*-simulator) AR=x86_64-apple-ios-simulator-ar ;; + static inline int +diff --git a/Include/cpython/object.h b/Include/cpython/object.h +index e4797029da4..71bd0188442 100644 +--- a/Include/cpython/object.h ++++ b/Include/cpython/object.h +@@ -221,7 +221,9 @@ + PyObject *tp_weaklist; /* not used for static builtin types */ + destructor tp_del; + +- /* Type attribute cache version tag. Added in version 2.6 */ ++ /* Type attribute cache version tag. Added in version 2.6. ++ * If zero, the cache is invalid and must be initialized. ++ */ + unsigned int tp_version_tag; + + destructor tp_finalize; +@@ -229,9 +231,17 @@ + + /* bitset of which type-watchers care about this type */ + unsigned char tp_watched; + -+ aarch64-apple-tvos*-simulator) AR=arm64-apple-tvos-simulator-ar ;; -+ aarch64-apple-tvos*) AR=arm64-apple-tvos-ar ;; -+ x86_64-apple-tvos*-simulator) AR=x86_64-apple-tvos-simulator-ar ;; ++ /* Number of tp_version_tag values used. ++ * Set to _Py_ATTR_CACHE_UNUSED if the attribute cache is ++ * disabled for this type (e.g. due to custom MRO entries). ++ * Otherwise, limited to MAX_VERSIONS_PER_CLASS (defined elsewhere). ++ */ + uint16_t tp_versions_used; + }; + ++#define _Py_ATTR_CACHE_UNUSED (30000) // (see tp_versions_used) + -+ aarch64-apple-watchos*-simulator) AR=arm64-apple-watchos-simulator-ar ;; -+ aarch64-apple-watchos*) AR=arm64_32-apple-watchos-ar ;; -+ x86_64-apple-watchos*-simulator) AR=x86_64-apple-watchos-simulator-ar ;; - *) - esac - fi -@@ -4152,6 +4168,14 @@ - aarch64-apple-ios*-simulator) CC=arm64-apple-ios-simulator-clang ;; - aarch64-apple-ios*) CC=arm64-apple-ios-clang ;; - x86_64-apple-ios*-simulator) CC=x86_64-apple-ios-simulator-clang ;; + /* This struct is used by the specializer + * It should be treated as an opaque blob + * by code other than the specializer and interpreter. */ +@@ -465,9 +475,6 @@ + passed as second argument to Py_TRASHCAN_BEGIN(). + */ + +-/* Python 3.9 private API, invoked by the macros below. */ +-PyAPI_FUNC(int) _PyTrash_begin(PyThreadState *tstate, PyObject *op); +-PyAPI_FUNC(void) _PyTrash_end(PyThreadState *tstate); + + PyAPI_FUNC(void) _PyTrash_thread_deposit_object(PyThreadState *tstate, PyObject *op); + PyAPI_FUNC(void) _PyTrash_thread_destroy_chain(PyThreadState *tstate); +@@ -534,3 +541,12 @@ + * 0 if the runtime ignored it. This function cannot fail. + */ + PyAPI_FUNC(int) PyUnstable_Object_EnableDeferredRefcount(PyObject *); + -+ aarch64-apple-tvos*-simulator) CC=arm64-apple-tvos-simulator-clang ;; -+ aarch64-apple-tvos*) CC=arm64-apple-tvos-clang ;; -+ x86_64-apple-tvos*-simulator) CC=x86_64-apple-tvos-simulator-clang ;; ++/* Check whether the object is immortal. This cannot fail. */ ++PyAPI_FUNC(int) PyUnstable_IsImmortal(PyObject *); + -+ aarch64-apple-watchos*-simulator) CC=arm64-apple-watchos-simulator-clang ;; -+ aarch64-apple-watchos*) CC=arm64_32-apple-watchos-clang ;; -+ x86_64-apple-watchos*-simulator) CC=x86_64-apple-watchos-simulator-clang ;; - *) - esac - fi -@@ -4160,6 +4184,14 @@ - aarch64-apple-ios*-simulator) CPP=arm64-apple-ios-simulator-cpp ;; - aarch64-apple-ios*) CPP=arm64-apple-ios-cpp ;; - x86_64-apple-ios*-simulator) CPP=x86_64-apple-ios-simulator-cpp ;; -+ -+ aarch64-apple-tvos*-simulator) CPP=arm64-apple-tvos-simulator-cpp ;; -+ aarch64-apple-tvos*) CPP=arm64-apple-tvos-cpp ;; -+ x86_64-apple-tvos*-simulator) CPP=x86_64-apple-tvos-simulator-cpp ;; -+ -+ aarch64-apple-watchos*-simulator) CPP=arm64-apple-watchos-simulator-cpp ;; -+ aarch64-apple-watchos*) CPP=arm64_32-apple-watchos-cpp ;; -+ x86_64-apple-watchos*-simulator) CPP=x86_64-apple-watchos-simulator-cpp ;; - *) - esac - fi -@@ -4168,6 +4200,14 @@ - aarch64-apple-ios*-simulator) CXX=arm64-apple-ios-simulator-clang++ ;; - aarch64-apple-ios*) CXX=arm64-apple-ios-clang++ ;; - x86_64-apple-ios*-simulator) CXX=x86_64-apple-ios-simulator-clang++ ;; ++// Increments the reference count of the object, if it's not zero. ++// PyUnstable_EnableTryIncRef() should be called on the object ++// before calling this function in order to avoid spurious failures. ++PyAPI_FUNC(int) PyUnstable_TryIncRef(PyObject *); ++PyAPI_FUNC(void) PyUnstable_EnableTryIncRef(PyObject *); +diff --git a/Include/cpython/pyatomic.h b/Include/cpython/pyatomic.h +index 6d106c1b499..2a0c11e7b3a 100644 +--- a/Include/cpython/pyatomic.h ++++ b/Include/cpython/pyatomic.h +@@ -574,15 +574,15 @@ + + #if _Py_USE_GCC_BUILTIN_ATOMICS + # define Py_ATOMIC_GCC_H +-# include "cpython/pyatomic_gcc.h" ++# include "pyatomic_gcc.h" + # undef Py_ATOMIC_GCC_H + #elif __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__) + # define Py_ATOMIC_STD_H +-# include "cpython/pyatomic_std.h" ++# include "pyatomic_std.h" + # undef Py_ATOMIC_STD_H + #elif defined(_MSC_VER) + # define Py_ATOMIC_MSC_H +-# include "cpython/pyatomic_msc.h" ++# include "pyatomic_msc.h" + # undef Py_ATOMIC_MSC_H + #else + # error "no available pyatomic implementation for this platform/compiler" +diff --git a/Include/cpython/pyhash.h b/Include/cpython/pyhash.h +index 876a7f0ea44..a33ba10b8d3 100644 +--- a/Include/cpython/pyhash.h ++++ b/Include/cpython/pyhash.h +@@ -29,9 +29,6 @@ + /* Helpers for hash functions */ + PyAPI_FUNC(Py_hash_t) _Py_HashDouble(PyObject *, double); + +-// Kept for backward compatibility +-#define _Py_HashPointer Py_HashPointer +- + + /* hash function definition */ + typedef struct { +@@ -44,6 +41,14 @@ + PyAPI_FUNC(PyHash_FuncDef*) PyHash_GetFuncDef(void); + + PyAPI_FUNC(Py_hash_t) Py_HashPointer(const void *ptr); + -+ aarch64-apple-tvos*-simulator) CXX=arm64-apple-tvos-simulator-clang++ ;; -+ aarch64-apple-tvos*) CXX=arm64-apple-tvos-clang++ ;; -+ x86_64-apple-tvos*-simulator) CXX=x86_64-apple-tvos-simulator-clang++ ;; ++// Deprecated alias kept for backward compatibility ++Py_DEPRECATED(3.14) static inline Py_hash_t ++_Py_HashPointer(const void *ptr) ++{ ++ return Py_HashPointer(ptr); ++} + -+ aarch64-apple-watchos*-simulator) CXX=arm64-apple-watchos-simulator-clang++ ;; -+ aarch64-apple-watchos*) CXX=arm64_32-apple-watchos-clang++ ;; -+ x86_64-apple-watchos*-simulator) CXX=x86_64-apple-watchos-simulator-clang++ ;; - *) - esac - fi -@@ -4288,8 +4328,10 @@ - case $enableval in - yes) - case $ac_sys_system in -- Darwin) enableval=/Library/Frameworks ;; -- iOS) enableval=iOS/Frameworks/\$\(MULTIARCH\) ;; -+ Darwin) enableval=/Library/Frameworks ;; -+ iOS) enableval=iOS/Frameworks/\$\(MULTIARCH\) ;; -+ tvOS) enableval=tvOS/Frameworks/\$\(MULTIARCH\) ;; -+ watchOS) enableval=watchOS/Frameworks/\$\(MULTIARCH\) ;; - *) as_fn_error $? "Unknown platform for framework build" "$LINENO" 5 - esac - esac -@@ -4298,6 +4340,8 @@ - no) - case $ac_sys_system in - iOS) as_fn_error $? "iOS builds must use --enable-framework" "$LINENO" 5 ;; -+ tvOS) as_fn_error $? "tvOS builds must use --enable-framework" "$LINENO" 5 ;; -+ watchOS) as_fn_error $? "watchOS builds must use --enable-framework" "$LINENO" 5 ;; - *) - PYTHONFRAMEWORK= - PYTHONFRAMEWORKDIR=no-framework -@@ -4404,6 +4448,36 @@ + PyAPI_FUNC(Py_hash_t) PyObject_GenericHash(PyObject *); - ac_config_files="$ac_config_files iOS/Resources/Info.plist" + PyAPI_FUNC(Py_hash_t) Py_HashBuffer(const void *ptr, Py_ssize_t len); +diff --git a/Include/cpython/pylifecycle.h b/Include/cpython/pylifecycle.h +index e46dfe59ec4..86ce6e6f798 100644 +--- a/Include/cpython/pylifecycle.h ++++ b/Include/cpython/pylifecycle.h +@@ -25,9 +25,6 @@ + PyAPI_FUNC(PyStatus) Py_InitializeFromConfig( + const PyConfig *config); -+ ;; -+ tvOS) : -+ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure" -+ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure " -+ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKPYTHONW= -+ INSTALLTARGETS="libinstall inclinstall sharedinstall" +-// Python 3.8 provisional API (PEP 587) +-PyAPI_FUNC(PyStatus) _Py_InitializeMain(void); +- + PyAPI_FUNC(int) Py_RunMain(void); + + +diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h +index 32f68378ea5..cd6d9582496 100644 +--- a/Include/cpython/pystate.h ++++ b/Include/cpython/pystate.h +@@ -239,8 +239,12 @@ + * if it is NULL. */ + PyAPI_FUNC(PyThreadState *) PyThreadState_GetUnchecked(void); + +-// Alias kept for backward compatibility +-#define _PyThreadState_UncheckedGet PyThreadState_GetUnchecked ++// Deprecated alias kept for backward compatibility ++Py_DEPRECATED(3.14) static inline PyThreadState* ++_PyThreadState_UncheckedGet(void) ++{ ++ return PyThreadState_GetUnchecked(); ++} + + + // Disable tracing and profiling. +diff --git a/Include/cpython/pystats.h b/Include/cpython/pystats.h +index 29ef0c0e4d4..4421b4d6e91 100644 +--- a/Include/cpython/pystats.h ++++ b/Include/cpython/pystats.h +@@ -31,7 +31,7 @@ + + #define PYSTATS_MAX_UOP_ID 512 + +-#define SPECIALIZATION_FAILURE_KINDS 36 ++#define SPECIALIZATION_FAILURE_KINDS 37 + + /* Stats for determining who is calling PyEval_EvalFrame */ + #define EVAL_CALL_TOTAL 0 +@@ -129,6 +129,7 @@ + uint64_t inner_loop; + uint64_t recursive_call; + uint64_t low_confidence; ++ uint64_t unknown_callee; + uint64_t executors_invalidated; + UOpStats opcode[PYSTATS_MAX_UOP_ID + 1]; + uint64_t unsupported_opcode[256]; +@@ -141,6 +142,14 @@ + uint64_t remove_globals_builtins_changed; + uint64_t remove_globals_incorrect_keys; + uint64_t error_in_opcode[PYSTATS_MAX_UOP_ID + 1]; ++ // JIT memory stats ++ uint64_t jit_total_memory_size; ++ uint64_t jit_code_size; ++ uint64_t jit_trampoline_size; ++ uint64_t jit_data_size; ++ uint64_t jit_padding_size; ++ uint64_t jit_freed_memory_size; ++ uint64_t trace_total_memory_hist[_Py_UOP_HIST_SIZE]; + } OptimizationStats; + + typedef struct _rare_event_stats { +diff --git a/Include/cpython/pythread.h b/Include/cpython/pythread.h +index 03f710a9f7e..e658b35bd90 100644 +--- a/Include/cpython/pythread.h ++++ b/Include/cpython/pythread.h +@@ -22,7 +22,7 @@ + */ + # define NATIVE_TSS_KEY_T unsigned long + #elif defined(HAVE_PTHREAD_STUBS) +-# include "cpython/pthread_stubs.h" ++# include "pthread_stubs.h" + # define NATIVE_TSS_KEY_T pthread_key_t + #else + # error "Require native threads. See https://bugs.python.org/issue31370" +diff --git a/Include/cpython/unicodeobject.h b/Include/cpython/unicodeobject.h +index 91799137101..cea69dd1280 100644 +--- a/Include/cpython/unicodeobject.h ++++ b/Include/cpython/unicodeobject.h +@@ -109,7 +109,7 @@ + 3: Interned, Immortal, and Static + This categorization allows the runtime to determine the right + cleanup mechanism at runtime shutdown. */ +- unsigned int interned:2; ++ uint16_t interned; + /* Character size: + + - PyUnicode_1BYTE_KIND (1): +@@ -132,21 +132,23 @@ + * all characters are in the range U+0000-U+10FFFF + * at least one character is in the range U+10000-U+10FFFF + */ +- unsigned int kind:3; ++ unsigned short kind:3; + /* Compact is with respect to the allocation scheme. Compact unicode + objects only require one memory block while non-compact objects use + one block for the PyUnicodeObject struct and another for its data + buffer. */ +- unsigned int compact:1; ++ unsigned short compact:1; + /* The string only contains characters in the range U+0000-U+007F (ASCII) + and the kind is PyUnicode_1BYTE_KIND. If ascii is set and compact is + set, use the PyASCIIObject structure. */ +- unsigned int ascii:1; ++ unsigned short ascii:1; + /* The object is statically allocated. */ +- unsigned int statically_allocated:1; ++ unsigned short statically_allocated:1; + /* Padding to ensure that PyUnicode_DATA() is always aligned to +- 4 bytes (see issue #19537 on m68k). */ +- unsigned int :24; ++ 4 bytes (see issue #19537 on m68k) and we use unsigned short to avoid ++ the extra four bytes on 32-bit Windows. This is restricted features ++ for specific compilers including GCC, MSVC, Clang and IBM's XL compiler. */ ++ unsigned short :10; + } state; + } PyASCIIObject; + +@@ -195,7 +197,11 @@ + + /* Use only if you know it's a string */ + static inline unsigned int PyUnicode_CHECK_INTERNED(PyObject *op) { ++#ifdef Py_GIL_DISABLED ++ return _Py_atomic_load_uint16_relaxed(&_PyASCIIObject_CAST(op)->state.interned); ++#else + return _PyASCIIObject_CAST(op)->state.interned; ++#endif + } + #define PyUnicode_CHECK_INTERNED(op) PyUnicode_CHECK_INTERNED(_PyObject_CAST(op)) + +@@ -234,6 +240,8 @@ + PyUnicode_4BYTE_KIND = 4 + }; + ++PyAPI_FUNC(int) PyUnicode_KIND(PyObject *op); + -+ prefix=$PYTHONFRAMEWORKPREFIX -+ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" -+ RESSRCDIR=tvOS/Resources + // PyUnicode_KIND(): Return one of the PyUnicode_*_KIND values defined above. + // + // gh-89653: Converting this macro to a static inline function would introduce +@@ -258,13 +266,15 @@ + return data; + } + +-static inline void* PyUnicode_DATA(PyObject *op) { ++PyAPI_FUNC(void*) PyUnicode_DATA(PyObject *op); + -+ ac_config_files="$ac_config_files tvOS/Resources/Info.plist" ++static inline void* _PyUnicode_DATA(PyObject *op) { + if (PyUnicode_IS_COMPACT(op)) { + return _PyUnicode_COMPACT_DATA(op); + } + return _PyUnicode_NONCOMPACT_DATA(op); + } +-#define PyUnicode_DATA(op) PyUnicode_DATA(_PyObject_CAST(op)) ++#define PyUnicode_DATA(op) _PyUnicode_DATA(_PyObject_CAST(op)) + + /* Return pointers to the canonical representation cast to unsigned char, + Py_UCS2, or Py_UCS4 for direct character access. +@@ -624,8 +634,12 @@ + + PyAPI_FUNC(const char *) PyUnicode_AsUTF8(PyObject *unicode); + +-// Alias kept for backward compatibility +-#define _PyUnicode_AsString PyUnicode_AsUTF8 ++// Deprecated alias kept for backward compatibility ++Py_DEPRECATED(3.14) static inline const char* ++_PyUnicode_AsString(PyObject *unicode) ++{ ++ return PyUnicode_AsUTF8(unicode); ++} + + + /* === Characters Type APIs =============================================== */ +diff --git a/Include/cpython/weakrefobject.h b/Include/cpython/weakrefobject.h +index 9aa1a92c413..da8e77cddac 100644 +--- a/Include/cpython/weakrefobject.h ++++ b/Include/cpython/weakrefobject.h +@@ -45,6 +45,9 @@ + #define _PyWeakref_CAST(op) \ + (assert(PyWeakref_Check(op)), _Py_CAST(PyWeakReference*, (op))) + ++// Test if a weak reference is dead. ++PyAPI_FUNC(int) PyWeakref_IsDead(PyObject *ref); + -+ ;; -+ watchOS) : -+ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure" -+ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure " -+ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKPYTHONW= -+ INSTALLTARGETS="libinstall inclinstall sharedinstall" + Py_DEPRECATED(3.13) static inline PyObject* PyWeakref_GET_OBJECT(PyObject *ref_obj) + { + PyWeakReference *ref = _PyWeakref_CAST(ref_obj); +diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h +index 80bd19a8878..fea8665ae39 100644 +--- a/Include/internal/pycore_ceval.h ++++ b/Include/internal/pycore_ceval.h +@@ -264,7 +264,7 @@ + + PyAPI_FUNC(int) _PyEval_CheckExceptStarTypeValid(PyThreadState *tstate, PyObject* right); + PyAPI_FUNC(int) _PyEval_CheckExceptTypeValid(PyThreadState *tstate, PyObject* right); +-PyAPI_FUNC(int) _PyEval_ExceptionGroupMatch(PyObject* exc_value, PyObject *match_type, PyObject **match, PyObject **rest); ++PyAPI_FUNC(int) _PyEval_ExceptionGroupMatch(_PyInterpreterFrame *, PyObject* exc_value, PyObject *match_type, PyObject **match, PyObject **rest); + PyAPI_FUNC(void) _PyEval_FormatAwaitableError(PyThreadState *tstate, PyTypeObject *type, int oparg); + PyAPI_FUNC(void) _PyEval_FormatExcCheckArg(PyThreadState *tstate, PyObject *exc, const char *format_str, PyObject *obj); + PyAPI_FUNC(void) _PyEval_FormatExcUnbound(PyThreadState *tstate, PyCodeObject *co, int oparg); +diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h +index d607a54aa4a..6d45d5f0c40 100644 +--- a/Include/internal/pycore_code.h ++++ b/Include/internal/pycore_code.h +@@ -100,6 +100,7 @@ + + typedef struct { + _Py_BackoffCounter counter; ++ uint16_t external_cache[4]; + } _PyBinaryOpCache; + + #define INLINE_CACHE_ENTRIES_BINARY_OP CACHE_ENTRIES(_PyBinaryOpCache) +@@ -337,8 +338,6 @@ + PyObject *name); + extern void _Py_Specialize_LoadGlobal(PyObject *globals, PyObject *builtins, + _Py_CODEUNIT *instr, PyObject *name); +-extern void _Py_Specialize_BinarySubscr(_PyStackRef sub, _PyStackRef container, +- _Py_CODEUNIT *instr); + extern void _Py_Specialize_StoreSubscr(_PyStackRef container, _PyStackRef sub, + _Py_CODEUNIT *instr); + extern void _Py_Specialize_Call(_PyStackRef callable, _Py_CODEUNIT *instr, +@@ -372,6 +371,7 @@ + do { if (_Py_stats && PyFunction_Check(callable)) _Py_stats->call_stats.eval_calls[name]++; } while (0) + #define GC_STAT_ADD(gen, name, n) do { if (_Py_stats) _Py_stats->gc_stats[(gen)].name += (n); } while (0) + #define OPT_STAT_INC(name) do { if (_Py_stats) _Py_stats->optimization_stats.name++; } while (0) ++#define OPT_STAT_ADD(name, n) do { if (_Py_stats) _Py_stats->optimization_stats.name += (n); } while (0) + #define UOP_STAT_INC(opname, name) do { if (_Py_stats) { assert(opname < 512); _Py_stats->optimization_stats.opcode[opname].name++; } } while (0) + #define UOP_PAIR_INC(uopcode, lastuop) \ + do { \ +@@ -407,6 +407,7 @@ + #define EVAL_CALL_STAT_INC_IF_FUNCTION(name, callable) ((void)0) + #define GC_STAT_ADD(gen, name, n) ((void)0) + #define OPT_STAT_INC(name) ((void)0) ++#define OPT_STAT_ADD(name, n) ((void)0) + #define UOP_STAT_INC(opname, name) ((void)0) + #define UOP_PAIR_INC(uopcode, lastuop) ((void)0) + #define OPT_UNSUPPORTED_OPCODE(opname) ((void)0) +@@ -438,7 +439,7 @@ + } + + static inline void +-write_obj(uint16_t *p, PyObject *val) ++write_ptr(uint16_t *p, void *val) + { + memcpy(p, &val, sizeof(val)); + } +@@ -576,6 +577,17 @@ + return restart_backoff_counter(counter); + } + ++/* Specialization Extensions */ + -+ prefix=$PYTHONFRAMEWORKPREFIX -+ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" -+ RESSRCDIR=watchOS/Resources ++/* callbacks for an external specialization */ ++typedef int (*binaryopguardfunc)(PyObject *lhs, PyObject *rhs); ++typedef PyObject *(*binaryopactionfunc)(PyObject *lhs, PyObject *rhs); + -+ ac_config_files="$ac_config_files watchOS/Resources/Info.plist" ++typedef struct { ++ int oparg; ++ binaryopguardfunc guard; ++ binaryopactionfunc action; ++} _PyBinaryOpSpecializationDescr; + + /* Comparison bit masks. */ + +@@ -603,6 +615,8 @@ + + extern int _PyInstruction_GetLength(PyCodeObject *code, int offset); + ++extern PyObject *_PyInstrumentation_BranchesIterator(PyCodeObject *code); + - ;; - *) - as_fn_error $? "Unknown platform for framework build" "$LINENO" 5 -@@ -4415,6 +4489,8 @@ + struct _PyCode8 _PyCode_DEF(8); - case $ac_sys_system in - iOS) as_fn_error $? "iOS builds must use --enable-framework" "$LINENO" 5 ;; -+ tvOS) as_fn_error $? "tvOS builds must use --enable-framework" "$LINENO" 5 ;; -+ watchOS) as_fn_error $? "watchOS builds must use --enable-framework" "$LINENO" 5 ;; - *) - PYTHONFRAMEWORK= - PYTHONFRAMEWORKDIR=no-framework -@@ -4468,8 +4544,8 @@ - case "$withval" in - yes) - case $ac_sys_system in -- Darwin|iOS) -- # iOS is able to share the macOS patch -+ Darwin|iOS|tvOS|watchOS) -+ # iOS/tvOS/watchOS is able to share the macOS patch - APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" - ;; - *) as_fn_error $? "no default app store compliance patch available for $ac_sys_system" "$LINENO" 5 ;; -@@ -4487,8 +4563,8 @@ - else $as_nop + PyAPI_DATA(const struct _PyCode8) _Py_InitCleanup; +diff --git a/Include/internal/pycore_critical_section.h b/Include/internal/pycore_critical_section.h +index 78cd0d54972..e66d6d805c1 100644 +--- a/Include/internal/pycore_critical_section.h ++++ b/Include/internal/pycore_critical_section.h +@@ -109,7 +109,7 @@ + static inline void + _PyCriticalSection_BeginMutex(PyCriticalSection *c, PyMutex *m) + { +- if (PyMutex_LockFast(&m->_bits)) { ++ if (PyMutex_LockFast(m)) { + PyThreadState *tstate = _PyThreadState_GET(); + c->_cs_mutex = m; + c->_cs_prev = tstate->critical_section; +@@ -145,6 +145,12 @@ + static inline void + _PyCriticalSection_End(PyCriticalSection *c) + { ++ // If the mutex is NULL, we used the fast path in ++ // _PyCriticalSection_BeginSlow for locks already held in the top-most ++ // critical section, and we shouldn't unlock or pop this critical section. ++ if (c->_cs_mutex == NULL) { ++ return; ++ } + PyMutex_Unlock(c->_cs_mutex); + _PyCriticalSection_Pop(c); + } +@@ -170,8 +176,8 @@ + m2 = tmp; + } - case $ac_sys_system in -- iOS) -- # Always apply the compliance patch on iOS; we can use the macOS patch -+ iOS|tvOS|watchOS) -+ # Always apply the compliance patch on iOS/tvOS/watchOS; we can use the macOS patch - APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: applying default app store compliance patch" >&5 - printf "%s\n" "applying default app store compliance patch" >&6; } -@@ -4542,6 +4618,50 @@ - ;; - esac - ;; -+ *-apple-tvos*) -+ _host_os=`echo $host | cut -d '-' -f3` -+ _host_device=`echo $host | cut -d '-' -f4` -+ _host_device=${_host_device:=os} +- if (PyMutex_LockFast(&m1->_bits)) { +- if (PyMutex_LockFast(&m2->_bits)) { ++ if (PyMutex_LockFast(m1)) { ++ if (PyMutex_LockFast(m2)) { + PyThreadState *tstate = _PyThreadState_GET(); + c->_cs_base._cs_mutex = m1; + c->_cs_mutex2 = m2; +@@ -199,6 +205,14 @@ + static inline void + _PyCriticalSection2_End(PyCriticalSection2 *c) + { ++ // if mutex1 is NULL, we used the fast path in ++ // _PyCriticalSection_BeginSlow for mutexes that are already held, ++ // which should only happen when mutex1 and mutex2 were the same mutex, ++ // and mutex2 should also be NULL. ++ if (c->_cs_base._cs_mutex == NULL) { ++ assert(c->_cs_mutex2 == NULL); ++ return; ++ } + if (c->_cs_mutex2) { + PyMutex_Unlock(c->_cs_mutex2); + } +diff --git a/Include/internal/pycore_debug_offsets.h b/Include/internal/pycore_debug_offsets.h +index 184f4b9360b..44feb079571 100644 +--- a/Include/internal/pycore_debug_offsets.h ++++ b/Include/internal/pycore_debug_offsets.h +@@ -11,6 +11,42 @@ + + #define _Py_Debug_Cookie "xdebugpy" + ++#if defined(__APPLE__) ++# include ++#endif + -+ # TVOS_DEPLOYMENT_TARGET is the minimum supported tvOS version -+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking tvOS deployment target" >&5 -+printf %s "checking tvOS deployment target... " >&6; } -+ TVOS_DEPLOYMENT_TARGET=${_host_os:4} -+ TVOS_DEPLOYMENT_TARGET=${TVOS_DEPLOYMENT_TARGET:=12.0} -+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $TVOS_DEPLOYMENT_TARGET" >&5 -+printf "%s\n" "$TVOS_DEPLOYMENT_TARGET" >&6; } ++// Macros to burn global values in custom sections so out-of-process ++// profilers can locate them easily. ++#define GENERATE_DEBUG_SECTION(name, declaration) \ ++ _GENERATE_DEBUG_SECTION_WINDOWS(name) \ ++ _GENERATE_DEBUG_SECTION_APPLE(name) \ ++ declaration \ ++ _GENERATE_DEBUG_SECTION_LINUX(name) + -+ case "$host_cpu" in -+ aarch64) -+ _host_ident=${TVOS_DEPLOYMENT_TARGET}-arm64-appletv${_host_device} -+ ;; -+ *) -+ _host_ident=${TVOS_DEPLOYMENT_TARGET}-$host_cpu-appletv${_host_device} -+ ;; -+ esac -+ ;; -+ *-apple-watchos*) -+ _host_os=`echo $host | cut -d '-' -f3` -+ _host_device=`echo $host | cut -d '-' -f4` -+ _host_device=${_host_device:=os} ++#if defined(MS_WINDOWS) ++#define _GENERATE_DEBUG_SECTION_WINDOWS(name) \ ++ _Pragma(Py_STRINGIFY(section(Py_STRINGIFY(name), read, write))) \ ++ __declspec(allocate(Py_STRINGIFY(name))) ++#else ++#define _GENERATE_DEBUG_SECTION_WINDOWS(name) ++#endif + -+ # WATCHOS_DEPLOYMENT_TARGET is the minimum supported watchOS version -+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking watchOS deployment target" >&5 -+printf %s "checking watchOS deployment target... " >&6; } -+ WATCHOS_DEPLOYMENT_TARGET=${_host_os:7} -+ WATCHOS_DEPLOYMENT_TARGET=${WATCHOS_DEPLOYMENT_TARGET:=4.0} -+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $WATCHOS_DEPLOYMENT_TARGET" >&5 -+printf "%s\n" "$WATCHOS_DEPLOYMENT_TARGET" >&6; } ++#if defined(__APPLE__) ++#define _GENERATE_DEBUG_SECTION_APPLE(name) \ ++ __attribute__((section(SEG_DATA "," Py_STRINGIFY(name)))) \ ++ __attribute__((used)) ++#else ++#define _GENERATE_DEBUG_SECTION_APPLE(name) ++#endif + -+ case "$host_cpu" in -+ aarch64) -+ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-arm64-watch${_host_device} -+ ;; -+ *) -+ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-$host_cpu-watch${_host_device} -+ ;; -+ esac -+ ;; - *-*-vxworks*) - _host_ident=$host_cpu - ;; -@@ -4620,9 +4740,13 @@ - define_xopen_source=no;; - Darwin/[12][0-9].*) - define_xopen_source=no;; -- # On iOS, defining _POSIX_C_SOURCE also disables platform specific features. -+ # On iOS/tvOS/watchOS, defining _POSIX_C_SOURCE also disables platform specific features. - iOS/*) - define_xopen_source=no;; -+ tvOS/*) -+ define_xopen_source=no;; -+ watchOS/*) -+ define_xopen_source=no;; - # On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from - # defining NI_NUMERICHOST. - QNX/6.3.2) -@@ -4685,7 +4809,10 @@ - CONFIGURE_MACOSX_DEPLOYMENT_TARGET= - EXPORT_MACOSX_DEPLOYMENT_TARGET='#' ++#if defined(__linux__) && (defined(__GNUC__) || defined(__clang__)) ++#define _GENERATE_DEBUG_SECTION_LINUX(name) \ ++ __attribute__((section("." Py_STRINGIFY(name)))) \ ++ __attribute__((used)) ++#else ++#define _GENERATE_DEBUG_SECTION_LINUX(name) ++#endif ++ + #ifdef Py_GIL_DISABLED + # define _Py_Debug_gilruntimestate_enabled offsetof(struct _gil_runtime_state, enabled) + # define _Py_Debug_Free_Threaded 1 +@@ -69,6 +105,7 @@ + uint64_t instr_ptr; + uint64_t localsplus; + uint64_t owner; ++ uint64_t stackpointer; + } interpreter_frame; --# Record the value of IPHONEOS_DEPLOYMENT_TARGET enforced by the selected host triple. -+# Record the value of IPHONEOS_DEPLOYMENT_TARGET / TVOS_DEPLOYMENT_TARGET / -+# WATCHOS_DEPLOYMENT_TARGET enforced by the selected host triple. + // Code object offset; +@@ -113,6 +150,14 @@ + uint64_t ob_size; + } list_object; + ++ // PySet object offset; ++ struct _set_object { ++ uint64_t size; ++ uint64_t used; ++ uint64_t table; ++ uint64_t mask; ++ } set_object; + + // PyDict object offset; + struct _dict_object { + uint64_t size; +@@ -153,6 +198,14 @@ + uint64_t size; + uint64_t collecting; + } gc; + ++ // Generator object offset; ++ struct _gen_object { ++ uint64_t size; ++ uint64_t gi_name; ++ uint64_t gi_iframe; ++ uint64_t gi_frame_state; ++ } gen_object; + } _Py_DebugOffsets; - # checks for alternative programs -@@ -4726,6 +4853,16 @@ - as_fn_append CFLAGS " -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}" - as_fn_append LDFLAGS " -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}" - ;; #( -+ tvOS) : -+ -+ as_fn_append CFLAGS " -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}" -+ as_fn_append LDFLAGS " -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}" -+ ;; #( -+ watchOS) : +@@ -198,6 +251,7 @@ + .instr_ptr = offsetof(_PyInterpreterFrame, instr_ptr), \ + .localsplus = offsetof(_PyInterpreterFrame, localsplus), \ + .owner = offsetof(_PyInterpreterFrame, owner), \ ++ .stackpointer = offsetof(_PyInterpreterFrame, stackpointer), \ + }, \ + .code_object = { \ + .size = sizeof(PyCodeObject), \ +@@ -231,6 +285,12 @@ + .ob_item = offsetof(PyListObject, ob_item), \ + .ob_size = offsetof(PyListObject, ob_base.ob_size), \ + }, \ ++ .set_object = { \ ++ .size = sizeof(PySetObject), \ ++ .used = offsetof(PySetObject, used), \ ++ .table = offsetof(PySetObject, table), \ ++ .mask = offsetof(PySetObject, mask), \ ++ }, \ + .dict_object = { \ + .size = sizeof(PyDictObject), \ + .ma_keys = offsetof(PyDictObject, ma_keys), \ +@@ -260,6 +320,12 @@ + .size = sizeof(struct _gc_runtime_state), \ + .collecting = offsetof(struct _gc_runtime_state, collecting), \ + }, \ ++ .gen_object = { \ ++ .size = sizeof(PyGenObject), \ ++ .gi_name = offsetof(PyGenObject, gi_name), \ ++ .gi_iframe = offsetof(PyGenObject, gi_iframe), \ ++ .gi_frame_state = offsetof(PyGenObject, gi_frame_state), \ ++ }, \ + } + + +diff --git a/Include/internal/pycore_dict.h b/Include/internal/pycore_dict.h +index 6e4a308226f..f4c55ca6cf6 100644 +--- a/Include/internal/pycore_dict.h ++++ b/Include/internal/pycore_dict.h +@@ -114,6 +114,17 @@ + + extern Py_ssize_t _PyDict_LookupIndex(PyDictObject *, PyObject *); + extern Py_ssize_t _PyDictKeys_StringLookup(PyDictKeysObject* dictkeys, PyObject *key); + -+ as_fn_append CFLAGS " -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}" -+ as_fn_append LDFLAGS " -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}" -+ ;; #( - *) : - ;; - esac -@@ -7030,6 +7167,10 @@ - MULTIARCH="" ;; #( - iOS) : - MULTIARCH="" ;; #( -+ tvOS) : -+ MULTIARCH="" ;; #( -+ watchOS) : -+ MULTIARCH="" ;; #( - FreeBSD*) : - MULTIARCH="" ;; #( - *) : -@@ -7050,7 +7191,7 @@ - printf "%s\n" "$MULTIARCH" >&6; } ++/* Look up a string key in an all unicode dict keys, assign the keys object a version, and ++ * store it in version. ++ * ++ * Returns DKIX_ERROR if key is not a string or if the keys object is not all ++ * strings. ++ * ++ * Returns DKIX_EMPTY if the key is not present. ++ */ ++extern Py_ssize_t _PyDictKeys_StringLookupAndVersion(PyDictKeysObject* dictkeys, PyObject *key, uint32_t *version); ++extern Py_ssize_t _PyDictKeys_StringLookupSplit(PyDictKeysObject* dictkeys, PyObject *key); + PyAPI_FUNC(PyObject *)_PyDict_LoadGlobal(PyDictObject *, PyDictObject *, PyObject *); + PyAPI_FUNC(void) _PyDict_LoadGlobalStackRef(PyDictObject *, PyDictObject *, PyObject *, _PyStackRef *); - case $ac_sys_system in #( -- iOS) : -+ iOS|tvOS|watchOS) : - SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f2` ;; #( - *) : - SOABI_PLATFORM=$PLATFORM_TRIPLET -@@ -7101,6 +7242,14 @@ - PY_SUPPORT_TIER=3 ;; #( - aarch64-apple-ios*/clang) : - PY_SUPPORT_TIER=3 ;; #( -+ aarch64-apple-tvos*-simulator/clang) : -+ PY_SUPPORT_TIER=3 ;; #( -+ aarch64-apple-tvos*/clang) : -+ PY_SUPPORT_TIER=3 ;; #( -+ aarch64-apple-watchos*-simulator/clang) : -+ PY_SUPPORT_TIER=3 ;; #( -+ arm64_32-apple-watchos*/clang) : -+ PY_SUPPORT_TIER=3 ;; #( - aarch64-*-linux-android/clang) : - PY_SUPPORT_TIER=3 ;; #( - x86_64-*-linux-android/clang) : -@@ -7530,7 +7679,7 @@ - case $ac_sys_system in - Darwin) - LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)';; -- iOS) -+ iOS|tvOS|watchOS) - LDLIBRARY='$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';; - *) - as_fn_error $? "Unknown platform for framework build" "$LINENO" 5;; -@@ -7596,7 +7745,7 @@ - BLDLIBRARY='-L. -lpython$(LDVERSION)' - RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}} - ;; -- iOS) -+ iOS|tvOS|watchOS) - LDLIBRARY='libpython$(LDVERSION).dylib' - ;; - AIX*) -@@ -13160,7 +13309,7 @@ - BLDSHARED="$LDSHARED" - fi - ;; -- iOS/*) -+ iOS/*|tvOS/*|watchOS/*) - LDSHARED='$(CC) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)' - LDCXXSHARED='$(CXX) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)' - BLDSHARED="$LDSHARED" -@@ -13293,7 +13442,7 @@ - Linux-android*) LINKFORSHARED="-pie -Xlinker -export-dynamic";; - Linux*|GNU*) LINKFORSHARED="-Xlinker -export-dynamic";; - # -u libsys_s pulls in all symbols in libsys -- Darwin/*|iOS/*) -+ Darwin/*|iOS/*|tvOS/*|watchOS/*) - LINKFORSHARED="$extra_undefs -framework CoreFoundation" - - # Issue #18075: the default maximum stack size (8MBytes) is too -@@ -13317,7 +13466,7 @@ - LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' - fi - LINKFORSHARED="$LINKFORSHARED" -- elif test $ac_sys_system = "iOS"; then -+ elif test "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "watchOS"; then - LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)' - fi - ;; -@@ -14769,7 +14918,7 @@ +@@ -336,8 +347,7 @@ + static inline Py_ssize_t + _PyDict_UniqueId(PyDictObject *mp) + { +- // Offset by one so that _ma_watcher_tag=0 represents an unassigned id +- return (Py_ssize_t)(mp->_ma_watcher_tag >> DICT_UNIQUE_ID_SHIFT) - 1; ++ return (Py_ssize_t)(mp->_ma_watcher_tag >> DICT_UNIQUE_ID_SHIFT); + } - ctypes_malloc_closure=yes - ;; #( -- iOS) : -+ iOS|tvOS|watchOS) : + static inline void +diff --git a/Include/internal/pycore_emscripten_trampoline.h b/Include/internal/pycore_emscripten_trampoline.h +index e519c99ad86..5546ebbbfcb 100644 +--- a/Include/internal/pycore_emscripten_trampoline.h ++++ b/Include/internal/pycore_emscripten_trampoline.h +@@ -27,24 +27,14 @@ - ctypes_malloc_closure=yes - ;; #( -@@ -18272,12 +18421,6 @@ - then : - printf "%s\n" "#define HAVE_DUP3 1" >>confdefs.h + #if defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE) --fi --ac_fn_c_check_func "$LINENO" "execv" "ac_cv_func_execv" --if test "x$ac_cv_func_execv" = xyes --then : -- printf "%s\n" "#define HAVE_EXECV 1" >>confdefs.h -- - fi - ac_fn_c_check_func "$LINENO" "explicit_bzero" "ac_cv_func_explicit_bzero" - if test "x$ac_cv_func_explicit_bzero" = xyes -@@ -18338,18 +18481,6 @@ - then : - printf "%s\n" "#define HAVE_FEXECVE 1" >>confdefs.h +-void _Py_EmscriptenTrampoline_Init(_PyRuntimeState *runtime); ++void ++_Py_EmscriptenTrampoline_Init(_PyRuntimeState *runtime); --fi --ac_fn_c_check_func "$LINENO" "fork" "ac_cv_func_fork" --if test "x$ac_cv_func_fork" = xyes --then : -- printf "%s\n" "#define HAVE_FORK 1" >>confdefs.h + PyObject* +-_PyEM_TrampolineCall_JavaScript(PyCFunctionWithKeywords func, +- PyObject* self, +- PyObject* args, +- PyObject* kw); - --fi --ac_fn_c_check_func "$LINENO" "fork1" "ac_cv_func_fork1" --if test "x$ac_cv_func_fork1" = xyes --then : -- printf "%s\n" "#define HAVE_FORK1 1" >>confdefs.h +-PyObject* +-_PyEM_TrampolineCall_Reflection(PyCFunctionWithKeywords func, +- PyObject* self, +- PyObject* args, +- PyObject* kw); - - fi - ac_fn_c_check_func "$LINENO" "fpathconf" "ac_cv_func_fpathconf" - if test "x$ac_cv_func_fpathconf" = xyes -@@ -18776,24 +18907,6 @@ - then : - printf "%s\n" "#define HAVE_POSIX_OPENPT 1" >>confdefs.h +-#define _PyEM_TrampolineCall(meth, self, args, kw) \ +- ((_PyRuntime.wasm_type_reflection_available) ? \ +- (_PyEM_TrampolineCall_Reflection((PyCFunctionWithKeywords)(meth), (self), (args), (kw))) : \ +- (_PyEM_TrampolineCall_JavaScript((PyCFunctionWithKeywords)(meth), (self), (args), (kw)))) ++_PyEM_TrampolineCall(PyCFunctionWithKeywords func, ++ PyObject* self, ++ PyObject* args, ++ PyObject* kw); --fi --ac_fn_c_check_func "$LINENO" "posix_spawn" "ac_cv_func_posix_spawn" --if test "x$ac_cv_func_posix_spawn" = xyes --then : -- printf "%s\n" "#define HAVE_POSIX_SPAWN 1" >>confdefs.h + #define _PyCFunction_TrampolineCall(meth, self, args) \ + _PyEM_TrampolineCall( \ +@@ -62,8 +52,6 @@ + + #else // defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE) + +-#define _Py_EmscriptenTrampoline_Init(runtime) - --fi --ac_fn_c_check_func "$LINENO" "posix_spawnp" "ac_cv_func_posix_spawnp" --if test "x$ac_cv_func_posix_spawnp" = xyes --then : -- printf "%s\n" "#define HAVE_POSIX_SPAWNP 1" >>confdefs.h + #define _PyCFunction_TrampolineCall(meth, self, args) \ + (meth)((self), (args)) + +diff --git a/Include/internal/pycore_exceptions.h b/Include/internal/pycore_exceptions.h +index 4a9df709131..26456d1966b 100644 +--- a/Include/internal/pycore_exceptions.h ++++ b/Include/internal/pycore_exceptions.h +@@ -24,6 +24,9 @@ + PyObject *errnomap; + PyBaseExceptionObject *memerrors_freelist; + int memerrors_numfree; ++#ifdef Py_GIL_DISABLED ++ PyMutex memerrors_lock; ++#endif + // The ExceptionGroup type + PyObject *PyExc_ExceptionGroup; + }; +diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h +index 96ae4dd22ec..8cc3504723b 100644 +--- a/Include/internal/pycore_frame.h ++++ b/Include/internal/pycore_frame.h +@@ -56,7 +56,8 @@ + FRAME_OWNED_BY_THREAD = 0, + FRAME_OWNED_BY_GENERATOR = 1, + FRAME_OWNED_BY_FRAME_OBJECT = 2, +- FRAME_OWNED_BY_CSTACK = 3, ++ FRAME_OWNED_BY_INTERPRETER = 3, ++ FRAME_OWNED_BY_CSTACK = 4, + }; + + typedef struct _PyInterpreterFrame { +@@ -68,14 +69,19 @@ + PyObject *f_locals; /* Strong reference, may be NULL. Only valid if not on C stack */ + PyFrameObject *frame_obj; /* Strong reference, may be NULL. Only valid if not on C stack */ + _Py_CODEUNIT *instr_ptr; /* Instruction currently executing (or about to begin) */ ++ _PyStackRef *stackpointer; + #ifdef Py_GIL_DISABLED + /* Index of thread-local bytecode containing instr_ptr. */ + int32_t tlbc_index; + #endif +- _PyStackRef *stackpointer; + uint16_t return_offset; /* Only relevant during a function call */ + char owner; +- char visited; ++#ifdef Py_DEBUG ++ uint8_t visited:1; ++ uint8_t lltrace:7; ++#else ++ uint8_t visited; ++#endif + /* Locals and stack */ + _PyStackRef localsplus[1]; + } _PyInterpreterFrame; +@@ -153,13 +159,6 @@ + // Don't leave a dangling pointer to the old frame when creating generators + // and coroutines: + dest->previous = NULL; - --fi --ac_fn_c_check_func "$LINENO" "posix_spawn_file_actions_addclosefrom_np" "ac_cv_func_posix_spawn_file_actions_addclosefrom_np" --if test "x$ac_cv_func_posix_spawn_file_actions_addclosefrom_np" = xyes --then : -- printf "%s\n" "#define HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP 1" >>confdefs.h +-#ifdef Py_GIL_DISABLED +- PyCodeObject *co = _PyFrame_GetCode(dest); +- for (int i = stacktop; i < co->co_nlocalsplus + co->co_stacksize; i++) { +- dest->localsplus[i] = PyStackRef_NULL; +- } +-#endif + } + + #ifdef Py_GIL_DISABLED +@@ -209,20 +208,13 @@ + frame->return_offset = 0; + frame->owner = FRAME_OWNED_BY_THREAD; + frame->visited = 0; ++#ifdef Py_DEBUG ++ frame->lltrace = 0; ++#endif + + for (int i = null_locals_from; i < code->co_nlocalsplus; i++) { + frame->localsplus[i] = PyStackRef_NULL; + } - - fi - ac_fn_c_check_func "$LINENO" "pread" "ac_cv_func_pread" - if test "x$ac_cv_func_pread" = xyes -@@ -19094,12 +19207,6 @@ - then : - printf "%s\n" "#define HAVE_SIGACTION 1" >>confdefs.h +-#ifdef Py_GIL_DISABLED +- // On GIL disabled, we walk the entire stack in GC. Since stacktop +- // is not always in sync with the real stack pointer, we have +- // no choice but to traverse the entire stack. +- // This just makes sure we don't pass the GC invalid stack values. +- for (int i = code->co_nlocalsplus; i < code->co_nlocalsplus + code->co_stacksize; i++) { +- frame->localsplus[i] = PyStackRef_NULL; +- } +-#endif + } --fi --ac_fn_c_check_func "$LINENO" "sigaltstack" "ac_cv_func_sigaltstack" --if test "x$ac_cv_func_sigaltstack" = xyes --then : -- printf "%s\n" "#define HAVE_SIGALTSTACK 1" >>confdefs.h + /* Gets the pointer to the locals array +@@ -264,7 +256,7 @@ + static inline bool + _PyFrame_IsIncomplete(_PyInterpreterFrame *frame) + { +- if (frame->owner == FRAME_OWNED_BY_CSTACK) { ++ if (frame->owner >= FRAME_OWNED_BY_INTERPRETER) { + return true; + } + return frame->owner != FRAME_OWNED_BY_GENERATOR && +@@ -392,14 +384,10 @@ + #endif + frame->owner = FRAME_OWNED_BY_THREAD; + frame->visited = 0; +- frame->return_offset = 0; - - fi - ac_fn_c_check_func "$LINENO" "sigfillset" "ac_cv_func_sigfillset" - if test "x$ac_cv_func_sigfillset" = xyes -@@ -19368,11 +19475,11 @@ +-#ifdef Py_GIL_DISABLED +- assert(code->co_nlocalsplus == 0); +- for (int i = 0; i < code->co_stacksize; i++) { +- frame->localsplus[i] = PyStackRef_NULL; +- } ++#ifdef Py_DEBUG ++ frame->lltrace = 0; + #endif ++ frame->return_offset = 0; + return frame; + } - fi +diff --git a/Include/internal/pycore_freelist_state.h b/Include/internal/pycore_freelist_state.h +index a1a94c1f2dc..7c252f5b570 100644 +--- a/Include/internal/pycore_freelist_state.h ++++ b/Include/internal/pycore_freelist_state.h +@@ -11,6 +11,8 @@ + # define PyTuple_MAXSAVESIZE 20 // Largest tuple to save on freelist + # define Py_tuple_MAXFREELIST 2000 // Maximum number of tuples of each size to save + # define Py_lists_MAXFREELIST 80 ++# define Py_list_iters_MAXFREELIST 10 ++# define Py_tuple_iters_MAXFREELIST 10 + # define Py_dicts_MAXFREELIST 80 + # define Py_dictkeys_MAXFREELIST 80 + # define Py_floats_MAXFREELIST 100 +@@ -22,6 +24,7 @@ + # define Py_futureiters_MAXFREELIST 255 + # define Py_object_stack_chunks_MAXFREELIST 4 + # define Py_unicode_writers_MAXFREELIST 1 ++# define Py_pymethodobjects_MAXFREELIST 20 --# iOS defines some system methods that can be linked (so they are -+# iOS/tvOS/watchOS define some system methods that can be linked (so they are - # found by configure), but either raise a compilation error (because the - # header definition prevents usage - autoconf doesn't use the headers), or - # raise an error if used at runtime. Force these symbols off. --if test "$ac_sys_system" != "iOS" ; then -+if test "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then - ac_fn_c_check_func "$LINENO" "getentropy" "ac_cv_func_getentropy" - if test "x$ac_cv_func_getentropy" = xyes - then : -@@ -19394,6 +19501,53 @@ + // A generic freelist of either PyObjects or other data structures. + struct _Py_freelist { +@@ -39,6 +42,8 @@ + struct _Py_freelist ints; + struct _Py_freelist tuples[PyTuple_MAXSAVESIZE]; + struct _Py_freelist lists; ++ struct _Py_freelist list_iters; ++ struct _Py_freelist tuple_iters; + struct _Py_freelist dicts; + struct _Py_freelist dictkeys; + struct _Py_freelist slices; +@@ -48,6 +53,7 @@ + struct _Py_freelist futureiters; + struct _Py_freelist object_stack_chunks; + struct _Py_freelist unicode_writers; ++ struct _Py_freelist pymethodobjects; + }; - fi + #ifdef __cplusplus +diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h +index 4ff34bf8ead..b1806df2706 100644 +--- a/Include/internal/pycore_gc.h ++++ b/Include/internal/pycore_gc.h +@@ -45,12 +45,13 @@ + * the per-object lock. + */ + #ifdef Py_GIL_DISABLED +-# define _PyGC_BITS_TRACKED (1) // Tracked by the GC +-# define _PyGC_BITS_FINALIZED (2) // tp_finalize was called +-# define _PyGC_BITS_UNREACHABLE (4) +-# define _PyGC_BITS_FROZEN (8) +-# define _PyGC_BITS_SHARED (16) +-# define _PyGC_BITS_DEFERRED (64) // Use deferred reference counting ++# define _PyGC_BITS_TRACKED (1<<0) // Tracked by the GC ++# define _PyGC_BITS_FINALIZED (1<<1) // tp_finalize was called ++# define _PyGC_BITS_UNREACHABLE (1<<2) ++# define _PyGC_BITS_FROZEN (1<<3) ++# define _PyGC_BITS_SHARED (1<<4) ++# define _PyGC_BITS_ALIVE (1<<5) // Reachable from a known root. ++# define _PyGC_BITS_DEFERRED (1<<6) // Use deferred reference counting + #endif -+# tvOS/watchOS have some additional methods that can be found, but not used. -+if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then -+ ac_fn_c_check_func "$LINENO" "execv" "ac_cv_func_execv" -+if test "x$ac_cv_func_execv" = xyes -+then : -+ printf "%s\n" "#define HAVE_EXECV 1" >>confdefs.h -+ -+fi -+ac_fn_c_check_func "$LINENO" "fork" "ac_cv_func_fork" -+if test "x$ac_cv_func_fork" = xyes -+then : -+ printf "%s\n" "#define HAVE_FORK 1" >>confdefs.h -+ -+fi -+ac_fn_c_check_func "$LINENO" "fork1" "ac_cv_func_fork1" -+if test "x$ac_cv_func_fork1" = xyes -+then : -+ printf "%s\n" "#define HAVE_FORK1 1" >>confdefs.h -+ -+fi -+ac_fn_c_check_func "$LINENO" "posix_spawn" "ac_cv_func_posix_spawn" -+if test "x$ac_cv_func_posix_spawn" = xyes -+then : -+ printf "%s\n" "#define HAVE_POSIX_SPAWN 1" >>confdefs.h -+ -+fi -+ac_fn_c_check_func "$LINENO" "posix_spawnp" "ac_cv_func_posix_spawnp" -+if test "x$ac_cv_func_posix_spawnp" = xyes -+then : -+ printf "%s\n" "#define HAVE_POSIX_SPAWNP 1" >>confdefs.h -+ -+fi -+ac_fn_c_check_func "$LINENO" "posix_spawn_file_actions_addclosefrom_np" "ac_cv_func_posix_spawn_file_actions_addclosefrom_np" -+if test "x$ac_cv_func_posix_spawn_file_actions_addclosefrom_np" = xyes -+then : -+ printf "%s\n" "#define HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP 1" >>confdefs.h -+ -+fi -+ac_fn_c_check_func "$LINENO" "sigaltstack" "ac_cv_func_sigaltstack" -+if test "x$ac_cv_func_sigaltstack" = xyes -+then : -+ printf "%s\n" "#define HAVE_SIGALTSTACK 1" >>confdefs.h -+ -+fi + #ifdef Py_GIL_DISABLED +@@ -330,6 +331,9 @@ + collections, and are awaiting to undergo a full collection for + the first time. */ + Py_ssize_t long_lived_pending; + -+fi ++ /* True if gc.freeze() has been used. */ ++ int freeze_active; + #endif + }; + +diff --git a/Include/internal/pycore_import.h b/Include/internal/pycore_import.h +index 318c712bdfa..5fe60df0a92 100644 +--- a/Include/internal/pycore_import.h ++++ b/Include/internal/pycore_import.h +@@ -31,12 +31,6 @@ + PyObject *modules + ); + +-// Export for many shared extensions, like '_json' +-PyAPI_FUNC(PyObject*) _PyImport_GetModuleAttr(PyObject *, PyObject *); +- +-// Export for many shared extensions, like '_datetime' +-PyAPI_FUNC(PyObject*) _PyImport_GetModuleAttrString(const char *, const char *); +- + + struct _import_runtime_state { + /* The builtin modules (defined in config.c). */ +diff --git a/Include/internal/pycore_instruments.h b/Include/internal/pycore_instruments.h +index 4e5b374968e..92d8f056f40 100644 +--- a/Include/internal/pycore_instruments.h ++++ b/Include/internal/pycore_instruments.h +@@ -48,8 +48,8 @@ + + _Py_CODEUNIT * + _Py_call_instrumentation_jump( +- PyThreadState *tstate, int event, +- _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *target); ++ _Py_CODEUNIT *instr, PyThreadState *tstate, int event, ++ _PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNIT *dest); + + extern int + _Py_call_instrumentation_arg(PyThreadState *tstate, int event, +diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h +index 87cdcb5b119..7fdfc790347 100644 +--- a/Include/internal/pycore_interp.h ++++ b/Include/internal/pycore_interp.h +@@ -31,9 +31,10 @@ + #include "pycore_list.h" // struct _Py_list_state + #include "pycore_mimalloc.h" // struct _mimalloc_interp_state + #include "pycore_object_state.h" // struct _py_object_state +-#include "pycore_optimizer.h" // _PyOptimizerObject ++#include "pycore_optimizer.h" // _PyExecutorObject + #include "pycore_obmalloc.h" // struct _obmalloc_state + #include "pycore_qsbr.h" // struct _qsbr_state ++#include "pycore_stackref.h" // Py_STACKREF_DEBUG + #include "pycore_tstate.h" // _PyThreadStateImpl + #include "pycore_tuple.h" // struct _Py_tuple_state + #include "pycore_uniqueid.h" // struct _Py_unique_id_pool +@@ -226,6 +227,13 @@ + PyMutex weakref_locks[NUM_WEAKREF_LIST_LOCKS]; + _PyIndexPool tlbc_indices; + #endif ++ // Per-interpreter list of tasks, any lingering tasks from thread ++ // states gets added here and removed from the corresponding ++ // thread state's list. ++ struct llist_node asyncio_tasks_head; ++ // `asyncio_tasks_lock` is used when tasks are moved ++ // from thread's list to interpreter's list. ++ PyMutex asyncio_tasks_lock; + + // Per-interpreter state for the obmalloc allocator. For the main + // interpreter and for all interpreters that don't have their +@@ -261,7 +269,7 @@ + struct ast_state ast; + struct types_state types; + struct callable_cache callable_cache; +- _PyOptimizerObject *optimizer; ++ bool jit; + _PyExecutorObject *executor_list_head; + size_t trace_run_counter; + _rare_events rare_events; +@@ -285,6 +293,11 @@ + _PyThreadStateImpl _initial_thread; + // _initial_thread should be the last field of PyInterpreterState. + // See https://github.com/python/cpython/issues/127117. + - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5 - printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; } - if test ${ac_cv_c_undeclared_builtin_options+y} -@@ -22269,7 +22423,8 @@ ++#if !defined(Py_GIL_DISABLED) && defined(Py_STACKREF_DEBUG) ++ uint64_t next_stackref; ++ _Py_hashtable_t *stackref_debug_table; ++#endif + }; - # check for openpty, login_tty, and forkpty +@@ -335,43 +348,6 @@ + + extern const PyConfig* _PyInterpreterState_GetConfig(PyInterpreterState *interp); + +-// Get a copy of the current interpreter configuration. +-// +-// Return 0 on success. Raise an exception and return -1 on error. +-// +-// The caller must initialize 'config', using PyConfig_InitPythonConfig() +-// for example. +-// +-// Python must be preinitialized to call this method. +-// The caller must hold the GIL. +-// +-// Once done with the configuration, PyConfig_Clear() must be called to clear +-// it. +-// +-// Export for '_testinternalcapi' shared extension. +-PyAPI_FUNC(int) _PyInterpreterState_GetConfigCopy( +- struct PyConfig *config); +- +-// Set the configuration of the current interpreter. +-// +-// This function should be called during or just after the Python +-// initialization. +-// +-// Update the sys module with the new configuration. If the sys module was +-// modified directly after the Python initialization, these changes are lost. +-// +-// Some configuration like faulthandler or warnoptions can be updated in the +-// configuration, but don't reconfigure Python (don't enable/disable +-// faulthandler and don't reconfigure warnings filters). +-// +-// Return 0 on success. Raise an exception and return -1 on error. +-// +-// The configuration should come from _PyInterpreterState_GetConfigCopy(). +-// +-// Export for '_testinternalcapi' shared extension. +-PyAPI_FUNC(int) _PyInterpreterState_SetConfig( +- const struct PyConfig *config); - -+# tvOS/watchOS have functions for tty, but can't use them -+if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then - for ac_func in openpty - do : -@@ -22365,7 +22520,7 @@ - fi + /* + Runtime Feature Flags +diff --git a/Include/internal/pycore_list.h b/Include/internal/pycore_list.h +index 836ff30abfc..5d817891408 100644 +--- a/Include/internal/pycore_list.h ++++ b/Include/internal/pycore_list.h +@@ -61,7 +61,7 @@ - done --{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing login_tty" >&5 -+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing login_tty" >&5 - printf %s "checking for library containing login_tty... " >&6; } - if test ${ac_cv_search_login_tty+y} - then : -@@ -22522,6 +22677,7 @@ - fi + union _PyStackRef; - done -+fi +-PyAPI_FUNC(PyObject *)_PyList_FromStackRefSteal(const union _PyStackRef *src, Py_ssize_t n); ++PyAPI_FUNC(PyObject *)_PyList_FromStackRefStealOnSuccess(const union _PyStackRef *src, Py_ssize_t n); + PyAPI_FUNC(PyObject *)_PyList_AsTupleAndClear(PyListObject *v); - # check for long file support functions - ac_fn_c_check_func "$LINENO" "fseek64" "ac_cv_func_fseek64" -@@ -22768,10 +22924,10 @@ + #ifdef __cplusplus +diff --git a/Include/internal/pycore_lock.h b/Include/internal/pycore_lock.h +index 57cbce8f126..7484b05d7f2 100644 +--- a/Include/internal/pycore_lock.h ++++ b/Include/internal/pycore_lock.h +@@ -18,9 +18,10 @@ + #define _Py_ONCE_INITIALIZED 4 - done + static inline int +-PyMutex_LockFast(uint8_t *lock_bits) ++PyMutex_LockFast(PyMutex *m) + { + uint8_t expected = _Py_UNLOCKED; ++ uint8_t *lock_bits = &m->_bits; + return _Py_atomic_compare_exchange_uint8(lock_bits, &expected, _Py_LOCKED); + } --# On Android and iOS, clock_settime can be linked (so it is found by -+# On Android, iOS, tvOS and watchOS, clock_settime can be linked (so it is found by - # configure), but when used in an unprivileged process, it crashes rather than - # returning an error. Force the symbol off. --if test "$ac_sys_system" != "Linux-android" && test "$ac_sys_system" != "iOS" -+if test "$ac_sys_system" != "Linux-android" -a "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" - then +@@ -51,7 +52,7 @@ - for ac_func in clock_settime -@@ -24999,8 +25155,8 @@ - LIBPYTHON="\$(BLDLIBRARY)" - fi + // Lock a mutex with an optional timeout and additional options. See + // _PyLockFlags for details. +-extern PyLockStatus ++extern PyAPI_FUNC(PyLockStatus) + _PyMutex_LockTimed(PyMutex *m, PyTime_t timeout_ns, _PyLockFlags flags); --# On iOS the shared libraries must be linked with the Python framework --if test "$ac_sys_system" = "iOS"; then -+# On iOS/tvOS/watchOS the shared libraries must be linked with the Python framework -+if test "$ac_sys_system" = "iOS" -o $ac_sys_system = "tvOS" -o $ac_sys_system = "watchOS"; then - MODULE_DEPS_SHARED="$MODULE_DEPS_SHARED \$(PYTHONFRAMEWORKDIR)/\$(PYTHONFRAMEWORK)" - fi + // Lock a mutex with additional options. See _PyLockFlags for details. +diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h +index 8bead00e706..df0656a7cb8 100644 +--- a/Include/internal/pycore_long.h ++++ b/Include/internal/pycore_long.h +@@ -65,6 +65,8 @@ + # error "_PY_NSMALLPOSINTS must be greater than or equal to 257" + #endif -@@ -27752,7 +27908,7 @@ - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for device files" >&5 - printf "%s\n" "$as_me: checking for device files" >&6;} ++#define _PY_IS_SMALL_INT(val) ((val) >= 0 && (val) < 256 && (val) < _PY_NSMALLPOSINTS) ++ + // Return a reference to the immortal zero singleton. + // The function cannot return NULL. + static inline PyObject* _PyLong_GetZero(void) +@@ -159,13 +161,14 @@ --if test "$ac_sys_system" = "Linux-android" || test "$ac_sys_system" = "iOS"; then -+if test "$ac_sys_system" = "Linux-android" -o "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "watchOS" ; then - ac_cv_file__dev_ptmx=no - ac_cv_file__dev_ptc=no - else -@@ -28184,7 +28340,7 @@ - with_ensurepip=no ;; #( - WASI) : - with_ensurepip=no ;; #( -- iOS) : -+ iOS|tvOS|watchOS) : - with_ensurepip=no ;; #( - *) : - with_ensurepip=upgrade -@@ -29130,7 +29286,7 @@ - ;; #( - Darwin) : - ;; #( -- iOS) : -+ iOS|tvOS|watchOS) : + /* Long value tag bits: + * 0-1: Sign bits value = (1-sign), ie. negative=2, positive=0, zero=1. +- * 2: Reserved for immortality bit ++ * 2: Set to 1 for the small ints + * 3+ Unsigned digit count + */ + #define SIGN_MASK 3 + #define SIGN_ZERO 1 + #define SIGN_NEGATIVE 2 + #define NON_SIZE_BITS 3 ++#define IMMORTALITY_BIT_MASK (1 << 2) + /* The functions _PyLong_IsCompact and _PyLong_CompactValue are defined + * in Include/cpython/longobject.h, since they need to be inline. +@@ -196,7 +199,7 @@ + static inline int + _PyLong_IsNonNegativeCompact(const PyLongObject* op) { + assert(PyLong_Check(op)); +- return op->long_value.lv_tag <= (1 << NON_SIZE_BITS); ++ return ((op->long_value.lv_tag & ~IMMORTALITY_BIT_MASK) <= (1 << NON_SIZE_BITS)); + } -@@ -33028,6 +33184,8 @@ - "Mac/Resources/framework/Info.plist") CONFIG_FILES="$CONFIG_FILES Mac/Resources/framework/Info.plist" ;; - "Mac/Resources/app/Info.plist") CONFIG_FILES="$CONFIG_FILES Mac/Resources/app/Info.plist" ;; - "iOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES iOS/Resources/Info.plist" ;; -+ "tvOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES tvOS/Resources/Info.plist" ;; -+ "watchOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES watchOS/Resources/Info.plist" ;; - "Makefile.pre") CONFIG_FILES="$CONFIG_FILES Makefile.pre" ;; - "Misc/python.pc") CONFIG_FILES="$CONFIG_FILES Misc/python.pc" ;; - "Misc/python-embed.pc") CONFIG_FILES="$CONFIG_FILES Misc/python-embed.pc" ;; -diff --git a/configure.ac b/configure.ac -index bd0221481c5..6dca265f3cc 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -330,6 +330,12 @@ - *-apple-ios*) - ac_sys_system=iOS - ;; -+ *-apple-tvos*) -+ ac_sys_system=tvOS -+ ;; -+ *-apple-watchos*) -+ ac_sys_system=watchOS -+ ;; - *-*-vxworks*) - ac_sys_system=VxWorks - ;; -@@ -401,7 +407,7 @@ - # On cross-compile builds, configure will look for a host-specific compiler by - # prepending the user-provided host triple to the required binary name. - # --# On iOS, this results in binaries like "arm64-apple-ios13.0-simulator-gcc", -+# On iOS/tvOS/watchOS, this results in binaries like "arm64-apple-ios13.0-simulator-gcc", - # which isn't a binary that exists, and isn't very convenient, as it contains the - # iOS version. As the default cross-compiler name won't exist, configure falls - # back to gcc, which *definitely* won't work. We're providing wrapper scripts for -@@ -416,6 +422,14 @@ - aarch64-apple-ios*-simulator) AR=arm64-apple-ios-simulator-ar ;; - aarch64-apple-ios*) AR=arm64-apple-ios-ar ;; - x86_64-apple-ios*-simulator) AR=x86_64-apple-ios-simulator-ar ;; +@@ -298,7 +301,7 @@ + .long_value = { \ + .lv_tag = TAG_FROM_SIGN_AND_SIZE( \ + (val) == 0 ? 0 : ((val) < 0 ? -1 : 1), \ +- (val) == 0 ? 0 : 1), \ ++ (val) == 0 ? 0 : 1) | IMMORTALITY_BIT_MASK, \ + { ((val) >= 0 ? (val) : -(val)) }, \ + } \ + } +diff --git a/Include/internal/pycore_magic_number.h b/Include/internal/pycore_magic_number.h +index 14e29576875..4803213e84b 100644 +--- a/Include/internal/pycore_magic_number.h ++++ b/Include/internal/pycore_magic_number.h +@@ -262,6 +262,13 @@ + Python 3.14a1 3607 (Add pseudo instructions JUMP_IF_TRUE/FALSE) + Python 3.14a1 3608 (Add support for slices) + Python 3.14a2 3609 (Add LOAD_SMALL_INT and LOAD_CONST_IMMORTAL instructions, remove RETURN_CONST) ++ Python 3.14a4 3610 (Add VALUE_WITH_FAKE_GLOBALS format to annotationlib) ++ Python 3.14a4 3611 (Add NOT_TAKEN instruction) ++ Python 3.14a4 3612 (Add POP_ITER and INSTRUMENTED_POP_ITER) ++ Python 3.14a4 3613 (Add LOAD_CONST_MORTAL instruction) ++ Python 3.14a5 3614 (Add BINARY_OP_EXTEND) ++ Python 3.14a5 3615 (CALL_FUNCTION_EX always take a kwargs argument) ++ Python 3.14a5 3616 (Remove BINARY_SUBSCR and family. Make them BINARY_OPs) + + Python 3.15 will start with 3650 + +@@ -274,7 +281,7 @@ + + */ + +-#define PYC_MAGIC_NUMBER 3609 ++#define PYC_MAGIC_NUMBER 3616 + /* This is equivalent to converting PYC_MAGIC_NUMBER to 2 bytes + (little-endian) and then appending b'\r\n'. */ + #define PYC_MAGIC_NUMBER_TOKEN \ +diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h +index d7d68f938a9..49ddfd5b43b 100644 +--- a/Include/internal/pycore_object.h ++++ b/Include/internal/pycore_object.h +@@ -62,7 +62,7 @@ + PyAPI_FUNC(int) _PyObject_IsFreed(PyObject *); + + /* We need to maintain an internal copy of Py{Var}Object_HEAD_INIT to avoid +- designated initializer conflicts in C++20. If we use the deinition in ++ designated initializer conflicts in C++20. If we use the definition in + object.h, we will be mixing designated and non-designated initializers in + pycore objects which is forbiddent in C++20. However, if we then use + designated initializers in object.h then Extensions without designated break. +@@ -120,8 +120,8 @@ + PyAPI_DATA(Py_ssize_t) _Py_RefTotal; + + extern void _Py_AddRefTotal(PyThreadState *, Py_ssize_t); +-extern void _Py_IncRefTotal(PyThreadState *); +-extern void _Py_DecRefTotal(PyThreadState *); ++extern PyAPI_FUNC(void) _Py_IncRefTotal(PyThreadState *); ++extern PyAPI_FUNC(void) _Py_DecRefTotal(PyThreadState *); + + # define _Py_DEC_REFTOTAL(interp) \ + interp->object_state.reftotal-- +@@ -299,12 +299,6 @@ + extern int _PyType_CheckConsistency(PyTypeObject *type); + extern int _PyDict_CheckConsistency(PyObject *mp, int check_content); + +-/* Update the Python traceback of an object. This function must be called +- when a memory block is reused from a free list. +- +- Internal function called by _Py_NewReference(). */ +-extern int _PyTraceMalloc_TraceRef(PyObject *op, PyRefTracerEvent event, void*); +- + // Fast inlined version of PyType_HasFeature() + static inline int + _PyType_HasFeature(PyTypeObject *type, unsigned long feature) { +@@ -342,20 +336,20 @@ + { + _PyThreadStateImpl *tstate = (_PyThreadStateImpl *)_PyThreadState_GET(); + +- // Unsigned comparison so that `unique_id=-1`, which indicates that +- // per-thread refcounting has been disabled on this object, is handled by +- // the "else". +- if ((size_t)unique_id < (size_t)tstate->refcounts.size) { ++ // The table index is `unique_id - 1` because 0 is not a valid unique id. ++ // Unsigned comparison so that `idx=-1` is handled by the "else". ++ size_t idx = (size_t)(unique_id - 1); ++ if (idx < (size_t)tstate->refcounts.size) { + # ifdef Py_REF_DEBUG + _Py_INCREF_IncRefTotal(); + # endif + _Py_INCREF_STAT_INC(); +- tstate->refcounts.values[unique_id]++; ++ tstate->refcounts.values[idx]++; + } + else { + // The slow path resizes the per-thread refcount array if necessary. +- // It handles the unique_id=-1 case to keep the inlinable function smaller. +- _PyObject_ThreadIncrefSlow(obj, unique_id); ++ // It handles the unique_id=0 case to keep the inlinable function smaller. ++ _PyObject_ThreadIncrefSlow(obj, idx); + } + } + +@@ -392,15 +386,15 @@ + { + _PyThreadStateImpl *tstate = (_PyThreadStateImpl *)_PyThreadState_GET(); + +- // Unsigned comparison so that `unique_id=-1`, which indicates that +- // per-thread refcounting has been disabled on this object, is handled by +- // the "else". +- if ((size_t)unique_id < (size_t)tstate->refcounts.size) { ++ // The table index is `unique_id - 1` because 0 is not a valid unique id. ++ // Unsigned comparison so that `idx=-1` is handled by the "else". ++ size_t idx = (size_t)(unique_id - 1); ++ if (idx < (size_t)tstate->refcounts.size) { + # ifdef Py_REF_DEBUG + _Py_DECREF_DecRefTotal(); + # endif + _Py_DECREF_STAT_INC(); +- tstate->refcounts.values[unique_id]--; ++ tstate->refcounts.values[idx]--; + } + else { + // Directly decref the object if the id is not assigned or if +@@ -716,7 +710,7 @@ + } + } + +-extern int _PyObject_ResurrectEndSlow(PyObject *op); ++extern PyAPI_FUNC(int) _PyObject_ResurrectEndSlow(PyObject *op); + #endif + + // Temporarily resurrects an object during deallocation. The refcount is set +diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h +index 28aa1120414..24c698adb31 100644 +--- a/Include/internal/pycore_opcode_metadata.h ++++ b/Include/internal/pycore_opcode_metadata.h +@@ -43,30 +43,30 @@ + return 2; + case BINARY_OP_ADD_UNICODE: + return 2; ++ case BINARY_OP_EXTEND: ++ return 2; + case BINARY_OP_INPLACE_ADD_UNICODE: + return 2; + case BINARY_OP_MULTIPLY_FLOAT: + return 2; + case BINARY_OP_MULTIPLY_INT: + return 2; +- case BINARY_OP_SUBTRACT_FLOAT: ++ case BINARY_OP_SUBSCR_DICT: + return 2; +- case BINARY_OP_SUBTRACT_INT: ++ case BINARY_OP_SUBSCR_GETITEM: + return 2; +- case BINARY_SLICE: +- return 3; +- case BINARY_SUBSCR: +- return 2; +- case BINARY_SUBSCR_DICT: ++ case BINARY_OP_SUBSCR_LIST_INT: + return 2; +- case BINARY_SUBSCR_GETITEM: ++ case BINARY_OP_SUBSCR_STR_INT: + return 2; +- case BINARY_SUBSCR_LIST_INT: ++ case BINARY_OP_SUBSCR_TUPLE_INT: + return 2; +- case BINARY_SUBSCR_STR_INT: ++ case BINARY_OP_SUBTRACT_FLOAT: + return 2; +- case BINARY_SUBSCR_TUPLE_INT: ++ case BINARY_OP_SUBTRACT_INT: + return 2; ++ case BINARY_SLICE: ++ return 3; + case BUILD_LIST: + return oparg; + case BUILD_MAP: +@@ -74,7 +74,7 @@ + case BUILD_SET: + return oparg; + case BUILD_SLICE: +- return 2 + ((oparg == 3) ? 1 : 0); ++ return oparg; + case BUILD_STRING: + return oparg; + case BUILD_TUPLE: +@@ -98,7 +98,7 @@ + case CALL_BUILTIN_O: + return 2 + oparg; + case CALL_FUNCTION_EX: +- return 3 + (oparg & 1); ++ return 4; + case CALL_INTRINSIC_1: + return 1; + case CALL_INTRINSIC_2: +@@ -224,9 +224,9 @@ + case INSTRUMENTED_CALL: + return 2 + oparg; + case INSTRUMENTED_CALL_FUNCTION_EX: +- return 0; ++ return 4; + case INSTRUMENTED_CALL_KW: +- return 0; ++ return 3 + oparg; + case INSTRUMENTED_END_FOR: + return 2; + case INSTRUMENTED_END_SEND: +@@ -242,7 +242,11 @@ + case INSTRUMENTED_LINE: + return 0; + case INSTRUMENTED_LOAD_SUPER_ATTR: ++ return 3; ++ case INSTRUMENTED_NOT_TAKEN: + return 0; ++ case INSTRUMENTED_POP_ITER: ++ return 1; + case INSTRUMENTED_POP_JUMP_IF_FALSE: + return 0; + case INSTRUMENTED_POP_JUMP_IF_NONE: +@@ -265,8 +269,12 @@ + return 0; + case JUMP_BACKWARD: + return 0; ++ case JUMP_BACKWARD_JIT: ++ return 0; + case JUMP_BACKWARD_NO_INTERRUPT: + return 0; ++ case JUMP_BACKWARD_NO_JIT: ++ return 0; + case JUMP_FORWARD: + return 0; + case JUMP_IF_FALSE: +@@ -317,6 +325,8 @@ + return 0; + case LOAD_CONST_IMMORTAL: + return 0; ++ case LOAD_CONST_MORTAL: ++ return 0; + case LOAD_DEREF: + return 0; + case LOAD_FAST: +@@ -367,10 +377,14 @@ + return 1; + case NOP: + return 0; ++ case NOT_TAKEN: ++ return 0; + case POP_BLOCK: + return 0; + case POP_EXCEPT: + return 1; ++ case POP_ITER: ++ return 1; + case POP_JUMP_IF_FALSE: + return 1; + case POP_JUMP_IF_NONE: +@@ -502,29 +516,29 @@ + return 1; + case BINARY_OP_ADD_UNICODE: + return 1; ++ case BINARY_OP_EXTEND: ++ return 1; + case BINARY_OP_INPLACE_ADD_UNICODE: + return 0; + case BINARY_OP_MULTIPLY_FLOAT: + return 1; + case BINARY_OP_MULTIPLY_INT: + return 1; +- case BINARY_OP_SUBTRACT_FLOAT: +- return 1; +- case BINARY_OP_SUBTRACT_INT: ++ case BINARY_OP_SUBSCR_DICT: + return 1; +- case BINARY_SLICE: ++ case BINARY_OP_SUBSCR_GETITEM: ++ return 0; ++ case BINARY_OP_SUBSCR_LIST_INT: + return 1; +- case BINARY_SUBSCR: ++ case BINARY_OP_SUBSCR_STR_INT: + return 1; +- case BINARY_SUBSCR_DICT: ++ case BINARY_OP_SUBSCR_TUPLE_INT: + return 1; +- case BINARY_SUBSCR_GETITEM: +- return 0; +- case BINARY_SUBSCR_LIST_INT: ++ case BINARY_OP_SUBTRACT_FLOAT: + return 1; +- case BINARY_SUBSCR_STR_INT: ++ case BINARY_OP_SUBTRACT_INT: + return 1; +- case BINARY_SUBSCR_TUPLE_INT: ++ case BINARY_SLICE: + return 1; + case BUILD_LIST: + return 1; +@@ -683,9 +697,9 @@ + case INSTRUMENTED_CALL: + return 1; + case INSTRUMENTED_CALL_FUNCTION_EX: +- return 0; ++ return 1; + case INSTRUMENTED_CALL_KW: +- return 0; ++ return 1; + case INSTRUMENTED_END_FOR: + return 1; + case INSTRUMENTED_END_SEND: +@@ -701,6 +715,10 @@ + case INSTRUMENTED_LINE: + return 0; + case INSTRUMENTED_LOAD_SUPER_ATTR: ++ return 1 + (oparg & 1); ++ case INSTRUMENTED_NOT_TAKEN: ++ return 0; ++ case INSTRUMENTED_POP_ITER: + return 0; + case INSTRUMENTED_POP_JUMP_IF_FALSE: + return 0; +@@ -724,8 +742,12 @@ + return 0; + case JUMP_BACKWARD: + return 0; ++ case JUMP_BACKWARD_JIT: ++ return 0; + case JUMP_BACKWARD_NO_INTERRUPT: + return 0; ++ case JUMP_BACKWARD_NO_JIT: ++ return 0; + case JUMP_FORWARD: + return 0; + case JUMP_IF_FALSE: +@@ -739,7 +761,7 @@ + case LIST_EXTEND: + return 1 + (oparg-1); + case LOAD_ATTR: +- return 1 + (oparg & 1); ++ return 1 + (oparg&1); + case LOAD_ATTR_CLASS: + return 1 + (oparg & 1); + case LOAD_ATTR_CLASS_WITH_METACLASS_CHECK: +@@ -776,6 +798,8 @@ + return 1; + case LOAD_CONST_IMMORTAL: + return 1; ++ case LOAD_CONST_MORTAL: ++ return 1; + case LOAD_DEREF: + return 1; + case LOAD_FAST: +@@ -826,10 +850,14 @@ + return 2; + case NOP: + return 0; ++ case NOT_TAKEN: ++ return 0; + case POP_BLOCK: + return 0; + case POP_EXCEPT: + return 0; ++ case POP_ITER: ++ return 0; + case POP_JUMP_IF_FALSE: + return 0; + case POP_JUMP_IF_NONE: +@@ -954,7 +982,7 @@ + int _PyOpcode_max_stack_effect(int opcode, int oparg, int *effect) { + switch(opcode) { + case BINARY_OP: { +- *effect = 0; ++ *effect = 1; + return 0; + } + case BINARY_OP_ADD_FLOAT: { +@@ -969,6 +997,10 @@ + *effect = 0; + return 0; + } ++ case BINARY_OP_EXTEND: { ++ *effect = 0; ++ return 0; ++ } + case BINARY_OP_INPLACE_ADD_UNICODE: { + *effect = 0; + return 0; +@@ -981,40 +1013,36 @@ + *effect = 0; + return 0; + } +- case BINARY_OP_SUBTRACT_FLOAT: { +- *effect = 0; ++ case BINARY_OP_SUBSCR_DICT: { ++ *effect = -1; + return 0; + } +- case BINARY_OP_SUBTRACT_INT: { +- *effect = 0; ++ case BINARY_OP_SUBSCR_GETITEM: { ++ *effect = 1; + return 0; + } +- case BINARY_SLICE: { +- *effect = 0; ++ case BINARY_OP_SUBSCR_LIST_INT: { ++ *effect = -1; + return 0; + } +- case BINARY_SUBSCR: { +- *effect = 0; ++ case BINARY_OP_SUBSCR_STR_INT: { ++ *effect = -1; + return 0; + } +- case BINARY_SUBSCR_DICT: { ++ case BINARY_OP_SUBSCR_TUPLE_INT: { + *effect = -1; + return 0; + } +- case BINARY_SUBSCR_GETITEM: { ++ case BINARY_OP_SUBTRACT_FLOAT: { + *effect = 0; + return 0; + } +- case BINARY_SUBSCR_LIST_INT: { +- *effect = -1; +- return 0; +- } +- case BINARY_SUBSCR_STR_INT: { +- *effect = -1; ++ case BINARY_OP_SUBTRACT_INT: { ++ *effect = 0; + return 0; + } +- case BINARY_SUBSCR_TUPLE_INT: { +- *effect = -1; ++ case BINARY_SLICE: { ++ *effect = 0; + return 0; + } + case BUILD_LIST: { +@@ -1030,7 +1058,7 @@ + return 0; + } + case BUILD_SLICE: { +- *effect = -1 - ((oparg == 3) ? 1 : 0); ++ *effect = 1 - oparg; + return 0; + } + case BUILD_STRING: { +@@ -1086,7 +1114,7 @@ + return 0; + } + case CALL_FUNCTION_EX: { +- *effect = Py_MAX(0, -2 - (oparg & 1)); ++ *effect = 0; + return 0; + } + case CALL_INTRINSIC_1: { +@@ -1352,7 +1380,7 @@ + return 0; + } + case INSTRUMENTED_CALL_KW: { +- *effect = 0; ++ *effect = Py_MAX(0, -2 - oparg); + return 0; + } + case INSTRUMENTED_END_FOR: { +@@ -1384,9 +1412,17 @@ + return 0; + } + case INSTRUMENTED_LOAD_SUPER_ATTR: { ++ *effect = Py_MAX(-2, -2 + (oparg & 1)); ++ return 0; ++ } ++ case INSTRUMENTED_NOT_TAKEN: { + *effect = 0; + return 0; + } ++ case INSTRUMENTED_POP_ITER: { ++ *effect = -1; ++ return 0; ++ } + case INSTRUMENTED_POP_JUMP_IF_FALSE: { + *effect = 0; + return 0; +@@ -1431,10 +1467,18 @@ + *effect = 0; + return 0; + } ++ case JUMP_BACKWARD_JIT: { ++ *effect = 0; ++ return 0; ++ } + case JUMP_BACKWARD_NO_INTERRUPT: { + *effect = 0; + return 0; + } ++ case JUMP_BACKWARD_NO_JIT: { ++ *effect = 0; ++ return 0; ++ } + case JUMP_FORWARD: { + *effect = 0; + return 0; +@@ -1460,7 +1504,9 @@ + return 0; + } + case LOAD_ATTR: { +- *effect = Py_MAX(1, (oparg & 1)); ++ int max_eff = Py_MAX(1, (oparg & 1)); ++ max_eff = Py_MAX(max_eff, (oparg&1)); ++ *effect = max_eff; + return 0; + } + case LOAD_ATTR_CLASS: { +@@ -1512,7 +1558,7 @@ + return 0; + } + case LOAD_ATTR_WITH_HINT: { +- *effect = Py_MAX(0, (oparg & 1)); ++ *effect = Py_MAX(1, (oparg & 1)); + return 0; + } + case LOAD_BUILD_CLASS: { +@@ -1535,6 +1581,10 @@ + *effect = 1; + return 0; + } ++ case LOAD_CONST_MORTAL: { ++ *effect = 1; ++ return 0; ++ } + case LOAD_DEREF: { + *effect = 1; + return 0; +@@ -1635,6 +1685,10 @@ + *effect = 0; + return 0; + } ++ case NOT_TAKEN: { ++ *effect = 0; ++ return 0; ++ } + case POP_BLOCK: { + *effect = 0; + return 0; +@@ -1643,6 +1697,10 @@ + *effect = -1; + return 0; + } ++ case POP_ITER: { ++ *effect = -1; ++ return 0; ++ } + case POP_JUMP_IF_FALSE: { + *effect = -1; + return 0; +@@ -1879,11 +1937,13 @@ + INSTR_FMT_IBC = 2, + INSTR_FMT_IBC00 = 3, + INSTR_FMT_IBC000 = 4, +- INSTR_FMT_IBC00000000 = 5, +- INSTR_FMT_IX = 6, +- INSTR_FMT_IXC = 7, +- INSTR_FMT_IXC00 = 8, +- INSTR_FMT_IXC000 = 9, ++ INSTR_FMT_IBC0000 = 5, ++ INSTR_FMT_IBC00000000 = 6, ++ INSTR_FMT_IX = 7, ++ INSTR_FMT_IXC = 8, ++ INSTR_FMT_IXC00 = 9, ++ INSTR_FMT_IXC000 = 10, ++ INSTR_FMT_IXC0000 = 11, + }; + + #define IS_VALID_OPCODE(OP) \ +@@ -1905,6 +1965,7 @@ + #define HAS_PASSTHROUGH_FLAG (4096) + #define HAS_OPARG_AND_1_FLAG (8192) + #define HAS_ERROR_NO_POP_FLAG (16384) ++#define HAS_NO_SAVE_IP_FLAG (32768) + #define OPCODE_HAS_ARG(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_ARG_FLAG)) + #define OPCODE_HAS_CONST(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_CONST_FLAG)) + #define OPCODE_HAS_NAME(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_NAME_FLAG)) +@@ -1920,6 +1981,7 @@ + #define OPCODE_HAS_PASSTHROUGH(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_PASSTHROUGH_FLAG)) + #define OPCODE_HAS_OPARG_AND_1(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_OPARG_AND_1_FLAG)) + #define OPCODE_HAS_ERROR_NO_POP(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_ERROR_NO_POP_FLAG)) ++#define OPCODE_HAS_NO_SAVE_IP(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_NO_SAVE_IP_FLAG)) + + #define OPARG_FULL 0 + #define OPARG_CACHE_1 1 +@@ -1932,45 +1994,45 @@ + + struct opcode_metadata { + uint8_t valid_entry; +- int8_t instr_format; +- int16_t flags; ++ uint8_t instr_format; ++ uint16_t flags; + }; + + extern const struct opcode_metadata _PyOpcode_opcode_metadata[266]; + #ifdef NEED_OPCODE_METADATA + const struct opcode_metadata _PyOpcode_opcode_metadata[266] = { +- [BINARY_OP] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, +- [BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, +- [BINARY_OP_ADD_INT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, +- [BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, +- [BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IXC, HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG }, +- [BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, +- [BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, +- [BINARY_OP_SUBTRACT_FLOAT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, +- [BINARY_OP_SUBTRACT_INT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, ++ [BINARY_OP] = { true, INSTR_FMT_IBC0000, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, ++ [BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, ++ [BINARY_OP_ADD_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, ++ [BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, ++ [BINARY_OP_EXTEND] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, ++ [BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IXC0000, HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG }, ++ [BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, ++ [BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, ++ [BINARY_OP_SUBSCR_DICT] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, ++ [BINARY_OP_SUBSCR_GETITEM] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG }, ++ [BINARY_OP_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, ++ [BINARY_OP_SUBSCR_STR_INT] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, ++ [BINARY_OP_SUBSCR_TUPLE_INT] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, ++ [BINARY_OP_SUBTRACT_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, ++ [BINARY_OP_SUBTRACT_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, + [BINARY_SLICE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, +- [BINARY_SUBSCR] = { true, INSTR_FMT_IXC, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, +- [BINARY_SUBSCR_DICT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, +- [BINARY_SUBSCR_GETITEM] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG }, +- [BINARY_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, +- [BINARY_SUBSCR_STR_INT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG }, +- [BINARY_SUBSCR_TUPLE_INT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG }, +- [BUILD_LIST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG }, ++ [BUILD_LIST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG }, + [BUILD_MAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [BUILD_SET] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [BUILD_SLICE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG }, + [BUILD_STRING] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG }, +- [BUILD_TUPLE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG }, ++ [BUILD_TUPLE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG }, + [CACHE] = { true, INSTR_FMT_IX, 0 }, + [CALL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [CALL_ALLOC_AND_ENTER_INIT] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, +- [CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, ++ [CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, + [CALL_BOUND_METHOD_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [CALL_BUILTIN_CLASS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [CALL_BUILTIN_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [CALL_BUILTIN_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, +- [CALL_FUNCTION_EX] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, ++ [CALL_FUNCTION_EX] = { true, INSTR_FMT_IX, HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [CALL_INTRINSIC_1] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [CALL_INTRINSIC_2] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [CALL_ISINSTANCE] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, +@@ -1979,7 +2041,7 @@ + [CALL_KW_NON_PY] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [CALL_KW_PY] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [CALL_LEN] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, +- [CALL_LIST_APPEND] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG }, ++ [CALL_LIST_APPEND] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [CALL_METHOD_DESCRIPTOR_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [CALL_METHOD_DESCRIPTOR_NOARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, +@@ -1989,7 +2051,7 @@ + [CALL_PY_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [CALL_STR_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [CALL_TUPLE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, +- [CALL_TYPE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, ++ [CALL_TYPE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, + [CHECK_EG_MATCH] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [CHECK_EXC_MATCH] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [CLEANUP_THROW] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, +@@ -2012,7 +2074,7 @@ + [DICT_MERGE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [DICT_UPDATE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [END_ASYNC_FOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, +- [END_FOR] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, ++ [END_FOR] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG | HAS_NO_SAVE_IP_FLAG }, + [END_SEND] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, + [ENTER_EXECUTOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [EXIT_INIT_CHECK] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, +@@ -2021,9 +2083,9 @@ + [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 }, + [FOR_ITER_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, +- [FOR_ITER_LIST] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG }, ++ [FOR_ITER_LIST] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, + [FOR_ITER_RANGE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG }, +- [FOR_ITER_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG }, ++ [FOR_ITER_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, + [GET_AITER] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [GET_ANEXT] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [GET_AWAITABLE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, +@@ -2033,19 +2095,21 @@ + [IMPORT_FROM] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [IMPORT_NAME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [INSTRUMENTED_CALL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, +- [INSTRUMENTED_CALL_FUNCTION_EX] = { true, INSTR_FMT_IX, 0 }, +- [INSTRUMENTED_CALL_KW] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, +- [INSTRUMENTED_END_FOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, ++ [INSTRUMENTED_CALL_FUNCTION_EX] = { true, INSTR_FMT_IX, HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, ++ [INSTRUMENTED_CALL_KW] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, ++ [INSTRUMENTED_END_FOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_NO_SAVE_IP_FLAG }, + [INSTRUMENTED_END_SEND] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, +- [INSTRUMENTED_FOR_ITER] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, ++ [INSTRUMENTED_FOR_ITER] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [INSTRUMENTED_INSTRUCTION] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [INSTRUMENTED_JUMP_BACKWARD] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [INSTRUMENTED_JUMP_FORWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [INSTRUMENTED_LINE] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG }, +- [INSTRUMENTED_LOAD_SUPER_ATTR] = { true, INSTR_FMT_IXC, 0 }, ++ [INSTRUMENTED_LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, ++ [INSTRUMENTED_NOT_TAKEN] = { true, INSTR_FMT_IX, 0 }, ++ [INSTRUMENTED_POP_ITER] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG }, + [INSTRUMENTED_POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, +- [INSTRUMENTED_POP_JUMP_IF_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, +- [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, ++ [INSTRUMENTED_POP_JUMP_IF_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_ESCAPES_FLAG }, ++ [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_ESCAPES_FLAG }, + [INSTRUMENTED_POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, + [INSTRUMENTED_RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [INSTRUMENTED_RETURN_VALUE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, +@@ -2053,7 +2117,9 @@ + [INTERPRETER_EXIT] = { true, INSTR_FMT_IX, 0 }, + [IS_OP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [JUMP_BACKWARD] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, ++ [JUMP_BACKWARD_JIT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [JUMP_BACKWARD_NO_INTERRUPT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, ++ [JUMP_BACKWARD_NO_JIT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [JUMP_FORWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, + [LIST_APPEND] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG }, + [LIST_EXTEND] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, +@@ -2061,11 +2127,11 @@ + [LOAD_ATTR_CLASS] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG }, + [LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG }, + [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG }, +- [LOAD_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, ++ [LOAD_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, + [LOAD_ATTR_METHOD_LAZY_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, + [LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG }, + [LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, +- [LOAD_ATTR_MODULE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, ++ [LOAD_ATTR_MODULE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, + [LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG }, + [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, + [LOAD_ATTR_PROPERTY] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, +@@ -2073,8 +2139,9 @@ + [LOAD_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, + [LOAD_BUILD_CLASS] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [LOAD_COMMON_CONSTANT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, +- [LOAD_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG | HAS_PURE_FLAG }, ++ [LOAD_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG }, + [LOAD_CONST_IMMORTAL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG }, ++ [LOAD_CONST_MORTAL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG }, + [LOAD_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_PURE_FLAG }, + [LOAD_FAST_AND_CLEAR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, +@@ -2091,8 +2158,8 @@ + [LOAD_SPECIAL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [LOAD_SUPER_ATTR_ATTR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, +- [LOAD_SUPER_ATTR_METHOD] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, +- [MAKE_CELL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG }, ++ [LOAD_SUPER_ATTR_METHOD] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, ++ [MAKE_CELL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [MAKE_FUNCTION] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [MAP_ADD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [MATCH_CLASS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, +@@ -2100,7 +2167,9 @@ + [MATCH_MAPPING] = { true, INSTR_FMT_IX, 0 }, + [MATCH_SEQUENCE] = { true, INSTR_FMT_IX, 0 }, + [NOP] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, ++ [NOT_TAKEN] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, + [POP_EXCEPT] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG }, ++ [POP_ITER] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, + [POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, + [POP_JUMP_IF_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, + [POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, +@@ -2122,19 +2191,19 @@ + [SET_FUNCTION_ATTRIBUTE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [SET_UPDATE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [STORE_ATTR] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, +- [STORE_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IXC000, HAS_EXIT_FLAG }, +- [STORE_ATTR_SLOT] = { true, INSTR_FMT_IXC000, HAS_EXIT_FLAG }, ++ [STORE_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IXC000, HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, ++ [STORE_ATTR_SLOT] = { true, INSTR_FMT_IXC000, HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, + [STORE_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, + [STORE_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ESCAPES_FLAG }, +- [STORE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, +- [STORE_FAST_LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, +- [STORE_FAST_STORE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, ++ [STORE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG }, ++ [STORE_FAST_LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG }, ++ [STORE_FAST_STORE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG }, + [STORE_GLOBAL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [STORE_NAME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [STORE_SLICE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [STORE_SUBSCR] = { true, INSTR_FMT_IXC, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [STORE_SUBSCR_DICT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, +- [STORE_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG }, ++ [STORE_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, + [SWAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_PURE_FLAG }, + [TO_BOOL] = { true, INSTR_FMT_IXC00, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [TO_BOOL_ALWAYS_TRUE] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG }, +@@ -2162,7 +2231,7 @@ + [SETUP_CLEANUP] = { true, -1, HAS_PURE_FLAG | HAS_ARG_FLAG }, + [SETUP_FINALLY] = { true, -1, HAS_PURE_FLAG | HAS_ARG_FLAG }, + [SETUP_WITH] = { true, -1, HAS_PURE_FLAG | HAS_ARG_FLAG }, +- [STORE_FAST_MAYBE_NULL] = { true, -1, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, ++ [STORE_FAST_MAYBE_NULL] = { true, -1, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG }, + }; + #endif + +@@ -2180,18 +2249,18 @@ + [BINARY_OP_ADD_FLOAT] = { .nuops = 2, .uops = { { _GUARD_BOTH_FLOAT, 0, 0 }, { _BINARY_OP_ADD_FLOAT, 0, 0 } } }, + [BINARY_OP_ADD_INT] = { .nuops = 2, .uops = { { _GUARD_BOTH_INT, 0, 0 }, { _BINARY_OP_ADD_INT, 0, 0 } } }, + [BINARY_OP_ADD_UNICODE] = { .nuops = 2, .uops = { { _GUARD_BOTH_UNICODE, 0, 0 }, { _BINARY_OP_ADD_UNICODE, 0, 0 } } }, ++ [BINARY_OP_EXTEND] = { .nuops = 2, .uops = { { _GUARD_BINARY_OP_EXTEND, 4, 1 }, { _BINARY_OP_EXTEND, 4, 1 } } }, + [BINARY_OP_INPLACE_ADD_UNICODE] = { .nuops = 2, .uops = { { _GUARD_BOTH_UNICODE, 0, 0 }, { _BINARY_OP_INPLACE_ADD_UNICODE, 0, 0 } } }, + [BINARY_OP_MULTIPLY_FLOAT] = { .nuops = 2, .uops = { { _GUARD_BOTH_FLOAT, 0, 0 }, { _BINARY_OP_MULTIPLY_FLOAT, 0, 0 } } }, + [BINARY_OP_MULTIPLY_INT] = { .nuops = 2, .uops = { { _GUARD_BOTH_INT, 0, 0 }, { _BINARY_OP_MULTIPLY_INT, 0, 0 } } }, ++ [BINARY_OP_SUBSCR_DICT] = { .nuops = 1, .uops = { { _BINARY_OP_SUBSCR_DICT, 0, 0 } } }, ++ [BINARY_OP_SUBSCR_GETITEM] = { .nuops = 4, .uops = { { _CHECK_PEP_523, 0, 0 }, { _BINARY_OP_SUBSCR_CHECK_FUNC, 0, 0 }, { _BINARY_OP_SUBSCR_INIT_CALL, 0, 0 }, { _PUSH_FRAME, 0, 0 } } }, ++ [BINARY_OP_SUBSCR_LIST_INT] = { .nuops = 1, .uops = { { _BINARY_OP_SUBSCR_LIST_INT, 0, 0 } } }, ++ [BINARY_OP_SUBSCR_STR_INT] = { .nuops = 1, .uops = { { _BINARY_OP_SUBSCR_STR_INT, 0, 0 } } }, ++ [BINARY_OP_SUBSCR_TUPLE_INT] = { .nuops = 1, .uops = { { _BINARY_OP_SUBSCR_TUPLE_INT, 0, 0 } } }, + [BINARY_OP_SUBTRACT_FLOAT] = { .nuops = 2, .uops = { { _GUARD_BOTH_FLOAT, 0, 0 }, { _BINARY_OP_SUBTRACT_FLOAT, 0, 0 } } }, + [BINARY_OP_SUBTRACT_INT] = { .nuops = 2, .uops = { { _GUARD_BOTH_INT, 0, 0 }, { _BINARY_OP_SUBTRACT_INT, 0, 0 } } }, + [BINARY_SLICE] = { .nuops = 1, .uops = { { _BINARY_SLICE, 0, 0 } } }, +- [BINARY_SUBSCR] = { .nuops = 1, .uops = { { _BINARY_SUBSCR, 0, 0 } } }, +- [BINARY_SUBSCR_DICT] = { .nuops = 1, .uops = { { _BINARY_SUBSCR_DICT, 0, 0 } } }, +- [BINARY_SUBSCR_GETITEM] = { .nuops = 4, .uops = { { _CHECK_PEP_523, 0, 0 }, { _BINARY_SUBSCR_CHECK_FUNC, 0, 0 }, { _BINARY_SUBSCR_INIT_CALL, 0, 0 }, { _PUSH_FRAME, 0, 0 } } }, +- [BINARY_SUBSCR_LIST_INT] = { .nuops = 1, .uops = { { _BINARY_SUBSCR_LIST_INT, 0, 0 } } }, +- [BINARY_SUBSCR_STR_INT] = { .nuops = 1, .uops = { { _BINARY_SUBSCR_STR_INT, 0, 0 } } }, +- [BINARY_SUBSCR_TUPLE_INT] = { .nuops = 1, .uops = { { _BINARY_SUBSCR_TUPLE_INT, 0, 0 } } }, + [BUILD_LIST] = { .nuops = 1, .uops = { { _BUILD_LIST, 0, 0 } } }, + [BUILD_MAP] = { .nuops = 1, .uops = { { _BUILD_MAP, 0, 0 } } }, + [BUILD_SET] = { .nuops = 1, .uops = { { _BUILD_SET, 0, 0 } } }, +@@ -2243,7 +2312,7 @@ + [DELETE_SUBSCR] = { .nuops = 1, .uops = { { _DELETE_SUBSCR, 0, 0 } } }, + [DICT_MERGE] = { .nuops = 1, .uops = { { _DICT_MERGE, 0, 0 } } }, + [DICT_UPDATE] = { .nuops = 1, .uops = { { _DICT_UPDATE, 0, 0 } } }, +- [END_FOR] = { .nuops = 1, .uops = { { _POP_TOP, 0, 0 } } }, ++ [END_FOR] = { .nuops = 1, .uops = { { _END_FOR, 0, 0 } } }, + [END_SEND] = { .nuops = 1, .uops = { { _END_SEND, 0, 0 } } }, + [EXIT_INIT_CHECK] = { .nuops = 1, .uops = { { _EXIT_INIT_CHECK, 0, 0 } } }, + [FORMAT_SIMPLE] = { .nuops = 1, .uops = { { _FORMAT_SIMPLE, 0, 0 } } }, +@@ -2265,31 +2334,31 @@ + [LIST_APPEND] = { .nuops = 1, .uops = { { _LIST_APPEND, 0, 0 } } }, + [LIST_EXTEND] = { .nuops = 1, .uops = { { _LIST_EXTEND, 0, 0 } } }, + [LOAD_ATTR] = { .nuops = 1, .uops = { { _LOAD_ATTR, 0, 0 } } }, +- [LOAD_ATTR_CLASS] = { .nuops = 2, .uops = { { _CHECK_ATTR_CLASS, 2, 1 }, { _LOAD_ATTR_CLASS, 4, 5 } } }, +- [LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = { .nuops = 3, .uops = { { _CHECK_ATTR_CLASS, 2, 1 }, { _GUARD_TYPE_VERSION, 2, 3 }, { _LOAD_ATTR_CLASS, 4, 5 } } }, +- [LOAD_ATTR_INSTANCE_VALUE] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_MANAGED_OBJECT_HAS_VALUES, 0, 0 }, { _LOAD_ATTR_INSTANCE_VALUE, 1, 3 } } }, ++ [LOAD_ATTR_CLASS] = { .nuops = 3, .uops = { { _CHECK_ATTR_CLASS, 2, 1 }, { _LOAD_ATTR_CLASS, 4, 5 }, { _PUSH_NULL_CONDITIONAL, 0, 0 } } }, ++ [LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = { .nuops = 4, .uops = { { _CHECK_ATTR_CLASS, 2, 1 }, { _GUARD_TYPE_VERSION, 2, 3 }, { _LOAD_ATTR_CLASS, 4, 5 }, { _PUSH_NULL_CONDITIONAL, 0, 0 } } }, ++ [LOAD_ATTR_INSTANCE_VALUE] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_MANAGED_OBJECT_HAS_VALUES, 0, 0 }, { _LOAD_ATTR_INSTANCE_VALUE, 1, 3 }, { _PUSH_NULL_CONDITIONAL, 0, 0 } } }, + [LOAD_ATTR_METHOD_LAZY_DICT] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_ATTR_METHOD_LAZY_DICT, 1, 3 }, { _LOAD_ATTR_METHOD_LAZY_DICT, 4, 5 } } }, + [LOAD_ATTR_METHOD_NO_DICT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_METHOD_NO_DICT, 4, 5 } } }, + [LOAD_ATTR_METHOD_WITH_VALUES] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, 0, 0 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_METHOD_WITH_VALUES, 4, 5 } } }, +- [LOAD_ATTR_MODULE] = { .nuops = 2, .uops = { { _CHECK_ATTR_MODULE_PUSH_KEYS, 2, 1 }, { _LOAD_ATTR_MODULE_FROM_KEYS, 1, 3 } } }, ++ [LOAD_ATTR_MODULE] = { .nuops = 3, .uops = { { _CHECK_ATTR_MODULE_PUSH_KEYS, 2, 1 }, { _LOAD_ATTR_MODULE_FROM_KEYS, 1, 3 }, { _PUSH_NULL_CONDITIONAL, 0, 0 } } }, + [LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_NONDESCRIPTOR_NO_DICT, 4, 5 } } }, + [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, 0, 0 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, 4, 5 } } }, + [LOAD_ATTR_PROPERTY] = { .nuops = 5, .uops = { { _CHECK_PEP_523, 0, 0 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_PROPERTY_FRAME, 4, 5 }, { _SAVE_RETURN_OFFSET, 7, 9 }, { _PUSH_FRAME, 0, 0 } } }, +- [LOAD_ATTR_SLOT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_SLOT, 1, 3 } } }, +- [LOAD_ATTR_WITH_HINT] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_ATTR_WITH_HINT, 0, 0 }, { _LOAD_ATTR_WITH_HINT, 1, 3 } } }, ++ [LOAD_ATTR_SLOT] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_SLOT, 1, 3 }, { _PUSH_NULL_CONDITIONAL, 0, 0 } } }, ++ [LOAD_ATTR_WITH_HINT] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_ATTR_WITH_HINT, 0, 0 }, { _LOAD_ATTR_WITH_HINT, 1, 3 }, { _PUSH_NULL_CONDITIONAL, 0, 0 } } }, + [LOAD_BUILD_CLASS] = { .nuops = 1, .uops = { { _LOAD_BUILD_CLASS, 0, 0 } } }, + [LOAD_COMMON_CONSTANT] = { .nuops = 1, .uops = { { _LOAD_COMMON_CONSTANT, 0, 0 } } }, +- [LOAD_CONST] = { .nuops = 1, .uops = { { _LOAD_CONST, 0, 0 } } }, + [LOAD_CONST_IMMORTAL] = { .nuops = 1, .uops = { { _LOAD_CONST_IMMORTAL, 0, 0 } } }, ++ [LOAD_CONST_MORTAL] = { .nuops = 1, .uops = { { _LOAD_CONST_MORTAL, 0, 0 } } }, + [LOAD_DEREF] = { .nuops = 1, .uops = { { _LOAD_DEREF, 0, 0 } } }, + [LOAD_FAST] = { .nuops = 1, .uops = { { _LOAD_FAST, 0, 0 } } }, + [LOAD_FAST_AND_CLEAR] = { .nuops = 1, .uops = { { _LOAD_FAST_AND_CLEAR, 0, 0 } } }, + [LOAD_FAST_CHECK] = { .nuops = 1, .uops = { { _LOAD_FAST_CHECK, 0, 0 } } }, + [LOAD_FAST_LOAD_FAST] = { .nuops = 2, .uops = { { _LOAD_FAST, 5, 0 }, { _LOAD_FAST, 6, 0 } } }, + [LOAD_FROM_DICT_OR_DEREF] = { .nuops = 1, .uops = { { _LOAD_FROM_DICT_OR_DEREF, 0, 0 } } }, +- [LOAD_GLOBAL] = { .nuops = 1, .uops = { { _LOAD_GLOBAL, 0, 0 } } }, +- [LOAD_GLOBAL_BUILTIN] = { .nuops = 3, .uops = { { _GUARD_GLOBALS_VERSION, 1, 1 }, { _GUARD_BUILTINS_VERSION_PUSH_KEYS, 1, 2 }, { _LOAD_GLOBAL_BUILTINS_FROM_KEYS, 1, 3 } } }, +- [LOAD_GLOBAL_MODULE] = { .nuops = 2, .uops = { { _GUARD_GLOBALS_VERSION_PUSH_KEYS, 1, 1 }, { _LOAD_GLOBAL_MODULE_FROM_KEYS, 1, 3 } } }, ++ [LOAD_GLOBAL] = { .nuops = 2, .uops = { { _LOAD_GLOBAL, 0, 0 }, { _PUSH_NULL_CONDITIONAL, 0, 0 } } }, ++ [LOAD_GLOBAL_BUILTIN] = { .nuops = 4, .uops = { { _GUARD_GLOBALS_VERSION, 1, 1 }, { _GUARD_BUILTINS_VERSION_PUSH_KEYS, 1, 2 }, { _LOAD_GLOBAL_BUILTINS_FROM_KEYS, 1, 3 }, { _PUSH_NULL_CONDITIONAL, 0, 0 } } }, ++ [LOAD_GLOBAL_MODULE] = { .nuops = 3, .uops = { { _GUARD_GLOBALS_VERSION_PUSH_KEYS, 1, 1 }, { _LOAD_GLOBAL_MODULE_FROM_KEYS, 1, 3 }, { _PUSH_NULL_CONDITIONAL, 0, 0 } } }, + [LOAD_LOCALS] = { .nuops = 1, .uops = { { _LOAD_LOCALS, 0, 0 } } }, + [LOAD_NAME] = { .nuops = 1, .uops = { { _LOAD_NAME, 0, 0 } } }, + [LOAD_SMALL_INT] = { .nuops = 1, .uops = { { _LOAD_SMALL_INT, 0, 0 } } }, +@@ -2304,7 +2373,9 @@ + [MATCH_MAPPING] = { .nuops = 1, .uops = { { _MATCH_MAPPING, 0, 0 } } }, + [MATCH_SEQUENCE] = { .nuops = 1, .uops = { { _MATCH_SEQUENCE, 0, 0 } } }, + [NOP] = { .nuops = 1, .uops = { { _NOP, 0, 0 } } }, ++ [NOT_TAKEN] = { .nuops = 1, .uops = { { _NOP, 0, 0 } } }, + [POP_EXCEPT] = { .nuops = 1, .uops = { { _POP_EXCEPT, 0, 0 } } }, ++ [POP_ITER] = { .nuops = 1, .uops = { { _POP_TOP, 0, 0 } } }, + [POP_JUMP_IF_FALSE] = { .nuops = 1, .uops = { { _POP_JUMP_IF_FALSE, 9, 1 } } }, + [POP_JUMP_IF_NONE] = { .nuops = 2, .uops = { { _IS_NONE, 0, 0 }, { _POP_JUMP_IF_TRUE, 9, 1 } } }, + [POP_JUMP_IF_NOT_NONE] = { .nuops = 2, .uops = { { _IS_NONE, 0, 0 }, { _POP_JUMP_IF_FALSE, 9, 1 } } }, +@@ -2321,7 +2392,7 @@ + [SET_FUNCTION_ATTRIBUTE] = { .nuops = 1, .uops = { { _SET_FUNCTION_ATTRIBUTE, 0, 0 } } }, + [SET_UPDATE] = { .nuops = 1, .uops = { { _SET_UPDATE, 0, 0 } } }, + [STORE_ATTR] = { .nuops = 1, .uops = { { _STORE_ATTR, 0, 0 } } }, +- [STORE_ATTR_INSTANCE_VALUE] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_NO_DICT, 0, 0 }, { _STORE_ATTR_INSTANCE_VALUE, 1, 3 } } }, ++ [STORE_ATTR_INSTANCE_VALUE] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION_AND_LOCK, 2, 1 }, { _GUARD_DORV_NO_DICT, 0, 0 }, { _STORE_ATTR_INSTANCE_VALUE, 1, 3 } } }, + [STORE_ATTR_SLOT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _STORE_ATTR_SLOT, 1, 3 } } }, + [STORE_ATTR_WITH_HINT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _STORE_ATTR_WITH_HINT, 1, 3 } } }, + [STORE_DEREF] = { .nuops = 1, .uops = { { _STORE_DEREF, 0, 0 } } }, +@@ -2362,18 +2433,18 @@ + [BINARY_OP_ADD_FLOAT] = "BINARY_OP_ADD_FLOAT", + [BINARY_OP_ADD_INT] = "BINARY_OP_ADD_INT", + [BINARY_OP_ADD_UNICODE] = "BINARY_OP_ADD_UNICODE", ++ [BINARY_OP_EXTEND] = "BINARY_OP_EXTEND", + [BINARY_OP_INPLACE_ADD_UNICODE] = "BINARY_OP_INPLACE_ADD_UNICODE", + [BINARY_OP_MULTIPLY_FLOAT] = "BINARY_OP_MULTIPLY_FLOAT", + [BINARY_OP_MULTIPLY_INT] = "BINARY_OP_MULTIPLY_INT", ++ [BINARY_OP_SUBSCR_DICT] = "BINARY_OP_SUBSCR_DICT", ++ [BINARY_OP_SUBSCR_GETITEM] = "BINARY_OP_SUBSCR_GETITEM", ++ [BINARY_OP_SUBSCR_LIST_INT] = "BINARY_OP_SUBSCR_LIST_INT", ++ [BINARY_OP_SUBSCR_STR_INT] = "BINARY_OP_SUBSCR_STR_INT", ++ [BINARY_OP_SUBSCR_TUPLE_INT] = "BINARY_OP_SUBSCR_TUPLE_INT", + [BINARY_OP_SUBTRACT_FLOAT] = "BINARY_OP_SUBTRACT_FLOAT", + [BINARY_OP_SUBTRACT_INT] = "BINARY_OP_SUBTRACT_INT", + [BINARY_SLICE] = "BINARY_SLICE", +- [BINARY_SUBSCR] = "BINARY_SUBSCR", +- [BINARY_SUBSCR_DICT] = "BINARY_SUBSCR_DICT", +- [BINARY_SUBSCR_GETITEM] = "BINARY_SUBSCR_GETITEM", +- [BINARY_SUBSCR_LIST_INT] = "BINARY_SUBSCR_LIST_INT", +- [BINARY_SUBSCR_STR_INT] = "BINARY_SUBSCR_STR_INT", +- [BINARY_SUBSCR_TUPLE_INT] = "BINARY_SUBSCR_TUPLE_INT", + [BUILD_LIST] = "BUILD_LIST", + [BUILD_MAP] = "BUILD_MAP", + [BUILD_SET] = "BUILD_SET", +@@ -2462,6 +2533,8 @@ + [INSTRUMENTED_JUMP_FORWARD] = "INSTRUMENTED_JUMP_FORWARD", + [INSTRUMENTED_LINE] = "INSTRUMENTED_LINE", + [INSTRUMENTED_LOAD_SUPER_ATTR] = "INSTRUMENTED_LOAD_SUPER_ATTR", ++ [INSTRUMENTED_NOT_TAKEN] = "INSTRUMENTED_NOT_TAKEN", ++ [INSTRUMENTED_POP_ITER] = "INSTRUMENTED_POP_ITER", + [INSTRUMENTED_POP_JUMP_IF_FALSE] = "INSTRUMENTED_POP_JUMP_IF_FALSE", + [INSTRUMENTED_POP_JUMP_IF_NONE] = "INSTRUMENTED_POP_JUMP_IF_NONE", + [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = "INSTRUMENTED_POP_JUMP_IF_NOT_NONE", +@@ -2473,7 +2546,9 @@ + [IS_OP] = "IS_OP", + [JUMP] = "JUMP", + [JUMP_BACKWARD] = "JUMP_BACKWARD", ++ [JUMP_BACKWARD_JIT] = "JUMP_BACKWARD_JIT", + [JUMP_BACKWARD_NO_INTERRUPT] = "JUMP_BACKWARD_NO_INTERRUPT", ++ [JUMP_BACKWARD_NO_JIT] = "JUMP_BACKWARD_NO_JIT", + [JUMP_FORWARD] = "JUMP_FORWARD", + [JUMP_IF_FALSE] = "JUMP_IF_FALSE", + [JUMP_IF_TRUE] = "JUMP_IF_TRUE", +@@ -2499,6 +2574,7 @@ + [LOAD_COMMON_CONSTANT] = "LOAD_COMMON_CONSTANT", + [LOAD_CONST] = "LOAD_CONST", + [LOAD_CONST_IMMORTAL] = "LOAD_CONST_IMMORTAL", ++ [LOAD_CONST_MORTAL] = "LOAD_CONST_MORTAL", + [LOAD_DEREF] = "LOAD_DEREF", + [LOAD_FAST] = "LOAD_FAST", + [LOAD_FAST_AND_CLEAR] = "LOAD_FAST_AND_CLEAR", +@@ -2524,8 +2600,10 @@ + [MATCH_MAPPING] = "MATCH_MAPPING", + [MATCH_SEQUENCE] = "MATCH_SEQUENCE", + [NOP] = "NOP", ++ [NOT_TAKEN] = "NOT_TAKEN", + [POP_BLOCK] = "POP_BLOCK", + [POP_EXCEPT] = "POP_EXCEPT", ++ [POP_ITER] = "POP_ITER", + [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE", + [POP_JUMP_IF_NONE] = "POP_JUMP_IF_NONE", + [POP_JUMP_IF_NOT_NONE] = "POP_JUMP_IF_NOT_NONE", +@@ -2589,7 +2667,6 @@ + #ifdef NEED_OPCODE_METADATA + const uint8_t _PyOpcode_Caches[256] = { + [TO_BOOL] = 3, +- [BINARY_SUBSCR] = 1, + [STORE_SUBSCR] = 1, + [SEND] = 1, + [UNPACK_SEQUENCE] = 1, +@@ -2607,7 +2684,7 @@ + [FOR_ITER] = 1, + [CALL] = 3, + [CALL_KW] = 3, +- [BINARY_OP] = 1, ++ [BINARY_OP] = 5, + }; + #endif + +@@ -2618,18 +2695,18 @@ + [BINARY_OP_ADD_FLOAT] = BINARY_OP, + [BINARY_OP_ADD_INT] = BINARY_OP, + [BINARY_OP_ADD_UNICODE] = BINARY_OP, ++ [BINARY_OP_EXTEND] = BINARY_OP, + [BINARY_OP_INPLACE_ADD_UNICODE] = BINARY_OP, + [BINARY_OP_MULTIPLY_FLOAT] = BINARY_OP, + [BINARY_OP_MULTIPLY_INT] = BINARY_OP, ++ [BINARY_OP_SUBSCR_DICT] = BINARY_OP, ++ [BINARY_OP_SUBSCR_GETITEM] = BINARY_OP, ++ [BINARY_OP_SUBSCR_LIST_INT] = BINARY_OP, ++ [BINARY_OP_SUBSCR_STR_INT] = BINARY_OP, ++ [BINARY_OP_SUBSCR_TUPLE_INT] = BINARY_OP, + [BINARY_OP_SUBTRACT_FLOAT] = BINARY_OP, + [BINARY_OP_SUBTRACT_INT] = BINARY_OP, + [BINARY_SLICE] = BINARY_SLICE, +- [BINARY_SUBSCR] = BINARY_SUBSCR, +- [BINARY_SUBSCR_DICT] = BINARY_SUBSCR, +- [BINARY_SUBSCR_GETITEM] = BINARY_SUBSCR, +- [BINARY_SUBSCR_LIST_INT] = BINARY_SUBSCR, +- [BINARY_SUBSCR_STR_INT] = BINARY_SUBSCR, +- [BINARY_SUBSCR_TUPLE_INT] = BINARY_SUBSCR, + [BUILD_LIST] = BUILD_LIST, + [BUILD_MAP] = BUILD_MAP, + [BUILD_SET] = BUILD_SET, +@@ -2718,6 +2795,8 @@ + [INSTRUMENTED_JUMP_FORWARD] = INSTRUMENTED_JUMP_FORWARD, + [INSTRUMENTED_LINE] = INSTRUMENTED_LINE, + [INSTRUMENTED_LOAD_SUPER_ATTR] = INSTRUMENTED_LOAD_SUPER_ATTR, ++ [INSTRUMENTED_NOT_TAKEN] = INSTRUMENTED_NOT_TAKEN, ++ [INSTRUMENTED_POP_ITER] = INSTRUMENTED_POP_ITER, + [INSTRUMENTED_POP_JUMP_IF_FALSE] = INSTRUMENTED_POP_JUMP_IF_FALSE, + [INSTRUMENTED_POP_JUMP_IF_NONE] = INSTRUMENTED_POP_JUMP_IF_NONE, + [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = INSTRUMENTED_POP_JUMP_IF_NOT_NONE, +@@ -2728,7 +2807,9 @@ + [INTERPRETER_EXIT] = INTERPRETER_EXIT, + [IS_OP] = IS_OP, + [JUMP_BACKWARD] = JUMP_BACKWARD, ++ [JUMP_BACKWARD_JIT] = JUMP_BACKWARD, + [JUMP_BACKWARD_NO_INTERRUPT] = JUMP_BACKWARD_NO_INTERRUPT, ++ [JUMP_BACKWARD_NO_JIT] = JUMP_BACKWARD, + [JUMP_FORWARD] = JUMP_FORWARD, + [LIST_APPEND] = LIST_APPEND, + [LIST_EXTEND] = LIST_EXTEND, +@@ -2750,6 +2831,7 @@ + [LOAD_COMMON_CONSTANT] = LOAD_COMMON_CONSTANT, + [LOAD_CONST] = LOAD_CONST, + [LOAD_CONST_IMMORTAL] = LOAD_CONST, ++ [LOAD_CONST_MORTAL] = LOAD_CONST, + [LOAD_DEREF] = LOAD_DEREF, + [LOAD_FAST] = LOAD_FAST, + [LOAD_FAST_AND_CLEAR] = LOAD_FAST_AND_CLEAR, +@@ -2775,7 +2857,9 @@ + [MATCH_MAPPING] = MATCH_MAPPING, + [MATCH_SEQUENCE] = MATCH_SEQUENCE, + [NOP] = NOP, ++ [NOT_TAKEN] = NOT_TAKEN, + [POP_EXCEPT] = POP_EXCEPT, ++ [POP_ITER] = POP_ITER, + [POP_JUMP_IF_FALSE] = POP_JUMP_IF_FALSE, + [POP_JUMP_IF_NONE] = POP_JUMP_IF_NONE, + [POP_JUMP_IF_NOT_NONE] = POP_JUMP_IF_NOT_NONE, +@@ -2833,7 +2917,6 @@ + #endif // NEED_OPCODE_METADATA + + #define EXTRA_CASES \ +- case 116: \ + case 117: \ + case 118: \ + case 119: \ +@@ -2866,15 +2949,9 @@ + case 146: \ + case 147: \ + case 148: \ +- case 228: \ +- case 229: \ +- case 230: \ +- case 231: \ + case 232: \ + case 233: \ + case 234: \ +- case 235: \ +- case 236: \ + ; + struct pseudo_targets { + uint8_t as_sequence; +diff --git a/Include/internal/pycore_opcode_utils.h b/Include/internal/pycore_opcode_utils.h +index c6ce7e65a65..0872231d1f2 100644 +--- a/Include/internal/pycore_opcode_utils.h ++++ b/Include/internal/pycore_opcode_utils.h +@@ -45,6 +45,12 @@ + (opcode) == JUMP_BACKWARD || \ + (opcode) == JUMP_BACKWARD_NO_INTERRUPT) + ++#define IS_CONDITIONAL_JUMP_OPCODE(opcode) \ ++ ((opcode) == POP_JUMP_IF_FALSE || \ ++ (opcode) == POP_JUMP_IF_TRUE || \ ++ (opcode) == POP_JUMP_IF_NONE || \ ++ (opcode) == POP_JUMP_IF_NOT_NONE) + -+ aarch64-apple-tvos*-simulator) AR=arm64-apple-tvos-simulator-ar ;; -+ aarch64-apple-tvos*) AR=arm64-apple-tvos-ar ;; -+ x86_64-apple-tvos*-simulator) AR=x86_64-apple-tvos-simulator-ar ;; + #define IS_SCOPE_EXIT_OPCODE(opcode) \ + ((opcode) == RETURN_VALUE || \ + (opcode) == RAISE_VARARGS || \ +diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h +index bc7cfcde613..25c3d3e5a22 100644 +--- a/Include/internal/pycore_optimizer.h ++++ b/Include/internal/pycore_optimizer.h +@@ -83,28 +83,6 @@ + _PyExitData exits[1]; + } _PyExecutorObject; + +-typedef struct _PyOptimizerObject _PyOptimizerObject; +- +-/* Should return > 0 if a new executor is created. O if no executor is produced and < 0 if an error occurred. */ +-typedef int (*_Py_optimize_func)( +- _PyOptimizerObject* self, struct _PyInterpreterFrame *frame, +- _Py_CODEUNIT *instr, _PyExecutorObject **exec_ptr, +- int curr_stackentries, bool progress_needed); +- +-struct _PyOptimizerObject { +- PyObject_HEAD +- _Py_optimize_func optimize; +- /* Data needed by the optimizer goes here, but is opaque to the VM */ +-}; +- +-/** Test support **/ +-typedef struct { +- _PyOptimizerObject base; +- int64_t count; +-} _PyCounterOptimizerObject; +- +-_PyOptimizerObject *_Py_SetOptimizer(PyInterpreterState *interp, _PyOptimizerObject* optimizer); +- + + // Export for '_opcode' shared extension (JIT compiler). + PyAPI_FUNC(_PyExecutorObject*) _Py_GetExecutor(PyCodeObject *code, int offset); +@@ -115,13 +93,6 @@ + void _Py_BloomFilter_Add(_PyBloomFilter *bloom, void *obj); + PyAPI_FUNC(void) _Py_Executor_DependsOn(_PyExecutorObject *executor, void *obj); + +-// For testing +-// Export for '_testinternalcapi' shared extension. +-PyAPI_FUNC(_PyOptimizerObject *) _Py_GetOptimizer(void); +-PyAPI_FUNC(int) _Py_SetTier2Optimizer(_PyOptimizerObject* optimizer); +-PyAPI_FUNC(PyObject *) _PyOptimizer_NewCounter(void); +-PyAPI_FUNC(PyObject *) _PyOptimizer_NewUOpOptimizer(void); +- + #define _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS 3 + #define _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS 6 + +@@ -150,21 +121,8 @@ + _PyUOpInstruction *trace, int trace_len, int curr_stackentries, + _PyBloomFilter *dependencies); + +-extern PyTypeObject _PyCounterExecutor_Type; +-extern PyTypeObject _PyCounterOptimizer_Type; +-extern PyTypeObject _PyDefaultOptimizer_Type; + extern PyTypeObject _PyUOpExecutor_Type; +-extern PyTypeObject _PyUOpOptimizer_Type; + +-/* Symbols */ +-/* See explanation in optimizer_symbols.c */ +- +-struct _Py_UopsSymbol { +- int flags; // 0 bits: Top; 2 or more bits: Bottom +- PyTypeObject *typ; // Borrowed reference +- PyObject *const_val; // Owned reference (!) +- unsigned int type_version; // currently stores type version +-}; + + #define UOP_FORMAT_TARGET 0 + #define UOP_FORMAT_JUMP 1 +@@ -201,16 +159,63 @@ + // handle before rejoining the rest of the program. + #define MAX_CHAIN_DEPTH 4 + +-typedef struct _Py_UopsSymbol _Py_UopsSymbol; ++/* Symbols */ ++/* See explanation in optimizer_symbols.c */ + -+ aarch64-apple-watchos*-simulator) AR=arm64-apple-watchos-simulator-ar ;; -+ aarch64-apple-watchos*) AR=arm64_32-apple-watchos-ar ;; -+ x86_64-apple-watchos*-simulator) AR=x86_64-apple-watchos-simulator-ar ;; - *) - esac - fi -@@ -424,6 +438,14 @@ - aarch64-apple-ios*-simulator) CC=arm64-apple-ios-simulator-clang ;; - aarch64-apple-ios*) CC=arm64-apple-ios-clang ;; - x86_64-apple-ios*-simulator) CC=x86_64-apple-ios-simulator-clang ;; + -+ aarch64-apple-tvos*-simulator) CC=arm64-apple-tvos-simulator-clang ;; -+ aarch64-apple-tvos*) CC=arm64-apple-tvos-clang ;; -+ x86_64-apple-tvos*-simulator) CC=x86_64-apple-tvos-simulator-clang ;; ++typedef enum _JitSymType { ++ JIT_SYM_UNKNOWN_TAG = 1, ++ JIT_SYM_NULL_TAG = 2, ++ JIT_SYM_NON_NULL_TAG = 3, ++ JIT_SYM_BOTTOM_TAG = 4, ++ JIT_SYM_TYPE_VERSION_TAG = 5, ++ JIT_SYM_KNOWN_CLASS_TAG = 6, ++ JIT_SYM_KNOWN_VALUE_TAG = 7, ++ JIT_SYM_TUPLE_TAG = 8, ++} JitSymType; + -+ aarch64-apple-watchos*-simulator) CC=arm64-apple-watchos-simulator-clang ;; -+ aarch64-apple-watchos*) CC=arm64_32-apple-watchos-clang ;; -+ x86_64-apple-watchos*-simulator) CC=x86_64-apple-watchos-simulator-clang ;; - *) - esac - fi -@@ -432,6 +454,14 @@ - aarch64-apple-ios*-simulator) CPP=arm64-apple-ios-simulator-cpp ;; - aarch64-apple-ios*) CPP=arm64-apple-ios-cpp ;; - x86_64-apple-ios*-simulator) CPP=x86_64-apple-ios-simulator-cpp ;; ++typedef struct _jit_opt_known_class { ++ uint8_t tag; ++ uint32_t version; ++ PyTypeObject *type; ++} JitOptKnownClass; + -+ aarch64-apple-tvos*-simulator) CPP=arm64-apple-tvos-simulator-cpp ;; -+ aarch64-apple-tvos*) CPP=arm64-apple-tvos-cpp ;; -+ x86_64-apple-tvos*-simulator) CPP=x86_64-apple-tvos-simulator-cpp ;; ++typedef struct _jit_opt_known_version { ++ uint8_t tag; ++ uint32_t version; ++} JitOptKnownVersion; + -+ aarch64-apple-watchos*-simulator) CPP=arm64-apple-watchos-simulator-cpp ;; -+ aarch64-apple-watchos*) CPP=arm64_32-apple-watchos-cpp ;; -+ x86_64-apple-watchos*-simulator) CPP=x86_64-apple-watchos-simulator-cpp ;; - *) - esac - fi -@@ -440,6 +470,14 @@ - aarch64-apple-ios*-simulator) CXX=arm64-apple-ios-simulator-clang++ ;; - aarch64-apple-ios*) CXX=arm64-apple-ios-clang++ ;; - x86_64-apple-ios*-simulator) CXX=x86_64-apple-ios-simulator-clang++ ;; ++typedef struct _jit_opt_known_value { ++ uint8_t tag; ++ PyObject *value; ++} JitOptKnownValue; ++ ++#define MAX_SYMBOLIC_TUPLE_SIZE 7 ++ ++typedef struct _jit_opt_tuple { ++ uint8_t tag; ++ uint8_t length; ++ uint16_t items[MAX_SYMBOLIC_TUPLE_SIZE]; ++} JitOptTuple; ++ ++typedef union _jit_opt_symbol { ++ uint8_t tag; ++ JitOptKnownClass cls; ++ JitOptKnownValue value; ++ JitOptKnownVersion version; ++ JitOptTuple tuple; ++} JitOptSymbol; + -+ aarch64-apple-tvos*-simulator) CXX=arm64-apple-tvos-simulator-clang++ ;; -+ aarch64-apple-tvos*) CXX=arm64-apple-tvos-clang++ ;; -+ x86_64-apple-tvos*-simulator) CXX=x86_64-apple-tvos-simulator-clang++ ;; + -+ aarch64-apple-watchos*-simulator) CXX=arm64-apple-watchos-simulator-clang++ ;; -+ aarch64-apple-watchos*) CXX=arm64_32-apple-watchos-clang++ ;; -+ x86_64-apple-watchos*-simulator) CXX=x86_64-apple-watchos-simulator-clang++ ;; - *) - esac - fi -@@ -554,8 +592,10 @@ - case $enableval in - yes) - case $ac_sys_system in -- Darwin) enableval=/Library/Frameworks ;; -- iOS) enableval=iOS/Frameworks/\$\(MULTIARCH\) ;; -+ Darwin) enableval=/Library/Frameworks ;; -+ iOS) enableval=iOS/Frameworks/\$\(MULTIARCH\) ;; -+ tvOS) enableval=tvOS/Frameworks/\$\(MULTIARCH\) ;; -+ watchOS) enableval=watchOS/Frameworks/\$\(MULTIARCH\) ;; - *) AC_MSG_ERROR([Unknown platform for framework build]) - esac - esac -@@ -564,6 +604,8 @@ - no) - case $ac_sys_system in - iOS) AC_MSG_ERROR([iOS builds must use --enable-framework]) ;; -+ tvOS) AC_MSG_ERROR([tvOS builds must use --enable-framework]) ;; -+ watchOS) AC_MSG_ERROR([watchOS builds must use --enable-framework]) ;; - *) - PYTHONFRAMEWORK= - PYTHONFRAMEWORKDIR=no-framework -@@ -666,6 +708,34 @@ - AC_CONFIG_FILES([iOS/Resources/Info.plist]) - ;; -+ tvOS) : -+ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure" -+ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure " -+ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKPYTHONW= -+ INSTALLTARGETS="libinstall inclinstall sharedinstall" + struct _Py_UOpsAbstractFrame { + // Max stacklen + int stack_len; + int locals_len; + +- _Py_UopsSymbol **stack_pointer; +- _Py_UopsSymbol **stack; +- _Py_UopsSymbol **locals; ++ JitOptSymbol **stack_pointer; ++ JitOptSymbol **stack; ++ JitOptSymbol **locals; + }; + + typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame; +@@ -218,10 +223,10 @@ + typedef struct ty_arena { + int ty_curr_number; + int ty_max_number; +- _Py_UopsSymbol arena[TY_ARENA_SIZE]; ++ JitOptSymbol arena[TY_ARENA_SIZE]; + } ty_arena; + +-struct _Py_UOpsContext { ++typedef struct _JitOptContext { + char done; + char out_of_space; + bool contradiction; +@@ -233,58 +238,58 @@ + // Arena for the symbolic types. + ty_arena t_arena; + +- _Py_UopsSymbol **n_consumed; +- _Py_UopsSymbol **limit; +- _Py_UopsSymbol *locals_and_stack[MAX_ABSTRACT_INTERP_SIZE]; +-}; +- +-typedef struct _Py_UOpsContext _Py_UOpsContext; +- +-extern bool _Py_uop_sym_is_null(_Py_UopsSymbol *sym); +-extern bool _Py_uop_sym_is_not_null(_Py_UopsSymbol *sym); +-extern bool _Py_uop_sym_is_const(_Py_UopsSymbol *sym); +-extern PyObject *_Py_uop_sym_get_const(_Py_UopsSymbol *sym); +-extern _Py_UopsSymbol *_Py_uop_sym_new_unknown(_Py_UOpsContext *ctx); +-extern _Py_UopsSymbol *_Py_uop_sym_new_not_null(_Py_UOpsContext *ctx); +-extern _Py_UopsSymbol *_Py_uop_sym_new_type( +- _Py_UOpsContext *ctx, PyTypeObject *typ); +-extern _Py_UopsSymbol *_Py_uop_sym_new_const(_Py_UOpsContext *ctx, PyObject *const_val); +-extern _Py_UopsSymbol *_Py_uop_sym_new_null(_Py_UOpsContext *ctx); +-extern bool _Py_uop_sym_has_type(_Py_UopsSymbol *sym); +-extern bool _Py_uop_sym_matches_type(_Py_UopsSymbol *sym, PyTypeObject *typ); +-extern bool _Py_uop_sym_matches_type_version(_Py_UopsSymbol *sym, unsigned int version); +-extern void _Py_uop_sym_set_null(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym); +-extern void _Py_uop_sym_set_non_null(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym); +-extern void _Py_uop_sym_set_type(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym, PyTypeObject *typ); +-extern bool _Py_uop_sym_set_type_version(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym, unsigned int version); +-extern void _Py_uop_sym_set_const(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym, PyObject *const_val); +-extern bool _Py_uop_sym_is_bottom(_Py_UopsSymbol *sym); +-extern int _Py_uop_sym_truthiness(_Py_UopsSymbol *sym); +-extern PyTypeObject *_Py_uop_sym_get_type(_Py_UopsSymbol *sym); +- +- +-extern void _Py_uop_abstractcontext_init(_Py_UOpsContext *ctx); +-extern void _Py_uop_abstractcontext_fini(_Py_UOpsContext *ctx); ++ JitOptSymbol **n_consumed; ++ JitOptSymbol **limit; ++ JitOptSymbol *locals_and_stack[MAX_ABSTRACT_INTERP_SIZE]; ++} JitOptContext; + -+ prefix=$PYTHONFRAMEWORKPREFIX -+ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" -+ RESSRCDIR=tvOS/Resources ++extern bool _Py_uop_sym_is_null(JitOptSymbol *sym); ++extern bool _Py_uop_sym_is_not_null(JitOptSymbol *sym); ++extern bool _Py_uop_sym_is_const(JitOptSymbol *sym); ++extern PyObject *_Py_uop_sym_get_const(JitOptSymbol *sym); ++extern JitOptSymbol *_Py_uop_sym_new_unknown(JitOptContext *ctx); ++extern JitOptSymbol *_Py_uop_sym_new_not_null(JitOptContext *ctx); ++extern JitOptSymbol *_Py_uop_sym_new_type( ++ JitOptContext *ctx, PyTypeObject *typ); ++extern JitOptSymbol *_Py_uop_sym_new_const(JitOptContext *ctx, PyObject *const_val); ++extern JitOptSymbol *_Py_uop_sym_new_null(JitOptContext *ctx); ++extern bool _Py_uop_sym_has_type(JitOptSymbol *sym); ++extern bool _Py_uop_sym_matches_type(JitOptSymbol *sym, PyTypeObject *typ); ++extern bool _Py_uop_sym_matches_type_version(JitOptSymbol *sym, unsigned int version); ++extern void _Py_uop_sym_set_null(JitOptContext *ctx, JitOptSymbol *sym); ++extern void _Py_uop_sym_set_non_null(JitOptContext *ctx, JitOptSymbol *sym); ++extern void _Py_uop_sym_set_type(JitOptContext *ctx, JitOptSymbol *sym, PyTypeObject *typ); ++extern bool _Py_uop_sym_set_type_version(JitOptContext *ctx, JitOptSymbol *sym, unsigned int version); ++extern void _Py_uop_sym_set_const(JitOptContext *ctx, JitOptSymbol *sym, PyObject *const_val); ++extern bool _Py_uop_sym_is_bottom(JitOptSymbol *sym); ++extern int _Py_uop_sym_truthiness(JitOptSymbol *sym); ++extern PyTypeObject *_Py_uop_sym_get_type(JitOptSymbol *sym); ++extern bool _Py_uop_sym_is_immortal(JitOptSymbol *sym); ++extern JitOptSymbol *_Py_uop_sym_new_tuple(JitOptContext *ctx, int size, JitOptSymbol **args); ++extern JitOptSymbol *_Py_uop_sym_tuple_getitem(JitOptContext *ctx, JitOptSymbol *sym, int item); ++extern int _Py_uop_sym_tuple_length(JitOptSymbol *sym); + -+ AC_CONFIG_FILES([tvOS/Resources/Info.plist]) -+ ;; -+ watchOS) : -+ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure" -+ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure " -+ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKPYTHONW= -+ INSTALLTARGETS="libinstall inclinstall sharedinstall" ++extern void _Py_uop_abstractcontext_init(JitOptContext *ctx); ++extern void _Py_uop_abstractcontext_fini(JitOptContext *ctx); + + extern _Py_UOpsAbstractFrame *_Py_uop_frame_new( +- _Py_UOpsContext *ctx, ++ JitOptContext *ctx, + PyCodeObject *co, + int curr_stackentries, +- _Py_UopsSymbol **args, ++ JitOptSymbol **args, + int arg_len); +-extern int _Py_uop_frame_pop(_Py_UOpsContext *ctx); ++extern int _Py_uop_frame_pop(JitOptContext *ctx); + + PyAPI_FUNC(PyObject *) _Py_uop_symbols_test(PyObject *self, PyObject *ignored); + +-PyAPI_FUNC(int) _PyOptimizer_Optimize(struct _PyInterpreterFrame *frame, _Py_CODEUNIT *start, _PyStackRef *stack_pointer, _PyExecutorObject **exec_ptr, int chain_depth); ++PyAPI_FUNC(int) _PyOptimizer_Optimize(struct _PyInterpreterFrame *frame, _Py_CODEUNIT *start, _PyExecutorObject **exec_ptr, int chain_depth); + + static inline int is_terminator(const _PyUOpInstruction *uop) + { + int opcode = uop->opcode; + return ( + opcode == _EXIT_TRACE || +- opcode == _JUMP_TO_TOP || +- opcode == _DYNAMIC_EXIT ++ opcode == _JUMP_TO_TOP + ); + } + +diff --git a/Include/internal/pycore_pyerrors.h b/Include/internal/pycore_pyerrors.h +index 02945f0e71a..fa7d9ee36d0 100644 +--- a/Include/internal/pycore_pyerrors.h ++++ b/Include/internal/pycore_pyerrors.h +@@ -130,6 +130,18 @@ + PyObject *exception, + const char *string); + ++/* ++ * Set an exception with the error message decoded from the current locale ++ * encoding (LC_CTYPE). ++ * ++ * Exceptions occurring in decoding take priority over the desired exception. ++ * ++ * Exported for '_ctypes' shared extensions. ++ */ ++PyAPI_FUNC(void) _PyErr_SetLocaleString( ++ PyObject *exception, ++ const char *string); + -+ prefix=$PYTHONFRAMEWORKPREFIX -+ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" -+ RESSRCDIR=watchOS/Resources + PyAPI_FUNC(PyObject*) _PyErr_Format( + PyThreadState *tstate, + PyObject *exception, +@@ -178,6 +190,15 @@ + PyAPI_DATA(PyTypeObject) _PyExc_IncompleteInputError; + #define PyExc_IncompleteInputError ((PyObject *)(&_PyExc_IncompleteInputError)) + ++extern int _PyUnicodeError_GetParams( ++ PyObject *self, ++ PyObject **obj, ++ Py_ssize_t *objlen, ++ Py_ssize_t *start, ++ Py_ssize_t *end, ++ Py_ssize_t *slen, ++ int as_bytes); + -+ AC_CONFIG_FILES([watchOS/Resources/Info.plist]) -+ ;; - *) - AC_MSG_ERROR([Unknown platform for framework build]) - ;; -@@ -674,6 +744,8 @@ - ],[ - case $ac_sys_system in - iOS) AC_MSG_ERROR([iOS builds must use --enable-framework]) ;; -+ tvOS) AC_MSG_ERROR([tvOS builds must use --enable-framework]) ;; -+ watchOS) AC_MSG_ERROR([watchOS builds must use --enable-framework]) ;; - *) - PYTHONFRAMEWORK= - PYTHONFRAMEWORKDIR=no-framework -@@ -726,8 +798,8 @@ - case "$withval" in - yes) - case $ac_sys_system in -- Darwin|iOS) -- # iOS is able to share the macOS patch -+ Darwin|iOS|tvOS|watchOS) -+ # iOS/tvOS/watchOS is able to share the macOS patch - APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" - ;; - *) AC_MSG_ERROR([no default app store compliance patch available for $ac_sys_system]) ;; -@@ -741,8 +813,8 @@ - esac - ],[ - case $ac_sys_system in -- iOS) -- # Always apply the compliance patch on iOS; we can use the macOS patch -+ iOS|tvOS|watchOS) -+ # Always apply the compliance patch on iOS/tvOS/watchOS; we can use the macOS patch - APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" - AC_MSG_RESULT([applying default app store compliance patch]) - ;; -@@ -790,6 +862,46 @@ - ;; - esac - ;; -+ *-apple-tvos*) -+ _host_os=`echo $host | cut -d '-' -f3` -+ _host_device=`echo $host | cut -d '-' -f4` -+ _host_device=${_host_device:=os} + #ifdef __cplusplus + } + #endif +diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h +index 1e73e541ef8..9ec59e60f60 100644 +--- a/Include/internal/pycore_pystate.h ++++ b/Include/internal/pycore_pystate.h +@@ -182,8 +182,8 @@ + // Perform a stop-the-world pause for threads in the specified interpreter. + // + // NOTE: This is a no-op outside of Py_GIL_DISABLED builds. +-extern void _PyEval_StopTheWorld(PyInterpreterState *interp); +-extern void _PyEval_StartTheWorld(PyInterpreterState *interp); ++extern PyAPI_FUNC(void) _PyEval_StopTheWorld(PyInterpreterState *interp); ++extern PyAPI_FUNC(void) _PyEval_StartTheWorld(PyInterpreterState *interp); + + + static inline void +@@ -300,6 +300,19 @@ + // See also PyInterpreterState_Get() and _PyInterpreterState_GET(). + extern PyInterpreterState* _PyGILState_GetInterpreterStateUnsafe(void); + ++#ifndef NDEBUG ++/* Modern equivalent of assert(PyGILState_Check()) */ ++static inline void ++_Py_AssertHoldsTstateFunc(const char *func) ++{ ++ PyThreadState *tstate = _PyThreadState_GET(); ++ _Py_EnsureFuncTstateNotNULL(func, tstate); ++} ++#define _Py_AssertHoldsTstate() _Py_AssertHoldsTstateFunc(__func__) ++#else ++#define _Py_AssertHoldsTstate() ++#endif + -+ # TVOS_DEPLOYMENT_TARGET is the minimum supported tvOS version -+ AC_MSG_CHECKING([tvOS deployment target]) -+ TVOS_DEPLOYMENT_TARGET=${_host_os:4} -+ TVOS_DEPLOYMENT_TARGET=${TVOS_DEPLOYMENT_TARGET:=12.0} -+ AC_MSG_RESULT([$TVOS_DEPLOYMENT_TARGET]) + #ifdef __cplusplus + } + #endif +diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h +index 86d024535fd..cf123791eba 100644 +--- a/Include/internal/pycore_runtime.h ++++ b/Include/internal/pycore_runtime.h +@@ -172,7 +172,7 @@ + #if defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE) + // Used in "Python/emscripten_trampoline.c" to choose between type + // reflection trampoline and EM_JS trampoline. +- bool wasm_type_reflection_available; ++ int (*emscripten_count_args_function)(PyCFunctionWithKeywords func); + #endif + + /* All the objects that are shared by the runtime's interpreters. */ +diff --git a/Include/internal/pycore_stackref.h b/Include/internal/pycore_stackref.h +index 90a3118352f..1ae62cc69bb 100644 +--- a/Include/internal/pycore_stackref.h ++++ b/Include/internal/pycore_stackref.h +@@ -4,6 +4,9 @@ + extern "C" { + #endif + ++// Define this to get precise tracking of stackrefs. ++// #define Py_STACKREF_DEBUG 1 + -+ case "$host_cpu" in -+ aarch64) -+ _host_ident=${TVOS_DEPLOYMENT_TARGET}-arm64-appletv${_host_device} -+ ;; -+ *) -+ _host_ident=${TVOS_DEPLOYMENT_TARGET}-$host_cpu-appletv${_host_device} -+ ;; -+ esac -+ ;; -+ *-apple-watchos*) -+ _host_os=`echo $host | cut -d '-' -f3` -+ _host_device=`echo $host | cut -d '-' -f4` -+ _host_device=${_host_device:=os} + #ifndef Py_BUILD_CORE + # error "this header requires Py_BUILD_CORE define" + #endif +@@ -49,6 +52,113 @@ + CPython refcounting operations on it! + */ + + -+ # WATCHOS_DEPLOYMENT_TARGET is the minimum supported watchOS version -+ AC_MSG_CHECKING([watchOS deployment target]) -+ WATCHOS_DEPLOYMENT_TARGET=${_host_os:7} -+ WATCHOS_DEPLOYMENT_TARGET=${WATCHOS_DEPLOYMENT_TARGET:=4.0} -+ AC_MSG_RESULT([$WATCHOS_DEPLOYMENT_TARGET]) ++#if !defined(Py_GIL_DISABLED) && defined(Py_STACKREF_DEBUG) + -+ case "$host_cpu" in -+ aarch64) -+ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-arm64-watch${_host_device} -+ ;; -+ *) -+ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-$host_cpu-watch${_host_device} -+ ;; -+ esac -+ ;; - *-*-vxworks*) - _host_ident=$host_cpu - ;; -@@ -867,9 +979,13 @@ - define_xopen_source=no;; - Darwin/@<:@[12]@:>@@<:@0-9@:>@.*) - define_xopen_source=no;; -- # On iOS, defining _POSIX_C_SOURCE also disables platform specific features. -+ # On iOS/tvOS/watchOS, defining _POSIX_C_SOURCE also disables platform specific features. - iOS/*) - define_xopen_source=no;; -+ tvOS/*) -+ define_xopen_source=no;; -+ watchOS/*) -+ define_xopen_source=no;; - # On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from - # defining NI_NUMERICHOST. - QNX/6.3.2) -@@ -928,8 +1044,11 @@ - CONFIGURE_MACOSX_DEPLOYMENT_TARGET= - EXPORT_MACOSX_DEPLOYMENT_TARGET='#' ++ ++ ++typedef union _PyStackRef { ++ uint64_t index; ++} _PyStackRef; ++ ++#define Py_TAG_BITS 0 ++ ++PyAPI_FUNC(PyObject *) _Py_stackref_get_object(_PyStackRef ref); ++PyAPI_FUNC(PyObject *) _Py_stackref_close(_PyStackRef ref); ++PyAPI_FUNC(_PyStackRef) _Py_stackref_create(PyObject *obj, const char *filename, int linenumber); ++PyAPI_FUNC(void) _Py_stackref_record_borrow(_PyStackRef ref, const char *filename, int linenumber); ++extern void _Py_stackref_associate(PyInterpreterState *interp, PyObject *obj, _PyStackRef ref); ++ ++static const _PyStackRef PyStackRef_NULL = { .index = 0 }; ++ ++#define PyStackRef_None ((_PyStackRef){ .index = 1 } ) ++#define PyStackRef_False ((_PyStackRef){ .index = 2 }) ++#define PyStackRef_True ((_PyStackRef){ .index = 3 }) ++ ++#define LAST_PREDEFINED_STACKREF_INDEX 3 ++ ++static inline int ++PyStackRef_IsNull(_PyStackRef ref) ++{ ++ return ref.index == 0; ++} ++ ++static inline int ++PyStackRef_IsTrue(_PyStackRef ref) ++{ ++ return _Py_stackref_get_object(ref) == Py_True; ++} ++ ++static inline int ++PyStackRef_IsFalse(_PyStackRef ref) ++{ ++ return _Py_stackref_get_object(ref) == Py_False; ++} ++ ++static inline int ++PyStackRef_IsNone(_PyStackRef ref) ++{ ++ return _Py_stackref_get_object(ref) == Py_None; ++} ++ ++static inline PyObject * ++_PyStackRef_AsPyObjectBorrow(_PyStackRef ref, const char *filename, int linenumber) ++{ ++ _Py_stackref_record_borrow(ref, filename, linenumber); ++ return _Py_stackref_get_object(ref); ++} ++ ++#define PyStackRef_AsPyObjectBorrow(REF) _PyStackRef_AsPyObjectBorrow((REF), __FILE__, __LINE__) ++ ++static inline PyObject * ++PyStackRef_AsPyObjectSteal(_PyStackRef ref) ++{ ++ return _Py_stackref_close(ref); ++} ++ ++static inline _PyStackRef ++_PyStackRef_FromPyObjectNew(PyObject *obj, const char *filename, int linenumber) ++{ ++ Py_INCREF(obj); ++ return _Py_stackref_create(obj, filename, linenumber); ++} ++#define PyStackRef_FromPyObjectNew(obj) _PyStackRef_FromPyObjectNew(_PyObject_CAST(obj), __FILE__, __LINE__) ++ ++static inline _PyStackRef ++_PyStackRef_FromPyObjectSteal(PyObject *obj, const char *filename, int linenumber) ++{ ++ return _Py_stackref_create(obj, filename, linenumber); ++} ++#define PyStackRef_FromPyObjectSteal(obj) _PyStackRef_FromPyObjectSteal(_PyObject_CAST(obj), __FILE__, __LINE__) ++ ++static inline _PyStackRef ++_PyStackRef_FromPyObjectImmortal(PyObject *obj, const char *filename, int linenumber) ++{ ++ assert(_Py_IsImmortal(obj)); ++ return _Py_stackref_create(obj, filename, linenumber); ++} ++#define PyStackRef_FromPyObjectImmortal(obj) _PyStackRef_FromPyObjectImmortal(_PyObject_CAST(obj), __FILE__, __LINE__) ++ ++static inline void ++PyStackRef_CLOSE(_PyStackRef ref) ++{ ++ PyObject *obj = _Py_stackref_close(ref); ++ Py_DECREF(obj); ++} ++ ++static inline _PyStackRef ++_PyStackRef_DUP(_PyStackRef ref, const char *filename, int linenumber) ++{ ++ PyObject *obj = _Py_stackref_get_object(ref); ++ Py_INCREF(obj); ++ return _Py_stackref_create(obj, filename, linenumber); ++} ++#define PyStackRef_DUP(REF) _PyStackRef_DUP(REF, __FILE__, __LINE__) ++ ++#define PyStackRef_CLOSE_SPECIALIZED(stackref, dealloc) PyStackRef_CLOSE(stackref) ++ ++#else ++ + typedef union _PyStackRef { + uintptr_t bits; + } _PyStackRef; +@@ -200,12 +310,15 @@ + #define PyStackRef_IsTrue(ref) (PyStackRef_AsPyObjectBorrow(ref) == Py_True) + #define PyStackRef_IsFalse(ref) (PyStackRef_AsPyObjectBorrow(ref) == Py_False) --# Record the value of IPHONEOS_DEPLOYMENT_TARGET enforced by the selected host triple. -+# Record the value of IPHONEOS_DEPLOYMENT_TARGET / TVOS_DEPLOYMENT_TARGET / -+# WATCHOS_DEPLOYMENT_TARGET enforced by the selected host triple. - AC_SUBST([IPHONEOS_DEPLOYMENT_TARGET]) -+AC_SUBST([TVOS_DEPLOYMENT_TARGET]) -+AC_SUBST([WATCHOS_DEPLOYMENT_TARGET]) ++#endif ++ + // Converts a PyStackRef back to a PyObject *, converting the + // stackref to a new reference. + #define PyStackRef_AsPyObjectNew(stackref) Py_NewRef(PyStackRef_AsPyObjectBorrow(stackref)) - # checks for alternative programs + #define PyStackRef_TYPE(stackref) Py_TYPE(PyStackRef_AsPyObjectBorrow(stackref)) -@@ -963,11 +1082,17 @@ - ], - ) ++ + #define PyStackRef_CLEAR(op) \ + do { \ + _PyStackRef *_tmp_op_ptr = &(op); \ +diff --git a/Include/internal/pycore_symtable.h b/Include/internal/pycore_symtable.h +index 91dac767d58..b7e27429611 100644 +--- a/Include/internal/pycore_symtable.h ++++ b/Include/internal/pycore_symtable.h +@@ -124,6 +124,7 @@ + unsigned ste_can_see_class_scope : 1; /* true if this block can see names bound in an + enclosing class scope */ + unsigned ste_has_docstring : 1; /* true if docstring present */ ++ unsigned ste_method : 1; /* true if block is a function block defined in class scope */ + int ste_comp_iter_expr; /* non-zero if visiting a comprehension range expression */ + _Py_SourceLocation ste_loc; /* source location of block */ + struct _symtable_entry *ste_annotation_block; /* symbol table entry for this entry's annotations */ +diff --git a/Include/internal/pycore_tracemalloc.h b/Include/internal/pycore_tracemalloc.h +index 7ddc5bac5d1..572e8025876 100644 +--- a/Include/internal/pycore_tracemalloc.h ++++ b/Include/internal/pycore_tracemalloc.h +@@ -11,10 +11,6 @@ + #include "pycore_hashtable.h" // _Py_hashtable_t --dnl Add the compiler flag for the iOS minimum supported OS version. -+dnl Add the compiler flag for the iOS/tvOS/watchOS minimum supported OS version. - AS_CASE([$ac_sys_system], - [iOS], [ - AS_VAR_APPEND([CFLAGS], [" -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}"]) - AS_VAR_APPEND([LDFLAGS], [" -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}"]) -+ ],[tvOS], [ -+ AS_VAR_APPEND([CFLAGS], [" -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}"]) -+ AS_VAR_APPEND([LDFLAGS], [" -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}"]) -+ ],[watchOS], [ -+ AS_VAR_APPEND([CFLAGS], [" -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}"]) -+ AS_VAR_APPEND([LDFLAGS], [" -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}"]) - ], - ) -@@ -1156,6 +1281,8 @@ - AS_CASE([$ac_sys_system], - [Darwin*], [MULTIARCH=""], - [iOS], [MULTIARCH=""], -+ [tvOS], [MULTIARCH=""], -+ [watchOS], [MULTIARCH=""], - [FreeBSD*], [MULTIARCH=""], - [MULTIARCH=$($CC --print-multiarch 2>/dev/null)] - ) -@@ -1177,7 +1304,7 @@ - dnl use a single "fat" binary at runtime. SOABI_PLATFORM is the component of - dnl the PLATFORM_TRIPLET that will be used in binary module extensions. - AS_CASE([$ac_sys_system], -- [iOS], [SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f2`], -+ [iOS|tvOS|watchOS], [SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f2`], - [SOABI_PLATFORM=$PLATFORM_TRIPLET] - ) +-/* Trace memory blocks allocated by PyMem_RawMalloc() */ +-#define TRACE_RAW_MALLOC +- +- + struct _PyTraceMalloc_Config { + /* Module initialized? + Variable protected by the GIL */ +@@ -25,7 +21,7 @@ + } initialized; -@@ -1211,6 +1338,10 @@ - [x86_64-*-freebsd*/clang], [PY_SUPPORT_TIER=3], dnl FreeBSD on AMD64 - [aarch64-apple-ios*-simulator/clang], [PY_SUPPORT_TIER=3], dnl iOS Simulator on arm64 - [aarch64-apple-ios*/clang], [PY_SUPPORT_TIER=3], dnl iOS on ARM64 -+ [aarch64-apple-tvos*-simulator/clang], [PY_SUPPORT_TIER=3], dnl tvOS Simulator on arm64 -+ [aarch64-apple-tvos*/clang], [PY_SUPPORT_TIER=3], dnl tvOS on ARM64 -+ [aarch64-apple-watchos*-simulator/clang], [PY_SUPPORT_TIER=3], dnl watchOS Simulator on arm64 -+ [arm64_32-apple-watchos*/clang], [PY_SUPPORT_TIER=3], dnl watchOS on ARM64 - [aarch64-*-linux-android/clang], [PY_SUPPORT_TIER=3], dnl Android on ARM64 - [x86_64-*-linux-android/clang], [PY_SUPPORT_TIER=3], dnl Android on AMD64 + /* Is tracemalloc tracing memory allocations? +- Variable protected by the GIL */ ++ Variable protected by the TABLES_LOCK(). */ + int tracing; -@@ -1520,7 +1651,7 @@ - case $ac_sys_system in - Darwin) - LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)';; -- iOS) -+ iOS|tvOS|watchOS) - LDLIBRARY='$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';; - *) - AC_MSG_ERROR([Unknown platform for framework build]);; -@@ -1585,7 +1716,7 @@ - BLDLIBRARY='-L. -lpython$(LDVERSION)' - RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}} - ;; -- iOS) -+ iOS|tvOS|watchOS) - LDLIBRARY='libpython$(LDVERSION).dylib' - ;; - AIX*) -@@ -3412,7 +3543,7 @@ - BLDSHARED="$LDSHARED" - fi - ;; -- iOS/*) -+ iOS/*|tvOS/*|watchOS/*) - LDSHARED='$(CC) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)' - LDCXXSHARED='$(CXX) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)' - BLDSHARED="$LDSHARED" -@@ -3536,7 +3667,7 @@ - Linux-android*) LINKFORSHARED="-pie -Xlinker -export-dynamic";; - Linux*|GNU*) LINKFORSHARED="-Xlinker -export-dynamic";; - # -u libsys_s pulls in all symbols in libsys -- Darwin/*|iOS/*) -+ Darwin/*|iOS/*|tvOS/*|watchOS/*) - LINKFORSHARED="$extra_undefs -framework CoreFoundation" + /* limit of the number of frames in a traceback, 1 by default. +@@ -74,9 +70,7 @@ + PyMemAllocatorEx obj; + } allocators; - # Issue #18075: the default maximum stack size (8MBytes) is too -@@ -3560,7 +3691,7 @@ - LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' - fi - LINKFORSHARED="$LINKFORSHARED" -- elif test $ac_sys_system = "iOS"; then -+ elif test "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "watchOS"; then - LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)' - fi - ;; -@@ -3980,7 +4111,7 @@ - dnl when do we need USING_APPLE_OS_LIBFFI? - ctypes_malloc_closure=yes - ], -- [iOS], [ -+ [iOS|tvOS|watchOS], [ - ctypes_malloc_closure=yes - ], - [sunos5], [AS_VAR_APPEND([LIBFFI_LIBS], [" -mimpure-text"])] -@@ -5098,9 +5229,9 @@ - # checks for library functions - AC_CHECK_FUNCS([ \ - accept4 alarm bind_textdomain_codeset chmod chown clock closefrom close_range confstr \ -- copy_file_range ctermid dup dup3 execv explicit_bzero explicit_memset \ -+ copy_file_range ctermid dup dup3 explicit_bzero explicit_memset \ - faccessat fchmod fchmodat fchown fchownat fdopendir fdwalk fexecve \ -- fork fork1 fpathconf fstatat ftime ftruncate futimens futimes futimesat \ -+ fpathconf fstatat ftime ftruncate futimens futimes futimesat \ - gai_strerror getegid geteuid getgid getgrent getgrgid getgrgid_r \ - getgrnam_r getgrouplist gethostname getitimer getloadavg getlogin \ - getpeername getpgid getpid getppid getpriority _getpty \ -@@ -5108,8 +5239,7 @@ - getspnam getuid getwd grantpt if_nameindex initgroups kill killpg lchown linkat \ - lockf lstat lutimes madvise mbrtowc memrchr mkdirat mkfifo mkfifoat \ - mknod mknodat mktime mmap mremap nice openat opendir pathconf pause pipe \ -- pipe2 plock poll posix_fadvise posix_fallocate posix_openpt posix_spawn posix_spawnp \ -- posix_spawn_file_actions_addclosefrom_np \ -+ pipe2 plock poll posix_fadvise posix_fallocate posix_openpt \ - pread preadv preadv2 process_vm_readv \ - pthread_cond_timedwait_relative_np pthread_condattr_setclock pthread_init \ - pthread_kill pthread_getname_np pthread_setname_np \ -@@ -5118,7 +5248,7 @@ - sched_setparam sched_setscheduler sem_clockwait sem_getvalue sem_open \ - sem_timedwait sem_unlink sendfile setegid seteuid setgid sethostname \ - setitimer setlocale setpgid setpgrp setpriority setregid setresgid \ -- setresuid setreuid setsid setuid setvbuf shutdown sigaction sigaltstack \ -+ setresuid setreuid setsid setuid setvbuf shutdown sigaction \ - sigfillset siginterrupt sigpending sigrelse sigtimedwait sigwait \ - sigwaitinfo snprintf splice strftime strlcpy strsignal symlinkat sync \ - sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile \ -@@ -5133,12 +5263,20 @@ - AC_CHECK_FUNCS([lchmod]) - fi +-#if defined(TRACE_RAW_MALLOC) +- PyThread_type_lock tables_lock; +-#endif ++ PyMutex tables_lock; + /* Size in bytes of currently traced memory. + Protected by TABLES_LOCK(). */ + size_t traced_memory; +@@ -85,14 +79,14 @@ + size_t peak_traced_memory; + /* Hash table used as a set to intern filenames: + PyObject* => PyObject*. +- Protected by the GIL */ ++ Protected by the TABLES_LOCK(). */ + _Py_hashtable_t *filenames; + /* Buffer to store a new traceback in traceback_new(). +- Protected by the GIL. */ ++ Protected by the TABLES_LOCK(). */ + struct tracemalloc_traceback *traceback; + /* Hash table used as a set to intern tracebacks: + traceback_t* => traceback_t* +- Protected by the GIL */ ++ Protected by the TABLES_LOCK(). */ + _Py_hashtable_t *tracebacks; + /* pointer (void*) => trace (trace_t*). + Protected by TABLES_LOCK(). */ +@@ -144,7 +138,7 @@ + extern PyObject* _PyTraceMalloc_GetObjectTraceback(PyObject *obj); + + /* Initialize tracemalloc */ +-extern int _PyTraceMalloc_Init(void); ++extern PyStatus _PyTraceMalloc_Init(void); + + /* Start tracemalloc */ + extern int _PyTraceMalloc_Start(int max_nframe); +diff --git a/Include/internal/pycore_tstate.h b/Include/internal/pycore_tstate.h +index b8bea72baea..932623f54c4 100644 +--- a/Include/internal/pycore_tstate.h ++++ b/Include/internal/pycore_tstate.h +@@ -22,10 +22,16 @@ + PyThreadState base; + + PyObject *asyncio_running_loop; // Strong reference ++ PyObject *asyncio_running_task; // Strong reference + ++ /* Head of circular linked-list of all tasks which are instances of `asyncio.Task` ++ or subclasses of it used in `asyncio.all_tasks`. ++ */ ++ struct llist_node asyncio_tasks_head; + struct _qsbr_thread_state *qsbr; // only used by free-threaded build + struct llist_node mem_free_queue; // delayed free queue --# iOS defines some system methods that can be linked (so they are -+# iOS/tvOS/watchOS define some system methods that can be linked (so they are - # found by configure), but either raise a compilation error (because the - # header definition prevents usage - autoconf doesn't use the headers), or - # raise an error if used at runtime. Force these symbols off. --if test "$ac_sys_system" != "iOS" ; then -- AC_CHECK_FUNCS([getentropy getgroups system]) -+if test "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then -+ AC_CHECK_FUNCS([ getentropy getgroups system ]) -+fi + -+# tvOS/watchOS have some additional methods that can be found, but not used. -+if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then -+ AC_CHECK_FUNCS([ \ -+ execv fork fork1 posix_spawn posix_spawnp posix_spawn_file_actions_addclosefrom_np \ -+ sigaltstack \ -+ ]) - fi + #ifdef Py_GIL_DISABLED + struct _gc_thread_state gc; + struct _mimalloc_thread_state mimalloc; +diff --git a/Include/internal/pycore_tuple.h b/Include/internal/pycore_tuple.h +index 82b875241f4..dc68d6648b9 100644 +--- a/Include/internal/pycore_tuple.h ++++ b/Include/internal/pycore_tuple.h +@@ -21,7 +21,7 @@ + #define _PyTuple_ITEMS(op) _Py_RVALUE(_PyTuple_CAST(op)->ob_item) - AC_CHECK_DECL([dirfd], -@@ -5392,20 +5530,22 @@ - ]) + PyAPI_FUNC(PyObject *)_PyTuple_FromArray(PyObject *const *, Py_ssize_t); +-PyAPI_FUNC(PyObject *)_PyTuple_FromStackRefSteal(const union _PyStackRef *, Py_ssize_t); ++PyAPI_FUNC(PyObject *)_PyTuple_FromStackRefStealOnSuccess(const union _PyStackRef *, Py_ssize_t); + PyAPI_FUNC(PyObject *)_PyTuple_FromArraySteal(PyObject *const *, Py_ssize_t); - # check for openpty, login_tty, and forkpty + typedef struct { +diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h +index 7b39d07f976..581153344a8 100644 +--- a/Include/internal/pycore_typeobject.h ++++ b/Include/internal/pycore_typeobject.h +@@ -278,6 +278,7 @@ + // and if the validation is passed, it will set the ``tp_version`` as valid + // tp_version_tag from the ``ty``. + extern int _PyType_Validate(PyTypeObject *ty, _py_validate_type validate, unsigned int *tp_version); ++extern int _PyType_CacheGetItemForSpecialization(PyHeapTypeObject *ht, PyObject *descriptor, uint32_t tp_version); + + #ifdef __cplusplus + } +diff --git a/Include/internal/pycore_uniqueid.h b/Include/internal/pycore_uniqueid.h +index d3db49ddb78..9d3c866a704 100644 +--- a/Include/internal/pycore_uniqueid.h ++++ b/Include/internal/pycore_uniqueid.h +@@ -16,7 +16,7 @@ + // Per-thread reference counting is used along with deferred reference + // counting to avoid scaling bottlenecks due to reference count contention. + // +-// An id of -1 is used to indicate that an object doesn't use per-thread ++// An id of 0 is used to indicate that an object doesn't use per-thread + // refcounting. This value is used when the object is finalized by the GC + // and during interpreter shutdown to allow the object to be + // deallocated promptly when the object's refcount reaches zero. +@@ -45,6 +45,8 @@ + Py_ssize_t size; + }; + ++#define _Py_INVALID_UNIQUE_ID 0 ++ + // Assigns the next id from the pool of ids. + extern Py_ssize_t _PyObject_AssignUniqueId(PyObject *obj); + +@@ -65,7 +67,7 @@ + extern void _PyObject_FinalizeUniqueIdPool(PyInterpreterState *interp); + + // Increfs the object, resizing the thread-local refcount array if necessary. +-PyAPI_FUNC(void) _PyObject_ThreadIncrefSlow(PyObject *obj, Py_ssize_t unique_id); ++PyAPI_FUNC(void) _PyObject_ThreadIncrefSlow(PyObject *obj, size_t idx); + + #endif /* Py_GIL_DISABLED */ + +diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h +index 45563585dd5..4e04dd69542 100644 +--- a/Include/internal/pycore_uop_ids.h ++++ b/Include/internal/pycore_uop_ids.h +@@ -15,19 +15,19 @@ + #define _BINARY_OP_ADD_FLOAT 303 + #define _BINARY_OP_ADD_INT 304 + #define _BINARY_OP_ADD_UNICODE 305 +-#define _BINARY_OP_INPLACE_ADD_UNICODE 306 +-#define _BINARY_OP_MULTIPLY_FLOAT 307 +-#define _BINARY_OP_MULTIPLY_INT 308 +-#define _BINARY_OP_SUBTRACT_FLOAT 309 +-#define _BINARY_OP_SUBTRACT_INT 310 +-#define _BINARY_SLICE 311 +-#define _BINARY_SUBSCR 312 +-#define _BINARY_SUBSCR_CHECK_FUNC 313 +-#define _BINARY_SUBSCR_DICT BINARY_SUBSCR_DICT +-#define _BINARY_SUBSCR_INIT_CALL 314 +-#define _BINARY_SUBSCR_LIST_INT BINARY_SUBSCR_LIST_INT +-#define _BINARY_SUBSCR_STR_INT BINARY_SUBSCR_STR_INT +-#define _BINARY_SUBSCR_TUPLE_INT BINARY_SUBSCR_TUPLE_INT ++#define _BINARY_OP_EXTEND 306 ++#define _BINARY_OP_INPLACE_ADD_UNICODE 307 ++#define _BINARY_OP_MULTIPLY_FLOAT 308 ++#define _BINARY_OP_MULTIPLY_INT 309 ++#define _BINARY_OP_SUBSCR_CHECK_FUNC 310 ++#define _BINARY_OP_SUBSCR_DICT BINARY_OP_SUBSCR_DICT ++#define _BINARY_OP_SUBSCR_INIT_CALL 311 ++#define _BINARY_OP_SUBSCR_LIST_INT BINARY_OP_SUBSCR_LIST_INT ++#define _BINARY_OP_SUBSCR_STR_INT BINARY_OP_SUBSCR_STR_INT ++#define _BINARY_OP_SUBSCR_TUPLE_INT BINARY_OP_SUBSCR_TUPLE_INT ++#define _BINARY_OP_SUBTRACT_FLOAT 312 ++#define _BINARY_OP_SUBTRACT_INT 313 ++#define _BINARY_SLICE 314 + #define _BUILD_LIST BUILD_LIST + #define _BUILD_MAP BUILD_MAP + #define _BUILD_SET BUILD_SET +@@ -100,24 +100,25 @@ + #define _DO_CALL 357 + #define _DO_CALL_FUNCTION_EX 358 + #define _DO_CALL_KW 359 +-#define _DYNAMIC_EXIT 360 ++#define _END_FOR END_FOR + #define _END_SEND END_SEND +-#define _ERROR_POP_N 361 ++#define _ERROR_POP_N 360 + #define _EXIT_INIT_CHECK EXIT_INIT_CHECK +-#define _EXPAND_METHOD 362 +-#define _EXPAND_METHOD_KW 363 +-#define _FATAL_ERROR 364 ++#define _EXPAND_METHOD 361 ++#define _EXPAND_METHOD_KW 362 ++#define _FATAL_ERROR 363 + #define _FORMAT_SIMPLE FORMAT_SIMPLE + #define _FORMAT_WITH_SPEC FORMAT_WITH_SPEC +-#define _FOR_ITER 365 +-#define _FOR_ITER_GEN_FRAME 366 +-#define _FOR_ITER_TIER_TWO 367 ++#define _FOR_ITER 364 ++#define _FOR_ITER_GEN_FRAME 365 ++#define _FOR_ITER_TIER_TWO 366 + #define _GET_AITER GET_AITER + #define _GET_ANEXT GET_ANEXT + #define _GET_AWAITABLE GET_AWAITABLE + #define _GET_ITER GET_ITER + #define _GET_LEN GET_LEN + #define _GET_YIELD_FROM_ITER GET_YIELD_FROM_ITER ++#define _GUARD_BINARY_OP_EXTEND 367 + #define _GUARD_BOTH_FLOAT 368 + #define _GUARD_BOTH_INT 369 + #define _GUARD_BOTH_UNICODE 370 +@@ -139,27 +140,25 @@ + #define _GUARD_TOS_FLOAT 386 + #define _GUARD_TOS_INT 387 + #define _GUARD_TYPE_VERSION 388 ++#define _GUARD_TYPE_VERSION_AND_LOCK 389 + #define _IMPORT_FROM IMPORT_FROM + #define _IMPORT_NAME IMPORT_NAME +-#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 389 +-#define _INIT_CALL_PY_EXACT_ARGS 390 +-#define _INIT_CALL_PY_EXACT_ARGS_0 391 +-#define _INIT_CALL_PY_EXACT_ARGS_1 392 +-#define _INIT_CALL_PY_EXACT_ARGS_2 393 +-#define _INIT_CALL_PY_EXACT_ARGS_3 394 +-#define _INIT_CALL_PY_EXACT_ARGS_4 395 +-#define _INSTRUMENTED_CALL_FUNCTION_EX INSTRUMENTED_CALL_FUNCTION_EX +-#define _INSTRUMENTED_CALL_KW INSTRUMENTED_CALL_KW ++#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 390 ++#define _INIT_CALL_PY_EXACT_ARGS 391 ++#define _INIT_CALL_PY_EXACT_ARGS_0 392 ++#define _INIT_CALL_PY_EXACT_ARGS_1 393 ++#define _INIT_CALL_PY_EXACT_ARGS_2 394 ++#define _INIT_CALL_PY_EXACT_ARGS_3 395 ++#define _INIT_CALL_PY_EXACT_ARGS_4 396 + #define _INSTRUMENTED_FOR_ITER INSTRUMENTED_FOR_ITER + #define _INSTRUMENTED_INSTRUCTION INSTRUMENTED_INSTRUCTION + #define _INSTRUMENTED_JUMP_FORWARD INSTRUMENTED_JUMP_FORWARD + #define _INSTRUMENTED_LINE INSTRUMENTED_LINE +-#define _INSTRUMENTED_LOAD_SUPER_ATTR INSTRUMENTED_LOAD_SUPER_ATTR ++#define _INSTRUMENTED_NOT_TAKEN INSTRUMENTED_NOT_TAKEN + #define _INSTRUMENTED_POP_JUMP_IF_FALSE INSTRUMENTED_POP_JUMP_IF_FALSE + #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 _INTERNAL_INCREMENT_OPT_COUNTER 396 + #define _IS_NONE 397 + #define _IS_OP IS_OP + #define _ITER_CHECK_LIST 398 +@@ -176,126 +175,121 @@ + #define _LIST_EXTEND LIST_EXTEND + #define _LOAD_ATTR 408 + #define _LOAD_ATTR_CLASS 409 +-#define _LOAD_ATTR_CLASS_0 410 +-#define _LOAD_ATTR_CLASS_1 411 + #define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN +-#define _LOAD_ATTR_INSTANCE_VALUE 412 +-#define _LOAD_ATTR_INSTANCE_VALUE_0 413 +-#define _LOAD_ATTR_INSTANCE_VALUE_1 414 +-#define _LOAD_ATTR_METHOD_LAZY_DICT 415 +-#define _LOAD_ATTR_METHOD_NO_DICT 416 +-#define _LOAD_ATTR_METHOD_WITH_VALUES 417 +-#define _LOAD_ATTR_MODULE 418 +-#define _LOAD_ATTR_MODULE_FROM_KEYS 419 +-#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 420 +-#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 421 +-#define _LOAD_ATTR_PROPERTY_FRAME 422 +-#define _LOAD_ATTR_SLOT 423 +-#define _LOAD_ATTR_SLOT_0 424 +-#define _LOAD_ATTR_SLOT_1 425 +-#define _LOAD_ATTR_WITH_HINT 426 ++#define _LOAD_ATTR_INSTANCE_VALUE 410 ++#define _LOAD_ATTR_METHOD_LAZY_DICT 411 ++#define _LOAD_ATTR_METHOD_NO_DICT 412 ++#define _LOAD_ATTR_METHOD_WITH_VALUES 413 ++#define _LOAD_ATTR_MODULE 414 ++#define _LOAD_ATTR_MODULE_FROM_KEYS 415 ++#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 416 ++#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 417 ++#define _LOAD_ATTR_PROPERTY_FRAME 418 ++#define _LOAD_ATTR_SLOT 419 ++#define _LOAD_ATTR_WITH_HINT 420 + #define _LOAD_BUILD_CLASS LOAD_BUILD_CLASS +-#define _LOAD_BYTECODE 427 ++#define _LOAD_BYTECODE 421 + #define _LOAD_COMMON_CONSTANT LOAD_COMMON_CONSTANT + #define _LOAD_CONST LOAD_CONST + #define _LOAD_CONST_IMMORTAL LOAD_CONST_IMMORTAL +-#define _LOAD_CONST_INLINE 428 +-#define _LOAD_CONST_INLINE_BORROW 429 +-#define _LOAD_CONST_INLINE_BORROW_WITH_NULL 430 +-#define _LOAD_CONST_INLINE_WITH_NULL 431 ++#define _LOAD_CONST_INLINE 422 ++#define _LOAD_CONST_INLINE_BORROW 423 ++#define _LOAD_CONST_MORTAL LOAD_CONST_MORTAL + #define _LOAD_DEREF LOAD_DEREF +-#define _LOAD_FAST 432 +-#define _LOAD_FAST_0 433 +-#define _LOAD_FAST_1 434 +-#define _LOAD_FAST_2 435 +-#define _LOAD_FAST_3 436 +-#define _LOAD_FAST_4 437 +-#define _LOAD_FAST_5 438 +-#define _LOAD_FAST_6 439 +-#define _LOAD_FAST_7 440 ++#define _LOAD_FAST 424 ++#define _LOAD_FAST_0 425 ++#define _LOAD_FAST_1 426 ++#define _LOAD_FAST_2 427 ++#define _LOAD_FAST_3 428 ++#define _LOAD_FAST_4 429 ++#define _LOAD_FAST_5 430 ++#define _LOAD_FAST_6 431 ++#define _LOAD_FAST_7 432 + #define _LOAD_FAST_AND_CLEAR LOAD_FAST_AND_CLEAR + #define _LOAD_FAST_CHECK LOAD_FAST_CHECK + #define _LOAD_FAST_LOAD_FAST LOAD_FAST_LOAD_FAST + #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 441 +-#define _LOAD_GLOBAL_BUILTINS 442 +-#define _LOAD_GLOBAL_BUILTINS_FROM_KEYS 443 +-#define _LOAD_GLOBAL_MODULE 444 +-#define _LOAD_GLOBAL_MODULE_FROM_KEYS 445 ++#define _LOAD_GLOBAL 433 ++#define _LOAD_GLOBAL_BUILTINS 434 ++#define _LOAD_GLOBAL_BUILTINS_FROM_KEYS 435 ++#define _LOAD_GLOBAL_MODULE 436 ++#define _LOAD_GLOBAL_MODULE_FROM_KEYS 437 + #define _LOAD_LOCALS LOAD_LOCALS + #define _LOAD_NAME LOAD_NAME +-#define _LOAD_SMALL_INT 446 +-#define _LOAD_SMALL_INT_0 447 +-#define _LOAD_SMALL_INT_1 448 +-#define _LOAD_SMALL_INT_2 449 +-#define _LOAD_SMALL_INT_3 450 ++#define _LOAD_SMALL_INT 438 ++#define _LOAD_SMALL_INT_0 439 ++#define _LOAD_SMALL_INT_1 440 ++#define _LOAD_SMALL_INT_2 441 ++#define _LOAD_SMALL_INT_3 442 + #define _LOAD_SPECIAL LOAD_SPECIAL + #define _LOAD_SUPER_ATTR_ATTR LOAD_SUPER_ATTR_ATTR + #define _LOAD_SUPER_ATTR_METHOD LOAD_SUPER_ATTR_METHOD +-#define _MAKE_CALLARGS_A_TUPLE 451 ++#define _MAKE_CALLARGS_A_TUPLE 443 + #define _MAKE_CELL MAKE_CELL + #define _MAKE_FUNCTION MAKE_FUNCTION +-#define _MAKE_WARM 452 ++#define _MAKE_WARM 444 + #define _MAP_ADD MAP_ADD + #define _MATCH_CLASS MATCH_CLASS + #define _MATCH_KEYS MATCH_KEYS + #define _MATCH_MAPPING MATCH_MAPPING + #define _MATCH_SEQUENCE MATCH_SEQUENCE +-#define _MAYBE_EXPAND_METHOD 453 +-#define _MAYBE_EXPAND_METHOD_KW 454 +-#define _MONITOR_CALL 455 +-#define _MONITOR_JUMP_BACKWARD 456 +-#define _MONITOR_RESUME 457 ++#define _MAYBE_EXPAND_METHOD 445 ++#define _MAYBE_EXPAND_METHOD_KW 446 ++#define _MONITOR_CALL 447 ++#define _MONITOR_CALL_KW 448 ++#define _MONITOR_JUMP_BACKWARD 449 ++#define _MONITOR_RESUME 450 + #define _NOP NOP + #define _POP_EXCEPT POP_EXCEPT +-#define _POP_JUMP_IF_FALSE 458 +-#define _POP_JUMP_IF_TRUE 459 ++#define _POP_JUMP_IF_FALSE 451 ++#define _POP_JUMP_IF_TRUE 452 + #define _POP_TOP POP_TOP +-#define _POP_TOP_LOAD_CONST_INLINE_BORROW 460 ++#define _POP_TOP_LOAD_CONST_INLINE_BORROW 453 + #define _PUSH_EXC_INFO PUSH_EXC_INFO +-#define _PUSH_FRAME 461 ++#define _PUSH_FRAME 454 + #define _PUSH_NULL PUSH_NULL +-#define _PY_FRAME_GENERAL 462 +-#define _PY_FRAME_KW 463 +-#define _QUICKEN_RESUME 464 +-#define _REPLACE_WITH_TRUE 465 ++#define _PUSH_NULL_CONDITIONAL 455 ++#define _PY_FRAME_GENERAL 456 ++#define _PY_FRAME_KW 457 ++#define _QUICKEN_RESUME 458 ++#define _REPLACE_WITH_TRUE 459 + #define _RESUME_CHECK RESUME_CHECK + #define _RETURN_GENERATOR RETURN_GENERATOR + #define _RETURN_VALUE RETURN_VALUE +-#define _SAVE_RETURN_OFFSET 466 +-#define _SEND 467 +-#define _SEND_GEN_FRAME 468 ++#define _SAVE_RETURN_OFFSET 460 ++#define _SEND 461 ++#define _SEND_GEN_FRAME 462 + #define _SETUP_ANNOTATIONS SETUP_ANNOTATIONS + #define _SET_ADD SET_ADD + #define _SET_FUNCTION_ATTRIBUTE SET_FUNCTION_ATTRIBUTE + #define _SET_UPDATE SET_UPDATE +-#define _START_EXECUTOR 469 +-#define _STORE_ATTR 470 +-#define _STORE_ATTR_INSTANCE_VALUE 471 +-#define _STORE_ATTR_SLOT 472 +-#define _STORE_ATTR_WITH_HINT 473 ++#define _START_EXECUTOR 463 ++#define _STORE_ATTR 464 ++#define _STORE_ATTR_INSTANCE_VALUE 465 ++#define _STORE_ATTR_SLOT 466 ++#define _STORE_ATTR_WITH_HINT 467 + #define _STORE_DEREF STORE_DEREF +-#define _STORE_FAST 474 +-#define _STORE_FAST_0 475 +-#define _STORE_FAST_1 476 +-#define _STORE_FAST_2 477 +-#define _STORE_FAST_3 478 +-#define _STORE_FAST_4 479 +-#define _STORE_FAST_5 480 +-#define _STORE_FAST_6 481 +-#define _STORE_FAST_7 482 ++#define _STORE_FAST 468 ++#define _STORE_FAST_0 469 ++#define _STORE_FAST_1 470 ++#define _STORE_FAST_2 471 ++#define _STORE_FAST_3 472 ++#define _STORE_FAST_4 473 ++#define _STORE_FAST_5 474 ++#define _STORE_FAST_6 475 ++#define _STORE_FAST_7 476 + #define _STORE_FAST_LOAD_FAST STORE_FAST_LOAD_FAST + #define _STORE_FAST_STORE_FAST STORE_FAST_STORE_FAST + #define _STORE_GLOBAL STORE_GLOBAL + #define _STORE_NAME STORE_NAME +-#define _STORE_SLICE 483 +-#define _STORE_SUBSCR 484 ++#define _STORE_SLICE 477 ++#define _STORE_SUBSCR 478 + #define _STORE_SUBSCR_DICT STORE_SUBSCR_DICT + #define _STORE_SUBSCR_LIST_INT STORE_SUBSCR_LIST_INT + #define _SWAP SWAP +-#define _TIER2_RESUME_CHECK 485 +-#define _TO_BOOL 486 ++#define _TIER2_RESUME_CHECK 479 ++#define _TO_BOOL 480 + #define _TO_BOOL_BOOL TO_BOOL_BOOL + #define _TO_BOOL_INT TO_BOOL_INT + #define _TO_BOOL_LIST TO_BOOL_LIST +@@ -305,13 +299,13 @@ + #define _UNARY_NEGATIVE UNARY_NEGATIVE + #define _UNARY_NOT UNARY_NOT + #define _UNPACK_EX UNPACK_EX +-#define _UNPACK_SEQUENCE 487 ++#define _UNPACK_SEQUENCE 481 + #define _UNPACK_SEQUENCE_LIST UNPACK_SEQUENCE_LIST + #define _UNPACK_SEQUENCE_TUPLE UNPACK_SEQUENCE_TUPLE + #define _UNPACK_SEQUENCE_TWO_TUPLE UNPACK_SEQUENCE_TWO_TUPLE + #define _WITH_EXCEPT_START WITH_EXCEPT_START + #define _YIELD_VALUE YIELD_VALUE +-#define MAX_UOP_ID 487 ++#define MAX_UOP_ID 481 + + #ifdef __cplusplus + } +diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h +index dd775d3f7d3..86a4843ea05 100644 +--- a/Include/internal/pycore_uop_metadata.h ++++ b/Include/internal/pycore_uop_metadata.h +@@ -35,26 +35,27 @@ + [_LOAD_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_PURE_FLAG, + [_LOAD_FAST_AND_CLEAR] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, + [_LOAD_FAST_LOAD_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, +- [_LOAD_CONST] = HAS_ARG_FLAG | HAS_CONST_FLAG | HAS_PURE_FLAG, ++ [_LOAD_CONST_MORTAL] = HAS_ARG_FLAG | HAS_CONST_FLAG, + [_LOAD_CONST_IMMORTAL] = HAS_ARG_FLAG | HAS_CONST_FLAG, + [_LOAD_SMALL_INT_0] = 0, + [_LOAD_SMALL_INT_1] = 0, + [_LOAD_SMALL_INT_2] = 0, + [_LOAD_SMALL_INT_3] = 0, + [_LOAD_SMALL_INT] = HAS_ARG_FLAG, +- [_STORE_FAST_0] = HAS_LOCAL_FLAG, +- [_STORE_FAST_1] = HAS_LOCAL_FLAG, +- [_STORE_FAST_2] = HAS_LOCAL_FLAG, +- [_STORE_FAST_3] = HAS_LOCAL_FLAG, +- [_STORE_FAST_4] = HAS_LOCAL_FLAG, +- [_STORE_FAST_5] = HAS_LOCAL_FLAG, +- [_STORE_FAST_6] = HAS_LOCAL_FLAG, +- [_STORE_FAST_7] = HAS_LOCAL_FLAG, +- [_STORE_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, +- [_STORE_FAST_LOAD_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, +- [_STORE_FAST_STORE_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, ++ [_STORE_FAST_0] = HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, ++ [_STORE_FAST_1] = HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, ++ [_STORE_FAST_2] = HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, ++ [_STORE_FAST_3] = HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, ++ [_STORE_FAST_4] = HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, ++ [_STORE_FAST_5] = HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, ++ [_STORE_FAST_6] = HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, ++ [_STORE_FAST_7] = HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, ++ [_STORE_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, ++ [_STORE_FAST_LOAD_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, ++ [_STORE_FAST_STORE_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, + [_POP_TOP] = HAS_PURE_FLAG, + [_PUSH_NULL] = HAS_PURE_FLAG, ++ [_END_FOR] = HAS_ESCAPES_FLAG | HAS_NO_SAVE_IP_FLAG, + [_END_SEND] = HAS_PURE_FLAG, + [_UNARY_NEGATIVE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_UNARY_NOT] = HAS_PURE_FLAG, +@@ -81,19 +82,20 @@ + [_GUARD_BOTH_UNICODE] = HAS_EXIT_FLAG, + [_BINARY_OP_ADD_UNICODE] = HAS_ERROR_FLAG | HAS_PURE_FLAG, + [_BINARY_OP_INPLACE_ADD_UNICODE] = HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG, +- [_BINARY_SUBSCR] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, ++ [_GUARD_BINARY_OP_EXTEND] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, ++ [_BINARY_OP_EXTEND] = HAS_ESCAPES_FLAG | HAS_PURE_FLAG, + [_BINARY_SLICE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_STORE_SLICE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, +- [_BINARY_SUBSCR_LIST_INT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, +- [_BINARY_SUBSCR_STR_INT] = HAS_DEOPT_FLAG, +- [_BINARY_SUBSCR_TUPLE_INT] = HAS_DEOPT_FLAG, +- [_BINARY_SUBSCR_DICT] = HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, +- [_BINARY_SUBSCR_CHECK_FUNC] = HAS_DEOPT_FLAG, +- [_BINARY_SUBSCR_INIT_CALL] = 0, ++ [_BINARY_OP_SUBSCR_LIST_INT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, ++ [_BINARY_OP_SUBSCR_STR_INT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, ++ [_BINARY_OP_SUBSCR_TUPLE_INT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, ++ [_BINARY_OP_SUBSCR_DICT] = HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, ++ [_BINARY_OP_SUBSCR_CHECK_FUNC] = HAS_DEOPT_FLAG, ++ [_BINARY_OP_SUBSCR_INIT_CALL] = 0, + [_LIST_APPEND] = HAS_ARG_FLAG | HAS_ERROR_FLAG, + [_SET_ADD] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_STORE_SUBSCR] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, +- [_STORE_SUBSCR_LIST_INT] = HAS_DEOPT_FLAG, ++ [_STORE_SUBSCR_LIST_INT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, + [_STORE_SUBSCR_DICT] = HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_DELETE_SUBSCR] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_CALL_INTRINSIC_1] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, +@@ -121,21 +123,22 @@ + [_LOAD_LOCALS] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_LOAD_NAME] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_LOAD_GLOBAL] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, ++ [_PUSH_NULL_CONDITIONAL] = HAS_ARG_FLAG, + [_GUARD_GLOBALS_VERSION] = HAS_DEOPT_FLAG, + [_GUARD_GLOBALS_VERSION_PUSH_KEYS] = HAS_DEOPT_FLAG, + [_GUARD_BUILTINS_VERSION_PUSH_KEYS] = HAS_DEOPT_FLAG, +- [_LOAD_GLOBAL_MODULE_FROM_KEYS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, +- [_LOAD_GLOBAL_BUILTINS_FROM_KEYS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, ++ [_LOAD_GLOBAL_MODULE_FROM_KEYS] = HAS_DEOPT_FLAG, ++ [_LOAD_GLOBAL_BUILTINS_FROM_KEYS] = HAS_DEOPT_FLAG, + [_DELETE_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, +- [_MAKE_CELL] = HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG, ++ [_MAKE_CELL] = HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, + [_DELETE_DEREF] = HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, + [_LOAD_FROM_DICT_OR_DEREF] = HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, + [_LOAD_DEREF] = HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_STORE_DEREF] = HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ESCAPES_FLAG, + [_COPY_FREE_VARS] = HAS_ARG_FLAG, + [_BUILD_STRING] = HAS_ARG_FLAG | HAS_ERROR_FLAG, +- [_BUILD_TUPLE] = HAS_ARG_FLAG | HAS_ERROR_FLAG, +- [_BUILD_LIST] = HAS_ARG_FLAG | HAS_ERROR_FLAG, ++ [_BUILD_TUPLE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG, ++ [_BUILD_LIST] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG, + [_LIST_EXTEND] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_SET_UPDATE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_BUILD_SET] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, +@@ -145,29 +148,24 @@ + [_DICT_MERGE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_MAP_ADD] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_LOAD_SUPER_ATTR_ATTR] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, +- [_LOAD_SUPER_ATTR_METHOD] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, ++ [_LOAD_SUPER_ATTR_METHOD] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, + [_LOAD_ATTR] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_GUARD_TYPE_VERSION] = HAS_EXIT_FLAG, ++ [_GUARD_TYPE_VERSION_AND_LOCK] = HAS_EXIT_FLAG, + [_CHECK_MANAGED_OBJECT_HAS_VALUES] = HAS_DEOPT_FLAG, +- [_LOAD_ATTR_INSTANCE_VALUE_0] = HAS_DEOPT_FLAG, +- [_LOAD_ATTR_INSTANCE_VALUE_1] = HAS_DEOPT_FLAG, +- [_LOAD_ATTR_INSTANCE_VALUE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_OPARG_AND_1_FLAG, ++ [_LOAD_ATTR_INSTANCE_VALUE] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, + [_CHECK_ATTR_MODULE_PUSH_KEYS] = HAS_DEOPT_FLAG, +- [_LOAD_ATTR_MODULE_FROM_KEYS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, ++ [_LOAD_ATTR_MODULE_FROM_KEYS] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, + [_CHECK_ATTR_WITH_HINT] = HAS_EXIT_FLAG, + [_LOAD_ATTR_WITH_HINT] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG, +- [_LOAD_ATTR_SLOT_0] = HAS_DEOPT_FLAG, +- [_LOAD_ATTR_SLOT_1] = HAS_DEOPT_FLAG, +- [_LOAD_ATTR_SLOT] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_OPARG_AND_1_FLAG, ++ [_LOAD_ATTR_SLOT] = HAS_DEOPT_FLAG, + [_CHECK_ATTR_CLASS] = HAS_EXIT_FLAG, +- [_LOAD_ATTR_CLASS_0] = 0, +- [_LOAD_ATTR_CLASS_1] = 0, +- [_LOAD_ATTR_CLASS] = HAS_ARG_FLAG | HAS_OPARG_AND_1_FLAG, ++ [_LOAD_ATTR_CLASS] = 0, + [_LOAD_ATTR_PROPERTY_FRAME] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_GUARD_DORV_NO_DICT] = HAS_EXIT_FLAG, +- [_STORE_ATTR_INSTANCE_VALUE] = 0, ++ [_STORE_ATTR_INSTANCE_VALUE] = HAS_ESCAPES_FLAG, + [_STORE_ATTR_WITH_HINT] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, +- [_STORE_ATTR_SLOT] = 0, ++ [_STORE_ATTR_SLOT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, + [_COMPARE_OP] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_COMPARE_OP_FLOAT] = HAS_ARG_FLAG, + [_COMPARE_OP_INT] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, +@@ -210,16 +208,16 @@ + [_LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = HAS_ARG_FLAG, + [_CHECK_ATTR_METHOD_LAZY_DICT] = HAS_DEOPT_FLAG, + [_LOAD_ATTR_METHOD_LAZY_DICT] = HAS_ARG_FLAG, +- [_MAYBE_EXPAND_METHOD] = HAS_ARG_FLAG, ++ [_MAYBE_EXPAND_METHOD] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, + [_PY_FRAME_GENERAL] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, + [_CHECK_FUNCTION_VERSION] = HAS_ARG_FLAG | HAS_EXIT_FLAG, + [_CHECK_FUNCTION_VERSION_INLINE] = HAS_EXIT_FLAG, + [_CHECK_METHOD_VERSION] = HAS_ARG_FLAG | HAS_EXIT_FLAG, +- [_EXPAND_METHOD] = HAS_ARG_FLAG, ++ [_EXPAND_METHOD] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, + [_CHECK_IS_NOT_PY_CALLABLE] = HAS_ARG_FLAG | HAS_EXIT_FLAG, + [_CALL_NON_PY_GENERAL] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_CHECK_CALL_BOUND_METHOD_EXACT_ARGS] = HAS_ARG_FLAG | HAS_EXIT_FLAG, +- [_INIT_CALL_BOUND_METHOD_EXACT_ARGS] = HAS_ARG_FLAG, ++ [_INIT_CALL_BOUND_METHOD_EXACT_ARGS] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, + [_CHECK_PEP_523] = HAS_DEOPT_FLAG, + [_CHECK_FUNCTION_EXACT_ARGS] = HAS_ARG_FLAG | HAS_EXIT_FLAG, + [_CHECK_STACK_SPACE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, +@@ -230,10 +228,10 @@ + [_INIT_CALL_PY_EXACT_ARGS_4] = HAS_PURE_FLAG, + [_INIT_CALL_PY_EXACT_ARGS] = HAS_ARG_FLAG | HAS_PURE_FLAG, + [_PUSH_FRAME] = 0, +- [_CALL_TYPE_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, ++ [_CALL_TYPE_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, + [_CALL_STR_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_CALL_TUPLE_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, +- [_CHECK_AND_ALLOCATE_OBJECT] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG, ++ [_CHECK_AND_ALLOCATE_OBJECT] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, + [_CREATE_INIT_FRAME] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, + [_EXIT_INIT_CHECK] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, + [_CALL_BUILTIN_CLASS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, +@@ -242,19 +240,19 @@ + [_CALL_BUILTIN_FAST_WITH_KEYWORDS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_CALL_LEN] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, + [_CALL_ISINSTANCE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, +- [_CALL_LIST_APPEND] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG, ++ [_CALL_LIST_APPEND] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_CALL_METHOD_DESCRIPTOR_O] = HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_CALL_METHOD_DESCRIPTOR_NOARGS] = HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_CALL_METHOD_DESCRIPTOR_FAST] = HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, +- [_MAYBE_EXPAND_METHOD_KW] = HAS_ARG_FLAG, ++ [_MAYBE_EXPAND_METHOD_KW] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, + [_PY_FRAME_KW] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, + [_CHECK_FUNCTION_VERSION_KW] = HAS_ARG_FLAG | HAS_EXIT_FLAG, + [_CHECK_METHOD_VERSION_KW] = HAS_ARG_FLAG | HAS_EXIT_FLAG, +- [_EXPAND_METHOD_KW] = HAS_ARG_FLAG, ++ [_EXPAND_METHOD_KW] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, + [_CHECK_IS_NOT_PY_CALLABLE_KW] = HAS_ARG_FLAG | HAS_EXIT_FLAG, + [_CALL_KW_NON_PY] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, +- [_MAKE_CALLARGS_A_TUPLE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, ++ [_MAKE_CALLARGS_A_TUPLE] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, + [_MAKE_FUNCTION] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_SET_FUNCTION_ATTRIBUTE] = HAS_ARG_FLAG, + [_RETURN_GENERATOR] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, +@@ -267,8 +265,8 @@ + [_SWAP] = HAS_ARG_FLAG | HAS_PURE_FLAG, + [_GUARD_IS_TRUE_POP] = HAS_EXIT_FLAG, + [_GUARD_IS_FALSE_POP] = HAS_EXIT_FLAG, +- [_GUARD_IS_NONE_POP] = HAS_EXIT_FLAG, +- [_GUARD_IS_NOT_NONE_POP] = HAS_EXIT_FLAG, ++ [_GUARD_IS_NONE_POP] = HAS_EXIT_FLAG | HAS_ESCAPES_FLAG, ++ [_GUARD_IS_NOT_NONE_POP] = HAS_EXIT_FLAG | HAS_ESCAPES_FLAG, + [_JUMP_TO_TOP] = 0, + [_SET_IP] = 0, + [_CHECK_STACK_SPACE_OPERAND] = HAS_DEOPT_FLAG, +@@ -277,21 +275,17 @@ + [_CHECK_VALIDITY] = HAS_DEOPT_FLAG, + [_LOAD_CONST_INLINE] = HAS_PURE_FLAG, + [_LOAD_CONST_INLINE_BORROW] = HAS_PURE_FLAG, +- [_POP_TOP_LOAD_CONST_INLINE_BORROW] = HAS_PURE_FLAG, +- [_LOAD_CONST_INLINE_WITH_NULL] = HAS_PURE_FLAG, +- [_LOAD_CONST_INLINE_BORROW_WITH_NULL] = HAS_PURE_FLAG, ++ [_POP_TOP_LOAD_CONST_INLINE_BORROW] = HAS_ESCAPES_FLAG | HAS_PURE_FLAG, + [_CHECK_FUNCTION] = HAS_DEOPT_FLAG, +- [_LOAD_GLOBAL_MODULE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, +- [_LOAD_GLOBAL_BUILTINS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, +- [_LOAD_ATTR_MODULE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, +- [_INTERNAL_INCREMENT_OPT_COUNTER] = 0, +- [_DYNAMIC_EXIT] = HAS_ESCAPES_FLAG, +- [_START_EXECUTOR] = 0, ++ [_LOAD_GLOBAL_MODULE] = HAS_DEOPT_FLAG, ++ [_LOAD_GLOBAL_BUILTINS] = HAS_DEOPT_FLAG, ++ [_LOAD_ATTR_MODULE] = HAS_DEOPT_FLAG, ++ [_START_EXECUTOR] = HAS_ESCAPES_FLAG, + [_MAKE_WARM] = 0, + [_FATAL_ERROR] = 0, + [_CHECK_VALIDITY_AND_SET_IP] = HAS_DEOPT_FLAG, + [_DEOPT] = 0, +- [_ERROR_POP_N] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, ++ [_ERROR_POP_N] = HAS_ARG_FLAG, + [_TIER2_RESUME_CHECK] = HAS_DEOPT_FLAG, + }; + +@@ -307,19 +301,19 @@ + [_BINARY_OP_ADD_FLOAT] = "_BINARY_OP_ADD_FLOAT", + [_BINARY_OP_ADD_INT] = "_BINARY_OP_ADD_INT", + [_BINARY_OP_ADD_UNICODE] = "_BINARY_OP_ADD_UNICODE", ++ [_BINARY_OP_EXTEND] = "_BINARY_OP_EXTEND", + [_BINARY_OP_INPLACE_ADD_UNICODE] = "_BINARY_OP_INPLACE_ADD_UNICODE", + [_BINARY_OP_MULTIPLY_FLOAT] = "_BINARY_OP_MULTIPLY_FLOAT", + [_BINARY_OP_MULTIPLY_INT] = "_BINARY_OP_MULTIPLY_INT", ++ [_BINARY_OP_SUBSCR_CHECK_FUNC] = "_BINARY_OP_SUBSCR_CHECK_FUNC", ++ [_BINARY_OP_SUBSCR_DICT] = "_BINARY_OP_SUBSCR_DICT", ++ [_BINARY_OP_SUBSCR_INIT_CALL] = "_BINARY_OP_SUBSCR_INIT_CALL", ++ [_BINARY_OP_SUBSCR_LIST_INT] = "_BINARY_OP_SUBSCR_LIST_INT", ++ [_BINARY_OP_SUBSCR_STR_INT] = "_BINARY_OP_SUBSCR_STR_INT", ++ [_BINARY_OP_SUBSCR_TUPLE_INT] = "_BINARY_OP_SUBSCR_TUPLE_INT", + [_BINARY_OP_SUBTRACT_FLOAT] = "_BINARY_OP_SUBTRACT_FLOAT", + [_BINARY_OP_SUBTRACT_INT] = "_BINARY_OP_SUBTRACT_INT", + [_BINARY_SLICE] = "_BINARY_SLICE", +- [_BINARY_SUBSCR] = "_BINARY_SUBSCR", +- [_BINARY_SUBSCR_CHECK_FUNC] = "_BINARY_SUBSCR_CHECK_FUNC", +- [_BINARY_SUBSCR_DICT] = "_BINARY_SUBSCR_DICT", +- [_BINARY_SUBSCR_INIT_CALL] = "_BINARY_SUBSCR_INIT_CALL", +- [_BINARY_SUBSCR_LIST_INT] = "_BINARY_SUBSCR_LIST_INT", +- [_BINARY_SUBSCR_STR_INT] = "_BINARY_SUBSCR_STR_INT", +- [_BINARY_SUBSCR_TUPLE_INT] = "_BINARY_SUBSCR_TUPLE_INT", + [_BUILD_LIST] = "_BUILD_LIST", + [_BUILD_MAP] = "_BUILD_MAP", + [_BUILD_SET] = "_BUILD_SET", +@@ -389,7 +383,7 @@ + [_DEOPT] = "_DEOPT", + [_DICT_MERGE] = "_DICT_MERGE", + [_DICT_UPDATE] = "_DICT_UPDATE", +- [_DYNAMIC_EXIT] = "_DYNAMIC_EXIT", ++ [_END_FOR] = "_END_FOR", + [_END_SEND] = "_END_SEND", + [_ERROR_POP_N] = "_ERROR_POP_N", + [_EXIT_INIT_CHECK] = "_EXIT_INIT_CHECK", +@@ -407,6 +401,7 @@ + [_GET_ITER] = "_GET_ITER", + [_GET_LEN] = "_GET_LEN", + [_GET_YIELD_FROM_ITER] = "_GET_YIELD_FROM_ITER", ++ [_GUARD_BINARY_OP_EXTEND] = "_GUARD_BINARY_OP_EXTEND", + [_GUARD_BOTH_FLOAT] = "_GUARD_BOTH_FLOAT", + [_GUARD_BOTH_INT] = "_GUARD_BOTH_INT", + [_GUARD_BOTH_UNICODE] = "_GUARD_BOTH_UNICODE", +@@ -428,6 +423,7 @@ + [_GUARD_TOS_FLOAT] = "_GUARD_TOS_FLOAT", + [_GUARD_TOS_INT] = "_GUARD_TOS_INT", + [_GUARD_TYPE_VERSION] = "_GUARD_TYPE_VERSION", ++ [_GUARD_TYPE_VERSION_AND_LOCK] = "_GUARD_TYPE_VERSION_AND_LOCK", + [_IMPORT_FROM] = "_IMPORT_FROM", + [_IMPORT_NAME] = "_IMPORT_NAME", + [_INIT_CALL_BOUND_METHOD_EXACT_ARGS] = "_INIT_CALL_BOUND_METHOD_EXACT_ARGS", +@@ -437,7 +433,6 @@ + [_INIT_CALL_PY_EXACT_ARGS_2] = "_INIT_CALL_PY_EXACT_ARGS_2", + [_INIT_CALL_PY_EXACT_ARGS_3] = "_INIT_CALL_PY_EXACT_ARGS_3", + [_INIT_CALL_PY_EXACT_ARGS_4] = "_INIT_CALL_PY_EXACT_ARGS_4", +- [_INTERNAL_INCREMENT_OPT_COUNTER] = "_INTERNAL_INCREMENT_OPT_COUNTER", + [_IS_NONE] = "_IS_NONE", + [_IS_OP] = "_IS_OP", + [_ITER_CHECK_LIST] = "_ITER_CHECK_LIST", +@@ -451,11 +446,7 @@ + [_LIST_EXTEND] = "_LIST_EXTEND", + [_LOAD_ATTR] = "_LOAD_ATTR", + [_LOAD_ATTR_CLASS] = "_LOAD_ATTR_CLASS", +- [_LOAD_ATTR_CLASS_0] = "_LOAD_ATTR_CLASS_0", +- [_LOAD_ATTR_CLASS_1] = "_LOAD_ATTR_CLASS_1", + [_LOAD_ATTR_INSTANCE_VALUE] = "_LOAD_ATTR_INSTANCE_VALUE", +- [_LOAD_ATTR_INSTANCE_VALUE_0] = "_LOAD_ATTR_INSTANCE_VALUE_0", +- [_LOAD_ATTR_INSTANCE_VALUE_1] = "_LOAD_ATTR_INSTANCE_VALUE_1", + [_LOAD_ATTR_METHOD_LAZY_DICT] = "_LOAD_ATTR_METHOD_LAZY_DICT", + [_LOAD_ATTR_METHOD_NO_DICT] = "_LOAD_ATTR_METHOD_NO_DICT", + [_LOAD_ATTR_METHOD_WITH_VALUES] = "_LOAD_ATTR_METHOD_WITH_VALUES", +@@ -465,17 +456,13 @@ + [_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = "_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", + [_LOAD_ATTR_PROPERTY_FRAME] = "_LOAD_ATTR_PROPERTY_FRAME", + [_LOAD_ATTR_SLOT] = "_LOAD_ATTR_SLOT", +- [_LOAD_ATTR_SLOT_0] = "_LOAD_ATTR_SLOT_0", +- [_LOAD_ATTR_SLOT_1] = "_LOAD_ATTR_SLOT_1", + [_LOAD_ATTR_WITH_HINT] = "_LOAD_ATTR_WITH_HINT", + [_LOAD_BUILD_CLASS] = "_LOAD_BUILD_CLASS", + [_LOAD_COMMON_CONSTANT] = "_LOAD_COMMON_CONSTANT", +- [_LOAD_CONST] = "_LOAD_CONST", + [_LOAD_CONST_IMMORTAL] = "_LOAD_CONST_IMMORTAL", + [_LOAD_CONST_INLINE] = "_LOAD_CONST_INLINE", + [_LOAD_CONST_INLINE_BORROW] = "_LOAD_CONST_INLINE_BORROW", +- [_LOAD_CONST_INLINE_BORROW_WITH_NULL] = "_LOAD_CONST_INLINE_BORROW_WITH_NULL", +- [_LOAD_CONST_INLINE_WITH_NULL] = "_LOAD_CONST_INLINE_WITH_NULL", ++ [_LOAD_CONST_MORTAL] = "_LOAD_CONST_MORTAL", + [_LOAD_DEREF] = "_LOAD_DEREF", + [_LOAD_FAST] = "_LOAD_FAST", + [_LOAD_FAST_0] = "_LOAD_FAST_0", +@@ -523,6 +510,7 @@ + [_PUSH_EXC_INFO] = "_PUSH_EXC_INFO", + [_PUSH_FRAME] = "_PUSH_FRAME", + [_PUSH_NULL] = "_PUSH_NULL", ++ [_PUSH_NULL_CONDITIONAL] = "_PUSH_NULL_CONDITIONAL", + [_PY_FRAME_GENERAL] = "_PY_FRAME_GENERAL", + [_PY_FRAME_KW] = "_PY_FRAME_KW", + [_REPLACE_WITH_TRUE] = "_REPLACE_WITH_TRUE", +@@ -613,7 +601,7 @@ + return 0; + case _LOAD_FAST_LOAD_FAST: + return 0; +- case _LOAD_CONST: ++ case _LOAD_CONST_MORTAL: + return 0; + case _LOAD_CONST_IMMORTAL: + return 0; +@@ -653,6 +641,8 @@ + return 1; + case _PUSH_NULL: + return 0; ++ case _END_FOR: ++ return 1; + case _END_SEND: + return 2; + case _UNARY_NEGATIVE: +@@ -705,24 +695,26 @@ + return 2; + case _BINARY_OP_INPLACE_ADD_UNICODE: + return 2; +- case _BINARY_SUBSCR: ++ case _GUARD_BINARY_OP_EXTEND: ++ return 0; ++ case _BINARY_OP_EXTEND: + return 2; + case _BINARY_SLICE: + return 3; + case _STORE_SLICE: + return 4; +- case _BINARY_SUBSCR_LIST_INT: ++ case _BINARY_OP_SUBSCR_LIST_INT: + return 2; +- case _BINARY_SUBSCR_STR_INT: ++ case _BINARY_OP_SUBSCR_STR_INT: + return 2; +- case _BINARY_SUBSCR_TUPLE_INT: ++ case _BINARY_OP_SUBSCR_TUPLE_INT: + return 2; +- case _BINARY_SUBSCR_DICT: ++ case _BINARY_OP_SUBSCR_DICT: + return 2; +- case _BINARY_SUBSCR_CHECK_FUNC: ++ case _BINARY_OP_SUBSCR_CHECK_FUNC: + return 0; +- case _BINARY_SUBSCR_INIT_CALL: +- return 2; ++ case _BINARY_OP_SUBSCR_INIT_CALL: ++ return 3; + case _LIST_APPEND: + return 1; + case _SET_ADD: +@@ -785,6 +777,8 @@ + return 0; + case _LOAD_GLOBAL: + return 0; ++ case _PUSH_NULL_CONDITIONAL: ++ return 0; + case _GUARD_GLOBALS_VERSION: + return 0; + case _GUARD_GLOBALS_VERSION_PUSH_KEYS: +@@ -839,12 +833,10 @@ + return 1; + case _GUARD_TYPE_VERSION: + return 0; ++ case _GUARD_TYPE_VERSION_AND_LOCK: ++ return 0; + case _CHECK_MANAGED_OBJECT_HAS_VALUES: + return 0; +- case _LOAD_ATTR_INSTANCE_VALUE_0: +- return 1; +- case _LOAD_ATTR_INSTANCE_VALUE_1: +- return 1; + case _LOAD_ATTR_INSTANCE_VALUE: + return 1; + case _CHECK_ATTR_MODULE_PUSH_KEYS: +@@ -854,19 +846,11 @@ + case _CHECK_ATTR_WITH_HINT: + return 0; + case _LOAD_ATTR_WITH_HINT: +- return 1; +- case _LOAD_ATTR_SLOT_0: +- return 1; +- case _LOAD_ATTR_SLOT_1: +- return 1; ++ return 2; + case _LOAD_ATTR_SLOT: + return 1; + case _CHECK_ATTR_CLASS: + return 0; +- case _LOAD_ATTR_CLASS_0: +- return 1; +- case _LOAD_ATTR_CLASS_1: +- return 1; + case _LOAD_ATTR_CLASS: + return 1; + case _LOAD_ATTR_PROPERTY_FRAME: +@@ -974,7 +958,7 @@ + case _CHECK_METHOD_VERSION: + return 0; + case _EXPAND_METHOD: +- return 2 + oparg; ++ return 0; + case _CHECK_IS_NOT_PY_CALLABLE: + return 0; + case _CALL_NON_PY_GENERAL: +@@ -982,7 +966,7 @@ + case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: + return 0; + case _INIT_CALL_BOUND_METHOD_EXACT_ARGS: +- return 2 + oparg; ++ return 0; + case _CHECK_PEP_523: + return 0; + case _CHECK_FUNCTION_EXACT_ARGS: +@@ -1046,13 +1030,13 @@ + case _CHECK_METHOD_VERSION_KW: + return 0; + case _EXPAND_METHOD_KW: +- return 3 + oparg; ++ return 0; + case _CHECK_IS_NOT_PY_CALLABLE_KW: + return 0; + case _CALL_KW_NON_PY: + return 3 + oparg; + case _MAKE_CALLARGS_A_TUPLE: +- return 1 + (oparg & 1); ++ return 2; + case _MAKE_FUNCTION: + return 1; + case _SET_FUNCTION_ATTRIBUTE: +@@ -1060,7 +1044,7 @@ + case _RETURN_GENERATOR: + return 0; + case _BUILD_SLICE: +- return 2 + ((oparg == 3) ? 1 : 0); ++ return oparg; + case _CONVERT_VALUE: + return 1; + case _FORMAT_SIMPLE: +@@ -1072,7 +1056,7 @@ + case _BINARY_OP: + return 2; + case _SWAP: +- return 2 + (oparg-2); ++ return 0; + case _GUARD_IS_TRUE_POP: + return 1; + case _GUARD_IS_FALSE_POP: +@@ -1099,10 +1083,6 @@ + return 0; + case _POP_TOP_LOAD_CONST_INLINE_BORROW: + return 1; +- case _LOAD_CONST_INLINE_WITH_NULL: +- return 0; +- case _LOAD_CONST_INLINE_BORROW_WITH_NULL: +- return 0; + case _CHECK_FUNCTION: + return 0; + case _LOAD_GLOBAL_MODULE: +@@ -1111,10 +1091,6 @@ + return 0; + case _LOAD_ATTR_MODULE: + return 1; +- case _INTERNAL_INCREMENT_OPT_COUNTER: +- return 1; +- case _DYNAMIC_EXIT: +- return 0; + case _START_EXECUTOR: + return 0; + case _MAKE_WARM: +@@ -1126,7 +1102,7 @@ + case _DEOPT: + return 0; + case _ERROR_POP_N: +- return oparg; ++ return 0; + case _TIER2_RESUME_CHECK: + return 0; + default: +diff --git a/Include/internal/pycore_warnings.h b/Include/internal/pycore_warnings.h +index f9f6559312f..672228cd6fb 100644 +--- a/Include/internal/pycore_warnings.h ++++ b/Include/internal/pycore_warnings.h +@@ -14,7 +14,7 @@ + PyObject *filters; /* List */ + PyObject *once_registry; /* Dict */ + PyObject *default_action; /* String */ +- PyMutex mutex; ++ _PyRecursiveMutex lock; + long filters_version; + }; + +diff --git a/Include/opcode.h b/Include/opcode.h +index 2619b690019..fcb972f2ec2 100644 +--- a/Include/opcode.h ++++ b/Include/opcode.h +@@ -33,8 +33,9 @@ + #define NB_INPLACE_SUBTRACT 23 + #define NB_INPLACE_TRUE_DIVIDE 24 + #define NB_INPLACE_XOR 25 ++#define NB_SUBSCR 26 + +-#define NB_OPARG_LAST 25 ++#define NB_OPARG_LAST 26 + + #ifdef __cplusplus + } +diff --git a/Include/opcode_ids.h b/Include/opcode_ids.h +index ce3d23eaa6d..54f543f4a8a 100644 +--- a/Include/opcode_ids.h ++++ b/Include/opcode_ids.h +@@ -12,7 +12,7 @@ + /* Instruction opcodes for compiled code */ + #define CACHE 0 + #define BINARY_SLICE 1 +-#define BINARY_SUBSCR 2 ++#define CALL_FUNCTION_EX 2 + #define BINARY_OP_INPLACE_ADD_UNICODE 3 + #define CHECK_EG_MATCH 4 + #define CHECK_EXC_MATCH 5 +@@ -38,189 +38,196 @@ + #define MATCH_MAPPING 25 + #define MATCH_SEQUENCE 26 + #define NOP 27 +-#define POP_EXCEPT 28 +-#define POP_TOP 29 +-#define PUSH_EXC_INFO 30 +-#define PUSH_NULL 31 +-#define RETURN_GENERATOR 32 +-#define RETURN_VALUE 33 +-#define SETUP_ANNOTATIONS 34 +-#define STORE_SLICE 35 +-#define STORE_SUBSCR 36 +-#define TO_BOOL 37 +-#define UNARY_INVERT 38 +-#define UNARY_NEGATIVE 39 +-#define UNARY_NOT 40 +-#define WITH_EXCEPT_START 41 +-#define BINARY_OP 42 +-#define BUILD_LIST 43 +-#define BUILD_MAP 44 +-#define BUILD_SET 45 +-#define BUILD_SLICE 46 +-#define BUILD_STRING 47 +-#define BUILD_TUPLE 48 +-#define CALL 49 +-#define CALL_FUNCTION_EX 50 +-#define CALL_INTRINSIC_1 51 +-#define CALL_INTRINSIC_2 52 +-#define CALL_KW 53 +-#define COMPARE_OP 54 +-#define CONTAINS_OP 55 +-#define CONVERT_VALUE 56 +-#define COPY 57 +-#define COPY_FREE_VARS 58 +-#define DELETE_ATTR 59 +-#define DELETE_DEREF 60 +-#define DELETE_FAST 61 +-#define DELETE_GLOBAL 62 +-#define DELETE_NAME 63 +-#define DICT_MERGE 64 +-#define DICT_UPDATE 65 +-#define EXTENDED_ARG 66 +-#define FOR_ITER 67 +-#define GET_AWAITABLE 68 +-#define IMPORT_FROM 69 +-#define IMPORT_NAME 70 +-#define IS_OP 71 +-#define JUMP_BACKWARD 72 +-#define JUMP_BACKWARD_NO_INTERRUPT 73 +-#define JUMP_FORWARD 74 +-#define LIST_APPEND 75 +-#define LIST_EXTEND 76 +-#define LOAD_ATTR 77 +-#define LOAD_COMMON_CONSTANT 78 +-#define LOAD_CONST 79 +-#define LOAD_DEREF 80 +-#define LOAD_FAST 81 +-#define LOAD_FAST_AND_CLEAR 82 +-#define LOAD_FAST_CHECK 83 +-#define LOAD_FAST_LOAD_FAST 84 +-#define LOAD_FROM_DICT_OR_DEREF 85 +-#define LOAD_FROM_DICT_OR_GLOBALS 86 +-#define LOAD_GLOBAL 87 +-#define LOAD_NAME 88 +-#define LOAD_SMALL_INT 89 +-#define LOAD_SPECIAL 90 +-#define LOAD_SUPER_ATTR 91 +-#define MAKE_CELL 92 +-#define MAP_ADD 93 +-#define MATCH_CLASS 94 +-#define POP_JUMP_IF_FALSE 95 +-#define POP_JUMP_IF_NONE 96 +-#define POP_JUMP_IF_NOT_NONE 97 +-#define POP_JUMP_IF_TRUE 98 +-#define RAISE_VARARGS 99 +-#define RERAISE 100 +-#define SEND 101 +-#define SET_ADD 102 +-#define SET_FUNCTION_ATTRIBUTE 103 +-#define SET_UPDATE 104 +-#define STORE_ATTR 105 +-#define STORE_DEREF 106 +-#define STORE_FAST 107 +-#define STORE_FAST_LOAD_FAST 108 +-#define STORE_FAST_STORE_FAST 109 +-#define STORE_GLOBAL 110 +-#define STORE_NAME 111 +-#define SWAP 112 +-#define UNPACK_EX 113 +-#define UNPACK_SEQUENCE 114 +-#define YIELD_VALUE 115 ++#define NOT_TAKEN 28 ++#define POP_EXCEPT 29 ++#define POP_ITER 30 ++#define POP_TOP 31 ++#define PUSH_EXC_INFO 32 ++#define PUSH_NULL 33 ++#define RETURN_GENERATOR 34 ++#define RETURN_VALUE 35 ++#define SETUP_ANNOTATIONS 36 ++#define STORE_SLICE 37 ++#define STORE_SUBSCR 38 ++#define TO_BOOL 39 ++#define UNARY_INVERT 40 ++#define UNARY_NEGATIVE 41 ++#define UNARY_NOT 42 ++#define WITH_EXCEPT_START 43 ++#define BINARY_OP 44 ++#define BUILD_LIST 45 ++#define BUILD_MAP 46 ++#define BUILD_SET 47 ++#define BUILD_SLICE 48 ++#define BUILD_STRING 49 ++#define BUILD_TUPLE 50 ++#define CALL 51 ++#define CALL_INTRINSIC_1 52 ++#define CALL_INTRINSIC_2 53 ++#define CALL_KW 54 ++#define COMPARE_OP 55 ++#define CONTAINS_OP 56 ++#define CONVERT_VALUE 57 ++#define COPY 58 ++#define COPY_FREE_VARS 59 ++#define DELETE_ATTR 60 ++#define DELETE_DEREF 61 ++#define DELETE_FAST 62 ++#define DELETE_GLOBAL 63 ++#define DELETE_NAME 64 ++#define DICT_MERGE 65 ++#define DICT_UPDATE 66 ++#define EXTENDED_ARG 67 ++#define FOR_ITER 68 ++#define GET_AWAITABLE 69 ++#define IMPORT_FROM 70 ++#define IMPORT_NAME 71 ++#define IS_OP 72 ++#define JUMP_BACKWARD 73 ++#define JUMP_BACKWARD_NO_INTERRUPT 74 ++#define JUMP_FORWARD 75 ++#define LIST_APPEND 76 ++#define LIST_EXTEND 77 ++#define LOAD_ATTR 78 ++#define LOAD_COMMON_CONSTANT 79 ++#define LOAD_CONST 80 ++#define LOAD_DEREF 81 ++#define LOAD_FAST 82 ++#define LOAD_FAST_AND_CLEAR 83 ++#define LOAD_FAST_CHECK 84 ++#define LOAD_FAST_LOAD_FAST 85 ++#define LOAD_FROM_DICT_OR_DEREF 86 ++#define LOAD_FROM_DICT_OR_GLOBALS 87 ++#define LOAD_GLOBAL 88 ++#define LOAD_NAME 89 ++#define LOAD_SMALL_INT 90 ++#define LOAD_SPECIAL 91 ++#define LOAD_SUPER_ATTR 92 ++#define MAKE_CELL 93 ++#define MAP_ADD 94 ++#define MATCH_CLASS 95 ++#define POP_JUMP_IF_FALSE 96 ++#define POP_JUMP_IF_NONE 97 ++#define POP_JUMP_IF_NOT_NONE 98 ++#define POP_JUMP_IF_TRUE 99 ++#define RAISE_VARARGS 100 ++#define RERAISE 101 ++#define SEND 102 ++#define SET_ADD 103 ++#define SET_FUNCTION_ATTRIBUTE 104 ++#define SET_UPDATE 105 ++#define STORE_ATTR 106 ++#define STORE_DEREF 107 ++#define STORE_FAST 108 ++#define STORE_FAST_LOAD_FAST 109 ++#define STORE_FAST_STORE_FAST 110 ++#define STORE_GLOBAL 111 ++#define STORE_NAME 112 ++#define SWAP 113 ++#define UNPACK_EX 114 ++#define UNPACK_SEQUENCE 115 ++#define YIELD_VALUE 116 + #define RESUME 149 + #define BINARY_OP_ADD_FLOAT 150 + #define BINARY_OP_ADD_INT 151 + #define BINARY_OP_ADD_UNICODE 152 +-#define BINARY_OP_MULTIPLY_FLOAT 153 +-#define BINARY_OP_MULTIPLY_INT 154 +-#define BINARY_OP_SUBTRACT_FLOAT 155 +-#define BINARY_OP_SUBTRACT_INT 156 +-#define BINARY_SUBSCR_DICT 157 +-#define BINARY_SUBSCR_GETITEM 158 +-#define BINARY_SUBSCR_LIST_INT 159 +-#define BINARY_SUBSCR_STR_INT 160 +-#define BINARY_SUBSCR_TUPLE_INT 161 +-#define CALL_ALLOC_AND_ENTER_INIT 162 +-#define CALL_BOUND_METHOD_EXACT_ARGS 163 +-#define CALL_BOUND_METHOD_GENERAL 164 +-#define CALL_BUILTIN_CLASS 165 +-#define CALL_BUILTIN_FAST 166 +-#define CALL_BUILTIN_FAST_WITH_KEYWORDS 167 +-#define CALL_BUILTIN_O 168 +-#define CALL_ISINSTANCE 169 +-#define CALL_KW_BOUND_METHOD 170 +-#define CALL_KW_NON_PY 171 +-#define CALL_KW_PY 172 +-#define CALL_LEN 173 +-#define CALL_LIST_APPEND 174 +-#define CALL_METHOD_DESCRIPTOR_FAST 175 +-#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 176 +-#define CALL_METHOD_DESCRIPTOR_NOARGS 177 +-#define CALL_METHOD_DESCRIPTOR_O 178 +-#define CALL_NON_PY_GENERAL 179 +-#define CALL_PY_EXACT_ARGS 180 +-#define CALL_PY_GENERAL 181 +-#define CALL_STR_1 182 +-#define CALL_TUPLE_1 183 +-#define CALL_TYPE_1 184 +-#define COMPARE_OP_FLOAT 185 +-#define COMPARE_OP_INT 186 +-#define COMPARE_OP_STR 187 +-#define CONTAINS_OP_DICT 188 +-#define CONTAINS_OP_SET 189 +-#define FOR_ITER_GEN 190 +-#define FOR_ITER_LIST 191 +-#define FOR_ITER_RANGE 192 +-#define FOR_ITER_TUPLE 193 +-#define LOAD_ATTR_CLASS 194 +-#define LOAD_ATTR_CLASS_WITH_METACLASS_CHECK 195 +-#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 196 +-#define LOAD_ATTR_INSTANCE_VALUE 197 +-#define LOAD_ATTR_METHOD_LAZY_DICT 198 +-#define LOAD_ATTR_METHOD_NO_DICT 199 +-#define LOAD_ATTR_METHOD_WITH_VALUES 200 +-#define LOAD_ATTR_MODULE 201 +-#define LOAD_ATTR_NONDESCRIPTOR_NO_DICT 202 +-#define LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 203 +-#define LOAD_ATTR_PROPERTY 204 +-#define LOAD_ATTR_SLOT 205 +-#define LOAD_ATTR_WITH_HINT 206 +-#define LOAD_CONST_IMMORTAL 207 +-#define LOAD_GLOBAL_BUILTIN 208 +-#define LOAD_GLOBAL_MODULE 209 +-#define LOAD_SUPER_ATTR_ATTR 210 +-#define LOAD_SUPER_ATTR_METHOD 211 +-#define RESUME_CHECK 212 +-#define SEND_GEN 213 +-#define STORE_ATTR_INSTANCE_VALUE 214 +-#define STORE_ATTR_SLOT 215 +-#define STORE_ATTR_WITH_HINT 216 +-#define STORE_SUBSCR_DICT 217 +-#define STORE_SUBSCR_LIST_INT 218 +-#define TO_BOOL_ALWAYS_TRUE 219 +-#define TO_BOOL_BOOL 220 +-#define TO_BOOL_INT 221 +-#define TO_BOOL_LIST 222 +-#define TO_BOOL_NONE 223 +-#define TO_BOOL_STR 224 +-#define UNPACK_SEQUENCE_LIST 225 +-#define UNPACK_SEQUENCE_TUPLE 226 +-#define UNPACK_SEQUENCE_TWO_TUPLE 227 +-#define INSTRUMENTED_END_FOR 237 +-#define INSTRUMENTED_END_SEND 238 +-#define INSTRUMENTED_LOAD_SUPER_ATTR 239 +-#define INSTRUMENTED_FOR_ITER 240 +-#define INSTRUMENTED_CALL_KW 241 +-#define INSTRUMENTED_CALL_FUNCTION_EX 242 +-#define INSTRUMENTED_INSTRUCTION 243 +-#define INSTRUMENTED_JUMP_FORWARD 244 +-#define INSTRUMENTED_POP_JUMP_IF_TRUE 245 +-#define INSTRUMENTED_POP_JUMP_IF_FALSE 246 +-#define INSTRUMENTED_POP_JUMP_IF_NONE 247 +-#define INSTRUMENTED_POP_JUMP_IF_NOT_NONE 248 +-#define INSTRUMENTED_RESUME 249 +-#define INSTRUMENTED_RETURN_VALUE 250 +-#define INSTRUMENTED_YIELD_VALUE 251 +-#define INSTRUMENTED_CALL 252 ++#define BINARY_OP_EXTEND 153 ++#define BINARY_OP_MULTIPLY_FLOAT 154 ++#define BINARY_OP_MULTIPLY_INT 155 ++#define BINARY_OP_SUBSCR_DICT 156 ++#define BINARY_OP_SUBSCR_GETITEM 157 ++#define BINARY_OP_SUBSCR_LIST_INT 158 ++#define BINARY_OP_SUBSCR_STR_INT 159 ++#define BINARY_OP_SUBSCR_TUPLE_INT 160 ++#define BINARY_OP_SUBTRACT_FLOAT 161 ++#define BINARY_OP_SUBTRACT_INT 162 ++#define CALL_ALLOC_AND_ENTER_INIT 163 ++#define CALL_BOUND_METHOD_EXACT_ARGS 164 ++#define CALL_BOUND_METHOD_GENERAL 165 ++#define CALL_BUILTIN_CLASS 166 ++#define CALL_BUILTIN_FAST 167 ++#define CALL_BUILTIN_FAST_WITH_KEYWORDS 168 ++#define CALL_BUILTIN_O 169 ++#define CALL_ISINSTANCE 170 ++#define CALL_KW_BOUND_METHOD 171 ++#define CALL_KW_NON_PY 172 ++#define CALL_KW_PY 173 ++#define CALL_LEN 174 ++#define CALL_LIST_APPEND 175 ++#define CALL_METHOD_DESCRIPTOR_FAST 176 ++#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 177 ++#define CALL_METHOD_DESCRIPTOR_NOARGS 178 ++#define CALL_METHOD_DESCRIPTOR_O 179 ++#define CALL_NON_PY_GENERAL 180 ++#define CALL_PY_EXACT_ARGS 181 ++#define CALL_PY_GENERAL 182 ++#define CALL_STR_1 183 ++#define CALL_TUPLE_1 184 ++#define CALL_TYPE_1 185 ++#define COMPARE_OP_FLOAT 186 ++#define COMPARE_OP_INT 187 ++#define COMPARE_OP_STR 188 ++#define CONTAINS_OP_DICT 189 ++#define CONTAINS_OP_SET 190 ++#define FOR_ITER_GEN 191 ++#define FOR_ITER_LIST 192 ++#define FOR_ITER_RANGE 193 ++#define FOR_ITER_TUPLE 194 ++#define JUMP_BACKWARD_JIT 195 ++#define JUMP_BACKWARD_NO_JIT 196 ++#define LOAD_ATTR_CLASS 197 ++#define LOAD_ATTR_CLASS_WITH_METACLASS_CHECK 198 ++#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 199 ++#define LOAD_ATTR_INSTANCE_VALUE 200 ++#define LOAD_ATTR_METHOD_LAZY_DICT 201 ++#define LOAD_ATTR_METHOD_NO_DICT 202 ++#define LOAD_ATTR_METHOD_WITH_VALUES 203 ++#define LOAD_ATTR_MODULE 204 ++#define LOAD_ATTR_NONDESCRIPTOR_NO_DICT 205 ++#define LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 206 ++#define LOAD_ATTR_PROPERTY 207 ++#define LOAD_ATTR_SLOT 208 ++#define LOAD_ATTR_WITH_HINT 209 ++#define LOAD_CONST_IMMORTAL 210 ++#define LOAD_CONST_MORTAL 211 ++#define LOAD_GLOBAL_BUILTIN 212 ++#define LOAD_GLOBAL_MODULE 213 ++#define LOAD_SUPER_ATTR_ATTR 214 ++#define LOAD_SUPER_ATTR_METHOD 215 ++#define RESUME_CHECK 216 ++#define SEND_GEN 217 ++#define STORE_ATTR_INSTANCE_VALUE 218 ++#define STORE_ATTR_SLOT 219 ++#define STORE_ATTR_WITH_HINT 220 ++#define STORE_SUBSCR_DICT 221 ++#define STORE_SUBSCR_LIST_INT 222 ++#define TO_BOOL_ALWAYS_TRUE 223 ++#define TO_BOOL_BOOL 224 ++#define TO_BOOL_INT 225 ++#define TO_BOOL_LIST 226 ++#define TO_BOOL_NONE 227 ++#define TO_BOOL_STR 228 ++#define UNPACK_SEQUENCE_LIST 229 ++#define UNPACK_SEQUENCE_TUPLE 230 ++#define UNPACK_SEQUENCE_TWO_TUPLE 231 ++#define INSTRUMENTED_END_FOR 235 ++#define INSTRUMENTED_POP_ITER 236 ++#define INSTRUMENTED_END_SEND 237 ++#define INSTRUMENTED_FOR_ITER 238 ++#define INSTRUMENTED_INSTRUCTION 239 ++#define INSTRUMENTED_JUMP_FORWARD 240 ++#define INSTRUMENTED_NOT_TAKEN 241 ++#define INSTRUMENTED_POP_JUMP_IF_TRUE 242 ++#define INSTRUMENTED_POP_JUMP_IF_FALSE 243 ++#define INSTRUMENTED_POP_JUMP_IF_NONE 244 ++#define INSTRUMENTED_POP_JUMP_IF_NOT_NONE 245 ++#define INSTRUMENTED_RESUME 246 ++#define INSTRUMENTED_RETURN_VALUE 247 ++#define INSTRUMENTED_YIELD_VALUE 248 ++#define INSTRUMENTED_LOAD_SUPER_ATTR 249 ++#define INSTRUMENTED_CALL 250 ++#define INSTRUMENTED_CALL_KW 251 ++#define INSTRUMENTED_CALL_FUNCTION_EX 252 + #define INSTRUMENTED_JUMP_BACKWARD 253 + #define INSTRUMENTED_LINE 254 + #define ENTER_EXECUTOR 255 +@@ -235,9 +242,9 @@ + #define SETUP_WITH 264 + #define STORE_FAST_MAYBE_NULL 265 + +-#define HAVE_ARGUMENT 41 ++#define HAVE_ARGUMENT 43 + #define MIN_SPECIALIZED_OPCODE 150 +-#define MIN_INSTRUMENTED_OPCODE 237 ++#define MIN_INSTRUMENTED_OPCODE 235 + + #ifdef __cplusplus + } +diff --git a/Include/patchlevel.h b/Include/patchlevel.h +index 1e9df2d9ebd..74b630a762f 100644 +--- a/Include/patchlevel.h ++++ b/Include/patchlevel.h +@@ -1,4 +1,5 @@ - --AC_CHECK_FUNCS([openpty], [], -- [AC_CHECK_LIB([util], [openpty], -- [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lutil"], -- [AC_CHECK_LIB([bsd], [openpty], -- [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lbsd"])])]) --AC_SEARCH_LIBS([login_tty], [util], -- [AC_DEFINE([HAVE_LOGIN_TTY], [1], [Define to 1 if you have the `login_tty' function.])] --) --AC_CHECK_FUNCS([forkpty], [], -- [AC_CHECK_LIB([util], [forkpty], -- [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lutil"], -- [AC_CHECK_LIB([bsd], [forkpty], -- [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lbsd"])])]) -+# tvOS/watchOS have functions for tty, but can't use them -+if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then -+ AC_CHECK_FUNCS([openpty], [], -+ [AC_CHECK_LIB([util], [openpty], -+ [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lutil"], -+ [AC_CHECK_LIB([bsd], [openpty], -+ [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lbsd"])])]) -+ AC_SEARCH_LIBS([login_tty], [util], -+ [AC_DEFINE([HAVE_LOGIN_TTY], [1], [Define to 1 if you have the `login_tty' function.])] -+ ) -+ AC_CHECK_FUNCS([forkpty], [], -+ [AC_CHECK_LIB([util], [forkpty], -+ [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lutil"], -+ [AC_CHECK_LIB([bsd], [forkpty], -+ [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lbsd"])])]) -+fi ++#ifndef _Py_PATCHLEVEL_H ++#define _Py_PATCHLEVEL_H + /* Python version identification scheme. - # check for long file support functions - AC_CHECK_FUNCS([fseek64 fseeko fstatvfs ftell64 ftello statvfs]) -@@ -5444,10 +5584,10 @@ - ]) - ]) + When the major or minor version changes, the VERSION variable in +@@ -20,16 +21,29 @@ + #define PY_MINOR_VERSION 14 + #define PY_MICRO_VERSION 0 + #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_ALPHA +-#define PY_RELEASE_SERIAL 3 ++#define PY_RELEASE_SERIAL 5 --# On Android and iOS, clock_settime can be linked (so it is found by -+# On Android, iOS, tvOS and watchOS, clock_settime can be linked (so it is found by - # configure), but when used in an unprivileged process, it crashes rather than - # returning an error. Force the symbol off. --if test "$ac_sys_system" != "Linux-android" && test "$ac_sys_system" != "iOS" -+if test "$ac_sys_system" != "Linux-android" -a "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" - then - AC_CHECK_FUNCS([clock_settime], [], [ - AC_CHECK_LIB([rt], [clock_settime], [ -@@ -6198,8 +6338,8 @@ - LIBPYTHON="\$(BLDLIBRARY)" - fi + /* Version as a string */ +-#define PY_VERSION "3.14.0a3" ++#define PY_VERSION "3.14.0a5" + /*--end constants--*/ --# On iOS the shared libraries must be linked with the Python framework --if test "$ac_sys_system" = "iOS"; then -+# On iOS/tvOS/watchOS the shared libraries must be linked with the Python framework -+if test "$ac_sys_system" = "iOS" -o $ac_sys_system = "tvOS" -o $ac_sys_system = "watchOS"; then - MODULE_DEPS_SHARED="$MODULE_DEPS_SHARED \$(PYTHONFRAMEWORKDIR)/\$(PYTHONFRAMEWORK)" - fi ++ ++#define _Py_PACK_FULL_VERSION(X, Y, Z, LEVEL, SERIAL) ( \ ++ (((X) & 0xff) << 24) | \ ++ (((Y) & 0xff) << 16) | \ ++ (((Z) & 0xff) << 8) | \ ++ (((LEVEL) & 0xf) << 4) | \ ++ (((SERIAL) & 0xf) << 0)) ++ + /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. + Use this for numeric comparisons, e.g. #if PY_VERSION_HEX >= ... */ +-#define PY_VERSION_HEX ((PY_MAJOR_VERSION << 24) | \ +- (PY_MINOR_VERSION << 16) | \ +- (PY_MICRO_VERSION << 8) | \ +- (PY_RELEASE_LEVEL << 4) | \ +- (PY_RELEASE_SERIAL << 0)) ++#define PY_VERSION_HEX _Py_PACK_FULL_VERSION( \ ++ PY_MAJOR_VERSION, \ ++ PY_MINOR_VERSION, \ ++ PY_MICRO_VERSION, \ ++ PY_RELEASE_LEVEL, \ ++ PY_RELEASE_SERIAL) ++ ++// Public Py_PACK_VERSION is declared in pymacro.h; it needs . ++ ++#endif //_Py_PATCHLEVEL_H +diff --git a/Include/pymacro.h b/Include/pymacro.h +index e0378f9d27a..a82f347866e 100644 +--- a/Include/pymacro.h ++++ b/Include/pymacro.h +@@ -190,4 +190,13 @@ + // "comparison of unsigned expression in '< 0' is always false". + #define _Py_IS_TYPE_SIGNED(type) ((type)(-1) <= 0) -@@ -6863,7 +7003,7 @@ - dnl NOTE: Inform user how to proceed with files when cross compiling. - dnl Some cross-compile builds are predictable; they won't ever - dnl have /dev/ptmx or /dev/ptc, so we can set them explicitly. --if test "$ac_sys_system" = "Linux-android" || test "$ac_sys_system" = "iOS"; then -+if test "$ac_sys_system" = "Linux-android" -o "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "watchOS" ; then - ac_cv_file__dev_ptmx=no - ac_cv_file__dev_ptc=no - else -@@ -7119,7 +7259,7 @@ ++#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030E0000 // 3.14 ++// Version helpers. These are primarily macros, but have exported equivalents. ++PyAPI_FUNC(uint32_t) Py_PACK_FULL_VERSION(int x, int y, int z, int level, int serial); ++PyAPI_FUNC(uint32_t) Py_PACK_VERSION(int x, int y); ++#define Py_PACK_FULL_VERSION _Py_PACK_FULL_VERSION ++#define Py_PACK_VERSION(X, Y) Py_PACK_FULL_VERSION(X, Y, 0, 0, 0) ++#endif // Py_LIMITED_API < 3.14 ++ ++ + #endif /* Py_PYMACRO_H */ +diff --git a/Include/pyport.h b/Include/pyport.h +index 2b6bd4c2111..aabd094df54 100644 +--- a/Include/pyport.h ++++ b/Include/pyport.h +@@ -625,8 +625,13 @@ + // case 2: code; break; + // } + // +-// __attribute__((fallthrough)) was introduced in GCC 7. +-#if _Py__has_attribute(fallthrough) ++// __attribute__((fallthrough)) was introduced in GCC 7 and Clang 10 / ++// Apple Clang 12.0. Earlier Clang versions support only the C++11 ++// style fallthrough attribute, not the GCC extension syntax used here, ++// and __has_attribute(fallthrough) evaluates to 1. ++#if _Py__has_attribute(fallthrough) && (!defined(__clang__) || \ ++ (!defined(__apple_build_version__) && __clang_major__ >= 10) || \ ++ (defined(__apple_build_version__) && __clang_major__ >= 12)) + # define _Py_FALLTHROUGH __attribute__((fallthrough)) + #else + # define _Py_FALLTHROUGH do { } while (0) +diff --git a/InternalDocs/README.md b/InternalDocs/README.md +index 794b4f3c6aa..4502902307c 100644 +--- a/InternalDocs/README.md ++++ b/InternalDocs/README.md +@@ -25,7 +25,7 @@ + + - [Code Objects](code_objects.md) + +-- [Generators (coming soon)](generators.md) ++- [Generators](generators.md) + + - [Frames](frames.md) + +diff --git a/InternalDocs/compiler.md b/InternalDocs/compiler.md +index c257bfd9faf..8ca19a42b91 100644 +--- a/InternalDocs/compiler.md ++++ b/InternalDocs/compiler.md +@@ -401,7 +401,7 @@ + add the `LOAD_CONST` opcode with the proper argument based on the + position of the specified PyObject in the consts table. + * `ADDOP_LOAD_CONST_NEW(struct compiler *, location, PyObject *)`: +- just like `ADDOP_LOAD_CONST_NEW`, but steals a reference to PyObject ++ just like `ADDOP_LOAD_CONST`, but steals a reference to PyObject + * `ADDOP_JUMP(struct compiler *, location, int, basicblock *)`: + create a jump to a basic block + +diff --git a/InternalDocs/frames.md b/InternalDocs/frames.md +index 2598873ca98..1a909009eea 100644 +--- a/InternalDocs/frames.md ++++ b/InternalDocs/frames.md +@@ -33,7 +33,7 @@ + * Stack + + This seems to provide the best performance without excessive complexity. +-The specials have a fixed size, so the offset of the locals is know. The ++The specials have a fixed size, so the offset of the locals is known. The + interpreter needs to hold two pointers, a frame pointer and a stack pointer. + + #### Alternative layout +@@ -52,7 +52,7 @@ + ### Generators and Coroutines + + Generators and coroutines contain a `_PyInterpreterFrame` +-The specials sections contains the following pointers: ++The specials section contains the following pointers: + + * Globals dict + * Builtins dict +@@ -69,7 +69,7 @@ + + When creating a backtrace or when calling `sys._getframe()` the frame becomes + visible to Python code. When this happens a new `PyFrameObject` is created +-and a strong reference to it placed in the `frame_obj` field of the specials ++and a strong reference to it is placed in the `frame_obj` field of the specials + section. The `frame_obj` field is initially `NULL`. + + The `PyFrameObject` may outlive a stack-allocated `_PyInterpreterFrame`. +@@ -128,7 +128,7 @@ + relative to `instr_ptr`. It is only meaningful to the callee, so it needs to + be set in any instruction that implements a call (to a Python function), + including CALL, SEND and BINARY_SUBSCR_GETITEM, among others. If there is no +-callee, then return_offset is meaningless. It is necessary to have a separate ++callee, then return_offset is meaningless. It is necessary to have a separate + field for the return offset because (1) if we apply this offset to `instr_ptr` + while executing the `RETURN`, this is too early and would lose us information + about the previous instruction which we could need for introspecting and +diff --git a/InternalDocs/generators.md b/InternalDocs/generators.md +index afa8b8f4bb8..87fbb912368 100644 +--- a/InternalDocs/generators.md ++++ b/InternalDocs/generators.md +@@ -1,8 +1,106 @@ ++ ++Generators and Coroutines ++========================= ++ + Generators +-========== ++---------- ++ ++Generators in CPython are implemented with the struct `PyGenObject`. ++They consist of a [`frame`](frames.md) and metadata about the generator's ++execution state. ++ ++A generator object resumes execution in its frame when its `send()` ++method is called. This is analogous to a function executing in its own ++frame when it is called, but a function returns to the calling frame only once, ++while a generator "returns" execution to the caller's frame every time ++it emits a new item with a ++[`yield` expression](https://docs.python.org/dev/reference/expressions.html#yield-expressions). ++This is implemented by the ++[`YIELD_VALUE`](https://docs.python.org/dev/library/dis.html#opcode-YIELD_VALUE) ++bytecode, which is similar to ++[`RETURN_VALUE`](https://docs.python.org/dev/library/dis.html#opcode-RETURN_VALUE) ++in the sense that it puts a value on the stack and returns execution to the ++calling frame, but it also needs to perform additional work to leave the generator ++frame in a state that allows it to be resumed. In particular, it updates the frame's ++instruction pointer and stores the interpreter's exception state on the generator ++object. When the generator is resumed, this exception state is copied back to the ++interpreter state. ++ ++The `frame` of a generator is embedded in the generator object struct as a ++[`_PyInterpreterFrame`](frames.md) (see `_PyGenObject_HEAD` in ++[`pycore_genobject.h`](../Include/internal/pycore_genobject.h)). ++This means that we can get the frame from the generator or the generator ++from the frame (see `_PyGen_GetGeneratorFromFrame` in the same file). ++Other fields of the generator struct include metadata (such as the name of ++the generator function) and runtime state information (such as whether its ++frame is executing, suspended, cleared, etc.). ++ ++Generator Object Creation and Destruction ++----------------------------------------- ++ ++The bytecode of a generator function begins with a ++[`RETURN_GENERATOR`](https://docs.python.org/dev/library/dis.html#opcode-RETURN_GENERATOR) ++instruction, which creates a generator object, including its embedded frame. ++The generator's frame is initialized as a copy of the frame in which ++`RETURN_GENERATOR` is executing, but its `owner` field is overwritten to indicate ++that it is owned by a generator. Finally, `RETURN_GENERATOR` pushes the new generator ++object to the stack and returns to the caller of the generator function (at ++which time its frame is destroyed). When the generator is next resumed by ++[`gen_send_ex2()`](../Objects/genobject.c), `_PyEval_EvalFrame()` is called ++to continue executing the generator function, in the frame that is embedded in ++the generator object. ++ ++When a generator object is destroyed in [`gen_dealloc`](../Objects/genobject.c), ++its embedded `_PyInterpreterFrame` field may need to be preserved, if it is exposed ++to Python as part of a [`PyFrameObject`](frames.md#frame-objects). This is detected ++in [`_PyFrame_ClearExceptCode`](../Python/frame.c) by the fact that the interpreter ++frame's `frame_obj` field is set, and the frame object it points to has refcount ++greater than 1. If so, the `take_ownership()` function is called to create a new ++copy of the interpreter frame and transfer ownership of it from the generator to ++the frame object. ++ ++Iteration ++--------- ++ ++The [`FOR_ITER`](https://docs.python.org/dev/library/dis.html#opcode-FOR_ITER) ++instruction calls `__next__` on the iterator which is on the top of the stack, ++and pushes the result to the stack. It has [`specializations`](adaptive.md) ++for a few common iterator types, including `FOR_ITER_GEN`, for iterating over ++a generator. `FOR_ITER_GEN` bypasses the call to `__next__`, and instead ++directly pushes the generator stack and resumes its execution from the ++instruction that follows the last yield. ++ ++Chained Generators ++------------------ ++ ++A `yield from` expression creates a generator that efficiently yields the ++sequence created by another generator. This is implemented with the ++[`SEND` instruction](https://docs.python.org/dev/library/dis.html#opcode-SEND), ++which pushes the value of its arg to the stack of the generator's frame, sets ++the exception state on this frame, and resumes execution of the chained generator. ++On return from `SEND`, the value at the top of the stack is sent back up ++the generator chain with a `YIELD_VALUE`. This sequence of `SEND` followed by ++`YIELD_VALUE` is repeated in a loop, until a `StopIteration` exception is ++raised to indicate that the generator has no more values to emit. ++ ++The [`CLEANUP_THROW`](https://docs.python.org/dev/library/dis.html#opcode-CLEANUP_THROW) ++instruction is used to handle exceptions raised from the send-yield loop. ++Exceptions of type `StopIteration` is handled, their `value` field hold the ++value to be returned by the generator's `close()` function. Any other ++exception is re-raised by `CLEANUP_THROW`. ++ ++Coroutines ++---------- + +-Coming soon. ++Coroutines are generators that use the value returned from a `yield` expression, ++i.e., the argument that was passed to the `.send()` call that resumed it after ++it yielded. This makes it possible for data to flow in both directions: from ++the generator to the caller via the argument of the `yield` expression, and ++from the caller to the generator via the send argument to the `send()` call. ++A `yield from` expression passes the `send` argument to the chained generator, ++so this data flow works along the chain (see `gen_send_ex2()` in ++[`genobject.c`](../Objects/genobject.c)). + +- ++Recall that a generator's `__next__` function simply calls `self.send(None)`, ++so all this works the same in generators and coroutines, but only coroutines ++use the value of the argument to `send`. +diff --git a/InternalDocs/interpreter.md b/InternalDocs/interpreter.md +index fa4a54fdc54..52702792c6c 100644 +--- a/InternalDocs/interpreter.md ++++ b/InternalDocs/interpreter.md +@@ -20,7 +20,7 @@ + [`PyEval_EvalCode()`](https://docs.python.org/3.14/c-api/veryhigh.html#c.PyEval_EvalCode) + function is called to execute a `CodeObject`, it constructs a [`Frame`](frames.md) and calls + [`_PyEval_EvalFrame()`](https://docs.python.org/3.14/c-api/veryhigh.html#c.PyEval_EvalCode) +-to execute the code object in this frame. The frame hold the dynamic state of the ++to execute the code object in this frame. The frame holds the dynamic state of the + `CodeObject`'s execution, including the instruction pointer, the globals and builtins. + It also has a reference to the `CodeObject` itself. + +@@ -153,9 +153,9 @@ + Most instructions read or write some data in the form of object references (`PyObject *`). + The CPython bytecode interpreter is a stack machine, meaning that its instructions operate + by pushing data onto and popping it off the stack. +-The stack is forms part of the frame for the code object. Its maximum depth is calculated ++The stack forms part of the frame for the code object. Its maximum depth is calculated + by the compiler and stored in the `co_stacksize` field of the code object, so that the +-stack can be pre-allocated is a contiguous array of `PyObject*` pointers, when the frame ++stack can be pre-allocated as a contiguous array of `PyObject*` pointers, when the frame + is created. + + The stack effects of each instruction are also exposed through the +@@ -462,7 +462,7 @@ + 2. Perform the operation quickly. + + This requires that the set of values is chosen such that membership can be +-tested quickly and that membership is sufficient to allow the operation to ++tested quickly and that membership is sufficient to allow the operation to be + performed quickly. + + For example, `LOAD_GLOBAL_MODULE` is specialized for `globals()` +diff --git a/InternalDocs/jit.md b/InternalDocs/jit.md +index 1e9f385d5f8..2c204f39792 100644 +--- a/InternalDocs/jit.md ++++ b/InternalDocs/jit.md +@@ -38,12 +38,8 @@ + + ## The micro-op optimizer + +-The optimizer that `_PyOptimizer_Optimize()` runs is configurable via the +-`_Py_SetTier2Optimizer()` function (this is used in test via +-`_testinternalcapi.set_optimizer()`.) +- + The micro-op (abbreviated `uop` to approximate `μop`) optimizer is defined in +-[`Python/optimizer.c`](../Python/optimizer.c) as the type `_PyUOpOptimizer_Type`. ++[`Python/optimizer.c`](../Python/optimizer.c) as `_PyOptimizer_Optimize`. + It translates an instruction trace into a sequence of micro-ops by replacing + each bytecode by an equivalent sequence of micro-ops (see + `_PyOpcode_macro_expansion` in +diff --git a/InternalDocs/parser.md b/InternalDocs/parser.md +index 445b866fc0c..be47efe2435 100644 +--- a/InternalDocs/parser.md ++++ b/InternalDocs/parser.md +@@ -56,7 +56,7 @@ + + Note that "failure" results do not imply that the program is incorrect, nor do + they necessarily mean that the parsing has failed. Since the choice operator is +-ordered, a failure very often merely indicates "try the following option". A ++ordered, a failure very often merely indicates "try the following option". A + direct implementation of a PEG parser as a recursive descent parser will present + exponential time performance in the worst case, because PEG parsers have + infinite lookahead (this means that they can consider an arbitrary number of +@@ -253,7 +253,7 @@ + If the action is omitted, a default action is generated: + + - If there is a single name in the rule, it gets returned. +-- If there multiple names in the rule, a collection with all parsed ++- If there are multiple names in the rule, a collection with all parsed + expressions gets returned (the type of the collection will be different + in C and Python). + +@@ -447,7 +447,7 @@ + $ make regen-pegen + ``` + +-using the `Makefile` in the main directory. If you are on Windows you can ++using the `Makefile` in the main directory. If you are on Windows you can + use the Visual Studio project files to regenerate the parser or to execute: + + ```dos +@@ -539,7 +539,7 @@ + The C parser used by Python is highly optimized and memoization can be expensive + both in memory and time. Although the memory cost is obvious (the parser needs + memory for storing previous results in the cache) the execution time cost comes +-for continuously checking if the given rule has a cache hit or not. In many ++from continuously checking if the given rule has a cache hit or not. In many + situations, just parsing it again can be faster. Pegen **disables memoization + by default** except for rules with the special marker `memo` after the rule + name (and type, if present): +@@ -605,7 +605,7 @@ + SyntaxError: invalid syntax + ``` + +-While soft keywords don't have this limitation if used in a context other the ++While soft keywords don't have this limitation if used in a context other than + one where they are defined as keywords: + + ```pycon +diff --git a/Lib/_colorize.py b/Lib/_colorize.py +index 709081e25ec..41e818f2a74 100644 +--- a/Lib/_colorize.py ++++ b/Lib/_colorize.py +@@ -6,9 +6,11 @@ + + + class ANSIColors: ++ BACKGROUND_YELLOW = "\x1b[43m" + BOLD_GREEN = "\x1b[1;32m" + BOLD_MAGENTA = "\x1b[1;35m" + BOLD_RED = "\x1b[1;31m" ++ BLACK = "\x1b[30m" + GREEN = "\x1b[32m" + GREY = "\x1b[90m" + MAGENTA = "\x1b[35m" +@@ -24,30 +26,32 @@ + setattr(NoColors, attr, "") + + +-def get_colors(colorize: bool = False) -> ANSIColors: +- if colorize or can_colorize(): ++def get_colors(colorize: bool = False, *, file=None) -> ANSIColors: ++ if colorize or can_colorize(file=file): + return ANSIColors() + else: + return NoColors + + +-def can_colorize() -> bool: ++def can_colorize(*, file=None) -> bool: ++ if file is None: ++ file = sys.stdout ++ + if not sys.flags.ignore_environment: + if os.environ.get("PYTHON_COLORS") == "0": + return False + if os.environ.get("PYTHON_COLORS") == "1": + return True +- if "NO_COLOR" in os.environ: +- return False ++ if os.environ.get("NO_COLOR"): ++ return False + if not COLORIZE: + return False +- if not sys.flags.ignore_environment: +- if "FORCE_COLOR" in os.environ: +- return True +- if os.environ.get("TERM") == "dumb": +- return False ++ if os.environ.get("FORCE_COLOR"): ++ return True ++ if os.environ.get("TERM") == "dumb": ++ return False + +- if not hasattr(sys.stderr, "fileno"): ++ if not hasattr(file, "fileno"): + return False + + if sys.platform == "win32": +@@ -60,6 +64,6 @@ + return False + + try: +- return os.isatty(sys.stderr.fileno()) ++ return os.isatty(file.fileno()) + except io.UnsupportedOperation: +- return sys.stderr.isatty() ++ return file.isatty() +diff --git a/Lib/_markupbase.py b/Lib/_markupbase.py +index 3ad7e279960..614f0cd16dd 100644 +--- a/Lib/_markupbase.py ++++ b/Lib/_markupbase.py +@@ -13,7 +13,7 @@ + _markedsectionclose = re.compile(r']\s*]\s*>') + + # An analysis of the MS-Word extensions is available at +-# http://www.planetpublish.com/xmlarena/xap/Thursday/WordtoXML.pdf ++# http://web.archive.org/web/20060321153828/http://www.planetpublish.com/xmlarena/xap/Thursday/WordtoXML.pdf + + _msmarkedsectionclose = re.compile(r']\s*>') + +diff --git a/Lib/_opcode_metadata.py b/Lib/_opcode_metadata.py +index cda3c340c32..0e18792402d 100644 +--- a/Lib/_opcode_metadata.py ++++ b/Lib/_opcode_metadata.py +@@ -7,6 +7,7 @@ + "RESUME_CHECK", + ], + "LOAD_CONST": [ ++ "LOAD_CONST_MORTAL", + "LOAD_CONST_IMMORTAL", + ], + "TO_BOOL": [ +@@ -25,15 +26,14 @@ + "BINARY_OP_ADD_FLOAT", + "BINARY_OP_SUBTRACT_FLOAT", + "BINARY_OP_ADD_UNICODE", ++ "BINARY_OP_SUBSCR_LIST_INT", ++ "BINARY_OP_SUBSCR_TUPLE_INT", ++ "BINARY_OP_SUBSCR_STR_INT", ++ "BINARY_OP_SUBSCR_DICT", ++ "BINARY_OP_SUBSCR_GETITEM", ++ "BINARY_OP_EXTEND", + "BINARY_OP_INPLACE_ADD_UNICODE", + ], +- "BINARY_SUBSCR": [ +- "BINARY_SUBSCR_DICT", +- "BINARY_SUBSCR_GETITEM", +- "BINARY_SUBSCR_LIST_INT", +- "BINARY_SUBSCR_STR_INT", +- "BINARY_SUBSCR_TUPLE_INT", +- ], + "STORE_SUBSCR": [ + "STORE_SUBSCR_DICT", + "STORE_SUBSCR_LIST_INT", +@@ -83,6 +83,10 @@ + "CONTAINS_OP_SET", + "CONTAINS_OP_DICT", + ], ++ "JUMP_BACKWARD": [ ++ "JUMP_BACKWARD_NO_JIT", ++ "JUMP_BACKWARD_JIT", ++ ], + "FOR_ITER": [ + "FOR_ITER_LIST", + "FOR_ITER_TUPLE", +@@ -122,82 +126,86 @@ + 'BINARY_OP_ADD_FLOAT': 150, + 'BINARY_OP_ADD_INT': 151, + 'BINARY_OP_ADD_UNICODE': 152, ++ 'BINARY_OP_EXTEND': 153, + 'BINARY_OP_INPLACE_ADD_UNICODE': 3, +- 'BINARY_OP_MULTIPLY_FLOAT': 153, +- 'BINARY_OP_MULTIPLY_INT': 154, +- 'BINARY_OP_SUBTRACT_FLOAT': 155, +- 'BINARY_OP_SUBTRACT_INT': 156, +- 'BINARY_SUBSCR_DICT': 157, +- 'BINARY_SUBSCR_GETITEM': 158, +- 'BINARY_SUBSCR_LIST_INT': 159, +- 'BINARY_SUBSCR_STR_INT': 160, +- 'BINARY_SUBSCR_TUPLE_INT': 161, +- 'CALL_ALLOC_AND_ENTER_INIT': 162, +- 'CALL_BOUND_METHOD_EXACT_ARGS': 163, +- 'CALL_BOUND_METHOD_GENERAL': 164, +- 'CALL_BUILTIN_CLASS': 165, +- 'CALL_BUILTIN_FAST': 166, +- 'CALL_BUILTIN_FAST_WITH_KEYWORDS': 167, +- 'CALL_BUILTIN_O': 168, +- 'CALL_ISINSTANCE': 169, +- 'CALL_KW_BOUND_METHOD': 170, +- 'CALL_KW_NON_PY': 171, +- 'CALL_KW_PY': 172, +- 'CALL_LEN': 173, +- 'CALL_LIST_APPEND': 174, +- 'CALL_METHOD_DESCRIPTOR_FAST': 175, +- 'CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS': 176, +- 'CALL_METHOD_DESCRIPTOR_NOARGS': 177, +- 'CALL_METHOD_DESCRIPTOR_O': 178, +- 'CALL_NON_PY_GENERAL': 179, +- 'CALL_PY_EXACT_ARGS': 180, +- 'CALL_PY_GENERAL': 181, +- 'CALL_STR_1': 182, +- 'CALL_TUPLE_1': 183, +- 'CALL_TYPE_1': 184, +- 'COMPARE_OP_FLOAT': 185, +- 'COMPARE_OP_INT': 186, +- 'COMPARE_OP_STR': 187, +- 'CONTAINS_OP_DICT': 188, +- 'CONTAINS_OP_SET': 189, +- 'FOR_ITER_GEN': 190, +- 'FOR_ITER_LIST': 191, +- 'FOR_ITER_RANGE': 192, +- 'FOR_ITER_TUPLE': 193, +- 'LOAD_ATTR_CLASS': 194, +- 'LOAD_ATTR_CLASS_WITH_METACLASS_CHECK': 195, +- 'LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN': 196, +- 'LOAD_ATTR_INSTANCE_VALUE': 197, +- 'LOAD_ATTR_METHOD_LAZY_DICT': 198, +- 'LOAD_ATTR_METHOD_NO_DICT': 199, +- 'LOAD_ATTR_METHOD_WITH_VALUES': 200, +- 'LOAD_ATTR_MODULE': 201, +- 'LOAD_ATTR_NONDESCRIPTOR_NO_DICT': 202, +- 'LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES': 203, +- 'LOAD_ATTR_PROPERTY': 204, +- 'LOAD_ATTR_SLOT': 205, +- 'LOAD_ATTR_WITH_HINT': 206, +- 'LOAD_CONST_IMMORTAL': 207, +- 'LOAD_GLOBAL_BUILTIN': 208, +- 'LOAD_GLOBAL_MODULE': 209, +- 'LOAD_SUPER_ATTR_ATTR': 210, +- 'LOAD_SUPER_ATTR_METHOD': 211, +- 'RESUME_CHECK': 212, +- 'SEND_GEN': 213, +- 'STORE_ATTR_INSTANCE_VALUE': 214, +- 'STORE_ATTR_SLOT': 215, +- 'STORE_ATTR_WITH_HINT': 216, +- 'STORE_SUBSCR_DICT': 217, +- 'STORE_SUBSCR_LIST_INT': 218, +- 'TO_BOOL_ALWAYS_TRUE': 219, +- 'TO_BOOL_BOOL': 220, +- 'TO_BOOL_INT': 221, +- 'TO_BOOL_LIST': 222, +- 'TO_BOOL_NONE': 223, +- 'TO_BOOL_STR': 224, +- 'UNPACK_SEQUENCE_LIST': 225, +- 'UNPACK_SEQUENCE_TUPLE': 226, +- 'UNPACK_SEQUENCE_TWO_TUPLE': 227, ++ 'BINARY_OP_MULTIPLY_FLOAT': 154, ++ 'BINARY_OP_MULTIPLY_INT': 155, ++ 'BINARY_OP_SUBSCR_DICT': 156, ++ 'BINARY_OP_SUBSCR_GETITEM': 157, ++ 'BINARY_OP_SUBSCR_LIST_INT': 158, ++ 'BINARY_OP_SUBSCR_STR_INT': 159, ++ 'BINARY_OP_SUBSCR_TUPLE_INT': 160, ++ 'BINARY_OP_SUBTRACT_FLOAT': 161, ++ 'BINARY_OP_SUBTRACT_INT': 162, ++ 'CALL_ALLOC_AND_ENTER_INIT': 163, ++ 'CALL_BOUND_METHOD_EXACT_ARGS': 164, ++ 'CALL_BOUND_METHOD_GENERAL': 165, ++ 'CALL_BUILTIN_CLASS': 166, ++ 'CALL_BUILTIN_FAST': 167, ++ 'CALL_BUILTIN_FAST_WITH_KEYWORDS': 168, ++ 'CALL_BUILTIN_O': 169, ++ 'CALL_ISINSTANCE': 170, ++ 'CALL_KW_BOUND_METHOD': 171, ++ 'CALL_KW_NON_PY': 172, ++ 'CALL_KW_PY': 173, ++ 'CALL_LEN': 174, ++ 'CALL_LIST_APPEND': 175, ++ 'CALL_METHOD_DESCRIPTOR_FAST': 176, ++ 'CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS': 177, ++ 'CALL_METHOD_DESCRIPTOR_NOARGS': 178, ++ 'CALL_METHOD_DESCRIPTOR_O': 179, ++ 'CALL_NON_PY_GENERAL': 180, ++ 'CALL_PY_EXACT_ARGS': 181, ++ 'CALL_PY_GENERAL': 182, ++ 'CALL_STR_1': 183, ++ 'CALL_TUPLE_1': 184, ++ 'CALL_TYPE_1': 185, ++ 'COMPARE_OP_FLOAT': 186, ++ 'COMPARE_OP_INT': 187, ++ 'COMPARE_OP_STR': 188, ++ 'CONTAINS_OP_DICT': 189, ++ 'CONTAINS_OP_SET': 190, ++ 'FOR_ITER_GEN': 191, ++ 'FOR_ITER_LIST': 192, ++ 'FOR_ITER_RANGE': 193, ++ 'FOR_ITER_TUPLE': 194, ++ 'JUMP_BACKWARD_JIT': 195, ++ 'JUMP_BACKWARD_NO_JIT': 196, ++ 'LOAD_ATTR_CLASS': 197, ++ 'LOAD_ATTR_CLASS_WITH_METACLASS_CHECK': 198, ++ 'LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN': 199, ++ 'LOAD_ATTR_INSTANCE_VALUE': 200, ++ 'LOAD_ATTR_METHOD_LAZY_DICT': 201, ++ 'LOAD_ATTR_METHOD_NO_DICT': 202, ++ 'LOAD_ATTR_METHOD_WITH_VALUES': 203, ++ 'LOAD_ATTR_MODULE': 204, ++ 'LOAD_ATTR_NONDESCRIPTOR_NO_DICT': 205, ++ 'LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES': 206, ++ 'LOAD_ATTR_PROPERTY': 207, ++ 'LOAD_ATTR_SLOT': 208, ++ 'LOAD_ATTR_WITH_HINT': 209, ++ 'LOAD_CONST_IMMORTAL': 210, ++ 'LOAD_CONST_MORTAL': 211, ++ 'LOAD_GLOBAL_BUILTIN': 212, ++ 'LOAD_GLOBAL_MODULE': 213, ++ 'LOAD_SUPER_ATTR_ATTR': 214, ++ 'LOAD_SUPER_ATTR_METHOD': 215, ++ 'RESUME_CHECK': 216, ++ 'SEND_GEN': 217, ++ 'STORE_ATTR_INSTANCE_VALUE': 218, ++ 'STORE_ATTR_SLOT': 219, ++ 'STORE_ATTR_WITH_HINT': 220, ++ 'STORE_SUBSCR_DICT': 221, ++ 'STORE_SUBSCR_LIST_INT': 222, ++ 'TO_BOOL_ALWAYS_TRUE': 223, ++ 'TO_BOOL_BOOL': 224, ++ 'TO_BOOL_INT': 225, ++ 'TO_BOOL_LIST': 226, ++ 'TO_BOOL_NONE': 227, ++ 'TO_BOOL_STR': 228, ++ 'UNPACK_SEQUENCE_LIST': 229, ++ 'UNPACK_SEQUENCE_TUPLE': 230, ++ 'UNPACK_SEQUENCE_TWO_TUPLE': 231, + } + + opmap = { +@@ -207,7 +215,7 @@ + 'INSTRUMENTED_LINE': 254, + 'ENTER_EXECUTOR': 255, + 'BINARY_SLICE': 1, +- 'BINARY_SUBSCR': 2, ++ 'CALL_FUNCTION_EX': 2, + 'CHECK_EG_MATCH': 4, + 'CHECK_EXC_MATCH': 5, + 'CLEANUP_THROW': 6, +@@ -231,110 +239,113 @@ + 'MATCH_MAPPING': 25, + 'MATCH_SEQUENCE': 26, + 'NOP': 27, +- 'POP_EXCEPT': 28, +- 'POP_TOP': 29, +- 'PUSH_EXC_INFO': 30, +- 'PUSH_NULL': 31, +- 'RETURN_GENERATOR': 32, +- 'RETURN_VALUE': 33, +- 'SETUP_ANNOTATIONS': 34, +- 'STORE_SLICE': 35, +- 'STORE_SUBSCR': 36, +- 'TO_BOOL': 37, +- 'UNARY_INVERT': 38, +- 'UNARY_NEGATIVE': 39, +- 'UNARY_NOT': 40, +- 'WITH_EXCEPT_START': 41, +- 'BINARY_OP': 42, +- 'BUILD_LIST': 43, +- 'BUILD_MAP': 44, +- 'BUILD_SET': 45, +- 'BUILD_SLICE': 46, +- 'BUILD_STRING': 47, +- 'BUILD_TUPLE': 48, +- 'CALL': 49, +- 'CALL_FUNCTION_EX': 50, +- 'CALL_INTRINSIC_1': 51, +- 'CALL_INTRINSIC_2': 52, +- 'CALL_KW': 53, +- 'COMPARE_OP': 54, +- 'CONTAINS_OP': 55, +- 'CONVERT_VALUE': 56, +- 'COPY': 57, +- 'COPY_FREE_VARS': 58, +- 'DELETE_ATTR': 59, +- 'DELETE_DEREF': 60, +- 'DELETE_FAST': 61, +- 'DELETE_GLOBAL': 62, +- 'DELETE_NAME': 63, +- 'DICT_MERGE': 64, +- 'DICT_UPDATE': 65, +- 'EXTENDED_ARG': 66, +- 'FOR_ITER': 67, +- 'GET_AWAITABLE': 68, +- 'IMPORT_FROM': 69, +- 'IMPORT_NAME': 70, +- 'IS_OP': 71, +- 'JUMP_BACKWARD': 72, +- 'JUMP_BACKWARD_NO_INTERRUPT': 73, +- 'JUMP_FORWARD': 74, +- 'LIST_APPEND': 75, +- 'LIST_EXTEND': 76, +- 'LOAD_ATTR': 77, +- 'LOAD_COMMON_CONSTANT': 78, +- 'LOAD_CONST': 79, +- 'LOAD_DEREF': 80, +- 'LOAD_FAST': 81, +- 'LOAD_FAST_AND_CLEAR': 82, +- 'LOAD_FAST_CHECK': 83, +- 'LOAD_FAST_LOAD_FAST': 84, +- 'LOAD_FROM_DICT_OR_DEREF': 85, +- 'LOAD_FROM_DICT_OR_GLOBALS': 86, +- 'LOAD_GLOBAL': 87, +- 'LOAD_NAME': 88, +- 'LOAD_SMALL_INT': 89, +- 'LOAD_SPECIAL': 90, +- 'LOAD_SUPER_ATTR': 91, +- 'MAKE_CELL': 92, +- 'MAP_ADD': 93, +- 'MATCH_CLASS': 94, +- 'POP_JUMP_IF_FALSE': 95, +- 'POP_JUMP_IF_NONE': 96, +- 'POP_JUMP_IF_NOT_NONE': 97, +- 'POP_JUMP_IF_TRUE': 98, +- 'RAISE_VARARGS': 99, +- 'RERAISE': 100, +- 'SEND': 101, +- 'SET_ADD': 102, +- 'SET_FUNCTION_ATTRIBUTE': 103, +- 'SET_UPDATE': 104, +- 'STORE_ATTR': 105, +- 'STORE_DEREF': 106, +- 'STORE_FAST': 107, +- 'STORE_FAST_LOAD_FAST': 108, +- 'STORE_FAST_STORE_FAST': 109, +- 'STORE_GLOBAL': 110, +- 'STORE_NAME': 111, +- 'SWAP': 112, +- 'UNPACK_EX': 113, +- 'UNPACK_SEQUENCE': 114, +- 'YIELD_VALUE': 115, +- 'INSTRUMENTED_END_FOR': 237, +- 'INSTRUMENTED_END_SEND': 238, +- 'INSTRUMENTED_LOAD_SUPER_ATTR': 239, +- 'INSTRUMENTED_FOR_ITER': 240, +- 'INSTRUMENTED_CALL_KW': 241, +- 'INSTRUMENTED_CALL_FUNCTION_EX': 242, +- 'INSTRUMENTED_INSTRUCTION': 243, +- 'INSTRUMENTED_JUMP_FORWARD': 244, +- 'INSTRUMENTED_POP_JUMP_IF_TRUE': 245, +- 'INSTRUMENTED_POP_JUMP_IF_FALSE': 246, +- 'INSTRUMENTED_POP_JUMP_IF_NONE': 247, +- 'INSTRUMENTED_POP_JUMP_IF_NOT_NONE': 248, +- 'INSTRUMENTED_RESUME': 249, +- 'INSTRUMENTED_RETURN_VALUE': 250, +- 'INSTRUMENTED_YIELD_VALUE': 251, +- 'INSTRUMENTED_CALL': 252, ++ 'NOT_TAKEN': 28, ++ 'POP_EXCEPT': 29, ++ 'POP_ITER': 30, ++ 'POP_TOP': 31, ++ 'PUSH_EXC_INFO': 32, ++ 'PUSH_NULL': 33, ++ 'RETURN_GENERATOR': 34, ++ 'RETURN_VALUE': 35, ++ 'SETUP_ANNOTATIONS': 36, ++ 'STORE_SLICE': 37, ++ 'STORE_SUBSCR': 38, ++ 'TO_BOOL': 39, ++ 'UNARY_INVERT': 40, ++ 'UNARY_NEGATIVE': 41, ++ 'UNARY_NOT': 42, ++ 'WITH_EXCEPT_START': 43, ++ 'BINARY_OP': 44, ++ 'BUILD_LIST': 45, ++ 'BUILD_MAP': 46, ++ 'BUILD_SET': 47, ++ 'BUILD_SLICE': 48, ++ 'BUILD_STRING': 49, ++ 'BUILD_TUPLE': 50, ++ 'CALL': 51, ++ 'CALL_INTRINSIC_1': 52, ++ 'CALL_INTRINSIC_2': 53, ++ 'CALL_KW': 54, ++ 'COMPARE_OP': 55, ++ 'CONTAINS_OP': 56, ++ 'CONVERT_VALUE': 57, ++ 'COPY': 58, ++ 'COPY_FREE_VARS': 59, ++ 'DELETE_ATTR': 60, ++ 'DELETE_DEREF': 61, ++ 'DELETE_FAST': 62, ++ 'DELETE_GLOBAL': 63, ++ 'DELETE_NAME': 64, ++ 'DICT_MERGE': 65, ++ 'DICT_UPDATE': 66, ++ 'EXTENDED_ARG': 67, ++ 'FOR_ITER': 68, ++ 'GET_AWAITABLE': 69, ++ 'IMPORT_FROM': 70, ++ 'IMPORT_NAME': 71, ++ 'IS_OP': 72, ++ 'JUMP_BACKWARD': 73, ++ 'JUMP_BACKWARD_NO_INTERRUPT': 74, ++ 'JUMP_FORWARD': 75, ++ 'LIST_APPEND': 76, ++ 'LIST_EXTEND': 77, ++ 'LOAD_ATTR': 78, ++ 'LOAD_COMMON_CONSTANT': 79, ++ 'LOAD_CONST': 80, ++ 'LOAD_DEREF': 81, ++ 'LOAD_FAST': 82, ++ 'LOAD_FAST_AND_CLEAR': 83, ++ 'LOAD_FAST_CHECK': 84, ++ 'LOAD_FAST_LOAD_FAST': 85, ++ 'LOAD_FROM_DICT_OR_DEREF': 86, ++ 'LOAD_FROM_DICT_OR_GLOBALS': 87, ++ 'LOAD_GLOBAL': 88, ++ 'LOAD_NAME': 89, ++ 'LOAD_SMALL_INT': 90, ++ 'LOAD_SPECIAL': 91, ++ 'LOAD_SUPER_ATTR': 92, ++ 'MAKE_CELL': 93, ++ 'MAP_ADD': 94, ++ 'MATCH_CLASS': 95, ++ 'POP_JUMP_IF_FALSE': 96, ++ 'POP_JUMP_IF_NONE': 97, ++ 'POP_JUMP_IF_NOT_NONE': 98, ++ 'POP_JUMP_IF_TRUE': 99, ++ 'RAISE_VARARGS': 100, ++ 'RERAISE': 101, ++ 'SEND': 102, ++ 'SET_ADD': 103, ++ 'SET_FUNCTION_ATTRIBUTE': 104, ++ 'SET_UPDATE': 105, ++ 'STORE_ATTR': 106, ++ 'STORE_DEREF': 107, ++ 'STORE_FAST': 108, ++ 'STORE_FAST_LOAD_FAST': 109, ++ 'STORE_FAST_STORE_FAST': 110, ++ 'STORE_GLOBAL': 111, ++ 'STORE_NAME': 112, ++ 'SWAP': 113, ++ 'UNPACK_EX': 114, ++ 'UNPACK_SEQUENCE': 115, ++ 'YIELD_VALUE': 116, ++ 'INSTRUMENTED_END_FOR': 235, ++ 'INSTRUMENTED_POP_ITER': 236, ++ 'INSTRUMENTED_END_SEND': 237, ++ 'INSTRUMENTED_FOR_ITER': 238, ++ 'INSTRUMENTED_INSTRUCTION': 239, ++ 'INSTRUMENTED_JUMP_FORWARD': 240, ++ 'INSTRUMENTED_NOT_TAKEN': 241, ++ 'INSTRUMENTED_POP_JUMP_IF_TRUE': 242, ++ 'INSTRUMENTED_POP_JUMP_IF_FALSE': 243, ++ 'INSTRUMENTED_POP_JUMP_IF_NONE': 244, ++ 'INSTRUMENTED_POP_JUMP_IF_NOT_NONE': 245, ++ 'INSTRUMENTED_RESUME': 246, ++ 'INSTRUMENTED_RETURN_VALUE': 247, ++ 'INSTRUMENTED_YIELD_VALUE': 248, ++ 'INSTRUMENTED_LOAD_SUPER_ATTR': 249, ++ 'INSTRUMENTED_CALL': 250, ++ 'INSTRUMENTED_CALL_KW': 251, ++ 'INSTRUMENTED_CALL_FUNCTION_EX': 252, + 'INSTRUMENTED_JUMP_BACKWARD': 253, + 'JUMP': 256, + 'JUMP_IF_FALSE': 257, +@@ -348,5 +359,5 @@ + 'STORE_FAST_MAYBE_NULL': 265, + } + +-HAVE_ARGUMENT = 41 +-MIN_INSTRUMENTED_OPCODE = 237 ++HAVE_ARGUMENT = 43 ++MIN_INSTRUMENTED_OPCODE = 235 +diff --git a/Lib/_pydatetime.py b/Lib/_pydatetime.py +index ed01670cfec..be90c9b1315 100644 +--- a/Lib/_pydatetime.py ++++ b/Lib/_pydatetime.py +@@ -2392,7 +2392,6 @@ + + def _isoweek1monday(year): + # Helper to calculate the day number of the Monday starting week 1 +- # XXX This could be done more efficiently + THURSDAY = 3 + firstday = _ymd2ord(year, 1, 1) + firstweekday = (firstday + 6) % 7 # See weekday() above +diff --git a/Lib/_pyio.py b/Lib/_pyio.py +index 14961c39d35..f7370dff19e 100644 +--- a/Lib/_pyio.py ++++ b/Lib/_pyio.py +@@ -937,10 +937,8 @@ + return 0 + pos = self._pos + if pos > len(self._buffer): +- # Inserts null bytes between the current end of the file +- # and the new write position. +- padding = b'\x00' * (pos - len(self._buffer)) +- self._buffer += padding ++ # Pad buffer to pos with null bytes. ++ self._buffer.resize(pos) + self._buffer[pos:pos + n] = b + self._pos += n + return n +@@ -1456,6 +1454,17 @@ + return BufferedWriter.write(self, b) + + ++def _new_buffersize(bytes_read): ++ # Parallels _io/fileio.c new_buffersize ++ if bytes_read > 65536: ++ addend = bytes_read >> 3 ++ else: ++ addend = 256 + bytes_read ++ if addend < DEFAULT_BUFFER_SIZE: ++ addend = DEFAULT_BUFFER_SIZE ++ return bytes_read + addend ++ ++ + class FileIO(RawIOBase): + _fd = -1 + _created = False +@@ -1674,31 +1683,30 @@ + except OSError: + pass + +- result = bytearray() +- while True: +- if len(result) >= bufsize: +- bufsize = len(result) +- bufsize += max(bufsize, DEFAULT_BUFFER_SIZE) +- n = bufsize - len(result) +- try: +- chunk = os.read(self._fd, n) +- except BlockingIOError: +- if result: +- break ++ result = bytearray(bufsize) ++ bytes_read = 0 ++ try: ++ while n := os.readinto(self._fd, memoryview(result)[bytes_read:]): ++ bytes_read += n ++ if bytes_read >= len(result): ++ result.resize(_new_buffersize(bytes_read)) ++ except BlockingIOError: ++ if not bytes_read: + return None +- if not chunk: # reached the end of the file +- break +- result += chunk + ++ assert len(result) - bytes_read >= 1, \ ++ "os.readinto buffer size 0 will result in erroneous EOF / returns 0" ++ result.resize(bytes_read) + return bytes(result) + +- def readinto(self, b): ++ def readinto(self, buffer): + """Same as RawIOBase.readinto().""" +- m = memoryview(b).cast('B') +- data = self.read(len(m)) +- n = len(data) +- m[:n] = data +- return n ++ self._checkClosed() ++ self._checkReadable() ++ try: ++ return os.readinto(self._fd, buffer) ++ except BlockingIOError: ++ return None + + def write(self, b): + """Write bytes b to file, return number written. +diff --git a/Lib/_pyrepl/commands.py b/Lib/_pyrepl/commands.py +index c3fce91013b..503ca1da329 100644 +--- a/Lib/_pyrepl/commands.py ++++ b/Lib/_pyrepl/commands.py +@@ -282,7 +282,7 @@ + x, y = r.pos2xy() + new_y = y + 1 + +- if new_y > r.max_row(): ++ if r.eol() == len(b): + if r.historyi < len(r.history): + r.select_item(r.historyi + 1) + r.pos = r.eol(0) +@@ -309,7 +309,7 @@ + class left(MotionCommand): + def do(self) -> None: + r = self.reader +- for i in range(r.get_arg()): ++ for _ in range(r.get_arg()): + p = r.pos - 1 + if p >= 0: + r.pos = p +@@ -321,7 +321,7 @@ + def do(self) -> None: + r = self.reader + b = r.buffer +- for i in range(r.get_arg()): ++ for _ in range(r.get_arg()): + p = r.pos + 1 + if p <= len(b): + r.pos = p +@@ -459,9 +459,15 @@ + from site import gethistoryfile # type: ignore[attr-defined] + + history = os.linesep.join(self.reader.history[:]) +- with self.reader.suspend(): +- pager = get_pager() +- pager(history, gethistoryfile()) ++ self.reader.console.restore() ++ pager = get_pager() ++ pager(history, gethistoryfile()) ++ self.reader.console.prepare() ++ ++ # We need to copy over the state so that it's consistent between ++ # console and reader, and console does not overwrite/append stuff ++ self.reader.console.screen = self.reader.screen.copy() ++ self.reader.console.posxy = self.reader.cxy + + + class paste_mode(Command): +diff --git a/Lib/_pyrepl/completing_reader.py b/Lib/_pyrepl/completing_reader.py +index e856bb9807c..1cd4b6367ca 100644 +--- a/Lib/_pyrepl/completing_reader.py ++++ b/Lib/_pyrepl/completing_reader.py +@@ -260,10 +260,15 @@ + def calc_screen(self) -> list[str]: + screen = super().calc_screen() + if self.cmpltn_menu_visible: +- ly = self.lxy[1] ++ # We display the completions menu below the current prompt ++ ly = self.lxy[1] + 1 + screen[ly:ly] = self.cmpltn_menu +- self.screeninfo[ly:ly] = [(0, [])]*len(self.cmpltn_menu) +- self.cxy = self.cxy[0], self.cxy[1] + len(self.cmpltn_menu) ++ # If we're not in the middle of multiline edit, don't append to screeninfo ++ # since that screws up the position calculation in pos2xy function. ++ # This is a hack to prevent the cursor jumping ++ # into the completions menu when pressing left or down arrow. ++ if self.pos != len(self.buffer): ++ self.screeninfo[ly:ly] = [(0, [])]*len(self.cmpltn_menu) + return screen + + def finish(self) -> None: +diff --git a/Lib/_pyrepl/console.py b/Lib/_pyrepl/console.py +index 03266c4dfc2..0d78890b4f4 100644 +--- a/Lib/_pyrepl/console.py ++++ b/Lib/_pyrepl/console.py +@@ -45,6 +45,7 @@ + + @dataclass + class Console(ABC): ++ posxy: tuple[int, int] + screen: list[str] = field(default_factory=list) + height: int = 25 + width: int = 80 +diff --git a/Lib/_pyrepl/fancy_termios.py b/Lib/_pyrepl/fancy_termios.py +index 5b85cb0f525..0468b9a2670 100644 +--- a/Lib/_pyrepl/fancy_termios.py ++++ b/Lib/_pyrepl/fancy_termios.py +@@ -40,7 +40,9 @@ + self.lflag, + self.ispeed, + self.ospeed, +- self.cc, ++ # Always return a copy of the control characters list to ensure ++ # there are not any additional references to self.cc ++ self.cc[:], + ] + + def copy(self): +diff --git a/Lib/_pyrepl/historical_reader.py b/Lib/_pyrepl/historical_reader.py +index 5d416f336ad..c4b95fa2e81 100644 +--- a/Lib/_pyrepl/historical_reader.py ++++ b/Lib/_pyrepl/historical_reader.py +@@ -290,13 +290,17 @@ + + @contextmanager + def suspend(self) -> SimpleContextManager: +- with super().suspend(): +- try: +- old_history = self.history[:] +- del self.history[:] +- yield +- finally: +- self.history[:] = old_history ++ with super().suspend(), self.suspend_history(): ++ yield ++ ++ @contextmanager ++ def suspend_history(self) -> SimpleContextManager: ++ try: ++ old_history = self.history[:] ++ del self.history[:] ++ yield ++ finally: ++ self.history[:] = old_history + + def prepare(self) -> None: + super().prepare() +diff --git a/Lib/_pyrepl/reader.py b/Lib/_pyrepl/reader.py +index 4b0700d069c..1252847e02b 100644 +--- a/Lib/_pyrepl/reader.py ++++ b/Lib/_pyrepl/reader.py +@@ -587,10 +587,11 @@ + def pos2xy(self) -> tuple[int, int]: + """Return the x, y coordinates of position 'pos'.""" + # this *is* incomprehensible, yes. +- y = 0 ++ p, y = 0, 0 ++ l2: list[int] = [] + pos = self.pos + assert 0 <= pos <= len(self.buffer) +- if pos == len(self.buffer): ++ if pos == len(self.buffer) and len(self.screeninfo) > 0: + y = len(self.screeninfo) - 1 + p, l2 = self.screeninfo[y] + return p + sum(l2) + l2.count(0), y +diff --git a/Lib/_pyrepl/simple_interact.py b/Lib/_pyrepl/simple_interact.py +index 342a4b58bfd..a065174ad42 100644 +--- a/Lib/_pyrepl/simple_interact.py ++++ b/Lib/_pyrepl/simple_interact.py +@@ -77,7 +77,7 @@ + "exit": _sitebuiltins.Quitter('exit', ''), + "quit": _sitebuiltins.Quitter('quit' ,''), + "copyright": _sitebuiltins._Printer('copyright', sys.copyright), +- "help": "help", ++ "help": _sitebuiltins._Helper(), + "clear": _clear_screen, + "\x1a": _sitebuiltins.Quitter('\x1a', ''), + } +@@ -124,21 +124,13 @@ + reader.history.pop() # skip internal commands in history + command = REPL_COMMANDS[statement] + if callable(command): +- command() ++ # Make sure that history does not change because of commands ++ with reader.suspend_history(): ++ command() + return True +- +- if isinstance(command, str): +- # Internal readline commands require a prepared reader like +- # inside multiline_input. +- reader.prepare() +- reader.refresh() +- reader.do_cmd((command, [statement])) +- reader.restore() +- return True +- + return False + +- while 1: ++ while True: + try: + try: + sys.stdout.flush() +diff --git a/Lib/_pyrepl/unix_console.py b/Lib/_pyrepl/unix_console.py +index 2576b938a34..96379bc20f3 100644 +--- a/Lib/_pyrepl/unix_console.py ++++ b/Lib/_pyrepl/unix_console.py +@@ -240,7 +240,7 @@ + self.__hide_cursor() + self.__move(0, len(self.screen) - 1) + self.__write("\n") +- self.__posxy = 0, len(self.screen) ++ self.posxy = 0, len(self.screen) + self.screen.append("") + else: + while len(self.screen) < len(screen): +@@ -250,7 +250,7 @@ + self.__gone_tall = 1 + self.__move = self.__move_tall + +- px, py = self.__posxy ++ px, py = self.posxy + old_offset = offset = self.__offset + height = self.height + +@@ -271,7 +271,7 @@ + if old_offset > offset and self._ri: + self.__hide_cursor() + self.__write_code(self._cup, 0, 0) +- self.__posxy = 0, old_offset ++ self.posxy = 0, old_offset + for i in range(old_offset - offset): + self.__write_code(self._ri) + oldscr.pop(-1) +@@ -279,7 +279,7 @@ + elif old_offset < offset and self._ind: + self.__hide_cursor() + self.__write_code(self._cup, self.height - 1, 0) +- self.__posxy = 0, old_offset + self.height - 1 ++ self.posxy = 0, old_offset + self.height - 1 + for i in range(offset - old_offset): + self.__write_code(self._ind) + oldscr.pop(0) +@@ -299,7 +299,7 @@ + while y < len(oldscr): + self.__hide_cursor() + self.__move(0, y) +- self.__posxy = 0, y ++ self.posxy = 0, y + self.__write_code(self._el) + y += 1 + +@@ -321,7 +321,7 @@ + self.event_queue.insert(Event("scroll", None)) + else: + self.__move(x, y) +- self.__posxy = x, y ++ self.posxy = x, y + self.flushoutput() + + def prepare(self): +@@ -350,7 +350,7 @@ + + self.__buffer = [] + +- self.__posxy = 0, 0 ++ self.posxy = 0, 0 + self.__gone_tall = 0 + self.__move = self.__move_short + self.__offset = 0 +@@ -449,10 +449,12 @@ + """ + try: + return int(os.environ["LINES"]), int(os.environ["COLUMNS"]) +- except KeyError: +- height, width = struct.unpack( +- "hhhh", ioctl(self.input_fd, TIOCGWINSZ, b"\000" * 8) +- )[0:2] ++ except (KeyError, TypeError, ValueError): ++ try: ++ size = ioctl(self.input_fd, TIOCGWINSZ, b"\000" * 8) ++ except OSError: ++ return 25, 80 ++ height, width = struct.unpack("hhhh", size)[0:2] + if not height: + return 25, 80 + return height, width +@@ -468,7 +470,7 @@ + """ + try: + return int(os.environ["LINES"]), int(os.environ["COLUMNS"]) +- except KeyError: ++ except (KeyError, TypeError, ValueError): + return 25, 80 + + def forgetinput(self): +@@ -559,7 +561,7 @@ + self.__write_code(self._clear) + self.__gone_tall = 1 + self.__move = self.__move_tall +- self.__posxy = 0, 0 ++ self.posxy = 0, 0 + self.screen = [] + + @property +@@ -644,8 +646,8 @@ + # if we need to insert a single character right after the first detected change + if oldline[x_pos:] == newline[x_pos + 1 :] and self.ich1: + if ( +- y == self.__posxy[1] +- and x_coord > self.__posxy[0] ++ y == self.posxy[1] ++ and x_coord > self.posxy[0] + and oldline[px_pos:x_pos] == newline[px_pos + 1 : x_pos + 1] + ): + x_pos = px_pos +@@ -654,7 +656,7 @@ + self.__move(x_coord, y) + self.__write_code(self.ich1) + self.__write(newline[x_pos]) +- self.__posxy = x_coord + character_width, y ++ self.posxy = x_coord + character_width, y + + # if it's a single character change in the middle of the line + elif ( +@@ -665,7 +667,7 @@ + character_width = wlen(newline[x_pos]) + self.__move(x_coord, y) + self.__write(newline[x_pos]) +- self.__posxy = x_coord + character_width, y ++ self.posxy = x_coord + character_width, y + + # if this is the last character to fit in the line and we edit in the middle of the line + elif ( +@@ -677,14 +679,14 @@ + ): + self.__hide_cursor() + self.__move(self.width - 2, y) +- self.__posxy = self.width - 2, y ++ self.posxy = self.width - 2, y + self.__write_code(self.dch1) + + character_width = wlen(newline[x_pos]) + self.__move(x_coord, y) + self.__write_code(self.ich1) + self.__write(newline[x_pos]) +- self.__posxy = character_width + 1, y ++ self.posxy = character_width + 1, y + + else: + self.__hide_cursor() +@@ -692,7 +694,7 @@ + if wlen(oldline) > wlen(newline): + self.__write_code(self._el) + self.__write(newline[x_pos:]) +- self.__posxy = wlen(newline), y ++ self.posxy = wlen(newline), y + + if "\x1b" in newline: + # ANSI escape characters are present, so we can't assume +@@ -711,32 +713,36 @@ + self.__write_code(fmt, *args) + + def __move_y_cuu1_cud1(self, y): +- dy = y - self.__posxy[1] ++ assert self._cud1 is not None ++ assert self._cuu1 is not None ++ dy = y - self.posxy[1] + if dy > 0: + self.__write_code(dy * self._cud1) + elif dy < 0: + self.__write_code((-dy) * self._cuu1) + + def __move_y_cuu_cud(self, y): +- dy = y - self.__posxy[1] ++ dy = y - self.posxy[1] + if dy > 0: + self.__write_code(self._cud, dy) + elif dy < 0: + self.__write_code(self._cuu, -dy) + + def __move_x_hpa(self, x: int) -> None: +- if x != self.__posxy[0]: ++ if x != self.posxy[0]: + self.__write_code(self._hpa, x) + + def __move_x_cub1_cuf1(self, x: int) -> None: +- dx = x - self.__posxy[0] ++ assert self._cuf1 is not None ++ assert self._cub1 is not None ++ dx = x - self.posxy[0] + if dx > 0: + self.__write_code(self._cuf1 * dx) + elif dx < 0: + self.__write_code(self._cub1 * (-dx)) + + def __move_x_cub_cuf(self, x: int) -> None: +- dx = x - self.__posxy[0] ++ dx = x - self.posxy[0] + if dx > 0: + self.__write_code(self._cuf, dx) + elif dx < 0: +@@ -766,12 +772,12 @@ + + def repaint(self): + if not self.__gone_tall: +- self.__posxy = 0, self.__posxy[1] ++ self.posxy = 0, self.posxy[1] + self.__write("\r") + ns = len(self.screen) * ["\000" * self.width] + self.screen = ns + else: +- self.__posxy = 0, self.__offset ++ self.posxy = 0, self.__offset + self.__move(0, self.__offset) + ns = self.height * ["\000" * self.width] + self.screen = ns +@@ -786,7 +792,7 @@ + # only if the bps is actually needed (which I'm + # betting is pretty unlkely) + bps = ratedict.get(self.__svtermstate.ospeed) +- while 1: ++ while True: + m = prog.search(fmt) + if not m: + os.write(self.output_fd, fmt) +diff --git a/Lib/_pyrepl/utils.py b/Lib/_pyrepl/utils.py +index 0f36083b6ff..4651717bd7e 100644 +--- a/Lib/_pyrepl/utils.py ++++ b/Lib/_pyrepl/utils.py +@@ -16,7 +16,7 @@ + + + def wlen(s: str) -> int: +- if len(s) == 1: ++ if len(s) == 1 and s != '\x1a': + return str_width(s) + length = sum(str_width(i) for i in s) + # remove lengths of any escape sequences +diff --git a/Lib/_pyrepl/windows_console.py b/Lib/_pyrepl/windows_console.py +index d457d2b5a33..e1ecd9845ae 100644 +--- a/Lib/_pyrepl/windows_console.py ++++ b/Lib/_pyrepl/windows_console.py +@@ -102,6 +102,10 @@ + MOVE_DOWN = "\x1b[{}B" + CLEAR = "\x1b[H\x1b[J" + ++# State of control keys: https://learn.microsoft.com/en-us/windows/console/key-event-record-str ++ALT_ACTIVE = 0x01 | 0x02 ++CTRL_ACTIVE = 0x04 | 0x08 ++ + + class _error(Exception): + pass +@@ -148,10 +152,10 @@ + self._hide_cursor() + self._move_relative(0, len(self.screen) - 1) + self.__write("\n") +- self.__posxy = 0, len(self.screen) ++ self.posxy = 0, len(self.screen) + self.screen.append("") + +- px, py = self.__posxy ++ px, py = self.posxy + old_offset = offset = self.__offset + height = self.height + +@@ -167,7 +171,7 @@ + # portion of the window. We need to scroll the visible portion and the + # entire history + self._scroll(scroll_lines, self._getscrollbacksize()) +- self.__posxy = self.__posxy[0], self.__posxy[1] + scroll_lines ++ self.posxy = self.posxy[0], self.posxy[1] + scroll_lines + self.__offset += scroll_lines + + for i in range(scroll_lines): +@@ -193,7 +197,7 @@ + y = len(newscr) + while y < len(oldscr): + self._move_relative(0, y) +- self.__posxy = 0, y ++ self.posxy = 0, y + self._erase_to_end() + y += 1 + +@@ -250,11 +254,11 @@ + if wlen(newline) == self.width: + # If we wrapped we want to start at the next line + self._move_relative(0, y + 1) +- self.__posxy = 0, y + 1 ++ self.posxy = 0, y + 1 + else: +- self.__posxy = wlen(newline), y ++ self.posxy = wlen(newline), y + +- if "\x1b" in newline or y != self.__posxy[1] or '\x1a' in newline: ++ if "\x1b" in newline or y != self.posxy[1] or '\x1a' in newline: + # ANSI escape characters are present, so we can't assume + # anything about the position of the cursor. Moving the cursor + # to the left margin should work to get to a known position. +@@ -316,7 +320,7 @@ + self.screen = [] + self.height, self.width = self.getheightwidth() + +- self.__posxy = 0, 0 ++ self.posxy = 0, 0 + self.__gone_tall = 0 + self.__offset = 0 + +@@ -324,9 +328,9 @@ + pass + + def _move_relative(self, x: int, y: int) -> None: +- """Moves relative to the current __posxy""" +- dx = x - self.__posxy[0] +- dy = y - self.__posxy[1] ++ """Moves relative to the current posxy""" ++ dx = x - self.posxy[0] ++ dy = y - self.posxy[1] + if dx < 0: + self.__write(MOVE_LEFT.format(-dx)) + elif dx > 0: +@@ -345,7 +349,7 @@ + self.event_queue.insert(0, Event("scroll", "")) + else: + self._move_relative(x, y) +- self.__posxy = x, y ++ self.posxy = x, y + + def set_cursor_vis(self, visible: bool) -> None: + if visible: +@@ -407,31 +411,37 @@ + continue + return None + +- key = rec.Event.KeyEvent.uChar.UnicodeChar ++ key_event = rec.Event.KeyEvent ++ raw_key = key = key_event.uChar.UnicodeChar + +- if rec.Event.KeyEvent.uChar.UnicodeChar == "\r": +- # Make enter make unix-like ++ if key == "\r": ++ # Make enter unix-like + return Event(evt="key", data="\n", raw=b"\n") +- elif rec.Event.KeyEvent.wVirtualKeyCode == 8: ++ elif key_event.wVirtualKeyCode == 8: + # Turn backspace directly into the command +- return Event( +- evt="key", +- data="backspace", +- raw=rec.Event.KeyEvent.uChar.UnicodeChar, +- ) +- elif rec.Event.KeyEvent.uChar.UnicodeChar == "\x00": ++ key = "backspace" ++ elif key == "\x00": + # Handle special keys like arrow keys and translate them into the appropriate command +- code = VK_MAP.get(rec.Event.KeyEvent.wVirtualKeyCode) +- if code: +- return Event( +- evt="key", data=code, raw=rec.Event.KeyEvent.uChar.UnicodeChar +- ) ++ key = VK_MAP.get(key_event.wVirtualKeyCode) ++ if key: ++ if key_event.dwControlKeyState & CTRL_ACTIVE: ++ key = f"ctrl {key}" ++ elif key_event.dwControlKeyState & ALT_ACTIVE: ++ # queue the key, return the meta command ++ self.event_queue.insert(0, Event(evt="key", data=key, raw=key)) ++ return Event(evt="key", data="\033") # keymap.py uses this for meta ++ return Event(evt="key", data=key, raw=key) + if block: + continue + + return None + +- return Event(evt="key", data=key, raw=rec.Event.KeyEvent.uChar.UnicodeChar) ++ if key_event.dwControlKeyState & ALT_ACTIVE: ++ # queue the key, return the meta command ++ self.event_queue.insert(0, Event(evt="key", data=key, raw=raw_key)) ++ return Event(evt="key", data="\033") # keymap.py uses this for meta ++ ++ return Event(evt="key", data=key, raw=raw_key) + + def push_char(self, char: int | bytes) -> None: + """ +@@ -445,7 +455,7 @@ + def clear(self) -> None: + """Wipe the screen""" + self.__write(CLEAR) +- self.__posxy = 0, 0 ++ self.posxy = 0, 0 + self.screen = [""] + + def finish(self) -> None: +diff --git a/Lib/ast.py b/Lib/ast.py +index 154d2c8c1f9..0937c27bdf8 100644 +--- a/Lib/ast.py ++++ b/Lib/ast.py +@@ -1196,9 +1196,14 @@ + fallback_to_repr = True + break + quote_types = new_quote_types +- elif "\n" in value: +- quote_types = [q for q in quote_types if q in _MULTI_QUOTES] +- assert quote_types ++ else: ++ if "\n" in value: ++ quote_types = [q for q in quote_types if q in _MULTI_QUOTES] ++ assert quote_types ++ ++ new_quote_types = [q for q in quote_types if q not in value] ++ if new_quote_types: ++ quote_types = new_quote_types + new_fstring_parts.append(value) + + if fallback_to_repr: +diff --git a/Lib/asyncio/__init__.py b/Lib/asyncio/__init__.py +index 03165a425eb..4be7112fa01 100644 +--- a/Lib/asyncio/__init__.py ++++ b/Lib/asyncio/__init__.py +@@ -10,6 +10,7 @@ + from .events import * + from .exceptions import * + from .futures import * ++from .graph import * + from .locks import * + from .protocols import * + from .runners import * +@@ -27,6 +28,7 @@ + events.__all__ + + exceptions.__all__ + + futures.__all__ + ++ graph.__all__ + + locks.__all__ + + protocols.__all__ + + runners.__all__ + +@@ -45,3 +47,19 @@ + else: + from .unix_events import * # pragma: no cover + __all__ += unix_events.__all__ ++ ++def __getattr__(name: str): ++ import warnings ++ ++ deprecated = { ++ "AbstractEventLoopPolicy", ++ "DefaultEventLoopPolicy", ++ "WindowsSelectorEventLoopPolicy", ++ "WindowsProactorEventLoopPolicy", ++ } ++ if name in deprecated: ++ warnings._deprecated(f"asyncio.{name}", remove=(3, 16)) ++ # deprecated things have underscores in front of them ++ return globals()["_" + name] ++ ++ raise AttributeError(f"module {__name__!r} has no attribute {name!r}") +diff --git a/Lib/asyncio/__main__.py b/Lib/asyncio/__main__.py +index 95c636f9e02..662ba649aa0 100644 +--- a/Lib/asyncio/__main__.py ++++ b/Lib/asyncio/__main__.py +@@ -149,7 +149,7 @@ + + return_code = 0 + loop = asyncio.new_event_loop() +- asyncio.set_event_loop(loop) ++ asyncio._set_event_loop(loop) + + repl_locals = {'asyncio': asyncio} + for key in {'__name__', '__package__', +diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py +index 5dbe4b28d23..ed852421e44 100644 +--- a/Lib/asyncio/base_events.py ++++ b/Lib/asyncio/base_events.py +@@ -458,26 +458,24 @@ + """Create a Future object attached to the loop.""" + return futures.Future(loop=self) + +- def create_task(self, coro, *, name=None, context=None): ++ def create_task(self, coro, **kwargs): + """Schedule a coroutine object. + + Return a task object. + """ + self._check_closed() +- if self._task_factory is None: +- task = tasks.Task(coro, loop=self, name=name, context=context) +- if task._source_traceback: +- del task._source_traceback[-1] +- else: +- if context is None: +- # Use legacy API if context is not needed +- task = self._task_factory(self, coro) +- else: +- task = self._task_factory(self, coro, context=context) +- +- task.set_name(name) ++ if self._task_factory is not None: ++ return self._task_factory(self, coro, **kwargs) + +- return task ++ task = tasks.Task(coro, loop=self, **kwargs) ++ if task._source_traceback: ++ del task._source_traceback[-1] ++ try: ++ return task ++ finally: ++ # gh-128552: prevent a refcycle of ++ # task.exception().__traceback__->BaseEventLoop.create_task->task ++ del task + + def set_task_factory(self, factory): + """Set a task factory that will be used by loop.create_task(). +@@ -485,9 +483,10 @@ + If factory is None the default task factory will be set. + + If factory is a callable, it should have a signature matching +- '(loop, coro)', where 'loop' will be a reference to the active +- event loop, 'coro' will be a coroutine object. The callable +- must return a Future. ++ '(loop, coro, **kwargs)', where 'loop' will be a reference to the active ++ event loop, 'coro' will be a coroutine object, and **kwargs will be ++ arbitrary keyword arguments that should be passed on to Task. ++ The callable must return a Task. + """ + if factory is not None and not callable(factory): + raise TypeError('task factory must be a callable or None') +@@ -873,7 +872,10 @@ + self._check_closed() + if self._debug: + self._check_callback(callback, 'call_soon_threadsafe') +- handle = self._call_soon(callback, args, context) ++ handle = events._ThreadSafeHandle(callback, args, self, context) ++ self._ready.append(handle) ++ if handle._source_traceback: ++ del handle._source_traceback[-1] + if handle._source_traceback: + del handle._source_traceback[-1] + self._write_to_self() +@@ -1585,7 +1587,9 @@ + if reuse_address: + sock.setsockopt( + socket.SOL_SOCKET, socket.SO_REUSEADDR, True) +- if reuse_port: ++ # Since Linux 6.12.9, SO_REUSEPORT is not allowed ++ # on other address families than AF_INET/AF_INET6. ++ if reuse_port and af in (socket.AF_INET, socket.AF_INET6): + _set_reuseport(sock) + if keep_alive: + sock.setsockopt( +diff --git a/Lib/asyncio/events.py b/Lib/asyncio/events.py +index ca0a4f2fee5..2e45b4fe6fa 100644 +--- a/Lib/asyncio/events.py ++++ b/Lib/asyncio/events.py +@@ -5,13 +5,22 @@ + # SPDX-FileCopyrightText: Copyright (c) 2015-2021 MagicStack Inc. http://magic.io + + __all__ = ( +- 'AbstractEventLoopPolicy', +- 'AbstractEventLoop', 'AbstractServer', +- 'Handle', 'TimerHandle', +- 'get_event_loop_policy', 'set_event_loop_policy', +- 'get_event_loop', 'set_event_loop', 'new_event_loop', +- '_set_running_loop', 'get_running_loop', +- '_get_running_loop', ++ "_AbstractEventLoopPolicy", ++ "AbstractEventLoop", ++ "AbstractServer", ++ "Handle", ++ "TimerHandle", ++ "_get_event_loop_policy", ++ "get_event_loop_policy", ++ "_set_event_loop_policy", ++ "set_event_loop_policy", ++ "get_event_loop", ++ "_set_event_loop", ++ "set_event_loop", ++ "new_event_loop", ++ "_set_running_loop", ++ "get_running_loop", ++ "_get_running_loop", + ) + + import contextvars +@@ -21,6 +30,7 @@ + import subprocess + import sys + import threading ++import warnings + + from . import format_helpers + +@@ -103,6 +113,34 @@ + self._loop.call_exception_handler(context) + self = None # Needed to break cycles when an exception occurs. + ++# _ThreadSafeHandle is used for callbacks scheduled with call_soon_threadsafe ++# and is thread safe unlike Handle which is not thread safe. ++class _ThreadSafeHandle(Handle): ++ ++ __slots__ = ('_lock',) ++ ++ def __init__(self, callback, args, loop, context=None): ++ super().__init__(callback, args, loop, context) ++ self._lock = threading.RLock() ++ ++ def cancel(self): ++ with self._lock: ++ return super().cancel() ++ ++ def cancelled(self): ++ with self._lock: ++ return super().cancelled() ++ ++ def _run(self): ++ # The event loop checks for cancellation without holding the lock ++ # It is possible that the handle is cancelled after the check ++ # but before the callback is called so check it again after acquiring ++ # the lock and return without calling the callback if it is cancelled. ++ with self._lock: ++ if self._cancelled: ++ return ++ return super()._run() ++ + + class TimerHandle(Handle): + """Object returned by timed callback registration methods.""" +@@ -291,7 +329,7 @@ + + # Method scheduling a coroutine object: create a task. + +- def create_task(self, coro, *, name=None, context=None): ++ def create_task(self, coro, **kwargs): + raise NotImplementedError + + # Methods for interacting with threads. +@@ -628,7 +666,7 @@ + raise NotImplementedError + + +-class AbstractEventLoopPolicy: ++class _AbstractEventLoopPolicy: + """Abstract policy for accessing the event loop.""" + + def get_event_loop(self): +@@ -651,7 +689,7 @@ + the current context, set_event_loop must be called explicitly.""" + raise NotImplementedError + +-class BaseDefaultEventLoopPolicy(AbstractEventLoopPolicy): ++class _BaseDefaultEventLoopPolicy(_AbstractEventLoopPolicy): + """Default policy implementation for accessing the event loop. + + In this policy, each thread has its own event loop. However, we +@@ -754,26 +792,32 @@ + global _event_loop_policy + with _lock: + if _event_loop_policy is None: # pragma: no branch +- from . import DefaultEventLoopPolicy +- _event_loop_policy = DefaultEventLoopPolicy() ++ from . import _DefaultEventLoopPolicy ++ _event_loop_policy = _DefaultEventLoopPolicy() + + +-def get_event_loop_policy(): ++def _get_event_loop_policy(): + """Get the current event loop policy.""" + if _event_loop_policy is None: + _init_event_loop_policy() + return _event_loop_policy + ++def get_event_loop_policy(): ++ warnings._deprecated('asyncio.get_event_loop_policy', remove=(3, 16)) ++ return _get_event_loop_policy() + +-def set_event_loop_policy(policy): ++def _set_event_loop_policy(policy): + """Set the current event loop policy. + + If policy is None, the default policy is restored.""" + global _event_loop_policy +- if policy is not None and not isinstance(policy, AbstractEventLoopPolicy): ++ if policy is not None and not isinstance(policy, _AbstractEventLoopPolicy): + raise TypeError(f"policy must be an instance of AbstractEventLoopPolicy or None, not '{type(policy).__name__}'") + _event_loop_policy = policy + ++def set_event_loop_policy(policy): ++ warnings._deprecated('asyncio.set_event_loop_policy', remove=(3,16)) ++ _set_event_loop_policy(policy) + + def get_event_loop(): + """Return an asyncio event loop. +@@ -788,17 +832,21 @@ + current_loop = _get_running_loop() + if current_loop is not None: + return current_loop +- return get_event_loop_policy().get_event_loop() ++ return _get_event_loop_policy().get_event_loop() ++ + ++def _set_event_loop(loop): ++ _get_event_loop_policy().set_event_loop(loop) + + def set_event_loop(loop): + """Equivalent to calling get_event_loop_policy().set_event_loop(loop).""" +- get_event_loop_policy().set_event_loop(loop) ++ warnings._deprecated('asyncio.set_event_loop', remove=(3,16)) ++ _set_event_loop(loop) + + + def new_event_loop(): + """Equivalent to calling get_event_loop_policy().new_event_loop().""" +- return get_event_loop_policy().new_event_loop() ++ return _get_event_loop_policy().new_event_loop() + + + # Alias pure-Python implementations for testing purposes. +@@ -828,7 +876,7 @@ + def on_fork(): + # Reset the loop and wakeupfd in the forked child process. + if _event_loop_policy is not None: +- _event_loop_policy._local = BaseDefaultEventLoopPolicy._Local() ++ _event_loop_policy._local = _BaseDefaultEventLoopPolicy._Local() + _set_running_loop(None) + signal.set_wakeup_fd(-1) + +diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py +index c95fce035cd..d1df6707302 100644 +--- a/Lib/asyncio/futures.py ++++ b/Lib/asyncio/futures.py +@@ -2,6 +2,7 @@ + + __all__ = ( + 'Future', 'wrap_future', 'isfuture', ++ 'future_add_to_awaited_by', 'future_discard_from_awaited_by', + ) + + import concurrent.futures +@@ -62,10 +63,13 @@ + # that it is not compatible by setting this to None. + # - It is set by __iter__() below so that Task.__step() can tell + # the difference between +- # `await Future()` or`yield from Future()` (correct) vs. ++ # `await Future()` or `yield from Future()` (correct) vs. + # `yield Future()` (incorrect). + _asyncio_future_blocking = False + ++ # Used by the capture_call_stack() API. ++ __asyncio_awaited_by = None ++ + __log_traceback = False + + def __init__(self, *, loop=None): +@@ -115,6 +119,12 @@ + raise ValueError('_log_traceback can only be set to False') + self.__log_traceback = False + ++ @property ++ def _asyncio_awaited_by(self): ++ if self.__asyncio_awaited_by is None: ++ return None ++ return frozenset(self.__asyncio_awaited_by) ++ + def get_loop(self): + """Return the event loop the Future is bound to.""" + loop = self._loop +@@ -415,6 +425,49 @@ + return new_future + + ++def future_add_to_awaited_by(fut, waiter, /): ++ """Record that `fut` is awaited on by `waiter`.""" ++ # For the sake of keeping the implementation minimal and assuming ++ # that most of asyncio users use the built-in Futures and Tasks ++ # (or their subclasses), we only support native Future objects ++ # and their subclasses. ++ # ++ # Longer version: tracking requires storing the caller-callee ++ # dependency somewhere. One obvious choice is to store that ++ # information right in the future itself in a dedicated attribute. ++ # This means that we'd have to require all duck-type compatible ++ # futures to implement a specific attribute used by asyncio for ++ # the book keeping. Another solution would be to store that in ++ # a global dictionary. The downside here is that that would create ++ # strong references and any scenario where the "add" call isn't ++ # followed by a "discard" call would lead to a memory leak. ++ # Using WeakDict would resolve that issue, but would complicate ++ # the C code (_asynciomodule.c). The bottom line here is that ++ # it's not clear that all this work would be worth the effort. ++ # ++ # Note that there's an accelerated version of this function ++ # shadowing this implementation later in this file. ++ if isinstance(fut, _PyFuture) and isinstance(waiter, _PyFuture): ++ if fut._Future__asyncio_awaited_by is None: ++ fut._Future__asyncio_awaited_by = set() ++ fut._Future__asyncio_awaited_by.add(waiter) ++ ++ ++def future_discard_from_awaited_by(fut, waiter, /): ++ """Record that `fut` is no longer awaited on by `waiter`.""" ++ # See the comment in "future_add_to_awaited_by()" body for ++ # details on implementation. ++ # ++ # Note that there's an accelerated version of this function ++ # shadowing this implementation later in this file. ++ if isinstance(fut, _PyFuture) and isinstance(waiter, _PyFuture): ++ if fut._Future__asyncio_awaited_by is not None: ++ fut._Future__asyncio_awaited_by.discard(waiter) ++ ++ ++_py_future_add_to_awaited_by = future_add_to_awaited_by ++_py_future_discard_from_awaited_by = future_discard_from_awaited_by ++ + try: + import _asyncio + except ImportError: +@@ -422,3 +475,7 @@ + else: + # _CFuture is needed for tests. + Future = _CFuture = _asyncio.Future ++ future_add_to_awaited_by = _asyncio.future_add_to_awaited_by ++ future_discard_from_awaited_by = _asyncio.future_discard_from_awaited_by ++ _c_future_add_to_awaited_by = future_add_to_awaited_by ++ _c_future_discard_from_awaited_by = future_discard_from_awaited_by +--- /dev/null ++++ b/Lib/asyncio/graph.py +@@ -0,0 +1,278 @@ ++"""Introspection utils for tasks call graphs.""" ++ ++import dataclasses ++import sys ++import types ++ ++from . import events ++from . import futures ++from . import tasks ++ ++__all__ = ( ++ 'capture_call_graph', ++ 'format_call_graph', ++ 'print_call_graph', ++ 'FrameCallGraphEntry', ++ 'FutureCallGraph', ++) ++ ++if False: # for type checkers ++ from typing import TextIO ++ ++# Sadly, we can't re-use the traceback module's datastructures as those ++# are tailored for error reporting, whereas we need to represent an ++# async call graph. ++# ++# Going with pretty verbose names as we'd like to export them to the ++# top level asyncio namespace, and want to avoid future name clashes. ++ ++ ++@dataclasses.dataclass(frozen=True, slots=True) ++class FrameCallGraphEntry: ++ frame: types.FrameType ++ ++ ++@dataclasses.dataclass(frozen=True, slots=True) ++class FutureCallGraph: ++ future: futures.Future ++ call_stack: tuple["FrameCallGraphEntry", ...] ++ awaited_by: tuple["FutureCallGraph", ...] ++ ++ ++def _build_graph_for_future( ++ future: futures.Future, ++ *, ++ limit: int | None = None, ++) -> FutureCallGraph: ++ if not isinstance(future, futures.Future): ++ raise TypeError( ++ f"{future!r} object does not appear to be compatible " ++ f"with asyncio.Future" ++ ) ++ ++ coro = None ++ if get_coro := getattr(future, 'get_coro', None): ++ coro = get_coro() if limit != 0 else None ++ ++ st: list[FrameCallGraphEntry] = [] ++ awaited_by: list[FutureCallGraph] = [] ++ ++ while coro is not None: ++ if hasattr(coro, 'cr_await'): ++ # A native coroutine or duck-type compatible iterator ++ st.append(FrameCallGraphEntry(coro.cr_frame)) ++ coro = coro.cr_await ++ elif hasattr(coro, 'ag_await'): ++ # A native async generator or duck-type compatible iterator ++ st.append(FrameCallGraphEntry(coro.cr_frame)) ++ coro = coro.ag_await ++ else: ++ break ++ ++ if future._asyncio_awaited_by: ++ for parent in future._asyncio_awaited_by: ++ awaited_by.append(_build_graph_for_future(parent, limit=limit)) ++ ++ if limit is not None: ++ if limit > 0: ++ st = st[:limit] ++ elif limit < 0: ++ st = st[limit:] ++ st.reverse() ++ return FutureCallGraph(future, tuple(st), tuple(awaited_by)) ++ ++ ++def capture_call_graph( ++ future: futures.Future | None = None, ++ /, ++ *, ++ depth: int = 1, ++ limit: int | None = None, ++) -> FutureCallGraph | None: ++ """Capture the async call graph for the current task or the provided Future. ++ ++ The graph is represented with three data structures: ++ ++ * FutureCallGraph(future, call_stack, awaited_by) ++ ++ Where 'future' is an instance of asyncio.Future or asyncio.Task. ++ ++ 'call_stack' is a tuple of FrameGraphEntry objects. ++ ++ 'awaited_by' is a tuple of FutureCallGraph objects. ++ ++ * FrameCallGraphEntry(frame) ++ ++ Where 'frame' is a frame object of a regular Python function ++ in the call stack. ++ ++ Receives an optional 'future' argument. If not passed, ++ the current task will be used. If there's no current task, the function ++ returns None. ++ ++ If "capture_call_graph()" is introspecting *the current task*, the ++ optional keyword-only 'depth' argument can be used to skip the specified ++ number of frames from top of the stack. ++ ++ If the optional keyword-only 'limit' argument is provided, each call stack ++ in the resulting graph is truncated to include at most ``abs(limit)`` ++ entries. If 'limit' is positive, the entries left are the closest to ++ the invocation point. If 'limit' is negative, the topmost entries are ++ left. If 'limit' is omitted or None, all entries are present. ++ If 'limit' is 0, the call stack is not captured at all, only ++ "awaited by" information is present. ++ """ ++ ++ loop = events._get_running_loop() ++ ++ if future is not None: ++ # Check if we're in a context of a running event loop; ++ # if yes - check if the passed future is the currently ++ # running task or not. ++ if loop is None or future is not tasks.current_task(loop=loop): ++ return _build_graph_for_future(future, limit=limit) ++ # else: future is the current task, move on. ++ else: ++ if loop is None: ++ raise RuntimeError( ++ 'capture_call_graph() is called outside of a running ' ++ 'event loop and no *future* to introspect was provided') ++ future = tasks.current_task(loop=loop) ++ ++ if future is None: ++ # This isn't a generic call stack introspection utility. If we ++ # can't determine the current task and none was provided, we ++ # just return. ++ return None ++ ++ if not isinstance(future, futures.Future): ++ raise TypeError( ++ f"{future!r} object does not appear to be compatible " ++ f"with asyncio.Future" ++ ) ++ ++ call_stack: list[FrameCallGraphEntry] = [] ++ ++ f = sys._getframe(depth) if limit != 0 else None ++ try: ++ while f is not None: ++ is_async = f.f_generator is not None ++ call_stack.append(FrameCallGraphEntry(f)) ++ ++ if is_async: ++ if f.f_back is not None and f.f_back.f_generator is None: ++ # We've reached the bottom of the coroutine stack, which ++ # must be the Task that runs it. ++ break ++ ++ f = f.f_back ++ finally: ++ del f ++ ++ awaited_by = [] ++ if future._asyncio_awaited_by: ++ for parent in future._asyncio_awaited_by: ++ awaited_by.append(_build_graph_for_future(parent, limit=limit)) ++ ++ if limit is not None: ++ limit *= -1 ++ if limit > 0: ++ call_stack = call_stack[:limit] ++ elif limit < 0: ++ call_stack = call_stack[limit:] ++ ++ return FutureCallGraph(future, tuple(call_stack), tuple(awaited_by)) ++ ++ ++def format_call_graph( ++ future: futures.Future | None = None, ++ /, ++ *, ++ depth: int = 1, ++ limit: int | None = None, ++) -> str: ++ """Return the async call graph as a string for `future`. ++ ++ If `future` is not provided, format the call graph for the current task. ++ """ ++ ++ def render_level(st: FutureCallGraph, buf: list[str], level: int) -> None: ++ def add_line(line: str) -> None: ++ buf.append(level * ' ' + line) ++ ++ if isinstance(st.future, tasks.Task): ++ add_line( ++ f'* Task(name={st.future.get_name()!r}, id={id(st.future):#x})' ++ ) ++ else: ++ add_line( ++ f'* Future(id={id(st.future):#x})' ++ ) ++ ++ if st.call_stack: ++ add_line( ++ f' + Call stack:' ++ ) ++ for ste in st.call_stack: ++ f = ste.frame ++ ++ if f.f_generator is None: ++ f = ste.frame ++ add_line( ++ f' | File {f.f_code.co_filename!r},' ++ f' line {f.f_lineno}, in' ++ f' {f.f_code.co_qualname}()' ++ ) ++ else: ++ c = f.f_generator ++ ++ try: ++ f = c.cr_frame ++ code = c.cr_code ++ tag = 'async' ++ except AttributeError: ++ try: ++ f = c.ag_frame ++ code = c.ag_code ++ tag = 'async generator' ++ except AttributeError: ++ f = c.gi_frame ++ code = c.gi_code ++ tag = 'generator' ++ ++ add_line( ++ f' | File {f.f_code.co_filename!r},' ++ f' line {f.f_lineno}, in' ++ f' {tag} {code.co_qualname}()' ++ ) ++ ++ if st.awaited_by: ++ add_line( ++ f' + Awaited by:' ++ ) ++ for fut in st.awaited_by: ++ render_level(fut, buf, level + 1) ++ ++ graph = capture_call_graph(future, depth=depth + 1, limit=limit) ++ if graph is None: ++ return "" ++ ++ buf: list[str] = [] ++ try: ++ render_level(graph, buf, 0) ++ finally: ++ # 'graph' has references to frames so we should ++ # make sure it's GC'ed as soon as we don't need it. ++ del graph ++ return '\n'.join(buf) ++ ++def print_call_graph( ++ future: futures.Future | None = None, ++ /, ++ *, ++ file: TextIO | None = None, ++ depth: int = 1, ++ limit: int | None = None, ++) -> None: ++ """Print the async call graph for the current task or the provided Future.""" ++ print(format_call_graph(future, depth=depth, limit=limit), file=file) +diff --git a/Lib/asyncio/locks.py b/Lib/asyncio/locks.py +index f2f8b7ec858..fa3a94764b5 100644 +--- a/Lib/asyncio/locks.py ++++ b/Lib/asyncio/locks.py +@@ -485,7 +485,7 @@ + def __init__(self, parties): + """Create a barrier, initialised to 'parties' tasks.""" + if parties < 1: +- raise ValueError('parties must be > 0') ++ raise ValueError('parties must be >= 1') + + self._cond = Condition() # notify all tasks when state changes + +diff --git a/Lib/asyncio/runners.py b/Lib/asyncio/runners.py +index 0e63c34f60f..14397b4ad0c 100644 +--- a/Lib/asyncio/runners.py ++++ b/Lib/asyncio/runners.py +@@ -74,7 +74,7 @@ + loop.shutdown_default_executor(constants.THREAD_JOIN_TIMEOUT)) + finally: + if self._set_event_loop: +- events.set_event_loop(None) ++ events._set_event_loop(None) + loop.close() + self._loop = None + self._state = _State.CLOSED +@@ -147,7 +147,7 @@ + if not self._set_event_loop: + # Call set_event_loop only once to avoid calling + # attach_loop multiple times on child watchers +- events.set_event_loop(self._loop) ++ events._set_event_loop(self._loop) + self._set_event_loop = True + else: + self._loop = self._loop_factory() +@@ -177,6 +177,7 @@ + running in the same thread. + + If debug is True, the event loop will be run in debug mode. ++ If loop_factory is passed, it is used for new event loop creation. + + This function always creates a new event loop and closes it at the end. + It should be used as a main entry point for asyncio programs, and should +diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py +index f1ab9b12d69..22147451fa7 100644 +--- a/Lib/asyncio/selector_events.py ++++ b/Lib/asyncio/selector_events.py +@@ -180,9 +180,13 @@ + logger.debug("%r got a new connection from %r: %r", + server, addr, conn) + conn.setblocking(False) +- except (BlockingIOError, InterruptedError, ConnectionAbortedError): +- # Early exit because the socket accept buffer is empty. +- return None ++ except ConnectionAbortedError: ++ # Discard connections that were aborted before accept(). ++ continue ++ except (BlockingIOError, InterruptedError): ++ # Early exit because of a signal or ++ # the socket accept buffer is empty. ++ return + except OSError as exc: + # There's nowhere to send the error, so just log it. + if exc.errno in (errno.EMFILE, errno.ENFILE, +@@ -1181,10 +1185,13 @@ + return True + + def _call_connection_lost(self, exc): +- super()._call_connection_lost(exc) +- if self._empty_waiter is not None: +- self._empty_waiter.set_exception( +- ConnectionError("Connection is closed by peer")) ++ try: ++ super()._call_connection_lost(exc) ++ finally: ++ self._write_ready = None ++ if self._empty_waiter is not None: ++ self._empty_waiter.set_exception( ++ ConnectionError("Connection is closed by peer")) + + def _make_empty_waiter(self): + if self._empty_waiter is not None: +@@ -1199,7 +1206,6 @@ + + def close(self): + self._read_ready_cb = None +- self._write_ready = None + super().close() + + +diff --git a/Lib/asyncio/staggered.py b/Lib/asyncio/staggered.py +index 0f4df8855a8..2ad65d8648e 100644 +--- a/Lib/asyncio/staggered.py ++++ b/Lib/asyncio/staggered.py +@@ -8,6 +8,7 @@ + from . import exceptions as exceptions_mod + from . import locks + from . import tasks ++from . import futures + + + async def staggered_race(coro_fns, delay, *, loop=None): +@@ -63,11 +64,32 @@ + """ + # TODO: when we have aiter() and anext(), allow async iterables in coro_fns. + loop = loop or events.get_running_loop() ++ parent_task = tasks.current_task(loop) + enum_coro_fns = enumerate(coro_fns) + winner_result = None + winner_index = None ++ unhandled_exceptions = [] + exceptions = [] +- running_tasks = [] ++ running_tasks = set() ++ on_completed_fut = None ++ ++ def task_done(task): ++ running_tasks.discard(task) ++ futures.future_discard_from_awaited_by(task, parent_task) ++ if ( ++ on_completed_fut is not None ++ and not on_completed_fut.done() ++ and not running_tasks ++ ): ++ on_completed_fut.set_result(None) ++ ++ if task.cancelled(): ++ return ++ ++ exc = task.exception() ++ if exc is None: ++ return ++ unhandled_exceptions.append(exc) + + async def run_one_coro(ok_to_start, previous_failed) -> None: + # in eager tasks this waits for the calling task to append this task +@@ -91,11 +113,12 @@ + this_failed = locks.Event() + next_ok_to_start = locks.Event() + next_task = loop.create_task(run_one_coro(next_ok_to_start, this_failed)) +- running_tasks.append(next_task) ++ futures.future_add_to_awaited_by(next_task, parent_task) ++ running_tasks.add(next_task) ++ next_task.add_done_callback(task_done) + # next_task has been appended to running_tasks so next_task is ok to + # start. + next_ok_to_start.set() +- assert len(running_tasks) == this_index + 2 + # Prepare place to put this coroutine's exceptions if not won + exceptions.append(None) + assert len(exceptions) == this_index + 1 +@@ -120,31 +143,37 @@ + # up as done() == True, cancelled() == False, exception() == + # asyncio.CancelledError. This behavior is specified in + # https://bugs.python.org/issue30048 +- for i, t in enumerate(running_tasks): +- if i != this_index: ++ current_task = tasks.current_task(loop) ++ for t in running_tasks: ++ if t is not current_task: + t.cancel() + +- ok_to_start = locks.Event() +- first_task = loop.create_task(run_one_coro(ok_to_start, None)) +- running_tasks.append(first_task) +- # first_task has been appended to running_tasks so first_task is ok to start. +- ok_to_start.set() ++ propagate_cancellation_error = None + try: +- # Wait for a growing list of tasks to all finish: poor man's version of +- # curio's TaskGroup or trio's nursery +- done_count = 0 +- while done_count != len(running_tasks): +- done, _ = await tasks.wait(running_tasks) +- done_count = len(done) ++ ok_to_start = locks.Event() ++ first_task = loop.create_task(run_one_coro(ok_to_start, None)) ++ futures.future_add_to_awaited_by(first_task, parent_task) ++ running_tasks.add(first_task) ++ first_task.add_done_callback(task_done) ++ # first_task has been appended to running_tasks so first_task is ok to start. ++ ok_to_start.set() ++ propagate_cancellation_error = None ++ # Make sure no tasks are left running if we leave this function ++ while running_tasks: ++ on_completed_fut = loop.create_future() ++ try: ++ await on_completed_fut ++ except exceptions_mod.CancelledError as ex: ++ propagate_cancellation_error = ex ++ for task in running_tasks: ++ task.cancel(*ex.args) ++ on_completed_fut = None ++ if __debug__ and unhandled_exceptions: + # If run_one_coro raises an unhandled exception, it's probably a + # programming error, and I want to see it. +- if __debug__: +- for d in done: +- if d.done() and not d.cancelled() and d.exception(): +- raise d.exception() ++ raise ExceptionGroup("staggered race failed", unhandled_exceptions) ++ if propagate_cancellation_error is not None: ++ raise propagate_cancellation_error + return winner_result, winner_index, exceptions + finally: +- del exceptions +- # Make sure no tasks are left running if we leave this function +- for t in running_tasks: +- t.cancel() ++ del exceptions, propagate_cancellation_error, unhandled_exceptions, parent_task +diff --git a/Lib/asyncio/taskgroups.py b/Lib/asyncio/taskgroups.py +index 9fa772ca9d0..1633478d1c8 100644 +--- a/Lib/asyncio/taskgroups.py ++++ b/Lib/asyncio/taskgroups.py +@@ -6,6 +6,7 @@ + + from . import events + from . import exceptions ++from . import futures + from . import tasks + + +@@ -197,15 +198,20 @@ + else: + task = self._loop.create_task(coro, name=name, context=context) + +- # optimization: Immediately call the done callback if the task is ++ futures.future_add_to_awaited_by(task, self._parent_task) ++ ++ # Always schedule the done callback even if the task is + # already done (e.g. if the coro was able to complete eagerly), +- # and skip scheduling a done callback +- if task.done(): +- self._on_task_done(task) +- else: +- self._tasks.add(task) +- task.add_done_callback(self._on_task_done) +- return task ++ # otherwise if the task completes with an exception then it will cancel ++ # the current task too early. gh-128550, gh-128588 ++ self._tasks.add(task) ++ task.add_done_callback(self._on_task_done) ++ try: ++ return task ++ finally: ++ # gh-128552: prevent a refcycle of ++ # task.exception().__traceback__->TaskGroup.create_task->task ++ del task + + # Since Python 3.8 Tasks propagate all exceptions correctly, + # except for KeyboardInterrupt and SystemExit which are +@@ -225,6 +231,8 @@ + def _on_task_done(self, task): + self._tasks.discard(task) + ++ futures.future_discard_from_awaited_by(task, self._parent_task) ++ + if self._on_completed_fut is not None and not self._tasks: + if not self._on_completed_fut.done(): + self._on_completed_fut.set_result(True) +diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py +index 2112dd4b99d..2d931040e57 100644 +--- a/Lib/asyncio/tasks.py ++++ b/Lib/asyncio/tasks.py +@@ -245,23 +245,23 @@ + return self._num_cancels_requested + + def __eager_start(self): +- prev_task = _swap_current_task(self._loop, self) ++ prev_task = _py_swap_current_task(self._loop, self) + try: +- _register_eager_task(self) ++ _py_register_eager_task(self) + try: + self._context.run(self.__step_run_and_handle_result, None) + finally: +- _unregister_eager_task(self) ++ _py_unregister_eager_task(self) + finally: + try: +- curtask = _swap_current_task(self._loop, prev_task) ++ curtask = _py_swap_current_task(self._loop, prev_task) + assert curtask is self + finally: + if self.done(): + self._coro = None + self = None # Needed to break cycles when an exception occurs. + else: +- _register_task(self) ++ _py_register_task(self) + + def __step(self, exc=None): + if self.done(): +@@ -273,11 +273,11 @@ + self._must_cancel = False + self._fut_waiter = None + +- _enter_task(self._loop, self) ++ _py_enter_task(self._loop, self) + try: + self.__step_run_and_handle_result(exc) + finally: +- _leave_task(self._loop, self) ++ _py_leave_task(self._loop, self) + self = None # Needed to break cycles when an exception occurs. + + def __step_run_and_handle_result(self, exc): +@@ -322,6 +322,7 @@ + self._loop.call_soon( + self.__step, new_exc, context=self._context) + else: ++ futures.future_add_to_awaited_by(result, self) + result._asyncio_future_blocking = False + result.add_done_callback( + self.__wakeup, context=self._context) +@@ -356,6 +357,7 @@ + self = None # Needed to break cycles when an exception occurs. + + def __wakeup(self, future): ++ futures.future_discard_from_awaited_by(future, self) + try: + future.result() + except BaseException as exc: +@@ -502,6 +504,7 @@ + if timeout is not None: + timeout_handle = loop.call_later(timeout, _release_waiter, waiter) + counter = len(fs) ++ cur_task = current_task() + + def _on_completion(f): + nonlocal counter +@@ -514,9 +517,11 @@ + timeout_handle.cancel() + if not waiter.done(): + waiter.set_result(None) ++ futures.future_discard_from_awaited_by(f, cur_task) + + for f in fs: + f.add_done_callback(_on_completion) ++ futures.future_add_to_awaited_by(f, cur_task) + + try: + await waiter +@@ -802,10 +807,19 @@ + outer.set_result([]) + return outer + +- def _done_callback(fut): ++ loop = events._get_running_loop() ++ if loop is not None: ++ cur_task = current_task(loop) ++ else: ++ cur_task = None ++ ++ def _done_callback(fut, cur_task=cur_task): + nonlocal nfinished + nfinished += 1 + ++ if cur_task is not None: ++ futures.future_discard_from_awaited_by(fut, cur_task) ++ + if outer is None or outer.done(): + if not fut.cancelled(): + # Mark exception retrieved. +@@ -862,7 +876,6 @@ + nfuts = 0 + nfinished = 0 + done_futs = [] +- loop = None + outer = None # bpo-46672 + for arg in coros_or_futures: + if arg not in arg_to_fut: +@@ -875,12 +888,13 @@ + # can't control it, disable the "destroy pending task" + # warning. + fut._log_destroy_pending = False +- + nfuts += 1 + arg_to_fut[arg] = fut + if fut.done(): + done_futs.append(fut) + else: ++ if cur_task is not None: ++ futures.future_add_to_awaited_by(fut, cur_task) + fut.add_done_callback(_done_callback) + + else: +@@ -940,7 +954,15 @@ + loop = futures._get_loop(inner) + outer = loop.create_future() + +- def _inner_done_callback(inner): ++ if loop is not None and (cur_task := current_task(loop)) is not None: ++ futures.future_add_to_awaited_by(inner, cur_task) ++ else: ++ cur_task = None ++ ++ def _inner_done_callback(inner, cur_task=cur_task): ++ if cur_task is not None: ++ futures.future_discard_from_awaited_by(inner, cur_task) ++ + if outer.cancelled(): + if not inner.cancelled(): + # Mark inner's result as retrieved. +diff --git a/Lib/asyncio/timeouts.py b/Lib/asyncio/timeouts.py +index e6f5100691d..09342dc7c13 100644 +--- a/Lib/asyncio/timeouts.py ++++ b/Lib/asyncio/timeouts.py +@@ -1,7 +1,6 @@ + import enum + + from types import TracebackType +-from typing import final, Optional, Type + + from . import events + from . import exceptions +@@ -23,14 +22,13 @@ + EXITED = "finished" + + +-@final + class Timeout: + """Asynchronous context manager for cancelling overdue coroutines. + + Use `timeout()` or `timeout_at()` rather than instantiating this class directly. + """ + +- def __init__(self, when: Optional[float]) -> None: ++ def __init__(self, when: float | None) -> None: + """Schedule a timeout that will trigger at a given loop time. + + - If `when` is `None`, the timeout will never trigger. +@@ -39,15 +37,15 @@ + """ + self._state = _State.CREATED + +- self._timeout_handler: Optional[events.TimerHandle] = None +- self._task: Optional[tasks.Task] = None ++ self._timeout_handler: events.TimerHandle | None = None ++ self._task: tasks.Task | None = None + self._when = when + +- def when(self) -> Optional[float]: ++ def when(self) -> float | None: + """Return the current deadline.""" + return self._when + +- def reschedule(self, when: Optional[float]) -> None: ++ def reschedule(self, when: float | None) -> None: + """Reschedule the timeout.""" + if self._state is not _State.ENTERED: + if self._state is _State.CREATED: +@@ -96,10 +94,10 @@ + + async def __aexit__( + self, +- exc_type: Optional[Type[BaseException]], +- exc_val: Optional[BaseException], +- exc_tb: Optional[TracebackType], +- ) -> Optional[bool]: ++ exc_type: type[BaseException] | None, ++ exc_val: BaseException | None, ++ exc_tb: TracebackType | None, ++ ) -> bool | None: + assert self._state in (_State.ENTERED, _State.EXPIRING) + + if self._timeout_handler is not None: +@@ -142,7 +140,7 @@ + exc_val = exc_val.__context__ + + +-def timeout(delay: Optional[float]) -> Timeout: ++def timeout(delay: float | None) -> Timeout: + """Timeout async context manager. + + Useful in cases when you want to apply timeout logic around block +@@ -162,7 +160,7 @@ + return Timeout(loop.time() + delay if delay is not None else None) + + +-def timeout_at(when: Optional[float]) -> Timeout: ++def timeout_at(when: float | None) -> Timeout: + """Schedule the timeout at absolute time. + + Like timeout() but argument gives absolute time in the same clock system +diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py +index 0227eb506c6..f69c6a64c39 100644 +--- a/Lib/asyncio/unix_events.py ++++ b/Lib/asyncio/unix_events.py +@@ -28,7 +28,7 @@ + + __all__ = ( + 'SelectorEventLoop', +- 'DefaultEventLoopPolicy', ++ '_DefaultEventLoopPolicy', + 'EventLoop', + ) + +@@ -963,11 +963,11 @@ + return True + + +-class _UnixDefaultEventLoopPolicy(events.BaseDefaultEventLoopPolicy): ++class _UnixDefaultEventLoopPolicy(events._BaseDefaultEventLoopPolicy): + """UNIX event loop policy""" + _loop_factory = _UnixSelectorEventLoop + + + SelectorEventLoop = _UnixSelectorEventLoop +-DefaultEventLoopPolicy = _UnixDefaultEventLoopPolicy ++_DefaultEventLoopPolicy = _UnixDefaultEventLoopPolicy + EventLoop = SelectorEventLoop +diff --git a/Lib/asyncio/windows_events.py b/Lib/asyncio/windows_events.py +index bf99bc271c7..5f75b17d8ca 100644 +--- a/Lib/asyncio/windows_events.py ++++ b/Lib/asyncio/windows_events.py +@@ -29,8 +29,8 @@ + + __all__ = ( + 'SelectorEventLoop', 'ProactorEventLoop', 'IocpProactor', +- 'DefaultEventLoopPolicy', 'WindowsSelectorEventLoopPolicy', +- 'WindowsProactorEventLoopPolicy', 'EventLoop', ++ '_DefaultEventLoopPolicy', '_WindowsSelectorEventLoopPolicy', ++ '_WindowsProactorEventLoopPolicy', 'EventLoop', + ) + + +@@ -891,13 +891,13 @@ + SelectorEventLoop = _WindowsSelectorEventLoop + + +-class WindowsSelectorEventLoopPolicy(events.BaseDefaultEventLoopPolicy): ++class _WindowsSelectorEventLoopPolicy(events._BaseDefaultEventLoopPolicy): + _loop_factory = SelectorEventLoop + + +-class WindowsProactorEventLoopPolicy(events.BaseDefaultEventLoopPolicy): ++class _WindowsProactorEventLoopPolicy(events._BaseDefaultEventLoopPolicy): + _loop_factory = ProactorEventLoop + + +-DefaultEventLoopPolicy = WindowsProactorEventLoopPolicy ++_DefaultEventLoopPolicy = _WindowsProactorEventLoopPolicy + EventLoop = ProactorEventLoop +diff --git a/Lib/base64.py b/Lib/base64.py +index 61be4fb856e..5d78cc09f40 100644 +--- a/Lib/base64.py ++++ b/Lib/base64.py +@@ -4,7 +4,6 @@ + # Modified 30-Dec-2003 by Barry Warsaw to add full RFC 3548 support + # Modified 22-May-2007 by Guido van Rossum to use bytes everywhere + +-import re + import struct + import binascii + +@@ -284,7 +283,7 @@ + s = _bytes_from_decode_data(s) + if casefold: + s = s.upper() +- if re.search(b'[^0-9A-F]', s): ++ if s.translate(None, delete=b'0123456789ABCDEF'): + raise binascii.Error('Non-base16 digit found') + return binascii.unhexlify(s) + +diff --git a/Lib/bdb.py b/Lib/bdb.py +index 81bba8a130f..a741628e32a 100644 +--- a/Lib/bdb.py ++++ b/Lib/bdb.py +@@ -4,6 +4,7 @@ + import sys + import os + import weakref ++from contextlib import contextmanager + from inspect import CO_GENERATOR, CO_COROUTINE, CO_ASYNC_GENERATOR + + __all__ = ["BdbQuit", "Bdb", "Breakpoint"] +@@ -65,6 +66,12 @@ + self.botframe = None + self._set_stopinfo(None, None) + ++ @contextmanager ++ def set_enterframe(self, frame): ++ self.enterframe = frame ++ yield ++ self.enterframe = None ++ + def trace_dispatch(self, frame, event, arg): + """Dispatch a trace function for debugged frames based on the event. + +@@ -90,28 +97,27 @@ + The arg parameter depends on the previous event. + """ + +- self.enterframe = frame +- +- if self.quitting: +- return # None +- if event == 'line': +- return self.dispatch_line(frame) +- if event == 'call': +- return self.dispatch_call(frame, arg) +- if event == 'return': +- return self.dispatch_return(frame, arg) +- if event == 'exception': +- return self.dispatch_exception(frame, arg) +- if event == 'c_call': +- return self.trace_dispatch +- if event == 'c_exception': +- return self.trace_dispatch +- if event == 'c_return': ++ with self.set_enterframe(frame): ++ if self.quitting: ++ return # None ++ if event == 'line': ++ return self.dispatch_line(frame) ++ if event == 'call': ++ return self.dispatch_call(frame, arg) ++ if event == 'return': ++ return self.dispatch_return(frame, arg) ++ if event == 'exception': ++ return self.dispatch_exception(frame, arg) ++ if event == 'c_call': ++ return self.trace_dispatch ++ if event == 'c_exception': ++ return self.trace_dispatch ++ if event == 'c_return': ++ return self.trace_dispatch ++ if event == 'opcode': ++ return self.dispatch_opcode(frame, arg) ++ print('bdb.Bdb.dispatch: unknown debugging event:', repr(event)) + return self.trace_dispatch +- if event == 'opcode': +- return self.dispatch_opcode(frame, arg) +- print('bdb.Bdb.dispatch: unknown debugging event:', repr(event)) +- return self.trace_dispatch + + def dispatch_line(self, frame): + """Invoke user function and return trace function for line event. +@@ -395,15 +401,15 @@ + if frame is None: + frame = sys._getframe().f_back + self.reset() +- self.enterframe = frame +- while frame: +- frame.f_trace = self.trace_dispatch +- self.botframe = frame +- self.frame_trace_lines_opcodes[frame] = (frame.f_trace_lines, frame.f_trace_opcodes) +- # We need f_trace_lines == True for the debugger to work +- frame.f_trace_lines = True +- frame = frame.f_back +- self.set_stepinstr() ++ with self.set_enterframe(frame): ++ while frame: ++ frame.f_trace = self.trace_dispatch ++ self.botframe = frame ++ self.frame_trace_lines_opcodes[frame] = (frame.f_trace_lines, frame.f_trace_opcodes) ++ # We need f_trace_lines == True for the debugger to work ++ frame.f_trace_lines = True ++ frame = frame.f_back ++ self.set_stepinstr() + sys.settrace(self.trace_dispatch) + + def set_continue(self): +diff --git a/Lib/calendar.py b/Lib/calendar.py +index 8c1c646da46..1105a705a80 100644 +--- a/Lib/calendar.py ++++ b/Lib/calendar.py +@@ -428,6 +428,7 @@ + headers = (header for k in months) + a(formatstring(headers, colwidth, c).rstrip()) + a('\n'*l) ++ + # max number of weeks for this row + height = max(len(cal) for cal in row) + for j in range(height): +@@ -646,6 +647,111 @@ + with different_locale(self.locale): + return super().formatmonthname(theyear, themonth, withyear) + ++ ++class _CLIDemoCalendar(LocaleTextCalendar): ++ 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): ++ """ ++ Returns a single week in a string (no newline). ++ """ ++ if highlight_day: ++ from _colorize import get_colors ++ ++ ansi = get_colors() ++ highlight = f"{ansi.BLACK}{ansi.BACKGROUND_YELLOW}" ++ reset = ansi.RESET ++ else: ++ highlight = reset = "" ++ ++ return ' '.join( ++ ( ++ f"{highlight}{self.formatday(d, wd, width)}{reset}" ++ if d == highlight_day ++ else self.formatday(d, wd, width) ++ ) ++ for (d, wd) in theweek ++ ) ++ ++ def formatmonth(self, theyear, themonth, w=0, l=0): ++ """ ++ Return a month's calendar string (multi-line). ++ """ ++ if ( ++ self.highlight_day ++ and self.highlight_day.year == theyear ++ and self.highlight_day.month == themonth ++ ): ++ highlight_day = self.highlight_day.day ++ else: ++ highlight_day = None ++ w = max(2, w) ++ l = max(1, l) ++ s = self.formatmonthname(theyear, themonth, 7 * (w + 1) - 1) ++ s = s.rstrip() ++ s += '\n' * l ++ s += self.formatweekheader(w).rstrip() ++ s += '\n' * l ++ for week in self.monthdays2calendar(theyear, themonth): ++ s += self.formatweek(week, w, highlight_day=highlight_day).rstrip() ++ s += '\n' * l ++ return s ++ ++ def formatyear(self, theyear, w=2, l=1, c=6, m=3): ++ """ ++ Returns a year's calendar as a multi-line string. ++ """ ++ w = max(2, w) ++ l = max(1, l) ++ c = max(2, c) ++ colwidth = (w + 1) * 7 - 1 ++ v = [] ++ a = v.append ++ a(repr(theyear).center(colwidth*m+c*(m-1)).rstrip()) ++ a('\n'*l) ++ header = self.formatweekheader(w) ++ for (i, row) in enumerate(self.yeardays2calendar(theyear, m)): ++ # months in this row ++ months = range(m*i+1, min(m*(i+1)+1, 13)) ++ a('\n'*l) ++ names = (self.formatmonthname(theyear, k, colwidth, False) ++ for k in months) ++ a(formatstring(names, colwidth, c).rstrip()) ++ a('\n'*l) ++ headers = (header for k in months) ++ a(formatstring(headers, colwidth, c).rstrip()) ++ a('\n'*l) ++ ++ if ( ++ self.highlight_day ++ and self.highlight_day.year == theyear ++ and self.highlight_day.month in months ++ ): ++ month_pos = months.index(self.highlight_day.month) ++ else: ++ month_pos = None ++ ++ # max number of weeks for this row ++ height = max(len(cal) for cal in row) ++ for j in range(height): ++ weeks = [] ++ for k, cal in enumerate(row): ++ if j >= len(cal): ++ weeks.append('') ++ else: ++ day = ( ++ self.highlight_day.day if k == month_pos else None ++ ) ++ weeks.append( ++ self.formatweek(cal[j], w, highlight_day=day) ++ ) ++ a(formatstring(weeks, colwidth, c).rstrip()) ++ a('\n' * l) ++ return ''.join(v) ++ ++ + # Support for old module level interface + c = TextCalendar() + +@@ -765,6 +871,7 @@ + sys.exit(1) + + locale = options.locale, options.encoding ++ today = datetime.date.today() + + if options.type == "html": + if options.month: +@@ -781,23 +888,23 @@ + optdict = dict(encoding=encoding, css=options.css) + write = sys.stdout.buffer.write + if options.year is None: +- write(cal.formatyearpage(datetime.date.today().year, **optdict)) ++ write(cal.formatyearpage(today.year, **optdict)) + else: + write(cal.formatyearpage(options.year, **optdict)) + else: + if options.locale: +- cal = LocaleTextCalendar(locale=locale) ++ cal = _CLIDemoCalendar(highlight_day=today, locale=locale) + else: +- cal = TextCalendar() ++ cal = _CLIDemoCalendar(highlight_day=today) + cal.setfirstweekday(options.first_weekday) + optdict = dict(w=options.width, l=options.lines) + if options.month is None: + optdict["c"] = options.spacing + optdict["m"] = options.months +- if options.month is not None: ++ else: + _validate_month(options.month) + if options.year is None: +- result = cal.formatyear(datetime.date.today().year, **optdict) ++ result = cal.formatyear(today.year, **optdict) + elif options.month is None: + result = cal.formatyear(options.year, **optdict) + else: +diff --git a/Lib/configparser.py b/Lib/configparser.py +index 420dce77c23..9dc4fa515cf 100644 +--- a/Lib/configparser.py ++++ b/Lib/configparser.py +@@ -1105,11 +1105,7 @@ + def _handle_rest(self, st, line, fpname): + # a section header or option header? + if self._allow_unnamed_section and st.cursect is None: +- st.sectname = UNNAMED_SECTION +- st.cursect = self._dict() +- self._sections[st.sectname] = st.cursect +- self._proxies[st.sectname] = SectionProxy(self, st.sectname) +- st.elements_added.add(st.sectname) ++ self._handle_header(st, UNNAMED_SECTION, fpname) + + st.indent_level = st.cur_indent_level + # is it a section header? +@@ -1118,10 +1114,10 @@ + if not mo and st.cursect is None: + raise MissingSectionHeaderError(fpname, st.lineno, line) + +- self._handle_header(st, mo, fpname) if mo else self._handle_option(st, line, fpname) ++ self._handle_header(st, mo.group('header'), fpname) if mo else self._handle_option(st, line, fpname) + +- def _handle_header(self, st, mo, fpname): +- st.sectname = mo.group('header') ++ def _handle_header(self, st, sectname, fpname): ++ st.sectname = sectname + if st.sectname in self._sections: + if self._strict and st.sectname in st.elements_added: + raise DuplicateSectionError(st.sectname, fpname, +diff --git a/Lib/copy.py b/Lib/copy.py +index f27e109973c..c64fc076179 100644 +--- a/Lib/copy.py ++++ b/Lib/copy.py +@@ -67,13 +67,15 @@ + + cls = type(x) + +- copier = _copy_dispatch.get(cls) +- if copier: +- return copier(x) ++ if cls in _copy_atomic_types: ++ return x ++ if cls in _copy_builtin_containers: ++ return cls.copy(x) ++ + + if issubclass(cls, type): + # treat it as a regular class: +- return _copy_immutable(x) ++ return x + + copier = getattr(cls, "__copy__", None) + if copier is not None: +@@ -98,23 +100,12 @@ + return _reconstruct(x, None, *rv) + + +-_copy_dispatch = d = {} +- +-def _copy_immutable(x): +- return x +-for t in (types.NoneType, int, float, bool, complex, str, tuple, ++_copy_atomic_types = {types.NoneType, int, float, bool, complex, str, tuple, + bytes, frozenset, type, range, slice, property, + types.BuiltinFunctionType, types.EllipsisType, + types.NotImplementedType, types.FunctionType, types.CodeType, +- weakref.ref, super): +- d[t] = _copy_immutable +- +-d[list] = list.copy +-d[dict] = dict.copy +-d[set] = set.copy +-d[bytearray] = bytearray.copy +- +-del d, t ++ weakref.ref, super} ++_copy_builtin_containers = {list, dict, set, bytearray} + + def deepcopy(x, memo=None, _nil=[]): + """Deep copy operation on arbitrary Python objects. +diff --git a/Lib/csv.py b/Lib/csv.py +index cd202659873..0a627ba7a51 100644 +--- a/Lib/csv.py ++++ b/Lib/csv.py +@@ -63,7 +63,6 @@ + written as two quotes + """ + +-import re + import types + from _csv import Error, writer, reader, register_dialect, \ + unregister_dialect, get_dialect, list_dialects, \ +@@ -281,6 +280,7 @@ + If there is no quotechar the delimiter can't be determined + this way. + """ ++ import re + + matches = [] + for restr in (r'(?P[^\w\n"\'])(?P ?)(?P["\']).*?(?P=quote)(?P=delim)', # ,".*?", +diff --git a/Lib/ctypes/__init__.py b/Lib/ctypes/__init__.py +index 2f2b0ca9f38..8e2a2926f7a 100644 +--- a/Lib/ctypes/__init__.py ++++ b/Lib/ctypes/__init__.py +@@ -524,6 +524,7 @@ + # functions + + from _ctypes import _memmove_addr, _memset_addr, _string_at_addr, _cast_addr ++from _ctypes import _memoryview_at_addr + + ## void *memmove(void *, const void *, size_t); + memmove = CFUNCTYPE(c_void_p, c_void_p, c_void_p, c_size_t)(_memmove_addr) +@@ -549,6 +550,14 @@ + Return the byte string at void *ptr.""" + return _string_at(ptr, size) + ++_memoryview_at = PYFUNCTYPE( ++ py_object, c_void_p, c_ssize_t, c_int)(_memoryview_at_addr) ++def memoryview_at(ptr, size, readonly=False): ++ """memoryview_at(ptr, size[, readonly]) -> memoryview ++ ++ Return a memoryview representing the memory at void *ptr.""" ++ return _memoryview_at(ptr, size, bool(readonly)) ++ + try: + from _ctypes import _wstring_at_addr + except ImportError: +diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py +index 117bf06cb01..99504911a3d 100644 +--- a/Lib/ctypes/util.py ++++ b/Lib/ctypes/util.py +@@ -67,6 +67,65 @@ + return fname + return None + ++ # Listing loaded DLLs on Windows relies on the following APIs: ++ # https://learn.microsoft.com/windows/win32/api/psapi/nf-psapi-enumprocessmodules ++ # https://learn.microsoft.com/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulefilenamew ++ import ctypes ++ from ctypes import wintypes ++ ++ _kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) ++ _get_current_process = _kernel32["GetCurrentProcess"] ++ _get_current_process.restype = wintypes.HANDLE ++ ++ _k32_get_module_file_name = _kernel32["GetModuleFileNameW"] ++ _k32_get_module_file_name.restype = wintypes.DWORD ++ _k32_get_module_file_name.argtypes = ( ++ wintypes.HMODULE, ++ wintypes.LPWSTR, ++ wintypes.DWORD, ++ ) ++ ++ _psapi = ctypes.WinDLL('psapi', use_last_error=True) ++ _enum_process_modules = _psapi["EnumProcessModules"] ++ _enum_process_modules.restype = wintypes.BOOL ++ _enum_process_modules.argtypes = ( ++ wintypes.HANDLE, ++ ctypes.POINTER(wintypes.HMODULE), ++ wintypes.DWORD, ++ wintypes.LPDWORD, ++ ) ++ ++ def _get_module_filename(module: wintypes.HMODULE): ++ name = (wintypes.WCHAR * 32767)() # UNICODE_STRING_MAX_CHARS ++ if _k32_get_module_file_name(module, name, len(name)): ++ return name.value ++ return None ++ ++ ++ def _get_module_handles(): ++ process = _get_current_process() ++ space_needed = wintypes.DWORD() ++ n = 1024 ++ while True: ++ modules = (wintypes.HMODULE * n)() ++ if not _enum_process_modules(process, ++ modules, ++ ctypes.sizeof(modules), ++ ctypes.byref(space_needed)): ++ err = ctypes.get_last_error() ++ msg = ctypes.FormatError(err).strip() ++ raise ctypes.WinError(err, f"EnumProcessModules failed: {msg}") ++ n = space_needed.value // ctypes.sizeof(wintypes.HMODULE) ++ if n <= len(modules): ++ return modules[:n] ++ ++ def dllist(): ++ """Return a list of loaded shared libraries in the current process.""" ++ modules = _get_module_handles() ++ libraries = [name for h in modules ++ if (name := _get_module_filename(h)) is not None] ++ return libraries ++ + elif os.name == "posix" and sys.platform in {"darwin", "ios", "tvos", "watchos"}: + from ctypes.macholib.dyld import dyld_find as _dyld_find + def find_library(name): +@@ -80,6 +139,22 @@ + continue + return None + ++ # Listing loaded libraries on Apple systems relies on the following API: ++ # https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dyld.3.html ++ import ctypes ++ ++ _libc = ctypes.CDLL(find_library("c")) ++ _dyld_get_image_name = _libc["_dyld_get_image_name"] ++ _dyld_get_image_name.restype = ctypes.c_char_p ++ ++ def dllist(): ++ """Return a list of loaded shared libraries in the current process.""" ++ num_images = _libc._dyld_image_count() ++ libraries = [os.fsdecode(name) for i in range(num_images) ++ if (name := _dyld_get_image_name(i)) is not None] ++ ++ return libraries ++ + elif sys.platform.startswith("aix"): + # AIX has two styles of storing shared libraries + # GNU auto_tools refer to these as svr4 and aix +@@ -341,6 +416,55 @@ + return _findSoname_ldconfig(name) or \ + _get_soname(_findLib_gcc(name)) or _get_soname(_findLib_ld(name)) + ++ ++# Listing loaded libraries on other systems will try to use ++# functions common to Linux and a few other Unix-like systems. ++# See the following for several platforms' documentation of the same API: ++# https://man7.org/linux/man-pages/man3/dl_iterate_phdr.3.html ++# https://man.freebsd.org/cgi/man.cgi?query=dl_iterate_phdr ++# https://man.openbsd.org/dl_iterate_phdr ++# https://docs.oracle.com/cd/E88353_01/html/E37843/dl-iterate-phdr-3c.html ++if (os.name == "posix" and ++ sys.platform not in {"darwin", "ios", "tvos", "watchos"}): ++ import ctypes ++ if hasattr((_libc := ctypes.CDLL(None)), "dl_iterate_phdr"): ++ ++ class _dl_phdr_info(ctypes.Structure): ++ _fields_ = [ ++ ("dlpi_addr", ctypes.c_void_p), ++ ("dlpi_name", ctypes.c_char_p), ++ ("dlpi_phdr", ctypes.c_void_p), ++ ("dlpi_phnum", ctypes.c_ushort), ++ ] ++ ++ _dl_phdr_callback = ctypes.CFUNCTYPE( ++ ctypes.c_int, ++ ctypes.POINTER(_dl_phdr_info), ++ ctypes.c_size_t, ++ ctypes.POINTER(ctypes.py_object), ++ ) ++ ++ @_dl_phdr_callback ++ def _info_callback(info, _size, data): ++ libraries = data.contents.value ++ name = os.fsdecode(info.contents.dlpi_name) ++ libraries.append(name) ++ return 0 ++ ++ _dl_iterate_phdr = _libc["dl_iterate_phdr"] ++ _dl_iterate_phdr.argtypes = [ ++ _dl_phdr_callback, ++ ctypes.POINTER(ctypes.py_object), ++ ] ++ _dl_iterate_phdr.restype = ctypes.c_int ++ ++ def dllist(): ++ """Return a list of loaded shared libraries in the current process.""" ++ libraries = [] ++ _dl_iterate_phdr(_info_callback, ++ ctypes.byref(ctypes.py_object(libraries))) ++ return libraries ++ + ################################################################ + # test code + +@@ -384,5 +508,12 @@ + print(cdll.LoadLibrary("libcrypt.so")) + print(find_library("crypt")) + ++ try: ++ dllist ++ except NameError: ++ print('dllist() not available') ++ else: ++ print(dllist()) ++ + if __name__ == "__main__": + test() +diff --git a/Lib/difflib.py b/Lib/difflib.py +index 7f595b6c72e..c124afdd039 100644 +--- a/Lib/difflib.py ++++ b/Lib/difflib.py +@@ -1632,13 +1632,22 @@ + """ + + _styles = """ ++ :root {color-scheme: light dark} + table.diff {font-family:Courier; border:medium;} + .diff_header {background-color:#e0e0e0} + td.diff_header {text-align:right} + .diff_next {background-color:#c0c0c0} +- .diff_add {background-color:#aaffaa} ++ .diff_add {background-color:palegreen} + .diff_chg {background-color:#ffff77} +- .diff_sub {background-color:#ffaaaa}""" ++ .diff_sub {background-color:#ffaaaa} ++ ++ @media (prefers-color-scheme: dark) { ++ .diff_header {background-color:#666} ++ .diff_next {background-color:#393939} ++ .diff_add {background-color:darkgreen} ++ .diff_chg {background-color:#847415} ++ .diff_sub {background-color:darkred} ++ }""" + + _table_template = """ + [ \t]+) | # spaces and horizontal tabs +- (?P[0-9]+\b) | # decimal integer +- (?Pn\b) | # only n is allowed +- (?P[()]) | +- (?P[-*/%+?:]|[>, +- # <=, >=, ==, !=, &&, ||, +- # ? : +- # unary and bitwise ops +- # not allowed +- (?P\w+|.) # invalid token +- """, re.VERBOSE|re.DOTALL) +- ++_token_pattern = None + + def _tokenize(plural): +- for mo in re.finditer(_token_pattern, plural): ++ global _token_pattern ++ if _token_pattern is None: ++ import re ++ _token_pattern = re.compile(r""" ++ (?P[ \t]+) | # spaces and horizontal tabs ++ (?P[0-9]+\b) | # decimal integer ++ (?Pn\b) | # only n is allowed ++ (?P[()]) | ++ (?P[-*/%+?:]|[>, ++ # <=, >=, ==, !=, &&, ||, ++ # ? : ++ # unary and bitwise ops ++ # not allowed ++ (?P\w+|.) # invalid token ++ """, re.VERBOSE|re.DOTALL) ++ ++ for mo in _token_pattern.finditer(plural): + kind = mo.lastgroup + if kind == 'WHITESPACES': + continue +diff --git a/Lib/glob.py b/Lib/glob.py +index 690ab1b8b9f..cd8859e6331 100644 +--- a/Lib/glob.py ++++ b/Lib/glob.py +@@ -348,13 +348,7 @@ + + @staticmethod + def scandir(path): +- """Implements os.scandir(). +- """ +- raise NotImplementedError +- +- @staticmethod +- def add_slash(path): +- """Returns a path with a trailing slash added. ++ """Like os.scandir(), but generates (entry, name, path) tuples. + """ + raise NotImplementedError + +@@ -389,10 +383,12 @@ + def special_selector(self, part, parts): + """Returns a function that selects special children of the given path. + """ ++ if parts: ++ part += self.sep + select_next = self.selector(parts) + + def select_special(path, exists=False): +- path = self.concat_path(self.add_slash(path), part) ++ path = self.concat_path(path, part) + return select_next(path, exists) + return select_special + +@@ -402,14 +398,16 @@ + + # Optimization: consume and join any subsequent literal parts here, + # rather than leaving them for the next selector. This reduces the +- # number of string concatenation operations and calls to add_slash(). ++ # number of string concatenation operations. + while parts and magic_check.search(parts[-1]) is None: + part += self.sep + parts.pop() ++ if parts: ++ part += self.sep + + select_next = self.selector(parts) + + def select_literal(path, exists=False): +- path = self.concat_path(self.add_slash(path), part) ++ path = self.concat_path(path, part) + return select_next(path, exists=False) + return select_literal + +@@ -425,24 +423,19 @@ + + def select_wildcard(path, exists=False): + try: +- # We must close the scandir() object before proceeding to +- # avoid exhausting file descriptors when globbing deep trees. +- with self.scandir(path) as scandir_it: +- entries = list(scandir_it) ++ entries = self.scandir(path) + except OSError: + pass + else: +- prefix = self.add_slash(path) +- for entry in entries: +- if match is None or match(entry.name): ++ for entry, entry_name, entry_path in entries: ++ if match is None or match(entry_name): + if dir_only: + try: + if not entry.is_dir(): + continue + except OSError: + continue +- entry_path = self.concat_path(prefix, entry.name) +- if dir_only: ++ entry_path = self.concat_path(entry_path, self.sep) + yield from select_next(entry_path, exists=True) + else: + yield entry_path +@@ -472,7 +465,6 @@ + select_next = self.selector(parts) + + def select_recursive(path, exists=False): +- path = self.add_slash(path) + match_pos = len(str(path)) + if match is None or match(str(path), match_pos): + yield from select_next(path, exists) +@@ -483,15 +475,11 @@ + def select_recursive_step(stack, match_pos): + path = stack.pop() + try: +- # We must close the scandir() object before proceeding to +- # avoid exhausting file descriptors when globbing deep trees. +- with self.scandir(path) as scandir_it: +- entries = list(scandir_it) ++ entries = self.scandir(path) + except OSError: + pass + else: +- prefix = self.add_slash(path) +- for entry in entries: ++ for entry, _entry_name, entry_path in entries: + is_dir = False + try: + if entry.is_dir(follow_symlinks=follow_symlinks): +@@ -500,8 +488,10 @@ + pass + + if is_dir or not dir_only: +- entry_path = self.concat_path(prefix, entry.name) +- if match is None or match(str(entry_path), match_pos): ++ entry_path_str = str(entry_path) ++ if dir_only: ++ entry_path = self.concat_path(entry_path, self.sep) ++ if match is None or match(entry_path_str, match_pos): + if dir_only: + yield from select_next(entry_path, exists=True) + else: +@@ -528,19 +518,27 @@ + """Provides shell-style pattern matching and globbing for string paths. + """ + lexists = staticmethod(os.path.lexists) +- scandir = staticmethod(os.scandir) + concat_path = operator.add + +- if os.name == 'nt': +- @staticmethod +- def add_slash(pathname): +- tail = os.path.splitroot(pathname)[2] +- if not tail or tail[-1] in '\\/': +- return pathname +- return f'{pathname}\\' +- else: +- @staticmethod +- def add_slash(pathname): +- if not pathname or pathname[-1] == '/': +- return pathname +- return f'{pathname}/' ++ @staticmethod ++ def scandir(path): ++ # We must close the scandir() object before proceeding to ++ # avoid exhausting file descriptors when globbing deep trees. ++ with os.scandir(path) as scandir_it: ++ entries = list(scandir_it) ++ return ((entry, entry.name, entry.path) for entry in entries) ++ ++ ++class _PathGlobber(_GlobberBase): ++ """Provides shell-style pattern matching and globbing for pathlib paths. ++ """ ++ ++ lexists = operator.methodcaller('exists', follow_symlinks=False) ++ ++ @staticmethod ++ def scandir(path): ++ return ((child.info, child.name, child) for child in path.iterdir()) ++ ++ @staticmethod ++ def concat_path(path, text): ++ return path.with_segments(str(path) + text) +diff --git a/Lib/graphlib.py b/Lib/graphlib.py +index 1438a5fc54b..82f33fb5cf3 100644 +--- a/Lib/graphlib.py ++++ b/Lib/graphlib.py +@@ -154,7 +154,7 @@ + This method unblocks any successor of each node in *nodes* for being returned + in the future by a call to "get_ready". + +- Raises :exec:`ValueError` if any node in *nodes* has already been marked as ++ Raises ValueError if any node in *nodes* has already been marked as + processed by a previous call to this method, if a node was not added to the + graph by using "add" or if called without calling "prepare" previously or if + node has not yet been returned by "get_ready". +diff --git a/Lib/http/__init__.py b/Lib/http/__init__.py +index d64741ec0dd..691b4a9a367 100644 +--- a/Lib/http/__init__.py ++++ b/Lib/http/__init__.py +@@ -54,8 +54,9 @@ + CONTINUE = 100, 'Continue', 'Request received, please continue' + SWITCHING_PROTOCOLS = (101, 'Switching Protocols', + 'Switching to new protocol; obey Upgrade header') +- PROCESSING = 102, 'Processing' +- EARLY_HINTS = 103, 'Early Hints' ++ PROCESSING = 102, 'Processing', 'Server is processing the request' ++ EARLY_HINTS = (103, 'Early Hints', ++ 'Headers sent to prepare for the response') + + # success + OK = 200, 'OK', 'Request fulfilled, document follows' +@@ -67,9 +68,11 @@ + NO_CONTENT = 204, 'No Content', 'Request fulfilled, nothing follows' + RESET_CONTENT = 205, 'Reset Content', 'Clear input form for further input' + PARTIAL_CONTENT = 206, 'Partial Content', 'Partial content follows' +- MULTI_STATUS = 207, 'Multi-Status' +- ALREADY_REPORTED = 208, 'Already Reported' +- IM_USED = 226, 'IM Used' ++ MULTI_STATUS = (207, 'Multi-Status', ++ 'Response contains multiple statuses in the body') ++ ALREADY_REPORTED = (208, 'Already Reported', ++ 'Operation has already been reported') ++ IM_USED = 226, 'IM Used', 'Request completed using instance manipulations' + + # redirection + MULTIPLE_CHOICES = (300, 'Multiple Choices', +@@ -128,15 +131,19 @@ + EXPECTATION_FAILED = (417, 'Expectation Failed', + 'Expect condition could not be satisfied') + IM_A_TEAPOT = (418, 'I\'m a Teapot', +- 'Server refuses to brew coffee because it is a teapot.') ++ 'Server refuses to brew coffee because it is a teapot') + MISDIRECTED_REQUEST = (421, 'Misdirected Request', + 'Server is not able to produce a response') +- UNPROCESSABLE_CONTENT = 422, 'Unprocessable Content' ++ UNPROCESSABLE_CONTENT = (422, 'Unprocessable Content', ++ 'Server is not able to process the contained instructions') + UNPROCESSABLE_ENTITY = UNPROCESSABLE_CONTENT +- LOCKED = 423, 'Locked' +- FAILED_DEPENDENCY = 424, 'Failed Dependency' +- TOO_EARLY = 425, 'Too Early' +- UPGRADE_REQUIRED = 426, 'Upgrade Required' ++ LOCKED = 423, 'Locked', 'Resource of a method is locked' ++ FAILED_DEPENDENCY = (424, 'Failed Dependency', ++ 'Dependent action of the request failed') ++ TOO_EARLY = (425, 'Too Early', ++ 'Server refuses to process a request that might be replayed') ++ UPGRADE_REQUIRED = (426, 'Upgrade Required', ++ 'Server refuses to perform the request using the current protocol') + PRECONDITION_REQUIRED = (428, 'Precondition Required', + 'The origin server requires the request to be conditional') + TOO_MANY_REQUESTS = (429, 'Too Many Requests', +@@ -164,10 +171,14 @@ + 'The gateway server did not receive a timely response') + HTTP_VERSION_NOT_SUPPORTED = (505, 'HTTP Version Not Supported', + 'Cannot fulfill request') +- VARIANT_ALSO_NEGOTIATES = 506, 'Variant Also Negotiates' +- INSUFFICIENT_STORAGE = 507, 'Insufficient Storage' +- LOOP_DETECTED = 508, 'Loop Detected' +- NOT_EXTENDED = 510, 'Not Extended' ++ VARIANT_ALSO_NEGOTIATES = (506, 'Variant Also Negotiates', ++ 'Server has an internal configuration error') ++ INSUFFICIENT_STORAGE = (507, 'Insufficient Storage', ++ 'Server is not able to store the representation') ++ LOOP_DETECTED = (508, 'Loop Detected', ++ 'Server encountered an infinite loop while processing a request') ++ NOT_EXTENDED = (510, 'Not Extended', ++ 'Request does not meet the resource access policy') + NETWORK_AUTHENTICATION_REQUIRED = (511, + 'Network Authentication Required', + 'The client needs to authenticate to gain network access') +@@ -179,7 +190,7 @@ + + Methods from the following RFCs are all observed: + +- * RFF 9110: HTTP Semantics, obsoletes 7231, which obsoleted 2616 ++ * RFC 9110: HTTP Semantics, obsoletes 7231, which obsoleted 2616 + * RFC 5789: PATCH Method for HTTP + """ + def __new__(cls, value, description): +diff --git a/Lib/http/client.py b/Lib/http/client.py +index fab90a0ba4e..33a858d34ae 100644 +--- a/Lib/http/client.py ++++ b/Lib/http/client.py +@@ -472,7 +472,7 @@ + if self.chunked: + return self._read_chunked(amt) + +- if amt is not None: ++ if amt is not None and amt >= 0: + if self.length is not None and amt > self.length: + # clip the read to the "end of response" + amt = self.length +@@ -590,6 +590,8 @@ + + def _read_chunked(self, amt=None): + assert self.chunked != _UNKNOWN ++ if amt is not None and amt < 0: ++ amt = None + value = [] + try: + while (chunk_left := self._get_chunk_left()) is not None: +diff --git a/Lib/http/cookies.py b/Lib/http/cookies.py +index 23d5461f86f..694b1b09a05 100644 +--- a/Lib/http/cookies.py ++++ b/Lib/http/cookies.py +@@ -264,11 +264,12 @@ + "httponly" : "HttpOnly", + "version" : "Version", + "samesite" : "SameSite", ++ "partitioned": "Partitioned", + } + + _reserved_defaults = dict.fromkeys(_reserved, "") + +- _flags = {'secure', 'httponly'} ++ _flags = {'secure', 'httponly', 'partitioned'} + + def __init__(self): + # Set defaults +diff --git a/Lib/http/server.py b/Lib/http/server.py +index a6f7aecc787..a90c8d34c39 100644 +--- a/Lib/http/server.py ++++ b/Lib/http/server.py +@@ -99,7 +99,7 @@ + import posixpath + import select + import shutil +-import socket # For gethostbyaddr() ++import socket + import socketserver + import sys + import time +diff --git a/Lib/idlelib/CREDITS.txt b/Lib/idlelib/CREDITS.txt +index 4a42af586a4..bea3ba7c20d 100644 +--- a/Lib/idlelib/CREDITS.txt ++++ b/Lib/idlelib/CREDITS.txt +@@ -33,15 +33,15 @@ + + - 2005: Tal Einat + - 2010: Terry Jan Reedy (current maintainer) +-- 2013: Roger Serwys ++- 2013: Roger Serwy + - 2014: Saimadhav Heblikar + - 2015: Mark Roseman + - 2017: Louie Lu, Cheryl Sabella, and Serhiy Storchaka + + For additional details refer to NEWS.txt and Changelog. + +-Please contact the IDLE maintainer (kbk@shore.net) to have yourself included +-here if you are one of those we missed! ++If we missed you, feel free to submit a PR with a summary of ++contributions (for instance, at least 5 merged PRs). + + + +diff --git a/Lib/idlelib/News3.txt b/Lib/idlelib/News3.txt +index 37ff93f9866..74d84b38931 100644 +--- a/Lib/idlelib/News3.txt ++++ b/Lib/idlelib/News3.txt +@@ -1,8 +1,26 @@ ++What's New in IDLE 3.14.0 ++(since 3.13.0) ++Released on 2025-10-07 ++========================= ++ ++ ++gh-127060: Set TERM environment variable to 'dumb' to not add ANSI escape ++sequences for text color in tracebacks. IDLE does not understand them. ++Patch by Victor Stinner. ++ ++gh-122392: Increase currently inadequate vertical spacing for the IDLE ++browsers (path, module, and stack) on high-resolution monitors. ++ ++ + What's New in IDLE 3.13.0 + (since 3.12.0) +-Released on 2024-10-xx ++Released on 2024-10-07 + ========================= + ++gh-120104: Fix padding in config and search dialog windows in IDLE. ++ ++gh-129873: Simplify displaying the IDLE doc by only copying the text ++section of idle.html to idlelib/help.html. Patch by Stan Ulbrych. + + gh-120083: Add explicit black IDLE Hovertip foreground color needed for + recent macOS. Fixes Sonoma showing unreadable white on pale yellow. +diff --git a/Lib/idlelib/__main__.py b/Lib/idlelib/__main__.py +index 6349ec75c64..ec3915b265f 100644 +--- a/Lib/idlelib/__main__.py ++++ b/Lib/idlelib/__main__.py +@@ -5,4 +5,3 @@ + """ + import idlelib.pyshell + idlelib.pyshell.main() +-# This file does not work for 2.7; See issue 24212. +diff --git a/Lib/idlelib/help.html b/Lib/idlelib/help.html +index 2a4adc6a4d3..ebff9a309d9 100644 +--- a/Lib/idlelib/help.html ++++ b/Lib/idlelib/help.html +@@ -1,231 +1,7 @@ +- +- +- +- +- +- +- +- IDLE — Python 3.14.0a0 documentation +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +-
+-
+-
+-
+- +-
+-

IDLE¶

+-

Source code: Lib/idlelib/

+-
++
++

IDLE — Python editor and shell¶

++

Source code: Lib/idlelib/

++
+

IDLE is Python’s Integrated Development and Learning Environment.

+

IDLE has the following features:

+
    +@@ -241,7 +17,7 @@ +
  • configuration, browsers, and other dialogs

  • +
+ +
+-

Editing and Navigation¶

++

Editing and Navigation¶

+
+-

Editor windows¶

++

Editor windows¶

+

IDLE may open editor windows when it starts, depending on settings + and how you start IDLE. Thereafter, use the File menu. There can be only + one open editor window for a given file.

+@@ -548,7 +324,7 @@ + and that other files do not. Run Python code with the Run menu.

+
+
+-

Key bindings¶

++

Key bindings¶

+

The IDLE insertion cursor is a thin vertical bar between character + positions. When characters are entered, the insertion cursor and + everything to its right moves right one character and +@@ -574,7 +350,7 @@ + may work. Keybindings are selected in the Configure IDLE dialog.

+
+
+-

Automatic indentation¶

++

Automatic indentation¶

+

After a block-opening statement, the next line is indented by 4 spaces (in the + Python Shell window by one tab). After certain keywords (break, return etc.) + the next line is dedented. In leading indentation, Backspace deletes up +@@ -585,14 +361,14 @@ + Format menu.

+
+
+-

Search and Replace¶

++

Search and Replace¶

+

Any selection becomes a search target. However, only selections within + a line work because searches are only performed within lines with the + terminal newline removed. If [x] Regular expression is checked, the + target is interpreted according to the Python re module.

+
+
+-

Completions¶

++

Completions¶

+

Completions are supplied, when requested and available, for module + names, attributes of classes or functions, or filenames. Each request + method displays a completion box with existing names. (See tab +@@ -636,7 +412,7 @@ + by typing ‘_’ after ‘.’, either before or after the box is opened.

+
+
+-

Calltips¶

++

Calltips¶

+

A calltip is shown automatically when one types ( after the name + of an accessible function. A function name expression may include + dots and subscripts. A calltip remains until it is clicked, the cursor +@@ -662,7 +438,7 @@ + adding function definitions, or after opening an existing file.

+
+
+-

Code Context¶

++

Code Context¶

+

Within an editor window containing Python code, code context can be toggled + in order to show or hide a pane at the top of the window. When shown, this + pane freezes the opening lines for block code, such as those beginning with +@@ -677,7 +453,7 @@ + the Highlights tab in the Configure IDLE dialog.

+
+
+-

Shell window¶

++

Shell window¶

+

In IDLE’s Shell, enter, edit, and recall complete statements. (Most + consoles and terminals only work with a single physical line at a time).

+

Submit a single-line statement for execution by hitting Return +@@ -707,7 +483,7 @@ + +

+
+-

Text colors¶

++

Text colors¶

+

Idle defaults to black on white text, but colors text with special meanings. + For the shell, these are shell output, shell error, user output, and + user error. For Python code, at the shell prompt or in an editor, these are +@@ -726,7 +502,7 @@ +

+
+
+-

Startup and Code Execution¶

++

Startup and Code Execution¶

+

Upon startup with the -s option, IDLE will execute the file referenced by + the environment variables IDLESTARTUP or PYTHONSTARTUP. + IDLE first checks for IDLESTARTUP; if IDLESTARTUP is present the file +@@ -740,7 +516,7 @@ + executed in the Tk namespace, so this file is not useful for importing + functions to be used from IDLE’s Python shell.

+
+-

Command line usage¶

++

Command line usage¶

+
idle.py [-c command] [-d] [-e] [-h] [-i] [-r file] [-s] [-t title] [-] [arg] ...
+ 
+ -c command  run command in the shell window
+@@ -765,7 +541,7 @@
+ 
+ 
+
+-

Startup failure¶

++

Startup failure¶

+

IDLE uses a socket to communicate between the IDLE GUI process and the user + code execution process. A connection must be established whenever the Shell + starts or restarts. (The latter is indicated by a divider line that says +@@ -817,7 +593,7 @@ + then re-configure IDLE to use a font that works better.

+
+
+-

Running user code¶

++

Running user code¶

+

With rare exceptions, the result of executing Python code with IDLE is + intended to be the same as executing the same code by the default method, + directly with Python in a text-mode system console or terminal window. +@@ -861,7 +637,7 @@ + IDLE returns to a Shell prompt instead of exiting.

+
+
+-

User output in Shell¶

++

User output in Shell¶

+

When a program outputs text, the result is determined by the + corresponding output device. When IDLE executes user code, sys.stdout + and sys.stderr are connected to the display area of IDLE’s Shell. Some of +@@ -915,7 +691,7 @@ + right-clicking the label.

+
+
+-

Developing tkinter applications¶

++

Developing tkinter applications¶

+

IDLE is intentionally different from standard Python in order to + facilitate development of tkinter programs. Enter import tkinter as tk; + root = tk.Tk() in standard Python and nothing appears. Enter the same +@@ -935,7 +711,7 @@ + re-enable the mainloop call when running in standard Python.

+
+
+-

Running without a subprocess¶

++

Running without a subprocess¶

+

By default, IDLE executes user code in a separate subprocess via a socket, + which uses the internal loopback interface. This connection is not + externally visible and no data is sent to or received from the internet. +@@ -961,9 +737,9 @@ +

+
+
+-

Help and Preferences¶

++

Help and Preferences¶

+
+-

Help sources¶

++

Help sources¶

+

Help menu entry “IDLE Help†displays a formatted html version of the + IDLE chapter of the Library Reference. The result, in a read-only + tkinter text window, is close to what one sees in a web browser. +@@ -980,7 +756,7 @@ + General tab of the Configure IDLE dialog.

+
+
+-

Setting preferences¶

++

Setting preferences¶

+

The font preferences, highlighting, keys, and general preferences can be + changed via Configure IDLE on the Option menu. + Non-default user settings are saved in a .idlerc directory in the user’s +@@ -998,13 +774,13 @@ + to older IDLEs.

+
+
+-

IDLE on macOS¶

++

IDLE on macOS¶

+

Under System Preferences: Dock, one can set “Prefer tabs when opening + documents†to “Alwaysâ€. This setting is not compatible with the tk/tkinter + GUI framework used by IDLE, and it breaks a few IDLE features.

+
+
+-

Extensions¶

++

Extensions¶

+

IDLE contains an extension facility. Preferences for extensions can be + changed with the Extensions tab of the preferences dialog. See the + beginning of config-extensions.def in the idlelib directory for further +@@ -1013,8 +789,8 @@ +

+
+
+-

idlelib¶

+-

Source code: Lib/idlelib

++

idlelib — implementation of IDLE application¶

++

Source code: Lib/idlelib

+
+

The Lib/idlelib package implements the IDLE application. See the rest + of this page for how to use IDLE.

+@@ -1027,168 +803,3 @@ +
+ + +-
+-
+-
+-
+- +-
+-
+- +- +- +- +- +diff --git a/Lib/idlelib/help.py b/Lib/idlelib/help.py +index d8613b2eadd..063a749df54 100644 +--- a/Lib/idlelib/help.py ++++ b/Lib/idlelib/help.py +@@ -20,7 +20,7 @@ + + HelpWindow - Display HelpFrame in a standalone window. + +-copy_strip - Copy idle.html to help.html, rstripping each line. ++copy_strip - Copy the text part of idle.html to help.html while rstripping each line. + + show_idlehelp - Create HelpWindow. Called in EditorWindow.help_dialog. + """ +@@ -54,7 +54,6 @@ + self.text = text # Text widget we're rendering into. + self.tags = '' # Current block level text tags to apply. + self.chartags = '' # Current character level text tags. +- self.show = False # Exclude html page navigation. + self.hdrlink = False # Exclude html header links. + self.level = 0 # Track indentation level. + self.pre = False # Displaying preformatted text? +@@ -77,11 +76,7 @@ + if a == 'class': + class_ = v + s = '' +- if tag == 'section' and attrs == [('id', 'idle')]: +- self.show = True # Start main content. +- elif tag == 'div' and class_ == 'clearer': +- self.show = False # End main content. +- elif tag == 'p' and self.prevtag and not self.prevtag[0]: ++ if tag == 'p' and self.prevtag and not self.prevtag[0]: + # Begin a new block for

tags after a closed tag. + # Avoid extra lines, e.g. after

 tags.
+             lastline = self.text.get('end-1c linestart', 'end-1c')
+@@ -112,31 +107,27 @@
+             s = '\n'
+         elif tag == 'pre':
+             self.pre = True
+-            if self.show:
+-                self.text.insert('end', '\n\n')
++            self.text.insert('end', '\n\n')
+             self.tags = 'preblock'
+         elif tag == 'a' and class_ == 'headerlink':
+             self.hdrlink = True
+         elif tag == 'h1':
+             self.tags = tag
+         elif tag in ['h2', 'h3']:
+-            if self.show:
+-                self.header = ''
+-                self.text.insert('end', '\n\n')
++            self.header = ''
++            self.text.insert('end', '\n\n')
+             self.tags = tag
+-        if self.show:
+-            self.text.insert('end', s, (self.tags, self.chartags))
++        self.text.insert('end', s, (self.tags, self.chartags))
+         self.prevtag = (True, tag)
+ 
+     def handle_endtag(self, tag):
+         "Handle endtags in help.html."
+         if tag in ['h1', 'h2', 'h3']:
+             assert self.level == 0
+-            if self.show:
+-                indent = ('        ' if tag == 'h3' else
+-                          '    ' if tag == 'h2' else
+-                          '')
+-                self.toc.append((indent+self.header, self.text.index('insert')))
++            indent = ('        ' if tag == 'h3' else
++                      '    ' if tag == 'h2' else
++                      '')
++            self.toc.append((indent+self.header, self.text.index('insert')))
+             self.tags = ''
+         elif tag in ['span', 'em']:
+             self.chartags = ''
+@@ -151,11 +142,13 @@
+ 
+     def handle_data(self, data):
+         "Handle date segments in help.html."
+-        if self.show and not self.hdrlink:
++        if not self.hdrlink:
+             d = data if self.pre else data.replace('\n', ' ')
+             if self.tags == 'h1':
+                 try:
+-                    self.hprefix = d[0:d.index(' ')]
++                    self.hprefix = d[:d.index(' ')]
++                    if not self.hprefix.isdigit():
++                        self.hprefix = ''
+                 except ValueError:
+                     self.hprefix = ''
+             if self.tags in ['h1', 'h2', 'h3']:
+@@ -251,7 +244,7 @@
+ 
+ 
+ def copy_strip():  # pragma: no cover
+-    """Copy idle.html to idlelib/help.html, stripping trailing whitespace.
++    """Copy the text part of idle.html to idlelib/help.html while stripping trailing whitespace.
+ 
+     Files with trailing whitespace cannot be pushed to the git cpython
+     repository.  For 3.x (on Windows), help.html is generated, after
+@@ -263,7 +256,7 @@
+ 
+     It can be worthwhile to occasionally generate help.html without
+     touching idle.rst.  Changes to the master version and to the doc
+-    build system may result in changes that should not changed
++    build system may result in changes that should not change
+     the displayed text, but might break HelpParser.
+ 
+     As long as master and maintenance versions of idle.rst remain the
+@@ -276,10 +269,14 @@
+     src = join(abspath(dirname(dirname(dirname(__file__)))),
+             'Doc', 'build', 'html', 'library', 'idle.html')
+     dst = join(abspath(dirname(__file__)), 'help.html')
+-    with open(src, 'rb') as inn,\
+-         open(dst, 'wb') as out:
++
++    with open(src, 'r', encoding="utf-8") as inn, open(dst, 'w', encoding="utf-8") as out:
++        copy = False
+         for line in inn:
+-            out.write(line.rstrip() + b'\n')
++            if '
' in line: copy = True ++ if '
' in line: break ++ if copy: out.write(line.strip() + '\n') ++ + print(f'{src} copied to {dst}') + + +diff --git a/Lib/idlelib/idle_test/test_configdialog.py b/Lib/idlelib/idle_test/test_configdialog.py +index 5099d093382..2773ed7ce61 100644 +--- a/Lib/idlelib/idle_test/test_configdialog.py ++++ b/Lib/idlelib/idle_test/test_configdialog.py +@@ -98,8 +98,8 @@ + dialog.buttons['Help'].invoke() + title, contents = view.kwds['title'], view.kwds['contents'] + self.assertEqual(title, 'Help for IDLE preferences') +- self.assertTrue(contents.startswith('When you click') and +- contents.endswith('a different name.\n')) ++ self.assertStartsWith(contents, 'When you click') ++ self.assertEndsWith(contents,'a different name.\n') + + + class FontPageTest(unittest.TestCase): +diff --git a/Lib/idlelib/idle_test/test_debugger.py b/Lib/idlelib/idle_test/test_debugger.py +index d1c9638dd5d..9ca3b332648 100644 +--- a/Lib/idlelib/idle_test/test_debugger.py ++++ b/Lib/idlelib/idle_test/test_debugger.py +@@ -256,7 +256,7 @@ + flist = None + master_window = self.root + sv = debugger.StackViewer(master_window, flist, gui) +- self.assertTrue(hasattr(sv, 'stack')) ++ self.assertHasAttr(sv, 'stack') + + def test_load_stack(self): + # Test the .load_stack() method against a fixed test stack. +diff --git a/Lib/idlelib/idle_test/test_grep.py b/Lib/idlelib/idle_test/test_grep.py +index a0b5b691718..d67dba76911 100644 +--- a/Lib/idlelib/idle_test/test_grep.py ++++ b/Lib/idlelib/idle_test/test_grep.py +@@ -143,7 +143,7 @@ + self.assertIn(pat, lines[0]) + self.assertIn('py: 1:', lines[1]) # line number 1 + self.assertIn('2', lines[3]) # hits found 2 +- self.assertTrue(lines[4].startswith('(Hint:')) ++ self.assertStartsWith(lines[4], '(Hint:') + + + class Default_commandTest(unittest.TestCase): +diff --git a/Lib/idlelib/idle_test/test_help.py b/Lib/idlelib/idle_test/test_help.py +index c528d4e77f8..ebb02b5c0d8 100644 +--- a/Lib/idlelib/idle_test/test_help.py ++++ b/Lib/idlelib/idle_test/test_help.py +@@ -29,7 +29,7 @@ + + def test_4text(self): + text = self.window.frame.text +- self.assertEqual(text.get('1.0', '1.end'), ' IDLE ') ++ self.assertEqual(text.get('1.0', '1.end'), ' IDLE — Python editor and shell ') + + + if __name__ == '__main__': +diff --git a/Lib/idlelib/idle_test/test_multicall.py b/Lib/idlelib/idle_test/test_multicall.py +index b3a3bfb88f9..67f28db6b08 100644 +--- a/Lib/idlelib/idle_test/test_multicall.py ++++ b/Lib/idlelib/idle_test/test_multicall.py +@@ -27,7 +27,7 @@ + def test_creator(self): + mc = self.mc + self.assertIs(multicall._multicall_dict[Text], mc) +- self.assertTrue(issubclass(mc, Text)) ++ self.assertIsSubclass(mc, Text) + mc2 = multicall.MultiCallCreator(Text) + self.assertIs(mc, mc2) + +diff --git a/Lib/idlelib/idle_test/test_query.py b/Lib/idlelib/idle_test/test_query.py +index bb12b2b0865..a6ef858a8c9 100644 +--- a/Lib/idlelib/idle_test/test_query.py ++++ b/Lib/idlelib/idle_test/test_query.py +@@ -134,10 +134,10 @@ + + def test_good_module_name(self): + dialog = self.Dummy_ModuleName('idlelib') +- self.assertTrue(dialog.entry_ok().endswith('__init__.py')) ++ self.assertEndsWith(dialog.entry_ok(), '__init__.py') + self.assertEqual(dialog.entry_error['text'], '') + dialog = self.Dummy_ModuleName('idlelib.idle') +- self.assertTrue(dialog.entry_ok().endswith('idle.py')) ++ self.assertEndsWith(dialog.entry_ok(), 'idle.py') + self.assertEqual(dialog.entry_error['text'], '') + + +@@ -389,7 +389,7 @@ + self.assertEqual(dialog.text0, 'idlelib') + self.assertEqual(dialog.entry.get(), 'idlelib') + dialog.button_ok.invoke() +- self.assertTrue(dialog.result.endswith('__init__.py')) ++ self.assertEndsWith(dialog.result, '__init__.py') + root.destroy() + + +diff --git a/Lib/idlelib/idle_test/test_redirector.py b/Lib/idlelib/idle_test/test_redirector.py +index a97b3002afc..bd486d7da66 100644 +--- a/Lib/idlelib/idle_test/test_redirector.py ++++ b/Lib/idlelib/idle_test/test_redirector.py +@@ -34,7 +34,7 @@ + redir.register('insert', Func) + redir.close() + self.assertEqual(redir._operations, {}) +- self.assertFalse(hasattr(self.text, 'widget')) ++ self.assertNotHasAttr(self.text, 'widget') + + + class WidgetRedirectorTest(unittest.TestCase): +diff --git a/Lib/idlelib/idle_test/test_sidebar.py b/Lib/idlelib/idle_test/test_sidebar.py +index 605e7a89257..4157a4b4dcd 100644 +--- a/Lib/idlelib/idle_test/test_sidebar.py ++++ b/Lib/idlelib/idle_test/test_sidebar.py +@@ -725,7 +725,7 @@ + + text.tag_add('sel', f'{first_line}.0', 'end-1c') + selected_text = text.get('sel.first', 'sel.last') +- self.assertTrue(selected_text.startswith('if True:\n')) ++ self.assertStartsWith(selected_text, 'if True:\n') + self.assertIn('\n1\n', selected_text) + + text.event_generate('<>') +@@ -749,7 +749,7 @@ + + text.tag_add('sel', f'{first_line}.3', 'end-1c') + selected_text = text.get('sel.first', 'sel.last') +- self.assertTrue(selected_text.startswith('True:\n')) ++ self.assertStartsWith(selected_text, 'True:\n') + + selected_lines_text = text.get('sel.first linestart', 'sel.last') + selected_lines = selected_lines_text.split('\n') +diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py +index e882c6cb3b8..295d06e4a5f 100755 +--- a/Lib/idlelib/pyshell.py ++++ b/Lib/idlelib/pyshell.py +@@ -424,7 +424,9 @@ + def spawn_subprocess(self): + if self.subprocess_arglist is None: + self.subprocess_arglist = self.build_subprocess_arglist() +- self.rpcsubproc = subprocess.Popen(self.subprocess_arglist) ++ # gh-127060: Disable traceback colors ++ env = dict(os.environ, TERM='dumb') ++ self.rpcsubproc = subprocess.Popen(self.subprocess_arglist, env=env) + + def build_subprocess_arglist(self): + assert (self.port!=0), ( +@@ -1131,8 +1133,7 @@ + def short_title(self): + return self.shell_title + +- COPYRIGHT = \ +- 'Type "help", "copyright", "credits" or "license()" for more information.' ++ SPLASHLINE = 'Enter "help" below or click "Help" above for more information.' + + def begin(self): + self.text.mark_set("iomark", "insert") +@@ -1151,7 +1152,7 @@ + sys.displayhook = rpc.displayhook + + self.write("Python %s on %s\n%s\n%s" % +- (sys.version, sys.platform, self.COPYRIGHT, nosub)) ++ (sys.version, sys.platform, self.SPLASHLINE, nosub)) + self.text.focus_force() + self.showprompt() + # User code should use separate default Tk root window +diff --git a/Lib/imaplib.py b/Lib/imaplib.py +index e576c29e67d..2c3925958d0 100644 +--- a/Lib/imaplib.py ++++ b/Lib/imaplib.py +@@ -19,8 +19,9 @@ + # GET/SETQUOTA contributed by Andreas Zeidler June 2002. + # PROXYAUTH contributed by Rick Holbert November 2002. + # GET/SETANNOTATION contributed by Tomas Lindroos June 2005. ++# IDLE contributed by Forest August 2024. + +-__version__ = "2.58" ++__version__ = "2.59" + + import binascii, errno, random, re, socket, subprocess, sys, time, calendar + from datetime import datetime, timezone, timedelta +@@ -74,6 +75,7 @@ + 'GETANNOTATION':('AUTH', 'SELECTED'), + 'GETQUOTA': ('AUTH', 'SELECTED'), + 'GETQUOTAROOT': ('AUTH', 'SELECTED'), ++ 'IDLE': ('AUTH', 'SELECTED'), + 'MYRIGHTS': ('AUTH', 'SELECTED'), + 'LIST': ('AUTH', 'SELECTED'), + 'LOGIN': ('NONAUTH',), +@@ -184,6 +186,7 @@ + class error(Exception): pass # Logical errors - debug required + class abort(error): pass # Service errors - close and retry + class readonly(abort): pass # Mailbox status changed to READ-ONLY ++ class _responsetimeout(TimeoutError): pass # No response during IDLE + + def __init__(self, host='', port=IMAP4_PORT, timeout=None): + self.debug = Debug +@@ -192,10 +195,13 @@ + self.tagged_commands = {} # Tagged commands awaiting response + self.untagged_responses = {} # {typ: [data, ...], ...} + self.continuation_response = '' # Last continuation response ++ self._idle_responses = [] # Response queue for idle iteration ++ self._idle_capture = False # Whether to queue responses for idle + self.is_readonly = False # READ-ONLY desired state + self.tagnum = 0 + self._tls_established = False + self._mode_ascii() ++ self._readbuf = [] + + # Open socket to server. + +@@ -310,17 +316,97 @@ + self.host = host + self.port = port + self.sock = self._create_socket(timeout) +- self.file = self.sock.makefile('rb') ++ self._file = self.sock.makefile('rb') ++ ++ ++ @property ++ def file(self): ++ # The old 'file' attribute is no longer used now that we do our own ++ # read() and readline() buffering, with which it conflicts. ++ # As an undocumented interface, it should never have been accessed by ++ # external code, and therefore does not warrant deprecation. ++ # Nevertheless, we provide this property for now, to avoid suddenly ++ # breaking any code in the wild that might have been using it in a ++ # harmless way. ++ import warnings ++ warnings.warn( ++ 'IMAP4.file is unsupported, can cause errors, and may be removed.', ++ RuntimeWarning, ++ stacklevel=2) ++ return self._file + + + def read(self, size): + """Read 'size' bytes from remote.""" +- return self.file.read(size) ++ # We need buffered read() to continue working after socket timeouts, ++ # since we use them during IDLE. Unfortunately, the standard library's ++ # SocketIO implementation makes this impossible, by setting a permanent ++ # error condition instead of letting the caller decide how to handle a ++ # timeout. We therefore implement our own buffered read(). ++ # https://github.com/python/cpython/issues/51571 ++ # ++ # Reading in chunks instead of delegating to a single ++ # BufferedReader.read() call also means we avoid its preallocation ++ # of an unreasonably large memory block if a malicious server claims ++ # it will send a huge literal without actually sending one. ++ # https://github.com/python/cpython/issues/119511 ++ ++ parts = [] ++ ++ while size > 0: ++ ++ if len(parts) < len(self._readbuf): ++ buf = self._readbuf[len(parts)] ++ else: ++ try: ++ buf = self.sock.recv(DEFAULT_BUFFER_SIZE) ++ except ConnectionError: ++ break ++ if not buf: ++ break ++ self._readbuf.append(buf) ++ ++ if len(buf) >= size: ++ parts.append(buf[:size]) ++ self._readbuf = [buf[size:]] + self._readbuf[len(parts):] ++ break ++ parts.append(buf) ++ size -= len(buf) ++ ++ return b''.join(parts) + + + def readline(self): + """Read line from remote.""" +- line = self.file.readline(_MAXLINE + 1) ++ # The comment in read() explains why we implement our own readline(). ++ ++ LF = b'\n' ++ parts = [] ++ length = 0 ++ ++ while length < _MAXLINE: ++ ++ if len(parts) < len(self._readbuf): ++ buf = self._readbuf[len(parts)] ++ else: ++ try: ++ buf = self.sock.recv(DEFAULT_BUFFER_SIZE) ++ except ConnectionError: ++ break ++ if not buf: ++ break ++ self._readbuf.append(buf) ++ ++ pos = buf.find(LF) ++ if pos != -1: ++ pos += 1 ++ parts.append(buf[:pos]) ++ self._readbuf = [buf[pos:]] + self._readbuf[len(parts):] ++ break ++ parts.append(buf) ++ length += len(buf) ++ ++ line = b''.join(parts) + if len(line) > _MAXLINE: + raise self.error("got more than %d bytes" % _MAXLINE) + return line +@@ -334,7 +420,7 @@ + + def shutdown(self): + """Close I/O established in "open".""" +- self.file.close() ++ self._file.close() + try: + self.sock.shutdown(socket.SHUT_RDWR) + except OSError as exc: +@@ -588,6 +674,19 @@ + return typ, [quotaroot, quota] + + ++ def idle(self, duration=None): ++ """Return an iterable IDLE context manager producing untagged responses. ++ If the argument is not None, limit iteration to 'duration' seconds. ++ ++ with M.idle(duration=29 * 60) as idler: ++ for typ, data in idler: ++ print(typ, data) ++ ++ Note: 'duration' requires a socket connection (not IMAP4_stream). ++ """ ++ return Idler(self, duration) ++ ++ + def list(self, directory='""', pattern='*'): + """List mailbox names in directory matching pattern. + +@@ -821,7 +920,7 @@ + if typ == 'OK': + self.sock = ssl_context.wrap_socket(self.sock, + server_hostname=self.host) +- self.file = self.sock.makefile('rb') ++ self._file = self.sock.makefile('rb') + self._tls_established = True + self._get_capabilities() + else: +@@ -944,6 +1043,24 @@ + def _append_untagged(self, typ, dat): + if dat is None: + dat = b'' ++ ++ # During idle, queue untagged responses for delivery via iteration ++ if self._idle_capture: ++ # Responses containing literal strings are passed to us one data ++ # fragment at a time, while others arrive in a single call. ++ if (not self._idle_responses or ++ isinstance(self._idle_responses[-1][1][-1], bytes)): ++ # We are not continuing a fragmented response; start a new one ++ self._idle_responses.append((typ, [dat])) ++ else: ++ # We are continuing a fragmented response; append the fragment ++ response = self._idle_responses[-1] ++ assert response[0] == typ ++ response[1].append(dat) ++ if __debug__ and self.debug >= 5: ++ self._mesg(f'idle: queue untagged {typ} {dat!r}') ++ return ++ + ur = self.untagged_responses + if __debug__: + if self.debug >= 5: +@@ -1065,14 +1182,29 @@ + self.capabilities = tuple(dat.split()) + + +- def _get_response(self): ++ def _get_response(self, start_timeout=False): + + # Read response and store. + # + # Returns None for continuation responses, + # otherwise first response line received. +- +- resp = self._get_line() ++ # ++ # If start_timeout is given, temporarily uses it as a socket ++ # timeout while waiting for the start of a response, raising ++ # _responsetimeout if one doesn't arrive. (Used by Idler.) ++ ++ if start_timeout is not False and self.sock: ++ assert start_timeout is None or start_timeout > 0 ++ saved_timeout = self.sock.gettimeout() ++ self.sock.settimeout(start_timeout) ++ try: ++ resp = self._get_line() ++ except TimeoutError as err: ++ raise self._responsetimeout from err ++ finally: ++ self.sock.settimeout(saved_timeout) ++ else: ++ resp = self._get_line() + + # Command completion response? + +@@ -1279,6 +1411,199 @@ + n -= 1 + + ++class Idler: ++ """Iterable IDLE context manager: start IDLE & produce untagged responses. ++ ++ An object of this type is returned by the IMAP4.idle() method. ++ ++ Note: The name and structure of this class are subject to change. ++ """ ++ ++ def __init__(self, imap, duration=None): ++ if 'IDLE' not in imap.capabilities: ++ raise imap.error("Server does not support IMAP4 IDLE") ++ if duration is not None and not imap.sock: ++ # IMAP4_stream pipes don't support timeouts ++ raise imap.error('duration requires a socket connection') ++ self._duration = duration ++ self._deadline = None ++ self._imap = imap ++ self._tag = None ++ self._saved_state = None ++ ++ def __enter__(self): ++ imap = self._imap ++ assert not imap._idle_responses ++ assert not imap._idle_capture ++ ++ if __debug__ and imap.debug >= 4: ++ imap._mesg(f'idle start duration={self._duration}') ++ ++ # Start capturing untagged responses before sending IDLE, ++ # so we can deliver via iteration any that arrive while ++ # the IDLE command continuation request is still pending. ++ imap._idle_capture = True ++ ++ try: ++ self._tag = imap._command('IDLE') ++ # As with any command, the server is allowed to send us unrelated, ++ # untagged responses before acting on IDLE. These lines will be ++ # returned by _get_response(). When the server is ready, it will ++ # send an IDLE continuation request, indicated by _get_response() ++ # returning None. We therefore process responses in a loop until ++ # this occurs. ++ while resp := imap._get_response(): ++ if imap.tagged_commands[self._tag]: ++ typ, data = imap.tagged_commands.pop(self._tag) ++ if typ == 'NO': ++ raise imap.error(f'idle denied: {data}') ++ raise imap.abort(f'unexpected status response: {resp}') ++ ++ if __debug__ and imap.debug >= 4: ++ prompt = imap.continuation_response ++ imap._mesg(f'idle continuation prompt: {prompt}') ++ except BaseException: ++ imap._idle_capture = False ++ raise ++ ++ if self._duration is not None: ++ self._deadline = time.monotonic() + self._duration ++ ++ self._saved_state = imap.state ++ imap.state = 'IDLING' ++ ++ return self ++ ++ def __exit__(self, exc_type, exc_val, exc_tb): ++ imap = self._imap ++ ++ if __debug__ and imap.debug >= 4: ++ imap._mesg('idle done') ++ imap.state = self._saved_state ++ ++ # Stop intercepting untagged responses before sending DONE, ++ # since we can no longer deliver them via iteration. ++ imap._idle_capture = False ++ ++ # If we captured untagged responses while the IDLE command ++ # continuation request was still pending, but the user did not ++ # iterate over them before exiting IDLE, we must put them ++ # someplace where the user can retrieve them. The only ++ # sensible place for this is the untagged_responses dict, ++ # despite its unfortunate inability to preserve the relative ++ # order of different response types. ++ if leftovers := len(imap._idle_responses): ++ if __debug__ and imap.debug >= 4: ++ imap._mesg(f'idle quit with {leftovers} leftover responses') ++ while imap._idle_responses: ++ typ, data = imap._idle_responses.pop(0) ++ # Append one fragment at a time, just as _get_response() does ++ for datum in data: ++ imap._append_untagged(typ, datum) ++ ++ try: ++ imap.send(b'DONE' + CRLF) ++ status, [msg] = imap._command_complete('IDLE', self._tag) ++ if __debug__ and imap.debug >= 4: ++ imap._mesg(f'idle status: {status} {msg!r}') ++ except OSError: ++ if not exc_type: ++ raise ++ ++ return False # Do not suppress context body exceptions ++ ++ def __iter__(self): ++ return self ++ ++ def _pop(self, timeout, default=('', None)): ++ # Get the next response, or a default value on timeout. ++ # The timeout arg can be an int or float, or None for no timeout. ++ # Timeouts require a socket connection (not IMAP4_stream). ++ # This method ignores self._duration. ++ ++ # Historical Note: ++ # The timeout was originally implemented using select() after ++ # checking for the presence of already-buffered data. ++ # That allowed timeouts on pipe connetions like IMAP4_stream. ++ # However, it seemed possible that SSL data arriving without any ++ # IMAP data afterward could cause select() to indicate available ++ # application data when there was none, leading to a read() call ++ # that would block with no timeout. It was unclear under what ++ # conditions this would happen in practice. Our implementation was ++ # changed to use socket timeouts instead of select(), just to be ++ # safe. ++ ++ imap = self._imap ++ if imap.state != 'IDLING': ++ raise imap.error('_pop() only works during IDLE') ++ ++ if imap._idle_responses: ++ # Response is ready to return to the user ++ resp = imap._idle_responses.pop(0) ++ if __debug__ and imap.debug >= 4: ++ imap._mesg(f'idle _pop({timeout}) de-queued {resp[0]}') ++ return resp ++ ++ if __debug__ and imap.debug >= 4: ++ imap._mesg(f'idle _pop({timeout}) reading') ++ ++ if timeout is not None: ++ if timeout <= 0: ++ return default ++ timeout = float(timeout) # Required by socket.settimeout() ++ ++ try: ++ imap._get_response(timeout) # Reads line, calls _append_untagged() ++ except IMAP4._responsetimeout: ++ if __debug__ and imap.debug >= 4: ++ imap._mesg(f'idle _pop({timeout}) done') ++ return default ++ ++ resp = imap._idle_responses.pop(0) ++ ++ if __debug__ and imap.debug >= 4: ++ imap._mesg(f'idle _pop({timeout}) read {resp[0]}') ++ return resp ++ ++ def __next__(self): ++ imap = self._imap ++ ++ if self._duration is None: ++ timeout = None ++ else: ++ timeout = self._deadline - time.monotonic() ++ typ, data = self._pop(timeout) ++ ++ if not typ: ++ if __debug__ and imap.debug >= 4: ++ imap._mesg('idle iterator exhausted') ++ raise StopIteration ++ ++ return typ, data ++ ++ def burst(self, interval=0.1): ++ """Yield a burst of responses no more than 'interval' seconds apart. ++ ++ with M.idle() as idler: ++ # get a response and any others following by < 0.1 seconds ++ batch = list(idler.burst()) ++ print(f'processing {len(batch)} responses...') ++ print(batch) ++ ++ Note: This generator requires a socket connection (not IMAP4_stream). ++ """ ++ if not self._imap.sock: ++ raise self._imap.error('burst() requires a socket connection') ++ ++ try: ++ yield next(self) ++ except StopIteration: ++ return ++ ++ while response := self._pop(interval, None): ++ yield response ++ ++ + if HAVE_SSL: + + class IMAP4_SSL(IMAP4): +@@ -1346,7 +1671,7 @@ + self.host = None # For compatibility with parent class + self.port = None + self.sock = None +- self.file = None ++ self._file = None + self.process = subprocess.Popen(self.command, + bufsize=DEFAULT_BUFFER_SIZE, + stdin=subprocess.PIPE, stdout=subprocess.PIPE, +diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py +index fa361597118..8bcd741c446 100644 +--- a/Lib/importlib/_bootstrap_external.py ++++ b/Lib/importlib/_bootstrap_external.py +@@ -716,6 +716,12 @@ + + @classmethod + def find_spec(cls, fullname, path=None, target=None): ++ _warnings.warn('importlib.machinery.WindowsRegistryFinder is ' ++ 'deprecated; use site configuration instead. ' ++ 'Future versions of Python may not enable this ' ++ 'finder by default.', ++ DeprecationWarning, stacklevel=2) ++ + filepath = cls._search_registry(fullname) + if filepath is None: + return None +@@ -1238,7 +1244,7 @@ + if path == '': + try: + path = _os.getcwd() +- except FileNotFoundError: ++ except (FileNotFoundError, PermissionError): + # Don't cache the failure as the cwd can easily change to + # a valid directory later on. + return None +diff --git a/Lib/importlib/abc.py b/Lib/importlib/abc.py +index eea6b38af6f..29f01f77eff 100644 +--- a/Lib/importlib/abc.py ++++ b/Lib/importlib/abc.py +@@ -70,6 +70,15 @@ + + """ + ++ def __init__(self): ++ import warnings ++ warnings.warn('importlib.abc.ResourceLoader is deprecated in ' ++ 'favour of supporting resource loading through ' ++ 'importlib.resources.abc.TraversableResources.', ++ DeprecationWarning, stacklevel=2) ++ super().__init__() ++ ++ + @abc.abstractmethod + def get_data(self, path): + """Abstract method which when implemented should return the bytes for +@@ -199,6 +208,10 @@ + + def path_mtime(self, path): + """Return the (int) modification time for the path (str).""" ++ import warnings ++ warnings.warn('SourceLoader.path_mtime is deprecated in favour of ' ++ 'SourceLoader.path_stats().', ++ DeprecationWarning, stacklevel=2) + if self.path_stats.__func__ is SourceLoader.path_stats: + raise OSError + return int(self.path_stats(path)['mtime']) +diff --git a/Lib/importlib/machinery.py b/Lib/importlib/machinery.py +index 6e294d59bfd..63d726445c3 100644 +--- a/Lib/importlib/machinery.py ++++ b/Lib/importlib/machinery.py +@@ -3,9 +3,11 @@ + from ._bootstrap import ModuleSpec + from ._bootstrap import BuiltinImporter + from ._bootstrap import FrozenImporter +-from ._bootstrap_external import (SOURCE_SUFFIXES, DEBUG_BYTECODE_SUFFIXES, +- OPTIMIZED_BYTECODE_SUFFIXES, BYTECODE_SUFFIXES, +- EXTENSION_SUFFIXES) ++from ._bootstrap_external import ( ++ SOURCE_SUFFIXES, BYTECODE_SUFFIXES, EXTENSION_SUFFIXES, ++ DEBUG_BYTECODE_SUFFIXES as _DEBUG_BYTECODE_SUFFIXES, ++ OPTIMIZED_BYTECODE_SUFFIXES as _OPTIMIZED_BYTECODE_SUFFIXES ++) + from ._bootstrap_external import WindowsRegistryFinder + from ._bootstrap_external import PathFinder + from ._bootstrap_external import FileFinder +@@ -27,3 +29,22 @@ + 'NamespaceLoader', 'OPTIMIZED_BYTECODE_SUFFIXES', 'PathFinder', + 'SOURCE_SUFFIXES', 'SourceFileLoader', 'SourcelessFileLoader', + 'WindowsRegistryFinder', 'all_suffixes'] ++ ++ ++def __getattr__(name): ++ import warnings ++ ++ if name == 'DEBUG_BYTECODE_SUFFIXES': ++ warnings.warn('importlib.machinery.DEBUG_BYTECODE_SUFFIXES is ' ++ 'deprecated; use importlib.machinery.BYTECODE_SUFFIXES ' ++ 'instead.', ++ DeprecationWarning, stacklevel=2) ++ return _DEBUG_BYTECODE_SUFFIXES ++ elif name == 'OPTIMIZED_BYTECODE_SUFFIXES': ++ warnings.warn('importlib.machinery.OPTIMIZED_BYTECODE_SUFFIXES is ' ++ 'deprecated; use importlib.machinery.BYTECODE_SUFFIXES ' ++ 'instead.', ++ DeprecationWarning, stacklevel=2) ++ return _OPTIMIZED_BYTECODE_SUFFIXES ++ ++ raise AttributeError(f'module {__name__!r} has no attribute {name!r}') +diff --git a/Lib/importlib/resources/__init__.py b/Lib/importlib/resources/__init__.py +index ec4441c9116..723c9f9eb33 100644 +--- a/Lib/importlib/resources/__init__.py ++++ b/Lib/importlib/resources/__init__.py +@@ -1,4 +1,11 @@ +-"""Read resources contained within a package.""" ++""" ++Read resources contained within a package. ++ ++This codebase is shared between importlib.resources in the stdlib ++and importlib_resources in PyPI. See ++https://github.com/python/importlib_metadata/wiki/Development-Methodology ++for more detail. ++""" + + from ._common import ( + as_file, +diff --git a/Lib/importlib/resources/_common.py b/Lib/importlib/resources/_common.py +index c2c92254370..4e9014c45a0 100644 +--- a/Lib/importlib/resources/_common.py ++++ b/Lib/importlib/resources/_common.py +@@ -66,10 +66,10 @@ + # zipimport.zipimporter does not support weak references, resulting in a + # TypeError. That seems terrible. + spec = package.__spec__ +- reader = getattr(spec.loader, 'get_resource_reader', None) # type: ignore ++ reader = getattr(spec.loader, 'get_resource_reader', None) # type: ignore[union-attr] + if reader is None: + return None +- return reader(spec.name) # type: ignore ++ return reader(spec.name) # type: ignore[union-attr] + + + @functools.singledispatch +diff --git a/Lib/importlib/resources/readers.py b/Lib/importlib/resources/readers.py +index ccc5abbeb4e..70fc7e2b9c0 100644 +--- a/Lib/importlib/resources/readers.py ++++ b/Lib/importlib/resources/readers.py +@@ -1,3 +1,5 @@ ++from __future__ import annotations ++ + import collections + import contextlib + import itertools +@@ -6,6 +8,7 @@ + import re + import warnings + import zipfile ++from collections.abc import Iterator + + from . import abc + +@@ -135,27 +138,31 @@ + def __init__(self, namespace_path): + if 'NamespacePath' not in str(namespace_path): + raise ValueError('Invalid path') +- self.path = MultiplexedPath(*map(self._resolve, namespace_path)) ++ self.path = MultiplexedPath(*filter(bool, map(self._resolve, namespace_path))) + + @classmethod +- def _resolve(cls, path_str) -> abc.Traversable: ++ def _resolve(cls, path_str) -> abc.Traversable | None: + r""" + Given an item from a namespace path, resolve it to a Traversable. + + path_str might be a directory on the filesystem or a path to a + zipfile plus the path within the zipfile, e.g. ``/foo/bar`` or + ``/foo/baz.zip/inner_dir`` or ``foo\baz.zip\inner_dir\sub``. ++ ++ path_str might also be a sentinel used by editable packages to ++ trigger other behaviors (see python/importlib_resources#311). ++ In that case, return None. + """ +- (dir,) = (cand for cand in cls._candidate_paths(path_str) if cand.is_dir()) +- return dir ++ dirs = (cand for cand in cls._candidate_paths(path_str) if cand.is_dir()) ++ return next(dirs, None) + + @classmethod +- def _candidate_paths(cls, path_str): ++ def _candidate_paths(cls, path_str: str) -> Iterator[abc.Traversable]: + yield pathlib.Path(path_str) + yield from cls._resolve_zip_path(path_str) + + @staticmethod +- def _resolve_zip_path(path_str): ++ def _resolve_zip_path(path_str: str): + for match in reversed(list(re.finditer(r'[\\/]', path_str))): + with contextlib.suppress( + FileNotFoundError, +diff --git a/Lib/importlib/resources/simple.py b/Lib/importlib/resources/simple.py +index 96f117fec62..2e75299b13a 100644 +--- a/Lib/importlib/resources/simple.py ++++ b/Lib/importlib/resources/simple.py +@@ -77,7 +77,7 @@ + + def __init__(self, parent: ResourceContainer, name: str): + self.parent = parent +- self.name = name # type: ignore ++ self.name = name # type: ignore[misc] + + def is_file(self): + return True +diff --git a/Lib/inspect.py b/Lib/inspect.py +index b7d8271f8a4..facad478103 100644 +--- a/Lib/inspect.py ++++ b/Lib/inspect.py +@@ -57,6 +57,7 @@ + "CO_VARARGS", + "CO_VARKEYWORDS", + "CO_HAS_DOCSTRING", ++ "CO_METHOD", + "ClassFoundException", + "ClosureVars", + "EndOfBlock", +@@ -857,8 +858,7 @@ + Return None if no way can be identified to get the source. + """ + filename = getfile(object) +- all_bytecode_suffixes = importlib.machinery.DEBUG_BYTECODE_SUFFIXES[:] +- all_bytecode_suffixes += importlib.machinery.OPTIMIZED_BYTECODE_SUFFIXES[:] ++ all_bytecode_suffixes = importlib.machinery.BYTECODE_SUFFIXES[:] + if any(filename.endswith(s) for s in all_bytecode_suffixes): + filename = (os.path.splitext(filename)[0] + + importlib.machinery.SOURCE_SUFFIXES[0]) +diff --git a/Lib/locale.py b/Lib/locale.py +index d8c09f1123d..213d5e93418 100644 +--- a/Lib/locale.py ++++ b/Lib/locale.py +@@ -860,6 +860,24 @@ + # updated 'ca_es@valencia' -> 'ca_ES.ISO8859-15@valencia' to 'ca_ES.UTF-8@valencia' + # updated 'kk_kz' -> 'kk_KZ.RK1048' to 'kk_KZ.ptcp154' + # updated 'russian' -> 'ru_RU.ISO8859-5' to 'ru_RU.KOI8-R' ++# ++# SS 2025-02-04: ++# Updated alias mapping with glibc 2.41 supported locales and the latest ++# X lib alias mapping. ++# ++# These are the differences compared to the old mapping (Python 3.13.1 ++# and older): ++# ++# updated 'c.utf8' -> 'C.UTF-8' to 'en_US.UTF-8' ++# updated 'de_it' -> 'de_IT.ISO8859-1' to 'de_IT.UTF-8' ++# removed 'de_li.utf8' ++# updated 'en_il' -> 'en_IL.UTF-8' to 'en_IL.ISO8859-1' ++# removed 'english.iso88591' ++# updated 'es_cu' -> 'es_CU.UTF-8' to 'es_CU.ISO8859-1' ++# updated 'russian' -> 'ru_RU.KOI8-R' to 'ru_RU.ISO8859-5' ++# updated 'sr@latn' -> 'sr_CS.UTF-8@latin' to 'sr_RS.UTF-8@latin' ++# removed 'univ' ++# removed 'universal' + + locale_alias = { + 'a3': 'az_AZ.KOI8-C', +@@ -939,7 +957,7 @@ + 'c.ascii': 'C', + 'c.en': 'C', + 'c.iso88591': 'en_US.ISO8859-1', +- 'c.utf8': 'C.UTF-8', ++ 'c.utf8': 'en_US.UTF-8', + 'c_c': 'C', + 'c_c.c': 'C', + 'ca': 'ca_ES.ISO8859-1', +@@ -956,6 +974,7 @@ + 'chr_us': 'chr_US.UTF-8', + 'ckb_iq': 'ckb_IQ.UTF-8', + 'cmn_tw': 'cmn_TW.UTF-8', ++ 'crh_ru': 'crh_RU.UTF-8', + 'crh_ua': 'crh_UA.UTF-8', + 'croatian': 'hr_HR.ISO8859-2', + 'cs': 'cs_CZ.ISO8859-2', +@@ -977,11 +996,12 @@ + 'de_be': 'de_BE.ISO8859-1', + 'de_ch': 'de_CH.ISO8859-1', + 'de_de': 'de_DE.ISO8859-1', +- 'de_it': 'de_IT.ISO8859-1', +- 'de_li.utf8': 'de_LI.UTF-8', ++ 'de_it': 'de_IT.UTF-8', ++ 'de_li': 'de_LI.ISO8859-1', + 'de_lu': 'de_LU.ISO8859-1', + 'deutsch': 'de_DE.ISO8859-1', + 'doi_in': 'doi_IN.UTF-8', ++ 'dsb_de': 'dsb_DE.UTF-8', + 'dutch': 'nl_NL.ISO8859-1', + 'dutch.iso88591': 'nl_BE.ISO8859-1', + 'dv_mv': 'dv_MV.UTF-8', +@@ -1004,7 +1024,7 @@ + 'en_gb': 'en_GB.ISO8859-1', + 'en_hk': 'en_HK.ISO8859-1', + 'en_ie': 'en_IE.ISO8859-1', +- 'en_il': 'en_IL.UTF-8', ++ 'en_il': 'en_IL.ISO8859-1', + 'en_in': 'en_IN.ISO8859-1', + 'en_ng': 'en_NG.UTF-8', + 'en_nz': 'en_NZ.ISO8859-1', +@@ -1020,7 +1040,6 @@ + 'en_zw.utf8': 'en_ZS.UTF-8', + 'eng_gb': 'en_GB.ISO8859-1', + 'english': 'en_EN.ISO8859-1', +- 'english.iso88591': 'en_US.ISO8859-1', + 'english_uk': 'en_GB.ISO8859-1', + 'english_united-states': 'en_US.ISO8859-1', + 'english_united-states.437': 'C', +@@ -1036,7 +1055,7 @@ + 'es_cl': 'es_CL.ISO8859-1', + 'es_co': 'es_CO.ISO8859-1', + 'es_cr': 'es_CR.ISO8859-1', +- 'es_cu': 'es_CU.UTF-8', ++ 'es_cu': 'es_CU.ISO8859-1', + 'es_do': 'es_DO.ISO8859-1', + 'es_ec': 'es_EC.ISO8859-1', + 'es_es': 'es_ES.ISO8859-1', +@@ -1086,6 +1105,7 @@ + 'ga_ie': 'ga_IE.ISO8859-1', + 'galego': 'gl_ES.ISO8859-1', + 'galician': 'gl_ES.ISO8859-1', ++ 'gbm_in': 'gbm_IN.UTF-8', + 'gd': 'gd_GB.ISO8859-1', + 'gd_gb': 'gd_GB.ISO8859-1', + 'ger_de': 'de_DE.ISO8859-1', +@@ -1126,6 +1146,7 @@ + 'icelandic': 'is_IS.ISO8859-1', + 'id': 'id_ID.ISO8859-1', + 'id_id': 'id_ID.ISO8859-1', ++ 'ie': 'ie.UTF-8', + 'ig_ng': 'ig_NG.UTF-8', + 'ik_ca': 'ik_CA.UTF-8', + 'in': 'id_ID.ISO8859-1', +@@ -1180,6 +1201,7 @@ + 'ks_in': 'ks_IN.UTF-8', + 'ks_in@devanagari.utf8': 'ks_IN.UTF-8@devanagari', + 'ku_tr': 'ku_TR.ISO8859-9', ++ 'kv_ru': 'kv_RU.UTF-8', + 'kw': 'kw_GB.ISO8859-1', + 'kw_gb': 'kw_GB.ISO8859-1', + 'ky': 'ky_KG.UTF-8', +@@ -1198,6 +1220,7 @@ + 'lo_la.mulelao1': 'lo_LA.MULELAO-1', + 'lt': 'lt_LT.ISO8859-13', + 'lt_lt': 'lt_LT.ISO8859-13', ++ 'ltg_lv.utf8': 'ltg_LV.UTF-8', + 'lv': 'lv_LV.ISO8859-13', + 'lv_lv': 'lv_LV.ISO8859-13', + 'lzh_tw': 'lzh_TW.UTF-8', +@@ -1205,6 +1228,7 @@ + 'mai': 'mai_IN.UTF-8', + 'mai_in': 'mai_IN.UTF-8', + 'mai_np': 'mai_NP.UTF-8', ++ 'mdf_ru': 'mdf_RU.UTF-8', + 'mfe_mu': 'mfe_MU.UTF-8', + 'mg_mg': 'mg_MG.ISO8859-15', + 'mhr_ru': 'mhr_RU.UTF-8', +@@ -1218,6 +1242,7 @@ + 'ml_in': 'ml_IN.UTF-8', + 'mn_mn': 'mn_MN.UTF-8', + 'mni_in': 'mni_IN.UTF-8', ++ 'mnw_mm': 'mnw_MM.UTF-8', + 'mr': 'mr_IN.UTF-8', + 'mr_in': 'mr_IN.UTF-8', + 'ms': 'ms_MY.ISO8859-1', +@@ -1286,6 +1311,7 @@ + 'pt_pt': 'pt_PT.ISO8859-1', + 'quz_pe': 'quz_PE.UTF-8', + 'raj_in': 'raj_IN.UTF-8', ++ 'rif_ma': 'rif_MA.UTF-8', + 'ro': 'ro_RO.ISO8859-2', + 'ro_ro': 'ro_RO.ISO8859-2', + 'romanian': 'ro_RO.ISO8859-2', +@@ -1293,12 +1319,14 @@ + 'ru_ru': 'ru_RU.UTF-8', + 'ru_ua': 'ru_UA.KOI8-U', + 'rumanian': 'ro_RO.ISO8859-2', +- 'russian': 'ru_RU.KOI8-R', ++ 'russian': 'ru_RU.ISO8859-5', + 'rw': 'rw_RW.ISO8859-1', + 'rw_rw': 'rw_RW.ISO8859-1', + 'sa_in': 'sa_IN.UTF-8', ++ 'sah_ru': 'sah_RU.UTF-8', + 'sat_in': 'sat_IN.UTF-8', + 'sc_it': 'sc_IT.UTF-8', ++ 'scn_it': 'scn_IT.UTF-8', + 'sd': 'sd_IN.UTF-8', + 'sd_in': 'sd_IN.UTF-8', + 'sd_in@devanagari.utf8': 'sd_IN.UTF-8@devanagari', +@@ -1340,7 +1368,7 @@ + 'sq_mk': 'sq_MK.UTF-8', + 'sr': 'sr_RS.UTF-8', + 'sr@cyrillic': 'sr_RS.UTF-8', +- 'sr@latn': 'sr_CS.UTF-8@latin', ++ 'sr@latn': 'sr_RS.UTF-8@latin', + 'sr_cs': 'sr_CS.UTF-8', + 'sr_cs.iso88592@latn': 'sr_CS.ISO8859-2', + 'sr_cs@latn': 'sr_CS.UTF-8@latin', +@@ -1359,14 +1387,17 @@ + 'sr_yu@cyrillic': 'sr_RS.UTF-8', + 'ss': 'ss_ZA.ISO8859-1', + 'ss_za': 'ss_ZA.ISO8859-1', ++ 'ssy_er': 'ssy_ER.UTF-8', + 'st': 'st_ZA.ISO8859-1', + 'st_za': 'st_ZA.ISO8859-1', ++ 'su_id': 'su_ID.UTF-8', + 'sv': 'sv_SE.ISO8859-1', + 'sv_fi': 'sv_FI.ISO8859-1', + 'sv_se': 'sv_SE.ISO8859-1', + 'sw_ke': 'sw_KE.UTF-8', + 'sw_tz': 'sw_TZ.UTF-8', + 'swedish': 'sv_SE.ISO8859-1', ++ 'syr': 'syr.UTF-8', + 'szl_pl': 'szl_PL.UTF-8', + 'ta': 'ta_IN.TSCII-0', + 'ta_in': 'ta_IN.TSCII-0', +@@ -1393,6 +1424,7 @@ + 'tn': 'tn_ZA.ISO8859-15', + 'tn_za': 'tn_ZA.ISO8859-15', + 'to_to': 'to_TO.UTF-8', ++ 'tok': 'tok.UTF-8', + 'tpi_pg': 'tpi_PG.UTF-8', + 'tr': 'tr_TR.ISO8859-9', + 'tr_cy': 'tr_CY.ISO8859-9', +@@ -1407,8 +1439,7 @@ + 'ug_cn': 'ug_CN.UTF-8', + 'uk': 'uk_UA.KOI8-U', + 'uk_ua': 'uk_UA.KOI8-U', +- 'univ': 'en_US.utf', +- 'universal': 'en_US.utf', ++ 'univ.utf8': 'en_US.UTF-8', + 'universal.utf8@ucs4': 'en_US.UTF-8', + 'unm_us': 'unm_US.UTF-8', + 'ur': 'ur_PK.CP1256', +@@ -1437,6 +1468,7 @@ + 'yo_ng': 'yo_NG.UTF-8', + 'yue_hk': 'yue_HK.UTF-8', + 'yuw_pg': 'yuw_PG.UTF-8', ++ 'zgh_ma': 'zgh_MA.UTF-8', + 'zh': 'zh_CN.eucCN', + 'zh_cn': 'zh_CN.gb2312', + 'zh_cn.big5': 'zh_TW.big5', +diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py +index 1cba64fd554..9abadbf5cdd 100644 +--- a/Lib/logging/handlers.py ++++ b/Lib/logging/handlers.py +@@ -855,7 +855,7 @@ + } + + def __init__(self, address=('localhost', SYSLOG_UDP_PORT), +- facility=LOG_USER, socktype=None): ++ facility=LOG_USER, socktype=None, timeout=None): + """ + Initialize a handler. + +@@ -872,6 +872,7 @@ + self.address = address + self.facility = facility + self.socktype = socktype ++ self.timeout = timeout + self.socket = None + self.createSocket() + +@@ -933,6 +934,8 @@ + err = sock = None + try: + sock = socket.socket(af, socktype, proto) ++ if self.timeout: ++ sock.settimeout(self.timeout) + if socktype == socket.SOCK_STREAM: + sock.connect(sa) + break +@@ -1040,7 +1043,8 @@ + only be used when authentication credentials are supplied. The tuple + will be either an empty tuple, or a single-value tuple with the name + of a keyfile, or a 2-value tuple with the names of the keyfile and +- certificate file. (This tuple is passed to the `starttls` method). ++ certificate file. (This tuple is passed to the ++ `ssl.SSLContext.load_cert_chain` method). + A timeout in seconds can be specified for the SMTP connection (the + default is one second). + """ +@@ -1093,8 +1097,23 @@ + msg.set_content(self.format(record)) + if self.username: + if self.secure is not None: ++ import ssl ++ ++ try: ++ keyfile = self.secure[0] ++ except IndexError: ++ keyfile = None ++ ++ try: ++ certfile = self.secure[1] ++ except IndexError: ++ certfile = None ++ ++ context = ssl._create_stdlib_context( ++ certfile=certfile, keyfile=keyfile ++ ) + smtp.ehlo() +- smtp.starttls(*self.secure) ++ smtp.starttls(context=context) + smtp.ehlo() + smtp.login(self.username, self.password) + smtp.send_message(msg) +diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py +index 710aba9685e..d429212d447 100644 +--- a/Lib/multiprocessing/connection.py ++++ b/Lib/multiprocessing/connection.py +@@ -853,7 +853,7 @@ + _LEGACY_LENGTHS = (_MD5ONLY_MESSAGE_LENGTH, _MD5_DIGEST_LEN) + + +-def _get_digest_name_and_payload(message: bytes) -> (str, bytes): ++def _get_digest_name_and_payload(message): # type: (bytes) -> tuple[str, bytes] + """Returns a digest name and the payload for a response hash. + + If a legacy protocol is detected based on the message length +diff --git a/Lib/multiprocessing/forkserver.py b/Lib/multiprocessing/forkserver.py +index df9b9be9d18..681af2610e9 100644 +--- a/Lib/multiprocessing/forkserver.py ++++ b/Lib/multiprocessing/forkserver.py +@@ -382,13 +382,14 @@ + # + + def read_signed(fd): +- data = b'' +- length = SIGNED_STRUCT.size +- while len(data) < length: +- s = os.read(fd, length - len(data)) +- if not s: ++ data = bytearray(SIGNED_STRUCT.size) ++ unread = memoryview(data) ++ while unread: ++ count = os.readinto(fd, unread) ++ if count == 0: + raise EOFError('unexpected EOF') +- data += s ++ unread = unread[count:] ++ + return SIGNED_STRUCT.unpack(data)[0] + + def write_signed(fd, n): +diff --git a/Lib/multiprocessing/resource_tracker.py b/Lib/multiprocessing/resource_tracker.py +index 20ddd9c50e3..90e036ae905 100644 +--- a/Lib/multiprocessing/resource_tracker.py ++++ b/Lib/multiprocessing/resource_tracker.py +@@ -155,13 +155,14 @@ + # that can make the child die before it registers signal handlers + # for SIGINT and SIGTERM. The mask is unregistered after spawning + # the child. ++ prev_sigmask = None + try: + if _HAVE_SIGMASK: +- signal.pthread_sigmask(signal.SIG_BLOCK, _IGNORED_SIGNALS) ++ prev_sigmask = signal.pthread_sigmask(signal.SIG_BLOCK, _IGNORED_SIGNALS) + pid = util.spawnv_passfds(exe, args, fds_to_pass) + finally: +- if _HAVE_SIGMASK: +- signal.pthread_sigmask(signal.SIG_UNBLOCK, _IGNORED_SIGNALS) ++ if prev_sigmask is not None: ++ signal.pthread_sigmask(signal.SIG_SETMASK, prev_sigmask) + except: + os.close(w) + raise +diff --git a/Lib/multiprocessing/synchronize.py b/Lib/multiprocessing/synchronize.py +index 4f72373c951..edd6c2543a7 100644 +--- a/Lib/multiprocessing/synchronize.py ++++ b/Lib/multiprocessing/synchronize.py +@@ -359,7 +359,7 @@ + return True + return False + +- def __repr__(self) -> str: ++ def __repr__(self): + set_status = 'set' if self.is_set() else 'unset' + return f"<{type(self).__qualname__} at {id(self):#x} {set_status}>" + # +diff --git a/Lib/opcode.py b/Lib/opcode.py +index 974f4d35e2a..4ee0d64026b 100644 +--- a/Lib/opcode.py ++++ b/Lib/opcode.py +@@ -17,8 +17,9 @@ + EXTENDED_ARG = opmap['EXTENDED_ARG'] + + opname = ['<%r>' % (op,) for op in range(max(opmap.values()) + 1)] +-for op, i in opmap.items(): +- opname[i] = op ++for m in (opmap, _specialized_opmap): ++ for op, i in m.items(): ++ opname[i] = op + + cmp_op = ('<', '<=', '==', '!=', '>', '>=') + +@@ -51,6 +52,7 @@ + }, + "BINARY_OP": { + "counter": 1, ++ "descr": 4, + }, + "UNPACK_SEQUENCE": { + "counter": 1, +diff --git a/Lib/optparse.py b/Lib/optparse.py +index cbe3451ced8..38cf16d21ef 100644 +--- a/Lib/optparse.py ++++ b/Lib/optparse.py +@@ -74,7 +74,6 @@ + """ + + import sys, os +-import textwrap + from gettext import gettext as _, ngettext + + +@@ -252,6 +251,7 @@ + Format a paragraph of free-form text for inclusion in the + help output at the current indentation level. + """ ++ import textwrap + text_width = max(self.width - self.current_indent, 11) + indent = " "*self.current_indent + return textwrap.fill(text, +@@ -308,6 +308,7 @@ + indent_first = 0 + result.append(opts) + if option.help: ++ import textwrap + help_text = self.expand_default(option) + help_lines = textwrap.wrap(help_text, self.help_width) + result.append("%*s%s\n" % (indent_first, "", help_lines[0])) +diff --git a/Lib/pathlib/_abc.py b/Lib/pathlib/_abc.py +index b4560295300..800d1b4503d 100644 +--- a/Lib/pathlib/_abc.py ++++ b/Lib/pathlib/_abc.py +@@ -7,17 +7,14 @@ + it's developed alongside pathlib. If it finds success and maturity as a PyPI + package, it could become a public part of the standard library. + +-Two base classes are defined here -- PurePathBase and PathBase -- that +-resemble pathlib's PurePath and Path respectively. ++Three base classes are defined here -- JoinablePath, ReadablePath and ++WritablePath. + """ + + import functools +-import operator + import posixpath +-from errno import EINVAL +-from glob import _GlobberBase, _no_recurse_symlinks +-from stat import S_ISDIR, S_ISLNK, S_ISREG +-from pathlib._os import copyfileobj ++from glob import _PathGlobber, _no_recurse_symlinks ++from pathlib._os import magic_open, CopyReader, CopyWriter + + + @functools.cache +@@ -25,88 +22,50 @@ + return parser.normcase('Aa') == 'Aa' + + +-class PathGlobber(_GlobberBase): ++def _explode_path(path): + """ +- Class providing shell-style globbing for path objects. ++ Split the path into a 2-tuple (anchor, parts), where *anchor* is the ++ uppermost parent of the path (equivalent to path.parents[-1]), and ++ *parts* is a reversed list of parts following the anchor. + """ +- +- lexists = operator.methodcaller('exists', follow_symlinks=False) +- add_slash = operator.methodcaller('joinpath', '') +- scandir = operator.methodcaller('_scandir') +- +- @staticmethod +- def concat_path(path, text): +- """Appends text to the given path.""" +- return path.with_segments(str(path) + text) ++ split = path.parser.split ++ path = str(path) ++ parent, name = split(path) ++ names = [] ++ while path != parent: ++ names.append(name) ++ path = parent ++ parent, name = split(path) ++ return path, names + + +-class PurePathBase: ++class JoinablePath: + """Base class for pure path objects. + + This class *does not* provide several magic methods that are defined in +- its subclass PurePath. They are: __fspath__, __bytes__, __reduce__, +- __hash__, __eq__, __lt__, __le__, __gt__, __ge__. Its initializer and path +- joining methods accept only strings, not os.PathLike objects more broadly. ++ its subclass PurePath. They are: __init__, __fspath__, __bytes__, ++ __reduce__, __hash__, __eq__, __lt__, __le__, __gt__, __ge__. + """ + +- __slots__ = ( +- # The `_raw_paths` slot stores unjoined string paths. This is set in +- # the `__init__()` method. +- '_raw_paths', +- ) ++ __slots__ = () + parser = posixpath +- _globber = PathGlobber +- +- def __init__(self, *args): +- for arg in args: +- if not isinstance(arg, str): +- raise TypeError( +- f"argument should be a str, not {type(arg).__name__!r}") +- self._raw_paths = list(args) + + def with_segments(self, *pathsegments): + """Construct a new path object from any number of path-like objects. + Subclasses may override this method to customize how new path objects + are created from methods like `iterdir()`. + """ +- return type(self)(*pathsegments) ++ raise NotImplementedError + + def __str__(self): + """Return the string representation of the path, suitable for + passing to system calls.""" +- paths = self._raw_paths +- if len(paths) == 1: +- return paths[0] +- elif paths: +- # Join path segments from the initializer. +- path = self.parser.join(*paths) +- # Cache the joined path. +- paths.clear() +- paths.append(path) +- return path +- else: +- paths.append('') +- return '' +- +- def as_posix(self): +- """Return the string representation of the path with forward (/) +- slashes.""" +- return str(self).replace(self.parser.sep, '/') +- +- @property +- def drive(self): +- """The drive prefix (letter or UNC path), if any.""" +- return self.parser.splitdrive(self.anchor)[0] +- +- @property +- def root(self): +- """The root of the path, if any.""" +- return self.parser.splitdrive(self.anchor)[1] ++ raise NotImplementedError + + @property + def anchor(self): + """The concatenation of the drive and root, or ''.""" +- return self._stack[0] ++ return _explode_path(self)[0] + + @property + def name(self): +@@ -174,56 +133,11 @@ + else: + return self.with_name(stem + suffix) + +- def relative_to(self, other, *, walk_up=False): +- """Return the relative path to another path identified by the passed +- arguments. If the operation is not possible (because this is not +- related to the other path), raise ValueError. +- +- The *walk_up* parameter controls whether `..` may be used to resolve +- the path. +- """ +- if not isinstance(other, PurePathBase): +- other = self.with_segments(other) +- anchor0, parts0 = self._stack +- anchor1, parts1 = other._stack +- if anchor0 != anchor1: +- raise ValueError(f"{str(self)!r} and {str(other)!r} have different anchors") +- while parts0 and parts1 and parts0[-1] == parts1[-1]: +- parts0.pop() +- parts1.pop() +- for part in parts1: +- if not part or part == '.': +- pass +- elif not walk_up: +- raise ValueError(f"{str(self)!r} is not in the subpath of {str(other)!r}") +- elif part == '..': +- raise ValueError(f"'..' segment in {str(other)!r} cannot be walked") +- else: +- parts0.append('..') +- return self.with_segments(*reversed(parts0)) +- +- def is_relative_to(self, other): +- """Return True if the path is relative to another path or False. +- """ +- if not isinstance(other, PurePathBase): +- other = self.with_segments(other) +- anchor0, parts0 = self._stack +- anchor1, parts1 = other._stack +- if anchor0 != anchor1: +- return False +- while parts0 and parts1 and parts0[-1] == parts1[-1]: +- parts0.pop() +- parts1.pop() +- for part in parts1: +- if part and part != '.': +- return False +- return True +- + @property + def parts(self): + """An object providing sequence-like access to the + components in the filesystem path.""" +- anchor, parts = self._stack ++ anchor, parts = _explode_path(self) + if anchor: + parts.append(anchor) + return tuple(reversed(parts)) +@@ -234,37 +148,20 @@ + paths) or a totally different path (if one of the arguments is + anchored). + """ +- return self.with_segments(*self._raw_paths, *pathsegments) ++ return self.with_segments(str(self), *pathsegments) + + def __truediv__(self, key): + try: +- return self.with_segments(*self._raw_paths, key) ++ return self.with_segments(str(self), key) + except TypeError: + return NotImplemented + + def __rtruediv__(self, key): + try: +- return self.with_segments(key, *self._raw_paths) ++ return self.with_segments(key, str(self)) + except TypeError: + return NotImplemented + +- @property +- def _stack(self): +- """ +- Split the path into a 2-tuple (anchor, parts), where *anchor* is the +- uppermost parent of the path (equivalent to path.parents[-1]), and +- *parts* is a reversed list of parts following the anchor. +- """ +- split = self.parser.split +- path = str(self) +- parent, name = split(path) +- names = [] +- while path != parent: +- names.append(name) +- path = parent +- parent, name = split(path) +- return path, names +- + @property + def parent(self): + """The logical parent of the path.""" +@@ -287,59 +184,22 @@ + parent = split(path)[0] + return tuple(parents) + +- def is_absolute(self): +- """True if the path is absolute (has both a root and, if applicable, +- a drive).""" +- return self.parser.isabs(str(self)) +- +- @property +- def _pattern_str(self): +- """The path expressed as a string, for use in pattern-matching.""" +- return str(self) +- +- def match(self, path_pattern, *, case_sensitive=None): +- """ +- Return True if this path matches the given pattern. If the pattern is +- relative, matching is done from the right; otherwise, the entire path +- is matched. The recursive wildcard '**' is *not* supported by this +- method. +- """ +- if not isinstance(path_pattern, PurePathBase): +- path_pattern = self.with_segments(path_pattern) +- if case_sensitive is None: +- case_sensitive = _is_case_sensitive(self.parser) +- sep = path_pattern.parser.sep +- path_parts = self.parts[::-1] +- pattern_parts = path_pattern.parts[::-1] +- if not pattern_parts: +- raise ValueError("empty pattern") +- if len(path_parts) < len(pattern_parts): +- return False +- if len(path_parts) > len(pattern_parts) and path_pattern.anchor: +- return False +- globber = self._globber(sep, case_sensitive) +- for path_part, pattern_part in zip(path_parts, pattern_parts): +- match = globber.compile(pattern_part) +- if match(path_part) is None: +- return False +- return True +- + def full_match(self, pattern, *, case_sensitive=None): + """ + Return True if this path matches the given glob-style pattern. The + pattern is matched against the entire path. + """ +- if not isinstance(pattern, PurePathBase): ++ if not isinstance(pattern, JoinablePath): + pattern = self.with_segments(pattern) + if case_sensitive is None: + case_sensitive = _is_case_sensitive(self.parser) +- globber = self._globber(pattern.parser.sep, case_sensitive, recursive=True) +- match = globber.compile(pattern._pattern_str) +- return match(self._pattern_str) is not None ++ globber = _PathGlobber(pattern.parser.sep, case_sensitive, recursive=True) ++ match = globber.compile(str(pattern)) ++ return match(str(self)) is not None + + + +-class PathBase(PurePathBase): ++class ReadablePath(JoinablePath): + """Base class for concrete path objects. + + This class provides dummy implementations for many methods that derived +@@ -354,15 +214,14 @@ + """ + __slots__ = () + +- def stat(self, *, follow_symlinks=True): ++ @property ++ def info(self): + """ +- Return the result of the stat() system call on this path, like +- os.stat() does. ++ A PathInfo object that exposes the file type and other file attributes ++ of this path. + """ + raise NotImplementedError + +- # Convenience functions for querying the stat results +- + def exists(self, *, follow_symlinks=True): + """ + Whether this path exists. +@@ -370,70 +229,35 @@ + This method normally follows symlinks; to check whether a symlink exists, + add the argument follow_symlinks=False. + """ +- try: +- self.stat(follow_symlinks=follow_symlinks) +- except (OSError, ValueError): +- return False +- return True ++ info = self.joinpath().info ++ return info.exists(follow_symlinks=follow_symlinks) + + def is_dir(self, *, follow_symlinks=True): + """ + Whether this path is a directory. + """ +- try: +- return S_ISDIR(self.stat(follow_symlinks=follow_symlinks).st_mode) +- except (OSError, ValueError): +- return False ++ info = self.joinpath().info ++ return info.is_dir(follow_symlinks=follow_symlinks) + + def is_file(self, *, follow_symlinks=True): + """ + Whether this path is a regular file (also True for symlinks pointing + to regular files). + """ +- try: +- return S_ISREG(self.stat(follow_symlinks=follow_symlinks).st_mode) +- except (OSError, ValueError): +- return False ++ info = self.joinpath().info ++ return info.is_file(follow_symlinks=follow_symlinks) + + def is_symlink(self): + """ + Whether this path is a symbolic link. + """ +- try: +- return S_ISLNK(self.stat(follow_symlinks=False).st_mode) +- except (OSError, ValueError): +- return False ++ info = self.joinpath().info ++ return info.is_symlink() + +- def _ensure_different_file(self, other_path): ++ def __open_rb__(self, buffering=-1): + """ +- Raise OSError(EINVAL) if both paths refer to the same file. +- """ +- pass +- +- def _ensure_distinct_path(self, other_path): +- """ +- Raise OSError(EINVAL) if the other path is within this path. +- """ +- # Note: there is no straightforward, foolproof algorithm to determine +- # if one directory is within another (a particularly perverse example +- # would be a single network share mounted in one location via NFS, and +- # in another location via CIFS), so we simply checks whether the +- # other path is lexically equal to, or within, this path. +- if self == other_path: +- err = OSError(EINVAL, "Source and target are the same path") +- elif self in other_path.parents: +- err = OSError(EINVAL, "Source path is a parent of target path") +- else: +- return +- err.filename = str(self) +- err.filename2 = str(other_path) +- raise err +- +- def open(self, mode='r', buffering=-1, encoding=None, +- errors=None, newline=None): +- """ +- Open the file pointed to by this path and return a file object, as +- the built-in open() function does. ++ Open the file pointed to by this path for reading in binary mode and ++ return a file object, like open(mode='rb'). + """ + raise NotImplementedError + +@@ -441,44 +265,16 @@ + """ + Open the file in bytes mode, read it, and close the file. + """ +- with self.open(mode='rb', buffering=0) as f: ++ with magic_open(self, mode='rb', buffering=0) as f: + return f.read() + + def read_text(self, encoding=None, errors=None, newline=None): + """ + Open the file in text mode, read it, and close the file. + """ +- with self.open(mode='r', encoding=encoding, errors=errors, newline=newline) as f: ++ with magic_open(self, mode='r', encoding=encoding, errors=errors, newline=newline) as f: + return f.read() + +- def write_bytes(self, data): +- """ +- Open the file in bytes mode, write to it, and close the file. +- """ +- # type-check for the buffer interface before truncating the file +- view = memoryview(data) +- with self.open(mode='wb') as f: +- return f.write(view) +- +- def write_text(self, data, encoding=None, errors=None, newline=None): +- """ +- Open the file in text mode, write to it, and close the file. +- """ +- if not isinstance(data, str): +- raise TypeError('data must be str, not %s' % +- data.__class__.__name__) +- with self.open(mode='w', encoding=encoding, errors=errors, newline=newline) as f: +- return f.write(data) +- +- def _scandir(self): +- """Yield os.DirEntry-like objects of the directory contents. +- +- The children are yielded in arbitrary order, and the +- special entries '.' and '..' are not included. +- """ +- import contextlib +- return contextlib.nullcontext(self.iterdir()) +- + def iterdir(self): + """Yield path objects of the directory contents. + +@@ -487,37 +283,33 @@ + """ + raise NotImplementedError + +- def _glob_selector(self, parts, case_sensitive, recurse_symlinks): +- if case_sensitive is None: +- case_sensitive = _is_case_sensitive(self.parser) +- case_pedantic = False +- else: +- # The user has expressed a case sensitivity choice, but we don't +- # know the case sensitivity of the underlying filesystem, so we +- # must use scandir() for everything, including non-wildcard parts. +- case_pedantic = True +- recursive = True if recurse_symlinks else _no_recurse_symlinks +- globber = self._globber(self.parser.sep, case_sensitive, case_pedantic, recursive) +- return globber.selector(parts) +- + def glob(self, pattern, *, case_sensitive=None, recurse_symlinks=True): + """Iterate over this subtree and yield all existing files (of any + kind, including directories) matching the given relative pattern. + """ +- if not isinstance(pattern, PurePathBase): ++ if not isinstance(pattern, JoinablePath): + pattern = self.with_segments(pattern) +- anchor, parts = pattern._stack ++ anchor, parts = _explode_path(pattern) + if anchor: + raise NotImplementedError("Non-relative patterns are unsupported") +- select = self._glob_selector(parts, case_sensitive, recurse_symlinks) +- return select(self) ++ if case_sensitive is None: ++ case_sensitive = _is_case_sensitive(self.parser) ++ case_pedantic = False ++ elif case_sensitive == _is_case_sensitive(self.parser): ++ case_pedantic = False ++ else: ++ case_pedantic = True ++ recursive = True if recurse_symlinks else _no_recurse_symlinks ++ globber = _PathGlobber(self.parser.sep, case_sensitive, case_pedantic, recursive) ++ select = globber.selector(parts) ++ return select(self.joinpath('')) + + def rglob(self, pattern, *, case_sensitive=None, recurse_symlinks=True): + """Recursively yield all existing files (of any kind, including + directories) matching the given relative pattern, anywhere in + this subtree. + """ +- if not isinstance(pattern, PurePathBase): ++ if not isinstance(pattern, JoinablePath): + pattern = self.with_segments(pattern) + pattern = '**' / pattern + return self.glob(pattern, case_sensitive=case_sensitive, recurse_symlinks=recurse_symlinks) +@@ -535,18 +327,16 @@ + if not top_down: + paths.append((path, dirnames, filenames)) + try: +- with path._scandir() as entries: +- for entry in entries: +- name = entry.name +- try: +- if entry.is_dir(follow_symlinks=follow_symlinks): +- if not top_down: +- paths.append(path.joinpath(name)) +- dirnames.append(name) +- else: +- filenames.append(name) +- except OSError: +- filenames.append(name) ++ for child in path.iterdir(): ++ try: ++ if child.info.is_dir(follow_symlinks=follow_symlinks): ++ if not top_down: ++ paths.append(child) ++ dirnames.append(child.name) ++ else: ++ filenames.append(child.name) ++ except OSError: ++ filenames.append(child.name) + except OSError as error: + if on_error is not None: + on_error(error) +@@ -564,95 +354,22 @@ + """ + raise NotImplementedError + +- def symlink_to(self, target, target_is_directory=False): +- """ +- Make this path a symlink pointing to the target path. +- Note the order of arguments (link, target) is the reverse of os.symlink. +- """ +- raise NotImplementedError ++ _copy_reader = property(CopyReader) + +- def _symlink_to_target_of(self, link): +- """ +- Make this path a symlink with the same target as the given link. This +- is used by copy(). +- """ +- self.symlink_to(link.readlink()) +- +- def mkdir(self, mode=0o777, parents=False, exist_ok=False): +- """ +- Create a new directory at this given path. +- """ +- raise NotImplementedError +- +- # Metadata keys supported by this path type. +- _readable_metadata = _writable_metadata = frozenset() +- +- def _read_metadata(self, keys=None, *, follow_symlinks=True): +- """ +- Returns path metadata as a dict with string keys. +- """ +- raise NotImplementedError +- +- def _write_metadata(self, metadata, *, follow_symlinks=True): +- """ +- Sets path metadata from the given dict with string keys. +- """ +- raise NotImplementedError +- +- def _copy_metadata(self, target, *, follow_symlinks=True): +- """ +- Copies metadata (permissions, timestamps, etc) from this path to target. +- """ +- # Metadata types supported by both source and target. +- keys = self._readable_metadata & target._writable_metadata +- if keys: +- metadata = self._read_metadata(keys, follow_symlinks=follow_symlinks) +- target._write_metadata(metadata, follow_symlinks=follow_symlinks) +- +- def _copy_file(self, target): +- """ +- Copy the contents of this file to the given target. +- """ +- self._ensure_different_file(target) +- with self.open('rb') as source_f: +- try: +- with target.open('wb') as target_f: +- copyfileobj(source_f, target_f) +- except IsADirectoryError as e: +- if not target.exists(): +- # Raise a less confusing exception. +- raise FileNotFoundError( +- f'Directory does not exist: {target}') from e +- else: +- raise +- +- def copy(self, target, *, follow_symlinks=True, dirs_exist_ok=False, ++ def copy(self, target, follow_symlinks=True, dirs_exist_ok=False, + preserve_metadata=False): + """ + Recursively copy this file or directory tree to the given destination. + """ +- if not isinstance(target, PathBase): ++ if not hasattr(target, '_copy_writer'): + target = self.with_segments(target) +- self._ensure_distinct_path(target) +- stack = [(self, target)] +- while stack: +- src, dst = stack.pop() +- if not follow_symlinks and src.is_symlink(): +- dst._symlink_to_target_of(src) +- if preserve_metadata: +- src._copy_metadata(dst, follow_symlinks=False) +- elif src.is_dir(): +- children = src.iterdir() +- dst.mkdir(exist_ok=dirs_exist_ok) +- stack.extend((child, dst.joinpath(child.name)) +- for child in children) +- if preserve_metadata: +- src._copy_metadata(dst) +- else: +- src._copy_file(dst) +- if preserve_metadata: +- src._copy_metadata(dst) +- return target ++ ++ # Delegate to the target path's CopyWriter object. ++ try: ++ create = target._copy_writer._create ++ except AttributeError: ++ raise TypeError(f"Target is not writable: {target}") from None ++ return create(self, follow_symlinks, dirs_exist_ok, preserve_metadata) + + def copy_into(self, target_dir, *, follow_symlinks=True, + dirs_exist_ok=False, preserve_metadata=False): +@@ -662,7 +379,7 @@ + name = self.name + if not name: + raise ValueError(f"{self!r} has an empty name") +- elif isinstance(target_dir, PathBase): ++ elif hasattr(target_dir, '_copy_writer'): + target = target_dir / name + else: + target = self.with_segments(target_dir, name) +@@ -670,29 +387,47 @@ + dirs_exist_ok=dirs_exist_ok, + preserve_metadata=preserve_metadata) + +- def _delete(self): ++ ++class WritablePath(JoinablePath): ++ __slots__ = () ++ ++ def symlink_to(self, target, target_is_directory=False): + """ +- Delete this file or directory (including all sub-directories). ++ Make this path a symlink pointing to the target path. ++ Note the order of arguments (link, target) is the reverse of os.symlink. + """ + raise NotImplementedError + +- def move(self, target): ++ def mkdir(self, mode=0o777, parents=False, exist_ok=False): + """ +- Recursively move this file or directory tree to the given destination. ++ Create a new directory at this given path. + """ +- target = self.copy(target, follow_symlinks=False, preserve_metadata=True) +- self._delete() +- return target ++ raise NotImplementedError + +- def move_into(self, target_dir): ++ def __open_wb__(self, buffering=-1): + """ +- Move this file or directory tree into the given existing directory. ++ Open the file pointed to by this path for writing in binary mode and ++ return a file object, like open(mode='wb'). + """ +- name = self.name +- if not name: +- raise ValueError(f"{self!r} has an empty name") +- elif isinstance(target_dir, PathBase): +- target = target_dir / name +- else: +- target = self.with_segments(target_dir, name) +- return self.move(target) ++ raise NotImplementedError ++ ++ def write_bytes(self, data): ++ """ ++ Open the file in bytes mode, write to it, and close the file. ++ """ ++ # type-check for the buffer interface before truncating the file ++ view = memoryview(data) ++ with magic_open(self, mode='wb') as f: ++ return f.write(view) ++ ++ def write_text(self, data, encoding=None, errors=None, newline=None): ++ """ ++ Open the file in text mode, write to it, and close the file. ++ """ ++ if not isinstance(data, str): ++ raise TypeError('data must be str, not %s' % ++ data.__class__.__name__) ++ with magic_open(self, mode='w', encoding=encoding, errors=errors, newline=newline) as f: ++ return f.write(data) ++ ++ _copy_writer = property(CopyWriter) +diff --git a/Lib/pathlib/_local.py b/Lib/pathlib/_local.py +index b933dd512ee..956c1920bf6 100644 +--- a/Lib/pathlib/_local.py ++++ b/Lib/pathlib/_local.py +@@ -4,10 +4,10 @@ + import os + import posixpath + import sys +-from errno import EINVAL, EXDEV +-from glob import _StringGlobber ++from errno import * ++from glob import _StringGlobber, _no_recurse_symlinks + from itertools import chain +-from stat import S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO ++from stat import S_ISDIR, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO + from _collections_abc import Sequence + + try: +@@ -19,9 +19,8 @@ + except ImportError: + grp = None + +-from pathlib._os import (copyfile, file_metadata_keys, read_file_metadata, +- write_file_metadata) +-from pathlib._abc import PurePathBase, PathBase ++from pathlib._os import LocalCopyReader, LocalCopyWriter, PathInfo, DirEntryInfo ++from pathlib._abc import JoinablePath, ReadablePath, WritablePath + + + __all__ = [ +@@ -66,7 +65,7 @@ + return "<{}.parents>".format(type(self._path).__name__) + + +-class PurePath(PurePathBase): ++class PurePath(JoinablePath): + """Base class for manipulating paths without I/O. + + PurePath represents a filesystem path and offers operations which +@@ -77,6 +76,10 @@ + """ + + __slots__ = ( ++ # The `_raw_paths` slot stores unjoined string paths. This is set in ++ # the `__init__()` method. ++ '_raw_paths', ++ + # The `_drv`, `_root` and `_tail_cached` slots store parsed and + # normalized parts of the path. They are set when any of the `drive`, + # `root` or `_tail` properties are accessed for the first time. The +@@ -108,7 +111,6 @@ + '_hash', + ) + parser = os.path +- _globber = _StringGlobber + + def __new__(cls, *args, **kwargs): + """Construct a PurePath from one or several strings and or existing +@@ -140,9 +142,15 @@ + "object where __fspath__ returns a str, " + f"not {type(path).__name__!r}") + paths.append(path) +- # Avoid calling super().__init__, as an optimisation + self._raw_paths = paths + ++ def with_segments(self, *pathsegments): ++ """Construct a new path object from any number of path-like objects. ++ Subclasses may override this method to customize how new path objects ++ are created from methods like `iterdir()`. ++ """ ++ return type(self)(*pathsegments) ++ + def joinpath(self, *pathsegments): + """Combine this path with one or several arguments, and return a + new path representing either a subpath (if all arguments are relative +@@ -304,14 +312,34 @@ + parts.append('') + return parts + ++ def as_posix(self): ++ """Return the string representation of the path with forward (/) ++ slashes.""" ++ return str(self).replace(self.parser.sep, '/') ++ ++ @property ++ def _raw_path(self): ++ paths = self._raw_paths ++ if len(paths) == 1: ++ return paths[0] ++ elif paths: ++ # Join path segments from the initializer. ++ path = self.parser.join(*paths) ++ # Cache the joined path. ++ paths.clear() ++ paths.append(path) ++ return path ++ else: ++ paths.append('') ++ return '' ++ + @property + def drive(self): + """The drive prefix (letter or UNC path), if any.""" + try: + return self._drv + except AttributeError: +- raw_path = PurePathBase.__str__(self) +- self._drv, self._root, self._tail_cached = self._parse_path(raw_path) ++ self._drv, self._root, self._tail_cached = self._parse_path(self._raw_path) + return self._drv + + @property +@@ -320,8 +348,7 @@ + try: + return self._root + except AttributeError: +- raw_path = PurePathBase.__str__(self) +- self._drv, self._root, self._tail_cached = self._parse_path(raw_path) ++ self._drv, self._root, self._tail_cached = self._parse_path(self._raw_path) + return self._root + + @property +@@ -329,8 +356,7 @@ + try: + return self._tail_cached + except AttributeError: +- raw_path = PurePathBase.__str__(self) +- self._drv, self._root, self._tail_cached = self._parse_path(raw_path) ++ self._drv, self._root, self._tail_cached = self._parse_path(self._raw_path) + return self._tail_cached + + @property +@@ -490,13 +516,48 @@ + from urllib.parse import quote_from_bytes + return prefix + quote_from_bytes(os.fsencode(path)) + +- @property +- def _pattern_str(self): +- """The path expressed as a string, for use in pattern-matching.""" ++ def full_match(self, pattern, *, case_sensitive=None): ++ """ ++ Return True if this path matches the given glob-style pattern. The ++ pattern is matched against the entire path. ++ """ ++ if not isinstance(pattern, PurePath): ++ pattern = self.with_segments(pattern) ++ if case_sensitive is None: ++ case_sensitive = self.parser is posixpath ++ + # The string representation of an empty path is a single dot ('.'). Empty + # paths shouldn't match wildcards, so we change it to the empty string. +- path_str = str(self) +- return '' if path_str == '.' else path_str ++ path = str(self) if self.parts else '' ++ pattern = str(pattern) if pattern.parts else '' ++ globber = _StringGlobber(self.parser.sep, case_sensitive, recursive=True) ++ return globber.compile(pattern)(path) is not None ++ ++ def match(self, path_pattern, *, case_sensitive=None): ++ """ ++ Return True if this path matches the given pattern. If the pattern is ++ relative, matching is done from the right; otherwise, the entire path ++ is matched. The recursive wildcard '**' is *not* supported by this ++ method. ++ """ ++ if not isinstance(path_pattern, PurePath): ++ path_pattern = self.with_segments(path_pattern) ++ if case_sensitive is None: ++ case_sensitive = self.parser is posixpath ++ path_parts = self.parts[::-1] ++ pattern_parts = path_pattern.parts[::-1] ++ if not pattern_parts: ++ raise ValueError("empty pattern") ++ if len(path_parts) < len(pattern_parts): ++ return False ++ if len(path_parts) > len(pattern_parts) and path_pattern.anchor: ++ return False ++ globber = _StringGlobber(self.parser.sep, case_sensitive) ++ for path_part, pattern_part in zip(path_parts, pattern_parts): ++ match = globber.compile(pattern_part) ++ if match(path_part) is None: ++ return False ++ return True + + # Subclassing os.PathLike makes isinstance() checks slower, + # which in turn makes Path construction slower. Register instead! +@@ -523,7 +584,7 @@ + __slots__ = () + + +-class Path(PathBase, PurePath): ++class Path(WritablePath, ReadablePath, PurePath): + """PurePath subclass that can make system calls. + + Path represents a filesystem path but unlike PurePath, also offers +@@ -532,13 +593,25 @@ + object. You can also instantiate a PosixPath or WindowsPath directly, + but cannot instantiate a WindowsPath on a POSIX system or vice versa. + """ +- __slots__ = () ++ __slots__ = ('_info',) + + def __new__(cls, *args, **kwargs): + if cls is Path: + cls = WindowsPath if os.name == 'nt' else PosixPath + return object.__new__(cls) + ++ @property ++ def info(self): ++ """ ++ A PathInfo object that exposes the file type and other file attributes ++ of this path. ++ """ ++ try: ++ return self._info ++ except AttributeError: ++ self._info = PathInfo(self) ++ return self._info ++ + def stat(self, *, follow_symlinks=True): + """ + Return the result of the stat() system call on this path, like +@@ -570,7 +643,10 @@ + """ + if follow_symlinks: + return os.path.isdir(self) +- return PathBase.is_dir(self, follow_symlinks=follow_symlinks) ++ try: ++ return S_ISDIR(self.stat(follow_symlinks=follow_symlinks).st_mode) ++ except (OSError, ValueError): ++ return False + + def is_file(self, *, follow_symlinks=True): + """ +@@ -579,7 +655,10 @@ + """ + if follow_symlinks: + return os.path.isfile(self) +- return PathBase.is_file(self, follow_symlinks=follow_symlinks) ++ try: ++ return S_ISREG(self.stat(follow_symlinks=follow_symlinks).st_mode) ++ except (OSError, ValueError): ++ return False + + def is_mount(self): + """ +@@ -647,20 +726,6 @@ + return (st.st_ino == other_st.st_ino and + st.st_dev == other_st.st_dev) + +- def _ensure_different_file(self, other_path): +- """ +- Raise OSError(EINVAL) if both paths refer to the same file. +- """ +- try: +- if not self.samefile(other_path): +- return +- except (OSError, ValueError): +- return +- err = OSError(EINVAL, "Source and target are the same file") +- err.filename = str(self) +- err.filename2 = str(other_path) +- raise err +- + def open(self, mode='r', buffering=-1, encoding=None, + errors=None, newline=None): + """ +@@ -671,6 +736,13 @@ + encoding = io.text_encoding(encoding) + return io.open(self, mode, buffering, encoding, errors, newline) + ++ def read_bytes(self): ++ """ ++ Open the file in bytes mode, read it, and close the file. ++ """ ++ with self.open(mode='rb', buffering=0) as f: ++ return f.read() ++ + def read_text(self, encoding=None, errors=None, newline=None): + """ + Open the file in text mode, read it, and close the file. +@@ -678,7 +750,17 @@ + # Call io.text_encoding() here to ensure any warning is raised at an + # appropriate stack level. + encoding = io.text_encoding(encoding) +- return PathBase.read_text(self, encoding, errors, newline) ++ with self.open(mode='r', encoding=encoding, errors=errors, newline=newline) as f: ++ return f.read() ++ ++ def write_bytes(self, data): ++ """ ++ Open the file in bytes mode, write to it, and close the file. ++ """ ++ # type-check for the buffer interface before truncating the file ++ view = memoryview(data) ++ with self.open(mode='wb') as f: ++ return f.write(view) + + def write_text(self, data, encoding=None, errors=None, newline=None): + """ +@@ -687,7 +769,11 @@ + # Call io.text_encoding() here to ensure any warning is raised at an + # appropriate stack level. + encoding = io.text_encoding(encoding) +- return PathBase.write_text(self, data, encoding, errors, newline) ++ if not isinstance(data, str): ++ raise TypeError('data must be str, not %s' % ++ data.__class__.__name__) ++ with self.open(mode='w', encoding=encoding, errors=errors, newline=newline) as f: ++ return f.write(data) + + _remove_leading_dot = operator.itemgetter(slice(2, None)) + _remove_trailing_slash = operator.itemgetter(slice(-1)) +@@ -700,13 +786,11 @@ + path_str = path_str[:-1] + yield path_str + +- def _scandir(self): +- """Yield os.DirEntry-like objects of the directory contents. +- +- The children are yielded in arbitrary order, and the +- special entries '.' and '..' are not included. +- """ +- return os.scandir(self) ++ def _from_dir_entry(self, dir_entry, path_str): ++ path = self.with_segments(path_str) ++ path._str = path_str ++ path._info = DirEntryInfo(dir_entry) ++ return path + + def iterdir(self): + """Yield path objects of the directory contents. +@@ -716,20 +800,31 @@ + """ + root_dir = str(self) + with os.scandir(root_dir) as scandir_it: +- paths = [entry.path for entry in scandir_it] ++ entries = list(scandir_it) + if root_dir == '.': +- paths = map(self._remove_leading_dot, paths) +- return map(self._from_parsed_string, paths) ++ return (self._from_dir_entry(e, e.name) for e in entries) ++ else: ++ return (self._from_dir_entry(e, e.path) for e in entries) + + def glob(self, pattern, *, case_sensitive=None, recurse_symlinks=False): + """Iterate over this subtree and yield all existing files (of any + kind, including directories) matching the given relative pattern. + """ + sys.audit("pathlib.Path.glob", self, pattern) ++ if case_sensitive is None: ++ case_sensitive = self.parser is posixpath ++ case_pedantic = False ++ else: ++ # The user has expressed a case sensitivity choice, but we don't ++ # know the case sensitivity of the underlying filesystem, so we ++ # must use scandir() for everything, including non-wildcard parts. ++ case_pedantic = True + parts = self._parse_pattern(pattern) +- select = self._glob_selector(parts[::-1], case_sensitive, recurse_symlinks) ++ recursive = True if recurse_symlinks else _no_recurse_symlinks ++ globber = _StringGlobber(self.parser.sep, case_sensitive, case_pedantic, recursive) ++ select = globber.selector(parts[::-1]) + root = str(self) +- paths = select(root) ++ paths = select(self.parser.join(root, '')) + + # Normalize results + if root == '.': +@@ -891,24 +986,6 @@ + if not exist_ok or not self.is_dir(): + raise + +- _readable_metadata = _writable_metadata = file_metadata_keys +- _read_metadata = read_file_metadata +- _write_metadata = write_file_metadata +- +- if copyfile: +- def _copy_file(self, target): +- """ +- Copy the contents of this file to the given target. +- """ +- try: +- target = os.fspath(target) +- except TypeError: +- if not isinstance(target, PathBase): +- raise +- PathBase._copy_file(self, target) +- else: +- copyfile(os.fspath(self), target) +- + def chmod(self, mode, *, follow_symlinks=True): + """ + Change the permissions of the path, like os.chmod(). +@@ -978,21 +1055,45 @@ + os.replace(self, target) + return self.with_segments(target) + ++ _copy_reader = property(LocalCopyReader) ++ _copy_writer = property(LocalCopyWriter) ++ + def move(self, target): + """ + Recursively move this file or directory tree to the given destination. + """ +- self._ensure_different_file(target) ++ # Use os.replace() if the target is os.PathLike and on the same FS. + try: +- return self.replace(target) ++ target_str = os.fspath(target) + except TypeError: +- if not isinstance(target, PathBase): +- raise +- except OSError as err: +- if err.errno != EXDEV: +- raise ++ pass ++ else: ++ if not hasattr(target, '_copy_writer'): ++ target = self.with_segments(target_str) ++ target._copy_writer._ensure_different_file(self) ++ try: ++ os.replace(self, target_str) ++ return target ++ except OSError as err: ++ if err.errno != EXDEV: ++ raise + # Fall back to copy+delete. +- return PathBase.move(self, target) ++ target = self.copy(target, follow_symlinks=False, preserve_metadata=True) ++ self._delete() ++ return target ++ ++ def move_into(self, target_dir): ++ """ ++ Move this file or directory tree into the given existing directory. ++ """ ++ name = self.name ++ if not name: ++ raise ValueError(f"{self!r} has an empty name") ++ elif hasattr(target_dir, '_copy_writer'): ++ target = target_dir / name ++ else: ++ target = self.with_segments(target_dir, name) ++ return self.move(target) + + if hasattr(os, "symlink"): + def symlink_to(self, target, target_is_directory=False): +@@ -1010,14 +1111,6 @@ + f = f"{type(self).__name__}.symlink_to()" + raise UnsupportedOperation(f"{f} is unsupported on this system") + +- if os.name == 'nt': +- def _symlink_to_target_of(self, link): +- """ +- Make this path a symlink with the same target as the given link. +- This is used by copy(). +- """ +- self.symlink_to(link.readlink(), link.is_dir()) +- + if hasattr(os, "link"): + def hardlink_to(self, target): + """ +diff --git a/Lib/pathlib/_os.py b/Lib/pathlib/_os.py +index 642b3a57c59..c0c81ada858 100644 +--- a/Lib/pathlib/_os.py ++++ b/Lib/pathlib/_os.py +@@ -3,8 +3,9 @@ + """ + + from errno import * ++from stat import S_ISDIR, S_ISREG, S_ISLNK, S_IMODE ++import io + import os +-import stat + import sys + try: + import fcntl +@@ -165,98 +166,449 @@ + write_target(buf) + + +-# Kinds of metadata supported by the operating system. +-file_metadata_keys = {'mode', 'times_ns'} +-if hasattr(os.stat_result, 'st_flags'): +- file_metadata_keys.add('flags') +-if hasattr(os, 'listxattr'): +- file_metadata_keys.add('xattrs') +-file_metadata_keys = frozenset(file_metadata_keys) ++def magic_open(path, mode='r', buffering=-1, encoding=None, errors=None, ++ newline=None): ++ """ ++ Open the file pointed to by this path and return a file object, as ++ the built-in open() function does. ++ """ ++ try: ++ return io.open(path, mode, buffering, encoding, errors, newline) ++ except TypeError: ++ pass ++ cls = type(path) ++ text = 'b' not in mode ++ mode = ''.join(sorted(c for c in mode if c not in 'bt')) ++ if text: ++ try: ++ attr = getattr(cls, f'__open_{mode}__') ++ except AttributeError: ++ pass ++ else: ++ return attr(path, buffering, encoding, errors, newline) + ++ try: ++ attr = getattr(cls, f'__open_{mode}b__') ++ except AttributeError: ++ pass ++ else: ++ stream = attr(path, buffering) ++ if text: ++ stream = io.TextIOWrapper(stream, encoding, errors, newline) ++ return stream ++ ++ raise TypeError(f"{cls.__name__} can't be opened with mode {mode!r}") + +-def read_file_metadata(path, keys=None, *, follow_symlinks=True): ++ ++class CopyReader: + """ +- Returns local path metadata as a dict with string keys. ++ Class that implements the "read" part of copying between path objects. ++ An instance of this class is available from the ReadablePath._copy_reader ++ property. + """ +- if keys is None: +- keys = file_metadata_keys +- assert keys.issubset(file_metadata_keys) +- result = {} +- for key in keys: +- if key == 'xattrs': ++ __slots__ = ('_path',) ++ ++ def __init__(self, path): ++ self._path = path ++ ++ _readable_metakeys = frozenset() ++ ++ def _read_metadata(self, metakeys, *, follow_symlinks=True): ++ """ ++ Returns path metadata as a dict with string keys. ++ """ ++ raise NotImplementedError ++ ++ ++class CopyWriter: ++ """ ++ Class that implements the "write" part of copying between path objects. An ++ instance of this class is available from the WritablePath._copy_writer ++ property. ++ """ ++ __slots__ = ('_path',) ++ ++ def __init__(self, path): ++ self._path = path ++ ++ _writable_metakeys = frozenset() ++ ++ def _write_metadata(self, metadata, *, follow_symlinks=True): ++ """ ++ Sets path metadata from the given dict with string keys. ++ """ ++ raise NotImplementedError ++ ++ def _create(self, source, follow_symlinks, dirs_exist_ok, preserve_metadata): ++ self._ensure_distinct_path(source) ++ if preserve_metadata: ++ metakeys = self._writable_metakeys & source._copy_reader._readable_metakeys ++ else: ++ metakeys = None ++ if not follow_symlinks and source.is_symlink(): ++ self._create_symlink(source, metakeys) ++ elif source.is_dir(): ++ self._create_dir(source, metakeys, follow_symlinks, dirs_exist_ok) ++ else: ++ self._create_file(source, metakeys) ++ return self._path ++ ++ def _create_dir(self, source, metakeys, follow_symlinks, dirs_exist_ok): ++ """Copy the given directory to our path.""" ++ children = list(source.iterdir()) ++ self._path.mkdir(exist_ok=dirs_exist_ok) ++ for src in children: ++ dst = self._path.joinpath(src.name) ++ if not follow_symlinks and src.is_symlink(): ++ dst._copy_writer._create_symlink(src, metakeys) ++ elif src.is_dir(): ++ dst._copy_writer._create_dir(src, metakeys, follow_symlinks, dirs_exist_ok) ++ else: ++ dst._copy_writer._create_file(src, metakeys) ++ if metakeys: ++ metadata = source._copy_reader._read_metadata(metakeys) ++ if metadata: ++ self._write_metadata(metadata) ++ ++ def _create_file(self, source, metakeys): ++ """Copy the given file to our path.""" ++ self._ensure_different_file(source) ++ with magic_open(source, 'rb') as source_f: ++ try: ++ with magic_open(self._path, 'wb') as target_f: ++ copyfileobj(source_f, target_f) ++ except IsADirectoryError as e: ++ if not self._path.exists(): ++ # Raise a less confusing exception. ++ raise FileNotFoundError( ++ f'Directory does not exist: {self._path}') from e ++ raise ++ if metakeys: ++ metadata = source._copy_reader._read_metadata(metakeys) ++ if metadata: ++ self._write_metadata(metadata) ++ ++ def _create_symlink(self, source, metakeys): ++ """Copy the given symbolic link to our path.""" ++ self._path.symlink_to(source.readlink()) ++ if metakeys: ++ metadata = source._copy_reader._read_metadata(metakeys, follow_symlinks=False) ++ if metadata: ++ self._write_metadata(metadata, follow_symlinks=False) ++ ++ def _ensure_different_file(self, source): ++ """ ++ Raise OSError(EINVAL) if both paths refer to the same file. ++ """ ++ pass ++ ++ def _ensure_distinct_path(self, source): ++ """ ++ Raise OSError(EINVAL) if the other path is within this path. ++ """ ++ # Note: there is no straightforward, foolproof algorithm to determine ++ # if one directory is within another (a particularly perverse example ++ # would be a single network share mounted in one location via NFS, and ++ # in another location via CIFS), so we simply checks whether the ++ # other path is lexically equal to, or within, this path. ++ if source == self._path: ++ err = OSError(EINVAL, "Source and target are the same path") ++ elif source in self._path.parents: ++ err = OSError(EINVAL, "Source path is a parent of target path") ++ else: ++ return ++ err.filename = str(source) ++ err.filename2 = str(self._path) ++ raise err ++ ++ ++class LocalCopyReader(CopyReader): ++ """This object implements the "read" part of copying local paths. Don't ++ try to construct it yourself. ++ """ ++ __slots__ = () ++ ++ _readable_metakeys = {'mode', 'times_ns'} ++ if hasattr(os.stat_result, 'st_flags'): ++ _readable_metakeys.add('flags') ++ if hasattr(os, 'listxattr'): ++ _readable_metakeys.add('xattrs') ++ _readable_metakeys = frozenset(_readable_metakeys) ++ ++ def _read_metadata(self, metakeys, *, follow_symlinks=True): ++ metadata = {} ++ if 'mode' in metakeys or 'times_ns' in metakeys or 'flags' in metakeys: ++ st = self._path.stat(follow_symlinks=follow_symlinks) ++ if 'mode' in metakeys: ++ metadata['mode'] = S_IMODE(st.st_mode) ++ if 'times_ns' in metakeys: ++ metadata['times_ns'] = st.st_atime_ns, st.st_mtime_ns ++ if 'flags' in metakeys: ++ metadata['flags'] = st.st_flags ++ if 'xattrs' in metakeys: + try: +- result['xattrs'] = [ +- (attr, os.getxattr(path, attr, follow_symlinks=follow_symlinks)) +- for attr in os.listxattr(path, follow_symlinks=follow_symlinks)] ++ metadata['xattrs'] = [ ++ (attr, os.getxattr(self._path, attr, follow_symlinks=follow_symlinks)) ++ for attr in os.listxattr(self._path, follow_symlinks=follow_symlinks)] + except OSError as err: + if err.errno not in (EPERM, ENOTSUP, ENODATA, EINVAL, EACCES): + raise +- continue +- st = os.stat(path, follow_symlinks=follow_symlinks) +- if key == 'mode': +- result['mode'] = stat.S_IMODE(st.st_mode) +- elif key == 'times_ns': +- result['times_ns'] = st.st_atime_ns, st.st_mtime_ns +- elif key == 'flags': +- result['flags'] = st.st_flags +- return result +- +- +-def write_file_metadata(path, metadata, *, follow_symlinks=True): +- """ +- Sets local path metadata from the given dict with string keys. ++ return metadata ++ ++ ++class LocalCopyWriter(CopyWriter): ++ """This object implements the "write" part of copying local paths. Don't ++ try to construct it yourself. + """ +- assert frozenset(metadata.keys()).issubset(file_metadata_keys) ++ __slots__ = () + +- def _nop(*args, ns=None, follow_symlinks=None): +- pass ++ _writable_metakeys = LocalCopyReader._readable_metakeys + +- if follow_symlinks: +- # use the real function if it exists +- def lookup(name): +- return getattr(os, name, _nop) +- else: +- # use the real function only if it exists +- # *and* it supports follow_symlinks +- def lookup(name): +- fn = getattr(os, name, _nop) +- if fn in os.supports_follow_symlinks: +- return fn +- return _nop +- +- times_ns = metadata.get('times_ns') +- if times_ns is not None: +- lookup("utime")(path, ns=times_ns, follow_symlinks=follow_symlinks) +- # We must copy extended attributes before the file is (potentially) +- # chmod()'ed read-only, otherwise setxattr() will error with -EACCES. +- xattrs = metadata.get('xattrs') +- if xattrs is not None: +- for attr, value in xattrs: ++ def _write_metadata(self, metadata, *, follow_symlinks=True): ++ def _nop(*args, ns=None, follow_symlinks=None): ++ pass ++ ++ if follow_symlinks: ++ # use the real function if it exists ++ def lookup(name): ++ return getattr(os, name, _nop) ++ else: ++ # use the real function only if it exists ++ # *and* it supports follow_symlinks ++ def lookup(name): ++ fn = getattr(os, name, _nop) ++ if fn in os.supports_follow_symlinks: ++ return fn ++ return _nop ++ ++ times_ns = metadata.get('times_ns') ++ if times_ns is not None: ++ lookup("utime")(self._path, ns=times_ns, follow_symlinks=follow_symlinks) ++ # We must copy extended attributes before the file is (potentially) ++ # chmod()'ed read-only, otherwise setxattr() will error with -EACCES. ++ xattrs = metadata.get('xattrs') ++ if xattrs is not None: ++ for attr, value in xattrs: ++ try: ++ os.setxattr(self._path, attr, value, follow_symlinks=follow_symlinks) ++ except OSError as e: ++ if e.errno not in (EPERM, ENOTSUP, ENODATA, EINVAL, EACCES): ++ raise ++ mode = metadata.get('mode') ++ if mode is not None: + try: +- os.setxattr(path, attr, value, follow_symlinks=follow_symlinks) +- except OSError as e: +- if e.errno not in (EPERM, ENOTSUP, ENODATA, EINVAL, EACCES): ++ lookup("chmod")(self._path, mode, follow_symlinks=follow_symlinks) ++ except NotImplementedError: ++ # if we got a NotImplementedError, it's because ++ # * follow_symlinks=False, ++ # * lchown() is unavailable, and ++ # * either ++ # * fchownat() is unavailable or ++ # * fchownat() doesn't implement AT_SYMLINK_NOFOLLOW. ++ # (it returned ENOSUP.) ++ # therefore we're out of options--we simply cannot chown the ++ # symlink. give up, suppress the error. ++ # (which is what shutil always did in this circumstance.) ++ pass ++ flags = metadata.get('flags') ++ if flags is not None: ++ try: ++ lookup("chflags")(self._path, flags, follow_symlinks=follow_symlinks) ++ except OSError as why: ++ if why.errno not in (EOPNOTSUPP, ENOTSUP): + raise +- mode = metadata.get('mode') +- if mode is not None: ++ ++ if copyfile: ++ # Use fast OS routine for local file copying where available. ++ def _create_file(self, source, metakeys): ++ """Copy the given file to the given target.""" ++ try: ++ source = os.fspath(source) ++ except TypeError: ++ super()._create_file(source, metakeys) ++ else: ++ copyfile(source, os.fspath(self._path)) ++ ++ if os.name == 'nt': ++ # Windows: symlink target might not exist yet if we're copying several ++ # files, so ensure we pass is_dir to os.symlink(). ++ def _create_symlink(self, source, metakeys): ++ """Copy the given symlink to the given target.""" ++ self._path.symlink_to(source.readlink(), source.is_dir()) ++ if metakeys: ++ metadata = source._copy_reader._read_metadata(metakeys, follow_symlinks=False) ++ if metadata: ++ self._write_metadata(metadata, follow_symlinks=False) ++ ++ def _ensure_different_file(self, source): ++ """ ++ Raise OSError(EINVAL) if both paths refer to the same file. ++ """ + try: +- lookup("chmod")(path, mode, follow_symlinks=follow_symlinks) +- except NotImplementedError: +- # if we got a NotImplementedError, it's because +- # * follow_symlinks=False, +- # * lchown() is unavailable, and +- # * either +- # * fchownat() is unavailable or +- # * fchownat() doesn't implement AT_SYMLINK_NOFOLLOW. +- # (it returned ENOSUP.) +- # therefore we're out of options--we simply cannot chown the +- # symlink. give up, suppress the error. +- # (which is what shutil always did in this circumstance.) +- pass +- flags = metadata.get('flags') +- if flags is not None: ++ if not self._path.samefile(source): ++ return ++ except (OSError, ValueError): ++ return ++ err = OSError(EINVAL, "Source and target are the same file") ++ err.filename = str(source) ++ err.filename2 = str(self._path) ++ raise err ++ ++ ++class _PathInfoBase: ++ __slots__ = () ++ ++ def __repr__(self): ++ path_type = "WindowsPath" if os.name == "nt" else "PosixPath" ++ return f"<{path_type}.info>" ++ ++ ++class _WindowsPathInfo(_PathInfoBase): ++ """Implementation of pathlib.types.PathInfo that provides status ++ information for Windows paths. Don't try to construct it yourself.""" ++ __slots__ = ('_path', '_exists', '_is_dir', '_is_file', '_is_symlink') ++ ++ def __init__(self, path): ++ self._path = str(path) ++ ++ def exists(self, *, follow_symlinks=True): ++ """Whether this path exists.""" ++ if not follow_symlinks and self.is_symlink(): ++ return True + try: +- lookup("chflags")(path, flags, follow_symlinks=follow_symlinks) +- except OSError as why: +- if why.errno not in (EOPNOTSUPP, ENOTSUP): +- raise ++ return self._exists ++ except AttributeError: ++ if os.path.exists(self._path): ++ self._exists = True ++ return True ++ else: ++ self._exists = self._is_dir = self._is_file = False ++ return False ++ ++ def is_dir(self, *, follow_symlinks=True): ++ """Whether this path is a directory.""" ++ if not follow_symlinks and self.is_symlink(): ++ return False ++ try: ++ return self._is_dir ++ except AttributeError: ++ if os.path.isdir(self._path): ++ self._is_dir = self._exists = True ++ return True ++ else: ++ self._is_dir = False ++ return False ++ ++ def is_file(self, *, follow_symlinks=True): ++ """Whether this path is a regular file.""" ++ if not follow_symlinks and self.is_symlink(): ++ return False ++ try: ++ return self._is_file ++ except AttributeError: ++ if os.path.isfile(self._path): ++ self._is_file = self._exists = True ++ return True ++ else: ++ self._is_file = False ++ return False ++ ++ def is_symlink(self): ++ """Whether this path is a symbolic link.""" ++ try: ++ return self._is_symlink ++ except AttributeError: ++ self._is_symlink = os.path.islink(self._path) ++ return self._is_symlink ++ ++ ++class _PosixPathInfo(_PathInfoBase): ++ """Implementation of pathlib.types.PathInfo that provides status ++ information for POSIX paths. Don't try to construct it yourself.""" ++ __slots__ = ('_path', '_mode') ++ ++ def __init__(self, path): ++ self._path = str(path) ++ self._mode = [None, None] ++ ++ def _get_mode(self, *, follow_symlinks=True): ++ idx = bool(follow_symlinks) ++ mode = self._mode[idx] ++ if mode is None: ++ try: ++ st = os.stat(self._path, follow_symlinks=follow_symlinks) ++ except (OSError, ValueError): ++ mode = 0 ++ else: ++ mode = st.st_mode ++ if follow_symlinks or S_ISLNK(mode): ++ self._mode[idx] = mode ++ else: ++ # Not a symlink, so stat() will give the same result ++ self._mode = [mode, mode] ++ return mode ++ ++ def exists(self, *, follow_symlinks=True): ++ """Whether this path exists.""" ++ return self._get_mode(follow_symlinks=follow_symlinks) > 0 ++ ++ def is_dir(self, *, follow_symlinks=True): ++ """Whether this path is a directory.""" ++ return S_ISDIR(self._get_mode(follow_symlinks=follow_symlinks)) ++ ++ def is_file(self, *, follow_symlinks=True): ++ """Whether this path is a regular file.""" ++ return S_ISREG(self._get_mode(follow_symlinks=follow_symlinks)) ++ ++ def is_symlink(self): ++ """Whether this path is a symbolic link.""" ++ return S_ISLNK(self._get_mode(follow_symlinks=False)) ++ ++ ++PathInfo = _WindowsPathInfo if os.name == 'nt' else _PosixPathInfo ++ ++ ++class DirEntryInfo(_PathInfoBase): ++ """Implementation of pathlib.types.PathInfo that provides status ++ information by querying a wrapped os.DirEntry object. Don't try to ++ construct it yourself.""" ++ __slots__ = ('_entry', '_exists') ++ ++ def __init__(self, entry): ++ self._entry = entry ++ ++ def exists(self, *, follow_symlinks=True): ++ """Whether this path exists.""" ++ if not follow_symlinks: ++ return True ++ try: ++ return self._exists ++ except AttributeError: ++ try: ++ self._entry.stat() ++ except OSError: ++ self._exists = False ++ else: ++ self._exists = True ++ return self._exists ++ ++ def is_dir(self, *, follow_symlinks=True): ++ """Whether this path is a directory.""" ++ try: ++ return self._entry.is_dir(follow_symlinks=follow_symlinks) ++ except OSError: ++ return False ++ ++ def is_file(self, *, follow_symlinks=True): ++ """Whether this path is a regular file.""" ++ try: ++ return self._entry.is_file(follow_symlinks=follow_symlinks) ++ except OSError: ++ return False ++ ++ def is_symlink(self): ++ """Whether this path is a symbolic link.""" ++ try: ++ return self._entry.is_symlink() ++ except OSError: ++ return False +diff --git a/Lib/pathlib/_types.py b/Lib/pathlib/types.py +similarity index 50% +rename from Lib/pathlib/_types.py +rename to Lib/pathlib/types.py +index 60df94d0b46..b781264796b 100644 +--- a/Lib/pathlib/_types.py ++++ b/Lib/pathlib/types.py +@@ -5,18 +5,26 @@ + + + @runtime_checkable +-class Parser(Protocol): ++class _PathParser(Protocol): + """Protocol for path parsers, which do low-level path manipulation. + + Path parsers provide a subset of the os.path API, specifically those +- functions needed to provide PurePathBase functionality. Each PurePathBase ++ functions needed to provide JoinablePath functionality. Each JoinablePath + subclass references its path parser via a 'parser' class attribute. + """ + + sep: str +- def join(self, path: str, *paths: str) -> str: ... + def split(self, path: str) -> tuple[str, str]: ... +- def splitdrive(self, path: str) -> tuple[str, str]: ... + def splitext(self, path: str) -> tuple[str, str]: ... + def normcase(self, path: str) -> str: ... +- def isabs(self, path: str) -> bool: ... ++ ++ ++@runtime_checkable ++class PathInfo(Protocol): ++ """Protocol for path info objects, which support querying the file type. ++ Methods may return cached results. ++ """ ++ def exists(self, *, follow_symlinks: bool = True) -> bool: ... ++ def is_dir(self, *, follow_symlinks: bool = True) -> bool: ... ++ def is_file(self, *, follow_symlinks: bool = True) -> bool: ... ++ def is_symlink(self) -> bool: ... +diff --git a/Lib/pdb.py b/Lib/pdb.py +index 10d1923cdad..4abf216b773 100644 +--- a/Lib/pdb.py ++++ b/Lib/pdb.py +@@ -90,6 +90,7 @@ + from contextlib import contextmanager + from rlcompleter import Completer + from types import CodeType ++from warnings import deprecated + + + class Restart(Exception): +@@ -421,6 +422,16 @@ + ] + self.rcLines = [] + ++ @property ++ @deprecated("The frame locals reference is no longer cached. Use 'curframe.f_locals' instead.") ++ def curframe_locals(self): ++ return self.curframe.f_locals ++ ++ @curframe_locals.setter ++ @deprecated("Setting 'curframe_locals' no longer has any effect. Update the contents of 'curframe.f_locals' instead.") ++ def curframe_locals(self, value): ++ pass ++ + # Override Bdb methods + + def user_call(self, frame, argument_list): +@@ -1725,6 +1736,19 @@ + + Quit from the debugger. The program being executed is aborted. + """ ++ if self.mode == 'inline': ++ while True: ++ try: ++ reply = input('Quitting pdb will kill the process. Quit anyway? [y/n] ') ++ reply = reply.lower().strip() ++ except EOFError: ++ reply = 'y' ++ self.message('') ++ if reply == 'y' or reply == '': ++ sys.exit(0) ++ elif reply.lower() == 'n': ++ return ++ + self._user_requested_quit = True + self.set_quit() + return 1 +@@ -1738,9 +1762,7 @@ + Handles the receipt of EOF as a command. + """ + self.message('') +- self._user_requested_quit = True +- self.set_quit() +- return 1 ++ return self.do_quit(arg) + + def do_args(self, arg): + """a(rgs) +diff --git a/Lib/pickle.py b/Lib/pickle.py +index 1920973e3f8..8afb4aa4285 100644 +--- a/Lib/pickle.py ++++ b/Lib/pickle.py +@@ -31,7 +31,6 @@ + import sys + from sys import maxsize + from struct import pack, unpack +-import re + import io + import codecs + import _compat_pickle +@@ -188,7 +187,7 @@ + NEXT_BUFFER = b'\x97' # push next out-of-band buffer + READONLY_BUFFER = b'\x98' # make top of stack readonly + +-__all__.extend([x for x in dir() if re.match("[A-Z][A-Z0-9_]+$", x)]) ++__all__.extend(x for x in dir() if x.isupper() and not x.startswith('_')) + + + class _Framer: +diff --git a/Lib/platform.py b/Lib/platform.py +index 1f6baed66d3..235dd98c60a 100644 +--- a/Lib/platform.py ++++ b/Lib/platform.py +@@ -521,6 +521,54 @@ + return IOSVersionInfo(system, release, model, is_simulator) + + ++# A namedtuple for tvOS version information. ++TVOSVersionInfo = collections.namedtuple( ++ "TVOSVersionInfo", ++ ["system", "release", "model", "is_simulator"] ++) ++ ++ ++def tvos_ver(system="", release="", model="", is_simulator=False): ++ """Get tvOS version information, and return it as a namedtuple: ++ (system, release, model, is_simulator). ++ ++ If values can't be determined, they are set to values provided as ++ parameters. ++ """ ++ if sys.platform == "tvos": ++ # TODO: Can the iOS implementation be used here? ++ import _ios_support ++ result = _ios_support.get_platform_ios() ++ if result is not None: ++ return TVOSVersionInfo(*result) ++ ++ return TVOSVersionInfo(system, release, model, is_simulator) ++ ++ ++# A namedtuple for watchOS version information. ++WatchOSVersionInfo = collections.namedtuple( ++ "WatchOSVersionInfo", ++ ["system", "release", "model", "is_simulator"] ++) ++ ++ ++def watchos_ver(system="", release="", model="", is_simulator=False): ++ """Get watchOS version information, and return it as a namedtuple: ++ (system, release, model, is_simulator). ++ ++ If values can't be determined, they are set to values provided as ++ parameters. ++ """ ++ if sys.platform == "watchos": ++ # TODO: Can the iOS implementation be used here? ++ import _ios_support ++ result = _ios_support.get_platform_ios() ++ if result is not None: ++ return WatchOSVersionInfo(*result) ++ ++ return WatchOSVersionInfo(system, release, model, is_simulator) ++ ++ + def _java_getprop(name, default): + """This private helper is deprecated in 3.13 and will be removed in 3.15""" + from java.lang import System +@@ -884,14 +932,25 @@ + csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0) + return 'Alpha' if cpu_number >= 128 else 'VAX' + +- # On the iOS simulator, os.uname returns the architecture as uname.machine. +- # On device it returns the model name for some reason; but there's only one +- # CPU architecture for iOS devices, so we know the right answer. ++ # On the iOS/tvOS/watchOS simulator, os.uname returns the architecture as ++ # uname.machine. On device it returns the model name for some reason; but ++ # there's only one CPU architecture for devices, so we know the right ++ # answer. + def get_ios(): + if sys.implementation._multiarch.endswith("simulator"): + return os.uname().machine + return 'arm64' + ++ def get_tvos(): ++ if sys.implementation._multiarch.endswith("simulator"): ++ return os.uname().machine ++ return 'arm64' ++ ++ def get_watchos(): ++ if sys.implementation._multiarch.endswith("simulator"): ++ return os.uname().machine ++ return 'arm64_32' ++ + def from_subprocess(): + """ + Fall back to `uname -p` +@@ -1051,9 +1110,13 @@ + system = 'Android' + release = android_ver().release + +- # Normalize responses on iOS ++ # Normalize responses on Apple mobile platforms + if sys.platform == 'ios': + system, release, _, _ = ios_ver() ++ if sys.platform == 'tvos': ++ system, release, _, _ = tvos_ver() ++ if sys.platform == 'watchos': ++ system, release, _, _ = watchos_ver() + + vals = system, node, release, version, machine + # Replace 'unknown' values with the more portable '' +@@ -1343,6 +1406,10 @@ + # macOS and iOS both report as a "Darwin" kernel + if sys.platform == "ios": + system, release, _, _ = ios_ver() ++ elif sys.platform == "tvos": ++ system, release, _, _ = tvos_ver() ++ elif sys.platform == "watchos": ++ system, release, _, _ = watchos_ver() + else: + macos_release = mac_ver()[0] + if macos_release: +diff --git a/Lib/pstats.py b/Lib/pstats.py +index 46e18fb7592..becaf35580e 100644 +--- a/Lib/pstats.py ++++ b/Lib/pstats.py +@@ -29,7 +29,6 @@ + from enum import StrEnum, _simple_enum + from functools import cmp_to_key + from dataclasses import dataclass +-from typing import Dict + + __all__ = ["Stats", "SortKey", "FunctionProfile", "StatsProfile"] + +@@ -69,7 +68,7 @@ + class StatsProfile: + '''Class for keeping track of an item in inventory.''' + total_tt: float +- func_profiles: Dict[str, FunctionProfile] ++ func_profiles: dict[str, FunctionProfile] + + class Stats: + """This class is used for creating reports from data generated by the +diff --git a/Lib/pydoc.py b/Lib/pydoc.py +index c863794ea14..1839b88fec2 100644 +--- a/Lib/pydoc.py ++++ b/Lib/pydoc.py +@@ -53,6 +53,7 @@ + # the current directory is changed with os.chdir(), an incorrect + # path will be displayed. + ++import ast + import __future__ + import builtins + import importlib._bootstrap +@@ -244,7 +245,7 @@ + if necessary) or module.""" + if '.' in object.__qualname__: + name = object.__qualname__.rpartition('.')[0] +- if object.__module__ != modname: ++ if object.__module__ != modname and object.__module__ is not None: + return object.__module__ + '.' + name + else: + return name +@@ -384,21 +385,29 @@ + return False + + def source_synopsis(file): +- line = file.readline() +- while line[:1] == '#' or not line.strip(): +- line = file.readline() +- if not line: break +- line = line.strip() +- if line[:4] == 'r"""': line = line[1:] +- if line[:3] == '"""': +- line = line[3:] +- if line[-1:] == '\\': line = line[:-1] +- while not line.strip(): +- line = file.readline() +- if not line: break +- result = line.split('"""')[0].strip() +- else: result = None +- return result ++ """Return the one-line summary of a file object, if present""" ++ ++ string = '' ++ try: ++ tokens = tokenize.generate_tokens(file.readline) ++ for tok_type, tok_string, _, _, _ in tokens: ++ if tok_type == tokenize.STRING: ++ string += tok_string ++ elif tok_type == tokenize.NEWLINE: ++ with warnings.catch_warnings(): ++ # Ignore the "invalid escape sequence" warning. ++ warnings.simplefilter("ignore", SyntaxWarning) ++ docstring = ast.literal_eval(string) ++ if not isinstance(docstring, str): ++ return None ++ return docstring.strip().split('\n')[0].strip() ++ elif tok_type == tokenize.OP and tok_string in ('(', ')'): ++ string += tok_string ++ elif tok_type not in (tokenize.COMMENT, tokenize.NL, tokenize.ENCODING): ++ return None ++ except (tokenize.TokenError, UnicodeDecodeError, SyntaxError): ++ return None ++ return None + + def synopsis(filename, cache={}): + """Get the one-line summary out of a module file.""" +@@ -1426,7 +1435,8 @@ + # List the built-in subclasses, if any: + subclasses = sorted( + (str(cls.__name__) for cls in type.__subclasses__(object) +- if not cls.__name__.startswith("_") and cls.__module__ == "builtins"), ++ if (not cls.__name__.startswith("_") and ++ getattr(cls, '__module__', '') == "builtins")), + key=str.lower + ) + no_of_subclasses = len(subclasses) +diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py +index aebcef2b81d..d58f10c120a 100644 +--- a/Lib/pydoc_data/topics.py ++++ b/Lib/pydoc_data/topics.py +@@ -1,17478 +1,12795 @@ +-# -*- coding: utf-8 -*- +-# Autogenerated by Sphinx on Tue Dec 17 11:49:52 2024 ++# Autogenerated by Sphinx on Tue Feb 11 19:16:18 2025 + # as part of the release process. +-topics = {'assert': 'The "assert" statement\n' +- '**********************\n' +- '\n' +- 'Assert statements are a convenient way to insert debugging ' +- 'assertions\n' +- 'into a program:\n' +- '\n' +- ' assert_stmt ::= "assert" expression ["," expression]\n' +- '\n' +- 'The simple form, "assert expression", is equivalent to\n' +- '\n' +- ' if __debug__:\n' +- ' if not expression: raise AssertionError\n' +- '\n' +- 'The extended form, "assert expression1, expression2", is ' +- 'equivalent to\n' +- '\n' +- ' if __debug__:\n' +- ' if not expression1: raise AssertionError(expression2)\n' +- '\n' +- 'These equivalences assume that "__debug__" and "AssertionError" ' +- 'refer\n' +- 'to the built-in variables with those names. In the current\n' +- 'implementation, the built-in variable "__debug__" is "True" under\n' +- 'normal circumstances, "False" when optimization is requested ' +- '(command\n' +- 'line option "-O"). The current code generator emits no code for ' +- 'an\n' +- '"assert" statement when optimization is requested at compile ' +- 'time.\n' +- 'Note that it is unnecessary to include the source code for the\n' +- 'expression that failed in the error message; it will be displayed ' +- 'as\n' +- 'part of the stack trace.\n' +- '\n' +- 'Assignments to "__debug__" are illegal. The value for the ' +- 'built-in\n' +- 'variable is determined when the interpreter starts.\n', +- 'assignment': 'Assignment statements\n' +- '*********************\n' +- '\n' +- 'Assignment statements are used to (re)bind names to values and ' +- 'to\n' +- 'modify attributes or items of mutable objects:\n' +- '\n' +- ' assignment_stmt ::= (target_list "=")+ (starred_expression ' +- '| yield_expression)\n' +- ' target_list ::= target ("," target)* [","]\n' +- ' target ::= identifier\n' +- ' | "(" [target_list] ")"\n' +- ' | "[" [target_list] "]"\n' +- ' | attributeref\n' +- ' | subscription\n' +- ' | slicing\n' +- ' | "*" target\n' +- '\n' +- '(See section Primaries for the syntax definitions for ' +- '*attributeref*,\n' +- '*subscription*, and *slicing*.)\n' +- '\n' +- 'An assignment statement evaluates the expression list ' +- '(remember that\n' +- 'this can be a single expression or a comma-separated list, the ' +- 'latter\n' +- 'yielding a tuple) and assigns the single resulting object to ' +- 'each of\n' +- 'the target lists, from left to right.\n' +- '\n' +- 'Assignment is defined recursively depending on the form of the ' +- 'target\n' +- '(list). When a target is part of a mutable object (an ' +- 'attribute\n' +- 'reference, subscription or slicing), the mutable object must\n' +- 'ultimately perform the assignment and decide about its ' +- 'validity, and\n' +- 'may raise an exception if the assignment is unacceptable. The ' +- 'rules\n' +- 'observed by various types and the exceptions raised are given ' +- 'with the\n' +- 'definition of the object types (see section The standard type\n' +- 'hierarchy).\n' +- '\n' +- 'Assignment of an object to a target list, optionally enclosed ' +- 'in\n' +- 'parentheses or square brackets, is recursively defined as ' +- 'follows.\n' +- '\n' +- '* If the target list is a single target with no trailing ' +- 'comma,\n' +- ' optionally in parentheses, the object is assigned to that ' +- 'target.\n' +- '\n' +- '* Else:\n' +- '\n' +- ' * If the target list contains one target prefixed with an ' +- 'asterisk,\n' +- ' called a “starred†target: The object must be an iterable ' +- 'with at\n' +- ' least as many items as there are targets in the target ' +- 'list, minus\n' +- ' one. The first items of the iterable are assigned, from ' +- 'left to\n' +- ' right, to the targets before the starred target. The ' +- 'final items\n' +- ' of the iterable are assigned to the targets after the ' +- 'starred\n' +- ' target. A list of the remaining items in the iterable is ' +- 'then\n' +- ' assigned to the starred target (the list can be empty).\n' +- '\n' +- ' * Else: The object must be an iterable with the same number ' +- 'of items\n' +- ' as there are targets in the target list, and the items ' +- 'are\n' +- ' assigned, from left to right, to the corresponding ' +- 'targets.\n' +- '\n' +- 'Assignment of an object to a single target is recursively ' +- 'defined as\n' +- 'follows.\n' +- '\n' +- '* If the target is an identifier (name):\n' +- '\n' +- ' * If the name does not occur in a "global" or "nonlocal" ' +- 'statement\n' +- ' in the current code block: the name is bound to the object ' +- 'in the\n' +- ' current local namespace.\n' +- '\n' +- ' * Otherwise: the name is bound to the object in the global ' +- 'namespace\n' +- ' or the outer namespace determined by "nonlocal", ' +- 'respectively.\n' +- '\n' +- ' The name is rebound if it was already bound. This may cause ' +- 'the\n' +- ' reference count for the object previously bound to the name ' +- 'to reach\n' +- ' zero, causing the object to be deallocated and its ' +- 'destructor (if it\n' +- ' has one) to be called.\n' +- '\n' +- '* If the target is an attribute reference: The primary ' +- 'expression in\n' +- ' the reference is evaluated. It should yield an object with\n' +- ' assignable attributes; if this is not the case, "TypeError" ' +- 'is\n' +- ' raised. That object is then asked to assign the assigned ' +- 'object to\n' +- ' the given attribute; if it cannot perform the assignment, it ' +- 'raises\n' +- ' an exception (usually but not necessarily ' +- '"AttributeError").\n' +- '\n' +- ' Note: If the object is a class instance and the attribute ' +- 'reference\n' +- ' occurs on both sides of the assignment operator, the ' +- 'right-hand side\n' +- ' expression, "a.x" can access either an instance attribute or ' +- '(if no\n' +- ' instance attribute exists) a class attribute. The left-hand ' +- 'side\n' +- ' target "a.x" is always set as an instance attribute, ' +- 'creating it if\n' +- ' necessary. Thus, the two occurrences of "a.x" do not ' +- 'necessarily\n' +- ' refer to the same attribute: if the right-hand side ' +- 'expression\n' +- ' refers to a class attribute, the left-hand side creates a ' +- 'new\n' +- ' instance attribute as the target of the assignment:\n' +- '\n' +- ' class Cls:\n' +- ' x = 3 # class variable\n' +- ' inst = Cls()\n' +- ' inst.x = inst.x + 1 # writes inst.x as 4 leaving Cls.x ' +- 'as 3\n' +- '\n' +- ' This description does not necessarily apply to descriptor\n' +- ' attributes, such as properties created with "property()".\n' +- '\n' +- '* If the target is a subscription: The primary expression in ' +- 'the\n' +- ' reference is evaluated. It should yield either a mutable ' +- 'sequence\n' +- ' object (such as a list) or a mapping object (such as a ' +- 'dictionary).\n' +- ' Next, the subscript expression is evaluated.\n' +- '\n' +- ' If the primary is a mutable sequence object (such as a ' +- 'list), the\n' +- ' subscript must yield an integer. If it is negative, the ' +- 'sequence’s\n' +- ' length is added to it. The resulting value must be a ' +- 'nonnegative\n' +- ' integer less than the sequence’s length, and the sequence is ' +- 'asked\n' +- ' to assign the assigned object to its item with that index. ' +- 'If the\n' +- ' index is out of range, "IndexError" is raised (assignment to ' +- 'a\n' +- ' subscripted sequence cannot add new items to a list).\n' +- '\n' +- ' If the primary is a mapping object (such as a dictionary), ' +- 'the\n' +- ' subscript must have a type compatible with the mapping’s key ' +- 'type,\n' +- ' and the mapping is then asked to create a key/value pair ' +- 'which maps\n' +- ' the subscript to the assigned object. This can either ' +- 'replace an\n' +- ' existing key/value pair with the same key value, or insert a ' +- 'new\n' +- ' key/value pair (if no key with the same value existed).\n' +- '\n' +- ' For user-defined objects, the "__setitem__()" method is ' +- 'called with\n' +- ' appropriate arguments.\n' +- '\n' +- '* If the target is a slicing: The primary expression in the ' +- 'reference\n' +- ' is evaluated. It should yield a mutable sequence object ' +- '(such as a\n' +- ' list). The assigned object should be a sequence object of ' +- 'the same\n' +- ' type. Next, the lower and upper bound expressions are ' +- 'evaluated,\n' +- ' insofar they are present; defaults are zero and the ' +- 'sequence’s\n' +- ' length. The bounds should evaluate to integers. If either ' +- 'bound is\n' +- ' negative, the sequence’s length is added to it. The ' +- 'resulting\n' +- ' bounds are clipped to lie between zero and the sequence’s ' +- 'length,\n' +- ' inclusive. Finally, the sequence object is asked to replace ' +- 'the\n' +- ' slice with the items of the assigned sequence. The length ' +- 'of the\n' +- ' slice may be different from the length of the assigned ' +- 'sequence,\n' +- ' thus changing the length of the target sequence, if the ' +- 'target\n' +- ' sequence allows it.\n' +- '\n' +- '**CPython implementation detail:** In the current ' +- 'implementation, the\n' +- 'syntax for targets is taken to be the same as for expressions, ' +- 'and\n' +- 'invalid syntax is rejected during the code generation phase, ' +- 'causing\n' +- 'less detailed error messages.\n' +- '\n' +- 'Although the definition of assignment implies that overlaps ' +- 'between\n' +- 'the left-hand side and the right-hand side are ‘simultaneous’ ' +- '(for\n' +- 'example "a, b = b, a" swaps two variables), overlaps *within* ' +- 'the\n' +- 'collection of assigned-to variables occur left-to-right, ' +- 'sometimes\n' +- 'resulting in confusion. For instance, the following program ' +- 'prints\n' +- '"[0, 2]":\n' +- '\n' +- ' x = [0, 1]\n' +- ' i = 0\n' +- ' i, x[i] = 1, 2 # i is updated, then x[i] is ' +- 'updated\n' +- ' print(x)\n' +- '\n' +- 'See also:\n' +- '\n' +- ' **PEP 3132** - Extended Iterable Unpacking\n' +- ' The specification for the "*target" feature.\n' +- '\n' +- '\n' +- 'Augmented assignment statements\n' +- '===============================\n' +- '\n' +- 'Augmented assignment is the combination, in a single ' +- 'statement, of a\n' +- 'binary operation and an assignment statement:\n' +- '\n' +- ' augmented_assignment_stmt ::= augtarget augop ' +- '(expression_list | yield_expression)\n' +- ' augtarget ::= identifier | attributeref | ' +- 'subscription | slicing\n' +- ' augop ::= "+=" | "-=" | "*=" | "@=" | ' +- '"/=" | "//=" | "%=" | "**="\n' +- ' | ">>=" | "<<=" | "&=" | "^=" | "|="\n' +- '\n' +- '(See section Primaries for the syntax definitions of the last ' +- 'three\n' +- 'symbols.)\n' +- '\n' +- 'An augmented assignment evaluates the target (which, unlike ' +- 'normal\n' +- 'assignment statements, cannot be an unpacking) and the ' +- 'expression\n' +- 'list, performs the binary operation specific to the type of ' +- 'assignment\n' +- 'on the two operands, and assigns the result to the original ' +- 'target.\n' +- 'The target is only evaluated once.\n' +- '\n' +- 'An augmented assignment statement like "x += 1" can be ' +- 'rewritten as "x\n' +- '= x + 1" to achieve a similar, but not exactly equal effect. ' +- 'In the\n' +- 'augmented version, "x" is only evaluated once. Also, when ' +- 'possible,\n' +- 'the actual operation is performed *in-place*, meaning that ' +- 'rather than\n' +- 'creating a new object and assigning that to the target, the ' +- 'old object\n' +- 'is modified instead.\n' +- '\n' +- 'Unlike normal assignments, augmented assignments evaluate the ' +- 'left-\n' +- 'hand side *before* evaluating the right-hand side. For ' +- 'example, "a[i]\n' +- '+= f(x)" first looks-up "a[i]", then it evaluates "f(x)" and ' +- 'performs\n' +- 'the addition, and lastly, it writes the result back to ' +- '"a[i]".\n' +- '\n' +- 'With the exception of assigning to tuples and multiple targets ' +- 'in a\n' +- 'single statement, the assignment done by augmented assignment\n' +- 'statements is handled the same way as normal assignments. ' +- 'Similarly,\n' +- 'with the exception of the possible *in-place* behavior, the ' +- 'binary\n' +- 'operation performed by augmented assignment is the same as the ' +- 'normal\n' +- 'binary operations.\n' +- '\n' +- 'For targets which are attribute references, the same caveat ' +- 'about\n' +- 'class and instance attributes applies as for regular ' +- 'assignments.\n' +- '\n' +- '\n' +- 'Annotated assignment statements\n' +- '===============================\n' +- '\n' +- '*Annotation* assignment is the combination, in a single ' +- 'statement, of\n' +- 'a variable or attribute annotation and an optional assignment\n' +- 'statement:\n' +- '\n' +- ' annotated_assignment_stmt ::= augtarget ":" expression\n' +- ' ["=" (starred_expression | ' +- 'yield_expression)]\n' +- '\n' +- 'The difference from normal Assignment statements is that only ' +- 'a single\n' +- 'target is allowed.\n' +- '\n' +- 'The assignment target is considered “simple†if it consists of ' +- 'a\n' +- 'single name that is not enclosed in parentheses. For simple ' +- 'assignment\n' +- 'targets, if in class or module scope, the annotations are ' +- 'gathered in\n' +- 'a lazily evaluated annotation scope. The annotations can be ' +- 'evaluated\n' +- 'using the "__annotations__" attribute of a class or module, or ' +- 'using\n' +- 'the facilities in the "annotationlib" module.\n' +- '\n' +- 'If the assignment target is not simple (an attribute, ' +- 'subscript node,\n' +- 'or parenthesized name), the annotation is never evaluated.\n' +- '\n' +- 'If a name is annotated in a function scope, then this name is ' +- 'local\n' +- 'for that scope. Annotations are never evaluated and stored in ' +- 'function\n' +- 'scopes.\n' +- '\n' +- 'If the right hand side is present, an annotated assignment ' +- 'performs\n' +- 'the actual assignment as if there was no annotation present. ' +- 'If the\n' +- 'right hand side is not present for an expression target, then ' +- 'the\n' +- 'interpreter evaluates the target except for the last ' +- '"__setitem__()"\n' +- 'or "__setattr__()" call.\n' +- '\n' +- 'See also:\n' +- '\n' +- ' **PEP 526** - Syntax for Variable Annotations\n' +- ' The proposal that added syntax for annotating the types ' +- 'of\n' +- ' variables (including class variables and instance ' +- 'variables),\n' +- ' instead of expressing them through comments.\n' +- '\n' +- ' **PEP 484** - Type hints\n' +- ' The proposal that added the "typing" module to provide a ' +- 'standard\n' +- ' syntax for type annotations that can be used in static ' +- 'analysis\n' +- ' tools and IDEs.\n' +- '\n' +- 'Changed in version 3.8: Now annotated assignments allow the ' +- 'same\n' +- 'expressions in the right hand side as regular assignments. ' +- 'Previously,\n' +- 'some expressions (like un-parenthesized tuple expressions) ' +- 'caused a\n' +- 'syntax error.\n' +- '\n' +- 'Changed in version 3.14: Annotations are now lazily evaluated ' +- 'in a\n' +- 'separate annotation scope. If the assignment target is not ' +- 'simple,\n' +- 'annotations are never evaluated.\n', +- 'assignment-expressions': 'Assignment expressions\n' +- '**********************\n' +- '\n' +- ' assignment_expression ::= [identifier ":="] ' +- 'expression\n' +- '\n' +- 'An assignment expression (sometimes also called a ' +- '“named expressionâ€\n' +- 'or “walrusâ€) assigns an "expression" to an ' +- '"identifier", while also\n' +- 'returning the value of the "expression".\n' +- '\n' +- 'One common use case is when handling matched ' +- 'regular expressions:\n' +- '\n' +- ' if matching := pattern.search(data):\n' +- ' do_something(matching)\n' +- '\n' +- 'Or, when processing a file stream in chunks:\n' +- '\n' +- ' while chunk := file.read(9000):\n' +- ' process(chunk)\n' +- '\n' +- 'Assignment expressions must be surrounded by ' +- 'parentheses when used as\n' +- 'expression statements and when used as ' +- 'sub-expressions in slicing,\n' +- 'conditional, lambda, keyword-argument, and ' +- 'comprehension-if\n' +- 'expressions and in "assert", "with", and ' +- '"assignment" statements. In\n' +- 'all other places where they can be used, ' +- 'parentheses are not required,\n' +- 'including in "if" and "while" statements.\n' +- '\n' +- 'Added in version 3.8: See **PEP 572** for more ' +- 'details about\n' +- 'assignment expressions.\n', +- 'async': 'Coroutines\n' +- '**********\n' +- '\n' +- 'Added in version 3.5.\n' +- '\n' +- '\n' +- 'Coroutine function definition\n' +- '=============================\n' +- '\n' +- ' async_funcdef ::= [decorators] "async" "def" funcname "(" ' +- '[parameter_list] ")"\n' +- ' ["->" expression] ":" suite\n' +- '\n' +- 'Execution of Python coroutines can be suspended and resumed at ' +- 'many\n' +- 'points (see *coroutine*). "await" expressions, "async for" and ' +- '"async\n' +- 'with" can only be used in the body of a coroutine function.\n' +- '\n' +- 'Functions defined with "async def" syntax are always coroutine\n' +- 'functions, even if they do not contain "await" or "async" ' +- 'keywords.\n' +- '\n' +- 'It is a "SyntaxError" to use a "yield from" expression inside the ' +- 'body\n' +- 'of a coroutine function.\n' +- '\n' +- 'An example of a coroutine function:\n' +- '\n' +- ' async def func(param1, param2):\n' +- ' do_stuff()\n' +- ' await some_coroutine()\n' +- '\n' +- 'Changed in version 3.7: "await" and "async" are now keywords;\n' +- 'previously they were only treated as such inside the body of a\n' +- 'coroutine function.\n' +- '\n' +- '\n' +- 'The "async for" statement\n' +- '=========================\n' +- '\n' +- ' async_for_stmt ::= "async" for_stmt\n' +- '\n' +- 'An *asynchronous iterable* provides an "__aiter__" method that\n' +- 'directly returns an *asynchronous iterator*, which can call\n' +- 'asynchronous code in its "__anext__" method.\n' +- '\n' +- 'The "async for" statement allows convenient iteration over\n' +- 'asynchronous iterables.\n' +- '\n' +- 'The following code:\n' +- '\n' +- ' async for TARGET in ITER:\n' +- ' SUITE\n' +- ' else:\n' +- ' SUITE2\n' +- '\n' +- 'Is semantically equivalent to:\n' +- '\n' +- ' iter = (ITER)\n' +- ' iter = type(iter).__aiter__(iter)\n' +- ' running = True\n' +- '\n' +- ' while running:\n' +- ' try:\n' +- ' TARGET = await type(iter).__anext__(iter)\n' +- ' except StopAsyncIteration:\n' +- ' running = False\n' +- ' else:\n' +- ' SUITE\n' +- ' else:\n' +- ' SUITE2\n' +- '\n' +- 'See also "__aiter__()" and "__anext__()" for details.\n' +- '\n' +- 'It is a "SyntaxError" to use an "async for" statement outside the ' +- 'body\n' +- 'of a coroutine function.\n' +- '\n' +- '\n' +- 'The "async with" statement\n' +- '==========================\n' +- '\n' +- ' async_with_stmt ::= "async" with_stmt\n' +- '\n' +- 'An *asynchronous context manager* is a *context manager* that is ' +- 'able\n' +- 'to suspend execution in its *enter* and *exit* methods.\n' +- '\n' +- 'The following code:\n' +- '\n' +- ' async with EXPRESSION as TARGET:\n' +- ' SUITE\n' +- '\n' +- 'is semantically equivalent to:\n' +- '\n' +- ' manager = (EXPRESSION)\n' +- ' aenter = type(manager).__aenter__\n' +- ' aexit = type(manager).__aexit__\n' +- ' value = await aenter(manager)\n' +- ' hit_except = False\n' +- '\n' +- ' try:\n' +- ' TARGET = value\n' +- ' SUITE\n' +- ' except:\n' +- ' hit_except = True\n' +- ' if not await aexit(manager, *sys.exc_info()):\n' +- ' raise\n' +- ' finally:\n' +- ' if not hit_except:\n' +- ' await aexit(manager, None, None, None)\n' +- '\n' +- 'See also "__aenter__()" and "__aexit__()" for details.\n' +- '\n' +- 'It is a "SyntaxError" to use an "async with" statement outside the\n' +- 'body of a coroutine function.\n' +- '\n' +- 'See also:\n' +- '\n' +- ' **PEP 492** - Coroutines with async and await syntax\n' +- ' The proposal that made coroutines a proper standalone concept ' +- 'in\n' +- ' Python, and added supporting syntax.\n', +- 'atom-identifiers': 'Identifiers (Names)\n' +- '*******************\n' +- '\n' +- 'An identifier occurring as an atom is a name. See ' +- 'section Identifiers\n' +- 'and keywords for lexical definition and section Naming ' +- 'and binding for\n' +- 'documentation of naming and binding.\n' +- '\n' +- 'When the name is bound to an object, evaluation of the ' +- 'atom yields\n' +- 'that object. When a name is not bound, an attempt to ' +- 'evaluate it\n' +- 'raises a "NameError" exception.\n' +- '\n' +- '\n' +- 'Private name mangling\n' +- '=====================\n' +- '\n' +- 'When an identifier that textually occurs in a class ' +- 'definition begins\n' +- 'with two or more underscore characters and does not end ' +- 'in two or more\n' +- 'underscores, it is considered a *private name* of that ' +- 'class.\n' +- '\n' +- 'See also: The class specifications.\n' +- '\n' +- 'More precisely, private names are transformed to a ' +- 'longer form before\n' +- 'code is generated for them. If the transformed name is ' +- 'longer than\n' +- '255 characters, implementation-defined truncation may ' +- 'happen.\n' +- '\n' +- 'The transformation is independent of the syntactical ' +- 'context in which\n' +- 'the identifier is used but only the following private ' +- 'identifiers are\n' +- 'mangled:\n' +- '\n' +- '* Any name used as the name of a variable that is ' +- 'assigned or read or\n' +- ' any name of an attribute being accessed.\n' +- '\n' +- ' The "__name__" attribute of nested functions, classes, ' +- 'and type\n' +- ' aliases is however not mangled.\n' +- '\n' +- '* The name of imported modules, e.g., "__spam" in ' +- '"import __spam". If\n' +- ' the module is part of a package (i.e., its name ' +- 'contains a dot), the\n' +- ' name is *not* mangled, e.g., the "__foo" in "import ' +- '__foo.bar" is\n' +- ' not mangled.\n' +- '\n' +- '* The name of an imported member, e.g., "__f" in "from ' +- 'spam import\n' +- ' __f".\n' +- '\n' +- 'The transformation rule is defined as follows:\n' +- '\n' +- '* The class name, with leading underscores removed and a ' +- 'single\n' +- ' leading underscore inserted, is inserted in front of ' +- 'the identifier,\n' +- ' e.g., the identifier "__spam" occurring in a class ' +- 'named "Foo",\n' +- ' "_Foo" or "__Foo" is transformed to "_Foo__spam".\n' +- '\n' +- '* If the class name consists only of underscores, the ' +- 'transformation\n' +- ' is the identity, e.g., the identifier "__spam" ' +- 'occurring in a class\n' +- ' named "_" or "__" is left as is.\n', +- 'atom-literals': 'Literals\n' +- '********\n' +- '\n' +- 'Python supports string and bytes literals and various ' +- 'numeric\n' +- 'literals:\n' +- '\n' +- ' literal ::= stringliteral | bytesliteral\n' +- ' | integer | floatnumber | imagnumber\n' +- '\n' +- 'Evaluation of a literal yields an object of the given type ' +- '(string,\n' +- 'bytes, integer, floating-point number, complex number) with ' +- 'the given\n' +- 'value. The value may be approximated in the case of ' +- 'floating-point\n' +- 'and imaginary (complex) literals. See section Literals for ' +- 'details.\n' +- '\n' +- 'All literals correspond to immutable data types, and hence ' +- 'the\n' +- 'object’s identity is less important than its value. ' +- 'Multiple\n' +- 'evaluations of literals with the same value (either the ' +- 'same\n' +- 'occurrence in the program text or a different occurrence) ' +- 'may obtain\n' +- 'the same object or a different object with the same ' +- 'value.\n', +- 'attribute-access': 'Customizing attribute access\n' +- '****************************\n' +- '\n' +- 'The following methods can be defined to customize the ' +- 'meaning of\n' +- 'attribute access (use of, assignment to, or deletion of ' +- '"x.name") for\n' +- 'class instances.\n' +- '\n' +- 'object.__getattr__(self, name)\n' +- '\n' +- ' Called when the default attribute access fails with ' +- 'an\n' +- ' "AttributeError" (either "__getattribute__()" raises ' +- 'an\n' +- ' "AttributeError" because *name* is not an instance ' +- 'attribute or an\n' +- ' attribute in the class tree for "self"; or ' +- '"__get__()" of a *name*\n' +- ' property raises "AttributeError"). This method ' +- 'should either\n' +- ' return the (computed) attribute value or raise an ' +- '"AttributeError"\n' +- ' exception. The "object" class itself does not provide ' +- 'this method.\n' +- '\n' +- ' Note that if the attribute is found through the ' +- 'normal mechanism,\n' +- ' "__getattr__()" is not called. (This is an ' +- 'intentional asymmetry\n' +- ' between "__getattr__()" and "__setattr__()".) This is ' +- 'done both for\n' +- ' efficiency reasons and because otherwise ' +- '"__getattr__()" would have\n' +- ' no way to access other attributes of the instance. ' +- 'Note that at\n' +- ' least for instance variables, you can take total ' +- 'control by not\n' +- ' inserting any values in the instance attribute ' +- 'dictionary (but\n' +- ' instead inserting them in another object). See the\n' +- ' "__getattribute__()" method below for a way to ' +- 'actually get total\n' +- ' control over attribute access.\n' +- '\n' +- 'object.__getattribute__(self, name)\n' +- '\n' +- ' Called unconditionally to implement attribute ' +- 'accesses for\n' +- ' instances of the class. If the class also defines ' +- '"__getattr__()",\n' +- ' the latter will not be called unless ' +- '"__getattribute__()" either\n' +- ' calls it explicitly or raises an "AttributeError". ' +- 'This method\n' +- ' should return the (computed) attribute value or raise ' +- 'an\n' +- ' "AttributeError" exception. In order to avoid ' +- 'infinite recursion in\n' +- ' this method, its implementation should always call ' +- 'the base class\n' +- ' method with the same name to access any attributes it ' +- 'needs, for\n' +- ' example, "object.__getattribute__(self, name)".\n' +- '\n' +- ' Note:\n' +- '\n' +- ' This method may still be bypassed when looking up ' +- 'special methods\n' +- ' as the result of implicit invocation via language ' +- 'syntax or\n' +- ' built-in functions. See Special method lookup.\n' +- '\n' +- ' For certain sensitive attribute accesses, raises an ' +- 'auditing event\n' +- ' "object.__getattr__" with arguments "obj" and ' +- '"name".\n' +- '\n' +- 'object.__setattr__(self, name, value)\n' +- '\n' +- ' Called when an attribute assignment is attempted. ' +- 'This is called\n' +- ' instead of the normal mechanism (i.e. store the value ' +- 'in the\n' +- ' instance dictionary). *name* is the attribute name, ' +- '*value* is the\n' +- ' value to be assigned to it.\n' +- '\n' +- ' If "__setattr__()" wants to assign to an instance ' +- 'attribute, it\n' +- ' should call the base class method with the same name, ' +- 'for example,\n' +- ' "object.__setattr__(self, name, value)".\n' +- '\n' +- ' For certain sensitive attribute assignments, raises ' +- 'an auditing\n' +- ' event "object.__setattr__" with arguments "obj", ' +- '"name", "value".\n' +- '\n' +- 'object.__delattr__(self, name)\n' +- '\n' +- ' Like "__setattr__()" but for attribute deletion ' +- 'instead of\n' +- ' assignment. This should only be implemented if "del ' +- 'obj.name" is\n' +- ' meaningful for the object.\n' +- '\n' +- ' For certain sensitive attribute deletions, raises an ' +- 'auditing event\n' +- ' "object.__delattr__" with arguments "obj" and ' +- '"name".\n' +- '\n' +- 'object.__dir__(self)\n' +- '\n' +- ' Called when "dir()" is called on the object. An ' +- 'iterable must be\n' +- ' returned. "dir()" converts the returned iterable to a ' +- 'list and\n' +- ' sorts it.\n' +- '\n' +- '\n' +- 'Customizing module attribute access\n' +- '===================================\n' +- '\n' +- 'Special names "__getattr__" and "__dir__" can be also ' +- 'used to\n' +- 'customize access to module attributes. The "__getattr__" ' +- 'function at\n' +- 'the module level should accept one argument which is the ' +- 'name of an\n' +- 'attribute and return the computed value or raise an ' +- '"AttributeError".\n' +- 'If an attribute is not found on a module object through ' +- 'the normal\n' +- 'lookup, i.e. "object.__getattribute__()", then ' +- '"__getattr__" is\n' +- 'searched in the module "__dict__" before raising an ' +- '"AttributeError".\n' +- 'If found, it is called with the attribute name and the ' +- 'result is\n' +- 'returned.\n' +- '\n' +- 'The "__dir__" function should accept no arguments, and ' +- 'return an\n' +- 'iterable of strings that represents the names accessible ' +- 'on module. If\n' +- 'present, this function overrides the standard "dir()" ' +- 'search on a\n' +- 'module.\n' +- '\n' +- 'For a more fine grained customization of the module ' +- 'behavior (setting\n' +- 'attributes, properties, etc.), one can set the ' +- '"__class__" attribute\n' +- 'of a module object to a subclass of "types.ModuleType". ' +- 'For example:\n' +- '\n' +- ' import sys\n' +- ' from types import ModuleType\n' +- '\n' +- ' class VerboseModule(ModuleType):\n' +- ' def __repr__(self):\n' +- " return f'Verbose {self.__name__}'\n" +- '\n' +- ' def __setattr__(self, attr, value):\n' +- " print(f'Setting {attr}...')\n" +- ' super().__setattr__(attr, value)\n' +- '\n' +- ' sys.modules[__name__].__class__ = VerboseModule\n' +- '\n' +- 'Note:\n' +- '\n' +- ' Defining module "__getattr__" and setting module ' +- '"__class__" only\n' +- ' affect lookups made using the attribute access syntax ' +- '– directly\n' +- ' accessing the module globals (whether by code within ' +- 'the module, or\n' +- ' via a reference to the module’s globals dictionary) is ' +- 'unaffected.\n' +- '\n' +- 'Changed in version 3.5: "__class__" module attribute is ' +- 'now writable.\n' +- '\n' +- 'Added in version 3.7: "__getattr__" and "__dir__" module ' +- 'attributes.\n' +- '\n' +- 'See also:\n' +- '\n' +- ' **PEP 562** - Module __getattr__ and __dir__\n' +- ' Describes the "__getattr__" and "__dir__" functions ' +- 'on modules.\n' +- '\n' +- '\n' +- 'Implementing Descriptors\n' +- '========================\n' +- '\n' +- 'The following methods only apply when an instance of the ' +- 'class\n' +- 'containing the method (a so-called *descriptor* class) ' +- 'appears in an\n' +- '*owner* class (the descriptor must be in either the ' +- 'owner’s class\n' +- 'dictionary or in the class dictionary for one of its ' +- 'parents). In the\n' +- 'examples below, “the attribute†refers to the attribute ' +- 'whose name is\n' +- 'the key of the property in the owner class’ "__dict__". ' +- 'The "object"\n' +- 'class itself does not implement any of these protocols.\n' +- '\n' +- 'object.__get__(self, instance, owner=None)\n' +- '\n' +- ' Called to get the attribute of the owner class (class ' +- 'attribute\n' +- ' access) or of an instance of that class (instance ' +- 'attribute\n' +- ' access). The optional *owner* argument is the owner ' +- 'class, while\n' +- ' *instance* is the instance that the attribute was ' +- 'accessed through,\n' +- ' or "None" when the attribute is accessed through the ' +- '*owner*.\n' +- '\n' +- ' This method should return the computed attribute ' +- 'value or raise an\n' +- ' "AttributeError" exception.\n' +- '\n' +- ' **PEP 252** specifies that "__get__()" is callable ' +- 'with one or two\n' +- ' arguments. Python’s own built-in descriptors support ' +- 'this\n' +- ' specification; however, it is likely that some ' +- 'third-party tools\n' +- ' have descriptors that require both arguments. ' +- 'Python’s own\n' +- ' "__getattribute__()" implementation always passes in ' +- 'both arguments\n' +- ' whether they are required or not.\n' +- '\n' +- 'object.__set__(self, instance, value)\n' +- '\n' +- ' Called to set the attribute on an instance *instance* ' +- 'of the owner\n' +- ' class to a new value, *value*.\n' +- '\n' +- ' Note, adding "__set__()" or "__delete__()" changes ' +- 'the kind of\n' +- ' descriptor to a “data descriptorâ€. See Invoking ' +- 'Descriptors for\n' +- ' more details.\n' +- '\n' +- 'object.__delete__(self, instance)\n' +- '\n' +- ' Called to delete the attribute on an instance ' +- '*instance* of the\n' +- ' owner class.\n' +- '\n' +- 'Instances of descriptors may also have the ' +- '"__objclass__" attribute\n' +- 'present:\n' +- '\n' +- 'object.__objclass__\n' +- '\n' +- ' The attribute "__objclass__" is interpreted by the ' +- '"inspect" module\n' +- ' as specifying the class where this object was defined ' +- '(setting this\n' +- ' appropriately can assist in runtime introspection of ' +- 'dynamic class\n' +- ' attributes). For callables, it may indicate that an ' +- 'instance of the\n' +- ' given type (or a subclass) is expected or required as ' +- 'the first\n' +- ' positional argument (for example, CPython sets this ' +- 'attribute for\n' +- ' unbound methods that are implemented in C).\n' +- '\n' +- '\n' +- 'Invoking Descriptors\n' +- '====================\n' +- '\n' +- 'In general, a descriptor is an object attribute with ' +- '“binding\n' +- 'behaviorâ€, one whose attribute access has been ' +- 'overridden by methods\n' +- 'in the descriptor protocol: "__get__()", "__set__()", ' +- 'and\n' +- '"__delete__()". If any of those methods are defined for ' +- 'an object, it\n' +- 'is said to be a descriptor.\n' +- '\n' +- 'The default behavior for attribute access is to get, ' +- 'set, or delete\n' +- 'the attribute from an object’s dictionary. For instance, ' +- '"a.x" has a\n' +- 'lookup chain starting with "a.__dict__[\'x\']", then\n' +- '"type(a).__dict__[\'x\']", and continuing through the ' +- 'base classes of\n' +- '"type(a)" excluding metaclasses.\n' +- '\n' +- 'However, if the looked-up value is an object defining ' +- 'one of the\n' +- 'descriptor methods, then Python may override the default ' +- 'behavior and\n' +- 'invoke the descriptor method instead. Where this occurs ' +- 'in the\n' +- 'precedence chain depends on which descriptor methods ' +- 'were defined and\n' +- 'how they were called.\n' +- '\n' +- 'The starting point for descriptor invocation is a ' +- 'binding, "a.x". How\n' +- 'the arguments are assembled depends on "a":\n' +- '\n' +- 'Direct Call\n' +- ' The simplest and least common call is when user code ' +- 'directly\n' +- ' invokes a descriptor method: "x.__get__(a)".\n' +- '\n' +- 'Instance Binding\n' +- ' If binding to an object instance, "a.x" is ' +- 'transformed into the\n' +- ' call: "type(a).__dict__[\'x\'].__get__(a, type(a))".\n' +- '\n' +- 'Class Binding\n' +- ' If binding to a class, "A.x" is transformed into the ' +- 'call:\n' +- ' "A.__dict__[\'x\'].__get__(None, A)".\n' +- '\n' +- 'Super Binding\n' +- ' A dotted lookup such as "super(A, a).x" searches\n' +- ' "a.__class__.__mro__" for a base class "B" following ' +- '"A" and then\n' +- ' returns "B.__dict__[\'x\'].__get__(a, A)". If not a ' +- 'descriptor, "x"\n' +- ' is returned unchanged.\n' +- '\n' +- 'For instance bindings, the precedence of descriptor ' +- 'invocation depends\n' +- 'on which descriptor methods are defined. A descriptor ' +- 'can define any\n' +- 'combination of "__get__()", "__set__()" and ' +- '"__delete__()". If it\n' +- 'does not define "__get__()", then accessing the ' +- 'attribute will return\n' +- 'the descriptor object itself unless there is a value in ' +- 'the object’s\n' +- 'instance dictionary. If the descriptor defines ' +- '"__set__()" and/or\n' +- '"__delete__()", it is a data descriptor; if it defines ' +- 'neither, it is\n' +- 'a non-data descriptor. Normally, data descriptors ' +- 'define both\n' +- '"__get__()" and "__set__()", while non-data descriptors ' +- 'have just the\n' +- '"__get__()" method. Data descriptors with "__get__()" ' +- 'and "__set__()"\n' +- '(and/or "__delete__()") defined always override a ' +- 'redefinition in an\n' +- 'instance dictionary. In contrast, non-data descriptors ' +- 'can be\n' +- 'overridden by instances.\n' +- '\n' +- 'Python methods (including those decorated with ' +- '"@staticmethod" and\n' +- '"@classmethod") are implemented as non-data ' +- 'descriptors. Accordingly,\n' +- 'instances can redefine and override methods. This ' +- 'allows individual\n' +- 'instances to acquire behaviors that differ from other ' +- 'instances of the\n' +- 'same class.\n' +- '\n' +- 'The "property()" function is implemented as a data ' +- 'descriptor.\n' +- 'Accordingly, instances cannot override the behavior of a ' +- 'property.\n' +- '\n' +- '\n' +- '__slots__\n' +- '=========\n' +- '\n' +- '*__slots__* allow us to explicitly declare data members ' +- '(like\n' +- 'properties) and deny the creation of "__dict__" and ' +- '*__weakref__*\n' +- '(unless explicitly declared in *__slots__* or available ' +- 'in a parent.)\n' +- '\n' +- 'The space saved over using "__dict__" can be ' +- 'significant. Attribute\n' +- 'lookup speed can be significantly improved as well.\n' +- '\n' +- 'object.__slots__\n' +- '\n' +- ' This class variable can be assigned a string, ' +- 'iterable, or sequence\n' +- ' of strings with variable names used by instances. ' +- '*__slots__*\n' +- ' reserves space for the declared variables and ' +- 'prevents the\n' +- ' automatic creation of "__dict__" and *__weakref__* ' +- 'for each\n' +- ' instance.\n' +- '\n' +- 'Notes on using *__slots__*:\n' +- '\n' +- '* When inheriting from a class without *__slots__*, the ' +- '"__dict__" and\n' +- ' *__weakref__* attribute of the instances will always ' +- 'be accessible.\n' +- '\n' +- '* Without a "__dict__" variable, instances cannot be ' +- 'assigned new\n' +- ' variables not listed in the *__slots__* definition. ' +- 'Attempts to\n' +- ' assign to an unlisted variable name raises ' +- '"AttributeError". If\n' +- ' dynamic assignment of new variables is desired, then ' +- 'add\n' +- ' "\'__dict__\'" to the sequence of strings in the ' +- '*__slots__*\n' +- ' declaration.\n' +- '\n' +- '* Without a *__weakref__* variable for each instance, ' +- 'classes defining\n' +- ' *__slots__* do not support "weak references" to its ' +- 'instances. If\n' +- ' weak reference support is needed, then add ' +- '"\'__weakref__\'" to the\n' +- ' sequence of strings in the *__slots__* declaration.\n' +- '\n' +- '* *__slots__* are implemented at the class level by ' +- 'creating\n' +- ' descriptors for each variable name. As a result, ' +- 'class attributes\n' +- ' cannot be used to set default values for instance ' +- 'variables defined\n' +- ' by *__slots__*; otherwise, the class attribute would ' +- 'overwrite the\n' +- ' descriptor assignment.\n' +- '\n' +- '* The action of a *__slots__* declaration is not limited ' +- 'to the class\n' +- ' where it is defined. *__slots__* declared in parents ' +- 'are available\n' +- ' in child classes. However, instances of a child ' +- 'subclass will get a\n' +- ' "__dict__" and *__weakref__* unless the subclass also ' +- 'defines\n' +- ' *__slots__* (which should only contain names of any ' +- '*additional*\n' +- ' slots).\n' +- '\n' +- '* If a class defines a slot also defined in a base ' +- 'class, the instance\n' +- ' variable defined by the base class slot is ' +- 'inaccessible (except by\n' +- ' retrieving its descriptor directly from the base ' +- 'class). This\n' +- ' renders the meaning of the program undefined. In the ' +- 'future, a\n' +- ' check may be added to prevent this.\n' +- '\n' +- '* "TypeError" will be raised if nonempty *__slots__* are ' +- 'defined for a\n' +- ' class derived from a ""variable-length" built-in type" ' +- 'such as\n' +- ' "int", "bytes", and "tuple".\n' +- '\n' +- '* Any non-string *iterable* may be assigned to ' +- '*__slots__*.\n' +- '\n' +- '* If a "dictionary" is used to assign *__slots__*, the ' +- 'dictionary keys\n' +- ' will be used as the slot names. The values of the ' +- 'dictionary can be\n' +- ' used to provide per-attribute docstrings that will be ' +- 'recognised by\n' +- ' "inspect.getdoc()" and displayed in the output of ' +- '"help()".\n' +- '\n' +- '* "__class__" assignment works only if both classes have ' +- 'the same\n' +- ' *__slots__*.\n' +- '\n' +- '* Multiple inheritance with multiple slotted parent ' +- 'classes can be\n' +- ' used, but only one parent is allowed to have ' +- 'attributes created by\n' +- ' slots (the other bases must have empty slot layouts) - ' +- 'violations\n' +- ' raise "TypeError".\n' +- '\n' +- '* If an *iterator* is used for *__slots__* then a ' +- '*descriptor* is\n' +- ' created for each of the iterator’s values. However, ' +- 'the *__slots__*\n' +- ' attribute will be an empty iterator.\n', +- 'attribute-references': 'Attribute references\n' +- '********************\n' +- '\n' +- 'An attribute reference is a primary followed by a ' +- 'period and a name:\n' +- '\n' +- ' attributeref ::= primary "." identifier\n' +- '\n' +- 'The primary must evaluate to an object of a type ' +- 'that supports\n' +- 'attribute references, which most objects do. This ' +- 'object is then\n' +- 'asked to produce the attribute whose name is the ' +- 'identifier. The type\n' +- 'and value produced is determined by the object. ' +- 'Multiple evaluations\n' +- 'of the same attribute reference may yield different ' +- 'objects.\n' +- '\n' +- 'This production can be customized by overriding the\n' +- '"__getattribute__()" method or the "__getattr__()" ' +- 'method. The\n' +- '"__getattribute__()" method is called first and ' +- 'either returns a value\n' +- 'or raises "AttributeError" if the attribute is not ' +- 'available.\n' +- '\n' +- 'If an "AttributeError" is raised and the object has ' +- 'a "__getattr__()"\n' +- 'method, that method is called as a fallback.\n', +- 'augassign': 'Augmented assignment statements\n' +- '*******************************\n' +- '\n' +- 'Augmented assignment is the combination, in a single statement, ' +- 'of a\n' +- 'binary operation and an assignment statement:\n' +- '\n' +- ' augmented_assignment_stmt ::= augtarget augop ' +- '(expression_list | yield_expression)\n' +- ' augtarget ::= identifier | attributeref | ' +- 'subscription | slicing\n' +- ' augop ::= "+=" | "-=" | "*=" | "@=" | ' +- '"/=" | "//=" | "%=" | "**="\n' +- ' | ">>=" | "<<=" | "&=" | "^=" | "|="\n' +- '\n' +- '(See section Primaries for the syntax definitions of the last ' +- 'three\n' +- 'symbols.)\n' +- '\n' +- 'An augmented assignment evaluates the target (which, unlike ' +- 'normal\n' +- 'assignment statements, cannot be an unpacking) and the ' +- 'expression\n' +- 'list, performs the binary operation specific to the type of ' +- 'assignment\n' +- 'on the two operands, and assigns the result to the original ' +- 'target.\n' +- 'The target is only evaluated once.\n' +- '\n' +- 'An augmented assignment statement like "x += 1" can be ' +- 'rewritten as "x\n' +- '= x + 1" to achieve a similar, but not exactly equal effect. In ' +- 'the\n' +- 'augmented version, "x" is only evaluated once. Also, when ' +- 'possible,\n' +- 'the actual operation is performed *in-place*, meaning that ' +- 'rather than\n' +- 'creating a new object and assigning that to the target, the old ' +- 'object\n' +- 'is modified instead.\n' +- '\n' +- 'Unlike normal assignments, augmented assignments evaluate the ' +- 'left-\n' +- 'hand side *before* evaluating the right-hand side. For ' +- 'example, "a[i]\n' +- '+= f(x)" first looks-up "a[i]", then it evaluates "f(x)" and ' +- 'performs\n' +- 'the addition, and lastly, it writes the result back to "a[i]".\n' +- '\n' +- 'With the exception of assigning to tuples and multiple targets ' +- 'in a\n' +- 'single statement, the assignment done by augmented assignment\n' +- 'statements is handled the same way as normal assignments. ' +- 'Similarly,\n' +- 'with the exception of the possible *in-place* behavior, the ' +- 'binary\n' +- 'operation performed by augmented assignment is the same as the ' +- 'normal\n' +- 'binary operations.\n' +- '\n' +- 'For targets which are attribute references, the same caveat ' +- 'about\n' +- 'class and instance attributes applies as for regular ' +- 'assignments.\n', +- 'await': 'Await expression\n' +- '****************\n' +- '\n' +- 'Suspend the execution of *coroutine* on an *awaitable* object. Can\n' +- 'only be used inside a *coroutine function*.\n' +- '\n' +- ' await_expr ::= "await" primary\n' +- '\n' +- 'Added in version 3.5.\n', +- 'binary': 'Binary arithmetic operations\n' +- '****************************\n' +- '\n' +- 'The binary arithmetic operations have the conventional priority\n' +- 'levels. Note that some of these operations also apply to certain ' +- 'non-\n' +- 'numeric types. Apart from the power operator, there are only two\n' +- 'levels, one for multiplicative operators and one for additive\n' +- 'operators:\n' +- '\n' +- ' m_expr ::= u_expr | m_expr "*" u_expr | m_expr "@" m_expr |\n' +- ' m_expr "//" u_expr | m_expr "/" u_expr |\n' +- ' m_expr "%" u_expr\n' +- ' a_expr ::= m_expr | a_expr "+" m_expr | a_expr "-" m_expr\n' +- '\n' +- 'The "*" (multiplication) operator yields the product of its ' +- 'arguments.\n' +- 'The arguments must either both be numbers, or one argument must be ' +- 'an\n' +- 'integer and the other must be a sequence. In the former case, the\n' +- 'numbers are converted to a common real type and then multiplied\n' +- 'together. In the latter case, sequence repetition is performed; ' +- 'a\n' +- 'negative repetition factor yields an empty sequence.\n' +- '\n' +- 'This operation can be customized using the special "__mul__()" ' +- 'and\n' +- '"__rmul__()" methods.\n' +- '\n' +- 'Changed in version 3.14: If only one operand is a complex number, ' +- 'the\n' +- 'other operand is converted to a floating-point number.\n' +- '\n' +- 'The "@" (at) operator is intended to be used for matrix\n' +- 'multiplication. No builtin Python types implement this operator.\n' +- '\n' +- 'This operation can be customized using the special "__matmul__()" ' +- 'and\n' +- '"__rmatmul__()" methods.\n' +- '\n' +- 'Added in version 3.5.\n' +- '\n' +- 'The "/" (division) and "//" (floor division) operators yield the\n' +- 'quotient of their arguments. The numeric arguments are first\n' +- 'converted to a common type. Division of integers yields a float, ' +- 'while\n' +- 'floor division of integers results in an integer; the result is ' +- 'that\n' +- 'of mathematical division with the ‘floor’ function applied to the\n' +- 'result. Division by zero raises the "ZeroDivisionError" ' +- 'exception.\n' +- '\n' +- 'The division operation can be customized using the special\n' +- '"__truediv__()" and "__rtruediv__()" methods. The floor division\n' +- 'operation can be customized using the special "__floordiv__()" ' +- 'and\n' +- '"__rfloordiv__()" methods.\n' +- '\n' +- 'The "%" (modulo) operator yields the remainder from the division ' +- 'of\n' +- 'the first argument by the second. The numeric arguments are ' +- 'first\n' +- 'converted to a common type. A zero right argument raises the\n' +- '"ZeroDivisionError" exception. The arguments may be ' +- 'floating-point\n' +- 'numbers, e.g., "3.14%0.7" equals "0.34" (since "3.14" equals ' +- '"4*0.7 +\n' +- '0.34".) The modulo operator always yields a result with the same ' +- 'sign\n' +- 'as its second operand (or zero); the absolute value of the result ' +- 'is\n' +- 'strictly smaller than the absolute value of the second operand ' +- '[1].\n' +- '\n' +- 'The floor division and modulo operators are connected by the ' +- 'following\n' +- 'identity: "x == (x//y)*y + (x%y)". Floor division and modulo are ' +- 'also\n' +- 'connected with the built-in function "divmod()": "divmod(x, y) ==\n' +- '(x//y, x%y)". [2].\n' +- '\n' +- 'In addition to performing the modulo operation on numbers, the ' +- '"%"\n' +- 'operator is also overloaded by string objects to perform ' +- 'old-style\n' +- 'string formatting (also known as interpolation). The syntax for\n' +- 'string formatting is described in the Python Library Reference,\n' +- 'section printf-style String Formatting.\n' +- '\n' +- 'The *modulo* operation can be customized using the special ' +- '"__mod__()"\n' +- 'and "__rmod__()" methods.\n' +- '\n' +- 'The floor division operator, the modulo operator, and the ' +- '"divmod()"\n' +- 'function are not defined for complex numbers. Instead, convert to ' +- 'a\n' +- 'floating-point number using the "abs()" function if appropriate.\n' +- '\n' +- 'The "+" (addition) operator yields the sum of its arguments. The\n' +- 'arguments must either both be numbers or both be sequences of the ' +- 'same\n' +- 'type. In the former case, the numbers are converted to a common ' +- 'real\n' +- 'type and then added together. In the latter case, the sequences ' +- 'are\n' +- 'concatenated.\n' +- '\n' +- 'This operation can be customized using the special "__add__()" ' +- 'and\n' +- '"__radd__()" methods.\n' +- '\n' +- 'Changed in version 3.14: If only one operand is a complex number, ' +- 'the\n' +- 'other operand is converted to a floating-point number.\n' +- '\n' +- 'The "-" (subtraction) operator yields the difference of its ' +- 'arguments.\n' +- 'The numeric arguments are first converted to a common real type.\n' +- '\n' +- 'This operation can be customized using the special "__sub__()" ' +- 'and\n' +- '"__rsub__()" methods.\n' +- '\n' +- 'Changed in version 3.14: If only one operand is a complex number, ' +- 'the\n' +- 'other operand is converted to a floating-point number.\n', +- 'bitwise': 'Binary bitwise operations\n' +- '*************************\n' +- '\n' +- 'Each of the three bitwise operations has a different priority ' +- 'level:\n' +- '\n' +- ' and_expr ::= shift_expr | and_expr "&" shift_expr\n' +- ' xor_expr ::= and_expr | xor_expr "^" and_expr\n' +- ' or_expr ::= xor_expr | or_expr "|" xor_expr\n' +- '\n' +- 'The "&" operator yields the bitwise AND of its arguments, which ' +- 'must\n' +- 'be integers or one of them must be a custom object overriding\n' +- '"__and__()" or "__rand__()" special methods.\n' +- '\n' +- 'The "^" operator yields the bitwise XOR (exclusive OR) of its\n' +- 'arguments, which must be integers or one of them must be a ' +- 'custom\n' +- 'object overriding "__xor__()" or "__rxor__()" special methods.\n' +- '\n' +- 'The "|" operator yields the bitwise (inclusive) OR of its ' +- 'arguments,\n' +- 'which must be integers or one of them must be a custom object\n' +- 'overriding "__or__()" or "__ror__()" special methods.\n', +- 'bltin-code-objects': 'Code Objects\n' +- '************\n' +- '\n' +- 'Code objects are used by the implementation to ' +- 'represent “pseudo-\n' +- 'compiled†executable Python code such as a function ' +- 'body. They differ\n' +- 'from function objects because they don’t contain a ' +- 'reference to their\n' +- 'global execution environment. Code objects are ' +- 'returned by the built-\n' +- 'in "compile()" function and can be extracted from ' +- 'function objects\n' +- 'through their "__code__" attribute. See also the ' +- '"code" module.\n' +- '\n' +- 'Accessing "__code__" raises an auditing event ' +- '"object.__getattr__"\n' +- 'with arguments "obj" and ""__code__"".\n' +- '\n' +- 'A code object can be executed or evaluated by passing ' +- 'it (instead of a\n' +- 'source string) to the "exec()" or "eval()" built-in ' +- 'functions.\n' +- '\n' +- 'See The standard type hierarchy for more ' +- 'information.\n', +- 'bltin-ellipsis-object': 'The Ellipsis Object\n' +- '*******************\n' +- '\n' +- 'This object is commonly used by slicing (see ' +- 'Slicings). It supports\n' +- 'no special operations. There is exactly one ' +- 'ellipsis object, named\n' +- '"Ellipsis" (a built-in name). "type(Ellipsis)()" ' +- 'produces the\n' +- '"Ellipsis" singleton.\n' +- '\n' +- 'It is written as "Ellipsis" or "...".\n', +- 'bltin-null-object': 'The Null Object\n' +- '***************\n' +- '\n' +- 'This object is returned by functions that don’t ' +- 'explicitly return a\n' +- 'value. It supports no special operations. There is ' +- 'exactly one null\n' +- 'object, named "None" (a built-in name). "type(None)()" ' +- 'produces the\n' +- 'same singleton.\n' +- '\n' +- 'It is written as "None".\n', +- 'bltin-type-objects': 'Type Objects\n' +- '************\n' +- '\n' +- 'Type objects represent the various object types. An ' +- 'object’s type is\n' +- 'accessed by the built-in function "type()". There are ' +- 'no special\n' +- 'operations on types. The standard module "types" ' +- 'defines names for\n' +- 'all standard built-in types.\n' +- '\n' +- 'Types are written like this: "".\n', +- 'booleans': 'Boolean operations\n' +- '******************\n' +- '\n' +- ' or_test ::= and_test | or_test "or" and_test\n' +- ' and_test ::= not_test | and_test "and" not_test\n' +- ' not_test ::= comparison | "not" not_test\n' +- '\n' +- 'In the context of Boolean operations, and also when expressions ' +- 'are\n' +- 'used by control flow statements, the following values are ' +- 'interpreted\n' +- 'as false: "False", "None", numeric zero of all types, and empty\n' +- 'strings and containers (including strings, tuples, lists,\n' +- 'dictionaries, sets and frozensets). All other values are ' +- 'interpreted\n' +- 'as true. User-defined objects can customize their truth value ' +- 'by\n' +- 'providing a "__bool__()" method.\n' +- '\n' +- 'The operator "not" yields "True" if its argument is false, ' +- '"False"\n' +- 'otherwise.\n' +- '\n' +- 'The expression "x and y" first evaluates *x*; if *x* is false, ' +- 'its\n' +- 'value is returned; otherwise, *y* is evaluated and the resulting ' +- 'value\n' +- 'is returned.\n' +- '\n' +- 'The expression "x or y" first evaluates *x*; if *x* is true, its ' +- 'value\n' +- 'is returned; otherwise, *y* is evaluated and the resulting value ' +- 'is\n' +- 'returned.\n' +- '\n' +- 'Note that neither "and" nor "or" restrict the value and type ' +- 'they\n' +- 'return to "False" and "True", but rather return the last ' +- 'evaluated\n' +- 'argument. This is sometimes useful, e.g., if "s" is a string ' +- 'that\n' +- 'should be replaced by a default value if it is empty, the ' +- 'expression\n' +- '"s or \'foo\'" yields the desired value. Because "not" has to ' +- 'create a\n' +- 'new value, it returns a boolean value regardless of the type of ' +- 'its\n' +- 'argument (for example, "not \'foo\'" produces "False" rather ' +- 'than "\'\'".)\n', +- 'break': 'The "break" statement\n' +- '*********************\n' +- '\n' +- ' break_stmt ::= "break"\n' +- '\n' +- '"break" may only occur syntactically nested in a "for" or "while"\n' +- 'loop, but not nested in a function or class definition within that\n' +- 'loop.\n' +- '\n' +- 'It terminates the nearest enclosing loop, skipping the optional ' +- '"else"\n' +- 'clause if the loop has one.\n' +- '\n' +- 'If a "for" loop is terminated by "break", the loop control target\n' +- 'keeps its current value.\n' +- '\n' +- 'When "break" passes control out of a "try" statement with a ' +- '"finally"\n' +- 'clause, that "finally" clause is executed before really leaving ' +- 'the\n' +- 'loop.\n', +- 'callable-types': 'Emulating callable objects\n' +- '**************************\n' +- '\n' +- 'object.__call__(self[, args...])\n' +- '\n' +- ' Called when the instance is “called†as a function; if ' +- 'this method\n' +- ' is defined, "x(arg1, arg2, ...)" roughly translates to\n' +- ' "type(x).__call__(x, arg1, ...)". The "object" class ' +- 'itself does\n' +- ' not provide this method.\n', +- 'calls': 'Calls\n' +- '*****\n' +- '\n' +- 'A call calls a callable object (e.g., a *function*) with a ' +- 'possibly\n' +- 'empty series of *arguments*:\n' +- '\n' +- ' call ::= primary "(" [argument_list [","] | ' +- 'comprehension] ")"\n' +- ' argument_list ::= positional_arguments ["," ' +- 'starred_and_keywords]\n' +- ' ["," keywords_arguments]\n' +- ' | starred_and_keywords ["," ' +- 'keywords_arguments]\n' +- ' | keywords_arguments\n' +- ' positional_arguments ::= positional_item ("," positional_item)*\n' +- ' positional_item ::= assignment_expression | "*" expression\n' +- ' starred_and_keywords ::= ("*" expression | keyword_item)\n' +- ' ("," "*" expression | "," ' +- 'keyword_item)*\n' +- ' keywords_arguments ::= (keyword_item | "**" expression)\n' +- ' ("," keyword_item | "," "**" ' +- 'expression)*\n' +- ' keyword_item ::= identifier "=" expression\n' +- '\n' +- 'An optional trailing comma may be present after the positional and\n' +- 'keyword arguments but does not affect the semantics.\n' +- '\n' +- 'The primary must evaluate to a callable object (user-defined\n' +- 'functions, built-in functions, methods of built-in objects, class\n' +- 'objects, methods of class instances, and all objects having a\n' +- '"__call__()" method are callable). All argument expressions are\n' +- 'evaluated before the call is attempted. Please refer to section\n' +- 'Function definitions for the syntax of formal *parameter* lists.\n' +- '\n' +- 'If keyword arguments are present, they are first converted to\n' +- 'positional arguments, as follows. First, a list of unfilled slots ' +- 'is\n' +- 'created for the formal parameters. If there are N positional\n' +- 'arguments, they are placed in the first N slots. Next, for each\n' +- 'keyword argument, the identifier is used to determine the\n' +- 'corresponding slot (if the identifier is the same as the first ' +- 'formal\n' +- 'parameter name, the first slot is used, and so on). If the slot ' +- 'is\n' +- 'already filled, a "TypeError" exception is raised. Otherwise, the\n' +- 'argument is placed in the slot, filling it (even if the expression ' +- 'is\n' +- '"None", it fills the slot). When all arguments have been ' +- 'processed,\n' +- 'the slots that are still unfilled are filled with the ' +- 'corresponding\n' +- 'default value from the function definition. (Default values are\n' +- 'calculated, once, when the function is defined; thus, a mutable ' +- 'object\n' +- 'such as a list or dictionary used as default value will be shared ' +- 'by\n' +- 'all calls that don’t specify an argument value for the ' +- 'corresponding\n' +- 'slot; this should usually be avoided.) If there are any unfilled\n' +- 'slots for which no default value is specified, a "TypeError" ' +- 'exception\n' +- 'is raised. Otherwise, the list of filled slots is used as the\n' +- 'argument list for the call.\n' +- '\n' +- '**CPython implementation detail:** An implementation may provide\n' +- 'built-in functions whose positional parameters do not have names, ' +- 'even\n' +- 'if they are ‘named’ for the purpose of documentation, and which\n' +- 'therefore cannot be supplied by keyword. In CPython, this is the ' +- 'case\n' +- 'for functions implemented in C that use "PyArg_ParseTuple()" to ' +- 'parse\n' +- 'their arguments.\n' +- '\n' +- 'If there are more positional arguments than there are formal ' +- 'parameter\n' +- 'slots, a "TypeError" exception is raised, unless a formal ' +- 'parameter\n' +- 'using the syntax "*identifier" is present; in this case, that ' +- 'formal\n' +- 'parameter receives a tuple containing the excess positional ' +- 'arguments\n' +- '(or an empty tuple if there were no excess positional arguments).\n' +- '\n' +- 'If any keyword argument does not correspond to a formal parameter\n' +- 'name, a "TypeError" exception is raised, unless a formal parameter\n' +- 'using the syntax "**identifier" is present; in this case, that ' +- 'formal\n' +- 'parameter receives a dictionary containing the excess keyword\n' +- 'arguments (using the keywords as keys and the argument values as\n' +- 'corresponding values), or a (new) empty dictionary if there were ' +- 'no\n' +- 'excess keyword arguments.\n' +- '\n' +- 'If the syntax "*expression" appears in the function call, ' +- '"expression"\n' +- 'must evaluate to an *iterable*. Elements from these iterables are\n' +- 'treated as if they were additional positional arguments. For the ' +- 'call\n' +- '"f(x1, x2, *y, x3, x4)", if *y* evaluates to a sequence *y1*, …, ' +- '*yM*,\n' +- 'this is equivalent to a call with M+4 positional arguments *x1*, ' +- '*x2*,\n' +- '*y1*, …, *yM*, *x3*, *x4*.\n' +- '\n' +- 'A consequence of this is that although the "*expression" syntax ' +- 'may\n' +- 'appear *after* explicit keyword arguments, it is processed ' +- '*before*\n' +- 'the keyword arguments (and any "**expression" arguments – see ' +- 'below).\n' +- 'So:\n' +- '\n' +- ' >>> def f(a, b):\n' +- ' ... print(a, b)\n' +- ' ...\n' +- ' >>> f(b=1, *(2,))\n' +- ' 2 1\n' +- ' >>> f(a=1, *(2,))\n' +- ' Traceback (most recent call last):\n' +- ' File "", line 1, in \n' +- " TypeError: f() got multiple values for keyword argument 'a'\n" +- ' >>> f(1, *(2,))\n' +- ' 1 2\n' +- '\n' +- 'It is unusual for both keyword arguments and the "*expression" ' +- 'syntax\n' +- 'to be used in the same call, so in practice this confusion does ' +- 'not\n' +- 'often arise.\n' +- '\n' +- 'If the syntax "**expression" appears in the function call,\n' +- '"expression" must evaluate to a *mapping*, the contents of which ' +- 'are\n' +- 'treated as additional keyword arguments. If a parameter matching a ' +- 'key\n' +- 'has already been given a value (by an explicit keyword argument, ' +- 'or\n' +- 'from another unpacking), a "TypeError" exception is raised.\n' +- '\n' +- 'When "**expression" is used, each key in this mapping must be a\n' +- 'string. Each value from the mapping is assigned to the first ' +- 'formal\n' +- 'parameter eligible for keyword assignment whose name is equal to ' +- 'the\n' +- 'key. A key need not be a Python identifier (e.g. ""max-temp °F"" ' +- 'is\n' +- 'acceptable, although it will not match any formal parameter that ' +- 'could\n' +- 'be declared). If there is no match to a formal parameter the ' +- 'key-value\n' +- 'pair is collected by the "**" parameter, if there is one, or if ' +- 'there\n' +- 'is not, a "TypeError" exception is raised.\n' +- '\n' +- 'Formal parameters using the syntax "*identifier" or "**identifier"\n' +- 'cannot be used as positional argument slots or as keyword argument\n' +- 'names.\n' +- '\n' +- 'Changed in version 3.5: Function calls accept any number of "*" ' +- 'and\n' +- '"**" unpackings, positional arguments may follow iterable ' +- 'unpackings\n' +- '("*"), and keyword arguments may follow dictionary unpackings ' +- '("**").\n' +- 'Originally proposed by **PEP 448**.\n' +- '\n' +- 'A call always returns some value, possibly "None", unless it raises ' +- 'an\n' +- 'exception. How this value is computed depends on the type of the\n' +- 'callable object.\n' +- '\n' +- 'If it is—\n' +- '\n' +- 'a user-defined function:\n' +- ' The code block for the function is executed, passing it the\n' +- ' argument list. The first thing the code block will do is bind ' +- 'the\n' +- ' formal parameters to the arguments; this is described in ' +- 'section\n' +- ' Function definitions. When the code block executes a "return"\n' +- ' statement, this specifies the return value of the function ' +- 'call.\n' +- ' If execution reaches the end of the code block without executing ' +- 'a\n' +- ' "return" statement, the return value is "None".\n' +- '\n' +- 'a built-in function or method:\n' +- ' The result is up to the interpreter; see Built-in Functions for ' +- 'the\n' +- ' descriptions of built-in functions and methods.\n' +- '\n' +- 'a class object:\n' +- ' A new instance of that class is returned.\n' +- '\n' +- 'a class instance method:\n' +- ' The corresponding user-defined function is called, with an ' +- 'argument\n' +- ' list that is one longer than the argument list of the call: the\n' +- ' instance becomes the first argument.\n' +- '\n' +- 'a class instance:\n' +- ' The class must define a "__call__()" method; the effect is then ' +- 'the\n' +- ' same as if that method was called.\n', +- 'class': 'Class definitions\n' +- '*****************\n' +- '\n' +- 'A class definition defines a class object (see section The ' +- 'standard\n' +- 'type hierarchy):\n' +- '\n' +- ' classdef ::= [decorators] "class" classname [type_params] ' +- '[inheritance] ":" suite\n' +- ' inheritance ::= "(" [argument_list] ")"\n' +- ' classname ::= identifier\n' +- '\n' +- 'A class definition is an executable statement. The inheritance ' +- 'list\n' +- 'usually gives a list of base classes (see Metaclasses for more\n' +- 'advanced uses), so each item in the list should evaluate to a ' +- 'class\n' +- 'object which allows subclassing. Classes without an inheritance ' +- 'list\n' +- 'inherit, by default, from the base class "object"; hence,\n' +- '\n' +- ' class Foo:\n' +- ' pass\n' +- '\n' +- 'is equivalent to\n' +- '\n' +- ' class Foo(object):\n' +- ' pass\n' +- '\n' +- 'The class’s suite is then executed in a new execution frame (see\n' +- 'Naming and binding), using a newly created local namespace and the\n' +- 'original global namespace. (Usually, the suite contains mostly\n' +- 'function definitions.) When the class’s suite finishes execution, ' +- 'its\n' +- 'execution frame is discarded but its local namespace is saved. [5] ' +- 'A\n' +- 'class object is then created using the inheritance list for the ' +- 'base\n' +- 'classes and the saved local namespace for the attribute ' +- 'dictionary.\n' +- 'The class name is bound to this class object in the original local\n' +- 'namespace.\n' +- '\n' +- 'The order in which attributes are defined in the class body is\n' +- 'preserved in the new class’s "__dict__". Note that this is ' +- 'reliable\n' +- 'only right after the class is created and only for classes that ' +- 'were\n' +- 'defined using the definition syntax.\n' +- '\n' +- 'Class creation can be customized heavily using metaclasses.\n' +- '\n' +- 'Classes can also be decorated: just like when decorating ' +- 'functions,\n' +- '\n' +- ' @f1(arg)\n' +- ' @f2\n' +- ' class Foo: pass\n' +- '\n' +- 'is roughly equivalent to\n' +- '\n' +- ' class Foo: pass\n' +- ' Foo = f1(arg)(f2(Foo))\n' +- '\n' +- 'The evaluation rules for the decorator expressions are the same as ' +- 'for\n' +- 'function decorators. The result is then bound to the class name.\n' +- '\n' +- 'Changed in version 3.9: Classes may be decorated with any valid\n' +- '"assignment_expression". Previously, the grammar was much more\n' +- 'restrictive; see **PEP 614** for details.\n' +- '\n' +- 'A list of type parameters may be given in square brackets ' +- 'immediately\n' +- 'after the class’s name. This indicates to static type checkers ' +- 'that\n' +- 'the class is generic. At runtime, the type parameters can be ' +- 'retrieved\n' +- 'from the class’s "__type_params__" attribute. See Generic classes ' +- 'for\n' +- 'more.\n' +- '\n' +- 'Changed in version 3.12: Type parameter lists are new in Python ' +- '3.12.\n' +- '\n' +- '**Programmer’s note:** Variables defined in the class definition ' +- 'are\n' +- 'class attributes; they are shared by instances. Instance ' +- 'attributes\n' +- 'can be set in a method with "self.name = value". Both class and\n' +- 'instance attributes are accessible through the notation ' +- '“"self.name"â€,\n' +- 'and an instance attribute hides a class attribute with the same ' +- 'name\n' +- 'when accessed in this way. Class attributes can be used as ' +- 'defaults\n' +- 'for instance attributes, but using mutable values there can lead ' +- 'to\n' +- 'unexpected results. Descriptors can be used to create instance\n' +- 'variables with different implementation details.\n' +- '\n' +- 'See also:\n' +- '\n' +- ' **PEP 3115** - Metaclasses in Python 3000\n' +- ' The proposal that changed the declaration of metaclasses to ' +- 'the\n' +- ' current syntax, and the semantics for how classes with\n' +- ' metaclasses are constructed.\n' +- '\n' +- ' **PEP 3129** - Class Decorators\n' +- ' The proposal that added class decorators. Function and ' +- 'method\n' +- ' decorators were introduced in **PEP 318**.\n', +- 'comparisons': 'Comparisons\n' +- '***********\n' +- '\n' +- 'Unlike C, all comparison operations in Python have the same ' +- 'priority,\n' +- 'which is lower than that of any arithmetic, shifting or ' +- 'bitwise\n' +- 'operation. Also unlike C, expressions like "a < b < c" have ' +- 'the\n' +- 'interpretation that is conventional in mathematics:\n' +- '\n' +- ' comparison ::= or_expr (comp_operator or_expr)*\n' +- ' comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n' +- ' | "is" ["not"] | ["not"] "in"\n' +- '\n' +- 'Comparisons yield boolean values: "True" or "False". Custom ' +- '*rich\n' +- 'comparison methods* may return non-boolean values. In this ' +- 'case Python\n' +- 'will call "bool()" on such value in boolean contexts.\n' +- '\n' +- 'Comparisons can be chained arbitrarily, e.g., "x < y <= z" ' +- 'is\n' +- 'equivalent to "x < y and y <= z", except that "y" is ' +- 'evaluated only\n' +- 'once (but in both cases "z" is not evaluated at all when "x < ' +- 'y" is\n' +- 'found to be false).\n' +- '\n' +- 'Formally, if *a*, *b*, *c*, …, *y*, *z* are expressions and ' +- '*op1*,\n' +- '*op2*, …, *opN* are comparison operators, then "a op1 b op2 c ' +- '... y\n' +- 'opN z" is equivalent to "a op1 b and b op2 c and ... y opN ' +- 'z", except\n' +- 'that each expression is evaluated at most once.\n' +- '\n' +- 'Note that "a op1 b op2 c" doesn’t imply any kind of ' +- 'comparison between\n' +- '*a* and *c*, so that, e.g., "x < y > z" is perfectly legal ' +- '(though\n' +- 'perhaps not pretty).\n' +- '\n' +- '\n' +- 'Value comparisons\n' +- '=================\n' +- '\n' +- 'The operators "<", ">", "==", ">=", "<=", and "!=" compare ' +- 'the values\n' +- 'of two objects. The objects do not need to have the same ' +- 'type.\n' +- '\n' +- 'Chapter Objects, values and types states that objects have a ' +- 'value (in\n' +- 'addition to type and identity). The value of an object is a ' +- 'rather\n' +- 'abstract notion in Python: For example, there is no canonical ' +- 'access\n' +- 'method for an object’s value. Also, there is no requirement ' +- 'that the\n' +- 'value of an object should be constructed in a particular way, ' +- 'e.g.\n' +- 'comprised of all its data attributes. Comparison operators ' +- 'implement a\n' +- 'particular notion of what the value of an object is. One can ' +- 'think of\n' +- 'them as defining the value of an object indirectly, by means ' +- 'of their\n' +- 'comparison implementation.\n' +- '\n' +- 'Because all types are (direct or indirect) subtypes of ' +- '"object", they\n' +- 'inherit the default comparison behavior from "object". Types ' +- 'can\n' +- 'customize their comparison behavior by implementing *rich ' +- 'comparison\n' +- 'methods* like "__lt__()", described in Basic customization.\n' +- '\n' +- 'The default behavior for equality comparison ("==" and "!=") ' +- 'is based\n' +- 'on the identity of the objects. Hence, equality comparison ' +- 'of\n' +- 'instances with the same identity results in equality, and ' +- 'equality\n' +- 'comparison of instances with different identities results in\n' +- 'inequality. A motivation for this default behavior is the ' +- 'desire that\n' +- 'all objects should be reflexive (i.e. "x is y" implies "x == ' +- 'y").\n' +- '\n' +- 'A default order comparison ("<", ">", "<=", and ">=") is not ' +- 'provided;\n' +- 'an attempt raises "TypeError". A motivation for this default ' +- 'behavior\n' +- 'is the lack of a similar invariant as for equality.\n' +- '\n' +- 'The behavior of the default equality comparison, that ' +- 'instances with\n' +- 'different identities are always unequal, may be in contrast ' +- 'to what\n' +- 'types will need that have a sensible definition of object ' +- 'value and\n' +- 'value-based equality. Such types will need to customize ' +- 'their\n' +- 'comparison behavior, and in fact, a number of built-in types ' +- 'have done\n' +- 'that.\n' +- '\n' +- 'The following list describes the comparison behavior of the ' +- 'most\n' +- 'important built-in types.\n' +- '\n' +- '* Numbers of built-in numeric types (Numeric Types — int, ' +- 'float,\n' +- ' complex) and of the standard library types ' +- '"fractions.Fraction" and\n' +- ' "decimal.Decimal" can be compared within and across their ' +- 'types,\n' +- ' with the restriction that complex numbers do not support ' +- 'order\n' +- ' comparison. Within the limits of the types involved, they ' +- 'compare\n' +- ' mathematically (algorithmically) correct without loss of ' +- 'precision.\n' +- '\n' +- ' The not-a-number values "float(\'NaN\')" and ' +- '"decimal.Decimal(\'NaN\')"\n' +- ' are special. Any ordered comparison of a number to a ' +- 'not-a-number\n' +- ' value is false. A counter-intuitive implication is that ' +- 'not-a-number\n' +- ' values are not equal to themselves. For example, if "x =\n' +- ' float(\'NaN\')", "3 < x", "x < 3" and "x == x" are all ' +- 'false, while "x\n' +- ' != x" is true. This behavior is compliant with IEEE 754.\n' +- '\n' +- '* "None" and "NotImplemented" are singletons. **PEP 8** ' +- 'advises that\n' +- ' comparisons for singletons should always be done with "is" ' +- 'or "is\n' +- ' not", never the equality operators.\n' +- '\n' +- '* Binary sequences (instances of "bytes" or "bytearray") can ' +- 'be\n' +- ' compared within and across their types. They compare\n' +- ' lexicographically using the numeric values of their ' +- 'elements.\n' +- '\n' +- '* Strings (instances of "str") compare lexicographically ' +- 'using the\n' +- ' numerical Unicode code points (the result of the built-in ' +- 'function\n' +- ' "ord()") of their characters. [3]\n' +- '\n' +- ' Strings and binary sequences cannot be directly compared.\n' +- '\n' +- '* Sequences (instances of "tuple", "list", or "range") can be ' +- 'compared\n' +- ' only within each of their types, with the restriction that ' +- 'ranges do\n' +- ' not support order comparison. Equality comparison across ' +- 'these\n' +- ' types results in inequality, and ordering comparison across ' +- 'these\n' +- ' types raises "TypeError".\n' +- '\n' +- ' Sequences compare lexicographically using comparison of\n' +- ' corresponding elements. The built-in containers typically ' +- 'assume\n' +- ' identical objects are equal to themselves. That lets them ' +- 'bypass\n' +- ' equality tests for identical objects to improve performance ' +- 'and to\n' +- ' maintain their internal invariants.\n' +- '\n' +- ' Lexicographical comparison between built-in collections ' +- 'works as\n' +- ' follows:\n' +- '\n' +- ' * For two collections to compare equal, they must be of the ' +- 'same\n' +- ' type, have the same length, and each pair of ' +- 'corresponding\n' +- ' elements must compare equal (for example, "[1,2] == ' +- '(1,2)" is\n' +- ' false because the type is not the same).\n' +- '\n' +- ' * Collections that support order comparison are ordered the ' +- 'same as\n' +- ' their first unequal elements (for example, "[1,2,x] <= ' +- '[1,2,y]"\n' +- ' has the same value as "x <= y"). If a corresponding ' +- 'element does\n' +- ' not exist, the shorter collection is ordered first (for ' +- 'example,\n' +- ' "[1,2] < [1,2,3]" is true).\n' +- '\n' +- '* Mappings (instances of "dict") compare equal if and only if ' +- 'they\n' +- ' have equal "(key, value)" pairs. Equality comparison of the ' +- 'keys and\n' +- ' values enforces reflexivity.\n' +- '\n' +- ' Order comparisons ("<", ">", "<=", and ">=") raise ' +- '"TypeError".\n' +- '\n' +- '* Sets (instances of "set" or "frozenset") can be compared ' +- 'within and\n' +- ' across their types.\n' +- '\n' +- ' They define order comparison operators to mean subset and ' +- 'superset\n' +- ' tests. Those relations do not define total orderings (for ' +- 'example,\n' +- ' the two sets "{1,2}" and "{2,3}" are not equal, nor subsets ' +- 'of one\n' +- ' another, nor supersets of one another). Accordingly, sets ' +- 'are not\n' +- ' appropriate arguments for functions which depend on total ' +- 'ordering\n' +- ' (for example, "min()", "max()", and "sorted()" produce ' +- 'undefined\n' +- ' results given a list of sets as inputs).\n' +- '\n' +- ' Comparison of sets enforces reflexivity of its elements.\n' +- '\n' +- '* Most other built-in types have no comparison methods ' +- 'implemented, so\n' +- ' they inherit the default comparison behavior.\n' +- '\n' +- 'User-defined classes that customize their comparison behavior ' +- 'should\n' +- 'follow some consistency rules, if possible:\n' +- '\n' +- '* Equality comparison should be reflexive. In other words, ' +- 'identical\n' +- ' objects should compare equal:\n' +- '\n' +- ' "x is y" implies "x == y"\n' +- '\n' +- '* Comparison should be symmetric. In other words, the ' +- 'following\n' +- ' expressions should have the same result:\n' +- '\n' +- ' "x == y" and "y == x"\n' +- '\n' +- ' "x != y" and "y != x"\n' +- '\n' +- ' "x < y" and "y > x"\n' +- '\n' +- ' "x <= y" and "y >= x"\n' +- '\n' +- '* Comparison should be transitive. The following ' +- '(non-exhaustive)\n' +- ' examples illustrate that:\n' +- '\n' +- ' "x > y and y > z" implies "x > z"\n' +- '\n' +- ' "x < y and y <= z" implies "x < z"\n' +- '\n' +- '* Inverse comparison should result in the boolean negation. ' +- 'In other\n' +- ' words, the following expressions should have the same ' +- 'result:\n' +- '\n' +- ' "x == y" and "not x != y"\n' +- '\n' +- ' "x < y" and "not x >= y" (for total ordering)\n' +- '\n' +- ' "x > y" and "not x <= y" (for total ordering)\n' +- '\n' +- ' The last two expressions apply to totally ordered ' +- 'collections (e.g.\n' +- ' to sequences, but not to sets or mappings). See also the\n' +- ' "total_ordering()" decorator.\n' +- '\n' +- '* The "hash()" result should be consistent with equality. ' +- 'Objects that\n' +- ' are equal should either have the same hash value, or be ' +- 'marked as\n' +- ' unhashable.\n' +- '\n' +- 'Python does not enforce these consistency rules. In fact, ' +- 'the\n' +- 'not-a-number values are an example for not following these ' +- 'rules.\n' +- '\n' +- '\n' +- 'Membership test operations\n' +- '==========================\n' +- '\n' +- 'The operators "in" and "not in" test for membership. "x in ' +- 's"\n' +- 'evaluates to "True" if *x* is a member of *s*, and "False" ' +- 'otherwise.\n' +- '"x not in s" returns the negation of "x in s". All built-in ' +- 'sequences\n' +- 'and set types support this as well as dictionary, for which ' +- '"in" tests\n' +- 'whether the dictionary has a given key. For container types ' +- 'such as\n' +- 'list, tuple, set, frozenset, dict, or collections.deque, the\n' +- 'expression "x in y" is equivalent to "any(x is e or x == e ' +- 'for e in\n' +- 'y)".\n' +- '\n' +- 'For the string and bytes types, "x in y" is "True" if and ' +- 'only if *x*\n' +- 'is a substring of *y*. An equivalent test is "y.find(x) != ' +- '-1".\n' +- 'Empty strings are always considered to be a substring of any ' +- 'other\n' +- 'string, so """ in "abc"" will return "True".\n' +- '\n' +- 'For user-defined classes which define the "__contains__()" ' +- 'method, "x\n' +- 'in y" returns "True" if "y.__contains__(x)" returns a true ' +- 'value, and\n' +- '"False" otherwise.\n' +- '\n' +- 'For user-defined classes which do not define "__contains__()" ' +- 'but do\n' +- 'define "__iter__()", "x in y" is "True" if some value "z", ' +- 'for which\n' +- 'the expression "x is z or x == z" is true, is produced while ' +- 'iterating\n' +- 'over "y". If an exception is raised during the iteration, it ' +- 'is as if\n' +- '"in" raised that exception.\n' +- '\n' +- 'Lastly, the old-style iteration protocol is tried: if a class ' +- 'defines\n' +- '"__getitem__()", "x in y" is "True" if and only if there is a ' +- 'non-\n' +- 'negative integer index *i* such that "x is y[i] or x == ' +- 'y[i]", and no\n' +- 'lower integer index raises the "IndexError" exception. (If ' +- 'any other\n' +- 'exception is raised, it is as if "in" raised that ' +- 'exception).\n' +- '\n' +- 'The operator "not in" is defined to have the inverse truth ' +- 'value of\n' +- '"in".\n' +- '\n' +- '\n' +- 'Identity comparisons\n' +- '====================\n' +- '\n' +- 'The operators "is" and "is not" test for an object’s ' +- 'identity: "x is\n' +- 'y" is true if and only if *x* and *y* are the same object. ' +- 'An\n' +- 'Object’s identity is determined using the "id()" function. ' +- '"x is not\n' +- 'y" yields the inverse truth value. [4]\n', +- 'compound': 'Compound statements\n' +- '*******************\n' +- '\n' +- 'Compound statements contain (groups of) other statements; they ' +- 'affect\n' +- 'or control the execution of those other statements in some way. ' +- 'In\n' +- 'general, compound statements span multiple lines, although in ' +- 'simple\n' +- 'incarnations a whole compound statement may be contained in one ' +- 'line.\n' +- '\n' +- 'The "if", "while" and "for" statements implement traditional ' +- 'control\n' +- 'flow constructs. "try" specifies exception handlers and/or ' +- 'cleanup\n' +- 'code for a group of statements, while the "with" statement ' +- 'allows the\n' +- 'execution of initialization and finalization code around a block ' +- 'of\n' +- 'code. Function and class definitions are also syntactically ' +- 'compound\n' +- 'statements.\n' +- '\n' +- 'A compound statement consists of one or more ‘clauses.’ A ' +- 'clause\n' +- 'consists of a header and a ‘suite.’ The clause headers of a\n' +- 'particular compound statement are all at the same indentation ' +- 'level.\n' +- 'Each clause header begins with a uniquely identifying keyword ' +- 'and ends\n' +- 'with a colon. A suite is a group of statements controlled by a\n' +- 'clause. A suite can be one or more semicolon-separated simple\n' +- 'statements on the same line as the header, following the ' +- 'header’s\n' +- 'colon, or it can be one or more indented statements on ' +- 'subsequent\n' +- 'lines. Only the latter form of a suite can contain nested ' +- 'compound\n' +- 'statements; the following is illegal, mostly because it wouldn’t ' +- 'be\n' +- 'clear to which "if" clause a following "else" clause would ' +- 'belong:\n' +- '\n' +- ' if test1: if test2: print(x)\n' +- '\n' +- 'Also note that the semicolon binds tighter than the colon in ' +- 'this\n' +- 'context, so that in the following example, either all or none of ' +- 'the\n' +- '"print()" calls are executed:\n' +- '\n' +- ' if x < y < z: print(x); print(y); print(z)\n' +- '\n' +- 'Summarizing:\n' +- '\n' +- ' compound_stmt ::= if_stmt\n' +- ' | while_stmt\n' +- ' | for_stmt\n' +- ' | try_stmt\n' +- ' | with_stmt\n' +- ' | match_stmt\n' +- ' | funcdef\n' +- ' | classdef\n' +- ' | async_with_stmt\n' +- ' | async_for_stmt\n' +- ' | async_funcdef\n' +- ' suite ::= stmt_list NEWLINE | NEWLINE INDENT ' +- 'statement+ DEDENT\n' +- ' statement ::= stmt_list NEWLINE | compound_stmt\n' +- ' stmt_list ::= simple_stmt (";" simple_stmt)* [";"]\n' +- '\n' +- 'Note that statements always end in a "NEWLINE" possibly followed ' +- 'by a\n' +- '"DEDENT". Also note that optional continuation clauses always ' +- 'begin\n' +- 'with a keyword that cannot start a statement, thus there are no\n' +- 'ambiguities (the ‘dangling "else"’ problem is solved in Python ' +- 'by\n' +- 'requiring nested "if" statements to be indented).\n' +- '\n' +- 'The formatting of the grammar rules in the following sections ' +- 'places\n' +- 'each clause on a separate line for clarity.\n' +- '\n' +- '\n' +- 'The "if" statement\n' +- '==================\n' +- '\n' +- 'The "if" statement is used for conditional execution:\n' +- '\n' +- ' if_stmt ::= "if" assignment_expression ":" suite\n' +- ' ("elif" assignment_expression ":" suite)*\n' +- ' ["else" ":" suite]\n' +- '\n' +- 'It selects exactly one of the suites by evaluating the ' +- 'expressions one\n' +- 'by one until one is found to be true (see section Boolean ' +- 'operations\n' +- 'for the definition of true and false); then that suite is ' +- 'executed\n' +- '(and no other part of the "if" statement is executed or ' +- 'evaluated).\n' +- 'If all expressions are false, the suite of the "else" clause, ' +- 'if\n' +- 'present, is executed.\n' +- '\n' +- '\n' +- 'The "while" statement\n' +- '=====================\n' +- '\n' +- 'The "while" statement is used for repeated execution as long as ' +- 'an\n' +- 'expression is true:\n' +- '\n' +- ' while_stmt ::= "while" assignment_expression ":" suite\n' +- ' ["else" ":" suite]\n' +- '\n' +- 'This repeatedly tests the expression and, if it is true, ' +- 'executes the\n' +- 'first suite; if the expression is false (which may be the first ' +- 'time\n' +- 'it is tested) the suite of the "else" clause, if present, is ' +- 'executed\n' +- 'and the loop terminates.\n' +- '\n' +- 'A "break" statement executed in the first suite terminates the ' +- 'loop\n' +- 'without executing the "else" clause’s suite. A "continue" ' +- 'statement\n' +- 'executed in the first suite skips the rest of the suite and goes ' +- 'back\n' +- 'to testing the expression.\n' +- '\n' +- '\n' +- 'The "for" statement\n' +- '===================\n' +- '\n' +- 'The "for" statement is used to iterate over the elements of a ' +- 'sequence\n' +- '(such as a string, tuple or list) or other iterable object:\n' +- '\n' +- ' for_stmt ::= "for" target_list "in" starred_list ":" suite\n' +- ' ["else" ":" suite]\n' +- '\n' +- 'The "starred_list" expression is evaluated once; it should yield ' +- 'an\n' +- '*iterable* object. An *iterator* is created for that iterable. ' +- 'The\n' +- 'first item provided by the iterator is then assigned to the ' +- 'target\n' +- 'list using the standard rules for assignments (see Assignment\n' +- 'statements), and the suite is executed. This repeats for each ' +- 'item\n' +- 'provided by the iterator. When the iterator is exhausted, the ' +- 'suite\n' +- 'in the "else" clause, if present, is executed, and the loop\n' +- 'terminates.\n' +- '\n' +- 'A "break" statement executed in the first suite terminates the ' +- 'loop\n' +- 'without executing the "else" clause’s suite. A "continue" ' +- 'statement\n' +- 'executed in the first suite skips the rest of the suite and ' +- 'continues\n' +- 'with the next item, or with the "else" clause if there is no ' +- 'next\n' +- 'item.\n' +- '\n' +- 'The for-loop makes assignments to the variables in the target ' +- 'list.\n' +- 'This overwrites all previous assignments to those variables ' +- 'including\n' +- 'those made in the suite of the for-loop:\n' +- '\n' +- ' for i in range(10):\n' +- ' print(i)\n' +- ' i = 5 # this will not affect the for-loop\n' +- ' # because i will be overwritten with ' +- 'the next\n' +- ' # index in the range\n' +- '\n' +- 'Names in the target list are not deleted when the loop is ' +- 'finished,\n' +- 'but if the sequence is empty, they will not have been assigned ' +- 'to at\n' +- 'all by the loop. Hint: the built-in type "range()" represents\n' +- 'immutable arithmetic sequences of integers. For instance, ' +- 'iterating\n' +- '"range(3)" successively yields 0, 1, and then 2.\n' +- '\n' +- 'Changed in version 3.11: Starred elements are now allowed in ' +- 'the\n' +- 'expression list.\n' +- '\n' +- '\n' +- 'The "try" statement\n' +- '===================\n' +- '\n' +- 'The "try" statement specifies exception handlers and/or cleanup ' +- 'code\n' +- 'for a group of statements:\n' +- '\n' +- ' try_stmt ::= try1_stmt | try2_stmt | try3_stmt\n' +- ' try1_stmt ::= "try" ":" suite\n' +- ' ("except" [expression ["as" identifier]] ":" ' +- 'suite)+\n' +- ' ["else" ":" suite]\n' +- ' ["finally" ":" suite]\n' +- ' try2_stmt ::= "try" ":" suite\n' +- ' ("except" "*" expression ["as" identifier] ":" ' +- 'suite)+\n' +- ' ["else" ":" suite]\n' +- ' ["finally" ":" suite]\n' +- ' try3_stmt ::= "try" ":" suite\n' +- ' "finally" ":" suite\n' +- '\n' +- 'Additional information on exceptions can be found in section\n' +- 'Exceptions, and information on using the "raise" statement to ' +- 'generate\n' +- 'exceptions may be found in section The raise statement.\n' +- '\n' +- '\n' +- '"except" clause\n' +- '---------------\n' +- '\n' +- 'The "except" clause(s) specify one or more exception handlers. ' +- 'When no\n' +- 'exception occurs in the "try" clause, no exception handler is\n' +- 'executed. When an exception occurs in the "try" suite, a search ' +- 'for an\n' +- 'exception handler is started. This search inspects the "except"\n' +- 'clauses in turn until one is found that matches the exception. ' +- 'An\n' +- 'expression-less "except" clause, if present, must be last; it ' +- 'matches\n' +- 'any exception.\n' +- '\n' +- 'For an "except" clause with an expression, the expression must\n' +- 'evaluate to an exception type or a tuple of exception types. ' +- 'The\n' +- 'raised exception matches an "except" clause whose expression ' +- 'evaluates\n' +- 'to the class or a *non-virtual base class* of the exception ' +- 'object, or\n' +- 'to a tuple that contains such a class.\n' +- '\n' +- 'If no "except" clause matches the exception, the search for an\n' +- 'exception handler continues in the surrounding code and on the\n' +- 'invocation stack. [1]\n' +- '\n' +- 'If the evaluation of an expression in the header of an "except" ' +- 'clause\n' +- 'raises an exception, the original search for a handler is ' +- 'canceled and\n' +- 'a search starts for the new exception in the surrounding code ' +- 'and on\n' +- 'the call stack (it is treated as if the entire "try" statement ' +- 'raised\n' +- 'the exception).\n' +- '\n' +- 'When a matching "except" clause is found, the exception is ' +- 'assigned to\n' +- 'the target specified after the "as" keyword in that "except" ' +- 'clause,\n' +- 'if present, and the "except" clause’s suite is executed. All ' +- '"except"\n' +- 'clauses must have an executable block. When the end of this ' +- 'block is\n' +- 'reached, execution continues normally after the entire "try"\n' +- 'statement. (This means that if two nested handlers exist for the ' +- 'same\n' +- 'exception, and the exception occurs in the "try" clause of the ' +- 'inner\n' +- 'handler, the outer handler will not handle the exception.)\n' +- '\n' +- 'When an exception has been assigned using "as target", it is ' +- 'cleared\n' +- 'at the end of the "except" clause. This is as if\n' +- '\n' +- ' except E as N:\n' +- ' foo\n' +- '\n' +- 'was translated to\n' +- '\n' +- ' except E as N:\n' +- ' try:\n' +- ' foo\n' +- ' finally:\n' +- ' del N\n' +- '\n' +- 'This means the exception must be assigned to a different name to ' +- 'be\n' +- 'able to refer to it after the "except" clause. Exceptions are ' +- 'cleared\n' +- 'because with the traceback attached to them, they form a ' +- 'reference\n' +- 'cycle with the stack frame, keeping all locals in that frame ' +- 'alive\n' +- 'until the next garbage collection occurs.\n' +- '\n' +- 'Before an "except" clause’s suite is executed, the exception is ' +- 'stored\n' +- 'in the "sys" module, where it can be accessed from within the ' +- 'body of\n' +- 'the "except" clause by calling "sys.exception()". When leaving ' +- 'an\n' +- 'exception handler, the exception stored in the "sys" module is ' +- 'reset\n' +- 'to its previous value:\n' +- '\n' +- ' >>> print(sys.exception())\n' +- ' None\n' +- ' >>> try:\n' +- ' ... raise TypeError\n' +- ' ... except:\n' +- ' ... print(repr(sys.exception()))\n' +- ' ... try:\n' +- ' ... raise ValueError\n' +- ' ... except:\n' +- ' ... print(repr(sys.exception()))\n' +- ' ... print(repr(sys.exception()))\n' +- ' ...\n' +- ' TypeError()\n' +- ' ValueError()\n' +- ' TypeError()\n' +- ' >>> print(sys.exception())\n' +- ' None\n' +- '\n' +- '\n' +- '"except*" clause\n' +- '----------------\n' +- '\n' +- 'The "except*" clause(s) are used for handling "ExceptionGroup"s. ' +- 'The\n' +- 'exception type for matching is interpreted as in the case of ' +- '"except",\n' +- 'but in the case of exception groups we can have partial matches ' +- 'when\n' +- 'the type matches some of the exceptions in the group. This means ' +- 'that\n' +- 'multiple "except*" clauses can execute, each handling part of ' +- 'the\n' +- 'exception group. Each clause executes at most once and handles ' +- 'an\n' +- 'exception group of all matching exceptions. Each exception in ' +- 'the\n' +- 'group is handled by at most one "except*" clause, the first ' +- 'that\n' +- 'matches it.\n' +- '\n' +- ' >>> try:\n' +- ' ... raise ExceptionGroup("eg",\n' +- ' ... [ValueError(1), TypeError(2), OSError(3), ' +- 'OSError(4)])\n' +- ' ... except* TypeError as e:\n' +- " ... print(f'caught {type(e)} with nested " +- "{e.exceptions}')\n" +- ' ... except* OSError as e:\n' +- " ... print(f'caught {type(e)} with nested " +- "{e.exceptions}')\n" +- ' ...\n' +- " caught with nested (TypeError(2),)\n" +- " caught with nested (OSError(3), " +- 'OSError(4))\n' +- ' + Exception Group Traceback (most recent call last):\n' +- ' | File "", line 2, in \n' +- ' | ExceptionGroup: eg\n' +- ' +-+---------------- 1 ----------------\n' +- ' | ValueError: 1\n' +- ' +------------------------------------\n' +- '\n' +- 'Any remaining exceptions that were not handled by any "except*" ' +- 'clause\n' +- 'are re-raised at the end, along with all exceptions that were ' +- 'raised\n' +- 'from within the "except*" clauses. If this list contains more ' +- 'than one\n' +- 'exception to reraise, they are combined into an exception ' +- 'group.\n' +- '\n' +- 'If the raised exception is not an exception group and its type ' +- 'matches\n' +- 'one of the "except*" clauses, it is caught and wrapped by an ' +- 'exception\n' +- 'group with an empty message string.\n' +- '\n' +- ' >>> try:\n' +- ' ... raise BlockingIOError\n' +- ' ... except* BlockingIOError as e:\n' +- ' ... print(repr(e))\n' +- ' ...\n' +- " ExceptionGroup('', (BlockingIOError()))\n" +- '\n' +- 'An "except*" clause must have a matching expression; it cannot ' +- 'be\n' +- '"except*:". Furthermore, this expression cannot contain ' +- 'exception\n' +- 'group types, because that would have ambiguous semantics.\n' +- '\n' +- 'It is not possible to mix "except" and "except*" in the same ' +- '"try".\n' +- '"break", "continue" and "return" cannot appear in an "except*" ' +- 'clause.\n' +- '\n' +- '\n' +- '"else" clause\n' +- '-------------\n' +- '\n' +- 'The optional "else" clause is executed if the control flow ' +- 'leaves the\n' +- '"try" suite, no exception was raised, and no "return", ' +- '"continue", or\n' +- '"break" statement was executed. Exceptions in the "else" clause ' +- 'are\n' +- 'not handled by the preceding "except" clauses.\n' +- '\n' +- '\n' +- '"finally" clause\n' +- '----------------\n' +- '\n' +- 'If "finally" is present, it specifies a ‘cleanup’ handler. The ' +- '"try"\n' +- 'clause is executed, including any "except" and "else" clauses. ' +- 'If an\n' +- 'exception occurs in any of the clauses and is not handled, the\n' +- 'exception is temporarily saved. The "finally" clause is ' +- 'executed. If\n' +- 'there is a saved exception it is re-raised at the end of the ' +- '"finally"\n' +- 'clause. If the "finally" clause raises another exception, the ' +- 'saved\n' +- 'exception is set as the context of the new exception. If the ' +- '"finally"\n' +- 'clause executes a "return", "break" or "continue" statement, the ' +- 'saved\n' +- 'exception is discarded:\n' +- '\n' +- ' >>> def f():\n' +- ' ... try:\n' +- ' ... 1/0\n' +- ' ... finally:\n' +- ' ... return 42\n' +- ' ...\n' +- ' >>> f()\n' +- ' 42\n' +- '\n' +- 'The exception information is not available to the program ' +- 'during\n' +- 'execution of the "finally" clause.\n' +- '\n' +- 'When a "return", "break" or "continue" statement is executed in ' +- 'the\n' +- '"try" suite of a "try"…"finally" statement, the "finally" clause ' +- 'is\n' +- 'also executed ‘on the way out.’\n' +- '\n' +- 'The return value of a function is determined by the last ' +- '"return"\n' +- 'statement executed. Since the "finally" clause always executes, ' +- 'a\n' +- '"return" statement executed in the "finally" clause will always ' +- 'be the\n' +- 'last one executed:\n' +- '\n' +- ' >>> def foo():\n' +- ' ... try:\n' +- " ... return 'try'\n" +- ' ... finally:\n' +- " ... return 'finally'\n" +- ' ...\n' +- ' >>> foo()\n' +- " 'finally'\n" +- '\n' +- 'Changed in version 3.8: Prior to Python 3.8, a "continue" ' +- 'statement\n' +- 'was illegal in the "finally" clause due to a problem with the\n' +- 'implementation.\n' +- '\n' +- '\n' +- 'The "with" statement\n' +- '====================\n' +- '\n' +- 'The "with" statement is used to wrap the execution of a block ' +- 'with\n' +- 'methods defined by a context manager (see section With ' +- 'Statement\n' +- 'Context Managers). This allows common "try"…"except"…"finally" ' +- 'usage\n' +- 'patterns to be encapsulated for convenient reuse.\n' +- '\n' +- ' with_stmt ::= "with" ( "(" with_stmt_contents ","? ' +- '")" | with_stmt_contents ) ":" suite\n' +- ' with_stmt_contents ::= with_item ("," with_item)*\n' +- ' with_item ::= expression ["as" target]\n' +- '\n' +- 'The execution of the "with" statement with one “item†proceeds ' +- 'as\n' +- 'follows:\n' +- '\n' +- '1. The context expression (the expression given in the ' +- '"with_item") is\n' +- ' evaluated to obtain a context manager.\n' +- '\n' +- '2. The context manager’s "__enter__()" is loaded for later use.\n' +- '\n' +- '3. The context manager’s "__exit__()" is loaded for later use.\n' +- '\n' +- '4. The context manager’s "__enter__()" method is invoked.\n' +- '\n' +- '5. If a target was included in the "with" statement, the return ' +- 'value\n' +- ' from "__enter__()" is assigned to it.\n' +- '\n' +- ' Note:\n' +- '\n' +- ' The "with" statement guarantees that if the "__enter__()" ' +- 'method\n' +- ' returns without an error, then "__exit__()" will always be\n' +- ' called. Thus, if an error occurs during the assignment to ' +- 'the\n' +- ' target list, it will be treated the same as an error ' +- 'occurring\n' +- ' within the suite would be. See step 7 below.\n' +- '\n' +- '6. The suite is executed.\n' +- '\n' +- '7. The context manager’s "__exit__()" method is invoked. If an\n' +- ' exception caused the suite to be exited, its type, value, ' +- 'and\n' +- ' traceback are passed as arguments to "__exit__()". Otherwise, ' +- 'three\n' +- ' "None" arguments are supplied.\n' +- '\n' +- ' If the suite was exited due to an exception, and the return ' +- 'value\n' +- ' from the "__exit__()" method was false, the exception is ' +- 'reraised.\n' +- ' If the return value was true, the exception is suppressed, ' +- 'and\n' +- ' execution continues with the statement following the "with"\n' +- ' statement.\n' +- '\n' +- ' If the suite was exited for any reason other than an ' +- 'exception, the\n' +- ' return value from "__exit__()" is ignored, and execution ' +- 'proceeds\n' +- ' at the normal location for the kind of exit that was taken.\n' +- '\n' +- 'The following code:\n' +- '\n' +- ' with EXPRESSION as TARGET:\n' +- ' SUITE\n' +- '\n' +- 'is semantically equivalent to:\n' +- '\n' +- ' manager = (EXPRESSION)\n' +- ' enter = type(manager).__enter__\n' +- ' exit = type(manager).__exit__\n' +- ' value = enter(manager)\n' +- '\n' +- ' try:\n' +- ' TARGET = value\n' +- ' SUITE\n' +- ' except:\n' +- ' if not exit(manager, *sys.exc_info()):\n' +- ' raise\n' +- ' else:\n' +- ' exit(manager, None, None, None)\n' +- '\n' +- 'With more than one item, the context managers are processed as ' +- 'if\n' +- 'multiple "with" statements were nested:\n' +- '\n' +- ' with A() as a, B() as b:\n' +- ' SUITE\n' +- '\n' +- 'is semantically equivalent to:\n' +- '\n' +- ' with A() as a:\n' +- ' with B() as b:\n' +- ' SUITE\n' +- '\n' +- 'You can also write multi-item context managers in multiple lines ' +- 'if\n' +- 'the items are surrounded by parentheses. For example:\n' +- '\n' +- ' with (\n' +- ' A() as a,\n' +- ' B() as b,\n' +- ' ):\n' +- ' SUITE\n' +- '\n' +- 'Changed in version 3.1: Support for multiple context ' +- 'expressions.\n' +- '\n' +- 'Changed in version 3.10: Support for using grouping parentheses ' +- 'to\n' +- 'break the statement in multiple lines.\n' +- '\n' +- 'See also:\n' +- '\n' +- ' **PEP 343** - The “with†statement\n' +- ' The specification, background, and examples for the Python ' +- '"with"\n' +- ' statement.\n' +- '\n' +- '\n' +- 'The "match" statement\n' +- '=====================\n' +- '\n' +- 'Added in version 3.10.\n' +- '\n' +- 'The match statement is used for pattern matching. Syntax:\n' +- '\n' +- ' match_stmt ::= \'match\' subject_expr ":" NEWLINE INDENT ' +- 'case_block+ DEDENT\n' +- ' subject_expr ::= star_named_expression "," ' +- 'star_named_expressions?\n' +- ' | named_expression\n' +- ' case_block ::= \'case\' patterns [guard] ":" block\n' +- '\n' +- 'Note:\n' +- '\n' +- ' This section uses single quotes to denote soft keywords.\n' +- '\n' +- 'Pattern matching takes a pattern as input (following "case") and ' +- 'a\n' +- 'subject value (following "match"). The pattern (which may ' +- 'contain\n' +- 'subpatterns) is matched against the subject value. The outcomes ' +- 'are:\n' +- '\n' +- '* A match success or failure (also termed a pattern success or\n' +- ' failure).\n' +- '\n' +- '* Possible binding of matched values to a name. The ' +- 'prerequisites for\n' +- ' this are further discussed below.\n' +- '\n' +- 'The "match" and "case" keywords are soft keywords.\n' +- '\n' +- 'See also:\n' +- '\n' +- ' * **PEP 634** – Structural Pattern Matching: Specification\n' +- '\n' +- ' * **PEP 636** – Structural Pattern Matching: Tutorial\n' +- '\n' +- '\n' +- 'Overview\n' +- '--------\n' +- '\n' +- 'Here’s an overview of the logical flow of a match statement:\n' +- '\n' +- '1. The subject expression "subject_expr" is evaluated and a ' +- 'resulting\n' +- ' subject value obtained. If the subject expression contains a ' +- 'comma,\n' +- ' a tuple is constructed using the standard rules.\n' +- '\n' +- '2. Each pattern in a "case_block" is attempted to match with ' +- 'the\n' +- ' subject value. The specific rules for success or failure are\n' +- ' described below. The match attempt can also bind some or all ' +- 'of the\n' +- ' standalone names within the pattern. The precise pattern ' +- 'binding\n' +- ' rules vary per pattern type and are specified below. **Name\n' +- ' bindings made during a successful pattern match outlive the\n' +- ' executed block and can be used after the match statement**.\n' +- '\n' +- ' Note:\n' +- '\n' +- ' During failed pattern matches, some subpatterns may ' +- 'succeed. Do\n' +- ' not rely on bindings being made for a failed match. ' +- 'Conversely,\n' +- ' do not rely on variables remaining unchanged after a ' +- 'failed\n' +- ' match. The exact behavior is dependent on implementation ' +- 'and may\n' +- ' vary. This is an intentional decision made to allow ' +- 'different\n' +- ' implementations to add optimizations.\n' +- '\n' +- '3. If the pattern succeeds, the corresponding guard (if present) ' +- 'is\n' +- ' evaluated. In this case all name bindings are guaranteed to ' +- 'have\n' +- ' happened.\n' +- '\n' +- ' * If the guard evaluates as true or is missing, the "block" ' +- 'inside\n' +- ' "case_block" is executed.\n' +- '\n' +- ' * Otherwise, the next "case_block" is attempted as described ' +- 'above.\n' +- '\n' +- ' * If there are no further case blocks, the match statement ' +- 'is\n' +- ' completed.\n' +- '\n' +- 'Note:\n' +- '\n' +- ' Users should generally never rely on a pattern being ' +- 'evaluated.\n' +- ' Depending on implementation, the interpreter may cache values ' +- 'or use\n' +- ' other optimizations which skip repeated evaluations.\n' +- '\n' +- 'A sample match statement:\n' +- '\n' +- ' >>> flag = False\n' +- ' >>> match (100, 200):\n' +- ' ... case (100, 300): # Mismatch: 200 != 300\n' +- " ... print('Case 1')\n" +- ' ... case (100, 200) if flag: # Successful match, but ' +- 'guard fails\n' +- " ... print('Case 2')\n" +- ' ... case (100, y): # Matches and binds y to 200\n' +- " ... print(f'Case 3, y: {y}')\n" +- ' ... case _: # Pattern not attempted\n' +- " ... print('Case 4, I match anything!')\n" +- ' ...\n' +- ' Case 3, y: 200\n' +- '\n' +- 'In this case, "if flag" is a guard. Read more about that in the ' +- 'next\n' +- 'section.\n' +- '\n' +- '\n' +- 'Guards\n' +- '------\n' +- '\n' +- ' guard ::= "if" named_expression\n' +- '\n' +- 'A "guard" (which is part of the "case") must succeed for code ' +- 'inside\n' +- 'the "case" block to execute. It takes the form: "if" followed ' +- 'by an\n' +- 'expression.\n' +- '\n' +- 'The logical flow of a "case" block with a "guard" follows:\n' +- '\n' +- '1. Check that the pattern in the "case" block succeeded. If ' +- 'the\n' +- ' pattern failed, the "guard" is not evaluated and the next ' +- '"case"\n' +- ' block is checked.\n' +- '\n' +- '2. If the pattern succeeded, evaluate the "guard".\n' +- '\n' +- ' * If the "guard" condition evaluates as true, the case block ' +- 'is\n' +- ' selected.\n' +- '\n' +- ' * If the "guard" condition evaluates as false, the case block ' +- 'is\n' +- ' not selected.\n' +- '\n' +- ' * If the "guard" raises an exception during evaluation, the\n' +- ' exception bubbles up.\n' +- '\n' +- 'Guards are allowed to have side effects as they are ' +- 'expressions.\n' +- 'Guard evaluation must proceed from the first to the last case ' +- 'block,\n' +- 'one at a time, skipping case blocks whose pattern(s) don’t all\n' +- 'succeed. (I.e., guard evaluation must happen in order.) Guard\n' +- 'evaluation must stop once a case block is selected.\n' +- '\n' +- '\n' +- 'Irrefutable Case Blocks\n' +- '-----------------------\n' +- '\n' +- 'An irrefutable case block is a match-all case block. A match\n' +- 'statement may have at most one irrefutable case block, and it ' +- 'must be\n' +- 'last.\n' +- '\n' +- 'A case block is considered irrefutable if it has no guard and ' +- 'its\n' +- 'pattern is irrefutable. A pattern is considered irrefutable if ' +- 'we can\n' +- 'prove from its syntax alone that it will always succeed. Only ' +- 'the\n' +- 'following patterns are irrefutable:\n' +- '\n' +- '* AS Patterns whose left-hand side is irrefutable\n' +- '\n' +- '* OR Patterns containing at least one irrefutable pattern\n' +- '\n' +- '* Capture Patterns\n' +- '\n' +- '* Wildcard Patterns\n' +- '\n' +- '* parenthesized irrefutable patterns\n' +- '\n' +- '\n' +- 'Patterns\n' +- '--------\n' +- '\n' +- 'Note:\n' +- '\n' +- ' This section uses grammar notations beyond standard EBNF:\n' +- '\n' +- ' * the notation "SEP.RULE+" is shorthand for "RULE (SEP ' +- 'RULE)*"\n' +- '\n' +- ' * the notation "!RULE" is shorthand for a negative lookahead\n' +- ' assertion\n' +- '\n' +- 'The top-level syntax for "patterns" is:\n' +- '\n' +- ' patterns ::= open_sequence_pattern | pattern\n' +- ' pattern ::= as_pattern | or_pattern\n' +- ' closed_pattern ::= | literal_pattern\n' +- ' | capture_pattern\n' +- ' | wildcard_pattern\n' +- ' | value_pattern\n' +- ' | group_pattern\n' +- ' | sequence_pattern\n' +- ' | mapping_pattern\n' +- ' | class_pattern\n' +- '\n' +- 'The descriptions below will include a description “in simple ' +- 'terms†of\n' +- 'what a pattern does for illustration purposes (credits to ' +- 'Raymond\n' +- 'Hettinger for a document that inspired most of the ' +- 'descriptions). Note\n' +- 'that these descriptions are purely for illustration purposes and ' +- '**may\n' +- 'not** reflect the underlying implementation. Furthermore, they ' +- 'do not\n' +- 'cover all valid forms.\n' +- '\n' +- '\n' +- 'OR Patterns\n' +- '~~~~~~~~~~~\n' +- '\n' +- 'An OR pattern is two or more patterns separated by vertical bars ' +- '"|".\n' +- 'Syntax:\n' +- '\n' +- ' or_pattern ::= "|".closed_pattern+\n' +- '\n' +- 'Only the final subpattern may be irrefutable, and each ' +- 'subpattern must\n' +- 'bind the same set of names to avoid ambiguity.\n' +- '\n' +- 'An OR pattern matches each of its subpatterns in turn to the ' +- 'subject\n' +- 'value, until one succeeds. The OR pattern is then considered\n' +- 'successful. Otherwise, if none of the subpatterns succeed, the ' +- 'OR\n' +- 'pattern fails.\n' +- '\n' +- 'In simple terms, "P1 | P2 | ..." will try to match "P1", if it ' +- 'fails\n' +- 'it will try to match "P2", succeeding immediately if any ' +- 'succeeds,\n' +- 'failing otherwise.\n' +- '\n' +- '\n' +- 'AS Patterns\n' +- '~~~~~~~~~~~\n' +- '\n' +- 'An AS pattern matches an OR pattern on the left of the "as" ' +- 'keyword\n' +- 'against a subject. Syntax:\n' +- '\n' +- ' as_pattern ::= or_pattern "as" capture_pattern\n' +- '\n' +- 'If the OR pattern fails, the AS pattern fails. Otherwise, the ' +- 'AS\n' +- 'pattern binds the subject to the name on the right of the as ' +- 'keyword\n' +- 'and succeeds. "capture_pattern" cannot be a "_".\n' +- '\n' +- 'In simple terms "P as NAME" will match with "P", and on success ' +- 'it\n' +- 'will set "NAME = ".\n' +- '\n' +- '\n' +- 'Literal Patterns\n' +- '~~~~~~~~~~~~~~~~\n' +- '\n' +- 'A literal pattern corresponds to most literals in Python. ' +- 'Syntax:\n' +- '\n' +- ' literal_pattern ::= signed_number\n' +- ' | signed_number "+" NUMBER\n' +- ' | signed_number "-" NUMBER\n' +- ' | strings\n' +- ' | "None"\n' +- ' | "True"\n' +- ' | "False"\n' +- ' signed_number ::= ["-"] NUMBER\n' +- '\n' +- 'The rule "strings" and the token "NUMBER" are defined in the ' +- 'standard\n' +- 'Python grammar. Triple-quoted strings are supported. Raw ' +- 'strings and\n' +- 'byte strings are supported. f-strings are not supported.\n' +- '\n' +- 'The forms "signed_number \'+\' NUMBER" and "signed_number \'-\' ' +- 'NUMBER"\n' +- 'are for expressing complex numbers; they require a real number ' +- 'on the\n' +- 'left and an imaginary number on the right. E.g. "3 + 4j".\n' +- '\n' +- 'In simple terms, "LITERAL" will succeed only if " ==\n' +- 'LITERAL". For the singletons "None", "True" and "False", the ' +- '"is"\n' +- 'operator is used.\n' +- '\n' +- '\n' +- 'Capture Patterns\n' +- '~~~~~~~~~~~~~~~~\n' +- '\n' +- 'A capture pattern binds the subject value to a name. Syntax:\n' +- '\n' +- " capture_pattern ::= !'_' NAME\n" +- '\n' +- 'A single underscore "_" is not a capture pattern (this is what ' +- '"!\'_\'"\n' +- 'expresses). It is instead treated as a "wildcard_pattern".\n' +- '\n' +- 'In a given pattern, a given name can only be bound once. E.g. ' +- '"case\n' +- 'x, x: ..." is invalid while "case [x] | x: ..." is allowed.\n' +- '\n' +- 'Capture patterns always succeed. The binding follows scoping ' +- 'rules\n' +- 'established by the assignment expression operator in **PEP ' +- '572**; the\n' +- 'name becomes a local variable in the closest containing function ' +- 'scope\n' +- 'unless there’s an applicable "global" or "nonlocal" statement.\n' +- '\n' +- 'In simple terms "NAME" will always succeed and it will set "NAME ' +- '=\n' +- '".\n' +- '\n' +- '\n' +- 'Wildcard Patterns\n' +- '~~~~~~~~~~~~~~~~~\n' +- '\n' +- 'A wildcard pattern always succeeds (matches anything) and binds ' +- 'no\n' +- 'name. Syntax:\n' +- '\n' +- " wildcard_pattern ::= '_'\n" +- '\n' +- '"_" is a soft keyword within any pattern, but only within ' +- 'patterns.\n' +- 'It is an identifier, as usual, even within "match" subject\n' +- 'expressions, "guard"s, and "case" blocks.\n' +- '\n' +- 'In simple terms, "_" will always succeed.\n' +- '\n' +- '\n' +- 'Value Patterns\n' +- '~~~~~~~~~~~~~~\n' +- '\n' +- 'A value pattern represents a named value in Python. Syntax:\n' +- '\n' +- ' value_pattern ::= attr\n' +- ' attr ::= name_or_attr "." NAME\n' +- ' name_or_attr ::= attr | NAME\n' +- '\n' +- 'The dotted name in the pattern is looked up using standard ' +- 'Python name\n' +- 'resolution rules. The pattern succeeds if the value found ' +- 'compares\n' +- 'equal to the subject value (using the "==" equality operator).\n' +- '\n' +- 'In simple terms "NAME1.NAME2" will succeed only if " ' +- '==\n' +- 'NAME1.NAME2"\n' +- '\n' +- 'Note:\n' +- '\n' +- ' If the same value occurs multiple times in the same match ' +- 'statement,\n' +- ' the interpreter may cache the first value found and reuse it ' +- 'rather\n' +- ' than repeat the same lookup. This cache is strictly tied to a ' +- 'given\n' +- ' execution of a given match statement.\n' +- '\n' +- '\n' +- 'Group Patterns\n' +- '~~~~~~~~~~~~~~\n' +- '\n' +- 'A group pattern allows users to add parentheses around patterns ' +- 'to\n' +- 'emphasize the intended grouping. Otherwise, it has no ' +- 'additional\n' +- 'syntax. Syntax:\n' +- '\n' +- ' group_pattern ::= "(" pattern ")"\n' +- '\n' +- 'In simple terms "(P)" has the same effect as "P".\n' +- '\n' +- '\n' +- 'Sequence Patterns\n' +- '~~~~~~~~~~~~~~~~~\n' +- '\n' +- 'A sequence pattern contains several subpatterns to be matched ' +- 'against\n' +- 'sequence elements. The syntax is similar to the unpacking of a ' +- 'list or\n' +- 'tuple.\n' +- '\n' +- ' sequence_pattern ::= "[" [maybe_sequence_pattern] "]"\n' +- ' | "(" [open_sequence_pattern] ")"\n' +- ' open_sequence_pattern ::= maybe_star_pattern "," ' +- '[maybe_sequence_pattern]\n' +- ' maybe_sequence_pattern ::= ",".maybe_star_pattern+ ","?\n' +- ' maybe_star_pattern ::= star_pattern | pattern\n' +- ' star_pattern ::= "*" (capture_pattern | ' +- 'wildcard_pattern)\n' +- '\n' +- 'There is no difference if parentheses or square brackets are ' +- 'used for\n' +- 'sequence patterns (i.e. "(...)" vs "[...]" ).\n' +- '\n' +- 'Note:\n' +- '\n' +- ' A single pattern enclosed in parentheses without a trailing ' +- 'comma\n' +- ' (e.g. "(3 | 4)") is a group pattern. While a single pattern ' +- 'enclosed\n' +- ' in square brackets (e.g. "[3 | 4]") is still a sequence ' +- 'pattern.\n' +- '\n' +- 'At most one star subpattern may be in a sequence pattern. The ' +- 'star\n' +- 'subpattern may occur in any position. If no star subpattern is\n' +- 'present, the sequence pattern is a fixed-length sequence ' +- 'pattern;\n' +- 'otherwise it is a variable-length sequence pattern.\n' +- '\n' +- 'The following is the logical flow for matching a sequence ' +- 'pattern\n' +- 'against a subject value:\n' +- '\n' +- '1. If the subject value is not a sequence [2], the sequence ' +- 'pattern\n' +- ' fails.\n' +- '\n' +- '2. If the subject value is an instance of "str", "bytes" or\n' +- ' "bytearray" the sequence pattern fails.\n' +- '\n' +- '3. The subsequent steps depend on whether the sequence pattern ' +- 'is\n' +- ' fixed or variable-length.\n' +- '\n' +- ' If the sequence pattern is fixed-length:\n' +- '\n' +- ' 1. If the length of the subject sequence is not equal to the ' +- 'number\n' +- ' of subpatterns, the sequence pattern fails\n' +- '\n' +- ' 2. Subpatterns in the sequence pattern are matched to their\n' +- ' corresponding items in the subject sequence from left to ' +- 'right.\n' +- ' Matching stops as soon as a subpattern fails. If all\n' +- ' subpatterns succeed in matching their corresponding item, ' +- 'the\n' +- ' sequence pattern succeeds.\n' +- '\n' +- ' Otherwise, if the sequence pattern is variable-length:\n' +- '\n' +- ' 1. If the length of the subject sequence is less than the ' +- 'number of\n' +- ' non-star subpatterns, the sequence pattern fails.\n' +- '\n' +- ' 2. The leading non-star subpatterns are matched to their\n' +- ' corresponding items as for fixed-length sequences.\n' +- '\n' +- ' 3. If the previous step succeeds, the star subpattern matches ' +- 'a\n' +- ' list formed of the remaining subject items, excluding the\n' +- ' remaining items corresponding to non-star subpatterns ' +- 'following\n' +- ' the star subpattern.\n' +- '\n' +- ' 4. Remaining non-star subpatterns are matched to their\n' +- ' corresponding subject items, as for a fixed-length ' +- 'sequence.\n' +- '\n' +- ' Note:\n' +- '\n' +- ' The length of the subject sequence is obtained via "len()" ' +- '(i.e.\n' +- ' via the "__len__()" protocol). This length may be cached ' +- 'by the\n' +- ' interpreter in a similar manner as value patterns.\n' +- '\n' +- 'In simple terms "[P1, P2, P3," … ", P]" matches only if all ' +- 'the\n' +- 'following happens:\n' +- '\n' +- '* check "" is a sequence\n' +- '\n' +- '* "len(subject) == "\n' +- '\n' +- '* "P1" matches "[0]" (note that this match can also ' +- 'bind\n' +- ' names)\n' +- '\n' +- '* "P2" matches "[1]" (note that this match can also ' +- 'bind\n' +- ' names)\n' +- '\n' +- '* … and so on for the corresponding pattern/element.\n' +- '\n' +- '\n' +- 'Mapping Patterns\n' +- '~~~~~~~~~~~~~~~~\n' +- '\n' +- 'A mapping pattern contains one or more key-value patterns. The ' +- 'syntax\n' +- 'is similar to the construction of a dictionary. Syntax:\n' +- '\n' +- ' mapping_pattern ::= "{" [items_pattern] "}"\n' +- ' items_pattern ::= ",".key_value_pattern+ ","?\n' +- ' key_value_pattern ::= (literal_pattern | value_pattern) ":" ' +- 'pattern\n' +- ' | double_star_pattern\n' +- ' double_star_pattern ::= "**" capture_pattern\n' +- '\n' +- 'At most one double star pattern may be in a mapping pattern. ' +- 'The\n' +- 'double star pattern must be the last subpattern in the mapping\n' +- 'pattern.\n' +- '\n' +- 'Duplicate keys in mapping patterns are disallowed. Duplicate ' +- 'literal\n' +- 'keys will raise a "SyntaxError". Two keys that otherwise have ' +- 'the same\n' +- 'value will raise a "ValueError" at runtime.\n' +- '\n' +- 'The following is the logical flow for matching a mapping ' +- 'pattern\n' +- 'against a subject value:\n' +- '\n' +- '1. If the subject value is not a mapping [3],the mapping ' +- 'pattern\n' +- ' fails.\n' +- '\n' +- '2. If every key given in the mapping pattern is present in the ' +- 'subject\n' +- ' mapping, and the pattern for each key matches the ' +- 'corresponding\n' +- ' item of the subject mapping, the mapping pattern succeeds.\n' +- '\n' +- '3. If duplicate keys are detected in the mapping pattern, the ' +- 'pattern\n' +- ' is considered invalid. A "SyntaxError" is raised for ' +- 'duplicate\n' +- ' literal values; or a "ValueError" for named keys of the same ' +- 'value.\n' +- '\n' +- 'Note:\n' +- '\n' +- ' Key-value pairs are matched using the two-argument form of ' +- 'the\n' +- ' mapping subject’s "get()" method. Matched key-value pairs ' +- 'must\n' +- ' already be present in the mapping, and not created on-the-fly ' +- 'via\n' +- ' "__missing__()" or "__getitem__()".\n' +- '\n' +- 'In simple terms "{KEY1: P1, KEY2: P2, ... }" matches only if all ' +- 'the\n' +- 'following happens:\n' +- '\n' +- '* check "" is a mapping\n' +- '\n' +- '* "KEY1 in "\n' +- '\n' +- '* "P1" matches "[KEY1]"\n' +- '\n' +- '* … and so on for the corresponding KEY/pattern pair.\n' +- '\n' +- '\n' +- 'Class Patterns\n' +- '~~~~~~~~~~~~~~\n' +- '\n' +- 'A class pattern represents a class and its positional and ' +- 'keyword\n' +- 'arguments (if any). Syntax:\n' +- '\n' +- ' class_pattern ::= name_or_attr "(" [pattern_arguments ' +- '","?] ")"\n' +- ' pattern_arguments ::= positional_patterns ["," ' +- 'keyword_patterns]\n' +- ' | keyword_patterns\n' +- ' positional_patterns ::= ",".pattern+\n' +- ' keyword_patterns ::= ",".keyword_pattern+\n' +- ' keyword_pattern ::= NAME "=" pattern\n' +- '\n' +- 'The same keyword should not be repeated in class patterns.\n' +- '\n' +- 'The following is the logical flow for matching a class pattern ' +- 'against\n' +- 'a subject value:\n' +- '\n' +- '1. If "name_or_attr" is not an instance of the builtin "type" , ' +- 'raise\n' +- ' "TypeError".\n' +- '\n' +- '2. If the subject value is not an instance of "name_or_attr" ' +- '(tested\n' +- ' via "isinstance()"), the class pattern fails.\n' +- '\n' +- '3. If no pattern arguments are present, the pattern succeeds.\n' +- ' Otherwise, the subsequent steps depend on whether keyword or\n' +- ' positional argument patterns are present.\n' +- '\n' +- ' For a number of built-in types (specified below), a single\n' +- ' positional subpattern is accepted which will match the ' +- 'entire\n' +- ' subject; for these types keyword patterns also work as for ' +- 'other\n' +- ' types.\n' +- '\n' +- ' If only keyword patterns are present, they are processed as\n' +- ' follows, one by one:\n' +- '\n' +- ' I. The keyword is looked up as an attribute on the subject.\n' +- '\n' +- ' * If this raises an exception other than "AttributeError", ' +- 'the\n' +- ' exception bubbles up.\n' +- '\n' +- ' * If this raises "AttributeError", the class pattern has ' +- 'failed.\n' +- '\n' +- ' * Else, the subpattern associated with the keyword pattern ' +- 'is\n' +- ' matched against the subject’s attribute value. If this ' +- 'fails,\n' +- ' the class pattern fails; if this succeeds, the match ' +- 'proceeds\n' +- ' to the next keyword.\n' +- '\n' +- ' II. If all keyword patterns succeed, the class pattern ' +- 'succeeds.\n' +- '\n' +- ' If any positional patterns are present, they are converted ' +- 'to\n' +- ' keyword patterns using the "__match_args__" attribute on the ' +- 'class\n' +- ' "name_or_attr" before matching:\n' +- '\n' +- ' I. The equivalent of "getattr(cls, "__match_args__", ())" is\n' +- ' called.\n' +- '\n' +- ' * If this raises an exception, the exception bubbles up.\n' +- '\n' +- ' * If the returned value is not a tuple, the conversion ' +- 'fails and\n' +- ' "TypeError" is raised.\n' +- '\n' +- ' * If there are more positional patterns than\n' +- ' "len(cls.__match_args__)", "TypeError" is raised.\n' +- '\n' +- ' * Otherwise, positional pattern "i" is converted to a ' +- 'keyword\n' +- ' pattern using "__match_args__[i]" as the keyword.\n' +- ' "__match_args__[i]" must be a string; if not "TypeError" ' +- 'is\n' +- ' raised.\n' +- '\n' +- ' * If there are duplicate keywords, "TypeError" is raised.\n' +- '\n' +- ' See also:\n' +- '\n' +- ' Customizing positional arguments in class pattern ' +- 'matching\n' +- '\n' +- ' II. Once all positional patterns have been converted to ' +- 'keyword\n' +- ' patterns,\n' +- ' the match proceeds as if there were only keyword ' +- 'patterns.\n' +- '\n' +- ' For the following built-in types the handling of positional\n' +- ' subpatterns is different:\n' +- '\n' +- ' * "bool"\n' +- '\n' +- ' * "bytearray"\n' +- '\n' +- ' * "bytes"\n' +- '\n' +- ' * "dict"\n' +- '\n' +- ' * "float"\n' +- '\n' +- ' * "frozenset"\n' +- '\n' +- ' * "int"\n' +- '\n' +- ' * "list"\n' +- '\n' +- ' * "set"\n' +- '\n' +- ' * "str"\n' +- '\n' +- ' * "tuple"\n' +- '\n' +- ' These classes accept a single positional argument, and the ' +- 'pattern\n' +- ' there is matched against the whole object rather than an ' +- 'attribute.\n' +- ' For example "int(0|1)" matches the value "0", but not the ' +- 'value\n' +- ' "0.0".\n' +- '\n' +- 'In simple terms "CLS(P1, attr=P2)" matches only if the ' +- 'following\n' +- 'happens:\n' +- '\n' +- '* "isinstance(, CLS)"\n' +- '\n' +- '* convert "P1" to a keyword pattern using "CLS.__match_args__"\n' +- '\n' +- '* For each keyword argument "attr=P2":\n' +- '\n' +- ' * "hasattr(, "attr")"\n' +- '\n' +- ' * "P2" matches ".attr"\n' +- '\n' +- '* … and so on for the corresponding keyword argument/pattern ' +- 'pair.\n' +- '\n' +- 'See also:\n' +- '\n' +- ' * **PEP 634** – Structural Pattern Matching: Specification\n' +- '\n' +- ' * **PEP 636** – Structural Pattern Matching: Tutorial\n' +- '\n' +- '\n' +- 'Function definitions\n' +- '====================\n' +- '\n' +- 'A function definition defines a user-defined function object ' +- '(see\n' +- 'section The standard type hierarchy):\n' +- '\n' +- ' funcdef ::= [decorators] "def" funcname ' +- '[type_params] "(" [parameter_list] ")"\n' +- ' ["->" expression] ":" suite\n' +- ' decorators ::= decorator+\n' +- ' decorator ::= "@" assignment_expression ' +- 'NEWLINE\n' +- ' parameter_list ::= defparameter ("," ' +- 'defparameter)* "," "/" ["," [parameter_list_no_posonly]]\n' +- ' | parameter_list_no_posonly\n' +- ' parameter_list_no_posonly ::= defparameter ("," ' +- 'defparameter)* ["," [parameter_list_starargs]]\n' +- ' | parameter_list_starargs\n' +- ' parameter_list_starargs ::= "*" [star_parameter] ("," ' +- 'defparameter)* ["," ["**" parameter [","]]]\n' +- ' | "**" parameter [","]\n' +- ' parameter ::= identifier [":" expression]\n' +- ' star_parameter ::= identifier [":" ["*"] ' +- 'expression]\n' +- ' defparameter ::= parameter ["=" expression]\n' +- ' funcname ::= identifier\n' +- '\n' +- 'A function definition is an executable statement. Its execution ' +- 'binds\n' +- 'the function name in the current local namespace to a function ' +- 'object\n' +- '(a wrapper around the executable code for the function). This\n' +- 'function object contains a reference to the current global ' +- 'namespace\n' +- 'as the global namespace to be used when the function is called.\n' +- '\n' +- 'The function definition does not execute the function body; this ' +- 'gets\n' +- 'executed only when the function is called. [4]\n' +- '\n' +- 'A function definition may be wrapped by one or more *decorator*\n' +- 'expressions. Decorator expressions are evaluated when the ' +- 'function is\n' +- 'defined, in the scope that contains the function definition. ' +- 'The\n' +- 'result must be a callable, which is invoked with the function ' +- 'object\n' +- 'as the only argument. The returned value is bound to the ' +- 'function name\n' +- 'instead of the function object. Multiple decorators are applied ' +- 'in\n' +- 'nested fashion. For example, the following code\n' +- '\n' +- ' @f1(arg)\n' +- ' @f2\n' +- ' def func(): pass\n' +- '\n' +- 'is roughly equivalent to\n' +- '\n' +- ' def func(): pass\n' +- ' func = f1(arg)(f2(func))\n' +- '\n' +- 'except that the original function is not temporarily bound to ' +- 'the name\n' +- '"func".\n' +- '\n' +- 'Changed in version 3.9: Functions may be decorated with any ' +- 'valid\n' +- '"assignment_expression". Previously, the grammar was much more\n' +- 'restrictive; see **PEP 614** for details.\n' +- '\n' +- 'A list of type parameters may be given in square brackets ' +- 'between the\n' +- 'function’s name and the opening parenthesis for its parameter ' +- 'list.\n' +- 'This indicates to static type checkers that the function is ' +- 'generic.\n' +- 'At runtime, the type parameters can be retrieved from the ' +- 'function’s\n' +- '"__type_params__" attribute. See Generic functions for more.\n' +- '\n' +- 'Changed in version 3.12: Type parameter lists are new in Python ' +- '3.12.\n' +- '\n' +- 'When one or more *parameters* have the form *parameter* "="\n' +- '*expression*, the function is said to have “default parameter ' +- 'values.â€\n' +- 'For a parameter with a default value, the corresponding ' +- '*argument* may\n' +- 'be omitted from a call, in which case the parameter’s default ' +- 'value is\n' +- 'substituted. If a parameter has a default value, all following\n' +- 'parameters up until the “"*"†must also have a default value — ' +- 'this is\n' +- 'a syntactic restriction that is not expressed by the grammar.\n' +- '\n' +- '**Default parameter values are evaluated from left to right when ' +- 'the\n' +- 'function definition is executed.** This means that the ' +- 'expression is\n' +- 'evaluated once, when the function is defined, and that the same ' +- '“pre-\n' +- 'computed†value is used for each call. This is especially ' +- 'important\n' +- 'to understand when a default parameter value is a mutable ' +- 'object, such\n' +- 'as a list or a dictionary: if the function modifies the object ' +- '(e.g.\n' +- 'by appending an item to a list), the default parameter value is ' +- 'in\n' +- 'effect modified. This is generally not what was intended. A ' +- 'way\n' +- 'around this is to use "None" as the default, and explicitly test ' +- 'for\n' +- 'it in the body of the function, e.g.:\n' +- '\n' +- ' def whats_on_the_telly(penguin=None):\n' +- ' if penguin is None:\n' +- ' penguin = []\n' +- ' penguin.append("property of the zoo")\n' +- ' return penguin\n' +- '\n' +- 'Function call semantics are described in more detail in section ' +- 'Calls.\n' +- 'A function call always assigns values to all parameters ' +- 'mentioned in\n' +- 'the parameter list, either from positional arguments, from ' +- 'keyword\n' +- 'arguments, or from default values. If the form “"*identifier"†' +- 'is\n' +- 'present, it is initialized to a tuple receiving any excess ' +- 'positional\n' +- 'parameters, defaulting to the empty tuple. If the form\n' +- '“"**identifier"†is present, it is initialized to a new ordered\n' +- 'mapping receiving any excess keyword arguments, defaulting to a ' +- 'new\n' +- 'empty mapping of the same type. Parameters after “"*"†or\n' +- '“"*identifier"†are keyword-only parameters and may only be ' +- 'passed by\n' +- 'keyword arguments. Parameters before “"/"†are positional-only\n' +- 'parameters and may only be passed by positional arguments.\n' +- '\n' +- 'Changed in version 3.8: The "/" function parameter syntax may be ' +- 'used\n' +- 'to indicate positional-only parameters. See **PEP 570** for ' +- 'details.\n' +- '\n' +- 'Parameters may have an *annotation* of the form “": ' +- 'expression"â€\n' +- 'following the parameter name. Any parameter may have an ' +- 'annotation,\n' +- 'even those of the form "*identifier" or "**identifier". (As a ' +- 'special\n' +- 'case, parameters of the form "*identifier" may have an ' +- 'annotation “":\n' +- '*expression"â€.) Functions may have “return†annotation of the ' +- 'form\n' +- '“"-> expression"†after the parameter list. These annotations ' +- 'can be\n' +- 'any valid Python expression. The presence of annotations does ' +- 'not\n' +- 'change the semantics of a function. See Annotations for more\n' +- 'information on annotations.\n' +- '\n' +- 'Changed in version 3.11: Parameters of the form “"*identifier"†' +- 'may\n' +- 'have an annotation “": *expression"â€. See **PEP 646**.\n' +- '\n' +- 'It is also possible to create anonymous functions (functions not ' +- 'bound\n' +- 'to a name), for immediate use in expressions. This uses lambda\n' +- 'expressions, described in section Lambdas. Note that the ' +- 'lambda\n' +- 'expression is merely a shorthand for a simplified function ' +- 'definition;\n' +- 'a function defined in a “"def"†statement can be passed around ' +- 'or\n' +- 'assigned to another name just like a function defined by a ' +- 'lambda\n' +- 'expression. The “"def"†form is actually more powerful since ' +- 'it\n' +- 'allows the execution of multiple statements and annotations.\n' +- '\n' +- '**Programmer’s note:** Functions are first-class objects. A ' +- '“"def"â€\n' +- 'statement executed inside a function definition defines a local\n' +- 'function that can be returned or passed around. Free variables ' +- 'used\n' +- 'in the nested function can access the local variables of the ' +- 'function\n' +- 'containing the def. See section Naming and binding for ' +- 'details.\n' +- '\n' +- 'See also:\n' +- '\n' +- ' **PEP 3107** - Function Annotations\n' +- ' The original specification for function annotations.\n' +- '\n' +- ' **PEP 484** - Type Hints\n' +- ' Definition of a standard meaning for annotations: type ' +- 'hints.\n' +- '\n' +- ' **PEP 526** - Syntax for Variable Annotations\n' +- ' Ability to type hint variable declarations, including ' +- 'class\n' +- ' variables and instance variables.\n' +- '\n' +- ' **PEP 563** - Postponed Evaluation of Annotations\n' +- ' Support for forward references within annotations by ' +- 'preserving\n' +- ' annotations in a string form at runtime instead of eager\n' +- ' evaluation.\n' +- '\n' +- ' **PEP 318** - Decorators for Functions and Methods\n' +- ' Function and method decorators were introduced. Class ' +- 'decorators\n' +- ' were introduced in **PEP 3129**.\n' +- '\n' +- '\n' +- 'Class definitions\n' +- '=================\n' +- '\n' +- 'A class definition defines a class object (see section The ' +- 'standard\n' +- 'type hierarchy):\n' +- '\n' +- ' classdef ::= [decorators] "class" classname [type_params] ' +- '[inheritance] ":" suite\n' +- ' inheritance ::= "(" [argument_list] ")"\n' +- ' classname ::= identifier\n' +- '\n' +- 'A class definition is an executable statement. The inheritance ' +- 'list\n' +- 'usually gives a list of base classes (see Metaclasses for more\n' +- 'advanced uses), so each item in the list should evaluate to a ' +- 'class\n' +- 'object which allows subclassing. Classes without an inheritance ' +- 'list\n' +- 'inherit, by default, from the base class "object"; hence,\n' +- '\n' +- ' class Foo:\n' +- ' pass\n' +- '\n' +- 'is equivalent to\n' +- '\n' +- ' class Foo(object):\n' +- ' pass\n' +- '\n' +- 'The class’s suite is then executed in a new execution frame ' +- '(see\n' +- 'Naming and binding), using a newly created local namespace and ' +- 'the\n' +- 'original global namespace. (Usually, the suite contains mostly\n' +- 'function definitions.) When the class’s suite finishes ' +- 'execution, its\n' +- 'execution frame is discarded but its local namespace is saved. ' +- '[5] A\n' +- 'class object is then created using the inheritance list for the ' +- 'base\n' +- 'classes and the saved local namespace for the attribute ' +- 'dictionary.\n' +- 'The class name is bound to this class object in the original ' +- 'local\n' +- 'namespace.\n' +- '\n' +- 'The order in which attributes are defined in the class body is\n' +- 'preserved in the new class’s "__dict__". Note that this is ' +- 'reliable\n' +- 'only right after the class is created and only for classes that ' +- 'were\n' +- 'defined using the definition syntax.\n' +- '\n' +- 'Class creation can be customized heavily using metaclasses.\n' +- '\n' +- 'Classes can also be decorated: just like when decorating ' +- 'functions,\n' +- '\n' +- ' @f1(arg)\n' +- ' @f2\n' +- ' class Foo: pass\n' +- '\n' +- 'is roughly equivalent to\n' +- '\n' +- ' class Foo: pass\n' +- ' Foo = f1(arg)(f2(Foo))\n' +- '\n' +- 'The evaluation rules for the decorator expressions are the same ' +- 'as for\n' +- 'function decorators. The result is then bound to the class ' +- 'name.\n' +- '\n' +- 'Changed in version 3.9: Classes may be decorated with any valid\n' +- '"assignment_expression". Previously, the grammar was much more\n' +- 'restrictive; see **PEP 614** for details.\n' +- '\n' +- 'A list of type parameters may be given in square brackets ' +- 'immediately\n' +- 'after the class’s name. This indicates to static type checkers ' +- 'that\n' +- 'the class is generic. At runtime, the type parameters can be ' +- 'retrieved\n' +- 'from the class’s "__type_params__" attribute. See Generic ' +- 'classes for\n' +- 'more.\n' +- '\n' +- 'Changed in version 3.12: Type parameter lists are new in Python ' +- '3.12.\n' +- '\n' +- '**Programmer’s note:** Variables defined in the class definition ' +- 'are\n' +- 'class attributes; they are shared by instances. Instance ' +- 'attributes\n' +- 'can be set in a method with "self.name = value". Both class ' +- 'and\n' +- 'instance attributes are accessible through the notation ' +- '“"self.name"â€,\n' +- 'and an instance attribute hides a class attribute with the same ' +- 'name\n' +- 'when accessed in this way. Class attributes can be used as ' +- 'defaults\n' +- 'for instance attributes, but using mutable values there can lead ' +- 'to\n' +- 'unexpected results. Descriptors can be used to create instance\n' +- 'variables with different implementation details.\n' +- '\n' +- 'See also:\n' +- '\n' +- ' **PEP 3115** - Metaclasses in Python 3000\n' +- ' The proposal that changed the declaration of metaclasses to ' +- 'the\n' +- ' current syntax, and the semantics for how classes with\n' +- ' metaclasses are constructed.\n' +- '\n' +- ' **PEP 3129** - Class Decorators\n' +- ' The proposal that added class decorators. Function and ' +- 'method\n' +- ' decorators were introduced in **PEP 318**.\n' +- '\n' +- '\n' +- 'Coroutines\n' +- '==========\n' +- '\n' +- 'Added in version 3.5.\n' +- '\n' +- '\n' +- 'Coroutine function definition\n' +- '-----------------------------\n' +- '\n' +- ' async_funcdef ::= [decorators] "async" "def" funcname "(" ' +- '[parameter_list] ")"\n' +- ' ["->" expression] ":" suite\n' +- '\n' +- 'Execution of Python coroutines can be suspended and resumed at ' +- 'many\n' +- 'points (see *coroutine*). "await" expressions, "async for" and ' +- '"async\n' +- 'with" can only be used in the body of a coroutine function.\n' +- '\n' +- 'Functions defined with "async def" syntax are always coroutine\n' +- 'functions, even if they do not contain "await" or "async" ' +- 'keywords.\n' +- '\n' +- 'It is a "SyntaxError" to use a "yield from" expression inside ' +- 'the body\n' +- 'of a coroutine function.\n' +- '\n' +- 'An example of a coroutine function:\n' +- '\n' +- ' async def func(param1, param2):\n' +- ' do_stuff()\n' +- ' await some_coroutine()\n' +- '\n' +- 'Changed in version 3.7: "await" and "async" are now keywords;\n' +- 'previously they were only treated as such inside the body of a\n' +- 'coroutine function.\n' +- '\n' +- '\n' +- 'The "async for" statement\n' +- '-------------------------\n' +- '\n' +- ' async_for_stmt ::= "async" for_stmt\n' +- '\n' +- 'An *asynchronous iterable* provides an "__aiter__" method that\n' +- 'directly returns an *asynchronous iterator*, which can call\n' +- 'asynchronous code in its "__anext__" method.\n' +- '\n' +- 'The "async for" statement allows convenient iteration over\n' +- 'asynchronous iterables.\n' +- '\n' +- 'The following code:\n' +- '\n' +- ' async for TARGET in ITER:\n' +- ' SUITE\n' +- ' else:\n' +- ' SUITE2\n' +- '\n' +- 'Is semantically equivalent to:\n' +- '\n' +- ' iter = (ITER)\n' +- ' iter = type(iter).__aiter__(iter)\n' +- ' running = True\n' +- '\n' +- ' while running:\n' +- ' try:\n' +- ' TARGET = await type(iter).__anext__(iter)\n' +- ' except StopAsyncIteration:\n' +- ' running = False\n' +- ' else:\n' +- ' SUITE\n' +- ' else:\n' +- ' SUITE2\n' +- '\n' +- 'See also "__aiter__()" and "__anext__()" for details.\n' +- '\n' +- 'It is a "SyntaxError" to use an "async for" statement outside ' +- 'the body\n' +- 'of a coroutine function.\n' +- '\n' +- '\n' +- 'The "async with" statement\n' +- '--------------------------\n' +- '\n' +- ' async_with_stmt ::= "async" with_stmt\n' +- '\n' +- 'An *asynchronous context manager* is a *context manager* that is ' +- 'able\n' +- 'to suspend execution in its *enter* and *exit* methods.\n' +- '\n' +- 'The following code:\n' +- '\n' +- ' async with EXPRESSION as TARGET:\n' +- ' SUITE\n' +- '\n' +- 'is semantically equivalent to:\n' +- '\n' +- ' manager = (EXPRESSION)\n' +- ' aenter = type(manager).__aenter__\n' +- ' aexit = type(manager).__aexit__\n' +- ' value = await aenter(manager)\n' +- ' hit_except = False\n' +- '\n' +- ' try:\n' +- ' TARGET = value\n' +- ' SUITE\n' +- ' except:\n' +- ' hit_except = True\n' +- ' if not await aexit(manager, *sys.exc_info()):\n' +- ' raise\n' +- ' finally:\n' +- ' if not hit_except:\n' +- ' await aexit(manager, None, None, None)\n' +- '\n' +- 'See also "__aenter__()" and "__aexit__()" for details.\n' +- '\n' +- 'It is a "SyntaxError" to use an "async with" statement outside ' +- 'the\n' +- 'body of a coroutine function.\n' +- '\n' +- 'See also:\n' +- '\n' +- ' **PEP 492** - Coroutines with async and await syntax\n' +- ' The proposal that made coroutines a proper standalone ' +- 'concept in\n' +- ' Python, and added supporting syntax.\n' +- '\n' +- '\n' +- 'Type parameter lists\n' +- '====================\n' +- '\n' +- 'Added in version 3.12.\n' +- '\n' +- 'Changed in version 3.13: Support for default values was added ' +- '(see\n' +- '**PEP 696**).\n' +- '\n' +- ' type_params ::= "[" type_param ("," type_param)* "]"\n' +- ' type_param ::= typevar | typevartuple | paramspec\n' +- ' typevar ::= identifier (":" expression)? ("=" ' +- 'expression)?\n' +- ' typevartuple ::= "*" identifier ("=" expression)?\n' +- ' paramspec ::= "**" identifier ("=" expression)?\n' +- '\n' +- 'Functions (including coroutines), classes and type aliases may ' +- 'contain\n' +- 'a type parameter list:\n' +- '\n' +- ' def max[T](args: list[T]) -> T:\n' +- ' ...\n' +- '\n' +- ' async def amax[T](args: list[T]) -> T:\n' +- ' ...\n' +- '\n' +- ' class Bag[T]:\n' +- ' def __iter__(self) -> Iterator[T]:\n' +- ' ...\n' +- '\n' +- ' def add(self, arg: T) -> None:\n' +- ' ...\n' +- '\n' +- ' type ListOrSet[T] = list[T] | set[T]\n' +- '\n' +- 'Semantically, this indicates that the function, class, or type ' +- 'alias\n' +- 'is generic over a type variable. This information is primarily ' +- 'used by\n' +- 'static type checkers, and at runtime, generic objects behave ' +- 'much like\n' +- 'their non-generic counterparts.\n' +- '\n' +- 'Type parameters are declared in square brackets ("[]") ' +- 'immediately\n' +- 'after the name of the function, class, or type alias. The type\n' +- 'parameters are accessible within the scope of the generic ' +- 'object, but\n' +- 'not elsewhere. Thus, after a declaration "def func[T](): pass", ' +- 'the\n' +- 'name "T" is not available in the module scope. Below, the ' +- 'semantics of\n' +- 'generic objects are described with more precision. The scope of ' +- 'type\n' +- 'parameters is modeled with a special function (technically, an\n' +- 'annotation scope) that wraps the creation of the generic ' +- 'object.\n' +- '\n' +- 'Generic functions, classes, and type aliases have a ' +- '"__type_params__"\n' +- 'attribute listing their type parameters.\n' +- '\n' +- 'Type parameters come in three kinds:\n' +- '\n' +- '* "typing.TypeVar", introduced by a plain name (e.g., "T").\n' +- ' Semantically, this represents a single type to a type ' +- 'checker.\n' +- '\n' +- '* "typing.TypeVarTuple", introduced by a name prefixed with a ' +- 'single\n' +- ' asterisk (e.g., "*Ts"). Semantically, this stands for a tuple ' +- 'of any\n' +- ' number of types.\n' +- '\n' +- '* "typing.ParamSpec", introduced by a name prefixed with two ' +- 'asterisks\n' +- ' (e.g., "**P"). Semantically, this stands for the parameters of ' +- 'a\n' +- ' callable.\n' +- '\n' +- '"typing.TypeVar" declarations can define *bounds* and ' +- '*constraints*\n' +- 'with a colon (":") followed by an expression. A single ' +- 'expression\n' +- 'after the colon indicates a bound (e.g. "T: int"). Semantically, ' +- 'this\n' +- 'means that the "typing.TypeVar" can only represent types that ' +- 'are a\n' +- 'subtype of this bound. A parenthesized tuple of expressions ' +- 'after the\n' +- 'colon indicates a set of constraints (e.g. "T: (str, bytes)"). ' +- 'Each\n' +- 'member of the tuple should be a type (again, this is not ' +- 'enforced at\n' +- 'runtime). Constrained type variables can only take on one of the ' +- 'types\n' +- 'in the list of constraints.\n' +- '\n' +- 'For "typing.TypeVar"s declared using the type parameter list ' +- 'syntax,\n' +- 'the bound and constraints are not evaluated when the generic ' +- 'object is\n' +- 'created, but only when the value is explicitly accessed through ' +- 'the\n' +- 'attributes "__bound__" and "__constraints__". To accomplish ' +- 'this, the\n' +- 'bounds or constraints are evaluated in a separate annotation ' +- 'scope.\n' +- '\n' +- '"typing.TypeVarTuple"s and "typing.ParamSpec"s cannot have ' +- 'bounds or\n' +- 'constraints.\n' +- '\n' +- 'All three flavors of type parameters can also have a *default ' +- 'value*,\n' +- 'which is used when the type parameter is not explicitly ' +- 'provided. This\n' +- 'is added by appending a single equals sign ("=") followed by an\n' +- 'expression. Like the bounds and constraints of type variables, ' +- 'the\n' +- 'default value is not evaluated when the object is created, but ' +- 'only\n' +- 'when the type parameter’s "__default__" attribute is accessed. ' +- 'To this\n' +- 'end, the default value is evaluated in a separate annotation ' +- 'scope. If\n' +- 'no default value is specified for a type parameter, the ' +- '"__default__"\n' +- 'attribute is set to the special sentinel object ' +- '"typing.NoDefault".\n' +- '\n' +- 'The following example indicates the full set of allowed type ' +- 'parameter\n' +- 'declarations:\n' +- '\n' +- ' def overly_generic[\n' +- ' SimpleTypeVar,\n' +- ' TypeVarWithDefault = int,\n' +- ' TypeVarWithBound: int,\n' +- ' TypeVarWithConstraints: (str, bytes),\n' +- ' *SimpleTypeVarTuple = (int, float),\n' +- ' **SimpleParamSpec = (str, bytearray),\n' +- ' ](\n' +- ' a: SimpleTypeVar,\n' +- ' b: TypeVarWithDefault,\n' +- ' c: TypeVarWithBound,\n' +- ' d: Callable[SimpleParamSpec, TypeVarWithConstraints],\n' +- ' *e: SimpleTypeVarTuple,\n' +- ' ): ...\n' +- '\n' +- '\n' +- 'Generic functions\n' +- '-----------------\n' +- '\n' +- 'Generic functions are declared as follows:\n' +- '\n' +- ' def func[T](arg: T): ...\n' +- '\n' +- 'This syntax is equivalent to:\n' +- '\n' +- ' annotation-def TYPE_PARAMS_OF_func():\n' +- ' T = typing.TypeVar("T")\n' +- ' def func(arg: T): ...\n' +- ' func.__type_params__ = (T,)\n' +- ' return func\n' +- ' func = TYPE_PARAMS_OF_func()\n' +- '\n' +- 'Here "annotation-def" indicates an annotation scope, which is ' +- 'not\n' +- 'actually bound to any name at runtime. (One other liberty is ' +- 'taken in\n' +- 'the translation: the syntax does not go through attribute access ' +- 'on\n' +- 'the "typing" module, but creates an instance of ' +- '"typing.TypeVar"\n' +- 'directly.)\n' +- '\n' +- 'The annotations of generic functions are evaluated within the\n' +- 'annotation scope used for declaring the type parameters, but ' +- 'the\n' +- 'function’s defaults and decorators are not.\n' +- '\n' +- 'The following example illustrates the scoping rules for these ' +- 'cases,\n' +- 'as well as for additional flavors of type parameters:\n' +- '\n' +- ' @decorator\n' +- ' def func[T: int, *Ts, **P](*args: *Ts, arg: Callable[P, T] = ' +- 'some_default):\n' +- ' ...\n' +- '\n' +- 'Except for the lazy evaluation of the "TypeVar" bound, this is\n' +- 'equivalent to:\n' +- '\n' +- ' DEFAULT_OF_arg = some_default\n' +- '\n' +- ' annotation-def TYPE_PARAMS_OF_func():\n' +- '\n' +- ' annotation-def BOUND_OF_T():\n' +- ' return int\n' +- ' # In reality, BOUND_OF_T() is evaluated only on demand.\n' +- ' T = typing.TypeVar("T", bound=BOUND_OF_T())\n' +- '\n' +- ' Ts = typing.TypeVarTuple("Ts")\n' +- ' P = typing.ParamSpec("P")\n' +- '\n' +- ' def func(*args: *Ts, arg: Callable[P, T] = ' +- 'DEFAULT_OF_arg):\n' +- ' ...\n' +- '\n' +- ' func.__type_params__ = (T, Ts, P)\n' +- ' return func\n' +- ' func = decorator(TYPE_PARAMS_OF_func())\n' +- '\n' +- 'The capitalized names like "DEFAULT_OF_arg" are not actually ' +- 'bound at\n' +- 'runtime.\n' +- '\n' +- '\n' +- 'Generic classes\n' +- '---------------\n' +- '\n' +- 'Generic classes are declared as follows:\n' +- '\n' +- ' class Bag[T]: ...\n' +- '\n' +- 'This syntax is equivalent to:\n' +- '\n' +- ' annotation-def TYPE_PARAMS_OF_Bag():\n' +- ' T = typing.TypeVar("T")\n' +- ' class Bag(typing.Generic[T]):\n' +- ' __type_params__ = (T,)\n' +- ' ...\n' +- ' return Bag\n' +- ' Bag = TYPE_PARAMS_OF_Bag()\n' +- '\n' +- 'Here again "annotation-def" (not a real keyword) indicates an\n' +- 'annotation scope, and the name "TYPE_PARAMS_OF_Bag" is not ' +- 'actually\n' +- 'bound at runtime.\n' +- '\n' +- 'Generic classes implicitly inherit from "typing.Generic". The ' +- 'base\n' +- 'classes and keyword arguments of generic classes are evaluated ' +- 'within\n' +- 'the type scope for the type parameters, and decorators are ' +- 'evaluated\n' +- 'outside that scope. This is illustrated by this example:\n' +- '\n' +- ' @decorator\n' +- ' class Bag(Base[T], arg=T): ...\n' +- '\n' +- 'This is equivalent to:\n' +- '\n' +- ' annotation-def TYPE_PARAMS_OF_Bag():\n' +- ' T = typing.TypeVar("T")\n' +- ' class Bag(Base[T], typing.Generic[T], arg=T):\n' +- ' __type_params__ = (T,)\n' +- ' ...\n' +- ' return Bag\n' +- ' Bag = decorator(TYPE_PARAMS_OF_Bag())\n' +- '\n' +- '\n' +- 'Generic type aliases\n' +- '--------------------\n' +- '\n' +- 'The "type" statement can also be used to create a generic type ' +- 'alias:\n' +- '\n' +- ' type ListOrSet[T] = list[T] | set[T]\n' +- '\n' +- 'Except for the lazy evaluation of the value, this is equivalent ' +- 'to:\n' +- '\n' +- ' annotation-def TYPE_PARAMS_OF_ListOrSet():\n' +- ' T = typing.TypeVar("T")\n' +- '\n' +- ' annotation-def VALUE_OF_ListOrSet():\n' +- ' return list[T] | set[T]\n' +- ' # In reality, the value is lazily evaluated\n' +- ' return typing.TypeAliasType("ListOrSet", ' +- 'VALUE_OF_ListOrSet(), type_params=(T,))\n' +- ' ListOrSet = TYPE_PARAMS_OF_ListOrSet()\n' +- '\n' +- 'Here, "annotation-def" (not a real keyword) indicates an ' +- 'annotation\n' +- 'scope. The capitalized names like "TYPE_PARAMS_OF_ListOrSet" are ' +- 'not\n' +- 'actually bound at runtime.\n' +- '\n' +- '\n' +- 'Annotations\n' +- '===========\n' +- '\n' +- 'Changed in version 3.14: Annotations are now lazily evaluated ' +- 'by\n' +- 'default.\n' +- '\n' +- 'Variables and function parameters may carry *annotations*, ' +- 'created by\n' +- 'adding a colon after the name, followed by an expression:\n' +- '\n' +- ' x: annotation = 1\n' +- ' def f(param: annotation): ...\n' +- '\n' +- 'Functions may also carry a return annotation following an ' +- 'arrow:\n' +- '\n' +- ' def f() -> annotation: ...\n' +- '\n' +- 'Annotations are conventionally used for *type hints*, but this ' +- 'is not\n' +- 'enforced by the language, and in general annotations may ' +- 'contain\n' +- 'arbitrary expressions. The presence of annotations does not ' +- 'change the\n' +- 'runtime semantics of the code, except if some mechanism is used ' +- 'that\n' +- 'introspects and uses the annotations (such as "dataclasses" or\n' +- '"functools.singledispatch()").\n' +- '\n' +- 'By default, annotations are lazily evaluated in a annotation ' +- 'scope.\n' +- 'This means that they are not evaluated when the code containing ' +- 'the\n' +- 'annotation is evaluated. Instead, the interpreter saves ' +- 'information\n' +- 'that can be used to evaluate the annotation later if requested. ' +- 'The\n' +- '"annotationlib" module provides tools for evaluating ' +- 'annotations.\n' +- '\n' +- 'If the future statement "from __future__ import annotations" is\n' +- 'present, all annotations are instead stored as strings:\n' +- '\n' +- ' >>> from __future__ import annotations\n' +- ' >>> def f(param: annotation): ...\n' +- ' >>> f.__annotations__\n' +- " {'param': 'annotation'}\n" +- '\n' +- '-[ Footnotes ]-\n' +- '\n' +- '[1] The exception is propagated to the invocation stack unless ' +- 'there\n' +- ' is a "finally" clause which happens to raise another ' +- 'exception.\n' +- ' That new exception causes the old one to be lost.\n' +- '\n' +- '[2] In pattern matching, a sequence is defined as one of the\n' +- ' following:\n' +- '\n' +- ' * a class that inherits from "collections.abc.Sequence"\n' +- '\n' +- ' * a Python class that has been registered as\n' +- ' "collections.abc.Sequence"\n' +- '\n' +- ' * a builtin class that has its (CPython) ' +- '"Py_TPFLAGS_SEQUENCE" bit\n' +- ' set\n' +- '\n' +- ' * a class that inherits from any of the above\n' +- '\n' +- ' The following standard library classes are sequences:\n' +- '\n' +- ' * "array.array"\n' +- '\n' +- ' * "collections.deque"\n' +- '\n' +- ' * "list"\n' +- '\n' +- ' * "memoryview"\n' +- '\n' +- ' * "range"\n' +- '\n' +- ' * "tuple"\n' +- '\n' +- ' Note:\n' +- '\n' +- ' Subject values of type "str", "bytes", and "bytearray" do ' +- 'not\n' +- ' match sequence patterns.\n' +- '\n' +- '[3] In pattern matching, a mapping is defined as one of the ' +- 'following:\n' +- '\n' +- ' * a class that inherits from "collections.abc.Mapping"\n' +- '\n' +- ' * a Python class that has been registered as\n' +- ' "collections.abc.Mapping"\n' +- '\n' +- ' * a builtin class that has its (CPython) ' +- '"Py_TPFLAGS_MAPPING" bit\n' +- ' set\n' +- '\n' +- ' * a class that inherits from any of the above\n' +- '\n' +- ' The standard library classes "dict" and ' +- '"types.MappingProxyType"\n' +- ' are mappings.\n' +- '\n' +- '[4] A string literal appearing as the first statement in the ' +- 'function\n' +- ' body is transformed into the function’s "__doc__" attribute ' +- 'and\n' +- ' therefore the function’s *docstring*.\n' +- '\n' +- '[5] A string literal appearing as the first statement in the ' +- 'class\n' +- ' body is transformed into the namespace’s "__doc__" item and\n' +- ' therefore the class’s *docstring*.\n', +- 'context-managers': 'With Statement Context Managers\n' +- '*******************************\n' +- '\n' +- 'A *context manager* is an object that defines the ' +- 'runtime context to\n' +- 'be established when executing a "with" statement. The ' +- 'context manager\n' +- 'handles the entry into, and the exit from, the desired ' +- 'runtime context\n' +- 'for the execution of the block of code. Context ' +- 'managers are normally\n' +- 'invoked using the "with" statement (described in section ' +- 'The with\n' +- 'statement), but can also be used by directly invoking ' +- 'their methods.\n' +- '\n' +- 'Typical uses of context managers include saving and ' +- 'restoring various\n' +- 'kinds of global state, locking and unlocking resources, ' +- 'closing opened\n' +- 'files, etc.\n' +- '\n' +- 'For more information on context managers, see Context ' +- 'Manager Types.\n' +- 'The "object" class itself does not provide the context ' +- 'manager\n' +- 'methods.\n' +- '\n' +- 'object.__enter__(self)\n' +- '\n' +- ' Enter the runtime context related to this object. The ' +- '"with"\n' +- ' statement will bind this method’s return value to the ' +- 'target(s)\n' +- ' specified in the "as" clause of the statement, if ' +- 'any.\n' +- '\n' +- 'object.__exit__(self, exc_type, exc_value, traceback)\n' +- '\n' +- ' Exit the runtime context related to this object. The ' +- 'parameters\n' +- ' describe the exception that caused the context to be ' +- 'exited. If the\n' +- ' context was exited without an exception, all three ' +- 'arguments will\n' +- ' be "None".\n' +- '\n' +- ' If an exception is supplied, and the method wishes to ' +- 'suppress the\n' +- ' exception (i.e., prevent it from being propagated), ' +- 'it should\n' +- ' return a true value. Otherwise, the exception will be ' +- 'processed\n' +- ' normally upon exit from this method.\n' +- '\n' +- ' Note that "__exit__()" methods should not reraise the ' +- 'passed-in\n' +- ' exception; this is the caller’s responsibility.\n' +- '\n' +- 'See also:\n' +- '\n' +- ' **PEP 343** - The “with†statement\n' +- ' The specification, background, and examples for the ' +- 'Python "with"\n' +- ' statement.\n', +- 'continue': 'The "continue" statement\n' +- '************************\n' +- '\n' +- ' continue_stmt ::= "continue"\n' +- '\n' +- '"continue" may only occur syntactically nested in a "for" or ' +- '"while"\n' +- 'loop, but not nested in a function or class definition within ' +- 'that\n' +- 'loop. It continues with the next cycle of the nearest enclosing ' +- 'loop.\n' +- '\n' +- 'When "continue" passes control out of a "try" statement with a\n' +- '"finally" clause, that "finally" clause is executed before ' +- 'really\n' +- 'starting the next loop cycle.\n', +- 'conversions': 'Arithmetic conversions\n' +- '**********************\n' +- '\n' +- 'When a description of an arithmetic operator below uses the ' +- 'phrase\n' +- '“the numeric arguments are converted to a common real typeâ€, ' +- 'this\n' +- 'means that the operator implementation for built-in types ' +- 'works as\n' +- 'follows:\n' +- '\n' +- '* If both arguments are complex numbers, no conversion is ' +- 'performed;\n' +- '\n' +- '* if either argument is a complex or a floating-point number, ' +- 'the\n' +- ' other is converted to a floating-point number;\n' +- '\n' +- '* otherwise, both must be integers and no conversion is ' +- 'necessary.\n' +- '\n' +- 'Some additional rules apply for certain operators (e.g., a ' +- 'string as a\n' +- 'left argument to the ‘%’ operator). Extensions must define ' +- 'their own\n' +- 'conversion behavior.\n', +- 'customization': 'Basic customization\n' +- '*******************\n' +- '\n' +- 'object.__new__(cls[, ...])\n' +- '\n' +- ' Called to create a new instance of class *cls*. ' +- '"__new__()" is a\n' +- ' static method (special-cased so you need not declare it ' +- 'as such)\n' +- ' that takes the class of which an instance was requested ' +- 'as its\n' +- ' first argument. The remaining arguments are those ' +- 'passed to the\n' +- ' object constructor expression (the call to the class). ' +- 'The return\n' +- ' value of "__new__()" should be the new object instance ' +- '(usually an\n' +- ' instance of *cls*).\n' +- '\n' +- ' Typical implementations create a new instance of the ' +- 'class by\n' +- ' invoking the superclass’s "__new__()" method using\n' +- ' "super().__new__(cls[, ...])" with appropriate arguments ' +- 'and then\n' +- ' modifying the newly created instance as necessary before ' +- 'returning\n' +- ' it.\n' +- '\n' +- ' If "__new__()" is invoked during object construction and ' +- 'it returns\n' +- ' an instance of *cls*, then the new instance’s ' +- '"__init__()" method\n' +- ' will be invoked like "__init__(self[, ...])", where ' +- '*self* is the\n' +- ' new instance and the remaining arguments are the same as ' +- 'were\n' +- ' passed to the object constructor.\n' +- '\n' +- ' If "__new__()" does not return an instance of *cls*, ' +- 'then the new\n' +- ' instance’s "__init__()" method will not be invoked.\n' +- '\n' +- ' "__new__()" is intended mainly to allow subclasses of ' +- 'immutable\n' +- ' types (like int, str, or tuple) to customize instance ' +- 'creation. It\n' +- ' is also commonly overridden in custom metaclasses in ' +- 'order to\n' +- ' customize class creation.\n' +- '\n' +- 'object.__init__(self[, ...])\n' +- '\n' +- ' Called after the instance has been created (by ' +- '"__new__()"), but\n' +- ' before it is returned to the caller. The arguments are ' +- 'those\n' +- ' passed to the class constructor expression. If a base ' +- 'class has an\n' +- ' "__init__()" method, the derived class’s "__init__()" ' +- 'method, if\n' +- ' any, must explicitly call it to ensure proper ' +- 'initialization of the\n' +- ' base class part of the instance; for example:\n' +- ' "super().__init__([args...])".\n' +- '\n' +- ' Because "__new__()" and "__init__()" work together in ' +- 'constructing\n' +- ' objects ("__new__()" to create it, and "__init__()" to ' +- 'customize\n' +- ' it), no non-"None" value may be returned by ' +- '"__init__()"; doing so\n' +- ' will cause a "TypeError" to be raised at runtime.\n' +- '\n' +- 'object.__del__(self)\n' +- '\n' +- ' Called when the instance is about to be destroyed. This ' +- 'is also\n' +- ' called a finalizer or (improperly) a destructor. If a ' +- 'base class\n' +- ' has a "__del__()" method, the derived class’s ' +- '"__del__()" method,\n' +- ' if any, must explicitly call it to ensure proper ' +- 'deletion of the\n' +- ' base class part of the instance.\n' +- '\n' +- ' It is possible (though not recommended!) for the ' +- '"__del__()" method\n' +- ' to postpone destruction of the instance by creating a ' +- 'new reference\n' +- ' to it. This is called object *resurrection*. It is\n' +- ' implementation-dependent whether "__del__()" is called a ' +- 'second\n' +- ' time when a resurrected object is about to be destroyed; ' +- 'the\n' +- ' current *CPython* implementation only calls it once.\n' +- '\n' +- ' It is not guaranteed that "__del__()" methods are called ' +- 'for\n' +- ' objects that still exist when the interpreter exits.\n' +- ' "weakref.finalize" provides a straightforward way to ' +- 'register a\n' +- ' cleanup function to be called when an object is garbage ' +- 'collected.\n' +- '\n' +- ' Note:\n' +- '\n' +- ' "del x" doesn’t directly call "x.__del__()" — the ' +- 'former\n' +- ' decrements the reference count for "x" by one, and the ' +- 'latter is\n' +- ' only called when "x"’s reference count reaches zero.\n' +- '\n' +- ' **CPython implementation detail:** It is possible for a ' +- 'reference\n' +- ' cycle to prevent the reference count of an object from ' +- 'going to\n' +- ' zero. In this case, the cycle will be later detected ' +- 'and deleted\n' +- ' by the *cyclic garbage collector*. A common cause of ' +- 'reference\n' +- ' cycles is when an exception has been caught in a local ' +- 'variable.\n' +- ' The frame’s locals then reference the exception, which ' +- 'references\n' +- ' its own traceback, which references the locals of all ' +- 'frames caught\n' +- ' in the traceback.\n' +- '\n' +- ' See also: Documentation for the "gc" module.\n' +- '\n' +- ' Warning:\n' +- '\n' +- ' Due to the precarious circumstances under which ' +- '"__del__()"\n' +- ' methods are invoked, exceptions that occur during ' +- 'their execution\n' +- ' are ignored, and a warning is printed to "sys.stderr" ' +- 'instead.\n' +- ' In particular:\n' +- '\n' +- ' * "__del__()" can be invoked when arbitrary code is ' +- 'being\n' +- ' executed, including from any arbitrary thread. If ' +- '"__del__()"\n' +- ' needs to take a lock or invoke any other blocking ' +- 'resource, it\n' +- ' may deadlock as the resource may already be taken by ' +- 'the code\n' +- ' that gets interrupted to execute "__del__()".\n' +- '\n' +- ' * "__del__()" can be executed during interpreter ' +- 'shutdown. As a\n' +- ' consequence, the global variables it needs to access ' +- '(including\n' +- ' other modules) may already have been deleted or set ' +- 'to "None".\n' +- ' Python guarantees that globals whose name begins ' +- 'with a single\n' +- ' underscore are deleted from their module before ' +- 'other globals\n' +- ' are deleted; if no other references to such globals ' +- 'exist, this\n' +- ' may help in assuring that imported modules are still ' +- 'available\n' +- ' at the time when the "__del__()" method is called.\n' +- '\n' +- 'object.__repr__(self)\n' +- '\n' +- ' Called by the "repr()" built-in function to compute the ' +- '“officialâ€\n' +- ' string representation of an object. If at all possible, ' +- 'this\n' +- ' should look like a valid Python expression that could be ' +- 'used to\n' +- ' recreate an object with the same value (given an ' +- 'appropriate\n' +- ' environment). If this is not possible, a string of the ' +- 'form\n' +- ' "<...some useful description...>" should be returned. ' +- 'The return\n' +- ' value must be a string object. If a class defines ' +- '"__repr__()" but\n' +- ' not "__str__()", then "__repr__()" is also used when an ' +- '“informalâ€\n' +- ' string representation of instances of that class is ' +- 'required.\n' +- '\n' +- ' This is typically used for debugging, so it is important ' +- 'that the\n' +- ' representation is information-rich and unambiguous. A ' +- 'default\n' +- ' implementation is provided by the "object" class ' +- 'itself.\n' +- '\n' +- 'object.__str__(self)\n' +- '\n' +- ' Called by "str(object)", the default "__format__()" ' +- 'implementation,\n' +- ' and the built-in function "print()", to compute the ' +- '“informal†or\n' +- ' nicely printable string representation of an object. ' +- 'The return\n' +- ' value must be a str object.\n' +- '\n' +- ' This method differs from "object.__repr__()" in that ' +- 'there is no\n' +- ' expectation that "__str__()" return a valid Python ' +- 'expression: a\n' +- ' more convenient or concise representation can be used.\n' +- '\n' +- ' The default implementation defined by the built-in type ' +- '"object"\n' +- ' calls "object.__repr__()".\n' +- '\n' +- 'object.__bytes__(self)\n' +- '\n' +- ' Called by bytes to compute a byte-string representation ' +- 'of an\n' +- ' object. This should return a "bytes" object. The ' +- '"object" class\n' +- ' itself does not provide this method.\n' +- '\n' +- 'object.__format__(self, format_spec)\n' +- '\n' +- ' Called by the "format()" built-in function, and by ' +- 'extension,\n' +- ' evaluation of formatted string literals and the ' +- '"str.format()"\n' +- ' method, to produce a “formatted†string representation ' +- 'of an\n' +- ' object. The *format_spec* argument is a string that ' +- 'contains a\n' +- ' description of the formatting options desired. The ' +- 'interpretation\n' +- ' of the *format_spec* argument is up to the type ' +- 'implementing\n' +- ' "__format__()", however most classes will either ' +- 'delegate\n' +- ' formatting to one of the built-in types, or use a ' +- 'similar\n' +- ' formatting option syntax.\n' +- '\n' +- ' See Format Specification Mini-Language for a description ' +- 'of the\n' +- ' standard formatting syntax.\n' +- '\n' +- ' The return value must be a string object.\n' +- '\n' +- ' The default implementation by the "object" class should ' +- 'be given an\n' +- ' empty *format_spec* string. It delegates to ' +- '"__str__()".\n' +- '\n' +- ' Changed in version 3.4: The __format__ method of ' +- '"object" itself\n' +- ' raises a "TypeError" if passed any non-empty string.\n' +- '\n' +- ' Changed in version 3.7: "object.__format__(x, \'\')" is ' +- 'now\n' +- ' equivalent to "str(x)" rather than "format(str(x), ' +- '\'\')".\n' +- '\n' +- 'object.__lt__(self, other)\n' +- 'object.__le__(self, other)\n' +- 'object.__eq__(self, other)\n' +- 'object.__ne__(self, other)\n' +- 'object.__gt__(self, other)\n' +- 'object.__ge__(self, other)\n' +- '\n' +- ' These are the so-called “rich comparison†methods. The\n' +- ' correspondence between operator symbols and method names ' +- 'is as\n' +- ' follows: "xy" calls\n' +- ' "x.__gt__(y)", and "x>=y" calls "x.__ge__(y)".\n' +- '\n' +- ' A rich comparison method may return the singleton ' +- '"NotImplemented"\n' +- ' if it does not implement the operation for a given pair ' +- 'of\n' +- ' arguments. By convention, "False" and "True" are ' +- 'returned for a\n' +- ' successful comparison. However, these methods can return ' +- 'any value,\n' +- ' so if the comparison operator is used in a Boolean ' +- 'context (e.g.,\n' +- ' in the condition of an "if" statement), Python will call ' +- '"bool()"\n' +- ' on the value to determine if the result is true or ' +- 'false.\n' +- '\n' +- ' By default, "object" implements "__eq__()" by using ' +- '"is", returning\n' +- ' "NotImplemented" in the case of a false comparison: ' +- '"True if x is y\n' +- ' else NotImplemented". For "__ne__()", by default it ' +- 'delegates to\n' +- ' "__eq__()" and inverts the result unless it is ' +- '"NotImplemented".\n' +- ' There are no other implied relationships among the ' +- 'comparison\n' +- ' operators or default implementations; for example, the ' +- 'truth of\n' +- ' "(x.__hash__".\n' +- '\n' +- ' If a class that does not override "__eq__()" wishes to ' +- 'suppress\n' +- ' hash support, it should include "__hash__ = None" in the ' +- 'class\n' +- ' definition. A class which defines its own "__hash__()" ' +- 'that\n' +- ' explicitly raises a "TypeError" would be incorrectly ' +- 'identified as\n' +- ' hashable by an "isinstance(obj, ' +- 'collections.abc.Hashable)" call.\n' +- '\n' +- ' Note:\n' +- '\n' +- ' By default, the "__hash__()" values of str and bytes ' +- 'objects are\n' +- ' “salted†with an unpredictable random value. Although ' +- 'they\n' +- ' remain constant within an individual Python process, ' +- 'they are not\n' +- ' predictable between repeated invocations of ' +- 'Python.This is\n' +- ' intended to provide protection against a ' +- 'denial-of-service caused\n' +- ' by carefully chosen inputs that exploit the worst ' +- 'case\n' +- ' performance of a dict insertion, *O*(*n*^2) ' +- 'complexity. See\n' +- ' http://ocert.org/advisories/ocert-2011-003.html for\n' +- ' details.Changing hash values affects the iteration ' +- 'order of sets.\n' +- ' Python has never made guarantees about this ordering ' +- '(and it\n' +- ' typically varies between 32-bit and 64-bit builds).See ' +- 'also\n' +- ' "PYTHONHASHSEED".\n' +- '\n' +- ' Changed in version 3.3: Hash randomization is enabled by ' +- 'default.\n' +- '\n' +- 'object.__bool__(self)\n' +- '\n' +- ' Called to implement truth value testing and the built-in ' +- 'operation\n' +- ' "bool()"; should return "False" or "True". When this ' +- 'method is not\n' +- ' defined, "__len__()" is called, if it is defined, and ' +- 'the object is\n' +- ' considered true if its result is nonzero. If a class ' +- 'defines\n' +- ' neither "__len__()" nor "__bool__()" (which is true of ' +- 'the "object"\n' +- ' class itself), all its instances are considered true.\n', +- 'debugger': '"pdb" — The Python Debugger\n' +- '***************************\n' +- '\n' +- '**Source code:** Lib/pdb.py\n' +- '\n' +- '======================================================================\n' +- '\n' +- 'The module "pdb" defines an interactive source code debugger ' +- 'for\n' +- 'Python programs. It supports setting (conditional) breakpoints ' +- 'and\n' +- 'single stepping at the source line level, inspection of stack ' +- 'frames,\n' +- 'source code listing, and evaluation of arbitrary Python code in ' +- 'the\n' +- 'context of any stack frame. It also supports post-mortem ' +- 'debugging\n' +- 'and can be called under program control.\n' +- '\n' +- 'The debugger is extensible – it is actually defined as the ' +- 'class\n' +- '"Pdb". This is currently undocumented but easily understood by ' +- 'reading\n' +- 'the source. The extension interface uses the modules "bdb" and ' +- '"cmd".\n' +- '\n' +- 'See also:\n' +- '\n' +- ' Module "faulthandler"\n' +- ' Used to dump Python tracebacks explicitly, on a fault, ' +- 'after a\n' +- ' timeout, or on a user signal.\n' +- '\n' +- ' Module "traceback"\n' +- ' Standard interface to extract, format and print stack ' +- 'traces of\n' +- ' Python programs.\n' +- '\n' +- 'The typical usage to break into the debugger is to insert:\n' +- '\n' +- ' import pdb; pdb.set_trace()\n' +- '\n' +- 'Or:\n' +- '\n' +- ' breakpoint()\n' +- '\n' +- 'at the location you want to break into the debugger, and then ' +- 'run the\n' +- 'program. You can then step through the code following this ' +- 'statement,\n' +- 'and continue running without the debugger using the "continue"\n' +- 'command.\n' +- '\n' +- 'Changed in version 3.7: The built-in "breakpoint()", when called ' +- 'with\n' +- 'defaults, can be used instead of "import pdb; pdb.set_trace()".\n' +- '\n' +- ' def double(x):\n' +- ' breakpoint()\n' +- ' return x * 2\n' +- ' val = 3\n' +- ' print(f"{val} * 2 is {double(val)}")\n' +- '\n' +- 'The debugger’s prompt is "(Pdb)", which is the indicator that ' +- 'you are\n' +- 'in debug mode:\n' +- '\n' +- ' > ...(2)double()\n' +- ' -> breakpoint()\n' +- ' (Pdb) p x\n' +- ' 3\n' +- ' (Pdb) continue\n' +- ' 3 * 2 is 6\n' +- '\n' +- 'Changed in version 3.3: Tab-completion via the "readline" module ' +- 'is\n' +- 'available for commands and command arguments, e.g. the current ' +- 'global\n' +- 'and local names are offered as arguments of the "p" command.\n' +- '\n' +- 'You can also invoke "pdb" from the command line to debug other\n' +- 'scripts. For example:\n' +- '\n' +- ' python -m pdb myscript.py\n' +- '\n' +- 'When invoked as a module, pdb will automatically enter ' +- 'post-mortem\n' +- 'debugging if the program being debugged exits abnormally. After ' +- 'post-\n' +- 'mortem debugging (or after normal exit of the program), pdb ' +- 'will\n' +- 'restart the program. Automatic restarting preserves pdb’s state ' +- '(such\n' +- 'as breakpoints) and in most cases is more useful than quitting ' +- 'the\n' +- 'debugger upon program’s exit.\n' +- '\n' +- 'Changed in version 3.2: Added the "-c" option to execute ' +- 'commands as\n' +- 'if given in a ".pdbrc" file; see Debugger Commands.\n' +- '\n' +- 'Changed in version 3.7: Added the "-m" option to execute ' +- 'modules\n' +- 'similar to the way "python -m" does. As with a script, the ' +- 'debugger\n' +- 'will pause execution just before the first line of the module.\n' +- '\n' +- 'Typical usage to execute a statement under control of the ' +- 'debugger is:\n' +- '\n' +- ' >>> import pdb\n' +- ' >>> def f(x):\n' +- ' ... print(1 / x)\n' +- ' >>> pdb.run("f(2)")\n' +- ' > (1)()\n' +- ' (Pdb) continue\n' +- ' 0.5\n' +- ' >>>\n' +- '\n' +- 'The typical usage to inspect a crashed program is:\n' +- '\n' +- ' >>> import pdb\n' +- ' >>> def f(x):\n' +- ' ... print(1 / x)\n' +- ' ...\n' +- ' >>> f(0)\n' +- ' Traceback (most recent call last):\n' +- ' File "", line 1, in \n' +- ' File "", line 2, in f\n' +- ' ZeroDivisionError: division by zero\n' +- ' >>> pdb.pm()\n' +- ' > (2)f()\n' +- ' (Pdb) p x\n' +- ' 0\n' +- ' (Pdb)\n' +- '\n' +- 'Changed in version 3.13: The implementation of **PEP 667** means ' +- 'that\n' +- 'name assignments made via "pdb" will immediately affect the ' +- 'active\n' +- 'scope, even when running inside an *optimized scope*.\n' +- '\n' +- 'The module defines the following functions; each enters the ' +- 'debugger\n' +- 'in a slightly different way:\n' +- '\n' +- 'pdb.run(statement, globals=None, locals=None)\n' +- '\n' +- ' Execute the *statement* (given as a string or a code object) ' +- 'under\n' +- ' debugger control. The debugger prompt appears before any ' +- 'code is\n' +- ' executed; you can set breakpoints and type "continue", or you ' +- 'can\n' +- ' step through the statement using "step" or "next" (all these\n' +- ' commands are explained below). The optional *globals* and ' +- '*locals*\n' +- ' arguments specify the environment in which the code is ' +- 'executed; by\n' +- ' default the dictionary of the module "__main__" is used. ' +- '(See the\n' +- ' explanation of the built-in "exec()" or "eval()" functions.)\n' +- '\n' +- 'pdb.runeval(expression, globals=None, locals=None)\n' +- '\n' +- ' Evaluate the *expression* (given as a string or a code ' +- 'object)\n' +- ' under debugger control. When "runeval()" returns, it returns ' +- 'the\n' +- ' value of the *expression*. Otherwise this function is ' +- 'similar to\n' +- ' "run()".\n' +- '\n' +- 'pdb.runcall(function, *args, **kwds)\n' +- '\n' +- ' Call the *function* (a function or method object, not a ' +- 'string)\n' +- ' with the given arguments. When "runcall()" returns, it ' +- 'returns\n' +- ' whatever the function call returned. The debugger prompt ' +- 'appears\n' +- ' as soon as the function is entered.\n' +- '\n' +- 'pdb.set_trace(*, header=None, commands=None)\n' +- '\n' +- ' Enter the debugger at the calling stack frame. This is ' +- 'useful to\n' +- ' hard-code a breakpoint at a given point in a program, even if ' +- 'the\n' +- ' code is not otherwise being debugged (e.g. when an assertion\n' +- ' fails). If given, *header* is printed to the console just ' +- 'before\n' +- ' debugging begins. The *commands* argument, if given, is a ' +- 'list of\n' +- ' commands to execute when the debugger starts.\n' +- '\n' +- ' Changed in version 3.7: The keyword-only argument *header*.\n' +- '\n' +- ' Changed in version 3.13: "set_trace()" will enter the ' +- 'debugger\n' +- ' immediately, rather than on the next line of code to be ' +- 'executed.\n' +- '\n' +- ' Added in version 3.14: The *commands* argument.\n' +- '\n' +- 'pdb.post_mortem(traceback=None)\n' +- '\n' +- ' Enter post-mortem debugging of the given *traceback* object. ' +- 'If no\n' +- ' *traceback* is given, it uses the one of the exception that ' +- 'is\n' +- ' currently being handled (an exception must be being handled ' +- 'if the\n' +- ' default is to be used).\n' +- '\n' +- 'pdb.pm()\n' +- '\n' +- ' Enter post-mortem debugging of the exception found in\n' +- ' "sys.last_exc".\n' +- '\n' +- 'The "run*" functions and "set_trace()" are aliases for ' +- 'instantiating\n' +- 'the "Pdb" class and calling the method of the same name. If you ' +- 'want\n' +- 'to access further features, you have to do this yourself:\n' +- '\n' +- "class pdb.Pdb(completekey='tab', stdin=None, stdout=None, " +- 'skip=None, nosigint=False, readrc=True, mode=None)\n' +- '\n' +- ' "Pdb" is the debugger class.\n' +- '\n' +- ' The *completekey*, *stdin* and *stdout* arguments are passed ' +- 'to the\n' +- ' underlying "cmd.Cmd" class; see the description there.\n' +- '\n' +- ' The *skip* argument, if given, must be an iterable of ' +- 'glob-style\n' +- ' module name patterns. The debugger will not step into frames ' +- 'that\n' +- ' originate in a module that matches one of these patterns. ' +- '[1]\n' +- '\n' +- ' By default, Pdb sets a handler for the SIGINT signal (which ' +- 'is sent\n' +- ' when the user presses "Ctrl-C" on the console) when you give ' +- 'a\n' +- ' "continue" command. This allows you to break into the ' +- 'debugger\n' +- ' again by pressing "Ctrl-C". If you want Pdb not to touch ' +- 'the\n' +- ' SIGINT handler, set *nosigint* to true.\n' +- '\n' +- ' The *readrc* argument defaults to true and controls whether ' +- 'Pdb\n' +- ' will load .pdbrc files from the filesystem.\n' +- '\n' +- ' The *mode* argument specifies how the debugger was invoked. ' +- 'It\n' +- ' impacts the workings of some debugger commands. Valid values ' +- 'are\n' +- ' "\'inline\'" (used by the breakpoint() builtin), "\'cli\'" ' +- '(used by the\n' +- ' command line invocation) or "None" (for backwards compatible\n' +- ' behaviour, as before the *mode* argument was added).\n' +- '\n' +- ' Example call to enable tracing with *skip*:\n' +- '\n' +- " import pdb; pdb.Pdb(skip=['django.*']).set_trace()\n" +- '\n' +- ' Raises an auditing event "pdb.Pdb" with no arguments.\n' +- '\n' +- ' Changed in version 3.1: Added the *skip* parameter.\n' +- '\n' +- ' Changed in version 3.2: Added the *nosigint* parameter. ' +- 'Previously,\n' +- ' a SIGINT handler was never set by Pdb.\n' +- '\n' +- ' Changed in version 3.6: The *readrc* argument.\n' +- '\n' +- ' Added in version 3.14: Added the *mode* argument.\n' +- '\n' +- ' run(statement, globals=None, locals=None)\n' +- ' runeval(expression, globals=None, locals=None)\n' +- ' runcall(function, *args, **kwds)\n' +- ' set_trace()\n' +- '\n' +- ' See the documentation for the functions explained above.\n' +- '\n' +- '\n' +- 'Debugger Commands\n' +- '=================\n' +- '\n' +- 'The commands recognized by the debugger are listed below. Most\n' +- 'commands can be abbreviated to one or two letters as indicated; ' +- 'e.g.\n' +- '"h(elp)" means that either "h" or "help" can be used to enter ' +- 'the help\n' +- 'command (but not "he" or "hel", nor "H" or "Help" or "HELP").\n' +- 'Arguments to commands must be separated by whitespace (spaces ' +- 'or\n' +- 'tabs). Optional arguments are enclosed in square brackets ' +- '("[]") in\n' +- 'the command syntax; the square brackets must not be typed.\n' +- 'Alternatives in the command syntax are separated by a vertical ' +- 'bar\n' +- '("|").\n' +- '\n' +- 'Entering a blank line repeats the last command entered. ' +- 'Exception: if\n' +- 'the last command was a "list" command, the next 11 lines are ' +- 'listed.\n' +- '\n' +- 'Commands that the debugger doesn’t recognize are assumed to be ' +- 'Python\n' +- 'statements and are executed in the context of the program being\n' +- 'debugged. Python statements can also be prefixed with an ' +- 'exclamation\n' +- 'point ("!"). This is a powerful way to inspect the program ' +- 'being\n' +- 'debugged; it is even possible to change a variable or call a ' +- 'function.\n' +- 'When an exception occurs in such a statement, the exception name ' +- 'is\n' +- 'printed but the debugger’s state is not changed.\n' +- '\n' +- 'Changed in version 3.13: Expressions/Statements whose prefix is ' +- 'a pdb\n' +- 'command are now correctly identified and executed.\n' +- '\n' +- 'The debugger supports aliases. Aliases can have parameters ' +- 'which\n' +- 'allows one a certain level of adaptability to the context under\n' +- 'examination.\n' +- '\n' +- 'Multiple commands may be entered on a single line, separated by ' +- '";;".\n' +- '(A single ";" is not used as it is the separator for multiple ' +- 'commands\n' +- 'in a line that is passed to the Python parser.) No intelligence ' +- 'is\n' +- 'applied to separating the commands; the input is split at the ' +- 'first\n' +- '";;" pair, even if it is in the middle of a quoted string. A\n' +- 'workaround for strings with double semicolons is to use ' +- 'implicit\n' +- 'string concatenation "\';\'\';\'" or "";"";"".\n' +- '\n' +- 'To set a temporary global variable, use a *convenience ' +- 'variable*. A\n' +- '*convenience variable* is a variable whose name starts with ' +- '"$". For\n' +- 'example, "$foo = 1" sets a global variable "$foo" which you can ' +- 'use in\n' +- 'the debugger session. The *convenience variables* are cleared ' +- 'when\n' +- 'the program resumes execution so it’s less likely to interfere ' +- 'with\n' +- 'your program compared to using normal variables like "foo = 1".\n' +- '\n' +- 'There are three preset *convenience variables*:\n' +- '\n' +- '* "$_frame": the current frame you are debugging\n' +- '\n' +- '* "$_retval": the return value if the frame is returning\n' +- '\n' +- '* "$_exception": the exception if the frame is raising an ' +- 'exception\n' +- '\n' +- 'Added in version 3.12: Added the *convenience variable* ' +- 'feature.\n' +- '\n' +- 'If a file ".pdbrc" exists in the user’s home directory or in ' +- 'the\n' +- 'current directory, it is read with "\'utf-8\'" encoding and ' +- 'executed as\n' +- 'if it had been typed at the debugger prompt, with the exception ' +- 'that\n' +- 'empty lines and lines starting with "#" are ignored. This is\n' +- 'particularly useful for aliases. If both files exist, the one ' +- 'in the\n' +- 'home directory is read first and aliases defined there can be\n' +- 'overridden by the local file.\n' +- '\n' +- 'Changed in version 3.2: ".pdbrc" can now contain commands that\n' +- 'continue debugging, such as "continue" or "next". Previously, ' +- 'these\n' +- 'commands had no effect.\n' +- '\n' +- 'Changed in version 3.11: ".pdbrc" is now read with "\'utf-8\'" ' +- 'encoding.\n' +- 'Previously, it was read with the system locale encoding.\n' +- '\n' +- 'h(elp) [command]\n' +- '\n' +- ' Without argument, print the list of available commands. With ' +- 'a\n' +- ' *command* as argument, print help about that command. "help ' +- 'pdb"\n' +- ' displays the full documentation (the docstring of the "pdb"\n' +- ' module). Since the *command* argument must be an identifier, ' +- '"help\n' +- ' exec" must be entered to get help on the "!" command.\n' +- '\n' +- 'w(here) [count]\n' +- '\n' +- ' Print a stack trace, with the most recent frame at the ' +- 'bottom. if\n' +- ' *count* is 0, print the current frame entry. If *count* is\n' +- ' negative, print the least recent - *count* frames. If *count* ' +- 'is\n' +- ' positive, print the most recent *count* frames. An arrow ' +- '(">")\n' +- ' indicates the current frame, which determines the context of ' +- 'most\n' +- ' commands.\n' +- '\n' +- ' Changed in version 3.14: *count* argument is added.\n' +- '\n' +- 'd(own) [count]\n' +- '\n' +- ' Move the current frame *count* (default one) levels down in ' +- 'the\n' +- ' stack trace (to a newer frame).\n' +- '\n' +- 'u(p) [count]\n' +- '\n' +- ' Move the current frame *count* (default one) levels up in the ' +- 'stack\n' +- ' trace (to an older frame).\n' +- '\n' +- 'b(reak) [([filename:]lineno | function) [, condition]]\n' +- '\n' +- ' With a *lineno* argument, set a break at line *lineno* in ' +- 'the\n' +- ' current file. The line number may be prefixed with a ' +- '*filename* and\n' +- ' a colon, to specify a breakpoint in another file (possibly ' +- 'one that\n' +- ' hasn’t been loaded yet). The file is searched on ' +- '"sys.path".\n' +- ' Acceptable forms of *filename* are "/abspath/to/file.py",\n' +- ' "relpath/file.py", "module" and "package.module".\n' +- '\n' +- ' With a *function* argument, set a break at the first ' +- 'executable\n' +- ' statement within that function. *function* can be any ' +- 'expression\n' +- ' that evaluates to a function in the current namespace.\n' +- '\n' +- ' If a second argument is present, it is an expression which ' +- 'must\n' +- ' evaluate to true before the breakpoint is honored.\n' +- '\n' +- ' Without argument, list all breaks, including for each ' +- 'breakpoint,\n' +- ' the number of times that breakpoint has been hit, the ' +- 'current\n' +- ' ignore count, and the associated condition if any.\n' +- '\n' +- ' Each breakpoint is assigned a number to which all the other\n' +- ' breakpoint commands refer.\n' +- '\n' +- 'tbreak [([filename:]lineno | function) [, condition]]\n' +- '\n' +- ' Temporary breakpoint, which is removed automatically when it ' +- 'is\n' +- ' first hit. The arguments are the same as for "break".\n' +- '\n' +- 'cl(ear) [filename:lineno | bpnumber ...]\n' +- '\n' +- ' With a *filename:lineno* argument, clear all the breakpoints ' +- 'at\n' +- ' this line. With a space separated list of breakpoint numbers, ' +- 'clear\n' +- ' those breakpoints. Without argument, clear all breaks (but ' +- 'first\n' +- ' ask confirmation).\n' +- '\n' +- 'disable bpnumber [bpnumber ...]\n' +- '\n' +- ' Disable the breakpoints given as a space separated list of\n' +- ' breakpoint numbers. Disabling a breakpoint means it cannot ' +- 'cause\n' +- ' the program to stop execution, but unlike clearing a ' +- 'breakpoint, it\n' +- ' remains in the list of breakpoints and can be (re-)enabled.\n' +- '\n' +- 'enable bpnumber [bpnumber ...]\n' +- '\n' +- ' Enable the breakpoints specified.\n' +- '\n' +- 'ignore bpnumber [count]\n' +- '\n' +- ' Set the ignore count for the given breakpoint number. If ' +- '*count*\n' +- ' is omitted, the ignore count is set to 0. A breakpoint ' +- 'becomes\n' +- ' active when the ignore count is zero. When non-zero, the ' +- '*count*\n' +- ' is decremented each time the breakpoint is reached and the\n' +- ' breakpoint is not disabled and any associated condition ' +- 'evaluates\n' +- ' to true.\n' +- '\n' +- 'condition bpnumber [condition]\n' +- '\n' +- ' Set a new *condition* for the breakpoint, an expression which ' +- 'must\n' +- ' evaluate to true before the breakpoint is honored. If ' +- '*condition*\n' +- ' is absent, any existing condition is removed; i.e., the ' +- 'breakpoint\n' +- ' is made unconditional.\n' +- '\n' +- 'commands [bpnumber]\n' +- '\n' +- ' Specify a list of commands for breakpoint number *bpnumber*. ' +- 'The\n' +- ' commands themselves appear on the following lines. Type a ' +- 'line\n' +- ' containing just "end" to terminate the commands. An example:\n' +- '\n' +- ' (Pdb) commands 1\n' +- ' (com) p some_variable\n' +- ' (com) end\n' +- ' (Pdb)\n' +- '\n' +- ' To remove all commands from a breakpoint, type "commands" ' +- 'and\n' +- ' follow it immediately with "end"; that is, give no commands.\n' +- '\n' +- ' With no *bpnumber* argument, "commands" refers to the last\n' +- ' breakpoint set.\n' +- '\n' +- ' You can use breakpoint commands to start your program up ' +- 'again.\n' +- ' Simply use the "continue" command, or "step", or any other ' +- 'command\n' +- ' that resumes execution.\n' +- '\n' +- ' Specifying any command resuming execution (currently ' +- '"continue",\n' +- ' "step", "next", "return", "until", "jump", "quit" and their\n' +- ' abbreviations) terminates the command list (as if that ' +- 'command was\n' +- ' immediately followed by end). This is because any time you ' +- 'resume\n' +- ' execution (even with a simple next or step), you may ' +- 'encounter\n' +- ' another breakpoint—which could have its own command list, ' +- 'leading\n' +- ' to ambiguities about which list to execute.\n' +- '\n' +- ' If the list of commands contains the "silent" command, or a ' +- 'command\n' +- ' that resumes execution, then the breakpoint message ' +- 'containing\n' +- ' information about the frame is not displayed.\n' +- '\n' +- ' Changed in version 3.14: Frame information will not be ' +- 'displayed if\n' +- ' a command that resumes execution is present in the command ' +- 'list.\n' +- '\n' +- 's(tep)\n' +- '\n' +- ' Execute the current line, stop at the first possible ' +- 'occasion\n' +- ' (either in a function that is called or on the next line in ' +- 'the\n' +- ' current function).\n' +- '\n' +- 'n(ext)\n' +- '\n' +- ' Continue execution until the next line in the current ' +- 'function is\n' +- ' reached or it returns. (The difference between "next" and ' +- '"step"\n' +- ' is that "step" stops inside a called function, while "next"\n' +- ' executes called functions at (nearly) full speed, only ' +- 'stopping at\n' +- ' the next line in the current function.)\n' +- '\n' +- 'unt(il) [lineno]\n' +- '\n' +- ' Without argument, continue execution until the line with a ' +- 'number\n' +- ' greater than the current one is reached.\n' +- '\n' +- ' With *lineno*, continue execution until a line with a number\n' +- ' greater or equal to *lineno* is reached. In both cases, also ' +- 'stop\n' +- ' when the current frame returns.\n' +- '\n' +- ' Changed in version 3.2: Allow giving an explicit line ' +- 'number.\n' +- '\n' +- 'r(eturn)\n' +- '\n' +- ' Continue execution until the current function returns.\n' +- '\n' +- 'c(ont(inue))\n' +- '\n' +- ' Continue execution, only stop when a breakpoint is ' +- 'encountered.\n' +- '\n' +- 'j(ump) lineno\n' +- '\n' +- ' Set the next line that will be executed. Only available in ' +- 'the\n' +- ' bottom-most frame. This lets you jump back and execute code ' +- 'again,\n' +- ' or jump forward to skip code that you don’t want to run.\n' +- '\n' +- ' It should be noted that not all jumps are allowed – for ' +- 'instance it\n' +- ' is not possible to jump into the middle of a "for" loop or ' +- 'out of a\n' +- ' "finally" clause.\n' +- '\n' +- 'l(ist) [first[, last]]\n' +- '\n' +- ' List source code for the current file. Without arguments, ' +- 'list 11\n' +- ' lines around the current line or continue the previous ' +- 'listing.\n' +- ' With "." as argument, list 11 lines around the current line. ' +- 'With\n' +- ' one argument, list 11 lines around at that line. With two\n' +- ' arguments, list the given range; if the second argument is ' +- 'less\n' +- ' than the first, it is interpreted as a count.\n' +- '\n' +- ' The current line in the current frame is indicated by "->". ' +- 'If an\n' +- ' exception is being debugged, the line where the exception ' +- 'was\n' +- ' originally raised or propagated is indicated by ">>", if it ' +- 'differs\n' +- ' from the current line.\n' +- '\n' +- ' Changed in version 3.2: Added the ">>" marker.\n' +- '\n' +- 'll | longlist\n' +- '\n' +- ' List all source code for the current function or frame.\n' +- ' Interesting lines are marked as for "list".\n' +- '\n' +- ' Added in version 3.2.\n' +- '\n' +- 'a(rgs)\n' +- '\n' +- ' Print the arguments of the current function and their ' +- 'current\n' +- ' values.\n' +- '\n' +- 'p expression\n' +- '\n' +- ' Evaluate *expression* in the current context and print its ' +- 'value.\n' +- '\n' +- ' Note:\n' +- '\n' +- ' "print()" can also be used, but is not a debugger command — ' +- 'this\n' +- ' executes the Python "print()" function.\n' +- '\n' +- 'pp expression\n' +- '\n' +- ' Like the "p" command, except the value of *expression* is ' +- 'pretty-\n' +- ' printed using the "pprint" module.\n' +- '\n' +- 'whatis expression\n' +- '\n' +- ' Print the type of *expression*.\n' +- '\n' +- 'source expression\n' +- '\n' +- ' Try to get source code of *expression* and display it.\n' +- '\n' +- ' Added in version 3.2.\n' +- '\n' +- 'display [expression]\n' +- '\n' +- ' Display the value of *expression* if it changed, each time\n' +- ' execution stops in the current frame.\n' +- '\n' +- ' Without *expression*, list all display expressions for the ' +- 'current\n' +- ' frame.\n' +- '\n' +- ' Note:\n' +- '\n' +- ' Display evaluates *expression* and compares to the result ' +- 'of the\n' +- ' previous evaluation of *expression*, so when the result is\n' +- ' mutable, display may not be able to pick up the changes.\n' +- '\n' +- ' Example:\n' +- '\n' +- ' lst = []\n' +- ' breakpoint()\n' +- ' pass\n' +- ' lst.append(1)\n' +- ' print(lst)\n' +- '\n' +- ' Display won’t realize "lst" has been changed because the ' +- 'result of\n' +- ' evaluation is modified in place by "lst.append(1)" before ' +- 'being\n' +- ' compared:\n' +- '\n' +- ' > example.py(3)()\n' +- ' -> pass\n' +- ' (Pdb) display lst\n' +- ' display lst: []\n' +- ' (Pdb) n\n' +- ' > example.py(4)()\n' +- ' -> lst.append(1)\n' +- ' (Pdb) n\n' +- ' > example.py(5)()\n' +- ' -> print(lst)\n' +- ' (Pdb)\n' +- '\n' +- ' You can do some tricks with copy mechanism to make it work:\n' +- '\n' +- ' > example.py(3)()\n' +- ' -> pass\n' +- ' (Pdb) display lst[:]\n' +- ' display lst[:]: []\n' +- ' (Pdb) n\n' +- ' > example.py(4)()\n' +- ' -> lst.append(1)\n' +- ' (Pdb) n\n' +- ' > example.py(5)()\n' +- ' -> print(lst)\n' +- ' display lst[:]: [1] [old: []]\n' +- ' (Pdb)\n' +- '\n' +- ' Added in version 3.2.\n' +- '\n' +- 'undisplay [expression]\n' +- '\n' +- ' Do not display *expression* anymore in the current frame. ' +- 'Without\n' +- ' *expression*, clear all display expressions for the current ' +- 'frame.\n' +- '\n' +- ' Added in version 3.2.\n' +- '\n' +- 'interact\n' +- '\n' +- ' Start an interactive interpreter (using the "code" module) in ' +- 'a new\n' +- ' global namespace initialised from the local and global ' +- 'namespaces\n' +- ' for the current scope. Use "exit()" or "quit()" to exit the\n' +- ' interpreter and return to the debugger.\n' +- '\n' +- ' Note:\n' +- '\n' +- ' As "interact" creates a new dedicated namespace for code\n' +- ' execution, assignments to variables will not affect the ' +- 'original\n' +- ' namespaces. However, modifications to any referenced ' +- 'mutable\n' +- ' objects will be reflected in the original namespaces as ' +- 'usual.\n' +- '\n' +- ' Added in version 3.2.\n' +- '\n' +- ' Changed in version 3.13: "exit()" and "quit()" can be used to ' +- 'exit\n' +- ' the "interact" command.\n' +- '\n' +- ' Changed in version 3.13: "interact" directs its output to ' +- 'the\n' +- ' debugger’s output channel rather than "sys.stderr".\n' +- '\n' +- 'alias [name [command]]\n' +- '\n' +- ' Create an alias called *name* that executes *command*. The\n' +- ' *command* must *not* be enclosed in quotes. Replaceable ' +- 'parameters\n' +- ' can be indicated by "%1", "%2", … and "%9", while "%*" is ' +- 'replaced\n' +- ' by all the parameters. If *command* is omitted, the current ' +- 'alias\n' +- ' for *name* is shown. If no arguments are given, all aliases ' +- 'are\n' +- ' listed.\n' +- '\n' +- ' Aliases may be nested and can contain anything that can be ' +- 'legally\n' +- ' typed at the pdb prompt. Note that internal pdb commands ' +- '*can* be\n' +- ' overridden by aliases. Such a command is then hidden until ' +- 'the\n' +- ' alias is removed. Aliasing is recursively applied to the ' +- 'first\n' +- ' word of the command line; all other words in the line are ' +- 'left\n' +- ' alone.\n' +- '\n' +- ' As an example, here are two useful aliases (especially when ' +- 'placed\n' +- ' in the ".pdbrc" file):\n' +- '\n' +- ' # Print instance variables (usage "pi classInst")\n' +- ' alias pi for k in %1.__dict__.keys(): print(f"%1.{k} = ' +- '{%1.__dict__[k]}")\n' +- ' # Print instance variables in self\n' +- ' alias ps pi self\n' +- '\n' +- 'unalias name\n' +- '\n' +- ' Delete the specified alias *name*.\n' +- '\n' +- '! statement\n' +- '\n' +- ' Execute the (one-line) *statement* in the context of the ' +- 'current\n' +- ' stack frame. The exclamation point can be omitted unless the ' +- 'first\n' +- ' word of the statement resembles a debugger command, e.g.:\n' +- '\n' +- ' (Pdb) ! n=42\n' +- ' (Pdb)\n' +- '\n' +- ' To set a global variable, you can prefix the assignment ' +- 'command\n' +- ' with a "global" statement on the same line, e.g.:\n' +- '\n' +- " (Pdb) global list_options; list_options = ['-l']\n" +- ' (Pdb)\n' +- '\n' +- 'run [args ...]\n' +- 'restart [args ...]\n' +- '\n' +- ' Restart the debugged Python program. If *args* is supplied, ' +- 'it is\n' +- ' split with "shlex" and the result is used as the new ' +- '"sys.argv".\n' +- ' History, breakpoints, actions and debugger options are ' +- 'preserved.\n' +- ' "restart" is an alias for "run".\n' +- '\n' +- ' Changed in version 3.14: "run" and "restart" commands are ' +- 'disabled\n' +- ' when the debugger is invoked in "\'inline\'" mode.\n' +- '\n' +- 'q(uit)\n' +- '\n' +- ' Quit from the debugger. The program being executed is ' +- 'aborted.\n' +- '\n' +- 'debug code\n' +- '\n' +- ' Enter a recursive debugger that steps through *code* (which ' +- 'is an\n' +- ' arbitrary expression or statement to be executed in the ' +- 'current\n' +- ' environment).\n' +- '\n' +- 'retval\n' +- '\n' +- ' Print the return value for the last return of the current ' +- 'function.\n' +- '\n' +- 'exceptions [excnumber]\n' +- '\n' +- ' List or jump between chained exceptions.\n' +- '\n' +- ' When using "pdb.pm()" or "Pdb.post_mortem(...)" with a ' +- 'chained\n' +- ' exception instead of a traceback, it allows the user to move\n' +- ' between the chained exceptions using "exceptions" command to ' +- 'list\n' +- ' exceptions, and "exception " to switch to that ' +- 'exception.\n' +- '\n' +- ' Example:\n' +- '\n' +- ' def out():\n' +- ' try:\n' +- ' middle()\n' +- ' except Exception as e:\n' +- ' raise ValueError("reraise middle() error") from e\n' +- '\n' +- ' def middle():\n' +- ' try:\n' +- ' return inner(0)\n' +- ' except Exception as e:\n' +- ' raise ValueError("Middle fail")\n' +- '\n' +- ' def inner(x):\n' +- ' 1 / x\n' +- '\n' +- ' out()\n' +- '\n' +- ' calling "pdb.pm()" will allow to move between exceptions:\n' +- '\n' +- ' > example.py(5)out()\n' +- ' -> raise ValueError("reraise middle() error") from e\n' +- '\n' +- ' (Pdb) exceptions\n' +- " 0 ZeroDivisionError('division by zero')\n" +- " 1 ValueError('Middle fail')\n" +- " > 2 ValueError('reraise middle() error')\n" +- '\n' +- ' (Pdb) exceptions 0\n' +- ' > example.py(16)inner()\n' +- ' -> 1 / x\n' +- '\n' +- ' (Pdb) up\n' +- ' > example.py(10)middle()\n' +- ' -> return inner(0)\n' +- '\n' +- ' Added in version 3.13.\n' +- '\n' +- '-[ Footnotes ]-\n' +- '\n' +- '[1] Whether a frame is considered to originate in a certain ' +- 'module is\n' +- ' determined by the "__name__" in the frame globals.\n', +- 'del': 'The "del" statement\n' +- '*******************\n' +- '\n' +- ' del_stmt ::= "del" target_list\n' +- '\n' +- 'Deletion is recursively defined very similar to the way assignment ' +- 'is\n' +- 'defined. Rather than spelling it out in full details, here are some\n' +- 'hints.\n' +- '\n' +- 'Deletion of a target list recursively deletes each target, from left\n' +- 'to right.\n' +- '\n' +- 'Deletion of a name removes the binding of that name from the local ' +- 'or\n' +- 'global namespace, depending on whether the name occurs in a "global"\n' +- 'statement in the same code block. If the name is unbound, a\n' +- '"NameError" exception will be raised.\n' +- '\n' +- 'Deletion of attribute references, subscriptions and slicings is ' +- 'passed\n' +- 'to the primary object involved; deletion of a slicing is in general\n' +- 'equivalent to assignment of an empty slice of the right type (but ' +- 'even\n' +- 'this is determined by the sliced object).\n' +- '\n' +- 'Changed in version 3.2: Previously it was illegal to delete a name\n' +- 'from the local namespace if it occurs as a free variable in a nested\n' +- 'block.\n', +- 'dict': 'Dictionary displays\n' +- '*******************\n' +- '\n' +- 'A dictionary display is a possibly empty series of dict items\n' +- '(key/value pairs) enclosed in curly braces:\n' +- '\n' +- ' dict_display ::= "{" [dict_item_list | dict_comprehension] ' +- '"}"\n' +- ' dict_item_list ::= dict_item ("," dict_item)* [","]\n' +- ' dict_item ::= expression ":" expression | "**" or_expr\n' +- ' dict_comprehension ::= expression ":" expression comp_for\n' +- '\n' +- 'A dictionary display yields a new dictionary object.\n' +- '\n' +- 'If a comma-separated sequence of dict items is given, they are\n' +- 'evaluated from left to right to define the entries of the ' +- 'dictionary:\n' +- 'each key object is used as a key into the dictionary to store the\n' +- 'corresponding value. This means that you can specify the same key\n' +- 'multiple times in the dict item list, and the final dictionary’s ' +- 'value\n' +- 'for that key will be the last one given.\n' +- '\n' +- 'A double asterisk "**" denotes *dictionary unpacking*. Its operand\n' +- 'must be a *mapping*. Each mapping item is added to the new\n' +- 'dictionary. Later values replace values already set by earlier ' +- 'dict\n' +- 'items and earlier dictionary unpackings.\n' +- '\n' +- 'Added in version 3.5: Unpacking into dictionary displays, ' +- 'originally\n' +- 'proposed by **PEP 448**.\n' +- '\n' +- 'A dict comprehension, in contrast to list and set comprehensions,\n' +- 'needs two expressions separated with a colon followed by the usual\n' +- '“for†and “if†clauses. When the comprehension is run, the ' +- 'resulting\n' +- 'key and value elements are inserted in the new dictionary in the ' +- 'order\n' +- 'they are produced.\n' +- '\n' +- 'Restrictions on the types of the key values are listed earlier in\n' +- 'section The standard type hierarchy. (To summarize, the key type\n' +- 'should be *hashable*, which excludes all mutable objects.) Clashes\n' +- 'between duplicate keys are not detected; the last value (textually\n' +- 'rightmost in the display) stored for a given key value prevails.\n' +- '\n' +- 'Changed in version 3.8: Prior to Python 3.8, in dict ' +- 'comprehensions,\n' +- 'the evaluation order of key and value was not well-defined. In\n' +- 'CPython, the value was evaluated before the key. Starting with ' +- '3.8,\n' +- 'the key is evaluated before the value, as proposed by **PEP 572**.\n', +- 'dynamic-features': 'Interaction with dynamic features\n' +- '*********************************\n' +- '\n' +- 'Name resolution of free variables occurs at runtime, not ' +- 'at compile\n' +- 'time. This means that the following code will print 42:\n' +- '\n' +- ' i = 10\n' +- ' def f():\n' +- ' print(i)\n' +- ' i = 42\n' +- ' f()\n' +- '\n' +- 'The "eval()" and "exec()" functions do not have access ' +- 'to the full\n' +- 'environment for resolving names. Names may be resolved ' +- 'in the local\n' +- 'and global namespaces of the caller. Free variables are ' +- 'not resolved\n' +- 'in the nearest enclosing namespace, but in the global ' +- 'namespace. [1]\n' +- 'The "exec()" and "eval()" functions have optional ' +- 'arguments to\n' +- 'override the global and local namespace. If only one ' +- 'namespace is\n' +- 'specified, it is used for both.\n', +- 'else': 'The "if" statement\n' +- '******************\n' +- '\n' +- 'The "if" statement is used for conditional execution:\n' +- '\n' +- ' if_stmt ::= "if" assignment_expression ":" suite\n' +- ' ("elif" assignment_expression ":" suite)*\n' +- ' ["else" ":" suite]\n' +- '\n' +- 'It selects exactly one of the suites by evaluating the expressions ' +- 'one\n' +- 'by one until one is found to be true (see section Boolean ' +- 'operations\n' +- 'for the definition of true and false); then that suite is executed\n' +- '(and no other part of the "if" statement is executed or evaluated).\n' +- 'If all expressions are false, the suite of the "else" clause, if\n' +- 'present, is executed.\n', +- 'exceptions': 'Exceptions\n' +- '**********\n' +- '\n' +- 'Exceptions are a means of breaking out of the normal flow of ' +- 'control\n' +- 'of a code block in order to handle errors or other ' +- 'exceptional\n' +- 'conditions. An exception is *raised* at the point where the ' +- 'error is\n' +- 'detected; it may be *handled* by the surrounding code block or ' +- 'by any\n' +- 'code block that directly or indirectly invoked the code block ' +- 'where\n' +- 'the error occurred.\n' +- '\n' +- 'The Python interpreter raises an exception when it detects a ' +- 'run-time\n' +- 'error (such as division by zero). A Python program can also\n' +- 'explicitly raise an exception with the "raise" statement. ' +- 'Exception\n' +- 'handlers are specified with the "try" … "except" statement. ' +- 'The\n' +- '"finally" clause of such a statement can be used to specify ' +- 'cleanup\n' +- 'code which does not handle the exception, but is executed ' +- 'whether an\n' +- 'exception occurred or not in the preceding code.\n' +- '\n' +- 'Python uses the “termination†model of error handling: an ' +- 'exception\n' +- 'handler can find out what happened and continue execution at ' +- 'an outer\n' +- 'level, but it cannot repair the cause of the error and retry ' +- 'the\n' +- 'failing operation (except by re-entering the offending piece ' +- 'of code\n' +- 'from the top).\n' +- '\n' +- 'When an exception is not handled at all, the interpreter ' +- 'terminates\n' +- 'execution of the program, or returns to its interactive main ' +- 'loop. In\n' +- 'either case, it prints a stack traceback, except when the ' +- 'exception is\n' +- '"SystemExit".\n' +- '\n' +- 'Exceptions are identified by class instances. The "except" ' +- 'clause is\n' +- 'selected depending on the class of the instance: it must ' +- 'reference the\n' +- 'class of the instance or a *non-virtual base class* thereof. ' +- 'The\n' +- 'instance can be received by the handler and can carry ' +- 'additional\n' +- 'information about the exceptional condition.\n' +- '\n' +- 'Note:\n' +- '\n' +- ' Exception messages are not part of the Python API. Their ' +- 'contents\n' +- ' may change from one version of Python to the next without ' +- 'warning\n' +- ' and should not be relied on by code which will run under ' +- 'multiple\n' +- ' versions of the interpreter.\n' +- '\n' +- 'See also the description of the "try" statement in section The ' +- 'try\n' +- 'statement and "raise" statement in section The raise ' +- 'statement.\n' +- '\n' +- '-[ Footnotes ]-\n' +- '\n' +- '[1] This limitation occurs because the code that is executed ' +- 'by these\n' +- ' operations is not available at the time the module is ' +- 'compiled.\n', +- 'execmodel': 'Execution model\n' +- '***************\n' +- '\n' +- '\n' +- 'Structure of a program\n' +- '======================\n' +- '\n' +- 'A Python program is constructed from code blocks. A *block* is ' +- 'a piece\n' +- 'of Python program text that is executed as a unit. The ' +- 'following are\n' +- 'blocks: a module, a function body, and a class definition. ' +- 'Each\n' +- 'command typed interactively is a block. A script file (a file ' +- 'given\n' +- 'as standard input to the interpreter or specified as a command ' +- 'line\n' +- 'argument to the interpreter) is a code block. A script command ' +- '(a\n' +- 'command specified on the interpreter command line with the ' +- '"-c"\n' +- 'option) is a code block. A module run as a top level script (as ' +- 'module\n' +- '"__main__") from the command line using a "-m" argument is also ' +- 'a code\n' +- 'block. The string argument passed to the built-in functions ' +- '"eval()"\n' +- 'and "exec()" is a code block.\n' +- '\n' +- 'A code block is executed in an *execution frame*. A frame ' +- 'contains\n' +- 'some administrative information (used for debugging) and ' +- 'determines\n' +- 'where and how execution continues after the code block’s ' +- 'execution has\n' +- 'completed.\n' +- '\n' +- '\n' +- 'Naming and binding\n' +- '==================\n' +- '\n' +- '\n' +- 'Binding of names\n' +- '----------------\n' +- '\n' +- '*Names* refer to objects. Names are introduced by name ' +- 'binding\n' +- 'operations.\n' +- '\n' +- 'The following constructs bind names:\n' +- '\n' +- '* formal parameters to functions,\n' +- '\n' +- '* class definitions,\n' +- '\n' +- '* function definitions,\n' +- '\n' +- '* assignment expressions,\n' +- '\n' +- '* targets that are identifiers if occurring in an assignment:\n' +- '\n' +- ' * "for" loop header,\n' +- '\n' +- ' * after "as" in a "with" statement, "except" clause, ' +- '"except*"\n' +- ' clause, or in the as-pattern in structural pattern ' +- 'matching,\n' +- '\n' +- ' * in a capture pattern in structural pattern matching\n' +- '\n' +- '* "import" statements.\n' +- '\n' +- '* "type" statements.\n' +- '\n' +- '* type parameter lists.\n' +- '\n' +- 'The "import" statement of the form "from ... import *" binds ' +- 'all names\n' +- 'defined in the imported module, except those beginning with an\n' +- 'underscore. This form may only be used at the module level.\n' +- '\n' +- 'A target occurring in a "del" statement is also considered ' +- 'bound for\n' +- 'this purpose (though the actual semantics are to unbind the ' +- 'name).\n' +- '\n' +- 'Each assignment or import statement occurs within a block ' +- 'defined by a\n' +- 'class or function definition or at the module level (the ' +- 'top-level\n' +- 'code block).\n' +- '\n' +- 'If a name is bound in a block, it is a local variable of that ' +- 'block,\n' +- 'unless declared as "nonlocal" or "global". If a name is bound ' +- 'at the\n' +- 'module level, it is a global variable. (The variables of the ' +- 'module\n' +- 'code block are local and global.) If a variable is used in a ' +- 'code\n' +- 'block but not defined there, it is a *free variable*.\n' +- '\n' +- 'Each occurrence of a name in the program text refers to the ' +- '*binding*\n' +- 'of that name established by the following name resolution ' +- 'rules.\n' +- '\n' +- '\n' +- 'Resolution of names\n' +- '-------------------\n' +- '\n' +- 'A *scope* defines the visibility of a name within a block. If ' +- 'a local\n' +- 'variable is defined in a block, its scope includes that block. ' +- 'If the\n' +- 'definition occurs in a function block, the scope extends to any ' +- 'blocks\n' +- 'contained within the defining one, unless a contained block ' +- 'introduces\n' +- 'a different binding for the name.\n' +- '\n' +- 'When a name is used in a code block, it is resolved using the ' +- 'nearest\n' +- 'enclosing scope. The set of all such scopes visible to a code ' +- 'block\n' +- 'is called the block’s *environment*.\n' +- '\n' +- 'When a name is not found at all, a "NameError" exception is ' +- 'raised. If\n' +- 'the current scope is a function scope, and the name refers to a ' +- 'local\n' +- 'variable that has not yet been bound to a value at the point ' +- 'where the\n' +- 'name is used, an "UnboundLocalError" exception is raised.\n' +- '"UnboundLocalError" is a subclass of "NameError".\n' +- '\n' +- 'If a name binding operation occurs anywhere within a code ' +- 'block, all\n' +- 'uses of the name within the block are treated as references to ' +- 'the\n' +- 'current block. This can lead to errors when a name is used ' +- 'within a\n' +- 'block before it is bound. This rule is subtle. Python lacks\n' +- 'declarations and allows name binding operations to occur ' +- 'anywhere\n' +- 'within a code block. The local variables of a code block can ' +- 'be\n' +- 'determined by scanning the entire text of the block for name ' +- 'binding\n' +- 'operations. See the FAQ entry on UnboundLocalError for ' +- 'examples.\n' +- '\n' +- 'If the "global" statement occurs within a block, all uses of ' +- 'the names\n' +- 'specified in the statement refer to the bindings of those names ' +- 'in the\n' +- 'top-level namespace. Names are resolved in the top-level ' +- 'namespace by\n' +- 'searching the global namespace, i.e. the namespace of the ' +- 'module\n' +- 'containing the code block, and the builtins namespace, the ' +- 'namespace\n' +- 'of the module "builtins". The global namespace is searched ' +- 'first. If\n' +- 'the names are not found there, the builtins namespace is ' +- 'searched\n' +- 'next. If the names are also not found in the builtins ' +- 'namespace, new\n' +- 'variables are created in the global namespace. The global ' +- 'statement\n' +- 'must precede all uses of the listed names.\n' +- '\n' +- 'The "global" statement has the same scope as a name binding ' +- 'operation\n' +- 'in the same block. If the nearest enclosing scope for a free ' +- 'variable\n' +- 'contains a global statement, the free variable is treated as a ' +- 'global.\n' +- '\n' +- 'The "nonlocal" statement causes corresponding names to refer ' +- 'to\n' +- 'previously bound variables in the nearest enclosing function ' +- 'scope.\n' +- '"SyntaxError" is raised at compile time if the given name does ' +- 'not\n' +- 'exist in any enclosing function scope. Type parameters cannot ' +- 'be\n' +- 'rebound with the "nonlocal" statement.\n' +- '\n' +- 'The namespace for a module is automatically created the first ' +- 'time a\n' +- 'module is imported. The main module for a script is always ' +- 'called\n' +- '"__main__".\n' +- '\n' +- 'Class definition blocks and arguments to "exec()" and "eval()" ' +- 'are\n' +- 'special in the context of name resolution. A class definition ' +- 'is an\n' +- 'executable statement that may use and define names. These ' +- 'references\n' +- 'follow the normal rules for name resolution with an exception ' +- 'that\n' +- 'unbound local variables are looked up in the global namespace. ' +- 'The\n' +- 'namespace of the class definition becomes the attribute ' +- 'dictionary of\n' +- 'the class. The scope of names defined in a class block is ' +- 'limited to\n' +- 'the class block; it does not extend to the code blocks of ' +- 'methods.\n' +- 'This includes comprehensions and generator expressions, but it ' +- 'does\n' +- 'not include annotation scopes, which have access to their ' +- 'enclosing\n' +- 'class scopes. This means that the following will fail:\n' +- '\n' +- ' class A:\n' +- ' a = 42\n' +- ' b = list(a + i for i in range(10))\n' +- '\n' +- 'However, the following will succeed:\n' +- '\n' +- ' class A:\n' +- ' type Alias = Nested\n' +- ' class Nested: pass\n' +- '\n' +- " print(A.Alias.__value__) # \n" +- '\n' +- '\n' +- 'Annotation scopes\n' +- '-----------------\n' +- '\n' +- '*Annotations*, type parameter lists and "type" statements ' +- 'introduce\n' +- '*annotation scopes*, which behave mostly like function scopes, ' +- 'but\n' +- 'with some exceptions discussed below.\n' +- '\n' +- 'Annotation scopes are used in the following contexts:\n' +- '\n' +- '* *Function annotations*.\n' +- '\n' +- '* *Variable annotations*.\n' +- '\n' +- '* Type parameter lists for generic type aliases.\n' +- '\n' +- '* Type parameter lists for generic functions. A generic ' +- 'function’s\n' +- ' annotations are executed within the annotation scope, but ' +- 'its\n' +- ' defaults and decorators are not.\n' +- '\n' +- '* Type parameter lists for generic classes. A generic class’s ' +- 'base\n' +- ' classes and keyword arguments are executed within the ' +- 'annotation\n' +- ' scope, but its decorators are not.\n' +- '\n' +- '* The bounds, constraints, and default values for type ' +- 'parameters\n' +- ' (lazily evaluated).\n' +- '\n' +- '* The value of type aliases (lazily evaluated).\n' +- '\n' +- 'Annotation scopes differ from function scopes in the following ' +- 'ways:\n' +- '\n' +- '* Annotation scopes have access to their enclosing class ' +- 'namespace. If\n' +- ' an annotation scope is immediately within a class scope, or ' +- 'within\n' +- ' another annotation scope that is immediately within a class ' +- 'scope,\n' +- ' the code in the annotation scope can use names defined in the ' +- 'class\n' +- ' scope as if it were executed directly within the class body. ' +- 'This\n' +- ' contrasts with regular functions defined within classes, ' +- 'which\n' +- ' cannot access names defined in the class scope.\n' +- '\n' +- '* Expressions in annotation scopes cannot contain "yield", ' +- '"yield\n' +- ' from", "await", or ":=" expressions. (These expressions are ' +- 'allowed\n' +- ' in other scopes contained within the annotation scope.)\n' +- '\n' +- '* Names defined in annotation scopes cannot be rebound with ' +- '"nonlocal"\n' +- ' statements in inner scopes. This includes only type ' +- 'parameters, as\n' +- ' no other syntactic elements that can appear within annotation ' +- 'scopes\n' +- ' can introduce new names.\n' +- '\n' +- '* While annotation scopes have an internal name, that name is ' +- 'not\n' +- ' reflected in the *qualified name* of objects defined within ' +- 'the\n' +- ' scope. Instead, the "__qualname__" of such objects is as if ' +- 'the\n' +- ' object were defined in the enclosing scope.\n' +- '\n' +- 'Added in version 3.12: Annotation scopes were introduced in ' +- 'Python\n' +- '3.12 as part of **PEP 695**.\n' +- '\n' +- 'Changed in version 3.13: Annotation scopes are also used for ' +- 'type\n' +- 'parameter defaults, as introduced by **PEP 696**.\n' +- '\n' +- 'Changed in version 3.14: Annotation scopes are now also used ' +- 'for\n' +- 'annotations, as specified in **PEP 649** and **PEP 749**.\n' +- '\n' +- '\n' +- 'Lazy evaluation\n' +- '---------------\n' +- '\n' +- 'Most annotation scopes are *lazily evaluated*. This includes\n' +- 'annotations, the values of type aliases created through the ' +- '"type"\n' +- 'statement, and the bounds, constraints, and default values of ' +- 'type\n' +- 'variables created through the type parameter syntax. This means ' +- 'that\n' +- 'they are not evaluated when the type alias or type variable is\n' +- 'created, or when the object carrying annotations is created. ' +- 'Instead,\n' +- 'they are only evaluated when necessary, for example when the\n' +- '"__value__" attribute on a type alias is accessed.\n' +- '\n' +- 'Example:\n' +- '\n' +- ' >>> type Alias = 1/0\n' +- ' >>> Alias.__value__\n' +- ' Traceback (most recent call last):\n' +- ' ...\n' +- ' ZeroDivisionError: division by zero\n' +- ' >>> def func[T: 1/0](): pass\n' +- ' >>> T = func.__type_params__[0]\n' +- ' >>> T.__bound__\n' +- ' Traceback (most recent call last):\n' +- ' ...\n' +- ' ZeroDivisionError: division by zero\n' +- '\n' +- 'Here the exception is raised only when the "__value__" ' +- 'attribute of\n' +- 'the type alias or the "__bound__" attribute of the type ' +- 'variable is\n' +- 'accessed.\n' +- '\n' +- 'This behavior is primarily useful for references to types that ' +- 'have\n' +- 'not yet been defined when the type alias or type variable is ' +- 'created.\n' +- 'For example, lazy evaluation enables creation of mutually ' +- 'recursive\n' +- 'type aliases:\n' +- '\n' +- ' from typing import Literal\n' +- '\n' +- ' type SimpleExpr = int | Parenthesized\n' +- ' type Parenthesized = tuple[Literal["("], Expr, ' +- 'Literal[")"]]\n' +- ' type Expr = SimpleExpr | tuple[SimpleExpr, Literal["+", ' +- '"-"], Expr]\n' +- '\n' +- 'Lazily evaluated values are evaluated in annotation scope, ' +- 'which means\n' +- 'that names that appear inside the lazily evaluated value are ' +- 'looked up\n' +- 'as if they were used in the immediately enclosing scope.\n' +- '\n' +- 'Added in version 3.12.\n' +- '\n' +- '\n' +- 'Builtins and restricted execution\n' +- '---------------------------------\n' +- '\n' +- '**CPython implementation detail:** Users should not touch\n' +- '"__builtins__"; it is strictly an implementation detail. ' +- 'Users\n' +- 'wanting to override values in the builtins namespace should ' +- '"import"\n' +- 'the "builtins" module and modify its attributes appropriately.\n' +- '\n' +- 'The builtins namespace associated with the execution of a code ' +- 'block\n' +- 'is actually found by looking up the name "__builtins__" in its ' +- 'global\n' +- 'namespace; this should be a dictionary or a module (in the ' +- 'latter case\n' +- 'the module’s dictionary is used). By default, when in the ' +- '"__main__"\n' +- 'module, "__builtins__" is the built-in module "builtins"; when ' +- 'in any\n' +- 'other module, "__builtins__" is an alias for the dictionary of ' +- 'the\n' +- '"builtins" module itself.\n' +- '\n' +- '\n' +- 'Interaction with dynamic features\n' +- '---------------------------------\n' +- '\n' +- 'Name resolution of free variables occurs at runtime, not at ' +- 'compile\n' +- 'time. This means that the following code will print 42:\n' +- '\n' +- ' i = 10\n' +- ' def f():\n' +- ' print(i)\n' +- ' i = 42\n' +- ' f()\n' +- '\n' +- 'The "eval()" and "exec()" functions do not have access to the ' +- 'full\n' +- 'environment for resolving names. Names may be resolved in the ' +- 'local\n' +- 'and global namespaces of the caller. Free variables are not ' +- 'resolved\n' +- 'in the nearest enclosing namespace, but in the global ' +- 'namespace. [1]\n' +- 'The "exec()" and "eval()" functions have optional arguments to\n' +- 'override the global and local namespace. If only one namespace ' +- 'is\n' +- 'specified, it is used for both.\n' +- '\n' +- '\n' +- 'Exceptions\n' +- '==========\n' +- '\n' +- 'Exceptions are a means of breaking out of the normal flow of ' +- 'control\n' +- 'of a code block in order to handle errors or other exceptional\n' +- 'conditions. An exception is *raised* at the point where the ' +- 'error is\n' +- 'detected; it may be *handled* by the surrounding code block or ' +- 'by any\n' +- 'code block that directly or indirectly invoked the code block ' +- 'where\n' +- 'the error occurred.\n' +- '\n' +- 'The Python interpreter raises an exception when it detects a ' +- 'run-time\n' +- 'error (such as division by zero). A Python program can also\n' +- 'explicitly raise an exception with the "raise" statement. ' +- 'Exception\n' +- 'handlers are specified with the "try" … "except" statement. ' +- 'The\n' +- '"finally" clause of such a statement can be used to specify ' +- 'cleanup\n' +- 'code which does not handle the exception, but is executed ' +- 'whether an\n' +- 'exception occurred or not in the preceding code.\n' +- '\n' +- 'Python uses the “termination†model of error handling: an ' +- 'exception\n' +- 'handler can find out what happened and continue execution at an ' +- 'outer\n' +- 'level, but it cannot repair the cause of the error and retry ' +- 'the\n' +- 'failing operation (except by re-entering the offending piece of ' +- 'code\n' +- 'from the top).\n' +- '\n' +- 'When an exception is not handled at all, the interpreter ' +- 'terminates\n' +- 'execution of the program, or returns to its interactive main ' +- 'loop. In\n' +- 'either case, it prints a stack traceback, except when the ' +- 'exception is\n' +- '"SystemExit".\n' +- '\n' +- 'Exceptions are identified by class instances. The "except" ' +- 'clause is\n' +- 'selected depending on the class of the instance: it must ' +- 'reference the\n' +- 'class of the instance or a *non-virtual base class* thereof. ' +- 'The\n' +- 'instance can be received by the handler and can carry ' +- 'additional\n' +- 'information about the exceptional condition.\n' +- '\n' +- 'Note:\n' +- '\n' +- ' Exception messages are not part of the Python API. Their ' +- 'contents\n' +- ' may change from one version of Python to the next without ' +- 'warning\n' +- ' and should not be relied on by code which will run under ' +- 'multiple\n' +- ' versions of the interpreter.\n' +- '\n' +- 'See also the description of the "try" statement in section The ' +- 'try\n' +- 'statement and "raise" statement in section The raise ' +- 'statement.\n' +- '\n' +- '-[ Footnotes ]-\n' +- '\n' +- '[1] This limitation occurs because the code that is executed by ' +- 'these\n' +- ' operations is not available at the time the module is ' +- 'compiled.\n', +- 'exprlists': 'Expression lists\n' +- '****************\n' +- '\n' +- ' starred_expression ::= ["*"] or_expr\n' +- ' flexible_expression ::= assignment_expression | ' +- 'starred_expression\n' +- ' flexible_expression_list ::= flexible_expression ("," ' +- 'flexible_expression)* [","]\n' +- ' starred_expression_list ::= starred_expression ("," ' +- 'starred_expression)* [","]\n' +- ' expression_list ::= expression ("," expression)* ' +- '[","]\n' +- ' yield_list ::= expression_list | ' +- 'starred_expression "," [starred_expression_list]\n' +- '\n' +- 'Except when part of a list or set display, an expression list\n' +- 'containing at least one comma yields a tuple. The length of ' +- 'the tuple\n' +- 'is the number of expressions in the list. The expressions are\n' +- 'evaluated from left to right.\n' +- '\n' +- 'An asterisk "*" denotes *iterable unpacking*. Its operand must ' +- 'be an\n' +- '*iterable*. The iterable is expanded into a sequence of items, ' +- 'which\n' +- 'are included in the new tuple, list, or set, at the site of ' +- 'the\n' +- 'unpacking.\n' +- '\n' +- 'Added in version 3.5: Iterable unpacking in expression lists,\n' +- 'originally proposed by **PEP 448**.\n' +- '\n' +- 'Added in version 3.11: Any item in an expression list may be ' +- 'starred.\n' +- 'See **PEP 646**.\n' +- '\n' +- 'A trailing comma is required only to create a one-item tuple, ' +- 'such as\n' +- '"1,"; it is optional in all other cases. A single expression ' +- 'without a\n' +- 'trailing comma doesn’t create a tuple, but rather yields the ' +- 'value of\n' +- 'that expression. (To create an empty tuple, use an empty pair ' +- 'of\n' +- 'parentheses: "()".)\n', +- 'floating': 'Floating-point literals\n' +- '***********************\n' +- '\n' +- 'Floating-point literals are described by the following lexical\n' +- 'definitions:\n' +- '\n' +- ' floatnumber ::= pointfloat | exponentfloat\n' +- ' pointfloat ::= [digitpart] fraction | digitpart "."\n' +- ' exponentfloat ::= (digitpart | pointfloat) exponent\n' +- ' digitpart ::= digit (["_"] digit)*\n' +- ' fraction ::= "." digitpart\n' +- ' exponent ::= ("e" | "E") ["+" | "-"] digitpart\n' +- '\n' +- 'Note that the integer and exponent parts are always interpreted ' +- 'using\n' +- 'radix 10. For example, "077e010" is legal, and denotes the same ' +- 'number\n' +- 'as "77e10". The allowed range of floating-point literals is\n' +- 'implementation-dependent. As in integer literals, underscores ' +- 'are\n' +- 'supported for digit grouping.\n' +- '\n' +- 'Some examples of floating-point literals:\n' +- '\n' +- ' 3.14 10. .001 1e100 3.14e-10 0e0 ' +- '3.14_15_93\n' +- '\n' +- 'Changed in version 3.6: Underscores are now allowed for ' +- 'grouping\n' +- 'purposes in literals.\n', +- 'for': 'The "for" statement\n' +- '*******************\n' +- '\n' +- 'The "for" statement is used to iterate over the elements of a ' +- 'sequence\n' +- '(such as a string, tuple or list) or other iterable object:\n' +- '\n' +- ' for_stmt ::= "for" target_list "in" starred_list ":" suite\n' +- ' ["else" ":" suite]\n' +- '\n' +- 'The "starred_list" expression is evaluated once; it should yield an\n' +- '*iterable* object. An *iterator* is created for that iterable. The\n' +- 'first item provided by the iterator is then assigned to the target\n' +- 'list using the standard rules for assignments (see Assignment\n' +- 'statements), and the suite is executed. This repeats for each item\n' +- 'provided by the iterator. When the iterator is exhausted, the suite\n' +- 'in the "else" clause, if present, is executed, and the loop\n' +- 'terminates.\n' +- '\n' +- 'A "break" statement executed in the first suite terminates the loop\n' +- 'without executing the "else" clause’s suite. A "continue" statement\n' +- 'executed in the first suite skips the rest of the suite and ' +- 'continues\n' +- 'with the next item, or with the "else" clause if there is no next\n' +- 'item.\n' +- '\n' +- 'The for-loop makes assignments to the variables in the target list.\n' +- 'This overwrites all previous assignments to those variables ' +- 'including\n' +- 'those made in the suite of the for-loop:\n' +- '\n' +- ' for i in range(10):\n' +- ' print(i)\n' +- ' i = 5 # this will not affect the for-loop\n' +- ' # because i will be overwritten with the ' +- 'next\n' +- ' # index in the range\n' +- '\n' +- 'Names in the target list are not deleted when the loop is finished,\n' +- 'but if the sequence is empty, they will not have been assigned to at\n' +- 'all by the loop. Hint: the built-in type "range()" represents\n' +- 'immutable arithmetic sequences of integers. For instance, iterating\n' +- '"range(3)" successively yields 0, 1, and then 2.\n' +- '\n' +- 'Changed in version 3.11: Starred elements are now allowed in the\n' +- 'expression list.\n', +- 'formatstrings': 'Format String Syntax\n' +- '********************\n' +- '\n' +- 'The "str.format()" method and the "Formatter" class share ' +- 'the same\n' +- 'syntax for format strings (although in the case of ' +- '"Formatter",\n' +- 'subclasses can define their own format string syntax). The ' +- 'syntax is\n' +- 'related to that of formatted string literals, but it is ' +- 'less\n' +- 'sophisticated and, in particular, does not support ' +- 'arbitrary\n' +- 'expressions.\n' +- '\n' +- 'Format strings contain “replacement fields†surrounded by ' +- 'curly braces\n' +- '"{}". Anything that is not contained in braces is ' +- 'considered literal\n' +- 'text, which is copied unchanged to the output. If you need ' +- 'to include\n' +- 'a brace character in the literal text, it can be escaped by ' +- 'doubling:\n' +- '"{{" and "}}".\n' +- '\n' +- 'The grammar for a replacement field is as follows:\n' +- '\n' +- ' replacement_field ::= "{" [field_name] ["!" conversion] ' +- '[":" format_spec] "}"\n' +- ' field_name ::= arg_name ("." attribute_name | "[" ' +- 'element_index "]")*\n' +- ' arg_name ::= [identifier | digit+]\n' +- ' attribute_name ::= identifier\n' +- ' element_index ::= digit+ | index_string\n' +- ' index_string ::= ' +- '+\n' +- ' conversion ::= "r" | "s" | "a"\n' +- ' format_spec ::= format-spec:format_spec\n' +- '\n' +- 'In less formal terms, the replacement field can start with ' +- 'a\n' +- '*field_name* that specifies the object whose value is to be ' +- 'formatted\n' +- 'and inserted into the output instead of the replacement ' +- 'field. The\n' +- '*field_name* is optionally followed by a *conversion* ' +- 'field, which is\n' +- 'preceded by an exclamation point "\'!\'", and a ' +- '*format_spec*, which is\n' +- 'preceded by a colon "\':\'". These specify a non-default ' +- 'format for the\n' +- 'replacement value.\n' +- '\n' +- 'See also the Format Specification Mini-Language section.\n' +- '\n' +- 'The *field_name* itself begins with an *arg_name* that is ' +- 'either a\n' +- 'number or a keyword. If it’s a number, it refers to a ' +- 'positional\n' +- 'argument, and if it’s a keyword, it refers to a named ' +- 'keyword\n' +- 'argument. An *arg_name* is treated as a number if a call ' +- 'to\n' +- '"str.isdecimal()" on the string would return true. If the ' +- 'numerical\n' +- 'arg_names in a format string are 0, 1, 2, … in sequence, ' +- 'they can all\n' +- 'be omitted (not just some) and the numbers 0, 1, 2, … will ' +- 'be\n' +- 'automatically inserted in that order. Because *arg_name* is ' +- 'not quote-\n' +- 'delimited, it is not possible to specify arbitrary ' +- 'dictionary keys\n' +- '(e.g., the strings "\'10\'" or "\':-]\'") within a format ' +- 'string. The\n' +- '*arg_name* can be followed by any number of index or ' +- 'attribute\n' +- 'expressions. An expression of the form "\'.name\'" selects ' +- 'the named\n' +- 'attribute using "getattr()", while an expression of the ' +- 'form\n' +- '"\'[index]\'" does an index lookup using "__getitem__()".\n' +- '\n' +- 'Changed in version 3.1: The positional argument specifiers ' +- 'can be\n' +- 'omitted for "str.format()", so "\'{} {}\'.format(a, b)" is ' +- 'equivalent to\n' +- '"\'{0} {1}\'.format(a, b)".\n' +- '\n' +- 'Changed in version 3.4: The positional argument specifiers ' +- 'can be\n' +- 'omitted for "Formatter".\n' +- '\n' +- 'Some simple format string examples:\n' +- '\n' +- ' "First, thou shalt count to {0}" # References first ' +- 'positional argument\n' +- ' "Bring me a {}" # Implicitly ' +- 'references the first positional argument\n' +- ' "From {} to {}" # Same as "From {0} to ' +- '{1}"\n' +- ' "My quest is {name}" # References keyword ' +- "argument 'name'\n" +- ' "Weight in tons {0.weight}" # \'weight\' attribute ' +- 'of first positional arg\n' +- ' "Units destroyed: {players[0]}" # First element of ' +- "keyword argument 'players'.\n" +- '\n' +- 'The *conversion* field causes a type coercion before ' +- 'formatting.\n' +- 'Normally, the job of formatting a value is done by the ' +- '"__format__()"\n' +- 'method of the value itself. However, in some cases it is ' +- 'desirable to\n' +- 'force a type to be formatted as a string, overriding its ' +- 'own\n' +- 'definition of formatting. By converting the value to a ' +- 'string before\n' +- 'calling "__format__()", the normal formatting logic is ' +- 'bypassed.\n' +- '\n' +- 'Three conversion flags are currently supported: "\'!s\'" ' +- 'which calls\n' +- '"str()" on the value, "\'!r\'" which calls "repr()" and ' +- '"\'!a\'" which\n' +- 'calls "ascii()".\n' +- '\n' +- 'Some examples:\n' +- '\n' +- ' "Harold\'s a clever {0!s}" # Calls str() on the ' +- 'argument first\n' +- ' "Bring out the holy {name!r}" # Calls repr() on the ' +- 'argument first\n' +- ' "More {!a}" # Calls ascii() on the ' +- 'argument first\n' +- '\n' +- 'The *format_spec* field contains a specification of how the ' +- 'value\n' +- 'should be presented, including such details as field width, ' +- 'alignment,\n' +- 'padding, decimal precision and so on. Each value type can ' +- 'define its\n' +- 'own “formatting mini-language†or interpretation of the ' +- '*format_spec*.\n' +- '\n' +- 'Most built-in types support a common formatting ' +- 'mini-language, which\n' +- 'is described in the next section.\n' +- '\n' +- 'A *format_spec* field can also include nested replacement ' +- 'fields\n' +- 'within it. These nested replacement fields may contain a ' +- 'field name,\n' +- 'conversion flag and format specification, but deeper ' +- 'nesting is not\n' +- 'allowed. The replacement fields within the format_spec ' +- 'are\n' +- 'substituted before the *format_spec* string is interpreted. ' +- 'This\n' +- 'allows the formatting of a value to be dynamically ' +- 'specified.\n' +- '\n' +- 'See the Format examples section for some examples.\n' +- '\n' +- '\n' +- 'Format Specification Mini-Language\n' +- '==================================\n' +- '\n' +- '“Format specifications†are used within replacement fields ' +- 'contained\n' +- 'within a format string to define how individual values are ' +- 'presented\n' +- '(see Format String Syntax and f-strings). They can also be ' +- 'passed\n' +- 'directly to the built-in "format()" function. Each ' +- 'formattable type\n' +- 'may define how the format specification is to be ' +- 'interpreted.\n' +- '\n' +- 'Most built-in types implement the following options for ' +- 'format\n' +- 'specifications, although some of the formatting options are ' +- 'only\n' +- 'supported by the numeric types.\n' +- '\n' +- 'A general convention is that an empty format specification ' +- 'produces\n' +- 'the same result as if you had called "str()" on the value. ' +- 'A non-empty\n' +- 'format specification typically modifies the result.\n' +- '\n' +- 'The general form of a *standard format specifier* is:\n' +- '\n' +- ' format_spec ::= ' +- '[[fill]align][sign]["z"]["#"]["0"][width][grouping_option]["." ' +- 'precision][type]\n' +- ' fill ::= \n' +- ' align ::= "<" | ">" | "=" | "^"\n' +- ' sign ::= "+" | "-" | " "\n' +- ' width ::= digit+\n' +- ' grouping_option ::= "_" | ","\n' +- ' precision ::= digit+\n' +- ' type ::= "b" | "c" | "d" | "e" | "E" | "f" | ' +- '"F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"\n' +- '\n' +- 'If a valid *align* value is specified, it can be preceded ' +- 'by a *fill*\n' +- 'character that can be any character and defaults to a space ' +- 'if\n' +- 'omitted. It is not possible to use a literal curly brace ' +- '(â€"{"†or\n' +- '“"}"â€) as the *fill* character in a formatted string ' +- 'literal or when\n' +- 'using the "str.format()" method. However, it is possible ' +- 'to insert a\n' +- 'curly brace with a nested replacement field. This ' +- 'limitation doesn’t\n' +- 'affect the "format()" function.\n' +- '\n' +- 'The meaning of the various alignment options is as ' +- 'follows:\n' +- '\n' +- '+-----------+------------------------------------------------------------+\n' +- '| Option | ' +- 'Meaning ' +- '|\n' +- '|===========|============================================================|\n' +- '| "\'<\'" | Forces the field to be left-aligned within ' +- 'the available |\n' +- '| | space (this is the default for most ' +- 'objects). |\n' +- '+-----------+------------------------------------------------------------+\n' +- '| "\'>\'" | Forces the field to be right-aligned within ' +- 'the available |\n' +- '| | space (this is the default for ' +- 'numbers). |\n' +- '+-----------+------------------------------------------------------------+\n' +- '| "\'=\'" | Forces the padding to be placed after the ' +- 'sign (if any) |\n' +- '| | but before the digits. This is used for ' +- 'printing fields |\n' +- '| | in the form ‘+000000120’. This alignment ' +- 'option is only |\n' +- '| | valid for numeric types, excluding "complex". ' +- 'It becomes |\n' +- '| | the default for numbers when ‘0’ immediately ' +- 'precedes the |\n' +- '| | field ' +- 'width. |\n' +- '+-----------+------------------------------------------------------------+\n' +- '| "\'^\'" | Forces the field to be centered within the ' +- 'available |\n' +- '| | ' +- 'space. ' +- '|\n' +- '+-----------+------------------------------------------------------------+\n' +- '\n' +- 'Note that unless a minimum field width is defined, the ' +- 'field width\n' +- 'will always be the same size as the data to fill it, so ' +- 'that the\n' +- 'alignment option has no meaning in this case.\n' +- '\n' +- 'The *sign* option is only valid for number types, and can ' +- 'be one of\n' +- 'the following:\n' +- '\n' +- '+-----------+------------------------------------------------------------+\n' +- '| Option | ' +- 'Meaning ' +- '|\n' +- '|===========|============================================================|\n' +- '| "\'+\'" | indicates that a sign should be used for ' +- 'both positive as |\n' +- '| | well as negative ' +- 'numbers. |\n' +- '+-----------+------------------------------------------------------------+\n' +- '| "\'-\'" | indicates that a sign should be used only ' +- 'for negative |\n' +- '| | numbers (this is the default ' +- 'behavior). |\n' +- '+-----------+------------------------------------------------------------+\n' +- '| space | indicates that a leading space should be used ' +- 'on positive |\n' +- '| | numbers, and a minus sign on negative ' +- 'numbers. |\n' +- '+-----------+------------------------------------------------------------+\n' +- '\n' +- 'The "\'z\'" option coerces negative zero floating-point ' +- 'values to\n' +- 'positive zero after rounding to the format precision. This ' +- 'option is\n' +- 'only valid for floating-point presentation types.\n' +- '\n' +- 'Changed in version 3.11: Added the "\'z\'" option (see also ' +- '**PEP\n' +- '682**).\n' +- '\n' +- 'The "\'#\'" option causes the “alternate form†to be used ' +- 'for the\n' +- 'conversion. The alternate form is defined differently for ' +- 'different\n' +- 'types. This option is only valid for integer, float and ' +- 'complex\n' +- 'types. For integers, when binary, octal, or hexadecimal ' +- 'output is\n' +- 'used, this option adds the respective prefix "\'0b\'", ' +- '"\'0o\'", "\'0x\'",\n' +- 'or "\'0X\'" to the output value. For float and complex the ' +- 'alternate\n' +- 'form causes the result of the conversion to always contain ' +- 'a decimal-\n' +- 'point character, even if no digits follow it. Normally, a ' +- 'decimal-\n' +- 'point character appears in the result of these conversions ' +- 'only if a\n' +- 'digit follows it. In addition, for "\'g\'" and "\'G\'" ' +- 'conversions,\n' +- 'trailing zeros are not removed from the result.\n' +- '\n' +- 'The "\',\'" option signals the use of a comma for a ' +- 'thousands separator\n' +- 'for floating-point presentation types and for integer ' +- 'presentation\n' +- 'type "\'d\'". For other presentation types, this option is ' +- 'an error. For\n' +- 'a locale aware separator, use the "\'n\'" integer ' +- 'presentation type\n' +- 'instead.\n' +- '\n' +- 'Changed in version 3.1: Added the "\',\'" option (see also ' +- '**PEP 378**).\n' +- '\n' +- 'The "\'_\'" option signals the use of an underscore for a ' +- 'thousands\n' +- 'separator for floating-point presentation types and for ' +- 'integer\n' +- 'presentation type "\'d\'". For integer presentation types ' +- '"\'b\'", "\'o\'",\n' +- '"\'x\'", and "\'X\'", underscores will be inserted every 4 ' +- 'digits. For\n' +- 'other presentation types, specifying this option is an ' +- 'error.\n' +- '\n' +- 'Changed in version 3.6: Added the "\'_\'" option (see also ' +- '**PEP 515**).\n' +- '\n' +- '*width* is a decimal integer defining the minimum total ' +- 'field width,\n' +- 'including any prefixes, separators, and other formatting ' +- 'characters.\n' +- 'If not specified, then the field width will be determined ' +- 'by the\n' +- 'content.\n' +- '\n' +- 'When no explicit alignment is given, preceding the *width* ' +- 'field by a\n' +- 'zero ("\'0\'") character enables sign-aware zero-padding ' +- 'for numeric\n' +- 'types, excluding "complex". This is equivalent to a *fill* ' +- 'character\n' +- 'of "\'0\'" with an *alignment* type of "\'=\'".\n' +- '\n' +- 'Changed in version 3.10: Preceding the *width* field by ' +- '"\'0\'" no\n' +- 'longer affects the default alignment for strings.\n' +- '\n' +- 'The *precision* is a decimal integer indicating how many ' +- 'digits should\n' +- 'be displayed after the decimal point for presentation types ' +- '"\'f\'" and\n' +- '"\'F\'", or before and after the decimal point for ' +- 'presentation types\n' +- '"\'g\'" or "\'G\'". For string presentation types the ' +- 'field indicates the\n' +- 'maximum field size - in other words, how many characters ' +- 'will be used\n' +- 'from the field content. The *precision* is not allowed for ' +- 'integer\n' +- 'presentation types.\n' +- '\n' +- 'Finally, the *type* determines how the data should be ' +- 'presented.\n' +- '\n' +- 'The available string presentation types are:\n' +- '\n' +- ' ' +- '+-----------+------------------------------------------------------------+\n' +- ' | Type | ' +- 'Meaning ' +- '|\n' +- ' ' +- '|===========|============================================================|\n' +- ' | "\'s\'" | String format. This is the default type ' +- 'for strings and |\n' +- ' | | may be ' +- 'omitted. |\n' +- ' ' +- '+-----------+------------------------------------------------------------+\n' +- ' | None | The same as ' +- '"\'s\'". |\n' +- ' ' +- '+-----------+------------------------------------------------------------+\n' +- '\n' +- 'The available integer presentation types are:\n' +- '\n' +- ' ' +- '+-----------+------------------------------------------------------------+\n' +- ' | Type | ' +- 'Meaning ' +- '|\n' +- ' ' +- '|===========|============================================================|\n' +- ' | "\'b\'" | Binary format. Outputs the number in ' +- 'base 2. |\n' +- ' ' +- '+-----------+------------------------------------------------------------+\n' +- ' | "\'c\'" | Character. Converts the integer to the ' +- 'corresponding |\n' +- ' | | unicode character before ' +- 'printing. |\n' +- ' ' +- '+-----------+------------------------------------------------------------+\n' +- ' | "\'d\'" | Decimal Integer. Outputs the number in ' +- 'base 10. |\n' +- ' ' +- '+-----------+------------------------------------------------------------+\n' +- ' | "\'o\'" | Octal format. Outputs the number in base ' +- '8. |\n' +- ' ' +- '+-----------+------------------------------------------------------------+\n' +- ' | "\'x\'" | Hex format. Outputs the number in base ' +- '16, using lower- |\n' +- ' | | case letters for the digits above ' +- '9. |\n' +- ' ' +- '+-----------+------------------------------------------------------------+\n' +- ' | "\'X\'" | Hex format. Outputs the number in base ' +- '16, using upper- |\n' +- ' | | case letters for the digits above 9. In ' +- 'case "\'#\'" is |\n' +- ' | | specified, the prefix "\'0x\'" will be ' +- 'upper-cased to "\'0X\'" |\n' +- ' | | as ' +- 'well. |\n' +- ' ' +- '+-----------+------------------------------------------------------------+\n' +- ' | "\'n\'" | Number. This is the same as "\'d\'", ' +- 'except that it uses the |\n' +- ' | | current locale setting to insert the ' +- 'appropriate number |\n' +- ' | | separator ' +- 'characters. |\n' +- ' ' +- '+-----------+------------------------------------------------------------+\n' +- ' | None | The same as ' +- '"\'d\'". |\n' +- ' ' +- '+-----------+------------------------------------------------------------+\n' +- '\n' +- 'In addition to the above presentation types, integers can ' +- 'be formatted\n' +- 'with the floating-point presentation types listed below ' +- '(except "\'n\'"\n' +- 'and "None"). When doing so, "float()" is used to convert ' +- 'the integer\n' +- 'to a floating-point number before formatting.\n' +- '\n' +- 'The available presentation types for "float" and "Decimal" ' +- 'values are:\n' +- '\n' +- ' ' +- '+-----------+------------------------------------------------------------+\n' +- ' | Type | ' +- 'Meaning ' +- '|\n' +- ' ' +- '|===========|============================================================|\n' +- ' | "\'e\'" | Scientific notation. For a given ' +- 'precision "p", formats |\n' +- ' | | the number in scientific notation with the ' +- 'letter ‘e’ |\n' +- ' | | separating the coefficient from the ' +- 'exponent. The |\n' +- ' | | coefficient has one digit before and "p" ' +- 'digits after the |\n' +- ' | | decimal point, for a total of "p + 1" ' +- 'significant digits. |\n' +- ' | | With no precision given, uses a precision ' +- 'of "6" digits |\n' +- ' | | after the decimal point for "float", and ' +- 'shows all |\n' +- ' | | coefficient digits for "Decimal". If ' +- '"p=0", the decimal |\n' +- ' | | point is omitted unless the "#" option is ' +- 'used. |\n' +- ' ' +- '+-----------+------------------------------------------------------------+\n' +- ' | "\'E\'" | Scientific notation. Same as "\'e\'" ' +- 'except it uses an upper |\n' +- ' | | case ‘E’ as the separator ' +- 'character. |\n' +- ' ' +- '+-----------+------------------------------------------------------------+\n' +- ' | "\'f\'" | Fixed-point notation. For a given ' +- 'precision "p", formats |\n' +- ' | | the number as a decimal number with ' +- 'exactly "p" digits |\n' +- ' | | following the decimal point. With no ' +- 'precision given, uses |\n' +- ' | | a precision of "6" digits after the ' +- 'decimal point for |\n' +- ' | | "float", and uses a precision large enough ' +- 'to show all |\n' +- ' | | coefficient digits for "Decimal". If ' +- '"p=0", the decimal |\n' +- ' | | point is omitted unless the "#" option is ' +- 'used. |\n' +- ' ' +- '+-----------+------------------------------------------------------------+\n' +- ' | "\'F\'" | Fixed-point notation. Same as "\'f\'", ' +- 'but converts "nan" to |\n' +- ' | | "NAN" and "inf" to ' +- '"INF". |\n' +- ' ' +- '+-----------+------------------------------------------------------------+\n' +- ' | "\'g\'" | General format. For a given precision ' +- '"p >= 1", this |\n' +- ' | | rounds the number to "p" significant ' +- 'digits and then |\n' +- ' | | formats the result in either fixed-point ' +- 'format or in |\n' +- ' | | scientific notation, depending on its ' +- 'magnitude. A |\n' +- ' | | precision of "0" is treated as equivalent ' +- 'to a precision |\n' +- ' | | of "1". The precise rules are as follows: ' +- 'suppose that |\n' +- ' | | the result formatted with presentation ' +- 'type "\'e\'" and |\n' +- ' | | precision "p-1" would have exponent ' +- '"exp". Then, if "m <= |\n' +- ' | | exp < p", where "m" is -4 for floats and ' +- '-6 for |\n' +- ' | | "Decimals", the number is formatted with ' +- 'presentation type |\n' +- ' | | "\'f\'" and precision "p-1-exp". ' +- 'Otherwise, the number is |\n' +- ' | | formatted with presentation type "\'e\'" ' +- 'and precision |\n' +- ' | | "p-1". In both cases insignificant ' +- 'trailing zeros are |\n' +- ' | | removed from the significand, and the ' +- 'decimal point is |\n' +- ' | | also removed if there are no remaining ' +- 'digits following |\n' +- ' | | it, unless the "\'#\'" option is used. ' +- 'With no precision |\n' +- ' | | given, uses a precision of "6" significant ' +- 'digits for |\n' +- ' | | "float". For "Decimal", the coefficient of ' +- 'the result is |\n' +- ' | | formed from the coefficient digits of the ' +- 'value; |\n' +- ' | | scientific notation is used for values ' +- 'smaller than "1e-6" |\n' +- ' | | in absolute value and values where the ' +- 'place value of the |\n' +- ' | | least significant digit is larger than 1, ' +- 'and fixed-point |\n' +- ' | | notation is used otherwise. Positive and ' +- 'negative |\n' +- ' | | infinity, positive and negative zero, and ' +- 'nans, are |\n' +- ' | | formatted as "inf", "-inf", "0", "-0" and ' +- '"nan" |\n' +- ' | | respectively, regardless of the ' +- 'precision. |\n' +- ' ' +- '+-----------+------------------------------------------------------------+\n' +- ' | "\'G\'" | General format. Same as "\'g\'" except ' +- 'switches to "\'E\'" if |\n' +- ' | | the number gets too large. The ' +- 'representations of infinity |\n' +- ' | | and NaN are uppercased, ' +- 'too. |\n' +- ' ' +- '+-----------+------------------------------------------------------------+\n' +- ' | "\'n\'" | Number. This is the same as "\'g\'", ' +- 'except that it uses the |\n' +- ' | | current locale setting to insert the ' +- 'appropriate number |\n' +- ' | | separator ' +- 'characters. |\n' +- ' ' +- '+-----------+------------------------------------------------------------+\n' +- ' | "\'%\'" | Percentage. Multiplies the number by 100 ' +- 'and displays in |\n' +- ' | | fixed ("\'f\'") format, followed by a ' +- 'percent sign. |\n' +- ' ' +- '+-----------+------------------------------------------------------------+\n' +- ' | None | For "float" this is like the "\'g\'" type, ' +- 'except that when |\n' +- ' | | fixed- point notation is used to format ' +- 'the result, it |\n' +- ' | | always includes at least one digit past ' +- 'the decimal point, |\n' +- ' | | and switches to the scientific notation ' +- 'when "exp >= p - |\n' +- ' | | 1". When the precision is not specified, ' +- 'the latter will |\n' +- ' | | be as large as needed to represent the ' +- 'given value |\n' +- ' | | faithfully. For "Decimal", this is the ' +- 'same as either |\n' +- ' | | "\'g\'" or "\'G\'" depending on the value ' +- 'of |\n' +- ' | | "context.capitals" for the current decimal ' +- 'context. The |\n' +- ' | | overall effect is to match the output of ' +- '"str()" as |\n' +- ' | | altered by the other format ' +- 'modifiers. |\n' +- ' ' +- '+-----------+------------------------------------------------------------+\n' +- '\n' +- 'The result should be correctly rounded to a given precision ' +- '"p" of\n' +- 'digits after the decimal point. The rounding mode for ' +- '"float" matches\n' +- 'that of the "round()" builtin. For "Decimal", the rounding ' +- 'mode of\n' +- 'the current context will be used.\n' +- '\n' +- 'The available presentation types for "complex" are the same ' +- 'as those\n' +- 'for "float" ("\'%\'" is not allowed). Both the real and ' +- 'imaginary\n' +- 'components of a complex number are formatted as ' +- 'floating-point\n' +- 'numbers, according to the specified presentation type. ' +- 'They are\n' +- 'separated by the mandatory sign of the imaginary part, the ' +- 'latter\n' +- 'being terminated by a "j" suffix. If the presentation type ' +- 'is\n' +- 'missing, the result will match the output of "str()" ' +- '(complex numbers\n' +- 'with a non-zero real part are also surrounded by ' +- 'parentheses),\n' +- 'possibly altered by other format modifiers.\n' +- '\n' +- '\n' +- 'Format examples\n' +- '===============\n' +- '\n' +- 'This section contains examples of the "str.format()" syntax ' +- 'and\n' +- 'comparison with the old "%"-formatting.\n' +- '\n' +- 'In most of the cases the syntax is similar to the old ' +- '"%"-formatting,\n' +- 'with the addition of the "{}" and with ":" used instead of ' +- '"%". For\n' +- 'example, "\'%03.2f\'" can be translated to "\'{:03.2f}\'".\n' +- '\n' +- 'The new format syntax also supports new and different ' +- 'options, shown\n' +- 'in the following examples.\n' +- '\n' +- 'Accessing arguments by position:\n' +- '\n' +- " >>> '{0}, {1}, {2}'.format('a', 'b', 'c')\n" +- " 'a, b, c'\n" +- " >>> '{}, {}, {}'.format('a', 'b', 'c') # 3.1+ only\n" +- " 'a, b, c'\n" +- " >>> '{2}, {1}, {0}'.format('a', 'b', 'c')\n" +- " 'c, b, a'\n" +- " >>> '{2}, {1}, {0}'.format(*'abc') # unpacking " +- 'argument sequence\n' +- " 'c, b, a'\n" +- " >>> '{0}{1}{0}'.format('abra', 'cad') # arguments' " +- 'indices can be repeated\n' +- " 'abracadabra'\n" +- '\n' +- 'Accessing arguments by name:\n' +- '\n' +- " >>> 'Coordinates: {latitude}, " +- "{longitude}'.format(latitude='37.24N', " +- "longitude='-115.81W')\n" +- " 'Coordinates: 37.24N, -115.81W'\n" +- " >>> coord = {'latitude': '37.24N', 'longitude': " +- "'-115.81W'}\n" +- " >>> 'Coordinates: {latitude}, " +- "{longitude}'.format(**coord)\n" +- " 'Coordinates: 37.24N, -115.81W'\n" +- '\n' +- 'Accessing arguments’ attributes:\n' +- '\n' +- ' >>> c = 3-5j\n' +- " >>> ('The complex number {0} is formed from the real " +- "part {0.real} '\n" +- " ... 'and the imaginary part {0.imag}.').format(c)\n" +- " 'The complex number (3-5j) is formed from the real part " +- "3.0 and the imaginary part -5.0.'\n" +- ' >>> class Point:\n' +- ' ... def __init__(self, x, y):\n' +- ' ... self.x, self.y = x, y\n' +- ' ... def __str__(self):\n' +- " ... return 'Point({self.x}, " +- "{self.y})'.format(self=self)\n" +- ' ...\n' +- ' >>> str(Point(4, 2))\n' +- " 'Point(4, 2)'\n" +- '\n' +- 'Accessing arguments’ items:\n' +- '\n' +- ' >>> coord = (3, 5)\n' +- " >>> 'X: {0[0]}; Y: {0[1]}'.format(coord)\n" +- " 'X: 3; Y: 5'\n" +- '\n' +- 'Replacing "%s" and "%r":\n' +- '\n' +- ' >>> "repr() shows quotes: {!r}; str() doesn\'t: ' +- '{!s}".format(\'test1\', \'test2\')\n' +- ' "repr() shows quotes: \'test1\'; str() doesn\'t: test2"\n' +- '\n' +- 'Aligning the text and specifying a width:\n' +- '\n' +- " >>> '{:<30}'.format('left aligned')\n" +- " 'left aligned '\n" +- " >>> '{:>30}'.format('right aligned')\n" +- " ' right aligned'\n" +- " >>> '{:^30}'.format('centered')\n" +- " ' centered '\n" +- " >>> '{:*^30}'.format('centered') # use '*' as a fill " +- 'char\n' +- " '***********centered***********'\n" +- '\n' +- 'Replacing "%+f", "%-f", and "% f" and specifying a sign:\n' +- '\n' +- " >>> '{:+f}; {:+f}'.format(3.14, -3.14) # show it " +- 'always\n' +- " '+3.140000; -3.140000'\n" +- " >>> '{: f}; {: f}'.format(3.14, -3.14) # show a space " +- 'for positive numbers\n' +- " ' 3.140000; -3.140000'\n" +- " >>> '{:-f}; {:-f}'.format(3.14, -3.14) # show only the " +- "minus -- same as '{:f}; {:f}'\n" +- " '3.140000; -3.140000'\n" +- '\n' +- 'Replacing "%x" and "%o" and converting the value to ' +- 'different bases:\n' +- '\n' +- ' >>> # format also supports binary numbers\n' +- ' >>> "int: {0:d}; hex: {0:x}; oct: {0:o}; bin: ' +- '{0:b}".format(42)\n' +- " 'int: 42; hex: 2a; oct: 52; bin: 101010'\n" +- ' >>> # with 0x, 0o, or 0b as prefix:\n' +- ' >>> "int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: ' +- '{0:#b}".format(42)\n' +- " 'int: 42; hex: 0x2a; oct: 0o52; bin: 0b101010'\n" +- '\n' +- 'Using the comma as a thousands separator:\n' +- '\n' +- " >>> '{:,}'.format(1234567890)\n" +- " '1,234,567,890'\n" +- '\n' +- 'Expressing a percentage:\n' +- '\n' +- ' >>> points = 19\n' +- ' >>> total = 22\n' +- " >>> 'Correct answers: {:.2%}'.format(points/total)\n" +- " 'Correct answers: 86.36%'\n" +- '\n' +- 'Using type-specific formatting:\n' +- '\n' +- ' >>> import datetime\n' +- ' >>> d = datetime.datetime(2010, 7, 4, 12, 15, 58)\n' +- " >>> '{:%Y-%m-%d %H:%M:%S}'.format(d)\n" +- " '2010-07-04 12:15:58'\n" +- '\n' +- 'Nesting arguments and more complex examples:\n' +- '\n' +- " >>> for align, text in zip('<^>', ['left', 'center', " +- "'right']):\n" +- " ... '{0:{fill}{align}16}'.format(text, fill=align, " +- 'align=align)\n' +- ' ...\n' +- " 'left<<<<<<<<<<<<'\n" +- " '^^^^^center^^^^^'\n" +- " '>>>>>>>>>>>right'\n" +- ' >>>\n' +- ' >>> octets = [192, 168, 0, 1]\n' +- " >>> '{:02X}{:02X}{:02X}{:02X}'.format(*octets)\n" +- " 'C0A80001'\n" +- ' >>> int(_, 16)\n' +- ' 3232235521\n' +- ' >>>\n' +- ' >>> width = 5\n' +- ' >>> for num in range(5,12): \n' +- " ... for base in 'dXob':\n" +- " ... print('{0:{width}{base}}'.format(num, " +- "base=base, width=width), end=' ')\n" +- ' ... print()\n' +- ' ...\n' +- ' 5 5 5 101\n' +- ' 6 6 6 110\n' +- ' 7 7 7 111\n' +- ' 8 8 10 1000\n' +- ' 9 9 11 1001\n' +- ' 10 A 12 1010\n' +- ' 11 B 13 1011\n', +- 'function': 'Function definitions\n' +- '********************\n' +- '\n' +- 'A function definition defines a user-defined function object ' +- '(see\n' +- 'section The standard type hierarchy):\n' +- '\n' +- ' funcdef ::= [decorators] "def" funcname ' +- '[type_params] "(" [parameter_list] ")"\n' +- ' ["->" expression] ":" suite\n' +- ' decorators ::= decorator+\n' +- ' decorator ::= "@" assignment_expression ' +- 'NEWLINE\n' +- ' parameter_list ::= defparameter ("," ' +- 'defparameter)* "," "/" ["," [parameter_list_no_posonly]]\n' +- ' | parameter_list_no_posonly\n' +- ' parameter_list_no_posonly ::= defparameter ("," ' +- 'defparameter)* ["," [parameter_list_starargs]]\n' +- ' | parameter_list_starargs\n' +- ' parameter_list_starargs ::= "*" [star_parameter] ("," ' +- 'defparameter)* ["," ["**" parameter [","]]]\n' +- ' | "**" parameter [","]\n' +- ' parameter ::= identifier [":" expression]\n' +- ' star_parameter ::= identifier [":" ["*"] ' +- 'expression]\n' +- ' defparameter ::= parameter ["=" expression]\n' +- ' funcname ::= identifier\n' +- '\n' +- 'A function definition is an executable statement. Its execution ' +- 'binds\n' +- 'the function name in the current local namespace to a function ' +- 'object\n' +- '(a wrapper around the executable code for the function). This\n' +- 'function object contains a reference to the current global ' +- 'namespace\n' +- 'as the global namespace to be used when the function is called.\n' +- '\n' +- 'The function definition does not execute the function body; this ' +- 'gets\n' +- 'executed only when the function is called. [4]\n' +- '\n' +- 'A function definition may be wrapped by one or more *decorator*\n' +- 'expressions. Decorator expressions are evaluated when the ' +- 'function is\n' +- 'defined, in the scope that contains the function definition. ' +- 'The\n' +- 'result must be a callable, which is invoked with the function ' +- 'object\n' +- 'as the only argument. The returned value is bound to the ' +- 'function name\n' +- 'instead of the function object. Multiple decorators are applied ' +- 'in\n' +- 'nested fashion. For example, the following code\n' +- '\n' +- ' @f1(arg)\n' +- ' @f2\n' +- ' def func(): pass\n' +- '\n' +- 'is roughly equivalent to\n' +- '\n' +- ' def func(): pass\n' +- ' func = f1(arg)(f2(func))\n' +- '\n' +- 'except that the original function is not temporarily bound to ' +- 'the name\n' +- '"func".\n' +- '\n' +- 'Changed in version 3.9: Functions may be decorated with any ' +- 'valid\n' +- '"assignment_expression". Previously, the grammar was much more\n' +- 'restrictive; see **PEP 614** for details.\n' +- '\n' +- 'A list of type parameters may be given in square brackets ' +- 'between the\n' +- 'function’s name and the opening parenthesis for its parameter ' +- 'list.\n' +- 'This indicates to static type checkers that the function is ' +- 'generic.\n' +- 'At runtime, the type parameters can be retrieved from the ' +- 'function’s\n' +- '"__type_params__" attribute. See Generic functions for more.\n' +- '\n' +- 'Changed in version 3.12: Type parameter lists are new in Python ' +- '3.12.\n' +- '\n' +- 'When one or more *parameters* have the form *parameter* "="\n' +- '*expression*, the function is said to have “default parameter ' +- 'values.â€\n' +- 'For a parameter with a default value, the corresponding ' +- '*argument* may\n' +- 'be omitted from a call, in which case the parameter’s default ' +- 'value is\n' +- 'substituted. If a parameter has a default value, all following\n' +- 'parameters up until the “"*"†must also have a default value — ' +- 'this is\n' +- 'a syntactic restriction that is not expressed by the grammar.\n' +- '\n' +- '**Default parameter values are evaluated from left to right when ' +- 'the\n' +- 'function definition is executed.** This means that the ' +- 'expression is\n' +- 'evaluated once, when the function is defined, and that the same ' +- '“pre-\n' +- 'computed†value is used for each call. This is especially ' +- 'important\n' +- 'to understand when a default parameter value is a mutable ' +- 'object, such\n' +- 'as a list or a dictionary: if the function modifies the object ' +- '(e.g.\n' +- 'by appending an item to a list), the default parameter value is ' +- 'in\n' +- 'effect modified. This is generally not what was intended. A ' +- 'way\n' +- 'around this is to use "None" as the default, and explicitly test ' +- 'for\n' +- 'it in the body of the function, e.g.:\n' +- '\n' +- ' def whats_on_the_telly(penguin=None):\n' +- ' if penguin is None:\n' +- ' penguin = []\n' +- ' penguin.append("property of the zoo")\n' +- ' return penguin\n' +- '\n' +- 'Function call semantics are described in more detail in section ' +- 'Calls.\n' +- 'A function call always assigns values to all parameters ' +- 'mentioned in\n' +- 'the parameter list, either from positional arguments, from ' +- 'keyword\n' +- 'arguments, or from default values. If the form “"*identifier"†' +- 'is\n' +- 'present, it is initialized to a tuple receiving any excess ' +- 'positional\n' +- 'parameters, defaulting to the empty tuple. If the form\n' +- '“"**identifier"†is present, it is initialized to a new ordered\n' +- 'mapping receiving any excess keyword arguments, defaulting to a ' +- 'new\n' +- 'empty mapping of the same type. Parameters after “"*"†or\n' +- '“"*identifier"†are keyword-only parameters and may only be ' +- 'passed by\n' +- 'keyword arguments. Parameters before “"/"†are positional-only\n' +- 'parameters and may only be passed by positional arguments.\n' +- '\n' +- 'Changed in version 3.8: The "/" function parameter syntax may be ' +- 'used\n' +- 'to indicate positional-only parameters. See **PEP 570** for ' +- 'details.\n' +- '\n' +- 'Parameters may have an *annotation* of the form “": ' +- 'expression"â€\n' +- 'following the parameter name. Any parameter may have an ' +- 'annotation,\n' +- 'even those of the form "*identifier" or "**identifier". (As a ' +- 'special\n' +- 'case, parameters of the form "*identifier" may have an ' +- 'annotation “":\n' +- '*expression"â€.) Functions may have “return†annotation of the ' +- 'form\n' +- '“"-> expression"†after the parameter list. These annotations ' +- 'can be\n' +- 'any valid Python expression. The presence of annotations does ' +- 'not\n' +- 'change the semantics of a function. See Annotations for more\n' +- 'information on annotations.\n' +- '\n' +- 'Changed in version 3.11: Parameters of the form “"*identifier"†' +- 'may\n' +- 'have an annotation “": *expression"â€. See **PEP 646**.\n' +- '\n' +- 'It is also possible to create anonymous functions (functions not ' +- 'bound\n' +- 'to a name), for immediate use in expressions. This uses lambda\n' +- 'expressions, described in section Lambdas. Note that the ' +- 'lambda\n' +- 'expression is merely a shorthand for a simplified function ' +- 'definition;\n' +- 'a function defined in a “"def"†statement can be passed around ' +- 'or\n' +- 'assigned to another name just like a function defined by a ' +- 'lambda\n' +- 'expression. The “"def"†form is actually more powerful since ' +- 'it\n' +- 'allows the execution of multiple statements and annotations.\n' +- '\n' +- '**Programmer’s note:** Functions are first-class objects. A ' +- '“"def"â€\n' +- 'statement executed inside a function definition defines a local\n' +- 'function that can be returned or passed around. Free variables ' +- 'used\n' +- 'in the nested function can access the local variables of the ' +- 'function\n' +- 'containing the def. See section Naming and binding for ' +- 'details.\n' +- '\n' +- 'See also:\n' +- '\n' +- ' **PEP 3107** - Function Annotations\n' +- ' The original specification for function annotations.\n' +- '\n' +- ' **PEP 484** - Type Hints\n' +- ' Definition of a standard meaning for annotations: type ' +- 'hints.\n' +- '\n' +- ' **PEP 526** - Syntax for Variable Annotations\n' +- ' Ability to type hint variable declarations, including ' +- 'class\n' +- ' variables and instance variables.\n' +- '\n' +- ' **PEP 563** - Postponed Evaluation of Annotations\n' +- ' Support for forward references within annotations by ' +- 'preserving\n' +- ' annotations in a string form at runtime instead of eager\n' +- ' evaluation.\n' +- '\n' +- ' **PEP 318** - Decorators for Functions and Methods\n' +- ' Function and method decorators were introduced. Class ' +- 'decorators\n' +- ' were introduced in **PEP 3129**.\n', +- 'global': 'The "global" statement\n' +- '**********************\n' +- '\n' +- ' global_stmt ::= "global" identifier ("," identifier)*\n' +- '\n' +- 'The "global" statement causes the listed identifiers to be ' +- 'interpreted\n' +- 'as globals. It would be impossible to assign to a global variable\n' +- 'without "global", although free variables may refer to globals ' +- 'without\n' +- 'being declared global.\n' +- '\n' +- 'The "global" statement applies to the entire scope of a function ' +- 'or\n' +- 'class body. A "SyntaxError" is raised if a variable is used or\n' +- 'assigned to prior to its global declaration in the scope.\n' +- '\n' +- '**Programmer’s note:** "global" is a directive to the parser. It\n' +- 'applies only to code parsed at the same time as the "global"\n' +- 'statement. In particular, a "global" statement contained in a ' +- 'string\n' +- 'or code object supplied to the built-in "exec()" function does ' +- 'not\n' +- 'affect the code block *containing* the function call, and code\n' +- 'contained in such a string is unaffected by "global" statements in ' +- 'the\n' +- 'code containing the function call. The same applies to the ' +- '"eval()"\n' +- 'and "compile()" functions.\n', +- 'id-classes': 'Reserved classes of identifiers\n' +- '*******************************\n' +- '\n' +- 'Certain classes of identifiers (besides keywords) have ' +- 'special\n' +- 'meanings. These classes are identified by the patterns of ' +- 'leading and\n' +- 'trailing underscore characters:\n' +- '\n' +- '"_*"\n' +- ' Not imported by "from module import *".\n' +- '\n' +- '"_"\n' +- ' In a "case" pattern within a "match" statement, "_" is a ' +- 'soft\n' +- ' keyword that denotes a wildcard.\n' +- '\n' +- ' Separately, the interactive interpreter makes the result of ' +- 'the\n' +- ' last evaluation available in the variable "_". (It is ' +- 'stored in the\n' +- ' "builtins" module, alongside built-in functions like ' +- '"print".)\n' +- '\n' +- ' Elsewhere, "_" is a regular identifier. It is often used to ' +- 'name\n' +- ' “special†items, but it is not special to Python itself.\n' +- '\n' +- ' Note:\n' +- '\n' +- ' The name "_" is often used in conjunction with\n' +- ' internationalization; refer to the documentation for the\n' +- ' "gettext" module for more information on this ' +- 'convention.It is\n' +- ' also commonly used for unused variables.\n' +- '\n' +- '"__*__"\n' +- ' System-defined names, informally known as “dunder†names. ' +- 'These\n' +- ' names are defined by the interpreter and its ' +- 'implementation\n' +- ' (including the standard library). Current system names are\n' +- ' discussed in the Special method names section and ' +- 'elsewhere. More\n' +- ' will likely be defined in future versions of Python. *Any* ' +- 'use of\n' +- ' "__*__" names, in any context, that does not follow ' +- 'explicitly\n' +- ' documented use, is subject to breakage without warning.\n' +- '\n' +- '"__*"\n' +- ' Class-private names. Names in this category, when used ' +- 'within the\n' +- ' context of a class definition, are re-written to use a ' +- 'mangled form\n' +- ' to help avoid name clashes between “private†attributes of ' +- 'base and\n' +- ' derived classes. See section Identifiers (Names).\n', +- 'identifiers': 'Identifiers and keywords\n' +- '************************\n' +- '\n' +- 'Identifiers (also referred to as *names*) are described by ' +- 'the\n' +- 'following lexical definitions.\n' +- '\n' +- 'The syntax of identifiers in Python is based on the Unicode ' +- 'standard\n' +- 'annex UAX-31, with elaboration and changes as defined below; ' +- 'see also\n' +- '**PEP 3131** for further details.\n' +- '\n' +- 'Within the ASCII range (U+0001..U+007F), the valid characters ' +- 'for\n' +- 'identifiers include the uppercase and lowercase letters "A" ' +- 'through\n' +- '"Z", the underscore "_" and, except for the first character, ' +- 'the\n' +- 'digits "0" through "9". Python 3.0 introduced additional ' +- 'characters\n' +- 'from outside the ASCII range (see **PEP 3131**). For these\n' +- 'characters, the classification uses the version of the ' +- 'Unicode\n' +- 'Character Database as included in the "unicodedata" module.\n' +- '\n' +- 'Identifiers are unlimited in length. Case is significant.\n' +- '\n' +- ' identifier ::= xid_start xid_continue*\n' +- ' id_start ::= \n' +- ' id_continue ::= \n' +- ' xid_start ::= \n' +- ' xid_continue ::= \n' +- '\n' +- 'The Unicode category codes mentioned above stand for:\n' +- '\n' +- '* *Lu* - uppercase letters\n' +- '\n' +- '* *Ll* - lowercase letters\n' +- '\n' +- '* *Lt* - titlecase letters\n' +- '\n' +- '* *Lm* - modifier letters\n' +- '\n' +- '* *Lo* - other letters\n' +- '\n' +- '* *Nl* - letter numbers\n' +- '\n' +- '* *Mn* - nonspacing marks\n' +- '\n' +- '* *Mc* - spacing combining marks\n' +- '\n' +- '* *Nd* - decimal numbers\n' +- '\n' +- '* *Pc* - connector punctuations\n' +- '\n' +- '* *Other_ID_Start* - explicit list of characters in ' +- 'PropList.txt to\n' +- ' support backwards compatibility\n' +- '\n' +- '* *Other_ID_Continue* - likewise\n' +- '\n' +- 'All identifiers are converted into the normal form NFKC while ' +- 'parsing;\n' +- 'comparison of identifiers is based on NFKC.\n' +- '\n' +- 'A non-normative HTML file listing all valid identifier ' +- 'characters for\n' +- 'Unicode 16.0.0 can be found at\n' +- 'https://www.unicode.org/Public/16.0.0/ucd/DerivedCoreProperties.txt\n' +- '\n' +- '\n' +- 'Keywords\n' +- '========\n' +- '\n' +- 'The following identifiers are used as reserved words, or ' +- '*keywords* of\n' +- 'the language, and cannot be used as ordinary identifiers. ' +- 'They must\n' +- 'be spelled exactly as written here:\n' +- '\n' +- ' False await else import pass\n' +- ' None break except in raise\n' +- ' True class finally is return\n' +- ' and continue for lambda try\n' +- ' as def from nonlocal while\n' +- ' assert del global not with\n' +- ' async elif if or yield\n' +- '\n' +- '\n' +- 'Soft Keywords\n' +- '=============\n' +- '\n' +- 'Added in version 3.10.\n' +- '\n' +- 'Some identifiers are only reserved under specific contexts. ' +- 'These are\n' +- 'known as *soft keywords*. The identifiers "match", "case", ' +- '"type" and\n' +- '"_" can syntactically act as keywords in certain contexts, ' +- 'but this\n' +- 'distinction is done at the parser level, not when ' +- 'tokenizing.\n' +- '\n' +- 'As soft keywords, their use in the grammar is possible while ' +- 'still\n' +- 'preserving compatibility with existing code that uses these ' +- 'names as\n' +- 'identifier names.\n' +- '\n' +- '"match", "case", and "_" are used in the "match" statement. ' +- '"type" is\n' +- 'used in the "type" statement.\n' +- '\n' +- 'Changed in version 3.12: "type" is now a soft keyword.\n' +- '\n' +- '\n' +- 'Reserved classes of identifiers\n' +- '===============================\n' +- '\n' +- 'Certain classes of identifiers (besides keywords) have ' +- 'special\n' +- 'meanings. These classes are identified by the patterns of ' +- 'leading and\n' +- 'trailing underscore characters:\n' +- '\n' +- '"_*"\n' +- ' Not imported by "from module import *".\n' +- '\n' +- '"_"\n' +- ' In a "case" pattern within a "match" statement, "_" is a ' +- 'soft\n' +- ' keyword that denotes a wildcard.\n' +- '\n' +- ' Separately, the interactive interpreter makes the result ' +- 'of the\n' +- ' last evaluation available in the variable "_". (It is ' +- 'stored in the\n' +- ' "builtins" module, alongside built-in functions like ' +- '"print".)\n' +- '\n' +- ' Elsewhere, "_" is a regular identifier. It is often used ' +- 'to name\n' +- ' “special†items, but it is not special to Python itself.\n' +- '\n' +- ' Note:\n' +- '\n' +- ' The name "_" is often used in conjunction with\n' +- ' internationalization; refer to the documentation for ' +- 'the\n' +- ' "gettext" module for more information on this ' +- 'convention.It is\n' +- ' also commonly used for unused variables.\n' +- '\n' +- '"__*__"\n' +- ' System-defined names, informally known as “dunder†names. ' +- 'These\n' +- ' names are defined by the interpreter and its ' +- 'implementation\n' +- ' (including the standard library). Current system names ' +- 'are\n' +- ' discussed in the Special method names section and ' +- 'elsewhere. More\n' +- ' will likely be defined in future versions of Python. ' +- '*Any* use of\n' +- ' "__*__" names, in any context, that does not follow ' +- 'explicitly\n' +- ' documented use, is subject to breakage without warning.\n' +- '\n' +- '"__*"\n' +- ' Class-private names. Names in this category, when used ' +- 'within the\n' +- ' context of a class definition, are re-written to use a ' +- 'mangled form\n' +- ' to help avoid name clashes between “private†attributes of ' +- 'base and\n' +- ' derived classes. See section Identifiers (Names).\n', +- 'if': 'The "if" statement\n' +- '******************\n' +- '\n' +- 'The "if" statement is used for conditional execution:\n' +- '\n' +- ' if_stmt ::= "if" assignment_expression ":" suite\n' +- ' ("elif" assignment_expression ":" suite)*\n' +- ' ["else" ":" suite]\n' +- '\n' +- 'It selects exactly one of the suites by evaluating the expressions ' +- 'one\n' +- 'by one until one is found to be true (see section Boolean operations\n' +- 'for the definition of true and false); then that suite is executed\n' +- '(and no other part of the "if" statement is executed or evaluated).\n' +- 'If all expressions are false, the suite of the "else" clause, if\n' +- 'present, is executed.\n', +- 'imaginary': 'Imaginary literals\n' +- '******************\n' +- '\n' +- 'Imaginary literals are described by the following lexical ' +- 'definitions:\n' +- '\n' +- ' imagnumber ::= (floatnumber | digitpart) ("j" | "J")\n' +- '\n' +- 'An imaginary literal yields a complex number with a real part ' +- 'of 0.0.\n' +- 'Complex numbers are represented as a pair of floating-point ' +- 'numbers\n' +- 'and have the same restrictions on their range. To create a ' +- 'complex\n' +- 'number with a nonzero real part, add a floating-point number to ' +- 'it,\n' +- 'e.g., "(3+4j)". Some examples of imaginary literals:\n' +- '\n' +- ' 3.14j 10.j 10j .001j 1e100j 3.14e-10j ' +- '3.14_15_93j\n', +- 'import': 'The "import" statement\n' +- '**********************\n' +- '\n' +- ' import_stmt ::= "import" module ["as" identifier] ("," ' +- 'module ["as" identifier])*\n' +- ' | "from" relative_module "import" identifier ' +- '["as" identifier]\n' +- ' ("," identifier ["as" identifier])*\n' +- ' | "from" relative_module "import" "(" ' +- 'identifier ["as" identifier]\n' +- ' ("," identifier ["as" identifier])* [","] ")"\n' +- ' | "from" relative_module "import" "*"\n' +- ' module ::= (identifier ".")* identifier\n' +- ' relative_module ::= "."* module | "."+\n' +- '\n' +- 'The basic import statement (no "from" clause) is executed in two\n' +- 'steps:\n' +- '\n' +- '1. find a module, loading and initializing it if necessary\n' +- '\n' +- '2. define a name or names in the local namespace for the scope ' +- 'where\n' +- ' the "import" statement occurs.\n' +- '\n' +- 'When the statement contains multiple clauses (separated by commas) ' +- 'the\n' +- 'two steps are carried out separately for each clause, just as ' +- 'though\n' +- 'the clauses had been separated out into individual import ' +- 'statements.\n' +- '\n' +- 'The details of the first step, finding and loading modules, are\n' +- 'described in greater detail in the section on the import system, ' +- 'which\n' +- 'also describes the various types of packages and modules that can ' +- 'be\n' +- 'imported, as well as all the hooks that can be used to customize ' +- 'the\n' +- 'import system. Note that failures in this step may indicate ' +- 'either\n' +- 'that the module could not be located, *or* that an error occurred\n' +- 'while initializing the module, which includes execution of the\n' +- 'module’s code.\n' +- '\n' +- 'If the requested module is retrieved successfully, it will be ' +- 'made\n' +- 'available in the local namespace in one of three ways:\n' +- '\n' +- '* If the module name is followed by "as", then the name following ' +- '"as"\n' +- ' is bound directly to the imported module.\n' +- '\n' +- '* If no other name is specified, and the module being imported is ' +- 'a\n' +- ' top level module, the module’s name is bound in the local ' +- 'namespace\n' +- ' as a reference to the imported module\n' +- '\n' +- '* If the module being imported is *not* a top level module, then ' +- 'the\n' +- ' name of the top level package that contains the module is bound ' +- 'in\n' +- ' the local namespace as a reference to the top level package. ' +- 'The\n' +- ' imported module must be accessed using its full qualified name\n' +- ' rather than directly\n' +- '\n' +- 'The "from" form uses a slightly more complex process:\n' +- '\n' +- '1. find the module specified in the "from" clause, loading and\n' +- ' initializing it if necessary;\n' +- '\n' +- '2. for each of the identifiers specified in the "import" clauses:\n' +- '\n' +- ' 1. check if the imported module has an attribute by that name\n' +- '\n' +- ' 2. if not, attempt to import a submodule with that name and ' +- 'then\n' +- ' check the imported module again for that attribute\n' +- '\n' +- ' 3. if the attribute is not found, "ImportError" is raised.\n' +- '\n' +- ' 4. otherwise, a reference to that value is stored in the local\n' +- ' namespace, using the name in the "as" clause if it is ' +- 'present,\n' +- ' otherwise using the attribute name\n' +- '\n' +- 'Examples:\n' +- '\n' +- ' import foo # foo imported and bound locally\n' +- ' import foo.bar.baz # foo, foo.bar, and foo.bar.baz ' +- 'imported, foo bound locally\n' +- ' import foo.bar.baz as fbb # foo, foo.bar, and foo.bar.baz ' +- 'imported, foo.bar.baz bound as fbb\n' +- ' from foo.bar import baz # foo, foo.bar, and foo.bar.baz ' +- 'imported, foo.bar.baz bound as baz\n' +- ' from foo import attr # foo imported and foo.attr bound as ' +- 'attr\n' +- '\n' +- 'If the list of identifiers is replaced by a star ("\'*\'"), all ' +- 'public\n' +- 'names defined in the module are bound in the local namespace for ' +- 'the\n' +- 'scope where the "import" statement occurs.\n' +- '\n' +- 'The *public names* defined by a module are determined by checking ' +- 'the\n' +- 'module’s namespace for a variable named "__all__"; if defined, it ' +- 'must\n' +- 'be a sequence of strings which are names defined or imported by ' +- 'that\n' +- 'module. The names given in "__all__" are all considered public ' +- 'and\n' +- 'are required to exist. If "__all__" is not defined, the set of ' +- 'public\n' +- 'names includes all names found in the module’s namespace which do ' +- 'not\n' +- 'begin with an underscore character ("\'_\'"). "__all__" should ' +- 'contain\n' +- 'the entire public API. It is intended to avoid accidentally ' +- 'exporting\n' +- 'items that are not part of the API (such as library modules which ' +- 'were\n' +- 'imported and used within the module).\n' +- '\n' +- 'The wild card form of import — "from module import *" — is only\n' +- 'allowed at the module level. Attempting to use it in class or\n' +- 'function definitions will raise a "SyntaxError".\n' +- '\n' +- 'When specifying what module to import you do not have to specify ' +- 'the\n' +- 'absolute name of the module. When a module or package is ' +- 'contained\n' +- 'within another package it is possible to make a relative import ' +- 'within\n' +- 'the same top package without having to mention the package name. ' +- 'By\n' +- 'using leading dots in the specified module or package after "from" ' +- 'you\n' +- 'can specify how high to traverse up the current package hierarchy\n' +- 'without specifying exact names. One leading dot means the current\n' +- 'package where the module making the import exists. Two dots means ' +- 'up\n' +- 'one package level. Three dots is up two levels, etc. So if you ' +- 'execute\n' +- '"from . import mod" from a module in the "pkg" package then you ' +- 'will\n' +- 'end up importing "pkg.mod". If you execute "from ..subpkg2 import ' +- 'mod"\n' +- 'from within "pkg.subpkg1" you will import "pkg.subpkg2.mod". The\n' +- 'specification for relative imports is contained in the Package\n' +- 'Relative Imports section.\n' +- '\n' +- '"importlib.import_module()" is provided to support applications ' +- 'that\n' +- 'determine dynamically the modules to be loaded.\n' +- '\n' +- 'Raises an auditing event "import" with arguments "module", ' +- '"filename",\n' +- '"sys.path", "sys.meta_path", "sys.path_hooks".\n' +- '\n' +- '\n' +- 'Future statements\n' +- '=================\n' +- '\n' +- 'A *future statement* is a directive to the compiler that a ' +- 'particular\n' +- 'module should be compiled using syntax or semantics that will be\n' +- 'available in a specified future release of Python where the ' +- 'feature\n' +- 'becomes standard.\n' +- '\n' +- 'The future statement is intended to ease migration to future ' +- 'versions\n' +- 'of Python that introduce incompatible changes to the language. ' +- 'It\n' +- 'allows use of the new features on a per-module basis before the\n' +- 'release in which the feature becomes standard.\n' +- '\n' +- ' future_stmt ::= "from" "__future__" "import" feature ["as" ' +- 'identifier]\n' +- ' ("," feature ["as" identifier])*\n' +- ' | "from" "__future__" "import" "(" feature ' +- '["as" identifier]\n' +- ' ("," feature ["as" identifier])* [","] ")"\n' +- ' feature ::= identifier\n' +- '\n' +- 'A future statement must appear near the top of the module. The ' +- 'only\n' +- 'lines that can appear before a future statement are:\n' +- '\n' +- '* the module docstring (if any),\n' +- '\n' +- '* comments,\n' +- '\n' +- '* blank lines, and\n' +- '\n' +- '* other future statements.\n' +- '\n' +- 'The only feature that requires using the future statement is\n' +- '"annotations" (see **PEP 563**).\n' +- '\n' +- 'All historical features enabled by the future statement are still\n' +- 'recognized by Python 3. The list includes "absolute_import",\n' +- '"division", "generators", "generator_stop", "unicode_literals",\n' +- '"print_function", "nested_scopes" and "with_statement". They are ' +- 'all\n' +- 'redundant because they are always enabled, and only kept for ' +- 'backwards\n' +- 'compatibility.\n' +- '\n' +- 'A future statement is recognized and treated specially at compile\n' +- 'time: Changes to the semantics of core constructs are often\n' +- 'implemented by generating different code. It may even be the ' +- 'case\n' +- 'that a new feature introduces new incompatible syntax (such as a ' +- 'new\n' +- 'reserved word), in which case the compiler may need to parse the\n' +- 'module differently. Such decisions cannot be pushed off until\n' +- 'runtime.\n' +- '\n' +- 'For any given release, the compiler knows which feature names ' +- 'have\n' +- 'been defined, and raises a compile-time error if a future ' +- 'statement\n' +- 'contains a feature not known to it.\n' +- '\n' +- 'The direct runtime semantics are the same as for any import ' +- 'statement:\n' +- 'there is a standard module "__future__", described later, and it ' +- 'will\n' +- 'be imported in the usual way at the time the future statement is\n' +- 'executed.\n' +- '\n' +- 'The interesting runtime semantics depend on the specific feature\n' +- 'enabled by the future statement.\n' +- '\n' +- 'Note that there is nothing special about the statement:\n' +- '\n' +- ' import __future__ [as name]\n' +- '\n' +- 'That is not a future statement; it’s an ordinary import statement ' +- 'with\n' +- 'no special semantics or syntax restrictions.\n' +- '\n' +- 'Code compiled by calls to the built-in functions "exec()" and\n' +- '"compile()" that occur in a module "M" containing a future ' +- 'statement\n' +- 'will, by default, use the new syntax or semantics associated with ' +- 'the\n' +- 'future statement. This can be controlled by optional arguments ' +- 'to\n' +- '"compile()" — see the documentation of that function for details.\n' +- '\n' +- 'A future statement typed at an interactive interpreter prompt ' +- 'will\n' +- 'take effect for the rest of the interpreter session. If an\n' +- 'interpreter is started with the "-i" option, is passed a script ' +- 'name\n' +- 'to execute, and the script includes a future statement, it will be ' +- 'in\n' +- 'effect in the interactive session started after the script is\n' +- 'executed.\n' +- '\n' +- 'See also:\n' +- '\n' +- ' **PEP 236** - Back to the __future__\n' +- ' The original proposal for the __future__ mechanism.\n', +- 'in': 'Membership test operations\n' +- '**************************\n' +- '\n' +- 'The operators "in" and "not in" test for membership. "x in s"\n' +- 'evaluates to "True" if *x* is a member of *s*, and "False" otherwise.\n' +- '"x not in s" returns the negation of "x in s". All built-in ' +- 'sequences\n' +- 'and set types support this as well as dictionary, for which "in" ' +- 'tests\n' +- 'whether the dictionary has a given key. For container types such as\n' +- 'list, tuple, set, frozenset, dict, or collections.deque, the\n' +- 'expression "x in y" is equivalent to "any(x is e or x == e for e in\n' +- 'y)".\n' +- '\n' +- 'For the string and bytes types, "x in y" is "True" if and only if *x*\n' +- 'is a substring of *y*. An equivalent test is "y.find(x) != -1".\n' +- 'Empty strings are always considered to be a substring of any other\n' +- 'string, so """ in "abc"" will return "True".\n' +- '\n' +- 'For user-defined classes which define the "__contains__()" method, "x\n' +- 'in y" returns "True" if "y.__contains__(x)" returns a true value, and\n' +- '"False" otherwise.\n' +- '\n' +- 'For user-defined classes which do not define "__contains__()" but do\n' +- 'define "__iter__()", "x in y" is "True" if some value "z", for which\n' +- 'the expression "x is z or x == z" is true, is produced while ' +- 'iterating\n' +- 'over "y". If an exception is raised during the iteration, it is as if\n' +- '"in" raised that exception.\n' +- '\n' +- 'Lastly, the old-style iteration protocol is tried: if a class defines\n' +- '"__getitem__()", "x in y" is "True" if and only if there is a non-\n' +- 'negative integer index *i* such that "x is y[i] or x == y[i]", and no\n' +- 'lower integer index raises the "IndexError" exception. (If any other\n' +- 'exception is raised, it is as if "in" raised that exception).\n' +- '\n' +- 'The operator "not in" is defined to have the inverse truth value of\n' +- '"in".\n', +- 'integers': 'Integer literals\n' +- '****************\n' +- '\n' +- 'Integer literals are described by the following lexical ' +- 'definitions:\n' +- '\n' +- ' integer ::= decinteger | bininteger | octinteger | ' +- 'hexinteger\n' +- ' decinteger ::= nonzerodigit (["_"] digit)* | "0"+ (["_"] ' +- '"0")*\n' +- ' bininteger ::= "0" ("b" | "B") (["_"] bindigit)+\n' +- ' octinteger ::= "0" ("o" | "O") (["_"] octdigit)+\n' +- ' hexinteger ::= "0" ("x" | "X") (["_"] hexdigit)+\n' +- ' nonzerodigit ::= "1"..."9"\n' +- ' digit ::= "0"..."9"\n' +- ' bindigit ::= "0" | "1"\n' +- ' octdigit ::= "0"..."7"\n' +- ' hexdigit ::= digit | "a"..."f" | "A"..."F"\n' +- '\n' +- 'There is no limit for the length of integer literals apart from ' +- 'what\n' +- 'can be stored in available memory.\n' +- '\n' +- 'Underscores are ignored for determining the numeric value of ' +- 'the\n' +- 'literal. They can be used to group digits for enhanced ' +- 'readability.\n' +- 'One underscore can occur between digits, and after base ' +- 'specifiers\n' +- 'like "0x".\n' +- '\n' +- 'Note that leading zeros in a non-zero decimal number are not ' +- 'allowed.\n' +- 'This is for disambiguation with C-style octal literals, which ' +- 'Python\n' +- 'used before version 3.0.\n' +- '\n' +- 'Some examples of integer literals:\n' +- '\n' +- ' 7 2147483647 0o177 0b100110111\n' +- ' 3 79228162514264337593543950336 0o377 0xdeadbeef\n' +- ' 100_000_000_000 0b_1110_0101\n' +- '\n' +- 'Changed in version 3.6: Underscores are now allowed for ' +- 'grouping\n' +- 'purposes in literals.\n', +- 'lambda': 'Lambdas\n' +- '*******\n' +- '\n' +- ' lambda_expr ::= "lambda" [parameter_list] ":" expression\n' +- '\n' +- 'Lambda expressions (sometimes called lambda forms) are used to ' +- 'create\n' +- 'anonymous functions. The expression "lambda parameters: ' +- 'expression"\n' +- 'yields a function object. The unnamed object behaves like a ' +- 'function\n' +- 'object defined with:\n' +- '\n' +- ' def (parameters):\n' +- ' return expression\n' +- '\n' +- 'See section Function definitions for the syntax of parameter ' +- 'lists.\n' +- 'Note that functions created with lambda expressions cannot ' +- 'contain\n' +- 'statements or annotations.\n', +- 'lists': 'List displays\n' +- '*************\n' +- '\n' +- 'A list display is a possibly empty series of expressions enclosed ' +- 'in\n' +- 'square brackets:\n' +- '\n' +- ' list_display ::= "[" [flexible_expression_list | comprehension] ' +- '"]"\n' +- '\n' +- 'A list display yields a new list object, the contents being ' +- 'specified\n' +- 'by either a list of expressions or a comprehension. When a comma-\n' +- 'separated list of expressions is supplied, its elements are ' +- 'evaluated\n' +- 'from left to right and placed into the list object in that order.\n' +- 'When a comprehension is supplied, the list is constructed from the\n' +- 'elements resulting from the comprehension.\n', +- 'naming': 'Naming and binding\n' +- '******************\n' +- '\n' +- '\n' +- 'Binding of names\n' +- '================\n' +- '\n' +- '*Names* refer to objects. Names are introduced by name binding\n' +- 'operations.\n' +- '\n' +- 'The following constructs bind names:\n' +- '\n' +- '* formal parameters to functions,\n' +- '\n' +- '* class definitions,\n' +- '\n' +- '* function definitions,\n' +- '\n' +- '* assignment expressions,\n' +- '\n' +- '* targets that are identifiers if occurring in an assignment:\n' +- '\n' +- ' * "for" loop header,\n' +- '\n' +- ' * after "as" in a "with" statement, "except" clause, "except*"\n' +- ' clause, or in the as-pattern in structural pattern matching,\n' +- '\n' +- ' * in a capture pattern in structural pattern matching\n' +- '\n' +- '* "import" statements.\n' +- '\n' +- '* "type" statements.\n' +- '\n' +- '* type parameter lists.\n' +- '\n' +- 'The "import" statement of the form "from ... import *" binds all ' +- 'names\n' +- 'defined in the imported module, except those beginning with an\n' +- 'underscore. This form may only be used at the module level.\n' +- '\n' +- 'A target occurring in a "del" statement is also considered bound ' +- 'for\n' +- 'this purpose (though the actual semantics are to unbind the ' +- 'name).\n' +- '\n' +- 'Each assignment or import statement occurs within a block defined ' +- 'by a\n' +- 'class or function definition or at the module level (the ' +- 'top-level\n' +- 'code block).\n' +- '\n' +- 'If a name is bound in a block, it is a local variable of that ' +- 'block,\n' +- 'unless declared as "nonlocal" or "global". If a name is bound at ' +- 'the\n' +- 'module level, it is a global variable. (The variables of the ' +- 'module\n' +- 'code block are local and global.) If a variable is used in a ' +- 'code\n' +- 'block but not defined there, it is a *free variable*.\n' +- '\n' +- 'Each occurrence of a name in the program text refers to the ' +- '*binding*\n' +- 'of that name established by the following name resolution rules.\n' +- '\n' +- '\n' +- 'Resolution of names\n' +- '===================\n' +- '\n' +- 'A *scope* defines the visibility of a name within a block. If a ' +- 'local\n' +- 'variable is defined in a block, its scope includes that block. If ' +- 'the\n' +- 'definition occurs in a function block, the scope extends to any ' +- 'blocks\n' +- 'contained within the defining one, unless a contained block ' +- 'introduces\n' +- 'a different binding for the name.\n' +- '\n' +- 'When a name is used in a code block, it is resolved using the ' +- 'nearest\n' +- 'enclosing scope. The set of all such scopes visible to a code ' +- 'block\n' +- 'is called the block’s *environment*.\n' +- '\n' +- 'When a name is not found at all, a "NameError" exception is ' +- 'raised. If\n' +- 'the current scope is a function scope, and the name refers to a ' +- 'local\n' +- 'variable that has not yet been bound to a value at the point where ' +- 'the\n' +- 'name is used, an "UnboundLocalError" exception is raised.\n' +- '"UnboundLocalError" is a subclass of "NameError".\n' +- '\n' +- 'If a name binding operation occurs anywhere within a code block, ' +- 'all\n' +- 'uses of the name within the block are treated as references to ' +- 'the\n' +- 'current block. This can lead to errors when a name is used within ' +- 'a\n' +- 'block before it is bound. This rule is subtle. Python lacks\n' +- 'declarations and allows name binding operations to occur anywhere\n' +- 'within a code block. The local variables of a code block can be\n' +- 'determined by scanning the entire text of the block for name ' +- 'binding\n' +- 'operations. See the FAQ entry on UnboundLocalError for examples.\n' +- '\n' +- 'If the "global" statement occurs within a block, all uses of the ' +- 'names\n' +- 'specified in the statement refer to the bindings of those names in ' +- 'the\n' +- 'top-level namespace. Names are resolved in the top-level ' +- 'namespace by\n' +- 'searching the global namespace, i.e. the namespace of the module\n' +- 'containing the code block, and the builtins namespace, the ' +- 'namespace\n' +- 'of the module "builtins". The global namespace is searched ' +- 'first. If\n' +- 'the names are not found there, the builtins namespace is searched\n' +- 'next. If the names are also not found in the builtins namespace, ' +- 'new\n' +- 'variables are created in the global namespace. The global ' +- 'statement\n' +- 'must precede all uses of the listed names.\n' +- '\n' +- 'The "global" statement has the same scope as a name binding ' +- 'operation\n' +- 'in the same block. If the nearest enclosing scope for a free ' +- 'variable\n' +- 'contains a global statement, the free variable is treated as a ' +- 'global.\n' +- '\n' +- 'The "nonlocal" statement causes corresponding names to refer to\n' +- 'previously bound variables in the nearest enclosing function ' +- 'scope.\n' +- '"SyntaxError" is raised at compile time if the given name does ' +- 'not\n' +- 'exist in any enclosing function scope. Type parameters cannot be\n' +- 'rebound with the "nonlocal" statement.\n' +- '\n' +- 'The namespace for a module is automatically created the first time ' +- 'a\n' +- 'module is imported. The main module for a script is always ' +- 'called\n' +- '"__main__".\n' +- '\n' +- 'Class definition blocks and arguments to "exec()" and "eval()" ' +- 'are\n' +- 'special in the context of name resolution. A class definition is ' +- 'an\n' +- 'executable statement that may use and define names. These ' +- 'references\n' +- 'follow the normal rules for name resolution with an exception ' +- 'that\n' +- 'unbound local variables are looked up in the global namespace. ' +- 'The\n' +- 'namespace of the class definition becomes the attribute dictionary ' +- 'of\n' +- 'the class. The scope of names defined in a class block is limited ' +- 'to\n' +- 'the class block; it does not extend to the code blocks of ' +- 'methods.\n' +- 'This includes comprehensions and generator expressions, but it ' +- 'does\n' +- 'not include annotation scopes, which have access to their ' +- 'enclosing\n' +- 'class scopes. This means that the following will fail:\n' +- '\n' +- ' class A:\n' +- ' a = 42\n' +- ' b = list(a + i for i in range(10))\n' +- '\n' +- 'However, the following will succeed:\n' +- '\n' +- ' class A:\n' +- ' type Alias = Nested\n' +- ' class Nested: pass\n' +- '\n' +- " print(A.Alias.__value__) # \n" +- '\n' +- '\n' +- 'Annotation scopes\n' +- '=================\n' +- '\n' +- '*Annotations*, type parameter lists and "type" statements ' +- 'introduce\n' +- '*annotation scopes*, which behave mostly like function scopes, ' +- 'but\n' +- 'with some exceptions discussed below.\n' +- '\n' +- 'Annotation scopes are used in the following contexts:\n' +- '\n' +- '* *Function annotations*.\n' +- '\n' +- '* *Variable annotations*.\n' +- '\n' +- '* Type parameter lists for generic type aliases.\n' +- '\n' +- '* Type parameter lists for generic functions. A generic ' +- 'function’s\n' +- ' annotations are executed within the annotation scope, but its\n' +- ' defaults and decorators are not.\n' +- '\n' +- '* Type parameter lists for generic classes. A generic class’s ' +- 'base\n' +- ' classes and keyword arguments are executed within the ' +- 'annotation\n' +- ' scope, but its decorators are not.\n' +- '\n' +- '* The bounds, constraints, and default values for type parameters\n' +- ' (lazily evaluated).\n' +- '\n' +- '* The value of type aliases (lazily evaluated).\n' +- '\n' +- 'Annotation scopes differ from function scopes in the following ' +- 'ways:\n' +- '\n' +- '* Annotation scopes have access to their enclosing class ' +- 'namespace. If\n' +- ' an annotation scope is immediately within a class scope, or ' +- 'within\n' +- ' another annotation scope that is immediately within a class ' +- 'scope,\n' +- ' the code in the annotation scope can use names defined in the ' +- 'class\n' +- ' scope as if it were executed directly within the class body. ' +- 'This\n' +- ' contrasts with regular functions defined within classes, which\n' +- ' cannot access names defined in the class scope.\n' +- '\n' +- '* Expressions in annotation scopes cannot contain "yield", "yield\n' +- ' from", "await", or ":=" expressions. (These expressions are ' +- 'allowed\n' +- ' in other scopes contained within the annotation scope.)\n' +- '\n' +- '* Names defined in annotation scopes cannot be rebound with ' +- '"nonlocal"\n' +- ' statements in inner scopes. This includes only type parameters, ' +- 'as\n' +- ' no other syntactic elements that can appear within annotation ' +- 'scopes\n' +- ' can introduce new names.\n' +- '\n' +- '* While annotation scopes have an internal name, that name is not\n' +- ' reflected in the *qualified name* of objects defined within the\n' +- ' scope. Instead, the "__qualname__" of such objects is as if the\n' +- ' object were defined in the enclosing scope.\n' +- '\n' +- 'Added in version 3.12: Annotation scopes were introduced in ' +- 'Python\n' +- '3.12 as part of **PEP 695**.\n' +- '\n' +- 'Changed in version 3.13: Annotation scopes are also used for type\n' +- 'parameter defaults, as introduced by **PEP 696**.\n' +- '\n' +- 'Changed in version 3.14: Annotation scopes are now also used for\n' +- 'annotations, as specified in **PEP 649** and **PEP 749**.\n' +- '\n' +- '\n' +- 'Lazy evaluation\n' +- '===============\n' +- '\n' +- 'Most annotation scopes are *lazily evaluated*. This includes\n' +- 'annotations, the values of type aliases created through the ' +- '"type"\n' +- 'statement, and the bounds, constraints, and default values of ' +- 'type\n' +- 'variables created through the type parameter syntax. This means ' +- 'that\n' +- 'they are not evaluated when the type alias or type variable is\n' +- 'created, or when the object carrying annotations is created. ' +- 'Instead,\n' +- 'they are only evaluated when necessary, for example when the\n' +- '"__value__" attribute on a type alias is accessed.\n' +- '\n' +- 'Example:\n' +- '\n' +- ' >>> type Alias = 1/0\n' +- ' >>> Alias.__value__\n' +- ' Traceback (most recent call last):\n' +- ' ...\n' +- ' ZeroDivisionError: division by zero\n' +- ' >>> def func[T: 1/0](): pass\n' +- ' >>> T = func.__type_params__[0]\n' +- ' >>> T.__bound__\n' +- ' Traceback (most recent call last):\n' +- ' ...\n' +- ' ZeroDivisionError: division by zero\n' +- '\n' +- 'Here the exception is raised only when the "__value__" attribute ' +- 'of\n' +- 'the type alias or the "__bound__" attribute of the type variable ' +- 'is\n' +- 'accessed.\n' +- '\n' +- 'This behavior is primarily useful for references to types that ' +- 'have\n' +- 'not yet been defined when the type alias or type variable is ' +- 'created.\n' +- 'For example, lazy evaluation enables creation of mutually ' +- 'recursive\n' +- 'type aliases:\n' +- '\n' +- ' from typing import Literal\n' +- '\n' +- ' type SimpleExpr = int | Parenthesized\n' +- ' type Parenthesized = tuple[Literal["("], Expr, Literal[")"]]\n' +- ' type Expr = SimpleExpr | tuple[SimpleExpr, Literal["+", "-"], ' +- 'Expr]\n' +- '\n' +- 'Lazily evaluated values are evaluated in annotation scope, which ' +- 'means\n' +- 'that names that appear inside the lazily evaluated value are ' +- 'looked up\n' +- 'as if they were used in the immediately enclosing scope.\n' +- '\n' +- 'Added in version 3.12.\n' +- '\n' +- '\n' +- 'Builtins and restricted execution\n' +- '=================================\n' +- '\n' +- '**CPython implementation detail:** Users should not touch\n' +- '"__builtins__"; it is strictly an implementation detail. Users\n' +- 'wanting to override values in the builtins namespace should ' +- '"import"\n' +- 'the "builtins" module and modify its attributes appropriately.\n' +- '\n' +- 'The builtins namespace associated with the execution of a code ' +- 'block\n' +- 'is actually found by looking up the name "__builtins__" in its ' +- 'global\n' +- 'namespace; this should be a dictionary or a module (in the latter ' +- 'case\n' +- 'the module’s dictionary is used). By default, when in the ' +- '"__main__"\n' +- 'module, "__builtins__" is the built-in module "builtins"; when in ' +- 'any\n' +- 'other module, "__builtins__" is an alias for the dictionary of ' +- 'the\n' +- '"builtins" module itself.\n' +- '\n' +- '\n' +- 'Interaction with dynamic features\n' +- '=================================\n' +- '\n' +- 'Name resolution of free variables occurs at runtime, not at ' +- 'compile\n' +- 'time. This means that the following code will print 42:\n' +- '\n' +- ' i = 10\n' +- ' def f():\n' +- ' print(i)\n' +- ' i = 42\n' +- ' f()\n' +- '\n' +- 'The "eval()" and "exec()" functions do not have access to the ' +- 'full\n' +- 'environment for resolving names. Names may be resolved in the ' +- 'local\n' +- 'and global namespaces of the caller. Free variables are not ' +- 'resolved\n' +- 'in the nearest enclosing namespace, but in the global namespace. ' +- '[1]\n' +- 'The "exec()" and "eval()" functions have optional arguments to\n' +- 'override the global and local namespace. If only one namespace ' +- 'is\n' +- 'specified, it is used for both.\n', +- 'nonlocal': 'The "nonlocal" statement\n' +- '************************\n' +- '\n' +- ' nonlocal_stmt ::= "nonlocal" identifier ("," identifier)*\n' +- '\n' +- 'When the definition of a function or class is nested (enclosed) ' +- 'within\n' +- 'the definitions of other functions, its nonlocal scopes are the ' +- 'local\n' +- 'scopes of the enclosing functions. The "nonlocal" statement ' +- 'causes the\n' +- 'listed identifiers to refer to names previously bound in ' +- 'nonlocal\n' +- 'scopes. It allows encapsulated code to rebind such nonlocal\n' +- 'identifiers. If a name is bound in more than one nonlocal ' +- 'scope, the\n' +- 'nearest binding is used. If a name is not bound in any nonlocal ' +- 'scope,\n' +- 'or if there is no nonlocal scope, a "SyntaxError" is raised.\n' +- '\n' +- 'The "nonlocal" statement applies to the entire scope of a ' +- 'function or\n' +- 'class body. A "SyntaxError" is raised if a variable is used or\n' +- 'assigned to prior to its nonlocal declaration in the scope.\n' +- '\n' +- 'See also:\n' +- '\n' +- ' **PEP 3104** - Access to Names in Outer Scopes\n' +- ' The specification for the "nonlocal" statement.\n' +- '\n' +- '**Programmer’s note:** "nonlocal" is a directive to the parser ' +- 'and\n' +- 'applies only to code parsed along with it. See the note for ' +- 'the\n' +- '"global" statement.\n', +- 'numbers': 'Numeric literals\n' +- '****************\n' +- '\n' +- 'There are three types of numeric literals: integers, ' +- 'floating-point\n' +- 'numbers, and imaginary numbers. There are no complex literals\n' +- '(complex numbers can be formed by adding a real number and an\n' +- 'imaginary number).\n' +- '\n' +- 'Note that numeric literals do not include a sign; a phrase like ' +- '"-1"\n' +- 'is actually an expression composed of the unary operator ‘"-"’ ' +- 'and the\n' +- 'literal "1".\n', +- 'numeric-types': 'Emulating numeric types\n' +- '***********************\n' +- '\n' +- 'The following methods can be defined to emulate numeric ' +- 'objects.\n' +- 'Methods corresponding to operations that are not supported ' +- 'by the\n' +- 'particular kind of number implemented (e.g., bitwise ' +- 'operations for\n' +- 'non-integral numbers) should be left undefined.\n' +- '\n' +- 'object.__add__(self, other)\n' +- 'object.__sub__(self, other)\n' +- 'object.__mul__(self, other)\n' +- 'object.__matmul__(self, other)\n' +- 'object.__truediv__(self, other)\n' +- 'object.__floordiv__(self, other)\n' +- 'object.__mod__(self, other)\n' +- 'object.__divmod__(self, other)\n' +- 'object.__pow__(self, other[, modulo])\n' +- 'object.__lshift__(self, other)\n' +- 'object.__rshift__(self, other)\n' +- 'object.__and__(self, other)\n' +- 'object.__xor__(self, other)\n' +- 'object.__or__(self, other)\n' +- '\n' +- ' These methods are called to implement the binary ' +- 'arithmetic\n' +- ' operations ("+", "-", "*", "@", "/", "//", "%", ' +- '"divmod()",\n' +- ' "pow()", "**", "<<", ">>", "&", "^", "|"). For ' +- 'instance, to\n' +- ' evaluate the expression "x + y", where *x* is an ' +- 'instance of a\n' +- ' class that has an "__add__()" method, ' +- '"type(x).__add__(x, y)" is\n' +- ' called. The "__divmod__()" method should be the ' +- 'equivalent to\n' +- ' using "__floordiv__()" and "__mod__()"; it should not be ' +- 'related to\n' +- ' "__truediv__()". Note that "__pow__()" should be ' +- 'defined to accept\n' +- ' an optional third argument if the ternary version of the ' +- 'built-in\n' +- ' "pow()" function is to be supported.\n' +- '\n' +- ' If one of those methods does not support the operation ' +- 'with the\n' +- ' supplied arguments, it should return "NotImplemented".\n' +- '\n' +- 'object.__radd__(self, other)\n' +- 'object.__rsub__(self, other)\n' +- 'object.__rmul__(self, other)\n' +- 'object.__rmatmul__(self, other)\n' +- 'object.__rtruediv__(self, other)\n' +- 'object.__rfloordiv__(self, other)\n' +- 'object.__rmod__(self, other)\n' +- 'object.__rdivmod__(self, other)\n' +- 'object.__rpow__(self, other[, modulo])\n' +- 'object.__rlshift__(self, other)\n' +- 'object.__rrshift__(self, other)\n' +- 'object.__rand__(self, other)\n' +- 'object.__rxor__(self, other)\n' +- 'object.__ror__(self, other)\n' +- '\n' +- ' These methods are called to implement the binary ' +- 'arithmetic\n' +- ' operations ("+", "-", "*", "@", "/", "//", "%", ' +- '"divmod()",\n' +- ' "pow()", "**", "<<", ">>", "&", "^", "|") with reflected ' +- '(swapped)\n' +- ' operands. These functions are only called if the ' +- 'operands are of\n' +- ' different types, when the left operand does not support ' +- 'the\n' +- ' corresponding operation [3], or the right operand’s ' +- 'class is\n' +- ' derived from the left operand’s class. [4] For instance, ' +- 'to\n' +- ' evaluate the expression "x - y", where *y* is an ' +- 'instance of a\n' +- ' class that has an "__rsub__()" method, ' +- '"type(y).__rsub__(y, x)" is\n' +- ' called if "type(x).__sub__(x, y)" returns ' +- '"NotImplemented" or\n' +- ' "type(y)" is a subclass of "type(x)". [5]\n' +- '\n' +- ' Note that ternary "pow()" will not try calling ' +- '"__rpow__()" (the\n' +- ' coercion rules would become too complicated).\n' +- '\n' +- ' Note:\n' +- '\n' +- ' If the right operand’s type is a subclass of the left ' +- 'operand’s\n' +- ' type and that subclass provides a different ' +- 'implementation of the\n' +- ' reflected method for the operation, this method will ' +- 'be called\n' +- ' before the left operand’s non-reflected method. This ' +- 'behavior\n' +- ' allows subclasses to override their ancestors’ ' +- 'operations.\n' +- '\n' +- 'object.__iadd__(self, other)\n' +- 'object.__isub__(self, other)\n' +- 'object.__imul__(self, other)\n' +- 'object.__imatmul__(self, other)\n' +- 'object.__itruediv__(self, other)\n' +- 'object.__ifloordiv__(self, other)\n' +- 'object.__imod__(self, other)\n' +- 'object.__ipow__(self, other[, modulo])\n' +- 'object.__ilshift__(self, other)\n' +- 'object.__irshift__(self, other)\n' +- 'object.__iand__(self, other)\n' +- 'object.__ixor__(self, other)\n' +- 'object.__ior__(self, other)\n' +- '\n' +- ' These methods are called to implement the augmented ' +- 'arithmetic\n' +- ' assignments ("+=", "-=", "*=", "@=", "/=", "//=", "%=", ' +- '"**=",\n' +- ' "<<=", ">>=", "&=", "^=", "|="). These methods should ' +- 'attempt to\n' +- ' do the operation in-place (modifying *self*) and return ' +- 'the result\n' +- ' (which could be, but does not have to be, *self*). If a ' +- 'specific\n' +- ' method is not defined, or if that method returns ' +- '"NotImplemented",\n' +- ' the augmented assignment falls back to the normal ' +- 'methods. For\n' +- ' instance, if *x* is an instance of a class with an ' +- '"__iadd__()"\n' +- ' method, "x += y" is equivalent to "x = x.__iadd__(y)" . ' +- 'If\n' +- ' "__iadd__()" does not exist, or if "x.__iadd__(y)" ' +- 'returns\n' +- ' "NotImplemented", "x.__add__(y)" and "y.__radd__(x)" ' +- 'are\n' +- ' considered, as with the evaluation of "x + y". In ' +- 'certain\n' +- ' situations, augmented assignment can result in ' +- 'unexpected errors\n' +- ' (see Why does a_tuple[i] += [‘item’] raise an exception ' +- 'when the\n' +- ' addition works?), but this behavior is in fact part of ' +- 'the data\n' +- ' model.\n' +- '\n' +- 'object.__neg__(self)\n' +- 'object.__pos__(self)\n' +- 'object.__abs__(self)\n' +- 'object.__invert__(self)\n' +- '\n' +- ' Called to implement the unary arithmetic operations ' +- '("-", "+",\n' +- ' "abs()" and "~").\n' +- '\n' +- 'object.__complex__(self)\n' +- 'object.__int__(self)\n' +- 'object.__float__(self)\n' +- '\n' +- ' Called to implement the built-in functions "complex()", ' +- '"int()" and\n' +- ' "float()". Should return a value of the appropriate ' +- 'type.\n' +- '\n' +- 'object.__index__(self)\n' +- '\n' +- ' Called to implement "operator.index()", and whenever ' +- 'Python needs\n' +- ' to losslessly convert the numeric object to an integer ' +- 'object (such\n' +- ' as in slicing, or in the built-in "bin()", "hex()" and ' +- '"oct()"\n' +- ' functions). Presence of this method indicates that the ' +- 'numeric\n' +- ' object is an integer type. Must return an integer.\n' +- '\n' +- ' If "__int__()", "__float__()" and "__complex__()" are ' +- 'not defined\n' +- ' then corresponding built-in functions "int()", "float()" ' +- 'and\n' +- ' "complex()" fall back to "__index__()".\n' +- '\n' +- 'object.__round__(self[, ndigits])\n' +- 'object.__trunc__(self)\n' +- 'object.__floor__(self)\n' +- 'object.__ceil__(self)\n' +- '\n' +- ' Called to implement the built-in function "round()" and ' +- '"math"\n' +- ' functions "trunc()", "floor()" and "ceil()". Unless ' +- '*ndigits* is\n' +- ' passed to "__round__()" all these methods should return ' +- 'the value\n' +- ' of the object truncated to an "Integral" (typically an ' +- '"int").\n' +- '\n' +- ' Changed in version 3.14: "int()" no longer delegates to ' +- 'the\n' +- ' "__trunc__()" method.\n', +- 'objects': 'Objects, values and types\n' +- '*************************\n' +- '\n' +- '*Objects* are Python’s abstraction for data. All data in a ' +- 'Python\n' +- 'program is represented by objects or by relations between ' +- 'objects. (In\n' +- 'a sense, and in conformance to Von Neumann’s model of a “stored\n' +- 'program computerâ€, code is also represented by objects.)\n' +- '\n' +- 'Every object has an identity, a type and a value. An object’s\n' +- '*identity* never changes once it has been created; you may think ' +- 'of it\n' +- 'as the object’s address in memory. The "is" operator compares ' +- 'the\n' +- 'identity of two objects; the "id()" function returns an integer\n' +- 'representing its identity.\n' +- '\n' +- '**CPython implementation detail:** For CPython, "id(x)" is the ' +- 'memory\n' +- 'address where "x" is stored.\n' +- '\n' +- 'An object’s type determines the operations that the object ' +- 'supports\n' +- '(e.g., “does it have a length?â€) and also defines the possible ' +- 'values\n' +- 'for objects of that type. The "type()" function returns an ' +- 'object’s\n' +- 'type (which is an object itself). Like its identity, an ' +- 'object’s\n' +- '*type* is also unchangeable. [1]\n' +- '\n' +- 'The *value* of some objects can change. Objects whose value can\n' +- 'change are said to be *mutable*; objects whose value is ' +- 'unchangeable\n' +- 'once they are created are called *immutable*. (The value of an\n' +- 'immutable container object that contains a reference to a ' +- 'mutable\n' +- 'object can change when the latter’s value is changed; however ' +- 'the\n' +- 'container is still considered immutable, because the collection ' +- 'of\n' +- 'objects it contains cannot be changed. So, immutability is not\n' +- 'strictly the same as having an unchangeable value, it is more ' +- 'subtle.)\n' +- 'An object’s mutability is determined by its type; for instance,\n' +- 'numbers, strings and tuples are immutable, while dictionaries ' +- 'and\n' +- 'lists are mutable.\n' +- '\n' +- 'Objects are never explicitly destroyed; however, when they ' +- 'become\n' +- 'unreachable they may be garbage-collected. An implementation is\n' +- 'allowed to postpone garbage collection or omit it altogether — it ' +- 'is a\n' +- 'matter of implementation quality how garbage collection is\n' +- 'implemented, as long as no objects are collected that are still\n' +- 'reachable.\n' +- '\n' +- '**CPython implementation detail:** CPython currently uses a ' +- 'reference-\n' +- 'counting scheme with (optional) delayed detection of cyclically ' +- 'linked\n' +- 'garbage, which collects most objects as soon as they become\n' +- 'unreachable, but is not guaranteed to collect garbage containing\n' +- 'circular references. See the documentation of the "gc" module ' +- 'for\n' +- 'information on controlling the collection of cyclic garbage. ' +- 'Other\n' +- 'implementations act differently and CPython may change. Do not ' +- 'depend\n' +- 'on immediate finalization of objects when they become unreachable ' +- '(so\n' +- 'you should always close files explicitly).\n' +- '\n' +- 'Note that the use of the implementation’s tracing or debugging\n' +- 'facilities may keep objects alive that would normally be ' +- 'collectable.\n' +- 'Also note that catching an exception with a "try"…"except" ' +- 'statement\n' +- 'may keep objects alive.\n' +- '\n' +- 'Some objects contain references to “external†resources such as ' +- 'open\n' +- 'files or windows. It is understood that these resources are ' +- 'freed\n' +- 'when the object is garbage-collected, but since garbage ' +- 'collection is\n' +- 'not guaranteed to happen, such objects also provide an explicit ' +- 'way to\n' +- 'release the external resource, usually a "close()" method. ' +- 'Programs\n' +- 'are strongly recommended to explicitly close such objects. The\n' +- '"try"…"finally" statement and the "with" statement provide ' +- 'convenient\n' +- 'ways to do this.\n' +- '\n' +- 'Some objects contain references to other objects; these are ' +- 'called\n' +- '*containers*. Examples of containers are tuples, lists and\n' +- 'dictionaries. The references are part of a container’s value. ' +- 'In\n' +- 'most cases, when we talk about the value of a container, we imply ' +- 'the\n' +- 'values, not the identities of the contained objects; however, ' +- 'when we\n' +- 'talk about the mutability of a container, only the identities of ' +- 'the\n' +- 'immediately contained objects are implied. So, if an immutable\n' +- 'container (like a tuple) contains a reference to a mutable ' +- 'object, its\n' +- 'value changes if that mutable object is changed.\n' +- '\n' +- 'Types affect almost all aspects of object behavior. Even the\n' +- 'importance of object identity is affected in some sense: for ' +- 'immutable\n' +- 'types, operations that compute new values may actually return a\n' +- 'reference to any existing object with the same type and value, ' +- 'while\n' +- 'for mutable objects this is not allowed. For example, after "a = ' +- '1; b\n' +- '= 1", *a* and *b* may or may not refer to the same object with ' +- 'the\n' +- 'value one, depending on the implementation. This is because "int" ' +- 'is\n' +- 'an immutable type, so the reference to "1" can be reused. This\n' +- 'behaviour depends on the implementation used, so should not be ' +- 'relied\n' +- 'upon, but is something to be aware of when making use of object\n' +- 'identity tests. However, after "c = []; d = []", *c* and *d* are\n' +- 'guaranteed to refer to two different, unique, newly created ' +- 'empty\n' +- 'lists. (Note that "e = f = []" assigns the *same* object to both ' +- '*e*\n' +- 'and *f*.)\n', +- 'operator-summary': 'Operator precedence\n' +- '*******************\n' +- '\n' +- 'The following table summarizes the operator precedence ' +- 'in Python, from\n' +- 'highest precedence (most binding) to lowest precedence ' +- '(least\n' +- 'binding). Operators in the same box have the same ' +- 'precedence. Unless\n' +- 'the syntax is explicitly given, operators are binary. ' +- 'Operators in\n' +- 'the same box group left to right (except for ' +- 'exponentiation and\n' +- 'conditional expressions, which group from right to ' +- 'left).\n' +- '\n' +- 'Note that comparisons, membership tests, and identity ' +- 'tests, all have\n' +- 'the same precedence and have a left-to-right chaining ' +- 'feature as\n' +- 'described in the Comparisons section.\n' +- '\n' +- '+-------------------------------------------------+---------------------------------------+\n' +- '| Operator | ' +- 'Description |\n' +- '|=================================================|=======================================|\n' +- '| "(expressions...)", "[expressions...]", "{key: | ' +- 'Binding or parenthesized expression, |\n' +- '| value...}", "{expressions...}" | list ' +- 'display, dictionary display, set |\n' +- '| | ' +- 'display |\n' +- '+-------------------------------------------------+---------------------------------------+\n' +- '| "x[index]", "x[index:index]", | ' +- 'Subscription, slicing, call, |\n' +- '| "x(arguments...)", "x.attribute" | ' +- 'attribute reference |\n' +- '+-------------------------------------------------+---------------------------------------+\n' +- '| "await x" | ' +- 'Await expression |\n' +- '+-------------------------------------------------+---------------------------------------+\n' +- '| "**" | ' +- 'Exponentiation [5] |\n' +- '+-------------------------------------------------+---------------------------------------+\n' +- '| "+x", "-x", "~x" | ' +- 'Positive, negative, bitwise NOT |\n' +- '+-------------------------------------------------+---------------------------------------+\n' +- '| "*", "@", "/", "//", "%" | ' +- 'Multiplication, matrix |\n' +- '| | ' +- 'multiplication, division, floor |\n' +- '| | ' +- 'division, remainder [6] |\n' +- '+-------------------------------------------------+---------------------------------------+\n' +- '| "+", "-" | ' +- 'Addition and subtraction |\n' +- '+-------------------------------------------------+---------------------------------------+\n' +- '| "<<", ">>" | ' +- 'Shifts |\n' +- '+-------------------------------------------------+---------------------------------------+\n' +- '| "&" | ' +- 'Bitwise AND |\n' +- '+-------------------------------------------------+---------------------------------------+\n' +- '| "^" | ' +- 'Bitwise XOR |\n' +- '+-------------------------------------------------+---------------------------------------+\n' +- '| "|" | ' +- 'Bitwise OR |\n' +- '+-------------------------------------------------+---------------------------------------+\n' +- '| "in", "not in", "is", "is not", "<", "<=", ">", | ' +- 'Comparisons, including membership |\n' +- '| ">=", "!=", "==" | ' +- 'tests and identity tests |\n' +- '+-------------------------------------------------+---------------------------------------+\n' +- '| "not x" | ' +- 'Boolean NOT |\n' +- '+-------------------------------------------------+---------------------------------------+\n' +- '| "and" | ' +- 'Boolean AND |\n' +- '+-------------------------------------------------+---------------------------------------+\n' +- '| "or" | ' +- 'Boolean OR |\n' +- '+-------------------------------------------------+---------------------------------------+\n' +- '| "if" – "else" | ' +- 'Conditional expression |\n' +- '+-------------------------------------------------+---------------------------------------+\n' +- '| "lambda" | ' +- 'Lambda expression |\n' +- '+-------------------------------------------------+---------------------------------------+\n' +- '| ":=" | ' +- 'Assignment expression |\n' +- '+-------------------------------------------------+---------------------------------------+\n' +- '\n' +- '-[ Footnotes ]-\n' +- '\n' +- '[1] While "abs(x%y) < abs(y)" is true mathematically, ' +- 'for floats it\n' +- ' may not be true numerically due to roundoff. For ' +- 'example, and\n' +- ' assuming a platform on which a Python float is an ' +- 'IEEE 754 double-\n' +- ' precision number, in order that "-1e-100 % 1e100" ' +- 'have the same\n' +- ' sign as "1e100", the computed result is "-1e-100 + ' +- '1e100", which\n' +- ' is numerically exactly equal to "1e100". The ' +- 'function\n' +- ' "math.fmod()" returns a result whose sign matches ' +- 'the sign of the\n' +- ' first argument instead, and so returns "-1e-100" in ' +- 'this case.\n' +- ' Which approach is more appropriate depends on the ' +- 'application.\n' +- '\n' +- '[2] If x is very close to an exact integer multiple of ' +- 'y, it’s\n' +- ' possible for "x//y" to be one larger than ' +- '"(x-x%y)//y" due to\n' +- ' rounding. In such cases, Python returns the latter ' +- 'result, in\n' +- ' order to preserve that "divmod(x,y)[0] * y + x % y" ' +- 'be very close\n' +- ' to "x".\n' +- '\n' +- '[3] The Unicode standard distinguishes between *code ' +- 'points* (e.g.\n' +- ' U+0041) and *abstract characters* (e.g. “LATIN ' +- 'CAPITAL LETTER Aâ€).\n' +- ' While most abstract characters in Unicode are only ' +- 'represented\n' +- ' using one code point, there is a number of abstract ' +- 'characters\n' +- ' that can in addition be represented using a sequence ' +- 'of more than\n' +- ' one code point. For example, the abstract character ' +- '“LATIN\n' +- ' CAPITAL LETTER C WITH CEDILLA†can be represented as ' +- 'a single\n' +- ' *precomposed character* at code position U+00C7, or ' +- 'as a sequence\n' +- ' of a *base character* at code position U+0043 (LATIN ' +- 'CAPITAL\n' +- ' LETTER C), followed by a *combining character* at ' +- 'code position\n' +- ' U+0327 (COMBINING CEDILLA).\n' +- '\n' +- ' The comparison operators on strings compare at the ' +- 'level of\n' +- ' Unicode code points. This may be counter-intuitive ' +- 'to humans. For\n' +- ' example, ""\\u00C7" == "\\u0043\\u0327"" is "False", ' +- 'even though both\n' +- ' strings represent the same abstract character “LATIN ' +- 'CAPITAL\n' +- ' LETTER C WITH CEDILLAâ€.\n' +- '\n' +- ' To compare strings at the level of abstract ' +- 'characters (that is,\n' +- ' in a way intuitive to humans), use ' +- '"unicodedata.normalize()".\n' +- '\n' +- '[4] Due to automatic garbage-collection, free lists, and ' +- 'the dynamic\n' +- ' nature of descriptors, you may notice seemingly ' +- 'unusual behaviour\n' +- ' in certain uses of the "is" operator, like those ' +- 'involving\n' +- ' comparisons between instance methods, or constants. ' +- 'Check their\n' +- ' documentation for more info.\n' +- '\n' +- '[5] The power operator "**" binds less tightly than an ' +- 'arithmetic or\n' +- ' bitwise unary operator on its right, that is, ' +- '"2**-1" is "0.5".\n' +- '\n' +- '[6] The "%" operator is also used for string formatting; ' +- 'the same\n' +- ' precedence applies.\n', +- 'pass': 'The "pass" statement\n' +- '********************\n' +- '\n' +- ' pass_stmt ::= "pass"\n' +- '\n' +- '"pass" is a null operation — when it is executed, nothing happens. ' +- 'It\n' +- 'is useful as a placeholder when a statement is required ' +- 'syntactically,\n' +- 'but no code needs to be executed, for example:\n' +- '\n' +- ' def f(arg): pass # a function that does nothing (yet)\n' +- '\n' +- ' class C: pass # a class with no methods (yet)\n', +- 'power': 'The power operator\n' +- '******************\n' +- '\n' +- 'The power operator binds more tightly than unary operators on its\n' +- 'left; it binds less tightly than unary operators on its right. ' +- 'The\n' +- 'syntax is:\n' +- '\n' +- ' power ::= (await_expr | primary) ["**" u_expr]\n' +- '\n' +- 'Thus, in an unparenthesized sequence of power and unary operators, ' +- 'the\n' +- 'operators are evaluated from right to left (this does not ' +- 'constrain\n' +- 'the evaluation order for the operands): "-1**2" results in "-1".\n' +- '\n' +- 'The power operator has the same semantics as the built-in "pow()"\n' +- 'function, when called with two arguments: it yields its left ' +- 'argument\n' +- 'raised to the power of its right argument. The numeric arguments ' +- 'are\n' +- 'first converted to a common type, and the result is of that type.\n' +- '\n' +- 'For int operands, the result has the same type as the operands ' +- 'unless\n' +- 'the second argument is negative; in that case, all arguments are\n' +- 'converted to float and a float result is delivered. For example,\n' +- '"10**2" returns "100", but "10**-2" returns "0.01".\n' +- '\n' +- 'Raising "0.0" to a negative power results in a ' +- '"ZeroDivisionError".\n' +- 'Raising a negative number to a fractional power results in a ' +- '"complex"\n' +- 'number. (In earlier versions it raised a "ValueError".)\n' +- '\n' +- 'This operation can be customized using the special "__pow__()" and\n' +- '"__rpow__()" methods.\n', +- 'raise': 'The "raise" statement\n' +- '*********************\n' +- '\n' +- ' raise_stmt ::= "raise" [expression ["from" expression]]\n' +- '\n' +- 'If no expressions are present, "raise" re-raises the exception that ' +- 'is\n' +- 'currently being handled, which is also known as the *active\n' +- 'exception*. If there isn’t currently an active exception, a\n' +- '"RuntimeError" exception is raised indicating that this is an ' +- 'error.\n' +- '\n' +- 'Otherwise, "raise" evaluates the first expression as the exception\n' +- 'object. It must be either a subclass or an instance of\n' +- '"BaseException". If it is a class, the exception instance will be\n' +- 'obtained when needed by instantiating the class with no arguments.\n' +- '\n' +- 'The *type* of the exception is the exception instance’s class, the\n' +- '*value* is the instance itself.\n' +- '\n' +- 'A traceback object is normally created automatically when an ' +- 'exception\n' +- 'is raised and attached to it as the "__traceback__" attribute. You ' +- 'can\n' +- 'create an exception and set your own traceback in one step using ' +- 'the\n' +- '"with_traceback()" exception method (which returns the same ' +- 'exception\n' +- 'instance, with its traceback set to its argument), like so:\n' +- '\n' +- ' raise Exception("foo occurred").with_traceback(tracebackobj)\n' +- '\n' +- 'The "from" clause is used for exception chaining: if given, the ' +- 'second\n' +- '*expression* must be another exception class or instance. If the\n' +- 'second expression is an exception instance, it will be attached to ' +- 'the\n' +- 'raised exception as the "__cause__" attribute (which is writable). ' +- 'If\n' +- 'the expression is an exception class, the class will be ' +- 'instantiated\n' +- 'and the resulting exception instance will be attached to the ' +- 'raised\n' +- 'exception as the "__cause__" attribute. If the raised exception is ' +- 'not\n' +- 'handled, both exceptions will be printed:\n' +- '\n' +- ' >>> try:\n' +- ' ... print(1 / 0)\n' +- ' ... except Exception as exc:\n' +- ' ... raise RuntimeError("Something bad happened") from exc\n' +- ' ...\n' +- ' Traceback (most recent call last):\n' +- ' File "", line 2, in \n' +- ' print(1 / 0)\n' +- ' ~~^~~\n' +- ' ZeroDivisionError: division by zero\n' +- '\n' +- ' The above exception was the direct cause of the following ' +- 'exception:\n' +- '\n' +- ' Traceback (most recent call last):\n' +- ' File "", line 4, in \n' +- ' raise RuntimeError("Something bad happened") from exc\n' +- ' RuntimeError: Something bad happened\n' +- '\n' +- 'A similar mechanism works implicitly if a new exception is raised ' +- 'when\n' +- 'an exception is already being handled. An exception may be ' +- 'handled\n' +- 'when an "except" or "finally" clause, or a "with" statement, is ' +- 'used.\n' +- 'The previous exception is then attached as the new exception’s\n' +- '"__context__" attribute:\n' +- '\n' +- ' >>> try:\n' +- ' ... print(1 / 0)\n' +- ' ... except:\n' +- ' ... raise RuntimeError("Something bad happened")\n' +- ' ...\n' +- ' Traceback (most recent call last):\n' +- ' File "", line 2, in \n' +- ' print(1 / 0)\n' +- ' ~~^~~\n' +- ' ZeroDivisionError: division by zero\n' +- '\n' +- ' During handling of the above exception, another exception ' +- 'occurred:\n' +- '\n' +- ' Traceback (most recent call last):\n' +- ' File "", line 4, in \n' +- ' raise RuntimeError("Something bad happened")\n' +- ' RuntimeError: Something bad happened\n' +- '\n' +- 'Exception chaining can be explicitly suppressed by specifying ' +- '"None"\n' +- 'in the "from" clause:\n' +- '\n' +- ' >>> try:\n' +- ' ... print(1 / 0)\n' +- ' ... except:\n' +- ' ... raise RuntimeError("Something bad happened") from None\n' +- ' ...\n' +- ' Traceback (most recent call last):\n' +- ' File "", line 4, in \n' +- ' RuntimeError: Something bad happened\n' +- '\n' +- 'Additional information on exceptions can be found in section\n' +- 'Exceptions, and information about handling exceptions is in ' +- 'section\n' +- 'The try statement.\n' +- '\n' +- 'Changed in version 3.3: "None" is now permitted as "Y" in "raise X\n' +- 'from Y".Added the "__suppress_context__" attribute to suppress\n' +- 'automatic display of the exception context.\n' +- '\n' +- 'Changed in version 3.11: If the traceback of the active exception ' +- 'is\n' +- 'modified in an "except" clause, a subsequent "raise" statement re-\n' +- 'raises the exception with the modified traceback. Previously, the\n' +- 'exception was re-raised with the traceback it had when it was ' +- 'caught.\n', +- 'return': 'The "return" statement\n' +- '**********************\n' +- '\n' +- ' return_stmt ::= "return" [expression_list]\n' +- '\n' +- '"return" may only occur syntactically nested in a function ' +- 'definition,\n' +- 'not within a nested class definition.\n' +- '\n' +- 'If an expression list is present, it is evaluated, else "None" is\n' +- 'substituted.\n' +- '\n' +- '"return" leaves the current function call with the expression list ' +- '(or\n' +- '"None") as return value.\n' +- '\n' +- 'When "return" passes control out of a "try" statement with a ' +- '"finally"\n' +- 'clause, that "finally" clause is executed before really leaving ' +- 'the\n' +- 'function.\n' +- '\n' +- 'In a generator function, the "return" statement indicates that ' +- 'the\n' +- 'generator is done and will cause "StopIteration" to be raised. ' +- 'The\n' +- 'returned value (if any) is used as an argument to construct\n' +- '"StopIteration" and becomes the "StopIteration.value" attribute.\n' +- '\n' +- 'In an asynchronous generator function, an empty "return" ' +- 'statement\n' +- 'indicates that the asynchronous generator is done and will cause\n' +- '"StopAsyncIteration" to be raised. A non-empty "return" statement ' +- 'is\n' +- 'a syntax error in an asynchronous generator function.\n', +- 'sequence-types': 'Emulating container types\n' +- '*************************\n' +- '\n' +- 'The following methods can be defined to implement ' +- 'container objects.\n' +- 'None of them are provided by the "object" class itself. ' +- 'Containers\n' +- 'usually are *sequences* (such as "lists" or "tuples") or ' +- '*mappings*\n' +- '(like *dictionaries*), but can represent other containers ' +- 'as well.\n' +- 'The first set of methods is used either to emulate a ' +- 'sequence or to\n' +- 'emulate a mapping; the difference is that for a sequence, ' +- 'the\n' +- 'allowable keys should be the integers *k* for which "0 <= ' +- 'k < N" where\n' +- '*N* is the length of the sequence, or "slice" objects, ' +- 'which define a\n' +- 'range of items. It is also recommended that mappings ' +- 'provide the\n' +- 'methods "keys()", "values()", "items()", "get()", ' +- '"clear()",\n' +- '"setdefault()", "pop()", "popitem()", "copy()", and ' +- '"update()"\n' +- 'behaving similar to those for Python’s standard ' +- '"dictionary" objects.\n' +- 'The "collections.abc" module provides a "MutableMapping" ' +- '*abstract\n' +- 'base class* to help create those methods from a base set ' +- 'of\n' +- '"__getitem__()", "__setitem__()", "__delitem__()", and ' +- '"keys()".\n' +- 'Mutable sequences should provide methods "append()", ' +- '"count()",\n' +- '"index()", "extend()", "insert()", "pop()", "remove()", ' +- '"reverse()"\n' +- 'and "sort()", like Python standard "list" objects. ' +- 'Finally, sequence\n' +- 'types should implement addition (meaning concatenation) ' +- 'and\n' +- 'multiplication (meaning repetition) by defining the ' +- 'methods\n' +- '"__add__()", "__radd__()", "__iadd__()", "__mul__()", ' +- '"__rmul__()" and\n' +- '"__imul__()" described below; they should not define other ' +- 'numerical\n' +- 'operators. It is recommended that both mappings and ' +- 'sequences\n' +- 'implement the "__contains__()" method to allow efficient ' +- 'use of the\n' +- '"in" operator; for mappings, "in" should search the ' +- 'mapping’s keys;\n' +- 'for sequences, it should search through the values. It is ' +- 'further\n' +- 'recommended that both mappings and sequences implement ' +- 'the\n' +- '"__iter__()" method to allow efficient iteration through ' +- 'the\n' +- 'container; for mappings, "__iter__()" should iterate ' +- 'through the\n' +- 'object’s keys; for sequences, it should iterate through ' +- 'the values.\n' +- '\n' +- 'object.__len__(self)\n' +- '\n' +- ' Called to implement the built-in function "len()". ' +- 'Should return\n' +- ' the length of the object, an integer ">=" 0. Also, an ' +- 'object that\n' +- ' doesn’t define a "__bool__()" method and whose ' +- '"__len__()" method\n' +- ' returns zero is considered to be false in a Boolean ' +- 'context.\n' +- '\n' +- ' **CPython implementation detail:** In CPython, the ' +- 'length is\n' +- ' required to be at most "sys.maxsize". If the length is ' +- 'larger than\n' +- ' "sys.maxsize" some features (such as "len()") may ' +- 'raise\n' +- ' "OverflowError". To prevent raising "OverflowError" by ' +- 'truth value\n' +- ' testing, an object must define a "__bool__()" method.\n' +- '\n' +- 'object.__length_hint__(self)\n' +- '\n' +- ' Called to implement "operator.length_hint()". Should ' +- 'return an\n' +- ' estimated length for the object (which may be greater ' +- 'or less than\n' +- ' the actual length). The length must be an integer ">=" ' +- '0. The\n' +- ' return value may also be "NotImplemented", which is ' +- 'treated the\n' +- ' same as if the "__length_hint__" method didn’t exist at ' +- 'all. This\n' +- ' method is purely an optimization and is never required ' +- 'for\n' +- ' correctness.\n' +- '\n' +- ' Added in version 3.4.\n' +- '\n' +- 'Note:\n' +- '\n' +- ' Slicing is done exclusively with the following three ' +- 'methods. A\n' +- ' call like\n' +- '\n' +- ' a[1:2] = b\n' +- '\n' +- ' is translated to\n' +- '\n' +- ' a[slice(1, 2, None)] = b\n' +- '\n' +- ' and so forth. Missing slice items are always filled in ' +- 'with "None".\n' +- '\n' +- 'object.__getitem__(self, key)\n' +- '\n' +- ' Called to implement evaluation of "self[key]". For ' +- '*sequence*\n' +- ' types, the accepted keys should be integers. ' +- 'Optionally, they may\n' +- ' support "slice" objects as well. Negative index ' +- 'support is also\n' +- ' optional. If *key* is of an inappropriate type, ' +- '"TypeError" may be\n' +- ' raised; if *key* is a value outside the set of indexes ' +- 'for the\n' +- ' sequence (after any special interpretation of negative ' +- 'values),\n' +- ' "IndexError" should be raised. For *mapping* types, if ' +- '*key* is\n' +- ' missing (not in the container), "KeyError" should be ' +- 'raised.\n' +- '\n' +- ' Note:\n' +- '\n' +- ' "for" loops expect that an "IndexError" will be ' +- 'raised for\n' +- ' illegal indexes to allow proper detection of the end ' +- 'of the\n' +- ' sequence.\n' +- '\n' +- ' Note:\n' +- '\n' +- ' When subscripting a *class*, the special class ' +- 'method\n' +- ' "__class_getitem__()" may be called instead of ' +- '"__getitem__()".\n' +- ' See __class_getitem__ versus __getitem__ for more ' +- 'details.\n' +- '\n' +- 'object.__setitem__(self, key, value)\n' +- '\n' +- ' Called to implement assignment to "self[key]". Same ' +- 'note as for\n' +- ' "__getitem__()". This should only be implemented for ' +- 'mappings if\n' +- ' the objects support changes to the values for keys, or ' +- 'if new keys\n' +- ' can be added, or for sequences if elements can be ' +- 'replaced. The\n' +- ' same exceptions should be raised for improper *key* ' +- 'values as for\n' +- ' the "__getitem__()" method.\n' +- '\n' +- 'object.__delitem__(self, key)\n' +- '\n' +- ' Called to implement deletion of "self[key]". Same note ' +- 'as for\n' +- ' "__getitem__()". This should only be implemented for ' +- 'mappings if\n' +- ' the objects support removal of keys, or for sequences ' +- 'if elements\n' +- ' can be removed from the sequence. The same exceptions ' +- 'should be\n' +- ' raised for improper *key* values as for the ' +- '"__getitem__()" method.\n' +- '\n' +- 'object.__missing__(self, key)\n' +- '\n' +- ' Called by "dict"."__getitem__()" to implement ' +- '"self[key]" for dict\n' +- ' subclasses when key is not in the dictionary.\n' +- '\n' +- 'object.__iter__(self)\n' +- '\n' +- ' This method is called when an *iterator* is required ' +- 'for a\n' +- ' container. This method should return a new iterator ' +- 'object that can\n' +- ' iterate over all the objects in the container. For ' +- 'mappings, it\n' +- ' should iterate over the keys of the container.\n' +- '\n' +- 'object.__reversed__(self)\n' +- '\n' +- ' Called (if present) by the "reversed()" built-in to ' +- 'implement\n' +- ' reverse iteration. It should return a new iterator ' +- 'object that\n' +- ' iterates over all the objects in the container in ' +- 'reverse order.\n' +- '\n' +- ' If the "__reversed__()" method is not provided, the ' +- '"reversed()"\n' +- ' built-in will fall back to using the sequence protocol ' +- '("__len__()"\n' +- ' and "__getitem__()"). Objects that support the ' +- 'sequence protocol\n' +- ' should only provide "__reversed__()" if they can ' +- 'provide an\n' +- ' implementation that is more efficient than the one ' +- 'provided by\n' +- ' "reversed()".\n' +- '\n' +- 'The membership test operators ("in" and "not in") are ' +- 'normally\n' +- 'implemented as an iteration through a container. However, ' +- 'container\n' +- 'objects can supply the following special method with a ' +- 'more efficient\n' +- 'implementation, which also does not require the object be ' +- 'iterable.\n' +- '\n' +- 'object.__contains__(self, item)\n' +- '\n' +- ' Called to implement membership test operators. Should ' +- 'return true\n' +- ' if *item* is in *self*, false otherwise. For mapping ' +- 'objects, this\n' +- ' should consider the keys of the mapping rather than the ' +- 'values or\n' +- ' the key-item pairs.\n' +- '\n' +- ' For objects that don’t define "__contains__()", the ' +- 'membership test\n' +- ' first tries iteration via "__iter__()", then the old ' +- 'sequence\n' +- ' iteration protocol via "__getitem__()", see this ' +- 'section in the\n' +- ' language reference.\n', +- 'shifting': 'Shifting operations\n' +- '*******************\n' +- '\n' +- 'The shifting operations have lower priority than the arithmetic\n' +- 'operations:\n' +- '\n' +- ' shift_expr ::= a_expr | shift_expr ("<<" | ">>") a_expr\n' +- '\n' +- 'These operators accept integers as arguments. They shift the ' +- 'first\n' +- 'argument to the left or right by the number of bits given by ' +- 'the\n' +- 'second argument.\n' +- '\n' +- 'The left shift operation can be customized using the special\n' +- '"__lshift__()" and "__rlshift__()" methods. The right shift ' +- 'operation\n' +- 'can be customized using the special "__rshift__()" and ' +- '"__rrshift__()"\n' +- 'methods.\n' +- '\n' +- 'A right shift by *n* bits is defined as floor division by ' +- '"pow(2,n)".\n' +- 'A left shift by *n* bits is defined as multiplication with ' +- '"pow(2,n)".\n', +- 'slicings': 'Slicings\n' +- '********\n' +- '\n' +- 'A slicing selects a range of items in a sequence object (e.g., ' +- 'a\n' +- 'string, tuple or list). Slicings may be used as expressions or ' +- 'as\n' +- 'targets in assignment or "del" statements. The syntax for a ' +- 'slicing:\n' +- '\n' +- ' slicing ::= primary "[" slice_list "]"\n' +- ' slice_list ::= slice_item ("," slice_item)* [","]\n' +- ' slice_item ::= expression | proper_slice\n' +- ' proper_slice ::= [lower_bound] ":" [upper_bound] [ ":" ' +- '[stride] ]\n' +- ' lower_bound ::= expression\n' +- ' upper_bound ::= expression\n' +- ' stride ::= expression\n' +- '\n' +- 'There is ambiguity in the formal syntax here: anything that ' +- 'looks like\n' +- 'an expression list also looks like a slice list, so any ' +- 'subscription\n' +- 'can be interpreted as a slicing. Rather than further ' +- 'complicating the\n' +- 'syntax, this is disambiguated by defining that in this case the\n' +- 'interpretation as a subscription takes priority over the\n' +- 'interpretation as a slicing (this is the case if the slice list\n' +- 'contains no proper slice).\n' +- '\n' +- 'The semantics for a slicing are as follows. The primary is ' +- 'indexed\n' +- '(using the same "__getitem__()" method as normal subscription) ' +- 'with a\n' +- 'key that is constructed from the slice list, as follows. If the ' +- 'slice\n' +- 'list contains at least one comma, the key is a tuple containing ' +- 'the\n' +- 'conversion of the slice items; otherwise, the conversion of the ' +- 'lone\n' +- 'slice item is the key. The conversion of a slice item that is ' +- 'an\n' +- 'expression is that expression. The conversion of a proper slice ' +- 'is a\n' +- 'slice object (see section The standard type hierarchy) whose ' +- '"start",\n' +- '"stop" and "step" attributes are the values of the expressions ' +- 'given\n' +- 'as lower bound, upper bound and stride, respectively, ' +- 'substituting\n' +- '"None" for missing expressions.\n', +- 'specialattrs': 'Special Attributes\n' +- '******************\n' +- '\n' +- 'The implementation adds a few special read-only attributes ' +- 'to several\n' +- 'object types, where they are relevant. Some of these are ' +- 'not reported\n' +- 'by the "dir()" built-in function.\n' +- '\n' +- 'definition.__name__\n' +- '\n' +- ' The name of the class, function, method, descriptor, or ' +- 'generator\n' +- ' instance.\n' +- '\n' +- 'definition.__qualname__\n' +- '\n' +- ' The *qualified name* of the class, function, method, ' +- 'descriptor, or\n' +- ' generator instance.\n' +- '\n' +- ' Added in version 3.3.\n' +- '\n' +- 'definition.__module__\n' +- '\n' +- ' The name of the module in which a class or function was ' +- 'defined.\n' +- '\n' +- 'definition.__doc__\n' +- '\n' +- ' The documentation string of a class or function, or ' +- '"None" if\n' +- ' undefined.\n' +- '\n' +- 'definition.__type_params__\n' +- '\n' +- ' The type parameters of generic classes, functions, and ' +- 'type\n' +- ' aliases. For classes and functions that are not generic, ' +- 'this will\n' +- ' be an empty tuple.\n' +- '\n' +- ' Added in version 3.12.\n', +- 'specialnames': 'Special method names\n' +- '********************\n' +- '\n' +- 'A class can implement certain operations that are invoked by ' +- 'special\n' +- 'syntax (such as arithmetic operations or subscripting and ' +- 'slicing) by\n' +- 'defining methods with special names. This is Python’s ' +- 'approach to\n' +- '*operator overloading*, allowing classes to define their own ' +- 'behavior\n' +- 'with respect to language operators. For instance, if a ' +- 'class defines\n' +- 'a method named "__getitem__()", and "x" is an instance of ' +- 'this class,\n' +- 'then "x[i]" is roughly equivalent to "type(x).__getitem__(x, ' +- 'i)".\n' +- 'Except where mentioned, attempts to execute an operation ' +- 'raise an\n' +- 'exception when no appropriate method is defined (typically\n' +- '"AttributeError" or "TypeError").\n' +- '\n' +- 'Setting a special method to "None" indicates that the ' +- 'corresponding\n' +- 'operation is not available. For example, if a class sets ' +- '"__iter__()"\n' +- 'to "None", the class is not iterable, so calling "iter()" on ' +- 'its\n' +- 'instances will raise a "TypeError" (without falling back to\n' +- '"__getitem__()"). [2]\n' +- '\n' +- 'When implementing a class that emulates any built-in type, ' +- 'it is\n' +- 'important that the emulation only be implemented to the ' +- 'degree that it\n' +- 'makes sense for the object being modelled. For example, ' +- 'some\n' +- 'sequences may work well with retrieval of individual ' +- 'elements, but\n' +- 'extracting a slice may not make sense. (One example of this ' +- 'is the\n' +- '"NodeList" interface in the W3C’s Document Object Model.)\n' +- '\n' +- '\n' +- 'Basic customization\n' +- '===================\n' +- '\n' +- 'object.__new__(cls[, ...])\n' +- '\n' +- ' Called to create a new instance of class *cls*. ' +- '"__new__()" is a\n' +- ' static method (special-cased so you need not declare it ' +- 'as such)\n' +- ' that takes the class of which an instance was requested ' +- 'as its\n' +- ' first argument. The remaining arguments are those passed ' +- 'to the\n' +- ' object constructor expression (the call to the class). ' +- 'The return\n' +- ' value of "__new__()" should be the new object instance ' +- '(usually an\n' +- ' instance of *cls*).\n' +- '\n' +- ' Typical implementations create a new instance of the ' +- 'class by\n' +- ' invoking the superclass’s "__new__()" method using\n' +- ' "super().__new__(cls[, ...])" with appropriate arguments ' +- 'and then\n' +- ' modifying the newly created instance as necessary before ' +- 'returning\n' +- ' it.\n' +- '\n' +- ' If "__new__()" is invoked during object construction and ' +- 'it returns\n' +- ' an instance of *cls*, then the new instance’s ' +- '"__init__()" method\n' +- ' will be invoked like "__init__(self[, ...])", where ' +- '*self* is the\n' +- ' new instance and the remaining arguments are the same as ' +- 'were\n' +- ' passed to the object constructor.\n' +- '\n' +- ' If "__new__()" does not return an instance of *cls*, then ' +- 'the new\n' +- ' instance’s "__init__()" method will not be invoked.\n' +- '\n' +- ' "__new__()" is intended mainly to allow subclasses of ' +- 'immutable\n' +- ' types (like int, str, or tuple) to customize instance ' +- 'creation. It\n' +- ' is also commonly overridden in custom metaclasses in ' +- 'order to\n' +- ' customize class creation.\n' +- '\n' +- 'object.__init__(self[, ...])\n' +- '\n' +- ' Called after the instance has been created (by ' +- '"__new__()"), but\n' +- ' before it is returned to the caller. The arguments are ' +- 'those\n' +- ' passed to the class constructor expression. If a base ' +- 'class has an\n' +- ' "__init__()" method, the derived class’s "__init__()" ' +- 'method, if\n' +- ' any, must explicitly call it to ensure proper ' +- 'initialization of the\n' +- ' base class part of the instance; for example:\n' +- ' "super().__init__([args...])".\n' +- '\n' +- ' Because "__new__()" and "__init__()" work together in ' +- 'constructing\n' +- ' objects ("__new__()" to create it, and "__init__()" to ' +- 'customize\n' +- ' it), no non-"None" value may be returned by "__init__()"; ' +- 'doing so\n' +- ' will cause a "TypeError" to be raised at runtime.\n' +- '\n' +- 'object.__del__(self)\n' +- '\n' +- ' Called when the instance is about to be destroyed. This ' +- 'is also\n' +- ' called a finalizer or (improperly) a destructor. If a ' +- 'base class\n' +- ' has a "__del__()" method, the derived class’s "__del__()" ' +- 'method,\n' +- ' if any, must explicitly call it to ensure proper deletion ' +- 'of the\n' +- ' base class part of the instance.\n' +- '\n' +- ' It is possible (though not recommended!) for the ' +- '"__del__()" method\n' +- ' to postpone destruction of the instance by creating a new ' +- 'reference\n' +- ' to it. This is called object *resurrection*. It is\n' +- ' implementation-dependent whether "__del__()" is called a ' +- 'second\n' +- ' time when a resurrected object is about to be destroyed; ' +- 'the\n' +- ' current *CPython* implementation only calls it once.\n' +- '\n' +- ' It is not guaranteed that "__del__()" methods are called ' +- 'for\n' +- ' objects that still exist when the interpreter exits.\n' +- ' "weakref.finalize" provides a straightforward way to ' +- 'register a\n' +- ' cleanup function to be called when an object is garbage ' +- 'collected.\n' +- '\n' +- ' Note:\n' +- '\n' +- ' "del x" doesn’t directly call "x.__del__()" — the ' +- 'former\n' +- ' decrements the reference count for "x" by one, and the ' +- 'latter is\n' +- ' only called when "x"’s reference count reaches zero.\n' +- '\n' +- ' **CPython implementation detail:** It is possible for a ' +- 'reference\n' +- ' cycle to prevent the reference count of an object from ' +- 'going to\n' +- ' zero. In this case, the cycle will be later detected and ' +- 'deleted\n' +- ' by the *cyclic garbage collector*. A common cause of ' +- 'reference\n' +- ' cycles is when an exception has been caught in a local ' +- 'variable.\n' +- ' The frame’s locals then reference the exception, which ' +- 'references\n' +- ' its own traceback, which references the locals of all ' +- 'frames caught\n' +- ' in the traceback.\n' +- '\n' +- ' See also: Documentation for the "gc" module.\n' +- '\n' +- ' Warning:\n' +- '\n' +- ' Due to the precarious circumstances under which ' +- '"__del__()"\n' +- ' methods are invoked, exceptions that occur during their ' +- 'execution\n' +- ' are ignored, and a warning is printed to "sys.stderr" ' +- 'instead.\n' +- ' In particular:\n' +- '\n' +- ' * "__del__()" can be invoked when arbitrary code is ' +- 'being\n' +- ' executed, including from any arbitrary thread. If ' +- '"__del__()"\n' +- ' needs to take a lock or invoke any other blocking ' +- 'resource, it\n' +- ' may deadlock as the resource may already be taken by ' +- 'the code\n' +- ' that gets interrupted to execute "__del__()".\n' +- '\n' +- ' * "__del__()" can be executed during interpreter ' +- 'shutdown. As a\n' +- ' consequence, the global variables it needs to access ' +- '(including\n' +- ' other modules) may already have been deleted or set ' +- 'to "None".\n' +- ' Python guarantees that globals whose name begins with ' +- 'a single\n' +- ' underscore are deleted from their module before other ' +- 'globals\n' +- ' are deleted; if no other references to such globals ' +- 'exist, this\n' +- ' may help in assuring that imported modules are still ' +- 'available\n' +- ' at the time when the "__del__()" method is called.\n' +- '\n' +- 'object.__repr__(self)\n' +- '\n' +- ' Called by the "repr()" built-in function to compute the ' +- '“officialâ€\n' +- ' string representation of an object. If at all possible, ' +- 'this\n' +- ' should look like a valid Python expression that could be ' +- 'used to\n' +- ' recreate an object with the same value (given an ' +- 'appropriate\n' +- ' environment). If this is not possible, a string of the ' +- 'form\n' +- ' "<...some useful description...>" should be returned. The ' +- 'return\n' +- ' value must be a string object. If a class defines ' +- '"__repr__()" but\n' +- ' not "__str__()", then "__repr__()" is also used when an ' +- '“informalâ€\n' +- ' string representation of instances of that class is ' +- 'required.\n' +- '\n' +- ' This is typically used for debugging, so it is important ' +- 'that the\n' +- ' representation is information-rich and unambiguous. A ' +- 'default\n' +- ' implementation is provided by the "object" class itself.\n' +- '\n' +- 'object.__str__(self)\n' +- '\n' +- ' Called by "str(object)", the default "__format__()" ' +- 'implementation,\n' +- ' and the built-in function "print()", to compute the ' +- '“informal†or\n' +- ' nicely printable string representation of an object. The ' +- 'return\n' +- ' value must be a str object.\n' +- '\n' +- ' This method differs from "object.__repr__()" in that ' +- 'there is no\n' +- ' expectation that "__str__()" return a valid Python ' +- 'expression: a\n' +- ' more convenient or concise representation can be used.\n' +- '\n' +- ' The default implementation defined by the built-in type ' +- '"object"\n' +- ' calls "object.__repr__()".\n' +- '\n' +- 'object.__bytes__(self)\n' +- '\n' +- ' Called by bytes to compute a byte-string representation ' +- 'of an\n' +- ' object. This should return a "bytes" object. The "object" ' +- 'class\n' +- ' itself does not provide this method.\n' +- '\n' +- 'object.__format__(self, format_spec)\n' +- '\n' +- ' Called by the "format()" built-in function, and by ' +- 'extension,\n' +- ' evaluation of formatted string literals and the ' +- '"str.format()"\n' +- ' method, to produce a “formatted†string representation of ' +- 'an\n' +- ' object. The *format_spec* argument is a string that ' +- 'contains a\n' +- ' description of the formatting options desired. The ' +- 'interpretation\n' +- ' of the *format_spec* argument is up to the type ' +- 'implementing\n' +- ' "__format__()", however most classes will either ' +- 'delegate\n' +- ' formatting to one of the built-in types, or use a ' +- 'similar\n' +- ' formatting option syntax.\n' +- '\n' +- ' See Format Specification Mini-Language for a description ' +- 'of the\n' +- ' standard formatting syntax.\n' +- '\n' +- ' The return value must be a string object.\n' +- '\n' +- ' The default implementation by the "object" class should ' +- 'be given an\n' +- ' empty *format_spec* string. It delegates to "__str__()".\n' +- '\n' +- ' Changed in version 3.4: The __format__ method of "object" ' +- 'itself\n' +- ' raises a "TypeError" if passed any non-empty string.\n' +- '\n' +- ' Changed in version 3.7: "object.__format__(x, \'\')" is ' +- 'now\n' +- ' equivalent to "str(x)" rather than "format(str(x), ' +- '\'\')".\n' +- '\n' +- 'object.__lt__(self, other)\n' +- 'object.__le__(self, other)\n' +- 'object.__eq__(self, other)\n' +- 'object.__ne__(self, other)\n' +- 'object.__gt__(self, other)\n' +- 'object.__ge__(self, other)\n' +- '\n' +- ' These are the so-called “rich comparison†methods. The\n' +- ' correspondence between operator symbols and method names ' +- 'is as\n' +- ' follows: "xy" calls\n' +- ' "x.__gt__(y)", and "x>=y" calls "x.__ge__(y)".\n' +- '\n' +- ' A rich comparison method may return the singleton ' +- '"NotImplemented"\n' +- ' if it does not implement the operation for a given pair ' +- 'of\n' +- ' arguments. By convention, "False" and "True" are returned ' +- 'for a\n' +- ' successful comparison. However, these methods can return ' +- 'any value,\n' +- ' so if the comparison operator is used in a Boolean ' +- 'context (e.g.,\n' +- ' in the condition of an "if" statement), Python will call ' +- '"bool()"\n' +- ' on the value to determine if the result is true or ' +- 'false.\n' +- '\n' +- ' By default, "object" implements "__eq__()" by using "is", ' +- 'returning\n' +- ' "NotImplemented" in the case of a false comparison: "True ' +- 'if x is y\n' +- ' else NotImplemented". For "__ne__()", by default it ' +- 'delegates to\n' +- ' "__eq__()" and inverts the result unless it is ' +- '"NotImplemented".\n' +- ' There are no other implied relationships among the ' +- 'comparison\n' +- ' operators or default implementations; for example, the ' +- 'truth of\n' +- ' "(x.__hash__".\n' +- '\n' +- ' If a class that does not override "__eq__()" wishes to ' +- 'suppress\n' +- ' hash support, it should include "__hash__ = None" in the ' +- 'class\n' +- ' definition. A class which defines its own "__hash__()" ' +- 'that\n' +- ' explicitly raises a "TypeError" would be incorrectly ' +- 'identified as\n' +- ' hashable by an "isinstance(obj, ' +- 'collections.abc.Hashable)" call.\n' +- '\n' +- ' Note:\n' +- '\n' +- ' By default, the "__hash__()" values of str and bytes ' +- 'objects are\n' +- ' “salted†with an unpredictable random value. Although ' +- 'they\n' +- ' remain constant within an individual Python process, ' +- 'they are not\n' +- ' predictable between repeated invocations of Python.This ' +- 'is\n' +- ' intended to provide protection against a ' +- 'denial-of-service caused\n' +- ' by carefully chosen inputs that exploit the worst case\n' +- ' performance of a dict insertion, *O*(*n*^2) ' +- 'complexity. See\n' +- ' http://ocert.org/advisories/ocert-2011-003.html for\n' +- ' details.Changing hash values affects the iteration ' +- 'order of sets.\n' +- ' Python has never made guarantees about this ordering ' +- '(and it\n' +- ' typically varies between 32-bit and 64-bit builds).See ' +- 'also\n' +- ' "PYTHONHASHSEED".\n' +- '\n' +- ' Changed in version 3.3: Hash randomization is enabled by ' +- 'default.\n' +- '\n' +- 'object.__bool__(self)\n' +- '\n' +- ' Called to implement truth value testing and the built-in ' +- 'operation\n' +- ' "bool()"; should return "False" or "True". When this ' +- 'method is not\n' +- ' defined, "__len__()" is called, if it is defined, and the ' +- 'object is\n' +- ' considered true if its result is nonzero. If a class ' +- 'defines\n' +- ' neither "__len__()" nor "__bool__()" (which is true of ' +- 'the "object"\n' +- ' class itself), all its instances are considered true.\n' +- '\n' +- '\n' +- 'Customizing attribute access\n' +- '============================\n' +- '\n' +- 'The following methods can be defined to customize the ' +- 'meaning of\n' +- 'attribute access (use of, assignment to, or deletion of ' +- '"x.name") for\n' +- 'class instances.\n' +- '\n' +- 'object.__getattr__(self, name)\n' +- '\n' +- ' Called when the default attribute access fails with an\n' +- ' "AttributeError" (either "__getattribute__()" raises an\n' +- ' "AttributeError" because *name* is not an instance ' +- 'attribute or an\n' +- ' attribute in the class tree for "self"; or "__get__()" of ' +- 'a *name*\n' +- ' property raises "AttributeError"). This method should ' +- 'either\n' +- ' return the (computed) attribute value or raise an ' +- '"AttributeError"\n' +- ' exception. The "object" class itself does not provide ' +- 'this method.\n' +- '\n' +- ' Note that if the attribute is found through the normal ' +- 'mechanism,\n' +- ' "__getattr__()" is not called. (This is an intentional ' +- 'asymmetry\n' +- ' between "__getattr__()" and "__setattr__()".) This is ' +- 'done both for\n' +- ' efficiency reasons and because otherwise "__getattr__()" ' +- 'would have\n' +- ' no way to access other attributes of the instance. Note ' +- 'that at\n' +- ' least for instance variables, you can take total control ' +- 'by not\n' +- ' inserting any values in the instance attribute dictionary ' +- '(but\n' +- ' instead inserting them in another object). See the\n' +- ' "__getattribute__()" method below for a way to actually ' +- 'get total\n' +- ' control over attribute access.\n' +- '\n' +- 'object.__getattribute__(self, name)\n' +- '\n' +- ' Called unconditionally to implement attribute accesses ' +- 'for\n' +- ' instances of the class. If the class also defines ' +- '"__getattr__()",\n' +- ' the latter will not be called unless "__getattribute__()" ' +- 'either\n' +- ' calls it explicitly or raises an "AttributeError". This ' +- 'method\n' +- ' should return the (computed) attribute value or raise an\n' +- ' "AttributeError" exception. In order to avoid infinite ' +- 'recursion in\n' +- ' this method, its implementation should always call the ' +- 'base class\n' +- ' method with the same name to access any attributes it ' +- 'needs, for\n' +- ' example, "object.__getattribute__(self, name)".\n' +- '\n' +- ' Note:\n' +- '\n' +- ' This method may still be bypassed when looking up ' +- 'special methods\n' +- ' as the result of implicit invocation via language ' +- 'syntax or\n' +- ' built-in functions. See Special method lookup.\n' +- '\n' +- ' For certain sensitive attribute accesses, raises an ' +- 'auditing event\n' +- ' "object.__getattr__" with arguments "obj" and "name".\n' +- '\n' +- 'object.__setattr__(self, name, value)\n' +- '\n' +- ' Called when an attribute assignment is attempted. This ' +- 'is called\n' +- ' instead of the normal mechanism (i.e. store the value in ' +- 'the\n' +- ' instance dictionary). *name* is the attribute name, ' +- '*value* is the\n' +- ' value to be assigned to it.\n' +- '\n' +- ' If "__setattr__()" wants to assign to an instance ' +- 'attribute, it\n' +- ' should call the base class method with the same name, for ' +- 'example,\n' +- ' "object.__setattr__(self, name, value)".\n' +- '\n' +- ' For certain sensitive attribute assignments, raises an ' +- 'auditing\n' +- ' event "object.__setattr__" with arguments "obj", "name", ' +- '"value".\n' +- '\n' +- 'object.__delattr__(self, name)\n' +- '\n' +- ' Like "__setattr__()" but for attribute deletion instead ' +- 'of\n' +- ' assignment. This should only be implemented if "del ' +- 'obj.name" is\n' +- ' meaningful for the object.\n' +- '\n' +- ' For certain sensitive attribute deletions, raises an ' +- 'auditing event\n' +- ' "object.__delattr__" with arguments "obj" and "name".\n' +- '\n' +- 'object.__dir__(self)\n' +- '\n' +- ' Called when "dir()" is called on the object. An iterable ' +- 'must be\n' +- ' returned. "dir()" converts the returned iterable to a ' +- 'list and\n' +- ' sorts it.\n' +- '\n' +- '\n' +- 'Customizing module attribute access\n' +- '-----------------------------------\n' +- '\n' +- 'Special names "__getattr__" and "__dir__" can be also used ' +- 'to\n' +- 'customize access to module attributes. The "__getattr__" ' +- 'function at\n' +- 'the module level should accept one argument which is the ' +- 'name of an\n' +- 'attribute and return the computed value or raise an ' +- '"AttributeError".\n' +- 'If an attribute is not found on a module object through the ' +- 'normal\n' +- 'lookup, i.e. "object.__getattribute__()", then "__getattr__" ' +- 'is\n' +- 'searched in the module "__dict__" before raising an ' +- '"AttributeError".\n' +- 'If found, it is called with the attribute name and the ' +- 'result is\n' +- 'returned.\n' +- '\n' +- 'The "__dir__" function should accept no arguments, and ' +- 'return an\n' +- 'iterable of strings that represents the names accessible on ' +- 'module. If\n' +- 'present, this function overrides the standard "dir()" search ' +- 'on a\n' +- 'module.\n' +- '\n' +- 'For a more fine grained customization of the module behavior ' +- '(setting\n' +- 'attributes, properties, etc.), one can set the "__class__" ' +- 'attribute\n' +- 'of a module object to a subclass of "types.ModuleType". For ' +- 'example:\n' +- '\n' +- ' import sys\n' +- ' from types import ModuleType\n' +- '\n' +- ' class VerboseModule(ModuleType):\n' +- ' def __repr__(self):\n' +- " return f'Verbose {self.__name__}'\n" +- '\n' +- ' def __setattr__(self, attr, value):\n' +- " print(f'Setting {attr}...')\n" +- ' super().__setattr__(attr, value)\n' +- '\n' +- ' sys.modules[__name__].__class__ = VerboseModule\n' +- '\n' +- 'Note:\n' +- '\n' +- ' Defining module "__getattr__" and setting module ' +- '"__class__" only\n' +- ' affect lookups made using the attribute access syntax – ' +- 'directly\n' +- ' accessing the module globals (whether by code within the ' +- 'module, or\n' +- ' via a reference to the module’s globals dictionary) is ' +- 'unaffected.\n' +- '\n' +- 'Changed in version 3.5: "__class__" module attribute is now ' +- 'writable.\n' +- '\n' +- 'Added in version 3.7: "__getattr__" and "__dir__" module ' +- 'attributes.\n' +- '\n' +- 'See also:\n' +- '\n' +- ' **PEP 562** - Module __getattr__ and __dir__\n' +- ' Describes the "__getattr__" and "__dir__" functions on ' +- 'modules.\n' +- '\n' +- '\n' +- 'Implementing Descriptors\n' +- '------------------------\n' +- '\n' +- 'The following methods only apply when an instance of the ' +- 'class\n' +- 'containing the method (a so-called *descriptor* class) ' +- 'appears in an\n' +- '*owner* class (the descriptor must be in either the owner’s ' +- 'class\n' +- 'dictionary or in the class dictionary for one of its ' +- 'parents). In the\n' +- 'examples below, “the attribute†refers to the attribute ' +- 'whose name is\n' +- 'the key of the property in the owner class’ "__dict__". The ' +- '"object"\n' +- 'class itself does not implement any of these protocols.\n' +- '\n' +- 'object.__get__(self, instance, owner=None)\n' +- '\n' +- ' Called to get the attribute of the owner class (class ' +- 'attribute\n' +- ' access) or of an instance of that class (instance ' +- 'attribute\n' +- ' access). The optional *owner* argument is the owner ' +- 'class, while\n' +- ' *instance* is the instance that the attribute was ' +- 'accessed through,\n' +- ' or "None" when the attribute is accessed through the ' +- '*owner*.\n' +- '\n' +- ' This method should return the computed attribute value or ' +- 'raise an\n' +- ' "AttributeError" exception.\n' +- '\n' +- ' **PEP 252** specifies that "__get__()" is callable with ' +- 'one or two\n' +- ' arguments. Python’s own built-in descriptors support ' +- 'this\n' +- ' specification; however, it is likely that some ' +- 'third-party tools\n' +- ' have descriptors that require both arguments. Python’s ' +- 'own\n' +- ' "__getattribute__()" implementation always passes in both ' +- 'arguments\n' +- ' whether they are required or not.\n' +- '\n' +- 'object.__set__(self, instance, value)\n' +- '\n' +- ' Called to set the attribute on an instance *instance* of ' +- 'the owner\n' +- ' class to a new value, *value*.\n' +- '\n' +- ' Note, adding "__set__()" or "__delete__()" changes the ' +- 'kind of\n' +- ' descriptor to a “data descriptorâ€. See Invoking ' +- 'Descriptors for\n' +- ' more details.\n' +- '\n' +- 'object.__delete__(self, instance)\n' +- '\n' +- ' Called to delete the attribute on an instance *instance* ' +- 'of the\n' +- ' owner class.\n' +- '\n' +- 'Instances of descriptors may also have the "__objclass__" ' +- 'attribute\n' +- 'present:\n' +- '\n' +- 'object.__objclass__\n' +- '\n' +- ' The attribute "__objclass__" is interpreted by the ' +- '"inspect" module\n' +- ' as specifying the class where this object was defined ' +- '(setting this\n' +- ' appropriately can assist in runtime introspection of ' +- 'dynamic class\n' +- ' attributes). For callables, it may indicate that an ' +- 'instance of the\n' +- ' given type (or a subclass) is expected or required as the ' +- 'first\n' +- ' positional argument (for example, CPython sets this ' +- 'attribute for\n' +- ' unbound methods that are implemented in C).\n' +- '\n' +- '\n' +- 'Invoking Descriptors\n' +- '--------------------\n' +- '\n' +- 'In general, a descriptor is an object attribute with ' +- '“binding\n' +- 'behaviorâ€, one whose attribute access has been overridden by ' +- 'methods\n' +- 'in the descriptor protocol: "__get__()", "__set__()", and\n' +- '"__delete__()". If any of those methods are defined for an ' +- 'object, it\n' +- 'is said to be a descriptor.\n' +- '\n' +- 'The default behavior for attribute access is to get, set, or ' +- 'delete\n' +- 'the attribute from an object’s dictionary. For instance, ' +- '"a.x" has a\n' +- 'lookup chain starting with "a.__dict__[\'x\']", then\n' +- '"type(a).__dict__[\'x\']", and continuing through the base ' +- 'classes of\n' +- '"type(a)" excluding metaclasses.\n' +- '\n' +- 'However, if the looked-up value is an object defining one of ' +- 'the\n' +- 'descriptor methods, then Python may override the default ' +- 'behavior and\n' +- 'invoke the descriptor method instead. Where this occurs in ' +- 'the\n' +- 'precedence chain depends on which descriptor methods were ' +- 'defined and\n' +- 'how they were called.\n' +- '\n' +- 'The starting point for descriptor invocation is a binding, ' +- '"a.x". How\n' +- 'the arguments are assembled depends on "a":\n' +- '\n' +- 'Direct Call\n' +- ' The simplest and least common call is when user code ' +- 'directly\n' +- ' invokes a descriptor method: "x.__get__(a)".\n' +- '\n' +- 'Instance Binding\n' +- ' If binding to an object instance, "a.x" is transformed ' +- 'into the\n' +- ' call: "type(a).__dict__[\'x\'].__get__(a, type(a))".\n' +- '\n' +- 'Class Binding\n' +- ' If binding to a class, "A.x" is transformed into the ' +- 'call:\n' +- ' "A.__dict__[\'x\'].__get__(None, A)".\n' +- '\n' +- 'Super Binding\n' +- ' A dotted lookup such as "super(A, a).x" searches\n' +- ' "a.__class__.__mro__" for a base class "B" following "A" ' +- 'and then\n' +- ' returns "B.__dict__[\'x\'].__get__(a, A)". If not a ' +- 'descriptor, "x"\n' +- ' is returned unchanged.\n' +- '\n' +- 'For instance bindings, the precedence of descriptor ' +- 'invocation depends\n' +- 'on which descriptor methods are defined. A descriptor can ' +- 'define any\n' +- 'combination of "__get__()", "__set__()" and "__delete__()". ' +- 'If it\n' +- 'does not define "__get__()", then accessing the attribute ' +- 'will return\n' +- 'the descriptor object itself unless there is a value in the ' +- 'object’s\n' +- 'instance dictionary. If the descriptor defines "__set__()" ' +- 'and/or\n' +- '"__delete__()", it is a data descriptor; if it defines ' +- 'neither, it is\n' +- 'a non-data descriptor. Normally, data descriptors define ' +- 'both\n' +- '"__get__()" and "__set__()", while non-data descriptors have ' +- 'just the\n' +- '"__get__()" method. Data descriptors with "__get__()" and ' +- '"__set__()"\n' +- '(and/or "__delete__()") defined always override a ' +- 'redefinition in an\n' +- 'instance dictionary. In contrast, non-data descriptors can ' +- 'be\n' +- 'overridden by instances.\n' +- '\n' +- 'Python methods (including those decorated with ' +- '"@staticmethod" and\n' +- '"@classmethod") are implemented as non-data descriptors. ' +- 'Accordingly,\n' +- 'instances can redefine and override methods. This allows ' +- 'individual\n' +- 'instances to acquire behaviors that differ from other ' +- 'instances of the\n' +- 'same class.\n' +- '\n' +- 'The "property()" function is implemented as a data ' +- 'descriptor.\n' +- 'Accordingly, instances cannot override the behavior of a ' +- 'property.\n' +- '\n' +- '\n' +- '__slots__\n' +- '---------\n' +- '\n' +- '*__slots__* allow us to explicitly declare data members ' +- '(like\n' +- 'properties) and deny the creation of "__dict__" and ' +- '*__weakref__*\n' +- '(unless explicitly declared in *__slots__* or available in a ' +- 'parent.)\n' +- '\n' +- 'The space saved over using "__dict__" can be significant. ' +- 'Attribute\n' +- 'lookup speed can be significantly improved as well.\n' +- '\n' +- 'object.__slots__\n' +- '\n' +- ' This class variable can be assigned a string, iterable, ' +- 'or sequence\n' +- ' of strings with variable names used by instances. ' +- '*__slots__*\n' +- ' reserves space for the declared variables and prevents ' +- 'the\n' +- ' automatic creation of "__dict__" and *__weakref__* for ' +- 'each\n' +- ' instance.\n' +- '\n' +- 'Notes on using *__slots__*:\n' +- '\n' +- '* When inheriting from a class without *__slots__*, the ' +- '"__dict__" and\n' +- ' *__weakref__* attribute of the instances will always be ' +- 'accessible.\n' +- '\n' +- '* Without a "__dict__" variable, instances cannot be ' +- 'assigned new\n' +- ' variables not listed in the *__slots__* definition. ' +- 'Attempts to\n' +- ' assign to an unlisted variable name raises ' +- '"AttributeError". If\n' +- ' dynamic assignment of new variables is desired, then add\n' +- ' "\'__dict__\'" to the sequence of strings in the ' +- '*__slots__*\n' +- ' declaration.\n' +- '\n' +- '* Without a *__weakref__* variable for each instance, ' +- 'classes defining\n' +- ' *__slots__* do not support "weak references" to its ' +- 'instances. If\n' +- ' weak reference support is needed, then add ' +- '"\'__weakref__\'" to the\n' +- ' sequence of strings in the *__slots__* declaration.\n' +- '\n' +- '* *__slots__* are implemented at the class level by ' +- 'creating\n' +- ' descriptors for each variable name. As a result, class ' +- 'attributes\n' +- ' cannot be used to set default values for instance ' +- 'variables defined\n' +- ' by *__slots__*; otherwise, the class attribute would ' +- 'overwrite the\n' +- ' descriptor assignment.\n' +- '\n' +- '* The action of a *__slots__* declaration is not limited to ' +- 'the class\n' +- ' where it is defined. *__slots__* declared in parents are ' +- 'available\n' +- ' in child classes. However, instances of a child subclass ' +- 'will get a\n' +- ' "__dict__" and *__weakref__* unless the subclass also ' +- 'defines\n' +- ' *__slots__* (which should only contain names of any ' +- '*additional*\n' +- ' slots).\n' +- '\n' +- '* If a class defines a slot also defined in a base class, ' +- 'the instance\n' +- ' variable defined by the base class slot is inaccessible ' +- '(except by\n' +- ' retrieving its descriptor directly from the base class). ' +- 'This\n' +- ' renders the meaning of the program undefined. In the ' +- 'future, a\n' +- ' check may be added to prevent this.\n' +- '\n' +- '* "TypeError" will be raised if nonempty *__slots__* are ' +- 'defined for a\n' +- ' class derived from a ""variable-length" built-in type" ' +- 'such as\n' +- ' "int", "bytes", and "tuple".\n' +- '\n' +- '* Any non-string *iterable* may be assigned to *__slots__*.\n' +- '\n' +- '* If a "dictionary" is used to assign *__slots__*, the ' +- 'dictionary keys\n' +- ' will be used as the slot names. The values of the ' +- 'dictionary can be\n' +- ' used to provide per-attribute docstrings that will be ' +- 'recognised by\n' +- ' "inspect.getdoc()" and displayed in the output of ' +- '"help()".\n' +- '\n' +- '* "__class__" assignment works only if both classes have the ' +- 'same\n' +- ' *__slots__*.\n' +- '\n' +- '* Multiple inheritance with multiple slotted parent classes ' +- 'can be\n' +- ' used, but only one parent is allowed to have attributes ' +- 'created by\n' +- ' slots (the other bases must have empty slot layouts) - ' +- 'violations\n' +- ' raise "TypeError".\n' +- '\n' +- '* If an *iterator* is used for *__slots__* then a ' +- '*descriptor* is\n' +- ' created for each of the iterator’s values. However, the ' +- '*__slots__*\n' +- ' attribute will be an empty iterator.\n' +- '\n' +- '\n' +- 'Customizing class creation\n' +- '==========================\n' +- '\n' +- 'Whenever a class inherits from another class, ' +- '"__init_subclass__()" is\n' +- 'called on the parent class. This way, it is possible to ' +- 'write classes\n' +- 'which change the behavior of subclasses. This is closely ' +- 'related to\n' +- 'class decorators, but where class decorators only affect the ' +- 'specific\n' +- 'class they’re applied to, "__init_subclass__" solely applies ' +- 'to future\n' +- 'subclasses of the class defining the method.\n' +- '\n' +- 'classmethod object.__init_subclass__(cls)\n' +- '\n' +- ' This method is called whenever the containing class is ' +- 'subclassed.\n' +- ' *cls* is then the new subclass. If defined as a normal ' +- 'instance\n' +- ' method, this method is implicitly converted to a class ' +- 'method.\n' +- '\n' +- ' Keyword arguments which are given to a new class are ' +- 'passed to the\n' +- ' parent class’s "__init_subclass__". For compatibility ' +- 'with other\n' +- ' classes using "__init_subclass__", one should take out ' +- 'the needed\n' +- ' keyword arguments and pass the others over to the base ' +- 'class, as\n' +- ' in:\n' +- '\n' +- ' class Philosopher:\n' +- ' def __init_subclass__(cls, /, default_name, ' +- '**kwargs):\n' +- ' super().__init_subclass__(**kwargs)\n' +- ' cls.default_name = default_name\n' +- '\n' +- ' class AustralianPhilosopher(Philosopher, ' +- 'default_name="Bruce"):\n' +- ' pass\n' +- '\n' +- ' The default implementation "object.__init_subclass__" ' +- 'does nothing,\n' +- ' but raises an error if it is called with any arguments.\n' +- '\n' +- ' Note:\n' +- '\n' +- ' The metaclass hint "metaclass" is consumed by the rest ' +- 'of the\n' +- ' type machinery, and is never passed to ' +- '"__init_subclass__"\n' +- ' implementations. The actual metaclass (rather than the ' +- 'explicit\n' +- ' hint) can be accessed as "type(cls)".\n' +- '\n' +- ' Added in version 3.6.\n' +- '\n' +- 'When a class is created, "type.__new__()" scans the class ' +- 'variables\n' +- 'and makes callbacks to those with a "__set_name__()" hook.\n' +- '\n' +- 'object.__set_name__(self, owner, name)\n' +- '\n' +- ' Automatically called at the time the owning class *owner* ' +- 'is\n' +- ' created. The object has been assigned to *name* in that ' +- 'class:\n' +- '\n' +- ' class A:\n' +- ' x = C() # Automatically calls: x.__set_name__(A, ' +- "'x')\n" +- '\n' +- ' If the class variable is assigned after the class is ' +- 'created,\n' +- ' "__set_name__()" will not be called automatically. If ' +- 'needed,\n' +- ' "__set_name__()" can be called directly:\n' +- '\n' +- ' class A:\n' +- ' pass\n' +- '\n' +- ' c = C()\n' +- ' A.x = c # The hook is not called\n' +- " c.__set_name__(A, 'x') # Manually invoke the hook\n" +- '\n' +- ' See Creating the class object for more details.\n' +- '\n' +- ' Added in version 3.6.\n' +- '\n' +- '\n' +- 'Metaclasses\n' +- '-----------\n' +- '\n' +- 'By default, classes are constructed using "type()". The ' +- 'class body is\n' +- 'executed in a new namespace and the class name is bound ' +- 'locally to the\n' +- 'result of "type(name, bases, namespace)".\n' +- '\n' +- 'The class creation process can be customized by passing the\n' +- '"metaclass" keyword argument in the class definition line, ' +- 'or by\n' +- 'inheriting from an existing class that included such an ' +- 'argument. In\n' +- 'the following example, both "MyClass" and "MySubclass" are ' +- 'instances\n' +- 'of "Meta":\n' +- '\n' +- ' class Meta(type):\n' +- ' pass\n' +- '\n' +- ' class MyClass(metaclass=Meta):\n' +- ' pass\n' +- '\n' +- ' class MySubclass(MyClass):\n' +- ' pass\n' +- '\n' +- 'Any other keyword arguments that are specified in the class ' +- 'definition\n' +- 'are passed through to all metaclass operations described ' +- 'below.\n' +- '\n' +- 'When a class definition is executed, the following steps ' +- 'occur:\n' +- '\n' +- '* MRO entries are resolved;\n' +- '\n' +- '* the appropriate metaclass is determined;\n' +- '\n' +- '* the class namespace is prepared;\n' +- '\n' +- '* the class body is executed;\n' +- '\n' +- '* the class object is created.\n' +- '\n' +- '\n' +- 'Resolving MRO entries\n' +- '---------------------\n' +- '\n' +- 'object.__mro_entries__(self, bases)\n' +- '\n' +- ' If a base that appears in a class definition is not an ' +- 'instance of\n' +- ' "type", then an "__mro_entries__()" method is searched on ' +- 'the base.\n' +- ' If an "__mro_entries__()" method is found, the base is ' +- 'substituted\n' +- ' with the result of a call to "__mro_entries__()" when ' +- 'creating the\n' +- ' class. The method is called with the original bases tuple ' +- 'passed to\n' +- ' the *bases* parameter, and must return a tuple of classes ' +- 'that will\n' +- ' be used instead of the base. The returned tuple may be ' +- 'empty: in\n' +- ' these cases, the original base is ignored.\n' +- '\n' +- 'See also:\n' +- '\n' +- ' "types.resolve_bases()"\n' +- ' Dynamically resolve bases that are not instances of ' +- '"type".\n' +- '\n' +- ' "types.get_original_bases()"\n' +- ' Retrieve a class’s “original bases†prior to ' +- 'modifications by\n' +- ' "__mro_entries__()".\n' +- '\n' +- ' **PEP 560**\n' +- ' Core support for typing module and generic types.\n' +- '\n' +- '\n' +- 'Determining the appropriate metaclass\n' +- '-------------------------------------\n' +- '\n' +- 'The appropriate metaclass for a class definition is ' +- 'determined as\n' +- 'follows:\n' +- '\n' +- '* if no bases and no explicit metaclass are given, then ' +- '"type()" is\n' +- ' used;\n' +- '\n' +- '* if an explicit metaclass is given and it is *not* an ' +- 'instance of\n' +- ' "type()", then it is used directly as the metaclass;\n' +- '\n' +- '* if an instance of "type()" is given as the explicit ' +- 'metaclass, or\n' +- ' bases are defined, then the most derived metaclass is ' +- 'used.\n' +- '\n' +- 'The most derived metaclass is selected from the explicitly ' +- 'specified\n' +- 'metaclass (if any) and the metaclasses (i.e. "type(cls)") of ' +- 'all\n' +- 'specified base classes. The most derived metaclass is one ' +- 'which is a\n' +- 'subtype of *all* of these candidate metaclasses. If none of ' +- 'the\n' +- 'candidate metaclasses meets that criterion, then the class ' +- 'definition\n' +- 'will fail with "TypeError".\n' +- '\n' +- '\n' +- 'Preparing the class namespace\n' +- '-----------------------------\n' +- '\n' +- 'Once the appropriate metaclass has been identified, then the ' +- 'class\n' +- 'namespace is prepared. If the metaclass has a "__prepare__" ' +- 'attribute,\n' +- 'it is called as "namespace = metaclass.__prepare__(name, ' +- 'bases,\n' +- '**kwds)" (where the additional keyword arguments, if any, ' +- 'come from\n' +- 'the class definition). The "__prepare__" method should be ' +- 'implemented\n' +- 'as a "classmethod". The namespace returned by "__prepare__" ' +- 'is passed\n' +- 'in to "__new__", but when the final class object is created ' +- 'the\n' +- 'namespace is copied into a new "dict".\n' +- '\n' +- 'If the metaclass has no "__prepare__" attribute, then the ' +- 'class\n' +- 'namespace is initialised as an empty ordered mapping.\n' +- '\n' +- 'See also:\n' +- '\n' +- ' **PEP 3115** - Metaclasses in Python 3000\n' +- ' Introduced the "__prepare__" namespace hook\n' +- '\n' +- '\n' +- 'Executing the class body\n' +- '------------------------\n' +- '\n' +- 'The class body is executed (approximately) as "exec(body, ' +- 'globals(),\n' +- 'namespace)". The key difference from a normal call to ' +- '"exec()" is that\n' +- 'lexical scoping allows the class body (including any ' +- 'methods) to\n' +- 'reference names from the current and outer scopes when the ' +- 'class\n' +- 'definition occurs inside a function.\n' +- '\n' +- 'However, even when the class definition occurs inside the ' +- 'function,\n' +- 'methods defined inside the class still cannot see names ' +- 'defined at the\n' +- 'class scope. Class variables must be accessed through the ' +- 'first\n' +- 'parameter of instance or class methods, or through the ' +- 'implicit\n' +- 'lexically scoped "__class__" reference described in the next ' +- 'section.\n' +- '\n' +- '\n' +- 'Creating the class object\n' +- '-------------------------\n' +- '\n' +- 'Once the class namespace has been populated by executing the ' +- 'class\n' +- 'body, the class object is created by calling ' +- '"metaclass(name, bases,\n' +- 'namespace, **kwds)" (the additional keywords passed here are ' +- 'the same\n' +- 'as those passed to "__prepare__").\n' +- '\n' +- 'This class object is the one that will be referenced by the ' +- 'zero-\n' +- 'argument form of "super()". "__class__" is an implicit ' +- 'closure\n' +- 'reference created by the compiler if any methods in a class ' +- 'body refer\n' +- 'to either "__class__" or "super". This allows the zero ' +- 'argument form\n' +- 'of "super()" to correctly identify the class being defined ' +- 'based on\n' +- 'lexical scoping, while the class or instance that was used ' +- 'to make the\n' +- 'current call is identified based on the first argument ' +- 'passed to the\n' +- 'method.\n' +- '\n' +- '**CPython implementation detail:** In CPython 3.6 and later, ' +- 'the\n' +- '"__class__" cell is passed to the metaclass as a ' +- '"__classcell__" entry\n' +- 'in the class namespace. If present, this must be propagated ' +- 'up to the\n' +- '"type.__new__" call in order for the class to be ' +- 'initialised\n' +- 'correctly. Failing to do so will result in a "RuntimeError" ' +- 'in Python\n' +- '3.8.\n' +- '\n' +- 'When using the default metaclass "type", or any metaclass ' +- 'that\n' +- 'ultimately calls "type.__new__", the following additional\n' +- 'customization steps are invoked after creating the class ' +- 'object:\n' +- '\n' +- '1. The "type.__new__" method collects all of the attributes ' +- 'in the\n' +- ' class namespace that define a "__set_name__()" method;\n' +- '\n' +- '2. Those "__set_name__" methods are called with the class ' +- 'being\n' +- ' defined and the assigned name of that particular ' +- 'attribute;\n' +- '\n' +- '3. The "__init_subclass__()" hook is called on the immediate ' +- 'parent of\n' +- ' the new class in its method resolution order.\n' +- '\n' +- 'After the class object is created, it is passed to the ' +- 'class\n' +- 'decorators included in the class definition (if any) and the ' +- 'resulting\n' +- 'object is bound in the local namespace as the defined ' +- 'class.\n' +- '\n' +- 'When a new class is created by "type.__new__", the object ' +- 'provided as\n' +- 'the namespace parameter is copied to a new ordered mapping ' +- 'and the\n' +- 'original object is discarded. The new copy is wrapped in a ' +- 'read-only\n' +- 'proxy, which becomes the "__dict__" attribute of the class ' +- 'object.\n' +- '\n' +- 'See also:\n' +- '\n' +- ' **PEP 3135** - New super\n' +- ' Describes the implicit "__class__" closure reference\n' +- '\n' +- '\n' +- 'Uses for metaclasses\n' +- '--------------------\n' +- '\n' +- 'The potential uses for metaclasses are boundless. Some ideas ' +- 'that have\n' +- 'been explored include enum, logging, interface checking, ' +- 'automatic\n' +- 'delegation, automatic property creation, proxies, ' +- 'frameworks, and\n' +- 'automatic resource locking/synchronization.\n' +- '\n' +- '\n' +- 'Customizing instance and subclass checks\n' +- '========================================\n' +- '\n' +- 'The following methods are used to override the default ' +- 'behavior of the\n' +- '"isinstance()" and "issubclass()" built-in functions.\n' +- '\n' +- 'In particular, the metaclass "abc.ABCMeta" implements these ' +- 'methods in\n' +- 'order to allow the addition of Abstract Base Classes (ABCs) ' +- 'as\n' +- '“virtual base classes†to any class or type (including ' +- 'built-in\n' +- 'types), including other ABCs.\n' +- '\n' +- 'type.__instancecheck__(self, instance)\n' +- '\n' +- ' Return true if *instance* should be considered a (direct ' +- 'or\n' +- ' indirect) instance of *class*. If defined, called to ' +- 'implement\n' +- ' "isinstance(instance, class)".\n' +- '\n' +- 'type.__subclasscheck__(self, subclass)\n' +- '\n' +- ' Return true if *subclass* should be considered a (direct ' +- 'or\n' +- ' indirect) subclass of *class*. If defined, called to ' +- 'implement\n' +- ' "issubclass(subclass, class)".\n' +- '\n' +- 'Note that these methods are looked up on the type ' +- '(metaclass) of a\n' +- 'class. They cannot be defined as class methods in the ' +- 'actual class.\n' +- 'This is consistent with the lookup of special methods that ' +- 'are called\n' +- 'on instances, only in this case the instance is itself a ' +- 'class.\n' +- '\n' +- 'See also:\n' +- '\n' +- ' **PEP 3119** - Introducing Abstract Base Classes\n' +- ' Includes the specification for customizing ' +- '"isinstance()" and\n' +- ' "issubclass()" behavior through "__instancecheck__()" ' +- 'and\n' +- ' "__subclasscheck__()", with motivation for this ' +- 'functionality in\n' +- ' the context of adding Abstract Base Classes (see the ' +- '"abc"\n' +- ' module) to the language.\n' +- '\n' +- '\n' +- 'Emulating generic types\n' +- '=======================\n' +- '\n' +- 'When using *type annotations*, it is often useful to ' +- '*parameterize* a\n' +- '*generic type* using Python’s square-brackets notation. For ' +- 'example,\n' +- 'the annotation "list[int]" might be used to signify a "list" ' +- 'in which\n' +- 'all the elements are of type "int".\n' +- '\n' +- 'See also:\n' +- '\n' +- ' **PEP 484** - Type Hints\n' +- ' Introducing Python’s framework for type annotations\n' +- '\n' +- ' Generic Alias Types\n' +- ' Documentation for objects representing parameterized ' +- 'generic\n' +- ' classes\n' +- '\n' +- ' Generics, user-defined generics and "typing.Generic"\n' +- ' Documentation on how to implement generic classes that ' +- 'can be\n' +- ' parameterized at runtime and understood by static ' +- 'type-checkers.\n' +- '\n' +- 'A class can *generally* only be parameterized if it defines ' +- 'the\n' +- 'special class method "__class_getitem__()".\n' +- '\n' +- 'classmethod object.__class_getitem__(cls, key)\n' +- '\n' +- ' Return an object representing the specialization of a ' +- 'generic class\n' +- ' by type arguments found in *key*.\n' +- '\n' +- ' When defined on a class, "__class_getitem__()" is ' +- 'automatically a\n' +- ' class method. As such, there is no need for it to be ' +- 'decorated with\n' +- ' "@classmethod" when it is defined.\n' +- '\n' +- '\n' +- 'The purpose of *__class_getitem__*\n' +- '----------------------------------\n' +- '\n' +- 'The purpose of "__class_getitem__()" is to allow runtime\n' +- 'parameterization of standard-library generic classes in ' +- 'order to more\n' +- 'easily apply *type hints* to these classes.\n' +- '\n' +- 'To implement custom generic classes that can be ' +- 'parameterized at\n' +- 'runtime and understood by static type-checkers, users should ' +- 'either\n' +- 'inherit from a standard library class that already ' +- 'implements\n' +- '"__class_getitem__()", or inherit from "typing.Generic", ' +- 'which has its\n' +- 'own implementation of "__class_getitem__()".\n' +- '\n' +- 'Custom implementations of "__class_getitem__()" on classes ' +- 'defined\n' +- 'outside of the standard library may not be understood by ' +- 'third-party\n' +- 'type-checkers such as mypy. Using "__class_getitem__()" on ' +- 'any class\n' +- 'for purposes other than type hinting is discouraged.\n' +- '\n' +- '\n' +- '*__class_getitem__* versus *__getitem__*\n' +- '----------------------------------------\n' +- '\n' +- 'Usually, the subscription of an object using square brackets ' +- 'will call\n' +- 'the "__getitem__()" instance method defined on the object’s ' +- 'class.\n' +- 'However, if the object being subscribed is itself a class, ' +- 'the class\n' +- 'method "__class_getitem__()" may be called instead.\n' +- '"__class_getitem__()" should return a GenericAlias object if ' +- 'it is\n' +- 'properly defined.\n' +- '\n' +- 'Presented with the *expression* "obj[x]", the Python ' +- 'interpreter\n' +- 'follows something like the following process to decide ' +- 'whether\n' +- '"__getitem__()" or "__class_getitem__()" should be called:\n' +- '\n' +- ' from inspect import isclass\n' +- '\n' +- ' def subscribe(obj, x):\n' +- ' """Return the result of the expression \'obj[x]\'"""\n' +- '\n' +- ' class_of_obj = type(obj)\n' +- '\n' +- ' # If the class of obj defines __getitem__,\n' +- ' # call class_of_obj.__getitem__(obj, x)\n' +- " if hasattr(class_of_obj, '__getitem__'):\n" +- ' return class_of_obj.__getitem__(obj, x)\n' +- '\n' +- ' # Else, if obj is a class and defines ' +- '__class_getitem__,\n' +- ' # call obj.__class_getitem__(x)\n' +- ' elif isclass(obj) and hasattr(obj, ' +- "'__class_getitem__'):\n" +- ' return obj.__class_getitem__(x)\n' +- '\n' +- ' # Else, raise an exception\n' +- ' else:\n' +- ' raise TypeError(\n' +- ' f"\'{class_of_obj.__name__}\' object is not ' +- 'subscriptable"\n' +- ' )\n' +- '\n' +- 'In Python, all classes are themselves instances of other ' +- 'classes. The\n' +- 'class of a class is known as that class’s *metaclass*, and ' +- 'most\n' +- 'classes have the "type" class as their metaclass. "type" ' +- 'does not\n' +- 'define "__getitem__()", meaning that expressions such as ' +- '"list[int]",\n' +- '"dict[str, float]" and "tuple[str, bytes]" all result in\n' +- '"__class_getitem__()" being called:\n' +- '\n' +- ' >>> # list has class "type" as its metaclass, like most ' +- 'classes:\n' +- ' >>> type(list)\n' +- " \n" +- ' >>> type(dict) == type(list) == type(tuple) == type(str) ' +- '== type(bytes)\n' +- ' True\n' +- ' >>> # "list[int]" calls "list.__class_getitem__(int)"\n' +- ' >>> list[int]\n' +- ' list[int]\n' +- ' >>> # list.__class_getitem__ returns a GenericAlias ' +- 'object:\n' +- ' >>> type(list[int])\n' +- " \n" +- '\n' +- 'However, if a class has a custom metaclass that defines\n' +- '"__getitem__()", subscribing the class may result in ' +- 'different\n' +- 'behaviour. An example of this can be found in the "enum" ' +- 'module:\n' +- '\n' +- ' >>> from enum import Enum\n' +- ' >>> class Menu(Enum):\n' +- ' ... """A breakfast menu"""\n' +- " ... SPAM = 'spam'\n" +- " ... BACON = 'bacon'\n" +- ' ...\n' +- ' >>> # Enum classes have a custom metaclass:\n' +- ' >>> type(Menu)\n' +- " \n" +- ' >>> # EnumMeta defines __getitem__,\n' +- ' >>> # so __class_getitem__ is not called,\n' +- ' >>> # and the result is not a GenericAlias object:\n' +- " >>> Menu['SPAM']\n" +- " \n" +- " >>> type(Menu['SPAM'])\n" +- " \n" +- '\n' +- 'See also:\n' +- '\n' +- ' **PEP 560** - Core Support for typing module and generic ' +- 'types\n' +- ' Introducing "__class_getitem__()", and outlining when ' +- 'a\n' +- ' subscription results in "__class_getitem__()" being ' +- 'called\n' +- ' instead of "__getitem__()"\n' +- '\n' +- '\n' +- 'Emulating callable objects\n' +- '==========================\n' +- '\n' +- 'object.__call__(self[, args...])\n' +- '\n' +- ' Called when the instance is “called†as a function; if ' +- 'this method\n' +- ' is defined, "x(arg1, arg2, ...)" roughly translates to\n' +- ' "type(x).__call__(x, arg1, ...)". The "object" class ' +- 'itself does\n' +- ' not provide this method.\n' +- '\n' +- '\n' +- 'Emulating container types\n' +- '=========================\n' +- '\n' +- 'The following methods can be defined to implement container ' +- 'objects.\n' +- 'None of them are provided by the "object" class itself. ' +- 'Containers\n' +- 'usually are *sequences* (such as "lists" or "tuples") or ' +- '*mappings*\n' +- '(like *dictionaries*), but can represent other containers as ' +- 'well.\n' +- 'The first set of methods is used either to emulate a ' +- 'sequence or to\n' +- 'emulate a mapping; the difference is that for a sequence, ' +- 'the\n' +- 'allowable keys should be the integers *k* for which "0 <= k ' +- '< N" where\n' +- '*N* is the length of the sequence, or "slice" objects, which ' +- 'define a\n' +- 'range of items. It is also recommended that mappings ' +- 'provide the\n' +- 'methods "keys()", "values()", "items()", "get()", ' +- '"clear()",\n' +- '"setdefault()", "pop()", "popitem()", "copy()", and ' +- '"update()"\n' +- 'behaving similar to those for Python’s standard "dictionary" ' +- 'objects.\n' +- 'The "collections.abc" module provides a "MutableMapping" ' +- '*abstract\n' +- 'base class* to help create those methods from a base set of\n' +- '"__getitem__()", "__setitem__()", "__delitem__()", and ' +- '"keys()".\n' +- 'Mutable sequences should provide methods "append()", ' +- '"count()",\n' +- '"index()", "extend()", "insert()", "pop()", "remove()", ' +- '"reverse()"\n' +- 'and "sort()", like Python standard "list" objects. Finally, ' +- 'sequence\n' +- 'types should implement addition (meaning concatenation) and\n' +- 'multiplication (meaning repetition) by defining the methods\n' +- '"__add__()", "__radd__()", "__iadd__()", "__mul__()", ' +- '"__rmul__()" and\n' +- '"__imul__()" described below; they should not define other ' +- 'numerical\n' +- 'operators. It is recommended that both mappings and ' +- 'sequences\n' +- 'implement the "__contains__()" method to allow efficient use ' +- 'of the\n' +- '"in" operator; for mappings, "in" should search the ' +- 'mapping’s keys;\n' +- 'for sequences, it should search through the values. It is ' +- 'further\n' +- 'recommended that both mappings and sequences implement the\n' +- '"__iter__()" method to allow efficient iteration through ' +- 'the\n' +- 'container; for mappings, "__iter__()" should iterate through ' +- 'the\n' +- 'object’s keys; for sequences, it should iterate through the ' +- 'values.\n' +- '\n' +- 'object.__len__(self)\n' +- '\n' +- ' Called to implement the built-in function "len()". ' +- 'Should return\n' +- ' the length of the object, an integer ">=" 0. Also, an ' +- 'object that\n' +- ' doesn’t define a "__bool__()" method and whose ' +- '"__len__()" method\n' +- ' returns zero is considered to be false in a Boolean ' +- 'context.\n' +- '\n' +- ' **CPython implementation detail:** In CPython, the length ' +- 'is\n' +- ' required to be at most "sys.maxsize". If the length is ' +- 'larger than\n' +- ' "sys.maxsize" some features (such as "len()") may raise\n' +- ' "OverflowError". To prevent raising "OverflowError" by ' +- 'truth value\n' +- ' testing, an object must define a "__bool__()" method.\n' +- '\n' +- 'object.__length_hint__(self)\n' +- '\n' +- ' Called to implement "operator.length_hint()". Should ' +- 'return an\n' +- ' estimated length for the object (which may be greater or ' +- 'less than\n' +- ' the actual length). The length must be an integer ">=" 0. ' +- 'The\n' +- ' return value may also be "NotImplemented", which is ' +- 'treated the\n' +- ' same as if the "__length_hint__" method didn’t exist at ' +- 'all. This\n' +- ' method is purely an optimization and is never required ' +- 'for\n' +- ' correctness.\n' +- '\n' +- ' Added in version 3.4.\n' +- '\n' +- 'Note:\n' +- '\n' +- ' Slicing is done exclusively with the following three ' +- 'methods. A\n' +- ' call like\n' +- '\n' +- ' a[1:2] = b\n' +- '\n' +- ' is translated to\n' +- '\n' +- ' a[slice(1, 2, None)] = b\n' +- '\n' +- ' and so forth. Missing slice items are always filled in ' +- 'with "None".\n' +- '\n' +- 'object.__getitem__(self, key)\n' +- '\n' +- ' Called to implement evaluation of "self[key]". For ' +- '*sequence*\n' +- ' types, the accepted keys should be integers. Optionally, ' +- 'they may\n' +- ' support "slice" objects as well. Negative index support ' +- 'is also\n' +- ' optional. If *key* is of an inappropriate type, ' +- '"TypeError" may be\n' +- ' raised; if *key* is a value outside the set of indexes ' +- 'for the\n' +- ' sequence (after any special interpretation of negative ' +- 'values),\n' +- ' "IndexError" should be raised. For *mapping* types, if ' +- '*key* is\n' +- ' missing (not in the container), "KeyError" should be ' +- 'raised.\n' +- '\n' +- ' Note:\n' +- '\n' +- ' "for" loops expect that an "IndexError" will be raised ' +- 'for\n' +- ' illegal indexes to allow proper detection of the end of ' +- 'the\n' +- ' sequence.\n' +- '\n' +- ' Note:\n' +- '\n' +- ' When subscripting a *class*, the special class method\n' +- ' "__class_getitem__()" may be called instead of ' +- '"__getitem__()".\n' +- ' See __class_getitem__ versus __getitem__ for more ' +- 'details.\n' +- '\n' +- 'object.__setitem__(self, key, value)\n' +- '\n' +- ' Called to implement assignment to "self[key]". Same note ' +- 'as for\n' +- ' "__getitem__()". This should only be implemented for ' +- 'mappings if\n' +- ' the objects support changes to the values for keys, or if ' +- 'new keys\n' +- ' can be added, or for sequences if elements can be ' +- 'replaced. The\n' +- ' same exceptions should be raised for improper *key* ' +- 'values as for\n' +- ' the "__getitem__()" method.\n' +- '\n' +- 'object.__delitem__(self, key)\n' +- '\n' +- ' Called to implement deletion of "self[key]". Same note ' +- 'as for\n' +- ' "__getitem__()". This should only be implemented for ' +- 'mappings if\n' +- ' the objects support removal of keys, or for sequences if ' +- 'elements\n' +- ' can be removed from the sequence. The same exceptions ' +- 'should be\n' +- ' raised for improper *key* values as for the ' +- '"__getitem__()" method.\n' +- '\n' +- 'object.__missing__(self, key)\n' +- '\n' +- ' Called by "dict"."__getitem__()" to implement "self[key]" ' +- 'for dict\n' +- ' subclasses when key is not in the dictionary.\n' +- '\n' +- 'object.__iter__(self)\n' +- '\n' +- ' This method is called when an *iterator* is required for ' +- 'a\n' +- ' container. This method should return a new iterator ' +- 'object that can\n' +- ' iterate over all the objects in the container. For ' +- 'mappings, it\n' +- ' should iterate over the keys of the container.\n' +- '\n' +- 'object.__reversed__(self)\n' +- '\n' +- ' Called (if present) by the "reversed()" built-in to ' +- 'implement\n' +- ' reverse iteration. It should return a new iterator ' +- 'object that\n' +- ' iterates over all the objects in the container in reverse ' +- 'order.\n' +- '\n' +- ' If the "__reversed__()" method is not provided, the ' +- '"reversed()"\n' +- ' built-in will fall back to using the sequence protocol ' +- '("__len__()"\n' +- ' and "__getitem__()"). Objects that support the sequence ' +- 'protocol\n' +- ' should only provide "__reversed__()" if they can provide ' +- 'an\n' +- ' implementation that is more efficient than the one ' +- 'provided by\n' +- ' "reversed()".\n' +- '\n' +- 'The membership test operators ("in" and "not in") are ' +- 'normally\n' +- 'implemented as an iteration through a container. However, ' +- 'container\n' +- 'objects can supply the following special method with a more ' +- 'efficient\n' +- 'implementation, which also does not require the object be ' +- 'iterable.\n' +- '\n' +- 'object.__contains__(self, item)\n' +- '\n' +- ' Called to implement membership test operators. Should ' +- 'return true\n' +- ' if *item* is in *self*, false otherwise. For mapping ' +- 'objects, this\n' +- ' should consider the keys of the mapping rather than the ' +- 'values or\n' +- ' the key-item pairs.\n' +- '\n' +- ' For objects that don’t define "__contains__()", the ' +- 'membership test\n' +- ' first tries iteration via "__iter__()", then the old ' +- 'sequence\n' +- ' iteration protocol via "__getitem__()", see this section ' +- 'in the\n' +- ' language reference.\n' +- '\n' +- '\n' +- 'Emulating numeric types\n' +- '=======================\n' +- '\n' +- 'The following methods can be defined to emulate numeric ' +- 'objects.\n' +- 'Methods corresponding to operations that are not supported ' +- 'by the\n' +- 'particular kind of number implemented (e.g., bitwise ' +- 'operations for\n' +- 'non-integral numbers) should be left undefined.\n' +- '\n' +- 'object.__add__(self, other)\n' +- 'object.__sub__(self, other)\n' +- 'object.__mul__(self, other)\n' +- 'object.__matmul__(self, other)\n' +- 'object.__truediv__(self, other)\n' +- 'object.__floordiv__(self, other)\n' +- 'object.__mod__(self, other)\n' +- 'object.__divmod__(self, other)\n' +- 'object.__pow__(self, other[, modulo])\n' +- 'object.__lshift__(self, other)\n' +- 'object.__rshift__(self, other)\n' +- 'object.__and__(self, other)\n' +- 'object.__xor__(self, other)\n' +- 'object.__or__(self, other)\n' +- '\n' +- ' These methods are called to implement the binary ' +- 'arithmetic\n' +- ' operations ("+", "-", "*", "@", "/", "//", "%", ' +- '"divmod()",\n' +- ' "pow()", "**", "<<", ">>", "&", "^", "|"). For instance, ' +- 'to\n' +- ' evaluate the expression "x + y", where *x* is an instance ' +- 'of a\n' +- ' class that has an "__add__()" method, "type(x).__add__(x, ' +- 'y)" is\n' +- ' called. The "__divmod__()" method should be the ' +- 'equivalent to\n' +- ' using "__floordiv__()" and "__mod__()"; it should not be ' +- 'related to\n' +- ' "__truediv__()". Note that "__pow__()" should be defined ' +- 'to accept\n' +- ' an optional third argument if the ternary version of the ' +- 'built-in\n' +- ' "pow()" function is to be supported.\n' +- '\n' +- ' If one of those methods does not support the operation ' +- 'with the\n' +- ' supplied arguments, it should return "NotImplemented".\n' +- '\n' +- 'object.__radd__(self, other)\n' +- 'object.__rsub__(self, other)\n' +- 'object.__rmul__(self, other)\n' +- 'object.__rmatmul__(self, other)\n' +- 'object.__rtruediv__(self, other)\n' +- 'object.__rfloordiv__(self, other)\n' +- 'object.__rmod__(self, other)\n' +- 'object.__rdivmod__(self, other)\n' +- 'object.__rpow__(self, other[, modulo])\n' +- 'object.__rlshift__(self, other)\n' +- 'object.__rrshift__(self, other)\n' +- 'object.__rand__(self, other)\n' +- 'object.__rxor__(self, other)\n' +- 'object.__ror__(self, other)\n' +- '\n' +- ' These methods are called to implement the binary ' +- 'arithmetic\n' +- ' operations ("+", "-", "*", "@", "/", "//", "%", ' +- '"divmod()",\n' +- ' "pow()", "**", "<<", ">>", "&", "^", "|") with reflected ' +- '(swapped)\n' +- ' operands. These functions are only called if the ' +- 'operands are of\n' +- ' different types, when the left operand does not support ' +- 'the\n' +- ' corresponding operation [3], or the right operand’s class ' +- 'is\n' +- ' derived from the left operand’s class. [4] For instance, ' +- 'to\n' +- ' evaluate the expression "x - y", where *y* is an instance ' +- 'of a\n' +- ' class that has an "__rsub__()" method, ' +- '"type(y).__rsub__(y, x)" is\n' +- ' called if "type(x).__sub__(x, y)" returns ' +- '"NotImplemented" or\n' +- ' "type(y)" is a subclass of "type(x)". [5]\n' +- '\n' +- ' Note that ternary "pow()" will not try calling ' +- '"__rpow__()" (the\n' +- ' coercion rules would become too complicated).\n' +- '\n' +- ' Note:\n' +- '\n' +- ' If the right operand’s type is a subclass of the left ' +- 'operand’s\n' +- ' type and that subclass provides a different ' +- 'implementation of the\n' +- ' reflected method for the operation, this method will be ' +- 'called\n' +- ' before the left operand’s non-reflected method. This ' +- 'behavior\n' +- ' allows subclasses to override their ancestors’ ' +- 'operations.\n' +- '\n' +- 'object.__iadd__(self, other)\n' +- 'object.__isub__(self, other)\n' +- 'object.__imul__(self, other)\n' +- 'object.__imatmul__(self, other)\n' +- 'object.__itruediv__(self, other)\n' +- 'object.__ifloordiv__(self, other)\n' +- 'object.__imod__(self, other)\n' +- 'object.__ipow__(self, other[, modulo])\n' +- 'object.__ilshift__(self, other)\n' +- 'object.__irshift__(self, other)\n' +- 'object.__iand__(self, other)\n' +- 'object.__ixor__(self, other)\n' +- 'object.__ior__(self, other)\n' +- '\n' +- ' These methods are called to implement the augmented ' +- 'arithmetic\n' +- ' assignments ("+=", "-=", "*=", "@=", "/=", "//=", "%=", ' +- '"**=",\n' +- ' "<<=", ">>=", "&=", "^=", "|="). These methods should ' +- 'attempt to\n' +- ' do the operation in-place (modifying *self*) and return ' +- 'the result\n' +- ' (which could be, but does not have to be, *self*). If a ' +- 'specific\n' +- ' method is not defined, or if that method returns ' +- '"NotImplemented",\n' +- ' the augmented assignment falls back to the normal ' +- 'methods. For\n' +- ' instance, if *x* is an instance of a class with an ' +- '"__iadd__()"\n' +- ' method, "x += y" is equivalent to "x = x.__iadd__(y)" . ' +- 'If\n' +- ' "__iadd__()" does not exist, or if "x.__iadd__(y)" ' +- 'returns\n' +- ' "NotImplemented", "x.__add__(y)" and "y.__radd__(x)" are\n' +- ' considered, as with the evaluation of "x + y". In ' +- 'certain\n' +- ' situations, augmented assignment can result in unexpected ' +- 'errors\n' +- ' (see Why does a_tuple[i] += [‘item’] raise an exception ' +- 'when the\n' +- ' addition works?), but this behavior is in fact part of ' +- 'the data\n' +- ' model.\n' +- '\n' +- 'object.__neg__(self)\n' +- 'object.__pos__(self)\n' +- 'object.__abs__(self)\n' +- 'object.__invert__(self)\n' +- '\n' +- ' Called to implement the unary arithmetic operations ("-", ' +- '"+",\n' +- ' "abs()" and "~").\n' +- '\n' +- 'object.__complex__(self)\n' +- 'object.__int__(self)\n' +- 'object.__float__(self)\n' +- '\n' +- ' Called to implement the built-in functions "complex()", ' +- '"int()" and\n' +- ' "float()". Should return a value of the appropriate ' +- 'type.\n' +- '\n' +- 'object.__index__(self)\n' +- '\n' +- ' Called to implement "operator.index()", and whenever ' +- 'Python needs\n' +- ' to losslessly convert the numeric object to an integer ' +- 'object (such\n' +- ' as in slicing, or in the built-in "bin()", "hex()" and ' +- '"oct()"\n' +- ' functions). Presence of this method indicates that the ' +- 'numeric\n' +- ' object is an integer type. Must return an integer.\n' +- '\n' +- ' If "__int__()", "__float__()" and "__complex__()" are not ' +- 'defined\n' +- ' then corresponding built-in functions "int()", "float()" ' +- 'and\n' +- ' "complex()" fall back to "__index__()".\n' +- '\n' +- 'object.__round__(self[, ndigits])\n' +- 'object.__trunc__(self)\n' +- 'object.__floor__(self)\n' +- 'object.__ceil__(self)\n' +- '\n' +- ' Called to implement the built-in function "round()" and ' +- '"math"\n' +- ' functions "trunc()", "floor()" and "ceil()". Unless ' +- '*ndigits* is\n' +- ' passed to "__round__()" all these methods should return ' +- 'the value\n' +- ' of the object truncated to an "Integral" (typically an ' +- '"int").\n' +- '\n' +- ' Changed in version 3.14: "int()" no longer delegates to ' +- 'the\n' +- ' "__trunc__()" method.\n' +- '\n' +- '\n' +- 'With Statement Context Managers\n' +- '===============================\n' +- '\n' +- 'A *context manager* is an object that defines the runtime ' +- 'context to\n' +- 'be established when executing a "with" statement. The ' +- 'context manager\n' +- 'handles the entry into, and the exit from, the desired ' +- 'runtime context\n' +- 'for the execution of the block of code. Context managers ' +- 'are normally\n' +- 'invoked using the "with" statement (described in section The ' +- 'with\n' +- 'statement), but can also be used by directly invoking their ' +- 'methods.\n' +- '\n' +- 'Typical uses of context managers include saving and ' +- 'restoring various\n' +- 'kinds of global state, locking and unlocking resources, ' +- 'closing opened\n' +- 'files, etc.\n' +- '\n' +- 'For more information on context managers, see Context ' +- 'Manager Types.\n' +- 'The "object" class itself does not provide the context ' +- 'manager\n' +- 'methods.\n' +- '\n' +- 'object.__enter__(self)\n' +- '\n' +- ' Enter the runtime context related to this object. The ' +- '"with"\n' +- ' statement will bind this method’s return value to the ' +- 'target(s)\n' +- ' specified in the "as" clause of the statement, if any.\n' +- '\n' +- 'object.__exit__(self, exc_type, exc_value, traceback)\n' +- '\n' +- ' Exit the runtime context related to this object. The ' +- 'parameters\n' +- ' describe the exception that caused the context to be ' +- 'exited. If the\n' +- ' context was exited without an exception, all three ' +- 'arguments will\n' +- ' be "None".\n' +- '\n' +- ' If an exception is supplied, and the method wishes to ' +- 'suppress the\n' +- ' exception (i.e., prevent it from being propagated), it ' +- 'should\n' +- ' return a true value. Otherwise, the exception will be ' +- 'processed\n' +- ' normally upon exit from this method.\n' +- '\n' +- ' Note that "__exit__()" methods should not reraise the ' +- 'passed-in\n' +- ' exception; this is the caller’s responsibility.\n' +- '\n' +- 'See also:\n' +- '\n' +- ' **PEP 343** - The “with†statement\n' +- ' The specification, background, and examples for the ' +- 'Python "with"\n' +- ' statement.\n' +- '\n' +- '\n' +- 'Customizing positional arguments in class pattern matching\n' +- '==========================================================\n' +- '\n' +- 'When using a class name in a pattern, positional arguments ' +- 'in the\n' +- 'pattern are not allowed by default, i.e. "case MyClass(x, ' +- 'y)" is\n' +- 'typically invalid without special support in "MyClass". To ' +- 'be able to\n' +- 'use that kind of pattern, the class needs to define a ' +- '*__match_args__*\n' +- 'attribute.\n' +- '\n' +- 'object.__match_args__\n' +- '\n' +- ' This class variable can be assigned a tuple of strings. ' +- 'When this\n' +- ' class is used in a class pattern with positional ' +- 'arguments, each\n' +- ' positional argument will be converted into a keyword ' +- 'argument,\n' +- ' using the corresponding value in *__match_args__* as the ' +- 'keyword.\n' +- ' The absence of this attribute is equivalent to setting it ' +- 'to "()".\n' +- '\n' +- 'For example, if "MyClass.__match_args__" is "("left", ' +- '"center",\n' +- '"right")" that means that "case MyClass(x, y)" is equivalent ' +- 'to "case\n' +- 'MyClass(left=x, center=y)". Note that the number of ' +- 'arguments in the\n' +- 'pattern must be smaller than or equal to the number of ' +- 'elements in\n' +- '*__match_args__*; if it is larger, the pattern match attempt ' +- 'will\n' +- 'raise a "TypeError".\n' +- '\n' +- 'Added in version 3.10.\n' +- '\n' +- 'See also:\n' +- '\n' +- ' **PEP 634** - Structural Pattern Matching\n' +- ' The specification for the Python "match" statement.\n' +- '\n' +- '\n' +- 'Emulating buffer types\n' +- '======================\n' +- '\n' +- 'The buffer protocol provides a way for Python objects to ' +- 'expose\n' +- 'efficient access to a low-level memory array. This protocol ' +- 'is\n' +- 'implemented by builtin types such as "bytes" and ' +- '"memoryview", and\n' +- 'third-party libraries may define additional buffer types.\n' +- '\n' +- 'While buffer types are usually implemented in C, it is also ' +- 'possible\n' +- 'to implement the protocol in Python.\n' +- '\n' +- 'object.__buffer__(self, flags)\n' +- '\n' +- ' Called when a buffer is requested from *self* (for ' +- 'example, by the\n' +- ' "memoryview" constructor). The *flags* argument is an ' +- 'integer\n' +- ' representing the kind of buffer requested, affecting for ' +- 'example\n' +- ' whether the returned buffer is read-only or writable.\n' +- ' "inspect.BufferFlags" provides a convenient way to ' +- 'interpret the\n' +- ' flags. The method must return a "memoryview" object.\n' +- '\n' +- 'object.__release_buffer__(self, buffer)\n' +- '\n' +- ' Called when a buffer is no longer needed. The *buffer* ' +- 'argument is\n' +- ' a "memoryview" object that was previously returned by\n' +- ' "__buffer__()". The method must release any resources ' +- 'associated\n' +- ' with the buffer. This method should return "None". Buffer ' +- 'objects\n' +- ' that do not need to perform any cleanup are not required ' +- 'to\n' +- ' implement this method.\n' +- '\n' +- 'Added in version 3.12.\n' +- '\n' +- 'See also:\n' +- '\n' +- ' **PEP 688** - Making the buffer protocol accessible in ' +- 'Python\n' +- ' Introduces the Python "__buffer__" and ' +- '"__release_buffer__"\n' +- ' methods.\n' +- '\n' +- ' "collections.abc.Buffer"\n' +- ' ABC for buffer types.\n' +- '\n' +- '\n' +- 'Annotations\n' +- '===========\n' +- '\n' +- 'Functions, classes, and modules may contain *annotations*, ' +- 'which are a\n' +- 'way to associate information (usually *type hints*) with a ' +- 'symbol.\n' +- '\n' +- 'object.__annotations__\n' +- '\n' +- ' This attribute contains the annotations for an object. It ' +- 'is lazily\n' +- ' evaluated, so accessing the attribute may execute ' +- 'arbitrary code\n' +- ' and raise exceptions. If evaluation is successful, the ' +- 'attribute is\n' +- ' set to a dictionary mapping from variable names to ' +- 'annotations.\n' +- '\n' +- ' Changed in version 3.14: Annotations are now lazily ' +- 'evaluated.\n' +- '\n' +- 'object.__annotate__(format)\n' +- '\n' +- ' An *annotate function*. Returns a new dictionary object ' +- 'mapping\n' +- ' attribute/parameter names to their annotation values.\n' +- '\n' +- ' Takes a format parameter specifying the format in which ' +- 'annotations\n' +- ' values should be provided. It must be a member of the\n' +- ' "annotationlib.Format" enum, or an integer with a value\n' +- ' corresponding to a member of the enum.\n' +- '\n' +- ' If an annotate function doesn’t support the requested ' +- 'format, it\n' +- ' must raise "NotImplementedError". Annotate functions must ' +- 'always\n' +- ' support "VALUE" format; they must not raise ' +- '"NotImplementedError()"\n' +- ' when called with this format.\n' +- '\n' +- ' When called with "VALUE" format, an annotate function ' +- 'may raise\n' +- ' "NameError"; it must not raise "NameError" when called ' +- 'requesting\n' +- ' any other format.\n' +- '\n' +- ' If an object does not have any annotations, ' +- '"__annotate__" should\n' +- ' preferably be set to "None" (it can’t be deleted), rather ' +- 'than set\n' +- ' to a function that returns an empty dict.\n' +- '\n' +- ' Added in version 3.14.\n' +- '\n' +- 'See also:\n' +- '\n' +- ' **PEP 649** — Deferred evaluation of annotation using ' +- 'descriptors\n' +- ' Introduces lazy evaluation of annotations and the ' +- '"__annotate__"\n' +- ' function.\n' +- '\n' +- '\n' +- 'Special method lookup\n' +- '=====================\n' +- '\n' +- 'For custom classes, implicit invocations of special methods ' +- 'are only\n' +- 'guaranteed to work correctly if defined on an object’s type, ' +- 'not in\n' +- 'the object’s instance dictionary. That behaviour is the ' +- 'reason why\n' +- 'the following code raises an exception:\n' +- '\n' +- ' >>> class C:\n' +- ' ... pass\n' +- ' ...\n' +- ' >>> c = C()\n' +- ' >>> c.__len__ = lambda: 5\n' +- ' >>> len(c)\n' +- ' Traceback (most recent call last):\n' +- ' File "", line 1, in \n' +- " TypeError: object of type 'C' has no len()\n" +- '\n' +- 'The rationale behind this behaviour lies with a number of ' +- 'special\n' +- 'methods such as "__hash__()" and "__repr__()" that are ' +- 'implemented by\n' +- 'all objects, including type objects. If the implicit lookup ' +- 'of these\n' +- 'methods used the conventional lookup process, they would ' +- 'fail when\n' +- 'invoked on the type object itself:\n' +- '\n' +- ' >>> 1 .__hash__() == hash(1)\n' +- ' True\n' +- ' >>> int.__hash__() == hash(int)\n' +- ' Traceback (most recent call last):\n' +- ' File "", line 1, in \n' +- " TypeError: descriptor '__hash__' of 'int' object needs an " +- 'argument\n' +- '\n' +- 'Incorrectly attempting to invoke an unbound method of a ' +- 'class in this\n' +- 'way is sometimes referred to as ‘metaclass confusion’, and ' +- 'is avoided\n' +- 'by bypassing the instance when looking up special methods:\n' +- '\n' +- ' >>> type(1).__hash__(1) == hash(1)\n' +- ' True\n' +- ' >>> type(int).__hash__(int) == hash(int)\n' +- ' True\n' +- '\n' +- 'In addition to bypassing any instance attributes in the ' +- 'interest of\n' +- 'correctness, implicit special method lookup generally also ' +- 'bypasses\n' +- 'the "__getattribute__()" method even of the object’s ' +- 'metaclass:\n' +- '\n' +- ' >>> class Meta(type):\n' +- ' ... def __getattribute__(*args):\n' +- ' ... print("Metaclass getattribute invoked")\n' +- ' ... return type.__getattribute__(*args)\n' +- ' ...\n' +- ' >>> class C(object, metaclass=Meta):\n' +- ' ... def __len__(self):\n' +- ' ... return 10\n' +- ' ... def __getattribute__(*args):\n' +- ' ... print("Class getattribute invoked")\n' +- ' ... return object.__getattribute__(*args)\n' +- ' ...\n' +- ' >>> c = C()\n' +- ' >>> c.__len__() # Explicit lookup via ' +- 'instance\n' +- ' Class getattribute invoked\n' +- ' 10\n' +- ' >>> type(c).__len__(c) # Explicit lookup via ' +- 'type\n' +- ' Metaclass getattribute invoked\n' +- ' 10\n' +- ' >>> len(c) # Implicit lookup\n' +- ' 10\n' +- '\n' +- 'Bypassing the "__getattribute__()" machinery in this fashion ' +- 'provides\n' +- 'significant scope for speed optimisations within the ' +- 'interpreter, at\n' +- 'the cost of some flexibility in the handling of special ' +- 'methods (the\n' +- 'special method *must* be set on the class object itself in ' +- 'order to be\n' +- 'consistently invoked by the interpreter).\n', +- 'string-methods': 'String Methods\n' +- '**************\n' +- '\n' +- 'Strings implement all of the common sequence operations, ' +- 'along with\n' +- 'the additional methods described below.\n' +- '\n' +- 'Strings also support two styles of string formatting, one ' +- 'providing a\n' +- 'large degree of flexibility and customization (see ' +- '"str.format()",\n' +- 'Format String Syntax and Custom String Formatting) and the ' +- 'other based\n' +- 'on C "printf" style formatting that handles a narrower ' +- 'range of types\n' +- 'and is slightly harder to use correctly, but is often ' +- 'faster for the\n' +- 'cases it can handle (printf-style String Formatting).\n' +- '\n' +- 'The Text Processing Services section of the standard ' +- 'library covers a\n' +- 'number of other modules that provide various text related ' +- 'utilities\n' +- '(including regular expression support in the "re" ' +- 'module).\n' +- '\n' +- 'str.capitalize()\n' +- '\n' +- ' Return a copy of the string with its first character ' +- 'capitalized\n' +- ' and the rest lowercased.\n' +- '\n' +- ' Changed in version 3.8: The first character is now put ' +- 'into\n' +- ' titlecase rather than uppercase. This means that ' +- 'characters like\n' +- ' digraphs will only have their first letter capitalized, ' +- 'instead of\n' +- ' the full character.\n' +- '\n' +- 'str.casefold()\n' +- '\n' +- ' Return a casefolded copy of the string. Casefolded ' +- 'strings may be\n' +- ' used for caseless matching.\n' +- '\n' +- ' Casefolding is similar to lowercasing but more ' +- 'aggressive because\n' +- ' it is intended to remove all case distinctions in a ' +- 'string. For\n' +- ' example, the German lowercase letter "\'ß\'" is ' +- 'equivalent to ""ss"".\n' +- ' Since it is already lowercase, "lower()" would do ' +- 'nothing to "\'ß\'";\n' +- ' "casefold()" converts it to ""ss"".\n' +- '\n' +- ' The casefolding algorithm is described in section 3.13 ' +- '‘Default\n' +- ' Case Folding’ of the Unicode Standard.\n' +- '\n' +- ' Added in version 3.3.\n' +- '\n' +- 'str.center(width[, fillchar])\n' +- '\n' +- ' Return centered in a string of length *width*. Padding ' +- 'is done\n' +- ' using the specified *fillchar* (default is an ASCII ' +- 'space). The\n' +- ' original string is returned if *width* is less than or ' +- 'equal to\n' +- ' "len(s)".\n' +- '\n' +- 'str.count(sub[, start[, end]])\n' +- '\n' +- ' Return the number of non-overlapping occurrences of ' +- 'substring *sub*\n' +- ' in the range [*start*, *end*]. Optional arguments ' +- '*start* and\n' +- ' *end* are interpreted as in slice notation.\n' +- '\n' +- ' If *sub* is empty, returns the number of empty strings ' +- 'between\n' +- ' characters which is the length of the string plus one.\n' +- '\n' +- "str.encode(encoding='utf-8', errors='strict')\n" +- '\n' +- ' Return the string encoded to "bytes".\n' +- '\n' +- ' *encoding* defaults to "\'utf-8\'"; see Standard ' +- 'Encodings for\n' +- ' possible values.\n' +- '\n' +- ' *errors* controls how encoding errors are handled. If ' +- '"\'strict\'"\n' +- ' (the default), a "UnicodeError" exception is raised. ' +- 'Other possible\n' +- ' values are "\'ignore\'", "\'replace\'", ' +- '"\'xmlcharrefreplace\'",\n' +- ' "\'backslashreplace\'" and any other name registered ' +- 'via\n' +- ' "codecs.register_error()". See Error Handlers for ' +- 'details.\n' +- '\n' +- ' For performance reasons, the value of *errors* is not ' +- 'checked for\n' +- ' validity unless an encoding error actually occurs, ' +- 'Python\n' +- ' Development Mode is enabled or a debug build is used.\n' +- '\n' +- ' Changed in version 3.1: Added support for keyword ' +- 'arguments.\n' +- '\n' +- ' Changed in version 3.9: The value of the *errors* ' +- 'argument is now\n' +- ' checked in Python Development Mode and in debug mode.\n' +- '\n' +- 'str.endswith(suffix[, start[, end]])\n' +- '\n' +- ' Return "True" if the string ends with the specified ' +- '*suffix*,\n' +- ' otherwise return "False". *suffix* can also be a tuple ' +- 'of suffixes\n' +- ' to look for. With optional *start*, test beginning at ' +- 'that\n' +- ' position. With optional *end*, stop comparing at that ' +- 'position.\n' +- '\n' +- 'str.expandtabs(tabsize=8)\n' +- '\n' +- ' Return a copy of the string where all tab characters ' +- 'are replaced\n' +- ' by one or more spaces, depending on the current column ' +- 'and the\n' +- ' given tab size. Tab positions occur every *tabsize* ' +- 'characters\n' +- ' (default is 8, giving tab positions at columns 0, 8, 16 ' +- 'and so on).\n' +- ' To expand the string, the current column is set to zero ' +- 'and the\n' +- ' string is examined character by character. If the ' +- 'character is a\n' +- ' tab ("\\t"), one or more space characters are inserted ' +- 'in the result\n' +- ' until the current column is equal to the next tab ' +- 'position. (The\n' +- ' tab character itself is not copied.) If the character ' +- 'is a newline\n' +- ' ("\\n") or return ("\\r"), it is copied and the current ' +- 'column is\n' +- ' reset to zero. Any other character is copied unchanged ' +- 'and the\n' +- ' current column is incremented by one regardless of how ' +- 'the\n' +- ' character is represented when printed.\n' +- '\n' +- " >>> '01\\t012\\t0123\\t01234'.expandtabs()\n" +- " '01 012 0123 01234'\n" +- " >>> '01\\t012\\t0123\\t01234'.expandtabs(4)\n" +- " '01 012 0123 01234'\n" +- '\n' +- 'str.find(sub[, start[, end]])\n' +- '\n' +- ' Return the lowest index in the string where substring ' +- '*sub* is\n' +- ' found within the slice "s[start:end]". Optional ' +- 'arguments *start*\n' +- ' and *end* are interpreted as in slice notation. Return ' +- '"-1" if\n' +- ' *sub* is not found.\n' +- '\n' +- ' Note:\n' +- '\n' +- ' The "find()" method should be used only if you need ' +- 'to know the\n' +- ' position of *sub*. To check if *sub* is a substring ' +- 'or not, use\n' +- ' the "in" operator:\n' +- '\n' +- " >>> 'Py' in 'Python'\n" +- ' True\n' +- '\n' +- 'str.format(*args, **kwargs)\n' +- '\n' +- ' Perform a string formatting operation. The string on ' +- 'which this\n' +- ' method is called can contain literal text or ' +- 'replacement fields\n' +- ' delimited by braces "{}". Each replacement field ' +- 'contains either\n' +- ' the numeric index of a positional argument, or the name ' +- 'of a\n' +- ' keyword argument. Returns a copy of the string where ' +- 'each\n' +- ' replacement field is replaced with the string value of ' +- 'the\n' +- ' corresponding argument.\n' +- '\n' +- ' >>> "The sum of 1 + 2 is {0}".format(1+2)\n' +- " 'The sum of 1 + 2 is 3'\n" +- '\n' +- ' See Format String Syntax for a description of the ' +- 'various\n' +- ' formatting options that can be specified in format ' +- 'strings.\n' +- '\n' +- ' Note:\n' +- '\n' +- ' When formatting a number ("int", "float", "complex",\n' +- ' "decimal.Decimal" and subclasses) with the "n" type ' +- '(ex:\n' +- ' "\'{:n}\'.format(1234)"), the function temporarily ' +- 'sets the\n' +- ' "LC_CTYPE" locale to the "LC_NUMERIC" locale to ' +- 'decode\n' +- ' "decimal_point" and "thousands_sep" fields of ' +- '"localeconv()" if\n' +- ' they are non-ASCII or longer than 1 byte, and the ' +- '"LC_NUMERIC"\n' +- ' locale is different than the "LC_CTYPE" locale. This ' +- 'temporary\n' +- ' change affects other threads.\n' +- '\n' +- ' Changed in version 3.7: When formatting a number with ' +- 'the "n" type,\n' +- ' the function sets temporarily the "LC_CTYPE" locale to ' +- 'the\n' +- ' "LC_NUMERIC" locale in some cases.\n' +- '\n' +- 'str.format_map(mapping, /)\n' +- '\n' +- ' Similar to "str.format(**mapping)", except that ' +- '"mapping" is used\n' +- ' directly and not copied to a "dict". This is useful if ' +- 'for example\n' +- ' "mapping" is a dict subclass:\n' +- '\n' +- ' >>> class Default(dict):\n' +- ' ... def __missing__(self, key):\n' +- ' ... return key\n' +- ' ...\n' +- " >>> '{name} was born in " +- "{country}'.format_map(Default(name='Guido'))\n" +- " 'Guido was born in country'\n" +- '\n' +- ' Added in version 3.2.\n' +- '\n' +- 'str.index(sub[, start[, end]])\n' +- '\n' +- ' Like "find()", but raise "ValueError" when the ' +- 'substring is not\n' +- ' found.\n' +- '\n' +- 'str.isalnum()\n' +- '\n' +- ' Return "True" if all characters in the string are ' +- 'alphanumeric and\n' +- ' there is at least one character, "False" otherwise. A ' +- 'character\n' +- ' "c" is alphanumeric if one of the following returns ' +- '"True":\n' +- ' "c.isalpha()", "c.isdecimal()", "c.isdigit()", or ' +- '"c.isnumeric()".\n' +- '\n' +- 'str.isalpha()\n' +- '\n' +- ' Return "True" if all characters in the string are ' +- 'alphabetic and\n' +- ' there is at least one character, "False" otherwise. ' +- 'Alphabetic\n' +- ' characters are those characters defined in the Unicode ' +- 'character\n' +- ' database as “Letterâ€, i.e., those with general category ' +- 'property\n' +- ' being one of “Lmâ€, “Ltâ€, “Luâ€, “Llâ€, or “Loâ€. Note ' +- 'that this is\n' +- ' different from the Alphabetic property defined in the ' +- 'section 4.10\n' +- ' ‘Letters, Alphabetic, and Ideographic’ of the Unicode ' +- 'Standard.\n' +- '\n' +- 'str.isascii()\n' +- '\n' +- ' Return "True" if the string is empty or all characters ' +- 'in the\n' +- ' string are ASCII, "False" otherwise. ASCII characters ' +- 'have code\n' +- ' points in the range U+0000-U+007F.\n' +- '\n' +- ' Added in version 3.7.\n' +- '\n' +- 'str.isdecimal()\n' +- '\n' +- ' Return "True" if all characters in the string are ' +- 'decimal\n' +- ' characters and there is at least one character, "False" ' +- 'otherwise.\n' +- ' Decimal characters are those that can be used to form ' +- 'numbers in\n' +- ' base 10, e.g. U+0660, ARABIC-INDIC DIGIT ZERO. ' +- 'Formally a decimal\n' +- ' character is a character in the Unicode General ' +- 'Category “Ndâ€.\n' +- '\n' +- 'str.isdigit()\n' +- '\n' +- ' Return "True" if all characters in the string are ' +- 'digits and there\n' +- ' is at least one character, "False" otherwise. Digits ' +- 'include\n' +- ' decimal characters and digits that need special ' +- 'handling, such as\n' +- ' the compatibility superscript digits. This covers ' +- 'digits which\n' +- ' cannot be used to form numbers in base 10, like the ' +- 'Kharosthi\n' +- ' numbers. Formally, a digit is a character that has the ' +- 'property\n' +- ' value Numeric_Type=Digit or Numeric_Type=Decimal.\n' +- '\n' +- 'str.isidentifier()\n' +- '\n' +- ' Return "True" if the string is a valid identifier ' +- 'according to the\n' +- ' language definition, section Identifiers and keywords.\n' +- '\n' +- ' "keyword.iskeyword()" can be used to test whether ' +- 'string "s" is a\n' +- ' reserved identifier, such as "def" and "class".\n' +- '\n' +- ' Example:\n' +- '\n' +- ' >>> from keyword import iskeyword\n' +- '\n' +- " >>> 'hello'.isidentifier(), iskeyword('hello')\n" +- ' (True, False)\n' +- " >>> 'def'.isidentifier(), iskeyword('def')\n" +- ' (True, True)\n' +- '\n' +- 'str.islower()\n' +- '\n' +- ' Return "True" if all cased characters [4] in the string ' +- 'are\n' +- ' lowercase and there is at least one cased character, ' +- '"False"\n' +- ' otherwise.\n' +- '\n' +- 'str.isnumeric()\n' +- '\n' +- ' Return "True" if all characters in the string are ' +- 'numeric\n' +- ' characters, and there is at least one character, ' +- '"False" otherwise.\n' +- ' Numeric characters include digit characters, and all ' +- 'characters\n' +- ' that have the Unicode numeric value property, e.g. ' +- 'U+2155, VULGAR\n' +- ' FRACTION ONE FIFTH. Formally, numeric characters are ' +- 'those with\n' +- ' the property value Numeric_Type=Digit, ' +- 'Numeric_Type=Decimal or\n' +- ' Numeric_Type=Numeric.\n' +- '\n' +- 'str.isprintable()\n' +- '\n' +- ' Return "True" if all characters in the string are ' +- 'printable or the\n' +- ' string is empty, "False" otherwise. Nonprintable ' +- 'characters are\n' +- ' those characters defined in the Unicode character ' +- 'database as\n' +- ' “Other†or “Separatorâ€, excepting the ASCII space ' +- '(0x20) which is\n' +- ' considered printable. (Note that printable characters ' +- 'in this\n' +- ' context are those which should not be escaped when ' +- '"repr()" is\n' +- ' invoked on a string. It has no bearing on the handling ' +- 'of strings\n' +- ' written to "sys.stdout" or "sys.stderr".)\n' +- '\n' +- 'str.isspace()\n' +- '\n' +- ' Return "True" if there are only whitespace characters ' +- 'in the string\n' +- ' and there is at least one character, "False" ' +- 'otherwise.\n' +- '\n' +- ' A character is *whitespace* if in the Unicode character ' +- 'database\n' +- ' (see "unicodedata"), either its general category is ' +- '"Zs"\n' +- ' (“Separator, spaceâ€), or its bidirectional class is one ' +- 'of "WS",\n' +- ' "B", or "S".\n' +- '\n' +- 'str.istitle()\n' +- '\n' +- ' Return "True" if the string is a titlecased string and ' +- 'there is at\n' +- ' least one character, for example uppercase characters ' +- 'may only\n' +- ' follow uncased characters and lowercase characters only ' +- 'cased ones.\n' +- ' Return "False" otherwise.\n' +- '\n' +- 'str.isupper()\n' +- '\n' +- ' Return "True" if all cased characters [4] in the string ' +- 'are\n' +- ' uppercase and there is at least one cased character, ' +- '"False"\n' +- ' otherwise.\n' +- '\n' +- " >>> 'BANANA'.isupper()\n" +- ' True\n' +- " >>> 'banana'.isupper()\n" +- ' False\n' +- " >>> 'baNana'.isupper()\n" +- ' False\n' +- " >>> ' '.isupper()\n" +- ' False\n' +- '\n' +- 'str.join(iterable)\n' +- '\n' +- ' Return a string which is the concatenation of the ' +- 'strings in\n' +- ' *iterable*. A "TypeError" will be raised if there are ' +- 'any non-\n' +- ' string values in *iterable*, including "bytes" ' +- 'objects. The\n' +- ' separator between elements is the string providing this ' +- 'method.\n' +- '\n' +- 'str.ljust(width[, fillchar])\n' +- '\n' +- ' Return the string left justified in a string of length ' +- '*width*.\n' +- ' Padding is done using the specified *fillchar* (default ' +- 'is an ASCII\n' +- ' space). The original string is returned if *width* is ' +- 'less than or\n' +- ' equal to "len(s)".\n' +- '\n' +- 'str.lower()\n' +- '\n' +- ' Return a copy of the string with all the cased ' +- 'characters [4]\n' +- ' converted to lowercase.\n' +- '\n' +- ' The lowercasing algorithm used is described in section ' +- '3.13\n' +- ' ‘Default Case Folding’ of the Unicode Standard.\n' +- '\n' +- 'str.lstrip([chars])\n' +- '\n' +- ' Return a copy of the string with leading characters ' +- 'removed. The\n' +- ' *chars* argument is a string specifying the set of ' +- 'characters to be\n' +- ' removed. If omitted or "None", the *chars* argument ' +- 'defaults to\n' +- ' removing whitespace. The *chars* argument is not a ' +- 'prefix; rather,\n' +- ' all combinations of its values are stripped:\n' +- '\n' +- " >>> ' spacious '.lstrip()\n" +- " 'spacious '\n" +- " >>> 'www.example.com'.lstrip('cmowz.')\n" +- " 'example.com'\n" +- '\n' +- ' See "str.removeprefix()" for a method that will remove ' +- 'a single\n' +- ' prefix string rather than all of a set of characters. ' +- 'For example:\n' +- '\n' +- " >>> 'Arthur: three!'.lstrip('Arthur: ')\n" +- " 'ee!'\n" +- " >>> 'Arthur: three!'.removeprefix('Arthur: ')\n" +- " 'three!'\n" +- '\n' +- 'static str.maketrans(x[, y[, z]])\n' +- '\n' +- ' This static method returns a translation table usable ' +- 'for\n' +- ' "str.translate()".\n' +- '\n' +- ' If there is only one argument, it must be a dictionary ' +- 'mapping\n' +- ' Unicode ordinals (integers) or characters (strings of ' +- 'length 1) to\n' +- ' Unicode ordinals, strings (of arbitrary lengths) or ' +- '"None".\n' +- ' Character keys will then be converted to ordinals.\n' +- '\n' +- ' If there are two arguments, they must be strings of ' +- 'equal length,\n' +- ' and in the resulting dictionary, each character in x ' +- 'will be mapped\n' +- ' to the character at the same position in y. If there ' +- 'is a third\n' +- ' argument, it must be a string, whose characters will be ' +- 'mapped to\n' +- ' "None" in the result.\n' +- '\n' +- 'str.partition(sep)\n' +- '\n' +- ' Split the string at the first occurrence of *sep*, and ' +- 'return a\n' +- ' 3-tuple containing the part before the separator, the ' +- 'separator\n' +- ' itself, and the part after the separator. If the ' +- 'separator is not\n' +- ' found, return a 3-tuple containing the string itself, ' +- 'followed by\n' +- ' two empty strings.\n' +- '\n' +- 'str.removeprefix(prefix, /)\n' +- '\n' +- ' If the string starts with the *prefix* string, return\n' +- ' "string[len(prefix):]". Otherwise, return a copy of the ' +- 'original\n' +- ' string:\n' +- '\n' +- " >>> 'TestHook'.removeprefix('Test')\n" +- " 'Hook'\n" +- " >>> 'BaseTestCase'.removeprefix('Test')\n" +- " 'BaseTestCase'\n" +- '\n' +- ' Added in version 3.9.\n' +- '\n' +- 'str.removesuffix(suffix, /)\n' +- '\n' +- ' If the string ends with the *suffix* string and that ' +- '*suffix* is\n' +- ' not empty, return "string[:-len(suffix)]". Otherwise, ' +- 'return a copy\n' +- ' of the original string:\n' +- '\n' +- " >>> 'MiscTests'.removesuffix('Tests')\n" +- " 'Misc'\n" +- " >>> 'TmpDirMixin'.removesuffix('Tests')\n" +- " 'TmpDirMixin'\n" +- '\n' +- ' Added in version 3.9.\n' +- '\n' +- 'str.replace(old, new, count=-1)\n' +- '\n' +- ' Return a copy of the string with all occurrences of ' +- 'substring *old*\n' +- ' replaced by *new*. If *count* is given, only the first ' +- '*count*\n' +- ' occurrences are replaced. If *count* is not specified ' +- 'or "-1", then\n' +- ' all occurrences are replaced.\n' +- '\n' +- ' Changed in version 3.13: *count* is now supported as a ' +- 'keyword\n' +- ' argument.\n' +- '\n' +- 'str.rfind(sub[, start[, end]])\n' +- '\n' +- ' Return the highest index in the string where substring ' +- '*sub* is\n' +- ' found, such that *sub* is contained within ' +- '"s[start:end]".\n' +- ' Optional arguments *start* and *end* are interpreted as ' +- 'in slice\n' +- ' notation. Return "-1" on failure.\n' +- '\n' +- 'str.rindex(sub[, start[, end]])\n' +- '\n' +- ' Like "rfind()" but raises "ValueError" when the ' +- 'substring *sub* is\n' +- ' not found.\n' +- '\n' +- 'str.rjust(width[, fillchar])\n' +- '\n' +- ' Return the string right justified in a string of length ' +- '*width*.\n' +- ' Padding is done using the specified *fillchar* (default ' +- 'is an ASCII\n' +- ' space). The original string is returned if *width* is ' +- 'less than or\n' +- ' equal to "len(s)".\n' +- '\n' +- 'str.rpartition(sep)\n' +- '\n' +- ' Split the string at the last occurrence of *sep*, and ' +- 'return a\n' +- ' 3-tuple containing the part before the separator, the ' +- 'separator\n' +- ' itself, and the part after the separator. If the ' +- 'separator is not\n' +- ' found, return a 3-tuple containing two empty strings, ' +- 'followed by\n' +- ' the string itself.\n' +- '\n' +- 'str.rsplit(sep=None, maxsplit=-1)\n' +- '\n' +- ' Return a list of the words in the string, using *sep* ' +- 'as the\n' +- ' delimiter string. If *maxsplit* is given, at most ' +- '*maxsplit* splits\n' +- ' are done, the *rightmost* ones. If *sep* is not ' +- 'specified or\n' +- ' "None", any whitespace string is a separator. Except ' +- 'for splitting\n' +- ' from the right, "rsplit()" behaves like "split()" which ' +- 'is\n' +- ' described in detail below.\n' +- '\n' +- 'str.rstrip([chars])\n' +- '\n' +- ' Return a copy of the string with trailing characters ' +- 'removed. The\n' +- ' *chars* argument is a string specifying the set of ' +- 'characters to be\n' +- ' removed. If omitted or "None", the *chars* argument ' +- 'defaults to\n' +- ' removing whitespace. The *chars* argument is not a ' +- 'suffix; rather,\n' +- ' all combinations of its values are stripped:\n' +- '\n' +- " >>> ' spacious '.rstrip()\n" +- " ' spacious'\n" +- " >>> 'mississippi'.rstrip('ipz')\n" +- " 'mississ'\n" +- '\n' +- ' See "str.removesuffix()" for a method that will remove ' +- 'a single\n' +- ' suffix string rather than all of a set of characters. ' +- 'For example:\n' +- '\n' +- " >>> 'Monty Python'.rstrip(' Python')\n" +- " 'M'\n" +- " >>> 'Monty Python'.removesuffix(' Python')\n" +- " 'Monty'\n" +- '\n' +- 'str.split(sep=None, maxsplit=-1)\n' +- '\n' +- ' Return a list of the words in the string, using *sep* ' +- 'as the\n' +- ' delimiter string. If *maxsplit* is given, at most ' +- '*maxsplit*\n' +- ' splits are done (thus, the list will have at most ' +- '"maxsplit+1"\n' +- ' elements). If *maxsplit* is not specified or "-1", ' +- 'then there is\n' +- ' no limit on the number of splits (all possible splits ' +- 'are made).\n' +- '\n' +- ' If *sep* is given, consecutive delimiters are not ' +- 'grouped together\n' +- ' and are deemed to delimit empty strings (for example,\n' +- ' "\'1,,2\'.split(\',\')" returns "[\'1\', \'\', ' +- '\'2\']"). The *sep* argument\n' +- ' may consist of multiple characters as a single ' +- 'delimiter (to split\n' +- ' with multiple delimiters, use "re.split()"). Splitting ' +- 'an empty\n' +- ' string with a specified separator returns "[\'\']".\n' +- '\n' +- ' For example:\n' +- '\n' +- " >>> '1,2,3'.split(',')\n" +- " ['1', '2', '3']\n" +- " >>> '1,2,3'.split(',', maxsplit=1)\n" +- " ['1', '2,3']\n" +- " >>> '1,2,,3,'.split(',')\n" +- " ['1', '2', '', '3', '']\n" +- " >>> '1<>2<>3<4'.split('<>')\n" +- " ['1', '2', '3<4']\n" +- '\n' +- ' If *sep* is not specified or is "None", a different ' +- 'splitting\n' +- ' algorithm is applied: runs of consecutive whitespace ' +- 'are regarded\n' +- ' as a single separator, and the result will contain no ' +- 'empty strings\n' +- ' at the start or end if the string has leading or ' +- 'trailing\n' +- ' whitespace. Consequently, splitting an empty string or ' +- 'a string\n' +- ' consisting of just whitespace with a "None" separator ' +- 'returns "[]".\n' +- '\n' +- ' For example:\n' +- '\n' +- " >>> '1 2 3'.split()\n" +- " ['1', '2', '3']\n" +- " >>> '1 2 3'.split(maxsplit=1)\n" +- " ['1', '2 3']\n" +- " >>> ' 1 2 3 '.split()\n" +- " ['1', '2', '3']\n" +- '\n' +- 'str.splitlines(keepends=False)\n' +- '\n' +- ' Return a list of the lines in the string, breaking at ' +- 'line\n' +- ' boundaries. Line breaks are not included in the ' +- 'resulting list\n' +- ' unless *keepends* is given and true.\n' +- '\n' +- ' This method splits on the following line boundaries. ' +- 'In\n' +- ' particular, the boundaries are a superset of *universal ' +- 'newlines*.\n' +- '\n' +- ' ' +- '+-------------------------+-------------------------------+\n' +- ' | Representation | ' +- 'Description |\n' +- ' ' +- '|=========================|===============================|\n' +- ' | "\\n" | Line ' +- 'Feed |\n' +- ' ' +- '+-------------------------+-------------------------------+\n' +- ' | "\\r" | Carriage ' +- 'Return |\n' +- ' ' +- '+-------------------------+-------------------------------+\n' +- ' | "\\r\\n" | Carriage Return + Line ' +- 'Feed |\n' +- ' ' +- '+-------------------------+-------------------------------+\n' +- ' | "\\v" or "\\x0b" | Line ' +- 'Tabulation |\n' +- ' ' +- '+-------------------------+-------------------------------+\n' +- ' | "\\f" or "\\x0c" | Form ' +- 'Feed |\n' +- ' ' +- '+-------------------------+-------------------------------+\n' +- ' | "\\x1c" | File ' +- 'Separator |\n' +- ' ' +- '+-------------------------+-------------------------------+\n' +- ' | "\\x1d" | Group ' +- 'Separator |\n' +- ' ' +- '+-------------------------+-------------------------------+\n' +- ' | "\\x1e" | Record ' +- 'Separator |\n' +- ' ' +- '+-------------------------+-------------------------------+\n' +- ' | "\\x85" | Next Line (C1 Control ' +- 'Code) |\n' +- ' ' +- '+-------------------------+-------------------------------+\n' +- ' | "\\u2028" | Line ' +- 'Separator |\n' +- ' ' +- '+-------------------------+-------------------------------+\n' +- ' | "\\u2029" | Paragraph ' +- 'Separator |\n' +- ' ' +- '+-------------------------+-------------------------------+\n' +- '\n' +- ' Changed in version 3.2: "\\v" and "\\f" added to list ' +- 'of line\n' +- ' boundaries.\n' +- '\n' +- ' For example:\n' +- '\n' +- " >>> 'ab c\\n\\nde fg\\rkl\\r\\n'.splitlines()\n" +- " ['ab c', '', 'de fg', 'kl']\n" +- " >>> 'ab c\\n\\nde " +- "fg\\rkl\\r\\n'.splitlines(keepends=True)\n" +- " ['ab c\\n', '\\n', 'de fg\\r', 'kl\\r\\n']\n" +- '\n' +- ' Unlike "split()" when a delimiter string *sep* is ' +- 'given, this\n' +- ' method returns an empty list for the empty string, and ' +- 'a terminal\n' +- ' line break does not result in an extra line:\n' +- '\n' +- ' >>> "".splitlines()\n' +- ' []\n' +- ' >>> "One line\\n".splitlines()\n' +- " ['One line']\n" +- '\n' +- ' For comparison, "split(\'\\n\')" gives:\n' +- '\n' +- " >>> ''.split('\\n')\n" +- " ['']\n" +- " >>> 'Two lines\\n'.split('\\n')\n" +- " ['Two lines', '']\n" +- '\n' +- 'str.startswith(prefix[, start[, end]])\n' +- '\n' +- ' Return "True" if string starts with the *prefix*, ' +- 'otherwise return\n' +- ' "False". *prefix* can also be a tuple of prefixes to ' +- 'look for.\n' +- ' With optional *start*, test string beginning at that ' +- 'position.\n' +- ' With optional *end*, stop comparing string at that ' +- 'position.\n' +- '\n' +- 'str.strip([chars])\n' +- '\n' +- ' Return a copy of the string with the leading and ' +- 'trailing\n' +- ' characters removed. The *chars* argument is a string ' +- 'specifying the\n' +- ' set of characters to be removed. If omitted or "None", ' +- 'the *chars*\n' +- ' argument defaults to removing whitespace. The *chars* ' +- 'argument is\n' +- ' not a prefix or suffix; rather, all combinations of its ' +- 'values are\n' +- ' stripped:\n' +- '\n' +- " >>> ' spacious '.strip()\n" +- " 'spacious'\n" +- " >>> 'www.example.com'.strip('cmowz.')\n" +- " 'example'\n" +- '\n' +- ' The outermost leading and trailing *chars* argument ' +- 'values are\n' +- ' stripped from the string. Characters are removed from ' +- 'the leading\n' +- ' end until reaching a string character that is not ' +- 'contained in the\n' +- ' set of characters in *chars*. A similar action takes ' +- 'place on the\n' +- ' trailing end. For example:\n' +- '\n' +- " >>> comment_string = '#....... Section 3.2.1 Issue " +- "#32 .......'\n" +- " >>> comment_string.strip('.#! ')\n" +- " 'Section 3.2.1 Issue #32'\n" +- '\n' +- 'str.swapcase()\n' +- '\n' +- ' Return a copy of the string with uppercase characters ' +- 'converted to\n' +- ' lowercase and vice versa. Note that it is not ' +- 'necessarily true that\n' +- ' "s.swapcase().swapcase() == s".\n' +- '\n' +- 'str.title()\n' +- '\n' +- ' Return a titlecased version of the string where words ' +- 'start with an\n' +- ' uppercase character and the remaining characters are ' +- 'lowercase.\n' +- '\n' +- ' For example:\n' +- '\n' +- " >>> 'Hello world'.title()\n" +- " 'Hello World'\n" +- '\n' +- ' The algorithm uses a simple language-independent ' +- 'definition of a\n' +- ' word as groups of consecutive letters. The definition ' +- 'works in\n' +- ' many contexts but it means that apostrophes in ' +- 'contractions and\n' +- ' possessives form word boundaries, which may not be the ' +- 'desired\n' +- ' result:\n' +- '\n' +- ' >>> "they\'re bill\'s friends from the UK".title()\n' +- ' "They\'Re Bill\'S Friends From The Uk"\n' +- '\n' +- ' The "string.capwords()" function does not have this ' +- 'problem, as it\n' +- ' splits words on spaces only.\n' +- '\n' +- ' Alternatively, a workaround for apostrophes can be ' +- 'constructed\n' +- ' using regular expressions:\n' +- '\n' +- ' >>> import re\n' +- ' >>> def titlecase(s):\n' +- ' ... return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n' +- ' ... lambda mo: ' +- 'mo.group(0).capitalize(),\n' +- ' ... s)\n' +- ' ...\n' +- ' >>> titlecase("they\'re bill\'s friends.")\n' +- ' "They\'re Bill\'s Friends."\n' +- '\n' +- 'str.translate(table)\n' +- '\n' +- ' Return a copy of the string in which each character has ' +- 'been mapped\n' +- ' through the given translation table. The table must be ' +- 'an object\n' +- ' that implements indexing via "__getitem__()", typically ' +- 'a *mapping*\n' +- ' or *sequence*. When indexed by a Unicode ordinal (an ' +- 'integer), the\n' +- ' table object can do any of the following: return a ' +- 'Unicode ordinal\n' +- ' or a string, to map the character to one or more other ' +- 'characters;\n' +- ' return "None", to delete the character from the return ' +- 'string; or\n' +- ' raise a "LookupError" exception, to map the character ' +- 'to itself.\n' +- '\n' +- ' You can use "str.maketrans()" to create a translation ' +- 'map from\n' +- ' character-to-character mappings in different formats.\n' +- '\n' +- ' See also the "codecs" module for a more flexible ' +- 'approach to custom\n' +- ' character mappings.\n' +- '\n' +- 'str.upper()\n' +- '\n' +- ' Return a copy of the string with all the cased ' +- 'characters [4]\n' +- ' converted to uppercase. Note that ' +- '"s.upper().isupper()" might be\n' +- ' "False" if "s" contains uncased characters or if the ' +- 'Unicode\n' +- ' category of the resulting character(s) is not “Lu†' +- '(Letter,\n' +- ' uppercase), but e.g. “Lt†(Letter, titlecase).\n' +- '\n' +- ' The uppercasing algorithm used is described in section ' +- '3.13\n' +- ' ‘Default Case Folding’ of the Unicode Standard.\n' +- '\n' +- 'str.zfill(width)\n' +- '\n' +- ' Return a copy of the string left filled with ASCII ' +- '"\'0\'" digits to\n' +- ' make a string of length *width*. A leading sign prefix\n' +- ' ("\'+\'"/"\'-\'") is handled by inserting the padding ' +- '*after* the sign\n' +- ' character rather than before. The original string is ' +- 'returned if\n' +- ' *width* is less than or equal to "len(s)".\n' +- '\n' +- ' For example:\n' +- '\n' +- ' >>> "42".zfill(5)\n' +- " '00042'\n" +- ' >>> "-42".zfill(5)\n' +- " '-0042'\n", +- 'strings': 'String and Bytes literals\n' +- '*************************\n' +- '\n' +- 'String literals are described by the following lexical ' +- 'definitions:\n' +- '\n' +- ' stringliteral ::= [stringprefix](shortstring | longstring)\n' +- ' stringprefix ::= "r" | "u" | "R" | "U" | "f" | "F"\n' +- ' | "fr" | "Fr" | "fR" | "FR" | "rf" | "rF" | ' +- '"Rf" | "RF"\n' +- ' shortstring ::= "\'" shortstringitem* "\'" | \'"\' ' +- 'shortstringitem* \'"\'\n' +- ' longstring ::= "\'\'\'" longstringitem* "\'\'\'" | ' +- '\'"""\' longstringitem* \'"""\'\n' +- ' shortstringitem ::= shortstringchar | stringescapeseq\n' +- ' longstringitem ::= longstringchar | stringescapeseq\n' +- ' shortstringchar ::= \n' +- ' longstringchar ::= \n' +- ' stringescapeseq ::= "\\" \n' +- '\n' +- ' bytesliteral ::= bytesprefix(shortbytes | longbytes)\n' +- ' bytesprefix ::= "b" | "B" | "br" | "Br" | "bR" | "BR" | ' +- '"rb" | "rB" | "Rb" | "RB"\n' +- ' shortbytes ::= "\'" shortbytesitem* "\'" | \'"\' ' +- 'shortbytesitem* \'"\'\n' +- ' longbytes ::= "\'\'\'" longbytesitem* "\'\'\'" | \'"""\' ' +- 'longbytesitem* \'"""\'\n' +- ' shortbytesitem ::= shortbyteschar | bytesescapeseq\n' +- ' longbytesitem ::= longbyteschar | bytesescapeseq\n' +- ' shortbyteschar ::= \n' +- ' longbyteschar ::= \n' +- ' bytesescapeseq ::= "\\" \n' +- '\n' +- 'One syntactic restriction not indicated by these productions is ' +- 'that\n' +- 'whitespace is not allowed between the "stringprefix" or ' +- '"bytesprefix"\n' +- 'and the rest of the literal. The source character set is defined ' +- 'by\n' +- 'the encoding declaration; it is UTF-8 if no encoding declaration ' +- 'is\n' +- 'given in the source file; see section Encoding declarations.\n' +- '\n' +- 'In plain English: Both types of literals can be enclosed in ' +- 'matching\n' +- 'single quotes ("\'") or double quotes ("""). They can also be ' +- 'enclosed\n' +- 'in matching groups of three single or double quotes (these are\n' +- 'generally referred to as *triple-quoted strings*). The backslash ' +- '("\\")\n' +- 'character is used to give special meaning to otherwise ordinary\n' +- 'characters like "n", which means ‘newline’ when escaped ("\\n"). ' +- 'It can\n' +- 'also be used to escape characters that otherwise have a special\n' +- 'meaning, such as newline, backslash itself, or the quote ' +- 'character.\n' +- 'See escape sequences below for examples.\n' +- '\n' +- 'Bytes literals are always prefixed with "\'b\'" or "\'B\'"; they ' +- 'produce\n' +- 'an instance of the "bytes" type instead of the "str" type. They ' +- 'may\n' +- 'only contain ASCII characters; bytes with a numeric value of 128 ' +- 'or\n' +- 'greater must be expressed with escapes.\n' +- '\n' +- 'Both string and bytes literals may optionally be prefixed with a\n' +- 'letter "\'r\'" or "\'R\'"; such constructs are called *raw ' +- 'string\n' +- 'literals* and *raw bytes literals* respectively and treat ' +- 'backslashes\n' +- 'as literal characters. As a result, in raw string literals, ' +- '"\'\\U\'"\n' +- 'and "\'\\u\'" escapes are not treated specially.\n' +- '\n' +- 'Added in version 3.3: The "\'rb\'" prefix of raw bytes literals ' +- 'has been\n' +- 'added as a synonym of "\'br\'".Support for the unicode legacy ' +- 'literal\n' +- '("u\'value\'") was reintroduced to simplify the maintenance of ' +- 'dual\n' +- 'Python 2.x and 3.x codebases. See **PEP 414** for more ' +- 'information.\n' +- '\n' +- 'A string literal with "\'f\'" or "\'F\'" in its prefix is a ' +- '*formatted\n' +- 'string literal*; see f-strings. The "\'f\'" may be combined with ' +- '"\'r\'",\n' +- 'but not with "\'b\'" or "\'u\'", therefore raw formatted strings ' +- 'are\n' +- 'possible, but formatted bytes literals are not.\n' +- '\n' +- 'In triple-quoted literals, unescaped newlines and quotes are ' +- 'allowed\n' +- '(and are retained), except that three unescaped quotes in a row\n' +- 'terminate the literal. (A “quote†is the character used to open ' +- 'the\n' +- 'literal, i.e. either "\'" or """.)\n' +- '\n' +- '\n' +- 'Escape sequences\n' +- '================\n' +- '\n' +- 'Unless an "\'r\'" or "\'R\'" prefix is present, escape sequences ' +- 'in string\n' +- 'and bytes literals are interpreted according to rules similar to ' +- 'those\n' +- 'used by Standard C. The recognized escape sequences are:\n' +- '\n' +- '+---------------------------+-----------------------------------+---------+\n' +- '| Escape Sequence | Meaning | ' +- 'Notes |\n' +- '|===========================|===================================|=========|\n' +- '| "\\" | Backslash and newline ignored ' +- '| (1) |\n' +- '+---------------------------+-----------------------------------+---------+\n' +- '| "\\\\" | Backslash ' +- '("\\") | |\n' +- '+---------------------------+-----------------------------------+---------+\n' +- '| "\\\'" | Single quote ' +- '("\'") | |\n' +- '+---------------------------+-----------------------------------+---------+\n' +- '| "\\"" | Double quote (""") ' +- '| |\n' +- '+---------------------------+-----------------------------------+---------+\n' +- '| "\\a" | ASCII Bell (BEL) ' +- '| |\n' +- '+---------------------------+-----------------------------------+---------+\n' +- '| "\\b" | ASCII Backspace (BS) ' +- '| |\n' +- '+---------------------------+-----------------------------------+---------+\n' +- '| "\\f" | ASCII Formfeed (FF) ' +- '| |\n' +- '+---------------------------+-----------------------------------+---------+\n' +- '| "\\n" | ASCII Linefeed (LF) ' +- '| |\n' +- '+---------------------------+-----------------------------------+---------+\n' +- '| "\\r" | ASCII Carriage Return (CR) ' +- '| |\n' +- '+---------------------------+-----------------------------------+---------+\n' +- '| "\\t" | ASCII Horizontal Tab (TAB) ' +- '| |\n' +- '+---------------------------+-----------------------------------+---------+\n' +- '| "\\v" | ASCII Vertical Tab (VT) ' +- '| |\n' +- '+---------------------------+-----------------------------------+---------+\n' +- '| "\\*ooo*" | Character with octal value *ooo* ' +- '| (2,4) |\n' +- '+---------------------------+-----------------------------------+---------+\n' +- '| "\\x*hh*" | Character with hex value *hh* ' +- '| (3,4) |\n' +- '+---------------------------+-----------------------------------+---------+\n' +- '\n' +- 'Escape sequences only recognized in string literals are:\n' +- '\n' +- '+---------------------------+-----------------------------------+---------+\n' +- '| Escape Sequence | Meaning | ' +- 'Notes |\n' +- '|===========================|===================================|=========|\n' +- '| "\\N{*name*}" | Character named *name* in the ' +- '| (5) |\n' +- '| | Unicode database ' +- '| |\n' +- '+---------------------------+-----------------------------------+---------+\n' +- '| "\\u*xxxx*" | Character with 16-bit hex value ' +- '| (6) |\n' +- '| | *xxxx* ' +- '| |\n' +- '+---------------------------+-----------------------------------+---------+\n' +- '| "\\U*xxxxxxxx*" | Character with 32-bit hex value ' +- '| (7) |\n' +- '| | *xxxxxxxx* ' +- '| |\n' +- '+---------------------------+-----------------------------------+---------+\n' +- '\n' +- 'Notes:\n' +- '\n' +- '1. A backslash can be added at the end of a line to ignore the\n' +- ' newline:\n' +- '\n' +- " >>> 'This string will not include \\\n" +- " ... backslashes or newline characters.'\n" +- " 'This string will not include backslashes or newline " +- "characters.'\n" +- '\n' +- ' The same result can be achieved using triple-quoted strings, ' +- 'or\n' +- ' parentheses and string literal concatenation.\n' +- '\n' +- '2. As in Standard C, up to three octal digits are accepted.\n' +- '\n' +- ' Changed in version 3.11: Octal escapes with value larger than\n' +- ' "0o377" produce a "DeprecationWarning".\n' +- '\n' +- ' Changed in version 3.12: Octal escapes with value larger than\n' +- ' "0o377" produce a "SyntaxWarning". In a future Python version ' +- 'they\n' +- ' will be eventually a "SyntaxError".\n' +- '\n' +- '3. Unlike in Standard C, exactly two hex digits are required.\n' +- '\n' +- '4. In a bytes literal, hexadecimal and octal escapes denote the ' +- 'byte\n' +- ' with the given value. In a string literal, these escapes ' +- 'denote a\n' +- ' Unicode character with the given value.\n' +- '\n' +- '5. Changed in version 3.3: Support for name aliases [1] has been\n' +- ' added.\n' +- '\n' +- '6. Exactly four hex digits are required.\n' +- '\n' +- '7. Any Unicode character can be encoded this way. Exactly eight ' +- 'hex\n' +- ' digits are required.\n' +- '\n' +- 'Unlike Standard C, all unrecognized escape sequences are left in ' +- 'the\n' +- 'string unchanged, i.e., *the backslash is left in the result*. ' +- '(This\n' +- 'behavior is useful when debugging: if an escape sequence is ' +- 'mistyped,\n' +- 'the resulting output is more easily recognized as broken.) It is ' +- 'also\n' +- 'important to note that the escape sequences only recognized in ' +- 'string\n' +- 'literals fall into the category of unrecognized escapes for ' +- 'bytes\n' +- 'literals.\n' +- '\n' +- 'Changed in version 3.6: Unrecognized escape sequences produce a\n' +- '"DeprecationWarning".\n' +- '\n' +- 'Changed in version 3.12: Unrecognized escape sequences produce a\n' +- '"SyntaxWarning". In a future Python version they will be ' +- 'eventually a\n' +- '"SyntaxError".\n' +- '\n' +- 'Even in a raw literal, quotes can be escaped with a backslash, ' +- 'but the\n' +- 'backslash remains in the result; for example, "r"\\""" is a ' +- 'valid\n' +- 'string literal consisting of two characters: a backslash and a ' +- 'double\n' +- 'quote; "r"\\"" is not a valid string literal (even a raw string ' +- 'cannot\n' +- 'end in an odd number of backslashes). Specifically, *a raw ' +- 'literal\n' +- 'cannot end in a single backslash* (since the backslash would ' +- 'escape\n' +- 'the following quote character). Note also that a single ' +- 'backslash\n' +- 'followed by a newline is interpreted as those two characters as ' +- 'part\n' +- 'of the literal, *not* as a line continuation.\n', +- 'subscriptions': 'Subscriptions\n' +- '*************\n' +- '\n' +- 'The subscription of an instance of a container class will ' +- 'generally\n' +- 'select an element from the container. The subscription of a ' +- '*generic\n' +- 'class* will generally return a GenericAlias object.\n' +- '\n' +- ' subscription ::= primary "[" flexible_expression_list ' +- '"]"\n' +- '\n' +- 'When an object is subscripted, the interpreter will ' +- 'evaluate the\n' +- 'primary and the expression list.\n' +- '\n' +- 'The primary must evaluate to an object that supports ' +- 'subscription. An\n' +- 'object may support subscription through defining one or ' +- 'both of\n' +- '"__getitem__()" and "__class_getitem__()". When the primary ' +- 'is\n' +- 'subscripted, the evaluated result of the expression list ' +- 'will be\n' +- 'passed to one of these methods. For more details on when\n' +- '"__class_getitem__" is called instead of "__getitem__", ' +- 'see\n' +- '__class_getitem__ versus __getitem__.\n' +- '\n' +- 'If the expression list contains at least one comma, or if ' +- 'any of the\n' +- 'expressions are starred, the expression list will evaluate ' +- 'to a\n' +- '"tuple" containing the items of the expression list. ' +- 'Otherwise, the\n' +- 'expression list will evaluate to the value of the list’s ' +- 'sole member.\n' +- '\n' +- 'Changed in version 3.11: Expressions in an expression list ' +- 'may be\n' +- 'starred. See **PEP 646**.\n' +- '\n' +- 'For built-in objects, there are two types of objects that ' +- 'support\n' +- 'subscription via "__getitem__()":\n' +- '\n' +- '1. Mappings. If the primary is a *mapping*, the expression ' +- 'list must\n' +- ' evaluate to an object whose value is one of the keys of ' +- 'the\n' +- ' mapping, and the subscription selects the value in the ' +- 'mapping that\n' +- ' corresponds to that key. An example of a builtin mapping ' +- 'class is\n' +- ' the "dict" class.\n' +- '\n' +- '2. Sequences. If the primary is a *sequence*, the ' +- 'expression list must\n' +- ' evaluate to an "int" or a "slice" (as discussed in the ' +- 'following\n' +- ' section). Examples of builtin sequence classes include ' +- 'the "str",\n' +- ' "list" and "tuple" classes.\n' +- '\n' +- 'The formal syntax makes no special provision for negative ' +- 'indices in\n' +- '*sequences*. However, built-in sequences all provide a ' +- '"__getitem__()"\n' +- 'method that interprets negative indices by adding the ' +- 'length of the\n' +- 'sequence to the index so that, for example, "x[-1]" selects ' +- 'the last\n' +- 'item of "x". The resulting value must be a nonnegative ' +- 'integer less\n' +- 'than the number of items in the sequence, and the ' +- 'subscription selects\n' +- 'the item whose index is that value (counting from zero). ' +- 'Since the\n' +- 'support for negative indices and slicing occurs in the ' +- 'object’s\n' +- '"__getitem__()" method, subclasses overriding this method ' +- 'will need to\n' +- 'explicitly add that support.\n' +- '\n' +- 'A "string" is a special kind of sequence whose items are ' +- '*characters*.\n' +- 'A character is not a separate data type but a string of ' +- 'exactly one\n' +- 'character.\n', +- 'truth': 'Truth Value Testing\n' +- '*******************\n' +- '\n' +- 'Any object can be tested for truth value, for use in an "if" or\n' +- '"while" condition or as operand of the Boolean operations below.\n' +- '\n' +- 'By default, an object is considered true unless its class defines\n' +- 'either a "__bool__()" method that returns "False" or a "__len__()"\n' +- 'method that returns zero, when called with the object. [1] Here ' +- 'are\n' +- 'most of the built-in objects considered false:\n' +- '\n' +- '* constants defined to be false: "None" and "False"\n' +- '\n' +- '* zero of any numeric type: "0", "0.0", "0j", "Decimal(0)",\n' +- ' "Fraction(0, 1)"\n' +- '\n' +- '* empty sequences and collections: "\'\'", "()", "[]", "{}", ' +- '"set()",\n' +- ' "range(0)"\n' +- '\n' +- 'Operations and built-in functions that have a Boolean result ' +- 'always\n' +- 'return "0" or "False" for false and "1" or "True" for true, unless\n' +- 'otherwise stated. (Important exception: the Boolean operations ' +- '"or"\n' +- 'and "and" always return one of their operands.)\n', +- 'try': 'The "try" statement\n' +- '*******************\n' +- '\n' +- 'The "try" statement specifies exception handlers and/or cleanup code\n' +- 'for a group of statements:\n' +- '\n' +- ' try_stmt ::= try1_stmt | try2_stmt | try3_stmt\n' +- ' try1_stmt ::= "try" ":" suite\n' +- ' ("except" [expression ["as" identifier]] ":" ' +- 'suite)+\n' +- ' ["else" ":" suite]\n' +- ' ["finally" ":" suite]\n' +- ' try2_stmt ::= "try" ":" suite\n' +- ' ("except" "*" expression ["as" identifier] ":" ' +- 'suite)+\n' +- ' ["else" ":" suite]\n' +- ' ["finally" ":" suite]\n' +- ' try3_stmt ::= "try" ":" suite\n' +- ' "finally" ":" suite\n' +- '\n' +- 'Additional information on exceptions can be found in section\n' +- 'Exceptions, and information on using the "raise" statement to ' +- 'generate\n' +- 'exceptions may be found in section The raise statement.\n' +- '\n' +- '\n' +- '"except" clause\n' +- '===============\n' +- '\n' +- 'The "except" clause(s) specify one or more exception handlers. When ' +- 'no\n' +- 'exception occurs in the "try" clause, no exception handler is\n' +- 'executed. When an exception occurs in the "try" suite, a search for ' +- 'an\n' +- 'exception handler is started. This search inspects the "except"\n' +- 'clauses in turn until one is found that matches the exception. An\n' +- 'expression-less "except" clause, if present, must be last; it ' +- 'matches\n' +- 'any exception.\n' +- '\n' +- 'For an "except" clause with an expression, the expression must\n' +- 'evaluate to an exception type or a tuple of exception types. The\n' +- 'raised exception matches an "except" clause whose expression ' +- 'evaluates\n' +- 'to the class or a *non-virtual base class* of the exception object, ' +- 'or\n' +- 'to a tuple that contains such a class.\n' +- '\n' +- 'If no "except" clause matches the exception, the search for an\n' +- 'exception handler continues in the surrounding code and on the\n' +- 'invocation stack. [1]\n' +- '\n' +- 'If the evaluation of an expression in the header of an "except" ' +- 'clause\n' +- 'raises an exception, the original search for a handler is canceled ' +- 'and\n' +- 'a search starts for the new exception in the surrounding code and on\n' +- 'the call stack (it is treated as if the entire "try" statement ' +- 'raised\n' +- 'the exception).\n' +- '\n' +- 'When a matching "except" clause is found, the exception is assigned ' +- 'to\n' +- 'the target specified after the "as" keyword in that "except" clause,\n' +- 'if present, and the "except" clause’s suite is executed. All ' +- '"except"\n' +- 'clauses must have an executable block. When the end of this block is\n' +- 'reached, execution continues normally after the entire "try"\n' +- 'statement. (This means that if two nested handlers exist for the ' +- 'same\n' +- 'exception, and the exception occurs in the "try" clause of the inner\n' +- 'handler, the outer handler will not handle the exception.)\n' +- '\n' +- 'When an exception has been assigned using "as target", it is cleared\n' +- 'at the end of the "except" clause. This is as if\n' +- '\n' +- ' except E as N:\n' +- ' foo\n' +- '\n' +- 'was translated to\n' +- '\n' +- ' except E as N:\n' +- ' try:\n' +- ' foo\n' +- ' finally:\n' +- ' del N\n' +- '\n' +- 'This means the exception must be assigned to a different name to be\n' +- 'able to refer to it after the "except" clause. Exceptions are ' +- 'cleared\n' +- 'because with the traceback attached to them, they form a reference\n' +- 'cycle with the stack frame, keeping all locals in that frame alive\n' +- 'until the next garbage collection occurs.\n' +- '\n' +- 'Before an "except" clause’s suite is executed, the exception is ' +- 'stored\n' +- 'in the "sys" module, where it can be accessed from within the body ' +- 'of\n' +- 'the "except" clause by calling "sys.exception()". When leaving an\n' +- 'exception handler, the exception stored in the "sys" module is reset\n' +- 'to its previous value:\n' +- '\n' +- ' >>> print(sys.exception())\n' +- ' None\n' +- ' >>> try:\n' +- ' ... raise TypeError\n' +- ' ... except:\n' +- ' ... print(repr(sys.exception()))\n' +- ' ... try:\n' +- ' ... raise ValueError\n' +- ' ... except:\n' +- ' ... print(repr(sys.exception()))\n' +- ' ... print(repr(sys.exception()))\n' +- ' ...\n' +- ' TypeError()\n' +- ' ValueError()\n' +- ' TypeError()\n' +- ' >>> print(sys.exception())\n' +- ' None\n' +- '\n' +- '\n' +- '"except*" clause\n' +- '================\n' +- '\n' +- 'The "except*" clause(s) are used for handling "ExceptionGroup"s. The\n' +- 'exception type for matching is interpreted as in the case of ' +- '"except",\n' +- 'but in the case of exception groups we can have partial matches when\n' +- 'the type matches some of the exceptions in the group. This means ' +- 'that\n' +- 'multiple "except*" clauses can execute, each handling part of the\n' +- 'exception group. Each clause executes at most once and handles an\n' +- 'exception group of all matching exceptions. Each exception in the\n' +- 'group is handled by at most one "except*" clause, the first that\n' +- 'matches it.\n' +- '\n' +- ' >>> try:\n' +- ' ... raise ExceptionGroup("eg",\n' +- ' ... [ValueError(1), TypeError(2), OSError(3), ' +- 'OSError(4)])\n' +- ' ... except* TypeError as e:\n' +- " ... print(f'caught {type(e)} with nested {e.exceptions}')\n" +- ' ... except* OSError as e:\n' +- " ... print(f'caught {type(e)} with nested {e.exceptions}')\n" +- ' ...\n' +- " caught with nested (TypeError(2),)\n" +- " caught with nested (OSError(3), " +- 'OSError(4))\n' +- ' + Exception Group Traceback (most recent call last):\n' +- ' | File "", line 2, in \n' +- ' | ExceptionGroup: eg\n' +- ' +-+---------------- 1 ----------------\n' +- ' | ValueError: 1\n' +- ' +------------------------------------\n' +- '\n' +- 'Any remaining exceptions that were not handled by any "except*" ' +- 'clause\n' +- 'are re-raised at the end, along with all exceptions that were raised\n' +- 'from within the "except*" clauses. If this list contains more than ' +- 'one\n' +- 'exception to reraise, they are combined into an exception group.\n' +- '\n' +- 'If the raised exception is not an exception group and its type ' +- 'matches\n' +- 'one of the "except*" clauses, it is caught and wrapped by an ' +- 'exception\n' +- 'group with an empty message string.\n' +- '\n' +- ' >>> try:\n' +- ' ... raise BlockingIOError\n' +- ' ... except* BlockingIOError as e:\n' +- ' ... print(repr(e))\n' +- ' ...\n' +- " ExceptionGroup('', (BlockingIOError()))\n" +- '\n' +- 'An "except*" clause must have a matching expression; it cannot be\n' +- '"except*:". Furthermore, this expression cannot contain exception\n' +- 'group types, because that would have ambiguous semantics.\n' +- '\n' +- 'It is not possible to mix "except" and "except*" in the same "try".\n' +- '"break", "continue" and "return" cannot appear in an "except*" ' +- 'clause.\n' +- '\n' +- '\n' +- '"else" clause\n' +- '=============\n' +- '\n' +- 'The optional "else" clause is executed if the control flow leaves ' +- 'the\n' +- '"try" suite, no exception was raised, and no "return", "continue", ' +- 'or\n' +- '"break" statement was executed. Exceptions in the "else" clause are\n' +- 'not handled by the preceding "except" clauses.\n' +- '\n' +- '\n' +- '"finally" clause\n' +- '================\n' +- '\n' +- 'If "finally" is present, it specifies a ‘cleanup’ handler. The ' +- '"try"\n' +- 'clause is executed, including any "except" and "else" clauses. If ' +- 'an\n' +- 'exception occurs in any of the clauses and is not handled, the\n' +- 'exception is temporarily saved. The "finally" clause is executed. ' +- 'If\n' +- 'there is a saved exception it is re-raised at the end of the ' +- '"finally"\n' +- 'clause. If the "finally" clause raises another exception, the saved\n' +- 'exception is set as the context of the new exception. If the ' +- '"finally"\n' +- 'clause executes a "return", "break" or "continue" statement, the ' +- 'saved\n' +- 'exception is discarded:\n' +- '\n' +- ' >>> def f():\n' +- ' ... try:\n' +- ' ... 1/0\n' +- ' ... finally:\n' +- ' ... return 42\n' +- ' ...\n' +- ' >>> f()\n' +- ' 42\n' +- '\n' +- 'The exception information is not available to the program during\n' +- 'execution of the "finally" clause.\n' +- '\n' +- 'When a "return", "break" or "continue" statement is executed in the\n' +- '"try" suite of a "try"…"finally" statement, the "finally" clause is\n' +- 'also executed ‘on the way out.’\n' +- '\n' +- 'The return value of a function is determined by the last "return"\n' +- 'statement executed. Since the "finally" clause always executes, a\n' +- '"return" statement executed in the "finally" clause will always be ' +- 'the\n' +- 'last one executed:\n' +- '\n' +- ' >>> def foo():\n' +- ' ... try:\n' +- " ... return 'try'\n" +- ' ... finally:\n' +- " ... return 'finally'\n" +- ' ...\n' +- ' >>> foo()\n' +- " 'finally'\n" +- '\n' +- 'Changed in version 3.8: Prior to Python 3.8, a "continue" statement\n' +- 'was illegal in the "finally" clause due to a problem with the\n' +- 'implementation.\n', +- 'types': 'The standard type hierarchy\n' +- '***************************\n' +- '\n' +- 'Below is a list of the types that are built into Python. ' +- 'Extension\n' +- 'modules (written in C, Java, or other languages, depending on the\n' +- 'implementation) can define additional types. Future versions of\n' +- 'Python may add types to the type hierarchy (e.g., rational ' +- 'numbers,\n' +- 'efficiently stored arrays of integers, etc.), although such ' +- 'additions\n' +- 'will often be provided via the standard library instead.\n' +- '\n' +- 'Some of the type descriptions below contain a paragraph listing\n' +- '‘special attributes.’ These are attributes that provide access to ' +- 'the\n' +- 'implementation and are not intended for general use. Their ' +- 'definition\n' +- 'may change in the future.\n' +- '\n' +- '\n' +- 'None\n' +- '====\n' +- '\n' +- 'This type has a single value. There is a single object with this\n' +- 'value. This object is accessed through the built-in name "None". It ' +- 'is\n' +- 'used to signify the absence of a value in many situations, e.g., it ' +- 'is\n' +- 'returned from functions that don’t explicitly return anything. Its\n' +- 'truth value is false.\n' +- '\n' +- '\n' +- 'NotImplemented\n' +- '==============\n' +- '\n' +- 'This type has a single value. There is a single object with this\n' +- 'value. This object is accessed through the built-in name\n' +- '"NotImplemented". Numeric methods and rich comparison methods ' +- 'should\n' +- 'return this value if they do not implement the operation for the\n' +- 'operands provided. (The interpreter will then try the reflected\n' +- 'operation, or some other fallback, depending on the operator.) It\n' +- 'should not be evaluated in a boolean context.\n' +- '\n' +- 'See Implementing the arithmetic operations for more details.\n' +- '\n' +- 'Changed in version 3.9: Evaluating "NotImplemented" in a boolean\n' +- 'context was deprecated.\n' +- '\n' +- 'Changed in version 3.14: Evaluating "NotImplemented" in a boolean\n' +- 'context now raises a "TypeError". It previously evaluated to ' +- '"True"\n' +- 'and emitted a "DeprecationWarning" since Python 3.9.\n' +- '\n' +- '\n' +- 'Ellipsis\n' +- '========\n' +- '\n' +- 'This type has a single value. There is a single object with this\n' +- 'value. This object is accessed through the literal "..." or the ' +- 'built-\n' +- 'in name "Ellipsis". Its truth value is true.\n' +- '\n' +- '\n' +- '"numbers.Number"\n' +- '================\n' +- '\n' +- 'These are created by numeric literals and returned as results by\n' +- 'arithmetic operators and arithmetic built-in functions. Numeric\n' +- 'objects are immutable; once created their value never changes. ' +- 'Python\n' +- 'numbers are of course strongly related to mathematical numbers, ' +- 'but\n' +- 'subject to the limitations of numerical representation in ' +- 'computers.\n' +- '\n' +- 'The string representations of the numeric classes, computed by\n' +- '"__repr__()" and "__str__()", have the following properties:\n' +- '\n' +- '* They are valid numeric literals which, when passed to their ' +- 'class\n' +- ' constructor, produce an object having the value of the original\n' +- ' numeric.\n' +- '\n' +- '* The representation is in base 10, when possible.\n' +- '\n' +- '* Leading zeros, possibly excepting a single zero before a decimal\n' +- ' point, are not shown.\n' +- '\n' +- '* Trailing zeros, possibly excepting a single zero after a decimal\n' +- ' point, are not shown.\n' +- '\n' +- '* A sign is shown only when the number is negative.\n' +- '\n' +- 'Python distinguishes between integers, floating-point numbers, and\n' +- 'complex numbers:\n' +- '\n' +- '\n' +- '"numbers.Integral"\n' +- '------------------\n' +- '\n' +- 'These represent elements from the mathematical set of integers\n' +- '(positive and negative).\n' +- '\n' +- 'Note:\n' +- '\n' +- ' The rules for integer representation are intended to give the ' +- 'most\n' +- ' meaningful interpretation of shift and mask operations involving\n' +- ' negative integers.\n' +- '\n' +- 'There are two types of integers:\n' +- '\n' +- 'Integers ("int")\n' +- ' These represent numbers in an unlimited range, subject to ' +- 'available\n' +- ' (virtual) memory only. For the purpose of shift and mask\n' +- ' operations, a binary representation is assumed, and negative\n' +- ' numbers are represented in a variant of 2’s complement which ' +- 'gives\n' +- ' the illusion of an infinite string of sign bits extending to ' +- 'the\n' +- ' left.\n' +- '\n' +- 'Booleans ("bool")\n' +- ' These represent the truth values False and True. The two ' +- 'objects\n' +- ' representing the values "False" and "True" are the only Boolean\n' +- ' objects. The Boolean type is a subtype of the integer type, and\n' +- ' Boolean values behave like the values 0 and 1, respectively, in\n' +- ' almost all contexts, the exception being that when converted to ' +- 'a\n' +- ' string, the strings ""False"" or ""True"" are returned,\n' +- ' respectively.\n' +- '\n' +- '\n' +- '"numbers.Real" ("float")\n' +- '------------------------\n' +- '\n' +- 'These represent machine-level double precision floating-point ' +- 'numbers.\n' +- 'You are at the mercy of the underlying machine architecture (and C ' +- 'or\n' +- 'Java implementation) for the accepted range and handling of ' +- 'overflow.\n' +- 'Python does not support single-precision floating-point numbers; ' +- 'the\n' +- 'savings in processor and memory usage that are usually the reason ' +- 'for\n' +- 'using these are dwarfed by the overhead of using objects in Python, ' +- 'so\n' +- 'there is no reason to complicate the language with two kinds of\n' +- 'floating-point numbers.\n' +- '\n' +- '\n' +- '"numbers.Complex" ("complex")\n' +- '-----------------------------\n' +- '\n' +- 'These represent complex numbers as a pair of machine-level double\n' +- 'precision floating-point numbers. The same caveats apply as for\n' +- 'floating-point numbers. The real and imaginary parts of a complex\n' +- 'number "z" can be retrieved through the read-only attributes ' +- '"z.real"\n' +- 'and "z.imag".\n' +- '\n' +- '\n' +- 'Sequences\n' +- '=========\n' +- '\n' +- 'These represent finite ordered sets indexed by non-negative ' +- 'numbers.\n' +- 'The built-in function "len()" returns the number of items of a\n' +- 'sequence. When the length of a sequence is *n*, the index set ' +- 'contains\n' +- 'the numbers 0, 1, …, *n*-1. Item *i* of sequence *a* is selected ' +- 'by\n' +- '"a[i]". Some sequences, including built-in sequences, interpret\n' +- 'negative subscripts by adding the sequence length. For example,\n' +- '"a[-2]" equals "a[n-2]", the second to last item of sequence a ' +- 'with\n' +- 'length "n".\n' +- '\n' +- 'Sequences also support slicing: "a[i:j]" selects all items with ' +- 'index\n' +- '*k* such that *i* "<=" *k* "<" *j*. When used as an expression, a\n' +- 'slice is a sequence of the same type. The comment above about ' +- 'negative\n' +- 'indexes also applies to negative slice positions.\n' +- '\n' +- 'Some sequences also support “extended slicing†with a third “stepâ€\n' +- 'parameter: "a[i:j:k]" selects all items of *a* with index *x* where ' +- '"x\n' +- '= i + n*k", *n* ">=" "0" and *i* "<=" *x* "<" *j*.\n' +- '\n' +- 'Sequences are distinguished according to their mutability:\n' +- '\n' +- '\n' +- 'Immutable sequences\n' +- '-------------------\n' +- '\n' +- 'An object of an immutable sequence type cannot change once it is\n' +- 'created. (If the object contains references to other objects, ' +- 'these\n' +- 'other objects may be mutable and may be changed; however, the\n' +- 'collection of objects directly referenced by an immutable object\n' +- 'cannot change.)\n' +- '\n' +- 'The following types are immutable sequences:\n' +- '\n' +- 'Strings\n' +- ' A string is a sequence of values that represent Unicode code\n' +- ' points. All the code points in the range "U+0000 - U+10FFFF" can ' +- 'be\n' +- ' represented in a string. Python doesn’t have a char type; ' +- 'instead,\n' +- ' every code point in the string is represented as a string ' +- 'object\n' +- ' with length "1". The built-in function "ord()" converts a code\n' +- ' point from its string form to an integer in the range "0 - ' +- '10FFFF";\n' +- ' "chr()" converts an integer in the range "0 - 10FFFF" to the\n' +- ' corresponding length "1" string object. "str.encode()" can be ' +- 'used\n' +- ' to convert a "str" to "bytes" using the given text encoding, ' +- 'and\n' +- ' "bytes.decode()" can be used to achieve the opposite.\n' +- '\n' +- 'Tuples\n' +- ' The items of a tuple are arbitrary Python objects. Tuples of two ' +- 'or\n' +- ' more items are formed by comma-separated lists of expressions. ' +- 'A\n' +- ' tuple of one item (a ‘singleton’) can be formed by affixing a ' +- 'comma\n' +- ' to an expression (an expression by itself does not create a ' +- 'tuple,\n' +- ' since parentheses must be usable for grouping of expressions). ' +- 'An\n' +- ' empty tuple can be formed by an empty pair of parentheses.\n' +- '\n' +- 'Bytes\n' +- ' A bytes object is an immutable array. The items are 8-bit ' +- 'bytes,\n' +- ' represented by integers in the range 0 <= x < 256. Bytes ' +- 'literals\n' +- ' (like "b\'abc\'") and the built-in "bytes()" constructor can be ' +- 'used\n' +- ' to create bytes objects. Also, bytes objects can be decoded to\n' +- ' strings via the "decode()" method.\n' +- '\n' +- '\n' +- 'Mutable sequences\n' +- '-----------------\n' +- '\n' +- 'Mutable sequences can be changed after they are created. The\n' +- 'subscription and slicing notations can be used as the target of\n' +- 'assignment and "del" (delete) statements.\n' +- '\n' +- 'Note:\n' +- '\n' +- ' The "collections" and "array" module provide additional examples ' +- 'of\n' +- ' mutable sequence types.\n' +- '\n' +- 'There are currently two intrinsic mutable sequence types:\n' +- '\n' +- 'Lists\n' +- ' The items of a list are arbitrary Python objects. Lists are ' +- 'formed\n' +- ' by placing a comma-separated list of expressions in square\n' +- ' brackets. (Note that there are no special cases needed to form\n' +- ' lists of length 0 or 1.)\n' +- '\n' +- 'Byte Arrays\n' +- ' A bytearray object is a mutable array. They are created by the\n' +- ' built-in "bytearray()" constructor. Aside from being mutable ' +- '(and\n' +- ' hence unhashable), byte arrays otherwise provide the same ' +- 'interface\n' +- ' and functionality as immutable "bytes" objects.\n' +- '\n' +- '\n' +- 'Set types\n' +- '=========\n' +- '\n' +- 'These represent unordered, finite sets of unique, immutable ' +- 'objects.\n' +- 'As such, they cannot be indexed by any subscript. However, they can ' +- 'be\n' +- 'iterated over, and the built-in function "len()" returns the number ' +- 'of\n' +- 'items in a set. Common uses for sets are fast membership testing,\n' +- 'removing duplicates from a sequence, and computing mathematical\n' +- 'operations such as intersection, union, difference, and symmetric\n' +- 'difference.\n' +- '\n' +- 'For set elements, the same immutability rules apply as for ' +- 'dictionary\n' +- 'keys. Note that numeric types obey the normal rules for numeric\n' +- 'comparison: if two numbers compare equal (e.g., "1" and "1.0"), ' +- 'only\n' +- 'one of them can be contained in a set.\n' +- '\n' +- 'There are currently two intrinsic set types:\n' +- '\n' +- 'Sets\n' +- ' These represent a mutable set. They are created by the built-in\n' +- ' "set()" constructor and can be modified afterwards by several\n' +- ' methods, such as "add()".\n' +- '\n' +- 'Frozen sets\n' +- ' These represent an immutable set. They are created by the ' +- 'built-in\n' +- ' "frozenset()" constructor. As a frozenset is immutable and\n' +- ' *hashable*, it can be used again as an element of another set, ' +- 'or\n' +- ' as a dictionary key.\n' +- '\n' +- '\n' +- 'Mappings\n' +- '========\n' +- '\n' +- 'These represent finite sets of objects indexed by arbitrary index\n' +- 'sets. The subscript notation "a[k]" selects the item indexed by ' +- '"k"\n' +- 'from the mapping "a"; this can be used in expressions and as the\n' +- 'target of assignments or "del" statements. The built-in function\n' +- '"len()" returns the number of items in a mapping.\n' +- '\n' +- 'There is currently a single intrinsic mapping type:\n' +- '\n' +- '\n' +- 'Dictionaries\n' +- '------------\n' +- '\n' +- 'These represent finite sets of objects indexed by nearly arbitrary\n' +- 'values. The only types of values not acceptable as keys are ' +- 'values\n' +- 'containing lists or dictionaries or other mutable types that are\n' +- 'compared by value rather than by object identity, the reason being\n' +- 'that the efficient implementation of dictionaries requires a key’s\n' +- 'hash value to remain constant. Numeric types used for keys obey ' +- 'the\n' +- 'normal rules for numeric comparison: if two numbers compare equal\n' +- '(e.g., "1" and "1.0") then they can be used interchangeably to ' +- 'index\n' +- 'the same dictionary entry.\n' +- '\n' +- 'Dictionaries preserve insertion order, meaning that keys will be\n' +- 'produced in the same order they were added sequentially over the\n' +- 'dictionary. Replacing an existing key does not change the order,\n' +- 'however removing a key and re-inserting it will add it to the end\n' +- 'instead of keeping its old place.\n' +- '\n' +- 'Dictionaries are mutable; they can be created by the "{}" notation\n' +- '(see section Dictionary displays).\n' +- '\n' +- 'The extension modules "dbm.ndbm" and "dbm.gnu" provide additional\n' +- 'examples of mapping types, as does the "collections" module.\n' +- '\n' +- 'Changed in version 3.7: Dictionaries did not preserve insertion ' +- 'order\n' +- 'in versions of Python before 3.6. In CPython 3.6, insertion order ' +- 'was\n' +- 'preserved, but it was considered an implementation detail at that ' +- 'time\n' +- 'rather than a language guarantee.\n' +- '\n' +- '\n' +- 'Callable types\n' +- '==============\n' +- '\n' +- 'These are the types to which the function call operation (see ' +- 'section\n' +- 'Calls) can be applied:\n' +- '\n' +- '\n' +- 'User-defined functions\n' +- '----------------------\n' +- '\n' +- 'A user-defined function object is created by a function definition\n' +- '(see section Function definitions). It should be called with an\n' +- 'argument list containing the same number of items as the ' +- 'function’s\n' +- 'formal parameter list.\n' +- '\n' +- '\n' +- 'Special read-only attributes\n' +- '~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n' +- '\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| Attribute | ' +- 'Meaning |\n' +- '|====================================================|====================================================|\n' +- '| function.__globals__ | A reference ' +- 'to the "dictionary" that holds the |\n' +- '| | function’s ' +- 'global variables – the global namespace |\n' +- '| | of the ' +- 'module in which the function was defined. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| function.__closure__ | "None" or a ' +- '"tuple" of cells that contain bindings |\n' +- '| | for the ' +- 'names specified in the "co_freevars" |\n' +- '| | attribute of ' +- 'the function’s "code object". A cell |\n' +- '| | object has ' +- 'the attribute "cell_contents". This can |\n' +- '| | be used to ' +- 'get the value of the cell, as well as |\n' +- '| | set the ' +- 'value. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '\n' +- '\n' +- 'Special writable attributes\n' +- '~~~~~~~~~~~~~~~~~~~~~~~~~~~\n' +- '\n' +- 'Most of these attributes check the type of the assigned value:\n' +- '\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| Attribute | ' +- 'Meaning |\n' +- '|====================================================|====================================================|\n' +- '| function.__doc__ | The ' +- 'function’s documentation string, or "None" if |\n' +- '| | ' +- 'unavailable. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| function.__name__ | The ' +- 'function’s name. See also: "__name__ |\n' +- '| | ' +- 'attributes". |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| function.__qualname__ | The ' +- 'function’s *qualified name*. See also: |\n' +- '| | ' +- '"__qualname__ attributes". Added in version 3.3. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| function.__module__ | The name of ' +- 'the module the function was defined |\n' +- '| | in, or ' +- '"None" if unavailable. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| function.__defaults__ | A "tuple" ' +- 'containing default *parameter* values |\n' +- '| | for those ' +- 'parameters that have defaults, or "None" |\n' +- '| | if no ' +- 'parameters have a default value. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| function.__code__ | The code ' +- 'object representing the compiled function |\n' +- '| | ' +- 'body. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| function.__dict__ | The ' +- 'namespace supporting arbitrary function |\n' +- '| | attributes. ' +- 'See also: "__dict__ attributes". |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| function.__annotations__ | A ' +- '"dictionary" containing annotations of |\n' +- '| | ' +- '*parameters*. The keys of the dictionary are the |\n' +- '| | parameter ' +- 'names, and "\'return\'" for the return |\n' +- '| | annotation, ' +- 'if provided. See also: |\n' +- '| | ' +- '"object.__annotations__". Changed in version |\n' +- '| | 3.14: ' +- 'Annotations are now lazily evaluated. See |\n' +- '| | **PEP ' +- '649**. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| function.__annotate__ | The ' +- '*annotate function* for this function, or |\n' +- '| | "None" if ' +- 'the function has no annotations. See |\n' +- '| | ' +- '"object.__annotate__". Added in version 3.14. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| function.__kwdefaults__ | A ' +- '"dictionary" containing defaults for keyword- |\n' +- '| | only ' +- '*parameters*. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| function.__type_params__ | A "tuple" ' +- 'containing the type parameters of a |\n' +- '| | generic ' +- 'function. Added in version 3.12. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '\n' +- 'Function objects also support getting and setting arbitrary\n' +- 'attributes, which can be used, for example, to attach metadata to\n' +- 'functions. Regular attribute dot-notation is used to get and set ' +- 'such\n' +- 'attributes.\n' +- '\n' +- '**CPython implementation detail:** CPython’s current ' +- 'implementation\n' +- 'only supports function attributes on user-defined functions. ' +- 'Function\n' +- 'attributes on built-in functions may be supported in the future.\n' +- '\n' +- 'Additional information about a function’s definition can be ' +- 'retrieved\n' +- 'from its code object (accessible via the "__code__" attribute).\n' +- '\n' +- '\n' +- 'Instance methods\n' +- '----------------\n' +- '\n' +- 'An instance method object combines a class, a class instance and ' +- 'any\n' +- 'callable object (normally a user-defined function).\n' +- '\n' +- 'Special read-only attributes:\n' +- '\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| method.__self__ | Refers to ' +- 'the class instance object to which the |\n' +- '| | method is ' +- 'bound |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| method.__func__ | Refers to ' +- 'the original function object |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| method.__doc__ | The method’s ' +- 'documentation (same as |\n' +- '| | ' +- '"method.__func__.__doc__"). A "string" if the |\n' +- '| | original ' +- 'function had a docstring, else "None". |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| method.__name__ | The name of ' +- 'the method (same as |\n' +- '| | ' +- '"method.__func__.__name__") |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| method.__module__ | The name of ' +- 'the module the method was defined in, |\n' +- '| | or "None" if ' +- 'unavailable. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '\n' +- 'Methods also support accessing (but not setting) the arbitrary\n' +- 'function attributes on the underlying function object.\n' +- '\n' +- 'User-defined method objects may be created when getting an ' +- 'attribute\n' +- 'of a class (perhaps via an instance of that class), if that ' +- 'attribute\n' +- 'is a user-defined function object or a "classmethod" object.\n' +- '\n' +- 'When an instance method object is created by retrieving a ' +- 'user-defined\n' +- 'function object from a class via one of its instances, its ' +- '"__self__"\n' +- 'attribute is the instance, and the method object is said to be\n' +- '*bound*. The new method’s "__func__" attribute is the original\n' +- 'function object.\n' +- '\n' +- 'When an instance method object is created by retrieving a\n' +- '"classmethod" object from a class or instance, its "__self__"\n' +- 'attribute is the class itself, and its "__func__" attribute is the\n' +- 'function object underlying the class method.\n' +- '\n' +- 'When an instance method object is called, the underlying function\n' +- '("__func__") is called, inserting the class instance ("__self__") ' +- 'in\n' +- 'front of the argument list. For instance, when "C" is a class ' +- 'which\n' +- 'contains a definition for a function "f()", and "x" is an instance ' +- 'of\n' +- '"C", calling "x.f(1)" is equivalent to calling "C.f(x, 1)".\n' +- '\n' +- 'When an instance method object is derived from a "classmethod" ' +- 'object,\n' +- 'the “class instance†stored in "__self__" will actually be the ' +- 'class\n' +- 'itself, so that calling either "x.f(1)" or "C.f(1)" is equivalent ' +- 'to\n' +- 'calling "f(C,1)" where "f" is the underlying function.\n' +- '\n' +- 'It is important to note that user-defined functions which are\n' +- 'attributes of a class instance are not converted to bound methods;\n' +- 'this *only* happens when the function is an attribute of the ' +- 'class.\n' +- '\n' +- '\n' +- 'Generator functions\n' +- '-------------------\n' +- '\n' +- 'A function or method which uses the "yield" statement (see section ' +- 'The\n' +- 'yield statement) is called a *generator function*. Such a ' +- 'function,\n' +- 'when called, always returns an *iterator* object which can be used ' +- 'to\n' +- 'execute the body of the function: calling the iterator’s\n' +- '"iterator.__next__()" method will cause the function to execute ' +- 'until\n' +- 'it provides a value using the "yield" statement. When the ' +- 'function\n' +- 'executes a "return" statement or falls off the end, a ' +- '"StopIteration"\n' +- 'exception is raised and the iterator will have reached the end of ' +- 'the\n' +- 'set of values to be returned.\n' +- '\n' +- '\n' +- 'Coroutine functions\n' +- '-------------------\n' +- '\n' +- 'A function or method which is defined using "async def" is called ' +- 'a\n' +- '*coroutine function*. Such a function, when called, returns a\n' +- '*coroutine* object. It may contain "await" expressions, as well ' +- 'as\n' +- '"async with" and "async for" statements. See also the Coroutine\n' +- 'Objects section.\n' +- '\n' +- '\n' +- 'Asynchronous generator functions\n' +- '--------------------------------\n' +- '\n' +- 'A function or method which is defined using "async def" and which ' +- 'uses\n' +- 'the "yield" statement is called a *asynchronous generator ' +- 'function*.\n' +- 'Such a function, when called, returns an *asynchronous iterator*\n' +- 'object which can be used in an "async for" statement to execute ' +- 'the\n' +- 'body of the function.\n' +- '\n' +- 'Calling the asynchronous iterator’s "aiterator.__anext__" method ' +- 'will\n' +- 'return an *awaitable* which when awaited will execute until it\n' +- 'provides a value using the "yield" expression. When the function\n' +- 'executes an empty "return" statement or falls off the end, a\n' +- '"StopAsyncIteration" exception is raised and the asynchronous ' +- 'iterator\n' +- 'will have reached the end of the set of values to be yielded.\n' +- '\n' +- '\n' +- 'Built-in functions\n' +- '------------------\n' +- '\n' +- 'A built-in function object is a wrapper around a C function. ' +- 'Examples\n' +- 'of built-in functions are "len()" and "math.sin()" ("math" is a\n' +- 'standard built-in module). The number and type of the arguments ' +- 'are\n' +- 'determined by the C function. Special read-only attributes:\n' +- '\n' +- '* "__doc__" is the function’s documentation string, or "None" if\n' +- ' unavailable. See "function.__doc__".\n' +- '\n' +- '* "__name__" is the function’s name. See "function.__name__".\n' +- '\n' +- '* "__self__" is set to "None" (but see the next item).\n' +- '\n' +- '* "__module__" is the name of the module the function was defined ' +- 'in\n' +- ' or "None" if unavailable. See "function.__module__".\n' +- '\n' +- '\n' +- 'Built-in methods\n' +- '----------------\n' +- '\n' +- 'This is really a different disguise of a built-in function, this ' +- 'time\n' +- 'containing an object passed to the C function as an implicit extra\n' +- 'argument. An example of a built-in method is "alist.append()",\n' +- 'assuming *alist* is a list object. In this case, the special ' +- 'read-only\n' +- 'attribute "__self__" is set to the object denoted by *alist*. (The\n' +- 'attribute has the same semantics as it does with "other instance\n' +- 'methods".)\n' +- '\n' +- '\n' +- 'Classes\n' +- '-------\n' +- '\n' +- 'Classes are callable. These objects normally act as factories for ' +- 'new\n' +- 'instances of themselves, but variations are possible for class ' +- 'types\n' +- 'that override "__new__()". The arguments of the call are passed ' +- 'to\n' +- '"__new__()" and, in the typical case, to "__init__()" to ' +- 'initialize\n' +- 'the new instance.\n' +- '\n' +- '\n' +- 'Class Instances\n' +- '---------------\n' +- '\n' +- 'Instances of arbitrary classes can be made callable by defining a\n' +- '"__call__()" method in their class.\n' +- '\n' +- '\n' +- 'Modules\n' +- '=======\n' +- '\n' +- 'Modules are a basic organizational unit of Python code, and are\n' +- 'created by the import system as invoked either by the "import"\n' +- 'statement, or by calling functions such as ' +- '"importlib.import_module()"\n' +- 'and built-in "__import__()". A module object has a namespace\n' +- 'implemented by a "dictionary" object (this is the dictionary\n' +- 'referenced by the "__globals__" attribute of functions defined in ' +- 'the\n' +- 'module). Attribute references are translated to lookups in this\n' +- 'dictionary, e.g., "m.x" is equivalent to "m.__dict__["x"]". A ' +- 'module\n' +- 'object does not contain the code object used to initialize the ' +- 'module\n' +- '(since it isn’t needed once the initialization is done).\n' +- '\n' +- 'Attribute assignment updates the module’s namespace dictionary, ' +- 'e.g.,\n' +- '"m.x = 1" is equivalent to "m.__dict__["x"] = 1".\n' +- '\n' +- '\n' +- 'Import-related attributes on module objects\n' +- '-------------------------------------------\n' +- '\n' +- 'Module objects have the following attributes that relate to the ' +- 'import\n' +- 'system. When a module is created using the machinery associated ' +- 'with\n' +- 'the import system, these attributes are filled in based on the\n' +- 'module’s *spec*, before the *loader* executes and loads the ' +- 'module.\n' +- '\n' +- 'To create a module dynamically rather than using the import ' +- 'system,\n' +- 'it’s recommended to use "importlib.util.module_from_spec()", which\n' +- 'will set the various import-controlled attributes to appropriate\n' +- 'values. It’s also possible to use the "types.ModuleType" ' +- 'constructor\n' +- 'to create modules directly, but this technique is more error-prone, ' +- 'as\n' +- 'most attributes must be manually set on the module object after it ' +- 'has\n' +- 'been created when using this approach.\n' +- '\n' +- 'Caution:\n' +- '\n' +- ' With the exception of "__name__", it is **strongly** recommended\n' +- ' that you rely on "__spec__" and its attributes instead of any of ' +- 'the\n' +- ' other individual attributes listed in this subsection. Note that\n' +- ' updating an attribute on "__spec__" will not update the\n' +- ' corresponding attribute on the module itself:\n' +- '\n' +- ' >>> import typing\n' +- ' >>> typing.__name__, typing.__spec__.name\n' +- " ('typing', 'typing')\n" +- " >>> typing.__spec__.name = 'spelling'\n" +- ' >>> typing.__name__, typing.__spec__.name\n' +- " ('typing', 'spelling')\n" +- " >>> typing.__name__ = 'keyboard_smashing'\n" +- ' >>> typing.__name__, typing.__spec__.name\n' +- " ('keyboard_smashing', 'spelling')\n" +- '\n' +- 'module.__name__\n' +- '\n' +- ' The name used to uniquely identify the module in the import ' +- 'system.\n' +- ' For a directly executed module, this will be set to ' +- '""__main__"".\n' +- '\n' +- ' This attribute must be set to the fully qualified name of the\n' +- ' module. It is expected to match the value of\n' +- ' "module.__spec__.name".\n' +- '\n' +- 'module.__spec__\n' +- '\n' +- ' A record of the module’s import-system-related state.\n' +- '\n' +- ' Set to the "module spec" that was used when importing the ' +- 'module.\n' +- ' See Module specs for more details.\n' +- '\n' +- ' Added in version 3.4.\n' +- '\n' +- 'module.__package__\n' +- '\n' +- ' The *package* a module belongs to.\n' +- '\n' +- ' If the module is top-level (that is, not a part of any specific\n' +- ' package) then the attribute should be set to "\'\'" (the empty\n' +- ' string). Otherwise, it should be set to the name of the ' +- 'module’s\n' +- ' package (which can be equal to "module.__name__" if the module\n' +- ' itself is a package). See **PEP 366** for further details.\n' +- '\n' +- ' This attribute is used instead of "__name__" to calculate ' +- 'explicit\n' +- ' relative imports for main modules. It defaults to "None" for\n' +- ' modules created dynamically using the "types.ModuleType"\n' +- ' constructor; use "importlib.util.module_from_spec()" instead to\n' +- ' ensure the attribute is set to a "str".\n' +- '\n' +- ' It is **strongly** recommended that you use\n' +- ' "module.__spec__.parent" instead of "module.__package__".\n' +- ' "__package__" is now only used as a fallback if ' +- '"__spec__.parent"\n' +- ' is not set, and this fallback path is deprecated.\n' +- '\n' +- ' Changed in version 3.4: This attribute now defaults to "None" ' +- 'for\n' +- ' modules created dynamically using the "types.ModuleType"\n' +- ' constructor. Previously the attribute was optional.\n' +- '\n' +- ' Changed in version 3.6: The value of "__package__" is expected ' +- 'to\n' +- ' be the same as "__spec__.parent". "__package__" is now only used ' +- 'as\n' +- ' a fallback during import resolution if "__spec__.parent" is not\n' +- ' defined.\n' +- '\n' +- ' Changed in version 3.10: "ImportWarning" is raised if an import\n' +- ' resolution falls back to "__package__" instead of\n' +- ' "__spec__.parent".\n' +- '\n' +- ' Changed in version 3.12: Raise "DeprecationWarning" instead of\n' +- ' "ImportWarning" when falling back to "__package__" during ' +- 'import\n' +- ' resolution.\n' +- '\n' +- ' Deprecated since version 3.13, will be removed in version 3.15:\n' +- ' "__package__" will cease to be set or taken into consideration ' +- 'by\n' +- ' the import system or standard library.\n' +- '\n' +- 'module.__loader__\n' +- '\n' +- ' The *loader* object that the import machinery used to load the\n' +- ' module.\n' +- '\n' +- ' This attribute is mostly useful for introspection, but can be ' +- 'used\n' +- ' for additional loader-specific functionality, for example ' +- 'getting\n' +- ' data associated with a loader.\n' +- '\n' +- ' "__loader__" defaults to "None" for modules created dynamically\n' +- ' using the "types.ModuleType" constructor; use\n' +- ' "importlib.util.module_from_spec()" instead to ensure the ' +- 'attribute\n' +- ' is set to a *loader* object.\n' +- '\n' +- ' It is **strongly** recommended that you use\n' +- ' "module.__spec__.loader" instead of "module.__loader__".\n' +- '\n' +- ' Changed in version 3.4: This attribute now defaults to "None" ' +- 'for\n' +- ' modules created dynamically using the "types.ModuleType"\n' +- ' constructor. Previously the attribute was optional.\n' +- '\n' +- ' Deprecated since version 3.12, will be removed in version 3.16:\n' +- ' Setting "__loader__" on a module while failing to set\n' +- ' "__spec__.loader" is deprecated. In Python 3.16, "__loader__" ' +- 'will\n' +- ' cease to be set or taken into consideration by the import system ' +- 'or\n' +- ' the standard library.\n' +- '\n' +- 'module.__path__\n' +- '\n' +- ' A (possibly empty) *sequence* of strings enumerating the ' +- 'locations\n' +- ' where the package’s submodules will be found. Non-package ' +- 'modules\n' +- ' should not have a "__path__" attribute. See __path__ attributes ' +- 'on\n' +- ' modules for more details.\n' +- '\n' +- ' It is **strongly** recommended that you use\n' +- ' "module.__spec__.submodule_search_locations" instead of\n' +- ' "module.__path__".\n' +- '\n' +- 'module.__file__\n' +- '\n' +- 'module.__cached__\n' +- '\n' +- ' "__file__" and "__cached__" are both optional attributes that ' +- 'may\n' +- ' or may not be set. Both attributes should be a "str" when they ' +- 'are\n' +- ' available.\n' +- '\n' +- ' "__file__" indicates the pathname of the file from which the ' +- 'module\n' +- ' was loaded (if loaded from a file), or the pathname of the ' +- 'shared\n' +- ' library file for extension modules loaded dynamically from a ' +- 'shared\n' +- ' library. It might be missing for certain types of modules, such ' +- 'as\n' +- ' C modules that are statically linked into the interpreter, and ' +- 'the\n' +- ' import system may opt to leave it unset if it has no semantic\n' +- ' meaning (for example, a module loaded from a database).\n' +- '\n' +- ' If "__file__" is set then the "__cached__" attribute might also ' +- 'be\n' +- ' set, which is the path to any compiled version of the code ' +- '(for\n' +- ' example, a byte-compiled file). The file does not need to exist ' +- 'to\n' +- ' set this attribute; the path can simply point to where the ' +- 'compiled\n' +- ' file *would* exist (see **PEP 3147**).\n' +- '\n' +- ' Note that "__cached__" may be set even if "__file__" is not ' +- 'set.\n' +- ' However, that scenario is quite atypical. Ultimately, the ' +- '*loader*\n' +- ' is what makes use of the module spec provided by the *finder* ' +- '(from\n' +- ' which "__file__" and "__cached__" are derived). So if a loader ' +- 'can\n' +- ' load from a cached module but otherwise does not load from a ' +- 'file,\n' +- ' that atypical scenario may be appropriate.\n' +- '\n' +- ' It is **strongly** recommended that you use\n' +- ' "module.__spec__.cached" instead of "module.__cached__".\n' +- '\n' +- ' Deprecated since version 3.13, will be removed in version 3.15:\n' +- ' Setting "__cached__" on a module while failing to set\n' +- ' "__spec__.cached" is deprecated. In Python 3.15, "__cached__" ' +- 'will\n' +- ' cease to be set or taken into consideration by the import system ' +- 'or\n' +- ' standard library.\n' +- '\n' +- '\n' +- 'Other writable attributes on module objects\n' +- '-------------------------------------------\n' +- '\n' +- 'As well as the import-related attributes listed above, module ' +- 'objects\n' +- 'also have the following writable attributes:\n' +- '\n' +- 'module.__doc__\n' +- '\n' +- ' The module’s documentation string, or "None" if unavailable. ' +- 'See\n' +- ' also: "__doc__ attributes".\n' +- '\n' +- 'module.__annotations__\n' +- '\n' +- ' A dictionary containing *variable annotations* collected during\n' +- ' module body execution. For best practices on working with\n' +- ' "__annotations__", see "annotationlib".\n' +- '\n' +- ' Changed in version 3.14: Annotations are now lazily evaluated. ' +- 'See\n' +- ' **PEP 649**.\n' +- '\n' +- 'module.__annotate__\n' +- '\n' +- ' The *annotate function* for this module, or "None" if the ' +- 'module\n' +- ' has no annotations. See also: "__annotate__" attributes.\n' +- '\n' +- ' Added in version 3.14.\n' +- '\n' +- '\n' +- 'Module dictionaries\n' +- '-------------------\n' +- '\n' +- 'Module objects also have the following special read-only ' +- 'attribute:\n' +- '\n' +- 'module.__dict__\n' +- '\n' +- ' The module’s namespace as a dictionary object. Uniquely among ' +- 'the\n' +- ' attributes listed here, "__dict__" cannot be accessed as a ' +- 'global\n' +- ' variable from within a module; it can only be accessed as an\n' +- ' attribute on module objects.\n' +- '\n' +- ' **CPython implementation detail:** Because of the way CPython\n' +- ' clears module dictionaries, the module dictionary will be ' +- 'cleared\n' +- ' when the module falls out of scope even if the dictionary still ' +- 'has\n' +- ' live references. To avoid this, copy the dictionary or keep ' +- 'the\n' +- ' module around while using its dictionary directly.\n' +- '\n' +- '\n' +- 'Custom classes\n' +- '==============\n' +- '\n' +- 'Custom class types are typically created by class definitions (see\n' +- 'section Class definitions). A class has a namespace implemented by ' +- 'a\n' +- 'dictionary object. Class attribute references are translated to\n' +- 'lookups in this dictionary, e.g., "C.x" is translated to\n' +- '"C.__dict__["x"]" (although there are a number of hooks which ' +- 'allow\n' +- 'for other means of locating attributes). When the attribute name ' +- 'is\n' +- 'not found there, the attribute search continues in the base ' +- 'classes.\n' +- 'This search of the base classes uses the C3 method resolution ' +- 'order\n' +- 'which behaves correctly even in the presence of ‘diamond’ ' +- 'inheritance\n' +- 'structures where there are multiple inheritance paths leading back ' +- 'to\n' +- 'a common ancestor. Additional details on the C3 MRO used by Python ' +- 'can\n' +- 'be found at The Python 2.3 Method Resolution Order.\n' +- '\n' +- 'When a class attribute reference (for class "C", say) would yield ' +- 'a\n' +- 'class method object, it is transformed into an instance method ' +- 'object\n' +- 'whose "__self__" attribute is "C". When it would yield a\n' +- '"staticmethod" object, it is transformed into the object wrapped ' +- 'by\n' +- 'the static method object. See section Implementing Descriptors for\n' +- 'another way in which attributes retrieved from a class may differ ' +- 'from\n' +- 'those actually contained in its "__dict__".\n' +- '\n' +- 'Class attribute assignments update the class’s dictionary, never ' +- 'the\n' +- 'dictionary of a base class.\n' +- '\n' +- 'A class object can be called (see above) to yield a class instance\n' +- '(see below).\n' +- '\n' +- '\n' +- 'Special attributes\n' +- '------------------\n' +- '\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| Attribute | ' +- 'Meaning |\n' +- '|====================================================|====================================================|\n' +- '| type.__name__ | The class’s ' +- 'name. See also: "__name__ attributes". |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| type.__qualname__ | The class’s ' +- '*qualified name*. See also: |\n' +- '| | ' +- '"__qualname__ attributes". |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| type.__module__ | The name of ' +- 'the module in which the class was |\n' +- '| | ' +- 'defined. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| type.__dict__ | A "mapping ' +- 'proxy" providing a read-only view of |\n' +- '| | the class’s ' +- 'namespace. See also: "__dict__ |\n' +- '| | ' +- 'attributes". |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| type.__bases__ | A "tuple" ' +- 'containing the class’s bases. In most |\n' +- '| | cases, for a ' +- 'class defined as "class X(A, B, C)", |\n' +- '| | ' +- '"X.__bases__" will be exactly equal to "(A, B, |\n' +- '| | ' +- 'C)". |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| type.__doc__ | The class’s ' +- 'documentation string, or "None" if |\n' +- '| | undefined. ' +- 'Not inherited by subclasses. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| type.__annotations__ | A dictionary ' +- 'containing *variable annotations* |\n' +- '| | collected ' +- 'during class body execution. See also: |\n' +- '| | ' +- '"__annotations__ attributes". For best practices |\n' +- '| | on working ' +- 'with "__annotations__", please see |\n' +- '| | ' +- '"annotationlib". Caution: Accessing the |\n' +- '| | ' +- '"__annotations__" attribute of a class object |\n' +- '| | directly may ' +- 'yield incorrect results in the |\n' +- '| | presence of ' +- 'metaclasses. In addition, the |\n' +- '| | attribute ' +- 'may not exist for some classes. Use |\n' +- '| | ' +- '"annotationlib.get_annotations()" to retrieve |\n' +- '| | class ' +- 'annotations safely. Changed in version |\n' +- '| | 3.14: ' +- 'Annotations are now lazily evaluated. See |\n' +- '| | **PEP ' +- '649**. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| type.__annotate__() | The ' +- '*annotate function* for this class, or "None" |\n' +- '| | if the class ' +- 'has no annotations. See also: |\n' +- '| | ' +- '"__annotate__ attributes". Caution: Accessing |\n' +- '| | the ' +- '"__annotate__" attribute of a class object |\n' +- '| | directly may ' +- 'yield incorrect results in the |\n' +- '| | presence of ' +- 'metaclasses. Use |\n' +- '| | ' +- '"annotationlib.get_annotate_function()" to |\n' +- '| | retrieve the ' +- 'annotate function safely. Added in |\n' +- '| | version ' +- '3.14. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| type.__type_params__ | A "tuple" ' +- 'containing the type parameters of a |\n' +- '| | generic ' +- 'class. Added in version 3.12. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| type.__static_attributes__ | A "tuple" ' +- 'containing names of attributes of this |\n' +- '| | class which ' +- 'are assigned through "self.X" from any |\n' +- '| | function in ' +- 'its body. Added in version 3.13. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| type.__firstlineno__ | The line ' +- 'number of the first line of the class |\n' +- '| | definition, ' +- 'including decorators. Setting the |\n' +- '| | "__module__" ' +- 'attribute removes the |\n' +- '| | ' +- '"__firstlineno__" item from the type’s dictionary. |\n' +- '| | Added in ' +- 'version 3.13. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| type.__mro__ | The "tuple" ' +- 'of classes that are considered when |\n' +- '| | looking for ' +- 'base classes during method resolution. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '\n' +- '\n' +- 'Special methods\n' +- '---------------\n' +- '\n' +- 'In addition to the special attributes described above, all Python\n' +- 'classes also have the following two methods available:\n' +- '\n' +- 'type.mro()\n' +- '\n' +- ' This method can be overridden by a metaclass to customize the\n' +- ' method resolution order for its instances. It is called at ' +- 'class\n' +- ' instantiation, and its result is stored in "__mro__".\n' +- '\n' +- 'type.__subclasses__()\n' +- '\n' +- ' Each class keeps a list of weak references to its immediate\n' +- ' subclasses. This method returns a list of all those references\n' +- ' still alive. The list is in definition order. Example:\n' +- '\n' +- ' >>> class A: pass\n' +- ' >>> class B(A): pass\n' +- ' >>> A.__subclasses__()\n' +- " []\n" +- '\n' +- '\n' +- 'Class instances\n' +- '===============\n' +- '\n' +- 'A class instance is created by calling a class object (see above). ' +- 'A\n' +- 'class instance has a namespace implemented as a dictionary which ' +- 'is\n' +- 'the first place in which attribute references are searched. When ' +- 'an\n' +- 'attribute is not found there, and the instance’s class has an\n' +- 'attribute by that name, the search continues with the class\n' +- 'attributes. If a class attribute is found that is a user-defined\n' +- 'function object, it is transformed into an instance method object\n' +- 'whose "__self__" attribute is the instance. Static method and ' +- 'class\n' +- 'method objects are also transformed; see above under “Classesâ€. ' +- 'See\n' +- 'section Implementing Descriptors for another way in which ' +- 'attributes\n' +- 'of a class retrieved via its instances may differ from the objects\n' +- 'actually stored in the class’s "__dict__". If no class attribute ' +- 'is\n' +- 'found, and the object’s class has a "__getattr__()" method, that ' +- 'is\n' +- 'called to satisfy the lookup.\n' +- '\n' +- 'Attribute assignments and deletions update the instance’s ' +- 'dictionary,\n' +- 'never a class’s dictionary. If the class has a "__setattr__()" or\n' +- '"__delattr__()" method, this is called instead of updating the\n' +- 'instance dictionary directly.\n' +- '\n' +- 'Class instances can pretend to be numbers, sequences, or mappings ' +- 'if\n' +- 'they have methods with certain special names. See section Special\n' +- 'method names.\n' +- '\n' +- '\n' +- 'Special attributes\n' +- '------------------\n' +- '\n' +- 'object.__class__\n' +- '\n' +- ' The class to which a class instance belongs.\n' +- '\n' +- 'object.__dict__\n' +- '\n' +- ' A dictionary or other mapping object used to store an object’s\n' +- ' (writable) attributes. Not all instances have a "__dict__"\n' +- ' attribute; see the section on __slots__ for more details.\n' +- '\n' +- '\n' +- 'I/O objects (also known as file objects)\n' +- '========================================\n' +- '\n' +- 'A *file object* represents an open file. Various shortcuts are\n' +- 'available to create file objects: the "open()" built-in function, ' +- 'and\n' +- 'also "os.popen()", "os.fdopen()", and the "makefile()" method of\n' +- 'socket objects (and perhaps by other functions or methods provided ' +- 'by\n' +- 'extension modules).\n' +- '\n' +- 'The objects "sys.stdin", "sys.stdout" and "sys.stderr" are ' +- 'initialized\n' +- 'to file objects corresponding to the interpreter’s standard input,\n' +- 'output and error streams; they are all open in text mode and ' +- 'therefore\n' +- 'follow the interface defined by the "io.TextIOBase" abstract ' +- 'class.\n' +- '\n' +- '\n' +- 'Internal types\n' +- '==============\n' +- '\n' +- 'A few types used internally by the interpreter are exposed to the\n' +- 'user. Their definitions may change with future versions of the\n' +- 'interpreter, but they are mentioned here for completeness.\n' +- '\n' +- '\n' +- 'Code objects\n' +- '------------\n' +- '\n' +- 'Code objects represent *byte-compiled* executable Python code, or\n' +- '*bytecode*. The difference between a code object and a function ' +- 'object\n' +- 'is that the function object contains an explicit reference to the\n' +- 'function’s globals (the module in which it was defined), while a ' +- 'code\n' +- 'object contains no context; also the default argument values are\n' +- 'stored in the function object, not in the code object (because ' +- 'they\n' +- 'represent values calculated at run-time). Unlike function ' +- 'objects,\n' +- 'code objects are immutable and contain no references (directly or\n' +- 'indirectly) to mutable objects.\n' +- '\n' +- '\n' +- 'Special read-only attributes\n' +- '~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n' +- '\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| codeobject.co_name | The function ' +- 'name |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| codeobject.co_qualname | The fully ' +- 'qualified function name Added in |\n' +- '| | version ' +- '3.11. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| codeobject.co_argcount | The total ' +- 'number of positional *parameters* |\n' +- '| | (including ' +- 'positional-only parameters and |\n' +- '| | parameters ' +- 'with default values) that the function |\n' +- '| | ' +- 'has |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| codeobject.co_posonlyargcount | The number ' +- 'of positional-only *parameters* |\n' +- '| | (including ' +- 'arguments with default values) that the |\n' +- '| | function ' +- 'has |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| codeobject.co_kwonlyargcount | The number ' +- 'of keyword-only *parameters* (including |\n' +- '| | arguments ' +- 'with default values) that the function |\n' +- '| | ' +- 'has |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| codeobject.co_nlocals | The number ' +- 'of local variables used by the function |\n' +- '| | (including ' +- 'parameters) |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| codeobject.co_varnames | A "tuple" ' +- 'containing the names of the local |\n' +- '| | variables in ' +- 'the function (starting with the |\n' +- '| | parameter ' +- 'names) |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| codeobject.co_cellvars | A "tuple" ' +- 'containing the names of local variables |\n' +- '| | that are ' +- 'referenced from at least one *nested |\n' +- '| | scope* ' +- 'inside the function |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| codeobject.co_freevars | A "tuple" ' +- 'containing the names of *free (closure) |\n' +- '| | variables* ' +- 'that a *nested scope* references in an |\n' +- '| | outer scope. ' +- 'See also "function.__closure__". |\n' +- '| | Note: ' +- 'references to global and builtin names are |\n' +- '| | *not* ' +- 'included. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| codeobject.co_code | A string ' +- 'representing the sequence of *bytecode* |\n' +- '| | instructions ' +- 'in the function |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| codeobject.co_consts | A "tuple" ' +- 'containing the literals used by the |\n' +- '| | *bytecode* ' +- 'in the function |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| codeobject.co_names | A "tuple" ' +- 'containing the names used by the |\n' +- '| | *bytecode* ' +- 'in the function |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| codeobject.co_filename | The name of ' +- 'the file from which the code was |\n' +- '| | ' +- 'compiled |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| codeobject.co_firstlineno | The line ' +- 'number of the first line of the function |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| codeobject.co_lnotab | A string ' +- 'encoding the mapping from *bytecode* |\n' +- '| | offsets to ' +- 'line numbers. For details, see the |\n' +- '| | source code ' +- 'of the interpreter. Deprecated since |\n' +- '| | version ' +- '3.12: This attribute of code objects is |\n' +- '| | deprecated, ' +- 'and may be removed in Python 3.15. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| codeobject.co_stacksize | The required ' +- 'stack size of the code object |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| codeobject.co_flags | An "integer" ' +- 'encoding a number of flags for the |\n' +- '| | ' +- 'interpreter. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '\n' +- 'The following flag bits are defined for "co_flags": bit "0x04" is ' +- 'set\n' +- 'if the function uses the "*arguments" syntax to accept an ' +- 'arbitrary\n' +- 'number of positional arguments; bit "0x08" is set if the function ' +- 'uses\n' +- 'the "**keywords" syntax to accept arbitrary keyword arguments; bit\n' +- '"0x20" is set if the function is a generator. See Code Objects Bit\n' +- 'Flags for details on the semantics of each flags that might be\n' +- 'present.\n' +- '\n' +- 'Future feature declarations ("from __future__ import division") ' +- 'also\n' +- 'use bits in "co_flags" to indicate whether a code object was ' +- 'compiled\n' +- 'with a particular feature enabled: bit "0x2000" is set if the ' +- 'function\n' +- 'was compiled with future division enabled; bits "0x10" and ' +- '"0x1000"\n' +- 'were used in earlier versions of Python.\n' +- '\n' +- 'Other bits in "co_flags" are reserved for internal use.\n' +- '\n' +- 'If a code object represents a function and has a docstring, the ' +- 'first\n' +- 'item in "co_consts" is the docstring of the function.\n' +- '\n' +- '\n' +- 'Methods on code objects\n' +- '~~~~~~~~~~~~~~~~~~~~~~~\n' +- '\n' +- 'codeobject.co_positions()\n' +- '\n' +- ' Returns an iterable over the source code positions of each\n' +- ' *bytecode* instruction in the code object.\n' +- '\n' +- ' The iterator returns "tuple"s containing the "(start_line,\n' +- ' end_line, start_column, end_column)". The *i-th* tuple ' +- 'corresponds\n' +- ' to the position of the source code that compiled to the *i-th* ' +- 'code\n' +- ' unit. Column information is 0-indexed utf-8 byte offsets on the\n' +- ' given source line.\n' +- '\n' +- ' This positional information can be missing. A non-exhaustive ' +- 'lists\n' +- ' of cases where this may happen:\n' +- '\n' +- ' * Running the interpreter with "-X" "no_debug_ranges".\n' +- '\n' +- ' * Loading a pyc file compiled while using "-X" ' +- '"no_debug_ranges".\n' +- '\n' +- ' * Position tuples corresponding to artificial instructions.\n' +- '\n' +- ' * Line and column numbers that can’t be represented due to\n' +- ' implementation specific limitations.\n' +- '\n' +- ' When this occurs, some or all of the tuple elements can be ' +- '"None".\n' +- '\n' +- ' Added in version 3.11.\n' +- '\n' +- ' Note:\n' +- '\n' +- ' This feature requires storing column positions in code ' +- 'objects\n' +- ' which may result in a small increase of disk usage of ' +- 'compiled\n' +- ' Python files or interpreter memory usage. To avoid storing ' +- 'the\n' +- ' extra information and/or deactivate printing the extra ' +- 'traceback\n' +- ' information, the "-X" "no_debug_ranges" command line flag or ' +- 'the\n' +- ' "PYTHONNODEBUGRANGES" environment variable can be used.\n' +- '\n' +- 'codeobject.co_lines()\n' +- '\n' +- ' Returns an iterator that yields information about successive ' +- 'ranges\n' +- ' of *bytecode*s. Each item yielded is a "(start, end, lineno)"\n' +- ' "tuple":\n' +- '\n' +- ' * "start" (an "int") represents the offset (inclusive) of the ' +- 'start\n' +- ' of the *bytecode* range\n' +- '\n' +- ' * "end" (an "int") represents the offset (exclusive) of the end ' +- 'of\n' +- ' the *bytecode* range\n' +- '\n' +- ' * "lineno" is an "int" representing the line number of the\n' +- ' *bytecode* range, or "None" if the bytecodes in the given ' +- 'range\n' +- ' have no line number\n' +- '\n' +- ' The items yielded will have the following properties:\n' +- '\n' +- ' * The first range yielded will have a "start" of 0.\n' +- '\n' +- ' * The "(start, end)" ranges will be non-decreasing and ' +- 'consecutive.\n' +- ' That is, for any pair of "tuple"s, the "start" of the second ' +- 'will\n' +- ' be equal to the "end" of the first.\n' +- '\n' +- ' * No range will be backwards: "end >= start" for all triples.\n' +- '\n' +- ' * The last "tuple" yielded will have "end" equal to the size of ' +- 'the\n' +- ' *bytecode*.\n' +- '\n' +- ' Zero-width ranges, where "start == end", are allowed. ' +- 'Zero-width\n' +- ' ranges are used for lines that are present in the source code, ' +- 'but\n' +- ' have been eliminated by the *bytecode* compiler.\n' +- '\n' +- ' Added in version 3.10.\n' +- '\n' +- ' See also:\n' +- '\n' +- ' **PEP 626** - Precise line numbers for debugging and other ' +- 'tools.\n' +- ' The PEP that introduced the "co_lines()" method.\n' +- '\n' +- 'codeobject.replace(**kwargs)\n' +- '\n' +- ' Return a copy of the code object with new values for the ' +- 'specified\n' +- ' fields.\n' +- '\n' +- ' Code objects are also supported by the generic function\n' +- ' "copy.replace()".\n' +- '\n' +- ' Added in version 3.8.\n' +- '\n' +- '\n' +- 'Frame objects\n' +- '-------------\n' +- '\n' +- 'Frame objects represent execution frames. They may occur in ' +- 'traceback\n' +- 'objects, and are also passed to registered trace functions.\n' +- '\n' +- '\n' +- 'Special read-only attributes\n' +- '~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n' +- '\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| frame.f_back | Points to ' +- 'the previous stack frame (towards the |\n' +- '| | caller), or ' +- '"None" if this is the bottom stack |\n' +- '| | ' +- 'frame |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| frame.f_code | The code ' +- 'object being executed in this frame. |\n' +- '| | Accessing ' +- 'this attribute raises an auditing event |\n' +- '| | ' +- '"object.__getattr__" with arguments "obj" and |\n' +- '| | ' +- '""f_code"". |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| frame.f_locals | The mapping ' +- 'used by the frame to look up local |\n' +- '| | variables. ' +- 'If the frame refers to an *optimized |\n' +- '| | scope*, this ' +- 'may return a write-through proxy |\n' +- '| | object. ' +- 'Changed in version 3.13: Return a proxy |\n' +- '| | for ' +- 'optimized scopes. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| frame.f_globals | The ' +- 'dictionary used by the frame to look up global |\n' +- '| | ' +- 'variables |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| frame.f_builtins | The ' +- 'dictionary used by the frame to look up built- |\n' +- '| | in ' +- '(intrinsic) names |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| frame.f_lasti | The “precise ' +- 'instruction†of the frame object |\n' +- '| | (this is an ' +- 'index into the *bytecode* string of |\n' +- '| | the code ' +- 'object) |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '\n' +- '\n' +- 'Special writable attributes\n' +- '~~~~~~~~~~~~~~~~~~~~~~~~~~~\n' +- '\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| frame.f_trace | If not ' +- '"None", this is a function called for |\n' +- '| | various ' +- 'events during code execution (this is used |\n' +- '| | by ' +- 'debuggers). Normally an event is triggered for |\n' +- '| | each new ' +- 'source line (see "f_trace_lines"). |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| frame.f_trace_lines | Set this ' +- 'attribute to "False" to disable |\n' +- '| | triggering a ' +- 'tracing event for each source line. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| frame.f_trace_opcodes | Set this ' +- 'attribute to "True" to allow per-opcode |\n' +- '| | events to be ' +- 'requested. Note that this may lead to |\n' +- '| | undefined ' +- 'interpreter behaviour if exceptions |\n' +- '| | raised by ' +- 'the trace function escape to the |\n' +- '| | function ' +- 'being traced. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| frame.f_lineno | The current ' +- 'line number of the frame – writing to |\n' +- '| | this from ' +- 'within a trace function jumps to the |\n' +- '| | given line ' +- '(only for the bottom-most frame). A |\n' +- '| | debugger can ' +- 'implement a Jump command (aka Set |\n' +- '| | Next ' +- 'Statement) by writing to this attribute. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '\n' +- '\n' +- 'Frame object methods\n' +- '~~~~~~~~~~~~~~~~~~~~\n' +- '\n' +- 'Frame objects support one method:\n' +- '\n' +- 'frame.clear()\n' +- '\n' +- ' This method clears all references to local variables held by ' +- 'the\n' +- ' frame. Also, if the frame belonged to a *generator*, the ' +- 'generator\n' +- ' is finalized. This helps break reference cycles involving ' +- 'frame\n' +- ' objects (for example when catching an exception and storing its\n' +- ' traceback for later use).\n' +- '\n' +- ' "RuntimeError" is raised if the frame is currently executing or\n' +- ' suspended.\n' +- '\n' +- ' Added in version 3.4.\n' +- '\n' +- ' Changed in version 3.13: Attempting to clear a suspended frame\n' +- ' raises "RuntimeError" (as has always been the case for ' +- 'executing\n' +- ' frames).\n' +- '\n' +- '\n' +- 'Traceback objects\n' +- '-----------------\n' +- '\n' +- 'Traceback objects represent the stack trace of an exception. A\n' +- 'traceback object is implicitly created when an exception occurs, ' +- 'and\n' +- 'may also be explicitly created by calling "types.TracebackType".\n' +- '\n' +- 'Changed in version 3.7: Traceback objects can now be explicitly\n' +- 'instantiated from Python code.\n' +- '\n' +- 'For implicitly created tracebacks, when the search for an ' +- 'exception\n' +- 'handler unwinds the execution stack, at each unwound level a ' +- 'traceback\n' +- 'object is inserted in front of the current traceback. When an\n' +- 'exception handler is entered, the stack trace is made available to ' +- 'the\n' +- 'program. (See section The try statement.) It is accessible as the\n' +- 'third item of the tuple returned by "sys.exc_info()", and as the\n' +- '"__traceback__" attribute of the caught exception.\n' +- '\n' +- 'When the program contains no suitable handler, the stack trace is\n' +- 'written (nicely formatted) to the standard error stream; if the\n' +- 'interpreter is interactive, it is also made available to the user ' +- 'as\n' +- '"sys.last_traceback".\n' +- '\n' +- 'For explicitly created tracebacks, it is up to the creator of the\n' +- 'traceback to determine how the "tb_next" attributes should be ' +- 'linked\n' +- 'to form a full stack trace.\n' +- '\n' +- 'Special read-only attributes:\n' +- '\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| traceback.tb_frame | Points to ' +- 'the execution frame of the current |\n' +- '| | level. ' +- 'Accessing this attribute raises an |\n' +- '| | auditing ' +- 'event "object.__getattr__" with arguments |\n' +- '| | "obj" and ' +- '""tb_frame"". |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| traceback.tb_lineno | Gives the ' +- 'line number where the exception occurred |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '| traceback.tb_lasti | Indicates ' +- 'the “precise instructionâ€. |\n' +- '+----------------------------------------------------+----------------------------------------------------+\n' +- '\n' +- 'The line number and last instruction in the traceback may differ ' +- 'from\n' +- 'the line number of its frame object if the exception occurred in a\n' +- '"try" statement with no matching except clause or with a "finally"\n' +- 'clause.\n' +- '\n' +- 'traceback.tb_next\n' +- '\n' +- ' The special writable attribute "tb_next" is the next level in ' +- 'the\n' +- ' stack trace (towards the frame where the exception occurred), ' +- 'or\n' +- ' "None" if there is no next level.\n' +- '\n' +- ' Changed in version 3.7: This attribute is now writable\n' +- '\n' +- '\n' +- 'Slice objects\n' +- '-------------\n' +- '\n' +- 'Slice objects are used to represent slices for "__getitem__()"\n' +- 'methods. They are also created by the built-in "slice()" ' +- 'function.\n' +- '\n' +- 'Special read-only attributes: "start" is the lower bound; "stop" ' +- 'is\n' +- 'the upper bound; "step" is the step value; each is "None" if ' +- 'omitted.\n' +- 'These attributes can have any type.\n' +- '\n' +- 'Slice objects support one method:\n' +- '\n' +- 'slice.indices(self, length)\n' +- '\n' +- ' This method takes a single integer argument *length* and ' +- 'computes\n' +- ' information about the slice that the slice object would describe ' +- 'if\n' +- ' applied to a sequence of *length* items. It returns a tuple of\n' +- ' three integers; respectively these are the *start* and *stop*\n' +- ' indices and the *step* or stride length of the slice. Missing ' +- 'or\n' +- ' out-of-bounds indices are handled in a manner consistent with\n' +- ' regular slices.\n' +- '\n' +- '\n' +- 'Static method objects\n' +- '---------------------\n' +- '\n' +- 'Static method objects provide a way of defeating the transformation ' +- 'of\n' +- 'function objects to method objects described above. A static ' +- 'method\n' +- 'object is a wrapper around any other object, usually a ' +- 'user-defined\n' +- 'method object. When a static method object is retrieved from a ' +- 'class\n' +- 'or a class instance, the object actually returned is the wrapped\n' +- 'object, which is not subject to any further transformation. Static\n' +- 'method objects are also callable. Static method objects are created ' +- 'by\n' +- 'the built-in "staticmethod()" constructor.\n' +- '\n' +- '\n' +- 'Class method objects\n' +- '--------------------\n' +- '\n' +- 'A class method object, like a static method object, is a wrapper\n' +- 'around another object that alters the way in which that object is\n' +- 'retrieved from classes and class instances. The behaviour of class\n' +- 'method objects upon such retrieval is described above, under ' +- '“instance\n' +- 'methodsâ€. Class method objects are created by the built-in\n' +- '"classmethod()" constructor.\n', +- 'typesfunctions': 'Functions\n' +- '*********\n' +- '\n' +- 'Function objects are created by function definitions. The ' +- 'only\n' +- 'operation on a function object is to call it: ' +- '"func(argument-list)".\n' +- '\n' +- 'There are really two flavors of function objects: built-in ' +- 'functions\n' +- 'and user-defined functions. Both support the same ' +- 'operation (to call\n' +- 'the function), but the implementation is different, hence ' +- 'the\n' +- 'different object types.\n' +- '\n' +- 'See Function definitions for more information.\n', +- 'typesmapping': 'Mapping Types — "dict"\n' +- '**********************\n' +- '\n' +- 'A *mapping* object maps *hashable* values to arbitrary ' +- 'objects.\n' +- 'Mappings are mutable objects. There is currently only one ' +- 'standard\n' +- 'mapping type, the *dictionary*. (For other containers see ' +- 'the built-\n' +- 'in "list", "set", and "tuple" classes, and the "collections" ' +- 'module.)\n' +- '\n' +- 'A dictionary’s keys are *almost* arbitrary values. Values ' +- 'that are\n' +- 'not *hashable*, that is, values containing lists, ' +- 'dictionaries or\n' +- 'other mutable types (that are compared by value rather than ' +- 'by object\n' +- 'identity) may not be used as keys. Values that compare equal ' +- '(such as\n' +- '"1", "1.0", and "True") can be used interchangeably to index ' +- 'the same\n' +- 'dictionary entry.\n' +- '\n' +- 'class dict(**kwargs)\n' +- 'class dict(mapping, **kwargs)\n' +- 'class dict(iterable, **kwargs)\n' +- '\n' +- ' Return a new dictionary initialized from an optional ' +- 'positional\n' +- ' argument and a possibly empty set of keyword arguments.\n' +- '\n' +- ' Dictionaries can be created by several means:\n' +- '\n' +- ' * Use a comma-separated list of "key: value" pairs within ' +- 'braces:\n' +- ' "{\'jack\': 4098, \'sjoerd\': 4127}" or "{4098: ' +- "'jack', 4127:\n" +- ' \'sjoerd\'}"\n' +- '\n' +- ' * Use a dict comprehension: "{}", "{x: x ** 2 for x in ' +- 'range(10)}"\n' +- '\n' +- ' * Use the type constructor: "dict()", "dict([(\'foo\', ' +- "100), ('bar',\n" +- ' 200)])", "dict(foo=100, bar=200)"\n' +- '\n' +- ' If no positional argument is given, an empty dictionary ' +- 'is created.\n' +- ' If a positional argument is given and it defines a ' +- '"keys()" method,\n' +- ' a dictionary is created by calling "__getitem__()" on the ' +- 'argument\n' +- ' with each returned key from the method. Otherwise, the ' +- 'positional\n' +- ' argument must be an *iterable* object. Each item in the ' +- 'iterable\n' +- ' must itself be an iterable with exactly two elements. ' +- 'The first\n' +- ' element of each item becomes a key in the new dictionary, ' +- 'and the\n' +- ' second element the corresponding value. If a key occurs ' +- 'more than\n' +- ' once, the last value for that key becomes the ' +- 'corresponding value\n' +- ' in the new dictionary.\n' +- '\n' +- ' If keyword arguments are given, the keyword arguments and ' +- 'their\n' +- ' values are added to the dictionary created from the ' +- 'positional\n' +- ' argument. If a key being added is already present, the ' +- 'value from\n' +- ' the keyword argument replaces the value from the ' +- 'positional\n' +- ' argument.\n' +- '\n' +- ' To illustrate, the following examples all return a ' +- 'dictionary equal\n' +- ' to "{"one": 1, "two": 2, "three": 3}":\n' +- '\n' +- ' >>> a = dict(one=1, two=2, three=3)\n' +- " >>> b = {'one': 1, 'two': 2, 'three': 3}\n" +- " >>> c = dict(zip(['one', 'two', 'three'], [1, 2, 3]))\n" +- " >>> d = dict([('two', 2), ('one', 1), ('three', 3)])\n" +- " >>> e = dict({'three': 3, 'one': 1, 'two': 2})\n" +- " >>> f = dict({'one': 1, 'three': 3}, two=2)\n" +- ' >>> a == b == c == d == e == f\n' +- ' True\n' +- '\n' +- ' Providing keyword arguments as in the first example only ' +- 'works for\n' +- ' keys that are valid Python identifiers. Otherwise, any ' +- 'valid keys\n' +- ' can be used.\n' +- '\n' +- ' These are the operations that dictionaries support (and ' +- 'therefore,\n' +- ' custom mapping types should support too):\n' +- '\n' +- ' list(d)\n' +- '\n' +- ' Return a list of all the keys used in the dictionary ' +- '*d*.\n' +- '\n' +- ' len(d)\n' +- '\n' +- ' Return the number of items in the dictionary *d*.\n' +- '\n' +- ' d[key]\n' +- '\n' +- ' Return the item of *d* with key *key*. Raises a ' +- '"KeyError" if\n' +- ' *key* is not in the map.\n' +- '\n' +- ' If a subclass of dict defines a method "__missing__()" ' +- 'and *key*\n' +- ' is not present, the "d[key]" operation calls that ' +- 'method with\n' +- ' the key *key* as argument. The "d[key]" operation ' +- 'then returns\n' +- ' or raises whatever is returned or raised by the\n' +- ' "__missing__(key)" call. No other operations or ' +- 'methods invoke\n' +- ' "__missing__()". If "__missing__()" is not defined, ' +- '"KeyError"\n' +- ' is raised. "__missing__()" must be a method; it cannot ' +- 'be an\n' +- ' instance variable:\n' +- '\n' +- ' >>> class Counter(dict):\n' +- ' ... def __missing__(self, key):\n' +- ' ... return 0\n' +- ' ...\n' +- ' >>> c = Counter()\n' +- " >>> c['red']\n" +- ' 0\n' +- " >>> c['red'] += 1\n" +- " >>> c['red']\n" +- ' 1\n' +- '\n' +- ' The example above shows part of the implementation of\n' +- ' "collections.Counter". A different "__missing__" ' +- 'method is used\n' +- ' by "collections.defaultdict".\n' +- '\n' +- ' d[key] = value\n' +- '\n' +- ' Set "d[key]" to *value*.\n' +- '\n' +- ' del d[key]\n' +- '\n' +- ' Remove "d[key]" from *d*. Raises a "KeyError" if ' +- '*key* is not\n' +- ' in the map.\n' +- '\n' +- ' key in d\n' +- '\n' +- ' Return "True" if *d* has a key *key*, else "False".\n' +- '\n' +- ' key not in d\n' +- '\n' +- ' Equivalent to "not key in d".\n' +- '\n' +- ' iter(d)\n' +- '\n' +- ' Return an iterator over the keys of the dictionary. ' +- 'This is a\n' +- ' shortcut for "iter(d.keys())".\n' +- '\n' +- ' clear()\n' +- '\n' +- ' Remove all items from the dictionary.\n' +- '\n' +- ' copy()\n' +- '\n' +- ' Return a shallow copy of the dictionary.\n' +- '\n' +- ' classmethod fromkeys(iterable, value=None, /)\n' +- '\n' +- ' Create a new dictionary with keys from *iterable* and ' +- 'values set\n' +- ' to *value*.\n' +- '\n' +- ' "fromkeys()" is a class method that returns a new ' +- 'dictionary.\n' +- ' *value* defaults to "None". All of the values refer ' +- 'to just a\n' +- ' single instance, so it generally doesn’t make sense ' +- 'for *value*\n' +- ' to be a mutable object such as an empty list. To get ' +- 'distinct\n' +- ' values, use a dict comprehension instead.\n' +- '\n' +- ' get(key, default=None)\n' +- '\n' +- ' Return the value for *key* if *key* is in the ' +- 'dictionary, else\n' +- ' *default*. If *default* is not given, it defaults to ' +- '"None", so\n' +- ' that this method never raises a "KeyError".\n' +- '\n' +- ' items()\n' +- '\n' +- ' Return a new view of the dictionary’s items ("(key, ' +- 'value)"\n' +- ' pairs). See the documentation of view objects.\n' +- '\n' +- ' keys()\n' +- '\n' +- ' Return a new view of the dictionary’s keys. See the\n' +- ' documentation of view objects.\n' +- '\n' +- ' pop(key[, default])\n' +- '\n' +- ' If *key* is in the dictionary, remove it and return ' +- 'its value,\n' +- ' else return *default*. If *default* is not given and ' +- '*key* is\n' +- ' not in the dictionary, a "KeyError" is raised.\n' +- '\n' +- ' popitem()\n' +- '\n' +- ' Remove and return a "(key, value)" pair from the ' +- 'dictionary.\n' +- ' Pairs are returned in LIFO (last-in, first-out) ' +- 'order.\n' +- '\n' +- ' "popitem()" is useful to destructively iterate over a\n' +- ' dictionary, as often used in set algorithms. If the ' +- 'dictionary\n' +- ' is empty, calling "popitem()" raises a "KeyError".\n' +- '\n' +- ' Changed in version 3.7: LIFO order is now guaranteed. ' +- 'In prior\n' +- ' versions, "popitem()" would return an arbitrary ' +- 'key/value pair.\n' +- '\n' +- ' reversed(d)\n' +- '\n' +- ' Return a reverse iterator over the keys of the ' +- 'dictionary. This\n' +- ' is a shortcut for "reversed(d.keys())".\n' +- '\n' +- ' Added in version 3.8.\n' +- '\n' +- ' setdefault(key, default=None)\n' +- '\n' +- ' If *key* is in the dictionary, return its value. If ' +- 'not, insert\n' +- ' *key* with a value of *default* and return *default*. ' +- '*default*\n' +- ' defaults to "None".\n' +- '\n' +- ' update([other])\n' +- '\n' +- ' Update the dictionary with the key/value pairs from ' +- '*other*,\n' +- ' overwriting existing keys. Return "None".\n' +- '\n' +- ' "update()" accepts either another object with a ' +- '"keys()" method\n' +- ' (in which case "__getitem__()" is called with every ' +- 'key returned\n' +- ' from the method) or an iterable of key/value pairs (as ' +- 'tuples or\n' +- ' other iterables of length two). If keyword arguments ' +- 'are\n' +- ' specified, the dictionary is then updated with those ' +- 'key/value\n' +- ' pairs: "d.update(red=1, blue=2)".\n' +- '\n' +- ' values()\n' +- '\n' +- ' Return a new view of the dictionary’s values. See ' +- 'the\n' +- ' documentation of view objects.\n' +- '\n' +- ' An equality comparison between one "dict.values()" ' +- 'view and\n' +- ' another will always return "False". This also applies ' +- 'when\n' +- ' comparing "dict.values()" to itself:\n' +- '\n' +- " >>> d = {'a': 1}\n" +- ' >>> d.values() == d.values()\n' +- ' False\n' +- '\n' +- ' d | other\n' +- '\n' +- ' Create a new dictionary with the merged keys and ' +- 'values of *d*\n' +- ' and *other*, which must both be dictionaries. The ' +- 'values of\n' +- ' *other* take priority when *d* and *other* share ' +- 'keys.\n' +- '\n' +- ' Added in version 3.9.\n' +- '\n' +- ' d |= other\n' +- '\n' +- ' Update the dictionary *d* with keys and values from ' +- '*other*,\n' +- ' which may be either a *mapping* or an *iterable* of ' +- 'key/value\n' +- ' pairs. The values of *other* take priority when *d* ' +- 'and *other*\n' +- ' share keys.\n' +- '\n' +- ' Added in version 3.9.\n' +- '\n' +- ' Dictionaries compare equal if and only if they have the ' +- 'same "(key,\n' +- ' value)" pairs (regardless of ordering). Order comparisons ' +- '(‘<’,\n' +- ' ‘<=’, ‘>=’, ‘>’) raise "TypeError".\n' +- '\n' +- ' Dictionaries preserve insertion order. Note that ' +- 'updating a key\n' +- ' does not affect the order. Keys added after deletion are ' +- 'inserted\n' +- ' at the end.\n' +- '\n' +- ' >>> d = {"one": 1, "two": 2, "three": 3, "four": 4}\n' +- ' >>> d\n' +- " {'one': 1, 'two': 2, 'three': 3, 'four': 4}\n" +- ' >>> list(d)\n' +- " ['one', 'two', 'three', 'four']\n" +- ' >>> list(d.values())\n' +- ' [1, 2, 3, 4]\n' +- ' >>> d["one"] = 42\n' +- ' >>> d\n' +- " {'one': 42, 'two': 2, 'three': 3, 'four': 4}\n" +- ' >>> del d["two"]\n' +- ' >>> d["two"] = None\n' +- ' >>> d\n' +- " {'one': 42, 'three': 3, 'four': 4, 'two': None}\n" +- '\n' +- ' Changed in version 3.7: Dictionary order is guaranteed to ' +- 'be\n' +- ' insertion order. This behavior was an implementation ' +- 'detail of\n' +- ' CPython from 3.6.\n' +- '\n' +- ' Dictionaries and dictionary views are reversible.\n' +- '\n' +- ' >>> d = {"one": 1, "two": 2, "three": 3, "four": 4}\n' +- ' >>> d\n' +- " {'one': 1, 'two': 2, 'three': 3, 'four': 4}\n" +- ' >>> list(reversed(d))\n' +- " ['four', 'three', 'two', 'one']\n" +- ' >>> list(reversed(d.values()))\n' +- ' [4, 3, 2, 1]\n' +- ' >>> list(reversed(d.items()))\n' +- " [('four', 4), ('three', 3), ('two', 2), ('one', 1)]\n" +- '\n' +- ' Changed in version 3.8: Dictionaries are now reversible.\n' +- '\n' +- 'See also:\n' +- '\n' +- ' "types.MappingProxyType" can be used to create a read-only ' +- 'view of a\n' +- ' "dict".\n' +- '\n' +- '\n' +- 'Dictionary view objects\n' +- '=======================\n' +- '\n' +- 'The objects returned by "dict.keys()", "dict.values()" and\n' +- '"dict.items()" are *view objects*. They provide a dynamic ' +- 'view on the\n' +- 'dictionary’s entries, which means that when the dictionary ' +- 'changes,\n' +- 'the view reflects these changes.\n' +- '\n' +- 'Dictionary views can be iterated over to yield their ' +- 'respective data,\n' +- 'and support membership tests:\n' +- '\n' +- 'len(dictview)\n' +- '\n' +- ' Return the number of entries in the dictionary.\n' +- '\n' +- 'iter(dictview)\n' +- '\n' +- ' Return an iterator over the keys, values or items ' +- '(represented as\n' +- ' tuples of "(key, value)") in the dictionary.\n' +- '\n' +- ' Keys and values are iterated over in insertion order. ' +- 'This allows\n' +- ' the creation of "(value, key)" pairs using "zip()": ' +- '"pairs =\n' +- ' zip(d.values(), d.keys())". Another way to create the ' +- 'same list is\n' +- ' "pairs = [(v, k) for (k, v) in d.items()]".\n' +- '\n' +- ' Iterating views while adding or deleting entries in the ' +- 'dictionary\n' +- ' may raise a "RuntimeError" or fail to iterate over all ' +- 'entries.\n' +- '\n' +- ' Changed in version 3.7: Dictionary order is guaranteed to ' +- 'be\n' +- ' insertion order.\n' +- '\n' +- 'x in dictview\n' +- '\n' +- ' Return "True" if *x* is in the underlying dictionary’s ' +- 'keys, values\n' +- ' or items (in the latter case, *x* should be a "(key, ' +- 'value)"\n' +- ' tuple).\n' +- '\n' +- 'reversed(dictview)\n' +- '\n' +- ' Return a reverse iterator over the keys, values or items ' +- 'of the\n' +- ' dictionary. The view will be iterated in reverse order of ' +- 'the\n' +- ' insertion.\n' +- '\n' +- ' Changed in version 3.8: Dictionary views are now ' +- 'reversible.\n' +- '\n' +- 'dictview.mapping\n' +- '\n' +- ' Return a "types.MappingProxyType" that wraps the ' +- 'original\n' +- ' dictionary to which the view refers.\n' +- '\n' +- ' Added in version 3.10.\n' +- '\n' +- 'Keys views are set-like since their entries are unique and ' +- '*hashable*.\n' +- 'Items views also have set-like operations since the (key, ' +- 'value) pairs\n' +- 'are unique and the keys are hashable. If all values in an ' +- 'items view\n' +- 'are hashable as well, then the items view can interoperate ' +- 'with other\n' +- 'sets. (Values views are not treated as set-like since the ' +- 'entries are\n' +- 'generally not unique.) For set-like views, all of the ' +- 'operations\n' +- 'defined for the abstract base class "collections.abc.Set" ' +- 'are\n' +- 'available (for example, "==", "<", or "^"). While using ' +- 'set\n' +- 'operators, set-like views accept any iterable as the other ' +- 'operand,\n' +- 'unlike sets which only accept sets as the input.\n' +- '\n' +- 'An example of dictionary view usage:\n' +- '\n' +- " >>> dishes = {'eggs': 2, 'sausage': 1, 'bacon': 1, " +- "'spam': 500}\n" +- ' >>> keys = dishes.keys()\n' +- ' >>> values = dishes.values()\n' +- '\n' +- ' >>> # iteration\n' +- ' >>> n = 0\n' +- ' >>> for val in values:\n' +- ' ... n += val\n' +- ' ...\n' +- ' >>> print(n)\n' +- ' 504\n' +- '\n' +- ' >>> # keys and values are iterated over in the same order ' +- '(insertion order)\n' +- ' >>> list(keys)\n' +- " ['eggs', 'sausage', 'bacon', 'spam']\n" +- ' >>> list(values)\n' +- ' [2, 1, 1, 500]\n' +- '\n' +- ' >>> # view objects are dynamic and reflect dict changes\n' +- " >>> del dishes['eggs']\n" +- " >>> del dishes['sausage']\n" +- ' >>> list(keys)\n' +- " ['bacon', 'spam']\n" +- '\n' +- ' >>> # set operations\n' +- " >>> keys & {'eggs', 'bacon', 'salad'}\n" +- " {'bacon'}\n" +- " >>> keys ^ {'sausage', 'juice'} == {'juice', 'sausage', " +- "'bacon', 'spam'}\n" +- ' True\n' +- " >>> keys | ['juice', 'juice', 'juice'] == {'bacon', " +- "'spam', 'juice'}\n" +- ' True\n' +- '\n' +- ' >>> # get back a read-only proxy for the original ' +- 'dictionary\n' +- ' >>> values.mapping\n' +- " mappingproxy({'bacon': 1, 'spam': 500})\n" +- " >>> values.mapping['spam']\n" +- ' 500\n', +- 'typesmethods': 'Methods\n' +- '*******\n' +- '\n' +- 'Methods are functions that are called using the attribute ' +- 'notation.\n' +- 'There are two flavors: built-in methods (such as "append()" ' +- 'on lists)\n' +- 'and class instance method. Built-in methods are described ' +- 'with the\n' +- 'types that support them.\n' +- '\n' +- 'If you access a method (a function defined in a class ' +- 'namespace)\n' +- 'through an instance, you get a special object: a *bound ' +- 'method* (also\n' +- 'called instance method) object. When called, it will add the ' +- '"self"\n' +- 'argument to the argument list. Bound methods have two ' +- 'special read-\n' +- 'only attributes: "m.__self__" is the object on which the ' +- 'method\n' +- 'operates, and "m.__func__" is the function implementing the ' +- 'method.\n' +- 'Calling "m(arg-1, arg-2, ..., arg-n)" is completely ' +- 'equivalent to\n' +- 'calling "m.__func__(m.__self__, arg-1, arg-2, ..., arg-n)".\n' +- '\n' +- 'Like function objects, bound method objects support getting ' +- 'arbitrary\n' +- 'attributes. However, since method attributes are actually ' +- 'stored on\n' +- 'the underlying function object ("method.__func__"), setting ' +- 'method\n' +- 'attributes on bound methods is disallowed. Attempting to ' +- 'set an\n' +- 'attribute on a method results in an "AttributeError" being ' +- 'raised. In\n' +- 'order to set a method attribute, you need to explicitly set ' +- 'it on the\n' +- 'underlying function object:\n' +- '\n' +- ' >>> class C:\n' +- ' ... def method(self):\n' +- ' ... pass\n' +- ' ...\n' +- ' >>> c = C()\n' +- " >>> c.method.whoami = 'my name is method' # can't set on " +- 'the method\n' +- ' Traceback (most recent call last):\n' +- ' File "", line 1, in \n' +- " AttributeError: 'method' object has no attribute " +- "'whoami'\n" +- " >>> c.method.__func__.whoami = 'my name is method'\n" +- ' >>> c.method.whoami\n' +- " 'my name is method'\n" +- '\n' +- 'See Instance methods for more information.\n', +- 'typesmodules': 'Modules\n' +- '*******\n' +- '\n' +- 'The only special operation on a module is attribute access: ' +- '"m.name",\n' +- 'where *m* is a module and *name* accesses a name defined in ' +- '*m*’s\n' +- 'symbol table. Module attributes can be assigned to. (Note ' +- 'that the\n' +- '"import" statement is not, strictly speaking, an operation ' +- 'on a module\n' +- 'object; "import foo" does not require a module object named ' +- '*foo* to\n' +- 'exist, rather it requires an (external) *definition* for a ' +- 'module\n' +- 'named *foo* somewhere.)\n' +- '\n' +- 'A special attribute of every module is "__dict__". This is ' +- 'the\n' +- 'dictionary containing the module’s symbol table. Modifying ' +- 'this\n' +- 'dictionary will actually change the module’s symbol table, ' +- 'but direct\n' +- 'assignment to the "__dict__" attribute is not possible (you ' +- 'can write\n' +- '"m.__dict__[\'a\'] = 1", which defines "m.a" to be "1", but ' +- 'you can’t\n' +- 'write "m.__dict__ = {}"). Modifying "__dict__" directly is ' +- 'not\n' +- 'recommended.\n' +- '\n' +- 'Modules built into the interpreter are written like this: ' +- '"". If loaded from a file, they are ' +- 'written as\n' +- '"".\n', +- 'typesseq': 'Sequence Types — "list", "tuple", "range"\n' +- '*****************************************\n' +- '\n' +- 'There are three basic sequence types: lists, tuples, and range\n' +- 'objects. Additional sequence types tailored for processing of ' +- 'binary\n' +- 'data and text strings are described in dedicated sections.\n' +- '\n' +- '\n' +- 'Common Sequence Operations\n' +- '==========================\n' +- '\n' +- 'The operations in the following table are supported by most ' +- 'sequence\n' +- 'types, both mutable and immutable. The ' +- '"collections.abc.Sequence" ABC\n' +- 'is provided to make it easier to correctly implement these ' +- 'operations\n' +- 'on custom sequence types.\n' +- '\n' +- 'This table lists the sequence operations sorted in ascending ' +- 'priority.\n' +- 'In the table, *s* and *t* are sequences of the same type, *n*, ' +- '*i*,\n' +- '*j* and *k* are integers and *x* is an arbitrary object that ' +- 'meets any\n' +- 'type and value restrictions imposed by *s*.\n' +- '\n' +- 'The "in" and "not in" operations have the same priorities as ' +- 'the\n' +- 'comparison operations. The "+" (concatenation) and "*" ' +- '(repetition)\n' +- 'operations have the same priority as the corresponding numeric\n' +- 'operations. [3]\n' +- '\n' +- '+----------------------------+----------------------------------+------------+\n' +- '| Operation | Result ' +- '| Notes |\n' +- '|============================|==================================|============|\n' +- '| "x in s" | "True" if an item of *s* is ' +- '| (1) |\n' +- '| | equal to *x*, else "False" ' +- '| |\n' +- '+----------------------------+----------------------------------+------------+\n' +- '| "x not in s" | "False" if an item of *s* is ' +- '| (1) |\n' +- '| | equal to *x*, else "True" ' +- '| |\n' +- '+----------------------------+----------------------------------+------------+\n' +- '| "s + t" | the concatenation of *s* and *t* ' +- '| (6)(7) |\n' +- '+----------------------------+----------------------------------+------------+\n' +- '| "s * n" or "n * s" | equivalent to adding *s* to ' +- '| (2)(7) |\n' +- '| | itself *n* times ' +- '| |\n' +- '+----------------------------+----------------------------------+------------+\n' +- '| "s[i]" | *i*th item of *s*, origin 0 ' +- '| (3) |\n' +- '+----------------------------+----------------------------------+------------+\n' +- '| "s[i:j]" | slice of *s* from *i* to *j* ' +- '| (3)(4) |\n' +- '+----------------------------+----------------------------------+------------+\n' +- '| "s[i:j:k]" | slice of *s* from *i* to *j* ' +- '| (3)(5) |\n' +- '| | with step *k* ' +- '| |\n' +- '+----------------------------+----------------------------------+------------+\n' +- '| "len(s)" | length of *s* ' +- '| |\n' +- '+----------------------------+----------------------------------+------------+\n' +- '| "min(s)" | smallest item of *s* ' +- '| |\n' +- '+----------------------------+----------------------------------+------------+\n' +- '| "max(s)" | largest item of *s* ' +- '| |\n' +- '+----------------------------+----------------------------------+------------+\n' +- '| "s.index(x[, i[, j]])" | index of the first occurrence of ' +- '| (8) |\n' +- '| | *x* in *s* (at or after index ' +- '| |\n' +- '| | *i* and before index *j*) ' +- '| |\n' +- '+----------------------------+----------------------------------+------------+\n' +- '| "s.count(x)" | total number of occurrences of ' +- '| |\n' +- '| | *x* in *s* ' +- '| |\n' +- '+----------------------------+----------------------------------+------------+\n' +- '\n' +- 'Sequences of the same type also support comparisons. In ' +- 'particular,\n' +- 'tuples and lists are compared lexicographically by comparing\n' +- 'corresponding elements. This means that to compare equal, every\n' +- 'element must compare equal and the two sequences must be of the ' +- 'same\n' +- 'type and have the same length. (For full details see ' +- 'Comparisons in\n' +- 'the language reference.)\n' +- '\n' +- 'Forward and reversed iterators over mutable sequences access ' +- 'values\n' +- 'using an index. That index will continue to march forward (or\n' +- 'backward) even if the underlying sequence is mutated. The ' +- 'iterator\n' +- 'terminates only when an "IndexError" or a "StopIteration" is\n' +- 'encountered (or when the index drops below zero).\n' +- '\n' +- 'Notes:\n' +- '\n' +- '1. While the "in" and "not in" operations are used only for ' +- 'simple\n' +- ' containment testing in the general case, some specialised ' +- 'sequences\n' +- ' (such as "str", "bytes" and "bytearray") also use them for\n' +- ' subsequence testing:\n' +- '\n' +- ' >>> "gg" in "eggs"\n' +- ' True\n' +- '\n' +- '2. Values of *n* less than "0" are treated as "0" (which yields ' +- 'an\n' +- ' empty sequence of the same type as *s*). Note that items in ' +- 'the\n' +- ' sequence *s* are not copied; they are referenced multiple ' +- 'times.\n' +- ' This often haunts new Python programmers; consider:\n' +- '\n' +- ' >>> lists = [[]] * 3\n' +- ' >>> lists\n' +- ' [[], [], []]\n' +- ' >>> lists[0].append(3)\n' +- ' >>> lists\n' +- ' [[3], [3], [3]]\n' +- '\n' +- ' What has happened is that "[[]]" is a one-element list ' +- 'containing\n' +- ' an empty list, so all three elements of "[[]] * 3" are ' +- 'references\n' +- ' to this single empty list. Modifying any of the elements of\n' +- ' "lists" modifies this single list. You can create a list of\n' +- ' different lists this way:\n' +- '\n' +- ' >>> lists = [[] for i in range(3)]\n' +- ' >>> lists[0].append(3)\n' +- ' >>> lists[1].append(5)\n' +- ' >>> lists[2].append(7)\n' +- ' >>> lists\n' +- ' [[3], [5], [7]]\n' +- '\n' +- ' Further explanation is available in the FAQ entry How do I ' +- 'create a\n' +- ' multidimensional list?.\n' +- '\n' +- '3. If *i* or *j* is negative, the index is relative to the end ' +- 'of\n' +- ' sequence *s*: "len(s) + i" or "len(s) + j" is substituted. ' +- 'But\n' +- ' note that "-0" is still "0".\n' +- '\n' +- '4. The slice of *s* from *i* to *j* is defined as the sequence ' +- 'of\n' +- ' items with index *k* such that "i <= k < j". If *i* or *j* ' +- 'is\n' +- ' greater than "len(s)", use "len(s)". If *i* is omitted or ' +- '"None",\n' +- ' use "0". If *j* is omitted or "None", use "len(s)". If *i* ' +- 'is\n' +- ' greater than or equal to *j*, the slice is empty.\n' +- '\n' +- '5. The slice of *s* from *i* to *j* with step *k* is defined as ' +- 'the\n' +- ' sequence of items with index "x = i + n*k" such that "0 <= n ' +- '<\n' +- ' (j-i)/k". In other words, the indices are "i", "i+k", ' +- '"i+2*k",\n' +- ' "i+3*k" and so on, stopping when *j* is reached (but never\n' +- ' including *j*). When *k* is positive, *i* and *j* are ' +- 'reduced to\n' +- ' "len(s)" if they are greater. When *k* is negative, *i* and ' +- '*j* are\n' +- ' reduced to "len(s) - 1" if they are greater. If *i* or *j* ' +- 'are\n' +- ' omitted or "None", they become “end†values (which end ' +- 'depends on\n' +- ' the sign of *k*). Note, *k* cannot be zero. If *k* is ' +- '"None", it\n' +- ' is treated like "1".\n' +- '\n' +- '6. Concatenating immutable sequences always results in a new ' +- 'object.\n' +- ' This means that building up a sequence by repeated ' +- 'concatenation\n' +- ' will have a quadratic runtime cost in the total sequence ' +- 'length.\n' +- ' To get a linear runtime cost, you must switch to one of the\n' +- ' alternatives below:\n' +- '\n' +- ' * if concatenating "str" objects, you can build a list and ' +- 'use\n' +- ' "str.join()" at the end or else write to an "io.StringIO"\n' +- ' instance and retrieve its value when complete\n' +- '\n' +- ' * if concatenating "bytes" objects, you can similarly use\n' +- ' "bytes.join()" or "io.BytesIO", or you can do in-place\n' +- ' concatenation with a "bytearray" object. "bytearray" ' +- 'objects are\n' +- ' mutable and have an efficient overallocation mechanism\n' +- '\n' +- ' * if concatenating "tuple" objects, extend a "list" instead\n' +- '\n' +- ' * for other types, investigate the relevant class ' +- 'documentation\n' +- '\n' +- '7. Some sequence types (such as "range") only support item ' +- 'sequences\n' +- ' that follow specific patterns, and hence don’t support ' +- 'sequence\n' +- ' concatenation or repetition.\n' +- '\n' +- '8. "index" raises "ValueError" when *x* is not found in *s*. Not ' +- 'all\n' +- ' implementations support passing the additional arguments *i* ' +- 'and\n' +- ' *j*. These arguments allow efficient searching of subsections ' +- 'of\n' +- ' the sequence. Passing the extra arguments is roughly ' +- 'equivalent to\n' +- ' using "s[i:j].index(x)", only without copying any data and ' +- 'with the\n' +- ' returned index being relative to the start of the sequence ' +- 'rather\n' +- ' than the start of the slice.\n' +- '\n' +- '\n' +- 'Immutable Sequence Types\n' +- '========================\n' +- '\n' +- 'The only operation that immutable sequence types generally ' +- 'implement\n' +- 'that is not also implemented by mutable sequence types is ' +- 'support for\n' +- 'the "hash()" built-in.\n' +- '\n' +- 'This support allows immutable sequences, such as "tuple" ' +- 'instances, to\n' +- 'be used as "dict" keys and stored in "set" and "frozenset" ' +- 'instances.\n' +- '\n' +- 'Attempting to hash an immutable sequence that contains ' +- 'unhashable\n' +- 'values will result in "TypeError".\n' +- '\n' +- '\n' +- 'Mutable Sequence Types\n' +- '======================\n' +- '\n' +- 'The operations in the following table are defined on mutable ' +- 'sequence\n' +- 'types. The "collections.abc.MutableSequence" ABC is provided to ' +- 'make\n' +- 'it easier to correctly implement these operations on custom ' +- 'sequence\n' +- 'types.\n' +- '\n' +- 'In the table *s* is an instance of a mutable sequence type, *t* ' +- 'is any\n' +- 'iterable object and *x* is an arbitrary object that meets any ' +- 'type and\n' +- 'value restrictions imposed by *s* (for example, "bytearray" ' +- 'only\n' +- 'accepts integers that meet the value restriction "0 <= x <= ' +- '255").\n' +- '\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| Operation | ' +- 'Result | Notes |\n' +- '|================================|==================================|=======================|\n' +- '| "s[i] = x" | item *i* of *s* is replaced ' +- 'by | |\n' +- '| | ' +- '*x* | |\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| "s[i:j] = t" | slice of *s* from *i* to *j* ' +- 'is | |\n' +- '| | replaced by the contents of ' +- 'the | |\n' +- '| | iterable ' +- '*t* | |\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| "del s[i:j]" | same as "s[i:j] = ' +- '[]" | |\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| "s[i:j:k] = t" | the elements of "s[i:j:k]" ' +- 'are | (1) |\n' +- '| | replaced by those of ' +- '*t* | |\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| "del s[i:j:k]" | removes the elements ' +- 'of | |\n' +- '| | "s[i:j:k]" from the ' +- 'list | |\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| "s.append(x)" | appends *x* to the end of ' +- 'the | |\n' +- '| | sequence (same ' +- 'as | |\n' +- '| | "s[len(s):len(s)] = ' +- '[x]") | |\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| "s.clear()" | removes all items from *s* ' +- '(same | (5) |\n' +- '| | as "del ' +- 's[:]") | |\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| "s.copy()" | creates a shallow copy of ' +- '*s* | (5) |\n' +- '| | (same as ' +- '"s[:]") | |\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| "s.extend(t)" or "s += t" | extends *s* with the contents ' +- 'of | |\n' +- '| | *t* (for the most part the ' +- 'same | |\n' +- '| | as "s[len(s):len(s)] = ' +- 't") | |\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| "s *= n" | updates *s* with its ' +- 'contents | (6) |\n' +- '| | repeated *n* ' +- 'times | |\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| "s.insert(i, x)" | inserts *x* into *s* at ' +- 'the | |\n' +- '| | index given by *i* (same ' +- 'as | |\n' +- '| | "s[i:i] = ' +- '[x]") | |\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| "s.pop()" or "s.pop(i)" | retrieves the item at *i* ' +- 'and | (2) |\n' +- '| | also removes it from ' +- '*s* | |\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| "s.remove(x)" | removes the first item from ' +- '*s* | (3) |\n' +- '| | where "s[i]" is equal to ' +- '*x* | |\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| "s.reverse()" | reverses the items of *s* ' +- 'in | (4) |\n' +- '| | ' +- 'place | |\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '\n' +- 'Notes:\n' +- '\n' +- '1. If *k* is not equal to "1", *t* must have the same length as ' +- 'the\n' +- ' slice it is replacing.\n' +- '\n' +- '2. The optional argument *i* defaults to "-1", so that by ' +- 'default the\n' +- ' last item is removed and returned.\n' +- '\n' +- '3. "remove()" raises "ValueError" when *x* is not found in *s*.\n' +- '\n' +- '4. The "reverse()" method modifies the sequence in place for ' +- 'economy\n' +- ' of space when reversing a large sequence. To remind users ' +- 'that it\n' +- ' operates by side effect, it does not return the reversed ' +- 'sequence.\n' +- '\n' +- '5. "clear()" and "copy()" are included for consistency with the\n' +- ' interfaces of mutable containers that don’t support slicing\n' +- ' operations (such as "dict" and "set"). "copy()" is not part ' +- 'of the\n' +- ' "collections.abc.MutableSequence" ABC, but most concrete ' +- 'mutable\n' +- ' sequence classes provide it.\n' +- '\n' +- ' Added in version 3.3: "clear()" and "copy()" methods.\n' +- '\n' +- '6. The value *n* is an integer, or an object implementing\n' +- ' "__index__()". Zero and negative values of *n* clear the ' +- 'sequence.\n' +- ' Items in the sequence are not copied; they are referenced ' +- 'multiple\n' +- ' times, as explained for "s * n" under Common Sequence ' +- 'Operations.\n' +- '\n' +- '\n' +- 'Lists\n' +- '=====\n' +- '\n' +- 'Lists are mutable sequences, typically used to store collections ' +- 'of\n' +- 'homogeneous items (where the precise degree of similarity will ' +- 'vary by\n' +- 'application).\n' +- '\n' +- 'class list([iterable])\n' +- '\n' +- ' Lists may be constructed in several ways:\n' +- '\n' +- ' * Using a pair of square brackets to denote the empty list: ' +- '"[]"\n' +- '\n' +- ' * Using square brackets, separating items with commas: "[a]", ' +- '"[a,\n' +- ' b, c]"\n' +- '\n' +- ' * Using a list comprehension: "[x for x in iterable]"\n' +- '\n' +- ' * Using the type constructor: "list()" or "list(iterable)"\n' +- '\n' +- ' The constructor builds a list whose items are the same and in ' +- 'the\n' +- ' same order as *iterable*’s items. *iterable* may be either ' +- 'a\n' +- ' sequence, a container that supports iteration, or an ' +- 'iterator\n' +- ' object. If *iterable* is already a list, a copy is made and\n' +- ' returned, similar to "iterable[:]". For example, ' +- '"list(\'abc\')"\n' +- ' returns "[\'a\', \'b\', \'c\']" and "list( (1, 2, 3) )" ' +- 'returns "[1, 2,\n' +- ' 3]". If no argument is given, the constructor creates a new ' +- 'empty\n' +- ' list, "[]".\n' +- '\n' +- ' Many other operations also produce lists, including the ' +- '"sorted()"\n' +- ' built-in.\n' +- '\n' +- ' Lists implement all of the common and mutable sequence ' +- 'operations.\n' +- ' Lists also provide the following additional method:\n' +- '\n' +- ' sort(*, key=None, reverse=False)\n' +- '\n' +- ' This method sorts the list in place, using only "<" ' +- 'comparisons\n' +- ' between items. Exceptions are not suppressed - if any ' +- 'comparison\n' +- ' operations fail, the entire sort operation will fail (and ' +- 'the\n' +- ' list will likely be left in a partially modified state).\n' +- '\n' +- ' "sort()" accepts two arguments that can only be passed by\n' +- ' keyword (keyword-only arguments):\n' +- '\n' +- ' *key* specifies a function of one argument that is used ' +- 'to\n' +- ' extract a comparison key from each list element (for ' +- 'example,\n' +- ' "key=str.lower"). The key corresponding to each item in ' +- 'the list\n' +- ' is calculated once and then used for the entire sorting ' +- 'process.\n' +- ' The default value of "None" means that list items are ' +- 'sorted\n' +- ' directly without calculating a separate key value.\n' +- '\n' +- ' The "functools.cmp_to_key()" utility is available to ' +- 'convert a\n' +- ' 2.x style *cmp* function to a *key* function.\n' +- '\n' +- ' *reverse* is a boolean value. If set to "True", then the ' +- 'list\n' +- ' elements are sorted as if each comparison were reversed.\n' +- '\n' +- ' This method modifies the sequence in place for economy of ' +- 'space\n' +- ' when sorting a large sequence. To remind users that it ' +- 'operates\n' +- ' by side effect, it does not return the sorted sequence ' +- '(use\n' +- ' "sorted()" to explicitly request a new sorted list ' +- 'instance).\n' +- '\n' +- ' The "sort()" method is guaranteed to be stable. A sort ' +- 'is\n' +- ' stable if it guarantees not to change the relative order ' +- 'of\n' +- ' elements that compare equal — this is helpful for sorting ' +- 'in\n' +- ' multiple passes (for example, sort by department, then by ' +- 'salary\n' +- ' grade).\n' +- '\n' +- ' For sorting examples and a brief sorting tutorial, see ' +- 'Sorting\n' +- ' Techniques.\n' +- '\n' +- ' **CPython implementation detail:** While a list is being ' +- 'sorted,\n' +- ' the effect of attempting to mutate, or even inspect, the ' +- 'list is\n' +- ' undefined. The C implementation of Python makes the list ' +- 'appear\n' +- ' empty for the duration, and raises "ValueError" if it can ' +- 'detect\n' +- ' that the list has been mutated during a sort.\n' +- '\n' +- '\n' +- 'Tuples\n' +- '======\n' +- '\n' +- 'Tuples are immutable sequences, typically used to store ' +- 'collections of\n' +- 'heterogeneous data (such as the 2-tuples produced by the ' +- '"enumerate()"\n' +- 'built-in). Tuples are also used for cases where an immutable ' +- 'sequence\n' +- 'of homogeneous data is needed (such as allowing storage in a ' +- '"set" or\n' +- '"dict" instance).\n' +- '\n' +- 'class tuple([iterable])\n' +- '\n' +- ' Tuples may be constructed in a number of ways:\n' +- '\n' +- ' * Using a pair of parentheses to denote the empty tuple: ' +- '"()"\n' +- '\n' +- ' * Using a trailing comma for a singleton tuple: "a," or ' +- '"(a,)"\n' +- '\n' +- ' * Separating items with commas: "a, b, c" or "(a, b, c)"\n' +- '\n' +- ' * Using the "tuple()" built-in: "tuple()" or ' +- '"tuple(iterable)"\n' +- '\n' +- ' The constructor builds a tuple whose items are the same and ' +- 'in the\n' +- ' same order as *iterable*’s items. *iterable* may be either ' +- 'a\n' +- ' sequence, a container that supports iteration, or an ' +- 'iterator\n' +- ' object. If *iterable* is already a tuple, it is returned\n' +- ' unchanged. For example, "tuple(\'abc\')" returns "(\'a\', ' +- '\'b\', \'c\')"\n' +- ' and "tuple( [1, 2, 3] )" returns "(1, 2, 3)". If no argument ' +- 'is\n' +- ' given, the constructor creates a new empty tuple, "()".\n' +- '\n' +- ' Note that it is actually the comma which makes a tuple, not ' +- 'the\n' +- ' parentheses. The parentheses are optional, except in the ' +- 'empty\n' +- ' tuple case, or when they are needed to avoid syntactic ' +- 'ambiguity.\n' +- ' For example, "f(a, b, c)" is a function call with three ' +- 'arguments,\n' +- ' while "f((a, b, c))" is a function call with a 3-tuple as the ' +- 'sole\n' +- ' argument.\n' +- '\n' +- ' Tuples implement all of the common sequence operations.\n' +- '\n' +- 'For heterogeneous collections of data where access by name is ' +- 'clearer\n' +- 'than access by index, "collections.namedtuple()" may be a more\n' +- 'appropriate choice than a simple tuple object.\n' +- '\n' +- '\n' +- 'Ranges\n' +- '======\n' +- '\n' +- 'The "range" type represents an immutable sequence of numbers and ' +- 'is\n' +- 'commonly used for looping a specific number of times in "for" ' +- 'loops.\n' +- '\n' +- 'class range(stop)\n' +- 'class range(start, stop[, step])\n' +- '\n' +- ' The arguments to the range constructor must be integers ' +- '(either\n' +- ' built-in "int" or any object that implements the ' +- '"__index__()"\n' +- ' special method). If the *step* argument is omitted, it ' +- 'defaults to\n' +- ' "1". If the *start* argument is omitted, it defaults to "0". ' +- 'If\n' +- ' *step* is zero, "ValueError" is raised.\n' +- '\n' +- ' For a positive *step*, the contents of a range "r" are ' +- 'determined\n' +- ' by the formula "r[i] = start + step*i" where "i >= 0" and ' +- '"r[i] <\n' +- ' stop".\n' +- '\n' +- ' For a negative *step*, the contents of the range are still\n' +- ' determined by the formula "r[i] = start + step*i", but the\n' +- ' constraints are "i >= 0" and "r[i] > stop".\n' +- '\n' +- ' A range object will be empty if "r[0]" does not meet the ' +- 'value\n' +- ' constraint. Ranges do support negative indices, but these ' +- 'are\n' +- ' interpreted as indexing from the end of the sequence ' +- 'determined by\n' +- ' the positive indices.\n' +- '\n' +- ' Ranges containing absolute values larger than "sys.maxsize" ' +- 'are\n' +- ' permitted but some features (such as "len()") may raise\n' +- ' "OverflowError".\n' +- '\n' +- ' Range examples:\n' +- '\n' +- ' >>> list(range(10))\n' +- ' [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n' +- ' >>> list(range(1, 11))\n' +- ' [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n' +- ' >>> list(range(0, 30, 5))\n' +- ' [0, 5, 10, 15, 20, 25]\n' +- ' >>> list(range(0, 10, 3))\n' +- ' [0, 3, 6, 9]\n' +- ' >>> list(range(0, -10, -1))\n' +- ' [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]\n' +- ' >>> list(range(0))\n' +- ' []\n' +- ' >>> list(range(1, 0))\n' +- ' []\n' +- '\n' +- ' Ranges implement all of the common sequence operations ' +- 'except\n' +- ' concatenation and repetition (due to the fact that range ' +- 'objects\n' +- ' can only represent sequences that follow a strict pattern ' +- 'and\n' +- ' repetition and concatenation will usually violate that ' +- 'pattern).\n' +- '\n' +- ' start\n' +- '\n' +- ' The value of the *start* parameter (or "0" if the ' +- 'parameter was\n' +- ' not supplied)\n' +- '\n' +- ' stop\n' +- '\n' +- ' The value of the *stop* parameter\n' +- '\n' +- ' step\n' +- '\n' +- ' The value of the *step* parameter (or "1" if the parameter ' +- 'was\n' +- ' not supplied)\n' +- '\n' +- 'The advantage of the "range" type over a regular "list" or ' +- '"tuple" is\n' +- 'that a "range" object will always take the same (small) amount ' +- 'of\n' +- 'memory, no matter the size of the range it represents (as it ' +- 'only\n' +- 'stores the "start", "stop" and "step" values, calculating ' +- 'individual\n' +- 'items and subranges as needed).\n' +- '\n' +- 'Range objects implement the "collections.abc.Sequence" ABC, and\n' +- 'provide features such as containment tests, element index ' +- 'lookup,\n' +- 'slicing and support for negative indices (see Sequence Types — ' +- 'list,\n' +- 'tuple, range):\n' +- '\n' +- '>>> r = range(0, 20, 2)\n' +- '>>> r\n' +- 'range(0, 20, 2)\n' +- '>>> 11 in r\n' +- 'False\n' +- '>>> 10 in r\n' +- 'True\n' +- '>>> r.index(10)\n' +- '5\n' +- '>>> r[5]\n' +- '10\n' +- '>>> r[:5]\n' +- 'range(0, 10, 2)\n' +- '>>> r[-1]\n' +- '18\n' +- '\n' +- 'Testing range objects for equality with "==" and "!=" compares ' +- 'them as\n' +- 'sequences. That is, two range objects are considered equal if ' +- 'they\n' +- 'represent the same sequence of values. (Note that two range ' +- 'objects\n' +- 'that compare equal might have different "start", "stop" and ' +- '"step"\n' +- 'attributes, for example "range(0) == range(2, 1, 3)" or ' +- '"range(0, 3,\n' +- '2) == range(0, 4, 2)".)\n' +- '\n' +- 'Changed in version 3.2: Implement the Sequence ABC. Support ' +- 'slicing\n' +- 'and negative indices. Test "int" objects for membership in ' +- 'constant\n' +- 'time instead of iterating through all items.\n' +- '\n' +- 'Changed in version 3.3: Define ‘==’ and ‘!=’ to compare range ' +- 'objects\n' +- 'based on the sequence of values they define (instead of ' +- 'comparing\n' +- 'based on object identity).Added the "start", "stop" and "step"\n' +- 'attributes.\n' +- '\n' +- 'See also:\n' +- '\n' +- ' * The linspace recipe shows how to implement a lazy version of ' +- 'range\n' +- ' suitable for floating-point applications.\n', +- 'typesseq-mutable': 'Mutable Sequence Types\n' +- '**********************\n' +- '\n' +- 'The operations in the following table are defined on ' +- 'mutable sequence\n' +- 'types. The "collections.abc.MutableSequence" ABC is ' +- 'provided to make\n' +- 'it easier to correctly implement these operations on ' +- 'custom sequence\n' +- 'types.\n' +- '\n' +- 'In the table *s* is an instance of a mutable sequence ' +- 'type, *t* is any\n' +- 'iterable object and *x* is an arbitrary object that ' +- 'meets any type and\n' +- 'value restrictions imposed by *s* (for example, ' +- '"bytearray" only\n' +- 'accepts integers that meet the value restriction "0 <= x ' +- '<= 255").\n' +- '\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| Operation | ' +- 'Result | Notes ' +- '|\n' +- '|================================|==================================|=======================|\n' +- '| "s[i] = x" | item *i* of *s* is ' +- 'replaced by | |\n' +- '| | ' +- '*x* | ' +- '|\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| "s[i:j] = t" | slice of *s* from *i* ' +- 'to *j* is | |\n' +- '| | replaced by the ' +- 'contents of the | |\n' +- '| | iterable ' +- '*t* | |\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| "del s[i:j]" | same as "s[i:j] = ' +- '[]" | |\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| "s[i:j:k] = t" | the elements of ' +- '"s[i:j:k]" are | (1) |\n' +- '| | replaced by those of ' +- '*t* | |\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| "del s[i:j:k]" | removes the elements ' +- 'of | |\n' +- '| | "s[i:j:k]" from the ' +- 'list | |\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| "s.append(x)" | appends *x* to the ' +- 'end of the | |\n' +- '| | sequence (same ' +- 'as | |\n' +- '| | "s[len(s):len(s)] = ' +- '[x]") | |\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| "s.clear()" | removes all items ' +- 'from *s* (same | (5) |\n' +- '| | as "del ' +- 's[:]") | |\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| "s.copy()" | creates a shallow ' +- 'copy of *s* | (5) |\n' +- '| | (same as ' +- '"s[:]") | |\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| "s.extend(t)" or "s += t" | extends *s* with the ' +- 'contents of | |\n' +- '| | *t* (for the most ' +- 'part the same | |\n' +- '| | as "s[len(s):len(s)] ' +- '= t") | |\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| "s *= n" | updates *s* with its ' +- 'contents | (6) |\n' +- '| | repeated *n* ' +- 'times | |\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| "s.insert(i, x)" | inserts *x* into *s* ' +- 'at the | |\n' +- '| | index given by *i* ' +- '(same as | |\n' +- '| | "s[i:i] = ' +- '[x]") | |\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| "s.pop()" or "s.pop(i)" | retrieves the item at ' +- '*i* and | (2) |\n' +- '| | also removes it from ' +- '*s* | |\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| "s.remove(x)" | removes the first ' +- 'item from *s* | (3) |\n' +- '| | where "s[i]" is equal ' +- 'to *x* | |\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '| "s.reverse()" | reverses the items of ' +- '*s* in | (4) |\n' +- '| | ' +- 'place | ' +- '|\n' +- '+--------------------------------+----------------------------------+-----------------------+\n' +- '\n' +- 'Notes:\n' +- '\n' +- '1. If *k* is not equal to "1", *t* must have the same ' +- 'length as the\n' +- ' slice it is replacing.\n' +- '\n' +- '2. The optional argument *i* defaults to "-1", so that ' +- 'by default the\n' +- ' last item is removed and returned.\n' +- '\n' +- '3. "remove()" raises "ValueError" when *x* is not found ' +- 'in *s*.\n' +- '\n' +- '4. The "reverse()" method modifies the sequence in place ' +- 'for economy\n' +- ' of space when reversing a large sequence. To remind ' +- 'users that it\n' +- ' operates by side effect, it does not return the ' +- 'reversed sequence.\n' +- '\n' +- '5. "clear()" and "copy()" are included for consistency ' +- 'with the\n' +- ' interfaces of mutable containers that don’t support ' +- 'slicing\n' +- ' operations (such as "dict" and "set"). "copy()" is ' +- 'not part of the\n' +- ' "collections.abc.MutableSequence" ABC, but most ' +- 'concrete mutable\n' +- ' sequence classes provide it.\n' +- '\n' +- ' Added in version 3.3: "clear()" and "copy()" ' +- 'methods.\n' +- '\n' +- '6. The value *n* is an integer, or an object ' +- 'implementing\n' +- ' "__index__()". Zero and negative values of *n* clear ' +- 'the sequence.\n' +- ' Items in the sequence are not copied; they are ' +- 'referenced multiple\n' +- ' times, as explained for "s * n" under Common Sequence ' +- 'Operations.\n', +- 'unary': 'Unary arithmetic and bitwise operations\n' +- '***************************************\n' +- '\n' +- 'All unary arithmetic and bitwise operations have the same ' +- 'priority:\n' +- '\n' +- ' u_expr ::= power | "-" u_expr | "+" u_expr | "~" u_expr\n' +- '\n' +- 'The unary "-" (minus) operator yields the negation of its numeric\n' +- 'argument; the operation can be overridden with the "__neg__()" ' +- 'special\n' +- 'method.\n' +- '\n' +- 'The unary "+" (plus) operator yields its numeric argument ' +- 'unchanged;\n' +- 'the operation can be overridden with the "__pos__()" special ' +- 'method.\n' +- '\n' +- 'The unary "~" (invert) operator yields the bitwise inversion of ' +- 'its\n' +- 'integer argument. The bitwise inversion of "x" is defined as\n' +- '"-(x+1)". It only applies to integral numbers or to custom ' +- 'objects\n' +- 'that override the "__invert__()" special method.\n' +- '\n' +- 'In all three cases, if the argument does not have the proper type, ' +- 'a\n' +- '"TypeError" exception is raised.\n', +- 'while': 'The "while" statement\n' +- '*********************\n' +- '\n' +- 'The "while" statement is used for repeated execution as long as an\n' +- 'expression is true:\n' +- '\n' +- ' while_stmt ::= "while" assignment_expression ":" suite\n' +- ' ["else" ":" suite]\n' +- '\n' +- 'This repeatedly tests the expression and, if it is true, executes ' +- 'the\n' +- 'first suite; if the expression is false (which may be the first ' +- 'time\n' +- 'it is tested) the suite of the "else" clause, if present, is ' +- 'executed\n' +- 'and the loop terminates.\n' +- '\n' +- 'A "break" statement executed in the first suite terminates the ' +- 'loop\n' +- 'without executing the "else" clause’s suite. A "continue" ' +- 'statement\n' +- 'executed in the first suite skips the rest of the suite and goes ' +- 'back\n' +- 'to testing the expression.\n', +- 'with': 'The "with" statement\n' +- '********************\n' +- '\n' +- 'The "with" statement is used to wrap the execution of a block with\n' +- 'methods defined by a context manager (see section With Statement\n' +- 'Context Managers). This allows common "try"…"except"…"finally" ' +- 'usage\n' +- 'patterns to be encapsulated for convenient reuse.\n' +- '\n' +- ' with_stmt ::= "with" ( "(" with_stmt_contents ","? ")" | ' +- 'with_stmt_contents ) ":" suite\n' +- ' with_stmt_contents ::= with_item ("," with_item)*\n' +- ' with_item ::= expression ["as" target]\n' +- '\n' +- 'The execution of the "with" statement with one “item†proceeds as\n' +- 'follows:\n' +- '\n' +- '1. The context expression (the expression given in the "with_item") ' +- 'is\n' +- ' evaluated to obtain a context manager.\n' +- '\n' +- '2. The context manager’s "__enter__()" is loaded for later use.\n' +- '\n' +- '3. The context manager’s "__exit__()" is loaded for later use.\n' +- '\n' +- '4. The context manager’s "__enter__()" method is invoked.\n' +- '\n' +- '5. If a target was included in the "with" statement, the return ' +- 'value\n' +- ' from "__enter__()" is assigned to it.\n' +- '\n' +- ' Note:\n' +- '\n' +- ' The "with" statement guarantees that if the "__enter__()" ' +- 'method\n' +- ' returns without an error, then "__exit__()" will always be\n' +- ' called. Thus, if an error occurs during the assignment to the\n' +- ' target list, it will be treated the same as an error occurring\n' +- ' within the suite would be. See step 7 below.\n' +- '\n' +- '6. The suite is executed.\n' +- '\n' +- '7. The context manager’s "__exit__()" method is invoked. If an\n' +- ' exception caused the suite to be exited, its type, value, and\n' +- ' traceback are passed as arguments to "__exit__()". Otherwise, ' +- 'three\n' +- ' "None" arguments are supplied.\n' +- '\n' +- ' If the suite was exited due to an exception, and the return ' +- 'value\n' +- ' from the "__exit__()" method was false, the exception is ' +- 'reraised.\n' +- ' If the return value was true, the exception is suppressed, and\n' +- ' execution continues with the statement following the "with"\n' +- ' statement.\n' +- '\n' +- ' If the suite was exited for any reason other than an exception, ' +- 'the\n' +- ' return value from "__exit__()" is ignored, and execution ' +- 'proceeds\n' +- ' at the normal location for the kind of exit that was taken.\n' +- '\n' +- 'The following code:\n' +- '\n' +- ' with EXPRESSION as TARGET:\n' +- ' SUITE\n' +- '\n' +- 'is semantically equivalent to:\n' +- '\n' +- ' manager = (EXPRESSION)\n' +- ' enter = type(manager).__enter__\n' +- ' exit = type(manager).__exit__\n' +- ' value = enter(manager)\n' +- '\n' +- ' try:\n' +- ' TARGET = value\n' +- ' SUITE\n' +- ' except:\n' +- ' if not exit(manager, *sys.exc_info()):\n' +- ' raise\n' +- ' else:\n' +- ' exit(manager, None, None, None)\n' +- '\n' +- 'With more than one item, the context managers are processed as if\n' +- 'multiple "with" statements were nested:\n' +- '\n' +- ' with A() as a, B() as b:\n' +- ' SUITE\n' +- '\n' +- 'is semantically equivalent to:\n' +- '\n' +- ' with A() as a:\n' +- ' with B() as b:\n' +- ' SUITE\n' +- '\n' +- 'You can also write multi-item context managers in multiple lines if\n' +- 'the items are surrounded by parentheses. For example:\n' +- '\n' +- ' with (\n' +- ' A() as a,\n' +- ' B() as b,\n' +- ' ):\n' +- ' SUITE\n' +- '\n' +- 'Changed in version 3.1: Support for multiple context expressions.\n' +- '\n' +- 'Changed in version 3.10: Support for using grouping parentheses to\n' +- 'break the statement in multiple lines.\n' +- '\n' +- 'See also:\n' +- '\n' +- ' **PEP 343** - The “with†statement\n' +- ' The specification, background, and examples for the Python ' +- '"with"\n' +- ' statement.\n', +- 'yield': 'The "yield" statement\n' +- '*********************\n' +- '\n' +- ' yield_stmt ::= yield_expression\n' +- '\n' +- 'A "yield" statement is semantically equivalent to a yield ' +- 'expression.\n' +- 'The "yield" statement can be used to omit the parentheses that ' +- 'would\n' +- 'otherwise be required in the equivalent yield expression ' +- 'statement.\n' +- 'For example, the yield statements\n' +- '\n' +- ' yield \n' +- ' yield from \n' +- '\n' +- 'are equivalent to the yield expression statements\n' +- '\n' +- ' (yield )\n' +- ' (yield from )\n' +- '\n' +- 'Yield expressions and statements are only used when defining a\n' +- '*generator* function, and are only used in the body of the ' +- 'generator\n' +- 'function. Using "yield" in a function definition is sufficient to\n' +- 'cause that definition to create a generator function instead of a\n' +- 'normal function.\n' +- '\n' +- 'For full details of "yield" semantics, refer to the Yield ' +- 'expressions\n' +- 'section.\n'} ++ ++topics = { ++ 'assert': r'''The "assert" statement ++********************** ++ ++Assert statements are a convenient way to insert debugging assertions ++into a program: ++ ++ **assert_stmt**: "assert" "expression" ["," "expression"] ++ ++The simple form, "assert expression", is equivalent to ++ ++ if __debug__: ++ if not expression: raise AssertionError ++ ++The extended form, "assert expression1, expression2", is equivalent to ++ ++ if __debug__: ++ if not expression1: raise AssertionError(expression2) ++ ++These equivalences assume that "__debug__" and "AssertionError" refer ++to the built-in variables with those names. In the current ++implementation, the built-in variable "__debug__" is "True" under ++normal circumstances, "False" when optimization is requested (command ++line option "-O"). The current code generator emits no code for an ++"assert" statement when optimization is requested at compile time. ++Note that it is unnecessary to include the source code for the ++expression that failed in the error message; it will be displayed as ++part of the stack trace. ++ ++Assignments to "__debug__" are illegal. The value for the built-in ++variable is determined when the interpreter starts. ++''', ++ 'assignment': r'''Assignment statements ++********************* ++ ++Assignment statements are used to (re)bind names to values and to ++modify attributes or items of mutable objects: ++ ++ **assignment_stmt**: ("target_list" "=")+ ("starred_expression" | "yield_expression") ++ **target_list**: "target" ("," "target")* [","] ++ **target**: "identifier" ++ | "(" ["target_list"] ")" ++ | "[" ["target_list"] "]" ++ | "attributeref" ++ | "subscription" ++ | "slicing" ++ | "*" "target" ++ ++(See section Primaries for the syntax definitions for *attributeref*, ++*subscription*, and *slicing*.) ++ ++An assignment statement evaluates the expression list (remember that ++this can be a single expression or a comma-separated list, the latter ++yielding a tuple) and assigns the single resulting object to each of ++the target lists, from left to right. ++ ++Assignment is defined recursively depending on the form of the target ++(list). When a target is part of a mutable object (an attribute ++reference, subscription or slicing), the mutable object must ++ultimately perform the assignment and decide about its validity, and ++may raise an exception if the assignment is unacceptable. The rules ++observed by various types and the exceptions raised are given with the ++definition of the object types (see section The standard type ++hierarchy). ++ ++Assignment of an object to a target list, optionally enclosed in ++parentheses or square brackets, is recursively defined as follows. ++ ++* If the target list is a single target with no trailing comma, ++ optionally in parentheses, the object is assigned to that target. ++ ++* Else: ++ ++ * If the target list contains one target prefixed with an asterisk, ++ called a “starred†target: The object must be an iterable with at ++ least as many items as there are targets in the target list, minus ++ one. The first items of the iterable are assigned, from left to ++ right, to the targets before the starred target. The final items ++ of the iterable are assigned to the targets after the starred ++ target. A list of the remaining items in the iterable is then ++ assigned to the starred target (the list can be empty). ++ ++ * Else: The object must be an iterable with the same number of items ++ as there are targets in the target list, and the items are ++ assigned, from left to right, to the corresponding targets. ++ ++Assignment of an object to a single target is recursively defined as ++follows. ++ ++* If the target is an identifier (name): ++ ++ * If the name does not occur in a "global" or "nonlocal" statement ++ in the current code block: the name is bound to the object in the ++ current local namespace. ++ ++ * Otherwise: the name is bound to the object in the global namespace ++ or the outer namespace determined by "nonlocal", respectively. ++ ++ The name is rebound if it was already bound. This may cause the ++ reference count for the object previously bound to the name to reach ++ zero, causing the object to be deallocated and its destructor (if it ++ has one) to be called. ++ ++* If the target is an attribute reference: The primary expression in ++ the reference is evaluated. It should yield an object with ++ assignable attributes; if this is not the case, "TypeError" is ++ raised. That object is then asked to assign the assigned object to ++ the given attribute; if it cannot perform the assignment, it raises ++ an exception (usually but not necessarily "AttributeError"). ++ ++ Note: If the object is a class instance and the attribute reference ++ occurs on both sides of the assignment operator, the right-hand side ++ expression, "a.x" can access either an instance attribute or (if no ++ instance attribute exists) a class attribute. The left-hand side ++ target "a.x" is always set as an instance attribute, creating it if ++ necessary. Thus, the two occurrences of "a.x" do not necessarily ++ refer to the same attribute: if the right-hand side expression ++ refers to a class attribute, the left-hand side creates a new ++ instance attribute as the target of the assignment: ++ ++ class Cls: ++ x = 3 # class variable ++ inst = Cls() ++ inst.x = inst.x + 1 # writes inst.x as 4 leaving Cls.x as 3 ++ ++ This description does not necessarily apply to descriptor ++ attributes, such as properties created with "property()". ++ ++* If the target is a subscription: The primary expression in the ++ reference is evaluated. It should yield either a mutable sequence ++ object (such as a list) or a mapping object (such as a dictionary). ++ Next, the subscript expression is evaluated. ++ ++ If the primary is a mutable sequence object (such as a list), the ++ subscript must yield an integer. If it is negative, the sequence’s ++ length is added to it. The resulting value must be a nonnegative ++ integer less than the sequence’s length, and the sequence is asked ++ to assign the assigned object to its item with that index. If the ++ index is out of range, "IndexError" is raised (assignment to a ++ subscripted sequence cannot add new items to a list). ++ ++ If the primary is a mapping object (such as a dictionary), the ++ subscript must have a type compatible with the mapping’s key type, ++ and the mapping is then asked to create a key/value pair which maps ++ the subscript to the assigned object. This can either replace an ++ existing key/value pair with the same key value, or insert a new ++ key/value pair (if no key with the same value existed). ++ ++ For user-defined objects, the "__setitem__()" method is called with ++ appropriate arguments. ++ ++* If the target is a slicing: The primary expression in the reference ++ is evaluated. It should yield a mutable sequence object (such as a ++ list). The assigned object should be a sequence object of the same ++ type. Next, the lower and upper bound expressions are evaluated, ++ insofar they are present; defaults are zero and the sequence’s ++ length. The bounds should evaluate to integers. If either bound is ++ negative, the sequence’s length is added to it. The resulting ++ bounds are clipped to lie between zero and the sequence’s length, ++ inclusive. Finally, the sequence object is asked to replace the ++ slice with the items of the assigned sequence. The length of the ++ slice may be different from the length of the assigned sequence, ++ thus changing the length of the target sequence, if the target ++ sequence allows it. ++ ++**CPython implementation detail:** In the current implementation, the ++syntax for targets is taken to be the same as for expressions, and ++invalid syntax is rejected during the code generation phase, causing ++less detailed error messages. ++ ++Although the definition of assignment implies that overlaps between ++the left-hand side and the right-hand side are ‘simultaneous’ (for ++example "a, b = b, a" swaps two variables), overlaps *within* the ++collection of assigned-to variables occur left-to-right, sometimes ++resulting in confusion. For instance, the following program prints ++"[0, 2]": ++ ++ x = [0, 1] ++ i = 0 ++ i, x[i] = 1, 2 # i is updated, then x[i] is updated ++ print(x) ++ ++See also: ++ ++ **PEP 3132** - Extended Iterable Unpacking ++ The specification for the "*target" feature. ++ ++ ++Augmented assignment statements ++=============================== ++ ++Augmented assignment is the combination, in a single statement, of a ++binary operation and an assignment statement: ++ ++ **augmented_assignment_stmt**: "augtarget" "augop" ("expression_list" | "yield_expression") ++ **augtarget**: "identifier" | "attributeref" | "subscription" | "slicing" ++ **augop**: "+=" | "-=" | "*=" | "@=" | "/=" | "//=" | "%=" | "**=" ++ | ">>=" | "<<=" | "&=" | "^=" | "|=" ++ ++(See section Primaries for the syntax definitions of the last three ++symbols.) ++ ++An augmented assignment evaluates the target (which, unlike normal ++assignment statements, cannot be an unpacking) and the expression ++list, performs the binary operation specific to the type of assignment ++on the two operands, and assigns the result to the original target. ++The target is only evaluated once. ++ ++An augmented assignment statement like "x += 1" can be rewritten as "x ++= x + 1" to achieve a similar, but not exactly equal effect. In the ++augmented version, "x" is only evaluated once. Also, when possible, ++the actual operation is performed *in-place*, meaning that rather than ++creating a new object and assigning that to the target, the old object ++is modified instead. ++ ++Unlike normal assignments, augmented assignments evaluate the left- ++hand side *before* evaluating the right-hand side. For example, "a[i] +++= f(x)" first looks-up "a[i]", then it evaluates "f(x)" and performs ++the addition, and lastly, it writes the result back to "a[i]". ++ ++With the exception of assigning to tuples and multiple targets in a ++single statement, the assignment done by augmented assignment ++statements is handled the same way as normal assignments. Similarly, ++with the exception of the possible *in-place* behavior, the binary ++operation performed by augmented assignment is the same as the normal ++binary operations. ++ ++For targets which are attribute references, the same caveat about ++class and instance attributes applies as for regular assignments. ++ ++ ++Annotated assignment statements ++=============================== ++ ++*Annotation* assignment is the combination, in a single statement, of ++a variable or attribute annotation and an optional assignment ++statement: ++ ++ **annotated_assignment_stmt**: "augtarget" ":" "expression" ++ ["=" ("starred_expression" | "yield_expression")] ++ ++The difference from normal Assignment statements is that only a single ++target is allowed. ++ ++The assignment target is considered “simple†if it consists of a ++single name that is not enclosed in parentheses. For simple assignment ++targets, if in class or module scope, the annotations are gathered in ++a lazily evaluated annotation scope. The annotations can be evaluated ++using the "__annotations__" attribute of a class or module, or using ++the facilities in the "annotationlib" module. ++ ++If the assignment target is not simple (an attribute, subscript node, ++or parenthesized name), the annotation is never evaluated. ++ ++If a name is annotated in a function scope, then this name is local ++for that scope. Annotations are never evaluated and stored in function ++scopes. ++ ++If the right hand side is present, an annotated assignment performs ++the actual assignment as if there was no annotation present. If the ++right hand side is not present for an expression target, then the ++interpreter evaluates the target except for the last "__setitem__()" ++or "__setattr__()" call. ++ ++See also: ++ ++ **PEP 526** - Syntax for Variable Annotations ++ The proposal that added syntax for annotating the types of ++ variables (including class variables and instance variables), ++ instead of expressing them through comments. ++ ++ **PEP 484** - Type hints ++ The proposal that added the "typing" module to provide a standard ++ syntax for type annotations that can be used in static analysis ++ tools and IDEs. ++ ++Changed in version 3.8: Now annotated assignments allow the same ++expressions in the right hand side as regular assignments. Previously, ++some expressions (like un-parenthesized tuple expressions) caused a ++syntax error. ++ ++Changed in version 3.14: Annotations are now lazily evaluated in a ++separate annotation scope. If the assignment target is not simple, ++annotations are never evaluated. ++''', ++ 'assignment-expressions': r'''Assignment expressions ++********************** ++ ++ **assignment_expression**: ["identifier" ":="] "expression" ++ ++An assignment expression (sometimes also called a “named expression†++or “walrusâ€) assigns an "expression" to an "identifier", while also ++returning the value of the "expression". ++ ++One common use case is when handling matched regular expressions: ++ ++ if matching := pattern.search(data): ++ do_something(matching) ++ ++Or, when processing a file stream in chunks: ++ ++ while chunk := file.read(9000): ++ process(chunk) ++ ++Assignment expressions must be surrounded by parentheses when used as ++expression statements and when used as sub-expressions in slicing, ++conditional, lambda, keyword-argument, and comprehension-if ++expressions and in "assert", "with", and "assignment" statements. In ++all other places where they can be used, parentheses are not required, ++including in "if" and "while" statements. ++ ++Added in version 3.8: See **PEP 572** for more details about ++assignment expressions. ++''', ++ 'async': r'''Coroutines ++********** ++ ++Added in version 3.5. ++ ++ ++Coroutine function definition ++============================= ++ ++ **async_funcdef**: ["decorators"] "async" "def" "funcname" "(" ["parameter_list"] ")" ++ ["->" "expression"] ":" "suite" ++ ++Execution of Python coroutines can be suspended and resumed at many ++points (see *coroutine*). "await" expressions, "async for" and "async ++with" can only be used in the body of a coroutine function. ++ ++Functions defined with "async def" syntax are always coroutine ++functions, even if they do not contain "await" or "async" keywords. ++ ++It is a "SyntaxError" to use a "yield from" expression inside the body ++of a coroutine function. ++ ++An example of a coroutine function: ++ ++ async def func(param1, param2): ++ do_stuff() ++ await some_coroutine() ++ ++Changed in version 3.7: "await" and "async" are now keywords; ++previously they were only treated as such inside the body of a ++coroutine function. ++ ++ ++The "async for" statement ++========================= ++ ++ **async_for_stmt**: "async" "for_stmt" ++ ++An *asynchronous iterable* provides an "__aiter__" method that ++directly returns an *asynchronous iterator*, which can call ++asynchronous code in its "__anext__" method. ++ ++The "async for" statement allows convenient iteration over ++asynchronous iterables. ++ ++The following code: ++ ++ async for TARGET in ITER: ++ SUITE ++ else: ++ SUITE2 ++ ++Is semantically equivalent to: ++ ++ iter = (ITER) ++ iter = type(iter).__aiter__(iter) ++ running = True ++ ++ while running: ++ try: ++ TARGET = await type(iter).__anext__(iter) ++ except StopAsyncIteration: ++ running = False ++ else: ++ SUITE ++ else: ++ SUITE2 ++ ++See also "__aiter__()" and "__anext__()" for details. ++ ++It is a "SyntaxError" to use an "async for" statement outside the body ++of a coroutine function. ++ ++ ++The "async with" statement ++========================== ++ ++ **async_with_stmt**: "async" "with_stmt" ++ ++An *asynchronous context manager* is a *context manager* that is able ++to suspend execution in its *enter* and *exit* methods. ++ ++The following code: ++ ++ async with EXPRESSION as TARGET: ++ SUITE ++ ++is semantically equivalent to: ++ ++ manager = (EXPRESSION) ++ aenter = type(manager).__aenter__ ++ aexit = type(manager).__aexit__ ++ value = await aenter(manager) ++ hit_except = False ++ ++ try: ++ TARGET = value ++ SUITE ++ except: ++ hit_except = True ++ if not await aexit(manager, *sys.exc_info()): ++ raise ++ finally: ++ if not hit_except: ++ await aexit(manager, None, None, None) ++ ++See also "__aenter__()" and "__aexit__()" for details. ++ ++It is a "SyntaxError" to use an "async with" statement outside the ++body of a coroutine function. ++ ++See also: ++ ++ **PEP 492** - Coroutines with async and await syntax ++ The proposal that made coroutines a proper standalone concept in ++ Python, and added supporting syntax. ++''', ++ 'atom-identifiers': r'''Identifiers (Names) ++******************* ++ ++An identifier occurring as an atom is a name. See section Identifiers ++and keywords for lexical definition and section Naming and binding for ++documentation of naming and binding. ++ ++When the name is bound to an object, evaluation of the atom yields ++that object. When a name is not bound, an attempt to evaluate it ++raises a "NameError" exception. ++ ++ ++Private name mangling ++===================== ++ ++When an identifier that textually occurs in a class definition begins ++with two or more underscore characters and does not end in two or more ++underscores, it is considered a *private name* of that class. ++ ++See also: The class specifications. ++ ++More precisely, private names are transformed to a longer form before ++code is generated for them. If the transformed name is longer than ++255 characters, implementation-defined truncation may happen. ++ ++The transformation is independent of the syntactical context in which ++the identifier is used but only the following private identifiers are ++mangled: ++ ++* Any name used as the name of a variable that is assigned or read or ++ any name of an attribute being accessed. ++ ++ The "__name__" attribute of nested functions, classes, and type ++ aliases is however not mangled. ++ ++* The name of imported modules, e.g., "__spam" in "import __spam". If ++ the module is part of a package (i.e., its name contains a dot), the ++ name is *not* mangled, e.g., the "__foo" in "import __foo.bar" is ++ not mangled. ++ ++* The name of an imported member, e.g., "__f" in "from spam import ++ __f". ++ ++The transformation rule is defined as follows: ++ ++* The class name, with leading underscores removed and a single ++ leading underscore inserted, is inserted in front of the identifier, ++ e.g., the identifier "__spam" occurring in a class named "Foo", ++ "_Foo" or "__Foo" is transformed to "_Foo__spam". ++ ++* If the class name consists only of underscores, the transformation ++ is the identity, e.g., the identifier "__spam" occurring in a class ++ named "_" or "__" is left as is. ++''', ++ 'atom-literals': r'''Literals ++******** ++ ++Python supports string and bytes literals and various numeric ++literals: ++ ++ **literal**: "stringliteral" | "bytesliteral" ++ | "integer" | "floatnumber" | "imagnumber" ++ ++Evaluation of a literal yields an object of the given type (string, ++bytes, integer, floating-point number, complex number) with the given ++value. The value may be approximated in the case of floating-point ++and imaginary (complex) literals. See section Literals for details. ++ ++All literals correspond to immutable data types, and hence the ++object’s identity is less important than its value. Multiple ++evaluations of literals with the same value (either the same ++occurrence in the program text or a different occurrence) may obtain ++the same object or a different object with the same value. ++''', ++ 'attribute-access': r'''Customizing attribute access ++**************************** ++ ++The following methods can be defined to customize the meaning of ++attribute access (use of, assignment to, or deletion of "x.name") for ++class instances. ++ ++object.__getattr__(self, name) ++ ++ Called when the default attribute access fails with an ++ "AttributeError" (either "__getattribute__()" raises an ++ "AttributeError" because *name* is not an instance attribute or an ++ attribute in the class tree for "self"; or "__get__()" of a *name* ++ property raises "AttributeError"). This method should either ++ return the (computed) attribute value or raise an "AttributeError" ++ exception. The "object" class itself does not provide this method. ++ ++ Note that if the attribute is found through the normal mechanism, ++ "__getattr__()" is not called. (This is an intentional asymmetry ++ between "__getattr__()" and "__setattr__()".) This is done both for ++ efficiency reasons and because otherwise "__getattr__()" would have ++ no way to access other attributes of the instance. Note that at ++ least for instance variables, you can take total control by not ++ inserting any values in the instance attribute dictionary (but ++ instead inserting them in another object). See the ++ "__getattribute__()" method below for a way to actually get total ++ control over attribute access. ++ ++object.__getattribute__(self, name) ++ ++ Called unconditionally to implement attribute accesses for ++ instances of the class. If the class also defines "__getattr__()", ++ the latter will not be called unless "__getattribute__()" either ++ calls it explicitly or raises an "AttributeError". This method ++ should return the (computed) attribute value or raise an ++ "AttributeError" exception. In order to avoid infinite recursion in ++ this method, its implementation should always call the base class ++ method with the same name to access any attributes it needs, for ++ example, "object.__getattribute__(self, name)". ++ ++ Note: ++ ++ This method may still be bypassed when looking up special methods ++ as the result of implicit invocation via language syntax or ++ built-in functions. See Special method lookup. ++ ++ For certain sensitive attribute accesses, raises an auditing event ++ "object.__getattr__" with arguments "obj" and "name". ++ ++object.__setattr__(self, name, value) ++ ++ Called when an attribute assignment is attempted. This is called ++ instead of the normal mechanism (i.e. store the value in the ++ instance dictionary). *name* is the attribute name, *value* is the ++ value to be assigned to it. ++ ++ If "__setattr__()" wants to assign to an instance attribute, it ++ should call the base class method with the same name, for example, ++ "object.__setattr__(self, name, value)". ++ ++ For certain sensitive attribute assignments, raises an auditing ++ event "object.__setattr__" with arguments "obj", "name", "value". ++ ++object.__delattr__(self, name) ++ ++ Like "__setattr__()" but for attribute deletion instead of ++ assignment. This should only be implemented if "del obj.name" is ++ meaningful for the object. ++ ++ For certain sensitive attribute deletions, raises an auditing event ++ "object.__delattr__" with arguments "obj" and "name". ++ ++object.__dir__(self) ++ ++ Called when "dir()" is called on the object. An iterable must be ++ returned. "dir()" converts the returned iterable to a list and ++ sorts it. ++ ++ ++Customizing module attribute access ++=================================== ++ ++Special names "__getattr__" and "__dir__" can be also used to ++customize access to module attributes. The "__getattr__" function at ++the module level should accept one argument which is the name of an ++attribute and return the computed value or raise an "AttributeError". ++If an attribute is not found on a module object through the normal ++lookup, i.e. "object.__getattribute__()", then "__getattr__" is ++searched in the module "__dict__" before raising an "AttributeError". ++If found, it is called with the attribute name and the result is ++returned. ++ ++The "__dir__" function should accept no arguments, and return an ++iterable of strings that represents the names accessible on module. If ++present, this function overrides the standard "dir()" search on a ++module. ++ ++For a more fine grained customization of the module behavior (setting ++attributes, properties, etc.), one can set the "__class__" attribute ++of a module object to a subclass of "types.ModuleType". For example: ++ ++ import sys ++ from types import ModuleType ++ ++ class VerboseModule(ModuleType): ++ def __repr__(self): ++ return f'Verbose {self.__name__}' ++ ++ def __setattr__(self, attr, value): ++ print(f'Setting {attr}...') ++ super().__setattr__(attr, value) ++ ++ sys.modules[__name__].__class__ = VerboseModule ++ ++Note: ++ ++ Defining module "__getattr__" and setting module "__class__" only ++ affect lookups made using the attribute access syntax – directly ++ accessing the module globals (whether by code within the module, or ++ via a reference to the module’s globals dictionary) is unaffected. ++ ++Changed in version 3.5: "__class__" module attribute is now writable. ++ ++Added in version 3.7: "__getattr__" and "__dir__" module attributes. ++ ++See also: ++ ++ **PEP 562** - Module __getattr__ and __dir__ ++ Describes the "__getattr__" and "__dir__" functions on modules. ++ ++ ++Implementing Descriptors ++======================== ++ ++The following methods only apply when an instance of the class ++containing the method (a so-called *descriptor* class) appears in an ++*owner* class (the descriptor must be in either the owner’s class ++dictionary or in the class dictionary for one of its parents). In the ++examples below, “the attribute†refers to the attribute whose name is ++the key of the property in the owner class’ "__dict__". The "object" ++class itself does not implement any of these protocols. ++ ++object.__get__(self, instance, owner=None) ++ ++ Called to get the attribute of the owner class (class attribute ++ access) or of an instance of that class (instance attribute ++ access). The optional *owner* argument is the owner class, while ++ *instance* is the instance that the attribute was accessed through, ++ or "None" when the attribute is accessed through the *owner*. ++ ++ This method should return the computed attribute value or raise an ++ "AttributeError" exception. ++ ++ **PEP 252** specifies that "__get__()" is callable with one or two ++ arguments. Python’s own built-in descriptors support this ++ specification; however, it is likely that some third-party tools ++ have descriptors that require both arguments. Python’s own ++ "__getattribute__()" implementation always passes in both arguments ++ whether they are required or not. ++ ++object.__set__(self, instance, value) ++ ++ Called to set the attribute on an instance *instance* of the owner ++ class to a new value, *value*. ++ ++ Note, adding "__set__()" or "__delete__()" changes the kind of ++ descriptor to a “data descriptorâ€. See Invoking Descriptors for ++ more details. ++ ++object.__delete__(self, instance) ++ ++ Called to delete the attribute on an instance *instance* of the ++ owner class. ++ ++Instances of descriptors may also have the "__objclass__" attribute ++present: ++ ++object.__objclass__ ++ ++ The attribute "__objclass__" is interpreted by the "inspect" module ++ as specifying the class where this object was defined (setting this ++ appropriately can assist in runtime introspection of dynamic class ++ attributes). For callables, it may indicate that an instance of the ++ given type (or a subclass) is expected or required as the first ++ positional argument (for example, CPython sets this attribute for ++ unbound methods that are implemented in C). ++ ++ ++Invoking Descriptors ++==================== ++ ++In general, a descriptor is an object attribute with “binding ++behaviorâ€, one whose attribute access has been overridden by methods ++in the descriptor protocol: "__get__()", "__set__()", and ++"__delete__()". If any of those methods are defined for an object, it ++is said to be a descriptor. ++ ++The default behavior for attribute access is to get, set, or delete ++the attribute from an object’s dictionary. For instance, "a.x" has a ++lookup chain starting with "a.__dict__['x']", then ++"type(a).__dict__['x']", and continuing through the base classes of ++"type(a)" excluding metaclasses. ++ ++However, if the looked-up value is an object defining one of the ++descriptor methods, then Python may override the default behavior and ++invoke the descriptor method instead. Where this occurs in the ++precedence chain depends on which descriptor methods were defined and ++how they were called. ++ ++The starting point for descriptor invocation is a binding, "a.x". How ++the arguments are assembled depends on "a": ++ ++Direct Call ++ The simplest and least common call is when user code directly ++ invokes a descriptor method: "x.__get__(a)". ++ ++Instance Binding ++ If binding to an object instance, "a.x" is transformed into the ++ call: "type(a).__dict__['x'].__get__(a, type(a))". ++ ++Class Binding ++ If binding to a class, "A.x" is transformed into the call: ++ "A.__dict__['x'].__get__(None, A)". ++ ++Super Binding ++ A dotted lookup such as "super(A, a).x" searches ++ "a.__class__.__mro__" for a base class "B" following "A" and then ++ returns "B.__dict__['x'].__get__(a, A)". If not a descriptor, "x" ++ is returned unchanged. ++ ++For instance bindings, the precedence of descriptor invocation depends ++on which descriptor methods are defined. A descriptor can define any ++combination of "__get__()", "__set__()" and "__delete__()". If it ++does not define "__get__()", then accessing the attribute will return ++the descriptor object itself unless there is a value in the object’s ++instance dictionary. If the descriptor defines "__set__()" and/or ++"__delete__()", it is a data descriptor; if it defines neither, it is ++a non-data descriptor. Normally, data descriptors define both ++"__get__()" and "__set__()", while non-data descriptors have just the ++"__get__()" method. Data descriptors with "__get__()" and "__set__()" ++(and/or "__delete__()") defined always override a redefinition in an ++instance dictionary. In contrast, non-data descriptors can be ++overridden by instances. ++ ++Python methods (including those decorated with "@staticmethod" and ++"@classmethod") are implemented as non-data descriptors. Accordingly, ++instances can redefine and override methods. This allows individual ++instances to acquire behaviors that differ from other instances of the ++same class. ++ ++The "property()" function is implemented as a data descriptor. ++Accordingly, instances cannot override the behavior of a property. ++ ++ ++__slots__ ++========= ++ ++*__slots__* allow us to explicitly declare data members (like ++properties) and deny the creation of "__dict__" and *__weakref__* ++(unless explicitly declared in *__slots__* or available in a parent.) ++ ++The space saved over using "__dict__" can be significant. Attribute ++lookup speed can be significantly improved as well. ++ ++object.__slots__ ++ ++ This class variable can be assigned a string, iterable, or sequence ++ of strings with variable names used by instances. *__slots__* ++ reserves space for the declared variables and prevents the ++ automatic creation of "__dict__" and *__weakref__* for each ++ instance. ++ ++Notes on using *__slots__*: ++ ++* When inheriting from a class without *__slots__*, the "__dict__" and ++ *__weakref__* attribute of the instances will always be accessible. ++ ++* Without a "__dict__" variable, instances cannot be assigned new ++ variables not listed in the *__slots__* definition. Attempts to ++ assign to an unlisted variable name raises "AttributeError". If ++ dynamic assignment of new variables is desired, then add ++ "'__dict__'" to the sequence of strings in the *__slots__* ++ declaration. ++ ++* Without a *__weakref__* variable for each instance, classes defining ++ *__slots__* do not support "weak references" to its instances. If ++ weak reference support is needed, then add "'__weakref__'" to the ++ sequence of strings in the *__slots__* declaration. ++ ++* *__slots__* are implemented at the class level by creating ++ descriptors for each variable name. As a result, class attributes ++ cannot be used to set default values for instance variables defined ++ by *__slots__*; otherwise, the class attribute would overwrite the ++ descriptor assignment. ++ ++* The action of a *__slots__* declaration is not limited to the class ++ where it is defined. *__slots__* declared in parents are available ++ in child classes. However, instances of a child subclass will get a ++ "__dict__" and *__weakref__* unless the subclass also defines ++ *__slots__* (which should only contain names of any *additional* ++ slots). ++ ++* If a class defines a slot also defined in a base class, the instance ++ variable defined by the base class slot is inaccessible (except by ++ retrieving its descriptor directly from the base class). This ++ renders the meaning of the program undefined. In the future, a ++ check may be added to prevent this. ++ ++* "TypeError" will be raised if nonempty *__slots__* are defined for a ++ class derived from a ""variable-length" built-in type" such as ++ "int", "bytes", and "tuple". ++ ++* Any non-string *iterable* may be assigned to *__slots__*. ++ ++* If a "dictionary" is used to assign *__slots__*, the dictionary keys ++ will be used as the slot names. The values of the dictionary can be ++ used to provide per-attribute docstrings that will be recognised by ++ "inspect.getdoc()" and displayed in the output of "help()". ++ ++* "__class__" assignment works only if both classes have the same ++ *__slots__*. ++ ++* Multiple inheritance with multiple slotted parent classes can be ++ used, but only one parent is allowed to have attributes created by ++ slots (the other bases must have empty slot layouts) - violations ++ raise "TypeError". ++ ++* If an *iterator* is used for *__slots__* then a *descriptor* is ++ created for each of the iterator’s values. However, the *__slots__* ++ attribute will be an empty iterator. ++''', ++ 'attribute-references': r'''Attribute references ++******************** ++ ++An attribute reference is a primary followed by a period and a name: ++ ++ **attributeref**: "primary" "." "identifier" ++ ++The primary must evaluate to an object of a type that supports ++attribute references, which most objects do. This object is then ++asked to produce the attribute whose name is the identifier. The type ++and value produced is determined by the object. Multiple evaluations ++of the same attribute reference may yield different objects. ++ ++This production can be customized by overriding the ++"__getattribute__()" method or the "__getattr__()" method. The ++"__getattribute__()" method is called first and either returns a value ++or raises "AttributeError" if the attribute is not available. ++ ++If an "AttributeError" is raised and the object has a "__getattr__()" ++method, that method is called as a fallback. ++''', ++ 'augassign': r'''Augmented assignment statements ++******************************* ++ ++Augmented assignment is the combination, in a single statement, of a ++binary operation and an assignment statement: ++ ++ **augmented_assignment_stmt**: "augtarget" "augop" ("expression_list" | "yield_expression") ++ **augtarget**: "identifier" | "attributeref" | "subscription" | "slicing" ++ **augop**: "+=" | "-=" | "*=" | "@=" | "/=" | "//=" | "%=" | "**=" ++ | ">>=" | "<<=" | "&=" | "^=" | "|=" ++ ++(See section Primaries for the syntax definitions of the last three ++symbols.) ++ ++An augmented assignment evaluates the target (which, unlike normal ++assignment statements, cannot be an unpacking) and the expression ++list, performs the binary operation specific to the type of assignment ++on the two operands, and assigns the result to the original target. ++The target is only evaluated once. ++ ++An augmented assignment statement like "x += 1" can be rewritten as "x ++= x + 1" to achieve a similar, but not exactly equal effect. In the ++augmented version, "x" is only evaluated once. Also, when possible, ++the actual operation is performed *in-place*, meaning that rather than ++creating a new object and assigning that to the target, the old object ++is modified instead. ++ ++Unlike normal assignments, augmented assignments evaluate the left- ++hand side *before* evaluating the right-hand side. For example, "a[i] +++= f(x)" first looks-up "a[i]", then it evaluates "f(x)" and performs ++the addition, and lastly, it writes the result back to "a[i]". ++ ++With the exception of assigning to tuples and multiple targets in a ++single statement, the assignment done by augmented assignment ++statements is handled the same way as normal assignments. Similarly, ++with the exception of the possible *in-place* behavior, the binary ++operation performed by augmented assignment is the same as the normal ++binary operations. ++ ++For targets which are attribute references, the same caveat about ++class and instance attributes applies as for regular assignments. ++''', ++ 'await': r'''Await expression ++**************** ++ ++Suspend the execution of *coroutine* on an *awaitable* object. Can ++only be used inside a *coroutine function*. ++ ++ **await_expr**: "await" "primary" ++ ++Added in version 3.5. ++''', ++ 'binary': r'''Binary arithmetic operations ++**************************** ++ ++The binary arithmetic operations have the conventional priority ++levels. Note that some of these operations also apply to certain non- ++numeric types. Apart from the power operator, there are only two ++levels, one for multiplicative operators and one for additive ++operators: ++ ++ **m_expr**: "u_expr" | "m_expr" "*" "u_expr" | "m_expr" "@" "m_expr" | ++ "m_expr" "//" "u_expr" | "m_expr" "/" "u_expr" | ++ "m_expr" "%" "u_expr" ++ **a_expr**: "m_expr" | "a_expr" "+" "m_expr" | "a_expr" "-" "m_expr" ++ ++The "*" (multiplication) operator yields the product of its arguments. ++The arguments must either both be numbers, or one argument must be an ++integer and the other must be a sequence. In the former case, the ++numbers are converted to a common real type and then multiplied ++together. In the latter case, sequence repetition is performed; a ++negative repetition factor yields an empty sequence. ++ ++This operation can be customized using the special "__mul__()" and ++"__rmul__()" methods. ++ ++Changed in version 3.14: If only one operand is a complex number, the ++other operand is converted to a floating-point number. ++ ++The "@" (at) operator is intended to be used for matrix ++multiplication. No builtin Python types implement this operator. ++ ++This operation can be customized using the special "__matmul__()" and ++"__rmatmul__()" methods. ++ ++Added in version 3.5. ++ ++The "/" (division) and "//" (floor division) operators yield the ++quotient of their arguments. The numeric arguments are first ++converted to a common type. Division of integers yields a float, while ++floor division of integers results in an integer; the result is that ++of mathematical division with the ‘floor’ function applied to the ++result. Division by zero raises the "ZeroDivisionError" exception. ++ ++The division operation can be customized using the special ++"__truediv__()" and "__rtruediv__()" methods. The floor division ++operation can be customized using the special "__floordiv__()" and ++"__rfloordiv__()" methods. ++ ++The "%" (modulo) operator yields the remainder from the division of ++the first argument by the second. The numeric arguments are first ++converted to a common type. A zero right argument raises the ++"ZeroDivisionError" exception. The arguments may be floating-point ++numbers, e.g., "3.14%0.7" equals "0.34" (since "3.14" equals "4*0.7 + ++0.34".) The modulo operator always yields a result with the same sign ++as its second operand (or zero); the absolute value of the result is ++strictly smaller than the absolute value of the second operand [1]. ++ ++The floor division and modulo operators are connected by the following ++identity: "x == (x//y)*y + (x%y)". Floor division and modulo are also ++connected with the built-in function "divmod()": "divmod(x, y) == ++(x//y, x%y)". [2]. ++ ++In addition to performing the modulo operation on numbers, the "%" ++operator is also overloaded by string objects to perform old-style ++string formatting (also known as interpolation). The syntax for ++string formatting is described in the Python Library Reference, ++section printf-style String Formatting. ++ ++The *modulo* operation can be customized using the special "__mod__()" ++and "__rmod__()" methods. ++ ++The floor division operator, the modulo operator, and the "divmod()" ++function are not defined for complex numbers. Instead, convert to a ++floating-point number using the "abs()" function if appropriate. ++ ++The "+" (addition) operator yields the sum of its arguments. The ++arguments must either both be numbers or both be sequences of the same ++type. In the former case, the numbers are converted to a common real ++type and then added together. In the latter case, the sequences are ++concatenated. ++ ++This operation can be customized using the special "__add__()" and ++"__radd__()" methods. ++ ++Changed in version 3.14: If only one operand is a complex number, the ++other operand is converted to a floating-point number. ++ ++The "-" (subtraction) operator yields the difference of its arguments. ++The numeric arguments are first converted to a common real type. ++ ++This operation can be customized using the special "__sub__()" and ++"__rsub__()" methods. ++ ++Changed in version 3.14: If only one operand is a complex number, the ++other operand is converted to a floating-point number. ++''', ++ 'bitwise': r'''Binary bitwise operations ++************************* ++ ++Each of the three bitwise operations has a different priority level: ++ ++ **and_expr**: "shift_expr" | "and_expr" "&" "shift_expr" ++ **xor_expr**: "and_expr" | "xor_expr" "^" "and_expr" ++ **or_expr**: "xor_expr" | "or_expr" "|" "xor_expr" ++ ++The "&" operator yields the bitwise AND of its arguments, which must ++be integers or one of them must be a custom object overriding ++"__and__()" or "__rand__()" special methods. ++ ++The "^" operator yields the bitwise XOR (exclusive OR) of its ++arguments, which must be integers or one of them must be a custom ++object overriding "__xor__()" or "__rxor__()" special methods. ++ ++The "|" operator yields the bitwise (inclusive) OR of its arguments, ++which must be integers or one of them must be a custom object ++overriding "__or__()" or "__ror__()" special methods. ++''', ++ 'bltin-code-objects': r'''Code Objects ++************ ++ ++Code objects are used by the implementation to represent “pseudo- ++compiled†executable Python code such as a function body. They differ ++from function objects because they don’t contain a reference to their ++global execution environment. Code objects are returned by the built- ++in "compile()" function and can be extracted from function objects ++through their "__code__" attribute. See also the "code" module. ++ ++Accessing "__code__" raises an auditing event "object.__getattr__" ++with arguments "obj" and ""__code__"". ++ ++A code object can be executed or evaluated by passing it (instead of a ++source string) to the "exec()" or "eval()" built-in functions. ++ ++See The standard type hierarchy for more information. ++''', ++ 'bltin-ellipsis-object': r'''The Ellipsis Object ++******************* ++ ++This object is commonly used by slicing (see Slicings). It supports ++no special operations. There is exactly one ellipsis object, named ++"Ellipsis" (a built-in name). "type(Ellipsis)()" produces the ++"Ellipsis" singleton. ++ ++It is written as "Ellipsis" or "...". ++''', ++ 'bltin-null-object': r'''The Null Object ++*************** ++ ++This object is returned by functions that don’t explicitly return a ++value. It supports no special operations. There is exactly one null ++object, named "None" (a built-in name). "type(None)()" produces the ++same singleton. ++ ++It is written as "None". ++''', ++ 'bltin-type-objects': r'''Type Objects ++************ ++ ++Type objects represent the various object types. An object’s type is ++accessed by the built-in function "type()". There are no special ++operations on types. The standard module "types" defines names for ++all standard built-in types. ++ ++Types are written like this: "". ++''', ++ 'booleans': r'''Boolean operations ++****************** ++ ++ **or_test**: "and_test" | "or_test" "or" "and_test" ++ **and_test**: "not_test" | "and_test" "and" "not_test" ++ **not_test**: "comparison" | "not" "not_test" ++ ++In the context of Boolean operations, and also when expressions are ++used by control flow statements, the following values are interpreted ++as false: "False", "None", numeric zero of all types, and empty ++strings and containers (including strings, tuples, lists, ++dictionaries, sets and frozensets). All other values are interpreted ++as true. User-defined objects can customize their truth value by ++providing a "__bool__()" method. ++ ++The operator "not" yields "True" if its argument is false, "False" ++otherwise. ++ ++The expression "x and y" first evaluates *x*; if *x* is false, its ++value is returned; otherwise, *y* is evaluated and the resulting value ++is returned. ++ ++The expression "x or y" first evaluates *x*; if *x* is true, its value ++is returned; otherwise, *y* is evaluated and the resulting value is ++returned. ++ ++Note that neither "and" nor "or" restrict the value and type they ++return to "False" and "True", but rather return the last evaluated ++argument. This is sometimes useful, e.g., if "s" is a string that ++should be replaced by a default value if it is empty, the expression ++"s or 'foo'" yields the desired value. Because "not" has to create a ++new value, it returns a boolean value regardless of the type of its ++argument (for example, "not 'foo'" produces "False" rather than "''".) ++''', ++ 'break': r'''The "break" statement ++********************* ++ ++ **break_stmt**: "break" ++ ++"break" may only occur syntactically nested in a "for" or "while" ++loop, but not nested in a function or class definition within that ++loop. ++ ++It terminates the nearest enclosing loop, skipping the optional "else" ++clause if the loop has one. ++ ++If a "for" loop is terminated by "break", the loop control target ++keeps its current value. ++ ++When "break" passes control out of a "try" statement with a "finally" ++clause, that "finally" clause is executed before really leaving the ++loop. ++''', ++ 'callable-types': r'''Emulating callable objects ++************************** ++ ++object.__call__(self[, args...]) ++ ++ Called when the instance is “called†as a function; if this method ++ is defined, "x(arg1, arg2, ...)" roughly translates to ++ "type(x).__call__(x, arg1, ...)". The "object" class itself does ++ not provide this method. ++''', ++ 'calls': r'''Calls ++***** ++ ++A call calls a callable object (e.g., a *function*) with a possibly ++empty series of *arguments*: ++ ++ **call**: "primary" "(" ["argument_list" [","] | "comprehension"] ")" ++ **argument_list**: "positional_arguments" ["," "starred_and_keywords"] ++ ["," "keywords_arguments"] ++ | "starred_and_keywords" ["," "keywords_arguments"] ++ | "keywords_arguments" ++ **positional_arguments**: positional_item ("," positional_item)* ++ **positional_item**: "assignment_expression" | "*" "expression" ++ **starred_and_keywords**: ("*" "expression" | "keyword_item") ++ ("," "*" "expression" | "," "keyword_item")* ++ **keywords_arguments**: ("keyword_item" | "**" "expression") ++ ("," "keyword_item" | "," "**" "expression")* ++ **keyword_item**: "identifier" "=" "expression" ++ ++An optional trailing comma may be present after the positional and ++keyword arguments but does not affect the semantics. ++ ++The primary must evaluate to a callable object (user-defined ++functions, built-in functions, methods of built-in objects, class ++objects, methods of class instances, and all objects having a ++"__call__()" method are callable). All argument expressions are ++evaluated before the call is attempted. Please refer to section ++Function definitions for the syntax of formal *parameter* lists. ++ ++If keyword arguments are present, they are first converted to ++positional arguments, as follows. First, a list of unfilled slots is ++created for the formal parameters. If there are N positional ++arguments, they are placed in the first N slots. Next, for each ++keyword argument, the identifier is used to determine the ++corresponding slot (if the identifier is the same as the first formal ++parameter name, the first slot is used, and so on). If the slot is ++already filled, a "TypeError" exception is raised. Otherwise, the ++argument is placed in the slot, filling it (even if the expression is ++"None", it fills the slot). When all arguments have been processed, ++the slots that are still unfilled are filled with the corresponding ++default value from the function definition. (Default values are ++calculated, once, when the function is defined; thus, a mutable object ++such as a list or dictionary used as default value will be shared by ++all calls that don’t specify an argument value for the corresponding ++slot; this should usually be avoided.) If there are any unfilled ++slots for which no default value is specified, a "TypeError" exception ++is raised. Otherwise, the list of filled slots is used as the ++argument list for the call. ++ ++**CPython implementation detail:** An implementation may provide ++built-in functions whose positional parameters do not have names, even ++if they are ‘named’ for the purpose of documentation, and which ++therefore cannot be supplied by keyword. In CPython, this is the case ++for functions implemented in C that use "PyArg_ParseTuple()" to parse ++their arguments. ++ ++If there are more positional arguments than there are formal parameter ++slots, a "TypeError" exception is raised, unless a formal parameter ++using the syntax "*identifier" is present; in this case, that formal ++parameter receives a tuple containing the excess positional arguments ++(or an empty tuple if there were no excess positional arguments). ++ ++If any keyword argument does not correspond to a formal parameter ++name, a "TypeError" exception is raised, unless a formal parameter ++using the syntax "**identifier" is present; in this case, that formal ++parameter receives a dictionary containing the excess keyword ++arguments (using the keywords as keys and the argument values as ++corresponding values), or a (new) empty dictionary if there were no ++excess keyword arguments. ++ ++If the syntax "*expression" appears in the function call, "expression" ++must evaluate to an *iterable*. Elements from these iterables are ++treated as if they were additional positional arguments. For the call ++"f(x1, x2, *y, x3, x4)", if *y* evaluates to a sequence *y1*, …, *yM*, ++this is equivalent to a call with M+4 positional arguments *x1*, *x2*, ++*y1*, …, *yM*, *x3*, *x4*. ++ ++A consequence of this is that although the "*expression" syntax may ++appear *after* explicit keyword arguments, it is processed *before* ++the keyword arguments (and any "**expression" arguments – see below). ++So: ++ ++ >>> def f(a, b): ++ ... print(a, b) ++ ... ++ >>> f(b=1, *(2,)) ++ 2 1 ++ >>> f(a=1, *(2,)) ++ Traceback (most recent call last): ++ File "", line 1, in ++ TypeError: f() got multiple values for keyword argument 'a' ++ >>> f(1, *(2,)) ++ 1 2 ++ ++It is unusual for both keyword arguments and the "*expression" syntax ++to be used in the same call, so in practice this confusion does not ++often arise. ++ ++If the syntax "**expression" appears in the function call, ++"expression" must evaluate to a *mapping*, the contents of which are ++treated as additional keyword arguments. If a parameter matching a key ++has already been given a value (by an explicit keyword argument, or ++from another unpacking), a "TypeError" exception is raised. ++ ++When "**expression" is used, each key in this mapping must be a ++string. Each value from the mapping is assigned to the first formal ++parameter eligible for keyword assignment whose name is equal to the ++key. A key need not be a Python identifier (e.g. ""max-temp °F"" is ++acceptable, although it will not match any formal parameter that could ++be declared). If there is no match to a formal parameter the key-value ++pair is collected by the "**" parameter, if there is one, or if there ++is not, a "TypeError" exception is raised. ++ ++Formal parameters using the syntax "*identifier" or "**identifier" ++cannot be used as positional argument slots or as keyword argument ++names. ++ ++Changed in version 3.5: Function calls accept any number of "*" and ++"**" unpackings, positional arguments may follow iterable unpackings ++("*"), and keyword arguments may follow dictionary unpackings ("**"). ++Originally proposed by **PEP 448**. ++ ++A call always returns some value, possibly "None", unless it raises an ++exception. How this value is computed depends on the type of the ++callable object. ++ ++If it is— ++ ++a user-defined function: ++ The code block for the function is executed, passing it the ++ argument list. The first thing the code block will do is bind the ++ formal parameters to the arguments; this is described in section ++ Function definitions. When the code block executes a "return" ++ statement, this specifies the return value of the function call. ++ If execution reaches the end of the code block without executing a ++ "return" statement, the return value is "None". ++ ++a built-in function or method: ++ The result is up to the interpreter; see Built-in Functions for the ++ descriptions of built-in functions and methods. ++ ++a class object: ++ A new instance of that class is returned. ++ ++a class instance method: ++ The corresponding user-defined function is called, with an argument ++ list that is one longer than the argument list of the call: the ++ instance becomes the first argument. ++ ++a class instance: ++ The class must define a "__call__()" method; the effect is then the ++ same as if that method was called. ++''', ++ 'class': r'''Class definitions ++***************** ++ ++A class definition defines a class object (see section The standard ++type hierarchy): ++ ++ **classdef**: ["decorators"] "class" "classname" ["type_params"] ["inheritance"] ":" "suite" ++ **inheritance**: "(" ["argument_list"] ")" ++ **classname**: "identifier" ++ ++A class definition is an executable statement. The inheritance list ++usually gives a list of base classes (see Metaclasses for more ++advanced uses), so each item in the list should evaluate to a class ++object which allows subclassing. Classes without an inheritance list ++inherit, by default, from the base class "object"; hence, ++ ++ class Foo: ++ pass ++ ++is equivalent to ++ ++ class Foo(object): ++ pass ++ ++The class’s suite is then executed in a new execution frame (see ++Naming and binding), using a newly created local namespace and the ++original global namespace. (Usually, the suite contains mostly ++function definitions.) When the class’s suite finishes execution, its ++execution frame is discarded but its local namespace is saved. [5] A ++class object is then created using the inheritance list for the base ++classes and the saved local namespace for the attribute dictionary. ++The class name is bound to this class object in the original local ++namespace. ++ ++The order in which attributes are defined in the class body is ++preserved in the new class’s "__dict__". Note that this is reliable ++only right after the class is created and only for classes that were ++defined using the definition syntax. ++ ++Class creation can be customized heavily using metaclasses. ++ ++Classes can also be decorated: just like when decorating functions, ++ ++ @f1(arg) ++ @f2 ++ class Foo: pass ++ ++is roughly equivalent to ++ ++ class Foo: pass ++ Foo = f1(arg)(f2(Foo)) ++ ++The evaluation rules for the decorator expressions are the same as for ++function decorators. The result is then bound to the class name. ++ ++Changed in version 3.9: Classes may be decorated with any valid ++"assignment_expression". Previously, the grammar was much more ++restrictive; see **PEP 614** for details. ++ ++A list of type parameters may be given in square brackets immediately ++after the class’s name. This indicates to static type checkers that ++the class is generic. At runtime, the type parameters can be retrieved ++from the class’s "__type_params__" attribute. See Generic classes for ++more. ++ ++Changed in version 3.12: Type parameter lists are new in Python 3.12. ++ ++**Programmer’s note:** Variables defined in the class definition are ++class attributes; they are shared by instances. Instance attributes ++can be set in a method with "self.name = value". Both class and ++instance attributes are accessible through the notation “"self.name"â€, ++and an instance attribute hides a class attribute with the same name ++when accessed in this way. Class attributes can be used as defaults ++for instance attributes, but using mutable values there can lead to ++unexpected results. Descriptors can be used to create instance ++variables with different implementation details. ++ ++See also: ++ ++ **PEP 3115** - Metaclasses in Python 3000 ++ The proposal that changed the declaration of metaclasses to the ++ current syntax, and the semantics for how classes with ++ metaclasses are constructed. ++ ++ **PEP 3129** - Class Decorators ++ The proposal that added class decorators. Function and method ++ decorators were introduced in **PEP 318**. ++''', ++ 'comparisons': r'''Comparisons ++*********** ++ ++Unlike C, all comparison operations in Python have the same priority, ++which is lower than that of any arithmetic, shifting or bitwise ++operation. Also unlike C, expressions like "a < b < c" have the ++interpretation that is conventional in mathematics: ++ ++ **comparison**: "or_expr" ("comp_operator" "or_expr")* ++ **comp_operator**: "<" | ">" | "==" | ">=" | "<=" | "!=" ++ | "is" ["not"] | ["not"] "in" ++ ++Comparisons yield boolean values: "True" or "False". Custom *rich ++comparison methods* may return non-boolean values. In this case Python ++will call "bool()" on such value in boolean contexts. ++ ++Comparisons can be chained arbitrarily, e.g., "x < y <= z" is ++equivalent to "x < y and y <= z", except that "y" is evaluated only ++once (but in both cases "z" is not evaluated at all when "x < y" is ++found to be false). ++ ++Formally, if *a*, *b*, *c*, …, *y*, *z* are expressions and *op1*, ++*op2*, …, *opN* are comparison operators, then "a op1 b op2 c ... y ++opN z" is equivalent to "a op1 b and b op2 c and ... y opN z", except ++that each expression is evaluated at most once. ++ ++Note that "a op1 b op2 c" doesn’t imply any kind of comparison between ++*a* and *c*, so that, e.g., "x < y > z" is perfectly legal (though ++perhaps not pretty). ++ ++ ++Value comparisons ++================= ++ ++The operators "<", ">", "==", ">=", "<=", and "!=" compare the values ++of two objects. The objects do not need to have the same type. ++ ++Chapter Objects, values and types states that objects have a value (in ++addition to type and identity). The value of an object is a rather ++abstract notion in Python: For example, there is no canonical access ++method for an object’s value. Also, there is no requirement that the ++value of an object should be constructed in a particular way, e.g. ++comprised of all its data attributes. Comparison operators implement a ++particular notion of what the value of an object is. One can think of ++them as defining the value of an object indirectly, by means of their ++comparison implementation. ++ ++Because all types are (direct or indirect) subtypes of "object", they ++inherit the default comparison behavior from "object". Types can ++customize their comparison behavior by implementing *rich comparison ++methods* like "__lt__()", described in Basic customization. ++ ++The default behavior for equality comparison ("==" and "!=") is based ++on the identity of the objects. Hence, equality comparison of ++instances with the same identity results in equality, and equality ++comparison of instances with different identities results in ++inequality. A motivation for this default behavior is the desire that ++all objects should be reflexive (i.e. "x is y" implies "x == y"). ++ ++A default order comparison ("<", ">", "<=", and ">=") is not provided; ++an attempt raises "TypeError". A motivation for this default behavior ++is the lack of a similar invariant as for equality. ++ ++The behavior of the default equality comparison, that instances with ++different identities are always unequal, may be in contrast to what ++types will need that have a sensible definition of object value and ++value-based equality. Such types will need to customize their ++comparison behavior, and in fact, a number of built-in types have done ++that. ++ ++The following list describes the comparison behavior of the most ++important built-in types. ++ ++* Numbers of built-in numeric types (Numeric Types — int, float, ++ complex) and of the standard library types "fractions.Fraction" and ++ "decimal.Decimal" can be compared within and across their types, ++ with the restriction that complex numbers do not support order ++ comparison. Within the limits of the types involved, they compare ++ mathematically (algorithmically) correct without loss of precision. ++ ++ The not-a-number values "float('NaN')" and "decimal.Decimal('NaN')" ++ are special. Any ordered comparison of a number to a not-a-number ++ value is false. A counter-intuitive implication is that not-a-number ++ values are not equal to themselves. For example, if "x = ++ float('NaN')", "3 < x", "x < 3" and "x == x" are all false, while "x ++ != x" is true. This behavior is compliant with IEEE 754. ++ ++* "None" and "NotImplemented" are singletons. **PEP 8** advises that ++ comparisons for singletons should always be done with "is" or "is ++ not", never the equality operators. ++ ++* Binary sequences (instances of "bytes" or "bytearray") can be ++ compared within and across their types. They compare ++ lexicographically using the numeric values of their elements. ++ ++* Strings (instances of "str") compare lexicographically using the ++ numerical Unicode code points (the result of the built-in function ++ "ord()") of their characters. [3] ++ ++ Strings and binary sequences cannot be directly compared. ++ ++* Sequences (instances of "tuple", "list", or "range") can be compared ++ only within each of their types, with the restriction that ranges do ++ not support order comparison. Equality comparison across these ++ types results in inequality, and ordering comparison across these ++ types raises "TypeError". ++ ++ Sequences compare lexicographically using comparison of ++ corresponding elements. The built-in containers typically assume ++ identical objects are equal to themselves. That lets them bypass ++ equality tests for identical objects to improve performance and to ++ maintain their internal invariants. ++ ++ Lexicographical comparison between built-in collections works as ++ follows: ++ ++ * For two collections to compare equal, they must be of the same ++ type, have the same length, and each pair of corresponding ++ elements must compare equal (for example, "[1,2] == (1,2)" is ++ false because the type is not the same). ++ ++ * Collections that support order comparison are ordered the same as ++ their first unequal elements (for example, "[1,2,x] <= [1,2,y]" ++ has the same value as "x <= y"). If a corresponding element does ++ not exist, the shorter collection is ordered first (for example, ++ "[1,2] < [1,2,3]" is true). ++ ++* Mappings (instances of "dict") compare equal if and only if they ++ have equal "(key, value)" pairs. Equality comparison of the keys and ++ values enforces reflexivity. ++ ++ Order comparisons ("<", ">", "<=", and ">=") raise "TypeError". ++ ++* Sets (instances of "set" or "frozenset") can be compared within and ++ across their types. ++ ++ They define order comparison operators to mean subset and superset ++ tests. Those relations do not define total orderings (for example, ++ the two sets "{1,2}" and "{2,3}" are not equal, nor subsets of one ++ another, nor supersets of one another). Accordingly, sets are not ++ appropriate arguments for functions which depend on total ordering ++ (for example, "min()", "max()", and "sorted()" produce undefined ++ results given a list of sets as inputs). ++ ++ Comparison of sets enforces reflexivity of its elements. ++ ++* Most other built-in types have no comparison methods implemented, so ++ they inherit the default comparison behavior. ++ ++User-defined classes that customize their comparison behavior should ++follow some consistency rules, if possible: ++ ++* Equality comparison should be reflexive. In other words, identical ++ objects should compare equal: ++ ++ "x is y" implies "x == y" ++ ++* Comparison should be symmetric. In other words, the following ++ expressions should have the same result: ++ ++ "x == y" and "y == x" ++ ++ "x != y" and "y != x" ++ ++ "x < y" and "y > x" ++ ++ "x <= y" and "y >= x" ++ ++* Comparison should be transitive. The following (non-exhaustive) ++ examples illustrate that: ++ ++ "x > y and y > z" implies "x > z" ++ ++ "x < y and y <= z" implies "x < z" ++ ++* Inverse comparison should result in the boolean negation. In other ++ words, the following expressions should have the same result: ++ ++ "x == y" and "not x != y" ++ ++ "x < y" and "not x >= y" (for total ordering) ++ ++ "x > y" and "not x <= y" (for total ordering) ++ ++ The last two expressions apply to totally ordered collections (e.g. ++ to sequences, but not to sets or mappings). See also the ++ "total_ordering()" decorator. ++ ++* The "hash()" result should be consistent with equality. Objects that ++ are equal should either have the same hash value, or be marked as ++ unhashable. ++ ++Python does not enforce these consistency rules. In fact, the ++not-a-number values are an example for not following these rules. ++ ++ ++Membership test operations ++========================== ++ ++The operators "in" and "not in" test for membership. "x in s" ++evaluates to "True" if *x* is a member of *s*, and "False" otherwise. ++"x not in s" returns the negation of "x in s". All built-in sequences ++and set types support this as well as dictionary, for which "in" tests ++whether the dictionary has a given key. For container types such as ++list, tuple, set, frozenset, dict, or collections.deque, the ++expression "x in y" is equivalent to "any(x is e or x == e for e in ++y)". ++ ++For the string and bytes types, "x in y" is "True" if and only if *x* ++is a substring of *y*. An equivalent test is "y.find(x) != -1". ++Empty strings are always considered to be a substring of any other ++string, so """ in "abc"" will return "True". ++ ++For user-defined classes which define the "__contains__()" method, "x ++in y" returns "True" if "y.__contains__(x)" returns a true value, and ++"False" otherwise. ++ ++For user-defined classes which do not define "__contains__()" but do ++define "__iter__()", "x in y" is "True" if some value "z", for which ++the expression "x is z or x == z" is true, is produced while iterating ++over "y". If an exception is raised during the iteration, it is as if ++"in" raised that exception. ++ ++Lastly, the old-style iteration protocol is tried: if a class defines ++"__getitem__()", "x in y" is "True" if and only if there is a non- ++negative integer index *i* such that "x is y[i] or x == y[i]", and no ++lower integer index raises the "IndexError" exception. (If any other ++exception is raised, it is as if "in" raised that exception). ++ ++The operator "not in" is defined to have the inverse truth value of ++"in". ++ ++ ++Identity comparisons ++==================== ++ ++The operators "is" and "is not" test for an object’s identity: "x is ++y" is true if and only if *x* and *y* are the same object. An ++Object’s identity is determined using the "id()" function. "x is not ++y" yields the inverse truth value. [4] ++''', ++ 'compound': r'''Compound statements ++******************* ++ ++Compound statements contain (groups of) other statements; they affect ++or control the execution of those other statements in some way. In ++general, compound statements span multiple lines, although in simple ++incarnations a whole compound statement may be contained in one line. ++ ++The "if", "while" and "for" statements implement traditional control ++flow constructs. "try" specifies exception handlers and/or cleanup ++code for a group of statements, while the "with" statement allows the ++execution of initialization and finalization code around a block of ++code. Function and class definitions are also syntactically compound ++statements. ++ ++A compound statement consists of one or more ‘clauses.’ A clause ++consists of a header and a ‘suite.’ The clause headers of a ++particular compound statement are all at the same indentation level. ++Each clause header begins with a uniquely identifying keyword and ends ++with a colon. A suite is a group of statements controlled by a ++clause. A suite can be one or more semicolon-separated simple ++statements on the same line as the header, following the header’s ++colon, or it can be one or more indented statements on subsequent ++lines. Only the latter form of a suite can contain nested compound ++statements; the following is illegal, mostly because it wouldn’t be ++clear to which "if" clause a following "else" clause would belong: ++ ++ if test1: if test2: print(x) ++ ++Also note that the semicolon binds tighter than the colon in this ++context, so that in the following example, either all or none of the ++"print()" calls are executed: ++ ++ if x < y < z: print(x); print(y); print(z) ++ ++Summarizing: ++ ++ **compound_stmt**: "if_stmt" ++ | "while_stmt" ++ | "for_stmt" ++ | "try_stmt" ++ | "with_stmt" ++ | "match_stmt" ++ | "funcdef" ++ | "classdef" ++ | "async_with_stmt" ++ | "async_for_stmt" ++ | "async_funcdef" ++ **suite**: "stmt_list" NEWLINE | NEWLINE INDENT "statement"+ DEDENT ++ **statement**: "stmt_list" NEWLINE | "compound_stmt" ++ **stmt_list**: "simple_stmt" (";" "simple_stmt")* [";"] ++ ++Note that statements always end in a "NEWLINE" possibly followed by a ++"DEDENT". Also note that optional continuation clauses always begin ++with a keyword that cannot start a statement, thus there are no ++ambiguities (the ‘dangling "else"’ problem is solved in Python by ++requiring nested "if" statements to be indented). ++ ++The formatting of the grammar rules in the following sections places ++each clause on a separate line for clarity. ++ ++ ++The "if" statement ++================== ++ ++The "if" statement is used for conditional execution: ++ ++ **if_stmt**: "if" "assignment_expression" ":" "suite" ++ ("elif" "assignment_expression" ":" "suite")* ++ ["else" ":" "suite"] ++ ++It selects exactly one of the suites by evaluating the expressions one ++by one until one is found to be true (see section Boolean operations ++for the definition of true and false); then that suite is executed ++(and no other part of the "if" statement is executed or evaluated). ++If all expressions are false, the suite of the "else" clause, if ++present, is executed. ++ ++ ++The "while" statement ++===================== ++ ++The "while" statement is used for repeated execution as long as an ++expression is true: ++ ++ **while_stmt**: "while" "assignment_expression" ":" "suite" ++ ["else" ":" "suite"] ++ ++This repeatedly tests the expression and, if it is true, executes the ++first suite; if the expression is false (which may be the first time ++it is tested) the suite of the "else" clause, if present, is executed ++and the loop terminates. ++ ++A "break" statement executed in the first suite terminates the loop ++without executing the "else" clause’s suite. A "continue" statement ++executed in the first suite skips the rest of the suite and goes back ++to testing the expression. ++ ++ ++The "for" statement ++=================== ++ ++The "for" statement is used to iterate over the elements of a sequence ++(such as a string, tuple or list) or other iterable object: ++ ++ **for_stmt**: "for" "target_list" "in" "starred_list" ":" "suite" ++ ["else" ":" "suite"] ++ ++The "starred_list" expression is evaluated once; it should yield an ++*iterable* object. An *iterator* is created for that iterable. The ++first item provided by the iterator is then assigned to the target ++list using the standard rules for assignments (see Assignment ++statements), and the suite is executed. This repeats for each item ++provided by the iterator. When the iterator is exhausted, the suite ++in the "else" clause, if present, is executed, and the loop ++terminates. ++ ++A "break" statement executed in the first suite terminates the loop ++without executing the "else" clause’s suite. A "continue" statement ++executed in the first suite skips the rest of the suite and continues ++with the next item, or with the "else" clause if there is no next ++item. ++ ++The for-loop makes assignments to the variables in the target list. ++This overwrites all previous assignments to those variables including ++those made in the suite of the for-loop: ++ ++ for i in range(10): ++ print(i) ++ i = 5 # this will not affect the for-loop ++ # because i will be overwritten with the next ++ # index in the range ++ ++Names in the target list are not deleted when the loop is finished, ++but if the sequence is empty, they will not have been assigned to at ++all by the loop. Hint: the built-in type "range()" represents ++immutable arithmetic sequences of integers. For instance, iterating ++"range(3)" successively yields 0, 1, and then 2. ++ ++Changed in version 3.11: Starred elements are now allowed in the ++expression list. ++ ++ ++The "try" statement ++=================== ++ ++The "try" statement specifies exception handlers and/or cleanup code ++for a group of statements: ++ ++ **try_stmt**: "try1_stmt" | "try2_stmt" | "try3_stmt" ++ **try1_stmt**: "try" ":" "suite" ++ ("except" ["expression" ["as" "identifier"]] ":" "suite")+ ++ ["else" ":" "suite"] ++ ["finally" ":" "suite"] ++ **try2_stmt**: "try" ":" "suite" ++ ("except" "*" "expression" ["as" "identifier"] ":" "suite")+ ++ ["else" ":" "suite"] ++ ["finally" ":" "suite"] ++ **try3_stmt**: "try" ":" "suite" ++ "finally" ":" "suite" ++ ++Additional information on exceptions can be found in section ++Exceptions, and information on using the "raise" statement to generate ++exceptions may be found in section The raise statement. ++ ++ ++"except" clause ++--------------- ++ ++The "except" clause(s) specify one or more exception handlers. When no ++exception occurs in the "try" clause, no exception handler is ++executed. When an exception occurs in the "try" suite, a search for an ++exception handler is started. This search inspects the "except" ++clauses in turn until one is found that matches the exception. An ++expression-less "except" clause, if present, must be last; it matches ++any exception. ++ ++For an "except" clause with an expression, the expression must ++evaluate to an exception type or a tuple of exception types. The ++raised exception matches an "except" clause whose expression evaluates ++to the class or a *non-virtual base class* of the exception object, or ++to a tuple that contains such a class. ++ ++If no "except" clause matches the exception, the search for an ++exception handler continues in the surrounding code and on the ++invocation stack. [1] ++ ++If the evaluation of an expression in the header of an "except" clause ++raises an exception, the original search for a handler is canceled and ++a search starts for the new exception in the surrounding code and on ++the call stack (it is treated as if the entire "try" statement raised ++the exception). ++ ++When a matching "except" clause is found, the exception is assigned to ++the target specified after the "as" keyword in that "except" clause, ++if present, and the "except" clause’s suite is executed. All "except" ++clauses must have an executable block. When the end of this block is ++reached, execution continues normally after the entire "try" ++statement. (This means that if two nested handlers exist for the same ++exception, and the exception occurs in the "try" clause of the inner ++handler, the outer handler will not handle the exception.) ++ ++When an exception has been assigned using "as target", it is cleared ++at the end of the "except" clause. This is as if ++ ++ except E as N: ++ foo ++ ++was translated to ++ ++ except E as N: ++ try: ++ foo ++ finally: ++ del N ++ ++This means the exception must be assigned to a different name to be ++able to refer to it after the "except" clause. Exceptions are cleared ++because with the traceback attached to them, they form a reference ++cycle with the stack frame, keeping all locals in that frame alive ++until the next garbage collection occurs. ++ ++Before an "except" clause’s suite is executed, the exception is stored ++in the "sys" module, where it can be accessed from within the body of ++the "except" clause by calling "sys.exception()". When leaving an ++exception handler, the exception stored in the "sys" module is reset ++to its previous value: ++ ++ >>> print(sys.exception()) ++ None ++ >>> try: ++ ... raise TypeError ++ ... except: ++ ... print(repr(sys.exception())) ++ ... try: ++ ... raise ValueError ++ ... except: ++ ... print(repr(sys.exception())) ++ ... print(repr(sys.exception())) ++ ... ++ TypeError() ++ ValueError() ++ TypeError() ++ >>> print(sys.exception()) ++ None ++ ++ ++"except*" clause ++---------------- ++ ++The "except*" clause(s) are used for handling "ExceptionGroup"s. The ++exception type for matching is interpreted as in the case of "except", ++but in the case of exception groups we can have partial matches when ++the type matches some of the exceptions in the group. This means that ++multiple "except*" clauses can execute, each handling part of the ++exception group. Each clause executes at most once and handles an ++exception group of all matching exceptions. Each exception in the ++group is handled by at most one "except*" clause, the first that ++matches it. ++ ++ >>> try: ++ ... raise ExceptionGroup("eg", ++ ... [ValueError(1), TypeError(2), OSError(3), OSError(4)]) ++ ... except* TypeError as e: ++ ... print(f'caught {type(e)} with nested {e.exceptions}') ++ ... except* OSError as e: ++ ... print(f'caught {type(e)} with nested {e.exceptions}') ++ ... ++ caught with nested (TypeError(2),) ++ caught with nested (OSError(3), OSError(4)) ++ + Exception Group Traceback (most recent call last): ++ | File "", line 2, in ++ | ExceptionGroup: eg ++ +-+---------------- 1 ---------------- ++ | ValueError: 1 ++ +------------------------------------ ++ ++Any remaining exceptions that were not handled by any "except*" clause ++are re-raised at the end, along with all exceptions that were raised ++from within the "except*" clauses. If this list contains more than one ++exception to reraise, they are combined into an exception group. ++ ++If the raised exception is not an exception group and its type matches ++one of the "except*" clauses, it is caught and wrapped by an exception ++group with an empty message string. ++ ++ >>> try: ++ ... raise BlockingIOError ++ ... except* BlockingIOError as e: ++ ... print(repr(e)) ++ ... ++ ExceptionGroup('', (BlockingIOError())) ++ ++An "except*" clause must have a matching expression; it cannot be ++"except*:". Furthermore, this expression cannot contain exception ++group types, because that would have ambiguous semantics. ++ ++It is not possible to mix "except" and "except*" in the same "try". ++"break", "continue" and "return" cannot appear in an "except*" clause. ++ ++ ++"else" clause ++------------- ++ ++The optional "else" clause is executed if the control flow leaves the ++"try" suite, no exception was raised, and no "return", "continue", or ++"break" statement was executed. Exceptions in the "else" clause are ++not handled by the preceding "except" clauses. ++ ++ ++"finally" clause ++---------------- ++ ++If "finally" is present, it specifies a ‘cleanup’ handler. The "try" ++clause is executed, including any "except" and "else" clauses. If an ++exception occurs in any of the clauses and is not handled, the ++exception is temporarily saved. The "finally" clause is executed. If ++there is a saved exception it is re-raised at the end of the "finally" ++clause. If the "finally" clause raises another exception, the saved ++exception is set as the context of the new exception. If the "finally" ++clause executes a "return", "break" or "continue" statement, the saved ++exception is discarded: ++ ++ >>> def f(): ++ ... try: ++ ... 1/0 ++ ... finally: ++ ... return 42 ++ ... ++ >>> f() ++ 42 ++ ++The exception information is not available to the program during ++execution of the "finally" clause. ++ ++When a "return", "break" or "continue" statement is executed in the ++"try" suite of a "try"…"finally" statement, the "finally" clause is ++also executed ‘on the way out.’ ++ ++The return value of a function is determined by the last "return" ++statement executed. Since the "finally" clause always executes, a ++"return" statement executed in the "finally" clause will always be the ++last one executed: ++ ++ >>> def foo(): ++ ... try: ++ ... return 'try' ++ ... finally: ++ ... return 'finally' ++ ... ++ >>> foo() ++ 'finally' ++ ++Changed in version 3.8: Prior to Python 3.8, a "continue" statement ++was illegal in the "finally" clause due to a problem with the ++implementation. ++ ++ ++The "with" statement ++==================== ++ ++The "with" statement is used to wrap the execution of a block with ++methods defined by a context manager (see section With Statement ++Context Managers). This allows common "try"…"except"…"finally" usage ++patterns to be encapsulated for convenient reuse. ++ ++ **with_stmt**: "with" ( "(" "with_stmt_contents" ","? ")" | "with_stmt_contents" ) ":" "suite" ++ **with_stmt_contents**: "with_item" ("," "with_item")* ++ **with_item**: "expression" ["as" "target"] ++ ++The execution of the "with" statement with one “item†proceeds as ++follows: ++ ++1. The context expression (the expression given in the "with_item") is ++ evaluated to obtain a context manager. ++ ++2. The context manager’s "__enter__()" is loaded for later use. ++ ++3. The context manager’s "__exit__()" is loaded for later use. ++ ++4. The context manager’s "__enter__()" method is invoked. ++ ++5. If a target was included in the "with" statement, the return value ++ from "__enter__()" is assigned to it. ++ ++ Note: ++ ++ The "with" statement guarantees that if the "__enter__()" method ++ returns without an error, then "__exit__()" will always be ++ called. Thus, if an error occurs during the assignment to the ++ target list, it will be treated the same as an error occurring ++ within the suite would be. See step 7 below. ++ ++6. The suite is executed. ++ ++7. The context manager’s "__exit__()" method is invoked. If an ++ exception caused the suite to be exited, its type, value, and ++ traceback are passed as arguments to "__exit__()". Otherwise, three ++ "None" arguments are supplied. ++ ++ If the suite was exited due to an exception, and the return value ++ from the "__exit__()" method was false, the exception is reraised. ++ If the return value was true, the exception is suppressed, and ++ execution continues with the statement following the "with" ++ statement. ++ ++ If the suite was exited for any reason other than an exception, the ++ return value from "__exit__()" is ignored, and execution proceeds ++ at the normal location for the kind of exit that was taken. ++ ++The following code: ++ ++ with EXPRESSION as TARGET: ++ SUITE ++ ++is semantically equivalent to: ++ ++ manager = (EXPRESSION) ++ enter = type(manager).__enter__ ++ exit = type(manager).__exit__ ++ value = enter(manager) ++ hit_except = False ++ ++ try: ++ TARGET = value ++ SUITE ++ except: ++ hit_except = True ++ if not exit(manager, *sys.exc_info()): ++ raise ++ finally: ++ if not hit_except: ++ exit(manager, None, None, None) ++ ++With more than one item, the context managers are processed as if ++multiple "with" statements were nested: ++ ++ with A() as a, B() as b: ++ SUITE ++ ++is semantically equivalent to: ++ ++ with A() as a: ++ with B() as b: ++ SUITE ++ ++You can also write multi-item context managers in multiple lines if ++the items are surrounded by parentheses. For example: ++ ++ with ( ++ A() as a, ++ B() as b, ++ ): ++ SUITE ++ ++Changed in version 3.1: Support for multiple context expressions. ++ ++Changed in version 3.10: Support for using grouping parentheses to ++break the statement in multiple lines. ++ ++See also: ++ ++ **PEP 343** - The “with†statement ++ The specification, background, and examples for the Python "with" ++ statement. ++ ++ ++The "match" statement ++===================== ++ ++Added in version 3.10. ++ ++The match statement is used for pattern matching. Syntax: ++ ++ **match_stmt**: 'match' "subject_expr" ":" NEWLINE INDENT "case_block"+ DEDENT ++ **subject_expr**: "star_named_expression" "," "star_named_expressions"? ++ | "named_expression" ++ **case_block**: 'case' "patterns" ["guard"] ":" "block" ++ ++Note: ++ ++ This section uses single quotes to denote soft keywords. ++ ++Pattern matching takes a pattern as input (following "case") and a ++subject value (following "match"). The pattern (which may contain ++subpatterns) is matched against the subject value. The outcomes are: ++ ++* A match success or failure (also termed a pattern success or ++ failure). ++ ++* Possible binding of matched values to a name. The prerequisites for ++ this are further discussed below. ++ ++The "match" and "case" keywords are soft keywords. ++ ++See also: ++ ++ * **PEP 634** – Structural Pattern Matching: Specification ++ ++ * **PEP 636** – Structural Pattern Matching: Tutorial ++ ++ ++Overview ++-------- ++ ++Here’s an overview of the logical flow of a match statement: ++ ++1. The subject expression "subject_expr" is evaluated and a resulting ++ subject value obtained. If the subject expression contains a comma, ++ a tuple is constructed using the standard rules. ++ ++2. Each pattern in a "case_block" is attempted to match with the ++ subject value. The specific rules for success or failure are ++ described below. The match attempt can also bind some or all of the ++ standalone names within the pattern. The precise pattern binding ++ rules vary per pattern type and are specified below. **Name ++ bindings made during a successful pattern match outlive the ++ executed block and can be used after the match statement**. ++ ++ Note: ++ ++ During failed pattern matches, some subpatterns may succeed. Do ++ not rely on bindings being made for a failed match. Conversely, ++ do not rely on variables remaining unchanged after a failed ++ match. The exact behavior is dependent on implementation and may ++ vary. This is an intentional decision made to allow different ++ implementations to add optimizations. ++ ++3. If the pattern succeeds, the corresponding guard (if present) is ++ evaluated. In this case all name bindings are guaranteed to have ++ happened. ++ ++ * If the guard evaluates as true or is missing, the "block" inside ++ "case_block" is executed. ++ ++ * Otherwise, the next "case_block" is attempted as described above. ++ ++ * If there are no further case blocks, the match statement is ++ completed. ++ ++Note: ++ ++ Users should generally never rely on a pattern being evaluated. ++ Depending on implementation, the interpreter may cache values or use ++ other optimizations which skip repeated evaluations. ++ ++A sample match statement: ++ ++ >>> flag = False ++ >>> match (100, 200): ++ ... case (100, 300): # Mismatch: 200 != 300 ++ ... print('Case 1') ++ ... case (100, 200) if flag: # Successful match, but guard fails ++ ... print('Case 2') ++ ... case (100, y): # Matches and binds y to 200 ++ ... print(f'Case 3, y: {y}') ++ ... case _: # Pattern not attempted ++ ... print('Case 4, I match anything!') ++ ... ++ Case 3, y: 200 ++ ++In this case, "if flag" is a guard. Read more about that in the next ++section. ++ ++ ++Guards ++------ ++ ++ **guard**: "if" "named_expression" ++ ++A "guard" (which is part of the "case") must succeed for code inside ++the "case" block to execute. It takes the form: "if" followed by an ++expression. ++ ++The logical flow of a "case" block with a "guard" follows: ++ ++1. Check that the pattern in the "case" block succeeded. If the ++ pattern failed, the "guard" is not evaluated and the next "case" ++ block is checked. ++ ++2. If the pattern succeeded, evaluate the "guard". ++ ++ * If the "guard" condition evaluates as true, the case block is ++ selected. ++ ++ * If the "guard" condition evaluates as false, the case block is ++ not selected. ++ ++ * If the "guard" raises an exception during evaluation, the ++ exception bubbles up. ++ ++Guards are allowed to have side effects as they are expressions. ++Guard evaluation must proceed from the first to the last case block, ++one at a time, skipping case blocks whose pattern(s) don’t all ++succeed. (I.e., guard evaluation must happen in order.) Guard ++evaluation must stop once a case block is selected. ++ ++ ++Irrefutable Case Blocks ++----------------------- ++ ++An irrefutable case block is a match-all case block. A match ++statement may have at most one irrefutable case block, and it must be ++last. ++ ++A case block is considered irrefutable if it has no guard and its ++pattern is irrefutable. A pattern is considered irrefutable if we can ++prove from its syntax alone that it will always succeed. Only the ++following patterns are irrefutable: ++ ++* AS Patterns whose left-hand side is irrefutable ++ ++* OR Patterns containing at least one irrefutable pattern ++ ++* Capture Patterns ++ ++* Wildcard Patterns ++ ++* parenthesized irrefutable patterns ++ ++ ++Patterns ++-------- ++ ++Note: ++ ++ This section uses grammar notations beyond standard EBNF: ++ ++ * the notation "SEP.RULE+" is shorthand for "RULE (SEP RULE)*" ++ ++ * the notation "!RULE" is shorthand for a negative lookahead ++ assertion ++ ++The top-level syntax for "patterns" is: ++ ++ **patterns**: "open_sequence_pattern" | "pattern" ++ **pattern**: "as_pattern" | "or_pattern" ++ **closed_pattern**: | "literal_pattern" ++ | "capture_pattern" ++ | "wildcard_pattern" ++ | "value_pattern" ++ | "group_pattern" ++ | "sequence_pattern" ++ | "mapping_pattern" ++ | "class_pattern" ++ ++The descriptions below will include a description “in simple terms†of ++what a pattern does for illustration purposes (credits to Raymond ++Hettinger for a document that inspired most of the descriptions). Note ++that these descriptions are purely for illustration purposes and **may ++not** reflect the underlying implementation. Furthermore, they do not ++cover all valid forms. ++ ++ ++OR Patterns ++~~~~~~~~~~~ ++ ++An OR pattern is two or more patterns separated by vertical bars "|". ++Syntax: ++ ++ **or_pattern**: "|"."closed_pattern"+ ++ ++Only the final subpattern may be irrefutable, and each subpattern must ++bind the same set of names to avoid ambiguity. ++ ++An OR pattern matches each of its subpatterns in turn to the subject ++value, until one succeeds. The OR pattern is then considered ++successful. Otherwise, if none of the subpatterns succeed, the OR ++pattern fails. ++ ++In simple terms, "P1 | P2 | ..." will try to match "P1", if it fails ++it will try to match "P2", succeeding immediately if any succeeds, ++failing otherwise. ++ ++ ++AS Patterns ++~~~~~~~~~~~ ++ ++An AS pattern matches an OR pattern on the left of the "as" keyword ++against a subject. Syntax: ++ ++ **as_pattern**: "or_pattern" "as" "capture_pattern" ++ ++If the OR pattern fails, the AS pattern fails. Otherwise, the AS ++pattern binds the subject to the name on the right of the as keyword ++and succeeds. "capture_pattern" cannot be a "_". ++ ++In simple terms "P as NAME" will match with "P", and on success it ++will set "NAME = ". ++ ++ ++Literal Patterns ++~~~~~~~~~~~~~~~~ ++ ++A literal pattern corresponds to most literals in Python. Syntax: ++ ++ **literal_pattern**: "signed_number" ++ | "signed_number" "+" NUMBER ++ | "signed_number" "-" NUMBER ++ | "strings" ++ | "None" ++ | "True" ++ | "False" ++ **signed_number**: ["-"] NUMBER ++ ++The rule "strings" and the token "NUMBER" are defined in the standard ++Python grammar. Triple-quoted strings are supported. Raw strings and ++byte strings are supported. f-strings are not supported. ++ ++The forms "signed_number '+' NUMBER" and "signed_number '-' NUMBER" ++are for expressing complex numbers; they require a real number on the ++left and an imaginary number on the right. E.g. "3 + 4j". ++ ++In simple terms, "LITERAL" will succeed only if " == ++LITERAL". For the singletons "None", "True" and "False", the "is" ++operator is used. ++ ++ ++Capture Patterns ++~~~~~~~~~~~~~~~~ ++ ++A capture pattern binds the subject value to a name. Syntax: ++ ++ **capture_pattern**: !'_' NAME ++ ++A single underscore "_" is not a capture pattern (this is what "!'_'" ++expresses). It is instead treated as a "wildcard_pattern". ++ ++In a given pattern, a given name can only be bound once. E.g. "case ++x, x: ..." is invalid while "case [x] | x: ..." is allowed. ++ ++Capture patterns always succeed. The binding follows scoping rules ++established by the assignment expression operator in **PEP 572**; the ++name becomes a local variable in the closest containing function scope ++unless there’s an applicable "global" or "nonlocal" statement. ++ ++In simple terms "NAME" will always succeed and it will set "NAME = ++". ++ ++ ++Wildcard Patterns ++~~~~~~~~~~~~~~~~~ ++ ++A wildcard pattern always succeeds (matches anything) and binds no ++name. Syntax: ++ ++ **wildcard_pattern**: '_' ++ ++"_" is a soft keyword within any pattern, but only within patterns. ++It is an identifier, as usual, even within "match" subject ++expressions, "guard"s, and "case" blocks. ++ ++In simple terms, "_" will always succeed. ++ ++ ++Value Patterns ++~~~~~~~~~~~~~~ ++ ++A value pattern represents a named value in Python. Syntax: ++ ++ **value_pattern**: "attr" ++ **attr**: "name_or_attr" "." NAME ++ **name_or_attr**: "attr" | NAME ++ ++The dotted name in the pattern is looked up using standard Python name ++resolution rules. The pattern succeeds if the value found compares ++equal to the subject value (using the "==" equality operator). ++ ++In simple terms "NAME1.NAME2" will succeed only if " == ++NAME1.NAME2" ++ ++Note: ++ ++ If the same value occurs multiple times in the same match statement, ++ the interpreter may cache the first value found and reuse it rather ++ than repeat the same lookup. This cache is strictly tied to a given ++ execution of a given match statement. ++ ++ ++Group Patterns ++~~~~~~~~~~~~~~ ++ ++A group pattern allows users to add parentheses around patterns to ++emphasize the intended grouping. Otherwise, it has no additional ++syntax. Syntax: ++ ++ **group_pattern**: "(" "pattern" ")" ++ ++In simple terms "(P)" has the same effect as "P". ++ ++ ++Sequence Patterns ++~~~~~~~~~~~~~~~~~ ++ ++A sequence pattern contains several subpatterns to be matched against ++sequence elements. The syntax is similar to the unpacking of a list or ++tuple. ++ ++ **sequence_pattern**: "[" ["maybe_sequence_pattern"] "]" ++ | "(" ["open_sequence_pattern"] ")" ++ **open_sequence_pattern**: "maybe_star_pattern" "," ["maybe_sequence_pattern"] ++ **maybe_sequence_pattern**: ","."maybe_star_pattern"+ ","? ++ **maybe_star_pattern**: "star_pattern" | "pattern" ++ **star_pattern**: "*" ("capture_pattern" | "wildcard_pattern") ++ ++There is no difference if parentheses or square brackets are used for ++sequence patterns (i.e. "(...)" vs "[...]" ). ++ ++Note: ++ ++ A single pattern enclosed in parentheses without a trailing comma ++ (e.g. "(3 | 4)") is a group pattern. While a single pattern enclosed ++ in square brackets (e.g. "[3 | 4]") is still a sequence pattern. ++ ++At most one star subpattern may be in a sequence pattern. The star ++subpattern may occur in any position. If no star subpattern is ++present, the sequence pattern is a fixed-length sequence pattern; ++otherwise it is a variable-length sequence pattern. ++ ++The following is the logical flow for matching a sequence pattern ++against a subject value: ++ ++1. If the subject value is not a sequence [2], the sequence pattern ++ fails. ++ ++2. If the subject value is an instance of "str", "bytes" or ++ "bytearray" the sequence pattern fails. ++ ++3. The subsequent steps depend on whether the sequence pattern is ++ fixed or variable-length. ++ ++ If the sequence pattern is fixed-length: ++ ++ 1. If the length of the subject sequence is not equal to the number ++ of subpatterns, the sequence pattern fails ++ ++ 2. Subpatterns in the sequence pattern are matched to their ++ corresponding items in the subject sequence from left to right. ++ Matching stops as soon as a subpattern fails. If all ++ subpatterns succeed in matching their corresponding item, the ++ sequence pattern succeeds. ++ ++ Otherwise, if the sequence pattern is variable-length: ++ ++ 1. If the length of the subject sequence is less than the number of ++ non-star subpatterns, the sequence pattern fails. ++ ++ 2. The leading non-star subpatterns are matched to their ++ corresponding items as for fixed-length sequences. ++ ++ 3. If the previous step succeeds, the star subpattern matches a ++ list formed of the remaining subject items, excluding the ++ remaining items corresponding to non-star subpatterns following ++ the star subpattern. ++ ++ 4. Remaining non-star subpatterns are matched to their ++ corresponding subject items, as for a fixed-length sequence. ++ ++ Note: ++ ++ The length of the subject sequence is obtained via "len()" (i.e. ++ via the "__len__()" protocol). This length may be cached by the ++ interpreter in a similar manner as value patterns. ++ ++In simple terms "[P1, P2, P3," … ", P]" matches only if all the ++following happens: ++ ++* check "" is a sequence ++ ++* "len(subject) == " ++ ++* "P1" matches "[0]" (note that this match can also bind ++ names) ++ ++* "P2" matches "[1]" (note that this match can also bind ++ names) ++ ++* … and so on for the corresponding pattern/element. ++ ++ ++Mapping Patterns ++~~~~~~~~~~~~~~~~ ++ ++A mapping pattern contains one or more key-value patterns. The syntax ++is similar to the construction of a dictionary. Syntax: ++ ++ **mapping_pattern**: "{" ["items_pattern"] "}" ++ **items_pattern**: ","."key_value_pattern"+ ","? ++ **key_value_pattern**: ("literal_pattern" | "value_pattern") ":" "pattern" ++ | "double_star_pattern" ++ **double_star_pattern**: "**" "capture_pattern" ++ ++At most one double star pattern may be in a mapping pattern. The ++double star pattern must be the last subpattern in the mapping ++pattern. ++ ++Duplicate keys in mapping patterns are disallowed. Duplicate literal ++keys will raise a "SyntaxError". Two keys that otherwise have the same ++value will raise a "ValueError" at runtime. ++ ++The following is the logical flow for matching a mapping pattern ++against a subject value: ++ ++1. If the subject value is not a mapping [3],the mapping pattern ++ fails. ++ ++2. If every key given in the mapping pattern is present in the subject ++ mapping, and the pattern for each key matches the corresponding ++ item of the subject mapping, the mapping pattern succeeds. ++ ++3. If duplicate keys are detected in the mapping pattern, the pattern ++ is considered invalid. A "SyntaxError" is raised for duplicate ++ literal values; or a "ValueError" for named keys of the same value. ++ ++Note: ++ ++ Key-value pairs are matched using the two-argument form of the ++ mapping subject’s "get()" method. Matched key-value pairs must ++ already be present in the mapping, and not created on-the-fly via ++ "__missing__()" or "__getitem__()". ++ ++In simple terms "{KEY1: P1, KEY2: P2, ... }" matches only if all the ++following happens: ++ ++* check "" is a mapping ++ ++* "KEY1 in " ++ ++* "P1" matches "[KEY1]" ++ ++* … and so on for the corresponding KEY/pattern pair. ++ ++ ++Class Patterns ++~~~~~~~~~~~~~~ ++ ++A class pattern represents a class and its positional and keyword ++arguments (if any). Syntax: ++ ++ **class_pattern**: "name_or_attr" "(" ["pattern_arguments" ","?] ")" ++ **pattern_arguments**: "positional_patterns" ["," "keyword_patterns"] ++ | "keyword_patterns" ++ **positional_patterns**: ","."pattern"+ ++ **keyword_patterns**: ","."keyword_pattern"+ ++ **keyword_pattern**: NAME "=" "pattern" ++ ++The same keyword should not be repeated in class patterns. ++ ++The following is the logical flow for matching a class pattern against ++a subject value: ++ ++1. If "name_or_attr" is not an instance of the builtin "type" , raise ++ "TypeError". ++ ++2. If the subject value is not an instance of "name_or_attr" (tested ++ via "isinstance()"), the class pattern fails. ++ ++3. If no pattern arguments are present, the pattern succeeds. ++ Otherwise, the subsequent steps depend on whether keyword or ++ positional argument patterns are present. ++ ++ For a number of built-in types (specified below), a single ++ positional subpattern is accepted which will match the entire ++ subject; for these types keyword patterns also work as for other ++ types. ++ ++ If only keyword patterns are present, they are processed as ++ follows, one by one: ++ ++ I. The keyword is looked up as an attribute on the subject. ++ ++ * If this raises an exception other than "AttributeError", the ++ exception bubbles up. ++ ++ * If this raises "AttributeError", the class pattern has failed. ++ ++ * Else, the subpattern associated with the keyword pattern is ++ matched against the subject’s attribute value. If this fails, ++ the class pattern fails; if this succeeds, the match proceeds ++ to the next keyword. ++ ++ II. If all keyword patterns succeed, the class pattern succeeds. ++ ++ If any positional patterns are present, they are converted to ++ keyword patterns using the "__match_args__" attribute on the class ++ "name_or_attr" before matching: ++ ++ I. The equivalent of "getattr(cls, "__match_args__", ())" is ++ called. ++ ++ * If this raises an exception, the exception bubbles up. ++ ++ * If the returned value is not a tuple, the conversion fails and ++ "TypeError" is raised. ++ ++ * If there are more positional patterns than ++ "len(cls.__match_args__)", "TypeError" is raised. ++ ++ * Otherwise, positional pattern "i" is converted to a keyword ++ pattern using "__match_args__[i]" as the keyword. ++ "__match_args__[i]" must be a string; if not "TypeError" is ++ raised. ++ ++ * If there are duplicate keywords, "TypeError" is raised. ++ ++ See also: ++ ++ Customizing positional arguments in class pattern matching ++ ++ II. Once all positional patterns have been converted to keyword ++ patterns, ++ the match proceeds as if there were only keyword patterns. ++ ++ For the following built-in types the handling of positional ++ subpatterns is different: ++ ++ * "bool" ++ ++ * "bytearray" ++ ++ * "bytes" ++ ++ * "dict" ++ ++ * "float" ++ ++ * "frozenset" ++ ++ * "int" ++ ++ * "list" ++ ++ * "set" ++ ++ * "str" ++ ++ * "tuple" ++ ++ These classes accept a single positional argument, and the pattern ++ there is matched against the whole object rather than an attribute. ++ For example "int(0|1)" matches the value "0", but not the value ++ "0.0". ++ ++In simple terms "CLS(P1, attr=P2)" matches only if the following ++happens: ++ ++* "isinstance(, CLS)" ++ ++* convert "P1" to a keyword pattern using "CLS.__match_args__" ++ ++* For each keyword argument "attr=P2": ++ ++ * "hasattr(, "attr")" ++ ++ * "P2" matches ".attr" ++ ++* … and so on for the corresponding keyword argument/pattern pair. ++ ++See also: ++ ++ * **PEP 634** – Structural Pattern Matching: Specification ++ ++ * **PEP 636** – Structural Pattern Matching: Tutorial ++ ++ ++Function definitions ++==================== ++ ++A function definition defines a user-defined function object (see ++section The standard type hierarchy): ++ ++ **funcdef**: ["decorators"] "def" "funcname" ["type_params"] "(" ["parameter_list"] ")" ++ ["->" "expression"] ":" "suite" ++ **decorators**: "decorator"+ ++ **decorator**: "@" "assignment_expression" NEWLINE ++ **parameter_list**: "defparameter" ("," "defparameter")* "," "/" ["," ["parameter_list_no_posonly"]] ++ | "parameter_list_no_posonly" ++ **parameter_list_no_posonly**: "defparameter" ("," "defparameter")* ["," ["parameter_list_starargs"]] ++ | "parameter_list_starargs" ++ **parameter_list_starargs**: "*" ["star_parameter"] ("," "defparameter")* ["," ["parameter_star_kwargs"]] ++ "*" ("," "defparameter")+ ["," ["parameter_star_kwargs"]] ++ | "parameter_star_kwargs" ++ **parameter_star_kwargs**: "**" "parameter" [","] ++ **parameter**: "identifier" [":" "expression"] ++ **star_parameter**: "identifier" [":" ["*"] "expression"] ++ **defparameter**: "parameter" ["=" "expression"] ++ **funcname**: "identifier" ++ ++A function definition is an executable statement. Its execution binds ++the function name in the current local namespace to a function object ++(a wrapper around the executable code for the function). This ++function object contains a reference to the current global namespace ++as the global namespace to be used when the function is called. ++ ++The function definition does not execute the function body; this gets ++executed only when the function is called. [4] ++ ++A function definition may be wrapped by one or more *decorator* ++expressions. Decorator expressions are evaluated when the function is ++defined, in the scope that contains the function definition. The ++result must be a callable, which is invoked with the function object ++as the only argument. The returned value is bound to the function name ++instead of the function object. Multiple decorators are applied in ++nested fashion. For example, the following code ++ ++ @f1(arg) ++ @f2 ++ def func(): pass ++ ++is roughly equivalent to ++ ++ def func(): pass ++ func = f1(arg)(f2(func)) ++ ++except that the original function is not temporarily bound to the name ++"func". ++ ++Changed in version 3.9: Functions may be decorated with any valid ++"assignment_expression". Previously, the grammar was much more ++restrictive; see **PEP 614** for details. ++ ++A list of type parameters may be given in square brackets between the ++function’s name and the opening parenthesis for its parameter list. ++This indicates to static type checkers that the function is generic. ++At runtime, the type parameters can be retrieved from the function’s ++"__type_params__" attribute. See Generic functions for more. ++ ++Changed in version 3.12: Type parameter lists are new in Python 3.12. ++ ++When one or more *parameters* have the form *parameter* "=" ++*expression*, the function is said to have “default parameter values.†++For a parameter with a default value, the corresponding *argument* may ++be omitted from a call, in which case the parameter’s default value is ++substituted. If a parameter has a default value, all following ++parameters up until the “"*"†must also have a default value — this is ++a syntactic restriction that is not expressed by the grammar. ++ ++**Default parameter values are evaluated from left to right when the ++function definition is executed.** This means that the expression is ++evaluated once, when the function is defined, and that the same “pre- ++computed†value is used for each call. This is especially important ++to understand when a default parameter value is a mutable object, such ++as a list or a dictionary: if the function modifies the object (e.g. ++by appending an item to a list), the default parameter value is in ++effect modified. This is generally not what was intended. A way ++around this is to use "None" as the default, and explicitly test for ++it in the body of the function, e.g.: ++ ++ def whats_on_the_telly(penguin=None): ++ if penguin is None: ++ penguin = [] ++ penguin.append("property of the zoo") ++ return penguin ++ ++Function call semantics are described in more detail in section Calls. ++A function call always assigns values to all parameters mentioned in ++the parameter list, either from positional arguments, from keyword ++arguments, or from default values. If the form “"*identifier"†is ++present, it is initialized to a tuple receiving any excess positional ++parameters, defaulting to the empty tuple. If the form ++“"**identifier"†is present, it is initialized to a new ordered ++mapping receiving any excess keyword arguments, defaulting to a new ++empty mapping of the same type. Parameters after “"*"†or ++“"*identifier"†are keyword-only parameters and may only be passed by ++keyword arguments. Parameters before “"/"†are positional-only ++parameters and may only be passed by positional arguments. ++ ++Changed in version 3.8: The "/" function parameter syntax may be used ++to indicate positional-only parameters. See **PEP 570** for details. ++ ++Parameters may have an *annotation* of the form “": expression"†++following the parameter name. Any parameter may have an annotation, ++even those of the form "*identifier" or "**identifier". (As a special ++case, parameters of the form "*identifier" may have an annotation “": ++*expression"â€.) Functions may have “return†annotation of the form ++“"-> expression"†after the parameter list. These annotations can be ++any valid Python expression. The presence of annotations does not ++change the semantics of a function. See Annotations for more ++information on annotations. ++ ++Changed in version 3.11: Parameters of the form “"*identifier"†may ++have an annotation “": *expression"â€. See **PEP 646**. ++ ++It is also possible to create anonymous functions (functions not bound ++to a name), for immediate use in expressions. This uses lambda ++expressions, described in section Lambdas. Note that the lambda ++expression is merely a shorthand for a simplified function definition; ++a function defined in a “"def"†statement can be passed around or ++assigned to another name just like a function defined by a lambda ++expression. The “"def"†form is actually more powerful since it ++allows the execution of multiple statements and annotations. ++ ++**Programmer’s note:** Functions are first-class objects. A “"def"†++statement executed inside a function definition defines a local ++function that can be returned or passed around. Free variables used ++in the nested function can access the local variables of the function ++containing the def. See section Naming and binding for details. ++ ++See also: ++ ++ **PEP 3107** - Function Annotations ++ The original specification for function annotations. ++ ++ **PEP 484** - Type Hints ++ Definition of a standard meaning for annotations: type hints. ++ ++ **PEP 526** - Syntax for Variable Annotations ++ Ability to type hint variable declarations, including class ++ variables and instance variables. ++ ++ **PEP 563** - Postponed Evaluation of Annotations ++ Support for forward references within annotations by preserving ++ annotations in a string form at runtime instead of eager ++ evaluation. ++ ++ **PEP 318** - Decorators for Functions and Methods ++ Function and method decorators were introduced. Class decorators ++ were introduced in **PEP 3129**. ++ ++ ++Class definitions ++================= ++ ++A class definition defines a class object (see section The standard ++type hierarchy): ++ ++ **classdef**: ["decorators"] "class" "classname" ["type_params"] ["inheritance"] ":" "suite" ++ **inheritance**: "(" ["argument_list"] ")" ++ **classname**: "identifier" ++ ++A class definition is an executable statement. The inheritance list ++usually gives a list of base classes (see Metaclasses for more ++advanced uses), so each item in the list should evaluate to a class ++object which allows subclassing. Classes without an inheritance list ++inherit, by default, from the base class "object"; hence, ++ ++ class Foo: ++ pass ++ ++is equivalent to ++ ++ class Foo(object): ++ pass ++ ++The class’s suite is then executed in a new execution frame (see ++Naming and binding), using a newly created local namespace and the ++original global namespace. (Usually, the suite contains mostly ++function definitions.) When the class’s suite finishes execution, its ++execution frame is discarded but its local namespace is saved. [5] A ++class object is then created using the inheritance list for the base ++classes and the saved local namespace for the attribute dictionary. ++The class name is bound to this class object in the original local ++namespace. ++ ++The order in which attributes are defined in the class body is ++preserved in the new class’s "__dict__". Note that this is reliable ++only right after the class is created and only for classes that were ++defined using the definition syntax. ++ ++Class creation can be customized heavily using metaclasses. ++ ++Classes can also be decorated: just like when decorating functions, ++ ++ @f1(arg) ++ @f2 ++ class Foo: pass ++ ++is roughly equivalent to ++ ++ class Foo: pass ++ Foo = f1(arg)(f2(Foo)) ++ ++The evaluation rules for the decorator expressions are the same as for ++function decorators. The result is then bound to the class name. ++ ++Changed in version 3.9: Classes may be decorated with any valid ++"assignment_expression". Previously, the grammar was much more ++restrictive; see **PEP 614** for details. ++ ++A list of type parameters may be given in square brackets immediately ++after the class’s name. This indicates to static type checkers that ++the class is generic. At runtime, the type parameters can be retrieved ++from the class’s "__type_params__" attribute. See Generic classes for ++more. ++ ++Changed in version 3.12: Type parameter lists are new in Python 3.12. ++ ++**Programmer’s note:** Variables defined in the class definition are ++class attributes; they are shared by instances. Instance attributes ++can be set in a method with "self.name = value". Both class and ++instance attributes are accessible through the notation “"self.name"â€, ++and an instance attribute hides a class attribute with the same name ++when accessed in this way. Class attributes can be used as defaults ++for instance attributes, but using mutable values there can lead to ++unexpected results. Descriptors can be used to create instance ++variables with different implementation details. ++ ++See also: ++ ++ **PEP 3115** - Metaclasses in Python 3000 ++ The proposal that changed the declaration of metaclasses to the ++ current syntax, and the semantics for how classes with ++ metaclasses are constructed. ++ ++ **PEP 3129** - Class Decorators ++ The proposal that added class decorators. Function and method ++ decorators were introduced in **PEP 318**. ++ ++ ++Coroutines ++========== ++ ++Added in version 3.5. ++ ++ ++Coroutine function definition ++----------------------------- ++ ++ **async_funcdef**: ["decorators"] "async" "def" "funcname" "(" ["parameter_list"] ")" ++ ["->" "expression"] ":" "suite" ++ ++Execution of Python coroutines can be suspended and resumed at many ++points (see *coroutine*). "await" expressions, "async for" and "async ++with" can only be used in the body of a coroutine function. ++ ++Functions defined with "async def" syntax are always coroutine ++functions, even if they do not contain "await" or "async" keywords. ++ ++It is a "SyntaxError" to use a "yield from" expression inside the body ++of a coroutine function. ++ ++An example of a coroutine function: ++ ++ async def func(param1, param2): ++ do_stuff() ++ await some_coroutine() ++ ++Changed in version 3.7: "await" and "async" are now keywords; ++previously they were only treated as such inside the body of a ++coroutine function. ++ ++ ++The "async for" statement ++------------------------- ++ ++ **async_for_stmt**: "async" "for_stmt" ++ ++An *asynchronous iterable* provides an "__aiter__" method that ++directly returns an *asynchronous iterator*, which can call ++asynchronous code in its "__anext__" method. ++ ++The "async for" statement allows convenient iteration over ++asynchronous iterables. ++ ++The following code: ++ ++ async for TARGET in ITER: ++ SUITE ++ else: ++ SUITE2 ++ ++Is semantically equivalent to: ++ ++ iter = (ITER) ++ iter = type(iter).__aiter__(iter) ++ running = True ++ ++ while running: ++ try: ++ TARGET = await type(iter).__anext__(iter) ++ except StopAsyncIteration: ++ running = False ++ else: ++ SUITE ++ else: ++ SUITE2 ++ ++See also "__aiter__()" and "__anext__()" for details. ++ ++It is a "SyntaxError" to use an "async for" statement outside the body ++of a coroutine function. ++ ++ ++The "async with" statement ++-------------------------- ++ ++ **async_with_stmt**: "async" "with_stmt" ++ ++An *asynchronous context manager* is a *context manager* that is able ++to suspend execution in its *enter* and *exit* methods. ++ ++The following code: ++ ++ async with EXPRESSION as TARGET: ++ SUITE ++ ++is semantically equivalent to: ++ ++ manager = (EXPRESSION) ++ aenter = type(manager).__aenter__ ++ aexit = type(manager).__aexit__ ++ value = await aenter(manager) ++ hit_except = False ++ ++ try: ++ TARGET = value ++ SUITE ++ except: ++ hit_except = True ++ if not await aexit(manager, *sys.exc_info()): ++ raise ++ finally: ++ if not hit_except: ++ await aexit(manager, None, None, None) ++ ++See also "__aenter__()" and "__aexit__()" for details. ++ ++It is a "SyntaxError" to use an "async with" statement outside the ++body of a coroutine function. ++ ++See also: ++ ++ **PEP 492** - Coroutines with async and await syntax ++ The proposal that made coroutines a proper standalone concept in ++ Python, and added supporting syntax. ++ ++ ++Type parameter lists ++==================== ++ ++Added in version 3.12. ++ ++Changed in version 3.13: Support for default values was added (see ++**PEP 696**). ++ ++ **type_params**: "[" "type_param" ("," "type_param")* "]" ++ **type_param**: "typevar" | "typevartuple" | "paramspec" ++ **typevar**: "identifier" (":" "expression")? ("=" "expression")? ++ **typevartuple**: "*" "identifier" ("=" "expression")? ++ **paramspec**: "**" "identifier" ("=" "expression")? ++ ++Functions (including coroutines), classes and type aliases may contain ++a type parameter list: ++ ++ def max[T](args: list[T]) -> T: ++ ... ++ ++ async def amax[T](args: list[T]) -> T: ++ ... ++ ++ class Bag[T]: ++ def __iter__(self) -> Iterator[T]: ++ ... ++ ++ def add(self, arg: T) -> None: ++ ... ++ ++ type ListOrSet[T] = list[T] | set[T] ++ ++Semantically, this indicates that the function, class, or type alias ++is generic over a type variable. This information is primarily used by ++static type checkers, and at runtime, generic objects behave much like ++their non-generic counterparts. ++ ++Type parameters are declared in square brackets ("[]") immediately ++after the name of the function, class, or type alias. The type ++parameters are accessible within the scope of the generic object, but ++not elsewhere. Thus, after a declaration "def func[T](): pass", the ++name "T" is not available in the module scope. Below, the semantics of ++generic objects are described with more precision. The scope of type ++parameters is modeled with a special function (technically, an ++annotation scope) that wraps the creation of the generic object. ++ ++Generic functions, classes, and type aliases have a "__type_params__" ++attribute listing their type parameters. ++ ++Type parameters come in three kinds: ++ ++* "typing.TypeVar", introduced by a plain name (e.g., "T"). ++ Semantically, this represents a single type to a type checker. ++ ++* "typing.TypeVarTuple", introduced by a name prefixed with a single ++ asterisk (e.g., "*Ts"). Semantically, this stands for a tuple of any ++ number of types. ++ ++* "typing.ParamSpec", introduced by a name prefixed with two asterisks ++ (e.g., "**P"). Semantically, this stands for the parameters of a ++ callable. ++ ++"typing.TypeVar" declarations can define *bounds* and *constraints* ++with a colon (":") followed by an expression. A single expression ++after the colon indicates a bound (e.g. "T: int"). Semantically, this ++means that the "typing.TypeVar" can only represent types that are a ++subtype of this bound. A parenthesized tuple of expressions after the ++colon indicates a set of constraints (e.g. "T: (str, bytes)"). Each ++member of the tuple should be a type (again, this is not enforced at ++runtime). Constrained type variables can only take on one of the types ++in the list of constraints. ++ ++For "typing.TypeVar"s declared using the type parameter list syntax, ++the bound and constraints are not evaluated when the generic object is ++created, but only when the value is explicitly accessed through the ++attributes "__bound__" and "__constraints__". To accomplish this, the ++bounds or constraints are evaluated in a separate annotation scope. ++ ++"typing.TypeVarTuple"s and "typing.ParamSpec"s cannot have bounds or ++constraints. ++ ++All three flavors of type parameters can also have a *default value*, ++which is used when the type parameter is not explicitly provided. This ++is added by appending a single equals sign ("=") followed by an ++expression. Like the bounds and constraints of type variables, the ++default value is not evaluated when the object is created, but only ++when the type parameter’s "__default__" attribute is accessed. To this ++end, the default value is evaluated in a separate annotation scope. If ++no default value is specified for a type parameter, the "__default__" ++attribute is set to the special sentinel object "typing.NoDefault". ++ ++The following example indicates the full set of allowed type parameter ++declarations: ++ ++ def overly_generic[ ++ SimpleTypeVar, ++ TypeVarWithDefault = int, ++ TypeVarWithBound: int, ++ TypeVarWithConstraints: (str, bytes), ++ *SimpleTypeVarTuple = (int, float), ++ **SimpleParamSpec = (str, bytearray), ++ ]( ++ a: SimpleTypeVar, ++ b: TypeVarWithDefault, ++ c: TypeVarWithBound, ++ d: Callable[SimpleParamSpec, TypeVarWithConstraints], ++ *e: SimpleTypeVarTuple, ++ ): ... ++ ++ ++Generic functions ++----------------- ++ ++Generic functions are declared as follows: ++ ++ def func[T](arg: T): ... ++ ++This syntax is equivalent to: ++ ++ annotation-def TYPE_PARAMS_OF_func(): ++ T = typing.TypeVar("T") ++ def func(arg: T): ... ++ func.__type_params__ = (T,) ++ return func ++ func = TYPE_PARAMS_OF_func() ++ ++Here "annotation-def" indicates an annotation scope, which is not ++actually bound to any name at runtime. (One other liberty is taken in ++the translation: the syntax does not go through attribute access on ++the "typing" module, but creates an instance of "typing.TypeVar" ++directly.) ++ ++The annotations of generic functions are evaluated within the ++annotation scope used for declaring the type parameters, but the ++function’s defaults and decorators are not. ++ ++The following example illustrates the scoping rules for these cases, ++as well as for additional flavors of type parameters: ++ ++ @decorator ++ def func[T: int, *Ts, **P](*args: *Ts, arg: Callable[P, T] = some_default): ++ ... ++ ++Except for the lazy evaluation of the "TypeVar" bound, this is ++equivalent to: ++ ++ DEFAULT_OF_arg = some_default ++ ++ annotation-def TYPE_PARAMS_OF_func(): ++ ++ annotation-def BOUND_OF_T(): ++ return int ++ # In reality, BOUND_OF_T() is evaluated only on demand. ++ T = typing.TypeVar("T", bound=BOUND_OF_T()) ++ ++ Ts = typing.TypeVarTuple("Ts") ++ P = typing.ParamSpec("P") ++ ++ def func(*args: *Ts, arg: Callable[P, T] = DEFAULT_OF_arg): ++ ... ++ ++ func.__type_params__ = (T, Ts, P) ++ return func ++ func = decorator(TYPE_PARAMS_OF_func()) ++ ++The capitalized names like "DEFAULT_OF_arg" are not actually bound at ++runtime. ++ ++ ++Generic classes ++--------------- ++ ++Generic classes are declared as follows: ++ ++ class Bag[T]: ... ++ ++This syntax is equivalent to: ++ ++ annotation-def TYPE_PARAMS_OF_Bag(): ++ T = typing.TypeVar("T") ++ class Bag(typing.Generic[T]): ++ __type_params__ = (T,) ++ ... ++ return Bag ++ Bag = TYPE_PARAMS_OF_Bag() ++ ++Here again "annotation-def" (not a real keyword) indicates an ++annotation scope, and the name "TYPE_PARAMS_OF_Bag" is not actually ++bound at runtime. ++ ++Generic classes implicitly inherit from "typing.Generic". The base ++classes and keyword arguments of generic classes are evaluated within ++the type scope for the type parameters, and decorators are evaluated ++outside that scope. This is illustrated by this example: ++ ++ @decorator ++ class Bag(Base[T], arg=T): ... ++ ++This is equivalent to: ++ ++ annotation-def TYPE_PARAMS_OF_Bag(): ++ T = typing.TypeVar("T") ++ class Bag(Base[T], typing.Generic[T], arg=T): ++ __type_params__ = (T,) ++ ... ++ return Bag ++ Bag = decorator(TYPE_PARAMS_OF_Bag()) ++ ++ ++Generic type aliases ++-------------------- ++ ++The "type" statement can also be used to create a generic type alias: ++ ++ type ListOrSet[T] = list[T] | set[T] ++ ++Except for the lazy evaluation of the value, this is equivalent to: ++ ++ annotation-def TYPE_PARAMS_OF_ListOrSet(): ++ T = typing.TypeVar("T") ++ ++ annotation-def VALUE_OF_ListOrSet(): ++ return list[T] | set[T] ++ # In reality, the value is lazily evaluated ++ return typing.TypeAliasType("ListOrSet", VALUE_OF_ListOrSet(), type_params=(T,)) ++ ListOrSet = TYPE_PARAMS_OF_ListOrSet() ++ ++Here, "annotation-def" (not a real keyword) indicates an annotation ++scope. The capitalized names like "TYPE_PARAMS_OF_ListOrSet" are not ++actually bound at runtime. ++ ++ ++Annotations ++=========== ++ ++Changed in version 3.14: Annotations are now lazily evaluated by ++default. ++ ++Variables and function parameters may carry *annotations*, created by ++adding a colon after the name, followed by an expression: ++ ++ x: annotation = 1 ++ def f(param: annotation): ... ++ ++Functions may also carry a return annotation following an arrow: ++ ++ def f() -> annotation: ... ++ ++Annotations are conventionally used for *type hints*, but this is not ++enforced by the language, and in general annotations may contain ++arbitrary expressions. The presence of annotations does not change the ++runtime semantics of the code, except if some mechanism is used that ++introspects and uses the annotations (such as "dataclasses" or ++"functools.singledispatch()"). ++ ++By default, annotations are lazily evaluated in a annotation scope. ++This means that they are not evaluated when the code containing the ++annotation is evaluated. Instead, the interpreter saves information ++that can be used to evaluate the annotation later if requested. The ++"annotationlib" module provides tools for evaluating annotations. ++ ++If the future statement "from __future__ import annotations" is ++present, all annotations are instead stored as strings: ++ ++ >>> from __future__ import annotations ++ >>> def f(param: annotation): ... ++ >>> f.__annotations__ ++ {'param': 'annotation'} ++ ++-[ Footnotes ]- ++ ++[1] The exception is propagated to the invocation stack unless there ++ is a "finally" clause which happens to raise another exception. ++ That new exception causes the old one to be lost. ++ ++[2] In pattern matching, a sequence is defined as one of the ++ following: ++ ++ * a class that inherits from "collections.abc.Sequence" ++ ++ * a Python class that has been registered as ++ "collections.abc.Sequence" ++ ++ * a builtin class that has its (CPython) "Py_TPFLAGS_SEQUENCE" bit ++ set ++ ++ * a class that inherits from any of the above ++ ++ The following standard library classes are sequences: ++ ++ * "array.array" ++ ++ * "collections.deque" ++ ++ * "list" ++ ++ * "memoryview" ++ ++ * "range" ++ ++ * "tuple" ++ ++ Note: ++ ++ Subject values of type "str", "bytes", and "bytearray" do not ++ match sequence patterns. ++ ++[3] In pattern matching, a mapping is defined as one of the following: ++ ++ * a class that inherits from "collections.abc.Mapping" ++ ++ * a Python class that has been registered as ++ "collections.abc.Mapping" ++ ++ * a builtin class that has its (CPython) "Py_TPFLAGS_MAPPING" bit ++ set ++ ++ * a class that inherits from any of the above ++ ++ The standard library classes "dict" and "types.MappingProxyType" ++ are mappings. ++ ++[4] A string literal appearing as the first statement in the function ++ body is transformed into the function’s "__doc__" attribute and ++ therefore the function’s *docstring*. ++ ++[5] A string literal appearing as the first statement in the class ++ body is transformed into the namespace’s "__doc__" item and ++ therefore the class’s *docstring*. ++''', ++ 'context-managers': r'''With Statement Context Managers ++******************************* ++ ++A *context manager* is an object that defines the runtime context to ++be established when executing a "with" statement. The context manager ++handles the entry into, and the exit from, the desired runtime context ++for the execution of the block of code. Context managers are normally ++invoked using the "with" statement (described in section The with ++statement), but can also be used by directly invoking their methods. ++ ++Typical uses of context managers include saving and restoring various ++kinds of global state, locking and unlocking resources, closing opened ++files, etc. ++ ++For more information on context managers, see Context Manager Types. ++The "object" class itself does not provide the context manager ++methods. ++ ++object.__enter__(self) ++ ++ Enter the runtime context related to this object. The "with" ++ statement will bind this method’s return value to the target(s) ++ specified in the "as" clause of the statement, if any. ++ ++object.__exit__(self, exc_type, exc_value, traceback) ++ ++ Exit the runtime context related to this object. The parameters ++ describe the exception that caused the context to be exited. If the ++ context was exited without an exception, all three arguments will ++ be "None". ++ ++ If an exception is supplied, and the method wishes to suppress the ++ exception (i.e., prevent it from being propagated), it should ++ return a true value. Otherwise, the exception will be processed ++ normally upon exit from this method. ++ ++ Note that "__exit__()" methods should not reraise the passed-in ++ exception; this is the caller’s responsibility. ++ ++See also: ++ ++ **PEP 343** - The “with†statement ++ The specification, background, and examples for the Python "with" ++ statement. ++''', ++ 'continue': r'''The "continue" statement ++************************ ++ ++ **continue_stmt**: "continue" ++ ++"continue" may only occur syntactically nested in a "for" or "while" ++loop, but not nested in a function or class definition within that ++loop. It continues with the next cycle of the nearest enclosing loop. ++ ++When "continue" passes control out of a "try" statement with a ++"finally" clause, that "finally" clause is executed before really ++starting the next loop cycle. ++''', ++ 'conversions': r'''Arithmetic conversions ++********************** ++ ++When a description of an arithmetic operator below uses the phrase ++“the numeric arguments are converted to a common real typeâ€, this ++means that the operator implementation for built-in types works as ++follows: ++ ++* If both arguments are complex numbers, no conversion is performed; ++ ++* if either argument is a complex or a floating-point number, the ++ other is converted to a floating-point number; ++ ++* otherwise, both must be integers and no conversion is necessary. ++ ++Some additional rules apply for certain operators (e.g., a string as a ++left argument to the ‘%’ operator). Extensions must define their own ++conversion behavior. ++''', ++ 'customization': r'''Basic customization ++******************* ++ ++object.__new__(cls[, ...]) ++ ++ Called to create a new instance of class *cls*. "__new__()" is a ++ static method (special-cased so you need not declare it as such) ++ that takes the class of which an instance was requested as its ++ first argument. The remaining arguments are those passed to the ++ object constructor expression (the call to the class). The return ++ value of "__new__()" should be the new object instance (usually an ++ instance of *cls*). ++ ++ Typical implementations create a new instance of the class by ++ invoking the superclass’s "__new__()" method using ++ "super().__new__(cls[, ...])" with appropriate arguments and then ++ modifying the newly created instance as necessary before returning ++ it. ++ ++ If "__new__()" is invoked during object construction and it returns ++ an instance of *cls*, then the new instance’s "__init__()" method ++ will be invoked like "__init__(self[, ...])", where *self* is the ++ new instance and the remaining arguments are the same as were ++ passed to the object constructor. ++ ++ If "__new__()" does not return an instance of *cls*, then the new ++ instance’s "__init__()" method will not be invoked. ++ ++ "__new__()" is intended mainly to allow subclasses of immutable ++ types (like int, str, or tuple) to customize instance creation. It ++ is also commonly overridden in custom metaclasses in order to ++ customize class creation. ++ ++object.__init__(self[, ...]) ++ ++ Called after the instance has been created (by "__new__()"), but ++ before it is returned to the caller. The arguments are those ++ passed to the class constructor expression. If a base class has an ++ "__init__()" method, the derived class’s "__init__()" method, if ++ any, must explicitly call it to ensure proper initialization of the ++ base class part of the instance; for example: ++ "super().__init__([args...])". ++ ++ Because "__new__()" and "__init__()" work together in constructing ++ objects ("__new__()" to create it, and "__init__()" to customize ++ it), no non-"None" value may be returned by "__init__()"; doing so ++ will cause a "TypeError" to be raised at runtime. ++ ++object.__del__(self) ++ ++ Called when the instance is about to be destroyed. This is also ++ called a finalizer or (improperly) a destructor. If a base class ++ has a "__del__()" method, the derived class’s "__del__()" method, ++ if any, must explicitly call it to ensure proper deletion of the ++ base class part of the instance. ++ ++ It is possible (though not recommended!) for the "__del__()" method ++ to postpone destruction of the instance by creating a new reference ++ to it. This is called object *resurrection*. It is ++ implementation-dependent whether "__del__()" is called a second ++ time when a resurrected object is about to be destroyed; the ++ current *CPython* implementation only calls it once. ++ ++ It is not guaranteed that "__del__()" methods are called for ++ objects that still exist when the interpreter exits. ++ "weakref.finalize" provides a straightforward way to register a ++ cleanup function to be called when an object is garbage collected. ++ ++ Note: ++ ++ "del x" doesn’t directly call "x.__del__()" — the former ++ decrements the reference count for "x" by one, and the latter is ++ only called when "x"’s reference count reaches zero. ++ ++ **CPython implementation detail:** It is possible for a reference ++ cycle to prevent the reference count of an object from going to ++ zero. In this case, the cycle will be later detected and deleted ++ by the *cyclic garbage collector*. A common cause of reference ++ cycles is when an exception has been caught in a local variable. ++ The frame’s locals then reference the exception, which references ++ its own traceback, which references the locals of all frames caught ++ in the traceback. ++ ++ See also: Documentation for the "gc" module. ++ ++ Warning: ++ ++ Due to the precarious circumstances under which "__del__()" ++ methods are invoked, exceptions that occur during their execution ++ are ignored, and a warning is printed to "sys.stderr" instead. ++ In particular: ++ ++ * "__del__()" can be invoked when arbitrary code is being ++ executed, including from any arbitrary thread. If "__del__()" ++ needs to take a lock or invoke any other blocking resource, it ++ may deadlock as the resource may already be taken by the code ++ that gets interrupted to execute "__del__()". ++ ++ * "__del__()" can be executed during interpreter shutdown. As a ++ consequence, the global variables it needs to access (including ++ other modules) may already have been deleted or set to "None". ++ Python guarantees that globals whose name begins with a single ++ underscore are deleted from their module before other globals ++ are deleted; if no other references to such globals exist, this ++ may help in assuring that imported modules are still available ++ at the time when the "__del__()" method is called. ++ ++object.__repr__(self) ++ ++ Called by the "repr()" built-in function to compute the “official†++ string representation of an object. If at all possible, this ++ should look like a valid Python expression that could be used to ++ recreate an object with the same value (given an appropriate ++ environment). If this is not possible, a string of the form ++ "<...some useful description...>" should be returned. The return ++ value must be a string object. If a class defines "__repr__()" but ++ not "__str__()", then "__repr__()" is also used when an “informal†++ string representation of instances of that class is required. ++ ++ This is typically used for debugging, so it is important that the ++ representation is information-rich and unambiguous. A default ++ implementation is provided by the "object" class itself. ++ ++object.__str__(self) ++ ++ Called by "str(object)", the default "__format__()" implementation, ++ and the built-in function "print()", to compute the “informal†or ++ nicely printable string representation of an object. The return ++ value must be a str object. ++ ++ This method differs from "object.__repr__()" in that there is no ++ expectation that "__str__()" return a valid Python expression: a ++ more convenient or concise representation can be used. ++ ++ The default implementation defined by the built-in type "object" ++ calls "object.__repr__()". ++ ++object.__bytes__(self) ++ ++ Called by bytes to compute a byte-string representation of an ++ object. This should return a "bytes" object. The "object" class ++ itself does not provide this method. ++ ++object.__format__(self, format_spec) ++ ++ Called by the "format()" built-in function, and by extension, ++ evaluation of formatted string literals and the "str.format()" ++ method, to produce a “formatted†string representation of an ++ object. The *format_spec* argument is a string that contains a ++ description of the formatting options desired. The interpretation ++ of the *format_spec* argument is up to the type implementing ++ "__format__()", however most classes will either delegate ++ formatting to one of the built-in types, or use a similar ++ formatting option syntax. ++ ++ See Format Specification Mini-Language for a description of the ++ standard formatting syntax. ++ ++ The return value must be a string object. ++ ++ The default implementation by the "object" class should be given an ++ empty *format_spec* string. It delegates to "__str__()". ++ ++ Changed in version 3.4: The __format__ method of "object" itself ++ raises a "TypeError" if passed any non-empty string. ++ ++ Changed in version 3.7: "object.__format__(x, '')" is now ++ equivalent to "str(x)" rather than "format(str(x), '')". ++ ++object.__lt__(self, other) ++object.__le__(self, other) ++object.__eq__(self, other) ++object.__ne__(self, other) ++object.__gt__(self, other) ++object.__ge__(self, other) ++ ++ These are the so-called “rich comparison†methods. The ++ correspondence between operator symbols and method names is as ++ follows: "xy" calls ++ "x.__gt__(y)", and "x>=y" calls "x.__ge__(y)". ++ ++ A rich comparison method may return the singleton "NotImplemented" ++ if it does not implement the operation for a given pair of ++ arguments. By convention, "False" and "True" are returned for a ++ successful comparison. However, these methods can return any value, ++ so if the comparison operator is used in a Boolean context (e.g., ++ in the condition of an "if" statement), Python will call "bool()" ++ on the value to determine if the result is true or false. ++ ++ By default, "object" implements "__eq__()" by using "is", returning ++ "NotImplemented" in the case of a false comparison: "True if x is y ++ else NotImplemented". For "__ne__()", by default it delegates to ++ "__eq__()" and inverts the result unless it is "NotImplemented". ++ There are no other implied relationships among the comparison ++ operators or default implementations; for example, the truth of ++ "(x.__hash__". ++ ++ If a class that does not override "__eq__()" wishes to suppress ++ hash support, it should include "__hash__ = None" in the class ++ definition. A class which defines its own "__hash__()" that ++ explicitly raises a "TypeError" would be incorrectly identified as ++ hashable by an "isinstance(obj, collections.abc.Hashable)" call. ++ ++ Note: ++ ++ By default, the "__hash__()" values of str and bytes objects are ++ “salted†with an unpredictable random value. Although they ++ remain constant within an individual Python process, they are not ++ predictable between repeated invocations of Python.This is ++ intended to provide protection against a denial-of-service caused ++ by carefully chosen inputs that exploit the worst case ++ performance of a dict insertion, *O*(*n*^2) complexity. See ++ http://ocert.org/advisories/ocert-2011-003.html for ++ details.Changing hash values affects the iteration order of sets. ++ Python has never made guarantees about this ordering (and it ++ typically varies between 32-bit and 64-bit builds).See also ++ "PYTHONHASHSEED". ++ ++ Changed in version 3.3: Hash randomization is enabled by default. ++ ++object.__bool__(self) ++ ++ Called to implement truth value testing and the built-in operation ++ "bool()"; should return "False" or "True". When this method is not ++ defined, "__len__()" is called, if it is defined, and the object is ++ considered true if its result is nonzero. If a class defines ++ neither "__len__()" nor "__bool__()" (which is true of the "object" ++ class itself), all its instances are considered true. ++''', ++ 'debugger': r'''"pdb" — The Python Debugger ++*************************** ++ ++**Source code:** Lib/pdb.py ++ ++====================================================================== ++ ++The module "pdb" defines an interactive source code debugger for ++Python programs. It supports setting (conditional) breakpoints and ++single stepping at the source line level, inspection of stack frames, ++source code listing, and evaluation of arbitrary Python code in the ++context of any stack frame. It also supports post-mortem debugging ++and can be called under program control. ++ ++The debugger is extensible – it is actually defined as the class ++"Pdb". This is currently undocumented but easily understood by reading ++the source. The extension interface uses the modules "bdb" and "cmd". ++ ++See also: ++ ++ Module "faulthandler" ++ Used to dump Python tracebacks explicitly, on a fault, after a ++ timeout, or on a user signal. ++ ++ Module "traceback" ++ Standard interface to extract, format and print stack traces of ++ Python programs. ++ ++The typical usage to break into the debugger is to insert: ++ ++ import pdb; pdb.set_trace() ++ ++Or: ++ ++ breakpoint() ++ ++at the location you want to break into the debugger, and then run the ++program. You can then step through the code following this statement, ++and continue running without the debugger using the "continue" ++command. ++ ++Changed in version 3.7: The built-in "breakpoint()", when called with ++defaults, can be used instead of "import pdb; pdb.set_trace()". ++ ++ def double(x): ++ breakpoint() ++ return x * 2 ++ val = 3 ++ print(f"{val} * 2 is {double(val)}") ++ ++The debugger’s prompt is "(Pdb)", which is the indicator that you are ++in debug mode: ++ ++ > ...(2)double() ++ -> breakpoint() ++ (Pdb) p x ++ 3 ++ (Pdb) continue ++ 3 * 2 is 6 ++ ++Changed in version 3.3: Tab-completion via the "readline" module is ++available for commands and command arguments, e.g. the current global ++and local names are offered as arguments of the "p" command. ++ ++You can also invoke "pdb" from the command line to debug other ++scripts. For example: ++ ++ python -m pdb myscript.py ++ ++When invoked as a module, pdb will automatically enter post-mortem ++debugging if the program being debugged exits abnormally. After post- ++mortem debugging (or after normal exit of the program), pdb will ++restart the program. Automatic restarting preserves pdb’s state (such ++as breakpoints) and in most cases is more useful than quitting the ++debugger upon program’s exit. ++ ++Changed in version 3.2: Added the "-c" option to execute commands as ++if given in a ".pdbrc" file; see Debugger Commands. ++ ++Changed in version 3.7: Added the "-m" option to execute modules ++similar to the way "python -m" does. As with a script, the debugger ++will pause execution just before the first line of the module. ++ ++Typical usage to execute a statement under control of the debugger is: ++ ++ >>> import pdb ++ >>> def f(x): ++ ... print(1 / x) ++ >>> pdb.run("f(2)") ++ > (1)() ++ (Pdb) continue ++ 0.5 ++ >>> ++ ++The typical usage to inspect a crashed program is: ++ ++ >>> import pdb ++ >>> def f(x): ++ ... print(1 / x) ++ ... ++ >>> f(0) ++ Traceback (most recent call last): ++ File "", line 1, in ++ File "", line 2, in f ++ ZeroDivisionError: division by zero ++ >>> pdb.pm() ++ > (2)f() ++ (Pdb) p x ++ 0 ++ (Pdb) ++ ++Changed in version 3.13: The implementation of **PEP 667** means that ++name assignments made via "pdb" will immediately affect the active ++scope, even when running inside an *optimized scope*. ++ ++The module defines the following functions; each enters the debugger ++in a slightly different way: ++ ++pdb.run(statement, globals=None, locals=None) ++ ++ Execute the *statement* (given as a string or a code object) under ++ debugger control. The debugger prompt appears before any code is ++ executed; you can set breakpoints and type "continue", or you can ++ step through the statement using "step" or "next" (all these ++ commands are explained below). The optional *globals* and *locals* ++ arguments specify the environment in which the code is executed; by ++ default the dictionary of the module "__main__" is used. (See the ++ explanation of the built-in "exec()" or "eval()" functions.) ++ ++pdb.runeval(expression, globals=None, locals=None) ++ ++ Evaluate the *expression* (given as a string or a code object) ++ under debugger control. When "runeval()" returns, it returns the ++ value of the *expression*. Otherwise this function is similar to ++ "run()". ++ ++pdb.runcall(function, *args, **kwds) ++ ++ Call the *function* (a function or method object, not a string) ++ with the given arguments. When "runcall()" returns, it returns ++ whatever the function call returned. The debugger prompt appears ++ as soon as the function is entered. ++ ++pdb.set_trace(*, header=None, commands=None) ++ ++ Enter the debugger at the calling stack frame. This is useful to ++ hard-code a breakpoint at a given point in a program, even if the ++ code is not otherwise being debugged (e.g. when an assertion ++ fails). If given, *header* is printed to the console just before ++ debugging begins. The *commands* argument, if given, is a list of ++ commands to execute when the debugger starts. ++ ++ Changed in version 3.7: The keyword-only argument *header*. ++ ++ Changed in version 3.13: "set_trace()" will enter the debugger ++ immediately, rather than on the next line of code to be executed. ++ ++ Added in version 3.14: The *commands* argument. ++ ++pdb.post_mortem(t=None) ++ ++ Enter post-mortem debugging of the given exception or traceback ++ object. If no value is given, it uses the exception that is ++ currently being handled, or raises "ValueError" if there isn’t one. ++ ++ Changed in version 3.13: Support for exception objects was added. ++ ++pdb.pm() ++ ++ Enter post-mortem debugging of the exception found in ++ "sys.last_exc". ++ ++The "run*" functions and "set_trace()" are aliases for instantiating ++the "Pdb" class and calling the method of the same name. If you want ++to access further features, you have to do this yourself: ++ ++class pdb.Pdb(completekey='tab', stdin=None, stdout=None, skip=None, nosigint=False, readrc=True, mode=None) ++ ++ "Pdb" is the debugger class. ++ ++ The *completekey*, *stdin* and *stdout* arguments are passed to the ++ underlying "cmd.Cmd" class; see the description there. ++ ++ The *skip* argument, if given, must be an iterable of glob-style ++ module name patterns. The debugger will not step into frames that ++ originate in a module that matches one of these patterns. [1] ++ ++ By default, Pdb sets a handler for the SIGINT signal (which is sent ++ when the user presses "Ctrl-C" on the console) when you give a ++ "continue" command. This allows you to break into the debugger ++ again by pressing "Ctrl-C". If you want Pdb not to touch the ++ SIGINT handler, set *nosigint* to true. ++ ++ The *readrc* argument defaults to true and controls whether Pdb ++ will load .pdbrc files from the filesystem. ++ ++ The *mode* argument specifies how the debugger was invoked. It ++ impacts the workings of some debugger commands. Valid values are ++ "'inline'" (used by the breakpoint() builtin), "'cli'" (used by the ++ command line invocation) or "None" (for backwards compatible ++ behaviour, as before the *mode* argument was added). ++ ++ Example call to enable tracing with *skip*: ++ ++ import pdb; pdb.Pdb(skip=['django.*']).set_trace() ++ ++ Raises an auditing event "pdb.Pdb" with no arguments. ++ ++ Changed in version 3.1: Added the *skip* parameter. ++ ++ Changed in version 3.2: Added the *nosigint* parameter. Previously, ++ a SIGINT handler was never set by Pdb. ++ ++ Changed in version 3.6: The *readrc* argument. ++ ++ Added in version 3.14: Added the *mode* argument. ++ ++ run(statement, globals=None, locals=None) ++ runeval(expression, globals=None, locals=None) ++ runcall(function, *args, **kwds) ++ set_trace() ++ ++ See the documentation for the functions explained above. ++ ++ ++Debugger Commands ++================= ++ ++The commands recognized by the debugger are listed below. Most ++commands can be abbreviated to one or two letters as indicated; e.g. ++"h(elp)" means that either "h" or "help" can be used to enter the help ++command (but not "he" or "hel", nor "H" or "Help" or "HELP"). ++Arguments to commands must be separated by whitespace (spaces or ++tabs). Optional arguments are enclosed in square brackets ("[]") in ++the command syntax; the square brackets must not be typed. ++Alternatives in the command syntax are separated by a vertical bar ++("|"). ++ ++Entering a blank line repeats the last command entered. Exception: if ++the last command was a "list" command, the next 11 lines are listed. ++ ++Commands that the debugger doesn’t recognize are assumed to be Python ++statements and are executed in the context of the program being ++debugged. Python statements can also be prefixed with an exclamation ++point ("!"). This is a powerful way to inspect the program being ++debugged; it is even possible to change a variable or call a function. ++When an exception occurs in such a statement, the exception name is ++printed but the debugger’s state is not changed. ++ ++Changed in version 3.13: Expressions/Statements whose prefix is a pdb ++command are now correctly identified and executed. ++ ++The debugger supports aliases. Aliases can have parameters which ++allows one a certain level of adaptability to the context under ++examination. ++ ++Multiple commands may be entered on a single line, separated by ";;". ++(A single ";" is not used as it is the separator for multiple commands ++in a line that is passed to the Python parser.) No intelligence is ++applied to separating the commands; the input is split at the first ++";;" pair, even if it is in the middle of a quoted string. A ++workaround for strings with double semicolons is to use implicit ++string concatenation "';'';'" or "";"";"". ++ ++To set a temporary global variable, use a *convenience variable*. A ++*convenience variable* is a variable whose name starts with "$". For ++example, "$foo = 1" sets a global variable "$foo" which you can use in ++the debugger session. The *convenience variables* are cleared when ++the program resumes execution so it’s less likely to interfere with ++your program compared to using normal variables like "foo = 1". ++ ++There are three preset *convenience variables*: ++ ++* "$_frame": the current frame you are debugging ++ ++* "$_retval": the return value if the frame is returning ++ ++* "$_exception": the exception if the frame is raising an exception ++ ++Added in version 3.12: Added the *convenience variable* feature. ++ ++If a file ".pdbrc" exists in the user’s home directory or in the ++current directory, it is read with "'utf-8'" encoding and executed as ++if it had been typed at the debugger prompt, with the exception that ++empty lines and lines starting with "#" are ignored. This is ++particularly useful for aliases. If both files exist, the one in the ++home directory is read first and aliases defined there can be ++overridden by the local file. ++ ++Changed in version 3.2: ".pdbrc" can now contain commands that ++continue debugging, such as "continue" or "next". Previously, these ++commands had no effect. ++ ++Changed in version 3.11: ".pdbrc" is now read with "'utf-8'" encoding. ++Previously, it was read with the system locale encoding. ++ ++h(elp) [command] ++ ++ Without argument, print the list of available commands. With a ++ *command* as argument, print help about that command. "help pdb" ++ displays the full documentation (the docstring of the "pdb" ++ module). Since the *command* argument must be an identifier, "help ++ exec" must be entered to get help on the "!" command. ++ ++w(here) [count] ++ ++ Print a stack trace, with the most recent frame at the bottom. if ++ *count* is 0, print the current frame entry. If *count* is ++ negative, print the least recent - *count* frames. If *count* is ++ positive, print the most recent *count* frames. An arrow (">") ++ indicates the current frame, which determines the context of most ++ commands. ++ ++ Changed in version 3.14: *count* argument is added. ++ ++d(own) [count] ++ ++ Move the current frame *count* (default one) levels down in the ++ stack trace (to a newer frame). ++ ++u(p) [count] ++ ++ Move the current frame *count* (default one) levels up in the stack ++ trace (to an older frame). ++ ++b(reak) [([filename:]lineno | function) [, condition]] ++ ++ With a *lineno* argument, set a break at line *lineno* in the ++ current file. The line number may be prefixed with a *filename* and ++ a colon, to specify a breakpoint in another file (possibly one that ++ hasn’t been loaded yet). The file is searched on "sys.path". ++ Acceptable forms of *filename* are "/abspath/to/file.py", ++ "relpath/file.py", "module" and "package.module". ++ ++ With a *function* argument, set a break at the first executable ++ statement within that function. *function* can be any expression ++ that evaluates to a function in the current namespace. ++ ++ If a second argument is present, it is an expression which must ++ evaluate to true before the breakpoint is honored. ++ ++ Without argument, list all breaks, including for each breakpoint, ++ the number of times that breakpoint has been hit, the current ++ ignore count, and the associated condition if any. ++ ++ Each breakpoint is assigned a number to which all the other ++ breakpoint commands refer. ++ ++tbreak [([filename:]lineno | function) [, condition]] ++ ++ Temporary breakpoint, which is removed automatically when it is ++ first hit. The arguments are the same as for "break". ++ ++cl(ear) [filename:lineno | bpnumber ...] ++ ++ With a *filename:lineno* argument, clear all the breakpoints at ++ this line. With a space separated list of breakpoint numbers, clear ++ those breakpoints. Without argument, clear all breaks (but first ++ ask confirmation). ++ ++disable bpnumber [bpnumber ...] ++ ++ Disable the breakpoints given as a space separated list of ++ breakpoint numbers. Disabling a breakpoint means it cannot cause ++ the program to stop execution, but unlike clearing a breakpoint, it ++ remains in the list of breakpoints and can be (re-)enabled. ++ ++enable bpnumber [bpnumber ...] ++ ++ Enable the breakpoints specified. ++ ++ignore bpnumber [count] ++ ++ Set the ignore count for the given breakpoint number. If *count* ++ is omitted, the ignore count is set to 0. A breakpoint becomes ++ active when the ignore count is zero. When non-zero, the *count* ++ is decremented each time the breakpoint is reached and the ++ breakpoint is not disabled and any associated condition evaluates ++ to true. ++ ++condition bpnumber [condition] ++ ++ Set a new *condition* for the breakpoint, an expression which must ++ evaluate to true before the breakpoint is honored. If *condition* ++ is absent, any existing condition is removed; i.e., the breakpoint ++ is made unconditional. ++ ++commands [bpnumber] ++ ++ Specify a list of commands for breakpoint number *bpnumber*. The ++ commands themselves appear on the following lines. Type a line ++ containing just "end" to terminate the commands. An example: ++ ++ (Pdb) commands 1 ++ (com) p some_variable ++ (com) end ++ (Pdb) ++ ++ To remove all commands from a breakpoint, type "commands" and ++ follow it immediately with "end"; that is, give no commands. ++ ++ With no *bpnumber* argument, "commands" refers to the last ++ breakpoint set. ++ ++ You can use breakpoint commands to start your program up again. ++ Simply use the "continue" command, or "step", or any other command ++ that resumes execution. ++ ++ Specifying any command resuming execution (currently "continue", ++ "step", "next", "return", "until", "jump", "quit" and their ++ abbreviations) terminates the command list (as if that command was ++ immediately followed by end). This is because any time you resume ++ execution (even with a simple next or step), you may encounter ++ another breakpoint—which could have its own command list, leading ++ to ambiguities about which list to execute. ++ ++ If the list of commands contains the "silent" command, or a command ++ that resumes execution, then the breakpoint message containing ++ information about the frame is not displayed. ++ ++ Changed in version 3.14: Frame information will not be displayed if ++ a command that resumes execution is present in the command list. ++ ++s(tep) ++ ++ Execute the current line, stop at the first possible occasion ++ (either in a function that is called or on the next line in the ++ current function). ++ ++n(ext) ++ ++ Continue execution until the next line in the current function is ++ reached or it returns. (The difference between "next" and "step" ++ is that "step" stops inside a called function, while "next" ++ executes called functions at (nearly) full speed, only stopping at ++ the next line in the current function.) ++ ++unt(il) [lineno] ++ ++ Without argument, continue execution until the line with a number ++ greater than the current one is reached. ++ ++ With *lineno*, continue execution until a line with a number ++ greater or equal to *lineno* is reached. In both cases, also stop ++ when the current frame returns. ++ ++ Changed in version 3.2: Allow giving an explicit line number. ++ ++r(eturn) ++ ++ Continue execution until the current function returns. ++ ++c(ont(inue)) ++ ++ Continue execution, only stop when a breakpoint is encountered. ++ ++j(ump) lineno ++ ++ Set the next line that will be executed. Only available in the ++ bottom-most frame. This lets you jump back and execute code again, ++ or jump forward to skip code that you don’t want to run. ++ ++ It should be noted that not all jumps are allowed – for instance it ++ is not possible to jump into the middle of a "for" loop or out of a ++ "finally" clause. ++ ++l(ist) [first[, last]] ++ ++ List source code for the current file. Without arguments, list 11 ++ lines around the current line or continue the previous listing. ++ With "." as argument, list 11 lines around the current line. With ++ one argument, list 11 lines around at that line. With two ++ arguments, list the given range; if the second argument is less ++ than the first, it is interpreted as a count. ++ ++ The current line in the current frame is indicated by "->". If an ++ exception is being debugged, the line where the exception was ++ originally raised or propagated is indicated by ">>", if it differs ++ from the current line. ++ ++ Changed in version 3.2: Added the ">>" marker. ++ ++ll | longlist ++ ++ List all source code for the current function or frame. ++ Interesting lines are marked as for "list". ++ ++ Added in version 3.2. ++ ++a(rgs) ++ ++ Print the arguments of the current function and their current ++ values. ++ ++p expression ++ ++ Evaluate *expression* in the current context and print its value. ++ ++ Note: ++ ++ "print()" can also be used, but is not a debugger command — this ++ executes the Python "print()" function. ++ ++pp expression ++ ++ Like the "p" command, except the value of *expression* is pretty- ++ printed using the "pprint" module. ++ ++whatis expression ++ ++ Print the type of *expression*. ++ ++source expression ++ ++ Try to get source code of *expression* and display it. ++ ++ Added in version 3.2. ++ ++display [expression] ++ ++ Display the value of *expression* if it changed, each time ++ execution stops in the current frame. ++ ++ Without *expression*, list all display expressions for the current ++ frame. ++ ++ Note: ++ ++ Display evaluates *expression* and compares to the result of the ++ previous evaluation of *expression*, so when the result is ++ mutable, display may not be able to pick up the changes. ++ ++ Example: ++ ++ lst = [] ++ breakpoint() ++ pass ++ lst.append(1) ++ print(lst) ++ ++ Display won’t realize "lst" has been changed because the result of ++ evaluation is modified in place by "lst.append(1)" before being ++ compared: ++ ++ > example.py(3)() ++ -> pass ++ (Pdb) display lst ++ display lst: [] ++ (Pdb) n ++ > example.py(4)() ++ -> lst.append(1) ++ (Pdb) n ++ > example.py(5)() ++ -> print(lst) ++ (Pdb) ++ ++ You can do some tricks with copy mechanism to make it work: ++ ++ > example.py(3)() ++ -> pass ++ (Pdb) display lst[:] ++ display lst[:]: [] ++ (Pdb) n ++ > example.py(4)() ++ -> lst.append(1) ++ (Pdb) n ++ > example.py(5)() ++ -> print(lst) ++ display lst[:]: [1] [old: []] ++ (Pdb) ++ ++ Added in version 3.2. ++ ++undisplay [expression] ++ ++ Do not display *expression* anymore in the current frame. Without ++ *expression*, clear all display expressions for the current frame. ++ ++ Added in version 3.2. ++ ++interact ++ ++ Start an interactive interpreter (using the "code" module) in a new ++ global namespace initialised from the local and global namespaces ++ for the current scope. Use "exit()" or "quit()" to exit the ++ interpreter and return to the debugger. ++ ++ Note: ++ ++ As "interact" creates a new dedicated namespace for code ++ execution, assignments to variables will not affect the original ++ namespaces. However, modifications to any referenced mutable ++ objects will be reflected in the original namespaces as usual. ++ ++ Added in version 3.2. ++ ++ Changed in version 3.13: "exit()" and "quit()" can be used to exit ++ the "interact" command. ++ ++ Changed in version 3.13: "interact" directs its output to the ++ debugger’s output channel rather than "sys.stderr". ++ ++alias [name [command]] ++ ++ Create an alias called *name* that executes *command*. The ++ *command* must *not* be enclosed in quotes. Replaceable parameters ++ can be indicated by "%1", "%2", … and "%9", while "%*" is replaced ++ by all the parameters. If *command* is omitted, the current alias ++ for *name* is shown. If no arguments are given, all aliases are ++ listed. ++ ++ Aliases may be nested and can contain anything that can be legally ++ typed at the pdb prompt. Note that internal pdb commands *can* be ++ overridden by aliases. Such a command is then hidden until the ++ alias is removed. Aliasing is recursively applied to the first ++ word of the command line; all other words in the line are left ++ alone. ++ ++ As an example, here are two useful aliases (especially when placed ++ in the ".pdbrc" file): ++ ++ # Print instance variables (usage "pi classInst") ++ alias pi for k in %1.__dict__.keys(): print(f"%1.{k} = {%1.__dict__[k]}") ++ # Print instance variables in self ++ alias ps pi self ++ ++unalias name ++ ++ Delete the specified alias *name*. ++ ++! statement ++ ++ Execute the (one-line) *statement* in the context of the current ++ stack frame. The exclamation point can be omitted unless the first ++ word of the statement resembles a debugger command, e.g.: ++ ++ (Pdb) ! n=42 ++ (Pdb) ++ ++ To set a global variable, you can prefix the assignment command ++ with a "global" statement on the same line, e.g.: ++ ++ (Pdb) global list_options; list_options = ['-l'] ++ (Pdb) ++ ++run [args ...] ++restart [args ...] ++ ++ Restart the debugged Python program. If *args* is supplied, it is ++ split with "shlex" and the result is used as the new "sys.argv". ++ History, breakpoints, actions and debugger options are preserved. ++ "restart" is an alias for "run". ++ ++ Changed in version 3.14: "run" and "restart" commands are disabled ++ when the debugger is invoked in "'inline'" mode. ++ ++q(uit) ++ ++ Quit from the debugger. The program being executed is aborted. An ++ end-of-file input is equivalent to "quit". ++ ++ A confirmation prompt will be shown if the debugger is invoked in ++ "'inline'" mode. Either "y", "Y", "" or "EOF" will confirm ++ the quit. ++ ++ Changed in version 3.14: A confirmation prompt will be shown if the ++ debugger is invoked in "'inline'" mode. After the confirmation, the ++ debugger will call "sys.exit()" immediately, instead of raising ++ "bdb.BdbQuit" in the next trace event. ++ ++debug code ++ ++ Enter a recursive debugger that steps through *code* (which is an ++ arbitrary expression or statement to be executed in the current ++ environment). ++ ++retval ++ ++ Print the return value for the last return of the current function. ++ ++exceptions [excnumber] ++ ++ List or jump between chained exceptions. ++ ++ When using "pdb.pm()" or "Pdb.post_mortem(...)" with a chained ++ exception instead of a traceback, it allows the user to move ++ between the chained exceptions using "exceptions" command to list ++ exceptions, and "exception " to switch to that exception. ++ ++ Example: ++ ++ def out(): ++ try: ++ middle() ++ except Exception as e: ++ raise ValueError("reraise middle() error") from e ++ ++ def middle(): ++ try: ++ return inner(0) ++ except Exception as e: ++ raise ValueError("Middle fail") ++ ++ def inner(x): ++ 1 / x ++ ++ out() ++ ++ calling "pdb.pm()" will allow to move between exceptions: ++ ++ > example.py(5)out() ++ -> raise ValueError("reraise middle() error") from e ++ ++ (Pdb) exceptions ++ 0 ZeroDivisionError('division by zero') ++ 1 ValueError('Middle fail') ++ > 2 ValueError('reraise middle() error') ++ ++ (Pdb) exceptions 0 ++ > example.py(16)inner() ++ -> 1 / x ++ ++ (Pdb) up ++ > example.py(10)middle() ++ -> return inner(0) ++ ++ Added in version 3.13. ++ ++-[ Footnotes ]- ++ ++[1] Whether a frame is considered to originate in a certain module is ++ determined by the "__name__" in the frame globals. ++''', ++ 'del': r'''The "del" statement ++******************* ++ ++ **del_stmt**: "del" "target_list" ++ ++Deletion is recursively defined very similar to the way assignment is ++defined. Rather than spelling it out in full details, here are some ++hints. ++ ++Deletion of a target list recursively deletes each target, from left ++to right. ++ ++Deletion of a name removes the binding of that name from the local or ++global namespace, depending on whether the name occurs in a "global" ++statement in the same code block. If the name is unbound, a ++"NameError" exception will be raised. ++ ++Deletion of attribute references, subscriptions and slicings is passed ++to the primary object involved; deletion of a slicing is in general ++equivalent to assignment of an empty slice of the right type (but even ++this is determined by the sliced object). ++ ++Changed in version 3.2: Previously it was illegal to delete a name ++from the local namespace if it occurs as a free variable in a nested ++block. ++''', ++ 'dict': r'''Dictionary displays ++******************* ++ ++A dictionary display is a possibly empty series of dict items ++(key/value pairs) enclosed in curly braces: ++ ++ **dict_display**: "{" ["dict_item_list" | "dict_comprehension"] "}" ++ **dict_item_list**: "dict_item" ("," "dict_item")* [","] ++ **dict_item**: "expression" ":" "expression" | "**" "or_expr" ++ **dict_comprehension**: "expression" ":" "expression" "comp_for" ++ ++A dictionary display yields a new dictionary object. ++ ++If a comma-separated sequence of dict items is given, they are ++evaluated from left to right to define the entries of the dictionary: ++each key object is used as a key into the dictionary to store the ++corresponding value. This means that you can specify the same key ++multiple times in the dict item list, and the final dictionary’s value ++for that key will be the last one given. ++ ++A double asterisk "**" denotes *dictionary unpacking*. Its operand ++must be a *mapping*. Each mapping item is added to the new ++dictionary. Later values replace values already set by earlier dict ++items and earlier dictionary unpackings. ++ ++Added in version 3.5: Unpacking into dictionary displays, originally ++proposed by **PEP 448**. ++ ++A dict comprehension, in contrast to list and set comprehensions, ++needs two expressions separated with a colon followed by the usual ++“for†and “if†clauses. When the comprehension is run, the resulting ++key and value elements are inserted in the new dictionary in the order ++they are produced. ++ ++Restrictions on the types of the key values are listed earlier in ++section The standard type hierarchy. (To summarize, the key type ++should be *hashable*, which excludes all mutable objects.) Clashes ++between duplicate keys are not detected; the last value (textually ++rightmost in the display) stored for a given key value prevails. ++ ++Changed in version 3.8: Prior to Python 3.8, in dict comprehensions, ++the evaluation order of key and value was not well-defined. In ++CPython, the value was evaluated before the key. Starting with 3.8, ++the key is evaluated before the value, as proposed by **PEP 572**. ++''', ++ 'dynamic-features': r'''Interaction with dynamic features ++********************************* ++ ++Name resolution of free variables occurs at runtime, not at compile ++time. This means that the following code will print 42: ++ ++ i = 10 ++ def f(): ++ print(i) ++ i = 42 ++ f() ++ ++The "eval()" and "exec()" functions do not have access to the full ++environment for resolving names. Names may be resolved in the local ++and global namespaces of the caller. Free variables are not resolved ++in the nearest enclosing namespace, but in the global namespace. [1] ++The "exec()" and "eval()" functions have optional arguments to ++override the global and local namespace. If only one namespace is ++specified, it is used for both. ++''', ++ 'else': r'''The "if" statement ++****************** ++ ++The "if" statement is used for conditional execution: ++ ++ **if_stmt**: "if" "assignment_expression" ":" "suite" ++ ("elif" "assignment_expression" ":" "suite")* ++ ["else" ":" "suite"] ++ ++It selects exactly one of the suites by evaluating the expressions one ++by one until one is found to be true (see section Boolean operations ++for the definition of true and false); then that suite is executed ++(and no other part of the "if" statement is executed or evaluated). ++If all expressions are false, the suite of the "else" clause, if ++present, is executed. ++''', ++ 'exceptions': r'''Exceptions ++********** ++ ++Exceptions are a means of breaking out of the normal flow of control ++of a code block in order to handle errors or other exceptional ++conditions. An exception is *raised* at the point where the error is ++detected; it may be *handled* by the surrounding code block or by any ++code block that directly or indirectly invoked the code block where ++the error occurred. ++ ++The Python interpreter raises an exception when it detects a run-time ++error (such as division by zero). A Python program can also ++explicitly raise an exception with the "raise" statement. Exception ++handlers are specified with the "try" … "except" statement. The ++"finally" clause of such a statement can be used to specify cleanup ++code which does not handle the exception, but is executed whether an ++exception occurred or not in the preceding code. ++ ++Python uses the “termination†model of error handling: an exception ++handler can find out what happened and continue execution at an outer ++level, but it cannot repair the cause of the error and retry the ++failing operation (except by re-entering the offending piece of code ++from the top). ++ ++When an exception is not handled at all, the interpreter terminates ++execution of the program, or returns to its interactive main loop. In ++either case, it prints a stack traceback, except when the exception is ++"SystemExit". ++ ++Exceptions are identified by class instances. The "except" clause is ++selected depending on the class of the instance: it must reference the ++class of the instance or a *non-virtual base class* thereof. The ++instance can be received by the handler and can carry additional ++information about the exceptional condition. ++ ++Note: ++ ++ Exception messages are not part of the Python API. Their contents ++ may change from one version of Python to the next without warning ++ and should not be relied on by code which will run under multiple ++ versions of the interpreter. ++ ++See also the description of the "try" statement in section The try ++statement and "raise" statement in section The raise statement. ++ ++-[ Footnotes ]- ++ ++[1] This limitation occurs because the code that is executed by these ++ operations is not available at the time the module is compiled. ++''', ++ 'execmodel': r'''Execution model ++*************** ++ ++ ++Structure of a program ++====================== ++ ++A Python program is constructed from code blocks. A *block* is a piece ++of Python program text that is executed as a unit. The following are ++blocks: a module, a function body, and a class definition. Each ++command typed interactively is a block. A script file (a file given ++as standard input to the interpreter or specified as a command line ++argument to the interpreter) is a code block. A script command (a ++command specified on the interpreter command line with the "-c" ++option) is a code block. A module run as a top level script (as module ++"__main__") from the command line using a "-m" argument is also a code ++block. The string argument passed to the built-in functions "eval()" ++and "exec()" is a code block. ++ ++A code block is executed in an *execution frame*. A frame contains ++some administrative information (used for debugging) and determines ++where and how execution continues after the code block’s execution has ++completed. ++ ++ ++Naming and binding ++================== ++ ++ ++Binding of names ++---------------- ++ ++*Names* refer to objects. Names are introduced by name binding ++operations. ++ ++The following constructs bind names: ++ ++* formal parameters to functions, ++ ++* class definitions, ++ ++* function definitions, ++ ++* assignment expressions, ++ ++* targets that are identifiers if occurring in an assignment: ++ ++ * "for" loop header, ++ ++ * after "as" in a "with" statement, "except" clause, "except*" ++ clause, or in the as-pattern in structural pattern matching, ++ ++ * in a capture pattern in structural pattern matching ++ ++* "import" statements. ++ ++* "type" statements. ++ ++* type parameter lists. ++ ++The "import" statement of the form "from ... import *" binds all names ++defined in the imported module, except those beginning with an ++underscore. This form may only be used at the module level. ++ ++A target occurring in a "del" statement is also considered bound for ++this purpose (though the actual semantics are to unbind the name). ++ ++Each assignment or import statement occurs within a block defined by a ++class or function definition or at the module level (the top-level ++code block). ++ ++If a name is bound in a block, it is a local variable of that block, ++unless declared as "nonlocal" or "global". If a name is bound at the ++module level, it is a global variable. (The variables of the module ++code block are local and global.) If a variable is used in a code ++block but not defined there, it is a *free variable*. ++ ++Each occurrence of a name in the program text refers to the *binding* ++of that name established by the following name resolution rules. ++ ++ ++Resolution of names ++------------------- ++ ++A *scope* defines the visibility of a name within a block. If a local ++variable is defined in a block, its scope includes that block. If the ++definition occurs in a function block, the scope extends to any blocks ++contained within the defining one, unless a contained block introduces ++a different binding for the name. ++ ++When a name is used in a code block, it is resolved using the nearest ++enclosing scope. The set of all such scopes visible to a code block ++is called the block’s *environment*. ++ ++When a name is not found at all, a "NameError" exception is raised. If ++the current scope is a function scope, and the name refers to a local ++variable that has not yet been bound to a value at the point where the ++name is used, an "UnboundLocalError" exception is raised. ++"UnboundLocalError" is a subclass of "NameError". ++ ++If a name binding operation occurs anywhere within a code block, all ++uses of the name within the block are treated as references to the ++current block. This can lead to errors when a name is used within a ++block before it is bound. This rule is subtle. Python lacks ++declarations and allows name binding operations to occur anywhere ++within a code block. The local variables of a code block can be ++determined by scanning the entire text of the block for name binding ++operations. See the FAQ entry on UnboundLocalError for examples. ++ ++If the "global" statement occurs within a block, all uses of the names ++specified in the statement refer to the bindings of those names in the ++top-level namespace. Names are resolved in the top-level namespace by ++searching the global namespace, i.e. the namespace of the module ++containing the code block, and the builtins namespace, the namespace ++of the module "builtins". The global namespace is searched first. If ++the names are not found there, the builtins namespace is searched ++next. If the names are also not found in the builtins namespace, new ++variables are created in the global namespace. The global statement ++must precede all uses of the listed names. ++ ++The "global" statement has the same scope as a name binding operation ++in the same block. If the nearest enclosing scope for a free variable ++contains a global statement, the free variable is treated as a global. ++ ++The "nonlocal" statement causes corresponding names to refer to ++previously bound variables in the nearest enclosing function scope. ++"SyntaxError" is raised at compile time if the given name does not ++exist in any enclosing function scope. Type parameters cannot be ++rebound with the "nonlocal" statement. ++ ++The namespace for a module is automatically created the first time a ++module is imported. The main module for a script is always called ++"__main__". ++ ++Class definition blocks and arguments to "exec()" and "eval()" are ++special in the context of name resolution. A class definition is an ++executable statement that may use and define names. These references ++follow the normal rules for name resolution with an exception that ++unbound local variables are looked up in the global namespace. The ++namespace of the class definition becomes the attribute dictionary of ++the class. The scope of names defined in a class block is limited to ++the class block; it does not extend to the code blocks of methods. ++This includes comprehensions and generator expressions, but it does ++not include annotation scopes, which have access to their enclosing ++class scopes. This means that the following will fail: ++ ++ class A: ++ a = 42 ++ b = list(a + i for i in range(10)) ++ ++However, the following will succeed: ++ ++ class A: ++ type Alias = Nested ++ class Nested: pass ++ ++ print(A.Alias.__value__) # ++ ++ ++Annotation scopes ++----------------- ++ ++*Annotations*, type parameter lists and "type" statements introduce ++*annotation scopes*, which behave mostly like function scopes, but ++with some exceptions discussed below. ++ ++Annotation scopes are used in the following contexts: ++ ++* *Function annotations*. ++ ++* *Variable annotations*. ++ ++* Type parameter lists for generic type aliases. ++ ++* Type parameter lists for generic functions. A generic function’s ++ annotations are executed within the annotation scope, but its ++ defaults and decorators are not. ++ ++* Type parameter lists for generic classes. A generic class’s base ++ classes and keyword arguments are executed within the annotation ++ scope, but its decorators are not. ++ ++* The bounds, constraints, and default values for type parameters ++ (lazily evaluated). ++ ++* The value of type aliases (lazily evaluated). ++ ++Annotation scopes differ from function scopes in the following ways: ++ ++* Annotation scopes have access to their enclosing class namespace. If ++ an annotation scope is immediately within a class scope, or within ++ another annotation scope that is immediately within a class scope, ++ the code in the annotation scope can use names defined in the class ++ scope as if it were executed directly within the class body. This ++ contrasts with regular functions defined within classes, which ++ cannot access names defined in the class scope. ++ ++* Expressions in annotation scopes cannot contain "yield", "yield ++ from", "await", or ":=" expressions. (These expressions are allowed ++ in other scopes contained within the annotation scope.) ++ ++* Names defined in annotation scopes cannot be rebound with "nonlocal" ++ statements in inner scopes. This includes only type parameters, as ++ no other syntactic elements that can appear within annotation scopes ++ can introduce new names. ++ ++* While annotation scopes have an internal name, that name is not ++ reflected in the *qualified name* of objects defined within the ++ scope. Instead, the "__qualname__" of such objects is as if the ++ object were defined in the enclosing scope. ++ ++Added in version 3.12: Annotation scopes were introduced in Python ++3.12 as part of **PEP 695**. ++ ++Changed in version 3.13: Annotation scopes are also used for type ++parameter defaults, as introduced by **PEP 696**. ++ ++Changed in version 3.14: Annotation scopes are now also used for ++annotations, as specified in **PEP 649** and **PEP 749**. ++ ++ ++Lazy evaluation ++--------------- ++ ++Most annotation scopes are *lazily evaluated*. This includes ++annotations, the values of type aliases created through the "type" ++statement, and the bounds, constraints, and default values of type ++variables created through the type parameter syntax. This means that ++they are not evaluated when the type alias or type variable is ++created, or when the object carrying annotations is created. Instead, ++they are only evaluated when necessary, for example when the ++"__value__" attribute on a type alias is accessed. ++ ++Example: ++ ++ >>> type Alias = 1/0 ++ >>> Alias.__value__ ++ Traceback (most recent call last): ++ ... ++ ZeroDivisionError: division by zero ++ >>> def func[T: 1/0](): pass ++ >>> T = func.__type_params__[0] ++ >>> T.__bound__ ++ Traceback (most recent call last): ++ ... ++ ZeroDivisionError: division by zero ++ ++Here the exception is raised only when the "__value__" attribute of ++the type alias or the "__bound__" attribute of the type variable is ++accessed. ++ ++This behavior is primarily useful for references to types that have ++not yet been defined when the type alias or type variable is created. ++For example, lazy evaluation enables creation of mutually recursive ++type aliases: ++ ++ from typing import Literal ++ ++ type SimpleExpr = int | Parenthesized ++ type Parenthesized = tuple[Literal["("], Expr, Literal[")"]] ++ type Expr = SimpleExpr | tuple[SimpleExpr, Literal["+", "-"], Expr] ++ ++Lazily evaluated values are evaluated in annotation scope, which means ++that names that appear inside the lazily evaluated value are looked up ++as if they were used in the immediately enclosing scope. ++ ++Added in version 3.12. ++ ++ ++Builtins and restricted execution ++--------------------------------- ++ ++**CPython implementation detail:** Users should not touch ++"__builtins__"; it is strictly an implementation detail. Users ++wanting to override values in the builtins namespace should "import" ++the "builtins" module and modify its attributes appropriately. ++ ++The builtins namespace associated with the execution of a code block ++is actually found by looking up the name "__builtins__" in its global ++namespace; this should be a dictionary or a module (in the latter case ++the module’s dictionary is used). By default, when in the "__main__" ++module, "__builtins__" is the built-in module "builtins"; when in any ++other module, "__builtins__" is an alias for the dictionary of the ++"builtins" module itself. ++ ++ ++Interaction with dynamic features ++--------------------------------- ++ ++Name resolution of free variables occurs at runtime, not at compile ++time. This means that the following code will print 42: ++ ++ i = 10 ++ def f(): ++ print(i) ++ i = 42 ++ f() ++ ++The "eval()" and "exec()" functions do not have access to the full ++environment for resolving names. Names may be resolved in the local ++and global namespaces of the caller. Free variables are not resolved ++in the nearest enclosing namespace, but in the global namespace. [1] ++The "exec()" and "eval()" functions have optional arguments to ++override the global and local namespace. If only one namespace is ++specified, it is used for both. ++ ++ ++Exceptions ++========== ++ ++Exceptions are a means of breaking out of the normal flow of control ++of a code block in order to handle errors or other exceptional ++conditions. An exception is *raised* at the point where the error is ++detected; it may be *handled* by the surrounding code block or by any ++code block that directly or indirectly invoked the code block where ++the error occurred. ++ ++The Python interpreter raises an exception when it detects a run-time ++error (such as division by zero). A Python program can also ++explicitly raise an exception with the "raise" statement. Exception ++handlers are specified with the "try" … "except" statement. The ++"finally" clause of such a statement can be used to specify cleanup ++code which does not handle the exception, but is executed whether an ++exception occurred or not in the preceding code. ++ ++Python uses the “termination†model of error handling: an exception ++handler can find out what happened and continue execution at an outer ++level, but it cannot repair the cause of the error and retry the ++failing operation (except by re-entering the offending piece of code ++from the top). ++ ++When an exception is not handled at all, the interpreter terminates ++execution of the program, or returns to its interactive main loop. In ++either case, it prints a stack traceback, except when the exception is ++"SystemExit". ++ ++Exceptions are identified by class instances. The "except" clause is ++selected depending on the class of the instance: it must reference the ++class of the instance or a *non-virtual base class* thereof. The ++instance can be received by the handler and can carry additional ++information about the exceptional condition. ++ ++Note: ++ ++ Exception messages are not part of the Python API. Their contents ++ may change from one version of Python to the next without warning ++ and should not be relied on by code which will run under multiple ++ versions of the interpreter. ++ ++See also the description of the "try" statement in section The try ++statement and "raise" statement in section The raise statement. ++ ++-[ Footnotes ]- ++ ++[1] This limitation occurs because the code that is executed by these ++ operations is not available at the time the module is compiled. ++''', ++ 'exprlists': r'''Expression lists ++**************** ++ ++ **starred_expression**: ["*"] "or_expr" ++ **flexible_expression**: "assignment_expression" | "starred_expression" ++ **flexible_expression_list**: "flexible_expression" ("," "flexible_expression")* [","] ++ **starred_expression_list**: "starred_expression" ("," "starred_expression")* [","] ++ **expression_list**: "expression" ("," "expression")* [","] ++ **yield_list**: "expression_list" | "starred_expression" "," ["starred_expression_list"] ++ ++Except when part of a list or set display, an expression list ++containing at least one comma yields a tuple. The length of the tuple ++is the number of expressions in the list. The expressions are ++evaluated from left to right. ++ ++An asterisk "*" denotes *iterable unpacking*. Its operand must be an ++*iterable*. The iterable is expanded into a sequence of items, which ++are included in the new tuple, list, or set, at the site of the ++unpacking. ++ ++Added in version 3.5: Iterable unpacking in expression lists, ++originally proposed by **PEP 448**. ++ ++Added in version 3.11: Any item in an expression list may be starred. ++See **PEP 646**. ++ ++A trailing comma is required only to create a one-item tuple, such as ++"1,"; it is optional in all other cases. A single expression without a ++trailing comma doesn’t create a tuple, but rather yields the value of ++that expression. (To create an empty tuple, use an empty pair of ++parentheses: "()".) ++''', ++ 'floating': r'''Floating-point literals ++*********************** ++ ++Floating-point literals are described by the following lexical ++definitions: ++ ++ **floatnumber**: "pointfloat" | "exponentfloat" ++ **pointfloat**: ["digitpart"] "fraction" | "digitpart" "." ++ **exponentfloat**: ("digitpart" | "pointfloat") "exponent" ++ **digitpart**: "digit" (["_"] "digit")* ++ **fraction**: "." "digitpart" ++ **exponent**: ("e" | "E") ["+" | "-"] "digitpart" ++ ++Note that the integer and exponent parts are always interpreted using ++radix 10. For example, "077e010" is legal, and denotes the same number ++as "77e10". The allowed range of floating-point literals is ++implementation-dependent. As in integer literals, underscores are ++supported for digit grouping. ++ ++Some examples of floating-point literals: ++ ++ 3.14 10. .001 1e100 3.14e-10 0e0 3.14_15_93 ++ ++Changed in version 3.6: Underscores are now allowed for grouping ++purposes in literals. ++''', ++ 'for': r'''The "for" statement ++******************* ++ ++The "for" statement is used to iterate over the elements of a sequence ++(such as a string, tuple or list) or other iterable object: ++ ++ **for_stmt**: "for" "target_list" "in" "starred_list" ":" "suite" ++ ["else" ":" "suite"] ++ ++The "starred_list" expression is evaluated once; it should yield an ++*iterable* object. An *iterator* is created for that iterable. The ++first item provided by the iterator is then assigned to the target ++list using the standard rules for assignments (see Assignment ++statements), and the suite is executed. This repeats for each item ++provided by the iterator. When the iterator is exhausted, the suite ++in the "else" clause, if present, is executed, and the loop ++terminates. ++ ++A "break" statement executed in the first suite terminates the loop ++without executing the "else" clause’s suite. A "continue" statement ++executed in the first suite skips the rest of the suite and continues ++with the next item, or with the "else" clause if there is no next ++item. ++ ++The for-loop makes assignments to the variables in the target list. ++This overwrites all previous assignments to those variables including ++those made in the suite of the for-loop: ++ ++ for i in range(10): ++ print(i) ++ i = 5 # this will not affect the for-loop ++ # because i will be overwritten with the next ++ # index in the range ++ ++Names in the target list are not deleted when the loop is finished, ++but if the sequence is empty, they will not have been assigned to at ++all by the loop. Hint: the built-in type "range()" represents ++immutable arithmetic sequences of integers. For instance, iterating ++"range(3)" successively yields 0, 1, and then 2. ++ ++Changed in version 3.11: Starred elements are now allowed in the ++expression list. ++''', ++ 'formatstrings': r'''Format String Syntax ++******************** ++ ++The "str.format()" method and the "Formatter" class share the same ++syntax for format strings (although in the case of "Formatter", ++subclasses can define their own format string syntax). The syntax is ++related to that of formatted string literals, but it is less ++sophisticated and, in particular, does not support arbitrary ++expressions. ++ ++Format strings contain “replacement fields†surrounded by curly braces ++"{}". Anything that is not contained in braces is considered literal ++text, which is copied unchanged to the output. If you need to include ++a brace character in the literal text, it can be escaped by doubling: ++"{{" and "}}". ++ ++The grammar for a replacement field is as follows: ++ ++ **replacement_field**: "{" ["field_name"] ["!" "conversion"] [":" "format_spec"] "}" ++ **field_name**: "arg_name" ("." "attribute_name" | "[" "element_index" "]")* ++ **arg_name**: ["identifier" | "digit"+] ++ **attribute_name**: "identifier" ++ **element_index**: "digit"+ | "index_string" ++ **index_string**: + ++ **conversion**: "r" | "s" | "a" ++ **format_spec**: "format-spec:format_spec" ++ ++In less formal terms, the replacement field can start with a ++*field_name* that specifies the object whose value is to be formatted ++and inserted into the output instead of the replacement field. The ++*field_name* is optionally followed by a *conversion* field, which is ++preceded by an exclamation point "'!'", and a *format_spec*, which is ++preceded by a colon "':'". These specify a non-default format for the ++replacement value. ++ ++See also the Format Specification Mini-Language section. ++ ++The *field_name* itself begins with an *arg_name* that is either a ++number or a keyword. If it’s a number, it refers to a positional ++argument, and if it’s a keyword, it refers to a named keyword ++argument. An *arg_name* is treated as a number if a call to ++"str.isdecimal()" on the string would return true. If the numerical ++arg_names in a format string are 0, 1, 2, … in sequence, they can all ++be omitted (not just some) and the numbers 0, 1, 2, … will be ++automatically inserted in that order. Because *arg_name* is not quote- ++delimited, it is not possible to specify arbitrary dictionary keys ++(e.g., the strings "'10'" or "':-]'") within a format string. The ++*arg_name* can be followed by any number of index or attribute ++expressions. An expression of the form "'.name'" selects the named ++attribute using "getattr()", while an expression of the form ++"'[index]'" does an index lookup using "__getitem__()". ++ ++Changed in version 3.1: The positional argument specifiers can be ++omitted for "str.format()", so "'{} {}'.format(a, b)" is equivalent to ++"'{0} {1}'.format(a, b)". ++ ++Changed in version 3.4: The positional argument specifiers can be ++omitted for "Formatter". ++ ++Some simple format string examples: ++ ++ "First, thou shalt count to {0}" # References first positional argument ++ "Bring me a {}" # Implicitly references the first positional argument ++ "From {} to {}" # Same as "From {0} to {1}" ++ "My quest is {name}" # References keyword argument 'name' ++ "Weight in tons {0.weight}" # 'weight' attribute of first positional arg ++ "Units destroyed: {players[0]}" # First element of keyword argument 'players'. ++ ++The *conversion* field causes a type coercion before formatting. ++Normally, the job of formatting a value is done by the "__format__()" ++method of the value itself. However, in some cases it is desirable to ++force a type to be formatted as a string, overriding its own ++definition of formatting. By converting the value to a string before ++calling "__format__()", the normal formatting logic is bypassed. ++ ++Three conversion flags are currently supported: "'!s'" which calls ++"str()" on the value, "'!r'" which calls "repr()" and "'!a'" which ++calls "ascii()". ++ ++Some examples: ++ ++ "Harold's a clever {0!s}" # Calls str() on the argument first ++ "Bring out the holy {name!r}" # Calls repr() on the argument first ++ "More {!a}" # Calls ascii() on the argument first ++ ++The *format_spec* field contains a specification of how the value ++should be presented, including such details as field width, alignment, ++padding, decimal precision and so on. Each value type can define its ++own “formatting mini-language†or interpretation of the *format_spec*. ++ ++Most built-in types support a common formatting mini-language, which ++is described in the next section. ++ ++A *format_spec* field can also include nested replacement fields ++within it. These nested replacement fields may contain a field name, ++conversion flag and format specification, but deeper nesting is not ++allowed. The replacement fields within the format_spec are ++substituted before the *format_spec* string is interpreted. This ++allows the formatting of a value to be dynamically specified. ++ ++See the Format examples section for some examples. ++ ++ ++Format Specification Mini-Language ++================================== ++ ++“Format specifications†are used within replacement fields contained ++within a format string to define how individual values are presented ++(see Format String Syntax and f-strings). They can also be passed ++directly to the built-in "format()" function. Each formattable type ++may define how the format specification is to be interpreted. ++ ++Most built-in types implement the following options for format ++specifications, although some of the formatting options are only ++supported by the numeric types. ++ ++A general convention is that an empty format specification produces ++the same result as if you had called "str()" on the value. A non-empty ++format specification typically modifies the result. ++ ++The general form of a *standard format specifier* is: ++ ++ **format_spec**: [["fill"]"align"]["sign"]["z"]["#"]["0"]["width"]["grouping_option"]["." "precision"]["type"] ++ **fill**: ++ **align**: "<" | ">" | "=" | "^" ++ **sign**: "+" | "-" | " " ++ **width**: "digit"+ ++ **grouping_option**: "_" | "," ++ **precision**: "digit"+ ++ **type**: "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%" ++ ++If a valid *align* value is specified, it can be preceded by a *fill* ++character that can be any character and defaults to a space if ++omitted. It is not possible to use a literal curly brace (â€"{"†or ++“"}"â€) as the *fill* character in a formatted string literal or when ++using the "str.format()" method. However, it is possible to insert a ++curly brace with a nested replacement field. This limitation doesn’t ++affect the "format()" function. ++ ++The meaning of the various alignment options is as follows: ++ +++-----------+------------------------------------------------------------+ ++| Option | Meaning | ++|===========|============================================================| ++| "'<'" | Forces the field to be left-aligned within the available | ++| | space (this is the default for most objects). | +++-----------+------------------------------------------------------------+ ++| "'>'" | Forces the field to be right-aligned within the available | ++| | space (this is the default for numbers). | +++-----------+------------------------------------------------------------+ ++| "'='" | Forces the padding to be placed after the sign (if any) | ++| | but before the digits. This is used for printing fields | ++| | in the form ‘+000000120’. This alignment option is only | ++| | valid for numeric types, excluding "complex". It becomes | ++| | the default for numbers when ‘0’ immediately precedes the | ++| | field width. | +++-----------+------------------------------------------------------------+ ++| "'^'" | Forces the field to be centered within the available | ++| | space. | +++-----------+------------------------------------------------------------+ ++ ++Note that unless a minimum field width is defined, the field width ++will always be the same size as the data to fill it, so that the ++alignment option has no meaning in this case. ++ ++The *sign* option is only valid for number types, and can be one of ++the following: ++ +++-----------+------------------------------------------------------------+ ++| Option | Meaning | ++|===========|============================================================| ++| "'+'" | indicates that a sign should be used for both positive as | ++| | well as negative numbers. | +++-----------+------------------------------------------------------------+ ++| "'-'" | indicates that a sign should be used only for negative | ++| | numbers (this is the default behavior). | +++-----------+------------------------------------------------------------+ ++| space | indicates that a leading space should be used on positive | ++| | numbers, and a minus sign on negative numbers. | +++-----------+------------------------------------------------------------+ ++ ++The "'z'" option coerces negative zero floating-point values to ++positive zero after rounding to the format precision. This option is ++only valid for floating-point presentation types. ++ ++Changed in version 3.11: Added the "'z'" option (see also **PEP ++682**). ++ ++The "'#'" option causes the “alternate form†to be used for the ++conversion. The alternate form is defined differently for different ++types. This option is only valid for integer, float and complex ++types. For integers, when binary, octal, or hexadecimal output is ++used, this option adds the respective prefix "'0b'", "'0o'", "'0x'", ++or "'0X'" to the output value. For float and complex the alternate ++form causes the result of the conversion to always contain a decimal- ++point character, even if no digits follow it. Normally, a decimal- ++point character appears in the result of these conversions only if a ++digit follows it. In addition, for "'g'" and "'G'" conversions, ++trailing zeros are not removed from the result. ++ ++The "','" option signals the use of a comma for a thousands separator ++for floating-point presentation types and for integer presentation ++type "'d'". For other presentation types, this option is an error. For ++a locale aware separator, use the "'n'" integer presentation type ++instead. ++ ++Changed in version 3.1: Added the "','" option (see also **PEP 378**). ++ ++The "'_'" option signals the use of an underscore for a thousands ++separator for floating-point presentation types and for integer ++presentation type "'d'". For integer presentation types "'b'", "'o'", ++"'x'", and "'X'", underscores will be inserted every 4 digits. For ++other presentation types, specifying this option is an error. ++ ++Changed in version 3.6: Added the "'_'" option (see also **PEP 515**). ++ ++*width* is a decimal integer defining the minimum total field width, ++including any prefixes, separators, and other formatting characters. ++If not specified, then the field width will be determined by the ++content. ++ ++When no explicit alignment is given, preceding the *width* field by a ++zero ("'0'") character enables sign-aware zero-padding for numeric ++types, excluding "complex". This is equivalent to a *fill* character ++of "'0'" with an *alignment* type of "'='". ++ ++Changed in version 3.10: Preceding the *width* field by "'0'" no ++longer affects the default alignment for strings. ++ ++The *precision* is a decimal integer indicating how many digits should ++be displayed after the decimal point for presentation types "'f'" and ++"'F'", or before and after the decimal point for presentation types ++"'g'" or "'G'". For string presentation types the field indicates the ++maximum field size - in other words, how many characters will be used ++from the field content. The *precision* is not allowed for integer ++presentation types. ++ ++Finally, the *type* determines how the data should be presented. ++ ++The available string presentation types are: ++ ++ +-----------+------------------------------------------------------------+ ++ | Type | Meaning | ++ |===========|============================================================| ++ | "'s'" | String format. This is the default type for strings and | ++ | | may be omitted. | ++ +-----------+------------------------------------------------------------+ ++ | None | The same as "'s'". | ++ +-----------+------------------------------------------------------------+ ++ ++The available integer presentation types are: ++ ++ +-----------+------------------------------------------------------------+ ++ | Type | Meaning | ++ |===========|============================================================| ++ | "'b'" | Binary format. Outputs the number in base 2. | ++ +-----------+------------------------------------------------------------+ ++ | "'c'" | Character. Converts the integer to the corresponding | ++ | | unicode character before printing. | ++ +-----------+------------------------------------------------------------+ ++ | "'d'" | Decimal Integer. Outputs the number in base 10. | ++ +-----------+------------------------------------------------------------+ ++ | "'o'" | Octal format. Outputs the number in base 8. | ++ +-----------+------------------------------------------------------------+ ++ | "'x'" | Hex format. Outputs the number in base 16, using lower- | ++ | | case letters for the digits above 9. | ++ +-----------+------------------------------------------------------------+ ++ | "'X'" | Hex format. Outputs the number in base 16, using upper- | ++ | | case letters for the digits above 9. In case "'#'" is | ++ | | specified, the prefix "'0x'" will be upper-cased to "'0X'" | ++ | | as well. | ++ +-----------+------------------------------------------------------------+ ++ | "'n'" | Number. This is the same as "'d'", except that it uses the | ++ | | current locale setting to insert the appropriate number | ++ | | separator characters. | ++ +-----------+------------------------------------------------------------+ ++ | None | The same as "'d'". | ++ +-----------+------------------------------------------------------------+ ++ ++In addition to the above presentation types, integers can be formatted ++with the floating-point presentation types listed below (except "'n'" ++and "None"). When doing so, "float()" is used to convert the integer ++to a floating-point number before formatting. ++ ++The available presentation types for "float" and "Decimal" values are: ++ ++ +-----------+------------------------------------------------------------+ ++ | Type | Meaning | ++ |===========|============================================================| ++ | "'e'" | Scientific notation. For a given precision "p", formats | ++ | | the number in scientific notation with the letter ‘e’ | ++ | | separating the coefficient from the exponent. The | ++ | | coefficient has one digit before and "p" digits after the | ++ | | decimal point, for a total of "p + 1" significant digits. | ++ | | With no precision given, uses a precision of "6" digits | ++ | | after the decimal point for "float", and shows all | ++ | | coefficient digits for "Decimal". If "p=0", the decimal | ++ | | point is omitted unless the "#" option is used. | ++ +-----------+------------------------------------------------------------+ ++ | "'E'" | Scientific notation. Same as "'e'" except it uses an upper | ++ | | case ‘E’ as the separator character. | ++ +-----------+------------------------------------------------------------+ ++ | "'f'" | Fixed-point notation. For a given precision "p", formats | ++ | | the number as a decimal number with exactly "p" digits | ++ | | following the decimal point. With no precision given, uses | ++ | | a precision of "6" digits after the decimal point for | ++ | | "float", and uses a precision large enough to show all | ++ | | coefficient digits for "Decimal". If "p=0", the decimal | ++ | | point is omitted unless the "#" option is used. | ++ +-----------+------------------------------------------------------------+ ++ | "'F'" | Fixed-point notation. Same as "'f'", but converts "nan" to | ++ | | "NAN" and "inf" to "INF". | ++ +-----------+------------------------------------------------------------+ ++ | "'g'" | General format. For a given precision "p >= 1", this | ++ | | rounds the number to "p" significant digits and then | ++ | | formats the result in either fixed-point format or in | ++ | | scientific notation, depending on its magnitude. A | ++ | | precision of "0" is treated as equivalent to a precision | ++ | | of "1". The precise rules are as follows: suppose that | ++ | | the result formatted with presentation type "'e'" and | ++ | | precision "p-1" would have exponent "exp". Then, if "m <= | ++ | | exp < p", where "m" is -4 for floats and -6 for | ++ | | "Decimals", the number is formatted with presentation type | ++ | | "'f'" and precision "p-1-exp". Otherwise, the number is | ++ | | formatted with presentation type "'e'" and precision | ++ | | "p-1". In both cases insignificant trailing zeros are | ++ | | removed from the significand, and the decimal point is | ++ | | also removed if there are no remaining digits following | ++ | | it, unless the "'#'" option is used. With no precision | ++ | | given, uses a precision of "6" significant digits for | ++ | | "float". For "Decimal", the coefficient of the result is | ++ | | formed from the coefficient digits of the value; | ++ | | scientific notation is used for values smaller than "1e-6" | ++ | | in absolute value and values where the place value of the | ++ | | least significant digit is larger than 1, and fixed-point | ++ | | notation is used otherwise. Positive and negative | ++ | | infinity, positive and negative zero, and nans, are | ++ | | formatted as "inf", "-inf", "0", "-0" and "nan" | ++ | | respectively, regardless of the precision. | ++ +-----------+------------------------------------------------------------+ ++ | "'G'" | General format. Same as "'g'" except switches to "'E'" if | ++ | | the number gets too large. The representations of infinity | ++ | | and NaN are uppercased, too. | ++ +-----------+------------------------------------------------------------+ ++ | "'n'" | Number. This is the same as "'g'", except that it uses the | ++ | | current locale setting to insert the appropriate number | ++ | | separator characters. | ++ +-----------+------------------------------------------------------------+ ++ | "'%'" | Percentage. Multiplies the number by 100 and displays in | ++ | | fixed ("'f'") format, followed by a percent sign. | ++ +-----------+------------------------------------------------------------+ ++ | None | For "float" this is like the "'g'" type, except that when | ++ | | fixed- point notation is used to format the result, it | ++ | | always includes at least one digit past the decimal point, | ++ | | and switches to the scientific notation when "exp >= p - | ++ | | 1". When the precision is not specified, the latter will | ++ | | be as large as needed to represent the given value | ++ | | faithfully. For "Decimal", this is the same as either | ++ | | "'g'" or "'G'" depending on the value of | ++ | | "context.capitals" for the current decimal context. The | ++ | | overall effect is to match the output of "str()" as | ++ | | altered by the other format modifiers. | ++ +-----------+------------------------------------------------------------+ ++ ++The result should be correctly rounded to a given precision "p" of ++digits after the decimal point. The rounding mode for "float" matches ++that of the "round()" builtin. For "Decimal", the rounding mode of ++the current context will be used. ++ ++The available presentation types for "complex" are the same as those ++for "float" ("'%'" is not allowed). Both the real and imaginary ++components of a complex number are formatted as floating-point ++numbers, according to the specified presentation type. They are ++separated by the mandatory sign of the imaginary part, the latter ++being terminated by a "j" suffix. If the presentation type is ++missing, the result will match the output of "str()" (complex numbers ++with a non-zero real part are also surrounded by parentheses), ++possibly altered by other format modifiers. ++ ++ ++Format examples ++=============== ++ ++This section contains examples of the "str.format()" syntax and ++comparison with the old "%"-formatting. ++ ++In most of the cases the syntax is similar to the old "%"-formatting, ++with the addition of the "{}" and with ":" used instead of "%". For ++example, "'%03.2f'" can be translated to "'{:03.2f}'". ++ ++The new format syntax also supports new and different options, shown ++in the following examples. ++ ++Accessing arguments by position: ++ ++ >>> '{0}, {1}, {2}'.format('a', 'b', 'c') ++ 'a, b, c' ++ >>> '{}, {}, {}'.format('a', 'b', 'c') # 3.1+ only ++ 'a, b, c' ++ >>> '{2}, {1}, {0}'.format('a', 'b', 'c') ++ 'c, b, a' ++ >>> '{2}, {1}, {0}'.format(*'abc') # unpacking argument sequence ++ 'c, b, a' ++ >>> '{0}{1}{0}'.format('abra', 'cad') # arguments' indices can be repeated ++ 'abracadabra' ++ ++Accessing arguments by name: ++ ++ >>> 'Coordinates: {latitude}, {longitude}'.format(latitude='37.24N', longitude='-115.81W') ++ 'Coordinates: 37.24N, -115.81W' ++ >>> coord = {'latitude': '37.24N', 'longitude': '-115.81W'} ++ >>> 'Coordinates: {latitude}, {longitude}'.format(**coord) ++ 'Coordinates: 37.24N, -115.81W' ++ ++Accessing arguments’ attributes: ++ ++ >>> c = 3-5j ++ >>> ('The complex number {0} is formed from the real part {0.real} ' ++ ... 'and the imaginary part {0.imag}.').format(c) ++ 'The complex number (3-5j) is formed from the real part 3.0 and the imaginary part -5.0.' ++ >>> class Point: ++ ... def __init__(self, x, y): ++ ... self.x, self.y = x, y ++ ... def __str__(self): ++ ... return 'Point({self.x}, {self.y})'.format(self=self) ++ ... ++ >>> str(Point(4, 2)) ++ 'Point(4, 2)' ++ ++Accessing arguments’ items: ++ ++ >>> coord = (3, 5) ++ >>> 'X: {0[0]}; Y: {0[1]}'.format(coord) ++ 'X: 3; Y: 5' ++ ++Replacing "%s" and "%r": ++ ++ >>> "repr() shows quotes: {!r}; str() doesn't: {!s}".format('test1', 'test2') ++ "repr() shows quotes: 'test1'; str() doesn't: test2" ++ ++Aligning the text and specifying a width: ++ ++ >>> '{:<30}'.format('left aligned') ++ 'left aligned ' ++ >>> '{:>30}'.format('right aligned') ++ ' right aligned' ++ >>> '{:^30}'.format('centered') ++ ' centered ' ++ >>> '{:*^30}'.format('centered') # use '*' as a fill char ++ '***********centered***********' ++ ++Replacing "%+f", "%-f", and "% f" and specifying a sign: ++ ++ >>> '{:+f}; {:+f}'.format(3.14, -3.14) # show it always ++ '+3.140000; -3.140000' ++ >>> '{: f}; {: f}'.format(3.14, -3.14) # show a space for positive numbers ++ ' 3.140000; -3.140000' ++ >>> '{:-f}; {:-f}'.format(3.14, -3.14) # show only the minus -- same as '{:f}; {:f}' ++ '3.140000; -3.140000' ++ ++Replacing "%x" and "%o" and converting the value to different bases: ++ ++ >>> # format also supports binary numbers ++ >>> "int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}".format(42) ++ 'int: 42; hex: 2a; oct: 52; bin: 101010' ++ >>> # with 0x, 0o, or 0b as prefix: ++ >>> "int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}".format(42) ++ 'int: 42; hex: 0x2a; oct: 0o52; bin: 0b101010' ++ ++Using the comma as a thousands separator: ++ ++ >>> '{:,}'.format(1234567890) ++ '1,234,567,890' ++ ++Expressing a percentage: ++ ++ >>> points = 19 ++ >>> total = 22 ++ >>> 'Correct answers: {:.2%}'.format(points/total) ++ 'Correct answers: 86.36%' ++ ++Using type-specific formatting: ++ ++ >>> import datetime ++ >>> d = datetime.datetime(2010, 7, 4, 12, 15, 58) ++ >>> '{:%Y-%m-%d %H:%M:%S}'.format(d) ++ '2010-07-04 12:15:58' ++ ++Nesting arguments and more complex examples: ++ ++ >>> for align, text in zip('<^>', ['left', 'center', 'right']): ++ ... '{0:{fill}{align}16}'.format(text, fill=align, align=align) ++ ... ++ 'left<<<<<<<<<<<<' ++ '^^^^^center^^^^^' ++ '>>>>>>>>>>>right' ++ >>> ++ >>> octets = [192, 168, 0, 1] ++ >>> '{:02X}{:02X}{:02X}{:02X}'.format(*octets) ++ 'C0A80001' ++ >>> int(_, 16) ++ 3232235521 ++ >>> ++ >>> width = 5 ++ >>> for num in range(5,12): ++ ... for base in 'dXob': ++ ... print('{0:{width}{base}}'.format(num, base=base, width=width), end=' ') ++ ... print() ++ ... ++ 5 5 5 101 ++ 6 6 6 110 ++ 7 7 7 111 ++ 8 8 10 1000 ++ 9 9 11 1001 ++ 10 A 12 1010 ++ 11 B 13 1011 ++''', ++ 'function': r'''Function definitions ++******************** ++ ++A function definition defines a user-defined function object (see ++section The standard type hierarchy): ++ ++ **funcdef**: ["decorators"] "def" "funcname" ["type_params"] "(" ["parameter_list"] ")" ++ ["->" "expression"] ":" "suite" ++ **decorators**: "decorator"+ ++ **decorator**: "@" "assignment_expression" NEWLINE ++ **parameter_list**: "defparameter" ("," "defparameter")* "," "/" ["," ["parameter_list_no_posonly"]] ++ | "parameter_list_no_posonly" ++ **parameter_list_no_posonly**: "defparameter" ("," "defparameter")* ["," ["parameter_list_starargs"]] ++ | "parameter_list_starargs" ++ **parameter_list_starargs**: "*" ["star_parameter"] ("," "defparameter")* ["," ["parameter_star_kwargs"]] ++ "*" ("," "defparameter")+ ["," ["parameter_star_kwargs"]] ++ | "parameter_star_kwargs" ++ **parameter_star_kwargs**: "**" "parameter" [","] ++ **parameter**: "identifier" [":" "expression"] ++ **star_parameter**: "identifier" [":" ["*"] "expression"] ++ **defparameter**: "parameter" ["=" "expression"] ++ **funcname**: "identifier" ++ ++A function definition is an executable statement. Its execution binds ++the function name in the current local namespace to a function object ++(a wrapper around the executable code for the function). This ++function object contains a reference to the current global namespace ++as the global namespace to be used when the function is called. ++ ++The function definition does not execute the function body; this gets ++executed only when the function is called. [4] ++ ++A function definition may be wrapped by one or more *decorator* ++expressions. Decorator expressions are evaluated when the function is ++defined, in the scope that contains the function definition. The ++result must be a callable, which is invoked with the function object ++as the only argument. The returned value is bound to the function name ++instead of the function object. Multiple decorators are applied in ++nested fashion. For example, the following code ++ ++ @f1(arg) ++ @f2 ++ def func(): pass ++ ++is roughly equivalent to ++ ++ def func(): pass ++ func = f1(arg)(f2(func)) ++ ++except that the original function is not temporarily bound to the name ++"func". ++ ++Changed in version 3.9: Functions may be decorated with any valid ++"assignment_expression". Previously, the grammar was much more ++restrictive; see **PEP 614** for details. ++ ++A list of type parameters may be given in square brackets between the ++function’s name and the opening parenthesis for its parameter list. ++This indicates to static type checkers that the function is generic. ++At runtime, the type parameters can be retrieved from the function’s ++"__type_params__" attribute. See Generic functions for more. ++ ++Changed in version 3.12: Type parameter lists are new in Python 3.12. ++ ++When one or more *parameters* have the form *parameter* "=" ++*expression*, the function is said to have “default parameter values.†++For a parameter with a default value, the corresponding *argument* may ++be omitted from a call, in which case the parameter’s default value is ++substituted. If a parameter has a default value, all following ++parameters up until the “"*"†must also have a default value — this is ++a syntactic restriction that is not expressed by the grammar. ++ ++**Default parameter values are evaluated from left to right when the ++function definition is executed.** This means that the expression is ++evaluated once, when the function is defined, and that the same “pre- ++computed†value is used for each call. This is especially important ++to understand when a default parameter value is a mutable object, such ++as a list or a dictionary: if the function modifies the object (e.g. ++by appending an item to a list), the default parameter value is in ++effect modified. This is generally not what was intended. A way ++around this is to use "None" as the default, and explicitly test for ++it in the body of the function, e.g.: ++ ++ def whats_on_the_telly(penguin=None): ++ if penguin is None: ++ penguin = [] ++ penguin.append("property of the zoo") ++ return penguin ++ ++Function call semantics are described in more detail in section Calls. ++A function call always assigns values to all parameters mentioned in ++the parameter list, either from positional arguments, from keyword ++arguments, or from default values. If the form “"*identifier"†is ++present, it is initialized to a tuple receiving any excess positional ++parameters, defaulting to the empty tuple. If the form ++“"**identifier"†is present, it is initialized to a new ordered ++mapping receiving any excess keyword arguments, defaulting to a new ++empty mapping of the same type. Parameters after “"*"†or ++“"*identifier"†are keyword-only parameters and may only be passed by ++keyword arguments. Parameters before “"/"†are positional-only ++parameters and may only be passed by positional arguments. ++ ++Changed in version 3.8: The "/" function parameter syntax may be used ++to indicate positional-only parameters. See **PEP 570** for details. ++ ++Parameters may have an *annotation* of the form “": expression"†++following the parameter name. Any parameter may have an annotation, ++even those of the form "*identifier" or "**identifier". (As a special ++case, parameters of the form "*identifier" may have an annotation “": ++*expression"â€.) Functions may have “return†annotation of the form ++“"-> expression"†after the parameter list. These annotations can be ++any valid Python expression. The presence of annotations does not ++change the semantics of a function. See Annotations for more ++information on annotations. ++ ++Changed in version 3.11: Parameters of the form “"*identifier"†may ++have an annotation “": *expression"â€. See **PEP 646**. ++ ++It is also possible to create anonymous functions (functions not bound ++to a name), for immediate use in expressions. This uses lambda ++expressions, described in section Lambdas. Note that the lambda ++expression is merely a shorthand for a simplified function definition; ++a function defined in a “"def"†statement can be passed around or ++assigned to another name just like a function defined by a lambda ++expression. The “"def"†form is actually more powerful since it ++allows the execution of multiple statements and annotations. ++ ++**Programmer’s note:** Functions are first-class objects. A “"def"†++statement executed inside a function definition defines a local ++function that can be returned or passed around. Free variables used ++in the nested function can access the local variables of the function ++containing the def. See section Naming and binding for details. ++ ++See also: ++ ++ **PEP 3107** - Function Annotations ++ The original specification for function annotations. ++ ++ **PEP 484** - Type Hints ++ Definition of a standard meaning for annotations: type hints. ++ ++ **PEP 526** - Syntax for Variable Annotations ++ Ability to type hint variable declarations, including class ++ variables and instance variables. ++ ++ **PEP 563** - Postponed Evaluation of Annotations ++ Support for forward references within annotations by preserving ++ annotations in a string form at runtime instead of eager ++ evaluation. ++ ++ **PEP 318** - Decorators for Functions and Methods ++ Function and method decorators were introduced. Class decorators ++ were introduced in **PEP 3129**. ++''', ++ 'global': r'''The "global" statement ++********************** ++ ++ **global_stmt**: "global" "identifier" ("," "identifier")* ++ ++The "global" statement causes the listed identifiers to be interpreted ++as globals. It would be impossible to assign to a global variable ++without "global", although free variables may refer to globals without ++being declared global. ++ ++The "global" statement applies to the entire scope of a function or ++class body. A "SyntaxError" is raised if a variable is used or ++assigned to prior to its global declaration in the scope. ++ ++**Programmer’s note:** "global" is a directive to the parser. It ++applies only to code parsed at the same time as the "global" ++statement. In particular, a "global" statement contained in a string ++or code object supplied to the built-in "exec()" function does not ++affect the code block *containing* the function call, and code ++contained in such a string is unaffected by "global" statements in the ++code containing the function call. The same applies to the "eval()" ++and "compile()" functions. ++''', ++ 'id-classes': r'''Reserved classes of identifiers ++******************************* ++ ++Certain classes of identifiers (besides keywords) have special ++meanings. These classes are identified by the patterns of leading and ++trailing underscore characters: ++ ++"_*" ++ Not imported by "from module import *". ++ ++"_" ++ In a "case" pattern within a "match" statement, "_" is a soft ++ keyword that denotes a wildcard. ++ ++ Separately, the interactive interpreter makes the result of the ++ last evaluation available in the variable "_". (It is stored in the ++ "builtins" module, alongside built-in functions like "print".) ++ ++ Elsewhere, "_" is a regular identifier. It is often used to name ++ “special†items, but it is not special to Python itself. ++ ++ Note: ++ ++ The name "_" is often used in conjunction with ++ internationalization; refer to the documentation for the ++ "gettext" module for more information on this convention.It is ++ also commonly used for unused variables. ++ ++"__*__" ++ System-defined names, informally known as “dunder†names. These ++ names are defined by the interpreter and its implementation ++ (including the standard library). Current system names are ++ discussed in the Special method names section and elsewhere. More ++ will likely be defined in future versions of Python. *Any* use of ++ "__*__" names, in any context, that does not follow explicitly ++ documented use, is subject to breakage without warning. ++ ++"__*" ++ Class-private names. Names in this category, when used within the ++ context of a class definition, are re-written to use a mangled form ++ to help avoid name clashes between “private†attributes of base and ++ derived classes. See section Identifiers (Names). ++''', ++ 'identifiers': r'''Identifiers and keywords ++************************ ++ ++Identifiers (also referred to as *names*) are described by the ++following lexical definitions. ++ ++The syntax of identifiers in Python is based on the Unicode standard ++annex UAX-31, with elaboration and changes as defined below; see also ++**PEP 3131** for further details. ++ ++Within the ASCII range (U+0001..U+007F), the valid characters for ++identifiers include the uppercase and lowercase letters "A" through ++"Z", the underscore "_" and, except for the first character, the ++digits "0" through "9". Python 3.0 introduced additional characters ++from outside the ASCII range (see **PEP 3131**). For these ++characters, the classification uses the version of the Unicode ++Character Database as included in the "unicodedata" module. ++ ++Identifiers are unlimited in length. Case is significant. ++ ++ **identifier**: "xid_start" "xid_continue"* ++ **id_start**: ++ **id_continue**: ++ **xid_start**: ++ **xid_continue**: ++ ++The Unicode category codes mentioned above stand for: ++ ++* *Lu* - uppercase letters ++ ++* *Ll* - lowercase letters ++ ++* *Lt* - titlecase letters ++ ++* *Lm* - modifier letters ++ ++* *Lo* - other letters ++ ++* *Nl* - letter numbers ++ ++* *Mn* - nonspacing marks ++ ++* *Mc* - spacing combining marks ++ ++* *Nd* - decimal numbers ++ ++* *Pc* - connector punctuations ++ ++* *Other_ID_Start* - explicit list of characters in PropList.txt to ++ support backwards compatibility ++ ++* *Other_ID_Continue* - likewise ++ ++All identifiers are converted into the normal form NFKC while parsing; ++comparison of identifiers is based on NFKC. ++ ++A non-normative HTML file listing all valid identifier characters for ++Unicode 16.0.0 can be found at ++https://www.unicode.org/Public/16.0.0/ucd/DerivedCoreProperties.txt ++ ++ ++Keywords ++======== ++ ++The following identifiers are used as reserved words, or *keywords* of ++the language, and cannot be used as ordinary identifiers. They must ++be spelled exactly as written here: ++ ++ False await else import pass ++ None break except in raise ++ True class finally is return ++ and continue for lambda try ++ as def from nonlocal while ++ assert del global not with ++ async elif if or yield ++ ++ ++Soft Keywords ++============= ++ ++Added in version 3.10. ++ ++Some identifiers are only reserved under specific contexts. These are ++known as *soft keywords*. The identifiers "match", "case", "type" and ++"_" can syntactically act as keywords in certain contexts, but this ++distinction is done at the parser level, not when tokenizing. ++ ++As soft keywords, their use in the grammar is possible while still ++preserving compatibility with existing code that uses these names as ++identifier names. ++ ++"match", "case", and "_" are used in the "match" statement. "type" is ++used in the "type" statement. ++ ++Changed in version 3.12: "type" is now a soft keyword. ++ ++ ++Reserved classes of identifiers ++=============================== ++ ++Certain classes of identifiers (besides keywords) have special ++meanings. These classes are identified by the patterns of leading and ++trailing underscore characters: ++ ++"_*" ++ Not imported by "from module import *". ++ ++"_" ++ In a "case" pattern within a "match" statement, "_" is a soft ++ keyword that denotes a wildcard. ++ ++ Separately, the interactive interpreter makes the result of the ++ last evaluation available in the variable "_". (It is stored in the ++ "builtins" module, alongside built-in functions like "print".) ++ ++ Elsewhere, "_" is a regular identifier. It is often used to name ++ “special†items, but it is not special to Python itself. ++ ++ Note: ++ ++ The name "_" is often used in conjunction with ++ internationalization; refer to the documentation for the ++ "gettext" module for more information on this convention.It is ++ also commonly used for unused variables. ++ ++"__*__" ++ System-defined names, informally known as “dunder†names. These ++ names are defined by the interpreter and its implementation ++ (including the standard library). Current system names are ++ discussed in the Special method names section and elsewhere. More ++ will likely be defined in future versions of Python. *Any* use of ++ "__*__" names, in any context, that does not follow explicitly ++ documented use, is subject to breakage without warning. ++ ++"__*" ++ Class-private names. Names in this category, when used within the ++ context of a class definition, are re-written to use a mangled form ++ to help avoid name clashes between “private†attributes of base and ++ derived classes. See section Identifiers (Names). ++''', ++ 'if': r'''The "if" statement ++****************** ++ ++The "if" statement is used for conditional execution: ++ ++ **if_stmt**: "if" "assignment_expression" ":" "suite" ++ ("elif" "assignment_expression" ":" "suite")* ++ ["else" ":" "suite"] ++ ++It selects exactly one of the suites by evaluating the expressions one ++by one until one is found to be true (see section Boolean operations ++for the definition of true and false); then that suite is executed ++(and no other part of the "if" statement is executed or evaluated). ++If all expressions are false, the suite of the "else" clause, if ++present, is executed. ++''', ++ 'imaginary': r'''Imaginary literals ++****************** ++ ++Imaginary literals are described by the following lexical definitions: ++ ++ **imagnumber**: ("floatnumber" | "digitpart") ("j" | "J") ++ ++An imaginary literal yields a complex number with a real part of 0.0. ++Complex numbers are represented as a pair of floating-point numbers ++and have the same restrictions on their range. To create a complex ++number with a nonzero real part, add a floating-point number to it, ++e.g., "(3+4j)". Some examples of imaginary literals: ++ ++ 3.14j 10.j 10j .001j 1e100j 3.14e-10j 3.14_15_93j ++''', ++ 'import': r'''The "import" statement ++********************** ++ ++ **import_stmt**: "import" "module" ["as" "identifier"] ("," "module" ["as" "identifier"])* ++ | "from" "relative_module" "import" "identifier" ["as" "identifier"] ++ ("," "identifier" ["as" "identifier"])* ++ | "from" "relative_module" "import" "(" "identifier" ["as" "identifier"] ++ ("," "identifier" ["as" "identifier"])* [","] ")" ++ | "from" "relative_module" "import" "*" ++ **module**: ("identifier" ".")* "identifier" ++ **relative_module**: "."* "module" | "."+ ++ ++The basic import statement (no "from" clause) is executed in two ++steps: ++ ++1. find a module, loading and initializing it if necessary ++ ++2. define a name or names in the local namespace for the scope where ++ the "import" statement occurs. ++ ++When the statement contains multiple clauses (separated by commas) the ++two steps are carried out separately for each clause, just as though ++the clauses had been separated out into individual import statements. ++ ++The details of the first step, finding and loading modules, are ++described in greater detail in the section on the import system, which ++also describes the various types of packages and modules that can be ++imported, as well as all the hooks that can be used to customize the ++import system. Note that failures in this step may indicate either ++that the module could not be located, *or* that an error occurred ++while initializing the module, which includes execution of the ++module’s code. ++ ++If the requested module is retrieved successfully, it will be made ++available in the local namespace in one of three ways: ++ ++* If the module name is followed by "as", then the name following "as" ++ is bound directly to the imported module. ++ ++* If no other name is specified, and the module being imported is a ++ top level module, the module’s name is bound in the local namespace ++ as a reference to the imported module ++ ++* If the module being imported is *not* a top level module, then the ++ name of the top level package that contains the module is bound in ++ the local namespace as a reference to the top level package. The ++ imported module must be accessed using its full qualified name ++ rather than directly ++ ++The "from" form uses a slightly more complex process: ++ ++1. find the module specified in the "from" clause, loading and ++ initializing it if necessary; ++ ++2. for each of the identifiers specified in the "import" clauses: ++ ++ 1. check if the imported module has an attribute by that name ++ ++ 2. if not, attempt to import a submodule with that name and then ++ check the imported module again for that attribute ++ ++ 3. if the attribute is not found, "ImportError" is raised. ++ ++ 4. otherwise, a reference to that value is stored in the local ++ namespace, using the name in the "as" clause if it is present, ++ otherwise using the attribute name ++ ++Examples: ++ ++ import foo # foo imported and bound locally ++ import foo.bar.baz # foo, foo.bar, and foo.bar.baz imported, foo bound locally ++ import foo.bar.baz as fbb # foo, foo.bar, and foo.bar.baz imported, foo.bar.baz bound as fbb ++ from foo.bar import baz # foo, foo.bar, and foo.bar.baz imported, foo.bar.baz bound as baz ++ from foo import attr # foo imported and foo.attr bound as attr ++ ++If the list of identifiers is replaced by a star ("'*'"), all public ++names defined in the module are bound in the local namespace for the ++scope where the "import" statement occurs. ++ ++The *public names* defined by a module are determined by checking the ++module’s namespace for a variable named "__all__"; if defined, it must ++be a sequence of strings which are names defined or imported by that ++module. The names given in "__all__" are all considered public and ++are required to exist. If "__all__" is not defined, the set of public ++names includes all names found in the module’s namespace which do not ++begin with an underscore character ("'_'"). "__all__" should contain ++the entire public API. It is intended to avoid accidentally exporting ++items that are not part of the API (such as library modules which were ++imported and used within the module). ++ ++The wild card form of import — "from module import *" — is only ++allowed at the module level. Attempting to use it in class or ++function definitions will raise a "SyntaxError". ++ ++When specifying what module to import you do not have to specify the ++absolute name of the module. When a module or package is contained ++within another package it is possible to make a relative import within ++the same top package without having to mention the package name. By ++using leading dots in the specified module or package after "from" you ++can specify how high to traverse up the current package hierarchy ++without specifying exact names. One leading dot means the current ++package where the module making the import exists. Two dots means up ++one package level. Three dots is up two levels, etc. So if you execute ++"from . import mod" from a module in the "pkg" package then you will ++end up importing "pkg.mod". If you execute "from ..subpkg2 import mod" ++from within "pkg.subpkg1" you will import "pkg.subpkg2.mod". The ++specification for relative imports is contained in the Package ++Relative Imports section. ++ ++"importlib.import_module()" is provided to support applications that ++determine dynamically the modules to be loaded. ++ ++Raises an auditing event "import" with arguments "module", "filename", ++"sys.path", "sys.meta_path", "sys.path_hooks". ++ ++ ++Future statements ++================= ++ ++A *future statement* is a directive to the compiler that a particular ++module should be compiled using syntax or semantics that will be ++available in a specified future release of Python where the feature ++becomes standard. ++ ++The future statement is intended to ease migration to future versions ++of Python that introduce incompatible changes to the language. It ++allows use of the new features on a per-module basis before the ++release in which the feature becomes standard. ++ ++ **future_stmt**: "from" "__future__" "import" "feature" ["as" "identifier"] ++ ("," "feature" ["as" "identifier"])* ++ | "from" "__future__" "import" "(" "feature" ["as" "identifier"] ++ ("," "feature" ["as" "identifier"])* [","] ")" ++ **feature**: "identifier" ++ ++A future statement must appear near the top of the module. The only ++lines that can appear before a future statement are: ++ ++* the module docstring (if any), ++ ++* comments, ++ ++* blank lines, and ++ ++* other future statements. ++ ++The only feature that requires using the future statement is ++"annotations" (see **PEP 563**). ++ ++All historical features enabled by the future statement are still ++recognized by Python 3. The list includes "absolute_import", ++"division", "generators", "generator_stop", "unicode_literals", ++"print_function", "nested_scopes" and "with_statement". They are all ++redundant because they are always enabled, and only kept for backwards ++compatibility. ++ ++A future statement is recognized and treated specially at compile ++time: Changes to the semantics of core constructs are often ++implemented by generating different code. It may even be the case ++that a new feature introduces new incompatible syntax (such as a new ++reserved word), in which case the compiler may need to parse the ++module differently. Such decisions cannot be pushed off until ++runtime. ++ ++For any given release, the compiler knows which feature names have ++been defined, and raises a compile-time error if a future statement ++contains a feature not known to it. ++ ++The direct runtime semantics are the same as for any import statement: ++there is a standard module "__future__", described later, and it will ++be imported in the usual way at the time the future statement is ++executed. ++ ++The interesting runtime semantics depend on the specific feature ++enabled by the future statement. ++ ++Note that there is nothing special about the statement: ++ ++ import __future__ [as name] ++ ++That is not a future statement; it’s an ordinary import statement with ++no special semantics or syntax restrictions. ++ ++Code compiled by calls to the built-in functions "exec()" and ++"compile()" that occur in a module "M" containing a future statement ++will, by default, use the new syntax or semantics associated with the ++future statement. This can be controlled by optional arguments to ++"compile()" — see the documentation of that function for details. ++ ++A future statement typed at an interactive interpreter prompt will ++take effect for the rest of the interpreter session. If an ++interpreter is started with the "-i" option, is passed a script name ++to execute, and the script includes a future statement, it will be in ++effect in the interactive session started after the script is ++executed. ++ ++See also: ++ ++ **PEP 236** - Back to the __future__ ++ The original proposal for the __future__ mechanism. ++''', ++ 'in': r'''Membership test operations ++************************** ++ ++The operators "in" and "not in" test for membership. "x in s" ++evaluates to "True" if *x* is a member of *s*, and "False" otherwise. ++"x not in s" returns the negation of "x in s". All built-in sequences ++and set types support this as well as dictionary, for which "in" tests ++whether the dictionary has a given key. For container types such as ++list, tuple, set, frozenset, dict, or collections.deque, the ++expression "x in y" is equivalent to "any(x is e or x == e for e in ++y)". ++ ++For the string and bytes types, "x in y" is "True" if and only if *x* ++is a substring of *y*. An equivalent test is "y.find(x) != -1". ++Empty strings are always considered to be a substring of any other ++string, so """ in "abc"" will return "True". ++ ++For user-defined classes which define the "__contains__()" method, "x ++in y" returns "True" if "y.__contains__(x)" returns a true value, and ++"False" otherwise. ++ ++For user-defined classes which do not define "__contains__()" but do ++define "__iter__()", "x in y" is "True" if some value "z", for which ++the expression "x is z or x == z" is true, is produced while iterating ++over "y". If an exception is raised during the iteration, it is as if ++"in" raised that exception. ++ ++Lastly, the old-style iteration protocol is tried: if a class defines ++"__getitem__()", "x in y" is "True" if and only if there is a non- ++negative integer index *i* such that "x is y[i] or x == y[i]", and no ++lower integer index raises the "IndexError" exception. (If any other ++exception is raised, it is as if "in" raised that exception). ++ ++The operator "not in" is defined to have the inverse truth value of ++"in". ++''', ++ 'integers': r'''Integer literals ++**************** ++ ++Integer literals are described by the following lexical definitions: ++ ++ **integer**: "decinteger" | "bininteger" | "octinteger" | "hexinteger" ++ **decinteger**: "nonzerodigit" (["_"] "digit")* | "0"+ (["_"] "0")* ++ **bininteger**: "0" ("b" | "B") (["_"] "bindigit")+ ++ **octinteger**: "0" ("o" | "O") (["_"] "octdigit")+ ++ **hexinteger**: "0" ("x" | "X") (["_"] "hexdigit")+ ++ **nonzerodigit**: "1"..."9" ++ **digit**: "0"..."9" ++ **bindigit**: "0" | "1" ++ **octdigit**: "0"..."7" ++ **hexdigit**: "digit" | "a"..."f" | "A"..."F" ++ ++There is no limit for the length of integer literals apart from what ++can be stored in available memory. ++ ++Underscores are ignored for determining the numeric value of the ++literal. They can be used to group digits for enhanced readability. ++One underscore can occur between digits, and after base specifiers ++like "0x". ++ ++Note that leading zeros in a non-zero decimal number are not allowed. ++This is for disambiguation with C-style octal literals, which Python ++used before version 3.0. ++ ++Some examples of integer literals: ++ ++ 7 2147483647 0o177 0b100110111 ++ 3 79228162514264337593543950336 0o377 0xdeadbeef ++ 100_000_000_000 0b_1110_0101 ++ ++Changed in version 3.6: Underscores are now allowed for grouping ++purposes in literals. ++''', ++ 'lambda': r'''Lambdas ++******* ++ ++ **lambda_expr**: "lambda" ["parameter_list"] ":" "expression" ++ ++Lambda expressions (sometimes called lambda forms) are used to create ++anonymous functions. The expression "lambda parameters: expression" ++yields a function object. The unnamed object behaves like a function ++object defined with: ++ ++ def (parameters): ++ return expression ++ ++See section Function definitions for the syntax of parameter lists. ++Note that functions created with lambda expressions cannot contain ++statements or annotations. ++''', ++ 'lists': r'''List displays ++************* ++ ++A list display is a possibly empty series of expressions enclosed in ++square brackets: ++ ++ **list_display**: "[" ["flexible_expression_list" | "comprehension"] "]" ++ ++A list display yields a new list object, the contents being specified ++by either a list of expressions or a comprehension. When a comma- ++separated list of expressions is supplied, its elements are evaluated ++from left to right and placed into the list object in that order. ++When a comprehension is supplied, the list is constructed from the ++elements resulting from the comprehension. ++''', ++ 'naming': r'''Naming and binding ++****************** ++ ++ ++Binding of names ++================ ++ ++*Names* refer to objects. Names are introduced by name binding ++operations. ++ ++The following constructs bind names: ++ ++* formal parameters to functions, ++ ++* class definitions, ++ ++* function definitions, ++ ++* assignment expressions, ++ ++* targets that are identifiers if occurring in an assignment: ++ ++ * "for" loop header, ++ ++ * after "as" in a "with" statement, "except" clause, "except*" ++ clause, or in the as-pattern in structural pattern matching, ++ ++ * in a capture pattern in structural pattern matching ++ ++* "import" statements. ++ ++* "type" statements. ++ ++* type parameter lists. ++ ++The "import" statement of the form "from ... import *" binds all names ++defined in the imported module, except those beginning with an ++underscore. This form may only be used at the module level. ++ ++A target occurring in a "del" statement is also considered bound for ++this purpose (though the actual semantics are to unbind the name). ++ ++Each assignment or import statement occurs within a block defined by a ++class or function definition or at the module level (the top-level ++code block). ++ ++If a name is bound in a block, it is a local variable of that block, ++unless declared as "nonlocal" or "global". If a name is bound at the ++module level, it is a global variable. (The variables of the module ++code block are local and global.) If a variable is used in a code ++block but not defined there, it is a *free variable*. ++ ++Each occurrence of a name in the program text refers to the *binding* ++of that name established by the following name resolution rules. ++ ++ ++Resolution of names ++=================== ++ ++A *scope* defines the visibility of a name within a block. If a local ++variable is defined in a block, its scope includes that block. If the ++definition occurs in a function block, the scope extends to any blocks ++contained within the defining one, unless a contained block introduces ++a different binding for the name. ++ ++When a name is used in a code block, it is resolved using the nearest ++enclosing scope. The set of all such scopes visible to a code block ++is called the block’s *environment*. ++ ++When a name is not found at all, a "NameError" exception is raised. If ++the current scope is a function scope, and the name refers to a local ++variable that has not yet been bound to a value at the point where the ++name is used, an "UnboundLocalError" exception is raised. ++"UnboundLocalError" is a subclass of "NameError". ++ ++If a name binding operation occurs anywhere within a code block, all ++uses of the name within the block are treated as references to the ++current block. This can lead to errors when a name is used within a ++block before it is bound. This rule is subtle. Python lacks ++declarations and allows name binding operations to occur anywhere ++within a code block. The local variables of a code block can be ++determined by scanning the entire text of the block for name binding ++operations. See the FAQ entry on UnboundLocalError for examples. ++ ++If the "global" statement occurs within a block, all uses of the names ++specified in the statement refer to the bindings of those names in the ++top-level namespace. Names are resolved in the top-level namespace by ++searching the global namespace, i.e. the namespace of the module ++containing the code block, and the builtins namespace, the namespace ++of the module "builtins". The global namespace is searched first. If ++the names are not found there, the builtins namespace is searched ++next. If the names are also not found in the builtins namespace, new ++variables are created in the global namespace. The global statement ++must precede all uses of the listed names. ++ ++The "global" statement has the same scope as a name binding operation ++in the same block. If the nearest enclosing scope for a free variable ++contains a global statement, the free variable is treated as a global. ++ ++The "nonlocal" statement causes corresponding names to refer to ++previously bound variables in the nearest enclosing function scope. ++"SyntaxError" is raised at compile time if the given name does not ++exist in any enclosing function scope. Type parameters cannot be ++rebound with the "nonlocal" statement. ++ ++The namespace for a module is automatically created the first time a ++module is imported. The main module for a script is always called ++"__main__". ++ ++Class definition blocks and arguments to "exec()" and "eval()" are ++special in the context of name resolution. A class definition is an ++executable statement that may use and define names. These references ++follow the normal rules for name resolution with an exception that ++unbound local variables are looked up in the global namespace. The ++namespace of the class definition becomes the attribute dictionary of ++the class. The scope of names defined in a class block is limited to ++the class block; it does not extend to the code blocks of methods. ++This includes comprehensions and generator expressions, but it does ++not include annotation scopes, which have access to their enclosing ++class scopes. This means that the following will fail: ++ ++ class A: ++ a = 42 ++ b = list(a + i for i in range(10)) ++ ++However, the following will succeed: ++ ++ class A: ++ type Alias = Nested ++ class Nested: pass ++ ++ print(A.Alias.__value__) # ++ ++ ++Annotation scopes ++================= ++ ++*Annotations*, type parameter lists and "type" statements introduce ++*annotation scopes*, which behave mostly like function scopes, but ++with some exceptions discussed below. ++ ++Annotation scopes are used in the following contexts: ++ ++* *Function annotations*. ++ ++* *Variable annotations*. ++ ++* Type parameter lists for generic type aliases. ++ ++* Type parameter lists for generic functions. A generic function’s ++ annotations are executed within the annotation scope, but its ++ defaults and decorators are not. ++ ++* Type parameter lists for generic classes. A generic class’s base ++ classes and keyword arguments are executed within the annotation ++ scope, but its decorators are not. ++ ++* The bounds, constraints, and default values for type parameters ++ (lazily evaluated). ++ ++* The value of type aliases (lazily evaluated). ++ ++Annotation scopes differ from function scopes in the following ways: ++ ++* Annotation scopes have access to their enclosing class namespace. If ++ an annotation scope is immediately within a class scope, or within ++ another annotation scope that is immediately within a class scope, ++ the code in the annotation scope can use names defined in the class ++ scope as if it were executed directly within the class body. This ++ contrasts with regular functions defined within classes, which ++ cannot access names defined in the class scope. ++ ++* Expressions in annotation scopes cannot contain "yield", "yield ++ from", "await", or ":=" expressions. (These expressions are allowed ++ in other scopes contained within the annotation scope.) ++ ++* Names defined in annotation scopes cannot be rebound with "nonlocal" ++ statements in inner scopes. This includes only type parameters, as ++ no other syntactic elements that can appear within annotation scopes ++ can introduce new names. ++ ++* While annotation scopes have an internal name, that name is not ++ reflected in the *qualified name* of objects defined within the ++ scope. Instead, the "__qualname__" of such objects is as if the ++ object were defined in the enclosing scope. ++ ++Added in version 3.12: Annotation scopes were introduced in Python ++3.12 as part of **PEP 695**. ++ ++Changed in version 3.13: Annotation scopes are also used for type ++parameter defaults, as introduced by **PEP 696**. ++ ++Changed in version 3.14: Annotation scopes are now also used for ++annotations, as specified in **PEP 649** and **PEP 749**. ++ ++ ++Lazy evaluation ++=============== ++ ++Most annotation scopes are *lazily evaluated*. This includes ++annotations, the values of type aliases created through the "type" ++statement, and the bounds, constraints, and default values of type ++variables created through the type parameter syntax. This means that ++they are not evaluated when the type alias or type variable is ++created, or when the object carrying annotations is created. Instead, ++they are only evaluated when necessary, for example when the ++"__value__" attribute on a type alias is accessed. ++ ++Example: ++ ++ >>> type Alias = 1/0 ++ >>> Alias.__value__ ++ Traceback (most recent call last): ++ ... ++ ZeroDivisionError: division by zero ++ >>> def func[T: 1/0](): pass ++ >>> T = func.__type_params__[0] ++ >>> T.__bound__ ++ Traceback (most recent call last): ++ ... ++ ZeroDivisionError: division by zero ++ ++Here the exception is raised only when the "__value__" attribute of ++the type alias or the "__bound__" attribute of the type variable is ++accessed. ++ ++This behavior is primarily useful for references to types that have ++not yet been defined when the type alias or type variable is created. ++For example, lazy evaluation enables creation of mutually recursive ++type aliases: ++ ++ from typing import Literal ++ ++ type SimpleExpr = int | Parenthesized ++ type Parenthesized = tuple[Literal["("], Expr, Literal[")"]] ++ type Expr = SimpleExpr | tuple[SimpleExpr, Literal["+", "-"], Expr] ++ ++Lazily evaluated values are evaluated in annotation scope, which means ++that names that appear inside the lazily evaluated value are looked up ++as if they were used in the immediately enclosing scope. ++ ++Added in version 3.12. ++ ++ ++Builtins and restricted execution ++================================= ++ ++**CPython implementation detail:** Users should not touch ++"__builtins__"; it is strictly an implementation detail. Users ++wanting to override values in the builtins namespace should "import" ++the "builtins" module and modify its attributes appropriately. ++ ++The builtins namespace associated with the execution of a code block ++is actually found by looking up the name "__builtins__" in its global ++namespace; this should be a dictionary or a module (in the latter case ++the module’s dictionary is used). By default, when in the "__main__" ++module, "__builtins__" is the built-in module "builtins"; when in any ++other module, "__builtins__" is an alias for the dictionary of the ++"builtins" module itself. ++ ++ ++Interaction with dynamic features ++================================= ++ ++Name resolution of free variables occurs at runtime, not at compile ++time. This means that the following code will print 42: ++ ++ i = 10 ++ def f(): ++ print(i) ++ i = 42 ++ f() ++ ++The "eval()" and "exec()" functions do not have access to the full ++environment for resolving names. Names may be resolved in the local ++and global namespaces of the caller. Free variables are not resolved ++in the nearest enclosing namespace, but in the global namespace. [1] ++The "exec()" and "eval()" functions have optional arguments to ++override the global and local namespace. If only one namespace is ++specified, it is used for both. ++''', ++ 'nonlocal': r'''The "nonlocal" statement ++************************ ++ ++ **nonlocal_stmt**: "nonlocal" "identifier" ("," "identifier")* ++ ++When the definition of a function or class is nested (enclosed) within ++the definitions of other functions, its nonlocal scopes are the local ++scopes of the enclosing functions. The "nonlocal" statement causes the ++listed identifiers to refer to names previously bound in nonlocal ++scopes. It allows encapsulated code to rebind such nonlocal ++identifiers. If a name is bound in more than one nonlocal scope, the ++nearest binding is used. If a name is not bound in any nonlocal scope, ++or if there is no nonlocal scope, a "SyntaxError" is raised. ++ ++The "nonlocal" statement applies to the entire scope of a function or ++class body. A "SyntaxError" is raised if a variable is used or ++assigned to prior to its nonlocal declaration in the scope. ++ ++See also: ++ ++ **PEP 3104** - Access to Names in Outer Scopes ++ The specification for the "nonlocal" statement. ++ ++**Programmer’s note:** "nonlocal" is a directive to the parser and ++applies only to code parsed along with it. See the note for the ++"global" statement. ++''', ++ 'numbers': r'''Numeric literals ++**************** ++ ++There are three types of numeric literals: integers, floating-point ++numbers, and imaginary numbers. There are no complex literals ++(complex numbers can be formed by adding a real number and an ++imaginary number). ++ ++Note that numeric literals do not include a sign; a phrase like "-1" ++is actually an expression composed of the unary operator ‘"-"’ and the ++literal "1". ++''', ++ 'numeric-types': r'''Emulating numeric types ++*********************** ++ ++The following methods can be defined to emulate numeric objects. ++Methods corresponding to operations that are not supported by the ++particular kind of number implemented (e.g., bitwise operations for ++non-integral numbers) should be left undefined. ++ ++object.__add__(self, other) ++object.__sub__(self, other) ++object.__mul__(self, other) ++object.__matmul__(self, other) ++object.__truediv__(self, other) ++object.__floordiv__(self, other) ++object.__mod__(self, other) ++object.__divmod__(self, other) ++object.__pow__(self, other[, modulo]) ++object.__lshift__(self, other) ++object.__rshift__(self, other) ++object.__and__(self, other) ++object.__xor__(self, other) ++object.__or__(self, other) ++ ++ These methods are called to implement the binary arithmetic ++ operations ("+", "-", "*", "@", "/", "//", "%", "divmod()", ++ "pow()", "**", "<<", ">>", "&", "^", "|"). For instance, to ++ evaluate the expression "x + y", where *x* is an instance of a ++ class that has an "__add__()" method, "type(x).__add__(x, y)" is ++ called. The "__divmod__()" method should be the equivalent to ++ using "__floordiv__()" and "__mod__()"; it should not be related to ++ "__truediv__()". Note that "__pow__()" should be defined to accept ++ an optional third argument if the ternary version of the built-in ++ "pow()" function is to be supported. ++ ++ If one of those methods does not support the operation with the ++ supplied arguments, it should return "NotImplemented". ++ ++object.__radd__(self, other) ++object.__rsub__(self, other) ++object.__rmul__(self, other) ++object.__rmatmul__(self, other) ++object.__rtruediv__(self, other) ++object.__rfloordiv__(self, other) ++object.__rmod__(self, other) ++object.__rdivmod__(self, other) ++object.__rpow__(self, other[, modulo]) ++object.__rlshift__(self, other) ++object.__rrshift__(self, other) ++object.__rand__(self, other) ++object.__rxor__(self, other) ++object.__ror__(self, other) ++ ++ These methods are called to implement the binary arithmetic ++ operations ("+", "-", "*", "@", "/", "//", "%", "divmod()", ++ "pow()", "**", "<<", ">>", "&", "^", "|") with reflected (swapped) ++ operands. These functions are only called if the operands are of ++ different types, when the left operand does not support the ++ corresponding operation [3], or the right operand’s class is ++ derived from the left operand’s class. [4] For instance, to ++ evaluate the expression "x - y", where *y* is an instance of a ++ class that has an "__rsub__()" method, "type(y).__rsub__(y, x)" is ++ called if "type(x).__sub__(x, y)" returns "NotImplemented" or ++ "type(y)" is a subclass of "type(x)". [5] ++ ++ Note that ternary "pow()" will not try calling "__rpow__()" (the ++ coercion rules would become too complicated). ++ ++ Note: ++ ++ If the right operand’s type is a subclass of the left operand’s ++ type and that subclass provides a different implementation of the ++ reflected method for the operation, this method will be called ++ before the left operand’s non-reflected method. This behavior ++ allows subclasses to override their ancestors’ operations. ++ ++object.__iadd__(self, other) ++object.__isub__(self, other) ++object.__imul__(self, other) ++object.__imatmul__(self, other) ++object.__itruediv__(self, other) ++object.__ifloordiv__(self, other) ++object.__imod__(self, other) ++object.__ipow__(self, other[, modulo]) ++object.__ilshift__(self, other) ++object.__irshift__(self, other) ++object.__iand__(self, other) ++object.__ixor__(self, other) ++object.__ior__(self, other) ++ ++ These methods are called to implement the augmented arithmetic ++ assignments ("+=", "-=", "*=", "@=", "/=", "//=", "%=", "**=", ++ "<<=", ">>=", "&=", "^=", "|="). These methods should attempt to ++ do the operation in-place (modifying *self*) and return the result ++ (which could be, but does not have to be, *self*). If a specific ++ method is not defined, or if that method returns "NotImplemented", ++ the augmented assignment falls back to the normal methods. For ++ instance, if *x* is an instance of a class with an "__iadd__()" ++ method, "x += y" is equivalent to "x = x.__iadd__(y)" . If ++ "__iadd__()" does not exist, or if "x.__iadd__(y)" returns ++ "NotImplemented", "x.__add__(y)" and "y.__radd__(x)" are ++ considered, as with the evaluation of "x + y". In certain ++ situations, augmented assignment can result in unexpected errors ++ (see Why does a_tuple[i] += [‘item’] raise an exception when the ++ addition works?), but this behavior is in fact part of the data ++ model. ++ ++object.__neg__(self) ++object.__pos__(self) ++object.__abs__(self) ++object.__invert__(self) ++ ++ Called to implement the unary arithmetic operations ("-", "+", ++ "abs()" and "~"). ++ ++object.__complex__(self) ++object.__int__(self) ++object.__float__(self) ++ ++ Called to implement the built-in functions "complex()", "int()" and ++ "float()". Should return a value of the appropriate type. ++ ++object.__index__(self) ++ ++ Called to implement "operator.index()", and whenever Python needs ++ to losslessly convert the numeric object to an integer object (such ++ as in slicing, or in the built-in "bin()", "hex()" and "oct()" ++ functions). Presence of this method indicates that the numeric ++ object is an integer type. Must return an integer. ++ ++ If "__int__()", "__float__()" and "__complex__()" are not defined ++ then corresponding built-in functions "int()", "float()" and ++ "complex()" fall back to "__index__()". ++ ++object.__round__(self[, ndigits]) ++object.__trunc__(self) ++object.__floor__(self) ++object.__ceil__(self) ++ ++ Called to implement the built-in function "round()" and "math" ++ functions "trunc()", "floor()" and "ceil()". Unless *ndigits* is ++ passed to "__round__()" all these methods should return the value ++ of the object truncated to an "Integral" (typically an "int"). ++ ++ Changed in version 3.14: "int()" no longer delegates to the ++ "__trunc__()" method. ++''', ++ 'objects': r'''Objects, values and types ++************************* ++ ++*Objects* are Python’s abstraction for data. All data in a Python ++program is represented by objects or by relations between objects. (In ++a sense, and in conformance to Von Neumann’s model of a “stored ++program computerâ€, code is also represented by objects.) ++ ++Every object has an identity, a type and a value. An object’s ++*identity* never changes once it has been created; you may think of it ++as the object’s address in memory. The "is" operator compares the ++identity of two objects; the "id()" function returns an integer ++representing its identity. ++ ++**CPython implementation detail:** For CPython, "id(x)" is the memory ++address where "x" is stored. ++ ++An object’s type determines the operations that the object supports ++(e.g., “does it have a length?â€) and also defines the possible values ++for objects of that type. The "type()" function returns an object’s ++type (which is an object itself). Like its identity, an object’s ++*type* is also unchangeable. [1] ++ ++The *value* of some objects can change. Objects whose value can ++change are said to be *mutable*; objects whose value is unchangeable ++once they are created are called *immutable*. (The value of an ++immutable container object that contains a reference to a mutable ++object can change when the latter’s value is changed; however the ++container is still considered immutable, because the collection of ++objects it contains cannot be changed. So, immutability is not ++strictly the same as having an unchangeable value, it is more subtle.) ++An object’s mutability is determined by its type; for instance, ++numbers, strings and tuples are immutable, while dictionaries and ++lists are mutable. ++ ++Objects are never explicitly destroyed; however, when they become ++unreachable they may be garbage-collected. An implementation is ++allowed to postpone garbage collection or omit it altogether — it is a ++matter of implementation quality how garbage collection is ++implemented, as long as no objects are collected that are still ++reachable. ++ ++**CPython implementation detail:** CPython currently uses a reference- ++counting scheme with (optional) delayed detection of cyclically linked ++garbage, which collects most objects as soon as they become ++unreachable, but is not guaranteed to collect garbage containing ++circular references. See the documentation of the "gc" module for ++information on controlling the collection of cyclic garbage. Other ++implementations act differently and CPython may change. Do not depend ++on immediate finalization of objects when they become unreachable (so ++you should always close files explicitly). ++ ++Note that the use of the implementation’s tracing or debugging ++facilities may keep objects alive that would normally be collectable. ++Also note that catching an exception with a "try"…"except" statement ++may keep objects alive. ++ ++Some objects contain references to “external†resources such as open ++files or windows. It is understood that these resources are freed ++when the object is garbage-collected, but since garbage collection is ++not guaranteed to happen, such objects also provide an explicit way to ++release the external resource, usually a "close()" method. Programs ++are strongly recommended to explicitly close such objects. The ++"try"…"finally" statement and the "with" statement provide convenient ++ways to do this. ++ ++Some objects contain references to other objects; these are called ++*containers*. Examples of containers are tuples, lists and ++dictionaries. The references are part of a container’s value. In ++most cases, when we talk about the value of a container, we imply the ++values, not the identities of the contained objects; however, when we ++talk about the mutability of a container, only the identities of the ++immediately contained objects are implied. So, if an immutable ++container (like a tuple) contains a reference to a mutable object, its ++value changes if that mutable object is changed. ++ ++Types affect almost all aspects of object behavior. Even the ++importance of object identity is affected in some sense: for immutable ++types, operations that compute new values may actually return a ++reference to any existing object with the same type and value, while ++for mutable objects this is not allowed. For example, after "a = 1; b ++= 1", *a* and *b* may or may not refer to the same object with the ++value one, depending on the implementation. This is because "int" is ++an immutable type, so the reference to "1" can be reused. This ++behaviour depends on the implementation used, so should not be relied ++upon, but is something to be aware of when making use of object ++identity tests. However, after "c = []; d = []", *c* and *d* are ++guaranteed to refer to two different, unique, newly created empty ++lists. (Note that "e = f = []" assigns the *same* object to both *e* ++and *f*.) ++''', ++ 'operator-summary': r'''Operator precedence ++******************* ++ ++The following table summarizes the operator precedence in Python, from ++highest precedence (most binding) to lowest precedence (least ++binding). Operators in the same box have the same precedence. Unless ++the syntax is explicitly given, operators are binary. Operators in ++the same box group left to right (except for exponentiation and ++conditional expressions, which group from right to left). ++ ++Note that comparisons, membership tests, and identity tests, all have ++the same precedence and have a left-to-right chaining feature as ++described in the Comparisons section. ++ +++-------------------------------------------------+---------------------------------------+ ++| Operator | Description | ++|=================================================|=======================================| ++| "(expressions...)", "[expressions...]", "{key: | Binding or parenthesized expression, | ++| value...}", "{expressions...}" | list display, dictionary display, set | ++| | display | +++-------------------------------------------------+---------------------------------------+ ++| "x[index]", "x[index:index]", | Subscription, slicing, call, | ++| "x(arguments...)", "x.attribute" | attribute reference | +++-------------------------------------------------+---------------------------------------+ ++| "await x" | Await expression | +++-------------------------------------------------+---------------------------------------+ ++| "**" | Exponentiation [5] | +++-------------------------------------------------+---------------------------------------+ ++| "+x", "-x", "~x" | Positive, negative, bitwise NOT | +++-------------------------------------------------+---------------------------------------+ ++| "*", "@", "/", "//", "%" | Multiplication, matrix | ++| | multiplication, division, floor | ++| | division, remainder [6] | +++-------------------------------------------------+---------------------------------------+ ++| "+", "-" | Addition and subtraction | +++-------------------------------------------------+---------------------------------------+ ++| "<<", ">>" | Shifts | +++-------------------------------------------------+---------------------------------------+ ++| "&" | Bitwise AND | +++-------------------------------------------------+---------------------------------------+ ++| "^" | Bitwise XOR | +++-------------------------------------------------+---------------------------------------+ ++| "|" | Bitwise OR | +++-------------------------------------------------+---------------------------------------+ ++| "in", "not in", "is", "is not", "<", "<=", ">", | Comparisons, including membership | ++| ">=", "!=", "==" | tests and identity tests | +++-------------------------------------------------+---------------------------------------+ ++| "not x" | Boolean NOT | +++-------------------------------------------------+---------------------------------------+ ++| "and" | Boolean AND | +++-------------------------------------------------+---------------------------------------+ ++| "or" | Boolean OR | +++-------------------------------------------------+---------------------------------------+ ++| "if" – "else" | Conditional expression | +++-------------------------------------------------+---------------------------------------+ ++| "lambda" | Lambda expression | +++-------------------------------------------------+---------------------------------------+ ++| ":=" | Assignment expression | +++-------------------------------------------------+---------------------------------------+ ++ ++-[ Footnotes ]- ++ ++[1] While "abs(x%y) < abs(y)" is true mathematically, for floats it ++ may not be true numerically due to roundoff. For example, and ++ assuming a platform on which a Python float is an IEEE 754 double- ++ precision number, in order that "-1e-100 % 1e100" have the same ++ sign as "1e100", the computed result is "-1e-100 + 1e100", which ++ is numerically exactly equal to "1e100". The function ++ "math.fmod()" returns a result whose sign matches the sign of the ++ first argument instead, and so returns "-1e-100" in this case. ++ Which approach is more appropriate depends on the application. ++ ++[2] If x is very close to an exact integer multiple of y, it’s ++ possible for "x//y" to be one larger than "(x-x%y)//y" due to ++ rounding. In such cases, Python returns the latter result, in ++ order to preserve that "divmod(x,y)[0] * y + x % y" be very close ++ to "x". ++ ++[3] The Unicode standard distinguishes between *code points* (e.g. ++ U+0041) and *abstract characters* (e.g. “LATIN CAPITAL LETTER Aâ€). ++ While most abstract characters in Unicode are only represented ++ using one code point, there is a number of abstract characters ++ that can in addition be represented using a sequence of more than ++ one code point. For example, the abstract character “LATIN ++ CAPITAL LETTER C WITH CEDILLA†can be represented as a single ++ *precomposed character* at code position U+00C7, or as a sequence ++ of a *base character* at code position U+0043 (LATIN CAPITAL ++ LETTER C), followed by a *combining character* at code position ++ U+0327 (COMBINING CEDILLA). ++ ++ The comparison operators on strings compare at the level of ++ Unicode code points. This may be counter-intuitive to humans. For ++ example, ""\u00C7" == "\u0043\u0327"" is "False", even though both ++ strings represent the same abstract character “LATIN CAPITAL ++ LETTER C WITH CEDILLAâ€. ++ ++ To compare strings at the level of abstract characters (that is, ++ in a way intuitive to humans), use "unicodedata.normalize()". ++ ++[4] Due to automatic garbage-collection, free lists, and the dynamic ++ nature of descriptors, you may notice seemingly unusual behaviour ++ in certain uses of the "is" operator, like those involving ++ comparisons between instance methods, or constants. Check their ++ documentation for more info. ++ ++[5] The power operator "**" binds less tightly than an arithmetic or ++ bitwise unary operator on its right, that is, "2**-1" is "0.5". ++ ++[6] The "%" operator is also used for string formatting; the same ++ precedence applies. ++''', ++ 'pass': r'''The "pass" statement ++******************** ++ ++ **pass_stmt**: "pass" ++ ++"pass" is a null operation — when it is executed, nothing happens. It ++is useful as a placeholder when a statement is required syntactically, ++but no code needs to be executed, for example: ++ ++ def f(arg): pass # a function that does nothing (yet) ++ ++ class C: pass # a class with no methods (yet) ++''', ++ 'power': r'''The power operator ++****************** ++ ++The power operator binds more tightly than unary operators on its ++left; it binds less tightly than unary operators on its right. The ++syntax is: ++ ++ **power**: ("await_expr" | "primary") ["**" "u_expr"] ++ ++Thus, in an unparenthesized sequence of power and unary operators, the ++operators are evaluated from right to left (this does not constrain ++the evaluation order for the operands): "-1**2" results in "-1". ++ ++The power operator has the same semantics as the built-in "pow()" ++function, when called with two arguments: it yields its left argument ++raised to the power of its right argument. The numeric arguments are ++first converted to a common type, and the result is of that type. ++ ++For int operands, the result has the same type as the operands unless ++the second argument is negative; in that case, all arguments are ++converted to float and a float result is delivered. For example, ++"10**2" returns "100", but "10**-2" returns "0.01". ++ ++Raising "0.0" to a negative power results in a "ZeroDivisionError". ++Raising a negative number to a fractional power results in a "complex" ++number. (In earlier versions it raised a "ValueError".) ++ ++This operation can be customized using the special "__pow__()" and ++"__rpow__()" methods. ++''', ++ 'raise': r'''The "raise" statement ++********************* ++ ++ **raise_stmt**: "raise" ["expression" ["from" "expression"]] ++ ++If no expressions are present, "raise" re-raises the exception that is ++currently being handled, which is also known as the *active ++exception*. If there isn’t currently an active exception, a ++"RuntimeError" exception is raised indicating that this is an error. ++ ++Otherwise, "raise" evaluates the first expression as the exception ++object. It must be either a subclass or an instance of ++"BaseException". If it is a class, the exception instance will be ++obtained when needed by instantiating the class with no arguments. ++ ++The *type* of the exception is the exception instance’s class, the ++*value* is the instance itself. ++ ++A traceback object is normally created automatically when an exception ++is raised and attached to it as the "__traceback__" attribute. You can ++create an exception and set your own traceback in one step using the ++"with_traceback()" exception method (which returns the same exception ++instance, with its traceback set to its argument), like so: ++ ++ raise Exception("foo occurred").with_traceback(tracebackobj) ++ ++The "from" clause is used for exception chaining: if given, the second ++*expression* must be another exception class or instance. If the ++second expression is an exception instance, it will be attached to the ++raised exception as the "__cause__" attribute (which is writable). If ++the expression is an exception class, the class will be instantiated ++and the resulting exception instance will be attached to the raised ++exception as the "__cause__" attribute. If the raised exception is not ++handled, both exceptions will be printed: ++ ++ >>> try: ++ ... print(1 / 0) ++ ... except Exception as exc: ++ ... raise RuntimeError("Something bad happened") from exc ++ ... ++ Traceback (most recent call last): ++ File "", line 2, in ++ print(1 / 0) ++ ~~^~~ ++ ZeroDivisionError: division by zero ++ ++ The above exception was the direct cause of the following exception: ++ ++ Traceback (most recent call last): ++ File "", line 4, in ++ raise RuntimeError("Something bad happened") from exc ++ RuntimeError: Something bad happened ++ ++A similar mechanism works implicitly if a new exception is raised when ++an exception is already being handled. An exception may be handled ++when an "except" or "finally" clause, or a "with" statement, is used. ++The previous exception is then attached as the new exception’s ++"__context__" attribute: ++ ++ >>> try: ++ ... print(1 / 0) ++ ... except: ++ ... raise RuntimeError("Something bad happened") ++ ... ++ Traceback (most recent call last): ++ File "", line 2, in ++ print(1 / 0) ++ ~~^~~ ++ ZeroDivisionError: division by zero ++ ++ During handling of the above exception, another exception occurred: ++ ++ Traceback (most recent call last): ++ File "", line 4, in ++ raise RuntimeError("Something bad happened") ++ RuntimeError: Something bad happened ++ ++Exception chaining can be explicitly suppressed by specifying "None" ++in the "from" clause: ++ ++ >>> try: ++ ... print(1 / 0) ++ ... except: ++ ... raise RuntimeError("Something bad happened") from None ++ ... ++ Traceback (most recent call last): ++ File "", line 4, in ++ RuntimeError: Something bad happened ++ ++Additional information on exceptions can be found in section ++Exceptions, and information about handling exceptions is in section ++The try statement. ++ ++Changed in version 3.3: "None" is now permitted as "Y" in "raise X ++from Y".Added the "__suppress_context__" attribute to suppress ++automatic display of the exception context. ++ ++Changed in version 3.11: If the traceback of the active exception is ++modified in an "except" clause, a subsequent "raise" statement re- ++raises the exception with the modified traceback. Previously, the ++exception was re-raised with the traceback it had when it was caught. ++''', ++ 'return': r'''The "return" statement ++********************** ++ ++ **return_stmt**: "return" ["expression_list"] ++ ++"return" may only occur syntactically nested in a function definition, ++not within a nested class definition. ++ ++If an expression list is present, it is evaluated, else "None" is ++substituted. ++ ++"return" leaves the current function call with the expression list (or ++"None") as return value. ++ ++When "return" passes control out of a "try" statement with a "finally" ++clause, that "finally" clause is executed before really leaving the ++function. ++ ++In a generator function, the "return" statement indicates that the ++generator is done and will cause "StopIteration" to be raised. The ++returned value (if any) is used as an argument to construct ++"StopIteration" and becomes the "StopIteration.value" attribute. ++ ++In an asynchronous generator function, an empty "return" statement ++indicates that the asynchronous generator is done and will cause ++"StopAsyncIteration" to be raised. A non-empty "return" statement is ++a syntax error in an asynchronous generator function. ++''', ++ 'sequence-types': r'''Emulating container types ++************************* ++ ++The following methods can be defined to implement container objects. ++None of them are provided by the "object" class itself. Containers ++usually are *sequences* (such as "lists" or "tuples") or *mappings* ++(like *dictionaries*), but can represent other containers as well. ++The first set of methods is used either to emulate a sequence or to ++emulate a mapping; the difference is that for a sequence, the ++allowable keys should be the integers *k* for which "0 <= k < N" where ++*N* is the length of the sequence, or "slice" objects, which define a ++range of items. It is also recommended that mappings provide the ++methods "keys()", "values()", "items()", "get()", "clear()", ++"setdefault()", "pop()", "popitem()", "copy()", and "update()" ++behaving similar to those for Python’s standard "dictionary" objects. ++The "collections.abc" module provides a "MutableMapping" *abstract ++base class* to help create those methods from a base set of ++"__getitem__()", "__setitem__()", "__delitem__()", and "keys()". ++Mutable sequences should provide methods "append()", "count()", ++"index()", "extend()", "insert()", "pop()", "remove()", "reverse()" ++and "sort()", like Python standard "list" objects. Finally, sequence ++types should implement addition (meaning concatenation) and ++multiplication (meaning repetition) by defining the methods ++"__add__()", "__radd__()", "__iadd__()", "__mul__()", "__rmul__()" and ++"__imul__()" described below; they should not define other numerical ++operators. It is recommended that both mappings and sequences ++implement the "__contains__()" method to allow efficient use of the ++"in" operator; for mappings, "in" should search the mapping’s keys; ++for sequences, it should search through the values. It is further ++recommended that both mappings and sequences implement the ++"__iter__()" method to allow efficient iteration through the ++container; for mappings, "__iter__()" should iterate through the ++object’s keys; for sequences, it should iterate through the values. ++ ++object.__len__(self) ++ ++ Called to implement the built-in function "len()". Should return ++ the length of the object, an integer ">=" 0. Also, an object that ++ doesn’t define a "__bool__()" method and whose "__len__()" method ++ returns zero is considered to be false in a Boolean context. ++ ++ **CPython implementation detail:** In CPython, the length is ++ required to be at most "sys.maxsize". If the length is larger than ++ "sys.maxsize" some features (such as "len()") may raise ++ "OverflowError". To prevent raising "OverflowError" by truth value ++ testing, an object must define a "__bool__()" method. ++ ++object.__length_hint__(self) ++ ++ Called to implement "operator.length_hint()". Should return an ++ estimated length for the object (which may be greater or less than ++ the actual length). The length must be an integer ">=" 0. The ++ return value may also be "NotImplemented", which is treated the ++ same as if the "__length_hint__" method didn’t exist at all. This ++ method is purely an optimization and is never required for ++ correctness. ++ ++ Added in version 3.4. ++ ++Note: ++ ++ Slicing is done exclusively with the following three methods. A ++ call like ++ ++ a[1:2] = b ++ ++ is translated to ++ ++ a[slice(1, 2, None)] = b ++ ++ and so forth. Missing slice items are always filled in with "None". ++ ++object.__getitem__(self, key) ++ ++ Called to implement evaluation of "self[key]". For *sequence* ++ types, the accepted keys should be integers. Optionally, they may ++ support "slice" objects as well. Negative index support is also ++ optional. If *key* is of an inappropriate type, "TypeError" may be ++ raised; if *key* is a value outside the set of indexes for the ++ sequence (after any special interpretation of negative values), ++ "IndexError" should be raised. For *mapping* types, if *key* is ++ missing (not in the container), "KeyError" should be raised. ++ ++ Note: ++ ++ "for" loops expect that an "IndexError" will be raised for ++ illegal indexes to allow proper detection of the end of the ++ sequence. ++ ++ Note: ++ ++ When subscripting a *class*, the special class method ++ "__class_getitem__()" may be called instead of "__getitem__()". ++ See __class_getitem__ versus __getitem__ for more details. ++ ++object.__setitem__(self, key, value) ++ ++ Called to implement assignment to "self[key]". Same note as for ++ "__getitem__()". This should only be implemented for mappings if ++ the objects support changes to the values for keys, or if new keys ++ can be added, or for sequences if elements can be replaced. The ++ same exceptions should be raised for improper *key* values as for ++ the "__getitem__()" method. ++ ++object.__delitem__(self, key) ++ ++ Called to implement deletion of "self[key]". Same note as for ++ "__getitem__()". This should only be implemented for mappings if ++ the objects support removal of keys, or for sequences if elements ++ can be removed from the sequence. The same exceptions should be ++ raised for improper *key* values as for the "__getitem__()" method. ++ ++object.__missing__(self, key) ++ ++ Called by "dict"."__getitem__()" to implement "self[key]" for dict ++ subclasses when key is not in the dictionary. ++ ++object.__iter__(self) ++ ++ This method is called when an *iterator* is required for a ++ container. This method should return a new iterator object that can ++ iterate over all the objects in the container. For mappings, it ++ should iterate over the keys of the container. ++ ++object.__reversed__(self) ++ ++ Called (if present) by the "reversed()" built-in to implement ++ reverse iteration. It should return a new iterator object that ++ iterates over all the objects in the container in reverse order. ++ ++ If the "__reversed__()" method is not provided, the "reversed()" ++ built-in will fall back to using the sequence protocol ("__len__()" ++ and "__getitem__()"). Objects that support the sequence protocol ++ should only provide "__reversed__()" if they can provide an ++ implementation that is more efficient than the one provided by ++ "reversed()". ++ ++The membership test operators ("in" and "not in") are normally ++implemented as an iteration through a container. However, container ++objects can supply the following special method with a more efficient ++implementation, which also does not require the object be iterable. ++ ++object.__contains__(self, item) ++ ++ Called to implement membership test operators. Should return true ++ if *item* is in *self*, false otherwise. For mapping objects, this ++ should consider the keys of the mapping rather than the values or ++ the key-item pairs. ++ ++ For objects that don’t define "__contains__()", the membership test ++ first tries iteration via "__iter__()", then the old sequence ++ iteration protocol via "__getitem__()", see this section in the ++ language reference. ++''', ++ 'shifting': r'''Shifting operations ++******************* ++ ++The shifting operations have lower priority than the arithmetic ++operations: ++ ++ **shift_expr**: "a_expr" | "shift_expr" ("<<" | ">>") "a_expr" ++ ++These operators accept integers as arguments. They shift the first ++argument to the left or right by the number of bits given by the ++second argument. ++ ++The left shift operation can be customized using the special ++"__lshift__()" and "__rlshift__()" methods. The right shift operation ++can be customized using the special "__rshift__()" and "__rrshift__()" ++methods. ++ ++A right shift by *n* bits is defined as floor division by "pow(2,n)". ++A left shift by *n* bits is defined as multiplication with "pow(2,n)". ++''', ++ 'slicings': r'''Slicings ++******** ++ ++A slicing selects a range of items in a sequence object (e.g., a ++string, tuple or list). Slicings may be used as expressions or as ++targets in assignment or "del" statements. The syntax for a slicing: ++ ++ **slicing**: "primary" "[" "slice_list" "]" ++ **slice_list**: "slice_item" ("," "slice_item")* [","] ++ **slice_item**: "expression" | "proper_slice" ++ **proper_slice**: ["lower_bound"] ":" ["upper_bound"] [ ":" ["stride"] ] ++ **lower_bound**: "expression" ++ **upper_bound**: "expression" ++ **stride**: "expression" ++ ++There is ambiguity in the formal syntax here: anything that looks like ++an expression list also looks like a slice list, so any subscription ++can be interpreted as a slicing. Rather than further complicating the ++syntax, this is disambiguated by defining that in this case the ++interpretation as a subscription takes priority over the ++interpretation as a slicing (this is the case if the slice list ++contains no proper slice). ++ ++The semantics for a slicing are as follows. The primary is indexed ++(using the same "__getitem__()" method as normal subscription) with a ++key that is constructed from the slice list, as follows. If the slice ++list contains at least one comma, the key is a tuple containing the ++conversion of the slice items; otherwise, the conversion of the lone ++slice item is the key. The conversion of a slice item that is an ++expression is that expression. The conversion of a proper slice is a ++slice object (see section The standard type hierarchy) whose "start", ++"stop" and "step" attributes are the values of the expressions given ++as lower bound, upper bound and stride, respectively, substituting ++"None" for missing expressions. ++''', ++ 'specialattrs': r'''Special Attributes ++****************** ++ ++The implementation adds a few special read-only attributes to several ++object types, where they are relevant. Some of these are not reported ++by the "dir()" built-in function. ++ ++definition.__name__ ++ ++ The name of the class, function, method, descriptor, or generator ++ instance. ++ ++definition.__qualname__ ++ ++ The *qualified name* of the class, function, method, descriptor, or ++ generator instance. ++ ++ Added in version 3.3. ++ ++definition.__module__ ++ ++ The name of the module in which a class or function was defined. ++ ++definition.__doc__ ++ ++ The documentation string of a class or function, or "None" if ++ undefined. ++ ++definition.__type_params__ ++ ++ The type parameters of generic classes, functions, and type ++ aliases. For classes and functions that are not generic, this will ++ be an empty tuple. ++ ++ Added in version 3.12. ++''', ++ 'specialnames': r'''Special method names ++******************** ++ ++A class can implement certain operations that are invoked by special ++syntax (such as arithmetic operations or subscripting and slicing) by ++defining methods with special names. This is Python’s approach to ++*operator overloading*, allowing classes to define their own behavior ++with respect to language operators. For instance, if a class defines ++a method named "__getitem__()", and "x" is an instance of this class, ++then "x[i]" is roughly equivalent to "type(x).__getitem__(x, i)". ++Except where mentioned, attempts to execute an operation raise an ++exception when no appropriate method is defined (typically ++"AttributeError" or "TypeError"). ++ ++Setting a special method to "None" indicates that the corresponding ++operation is not available. For example, if a class sets "__iter__()" ++to "None", the class is not iterable, so calling "iter()" on its ++instances will raise a "TypeError" (without falling back to ++"__getitem__()"). [2] ++ ++When implementing a class that emulates any built-in type, it is ++important that the emulation only be implemented to the degree that it ++makes sense for the object being modelled. For example, some ++sequences may work well with retrieval of individual elements, but ++extracting a slice may not make sense. (One example of this is the ++"NodeList" interface in the W3C’s Document Object Model.) ++ ++ ++Basic customization ++=================== ++ ++object.__new__(cls[, ...]) ++ ++ Called to create a new instance of class *cls*. "__new__()" is a ++ static method (special-cased so you need not declare it as such) ++ that takes the class of which an instance was requested as its ++ first argument. The remaining arguments are those passed to the ++ object constructor expression (the call to the class). The return ++ value of "__new__()" should be the new object instance (usually an ++ instance of *cls*). ++ ++ Typical implementations create a new instance of the class by ++ invoking the superclass’s "__new__()" method using ++ "super().__new__(cls[, ...])" with appropriate arguments and then ++ modifying the newly created instance as necessary before returning ++ it. ++ ++ If "__new__()" is invoked during object construction and it returns ++ an instance of *cls*, then the new instance’s "__init__()" method ++ will be invoked like "__init__(self[, ...])", where *self* is the ++ new instance and the remaining arguments are the same as were ++ passed to the object constructor. ++ ++ If "__new__()" does not return an instance of *cls*, then the new ++ instance’s "__init__()" method will not be invoked. ++ ++ "__new__()" is intended mainly to allow subclasses of immutable ++ types (like int, str, or tuple) to customize instance creation. It ++ is also commonly overridden in custom metaclasses in order to ++ customize class creation. ++ ++object.__init__(self[, ...]) ++ ++ Called after the instance has been created (by "__new__()"), but ++ before it is returned to the caller. The arguments are those ++ passed to the class constructor expression. If a base class has an ++ "__init__()" method, the derived class’s "__init__()" method, if ++ any, must explicitly call it to ensure proper initialization of the ++ base class part of the instance; for example: ++ "super().__init__([args...])". ++ ++ Because "__new__()" and "__init__()" work together in constructing ++ objects ("__new__()" to create it, and "__init__()" to customize ++ it), no non-"None" value may be returned by "__init__()"; doing so ++ will cause a "TypeError" to be raised at runtime. ++ ++object.__del__(self) ++ ++ Called when the instance is about to be destroyed. This is also ++ called a finalizer or (improperly) a destructor. If a base class ++ has a "__del__()" method, the derived class’s "__del__()" method, ++ if any, must explicitly call it to ensure proper deletion of the ++ base class part of the instance. ++ ++ It is possible (though not recommended!) for the "__del__()" method ++ to postpone destruction of the instance by creating a new reference ++ to it. This is called object *resurrection*. It is ++ implementation-dependent whether "__del__()" is called a second ++ time when a resurrected object is about to be destroyed; the ++ current *CPython* implementation only calls it once. ++ ++ It is not guaranteed that "__del__()" methods are called for ++ objects that still exist when the interpreter exits. ++ "weakref.finalize" provides a straightforward way to register a ++ cleanup function to be called when an object is garbage collected. ++ ++ Note: ++ ++ "del x" doesn’t directly call "x.__del__()" — the former ++ decrements the reference count for "x" by one, and the latter is ++ only called when "x"’s reference count reaches zero. ++ ++ **CPython implementation detail:** It is possible for a reference ++ cycle to prevent the reference count of an object from going to ++ zero. In this case, the cycle will be later detected and deleted ++ by the *cyclic garbage collector*. A common cause of reference ++ cycles is when an exception has been caught in a local variable. ++ The frame’s locals then reference the exception, which references ++ its own traceback, which references the locals of all frames caught ++ in the traceback. ++ ++ See also: Documentation for the "gc" module. ++ ++ Warning: ++ ++ Due to the precarious circumstances under which "__del__()" ++ methods are invoked, exceptions that occur during their execution ++ are ignored, and a warning is printed to "sys.stderr" instead. ++ In particular: ++ ++ * "__del__()" can be invoked when arbitrary code is being ++ executed, including from any arbitrary thread. If "__del__()" ++ needs to take a lock or invoke any other blocking resource, it ++ may deadlock as the resource may already be taken by the code ++ that gets interrupted to execute "__del__()". ++ ++ * "__del__()" can be executed during interpreter shutdown. As a ++ consequence, the global variables it needs to access (including ++ other modules) may already have been deleted or set to "None". ++ Python guarantees that globals whose name begins with a single ++ underscore are deleted from their module before other globals ++ are deleted; if no other references to such globals exist, this ++ may help in assuring that imported modules are still available ++ at the time when the "__del__()" method is called. ++ ++object.__repr__(self) ++ ++ Called by the "repr()" built-in function to compute the “official†++ string representation of an object. If at all possible, this ++ should look like a valid Python expression that could be used to ++ recreate an object with the same value (given an appropriate ++ environment). If this is not possible, a string of the form ++ "<...some useful description...>" should be returned. The return ++ value must be a string object. If a class defines "__repr__()" but ++ not "__str__()", then "__repr__()" is also used when an “informal†++ string representation of instances of that class is required. ++ ++ This is typically used for debugging, so it is important that the ++ representation is information-rich and unambiguous. A default ++ implementation is provided by the "object" class itself. ++ ++object.__str__(self) ++ ++ Called by "str(object)", the default "__format__()" implementation, ++ and the built-in function "print()", to compute the “informal†or ++ nicely printable string representation of an object. The return ++ value must be a str object. ++ ++ This method differs from "object.__repr__()" in that there is no ++ expectation that "__str__()" return a valid Python expression: a ++ more convenient or concise representation can be used. ++ ++ The default implementation defined by the built-in type "object" ++ calls "object.__repr__()". ++ ++object.__bytes__(self) ++ ++ Called by bytes to compute a byte-string representation of an ++ object. This should return a "bytes" object. The "object" class ++ itself does not provide this method. ++ ++object.__format__(self, format_spec) ++ ++ Called by the "format()" built-in function, and by extension, ++ evaluation of formatted string literals and the "str.format()" ++ method, to produce a “formatted†string representation of an ++ object. The *format_spec* argument is a string that contains a ++ description of the formatting options desired. The interpretation ++ of the *format_spec* argument is up to the type implementing ++ "__format__()", however most classes will either delegate ++ formatting to one of the built-in types, or use a similar ++ formatting option syntax. ++ ++ See Format Specification Mini-Language for a description of the ++ standard formatting syntax. ++ ++ The return value must be a string object. ++ ++ The default implementation by the "object" class should be given an ++ empty *format_spec* string. It delegates to "__str__()". ++ ++ Changed in version 3.4: The __format__ method of "object" itself ++ raises a "TypeError" if passed any non-empty string. ++ ++ Changed in version 3.7: "object.__format__(x, '')" is now ++ equivalent to "str(x)" rather than "format(str(x), '')". ++ ++object.__lt__(self, other) ++object.__le__(self, other) ++object.__eq__(self, other) ++object.__ne__(self, other) ++object.__gt__(self, other) ++object.__ge__(self, other) ++ ++ These are the so-called “rich comparison†methods. The ++ correspondence between operator symbols and method names is as ++ follows: "xy" calls ++ "x.__gt__(y)", and "x>=y" calls "x.__ge__(y)". ++ ++ A rich comparison method may return the singleton "NotImplemented" ++ if it does not implement the operation for a given pair of ++ arguments. By convention, "False" and "True" are returned for a ++ successful comparison. However, these methods can return any value, ++ so if the comparison operator is used in a Boolean context (e.g., ++ in the condition of an "if" statement), Python will call "bool()" ++ on the value to determine if the result is true or false. ++ ++ By default, "object" implements "__eq__()" by using "is", returning ++ "NotImplemented" in the case of a false comparison: "True if x is y ++ else NotImplemented". For "__ne__()", by default it delegates to ++ "__eq__()" and inverts the result unless it is "NotImplemented". ++ There are no other implied relationships among the comparison ++ operators or default implementations; for example, the truth of ++ "(x.__hash__". ++ ++ If a class that does not override "__eq__()" wishes to suppress ++ hash support, it should include "__hash__ = None" in the class ++ definition. A class which defines its own "__hash__()" that ++ explicitly raises a "TypeError" would be incorrectly identified as ++ hashable by an "isinstance(obj, collections.abc.Hashable)" call. ++ ++ Note: ++ ++ By default, the "__hash__()" values of str and bytes objects are ++ “salted†with an unpredictable random value. Although they ++ remain constant within an individual Python process, they are not ++ predictable between repeated invocations of Python.This is ++ intended to provide protection against a denial-of-service caused ++ by carefully chosen inputs that exploit the worst case ++ performance of a dict insertion, *O*(*n*^2) complexity. See ++ http://ocert.org/advisories/ocert-2011-003.html for ++ details.Changing hash values affects the iteration order of sets. ++ Python has never made guarantees about this ordering (and it ++ typically varies between 32-bit and 64-bit builds).See also ++ "PYTHONHASHSEED". ++ ++ Changed in version 3.3: Hash randomization is enabled by default. ++ ++object.__bool__(self) ++ ++ Called to implement truth value testing and the built-in operation ++ "bool()"; should return "False" or "True". When this method is not ++ defined, "__len__()" is called, if it is defined, and the object is ++ considered true if its result is nonzero. If a class defines ++ neither "__len__()" nor "__bool__()" (which is true of the "object" ++ class itself), all its instances are considered true. ++ ++ ++Customizing attribute access ++============================ ++ ++The following methods can be defined to customize the meaning of ++attribute access (use of, assignment to, or deletion of "x.name") for ++class instances. ++ ++object.__getattr__(self, name) ++ ++ Called when the default attribute access fails with an ++ "AttributeError" (either "__getattribute__()" raises an ++ "AttributeError" because *name* is not an instance attribute or an ++ attribute in the class tree for "self"; or "__get__()" of a *name* ++ property raises "AttributeError"). This method should either ++ return the (computed) attribute value or raise an "AttributeError" ++ exception. The "object" class itself does not provide this method. ++ ++ Note that if the attribute is found through the normal mechanism, ++ "__getattr__()" is not called. (This is an intentional asymmetry ++ between "__getattr__()" and "__setattr__()".) This is done both for ++ efficiency reasons and because otherwise "__getattr__()" would have ++ no way to access other attributes of the instance. Note that at ++ least for instance variables, you can take total control by not ++ inserting any values in the instance attribute dictionary (but ++ instead inserting them in another object). See the ++ "__getattribute__()" method below for a way to actually get total ++ control over attribute access. ++ ++object.__getattribute__(self, name) ++ ++ Called unconditionally to implement attribute accesses for ++ instances of the class. If the class also defines "__getattr__()", ++ the latter will not be called unless "__getattribute__()" either ++ calls it explicitly or raises an "AttributeError". This method ++ should return the (computed) attribute value or raise an ++ "AttributeError" exception. In order to avoid infinite recursion in ++ this method, its implementation should always call the base class ++ method with the same name to access any attributes it needs, for ++ example, "object.__getattribute__(self, name)". ++ ++ Note: ++ ++ This method may still be bypassed when looking up special methods ++ as the result of implicit invocation via language syntax or ++ built-in functions. See Special method lookup. ++ ++ For certain sensitive attribute accesses, raises an auditing event ++ "object.__getattr__" with arguments "obj" and "name". ++ ++object.__setattr__(self, name, value) ++ ++ Called when an attribute assignment is attempted. This is called ++ instead of the normal mechanism (i.e. store the value in the ++ instance dictionary). *name* is the attribute name, *value* is the ++ value to be assigned to it. ++ ++ If "__setattr__()" wants to assign to an instance attribute, it ++ should call the base class method with the same name, for example, ++ "object.__setattr__(self, name, value)". ++ ++ For certain sensitive attribute assignments, raises an auditing ++ event "object.__setattr__" with arguments "obj", "name", "value". ++ ++object.__delattr__(self, name) ++ ++ Like "__setattr__()" but for attribute deletion instead of ++ assignment. This should only be implemented if "del obj.name" is ++ meaningful for the object. ++ ++ For certain sensitive attribute deletions, raises an auditing event ++ "object.__delattr__" with arguments "obj" and "name". ++ ++object.__dir__(self) ++ ++ Called when "dir()" is called on the object. An iterable must be ++ returned. "dir()" converts the returned iterable to a list and ++ sorts it. ++ ++ ++Customizing module attribute access ++----------------------------------- ++ ++Special names "__getattr__" and "__dir__" can be also used to ++customize access to module attributes. The "__getattr__" function at ++the module level should accept one argument which is the name of an ++attribute and return the computed value or raise an "AttributeError". ++If an attribute is not found on a module object through the normal ++lookup, i.e. "object.__getattribute__()", then "__getattr__" is ++searched in the module "__dict__" before raising an "AttributeError". ++If found, it is called with the attribute name and the result is ++returned. ++ ++The "__dir__" function should accept no arguments, and return an ++iterable of strings that represents the names accessible on module. If ++present, this function overrides the standard "dir()" search on a ++module. ++ ++For a more fine grained customization of the module behavior (setting ++attributes, properties, etc.), one can set the "__class__" attribute ++of a module object to a subclass of "types.ModuleType". For example: ++ ++ import sys ++ from types import ModuleType ++ ++ class VerboseModule(ModuleType): ++ def __repr__(self): ++ return f'Verbose {self.__name__}' ++ ++ def __setattr__(self, attr, value): ++ print(f'Setting {attr}...') ++ super().__setattr__(attr, value) ++ ++ sys.modules[__name__].__class__ = VerboseModule ++ ++Note: ++ ++ Defining module "__getattr__" and setting module "__class__" only ++ affect lookups made using the attribute access syntax – directly ++ accessing the module globals (whether by code within the module, or ++ via a reference to the module’s globals dictionary) is unaffected. ++ ++Changed in version 3.5: "__class__" module attribute is now writable. ++ ++Added in version 3.7: "__getattr__" and "__dir__" module attributes. ++ ++See also: ++ ++ **PEP 562** - Module __getattr__ and __dir__ ++ Describes the "__getattr__" and "__dir__" functions on modules. ++ ++ ++Implementing Descriptors ++------------------------ ++ ++The following methods only apply when an instance of the class ++containing the method (a so-called *descriptor* class) appears in an ++*owner* class (the descriptor must be in either the owner’s class ++dictionary or in the class dictionary for one of its parents). In the ++examples below, “the attribute†refers to the attribute whose name is ++the key of the property in the owner class’ "__dict__". The "object" ++class itself does not implement any of these protocols. ++ ++object.__get__(self, instance, owner=None) ++ ++ Called to get the attribute of the owner class (class attribute ++ access) or of an instance of that class (instance attribute ++ access). The optional *owner* argument is the owner class, while ++ *instance* is the instance that the attribute was accessed through, ++ or "None" when the attribute is accessed through the *owner*. ++ ++ This method should return the computed attribute value or raise an ++ "AttributeError" exception. ++ ++ **PEP 252** specifies that "__get__()" is callable with one or two ++ arguments. Python’s own built-in descriptors support this ++ specification; however, it is likely that some third-party tools ++ have descriptors that require both arguments. Python’s own ++ "__getattribute__()" implementation always passes in both arguments ++ whether they are required or not. ++ ++object.__set__(self, instance, value) ++ ++ Called to set the attribute on an instance *instance* of the owner ++ class to a new value, *value*. ++ ++ Note, adding "__set__()" or "__delete__()" changes the kind of ++ descriptor to a “data descriptorâ€. See Invoking Descriptors for ++ more details. ++ ++object.__delete__(self, instance) ++ ++ Called to delete the attribute on an instance *instance* of the ++ owner class. ++ ++Instances of descriptors may also have the "__objclass__" attribute ++present: ++ ++object.__objclass__ ++ ++ The attribute "__objclass__" is interpreted by the "inspect" module ++ as specifying the class where this object was defined (setting this ++ appropriately can assist in runtime introspection of dynamic class ++ attributes). For callables, it may indicate that an instance of the ++ given type (or a subclass) is expected or required as the first ++ positional argument (for example, CPython sets this attribute for ++ unbound methods that are implemented in C). ++ ++ ++Invoking Descriptors ++-------------------- ++ ++In general, a descriptor is an object attribute with “binding ++behaviorâ€, one whose attribute access has been overridden by methods ++in the descriptor protocol: "__get__()", "__set__()", and ++"__delete__()". If any of those methods are defined for an object, it ++is said to be a descriptor. ++ ++The default behavior for attribute access is to get, set, or delete ++the attribute from an object’s dictionary. For instance, "a.x" has a ++lookup chain starting with "a.__dict__['x']", then ++"type(a).__dict__['x']", and continuing through the base classes of ++"type(a)" excluding metaclasses. ++ ++However, if the looked-up value is an object defining one of the ++descriptor methods, then Python may override the default behavior and ++invoke the descriptor method instead. Where this occurs in the ++precedence chain depends on which descriptor methods were defined and ++how they were called. ++ ++The starting point for descriptor invocation is a binding, "a.x". How ++the arguments are assembled depends on "a": ++ ++Direct Call ++ The simplest and least common call is when user code directly ++ invokes a descriptor method: "x.__get__(a)". ++ ++Instance Binding ++ If binding to an object instance, "a.x" is transformed into the ++ call: "type(a).__dict__['x'].__get__(a, type(a))". ++ ++Class Binding ++ If binding to a class, "A.x" is transformed into the call: ++ "A.__dict__['x'].__get__(None, A)". ++ ++Super Binding ++ A dotted lookup such as "super(A, a).x" searches ++ "a.__class__.__mro__" for a base class "B" following "A" and then ++ returns "B.__dict__['x'].__get__(a, A)". If not a descriptor, "x" ++ is returned unchanged. ++ ++For instance bindings, the precedence of descriptor invocation depends ++on which descriptor methods are defined. A descriptor can define any ++combination of "__get__()", "__set__()" and "__delete__()". If it ++does not define "__get__()", then accessing the attribute will return ++the descriptor object itself unless there is a value in the object’s ++instance dictionary. If the descriptor defines "__set__()" and/or ++"__delete__()", it is a data descriptor; if it defines neither, it is ++a non-data descriptor. Normally, data descriptors define both ++"__get__()" and "__set__()", while non-data descriptors have just the ++"__get__()" method. Data descriptors with "__get__()" and "__set__()" ++(and/or "__delete__()") defined always override a redefinition in an ++instance dictionary. In contrast, non-data descriptors can be ++overridden by instances. ++ ++Python methods (including those decorated with "@staticmethod" and ++"@classmethod") are implemented as non-data descriptors. Accordingly, ++instances can redefine and override methods. This allows individual ++instances to acquire behaviors that differ from other instances of the ++same class. ++ ++The "property()" function is implemented as a data descriptor. ++Accordingly, instances cannot override the behavior of a property. ++ ++ ++__slots__ ++--------- ++ ++*__slots__* allow us to explicitly declare data members (like ++properties) and deny the creation of "__dict__" and *__weakref__* ++(unless explicitly declared in *__slots__* or available in a parent.) ++ ++The space saved over using "__dict__" can be significant. Attribute ++lookup speed can be significantly improved as well. ++ ++object.__slots__ ++ ++ This class variable can be assigned a string, iterable, or sequence ++ of strings with variable names used by instances. *__slots__* ++ reserves space for the declared variables and prevents the ++ automatic creation of "__dict__" and *__weakref__* for each ++ instance. ++ ++Notes on using *__slots__*: ++ ++* When inheriting from a class without *__slots__*, the "__dict__" and ++ *__weakref__* attribute of the instances will always be accessible. ++ ++* Without a "__dict__" variable, instances cannot be assigned new ++ variables not listed in the *__slots__* definition. Attempts to ++ assign to an unlisted variable name raises "AttributeError". If ++ dynamic assignment of new variables is desired, then add ++ "'__dict__'" to the sequence of strings in the *__slots__* ++ declaration. ++ ++* Without a *__weakref__* variable for each instance, classes defining ++ *__slots__* do not support "weak references" to its instances. If ++ weak reference support is needed, then add "'__weakref__'" to the ++ sequence of strings in the *__slots__* declaration. ++ ++* *__slots__* are implemented at the class level by creating ++ descriptors for each variable name. As a result, class attributes ++ cannot be used to set default values for instance variables defined ++ by *__slots__*; otherwise, the class attribute would overwrite the ++ descriptor assignment. ++ ++* The action of a *__slots__* declaration is not limited to the class ++ where it is defined. *__slots__* declared in parents are available ++ in child classes. However, instances of a child subclass will get a ++ "__dict__" and *__weakref__* unless the subclass also defines ++ *__slots__* (which should only contain names of any *additional* ++ slots). ++ ++* If a class defines a slot also defined in a base class, the instance ++ variable defined by the base class slot is inaccessible (except by ++ retrieving its descriptor directly from the base class). This ++ renders the meaning of the program undefined. In the future, a ++ check may be added to prevent this. ++ ++* "TypeError" will be raised if nonempty *__slots__* are defined for a ++ class derived from a ""variable-length" built-in type" such as ++ "int", "bytes", and "tuple". ++ ++* Any non-string *iterable* may be assigned to *__slots__*. ++ ++* If a "dictionary" is used to assign *__slots__*, the dictionary keys ++ will be used as the slot names. The values of the dictionary can be ++ used to provide per-attribute docstrings that will be recognised by ++ "inspect.getdoc()" and displayed in the output of "help()". ++ ++* "__class__" assignment works only if both classes have the same ++ *__slots__*. ++ ++* Multiple inheritance with multiple slotted parent classes can be ++ used, but only one parent is allowed to have attributes created by ++ slots (the other bases must have empty slot layouts) - violations ++ raise "TypeError". ++ ++* If an *iterator* is used for *__slots__* then a *descriptor* is ++ created for each of the iterator’s values. However, the *__slots__* ++ attribute will be an empty iterator. ++ ++ ++Customizing class creation ++========================== ++ ++Whenever a class inherits from another class, "__init_subclass__()" is ++called on the parent class. This way, it is possible to write classes ++which change the behavior of subclasses. This is closely related to ++class decorators, but where class decorators only affect the specific ++class they’re applied to, "__init_subclass__" solely applies to future ++subclasses of the class defining the method. ++ ++classmethod object.__init_subclass__(cls) ++ ++ This method is called whenever the containing class is subclassed. ++ *cls* is then the new subclass. If defined as a normal instance ++ method, this method is implicitly converted to a class method. ++ ++ Keyword arguments which are given to a new class are passed to the ++ parent class’s "__init_subclass__". For compatibility with other ++ classes using "__init_subclass__", one should take out the needed ++ keyword arguments and pass the others over to the base class, as ++ in: ++ ++ class Philosopher: ++ def __init_subclass__(cls, /, default_name, **kwargs): ++ super().__init_subclass__(**kwargs) ++ cls.default_name = default_name ++ ++ class AustralianPhilosopher(Philosopher, default_name="Bruce"): ++ pass ++ ++ The default implementation "object.__init_subclass__" does nothing, ++ but raises an error if it is called with any arguments. ++ ++ Note: ++ ++ The metaclass hint "metaclass" is consumed by the rest of the ++ type machinery, and is never passed to "__init_subclass__" ++ implementations. The actual metaclass (rather than the explicit ++ hint) can be accessed as "type(cls)". ++ ++ Added in version 3.6. ++ ++When a class is created, "type.__new__()" scans the class variables ++and makes callbacks to those with a "__set_name__()" hook. ++ ++object.__set_name__(self, owner, name) ++ ++ Automatically called at the time the owning class *owner* is ++ created. The object has been assigned to *name* in that class: ++ ++ class A: ++ x = C() # Automatically calls: x.__set_name__(A, 'x') ++ ++ If the class variable is assigned after the class is created, ++ "__set_name__()" will not be called automatically. If needed, ++ "__set_name__()" can be called directly: ++ ++ class A: ++ pass ++ ++ c = C() ++ A.x = c # The hook is not called ++ c.__set_name__(A, 'x') # Manually invoke the hook ++ ++ See Creating the class object for more details. ++ ++ Added in version 3.6. ++ ++ ++Metaclasses ++----------- ++ ++By default, classes are constructed using "type()". The class body is ++executed in a new namespace and the class name is bound locally to the ++result of "type(name, bases, namespace)". ++ ++The class creation process can be customized by passing the ++"metaclass" keyword argument in the class definition line, or by ++inheriting from an existing class that included such an argument. In ++the following example, both "MyClass" and "MySubclass" are instances ++of "Meta": ++ ++ class Meta(type): ++ pass ++ ++ class MyClass(metaclass=Meta): ++ pass ++ ++ class MySubclass(MyClass): ++ pass ++ ++Any other keyword arguments that are specified in the class definition ++are passed through to all metaclass operations described below. ++ ++When a class definition is executed, the following steps occur: ++ ++* MRO entries are resolved; ++ ++* the appropriate metaclass is determined; ++ ++* the class namespace is prepared; ++ ++* the class body is executed; ++ ++* the class object is created. ++ ++ ++Resolving MRO entries ++--------------------- ++ ++object.__mro_entries__(self, bases) ++ ++ If a base that appears in a class definition is not an instance of ++ "type", then an "__mro_entries__()" method is searched on the base. ++ If an "__mro_entries__()" method is found, the base is substituted ++ with the result of a call to "__mro_entries__()" when creating the ++ class. The method is called with the original bases tuple passed to ++ the *bases* parameter, and must return a tuple of classes that will ++ be used instead of the base. The returned tuple may be empty: in ++ these cases, the original base is ignored. ++ ++See also: ++ ++ "types.resolve_bases()" ++ Dynamically resolve bases that are not instances of "type". ++ ++ "types.get_original_bases()" ++ Retrieve a class’s “original bases†prior to modifications by ++ "__mro_entries__()". ++ ++ **PEP 560** ++ Core support for typing module and generic types. ++ ++ ++Determining the appropriate metaclass ++------------------------------------- ++ ++The appropriate metaclass for a class definition is determined as ++follows: ++ ++* if no bases and no explicit metaclass are given, then "type()" is ++ used; ++ ++* if an explicit metaclass is given and it is *not* an instance of ++ "type()", then it is used directly as the metaclass; ++ ++* if an instance of "type()" is given as the explicit metaclass, or ++ bases are defined, then the most derived metaclass is used. ++ ++The most derived metaclass is selected from the explicitly specified ++metaclass (if any) and the metaclasses (i.e. "type(cls)") of all ++specified base classes. The most derived metaclass is one which is a ++subtype of *all* of these candidate metaclasses. If none of the ++candidate metaclasses meets that criterion, then the class definition ++will fail with "TypeError". ++ ++ ++Preparing the class namespace ++----------------------------- ++ ++Once the appropriate metaclass has been identified, then the class ++namespace is prepared. If the metaclass has a "__prepare__" attribute, ++it is called as "namespace = metaclass.__prepare__(name, bases, ++**kwds)" (where the additional keyword arguments, if any, come from ++the class definition). The "__prepare__" method should be implemented ++as a "classmethod". The namespace returned by "__prepare__" is passed ++in to "__new__", but when the final class object is created the ++namespace is copied into a new "dict". ++ ++If the metaclass has no "__prepare__" attribute, then the class ++namespace is initialised as an empty ordered mapping. ++ ++See also: ++ ++ **PEP 3115** - Metaclasses in Python 3000 ++ Introduced the "__prepare__" namespace hook ++ ++ ++Executing the class body ++------------------------ ++ ++The class body is executed (approximately) as "exec(body, globals(), ++namespace)". The key difference from a normal call to "exec()" is that ++lexical scoping allows the class body (including any methods) to ++reference names from the current and outer scopes when the class ++definition occurs inside a function. ++ ++However, even when the class definition occurs inside the function, ++methods defined inside the class still cannot see names defined at the ++class scope. Class variables must be accessed through the first ++parameter of instance or class methods, or through the implicit ++lexically scoped "__class__" reference described in the next section. ++ ++ ++Creating the class object ++------------------------- ++ ++Once the class namespace has been populated by executing the class ++body, the class object is created by calling "metaclass(name, bases, ++namespace, **kwds)" (the additional keywords passed here are the same ++as those passed to "__prepare__"). ++ ++This class object is the one that will be referenced by the zero- ++argument form of "super()". "__class__" is an implicit closure ++reference created by the compiler if any methods in a class body refer ++to either "__class__" or "super". This allows the zero argument form ++of "super()" to correctly identify the class being defined based on ++lexical scoping, while the class or instance that was used to make the ++current call is identified based on the first argument passed to the ++method. ++ ++**CPython implementation detail:** In CPython 3.6 and later, the ++"__class__" cell is passed to the metaclass as a "__classcell__" entry ++in the class namespace. If present, this must be propagated up to the ++"type.__new__" call in order for the class to be initialised ++correctly. Failing to do so will result in a "RuntimeError" in Python ++3.8. ++ ++When using the default metaclass "type", or any metaclass that ++ultimately calls "type.__new__", the following additional ++customization steps are invoked after creating the class object: ++ ++1. The "type.__new__" method collects all of the attributes in the ++ class namespace that define a "__set_name__()" method; ++ ++2. Those "__set_name__" methods are called with the class being ++ defined and the assigned name of that particular attribute; ++ ++3. The "__init_subclass__()" hook is called on the immediate parent of ++ the new class in its method resolution order. ++ ++After the class object is created, it is passed to the class ++decorators included in the class definition (if any) and the resulting ++object is bound in the local namespace as the defined class. ++ ++When a new class is created by "type.__new__", the object provided as ++the namespace parameter is copied to a new ordered mapping and the ++original object is discarded. The new copy is wrapped in a read-only ++proxy, which becomes the "__dict__" attribute of the class object. ++ ++See also: ++ ++ **PEP 3135** - New super ++ Describes the implicit "__class__" closure reference ++ ++ ++Uses for metaclasses ++-------------------- ++ ++The potential uses for metaclasses are boundless. Some ideas that have ++been explored include enum, logging, interface checking, automatic ++delegation, automatic property creation, proxies, frameworks, and ++automatic resource locking/synchronization. ++ ++ ++Customizing instance and subclass checks ++======================================== ++ ++The following methods are used to override the default behavior of the ++"isinstance()" and "issubclass()" built-in functions. ++ ++In particular, the metaclass "abc.ABCMeta" implements these methods in ++order to allow the addition of Abstract Base Classes (ABCs) as ++“virtual base classes†to any class or type (including built-in ++types), including other ABCs. ++ ++type.__instancecheck__(self, instance) ++ ++ Return true if *instance* should be considered a (direct or ++ indirect) instance of *class*. If defined, called to implement ++ "isinstance(instance, class)". ++ ++type.__subclasscheck__(self, subclass) ++ ++ Return true if *subclass* should be considered a (direct or ++ indirect) subclass of *class*. If defined, called to implement ++ "issubclass(subclass, class)". ++ ++Note that these methods are looked up on the type (metaclass) of a ++class. They cannot be defined as class methods in the actual class. ++This is consistent with the lookup of special methods that are called ++on instances, only in this case the instance is itself a class. ++ ++See also: ++ ++ **PEP 3119** - Introducing Abstract Base Classes ++ Includes the specification for customizing "isinstance()" and ++ "issubclass()" behavior through "__instancecheck__()" and ++ "__subclasscheck__()", with motivation for this functionality in ++ the context of adding Abstract Base Classes (see the "abc" ++ module) to the language. ++ ++ ++Emulating generic types ++======================= ++ ++When using *type annotations*, it is often useful to *parameterize* a ++*generic type* using Python’s square-brackets notation. For example, ++the annotation "list[int]" might be used to signify a "list" in which ++all the elements are of type "int". ++ ++See also: ++ ++ **PEP 484** - Type Hints ++ Introducing Python’s framework for type annotations ++ ++ Generic Alias Types ++ Documentation for objects representing parameterized generic ++ classes ++ ++ Generics, user-defined generics and "typing.Generic" ++ Documentation on how to implement generic classes that can be ++ parameterized at runtime and understood by static type-checkers. ++ ++A class can *generally* only be parameterized if it defines the ++special class method "__class_getitem__()". ++ ++classmethod object.__class_getitem__(cls, key) ++ ++ Return an object representing the specialization of a generic class ++ by type arguments found in *key*. ++ ++ When defined on a class, "__class_getitem__()" is automatically a ++ class method. As such, there is no need for it to be decorated with ++ "@classmethod" when it is defined. ++ ++ ++The purpose of *__class_getitem__* ++---------------------------------- ++ ++The purpose of "__class_getitem__()" is to allow runtime ++parameterization of standard-library generic classes in order to more ++easily apply *type hints* to these classes. ++ ++To implement custom generic classes that can be parameterized at ++runtime and understood by static type-checkers, users should either ++inherit from a standard library class that already implements ++"__class_getitem__()", or inherit from "typing.Generic", which has its ++own implementation of "__class_getitem__()". ++ ++Custom implementations of "__class_getitem__()" on classes defined ++outside of the standard library may not be understood by third-party ++type-checkers such as mypy. Using "__class_getitem__()" on any class ++for purposes other than type hinting is discouraged. ++ ++ ++*__class_getitem__* versus *__getitem__* ++---------------------------------------- ++ ++Usually, the subscription of an object using square brackets will call ++the "__getitem__()" instance method defined on the object’s class. ++However, if the object being subscribed is itself a class, the class ++method "__class_getitem__()" may be called instead. ++"__class_getitem__()" should return a GenericAlias object if it is ++properly defined. ++ ++Presented with the *expression* "obj[x]", the Python interpreter ++follows something like the following process to decide whether ++"__getitem__()" or "__class_getitem__()" should be called: ++ ++ from inspect import isclass ++ ++ def subscribe(obj, x): ++ """Return the result of the expression 'obj[x]'""" ++ ++ class_of_obj = type(obj) ++ ++ # If the class of obj defines __getitem__, ++ # call class_of_obj.__getitem__(obj, x) ++ if hasattr(class_of_obj, '__getitem__'): ++ return class_of_obj.__getitem__(obj, x) ++ ++ # Else, if obj is a class and defines __class_getitem__, ++ # call obj.__class_getitem__(x) ++ elif isclass(obj) and hasattr(obj, '__class_getitem__'): ++ return obj.__class_getitem__(x) ++ ++ # Else, raise an exception ++ else: ++ raise TypeError( ++ f"'{class_of_obj.__name__}' object is not subscriptable" ++ ) ++ ++In Python, all classes are themselves instances of other classes. The ++class of a class is known as that class’s *metaclass*, and most ++classes have the "type" class as their metaclass. "type" does not ++define "__getitem__()", meaning that expressions such as "list[int]", ++"dict[str, float]" and "tuple[str, bytes]" all result in ++"__class_getitem__()" being called: ++ ++ >>> # list has class "type" as its metaclass, like most classes: ++ >>> type(list) ++ ++ >>> type(dict) == type(list) == type(tuple) == type(str) == type(bytes) ++ True ++ >>> # "list[int]" calls "list.__class_getitem__(int)" ++ >>> list[int] ++ list[int] ++ >>> # list.__class_getitem__ returns a GenericAlias object: ++ >>> type(list[int]) ++ ++ ++However, if a class has a custom metaclass that defines ++"__getitem__()", subscribing the class may result in different ++behaviour. An example of this can be found in the "enum" module: ++ ++ >>> from enum import Enum ++ >>> class Menu(Enum): ++ ... """A breakfast menu""" ++ ... SPAM = 'spam' ++ ... BACON = 'bacon' ++ ... ++ >>> # Enum classes have a custom metaclass: ++ >>> type(Menu) ++ ++ >>> # EnumMeta defines __getitem__, ++ >>> # so __class_getitem__ is not called, ++ >>> # and the result is not a GenericAlias object: ++ >>> Menu['SPAM'] ++ ++ >>> type(Menu['SPAM']) ++ ++ ++See also: ++ ++ **PEP 560** - Core Support for typing module and generic types ++ Introducing "__class_getitem__()", and outlining when a ++ subscription results in "__class_getitem__()" being called ++ instead of "__getitem__()" ++ ++ ++Emulating callable objects ++========================== ++ ++object.__call__(self[, args...]) ++ ++ Called when the instance is “called†as a function; if this method ++ is defined, "x(arg1, arg2, ...)" roughly translates to ++ "type(x).__call__(x, arg1, ...)". The "object" class itself does ++ not provide this method. ++ ++ ++Emulating container types ++========================= ++ ++The following methods can be defined to implement container objects. ++None of them are provided by the "object" class itself. Containers ++usually are *sequences* (such as "lists" or "tuples") or *mappings* ++(like *dictionaries*), but can represent other containers as well. ++The first set of methods is used either to emulate a sequence or to ++emulate a mapping; the difference is that for a sequence, the ++allowable keys should be the integers *k* for which "0 <= k < N" where ++*N* is the length of the sequence, or "slice" objects, which define a ++range of items. It is also recommended that mappings provide the ++methods "keys()", "values()", "items()", "get()", "clear()", ++"setdefault()", "pop()", "popitem()", "copy()", and "update()" ++behaving similar to those for Python’s standard "dictionary" objects. ++The "collections.abc" module provides a "MutableMapping" *abstract ++base class* to help create those methods from a base set of ++"__getitem__()", "__setitem__()", "__delitem__()", and "keys()". ++Mutable sequences should provide methods "append()", "count()", ++"index()", "extend()", "insert()", "pop()", "remove()", "reverse()" ++and "sort()", like Python standard "list" objects. Finally, sequence ++types should implement addition (meaning concatenation) and ++multiplication (meaning repetition) by defining the methods ++"__add__()", "__radd__()", "__iadd__()", "__mul__()", "__rmul__()" and ++"__imul__()" described below; they should not define other numerical ++operators. It is recommended that both mappings and sequences ++implement the "__contains__()" method to allow efficient use of the ++"in" operator; for mappings, "in" should search the mapping’s keys; ++for sequences, it should search through the values. It is further ++recommended that both mappings and sequences implement the ++"__iter__()" method to allow efficient iteration through the ++container; for mappings, "__iter__()" should iterate through the ++object’s keys; for sequences, it should iterate through the values. ++ ++object.__len__(self) ++ ++ Called to implement the built-in function "len()". Should return ++ the length of the object, an integer ">=" 0. Also, an object that ++ doesn’t define a "__bool__()" method and whose "__len__()" method ++ returns zero is considered to be false in a Boolean context. ++ ++ **CPython implementation detail:** In CPython, the length is ++ required to be at most "sys.maxsize". If the length is larger than ++ "sys.maxsize" some features (such as "len()") may raise ++ "OverflowError". To prevent raising "OverflowError" by truth value ++ testing, an object must define a "__bool__()" method. ++ ++object.__length_hint__(self) ++ ++ Called to implement "operator.length_hint()". Should return an ++ estimated length for the object (which may be greater or less than ++ the actual length). The length must be an integer ">=" 0. The ++ return value may also be "NotImplemented", which is treated the ++ same as if the "__length_hint__" method didn’t exist at all. This ++ method is purely an optimization and is never required for ++ correctness. ++ ++ Added in version 3.4. ++ ++Note: ++ ++ Slicing is done exclusively with the following three methods. A ++ call like ++ ++ a[1:2] = b ++ ++ is translated to ++ ++ a[slice(1, 2, None)] = b ++ ++ and so forth. Missing slice items are always filled in with "None". ++ ++object.__getitem__(self, key) ++ ++ Called to implement evaluation of "self[key]". For *sequence* ++ types, the accepted keys should be integers. Optionally, they may ++ support "slice" objects as well. Negative index support is also ++ optional. If *key* is of an inappropriate type, "TypeError" may be ++ raised; if *key* is a value outside the set of indexes for the ++ sequence (after any special interpretation of negative values), ++ "IndexError" should be raised. For *mapping* types, if *key* is ++ missing (not in the container), "KeyError" should be raised. ++ ++ Note: ++ ++ "for" loops expect that an "IndexError" will be raised for ++ illegal indexes to allow proper detection of the end of the ++ sequence. ++ ++ Note: ++ ++ When subscripting a *class*, the special class method ++ "__class_getitem__()" may be called instead of "__getitem__()". ++ See __class_getitem__ versus __getitem__ for more details. ++ ++object.__setitem__(self, key, value) ++ ++ Called to implement assignment to "self[key]". Same note as for ++ "__getitem__()". This should only be implemented for mappings if ++ the objects support changes to the values for keys, or if new keys ++ can be added, or for sequences if elements can be replaced. The ++ same exceptions should be raised for improper *key* values as for ++ the "__getitem__()" method. ++ ++object.__delitem__(self, key) ++ ++ Called to implement deletion of "self[key]". Same note as for ++ "__getitem__()". This should only be implemented for mappings if ++ the objects support removal of keys, or for sequences if elements ++ can be removed from the sequence. The same exceptions should be ++ raised for improper *key* values as for the "__getitem__()" method. ++ ++object.__missing__(self, key) ++ ++ Called by "dict"."__getitem__()" to implement "self[key]" for dict ++ subclasses when key is not in the dictionary. ++ ++object.__iter__(self) ++ ++ This method is called when an *iterator* is required for a ++ container. This method should return a new iterator object that can ++ iterate over all the objects in the container. For mappings, it ++ should iterate over the keys of the container. ++ ++object.__reversed__(self) ++ ++ Called (if present) by the "reversed()" built-in to implement ++ reverse iteration. It should return a new iterator object that ++ iterates over all the objects in the container in reverse order. ++ ++ If the "__reversed__()" method is not provided, the "reversed()" ++ built-in will fall back to using the sequence protocol ("__len__()" ++ and "__getitem__()"). Objects that support the sequence protocol ++ should only provide "__reversed__()" if they can provide an ++ implementation that is more efficient than the one provided by ++ "reversed()". ++ ++The membership test operators ("in" and "not in") are normally ++implemented as an iteration through a container. However, container ++objects can supply the following special method with a more efficient ++implementation, which also does not require the object be iterable. ++ ++object.__contains__(self, item) ++ ++ Called to implement membership test operators. Should return true ++ if *item* is in *self*, false otherwise. For mapping objects, this ++ should consider the keys of the mapping rather than the values or ++ the key-item pairs. ++ ++ For objects that don’t define "__contains__()", the membership test ++ first tries iteration via "__iter__()", then the old sequence ++ iteration protocol via "__getitem__()", see this section in the ++ language reference. ++ ++ ++Emulating numeric types ++======================= ++ ++The following methods can be defined to emulate numeric objects. ++Methods corresponding to operations that are not supported by the ++particular kind of number implemented (e.g., bitwise operations for ++non-integral numbers) should be left undefined. ++ ++object.__add__(self, other) ++object.__sub__(self, other) ++object.__mul__(self, other) ++object.__matmul__(self, other) ++object.__truediv__(self, other) ++object.__floordiv__(self, other) ++object.__mod__(self, other) ++object.__divmod__(self, other) ++object.__pow__(self, other[, modulo]) ++object.__lshift__(self, other) ++object.__rshift__(self, other) ++object.__and__(self, other) ++object.__xor__(self, other) ++object.__or__(self, other) ++ ++ These methods are called to implement the binary arithmetic ++ operations ("+", "-", "*", "@", "/", "//", "%", "divmod()", ++ "pow()", "**", "<<", ">>", "&", "^", "|"). For instance, to ++ evaluate the expression "x + y", where *x* is an instance of a ++ class that has an "__add__()" method, "type(x).__add__(x, y)" is ++ called. The "__divmod__()" method should be the equivalent to ++ using "__floordiv__()" and "__mod__()"; it should not be related to ++ "__truediv__()". Note that "__pow__()" should be defined to accept ++ an optional third argument if the ternary version of the built-in ++ "pow()" function is to be supported. ++ ++ If one of those methods does not support the operation with the ++ supplied arguments, it should return "NotImplemented". ++ ++object.__radd__(self, other) ++object.__rsub__(self, other) ++object.__rmul__(self, other) ++object.__rmatmul__(self, other) ++object.__rtruediv__(self, other) ++object.__rfloordiv__(self, other) ++object.__rmod__(self, other) ++object.__rdivmod__(self, other) ++object.__rpow__(self, other[, modulo]) ++object.__rlshift__(self, other) ++object.__rrshift__(self, other) ++object.__rand__(self, other) ++object.__rxor__(self, other) ++object.__ror__(self, other) ++ ++ These methods are called to implement the binary arithmetic ++ operations ("+", "-", "*", "@", "/", "//", "%", "divmod()", ++ "pow()", "**", "<<", ">>", "&", "^", "|") with reflected (swapped) ++ operands. These functions are only called if the operands are of ++ different types, when the left operand does not support the ++ corresponding operation [3], or the right operand’s class is ++ derived from the left operand’s class. [4] For instance, to ++ evaluate the expression "x - y", where *y* is an instance of a ++ class that has an "__rsub__()" method, "type(y).__rsub__(y, x)" is ++ called if "type(x).__sub__(x, y)" returns "NotImplemented" or ++ "type(y)" is a subclass of "type(x)". [5] ++ ++ Note that ternary "pow()" will not try calling "__rpow__()" (the ++ coercion rules would become too complicated). ++ ++ Note: ++ ++ If the right operand’s type is a subclass of the left operand’s ++ type and that subclass provides a different implementation of the ++ reflected method for the operation, this method will be called ++ before the left operand’s non-reflected method. This behavior ++ allows subclasses to override their ancestors’ operations. ++ ++object.__iadd__(self, other) ++object.__isub__(self, other) ++object.__imul__(self, other) ++object.__imatmul__(self, other) ++object.__itruediv__(self, other) ++object.__ifloordiv__(self, other) ++object.__imod__(self, other) ++object.__ipow__(self, other[, modulo]) ++object.__ilshift__(self, other) ++object.__irshift__(self, other) ++object.__iand__(self, other) ++object.__ixor__(self, other) ++object.__ior__(self, other) ++ ++ These methods are called to implement the augmented arithmetic ++ assignments ("+=", "-=", "*=", "@=", "/=", "//=", "%=", "**=", ++ "<<=", ">>=", "&=", "^=", "|="). These methods should attempt to ++ do the operation in-place (modifying *self*) and return the result ++ (which could be, but does not have to be, *self*). If a specific ++ method is not defined, or if that method returns "NotImplemented", ++ the augmented assignment falls back to the normal methods. For ++ instance, if *x* is an instance of a class with an "__iadd__()" ++ method, "x += y" is equivalent to "x = x.__iadd__(y)" . If ++ "__iadd__()" does not exist, or if "x.__iadd__(y)" returns ++ "NotImplemented", "x.__add__(y)" and "y.__radd__(x)" are ++ considered, as with the evaluation of "x + y". In certain ++ situations, augmented assignment can result in unexpected errors ++ (see Why does a_tuple[i] += [‘item’] raise an exception when the ++ addition works?), but this behavior is in fact part of the data ++ model. ++ ++object.__neg__(self) ++object.__pos__(self) ++object.__abs__(self) ++object.__invert__(self) ++ ++ Called to implement the unary arithmetic operations ("-", "+", ++ "abs()" and "~"). ++ ++object.__complex__(self) ++object.__int__(self) ++object.__float__(self) ++ ++ Called to implement the built-in functions "complex()", "int()" and ++ "float()". Should return a value of the appropriate type. ++ ++object.__index__(self) ++ ++ Called to implement "operator.index()", and whenever Python needs ++ to losslessly convert the numeric object to an integer object (such ++ as in slicing, or in the built-in "bin()", "hex()" and "oct()" ++ functions). Presence of this method indicates that the numeric ++ object is an integer type. Must return an integer. ++ ++ If "__int__()", "__float__()" and "__complex__()" are not defined ++ then corresponding built-in functions "int()", "float()" and ++ "complex()" fall back to "__index__()". ++ ++object.__round__(self[, ndigits]) ++object.__trunc__(self) ++object.__floor__(self) ++object.__ceil__(self) ++ ++ Called to implement the built-in function "round()" and "math" ++ functions "trunc()", "floor()" and "ceil()". Unless *ndigits* is ++ passed to "__round__()" all these methods should return the value ++ of the object truncated to an "Integral" (typically an "int"). ++ ++ Changed in version 3.14: "int()" no longer delegates to the ++ "__trunc__()" method. ++ ++ ++With Statement Context Managers ++=============================== ++ ++A *context manager* is an object that defines the runtime context to ++be established when executing a "with" statement. The context manager ++handles the entry into, and the exit from, the desired runtime context ++for the execution of the block of code. Context managers are normally ++invoked using the "with" statement (described in section The with ++statement), but can also be used by directly invoking their methods. ++ ++Typical uses of context managers include saving and restoring various ++kinds of global state, locking and unlocking resources, closing opened ++files, etc. ++ ++For more information on context managers, see Context Manager Types. ++The "object" class itself does not provide the context manager ++methods. ++ ++object.__enter__(self) ++ ++ Enter the runtime context related to this object. The "with" ++ statement will bind this method’s return value to the target(s) ++ specified in the "as" clause of the statement, if any. ++ ++object.__exit__(self, exc_type, exc_value, traceback) ++ ++ Exit the runtime context related to this object. The parameters ++ describe the exception that caused the context to be exited. If the ++ context was exited without an exception, all three arguments will ++ be "None". ++ ++ If an exception is supplied, and the method wishes to suppress the ++ exception (i.e., prevent it from being propagated), it should ++ return a true value. Otherwise, the exception will be processed ++ normally upon exit from this method. ++ ++ Note that "__exit__()" methods should not reraise the passed-in ++ exception; this is the caller’s responsibility. ++ ++See also: ++ ++ **PEP 343** - The “with†statement ++ The specification, background, and examples for the Python "with" ++ statement. ++ ++ ++Customizing positional arguments in class pattern matching ++========================================================== ++ ++When using a class name in a pattern, positional arguments in the ++pattern are not allowed by default, i.e. "case MyClass(x, y)" is ++typically invalid without special support in "MyClass". To be able to ++use that kind of pattern, the class needs to define a *__match_args__* ++attribute. ++ ++object.__match_args__ ++ ++ This class variable can be assigned a tuple of strings. When this ++ class is used in a class pattern with positional arguments, each ++ positional argument will be converted into a keyword argument, ++ using the corresponding value in *__match_args__* as the keyword. ++ The absence of this attribute is equivalent to setting it to "()". ++ ++For example, if "MyClass.__match_args__" is "("left", "center", ++"right")" that means that "case MyClass(x, y)" is equivalent to "case ++MyClass(left=x, center=y)". Note that the number of arguments in the ++pattern must be smaller than or equal to the number of elements in ++*__match_args__*; if it is larger, the pattern match attempt will ++raise a "TypeError". ++ ++Added in version 3.10. ++ ++See also: ++ ++ **PEP 634** - Structural Pattern Matching ++ The specification for the Python "match" statement. ++ ++ ++Emulating buffer types ++====================== ++ ++The buffer protocol provides a way for Python objects to expose ++efficient access to a low-level memory array. This protocol is ++implemented by builtin types such as "bytes" and "memoryview", and ++third-party libraries may define additional buffer types. ++ ++While buffer types are usually implemented in C, it is also possible ++to implement the protocol in Python. ++ ++object.__buffer__(self, flags) ++ ++ Called when a buffer is requested from *self* (for example, by the ++ "memoryview" constructor). The *flags* argument is an integer ++ representing the kind of buffer requested, affecting for example ++ whether the returned buffer is read-only or writable. ++ "inspect.BufferFlags" provides a convenient way to interpret the ++ flags. The method must return a "memoryview" object. ++ ++object.__release_buffer__(self, buffer) ++ ++ Called when a buffer is no longer needed. The *buffer* argument is ++ a "memoryview" object that was previously returned by ++ "__buffer__()". The method must release any resources associated ++ with the buffer. This method should return "None". Buffer objects ++ that do not need to perform any cleanup are not required to ++ implement this method. ++ ++Added in version 3.12. ++ ++See also: ++ ++ **PEP 688** - Making the buffer protocol accessible in Python ++ Introduces the Python "__buffer__" and "__release_buffer__" ++ methods. ++ ++ "collections.abc.Buffer" ++ ABC for buffer types. ++ ++ ++Annotations ++=========== ++ ++Functions, classes, and modules may contain *annotations*, which are a ++way to associate information (usually *type hints*) with a symbol. ++ ++object.__annotations__ ++ ++ This attribute contains the annotations for an object. It is lazily ++ evaluated, so accessing the attribute may execute arbitrary code ++ and raise exceptions. If evaluation is successful, the attribute is ++ set to a dictionary mapping from variable names to annotations. ++ ++ Changed in version 3.14: Annotations are now lazily evaluated. ++ ++object.__annotate__(format) ++ ++ An *annotate function*. Returns a new dictionary object mapping ++ attribute/parameter names to their annotation values. ++ ++ Takes a format parameter specifying the format in which annotations ++ values should be provided. It must be a member of the ++ "annotationlib.Format" enum, or an integer with a value ++ corresponding to a member of the enum. ++ ++ If an annotate function doesn’t support the requested format, it ++ must raise "NotImplementedError". Annotate functions must always ++ support "VALUE" format; they must not raise "NotImplementedError()" ++ when called with this format. ++ ++ When called with "VALUE" format, an annotate function may raise ++ "NameError"; it must not raise "NameError" when called requesting ++ any other format. ++ ++ If an object does not have any annotations, "__annotate__" should ++ preferably be set to "None" (it can’t be deleted), rather than set ++ to a function that returns an empty dict. ++ ++ Added in version 3.14. ++ ++See also: ++ ++ **PEP 649** — Deferred evaluation of annotation using descriptors ++ Introduces lazy evaluation of annotations and the "__annotate__" ++ function. ++ ++ ++Special method lookup ++===================== ++ ++For custom classes, implicit invocations of special methods are only ++guaranteed to work correctly if defined on an object’s type, not in ++the object’s instance dictionary. That behaviour is the reason why ++the following code raises an exception: ++ ++ >>> class C: ++ ... pass ++ ... ++ >>> c = C() ++ >>> c.__len__ = lambda: 5 ++ >>> len(c) ++ Traceback (most recent call last): ++ File "", line 1, in ++ TypeError: object of type 'C' has no len() ++ ++The rationale behind this behaviour lies with a number of special ++methods such as "__hash__()" and "__repr__()" that are implemented by ++all objects, including type objects. If the implicit lookup of these ++methods used the conventional lookup process, they would fail when ++invoked on the type object itself: ++ ++ >>> 1 .__hash__() == hash(1) ++ True ++ >>> int.__hash__() == hash(int) ++ Traceback (most recent call last): ++ File "", line 1, in ++ TypeError: descriptor '__hash__' of 'int' object needs an argument ++ ++Incorrectly attempting to invoke an unbound method of a class in this ++way is sometimes referred to as ‘metaclass confusion’, and is avoided ++by bypassing the instance when looking up special methods: ++ ++ >>> type(1).__hash__(1) == hash(1) ++ True ++ >>> type(int).__hash__(int) == hash(int) ++ True ++ ++In addition to bypassing any instance attributes in the interest of ++correctness, implicit special method lookup generally also bypasses ++the "__getattribute__()" method even of the object’s metaclass: ++ ++ >>> class Meta(type): ++ ... def __getattribute__(*args): ++ ... print("Metaclass getattribute invoked") ++ ... return type.__getattribute__(*args) ++ ... ++ >>> class C(object, metaclass=Meta): ++ ... def __len__(self): ++ ... return 10 ++ ... def __getattribute__(*args): ++ ... print("Class getattribute invoked") ++ ... return object.__getattribute__(*args) ++ ... ++ >>> c = C() ++ >>> c.__len__() # Explicit lookup via instance ++ Class getattribute invoked ++ 10 ++ >>> type(c).__len__(c) # Explicit lookup via type ++ Metaclass getattribute invoked ++ 10 ++ >>> len(c) # Implicit lookup ++ 10 ++ ++Bypassing the "__getattribute__()" machinery in this fashion provides ++significant scope for speed optimisations within the interpreter, at ++the cost of some flexibility in the handling of special methods (the ++special method *must* be set on the class object itself in order to be ++consistently invoked by the interpreter). ++''', ++ 'string-methods': r'''String Methods ++************** ++ ++Strings implement all of the common sequence operations, along with ++the additional methods described below. ++ ++Strings also support two styles of string formatting, one providing a ++large degree of flexibility and customization (see "str.format()", ++Format String Syntax and Custom String Formatting) and the other based ++on C "printf" style formatting that handles a narrower range of types ++and is slightly harder to use correctly, but is often faster for the ++cases it can handle (printf-style String Formatting). ++ ++The Text Processing Services section of the standard library covers a ++number of other modules that provide various text related utilities ++(including regular expression support in the "re" module). ++ ++str.capitalize() ++ ++ Return a copy of the string with its first character capitalized ++ and the rest lowercased. ++ ++ Changed in version 3.8: The first character is now put into ++ titlecase rather than uppercase. This means that characters like ++ digraphs will only have their first letter capitalized, instead of ++ the full character. ++ ++str.casefold() ++ ++ Return a casefolded copy of the string. Casefolded strings may be ++ used for caseless matching. ++ ++ Casefolding is similar to lowercasing but more aggressive because ++ it is intended to remove all case distinctions in a string. For ++ example, the German lowercase letter "'ß'" is equivalent to ""ss"". ++ Since it is already lowercase, "lower()" would do nothing to "'ß'"; ++ "casefold()" converts it to ""ss"". ++ ++ The casefolding algorithm is described in section 3.13 ‘Default ++ Case Folding’ of the Unicode Standard. ++ ++ Added in version 3.3. ++ ++str.center(width[, fillchar]) ++ ++ Return centered in a string of length *width*. Padding is done ++ using the specified *fillchar* (default is an ASCII space). The ++ original string is returned if *width* is less than or equal to ++ "len(s)". ++ ++str.count(sub[, start[, end]]) ++ ++ Return the number of non-overlapping occurrences of substring *sub* ++ in the range [*start*, *end*]. Optional arguments *start* and ++ *end* are interpreted as in slice notation. ++ ++ If *sub* is empty, returns the number of empty strings between ++ characters which is the length of the string plus one. ++ ++str.encode(encoding='utf-8', errors='strict') ++ ++ Return the string encoded to "bytes". ++ ++ *encoding* defaults to "'utf-8'"; see Standard Encodings for ++ possible values. ++ ++ *errors* controls how encoding errors are handled. If "'strict'" ++ (the default), a "UnicodeError" exception is raised. Other possible ++ values are "'ignore'", "'replace'", "'xmlcharrefreplace'", ++ "'backslashreplace'" and any other name registered via ++ "codecs.register_error()". See Error Handlers for details. ++ ++ For performance reasons, the value of *errors* is not checked for ++ validity unless an encoding error actually occurs, Python ++ Development Mode is enabled or a debug build is used. ++ ++ Changed in version 3.1: Added support for keyword arguments. ++ ++ Changed in version 3.9: The value of the *errors* argument is now ++ checked in Python Development Mode and in debug mode. ++ ++str.endswith(suffix[, start[, end]]) ++ ++ Return "True" if the string ends with the specified *suffix*, ++ otherwise return "False". *suffix* can also be a tuple of suffixes ++ to look for. With optional *start*, test beginning at that ++ position. With optional *end*, stop comparing at that position. ++ ++str.expandtabs(tabsize=8) ++ ++ Return a copy of the string where all tab characters are replaced ++ by one or more spaces, depending on the current column and the ++ given tab size. Tab positions occur every *tabsize* characters ++ (default is 8, giving tab positions at columns 0, 8, 16 and so on). ++ To expand the string, the current column is set to zero and the ++ string is examined character by character. If the character is a ++ tab ("\t"), one or more space characters are inserted in the result ++ until the current column is equal to the next tab position. (The ++ tab character itself is not copied.) If the character is a newline ++ ("\n") or return ("\r"), it is copied and the current column is ++ reset to zero. Any other character is copied unchanged and the ++ current column is incremented by one regardless of how the ++ character is represented when printed. ++ ++ >>> '01\t012\t0123\t01234'.expandtabs() ++ '01 012 0123 01234' ++ >>> '01\t012\t0123\t01234'.expandtabs(4) ++ '01 012 0123 01234' ++ ++str.find(sub[, start[, end]]) ++ ++ Return the lowest index in the string where substring *sub* is ++ found within the slice "s[start:end]". Optional arguments *start* ++ and *end* are interpreted as in slice notation. Return "-1" if ++ *sub* is not found. ++ ++ Note: ++ ++ The "find()" method should be used only if you need to know the ++ position of *sub*. To check if *sub* is a substring or not, use ++ the "in" operator: ++ ++ >>> 'Py' in 'Python' ++ True ++ ++str.format(*args, **kwargs) ++ ++ Perform a string formatting operation. The string on which this ++ method is called can contain literal text or replacement fields ++ delimited by braces "{}". Each replacement field contains either ++ the numeric index of a positional argument, or the name of a ++ keyword argument. Returns a copy of the string where each ++ replacement field is replaced with the string value of the ++ corresponding argument. ++ ++ >>> "The sum of 1 + 2 is {0}".format(1+2) ++ 'The sum of 1 + 2 is 3' ++ ++ See Format String Syntax for a description of the various ++ formatting options that can be specified in format strings. ++ ++ Note: ++ ++ When formatting a number ("int", "float", "complex", ++ "decimal.Decimal" and subclasses) with the "n" type (ex: ++ "'{:n}'.format(1234)"), the function temporarily sets the ++ "LC_CTYPE" locale to the "LC_NUMERIC" locale to decode ++ "decimal_point" and "thousands_sep" fields of "localeconv()" if ++ they are non-ASCII or longer than 1 byte, and the "LC_NUMERIC" ++ locale is different than the "LC_CTYPE" locale. This temporary ++ change affects other threads. ++ ++ Changed in version 3.7: When formatting a number with the "n" type, ++ the function sets temporarily the "LC_CTYPE" locale to the ++ "LC_NUMERIC" locale in some cases. ++ ++str.format_map(mapping, /) ++ ++ Similar to "str.format(**mapping)", except that "mapping" is used ++ directly and not copied to a "dict". This is useful if for example ++ "mapping" is a dict subclass: ++ ++ >>> class Default(dict): ++ ... def __missing__(self, key): ++ ... return key ++ ... ++ >>> '{name} was born in {country}'.format_map(Default(name='Guido')) ++ 'Guido was born in country' ++ ++ Added in version 3.2. ++ ++str.index(sub[, start[, end]]) ++ ++ Like "find()", but raise "ValueError" when the substring is not ++ found. ++ ++str.isalnum() ++ ++ Return "True" if all characters in the string are alphanumeric and ++ there is at least one character, "False" otherwise. A character ++ "c" is alphanumeric if one of the following returns "True": ++ "c.isalpha()", "c.isdecimal()", "c.isdigit()", or "c.isnumeric()". ++ ++str.isalpha() ++ ++ Return "True" if all characters in the string are alphabetic and ++ there is at least one character, "False" otherwise. Alphabetic ++ characters are those characters defined in the Unicode character ++ database as “Letterâ€, i.e., those with general category property ++ being one of “Lmâ€, “Ltâ€, “Luâ€, “Llâ€, or “Loâ€. Note that this is ++ different from the Alphabetic property defined in the section 4.10 ++ ‘Letters, Alphabetic, and Ideographic’ of the Unicode Standard. ++ ++str.isascii() ++ ++ Return "True" if the string is empty or all characters in the ++ string are ASCII, "False" otherwise. ASCII characters have code ++ points in the range U+0000-U+007F. ++ ++ Added in version 3.7. ++ ++str.isdecimal() ++ ++ Return "True" if all characters in the string are decimal ++ characters and there is at least one character, "False" otherwise. ++ Decimal characters are those that can be used to form numbers in ++ base 10, e.g. U+0660, ARABIC-INDIC DIGIT ZERO. Formally a decimal ++ character is a character in the Unicode General Category “Ndâ€. ++ ++str.isdigit() ++ ++ Return "True" if all characters in the string are digits and there ++ is at least one character, "False" otherwise. Digits include ++ decimal characters and digits that need special handling, such as ++ the compatibility superscript digits. This covers digits which ++ cannot be used to form numbers in base 10, like the Kharosthi ++ numbers. Formally, a digit is a character that has the property ++ value Numeric_Type=Digit or Numeric_Type=Decimal. ++ ++str.isidentifier() ++ ++ Return "True" if the string is a valid identifier according to the ++ language definition, section Identifiers and keywords. ++ ++ "keyword.iskeyword()" can be used to test whether string "s" is a ++ reserved identifier, such as "def" and "class". ++ ++ Example: ++ ++ >>> from keyword import iskeyword ++ ++ >>> 'hello'.isidentifier(), iskeyword('hello') ++ (True, False) ++ >>> 'def'.isidentifier(), iskeyword('def') ++ (True, True) ++ ++str.islower() ++ ++ Return "True" if all cased characters [4] in the string are ++ lowercase and there is at least one cased character, "False" ++ otherwise. ++ ++str.isnumeric() ++ ++ Return "True" if all characters in the string are numeric ++ characters, and there is at least one character, "False" otherwise. ++ Numeric characters include digit characters, and all characters ++ that have the Unicode numeric value property, e.g. U+2155, VULGAR ++ FRACTION ONE FIFTH. Formally, numeric characters are those with ++ the property value Numeric_Type=Digit, Numeric_Type=Decimal or ++ Numeric_Type=Numeric. ++ ++str.isprintable() ++ ++ Return "True" if all characters in the string are printable or the ++ string is empty, "False" otherwise. Nonprintable characters are ++ those characters defined in the Unicode character database as ++ “Other†or “Separatorâ€, excepting the ASCII space (0x20) which is ++ considered printable. (Note that printable characters in this ++ context are those which should not be escaped when "repr()" is ++ invoked on a string. It has no bearing on the handling of strings ++ written to "sys.stdout" or "sys.stderr".) ++ ++str.isspace() ++ ++ Return "True" if there are only whitespace characters in the string ++ and there is at least one character, "False" otherwise. ++ ++ A character is *whitespace* if in the Unicode character database ++ (see "unicodedata"), either its general category is "Zs" ++ (“Separator, spaceâ€), or its bidirectional class is one of "WS", ++ "B", or "S". ++ ++str.istitle() ++ ++ Return "True" if the string is a titlecased string and there is at ++ least one character, for example uppercase characters may only ++ follow uncased characters and lowercase characters only cased ones. ++ Return "False" otherwise. ++ ++str.isupper() ++ ++ Return "True" if all cased characters [4] in the string are ++ uppercase and there is at least one cased character, "False" ++ otherwise. ++ ++ >>> 'BANANA'.isupper() ++ True ++ >>> 'banana'.isupper() ++ False ++ >>> 'baNana'.isupper() ++ False ++ >>> ' '.isupper() ++ False ++ ++str.join(iterable) ++ ++ Return a string which is the concatenation of the strings in ++ *iterable*. A "TypeError" will be raised if there are any non- ++ string values in *iterable*, including "bytes" objects. The ++ separator between elements is the string providing this method. ++ ++str.ljust(width[, fillchar]) ++ ++ Return the string left justified in a string of length *width*. ++ Padding is done using the specified *fillchar* (default is an ASCII ++ space). The original string is returned if *width* is less than or ++ equal to "len(s)". ++ ++str.lower() ++ ++ Return a copy of the string with all the cased characters [4] ++ converted to lowercase. ++ ++ The lowercasing algorithm used is described in section 3.13 ++ ‘Default Case Folding’ of the Unicode Standard. ++ ++str.lstrip([chars]) ++ ++ Return a copy of the string with leading characters removed. The ++ *chars* argument is a string specifying the set of characters to be ++ removed. If omitted or "None", the *chars* argument defaults to ++ removing whitespace. The *chars* argument is not a prefix; rather, ++ all combinations of its values are stripped: ++ ++ >>> ' spacious '.lstrip() ++ 'spacious ' ++ >>> 'www.example.com'.lstrip('cmowz.') ++ 'example.com' ++ ++ See "str.removeprefix()" for a method that will remove a single ++ prefix string rather than all of a set of characters. For example: ++ ++ >>> 'Arthur: three!'.lstrip('Arthur: ') ++ 'ee!' ++ >>> 'Arthur: three!'.removeprefix('Arthur: ') ++ 'three!' ++ ++static str.maketrans(x[, y[, z]]) ++ ++ This static method returns a translation table usable for ++ "str.translate()". ++ ++ If there is only one argument, it must be a dictionary mapping ++ Unicode ordinals (integers) or characters (strings of length 1) to ++ Unicode ordinals, strings (of arbitrary lengths) or "None". ++ Character keys will then be converted to ordinals. ++ ++ If there are two arguments, they must be strings of equal length, ++ and in the resulting dictionary, each character in x will be mapped ++ to the character at the same position in y. If there is a third ++ argument, it must be a string, whose characters will be mapped to ++ "None" in the result. ++ ++str.partition(sep) ++ ++ Split the string at the first occurrence of *sep*, and return a ++ 3-tuple containing the part before the separator, the separator ++ itself, and the part after the separator. If the separator is not ++ found, return a 3-tuple containing the string itself, followed by ++ two empty strings. ++ ++str.removeprefix(prefix, /) ++ ++ If the string starts with the *prefix* string, return ++ "string[len(prefix):]". Otherwise, return a copy of the original ++ string: ++ ++ >>> 'TestHook'.removeprefix('Test') ++ 'Hook' ++ >>> 'BaseTestCase'.removeprefix('Test') ++ 'BaseTestCase' ++ ++ Added in version 3.9. ++ ++str.removesuffix(suffix, /) ++ ++ If the string ends with the *suffix* string and that *suffix* is ++ not empty, return "string[:-len(suffix)]". Otherwise, return a copy ++ of the original string: ++ ++ >>> 'MiscTests'.removesuffix('Tests') ++ 'Misc' ++ >>> 'TmpDirMixin'.removesuffix('Tests') ++ 'TmpDirMixin' ++ ++ Added in version 3.9. ++ ++str.replace(old, new, count=-1) ++ ++ Return a copy of the string with all occurrences of substring *old* ++ replaced by *new*. If *count* is given, only the first *count* ++ occurrences are replaced. If *count* is not specified or "-1", then ++ all occurrences are replaced. ++ ++ Changed in version 3.13: *count* is now supported as a keyword ++ argument. ++ ++str.rfind(sub[, start[, end]]) ++ ++ Return the highest index in the string where substring *sub* is ++ found, such that *sub* is contained within "s[start:end]". ++ Optional arguments *start* and *end* are interpreted as in slice ++ notation. Return "-1" on failure. ++ ++str.rindex(sub[, start[, end]]) ++ ++ Like "rfind()" but raises "ValueError" when the substring *sub* is ++ not found. ++ ++str.rjust(width[, fillchar]) ++ ++ Return the string right justified in a string of length *width*. ++ Padding is done using the specified *fillchar* (default is an ASCII ++ space). The original string is returned if *width* is less than or ++ equal to "len(s)". ++ ++str.rpartition(sep) ++ ++ Split the string at the last occurrence of *sep*, and return a ++ 3-tuple containing the part before the separator, the separator ++ itself, and the part after the separator. If the separator is not ++ found, return a 3-tuple containing two empty strings, followed by ++ the string itself. ++ ++str.rsplit(sep=None, maxsplit=-1) ++ ++ Return a list of the words in the string, using *sep* as the ++ delimiter string. If *maxsplit* is given, at most *maxsplit* splits ++ are done, the *rightmost* ones. If *sep* is not specified or ++ "None", any whitespace string is a separator. Except for splitting ++ from the right, "rsplit()" behaves like "split()" which is ++ described in detail below. ++ ++str.rstrip([chars]) ++ ++ Return a copy of the string with trailing characters removed. The ++ *chars* argument is a string specifying the set of characters to be ++ removed. If omitted or "None", the *chars* argument defaults to ++ removing whitespace. The *chars* argument is not a suffix; rather, ++ all combinations of its values are stripped: ++ ++ >>> ' spacious '.rstrip() ++ ' spacious' ++ >>> 'mississippi'.rstrip('ipz') ++ 'mississ' ++ ++ See "str.removesuffix()" for a method that will remove a single ++ suffix string rather than all of a set of characters. For example: ++ ++ >>> 'Monty Python'.rstrip(' Python') ++ 'M' ++ >>> 'Monty Python'.removesuffix(' Python') ++ 'Monty' ++ ++str.split(sep=None, maxsplit=-1) ++ ++ Return a list of the words in the string, using *sep* as the ++ delimiter string. If *maxsplit* is given, at most *maxsplit* ++ splits are done (thus, the list will have at most "maxsplit+1" ++ elements). If *maxsplit* is not specified or "-1", then there is ++ no limit on the number of splits (all possible splits are made). ++ ++ If *sep* is given, consecutive delimiters are not grouped together ++ and are deemed to delimit empty strings (for example, ++ "'1,,2'.split(',')" returns "['1', '', '2']"). The *sep* argument ++ may consist of multiple characters as a single delimiter (to split ++ with multiple delimiters, use "re.split()"). Splitting an empty ++ string with a specified separator returns "['']". ++ ++ For example: ++ ++ >>> '1,2,3'.split(',') ++ ['1', '2', '3'] ++ >>> '1,2,3'.split(',', maxsplit=1) ++ ['1', '2,3'] ++ >>> '1,2,,3,'.split(',') ++ ['1', '2', '', '3', ''] ++ >>> '1<>2<>3<4'.split('<>') ++ ['1', '2', '3<4'] ++ ++ If *sep* is not specified or is "None", a different splitting ++ algorithm is applied: runs of consecutive whitespace are regarded ++ as a single separator, and the result will contain no empty strings ++ at the start or end if the string has leading or trailing ++ whitespace. Consequently, splitting an empty string or a string ++ consisting of just whitespace with a "None" separator returns "[]". ++ ++ For example: ++ ++ >>> '1 2 3'.split() ++ ['1', '2', '3'] ++ >>> '1 2 3'.split(maxsplit=1) ++ ['1', '2 3'] ++ >>> ' 1 2 3 '.split() ++ ['1', '2', '3'] ++ ++str.splitlines(keepends=False) ++ ++ Return a list of the lines in the string, breaking at line ++ boundaries. Line breaks are not included in the resulting list ++ unless *keepends* is given and true. ++ ++ This method splits on the following line boundaries. In ++ particular, the boundaries are a superset of *universal newlines*. ++ ++ +-------------------------+-------------------------------+ ++ | Representation | Description | ++ |=========================|===============================| ++ | "\n" | Line Feed | ++ +-------------------------+-------------------------------+ ++ | "\r" | Carriage Return | ++ +-------------------------+-------------------------------+ ++ | "\r\n" | Carriage Return + Line Feed | ++ +-------------------------+-------------------------------+ ++ | "\v" or "\x0b" | Line Tabulation | ++ +-------------------------+-------------------------------+ ++ | "\f" or "\x0c" | Form Feed | ++ +-------------------------+-------------------------------+ ++ | "\x1c" | File Separator | ++ +-------------------------+-------------------------------+ ++ | "\x1d" | Group Separator | ++ +-------------------------+-------------------------------+ ++ | "\x1e" | Record Separator | ++ +-------------------------+-------------------------------+ ++ | "\x85" | Next Line (C1 Control Code) | ++ +-------------------------+-------------------------------+ ++ | "\u2028" | Line Separator | ++ +-------------------------+-------------------------------+ ++ | "\u2029" | Paragraph Separator | ++ +-------------------------+-------------------------------+ ++ ++ Changed in version 3.2: "\v" and "\f" added to list of line ++ boundaries. ++ ++ For example: ++ ++ >>> 'ab c\n\nde fg\rkl\r\n'.splitlines() ++ ['ab c', '', 'de fg', 'kl'] ++ >>> 'ab c\n\nde fg\rkl\r\n'.splitlines(keepends=True) ++ ['ab c\n', '\n', 'de fg\r', 'kl\r\n'] ++ ++ Unlike "split()" when a delimiter string *sep* is given, this ++ method returns an empty list for the empty string, and a terminal ++ line break does not result in an extra line: ++ ++ >>> "".splitlines() ++ [] ++ >>> "One line\n".splitlines() ++ ['One line'] ++ ++ For comparison, "split('\n')" gives: ++ ++ >>> ''.split('\n') ++ [''] ++ >>> 'Two lines\n'.split('\n') ++ ['Two lines', ''] ++ ++str.startswith(prefix[, start[, end]]) ++ ++ Return "True" if string starts with the *prefix*, otherwise return ++ "False". *prefix* can also be a tuple of prefixes to look for. ++ With optional *start*, test string beginning at that position. ++ With optional *end*, stop comparing string at that position. ++ ++str.strip([chars]) ++ ++ Return a copy of the string with the leading and trailing ++ characters removed. The *chars* argument is a string specifying the ++ set of characters to be removed. If omitted or "None", the *chars* ++ argument defaults to removing whitespace. The *chars* argument is ++ not a prefix or suffix; rather, all combinations of its values are ++ stripped: ++ ++ >>> ' spacious '.strip() ++ 'spacious' ++ >>> 'www.example.com'.strip('cmowz.') ++ 'example' ++ ++ The outermost leading and trailing *chars* argument values are ++ stripped from the string. Characters are removed from the leading ++ end until reaching a string character that is not contained in the ++ set of characters in *chars*. A similar action takes place on the ++ trailing end. For example: ++ ++ >>> comment_string = '#....... Section 3.2.1 Issue #32 .......' ++ >>> comment_string.strip('.#! ') ++ 'Section 3.2.1 Issue #32' ++ ++str.swapcase() ++ ++ Return a copy of the string with uppercase characters converted to ++ lowercase and vice versa. Note that it is not necessarily true that ++ "s.swapcase().swapcase() == s". ++ ++str.title() ++ ++ Return a titlecased version of the string where words start with an ++ uppercase character and the remaining characters are lowercase. ++ ++ For example: ++ ++ >>> 'Hello world'.title() ++ 'Hello World' ++ ++ The algorithm uses a simple language-independent definition of a ++ word as groups of consecutive letters. The definition works in ++ many contexts but it means that apostrophes in contractions and ++ possessives form word boundaries, which may not be the desired ++ result: ++ ++ >>> "they're bill's friends from the UK".title() ++ "They'Re Bill'S Friends From The Uk" ++ ++ The "string.capwords()" function does not have this problem, as it ++ splits words on spaces only. ++ ++ Alternatively, a workaround for apostrophes can be constructed ++ using regular expressions: ++ ++ >>> import re ++ >>> def titlecase(s): ++ ... return re.sub(r"[A-Za-z]+('[A-Za-z]+)?", ++ ... lambda mo: mo.group(0).capitalize(), ++ ... s) ++ ... ++ >>> titlecase("they're bill's friends.") ++ "They're Bill's Friends." ++ ++str.translate(table) ++ ++ Return a copy of the string in which each character has been mapped ++ through the given translation table. The table must be an object ++ that implements indexing via "__getitem__()", typically a *mapping* ++ or *sequence*. When indexed by a Unicode ordinal (an integer), the ++ table object can do any of the following: return a Unicode ordinal ++ or a string, to map the character to one or more other characters; ++ return "None", to delete the character from the return string; or ++ raise a "LookupError" exception, to map the character to itself. ++ ++ You can use "str.maketrans()" to create a translation map from ++ character-to-character mappings in different formats. ++ ++ See also the "codecs" module for a more flexible approach to custom ++ character mappings. ++ ++str.upper() ++ ++ Return a copy of the string with all the cased characters [4] ++ converted to uppercase. Note that "s.upper().isupper()" might be ++ "False" if "s" contains uncased characters or if the Unicode ++ category of the resulting character(s) is not “Lu†(Letter, ++ uppercase), but e.g. “Lt†(Letter, titlecase). ++ ++ The uppercasing algorithm used is described in section 3.13 ++ ‘Default Case Folding’ of the Unicode Standard. ++ ++str.zfill(width) ++ ++ Return a copy of the string left filled with ASCII "'0'" digits to ++ make a string of length *width*. A leading sign prefix ++ ("'+'"/"'-'") is handled by inserting the padding *after* the sign ++ character rather than before. The original string is returned if ++ *width* is less than or equal to "len(s)". ++ ++ For example: ++ ++ >>> "42".zfill(5) ++ '00042' ++ >>> "-42".zfill(5) ++ '-0042' ++''', ++ 'strings': '''String and Bytes literals ++************************* ++ ++String literals are described by the following lexical definitions: ++ ++ **stringliteral**: ["stringprefix"]("shortstring" | "longstring") ++ **stringprefix**: "r" | "u" | "R" | "U" | "f" | "F" ++ | "fr" | "Fr" | "fR" | "FR" | "rf" | "rF" | "Rf" | "RF" ++ **shortstring**: "'" "shortstringitem"* "'" | '"' "shortstringitem"* '"' ++ **longstring**: "\'\'\'" "longstringitem"* "\'\'\'" | '"""' "longstringitem"* '"""' ++ **shortstringitem**: "shortstringchar" | "stringescapeseq" ++ **longstringitem**: "longstringchar" | "stringescapeseq" ++ **shortstringchar**: ++ **longstringchar**: ++ **stringescapeseq**: "\\" ++ ++ **bytesliteral**: "bytesprefix"("shortbytes" | "longbytes") ++ **bytesprefix**: "b" | "B" | "br" | "Br" | "bR" | "BR" | "rb" | "rB" | "Rb" | "RB" ++ **shortbytes**: "'" "shortbytesitem"* "'" | '"' "shortbytesitem"* '"' ++ **longbytes**: "\'\'\'" "longbytesitem"* "\'\'\'" | '"""' "longbytesitem"* '"""' ++ **shortbytesitem**: "shortbyteschar" | "bytesescapeseq" ++ **longbytesitem**: "longbyteschar" | "bytesescapeseq" ++ **shortbyteschar**: ++ **longbyteschar**: ++ **bytesescapeseq**: "\\" ++ ++One syntactic restriction not indicated by these productions is that ++whitespace is not allowed between the "stringprefix" or "bytesprefix" ++and the rest of the literal. The source character set is defined by ++the encoding declaration; it is UTF-8 if no encoding declaration is ++given in the source file; see section Encoding declarations. ++ ++In plain English: Both types of literals can be enclosed in matching ++single quotes ("'") or double quotes ("""). They can also be enclosed ++in matching groups of three single or double quotes (these are ++generally referred to as *triple-quoted strings*). The backslash ("\\") ++character is used to give special meaning to otherwise ordinary ++characters like "n", which means ‘newline’ when escaped ("\\n"). It can ++also be used to escape characters that otherwise have a special ++meaning, such as newline, backslash itself, or the quote character. ++See escape sequences below for examples. ++ ++Bytes literals are always prefixed with "'b'" or "'B'"; they produce ++an instance of the "bytes" type instead of the "str" type. They may ++only contain ASCII characters; bytes with a numeric value of 128 or ++greater must be expressed with escapes. ++ ++Both string and bytes literals may optionally be prefixed with a ++letter "'r'" or "'R'"; such constructs are called *raw string ++literals* and *raw bytes literals* respectively and treat backslashes ++as literal characters. As a result, in raw string literals, "'\\U'" ++and "'\\u'" escapes are not treated specially. ++ ++Added in version 3.3: The "'rb'" prefix of raw bytes literals has been ++added as a synonym of "'br'".Support for the unicode legacy literal ++("u'value'") was reintroduced to simplify the maintenance of dual ++Python 2.x and 3.x codebases. See **PEP 414** for more information. ++ ++A string literal with "'f'" or "'F'" in its prefix is a *formatted ++string literal*; see f-strings. The "'f'" may be combined with "'r'", ++but not with "'b'" or "'u'", therefore raw formatted strings are ++possible, but formatted bytes literals are not. ++ ++In triple-quoted literals, unescaped newlines and quotes are allowed ++(and are retained), except that three unescaped quotes in a row ++terminate the literal. (A “quote†is the character used to open the ++literal, i.e. either "'" or """.) ++ ++ ++Escape sequences ++================ ++ ++Unless an "'r'" or "'R'" prefix is present, escape sequences in string ++and bytes literals are interpreted according to rules similar to those ++used by Standard C. The recognized escape sequences are: ++ +++---------------------------+-----------------------------------+---------+ ++| Escape Sequence | Meaning | Notes | ++|===========================|===================================|=========| ++| "\\" | Backslash and newline ignored | (1) | +++---------------------------+-----------------------------------+---------+ ++| "\\\\" | Backslash ("\\") | | +++---------------------------+-----------------------------------+---------+ ++| "\\'" | Single quote ("'") | | +++---------------------------+-----------------------------------+---------+ ++| "\\"" | Double quote (""") | | +++---------------------------+-----------------------------------+---------+ ++| "\\a" | ASCII Bell (BEL) | | +++---------------------------+-----------------------------------+---------+ ++| "\\b" | ASCII Backspace (BS) | | +++---------------------------+-----------------------------------+---------+ ++| "\\f" | ASCII Formfeed (FF) | | +++---------------------------+-----------------------------------+---------+ ++| "\\n" | ASCII Linefeed (LF) | | +++---------------------------+-----------------------------------+---------+ ++| "\\r" | ASCII Carriage Return (CR) | | +++---------------------------+-----------------------------------+---------+ ++| "\\t" | ASCII Horizontal Tab (TAB) | | +++---------------------------+-----------------------------------+---------+ ++| "\\v" | ASCII Vertical Tab (VT) | | +++---------------------------+-----------------------------------+---------+ ++| "\\*ooo*" | Character with octal value *ooo* | (2,4) | +++---------------------------+-----------------------------------+---------+ ++| "\\x*hh*" | Character with hex value *hh* | (3,4) | +++---------------------------+-----------------------------------+---------+ ++ ++Escape sequences only recognized in string literals are: ++ +++---------------------------+-----------------------------------+---------+ ++| Escape Sequence | Meaning | Notes | ++|===========================|===================================|=========| ++| "\\N{*name*}" | Character named *name* in the | (5) | ++| | Unicode database | | +++---------------------------+-----------------------------------+---------+ ++| "\\u*xxxx*" | Character with 16-bit hex value | (6) | ++| | *xxxx* | | +++---------------------------+-----------------------------------+---------+ ++| "\\U*xxxxxxxx*" | Character with 32-bit hex value | (7) | ++| | *xxxxxxxx* | | +++---------------------------+-----------------------------------+---------+ ++ ++Notes: ++ ++1. A backslash can be added at the end of a line to ignore the ++ newline: ++ ++ >>> 'This string will not include \\ ++ ... backslashes or newline characters.' ++ 'This string will not include backslashes or newline characters.' ++ ++ The same result can be achieved using triple-quoted strings, or ++ parentheses and string literal concatenation. ++ ++2. As in Standard C, up to three octal digits are accepted. ++ ++ Changed in version 3.11: Octal escapes with value larger than ++ "0o377" produce a "DeprecationWarning". ++ ++ Changed in version 3.12: Octal escapes with value larger than ++ "0o377" produce a "SyntaxWarning". In a future Python version they ++ will be eventually a "SyntaxError". ++ ++3. Unlike in Standard C, exactly two hex digits are required. ++ ++4. In a bytes literal, hexadecimal and octal escapes denote the byte ++ with the given value. In a string literal, these escapes denote a ++ Unicode character with the given value. ++ ++5. Changed in version 3.3: Support for name aliases [1] has been ++ added. ++ ++6. Exactly four hex digits are required. ++ ++7. Any Unicode character can be encoded this way. Exactly eight hex ++ digits are required. ++ ++Unlike Standard C, all unrecognized escape sequences are left in the ++string unchanged, i.e., *the backslash is left in the result*. (This ++behavior is useful when debugging: if an escape sequence is mistyped, ++the resulting output is more easily recognized as broken.) It is also ++important to note that the escape sequences only recognized in string ++literals fall into the category of unrecognized escapes for bytes ++literals. ++ ++Changed in version 3.6: Unrecognized escape sequences produce a ++"DeprecationWarning". ++ ++Changed in version 3.12: Unrecognized escape sequences produce a ++"SyntaxWarning". In a future Python version they will be eventually a ++"SyntaxError". ++ ++Even in a raw literal, quotes can be escaped with a backslash, but the ++backslash remains in the result; for example, "r"\\""" is a valid ++string literal consisting of two characters: a backslash and a double ++quote; "r"\\"" is not a valid string literal (even a raw string cannot ++end in an odd number of backslashes). Specifically, *a raw literal ++cannot end in a single backslash* (since the backslash would escape ++the following quote character). Note also that a single backslash ++followed by a newline is interpreted as those two characters as part ++of the literal, *not* as a line continuation. ++''', ++ 'subscriptions': r'''Subscriptions ++************* ++ ++The subscription of an instance of a container class will generally ++select an element from the container. The subscription of a *generic ++class* will generally return a GenericAlias object. ++ ++ **subscription**: "primary" "[" "flexible_expression_list" "]" ++ ++When an object is subscripted, the interpreter will evaluate the ++primary and the expression list. ++ ++The primary must evaluate to an object that supports subscription. An ++object may support subscription through defining one or both of ++"__getitem__()" and "__class_getitem__()". When the primary is ++subscripted, the evaluated result of the expression list will be ++passed to one of these methods. For more details on when ++"__class_getitem__" is called instead of "__getitem__", see ++__class_getitem__ versus __getitem__. ++ ++If the expression list contains at least one comma, or if any of the ++expressions are starred, the expression list will evaluate to a ++"tuple" containing the items of the expression list. Otherwise, the ++expression list will evaluate to the value of the list’s sole member. ++ ++Changed in version 3.11: Expressions in an expression list may be ++starred. See **PEP 646**. ++ ++For built-in objects, there are two types of objects that support ++subscription via "__getitem__()": ++ ++1. Mappings. If the primary is a *mapping*, the expression list must ++ evaluate to an object whose value is one of the keys of the ++ mapping, and the subscription selects the value in the mapping that ++ corresponds to that key. An example of a builtin mapping class is ++ the "dict" class. ++ ++2. Sequences. If the primary is a *sequence*, the expression list must ++ evaluate to an "int" or a "slice" (as discussed in the following ++ section). Examples of builtin sequence classes include the "str", ++ "list" and "tuple" classes. ++ ++The formal syntax makes no special provision for negative indices in ++*sequences*. However, built-in sequences all provide a "__getitem__()" ++method that interprets negative indices by adding the length of the ++sequence to the index so that, for example, "x[-1]" selects the last ++item of "x". The resulting value must be a nonnegative integer less ++than the number of items in the sequence, and the subscription selects ++the item whose index is that value (counting from zero). Since the ++support for negative indices and slicing occurs in the object’s ++"__getitem__()" method, subclasses overriding this method will need to ++explicitly add that support. ++ ++A "string" is a special kind of sequence whose items are *characters*. ++A character is not a separate data type but a string of exactly one ++character. ++''', ++ 'truth': r'''Truth Value Testing ++******************* ++ ++Any object can be tested for truth value, for use in an "if" or ++"while" condition or as operand of the Boolean operations below. ++ ++By default, an object is considered true unless its class defines ++either a "__bool__()" method that returns "False" or a "__len__()" ++method that returns zero, when called with the object. [1] Here are ++most of the built-in objects considered false: ++ ++* constants defined to be false: "None" and "False" ++ ++* zero of any numeric type: "0", "0.0", "0j", "Decimal(0)", ++ "Fraction(0, 1)" ++ ++* empty sequences and collections: "''", "()", "[]", "{}", "set()", ++ "range(0)" ++ ++Operations and built-in functions that have a Boolean result always ++return "0" or "False" for false and "1" or "True" for true, unless ++otherwise stated. (Important exception: the Boolean operations "or" ++and "and" always return one of their operands.) ++''', ++ 'try': r'''The "try" statement ++******************* ++ ++The "try" statement specifies exception handlers and/or cleanup code ++for a group of statements: ++ ++ **try_stmt**: "try1_stmt" | "try2_stmt" | "try3_stmt" ++ **try1_stmt**: "try" ":" "suite" ++ ("except" ["expression" ["as" "identifier"]] ":" "suite")+ ++ ["else" ":" "suite"] ++ ["finally" ":" "suite"] ++ **try2_stmt**: "try" ":" "suite" ++ ("except" "*" "expression" ["as" "identifier"] ":" "suite")+ ++ ["else" ":" "suite"] ++ ["finally" ":" "suite"] ++ **try3_stmt**: "try" ":" "suite" ++ "finally" ":" "suite" ++ ++Additional information on exceptions can be found in section ++Exceptions, and information on using the "raise" statement to generate ++exceptions may be found in section The raise statement. ++ ++ ++"except" clause ++=============== ++ ++The "except" clause(s) specify one or more exception handlers. When no ++exception occurs in the "try" clause, no exception handler is ++executed. When an exception occurs in the "try" suite, a search for an ++exception handler is started. This search inspects the "except" ++clauses in turn until one is found that matches the exception. An ++expression-less "except" clause, if present, must be last; it matches ++any exception. ++ ++For an "except" clause with an expression, the expression must ++evaluate to an exception type or a tuple of exception types. The ++raised exception matches an "except" clause whose expression evaluates ++to the class or a *non-virtual base class* of the exception object, or ++to a tuple that contains such a class. ++ ++If no "except" clause matches the exception, the search for an ++exception handler continues in the surrounding code and on the ++invocation stack. [1] ++ ++If the evaluation of an expression in the header of an "except" clause ++raises an exception, the original search for a handler is canceled and ++a search starts for the new exception in the surrounding code and on ++the call stack (it is treated as if the entire "try" statement raised ++the exception). ++ ++When a matching "except" clause is found, the exception is assigned to ++the target specified after the "as" keyword in that "except" clause, ++if present, and the "except" clause’s suite is executed. All "except" ++clauses must have an executable block. When the end of this block is ++reached, execution continues normally after the entire "try" ++statement. (This means that if two nested handlers exist for the same ++exception, and the exception occurs in the "try" clause of the inner ++handler, the outer handler will not handle the exception.) ++ ++When an exception has been assigned using "as target", it is cleared ++at the end of the "except" clause. This is as if ++ ++ except E as N: ++ foo ++ ++was translated to ++ ++ except E as N: ++ try: ++ foo ++ finally: ++ del N ++ ++This means the exception must be assigned to a different name to be ++able to refer to it after the "except" clause. Exceptions are cleared ++because with the traceback attached to them, they form a reference ++cycle with the stack frame, keeping all locals in that frame alive ++until the next garbage collection occurs. ++ ++Before an "except" clause’s suite is executed, the exception is stored ++in the "sys" module, where it can be accessed from within the body of ++the "except" clause by calling "sys.exception()". When leaving an ++exception handler, the exception stored in the "sys" module is reset ++to its previous value: ++ ++ >>> print(sys.exception()) ++ None ++ >>> try: ++ ... raise TypeError ++ ... except: ++ ... print(repr(sys.exception())) ++ ... try: ++ ... raise ValueError ++ ... except: ++ ... print(repr(sys.exception())) ++ ... print(repr(sys.exception())) ++ ... ++ TypeError() ++ ValueError() ++ TypeError() ++ >>> print(sys.exception()) ++ None ++ ++ ++"except*" clause ++================ ++ ++The "except*" clause(s) are used for handling "ExceptionGroup"s. The ++exception type for matching is interpreted as in the case of "except", ++but in the case of exception groups we can have partial matches when ++the type matches some of the exceptions in the group. This means that ++multiple "except*" clauses can execute, each handling part of the ++exception group. Each clause executes at most once and handles an ++exception group of all matching exceptions. Each exception in the ++group is handled by at most one "except*" clause, the first that ++matches it. ++ ++ >>> try: ++ ... raise ExceptionGroup("eg", ++ ... [ValueError(1), TypeError(2), OSError(3), OSError(4)]) ++ ... except* TypeError as e: ++ ... print(f'caught {type(e)} with nested {e.exceptions}') ++ ... except* OSError as e: ++ ... print(f'caught {type(e)} with nested {e.exceptions}') ++ ... ++ caught with nested (TypeError(2),) ++ caught with nested (OSError(3), OSError(4)) ++ + Exception Group Traceback (most recent call last): ++ | File "", line 2, in ++ | ExceptionGroup: eg ++ +-+---------------- 1 ---------------- ++ | ValueError: 1 ++ +------------------------------------ ++ ++Any remaining exceptions that were not handled by any "except*" clause ++are re-raised at the end, along with all exceptions that were raised ++from within the "except*" clauses. If this list contains more than one ++exception to reraise, they are combined into an exception group. ++ ++If the raised exception is not an exception group and its type matches ++one of the "except*" clauses, it is caught and wrapped by an exception ++group with an empty message string. ++ ++ >>> try: ++ ... raise BlockingIOError ++ ... except* BlockingIOError as e: ++ ... print(repr(e)) ++ ... ++ ExceptionGroup('', (BlockingIOError())) ++ ++An "except*" clause must have a matching expression; it cannot be ++"except*:". Furthermore, this expression cannot contain exception ++group types, because that would have ambiguous semantics. ++ ++It is not possible to mix "except" and "except*" in the same "try". ++"break", "continue" and "return" cannot appear in an "except*" clause. ++ ++ ++"else" clause ++============= ++ ++The optional "else" clause is executed if the control flow leaves the ++"try" suite, no exception was raised, and no "return", "continue", or ++"break" statement was executed. Exceptions in the "else" clause are ++not handled by the preceding "except" clauses. ++ ++ ++"finally" clause ++================ ++ ++If "finally" is present, it specifies a ‘cleanup’ handler. The "try" ++clause is executed, including any "except" and "else" clauses. If an ++exception occurs in any of the clauses and is not handled, the ++exception is temporarily saved. The "finally" clause is executed. If ++there is a saved exception it is re-raised at the end of the "finally" ++clause. If the "finally" clause raises another exception, the saved ++exception is set as the context of the new exception. If the "finally" ++clause executes a "return", "break" or "continue" statement, the saved ++exception is discarded: ++ ++ >>> def f(): ++ ... try: ++ ... 1/0 ++ ... finally: ++ ... return 42 ++ ... ++ >>> f() ++ 42 ++ ++The exception information is not available to the program during ++execution of the "finally" clause. ++ ++When a "return", "break" or "continue" statement is executed in the ++"try" suite of a "try"…"finally" statement, the "finally" clause is ++also executed ‘on the way out.’ ++ ++The return value of a function is determined by the last "return" ++statement executed. Since the "finally" clause always executes, a ++"return" statement executed in the "finally" clause will always be the ++last one executed: ++ ++ >>> def foo(): ++ ... try: ++ ... return 'try' ++ ... finally: ++ ... return 'finally' ++ ... ++ >>> foo() ++ 'finally' ++ ++Changed in version 3.8: Prior to Python 3.8, a "continue" statement ++was illegal in the "finally" clause due to a problem with the ++implementation. ++''', ++ 'types': r'''The standard type hierarchy ++*************************** ++ ++Below is a list of the types that are built into Python. Extension ++modules (written in C, Java, or other languages, depending on the ++implementation) can define additional types. Future versions of ++Python may add types to the type hierarchy (e.g., rational numbers, ++efficiently stored arrays of integers, etc.), although such additions ++will often be provided via the standard library instead. ++ ++Some of the type descriptions below contain a paragraph listing ++‘special attributes.’ These are attributes that provide access to the ++implementation and are not intended for general use. Their definition ++may change in the future. ++ ++ ++None ++==== ++ ++This type has a single value. There is a single object with this ++value. This object is accessed through the built-in name "None". It is ++used to signify the absence of a value in many situations, e.g., it is ++returned from functions that don’t explicitly return anything. Its ++truth value is false. ++ ++ ++NotImplemented ++============== ++ ++This type has a single value. There is a single object with this ++value. This object is accessed through the built-in name ++"NotImplemented". Numeric methods and rich comparison methods should ++return this value if they do not implement the operation for the ++operands provided. (The interpreter will then try the reflected ++operation, or some other fallback, depending on the operator.) It ++should not be evaluated in a boolean context. ++ ++See Implementing the arithmetic operations for more details. ++ ++Changed in version 3.9: Evaluating "NotImplemented" in a boolean ++context was deprecated. ++ ++Changed in version 3.14: Evaluating "NotImplemented" in a boolean ++context now raises a "TypeError". It previously evaluated to "True" ++and emitted a "DeprecationWarning" since Python 3.9. ++ ++ ++Ellipsis ++======== ++ ++This type has a single value. There is a single object with this ++value. This object is accessed through the literal "..." or the built- ++in name "Ellipsis". Its truth value is true. ++ ++ ++"numbers.Number" ++================ ++ ++These are created by numeric literals and returned as results by ++arithmetic operators and arithmetic built-in functions. Numeric ++objects are immutable; once created their value never changes. Python ++numbers are of course strongly related to mathematical numbers, but ++subject to the limitations of numerical representation in computers. ++ ++The string representations of the numeric classes, computed by ++"__repr__()" and "__str__()", have the following properties: ++ ++* They are valid numeric literals which, when passed to their class ++ constructor, produce an object having the value of the original ++ numeric. ++ ++* The representation is in base 10, when possible. ++ ++* Leading zeros, possibly excepting a single zero before a decimal ++ point, are not shown. ++ ++* Trailing zeros, possibly excepting a single zero after a decimal ++ point, are not shown. ++ ++* A sign is shown only when the number is negative. ++ ++Python distinguishes between integers, floating-point numbers, and ++complex numbers: ++ ++ ++"numbers.Integral" ++------------------ ++ ++These represent elements from the mathematical set of integers ++(positive and negative). ++ ++Note: ++ ++ The rules for integer representation are intended to give the most ++ meaningful interpretation of shift and mask operations involving ++ negative integers. ++ ++There are two types of integers: ++ ++Integers ("int") ++ These represent numbers in an unlimited range, subject to available ++ (virtual) memory only. For the purpose of shift and mask ++ operations, a binary representation is assumed, and negative ++ numbers are represented in a variant of 2’s complement which gives ++ the illusion of an infinite string of sign bits extending to the ++ left. ++ ++Booleans ("bool") ++ These represent the truth values False and True. The two objects ++ representing the values "False" and "True" are the only Boolean ++ objects. The Boolean type is a subtype of the integer type, and ++ Boolean values behave like the values 0 and 1, respectively, in ++ almost all contexts, the exception being that when converted to a ++ string, the strings ""False"" or ""True"" are returned, ++ respectively. ++ ++ ++"numbers.Real" ("float") ++------------------------ ++ ++These represent machine-level double precision floating-point numbers. ++You are at the mercy of the underlying machine architecture (and C or ++Java implementation) for the accepted range and handling of overflow. ++Python does not support single-precision floating-point numbers; the ++savings in processor and memory usage that are usually the reason for ++using these are dwarfed by the overhead of using objects in Python, so ++there is no reason to complicate the language with two kinds of ++floating-point numbers. ++ ++ ++"numbers.Complex" ("complex") ++----------------------------- ++ ++These represent complex numbers as a pair of machine-level double ++precision floating-point numbers. The same caveats apply as for ++floating-point numbers. The real and imaginary parts of a complex ++number "z" can be retrieved through the read-only attributes "z.real" ++and "z.imag". ++ ++ ++Sequences ++========= ++ ++These represent finite ordered sets indexed by non-negative numbers. ++The built-in function "len()" returns the number of items of a ++sequence. When the length of a sequence is *n*, the index set contains ++the numbers 0, 1, …, *n*-1. Item *i* of sequence *a* is selected by ++"a[i]". Some sequences, including built-in sequences, interpret ++negative subscripts by adding the sequence length. For example, ++"a[-2]" equals "a[n-2]", the second to last item of sequence a with ++length "n". ++ ++Sequences also support slicing: "a[i:j]" selects all items with index ++*k* such that *i* "<=" *k* "<" *j*. When used as an expression, a ++slice is a sequence of the same type. The comment above about negative ++indexes also applies to negative slice positions. ++ ++Some sequences also support “extended slicing†with a third “step†++parameter: "a[i:j:k]" selects all items of *a* with index *x* where "x ++= i + n*k", *n* ">=" "0" and *i* "<=" *x* "<" *j*. ++ ++Sequences are distinguished according to their mutability: ++ ++ ++Immutable sequences ++------------------- ++ ++An object of an immutable sequence type cannot change once it is ++created. (If the object contains references to other objects, these ++other objects may be mutable and may be changed; however, the ++collection of objects directly referenced by an immutable object ++cannot change.) ++ ++The following types are immutable sequences: ++ ++Strings ++ A string is a sequence of values that represent Unicode code ++ points. All the code points in the range "U+0000 - U+10FFFF" can be ++ represented in a string. Python doesn’t have a char type; instead, ++ every code point in the string is represented as a string object ++ with length "1". The built-in function "ord()" converts a code ++ point from its string form to an integer in the range "0 - 10FFFF"; ++ "chr()" converts an integer in the range "0 - 10FFFF" to the ++ corresponding length "1" string object. "str.encode()" can be used ++ to convert a "str" to "bytes" using the given text encoding, and ++ "bytes.decode()" can be used to achieve the opposite. ++ ++Tuples ++ The items of a tuple are arbitrary Python objects. Tuples of two or ++ more items are formed by comma-separated lists of expressions. A ++ tuple of one item (a ‘singleton’) can be formed by affixing a comma ++ to an expression (an expression by itself does not create a tuple, ++ since parentheses must be usable for grouping of expressions). An ++ empty tuple can be formed by an empty pair of parentheses. ++ ++Bytes ++ A bytes object is an immutable array. The items are 8-bit bytes, ++ represented by integers in the range 0 <= x < 256. Bytes literals ++ (like "b'abc'") and the built-in "bytes()" constructor can be used ++ to create bytes objects. Also, bytes objects can be decoded to ++ strings via the "decode()" method. ++ ++ ++Mutable sequences ++----------------- ++ ++Mutable sequences can be changed after they are created. The ++subscription and slicing notations can be used as the target of ++assignment and "del" (delete) statements. ++ ++Note: ++ ++ The "collections" and "array" module provide additional examples of ++ mutable sequence types. ++ ++There are currently two intrinsic mutable sequence types: ++ ++Lists ++ The items of a list are arbitrary Python objects. Lists are formed ++ by placing a comma-separated list of expressions in square ++ brackets. (Note that there are no special cases needed to form ++ lists of length 0 or 1.) ++ ++Byte Arrays ++ A bytearray object is a mutable array. They are created by the ++ built-in "bytearray()" constructor. Aside from being mutable (and ++ hence unhashable), byte arrays otherwise provide the same interface ++ and functionality as immutable "bytes" objects. ++ ++ ++Set types ++========= ++ ++These represent unordered, finite sets of unique, immutable objects. ++As such, they cannot be indexed by any subscript. However, they can be ++iterated over, and the built-in function "len()" returns the number of ++items in a set. Common uses for sets are fast membership testing, ++removing duplicates from a sequence, and computing mathematical ++operations such as intersection, union, difference, and symmetric ++difference. ++ ++For set elements, the same immutability rules apply as for dictionary ++keys. Note that numeric types obey the normal rules for numeric ++comparison: if two numbers compare equal (e.g., "1" and "1.0"), only ++one of them can be contained in a set. ++ ++There are currently two intrinsic set types: ++ ++Sets ++ These represent a mutable set. They are created by the built-in ++ "set()" constructor and can be modified afterwards by several ++ methods, such as "add()". ++ ++Frozen sets ++ These represent an immutable set. They are created by the built-in ++ "frozenset()" constructor. As a frozenset is immutable and ++ *hashable*, it can be used again as an element of another set, or ++ as a dictionary key. ++ ++ ++Mappings ++======== ++ ++These represent finite sets of objects indexed by arbitrary index ++sets. The subscript notation "a[k]" selects the item indexed by "k" ++from the mapping "a"; this can be used in expressions and as the ++target of assignments or "del" statements. The built-in function ++"len()" returns the number of items in a mapping. ++ ++There is currently a single intrinsic mapping type: ++ ++ ++Dictionaries ++------------ ++ ++These represent finite sets of objects indexed by nearly arbitrary ++values. The only types of values not acceptable as keys are values ++containing lists or dictionaries or other mutable types that are ++compared by value rather than by object identity, the reason being ++that the efficient implementation of dictionaries requires a key’s ++hash value to remain constant. Numeric types used for keys obey the ++normal rules for numeric comparison: if two numbers compare equal ++(e.g., "1" and "1.0") then they can be used interchangeably to index ++the same dictionary entry. ++ ++Dictionaries preserve insertion order, meaning that keys will be ++produced in the same order they were added sequentially over the ++dictionary. Replacing an existing key does not change the order, ++however removing a key and re-inserting it will add it to the end ++instead of keeping its old place. ++ ++Dictionaries are mutable; they can be created by the "{}" notation ++(see section Dictionary displays). ++ ++The extension modules "dbm.ndbm" and "dbm.gnu" provide additional ++examples of mapping types, as does the "collections" module. ++ ++Changed in version 3.7: Dictionaries did not preserve insertion order ++in versions of Python before 3.6. In CPython 3.6, insertion order was ++preserved, but it was considered an implementation detail at that time ++rather than a language guarantee. ++ ++ ++Callable types ++============== ++ ++These are the types to which the function call operation (see section ++Calls) can be applied: ++ ++ ++User-defined functions ++---------------------- ++ ++A user-defined function object is created by a function definition ++(see section Function definitions). It should be called with an ++argument list containing the same number of items as the function’s ++formal parameter list. ++ ++ ++Special read-only attributes ++~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ +++----------------------------------------------------+----------------------------------------------------+ ++| Attribute | Meaning | ++|====================================================|====================================================| ++| function.__globals__ | A reference to the "dictionary" that holds the | ++| | function’s global variables – the global namespace | ++| | of the module in which the function was defined. | +++----------------------------------------------------+----------------------------------------------------+ ++| function.__closure__ | "None" or a "tuple" of cells that contain bindings | ++| | for the names specified in the "co_freevars" | ++| | attribute of the function’s "code object". A cell | ++| | object has the attribute "cell_contents". This can | ++| | be used to get the value of the cell, as well as | ++| | set the value. | +++----------------------------------------------------+----------------------------------------------------+ ++ ++ ++Special writable attributes ++~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ ++Most of these attributes check the type of the assigned value: ++ +++----------------------------------------------------+----------------------------------------------------+ ++| Attribute | Meaning | ++|====================================================|====================================================| ++| function.__doc__ | The function’s documentation string, or "None" if | ++| | unavailable. | +++----------------------------------------------------+----------------------------------------------------+ ++| function.__name__ | The function’s name. See also: "__name__ | ++| | attributes". | +++----------------------------------------------------+----------------------------------------------------+ ++| function.__qualname__ | The function’s *qualified name*. See also: | ++| | "__qualname__ attributes". Added in version 3.3. | +++----------------------------------------------------+----------------------------------------------------+ ++| function.__module__ | The name of the module the function was defined | ++| | in, or "None" if unavailable. | +++----------------------------------------------------+----------------------------------------------------+ ++| function.__defaults__ | A "tuple" containing default *parameter* values | ++| | for those parameters that have defaults, or "None" | ++| | if no parameters have a default value. | +++----------------------------------------------------+----------------------------------------------------+ ++| function.__code__ | The code object representing the compiled function | ++| | body. | +++----------------------------------------------------+----------------------------------------------------+ ++| function.__dict__ | The namespace supporting arbitrary function | ++| | attributes. See also: "__dict__ attributes". | +++----------------------------------------------------+----------------------------------------------------+ ++| function.__annotations__ | A "dictionary" containing annotations of | ++| | *parameters*. The keys of the dictionary are the | ++| | parameter names, and "'return'" for the return | ++| | annotation, if provided. See also: | ++| | "object.__annotations__". Changed in version | ++| | 3.14: Annotations are now lazily evaluated. See | ++| | **PEP 649**. | +++----------------------------------------------------+----------------------------------------------------+ ++| function.__annotate__ | The *annotate function* for this function, or | ++| | "None" if the function has no annotations. See | ++| | "object.__annotate__". Added in version 3.14. | +++----------------------------------------------------+----------------------------------------------------+ ++| function.__kwdefaults__ | A "dictionary" containing defaults for keyword- | ++| | only *parameters*. | +++----------------------------------------------------+----------------------------------------------------+ ++| function.__type_params__ | A "tuple" containing the type parameters of a | ++| | generic function. Added in version 3.12. | +++----------------------------------------------------+----------------------------------------------------+ ++ ++Function objects also support getting and setting arbitrary ++attributes, which can be used, for example, to attach metadata to ++functions. Regular attribute dot-notation is used to get and set such ++attributes. ++ ++**CPython implementation detail:** CPython’s current implementation ++only supports function attributes on user-defined functions. Function ++attributes on built-in functions may be supported in the future. ++ ++Additional information about a function’s definition can be retrieved ++from its code object (accessible via the "__code__" attribute). ++ ++ ++Instance methods ++---------------- ++ ++An instance method object combines a class, a class instance and any ++callable object (normally a user-defined function). ++ ++Special read-only attributes: ++ +++----------------------------------------------------+----------------------------------------------------+ ++| method.__self__ | Refers to the class instance object to which the | ++| | method is bound | +++----------------------------------------------------+----------------------------------------------------+ ++| method.__func__ | Refers to the original function object | +++----------------------------------------------------+----------------------------------------------------+ ++| method.__doc__ | The method’s documentation (same as | ++| | "method.__func__.__doc__"). A "string" if the | ++| | original function had a docstring, else "None". | +++----------------------------------------------------+----------------------------------------------------+ ++| method.__name__ | The name of the method (same as | ++| | "method.__func__.__name__") | +++----------------------------------------------------+----------------------------------------------------+ ++| method.__module__ | The name of the module the method was defined in, | ++| | or "None" if unavailable. | +++----------------------------------------------------+----------------------------------------------------+ ++ ++Methods also support accessing (but not setting) the arbitrary ++function attributes on the underlying function object. ++ ++User-defined method objects may be created when getting an attribute ++of a class (perhaps via an instance of that class), if that attribute ++is a user-defined function object or a "classmethod" object. ++ ++When an instance method object is created by retrieving a user-defined ++function object from a class via one of its instances, its "__self__" ++attribute is the instance, and the method object is said to be ++*bound*. The new method’s "__func__" attribute is the original ++function object. ++ ++When an instance method object is created by retrieving a ++"classmethod" object from a class or instance, its "__self__" ++attribute is the class itself, and its "__func__" attribute is the ++function object underlying the class method. ++ ++When an instance method object is called, the underlying function ++("__func__") is called, inserting the class instance ("__self__") in ++front of the argument list. For instance, when "C" is a class which ++contains a definition for a function "f()", and "x" is an instance of ++"C", calling "x.f(1)" is equivalent to calling "C.f(x, 1)". ++ ++When an instance method object is derived from a "classmethod" object, ++the “class instance†stored in "__self__" will actually be the class ++itself, so that calling either "x.f(1)" or "C.f(1)" is equivalent to ++calling "f(C,1)" where "f" is the underlying function. ++ ++It is important to note that user-defined functions which are ++attributes of a class instance are not converted to bound methods; ++this *only* happens when the function is an attribute of the class. ++ ++ ++Generator functions ++------------------- ++ ++A function or method which uses the "yield" statement (see section The ++yield statement) is called a *generator function*. Such a function, ++when called, always returns an *iterator* object which can be used to ++execute the body of the function: calling the iterator’s ++"iterator.__next__()" method will cause the function to execute until ++it provides a value using the "yield" statement. When the function ++executes a "return" statement or falls off the end, a "StopIteration" ++exception is raised and the iterator will have reached the end of the ++set of values to be returned. ++ ++ ++Coroutine functions ++------------------- ++ ++A function or method which is defined using "async def" is called a ++*coroutine function*. Such a function, when called, returns a ++*coroutine* object. It may contain "await" expressions, as well as ++"async with" and "async for" statements. See also the Coroutine ++Objects section. ++ ++ ++Asynchronous generator functions ++-------------------------------- ++ ++A function or method which is defined using "async def" and which uses ++the "yield" statement is called a *asynchronous generator function*. ++Such a function, when called, returns an *asynchronous iterator* ++object which can be used in an "async for" statement to execute the ++body of the function. ++ ++Calling the asynchronous iterator’s "aiterator.__anext__" method will ++return an *awaitable* which when awaited will execute until it ++provides a value using the "yield" expression. When the function ++executes an empty "return" statement or falls off the end, a ++"StopAsyncIteration" exception is raised and the asynchronous iterator ++will have reached the end of the set of values to be yielded. ++ ++ ++Built-in functions ++------------------ ++ ++A built-in function object is a wrapper around a C function. Examples ++of built-in functions are "len()" and "math.sin()" ("math" is a ++standard built-in module). The number and type of the arguments are ++determined by the C function. Special read-only attributes: ++ ++* "__doc__" is the function’s documentation string, or "None" if ++ unavailable. See "function.__doc__". ++ ++* "__name__" is the function’s name. See "function.__name__". ++ ++* "__self__" is set to "None" (but see the next item). ++ ++* "__module__" is the name of the module the function was defined in ++ or "None" if unavailable. See "function.__module__". ++ ++ ++Built-in methods ++---------------- ++ ++This is really a different disguise of a built-in function, this time ++containing an object passed to the C function as an implicit extra ++argument. An example of a built-in method is "alist.append()", ++assuming *alist* is a list object. In this case, the special read-only ++attribute "__self__" is set to the object denoted by *alist*. (The ++attribute has the same semantics as it does with "other instance ++methods".) ++ ++ ++Classes ++------- ++ ++Classes are callable. These objects normally act as factories for new ++instances of themselves, but variations are possible for class types ++that override "__new__()". The arguments of the call are passed to ++"__new__()" and, in the typical case, to "__init__()" to initialize ++the new instance. ++ ++ ++Class Instances ++--------------- ++ ++Instances of arbitrary classes can be made callable by defining a ++"__call__()" method in their class. ++ ++ ++Modules ++======= ++ ++Modules are a basic organizational unit of Python code, and are ++created by the import system as invoked either by the "import" ++statement, or by calling functions such as "importlib.import_module()" ++and built-in "__import__()". A module object has a namespace ++implemented by a "dictionary" object (this is the dictionary ++referenced by the "__globals__" attribute of functions defined in the ++module). Attribute references are translated to lookups in this ++dictionary, e.g., "m.x" is equivalent to "m.__dict__["x"]". A module ++object does not contain the code object used to initialize the module ++(since it isn’t needed once the initialization is done). ++ ++Attribute assignment updates the module’s namespace dictionary, e.g., ++"m.x = 1" is equivalent to "m.__dict__["x"] = 1". ++ ++ ++Import-related attributes on module objects ++------------------------------------------- ++ ++Module objects have the following attributes that relate to the import ++system. When a module is created using the machinery associated with ++the import system, these attributes are filled in based on the ++module’s *spec*, before the *loader* executes and loads the module. ++ ++To create a module dynamically rather than using the import system, ++it’s recommended to use "importlib.util.module_from_spec()", which ++will set the various import-controlled attributes to appropriate ++values. It’s also possible to use the "types.ModuleType" constructor ++to create modules directly, but this technique is more error-prone, as ++most attributes must be manually set on the module object after it has ++been created when using this approach. ++ ++Caution: ++ ++ With the exception of "__name__", it is **strongly** recommended ++ that you rely on "__spec__" and its attributes instead of any of the ++ other individual attributes listed in this subsection. Note that ++ updating an attribute on "__spec__" will not update the ++ corresponding attribute on the module itself: ++ ++ >>> import typing ++ >>> typing.__name__, typing.__spec__.name ++ ('typing', 'typing') ++ >>> typing.__spec__.name = 'spelling' ++ >>> typing.__name__, typing.__spec__.name ++ ('typing', 'spelling') ++ >>> typing.__name__ = 'keyboard_smashing' ++ >>> typing.__name__, typing.__spec__.name ++ ('keyboard_smashing', 'spelling') ++ ++module.__name__ ++ ++ The name used to uniquely identify the module in the import system. ++ For a directly executed module, this will be set to ""__main__"". ++ ++ This attribute must be set to the fully qualified name of the ++ module. It is expected to match the value of ++ "module.__spec__.name". ++ ++module.__spec__ ++ ++ A record of the module’s import-system-related state. ++ ++ Set to the "module spec" that was used when importing the module. ++ See Module specs for more details. ++ ++ Added in version 3.4. ++ ++module.__package__ ++ ++ The *package* a module belongs to. ++ ++ If the module is top-level (that is, not a part of any specific ++ package) then the attribute should be set to "''" (the empty ++ string). Otherwise, it should be set to the name of the module’s ++ package (which can be equal to "module.__name__" if the module ++ itself is a package). See **PEP 366** for further details. ++ ++ This attribute is used instead of "__name__" to calculate explicit ++ relative imports for main modules. It defaults to "None" for ++ modules created dynamically using the "types.ModuleType" ++ constructor; use "importlib.util.module_from_spec()" instead to ++ ensure the attribute is set to a "str". ++ ++ It is **strongly** recommended that you use ++ "module.__spec__.parent" instead of "module.__package__". ++ "__package__" is now only used as a fallback if "__spec__.parent" ++ is not set, and this fallback path is deprecated. ++ ++ Changed in version 3.4: This attribute now defaults to "None" for ++ modules created dynamically using the "types.ModuleType" ++ constructor. Previously the attribute was optional. ++ ++ Changed in version 3.6: The value of "__package__" is expected to ++ be the same as "__spec__.parent". "__package__" is now only used as ++ a fallback during import resolution if "__spec__.parent" is not ++ defined. ++ ++ Changed in version 3.10: "ImportWarning" is raised if an import ++ resolution falls back to "__package__" instead of ++ "__spec__.parent". ++ ++ Changed in version 3.12: Raise "DeprecationWarning" instead of ++ "ImportWarning" when falling back to "__package__" during import ++ resolution. ++ ++ Deprecated since version 3.13, will be removed in version 3.15: ++ "__package__" will cease to be set or taken into consideration by ++ the import system or standard library. ++ ++module.__loader__ ++ ++ The *loader* object that the import machinery used to load the ++ module. ++ ++ This attribute is mostly useful for introspection, but can be used ++ for additional loader-specific functionality, for example getting ++ data associated with a loader. ++ ++ "__loader__" defaults to "None" for modules created dynamically ++ using the "types.ModuleType" constructor; use ++ "importlib.util.module_from_spec()" instead to ensure the attribute ++ is set to a *loader* object. ++ ++ It is **strongly** recommended that you use ++ "module.__spec__.loader" instead of "module.__loader__". ++ ++ Changed in version 3.4: This attribute now defaults to "None" for ++ modules created dynamically using the "types.ModuleType" ++ constructor. Previously the attribute was optional. ++ ++ Deprecated since version 3.12, will be removed in version 3.16: ++ Setting "__loader__" on a module while failing to set ++ "__spec__.loader" is deprecated. In Python 3.16, "__loader__" will ++ cease to be set or taken into consideration by the import system or ++ the standard library. ++ ++module.__path__ ++ ++ A (possibly empty) *sequence* of strings enumerating the locations ++ where the package’s submodules will be found. Non-package modules ++ should not have a "__path__" attribute. See __path__ attributes on ++ modules for more details. ++ ++ It is **strongly** recommended that you use ++ "module.__spec__.submodule_search_locations" instead of ++ "module.__path__". ++ ++module.__file__ ++ ++module.__cached__ ++ ++ "__file__" and "__cached__" are both optional attributes that may ++ or may not be set. Both attributes should be a "str" when they are ++ available. ++ ++ "__file__" indicates the pathname of the file from which the module ++ was loaded (if loaded from a file), or the pathname of the shared ++ library file for extension modules loaded dynamically from a shared ++ library. It might be missing for certain types of modules, such as ++ C modules that are statically linked into the interpreter, and the ++ import system may opt to leave it unset if it has no semantic ++ meaning (for example, a module loaded from a database). ++ ++ If "__file__" is set then the "__cached__" attribute might also be ++ set, which is the path to any compiled version of the code (for ++ example, a byte-compiled file). The file does not need to exist to ++ set this attribute; the path can simply point to where the compiled ++ file *would* exist (see **PEP 3147**). ++ ++ Note that "__cached__" may be set even if "__file__" is not set. ++ However, that scenario is quite atypical. Ultimately, the *loader* ++ is what makes use of the module spec provided by the *finder* (from ++ which "__file__" and "__cached__" are derived). So if a loader can ++ load from a cached module but otherwise does not load from a file, ++ that atypical scenario may be appropriate. ++ ++ It is **strongly** recommended that you use ++ "module.__spec__.cached" instead of "module.__cached__". ++ ++ Deprecated since version 3.13, will be removed in version 3.15: ++ Setting "__cached__" on a module while failing to set ++ "__spec__.cached" is deprecated. In Python 3.15, "__cached__" will ++ cease to be set or taken into consideration by the import system or ++ standard library. ++ ++ ++Other writable attributes on module objects ++------------------------------------------- ++ ++As well as the import-related attributes listed above, module objects ++also have the following writable attributes: ++ ++module.__doc__ ++ ++ The module’s documentation string, or "None" if unavailable. See ++ also: "__doc__ attributes". ++ ++module.__annotations__ ++ ++ A dictionary containing *variable annotations* collected during ++ module body execution. For best practices on working with ++ "__annotations__", see "annotationlib". ++ ++ Changed in version 3.14: Annotations are now lazily evaluated. See ++ **PEP 649**. ++ ++module.__annotate__ ++ ++ The *annotate function* for this module, or "None" if the module ++ has no annotations. See also: "__annotate__" attributes. ++ ++ Added in version 3.14. ++ ++ ++Module dictionaries ++------------------- ++ ++Module objects also have the following special read-only attribute: ++ ++module.__dict__ ++ ++ The module’s namespace as a dictionary object. Uniquely among the ++ attributes listed here, "__dict__" cannot be accessed as a global ++ variable from within a module; it can only be accessed as an ++ attribute on module objects. ++ ++ **CPython implementation detail:** Because of the way CPython ++ clears module dictionaries, the module dictionary will be cleared ++ when the module falls out of scope even if the dictionary still has ++ live references. To avoid this, copy the dictionary or keep the ++ module around while using its dictionary directly. ++ ++ ++Custom classes ++============== ++ ++Custom class types are typically created by class definitions (see ++section Class definitions). A class has a namespace implemented by a ++dictionary object. Class attribute references are translated to ++lookups in this dictionary, e.g., "C.x" is translated to ++"C.__dict__["x"]" (although there are a number of hooks which allow ++for other means of locating attributes). When the attribute name is ++not found there, the attribute search continues in the base classes. ++This search of the base classes uses the C3 method resolution order ++which behaves correctly even in the presence of ‘diamond’ inheritance ++structures where there are multiple inheritance paths leading back to ++a common ancestor. Additional details on the C3 MRO used by Python can ++be found at The Python 2.3 Method Resolution Order. ++ ++When a class attribute reference (for class "C", say) would yield a ++class method object, it is transformed into an instance method object ++whose "__self__" attribute is "C". When it would yield a ++"staticmethod" object, it is transformed into the object wrapped by ++the static method object. See section Implementing Descriptors for ++another way in which attributes retrieved from a class may differ from ++those actually contained in its "__dict__". ++ ++Class attribute assignments update the class’s dictionary, never the ++dictionary of a base class. ++ ++A class object can be called (see above) to yield a class instance ++(see below). ++ ++ ++Special attributes ++------------------ ++ +++----------------------------------------------------+----------------------------------------------------+ ++| Attribute | Meaning | ++|====================================================|====================================================| ++| type.__name__ | The class’s name. See also: "__name__ attributes". | +++----------------------------------------------------+----------------------------------------------------+ ++| type.__qualname__ | The class’s *qualified name*. See also: | ++| | "__qualname__ attributes". | +++----------------------------------------------------+----------------------------------------------------+ ++| type.__module__ | The name of the module in which the class was | ++| | defined. | +++----------------------------------------------------+----------------------------------------------------+ ++| type.__dict__ | A "mapping proxy" providing a read-only view of | ++| | the class’s namespace. See also: "__dict__ | ++| | attributes". | +++----------------------------------------------------+----------------------------------------------------+ ++| type.__bases__ | A "tuple" containing the class’s bases. In most | ++| | cases, for a class defined as "class X(A, B, C)", | ++| | "X.__bases__" will be exactly equal to "(A, B, | ++| | C)". | +++----------------------------------------------------+----------------------------------------------------+ ++| type.__doc__ | The class’s documentation string, or "None" if | ++| | undefined. Not inherited by subclasses. | +++----------------------------------------------------+----------------------------------------------------+ ++| type.__annotations__ | A dictionary containing *variable annotations* | ++| | collected during class body execution. See also: | ++| | "__annotations__ attributes". For best practices | ++| | on working with "__annotations__", please see | ++| | "annotationlib". Caution: Accessing the | ++| | "__annotations__" attribute of a class object | ++| | directly may yield incorrect results in the | ++| | presence of metaclasses. In addition, the | ++| | attribute may not exist for some classes. Use | ++| | "annotationlib.get_annotations()" to retrieve | ++| | class annotations safely. Changed in version | ++| | 3.14: Annotations are now lazily evaluated. See | ++| | **PEP 649**. | +++----------------------------------------------------+----------------------------------------------------+ ++| type.__annotate__() | The *annotate function* for this class, or "None" | ++| | if the class has no annotations. See also: | ++| | "__annotate__ attributes". Caution: Accessing | ++| | the "__annotate__" attribute of a class object | ++| | directly may yield incorrect results in the | ++| | presence of metaclasses. Use | ++| | "annotationlib.get_annotate_function()" to | ++| | retrieve the annotate function safely. Added in | ++| | version 3.14. | +++----------------------------------------------------+----------------------------------------------------+ ++| type.__type_params__ | A "tuple" containing the type parameters of a | ++| | generic class. Added in version 3.12. | +++----------------------------------------------------+----------------------------------------------------+ ++| type.__static_attributes__ | A "tuple" containing names of attributes of this | ++| | class which are assigned through "self.X" from any | ++| | function in its body. Added in version 3.13. | +++----------------------------------------------------+----------------------------------------------------+ ++| type.__firstlineno__ | The line number of the first line of the class | ++| | definition, including decorators. Setting the | ++| | "__module__" attribute removes the | ++| | "__firstlineno__" item from the type’s dictionary. | ++| | Added in version 3.13. | +++----------------------------------------------------+----------------------------------------------------+ ++| type.__mro__ | The "tuple" of classes that are considered when | ++| | looking for base classes during method resolution. | +++----------------------------------------------------+----------------------------------------------------+ ++ ++ ++Special methods ++--------------- ++ ++In addition to the special attributes described above, all Python ++classes also have the following two methods available: ++ ++type.mro() ++ ++ This method can be overridden by a metaclass to customize the ++ method resolution order for its instances. It is called at class ++ instantiation, and its result is stored in "__mro__". ++ ++type.__subclasses__() ++ ++ Each class keeps a list of weak references to its immediate ++ subclasses. This method returns a list of all those references ++ still alive. The list is in definition order. Example: ++ ++ >>> class A: pass ++ >>> class B(A): pass ++ >>> A.__subclasses__() ++ [] ++ ++ ++Class instances ++=============== ++ ++A class instance is created by calling a class object (see above). A ++class instance has a namespace implemented as a dictionary which is ++the first place in which attribute references are searched. When an ++attribute is not found there, and the instance’s class has an ++attribute by that name, the search continues with the class ++attributes. If a class attribute is found that is a user-defined ++function object, it is transformed into an instance method object ++whose "__self__" attribute is the instance. Static method and class ++method objects are also transformed; see above under “Classesâ€. See ++section Implementing Descriptors for another way in which attributes ++of a class retrieved via its instances may differ from the objects ++actually stored in the class’s "__dict__". If no class attribute is ++found, and the object’s class has a "__getattr__()" method, that is ++called to satisfy the lookup. ++ ++Attribute assignments and deletions update the instance’s dictionary, ++never a class’s dictionary. If the class has a "__setattr__()" or ++"__delattr__()" method, this is called instead of updating the ++instance dictionary directly. ++ ++Class instances can pretend to be numbers, sequences, or mappings if ++they have methods with certain special names. See section Special ++method names. ++ ++ ++Special attributes ++------------------ ++ ++object.__class__ ++ ++ The class to which a class instance belongs. ++ ++object.__dict__ ++ ++ A dictionary or other mapping object used to store an object’s ++ (writable) attributes. Not all instances have a "__dict__" ++ attribute; see the section on __slots__ for more details. ++ ++ ++I/O objects (also known as file objects) ++======================================== ++ ++A *file object* represents an open file. Various shortcuts are ++available to create file objects: the "open()" built-in function, and ++also "os.popen()", "os.fdopen()", and the "makefile()" method of ++socket objects (and perhaps by other functions or methods provided by ++extension modules). ++ ++The objects "sys.stdin", "sys.stdout" and "sys.stderr" are initialized ++to file objects corresponding to the interpreter’s standard input, ++output and error streams; they are all open in text mode and therefore ++follow the interface defined by the "io.TextIOBase" abstract class. ++ ++ ++Internal types ++============== ++ ++A few types used internally by the interpreter are exposed to the ++user. Their definitions may change with future versions of the ++interpreter, but they are mentioned here for completeness. ++ ++ ++Code objects ++------------ ++ ++Code objects represent *byte-compiled* executable Python code, or ++*bytecode*. The difference between a code object and a function object ++is that the function object contains an explicit reference to the ++function’s globals (the module in which it was defined), while a code ++object contains no context; also the default argument values are ++stored in the function object, not in the code object (because they ++represent values calculated at run-time). Unlike function objects, ++code objects are immutable and contain no references (directly or ++indirectly) to mutable objects. ++ ++ ++Special read-only attributes ++~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ +++----------------------------------------------------+----------------------------------------------------+ ++| codeobject.co_name | The function name | +++----------------------------------------------------+----------------------------------------------------+ ++| codeobject.co_qualname | The fully qualified function name Added in | ++| | version 3.11. | +++----------------------------------------------------+----------------------------------------------------+ ++| codeobject.co_argcount | The total number of positional *parameters* | ++| | (including positional-only parameters and | ++| | parameters with default values) that the function | ++| | has | +++----------------------------------------------------+----------------------------------------------------+ ++| codeobject.co_posonlyargcount | The number of positional-only *parameters* | ++| | (including arguments with default values) that the | ++| | function has | +++----------------------------------------------------+----------------------------------------------------+ ++| codeobject.co_kwonlyargcount | The number of keyword-only *parameters* (including | ++| | arguments with default values) that the function | ++| | has | +++----------------------------------------------------+----------------------------------------------------+ ++| codeobject.co_nlocals | The number of local variables used by the function | ++| | (including parameters) | +++----------------------------------------------------+----------------------------------------------------+ ++| codeobject.co_varnames | A "tuple" containing the names of the local | ++| | variables in the function (starting with the | ++| | parameter names) | +++----------------------------------------------------+----------------------------------------------------+ ++| codeobject.co_cellvars | A "tuple" containing the names of local variables | ++| | that are referenced from at least one *nested | ++| | scope* inside the function | +++----------------------------------------------------+----------------------------------------------------+ ++| codeobject.co_freevars | A "tuple" containing the names of *free (closure) | ++| | variables* that a *nested scope* references in an | ++| | outer scope. See also "function.__closure__". | ++| | Note: references to global and builtin names are | ++| | *not* included. | +++----------------------------------------------------+----------------------------------------------------+ ++| codeobject.co_code | A string representing the sequence of *bytecode* | ++| | instructions in the function | +++----------------------------------------------------+----------------------------------------------------+ ++| codeobject.co_consts | A "tuple" containing the literals used by the | ++| | *bytecode* in the function | +++----------------------------------------------------+----------------------------------------------------+ ++| codeobject.co_names | A "tuple" containing the names used by the | ++| | *bytecode* in the function | +++----------------------------------------------------+----------------------------------------------------+ ++| codeobject.co_filename | The name of the file from which the code was | ++| | compiled | +++----------------------------------------------------+----------------------------------------------------+ ++| codeobject.co_firstlineno | The line number of the first line of the function | +++----------------------------------------------------+----------------------------------------------------+ ++| codeobject.co_lnotab | A string encoding the mapping from *bytecode* | ++| | offsets to line numbers. For details, see the | ++| | source code of the interpreter. Deprecated since | ++| | version 3.12: This attribute of code objects is | ++| | deprecated, and may be removed in Python 3.15. | +++----------------------------------------------------+----------------------------------------------------+ ++| codeobject.co_stacksize | The required stack size of the code object | +++----------------------------------------------------+----------------------------------------------------+ ++| codeobject.co_flags | An "integer" encoding a number of flags for the | ++| | interpreter. | +++----------------------------------------------------+----------------------------------------------------+ ++ ++The following flag bits are defined for "co_flags": bit "0x04" is set ++if the function uses the "*arguments" syntax to accept an arbitrary ++number of positional arguments; bit "0x08" is set if the function uses ++the "**keywords" syntax to accept arbitrary keyword arguments; bit ++"0x20" is set if the function is a generator. See Code Objects Bit ++Flags for details on the semantics of each flags that might be ++present. ++ ++Future feature declarations ("from __future__ import division") also ++use bits in "co_flags" to indicate whether a code object was compiled ++with a particular feature enabled: bit "0x2000" is set if the function ++was compiled with future division enabled; bits "0x10" and "0x1000" ++were used in earlier versions of Python. ++ ++Other bits in "co_flags" are reserved for internal use. ++ ++If a code object represents a function and has a docstring, the first ++item in "co_consts" is the docstring of the function. ++ ++ ++Methods on code objects ++~~~~~~~~~~~~~~~~~~~~~~~ ++ ++codeobject.co_positions() ++ ++ Returns an iterable over the source code positions of each ++ *bytecode* instruction in the code object. ++ ++ The iterator returns "tuple"s containing the "(start_line, ++ end_line, start_column, end_column)". The *i-th* tuple corresponds ++ to the position of the source code that compiled to the *i-th* code ++ unit. Column information is 0-indexed utf-8 byte offsets on the ++ given source line. ++ ++ This positional information can be missing. A non-exhaustive lists ++ of cases where this may happen: ++ ++ * Running the interpreter with "-X" "no_debug_ranges". ++ ++ * Loading a pyc file compiled while using "-X" "no_debug_ranges". ++ ++ * Position tuples corresponding to artificial instructions. ++ ++ * Line and column numbers that can’t be represented due to ++ implementation specific limitations. ++ ++ When this occurs, some or all of the tuple elements can be "None". ++ ++ Added in version 3.11. ++ ++ Note: ++ ++ This feature requires storing column positions in code objects ++ which may result in a small increase of disk usage of compiled ++ Python files or interpreter memory usage. To avoid storing the ++ extra information and/or deactivate printing the extra traceback ++ information, the "-X" "no_debug_ranges" command line flag or the ++ "PYTHONNODEBUGRANGES" environment variable can be used. ++ ++codeobject.co_lines() ++ ++ Returns an iterator that yields information about successive ranges ++ of *bytecode*s. Each item yielded is a "(start, end, lineno)" ++ "tuple": ++ ++ * "start" (an "int") represents the offset (inclusive) of the start ++ of the *bytecode* range ++ ++ * "end" (an "int") represents the offset (exclusive) of the end of ++ the *bytecode* range ++ ++ * "lineno" is an "int" representing the line number of the ++ *bytecode* range, or "None" if the bytecodes in the given range ++ have no line number ++ ++ The items yielded will have the following properties: ++ ++ * The first range yielded will have a "start" of 0. ++ ++ * The "(start, end)" ranges will be non-decreasing and consecutive. ++ That is, for any pair of "tuple"s, the "start" of the second will ++ be equal to the "end" of the first. ++ ++ * No range will be backwards: "end >= start" for all triples. ++ ++ * The last "tuple" yielded will have "end" equal to the size of the ++ *bytecode*. ++ ++ Zero-width ranges, where "start == end", are allowed. Zero-width ++ ranges are used for lines that are present in the source code, but ++ have been eliminated by the *bytecode* compiler. ++ ++ Added in version 3.10. ++ ++ See also: ++ ++ **PEP 626** - Precise line numbers for debugging and other tools. ++ The PEP that introduced the "co_lines()" method. ++ ++codeobject.replace(**kwargs) ++ ++ Return a copy of the code object with new values for the specified ++ fields. ++ ++ Code objects are also supported by the generic function ++ "copy.replace()". ++ ++ Added in version 3.8. ++ ++ ++Frame objects ++------------- ++ ++Frame objects represent execution frames. They may occur in traceback ++objects, and are also passed to registered trace functions. ++ ++ ++Special read-only attributes ++~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ +++----------------------------------------------------+----------------------------------------------------+ ++| frame.f_back | Points to the previous stack frame (towards the | ++| | caller), or "None" if this is the bottom stack | ++| | frame | +++----------------------------------------------------+----------------------------------------------------+ ++| frame.f_code | The code object being executed in this frame. | ++| | Accessing this attribute raises an auditing event | ++| | "object.__getattr__" with arguments "obj" and | ++| | ""f_code"". | +++----------------------------------------------------+----------------------------------------------------+ ++| frame.f_locals | The mapping used by the frame to look up local | ++| | variables. If the frame refers to an *optimized | ++| | scope*, this may return a write-through proxy | ++| | object. Changed in version 3.13: Return a proxy | ++| | for optimized scopes. | +++----------------------------------------------------+----------------------------------------------------+ ++| frame.f_globals | The dictionary used by the frame to look up global | ++| | variables | +++----------------------------------------------------+----------------------------------------------------+ ++| frame.f_builtins | The dictionary used by the frame to look up built- | ++| | in (intrinsic) names | +++----------------------------------------------------+----------------------------------------------------+ ++| frame.f_lasti | The “precise instruction†of the frame object | ++| | (this is an index into the *bytecode* string of | ++| | the code object) | +++----------------------------------------------------+----------------------------------------------------+ ++ ++ ++Special writable attributes ++~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ +++----------------------------------------------------+----------------------------------------------------+ ++| frame.f_trace | If not "None", this is a function called for | ++| | various events during code execution (this is used | ++| | by debuggers). Normally an event is triggered for | ++| | each new source line (see "f_trace_lines"). | +++----------------------------------------------------+----------------------------------------------------+ ++| frame.f_trace_lines | Set this attribute to "False" to disable | ++| | triggering a tracing event for each source line. | +++----------------------------------------------------+----------------------------------------------------+ ++| frame.f_trace_opcodes | Set this attribute to "True" to allow per-opcode | ++| | events to be requested. Note that this may lead to | ++| | undefined interpreter behaviour if exceptions | ++| | raised by the trace function escape to the | ++| | function being traced. | +++----------------------------------------------------+----------------------------------------------------+ ++| frame.f_lineno | The current line number of the frame – writing to | ++| | this from within a trace function jumps to the | ++| | given line (only for the bottom-most frame). A | ++| | debugger can implement a Jump command (aka Set | ++| | Next Statement) by writing to this attribute. | +++----------------------------------------------------+----------------------------------------------------+ ++ ++ ++Frame object methods ++~~~~~~~~~~~~~~~~~~~~ ++ ++Frame objects support one method: ++ ++frame.clear() ++ ++ This method clears all references to local variables held by the ++ frame. Also, if the frame belonged to a *generator*, the generator ++ is finalized. This helps break reference cycles involving frame ++ objects (for example when catching an exception and storing its ++ traceback for later use). ++ ++ "RuntimeError" is raised if the frame is currently executing or ++ suspended. ++ ++ Added in version 3.4. ++ ++ Changed in version 3.13: Attempting to clear a suspended frame ++ raises "RuntimeError" (as has always been the case for executing ++ frames). ++ ++ ++Traceback objects ++----------------- ++ ++Traceback objects represent the stack trace of an exception. A ++traceback object is implicitly created when an exception occurs, and ++may also be explicitly created by calling "types.TracebackType". ++ ++Changed in version 3.7: Traceback objects can now be explicitly ++instantiated from Python code. ++ ++For implicitly created tracebacks, when the search for an exception ++handler unwinds the execution stack, at each unwound level a traceback ++object is inserted in front of the current traceback. When an ++exception handler is entered, the stack trace is made available to the ++program. (See section The try statement.) It is accessible as the ++third item of the tuple returned by "sys.exc_info()", and as the ++"__traceback__" attribute of the caught exception. ++ ++When the program contains no suitable handler, the stack trace is ++written (nicely formatted) to the standard error stream; if the ++interpreter is interactive, it is also made available to the user as ++"sys.last_traceback". ++ ++For explicitly created tracebacks, it is up to the creator of the ++traceback to determine how the "tb_next" attributes should be linked ++to form a full stack trace. ++ ++Special read-only attributes: ++ +++----------------------------------------------------+----------------------------------------------------+ ++| traceback.tb_frame | Points to the execution frame of the current | ++| | level. Accessing this attribute raises an | ++| | auditing event "object.__getattr__" with arguments | ++| | "obj" and ""tb_frame"". | +++----------------------------------------------------+----------------------------------------------------+ ++| traceback.tb_lineno | Gives the line number where the exception occurred | +++----------------------------------------------------+----------------------------------------------------+ ++| traceback.tb_lasti | Indicates the “precise instructionâ€. | +++----------------------------------------------------+----------------------------------------------------+ ++ ++The line number and last instruction in the traceback may differ from ++the line number of its frame object if the exception occurred in a ++"try" statement with no matching except clause or with a "finally" ++clause. ++ ++traceback.tb_next ++ ++ The special writable attribute "tb_next" is the next level in the ++ stack trace (towards the frame where the exception occurred), or ++ "None" if there is no next level. ++ ++ Changed in version 3.7: This attribute is now writable ++ ++ ++Slice objects ++------------- ++ ++Slice objects are used to represent slices for "__getitem__()" ++methods. They are also created by the built-in "slice()" function. ++ ++Special read-only attributes: "start" is the lower bound; "stop" is ++the upper bound; "step" is the step value; each is "None" if omitted. ++These attributes can have any type. ++ ++Slice objects support one method: ++ ++slice.indices(self, length) ++ ++ This method takes a single integer argument *length* and computes ++ information about the slice that the slice object would describe if ++ applied to a sequence of *length* items. It returns a tuple of ++ three integers; respectively these are the *start* and *stop* ++ indices and the *step* or stride length of the slice. Missing or ++ out-of-bounds indices are handled in a manner consistent with ++ regular slices. ++ ++ ++Static method objects ++--------------------- ++ ++Static method objects provide a way of defeating the transformation of ++function objects to method objects described above. A static method ++object is a wrapper around any other object, usually a user-defined ++method object. When a static method object is retrieved from a class ++or a class instance, the object actually returned is the wrapped ++object, which is not subject to any further transformation. Static ++method objects are also callable. Static method objects are created by ++the built-in "staticmethod()" constructor. ++ ++ ++Class method objects ++-------------------- ++ ++A class method object, like a static method object, is a wrapper ++around another object that alters the way in which that object is ++retrieved from classes and class instances. The behaviour of class ++method objects upon such retrieval is described above, under “instance ++methodsâ€. Class method objects are created by the built-in ++"classmethod()" constructor. ++''', ++ 'typesfunctions': r'''Functions ++********* ++ ++Function objects are created by function definitions. The only ++operation on a function object is to call it: "func(argument-list)". ++ ++There are really two flavors of function objects: built-in functions ++and user-defined functions. Both support the same operation (to call ++the function), but the implementation is different, hence the ++different object types. ++ ++See Function definitions for more information. ++''', ++ 'typesmapping': r'''Mapping Types — "dict" ++********************** ++ ++A *mapping* object maps *hashable* values to arbitrary objects. ++Mappings are mutable objects. There is currently only one standard ++mapping type, the *dictionary*. (For other containers see the built- ++in "list", "set", and "tuple" classes, and the "collections" module.) ++ ++A dictionary’s keys are *almost* arbitrary values. Values that are ++not *hashable*, that is, values containing lists, dictionaries or ++other mutable types (that are compared by value rather than by object ++identity) may not be used as keys. Values that compare equal (such as ++"1", "1.0", and "True") can be used interchangeably to index the same ++dictionary entry. ++ ++class dict(**kwargs) ++class dict(mapping, **kwargs) ++class dict(iterable, **kwargs) ++ ++ Return a new dictionary initialized from an optional positional ++ argument and a possibly empty set of keyword arguments. ++ ++ Dictionaries can be created by several means: ++ ++ * Use a comma-separated list of "key: value" pairs within braces: ++ "{'jack': 4098, 'sjoerd': 4127}" or "{4098: 'jack', 4127: ++ 'sjoerd'}" ++ ++ * Use a dict comprehension: "{}", "{x: x ** 2 for x in range(10)}" ++ ++ * Use the type constructor: "dict()", "dict([('foo', 100), ('bar', ++ 200)])", "dict(foo=100, bar=200)" ++ ++ If no positional argument is given, an empty dictionary is created. ++ If a positional argument is given and it defines a "keys()" method, ++ a dictionary is created by calling "__getitem__()" on the argument ++ with each returned key from the method. Otherwise, the positional ++ argument must be an *iterable* object. Each item in the iterable ++ must itself be an iterable with exactly two elements. The first ++ element of each item becomes a key in the new dictionary, and the ++ second element the corresponding value. If a key occurs more than ++ once, the last value for that key becomes the corresponding value ++ in the new dictionary. ++ ++ If keyword arguments are given, the keyword arguments and their ++ values are added to the dictionary created from the positional ++ argument. If a key being added is already present, the value from ++ the keyword argument replaces the value from the positional ++ argument. ++ ++ To illustrate, the following examples all return a dictionary equal ++ to "{"one": 1, "two": 2, "three": 3}": ++ ++ >>> a = dict(one=1, two=2, three=3) ++ >>> b = {'one': 1, 'two': 2, 'three': 3} ++ >>> c = dict(zip(['one', 'two', 'three'], [1, 2, 3])) ++ >>> d = dict([('two', 2), ('one', 1), ('three', 3)]) ++ >>> e = dict({'three': 3, 'one': 1, 'two': 2}) ++ >>> f = dict({'one': 1, 'three': 3}, two=2) ++ >>> a == b == c == d == e == f ++ True ++ ++ Providing keyword arguments as in the first example only works for ++ keys that are valid Python identifiers. Otherwise, any valid keys ++ can be used. ++ ++ These are the operations that dictionaries support (and therefore, ++ custom mapping types should support too): ++ ++ list(d) ++ ++ Return a list of all the keys used in the dictionary *d*. ++ ++ len(d) ++ ++ Return the number of items in the dictionary *d*. ++ ++ d[key] ++ ++ Return the item of *d* with key *key*. Raises a "KeyError" if ++ *key* is not in the map. ++ ++ If a subclass of dict defines a method "__missing__()" and *key* ++ is not present, the "d[key]" operation calls that method with ++ the key *key* as argument. The "d[key]" operation then returns ++ or raises whatever is returned or raised by the ++ "__missing__(key)" call. No other operations or methods invoke ++ "__missing__()". If "__missing__()" is not defined, "KeyError" ++ is raised. "__missing__()" must be a method; it cannot be an ++ instance variable: ++ ++ >>> class Counter(dict): ++ ... def __missing__(self, key): ++ ... return 0 ++ ... ++ >>> c = Counter() ++ >>> c['red'] ++ 0 ++ >>> c['red'] += 1 ++ >>> c['red'] ++ 1 ++ ++ The example above shows part of the implementation of ++ "collections.Counter". A different "__missing__" method is used ++ by "collections.defaultdict". ++ ++ d[key] = value ++ ++ Set "d[key]" to *value*. ++ ++ del d[key] ++ ++ Remove "d[key]" from *d*. Raises a "KeyError" if *key* is not ++ in the map. ++ ++ key in d ++ ++ Return "True" if *d* has a key *key*, else "False". ++ ++ key not in d ++ ++ Equivalent to "not key in d". ++ ++ iter(d) ++ ++ Return an iterator over the keys of the dictionary. This is a ++ shortcut for "iter(d.keys())". ++ ++ clear() ++ ++ Remove all items from the dictionary. ++ ++ copy() ++ ++ Return a shallow copy of the dictionary. ++ ++ classmethod fromkeys(iterable, value=None, /) ++ ++ Create a new dictionary with keys from *iterable* and values set ++ to *value*. ++ ++ "fromkeys()" is a class method that returns a new dictionary. ++ *value* defaults to "None". All of the values refer to just a ++ single instance, so it generally doesn’t make sense for *value* ++ to be a mutable object such as an empty list. To get distinct ++ values, use a dict comprehension instead. ++ ++ get(key, default=None) ++ ++ Return the value for *key* if *key* is in the dictionary, else ++ *default*. If *default* is not given, it defaults to "None", so ++ that this method never raises a "KeyError". ++ ++ items() ++ ++ Return a new view of the dictionary’s items ("(key, value)" ++ pairs). See the documentation of view objects. ++ ++ keys() ++ ++ Return a new view of the dictionary’s keys. See the ++ documentation of view objects. ++ ++ pop(key[, default]) ++ ++ If *key* is in the dictionary, remove it and return its value, ++ else return *default*. If *default* is not given and *key* is ++ not in the dictionary, a "KeyError" is raised. ++ ++ popitem() ++ ++ Remove and return a "(key, value)" pair from the dictionary. ++ Pairs are returned in LIFO (last-in, first-out) order. ++ ++ "popitem()" is useful to destructively iterate over a ++ dictionary, as often used in set algorithms. If the dictionary ++ is empty, calling "popitem()" raises a "KeyError". ++ ++ Changed in version 3.7: LIFO order is now guaranteed. In prior ++ versions, "popitem()" would return an arbitrary key/value pair. ++ ++ reversed(d) ++ ++ Return a reverse iterator over the keys of the dictionary. This ++ is a shortcut for "reversed(d.keys())". ++ ++ Added in version 3.8. ++ ++ setdefault(key, default=None) ++ ++ If *key* is in the dictionary, return its value. If not, insert ++ *key* with a value of *default* and return *default*. *default* ++ defaults to "None". ++ ++ update([other]) ++ ++ Update the dictionary with the key/value pairs from *other*, ++ overwriting existing keys. Return "None". ++ ++ "update()" accepts either another object with a "keys()" method ++ (in which case "__getitem__()" is called with every key returned ++ from the method) or an iterable of key/value pairs (as tuples or ++ other iterables of length two). If keyword arguments are ++ specified, the dictionary is then updated with those key/value ++ pairs: "d.update(red=1, blue=2)". ++ ++ values() ++ ++ Return a new view of the dictionary’s values. See the ++ documentation of view objects. ++ ++ An equality comparison between one "dict.values()" view and ++ another will always return "False". This also applies when ++ comparing "dict.values()" to itself: ++ ++ >>> d = {'a': 1} ++ >>> d.values() == d.values() ++ False ++ ++ d | other ++ ++ Create a new dictionary with the merged keys and values of *d* ++ and *other*, which must both be dictionaries. The values of ++ *other* take priority when *d* and *other* share keys. ++ ++ Added in version 3.9. ++ ++ d |= other ++ ++ Update the dictionary *d* with keys and values from *other*, ++ which may be either a *mapping* or an *iterable* of key/value ++ pairs. The values of *other* take priority when *d* and *other* ++ share keys. ++ ++ Added in version 3.9. ++ ++ Dictionaries compare equal if and only if they have the same "(key, ++ value)" pairs (regardless of ordering). Order comparisons (‘<’, ++ ‘<=’, ‘>=’, ‘>’) raise "TypeError". ++ ++ Dictionaries preserve insertion order. Note that updating a key ++ does not affect the order. Keys added after deletion are inserted ++ at the end. ++ ++ >>> d = {"one": 1, "two": 2, "three": 3, "four": 4} ++ >>> d ++ {'one': 1, 'two': 2, 'three': 3, 'four': 4} ++ >>> list(d) ++ ['one', 'two', 'three', 'four'] ++ >>> list(d.values()) ++ [1, 2, 3, 4] ++ >>> d["one"] = 42 ++ >>> d ++ {'one': 42, 'two': 2, 'three': 3, 'four': 4} ++ >>> del d["two"] ++ >>> d["two"] = None ++ >>> d ++ {'one': 42, 'three': 3, 'four': 4, 'two': None} ++ ++ Changed in version 3.7: Dictionary order is guaranteed to be ++ insertion order. This behavior was an implementation detail of ++ CPython from 3.6. ++ ++ Dictionaries and dictionary views are reversible. ++ ++ >>> d = {"one": 1, "two": 2, "three": 3, "four": 4} ++ >>> d ++ {'one': 1, 'two': 2, 'three': 3, 'four': 4} ++ >>> list(reversed(d)) ++ ['four', 'three', 'two', 'one'] ++ >>> list(reversed(d.values())) ++ [4, 3, 2, 1] ++ >>> list(reversed(d.items())) ++ [('four', 4), ('three', 3), ('two', 2), ('one', 1)] ++ ++ Changed in version 3.8: Dictionaries are now reversible. ++ ++See also: ++ ++ "types.MappingProxyType" can be used to create a read-only view of a ++ "dict". ++ ++ ++Dictionary view objects ++======================= ++ ++The objects returned by "dict.keys()", "dict.values()" and ++"dict.items()" are *view objects*. They provide a dynamic view on the ++dictionary’s entries, which means that when the dictionary changes, ++the view reflects these changes. ++ ++Dictionary views can be iterated over to yield their respective data, ++and support membership tests: ++ ++len(dictview) ++ ++ Return the number of entries in the dictionary. ++ ++iter(dictview) ++ ++ Return an iterator over the keys, values or items (represented as ++ tuples of "(key, value)") in the dictionary. ++ ++ Keys and values are iterated over in insertion order. This allows ++ the creation of "(value, key)" pairs using "zip()": "pairs = ++ zip(d.values(), d.keys())". Another way to create the same list is ++ "pairs = [(v, k) for (k, v) in d.items()]". ++ ++ Iterating views while adding or deleting entries in the dictionary ++ may raise a "RuntimeError" or fail to iterate over all entries. ++ ++ Changed in version 3.7: Dictionary order is guaranteed to be ++ insertion order. ++ ++x in dictview ++ ++ Return "True" if *x* is in the underlying dictionary’s keys, values ++ or items (in the latter case, *x* should be a "(key, value)" ++ tuple). ++ ++reversed(dictview) ++ ++ Return a reverse iterator over the keys, values or items of the ++ dictionary. The view will be iterated in reverse order of the ++ insertion. ++ ++ Changed in version 3.8: Dictionary views are now reversible. ++ ++dictview.mapping ++ ++ Return a "types.MappingProxyType" that wraps the original ++ dictionary to which the view refers. ++ ++ Added in version 3.10. ++ ++Keys views are set-like since their entries are unique and *hashable*. ++Items views also have set-like operations since the (key, value) pairs ++are unique and the keys are hashable. If all values in an items view ++are hashable as well, then the items view can interoperate with other ++sets. (Values views are not treated as set-like since the entries are ++generally not unique.) For set-like views, all of the operations ++defined for the abstract base class "collections.abc.Set" are ++available (for example, "==", "<", or "^"). While using set ++operators, set-like views accept any iterable as the other operand, ++unlike sets which only accept sets as the input. ++ ++An example of dictionary view usage: ++ ++ >>> dishes = {'eggs': 2, 'sausage': 1, 'bacon': 1, 'spam': 500} ++ >>> keys = dishes.keys() ++ >>> values = dishes.values() ++ ++ >>> # iteration ++ >>> n = 0 ++ >>> for val in values: ++ ... n += val ++ ... ++ >>> print(n) ++ 504 ++ ++ >>> # keys and values are iterated over in the same order (insertion order) ++ >>> list(keys) ++ ['eggs', 'sausage', 'bacon', 'spam'] ++ >>> list(values) ++ [2, 1, 1, 500] ++ ++ >>> # view objects are dynamic and reflect dict changes ++ >>> del dishes['eggs'] ++ >>> del dishes['sausage'] ++ >>> list(keys) ++ ['bacon', 'spam'] ++ ++ >>> # set operations ++ >>> keys & {'eggs', 'bacon', 'salad'} ++ {'bacon'} ++ >>> keys ^ {'sausage', 'juice'} == {'juice', 'sausage', 'bacon', 'spam'} ++ True ++ >>> keys | ['juice', 'juice', 'juice'] == {'bacon', 'spam', 'juice'} ++ True ++ ++ >>> # get back a read-only proxy for the original dictionary ++ >>> values.mapping ++ mappingproxy({'bacon': 1, 'spam': 500}) ++ >>> values.mapping['spam'] ++ 500 ++''', ++ 'typesmethods': r'''Methods ++******* ++ ++Methods are functions that are called using the attribute notation. ++There are two flavors: built-in methods (such as "append()" on lists) ++and class instance method. Built-in methods are described with the ++types that support them. ++ ++If you access a method (a function defined in a class namespace) ++through an instance, you get a special object: a *bound method* (also ++called instance method) object. When called, it will add the "self" ++argument to the argument list. Bound methods have two special read- ++only attributes: "m.__self__" is the object on which the method ++operates, and "m.__func__" is the function implementing the method. ++Calling "m(arg-1, arg-2, ..., arg-n)" is completely equivalent to ++calling "m.__func__(m.__self__, arg-1, arg-2, ..., arg-n)". ++ ++Like function objects, bound method objects support getting arbitrary ++attributes. However, since method attributes are actually stored on ++the underlying function object ("method.__func__"), setting method ++attributes on bound methods is disallowed. Attempting to set an ++attribute on a method results in an "AttributeError" being raised. In ++order to set a method attribute, you need to explicitly set it on the ++underlying function object: ++ ++ >>> class C: ++ ... def method(self): ++ ... pass ++ ... ++ >>> c = C() ++ >>> c.method.whoami = 'my name is method' # can't set on the method ++ Traceback (most recent call last): ++ File "", line 1, in ++ AttributeError: 'method' object has no attribute 'whoami' ++ >>> c.method.__func__.whoami = 'my name is method' ++ >>> c.method.whoami ++ 'my name is method' ++ ++See Instance methods for more information. ++''', ++ 'typesmodules': r'''Modules ++******* ++ ++The only special operation on a module is attribute access: "m.name", ++where *m* is a module and *name* accesses a name defined in *m*’s ++symbol table. Module attributes can be assigned to. (Note that the ++"import" statement is not, strictly speaking, an operation on a module ++object; "import foo" does not require a module object named *foo* to ++exist, rather it requires an (external) *definition* for a module ++named *foo* somewhere.) ++ ++A special attribute of every module is "__dict__". This is the ++dictionary containing the module’s symbol table. Modifying this ++dictionary will actually change the module’s symbol table, but direct ++assignment to the "__dict__" attribute is not possible (you can write ++"m.__dict__['a'] = 1", which defines "m.a" to be "1", but you can’t ++write "m.__dict__ = {}"). Modifying "__dict__" directly is not ++recommended. ++ ++Modules built into the interpreter are written like this: "". If loaded from a file, they are written as ++"". ++''', ++ 'typesseq': r'''Sequence Types — "list", "tuple", "range" ++***************************************** ++ ++There are three basic sequence types: lists, tuples, and range ++objects. Additional sequence types tailored for processing of binary ++data and text strings are described in dedicated sections. ++ ++ ++Common Sequence Operations ++========================== ++ ++The operations in the following table are supported by most sequence ++types, both mutable and immutable. The "collections.abc.Sequence" ABC ++is provided to make it easier to correctly implement these operations ++on custom sequence types. ++ ++This table lists the sequence operations sorted in ascending priority. ++In the table, *s* and *t* are sequences of the same type, *n*, *i*, ++*j* and *k* are integers and *x* is an arbitrary object that meets any ++type and value restrictions imposed by *s*. ++ ++The "in" and "not in" operations have the same priorities as the ++comparison operations. The "+" (concatenation) and "*" (repetition) ++operations have the same priority as the corresponding numeric ++operations. [3] ++ +++----------------------------+----------------------------------+------------+ ++| Operation | Result | Notes | ++|============================|==================================|============| ++| "x in s" | "True" if an item of *s* is | (1) | ++| | equal to *x*, else "False" | | +++----------------------------+----------------------------------+------------+ ++| "x not in s" | "False" if an item of *s* is | (1) | ++| | equal to *x*, else "True" | | +++----------------------------+----------------------------------+------------+ ++| "s + t" | the concatenation of *s* and *t* | (6)(7) | +++----------------------------+----------------------------------+------------+ ++| "s * n" or "n * s" | equivalent to adding *s* to | (2)(7) | ++| | itself *n* times | | +++----------------------------+----------------------------------+------------+ ++| "s[i]" | *i*th item of *s*, origin 0 | (3) | +++----------------------------+----------------------------------+------------+ ++| "s[i:j]" | slice of *s* from *i* to *j* | (3)(4) | +++----------------------------+----------------------------------+------------+ ++| "s[i:j:k]" | slice of *s* from *i* to *j* | (3)(5) | ++| | with step *k* | | +++----------------------------+----------------------------------+------------+ ++| "len(s)" | length of *s* | | +++----------------------------+----------------------------------+------------+ ++| "min(s)" | smallest item of *s* | | +++----------------------------+----------------------------------+------------+ ++| "max(s)" | largest item of *s* | | +++----------------------------+----------------------------------+------------+ ++| "s.index(x[, i[, j]])" | index of the first occurrence of | (8) | ++| | *x* in *s* (at or after index | | ++| | *i* and before index *j*) | | +++----------------------------+----------------------------------+------------+ ++| "s.count(x)" | total number of occurrences of | | ++| | *x* in *s* | | +++----------------------------+----------------------------------+------------+ ++ ++Sequences of the same type also support comparisons. In particular, ++tuples and lists are compared lexicographically by comparing ++corresponding elements. This means that to compare equal, every ++element must compare equal and the two sequences must be of the same ++type and have the same length. (For full details see Comparisons in ++the language reference.) ++ ++Forward and reversed iterators over mutable sequences access values ++using an index. That index will continue to march forward (or ++backward) even if the underlying sequence is mutated. The iterator ++terminates only when an "IndexError" or a "StopIteration" is ++encountered (or when the index drops below zero). ++ ++Notes: ++ ++1. While the "in" and "not in" operations are used only for simple ++ containment testing in the general case, some specialised sequences ++ (such as "str", "bytes" and "bytearray") also use them for ++ subsequence testing: ++ ++ >>> "gg" in "eggs" ++ True ++ ++2. Values of *n* less than "0" are treated as "0" (which yields an ++ empty sequence of the same type as *s*). Note that items in the ++ sequence *s* are not copied; they are referenced multiple times. ++ This often haunts new Python programmers; consider: ++ ++ >>> lists = [[]] * 3 ++ >>> lists ++ [[], [], []] ++ >>> lists[0].append(3) ++ >>> lists ++ [[3], [3], [3]] ++ ++ What has happened is that "[[]]" is a one-element list containing ++ an empty list, so all three elements of "[[]] * 3" are references ++ to this single empty list. Modifying any of the elements of ++ "lists" modifies this single list. You can create a list of ++ different lists this way: ++ ++ >>> lists = [[] for i in range(3)] ++ >>> lists[0].append(3) ++ >>> lists[1].append(5) ++ >>> lists[2].append(7) ++ >>> lists ++ [[3], [5], [7]] ++ ++ Further explanation is available in the FAQ entry How do I create a ++ multidimensional list?. ++ ++3. If *i* or *j* is negative, the index is relative to the end of ++ sequence *s*: "len(s) + i" or "len(s) + j" is substituted. But ++ note that "-0" is still "0". ++ ++4. The slice of *s* from *i* to *j* is defined as the sequence of ++ items with index *k* such that "i <= k < j". If *i* or *j* is ++ greater than "len(s)", use "len(s)". If *i* is omitted or "None", ++ use "0". If *j* is omitted or "None", use "len(s)". If *i* is ++ greater than or equal to *j*, the slice is empty. ++ ++5. The slice of *s* from *i* to *j* with step *k* is defined as the ++ sequence of items with index "x = i + n*k" such that "0 <= n < ++ (j-i)/k". In other words, the indices are "i", "i+k", "i+2*k", ++ "i+3*k" and so on, stopping when *j* is reached (but never ++ including *j*). When *k* is positive, *i* and *j* are reduced to ++ "len(s)" if they are greater. When *k* is negative, *i* and *j* are ++ reduced to "len(s) - 1" if they are greater. If *i* or *j* are ++ omitted or "None", they become “end†values (which end depends on ++ the sign of *k*). Note, *k* cannot be zero. If *k* is "None", it ++ is treated like "1". ++ ++6. Concatenating immutable sequences always results in a new object. ++ This means that building up a sequence by repeated concatenation ++ will have a quadratic runtime cost in the total sequence length. ++ To get a linear runtime cost, you must switch to one of the ++ alternatives below: ++ ++ * if concatenating "str" objects, you can build a list and use ++ "str.join()" at the end or else write to an "io.StringIO" ++ instance and retrieve its value when complete ++ ++ * if concatenating "bytes" objects, you can similarly use ++ "bytes.join()" or "io.BytesIO", or you can do in-place ++ concatenation with a "bytearray" object. "bytearray" objects are ++ mutable and have an efficient overallocation mechanism ++ ++ * if concatenating "tuple" objects, extend a "list" instead ++ ++ * for other types, investigate the relevant class documentation ++ ++7. Some sequence types (such as "range") only support item sequences ++ that follow specific patterns, and hence don’t support sequence ++ concatenation or repetition. ++ ++8. "index" raises "ValueError" when *x* is not found in *s*. Not all ++ implementations support passing the additional arguments *i* and ++ *j*. These arguments allow efficient searching of subsections of ++ the sequence. Passing the extra arguments is roughly equivalent to ++ using "s[i:j].index(x)", only without copying any data and with the ++ returned index being relative to the start of the sequence rather ++ than the start of the slice. ++ ++ ++Immutable Sequence Types ++======================== ++ ++The only operation that immutable sequence types generally implement ++that is not also implemented by mutable sequence types is support for ++the "hash()" built-in. ++ ++This support allows immutable sequences, such as "tuple" instances, to ++be used as "dict" keys and stored in "set" and "frozenset" instances. ++ ++Attempting to hash an immutable sequence that contains unhashable ++values will result in "TypeError". ++ ++ ++Mutable Sequence Types ++====================== ++ ++The operations in the following table are defined on mutable sequence ++types. The "collections.abc.MutableSequence" ABC is provided to make ++it easier to correctly implement these operations on custom sequence ++types. ++ ++In the table *s* is an instance of a mutable sequence type, *t* is any ++iterable object and *x* is an arbitrary object that meets any type and ++value restrictions imposed by *s* (for example, "bytearray" only ++accepts integers that meet the value restriction "0 <= x <= 255"). ++ +++--------------------------------+----------------------------------+-----------------------+ ++| Operation | Result | Notes | ++|================================|==================================|=======================| ++| "s[i] = x" | item *i* of *s* is replaced by | | ++| | *x* | | +++--------------------------------+----------------------------------+-----------------------+ ++| "s[i:j] = t" | slice of *s* from *i* to *j* is | | ++| | replaced by the contents of the | | ++| | iterable *t* | | +++--------------------------------+----------------------------------+-----------------------+ ++| "del s[i:j]" | same as "s[i:j] = []" | | +++--------------------------------+----------------------------------+-----------------------+ ++| "s[i:j:k] = t" | the elements of "s[i:j:k]" are | (1) | ++| | replaced by those of *t* | | +++--------------------------------+----------------------------------+-----------------------+ ++| "del s[i:j:k]" | removes the elements of | | ++| | "s[i:j:k]" from the list | | +++--------------------------------+----------------------------------+-----------------------+ ++| "s.append(x)" | appends *x* to the end of the | | ++| | sequence (same as | | ++| | "s[len(s):len(s)] = [x]") | | +++--------------------------------+----------------------------------+-----------------------+ ++| "s.clear()" | removes all items from *s* (same | (5) | ++| | as "del s[:]") | | +++--------------------------------+----------------------------------+-----------------------+ ++| "s.copy()" | creates a shallow copy of *s* | (5) | ++| | (same as "s[:]") | | +++--------------------------------+----------------------------------+-----------------------+ ++| "s.extend(t)" or "s += t" | extends *s* with the contents of | | ++| | *t* (for the most part the same | | ++| | as "s[len(s):len(s)] = t") | | +++--------------------------------+----------------------------------+-----------------------+ ++| "s *= n" | updates *s* with its contents | (6) | ++| | repeated *n* times | | +++--------------------------------+----------------------------------+-----------------------+ ++| "s.insert(i, x)" | inserts *x* into *s* at the | | ++| | index given by *i* (same as | | ++| | "s[i:i] = [x]") | | +++--------------------------------+----------------------------------+-----------------------+ ++| "s.pop()" or "s.pop(i)" | retrieves the item at *i* and | (2) | ++| | also removes it from *s* | | +++--------------------------------+----------------------------------+-----------------------+ ++| "s.remove(x)" | removes the first item from *s* | (3) | ++| | where "s[i]" is equal to *x* | | +++--------------------------------+----------------------------------+-----------------------+ ++| "s.reverse()" | reverses the items of *s* in | (4) | ++| | place | | +++--------------------------------+----------------------------------+-----------------------+ ++ ++Notes: ++ ++1. If *k* is not equal to "1", *t* must have the same length as the ++ slice it is replacing. ++ ++2. The optional argument *i* defaults to "-1", so that by default the ++ last item is removed and returned. ++ ++3. "remove()" raises "ValueError" when *x* is not found in *s*. ++ ++4. The "reverse()" method modifies the sequence in place for economy ++ of space when reversing a large sequence. To remind users that it ++ operates by side effect, it does not return the reversed sequence. ++ ++5. "clear()" and "copy()" are included for consistency with the ++ interfaces of mutable containers that don’t support slicing ++ operations (such as "dict" and "set"). "copy()" is not part of the ++ "collections.abc.MutableSequence" ABC, but most concrete mutable ++ sequence classes provide it. ++ ++ Added in version 3.3: "clear()" and "copy()" methods. ++ ++6. The value *n* is an integer, or an object implementing ++ "__index__()". Zero and negative values of *n* clear the sequence. ++ Items in the sequence are not copied; they are referenced multiple ++ times, as explained for "s * n" under Common Sequence Operations. ++ ++ ++Lists ++===== ++ ++Lists are mutable sequences, typically used to store collections of ++homogeneous items (where the precise degree of similarity will vary by ++application). ++ ++class list([iterable]) ++ ++ Lists may be constructed in several ways: ++ ++ * Using a pair of square brackets to denote the empty list: "[]" ++ ++ * Using square brackets, separating items with commas: "[a]", "[a, ++ b, c]" ++ ++ * Using a list comprehension: "[x for x in iterable]" ++ ++ * Using the type constructor: "list()" or "list(iterable)" ++ ++ The constructor builds a list whose items are the same and in the ++ same order as *iterable*’s items. *iterable* may be either a ++ sequence, a container that supports iteration, or an iterator ++ object. If *iterable* is already a list, a copy is made and ++ returned, similar to "iterable[:]". For example, "list('abc')" ++ returns "['a', 'b', 'c']" and "list( (1, 2, 3) )" returns "[1, 2, ++ 3]". If no argument is given, the constructor creates a new empty ++ list, "[]". ++ ++ Many other operations also produce lists, including the "sorted()" ++ built-in. ++ ++ Lists implement all of the common and mutable sequence operations. ++ Lists also provide the following additional method: ++ ++ sort(*, key=None, reverse=False) ++ ++ This method sorts the list in place, using only "<" comparisons ++ between items. Exceptions are not suppressed - if any comparison ++ operations fail, the entire sort operation will fail (and the ++ list will likely be left in a partially modified state). ++ ++ "sort()" accepts two arguments that can only be passed by ++ keyword (keyword-only arguments): ++ ++ *key* specifies a function of one argument that is used to ++ extract a comparison key from each list element (for example, ++ "key=str.lower"). The key corresponding to each item in the list ++ is calculated once and then used for the entire sorting process. ++ The default value of "None" means that list items are sorted ++ directly without calculating a separate key value. ++ ++ The "functools.cmp_to_key()" utility is available to convert a ++ 2.x style *cmp* function to a *key* function. ++ ++ *reverse* is a boolean value. If set to "True", then the list ++ elements are sorted as if each comparison were reversed. ++ ++ This method modifies the sequence in place for economy of space ++ when sorting a large sequence. To remind users that it operates ++ by side effect, it does not return the sorted sequence (use ++ "sorted()" to explicitly request a new sorted list instance). ++ ++ The "sort()" method is guaranteed to be stable. A sort is ++ stable if it guarantees not to change the relative order of ++ elements that compare equal — this is helpful for sorting in ++ multiple passes (for example, sort by department, then by salary ++ grade). ++ ++ For sorting examples and a brief sorting tutorial, see Sorting ++ Techniques. ++ ++ **CPython implementation detail:** While a list is being sorted, ++ the effect of attempting to mutate, or even inspect, the list is ++ undefined. The C implementation of Python makes the list appear ++ empty for the duration, and raises "ValueError" if it can detect ++ that the list has been mutated during a sort. ++ ++ ++Tuples ++====== ++ ++Tuples are immutable sequences, typically used to store collections of ++heterogeneous data (such as the 2-tuples produced by the "enumerate()" ++built-in). Tuples are also used for cases where an immutable sequence ++of homogeneous data is needed (such as allowing storage in a "set" or ++"dict" instance). ++ ++class tuple([iterable]) ++ ++ Tuples may be constructed in a number of ways: ++ ++ * Using a pair of parentheses to denote the empty tuple: "()" ++ ++ * Using a trailing comma for a singleton tuple: "a," or "(a,)" ++ ++ * Separating items with commas: "a, b, c" or "(a, b, c)" ++ ++ * Using the "tuple()" built-in: "tuple()" or "tuple(iterable)" ++ ++ The constructor builds a tuple whose items are the same and in the ++ same order as *iterable*’s items. *iterable* may be either a ++ sequence, a container that supports iteration, or an iterator ++ object. If *iterable* is already a tuple, it is returned ++ unchanged. For example, "tuple('abc')" returns "('a', 'b', 'c')" ++ and "tuple( [1, 2, 3] )" returns "(1, 2, 3)". If no argument is ++ given, the constructor creates a new empty tuple, "()". ++ ++ Note that it is actually the comma which makes a tuple, not the ++ parentheses. The parentheses are optional, except in the empty ++ tuple case, or when they are needed to avoid syntactic ambiguity. ++ For example, "f(a, b, c)" is a function call with three arguments, ++ while "f((a, b, c))" is a function call with a 3-tuple as the sole ++ argument. ++ ++ Tuples implement all of the common sequence operations. ++ ++For heterogeneous collections of data where access by name is clearer ++than access by index, "collections.namedtuple()" may be a more ++appropriate choice than a simple tuple object. ++ ++ ++Ranges ++====== ++ ++The "range" type represents an immutable sequence of numbers and is ++commonly used for looping a specific number of times in "for" loops. ++ ++class range(stop) ++class range(start, stop[, step]) ++ ++ The arguments to the range constructor must be integers (either ++ built-in "int" or any object that implements the "__index__()" ++ special method). If the *step* argument is omitted, it defaults to ++ "1". If the *start* argument is omitted, it defaults to "0". If ++ *step* is zero, "ValueError" is raised. ++ ++ For a positive *step*, the contents of a range "r" are determined ++ by the formula "r[i] = start + step*i" where "i >= 0" and "r[i] < ++ stop". ++ ++ For a negative *step*, the contents of the range are still ++ determined by the formula "r[i] = start + step*i", but the ++ constraints are "i >= 0" and "r[i] > stop". ++ ++ A range object will be empty if "r[0]" does not meet the value ++ constraint. Ranges do support negative indices, but these are ++ interpreted as indexing from the end of the sequence determined by ++ the positive indices. ++ ++ Ranges containing absolute values larger than "sys.maxsize" are ++ permitted but some features (such as "len()") may raise ++ "OverflowError". ++ ++ Range examples: ++ ++ >>> list(range(10)) ++ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] ++ >>> list(range(1, 11)) ++ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ++ >>> list(range(0, 30, 5)) ++ [0, 5, 10, 15, 20, 25] ++ >>> list(range(0, 10, 3)) ++ [0, 3, 6, 9] ++ >>> list(range(0, -10, -1)) ++ [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] ++ >>> list(range(0)) ++ [] ++ >>> list(range(1, 0)) ++ [] ++ ++ Ranges implement all of the common sequence operations except ++ concatenation and repetition (due to the fact that range objects ++ can only represent sequences that follow a strict pattern and ++ repetition and concatenation will usually violate that pattern). ++ ++ start ++ ++ The value of the *start* parameter (or "0" if the parameter was ++ not supplied) ++ ++ stop ++ ++ The value of the *stop* parameter ++ ++ step ++ ++ The value of the *step* parameter (or "1" if the parameter was ++ not supplied) ++ ++The advantage of the "range" type over a regular "list" or "tuple" is ++that a "range" object will always take the same (small) amount of ++memory, no matter the size of the range it represents (as it only ++stores the "start", "stop" and "step" values, calculating individual ++items and subranges as needed). ++ ++Range objects implement the "collections.abc.Sequence" ABC, and ++provide features such as containment tests, element index lookup, ++slicing and support for negative indices (see Sequence Types — list, ++tuple, range): ++ ++>>> r = range(0, 20, 2) ++>>> r ++range(0, 20, 2) ++>>> 11 in r ++False ++>>> 10 in r ++True ++>>> r.index(10) ++5 ++>>> r[5] ++10 ++>>> r[:5] ++range(0, 10, 2) ++>>> r[-1] ++18 ++ ++Testing range objects for equality with "==" and "!=" compares them as ++sequences. That is, two range objects are considered equal if they ++represent the same sequence of values. (Note that two range objects ++that compare equal might have different "start", "stop" and "step" ++attributes, for example "range(0) == range(2, 1, 3)" or "range(0, 3, ++2) == range(0, 4, 2)".) ++ ++Changed in version 3.2: Implement the Sequence ABC. Support slicing ++and negative indices. Test "int" objects for membership in constant ++time instead of iterating through all items. ++ ++Changed in version 3.3: Define ‘==’ and ‘!=’ to compare range objects ++based on the sequence of values they define (instead of comparing ++based on object identity).Added the "start", "stop" and "step" ++attributes. ++ ++See also: ++ ++ * The linspace recipe shows how to implement a lazy version of range ++ suitable for floating-point applications. ++''', ++ 'typesseq-mutable': r'''Mutable Sequence Types ++********************** ++ ++The operations in the following table are defined on mutable sequence ++types. The "collections.abc.MutableSequence" ABC is provided to make ++it easier to correctly implement these operations on custom sequence ++types. ++ ++In the table *s* is an instance of a mutable sequence type, *t* is any ++iterable object and *x* is an arbitrary object that meets any type and ++value restrictions imposed by *s* (for example, "bytearray" only ++accepts integers that meet the value restriction "0 <= x <= 255"). ++ +++--------------------------------+----------------------------------+-----------------------+ ++| Operation | Result | Notes | ++|================================|==================================|=======================| ++| "s[i] = x" | item *i* of *s* is replaced by | | ++| | *x* | | +++--------------------------------+----------------------------------+-----------------------+ ++| "s[i:j] = t" | slice of *s* from *i* to *j* is | | ++| | replaced by the contents of the | | ++| | iterable *t* | | +++--------------------------------+----------------------------------+-----------------------+ ++| "del s[i:j]" | same as "s[i:j] = []" | | +++--------------------------------+----------------------------------+-----------------------+ ++| "s[i:j:k] = t" | the elements of "s[i:j:k]" are | (1) | ++| | replaced by those of *t* | | +++--------------------------------+----------------------------------+-----------------------+ ++| "del s[i:j:k]" | removes the elements of | | ++| | "s[i:j:k]" from the list | | +++--------------------------------+----------------------------------+-----------------------+ ++| "s.append(x)" | appends *x* to the end of the | | ++| | sequence (same as | | ++| | "s[len(s):len(s)] = [x]") | | +++--------------------------------+----------------------------------+-----------------------+ ++| "s.clear()" | removes all items from *s* (same | (5) | ++| | as "del s[:]") | | +++--------------------------------+----------------------------------+-----------------------+ ++| "s.copy()" | creates a shallow copy of *s* | (5) | ++| | (same as "s[:]") | | +++--------------------------------+----------------------------------+-----------------------+ ++| "s.extend(t)" or "s += t" | extends *s* with the contents of | | ++| | *t* (for the most part the same | | ++| | as "s[len(s):len(s)] = t") | | +++--------------------------------+----------------------------------+-----------------------+ ++| "s *= n" | updates *s* with its contents | (6) | ++| | repeated *n* times | | +++--------------------------------+----------------------------------+-----------------------+ ++| "s.insert(i, x)" | inserts *x* into *s* at the | | ++| | index given by *i* (same as | | ++| | "s[i:i] = [x]") | | +++--------------------------------+----------------------------------+-----------------------+ ++| "s.pop()" or "s.pop(i)" | retrieves the item at *i* and | (2) | ++| | also removes it from *s* | | +++--------------------------------+----------------------------------+-----------------------+ ++| "s.remove(x)" | removes the first item from *s* | (3) | ++| | where "s[i]" is equal to *x* | | +++--------------------------------+----------------------------------+-----------------------+ ++| "s.reverse()" | reverses the items of *s* in | (4) | ++| | place | | +++--------------------------------+----------------------------------+-----------------------+ ++ ++Notes: ++ ++1. If *k* is not equal to "1", *t* must have the same length as the ++ slice it is replacing. ++ ++2. The optional argument *i* defaults to "-1", so that by default the ++ last item is removed and returned. ++ ++3. "remove()" raises "ValueError" when *x* is not found in *s*. ++ ++4. The "reverse()" method modifies the sequence in place for economy ++ of space when reversing a large sequence. To remind users that it ++ operates by side effect, it does not return the reversed sequence. ++ ++5. "clear()" and "copy()" are included for consistency with the ++ interfaces of mutable containers that don’t support slicing ++ operations (such as "dict" and "set"). "copy()" is not part of the ++ "collections.abc.MutableSequence" ABC, but most concrete mutable ++ sequence classes provide it. ++ ++ Added in version 3.3: "clear()" and "copy()" methods. ++ ++6. The value *n* is an integer, or an object implementing ++ "__index__()". Zero and negative values of *n* clear the sequence. ++ Items in the sequence are not copied; they are referenced multiple ++ times, as explained for "s * n" under Common Sequence Operations. ++''', ++ 'unary': r'''Unary arithmetic and bitwise operations ++*************************************** ++ ++All unary arithmetic and bitwise operations have the same priority: ++ ++ **u_expr**: "power" | "-" "u_expr" | "+" "u_expr" | "~" "u_expr" ++ ++The unary "-" (minus) operator yields the negation of its numeric ++argument; the operation can be overridden with the "__neg__()" special ++method. ++ ++The unary "+" (plus) operator yields its numeric argument unchanged; ++the operation can be overridden with the "__pos__()" special method. ++ ++The unary "~" (invert) operator yields the bitwise inversion of its ++integer argument. The bitwise inversion of "x" is defined as ++"-(x+1)". It only applies to integral numbers or to custom objects ++that override the "__invert__()" special method. ++ ++In all three cases, if the argument does not have the proper type, a ++"TypeError" exception is raised. ++''', ++ 'while': r'''The "while" statement ++********************* ++ ++The "while" statement is used for repeated execution as long as an ++expression is true: ++ ++ **while_stmt**: "while" "assignment_expression" ":" "suite" ++ ["else" ":" "suite"] ++ ++This repeatedly tests the expression and, if it is true, executes the ++first suite; if the expression is false (which may be the first time ++it is tested) the suite of the "else" clause, if present, is executed ++and the loop terminates. ++ ++A "break" statement executed in the first suite terminates the loop ++without executing the "else" clause’s suite. A "continue" statement ++executed in the first suite skips the rest of the suite and goes back ++to testing the expression. ++''', ++ 'with': r'''The "with" statement ++******************** ++ ++The "with" statement is used to wrap the execution of a block with ++methods defined by a context manager (see section With Statement ++Context Managers). This allows common "try"…"except"…"finally" usage ++patterns to be encapsulated for convenient reuse. ++ ++ **with_stmt**: "with" ( "(" "with_stmt_contents" ","? ")" | "with_stmt_contents" ) ":" "suite" ++ **with_stmt_contents**: "with_item" ("," "with_item")* ++ **with_item**: "expression" ["as" "target"] ++ ++The execution of the "with" statement with one “item†proceeds as ++follows: ++ ++1. The context expression (the expression given in the "with_item") is ++ evaluated to obtain a context manager. ++ ++2. The context manager’s "__enter__()" is loaded for later use. ++ ++3. The context manager’s "__exit__()" is loaded for later use. ++ ++4. The context manager’s "__enter__()" method is invoked. ++ ++5. If a target was included in the "with" statement, the return value ++ from "__enter__()" is assigned to it. ++ ++ Note: ++ ++ The "with" statement guarantees that if the "__enter__()" method ++ returns without an error, then "__exit__()" will always be ++ called. Thus, if an error occurs during the assignment to the ++ target list, it will be treated the same as an error occurring ++ within the suite would be. See step 7 below. ++ ++6. The suite is executed. ++ ++7. The context manager’s "__exit__()" method is invoked. If an ++ exception caused the suite to be exited, its type, value, and ++ traceback are passed as arguments to "__exit__()". Otherwise, three ++ "None" arguments are supplied. ++ ++ If the suite was exited due to an exception, and the return value ++ from the "__exit__()" method was false, the exception is reraised. ++ If the return value was true, the exception is suppressed, and ++ execution continues with the statement following the "with" ++ statement. ++ ++ If the suite was exited for any reason other than an exception, the ++ return value from "__exit__()" is ignored, and execution proceeds ++ at the normal location for the kind of exit that was taken. ++ ++The following code: ++ ++ with EXPRESSION as TARGET: ++ SUITE ++ ++is semantically equivalent to: ++ ++ manager = (EXPRESSION) ++ enter = type(manager).__enter__ ++ exit = type(manager).__exit__ ++ value = enter(manager) ++ hit_except = False ++ ++ try: ++ TARGET = value ++ SUITE ++ except: ++ hit_except = True ++ if not exit(manager, *sys.exc_info()): ++ raise ++ finally: ++ if not hit_except: ++ exit(manager, None, None, None) ++ ++With more than one item, the context managers are processed as if ++multiple "with" statements were nested: ++ ++ with A() as a, B() as b: ++ SUITE ++ ++is semantically equivalent to: ++ ++ with A() as a: ++ with B() as b: ++ SUITE ++ ++You can also write multi-item context managers in multiple lines if ++the items are surrounded by parentheses. For example: ++ ++ with ( ++ A() as a, ++ B() as b, ++ ): ++ SUITE ++ ++Changed in version 3.1: Support for multiple context expressions. ++ ++Changed in version 3.10: Support for using grouping parentheses to ++break the statement in multiple lines. ++ ++See also: ++ ++ **PEP 343** - The “with†statement ++ The specification, background, and examples for the Python "with" ++ statement. ++''', ++ 'yield': r'''The "yield" statement ++********************* ++ ++ **yield_stmt**: "yield_expression" ++ ++A "yield" statement is semantically equivalent to a yield expression. ++The "yield" statement can be used to omit the parentheses that would ++otherwise be required in the equivalent yield expression statement. ++For example, the yield statements ++ ++ yield ++ yield from ++ ++are equivalent to the yield expression statements ++ ++ (yield ) ++ (yield from ) ++ ++Yield expressions and statements are only used when defining a ++*generator* function, and are only used in the body of the generator ++function. Using "yield" in a function definition is sufficient to ++cause that definition to create a generator function instead of a ++normal function. ++ ++For full details of "yield" semantics, refer to the Yield expressions ++section. ++''', ++} +diff --git a/Lib/shutil.py b/Lib/shutil.py +index 171489ca41f..510ae8c6f22 100644 +--- a/Lib/shutil.py ++++ b/Lib/shutil.py +@@ -49,6 +49,7 @@ + # https://bugs.python.org/issue43743#msg393429 + _USE_CP_SENDFILE = (hasattr(os, "sendfile") + and sys.platform.startswith(("linux", "android", "sunos"))) ++_USE_CP_COPY_FILE_RANGE = hasattr(os, "copy_file_range") + _HAS_FCOPYFILE = posix and hasattr(posix, "_fcopyfile") # macOS + + # CMD defaults in Windows 10 +@@ -107,6 +108,66 @@ + else: + raise err from None + ++def _determine_linux_fastcopy_blocksize(infd): ++ """Determine blocksize for fastcopying on Linux. ++ ++ Hopefully the whole file will be copied in a single call. ++ The copying itself should be performed in a loop 'till EOF is ++ reached (0 return) so a blocksize smaller or bigger than the actual ++ file size should not make any difference, also in case the file ++ content changes while being copied. ++ """ ++ try: ++ blocksize = max(os.fstat(infd).st_size, 2 ** 23) # min 8 MiB ++ except OSError: ++ blocksize = 2 ** 27 # 128 MiB ++ # On 32-bit architectures truncate to 1 GiB to avoid OverflowError, ++ # see gh-82500. ++ if sys.maxsize < 2 ** 32: ++ blocksize = min(blocksize, 2 ** 30) ++ return blocksize ++ ++def _fastcopy_copy_file_range(fsrc, fdst): ++ """Copy data from one regular mmap-like fd to another by using ++ a high-performance copy_file_range(2) syscall that gives filesystems ++ an opportunity to implement the use of reflinks or server-side copy. ++ ++ This should work on Linux >= 4.5 only. ++ """ ++ try: ++ infd = fsrc.fileno() ++ outfd = fdst.fileno() ++ except Exception as err: ++ raise _GiveupOnFastCopy(err) # not a regular file ++ ++ blocksize = _determine_linux_fastcopy_blocksize(infd) ++ offset = 0 ++ while True: ++ try: ++ n_copied = os.copy_file_range(infd, outfd, blocksize, offset_dst=offset) ++ except OSError as err: ++ # ...in oder to have a more informative exception. ++ err.filename = fsrc.name ++ err.filename2 = fdst.name ++ ++ if err.errno == errno.ENOSPC: # filesystem is full ++ raise err from None ++ ++ # Give up on first call and if no data was copied. ++ if offset == 0 and os.lseek(outfd, 0, os.SEEK_CUR) == 0: ++ raise _GiveupOnFastCopy(err) ++ ++ raise err ++ else: ++ if n_copied == 0: ++ # If no bytes have been copied yet, copy_file_range ++ # might silently fail. ++ # https://lore.kernel.org/linux-fsdevel/20210126233840.GG4626@dread.disaster.area/T/#m05753578c7f7882f6e9ffe01f981bc223edef2b0 ++ if offset == 0: ++ raise _GiveupOnFastCopy() ++ break ++ offset += n_copied ++ + def _fastcopy_sendfile(fsrc, fdst): + """Copy data from one regular mmap-like fd to another by using + high-performance sendfile(2) syscall. +@@ -128,20 +189,7 @@ + except Exception as err: + raise _GiveupOnFastCopy(err) # not a regular file + +- # Hopefully the whole file will be copied in a single call. +- # sendfile() is called in a loop 'till EOF is reached (0 return) +- # so a bufsize smaller or bigger than the actual file size +- # should not make any difference, also in case the file content +- # changes while being copied. +- try: +- blocksize = max(os.fstat(infd).st_size, 2 ** 23) # min 8MiB +- except OSError: +- blocksize = 2 ** 27 # 128MiB +- # On 32-bit architectures truncate to 1GiB to avoid OverflowError, +- # see bpo-38319. +- if sys.maxsize < 2 ** 32: +- blocksize = min(blocksize, 2 ** 30) +- ++ blocksize = _determine_linux_fastcopy_blocksize(infd) + offset = 0 + while True: + try: +@@ -266,12 +314,20 @@ + except _GiveupOnFastCopy: + pass + # Linux / Android / Solaris +- elif _USE_CP_SENDFILE: +- try: +- _fastcopy_sendfile(fsrc, fdst) +- return dst +- except _GiveupOnFastCopy: +- pass ++ elif _USE_CP_SENDFILE or _USE_CP_COPY_FILE_RANGE: ++ # reflink may be implicit in copy_file_range. ++ if _USE_CP_COPY_FILE_RANGE: ++ try: ++ _fastcopy_copy_file_range(fsrc, fdst) ++ return dst ++ except _GiveupOnFastCopy: ++ pass ++ if _USE_CP_SENDFILE: ++ try: ++ _fastcopy_sendfile(fsrc, fdst) ++ return dst ++ except _GiveupOnFastCopy: ++ pass + # Windows, see: + # https://github.com/python/cpython/pull/7160#discussion_r195405230 + elif _WINDOWS and file_size > 0: +diff --git a/Lib/site.py b/Lib/site.py +index 92bd1ccdadd..9da8b6724e1 100644 +--- a/Lib/site.py ++++ b/Lib/site.py +@@ -633,12 +633,9 @@ + # Doing this here ensures venv takes precedence over user-site + addsitepackages(known_paths, [sys.prefix]) + +- # addsitepackages will process site_prefix again if its in PREFIXES, +- # but that's ok; known_paths will prevent anything being added twice + if system_site == "true": +- PREFIXES.insert(0, sys.prefix) ++ PREFIXES += [sys.base_prefix, sys.base_exec_prefix] + else: +- PREFIXES = [sys.prefix] + ENABLE_USER_SITE = False + + return known_paths +diff --git a/Lib/socket.py b/Lib/socket.py +index be37c24d617..727b0e75f03 100644 +--- a/Lib/socket.py ++++ b/Lib/socket.py +@@ -937,7 +937,9 @@ + # Fail later on bind(), for platforms which may not + # support this option. + pass +- if reuse_port: ++ # Since Linux 6.12.9, SO_REUSEPORT is not allowed ++ # on other address families than AF_INET/AF_INET6. ++ if reuse_port and family in (AF_INET, AF_INET6): + sock.setsockopt(SOL_SOCKET, SO_REUSEPORT, 1) + if has_ipv6 and family == AF_INET6: + if dualstack_ipv6: +diff --git a/Lib/socketserver.py b/Lib/socketserver.py +index cd028ef1c63..35b2723de3b 100644 +--- a/Lib/socketserver.py ++++ b/Lib/socketserver.py +@@ -468,7 +468,12 @@ + """ + if self.allow_reuse_address and hasattr(socket, "SO_REUSEADDR"): + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) +- if self.allow_reuse_port and hasattr(socket, "SO_REUSEPORT"): ++ # Since Linux 6.12.9, SO_REUSEPORT is not allowed ++ # on other address families than AF_INET/AF_INET6. ++ if ( ++ self.allow_reuse_port and hasattr(socket, "SO_REUSEPORT") ++ and self.address_family in (socket.AF_INET, socket.AF_INET6) ++ ): + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) + self.socket.bind(self.server_address) + self.server_address = self.socket.getsockname() +diff --git a/Lib/sqlite3/__init__.py b/Lib/sqlite3/__init__.py +index 34a9c047dd6..ed727fae609 100644 +--- a/Lib/sqlite3/__init__.py ++++ b/Lib/sqlite3/__init__.py +@@ -22,7 +22,7 @@ + + """ + The sqlite3 extension module provides a DB-API 2.0 (PEP 249) compliant +-interface to the SQLite library, and requires SQLite 3.7.15 or newer. ++interface to the SQLite library, and requires SQLite 3.15.2 or newer. + + To use the module, start by creating a database Connection object: + +diff --git a/Lib/ssl.py b/Lib/ssl.py +index c8703b046cf..05df4ad7f0f 100644 +--- a/Lib/ssl.py ++++ b/Lib/ssl.py +@@ -116,7 +116,7 @@ + + from _ssl import ( + HAS_SNI, HAS_ECDH, HAS_NPN, HAS_ALPN, HAS_SSLv2, HAS_SSLv3, HAS_TLSv1, +- HAS_TLSv1_1, HAS_TLSv1_2, HAS_TLSv1_3, HAS_PSK ++ HAS_TLSv1_1, HAS_TLSv1_2, HAS_TLSv1_3, HAS_PSK, HAS_PHA + ) + from _ssl import _DEFAULT_CIPHERS, _OPENSSL_API_VERSION + +diff --git a/Lib/string.py b/Lib/string.py +index 2eab6d4f595..c4f05c7223c 100644 +--- a/Lib/string.py ++++ b/Lib/string.py +@@ -212,19 +212,20 @@ + # this is some markup, find the object and do + # the formatting + +- # handle arg indexing when empty field_names are given. +- if field_name == '': ++ # handle arg indexing when empty field first parts are given. ++ field_first, _ = _string.formatter_field_name_split(field_name) ++ if field_first == '': + if auto_arg_index is False: + raise ValueError('cannot switch from manual field ' + 'specification to automatic field ' + 'numbering') +- field_name = str(auto_arg_index) ++ field_name = str(auto_arg_index) + field_name + auto_arg_index += 1 +- elif field_name.isdigit(): ++ elif isinstance(field_first, int): + if auto_arg_index: +- raise ValueError('cannot switch from manual field ' +- 'specification to automatic field ' +- 'numbering') ++ raise ValueError('cannot switch from automatic field ' ++ 'numbering to manual field ' ++ 'specification') + # disable auto arg incrementing, if it gets + # used later on, then an exception will be raised + auto_arg_index = False +diff --git a/Lib/subprocess.py b/Lib/subprocess.py +index 88f0230b05f..2044d2a4289 100644 +--- a/Lib/subprocess.py ++++ b/Lib/subprocess.py +@@ -43,10 +43,8 @@ + import builtins + import errno + import io +-import locale + import os + import time +-import signal + import sys + import threading + import warnings +@@ -144,6 +142,8 @@ + + def __str__(self): + if self.returncode and self.returncode < 0: ++ # Lazy import to improve module import time ++ import signal + try: + return "Command '%s' died with %r." % ( + self.cmd, signal.Signals(-self.returncode)) +@@ -381,12 +381,14 @@ + if sys.flags.utf8_mode: + return "utf-8" + else: ++ # Lazy import to improve module import time ++ import locale + return locale.getencoding() + + + def call(*popenargs, timeout=None, **kwargs): + """Run command with arguments. Wait for command to complete or +- timeout, then return the returncode attribute. ++ for timeout seconds, then return the returncode attribute. + + The arguments are the same as for the Popen constructor. Example: + +@@ -523,8 +525,8 @@ + in the returncode attribute, and output & stderr attributes if those streams + were captured. + +- If timeout is given, and the process takes too long, a TimeoutExpired +- exception will be raised. ++ If timeout (seconds) is given and the process takes too long, ++ a TimeoutExpired exception will be raised. + + There is an optional argument "input", allowing you to + pass bytes or a string to the subprocess's stdin. If you use this argument +@@ -1664,6 +1666,9 @@ + # Don't signal a process that we know has already died. + if self.returncode is not None: + return ++ ++ # Lazy import to improve module import time ++ import signal + if sig == signal.SIGTERM: + self.terminate() + elif sig == signal.CTRL_C_EVENT: +@@ -1765,6 +1770,9 @@ + """Execute program using os.posix_spawn().""" + kwargs = {} + if restore_signals: ++ # Lazy import to improve module import time ++ import signal ++ + # See _Py_RestoreSignals() in Python/pylifecycle.c + sigset = [] + for signame in ('SIGPIPE', 'SIGXFZ', 'SIGXFSZ'): +@@ -2214,9 +2222,13 @@ + def terminate(self): + """Terminate the process with SIGTERM + """ ++ # Lazy import to improve module import time ++ import signal + self.send_signal(signal.SIGTERM) + + def kill(self): + """Kill the process with SIGKILL + """ ++ # Lazy import to improve module import time ++ import signal + self.send_signal(signal.SIGKILL) +diff --git a/Lib/sysconfig/__init__.py b/Lib/sysconfig/__init__.py +index ed7b6a335d0..34ce643340b 100644 +--- a/Lib/sysconfig/__init__.py ++++ b/Lib/sysconfig/__init__.py +@@ -116,8 +116,10 @@ + if env_base: + return env_base + +- # Emscripten, iOS, tvOS, VxWorks, WASI, and watchOS have no home directories +- if sys.platform in {"emscripten", "ios", "tvos", "vxworks", "wasi", "watchos"}: ++ # Emscripten, iOS, tvOS, VxWorks, WASI, and watchOS have no home directories. ++ # Use _PYTHON_HOST_PLATFORM to get the correct platform when cross-compiling. ++ system_name = os.environ.get('_PYTHON_HOST_PLATFORM', sys.platform).split('-')[0] ++ if system_name in {"emscripten", "ios", "tvos", "vxworks", "wasi", "watchos"}: + return None + + def joinuser(*args): +@@ -220,8 +222,15 @@ + def is_python_build(check_home=None): + if check_home is not None: + import warnings +- warnings.warn("check_home argument is deprecated and ignored.", +- DeprecationWarning, stacklevel=2) ++ warnings.warn( ++ ( ++ 'The check_home argument of sysconfig.is_python_build is ' ++ 'deprecated and its value is ignored. ' ++ 'It will be removed in Python 3.15.' ++ ), ++ DeprecationWarning, ++ stacklevel=2, ++ ) + for fn in ("Setup", "Setup.local"): + if os.path.isfile(os.path.join(_PROJECT_BASE, "Modules", fn)): + return True +@@ -335,6 +344,18 @@ + return os.path.join(get_path('stdlib'), config_dir_name, 'Makefile') + + ++def _import_from_directory(path, name): ++ if name not in sys.modules: ++ import importlib.machinery ++ import importlib.util ++ ++ spec = importlib.machinery.PathFinder.find_spec(name, [path]) ++ module = importlib.util.module_from_spec(spec) ++ spec.loader.exec_module(module) ++ sys.modules[name] = module ++ return sys.modules[name] ++ ++ + def _get_sysconfigdata_name(): + multiarch = getattr(sys.implementation, '_multiarch', '') + return os.environ.get( +@@ -342,27 +363,34 @@ + f'_sysconfigdata_{sys.abiflags}_{sys.platform}_{multiarch}', + ) + +-def _init_posix(vars): +- """Initialize the module as appropriate for POSIX systems.""" +- # _sysconfigdata is generated at build time, see _generate_posix_vars() ++ ++def _get_sysconfigdata(): ++ import importlib ++ + name = _get_sysconfigdata_name() ++ path = os.environ.get('_PYTHON_SYSCONFIGDATA_PATH') ++ module = _import_from_directory(path, name) if path else importlib.import_module(name) + +- # For cross builds, the path to the target's sysconfigdata must be specified +- # so it can be imported. It cannot be in PYTHONPATH, as foreign modules in +- # sys.path can cause crashes when loaded by the host interpreter. +- # Rely on truthiness as a valueless env variable is still an empty string. +- # See OS X note in _generate_posix_vars re _sysconfigdata. +- if (path := os.environ.get('_PYTHON_SYSCONFIGDATA_PATH')): +- from importlib.machinery import FileFinder, SourceFileLoader, SOURCE_SUFFIXES +- from importlib.util import module_from_spec +- spec = FileFinder(path, (SourceFileLoader, SOURCE_SUFFIXES)).find_spec(name) +- _temp = module_from_spec(spec) +- spec.loader.exec_module(_temp) +- else: +- _temp = __import__(name, globals(), locals(), ['build_time_vars'], 0) +- build_time_vars = _temp.build_time_vars ++ return module.build_time_vars ++ ++ ++def _installation_is_relocated(): ++ """Is the Python installation running from a different prefix than what was targetted when building?""" ++ if os.name != 'posix': ++ raise NotImplementedError('sysconfig._installation_is_relocated() is currently only supported on POSIX') ++ ++ data = _get_sysconfigdata() ++ return ( ++ data['prefix'] != getattr(sys, 'base_prefix', '') ++ or data['exec_prefix'] != getattr(sys, 'base_exec_prefix', '') ++ ) ++ ++ ++def _init_posix(vars): ++ """Initialize the module as appropriate for POSIX systems.""" + # GH-126920: Make sure we don't overwrite any of the keys already set +- vars.update(build_time_vars | vars) ++ vars.update(_get_sysconfigdata() | vars) ++ + + def _init_non_posix(vars): + """Initialize the module as appropriate for NT""" +@@ -485,10 +513,10 @@ + _init_posix(_CONFIG_VARS) + # If we are cross-compiling, load the prefixes from the Makefile instead. + if '_PYTHON_PROJECT_BASE' in os.environ: +- prefix = _CONFIG_VARS['prefix'] +- exec_prefix = _CONFIG_VARS['exec_prefix'] +- base_prefix = _CONFIG_VARS['prefix'] +- base_exec_prefix = _CONFIG_VARS['exec_prefix'] ++ prefix = _CONFIG_VARS['host_prefix'] ++ exec_prefix = _CONFIG_VARS['host_exec_prefix'] ++ base_prefix = _CONFIG_VARS['host_prefix'] ++ base_exec_prefix = _CONFIG_VARS['host_exec_prefix'] + abiflags = _CONFIG_VARS['ABIFLAGS'] + + # Normalized versions of prefix and exec_prefix are handy to have; +@@ -616,7 +644,8 @@ + solaris-2.6-sun4u + + Windows will return one of: +- win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc) ++ win-amd64 (64-bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc) ++ win-arm64 (64-bit Windows on ARM64 (aka AArch64) + win32 (all others - specifically, sys.platform is returned) + + For other non-POSIX platforms, currently just returns 'sys.platform'. +@@ -690,6 +719,14 @@ + release = get_config_vars().get("IPHONEOS_DEPLOYMENT_TARGET", "13.0") + osname = sys.platform + machine = sys.implementation._multiarch ++ elif sys.platform == "tvos": ++ release = get_config_vars().get("TVOS_DEPLOYMENT_TARGET", "9.0") ++ osname = sys.platform ++ machine = sys.implementation._multiarch ++ elif sys.platform == "watchos": ++ release = get_config_vars().get("WATCHOS_DEPLOYMENT_TARGET", "4.0") ++ osname = sys.platform ++ machine = sys.implementation._multiarch + else: + import _osx_support + osname, release, machine = _osx_support.get_platform_osx( +@@ -715,8 +752,20 @@ + variable expansions; if 'vars' is the output of 'parse_makefile()', + you're fine. Returns a variable-expanded version of 's'. + """ ++ ++ import warnings ++ warnings.warn( ++ 'sysconfig.expand_makefile_vars is deprecated and will be removed in ' ++ 'Python 3.16. Use sysconfig.get_paths(vars=...) instead.', ++ DeprecationWarning, ++ stacklevel=2, ++ ) ++ + import re + ++ _findvar1_rx = r"\$\(([A-Za-z][A-Za-z0-9_]*)\)" ++ _findvar2_rx = r"\${([A-Za-z][A-Za-z0-9_]*)}" ++ + # This algorithm does multiple expansion, so if vars['foo'] contains + # "${bar}", it will expand ${foo} to ${bar}, and then expand + # ${bar}... and so forth. This is fine as long as 'vars' comes from +diff --git a/Lib/sysconfig/__main__.py b/Lib/sysconfig/__main__.py +index 10728c709e1..bc2197cfe79 100644 +--- a/Lib/sysconfig/__main__.py ++++ b/Lib/sysconfig/__main__.py +@@ -232,10 +232,14 @@ + + print(f'Written {destfile}') + ++ install_vars = get_config_vars() ++ # Fix config vars to match the values after install (of the default environment) ++ install_vars['projectbase'] = install_vars['BINDIR'] ++ install_vars['srcdir'] = install_vars['LIBPL'] + # Write a JSON file with the output of sysconfig.get_config_vars + jsonfile = os.path.join(pybuilddir, _get_json_data_name()) + with open(jsonfile, 'w') as f: +- json.dump(get_config_vars(), f, indent=2) ++ json.dump(install_vars, f, indent=2) + + print(f'Written {jsonfile}') + +diff --git a/Lib/tempfile.py b/Lib/tempfile.py +index b5a15f7b72c..0eb9ddeb6ac 100644 +--- a/Lib/tempfile.py ++++ b/Lib/tempfile.py +@@ -437,11 +437,19 @@ + cleanup_called = False + close_called = False + +- def __init__(self, file, name, delete=True, delete_on_close=True): ++ def __init__( ++ self, ++ file, ++ name, ++ delete=True, ++ delete_on_close=True, ++ warn_message="Implicitly cleaning up unknown file", ++ ): + self.file = file + self.name = name + self.delete = delete + self.delete_on_close = delete_on_close ++ self.warn_message = warn_message + + def cleanup(self, windows=(_os.name == 'nt'), unlink=_os.unlink): + if not self.cleanup_called: +@@ -469,7 +477,10 @@ + self.cleanup() + + def __del__(self): ++ close_called = self.close_called + self.cleanup() ++ if not close_called: ++ _warnings.warn(self.warn_message, ResourceWarning) + + + class _TemporaryFileWrapper: +@@ -483,8 +494,17 @@ + def __init__(self, file, name, delete=True, delete_on_close=True): + self.file = file + self.name = name +- self._closer = _TemporaryFileCloser(file, name, delete, +- delete_on_close) ++ self._closer = _TemporaryFileCloser( ++ file, ++ name, ++ delete, ++ delete_on_close, ++ warn_message=f"Implicitly cleaning up {self!r}", ++ ) ++ ++ def __repr__(self): ++ file = self.__dict__['file'] ++ return f"<{type(self).__name__} {file=}>" + + def __getattr__(self, name): + # Attribute lookups are delegated to the underlying file +diff --git a/Lib/test/_test_eintr.py b/Lib/test/_test_eintr.py +index 493932d6c6d..0ce42276bfe 100644 +--- a/Lib/test/_test_eintr.py ++++ b/Lib/test/_test_eintr.py +@@ -91,7 +91,7 @@ + """ EINTR tests for the os module. """ + + def new_sleep_process(self): +- code = 'import time; time.sleep(%r)' % self.sleep_time ++ code = f'import time; time.sleep({self.sleep_time!r})' + return self.subprocess(code) + + def _test_wait_multiple(self, wait_func): +@@ -123,35 +123,46 @@ + def test_wait4(self): + self._test_wait_single(lambda pid: os.wait4(pid, 0)) + +- def test_read(self): ++ def _interrupted_reads(self): ++ """Make a fd which will force block on read of expected bytes.""" + rd, wr = os.pipe() + self.addCleanup(os.close, rd) + # wr closed explicitly by parent + + # the payload below are smaller than PIPE_BUF, hence the writes will be + # atomic +- datas = [b"hello", b"world", b"spam"] ++ data = [b"hello", b"world", b"spam"] + + code = '\n'.join(( + 'import os, sys, time', + '', + 'wr = int(sys.argv[1])', +- 'datas = %r' % datas, +- 'sleep_time = %r' % self.sleep_time, ++ f'data = {data!r}', ++ f'sleep_time = {self.sleep_time!r}', + '', +- 'for data in datas:', ++ 'for item in data:', + ' # let the parent block on read()', + ' time.sleep(sleep_time)', +- ' os.write(wr, data)', ++ ' os.write(wr, item)', + )) + + proc = self.subprocess(code, str(wr), pass_fds=[wr]) + with kill_on_error(proc): + os.close(wr) +- for data in datas: +- self.assertEqual(data, os.read(rd, len(data))) ++ for datum in data: ++ yield rd, datum + self.assertEqual(proc.wait(), 0) + ++ def test_read(self): ++ for fd, expected in self._interrupted_reads(): ++ self.assertEqual(expected, os.read(fd, len(expected))) ++ ++ def test_readinto(self): ++ for fd, expected in self._interrupted_reads(): ++ buffer = bytearray(len(expected)) ++ self.assertEqual(os.readinto(fd, buffer), len(expected)) ++ self.assertEqual(buffer, expected) ++ + def test_write(self): + rd, wr = os.pipe() + self.addCleanup(os.close, wr) +@@ -164,8 +175,8 @@ + 'import io, os, sys, time', + '', + 'rd = int(sys.argv[1])', +- 'sleep_time = %r' % self.sleep_time, +- 'data = b"x" * %s' % support.PIPE_MAX_SIZE, ++ f'sleep_time = {self.sleep_time!r}', ++ f'data = b"x" * {support.PIPE_MAX_SIZE}', + 'data_len = len(data)', + '', + '# let the parent block on write()', +@@ -178,8 +189,8 @@ + '', + 'value = read_data.getvalue()', + 'if value != data:', +- ' raise Exception("read error: %s vs %s bytes"', +- ' % (len(value), data_len))', ++ ' raise Exception(f"read error: {len(value)}' ++ ' vs {data_len} bytes")', + )) + + proc = self.subprocess(code, str(rd), pass_fds=[rd]) +@@ -202,33 +213,33 @@ + # wr closed explicitly by parent + + # single-byte payload guard us against partial recv +- datas = [b"x", b"y", b"z"] ++ data = [b"x", b"y", b"z"] + + code = '\n'.join(( + 'import os, socket, sys, time', + '', + 'fd = int(sys.argv[1])', +- 'family = %s' % int(wr.family), +- 'sock_type = %s' % int(wr.type), +- 'datas = %r' % datas, +- 'sleep_time = %r' % self.sleep_time, ++ f'family = {int(wr.family)}', ++ f'sock_type = {int(wr.type)}', ++ f'data = {data!r}', ++ f'sleep_time = {self.sleep_time!r}', + '', + 'wr = socket.fromfd(fd, family, sock_type)', + 'os.close(fd)', + '', + 'with wr:', +- ' for data in datas:', ++ ' for item in data:', + ' # let the parent block on recv()', + ' time.sleep(sleep_time)', +- ' wr.sendall(data)', ++ ' wr.sendall(item)', + )) + + fd = wr.fileno() + proc = self.subprocess(code, str(fd), pass_fds=[fd]) + with kill_on_error(proc): + wr.close() +- for data in datas: +- self.assertEqual(data, recv_func(rd, len(data))) ++ for item in data: ++ self.assertEqual(item, recv_func(rd, len(item))) + self.assertEqual(proc.wait(), 0) + + def test_recv(self): +@@ -250,10 +261,10 @@ + 'import os, socket, sys, time', + '', + 'fd = int(sys.argv[1])', +- 'family = %s' % int(rd.family), +- 'sock_type = %s' % int(rd.type), +- 'sleep_time = %r' % self.sleep_time, +- 'data = b"xyz" * %s' % (support.SOCK_MAX_SIZE // 3), ++ f'family = {int(rd.family)}', ++ f'sock_type = {int(rd.type)}', ++ f'sleep_time = {self.sleep_time!r}', ++ f'data = b"xyz" * {support.SOCK_MAX_SIZE // 3}', + 'data_len = len(data)', + '', + 'rd = socket.fromfd(fd, family, sock_type)', +@@ -269,8 +280,8 @@ + ' n += rd.recv_into(memoryview(received_data)[n:])', + '', + 'if received_data != data:', +- ' raise Exception("recv error: %s vs %s bytes"', +- ' % (len(received_data), data_len))', ++ ' raise Exception(f"recv error: {len(received_data)}' ++ ' vs {data_len} bytes")', + )) + + fd = rd.fileno() +@@ -302,9 +313,9 @@ + code = '\n'.join(( + 'import socket, time', + '', +- 'host = %r' % socket_helper.HOST, +- 'port = %s' % port, +- 'sleep_time = %r' % self.sleep_time, ++ f'host = {socket_helper.HOST!r}', ++ f'port = {port}', ++ f'sleep_time = {self.sleep_time!r}', + '', + '# let parent block on accept()', + 'time.sleep(sleep_time)', +@@ -332,15 +343,15 @@ + os_helper.unlink(filename) + try: + os.mkfifo(filename) +- except PermissionError as e: +- self.skipTest('os.mkfifo(): %s' % e) ++ except PermissionError as exc: ++ self.skipTest(f'os.mkfifo(): {exc!r}') + self.addCleanup(os_helper.unlink, filename) + + code = '\n'.join(( + 'import os, time', + '', +- 'path = %a' % filename, +- 'sleep_time = %r' % self.sleep_time, ++ f'path = {filename!a}', ++ f'sleep_time = {self.sleep_time!r}', + '', + '# let the parent block', + 'time.sleep(sleep_time)', +@@ -396,21 +407,20 @@ + + def check_sigwait(self, wait_func): + signum = signal.SIGUSR1 +- pid = os.getpid() + + old_handler = signal.signal(signum, lambda *args: None) + self.addCleanup(signal.signal, signum, old_handler) + + code = '\n'.join(( + 'import os, time', +- 'pid = %s' % os.getpid(), +- 'signum = %s' % int(signum), +- 'sleep_time = %r' % self.sleep_time, ++ f'pid = {os.getpid()}', ++ f'signum = {int(signum)}', ++ f'sleep_time = {self.sleep_time!r}', + 'time.sleep(sleep_time)', + 'os.kill(pid, signum)', + )) + +- old_mask = signal.pthread_sigmask(signal.SIG_BLOCK, [signum]) ++ signal.pthread_sigmask(signal.SIG_BLOCK, [signum]) + self.addCleanup(signal.pthread_sigmask, signal.SIG_UNBLOCK, [signum]) + + proc = self.subprocess(code) +diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py +index 80b08b8ac66..4b7c3e7fa8b 100644 +--- a/Lib/test/_test_multiprocessing.py ++++ b/Lib/test/_test_multiprocessing.py +@@ -319,7 +319,7 @@ + authkey = current.authkey + + self.assertTrue(current.is_alive()) +- self.assertTrue(not current.daemon) ++ self.assertFalse(current.daemon) + self.assertIsInstance(authkey, bytes) + self.assertTrue(len(authkey) > 0) + self.assertEqual(current.ident, os.getpid()) +@@ -463,7 +463,7 @@ + self.assertEqual(p.is_alive(), False) + self.assertEqual(p.daemon, True) + self.assertNotIn(p, self.active_children()) +- self.assertTrue(type(self.active_children()) is list) ++ self.assertIs(type(self.active_children()), list) + self.assertEqual(p.exitcode, None) + + p.start() +@@ -583,8 +583,8 @@ + cpus = multiprocessing.cpu_count() + except NotImplementedError: + cpus = 1 +- self.assertTrue(type(cpus) is int) +- self.assertTrue(cpus >= 1) ++ self.assertIsInstance(cpus, int) ++ self.assertGreaterEqual(cpus, 1) + + def test_active_children(self): + self.assertEqual(type(self.active_children()), list) +@@ -2382,14 +2382,14 @@ + self.assertEqual(lock, lock3) + + arr4 = self.Value('i', 5, lock=False) +- self.assertFalse(hasattr(arr4, 'get_lock')) +- self.assertFalse(hasattr(arr4, 'get_obj')) ++ self.assertNotHasAttr(arr4, 'get_lock') ++ self.assertNotHasAttr(arr4, 'get_obj') + + self.assertRaises(AttributeError, self.Value, 'i', 5, lock='navalue') + + arr5 = self.RawValue('i', 5) +- self.assertFalse(hasattr(arr5, 'get_lock')) +- self.assertFalse(hasattr(arr5, 'get_obj')) ++ self.assertNotHasAttr(arr5, 'get_lock') ++ self.assertNotHasAttr(arr5, 'get_obj') + + + class _TestArray(BaseTestCase): +@@ -2462,14 +2462,14 @@ + self.assertEqual(lock, lock3) + + arr4 = self.Array('i', range(10), lock=False) +- self.assertFalse(hasattr(arr4, 'get_lock')) +- self.assertFalse(hasattr(arr4, 'get_obj')) ++ self.assertNotHasAttr(arr4, 'get_lock') ++ self.assertNotHasAttr(arr4, 'get_obj') + self.assertRaises(AttributeError, + self.Array, 'i', range(10), lock='notalock') + + arr5 = self.RawArray('i', range(10)) +- self.assertFalse(hasattr(arr5, 'get_lock')) +- self.assertFalse(hasattr(arr5, 'get_obj')) ++ self.assertNotHasAttr(arr5, 'get_lock') ++ self.assertNotHasAttr(arr5, 'get_obj') + + # + # +@@ -2657,8 +2657,8 @@ + self.assertEqual((n.name, n.job), ('Bob', 'Builder')) + del n.job + self.assertEqual(str(n), "Namespace(name='Bob')") +- self.assertTrue(hasattr(n, 'name')) +- self.assertTrue(not hasattr(n, 'job')) ++ self.assertHasAttr(n, 'name') ++ self.assertNotHasAttr(n, 'job') + + # + # +@@ -4938,13 +4938,9 @@ + for name in modules: + __import__(name) + mod = sys.modules[name] +- self.assertTrue(hasattr(mod, '__all__'), name) +- ++ self.assertHasAttr(mod, '__all__', name) + for attr in mod.__all__: +- self.assertTrue( +- hasattr(mod, attr), +- '%r does not have attribute %r' % (mod, attr) +- ) ++ self.assertHasAttr(mod, attr) + + # + # Quick test that logging works -- does not test logging output +@@ -4957,7 +4953,7 @@ + def test_enable_logging(self): + logger = multiprocessing.get_logger() + logger.setLevel(util.SUBWARNING) +- self.assertTrue(logger is not None) ++ self.assertIsNotNone(logger) + logger.debug('this will not be printed') + logger.info('nor will this') + logger.setLevel(LOG_LEVEL) +@@ -5753,9 +5749,8 @@ + self.assertEqual(multiprocessing.get_start_method(), method) + ctx = multiprocessing.get_context() + self.assertEqual(ctx.get_start_method(), method) +- self.assertTrue(type(ctx).__name__.lower().startswith(method)) +- self.assertTrue( +- ctx.Process.__name__.lower().startswith(method)) ++ self.assertStartsWith(type(ctx).__name__.lower(), method) ++ self.assertStartsWith(ctx.Process.__name__.lower(), method) + self.check_context(multiprocessing) + count += 1 + finally: +@@ -5956,9 +5951,9 @@ + if should_die: + self.assertEqual(len(all_warn), 1) + the_warn = all_warn[0] +- self.assertTrue(issubclass(the_warn.category, UserWarning)) +- self.assertTrue("resource_tracker: process died" +- in str(the_warn.message)) ++ self.assertIsSubclass(the_warn.category, UserWarning) ++ self.assertIn("resource_tracker: process died", ++ str(the_warn.message)) + else: + self.assertEqual(len(all_warn), 0) + +@@ -6045,6 +6040,27 @@ + cleanup=cleanup, + ) + ++ @unittest.skipUnless(hasattr(signal, "pthread_sigmask"), "pthread_sigmask is not available") ++ def test_resource_tracker_blocked_signals(self): ++ # ++ # gh-127586: Check that resource_tracker does not override blocked signals of caller. ++ # ++ from multiprocessing.resource_tracker import ResourceTracker ++ orig_sigmask = signal.pthread_sigmask(signal.SIG_BLOCK, set()) ++ signals = {signal.SIGTERM, signal.SIGINT, signal.SIGUSR1} ++ ++ try: ++ for sig in signals: ++ signal.pthread_sigmask(signal.SIG_SETMASK, {sig}) ++ self.assertEqual(signal.pthread_sigmask(signal.SIG_BLOCK, set()), {sig}) ++ tracker = ResourceTracker() ++ tracker.ensure_running() ++ self.assertEqual(signal.pthread_sigmask(signal.SIG_BLOCK, set()), {sig}) ++ tracker._stop() ++ finally: ++ # restore sigmask to what it was before executing test ++ signal.pthread_sigmask(signal.SIG_SETMASK, orig_sigmask) ++ + class TestSimpleQueue(unittest.TestCase): + + @classmethod +@@ -6142,8 +6158,8 @@ + Process=FailingForkProcess)) + p.close() + p.join() +- self.assertFalse( +- any(process.is_alive() for process in forked_processes)) ++ for process in forked_processes: ++ self.assertFalse(process.is_alive(), process) + + + @hashlib_helper.requires_hashdigest('sha256') +diff --git a/Lib/test/audit-tests.py b/Lib/test/audit-tests.py +index 6df09d89143..6b9b21cf7f6 100644 +--- a/Lib/test/audit-tests.py ++++ b/Lib/test/audit-tests.py +@@ -187,7 +187,7 @@ + + + def test_open(testfn): +- # SSLContext.load_dh_params uses _Py_fopen_obj rather than normal open() ++ # SSLContext.load_dh_params uses Py_fopen() rather than normal open() + try: + import ssl + +diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c +index b6ae04ecf2f..0dfcc281985 100644 +--- a/Lib/test/clinic.test.c ++++ b/Lib/test/clinic.test.c +@@ -4758,7 +4758,7 @@ + Test_cls_with_param_impl(TestObj *self, PyTypeObject *cls, int a); + + static PyObject * +-Test_cls_with_param(TestObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++Test_cls_with_param(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -4798,7 +4798,7 @@ + if (a == -1 && PyErr_Occurred()) { + goto exit; + } +- return_value = Test_cls_with_param_impl(self, cls, a); ++ return_value = Test_cls_with_param_impl((TestObj *)self, cls, a); + + exit: + return return_value; +@@ -4806,7 +4806,7 @@ + + static PyObject * + Test_cls_with_param_impl(TestObj *self, PyTypeObject *cls, int a) +-/*[clinic end generated code: output=83a391eea66d08f8 input=af158077bd237ef9]*/ ++/*[clinic end generated code: output=7e893134a81fef92 input=af158077bd237ef9]*/ + + + /*[clinic input] +@@ -4908,18 +4908,18 @@ + Test_cls_no_params_impl(TestObj *self, PyTypeObject *cls); + + static PyObject * +-Test_cls_no_params(TestObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++Test_cls_no_params(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "cls_no_params() takes no arguments"); + return NULL; + } +- return Test_cls_no_params_impl(self, cls); ++ return Test_cls_no_params_impl((TestObj *)self, cls); + } + + static PyObject * + Test_cls_no_params_impl(TestObj *self, PyTypeObject *cls) +-/*[clinic end generated code: output=4d68b4652c144af3 input=e7e2e4e344e96a11]*/ ++/*[clinic end generated code: output=8845de054449f40a input=e7e2e4e344e96a11]*/ + + + /*[clinic input] +@@ -4945,7 +4945,7 @@ + PyObject *return_value = NULL; + int _return_value; + +- _return_value = Test_metho_not_default_return_converter_impl(self, a); ++ _return_value = Test_metho_not_default_return_converter_impl((TestObj *)self, a); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } +@@ -4957,7 +4957,7 @@ + + static int + Test_metho_not_default_return_converter_impl(TestObj *self, PyObject *a) +-/*[clinic end generated code: output=3350de11bd538007 input=428657129b521177]*/ ++/*[clinic end generated code: output=b2cce75a7af2e6ce input=428657129b521177]*/ + + + /*[clinic input] +@@ -4983,7 +4983,7 @@ + Test_an_metho_arg_named_arg_impl(TestObj *self, int arg); + + static PyObject * +-Test_an_metho_arg_named_arg(TestObj *self, PyObject *arg_) ++Test_an_metho_arg_named_arg(PyObject *self, PyObject *arg_) + { + PyObject *return_value = NULL; + int arg; +@@ -4992,7 +4992,7 @@ + if (arg == -1 && PyErr_Occurred()) { + goto exit; + } +- return_value = Test_an_metho_arg_named_arg_impl(self, arg); ++ return_value = Test_an_metho_arg_named_arg_impl((TestObj *)self, arg); + + exit: + return return_value; +@@ -5000,7 +5000,7 @@ + + static PyObject * + Test_an_metho_arg_named_arg_impl(TestObj *self, int arg) +-/*[clinic end generated code: output=9f04de4a62287e28 input=2a53a57cf5624f95]*/ ++/*[clinic end generated code: output=38554f09950d07e7 input=2a53a57cf5624f95]*/ + + + /*[clinic input] +@@ -5289,14 +5289,14 @@ + Test_meth_coexist_impl(TestObj *self); + + static PyObject * +-Test_meth_coexist(TestObj *self, PyObject *Py_UNUSED(ignored)) ++Test_meth_coexist(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return Test_meth_coexist_impl(self); ++ return Test_meth_coexist_impl((TestObj *)self); + } + + static PyObject * + Test_meth_coexist_impl(TestObj *self) +-/*[clinic end generated code: output=808a293d0cd27439 input=2a1d75b5e6fec6dd]*/ ++/*[clinic end generated code: output=7edf4e95b29f06fa input=2a1d75b5e6fec6dd]*/ + + /*[clinic input] + @getter +@@ -5317,14 +5317,14 @@ + Test_property_get_impl(TestObj *self); + + static PyObject * +-Test_property_get(TestObj *self, void *Py_UNUSED(context)) ++Test_property_get(PyObject *self, void *Py_UNUSED(context)) + { +- return Test_property_get_impl(self); ++ return Test_property_get_impl((TestObj *)self); + } + + static PyObject * + Test_property_get_impl(TestObj *self) +-/*[clinic end generated code: output=7cadd0f539805266 input=2d92b3449fbc7d2b]*/ ++/*[clinic end generated code: output=b38d68abd3466a6e input=2d92b3449fbc7d2b]*/ + + /*[clinic input] + @setter +@@ -5345,18 +5345,87 @@ + Test_property_set_impl(TestObj *self, PyObject *value); + + static int +-Test_property_set(TestObj *self, PyObject *value, void *Py_UNUSED(context)) ++Test_property_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) + { + int return_value; + +- return_value = Test_property_set_impl(self, value); ++ return_value = Test_property_set_impl((TestObj *)self, value); + + return return_value; + } + + static int + Test_property_set_impl(TestObj *self, PyObject *value) +-/*[clinic end generated code: output=e4342fe9bb1d7817 input=3bc3f46a23c83a88]*/ ++/*[clinic end generated code: output=49f925ab2a33b637 input=3bc3f46a23c83a88]*/ ++ ++/*[clinic input] ++@setter ++Test.setter_first_with_docstr ++[clinic start generated code]*/ ++ ++#if !defined(Test_setter_first_with_docstr_DOCSTR) ++# define Test_setter_first_with_docstr_DOCSTR NULL ++#endif ++#if defined(TEST_SETTER_FIRST_WITH_DOCSTR_GETSETDEF) ++# undef TEST_SETTER_FIRST_WITH_DOCSTR_GETSETDEF ++# define TEST_SETTER_FIRST_WITH_DOCSTR_GETSETDEF {"setter_first_with_docstr", (getter)Test_setter_first_with_docstr_get, (setter)Test_setter_first_with_docstr_set, Test_setter_first_with_docstr_DOCSTR}, ++#else ++# define TEST_SETTER_FIRST_WITH_DOCSTR_GETSETDEF {"setter_first_with_docstr", NULL, (setter)Test_setter_first_with_docstr_set, NULL}, ++#endif ++ ++static int ++Test_setter_first_with_docstr_set_impl(TestObj *self, PyObject *value); ++ ++static int ++Test_setter_first_with_docstr_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) ++{ ++ int return_value; ++ ++ return_value = Test_setter_first_with_docstr_set_impl((TestObj *)self, value); ++ ++ return return_value; ++} ++ ++static int ++Test_setter_first_with_docstr_set_impl(TestObj *self, PyObject *value) ++/*[clinic end generated code: output=5aaf44373c0af545 input=31a045ce11bbe961]*/ ++ ++/*[clinic input] ++@getter ++Test.setter_first_with_docstr ++ ++my silly docstring ++[clinic start generated code]*/ ++ ++PyDoc_STRVAR(Test_setter_first_with_docstr__doc__, ++"my silly docstring"); ++#if defined(Test_setter_first_with_docstr_DOCSTR) ++# undef Test_setter_first_with_docstr_DOCSTR ++#endif ++#define Test_setter_first_with_docstr_DOCSTR Test_setter_first_with_docstr__doc__ ++ ++#if !defined(Test_setter_first_with_docstr_DOCSTR) ++# define Test_setter_first_with_docstr_DOCSTR NULL ++#endif ++#if defined(TEST_SETTER_FIRST_WITH_DOCSTR_GETSETDEF) ++# undef TEST_SETTER_FIRST_WITH_DOCSTR_GETSETDEF ++# define TEST_SETTER_FIRST_WITH_DOCSTR_GETSETDEF {"setter_first_with_docstr", (getter)Test_setter_first_with_docstr_get, (setter)Test_setter_first_with_docstr_set, Test_setter_first_with_docstr_DOCSTR}, ++#else ++# define TEST_SETTER_FIRST_WITH_DOCSTR_GETSETDEF {"setter_first_with_docstr", (getter)Test_setter_first_with_docstr_get, NULL, Test_setter_first_with_docstr_DOCSTR}, ++#endif ++ ++static PyObject * ++Test_setter_first_with_docstr_get_impl(TestObj *self); ++ ++static PyObject * ++Test_setter_first_with_docstr_get(PyObject *self, void *Py_UNUSED(context)) ++{ ++ return Test_setter_first_with_docstr_get_impl((TestObj *)self); ++} ++ ++static PyObject * ++Test_setter_first_with_docstr_get_impl(TestObj *self) ++/*[clinic end generated code: output=fe6e3aa844a24920 input=10af4e43b3cb34dc]*/ + + /*[clinic input] + output push +@@ -5639,7 +5708,7 @@ + Py_ssize_t key_length); + + static PyObject * +-Test__pyarg_parsestackandkeywords(TestObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++Test__pyarg_parsestackandkeywords(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -5662,7 +5731,7 @@ + &key, &key_length)) { + goto exit; + } +- return_value = Test__pyarg_parsestackandkeywords_impl(self, cls, key, key_length); ++ return_value = Test__pyarg_parsestackandkeywords_impl((TestObj *)self, cls, key, key_length); + + exit: + return return_value; +@@ -5672,7 +5741,7 @@ + Test__pyarg_parsestackandkeywords_impl(TestObj *self, PyTypeObject *cls, + const char *key, + Py_ssize_t key_length) +-/*[clinic end generated code: output=4fda8a7f2547137c input=fc72ef4b4cfafabc]*/ ++/*[clinic end generated code: output=7060c213d7b8200e input=fc72ef4b4cfafabc]*/ + + + /*[clinic input] +diff --git a/Lib/test/libregrtest/cmdline.py b/Lib/test/libregrtest/cmdline.py +index bf9a71efbdb..81c7106ac0c 100644 +--- a/Lib/test/libregrtest/cmdline.py ++++ b/Lib/test/libregrtest/cmdline.py +@@ -160,6 +160,7 @@ + self.print_slow = False + self.random_seed = None + self.use_mp = None ++ self.parallel_threads = None + self.forever = False + self.header = False + self.failfast = False +@@ -167,6 +168,7 @@ + self.pgo = False + self.pgo_extended = False + self.tsan = False ++ self.tsan_parallel = False + self.worker_json = None + self.start = None + self.timeout = None +@@ -316,6 +318,10 @@ + 'a single process, ignore -jN option, ' + 'and failed tests are also rerun sequentially ' + 'in the same process') ++ group.add_argument('--parallel-threads', metavar='PARALLEL_THREADS', ++ type=int, ++ help='run copies of each test in PARALLEL_THREADS at ' ++ 'once') + group.add_argument('-T', '--coverage', action='store_true', + dest='trace', + help='turn on code coverage tracing using the trace ' +@@ -346,6 +352,9 @@ + help='enable extended PGO training (slower training)') + group.add_argument('--tsan', dest='tsan', action='store_true', + help='run a subset of test cases that are proper for the TSAN test') ++ group.add_argument('--tsan-parallel', action='store_true', ++ help='run a subset of test cases that are appropriate ' ++ 'for TSAN with `--parallel-threads=N`') + group.add_argument('--fail-env-changed', action='store_true', + help='if a test file alters the environment, mark ' + 'the test as failed') +diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py +index dcbcc6790c6..2f8fd4c92c1 100644 +--- a/Lib/test/libregrtest/main.py ++++ b/Lib/test/libregrtest/main.py +@@ -20,7 +20,7 @@ + from .runtests import RunTests, HuntRefleak + from .setup import setup_process, setup_test_dir + from .single import run_single_test, PROGRESS_MIN_TIME +-from .tsan import setup_tsan_tests ++from .tsan import setup_tsan_tests, setup_tsan_parallel_tests + from .utils import ( + StrPath, StrJSON, TestName, TestList, TestTuple, TestFilter, + strip_py_suffix, count, format_duration, +@@ -60,6 +60,7 @@ + self.pgo: bool = ns.pgo + self.pgo_extended: bool = ns.pgo_extended + self.tsan: bool = ns.tsan ++ self.tsan_parallel: bool = ns.tsan_parallel + + # Test results + self.results: TestResults = TestResults() +@@ -142,6 +143,8 @@ + else: + self.random_seed = ns.random_seed + ++ self.parallel_threads = ns.parallel_threads ++ + # tests + self.first_runtests: RunTests | None = None + +@@ -193,6 +196,9 @@ + if self.tsan: + setup_tsan_tests(self.cmdline_args) + ++ if self.tsan_parallel: ++ setup_tsan_parallel_tests(self.cmdline_args) ++ + exclude_tests = set() + if self.exclude: + for arg in self.cmdline_args: +@@ -506,6 +512,7 @@ + python_cmd=self.python_cmd, + randomize=self.randomize, + random_seed=self.random_seed, ++ parallel_threads=self.parallel_threads, + ) + + def _run_tests(self, selected: TestTuple, tests: TestList | None) -> int: +--- /dev/null ++++ b/Lib/test/libregrtest/parallel_case.py +@@ -0,0 +1,79 @@ ++"""Run a test case multiple times in parallel threads.""" ++ ++import copy ++import functools ++import threading ++import unittest ++ ++from unittest import TestCase ++ ++ ++class ParallelTestCase(TestCase): ++ def __init__(self, test_case: TestCase, num_threads: int): ++ self.test_case = test_case ++ self.num_threads = num_threads ++ self._testMethodName = test_case._testMethodName ++ self._testMethodDoc = test_case._testMethodDoc ++ ++ def __str__(self): ++ return f"{str(self.test_case)} [threads={self.num_threads}]" ++ ++ def run_worker(self, test_case: TestCase, result: unittest.TestResult, ++ barrier: threading.Barrier): ++ barrier.wait() ++ test_case.run(result) ++ ++ def run(self, result=None): ++ if result is None: ++ result = test_case.defaultTestResult() ++ startTestRun = getattr(result, 'startTestRun', None) ++ stopTestRun = getattr(result, 'stopTestRun', None) ++ if startTestRun is not None: ++ startTestRun() ++ else: ++ stopTestRun = None ++ ++ # Called at the beginning of each test. See TestCase.run. ++ result.startTest(self) ++ ++ cases = [copy.copy(self.test_case) for _ in range(self.num_threads)] ++ results = [unittest.TestResult() for _ in range(self.num_threads)] ++ ++ barrier = threading.Barrier(self.num_threads) ++ threads = [] ++ for i, (case, r) in enumerate(zip(cases, results)): ++ thread = threading.Thread(target=self.run_worker, ++ args=(case, r, barrier), ++ name=f"{str(self.test_case)}-{i}", ++ daemon=True) ++ threads.append(thread) ++ ++ for thread in threads: ++ thread.start() ++ ++ for threads in threads: ++ threads.join() ++ ++ # Aggregate test results ++ if all(r.wasSuccessful() for r in results): ++ result.addSuccess(self) ++ ++ # Note: We can't call result.addError, result.addFailure, etc. because ++ # we no longer have the original exception, just the string format. ++ for r in results: ++ if len(r.errors) > 0 or len(r.failures) > 0: ++ result._mirrorOutput = True ++ result.errors.extend(r.errors) ++ result.failures.extend(r.failures) ++ result.skipped.extend(r.skipped) ++ result.expectedFailures.extend(r.expectedFailures) ++ result.unexpectedSuccesses.extend(r.unexpectedSuccesses) ++ result.collectedDurations.extend(r.collectedDurations) ++ ++ if any(r.shouldStop for r in results): ++ result.stop() ++ ++ # Test has finished running ++ result.stopTest(self) ++ if stopTestRun is not None: ++ stopTestRun() +diff --git a/Lib/test/libregrtest/pgo.py b/Lib/test/libregrtest/pgo.py +index f762345c88c..04803ddf644 100644 +--- a/Lib/test/libregrtest/pgo.py ++++ b/Lib/test/libregrtest/pgo.py +@@ -19,7 +19,6 @@ + 'test_datetime', + 'test_decimal', + 'test_difflib', +- 'test_embed', + 'test_float', + 'test_fstring', + 'test_functools', +diff --git a/Lib/test/libregrtest/runtests.py b/Lib/test/libregrtest/runtests.py +index 130c036a62e..759f24fc25e 100644 +--- a/Lib/test/libregrtest/runtests.py ++++ b/Lib/test/libregrtest/runtests.py +@@ -100,6 +100,7 @@ + python_cmd: tuple[str, ...] | None + randomize: bool + random_seed: int | str ++ parallel_threads: int | None + + def copy(self, **override) -> 'RunTests': + state = dataclasses.asdict(self) +@@ -184,6 +185,8 @@ + args.extend(("--python", cmd)) + if self.randomize: + args.append(f"--randomize") ++ if self.parallel_threads: ++ args.append(f"--parallel-threads={self.parallel_threads}") + args.append(f"--randseed={self.random_seed}") + return args + +diff --git a/Lib/test/libregrtest/save_env.py b/Lib/test/libregrtest/save_env.py +index b2cc381344b..ffc29fa8dc6 100644 +--- a/Lib/test/libregrtest/save_env.py ++++ b/Lib/test/libregrtest/save_env.py +@@ -97,7 +97,7 @@ + return support.maybe_get_event_loop_policy() + def restore_asyncio_events__event_loop_policy(self, policy): + asyncio = self.get_module('asyncio') +- asyncio.set_event_loop_policy(policy) ++ asyncio._set_event_loop_policy(policy) + + def get_sys_argv(self): + return id(sys.argv), sys.argv, sys.argv[:] +diff --git a/Lib/test/libregrtest/single.py b/Lib/test/libregrtest/single.py +index 0e174f82abe..57d7b649d2e 100644 +--- a/Lib/test/libregrtest/single.py ++++ b/Lib/test/libregrtest/single.py +@@ -17,6 +17,7 @@ + from .save_env import saved_test_environment + from .setup import setup_tests + from .testresult import get_test_runner ++from .parallel_case import ParallelTestCase + from .utils import ( + TestName, + clear_caches, remove_testfn, abs_module_name, print_warning) +@@ -27,14 +28,17 @@ + PROGRESS_MIN_TIME = 30.0 # seconds + + +-def run_unittest(test_mod): ++def run_unittest(test_mod, runtests: RunTests): + loader = unittest.TestLoader() + tests = loader.loadTestsFromModule(test_mod) ++ + for error in loader.errors: + print(error, file=sys.stderr) + if loader.errors: + raise Exception("errors while loading tests") + _filter_suite(tests, match_test) ++ if runtests.parallel_threads: ++ _parallelize_tests(tests, runtests.parallel_threads) + return _run_suite(tests) + + def _filter_suite(suite, pred): +@@ -49,6 +53,28 @@ + newtests.append(test) + suite._tests = newtests + ++def _parallelize_tests(suite, parallel_threads: int): ++ def is_thread_unsafe(test): ++ test_method = getattr(test, test._testMethodName) ++ instance = test_method.__self__ ++ return (getattr(test_method, "__unittest_thread_unsafe__", False) or ++ getattr(instance, "__unittest_thread_unsafe__", False)) ++ ++ newtests: list[object] = [] ++ for test in suite._tests: ++ if isinstance(test, unittest.TestSuite): ++ _parallelize_tests(test, parallel_threads) ++ newtests.append(test) ++ continue ++ ++ if is_thread_unsafe(test): ++ # Don't parallelize thread-unsafe tests ++ newtests.append(test) ++ continue ++ ++ newtests.append(ParallelTestCase(test, parallel_threads)) ++ suite._tests = newtests ++ + def _run_suite(suite): + """Run tests from a unittest.TestSuite-derived class.""" + runner = get_test_runner(sys.stdout, +@@ -133,7 +159,7 @@ + raise Exception(f"Module {test_name} defines test_main() which " + f"is no longer supported by regrtest") + def test_func(): +- return run_unittest(test_mod) ++ return run_unittest(test_mod, runtests) + + try: + regrtest_runner(result, test_func, runtests) +@@ -162,8 +188,8 @@ + def _runtest_env_changed_exc(result: TestResult, runtests: RunTests, + display_failure: bool = True) -> None: + # Handle exceptions, detect environment changes. +- ansi = get_colors() +- red, reset, yellow = ansi.RED, ansi.RESET, ansi.YELLOW ++ stdout = get_colors(file=sys.stdout) ++ stderr = get_colors(file=sys.stderr) + + # Reset the environment_altered flag to detect if a test altered + # the environment +@@ -184,18 +210,24 @@ + _load_run_test(result, runtests) + except support.ResourceDenied as exc: + if not quiet and not pgo: +- print(f"{yellow}{test_name} skipped -- {exc}{reset}", flush=True) ++ print( ++ f"{stdout.YELLOW}{test_name} skipped -- {exc}{stdout.RESET}", ++ flush=True, ++ ) + result.state = State.RESOURCE_DENIED + return + except unittest.SkipTest as exc: + if not quiet and not pgo: +- print(f"{yellow}{test_name} skipped -- {exc}{reset}", flush=True) ++ print( ++ f"{stdout.YELLOW}{test_name} skipped -- {exc}{stdout.RESET}", ++ flush=True, ++ ) + result.state = State.SKIPPED + return + except support.TestFailedWithDetails as exc: +- msg = f"{red}test {test_name} failed{reset}" ++ msg = f"{stderr.RED}test {test_name} failed{stderr.RESET}" + if display_failure: +- msg = f"{red}{msg} -- {exc}{reset}" ++ msg = f"{stderr.RED}{msg} -- {exc}{stderr.RESET}" + print(msg, file=sys.stderr, flush=True) + result.state = State.FAILED + result.errors = exc.errors +@@ -203,9 +235,9 @@ + result.stats = exc.stats + return + except support.TestFailed as exc: +- msg = f"{red}test {test_name} failed{reset}" ++ msg = f"{stderr.RED}test {test_name} failed{stderr.RESET}" + if display_failure: +- msg = f"{red}{msg} -- {exc}{reset}" ++ msg = f"{stderr.RED}{msg} -- {exc}{stderr.RESET}" + print(msg, file=sys.stderr, flush=True) + result.state = State.FAILED + result.stats = exc.stats +@@ -220,8 +252,11 @@ + except: + if not pgo: + msg = traceback.format_exc() +- print(f"{red}test {test_name} crashed -- {msg}{reset}", +- file=sys.stderr, flush=True) ++ print( ++ f"{stderr.RED}test {test_name} crashed -- {msg}{stderr.RESET}", ++ file=sys.stderr, ++ flush=True, ++ ) + result.state = State.UNCAUGHT_EXC + return + +@@ -303,7 +338,7 @@ + If runtests.use_junit, xml_data is a list containing each generated + testsuite element. + """ +- ansi = get_colors() ++ ansi = get_colors(file=sys.stderr) + red, reset, yellow = ansi.BOLD_RED, ansi.RESET, ansi.YELLOW + + start_time = time.perf_counter() +diff --git a/Lib/test/libregrtest/tsan.py b/Lib/test/libregrtest/tsan.py +index 00d5779d950..10b12cce165 100644 +--- a/Lib/test/libregrtest/tsan.py ++++ b/Lib/test/libregrtest/tsan.py +@@ -25,10 +25,22 @@ + 'test_threading_local', + 'test_threadsignals', + 'test_weakref', +- 'test_free_threading.test_slots', ++ 'test_free_threading', ++] ++ ++# Tests that should be run with `--parallel-threads=N` under TSAN. These tests ++# typically do not use threads, but are run multiple times in parallel by ++# the regression test runner with the `--parallel-threads` option enabled. ++TSAN_PARALLEL_TESTS = [ ++ 'test_abc', ++ 'test_hashlib', + ] + + + def setup_tsan_tests(cmdline_args) -> None: + if not cmdline_args: + cmdline_args[:] = TSAN_TESTS[:] ++ ++def setup_tsan_parallel_tests(cmdline_args) -> None: ++ if not cmdline_args: ++ cmdline_args[:] = TSAN_PARALLEL_TESTS[:] +diff --git a/Lib/test/libregrtest/worker.py b/Lib/test/libregrtest/worker.py +index 0c9f5bd6e42..5d75bf7ae78 100644 +--- a/Lib/test/libregrtest/worker.py ++++ b/Lib/test/libregrtest/worker.py +@@ -56,6 +56,15 @@ + if USE_PROCESS_GROUP and test_name not in NEED_TTY: + kwargs['start_new_session'] = True + ++ # Include the test name in the TSAN log file name ++ if 'TSAN_OPTIONS' in env: ++ parts = env['TSAN_OPTIONS'].split(' ') ++ for i, part in enumerate(parts): ++ if part.startswith('log_path='): ++ parts[i] = f'{part}.{test_name}' ++ break ++ env['TSAN_OPTIONS'] = ' '.join(parts) ++ + # Pass json_file to the worker process + json_file = runtests.json_file + json_file.configure_subprocess(kwargs) +diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py +index 5c738ffaa27..f31d98bf731 100644 +--- a/Lib/test/support/__init__.py ++++ b/Lib/test/support/__init__.py +@@ -40,7 +40,7 @@ + "anticipate_failure", "load_package_tests", "detect_api_mismatch", + "check__all__", "skip_if_buggy_ucrt_strfptime", + "check_disallow_instantiation", "check_sanitizer", "skip_if_sanitizer", +- "requires_limited_api", "requires_specialization", ++ "requires_limited_api", "requires_specialization", "thread_unsafe", + # sys + "MS_WINDOWS", "is_jython", "is_android", "is_emscripten", "is_wasi", + "is_apple_mobile", "check_impl_detail", "unix_shell", "setswitchinterval", +@@ -58,10 +58,15 @@ + "LOOPBACK_TIMEOUT", "INTERNET_TIMEOUT", "SHORT_TIMEOUT", "LONG_TIMEOUT", + "Py_DEBUG", "exceeds_recursion_limit", "get_c_recursion_limit", + "skip_on_s390x", +- "without_optimizer", ++ "requires_jit_enabled", ++ "requires_jit_disabled", + "force_not_colorized", ++ "force_not_colorized_test_class", ++ "make_clean_env", + "BrokenIter", + "in_systemd_nspawn_sync_suppressed", ++ "run_no_yield_async_fn", "run_yielding_async_fn", "async_yield", ++ "reset_code", + ] + + +@@ -377,6 +382,21 @@ + return decorator + + ++def thread_unsafe(reason): ++ """Mark a test as not thread safe. When the test runner is run with ++ --parallel-threads=N, the test will be run in a single thread.""" ++ def decorator(test_item): ++ test_item.__unittest_thread_unsafe__ = True ++ # the reason is not currently used ++ test_item.__unittest_thread_unsafe__why__ = reason ++ return test_item ++ if isinstance(reason, types.FunctionType): ++ test_item = reason ++ reason = '' ++ return decorator(test_item) ++ return decorator ++ ++ + def skip_if_buildbot(reason=None): + """Decorator raising SkipTest if running on a buildbot.""" + import getpass +@@ -503,10 +523,10 @@ + + def has_no_debug_ranges(): + try: +- import _testinternalcapi ++ import _testcapi + except ImportError: + raise unittest.SkipTest("_testinternalcapi required") +- config = _testinternalcapi.get_config() ++ return not _testcapi.config_get('code_debug_ranges') + return not bool(config['code_debug_ranges']) + + def requires_debug_ranges(reason='requires co_positions / debug_ranges'): +@@ -1282,6 +1302,12 @@ + _opcode.ENABLE_SPECIALIZATION_FT, "requires specialization")(test) + + ++def reset_code(f: types.FunctionType) -> types.FunctionType: ++ """Clear all specializations, local instrumentation, and JIT code for the given function.""" ++ f.__code__ = f.__code__.replace() ++ return f ++ ++ + #======================================================================= + # Check for the presence of docstrings. + +@@ -2617,21 +2643,13 @@ + + Py_TRACE_REFS = hasattr(sys, 'getobjects') + +-# Decorator to disable optimizer while a function run +-def without_optimizer(func): +- try: +- from _testinternalcapi import get_optimizer, set_optimizer +- except ImportError: +- return func +- @functools.wraps(func) +- def wrapper(*args, **kwargs): +- save_opt = get_optimizer() +- try: +- set_optimizer(None) +- return func(*args, **kwargs) +- finally: +- set_optimizer(save_opt) +- return wrapper ++try: ++ from _testinternalcapi import jit_enabled ++except ImportError: ++ requires_jit_enabled = requires_jit_disabled = unittest.skip("requires _testinternalcapi") ++else: ++ requires_jit_enabled = unittest.skipUnless(jit_enabled(), "requires JIT enabled") ++ requires_jit_disabled = unittest.skipIf(jit_enabled(), "requires JIT disabled") + + + _BASE_COPY_SRC_DIR_IGNORED_NAMES = frozenset({ +@@ -2831,30 +2849,54 @@ + yield name, True + + ++@contextlib.contextmanager ++def no_color(): ++ import _colorize ++ from .os_helper import EnvironmentVarGuard ++ ++ with ( ++ swap_attr(_colorize, "can_colorize", lambda file=None: False), ++ EnvironmentVarGuard() as env, ++ ): ++ for var in {"FORCE_COLOR", "NO_COLOR", "PYTHON_COLORS"}: ++ env.unset(var) ++ env.set("NO_COLOR", "1") ++ yield ++ ++ + def force_not_colorized(func): + """Force the terminal not to be colorized.""" + @functools.wraps(func) + def wrapper(*args, **kwargs): +- import _colorize +- original_fn = _colorize.can_colorize +- variables: dict[str, str | None] = { +- "PYTHON_COLORS": None, "FORCE_COLOR": None, "NO_COLOR": None +- } +- try: +- for key in variables: +- variables[key] = os.environ.pop(key, None) +- os.environ["NO_COLOR"] = "1" +- _colorize.can_colorize = lambda: False ++ with no_color(): + return func(*args, **kwargs) +- finally: +- _colorize.can_colorize = original_fn +- del os.environ["NO_COLOR"] +- for key, value in variables.items(): +- if value is not None: +- os.environ[key] = value + return wrapper + + ++def force_not_colorized_test_class(cls): ++ """Force the terminal not to be colorized for the entire test class.""" ++ original_setUpClass = cls.setUpClass ++ ++ @classmethod ++ @functools.wraps(cls.setUpClass) ++ def new_setUpClass(cls): ++ cls.enterClassContext(no_color()) ++ original_setUpClass() ++ ++ cls.setUpClass = new_setUpClass ++ return cls ++ ++ ++def make_clean_env() -> dict[str, str]: ++ clean_env = os.environ.copy() ++ for k in clean_env.copy(): ++ if k.startswith("PYTHON"): ++ clean_env.pop(k) ++ clean_env.pop("FORCE_COLOR", None) ++ clean_env.pop("NO_COLOR", None) ++ return clean_env ++ ++ + def initialized_with_pyrepl(): + """Detect whether PyREPL was used during Python initialization.""" + # If the main module has a __file__ attribute it's a Python module, which means PyREPL. +@@ -2940,3 +2982,39 @@ + os.close(fd) + + return False ++ ++def run_no_yield_async_fn(async_fn, /, *args, **kwargs): ++ coro = async_fn(*args, **kwargs) ++ try: ++ coro.send(None) ++ except StopIteration as e: ++ return e.value ++ else: ++ raise AssertionError("coroutine did not complete") ++ finally: ++ coro.close() ++ ++ ++@types.coroutine ++def async_yield(v): ++ return (yield v) ++ ++ ++def run_yielding_async_fn(async_fn, /, *args, **kwargs): ++ coro = async_fn(*args, **kwargs) ++ try: ++ while True: ++ try: ++ coro.send(None) ++ except StopIteration as e: ++ return e.value ++ finally: ++ coro.close() ++ ++ ++def is_libssl_fips_mode(): ++ try: ++ from _hashlib import get_fips_mode # ask _hashopenssl.c ++ except ImportError: ++ return False # more of a maybe, unless we add this to the _ssl module. ++ return get_fips_mode() != 0 +diff --git a/Lib/test/support/os_helper.py b/Lib/test/support/os_helper.py +index 8071c248b9b..15dcdc9b1fd 100644 +--- a/Lib/test/support/os_helper.py ++++ b/Lib/test/support/os_helper.py +@@ -294,6 +294,33 @@ + return test if ok else unittest.skip(msg)(test) + + ++@contextlib.contextmanager ++def save_mode(path, *, quiet=False): ++ """Context manager that restores the mode (permissions) of *path* on exit. ++ ++ Arguments: ++ ++ path: Path of the file to restore the mode of. ++ ++ quiet: if False (the default), the context manager raises an exception ++ on error. Otherwise, it issues only a warning and keeps the current ++ working directory the same. ++ ++ """ ++ saved_mode = os.stat(path) ++ try: ++ yield ++ finally: ++ try: ++ os.chmod(path, saved_mode.st_mode) ++ except OSError as exc: ++ if not quiet: ++ raise ++ warnings.warn(f'tests may fail, unable to restore the mode of ' ++ f'{path!r} to {saved_mode.st_mode}: {exc}', ++ RuntimeWarning, stacklevel=3) ++ ++ + # Check whether the current effective user has the capability to override + # DAC (discretionary access control). Typically user root is able to + # bypass file read, write, and execute permission checks. The capability +diff --git a/Lib/test/support/venv.py b/Lib/test/support/venv.py +index 78e6a51ec18..7bfb9e4f3c4 100644 +--- a/Lib/test/support/venv.py ++++ b/Lib/test/support/venv.py +@@ -6,6 +6,7 @@ + import sys + import sysconfig + import tempfile ++import unittest + import venv + + +@@ -68,3 +69,14 @@ + raise + else: + return result ++ ++ ++class VirtualEnvironmentMixin: ++ def venv(self, name=None, **venv_create_args): ++ venv_name = self.id() ++ if name: ++ venv_name += f'-{name}' ++ return VirtualEnvironment.from_tmpdir( ++ prefix=f'{venv_name}-venv-', ++ **venv_create_args, ++ ) +diff --git a/Lib/test/test__colorize.py b/Lib/test/test__colorize.py +index 1871775fa20..056a5306ced 100644 +--- a/Lib/test/test__colorize.py ++++ b/Lib/test/test__colorize.py +@@ -1,68 +1,134 @@ + import contextlib ++import io + import sys + import unittest + import unittest.mock + import _colorize +-from test.support import force_not_colorized ++from test.support.os_helper import EnvironmentVarGuard + +-ORIGINAL_CAN_COLORIZE = _colorize.can_colorize + ++@contextlib.contextmanager ++def clear_env(): ++ with EnvironmentVarGuard() as mock_env: ++ for var in "FORCE_COLOR", "NO_COLOR", "PYTHON_COLORS": ++ mock_env.unset(var) ++ yield mock_env + +-def setUpModule(): +- _colorize.can_colorize = lambda: False + +- +-def tearDownModule(): +- _colorize.can_colorize = ORIGINAL_CAN_COLORIZE ++def supports_virtual_terminal(): ++ if sys.platform == "win32": ++ return unittest.mock.patch("nt._supports_virtual_terminal", return_value=True) ++ else: ++ return contextlib.nullcontext() + + + class TestColorizeFunction(unittest.TestCase): +- @force_not_colorized + def test_colorized_detection_checks_for_environment_variables(self): +- flags = unittest.mock.MagicMock(ignore_environment=False) ++ def check(env, fallback, expected): ++ with (self.subTest(env=env, fallback=fallback), ++ clear_env() as mock_env): ++ mock_env.update(env) ++ isatty_mock.return_value = fallback ++ stdout_mock.isatty.return_value = fallback ++ self.assertEqual(_colorize.can_colorize(), expected) ++ + with (unittest.mock.patch("os.isatty") as isatty_mock, ++ unittest.mock.patch("sys.stdout") as stdout_mock, ++ supports_virtual_terminal()): ++ stdout_mock.fileno.return_value = 1 ++ ++ for fallback in False, True: ++ check({}, fallback, fallback) ++ check({'TERM': 'dumb'}, fallback, False) ++ check({'TERM': 'xterm'}, fallback, fallback) ++ check({'TERM': ''}, fallback, fallback) ++ check({'FORCE_COLOR': '1'}, fallback, True) ++ check({'FORCE_COLOR': '0'}, fallback, True) ++ check({'FORCE_COLOR': ''}, fallback, fallback) ++ check({'NO_COLOR': '1'}, fallback, False) ++ check({'NO_COLOR': '0'}, fallback, False) ++ check({'NO_COLOR': ''}, fallback, fallback) ++ ++ check({'TERM': 'dumb', 'FORCE_COLOR': '1'}, False, True) ++ check({'FORCE_COLOR': '1', 'NO_COLOR': '1'}, True, False) ++ ++ for ignore_environment in False, True: ++ # Simulate running with or without `-E`. ++ flags = unittest.mock.MagicMock(ignore_environment=ignore_environment) ++ with unittest.mock.patch("sys.flags", flags): ++ check({'PYTHON_COLORS': '1'}, True, True) ++ check({'PYTHON_COLORS': '1'}, False, not ignore_environment) ++ check({'PYTHON_COLORS': '0'}, True, ignore_environment) ++ check({'PYTHON_COLORS': '0'}, False, False) ++ for fallback in False, True: ++ check({'PYTHON_COLORS': 'x'}, fallback, fallback) ++ check({'PYTHON_COLORS': ''}, fallback, fallback) ++ ++ check({'TERM': 'dumb', 'PYTHON_COLORS': '1'}, False, not ignore_environment) ++ check({'NO_COLOR': '1', 'PYTHON_COLORS': '1'}, False, not ignore_environment) ++ check({'FORCE_COLOR': '1', 'PYTHON_COLORS': '0'}, True, ignore_environment) ++ ++ @unittest.skipUnless(sys.platform == "win32", "requires Windows") ++ def test_colorized_detection_checks_on_windows(self): ++ with (clear_env(), ++ unittest.mock.patch("os.isatty") as isatty_mock, ++ unittest.mock.patch("sys.stdout") as stdout_mock, ++ supports_virtual_terminal() as vt_mock): ++ stdout_mock.fileno.return_value = 1 ++ isatty_mock.return_value = True ++ stdout_mock.isatty.return_value = True ++ ++ vt_mock.return_value = True ++ self.assertEqual(_colorize.can_colorize(), True) ++ vt_mock.return_value = False ++ self.assertEqual(_colorize.can_colorize(), False) ++ import nt ++ del nt._supports_virtual_terminal ++ self.assertEqual(_colorize.can_colorize(), False) ++ ++ def test_colorized_detection_checks_for_std_streams(self): ++ with (clear_env(), ++ unittest.mock.patch("os.isatty") as isatty_mock, ++ unittest.mock.patch("sys.stdout") as stdout_mock, + unittest.mock.patch("sys.stderr") as stderr_mock, +- unittest.mock.patch("sys.flags", flags), +- unittest.mock.patch("_colorize.can_colorize", ORIGINAL_CAN_COLORIZE), +- (unittest.mock.patch("nt._supports_virtual_terminal", return_value=False) +- if sys.platform == "win32" else +- contextlib.nullcontext()) as vt_mock): ++ supports_virtual_terminal()): ++ stdout_mock.fileno.return_value = 1 ++ stderr_mock.fileno.side_effect = ZeroDivisionError ++ stderr_mock.isatty.side_effect = ZeroDivisionError + + isatty_mock.return_value = True +- stderr_mock.fileno.return_value = 2 +- stderr_mock.isatty.return_value = True +- with unittest.mock.patch("os.environ", {'TERM': 'dumb'}): +- self.assertEqual(_colorize.can_colorize(), False) +- with unittest.mock.patch("os.environ", {'PYTHON_COLORS': '1'}): +- self.assertEqual(_colorize.can_colorize(), True) +- with unittest.mock.patch("os.environ", {'PYTHON_COLORS': '0'}): +- self.assertEqual(_colorize.can_colorize(), False) +- with unittest.mock.patch("os.environ", {'NO_COLOR': '1'}): +- self.assertEqual(_colorize.can_colorize(), False) +- with unittest.mock.patch("os.environ", +- {'NO_COLOR': '1', "PYTHON_COLORS": '1'}): +- self.assertEqual(_colorize.can_colorize(), True) +- with unittest.mock.patch("os.environ", {'FORCE_COLOR': '1'}): +- self.assertEqual(_colorize.can_colorize(), True) +- with unittest.mock.patch("os.environ", +- {'FORCE_COLOR': '1', 'NO_COLOR': '1'}): +- self.assertEqual(_colorize.can_colorize(), False) +- with unittest.mock.patch("os.environ", +- {'FORCE_COLOR': '1', "PYTHON_COLORS": '0'}): +- self.assertEqual(_colorize.can_colorize(), False) +- +- with unittest.mock.patch("os.environ", {}): +- if sys.platform == "win32": +- self.assertEqual(_colorize.can_colorize(), False) +- +- vt_mock.return_value = True +- self.assertEqual(_colorize.can_colorize(), True) +- else: +- self.assertEqual(_colorize.can_colorize(), True) ++ stdout_mock.isatty.return_value = True ++ self.assertEqual(_colorize.can_colorize(), True) ++ ++ isatty_mock.return_value = False ++ stdout_mock.isatty.return_value = False ++ self.assertEqual(_colorize.can_colorize(), False) + ++ def test_colorized_detection_checks_for_file(self): ++ with clear_env(), supports_virtual_terminal(): ++ ++ with unittest.mock.patch("os.isatty") as isatty_mock: ++ file = unittest.mock.MagicMock() ++ file.fileno.return_value = 1 ++ isatty_mock.return_value = True ++ self.assertEqual(_colorize.can_colorize(file=file), True) + isatty_mock.return_value = False +- stderr_mock.isatty.return_value = False +- self.assertEqual(_colorize.can_colorize(), False) ++ self.assertEqual(_colorize.can_colorize(file=file), False) ++ ++ # No file.fileno. ++ with unittest.mock.patch("os.isatty", side_effect=ZeroDivisionError): ++ file = unittest.mock.MagicMock(spec=['isatty']) ++ file.isatty.return_value = True ++ self.assertEqual(_colorize.can_colorize(file=file), False) ++ ++ # file.fileno() raises io.UnsupportedOperation. ++ with unittest.mock.patch("os.isatty", side_effect=ZeroDivisionError): ++ file = unittest.mock.MagicMock() ++ file.fileno.side_effect = io.UnsupportedOperation ++ file.isatty.return_value = True ++ self.assertEqual(_colorize.can_colorize(file=file), True) ++ file.isatty.return_value = False ++ self.assertEqual(_colorize.can_colorize(file=file), False) + + + if __name__ == "__main__": +diff --git a/Lib/test/test__interpreters.py b/Lib/test/test__interpreters.py +index bf3165e2341..fd444f1f06c 100644 +--- a/Lib/test/test__interpreters.py ++++ b/Lib/test/test__interpreters.py +@@ -557,7 +557,7 @@ + self.id = _interpreters.create() + + def test_signatures(self): +- # for method in ['exec', 'run_string', 'run_func']: ++ # See https://github.com/python/cpython/issues/126654 + msg = "expected 'shared' to be a dict" + with self.assertRaisesRegex(TypeError, msg): + _interpreters.exec(self.id, 'a', 1) +@@ -568,6 +568,17 @@ + with self.assertRaisesRegex(TypeError, msg): + _interpreters.run_func(self.id, lambda: None, shared=1) + ++ def test_invalid_shared_encoding(self): ++ # See https://github.com/python/cpython/issues/127196 ++ bad_shared = {"\uD82A": 0} ++ msg = 'surrogates not allowed' ++ with self.assertRaisesRegex(UnicodeEncodeError, msg): ++ _interpreters.exec(self.id, 'a', shared=bad_shared) ++ with self.assertRaisesRegex(UnicodeEncodeError, msg): ++ _interpreters.run_string(self.id, 'a', shared=bad_shared) ++ with self.assertRaisesRegex(UnicodeEncodeError, msg): ++ _interpreters.run_func(self.id, lambda: None, shared=bad_shared) ++ + + class RunStringTests(TestBase): + +diff --git a/Lib/test/test__opcode.py b/Lib/test/test__opcode.py +index d5cf014d40d..c253bc2be02 100644 +--- a/Lib/test/test__opcode.py ++++ b/Lib/test/test__opcode.py +@@ -38,6 +38,13 @@ + opcodes = [dis.opmap[opname] for opname in names] + self.check_bool_function_result(_opcode.is_valid, opcodes, True) + ++ def test_opmaps(self): ++ def check_roundtrip(name, map): ++ return self.assertEqual(opcode.opname[map[name]], name) ++ ++ check_roundtrip('BINARY_OP', opcode.opmap) ++ check_roundtrip('BINARY_OP_ADD_INT', opcode._specialized_opmap) ++ + def test_oplists(self): + def check_function(self, func, expected): + for op in [-10, 520]: +@@ -58,8 +65,7 @@ + class StackEffectTests(unittest.TestCase): + def test_stack_effect(self): + self.assertEqual(stack_effect(dis.opmap['POP_TOP']), -1) +- self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 0), -1) +- self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 1), -1) ++ self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 2), -1) + self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 3), -2) + self.assertRaises(ValueError, stack_effect, 30000) + # All defined opcodes +@@ -117,7 +123,7 @@ + if opcode._inline_cache_entries.get(op, 0) + ] + self.assertIn('load_attr', specialized_opcodes) +- self.assertIn('binary_subscr', specialized_opcodes) ++ self.assertIn('binary_op', specialized_opcodes) + + stats = _opcode.get_specialization_stats() + if stats is not None: +diff --git a/Lib/test/test_abc.py b/Lib/test/test_abc.py +index 5ce57cc209e..e90a8dc617c 100644 +--- a/Lib/test/test_abc.py ++++ b/Lib/test/test_abc.py +@@ -20,7 +20,7 @@ + def foo(self): pass + self.assertTrue(foo.__isabstractmethod__) + def bar(self): pass +- self.assertFalse(hasattr(bar, "__isabstractmethod__")) ++ self.assertNotHasAttr(bar, "__isabstractmethod__") + + class C(metaclass=abc_ABCMeta): + @abc.abstractproperty +@@ -89,7 +89,7 @@ + def foo(self): pass + self.assertTrue(foo.__isabstractmethod__) + def bar(self): pass +- self.assertFalse(hasattr(bar, "__isabstractmethod__")) ++ self.assertNotHasAttr(bar, "__isabstractmethod__") + + def test_abstractproperty_basics(self): + @property +@@ -276,21 +276,21 @@ + class B(object): + pass + b = B() +- self.assertFalse(issubclass(B, A)) +- self.assertFalse(issubclass(B, (A,))) ++ self.assertNotIsSubclass(B, A) ++ self.assertNotIsSubclass(B, (A,)) + self.assertNotIsInstance(b, A) + self.assertNotIsInstance(b, (A,)) + B1 = A.register(B) +- self.assertTrue(issubclass(B, A)) +- self.assertTrue(issubclass(B, (A,))) ++ self.assertIsSubclass(B, A) ++ self.assertIsSubclass(B, (A,)) + self.assertIsInstance(b, A) + self.assertIsInstance(b, (A,)) + self.assertIs(B1, B) + class C(B): + pass + c = C() +- self.assertTrue(issubclass(C, A)) +- self.assertTrue(issubclass(C, (A,))) ++ self.assertIsSubclass(C, A) ++ self.assertIsSubclass(C, (A,)) + self.assertIsInstance(c, A) + self.assertIsInstance(c, (A,)) + +@@ -301,16 +301,16 @@ + class B(object): + pass + b = B() +- self.assertTrue(issubclass(B, A)) +- self.assertTrue(issubclass(B, (A,))) ++ self.assertIsSubclass(B, A) ++ self.assertIsSubclass(B, (A,)) + self.assertIsInstance(b, A) + self.assertIsInstance(b, (A,)) + @A.register + class C(B): + pass + c = C() +- self.assertTrue(issubclass(C, A)) +- self.assertTrue(issubclass(C, (A,))) ++ self.assertIsSubclass(C, A) ++ self.assertIsSubclass(C, (A,)) + self.assertIsInstance(c, A) + self.assertIsInstance(c, (A,)) + self.assertIs(C, A.register(C)) +@@ -321,14 +321,14 @@ + class B: + pass + b = B() +- self.assertFalse(isinstance(b, A)) +- self.assertFalse(isinstance(b, (A,))) ++ self.assertNotIsInstance(b, A) ++ self.assertNotIsInstance(b, (A,)) + token_old = abc_get_cache_token() + A.register(B) + token_new = abc_get_cache_token() + self.assertGreater(token_new, token_old) +- self.assertTrue(isinstance(b, A)) +- self.assertTrue(isinstance(b, (A,))) ++ self.assertIsInstance(b, A) ++ self.assertIsInstance(b, (A,)) + + def test_registration_builtins(self): + class A(metaclass=abc_ABCMeta): +@@ -336,18 +336,18 @@ + A.register(int) + self.assertIsInstance(42, A) + self.assertIsInstance(42, (A,)) +- self.assertTrue(issubclass(int, A)) +- self.assertTrue(issubclass(int, (A,))) ++ self.assertIsSubclass(int, A) ++ self.assertIsSubclass(int, (A,)) + class B(A): + pass + B.register(str) + class C(str): pass + self.assertIsInstance("", A) + self.assertIsInstance("", (A,)) +- self.assertTrue(issubclass(str, A)) +- self.assertTrue(issubclass(str, (A,))) +- self.assertTrue(issubclass(C, A)) +- self.assertTrue(issubclass(C, (A,))) ++ self.assertIsSubclass(str, A) ++ self.assertIsSubclass(str, (A,)) ++ self.assertIsSubclass(C, A) ++ self.assertIsSubclass(C, (A,)) + + def test_registration_edge_cases(self): + class A(metaclass=abc_ABCMeta): +@@ -375,39 +375,39 @@ + def test_registration_transitiveness(self): + class A(metaclass=abc_ABCMeta): + pass +- self.assertTrue(issubclass(A, A)) +- self.assertTrue(issubclass(A, (A,))) ++ self.assertIsSubclass(A, A) ++ self.assertIsSubclass(A, (A,)) + class B(metaclass=abc_ABCMeta): + pass +- self.assertFalse(issubclass(A, B)) +- self.assertFalse(issubclass(A, (B,))) +- self.assertFalse(issubclass(B, A)) +- self.assertFalse(issubclass(B, (A,))) ++ self.assertNotIsSubclass(A, B) ++ self.assertNotIsSubclass(A, (B,)) ++ self.assertNotIsSubclass(B, A) ++ self.assertNotIsSubclass(B, (A,)) + class C(metaclass=abc_ABCMeta): + pass + A.register(B) + class B1(B): + pass +- self.assertTrue(issubclass(B1, A)) +- self.assertTrue(issubclass(B1, (A,))) ++ self.assertIsSubclass(B1, A) ++ self.assertIsSubclass(B1, (A,)) + class C1(C): + pass + B1.register(C1) +- self.assertFalse(issubclass(C, B)) +- self.assertFalse(issubclass(C, (B,))) +- self.assertFalse(issubclass(C, B1)) +- self.assertFalse(issubclass(C, (B1,))) +- self.assertTrue(issubclass(C1, A)) +- self.assertTrue(issubclass(C1, (A,))) +- self.assertTrue(issubclass(C1, B)) +- self.assertTrue(issubclass(C1, (B,))) +- self.assertTrue(issubclass(C1, B1)) +- self.assertTrue(issubclass(C1, (B1,))) ++ self.assertNotIsSubclass(C, B) ++ self.assertNotIsSubclass(C, (B,)) ++ self.assertNotIsSubclass(C, B1) ++ self.assertNotIsSubclass(C, (B1,)) ++ self.assertIsSubclass(C1, A) ++ self.assertIsSubclass(C1, (A,)) ++ self.assertIsSubclass(C1, B) ++ self.assertIsSubclass(C1, (B,)) ++ self.assertIsSubclass(C1, B1) ++ self.assertIsSubclass(C1, (B1,)) + C1.register(int) + class MyInt(int): + pass +- self.assertTrue(issubclass(MyInt, A)) +- self.assertTrue(issubclass(MyInt, (A,))) ++ self.assertIsSubclass(MyInt, A) ++ self.assertIsSubclass(MyInt, (A,)) + self.assertIsInstance(42, A) + self.assertIsInstance(42, (A,)) + +@@ -467,16 +467,16 @@ + if cls is A: + return 'foo' in C.__dict__ + return NotImplemented +- self.assertFalse(issubclass(A, A)) +- self.assertFalse(issubclass(A, (A,))) ++ self.assertNotIsSubclass(A, A) ++ self.assertNotIsSubclass(A, (A,)) + class B: + foo = 42 +- self.assertTrue(issubclass(B, A)) +- self.assertTrue(issubclass(B, (A,))) ++ self.assertIsSubclass(B, A) ++ self.assertIsSubclass(B, (A,)) + class C: + spam = 42 +- self.assertFalse(issubclass(C, A)) +- self.assertFalse(issubclass(C, (A,))) ++ self.assertNotIsSubclass(C, A) ++ self.assertNotIsSubclass(C, (A,)) + + def test_all_new_methods_are_called(self): + class A(metaclass=abc_ABCMeta): +@@ -493,7 +493,7 @@ + self.assertEqual(B.counter, 1) + + def test_ABC_has___slots__(self): +- self.assertTrue(hasattr(abc.ABC, '__slots__')) ++ self.assertHasAttr(abc.ABC, '__slots__') + + def test_tricky_new_works(self): + def with_metaclass(meta, *bases): +@@ -515,7 +515,7 @@ + + del A.foo + self.assertEqual(A.__abstractmethods__, {'foo'}) +- self.assertFalse(hasattr(A, 'foo')) ++ self.assertNotHasAttr(A, 'foo') + + abc.update_abstractmethods(A) + +@@ -588,7 +588,7 @@ + A.foo = updated_foo + abc.update_abstractmethods(A) + A() +- self.assertFalse(hasattr(A, '__abstractmethods__')) ++ self.assertNotHasAttr(A, '__abstractmethods__') + + def test_update_del_implementation(self): + class A(metaclass=abc_ABCMeta): +diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py +index f621f343eb0..58ea89c4fac 100755 +--- a/Lib/test/test_array.py ++++ b/Lib/test/test_array.py +@@ -1665,5 +1665,13 @@ + self.assertEqual(ls[:8], list(example[:8])) + self.assertEqual(ls[-8:], list(example[-8:])) + ++ def test_gh_128961(self): ++ a = array.array('i') ++ it = iter(a) ++ list(it) ++ it.__setstate__(0) ++ self.assertRaises(StopIteration, next, it) ++ ++ + if __name__ == "__main__": + unittest.main() +diff --git a/Lib/test/test_ast/test_ast.py b/Lib/test/test_ast/test_ast.py +index c268a1f00f9..a438c8e81e4 100644 +--- a/Lib/test/test_ast/test_ast.py ++++ b/Lib/test/test_ast/test_ast.py +@@ -3279,16 +3279,6 @@ + + self.assert_ast(code % (left, right), non_optimized_target, optimized_target) + +- def test_folding_subscript(self): +- code = "(1,)[0]" +- +- non_optimized_target = self.wrap_expr( +- ast.Subscript(value=ast.Tuple(elts=[ast.Constant(value=1)]), slice=ast.Constant(value=0)) +- ) +- optimized_target = self.wrap_expr(ast.Constant(value=1)) +- +- self.assert_ast(code, non_optimized_target, optimized_target) +- + def test_folding_type_param_in_function_def(self): + code = "def foo[%s = 1 + 1](): pass" + +diff --git a/Lib/test/test_asyncgen.py b/Lib/test/test_asyncgen.py +index 4f2278bb263..b8118787175 100644 +--- a/Lib/test/test_asyncgen.py ++++ b/Lib/test/test_asyncgen.py +@@ -624,12 +624,12 @@ + + def setUp(self): + self.loop = asyncio.new_event_loop() +- asyncio.set_event_loop(None) ++ asyncio._set_event_loop(None) + + def tearDown(self): + self.loop.close() + self.loop = None +- asyncio.set_event_loop_policy(None) ++ asyncio._set_event_loop_policy(None) + + def check_async_iterator_anext(self, ait_class): + with self.subTest(anext="pure-Python"): +@@ -1152,6 +1152,23 @@ + + self.loop.run_until_complete(run()) + ++ def test_async_gen_asyncio_anext_tuple_no_exceptions(self): ++ # StopAsyncIteration exceptions should be cleared. ++ # See: https://github.com/python/cpython/issues/128078. ++ ++ async def foo(): ++ if False: ++ yield (1, 2) ++ ++ async def run(): ++ it = foo().__aiter__() ++ with self.assertRaises(StopAsyncIteration): ++ await it.__anext__() ++ res = await anext(it, ('a', 'b')) ++ self.assertTupleEqual(res, ('a', 'b')) ++ ++ self.loop.run_until_complete(run()) ++ + def test_async_gen_asyncio_anext_stopiteration(self): + async def foo(): + try: +diff --git a/Lib/test/test_asyncio/functional.py b/Lib/test/test_asyncio/functional.py +index d19c7a612cc..2934325b6df 100644 +--- a/Lib/test/test_asyncio/functional.py ++++ b/Lib/test/test_asyncio/functional.py +@@ -24,7 +24,7 @@ + + def setUp(self): + self.loop = self.new_loop() +- asyncio.set_event_loop(None) ++ asyncio._set_event_loop(None) + + self.loop.set_exception_handler(self.loop_exception_handler) + self.__unhandled_exceptions = [] +@@ -39,7 +39,7 @@ + self.fail('unexpected calls to loop.call_exception_handler()') + + finally: +- asyncio.set_event_loop(None) ++ asyncio._set_event_loop(None) + self.loop = None + + def tcp_server(self, server_prog, *, +diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py +index c14a0bb180d..8cf1f6891fa 100644 +--- a/Lib/test/test_asyncio/test_base_events.py ++++ b/Lib/test/test_asyncio/test_base_events.py +@@ -25,7 +25,7 @@ + + + def tearDownModule(): +- asyncio.set_event_loop_policy(None) ++ asyncio._set_event_loop_policy(None) + + + def mock_socket_module(): +@@ -331,10 +331,10 @@ + if create_loop: + loop2 = base_events.BaseEventLoop() + try: +- asyncio.set_event_loop(loop2) ++ asyncio._set_event_loop(loop2) + self.check_thread(loop, debug) + finally: +- asyncio.set_event_loop(None) ++ asyncio._set_event_loop(None) + loop2.close() + else: + self.check_thread(loop, debug) +@@ -690,7 +690,7 @@ + + loop = Loop() + self.addCleanup(loop.close) +- asyncio.set_event_loop(loop) ++ asyncio._set_event_loop(loop) + + def run_loop(): + def zero_error(): +@@ -833,8 +833,8 @@ + loop.close() + + def test_create_named_task_with_custom_factory(self): +- def task_factory(loop, coro): +- return asyncio.Task(coro, loop=loop) ++ def task_factory(loop, coro, **kwargs): ++ return asyncio.Task(coro, loop=loop, **kwargs) + + async def test(): + pass +@@ -1345,7 +1345,7 @@ + with self.assertRaises(OSError) as cm: + self.loop.run_until_complete(coro) + +- self.assertTrue(str(cm.exception).startswith('Multiple exceptions: ')) ++ self.assertStartsWith(str(cm.exception), 'Multiple exceptions: ') + self.assertTrue(m_socket.socket.return_value.close.called) + + coro = self.loop.create_connection( +@@ -1983,7 +1983,7 @@ + async def stop_loop_coro(loop): + loop.stop() + +- asyncio.set_event_loop(self.loop) ++ asyncio._set_event_loop(self.loop) + self.loop.set_debug(True) + self.loop.slow_callback_duration = 0.0 + +diff --git a/Lib/test/test_asyncio/test_buffered_proto.py b/Lib/test/test_asyncio/test_buffered_proto.py +index f24e363ebfc..9c386dd2e63 100644 +--- a/Lib/test/test_asyncio/test_buffered_proto.py ++++ b/Lib/test/test_asyncio/test_buffered_proto.py +@@ -5,7 +5,7 @@ + + + def tearDownModule(): +- asyncio.set_event_loop_policy(None) ++ asyncio._set_event_loop_policy(None) + + + class ReceiveStuffProto(asyncio.BufferedProtocol): +diff --git a/Lib/test/test_asyncio/test_context.py b/Lib/test/test_asyncio/test_context.py +index 6b80721873d..ad394f44e7e 100644 +--- a/Lib/test/test_asyncio/test_context.py ++++ b/Lib/test/test_asyncio/test_context.py +@@ -4,7 +4,7 @@ + + + def tearDownModule(): +- asyncio.set_event_loop_policy(None) ++ asyncio._set_event_loop_policy(None) + + + @unittest.skipUnless(decimal.HAVE_CONTEXTVAR, "decimal is built with a thread-local context") +diff --git a/Lib/test/test_asyncio/test_eager_task_factory.py b/Lib/test/test_asyncio/test_eager_task_factory.py +index 0e2b189f761..bb0760a6967 100644 +--- a/Lib/test/test_asyncio/test_eager_task_factory.py ++++ b/Lib/test/test_asyncio/test_eager_task_factory.py +@@ -13,7 +13,7 @@ + + + def tearDownModule(): +- asyncio.set_event_loop_policy(None) ++ asyncio._set_event_loop_policy(None) + + + class EagerTaskFactoryLoopTests: +@@ -267,12 +267,33 @@ + class PyEagerTaskFactoryLoopTests(EagerTaskFactoryLoopTests, test_utils.TestCase): + Task = tasks._PyTask + ++ def setUp(self): ++ self._current_task = asyncio.current_task ++ asyncio.current_task = asyncio.tasks.current_task = asyncio.tasks._py_current_task ++ return super().setUp() ++ ++ def tearDown(self): ++ asyncio.current_task = asyncio.tasks.current_task = self._current_task ++ return super().tearDown() ++ ++ + + @unittest.skipUnless(hasattr(tasks, '_CTask'), + 'requires the C _asyncio module') + class CEagerTaskFactoryLoopTests(EagerTaskFactoryLoopTests, test_utils.TestCase): + Task = getattr(tasks, '_CTask', None) + ++ def setUp(self): ++ self._current_task = asyncio.current_task ++ asyncio.current_task = asyncio.tasks.current_task = asyncio.tasks._c_current_task ++ return super().setUp() ++ ++ def tearDown(self): ++ asyncio.current_task = asyncio.tasks.current_task = self._current_task ++ return super().tearDown() ++ ++ ++ @unittest.skip("skip") + def test_issue105987(self): + code = """if 1: + from _asyncio import _swap_current_task +@@ -302,6 +323,18 @@ + + self.run_coro(run()) + ++ def test_name(self): ++ name = None ++ async def coro(): ++ nonlocal name ++ name = asyncio.current_task().get_name() ++ ++ async def main(): ++ task = self.loop.create_task(coro(), name="test name") ++ self.assertEqual(name, "test name") ++ await task ++ ++ self.run_coro(coro()) + + class AsyncTaskCounter: + def __init__(self, loop, *, task_class, eager): +@@ -388,31 +421,83 @@ + + + class NonEagerTests(BaseNonEagerTaskFactoryTests, test_utils.TestCase): +- Task = asyncio.Task ++ Task = asyncio.tasks._CTask + ++ def setUp(self): ++ self._current_task = asyncio.current_task ++ asyncio.current_task = asyncio.tasks.current_task = asyncio.tasks._c_current_task ++ return super().setUp() ++ ++ def tearDown(self): ++ asyncio.current_task = asyncio.tasks.current_task = self._current_task ++ return super().tearDown() + + class EagerTests(BaseEagerTaskFactoryTests, test_utils.TestCase): +- Task = asyncio.Task ++ Task = asyncio.tasks._CTask ++ ++ def setUp(self): ++ self._current_task = asyncio.current_task ++ asyncio.current_task = asyncio.tasks.current_task = asyncio.tasks._c_current_task ++ return super().setUp() ++ ++ def tearDown(self): ++ asyncio.current_task = asyncio.tasks.current_task = self._current_task ++ return super().tearDown() + + + class NonEagerPyTaskTests(BaseNonEagerTaskFactoryTests, test_utils.TestCase): + Task = tasks._PyTask + ++ def setUp(self): ++ self._current_task = asyncio.current_task ++ asyncio.current_task = asyncio.tasks.current_task = asyncio.tasks._py_current_task ++ return super().setUp() ++ ++ def tearDown(self): ++ asyncio.current_task = asyncio.tasks.current_task = self._current_task ++ return super().tearDown() ++ + + class EagerPyTaskTests(BaseEagerTaskFactoryTests, test_utils.TestCase): + Task = tasks._PyTask + ++ def setUp(self): ++ self._current_task = asyncio.current_task ++ asyncio.current_task = asyncio.tasks.current_task = asyncio.tasks._py_current_task ++ return super().setUp() ++ ++ def tearDown(self): ++ asyncio.current_task = asyncio.tasks.current_task = self._current_task ++ return super().tearDown() + + @unittest.skipUnless(hasattr(tasks, '_CTask'), + 'requires the C _asyncio module') + class NonEagerCTaskTests(BaseNonEagerTaskFactoryTests, test_utils.TestCase): + Task = getattr(tasks, '_CTask', None) + ++ def setUp(self): ++ self._current_task = asyncio.current_task ++ asyncio.current_task = asyncio.tasks.current_task = asyncio.tasks._c_current_task ++ return super().setUp() ++ ++ def tearDown(self): ++ asyncio.current_task = asyncio.tasks.current_task = self._current_task ++ return super().tearDown() ++ + + @unittest.skipUnless(hasattr(tasks, '_CTask'), + 'requires the C _asyncio module') + class EagerCTaskTests(BaseEagerTaskFactoryTests, test_utils.TestCase): + Task = getattr(tasks, '_CTask', None) + ++ def setUp(self): ++ self._current_task = asyncio.current_task ++ asyncio.current_task = asyncio.tasks.current_task = asyncio.tasks._c_current_task ++ return super().setUp() ++ ++ def tearDown(self): ++ asyncio.current_task = asyncio.tasks.current_task = self._current_task ++ return super().tearDown() ++ + if __name__ == '__main__': + unittest.main() +diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py +index 2ab638dc527..3838993fa8c 100644 +--- a/Lib/test/test_asyncio/test_events.py ++++ b/Lib/test/test_asyncio/test_events.py +@@ -36,10 +36,10 @@ + from test.support import socket_helper + from test.support import threading_helper + from test.support import ALWAYS_EQ, LARGEST, SMALLEST +- ++from test.support import warnings_helper + + def tearDownModule(): +- asyncio.set_event_loop_policy(None) ++ asyncio._set_event_loop_policy(None) + + + def broken_unix_getsockname(): +@@ -58,7 +58,7 @@ + return 'hello' + + loop = asyncio.new_event_loop() +- asyncio.set_event_loop(loop) ++ asyncio._set_event_loop(loop) + return loop.run_until_complete(doit()) + + +@@ -353,6 +353,124 @@ + t.join() + self.assertEqual(results, ['hello', 'world']) + ++ def test_call_soon_threadsafe_handle_block_check_cancelled(self): ++ results = [] ++ ++ callback_started = threading.Event() ++ callback_finished = threading.Event() ++ def callback(arg): ++ callback_started.set() ++ results.append(arg) ++ time.sleep(1) ++ callback_finished.set() ++ ++ def run_in_thread(): ++ handle = self.loop.call_soon_threadsafe(callback, 'hello') ++ self.assertIsInstance(handle, events._ThreadSafeHandle) ++ callback_started.wait() ++ # callback started so it should block checking for cancellation ++ # until it finishes ++ self.assertFalse(handle.cancelled()) ++ self.assertTrue(callback_finished.is_set()) ++ self.loop.call_soon_threadsafe(self.loop.stop) ++ ++ t = threading.Thread(target=run_in_thread) ++ t.start() ++ ++ self.loop.run_forever() ++ t.join() ++ self.assertEqual(results, ['hello']) ++ ++ def test_call_soon_threadsafe_handle_block_cancellation(self): ++ results = [] ++ ++ callback_started = threading.Event() ++ callback_finished = threading.Event() ++ def callback(arg): ++ callback_started.set() ++ results.append(arg) ++ time.sleep(1) ++ callback_finished.set() ++ ++ def run_in_thread(): ++ handle = self.loop.call_soon_threadsafe(callback, 'hello') ++ self.assertIsInstance(handle, events._ThreadSafeHandle) ++ callback_started.wait() ++ # callback started so it cannot be cancelled from other thread until ++ # it finishes ++ handle.cancel() ++ self.assertTrue(callback_finished.is_set()) ++ self.loop.call_soon_threadsafe(self.loop.stop) ++ ++ t = threading.Thread(target=run_in_thread) ++ t.start() ++ ++ self.loop.run_forever() ++ t.join() ++ self.assertEqual(results, ['hello']) ++ ++ def test_call_soon_threadsafe_handle_cancel_same_thread(self): ++ results = [] ++ callback_started = threading.Event() ++ callback_finished = threading.Event() ++ ++ fut = concurrent.futures.Future() ++ def callback(arg): ++ callback_started.set() ++ handle = fut.result() ++ handle.cancel() ++ results.append(arg) ++ callback_finished.set() ++ self.loop.stop() ++ ++ def run_in_thread(): ++ handle = self.loop.call_soon_threadsafe(callback, 'hello') ++ fut.set_result(handle) ++ self.assertIsInstance(handle, events._ThreadSafeHandle) ++ callback_started.wait() ++ # callback cancels itself from same thread so it has no effect ++ # it runs to completion ++ self.assertTrue(handle.cancelled()) ++ self.assertTrue(callback_finished.is_set()) ++ self.loop.call_soon_threadsafe(self.loop.stop) ++ ++ t = threading.Thread(target=run_in_thread) ++ t.start() ++ ++ self.loop.run_forever() ++ t.join() ++ self.assertEqual(results, ['hello']) ++ ++ def test_call_soon_threadsafe_handle_cancel_other_thread(self): ++ results = [] ++ ev = threading.Event() ++ ++ callback_finished = threading.Event() ++ def callback(arg): ++ results.append(arg) ++ callback_finished.set() ++ self.loop.stop() ++ ++ def run_in_thread(): ++ handle = self.loop.call_soon_threadsafe(callback, 'hello') ++ # handle can be cancelled from other thread if not started yet ++ self.assertIsInstance(handle, events._ThreadSafeHandle) ++ handle.cancel() ++ self.assertTrue(handle.cancelled()) ++ self.assertFalse(callback_finished.is_set()) ++ ev.set() ++ self.loop.call_soon_threadsafe(self.loop.stop) ++ ++ # block the main loop until the callback is added and cancelled in the ++ # other thread ++ self.loop.call_soon(ev.wait) ++ t = threading.Thread(target=run_in_thread) ++ t.start() ++ self.loop.run_forever() ++ t.join() ++ self.assertEqual(results, []) ++ self.assertFalse(callback_finished.is_set()) ++ + def test_call_soon_threadsafe_same_thread(self): + results = [] + +@@ -2066,7 +2184,7 @@ + + transp.close() + self.assertEqual(b'OUT:test', proto.data[1]) +- self.assertTrue(proto.data[2].startswith(b'ERR:test'), proto.data[2]) ++ self.assertStartsWith(proto.data[2], b'ERR:test') + self.assertEqual(0, proto.returncode) + + @support.requires_subprocess() +@@ -2088,8 +2206,7 @@ + + stdin.write(b'test') + self.loop.run_until_complete(proto.completed) +- self.assertTrue(proto.data[1].startswith(b'OUT:testERR:test'), +- proto.data[1]) ++ self.assertStartsWith(proto.data[1], b'OUT:testERR:test') + self.assertEqual(b'', proto.data[2]) + + transp.close() +@@ -2397,7 +2514,7 @@ + self.assertRegex(repr(h), regex) + + def test_handle_source_traceback(self): +- loop = asyncio.get_event_loop_policy().new_event_loop() ++ loop = asyncio.new_event_loop() + loop.set_debug(True) + self.set_event_loop(loop) + +@@ -2695,14 +2812,34 @@ + + class PolicyTests(unittest.TestCase): + ++ def test_asyncio_set_event_loop_deprecation(self): ++ with self.assertWarnsRegex( ++ DeprecationWarning, "'asyncio.set_event_loop' is deprecated"): ++ loop = asyncio.new_event_loop() ++ asyncio.set_event_loop(loop) ++ self.assertIs(loop, asyncio.get_event_loop()) ++ loop.close() ++ ++ def test_abstract_event_loop_policy_deprecation(self): ++ with self.assertWarnsRegex( ++ DeprecationWarning, "'asyncio.AbstractEventLoopPolicy' is deprecated"): ++ policy = asyncio.AbstractEventLoopPolicy() ++ self.assertIsInstance(policy, asyncio.AbstractEventLoopPolicy) ++ ++ def test_default_event_loop_policy_deprecation(self): ++ with self.assertWarnsRegex( ++ DeprecationWarning, "'asyncio.DefaultEventLoopPolicy' is deprecated"): ++ policy = asyncio.DefaultEventLoopPolicy() ++ self.assertIsInstance(policy, asyncio.DefaultEventLoopPolicy) ++ + def test_event_loop_policy(self): +- policy = asyncio.AbstractEventLoopPolicy() ++ policy = asyncio._AbstractEventLoopPolicy() + self.assertRaises(NotImplementedError, policy.get_event_loop) + self.assertRaises(NotImplementedError, policy.set_event_loop, object()) + self.assertRaises(NotImplementedError, policy.new_event_loop) + + def test_get_event_loop(self): +- policy = asyncio.DefaultEventLoopPolicy() ++ policy = asyncio._DefaultEventLoopPolicy() + self.assertIsNone(policy._local._loop) + + with self.assertRaises(RuntimeError): +@@ -2710,7 +2847,7 @@ + self.assertIsNone(policy._local._loop) + + def test_get_event_loop_does_not_call_set_event_loop(self): +- policy = asyncio.DefaultEventLoopPolicy() ++ policy = asyncio._DefaultEventLoopPolicy() + + with mock.patch.object( + policy, "set_event_loop", +@@ -2722,7 +2859,7 @@ + m_set_event_loop.assert_not_called() + + def test_get_event_loop_after_set_none(self): +- policy = asyncio.DefaultEventLoopPolicy() ++ policy = asyncio._DefaultEventLoopPolicy() + policy.set_event_loop(None) + self.assertRaises(RuntimeError, policy.get_event_loop) + +@@ -2730,7 +2867,7 @@ + def test_get_event_loop_thread(self, m_current_thread): + + def f(): +- policy = asyncio.DefaultEventLoopPolicy() ++ policy = asyncio._DefaultEventLoopPolicy() + self.assertRaises(RuntimeError, policy.get_event_loop) + + th = threading.Thread(target=f) +@@ -2738,14 +2875,14 @@ + th.join() + + def test_new_event_loop(self): +- policy = asyncio.DefaultEventLoopPolicy() ++ policy = asyncio._DefaultEventLoopPolicy() + + loop = policy.new_event_loop() + self.assertIsInstance(loop, asyncio.AbstractEventLoop) + loop.close() + + def test_set_event_loop(self): +- policy = asyncio.DefaultEventLoopPolicy() ++ policy = asyncio._DefaultEventLoopPolicy() + old_loop = policy.new_event_loop() + policy.set_event_loop(old_loop) + +@@ -2759,20 +2896,31 @@ + old_loop.close() + + def test_get_event_loop_policy(self): +- policy = asyncio.get_event_loop_policy() +- self.assertIsInstance(policy, asyncio.AbstractEventLoopPolicy) +- self.assertIs(policy, asyncio.get_event_loop_policy()) ++ with self.assertWarnsRegex( ++ DeprecationWarning, "'asyncio.get_event_loop_policy' is deprecated"): ++ policy = asyncio.get_event_loop_policy() ++ self.assertIsInstance(policy, asyncio._AbstractEventLoopPolicy) ++ self.assertIs(policy, asyncio.get_event_loop_policy()) + + def test_set_event_loop_policy(self): +- self.assertRaises( +- TypeError, asyncio.set_event_loop_policy, object()) ++ with self.assertWarnsRegex( ++ DeprecationWarning, "'asyncio.set_event_loop_policy' is deprecated"): ++ self.assertRaises( ++ TypeError, asyncio.set_event_loop_policy, object()) + +- old_policy = asyncio.get_event_loop_policy() ++ with self.assertWarnsRegex( ++ DeprecationWarning, "'asyncio.get_event_loop_policy' is deprecated"): ++ old_policy = asyncio.get_event_loop_policy() + +- policy = asyncio.DefaultEventLoopPolicy() +- asyncio.set_event_loop_policy(policy) +- self.assertIs(policy, asyncio.get_event_loop_policy()) +- self.assertIsNot(policy, old_policy) ++ policy = asyncio._DefaultEventLoopPolicy() ++ with self.assertWarnsRegex( ++ DeprecationWarning, "'asyncio.set_event_loop_policy' is deprecated"): ++ asyncio.set_event_loop_policy(policy) ++ ++ with self.assertWarnsRegex( ++ DeprecationWarning, "'asyncio.get_event_loop_policy' is deprecated"): ++ self.assertIs(policy, asyncio.get_event_loop_policy()) ++ self.assertIsNot(policy, old_policy) + + + class GetEventLoopTestsMixin: +@@ -2782,11 +2930,16 @@ + get_running_loop_impl = None + get_event_loop_impl = None + ++ Task = None ++ Future = None ++ + def setUp(self): + self._get_running_loop_saved = events._get_running_loop + self._set_running_loop_saved = events._set_running_loop + self.get_running_loop_saved = events.get_running_loop + self.get_event_loop_saved = events.get_event_loop ++ self._Task_saved = asyncio.Task ++ self._Future_saved = asyncio.Future + + events._get_running_loop = type(self)._get_running_loop_impl + events._set_running_loop = type(self)._set_running_loop_impl +@@ -2798,17 +2951,19 @@ + asyncio.get_running_loop = type(self).get_running_loop_impl + asyncio.get_event_loop = type(self).get_event_loop_impl + ++ asyncio.Task = asyncio.tasks.Task = type(self).Task ++ asyncio.Future = asyncio.futures.Future = type(self).Future + super().setUp() + + self.loop = asyncio.new_event_loop() +- asyncio.set_event_loop(self.loop) ++ asyncio._set_event_loop(self.loop) + + def tearDown(self): + try: + super().tearDown() + finally: + self.loop.close() +- asyncio.set_event_loop(None) ++ asyncio._set_event_loop(None) + + events._get_running_loop = self._get_running_loop_saved + events._set_running_loop = self._set_running_loop_saved +@@ -2820,8 +2975,10 @@ + asyncio.get_running_loop = self.get_running_loop_saved + asyncio.get_event_loop = self.get_event_loop_saved + +- if sys.platform != 'win32': ++ asyncio.Task = asyncio.tasks.Task = self._Task_saved ++ asyncio.Future = asyncio.futures.Future = self._Future_saved + ++ if sys.platform != 'win32': + def test_get_event_loop_new_process(self): + # bpo-32126: The multiprocessing module used by + # ProcessPoolExecutor is not functional when the +@@ -2851,18 +3008,18 @@ + class TestError(Exception): + pass + +- class Policy(asyncio.DefaultEventLoopPolicy): ++ class Policy(asyncio._DefaultEventLoopPolicy): + def get_event_loop(self): + raise TestError + +- old_policy = asyncio.get_event_loop_policy() ++ old_policy = asyncio._get_event_loop_policy() + try: +- asyncio.set_event_loop_policy(Policy()) ++ asyncio._set_event_loop_policy(Policy()) + loop = asyncio.new_event_loop() + + with self.assertRaises(TestError): + asyncio.get_event_loop() +- asyncio.set_event_loop(None) ++ asyncio._set_event_loop(None) + with self.assertRaises(TestError): + asyncio.get_event_loop() + +@@ -2877,15 +3034,15 @@ + + loop.run_until_complete(func()) + +- asyncio.set_event_loop(loop) ++ asyncio._set_event_loop(loop) + with self.assertRaises(TestError): + asyncio.get_event_loop() +- asyncio.set_event_loop(None) ++ asyncio._set_event_loop(None) + with self.assertRaises(TestError): + asyncio.get_event_loop() + + finally: +- asyncio.set_event_loop_policy(old_policy) ++ asyncio._set_event_loop_policy(old_policy) + if loop is not None: + loop.close() + +@@ -2895,16 +3052,16 @@ + self.assertIs(asyncio._get_running_loop(), None) + + def test_get_event_loop_returns_running_loop2(self): +- old_policy = asyncio.get_event_loop_policy() ++ old_policy = asyncio._get_event_loop_policy() + try: +- asyncio.set_event_loop_policy(asyncio.DefaultEventLoopPolicy()) ++ asyncio._set_event_loop_policy(asyncio._DefaultEventLoopPolicy()) + loop = asyncio.new_event_loop() + self.addCleanup(loop.close) + + with self.assertRaisesRegex(RuntimeError, 'no current'): + asyncio.get_event_loop() + +- asyncio.set_event_loop(None) ++ asyncio._set_event_loop(None) + with self.assertRaisesRegex(RuntimeError, 'no current'): + asyncio.get_event_loop() + +@@ -2915,15 +3072,15 @@ + + loop.run_until_complete(func()) + +- asyncio.set_event_loop(loop) ++ asyncio._set_event_loop(loop) + self.assertIs(asyncio.get_event_loop(), loop) + +- asyncio.set_event_loop(None) ++ asyncio._set_event_loop(None) + with self.assertRaisesRegex(RuntimeError, 'no current'): + asyncio.get_event_loop() + + finally: +- asyncio.set_event_loop_policy(old_policy) ++ asyncio._set_event_loop_policy(old_policy) + if loop is not None: + loop.close() + +@@ -2940,6 +3097,8 @@ + get_running_loop_impl = events._py_get_running_loop + get_event_loop_impl = events._py_get_event_loop + ++ Task = asyncio.tasks._PyTask ++ Future = asyncio.futures._PyFuture + + try: + import _asyncio # NoQA +@@ -2954,6 +3113,8 @@ + get_running_loop_impl = events._c_get_running_loop + get_event_loop_impl = events._c_get_event_loop + ++ Task = asyncio.tasks._CTask ++ Future = asyncio.futures._CFuture + + class TestServer(unittest.TestCase): + +--- /dev/null ++++ b/Lib/test/test_asyncio/test_free_threading.py +@@ -0,0 +1,211 @@ ++import asyncio ++import threading ++import unittest ++from threading import Thread ++from unittest import TestCase ++import weakref ++from test import support ++from test.support import threading_helper ++ ++threading_helper.requires_working_threading(module=True) ++ ++ ++class MyException(Exception): ++ pass ++ ++ ++def tearDownModule(): ++ asyncio._set_event_loop_policy(None) ++ ++ ++class TestFreeThreading: ++ def test_all_tasks_race(self) -> None: ++ async def main(): ++ loop = asyncio.get_running_loop() ++ future = loop.create_future() ++ ++ async def coro(): ++ await future ++ ++ tasks = set() ++ ++ async with asyncio.TaskGroup() as tg: ++ for _ in range(100): ++ tasks.add(tg.create_task(coro())) ++ ++ all_tasks = self.all_tasks(loop) ++ self.assertEqual(len(all_tasks), 101) ++ ++ for task in all_tasks: ++ self.assertEqual(task.get_loop(), loop) ++ self.assertFalse(task.done()) ++ ++ current = asyncio.current_task() ++ self.assertEqual(current.get_loop(), loop) ++ self.assertSetEqual(all_tasks, tasks | {current}) ++ future.set_result(None) ++ ++ def runner(): ++ with asyncio.Runner() as runner: ++ loop = runner.get_loop() ++ loop.set_task_factory(self.factory) ++ runner.run(main()) ++ ++ threads = [] ++ ++ for _ in range(10): ++ thread = Thread(target=runner) ++ threads.append(thread) ++ ++ with threading_helper.start_threads(threads): ++ pass ++ ++ def test_all_tasks_different_thread(self) -> None: ++ loop = None ++ started = threading.Event() ++ done = threading.Event() # used for main task not finishing early ++ async def coro(): ++ await asyncio.Future() ++ ++ lock = threading.Lock() ++ tasks = set() ++ ++ async def main(): ++ nonlocal tasks, loop ++ loop = asyncio.get_running_loop() ++ started.set() ++ for i in range(1000): ++ with lock: ++ asyncio.create_task(coro()) ++ tasks = self.all_tasks(loop) ++ done.wait() ++ ++ runner = threading.Thread(target=lambda: asyncio.run(main())) ++ ++ def check(): ++ started.wait() ++ with lock: ++ self.assertSetEqual(tasks & self.all_tasks(loop), tasks) ++ ++ threads = [threading.Thread(target=check) for _ in range(10)] ++ runner.start() ++ ++ with threading_helper.start_threads(threads): ++ pass ++ ++ done.set() ++ runner.join() ++ ++ def test_task_different_thread_finalized(self) -> None: ++ task = None ++ async def func(): ++ nonlocal task ++ task = asyncio.current_task() ++ def runner(): ++ with asyncio.Runner() as runner: ++ loop = runner.get_loop() ++ loop.set_task_factory(self.factory) ++ runner.run(func()) ++ thread = Thread(target=runner) ++ thread.start() ++ thread.join() ++ wr = weakref.ref(task) ++ del thread ++ del task ++ # task finalization in different thread shouldn't crash ++ support.gc_collect() ++ self.assertIsNone(wr()) ++ ++ def test_run_coroutine_threadsafe(self) -> None: ++ results = [] ++ ++ def in_thread(loop: asyncio.AbstractEventLoop): ++ coro = asyncio.sleep(0.1, result=42) ++ fut = asyncio.run_coroutine_threadsafe(coro, loop) ++ result = fut.result() ++ self.assertEqual(result, 42) ++ results.append(result) ++ ++ async def main(): ++ loop = asyncio.get_running_loop() ++ async with asyncio.TaskGroup() as tg: ++ for _ in range(10): ++ tg.create_task(asyncio.to_thread(in_thread, loop)) ++ self.assertEqual(results, [42] * 10) ++ ++ with asyncio.Runner() as r: ++ loop = r.get_loop() ++ loop.set_task_factory(self.factory) ++ r.run(main()) ++ ++ def test_run_coroutine_threadsafe_exception(self) -> None: ++ async def coro(): ++ await asyncio.sleep(0) ++ raise MyException("test") ++ ++ def in_thread(loop: asyncio.AbstractEventLoop): ++ fut = asyncio.run_coroutine_threadsafe(coro(), loop) ++ return fut.result() ++ ++ async def main(): ++ loop = asyncio.get_running_loop() ++ tasks = [] ++ for _ in range(10): ++ task = loop.create_task(asyncio.to_thread(in_thread, loop)) ++ tasks.append(task) ++ results = await asyncio.gather(*tasks, return_exceptions=True) ++ ++ self.assertEqual(len(results), 10) ++ for result in results: ++ self.assertIsInstance(result, MyException) ++ self.assertEqual(str(result), "test") ++ ++ with asyncio.Runner() as r: ++ loop = r.get_loop() ++ loop.set_task_factory(self.factory) ++ r.run(main()) ++ ++ ++class TestPyFreeThreading(TestFreeThreading, TestCase): ++ all_tasks = staticmethod(asyncio.tasks._py_all_tasks) ++ ++ def setUp(self): ++ self._old_current_task = asyncio.current_task ++ asyncio.current_task = asyncio.tasks.current_task = asyncio.tasks._py_current_task ++ return super().setUp() ++ ++ def tearDown(self): ++ asyncio.current_task = asyncio.tasks.current_task = self._old_current_task ++ return super().tearDown() ++ ++ def factory(self, loop, coro, **kwargs): ++ return asyncio.tasks._PyTask(coro, loop=loop, **kwargs) ++ ++ ++@unittest.skipUnless(hasattr(asyncio.tasks, "_c_all_tasks"), "requires _asyncio") ++class TestCFreeThreading(TestFreeThreading, TestCase): ++ all_tasks = staticmethod(getattr(asyncio.tasks, "_c_all_tasks", None)) ++ ++ def setUp(self): ++ self._old_current_task = asyncio.current_task ++ asyncio.current_task = asyncio.tasks.current_task = asyncio.tasks._c_current_task ++ return super().setUp() ++ ++ def tearDown(self): ++ asyncio.current_task = asyncio.tasks.current_task = self._old_current_task ++ return super().tearDown() ++ ++ ++ def factory(self, loop, coro, **kwargs): ++ return asyncio.tasks._CTask(coro, loop=loop, **kwargs) ++ ++ ++class TestEagerPyFreeThreading(TestPyFreeThreading): ++ def factory(self, loop, coro, eager_start=True, **kwargs): ++ return asyncio.tasks._PyTask(coro, loop=loop, **kwargs, eager_start=eager_start) ++ ++ ++@unittest.skipUnless(hasattr(asyncio.tasks, "_c_all_tasks"), "requires _asyncio") ++class TestEagerCFreeThreading(TestCFreeThreading, TestCase): ++ def factory(self, loop, coro, eager_start=True, **kwargs): ++ return asyncio.tasks._CTask(coro, loop=loop, **kwargs, eager_start=eager_start) +diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py +index 3a4291e3a68..01d6230e6dd 100644 +--- a/Lib/test/test_asyncio/test_futures.py ++++ b/Lib/test/test_asyncio/test_futures.py +@@ -17,7 +17,7 @@ + + + def tearDownModule(): +- asyncio.set_event_loop_policy(None) ++ asyncio._set_event_loop_policy(None) + + + def _fakefunc(f): +@@ -178,8 +178,8 @@ + + def test_constructor_use_global_loop(self): + # Deprecated in 3.10, undeprecated in 3.12 +- asyncio.set_event_loop(self.loop) +- self.addCleanup(asyncio.set_event_loop, None) ++ asyncio._set_event_loop(self.loop) ++ self.addCleanup(asyncio._set_event_loop, None) + f = self._new_future() + self.assertIs(f._loop, self.loop) + self.assertIs(f.get_loop(), self.loop) +@@ -242,7 +242,7 @@ + + def test_future_cancel_message_getter(self): + f = self._new_future(loop=self.loop) +- self.assertTrue(hasattr(f, '_cancel_message')) ++ self.assertHasAttr(f, '_cancel_message') + self.assertEqual(f._cancel_message, None) + + f.cancel('my message') +@@ -566,8 +566,8 @@ + + def test_wrap_future_use_global_loop(self): + # Deprecated in 3.10, undeprecated in 3.12 +- asyncio.set_event_loop(self.loop) +- self.addCleanup(asyncio.set_event_loop, None) ++ asyncio._set_event_loop(self.loop) ++ self.addCleanup(asyncio._set_event_loop, None) + def run(arg): + return (arg, threading.get_ident()) + ex = concurrent.futures.ThreadPoolExecutor(1) +diff --git a/Lib/test/test_asyncio/test_futures2.py b/Lib/test/test_asyncio/test_futures2.py +index b7cfffb76bd..e2cddea01ec 100644 +--- a/Lib/test/test_asyncio/test_futures2.py ++++ b/Lib/test/test_asyncio/test_futures2.py +@@ -7,7 +7,7 @@ + + + def tearDownModule(): +- asyncio.set_event_loop_policy(None) ++ asyncio._set_event_loop_policy(None) + + + class FutureTests: +--- /dev/null ++++ b/Lib/test/test_asyncio/test_graph.py +@@ -0,0 +1,445 @@ ++import asyncio ++import io ++import unittest ++ ++ ++# To prevent a warning "test altered the execution environment" ++def tearDownModule(): ++ asyncio._set_event_loop_policy(None) ++ ++ ++def capture_test_stack(*, fut=None, depth=1): ++ ++ def walk(s): ++ ret = [ ++ (f"T<{n}>" if '-' not in (n := s.future.get_name()) else 'T') ++ if isinstance(s.future, asyncio.Task) else 'F' ++ ] ++ ++ ret.append( ++ [ ++ ( ++ f"s {entry.frame.f_code.co_name}" ++ if entry.frame.f_generator is None else ++ ( ++ f"a {entry.frame.f_generator.cr_code.co_name}" ++ if hasattr(entry.frame.f_generator, 'cr_code') else ++ f"ag {entry.frame.f_generator.ag_code.co_name}" ++ ) ++ ) for entry in s.call_stack ++ ] ++ ) ++ ++ ret.append( ++ sorted([ ++ walk(ab) for ab in s.awaited_by ++ ], key=lambda entry: entry[0]) ++ ) ++ ++ return ret ++ ++ buf = io.StringIO() ++ asyncio.print_call_graph(fut, file=buf, depth=depth+1) ++ ++ stack = asyncio.capture_call_graph(fut, depth=depth) ++ return walk(stack), buf.getvalue() ++ ++ ++class CallStackTestBase: ++ ++ async def test_stack_tgroup(self): ++ ++ stack_for_c5 = None ++ ++ def c5(): ++ nonlocal stack_for_c5 ++ stack_for_c5 = capture_test_stack(depth=2) ++ ++ async def c4(): ++ await asyncio.sleep(0) ++ c5() ++ ++ async def c3(): ++ await c4() ++ ++ async def c2(): ++ await c3() ++ ++ async def c1(task): ++ await task ++ ++ async def main(): ++ async with asyncio.TaskGroup() as tg: ++ task = tg.create_task(c2(), name="c2_root") ++ tg.create_task(c1(task), name="sub_main_1") ++ tg.create_task(c1(task), name="sub_main_2") ++ ++ await main() ++ ++ self.assertEqual(stack_for_c5[0], [ ++ # task name ++ 'T', ++ # call stack ++ ['s c5', 'a c4', 'a c3', 'a c2'], ++ # awaited by ++ [ ++ ['T', ++ ['a _aexit', 'a __aexit__', 'a main', 'a test_stack_tgroup'], [] ++ ], ++ ['T', ++ ['a c1'], ++ [ ++ ['T', ++ ['a _aexit', 'a __aexit__', 'a main', 'a test_stack_tgroup'], [] ++ ] ++ ] ++ ], ++ ['T', ++ ['a c1'], ++ [ ++ ['T', ++ ['a _aexit', 'a __aexit__', 'a main', 'a test_stack_tgroup'], [] ++ ] ++ ] ++ ] ++ ] ++ ]) ++ ++ self.assertIn( ++ ' async CallStackTestBase.test_stack_tgroup()', ++ stack_for_c5[1]) ++ ++ ++ async def test_stack_async_gen(self): ++ ++ stack_for_gen_nested_call = None ++ ++ async def gen_nested_call(): ++ nonlocal stack_for_gen_nested_call ++ stack_for_gen_nested_call = capture_test_stack() ++ ++ async def gen(): ++ for num in range(2): ++ yield num ++ if num == 1: ++ await gen_nested_call() ++ ++ async def main(): ++ async for el in gen(): ++ pass ++ ++ await main() ++ ++ self.assertEqual(stack_for_gen_nested_call[0], [ ++ 'T', ++ [ ++ 's capture_test_stack', ++ 'a gen_nested_call', ++ 'ag gen', ++ 'a main', ++ 'a test_stack_async_gen' ++ ], ++ [] ++ ]) ++ ++ self.assertIn( ++ 'async generator CallStackTestBase.test_stack_async_gen..gen()', ++ stack_for_gen_nested_call[1]) ++ ++ async def test_stack_gather(self): ++ ++ stack_for_deep = None ++ ++ async def deep(): ++ await asyncio.sleep(0) ++ nonlocal stack_for_deep ++ stack_for_deep = capture_test_stack() ++ ++ async def c1(): ++ await asyncio.sleep(0) ++ await deep() ++ ++ async def c2(): ++ await asyncio.sleep(0) ++ ++ async def main(): ++ await asyncio.gather(c1(), c2()) ++ ++ await main() ++ ++ self.assertEqual(stack_for_deep[0], [ ++ 'T', ++ ['s capture_test_stack', 'a deep', 'a c1'], ++ [ ++ ['T', ['a main', 'a test_stack_gather'], []] ++ ] ++ ]) ++ ++ async def test_stack_shield(self): ++ ++ stack_for_shield = None ++ ++ async def deep(): ++ await asyncio.sleep(0) ++ nonlocal stack_for_shield ++ stack_for_shield = capture_test_stack() ++ ++ async def c1(): ++ await asyncio.sleep(0) ++ await deep() ++ ++ async def main(): ++ await asyncio.shield(c1()) ++ ++ await main() ++ ++ self.assertEqual(stack_for_shield[0], [ ++ 'T', ++ ['s capture_test_stack', 'a deep', 'a c1'], ++ [ ++ ['T', ['a main', 'a test_stack_shield'], []] ++ ] ++ ]) ++ ++ async def test_stack_timeout(self): ++ ++ stack_for_inner = None ++ ++ async def inner(): ++ await asyncio.sleep(0) ++ nonlocal stack_for_inner ++ stack_for_inner = capture_test_stack() ++ ++ async def c1(): ++ async with asyncio.timeout(1): ++ await asyncio.sleep(0) ++ await inner() ++ ++ async def main(): ++ await asyncio.shield(c1()) ++ ++ await main() ++ ++ self.assertEqual(stack_for_inner[0], [ ++ 'T', ++ ['s capture_test_stack', 'a inner', 'a c1'], ++ [ ++ ['T', ['a main', 'a test_stack_timeout'], []] ++ ] ++ ]) ++ ++ async def test_stack_wait(self): ++ ++ stack_for_inner = None ++ ++ async def inner(): ++ await asyncio.sleep(0) ++ nonlocal stack_for_inner ++ stack_for_inner = capture_test_stack() ++ ++ async def c1(): ++ async with asyncio.timeout(1): ++ await asyncio.sleep(0) ++ await inner() ++ ++ async def c2(): ++ for i in range(3): ++ await asyncio.sleep(0) ++ ++ async def main(t1, t2): ++ while True: ++ _, pending = await asyncio.wait([t1, t2]) ++ if not pending: ++ break ++ ++ t1 = asyncio.create_task(c1()) ++ t2 = asyncio.create_task(c2()) ++ try: ++ await main(t1, t2) ++ finally: ++ await t1 ++ await t2 ++ ++ self.assertEqual(stack_for_inner[0], [ ++ 'T', ++ ['s capture_test_stack', 'a inner', 'a c1'], ++ [ ++ ['T', ++ ['a _wait', 'a wait', 'a main', 'a test_stack_wait'], ++ [] ++ ] ++ ] ++ ]) ++ ++ async def test_stack_task(self): ++ ++ stack_for_inner = None ++ ++ async def inner(): ++ await asyncio.sleep(0) ++ nonlocal stack_for_inner ++ stack_for_inner = capture_test_stack() ++ ++ async def c1(): ++ await inner() ++ ++ async def c2(): ++ await asyncio.create_task(c1(), name='there there') ++ ++ async def main(): ++ await c2() ++ ++ await main() ++ ++ self.assertEqual(stack_for_inner[0], [ ++ 'T', ++ ['s capture_test_stack', 'a inner', 'a c1'], ++ [['T', ['a c2', 'a main', 'a test_stack_task'], []]] ++ ]) ++ ++ async def test_stack_future(self): ++ ++ stack_for_fut = None ++ ++ async def a2(fut): ++ await fut ++ ++ async def a1(fut): ++ await a2(fut) ++ ++ async def b1(fut): ++ await fut ++ ++ async def main(): ++ nonlocal stack_for_fut ++ ++ fut = asyncio.Future() ++ async with asyncio.TaskGroup() as g: ++ g.create_task(a1(fut), name="task A") ++ g.create_task(b1(fut), name='task B') ++ ++ for _ in range(5): ++ # Do a few iterations to ensure that both a1 and b1 ++ # await on the future ++ await asyncio.sleep(0) ++ ++ stack_for_fut = capture_test_stack(fut=fut) ++ fut.set_result(None) ++ ++ await main() ++ ++ self.assertEqual(stack_for_fut[0], ++ ['F', ++ [], ++ [ ++ ['T', ++ ['a a2', 'a a1'], ++ [['T', ['a test_stack_future'], []]] ++ ], ++ ['T', ++ ['a b1'], ++ [['T', ['a test_stack_future'], []]] ++ ], ++ ]] ++ ) ++ ++ self.assertTrue(stack_for_fut[1].startswith('* Future(id=')) ++ ++ ++@unittest.skipIf( ++ not hasattr(asyncio.futures, "_c_future_add_to_awaited_by"), ++ "C-accelerated asyncio call graph backend missing", ++) ++class TestCallStackC(CallStackTestBase, unittest.IsolatedAsyncioTestCase): ++ def setUp(self): ++ futures = asyncio.futures ++ tasks = asyncio.tasks ++ ++ self._Future = asyncio.Future ++ asyncio.Future = futures.Future = futures._CFuture ++ ++ self._Task = asyncio.Task ++ asyncio.Task = tasks.Task = tasks._CTask ++ ++ self._future_add_to_awaited_by = asyncio.future_add_to_awaited_by ++ futures.future_add_to_awaited_by = futures._c_future_add_to_awaited_by ++ asyncio.future_add_to_awaited_by = futures.future_add_to_awaited_by ++ ++ self._future_discard_from_awaited_by = asyncio.future_discard_from_awaited_by ++ futures.future_discard_from_awaited_by = futures._c_future_discard_from_awaited_by ++ asyncio.future_discard_from_awaited_by = futures.future_discard_from_awaited_by ++ ++ self._current_task = asyncio.current_task ++ asyncio.current_task = asyncio.tasks.current_task = tasks._c_current_task ++ ++ def tearDown(self): ++ futures = asyncio.futures ++ tasks = asyncio.tasks ++ ++ futures.future_discard_from_awaited_by = self._future_discard_from_awaited_by ++ asyncio.future_discard_from_awaited_by = self._future_discard_from_awaited_by ++ del self._future_discard_from_awaited_by ++ ++ futures.future_add_to_awaited_by = self._future_add_to_awaited_by ++ asyncio.future_add_to_awaited_by = self._future_add_to_awaited_by ++ del self._future_add_to_awaited_by ++ ++ asyncio.Task = self._Task ++ tasks.Task = self._Task ++ del self._Task ++ ++ asyncio.Future = self._Future ++ futures.Future = self._Future ++ del self._Future ++ ++ asyncio.current_task = asyncio.tasks.current_task = self._current_task ++ ++ ++@unittest.skipIf( ++ not hasattr(asyncio.futures, "_py_future_add_to_awaited_by"), ++ "Pure Python asyncio call graph backend missing", ++) ++class TestCallStackPy(CallStackTestBase, unittest.IsolatedAsyncioTestCase): ++ def setUp(self): ++ futures = asyncio.futures ++ tasks = asyncio.tasks ++ ++ self._Future = asyncio.Future ++ asyncio.Future = futures.Future = futures._PyFuture ++ ++ self._Task = asyncio.Task ++ asyncio.Task = tasks.Task = tasks._PyTask ++ ++ self._future_add_to_awaited_by = asyncio.future_add_to_awaited_by ++ futures.future_add_to_awaited_by = futures._py_future_add_to_awaited_by ++ asyncio.future_add_to_awaited_by = futures.future_add_to_awaited_by ++ ++ self._future_discard_from_awaited_by = asyncio.future_discard_from_awaited_by ++ futures.future_discard_from_awaited_by = futures._py_future_discard_from_awaited_by ++ asyncio.future_discard_from_awaited_by = futures.future_discard_from_awaited_by ++ ++ self._current_task = asyncio.current_task ++ asyncio.current_task = asyncio.tasks.current_task = tasks._py_current_task ++ ++ ++ def tearDown(self): ++ futures = asyncio.futures ++ tasks = asyncio.tasks ++ ++ futures.future_discard_from_awaited_by = self._future_discard_from_awaited_by ++ asyncio.future_discard_from_awaited_by = self._future_discard_from_awaited_by ++ del self._future_discard_from_awaited_by ++ ++ futures.future_add_to_awaited_by = self._future_add_to_awaited_by ++ asyncio.future_add_to_awaited_by = self._future_add_to_awaited_by ++ del self._future_add_to_awaited_by ++ ++ asyncio.Task = self._Task ++ tasks.Task = self._Task ++ del self._Task ++ ++ asyncio.Future = self._Future ++ futures.Future = self._Future ++ del self._Future ++ ++ asyncio.current_task = asyncio.tasks.current_task = self._current_task +diff --git a/Lib/test/test_asyncio/test_locks.py b/Lib/test/test_asyncio/test_locks.py +index c3bff760f73..3bb3e5c4ca0 100644 +--- a/Lib/test/test_asyncio/test_locks.py ++++ b/Lib/test/test_asyncio/test_locks.py +@@ -20,18 +20,18 @@ + + + def tearDownModule(): +- asyncio.set_event_loop_policy(None) ++ asyncio._set_event_loop_policy(None) + + + class LockTests(unittest.IsolatedAsyncioTestCase): + + async def test_repr(self): + lock = asyncio.Lock() +- self.assertTrue(repr(lock).endswith('[unlocked]>')) ++ self.assertEndsWith(repr(lock), '[unlocked]>') + self.assertTrue(RGX_REPR.match(repr(lock))) + + await lock.acquire() +- self.assertTrue(repr(lock).endswith('[locked]>')) ++ self.assertEndsWith(repr(lock), '[locked]>') + self.assertTrue(RGX_REPR.match(repr(lock))) + + async def test_lock(self): +@@ -286,12 +286,12 @@ + + def test_repr(self): + ev = asyncio.Event() +- self.assertTrue(repr(ev).endswith('[unset]>')) ++ self.assertEndsWith(repr(ev), '[unset]>') + match = RGX_REPR.match(repr(ev)) + self.assertEqual(match.group('extras'), 'unset') + + ev.set() +- self.assertTrue(repr(ev).endswith('[set]>')) ++ self.assertEndsWith(repr(ev), '[set]>') + self.assertTrue(RGX_REPR.match(repr(ev))) + + ev._waiters.append(mock.Mock()) +@@ -916,11 +916,11 @@ + + async def test_repr(self): + sem = asyncio.Semaphore() +- self.assertTrue(repr(sem).endswith('[unlocked, value:1]>')) ++ self.assertEndsWith(repr(sem), '[unlocked, value:1]>') + self.assertTrue(RGX_REPR.match(repr(sem))) + + await sem.acquire() +- self.assertTrue(repr(sem).endswith('[locked]>')) ++ self.assertEndsWith(repr(sem), '[locked]>') + self.assertTrue('waiters' not in repr(sem)) + self.assertTrue(RGX_REPR.match(repr(sem))) + +diff --git a/Lib/test/test_asyncio/test_pep492.py b/Lib/test/test_asyncio/test_pep492.py +index 84c5f991295..48f4a75e0fd 100644 +--- a/Lib/test/test_asyncio/test_pep492.py ++++ b/Lib/test/test_asyncio/test_pep492.py +@@ -11,7 +11,7 @@ + + + def tearDownModule(): +- asyncio.set_event_loop_policy(None) ++ asyncio._set_event_loop_policy(None) + + + # Test that asyncio.iscoroutine() uses collections.abc.Coroutine +diff --git a/Lib/test/test_asyncio/test_proactor_events.py b/Lib/test/test_asyncio/test_proactor_events.py +index 4b3d551dd7b..24c4e8546b1 100644 +--- a/Lib/test/test_asyncio/test_proactor_events.py ++++ b/Lib/test/test_asyncio/test_proactor_events.py +@@ -18,7 +18,7 @@ + + + def tearDownModule(): +- asyncio.set_event_loop_policy(None) ++ asyncio._set_event_loop_policy(None) + + + def close_transport(transport): +diff --git a/Lib/test/test_asyncio/test_protocols.py b/Lib/test/test_asyncio/test_protocols.py +index 0f232631867..4484a031988 100644 +--- a/Lib/test/test_asyncio/test_protocols.py ++++ b/Lib/test/test_asyncio/test_protocols.py +@@ -7,7 +7,7 @@ + def tearDownModule(): + # not needed for the test file but added for uniformness with all other + # asyncio test files for the sake of unified cleanup +- asyncio.set_event_loop_policy(None) ++ asyncio._set_event_loop_policy(None) + + + class ProtocolsAbsTests(unittest.TestCase): +@@ -19,7 +19,7 @@ + self.assertIsNone(p.connection_lost(f)) + self.assertIsNone(p.pause_writing()) + self.assertIsNone(p.resume_writing()) +- self.assertFalse(hasattr(p, '__dict__')) ++ self.assertNotHasAttr(p, '__dict__') + + def test_protocol(self): + f = mock.Mock() +@@ -30,7 +30,7 @@ + self.assertIsNone(p.eof_received()) + self.assertIsNone(p.pause_writing()) + self.assertIsNone(p.resume_writing()) +- self.assertFalse(hasattr(p, '__dict__')) ++ self.assertNotHasAttr(p, '__dict__') + + def test_buffered_protocol(self): + f = mock.Mock() +@@ -41,7 +41,7 @@ + self.assertIsNone(p.buffer_updated(150)) + self.assertIsNone(p.pause_writing()) + self.assertIsNone(p.resume_writing()) +- self.assertFalse(hasattr(p, '__dict__')) ++ self.assertNotHasAttr(p, '__dict__') + + def test_datagram_protocol(self): + f = mock.Mock() +@@ -50,7 +50,7 @@ + self.assertIsNone(dp.connection_lost(f)) + self.assertIsNone(dp.error_received(f)) + self.assertIsNone(dp.datagram_received(f, f)) +- self.assertFalse(hasattr(dp, '__dict__')) ++ self.assertNotHasAttr(dp, '__dict__') + + def test_subprocess_protocol(self): + f = mock.Mock() +@@ -60,7 +60,7 @@ + self.assertIsNone(sp.pipe_data_received(1, f)) + self.assertIsNone(sp.pipe_connection_lost(1, f)) + self.assertIsNone(sp.process_exited()) +- self.assertFalse(hasattr(sp, '__dict__')) ++ self.assertNotHasAttr(sp, '__dict__') + + + if __name__ == '__main__': +diff --git a/Lib/test/test_asyncio/test_queues.py b/Lib/test/test_asyncio/test_queues.py +index 5019e9a2935..090b9774c22 100644 +--- a/Lib/test/test_asyncio/test_queues.py ++++ b/Lib/test/test_asyncio/test_queues.py +@@ -6,7 +6,7 @@ + + + def tearDownModule(): +- asyncio.set_event_loop_policy(None) ++ asyncio._set_event_loop_policy(None) + + + class QueueBasicTests(unittest.IsolatedAsyncioTestCase): +@@ -18,7 +18,7 @@ + appear in fn(Queue()). + """ + q = asyncio.Queue() +- self.assertTrue(fn(q).startswith(' None: ++ self.sock = sock ++ ++ def __getattr__(self, name): ++ return getattr(self.sock, name) ++ ++ def send(self, data): ++ # Fake that our write buffer is full, send only half ++ to_send = len(data)//2 ++ return self.sock.send(data[:to_send]) ++ ++ def _fake_full_write_buffer(data): ++ if socket_transport._read_ready_cb is None and not isinstance(socket_transport._sock, SocketWrapper): ++ socket_transport._sock = SocketWrapper(socket_transport._sock) ++ return unittest.mock.DEFAULT ++ ++ with unittest.mock.patch.object( ++ socket_transport, "write", ++ wraps=socket_transport.write, ++ side_effect=_fake_full_write_buffer ++ ): ++ await future ++ ++ writer.close() ++ await self.wait_closed(writer) ++ ++ def run(meth): ++ def wrapper(sock): ++ try: ++ meth(sock) ++ except Exception as ex: ++ self.loop.call_soon_threadsafe(future.set_exception, ex) ++ else: ++ self.loop.call_soon_threadsafe(future.set_result, None) ++ return wrapper ++ ++ with self.tcp_server(run(server)) as srv: ++ self.loop.run_until_complete(client(srv.addr)) ++ ++ with self.tcp_server(run(eof_server)) as srv: ++ self.loop.run_until_complete(client(srv.addr)) ++ + def test_connect_timeout_warning(self): + s = socket.socket(socket.AF_INET) + s.bind(('127.0.0.1', 0)) +diff --git a/Lib/test/test_asyncio/test_sslproto.py b/Lib/test/test_asyncio/test_sslproto.py +index 761904c5146..aa248c5786f 100644 +--- a/Lib/test/test_asyncio/test_sslproto.py ++++ b/Lib/test/test_asyncio/test_sslproto.py +@@ -21,7 +21,7 @@ + + + def tearDownModule(): +- asyncio.set_event_loop_policy(None) ++ asyncio._set_event_loop_policy(None) + + + @unittest.skipIf(ssl is None, 'No ssl module') +diff --git a/Lib/test/test_asyncio/test_staggered.py b/Lib/test/test_asyncio/test_staggered.py +index 74941f704c4..ad34aa6da01 100644 +--- a/Lib/test/test_asyncio/test_staggered.py ++++ b/Lib/test/test_asyncio/test_staggered.py +@@ -8,7 +8,7 @@ + + + def tearDownModule(): +- asyncio.set_event_loop_policy(None) ++ asyncio._set_event_loop_policy(None) + + + class StaggeredTests(unittest.IsolatedAsyncioTestCase): +@@ -122,3 +122,30 @@ + self.assertIsNone(excs[0], None) + self.assertIsInstance(excs[1], asyncio.CancelledError) + self.assertIsInstance(excs[2], asyncio.CancelledError) ++ ++ ++ async def test_cancelled(self): ++ log = [] ++ with self.assertRaises(TimeoutError): ++ async with asyncio.timeout(None) as cs_outer, asyncio.timeout(None) as cs_inner: ++ async def coro_fn(): ++ cs_inner.reschedule(-1) ++ await asyncio.sleep(0) ++ try: ++ await asyncio.sleep(0) ++ except asyncio.CancelledError: ++ log.append("cancelled 1") ++ ++ cs_outer.reschedule(-1) ++ await asyncio.sleep(0) ++ try: ++ await asyncio.sleep(0) ++ except asyncio.CancelledError: ++ log.append("cancelled 2") ++ try: ++ await staggered_race([coro_fn], delay=None) ++ except asyncio.CancelledError: ++ log.append("cancelled 3") ++ raise ++ ++ self.assertListEqual(log, ["cancelled 1", "cancelled 2", "cancelled 3"]) +diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py +index dbe5646c2b7..673c6b46c64 100644 +--- a/Lib/test/test_asyncio/test_streams.py ++++ b/Lib/test/test_asyncio/test_streams.py +@@ -21,7 +21,7 @@ + + + def tearDownModule(): +- asyncio.set_event_loop_policy(None) ++ asyncio._set_event_loop_policy(None) + + + class StreamTests(test_utils.TestCase): +@@ -50,7 +50,7 @@ + self.assertEqual(data, b'HTTP/1.0 200 OK\r\n') + f = reader.read() + data = self.loop.run_until_complete(f) +- self.assertTrue(data.endswith(b'\r\n\r\nTest message')) ++ self.assertEndsWith(data, b'\r\n\r\nTest message') + writer.close() + self.assertEqual(messages, []) + +@@ -71,11 +71,11 @@ + try: + reader, writer = self.loop.run_until_complete(open_connection_fut) + finally: +- asyncio.set_event_loop(None) ++ asyncio._set_event_loop(None) + writer.write(b'GET / HTTP/1.0\r\n\r\n') + f = reader.read() + data = self.loop.run_until_complete(f) +- self.assertTrue(data.endswith(b'\r\n\r\nTest message')) ++ self.assertEndsWith(data, b'\r\n\r\nTest message') + + writer.close() + self.assertEqual(messages, []) +@@ -839,8 +839,8 @@ + # asyncio issue #184: Ensure that StreamReaderProtocol constructor + # retrieves the current loop if the loop parameter is not set + # Deprecated in 3.10, undeprecated in 3.12 +- self.addCleanup(asyncio.set_event_loop, None) +- asyncio.set_event_loop(self.loop) ++ self.addCleanup(asyncio._set_event_loop, None) ++ asyncio._set_event_loop(self.loop) + reader = asyncio.StreamReader() + self.assertIs(reader._loop, self.loop) + +@@ -863,8 +863,8 @@ + # asyncio issue #184: Ensure that StreamReaderProtocol constructor + # retrieves the current loop if the loop parameter is not set + # Deprecated in 3.10, undeprecated in 3.12 +- self.addCleanup(asyncio.set_event_loop, None) +- asyncio.set_event_loop(self.loop) ++ self.addCleanup(asyncio._set_event_loop, None) ++ asyncio._set_event_loop(self.loop) + reader = mock.Mock() + protocol = asyncio.StreamReaderProtocol(reader) + self.assertIs(protocol._loop, self.loop) +@@ -1002,7 +1002,7 @@ + self.assertEqual(data, b'HTTP/1.0 200 OK\r\n') + f = rd.read() + data = self.loop.run_until_complete(f) +- self.assertTrue(data.endswith(b'\r\n\r\nTest message')) ++ self.assertEndsWith(data, b'\r\n\r\nTest message') + self.assertFalse(wr.is_closing()) + wr.close() + self.assertTrue(wr.is_closing()) +@@ -1028,7 +1028,7 @@ + data = await rd.readline() + self.assertEqual(data, b'HTTP/1.0 200 OK\r\n') + data = await rd.read() +- self.assertTrue(data.endswith(b'\r\n\r\nTest message')) ++ self.assertEndsWith(data, b'\r\n\r\nTest message') + wr.close() + await wr.wait_closed() + +@@ -1048,7 +1048,7 @@ + data = await rd.readline() + self.assertEqual(data, b'HTTP/1.0 200 OK\r\n') + data = await rd.read() +- self.assertTrue(data.endswith(b'\r\n\r\nTest message')) ++ self.assertEndsWith(data, b'\r\n\r\nTest message') + wr.close() + with self.assertRaises(ConnectionResetError): + wr.write(b'data') +@@ -1089,12 +1089,12 @@ + data = await rd.readline() + self.assertEqual(data, b'HTTP/1.0 200 OK\r\n') + data = await rd.read() +- self.assertTrue(data.endswith(b'\r\n\r\nTest message')) ++ self.assertEndsWith(data, b'\r\n\r\nTest message') + with self.assertWarns(ResourceWarning) as cm: + del wr + gc.collect() + self.assertEqual(len(cm.warnings), 1) +- self.assertTrue(str(cm.warnings[0].message).startswith("unclosed 50 times +- for _ in range(10 * ADAPTIVE_WARMUP_DELAY): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + assert_equal("overridden", f(num)) + + def test_setvectorcall_load_attr_specialization_skip(self): + from _testcapi import function_setvectorcall ++ _testinternalcapi = import_helper.import_module("_testinternalcapi") + + class X: + def __getattribute__(self, attr): +@@ -824,11 +823,12 @@ + function_setvectorcall(X.__getattribute__) + # make sure specialization doesn't trigger + # when vectorcall is overridden +- for _ in range(ADAPTIVE_WARMUP_DELAY): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + assert_equal("overridden", x.a) + + def test_setvectorcall_load_attr_specialization_deopt(self): + from _testcapi import function_setvectorcall ++ _testinternalcapi = import_helper.import_module("_testinternalcapi") + + class X: + def __getattribute__(self, attr): +@@ -840,12 +840,12 @@ + assert_equal = self.assertEqual + x = X() + # trigger LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN specialization +- for _ in range(ADAPTIVE_WARMUP_DELAY): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + assert_equal("a", get_a(x)) + function_setvectorcall(X.__getattribute__) + # make sure specialized LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN + # gets deopted due to overridden vectorcall +- for _ in range(ADAPTIVE_WARMUP_DELAY): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + assert_equal("overridden", get_a(x)) + + @requires_limited_api +@@ -1037,6 +1037,7 @@ + + @skip_on_s390x + @unittest.skipIf(is_wasi and Py_DEBUG, "requires deep stack") ++ @skip_if_sanitizer("requires deep stack", thread=True) + @unittest.skipIf(_testcapi is None, "requires _testcapi") + @skip_emscripten_stack_overflow() + def test_super_deep(self): +diff --git a/Lib/test/test_capi/test_abstract.py b/Lib/test/test_capi/test_abstract.py +index 6a626813f23..3de251bc5c2 100644 +--- a/Lib/test/test_capi/test_abstract.py ++++ b/Lib/test/test_capi/test_abstract.py +@@ -274,7 +274,7 @@ + + # PyObject_SetAttr(obj, attr_name, NULL) removes the attribute + xsetattr(obj, 'a', NULL) +- self.assertFalse(hasattr(obj, 'a')) ++ self.assertNotHasAttr(obj, 'a') + self.assertRaises(AttributeError, xsetattr, obj, 'b', NULL) + self.assertRaises(RuntimeError, xsetattr, obj, 'evil', NULL) + +@@ -294,7 +294,7 @@ + + # PyObject_SetAttrString(obj, attr_name, NULL) removes the attribute + setattrstring(obj, b'a', NULL) +- self.assertFalse(hasattr(obj, 'a')) ++ self.assertNotHasAttr(obj, 'a') + self.assertRaises(AttributeError, setattrstring, obj, b'b', NULL) + self.assertRaises(RuntimeError, setattrstring, obj, b'evil', NULL) + +@@ -311,10 +311,10 @@ + obj.a = 1 + setattr(obj, '\U0001f40d', 2) + xdelattr(obj, 'a') +- self.assertFalse(hasattr(obj, 'a')) ++ self.assertNotHasAttr(obj, 'a') + self.assertRaises(AttributeError, xdelattr, obj, 'b') + xdelattr(obj, '\U0001f40d') +- self.assertFalse(hasattr(obj, '\U0001f40d')) ++ self.assertNotHasAttr(obj, '\U0001f40d') + + self.assertRaises(AttributeError, xdelattr, 42, 'numerator') + self.assertRaises(RuntimeError, xdelattr, obj, 'evil') +@@ -328,10 +328,10 @@ + obj.a = 1 + setattr(obj, '\U0001f40d', 2) + delattrstring(obj, b'a') +- self.assertFalse(hasattr(obj, 'a')) ++ self.assertNotHasAttr(obj, 'a') + self.assertRaises(AttributeError, delattrstring, obj, b'b') + delattrstring(obj, '\U0001f40d'.encode()) +- self.assertFalse(hasattr(obj, '\U0001f40d')) ++ self.assertNotHasAttr(obj, '\U0001f40d') + + self.assertRaises(AttributeError, delattrstring, 42, b'numerator') + self.assertRaises(RuntimeError, delattrstring, obj, b'evil') +diff --git a/Lib/test/test_capi/test_bytearray.py b/Lib/test/test_capi/test_bytearray.py +index 39099f6b822..323e0d2a5ac 100644 +--- a/Lib/test/test_capi/test_bytearray.py ++++ b/Lib/test/test_capi/test_bytearray.py +@@ -151,10 +151,11 @@ + self.assertEqual(resize(ba, 3), 0) + self.assertEqual(ba, bytearray(b'abc')) + ++ self.assertRaises(ValueError, resize, bytearray(), -1) ++ self.assertRaises(ValueError, resize, bytearray(), -200) + self.assertRaises(MemoryError, resize, bytearray(), PY_SSIZE_T_MAX) + self.assertRaises(MemoryError, resize, bytearray(1000), PY_SSIZE_T_MAX) + +- # CRASHES resize(bytearray(b'abc'), -1) + # CRASHES resize(b'abc', 0) + # CRASHES resize(object(), 0) + # CRASHES resize(NULL, 0) +diff --git a/Lib/test/test_capi/test_codecs.py b/Lib/test/test_capi/test_codecs.py +index a557e35e689..a0355c7a388 100644 +--- a/Lib/test/test_capi/test_codecs.py ++++ b/Lib/test/test_capi/test_codecs.py +@@ -854,20 +854,18 @@ + self.do_test_codec_errors_handler(handler, self.unicode_encode_errors) + + def do_test_codec_errors_handler(self, handler, exceptions): +- at_least_one = False ++ self.assertNotEqual(len(exceptions), 0) + for exc in exceptions: +- # See https://github.com/python/cpython/issues/123378 and related +- # discussion and issues for details. +- if self._exception_may_crash(exc): +- continue +- +- at_least_one = True + with self.subTest(handler=handler, exc=exc): + # test that the handler does not crash +- self.assertIsInstance(handler(exc), tuple) +- +- if exceptions: +- self.assertTrue(at_least_one, "all exceptions are crashing") ++ res = handler(exc) ++ self.assertIsInstance(res, tuple) ++ self.assertEqual(len(res), 2) ++ replacement, continue_from = res ++ self.assertIsInstance(replacement, str) ++ self.assertIsInstance(continue_from, int) ++ self.assertGreaterEqual(continue_from, 0) ++ self.assertLessEqual(continue_from, len(exc.object)) + + for bad_exc in ( + self.bad_unicode_errors +@@ -876,30 +874,6 @@ + with self.subTest('bad type', handler=handler, exc=bad_exc): + self.assertRaises(TypeError, handler, bad_exc) + +- @classmethod +- def _exception_may_crash(cls, exc): +- """Indicate whether a Unicode exception might currently crash +- the interpreter when used by a built-in codecs error handler. +- +- Until gh-123378 is fixed, we skip the tests for these exceptions. +- +- This should only be used by "do_test_codec_errors_handler". +- """ +- message, start, end = exc.object, exc.start, exc.end +- match exc: +- case UnicodeEncodeError(): +- return end < start or (end - start) >= len(message) +- case UnicodeDecodeError(): +- # The case "end - start >= len(message)" does not crash. +- return end < start +- case UnicodeTranslateError(): +- # Test "end <= start" because PyCodec_ReplaceErrors checks +- # the Unicode kind of a 0-length string which by convention +- # is PyUnicode_1BYTE_KIND and not PyUnicode_2BYTE_KIND as +- # the handler currently expects. +- return end <= start or (end - start) >= len(message) +- return False +- + + if __name__ == "__main__": + unittest.main() +--- /dev/null ++++ b/Lib/test/test_capi/test_file.py +@@ -0,0 +1,305 @@ ++import io ++import os ++import unittest ++import warnings ++from test import support ++from test.support import import_helper, os_helper, warnings_helper ++ ++ ++_testcapi = import_helper.import_module('_testcapi') ++_testlimitedcapi = import_helper.import_module('_testlimitedcapi') ++_io = import_helper.import_module('_io') ++NULL = None ++STDOUT_FD = 1 ++ ++with open(__file__, 'rb') as fp: ++ FIRST_LINE = next(fp).decode() ++FIRST_LINE_NORM = FIRST_LINE.rstrip() + '\n' ++ ++ ++class CAPIFileTest(unittest.TestCase): ++ def test_pyfile_fromfd(self): ++ # Test PyFile_FromFd() which is a thin wrapper to _io.open() ++ pyfile_fromfd = _testlimitedcapi.pyfile_fromfd ++ filename = __file__ ++ with open(filename, "rb") as fp: ++ fd = fp.fileno() ++ ++ # FileIO ++ fp.seek(0) ++ obj = pyfile_fromfd(fd, filename, "rb", 0, NULL, NULL, NULL, 0) ++ try: ++ self.assertIsInstance(obj, _io.FileIO) ++ self.assertEqual(obj.readline(), FIRST_LINE.encode()) ++ finally: ++ obj.close() ++ ++ # BufferedReader ++ fp.seek(0) ++ obj = pyfile_fromfd(fd, filename, "rb", 1024, NULL, NULL, NULL, 0) ++ try: ++ self.assertIsInstance(obj, _io.BufferedReader) ++ self.assertEqual(obj.readline(), FIRST_LINE.encode()) ++ finally: ++ obj.close() ++ ++ # TextIOWrapper ++ fp.seek(0) ++ obj = pyfile_fromfd(fd, filename, "r", 1, ++ "utf-8", "replace", NULL, 0) ++ try: ++ self.assertIsInstance(obj, _io.TextIOWrapper) ++ self.assertEqual(obj.encoding, "utf-8") ++ self.assertEqual(obj.errors, "replace") ++ self.assertEqual(obj.readline(), FIRST_LINE_NORM) ++ finally: ++ obj.close() ++ ++ def test_pyfile_getline(self): ++ # Test PyFile_GetLine(file, n): call file.readline() ++ # and strip "\n" suffix if n < 0. ++ pyfile_getline = _testlimitedcapi.pyfile_getline ++ ++ # Test Unicode ++ with open(__file__, "r") as fp: ++ fp.seek(0) ++ self.assertEqual(pyfile_getline(fp, -1), ++ FIRST_LINE_NORM.rstrip('\n')) ++ fp.seek(0) ++ self.assertEqual(pyfile_getline(fp, 0), ++ FIRST_LINE_NORM) ++ fp.seek(0) ++ self.assertEqual(pyfile_getline(fp, 6), ++ FIRST_LINE_NORM[:6]) ++ ++ # Test bytes ++ with open(__file__, "rb") as fp: ++ fp.seek(0) ++ self.assertEqual(pyfile_getline(fp, -1), ++ FIRST_LINE.rstrip('\n').encode()) ++ fp.seek(0) ++ self.assertEqual(pyfile_getline(fp, 0), ++ FIRST_LINE.encode()) ++ fp.seek(0) ++ self.assertEqual(pyfile_getline(fp, 6), ++ FIRST_LINE.encode()[:6]) ++ ++ def test_pyfile_writestring(self): ++ # Test PyFile_WriteString(str, file): call file.write(str) ++ writestr = _testlimitedcapi.pyfile_writestring ++ ++ with io.StringIO() as fp: ++ self.assertEqual(writestr("a\xe9\u20ac\U0010FFFF".encode(), fp), 0) ++ with self.assertRaises(UnicodeDecodeError): ++ writestr(b"\xff", fp) ++ with self.assertRaises(UnicodeDecodeError): ++ writestr("\udc80".encode("utf-8", "surrogatepass"), fp) ++ ++ text = fp.getvalue() ++ self.assertEqual(text, "a\xe9\u20ac\U0010FFFF") ++ ++ with self.assertRaises(SystemError): ++ writestr(b"abc", NULL) ++ ++ def test_pyfile_writeobject(self): ++ # Test PyFile_WriteObject(obj, file, flags): ++ # - Call file.write(str(obj)) if flags equals Py_PRINT_RAW. ++ # - Call file.write(repr(obj)) otherwise. ++ writeobject = _testlimitedcapi.pyfile_writeobject ++ Py_PRINT_RAW = 1 ++ ++ with io.StringIO() as fp: ++ # Test flags=Py_PRINT_RAW ++ self.assertEqual(writeobject("raw", fp, Py_PRINT_RAW), 0) ++ writeobject(NULL, fp, Py_PRINT_RAW) ++ ++ # Test flags=0 ++ self.assertEqual(writeobject("repr", fp, 0), 0) ++ writeobject(NULL, fp, 0) ++ ++ text = fp.getvalue() ++ self.assertEqual(text, "raw'repr'") ++ ++ # invalid file type ++ for invalid_file in (123, "abc", object()): ++ with self.subTest(file=invalid_file): ++ with self.assertRaises(AttributeError): ++ writeobject("abc", invalid_file, Py_PRINT_RAW) ++ ++ with self.assertRaises(TypeError): ++ writeobject("abc", NULL, 0) ++ ++ def test_pyobject_asfiledescriptor(self): ++ # Test PyObject_AsFileDescriptor(obj): ++ # - Return obj if obj is an integer. ++ # - Return obj.fileno() otherwise. ++ # File descriptor must be >= 0. ++ asfd = _testlimitedcapi.pyobject_asfiledescriptor ++ ++ self.assertEqual(asfd(123), 123) ++ self.assertEqual(asfd(0), 0) ++ ++ with open(__file__, "rb") as fp: ++ self.assertEqual(asfd(fp), fp.fileno()) ++ ++ # bool emits RuntimeWarning ++ msg = r"bool is used as a file descriptor" ++ with warnings_helper.check_warnings((msg, RuntimeWarning)): ++ self.assertEqual(asfd(True), 1) ++ ++ class FakeFile: ++ def __init__(self, fd): ++ self.fd = fd ++ def fileno(self): ++ return self.fd ++ ++ # file descriptor must be positive ++ with self.assertRaises(ValueError): ++ asfd(-1) ++ with self.assertRaises(ValueError): ++ asfd(FakeFile(-1)) ++ ++ # fileno() result must be an integer ++ with self.assertRaises(TypeError): ++ asfd(FakeFile("text")) ++ ++ # unsupported types ++ for obj in ("string", ["list"], object()): ++ with self.subTest(obj=obj): ++ with self.assertRaises(TypeError): ++ asfd(obj) ++ ++ # CRASHES asfd(NULL) ++ ++ def test_pyfile_newstdprinter(self): ++ # Test PyFile_NewStdPrinter() ++ pyfile_newstdprinter = _testcapi.pyfile_newstdprinter ++ ++ file = pyfile_newstdprinter(STDOUT_FD) ++ self.assertEqual(file.closed, False) ++ self.assertIsNone(file.encoding) ++ self.assertEqual(file.mode, "w") ++ ++ self.assertEqual(file.fileno(), STDOUT_FD) ++ self.assertEqual(file.isatty(), os.isatty(STDOUT_FD)) ++ ++ # flush() is a no-op ++ self.assertIsNone(file.flush()) ++ ++ # close() is a no-op ++ self.assertIsNone(file.close()) ++ self.assertEqual(file.closed, False) ++ ++ support.check_disallow_instantiation(self, type(file)) ++ ++ def test_pyfile_newstdprinter_write(self): ++ # Test the write() method of PyFile_NewStdPrinter() ++ pyfile_newstdprinter = _testcapi.pyfile_newstdprinter ++ ++ filename = os_helper.TESTFN ++ self.addCleanup(os_helper.unlink, filename) ++ ++ try: ++ old_stdout = os.dup(STDOUT_FD) ++ except OSError as exc: ++ # os.dup(STDOUT_FD) is not supported on WASI ++ self.skipTest(f"os.dup() failed with {exc!r}") ++ ++ try: ++ with open(filename, "wb") as fp: ++ # PyFile_NewStdPrinter() only accepts fileno(stdout) ++ # or fileno(stderr) file descriptor. ++ fd = fp.fileno() ++ os.dup2(fd, STDOUT_FD) ++ ++ file = pyfile_newstdprinter(STDOUT_FD) ++ self.assertEqual(file.write("text"), 4) ++ # The surrogate character is encoded with ++ # the "surrogateescape" error handler ++ self.assertEqual(file.write("[\udc80]"), 8) ++ finally: ++ os.dup2(old_stdout, STDOUT_FD) ++ os.close(old_stdout) ++ ++ with open(filename, "r") as fp: ++ self.assertEqual(fp.read(), "text[\\udc80]") ++ ++ def test_py_fopen(self): ++ # Test Py_fopen() and Py_fclose() ++ py_fopen = _testcapi.py_fopen ++ ++ with open(__file__, "rb") as fp: ++ source = fp.read() ++ ++ for filename in (__file__, os.fsencode(__file__)): ++ with self.subTest(filename=filename): ++ data = py_fopen(filename, "rb") ++ self.assertEqual(data, source[:256]) ++ ++ data = py_fopen(os_helper.FakePath(filename), "rb") ++ self.assertEqual(data, source[:256]) ++ ++ filenames = [ ++ os_helper.TESTFN, ++ os.fsencode(os_helper.TESTFN), ++ ] ++ if os_helper.TESTFN_UNDECODABLE is not None: ++ filenames.append(os_helper.TESTFN_UNDECODABLE) ++ filenames.append(os.fsdecode(os_helper.TESTFN_UNDECODABLE)) ++ if os_helper.TESTFN_UNENCODABLE is not None: ++ filenames.append(os_helper.TESTFN_UNENCODABLE) ++ for filename in filenames: ++ with self.subTest(filename=filename): ++ try: ++ with open(filename, "wb") as fp: ++ fp.write(source) ++ except OSError: ++ # TESTFN_UNDECODABLE cannot be used to create a file ++ # on macOS/WASI. ++ filename = None ++ continue ++ try: ++ data = py_fopen(filename, "rb") ++ self.assertEqual(data, source[:256]) ++ finally: ++ os_helper.unlink(filename) ++ ++ # embedded null character/byte in the filename ++ with self.assertRaises(ValueError): ++ py_fopen("a\x00b", "rb") ++ with self.assertRaises(ValueError): ++ py_fopen(b"a\x00b", "rb") ++ ++ # non-ASCII mode failing with "Invalid argument" ++ with self.assertRaises(OSError): ++ py_fopen(__file__, b"\xc2\x80") ++ with self.assertRaises(OSError): ++ # \x98 is invalid in cp1250, cp1251, cp1257 ++ # \x9d is invalid in cp1252-cp1255, cp1258 ++ py_fopen(__file__, b"\xc2\x98\xc2\x9d") ++ # UnicodeDecodeError can come from the audit hook code ++ with self.assertRaises((UnicodeDecodeError, OSError)): ++ py_fopen(__file__, b"\x98\x9d") ++ ++ # invalid filename type ++ for invalid_type in (123, object()): ++ with self.subTest(filename=invalid_type): ++ with self.assertRaises(TypeError): ++ py_fopen(invalid_type, "rb") ++ ++ if support.MS_WINDOWS: ++ with self.assertRaises(OSError): ++ # On Windows, the file mode is limited to 10 characters ++ py_fopen(__file__, "rt+, ccs=UTF-8") ++ ++ # CRASHES py_fopen(NULL, 'rb') ++ # CRASHES py_fopen(__file__, NULL) ++ ++ # TODO: Test Py_UniversalNewlineFgets() ++ ++ # PyFile_SetOpenCodeHook() and PyFile_OpenCode() are tested by ++ # test_embed.test_open_code_hook() ++ ++ ++if __name__ == "__main__": ++ unittest.main() +--- /dev/null ++++ b/Lib/test/test_capi/test_frame.py +@@ -0,0 +1,56 @@ ++import sys ++import unittest ++from test.support import import_helper ++ ++ ++_testcapi = import_helper.import_module('_testcapi') ++ ++ ++class FrameTest(unittest.TestCase): ++ def getframe(self): ++ return sys._getframe() ++ ++ def test_frame_getters(self): ++ frame = self.getframe() ++ self.assertEqual(frame.f_locals, _testcapi.frame_getlocals(frame)) ++ self.assertIs(frame.f_globals, _testcapi.frame_getglobals(frame)) ++ self.assertIs(frame.f_builtins, _testcapi.frame_getbuiltins(frame)) ++ self.assertEqual(frame.f_lasti, _testcapi.frame_getlasti(frame)) ++ ++ def test_getvar(self): ++ current_frame = sys._getframe() ++ x = 1 ++ self.assertEqual(_testcapi.frame_getvar(current_frame, "x"), 1) ++ self.assertEqual(_testcapi.frame_getvarstring(current_frame, b"x"), 1) ++ with self.assertRaises(NameError): ++ _testcapi.frame_getvar(current_frame, "y") ++ with self.assertRaises(NameError): ++ _testcapi.frame_getvarstring(current_frame, b"y") ++ ++ # wrong name type ++ with self.assertRaises(TypeError): ++ _testcapi.frame_getvar(current_frame, b'x') ++ with self.assertRaises(TypeError): ++ _testcapi.frame_getvar(current_frame, 123) ++ ++ def getgenframe(self): ++ yield sys._getframe() ++ ++ def test_frame_get_generator(self): ++ gen = self.getgenframe() ++ frame = next(gen) ++ self.assertIs(gen, _testcapi.frame_getgenerator(frame)) ++ ++ def test_frame_fback_api(self): ++ """Test that accessing `f_back` does not cause a segmentation fault on ++ a frame created with `PyFrame_New` (GH-99110).""" ++ def dummy(): ++ pass ++ ++ frame = _testcapi.frame_new(dummy.__code__, globals(), locals()) ++ # The following line should not cause a segmentation fault. ++ self.assertIsNone(frame.f_back) ++ ++ ++if __name__ == "__main__": ++ unittest.main() +--- /dev/null ++++ b/Lib/test/test_capi/test_function.py +@@ -0,0 +1,323 @@ ++import unittest ++from test.support import import_helper ++ ++ ++_testcapi = import_helper.import_module('_testcapi') ++ ++ ++class FunctionTest(unittest.TestCase): ++ def test_function_get_code(self): ++ # Test PyFunction_GetCode() ++ import types ++ ++ def some(): ++ pass ++ ++ code = _testcapi.function_get_code(some) ++ self.assertIsInstance(code, types.CodeType) ++ self.assertEqual(code, some.__code__) ++ ++ with self.assertRaises(SystemError): ++ _testcapi.function_get_code(None) # not a function ++ ++ def test_function_get_globals(self): ++ # Test PyFunction_GetGlobals() ++ def some(): ++ pass ++ ++ globals_ = _testcapi.function_get_globals(some) ++ self.assertIsInstance(globals_, dict) ++ self.assertEqual(globals_, some.__globals__) ++ ++ with self.assertRaises(SystemError): ++ _testcapi.function_get_globals(None) # not a function ++ ++ def test_function_get_module(self): ++ # Test PyFunction_GetModule() ++ def some(): ++ pass ++ ++ module = _testcapi.function_get_module(some) ++ self.assertIsInstance(module, str) ++ self.assertEqual(module, some.__module__) ++ ++ with self.assertRaises(SystemError): ++ _testcapi.function_get_module(None) # not a function ++ ++ def test_function_get_defaults(self): ++ # Test PyFunction_GetDefaults() ++ def some( ++ pos_only1, pos_only2='p', ++ /, ++ zero=0, optional=None, ++ *, ++ kw1, ++ kw2=True, ++ ): ++ pass ++ ++ defaults = _testcapi.function_get_defaults(some) ++ self.assertEqual(defaults, ('p', 0, None)) ++ self.assertEqual(defaults, some.__defaults__) ++ ++ with self.assertRaises(SystemError): ++ _testcapi.function_get_defaults(None) # not a function ++ ++ def test_function_set_defaults(self): ++ # Test PyFunction_SetDefaults() ++ def some( ++ pos_only1, pos_only2='p', ++ /, ++ zero=0, optional=None, ++ *, ++ kw1, ++ kw2=True, ++ ): ++ pass ++ ++ old_defaults = ('p', 0, None) ++ self.assertEqual(_testcapi.function_get_defaults(some), old_defaults) ++ self.assertEqual(some.__defaults__, old_defaults) ++ ++ with self.assertRaises(SystemError): ++ _testcapi.function_set_defaults(some, 1) # not tuple or None ++ self.assertEqual(_testcapi.function_get_defaults(some), old_defaults) ++ self.assertEqual(some.__defaults__, old_defaults) ++ ++ with self.assertRaises(SystemError): ++ _testcapi.function_set_defaults(1, ()) # not a function ++ self.assertEqual(_testcapi.function_get_defaults(some), old_defaults) ++ self.assertEqual(some.__defaults__, old_defaults) ++ ++ new_defaults = ('q', 1, None) ++ _testcapi.function_set_defaults(some, new_defaults) ++ self.assertEqual(_testcapi.function_get_defaults(some), new_defaults) ++ self.assertEqual(some.__defaults__, new_defaults) ++ ++ # Empty tuple is fine: ++ new_defaults = () ++ _testcapi.function_set_defaults(some, new_defaults) ++ self.assertEqual(_testcapi.function_get_defaults(some), new_defaults) ++ self.assertEqual(some.__defaults__, new_defaults) ++ ++ class tuplesub(tuple): ... # tuple subclasses must work ++ ++ new_defaults = tuplesub(((1, 2), ['a', 'b'], None)) ++ _testcapi.function_set_defaults(some, new_defaults) ++ self.assertEqual(_testcapi.function_get_defaults(some), new_defaults) ++ self.assertEqual(some.__defaults__, new_defaults) ++ ++ # `None` is special, it sets `defaults` to `NULL`, ++ # it needs special handling in `_testcapi`: ++ _testcapi.function_set_defaults(some, None) ++ self.assertEqual(_testcapi.function_get_defaults(some), None) ++ self.assertEqual(some.__defaults__, None) ++ ++ def test_function_get_kw_defaults(self): ++ # Test PyFunction_GetKwDefaults() ++ def some( ++ pos_only1, pos_only2='p', ++ /, ++ zero=0, optional=None, ++ *, ++ kw1, ++ kw2=True, ++ ): ++ pass ++ ++ defaults = _testcapi.function_get_kw_defaults(some) ++ self.assertEqual(defaults, {'kw2': True}) ++ self.assertEqual(defaults, some.__kwdefaults__) ++ ++ with self.assertRaises(SystemError): ++ _testcapi.function_get_kw_defaults(None) # not a function ++ ++ def test_function_set_kw_defaults(self): ++ # Test PyFunction_SetKwDefaults() ++ def some( ++ pos_only1, pos_only2='p', ++ /, ++ zero=0, optional=None, ++ *, ++ kw1, ++ kw2=True, ++ ): ++ pass ++ ++ old_defaults = {'kw2': True} ++ self.assertEqual(_testcapi.function_get_kw_defaults(some), old_defaults) ++ self.assertEqual(some.__kwdefaults__, old_defaults) ++ ++ with self.assertRaises(SystemError): ++ _testcapi.function_set_kw_defaults(some, 1) # not dict or None ++ self.assertEqual(_testcapi.function_get_kw_defaults(some), old_defaults) ++ self.assertEqual(some.__kwdefaults__, old_defaults) ++ ++ with self.assertRaises(SystemError): ++ _testcapi.function_set_kw_defaults(1, {}) # not a function ++ self.assertEqual(_testcapi.function_get_kw_defaults(some), old_defaults) ++ self.assertEqual(some.__kwdefaults__, old_defaults) ++ ++ new_defaults = {'kw2': (1, 2, 3)} ++ _testcapi.function_set_kw_defaults(some, new_defaults) ++ self.assertEqual(_testcapi.function_get_kw_defaults(some), new_defaults) ++ self.assertEqual(some.__kwdefaults__, new_defaults) ++ ++ # Empty dict is fine: ++ new_defaults = {} ++ _testcapi.function_set_kw_defaults(some, new_defaults) ++ self.assertEqual(_testcapi.function_get_kw_defaults(some), new_defaults) ++ self.assertEqual(some.__kwdefaults__, new_defaults) ++ ++ class dictsub(dict): ... # dict subclasses must work ++ ++ new_defaults = dictsub({'kw2': None}) ++ _testcapi.function_set_kw_defaults(some, new_defaults) ++ self.assertEqual(_testcapi.function_get_kw_defaults(some), new_defaults) ++ self.assertEqual(some.__kwdefaults__, new_defaults) ++ ++ # `None` is special, it sets `kwdefaults` to `NULL`, ++ # it needs special handling in `_testcapi`: ++ _testcapi.function_set_kw_defaults(some, None) ++ self.assertEqual(_testcapi.function_get_kw_defaults(some), None) ++ self.assertEqual(some.__kwdefaults__, None) ++ ++ def test_function_get_closure(self): ++ # Test PyFunction_GetClosure() ++ from types import CellType ++ ++ def regular_function(): ... ++ def unused_one_level(arg1): ++ def inner(arg2, arg3): ... ++ return inner ++ def unused_two_levels(arg1, arg2): ++ def decorator(arg3, arg4): ++ def inner(arg5, arg6): ... ++ return inner ++ return decorator ++ def with_one_level(arg1): ++ def inner(arg2, arg3): ++ return arg1 + arg2 + arg3 ++ return inner ++ def with_two_levels(arg1, arg2): ++ def decorator(arg3, arg4): ++ def inner(arg5, arg6): ++ return arg1 + arg2 + arg3 + arg4 + arg5 + arg6 ++ return inner ++ return decorator ++ ++ # Functions without closures: ++ self.assertIsNone(_testcapi.function_get_closure(regular_function)) ++ self.assertIsNone(regular_function.__closure__) ++ ++ func = unused_one_level(1) ++ closure = _testcapi.function_get_closure(func) ++ self.assertIsNone(closure) ++ self.assertIsNone(func.__closure__) ++ ++ func = unused_two_levels(1, 2)(3, 4) ++ closure = _testcapi.function_get_closure(func) ++ self.assertIsNone(closure) ++ self.assertIsNone(func.__closure__) ++ ++ # Functions with closures: ++ func = with_one_level(5) ++ closure = _testcapi.function_get_closure(func) ++ self.assertEqual(closure, func.__closure__) ++ self.assertIsInstance(closure, tuple) ++ self.assertEqual(len(closure), 1) ++ self.assertEqual(len(closure), len(func.__code__.co_freevars)) ++ for cell in closure: ++ self.assertIsInstance(cell, CellType) ++ self.assertTrue(closure[0].cell_contents, 5) ++ ++ func = with_two_levels(1, 2)(3, 4) ++ closure = _testcapi.function_get_closure(func) ++ self.assertEqual(closure, func.__closure__) ++ self.assertIsInstance(closure, tuple) ++ self.assertEqual(len(closure), 4) ++ self.assertEqual(len(closure), len(func.__code__.co_freevars)) ++ for cell in closure: ++ self.assertIsInstance(cell, CellType) ++ self.assertEqual([cell.cell_contents for cell in closure], ++ [1, 2, 3, 4]) ++ ++ def test_function_get_closure_error(self): ++ # Test PyFunction_GetClosure() ++ with self.assertRaises(SystemError): ++ _testcapi.function_get_closure(1) ++ with self.assertRaises(SystemError): ++ _testcapi.function_get_closure(None) ++ ++ def test_function_set_closure(self): ++ # Test PyFunction_SetClosure() ++ from types import CellType ++ ++ def function_without_closure(): ... ++ def function_with_closure(arg): ++ def inner(): ++ return arg ++ return inner ++ ++ func = function_without_closure ++ _testcapi.function_set_closure(func, (CellType(1), CellType(1))) ++ closure = _testcapi.function_get_closure(func) ++ self.assertEqual([c.cell_contents for c in closure], [1, 1]) ++ self.assertEqual([c.cell_contents for c in func.__closure__], [1, 1]) ++ ++ func = function_with_closure(1) ++ _testcapi.function_set_closure(func, ++ (CellType(1), CellType(2), CellType(3))) ++ closure = _testcapi.function_get_closure(func) ++ self.assertEqual([c.cell_contents for c in closure], [1, 2, 3]) ++ self.assertEqual([c.cell_contents for c in func.__closure__], [1, 2, 3]) ++ ++ def test_function_set_closure_none(self): ++ # Test PyFunction_SetClosure() ++ def function_without_closure(): ... ++ def function_with_closure(arg): ++ def inner(): ++ return arg ++ return inner ++ ++ _testcapi.function_set_closure(function_without_closure, None) ++ self.assertIsNone( ++ _testcapi.function_get_closure(function_without_closure)) ++ self.assertIsNone(function_without_closure.__closure__) ++ ++ _testcapi.function_set_closure(function_with_closure, None) ++ self.assertIsNone( ++ _testcapi.function_get_closure(function_with_closure)) ++ self.assertIsNone(function_with_closure.__closure__) ++ ++ def test_function_set_closure_errors(self): ++ # Test PyFunction_SetClosure() ++ def function_without_closure(): ... ++ ++ with self.assertRaises(SystemError): ++ _testcapi.function_set_closure(None, ()) # not a function ++ ++ with self.assertRaises(SystemError): ++ _testcapi.function_set_closure(function_without_closure, 1) ++ self.assertIsNone(function_without_closure.__closure__) # no change ++ ++ # NOTE: this works, but goes against the docs: ++ _testcapi.function_set_closure(function_without_closure, (1, 2)) ++ self.assertEqual( ++ _testcapi.function_get_closure(function_without_closure), (1, 2)) ++ self.assertEqual(function_without_closure.__closure__, (1, 2)) ++ ++ # TODO: test PyFunction_New() ++ # TODO: test PyFunction_NewWithQualName() ++ # TODO: test PyFunction_SetVectorcall() ++ # TODO: test PyFunction_GetAnnotations() ++ # TODO: test PyFunction_SetAnnotations() ++ # TODO: test PyClassMethod_New() ++ # TODO: test PyStaticMethod_New() ++ # ++ # PyFunction_AddWatcher() and PyFunction_ClearWatcher() are tested by ++ # test_capi.test_watchers. ++ ++ ++if __name__ == "__main__": ++ unittest.main() +diff --git a/Lib/test/test_capi/test_immortal.py b/Lib/test/test_capi/test_immortal.py +index 3e36913ac30..660e8a0e789 100644 +--- a/Lib/test/test_capi/test_immortal.py ++++ b/Lib/test/test_capi/test_immortal.py +@@ -5,12 +5,22 @@ + _testinternalcapi = import_helper.import_module('_testinternalcapi') + + +-class TestCAPI(unittest.TestCase): +- def test_immortal_builtins(self): +- _testcapi.test_immortal_builtins() ++class TestUnstableCAPI(unittest.TestCase): ++ def test_immortal(self): ++ # Not extensive ++ known_immortals = (True, False, None, 0, ()) ++ for immortal in known_immortals: ++ with self.subTest(immortal=immortal): ++ self.assertTrue(_testcapi.is_immortal(immortal)) ++ ++ # Some arbitrary mutable objects ++ non_immortals = (object(), self, [object()]) ++ for non_immortal in non_immortals: ++ with self.subTest(non_immortal=non_immortal): ++ self.assertFalse(_testcapi.is_immortal(non_immortal)) ++ ++ # CRASHES _testcapi.is_immortal(NULL) + +- def test_immortal_small_ints(self): +- _testcapi.test_immortal_small_ints() + + class TestInternalCAPI(unittest.TestCase): + +--- /dev/null ++++ b/Lib/test/test_capi/test_import.py +@@ -0,0 +1,381 @@ ++import importlib.util ++import os.path ++import sys ++import types ++import unittest ++from test.support import os_helper ++from test.support import import_helper ++from test.support.warnings_helper import check_warnings ++ ++_testcapi = import_helper.import_module('_testcapi') ++_testlimitedcapi = import_helper.import_module('_testlimitedcapi') ++NULL = None ++ ++ ++class ImportTests(unittest.TestCase): ++ def test_getmagicnumber(self): ++ # Test PyImport_GetMagicNumber() ++ magic = _testlimitedcapi.PyImport_GetMagicNumber() ++ self.assertEqual(magic, ++ int.from_bytes(importlib.util.MAGIC_NUMBER, 'little')) ++ ++ def test_getmagictag(self): ++ # Test PyImport_GetMagicTag() ++ tag = _testlimitedcapi.PyImport_GetMagicTag() ++ self.assertEqual(tag, sys.implementation.cache_tag) ++ ++ def test_getmoduledict(self): ++ # Test PyImport_GetModuleDict() ++ modules = _testlimitedcapi.PyImport_GetModuleDict() ++ self.assertIs(modules, sys.modules) ++ ++ def check_import_loaded_module(self, import_module): ++ for name in ('os', 'sys', 'test', 'unittest'): ++ with self.subTest(name=name): ++ self.assertIn(name, sys.modules) ++ old_module = sys.modules[name] ++ module = import_module(name) ++ self.assertIsInstance(module, types.ModuleType) ++ self.assertIs(module, old_module) ++ ++ def check_import_fresh_module(self, import_module): ++ old_modules = dict(sys.modules) ++ try: ++ for name in ('colorsys', 'math'): ++ with self.subTest(name=name): ++ sys.modules.pop(name, None) ++ module = import_module(name) ++ self.assertIsInstance(module, types.ModuleType) ++ self.assertIs(module, sys.modules[name]) ++ self.assertEqual(module.__name__, name) ++ finally: ++ sys.modules.clear() ++ sys.modules.update(old_modules) ++ ++ def test_getmodule(self): ++ # Test PyImport_GetModule() ++ getmodule = _testlimitedcapi.PyImport_GetModule ++ self.check_import_loaded_module(getmodule) ++ ++ nonexistent = 'nonexistent' ++ self.assertNotIn(nonexistent, sys.modules) ++ self.assertIs(getmodule(nonexistent), KeyError) ++ self.assertIs(getmodule(''), KeyError) ++ self.assertIs(getmodule(object()), KeyError) ++ ++ self.assertRaises(TypeError, getmodule, []) # unhashable ++ # CRASHES getmodule(NULL) ++ ++ def check_addmodule(self, add_module, accept_nonstr=False): ++ # create a new module ++ names = ['nonexistent'] ++ if accept_nonstr: ++ names.append(b'\xff') # non-UTF-8 ++ # PyImport_AddModuleObject() accepts non-string names ++ names.append(tuple(['hashable non-string'])) ++ for name in names: ++ with self.subTest(name=name): ++ self.assertNotIn(name, sys.modules) ++ try: ++ module = add_module(name) ++ self.assertIsInstance(module, types.ModuleType) ++ self.assertEqual(module.__name__, name) ++ self.assertIs(module, sys.modules[name]) ++ finally: ++ sys.modules.pop(name, None) ++ ++ # get an existing module ++ self.check_import_loaded_module(add_module) ++ ++ def test_addmoduleobject(self): ++ # Test PyImport_AddModuleObject() ++ addmoduleobject = _testlimitedcapi.PyImport_AddModuleObject ++ self.check_addmodule(addmoduleobject, accept_nonstr=True) ++ ++ self.assertRaises(TypeError, addmoduleobject, []) # unhashable ++ # CRASHES addmoduleobject(NULL) ++ ++ def test_addmodule(self): ++ # Test PyImport_AddModule() ++ addmodule = _testlimitedcapi.PyImport_AddModule ++ self.check_addmodule(addmodule) ++ ++ self.assertRaises(UnicodeDecodeError, addmodule, b'\xff') ++ # CRASHES addmodule(NULL) ++ ++ def test_addmoduleref(self): ++ # Test PyImport_AddModuleRef() ++ addmoduleref = _testlimitedcapi.PyImport_AddModuleRef ++ self.check_addmodule(addmoduleref) ++ ++ self.assertRaises(UnicodeDecodeError, addmoduleref, b'\xff') ++ # CRASHES addmoduleref(NULL) ++ ++ def check_import_func(self, import_module): ++ self.check_import_loaded_module(import_module) ++ self.check_import_fresh_module(import_module) ++ self.assertRaises(ModuleNotFoundError, import_module, 'nonexistent') ++ self.assertRaises(ValueError, import_module, '') ++ ++ def test_import(self): ++ # Test PyImport_Import() ++ import_ = _testlimitedcapi.PyImport_Import ++ self.check_import_func(import_) ++ ++ self.assertRaises(TypeError, import_, b'os') ++ self.assertRaises(SystemError, import_, NULL) ++ ++ def test_importmodule(self): ++ # Test PyImport_ImportModule() ++ importmodule = _testlimitedcapi.PyImport_ImportModule ++ self.check_import_func(importmodule) ++ ++ self.assertRaises(UnicodeDecodeError, importmodule, b'\xff') ++ # CRASHES importmodule(NULL) ++ ++ def test_importmodulenoblock(self): ++ # Test deprecated PyImport_ImportModuleNoBlock() ++ importmodulenoblock = _testlimitedcapi.PyImport_ImportModuleNoBlock ++ with check_warnings(('', DeprecationWarning)): ++ self.check_import_func(importmodulenoblock) ++ self.assertRaises(UnicodeDecodeError, importmodulenoblock, b'\xff') ++ ++ # CRASHES importmodulenoblock(NULL) ++ ++ def check_frozen_import(self, import_frozen_module): ++ # Importing a frozen module executes its code, so start by unloading ++ # the module to execute the code in a new (temporary) module. ++ old_zipimport = sys.modules.pop('zipimport') ++ try: ++ self.assertEqual(import_frozen_module('zipimport'), 1) ++ ++ # import zipimport again ++ self.assertEqual(import_frozen_module('zipimport'), 1) ++ finally: ++ sys.modules['zipimport'] = old_zipimport ++ ++ # not a frozen module ++ self.assertEqual(import_frozen_module('sys'), 0) ++ self.assertEqual(import_frozen_module('nonexistent'), 0) ++ self.assertEqual(import_frozen_module(''), 0) ++ ++ def test_importfrozenmodule(self): ++ # Test PyImport_ImportFrozenModule() ++ importfrozenmodule = _testlimitedcapi.PyImport_ImportFrozenModule ++ self.check_frozen_import(importfrozenmodule) ++ ++ self.assertRaises(UnicodeDecodeError, importfrozenmodule, b'\xff') ++ # CRASHES importfrozenmodule(NULL) ++ ++ def test_importfrozenmoduleobject(self): ++ # Test PyImport_ImportFrozenModuleObject() ++ importfrozenmoduleobject = _testlimitedcapi.PyImport_ImportFrozenModuleObject ++ self.check_frozen_import(importfrozenmoduleobject) ++ self.assertEqual(importfrozenmoduleobject(b'zipimport'), 0) ++ self.assertEqual(importfrozenmoduleobject(NULL), 0) ++ ++ def test_importmoduleex(self): ++ # Test PyImport_ImportModuleEx() ++ importmoduleex = _testlimitedcapi.PyImport_ImportModuleEx ++ self.check_import_func(lambda name: importmoduleex(name, NULL, NULL, NULL)) ++ ++ self.assertRaises(ModuleNotFoundError, importmoduleex, 'nonexistent', NULL, NULL, NULL) ++ self.assertRaises(ValueError, importmoduleex, '', NULL, NULL, NULL) ++ self.assertRaises(UnicodeDecodeError, importmoduleex, b'\xff', NULL, NULL, NULL) ++ # CRASHES importmoduleex(NULL, NULL, NULL, NULL) ++ ++ def check_importmodulelevel(self, importmodulelevel): ++ self.check_import_func(lambda name: importmodulelevel(name, NULL, NULL, NULL, 0)) ++ ++ self.assertRaises(ModuleNotFoundError, importmodulelevel, 'nonexistent', NULL, NULL, NULL, 0) ++ self.assertRaises(ValueError, importmodulelevel, '', NULL, NULL, NULL, 0) ++ ++ if __package__: ++ self.assertIs(importmodulelevel('test_import', globals(), NULL, NULL, 1), ++ sys.modules['test.test_capi.test_import']) ++ self.assertIs(importmodulelevel('test_capi', globals(), NULL, NULL, 2), ++ sys.modules['test.test_capi']) ++ self.assertRaises(ValueError, importmodulelevel, 'os', NULL, NULL, NULL, -1) ++ with self.assertWarns(ImportWarning): ++ self.assertRaises(KeyError, importmodulelevel, 'test_import', {}, NULL, NULL, 1) ++ self.assertRaises(TypeError, importmodulelevel, 'test_import', [], NULL, NULL, 1) ++ ++ def test_importmodulelevel(self): ++ # Test PyImport_ImportModuleLevel() ++ importmodulelevel = _testlimitedcapi.PyImport_ImportModuleLevel ++ self.check_importmodulelevel(importmodulelevel) ++ ++ self.assertRaises(UnicodeDecodeError, importmodulelevel, b'\xff', NULL, NULL, NULL, 0) ++ # CRASHES importmodulelevel(NULL, NULL, NULL, NULL, 0) ++ ++ def test_importmodulelevelobject(self): ++ # Test PyImport_ImportModuleLevelObject() ++ importmodulelevel = _testlimitedcapi.PyImport_ImportModuleLevelObject ++ self.check_importmodulelevel(importmodulelevel) ++ ++ self.assertRaises(TypeError, importmodulelevel, b'os', NULL, NULL, NULL, 0) ++ self.assertRaises(ValueError, importmodulelevel, NULL, NULL, NULL, NULL, 0) ++ ++ def check_executecodemodule(self, execute_code, *args): ++ name = 'test_import_executecode' ++ try: ++ # Create a temporary module where the code will be executed ++ self.assertNotIn(name, sys.modules) ++ module = _testlimitedcapi.PyImport_AddModuleRef(name) ++ self.assertNotHasAttr(module, 'attr') ++ ++ # Execute the code ++ code = compile('attr = 1', '', 'exec') ++ module2 = execute_code(name, code, *args) ++ self.assertIs(module2, module) ++ ++ # Check the function side effects ++ self.assertEqual(module.attr, 1) ++ finally: ++ sys.modules.pop(name, None) ++ return module.__spec__.origin ++ ++ def test_executecodemodule(self): ++ # Test PyImport_ExecCodeModule() ++ execcodemodule = _testlimitedcapi.PyImport_ExecCodeModule ++ self.check_executecodemodule(execcodemodule) ++ ++ code = compile('attr = 1', '', 'exec') ++ self.assertRaises(UnicodeDecodeError, execcodemodule, b'\xff', code) ++ # CRASHES execcodemodule(NULL, code) ++ # CRASHES execcodemodule(name, NULL) ++ ++ def test_executecodemoduleex(self): ++ # Test PyImport_ExecCodeModuleEx() ++ execcodemoduleex = _testlimitedcapi.PyImport_ExecCodeModuleEx ++ ++ # Test NULL path (it should not crash) ++ self.check_executecodemodule(execcodemoduleex, NULL) ++ ++ # Test non-NULL path ++ pathname = b'pathname' ++ origin = self.check_executecodemodule(execcodemoduleex, pathname) ++ self.assertEqual(origin, os.path.abspath(os.fsdecode(pathname))) ++ ++ pathname = os_helper.TESTFN_UNDECODABLE ++ if pathname: ++ origin = self.check_executecodemodule(execcodemoduleex, pathname) ++ self.assertEqual(origin, os.path.abspath(os.fsdecode(pathname))) ++ ++ code = compile('attr = 1', '', 'exec') ++ self.assertRaises(UnicodeDecodeError, execcodemoduleex, b'\xff', code, NULL) ++ # CRASHES execcodemoduleex(NULL, code, NULL) ++ # CRASHES execcodemoduleex(name, NULL, NULL) ++ ++ def check_executecode_pathnames(self, execute_code_func, object=False): ++ # Test non-NULL pathname and NULL cpathname ++ ++ # Test NULL paths (it should not crash) ++ self.check_executecodemodule(execute_code_func, NULL, NULL) ++ ++ pathname = 'pathname' ++ origin = self.check_executecodemodule(execute_code_func, pathname, NULL) ++ self.assertEqual(origin, os.path.abspath(os.fsdecode(pathname))) ++ origin = self.check_executecodemodule(execute_code_func, NULL, pathname) ++ if not object: ++ self.assertEqual(origin, os.path.abspath(os.fsdecode(pathname))) ++ ++ pathname = os_helper.TESTFN_UNDECODABLE ++ if pathname: ++ if object: ++ pathname = os.fsdecode(pathname) ++ origin = self.check_executecodemodule(execute_code_func, pathname, NULL) ++ self.assertEqual(origin, os.path.abspath(os.fsdecode(pathname))) ++ self.check_executecodemodule(execute_code_func, NULL, pathname) ++ ++ # Test NULL pathname and non-NULL cpathname ++ pyc_filename = importlib.util.cache_from_source(__file__) ++ py_filename = importlib.util.source_from_cache(pyc_filename) ++ origin = self.check_executecodemodule(execute_code_func, NULL, pyc_filename) ++ if not object: ++ self.assertEqual(origin, py_filename) ++ ++ def test_executecodemodulewithpathnames(self): ++ # Test PyImport_ExecCodeModuleWithPathnames() ++ execute_code_func = _testlimitedcapi.PyImport_ExecCodeModuleWithPathnames ++ self.check_executecode_pathnames(execute_code_func) ++ ++ code = compile('attr = 1', '', 'exec') ++ self.assertRaises(UnicodeDecodeError, execute_code_func, b'\xff', code, NULL, NULL) ++ # CRASHES execute_code_func(NULL, code, NULL, NULL) ++ # CRASHES execute_code_func(name, NULL, NULL, NULL) ++ ++ def test_executecodemoduleobject(self): ++ # Test PyImport_ExecCodeModuleObject() ++ execute_code_func = _testlimitedcapi.PyImport_ExecCodeModuleObject ++ self.check_executecode_pathnames(execute_code_func, object=True) ++ ++ code = compile('attr = 1', '', 'exec') ++ self.assertRaises(TypeError, execute_code_func, [], code, NULL, NULL) ++ nonstring = tuple(['hashable non-string']) ++ self.assertRaises(AttributeError, execute_code_func, nonstring, code, NULL, NULL) ++ sys.modules.pop(nonstring, None) ++ # CRASHES execute_code_func(NULL, code, NULL, NULL) ++ # CRASHES execute_code_func(name, NULL, NULL, NULL) ++ ++ def check_importmoduleattr(self, importmoduleattr): ++ self.assertIs(importmoduleattr('sys', 'argv'), sys.argv) ++ self.assertIs(importmoduleattr('types', 'ModuleType'), types.ModuleType) ++ ++ # module name containing a dot ++ attr = importmoduleattr('email.message', 'Message') ++ from email.message import Message ++ self.assertIs(attr, Message) ++ ++ with self.assertRaises(ImportError): ++ # nonexistent module ++ importmoduleattr('nonexistentmodule', 'attr') ++ with self.assertRaises(AttributeError): ++ # nonexistent attribute ++ importmoduleattr('sys', 'nonexistentattr') ++ with self.assertRaises(AttributeError): ++ # attribute name containing a dot ++ importmoduleattr('sys', 'implementation.name') ++ ++ def test_importmoduleattr(self): ++ # Test PyImport_ImportModuleAttr() ++ importmoduleattr = _testcapi.PyImport_ImportModuleAttr ++ self.check_importmoduleattr(importmoduleattr) ++ ++ # Invalid module name type ++ for mod_name in (object(), 123, b'bytes'): ++ with self.subTest(mod_name=mod_name): ++ with self.assertRaises(TypeError): ++ importmoduleattr(mod_name, "attr") ++ ++ # Invalid attribute name type ++ for attr_name in (object(), 123, b'bytes'): ++ with self.subTest(attr_name=attr_name): ++ with self.assertRaises(TypeError): ++ importmoduleattr("sys", attr_name) ++ ++ with self.assertRaises(SystemError): ++ importmoduleattr(NULL, "argv") ++ # CRASHES importmoduleattr("sys", NULL) ++ ++ def test_importmoduleattrstring(self): ++ # Test PyImport_ImportModuleAttrString() ++ importmoduleattr = _testcapi.PyImport_ImportModuleAttrString ++ self.check_importmoduleattr(importmoduleattr) ++ ++ with self.assertRaises(UnicodeDecodeError): ++ importmoduleattr(b"sys\xff", "argv") ++ with self.assertRaises(UnicodeDecodeError): ++ importmoduleattr("sys", b"argv\xff") ++ ++ # CRASHES importmoduleattr(NULL, "argv") ++ # CRASHES importmoduleattr("sys", NULL) ++ ++ # TODO: test PyImport_GetImporter() ++ # TODO: test PyImport_ReloadModule() ++ # TODO: test PyImport_ExtendInittab() ++ # PyImport_AppendInittab() is tested by test_embed ++ ++ ++if __name__ == "__main__": ++ unittest.main() +diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py +index ada30181aee..b218f72f1bb 100644 +--- a/Lib/test/test_capi/test_misc.py ++++ b/Lib/test/test_capi/test_misc.py +@@ -75,6 +75,11 @@ + id = _testcapi.instancemethod(id) + testfunction = _testcapi.instancemethod(testfunction) + ++ ++CURRENT_THREAD_REGEX = r'Current thread.*:\n' if not support.Py_GIL_DISABLED else r'Stack .*:\n' ++ ++ ++@support.force_not_colorized_test_class + class CAPITest(unittest.TestCase): + + def test_instancemethod(self): +@@ -114,8 +119,7 @@ + "after Python initialization and before Python finalization, " + "but it was called without an active thread state. " + "Are you trying to call the C API inside of a Py_BEGIN_ALLOW_THREADS block?").encode() +- self.assertTrue(err.rstrip().startswith(msg), +- err) ++ self.assertStartsWith(err.rstrip(), msg) + + def test_memoryview_from_NULL_pointer(self): + self.assertRaises(ValueError, _testcapi.make_memoryview_from_NULL_pointer) +@@ -234,8 +238,8 @@ + r'Python runtime state: initialized\n' + r'SystemError: ' + r'returned NULL without setting an exception\n' +- r'\n' +- r'Current thread.*:\n' ++ r'\n' + ++ CURRENT_THREAD_REGEX + + r' File .*", line 6 in \n') + else: + with self.assertRaises(SystemError) as cm: +@@ -268,8 +272,8 @@ + r'SystemError: ' + r'returned a result with an exception set\n' +- r'\n' +- r'Current thread.*:\n' ++ r'\n' + ++ CURRENT_THREAD_REGEX + + r' File .*, line 6 in \n') + else: + with self.assertRaises(SystemError) as cm: +@@ -298,11 +302,11 @@ + r'with an exception set\n' + r'Python runtime state: initialized\n' + r'ValueError: bug\n' +- r'\n' +- r'Current thread .* \(most recent call first\):\n' ++ r'\n' + ++ CURRENT_THREAD_REGEX + + r' File .*, line 6 in \n' + r'\n' +- r'Extension modules: _testcapi \(total: 1\)\n') ++ r'Extension modules: _testcapi, _testinternalcapi \(total: 2\)\n') + else: + # Python built with NDEBUG macro defined: + # test _Py_CheckFunctionResult() instead. +@@ -399,42 +403,6 @@ + def test_buildvalue_N(self): + _testcapi.test_buildvalue_N() + +- def check_negative_refcount(self, code): +- # bpo-35059: Check that Py_DECREF() reports the correct filename +- # when calling _Py_NegativeRefcount() to abort Python. +- code = textwrap.dedent(code) +- rc, out, err = assert_python_failure('-c', code) +- self.assertRegex(err, +- br'_testcapimodule\.c:[0-9]+: ' +- br'_Py_NegativeRefcount: Assertion failed: ' +- br'object has negative ref count') +- +- @unittest.skipUnless(hasattr(_testcapi, 'negative_refcount'), +- 'need _testcapi.negative_refcount()') +- def test_negative_refcount(self): +- code = """ +- import _testcapi +- from test import support +- +- with support.SuppressCrashReport(): +- _testcapi.negative_refcount() +- """ +- self.check_negative_refcount(code) +- +- @unittest.skipUnless(hasattr(_testcapi, 'decref_freed_object'), +- 'need _testcapi.decref_freed_object()') +- @support.skip_if_sanitizer("use after free on purpose", +- address=True, memory=True, ub=True) +- def test_decref_freed_object(self): +- code = """ +- import _testcapi +- from test import support +- +- with support.SuppressCrashReport(): +- _testcapi.decref_freed_object() +- """ +- self.check_negative_refcount(code) +- + def test_trashcan_subclass(self): + # bpo-35983: Check that the trashcan mechanism for "list" is NOT + # activated when its tp_dealloc is being called by a subclass +@@ -718,7 +686,7 @@ + + def test_heaptype_with_custom_metaclass(self): + metaclass = _testcapi.HeapCTypeMetaclass +- self.assertTrue(issubclass(metaclass, type)) ++ self.assertIsSubclass(metaclass, type) + + # Class creation from C + t = _testcapi.pytype_fromspec_meta(metaclass) +@@ -734,7 +702,7 @@ + def test_heaptype_with_custom_metaclass_null_new(self): + metaclass = _testcapi.HeapCTypeMetaclassNullNew + +- self.assertTrue(issubclass(metaclass, type)) ++ self.assertIsSubclass(metaclass, type) + + # Class creation from C + t = _testcapi.pytype_fromspec_meta(metaclass) +@@ -749,7 +717,7 @@ + def test_heaptype_with_custom_metaclass_custom_new(self): + metaclass = _testcapi.HeapCTypeMetaclassCustomNew + +- self.assertTrue(issubclass(_testcapi.HeapCTypeMetaclassCustomNew, type)) ++ self.assertIsSubclass(_testcapi.HeapCTypeMetaclassCustomNew, type) + + msg = "Metaclasses with custom tp_new are not supported." + with self.assertRaisesRegex(TypeError, msg): +@@ -908,8 +876,7 @@ + names.append('Py_FrozenMain') + + for name in names: +- with self.subTest(name=name): +- self.assertTrue(hasattr(ctypes.pythonapi, name)) ++ self.assertHasAttr(ctypes.pythonapi, name) + + def test_clear_managed_dict(self): + +@@ -925,175 +892,6 @@ + _testcapi.clear_managed_dict(c) + self.assertEqual(c.__dict__, {}) + +- def test_function_get_code(self): +- import types +- +- def some(): +- pass +- +- code = _testcapi.function_get_code(some) +- self.assertIsInstance(code, types.CodeType) +- self.assertEqual(code, some.__code__) +- +- with self.assertRaises(SystemError): +- _testcapi.function_get_code(None) # not a function +- +- def test_function_get_globals(self): +- def some(): +- pass +- +- globals_ = _testcapi.function_get_globals(some) +- self.assertIsInstance(globals_, dict) +- self.assertEqual(globals_, some.__globals__) +- +- with self.assertRaises(SystemError): +- _testcapi.function_get_globals(None) # not a function +- +- def test_function_get_module(self): +- def some(): +- pass +- +- module = _testcapi.function_get_module(some) +- self.assertIsInstance(module, str) +- self.assertEqual(module, some.__module__) +- +- with self.assertRaises(SystemError): +- _testcapi.function_get_module(None) # not a function +- +- def test_function_get_defaults(self): +- def some( +- pos_only1, pos_only2='p', +- /, +- zero=0, optional=None, +- *, +- kw1, +- kw2=True, +- ): +- pass +- +- defaults = _testcapi.function_get_defaults(some) +- self.assertEqual(defaults, ('p', 0, None)) +- self.assertEqual(defaults, some.__defaults__) +- +- with self.assertRaises(SystemError): +- _testcapi.function_get_defaults(None) # not a function +- +- def test_function_set_defaults(self): +- def some( +- pos_only1, pos_only2='p', +- /, +- zero=0, optional=None, +- *, +- kw1, +- kw2=True, +- ): +- pass +- +- old_defaults = ('p', 0, None) +- self.assertEqual(_testcapi.function_get_defaults(some), old_defaults) +- self.assertEqual(some.__defaults__, old_defaults) +- +- with self.assertRaises(SystemError): +- _testcapi.function_set_defaults(some, 1) # not tuple or None +- self.assertEqual(_testcapi.function_get_defaults(some), old_defaults) +- self.assertEqual(some.__defaults__, old_defaults) +- +- with self.assertRaises(SystemError): +- _testcapi.function_set_defaults(1, ()) # not a function +- self.assertEqual(_testcapi.function_get_defaults(some), old_defaults) +- self.assertEqual(some.__defaults__, old_defaults) +- +- new_defaults = ('q', 1, None) +- _testcapi.function_set_defaults(some, new_defaults) +- self.assertEqual(_testcapi.function_get_defaults(some), new_defaults) +- self.assertEqual(some.__defaults__, new_defaults) +- +- # Empty tuple is fine: +- new_defaults = () +- _testcapi.function_set_defaults(some, new_defaults) +- self.assertEqual(_testcapi.function_get_defaults(some), new_defaults) +- self.assertEqual(some.__defaults__, new_defaults) +- +- class tuplesub(tuple): ... # tuple subclasses must work +- +- new_defaults = tuplesub(((1, 2), ['a', 'b'], None)) +- _testcapi.function_set_defaults(some, new_defaults) +- self.assertEqual(_testcapi.function_get_defaults(some), new_defaults) +- self.assertEqual(some.__defaults__, new_defaults) +- +- # `None` is special, it sets `defaults` to `NULL`, +- # it needs special handling in `_testcapi`: +- _testcapi.function_set_defaults(some, None) +- self.assertEqual(_testcapi.function_get_defaults(some), None) +- self.assertEqual(some.__defaults__, None) +- +- def test_function_get_kw_defaults(self): +- def some( +- pos_only1, pos_only2='p', +- /, +- zero=0, optional=None, +- *, +- kw1, +- kw2=True, +- ): +- pass +- +- defaults = _testcapi.function_get_kw_defaults(some) +- self.assertEqual(defaults, {'kw2': True}) +- self.assertEqual(defaults, some.__kwdefaults__) +- +- with self.assertRaises(SystemError): +- _testcapi.function_get_kw_defaults(None) # not a function +- +- def test_function_set_kw_defaults(self): +- def some( +- pos_only1, pos_only2='p', +- /, +- zero=0, optional=None, +- *, +- kw1, +- kw2=True, +- ): +- pass +- +- old_defaults = {'kw2': True} +- self.assertEqual(_testcapi.function_get_kw_defaults(some), old_defaults) +- self.assertEqual(some.__kwdefaults__, old_defaults) +- +- with self.assertRaises(SystemError): +- _testcapi.function_set_kw_defaults(some, 1) # not dict or None +- self.assertEqual(_testcapi.function_get_kw_defaults(some), old_defaults) +- self.assertEqual(some.__kwdefaults__, old_defaults) +- +- with self.assertRaises(SystemError): +- _testcapi.function_set_kw_defaults(1, {}) # not a function +- self.assertEqual(_testcapi.function_get_kw_defaults(some), old_defaults) +- self.assertEqual(some.__kwdefaults__, old_defaults) +- +- new_defaults = {'kw2': (1, 2, 3)} +- _testcapi.function_set_kw_defaults(some, new_defaults) +- self.assertEqual(_testcapi.function_get_kw_defaults(some), new_defaults) +- self.assertEqual(some.__kwdefaults__, new_defaults) +- +- # Empty dict is fine: +- new_defaults = {} +- _testcapi.function_set_kw_defaults(some, new_defaults) +- self.assertEqual(_testcapi.function_get_kw_defaults(some), new_defaults) +- self.assertEqual(some.__kwdefaults__, new_defaults) +- +- class dictsub(dict): ... # dict subclasses must work +- +- new_defaults = dictsub({'kw2': None}) +- _testcapi.function_set_kw_defaults(some, new_defaults) +- self.assertEqual(_testcapi.function_get_kw_defaults(some), new_defaults) +- self.assertEqual(some.__kwdefaults__, new_defaults) +- +- # `None` is special, it sets `kwdefaults` to `NULL`, +- # it needs special handling in `_testcapi`: +- _testcapi.function_set_kw_defaults(some, None) +- self.assertEqual(_testcapi.function_get_kw_defaults(some), None) +- self.assertEqual(some.__kwdefaults__, None) +- + def test_unstable_gc_new_with_extra_data(self): + class Data(_testcapi.ObjExtraData): + __slots__ = ('x', 'y') +@@ -1108,147 +906,6 @@ + del d.extra + self.assertIsNone(d.extra) + +- def test_get_type_name(self): +- class MyType: +- pass +- +- from _testcapi import ( +- get_type_name, get_type_qualname, +- get_type_fullyqualname, get_type_module_name) +- +- from collections import OrderedDict +- ht = _testcapi.get_heaptype_for_name() +- for cls, fullname, modname, qualname, name in ( +- (int, +- 'int', +- 'builtins', +- 'int', +- 'int'), +- (OrderedDict, +- 'collections.OrderedDict', +- 'collections', +- 'OrderedDict', +- 'OrderedDict'), +- (ht, +- '_testcapi.HeapTypeNameType', +- '_testcapi', +- 'HeapTypeNameType', +- 'HeapTypeNameType'), +- (MyType, +- f'{__name__}.CAPITest.test_get_type_name..MyType', +- __name__, +- 'CAPITest.test_get_type_name..MyType', +- 'MyType'), +- ): +- with self.subTest(cls=repr(cls)): +- self.assertEqual(get_type_fullyqualname(cls), fullname) +- self.assertEqual(get_type_module_name(cls), modname) +- self.assertEqual(get_type_qualname(cls), qualname) +- self.assertEqual(get_type_name(cls), name) +- +- # override __module__ +- ht.__module__ = 'test_module' +- self.assertEqual(get_type_fullyqualname(ht), 'test_module.HeapTypeNameType') +- self.assertEqual(get_type_module_name(ht), 'test_module') +- self.assertEqual(get_type_qualname(ht), 'HeapTypeNameType') +- self.assertEqual(get_type_name(ht), 'HeapTypeNameType') +- +- # override __name__ and __qualname__ +- MyType.__name__ = 'my_name' +- MyType.__qualname__ = 'my_qualname' +- self.assertEqual(get_type_fullyqualname(MyType), f'{__name__}.my_qualname') +- self.assertEqual(get_type_module_name(MyType), __name__) +- self.assertEqual(get_type_qualname(MyType), 'my_qualname') +- self.assertEqual(get_type_name(MyType), 'my_name') +- +- # override also __module__ +- MyType.__module__ = 'my_module' +- self.assertEqual(get_type_fullyqualname(MyType), 'my_module.my_qualname') +- self.assertEqual(get_type_module_name(MyType), 'my_module') +- self.assertEqual(get_type_qualname(MyType), 'my_qualname') +- self.assertEqual(get_type_name(MyType), 'my_name') +- +- # PyType_GetFullyQualifiedName() ignores the module if it's "builtins" +- # or "__main__" of it is not a string +- MyType.__module__ = 'builtins' +- self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname') +- MyType.__module__ = '__main__' +- self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname') +- MyType.__module__ = 123 +- self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname') +- +- def test_get_base_by_token(self): +- def get_base_by_token(src, key, comparable=True): +- def run(use_mro): +- find_first = _testcapi.pytype_getbasebytoken +- ret1, result = find_first(src, key, use_mro, True) +- ret2, no_result = find_first(src, key, use_mro, False) +- self.assertIn(ret1, (0, 1)) +- self.assertEqual(ret1, result is not None) +- self.assertEqual(ret1, ret2) +- self.assertIsNone(no_result) +- return result +- +- found_in_mro = run(True) +- found_in_bases = run(False) +- if comparable: +- self.assertIs(found_in_mro, found_in_bases) +- return found_in_mro +- return found_in_mro, found_in_bases +- +- create_type = _testcapi.create_type_with_token +- get_token = _testcapi.get_tp_token +- +- Py_TP_USE_SPEC = _testcapi.Py_TP_USE_SPEC +- self.assertEqual(Py_TP_USE_SPEC, 0) +- +- A1 = create_type('_testcapi.A1', Py_TP_USE_SPEC) +- self.assertTrue(get_token(A1) != Py_TP_USE_SPEC) +- +- B1 = create_type('_testcapi.B1', id(self)) +- self.assertTrue(get_token(B1) == id(self)) +- +- tokenA1 = get_token(A1) +- # find A1 from A1 +- found = get_base_by_token(A1, tokenA1) +- self.assertIs(found, A1) +- +- # no token in static types +- STATIC = type(1) +- self.assertEqual(get_token(STATIC), 0) +- found = get_base_by_token(STATIC, tokenA1) +- self.assertIs(found, None) +- +- # no token in pure subtypes +- class A2(A1): pass +- self.assertEqual(get_token(A2), 0) +- # find A1 +- class Z(STATIC, B1, A2): pass +- found = get_base_by_token(Z, tokenA1) +- self.assertIs(found, A1) +- +- # searching for NULL token is an error +- with self.assertRaises(SystemError): +- get_base_by_token(Z, 0) +- with self.assertRaises(SystemError): +- get_base_by_token(STATIC, 0) +- +- # share the token with A1 +- C1 = create_type('_testcapi.C1', tokenA1) +- self.assertTrue(get_token(C1) == tokenA1) +- +- # find C1 first by shared token +- class Z(C1, A2): pass +- found = get_base_by_token(Z, tokenA1) +- self.assertIs(found, C1) +- # B1 not found +- found = get_base_by_token(Z, get_token(B1)) +- self.assertIs(found, None) +- +- with self.assertRaises(TypeError): +- _testcapi.pytype_getbasebytoken( +- 'not a type', id(self), True, False) +- + def test_gen_get_code(self): + def genf(): yield + gen = genf() +@@ -1457,125 +1114,6 @@ + _testcapi.pyobject_getitemdata(0) + + +- def test_function_get_closure(self): +- from types import CellType +- +- def regular_function(): ... +- def unused_one_level(arg1): +- def inner(arg2, arg3): ... +- return inner +- def unused_two_levels(arg1, arg2): +- def decorator(arg3, arg4): +- def inner(arg5, arg6): ... +- return inner +- return decorator +- def with_one_level(arg1): +- def inner(arg2, arg3): +- return arg1 + arg2 + arg3 +- return inner +- def with_two_levels(arg1, arg2): +- def decorator(arg3, arg4): +- def inner(arg5, arg6): +- return arg1 + arg2 + arg3 + arg4 + arg5 + arg6 +- return inner +- return decorator +- +- # Functions without closures: +- self.assertIsNone(_testcapi.function_get_closure(regular_function)) +- self.assertIsNone(regular_function.__closure__) +- +- func = unused_one_level(1) +- closure = _testcapi.function_get_closure(func) +- self.assertIsNone(closure) +- self.assertIsNone(func.__closure__) +- +- func = unused_two_levels(1, 2)(3, 4) +- closure = _testcapi.function_get_closure(func) +- self.assertIsNone(closure) +- self.assertIsNone(func.__closure__) +- +- # Functions with closures: +- func = with_one_level(5) +- closure = _testcapi.function_get_closure(func) +- self.assertEqual(closure, func.__closure__) +- self.assertIsInstance(closure, tuple) +- self.assertEqual(len(closure), 1) +- self.assertEqual(len(closure), len(func.__code__.co_freevars)) +- self.assertTrue(all(isinstance(cell, CellType) for cell in closure)) +- self.assertTrue(closure[0].cell_contents, 5) +- +- func = with_two_levels(1, 2)(3, 4) +- closure = _testcapi.function_get_closure(func) +- self.assertEqual(closure, func.__closure__) +- self.assertIsInstance(closure, tuple) +- self.assertEqual(len(closure), 4) +- self.assertEqual(len(closure), len(func.__code__.co_freevars)) +- self.assertTrue(all(isinstance(cell, CellType) for cell in closure)) +- self.assertEqual([cell.cell_contents for cell in closure], +- [1, 2, 3, 4]) +- +- def test_function_get_closure_error(self): +- with self.assertRaises(SystemError): +- _testcapi.function_get_closure(1) +- with self.assertRaises(SystemError): +- _testcapi.function_get_closure(None) +- +- def test_function_set_closure(self): +- from types import CellType +- +- def function_without_closure(): ... +- def function_with_closure(arg): +- def inner(): +- return arg +- return inner +- +- func = function_without_closure +- _testcapi.function_set_closure(func, (CellType(1), CellType(1))) +- closure = _testcapi.function_get_closure(func) +- self.assertEqual([c.cell_contents for c in closure], [1, 1]) +- self.assertEqual([c.cell_contents for c in func.__closure__], [1, 1]) +- +- func = function_with_closure(1) +- _testcapi.function_set_closure(func, +- (CellType(1), CellType(2), CellType(3))) +- closure = _testcapi.function_get_closure(func) +- self.assertEqual([c.cell_contents for c in closure], [1, 2, 3]) +- self.assertEqual([c.cell_contents for c in func.__closure__], [1, 2, 3]) +- +- def test_function_set_closure_none(self): +- def function_without_closure(): ... +- def function_with_closure(arg): +- def inner(): +- return arg +- return inner +- +- _testcapi.function_set_closure(function_without_closure, None) +- self.assertIsNone( +- _testcapi.function_get_closure(function_without_closure)) +- self.assertIsNone(function_without_closure.__closure__) +- +- _testcapi.function_set_closure(function_with_closure, None) +- self.assertIsNone( +- _testcapi.function_get_closure(function_with_closure)) +- self.assertIsNone(function_with_closure.__closure__) +- +- def test_function_set_closure_errors(self): +- def function_without_closure(): ... +- +- with self.assertRaises(SystemError): +- _testcapi.function_set_closure(None, ()) # not a function +- +- with self.assertRaises(SystemError): +- _testcapi.function_set_closure(function_without_closure, 1) +- self.assertIsNone(function_without_closure.__closure__) # no change +- +- # NOTE: this works, but goes against the docs: +- _testcapi.function_set_closure(function_without_closure, (1, 2)) +- self.assertEqual( +- _testcapi.function_get_closure(function_without_closure), (1, 2)) +- self.assertEqual(function_without_closure.__closure__, (1, 2)) +- +- + class TestPendingCalls(unittest.TestCase): + + # See the comment in ceval.c (at the "handle_eval_breaker" label) +@@ -2139,28 +1677,27 @@ + self.assertEqual(ret, 0) + self.assertEqual(pickle.load(f), {'a': '123x', 'b': '123'}) + ++ # _testcapi cannot be imported in a subinterpreter on a Free Threaded build ++ @support.requires_gil_enabled() + def test_py_config_isoloated_per_interpreter(self): + # A config change in one interpreter must not leak to out to others. + # + # This test could verify ANY config value, it just happens to have been + # written around the time of int_max_str_digits. Refactoring is okay. + code = """if 1: +- import sys, _testinternalcapi ++ import sys, _testcapi + + # Any config value would do, this happens to be the one being + # double checked at the time this test was written. +- config = _testinternalcapi.get_config() +- config['int_max_str_digits'] = 55555 +- config['parse_argv'] = 0 +- _testinternalcapi.set_config(config) +- sub_value = _testinternalcapi.get_config()['int_max_str_digits'] ++ _testcapi.config_set('int_max_str_digits', 55555) ++ sub_value = _testcapi.config_get('int_max_str_digits') + assert sub_value == 55555, sub_value + """ +- before_config = _testinternalcapi.get_config() +- assert before_config['int_max_str_digits'] != 55555 ++ before_config = _testcapi.config_get('int_max_str_digits') ++ assert before_config != 55555 + self.assertEqual(support.run_in_subinterp(code), 0, + 'subinterp code failure, check stderr.') +- after_config = _testinternalcapi.get_config() ++ after_config = _testcapi.config_get('int_max_str_digits') + self.assertIsNot( + before_config, after_config, + "Expected get_config() to return a new dict on each call") +@@ -2363,7 +1900,7 @@ + + support.run_in_subinterp("import binascii; binascii.Error.foobar = 'foobar'") + +- self.assertFalse(hasattr(binascii.Error, "foobar")) ++ self.assertNotHasAttr(binascii.Error, "foobar") + + @unittest.skipIf(_testmultiphase is None, "test requires _testmultiphase module") + # gh-117649: The free-threaded build does not currently support sharing +@@ -2918,39 +2455,6 @@ + 0, get_refcount(interpid)) + + +-class BuiltinStaticTypesTests(unittest.TestCase): +- +- TYPES = [ +- object, +- type, +- int, +- str, +- dict, +- type(None), +- bool, +- BaseException, +- Exception, +- Warning, +- DeprecationWarning, # Warning subclass +- ] +- +- def test_tp_bases_is_set(self): +- # PyTypeObject.tp_bases is documented as public API. +- # See https://github.com/python/cpython/issues/105020. +- for typeobj in self.TYPES: +- with self.subTest(typeobj): +- bases = _testcapi.type_get_tp_bases(typeobj) +- self.assertIsNot(bases, None) +- +- def test_tp_mro_is_set(self): +- # PyTypeObject.tp_bases is documented as public API. +- # See https://github.com/python/cpython/issues/105020. +- for typeobj in self.TYPES: +- with self.subTest(typeobj): +- mro = _testcapi.type_get_tp_mro(typeobj) +- self.assertIsNot(mro, None) +- +- + class TestStaticTypes(unittest.TestCase): + + _has_run = False +@@ -3335,6 +2839,50 @@ + self.assertEqual(len(set(py_thread_ids)), len(py_thread_ids), + py_thread_ids) + ++class TestVersions(unittest.TestCase): ++ full_cases = ( ++ (3, 4, 1, 0xA, 2, 0x030401a2), ++ (3, 10, 0, 0xF, 0, 0x030a00f0), ++ (0x103, 0x10B, 0xFF00, -1, 0xF0, 0x030b00f0), # test masking ++ ) ++ xy_cases = ( ++ (3, 4, 0x03040000), ++ (3, 10, 0x030a0000), ++ (0x103, 0x10B, 0x030b0000), # test masking ++ ) ++ ++ def test_pack_full_version(self): ++ for *args, expected in self.full_cases: ++ with self.subTest(hexversion=hex(expected)): ++ result = _testlimitedcapi.pack_full_version(*args) ++ self.assertEqual(result, expected) ++ ++ def test_pack_version(self): ++ for *args, expected in self.xy_cases: ++ with self.subTest(hexversion=hex(expected)): ++ result = _testlimitedcapi.pack_version(*args) ++ self.assertEqual(result, expected) ++ ++ def test_pack_full_version_ctypes(self): ++ ctypes = import_helper.import_module('ctypes') ++ ctypes_func = ctypes.pythonapi.Py_PACK_FULL_VERSION ++ ctypes_func.restype = ctypes.c_uint32 ++ ctypes_func.argtypes = [ctypes.c_int] * 5 ++ for *args, expected in self.full_cases: ++ with self.subTest(hexversion=hex(expected)): ++ result = ctypes_func(*args) ++ self.assertEqual(result, expected) ++ ++ def test_pack_version_ctypes(self): ++ ctypes = import_helper.import_module('ctypes') ++ ctypes_func = ctypes.pythonapi.Py_PACK_VERSION ++ ctypes_func.restype = ctypes.c_uint32 ++ ctypes_func.argtypes = [ctypes.c_int] * 2 ++ for *args, expected in self.xy_cases: ++ with self.subTest(hexversion=hex(expected)): ++ result = ctypes_func(*args) ++ self.assertEqual(result, expected) ++ + + if __name__ == "__main__": + unittest.main() +diff --git a/Lib/test/test_capi/test_object.py b/Lib/test/test_capi/test_object.py +index b0d39937fd8..5d0a383de64 100644 +--- a/Lib/test/test_capi/test_object.py ++++ b/Lib/test/test_capi/test_object.py +@@ -1,9 +1,12 @@ + import enum ++import textwrap + import unittest + from test import support + from test.support import import_helper + from test.support import os_helper + from test.support import threading_helper ++from test.support.script_helper import assert_python_failure ++ + + _testlimitedcapi = import_helper.import_module('_testlimitedcapi') + _testcapi = import_helper.import_module('_testcapi') +@@ -170,5 +173,42 @@ + self.assertTrue(_testinternalcapi.has_deferred_refcount(silly_list)) + + ++class CAPITest(unittest.TestCase): ++ def check_negative_refcount(self, code): ++ # bpo-35059: Check that Py_DECREF() reports the correct filename ++ # when calling _Py_NegativeRefcount() to abort Python. ++ code = textwrap.dedent(code) ++ rc, out, err = assert_python_failure('-c', code) ++ self.assertRegex(err, ++ br'object\.c:[0-9]+: ' ++ br'_Py_NegativeRefcount: Assertion failed: ' ++ br'object has negative ref count') ++ ++ @unittest.skipUnless(hasattr(_testcapi, 'negative_refcount'), ++ 'need _testcapi.negative_refcount()') ++ def test_negative_refcount(self): ++ code = """ ++ import _testcapi ++ from test import support ++ ++ with support.SuppressCrashReport(): ++ _testcapi.negative_refcount() ++ """ ++ self.check_negative_refcount(code) ++ ++ @unittest.skipUnless(hasattr(_testcapi, 'decref_freed_object'), ++ 'need _testcapi.decref_freed_object()') ++ @support.skip_if_sanitizer("use after free on purpose", ++ address=True, memory=True, ub=True) ++ def test_decref_freed_object(self): ++ code = """ ++ import _testcapi ++ from test import support ++ ++ with support.SuppressCrashReport(): ++ _testcapi.decref_freed_object() ++ """ ++ self.check_negative_refcount(code) ++ + if __name__ == "__main__": + unittest.main() +diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py +index 4cf9b66170c..2a9b777862c 100644 +--- a/Lib/test/test_capi/test_opt.py ++++ b/Lib/test/test_capi/test_opt.py +@@ -1,4 +1,5 @@ + import contextlib ++import itertools + import sys + import textwrap + import unittest +@@ -8,114 +9,22 @@ + import _opcode + + from test.support import (script_helper, requires_specialization, +- import_helper, Py_GIL_DISABLED) ++ import_helper, Py_GIL_DISABLED, requires_jit_enabled, ++ reset_code) + + _testinternalcapi = import_helper.import_module("_testinternalcapi") + + from _testinternalcapi import TIER2_THRESHOLD + +-@contextlib.contextmanager +-def temporary_optimizer(opt): +- old_opt = _testinternalcapi.get_optimizer() +- _testinternalcapi.set_optimizer(opt) +- try: +- yield +- finally: +- _testinternalcapi.set_optimizer(old_opt) +- + + @contextlib.contextmanager + def clear_executors(func): + # Clear executors in func before and after running a block +- func.__code__ = func.__code__.replace() ++ reset_code(func) + try: + yield + finally: +- func.__code__ = func.__code__.replace() +- +- +-@requires_specialization +-@unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds") +-@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"), +- "Requires optimizer infrastructure") +-class TestOptimizerAPI(unittest.TestCase): +- +- def test_new_counter_optimizer_dealloc(self): +- # See gh-108727 +- def f(): +- _testinternalcapi.new_counter_optimizer() +- +- f() +- +- def test_get_set_optimizer(self): +- old = _testinternalcapi.get_optimizer() +- opt = _testinternalcapi.new_counter_optimizer() +- try: +- _testinternalcapi.set_optimizer(opt) +- self.assertEqual(_testinternalcapi.get_optimizer(), opt) +- _testinternalcapi.set_optimizer(None) +- self.assertEqual(_testinternalcapi.get_optimizer(), None) +- finally: +- _testinternalcapi.set_optimizer(old) +- +- +- def test_counter_optimizer(self): +- # Generate a new function at each call +- ns = {} +- exec(textwrap.dedent(f""" +- def loop(): +- for _ in range({TIER2_THRESHOLD + 1000}): +- pass +- """), ns, ns) +- loop = ns['loop'] +- +- for repeat in range(5): +- opt = _testinternalcapi.new_counter_optimizer() +- with temporary_optimizer(opt): +- self.assertEqual(opt.get_count(), 0) +- with clear_executors(loop): +- loop() +- self.assertEqual(opt.get_count(), 1001) +- +- def test_long_loop(self): +- "Check that we aren't confused by EXTENDED_ARG" +- +- # Generate a new function at each call +- ns = {} +- exec(textwrap.dedent(f""" +- def nop(): +- pass +- +- def long_loop(): +- for _ in range({TIER2_THRESHOLD + 20}): +- nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); +- nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); +- nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); +- nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); +- nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); +- nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); +- nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); +- """), ns, ns) +- long_loop = ns['long_loop'] +- +- opt = _testinternalcapi.new_counter_optimizer() +- with temporary_optimizer(opt): +- self.assertEqual(opt.get_count(), 0) +- long_loop() +- self.assertEqual(opt.get_count(), 21) # Need iterations to warm up +- +- def test_code_restore_for_ENTER_EXECUTOR(self): +- def testfunc(x): +- i = 0 +- while i < x: +- i += 1 +- +- opt = _testinternalcapi.new_counter_optimizer() +- with temporary_optimizer(opt): +- testfunc(1000) +- code, replace_code = testfunc.__code__, testfunc.__code__.replace() +- self.assertEqual(code, replace_code) +- self.assertEqual(hash(code), hash(replace_code)) ++ reset_code(func) + + + def get_first_executor(func): +@@ -140,18 +49,9 @@ + + @requires_specialization + @unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds") +-@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"), +- "Requires optimizer infrastructure") ++@requires_jit_enabled + class TestExecutorInvalidation(unittest.TestCase): + +- def setUp(self): +- self.old = _testinternalcapi.get_optimizer() +- self.opt = _testinternalcapi.new_counter_optimizer() +- _testinternalcapi.set_optimizer(self.opt) +- +- def tearDown(self): +- _testinternalcapi.set_optimizer(self.old) +- + def test_invalidate_object(self): + # Generate a new set of functions at each call + ns = {} +@@ -195,9 +95,7 @@ + pass + """), ns, ns) + f = ns['f'] +- opt = _testinternalcapi.new_uop_optimizer() +- with temporary_optimizer(opt): +- f() ++ f() + exe = get_first_executor(f) + self.assertIsNotNone(exe) + self.assertTrue(exe.is_valid()) +@@ -208,9 +106,7 @@ + def f(): + for _ in range(TIER2_THRESHOLD): + pass +- opt = _testinternalcapi.new_uop_optimizer() +- with temporary_optimizer(opt): +- f() ++ f() + exe = get_first_executor(f) + self.assertIsNotNone(exe) + self.assertTrue(exe.is_valid()) +@@ -222,8 +118,7 @@ + + @requires_specialization + @unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds") +-@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"), +- "Requires optimizer infrastructure") ++@requires_jit_enabled + @unittest.skipIf(os.getenv("PYTHON_UOPS_OPTIMIZE") == "0", "Needs uop optimizer to run.") + class TestUops(unittest.TestCase): + +@@ -233,9 +128,7 @@ + while i < x: + i += 1 + +- opt = _testinternalcapi.new_uop_optimizer() +- with temporary_optimizer(opt): +- testfunc(TIER2_THRESHOLD) ++ testfunc(TIER2_THRESHOLD) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) +@@ -281,11 +174,9 @@ + """), ns, ns) + many_vars = ns["many_vars"] + +- opt = _testinternalcapi.new_uop_optimizer() +- with temporary_optimizer(opt): +- ex = get_first_executor(many_vars) +- self.assertIsNone(ex) +- many_vars() ++ ex = get_first_executor(many_vars) ++ self.assertIsNone(ex) ++ many_vars() + + ex = get_first_executor(many_vars) + self.assertIsNotNone(ex) +@@ -304,10 +195,7 @@ + while i < x: + i += 1 + +- opt = _testinternalcapi.new_uop_optimizer() +- +- with temporary_optimizer(opt): +- testfunc(TIER2_THRESHOLD) ++ testfunc(TIER2_THRESHOLD) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) +@@ -320,9 +208,7 @@ + while i < n: + i += 1 + +- opt = _testinternalcapi.new_uop_optimizer() +- with temporary_optimizer(opt): +- testfunc(TIER2_THRESHOLD) ++ testfunc(TIER2_THRESHOLD) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) +@@ -335,9 +221,7 @@ + if x is None: + x = 0 + +- opt = _testinternalcapi.new_uop_optimizer() +- with temporary_optimizer(opt): +- testfunc(range(TIER2_THRESHOLD)) ++ testfunc(range(TIER2_THRESHOLD)) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) +@@ -352,9 +236,7 @@ + if x is not None: + x = 0 + +- opt = _testinternalcapi.new_uop_optimizer() +- with temporary_optimizer(opt): +- testfunc(range(TIER2_THRESHOLD)) ++ testfunc(range(TIER2_THRESHOLD)) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) +@@ -368,9 +250,7 @@ + while not i >= n: + i += 1 + +- opt = _testinternalcapi.new_uop_optimizer() +- with temporary_optimizer(opt): +- testfunc(TIER2_THRESHOLD) ++ testfunc(TIER2_THRESHOLD) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) +@@ -383,9 +263,7 @@ + while i < n: + i += 1 + +- opt = _testinternalcapi.new_uop_optimizer() +- with temporary_optimizer(opt): +- testfunc(TIER2_THRESHOLD) ++ testfunc(TIER2_THRESHOLD) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) +@@ -403,9 +281,7 @@ + a += 1 + return a + +- opt = _testinternalcapi.new_uop_optimizer() +- with temporary_optimizer(opt): +- testfunc(TIER2_THRESHOLD) ++ testfunc(TIER2_THRESHOLD) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) +@@ -421,10 +297,8 @@ + total += i + return total + +- opt = _testinternalcapi.new_uop_optimizer() +- with temporary_optimizer(opt): +- total = testfunc(TIER2_THRESHOLD) +- self.assertEqual(total, sum(range(TIER2_THRESHOLD))) ++ total = testfunc(TIER2_THRESHOLD) ++ self.assertEqual(total, sum(range(TIER2_THRESHOLD))) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) +@@ -442,11 +316,9 @@ + total += i + return total + +- opt = _testinternalcapi.new_uop_optimizer() +- with temporary_optimizer(opt): +- a = list(range(TIER2_THRESHOLD)) +- total = testfunc(a) +- self.assertEqual(total, sum(a)) ++ a = list(range(TIER2_THRESHOLD)) ++ total = testfunc(a) ++ self.assertEqual(total, sum(a)) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) +@@ -464,11 +336,9 @@ + total += i + return total + +- opt = _testinternalcapi.new_uop_optimizer() +- with temporary_optimizer(opt): +- a = tuple(range(TIER2_THRESHOLD)) +- total = testfunc(a) +- self.assertEqual(total, sum(a)) ++ a = tuple(range(TIER2_THRESHOLD)) ++ total = testfunc(a) ++ self.assertEqual(total, sum(a)) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) +@@ -484,14 +354,12 @@ + for x in it: + pass + +- opt = _testinternalcapi.new_uop_optimizer() +- with temporary_optimizer(opt): +- a = [1, 2, 3] +- it = iter(a) +- testfunc(it) +- a.append(4) +- with self.assertRaises(StopIteration): +- next(it) ++ a = [1, 2, 3] ++ it = iter(a) ++ testfunc(it) ++ a.append(4) ++ with self.assertRaises(StopIteration): ++ next(it) + + def test_call_py_exact_args(self): + def testfunc(n): +@@ -500,9 +368,7 @@ + for i in range(n): + dummy(i) + +- opt = _testinternalcapi.new_uop_optimizer() +- with temporary_optimizer(opt): +- testfunc(TIER2_THRESHOLD) ++ testfunc(TIER2_THRESHOLD) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) +@@ -518,9 +384,7 @@ + else: + i = 1 + +- opt = _testinternalcapi.new_uop_optimizer() +- with temporary_optimizer(opt): +- testfunc(TIER2_THRESHOLD) ++ testfunc(TIER2_THRESHOLD) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) +@@ -546,9 +410,7 @@ + x += 1000*i + j + return x + +- opt = _testinternalcapi.new_uop_optimizer() +- with temporary_optimizer(opt): +- x = testfunc(TIER2_THRESHOLD, TIER2_THRESHOLD) ++ x = testfunc(TIER2_THRESHOLD, TIER2_THRESHOLD) + + self.assertEqual(x, sum(range(TIER2_THRESHOLD)) * TIER2_THRESHOLD * 1001) + +@@ -573,9 +435,7 @@ + bits += 1 + return bits + +- opt = _testinternalcapi.new_uop_optimizer() +- with temporary_optimizer(opt): +- x = testfunc(TIER2_THRESHOLD * 2) ++ x = testfunc(TIER2_THRESHOLD * 2) + + self.assertEqual(x, TIER2_THRESHOLD * 5) + ex = get_first_executor(testfunc) +@@ -588,16 +448,12 @@ + + @requires_specialization + @unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds") +-@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"), +- "Requires optimizer infrastructure") ++@requires_jit_enabled + @unittest.skipIf(os.getenv("PYTHON_UOPS_OPTIMIZE") == "0", "Needs uop optimizer to run.") + class TestUopsOptimization(unittest.TestCase): + + def _run_with_optimizer(self, testfunc, arg): +- res = None +- opt = _testinternalcapi.new_uop_optimizer() +- with temporary_optimizer(opt): +- res = testfunc(arg) ++ res = testfunc(arg) + + ex = get_first_executor(testfunc) + return res, ex +@@ -631,10 +487,7 @@ + num += 1 + return a + +- opt = _testinternalcapi.new_uop_optimizer() +- res = None +- with temporary_optimizer(opt): +- res = testfunc(TIER2_THRESHOLD) ++ res = testfunc(TIER2_THRESHOLD) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) +@@ -655,10 +508,7 @@ + num += 1 + return x + +- opt = _testinternalcapi.new_uop_optimizer() +- res = None +- with temporary_optimizer(opt): +- res = testfunc(TIER2_THRESHOLD) ++ res = testfunc(TIER2_THRESHOLD) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) +@@ -750,16 +600,14 @@ + for i in range(n): + dummy(i) + +- opt = _testinternalcapi.new_uop_optimizer() + # Trigger specialization + testfunc(8) +- with temporary_optimizer(opt): +- del dummy +- gc.collect() ++ del dummy ++ gc.collect() + +- def dummy(x): +- return x + 2 +- testfunc(32) ++ def dummy(x): ++ return x + 2 ++ testfunc(32) + + ex = get_first_executor(testfunc) + # Honestly as long as it doesn't crash it's fine. +@@ -792,16 +640,14 @@ + x = range(i) + return x + +- opt = _testinternalcapi.new_uop_optimizer() +- _testinternalcapi.set_optimizer(opt) + testfunc(_testinternalcapi.TIER2_THRESHOLD) + + ex = get_first_executor(testfunc) + assert ex is not None + uops = get_opnames(ex) + assert "_LOAD_GLOBAL_BUILTINS" not in uops +- assert "_LOAD_CONST_INLINE_BORROW_WITH_NULL" in uops +- """)) ++ assert "_LOAD_CONST_INLINE_BORROW" in uops ++ """), PYTHON_JIT="1") + self.assertEqual(result[0].rc, 0, result) + + def test_float_add_constant_propagation(self): +@@ -1314,6 +1160,7 @@ + self.assertIsNotNone(ex) + self.assertIn("_RETURN_GENERATOR", get_opnames(ex)) + ++ @unittest.skip("Tracing into generators currently isn't supported.") + def test_for_iter_gen(self): + def gen(n): + for i in range(n): +@@ -1488,9 +1335,7 @@ + # Only works on functions promoted to constants + global_identity(i) + +- opt = _testinternalcapi.new_uop_optimizer() +- with temporary_optimizer(opt): +- testfunc(TIER2_THRESHOLD) ++ testfunc(TIER2_THRESHOLD) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) +@@ -1511,6 +1356,87 @@ + with self.assertRaises(TypeError): + {item for item in items} + ++ def test_power_type_depends_on_input_values(self): ++ template = textwrap.dedent(""" ++ import _testinternalcapi ++ ++ L, R, X, Y = {l}, {r}, {x}, {y} ++ ++ def check(actual: complex, expected: complex) -> None: ++ assert actual == expected, (actual, expected) ++ assert type(actual) is type(expected), (actual, expected) ++ ++ def f(l: complex, r: complex) -> None: ++ expected_local_local = pow(l, r) + pow(l, r) ++ expected_const_local = pow(L, r) + pow(L, r) ++ expected_local_const = pow(l, R) + pow(l, R) ++ expected_const_const = pow(L, R) + pow(L, R) ++ for _ in range(_testinternalcapi.TIER2_THRESHOLD): ++ # Narrow types: ++ l + l, r + r ++ # The powers produce results, and the addition is unguarded: ++ check(l ** r + l ** r, expected_local_local) ++ check(L ** r + L ** r, expected_const_local) ++ check(l ** R + l ** R, expected_local_const) ++ check(L ** R + L ** R, expected_const_const) ++ ++ # JIT for one pair of values... ++ f(L, R) ++ # ...then run with another: ++ f(X, Y) ++ """) ++ interesting = [ ++ (1, 1), # int ** int -> int ++ (1, -1), # int ** int -> float ++ (1.0, 1), # float ** int -> float ++ (1, 1.0), # int ** float -> float ++ (-1, 0.5), # int ** float -> complex ++ (1.0, 1.0), # float ** float -> float ++ (-1.0, 0.5), # float ** float -> complex ++ ] ++ for (l, r), (x, y) in itertools.product(interesting, repeat=2): ++ s = template.format(l=l, r=r, x=x, y=y) ++ with self.subTest(l=l, r=r, x=x, y=y): ++ script_helper.assert_python_ok("-c", s) ++ ++ def test_symbols_flow_through_tuples(self): ++ def testfunc(n): ++ for _ in range(n): ++ a = 1 ++ b = 2 ++ t = a, b ++ x, y = t ++ r = x + y ++ return r ++ ++ res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) ++ self.assertEqual(res, 3) ++ self.assertIsNotNone(ex) ++ uops = get_opnames(ex) ++ self.assertIn("_BINARY_OP_ADD_INT", uops) ++ self.assertNotIn("_GUARD_BOTH_INT", uops) ++ self.assertNotIn("_GUARD_NOS_INT", uops) ++ self.assertNotIn("_GUARD_TOS_INT", uops) ++ ++ def test_decref_escapes(self): ++ class Convert9999ToNone: ++ def __del__(self): ++ ns = sys._getframe(1).f_locals ++ if ns["i"] == _testinternalcapi.TIER2_THRESHOLD: ++ ns["i"] = None ++ ++ def crash_addition(): ++ try: ++ for i in range(_testinternalcapi.TIER2_THRESHOLD + 1): ++ n = Convert9999ToNone() ++ i + i # Remove guards for i. ++ n = None # Change i. ++ i + i # This crashed when we didn't treat DECREF as escaping (gh-124483) ++ except TypeError: ++ pass ++ ++ crash_addition() ++ + + def global_identity(x): + return x +diff --git a/Lib/test/test_capi/test_sys.py b/Lib/test/test_capi/test_sys.py +index 54a8e026d88..d3a9b378e77 100644 +--- a/Lib/test/test_capi/test_sys.py ++++ b/Lib/test/test_capi/test_sys.py +@@ -51,7 +51,7 @@ + self.assertEqual(setobject(b'newattr', value2), 0) + self.assertIs(sys.newattr, value2) + self.assertEqual(setobject(b'newattr', NULL), 0) +- self.assertFalse(hasattr(sys, 'newattr')) ++ self.assertNotHasAttr(sys, 'newattr') + self.assertEqual(setobject(b'newattr', NULL), 0) + finally: + with contextlib.suppress(AttributeError): +@@ -60,7 +60,7 @@ + self.assertEqual(setobject('\U0001f40d'.encode(), value), 0) + self.assertIs(getattr(sys, '\U0001f40d'), value) + self.assertEqual(setobject('\U0001f40d'.encode(), NULL), 0) +- self.assertFalse(hasattr(sys, '\U0001f40d')) ++ self.assertNotHasAttr(sys, '\U0001f40d') + finally: + with contextlib.suppress(AttributeError): + delattr(sys, '\U0001f40d') +diff --git a/Lib/test/test_capi/test_type.py b/Lib/test/test_capi/test_type.py +index 54c83e09f89..7e5d013d737 100644 +--- a/Lib/test/test_capi/test_type.py ++++ b/Lib/test/test_capi/test_type.py +@@ -1,10 +1,184 @@ +-from test.support import import_helper ++from test.support import import_helper, Py_GIL_DISABLED, refleak_helper + import unittest + + _testcapi = import_helper.import_module('_testcapi') + + ++class BuiltinStaticTypesTests(unittest.TestCase): ++ ++ TYPES = [ ++ object, ++ type, ++ int, ++ str, ++ dict, ++ type(None), ++ bool, ++ BaseException, ++ Exception, ++ Warning, ++ DeprecationWarning, # Warning subclass ++ ] ++ ++ def test_tp_bases_is_set(self): ++ # PyTypeObject.tp_bases is documented as public API. ++ # See https://github.com/python/cpython/issues/105020. ++ for typeobj in self.TYPES: ++ with self.subTest(typeobj): ++ bases = _testcapi.type_get_tp_bases(typeobj) ++ self.assertIsNot(bases, None) ++ ++ def test_tp_mro_is_set(self): ++ # PyTypeObject.tp_bases is documented as public API. ++ # See https://github.com/python/cpython/issues/105020. ++ for typeobj in self.TYPES: ++ with self.subTest(typeobj): ++ mro = _testcapi.type_get_tp_mro(typeobj) ++ self.assertIsNot(mro, None) ++ ++ + class TypeTests(unittest.TestCase): ++ def test_get_type_name(self): ++ class MyType: ++ pass ++ ++ from _testcapi import ( ++ get_type_name, get_type_qualname, ++ get_type_fullyqualname, get_type_module_name) ++ ++ from collections import OrderedDict ++ ht = _testcapi.get_heaptype_for_name() ++ for cls, fullname, modname, qualname, name in ( ++ (int, ++ 'int', ++ 'builtins', ++ 'int', ++ 'int'), ++ (OrderedDict, ++ 'collections.OrderedDict', ++ 'collections', ++ 'OrderedDict', ++ 'OrderedDict'), ++ (ht, ++ '_testcapi.HeapTypeNameType', ++ '_testcapi', ++ 'HeapTypeNameType', ++ 'HeapTypeNameType'), ++ (MyType, ++ f'{__name__}.TypeTests.test_get_type_name..MyType', ++ __name__, ++ 'TypeTests.test_get_type_name..MyType', ++ 'MyType'), ++ ): ++ with self.subTest(cls=repr(cls)): ++ self.assertEqual(get_type_fullyqualname(cls), fullname) ++ self.assertEqual(get_type_module_name(cls), modname) ++ self.assertEqual(get_type_qualname(cls), qualname) ++ self.assertEqual(get_type_name(cls), name) ++ ++ # override __module__ ++ ht.__module__ = 'test_module' ++ self.assertEqual(get_type_fullyqualname(ht), 'test_module.HeapTypeNameType') ++ self.assertEqual(get_type_module_name(ht), 'test_module') ++ self.assertEqual(get_type_qualname(ht), 'HeapTypeNameType') ++ self.assertEqual(get_type_name(ht), 'HeapTypeNameType') ++ ++ # override __name__ and __qualname__ ++ MyType.__name__ = 'my_name' ++ MyType.__qualname__ = 'my_qualname' ++ self.assertEqual(get_type_fullyqualname(MyType), f'{__name__}.my_qualname') ++ self.assertEqual(get_type_module_name(MyType), __name__) ++ self.assertEqual(get_type_qualname(MyType), 'my_qualname') ++ self.assertEqual(get_type_name(MyType), 'my_name') ++ ++ # override also __module__ ++ MyType.__module__ = 'my_module' ++ self.assertEqual(get_type_fullyqualname(MyType), 'my_module.my_qualname') ++ self.assertEqual(get_type_module_name(MyType), 'my_module') ++ self.assertEqual(get_type_qualname(MyType), 'my_qualname') ++ self.assertEqual(get_type_name(MyType), 'my_name') ++ ++ # PyType_GetFullyQualifiedName() ignores the module if it's "builtins" ++ # or "__main__" of it is not a string ++ MyType.__module__ = 'builtins' ++ self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname') ++ MyType.__module__ = '__main__' ++ self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname') ++ MyType.__module__ = 123 ++ self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname') ++ ++ def test_get_base_by_token(self): ++ def get_base_by_token(src, key, comparable=True): ++ def run(use_mro): ++ find_first = _testcapi.pytype_getbasebytoken ++ ret1, result = find_first(src, key, use_mro, True) ++ ret2, no_result = find_first(src, key, use_mro, False) ++ self.assertIn(ret1, (0, 1)) ++ self.assertEqual(ret1, result is not None) ++ self.assertEqual(ret1, ret2) ++ self.assertIsNone(no_result) ++ return result ++ ++ found_in_mro = run(True) ++ found_in_bases = run(False) ++ if comparable: ++ self.assertIs(found_in_mro, found_in_bases) ++ return found_in_mro ++ return found_in_mro, found_in_bases ++ ++ create_type = _testcapi.create_type_with_token ++ get_token = _testcapi.get_tp_token ++ ++ Py_TP_USE_SPEC = _testcapi.Py_TP_USE_SPEC ++ self.assertEqual(Py_TP_USE_SPEC, 0) ++ ++ A1 = create_type('_testcapi.A1', Py_TP_USE_SPEC) ++ self.assertTrue(get_token(A1) != Py_TP_USE_SPEC) ++ ++ B1 = create_type('_testcapi.B1', id(self)) ++ self.assertTrue(get_token(B1) == id(self)) ++ ++ tokenA1 = get_token(A1) ++ # find A1 from A1 ++ found = get_base_by_token(A1, tokenA1) ++ self.assertIs(found, A1) ++ ++ # no token in static types ++ STATIC = type(1) ++ self.assertEqual(get_token(STATIC), 0) ++ found = get_base_by_token(STATIC, tokenA1) ++ self.assertIs(found, None) ++ ++ # no token in pure subtypes ++ class A2(A1): pass ++ self.assertEqual(get_token(A2), 0) ++ # find A1 ++ class Z(STATIC, B1, A2): pass ++ found = get_base_by_token(Z, tokenA1) ++ self.assertIs(found, A1) ++ ++ # searching for NULL token is an error ++ with self.assertRaises(SystemError): ++ get_base_by_token(Z, 0) ++ with self.assertRaises(SystemError): ++ get_base_by_token(STATIC, 0) ++ ++ # share the token with A1 ++ C1 = create_type('_testcapi.C1', tokenA1) ++ self.assertTrue(get_token(C1) == tokenA1) ++ ++ # find C1 first by shared token ++ class Z(C1, A2): pass ++ found = get_base_by_token(Z, tokenA1) ++ self.assertIs(found, C1) ++ # B1 not found ++ found = get_base_by_token(Z, get_token(B1)) ++ self.assertIs(found, None) ++ ++ with self.assertRaises(TypeError): ++ _testcapi.pytype_getbasebytoken( ++ 'not a type', id(self), True, False) ++ + def test_freeze(self): + # test PyType_Freeze() + type_freeze = _testcapi.type_freeze +@@ -37,6 +211,9 @@ + # as well + type_freeze(D) + ++ @unittest.skipIf( ++ Py_GIL_DISABLED and refleak_helper.hunting_for_refleaks(), ++ "Specialization failure triggers gh-127773") + def test_freeze_meta(self): + """test PyType_Freeze() with overridden MRO""" + type_freeze = _testcapi.type_freeze +@@ -64,3 +241,10 @@ + Base.value = 3 + type_freeze(FreezeThis) + self.assertEqual(FreezeThis.value, 2) ++ ++ def test_manual_heap_type(self): ++ # gh-128923: test that a manually allocated and initailized heap type ++ # works correctly ++ ManualHeapType = _testcapi.ManualHeapType ++ for i in range(100): ++ self.assertIsInstance(ManualHeapType(), ManualHeapType) +diff --git a/Lib/test/test_capi/test_unicode.py b/Lib/test/test_capi/test_unicode.py +index 65d8242ad3f..3408c10f426 100644 +--- a/Lib/test/test_capi/test_unicode.py ++++ b/Lib/test/test_capi/test_unicode.py +@@ -1,7 +1,7 @@ + import unittest + import sys + from test import support +-from test.support import import_helper ++from test.support import threading_helper + + try: + import _testcapi +@@ -1005,6 +1005,24 @@ + self.assertRaises(TypeError, unicode_asutf8, [], 0) + # CRASHES unicode_asutf8(NULL, 0) + ++ @unittest.skipIf(_testcapi is None, 'need _testcapi module') ++ @threading_helper.requires_working_threading() ++ def test_asutf8_race(self): ++ """Test that there's no race condition in PyUnicode_AsUTF8()""" ++ unicode_asutf8 = _testcapi.unicode_asutf8 ++ from threading import Thread ++ ++ data = "😊" ++ ++ def worker(): ++ for _ in range(1000): ++ self.assertEqual(unicode_asutf8(data, 5), b'\xf0\x9f\x98\x8a\0') ++ ++ threads = [Thread(target=worker) for _ in range(10)] ++ with threading_helper.start_threads(threads): ++ pass ++ ++ + @support.cpython_only + @unittest.skipIf(_testlimitedcapi is None, 'need _testlimitedcapi module') + def test_asutf8andsize(self): +diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py +index e20e59944e9..017aca3c828 100644 +--- a/Lib/test/test_class.py ++++ b/Lib/test/test_class.py +@@ -1,6 +1,7 @@ + "Test the functionality of Python classes implementing operators." + + import unittest ++from test import support + from test.support import cpython_only, import_helper, script_helper, skip_emscripten_stack_overflow + + testmeths = [ +@@ -134,6 +135,7 @@ + AllTests = type("AllTests", (object,), d) + del d, statictests, method, method_template + ++@support.thread_unsafe("callLst is shared between threads") + class ClassTests(unittest.TestCase): + def setUp(self): + callLst[:] = [] +diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py +index 11054963b6f..b45b9ee89ee 100644 +--- a/Lib/test/test_clinic.py ++++ b/Lib/test/test_clinic.py +@@ -740,6 +740,16 @@ + err = "Cannot use @text_signature when cloning a function" + self.expect_failure(block, err, lineno=11) + ++ def test_ignore_preprocessor_in_comments(self): ++ for dsl in "clinic", "python": ++ raw = dedent(f"""\ ++ /*[{dsl} input] ++ # CPP directives, valid or not, should be ignored in C comments. ++ # ++ [{dsl} start generated code]*/ ++ """) ++ self.clinic.parse(raw) ++ + + class ParseFileUnitTest(TestCase): + def expect_parsing_failure( +diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py +index 634efda3544..b949b310ac0 100644 +--- a/Lib/test/test_cmd_line.py ++++ b/Lib/test/test_cmd_line.py +@@ -336,6 +336,8 @@ + self.assertEqual(stdout, expected) + self.assertEqual(p.returncode, 0) + ++ @unittest.skipIf(os.environ.get("PYTHONUNBUFFERED", "0") != "0", ++ "Python stdio buffering is disabled.") + def test_non_interactive_output_buffering(self): + code = textwrap.dedent(""" + import sys +@@ -489,7 +491,7 @@ + rc, out, err = assert_python_failure('-c', code) + self.assertEqual(b'', out) + self.assertEqual(120, rc) +- self.assertIn(b'Exception ignored on flushing sys.stdout:\n' ++ self.assertIn(b'Exception ignored while flushing sys.stdout:\n' + b'OSError: '.replace(b'\n', os.linesep.encode()), + err) + +@@ -1012,7 +1014,7 @@ + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True) +- err_msg = "unknown option --unknown-option\nusage: " ++ err_msg = "Unknown option: --unknown-option\nusage: " + self.assertTrue(proc.stderr.startswith(err_msg), proc.stderr) + self.assertNotEqual(proc.returncode, 0) + +diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py +index f30107225ff..e7f3e46c186 100644 +--- a/Lib/test/test_cmd_line_script.py ++++ b/Lib/test/test_cmd_line_script.py +@@ -88,6 +88,8 @@ + importlib.invalidate_caches() + return to_return + ++ ++@support.force_not_colorized_test_class + class CmdLineTest(unittest.TestCase): + def _check_output(self, script_name, exit_code, data, + expected_file, expected_argv0, +@@ -659,7 +661,8 @@ + stderr.splitlines()[-3:], + [ b' foo = """\\q"""', + b' ^^^^^^^^', +- b'SyntaxError: invalid escape sequence \'\\q\'' ++ b'SyntaxError: "\\q" is an invalid escape sequence. ' ++ b'Did you mean "\\\\q"? A raw string is also an option.' + ], + ) + +diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py +index 2a1b26e8a1f..69c1ee0690d 100644 +--- a/Lib/test/test_code.py ++++ b/Lib/test/test_code.py +@@ -215,6 +215,8 @@ + from test.support import threading_helper, import_helper + from test.support.bytecode_helper import instructions_with_positions + from opcode import opmap, opname ++from _testcapi import code_offset_to_line ++ + COPY_FREE_VARS = opmap['COPY_FREE_VARS'] + + +@@ -427,14 +429,14 @@ + def foo(): + pass + +- # assert that opcode 229 is invalid +- self.assertEqual(opname[229], '<229>') ++ # assert that opcode 135 is invalid ++ self.assertEqual(opname[135], '<135>') + +- # change first opcode to 0xeb (=229) ++ # change first opcode to 0x87 (=135) + foo.__code__ = foo.__code__.replace( +- co_code=b'\xe5' + foo.__code__.co_code[1:]) ++ co_code=b'\x87' + foo.__code__.co_code[1:]) + +- msg = "unknown opcode 229" ++ msg = "unknown opcode 135" + with self.assertRaisesRegex(SystemError, msg): + foo() + +@@ -896,6 +898,44 @@ + + rc, out, err = assert_python_ok('-OO', '-c', code) + ++ def test_co_branches(self): ++ ++ def get_line_branches(func): ++ code = func.__code__ ++ base = code.co_firstlineno ++ return [ ++ ( ++ code_offset_to_line(code, src) - base, ++ code_offset_to_line(code, left) - base, ++ code_offset_to_line(code, right) - base ++ ) for (src, left, right) in ++ code.co_branches() ++ ] ++ ++ def simple(x): ++ if x: ++ A ++ else: ++ B ++ ++ self.assertEqual( ++ get_line_branches(simple), ++ [(1,2,4)]) ++ ++ def with_extended_args(x): ++ if x: ++ A.x; A.x; A.x; A.x; A.x; A.x; ++ A.x; A.x; A.x; A.x; A.x; A.x; ++ A.x; A.x; A.x; A.x; A.x; A.x; ++ A.x; A.x; A.x; A.x; A.x; A.x; ++ A.x; A.x; A.x; A.x; A.x; A.x; ++ else: ++ B ++ ++ self.assertEqual( ++ get_line_branches(with_extended_args), ++ [(1,2,8)]) ++ + if check_impl_detail(cpython=True) and ctypes is not None: + py = ctypes.pythonapi + freefunc = ctypes.CFUNCTYPE(None,ctypes.c_voidp) +diff --git a/Lib/test/test_code_module.py b/Lib/test/test_code_module.py +index 37c7bc772ed..20b960ce8d1 100644 +--- a/Lib/test/test_code_module.py ++++ b/Lib/test/test_code_module.py +@@ -5,9 +5,9 @@ + from textwrap import dedent + from contextlib import ExitStack + from unittest import mock ++from test.support import force_not_colorized_test_class + from test.support import import_helper + +- + code = import_helper.import_module('code') + + +@@ -30,6 +30,7 @@ + del self.sysmod.ps2 + + ++@force_not_colorized_test_class + class TestInteractiveConsole(unittest.TestCase, MockSys): + maxDiff = None + +diff --git a/Lib/test/test_codeop.py b/Lib/test/test_codeop.py +index 787bd1b6a79..0eefc22d11b 100644 +--- a/Lib/test/test_codeop.py ++++ b/Lib/test/test_codeop.py +@@ -282,7 +282,7 @@ + # Test that the warning is only returned once. + with warnings_helper.check_warnings( + ('"is" with \'str\' literal', SyntaxWarning), +- ("invalid escape sequence", SyntaxWarning), ++ ('"\\\\e" is an invalid escape sequence', SyntaxWarning), + ) as w: + compile_command(r"'\e' is 0") + self.assertEqual(len(w.warnings), 2) +diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py +index a24d3e3ea14..1e93530398b 100644 +--- a/Lib/test/test_collections.py ++++ b/Lib/test/test_collections.py +@@ -742,11 +742,11 @@ + C = type('C', (object,), {'__hash__': None}) + setattr(C, name, stub) + self.assertIsInstance(C(), abc) +- self.assertTrue(issubclass(C, abc)) ++ self.assertIsSubclass(C, abc) + + C = type('C', (object,), {'__hash__': None}) + self.assertNotIsInstance(C(), abc) +- self.assertFalse(issubclass(C, abc)) ++ self.assertNotIsSubclass(C, abc) + + def validate_comparison(self, instance): + ops = ['lt', 'gt', 'le', 'ge', 'ne', 'or', 'and', 'xor', 'sub'] +@@ -812,12 +812,12 @@ + non_samples = [None, int(), gen(), object()] + for x in non_samples: + self.assertNotIsInstance(x, Awaitable) +- self.assertFalse(issubclass(type(x), Awaitable), repr(type(x))) ++ self.assertNotIsSubclass(type(x), Awaitable) + + samples = [Bar(), MinimalCoro()] + for x in samples: + self.assertIsInstance(x, Awaitable) +- self.assertTrue(issubclass(type(x), Awaitable)) ++ self.assertIsSubclass(type(x), Awaitable) + + c = coro() + # Iterable coroutines (generators with CO_ITERABLE_COROUTINE +@@ -831,8 +831,8 @@ + + class CoroLike: pass + Coroutine.register(CoroLike) +- self.assertTrue(isinstance(CoroLike(), Awaitable)) +- self.assertTrue(issubclass(CoroLike, Awaitable)) ++ self.assertIsInstance(CoroLike(), Awaitable) ++ self.assertIsSubclass(CoroLike, Awaitable) + CoroLike = None + support.gc_collect() # Kill CoroLike to clean-up ABCMeta cache + +@@ -864,12 +864,12 @@ + non_samples = [None, int(), gen(), object(), Bar()] + for x in non_samples: + self.assertNotIsInstance(x, Coroutine) +- self.assertFalse(issubclass(type(x), Coroutine), repr(type(x))) ++ self.assertNotIsSubclass(type(x), Coroutine) + + samples = [MinimalCoro()] + for x in samples: + self.assertIsInstance(x, Awaitable) +- self.assertTrue(issubclass(type(x), Awaitable)) ++ self.assertIsSubclass(type(x), Awaitable) + + c = coro() + # Iterable coroutines (generators with CO_ITERABLE_COROUTINE +@@ -890,8 +890,8 @@ + pass + def __await__(self): + pass +- self.assertTrue(isinstance(CoroLike(), Coroutine)) +- self.assertTrue(issubclass(CoroLike, Coroutine)) ++ self.assertIsInstance(CoroLike(), Coroutine) ++ self.assertIsSubclass(CoroLike, Coroutine) + + class CoroLike: + def send(self, value): +@@ -900,15 +900,15 @@ + pass + def __await__(self): + pass +- self.assertFalse(isinstance(CoroLike(), Coroutine)) +- self.assertFalse(issubclass(CoroLike, Coroutine)) ++ self.assertNotIsInstance(CoroLike(), Coroutine) ++ self.assertNotIsSubclass(CoroLike, Coroutine) + + def test_Hashable(self): + # Check some non-hashables + non_samples = [bytearray(), list(), set(), dict()] + for x in non_samples: + self.assertNotIsInstance(x, Hashable) +- self.assertFalse(issubclass(type(x), Hashable), repr(type(x))) ++ self.assertNotIsSubclass(type(x), Hashable) + # Check some hashables + samples = [None, + int(), float(), complex(), +@@ -918,14 +918,14 @@ + ] + for x in samples: + self.assertIsInstance(x, Hashable) +- self.assertTrue(issubclass(type(x), Hashable), repr(type(x))) ++ self.assertIsSubclass(type(x), Hashable) + self.assertRaises(TypeError, Hashable) + # Check direct subclassing + class H(Hashable): + def __hash__(self): + return super().__hash__() + self.assertEqual(hash(H()), 0) +- self.assertFalse(issubclass(int, H)) ++ self.assertNotIsSubclass(int, H) + self.validate_abstract_methods(Hashable, '__hash__') + self.validate_isinstance(Hashable, '__hash__') + +@@ -933,13 +933,13 @@ + class AI: + def __aiter__(self): + return self +- self.assertTrue(isinstance(AI(), AsyncIterable)) +- self.assertTrue(issubclass(AI, AsyncIterable)) ++ self.assertIsInstance(AI(), AsyncIterable) ++ self.assertIsSubclass(AI, AsyncIterable) + # Check some non-iterables + non_samples = [None, object, []] + for x in non_samples: + self.assertNotIsInstance(x, AsyncIterable) +- self.assertFalse(issubclass(type(x), AsyncIterable), repr(type(x))) ++ self.assertNotIsSubclass(type(x), AsyncIterable) + self.validate_abstract_methods(AsyncIterable, '__aiter__') + self.validate_isinstance(AsyncIterable, '__aiter__') + +@@ -949,13 +949,13 @@ + return self + async def __anext__(self): + raise StopAsyncIteration +- self.assertTrue(isinstance(AI(), AsyncIterator)) +- self.assertTrue(issubclass(AI, AsyncIterator)) ++ self.assertIsInstance(AI(), AsyncIterator) ++ self.assertIsSubclass(AI, AsyncIterator) + non_samples = [None, object, []] + # Check some non-iterables + for x in non_samples: + self.assertNotIsInstance(x, AsyncIterator) +- self.assertFalse(issubclass(type(x), AsyncIterator), repr(type(x))) ++ self.assertNotIsSubclass(type(x), AsyncIterator) + # Similarly to regular iterators (see issue 10565) + class AnextOnly: + async def __anext__(self): +@@ -968,7 +968,7 @@ + non_samples = [None, 42, 3.14, 1j] + for x in non_samples: + self.assertNotIsInstance(x, Iterable) +- self.assertFalse(issubclass(type(x), Iterable), repr(type(x))) ++ self.assertNotIsSubclass(type(x), Iterable) + # Check some iterables + samples = [bytes(), str(), + tuple(), list(), set(), frozenset(), dict(), +@@ -978,13 +978,13 @@ + ] + for x in samples: + self.assertIsInstance(x, Iterable) +- self.assertTrue(issubclass(type(x), Iterable), repr(type(x))) ++ self.assertIsSubclass(type(x), Iterable) + # Check direct subclassing + class I(Iterable): + def __iter__(self): + return super().__iter__() + self.assertEqual(list(I()), []) +- self.assertFalse(issubclass(str, I)) ++ self.assertNotIsSubclass(str, I) + self.validate_abstract_methods(Iterable, '__iter__') + self.validate_isinstance(Iterable, '__iter__') + # Check None blocking +@@ -992,22 +992,22 @@ + def __iter__(self): return iter([]) + class ItBlocked(It): + __iter__ = None +- self.assertTrue(issubclass(It, Iterable)) +- self.assertTrue(isinstance(It(), Iterable)) +- self.assertFalse(issubclass(ItBlocked, Iterable)) +- self.assertFalse(isinstance(ItBlocked(), Iterable)) ++ self.assertIsSubclass(It, Iterable) ++ self.assertIsInstance(It(), Iterable) ++ self.assertNotIsSubclass(ItBlocked, Iterable) ++ self.assertNotIsInstance(ItBlocked(), Iterable) + + def test_Reversible(self): + # Check some non-reversibles + non_samples = [None, 42, 3.14, 1j, set(), frozenset()] + for x in non_samples: + self.assertNotIsInstance(x, Reversible) +- self.assertFalse(issubclass(type(x), Reversible), repr(type(x))) ++ self.assertNotIsSubclass(type(x), Reversible) + # Check some non-reversible iterables + non_reversibles = [_test_gen(), (x for x in []), iter([]), reversed([])] + for x in non_reversibles: + self.assertNotIsInstance(x, Reversible) +- self.assertFalse(issubclass(type(x), Reversible), repr(type(x))) ++ self.assertNotIsSubclass(type(x), Reversible) + # Check some reversible iterables + samples = [bytes(), str(), tuple(), list(), OrderedDict(), + OrderedDict().keys(), OrderedDict().items(), +@@ -1016,11 +1016,11 @@ + dict().keys(), dict().items(), dict().values()] + for x in samples: + self.assertIsInstance(x, Reversible) +- self.assertTrue(issubclass(type(x), Reversible), repr(type(x))) ++ self.assertIsSubclass(type(x), Reversible) + # Check also Mapping, MutableMapping, and Sequence +- self.assertTrue(issubclass(Sequence, Reversible), repr(Sequence)) +- self.assertFalse(issubclass(Mapping, Reversible), repr(Mapping)) +- self.assertFalse(issubclass(MutableMapping, Reversible), repr(MutableMapping)) ++ self.assertIsSubclass(Sequence, Reversible) ++ self.assertNotIsSubclass(Mapping, Reversible) ++ self.assertNotIsSubclass(MutableMapping, Reversible) + # Check direct subclassing + class R(Reversible): + def __iter__(self): +@@ -1028,17 +1028,17 @@ + def __reversed__(self): + return iter(list()) + self.assertEqual(list(reversed(R())), []) +- self.assertFalse(issubclass(float, R)) ++ self.assertNotIsSubclass(float, R) + self.validate_abstract_methods(Reversible, '__reversed__', '__iter__') + # Check reversible non-iterable (which is not Reversible) + class RevNoIter: + def __reversed__(self): return reversed([]) + class RevPlusIter(RevNoIter): + def __iter__(self): return iter([]) +- self.assertFalse(issubclass(RevNoIter, Reversible)) +- self.assertFalse(isinstance(RevNoIter(), Reversible)) +- self.assertTrue(issubclass(RevPlusIter, Reversible)) +- self.assertTrue(isinstance(RevPlusIter(), Reversible)) ++ self.assertNotIsSubclass(RevNoIter, Reversible) ++ self.assertNotIsInstance(RevNoIter(), Reversible) ++ self.assertIsSubclass(RevPlusIter, Reversible) ++ self.assertIsInstance(RevPlusIter(), Reversible) + # Check None blocking + class Rev: + def __iter__(self): return iter([]) +@@ -1047,39 +1047,38 @@ + __iter__ = None + class RevRevBlocked(Rev): + __reversed__ = None +- self.assertTrue(issubclass(Rev, Reversible)) +- self.assertTrue(isinstance(Rev(), Reversible)) +- self.assertFalse(issubclass(RevItBlocked, Reversible)) +- self.assertFalse(isinstance(RevItBlocked(), Reversible)) +- self.assertFalse(issubclass(RevRevBlocked, Reversible)) +- self.assertFalse(isinstance(RevRevBlocked(), Reversible)) ++ self.assertIsSubclass(Rev, Reversible) ++ self.assertIsInstance(Rev(), Reversible) ++ self.assertNotIsSubclass(RevItBlocked, Reversible) ++ self.assertNotIsInstance(RevItBlocked(), Reversible) ++ self.assertNotIsSubclass(RevRevBlocked, Reversible) ++ self.assertNotIsInstance(RevRevBlocked(), Reversible) + + def test_Collection(self): + # Check some non-collections + non_collections = [None, 42, 3.14, 1j, lambda x: 2*x] + for x in non_collections: + self.assertNotIsInstance(x, Collection) +- self.assertFalse(issubclass(type(x), Collection), repr(type(x))) ++ self.assertNotIsSubclass(type(x), Collection) + # Check some non-collection iterables + non_col_iterables = [_test_gen(), iter(b''), iter(bytearray()), + (x for x in [])] + for x in non_col_iterables: + self.assertNotIsInstance(x, Collection) +- self.assertFalse(issubclass(type(x), Collection), repr(type(x))) ++ self.assertNotIsSubclass(type(x), Collection) + # Check some collections + samples = [set(), frozenset(), dict(), bytes(), str(), tuple(), + list(), dict().keys(), dict().items(), dict().values()] + for x in samples: + self.assertIsInstance(x, Collection) +- self.assertTrue(issubclass(type(x), Collection), repr(type(x))) ++ self.assertIsSubclass(type(x), Collection) + # Check also Mapping, MutableMapping, etc. +- self.assertTrue(issubclass(Sequence, Collection), repr(Sequence)) +- self.assertTrue(issubclass(Mapping, Collection), repr(Mapping)) +- self.assertTrue(issubclass(MutableMapping, Collection), +- repr(MutableMapping)) +- self.assertTrue(issubclass(Set, Collection), repr(Set)) +- self.assertTrue(issubclass(MutableSet, Collection), repr(MutableSet)) +- self.assertTrue(issubclass(Sequence, Collection), repr(MutableSet)) ++ self.assertIsSubclass(Sequence, Collection) ++ self.assertIsSubclass(Mapping, Collection) ++ self.assertIsSubclass(MutableMapping, Collection) ++ self.assertIsSubclass(Set, Collection) ++ self.assertIsSubclass(MutableSet, Collection) ++ self.assertIsSubclass(Sequence, Collection) + # Check direct subclassing + class Col(Collection): + def __iter__(self): +@@ -1090,13 +1089,13 @@ + return False + class DerCol(Col): pass + self.assertEqual(list(iter(Col())), []) +- self.assertFalse(issubclass(list, Col)) +- self.assertFalse(issubclass(set, Col)) +- self.assertFalse(issubclass(float, Col)) ++ self.assertNotIsSubclass(list, Col) ++ self.assertNotIsSubclass(set, Col) ++ self.assertNotIsSubclass(float, Col) + self.assertEqual(list(iter(DerCol())), []) +- self.assertFalse(issubclass(list, DerCol)) +- self.assertFalse(issubclass(set, DerCol)) +- self.assertFalse(issubclass(float, DerCol)) ++ self.assertNotIsSubclass(list, DerCol) ++ self.assertNotIsSubclass(set, DerCol) ++ self.assertNotIsSubclass(float, DerCol) + self.validate_abstract_methods(Collection, '__len__', '__iter__', + '__contains__') + # Check sized container non-iterable (which is not Collection) etc. +@@ -1109,12 +1108,12 @@ + class ColNoCont: + def __iter__(self): return iter([]) + def __len__(self): return 0 +- self.assertFalse(issubclass(ColNoIter, Collection)) +- self.assertFalse(isinstance(ColNoIter(), Collection)) +- self.assertFalse(issubclass(ColNoSize, Collection)) +- self.assertFalse(isinstance(ColNoSize(), Collection)) +- self.assertFalse(issubclass(ColNoCont, Collection)) +- self.assertFalse(isinstance(ColNoCont(), Collection)) ++ self.assertNotIsSubclass(ColNoIter, Collection) ++ self.assertNotIsInstance(ColNoIter(), Collection) ++ self.assertNotIsSubclass(ColNoSize, Collection) ++ self.assertNotIsInstance(ColNoSize(), Collection) ++ self.assertNotIsSubclass(ColNoCont, Collection) ++ self.assertNotIsInstance(ColNoCont(), Collection) + # Check None blocking + class SizeBlock: + def __iter__(self): return iter([]) +@@ -1124,10 +1123,10 @@ + def __len__(self): return 0 + def __contains__(self): return True + __iter__ = None +- self.assertFalse(issubclass(SizeBlock, Collection)) +- self.assertFalse(isinstance(SizeBlock(), Collection)) +- self.assertFalse(issubclass(IterBlock, Collection)) +- self.assertFalse(isinstance(IterBlock(), Collection)) ++ self.assertNotIsSubclass(SizeBlock, Collection) ++ self.assertNotIsInstance(SizeBlock(), Collection) ++ self.assertNotIsSubclass(IterBlock, Collection) ++ self.assertNotIsInstance(IterBlock(), Collection) + # Check None blocking in subclass + class ColImpl: + def __iter__(self): +@@ -1138,15 +1137,15 @@ + return False + class NonCol(ColImpl): + __contains__ = None +- self.assertFalse(issubclass(NonCol, Collection)) +- self.assertFalse(isinstance(NonCol(), Collection)) ++ self.assertNotIsSubclass(NonCol, Collection) ++ self.assertNotIsInstance(NonCol(), Collection) + + + def test_Iterator(self): + non_samples = [None, 42, 3.14, 1j, b"", "", (), [], {}, set()] + for x in non_samples: + self.assertNotIsInstance(x, Iterator) +- self.assertFalse(issubclass(type(x), Iterator), repr(type(x))) ++ self.assertNotIsSubclass(type(x), Iterator) + samples = [iter(bytes()), iter(str()), + iter(tuple()), iter(list()), iter(dict()), + iter(set()), iter(frozenset()), +@@ -1157,7 +1156,7 @@ + ] + for x in samples: + self.assertIsInstance(x, Iterator) +- self.assertTrue(issubclass(type(x), Iterator), repr(type(x))) ++ self.assertIsSubclass(type(x), Iterator) + self.validate_abstract_methods(Iterator, '__next__', '__iter__') + + # Issue 10565 +@@ -1190,7 +1189,7 @@ + iter(()), iter([]), NonGen1(), NonGen2(), NonGen3()] + for x in non_samples: + self.assertNotIsInstance(x, Generator) +- self.assertFalse(issubclass(type(x), Generator), repr(type(x))) ++ self.assertNotIsSubclass(type(x), Generator) + + class Gen: + def __iter__(self): return self +@@ -1212,7 +1211,7 @@ + for x in samples: + self.assertIsInstance(x, Iterator) + self.assertIsInstance(x, Generator) +- self.assertTrue(issubclass(type(x), Generator), repr(type(x))) ++ self.assertIsSubclass(type(x), Generator) + self.validate_abstract_methods(Generator, 'send', 'throw') + + # mixin tests +@@ -1261,7 +1260,7 @@ + iter(()), iter([]), NonAGen1(), NonAGen2(), NonAGen3()] + for x in non_samples: + self.assertNotIsInstance(x, AsyncGenerator) +- self.assertFalse(issubclass(type(x), AsyncGenerator), repr(type(x))) ++ self.assertNotIsSubclass(type(x), AsyncGenerator) + + class Gen: + def __aiter__(self): return self +@@ -1283,7 +1282,7 @@ + for x in samples: + self.assertIsInstance(x, AsyncIterator) + self.assertIsInstance(x, AsyncGenerator) +- self.assertTrue(issubclass(type(x), AsyncGenerator), repr(type(x))) ++ self.assertIsSubclass(type(x), AsyncGenerator) + self.validate_abstract_methods(AsyncGenerator, 'asend', 'athrow') + + def run_async(coro): +@@ -1326,14 +1325,14 @@ + ] + for x in non_samples: + self.assertNotIsInstance(x, Sized) +- self.assertFalse(issubclass(type(x), Sized), repr(type(x))) ++ self.assertNotIsSubclass(type(x), Sized) + samples = [bytes(), str(), + tuple(), list(), set(), frozenset(), dict(), + dict().keys(), dict().items(), dict().values(), + ] + for x in samples: + self.assertIsInstance(x, Sized) +- self.assertTrue(issubclass(type(x), Sized), repr(type(x))) ++ self.assertIsSubclass(type(x), Sized) + self.validate_abstract_methods(Sized, '__len__') + self.validate_isinstance(Sized, '__len__') + +@@ -1344,14 +1343,14 @@ + ] + for x in non_samples: + self.assertNotIsInstance(x, Container) +- self.assertFalse(issubclass(type(x), Container), repr(type(x))) ++ self.assertNotIsSubclass(type(x), Container) + samples = [bytes(), str(), + tuple(), list(), set(), frozenset(), dict(), + dict().keys(), dict().items(), + ] + for x in samples: + self.assertIsInstance(x, Container) +- self.assertTrue(issubclass(type(x), Container), repr(type(x))) ++ self.assertIsSubclass(type(x), Container) + self.validate_abstract_methods(Container, '__contains__') + self.validate_isinstance(Container, '__contains__') + +@@ -1363,7 +1362,7 @@ + ] + for x in non_samples: + self.assertNotIsInstance(x, Callable) +- self.assertFalse(issubclass(type(x), Callable), repr(type(x))) ++ self.assertNotIsSubclass(type(x), Callable) + samples = [lambda: None, + type, int, object, + len, +@@ -1371,7 +1370,7 @@ + ] + for x in samples: + self.assertIsInstance(x, Callable) +- self.assertTrue(issubclass(type(x), Callable), repr(type(x))) ++ self.assertIsSubclass(type(x), Callable) + self.validate_abstract_methods(Callable, '__call__') + self.validate_isinstance(Callable, '__call__') + +@@ -1379,16 +1378,16 @@ + for B in Hashable, Iterable, Iterator, Reversible, Sized, Container, Callable: + class C(B): + pass +- self.assertTrue(issubclass(C, B)) +- self.assertFalse(issubclass(int, C)) ++ self.assertIsSubclass(C, B) ++ self.assertNotIsSubclass(int, C) + + def test_registration(self): + for B in Hashable, Iterable, Iterator, Reversible, Sized, Container, Callable: + class C: + __hash__ = None # Make sure it isn't hashable by default +- self.assertFalse(issubclass(C, B), B.__name__) ++ self.assertNotIsSubclass(C, B) + B.register(C) +- self.assertTrue(issubclass(C, B)) ++ self.assertIsSubclass(C, B) + + class WithSet(MutableSet): + +@@ -1419,7 +1418,7 @@ + def test_Set(self): + for sample in [set, frozenset]: + self.assertIsInstance(sample(), Set) +- self.assertTrue(issubclass(sample, Set)) ++ self.assertIsSubclass(sample, Set) + self.validate_abstract_methods(Set, '__contains__', '__iter__', '__len__') + class MySet(Set): + def __contains__(self, x): +@@ -1500,9 +1499,9 @@ + + def test_MutableSet(self): + self.assertIsInstance(set(), MutableSet) +- self.assertTrue(issubclass(set, MutableSet)) ++ self.assertIsSubclass(set, MutableSet) + self.assertNotIsInstance(frozenset(), MutableSet) +- self.assertFalse(issubclass(frozenset, MutableSet)) ++ self.assertNotIsSubclass(frozenset, MutableSet) + self.validate_abstract_methods(MutableSet, '__contains__', '__iter__', '__len__', + 'add', 'discard') + +@@ -1841,7 +1840,7 @@ + def test_Mapping(self): + for sample in [dict]: + self.assertIsInstance(sample(), Mapping) +- self.assertTrue(issubclass(sample, Mapping)) ++ self.assertIsSubclass(sample, Mapping) + self.validate_abstract_methods(Mapping, '__contains__', '__iter__', '__len__', + '__getitem__') + class MyMapping(Mapping): +@@ -1857,7 +1856,7 @@ + def test_MutableMapping(self): + for sample in [dict]: + self.assertIsInstance(sample(), MutableMapping) +- self.assertTrue(issubclass(sample, MutableMapping)) ++ self.assertIsSubclass(sample, MutableMapping) + self.validate_abstract_methods(MutableMapping, '__contains__', '__iter__', '__len__', + '__getitem__', '__setitem__', '__delitem__') + +@@ -1891,12 +1890,12 @@ + def test_Sequence(self): + for sample in [tuple, list, bytes, str]: + self.assertIsInstance(sample(), Sequence) +- self.assertTrue(issubclass(sample, Sequence)) ++ self.assertIsSubclass(sample, Sequence) + self.assertIsInstance(range(10), Sequence) +- self.assertTrue(issubclass(range, Sequence)) ++ self.assertIsSubclass(range, Sequence) + self.assertIsInstance(memoryview(b""), Sequence) +- self.assertTrue(issubclass(memoryview, Sequence)) +- self.assertTrue(issubclass(str, Sequence)) ++ self.assertIsSubclass(memoryview, Sequence) ++ self.assertIsSubclass(str, Sequence) + self.validate_abstract_methods(Sequence, '__contains__', '__iter__', '__len__', + '__getitem__') + +@@ -1938,21 +1937,21 @@ + def test_Buffer(self): + for sample in [bytes, bytearray, memoryview]: + self.assertIsInstance(sample(b"x"), Buffer) +- self.assertTrue(issubclass(sample, Buffer)) ++ self.assertIsSubclass(sample, Buffer) + for sample in [str, list, tuple]: + self.assertNotIsInstance(sample(), Buffer) +- self.assertFalse(issubclass(sample, Buffer)) ++ self.assertNotIsSubclass(sample, Buffer) + self.validate_abstract_methods(Buffer, '__buffer__') + + def test_MutableSequence(self): + for sample in [tuple, str, bytes]: + self.assertNotIsInstance(sample(), MutableSequence) +- self.assertFalse(issubclass(sample, MutableSequence)) ++ self.assertNotIsSubclass(sample, MutableSequence) + for sample in [list, bytearray, deque]: + self.assertIsInstance(sample(), MutableSequence) +- self.assertTrue(issubclass(sample, MutableSequence)) +- self.assertTrue(issubclass(array.array, MutableSequence)) +- self.assertFalse(issubclass(str, MutableSequence)) ++ self.assertIsSubclass(sample, MutableSequence) ++ self.assertIsSubclass(array.array, MutableSequence) ++ self.assertNotIsSubclass(str, MutableSequence) + self.validate_abstract_methods(MutableSequence, '__contains__', '__iter__', + '__len__', '__getitem__', '__setitem__', '__delitem__', 'insert') + +@@ -2043,8 +2042,8 @@ + self.assertEqual(c, Counter(a=3, b=2, c=1)) + self.assertIsInstance(c, dict) + self.assertIsInstance(c, Mapping) +- self.assertTrue(issubclass(Counter, dict)) +- self.assertTrue(issubclass(Counter, Mapping)) ++ self.assertIsSubclass(Counter, dict) ++ self.assertIsSubclass(Counter, Mapping) + self.assertEqual(len(c), 3) + self.assertEqual(sum(c.values()), 6) + self.assertEqual(list(c.values()), [3, 2, 1]) +diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py +index b5cf2ad18fe..6c3de2091c4 100644 +--- a/Lib/test/test_compile.py ++++ b/Lib/test/test_compile.py +@@ -1410,7 +1410,7 @@ + check_op_count(load, "BINARY_SLICE", 3) + check_op_count(load, "BUILD_SLICE", 0) + check_consts(load, slice, [slice(None, None, None)]) +- check_op_count(load, "BINARY_SUBSCR", 1) ++ check_op_count(load, "BINARY_OP", 4) + + def store(): + x[a:b] = y +@@ -1429,7 +1429,7 @@ + check_op_count(long_slice, "BUILD_SLICE", 1) + check_op_count(long_slice, "BINARY_SLICE", 0) + check_consts(long_slice, slice, []) +- check_op_count(long_slice, "BINARY_SUBSCR", 1) ++ check_op_count(long_slice, "BINARY_OP", 1) + + def aug(): + x[a:b] += y +@@ -1437,7 +1437,7 @@ + check_op_count(aug, "BINARY_SLICE", 1) + check_op_count(aug, "STORE_SLICE", 1) + check_op_count(aug, "BUILD_SLICE", 0) +- check_op_count(aug, "BINARY_SUBSCR", 0) ++ check_op_count(aug, "BINARY_OP", 1) + check_op_count(aug, "STORE_SUBSCR", 0) + check_consts(aug, slice, []) + +@@ -1446,7 +1446,7 @@ + + check_op_count(aug_const, "BINARY_SLICE", 0) + check_op_count(aug_const, "STORE_SLICE", 0) +- check_op_count(aug_const, "BINARY_SUBSCR", 1) ++ check_op_count(aug_const, "BINARY_OP", 2) + check_op_count(aug_const, "STORE_SUBSCR", 1) + check_consts(aug_const, slice, [slice(1, 2)]) + +@@ -2050,16 +2050,16 @@ + snippet = "a - b @ (c * x['key'] + 23)" + + compiled_code, _ = self.check_positions_against_ast(snippet) +- self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_SUBSCR', ++ self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP', + line=1, end_line=1, column=13, end_column=21) + self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP', +- line=1, end_line=1, column=9, end_column=21, occurrence=1) ++ line=1, end_line=1, column=9, end_column=21, occurrence=2) + self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP', +- line=1, end_line=1, column=9, end_column=26, occurrence=2) ++ line=1, end_line=1, column=9, end_column=26, occurrence=3) + self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP', +- line=1, end_line=1, column=4, end_column=27, occurrence=3) ++ line=1, end_line=1, column=4, end_column=27, occurrence=4) + self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP', +- line=1, end_line=1, column=0, end_column=27, occurrence=4) ++ line=1, end_line=1, column=0, end_column=27, occurrence=5) + + def test_multiline_assert_rewritten_as_method_call(self): + # GH-94694: Don't crash if pytest rewrites a multiline assert as a +diff --git a/Lib/test/test_compileall.py b/Lib/test/test_compileall.py +index 3a34c6822bc..a580a240d9f 100644 +--- a/Lib/test/test_compileall.py ++++ b/Lib/test/test_compileall.py +@@ -766,6 +766,7 @@ + rc, out, err = self.assertRunNotOK('-q', '-d', 'dinsdale', self.pkgdir) + self.assertRegex(out, b'File "dinsdale') + ++ @support.force_not_colorized + def test_d_runtime_error(self): + bazfn = script_helper.make_script(self.pkgdir, 'baz', 'raise Exception') + self.assertRunOK('-q', '-d', 'dinsdale', self.pkgdir) +diff --git a/Lib/test/test_compiler_codegen.py b/Lib/test/test_compiler_codegen.py +index 2dd7cf65ee3..cf5e2d901db 100644 +--- a/Lib/test/test_compiler_codegen.py ++++ b/Lib/test/test_compiler_codegen.py +@@ -59,7 +59,7 @@ + ('JUMP', loop_lbl), + exit_lbl, + ('END_FOR', None), +- ('POP_TOP', None), ++ ('POP_ITER', None), + ('LOAD_CONST', 0), + ('RETURN_VALUE', None), + ] +diff --git a/Lib/test/test_concurrent_futures/test_interpreter_pool.py b/Lib/test/test_concurrent_futures/test_interpreter_pool.py +index ea1512fc830..93eec08bfe1 100644 +--- a/Lib/test/test_concurrent_futures/test_interpreter_pool.py ++++ b/Lib/test/test_concurrent_futures/test_interpreter_pool.py +@@ -311,7 +311,7 @@ + # tests left a policy in place, just in case. + policy = support.maybe_get_event_loop_policy() + assert policy is None, policy +- cls.addClassCleanup(lambda: asyncio.set_event_loop_policy(None)) ++ cls.addClassCleanup(lambda: asyncio._set_event_loop_policy(None)) + + def setUp(self): + super().setUp() +diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py +index e3c5d08dd1e..bde805eb741 100644 +--- a/Lib/test/test_configparser.py ++++ b/Lib/test/test_configparser.py +@@ -2174,6 +2174,15 @@ + with self.assertRaises(configparser.UnnamedSectionDisabledError): + configparser.ConfigParser().add_section(configparser.UNNAMED_SECTION) + ++ def test_multiple_configs(self): ++ cfg = configparser.ConfigParser(allow_unnamed_section=True) ++ cfg.read_string('a = 1') ++ cfg.read_string('b = 2') ++ ++ self.assertEqual([configparser.UNNAMED_SECTION], cfg.sections()) ++ self.assertEqual('1', cfg[configparser.UNNAMED_SECTION]['a']) ++ self.assertEqual('2', cfg[configparser.UNNAMED_SECTION]['b']) ++ + + class MiscTestCase(unittest.TestCase): + def test__all__(self): +diff --git a/Lib/test/test_contextlib_async.py b/Lib/test/test_contextlib_async.py +index ca7315783b9..7750186e56a 100644 +--- a/Lib/test/test_contextlib_async.py ++++ b/Lib/test/test_contextlib_async.py +@@ -1,21 +1,27 @@ +-import asyncio ++import functools + from contextlib import ( + asynccontextmanager, AbstractAsyncContextManager, + AsyncExitStack, nullcontext, aclosing, contextmanager) + from test import support ++from test.support import run_no_yield_async_fn as _run_async_fn + import unittest + import traceback + + from test.test_contextlib import TestBaseExitStack + +-support.requires_working_socket(module=True) + +-def tearDownModule(): +- asyncio.set_event_loop_policy(None) ++def _async_test(async_fn): ++ """Decorator to turn an async function into a synchronous function""" ++ @functools.wraps(async_fn) ++ def wrapper(*args, **kwargs): ++ return _run_async_fn(async_fn, *args, **kwargs) + ++ return wrapper + +-class TestAbstractAsyncContextManager(unittest.IsolatedAsyncioTestCase): + ++class TestAbstractAsyncContextManager(unittest.TestCase): ++ ++ @_async_test + async def test_enter(self): + class DefaultEnter(AbstractAsyncContextManager): + async def __aexit__(self, *args): +@@ -27,6 +33,7 @@ + async with manager as context: + self.assertIs(manager, context) + ++ @_async_test + async def test_slots(self): + class DefaultAsyncContextManager(AbstractAsyncContextManager): + __slots__ = () +@@ -38,6 +45,7 @@ + manager = DefaultAsyncContextManager() + manager.var = 42 + ++ @_async_test + async def test_async_gen_propagates_generator_exit(self): + # A regression test for https://bugs.python.org/issue33786. + +@@ -88,8 +96,9 @@ + self.assertFalse(issubclass(NoneAexit, AbstractAsyncContextManager)) + + +-class AsyncContextManagerTestCase(unittest.IsolatedAsyncioTestCase): ++class AsyncContextManagerTestCase(unittest.TestCase): + ++ @_async_test + async def test_contextmanager_plain(self): + state = [] + @asynccontextmanager +@@ -103,6 +112,7 @@ + state.append(x) + self.assertEqual(state, [1, 42, 999]) + ++ @_async_test + async def test_contextmanager_finally(self): + state = [] + @asynccontextmanager +@@ -120,6 +130,7 @@ + raise ZeroDivisionError() + self.assertEqual(state, [1, 42, 999]) + ++ @_async_test + async def test_contextmanager_traceback(self): + @asynccontextmanager + async def f(): +@@ -175,6 +186,7 @@ + self.assertEqual(frames[0].name, 'test_contextmanager_traceback') + self.assertEqual(frames[0].line, 'raise stop_exc') + ++ @_async_test + async def test_contextmanager_no_reraise(self): + @asynccontextmanager + async def whee(): +@@ -184,6 +196,7 @@ + # Calling __aexit__ should not result in an exception + self.assertFalse(await ctx.__aexit__(TypeError, TypeError("foo"), None)) + ++ @_async_test + async def test_contextmanager_trap_yield_after_throw(self): + @asynccontextmanager + async def whoo(): +@@ -199,6 +212,7 @@ + # The "gen" attribute is an implementation detail. + self.assertFalse(ctx.gen.ag_suspended) + ++ @_async_test + async def test_contextmanager_trap_no_yield(self): + @asynccontextmanager + async def whoo(): +@@ -208,6 +222,7 @@ + with self.assertRaises(RuntimeError): + await ctx.__aenter__() + ++ @_async_test + async def test_contextmanager_trap_second_yield(self): + @asynccontextmanager + async def whoo(): +@@ -221,6 +236,7 @@ + # The "gen" attribute is an implementation detail. + self.assertFalse(ctx.gen.ag_suspended) + ++ @_async_test + async def test_contextmanager_non_normalised(self): + @asynccontextmanager + async def whoo(): +@@ -234,6 +250,7 @@ + with self.assertRaises(SyntaxError): + await ctx.__aexit__(RuntimeError, None, None) + ++ @_async_test + async def test_contextmanager_except(self): + state = [] + @asynccontextmanager +@@ -251,6 +268,7 @@ + raise ZeroDivisionError(999) + self.assertEqual(state, [1, 42, 999]) + ++ @_async_test + async def test_contextmanager_except_stopiter(self): + @asynccontextmanager + async def woohoo(): +@@ -277,6 +295,7 @@ + else: + self.fail(f'{stop_exc} was suppressed') + ++ @_async_test + async def test_contextmanager_wrap_runtimeerror(self): + @asynccontextmanager + async def woohoo(): +@@ -321,12 +340,14 @@ + self.assertEqual(baz.__doc__, "Whee!") + + @support.requires_docstrings ++ @_async_test + async def test_instance_docstring_given_cm_docstring(self): + baz = self._create_contextmanager_attribs()(None) + self.assertEqual(baz.__doc__, "Whee!") + async with baz: + pass # suppress warning + ++ @_async_test + async def test_keywords(self): + # Ensure no keyword arguments are inhibited + @asynccontextmanager +@@ -335,6 +356,7 @@ + async with woohoo(self=11, func=22, args=33, kwds=44) as target: + self.assertEqual(target, (11, 22, 33, 44)) + ++ @_async_test + async def test_recursive(self): + depth = 0 + ncols = 0 +@@ -361,6 +383,7 @@ + self.assertEqual(ncols, 10) + self.assertEqual(depth, 0) + ++ @_async_test + async def test_decorator(self): + entered = False + +@@ -379,6 +402,7 @@ + await test() + self.assertFalse(entered) + ++ @_async_test + async def test_decorator_with_exception(self): + entered = False + +@@ -401,6 +425,7 @@ + await test() + self.assertFalse(entered) + ++ @_async_test + async def test_decorating_method(self): + + @asynccontextmanager +@@ -435,7 +460,7 @@ + self.assertEqual(test.b, 2) + + +-class AclosingTestCase(unittest.IsolatedAsyncioTestCase): ++class AclosingTestCase(unittest.TestCase): + + @support.requires_docstrings + def test_instance_docs(self): +@@ -443,6 +468,7 @@ + obj = aclosing(None) + self.assertEqual(obj.__doc__, cm_docstring) + ++ @_async_test + async def test_aclosing(self): + state = [] + class C: +@@ -454,6 +480,7 @@ + self.assertEqual(x, y) + self.assertEqual(state, [1]) + ++ @_async_test + async def test_aclosing_error(self): + state = [] + class C: +@@ -467,6 +494,7 @@ + 1 / 0 + self.assertEqual(state, [1]) + ++ @_async_test + async def test_aclosing_bpo41229(self): + state = [] + +@@ -492,45 +520,27 @@ + self.assertEqual(state, [1]) + + +-class TestAsyncExitStack(TestBaseExitStack, unittest.IsolatedAsyncioTestCase): ++class TestAsyncExitStack(TestBaseExitStack, unittest.TestCase): + class SyncAsyncExitStack(AsyncExitStack): +- @staticmethod +- def run_coroutine(coro): +- loop = asyncio.get_event_loop_policy().get_event_loop() +- t = loop.create_task(coro) +- t.add_done_callback(lambda f: loop.stop()) +- loop.run_forever() +- +- exc = t.exception() +- if not exc: +- return t.result() +- else: +- context = exc.__context__ +- +- try: +- raise exc +- except: +- exc.__context__ = context +- raise exc + + def close(self): +- return self.run_coroutine(self.aclose()) ++ return _run_async_fn(self.aclose) + + def __enter__(self): +- return self.run_coroutine(self.__aenter__()) ++ return _run_async_fn(self.__aenter__) + + def __exit__(self, *exc_details): +- return self.run_coroutine(self.__aexit__(*exc_details)) ++ return _run_async_fn(self.__aexit__, *exc_details) + + exit_stack = SyncAsyncExitStack + callback_error_internal_frames = [ +- ('__exit__', 'return self.run_coroutine(self.__aexit__(*exc_details))'), +- ('run_coroutine', 'raise exc'), +- ('run_coroutine', 'raise exc'), ++ ('__exit__', 'return _run_async_fn(self.__aexit__, *exc_details)'), ++ ('run_no_yield_async_fn', 'coro.send(None)'), + ('__aexit__', 'raise exc'), + ('__aexit__', 'cb_suppress = cb(*exc_details)'), + ] + ++ @_async_test + async def test_async_callback(self): + expected = [ + ((), {}), +@@ -573,6 +583,7 @@ + stack.push_async_callback(callback=_exit, arg=3) + self.assertEqual(result, []) + ++ @_async_test + async def test_async_push(self): + exc_raised = ZeroDivisionError + async def _expect_exc(exc_type, exc, exc_tb): +@@ -608,6 +619,7 @@ + self.assertIs(stack._exit_callbacks[-1][1], _expect_exc) + 1/0 + ++ @_async_test + async def test_enter_async_context(self): + class TestCM(object): + async def __aenter__(self): +@@ -629,6 +641,7 @@ + + self.assertEqual(result, [1, 2, 3, 4]) + ++ @_async_test + async def test_enter_async_context_errors(self): + class LacksEnterAndExit: + pass +@@ -648,6 +661,7 @@ + await stack.enter_async_context(LacksExit()) + self.assertFalse(stack._exit_callbacks) + ++ @_async_test + async def test_async_exit_exception_chaining(self): + # Ensure exception chaining matches the reference behaviour + async def raise_exc(exc): +@@ -679,6 +693,7 @@ + self.assertIsInstance(inner_exc, ValueError) + self.assertIsInstance(inner_exc.__context__, ZeroDivisionError) + ++ @_async_test + async def test_async_exit_exception_explicit_none_context(self): + # Ensure AsyncExitStack chaining matches actual nested `with` statements + # regarding explicit __context__ = None. +@@ -713,6 +728,7 @@ + else: + self.fail("Expected IndexError, but no exception was raised") + ++ @_async_test + async def test_instance_bypass_async(self): + class Example(object): pass + cm = Example() +@@ -725,7 +741,8 @@ + self.assertIs(stack._exit_callbacks[-1][1], cm) + + +-class TestAsyncNullcontext(unittest.IsolatedAsyncioTestCase): ++class TestAsyncNullcontext(unittest.TestCase): ++ @_async_test + async def test_async_nullcontext(self): + class C: + pass +diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py +index e6d65e7d90a..ae3cd355500 100644 +--- a/Lib/test/test_coroutines.py ++++ b/Lib/test/test_coroutines.py +@@ -735,7 +735,7 @@ + + def test_func_12(self): + async def g(): +- i = me.send(None) ++ me.send(None) + await foo + me = g() + with self.assertRaisesRegex(ValueError, +@@ -2136,8 +2136,10 @@ + coro = None + support.gc_collect() + ++ self.assertEqual(cm.unraisable.err_msg, ++ f"Exception ignored while finalizing " ++ f"coroutine {coro_repr}") + self.assertIn("was never awaited", str(cm.unraisable.exc_value)) +- self.assertEqual(repr(cm.unraisable.object), coro_repr) + + def test_for_assign_raising_stop_async_iteration(self): + class BadTarget: +@@ -2281,20 +2283,20 @@ + buffer.append(exc_type.__name__) + + async def f(): +- async with CM() as c: ++ async with CM(): + await asyncio.sleep(0.01) + raise MyException + buffer.append('unreachable') + + loop = asyncio.new_event_loop() +- asyncio.set_event_loop(loop) ++ asyncio._set_event_loop(loop) + try: + loop.run_until_complete(f()) + except MyException: + pass + finally: + loop.close() +- asyncio.set_event_loop_policy(None) ++ asyncio._set_event_loop_policy(None) + + self.assertEqual(buffer, [1, 2, 'MyException']) + +@@ -2373,7 +2375,7 @@ + + orig_depth = sys.get_coroutine_origin_tracking_depth() + try: +- msg = check(0, f"coroutine '{corofn.__qualname__}' was never awaited") ++ check(0, f"coroutine '{corofn.__qualname__}' was never awaited") + check(1, "".join([ + f"coroutine '{corofn.__qualname__}' was never awaited\n", + "Coroutine created at (most recent call last)\n", +@@ -2414,7 +2416,9 @@ + del coro + support.gc_collect() + +- self.assertEqual(repr(cm.unraisable.object), coro_repr) ++ self.assertEqual(cm.unraisable.err_msg, ++ f"Exception ignored while finalizing " ++ f"coroutine {coro_repr}") + self.assertEqual(cm.unraisable.exc_type, ZeroDivisionError) + + del warnings._warn_unawaited_coroutine +diff --git a/Lib/test/test_ctypes/test_arrays.py b/Lib/test/test_ctypes/test_arrays.py +index c80fdff5de6..7f1f6cf5840 100644 +--- a/Lib/test/test_ctypes/test_arrays.py ++++ b/Lib/test/test_ctypes/test_arrays.py +@@ -5,7 +5,7 @@ + create_string_buffer, create_unicode_buffer, + c_char, c_wchar, c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint, + c_long, c_ulonglong, c_float, c_double, c_longdouble) +-from test.support import bigmemtest, _2G ++from test.support import bigmemtest, _2G, threading_helper, Py_GIL_DISABLED + from ._support import (_CData, PyCArrayType, Py_TPFLAGS_DISALLOW_INSTANTIATION, + Py_TPFLAGS_IMMUTABLETYPE) + +@@ -267,6 +267,26 @@ + def test_large_array(self, size): + c_char * size + ++ @threading_helper.requires_working_threading() ++ @unittest.skipUnless(Py_GIL_DISABLED, "only meaningful if the GIL is disabled") ++ def test_thread_safety(self): ++ from threading import Thread ++ ++ buffer = (ctypes.c_char_p * 10)() ++ ++ def run(): ++ for i in range(100): ++ buffer.value = b"hello" ++ buffer[0] = b"j" ++ ++ with threading_helper.catch_threading_exception() as cm: ++ threads = (Thread(target=run) for _ in range(25)) ++ with threading_helper.start_threads(threads): ++ pass ++ ++ if cm.exc_value: ++ raise cm.exc_value ++ + + if __name__ == '__main__': + unittest.main() +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 eb77d6d7782..b446fd5c77d 100644 +--- a/Lib/test/test_ctypes/test_c_simple_type_meta.py ++++ b/Lib/test/test_ctypes/test_c_simple_type_meta.py +@@ -1,4 +1,5 @@ + import unittest ++from test.support import MS_WINDOWS + import ctypes + from ctypes import POINTER, c_void_p + +@@ -54,9 +55,9 @@ + pass + + self.assertIsInstance(POINTER(Sub2), p_meta) +- self.assertTrue(issubclass(POINTER(Sub2), Sub2)) +- self.assertTrue(issubclass(POINTER(Sub2), POINTER(Sub))) +- self.assertTrue(issubclass(POINTER(Sub), POINTER(CtBase))) ++ self.assertIsSubclass(POINTER(Sub2), Sub2) ++ self.assertIsSubclass(POINTER(Sub2), POINTER(Sub)) ++ self.assertIsSubclass(POINTER(Sub), POINTER(CtBase)) + + def test_creating_pointer_in_dunder_new_2(self): + # A simpler variant of the above, used in `CoClass` of the `comtypes` +@@ -84,7 +85,7 @@ + pass + + self.assertIsInstance(POINTER(Sub), p_meta) +- self.assertTrue(issubclass(POINTER(Sub), Sub)) ++ self.assertIsSubclass(POINTER(Sub), Sub) + + def test_creating_pointer_in_dunder_init_1(self): + class ct_meta(type): +@@ -120,9 +121,9 @@ + pass + + self.assertIsInstance(POINTER(Sub2), p_meta) +- self.assertTrue(issubclass(POINTER(Sub2), Sub2)) +- self.assertTrue(issubclass(POINTER(Sub2), POINTER(Sub))) +- self.assertTrue(issubclass(POINTER(Sub), POINTER(CtBase))) ++ self.assertIsSubclass(POINTER(Sub2), Sub2) ++ self.assertIsSubclass(POINTER(Sub2), POINTER(Sub)) ++ self.assertIsSubclass(POINTER(Sub), POINTER(CtBase)) + + def test_creating_pointer_in_dunder_init_2(self): + class ct_meta(type): +@@ -149,4 +150,21 @@ + pass + + self.assertIsInstance(POINTER(Sub), p_meta) +- self.assertTrue(issubclass(POINTER(Sub), Sub)) ++ self.assertIsSubclass(POINTER(Sub), Sub) ++ ++ def test_bad_type_message(self): ++ """Verify the error message that lists all available type codes""" ++ # (The string is generated at runtime, so this checks the underlying ++ # set of types as well as correct construction of the string.) ++ with self.assertRaises(AttributeError) as cm: ++ class F(metaclass=PyCSimpleType): ++ _type_ = "\0" ++ message = str(cm.exception) ++ expected_type_chars = list('cbBhHiIlLdCEFfuzZqQPXOv?g') ++ if not hasattr(ctypes, 'c_float_complex'): ++ expected_type_chars.remove('C') ++ expected_type_chars.remove('E') ++ expected_type_chars.remove('F') ++ if not MS_WINDOWS: ++ expected_type_chars.remove('X') ++ self.assertIn("'" + ''.join(expected_type_chars) + "'", message) +diff --git a/Lib/test/test_ctypes/test_callbacks.py b/Lib/test/test_ctypes/test_callbacks.py +index 8f483dfe1db..6c7c2e52707 100644 +--- a/Lib/test/test_ctypes/test_callbacks.py ++++ b/Lib/test/test_ctypes/test_callbacks.py +@@ -324,7 +324,7 @@ + + self.assertIsInstance(cm.unraisable.exc_value, TypeError) + self.assertEqual(cm.unraisable.err_msg, +- f"Exception ignored on converting result " ++ f"Exception ignored while converting result " + f"of ctypes callback function {func!r}") + self.assertIsNone(cm.unraisable.object) + +diff --git a/Lib/test/test_ctypes/test_cfuncs.py b/Lib/test/test_ctypes/test_cfuncs.py +index 48330c4b0a7..e0c124607cb 100644 +--- a/Lib/test/test_ctypes/test_cfuncs.py ++++ b/Lib/test/test_ctypes/test_cfuncs.py +@@ -5,7 +5,8 @@ + c_short, c_ushort, c_int, c_uint, + c_long, c_ulong, c_longlong, c_ulonglong, + c_float, c_double, c_longdouble) +-from test.support import import_helper ++from test import support ++from test.support import import_helper, threading_helper + _ctypes_test = import_helper.import_module("_ctypes_test") + + +@@ -191,6 +192,23 @@ + self.assertEqual(self._dll.tv_i(-42), None) + self.assertEqual(self.S(), -42) + ++ @threading_helper.requires_working_threading() ++ @support.requires_resource("cpu") ++ @unittest.skipUnless(support.Py_GIL_DISABLED, "only meaningful on free-threading") ++ def test_thread_safety(self): ++ from threading import Thread ++ ++ def concurrent(): ++ for _ in range(100): ++ self._dll.tf_b.restype = c_byte ++ self._dll.tf_b.argtypes = (c_byte,) ++ ++ with threading_helper.catch_threading_exception() as exc: ++ with threading_helper.start_threads((Thread(target=concurrent) for _ in range(10))): ++ pass ++ ++ self.assertIsNone(exc.exc_value) ++ + + # The following repeats the above tests with stdcall functions (where + # they are available) +diff --git a/Lib/test/test_ctypes/test_dlerror.py b/Lib/test/test_ctypes/test_dlerror.py +index 4441e30cd7a..1c1b2aab3d5 100644 +--- a/Lib/test/test_ctypes/test_dlerror.py ++++ b/Lib/test/test_ctypes/test_dlerror.py +@@ -1,7 +1,12 @@ ++import _ctypes + import os ++import platform + import sys ++import test.support + import unittest +-import platform ++from ctypes import CDLL, c_int ++from ctypes.util import find_library ++ + + FOO_C = r""" + #include +@@ -26,7 +31,7 @@ + + + @unittest.skipUnless(sys.platform.startswith('linux'), +- 'Test only valid for Linux') ++ 'test requires GNU IFUNC support') + class TestNullDlsym(unittest.TestCase): + """GH-126554: Ensure that we catch NULL dlsym return values + +@@ -53,19 +58,14 @@ + import subprocess + import tempfile + +- # To avoid ImportErrors on Windows, where _ctypes does not have +- # dlopen and dlsym, +- # import here, i.e., inside the test function. +- # The skipUnless('linux') decorator ensures that we're on linux +- # if we're executing these statements. +- from ctypes import CDLL, c_int +- from _ctypes import dlopen, dlsym +- +- retcode = subprocess.call(["gcc", "--version"], +- stdout=subprocess.DEVNULL, +- stderr=subprocess.DEVNULL) +- if retcode != 0: ++ try: ++ retcode = subprocess.call(["gcc", "--version"], ++ stdout=subprocess.DEVNULL, ++ stderr=subprocess.DEVNULL) ++ except OSError: + self.skipTest("gcc is missing") ++ if retcode != 0: ++ self.skipTest("gcc --version failed") + + pipe_r, pipe_w = os.pipe() + self.addCleanup(os.close, pipe_r) +@@ -111,6 +111,8 @@ + self.assertEqual(os.read(pipe_r, 2), b'OK') + + # Case #3: Test 'py_dl_sym' from Modules/_ctypes/callproc.c ++ dlopen = test.support.get_attribute(_ctypes, 'dlopen') ++ dlsym = test.support.get_attribute(_ctypes, 'dlsym') + L = dlopen(dstname) + with self.assertRaisesRegex(OSError, "symbol 'foo' not found"): + dlsym(L, "foo") +@@ -119,5 +121,59 @@ + self.assertEqual(os.read(pipe_r, 2), b'OK') + + ++@unittest.skipUnless(os.name != 'nt', 'test requires dlerror() calls') ++class TestLocalization(unittest.TestCase): ++ ++ @staticmethod ++ def configure_locales(func): ++ return test.support.run_with_locale( ++ 'LC_ALL', ++ 'fr_FR.iso88591', 'ja_JP.sjis', 'zh_CN.gbk', ++ 'fr_FR.utf8', 'en_US.utf8', ++ '', ++ )(func) ++ ++ @classmethod ++ def setUpClass(cls): ++ cls.libc_filename = find_library("c") ++ if cls.libc_filename is None: ++ raise unittest.SkipTest('cannot find libc') ++ ++ @configure_locales ++ def test_localized_error_from_dll(self): ++ dll = CDLL(self.libc_filename) ++ with self.assertRaises(AttributeError): ++ dll.this_name_does_not_exist ++ ++ @configure_locales ++ def test_localized_error_in_dll(self): ++ dll = CDLL(self.libc_filename) ++ with self.assertRaises(ValueError): ++ c_int.in_dll(dll, 'this_name_does_not_exist') ++ ++ @unittest.skipUnless(hasattr(_ctypes, 'dlopen'), ++ 'test requires _ctypes.dlopen()') ++ @configure_locales ++ def test_localized_error_dlopen(self): ++ missing_filename = b'missing\xff.so' ++ # Depending whether the locale, we may encode '\xff' differently ++ # but we are only interested in avoiding a UnicodeDecodeError ++ # when reporting the dlerror() error message which contains ++ # the localized filename. ++ filename_pattern = r'missing.*?\.so' ++ with self.assertRaisesRegex(OSError, filename_pattern): ++ _ctypes.dlopen(missing_filename, 2) ++ ++ @unittest.skipUnless(hasattr(_ctypes, 'dlopen'), ++ 'test requires _ctypes.dlopen()') ++ @unittest.skipUnless(hasattr(_ctypes, 'dlsym'), ++ 'test requires _ctypes.dlsym()') ++ @configure_locales ++ def test_localized_error_dlsym(self): ++ dll = _ctypes.dlopen(self.libc_filename) ++ with self.assertRaises(OSError): ++ _ctypes.dlsym(dll, 'this_name_does_not_exist') ++ ++ + if __name__ == "__main__": + unittest.main() +--- /dev/null ++++ b/Lib/test/test_ctypes/test_dllist.py +@@ -0,0 +1,59 @@ ++import os ++import sys ++import unittest ++from ctypes import CDLL ++import ctypes.util ++from test.support import import_helper ++ ++ ++WINDOWS = os.name == "nt" ++APPLE = sys.platform in {"darwin", "ios", "tvos", "watchos"} ++ ++if WINDOWS: ++ KNOWN_LIBRARIES = ["KERNEL32.DLL"] ++elif APPLE: ++ KNOWN_LIBRARIES = ["libSystem.B.dylib"] ++else: ++ # trickier than it seems, because libc may not be present ++ # on musl systems, and sometimes goes by different names. ++ # However, ctypes itself loads libffi ++ KNOWN_LIBRARIES = ["libc.so", "libffi.so"] ++ ++ ++@unittest.skipUnless( ++ hasattr(ctypes.util, "dllist"), ++ "ctypes.util.dllist is not available on this platform", ++) ++class ListSharedLibraries(unittest.TestCase): ++ ++ def test_lists_system(self): ++ dlls = ctypes.util.dllist() ++ ++ self.assertGreater(len(dlls), 0, f"loaded={dlls}") ++ self.assertTrue( ++ any(lib in dll for dll in dlls for lib in KNOWN_LIBRARIES), f"loaded={dlls}" ++ ) ++ ++ def test_lists_updates(self): ++ dlls = ctypes.util.dllist() ++ ++ # this test relies on being able to import a library which is ++ # not already loaded. ++ # If it is (e.g. by a previous test in the same process), we skip ++ if any("_ctypes_test" in dll for dll in dlls): ++ self.skipTest("Test library is already loaded") ++ ++ _ctypes_test = import_helper.import_module("_ctypes_test") ++ test_module = CDLL(_ctypes_test.__file__) ++ dlls2 = ctypes.util.dllist() ++ self.assertIsNotNone(dlls2) ++ ++ dlls1 = set(dlls) ++ dlls2 = set(dlls2) ++ ++ self.assertGreater(dlls2, dlls1, f"newly loaded libraries: {dlls2 - dlls1}") ++ self.assertTrue(any("_ctypes_test" in dll for dll in dlls2), f"loaded={dlls2}") ++ ++ ++if __name__ == "__main__": ++ unittest.main() +diff --git a/Lib/test/test_ctypes/test_generated_structs.py b/Lib/test/test_ctypes/test_generated_structs.py +index d61754d6d49..1df9f0dc163 100644 +--- a/Lib/test/test_ctypes/test_generated_structs.py ++++ b/Lib/test/test_ctypes/test_generated_structs.py +@@ -443,7 +443,7 @@ + - None + - reason to skip the test (str) + +- This does depend on the C compiler keeping padding bits zero. ++ This does depend on the C compiler keeping padding bits unchanged. + Common compilers seem to do so. + """ + for name, cls in TESTCASES.items(): +@@ -696,7 +696,8 @@ + output(' ' + line) + typename = f'{struct_or_union(cls)} {name}' + output(f""" +- {typename} value = {{0}}; ++ {typename} value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString({c_str_repr(name)})); + APPEND(PyLong_FromLong(sizeof({typename}))); + APPEND(PyLong_FromLong(_Alignof({typename}))); +diff --git a/Lib/test/test_ctypes/test_loading.py b/Lib/test/test_ctypes/test_loading.py +index fc1eecb77e1..13ed813ad98 100644 +--- a/Lib/test/test_ctypes/test_loading.py ++++ b/Lib/test/test_ctypes/test_loading.py +@@ -135,7 +135,7 @@ + 'test specific to Windows') + def test_load_hasattr(self): + # bpo-34816: shouldn't raise OSError +- self.assertFalse(hasattr(ctypes.windll, 'test')) ++ self.assertNotHasAttr(ctypes.windll, 'test') + + @unittest.skipUnless(os.name == "nt", + 'test specific to Windows') +diff --git a/Lib/test/test_ctypes/test_memfunctions.py b/Lib/test/test_ctypes/test_memfunctions.py +index 112b27ba48e..32548761813 100644 +--- a/Lib/test/test_ctypes/test_memfunctions.py ++++ b/Lib/test/test_ctypes/test_memfunctions.py +@@ -5,7 +5,9 @@ + create_string_buffer, string_at, + create_unicode_buffer, wstring_at, + memmove, memset, +- c_char_p, c_byte, c_ubyte, c_wchar) ++ memoryview_at, c_void_p, ++ c_char_p, c_byte, c_ubyte, c_wchar, ++ addressof, byref) + + + class MemFunctionsTest(unittest.TestCase): +@@ -77,6 +79,62 @@ + self.assertEqual(wstring_at(a, 16), "Hello, World\0\0\0\0") + self.assertEqual(wstring_at(a, 0), "") + ++ def test_memoryview_at(self): ++ b = (c_byte * 10)() ++ ++ size = len(b) ++ for foreign_ptr in ( ++ b, ++ cast(b, c_void_p), ++ byref(b), ++ addressof(b), ++ ): ++ with self.subTest(foreign_ptr=type(foreign_ptr).__name__): ++ b[:] = b"initialval" ++ v = memoryview_at(foreign_ptr, size) ++ self.assertIsInstance(v, memoryview) ++ self.assertEqual(bytes(v), b"initialval") ++ ++ # test that writes to source buffer get reflected in memoryview ++ b[:] = b"0123456789" ++ self.assertEqual(bytes(v), b"0123456789") ++ ++ # test that writes to memoryview get reflected in source buffer ++ v[:] = b"9876543210" ++ self.assertEqual(bytes(b), b"9876543210") ++ ++ with self.assertRaises(ValueError): ++ memoryview_at(foreign_ptr, -1) ++ ++ with self.assertRaises(ValueError): ++ memoryview_at(foreign_ptr, sys.maxsize + 1) ++ ++ v0 = memoryview_at(foreign_ptr, 0) ++ self.assertEqual(bytes(v0), b'') ++ ++ def test_memoryview_at_readonly(self): ++ b = (c_byte * 10)() ++ ++ size = len(b) ++ for foreign_ptr in ( ++ b, ++ cast(b, c_void_p), ++ byref(b), ++ addressof(b), ++ ): ++ with self.subTest(foreign_ptr=type(foreign_ptr).__name__): ++ b[:] = b"initialval" ++ v = memoryview_at(foreign_ptr, size, readonly=True) ++ self.assertIsInstance(v, memoryview) ++ self.assertEqual(bytes(v), b"initialval") ++ ++ # test that writes to source buffer get reflected in memoryview ++ b[:] = b"0123456789" ++ self.assertEqual(bytes(v), b"0123456789") ++ ++ # test that writes to the memoryview are blocked ++ with self.assertRaises(TypeError): ++ v[:] = b"9876543210" + + if __name__ == "__main__": + unittest.main() +diff --git a/Lib/test/test_ctypes/test_random_things.py b/Lib/test/test_ctypes/test_random_things.py +index 630f6ed9489..73ff57d925e 100644 +--- a/Lib/test/test_ctypes/test_random_things.py ++++ b/Lib/test/test_ctypes/test_random_things.py +@@ -51,7 +51,7 @@ + if exc_msg is not None: + self.assertEqual(str(cm.unraisable.exc_value), exc_msg) + self.assertEqual(cm.unraisable.err_msg, +- f"Exception ignored on calling ctypes " ++ f"Exception ignored while calling ctypes " + f"callback function {callback_func!r}") + self.assertIsNone(cm.unraisable.object) + +diff --git a/Lib/test/test_ctypes/test_repr.py b/Lib/test/test_ctypes/test_repr.py +index e7587984a92..8c85e6cbe70 100644 +--- a/Lib/test/test_ctypes/test_repr.py ++++ b/Lib/test/test_ctypes/test_repr.py +@@ -22,12 +22,12 @@ + def test_numbers(self): + for typ in subclasses: + base = typ.__bases__[0] +- self.assertTrue(repr(base(42)).startswith(base.__name__)) +- self.assertEqual(" + + + + +diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py +index c719f571152..27350120d66 100644 +--- a/Lib/test/test_dis.py ++++ b/Lib/test/test_dis.py +@@ -15,7 +15,7 @@ + import unittest + from test.support import (captured_stdout, requires_debug_ranges, + requires_specialization, cpython_only, +- os_helper) ++ os_helper, import_helper, reset_code) + from test.support.bytecode_helper import BytecodeTestCase + + +@@ -181,7 +181,7 @@ + %3d JUMP_BACKWARD 5 (to L1) + + %3d L2: END_FOR +- POP_TOP ++ POP_ITER + LOAD_CONST 0 (None) + RETURN_VALUE + """ % (bug708901.__code__.co_firstlineno, +@@ -438,7 +438,7 @@ + LOAD_SMALL_INT 1 + BINARY_OP 13 (+=) + STORE_NAME 0 (x) +- JUMP_BACKWARD 8 (to L1) ++ JUMP_BACKWARD 12 (to L1) + """ + + dis_traceback = """\ +@@ -458,7 +458,8 @@ + + %4d LOAD_GLOBAL 0 (Exception) + CHECK_EXC_MATCH +- POP_JUMP_IF_FALSE 23 (to L7) ++ POP_JUMP_IF_FALSE 24 (to L7) ++ NOT_TAKEN + STORE_FAST 0 (e) + + %4d L4: LOAD_FAST 0 (e) +@@ -555,7 +556,8 @@ + %4d L3: PUSH_EXC_INFO + WITH_EXCEPT_START + TO_BOOL +- POP_JUMP_IF_TRUE 1 (to L4) ++ POP_JUMP_IF_TRUE 2 (to L4) ++ NOT_TAKEN + RERAISE 2 + L4: POP_TOP + L5: POP_EXCEPT +@@ -645,10 +647,11 @@ + L20: CLEANUP_THROW + L21: END_SEND + TO_BOOL +- POP_JUMP_IF_TRUE 1 (to L22) +- RERAISE 2 +- L22: POP_TOP +- L23: POP_EXCEPT ++ POP_JUMP_IF_TRUE 2 (to L24) ++ L22: NOT_TAKEN ++ L23: RERAISE 2 ++ L24: POP_TOP ++ L25: POP_EXCEPT + POP_TOP + POP_TOP + POP_TOP +@@ -658,24 +661,25 @@ + LOAD_CONST 0 (None) + RETURN_VALUE + +- -- L24: COPY 3 ++ -- L26: COPY 3 + POP_EXCEPT + RERAISE 1 +- L25: CALL_INTRINSIC_1 3 (INTRINSIC_STOPITERATION_ERROR) ++ L27: CALL_INTRINSIC_1 3 (INTRINSIC_STOPITERATION_ERROR) + RERAISE 1 + ExceptionTable: +- L1 to L3 -> L25 [0] lasti ++ L1 to L3 -> L27 [0] lasti + L3 to L4 -> L12 [4] +- L4 to L6 -> L25 [0] lasti ++ L4 to L6 -> L27 [0] lasti + L6 to L7 -> L16 [2] lasti +- L7 to L9 -> L25 [0] lasti ++ L7 to L9 -> L27 [0] lasti + L9 to L10 -> L14 [2] +- L10 to L13 -> L25 [0] lasti +- L14 to L15 -> L25 [0] lasti +- L16 to L18 -> L24 [4] lasti ++ L10 to L13 -> L27 [0] lasti ++ L14 to L15 -> L27 [0] lasti ++ L16 to L18 -> L26 [4] lasti + L18 to L19 -> L20 [7] +- L19 to L23 -> L24 [4] lasti +- L23 to L25 -> L25 [0] lasti ++ L19 to L22 -> L26 [4] lasti ++ L23 to L25 -> L26 [4] lasti ++ L25 to L27 -> L27 [0] lasti + """ % (_asyncwith.__code__.co_firstlineno, + _asyncwith.__code__.co_firstlineno + 1, + _asyncwith.__code__.co_firstlineno + 2, +@@ -839,7 +843,7 @@ + L1: RESUME 0 + LOAD_FAST 0 (.0) + GET_ITER +- L2: FOR_ITER 10 (to L3) ++ L2: FOR_ITER 14 (to L3) + STORE_FAST 1 (z) + LOAD_DEREF 2 (x) + LOAD_FAST 1 (z) +@@ -847,9 +851,9 @@ + YIELD_VALUE 0 + RESUME 5 + POP_TOP +- JUMP_BACKWARD 12 (to L2) ++ JUMP_BACKWARD 16 (to L2) + L3: END_FOR +- POP_TOP ++ POP_ITER + LOAD_CONST 0 (None) + RETURN_VALUE + +@@ -888,7 +892,7 @@ + %3d RESUME_CHECK 0 + + %3d BUILD_LIST 0 +- LOAD_CONST 0 ((1, 2, 3)) ++ LOAD_CONST_MORTAL 1 ((1, 2, 3)) + LIST_EXTEND 1 + LOAD_SMALL_INT 3 + BINARY_OP 5 (*) +@@ -900,11 +904,11 @@ + LOAD_FAST 0 (i) + CALL_PY_GENERAL 1 + POP_TOP +- JUMP_BACKWARD 16 (to L1) ++ JUMP_BACKWARD_{: <6} 16 (to L1) + + %3d L2: END_FOR +- POP_TOP +- LOAD_CONST_IMMORTAL 1 (None) ++ POP_ITER ++ LOAD_CONST_IMMORTAL 0 (None) + RETURN_VALUE + """ % (loop_test.__code__.co_firstlineno, + loop_test.__code__.co_firstlineno + 1, +@@ -927,8 +931,6 @@ + """% (extended_arg_quick.__code__.co_firstlineno, + extended_arg_quick.__code__.co_firstlineno + 1,) + +-ADAPTIVE_WARMUP_DELAY = 2 +- + class DisTestBase(unittest.TestCase): + "Common utilities for DisTests and TestDisTraceback" + +@@ -995,12 +997,14 @@ + def test_widths(self): + long_opcodes = set(['JUMP_BACKWARD_NO_INTERRUPT', + 'INSTRUMENTED_CALL_FUNCTION_EX']) +- for opcode, opname in enumerate(dis.opname): ++ for op, opname in enumerate(dis.opname): + if opname in long_opcodes or opname.startswith("INSTRUMENTED"): + continue ++ if opname in opcode._specialized_opmap: ++ continue + with self.subTest(opname=opname): + width = dis._OPNAME_WIDTH +- if opcode in dis.hasarg: ++ if op in dis.hasarg: + width += 1 + dis._OPARG_WIDTH + self.assertLessEqual(len(opname), width) + +@@ -1253,8 +1257,9 @@ + self.assertIsNone(e.__context__) + + @staticmethod +- def code_quicken(f, times=ADAPTIVE_WARMUP_DELAY): +- for _ in range(times): ++ def code_quicken(f): ++ _testinternalcapi = import_helper.import_module("_testinternalcapi") ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + f() + + @cpython_only +@@ -1300,16 +1305,18 @@ + @requires_specialization + def test_loop_quicken(self): + # Loop can trigger a quicken where the loop is located +- self.code_quicken(loop_test, 4) ++ self.code_quicken(loop_test) + got = self.get_disassembly(loop_test, adaptive=True) +- expected = dis_loop_test_quickened_code ++ jit = import_helper.import_module("_testinternalcapi").jit_enabled() ++ expected = dis_loop_test_quickened_code.format("JIT" if jit else "NO_JIT") + self.do_disassembly_compare(got, expected) + + @cpython_only + @requires_specialization + def test_loop_with_conditional_at_end_is_quickened(self): ++ _testinternalcapi = import_helper.import_module("_testinternalcapi") + def for_loop_true(x): +- for i in range(10): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + if x: + pass + +@@ -1318,7 +1325,7 @@ + self.get_disassembly(for_loop_true, adaptive=True)) + + def for_loop_false(x): +- for i in range(10): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + if x: + pass + +@@ -1328,7 +1335,7 @@ + + def while_loop(): + i = 0 +- while i < 10: ++ while i < _testinternalcapi.SPECIALIZATION_THRESHOLD: + i += 1 + + while_loop() +@@ -1349,7 +1356,7 @@ + self.code_quicken(f) + else: + # "copy" the code to un-quicken it: +- f.__code__ = f.__code__.replace() ++ reset_code(f) + for instruction in _unroll_caches_as_Instructions(dis.get_instructions( + f, show_caches=True, adaptive=adaptive + ), show_caches=True): +@@ -1699,204 +1706,211 @@ + Instruction = dis.Instruction + + expected_opinfo_outer = [ +- Instruction(opname='MAKE_CELL', opcode=92, arg=0, argval='a', argrepr='a', offset=0, start_offset=0, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), +- Instruction(opname='MAKE_CELL', opcode=92, arg=1, argval='b', argrepr='b', offset=2, start_offset=2, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), ++ Instruction(opname='MAKE_CELL', opcode=93, arg=0, argval='a', argrepr='a', offset=0, start_offset=0, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), ++ Instruction(opname='MAKE_CELL', opcode=93, arg=1, argval='b', argrepr='b', offset=2, start_offset=2, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), + Instruction(opname='RESUME', opcode=149, arg=0, argval=0, argrepr='', offset=4, start_offset=4, starts_line=True, line_number=1, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_CONST', opcode=79, arg=3, argval=(3, 4), argrepr='(3, 4)', offset=6, start_offset=6, starts_line=True, line_number=2, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_FAST', opcode=81, arg=0, argval='a', argrepr='a', offset=8, start_offset=8, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_FAST', opcode=81, arg=1, argval='b', argrepr='b', offset=10, start_offset=10, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), +- Instruction(opname='BUILD_TUPLE', opcode=48, arg=2, argval=2, argrepr='', offset=12, start_offset=12, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_CONST', opcode=79, arg=0, argval=code_object_f, argrepr=repr(code_object_f), offset=14, start_offset=14, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_CONST', opcode=80, arg=3, argval=(3, 4), argrepr='(3, 4)', offset=6, start_offset=6, starts_line=True, line_number=2, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_FAST', opcode=82, arg=0, argval='a', argrepr='a', offset=8, start_offset=8, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_FAST', opcode=82, arg=1, argval='b', argrepr='b', offset=10, start_offset=10, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), ++ Instruction(opname='BUILD_TUPLE', opcode=50, arg=2, argval=2, argrepr='', offset=12, start_offset=12, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_CONST', opcode=80, arg=0, argval=code_object_f, argrepr=repr(code_object_f), offset=14, start_offset=14, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), + Instruction(opname='MAKE_FUNCTION', opcode=23, arg=None, argval=None, argrepr='', offset=16, start_offset=16, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), +- Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=103, arg=8, argval=8, argrepr='closure', offset=18, start_offset=18, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), +- Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=103, arg=1, argval=1, argrepr='defaults', offset=20, start_offset=20, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), +- Instruction(opname='STORE_FAST', opcode=107, arg=2, argval='f', argrepr='f', offset=22, start_offset=22, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_GLOBAL', opcode=87, arg=1, argval='print', argrepr='print + NULL', offset=24, start_offset=24, starts_line=True, line_number=7, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), +- Instruction(opname='LOAD_DEREF', opcode=80, arg=0, argval='a', argrepr='a', offset=34, start_offset=34, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_DEREF', opcode=80, arg=1, argval='b', argrepr='b', offset=36, start_offset=36, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_CONST', opcode=79, arg=1, argval='', argrepr="''", offset=38, start_offset=38, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_SMALL_INT', opcode=89, arg=1, argval=1, argrepr='', offset=40, start_offset=40, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), +- Instruction(opname='BUILD_LIST', opcode=43, arg=0, argval=0, argrepr='', offset=42, start_offset=42, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), +- Instruction(opname='BUILD_MAP', opcode=44, arg=0, argval=0, argrepr='', offset=44, start_offset=44, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_CONST', opcode=79, arg=2, argval='Hello world!', argrepr="'Hello world!'", offset=46, start_offset=46, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), +- Instruction(opname='CALL', opcode=49, arg=7, argval=7, argrepr='', offset=48, start_offset=48, starts_line=False, line_number=7, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), +- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=56, start_offset=56, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_FAST', opcode=81, arg=2, argval='f', argrepr='f', offset=58, start_offset=58, starts_line=True, line_number=8, label=None, positions=None, cache_info=None), +- Instruction(opname='RETURN_VALUE', opcode=33, arg=None, argval=None, argrepr='', offset=60, start_offset=60, starts_line=False, line_number=8, label=None, positions=None, cache_info=None), ++ Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=104, arg=8, argval=8, argrepr='closure', offset=18, start_offset=18, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), ++ Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=104, arg=1, argval=1, argrepr='defaults', offset=20, start_offset=20, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), ++ Instruction(opname='STORE_FAST', opcode=108, arg=2, argval='f', argrepr='f', offset=22, start_offset=22, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_GLOBAL', opcode=88, arg=1, argval='print', argrepr='print + NULL', offset=24, start_offset=24, starts_line=True, line_number=7, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), ++ Instruction(opname='LOAD_DEREF', opcode=81, arg=0, argval='a', argrepr='a', offset=34, start_offset=34, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_DEREF', opcode=81, arg=1, argval='b', argrepr='b', offset=36, start_offset=36, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_CONST', opcode=80, arg=1, argval='', argrepr="''", offset=38, start_offset=38, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_SMALL_INT', opcode=90, arg=1, argval=1, argrepr='', offset=40, start_offset=40, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), ++ Instruction(opname='BUILD_LIST', opcode=45, arg=0, argval=0, argrepr='', offset=42, start_offset=42, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), ++ Instruction(opname='BUILD_MAP', opcode=46, arg=0, argval=0, argrepr='', offset=44, start_offset=44, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_CONST', opcode=80, arg=2, argval='Hello world!', argrepr="'Hello world!'", offset=46, start_offset=46, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), ++ Instruction(opname='CALL', opcode=51, arg=7, argval=7, argrepr='', offset=48, start_offset=48, starts_line=False, line_number=7, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), ++ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=56, start_offset=56, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_FAST', opcode=82, arg=2, argval='f', argrepr='f', offset=58, start_offset=58, starts_line=True, line_number=8, label=None, positions=None, cache_info=None), ++ Instruction(opname='RETURN_VALUE', opcode=35, arg=None, argval=None, argrepr='', offset=60, start_offset=60, starts_line=False, line_number=8, label=None, positions=None, cache_info=None), + ] + + expected_opinfo_f = [ +- Instruction(opname='COPY_FREE_VARS', opcode=58, arg=2, argval=2, argrepr='', offset=0, start_offset=0, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), +- Instruction(opname='MAKE_CELL', opcode=92, arg=0, argval='c', argrepr='c', offset=2, start_offset=2, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), +- Instruction(opname='MAKE_CELL', opcode=92, arg=1, argval='d', argrepr='d', offset=4, start_offset=4, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), ++ Instruction(opname='COPY_FREE_VARS', opcode=59, arg=2, argval=2, argrepr='', offset=0, start_offset=0, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), ++ Instruction(opname='MAKE_CELL', opcode=93, arg=0, argval='c', argrepr='c', offset=2, start_offset=2, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), ++ Instruction(opname='MAKE_CELL', opcode=93, arg=1, argval='d', argrepr='d', offset=4, start_offset=4, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), + Instruction(opname='RESUME', opcode=149, arg=0, argval=0, argrepr='', offset=6, start_offset=6, starts_line=True, line_number=2, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_CONST', opcode=79, arg=1, argval=(5, 6), argrepr='(5, 6)', offset=8, start_offset=8, starts_line=True, line_number=3, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_FAST', opcode=81, arg=3, argval='a', argrepr='a', offset=10, start_offset=10, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_FAST', opcode=81, arg=4, argval='b', argrepr='b', offset=12, start_offset=12, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_FAST', opcode=81, arg=0, argval='c', argrepr='c', offset=14, start_offset=14, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_FAST', opcode=81, arg=1, argval='d', argrepr='d', offset=16, start_offset=16, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), +- Instruction(opname='BUILD_TUPLE', opcode=48, arg=4, argval=4, argrepr='', offset=18, start_offset=18, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_CONST', opcode=79, arg=0, argval=code_object_inner, argrepr=repr(code_object_inner), offset=20, start_offset=20, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_CONST', opcode=80, arg=1, argval=(5, 6), argrepr='(5, 6)', offset=8, start_offset=8, starts_line=True, line_number=3, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_FAST', opcode=82, arg=3, argval='a', argrepr='a', offset=10, start_offset=10, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_FAST', opcode=82, arg=4, argval='b', argrepr='b', offset=12, start_offset=12, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_FAST', opcode=82, arg=0, argval='c', argrepr='c', offset=14, start_offset=14, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_FAST', opcode=82, arg=1, argval='d', argrepr='d', offset=16, start_offset=16, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), ++ Instruction(opname='BUILD_TUPLE', opcode=50, arg=4, argval=4, argrepr='', offset=18, start_offset=18, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_CONST', opcode=80, arg=0, argval=code_object_inner, argrepr=repr(code_object_inner), offset=20, start_offset=20, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), + Instruction(opname='MAKE_FUNCTION', opcode=23, arg=None, argval=None, argrepr='', offset=22, start_offset=22, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), +- Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=103, arg=8, argval=8, argrepr='closure', offset=24, start_offset=24, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), +- Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=103, arg=1, argval=1, argrepr='defaults', offset=26, start_offset=26, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), +- Instruction(opname='STORE_FAST', opcode=107, arg=2, argval='inner', argrepr='inner', offset=28, start_offset=28, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_GLOBAL', opcode=87, arg=1, argval='print', argrepr='print + NULL', offset=30, start_offset=30, starts_line=True, line_number=5, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), +- Instruction(opname='LOAD_DEREF', opcode=80, arg=3, argval='a', argrepr='a', offset=40, start_offset=40, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_DEREF', opcode=80, arg=4, argval='b', argrepr='b', offset=42, start_offset=42, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_DEREF', opcode=80, arg=0, argval='c', argrepr='c', offset=44, start_offset=44, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_DEREF', opcode=80, arg=1, argval='d', argrepr='d', offset=46, start_offset=46, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), +- Instruction(opname='CALL', opcode=49, arg=4, argval=4, argrepr='', offset=48, start_offset=48, starts_line=False, line_number=5, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), +- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=56, start_offset=56, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_FAST', opcode=81, arg=2, argval='inner', argrepr='inner', offset=58, start_offset=58, starts_line=True, line_number=6, label=None, positions=None, cache_info=None), +- Instruction(opname='RETURN_VALUE', opcode=33, arg=None, argval=None, argrepr='', offset=60, start_offset=60, starts_line=False, line_number=6, label=None, positions=None, cache_info=None), ++ Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=104, arg=8, argval=8, argrepr='closure', offset=24, start_offset=24, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), ++ Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=104, arg=1, argval=1, argrepr='defaults', offset=26, start_offset=26, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), ++ Instruction(opname='STORE_FAST', opcode=108, arg=2, argval='inner', argrepr='inner', offset=28, start_offset=28, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_GLOBAL', opcode=88, arg=1, argval='print', argrepr='print + NULL', offset=30, start_offset=30, starts_line=True, line_number=5, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), ++ Instruction(opname='LOAD_DEREF', opcode=81, arg=3, argval='a', argrepr='a', offset=40, start_offset=40, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_DEREF', opcode=81, arg=4, argval='b', argrepr='b', offset=42, start_offset=42, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_DEREF', opcode=81, arg=0, argval='c', argrepr='c', offset=44, start_offset=44, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_DEREF', opcode=81, arg=1, argval='d', argrepr='d', offset=46, start_offset=46, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), ++ Instruction(opname='CALL', opcode=51, arg=4, argval=4, argrepr='', offset=48, start_offset=48, starts_line=False, line_number=5, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), ++ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=56, start_offset=56, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_FAST', opcode=82, arg=2, argval='inner', argrepr='inner', offset=58, start_offset=58, starts_line=True, line_number=6, label=None, positions=None, cache_info=None), ++ Instruction(opname='RETURN_VALUE', opcode=35, arg=None, argval=None, argrepr='', offset=60, start_offset=60, starts_line=False, line_number=6, label=None, positions=None, cache_info=None), + ] + + expected_opinfo_inner = [ +- Instruction(opname='COPY_FREE_VARS', opcode=58, arg=4, argval=4, argrepr='', offset=0, start_offset=0, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), ++ Instruction(opname='COPY_FREE_VARS', opcode=59, arg=4, argval=4, argrepr='', offset=0, start_offset=0, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), + Instruction(opname='RESUME', opcode=149, arg=0, argval=0, argrepr='', offset=2, start_offset=2, starts_line=True, line_number=3, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_GLOBAL', opcode=87, arg=1, argval='print', argrepr='print + NULL', offset=4, start_offset=4, starts_line=True, line_number=4, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), +- Instruction(opname='LOAD_DEREF', opcode=80, arg=2, argval='a', argrepr='a', offset=14, start_offset=14, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_DEREF', opcode=80, arg=3, argval='b', argrepr='b', offset=16, start_offset=16, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_DEREF', opcode=80, arg=4, argval='c', argrepr='c', offset=18, start_offset=18, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_DEREF', opcode=80, arg=5, argval='d', argrepr='d', offset=20, start_offset=20, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_FAST_LOAD_FAST', opcode=84, arg=1, argval=('e', 'f'), argrepr='e, f', offset=22, start_offset=22, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), +- Instruction(opname='CALL', opcode=49, arg=6, argval=6, argrepr='', offset=24, start_offset=24, starts_line=False, line_number=4, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), +- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=32, start_offset=32, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_CONST', opcode=79, arg=0, argval=None, argrepr='None', offset=34, start_offset=34, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), +- Instruction(opname='RETURN_VALUE', opcode=33, arg=None, argval=None, argrepr='', offset=36, start_offset=36, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_GLOBAL', opcode=88, arg=1, argval='print', argrepr='print + NULL', offset=4, start_offset=4, starts_line=True, line_number=4, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), ++ Instruction(opname='LOAD_DEREF', opcode=81, arg=2, argval='a', argrepr='a', offset=14, start_offset=14, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_DEREF', opcode=81, arg=3, argval='b', argrepr='b', offset=16, start_offset=16, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_DEREF', opcode=81, arg=4, argval='c', argrepr='c', offset=18, start_offset=18, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_DEREF', opcode=81, arg=5, argval='d', argrepr='d', offset=20, start_offset=20, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_FAST_LOAD_FAST', opcode=85, arg=1, argval=('e', 'f'), argrepr='e, f', offset=22, start_offset=22, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), ++ Instruction(opname='CALL', opcode=51, arg=6, argval=6, argrepr='', offset=24, start_offset=24, starts_line=False, line_number=4, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), ++ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=32, start_offset=32, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_CONST', opcode=80, arg=0, argval=None, argrepr='None', offset=34, start_offset=34, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), ++ Instruction(opname='RETURN_VALUE', opcode=35, arg=None, argval=None, argrepr='', offset=36, start_offset=36, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), + ] + + expected_opinfo_jumpy = [ + Instruction(opname='RESUME', opcode=149, arg=0, argval=0, argrepr='', offset=0, start_offset=0, starts_line=True, line_number=1, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_GLOBAL', opcode=87, arg=1, argval='range', argrepr='range + NULL', offset=2, start_offset=2, starts_line=True, line_number=3, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), +- Instruction(opname='LOAD_SMALL_INT', opcode=89, arg=10, argval=10, argrepr='', offset=12, start_offset=12, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), +- Instruction(opname='CALL', opcode=49, arg=1, argval=1, argrepr='', offset=14, start_offset=14, starts_line=False, line_number=3, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), ++ Instruction(opname='LOAD_GLOBAL', opcode=88, arg=1, argval='range', argrepr='range + NULL', offset=2, start_offset=2, starts_line=True, line_number=3, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), ++ Instruction(opname='LOAD_SMALL_INT', opcode=90, arg=10, argval=10, argrepr='', offset=12, start_offset=12, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), ++ Instruction(opname='CALL', opcode=51, arg=1, argval=1, argrepr='', offset=14, start_offset=14, starts_line=False, line_number=3, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), + Instruction(opname='GET_ITER', opcode=16, arg=None, argval=None, argrepr='', offset=22, start_offset=22, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), +- Instruction(opname='FOR_ITER', opcode=67, arg=30, argval=88, argrepr='to L4', offset=24, start_offset=24, starts_line=False, line_number=3, label=1, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), +- Instruction(opname='STORE_FAST', opcode=107, arg=0, argval='i', argrepr='i', offset=28, start_offset=28, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_GLOBAL', opcode=87, arg=3, argval='print', argrepr='print + NULL', offset=30, start_offset=30, starts_line=True, line_number=4, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), +- Instruction(opname='LOAD_FAST', opcode=81, arg=0, argval='i', argrepr='i', offset=40, start_offset=40, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), +- Instruction(opname='CALL', opcode=49, arg=1, argval=1, argrepr='', offset=42, start_offset=42, starts_line=False, line_number=4, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), +- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=50, start_offset=50, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_FAST', opcode=81, arg=0, argval='i', argrepr='i', offset=52, start_offset=52, starts_line=True, line_number=5, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_SMALL_INT', opcode=89, arg=4, argval=4, argrepr='', offset=54, start_offset=54, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), +- Instruction(opname='COMPARE_OP', opcode=54, arg=18, argval='<', argrepr='bool(<)', offset=56, start_offset=56, starts_line=False, line_number=5, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), +- Instruction(opname='POP_JUMP_IF_FALSE', opcode=95, arg=2, argval=68, argrepr='to L2', offset=60, start_offset=60, starts_line=False, line_number=5, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), +- Instruction(opname='JUMP_BACKWARD', opcode=72, arg=22, argval=24, argrepr='to L1', offset=64, start_offset=64, starts_line=True, line_number=6, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), +- Instruction(opname='LOAD_FAST', opcode=81, arg=0, argval='i', argrepr='i', offset=68, start_offset=68, starts_line=True, line_number=7, label=2, positions=None, cache_info=None), +- Instruction(opname='LOAD_SMALL_INT', opcode=89, arg=6, argval=6, argrepr='', offset=70, start_offset=70, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), +- Instruction(opname='COMPARE_OP', opcode=54, arg=148, argval='>', argrepr='bool(>)', offset=72, start_offset=72, starts_line=False, line_number=7, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), +- Instruction(opname='POP_JUMP_IF_TRUE', opcode=98, arg=2, argval=84, argrepr='to L3', offset=76, start_offset=76, starts_line=False, line_number=7, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), +- Instruction(opname='JUMP_BACKWARD', opcode=72, arg=30, argval=24, argrepr='to L1', offset=80, start_offset=80, starts_line=False, line_number=7, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), +- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=84, start_offset=84, starts_line=True, line_number=8, label=3, positions=None, cache_info=None), +- Instruction(opname='JUMP_FORWARD', opcode=74, arg=13, argval=114, argrepr='to L5', offset=86, start_offset=86, starts_line=False, line_number=8, label=None, positions=None, cache_info=None), +- Instruction(opname='END_FOR', opcode=9, arg=None, argval=None, argrepr='', offset=88, start_offset=88, starts_line=True, line_number=3, label=4, positions=None, cache_info=None), +- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=90, start_offset=90, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_GLOBAL', opcode=87, arg=3, argval='print', argrepr='print + NULL', offset=92, start_offset=92, starts_line=True, line_number=10, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), +- Instruction(opname='LOAD_CONST', opcode=79, arg=0, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=102, start_offset=102, starts_line=False, line_number=10, label=None, positions=None, cache_info=None), +- Instruction(opname='CALL', opcode=49, arg=1, argval=1, argrepr='', offset=104, start_offset=104, starts_line=False, line_number=10, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), +- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=112, start_offset=112, starts_line=False, line_number=10, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_FAST_CHECK', opcode=83, arg=0, argval='i', argrepr='i', offset=114, start_offset=114, starts_line=True, line_number=11, label=5, positions=None, cache_info=None), +- Instruction(opname='TO_BOOL', opcode=37, arg=None, argval=None, argrepr='', offset=116, start_offset=116, starts_line=False, line_number=11, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('version', 2, b'\x00\x00\x00\x00')]), +- Instruction(opname='POP_JUMP_IF_FALSE', opcode=95, arg=33, argval=194, argrepr='to L8', offset=124, start_offset=124, starts_line=False, line_number=11, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), +- Instruction(opname='LOAD_GLOBAL', opcode=87, arg=3, argval='print', argrepr='print + NULL', offset=128, start_offset=128, starts_line=True, line_number=12, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), +- Instruction(opname='LOAD_FAST', opcode=81, arg=0, argval='i', argrepr='i', offset=138, start_offset=138, starts_line=False, line_number=12, label=None, positions=None, cache_info=None), +- Instruction(opname='CALL', opcode=49, arg=1, argval=1, argrepr='', offset=140, start_offset=140, starts_line=False, line_number=12, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), +- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=148, start_offset=148, starts_line=False, line_number=12, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_FAST', opcode=81, arg=0, argval='i', argrepr='i', offset=150, start_offset=150, starts_line=True, line_number=13, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_SMALL_INT', opcode=89, arg=1, argval=1, argrepr='', offset=152, start_offset=152, starts_line=False, line_number=13, label=None, positions=None, cache_info=None), +- Instruction(opname='BINARY_OP', opcode=42, arg=23, argval=23, argrepr='-=', offset=154, start_offset=154, starts_line=False, line_number=13, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), +- Instruction(opname='STORE_FAST', opcode=107, arg=0, argval='i', argrepr='i', offset=158, start_offset=158, starts_line=False, line_number=13, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_FAST', opcode=81, arg=0, argval='i', argrepr='i', offset=160, start_offset=160, starts_line=True, line_number=14, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_SMALL_INT', opcode=89, arg=6, argval=6, argrepr='', offset=162, start_offset=162, starts_line=False, line_number=14, label=None, positions=None, cache_info=None), +- Instruction(opname='COMPARE_OP', opcode=54, arg=148, argval='>', argrepr='bool(>)', offset=164, start_offset=164, starts_line=False, line_number=14, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), +- Instruction(opname='POP_JUMP_IF_FALSE', opcode=95, arg=2, argval=176, argrepr='to L6', offset=168, start_offset=168, starts_line=False, line_number=14, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), +- Instruction(opname='JUMP_BACKWARD', opcode=72, arg=31, argval=114, argrepr='to L5', offset=172, start_offset=172, starts_line=True, line_number=15, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), +- Instruction(opname='LOAD_FAST', opcode=81, arg=0, argval='i', argrepr='i', offset=176, start_offset=176, starts_line=True, line_number=16, label=6, positions=None, cache_info=None), +- Instruction(opname='LOAD_SMALL_INT', opcode=89, arg=4, argval=4, argrepr='', offset=178, start_offset=178, starts_line=False, line_number=16, label=None, positions=None, cache_info=None), +- Instruction(opname='COMPARE_OP', opcode=54, arg=18, argval='<', argrepr='bool(<)', offset=180, start_offset=180, starts_line=False, line_number=16, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), +- Instruction(opname='POP_JUMP_IF_TRUE', opcode=98, arg=2, argval=192, argrepr='to L7', offset=184, start_offset=184, starts_line=False, line_number=16, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), +- Instruction(opname='JUMP_BACKWARD', opcode=72, arg=39, argval=114, argrepr='to L5', offset=188, start_offset=188, starts_line=False, line_number=16, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), +- Instruction(opname='JUMP_FORWARD', opcode=74, arg=11, argval=216, argrepr='to L9', offset=192, start_offset=192, starts_line=True, line_number=17, label=7, positions=None, cache_info=None), +- Instruction(opname='LOAD_GLOBAL', opcode=87, arg=3, argval='print', argrepr='print + NULL', offset=194, start_offset=194, starts_line=True, line_number=19, label=8, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), +- Instruction(opname='LOAD_CONST', opcode=79, arg=1, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=204, start_offset=204, starts_line=False, line_number=19, label=None, positions=None, cache_info=None), +- Instruction(opname='CALL', opcode=49, arg=1, argval=1, argrepr='', offset=206, start_offset=206, starts_line=False, line_number=19, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), +- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=214, start_offset=214, starts_line=False, line_number=19, label=None, positions=None, cache_info=None), +- Instruction(opname='NOP', opcode=27, arg=None, argval=None, argrepr='', offset=216, start_offset=216, starts_line=True, line_number=20, label=9, positions=None, cache_info=None), +- Instruction(opname='LOAD_SMALL_INT', opcode=89, arg=1, argval=1, argrepr='', offset=218, start_offset=218, starts_line=True, line_number=21, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_SMALL_INT', opcode=89, arg=0, argval=0, argrepr='', offset=220, start_offset=220, starts_line=False, line_number=21, label=None, positions=None, cache_info=None), +- Instruction(opname='BINARY_OP', opcode=42, arg=11, argval=11, argrepr='/', offset=222, start_offset=222, starts_line=False, line_number=21, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), +- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=226, start_offset=226, starts_line=False, line_number=21, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_FAST', opcode=81, arg=0, argval='i', argrepr='i', offset=228, start_offset=228, starts_line=True, line_number=25, label=None, positions=None, cache_info=None), +- Instruction(opname='COPY', opcode=57, arg=1, argval=1, argrepr='', offset=230, start_offset=230, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_SPECIAL', opcode=90, arg=1, argval=1, argrepr='__exit__', offset=232, start_offset=232, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), +- Instruction(opname='SWAP', opcode=112, arg=2, argval=2, argrepr='', offset=234, start_offset=234, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), +- Instruction(opname='SWAP', opcode=112, arg=3, argval=3, argrepr='', offset=236, start_offset=236, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_SPECIAL', opcode=90, arg=0, argval=0, argrepr='__enter__', offset=238, start_offset=238, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), +- Instruction(opname='CALL', opcode=49, arg=0, argval=0, argrepr='', offset=240, start_offset=240, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), +- Instruction(opname='STORE_FAST', opcode=107, arg=1, argval='dodgy', argrepr='dodgy', offset=248, start_offset=248, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_GLOBAL', opcode=87, arg=3, argval='print', argrepr='print + NULL', offset=250, start_offset=250, starts_line=True, line_number=26, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), +- Instruction(opname='LOAD_CONST', opcode=79, arg=2, argval='Never reach this', argrepr="'Never reach this'", offset=260, start_offset=260, starts_line=False, line_number=26, label=None, positions=None, cache_info=None), +- Instruction(opname='CALL', opcode=49, arg=1, argval=1, argrepr='', offset=262, start_offset=262, starts_line=False, line_number=26, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), +- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=270, start_offset=270, starts_line=False, line_number=26, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_CONST', opcode=79, arg=3, argval=None, argrepr='None', offset=272, start_offset=272, starts_line=True, line_number=25, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_CONST', opcode=79, arg=3, argval=None, argrepr='None', offset=274, start_offset=274, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_CONST', opcode=79, arg=3, argval=None, argrepr='None', offset=276, start_offset=276, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), +- Instruction(opname='CALL', opcode=49, arg=3, argval=3, argrepr='', offset=278, start_offset=278, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), +- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=286, start_offset=286, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_GLOBAL', opcode=87, arg=3, argval='print', argrepr='print + NULL', offset=288, start_offset=288, starts_line=True, line_number=28, label=10, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), +- Instruction(opname='LOAD_CONST', opcode=79, arg=5, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=298, start_offset=298, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), +- Instruction(opname='CALL', opcode=49, arg=1, argval=1, argrepr='', offset=300, start_offset=300, starts_line=False, line_number=28, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), +- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=308, start_offset=308, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_CONST', opcode=79, arg=3, argval=None, argrepr='None', offset=310, start_offset=310, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), +- Instruction(opname='RETURN_VALUE', opcode=33, arg=None, argval=None, argrepr='', offset=312, start_offset=312, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), +- Instruction(opname='PUSH_EXC_INFO', opcode=30, arg=None, argval=None, argrepr='', offset=314, start_offset=314, starts_line=True, line_number=25, label=None, positions=None, cache_info=None), +- Instruction(opname='WITH_EXCEPT_START', opcode=41, arg=None, argval=None, argrepr='', offset=316, start_offset=316, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), +- Instruction(opname='TO_BOOL', opcode=37, arg=None, argval=None, argrepr='', offset=318, start_offset=318, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('version', 2, b'\x00\x00\x00\x00')]), +- Instruction(opname='POP_JUMP_IF_TRUE', opcode=98, arg=1, argval=332, argrepr='to L11', offset=326, start_offset=326, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), +- Instruction(opname='RERAISE', opcode=100, arg=2, argval=2, argrepr='', offset=330, start_offset=330, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), +- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=332, start_offset=332, starts_line=False, line_number=25, label=11, positions=None, cache_info=None), +- Instruction(opname='POP_EXCEPT', opcode=28, arg=None, argval=None, argrepr='', offset=334, start_offset=334, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), +- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=336, start_offset=336, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), +- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=338, start_offset=338, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), +- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=340, start_offset=340, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), +- Instruction(opname='JUMP_BACKWARD_NO_INTERRUPT', opcode=73, arg=28, argval=288, argrepr='to L10', offset=342, start_offset=342, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), +- Instruction(opname='COPY', opcode=57, arg=3, argval=3, argrepr='', offset=344, start_offset=344, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), +- Instruction(opname='POP_EXCEPT', opcode=28, arg=None, argval=None, argrepr='', offset=346, start_offset=346, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), +- Instruction(opname='RERAISE', opcode=100, arg=1, argval=1, argrepr='', offset=348, start_offset=348, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), +- Instruction(opname='PUSH_EXC_INFO', opcode=30, arg=None, argval=None, argrepr='', offset=350, start_offset=350, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_GLOBAL', opcode=87, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=352, start_offset=352, starts_line=True, line_number=22, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), +- Instruction(opname='CHECK_EXC_MATCH', opcode=5, arg=None, argval=None, argrepr='', offset=362, start_offset=362, starts_line=False, line_number=22, label=None, positions=None, cache_info=None), +- Instruction(opname='POP_JUMP_IF_FALSE', opcode=95, arg=14, argval=396, argrepr='to L12', offset=364, start_offset=364, starts_line=False, line_number=22, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), +- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=368, start_offset=368, starts_line=False, line_number=22, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_GLOBAL', opcode=87, arg=3, argval='print', argrepr='print + NULL', offset=370, start_offset=370, starts_line=True, line_number=23, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), +- Instruction(opname='LOAD_CONST', opcode=79, arg=4, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=380, start_offset=380, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), +- Instruction(opname='CALL', opcode=49, arg=1, argval=1, argrepr='', offset=382, start_offset=382, starts_line=False, line_number=23, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), +- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=390, start_offset=390, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), +- Instruction(opname='POP_EXCEPT', opcode=28, arg=None, argval=None, argrepr='', offset=392, start_offset=392, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), +- Instruction(opname='JUMP_BACKWARD_NO_INTERRUPT', opcode=73, arg=54, argval=288, argrepr='to L10', offset=394, start_offset=394, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), +- Instruction(opname='RERAISE', opcode=100, arg=0, argval=0, argrepr='', offset=396, start_offset=396, starts_line=True, line_number=22, label=12, positions=None, cache_info=None), +- Instruction(opname='COPY', opcode=57, arg=3, argval=3, argrepr='', offset=398, start_offset=398, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), +- Instruction(opname='POP_EXCEPT', opcode=28, arg=None, argval=None, argrepr='', offset=400, start_offset=400, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), +- Instruction(opname='RERAISE', opcode=100, arg=1, argval=1, argrepr='', offset=402, start_offset=402, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), +- Instruction(opname='PUSH_EXC_INFO', opcode=30, arg=None, argval=None, argrepr='', offset=404, start_offset=404, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), +- Instruction(opname='LOAD_GLOBAL', opcode=87, arg=3, argval='print', argrepr='print + NULL', offset=406, start_offset=406, starts_line=True, line_number=28, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), +- Instruction(opname='LOAD_CONST', opcode=79, arg=5, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=416, start_offset=416, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), +- Instruction(opname='CALL', opcode=49, arg=1, argval=1, argrepr='', offset=418, start_offset=418, starts_line=False, line_number=28, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), +- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=426, start_offset=426, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), +- Instruction(opname='RERAISE', opcode=100, arg=0, argval=0, argrepr='', offset=428, start_offset=428, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), +- Instruction(opname='COPY', opcode=57, arg=3, argval=3, argrepr='', offset=430, start_offset=430, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), +- Instruction(opname='POP_EXCEPT', opcode=28, arg=None, argval=None, argrepr='', offset=432, start_offset=432, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), +- Instruction(opname='RERAISE', opcode=100, arg=1, argval=1, argrepr='', offset=434, start_offset=434, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), ++ Instruction(opname='FOR_ITER', opcode=68, arg=32, argval=92, argrepr='to L4', offset=24, start_offset=24, starts_line=False, line_number=3, label=1, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), ++ Instruction(opname='STORE_FAST', opcode=108, arg=0, argval='i', argrepr='i', offset=28, start_offset=28, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_GLOBAL', opcode=88, arg=3, argval='print', argrepr='print + NULL', offset=30, start_offset=30, starts_line=True, line_number=4, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), ++ Instruction(opname='LOAD_FAST', opcode=82, arg=0, argval='i', argrepr='i', offset=40, start_offset=40, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), ++ Instruction(opname='CALL', opcode=51, arg=1, argval=1, argrepr='', offset=42, start_offset=42, starts_line=False, line_number=4, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), ++ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=50, start_offset=50, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_FAST', opcode=82, arg=0, argval='i', argrepr='i', offset=52, start_offset=52, starts_line=True, line_number=5, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_SMALL_INT', opcode=90, arg=4, argval=4, argrepr='', offset=54, start_offset=54, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), ++ Instruction(opname='COMPARE_OP', opcode=55, arg=18, argval='<', argrepr='bool(<)', offset=56, start_offset=56, starts_line=False, line_number=5, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), ++ Instruction(opname='POP_JUMP_IF_FALSE', opcode=96, arg=3, argval=70, argrepr='to L2', offset=60, start_offset=60, starts_line=False, line_number=5, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), ++ Instruction(opname='NOT_TAKEN', opcode=28, arg=None, argval=None, argrepr='', offset=64, start_offset=64, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), ++ Instruction(opname='JUMP_BACKWARD', opcode=73, arg=23, argval=24, argrepr='to L1', offset=66, start_offset=66, starts_line=True, line_number=6, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), ++ Instruction(opname='LOAD_FAST', opcode=82, arg=0, argval='i', argrepr='i', offset=70, start_offset=70, starts_line=True, line_number=7, label=2, positions=None, cache_info=None), ++ Instruction(opname='LOAD_SMALL_INT', opcode=90, arg=6, argval=6, argrepr='', offset=72, start_offset=72, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), ++ Instruction(opname='COMPARE_OP', opcode=55, arg=148, argval='>', argrepr='bool(>)', offset=74, start_offset=74, starts_line=False, line_number=7, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), ++ Instruction(opname='POP_JUMP_IF_TRUE', opcode=99, arg=3, argval=88, argrepr='to L3', offset=78, start_offset=78, starts_line=False, line_number=7, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), ++ Instruction(opname='NOT_TAKEN', opcode=28, arg=None, argval=None, argrepr='', offset=82, start_offset=82, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), ++ Instruction(opname='JUMP_BACKWARD', opcode=73, arg=32, argval=24, argrepr='to L1', offset=84, start_offset=84, starts_line=False, line_number=7, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), ++ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=88, start_offset=88, starts_line=True, line_number=8, label=3, positions=None, cache_info=None), ++ Instruction(opname='JUMP_FORWARD', opcode=75, arg=13, argval=118, argrepr='to L5', offset=90, start_offset=90, starts_line=False, line_number=8, label=None, positions=None, cache_info=None), ++ Instruction(opname='END_FOR', opcode=9, arg=None, argval=None, argrepr='', offset=92, start_offset=92, starts_line=True, line_number=3, label=4, positions=None, cache_info=None), ++ Instruction(opname='POP_ITER', opcode=30, arg=None, argval=None, argrepr='', offset=94, start_offset=94, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_GLOBAL', opcode=88, arg=3, argval='print', argrepr='print + NULL', offset=96, start_offset=96, starts_line=True, line_number=10, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), ++ Instruction(opname='LOAD_CONST', opcode=80, arg=0, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=106, start_offset=106, starts_line=False, line_number=10, label=None, positions=None, cache_info=None), ++ Instruction(opname='CALL', opcode=51, arg=1, argval=1, argrepr='', offset=108, start_offset=108, starts_line=False, line_number=10, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), ++ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=116, start_offset=116, starts_line=False, line_number=10, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_FAST_CHECK', opcode=84, arg=0, argval='i', argrepr='i', offset=118, start_offset=118, starts_line=True, line_number=11, label=5, positions=None, cache_info=None), ++ Instruction(opname='TO_BOOL', opcode=39, arg=None, argval=None, argrepr='', offset=120, start_offset=120, starts_line=False, line_number=11, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('version', 2, b'\x00\x00\x00\x00')]), ++ Instruction(opname='POP_JUMP_IF_FALSE', opcode=96, arg=40, argval=212, argrepr='to L8', offset=128, start_offset=128, starts_line=False, line_number=11, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), ++ Instruction(opname='NOT_TAKEN', opcode=28, arg=None, argval=None, argrepr='', offset=132, start_offset=132, starts_line=False, line_number=11, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_GLOBAL', opcode=88, arg=3, argval='print', argrepr='print + NULL', offset=134, start_offset=134, starts_line=True, line_number=12, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), ++ Instruction(opname='LOAD_FAST', opcode=82, arg=0, argval='i', argrepr='i', offset=144, start_offset=144, starts_line=False, line_number=12, label=None, positions=None, cache_info=None), ++ Instruction(opname='CALL', opcode=51, arg=1, argval=1, argrepr='', offset=146, start_offset=146, starts_line=False, line_number=12, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), ++ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=154, start_offset=154, starts_line=False, line_number=12, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_FAST', opcode=82, arg=0, argval='i', argrepr='i', offset=156, start_offset=156, starts_line=True, line_number=13, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_SMALL_INT', opcode=90, arg=1, argval=1, argrepr='', offset=158, start_offset=158, starts_line=False, line_number=13, label=None, positions=None, cache_info=None), ++ Instruction(opname='BINARY_OP', opcode=44, arg=23, argval=23, argrepr='-=', offset=160, start_offset=160, starts_line=False, line_number=13, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('descr', 4, b'\x00\x00\x00\x00\x00\x00\x00\x00')]), ++ Instruction(opname='STORE_FAST', opcode=108, arg=0, argval='i', argrepr='i', offset=172, start_offset=172, starts_line=False, line_number=13, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_FAST', opcode=82, arg=0, argval='i', argrepr='i', offset=174, start_offset=174, starts_line=True, line_number=14, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_SMALL_INT', opcode=90, arg=6, argval=6, argrepr='', offset=176, start_offset=176, starts_line=False, line_number=14, label=None, positions=None, cache_info=None), ++ Instruction(opname='COMPARE_OP', opcode=55, arg=148, argval='>', argrepr='bool(>)', offset=178, start_offset=178, starts_line=False, line_number=14, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), ++ Instruction(opname='POP_JUMP_IF_FALSE', opcode=96, arg=3, argval=192, argrepr='to L6', offset=182, start_offset=182, starts_line=False, line_number=14, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), ++ Instruction(opname='NOT_TAKEN', opcode=28, arg=None, argval=None, argrepr='', offset=186, start_offset=186, starts_line=False, line_number=14, label=None, positions=None, cache_info=None), ++ Instruction(opname='JUMP_BACKWARD', opcode=73, arg=37, argval=118, argrepr='to L5', offset=188, start_offset=188, starts_line=True, line_number=15, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), ++ Instruction(opname='LOAD_FAST', opcode=82, arg=0, argval='i', argrepr='i', offset=192, start_offset=192, starts_line=True, line_number=16, label=6, positions=None, cache_info=None), ++ Instruction(opname='LOAD_SMALL_INT', opcode=90, arg=4, argval=4, argrepr='', offset=194, start_offset=194, starts_line=False, line_number=16, label=None, positions=None, cache_info=None), ++ Instruction(opname='COMPARE_OP', opcode=55, arg=18, argval='<', argrepr='bool(<)', offset=196, start_offset=196, starts_line=False, line_number=16, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), ++ Instruction(opname='POP_JUMP_IF_TRUE', opcode=99, arg=3, argval=210, argrepr='to L7', offset=200, start_offset=200, starts_line=False, line_number=16, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), ++ Instruction(opname='NOT_TAKEN', opcode=28, arg=None, argval=None, argrepr='', offset=204, start_offset=204, starts_line=False, line_number=16, label=None, positions=None, cache_info=None), ++ Instruction(opname='JUMP_BACKWARD', opcode=73, arg=46, argval=118, argrepr='to L5', offset=206, start_offset=206, starts_line=False, line_number=16, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), ++ Instruction(opname='JUMP_FORWARD', opcode=75, arg=11, argval=234, argrepr='to L9', offset=210, start_offset=210, starts_line=True, line_number=17, label=7, positions=None, cache_info=None), ++ Instruction(opname='LOAD_GLOBAL', opcode=88, arg=3, argval='print', argrepr='print + NULL', offset=212, start_offset=212, starts_line=True, line_number=19, label=8, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), ++ Instruction(opname='LOAD_CONST', opcode=80, arg=1, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=222, start_offset=222, starts_line=False, line_number=19, label=None, positions=None, cache_info=None), ++ Instruction(opname='CALL', opcode=51, arg=1, argval=1, argrepr='', offset=224, start_offset=224, starts_line=False, line_number=19, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), ++ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=232, start_offset=232, starts_line=False, line_number=19, label=None, positions=None, cache_info=None), ++ Instruction(opname='NOP', opcode=27, arg=None, argval=None, argrepr='', offset=234, start_offset=234, starts_line=True, line_number=20, label=9, positions=None, cache_info=None), ++ Instruction(opname='LOAD_SMALL_INT', opcode=90, arg=1, argval=1, argrepr='', offset=236, start_offset=236, starts_line=True, line_number=21, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_SMALL_INT', opcode=90, arg=0, argval=0, argrepr='', offset=238, start_offset=238, starts_line=False, line_number=21, label=None, positions=None, cache_info=None), ++ Instruction(opname='BINARY_OP', opcode=44, arg=11, argval=11, argrepr='/', offset=240, start_offset=240, starts_line=False, line_number=21, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('descr', 4, b'\x00\x00\x00\x00\x00\x00\x00\x00')]), ++ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=252, start_offset=252, starts_line=False, line_number=21, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_FAST', opcode=82, arg=0, argval='i', argrepr='i', offset=254, start_offset=254, starts_line=True, line_number=25, label=None, positions=None, cache_info=None), ++ Instruction(opname='COPY', opcode=58, arg=1, argval=1, argrepr='', offset=256, start_offset=256, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_SPECIAL', opcode=91, arg=1, argval=1, argrepr='__exit__', offset=258, start_offset=258, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), ++ Instruction(opname='SWAP', opcode=113, arg=2, argval=2, argrepr='', offset=260, start_offset=260, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), ++ Instruction(opname='SWAP', opcode=113, arg=3, argval=3, argrepr='', offset=262, start_offset=262, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_SPECIAL', opcode=91, arg=0, argval=0, argrepr='__enter__', offset=264, start_offset=264, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), ++ Instruction(opname='CALL', opcode=51, arg=0, argval=0, argrepr='', offset=266, start_offset=266, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), ++ Instruction(opname='STORE_FAST', opcode=108, arg=1, argval='dodgy', argrepr='dodgy', offset=274, start_offset=274, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_GLOBAL', opcode=88, arg=3, argval='print', argrepr='print + NULL', offset=276, start_offset=276, starts_line=True, line_number=26, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), ++ Instruction(opname='LOAD_CONST', opcode=80, arg=2, argval='Never reach this', argrepr="'Never reach this'", offset=286, start_offset=286, starts_line=False, line_number=26, label=None, positions=None, cache_info=None), ++ Instruction(opname='CALL', opcode=51, arg=1, argval=1, argrepr='', offset=288, start_offset=288, starts_line=False, line_number=26, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), ++ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=296, start_offset=296, starts_line=False, line_number=26, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_CONST', opcode=80, arg=3, argval=None, argrepr='None', offset=298, start_offset=298, starts_line=True, line_number=25, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_CONST', opcode=80, arg=3, argval=None, argrepr='None', offset=300, start_offset=300, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_CONST', opcode=80, arg=3, argval=None, argrepr='None', offset=302, start_offset=302, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), ++ Instruction(opname='CALL', opcode=51, arg=3, argval=3, argrepr='', offset=304, start_offset=304, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), ++ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=312, start_offset=312, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_GLOBAL', opcode=88, arg=3, argval='print', argrepr='print + NULL', offset=314, start_offset=314, starts_line=True, line_number=28, label=10, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), ++ Instruction(opname='LOAD_CONST', opcode=80, arg=5, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=324, start_offset=324, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), ++ Instruction(opname='CALL', opcode=51, arg=1, argval=1, argrepr='', offset=326, start_offset=326, starts_line=False, line_number=28, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), ++ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=334, start_offset=334, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_CONST', opcode=80, arg=3, argval=None, argrepr='None', offset=336, start_offset=336, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), ++ Instruction(opname='RETURN_VALUE', opcode=35, arg=None, argval=None, argrepr='', offset=338, start_offset=338, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), ++ Instruction(opname='PUSH_EXC_INFO', opcode=32, arg=None, argval=None, argrepr='', offset=340, start_offset=340, starts_line=True, line_number=25, label=None, positions=None, cache_info=None), ++ Instruction(opname='WITH_EXCEPT_START', opcode=43, arg=None, argval=None, argrepr='', offset=342, start_offset=342, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), ++ Instruction(opname='TO_BOOL', opcode=39, arg=None, argval=None, argrepr='', offset=344, start_offset=344, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('version', 2, b'\x00\x00\x00\x00')]), ++ Instruction(opname='POP_JUMP_IF_TRUE', opcode=99, arg=2, argval=360, argrepr='to L11', offset=352, start_offset=352, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), ++ Instruction(opname='NOT_TAKEN', opcode=28, arg=None, argval=None, argrepr='', offset=356, start_offset=356, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), ++ Instruction(opname='RERAISE', opcode=101, arg=2, argval=2, argrepr='', offset=358, start_offset=358, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), ++ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=360, start_offset=360, starts_line=False, line_number=25, label=11, positions=None, cache_info=None), ++ Instruction(opname='POP_EXCEPT', opcode=29, arg=None, argval=None, argrepr='', offset=362, start_offset=362, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), ++ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=364, start_offset=364, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), ++ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=366, start_offset=366, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), ++ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=368, start_offset=368, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), ++ Instruction(opname='JUMP_BACKWARD_NO_INTERRUPT', opcode=74, arg=29, argval=314, argrepr='to L10', offset=370, start_offset=370, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), ++ Instruction(opname='COPY', opcode=58, arg=3, argval=3, argrepr='', offset=372, start_offset=372, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), ++ Instruction(opname='POP_EXCEPT', opcode=29, arg=None, argval=None, argrepr='', offset=374, start_offset=374, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), ++ Instruction(opname='RERAISE', opcode=101, arg=1, argval=1, argrepr='', offset=376, start_offset=376, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), ++ Instruction(opname='PUSH_EXC_INFO', opcode=32, arg=None, argval=None, argrepr='', offset=378, start_offset=378, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_GLOBAL', opcode=88, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=380, start_offset=380, starts_line=True, line_number=22, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), ++ Instruction(opname='CHECK_EXC_MATCH', opcode=5, arg=None, argval=None, argrepr='', offset=390, start_offset=390, starts_line=False, line_number=22, label=None, positions=None, cache_info=None), ++ Instruction(opname='POP_JUMP_IF_FALSE', opcode=96, arg=15, argval=426, argrepr='to L12', offset=392, start_offset=392, starts_line=False, line_number=22, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), ++ Instruction(opname='NOT_TAKEN', opcode=28, arg=None, argval=None, argrepr='', offset=396, start_offset=396, starts_line=False, line_number=22, label=None, positions=None, cache_info=None), ++ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=398, start_offset=398, starts_line=False, line_number=22, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_GLOBAL', opcode=88, arg=3, argval='print', argrepr='print + NULL', offset=400, start_offset=400, starts_line=True, line_number=23, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), ++ Instruction(opname='LOAD_CONST', opcode=80, arg=4, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=410, start_offset=410, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), ++ Instruction(opname='CALL', opcode=51, arg=1, argval=1, argrepr='', offset=412, start_offset=412, starts_line=False, line_number=23, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), ++ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=420, start_offset=420, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), ++ Instruction(opname='POP_EXCEPT', opcode=29, arg=None, argval=None, argrepr='', offset=422, start_offset=422, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), ++ Instruction(opname='JUMP_BACKWARD_NO_INTERRUPT', opcode=74, arg=56, argval=314, argrepr='to L10', offset=424, start_offset=424, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), ++ Instruction(opname='RERAISE', opcode=101, arg=0, argval=0, argrepr='', offset=426, start_offset=426, starts_line=True, line_number=22, label=12, positions=None, cache_info=None), ++ Instruction(opname='COPY', opcode=58, arg=3, argval=3, argrepr='', offset=428, start_offset=428, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), ++ Instruction(opname='POP_EXCEPT', opcode=29, arg=None, argval=None, argrepr='', offset=430, start_offset=430, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), ++ Instruction(opname='RERAISE', opcode=101, arg=1, argval=1, argrepr='', offset=432, start_offset=432, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), ++ Instruction(opname='PUSH_EXC_INFO', opcode=32, arg=None, argval=None, argrepr='', offset=434, start_offset=434, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), ++ Instruction(opname='LOAD_GLOBAL', opcode=88, arg=3, argval='print', argrepr='print + NULL', offset=436, start_offset=436, starts_line=True, line_number=28, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), ++ Instruction(opname='LOAD_CONST', opcode=80, arg=5, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=446, start_offset=446, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), ++ Instruction(opname='CALL', opcode=51, arg=1, argval=1, argrepr='', offset=448, start_offset=448, starts_line=False, line_number=28, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), ++ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=456, start_offset=456, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), ++ Instruction(opname='RERAISE', opcode=101, arg=0, argval=0, argrepr='', offset=458, start_offset=458, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), ++ Instruction(opname='COPY', opcode=58, arg=3, argval=3, argrepr='', offset=460, start_offset=460, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), ++ Instruction(opname='POP_EXCEPT', opcode=29, arg=None, argval=None, argrepr='', offset=462, start_offset=462, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), ++ Instruction(opname='RERAISE', opcode=101, arg=1, argval=1, argrepr='', offset=464, start_offset=464, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), + ] + + # One last piece of inspect fodder to check the default line number handling + def simple(): pass + expected_opinfo_simple = [ + Instruction(opname='RESUME', opcode=149, arg=0, argval=0, argrepr='', offset=0, start_offset=0, starts_line=True, line_number=simple.__code__.co_firstlineno, label=None, positions=None), +- Instruction(opname='LOAD_CONST', opcode=79, arg=0, argval=None, argrepr='None', offset=2, start_offset=2, starts_line=False, line_number=simple.__code__.co_firstlineno, label=None), +- Instruction(opname='RETURN_VALUE', opcode=33, arg=None, argval=None, argrepr='', offset=4, start_offset=4, starts_line=False, line_number=simple.__code__.co_firstlineno, label=None), ++ Instruction(opname='LOAD_CONST', opcode=80, arg=0, argval=None, argrepr='None', offset=2, start_offset=2, starts_line=False, line_number=simple.__code__.co_firstlineno, label=None), ++ Instruction(opname='RETURN_VALUE', opcode=35, arg=None, argval=None, argrepr='', offset=4, start_offset=4, starts_line=False, line_number=simple.__code__.co_firstlineno, label=None), + ] + + +@@ -2537,7 +2551,7 @@ + expect = ''' + 0 RESUME 0 + +- 1 LOAD_CONST_IMMORTAL 0 (None) ++ 1 LOAD_CONST 0 (None) + RETURN_VALUE + ''' + for flag in ['-S', '--specialized']: +diff --git a/Lib/test/test_doctest/test_doctest.py b/Lib/test/test_doctest/test_doctest.py +index b1e165fe16b..a4a49298bab 100644 +--- a/Lib/test/test_doctest/test_doctest.py ++++ b/Lib/test/test_doctest/test_doctest.py +@@ -2860,7 +2860,7 @@ + >>> _colorize.COLORIZE = save_colorize + """ + +-class TestImporter(importlib.abc.MetaPathFinder, importlib.abc.ResourceLoader): ++class TestImporter(importlib.abc.MetaPathFinder): + + def find_spec(self, fullname, path, target=None): + return importlib.util.spec_from_file_location(fullname, path, loader=self) +@@ -2869,6 +2869,12 @@ + with open(path, mode='rb') as f: + return f.read() + ++ def exec_module(self, module): ++ raise ImportError ++ ++ def create_module(self, spec): ++ return None ++ + class TestHook: + + def __init__(self, pathdir): +diff --git a/Lib/test/test_email/test__header_value_parser.py b/Lib/test/test_email/test__header_value_parser.py +index 95224e19f67..d60a7039f9d 100644 +--- a/Lib/test/test_email/test__header_value_parser.py ++++ b/Lib/test/test_email/test__header_value_parser.py +@@ -3082,13 +3082,40 @@ + self._test(parser.get_address_list(to)[0], + f'{a},\n =?utf-8?q?H=C3=BCbsch?= Kaktus \n') + +- a = '.' * 79 ++ a = '.' * 79 # ('.' is a special, so must be in quoted-string.) + to = f'"{a}" , "Hübsch Kaktus" ' + self._test(parser.get_address_list(to)[0], +- f'{a}\n' ++ f'"{a}"\n' + ' , =?utf-8?q?H=C3=BCbsch?= Kaktus ' + '\n') + ++ def test_address_list_with_specials_in_long_quoted_string(self): ++ # Regression for gh-80222. ++ policy = self.policy.clone(max_line_length=40) ++ cases = [ ++ # (to, folded) ++ ('"Exfiltrator (unclosed comment?" ', ++ '"Exfiltrator (unclosed\n' ++ ' comment?" \n'), ++ ('"Escaped \\" chars \\\\ in quoted-string stay escaped" ', ++ '"Escaped \\" chars \\\\ in quoted-string\n' ++ ' stay escaped" \n'), ++ ('This long display name does not need quotes ', ++ 'This long display name does not need\n' ++ ' quotes \n'), ++ ('"Quotes are not required but are retained here" ', ++ '"Quotes are not required but are\n' ++ ' retained here" \n'), ++ ('"A quoted-string, it can be a valid local-part"@example.com', ++ '"A quoted-string, it can be a valid\n' ++ ' local-part"@example.com\n'), ++ ('"local-part-with-specials@but-no-fws.cannot-fold"@example.com', ++ '"local-part-with-specials@but-no-fws.cannot-fold"@example.com\n'), ++ ] ++ for (to, folded) in cases: ++ with self.subTest(to=to): ++ self._test(parser.get_address_list(to)[0], folded, policy=policy) ++ + # XXX Need tests with comments on various sides of a unicode token, + # and with unicode tokens in the comments. Spaces inside the quotes + # currently don't do the right thing. +diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py +index abe9ef2e944..2deb3572157 100644 +--- a/Lib/test/test_email/test_email.py ++++ b/Lib/test/test_email/test_email.py +@@ -810,6 +810,16 @@ + w4kgdGVzdGFiYwo= + """)) + ++ def test_string_payload_with_base64_cte(self): ++ msg = email.message_from_string(textwrap.dedent("""\ ++ Content-Transfer-Encoding: base64 ++ ++ SGVsbG8uIFRlc3Rpbmc= ++ """), policy=email.policy.default) ++ self.assertEqual(msg.get_payload(decode=True), b"Hello. Testing") ++ self.assertDefectsEqual(msg['content-transfer-encoding'].defects, []) ++ ++ + + # Test the email.encoders module + class TestEncoders(unittest.TestCase): +@@ -2352,6 +2362,40 @@ + self.assertDefectsEqual(msg.defects, + [errors.MissingHeaderBodySeparatorDefect]) + ++ def test_string_payload_with_extra_space_after_cte(self): ++ # https://github.com/python/cpython/issues/98188 ++ cte = "base64 " ++ msg = email.message_from_string(textwrap.dedent(f"""\ ++ Content-Transfer-Encoding: {cte} ++ ++ SGVsbG8uIFRlc3Rpbmc= ++ """), policy=email.policy.default) ++ self.assertEqual(msg.get_payload(decode=True), b"Hello. Testing") ++ self.assertDefectsEqual(msg['content-transfer-encoding'].defects, []) ++ ++ def test_string_payload_with_extra_text_after_cte(self): ++ msg = email.message_from_string(textwrap.dedent("""\ ++ Content-Transfer-Encoding: base64 some text ++ ++ SGVsbG8uIFRlc3Rpbmc= ++ """), policy=email.policy.default) ++ self.assertEqual(msg.get_payload(decode=True), b"Hello. Testing") ++ cte = msg['content-transfer-encoding'] ++ self.assertDefectsEqual(cte.defects, [email.errors.InvalidHeaderDefect]) ++ ++ def test_string_payload_with_extra_space_after_cte_compat32(self): ++ cte = "base64 " ++ msg = email.message_from_string(textwrap.dedent(f"""\ ++ Content-Transfer-Encoding: {cte} ++ ++ SGVsbG8uIFRlc3Rpbmc= ++ """), policy=email.policy.compat32) ++ pasted_cte = msg['content-transfer-encoding'] ++ self.assertEqual(pasted_cte, cte) ++ self.assertEqual(msg.get_payload(decode=True), b"Hello. Testing") ++ self.assertDefectsEqual(msg.defects, []) ++ ++ + + # Test RFC 2047 header encoding and decoding + class TestRFC2047(TestEmailBase): +diff --git a/Lib/test/test_email/test_headerregistry.py b/Lib/test/test_email/test_headerregistry.py +index 4c0523f4103..ff7a6da644d 100644 +--- a/Lib/test/test_email/test_headerregistry.py ++++ b/Lib/test/test_email/test_headerregistry.py +@@ -837,6 +837,11 @@ + '7bit', + [errors.InvalidHeaderDefect]), + ++ 'extra_space_after_cte': ( ++ 'base64 ', ++ 'base64', ++ []), ++ + } + + +diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py +index 7110fb889f3..cd65496cafb 100644 +--- a/Lib/test/test_embed.py ++++ b/Lib/test/test_embed.py +@@ -51,6 +51,14 @@ + MAX_HASH_SEED = 4294967295 + + ABI_THREAD = 't' if sysconfig.get_config_var('Py_GIL_DISABLED') else '' ++# PLATSTDLIB_LANDMARK copied from Modules/getpath.py ++if os.name == 'nt': ++ PLATSTDLIB_LANDMARK = f'{sys.platlibdir}' ++else: ++ VERSION_MAJOR = sys.version_info.major ++ VERSION_MINOR = sys.version_info.minor ++ PLATSTDLIB_LANDMARK = (f'{sys.platlibdir}/python{VERSION_MAJOR}.' ++ f'{VERSION_MINOR}{ABI_THREAD}/lib-dynload') + + + # If we are running from a build dir, but the stdlib has been installed, +@@ -376,11 +384,14 @@ + def test_specialized_static_code_gets_unspecialized_at_Py_FINALIZE(self): + # https://github.com/python/cpython/issues/92031 + +- code = textwrap.dedent("""\ ++ _testinternalcapi = import_helper.import_module("_testinternalcapi") ++ ++ code = textwrap.dedent(f"""\ + import dis + import importlib._bootstrap + import opcode + import test.test_dis ++ import test.support + + def is_specialized(f): + for instruction in dis.get_instructions(f, adaptive=True): +@@ -399,11 +410,11 @@ + func = importlib._bootstrap._handle_fromlist + + # "copy" the code to un-specialize it: +- func.__code__ = func.__code__.replace() ++ test.support.reset_code(func) + + assert not is_specialized(func), "specialized instructions found" + +- for i in range(test.test_dis.ADAPTIVE_WARMUP_DELAY): ++ for _ in range({_testinternalcapi.SPECIALIZATION_THRESHOLD}): + func(importlib._bootstrap, ["x"], lambda *args: None) + + assert is_specialized(func), "no specialized instructions found" +@@ -940,6 +951,7 @@ + self.check_global_config(configs) + return configs + ++ @unittest.skipIf(support.check_bolt_optimized, "segfaults on BOLT instrumented binaries") + def test_init_default_config(self): + self.check_all_configs("test_init_initialize_config", api=API_COMPAT) + +@@ -1039,6 +1051,7 @@ + self.check_all_configs("test_init_from_config", config, preconfig, + api=API_COMPAT) + ++ @unittest.skipIf(support.check_bolt_optimized, "segfaults on BOLT instrumented binaries") + def test_init_compat_env(self): + preconfig = { + 'allocator': ALLOCATOR_FOR_CONFIG, +@@ -1047,7 +1060,6 @@ + 'use_hash_seed': True, + 'hash_seed': 42, + 'tracemalloc': 2, +- 'perf_profiling': 0, + 'import_time': True, + 'code_debug_ranges': False, + 'malloc_stats': True, +@@ -1074,6 +1086,7 @@ + self.check_all_configs("test_init_compat_env", config, preconfig, + api=API_COMPAT) + ++ @unittest.skipIf(support.check_bolt_optimized, "segfaults on BOLT instrumented binaries") + def test_init_python_env(self): + preconfig = { + 'allocator': ALLOCATOR_FOR_CONFIG, +@@ -1083,7 +1096,6 @@ + 'use_hash_seed': True, + 'hash_seed': 42, + 'tracemalloc': 2, +- 'perf_profiling': 0, + 'import_time': True, + 'code_debug_ranges': False, + 'malloc_stats': True, +@@ -1271,24 +1283,6 @@ + } + self.check_all_configs("test_init_run_main", config, api=API_PYTHON) + +- def test_init_main(self): +- code = ('import _testinternalcapi, json; ' +- 'print(json.dumps(_testinternalcapi.get_configs()))') +- config = { +- 'argv': ['-c', 'arg2'], +- 'orig_argv': ['python3', +- '-c', code, +- 'arg2'], +- 'program_name': './python3', +- 'run_command': code + '\n', +- 'parse_argv': True, +- '_init_main': False, +- 'sys_path_0': '', +- } +- self.check_all_configs("test_init_main", config, +- api=API_PYTHON, +- stderr="Run Python code before _Py_InitializeMain") +- + def test_init_parse_argv(self): + config = { + 'parse_argv': True, +@@ -1613,7 +1607,13 @@ + + with self.tmpdir_with_python() as tmpdir, \ + tempfile.TemporaryDirectory() as pyvenv_home: ++ + ver = sys.version_info ++ base_prefix = sysconfig.get_config_var("prefix") ++ ++ # gh-128690: base_exec_prefix depends if PLATSTDLIB_LANDMARK exists ++ platstdlib = os.path.join(base_prefix, PLATSTDLIB_LANDMARK) ++ change_exec_prefix = not os.path.isdir(platstdlib) + + if not MS_WINDOWS: + lib_dynload = os.path.join(pyvenv_home, +@@ -1637,7 +1637,8 @@ + + paths = self.module_search_paths() + if not MS_WINDOWS: +- paths[-1] = lib_dynload ++ if change_exec_prefix: ++ paths[-1] = lib_dynload + else: + paths = [ + os.path.join(tmpdir, os.path.basename(paths[0])), +@@ -1647,16 +1648,16 @@ + + executable = self.test_exe + base_executable = os.path.join(pyvenv_home, os.path.basename(executable)) +- exec_prefix = pyvenv_home + config = { +- 'base_prefix': sysconfig.get_config_var("prefix"), +- 'base_exec_prefix': exec_prefix, ++ 'base_prefix': base_prefix, + 'exec_prefix': tmpdir, + 'prefix': tmpdir, + 'base_executable': base_executable, + 'executable': executable, + 'module_search_paths': paths, + } ++ if change_exec_prefix: ++ config['base_exec_prefix'] = pyvenv_home + if MS_WINDOWS: + config['base_prefix'] = pyvenv_home + config['stdlib_dir'] = os.path.join(pyvenv_home, 'Lib') +@@ -1763,15 +1764,7 @@ + self.check_all_configs("test_init_warnoptions", config, preconfig, + api=API_PYTHON) + +- def test_init_set_config(self): +- config = { +- '_init_main': 0, +- 'bytes_warning': 2, +- 'warnoptions': ['error::BytesWarning'], +- } +- self.check_all_configs("test_init_set_config", config, +- api=API_ISOLATED) +- ++ @unittest.skipIf(support.check_bolt_optimized, "segfaults on BOLT instrumented binaries") + def test_initconfig_api(self): + preconfig = { + 'configure_locale': True, +@@ -1862,22 +1855,6 @@ + self.assertEqual(err, "") + + +-class SetConfigTests(unittest.TestCase): +- def test_set_config(self): +- # bpo-42260: Test _PyInterpreterState_SetConfig() +- import_helper.import_module('_testcapi') +- cmd = [sys.executable, '-X', 'utf8', '-I', '-m', 'test._test_embed_set_config'] +- proc = subprocess.run(cmd, +- stdout=subprocess.PIPE, +- stderr=subprocess.PIPE, +- encoding='utf-8', errors='backslashreplace') +- if proc.returncode and support.verbose: +- print(proc.stdout) +- print(proc.stderr) +- self.assertEqual(proc.returncode, 0, +- (proc.returncode, proc.stdout, proc.stderr)) +- +- + class AuditingTests(EmbeddingTestsMixin, unittest.TestCase): + def test_open_code_hook(self): + self.run_embedded_interpreter("test_open_code_hook") +@@ -2009,56 +1986,5 @@ + self.assertIn("unique-python-message", out) + + +-class StdPrinterTests(EmbeddingTestsMixin, unittest.TestCase): +- # Test PyStdPrinter_Type which is used by _PySys_SetPreliminaryStderr(): +- # "Set up a preliminary stderr printer until we have enough +- # infrastructure for the io module in place." +- +- STDOUT_FD = 1 +- +- def create_printer(self, fd): +- ctypes = import_helper.import_module('ctypes') +- PyFile_NewStdPrinter = ctypes.pythonapi.PyFile_NewStdPrinter +- PyFile_NewStdPrinter.argtypes = (ctypes.c_int,) +- PyFile_NewStdPrinter.restype = ctypes.py_object +- return PyFile_NewStdPrinter(fd) +- +- def test_write(self): +- message = "unicode:\xe9-\u20ac-\udc80!\n" +- +- stdout_fd = self.STDOUT_FD +- stdout_fd_copy = os.dup(stdout_fd) +- self.addCleanup(os.close, stdout_fd_copy) +- +- rfd, wfd = os.pipe() +- self.addCleanup(os.close, rfd) +- self.addCleanup(os.close, wfd) +- try: +- # PyFile_NewStdPrinter() only accepts fileno(stdout) +- # or fileno(stderr) file descriptor. +- os.dup2(wfd, stdout_fd) +- +- printer = self.create_printer(stdout_fd) +- printer.write(message) +- finally: +- os.dup2(stdout_fd_copy, stdout_fd) +- +- data = os.read(rfd, 100) +- self.assertEqual(data, message.encode('utf8', 'backslashreplace')) +- +- def test_methods(self): +- fd = self.STDOUT_FD +- printer = self.create_printer(fd) +- self.assertEqual(printer.fileno(), fd) +- self.assertEqual(printer.isatty(), os.isatty(fd)) +- printer.flush() # noop +- printer.close() # noop +- +- def test_disallow_instantiation(self): +- fd = self.STDOUT_FD +- printer = self.create_printer(fd) +- support.check_disallow_instantiation(self, type(printer)) +- +- + if __name__ == "__main__": + unittest.main() +diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py +index b9e13fb8c35..8884295b1ab 100644 +--- a/Lib/test/test_enum.py ++++ b/Lib/test/test_enum.py +@@ -14,7 +14,7 @@ + from enum import Enum, EnumMeta, IntEnum, StrEnum, EnumType, Flag, IntFlag, unique, auto + from enum import STRICT, CONFORM, EJECT, KEEP, _simple_enum, _test_simple_enum + from enum import verify, UNIQUE, CONTINUOUS, NAMED_FLAGS, ReprEnum +-from enum import member, nonmember, _iter_bits_lsb ++from enum import member, nonmember, _iter_bits_lsb, EnumDict + from io import StringIO + from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL + from test import support +@@ -5440,6 +5440,37 @@ + self.assertEqual(format(test_type.CONVERT_STRING_TEST_NAME_A), '5') + + ++class TestEnumDict(unittest.TestCase): ++ def test_enum_dict_in_metaclass(self): ++ """Test that EnumDict is usable as a class namespace""" ++ class Meta(type): ++ @classmethod ++ def __prepare__(metacls, cls, bases, **kwds): ++ return EnumDict(cls) ++ ++ class MyClass(metaclass=Meta): ++ a = 1 ++ ++ with self.assertRaises(TypeError): ++ a = 2 # duplicate ++ ++ with self.assertRaises(ValueError): ++ _a_sunder_ = 3 ++ ++ def test_enum_dict_standalone(self): ++ """Test that EnumDict is usable on its own""" ++ enumdict = EnumDict() ++ enumdict['a'] = 1 ++ ++ with self.assertRaises(TypeError): ++ enumdict['a'] = 'other value' ++ ++ # Only MutableMapping interface is overridden for now. ++ # If this stops passing, update the documentation. ++ enumdict |= {'a': 'other value'} ++ self.assertEqual(enumdict['a'], 'other value') ++ ++ + # helpers + + def enum_dir(cls): +diff --git a/Lib/test/test_eof.py b/Lib/test/test_eof.py +index e377383450e..582e5b6de6e 100644 +--- a/Lib/test/test_eof.py ++++ b/Lib/test/test_eof.py +@@ -2,7 +2,7 @@ + + import sys + from codecs import BOM_UTF8 +-from test import support ++from test.support import force_not_colorized + from test.support import os_helper + from test.support import script_helper + from test.support import warnings_helper +@@ -44,6 +44,7 @@ + self.assertEqual(cm.exception.text, "ä = '''thîs is ") + self.assertEqual(cm.exception.offset, 5) + ++ @force_not_colorized + def test_EOFS_with_file(self): + expect = ("(, line 1)") + with os_helper.temp_dir() as temp_dir: +@@ -123,6 +124,7 @@ + self.assertEqual(str(cm.exception), expect) + + @unittest.skipIf(not sys.executable, "sys.executable required") ++ @force_not_colorized + def test_line_continuation_EOF_from_file_bpo2180(self): + """Ensure tok_nextc() does not add too many ending newlines.""" + with os_helper.temp_dir() as temp_dir: +diff --git a/Lib/test/test_except_star.py b/Lib/test/test_except_star.py +index c49c6008e08..284907f6121 100644 +--- a/Lib/test/test_except_star.py ++++ b/Lib/test/test_except_star.py +@@ -952,6 +952,49 @@ + self.assertExceptionIsLike(tes, FalsyEG("eg", [TypeError(1)])) + self.assertExceptionIsLike(ves, FalsyEG("eg", [ValueError(2)])) + ++ def test_exception_group_subclass_with_bad_split_func(self): ++ # see gh-128049. ++ class BadEG1(ExceptionGroup): ++ def split(self, *args): ++ return "NOT A 2-TUPLE!" ++ ++ class BadEG2(ExceptionGroup): ++ def split(self, *args): ++ return ("NOT A 2-TUPLE!",) ++ ++ eg_list = [ ++ (BadEG1("eg", [OSError(123), ValueError(456)]), ++ r"split must return a tuple, not str"), ++ (BadEG2("eg", [OSError(123), ValueError(456)]), ++ r"split must return a 2-tuple, got tuple of size 1") ++ ] ++ ++ for eg_class, msg in eg_list: ++ with self.assertRaisesRegex(TypeError, msg) as m: ++ try: ++ raise eg_class ++ except* ValueError: ++ pass ++ except* OSError: ++ pass ++ ++ self.assertExceptionIsLike(m.exception.__context__, eg_class) ++ ++ # we allow tuples of length > 2 for backwards compatibility ++ class WeirdEG(ExceptionGroup): ++ def split(self, *args): ++ return super().split(*args) + ("anything", 123456, None) ++ ++ try: ++ raise WeirdEG("eg", [OSError(123), ValueError(456)]) ++ except* OSError as e: ++ oeg = e ++ except* ValueError as e: ++ veg = e ++ ++ self.assertExceptionIsLike(oeg, WeirdEG("eg", [OSError(123)])) ++ self.assertExceptionIsLike(veg, WeirdEG("eg", [ValueError(456)])) ++ + + class TestExceptStarCleanup(ExceptStarTest): + def test_sys_exception_restored(self): +diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py +index 6ccfa9575f8..3838eb5b27c 100644 +--- a/Lib/test/test_exceptions.py ++++ b/Lib/test/test_exceptions.py +@@ -1465,6 +1465,7 @@ + + @cpython_only + @unittest.skipIf(_testcapi is None, "requires _testcapi") ++ @force_not_colorized + def test_recursion_normalizing_infinite_exception(self): + # Issue #30697. Test that a RecursionError is raised when + # maximum recursion depth has been exceeded when creating +@@ -1677,10 +1678,13 @@ + + obj = BrokenDel() + with support.catch_unraisable_exception() as cm: ++ obj_repr = repr(type(obj).__del__) + del obj + + gc_collect() # For PyPy or other GCs. +- self.assertEqual(cm.unraisable.object, BrokenDel.__del__) ++ self.assertEqual(cm.unraisable.err_msg, ++ f"Exception ignored while calling " ++ f"deallocator {obj_repr}") + self.assertIsNotNone(cm.unraisable.exc_traceback) + + def test_unhandled(self): +@@ -2180,6 +2184,7 @@ + self.assertEqual(result[-len(expected):], expected) + + ++@support.force_not_colorized_test_class + class SyntaxErrorTests(unittest.TestCase): + maxDiff = None + +@@ -2274,6 +2279,7 @@ + self.assertIn(expected, err.getvalue()) + the_exception = exc + ++ @force_not_colorized + def test_subclass(self): + class MySyntaxError(SyntaxError): + pass +diff --git a/Lib/test/test_external_inspection.py b/Lib/test/test_external_inspection.py +index d896fec73d1..2ab48a4778b 100644 +--- a/Lib/test/test_external_inspection.py ++++ b/Lib/test/test_external_inspection.py +@@ -13,8 +13,10 @@ + try: + from _testexternalinspection import PROCESS_VM_READV_SUPPORTED + from _testexternalinspection import get_stack_trace ++ from _testexternalinspection import get_async_stack_trace + except ImportError: +- raise unittest.SkipTest("Test only runs when _testexternalinspection is available") ++ raise unittest.SkipTest( ++ "Test only runs when _testexternalinspection is available") + + def _make_test_script(script_dir, script_basename, source): + to_return = make_script(script_dir, script_basename, source) +@@ -23,12 +25,14 @@ + + class TestGetStackTrace(unittest.TestCase): + +- @unittest.skipIf(sys.platform != "darwin" and sys.platform != "linux", "Test only runs on Linux and MacOS") +- @unittest.skipIf(sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, "Test only runs on Linux with process_vm_readv support") ++ @unittest.skipIf(sys.platform != "darwin" and sys.platform != "linux", ++ "Test only runs on Linux and MacOS") ++ @unittest.skipIf(sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, ++ "Test only runs on Linux with process_vm_readv support") + def test_remote_stack_trace(self): + # Spawn a process with some realistic Python code + script = textwrap.dedent("""\ +- import time, sys, os ++ import time, sys + def bar(): + for x in range(100): + if x == 50: +@@ -37,8 +41,8 @@ + foo() + + def foo(): +- fifo = sys.argv[1] +- with open(sys.argv[1], "w") as fifo: ++ fifo_path = sys.argv[1] ++ with open(fifo_path, "w") as fifo: + fifo.write("ready") + time.sleep(1000) + +@@ -74,8 +78,281 @@ + ] + self.assertEqual(stack_trace, expected_stack_trace) + +- @unittest.skipIf(sys.platform != "darwin" and sys.platform != "linux", "Test only runs on Linux and MacOS") +- @unittest.skipIf(sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, "Test only runs on Linux with process_vm_readv support") ++ @unittest.skipIf(sys.platform != "darwin" and sys.platform != "linux", ++ "Test only runs on Linux and MacOS") ++ @unittest.skipIf(sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, ++ "Test only runs on Linux with process_vm_readv support") ++ def test_async_remote_stack_trace(self): ++ # Spawn a process with some realistic Python code ++ script = textwrap.dedent("""\ ++ import asyncio ++ import time ++ import sys ++ ++ def c5(): ++ fifo_path = sys.argv[1] ++ with open(fifo_path, "w") as fifo: ++ fifo.write("ready") ++ time.sleep(10000) ++ ++ async def c4(): ++ await asyncio.sleep(0) ++ c5() ++ ++ async def c3(): ++ await c4() ++ ++ async def c2(): ++ await c3() ++ ++ async def c1(task): ++ await task ++ ++ async def main(): ++ async with asyncio.TaskGroup() as tg: ++ task = tg.create_task(c2(), name="c2_root") ++ tg.create_task(c1(task), name="sub_main_1") ++ tg.create_task(c1(task), name="sub_main_2") ++ ++ def new_eager_loop(): ++ loop = asyncio.new_event_loop() ++ eager_task_factory = asyncio.create_eager_task_factory( ++ asyncio.Task) ++ loop.set_task_factory(eager_task_factory) ++ return loop ++ ++ asyncio.run(main(), loop_factory={TASK_FACTORY}) ++ """) ++ stack_trace = None ++ for task_factory_variant in "asyncio.new_event_loop", "new_eager_loop": ++ with ( ++ self.subTest(task_factory_variant=task_factory_variant), ++ os_helper.temp_dir() as work_dir, ++ ): ++ script_dir = os.path.join(work_dir, "script_pkg") ++ os.mkdir(script_dir) ++ fifo = f"{work_dir}/the_fifo" ++ os.mkfifo(fifo) ++ script_name = _make_test_script( ++ script_dir, 'script', ++ script.format(TASK_FACTORY=task_factory_variant)) ++ try: ++ p = subprocess.Popen( ++ [sys.executable, script_name, str(fifo)] ++ ) ++ with open(fifo, "r") as fifo_file: ++ response = fifo_file.read() ++ self.assertEqual(response, "ready") ++ stack_trace = get_async_stack_trace(p.pid) ++ except PermissionError: ++ self.skipTest( ++ "Insufficient permissions to read the stack trace") ++ finally: ++ os.remove(fifo) ++ p.kill() ++ p.terminate() ++ p.wait(timeout=SHORT_TIMEOUT) ++ ++ # sets are unordered, so we want to sort "awaited_by"s ++ stack_trace[2].sort(key=lambda x: x[1]) ++ ++ root_task = "Task-1" ++ expected_stack_trace = [ ++ ["c5", "c4", "c3", "c2"], ++ "c2_root", ++ [ ++ [["main"], root_task, []], ++ [["c1"], "sub_main_1", [[["main"], root_task, []]]], ++ [["c1"], "sub_main_2", [[["main"], root_task, []]]], ++ ], ++ ] ++ self.assertEqual(stack_trace, expected_stack_trace) ++ ++ @unittest.skipIf(sys.platform != "darwin" and sys.platform != "linux", ++ "Test only runs on Linux and MacOS") ++ @unittest.skipIf(sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, ++ "Test only runs on Linux with process_vm_readv support") ++ def test_asyncgen_remote_stack_trace(self): ++ # Spawn a process with some realistic Python code ++ script = textwrap.dedent("""\ ++ import asyncio ++ import time ++ import sys ++ ++ async def gen_nested_call(): ++ fifo_path = sys.argv[1] ++ with open(fifo_path, "w") as fifo: ++ fifo.write("ready") ++ time.sleep(10000) ++ ++ async def gen(): ++ for num in range(2): ++ yield num ++ if num == 1: ++ await gen_nested_call() ++ ++ async def main(): ++ async for el in gen(): ++ pass ++ ++ asyncio.run(main()) ++ """) ++ stack_trace = None ++ with os_helper.temp_dir() as work_dir: ++ script_dir = os.path.join(work_dir, "script_pkg") ++ os.mkdir(script_dir) ++ fifo = f"{work_dir}/the_fifo" ++ os.mkfifo(fifo) ++ script_name = _make_test_script(script_dir, 'script', script) ++ try: ++ p = subprocess.Popen([sys.executable, script_name, str(fifo)]) ++ with open(fifo, "r") as fifo_file: ++ response = fifo_file.read() ++ self.assertEqual(response, "ready") ++ stack_trace = get_async_stack_trace(p.pid) ++ except PermissionError: ++ self.skipTest("Insufficient permissions to read the stack trace") ++ finally: ++ os.remove(fifo) ++ p.kill() ++ p.terminate() ++ p.wait(timeout=SHORT_TIMEOUT) ++ ++ # sets are unordered, so we want to sort "awaited_by"s ++ stack_trace[2].sort(key=lambda x: x[1]) ++ ++ expected_stack_trace = [ ++ ['gen_nested_call', 'gen', 'main'], 'Task-1', [] ++ ] ++ self.assertEqual(stack_trace, expected_stack_trace) ++ ++ @unittest.skipIf(sys.platform != "darwin" and sys.platform != "linux", ++ "Test only runs on Linux and MacOS") ++ @unittest.skipIf(sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, ++ "Test only runs on Linux with process_vm_readv support") ++ def test_async_gather_remote_stack_trace(self): ++ # Spawn a process with some realistic Python code ++ script = textwrap.dedent("""\ ++ import asyncio ++ import time ++ import sys ++ ++ async def deep(): ++ await asyncio.sleep(0) ++ fifo_path = sys.argv[1] ++ with open(fifo_path, "w") as fifo: ++ fifo.write("ready") ++ time.sleep(10000) ++ ++ async def c1(): ++ await asyncio.sleep(0) ++ await deep() ++ ++ async def c2(): ++ await asyncio.sleep(0) ++ ++ async def main(): ++ await asyncio.gather(c1(), c2()) ++ ++ asyncio.run(main()) ++ """) ++ stack_trace = None ++ with os_helper.temp_dir() as work_dir: ++ script_dir = os.path.join(work_dir, "script_pkg") ++ os.mkdir(script_dir) ++ fifo = f"{work_dir}/the_fifo" ++ os.mkfifo(fifo) ++ script_name = _make_test_script(script_dir, 'script', script) ++ try: ++ p = subprocess.Popen([sys.executable, script_name, str(fifo)]) ++ with open(fifo, "r") as fifo_file: ++ response = fifo_file.read() ++ self.assertEqual(response, "ready") ++ stack_trace = get_async_stack_trace(p.pid) ++ except PermissionError: ++ self.skipTest( ++ "Insufficient permissions to read the stack trace") ++ finally: ++ os.remove(fifo) ++ p.kill() ++ p.terminate() ++ p.wait(timeout=SHORT_TIMEOUT) ++ ++ # sets are unordered, so we want to sort "awaited_by"s ++ stack_trace[2].sort(key=lambda x: x[1]) ++ ++ expected_stack_trace = [ ++ ['deep', 'c1'], 'Task-2', [[['main'], 'Task-1', []]] ++ ] ++ self.assertEqual(stack_trace, expected_stack_trace) ++ ++ @unittest.skipIf(sys.platform != "darwin" and sys.platform != "linux", ++ "Test only runs on Linux and MacOS") ++ @unittest.skipIf(sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, ++ "Test only runs on Linux with process_vm_readv support") ++ def test_async_staggered_race_remote_stack_trace(self): ++ # Spawn a process with some realistic Python code ++ script = textwrap.dedent("""\ ++ import asyncio.staggered ++ import time ++ import sys ++ ++ async def deep(): ++ await asyncio.sleep(0) ++ fifo_path = sys.argv[1] ++ with open(fifo_path, "w") as fifo: ++ fifo.write("ready") ++ time.sleep(10000) ++ ++ async def c1(): ++ await asyncio.sleep(0) ++ await deep() ++ ++ async def c2(): ++ await asyncio.sleep(10000) ++ ++ async def main(): ++ await asyncio.staggered.staggered_race( ++ [c1, c2], ++ delay=None, ++ ) ++ ++ asyncio.run(main()) ++ """) ++ stack_trace = None ++ with os_helper.temp_dir() as work_dir: ++ script_dir = os.path.join(work_dir, "script_pkg") ++ os.mkdir(script_dir) ++ fifo = f"{work_dir}/the_fifo" ++ os.mkfifo(fifo) ++ script_name = _make_test_script(script_dir, 'script', script) ++ try: ++ p = subprocess.Popen([sys.executable, script_name, str(fifo)]) ++ with open(fifo, "r") as fifo_file: ++ response = fifo_file.read() ++ self.assertEqual(response, "ready") ++ stack_trace = get_async_stack_trace(p.pid) ++ except PermissionError: ++ self.skipTest( ++ "Insufficient permissions to read the stack trace") ++ finally: ++ os.remove(fifo) ++ p.kill() ++ p.terminate() ++ p.wait(timeout=SHORT_TIMEOUT) ++ ++ # sets are unordered, so we want to sort "awaited_by"s ++ stack_trace[2].sort(key=lambda x: x[1]) ++ ++ expected_stack_trace = [ ++ ['deep', 'c1', 'run_one_coro'], 'Task-2', [[['main'], 'Task-1', []]] ++ ] ++ self.assertEqual(stack_trace, expected_stack_trace) ++ ++ @unittest.skipIf(sys.platform != "darwin" and sys.platform != "linux", ++ "Test only runs on Linux and MacOS") ++ @unittest.skipIf(sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, ++ "Test only runs on Linux with process_vm_readv support") + def test_self_trace(self): + stack_trace = get_stack_trace(os.getpid()) + self.assertEqual(stack_trace[0], "test_self_trace") +diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py +index 60815be96e1..bcebaef0a51 100644 +--- a/Lib/test/test_faulthandler.py ++++ b/Lib/test/test_faulthandler.py +@@ -7,7 +7,7 @@ + import subprocess + import sys + from test import support +-from test.support import os_helper, script_helper, is_android, MS_WINDOWS ++from test.support import os_helper, script_helper, is_android, MS_WINDOWS, threading_helper + import tempfile + import unittest + from textwrap import dedent +@@ -100,7 +100,11 @@ + + Raise an error if the output doesn't match the expected format. + """ +- if all_threads: ++ all_threads_disabled = ( ++ all_threads ++ and (not sys._is_gil_enabled()) ++ ) ++ if all_threads and not all_threads_disabled: + if know_current_thread: + header = 'Current thread 0x[0-9a-f]+' + else: +@@ -111,10 +115,15 @@ + if py_fatal_error: + regex.append("Python runtime state: initialized") + regex.append('') ++ if all_threads_disabled and not py_fatal_error: ++ regex.append("") + regex.append(fr'{header} \(most recent call first\):') +- if garbage_collecting: +- regex.append(' Garbage-collecting') +- regex.append(fr' File "", line {lineno} in {function}') ++ if support.Py_GIL_DISABLED and py_fatal_error and not know_current_thread: ++ regex.append(" ") ++ else: ++ if garbage_collecting and not all_threads_disabled: ++ regex.append(' Garbage-collecting') ++ regex.append(fr' File "", line {lineno} in {function}') + regex = '\n'.join(regex) + + if other_regex: +@@ -786,6 +795,7 @@ + def test_register_threads(self): + self.check_register(all_threads=True) + ++ @support.skip_if_sanitizer("gh-129825: hangs under TSAN", thread=True) + def test_register_chain(self): + self.check_register(chain=True) + +@@ -896,6 +906,34 @@ + self.assertEqual(output, []) + self.assertEqual(exitcode, 0) + ++ @threading_helper.requires_working_threading() ++ @unittest.skipUnless(support.Py_GIL_DISABLED, "only meaningful if the GIL is disabled") ++ def test_free_threaded_dump_traceback(self): ++ # gh-128400: Other threads need to be paused to invoke faulthandler ++ code = dedent(""" ++ import faulthandler ++ from threading import Thread, Event ++ ++ class Waiter(Thread): ++ def __init__(self): ++ Thread.__init__(self) ++ self.running = Event() ++ self.stop = Event() ++ ++ def run(self): ++ self.running.set() ++ self.stop.wait() ++ ++ for _ in range(100): ++ waiter = Waiter() ++ waiter.start() ++ waiter.running.wait() ++ faulthandler.dump_traceback(all_threads=True) ++ waiter.stop.set() ++ waiter.join() ++ """) ++ _, exitcode = self.get_output(code) ++ self.assertEqual(exitcode, 0) + + if __name__ == "__main__": + unittest.main() +diff --git a/Lib/test/test_frame.py b/Lib/test/test_frame.py +index 11f191700cc..4d086064023 100644 +--- a/Lib/test/test_frame.py ++++ b/Lib/test/test_frame.py +@@ -222,6 +222,56 @@ + with self.assertRaises(AttributeError): + del f.f_lineno + ++ def test_f_generator(self): ++ # Test f_generator in different contexts. ++ ++ def t0(): ++ def nested(): ++ frame = sys._getframe() ++ return frame.f_generator ++ ++ def gen(): ++ yield nested() ++ ++ g = gen() ++ try: ++ return next(g) ++ finally: ++ g.close() ++ ++ def t1(): ++ frame = sys._getframe() ++ return frame.f_generator ++ ++ def t2(): ++ frame = sys._getframe() ++ yield frame.f_generator ++ ++ async def t3(): ++ frame = sys._getframe() ++ return frame.f_generator ++ ++ # For regular functions f_generator is None ++ self.assertIsNone(t0()) ++ self.assertIsNone(t1()) ++ ++ # For generators f_generator is equal to self ++ g = t2() ++ try: ++ frame_g = next(g) ++ self.assertIs(g, frame_g) ++ finally: ++ g.close() ++ ++ # Ditto for coroutines ++ c = t3() ++ try: ++ c.send(None) ++ except StopIteration as ex: ++ self.assertIs(ex.value, c) ++ else: ++ raise AssertionError('coroutine did not exit') ++ + + class ReprTest(unittest.TestCase): + """ +@@ -723,51 +773,6 @@ + self.assertIs(catcher.unraisable.exc_type, TypeError) + self.assertIsNone(weak()) + +-@unittest.skipIf(_testcapi is None, 'need _testcapi') +-class TestCAPI(unittest.TestCase): +- def getframe(self): +- return sys._getframe() +- +- def test_frame_getters(self): +- frame = self.getframe() +- self.assertEqual(frame.f_locals, _testcapi.frame_getlocals(frame)) +- self.assertIs(frame.f_globals, _testcapi.frame_getglobals(frame)) +- self.assertIs(frame.f_builtins, _testcapi.frame_getbuiltins(frame)) +- self.assertEqual(frame.f_lasti, _testcapi.frame_getlasti(frame)) +- +- def test_getvar(self): +- current_frame = sys._getframe() +- x = 1 +- self.assertEqual(_testcapi.frame_getvar(current_frame, "x"), 1) +- self.assertEqual(_testcapi.frame_getvarstring(current_frame, b"x"), 1) +- with self.assertRaises(NameError): +- _testcapi.frame_getvar(current_frame, "y") +- with self.assertRaises(NameError): +- _testcapi.frame_getvarstring(current_frame, b"y") +- +- # wrong name type +- with self.assertRaises(TypeError): +- _testcapi.frame_getvar(current_frame, b'x') +- with self.assertRaises(TypeError): +- _testcapi.frame_getvar(current_frame, 123) +- +- def getgenframe(self): +- yield sys._getframe() +- +- def test_frame_get_generator(self): +- gen = self.getgenframe() +- frame = next(gen) +- self.assertIs(gen, _testcapi.frame_getgenerator(frame)) +- +- def test_frame_fback_api(self): +- """Test that accessing `f_back` does not cause a segmentation fault on +- a frame created with `PyFrame_New` (GH-99110).""" +- def dummy(): +- pass +- +- frame = _testcapi.frame_new(dummy.__code__, globals(), locals()) +- # The following line should not cause a segmentation fault. +- self.assertIsNone(frame.f_back) + + if __name__ == "__main__": + unittest.main() +diff --git a/Lib/test/test_free_threading/test_dict.py b/Lib/test/test_free_threading/test_dict.py +index 13717cb39fa..4f605e0c51f 100644 +--- a/Lib/test/test_free_threading/test_dict.py ++++ b/Lib/test/test_free_threading/test_dict.py +@@ -5,7 +5,7 @@ + + from ast import Or + from functools import partial +-from threading import Thread ++from threading import Barrier, Thread + from unittest import TestCase + + try: +@@ -142,6 +142,27 @@ + for ref in thread_list: + self.assertIsNone(ref()) + ++ def test_racing_get_set_dict(self): ++ """Races getting and setting a dict should be thread safe""" ++ THREAD_COUNT = 10 ++ barrier = Barrier(THREAD_COUNT) ++ def work(d): ++ barrier.wait() ++ for _ in range(1000): ++ d[10] = 0 ++ d.get(10, None) ++ _ = d[10] ++ ++ d = {} ++ worker_threads = [] ++ for ii in range(THREAD_COUNT): ++ worker_threads.append(Thread(target=work, args=[d])) ++ for t in worker_threads: ++ t.start() ++ for t in worker_threads: ++ t.join() ++ ++ + def test_racing_set_object_dict(self): + """Races assigning to __dict__ should be thread safe""" + class C: pass +--- /dev/null ++++ b/Lib/test/test_free_threading/test_func_annotations.py +@@ -0,0 +1,67 @@ ++import concurrent.futures ++import unittest ++import inspect ++from threading import Thread, Barrier ++from unittest import TestCase ++ ++from test.support import threading_helper, Py_GIL_DISABLED ++ ++threading_helper.requires_working_threading(module=True) ++ ++ ++def get_func_annotation(f, b): ++ b.wait() ++ return inspect.get_annotations(f) ++ ++ ++def get_func_annotation_dunder(f, b): ++ b.wait() ++ return f.__annotations__ ++ ++ ++def set_func_annotation(f, b): ++ b.wait() ++ f.__annotations__ = {'x': int, 'y': int, 'return': int} ++ return f.__annotations__ ++ ++ ++@unittest.skipUnless(Py_GIL_DISABLED, "Enable only in FT build") ++class TestFTFuncAnnotations(TestCase): ++ NUM_THREADS = 8 ++ ++ def test_concurrent_read(self): ++ def f(x: int) -> int: ++ return x + 1 ++ ++ for _ in range(100): ++ with concurrent.futures.ThreadPoolExecutor(max_workers=self.NUM_THREADS) as executor: ++ b = Barrier(self.NUM_THREADS) ++ futures = {executor.submit(get_func_annotation, f, b): i for i in range(self.NUM_THREADS)} ++ for fut in concurrent.futures.as_completed(futures): ++ annotate = fut.result() ++ self.assertIsNotNone(annotate) ++ self.assertEqual(annotate, {'x': int, 'return': int}) ++ ++ with concurrent.futures.ThreadPoolExecutor(max_workers=self.NUM_THREADS) as executor: ++ b = Barrier(self.NUM_THREADS) ++ futures = {executor.submit(get_func_annotation_dunder, f, b): i for i in range(self.NUM_THREADS)} ++ for fut in concurrent.futures.as_completed(futures): ++ annotate = fut.result() ++ self.assertIsNotNone(annotate) ++ self.assertEqual(annotate, {'x': int, 'return': int}) ++ ++ def test_concurrent_write(self): ++ def bar(x: int, y: float) -> float: ++ return y ** x ++ ++ for _ in range(100): ++ with concurrent.futures.ThreadPoolExecutor(max_workers=self.NUM_THREADS) as executor: ++ b = Barrier(self.NUM_THREADS) ++ futures = {executor.submit(set_func_annotation, bar, b): i for i in range(self.NUM_THREADS)} ++ for fut in concurrent.futures.as_completed(futures): ++ annotate = fut.result() ++ self.assertIsNotNone(annotate) ++ self.assertEqual(annotate, {'x': int, 'y': int, 'return': int}) ++ ++ # func_get_annotations returns in-place dict, so bar.__annotations__ should be modified as well ++ self.assertEqual(bar.__annotations__, {'x': int, 'y': int, 'return': int}) +diff --git a/Lib/test/test_free_threading/test_races.py b/Lib/test/test_free_threading/test_races.py +index 09e1d52e350..85aa69c8cd4 100644 +--- a/Lib/test/test_free_threading/test_races.py ++++ b/Lib/test/test_free_threading/test_races.py +@@ -4,6 +4,7 @@ + import threading + import time + import unittest ++import _testinternalcapi + + from test.support import threading_helper + +@@ -129,6 +130,161 @@ + # with the cell binding being changed). + do_race(access, mutate) + ++ def test_racing_to_bool(self): ++ ++ seq = [1] ++ ++ class C: ++ def __bool__(self): ++ return False ++ ++ def access(): ++ if seq: ++ return 1 ++ else: ++ return 2 ++ ++ def mutate(): ++ nonlocal seq ++ seq = [1] ++ time.sleep(0) ++ seq = C() ++ time.sleep(0) ++ ++ do_race(access, mutate) ++ ++ def test_racing_store_attr_slot(self): ++ class C: ++ __slots__ = ['x', '__dict__'] ++ ++ c = C() ++ ++ def set_slot(): ++ for i in range(10): ++ c.x = i ++ time.sleep(0) ++ ++ def change_type(): ++ def set_x(self, x): ++ pass ++ ++ def get_x(self): ++ pass ++ ++ C.x = property(get_x, set_x) ++ time.sleep(0) ++ del C.x ++ time.sleep(0) ++ ++ do_race(set_slot, change_type) ++ ++ def set_getattribute(): ++ C.__getattribute__ = lambda self, x: x ++ time.sleep(0) ++ del C.__getattribute__ ++ time.sleep(0) ++ ++ do_race(set_slot, set_getattribute) ++ ++ def test_racing_store_attr_instance_value(self): ++ class C: ++ pass ++ ++ c = C() ++ ++ def set_value(): ++ for i in range(100): ++ c.x = i ++ ++ set_value() ++ ++ def read(): ++ x = c.x ++ ++ def mutate(): ++ # Adding a property for 'x' should unspecialize it. ++ C.x = property(lambda self: None, lambda self, x: None) ++ time.sleep(0) ++ del C.x ++ time.sleep(0) ++ ++ do_race(read, mutate) ++ ++ def test_racing_store_attr_with_hint(self): ++ class C: ++ pass ++ ++ c = C() ++ for i in range(29): ++ setattr(c, f"_{i}", None) ++ ++ def set_value(): ++ for i in range(100): ++ c.x = i ++ ++ set_value() ++ ++ def read(): ++ x = c.x ++ ++ def mutate(): ++ # Adding a property for 'x' should unspecialize it. ++ C.x = property(lambda self: None, lambda self, x: None) ++ time.sleep(0) ++ del C.x ++ time.sleep(0) ++ ++ do_race(read, mutate) ++ ++ def make_shared_key_dict(self): ++ class C: ++ pass ++ ++ a = C() ++ a.x = 1 ++ return a.__dict__ ++ ++ def test_racing_store_attr_dict(self): ++ """Test STORE_ATTR with various dictionary types.""" ++ class C: ++ pass ++ ++ c = C() ++ ++ def set_value(): ++ for i in range(20): ++ c.x = i ++ ++ def mutate(): ++ nonlocal c ++ c.x = 1 ++ self.assertTrue(_testinternalcapi.has_inline_values(c)) ++ for i in range(30): ++ setattr(c, f"_{i}", None) ++ self.assertFalse(_testinternalcapi.has_inline_values(c.__dict__)) ++ c.__dict__ = self.make_shared_key_dict() ++ self.assertTrue(_testinternalcapi.has_split_table(c.__dict__)) ++ c.__dict__[1] = None ++ self.assertFalse(_testinternalcapi.has_split_table(c.__dict__)) ++ c = C() ++ ++ do_race(set_value, mutate) ++ ++ def test_racing_recursion_limit(self): ++ def something_recursive(): ++ def count(n): ++ if n > 0: ++ return count(n - 1) + 1 ++ return 0 ++ ++ count(50) ++ ++ def set_recursion_limit(): ++ for limit in range(100, 200): ++ sys.setrecursionlimit(limit) ++ ++ do_race(something_recursive, set_recursion_limit) ++ + + if __name__ == "__main__": + unittest.main() +diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py +index c359f2ecce0..1d96b7a2c24 100644 +--- a/Lib/test/test_fstring.py ++++ b/Lib/test/test_fstring.py +@@ -1649,6 +1649,14 @@ + #self.assertEqual(f'X{x =}Y', 'Xx\t='+repr(x)+'Y') + #self.assertEqual(f'X{x = }Y', 'Xx\t=\t'+repr(x)+'Y') + ++ def test_debug_expressions_are_raw_strings(self): ++ ++ self.assertEqual(f'{b"\N{OX}"=}', 'b"\\N{OX}"=b\'\\\\N{OX}\'') ++ self.assertEqual(f'{r"\xff"=}', 'r"\\xff"=\'\\\\xff\'') ++ self.assertEqual(f'{r"\n"=}', 'r"\\n"=\'\\\\n\'') ++ self.assertEqual(f"{'\''=}", "'\\''=\"'\"") ++ self.assertEqual(f'{'\xc5'=}', r"'\xc5'='Ã…'") ++ + def test_walrus(self): + x = 20 + # This isn't an assignment expression, it's 'x', with a format +@@ -1757,5 +1765,23 @@ + for s in ["", "some string"]: + self.assertEqual(get_code(f"'{s}'"), get_code(f"f'{s}'")) + ++ def test_gh129093(self): ++ self.assertEqual(f'{1==2=}', '1==2=False') ++ self.assertEqual(f'{1 == 2=}', '1 == 2=False') ++ self.assertEqual(f'{1!=2=}', '1!=2=True') ++ self.assertEqual(f'{1 != 2=}', '1 != 2=True') ++ ++ self.assertEqual(f'{(1) != 2=}', '(1) != 2=True') ++ self.assertEqual(f'{(1*2) != (3)=}', '(1*2) != (3)=True') ++ ++ self.assertEqual(f'{1 != 2 == 3 != 4=}', '1 != 2 == 3 != 4=False') ++ self.assertEqual(f'{1 == 2 != 3 == 4=}', '1 == 2 != 3 == 4=False') ++ ++ self.assertEqual(f'{f'{1==2=}'=}', "f'{1==2=}'='1==2=False'") ++ self.assertEqual(f'{f'{1 == 2=}'=}', "f'{1 == 2=}'='1 == 2=False'") ++ self.assertEqual(f'{f'{1!=2=}'=}', "f'{1!=2=}'='1!=2=True'") ++ self.assertEqual(f'{f'{1 != 2=}'=}', "f'{1 != 2=}'='1 != 2=True'") ++ ++ + if __name__ == '__main__': + unittest.main() +diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py +index ffd2adb8665..1b7a76bec83 100644 +--- a/Lib/test/test_functools.py ++++ b/Lib/test/test_functools.py +@@ -473,6 +473,12 @@ + self.assertEqual(a.cmeth(3, b=4), ((1, A, 3), {'a': 2, 'b': 4})) + self.assertEqual(a.smeth(3, b=4), ((1, 3), {'a': 2, 'b': 4})) + ++ def test_partial_genericalias(self): ++ alias = self.partial[int] ++ self.assertIs(alias.__origin__, self.partial) ++ self.assertEqual(alias.__args__, (int,)) ++ self.assertEqual(alias.__parameters__, ()) ++ + + @unittest.skipUnless(c_functools, 'requires the C _functools module') + class TestPartialC(TestPartial, unittest.TestCase): +@@ -639,11 +645,11 @@ + + def test_unbound_method_retrieval(self): + obj = self.A +- self.assertFalse(hasattr(obj.both, "__self__")) +- self.assertFalse(hasattr(obj.nested, "__self__")) +- self.assertFalse(hasattr(obj.over_partial, "__self__")) +- self.assertFalse(hasattr(obj.static, "__self__")) +- self.assertFalse(hasattr(self.a.static, "__self__")) ++ self.assertNotHasAttr(obj.both, "__self__") ++ self.assertNotHasAttr(obj.nested, "__self__") ++ self.assertNotHasAttr(obj.over_partial, "__self__") ++ self.assertNotHasAttr(obj.static, "__self__") ++ self.assertNotHasAttr(self.a.static, "__self__") + + def test_descriptors(self): + for obj in [self.A, self.a]: +@@ -785,7 +791,7 @@ + self.assertNotEqual(wrapper.__qualname__, f.__qualname__) + self.assertEqual(wrapper.__doc__, None) + self.assertEqual(wrapper.__annotations__, {}) +- self.assertFalse(hasattr(wrapper, 'attr')) ++ self.assertNotHasAttr(wrapper, 'attr') + + def test_selective_update(self): + def f(): +@@ -834,7 +840,7 @@ + pass + functools.update_wrapper(wrapper, max) + self.assertEqual(wrapper.__name__, 'max') +- self.assertTrue(wrapper.__doc__.startswith('max(')) ++ self.assertStartsWith(wrapper.__doc__, 'max(') + self.assertEqual(wrapper.__annotations__, {}) + + def test_update_type_wrapper(self): +@@ -904,7 +910,7 @@ + self.assertEqual(wrapper.__name__, 'wrapper') + self.assertNotEqual(wrapper.__qualname__, f.__qualname__) + self.assertEqual(wrapper.__doc__, None) +- self.assertFalse(hasattr(wrapper, 'attr')) ++ self.assertNotHasAttr(wrapper, 'attr') + + def test_selective_update(self): + def f(): +@@ -1039,6 +1045,12 @@ + class TestReducePy(TestReduce, unittest.TestCase): + reduce = staticmethod(py_functools.reduce) + ++ def test_reduce_with_kwargs(self): ++ with self.assertWarns(DeprecationWarning): ++ self.reduce(function=lambda x, y: x + y, sequence=[1, 2, 3, 4, 5], initial=1) ++ with self.assertWarns(DeprecationWarning): ++ self.reduce(lambda x, y: x + y, sequence=[1, 2, 3, 4, 5], initial=1) ++ + + class TestCmpToKey: + +@@ -2055,6 +2067,7 @@ + + @support.skip_on_s390x + @unittest.skipIf(support.is_wasi, "WASI has limited C stack") ++ @support.skip_if_sanitizer("requires deep stack", thread=True) + @support.skip_emscripten_stack_overflow() + def test_lru_recursion(self): + +@@ -2654,15 +2667,15 @@ + a.t(0) + self.assertEqual(a.arg, "int") + aa = A() +- self.assertFalse(hasattr(aa, 'arg')) ++ self.assertNotHasAttr(aa, 'arg') + a.t('') + self.assertEqual(a.arg, "str") + aa = A() +- self.assertFalse(hasattr(aa, 'arg')) ++ self.assertNotHasAttr(aa, 'arg') + a.t(0.0) + self.assertEqual(a.arg, "base") + aa = A() +- self.assertFalse(hasattr(aa, 'arg')) ++ self.assertNotHasAttr(aa, 'arg') + + def test_staticmethod_register(self): + class A: +@@ -3024,16 +3037,16 @@ + @i.register(42) + def _(arg): + return "I annotated with a non-type" +- self.assertTrue(str(exc.exception).startswith(msg_prefix + "42")) +- self.assertTrue(str(exc.exception).endswith(msg_suffix)) ++ self.assertStartsWith(str(exc.exception), msg_prefix + "42") ++ self.assertEndsWith(str(exc.exception), msg_suffix) + with self.assertRaises(TypeError) as exc: + @i.register + def _(arg): + return "I forgot to annotate" +- self.assertTrue(str(exc.exception).startswith(msg_prefix + ++ self.assertStartsWith(str(exc.exception), msg_prefix + + "._" +- )) +- self.assertTrue(str(exc.exception).endswith(msg_suffix)) ++ ) ++ self.assertEndsWith(str(exc.exception), msg_suffix) + + with self.assertRaises(TypeError) as exc: + @i.register +@@ -3043,23 +3056,23 @@ + # types from `typing`. Instead, annotate with regular types + # or ABCs. + return "I annotated with a generic collection" +- self.assertTrue(str(exc.exception).startswith( ++ self.assertStartsWith(str(exc.exception), + "Invalid annotation for 'arg'." +- )) +- self.assertTrue(str(exc.exception).endswith( ++ ) ++ self.assertEndsWith(str(exc.exception), + 'typing.Iterable[str] is not a class.' +- )) ++ ) + + with self.assertRaises(TypeError) as exc: + @i.register + def _(arg: typing.Union[int, typing.Iterable[str]]): + return "Invalid Union" +- self.assertTrue(str(exc.exception).startswith( ++ self.assertStartsWith(str(exc.exception), + "Invalid annotation for 'arg'." +- )) +- self.assertTrue(str(exc.exception).endswith( ++ ) ++ self.assertEndsWith(str(exc.exception), + 'typing.Union[int, typing.Iterable[str]] not all arguments are classes.' +- )) ++ ) + + def test_invalid_positional_argument(self): + @functools.singledispatch +diff --git a/Lib/test/test_gdb/util.py b/Lib/test/test_gdb/util.py +index 8fe9cfc5433..8097fd52aba 100644 +--- a/Lib/test/test_gdb/util.py ++++ b/Lib/test/test_gdb/util.py +@@ -280,11 +280,6 @@ + + return out + +- def assertEndsWith(self, actual, exp_end): +- '''Ensure that the given "actual" string ends with "exp_end"''' +- self.assertTrue(actual.endswith(exp_end), +- msg='%r did not end with %r' % (actual, exp_end)) +- + def assertMultilineMatches(self, actual, pattern): + m = re.match(pattern, actual, re.DOTALL) + if not m: +diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py +index 9c65e81dfe4..0e0f28be6b2 100644 +--- a/Lib/test/test_generated_cases.py ++++ b/Lib/test/test_generated_cases.py +@@ -281,12 +281,12 @@ + ) + + with open(self.temp_output_filename) as temp_output: +- lines = temp_output.readlines() +- while lines and lines[0].startswith(("// ", "#", " #", "\n")): +- lines.pop(0) +- while lines and lines[-1].startswith(("#", "\n")): +- lines.pop(-1) +- actual = "".join(lines) ++ lines = temp_output.read() ++ _, rest = lines.split(tier1_generator.INSTRUCTION_START_MARKER) ++ instructions, labels_with_prelude_and_postlude = rest.split(tier1_generator.INSTRUCTION_END_MARKER) ++ _, labels_with_postlude = labels_with_prelude_and_postlude.split(tier1_generator.LABEL_START_MARKER) ++ labels, _ = labels_with_postlude.split(tier1_generator.LABEL_END_MARKER) ++ actual = instructions.strip() + "\n\n " + labels.strip() + # if actual.strip() != expected.strip(): + # print("Actual:") + # print(actual) +@@ -304,6 +304,10 @@ + """ + output = """ + TARGET(OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP); +@@ -322,6 +326,10 @@ + """ + output = """ + TARGET(OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP); +@@ -343,6 +351,10 @@ + """ + output = """ + TARGET(OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP); +@@ -365,6 +377,10 @@ + """ + output = """ + TARGET(OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP); +@@ -388,6 +404,10 @@ + """ + output = """ + TARGET(OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP); +@@ -414,6 +434,10 @@ + """ + output = """ + TARGET(OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP); +@@ -442,10 +466,14 @@ + """ + output = """ + TARGET(OP1) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP1; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP1); +- PREDICTED(OP1); ++ PREDICTED_OP1:; + _PyStackRef res; + res = Py_None; + stack_pointer[-1] = res; +@@ -453,12 +481,22 @@ + } + + TARGET(OP3) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP3; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP3); + static_assert(INLINE_CACHE_ENTRIES_OP1 == 0, "incorrect cache size"); + _PyStackRef res; +- DEOPT_IF(xxx, OP1); ++ if (xxx) { ++ UPDATE_MISS_STATS(OP1); ++ assert(_PyOpcode_Deopt[opcode] == (OP1)); ++ JUMP_TO_PREDICTED(OP1); ++ } + res = Py_None; + stack_pointer[-1] = res; + DISPATCH(); +@@ -481,6 +519,10 @@ + """ + output = """ + TARGET(A) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = A; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(A); +@@ -498,6 +540,10 @@ + } + + TARGET(B) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = B; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(B); +@@ -535,10 +581,16 @@ + """ + output = """ + TARGET(OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP); +- if (cond) goto label; ++ if (cond) { ++ JUMP_TO_LABEL(label); ++ } + DISPATCH(); + } + """ +@@ -552,10 +604,16 @@ + """ + output = """ + TARGET(OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP); +- if (cond) goto label; ++ if (cond) { ++ JUMP_TO_LABEL(label); ++ } + // Comment is ok + DISPATCH(); + } +@@ -573,6 +631,10 @@ + """ + output = """ + TARGET(OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP); +@@ -582,7 +644,9 @@ + right = stack_pointer[-1]; + left = stack_pointer[-2]; + SPAM(left, right); +- if (cond) goto pop_2_label; ++ if (cond) { ++ JUMP_TO_LABEL(pop_2_label); ++ } + res = 0; + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -602,6 +666,10 @@ + """ + output = """ + TARGET(OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP); +@@ -611,7 +679,9 @@ + right = stack_pointer[-1]; + left = stack_pointer[-2]; + res = SPAM(left, right); +- if (cond) goto pop_2_label; ++ if (cond) { ++ JUMP_TO_LABEL(pop_2_label); ++ } + stack_pointer[-2] = res; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); +@@ -627,8 +697,13 @@ + """ + output = """ + TARGET(OP) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(OP); + uint16_t counter = read_u16(&this_instr[1].cache); +@@ -644,16 +719,28 @@ + + def test_suppress_dispatch(self): + input = """ ++ label(somewhere) { ++ } ++ + inst(OP, (--)) { + goto somewhere; + } + """ + output = """ + TARGET(OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP); +- goto somewhere; ++ JUMP_TO_LABEL(somewhere); ++ } ++ ++ LABEL(somewhere) ++ { ++ + } + """ + self.run_cases_test(input, output) +@@ -676,10 +763,14 @@ + """ + output = """ + TARGET(OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 6; + INSTRUCTION_STATS(OP); +- PREDICTED(OP); ++ PREDICTED_OP:; + _Py_CODEUNIT* const this_instr = next_instr - 6; + (void)this_instr; + _PyStackRef left; +@@ -713,8 +804,13 @@ + } + + TARGET(OP1) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP1; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(OP1); + _PyStackRef left; +@@ -730,6 +826,10 @@ + } + + TARGET(OP3) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP3; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 6; + INSTRUCTION_STATS(OP3); +@@ -761,6 +861,10 @@ + """ + output = """ + TARGET(OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(OP); +@@ -783,6 +887,10 @@ + """ + output = """ + TARGET(OP1) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP1; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP1); +@@ -802,6 +910,10 @@ + """ + output = """ + TARGET(OP1) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP1; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP1); +@@ -824,6 +936,10 @@ + """ + output = """ + TARGET(OP1) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP1; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP1); +@@ -831,6 +947,10 @@ + } + + TARGET(OP2) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP2; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP2); +@@ -848,6 +968,10 @@ + """ + output = """ + TARGET(OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP); +@@ -871,6 +995,10 @@ + """ + output = """ + TARGET(OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP); +@@ -899,6 +1027,10 @@ + """ + output = """ + TARGET(OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP); +@@ -923,13 +1055,17 @@ + """ + output = """ + TARGET(OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP); + if (oparg == 0) { + stack_pointer += -1 - oparg; + assert(WITHIN_STACK_BOUNDS()); +- goto somewhere; ++ JUMP_TO_LABEL(somewhere); + } + stack_pointer += -1 - oparg; + assert(WITHIN_STACK_BOUNDS()); +@@ -949,6 +1085,10 @@ + """ + output = """ + TARGET(OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP); +@@ -990,6 +1130,10 @@ + """ + output = """ + TARGET(M) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = M; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(M); +@@ -1034,6 +1178,10 @@ + """ + output = """ + TARGET(M) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = M; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(M); +@@ -1067,6 +1215,10 @@ + """ + output = """ + TARGET(OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP); +@@ -1088,6 +1240,10 @@ + """ + output = """ + TARGET(M) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = M; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(M); +@@ -1105,6 +1261,10 @@ + """ + output = """ + TARGET(OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP); +@@ -1123,6 +1283,10 @@ + """ + output = """ + TARGET(M) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = M; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(M); +@@ -1159,6 +1323,10 @@ + """ + output = """ + TARGET(OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP); +@@ -1181,6 +1349,10 @@ + """ + output = """ + TARGET(OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP); +@@ -1219,6 +1391,10 @@ + """ + output = """ + TARGET(INST) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = INST; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(INST); +@@ -1245,6 +1421,10 @@ + """ + output = """ + TARGET(TEST) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = TEST; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(TEST); +@@ -1285,6 +1465,10 @@ + """ + output = """ + TARGET(TEST) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = TEST; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(TEST); +@@ -1324,6 +1508,10 @@ + """ + output = """ + TARGET(TEST) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = TEST; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(TEST); +@@ -1372,6 +1560,10 @@ + """ + output = """ + TARGET(TEST) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = TEST; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(TEST); +@@ -1392,7 +1584,9 @@ + // THIRD + { + // Mark j and k as used +- if (cond) goto pop_2_error; ++ if (cond) { ++ JUMP_TO_LABEL(pop_2_error); ++ } + } + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); +@@ -1418,6 +1612,10 @@ + + output = """ + TARGET(TEST) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = TEST; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(TEST); +@@ -1435,7 +1633,7 @@ + stack_pointer[1] = b; + stack_pointer += 2; + assert(WITHIN_STACK_BOUNDS()); +- goto error; ++ JUMP_TO_LABEL(error); + } + } + stack_pointer[0] = a; +@@ -1459,17 +1657,25 @@ + """ + output = """ + TARGET(OP1) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP1; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP1); +- goto here; ++ JUMP_TO_LABEL(here); + } + + TARGET(OP2) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP2; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP2); +- goto there; ++ JUMP_TO_LABEL(there); + } + """ + self.run_cases_test(input, output) +@@ -1523,6 +1729,10 @@ + + output = """ + TARGET(BALANCED) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = BALANCED; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(BALANCED); +@@ -1543,6 +1753,10 @@ + + output = """ + TARGET(BALANCED) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = BALANCED; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(BALANCED); +@@ -1564,6 +1778,12 @@ + + output = """ + TARGET(BALANCED) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = BALANCED; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(BALANCED); +@@ -1584,6 +1804,10 @@ + + output = """ + TARGET(OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP); +@@ -1619,6 +1843,10 @@ + """ + output = """ + TARGET(OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP); +@@ -1639,47 +1867,67 @@ + """ + self.run_cases_test(input, output) + +- def test_pop_dead_inputs_all_live(self): ++ def test_pystackref_frompyobject_new_next_to_cmacro(self): + input = """ +- inst(OP, (a, b --)) { +- POP_DEAD_INPUTS(); +- HAM(a, b); +- INPUTS_DEAD(); ++ inst(OP, (-- out1, out2)) { ++ PyObject *obj = SPAM(); ++ #ifdef Py_GIL_DISABLED ++ out1 = PyStackRef_FromPyObjectNew(obj); ++ #else ++ out1 = PyStackRef_FromPyObjectNew(obj); ++ #endif ++ out2 = PyStackRef_FromPyObjectNew(obj); + } + """ + output = """ + TARGET(OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP); +- _PyStackRef a; +- _PyStackRef b; +- b = stack_pointer[-1]; +- a = stack_pointer[-2]; +- HAM(a, b); +- stack_pointer += -2; ++ _PyStackRef out1; ++ _PyStackRef out2; ++ PyObject *obj = SPAM(); ++ #ifdef Py_GIL_DISABLED ++ out1 = PyStackRef_FromPyObjectNew(obj); ++ #else ++ out1 = PyStackRef_FromPyObjectNew(obj); ++ #endif ++ out2 = PyStackRef_FromPyObjectNew(obj); ++ stack_pointer[0] = out1; ++ stack_pointer[1] = out2; ++ stack_pointer += 2; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + """ + self.run_cases_test(input, output) + +- def test_pop_dead_inputs_some_live(self): ++ def test_pop_input(self): + input = """ +- inst(OP, (a, b, c --)) { +- POP_DEAD_INPUTS(); ++ inst(OP, (a, b --)) { ++ POP_INPUT(b); + HAM(a); + INPUTS_DEAD(); + } + """ + output = """ + TARGET(OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(OP); + _PyStackRef a; +- a = stack_pointer[-3]; +- stack_pointer += -2; ++ _PyStackRef b; ++ b = stack_pointer[-1]; ++ a = stack_pointer[-2]; ++ stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + HAM(a); + stack_pointer += -1; +@@ -1689,26 +1937,190 @@ + """ + self.run_cases_test(input, output) + +- def test_pop_dead_inputs_with_output(self): ++ def test_pop_input_with_empty_stack(self): ++ input = """ ++ inst(OP, (--)) { ++ POP_INPUT(foo); ++ } ++ """ ++ with self.assertRaises(SyntaxError): ++ self.run_cases_test(input, "") ++ ++ def test_pop_input_with_non_tos(self): ++ input = """ ++ inst(OP, (a, b --)) { ++ POP_INPUT(a); ++ } ++ """ ++ with self.assertRaises(SyntaxError): ++ self.run_cases_test(input, "") ++ ++ def test_no_escaping_calls_in_branching_macros(self): ++ ++ input = """ ++ inst(OP, ( -- )) { ++ DEOPT_IF(escaping_call()); ++ } ++ """ ++ with self.assertRaises(SyntaxError): ++ self.run_cases_test(input, "") ++ ++ input = """ ++ inst(OP, ( -- )) { ++ EXIT_IF(escaping_call()); ++ } ++ """ ++ with self.assertRaises(SyntaxError): ++ self.run_cases_test(input, "") ++ ++ input = """ ++ inst(OP, ( -- )) { ++ ERROR_IF(escaping_call(), error); ++ } ++ """ ++ with self.assertRaises(SyntaxError): ++ self.run_cases_test(input, "") ++ ++ def test_kill_in_wrong_order(self): + input = """ + inst(OP, (a, b -- c)) { +- POP_DEAD_INPUTS(); +- c = SPAM(); ++ c = b; ++ PyStackRef_CLOSE(a); ++ PyStackRef_CLOSE(b); ++ } ++ """ ++ with self.assertRaises(SyntaxError): ++ self.run_cases_test(input, "") ++ ++ def test_complex_label(self): ++ input = """ ++ label(other_label) { ++ } ++ ++ label(other_label2) { ++ } ++ ++ label(my_label) { ++ // Comment ++ do_thing(); ++ if (complex) { ++ goto other_label; ++ } ++ goto other_label2; + } + """ ++ + output = """ +- TARGET(OP) { +- frame->instr_ptr = next_instr; +- next_instr += 1; +- INSTRUCTION_STATS(OP); +- _PyStackRef c; +- stack_pointer += -2; +- assert(WITHIN_STACK_BOUNDS()); +- c = SPAM(); +- stack_pointer[0] = c; +- stack_pointer += 1; +- assert(WITHIN_STACK_BOUNDS()); +- DISPATCH(); ++ LABEL(other_label) ++ { ++ ++ } ++ ++ LABEL(other_label2) ++ { ++ ++ } ++ ++ LABEL(my_label) ++ { ++ // Comment ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ do_thing(); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (complex) { ++ JUMP_TO_LABEL(other_label); ++ } ++ JUMP_TO_LABEL(other_label2); ++ } ++ """ ++ self.run_cases_test(input, output) ++ ++ def test_spilled_label(self): ++ input = """ ++ spilled label(one) { ++ RELOAD_STACK(); ++ goto two; ++ } ++ ++ label(two) { ++ SAVE_STACK(); ++ goto one; ++ } ++ """ ++ ++ output = """ ++ LABEL(one) ++ { ++ /* STACK SPILLED */ ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ JUMP_TO_LABEL(two); ++ } ++ ++ LABEL(two) ++ { ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ JUMP_TO_LABEL(one); ++ } ++ """ ++ self.run_cases_test(input, output) ++ ++ ++ def test_incorrect_spills(self): ++ input1 = """ ++ spilled label(one) { ++ goto two; ++ } ++ ++ label(two) { ++ } ++ """ ++ ++ input2 = """ ++ spilled label(one) { ++ } ++ ++ label(two) { ++ goto one; ++ } ++ """ ++ with self.assertRaisesRegex(SyntaxError, ".*reload.*"): ++ self.run_cases_test(input1, "") ++ with self.assertRaisesRegex(SyntaxError, ".*spill.*"): ++ self.run_cases_test(input2, "") ++ ++ ++ def test_multiple_labels(self): ++ input = """ ++ label(my_label_1) { ++ // Comment ++ do_thing1(); ++ goto my_label_2; ++ } ++ ++ label(my_label_2) { ++ // Comment ++ do_thing2(); ++ goto my_label_1; ++ } ++ """ ++ ++ output = """ ++ LABEL(my_label_1) ++ { ++ // Comment ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ do_thing1(); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ JUMP_TO_LABEL(my_label_2); ++ } ++ ++ LABEL(my_label_2) ++ { ++ // Comment ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ do_thing2(); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ JUMP_TO_LABEL(my_label_1); + } + """ + self.run_cases_test(input, output) +@@ -1799,8 +2211,8 @@ + """ + output = """ + case OP: { +- _Py_UopsSymbol *arg1; +- _Py_UopsSymbol *out; ++ JitOptSymbol *arg1; ++ JitOptSymbol *out; + arg1 = stack_pointer[-1]; + out = EGGS(arg1); + stack_pointer[-1] = out; +@@ -1808,7 +2220,7 @@ + } + + case OP2: { +- _Py_UopsSymbol *out; ++ JitOptSymbol *out; + out = sym_new_not_null(ctx); + stack_pointer[-1] = out; + break; +@@ -1833,14 +2245,14 @@ + """ + output = """ + case OP: { +- _Py_UopsSymbol *out; ++ JitOptSymbol *out; + out = sym_new_not_null(ctx); + stack_pointer[-1] = out; + break; + } + + case OP2: { +- _Py_UopsSymbol *out; ++ JitOptSymbol *out; + out = NULL; + stack_pointer[-1] = out; + break; +diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py +index 2ea6dba12ef..bf4b88cd9c4 100644 +--- a/Lib/test/test_generators.py ++++ b/Lib/test/test_generators.py +@@ -652,6 +652,89 @@ + self.assertIsNone(f_wr()) + + ++# See https://github.com/python/cpython/issues/125723 ++class GeneratorDeallocTest(unittest.TestCase): ++ def test_frame_outlives_generator(self): ++ def g1(): ++ a = 42 ++ yield sys._getframe() ++ ++ def g2(): ++ a = 42 ++ yield ++ ++ def g3(obj): ++ a = 42 ++ obj.frame = sys._getframe() ++ yield ++ ++ class ObjectWithFrame(): ++ def __init__(self): ++ self.frame = None ++ ++ def get_frame(index): ++ if index == 1: ++ return next(g1()) ++ elif index == 2: ++ gen = g2() ++ next(gen) ++ return gen.gi_frame ++ elif index == 3: ++ obj = ObjectWithFrame() ++ next(g3(obj)) ++ return obj.frame ++ else: ++ return None ++ ++ for index in (1, 2, 3): ++ with self.subTest(index=index): ++ frame = get_frame(index) ++ frame_locals = frame.f_locals ++ self.assertIn('a', frame_locals) ++ self.assertEqual(frame_locals['a'], 42) ++ ++ def test_frame_locals_outlive_generator(self): ++ frame_locals1 = None ++ ++ def g1(): ++ nonlocal frame_locals1 ++ frame_locals1 = sys._getframe().f_locals ++ a = 42 ++ yield ++ ++ def g2(): ++ a = 42 ++ yield sys._getframe().f_locals ++ ++ def get_frame_locals(index): ++ if index == 1: ++ nonlocal frame_locals1 ++ next(g1()) ++ return frame_locals1 ++ if index == 2: ++ return next(g2()) ++ else: ++ return None ++ ++ for index in (1, 2): ++ with self.subTest(index=index): ++ frame_locals = get_frame_locals(index) ++ self.assertIn('a', frame_locals) ++ self.assertEqual(frame_locals['a'], 42) ++ ++ def test_frame_locals_outlive_generator_with_exec(self): ++ def g(): ++ a = 42 ++ yield locals(), sys._getframe().f_locals ++ ++ locals_ = {'g': g} ++ for i in range(10): ++ exec("snapshot, live_locals = next(g())", locals=locals_) ++ for l in (locals_['snapshot'], locals_['live_locals']): ++ self.assertIn('a', l) ++ self.assertEqual(l['a'], 42) ++ ++ + class GeneratorThrowTest(unittest.TestCase): + + def test_exception_context_with_yield(self): +@@ -2581,14 +2664,18 @@ + >>> with support.catch_unraisable_exception() as cm: + ... g = f() + ... next(g) ++... gen_repr = repr(g) + ... del g + ... ++... cm.unraisable.err_msg == (f'Exception ignored while closing ' ++... f'generator {gen_repr}') + ... cm.unraisable.exc_type == RuntimeError + ... "generator ignored GeneratorExit" in str(cm.unraisable.exc_value) + ... cm.unraisable.exc_traceback is not None + True + True + True ++True + + And errors thrown during closing should propagate: + +@@ -2693,10 +2780,12 @@ + ... invoke("del failed") + ... + >>> with support.catch_unraisable_exception() as cm: +-... l = Leaker() +-... del l ++... leaker = Leaker() ++... del_repr = repr(type(leaker).__del__) ++... del leaker + ... +-... cm.unraisable.object == Leaker.__del__ ++... cm.unraisable.err_msg == (f'Exception ignored while ' ++... f'calling deallocator {del_repr}') + ... cm.unraisable.exc_type == RuntimeError + ... str(cm.unraisable.exc_value) == "del failed" + ... cm.unraisable.exc_traceback is not None +diff --git a/Lib/test/test_genericpath.py b/Lib/test/test_genericpath.py +index 6d2593cb4cf..391158b8556 100644 +--- a/Lib/test/test_genericpath.py ++++ b/Lib/test/test_genericpath.py +@@ -161,7 +161,7 @@ + self.assertIs(self.pathmodule.lexists(path=filename), True) + + @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") +- @unittest.skipIf(is_emscripten, "Emscripten pipe fds have no stat") ++ @unittest.skipIf(is_emscripten, "Fixed in next Emscripten release after 4.0.1") + def test_exists_fd(self): + r, w = os.pipe() + try: +diff --git a/Lib/test/test_glob.py b/Lib/test/test_glob.py +index b72640bd871..a45b30599d5 100644 +--- a/Lib/test/test_glob.py ++++ b/Lib/test/test_glob.py +@@ -6,6 +6,7 @@ + import unittest + import warnings + ++from test import support + from test.support import is_wasi, Py_DEBUG + from test.support.os_helper import (TESTFN, skip_unless_symlink, + can_symlink, create_empty_file, change_cwd) +@@ -170,37 +171,45 @@ + self.norm('aab', 'F')]) + + def test_glob_directory_with_trailing_slash(self): +- # Patterns ending with a slash shouldn't match non-dirs +- res = glob.glob(self.norm('Z*Z') + os.sep) +- self.assertEqual(res, []) +- res = glob.glob(self.norm('ZZZ') + os.sep) +- self.assertEqual(res, []) +- # When there is a wildcard pattern which ends with os.sep, glob() +- # doesn't blow up. +- res = glob.glob(self.norm('aa*') + os.sep) +- self.assertEqual(len(res), 2) +- # either of these results is reasonable +- self.assertIn(set(res), [ +- {self.norm('aaa'), self.norm('aab')}, +- {self.norm('aaa') + os.sep, self.norm('aab') + os.sep}, +- ]) ++ seps = (os.sep, os.altsep) if os.altsep else (os.sep,) ++ for sep in seps: ++ # Patterns ending with a slash shouldn't match non-dirs ++ self.assertEqual(glob.glob(self.norm('Z*Z') + sep), []) ++ self.assertEqual(glob.glob(self.norm('ZZZ') + sep), []) ++ self.assertEqual(glob.glob(self.norm('aaa') + sep), ++ [self.norm('aaa') + sep]) ++ # Preserving the redundant separators is an implementation detail. ++ self.assertEqual(glob.glob(self.norm('aaa') + sep*2), ++ [self.norm('aaa') + sep*2]) ++ # When there is a wildcard pattern which ends with a pathname ++ # separator, glob() doesn't blow. ++ # The result should end with the pathname separator. ++ # Normalizing the trailing separator is an implementation detail. ++ eq = self.assertSequencesEqual_noorder ++ eq(glob.glob(self.norm('aa*') + sep), ++ [self.norm('aaa') + os.sep, self.norm('aab') + os.sep]) ++ # Stripping the redundant separators is an implementation detail. ++ eq(glob.glob(self.norm('aa*') + sep*2), ++ [self.norm('aaa') + os.sep, self.norm('aab') + os.sep]) + + def test_glob_bytes_directory_with_trailing_slash(self): + # Same as test_glob_directory_with_trailing_slash, but with a + # bytes argument. +- res = glob.glob(os.fsencode(self.norm('Z*Z') + os.sep)) +- self.assertEqual(res, []) +- res = glob.glob(os.fsencode(self.norm('ZZZ') + os.sep)) +- self.assertEqual(res, []) +- res = glob.glob(os.fsencode(self.norm('aa*') + os.sep)) +- self.assertEqual(len(res), 2) +- # either of these results is reasonable +- self.assertIn(set(res), [ +- {os.fsencode(self.norm('aaa')), +- os.fsencode(self.norm('aab'))}, +- {os.fsencode(self.norm('aaa') + os.sep), +- os.fsencode(self.norm('aab') + os.sep)}, +- ]) ++ seps = (os.sep, os.altsep) if os.altsep else (os.sep,) ++ for sep in seps: ++ self.assertEqual(glob.glob(os.fsencode(self.norm('Z*Z') + sep)), []) ++ self.assertEqual(glob.glob(os.fsencode(self.norm('ZZZ') + sep)), []) ++ self.assertEqual(glob.glob(os.fsencode(self.norm('aaa') + sep)), ++ [os.fsencode(self.norm('aaa') + sep)]) ++ self.assertEqual(glob.glob(os.fsencode(self.norm('aaa') + sep*2)), ++ [os.fsencode(self.norm('aaa') + sep*2)]) ++ eq = self.assertSequencesEqual_noorder ++ eq(glob.glob(os.fsencode(self.norm('aa*') + sep)), ++ [os.fsencode(self.norm('aaa') + os.sep), ++ os.fsencode(self.norm('aab') + os.sep)]) ++ eq(glob.glob(os.fsencode(self.norm('aa*') + sep*2)), ++ [os.fsencode(self.norm('aaa') + os.sep), ++ os.fsencode(self.norm('aab') + os.sep)]) + + @skip_unless_symlink + def test_glob_symlinks(self): +@@ -208,8 +217,7 @@ + eq(self.glob('sym3'), [self.norm('sym3')]) + eq(self.glob('sym3', '*'), [self.norm('sym3', 'EF'), + self.norm('sym3', 'efg')]) +- self.assertIn(self.glob('sym3' + os.sep), +- [[self.norm('sym3')], [self.norm('sym3') + os.sep]]) ++ eq(self.glob('sym3' + os.sep), [self.norm('sym3') + os.sep]) + eq(self.glob('*', '*F'), + [self.norm('aaa', 'zzzF'), + self.norm('aab', 'F'), self.norm('sym3', 'EF')]) +@@ -510,11 +518,21 @@ + @skip_unless_symlink + class SymlinkLoopGlobTests(unittest.TestCase): + ++ # gh-109959: On Linux, glob._isdir() and glob._lexists() can return False ++ # randomly when checking the "link/" symbolic link. ++ # https://github.com/python/cpython/issues/109959#issuecomment-2577550700 ++ @unittest.skip("flaky test") + def test_selflink(self): + tempdir = TESTFN + "_dir" + os.makedirs(tempdir) + self.addCleanup(shutil.rmtree, tempdir) + with change_cwd(tempdir): ++ if support.verbose: ++ cwd = os.getcwd() ++ print(f"cwd: {cwd} ({len(cwd)} chars)") ++ cwdb = os.getcwdb() ++ print(f"cwdb: {cwdb!r} ({len(cwdb)} bytes)") ++ + os.makedirs('dir') + create_empty_file(os.path.join('dir', 'file')) + os.symlink(os.curdir, os.path.join('dir', 'link')) +diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py +index 575b2cd0da7..d1b04128bf6 100644 +--- a/Lib/test/test_hashlib.py ++++ b/Lib/test/test_hashlib.py +@@ -13,13 +13,13 @@ + import os + import sys + import sysconfig ++import tempfile + import threading + import unittest + import warnings + from test import support + from test.support import _4G, bigmemtest + from test.support.import_helper import import_fresh_module +-from test.support import os_helper + from test.support import requires_resource + from test.support import threading_helper + from http.client import HTTPException +@@ -414,21 +414,18 @@ + digests = [name] + digests.extend(self.constructors_to_test[name]) + +- with open(os_helper.TESTFN, "wb") as f: ++ with tempfile.TemporaryFile() as f: + f.write(data) + +- try: + for digest in digests: + buf = io.BytesIO(data) + buf.seek(0) + self.assertEqual( + hashlib.file_digest(buf, digest).hexdigest(), hexdigest + ) +- with open(os_helper.TESTFN, "rb") as f: +- digestobj = hashlib.file_digest(f, digest) ++ f.seek(0) ++ digestobj = hashlib.file_digest(f, digest) + self.assertEqual(digestobj.hexdigest(), hexdigest) +- finally: +- os.unlink(os_helper.TESTFN) + + def check_no_unicode(self, algorithm_name): + # Unicode objects are not allowed as input. +@@ -1172,29 +1169,29 @@ + def test_file_digest(self): + data = b'a' * 65536 + d1 = hashlib.sha256() +- self.addCleanup(os.unlink, os_helper.TESTFN) +- with open(os_helper.TESTFN, "wb") as f: ++ with tempfile.NamedTemporaryFile(delete_on_close=False) as fp: + for _ in range(10): + d1.update(data) +- f.write(data) ++ fp.write(data) ++ fp.close() + +- with open(os_helper.TESTFN, "rb") as f: +- d2 = hashlib.file_digest(f, hashlib.sha256) ++ with open(fp.name, "rb") as f: ++ d2 = hashlib.file_digest(f, hashlib.sha256) + +- self.assertEqual(d1.hexdigest(), d2.hexdigest()) +- self.assertEqual(d1.name, d2.name) +- self.assertIs(type(d1), type(d2)) ++ self.assertEqual(d1.hexdigest(), d2.hexdigest()) ++ self.assertEqual(d1.name, d2.name) ++ self.assertIs(type(d1), type(d2)) + +- with self.assertRaises(ValueError): +- hashlib.file_digest(None, "sha256") ++ with self.assertRaises(ValueError): ++ with open(fp.name, "r") as f: ++ hashlib.file_digest(f, "sha256") + +- with self.assertRaises(ValueError): +- with open(os_helper.TESTFN, "r") as f: +- hashlib.file_digest(f, "sha256") ++ with self.assertRaises(ValueError): ++ with open(fp.name, "wb") as f: ++ hashlib.file_digest(f, "sha256") + + with self.assertRaises(ValueError): +- with open(os_helper.TESTFN, "wb") as f: +- hashlib.file_digest(f, "sha256") ++ hashlib.file_digest(None, "sha256") + + + if __name__ == "__main__": +diff --git a/Lib/test/test_http_cookies.py b/Lib/test/test_http_cookies.py +index 7b3dc0fdaed..d945de23493 100644 +--- a/Lib/test/test_http_cookies.py ++++ b/Lib/test/test_http_cookies.py +@@ -205,6 +205,14 @@ + self.assertEqual(C.output(), + 'Set-Cookie: Customer="WILE_E_COYOTE"; HttpOnly; Secure') + ++ def test_set_secure_httponly_partitioned_attrs(self): ++ C = cookies.SimpleCookie('Customer="WILE_E_COYOTE"') ++ C['Customer']['secure'] = True ++ C['Customer']['httponly'] = True ++ C['Customer']['partitioned'] = True ++ self.assertEqual(C.output(), ++ 'Set-Cookie: Customer="WILE_E_COYOTE"; HttpOnly; Partitioned; Secure') ++ + def test_samesite_attrs(self): + samesite_values = ['Strict', 'Lax', 'strict', 'lax'] + for val in samesite_values: +diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py +index 9d853d254db..75b748aee05 100644 +--- a/Lib/test/test_httplib.py ++++ b/Lib/test/test_httplib.py +@@ -594,8 +594,9 @@ + CONTINUE = 100, 'Continue', 'Request received, please continue' + SWITCHING_PROTOCOLS = (101, 'Switching Protocols', + 'Switching to new protocol; obey Upgrade header') +- PROCESSING = 102, 'Processing' +- EARLY_HINTS = 103, 'Early Hints' ++ PROCESSING = 102, 'Processing', 'Server is processing the request' ++ EARLY_HINTS = (103, 'Early Hints', ++ 'Headers sent to prepare for the response') + # success + OK = 200, 'OK', 'Request fulfilled, document follows' + CREATED = 201, 'Created', 'Document created, URL follows' +@@ -606,9 +607,11 @@ + NO_CONTENT = 204, 'No Content', 'Request fulfilled, nothing follows' + RESET_CONTENT = 205, 'Reset Content', 'Clear input form for further input' + PARTIAL_CONTENT = 206, 'Partial Content', 'Partial content follows' +- MULTI_STATUS = 207, 'Multi-Status' +- ALREADY_REPORTED = 208, 'Already Reported' +- IM_USED = 226, 'IM Used' ++ MULTI_STATUS = (207, 'Multi-Status', ++ 'Response contains multiple statuses in the body') ++ ALREADY_REPORTED = (208, 'Already Reported', ++ 'Operation has already been reported') ++ IM_USED = 226, 'IM Used', 'Request completed using instance manipulations' + # redirection + MULTIPLE_CHOICES = (300, 'Multiple Choices', + 'Object has several resources -- see URI list') +@@ -665,15 +668,19 @@ + EXPECTATION_FAILED = (417, 'Expectation Failed', + 'Expect condition could not be satisfied') + IM_A_TEAPOT = (418, 'I\'m a Teapot', +- 'Server refuses to brew coffee because it is a teapot.') ++ 'Server refuses to brew coffee because it is a teapot') + MISDIRECTED_REQUEST = (421, 'Misdirected Request', + 'Server is not able to produce a response') +- UNPROCESSABLE_CONTENT = 422, 'Unprocessable Content' ++ UNPROCESSABLE_CONTENT = (422, 'Unprocessable Content', ++ 'Server is not able to process the contained instructions') + UNPROCESSABLE_ENTITY = UNPROCESSABLE_CONTENT +- LOCKED = 423, 'Locked' +- FAILED_DEPENDENCY = 424, 'Failed Dependency' +- TOO_EARLY = 425, 'Too Early' +- UPGRADE_REQUIRED = 426, 'Upgrade Required' ++ LOCKED = 423, 'Locked', 'Resource of a method is locked' ++ FAILED_DEPENDENCY = (424, 'Failed Dependency', ++ 'Dependent action of the request failed') ++ TOO_EARLY = (425, 'Too Early', ++ 'Server refuses to process a request that might be replayed') ++ UPGRADE_REQUIRED = (426, 'Upgrade Required', ++ 'Server refuses to perform the request using the current protocol') + PRECONDITION_REQUIRED = (428, 'Precondition Required', + 'The origin server requires the request to be conditional') + TOO_MANY_REQUESTS = (429, 'Too Many Requests', +@@ -700,10 +707,14 @@ + 'The gateway server did not receive a timely response') + HTTP_VERSION_NOT_SUPPORTED = (505, 'HTTP Version Not Supported', + 'Cannot fulfill request') +- VARIANT_ALSO_NEGOTIATES = 506, 'Variant Also Negotiates' +- INSUFFICIENT_STORAGE = 507, 'Insufficient Storage' +- LOOP_DETECTED = 508, 'Loop Detected' +- NOT_EXTENDED = 510, 'Not Extended' ++ VARIANT_ALSO_NEGOTIATES = (506, 'Variant Also Negotiates', ++ 'Server has an internal configuration error') ++ INSUFFICIENT_STORAGE = (507, 'Insufficient Storage', ++ 'Server is not able to store the representation') ++ LOOP_DETECTED = (508, 'Loop Detected', ++ 'Server encountered an infinite loop while processing a request') ++ NOT_EXTENDED = (510, 'Not Extended', ++ 'Request does not meet the resource access policy') + NETWORK_AUTHENTICATION_REQUIRED = (511, + 'Network Authentication Required', + 'The client needs to authenticate to gain network access') +@@ -1081,6 +1092,25 @@ + self.assertEqual(resp.read(), expected) + resp.close() + ++ # Explicit full read ++ for n in (-123, -1, None): ++ with self.subTest('full read', n=n): ++ sock = FakeSocket(chunked_start + last_chunk + chunked_end) ++ resp = client.HTTPResponse(sock, method="GET") ++ resp.begin() ++ self.assertTrue(resp.chunked) ++ self.assertEqual(resp.read(n), expected) ++ resp.close() ++ ++ # Read first chunk ++ with self.subTest('read1(-1)'): ++ sock = FakeSocket(chunked_start + last_chunk + chunked_end) ++ resp = client.HTTPResponse(sock, method="GET") ++ resp.begin() ++ self.assertTrue(resp.chunked) ++ self.assertEqual(resp.read1(-1), b"hello worl") ++ resp.close() ++ + # Various read sizes + for n in range(1, 12): + sock = FakeSocket(chunked_start + last_chunk + chunked_end) +@@ -2073,8 +2103,8 @@ + + def test_tls13_pha(self): + import ssl +- if not ssl.HAS_TLSv1_3: +- self.skipTest('TLS 1.3 support required') ++ if not ssl.HAS_TLSv1_3 or not ssl.HAS_PHA: ++ self.skipTest('TLS 1.3 PHA support required') + # just check status of PHA flag + h = client.HTTPSConnection('localhost', 443) + self.assertTrue(h._context.post_handshake_auth) +diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py +index a6509fc3ba0..a13ee58d650 100644 +--- a/Lib/test/test_imaplib.py ++++ b/Lib/test/test_imaplib.py +@@ -208,6 +208,54 @@ + self._send_tagged(tag, 'BAD', 'No mailbox selected') + + ++class IdleCmdDenyHandler(SimpleIMAPHandler): ++ capabilities = 'IDLE' ++ def cmd_IDLE(self, tag, args): ++ self._send_tagged(tag, 'NO', 'IDLE is not allowed at this time') ++ ++ ++class IdleCmdHandler(SimpleIMAPHandler): ++ capabilities = 'IDLE' ++ def cmd_IDLE(self, tag, args): ++ # pre-idle-continuation response ++ self._send_line(b'* 0 EXISTS') ++ self._send_textline('+ idling') ++ # simple response ++ self._send_line(b'* 2 EXISTS') ++ # complex response: fragmented data due to literal string ++ self._send_line(b'* 1 FETCH (BODY[HEADER.FIELDS (DATE)] {41}') ++ self._send(b'Date: Fri, 06 Dec 2024 06:00:00 +0000\r\n\r\n') ++ self._send_line(b')') ++ # simple response following a fragmented one ++ self._send_line(b'* 3 EXISTS') ++ # response arriving later ++ time.sleep(1) ++ self._send_line(b'* 1 RECENT') ++ r = yield ++ if r == b'DONE\r\n': ++ self._send_line(b'* 9 RECENT') ++ self._send_tagged(tag, 'OK', 'Idle completed') ++ else: ++ self._send_tagged(tag, 'BAD', 'Expected DONE') ++ ++ ++class IdleCmdDelayedPacketHandler(SimpleIMAPHandler): ++ capabilities = 'IDLE' ++ def cmd_IDLE(self, tag, args): ++ self._send_textline('+ idling') ++ # response line spanning multiple packets, the last one delayed ++ self._send(b'* 1 EX') ++ time.sleep(0.2) ++ self._send(b'IS') ++ time.sleep(1) ++ self._send(b'TS\r\n') ++ r = yield ++ if r == b'DONE\r\n': ++ self._send_tagged(tag, 'OK', 'Idle completed') ++ else: ++ self._send_tagged(tag, 'BAD', 'Expected DONE') ++ ++ + class NewIMAPTestsMixin(): + client = None + +@@ -497,6 +545,73 @@ + + # command tests + ++ def test_idle_capability(self): ++ client, _ = self._setup(SimpleIMAPHandler) ++ with self.assertRaisesRegex(imaplib.IMAP4.error, ++ 'does not support IMAP4 IDLE'): ++ with client.idle(): ++ pass ++ ++ def test_idle_denied(self): ++ client, _ = self._setup(IdleCmdDenyHandler) ++ client.login('user', 'pass') ++ with self.assertRaises(imaplib.IMAP4.error): ++ with client.idle() as idler: ++ pass ++ ++ def test_idle_iter(self): ++ client, _ = self._setup(IdleCmdHandler) ++ client.login('user', 'pass') ++ with client.idle() as idler: ++ # iteration should include response between 'IDLE' & '+ idling' ++ response = next(idler) ++ self.assertEqual(response, ('EXISTS', [b'0'])) ++ # iteration should produce responses ++ response = next(idler) ++ self.assertEqual(response, ('EXISTS', [b'2'])) ++ # fragmented response (with literal string) should arrive whole ++ expected_fetch_data = [ ++ (b'1 (BODY[HEADER.FIELDS (DATE)] {41}', ++ b'Date: Fri, 06 Dec 2024 06:00:00 +0000\r\n\r\n'), ++ b')'] ++ typ, data = next(idler) ++ self.assertEqual(typ, 'FETCH') ++ self.assertEqual(data, expected_fetch_data) ++ # response after a fragmented one should arrive separately ++ response = next(idler) ++ self.assertEqual(response, ('EXISTS', [b'3'])) ++ # iteration should have consumed untagged responses ++ _, data = client.response('EXISTS') ++ self.assertEqual(data, [None]) ++ # responses not iterated should be available after idle ++ _, data = client.response('RECENT') ++ self.assertEqual(data[0], b'1') ++ # responses received after 'DONE' should be available after idle ++ self.assertEqual(data[1], b'9') ++ ++ def test_idle_burst(self): ++ client, _ = self._setup(IdleCmdHandler) ++ client.login('user', 'pass') ++ # burst() should yield immediately available responses ++ with client.idle() as idler: ++ batch = list(idler.burst()) ++ self.assertEqual(len(batch), 4) ++ # burst() should not have consumed later responses ++ _, data = client.response('RECENT') ++ self.assertEqual(data, [b'1', b'9']) ++ ++ def test_idle_delayed_packet(self): ++ client, _ = self._setup(IdleCmdDelayedPacketHandler) ++ client.login('user', 'pass') ++ # If our readline() implementation fails to preserve line fragments ++ # when idle timeouts trigger, a response spanning delayed packets ++ # can be corrupted, leaving the protocol stream in a bad state. ++ try: ++ with client.idle(0.5) as idler: ++ self.assertRaises(StopIteration, next, idler) ++ except client.abort as err: ++ self.fail('multi-packet response was corrupted by idle timeout') ++ + def test_login(self): + client, _ = self._setup(SimpleIMAPHandler) + typ, data = client.login('user', 'pass') +@@ -537,6 +652,14 @@ + self.assertEqual(data[0], b'Returned to authenticated state. (Success)') + self.assertEqual(client.state, 'AUTH') + ++ # property tests ++ ++ def test_file_property_should_not_be_accessed(self): ++ client, _ = self._setup(SimpleIMAPHandler) ++ # the 'file' property replaced a private attribute that is now unsafe ++ with self.assertWarns(RuntimeWarning): ++ client.file ++ + + class NewIMAPTests(NewIMAPTestsMixin, unittest.TestCase): + imap_class = imaplib.IMAP4 +@@ -901,6 +1024,20 @@ + self.assertRaises(imaplib.IMAP4.error, + self.imap_class, *server.server_address) + ++ def test_truncated_large_literal(self): ++ size = 0 ++ class BadHandler(SimpleIMAPHandler): ++ def handle(self): ++ self._send_textline('* OK {%d}' % size) ++ self._send_textline('IMAP4rev1') ++ ++ for exponent in range(15, 64): ++ size = 1 << exponent ++ with self.subTest(f"size=2e{size}"): ++ with self.reaped_server(BadHandler) as server: ++ with self.assertRaises(imaplib.IMAP4.abort): ++ self.imap_class(*server.server_address) ++ + @threading_helper.reap_threads + def test_simple_with_statement(self): + # simplest call +diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py +index 83efbc1e25e..207b7ae7517 100644 +--- a/Lib/test/test_import/__init__.py ++++ b/Lib/test/test_import/__init__.py +@@ -29,9 +29,21 @@ + + from test.support import os_helper + from test.support import ( +- STDLIB_DIR, swap_attr, swap_item, cpython_only, is_apple_mobile, is_emscripten, +- is_wasi, run_in_subinterp, run_in_subinterp_with_config, Py_TRACE_REFS, +- requires_gil_enabled, Py_GIL_DISABLED, no_rerun) ++ STDLIB_DIR, ++ swap_attr, ++ swap_item, ++ cpython_only, ++ is_apple_mobile, ++ is_emscripten, ++ is_wasi, ++ run_in_subinterp, ++ run_in_subinterp_with_config, ++ Py_TRACE_REFS, ++ requires_gil_enabled, ++ Py_GIL_DISABLED, ++ no_rerun, ++ force_not_colorized_test_class, ++) + from test.support.import_helper import ( + forget, make_legacy_pyc, unlink, unload, ready_to_import, + DirsOnSysPath, CleanImport, import_module) +@@ -333,6 +345,7 @@ + return cls.parse(text.decode()) + + ++@force_not_colorized_test_class + class ImportTests(unittest.TestCase): + + def setUp(self): +@@ -539,7 +552,7 @@ + import test as x + import test.support + self.assertIs(x, test, x.__name__) +- self.assertTrue(hasattr(test.support, "__file__")) ++ self.assertHasAttr(test.support, "__file__") + + # import x.y.z as w binds z as w + import test.support as y +@@ -610,7 +623,7 @@ + sys.path.insert(0, os.curdir) + try: + mod = __import__(TESTFN) +- self.assertTrue(mod.__file__.endswith('.py')) ++ self.assertEndsWith(mod.__file__, '.py') + os.remove(source) + del sys.modules[TESTFN] + make_legacy_pyc(source) +@@ -851,6 +864,29 @@ + stdout, stderr = popen.communicate() + self.assertIn(expected_error, stdout) + ++ def test_non_module_from_import_error(self): ++ prefix = """ ++import sys ++class NotAModule: ... ++nm = NotAModule() ++nm.symbol = 123 ++sys.modules["not_a_module"] = nm ++from not_a_module import symbol ++""" ++ scripts = [ ++ prefix + "from not_a_module import missing_symbol", ++ prefix + "nm.__spec__ = []\nfrom not_a_module import missing_symbol", ++ ] ++ for script in scripts: ++ with self.subTest(script=script): ++ expected_error = ( ++ b"ImportError: cannot import name 'missing_symbol' from " ++ b"'' (unknown location)" ++ ) ++ popen = script_helper.spawn_python("-c", script) ++ stdout, stderr = popen.communicate() ++ self.assertIn(expected_error, stdout) ++ + def test_script_shadowing_stdlib(self): + script_errors = [ + ( +@@ -1420,7 +1456,7 @@ + self.fail("could not import 'test_unc_path' from %r: %r" + % (unc, e)) + self.assertEqual(mod.testdata, 'test_unc_path') +- self.assertTrue(mod.__file__.startswith(unc), mod.__file__) ++ self.assertStartsWith(mod.__file__, unc) + unload("test_unc_path") + + +@@ -1433,7 +1469,7 @@ + def test_relimport_star(self): + # This will import * from .test_import. + from .. import relimport +- self.assertTrue(hasattr(relimport, "RelativeImportTests")) ++ self.assertHasAttr(relimport, "RelativeImportTests") + + def test_issue3221(self): + # Note for mergers: the 'absolute' tests from the 2.x branch +@@ -1763,7 +1799,7 @@ + self.assertIs(mod, _bootstrap) + self.assertEqual(mod.__name__, 'importlib._bootstrap') + self.assertEqual(mod.__package__, 'importlib') +- self.assertTrue(mod.__file__.endswith('_bootstrap.py'), mod.__file__) ++ self.assertEndsWith(mod.__file__, '_bootstrap.py') + + def test_frozen_importlib_external_is_bootstrap_external(self): + from importlib import _bootstrap_external +@@ -1771,7 +1807,7 @@ + self.assertIs(mod, _bootstrap_external) + self.assertEqual(mod.__name__, 'importlib._bootstrap_external') + self.assertEqual(mod.__package__, 'importlib') +- self.assertTrue(mod.__file__.endswith('_bootstrap_external.py'), mod.__file__) ++ self.assertEndsWith(mod.__file__, '_bootstrap_external.py') + + def test_there_can_be_only_one(self): + # Issue #15386 revealed a tricky loophole in the bootstrapping +@@ -2777,7 +2813,7 @@ + self.assertEqual(mod.__file__, self.FILE) + self.assertEqual(mod.__spec__.origin, self.ORIGIN) + if not isolated: +- self.assertTrue(issubclass(mod.error, Exception)) ++ self.assertIsSubclass(mod.error, Exception) + self.assertEqual(mod.int_const, 1969) + self.assertEqual(mod.str_const, 'something different') + self.assertIsInstance(mod._module_initialized, float) +@@ -3288,30 +3324,6 @@ + # * module's global state was initialized, not reset + + +-@cpython_only +-class CAPITests(unittest.TestCase): +- def test_pyimport_addmodule(self): +- # gh-105922: Test PyImport_AddModuleRef(), PyImport_AddModule() +- # and PyImport_AddModuleObject() +- _testcapi = import_module("_testcapi") +- for name in ( +- 'sys', # frozen module +- 'test', # package +- __name__, # package.module +- ): +- _testcapi.check_pyimport_addmodule(name) +- +- def test_pyimport_addmodule_create(self): +- # gh-105922: Test PyImport_AddModuleRef(), create a new module +- _testcapi = import_module("_testcapi") +- name = 'dontexist' +- self.assertNotIn(name, sys.modules) +- self.addCleanup(unload, name) +- +- mod = _testcapi.check_pyimport_addmodule(name) +- self.assertIs(mod, sys.modules[name]) +- +- + @cpython_only + class TestMagicNumber(unittest.TestCase): + def test_magic_number_endianness(self): +diff --git a/Lib/test/test_importlib/extension/test_path_hook.py b/Lib/test/test_importlib/extension/test_path_hook.py +index 314a635c77e..941dcd5432c 100644 +--- a/Lib/test/test_importlib/extension/test_path_hook.py ++++ b/Lib/test/test_importlib/extension/test_path_hook.py +@@ -21,7 +21,7 @@ + def test_success(self): + # Path hook should handle a directory where a known extension module + # exists. +- self.assertTrue(hasattr(self.hook(util.EXTENSIONS.path), 'find_spec')) ++ self.assertHasAttr(self.hook(util.EXTENSIONS.path), 'find_spec') + + + (Frozen_PathHooksTests, +diff --git a/Lib/test/test_importlib/frozen/test_loader.py b/Lib/test/test_importlib/frozen/test_loader.py +index 1112c0664ad..c808bb73291 100644 +--- a/Lib/test/test_importlib/frozen/test_loader.py ++++ b/Lib/test/test_importlib/frozen/test_loader.py +@@ -61,7 +61,7 @@ + module.main() + + self.assertTrue(module.initialized) +- self.assertTrue(hasattr(module, '__spec__')) ++ self.assertHasAttr(module, '__spec__') + self.assertEqual(module.__spec__.origin, 'frozen') + return module, stdout.getvalue() + +@@ -72,7 +72,7 @@ + for attr, value in check.items(): + self.assertEqual(getattr(module, attr), value) + self.assertEqual(output, 'Hello world!\n') +- self.assertTrue(hasattr(module, '__spec__')) ++ self.assertHasAttr(module, '__spec__') + self.assertEqual(module.__spec__.loader_state.origname, name) + + def test_package(self): +@@ -136,7 +136,7 @@ + exec(code, mod.__dict__) + with captured_stdout() as stdout: + mod.main() +- self.assertTrue(hasattr(mod, 'initialized')) ++ self.assertHasAttr(mod, 'initialized') + self.assertEqual(stdout.getvalue(), 'Hello world!\n') + + def test_get_source(self): +diff --git a/Lib/test/test_importlib/import_/test_caching.py b/Lib/test/test_importlib/import_/test_caching.py +index aedf0fd4f9d..718e7d041b0 100644 +--- a/Lib/test/test_importlib/import_/test_caching.py ++++ b/Lib/test/test_importlib/import_/test_caching.py +@@ -78,7 +78,7 @@ + with self.create_mock('pkg.__init__', 'pkg.module') as importer: + with util.import_state(meta_path=[importer]): + module = self.__import__('pkg.module') +- self.assertTrue(hasattr(module, 'module')) ++ self.assertHasAttr(module, 'module') + self.assertEqual(id(module.module), + id(sys.modules['pkg.module'])) + +@@ -88,7 +88,7 @@ + with self.create_mock('pkg.__init__', 'pkg.module') as importer: + with util.import_state(meta_path=[importer]): + module = self.__import__('pkg', fromlist=['module']) +- self.assertTrue(hasattr(module, 'module')) ++ self.assertHasAttr(module, 'module') + self.assertEqual(id(module.module), + id(sys.modules['pkg.module'])) + +diff --git a/Lib/test/test_importlib/import_/test_fromlist.py b/Lib/test/test_importlib/import_/test_fromlist.py +index 4b4b9bc3f5e..feccc7be09a 100644 +--- a/Lib/test/test_importlib/import_/test_fromlist.py ++++ b/Lib/test/test_importlib/import_/test_fromlist.py +@@ -63,7 +63,7 @@ + with util.import_state(meta_path=[importer]): + module = self.__import__('module', fromlist=['non_existent']) + self.assertEqual(module.__name__, 'module') +- self.assertFalse(hasattr(module, 'non_existent')) ++ self.assertNotHasAttr(module, 'non_existent') + + def test_module_from_package(self): + # [module] +@@ -71,7 +71,7 @@ + with util.import_state(meta_path=[importer]): + module = self.__import__('pkg', fromlist=['module']) + self.assertEqual(module.__name__, 'pkg') +- self.assertTrue(hasattr(module, 'module')) ++ self.assertHasAttr(module, 'module') + self.assertEqual(module.module.__name__, 'pkg.module') + + def test_nonexistent_from_package(self): +@@ -79,7 +79,7 @@ + with util.import_state(meta_path=[importer]): + module = self.__import__('pkg', fromlist=['non_existent']) + self.assertEqual(module.__name__, 'pkg') +- self.assertFalse(hasattr(module, 'non_existent')) ++ self.assertNotHasAttr(module, 'non_existent') + + def test_module_from_package_triggers_ModuleNotFoundError(self): + # If a submodule causes an ModuleNotFoundError because it tries +@@ -107,7 +107,7 @@ + mock['pkg'].__all__ = ['module'] + module = self.__import__('pkg', fromlist=fromlist) + self.assertEqual(module.__name__, 'pkg') +- self.assertTrue(hasattr(module, 'module')) ++ self.assertHasAttr(module, 'module') + self.assertEqual(module.module.__name__, 'pkg.module') + + def test_using_star(self): +@@ -125,8 +125,8 @@ + mock['pkg'].__all__ = ['module1'] + module = self.__import__('pkg', fromlist=['module2', '*']) + self.assertEqual(module.__name__, 'pkg') +- self.assertTrue(hasattr(module, 'module1')) +- self.assertTrue(hasattr(module, 'module2')) ++ self.assertHasAttr(module, 'module1') ++ self.assertHasAttr(module, 'module2') + self.assertEqual(module.module1.__name__, 'pkg.module1') + self.assertEqual(module.module2.__name__, 'pkg.module2') + +@@ -136,7 +136,7 @@ + importer['pkg'].__all__ = ['non_existent'] + module = self.__import__('pkg', fromlist=['*']) + self.assertEqual(module.__name__, 'pkg') +- self.assertFalse(hasattr(module, 'non_existent')) ++ self.assertNotHasAttr(module, 'non_existent') + + def test_star_in_all(self): + with util.mock_spec('pkg.__init__') as importer: +@@ -144,7 +144,7 @@ + importer['pkg'].__all__ = ['*'] + module = self.__import__('pkg', fromlist=['*']) + self.assertEqual(module.__name__, 'pkg') +- self.assertFalse(hasattr(module, '*')) ++ self.assertNotHasAttr(module, '*') + + def test_invalid_type(self): + with util.mock_spec('pkg.__init__') as importer: +diff --git a/Lib/test/test_importlib/import_/test_meta_path.py b/Lib/test/test_importlib/import_/test_meta_path.py +index 8689017ba43..4c00f60681a 100644 +--- a/Lib/test/test_importlib/import_/test_meta_path.py ++++ b/Lib/test/test_importlib/import_/test_meta_path.py +@@ -43,7 +43,7 @@ + self.assertIsNone(importlib._bootstrap._find_spec('nothing', + None)) + self.assertEqual(len(w), 1) +- self.assertTrue(issubclass(w[-1].category, ImportWarning)) ++ self.assertIsSubclass(w[-1].category, ImportWarning) + + + (Frozen_CallingOrder, +diff --git a/Lib/test/test_importlib/import_/test_path.py b/Lib/test/test_importlib/import_/test_path.py +index 89b52fbd1e1..51ff6115e12 100644 +--- a/Lib/test/test_importlib/import_/test_path.py ++++ b/Lib/test/test_importlib/import_/test_path.py +@@ -1,3 +1,4 @@ ++from test.support import os_helper + from test.test_importlib import util + + importlib = util.import_importlib('importlib') +@@ -80,7 +81,7 @@ + self.assertIsNone(self.find('os')) + self.assertIsNone(sys.path_importer_cache[path_entry]) + self.assertEqual(len(w), 1) +- self.assertTrue(issubclass(w[-1].category, ImportWarning)) ++ self.assertIsSubclass(w[-1].category, ImportWarning) + + def test_path_importer_cache_empty_string(self): + # The empty string should create a finder using the cwd. +@@ -153,6 +154,28 @@ + # Do not want FileNotFoundError raised. + self.assertIsNone(self.machinery.PathFinder.find_spec('whatever')) + ++ @os_helper.skip_unless_working_chmod ++ def test_permission_error_cwd(self): ++ # gh-115911: Test that an unreadable CWD does not break imports, in ++ # particular during early stages of interpreter startup. ++ with ( ++ os_helper.temp_dir() as new_dir, ++ os_helper.save_mode(new_dir), ++ os_helper.change_cwd(new_dir), ++ util.import_state(path=['']), ++ ): ++ # chmod() is done here (inside the 'with' block) because the order ++ # of teardown operations cannot be the reverse of setup order. See ++ # https://github.com/python/cpython/pull/116131#discussion_r1739649390 ++ try: ++ os.chmod(new_dir, 0o000) ++ except OSError: ++ self.skipTest("platform does not allow " ++ "changing mode of the cwd") ++ ++ # Do not want PermissionError raised. ++ self.assertIsNone(self.machinery.PathFinder.find_spec('whatever')) ++ + def test_invalidate_caches_finders(self): + # Finders with an invalidate_caches() method have it called. + class FakeFinder: +diff --git a/Lib/test/test_importlib/import_/test_relative_imports.py b/Lib/test/test_importlib/import_/test_relative_imports.py +index 99c24f1fd94..e535d119763 100644 +--- a/Lib/test/test_importlib/import_/test_relative_imports.py ++++ b/Lib/test/test_importlib/import_/test_relative_imports.py +@@ -81,7 +81,7 @@ + self.__import__('pkg') # For __import__(). + module = self.__import__('', global_, fromlist=['mod2'], level=1) + self.assertEqual(module.__name__, 'pkg') +- self.assertTrue(hasattr(module, 'mod2')) ++ self.assertHasAttr(module, 'mod2') + self.assertEqual(module.mod2.attr, 'pkg.mod2') + self.relative_import_test(create, globals_, callback) + +@@ -107,7 +107,7 @@ + module = self.__import__('', global_, fromlist=['module'], + level=1) + self.assertEqual(module.__name__, 'pkg') +- self.assertTrue(hasattr(module, 'module')) ++ self.assertHasAttr(module, 'module') + self.assertEqual(module.module.attr, 'pkg.module') + self.relative_import_test(create, globals_, callback) + +@@ -131,7 +131,7 @@ + module = self.__import__('', global_, fromlist=['subpkg2'], + level=2) + self.assertEqual(module.__name__, 'pkg') +- self.assertTrue(hasattr(module, 'subpkg2')) ++ self.assertHasAttr(module, 'subpkg2') + self.assertEqual(module.subpkg2.attr, 'pkg.subpkg2.__init__') + self.relative_import_test(create, globals_, callback) + +diff --git a/Lib/test/test_importlib/resources/_path.py b/Lib/test/test_importlib/resources/_path.py +index 1f97c961469..b144628cb73 100644 +--- a/Lib/test/test_importlib/resources/_path.py ++++ b/Lib/test/test_importlib/resources/_path.py +@@ -2,15 +2,44 @@ + import functools + + from typing import Dict, Union ++from typing import runtime_checkable ++from typing import Protocol + + + #### +-# from jaraco.path 3.4.1 ++# from jaraco.path 3.7.1 + +-FilesSpec = Dict[str, Union[str, bytes, 'FilesSpec']] # type: ignore + ++class Symlink(str): ++ """ ++ A string indicating the target of a symlink. ++ """ ++ ++ ++FilesSpec = Dict[str, Union[str, bytes, Symlink, 'FilesSpec']] ++ ++ ++@runtime_checkable ++class TreeMaker(Protocol): ++ def __truediv__(self, *args, **kwargs): ... # pragma: no cover ++ ++ def mkdir(self, **kwargs): ... # pragma: no cover ++ ++ def write_text(self, content, **kwargs): ... # pragma: no cover ++ ++ def write_bytes(self, content): ... # pragma: no cover + +-def build(spec: FilesSpec, prefix=pathlib.Path()): ++ def symlink_to(self, target): ... # pragma: no cover ++ ++ ++def _ensure_tree_maker(obj: Union[str, TreeMaker]) -> TreeMaker: ++ return obj if isinstance(obj, TreeMaker) else pathlib.Path(obj) # type: ignore[return-value] ++ ++ ++def build( ++ spec: FilesSpec, ++ prefix: Union[str, TreeMaker] = pathlib.Path(), # type: ignore[assignment] ++): + """ + Build a set of files/directories, as described by the spec. + +@@ -25,21 +54,25 @@ + ... "__init__.py": "", + ... }, + ... "baz.py": "# Some code", +- ... } ++ ... "bar.py": Symlink("baz.py"), ++ ... }, ++ ... "bing": Symlink("foo"), + ... } + >>> target = getfixture('tmp_path') + >>> build(spec, target) + >>> target.joinpath('foo/baz.py').read_text(encoding='utf-8') + '# Some code' ++ >>> target.joinpath('bing/bar.py').read_text(encoding='utf-8') ++ '# Some code' + """ + for name, contents in spec.items(): +- create(contents, pathlib.Path(prefix) / name) ++ create(contents, _ensure_tree_maker(prefix) / name) + + + @functools.singledispatch + def create(content: Union[str, bytes, FilesSpec], path): + path.mkdir(exist_ok=True) +- build(content, prefix=path) # type: ignore ++ build(content, prefix=path) # type: ignore[arg-type] + + + @create.register +@@ -52,5 +85,10 @@ + path.write_text(content, encoding='utf-8') + + ++@create.register ++def _(content: Symlink, path): ++ path.symlink_to(content) ++ ++ + # end from jaraco.path + #### +diff --git a/Lib/test/test_importlib/resources/test_files.py b/Lib/test/test_importlib/resources/test_files.py +index 933894dce2c..db8a4e62a32 100644 +--- a/Lib/test/test_importlib/resources/test_files.py ++++ b/Lib/test/test_importlib/resources/test_files.py +@@ -60,6 +60,26 @@ + class OpenNamespaceTests(FilesTests, util.DiskSetup, unittest.TestCase): + MODULE = 'namespacedata01' + ++ def test_non_paths_in_dunder_path(self): ++ """ ++ Non-path items in a namespace package's ``__path__`` are ignored. ++ ++ As reported in python/importlib_resources#311, some tools ++ like Setuptools, when creating editable packages, will inject ++ non-paths into a namespace package's ``__path__``, a ++ sentinel like ++ ``__editable__.sample_namespace-1.0.finder.__path_hook__`` ++ to cause the ``PathEntryFinder`` to be called when searching ++ for packages. In that case, resources should still be loadable. ++ """ ++ import namespacedata01 ++ ++ namespacedata01.__path__.append( ++ '__editable__.sample_namespace-1.0.finder.__path_hook__' ++ ) ++ ++ resources.files(namespacedata01) ++ + + class OpenNamespaceZipTests(FilesTests, util.ZipSetup, unittest.TestCase): + ZIP_MODULE = 'namespacedata01' +@@ -86,7 +106,7 @@ + """ + A module can have resources found adjacent to the module. + """ +- import mod ++ import mod # type: ignore[import-not-found] + + actual = resources.files(mod).joinpath('res.txt').read_text(encoding='utf-8') + assert actual == self.spec['res.txt'] +diff --git a/Lib/test/test_importlib/resources/test_functional.py b/Lib/test/test_importlib/resources/test_functional.py +index 4317abf3162..e8d25fa4d9f 100644 +--- a/Lib/test/test_importlib/resources/test_functional.py ++++ b/Lib/test/test_importlib/resources/test_functional.py +@@ -43,12 +43,6 @@ + with self.subTest(path_parts=path_parts): + yield path_parts + +- def assertEndsWith(self, string, suffix): +- """Assert that `string` ends with `suffix`. +- +- Used to ignore an architecture-specific UTF-16 byte-order mark.""" +- self.assertEqual(string[-len(suffix) :], suffix) +- + def test_read_text(self): + self.assertEqual( + resources.read_text(self.anchor01, 'utf-8.file'), +diff --git a/Lib/test/test_importlib/resources/test_path.py b/Lib/test/test_importlib/resources/test_path.py +index 378dc7a2bae..903911f57b3 100644 +--- a/Lib/test/test_importlib/resources/test_path.py ++++ b/Lib/test/test_importlib/resources/test_path.py +@@ -20,7 +20,7 @@ + target = resources.files(self.data) / 'utf-8.file' + with resources.as_file(target) as path: + self.assertIsInstance(path, pathlib.Path) +- self.assertTrue(path.name.endswith("utf-8.file"), repr(path)) ++ self.assertEndsWith(path.name, "utf-8.file") + self.assertEqual('Hello, UTF-8 world!\n', path.read_text(encoding='utf-8')) + + +diff --git a/Lib/test/test_importlib/source/test_finder.py b/Lib/test/test_importlib/source/test_finder.py +index 8c06c4da1f5..4de736a6bf3 100644 +--- a/Lib/test/test_importlib/source/test_finder.py ++++ b/Lib/test/test_importlib/source/test_finder.py +@@ -73,7 +73,7 @@ + if error.errno != errno.ENOENT: + raise + loader = self.import_(mapping['.root'], test) +- self.assertTrue(hasattr(loader, 'load_module')) ++ self.assertHasAttr(loader, 'load_module') + return loader + + def test_module(self): +@@ -100,7 +100,7 @@ + with util.create_modules('pkg.__init__', 'pkg.sub') as mapping: + pkg_dir = os.path.dirname(mapping['pkg.__init__']) + loader = self.import_(pkg_dir, 'pkg.sub') +- self.assertTrue(hasattr(loader, 'load_module')) ++ self.assertHasAttr(loader, 'load_module') + + # [sub package] + def test_package_in_package(self): +@@ -108,7 +108,7 @@ + with context as mapping: + pkg_dir = os.path.dirname(mapping['pkg.__init__']) + loader = self.import_(pkg_dir, 'pkg.sub') +- self.assertTrue(hasattr(loader, 'load_module')) ++ self.assertHasAttr(loader, 'load_module') + + # [package over modules] + def test_package_over_module(self): +@@ -129,7 +129,7 @@ + file.write("# test file for importlib") + try: + loader = self._find(finder, 'mod', loader_only=True) +- self.assertTrue(hasattr(loader, 'load_module')) ++ self.assertHasAttr(loader, 'load_module') + finally: + os.unlink('mod.py') + +diff --git a/Lib/test/test_importlib/source/test_path_hook.py b/Lib/test/test_importlib/source/test_path_hook.py +index f274330e0b3..6e1c23e6a98 100644 +--- a/Lib/test/test_importlib/source/test_path_hook.py ++++ b/Lib/test/test_importlib/source/test_path_hook.py +@@ -15,12 +15,12 @@ + + def test_success(self): + with util.create_modules('dummy') as mapping: +- self.assertTrue(hasattr(self.path_hook()(mapping['.root']), +- 'find_spec')) ++ self.assertHasAttr(self.path_hook()(mapping['.root']), ++ 'find_spec') + + def test_empty_string(self): + # The empty string represents the cwd. +- self.assertTrue(hasattr(self.path_hook()(''), 'find_spec')) ++ self.assertHasAttr(self.path_hook()(''), 'find_spec') + + + (Frozen_PathHookTest, +diff --git a/Lib/test/test_importlib/test_abc.py b/Lib/test/test_importlib/test_abc.py +index 603125f6d92..b1ab52f966f 100644 +--- a/Lib/test/test_importlib/test_abc.py ++++ b/Lib/test/test_importlib/test_abc.py +@@ -43,14 +43,12 @@ + def test_subclasses(self): + # Test that the expected subclasses inherit. + for subclass in self.subclasses: +- self.assertTrue(issubclass(subclass, self.__test), +- "{0} is not a subclass of {1}".format(subclass, self.__test)) ++ self.assertIsSubclass(subclass, self.__test) + + def test_superclasses(self): + # Test that the class inherits from the expected superclasses. + for superclass in self.superclasses: +- self.assertTrue(issubclass(self.__test, superclass), +- "{0} is not a superclass of {1}".format(superclass, self.__test)) ++ self.assertIsSubclass(self.__test, superclass) + + + class MetaPathFinder(InheritanceTests): +@@ -226,7 +224,15 @@ + SPLIT = make_abc_subclasses(ResourceLoader) + + def test_get_data(self): +- with self.assertRaises(IOError): ++ with ( ++ self.assertRaises(IOError), ++ self.assertWarnsRegex( ++ DeprecationWarning, ++ r"importlib\.abc\.ResourceLoader is deprecated in favour of " ++ r"supporting resource loading through importlib\.resources" ++ r"\.abc\.TraversableResources.", ++ ), ++ ): + self.ins.get_data('/some/path') + + +@@ -416,14 +422,14 @@ + # Since compile() can handle strings, so should source_to_code(). + source = 'attr = 42' + module = self.source_to_module(source) +- self.assertTrue(hasattr(module, 'attr')) ++ self.assertHasAttr(module, 'attr') + self.assertEqual(module.attr, 42) + + def test_source_to_code_bytes(self): + # Since compile() can handle bytes, so should source_to_code(). + source = b'attr = 42' + module = self.source_to_module(source) +- self.assertTrue(hasattr(module, 'attr')) ++ self.assertHasAttr(module, 'attr') + self.assertEqual(module.attr, 42) + + def test_source_to_code_path(self): +@@ -757,7 +763,7 @@ + warnings.simplefilter('ignore', DeprecationWarning) + module = self.loader.load_module(self.name) + self.verify_module(module) +- self.assertFalse(hasattr(module, '__path__')) ++ self.assertNotHasAttr(module, '__path__') + + def test_get_source_encoding(self): + # Source is considered encoded in UTF-8 by default unless otherwise +@@ -913,5 +919,47 @@ + SourceOnlyLoaderMock=SPLIT_SOL) + + ++class SourceLoaderDeprecationWarningsTests(unittest.TestCase): ++ """Tests SourceLoader deprecation warnings.""" ++ ++ def test_deprecated_path_mtime(self): ++ from importlib.abc import SourceLoader ++ class DummySourceLoader(SourceLoader): ++ def get_data(self, path): ++ return b'' ++ ++ def get_filename(self, fullname): ++ return 'foo.py' ++ ++ def path_stats(self, path): ++ return {'mtime': 1} ++ with self.assertWarnsRegex( ++ DeprecationWarning, ++ r"importlib\.abc\.ResourceLoader is deprecated in favour of " ++ r"supporting resource loading through importlib\.resources" ++ r"\.abc\.TraversableResources.", ++ ): ++ loader = DummySourceLoader() ++ ++ with self.assertWarnsRegex( ++ DeprecationWarning, ++ r"SourceLoader\.path_mtime is deprecated in favour of " ++ r"SourceLoader\.path_stats\(\)\." ++ ): ++ loader.path_mtime('foo.py') ++ ++ ++class ResourceLoaderDeprecationWarningsTests(unittest.TestCase): ++ """Tests ResourceLoader deprecation warnings.""" ++ ++ def test_deprecated_resource_loader(self): ++ from importlib.abc import ResourceLoader ++ class DummyLoader(ResourceLoader): ++ def get_data(self, path): ++ return b'' ++ ++ with self.assertWarns(DeprecationWarning): ++ DummyLoader() ++ + if __name__ == '__main__': + unittest.main() +diff --git a/Lib/test/test_importlib/test_api.py b/Lib/test/test_importlib/test_api.py +index 51ea5270b1a..1bc531a2fe3 100644 +--- a/Lib/test/test_importlib/test_api.py ++++ b/Lib/test/test_importlib/test_api.py +@@ -430,8 +430,7 @@ + for name, module in sys.modules.items(): + if isinstance(module, types.ModuleType): + with self.subTest(name=name): +- self.assertTrue(hasattr(module, '__loader__'), +- '{!r} lacks a __loader__ attribute'.format(name)) ++ self.assertHasAttr(module, '__loader__') + if self.machinery.BuiltinImporter.find_spec(name): + self.assertIsNot(module.__loader__, None) + elif self.machinery.FrozenImporter.find_spec(name): +@@ -441,7 +440,7 @@ + for name, module in sys.modules.items(): + if isinstance(module, types.ModuleType): + with self.subTest(name=name): +- self.assertTrue(hasattr(module, '__spec__')) ++ self.assertHasAttr(module, '__spec__') + if self.machinery.BuiltinImporter.find_spec(name): + self.assertIsNot(module.__spec__, None) + elif self.machinery.FrozenImporter.find_spec(name): +@@ -492,5 +491,18 @@ + support.check__all__(self, util['Source'], extra=extra) + + ++class TestDeprecations(unittest.TestCase): ++ def test_machinery_deprecated_attributes(self): ++ from importlib import machinery ++ attributes = ( ++ 'DEBUG_BYTECODE_SUFFIXES', ++ 'OPTIMIZED_BYTECODE_SUFFIXES', ++ ) ++ for attr in attributes: ++ with self.subTest(attr=attr): ++ with self.assertWarns(DeprecationWarning): ++ getattr(machinery, attr) ++ ++ + if __name__ == '__main__': + unittest.main() +diff --git a/Lib/test/test_importlib/test_lazy.py b/Lib/test/test_importlib/test_lazy.py +index 5c6e0303528..e48fad8898f 100644 +--- a/Lib/test/test_importlib/test_lazy.py ++++ b/Lib/test/test_importlib/test_lazy.py +@@ -125,12 +125,12 @@ + # Deleting an attribute should stay deleted. + module = self.new_module() + del module.attr +- self.assertFalse(hasattr(module, 'attr')) ++ self.assertNotHasAttr(module, 'attr') + + def test_delete_preexisting_attr(self): + module = self.new_module() + del module.__name__ +- self.assertFalse(hasattr(module, '__name__')) ++ self.assertNotHasAttr(module, '__name__') + + def test_module_substitution_error(self): + with test_util.uncache(TestingImporter.module_name): +diff --git a/Lib/test/test_importlib/test_namespace_pkgs.py b/Lib/test/test_importlib/test_namespace_pkgs.py +index cbbdada3b01..6ca0978f9bc 100644 +--- a/Lib/test/test_importlib/test_namespace_pkgs.py ++++ b/Lib/test/test_importlib/test_namespace_pkgs.py +@@ -80,7 +80,7 @@ + + def test_simple_repr(self): + import foo.one +- self.assertTrue(repr(foo).startswith("sp\xc3\xa4m\x00') + ++ @patch('socket.socket') ++ def test_tcp_timeout(self, mock_socket): ++ instance_mock_sock = mock_socket.return_value ++ instance_mock_sock.connect.side_effect = socket.timeout ++ ++ with self.assertRaises(socket.timeout): ++ logging.handlers.SysLogHandler(address=('localhost', 514), ++ socktype=socket.SOCK_STREAM, ++ timeout=1) ++ ++ instance_mock_sock.close.assert_called() ++ + @unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required") + class UnixSysLogHandlerTest(SysLogHandlerTest): + +@@ -3524,7 +3537,7 @@ + self.assertEqual(h.foo, 'bar') + self.assertEqual(h.terminator, '!\n') + logging.warning('Exclamation') +- self.assertTrue(output.getvalue().endswith('Exclamation!\n')) ++ self.assertEndsWith(output.getvalue(), 'Exclamation!\n') + + def test_config15_ok(self): + +@@ -4281,7 +4294,7 @@ + msg = self.next_message() + self.que_logger.warning(msg) + data = self.queue.get_nowait() +- self.assertTrue(isinstance(data, logging.LogRecord)) ++ self.assertIsInstance(data, logging.LogRecord) + self.assertEqual(data.name, self.que_logger.name) + self.assertEqual((data.msg, data.args), (msg, None)) + +@@ -4879,14 +4892,14 @@ + r.removeHandler(h) + h.close() + r = h.records[0] +- self.assertTrue(r.exc_text.startswith('Traceback (most recent ' +- 'call last):\n')) +- self.assertTrue(r.exc_text.endswith('\nRuntimeError: ' +- 'deliberate mistake')) +- self.assertTrue(r.stack_info.startswith('Stack (most recent ' +- 'call last):\n')) +- self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', ' +- 'stack_info=True)')) ++ self.assertStartsWith(r.exc_text, ++ 'Traceback (most recent call last):\n') ++ self.assertEndsWith(r.exc_text, ++ '\nRuntimeError: deliberate mistake') ++ self.assertStartsWith(r.stack_info, ++ 'Stack (most recent call last):\n') ++ self.assertEndsWith(r.stack_info, ++ "logging.exception('failed', stack_info=True)") + + + class LastResortTest(BaseTest): +@@ -5229,8 +5242,8 @@ + def test_str_rep(self): + r = logging.makeLogRecord({}) + s = str(r) +- self.assertTrue(s.startswith('')) ++ self.assertStartsWith(s, '') + + def test_dict_arg(self): + h = RecordingHandler() +@@ -5352,7 +5365,7 @@ + logging.logAsyncioTasks = False + runner.run(make_record(self.assertIsNone)) + finally: +- asyncio.set_event_loop_policy(None) ++ asyncio._set_event_loop_policy(None) + + @support.requires_working_socket() + def test_taskName_without_asyncio_imported(self): +@@ -5364,7 +5377,7 @@ + logging.logAsyncioTasks = False + runner.run(make_record(self.assertIsNone)) + finally: +- asyncio.set_event_loop_policy(None) ++ asyncio._set_event_loop_policy(None) + + + class BasicConfigTest(unittest.TestCase): +@@ -5668,7 +5681,7 @@ + data = f.read().strip() + self.assertRegex(data, r'Task-\d+ - hello world') + finally: +- asyncio.set_event_loop_policy(None) ++ asyncio._set_event_loop_policy(None) + if handler: + handler.close() + +@@ -5880,14 +5893,14 @@ + self.adapter.critical('foo should be here') + self.assertEqual(len(self.recording.records), 1) + record = self.recording.records[0] +- self.assertTrue(hasattr(record, 'foo')) ++ self.assertHasAttr(record, 'foo') + self.assertEqual(record.foo, '1') + + def test_extra_not_merged_by_default(self): + self.adapter.critical('foo should NOT be here', extra={'foo': 'nope'}) + self.assertEqual(len(self.recording.records), 1) + record = self.recording.records[0] +- self.assertFalse(hasattr(record, 'foo')) ++ self.assertNotHasAttr(record, 'foo') + + def test_extra_merged(self): + self.adapter = logging.LoggerAdapter(logger=self.logger, +@@ -5897,8 +5910,8 @@ + self.adapter.critical('foo and bar should be here', extra={'bar': '2'}) + self.assertEqual(len(self.recording.records), 1) + record = self.recording.records[0] +- self.assertTrue(hasattr(record, 'foo')) +- self.assertTrue(hasattr(record, 'bar')) ++ self.assertHasAttr(record, 'foo') ++ self.assertHasAttr(record, 'bar') + self.assertEqual(record.foo, '1') + self.assertEqual(record.bar, '2') + +@@ -5910,7 +5923,7 @@ + self.adapter.critical('foo shall be min', extra={'foo': '2'}) + self.assertEqual(len(self.recording.records), 1) + record = self.recording.records[0] +- self.assertTrue(hasattr(record, 'foo')) ++ self.assertHasAttr(record, 'foo') + self.assertEqual(record.foo, '2') + + +@@ -6624,18 +6637,19 @@ + p = '%s.log.' % prefix + for c in candidates: + d, fn = os.path.split(c) +- self.assertTrue(fn.startswith(p)) ++ self.assertStartsWith(fn, p) + elif prefix.startswith('d.e'): + for c in candidates: + d, fn = os.path.split(c) +- self.assertTrue(fn.endswith('.log'), fn) +- self.assertTrue(fn.startswith(prefix + '.') and +- fn[len(prefix) + 2].isdigit()) ++ self.assertEndsWith(fn, '.log') ++ self.assertStartsWith(fn, prefix + '.') ++ self.assertTrue(fn[len(prefix) + 2].isdigit()) + elif prefix == 'g': + for c in candidates: + d, fn = os.path.split(c) +- self.assertTrue(fn.endswith('.oldlog')) +- self.assertTrue(fn.startswith('g') and fn[1].isdigit()) ++ self.assertEndsWith(fn, '.oldlog') ++ self.assertStartsWith(fn, 'g') ++ self.assertTrue(fn[1].isdigit()) + + def test_compute_files_to_delete_same_filename_different_extensions(self): + # See GH-93205 for background +@@ -6673,7 +6687,7 @@ + matcher = re.compile(r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}\Z") + for c in candidates: + d, fn = os.path.split(c) +- self.assertTrue(fn.startswith(prefix+'.')) ++ self.assertStartsWith(fn, prefix+'.') + suffix = fn[(len(prefix)+1):] + self.assertRegex(suffix, matcher) + +diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py +index 19978118c80..f336d49fa4f 100644 +--- a/Lib/test/test_long.py ++++ b/Lib/test/test_long.py +@@ -1470,7 +1470,6 @@ + b'\x00': 0, + b'\x00\x00': 0, + b'\x01': 1, +- b'\x00\x01': 256, + b'\xff': -1, + b'\xff\xff': -1, + b'\x81': -127, +diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py +index 6976a5d85da..2c57d288bc0 100644 +--- a/Lib/test/test_math.py ++++ b/Lib/test/test_math.py +@@ -2503,6 +2503,46 @@ + self.assertRaises(TypeError, math.atan2, 1.0) + self.assertRaises(TypeError, math.atan2, 1.0, 2.0, 3.0) + ++ def test_exception_messages(self): ++ x = -1.1 ++ with self.assertRaisesRegex(ValueError, ++ f"expected a nonnegative input, got {x}"): ++ math.sqrt(x) ++ with self.assertRaisesRegex(ValueError, ++ f"expected a positive input, got {x}"): ++ math.log(x) ++ with self.assertRaisesRegex(ValueError, ++ f"expected a positive input, got {x}"): ++ math.log(123, x) ++ with self.assertRaisesRegex(ValueError, ++ f"expected a positive input, got {x}"): ++ math.log(x, 123) ++ with self.assertRaisesRegex(ValueError, ++ f"expected a positive input, got {x}"): ++ math.log2(x) ++ with self.assertRaisesRegex(ValueError, ++ f"expected a positive input, got {x}"): ++ math.log10(x) ++ x = decimal.Decimal('-1.1') ++ with self.assertRaisesRegex(ValueError, ++ f"expected a positive input, got {x}"): ++ math.log(x) ++ x = fractions.Fraction(1, 10**400) ++ with self.assertRaisesRegex(ValueError, ++ f"expected a positive input, got {float(x)}"): ++ math.log(x) ++ x = -123 ++ with self.assertRaisesRegex(ValueError, ++ f"expected a positive input, got {x}"): ++ math.log(x) ++ with self.assertRaisesRegex(ValueError, ++ f"expected a float or nonnegative integer, got {x}"): ++ math.gamma(x) ++ x = 1.0 ++ with self.assertRaisesRegex(ValueError, ++ f"expected a number between -1 and 1, got {x}"): ++ math.atanh(x) ++ + # Custom assertions. + + def assertIsNaN(self, value): +diff --git a/Lib/test/test_metaclass.py b/Lib/test/test_metaclass.py +index b37b7defe84..07a333f98fa 100644 +--- a/Lib/test/test_metaclass.py ++++ b/Lib/test/test_metaclass.py +@@ -254,6 +254,33 @@ + [...] + test.test_metaclass.ObscureException + ++Test setting attributes with a non-base type in mro() (gh-127773). ++ ++ >>> class Base: ++ ... value = 1 ++ ... ++ >>> class Meta(type): ++ ... def mro(cls): ++ ... return (cls, Base, object) ++ ... ++ >>> class WeirdClass(metaclass=Meta): ++ ... pass ++ ... ++ >>> Base.value ++ 1 ++ >>> WeirdClass.value ++ 1 ++ >>> Base.value = 2 ++ >>> Base.value ++ 2 ++ >>> WeirdClass.value ++ 2 ++ >>> Base.value = 3 ++ >>> Base.value ++ 3 ++ >>> WeirdClass.value ++ 3 ++ + """ + + import sys +diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py +index 5a4bcebedf1..3125d190626 100644 +--- a/Lib/test/test_monitoring.py ++++ b/Lib/test/test_monitoring.py +@@ -12,9 +12,9 @@ + + import test.support + from test.support import requires_specialization_ft, script_helper +-from test.support.import_helper import import_module + + _testcapi = test.support.import_helper.import_module("_testcapi") ++_testinternalcapi = test.support.import_helper.import_module("_testinternalcapi") + + PAIR = (0,1) + +@@ -850,12 +850,6 @@ + def __call__(self, code, offset, val): + self.events.append(("return", code.co_name, val)) + +-# gh-127274: CALL_ALLOC_AND_ENTER_INIT will only cache __init__ methods that +-# are deferred. We only defer functions defined at the top-level. +-class ValueErrorRaiser: +- def __init__(self): +- raise ValueError() +- + + class ExceptionMonitoringTest(CheckEvents): + +@@ -904,13 +898,13 @@ + # re-specialize immediately, so that we can we can test the + # unspecialized version of the loop first. + # Note: this assumes that we don't specialize loops over sets. +- implicit_stop_iteration(set(range(100))) ++ implicit_stop_iteration(set(range(_testinternalcapi.SPECIALIZATION_THRESHOLD))) + + # This will record a RAISE event for the StopIteration. + self.check_events(implicit_stop_iteration, expected, recorders=recorders) + + # Now specialize, so that we see a STOP_ITERATION event. +- for _ in range(100): ++ for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN): + implicit_stop_iteration() + + # This will record a STOP_ITERATION event for the StopIteration. +@@ -1054,6 +1048,9 @@ + + @requires_specialization_ft + def test_no_unwind_for_shim_frame(self): ++ class ValueErrorRaiser: ++ def __init__(self): ++ raise ValueError() + + def f(): + try: +@@ -1061,7 +1058,7 @@ + except ValueError: + pass + +- for _ in range(100): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + f() + recorders = ( + ReturnRecorder, +@@ -1491,7 +1488,15 @@ + event_type = E.BRANCH + name = "branch" + ++class BranchRightRecorder(JumpRecorder): ++ ++ event_type = E.BRANCH_RIGHT ++ name = "branch right" ++ ++class BranchLeftRecorder(JumpRecorder): + ++ event_type = E.BRANCH_LEFT ++ name = "branch left" + + class JumpOffsetRecorder: + +@@ -1504,16 +1509,23 @@ + def __call__(self, code, from_, to): + self.events.append((self.name, code.co_name, from_, to)) + +-class BranchOffsetRecorder(JumpOffsetRecorder): ++class BranchLeftOffsetRecorder(JumpOffsetRecorder): + +- event_type = E.BRANCH +- name = "branch" ++ event_type = E.BRANCH_LEFT ++ name = "branch left" ++ ++class BranchRightOffsetRecorder(JumpOffsetRecorder): ++ ++ event_type = E.BRANCH_RIGHT ++ name = "branch right" + + + JUMP_AND_BRANCH_RECORDERS = JumpRecorder, BranchRecorder + JUMP_BRANCH_AND_LINE_RECORDERS = JumpRecorder, BranchRecorder, LineRecorder + FLOW_AND_LINE_RECORDERS = JumpRecorder, BranchRecorder, LineRecorder, ExceptionRecorder, ReturnRecorder +-BRANCH_OFFSET_RECORDERS = BranchOffsetRecorder, ++ ++BRANCHES_RECORDERS = BranchLeftRecorder, BranchRightRecorder ++BRANCH_OFFSET_RECORDERS = BranchLeftOffsetRecorder, BranchRightOffsetRecorder + + class TestBranchAndJumpEvents(CheckEvents): + maxDiff = None +@@ -1529,6 +1541,11 @@ + x = 6 + 7 + ++ def whilefunc(n=0): ++ while n < 3: ++ n += 1 # line 2 ++ 3 ++ + self.check_events(func, recorders = JUMP_AND_BRANCH_RECORDERS, expected = [ + ('branch', 'func', 2, 2), + ('branch', 'func', 3, 6), +@@ -1558,6 +1575,26 @@ + ('line', 'func', 7), + ('line', 'get_events', 11)]) + ++ self.check_events(func, recorders = BRANCHES_RECORDERS, expected = [ ++ ('branch left', 'func', 2, 2), ++ ('branch right', 'func', 3, 6), ++ ('branch left', 'func', 2, 2), ++ ('branch left', 'func', 3, 4), ++ ('branch right', 'func', 2, 7)]) ++ ++ self.check_events(whilefunc, recorders = BRANCHES_RECORDERS, expected = [ ++ ('branch left', 'whilefunc', 1, 2), ++ ('branch left', 'whilefunc', 1, 2), ++ ('branch left', 'whilefunc', 1, 2), ++ ('branch right', 'whilefunc', 1, 3)]) ++ ++ self.check_events(func, recorders = BRANCH_OFFSET_RECORDERS, expected = [ ++ ('branch left', 'func', 28, 32), ++ ('branch right', 'func', 44, 58), ++ ('branch left', 'func', 28, 32), ++ ('branch left', 'func', 44, 50), ++ ('branch right', 'func', 28, 70)]) ++ + def test_except_star(self): + + class Foo: +@@ -1583,8 +1620,8 @@ + ('branch', 'func', 4, 4), + ('line', 'func', 5), + ('line', 'meth', 1), +- ('jump', 'func', 5, '[offset=118]'), +- ('branch', 'func', '[offset=122]', '[offset=126]'), ++ ('jump', 'func', 5, '[offset=120]'), ++ ('branch', 'func', '[offset=124]', '[offset=130]'), + ('line', 'get_events', 11)]) + + self.check_events(func, recorders = FLOW_AND_LINE_RECORDERS, expected = [ +@@ -1598,8 +1635,8 @@ + ('line', 'func', 5), + ('line', 'meth', 1), + ('return', 'meth', None), +- ('jump', 'func', 5, '[offset=118]'), +- ('branch', 'func', '[offset=122]', '[offset=126]'), ++ ('jump', 'func', 5, '[offset=120]'), ++ ('branch', 'func', '[offset=124]', '[offset=130]'), + ('return', 'func', None), + ('line', 'get_events', 11)]) + +@@ -1611,8 +1648,8 @@ + n += 1 + return None + +- in_loop = ('branch', 'foo', 10, 14) +- exit_loop = ('branch', 'foo', 10, 30) ++ in_loop = ('branch left', 'foo', 10, 16) ++ exit_loop = ('branch right', 'foo', 10, 40) + self.check_events(foo, recorders = BRANCH_OFFSET_RECORDERS, expected = [ + in_loop, + in_loop, +@@ -1621,6 +1658,88 @@ + exit_loop]) + + ++class TestBranchConsistency(MonitoringTestBase, unittest.TestCase): ++ ++ def check_branches(self, func, tool=TEST_TOOL, recorders=BRANCH_OFFSET_RECORDERS): ++ try: ++ self.assertEqual(sys.monitoring._all_events(), {}) ++ event_list = [] ++ all_events = 0 ++ for recorder in recorders: ++ ev = recorder.event_type ++ sys.monitoring.register_callback(tool, ev, recorder(event_list)) ++ all_events |= ev ++ sys.monitoring.set_local_events(tool, func.__code__, all_events) ++ func() ++ sys.monitoring.set_local_events(tool, func.__code__, 0) ++ for recorder in recorders: ++ sys.monitoring.register_callback(tool, recorder.event_type, None) ++ lefts = set() ++ rights = set() ++ for (src, left, right) in func.__code__.co_branches(): ++ lefts.add((src, left)) ++ rights.add((src, right)) ++ for event in event_list: ++ way, _, src, dest = event ++ if "left" in way: ++ self.assertIn((src, dest), lefts) ++ else: ++ self.assertIn("right", way) ++ self.assertIn((src, dest), rights) ++ finally: ++ sys.monitoring.set_local_events(tool, func.__code__, 0) ++ for recorder in recorders: ++ sys.monitoring.register_callback(tool, recorder.event_type, None) ++ ++ def test_simple(self): ++ ++ def func(): ++ x = 1 ++ for a in range(2): ++ if a: ++ x = 4 ++ else: ++ x = 6 ++ 7 ++ ++ self.check_branches(func) ++ ++ def whilefunc(n=0): ++ while n < 3: ++ n += 1 # line 2 ++ 3 ++ ++ self.check_branches(whilefunc) ++ ++ def test_except_star(self): ++ ++ class Foo: ++ def meth(self): ++ pass ++ ++ def func(): ++ try: ++ try: ++ raise KeyError ++ except* Exception as e: ++ f = Foo(); f.meth() ++ except KeyError: ++ pass ++ ++ ++ self.check_branches(func) ++ ++ def test4(self): ++ ++ def foo(n=0): ++ while n<4: ++ pass ++ n += 1 ++ return None ++ ++ self.check_branches(foo) ++ ++ + class TestLoadSuperAttr(CheckEvents): + RECORDERS = CallRecorder, LineRecorder, CRaiseRecorder, CReturnRecorder + +@@ -1852,6 +1971,10 @@ + code = f1.__code__ + sys.monitoring.set_local_events(TEST_TOOL, code, E.PY_START) + self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL, code), E.PY_START) ++ sys.monitoring.set_local_events(TEST_TOOL, code, 0) ++ sys.monitoring.set_local_events(TEST_TOOL, code, E.BRANCH) ++ self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL, code), E.BRANCH_LEFT | E.BRANCH_RIGHT) ++ sys.monitoring.set_local_events(TEST_TOOL, code, 0) + sys.monitoring.set_local_events(TEST_TOOL2, code, E.PY_START) + self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL2, code), E.PY_START) + sys.monitoring.set_local_events(TEST_TOOL, code, 0) +@@ -1911,8 +2034,8 @@ + sys.monitoring.set_events(TEST_TOOL, E.PY_RESUME) + + def make_foo_optimized_then_set_event(): +- for i in range(100): +- Foo(i == 99) ++ for i in range(_testinternalcapi.SPECIALIZATION_THRESHOLD + 1): ++ Foo(i == _testinternalcapi.SPECIALIZATION_THRESHOLD) + + try: + make_foo_optimized_then_set_event() +@@ -1964,20 +2087,6 @@ + + class TestOptimizer(MonitoringTestBase, unittest.TestCase): + +- def setUp(self): +- _testinternalcapi = import_module("_testinternalcapi") +- if hasattr(_testinternalcapi, "get_optimizer"): +- self.old_opt = _testinternalcapi.get_optimizer() +- opt = _testinternalcapi.new_counter_optimizer() +- _testinternalcapi.set_optimizer(opt) +- super(TestOptimizer, self).setUp() +- +- def tearDown(self): +- super(TestOptimizer, self).tearDown() +- import _testinternalcapi +- if hasattr(_testinternalcapi, "get_optimizer"): +- _testinternalcapi.set_optimizer(self.old_opt) +- + def test_for_loop(self): + def test_func(x): + i = 0 +@@ -1998,9 +2107,9 @@ + set_events = sys.monitoring.set_events + line = E.LINE + i = 0 +- for i in range(551): +- # Turn on events without branching once i reaches 500. +- set_events(TEST_TOOL, line * int(i >= 500)) ++ for i in range(_testinternalcapi.SPECIALIZATION_THRESHOLD + 51): ++ # Turn on events without branching once i reaches _testinternalcapi.SPECIALIZATION_THRESHOLD. ++ set_events(TEST_TOOL, line * int(i >= _testinternalcapi.SPECIALIZATION_THRESHOLD)) + pass + pass + pass +@@ -2053,7 +2162,8 @@ + ( 1, E.PY_RETURN, capi.fire_event_py_return, 20), + ( 2, E.CALL, capi.fire_event_call, callable, 40), + ( 1, E.JUMP, capi.fire_event_jump, 60), +- ( 1, E.BRANCH, capi.fire_event_branch, 70), ++ ( 1, E.BRANCH_RIGHT, capi.fire_event_branch_right, 70), ++ ( 1, E.BRANCH_LEFT, capi.fire_event_branch_left, 80), + ( 1, E.PY_THROW, capi.fire_event_py_throw, ValueError(1)), + ( 1, E.RAISE, capi.fire_event_raise, ValueError(2)), + ( 1, E.EXCEPTION_HANDLED, capi.fire_event_exception_handled, ValueError(5)), +diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py +index 6715071af8c..da01c65a1c2 100644 +--- a/Lib/test/test_ntpath.py ++++ b/Lib/test/test_ntpath.py +@@ -940,7 +940,7 @@ + self.assertRaises(TypeError, ntpath.commonpath, ['C:\\Foo', b'Foo\\Baz']) + self.assertRaises(TypeError, ntpath.commonpath, ['Foo', b'C:\\Foo\\Baz']) + +- @unittest.skipIf(is_emscripten, "Emscripten cannot fstat unnamed files.") ++ @unittest.skipIf(is_emscripten, "Fixed in next Emscripten release after 4.0.1") + def test_sameopenfile(self): + with TemporaryFile() as tf1, TemporaryFile() as tf2: + # Make sure the same file is really the same +diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py +index 0a7557adc47..e4224b843b2 100644 +--- a/Lib/test/test_opcache.py ++++ b/Lib/test/test_opcache.py +@@ -6,7 +6,7 @@ + import unittest + from test.support import (threading_helper, check_impl_detail, + requires_specialization, requires_specialization_ft, +- cpython_only) ++ cpython_only, requires_jit_disabled, reset_code) + from test.support.import_helper import import_module + + # Skip this module on other interpreters, it is cpython specific: +@@ -16,20 +16,6 @@ + _testinternalcapi = import_module("_testinternalcapi") + + +-def disabling_optimizer(func): +- def wrapper(*args, **kwargs): +- if not hasattr(_testinternalcapi, "get_optimizer"): +- return func(*args, **kwargs) +- old_opt = _testinternalcapi.get_optimizer() +- _testinternalcapi.set_optimizer(None) +- try: +- return func(*args, **kwargs) +- finally: +- _testinternalcapi.set_optimizer(old_opt) +- +- return wrapper +- +- + class TestBase(unittest.TestCase): + def assert_specialized(self, f, opname): + instructions = dis.get_instructions(f, adaptive=True) +@@ -59,7 +45,8 @@ + + d = D() + +- self.assertEqual(d.f(), 1) # warmup ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD - 1): ++ self.assertEqual(d.f(), 1) # warmup + calls.clear() + self.assertEqual(d.f(), 1) # try to specialize + self.assertEqual(calls, [(d, D)]) +@@ -79,7 +66,7 @@ + return o.x + + o = C() +- for i in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + assert f(o) == 1 + + Descriptor.__get__ = lambda self, instance, value: 2 +@@ -106,13 +93,13 @@ + def f(): + return Class.attribute + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + self.assertTrue(f()) + + Descriptor.__get__ = __get__ + Descriptor.__set__ = __set__ + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN): + self.assertFalse(f()) + + def test_metaclass_descriptor_shadows_class_attribute(self): +@@ -127,7 +114,7 @@ + def f(): + return Class.attribute + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + self.assertTrue(f()) + + def test_metaclass_set_descriptor_after_optimization(self): +@@ -144,12 +131,12 @@ + def f(): + return Class.attribute + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + self.assertTrue(f()) + + Metaclass.attribute = attribute + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN): + self.assertFalse(f()) + + def test_metaclass_del_descriptor_after_optimization(self): +@@ -164,12 +151,12 @@ + def f(): + return Class.attribute + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + self.assertTrue(f()) + + del Metaclass.attribute + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN): + self.assertFalse(f()) + + def test_type_descriptor_shadows_attribute_method(self): +@@ -179,7 +166,7 @@ + def f(): + return Class.mro + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + self.assertIsNone(f()) + + def test_type_descriptor_shadows_attribute_member(self): +@@ -189,7 +176,7 @@ + def f(): + return Class.__base__ + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + self.assertIs(f(), object) + + def test_type_descriptor_shadows_attribute_getset(self): +@@ -199,7 +186,7 @@ + def f(): + return Class.__name__ + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + self.assertEqual(f(), "Class") + + def test_metaclass_getattribute(self): +@@ -213,7 +200,7 @@ + def f(): + return Class.attribute + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + self.assertTrue(f()) + + def test_metaclass_swap(self): +@@ -233,12 +220,12 @@ + def f(): + return Class.attribute + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + self.assertTrue(f()) + + Class.__class__ = NewMetaclass + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN): + self.assertFalse(f()) + + def test_load_shadowing_slot_should_raise_type_error(self): +@@ -255,7 +242,7 @@ + o = Sneaky() + o.shadowed = 42 + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + with self.assertRaises(TypeError): + f(o) + +@@ -272,7 +259,7 @@ + + o = Sneaky() + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + with self.assertRaises(TypeError): + f(o) + +@@ -288,7 +275,7 @@ + + o = Sneaky() + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + with self.assertRaises(TypeError): + f(o) + +@@ -304,7 +291,7 @@ + + o = Sneaky() + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + with self.assertRaises(TypeError): + f(o) + +@@ -332,13 +319,13 @@ + def f(): + return instance.attribute() + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + self.assertTrue(f()) + + Descriptor.__get__ = __get__ + Descriptor.__set__ = __set__ + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN): + self.assertFalse(f()) + + def test_metaclass_descriptor_added_after_optimization(self): +@@ -361,13 +348,13 @@ + def f(): + return Class.attribute() + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + self.assertTrue(f()) + + Descriptor.__get__ = __get__ + Descriptor.__set__ = __set__ + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN): + self.assertFalse(f()) + + def test_metaclass_descriptor_shadows_class_attribute(self): +@@ -383,7 +370,7 @@ + def f(): + return Class.attribute() + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + self.assertTrue(f()) + + def test_metaclass_set_descriptor_after_optimization(self): +@@ -401,12 +388,12 @@ + def f(): + return Class.attribute() + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + self.assertTrue(f()) + + Metaclass.attribute = attribute + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN): + self.assertFalse(f()) + + def test_metaclass_del_descriptor_after_optimization(self): +@@ -422,12 +409,12 @@ + def f(): + return Class.attribute() + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + self.assertTrue(f()) + + del Metaclass.attribute + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN): + self.assertFalse(f()) + + def test_type_descriptor_shadows_attribute_method(self): +@@ -438,7 +425,7 @@ + def f(): + return Class.mro() + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + self.assertEqual(f(), ["Spam", "eggs"]) + + def test_type_descriptor_shadows_attribute_member(self): +@@ -449,7 +436,7 @@ + def f(): + return Class.__base__() + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + self.assertNotEqual(f(), "Spam") + + def test_metaclass_getattribute(self): +@@ -464,7 +451,7 @@ + def f(): + return Class.attribute() + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + self.assertTrue(f()) + + def test_metaclass_swap(self): +@@ -484,22 +471,15 @@ + def f(): + return Class.attribute() + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + self.assertTrue(f()) + + Class.__class__ = NewMetaclass + +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN): + self.assertFalse(f()) + + +-# gh-127274: CALL_ALLOC_AND_ENTER_INIT will only cache __init__ methods that +-# are deferred. We only defer functions defined at the top-level. +-class MyClass: +- def __init__(self): +- pass +- +- + class InitTakesArg: + def __init__(self, arg): + self.arg = arg +@@ -511,7 +491,7 @@ + pass + + f.__defaults__ = (None,) +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + f() + + def test_too_many_defaults_1(self): +@@ -519,7 +499,7 @@ + pass + + f.__defaults__ = (None, None) +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + f(None) + f() + +@@ -528,19 +508,23 @@ + pass + + f.__defaults__ = (None, None, None) +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + f(None, None) + f(None) + f() + +- @disabling_optimizer ++ @requires_jit_disabled + @requires_specialization_ft + def test_assign_init_code(self): ++ class MyClass: ++ def __init__(self): ++ pass ++ + def instantiate(): + return MyClass() + + # Trigger specialization +- for _ in range(1025): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + instantiate() + self.assert_specialized(instantiate, "CALL_ALLOC_AND_ENTER_INIT") + +@@ -552,13 +536,13 @@ + MyClass.__init__.__code__ = count_args.__code__ + instantiate() + +- @disabling_optimizer ++ @requires_jit_disabled + @requires_specialization_ft + def test_push_init_frame_fails(self): + def instantiate(): + return InitTakesArg() + +- for _ in range(2): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + with self.assertRaises(TypeError): + instantiate() + self.assert_specialized(instantiate, "CALL_ALLOC_AND_ENTER_INIT") +@@ -567,16 +551,25 @@ + instantiate() + + ++def make_deferred_ref_count_obj(): ++ """Create an object that uses deferred reference counting. ++ ++ Only objects that use deferred refence counting may be stored in inline ++ caches in free-threaded builds. This constructs a new class named Foo, ++ which uses deferred reference counting. ++ """ ++ return type("Foo", (object,), {}) ++ ++ + @threading_helper.requires_working_threading() + class TestRacesDoNotCrash(TestBase): + # Careful with these. Bigger numbers have a higher chance of catching bugs, + # but you can also burn through a *ton* of type/dict/function versions: + ITEMS = 1000 + LOOPS = 4 +- WARMUPS = 2 + WRITERS = 2 + +- @disabling_optimizer ++ @requires_jit_disabled + def assert_races_do_not_crash( + self, opname, get_items, read, write, *, check_items=False + ): +@@ -586,11 +579,11 @@ + # Reset: + if check_items: + for item in items: +- item.__code__ = item.__code__.replace() ++ reset_code(item) + else: +- read.__code__ = read.__code__.replace() ++ reset_code(read) + # Specialize: +- for _ in range(self.WARMUPS): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + read(items) + if check_items: + for item in items: +@@ -609,7 +602,7 @@ + for writer in writers: + writer.join() + +- @requires_specialization ++ @requires_specialization_ft + def test_binary_subscr_getitem(self): + def get_items(): + class C: +@@ -636,7 +629,7 @@ + pass + type(item).__getitem__ = lambda self, item: None + +- opname = "BINARY_SUBSCR_GETITEM" ++ opname = "BINARY_OP_SUBSCR_GETITEM" + self.assert_races_do_not_crash(opname, get_items, read, write) + + @requires_specialization_ft +@@ -660,7 +653,7 @@ + item.clear() + item.append(None) + +- opname = "BINARY_SUBSCR_LIST_INT" ++ opname = "BINARY_OP_SUBSCR_LIST_INT" + self.assert_races_do_not_crash(opname, get_items, read, write) + + @requires_specialization +@@ -717,11 +710,11 @@ + opname = "FOR_ITER_LIST" + self.assert_races_do_not_crash(opname, get_items, read, write) + +- @requires_specialization ++ @requires_specialization_ft + def test_load_attr_class(self): + def get_items(): + class C: +- a = object() ++ a = make_deferred_ref_count_obj() + + items = [] + for _ in range(self.ITEMS): +@@ -742,12 +735,45 @@ + del item.a + except AttributeError: + pass +- item.a = object() ++ item.a = make_deferred_ref_count_obj() + + opname = "LOAD_ATTR_CLASS" + self.assert_races_do_not_crash(opname, get_items, read, write) + +- @requires_specialization ++ @requires_specialization_ft ++ def test_load_attr_class_with_metaclass_check(self): ++ def get_items(): ++ class Meta(type): ++ pass ++ ++ class C(metaclass=Meta): ++ a = make_deferred_ref_count_obj() ++ ++ items = [] ++ for _ in range(self.ITEMS): ++ item = C ++ items.append(item) ++ return items ++ ++ def read(items): ++ for item in items: ++ try: ++ item.a ++ except AttributeError: ++ pass ++ ++ def write(items): ++ for item in items: ++ try: ++ del item.a ++ except AttributeError: ++ pass ++ item.a = make_deferred_ref_count_obj() ++ ++ opname = "LOAD_ATTR_CLASS_WITH_METACLASS_CHECK" ++ self.assert_races_do_not_crash(opname, get_items, read, write) ++ ++ @requires_specialization_ft + def test_load_attr_getattribute_overridden(self): + def get_items(): + class C: +@@ -777,7 +803,7 @@ + opname = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN" + self.assert_races_do_not_crash(opname, get_items, read, write) + +- @requires_specialization ++ @requires_specialization_ft + def test_load_attr_instance_value(self): + def get_items(): + class C: +@@ -801,7 +827,7 @@ + opname = "LOAD_ATTR_INSTANCE_VALUE" + self.assert_races_do_not_crash(opname, get_items, read, write) + +- @requires_specialization ++ @requires_specialization_ft + def test_load_attr_method_lazy_dict(self): + def get_items(): + class C(Exception): +@@ -831,7 +857,7 @@ + opname = "LOAD_ATTR_METHOD_LAZY_DICT" + self.assert_races_do_not_crash(opname, get_items, read, write) + +- @requires_specialization ++ @requires_specialization_ft + def test_load_attr_method_no_dict(self): + def get_items(): + class C: +@@ -862,7 +888,7 @@ + opname = "LOAD_ATTR_METHOD_NO_DICT" + self.assert_races_do_not_crash(opname, get_items, read, write) + +- @requires_specialization ++ @requires_specialization_ft + def test_load_attr_method_with_values(self): + def get_items(): + class C: +@@ -917,7 +943,7 @@ + opname = "LOAD_ATTR_MODULE" + self.assert_races_do_not_crash(opname, get_items, read, write) + +- @requires_specialization ++ @requires_specialization_ft + def test_load_attr_property(self): + def get_items(): + class C: +@@ -947,7 +973,34 @@ + opname = "LOAD_ATTR_PROPERTY" + self.assert_races_do_not_crash(opname, get_items, read, write) + +- @requires_specialization ++ @requires_specialization_ft ++ def test_load_attr_slot(self): ++ def get_items(): ++ class C: ++ __slots__ = ["a", "b"] ++ ++ items = [] ++ for i in range(self.ITEMS): ++ item = C() ++ item.a = i ++ item.b = i + self.ITEMS ++ items.append(item) ++ return items ++ ++ def read(items): ++ for item in items: ++ item.a ++ item.b ++ ++ def write(items): ++ for item in items: ++ item.a = 100 ++ item.b = 200 ++ ++ opname = "LOAD_ATTR_SLOT" ++ self.assert_races_do_not_crash(opname, get_items, read, write) ++ ++ @requires_specialization_ft + def test_load_attr_with_hint(self): + def get_items(): + class C: +@@ -958,7 +1011,7 @@ + item = C() + item.a = None + # Resize into a combined unicode dict: +- for i in range(29): ++ for i in range(_testinternalcapi.SHARED_KEYS_MAX_SIZE - 1): + setattr(item, f"_{i}", None) + items.append(item) + return items +@@ -1029,7 +1082,7 @@ + for _ in range(self.ITEMS): + item = C() + # Resize into a combined unicode dict: +- for i in range(29): ++ for i in range(_testinternalcapi.SHARED_KEYS_MAX_SIZE - 1): + setattr(item, f"_{i}", None) + items.append(item) + return items +@@ -1069,7 +1122,7 @@ + opname = "STORE_SUBSCR_LIST_INT" + self.assert_races_do_not_crash(opname, get_items, read, write) + +- @requires_specialization ++ @requires_specialization_ft + def test_unpack_sequence_list(self): + def get_items(): + items = [] +@@ -1125,7 +1178,7 @@ + c.a = 1 + c.b = 2 + c.__dict__ +- for _ in range(100): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + c.a + self.assertEqual( + _testinternalcapi.get_object_dict_values(c), +@@ -1137,7 +1190,7 @@ + c.a = 1 + c.b = 2 + d = c.__dict__ +- for _ in range(100): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + c.a + self.assertIs(c.__dict__, d) + +@@ -1146,7 +1199,7 @@ + c.a = 1 + c.b = 2 + c2 = copy.copy(c) +- for _ in range(100): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + c.a + c2.a + self.assertEqual( +@@ -1158,7 +1211,7 @@ + (1, 2, '') + ) + c3 = copy.deepcopy(c) +- for _ in range(100): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + c.a + c3.a + self.assertEqual( +@@ -1172,7 +1225,7 @@ + c.a = 1 + c.b = 2 + c2 = pickle.loads(pickle.dumps(c)) +- for _ in range(100): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + c.a + c2.a + self.assertEqual( +@@ -1190,7 +1243,7 @@ + c.a = 1 + c.b = 2 + c.__dict__ = D(c.__dict__) +- for _ in range(100): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + c.a + self.assertIs( + _testinternalcapi.get_object_dict_values(c), +@@ -1235,7 +1288,7 @@ + for i in range(n): + o.b = i + # Prime f to store to dict slot 1 +- f(c, 100) ++ f(c, _testinternalcapi.SPECIALIZATION_THRESHOLD) + + test_obj = NoInlineAorB() + test_obj.__dict__ = make_special_dict() +@@ -1252,7 +1305,7 @@ + @requires_specialization_ft + def test_binary_op(self): + def binary_op_add_int(): +- for _ in range(100): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + a, b = 1, 2 + c = a + b + self.assertEqual(c, 3) +@@ -1262,7 +1315,7 @@ + self.assert_no_opcode(binary_op_add_int, "BINARY_OP") + + def binary_op_add_unicode(): +- for _ in range(100): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + a, b = "foo", "bar" + c = a + b + self.assertEqual(c, "foobar") +@@ -1271,6 +1324,103 @@ + self.assert_specialized(binary_op_add_unicode, "BINARY_OP_ADD_UNICODE") + self.assert_no_opcode(binary_op_add_unicode, "BINARY_OP") + ++ def binary_op_add_extend(): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): ++ a, b = 6, 3.0 ++ c = a + b ++ self.assertEqual(c, 9.0) ++ c = b + a ++ self.assertEqual(c, 9.0) ++ c = a - b ++ self.assertEqual(c, 3.0) ++ c = b - a ++ self.assertEqual(c, -3.0) ++ c = a * b ++ self.assertEqual(c, 18.0) ++ c = b * a ++ self.assertEqual(c, 18.0) ++ c = a / b ++ self.assertEqual(c, 2.0) ++ c = b / a ++ self.assertEqual(c, 0.5) ++ ++ binary_op_add_extend() ++ self.assert_specialized(binary_op_add_extend, "BINARY_OP_EXTEND") ++ self.assert_no_opcode(binary_op_add_extend, "BINARY_OP") ++ ++ def binary_op_zero_division(): ++ def compactlong_lhs(arg): ++ 42 / arg ++ def float_lhs(arg): ++ 42.0 / arg ++ ++ with self.assertRaises(ZeroDivisionError): ++ compactlong_lhs(0) ++ with self.assertRaises(ZeroDivisionError): ++ compactlong_lhs(0.0) ++ with self.assertRaises(ZeroDivisionError): ++ float_lhs(0.0) ++ with self.assertRaises(ZeroDivisionError): ++ float_lhs(0) ++ ++ self.assert_no_opcode(compactlong_lhs, "BINARY_OP_EXTEND") ++ self.assert_no_opcode(float_lhs, "BINARY_OP_EXTEND") ++ ++ binary_op_zero_division() ++ ++ def binary_op_nan(): ++ def compactlong_lhs(arg): ++ return ( ++ 42 + arg, ++ 42 - arg, ++ 42 * arg, ++ 42 / arg, ++ ) ++ def compactlong_rhs(arg): ++ return ( ++ arg + 42, ++ arg - 42, ++ arg * 2, ++ arg / 42, ++ ) ++ nan = float('nan') ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): ++ self.assertEqual(compactlong_lhs(1.0), (43.0, 41.0, 42.0, 42.0)) ++ for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN): ++ self.assertTrue(all(filter(lambda x: x is nan, compactlong_lhs(nan)))) ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): ++ self.assertEqual(compactlong_rhs(42.0), (84.0, 0.0, 84.0, 1.0)) ++ for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN): ++ self.assertTrue(all(filter(lambda x: x is nan, compactlong_rhs(nan)))) ++ ++ self.assert_no_opcode(compactlong_lhs, "BINARY_OP_EXTEND") ++ self.assert_no_opcode(compactlong_rhs, "BINARY_OP_EXTEND") ++ ++ binary_op_nan() ++ ++ def binary_op_bitwise_extend(): ++ for _ in range(100): ++ a, b = 2, 7 ++ x = a | b ++ self.assertEqual(x, 7) ++ y = a & b ++ self.assertEqual(y, 2) ++ z = a ^ b ++ self.assertEqual(z, 5) ++ a, b = 3, 9 ++ a |= b ++ self.assertEqual(a, 11) ++ a, b = 11, 9 ++ a &= b ++ self.assertEqual(a, 9) ++ a, b = 3, 9 ++ a ^= b ++ self.assertEqual(a, 10) ++ ++ binary_op_bitwise_extend() ++ self.assert_specialized(binary_op_bitwise_extend, "BINARY_OP_EXTEND") ++ self.assert_no_opcode(binary_op_bitwise_extend, "BINARY_OP") ++ + @cpython_only + @requires_specialization_ft + def test_load_super_attr(self): +@@ -1281,7 +1431,7 @@ + meth = super().__init__ + super().__init__() + +- for _ in range(100): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + A() + + self.assert_specialized(A.__init__, "LOAD_SUPER_ATTR_ATTR") +@@ -1301,7 +1451,7 @@ + globals()['super'] = fake_super + try: + # Should be unspecialized after enough calls. +- for _ in range(100): ++ for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN): + A() + finally: + globals()['super'] = real_super +@@ -1314,7 +1464,7 @@ + @requires_specialization_ft + def test_contain_op(self): + def contains_op_dict(): +- for _ in range(100): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + a, b = 1, {1: 2, 2: 5} + self.assertTrue(a in b) + self.assertFalse(3 in b) +@@ -1324,7 +1474,7 @@ + self.assert_no_opcode(contains_op_dict, "CONTAINS_OP") + + def contains_op_set(): +- for _ in range(100): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + a, b = 1, {1, 2} + self.assertTrue(a in b) + self.assertFalse(3 in b) +@@ -1351,7 +1501,7 @@ + pass + + async def send_with(): +- for i in range(100): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + async with CM(): + x = 1 + +@@ -1369,25 +1519,94 @@ + def send_yield_from(): + yield from g() + +- for i in range(100): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + list(send_yield_from()) + + self.assert_specialized(send_yield_from, "SEND_GEN") + self.assert_no_opcode(send_yield_from, "SEND") + ++ @cpython_only ++ @requires_specialization_ft ++ def test_store_attr_slot(self): ++ class C: ++ __slots__ = ['x'] ++ ++ def set_slot(n): ++ c = C() ++ for i in range(n): ++ c.x = i ++ ++ set_slot(_testinternalcapi.SPECIALIZATION_THRESHOLD) ++ ++ self.assert_specialized(set_slot, "STORE_ATTR_SLOT") ++ self.assert_no_opcode(set_slot, "STORE_ATTR") ++ ++ # Adding a property for 'x' should unspecialize it. ++ C.x = property(lambda self: None, lambda self, x: None) ++ set_slot(_testinternalcapi.SPECIALIZATION_COOLDOWN) ++ self.assert_no_opcode(set_slot, "STORE_ATTR_SLOT") ++ ++ @cpython_only ++ @requires_specialization_ft ++ def test_store_attr_instance_value(self): ++ class C: ++ pass ++ ++ @reset_code ++ def set_value(n): ++ c = C() ++ for i in range(n): ++ c.x = i ++ ++ set_value(_testinternalcapi.SPECIALIZATION_THRESHOLD) ++ ++ self.assert_specialized(set_value, "STORE_ATTR_INSTANCE_VALUE") ++ self.assert_no_opcode(set_value, "STORE_ATTR") ++ ++ # Adding a property for 'x' should unspecialize it. ++ C.x = property(lambda self: None, lambda self, x: None) ++ set_value(_testinternalcapi.SPECIALIZATION_COOLDOWN) ++ self.assert_no_opcode(set_value, "STORE_ATTR_INSTANCE_VALUE") ++ ++ @cpython_only ++ @requires_specialization_ft ++ def test_store_attr_with_hint(self): ++ class C: ++ pass ++ ++ c = C() ++ for i in range(_testinternalcapi.SHARED_KEYS_MAX_SIZE - 1): ++ setattr(c, f"_{i}", None) ++ ++ @reset_code ++ def set_value(n): ++ for i in range(n): ++ c.x = i ++ ++ set_value(_testinternalcapi.SPECIALIZATION_THRESHOLD) ++ ++ self.assert_specialized(set_value, "STORE_ATTR_WITH_HINT") ++ self.assert_no_opcode(set_value, "STORE_ATTR") ++ ++ # Adding a property for 'x' should unspecialize it. ++ C.x = property(lambda self: None, lambda self, x: None) ++ set_value(_testinternalcapi.SPECIALIZATION_COOLDOWN) ++ self.assert_no_opcode(set_value, "STORE_ATTR_WITH_HINT") ++ + @cpython_only + @requires_specialization_ft + def test_to_bool(self): + def to_bool_bool(): + true_cnt, false_cnt = 0, 0 +- elems = [e % 2 == 0 for e in range(100)] ++ elems = [e % 2 == 0 for e in range(_testinternalcapi.SPECIALIZATION_THRESHOLD)] + for e in elems: + if e: + true_cnt += 1 + else: + false_cnt += 1 +- self.assertEqual(true_cnt, 50) +- self.assertEqual(false_cnt, 50) ++ d, m = divmod(_testinternalcapi.SPECIALIZATION_THRESHOLD, 2) ++ self.assertEqual(true_cnt, d + m) ++ self.assertEqual(false_cnt, d) + + to_bool_bool() + self.assert_specialized(to_bool_bool, "TO_BOOL_BOOL") +@@ -1395,12 +1614,12 @@ + + def to_bool_int(): + count = 0 +- for i in range(100): ++ for i in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + if i: + count += 1 + else: + count -= 1 +- self.assertEqual(count, 98) ++ self.assertEqual(count, _testinternalcapi.SPECIALIZATION_THRESHOLD - 2) + + to_bool_int() + self.assert_specialized(to_bool_int, "TO_BOOL_INT") +@@ -1408,11 +1627,11 @@ + + def to_bool_list(): + count = 0 +- elems = [1, 2, 3] ++ elems = list(range(_testinternalcapi.SPECIALIZATION_THRESHOLD)) + while elems: + count += elems.pop() + self.assertEqual(elems, []) +- self.assertEqual(count, 6) ++ self.assertEqual(count, sum(range(_testinternalcapi.SPECIALIZATION_THRESHOLD))) + + to_bool_list() + self.assert_specialized(to_bool_list, "TO_BOOL_LIST") +@@ -1420,11 +1639,11 @@ + + def to_bool_none(): + count = 0 +- elems = [None, None, None, None] ++ elems = [None] * _testinternalcapi.SPECIALIZATION_THRESHOLD + for e in elems: + if not e: + count += 1 +- self.assertEqual(count, len(elems)) ++ self.assertEqual(count, _testinternalcapi.SPECIALIZATION_THRESHOLD) + + to_bool_none() + self.assert_specialized(to_bool_none, "TO_BOOL_NONE") +@@ -1432,11 +1651,11 @@ + + def to_bool_str(): + count = 0 +- elems = ["", "foo", ""] ++ elems = [""] + ["foo"] * (_testinternalcapi.SPECIALIZATION_THRESHOLD - 1) + for e in elems: + if e: + count += 1 +- self.assertEqual(count, 1) ++ self.assertEqual(count, _testinternalcapi.SPECIALIZATION_THRESHOLD - 1) + + to_bool_str() + self.assert_specialized(to_bool_str, "TO_BOOL_STR") +@@ -1446,7 +1665,7 @@ + @requires_specialization_ft + def test_unpack_sequence(self): + def unpack_sequence_two_tuple(): +- for _ in range(100): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + a, b = 1, 2 + self.assertEqual(a, 1) + self.assertEqual(b, 2) +@@ -1457,7 +1676,7 @@ + self.assert_no_opcode(unpack_sequence_two_tuple, "UNPACK_SEQUENCE") + + def unpack_sequence_tuple(): +- for _ in range(100): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + a, = 1, + self.assertEqual(a, 1) + +@@ -1466,7 +1685,7 @@ + self.assert_no_opcode(unpack_sequence_tuple, "UNPACK_SEQUENCE") + + def unpack_sequence_list(): +- for _ in range(100): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + a, b = [1, 2] + self.assertEqual(a, 1) + self.assertEqual(b, 2) +@@ -1479,47 +1698,109 @@ + @requires_specialization_ft + def test_binary_subscr(self): + def binary_subscr_list_int(): +- for _ in range(100): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + a = [1, 2, 3] + for idx, expected in enumerate(a): + self.assertEqual(a[idx], expected) + + binary_subscr_list_int() + self.assert_specialized(binary_subscr_list_int, +- "BINARY_SUBSCR_LIST_INT") ++ "BINARY_OP_SUBSCR_LIST_INT") + self.assert_no_opcode(binary_subscr_list_int, "BINARY_SUBSCR") + + def binary_subscr_tuple_int(): +- for _ in range(100): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + a = (1, 2, 3) + for idx, expected in enumerate(a): + self.assertEqual(a[idx], expected) + + binary_subscr_tuple_int() + self.assert_specialized(binary_subscr_tuple_int, +- "BINARY_SUBSCR_TUPLE_INT") ++ "BINARY_OP_SUBSCR_TUPLE_INT") + self.assert_no_opcode(binary_subscr_tuple_int, "BINARY_SUBSCR") + + def binary_subscr_dict(): +- for _ in range(100): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + a = {1: 2, 2: 3} + self.assertEqual(a[1], 2) + self.assertEqual(a[2], 3) + + binary_subscr_dict() +- self.assert_specialized(binary_subscr_dict, "BINARY_SUBSCR_DICT") +- self.assert_no_opcode(binary_subscr_dict, "BINARY_SUBSCR") ++ self.assert_specialized(binary_subscr_dict, "BINARY_OP_SUBSCR_DICT") ++ self.assert_no_opcode(binary_subscr_dict, "BINARY_OP") + + def binary_subscr_str_int(): +- for _ in range(100): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + a = "foobar" + for idx, expected in enumerate(a): + self.assertEqual(a[idx], expected) + + binary_subscr_str_int() +- self.assert_specialized(binary_subscr_str_int, "BINARY_SUBSCR_STR_INT") ++ self.assert_specialized(binary_subscr_str_int, "BINARY_OP_SUBSCR_STR_INT") + self.assert_no_opcode(binary_subscr_str_int, "BINARY_SUBSCR") + ++ def binary_subscr_getitems(): ++ class C: ++ def __init__(self, val): ++ self.val = val ++ def __getitem__(self, item): ++ return self.val ++ ++ items = [C(i) for i in range(_testinternalcapi.SPECIALIZATION_THRESHOLD)] ++ for i in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): ++ self.assertEqual(items[i][i], i) ++ ++ binary_subscr_getitems() ++ self.assert_specialized(binary_subscr_getitems, "BINARY_OP_SUBSCR_GETITEM") ++ self.assert_no_opcode(binary_subscr_getitems, "BINARY_SUBSCR") ++ ++ @cpython_only ++ @requires_specialization_ft ++ def test_compare_op(self): ++ def compare_op_int(): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): ++ a, b = 1, 2 ++ c = a == b ++ self.assertFalse(c) ++ ++ compare_op_int() ++ self.assert_specialized(compare_op_int, "COMPARE_OP_INT") ++ self.assert_no_opcode(compare_op_int, "COMPARE_OP") ++ ++ def compare_op_float(): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): ++ a, b = 1.0, 2.0 ++ c = a == b ++ self.assertFalse(c) ++ ++ compare_op_float() ++ self.assert_specialized(compare_op_float, "COMPARE_OP_FLOAT") ++ self.assert_no_opcode(compare_op_float, "COMPARE_OP") ++ ++ def compare_op_str(): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): ++ a, b = "spam", "ham" ++ c = a == b ++ self.assertFalse(c) ++ ++ compare_op_str() ++ self.assert_specialized(compare_op_str, "COMPARE_OP_STR") ++ self.assert_no_opcode(compare_op_str, "COMPARE_OP") ++ ++ @cpython_only ++ @requires_specialization_ft ++ def test_load_const(self): ++ def load_const(): ++ def unused(): pass ++ # Currently, the empty tuple is immortal, and the otherwise ++ # unused nested function's code object is mortal. This test will ++ # have to use different values if either of that changes. ++ return () ++ ++ load_const() ++ self.assert_specialized(load_const, "LOAD_CONST_IMMORTAL") ++ self.assert_specialized(load_const, "LOAD_CONST_MORTAL") ++ self.assert_no_opcode(load_const, "LOAD_CONST") + + if __name__ == "__main__": + unittest.main() +diff --git a/Lib/test/test_operator.py b/Lib/test/test_operator.py +index 82578a0ef1e..1757824580e 100644 +--- a/Lib/test/test_operator.py ++++ b/Lib/test/test_operator.py +@@ -666,6 +666,7 @@ + module = c_operator + + ++@support.thread_unsafe("swaps global operator module") + class OperatorPickleTestCase: + def copy(self, obj, proto): + with support.swap_item(sys.modules, 'operator', self.module): +diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py +index b0e686cb754..6e40cb4f58b 100644 +--- a/Lib/test/test_os.py ++++ b/Lib/test/test_os.py +@@ -105,7 +105,7 @@ + + + def tearDownModule(): +- asyncio.set_event_loop_policy(None) ++ asyncio._set_event_loop_policy(None) + + + class MiscTests(unittest.TestCase): +@@ -230,6 +230,94 @@ + self.assertEqual(type(s), bytes) + self.assertEqual(s, b"spam") + ++ def test_readinto(self): ++ with open(os_helper.TESTFN, "w+b") as fobj: ++ fobj.write(b"spam") ++ fobj.flush() ++ fd = fobj.fileno() ++ os.lseek(fd, 0, 0) ++ # Oversized so readinto without hitting end. ++ buffer = bytearray(7) ++ s = os.readinto(fd, buffer) ++ self.assertEqual(type(s), int) ++ self.assertEqual(s, 4) ++ # Should overwrite the first 4 bytes of the buffer. ++ self.assertEqual(buffer[:4], b"spam") ++ ++ # Readinto at EOF should return 0 and not touch buffer. ++ buffer[:] = b"notspam" ++ s = os.readinto(fd, buffer) ++ self.assertEqual(type(s), int) ++ self.assertEqual(s, 0) ++ self.assertEqual(bytes(buffer), b"notspam") ++ s = os.readinto(fd, buffer) ++ self.assertEqual(s, 0) ++ self.assertEqual(bytes(buffer), b"notspam") ++ ++ # Readinto a 0 length bytearray when at EOF should return 0 ++ self.assertEqual(os.readinto(fd, bytearray()), 0) ++ ++ # Readinto a 0 length bytearray with data available should return 0. ++ os.lseek(fd, 0, 0) ++ self.assertEqual(os.readinto(fd, bytearray()), 0) ++ ++ @unittest.skipUnless(hasattr(os, 'get_blocking'), ++ 'needs os.get_blocking() and os.set_blocking()') ++ @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") ++ @unittest.skipIf(support.is_emscripten, "set_blocking does not work correctly") ++ def test_readinto_non_blocking(self): ++ # Verify behavior of a readinto which would block on a non-blocking fd. ++ r, w = os.pipe() ++ try: ++ os.set_blocking(r, False) ++ with self.assertRaises(BlockingIOError): ++ os.readinto(r, bytearray(5)) ++ ++ # Pass some data through ++ os.write(w, b"spam") ++ self.assertEqual(os.readinto(r, bytearray(4)), 4) ++ ++ # Still don't block or return 0. ++ with self.assertRaises(BlockingIOError): ++ os.readinto(r, bytearray(5)) ++ ++ # At EOF should return size 0 ++ os.close(w) ++ w = None ++ self.assertEqual(os.readinto(r, bytearray(5)), 0) ++ self.assertEqual(os.readinto(r, bytearray(5)), 0) # Still EOF ++ ++ finally: ++ os.close(r) ++ if w is not None: ++ os.close(w) ++ ++ def test_readinto_badarg(self): ++ with open(os_helper.TESTFN, "w+b") as fobj: ++ fobj.write(b"spam") ++ fobj.flush() ++ fd = fobj.fileno() ++ os.lseek(fd, 0, 0) ++ ++ for bad_arg in ("test", bytes(), 14): ++ with self.subTest(f"bad buffer {type(bad_arg)}"): ++ with self.assertRaises(TypeError): ++ os.readinto(fd, bad_arg) ++ ++ with self.subTest("doesn't work on file objects"): ++ with self.assertRaises(TypeError): ++ os.readinto(fobj, bytearray(5)) ++ ++ # takes two args ++ with self.assertRaises(TypeError): ++ os.readinto(fd) ++ ++ # No data should have been read with the bad arguments. ++ buffer = bytearray(4) ++ s = os.readinto(fd, buffer) ++ self.assertEqual(s, 4) ++ self.assertEqual(buffer, b"spam") ++ + @support.cpython_only + # Skip the test on 32-bit platforms: the number of bytes must fit in a + # Py_ssize_t type +@@ -249,6 +337,29 @@ + # operating system is free to return less bytes than requested. + self.assertEqual(data, b'test') + ++ ++ @support.cpython_only ++ # Skip the test on 32-bit platforms: the number of bytes must fit in a ++ # Py_ssize_t type ++ @unittest.skipUnless(INT_MAX < PY_SSIZE_T_MAX, ++ "needs INT_MAX < PY_SSIZE_T_MAX") ++ @support.bigmemtest(size=INT_MAX + 10, memuse=1, dry_run=False) ++ def test_large_readinto(self, size): ++ self.addCleanup(os_helper.unlink, os_helper.TESTFN) ++ create_file(os_helper.TESTFN, b'test') ++ ++ # Issue #21932: For readinto the buffer contains the length rather than ++ # a length being passed explicitly to read, should still get capped to a ++ # valid size / not raise an OverflowError for sizes larger than INT_MAX. ++ buffer = bytearray(INT_MAX + 10) ++ with open(os_helper.TESTFN, "rb") as fp: ++ length = os.readinto(fp.fileno(), buffer) ++ ++ # The test does not try to read more than 2 GiB at once because the ++ # operating system is free to return less bytes than requested. ++ self.assertEqual(length, 4) ++ self.assertEqual(buffer[:4], b'test') ++ + def test_write(self): + # os.write() accepts bytes- and buffer-like objects but not strings + fd = os.open(os_helper.TESTFN, os.O_CREAT | os.O_WRONLY) +@@ -2467,6 +2578,10 @@ + def test_read(self): + self.check(os.read, 1) + ++ @unittest.skipUnless(hasattr(os, 'readinto'), 'test needs os.readinto()') ++ def test_readinto(self): ++ self.check(os.readinto, bytearray(5)) ++ + @unittest.skipUnless(hasattr(os, 'readv'), 'test needs os.readv()') + def test_readv(self): + buf = bytearray(10) +diff --git a/Lib/test/test_pathlib/test_pathlib.py b/Lib/test/test_pathlib/test_pathlib.py +index ac3a3b4f15c..31e5306ae60 100644 +--- a/Lib/test/test_pathlib/test_pathlib.py ++++ b/Lib/test/test_pathlib/test_pathlib.py +@@ -75,7 +75,7 @@ + # Tests for the pure classes. + # + +-class PurePathTest(test_pathlib_abc.DummyPurePathTest): ++class PurePathTest(test_pathlib_abc.DummyJoinablePathTest): + cls = pathlib.PurePath + + # Make sure any symbolic links in the base test path are resolved. +@@ -229,6 +229,31 @@ + self._check_str(p.__fspath__(), ('a/b',)) + self._check_str(os.fspath(p), ('a/b',)) + ++ def test_bytes(self): ++ P = self.cls ++ with self.assertRaises(TypeError): ++ P(b'a') ++ with self.assertRaises(TypeError): ++ P(b'a', 'b') ++ with self.assertRaises(TypeError): ++ P('a', b'b') ++ with self.assertRaises(TypeError): ++ P('a').joinpath(b'b') ++ with self.assertRaises(TypeError): ++ P('a') / b'b' ++ with self.assertRaises(TypeError): ++ b'a' / P('b') ++ with self.assertRaises(TypeError): ++ P('a').match(b'b') ++ with self.assertRaises(TypeError): ++ P('a').relative_to(b'b') ++ with self.assertRaises(TypeError): ++ P('a').with_name(b'b') ++ with self.assertRaises(TypeError): ++ P('a').with_stem(b'b') ++ with self.assertRaises(TypeError): ++ P('a').with_suffix(b'b') ++ + def test_bytes_exc_message(self): + P = self.cls + message = (r"argument should be a str or an os\.PathLike object " +@@ -245,6 +270,12 @@ + P = self.cls + self.assertEqual(bytes(P('a/b')), b'a' + sep + b'b') + ++ def test_as_posix_common(self): ++ P = self.cls ++ for pathstr in ('a', 'a/b', 'a/b/c', '/', '/a/b', '/a/b/c'): ++ self.assertEqual(P(pathstr).as_posix(), pathstr) ++ # Other tests for as_posix() are in test_equivalences(). ++ + def test_eq_common(self): + P = self.cls + self.assertEqual(P('a/b'), P('a/b')) +@@ -324,6 +355,51 @@ + self.assertEqual(q, p) + self.assertEqual(repr(q), r) + ++ def test_drive_common(self): ++ P = self.cls ++ self.assertEqual(P('a/b').drive, '') ++ self.assertEqual(P('/a/b').drive, '') ++ self.assertEqual(P('').drive, '') ++ ++ @needs_windows ++ def test_drive_windows(self): ++ P = self.cls ++ self.assertEqual(P('c:').drive, 'c:') ++ self.assertEqual(P('c:a/b').drive, 'c:') ++ self.assertEqual(P('c:/').drive, 'c:') ++ self.assertEqual(P('c:/a/b/').drive, 'c:') ++ self.assertEqual(P('//a/b').drive, '\\\\a\\b') ++ self.assertEqual(P('//a/b/').drive, '\\\\a\\b') ++ self.assertEqual(P('//a/b/c/d').drive, '\\\\a\\b') ++ self.assertEqual(P('./c:a').drive, '') ++ ++ ++ def test_root_common(self): ++ P = self.cls ++ sep = self.sep ++ self.assertEqual(P('').root, '') ++ self.assertEqual(P('a/b').root, '') ++ self.assertEqual(P('/').root, sep) ++ self.assertEqual(P('/a/b').root, sep) ++ ++ @needs_posix ++ def test_root_posix(self): ++ P = self.cls ++ self.assertEqual(P('/a/b').root, '/') ++ # POSIX special case for two leading slashes. ++ self.assertEqual(P('//a/b').root, '//') ++ ++ @needs_windows ++ def test_root_windows(self): ++ P = self.cls ++ self.assertEqual(P('c:').root, '') ++ self.assertEqual(P('c:a/b').root, '') ++ self.assertEqual(P('c:/').root, '\\') ++ self.assertEqual(P('c:/a/b/').root, '\\') ++ self.assertEqual(P('//a/b').root, '\\') ++ self.assertEqual(P('//a/b/').root, '\\') ++ self.assertEqual(P('//a/b/c/d').root, '\\') ++ + def test_name_empty(self): + P = self.cls + self.assertEqual(P('').name, '') +@@ -362,6 +438,84 @@ + self.assertRaises(ValueError, P('a').match, '') + self.assertRaises(ValueError, P('a').match, '.') + ++ def test_match_common(self): ++ P = self.cls ++ # Simple relative pattern. ++ self.assertTrue(P('b.py').match('b.py')) ++ self.assertTrue(P('a/b.py').match('b.py')) ++ self.assertTrue(P('/a/b.py').match('b.py')) ++ self.assertFalse(P('a.py').match('b.py')) ++ self.assertFalse(P('b/py').match('b.py')) ++ self.assertFalse(P('/a.py').match('b.py')) ++ self.assertFalse(P('b.py/c').match('b.py')) ++ # Wildcard relative pattern. ++ self.assertTrue(P('b.py').match('*.py')) ++ self.assertTrue(P('a/b.py').match('*.py')) ++ self.assertTrue(P('/a/b.py').match('*.py')) ++ self.assertFalse(P('b.pyc').match('*.py')) ++ self.assertFalse(P('b./py').match('*.py')) ++ self.assertFalse(P('b.py/c').match('*.py')) ++ # Multi-part relative pattern. ++ self.assertTrue(P('ab/c.py').match('a*/*.py')) ++ self.assertTrue(P('/d/ab/c.py').match('a*/*.py')) ++ self.assertFalse(P('a.py').match('a*/*.py')) ++ self.assertFalse(P('/dab/c.py').match('a*/*.py')) ++ self.assertFalse(P('ab/c.py/d').match('a*/*.py')) ++ # Absolute pattern. ++ self.assertTrue(P('/b.py').match('/*.py')) ++ self.assertFalse(P('b.py').match('/*.py')) ++ self.assertFalse(P('a/b.py').match('/*.py')) ++ self.assertFalse(P('/a/b.py').match('/*.py')) ++ # Multi-part absolute pattern. ++ self.assertTrue(P('/a/b.py').match('/a/*.py')) ++ self.assertFalse(P('/ab.py').match('/a/*.py')) ++ self.assertFalse(P('/a/b/c.py').match('/a/*.py')) ++ # Multi-part glob-style pattern. ++ self.assertFalse(P('/a/b/c.py').match('/**/*.py')) ++ self.assertTrue(P('/a/b/c.py').match('/a/**/*.py')) ++ # Case-sensitive flag ++ self.assertFalse(P('A.py').match('a.PY', case_sensitive=True)) ++ self.assertTrue(P('A.py').match('a.PY', case_sensitive=False)) ++ self.assertFalse(P('c:/a/B.Py').match('C:/A/*.pY', case_sensitive=True)) ++ self.assertTrue(P('/a/b/c.py').match('/A/*/*.Py', case_sensitive=False)) ++ # Matching against empty path ++ self.assertFalse(P('').match('*')) ++ self.assertFalse(P('').match('**')) ++ self.assertFalse(P('').match('**/*')) ++ ++ @needs_posix ++ def test_match_posix(self): ++ P = self.cls ++ self.assertFalse(P('A.py').match('a.PY')) ++ ++ @needs_windows ++ def test_match_windows(self): ++ P = self.cls ++ # Absolute patterns. ++ self.assertTrue(P('c:/b.py').match('*:/*.py')) ++ self.assertTrue(P('c:/b.py').match('c:/*.py')) ++ self.assertFalse(P('d:/b.py').match('c:/*.py')) # wrong drive ++ self.assertFalse(P('b.py').match('/*.py')) ++ self.assertFalse(P('b.py').match('c:*.py')) ++ self.assertFalse(P('b.py').match('c:/*.py')) ++ self.assertFalse(P('c:b.py').match('/*.py')) ++ self.assertFalse(P('c:b.py').match('c:/*.py')) ++ self.assertFalse(P('/b.py').match('c:*.py')) ++ self.assertFalse(P('/b.py').match('c:/*.py')) ++ # UNC patterns. ++ self.assertTrue(P('//some/share/a.py').match('//*/*/*.py')) ++ self.assertTrue(P('//some/share/a.py').match('//some/share/*.py')) ++ self.assertFalse(P('//other/share/a.py').match('//some/share/*.py')) ++ self.assertFalse(P('//some/share/a/b.py').match('//some/share/*.py')) ++ # Case-insensitivity. ++ self.assertTrue(P('B.py').match('b.PY')) ++ self.assertTrue(P('c:/a/B.Py').match('C:/A/*.pY')) ++ self.assertTrue(P('//Some/Share/B.Py').match('//somE/sharE/*.pY')) ++ # Path anchor doesn't match pattern anchor ++ self.assertFalse(P('c:/b.py').match('/*.py')) # 'c:/' vs '/' ++ self.assertFalse(P('c:/b.py').match('c:*.py')) # 'c:/' vs 'c:' ++ self.assertFalse(P('//some/share/a.py').match('/*.py')) # '//some/share/' vs '/' ++ + @needs_posix + def test_parse_path_posix(self): + check = self._check_parse_path +@@ -522,6 +676,311 @@ + self.assertFalse(p < q) + self.assertFalse(p > q) + ++ @needs_posix ++ def test_is_absolute_posix(self): ++ P = self.cls ++ self.assertFalse(P('').is_absolute()) ++ self.assertFalse(P('a').is_absolute()) ++ self.assertFalse(P('a/b/').is_absolute()) ++ self.assertTrue(P('/').is_absolute()) ++ self.assertTrue(P('/a').is_absolute()) ++ self.assertTrue(P('/a/b/').is_absolute()) ++ self.assertTrue(P('//a').is_absolute()) ++ self.assertTrue(P('//a/b').is_absolute()) ++ ++ @needs_windows ++ def test_is_absolute_windows(self): ++ P = self.cls ++ # Under NT, only paths with both a drive and a root are absolute. ++ self.assertFalse(P().is_absolute()) ++ self.assertFalse(P('a').is_absolute()) ++ self.assertFalse(P('a/b/').is_absolute()) ++ self.assertFalse(P('/').is_absolute()) ++ self.assertFalse(P('/a').is_absolute()) ++ self.assertFalse(P('/a/b/').is_absolute()) ++ self.assertFalse(P('c:').is_absolute()) ++ self.assertFalse(P('c:a').is_absolute()) ++ self.assertFalse(P('c:a/b/').is_absolute()) ++ self.assertTrue(P('c:/').is_absolute()) ++ self.assertTrue(P('c:/a').is_absolute()) ++ self.assertTrue(P('c:/a/b/').is_absolute()) ++ # UNC paths are absolute by definition. ++ self.assertTrue(P('//').is_absolute()) ++ self.assertTrue(P('//a').is_absolute()) ++ self.assertTrue(P('//a/b').is_absolute()) ++ self.assertTrue(P('//a/b/').is_absolute()) ++ self.assertTrue(P('//a/b/c').is_absolute()) ++ self.assertTrue(P('//a/b/c/d').is_absolute()) ++ self.assertTrue(P('//?/UNC/').is_absolute()) ++ self.assertTrue(P('//?/UNC/spam').is_absolute()) ++ ++ def test_relative_to_common(self): ++ P = self.cls ++ p = P('a/b') ++ self.assertRaises(TypeError, p.relative_to) ++ self.assertRaises(TypeError, p.relative_to, b'a') ++ self.assertEqual(p.relative_to(P('')), P('a/b')) ++ self.assertEqual(p.relative_to(''), P('a/b')) ++ self.assertEqual(p.relative_to(P('a')), P('b')) ++ self.assertEqual(p.relative_to('a'), P('b')) ++ self.assertEqual(p.relative_to('a/'), P('b')) ++ self.assertEqual(p.relative_to(P('a/b')), P('')) ++ self.assertEqual(p.relative_to('a/b'), P('')) ++ self.assertEqual(p.relative_to(P(''), walk_up=True), P('a/b')) ++ self.assertEqual(p.relative_to('', walk_up=True), P('a/b')) ++ self.assertEqual(p.relative_to(P('a'), walk_up=True), P('b')) ++ self.assertEqual(p.relative_to('a', walk_up=True), P('b')) ++ self.assertEqual(p.relative_to('a/', walk_up=True), P('b')) ++ self.assertEqual(p.relative_to(P('a/b'), walk_up=True), P('')) ++ self.assertEqual(p.relative_to('a/b', walk_up=True), P('')) ++ self.assertEqual(p.relative_to(P('a/c'), walk_up=True), P('../b')) ++ self.assertEqual(p.relative_to('a/c', walk_up=True), P('../b')) ++ self.assertEqual(p.relative_to(P('a/b/c'), walk_up=True), P('..')) ++ self.assertEqual(p.relative_to('a/b/c', walk_up=True), P('..')) ++ self.assertEqual(p.relative_to(P('c'), walk_up=True), P('../a/b')) ++ self.assertEqual(p.relative_to('c', walk_up=True), P('../a/b')) ++ # Unrelated paths. ++ self.assertRaises(ValueError, p.relative_to, P('c')) ++ self.assertRaises(ValueError, p.relative_to, P('a/b/c')) ++ self.assertRaises(ValueError, p.relative_to, P('a/c')) ++ self.assertRaises(ValueError, p.relative_to, P('/a')) ++ self.assertRaises(ValueError, p.relative_to, P("../a")) ++ self.assertRaises(ValueError, p.relative_to, P("a/..")) ++ self.assertRaises(ValueError, p.relative_to, P("/a/..")) ++ self.assertRaises(ValueError, p.relative_to, P('/'), walk_up=True) ++ self.assertRaises(ValueError, p.relative_to, P('/a'), walk_up=True) ++ self.assertRaises(ValueError, p.relative_to, P("../a"), walk_up=True) ++ self.assertRaises(ValueError, p.relative_to, P("a/.."), walk_up=True) ++ self.assertRaises(ValueError, p.relative_to, P("/a/.."), walk_up=True) ++ p = P('/a/b') ++ self.assertEqual(p.relative_to(P('/')), P('a/b')) ++ self.assertEqual(p.relative_to('/'), P('a/b')) ++ self.assertEqual(p.relative_to(P('/a')), P('b')) ++ self.assertEqual(p.relative_to('/a'), P('b')) ++ self.assertEqual(p.relative_to('/a/'), P('b')) ++ self.assertEqual(p.relative_to(P('/a/b')), P('')) ++ self.assertEqual(p.relative_to('/a/b'), P('')) ++ self.assertEqual(p.relative_to(P('/'), walk_up=True), P('a/b')) ++ self.assertEqual(p.relative_to('/', walk_up=True), P('a/b')) ++ self.assertEqual(p.relative_to(P('/a'), walk_up=True), P('b')) ++ self.assertEqual(p.relative_to('/a', walk_up=True), P('b')) ++ self.assertEqual(p.relative_to('/a/', walk_up=True), P('b')) ++ self.assertEqual(p.relative_to(P('/a/b'), walk_up=True), P('')) ++ self.assertEqual(p.relative_to('/a/b', walk_up=True), P('')) ++ self.assertEqual(p.relative_to(P('/a/c'), walk_up=True), P('../b')) ++ self.assertEqual(p.relative_to('/a/c', walk_up=True), P('../b')) ++ self.assertEqual(p.relative_to(P('/a/b/c'), walk_up=True), P('..')) ++ self.assertEqual(p.relative_to('/a/b/c', walk_up=True), P('..')) ++ self.assertEqual(p.relative_to(P('/c'), walk_up=True), P('../a/b')) ++ self.assertEqual(p.relative_to('/c', walk_up=True), P('../a/b')) ++ # Unrelated paths. ++ self.assertRaises(ValueError, p.relative_to, P('/c')) ++ self.assertRaises(ValueError, p.relative_to, P('/a/b/c')) ++ self.assertRaises(ValueError, p.relative_to, P('/a/c')) ++ self.assertRaises(ValueError, p.relative_to, P('')) ++ self.assertRaises(ValueError, p.relative_to, '') ++ self.assertRaises(ValueError, p.relative_to, P('a')) ++ self.assertRaises(ValueError, p.relative_to, P("../a")) ++ self.assertRaises(ValueError, p.relative_to, P("a/..")) ++ self.assertRaises(ValueError, p.relative_to, P("/a/..")) ++ self.assertRaises(ValueError, p.relative_to, P(''), walk_up=True) ++ self.assertRaises(ValueError, p.relative_to, P('a'), walk_up=True) ++ self.assertRaises(ValueError, p.relative_to, P("../a"), walk_up=True) ++ self.assertRaises(ValueError, p.relative_to, P("a/.."), walk_up=True) ++ self.assertRaises(ValueError, p.relative_to, P("/a/.."), walk_up=True) ++ ++ @needs_windows ++ def test_relative_to_windows(self): ++ P = self.cls ++ p = P('C:Foo/Bar') ++ self.assertEqual(p.relative_to(P('c:')), P('Foo/Bar')) ++ self.assertEqual(p.relative_to('c:'), P('Foo/Bar')) ++ self.assertEqual(p.relative_to(P('c:foO')), P('Bar')) ++ self.assertEqual(p.relative_to('c:foO'), P('Bar')) ++ self.assertEqual(p.relative_to('c:foO/'), P('Bar')) ++ self.assertEqual(p.relative_to(P('c:foO/baR')), P()) ++ self.assertEqual(p.relative_to('c:foO/baR'), P()) ++ self.assertEqual(p.relative_to(P('c:'), walk_up=True), P('Foo/Bar')) ++ self.assertEqual(p.relative_to('c:', walk_up=True), P('Foo/Bar')) ++ self.assertEqual(p.relative_to(P('c:foO'), walk_up=True), P('Bar')) ++ self.assertEqual(p.relative_to('c:foO', walk_up=True), P('Bar')) ++ self.assertEqual(p.relative_to('c:foO/', walk_up=True), P('Bar')) ++ self.assertEqual(p.relative_to(P('c:foO/baR'), walk_up=True), P()) ++ self.assertEqual(p.relative_to('c:foO/baR', walk_up=True), P()) ++ self.assertEqual(p.relative_to(P('C:Foo/Bar/Baz'), walk_up=True), P('..')) ++ self.assertEqual(p.relative_to(P('C:Foo/Baz'), walk_up=True), P('../Bar')) ++ self.assertEqual(p.relative_to(P('C:Baz/Bar'), walk_up=True), P('../../Foo/Bar')) ++ # Unrelated paths. ++ self.assertRaises(ValueError, p.relative_to, P()) ++ self.assertRaises(ValueError, p.relative_to, '') ++ self.assertRaises(ValueError, p.relative_to, P('d:')) ++ self.assertRaises(ValueError, p.relative_to, P('/')) ++ self.assertRaises(ValueError, p.relative_to, P('Foo')) ++ self.assertRaises(ValueError, p.relative_to, P('/Foo')) ++ self.assertRaises(ValueError, p.relative_to, P('C:/Foo')) ++ self.assertRaises(ValueError, p.relative_to, P('C:Foo/Bar/Baz')) ++ self.assertRaises(ValueError, p.relative_to, P('C:Foo/Baz')) ++ self.assertRaises(ValueError, p.relative_to, P(), walk_up=True) ++ self.assertRaises(ValueError, p.relative_to, '', walk_up=True) ++ self.assertRaises(ValueError, p.relative_to, P('d:'), walk_up=True) ++ self.assertRaises(ValueError, p.relative_to, P('/'), walk_up=True) ++ self.assertRaises(ValueError, p.relative_to, P('Foo'), walk_up=True) ++ self.assertRaises(ValueError, p.relative_to, P('/Foo'), walk_up=True) ++ self.assertRaises(ValueError, p.relative_to, P('C:/Foo'), walk_up=True) ++ p = P('C:/Foo/Bar') ++ self.assertEqual(p.relative_to(P('c:/')), P('Foo/Bar')) ++ self.assertEqual(p.relative_to('c:/'), P('Foo/Bar')) ++ self.assertEqual(p.relative_to(P('c:/foO')), P('Bar')) ++ self.assertEqual(p.relative_to('c:/foO'), P('Bar')) ++ self.assertEqual(p.relative_to('c:/foO/'), P('Bar')) ++ self.assertEqual(p.relative_to(P('c:/foO/baR')), P()) ++ self.assertEqual(p.relative_to('c:/foO/baR'), P()) ++ self.assertEqual(p.relative_to(P('c:/'), walk_up=True), P('Foo/Bar')) ++ self.assertEqual(p.relative_to('c:/', walk_up=True), P('Foo/Bar')) ++ self.assertEqual(p.relative_to(P('c:/foO'), walk_up=True), P('Bar')) ++ self.assertEqual(p.relative_to('c:/foO', walk_up=True), P('Bar')) ++ self.assertEqual(p.relative_to('c:/foO/', walk_up=True), P('Bar')) ++ self.assertEqual(p.relative_to(P('c:/foO/baR'), walk_up=True), P()) ++ self.assertEqual(p.relative_to('c:/foO/baR', walk_up=True), P()) ++ self.assertEqual(p.relative_to('C:/Baz', walk_up=True), P('../Foo/Bar')) ++ self.assertEqual(p.relative_to('C:/Foo/Bar/Baz', walk_up=True), P('..')) ++ self.assertEqual(p.relative_to('C:/Foo/Baz', walk_up=True), P('../Bar')) ++ # Unrelated paths. ++ self.assertRaises(ValueError, p.relative_to, 'c:') ++ self.assertRaises(ValueError, p.relative_to, P('c:')) ++ self.assertRaises(ValueError, p.relative_to, P('C:/Baz')) ++ self.assertRaises(ValueError, p.relative_to, P('C:/Foo/Bar/Baz')) ++ self.assertRaises(ValueError, p.relative_to, P('C:/Foo/Baz')) ++ self.assertRaises(ValueError, p.relative_to, P('C:Foo')) ++ self.assertRaises(ValueError, p.relative_to, P('d:')) ++ self.assertRaises(ValueError, p.relative_to, P('d:/')) ++ self.assertRaises(ValueError, p.relative_to, P('/')) ++ self.assertRaises(ValueError, p.relative_to, P('/Foo')) ++ self.assertRaises(ValueError, p.relative_to, P('//C/Foo')) ++ self.assertRaises(ValueError, p.relative_to, 'c:', walk_up=True) ++ self.assertRaises(ValueError, p.relative_to, P('c:'), walk_up=True) ++ self.assertRaises(ValueError, p.relative_to, P('C:Foo'), walk_up=True) ++ self.assertRaises(ValueError, p.relative_to, P('d:'), walk_up=True) ++ self.assertRaises(ValueError, p.relative_to, P('d:/'), walk_up=True) ++ self.assertRaises(ValueError, p.relative_to, P('/'), walk_up=True) ++ self.assertRaises(ValueError, p.relative_to, P('/Foo'), walk_up=True) ++ self.assertRaises(ValueError, p.relative_to, P('//C/Foo'), walk_up=True) ++ # UNC paths. ++ p = P('//Server/Share/Foo/Bar') ++ self.assertEqual(p.relative_to(P('//sErver/sHare')), P('Foo/Bar')) ++ self.assertEqual(p.relative_to('//sErver/sHare'), P('Foo/Bar')) ++ self.assertEqual(p.relative_to('//sErver/sHare/'), P('Foo/Bar')) ++ self.assertEqual(p.relative_to(P('//sErver/sHare/Foo')), P('Bar')) ++ self.assertEqual(p.relative_to('//sErver/sHare/Foo'), P('Bar')) ++ self.assertEqual(p.relative_to('//sErver/sHare/Foo/'), P('Bar')) ++ self.assertEqual(p.relative_to(P('//sErver/sHare/Foo/Bar')), P()) ++ self.assertEqual(p.relative_to('//sErver/sHare/Foo/Bar'), P()) ++ self.assertEqual(p.relative_to(P('//sErver/sHare'), walk_up=True), P('Foo/Bar')) ++ self.assertEqual(p.relative_to('//sErver/sHare', walk_up=True), P('Foo/Bar')) ++ self.assertEqual(p.relative_to('//sErver/sHare/', walk_up=True), P('Foo/Bar')) ++ self.assertEqual(p.relative_to(P('//sErver/sHare/Foo'), walk_up=True), P('Bar')) ++ self.assertEqual(p.relative_to('//sErver/sHare/Foo', walk_up=True), P('Bar')) ++ self.assertEqual(p.relative_to('//sErver/sHare/Foo/', walk_up=True), P('Bar')) ++ self.assertEqual(p.relative_to(P('//sErver/sHare/Foo/Bar'), walk_up=True), P()) ++ self.assertEqual(p.relative_to('//sErver/sHare/Foo/Bar', walk_up=True), P()) ++ self.assertEqual(p.relative_to(P('//sErver/sHare/bar'), walk_up=True), P('../Foo/Bar')) ++ self.assertEqual(p.relative_to('//sErver/sHare/bar', walk_up=True), P('../Foo/Bar')) ++ # Unrelated paths. ++ self.assertRaises(ValueError, p.relative_to, P('/Server/Share/Foo')) ++ self.assertRaises(ValueError, p.relative_to, P('c:/Server/Share/Foo')) ++ self.assertRaises(ValueError, p.relative_to, P('//z/Share/Foo')) ++ self.assertRaises(ValueError, p.relative_to, P('//Server/z/Foo')) ++ self.assertRaises(ValueError, p.relative_to, P('/Server/Share/Foo'), walk_up=True) ++ self.assertRaises(ValueError, p.relative_to, P('c:/Server/Share/Foo'), walk_up=True) ++ self.assertRaises(ValueError, p.relative_to, P('//z/Share/Foo'), walk_up=True) ++ self.assertRaises(ValueError, p.relative_to, P('//Server/z/Foo'), walk_up=True) ++ ++ def test_is_relative_to_common(self): ++ P = self.cls ++ p = P('a/b') ++ self.assertRaises(TypeError, p.is_relative_to) ++ self.assertRaises(TypeError, p.is_relative_to, b'a') ++ self.assertTrue(p.is_relative_to(P(''))) ++ self.assertTrue(p.is_relative_to('')) ++ self.assertTrue(p.is_relative_to(P('a'))) ++ self.assertTrue(p.is_relative_to('a/')) ++ self.assertTrue(p.is_relative_to(P('a/b'))) ++ self.assertTrue(p.is_relative_to('a/b')) ++ # Unrelated paths. ++ self.assertFalse(p.is_relative_to(P('c'))) ++ self.assertFalse(p.is_relative_to(P('a/b/c'))) ++ self.assertFalse(p.is_relative_to(P('a/c'))) ++ self.assertFalse(p.is_relative_to(P('/a'))) ++ p = P('/a/b') ++ self.assertTrue(p.is_relative_to(P('/'))) ++ self.assertTrue(p.is_relative_to('/')) ++ self.assertTrue(p.is_relative_to(P('/a'))) ++ self.assertTrue(p.is_relative_to('/a')) ++ self.assertTrue(p.is_relative_to('/a/')) ++ self.assertTrue(p.is_relative_to(P('/a/b'))) ++ self.assertTrue(p.is_relative_to('/a/b')) ++ # Unrelated paths. ++ self.assertFalse(p.is_relative_to(P('/c'))) ++ self.assertFalse(p.is_relative_to(P('/a/b/c'))) ++ self.assertFalse(p.is_relative_to(P('/a/c'))) ++ self.assertFalse(p.is_relative_to(P(''))) ++ self.assertFalse(p.is_relative_to('')) ++ self.assertFalse(p.is_relative_to(P('a'))) ++ ++ @needs_windows ++ def test_is_relative_to_windows(self): ++ P = self.cls ++ p = P('C:Foo/Bar') ++ self.assertTrue(p.is_relative_to(P('c:'))) ++ self.assertTrue(p.is_relative_to('c:')) ++ self.assertTrue(p.is_relative_to(P('c:foO'))) ++ self.assertTrue(p.is_relative_to('c:foO')) ++ self.assertTrue(p.is_relative_to('c:foO/')) ++ self.assertTrue(p.is_relative_to(P('c:foO/baR'))) ++ self.assertTrue(p.is_relative_to('c:foO/baR')) ++ # Unrelated paths. ++ self.assertFalse(p.is_relative_to(P())) ++ self.assertFalse(p.is_relative_to('')) ++ self.assertFalse(p.is_relative_to(P('d:'))) ++ self.assertFalse(p.is_relative_to(P('/'))) ++ self.assertFalse(p.is_relative_to(P('Foo'))) ++ self.assertFalse(p.is_relative_to(P('/Foo'))) ++ self.assertFalse(p.is_relative_to(P('C:/Foo'))) ++ self.assertFalse(p.is_relative_to(P('C:Foo/Bar/Baz'))) ++ self.assertFalse(p.is_relative_to(P('C:Foo/Baz'))) ++ p = P('C:/Foo/Bar') ++ self.assertTrue(p.is_relative_to(P('c:/'))) ++ self.assertTrue(p.is_relative_to(P('c:/foO'))) ++ self.assertTrue(p.is_relative_to('c:/foO/')) ++ self.assertTrue(p.is_relative_to(P('c:/foO/baR'))) ++ self.assertTrue(p.is_relative_to('c:/foO/baR')) ++ # Unrelated paths. ++ self.assertFalse(p.is_relative_to('c:')) ++ self.assertFalse(p.is_relative_to(P('C:/Baz'))) ++ self.assertFalse(p.is_relative_to(P('C:/Foo/Bar/Baz'))) ++ self.assertFalse(p.is_relative_to(P('C:/Foo/Baz'))) ++ self.assertFalse(p.is_relative_to(P('C:Foo'))) ++ self.assertFalse(p.is_relative_to(P('d:'))) ++ self.assertFalse(p.is_relative_to(P('d:/'))) ++ self.assertFalse(p.is_relative_to(P('/'))) ++ self.assertFalse(p.is_relative_to(P('/Foo'))) ++ self.assertFalse(p.is_relative_to(P('//C/Foo'))) ++ # UNC paths. ++ p = P('//Server/Share/Foo/Bar') ++ self.assertTrue(p.is_relative_to(P('//sErver/sHare'))) ++ self.assertTrue(p.is_relative_to('//sErver/sHare')) ++ self.assertTrue(p.is_relative_to('//sErver/sHare/')) ++ self.assertTrue(p.is_relative_to(P('//sErver/sHare/Foo'))) ++ self.assertTrue(p.is_relative_to('//sErver/sHare/Foo')) ++ self.assertTrue(p.is_relative_to('//sErver/sHare/Foo/')) ++ self.assertTrue(p.is_relative_to(P('//sErver/sHare/Foo/Bar'))) ++ self.assertTrue(p.is_relative_to('//sErver/sHare/Foo/Bar')) ++ # Unrelated paths. ++ self.assertFalse(p.is_relative_to(P('/Server/Share/Foo'))) ++ self.assertFalse(p.is_relative_to(P('c:/Server/Share/Foo'))) ++ self.assertFalse(p.is_relative_to(P('//z/Share/Foo'))) ++ self.assertFalse(p.is_relative_to(P('//Server/z/Foo'))) ++ + + class PurePosixPathTest(PurePathTest): + cls = pathlib.PurePosixPath +@@ -543,7 +1002,7 @@ + # Tests for the concrete classes. + # + +-class PathTest(test_pathlib_abc.DummyPathTest, PurePathTest): ++class PathTest(test_pathlib_abc.DummyRWPathTest, PurePathTest): + """Tests for the FS-accessing functionalities of the Path classes.""" + cls = pathlib.Path + can_symlink = os_helper.can_symlink() +@@ -553,10 +1012,44 @@ + if name in _tests_needing_symlinks and not self.can_symlink: + self.skipTest('requires symlinks') + super().setUp() +- os.chmod(self.parser.join(self.base, 'dirE'), 0) ++ ++ def createTestHierarchy(self): ++ os.mkdir(self.base) ++ os.mkdir(os.path.join(self.base, 'dirA')) ++ os.mkdir(os.path.join(self.base, 'dirB')) ++ os.mkdir(os.path.join(self.base, 'dirC')) ++ os.mkdir(os.path.join(self.base, 'dirC', 'dirD')) ++ os.mkdir(os.path.join(self.base, 'dirE')) ++ with open(os.path.join(self.base, 'fileA'), 'wb') as f: ++ f.write(b"this is file A\n") ++ with open(os.path.join(self.base, 'dirB', 'fileB'), 'wb') as f: ++ f.write(b"this is file B\n") ++ with open(os.path.join(self.base, 'dirC', 'fileC'), 'wb') as f: ++ f.write(b"this is file C\n") ++ with open(os.path.join(self.base, 'dirC', 'novel.txt'), 'wb') as f: ++ f.write(b"this is a novel\n") ++ with open(os.path.join(self.base, 'dirC', 'dirD', 'fileD'), 'wb') as f: ++ f.write(b"this is file D\n") ++ os.chmod(os.path.join(self.base, 'dirE'), 0) ++ if self.can_symlink: ++ # Relative symlinks. ++ os.symlink('fileA', os.path.join(self.base, 'linkA')) ++ os.symlink('non-existing', os.path.join(self.base, 'brokenLink')) ++ os.symlink('dirB', ++ os.path.join(self.base, 'linkB'), ++ target_is_directory=True) ++ os.symlink(os.path.join('..', 'dirB'), ++ os.path.join(self.base, 'dirA', 'linkC'), ++ target_is_directory=True) ++ # This one goes upwards, creating a loop. ++ os.symlink(os.path.join('..', 'dirB'), ++ os.path.join(self.base, 'dirB', 'linkD'), ++ target_is_directory=True) ++ # Broken symlink (pointing to itself). ++ os.symlink('brokenLinkLoop', os.path.join(self.base, 'brokenLinkLoop')) + + def tearDown(self): +- os.chmod(self.parser.join(self.base, 'dirE'), 0o777) ++ os.chmod(os.path.join(self.base, 'dirE'), 0o777) + os_helper.rmtree(self.base) + + def tempdir(self): +@@ -565,15 +1058,15 @@ + self.addCleanup(os_helper.rmtree, d) + return d + +- def test_matches_pathbase_docstrings(self): +- path_names = {name for name in dir(pathlib._abc.PathBase) if name[0] != '_'} ++ def test_matches_writablepath_docstrings(self): ++ path_names = {name for name in dir(pathlib._abc.WritablePath) if name[0] != '_'} + for attr_name in path_names: + if attr_name == 'parser': +- # On Windows, Path.parser is ntpath, but PathBase.parser is ++ # On Windows, Path.parser is ntpath, but WritablePath.parser is + # posixpath, and so their docstrings differ. + continue + our_attr = getattr(self.cls, attr_name) +- path_attr = getattr(pathlib._abc.PathBase, attr_name) ++ path_attr = getattr(pathlib._abc.WritablePath, attr_name) + self.assertEqual(our_attr.__doc__, path_attr.__doc__) + + def test_concrete_class(self): +@@ -687,6 +1180,15 @@ + for dirpath, dirnames, filenames in p.walk(): + self.assertEqual(42, dirpath.session_id) + ++ def test_open_common(self): ++ p = self.cls(self.base) ++ with (p / 'fileA').open('r') as f: ++ self.assertIsInstance(f, io.TextIOBase) ++ self.assertEqual(f.read(), "this is file A\n") ++ with (p / 'fileA').open('rb') as f: ++ self.assertIsInstance(f, io.BufferedIOBase) ++ self.assertEqual(f.read().strip(), b"this is file A") ++ + def test_open_unbuffered(self): + p = self.cls(self.base) + with (p / 'fileA').open('rb', buffering=0) as f: +@@ -1008,26 +1510,97 @@ + self.assertTrue(target.is_symlink()) + self.assertEqual(source_readlink, target.readlink()) + ++ def test_move_file(self): ++ base = self.cls(self.base) ++ source = base / 'fileA' ++ source_text = source.read_text() ++ target = base / 'fileA_moved' ++ result = source.move(target) ++ self.assertEqual(result, target) ++ self.assertFalse(source.exists()) ++ self.assertTrue(target.exists()) ++ self.assertEqual(source_text, target.read_text()) ++ + @patch_replace + def test_move_file_other_fs(self): + self.test_move_file() + ++ def test_move_file_to_file(self): ++ base = self.cls(self.base) ++ source = base / 'fileA' ++ source_text = source.read_text() ++ target = base / 'dirB' / 'fileB' ++ result = source.move(target) ++ self.assertEqual(result, target) ++ self.assertFalse(source.exists()) ++ self.assertTrue(target.exists()) ++ self.assertEqual(source_text, target.read_text()) ++ + @patch_replace + def test_move_file_to_file_other_fs(self): + self.test_move_file_to_file() + ++ def test_move_file_to_dir(self): ++ base = self.cls(self.base) ++ source = base / 'fileA' ++ target = base / 'dirB' ++ self.assertRaises(OSError, source.move, target) ++ + @patch_replace + def test_move_file_to_dir_other_fs(self): + self.test_move_file_to_dir() + ++ def test_move_file_to_itself(self): ++ base = self.cls(self.base) ++ source = base / 'fileA' ++ self.assertRaises(OSError, source.move, source) ++ ++ def test_move_dir(self): ++ base = self.cls(self.base) ++ source = base / 'dirC' ++ target = base / 'dirC_moved' ++ result = source.move(target) ++ self.assertEqual(result, target) ++ self.assertFalse(source.exists()) ++ self.assertTrue(target.is_dir()) ++ self.assertTrue(target.joinpath('dirD').is_dir()) ++ self.assertTrue(target.joinpath('dirD', 'fileD').is_file()) ++ self.assertEqual(target.joinpath('dirD', 'fileD').read_text(), ++ "this is file D\n") ++ self.assertTrue(target.joinpath('fileC').is_file()) ++ self.assertTrue(target.joinpath('fileC').read_text(), ++ "this is file C\n") ++ + @patch_replace + def test_move_dir_other_fs(self): + self.test_move_dir() + ++ def test_move_dir_to_dir(self): ++ base = self.cls(self.base) ++ source = base / 'dirC' ++ target = base / 'dirB' ++ self.assertRaises(OSError, source.move, target) ++ self.assertTrue(source.exists()) ++ self.assertTrue(target.exists()) ++ + @patch_replace + def test_move_dir_to_dir_other_fs(self): + self.test_move_dir_to_dir() + ++ def test_move_dir_to_itself(self): ++ base = self.cls(self.base) ++ source = base / 'dirC' ++ self.assertRaises(OSError, source.move, source) ++ self.assertTrue(source.exists()) ++ ++ def test_move_dir_into_itself(self): ++ base = self.cls(self.base) ++ source = base / 'dirC' ++ target = base / 'dirC' / 'bar' ++ self.assertRaises(OSError, source.move, target) ++ self.assertTrue(source.exists()) ++ self.assertFalse(target.exists()) ++ + @patch_replace + def test_move_dir_into_itself_other_fs(self): + self.test_move_dir_into_itself() +@@ -1057,10 +1630,26 @@ + def test_move_dangling_symlink_other_fs(self): + self.test_move_dangling_symlink() + ++ def test_move_into(self): ++ base = self.cls(self.base) ++ source = base / 'fileA' ++ source_text = source.read_text() ++ target_dir = base / 'dirA' ++ result = source.move_into(target_dir) ++ self.assertEqual(result, target_dir / 'fileA') ++ self.assertFalse(source.exists()) ++ self.assertTrue(result.exists()) ++ self.assertEqual(source_text, result.read_text()) ++ + @patch_replace + def test_move_into_other_os(self): + self.test_move_into() + ++ def test_move_into_empty_name(self): ++ source = self.cls('') ++ target_dir = self.base ++ self.assertRaises(ValueError, source.move_into, target_dir) ++ + @patch_replace + def test_move_into_empty_name_other_os(self): + self.test_move_into_empty_name() +@@ -1379,6 +1968,37 @@ + self.assertFileNotFound(p.stat) + self.assertFileNotFound(p.unlink) + ++ def test_delete_file(self): ++ p = self.cls(self.base) / 'fileA' ++ p._delete() ++ self.assertFalse(p.exists()) ++ self.assertFileNotFound(p._delete) ++ ++ def test_delete_dir(self): ++ base = self.cls(self.base) ++ base.joinpath('dirA')._delete() ++ self.assertFalse(base.joinpath('dirA').exists()) ++ self.assertFalse(base.joinpath('dirA', 'linkC').exists( ++ follow_symlinks=False)) ++ base.joinpath('dirB')._delete() ++ self.assertFalse(base.joinpath('dirB').exists()) ++ self.assertFalse(base.joinpath('dirB', 'fileB').exists()) ++ self.assertFalse(base.joinpath('dirB', 'linkD').exists( ++ follow_symlinks=False)) ++ base.joinpath('dirC')._delete() ++ self.assertFalse(base.joinpath('dirC').exists()) ++ self.assertFalse(base.joinpath('dirC', 'dirD').exists()) ++ self.assertFalse(base.joinpath('dirC', 'dirD', 'fileD').exists()) ++ self.assertFalse(base.joinpath('dirC', 'fileC').exists()) ++ self.assertFalse(base.joinpath('dirC', 'novel.txt').exists()) ++ ++ def test_delete_missing(self): ++ tmp = self.cls(self.base, 'delete') ++ tmp.mkdir() ++ # filename is guaranteed not to exist ++ filename = tmp / 'foo' ++ self.assertRaises(FileNotFoundError, filename._delete) ++ + @needs_symlinks + def test_delete_symlink(self): + tmp = self.cls(self.base, 'delete') +@@ -1776,6 +2396,44 @@ + with self.assertRaises(pathlib.UnsupportedOperation): + q.symlink_to(p) + ++ @needs_symlinks ++ def test_info_is_symlink_caching(self): ++ p = self.cls(self.base) ++ q = p / 'mylink' ++ self.assertFalse(q.info.is_symlink()) ++ q.symlink_to('blah') ++ self.assertFalse(q.info.is_symlink()) ++ ++ q = p / 'mylink' # same path, new instance. ++ self.assertTrue(q.info.is_symlink()) ++ q.unlink() ++ self.assertTrue(q.info.is_symlink()) ++ ++ def test_stat(self): ++ statA = self.cls(self.base).joinpath('fileA').stat() ++ statB = self.cls(self.base).joinpath('dirB', 'fileB').stat() ++ statC = self.cls(self.base).joinpath('dirC').stat() ++ # st_mode: files are the same, directory differs. ++ self.assertIsInstance(statA.st_mode, int) ++ self.assertEqual(statA.st_mode, statB.st_mode) ++ self.assertNotEqual(statA.st_mode, statC.st_mode) ++ self.assertNotEqual(statB.st_mode, statC.st_mode) ++ # st_ino: all different, ++ self.assertIsInstance(statA.st_ino, int) ++ self.assertNotEqual(statA.st_ino, statB.st_ino) ++ self.assertNotEqual(statA.st_ino, statC.st_ino) ++ self.assertNotEqual(statB.st_ino, statC.st_ino) ++ # st_dev: all the same. ++ self.assertIsInstance(statA.st_dev, int) ++ self.assertEqual(statA.st_dev, statB.st_dev) ++ self.assertEqual(statA.st_dev, statC.st_dev) ++ # other attributes not used by pathlib. ++ ++ def test_stat_no_follow_symlinks_nosymlink(self): ++ p = self.cls(self.base) / 'fileA' ++ st = p.stat() ++ self.assertEqual(st, p.stat(follow_symlinks=False)) ++ + @needs_symlinks + def test_stat_no_follow_symlinks(self): + p = self.cls(self.base) / 'linkA' +@@ -2461,7 +3119,7 @@ + P('c:/').group() + + +-class PathWalkTest(test_pathlib_abc.DummyPathWalkTest): ++class PathWalkTest(test_pathlib_abc.DummyReadablePathWalkTest): + cls = pathlib.Path + base = PathTest.base + can_symlink = PathTest.can_symlink +@@ -2471,6 +3129,42 @@ + if name in _tests_needing_symlinks and not self.can_symlink: + self.skipTest('requires symlinks') + super().setUp() ++ ++ def createTestHierarchy(self): ++ # Build: ++ # TESTFN/ ++ # TEST1/ a file kid and two directory kids ++ # tmp1 ++ # SUB1/ a file kid and a directory kid ++ # tmp2 ++ # SUB11/ no kids ++ # SUB2/ a file kid and a dirsymlink kid ++ # tmp3 ++ # link/ a symlink to TEST2 ++ # broken_link ++ # broken_link2 ++ # TEST2/ ++ # tmp4 a lone file ++ t2_path = self.cls(self.base, "TEST2") ++ os.makedirs(self.sub11_path) ++ os.makedirs(self.sub2_path) ++ os.makedirs(t2_path) ++ ++ tmp1_path = self.walk_path / "tmp1" ++ tmp2_path = self.sub1_path / "tmp2" ++ tmp3_path = self.sub2_path / "tmp3" ++ tmp4_path = self.cls(self.base, "TEST2", "tmp4") ++ for path in tmp1_path, tmp2_path, tmp3_path, tmp4_path: ++ with open(path, "w", encoding='utf-8') as f: ++ f.write(f"I'm {path} and proud of it. Blame test_pathlib.\n") ++ ++ if self.can_symlink: ++ broken_link_path = self.sub2_path / "broken_link" ++ broken_link2_path = self.sub2_path / "broken_link2" ++ os.symlink(t2_path, self.link_path, target_is_directory=True) ++ os.symlink('broken', broken_link_path) ++ os.symlink(os.path.join('tmp3', 'broken'), broken_link2_path) ++ self.sub2_tree = (self.sub2_path, [], ["broken_link", "broken_link2", "link", "tmp3"]) + sub21_path= self.sub2_path / "SUB21" + tmp5_path = sub21_path / "tmp3" + broken_link3_path = self.sub2_path / "broken_link3" +@@ -2494,7 +3188,7 @@ + def tearDown(self): + if 'SUB21' in self.sub2_tree[1]: + os.chmod(self.sub2_path / "SUB21", stat.S_IRWXU) +- super().tearDown() ++ os_helper.rmtree(self.base) + + def test_walk_bad_dir(self): + errors = [] +diff --git a/Lib/test/test_pathlib/test_pathlib_abc.py b/Lib/test/test_pathlib/test_pathlib_abc.py +index e230dd18879..836d8387bdc 100644 +--- a/Lib/test/test_pathlib/test_pathlib_abc.py ++++ b/Lib/test/test_pathlib/test_pathlib_abc.py +@@ -2,11 +2,10 @@ + import io + import os + import errno +-import stat + import unittest + +-from pathlib._abc import PurePathBase, PathBase +-from pathlib._types import Parser ++from pathlib._abc import JoinablePath, ReadablePath, WritablePath, magic_open ++from pathlib.types import _PathParser, PathInfo + import posixpath + + from test.support.os_helper import TESTFN +@@ -32,8 +31,8 @@ + # + + +-class PurePathBaseTest(unittest.TestCase): +- cls = PurePathBase ++class JoinablePathTest(unittest.TestCase): ++ cls = JoinablePath + + def test_magic_methods(self): + P = self.cls +@@ -52,11 +51,19 @@ + self.assertIs(self.cls.parser, posixpath) + + +-class DummyPurePath(PurePathBase): +- __slots__ = () ++class DummyJoinablePath(JoinablePath): ++ __slots__ = ('_segments',) ++ ++ def __init__(self, *segments): ++ self._segments = segments ++ ++ def __str__(self): ++ if self._segments: ++ return self.parser.join(*self._segments) ++ return '' + + def __eq__(self, other): +- if not isinstance(other, DummyPurePath): ++ if not isinstance(other, DummyJoinablePath): + return NotImplemented + return str(self) == str(other) + +@@ -64,11 +71,14 @@ + return hash(str(self)) + + def __repr__(self): +- return "{}({!r})".format(self.__class__.__name__, self.as_posix()) ++ return "{}({!r})".format(self.__class__.__name__, str(self)) ++ ++ def with_segments(self, *pathsegments): ++ return type(self)(*pathsegments) + + +-class DummyPurePathTest(unittest.TestCase): +- cls = DummyPurePath ++class DummyJoinablePathTest(unittest.TestCase): ++ cls = DummyJoinablePath + + # Use a base path that's unrelated to any real filesystem path. + base = f'/this/path/kills/fascists/{TESTFN}' +@@ -85,7 +95,7 @@ + self.altsep = self.parser.altsep + + def test_parser(self): +- self.assertIsInstance(self.cls.parser, Parser) ++ self.assertIsInstance(self.cls.parser, _PathParser) + + def test_constructor_common(self): + P = self.cls +@@ -97,31 +107,6 @@ + P('a/b/c') + P('/a/b/c') + +- def test_bytes(self): +- P = self.cls +- with self.assertRaises(TypeError): +- P(b'a') +- with self.assertRaises(TypeError): +- P(b'a', 'b') +- with self.assertRaises(TypeError): +- P('a', b'b') +- with self.assertRaises(TypeError): +- P('a').joinpath(b'b') +- with self.assertRaises(TypeError): +- P('a') / b'b' +- with self.assertRaises(TypeError): +- b'a' / P('b') +- with self.assertRaises(TypeError): +- P('a').match(b'b') +- with self.assertRaises(TypeError): +- P('a').relative_to(b'b') +- with self.assertRaises(TypeError): +- P('a').with_name(b'b') +- with self.assertRaises(TypeError): +- P('a').with_stem(b'b') +- with self.assertRaises(TypeError): +- P('a').with_suffix(b'b') +- + def _check_str_subclass(self, *args): + # Issue #21127: it should be possible to construct a PurePath object + # from a str subclass instance, and it then gets converted to +@@ -170,7 +155,6 @@ + self.assertEqual(42, p.with_stem('foo').session_id) + self.assertEqual(42, p.with_suffix('.foo').session_id) + self.assertEqual(42, p.with_segments('foo').session_id) +- self.assertEqual(42, p.relative_to('foo').session_id) + self.assertEqual(42, p.parent.session_id) + for parent in p.parents: + self.assertEqual(42, parent.session_id) +@@ -312,94 +296,6 @@ + p = self.cls('//a/b/c/d') + self.assertEqual(str(p), '\\\\a\\b\\c\\d') + +- def test_as_posix_common(self): +- P = self.cls +- for pathstr in ('a', 'a/b', 'a/b/c', '/', '/a/b', '/a/b/c'): +- self.assertEqual(P(pathstr).as_posix(), pathstr) +- # Other tests for as_posix() are in test_equivalences(). +- +- def test_match_empty(self): +- P = self.cls +- self.assertRaises(ValueError, P('a').match, '') +- +- def test_match_common(self): +- P = self.cls +- # Simple relative pattern. +- self.assertTrue(P('b.py').match('b.py')) +- self.assertTrue(P('a/b.py').match('b.py')) +- self.assertTrue(P('/a/b.py').match('b.py')) +- self.assertFalse(P('a.py').match('b.py')) +- self.assertFalse(P('b/py').match('b.py')) +- self.assertFalse(P('/a.py').match('b.py')) +- self.assertFalse(P('b.py/c').match('b.py')) +- # Wildcard relative pattern. +- self.assertTrue(P('b.py').match('*.py')) +- self.assertTrue(P('a/b.py').match('*.py')) +- self.assertTrue(P('/a/b.py').match('*.py')) +- self.assertFalse(P('b.pyc').match('*.py')) +- self.assertFalse(P('b./py').match('*.py')) +- self.assertFalse(P('b.py/c').match('*.py')) +- # Multi-part relative pattern. +- self.assertTrue(P('ab/c.py').match('a*/*.py')) +- self.assertTrue(P('/d/ab/c.py').match('a*/*.py')) +- self.assertFalse(P('a.py').match('a*/*.py')) +- self.assertFalse(P('/dab/c.py').match('a*/*.py')) +- self.assertFalse(P('ab/c.py/d').match('a*/*.py')) +- # Absolute pattern. +- self.assertTrue(P('/b.py').match('/*.py')) +- self.assertFalse(P('b.py').match('/*.py')) +- self.assertFalse(P('a/b.py').match('/*.py')) +- self.assertFalse(P('/a/b.py').match('/*.py')) +- # Multi-part absolute pattern. +- self.assertTrue(P('/a/b.py').match('/a/*.py')) +- self.assertFalse(P('/ab.py').match('/a/*.py')) +- self.assertFalse(P('/a/b/c.py').match('/a/*.py')) +- # Multi-part glob-style pattern. +- self.assertFalse(P('/a/b/c.py').match('/**/*.py')) +- self.assertTrue(P('/a/b/c.py').match('/a/**/*.py')) +- # Case-sensitive flag +- self.assertFalse(P('A.py').match('a.PY', case_sensitive=True)) +- self.assertTrue(P('A.py').match('a.PY', case_sensitive=False)) +- self.assertFalse(P('c:/a/B.Py').match('C:/A/*.pY', case_sensitive=True)) +- self.assertTrue(P('/a/b/c.py').match('/A/*/*.Py', case_sensitive=False)) +- # Matching against empty path +- self.assertFalse(P('').match('*')) +- self.assertFalse(P('').match('**')) +- self.assertFalse(P('').match('**/*')) +- +- @needs_posix +- def test_match_posix(self): +- P = self.cls +- self.assertFalse(P('A.py').match('a.PY')) +- +- @needs_windows +- def test_match_windows(self): +- P = self.cls +- # Absolute patterns. +- self.assertTrue(P('c:/b.py').match('*:/*.py')) +- self.assertTrue(P('c:/b.py').match('c:/*.py')) +- self.assertFalse(P('d:/b.py').match('c:/*.py')) # wrong drive +- self.assertFalse(P('b.py').match('/*.py')) +- self.assertFalse(P('b.py').match('c:*.py')) +- self.assertFalse(P('b.py').match('c:/*.py')) +- self.assertFalse(P('c:b.py').match('/*.py')) +- self.assertFalse(P('c:b.py').match('c:/*.py')) +- self.assertFalse(P('/b.py').match('c:*.py')) +- self.assertFalse(P('/b.py').match('c:/*.py')) +- # UNC patterns. +- self.assertTrue(P('//some/share/a.py').match('//*/*/*.py')) +- self.assertTrue(P('//some/share/a.py').match('//some/share/*.py')) +- self.assertFalse(P('//other/share/a.py').match('//some/share/*.py')) +- self.assertFalse(P('//some/share/a/b.py').match('//some/share/*.py')) +- # Case-insensitivity. +- self.assertTrue(P('B.py').match('b.PY')) +- self.assertTrue(P('c:/a/B.Py').match('C:/A/*.pY')) +- self.assertTrue(P('//Some/Share/B.Py').match('//somE/sharE/*.pY')) +- # Path anchor doesn't match pattern anchor +- self.assertFalse(P('c:/b.py').match('/*.py')) # 'c:/' vs '/' +- self.assertFalse(P('c:/b.py').match('c:*.py')) # 'c:/' vs 'c:' +- self.assertFalse(P('//some/share/a.py').match('/*.py')) # '//some/share/' vs '/' +- + def test_full_match_common(self): + P = self.cls + # Simple relative pattern. +@@ -624,50 +520,6 @@ + with self.assertRaises(IndexError): + par[2] + +- def test_drive_common(self): +- P = self.cls +- self.assertEqual(P('a/b').drive, '') +- self.assertEqual(P('/a/b').drive, '') +- self.assertEqual(P('').drive, '') +- +- @needs_windows +- def test_drive_windows(self): +- P = self.cls +- self.assertEqual(P('c:').drive, 'c:') +- self.assertEqual(P('c:a/b').drive, 'c:') +- self.assertEqual(P('c:/').drive, 'c:') +- self.assertEqual(P('c:/a/b/').drive, 'c:') +- self.assertEqual(P('//a/b').drive, '\\\\a\\b') +- self.assertEqual(P('//a/b/').drive, '\\\\a\\b') +- self.assertEqual(P('//a/b/c/d').drive, '\\\\a\\b') +- self.assertEqual(P('./c:a').drive, '') +- +- def test_root_common(self): +- P = self.cls +- sep = self.sep +- self.assertEqual(P('').root, '') +- self.assertEqual(P('a/b').root, '') +- self.assertEqual(P('/').root, sep) +- self.assertEqual(P('/a/b').root, sep) +- +- @needs_posix +- def test_root_posix(self): +- P = self.cls +- self.assertEqual(P('/a/b').root, '/') +- # POSIX special case for two leading slashes. +- self.assertEqual(P('//a/b').root, '//') +- +- @needs_windows +- def test_root_windows(self): +- P = self.cls +- self.assertEqual(P('c:').root, '') +- self.assertEqual(P('c:a/b').root, '') +- self.assertEqual(P('c:/').root, '\\') +- self.assertEqual(P('c:/a/b/').root, '\\') +- self.assertEqual(P('//a/b').root, '\\') +- self.assertEqual(P('//a/b/').root, '\\') +- self.assertEqual(P('//a/b/c/d').root, '\\') +- + def test_anchor_common(self): + P = self.cls + sep = self.sep +@@ -976,350 +828,15 @@ + self.assertRaises(ValueError, P('a/b').with_suffix, '.d/.') + self.assertRaises(TypeError, P('a/b').with_suffix, None) + +- def test_relative_to_common(self): +- P = self.cls +- p = P('a/b') +- self.assertRaises(TypeError, p.relative_to) +- self.assertRaises(TypeError, p.relative_to, b'a') +- self.assertEqual(p.relative_to(P('')), P('a/b')) +- self.assertEqual(p.relative_to(''), P('a/b')) +- self.assertEqual(p.relative_to(P('a')), P('b')) +- self.assertEqual(p.relative_to('a'), P('b')) +- self.assertEqual(p.relative_to('a/'), P('b')) +- self.assertEqual(p.relative_to(P('a/b')), P('')) +- self.assertEqual(p.relative_to('a/b'), P('')) +- self.assertEqual(p.relative_to(P(''), walk_up=True), P('a/b')) +- self.assertEqual(p.relative_to('', walk_up=True), P('a/b')) +- self.assertEqual(p.relative_to(P('a'), walk_up=True), P('b')) +- self.assertEqual(p.relative_to('a', walk_up=True), P('b')) +- self.assertEqual(p.relative_to('a/', walk_up=True), P('b')) +- self.assertEqual(p.relative_to(P('a/b'), walk_up=True), P('')) +- self.assertEqual(p.relative_to('a/b', walk_up=True), P('')) +- self.assertEqual(p.relative_to(P('a/c'), walk_up=True), P('../b')) +- self.assertEqual(p.relative_to('a/c', walk_up=True), P('../b')) +- self.assertEqual(p.relative_to(P('a/b/c'), walk_up=True), P('..')) +- self.assertEqual(p.relative_to('a/b/c', walk_up=True), P('..')) +- self.assertEqual(p.relative_to(P('c'), walk_up=True), P('../a/b')) +- self.assertEqual(p.relative_to('c', walk_up=True), P('../a/b')) +- # Unrelated paths. +- self.assertRaises(ValueError, p.relative_to, P('c')) +- self.assertRaises(ValueError, p.relative_to, P('a/b/c')) +- self.assertRaises(ValueError, p.relative_to, P('a/c')) +- self.assertRaises(ValueError, p.relative_to, P('/a')) +- self.assertRaises(ValueError, p.relative_to, P("../a")) +- self.assertRaises(ValueError, p.relative_to, P("a/..")) +- self.assertRaises(ValueError, p.relative_to, P("/a/..")) +- self.assertRaises(ValueError, p.relative_to, P('/'), walk_up=True) +- self.assertRaises(ValueError, p.relative_to, P('/a'), walk_up=True) +- self.assertRaises(ValueError, p.relative_to, P("../a"), walk_up=True) +- self.assertRaises(ValueError, p.relative_to, P("a/.."), walk_up=True) +- self.assertRaises(ValueError, p.relative_to, P("/a/.."), walk_up=True) +- p = P('/a/b') +- self.assertEqual(p.relative_to(P('/')), P('a/b')) +- self.assertEqual(p.relative_to('/'), P('a/b')) +- self.assertEqual(p.relative_to(P('/a')), P('b')) +- self.assertEqual(p.relative_to('/a'), P('b')) +- self.assertEqual(p.relative_to('/a/'), P('b')) +- self.assertEqual(p.relative_to(P('/a/b')), P('')) +- self.assertEqual(p.relative_to('/a/b'), P('')) +- self.assertEqual(p.relative_to(P('/'), walk_up=True), P('a/b')) +- self.assertEqual(p.relative_to('/', walk_up=True), P('a/b')) +- self.assertEqual(p.relative_to(P('/a'), walk_up=True), P('b')) +- self.assertEqual(p.relative_to('/a', walk_up=True), P('b')) +- self.assertEqual(p.relative_to('/a/', walk_up=True), P('b')) +- self.assertEqual(p.relative_to(P('/a/b'), walk_up=True), P('')) +- self.assertEqual(p.relative_to('/a/b', walk_up=True), P('')) +- self.assertEqual(p.relative_to(P('/a/c'), walk_up=True), P('../b')) +- self.assertEqual(p.relative_to('/a/c', walk_up=True), P('../b')) +- self.assertEqual(p.relative_to(P('/a/b/c'), walk_up=True), P('..')) +- self.assertEqual(p.relative_to('/a/b/c', walk_up=True), P('..')) +- self.assertEqual(p.relative_to(P('/c'), walk_up=True), P('../a/b')) +- self.assertEqual(p.relative_to('/c', walk_up=True), P('../a/b')) +- # Unrelated paths. +- self.assertRaises(ValueError, p.relative_to, P('/c')) +- self.assertRaises(ValueError, p.relative_to, P('/a/b/c')) +- self.assertRaises(ValueError, p.relative_to, P('/a/c')) +- self.assertRaises(ValueError, p.relative_to, P('')) +- self.assertRaises(ValueError, p.relative_to, '') +- self.assertRaises(ValueError, p.relative_to, P('a')) +- self.assertRaises(ValueError, p.relative_to, P("../a")) +- self.assertRaises(ValueError, p.relative_to, P("a/..")) +- self.assertRaises(ValueError, p.relative_to, P("/a/..")) +- self.assertRaises(ValueError, p.relative_to, P(''), walk_up=True) +- self.assertRaises(ValueError, p.relative_to, P('a'), walk_up=True) +- self.assertRaises(ValueError, p.relative_to, P("../a"), walk_up=True) +- self.assertRaises(ValueError, p.relative_to, P("a/.."), walk_up=True) +- self.assertRaises(ValueError, p.relative_to, P("/a/.."), walk_up=True) +- +- @needs_windows +- def test_relative_to_windows(self): +- P = self.cls +- p = P('C:Foo/Bar') +- self.assertEqual(p.relative_to(P('c:')), P('Foo/Bar')) +- self.assertEqual(p.relative_to('c:'), P('Foo/Bar')) +- self.assertEqual(p.relative_to(P('c:foO')), P('Bar')) +- self.assertEqual(p.relative_to('c:foO'), P('Bar')) +- self.assertEqual(p.relative_to('c:foO/'), P('Bar')) +- self.assertEqual(p.relative_to(P('c:foO/baR')), P()) +- self.assertEqual(p.relative_to('c:foO/baR'), P()) +- self.assertEqual(p.relative_to(P('c:'), walk_up=True), P('Foo/Bar')) +- self.assertEqual(p.relative_to('c:', walk_up=True), P('Foo/Bar')) +- self.assertEqual(p.relative_to(P('c:foO'), walk_up=True), P('Bar')) +- self.assertEqual(p.relative_to('c:foO', walk_up=True), P('Bar')) +- self.assertEqual(p.relative_to('c:foO/', walk_up=True), P('Bar')) +- self.assertEqual(p.relative_to(P('c:foO/baR'), walk_up=True), P()) +- self.assertEqual(p.relative_to('c:foO/baR', walk_up=True), P()) +- self.assertEqual(p.relative_to(P('C:Foo/Bar/Baz'), walk_up=True), P('..')) +- self.assertEqual(p.relative_to(P('C:Foo/Baz'), walk_up=True), P('../Bar')) +- self.assertEqual(p.relative_to(P('C:Baz/Bar'), walk_up=True), P('../../Foo/Bar')) +- # Unrelated paths. +- self.assertRaises(ValueError, p.relative_to, P()) +- self.assertRaises(ValueError, p.relative_to, '') +- self.assertRaises(ValueError, p.relative_to, P('d:')) +- self.assertRaises(ValueError, p.relative_to, P('/')) +- self.assertRaises(ValueError, p.relative_to, P('Foo')) +- self.assertRaises(ValueError, p.relative_to, P('/Foo')) +- self.assertRaises(ValueError, p.relative_to, P('C:/Foo')) +- self.assertRaises(ValueError, p.relative_to, P('C:Foo/Bar/Baz')) +- self.assertRaises(ValueError, p.relative_to, P('C:Foo/Baz')) +- self.assertRaises(ValueError, p.relative_to, P(), walk_up=True) +- self.assertRaises(ValueError, p.relative_to, '', walk_up=True) +- self.assertRaises(ValueError, p.relative_to, P('d:'), walk_up=True) +- self.assertRaises(ValueError, p.relative_to, P('/'), walk_up=True) +- self.assertRaises(ValueError, p.relative_to, P('Foo'), walk_up=True) +- self.assertRaises(ValueError, p.relative_to, P('/Foo'), walk_up=True) +- self.assertRaises(ValueError, p.relative_to, P('C:/Foo'), walk_up=True) +- p = P('C:/Foo/Bar') +- self.assertEqual(p.relative_to(P('c:/')), P('Foo/Bar')) +- self.assertEqual(p.relative_to('c:/'), P('Foo/Bar')) +- self.assertEqual(p.relative_to(P('c:/foO')), P('Bar')) +- self.assertEqual(p.relative_to('c:/foO'), P('Bar')) +- self.assertEqual(p.relative_to('c:/foO/'), P('Bar')) +- self.assertEqual(p.relative_to(P('c:/foO/baR')), P()) +- self.assertEqual(p.relative_to('c:/foO/baR'), P()) +- self.assertEqual(p.relative_to(P('c:/'), walk_up=True), P('Foo/Bar')) +- self.assertEqual(p.relative_to('c:/', walk_up=True), P('Foo/Bar')) +- self.assertEqual(p.relative_to(P('c:/foO'), walk_up=True), P('Bar')) +- self.assertEqual(p.relative_to('c:/foO', walk_up=True), P('Bar')) +- self.assertEqual(p.relative_to('c:/foO/', walk_up=True), P('Bar')) +- self.assertEqual(p.relative_to(P('c:/foO/baR'), walk_up=True), P()) +- self.assertEqual(p.relative_to('c:/foO/baR', walk_up=True), P()) +- self.assertEqual(p.relative_to('C:/Baz', walk_up=True), P('../Foo/Bar')) +- self.assertEqual(p.relative_to('C:/Foo/Bar/Baz', walk_up=True), P('..')) +- self.assertEqual(p.relative_to('C:/Foo/Baz', walk_up=True), P('../Bar')) +- # Unrelated paths. +- self.assertRaises(ValueError, p.relative_to, 'c:') +- self.assertRaises(ValueError, p.relative_to, P('c:')) +- self.assertRaises(ValueError, p.relative_to, P('C:/Baz')) +- self.assertRaises(ValueError, p.relative_to, P('C:/Foo/Bar/Baz')) +- self.assertRaises(ValueError, p.relative_to, P('C:/Foo/Baz')) +- self.assertRaises(ValueError, p.relative_to, P('C:Foo')) +- self.assertRaises(ValueError, p.relative_to, P('d:')) +- self.assertRaises(ValueError, p.relative_to, P('d:/')) +- self.assertRaises(ValueError, p.relative_to, P('/')) +- self.assertRaises(ValueError, p.relative_to, P('/Foo')) +- self.assertRaises(ValueError, p.relative_to, P('//C/Foo')) +- self.assertRaises(ValueError, p.relative_to, 'c:', walk_up=True) +- self.assertRaises(ValueError, p.relative_to, P('c:'), walk_up=True) +- self.assertRaises(ValueError, p.relative_to, P('C:Foo'), walk_up=True) +- self.assertRaises(ValueError, p.relative_to, P('d:'), walk_up=True) +- self.assertRaises(ValueError, p.relative_to, P('d:/'), walk_up=True) +- self.assertRaises(ValueError, p.relative_to, P('/'), walk_up=True) +- self.assertRaises(ValueError, p.relative_to, P('/Foo'), walk_up=True) +- self.assertRaises(ValueError, p.relative_to, P('//C/Foo'), walk_up=True) +- # UNC paths. +- p = P('//Server/Share/Foo/Bar') +- self.assertEqual(p.relative_to(P('//sErver/sHare')), P('Foo/Bar')) +- self.assertEqual(p.relative_to('//sErver/sHare'), P('Foo/Bar')) +- self.assertEqual(p.relative_to('//sErver/sHare/'), P('Foo/Bar')) +- self.assertEqual(p.relative_to(P('//sErver/sHare/Foo')), P('Bar')) +- self.assertEqual(p.relative_to('//sErver/sHare/Foo'), P('Bar')) +- self.assertEqual(p.relative_to('//sErver/sHare/Foo/'), P('Bar')) +- self.assertEqual(p.relative_to(P('//sErver/sHare/Foo/Bar')), P()) +- self.assertEqual(p.relative_to('//sErver/sHare/Foo/Bar'), P()) +- self.assertEqual(p.relative_to(P('//sErver/sHare'), walk_up=True), P('Foo/Bar')) +- self.assertEqual(p.relative_to('//sErver/sHare', walk_up=True), P('Foo/Bar')) +- self.assertEqual(p.relative_to('//sErver/sHare/', walk_up=True), P('Foo/Bar')) +- self.assertEqual(p.relative_to(P('//sErver/sHare/Foo'), walk_up=True), P('Bar')) +- self.assertEqual(p.relative_to('//sErver/sHare/Foo', walk_up=True), P('Bar')) +- self.assertEqual(p.relative_to('//sErver/sHare/Foo/', walk_up=True), P('Bar')) +- self.assertEqual(p.relative_to(P('//sErver/sHare/Foo/Bar'), walk_up=True), P()) +- self.assertEqual(p.relative_to('//sErver/sHare/Foo/Bar', walk_up=True), P()) +- self.assertEqual(p.relative_to(P('//sErver/sHare/bar'), walk_up=True), P('../Foo/Bar')) +- self.assertEqual(p.relative_to('//sErver/sHare/bar', walk_up=True), P('../Foo/Bar')) +- # Unrelated paths. +- self.assertRaises(ValueError, p.relative_to, P('/Server/Share/Foo')) +- self.assertRaises(ValueError, p.relative_to, P('c:/Server/Share/Foo')) +- self.assertRaises(ValueError, p.relative_to, P('//z/Share/Foo')) +- self.assertRaises(ValueError, p.relative_to, P('//Server/z/Foo')) +- self.assertRaises(ValueError, p.relative_to, P('/Server/Share/Foo'), walk_up=True) +- self.assertRaises(ValueError, p.relative_to, P('c:/Server/Share/Foo'), walk_up=True) +- self.assertRaises(ValueError, p.relative_to, P('//z/Share/Foo'), walk_up=True) +- self.assertRaises(ValueError, p.relative_to, P('//Server/z/Foo'), walk_up=True) +- +- def test_is_relative_to_common(self): +- P = self.cls +- p = P('a/b') +- self.assertRaises(TypeError, p.is_relative_to) +- self.assertRaises(TypeError, p.is_relative_to, b'a') +- self.assertTrue(p.is_relative_to(P(''))) +- self.assertTrue(p.is_relative_to('')) +- self.assertTrue(p.is_relative_to(P('a'))) +- self.assertTrue(p.is_relative_to('a/')) +- self.assertTrue(p.is_relative_to(P('a/b'))) +- self.assertTrue(p.is_relative_to('a/b')) +- # Unrelated paths. +- self.assertFalse(p.is_relative_to(P('c'))) +- self.assertFalse(p.is_relative_to(P('a/b/c'))) +- self.assertFalse(p.is_relative_to(P('a/c'))) +- self.assertFalse(p.is_relative_to(P('/a'))) +- p = P('/a/b') +- self.assertTrue(p.is_relative_to(P('/'))) +- self.assertTrue(p.is_relative_to('/')) +- self.assertTrue(p.is_relative_to(P('/a'))) +- self.assertTrue(p.is_relative_to('/a')) +- self.assertTrue(p.is_relative_to('/a/')) +- self.assertTrue(p.is_relative_to(P('/a/b'))) +- self.assertTrue(p.is_relative_to('/a/b')) +- # Unrelated paths. +- self.assertFalse(p.is_relative_to(P('/c'))) +- self.assertFalse(p.is_relative_to(P('/a/b/c'))) +- self.assertFalse(p.is_relative_to(P('/a/c'))) +- self.assertFalse(p.is_relative_to(P(''))) +- self.assertFalse(p.is_relative_to('')) +- self.assertFalse(p.is_relative_to(P('a'))) +- +- @needs_windows +- def test_is_relative_to_windows(self): +- P = self.cls +- p = P('C:Foo/Bar') +- self.assertTrue(p.is_relative_to(P('c:'))) +- self.assertTrue(p.is_relative_to('c:')) +- self.assertTrue(p.is_relative_to(P('c:foO'))) +- self.assertTrue(p.is_relative_to('c:foO')) +- self.assertTrue(p.is_relative_to('c:foO/')) +- self.assertTrue(p.is_relative_to(P('c:foO/baR'))) +- self.assertTrue(p.is_relative_to('c:foO/baR')) +- # Unrelated paths. +- self.assertFalse(p.is_relative_to(P())) +- self.assertFalse(p.is_relative_to('')) +- self.assertFalse(p.is_relative_to(P('d:'))) +- self.assertFalse(p.is_relative_to(P('/'))) +- self.assertFalse(p.is_relative_to(P('Foo'))) +- self.assertFalse(p.is_relative_to(P('/Foo'))) +- self.assertFalse(p.is_relative_to(P('C:/Foo'))) +- self.assertFalse(p.is_relative_to(P('C:Foo/Bar/Baz'))) +- self.assertFalse(p.is_relative_to(P('C:Foo/Baz'))) +- p = P('C:/Foo/Bar') +- self.assertTrue(p.is_relative_to(P('c:/'))) +- self.assertTrue(p.is_relative_to(P('c:/foO'))) +- self.assertTrue(p.is_relative_to('c:/foO/')) +- self.assertTrue(p.is_relative_to(P('c:/foO/baR'))) +- self.assertTrue(p.is_relative_to('c:/foO/baR')) +- # Unrelated paths. +- self.assertFalse(p.is_relative_to('c:')) +- self.assertFalse(p.is_relative_to(P('C:/Baz'))) +- self.assertFalse(p.is_relative_to(P('C:/Foo/Bar/Baz'))) +- self.assertFalse(p.is_relative_to(P('C:/Foo/Baz'))) +- self.assertFalse(p.is_relative_to(P('C:Foo'))) +- self.assertFalse(p.is_relative_to(P('d:'))) +- self.assertFalse(p.is_relative_to(P('d:/'))) +- self.assertFalse(p.is_relative_to(P('/'))) +- self.assertFalse(p.is_relative_to(P('/Foo'))) +- self.assertFalse(p.is_relative_to(P('//C/Foo'))) +- # UNC paths. +- p = P('//Server/Share/Foo/Bar') +- self.assertTrue(p.is_relative_to(P('//sErver/sHare'))) +- self.assertTrue(p.is_relative_to('//sErver/sHare')) +- self.assertTrue(p.is_relative_to('//sErver/sHare/')) +- self.assertTrue(p.is_relative_to(P('//sErver/sHare/Foo'))) +- self.assertTrue(p.is_relative_to('//sErver/sHare/Foo')) +- self.assertTrue(p.is_relative_to('//sErver/sHare/Foo/')) +- self.assertTrue(p.is_relative_to(P('//sErver/sHare/Foo/Bar'))) +- self.assertTrue(p.is_relative_to('//sErver/sHare/Foo/Bar')) +- # Unrelated paths. +- self.assertFalse(p.is_relative_to(P('/Server/Share/Foo'))) +- self.assertFalse(p.is_relative_to(P('c:/Server/Share/Foo'))) +- self.assertFalse(p.is_relative_to(P('//z/Share/Foo'))) +- self.assertFalse(p.is_relative_to(P('//Server/z/Foo'))) +- +- @needs_posix +- def test_is_absolute_posix(self): +- P = self.cls +- self.assertFalse(P('').is_absolute()) +- self.assertFalse(P('a').is_absolute()) +- self.assertFalse(P('a/b/').is_absolute()) +- self.assertTrue(P('/').is_absolute()) +- self.assertTrue(P('/a').is_absolute()) +- self.assertTrue(P('/a/b/').is_absolute()) +- self.assertTrue(P('//a').is_absolute()) +- self.assertTrue(P('//a/b').is_absolute()) +- +- @needs_windows +- def test_is_absolute_windows(self): +- P = self.cls +- # Under NT, only paths with both a drive and a root are absolute. +- self.assertFalse(P().is_absolute()) +- self.assertFalse(P('a').is_absolute()) +- self.assertFalse(P('a/b/').is_absolute()) +- self.assertFalse(P('/').is_absolute()) +- self.assertFalse(P('/a').is_absolute()) +- self.assertFalse(P('/a/b/').is_absolute()) +- self.assertFalse(P('c:').is_absolute()) +- self.assertFalse(P('c:a').is_absolute()) +- self.assertFalse(P('c:a/b/').is_absolute()) +- self.assertTrue(P('c:/').is_absolute()) +- self.assertTrue(P('c:/a').is_absolute()) +- self.assertTrue(P('c:/a/b/').is_absolute()) +- # UNC paths are absolute by definition. +- self.assertTrue(P('//').is_absolute()) +- self.assertTrue(P('//a').is_absolute()) +- self.assertTrue(P('//a/b').is_absolute()) +- self.assertTrue(P('//a/b/').is_absolute()) +- self.assertTrue(P('//a/b/c').is_absolute()) +- self.assertTrue(P('//a/b/c/d').is_absolute()) +- self.assertTrue(P('//?/UNC/').is_absolute()) +- self.assertTrue(P('//?/UNC/spam').is_absolute()) +- + + # + # Tests for the virtual classes. + # + +-class PathBaseTest(PurePathBaseTest): +- cls = PathBase +- +- def test_not_implemented_error(self): +- p = self.cls('') +- e = NotImplementedError +- self.assertRaises(e, p.stat) +- self.assertRaises(e, p.exists) +- self.assertRaises(e, p.is_dir) +- self.assertRaises(e, p.is_file) +- self.assertRaises(e, p.is_symlink) +- self.assertRaises(e, p.open) +- self.assertRaises(e, p.read_bytes) +- self.assertRaises(e, p.read_text) +- self.assertRaises(e, p.write_bytes, b'foo') +- self.assertRaises(e, p.write_text, 'foo') +- self.assertRaises(e, p.iterdir) +- self.assertRaises(e, lambda: list(p.glob('*'))) +- self.assertRaises(e, lambda: list(p.rglob('*'))) +- self.assertRaises(e, lambda: list(p.walk())) +- self.assertRaises(e, p.readlink) +- self.assertRaises(e, p.symlink_to, 'foo') +- self.assertRaises(e, p.mkdir) +- +- def test_fspath_common(self): +- self.assertRaises(TypeError, os.fspath, self.cls('')) +- +- def test_as_bytes_common(self): +- self.assertRaises(TypeError, bytes, self.cls('')) +- +- +-class DummyPathIO(io.BytesIO): ++ ++class DummyWritablePathIO(io.BytesIO): + """ +- Used by DummyPath to implement `open('w')` ++ Used by DummyWritablePath to implement `__open_wb__()` + """ + + def __init__(self, files, path): +@@ -1332,68 +849,56 @@ + super().close() + + +-DummyPathStatResult = collections.namedtuple( +- 'DummyPathStatResult', +- 'st_mode st_ino st_dev st_nlink st_uid st_gid st_size st_atime st_mtime st_ctime') ++class DummyReadablePathInfo: ++ __slots__ = ('_is_dir', '_is_file') ++ ++ def __init__(self, is_dir, is_file): ++ self._is_dir = is_dir ++ self._is_file = is_file + ++ def exists(self, *, follow_symlinks=True): ++ return self._is_dir or self._is_file + +-class DummyPath(PathBase): ++ def is_dir(self, *, follow_symlinks=True): ++ return self._is_dir ++ ++ def is_file(self, *, follow_symlinks=True): ++ return self._is_file ++ ++ def is_symlink(self): ++ return False ++ ++ ++class DummyReadablePath(ReadablePath, DummyJoinablePath): + """ +- Simple implementation of PathBase that keeps files and directories in +- memory. ++ Simple implementation of DummyReadablePath that keeps files and ++ directories in memory. + """ +- __slots__ = () ++ __slots__ = ('_info') + + _files = {} + _directories = {} + +- def __eq__(self, other): +- if not isinstance(other, DummyPath): +- return NotImplemented +- return str(self) == str(other) +- +- def __hash__(self): +- return hash(str(self)) +- +- def __repr__(self): +- return "{}({!r})".format(self.__class__.__name__, self.as_posix()) ++ def __init__(self, *segments): ++ super().__init__(*segments) ++ self._info = None + +- def stat(self, *, follow_symlinks=True): +- path = str(self).rstrip('/') +- if path in self._files: +- st_mode = stat.S_IFREG +- elif path in self._directories: +- st_mode = stat.S_IFDIR +- else: +- raise FileNotFoundError(errno.ENOENT, "Not found", str(self)) +- return DummyPathStatResult(st_mode, hash(str(self)), 0, 0, 0, 0, 0, 0, 0, 0) ++ @property ++ def info(self): ++ if self._info is None: ++ path_str = str(self) ++ self._info = DummyReadablePathInfo( ++ is_dir=path_str.rstrip('/') in self._directories, ++ is_file=path_str in self._files) ++ return self._info + +- def open(self, mode='r', buffering=-1, encoding=None, +- errors=None, newline=None): +- if buffering != -1 and not (buffering == 0 and 'b' in mode): +- raise NotImplementedError ++ def __open_rb__(self, buffering=-1): + path = str(self) + if path in self._directories: + raise IsADirectoryError(errno.EISDIR, "Is a directory", path) +- +- text = 'b' not in mode +- mode = ''.join(c for c in mode if c not in 'btU') +- if mode == 'r': +- if path not in self._files: +- raise FileNotFoundError(errno.ENOENT, "File not found", path) +- stream = io.BytesIO(self._files[path]) +- elif mode == 'w': +- parent, name = posixpath.split(path) +- if parent not in self._directories: +- raise FileNotFoundError(errno.ENOENT, "File not found", parent) +- stream = DummyPathIO(self._files, path) +- self._files[path] = b'' +- self._directories[parent].add(name) +- else: +- raise NotImplementedError +- if text: +- stream = io.TextIOWrapper(stream, encoding=encoding, errors=errors, newline=newline) +- return stream ++ elif path not in self._files: ++ raise FileNotFoundError(errno.ENOENT, "File not found", path) ++ return io.BytesIO(self._files[path]) + + def iterdir(self): + path = str(self).rstrip('/') +@@ -1404,6 +909,21 @@ + else: + raise FileNotFoundError(errno.ENOENT, "File not found", path) + ++ ++class DummyWritablePath(WritablePath, DummyJoinablePath): ++ __slots__ = () ++ ++ def __open_wb__(self, buffering=-1): ++ path = str(self) ++ if path in self._directories: ++ raise IsADirectoryError(errno.EISDIR, "Is a directory", path) ++ parent, name = posixpath.split(path) ++ if parent not in self._directories: ++ raise FileNotFoundError(errno.ENOENT, "File not found", parent) ++ self._files[path] = b'' ++ self._directories[parent].add(name) ++ return DummyWritablePathIO(self._files, path) ++ + def mkdir(self, mode=0o777, parents=False, exist_ok=False): + path = str(self) + parent = str(self.parent) +@@ -1422,24 +942,11 @@ + self.parent.mkdir(parents=True, exist_ok=True) + self.mkdir(mode, parents=False, exist_ok=exist_ok) + +- def _delete(self): +- path = str(self) +- if path in self._files: +- del self._files[path] +- elif path in self._directories: +- for name in list(self._directories[path]): +- self.joinpath(name)._delete() +- del self._directories[path] +- else: +- raise FileNotFoundError(errno.ENOENT, "File not found", path) +- parent = str(self.parent) +- self._directories[parent].remove(self.name) +- + +-class DummyPathTest(DummyPurePathTest): +- """Tests for PathBase methods that use stat(), open() and iterdir().""" ++class DummyReadablePathTest(DummyJoinablePathTest): ++ """Tests for ReadablePathTest methods that use stat(), open() and iterdir().""" + +- cls = DummyPath ++ cls = DummyReadablePath + can_symlink = False + + # (self.base) +@@ -1464,33 +971,25 @@ + + def setUp(self): + super().setUp() +- parser = self.cls.parser +- p = self.cls(self.base) +- p.mkdir(parents=True) +- p.joinpath('dirA').mkdir() +- p.joinpath('dirB').mkdir() +- p.joinpath('dirC').mkdir() +- p.joinpath('dirC', 'dirD').mkdir() +- p.joinpath('dirE').mkdir() +- with p.joinpath('fileA').open('wb') as f: +- f.write(b"this is file A\n") +- with p.joinpath('dirB', 'fileB').open('wb') as f: +- f.write(b"this is file B\n") +- with p.joinpath('dirC', 'fileC').open('wb') as f: +- f.write(b"this is file C\n") +- with p.joinpath('dirC', 'novel.txt').open('wb') as f: +- f.write(b"this is a novel\n") +- with p.joinpath('dirC', 'dirD', 'fileD').open('wb') as f: +- f.write(b"this is file D\n") +- if self.can_symlink: +- p.joinpath('linkA').symlink_to('fileA') +- p.joinpath('brokenLink').symlink_to('non-existing') +- p.joinpath('linkB').symlink_to('dirB', target_is_directory=True) +- p.joinpath('dirA', 'linkC').symlink_to( +- parser.join('..', 'dirB'), target_is_directory=True) +- p.joinpath('dirB', 'linkD').symlink_to( +- parser.join('..', 'dirB'), target_is_directory=True) +- p.joinpath('brokenLinkLoop').symlink_to('brokenLinkLoop') ++ self.createTestHierarchy() ++ ++ def createTestHierarchy(self): ++ cls = self.cls ++ cls._files = { ++ f'{self.base}/fileA': b'this is file A\n', ++ f'{self.base}/dirB/fileB': b'this is file B\n', ++ f'{self.base}/dirC/fileC': b'this is file C\n', ++ f'{self.base}/dirC/dirD/fileD': b'this is file D\n', ++ f'{self.base}/dirC/novel.txt': b'this is a novel\n', ++ } ++ cls._directories = { ++ f'{self.base}': {'fileA', 'dirA', 'dirB', 'dirC', 'dirE'}, ++ f'{self.base}/dirA': set(), ++ f'{self.base}/dirB': {'fileB'}, ++ f'{self.base}/dirC': {'fileC', 'dirD', 'novel.txt'}, ++ f'{self.base}/dirC/dirD': {'fileD'}, ++ f'{self.base}/dirE': set(), ++ } + + def tearDown(self): + cls = self.cls +@@ -1530,398 +1029,103 @@ + self.assertIs(False, P(self.base + '\udfff').exists()) + self.assertIs(False, P(self.base + '\x00').exists()) + +- def test_open_common(self): ++ def test_magic_open(self): + p = self.cls(self.base) +- with (p / 'fileA').open('r') as f: ++ with magic_open(p / 'fileA', 'r') as f: + self.assertIsInstance(f, io.TextIOBase) + self.assertEqual(f.read(), "this is file A\n") +- with (p / 'fileA').open('rb') as f: ++ with magic_open(p / 'fileA', 'rb') as f: + self.assertIsInstance(f, io.BufferedIOBase) + self.assertEqual(f.read().strip(), b"this is file A") + +- def test_read_write_bytes(self): +- p = self.cls(self.base) +- (p / 'fileA').write_bytes(b'abcdefg') +- self.assertEqual((p / 'fileA').read_bytes(), b'abcdefg') +- # Check that trying to write str does not truncate the file. +- self.assertRaises(TypeError, (p / 'fileA').write_bytes, 'somestr') +- self.assertEqual((p / 'fileA').read_bytes(), b'abcdefg') ++ def test_iterdir(self): ++ P = self.cls ++ p = P(self.base) ++ it = p.iterdir() ++ paths = set(it) ++ expected = ['dirA', 'dirB', 'dirC', 'dirE', 'fileA'] ++ if self.can_symlink: ++ expected += ['linkA', 'linkB', 'brokenLink', 'brokenLinkLoop'] ++ self.assertEqual(paths, { P(self.base, q) for q in expected }) + +- def test_read_write_text(self): +- p = self.cls(self.base) +- (p / 'fileA').write_text('äbcdefg', encoding='latin-1') +- self.assertEqual((p / 'fileA').read_text( +- encoding='utf-8', errors='ignore'), 'bcdefg') +- # Check that trying to write bytes does not truncate the file. +- self.assertRaises(TypeError, (p / 'fileA').write_text, b'somebytes') +- self.assertEqual((p / 'fileA').read_text(encoding='latin-1'), 'äbcdefg') ++ def test_iterdir_nodir(self): ++ # __iter__ on something that is not a directory. ++ p = self.cls(self.base, 'fileA') ++ with self.assertRaises(OSError) as cm: ++ p.iterdir() ++ # ENOENT or EINVAL under Windows, ENOTDIR otherwise ++ # (see issue #12802). ++ self.assertIn(cm.exception.errno, (errno.ENOTDIR, ++ errno.ENOENT, errno.EINVAL)) + +- def test_read_text_with_newlines(self): ++ def test_iterdir_info(self): + p = self.cls(self.base) +- # Check that `\n` character change nothing +- (p / 'fileA').write_bytes(b'abcde\r\nfghlk\n\rmnopq') +- self.assertEqual((p / 'fileA').read_text(newline='\n'), +- 'abcde\r\nfghlk\n\rmnopq') +- # Check that `\r` character replaces `\n` +- (p / 'fileA').write_bytes(b'abcde\r\nfghlk\n\rmnopq') +- self.assertEqual((p / 'fileA').read_text(newline='\r'), +- 'abcde\r\nfghlk\n\rmnopq') +- # Check that `\r\n` character replaces `\n` +- (p / 'fileA').write_bytes(b'abcde\r\nfghlk\n\rmnopq') +- self.assertEqual((p / 'fileA').read_text(newline='\r\n'), +- 'abcde\r\nfghlk\n\rmnopq') ++ for child in p.iterdir(): ++ info = child.info ++ self.assertIsInstance(info, PathInfo) ++ self.assertEqual(info.exists(), child.exists()) ++ self.assertEqual(info.is_dir(), child.is_dir()) ++ self.assertEqual(info.is_file(), child.is_file()) ++ self.assertEqual(info.is_symlink(), child.is_symlink()) ++ self.assertTrue(info.exists(follow_symlinks=False)) ++ self.assertEqual(info.is_dir(follow_symlinks=False), ++ child.is_dir(follow_symlinks=False)) ++ self.assertEqual(info.is_file(follow_symlinks=False), ++ child.is_file(follow_symlinks=False)) + +- def test_write_text_with_newlines(self): +- p = self.cls(self.base) +- # Check that `\n` character change nothing +- (p / 'fileA').write_text('abcde\r\nfghlk\n\rmnopq', newline='\n') +- self.assertEqual((p / 'fileA').read_bytes(), +- b'abcde\r\nfghlk\n\rmnopq') +- # Check that `\r` character replaces `\n` +- (p / 'fileA').write_text('abcde\r\nfghlk\n\rmnopq', newline='\r') +- self.assertEqual((p / 'fileA').read_bytes(), +- b'abcde\r\rfghlk\r\rmnopq') +- # Check that `\r\n` character replaces `\n` +- (p / 'fileA').write_text('abcde\r\nfghlk\n\rmnopq', newline='\r\n') +- self.assertEqual((p / 'fileA').read_bytes(), +- b'abcde\r\r\nfghlk\r\n\rmnopq') +- # Check that no argument passed will change `\n` to `os.linesep` +- os_linesep_byte = bytes(os.linesep, encoding='ascii') +- (p / 'fileA').write_text('abcde\nfghlk\n\rmnopq') +- self.assertEqual((p / 'fileA').read_bytes(), +- b'abcde' + os_linesep_byte + b'fghlk' + os_linesep_byte + b'\rmnopq') ++ def test_glob_common(self): ++ def _check(glob, expected): ++ self.assertEqual(set(glob), { P(self.base, q) for q in expected }) ++ P = self.cls ++ p = P(self.base) ++ it = p.glob("fileA") ++ self.assertIsInstance(it, collections.abc.Iterator) ++ _check(it, ["fileA"]) ++ _check(p.glob("fileB"), []) ++ _check(p.glob("dir*/file*"), ["dirB/fileB", "dirC/fileC"]) ++ if not self.can_symlink: ++ _check(p.glob("*A"), ['dirA', 'fileA']) ++ else: ++ _check(p.glob("*A"), ['dirA', 'fileA', 'linkA']) ++ if not self.can_symlink: ++ _check(p.glob("*B/*"), ['dirB/fileB']) ++ else: ++ _check(p.glob("*B/*"), ['dirB/fileB', 'dirB/linkD', ++ 'linkB/fileB', 'linkB/linkD']) ++ if not self.can_symlink: ++ _check(p.glob("*/fileB"), ['dirB/fileB']) ++ else: ++ _check(p.glob("*/fileB"), ['dirB/fileB', 'linkB/fileB']) ++ if self.can_symlink: ++ _check(p.glob("brokenLink"), ['brokenLink']) + +- def test_copy_file(self): +- base = self.cls(self.base) +- source = base / 'fileA' +- target = base / 'copyA' +- result = source.copy(target) +- self.assertEqual(result, target) +- self.assertTrue(target.exists()) +- self.assertEqual(source.read_text(), target.read_text()) ++ if not self.can_symlink: ++ _check(p.glob("*/"), ["dirA/", "dirB/", "dirC/", "dirE/"]) ++ else: ++ _check(p.glob("*/"), ["dirA/", "dirB/", "dirC/", "dirE/", "linkB/"]) + +- def test_copy_file_to_existing_file(self): +- base = self.cls(self.base) +- source = base / 'fileA' +- target = base / 'dirB' / 'fileB' +- result = source.copy(target) +- self.assertEqual(result, target) +- self.assertTrue(target.exists()) +- self.assertEqual(source.read_text(), target.read_text()) ++ @needs_posix ++ def test_glob_posix(self): ++ P = self.cls ++ p = P(self.base) ++ q = p / "FILEa" ++ given = set(p.glob("FILEa")) ++ expect = {q} if q.exists() else set() ++ self.assertEqual(given, expect) ++ self.assertEqual(set(p.glob("FILEa*")), set()) + +- def test_copy_file_to_existing_directory(self): +- base = self.cls(self.base) +- source = base / 'fileA' +- target = base / 'dirA' +- self.assertRaises(OSError, source.copy, target) ++ @needs_windows ++ def test_glob_windows(self): ++ P = self.cls ++ p = P(self.base) ++ self.assertEqual(set(p.glob("FILEa")), { P(self.base, "fileA") }) ++ self.assertEqual(set(p.glob("*a\\")), { P(self.base, "dirA/") }) ++ self.assertEqual(set(p.glob("F*a")), { P(self.base, "fileA") }) + +- def test_copy_file_empty(self): +- base = self.cls(self.base) +- source = base / 'empty' +- target = base / 'copyA' +- source.write_bytes(b'') +- result = source.copy(target) +- self.assertEqual(result, target) +- self.assertTrue(target.exists()) +- self.assertEqual(target.read_bytes(), b'') +- +- def test_copy_file_to_itself(self): +- base = self.cls(self.base) +- source = base / 'empty' +- source.write_bytes(b'') +- self.assertRaises(OSError, source.copy, source) +- self.assertRaises(OSError, source.copy, source, follow_symlinks=False) +- +- def test_copy_dir_simple(self): +- base = self.cls(self.base) +- source = base / 'dirC' +- target = base / 'copyC' +- result = source.copy(target) +- self.assertEqual(result, target) +- self.assertTrue(target.is_dir()) +- self.assertTrue(target.joinpath('dirD').is_dir()) +- self.assertTrue(target.joinpath('dirD', 'fileD').is_file()) +- self.assertEqual(target.joinpath('dirD', 'fileD').read_text(), +- "this is file D\n") +- self.assertTrue(target.joinpath('fileC').is_file()) +- self.assertTrue(target.joinpath('fileC').read_text(), +- "this is file C\n") +- +- def test_copy_dir_complex(self, follow_symlinks=True): +- def ordered_walk(path): +- for dirpath, dirnames, filenames in path.walk(follow_symlinks=follow_symlinks): +- dirnames.sort() +- filenames.sort() +- yield dirpath, dirnames, filenames +- base = self.cls(self.base) +- source = base / 'dirC' +- +- if self.can_symlink: +- # Add some symlinks +- source.joinpath('linkC').symlink_to('fileC') +- source.joinpath('linkD').symlink_to('dirD', target_is_directory=True) +- +- # Perform the copy +- target = base / 'copyC' +- result = source.copy(target, follow_symlinks=follow_symlinks) +- self.assertEqual(result, target) +- +- # Compare the source and target trees +- source_walk = ordered_walk(source) +- target_walk = ordered_walk(target) +- for source_item, target_item in zip(source_walk, target_walk, strict=True): +- self.assertEqual(source_item[0].relative_to(source), +- target_item[0].relative_to(target)) # dirpath +- self.assertEqual(source_item[1], target_item[1]) # dirnames +- self.assertEqual(source_item[2], target_item[2]) # filenames +- # Compare files and symlinks +- for filename in source_item[2]: +- source_file = source_item[0].joinpath(filename) +- target_file = target_item[0].joinpath(filename) +- if follow_symlinks or not source_file.is_symlink(): +- # Regular file. +- self.assertEqual(source_file.read_bytes(), target_file.read_bytes()) +- elif source_file.is_dir(): +- # Symlink to directory. +- self.assertTrue(target_file.is_dir()) +- self.assertEqual(source_file.readlink(), target_file.readlink()) +- else: +- # Symlink to file. +- self.assertEqual(source_file.read_bytes(), target_file.read_bytes()) +- self.assertEqual(source_file.readlink(), target_file.readlink()) +- +- def test_copy_dir_complex_follow_symlinks_false(self): +- self.test_copy_dir_complex(follow_symlinks=False) +- +- def test_copy_dir_to_existing_directory(self): +- base = self.cls(self.base) +- source = base / 'dirC' +- target = base / 'copyC' +- target.mkdir() +- target.joinpath('dirD').mkdir() +- self.assertRaises(FileExistsError, source.copy, target) +- +- def test_copy_dir_to_existing_directory_dirs_exist_ok(self): +- base = self.cls(self.base) +- source = base / 'dirC' +- target = base / 'copyC' +- target.mkdir() +- target.joinpath('dirD').mkdir() +- result = source.copy(target, dirs_exist_ok=True) +- self.assertEqual(result, target) +- self.assertTrue(target.is_dir()) +- self.assertTrue(target.joinpath('dirD').is_dir()) +- self.assertTrue(target.joinpath('dirD', 'fileD').is_file()) +- self.assertEqual(target.joinpath('dirD', 'fileD').read_text(), +- "this is file D\n") +- self.assertTrue(target.joinpath('fileC').is_file()) +- self.assertTrue(target.joinpath('fileC').read_text(), +- "this is file C\n") +- +- def test_copy_dir_to_itself(self): +- base = self.cls(self.base) +- source = base / 'dirC' +- self.assertRaises(OSError, source.copy, source) +- self.assertRaises(OSError, source.copy, source, follow_symlinks=False) +- +- def test_copy_dir_into_itself(self): +- base = self.cls(self.base) +- source = base / 'dirC' +- target = base / 'dirC' / 'dirD' / 'copyC' +- self.assertRaises(OSError, source.copy, target) +- self.assertRaises(OSError, source.copy, target, follow_symlinks=False) +- self.assertFalse(target.exists()) +- +- def test_copy_into(self): +- base = self.cls(self.base) +- source = base / 'fileA' +- target_dir = base / 'dirA' +- result = source.copy_into(target_dir) +- self.assertEqual(result, target_dir / 'fileA') +- self.assertTrue(result.exists()) +- self.assertEqual(source.read_text(), result.read_text()) +- +- def test_copy_into_empty_name(self): +- source = self.cls('') +- target_dir = self.base +- self.assertRaises(ValueError, source.copy_into, target_dir) +- +- def test_move_file(self): +- base = self.cls(self.base) +- source = base / 'fileA' +- source_text = source.read_text() +- target = base / 'fileA_moved' +- result = source.move(target) +- self.assertEqual(result, target) +- self.assertFalse(source.exists()) +- self.assertTrue(target.exists()) +- self.assertEqual(source_text, target.read_text()) +- +- def test_move_file_to_file(self): +- base = self.cls(self.base) +- source = base / 'fileA' +- source_text = source.read_text() +- target = base / 'dirB' / 'fileB' +- result = source.move(target) +- self.assertEqual(result, target) +- self.assertFalse(source.exists()) +- self.assertTrue(target.exists()) +- self.assertEqual(source_text, target.read_text()) +- +- def test_move_file_to_dir(self): +- base = self.cls(self.base) +- source = base / 'fileA' +- target = base / 'dirB' +- self.assertRaises(OSError, source.move, target) +- +- def test_move_file_to_itself(self): +- base = self.cls(self.base) +- source = base / 'fileA' +- self.assertRaises(OSError, source.move, source) +- +- def test_move_dir(self): +- base = self.cls(self.base) +- source = base / 'dirC' +- target = base / 'dirC_moved' +- result = source.move(target) +- self.assertEqual(result, target) +- self.assertFalse(source.exists()) +- self.assertTrue(target.is_dir()) +- self.assertTrue(target.joinpath('dirD').is_dir()) +- self.assertTrue(target.joinpath('dirD', 'fileD').is_file()) +- self.assertEqual(target.joinpath('dirD', 'fileD').read_text(), +- "this is file D\n") +- self.assertTrue(target.joinpath('fileC').is_file()) +- self.assertTrue(target.joinpath('fileC').read_text(), +- "this is file C\n") +- +- def test_move_dir_to_dir(self): +- base = self.cls(self.base) +- source = base / 'dirC' +- target = base / 'dirB' +- self.assertRaises(OSError, source.move, target) +- self.assertTrue(source.exists()) +- self.assertTrue(target.exists()) +- +- def test_move_dir_to_itself(self): +- base = self.cls(self.base) +- source = base / 'dirC' +- self.assertRaises(OSError, source.move, source) +- self.assertTrue(source.exists()) +- +- def test_move_dir_into_itself(self): +- base = self.cls(self.base) +- source = base / 'dirC' +- target = base / 'dirC' / 'bar' +- self.assertRaises(OSError, source.move, target) +- self.assertTrue(source.exists()) +- self.assertFalse(target.exists()) +- +- def test_move_into(self): +- base = self.cls(self.base) +- source = base / 'fileA' +- source_text = source.read_text() +- target_dir = base / 'dirA' +- result = source.move_into(target_dir) +- self.assertEqual(result, target_dir / 'fileA') +- self.assertFalse(source.exists()) +- self.assertTrue(result.exists()) +- self.assertEqual(source_text, result.read_text()) +- +- def test_move_into_empty_name(self): +- source = self.cls('') +- target_dir = self.base +- self.assertRaises(ValueError, source.move_into, target_dir) +- +- def test_iterdir(self): +- P = self.cls +- p = P(self.base) +- it = p.iterdir() +- paths = set(it) +- expected = ['dirA', 'dirB', 'dirC', 'dirE', 'fileA'] +- if self.can_symlink: +- expected += ['linkA', 'linkB', 'brokenLink', 'brokenLinkLoop'] +- self.assertEqual(paths, { P(self.base, q) for q in expected }) +- +- def test_iterdir_nodir(self): +- # __iter__ on something that is not a directory. +- p = self.cls(self.base, 'fileA') +- with self.assertRaises(OSError) as cm: +- p.iterdir() +- # ENOENT or EINVAL under Windows, ENOTDIR otherwise +- # (see issue #12802). +- self.assertIn(cm.exception.errno, (errno.ENOTDIR, +- errno.ENOENT, errno.EINVAL)) +- +- def test_scandir(self): +- p = self.cls(self.base) +- with p._scandir() as entries: +- self.assertTrue(list(entries)) +- with p._scandir() as entries: +- for entry in entries: +- child = p / entry.name +- self.assertIsNotNone(entry) +- self.assertEqual(entry.name, child.name) +- self.assertEqual(entry.is_symlink(), +- child.is_symlink()) +- self.assertEqual(entry.is_dir(follow_symlinks=False), +- child.is_dir(follow_symlinks=False)) +- if entry.name != 'brokenLinkLoop': +- self.assertEqual(entry.is_dir(), child.is_dir()) +- +- def test_glob_common(self): +- def _check(glob, expected): +- self.assertEqual(set(glob), { P(self.base, q) for q in expected }) +- P = self.cls +- p = P(self.base) +- it = p.glob("fileA") +- self.assertIsInstance(it, collections.abc.Iterator) +- _check(it, ["fileA"]) +- _check(p.glob("fileB"), []) +- _check(p.glob("dir*/file*"), ["dirB/fileB", "dirC/fileC"]) +- if not self.can_symlink: +- _check(p.glob("*A"), ['dirA', 'fileA']) +- else: +- _check(p.glob("*A"), ['dirA', 'fileA', 'linkA']) +- if not self.can_symlink: +- _check(p.glob("*B/*"), ['dirB/fileB']) +- else: +- _check(p.glob("*B/*"), ['dirB/fileB', 'dirB/linkD', +- 'linkB/fileB', 'linkB/linkD']) +- if not self.can_symlink: +- _check(p.glob("*/fileB"), ['dirB/fileB']) +- else: +- _check(p.glob("*/fileB"), ['dirB/fileB', 'linkB/fileB']) +- if self.can_symlink: +- _check(p.glob("brokenLink"), ['brokenLink']) +- +- if not self.can_symlink: +- _check(p.glob("*/"), ["dirA/", "dirB/", "dirC/", "dirE/"]) +- else: +- _check(p.glob("*/"), ["dirA/", "dirB/", "dirC/", "dirE/", "linkB/"]) +- +- @needs_posix +- def test_glob_posix(self): +- P = self.cls +- p = P(self.base) +- q = p / "FILEa" +- given = set(p.glob("FILEa")) +- expect = {q} if q.exists() else set() +- self.assertEqual(given, expect) +- self.assertEqual(set(p.glob("FILEa*")), set()) +- +- @needs_windows +- def test_glob_windows(self): +- P = self.cls +- p = P(self.base) +- self.assertEqual(set(p.glob("FILEa")), { P(self.base, "fileA") }) +- self.assertEqual(set(p.glob("*a\\")), { P(self.base, "dirA/") }) +- self.assertEqual(set(p.glob("F*a")), { P(self.base, "fileA") }) +- +- def test_glob_empty_pattern(self): +- P = self.cls +- p = P(self.base) +- self.assertEqual(list(p.glob("")), [p]) ++ def test_glob_empty_pattern(self): ++ P = self.cls ++ p = P(self.base) ++ self.assertEqual(list(p.glob("")), [p.joinpath("")]) + + def test_glob_case_sensitive(self): + P = self.cls +@@ -1993,30 +1197,117 @@ + self.assertEqual(set(p.rglob("FILEd")), { P(self.base, "dirC/dirD/fileD") }) + self.assertEqual(set(p.rglob("*\\")), { P(self.base, "dirC/dirD/") }) + +- def test_stat(self): +- statA = self.cls(self.base).joinpath('fileA').stat() +- statB = self.cls(self.base).joinpath('dirB', 'fileB').stat() +- statC = self.cls(self.base).joinpath('dirC').stat() +- # st_mode: files are the same, directory differs. +- self.assertIsInstance(statA.st_mode, int) +- self.assertEqual(statA.st_mode, statB.st_mode) +- self.assertNotEqual(statA.st_mode, statC.st_mode) +- self.assertNotEqual(statB.st_mode, statC.st_mode) +- # st_ino: all different, +- self.assertIsInstance(statA.st_ino, int) +- self.assertNotEqual(statA.st_ino, statB.st_ino) +- self.assertNotEqual(statA.st_ino, statC.st_ino) +- self.assertNotEqual(statB.st_ino, statC.st_ino) +- # st_dev: all the same. +- self.assertIsInstance(statA.st_dev, int) +- self.assertEqual(statA.st_dev, statB.st_dev) +- self.assertEqual(statA.st_dev, statC.st_dev) +- # other attributes not used by pathlib. +- +- def test_stat_no_follow_symlinks_nosymlink(self): +- p = self.cls(self.base) / 'fileA' +- st = p.stat() +- self.assertEqual(st, p.stat(follow_symlinks=False)) ++ def test_info_exists(self): ++ p = self.cls(self.base) ++ self.assertTrue(p.info.exists()) ++ self.assertTrue((p / 'dirA').info.exists()) ++ self.assertTrue((p / 'dirA').info.exists(follow_symlinks=False)) ++ self.assertTrue((p / 'fileA').info.exists()) ++ self.assertTrue((p / 'fileA').info.exists(follow_symlinks=False)) ++ self.assertFalse((p / 'non-existing').info.exists()) ++ self.assertFalse((p / 'non-existing').info.exists(follow_symlinks=False)) ++ if self.can_symlink: ++ self.assertTrue((p / 'linkA').info.exists()) ++ self.assertTrue((p / 'linkA').info.exists(follow_symlinks=False)) ++ self.assertTrue((p / 'linkB').info.exists()) ++ self.assertTrue((p / 'linkB').info.exists(follow_symlinks=True)) ++ self.assertFalse((p / 'brokenLink').info.exists()) ++ self.assertTrue((p / 'brokenLink').info.exists(follow_symlinks=False)) ++ self.assertFalse((p / 'brokenLinkLoop').info.exists()) ++ self.assertTrue((p / 'brokenLinkLoop').info.exists(follow_symlinks=False)) ++ self.assertFalse((p / 'fileA\udfff').info.exists()) ++ self.assertFalse((p / 'fileA\udfff').info.exists(follow_symlinks=False)) ++ self.assertFalse((p / 'fileA\x00').info.exists()) ++ self.assertFalse((p / 'fileA\x00').info.exists(follow_symlinks=False)) ++ ++ def test_info_exists_caching(self): ++ p = self.cls(self.base) ++ q = p / 'myfile' ++ self.assertFalse(q.info.exists()) ++ self.assertFalse(q.info.exists(follow_symlinks=False)) ++ if isinstance(self.cls, WritablePath): ++ q.write_text('hullo') ++ self.assertFalse(q.info.exists()) ++ self.assertFalse(q.info.exists(follow_symlinks=False)) ++ ++ def test_info_is_dir(self): ++ p = self.cls(self.base) ++ self.assertTrue((p / 'dirA').info.is_dir()) ++ self.assertTrue((p / 'dirA').info.is_dir(follow_symlinks=False)) ++ self.assertFalse((p / 'fileA').info.is_dir()) ++ self.assertFalse((p / 'fileA').info.is_dir(follow_symlinks=False)) ++ self.assertFalse((p / 'non-existing').info.is_dir()) ++ self.assertFalse((p / 'non-existing').info.is_dir(follow_symlinks=False)) ++ if self.can_symlink: ++ self.assertFalse((p / 'linkA').info.is_dir()) ++ self.assertFalse((p / 'linkA').info.is_dir(follow_symlinks=False)) ++ self.assertTrue((p / 'linkB').info.is_dir()) ++ self.assertFalse((p / 'linkB').info.is_dir(follow_symlinks=False)) ++ self.assertFalse((p / 'brokenLink').info.is_dir()) ++ self.assertFalse((p / 'brokenLink').info.is_dir(follow_symlinks=False)) ++ self.assertFalse((p / 'brokenLinkLoop').info.is_dir()) ++ self.assertFalse((p / 'brokenLinkLoop').info.is_dir(follow_symlinks=False)) ++ self.assertFalse((p / 'dirA\udfff').info.is_dir()) ++ self.assertFalse((p / 'dirA\udfff').info.is_dir(follow_symlinks=False)) ++ self.assertFalse((p / 'dirA\x00').info.is_dir()) ++ self.assertFalse((p / 'dirA\x00').info.is_dir(follow_symlinks=False)) ++ ++ def test_info_is_dir_caching(self): ++ p = self.cls(self.base) ++ q = p / 'mydir' ++ self.assertFalse(q.info.is_dir()) ++ self.assertFalse(q.info.is_dir(follow_symlinks=False)) ++ if isinstance(self.cls, WritablePath): ++ q.mkdir() ++ self.assertFalse(q.info.is_dir()) ++ self.assertFalse(q.info.is_dir(follow_symlinks=False)) ++ ++ def test_info_is_file(self): ++ p = self.cls(self.base) ++ self.assertTrue((p / 'fileA').info.is_file()) ++ self.assertTrue((p / 'fileA').info.is_file(follow_symlinks=False)) ++ self.assertFalse((p / 'dirA').info.is_file()) ++ self.assertFalse((p / 'dirA').info.is_file(follow_symlinks=False)) ++ self.assertFalse((p / 'non-existing').info.is_file()) ++ self.assertFalse((p / 'non-existing').info.is_file(follow_symlinks=False)) ++ if self.can_symlink: ++ self.assertTrue((p / 'linkA').info.is_file()) ++ self.assertFalse((p / 'linkA').info.is_file(follow_symlinks=False)) ++ self.assertFalse((p / 'linkB').info.is_file()) ++ self.assertFalse((p / 'linkB').info.is_file(follow_symlinks=False)) ++ self.assertFalse((p / 'brokenLink').info.is_file()) ++ self.assertFalse((p / 'brokenLink').info.is_file(follow_symlinks=False)) ++ self.assertFalse((p / 'brokenLinkLoop').info.is_file()) ++ self.assertFalse((p / 'brokenLinkLoop').info.is_file(follow_symlinks=False)) ++ self.assertFalse((p / 'fileA\udfff').info.is_file()) ++ self.assertFalse((p / 'fileA\udfff').info.is_file(follow_symlinks=False)) ++ self.assertFalse((p / 'fileA\x00').info.is_file()) ++ self.assertFalse((p / 'fileA\x00').info.is_file(follow_symlinks=False)) ++ ++ def test_info_is_file_caching(self): ++ p = self.cls(self.base) ++ q = p / 'myfile' ++ self.assertFalse(q.info.is_file()) ++ self.assertFalse(q.info.is_file(follow_symlinks=False)) ++ if isinstance(self.cls, WritablePath): ++ q.write_text('hullo') ++ self.assertFalse(q.info.is_file()) ++ self.assertFalse(q.info.is_file(follow_symlinks=False)) ++ ++ def test_info_is_symlink(self): ++ p = self.cls(self.base) ++ self.assertFalse((p / 'fileA').info.is_symlink()) ++ self.assertFalse((p / 'dirA').info.is_symlink()) ++ self.assertFalse((p / 'non-existing').info.is_symlink()) ++ if self.can_symlink: ++ self.assertTrue((p / 'linkA').info.is_symlink()) ++ self.assertTrue((p / 'linkB').info.is_symlink()) ++ self.assertTrue((p / 'brokenLink').info.is_symlink()) ++ self.assertFalse((p / 'linkA\udfff').info.is_symlink()) ++ self.assertFalse((p / 'linkA\x00').info.is_symlink()) ++ self.assertTrue((p / 'brokenLinkLoop').info.is_symlink()) ++ self.assertFalse((p / 'fileA\udfff').info.is_symlink()) ++ self.assertFalse((p / 'fileA\x00').info.is_symlink()) + + def test_is_dir(self): + P = self.cls(self.base) +@@ -2086,90 +1377,262 @@ + self.assertIs((P / 'linkA\udfff').is_file(), False) + self.assertIs((P / 'linkA\x00').is_file(), False) + +- def test_delete_file(self): +- p = self.cls(self.base) / 'fileA' +- p._delete() +- self.assertFileNotFound(p.stat) +- self.assertFileNotFound(p._delete) + +- def test_delete_dir(self): ++class DummyWritablePathTest(DummyJoinablePathTest): ++ cls = DummyWritablePath ++ ++ ++class DummyRWPath(DummyWritablePath, DummyReadablePath): ++ __slots__ = () ++ ++ ++class DummyRWPathTest(DummyWritablePathTest, DummyReadablePathTest): ++ cls = DummyRWPath ++ can_symlink = False ++ ++ def test_read_write_bytes(self): ++ p = self.cls(self.base) ++ (p / 'fileA').write_bytes(b'abcdefg') ++ self.assertEqual((p / 'fileA').read_bytes(), b'abcdefg') ++ # Check that trying to write str does not truncate the file. ++ self.assertRaises(TypeError, (p / 'fileA').write_bytes, 'somestr') ++ self.assertEqual((p / 'fileA').read_bytes(), b'abcdefg') ++ ++ def test_read_write_text(self): ++ p = self.cls(self.base) ++ (p / 'fileA').write_text('äbcdefg', encoding='latin-1') ++ self.assertEqual((p / 'fileA').read_text( ++ encoding='utf-8', errors='ignore'), 'bcdefg') ++ # Check that trying to write bytes does not truncate the file. ++ self.assertRaises(TypeError, (p / 'fileA').write_text, b'somebytes') ++ self.assertEqual((p / 'fileA').read_text(encoding='latin-1'), 'äbcdefg') ++ ++ def test_read_text_with_newlines(self): ++ p = self.cls(self.base) ++ # Check that `\n` character change nothing ++ (p / 'fileA').write_bytes(b'abcde\r\nfghlk\n\rmnopq') ++ self.assertEqual((p / 'fileA').read_text(newline='\n'), ++ 'abcde\r\nfghlk\n\rmnopq') ++ # Check that `\r` character replaces `\n` ++ (p / 'fileA').write_bytes(b'abcde\r\nfghlk\n\rmnopq') ++ self.assertEqual((p / 'fileA').read_text(newline='\r'), ++ 'abcde\r\nfghlk\n\rmnopq') ++ # Check that `\r\n` character replaces `\n` ++ (p / 'fileA').write_bytes(b'abcde\r\nfghlk\n\rmnopq') ++ self.assertEqual((p / 'fileA').read_text(newline='\r\n'), ++ 'abcde\r\nfghlk\n\rmnopq') ++ ++ def test_write_text_with_newlines(self): ++ p = self.cls(self.base) ++ # Check that `\n` character change nothing ++ (p / 'fileA').write_text('abcde\r\nfghlk\n\rmnopq', newline='\n') ++ self.assertEqual((p / 'fileA').read_bytes(), ++ b'abcde\r\nfghlk\n\rmnopq') ++ # Check that `\r` character replaces `\n` ++ (p / 'fileA').write_text('abcde\r\nfghlk\n\rmnopq', newline='\r') ++ self.assertEqual((p / 'fileA').read_bytes(), ++ b'abcde\r\rfghlk\r\rmnopq') ++ # Check that `\r\n` character replaces `\n` ++ (p / 'fileA').write_text('abcde\r\nfghlk\n\rmnopq', newline='\r\n') ++ self.assertEqual((p / 'fileA').read_bytes(), ++ b'abcde\r\r\nfghlk\r\n\rmnopq') ++ # Check that no argument passed will change `\n` to `os.linesep` ++ os_linesep_byte = bytes(os.linesep, encoding='ascii') ++ (p / 'fileA').write_text('abcde\nfghlk\n\rmnopq') ++ self.assertEqual((p / 'fileA').read_bytes(), ++ b'abcde' + os_linesep_byte + b'fghlk' + os_linesep_byte + b'\rmnopq') ++ ++ def test_copy_file(self): ++ base = self.cls(self.base) ++ source = base / 'fileA' ++ target = base / 'copyA' ++ result = source.copy(target) ++ self.assertEqual(result, target) ++ self.assertTrue(target.exists()) ++ self.assertEqual(source.read_text(), target.read_text()) ++ ++ def test_copy_file_to_existing_file(self): ++ base = self.cls(self.base) ++ source = base / 'fileA' ++ target = base / 'dirB' / 'fileB' ++ result = source.copy(target) ++ self.assertEqual(result, target) ++ self.assertTrue(target.exists()) ++ self.assertEqual(source.read_text(), target.read_text()) ++ ++ def test_copy_file_to_existing_directory(self): ++ base = self.cls(self.base) ++ source = base / 'fileA' ++ target = base / 'dirA' ++ self.assertRaises(OSError, source.copy, target) ++ ++ def test_copy_file_empty(self): ++ base = self.cls(self.base) ++ source = base / 'empty' ++ target = base / 'copyA' ++ source.write_bytes(b'') ++ result = source.copy(target) ++ self.assertEqual(result, target) ++ self.assertTrue(target.exists()) ++ self.assertEqual(target.read_bytes(), b'') ++ ++ def test_copy_file_to_itself(self): ++ base = self.cls(self.base) ++ source = base / 'empty' ++ source.write_bytes(b'') ++ self.assertRaises(OSError, source.copy, source) ++ self.assertRaises(OSError, source.copy, source, follow_symlinks=False) ++ ++ def test_copy_dir_simple(self): ++ base = self.cls(self.base) ++ source = base / 'dirC' ++ target = base / 'copyC' ++ result = source.copy(target) ++ self.assertEqual(result, target) ++ self.assertTrue(target.is_dir()) ++ self.assertTrue(target.joinpath('dirD').is_dir()) ++ self.assertTrue(target.joinpath('dirD', 'fileD').is_file()) ++ self.assertEqual(target.joinpath('dirD', 'fileD').read_text(), ++ "this is file D\n") ++ self.assertTrue(target.joinpath('fileC').is_file()) ++ self.assertTrue(target.joinpath('fileC').read_text(), ++ "this is file C\n") ++ ++ def test_copy_dir_complex(self, follow_symlinks=True): ++ def ordered_walk(path): ++ for dirpath, dirnames, filenames in path.walk(follow_symlinks=follow_symlinks): ++ dirnames.sort() ++ filenames.sort() ++ yield dirpath, dirnames, filenames ++ base = self.cls(self.base) ++ source = base / 'dirC' ++ ++ if self.can_symlink: ++ # Add some symlinks ++ source.joinpath('linkC').symlink_to('fileC') ++ source.joinpath('linkD').symlink_to('dirD', target_is_directory=True) ++ ++ # Perform the copy ++ target = base / 'copyC' ++ result = source.copy(target, follow_symlinks=follow_symlinks) ++ self.assertEqual(result, target) ++ ++ # Compare the source and target trees ++ source_walk = ordered_walk(source) ++ target_walk = ordered_walk(target) ++ for source_item, target_item in zip(source_walk, target_walk, strict=True): ++ self.assertEqual(source_item[0].parts[len(source.parts):], ++ target_item[0].parts[len(target.parts):]) # dirpath ++ self.assertEqual(source_item[1], target_item[1]) # dirnames ++ self.assertEqual(source_item[2], target_item[2]) # filenames ++ # Compare files and symlinks ++ for filename in source_item[2]: ++ source_file = source_item[0].joinpath(filename) ++ target_file = target_item[0].joinpath(filename) ++ if follow_symlinks or not source_file.is_symlink(): ++ # Regular file. ++ self.assertEqual(source_file.read_bytes(), target_file.read_bytes()) ++ elif source_file.is_dir(): ++ # Symlink to directory. ++ self.assertTrue(target_file.is_dir()) ++ self.assertEqual(source_file.readlink(), target_file.readlink()) ++ else: ++ # Symlink to file. ++ self.assertEqual(source_file.read_bytes(), target_file.read_bytes()) ++ self.assertEqual(source_file.readlink(), target_file.readlink()) ++ ++ def test_copy_dir_complex_follow_symlinks_false(self): ++ self.test_copy_dir_complex(follow_symlinks=False) ++ ++ def test_copy_dir_to_existing_directory(self): ++ base = self.cls(self.base) ++ source = base / 'dirC' ++ target = base / 'copyC' ++ target.mkdir() ++ target.joinpath('dirD').mkdir() ++ self.assertRaises(FileExistsError, source.copy, target) ++ ++ def test_copy_dir_to_existing_directory_dirs_exist_ok(self): ++ base = self.cls(self.base) ++ source = base / 'dirC' ++ target = base / 'copyC' ++ target.mkdir() ++ target.joinpath('dirD').mkdir() ++ result = source.copy(target, dirs_exist_ok=True) ++ self.assertEqual(result, target) ++ self.assertTrue(target.is_dir()) ++ self.assertTrue(target.joinpath('dirD').is_dir()) ++ self.assertTrue(target.joinpath('dirD', 'fileD').is_file()) ++ self.assertEqual(target.joinpath('dirD', 'fileD').read_text(), ++ "this is file D\n") ++ self.assertTrue(target.joinpath('fileC').is_file()) ++ self.assertTrue(target.joinpath('fileC').read_text(), ++ "this is file C\n") ++ ++ def test_copy_dir_to_itself(self): ++ base = self.cls(self.base) ++ source = base / 'dirC' ++ self.assertRaises(OSError, source.copy, source) ++ self.assertRaises(OSError, source.copy, source, follow_symlinks=False) ++ ++ def test_copy_dir_into_itself(self): + base = self.cls(self.base) +- base.joinpath('dirA')._delete() +- self.assertRaises(FileNotFoundError, base.joinpath('dirA').stat) +- self.assertRaises(FileNotFoundError, base.joinpath('dirA', 'linkC').stat, +- follow_symlinks=False) +- base.joinpath('dirB')._delete() +- self.assertRaises(FileNotFoundError, base.joinpath('dirB').stat) +- self.assertRaises(FileNotFoundError, base.joinpath('dirB', 'fileB').stat) +- self.assertRaises(FileNotFoundError, base.joinpath('dirB', 'linkD').stat, +- follow_symlinks=False) +- base.joinpath('dirC')._delete() +- self.assertRaises(FileNotFoundError, base.joinpath('dirC').stat) +- self.assertRaises(FileNotFoundError, base.joinpath('dirC', 'dirD').stat) +- self.assertRaises(FileNotFoundError, base.joinpath('dirC', 'dirD', 'fileD').stat) +- self.assertRaises(FileNotFoundError, base.joinpath('dirC', 'fileC').stat) +- self.assertRaises(FileNotFoundError, base.joinpath('dirC', 'novel.txt').stat) +- +- def test_delete_missing(self): +- tmp = self.cls(self.base, 'delete') +- tmp.mkdir() +- # filename is guaranteed not to exist +- filename = tmp / 'foo' +- self.assertRaises(FileNotFoundError, filename._delete) +- +- +-class DummyPathWalkTest(unittest.TestCase): +- cls = DummyPath +- base = DummyPathTest.base ++ source = base / 'dirC' ++ target = base / 'dirC' / 'dirD' / 'copyC' ++ self.assertRaises(OSError, source.copy, target) ++ self.assertRaises(OSError, source.copy, target, follow_symlinks=False) ++ self.assertFalse(target.exists()) ++ ++ def test_copy_into(self): ++ base = self.cls(self.base) ++ source = base / 'fileA' ++ target_dir = base / 'dirA' ++ result = source.copy_into(target_dir) ++ self.assertEqual(result, target_dir / 'fileA') ++ self.assertTrue(result.exists()) ++ self.assertEqual(source.read_text(), result.read_text()) ++ ++ def test_copy_into_empty_name(self): ++ source = self.cls('') ++ target_dir = self.base ++ self.assertRaises(ValueError, source.copy_into, target_dir) ++ ++ ++class DummyReadablePathWalkTest(unittest.TestCase): ++ cls = DummyReadablePath ++ base = DummyReadablePathTest.base + can_symlink = False + + def setUp(self): +- # Build: +- # TESTFN/ +- # TEST1/ a file kid and two directory kids +- # tmp1 +- # SUB1/ a file kid and a directory kid +- # tmp2 +- # SUB11/ no kids +- # SUB2/ a file kid and a dirsymlink kid +- # tmp3 +- # link/ a symlink to TEST2 +- # broken_link +- # broken_link2 +- # TEST2/ +- # tmp4 a lone file + self.walk_path = self.cls(self.base, "TEST1") + self.sub1_path = self.walk_path / "SUB1" + self.sub11_path = self.sub1_path / "SUB11" + self.sub2_path = self.walk_path / "SUB2" +- tmp1_path = self.walk_path / "tmp1" +- tmp2_path = self.sub1_path / "tmp2" +- tmp3_path = self.sub2_path / "tmp3" + self.link_path = self.sub2_path / "link" +- t2_path = self.cls(self.base, "TEST2") +- tmp4_path = self.cls(self.base, "TEST2", "tmp4") +- broken_link_path = self.sub2_path / "broken_link" +- broken_link2_path = self.sub2_path / "broken_link2" +- +- self.sub11_path.mkdir(parents=True) +- self.sub2_path.mkdir(parents=True) +- t2_path.mkdir(parents=True) +- +- for path in tmp1_path, tmp2_path, tmp3_path, tmp4_path: +- with path.open("w", encoding='utf-8') as f: +- f.write(f"I'm {path} and proud of it. Blame test_pathlib.\n") ++ self.sub2_tree = (self.sub2_path, [], ["tmp3"]) ++ self.createTestHierarchy() + +- if self.can_symlink: +- self.link_path.symlink_to(t2_path, target_is_directory=True) +- broken_link_path.symlink_to('broken') +- broken_link2_path.symlink_to(self.cls('tmp3', 'broken')) +- self.sub2_tree = (self.sub2_path, [], ["broken_link", "broken_link2", "link", "tmp3"]) +- else: +- self.sub2_tree = (self.sub2_path, [], ["tmp3"]) ++ def createTestHierarchy(self): ++ cls = self.cls ++ cls._files = { ++ f'{self.base}/TEST1/tmp1': b'this is tmp1\n', ++ f'{self.base}/TEST1/SUB1/tmp2': b'this is tmp2\n', ++ f'{self.base}/TEST1/SUB2/tmp3': b'this is tmp3\n', ++ f'{self.base}/TEST2/tmp4': b'this is tmp4\n', ++ } ++ cls._directories = { ++ f'{self.base}': {'TEST1', 'TEST2'}, ++ f'{self.base}/TEST1': {'SUB1', 'SUB2', 'tmp1'}, ++ f'{self.base}/TEST1/SUB1': {'SUB11', 'tmp2'}, ++ f'{self.base}/TEST1/SUB1/SUB11': set(), ++ f'{self.base}/TEST1/SUB2': {'tmp3'}, ++ f'{self.base}/TEST2': {'tmp4'}, ++ } + + def tearDown(self): +- base = self.cls(self.base) +- base._delete() ++ cls = self.cls ++ cls._files.clear() ++ cls._directories.clear() + + def test_walk_topdown(self): + walker = self.walk_path.walk() +diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py +index 48a4c568651..4d371a6e754 100644 +--- a/Lib/test/test_pdb.py ++++ b/Lib/test/test_pdb.py +@@ -20,8 +20,7 @@ + from test.support.pty_helper import run_pty, FakeInput + from unittest.mock import patch + +-# gh-114275: WASI fails to run asyncio tests, similar skip than test_asyncio. +-SKIP_ASYNCIO_TESTS = (not support.has_socket_support) ++SKIP_CORO_TESTS = False + + + class PdbTestInput(object): +@@ -1987,7 +1986,7 @@ + """ + + def test_pdb_next_command_for_generator(): +- """Testing skip unwindng stack on yield for generators for "next" command ++ """Testing skip unwinding stack on yield for generators for "next" command + + >>> def test_gen(): + ... yield 0 +@@ -2049,26 +2048,23 @@ + finished + """ + +-if not SKIP_ASYNCIO_TESTS: ++if not SKIP_CORO_TESTS: + def test_pdb_next_command_for_coroutine(): +- """Testing skip unwindng stack on yield for coroutines for "next" command ++ """Testing skip unwinding stack on yield for coroutines for "next" command + +- >>> import asyncio ++ >>> from test.support import run_yielding_async_fn, async_yield + + >>> async def test_coro(): +- ... await asyncio.sleep(0) +- ... await asyncio.sleep(0) +- ... await asyncio.sleep(0) ++ ... await async_yield(0) ++ ... await async_yield(0) ++ ... await async_yield(0) + + >>> async def test_main(): + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... await test_coro() + + >>> def test_function(): +- ... loop = asyncio.new_event_loop() +- ... loop.run_until_complete(test_main()) +- ... loop.close() +- ... asyncio.set_event_loop_policy(None) ++ ... run_yielding_async_fn(test_main) + ... print("finished") + + >>> with PdbTestInput(['step', +@@ -2091,13 +2087,13 @@ + -> async def test_coro(): + (Pdb) step + > (2)test_coro() +- -> await asyncio.sleep(0) ++ -> await async_yield(0) + (Pdb) next + > (3)test_coro() +- -> await asyncio.sleep(0) ++ -> await async_yield(0) + (Pdb) next + > (4)test_coro() +- -> await asyncio.sleep(0) ++ -> await async_yield(0) + (Pdb) next + Internal StopIteration + > (3)test_main() +@@ -2111,13 +2107,13 @@ + """ + + def test_pdb_next_command_for_asyncgen(): +- """Testing skip unwindng stack on yield for coroutines for "next" command ++ """Testing skip unwinding stack on yield for coroutines for "next" command + +- >>> import asyncio ++ >>> from test.support import run_yielding_async_fn, async_yield + + >>> async def agen(): + ... yield 1 +- ... await asyncio.sleep(0) ++ ... await async_yield(0) + ... yield 2 + + >>> async def test_coro(): +@@ -2129,10 +2125,7 @@ + ... await test_coro() + + >>> def test_function(): +- ... loop = asyncio.new_event_loop() +- ... loop.run_until_complete(test_main()) +- ... loop.close() +- ... asyncio.set_event_loop_policy(None) ++ ... run_yielding_async_fn(test_main) + ... print("finished") + + >>> with PdbTestInput(['step', +@@ -2169,14 +2162,14 @@ + -> yield 1 + (Pdb) next + > (3)agen() +- -> await asyncio.sleep(0) ++ -> await async_yield(0) + (Pdb) continue + 2 + finished + """ + + def test_pdb_return_command_for_generator(): +- """Testing no unwindng stack on yield for generators ++ """Testing no unwinding stack on yield for generators + for "return" command + + >>> def test_gen(): +@@ -2234,26 +2227,23 @@ + finished + """ + +-if not SKIP_ASYNCIO_TESTS: ++if not SKIP_CORO_TESTS: + def test_pdb_return_command_for_coroutine(): +- """Testing no unwindng stack on yield for coroutines for "return" command ++ """Testing no unwinding stack on yield for coroutines for "return" command + +- >>> import asyncio ++ >>> from test.support import run_yielding_async_fn, async_yield + + >>> async def test_coro(): +- ... await asyncio.sleep(0) +- ... await asyncio.sleep(0) +- ... await asyncio.sleep(0) ++ ... await async_yield(0) ++ ... await async_yield(0) ++ ... await async_yield(0) + + >>> async def test_main(): + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... await test_coro() + + >>> def test_function(): +- ... loop = asyncio.new_event_loop() +- ... loop.run_until_complete(test_main()) +- ... loop.close() +- ... asyncio.set_event_loop_policy(None) ++ ... run_yielding_async_fn(test_main) + ... print("finished") + + >>> with PdbTestInput(['step', +@@ -2273,16 +2263,16 @@ + -> async def test_coro(): + (Pdb) step + > (2)test_coro() +- -> await asyncio.sleep(0) ++ -> await async_yield(0) + (Pdb) next + > (3)test_coro() +- -> await asyncio.sleep(0) ++ -> await async_yield(0) + (Pdb) continue + finished + """ + + def test_pdb_until_command_for_generator(): +- """Testing no unwindng stack on yield for generators ++ """Testing no unwinding stack on yield for generators + for "until" command if target breakpoint is not reached + + >>> def test_gen(): +@@ -2329,20 +2319,20 @@ + finished + """ + +-if not SKIP_ASYNCIO_TESTS: ++if not SKIP_CORO_TESTS: + def test_pdb_until_command_for_coroutine(): +- """Testing no unwindng stack for coroutines ++ """Testing no unwinding stack for coroutines + for "until" command if target breakpoint is not reached + +- >>> import asyncio ++ >>> from test.support import run_yielding_async_fn, async_yield + + >>> async def test_coro(): + ... print(0) +- ... await asyncio.sleep(0) ++ ... await async_yield(0) + ... print(1) +- ... await asyncio.sleep(0) ++ ... await async_yield(0) + ... print(2) +- ... await asyncio.sleep(0) ++ ... await async_yield(0) + ... print(3) + + >>> async def test_main(): +@@ -2350,10 +2340,7 @@ + ... await test_coro() + + >>> def test_function(): +- ... loop = asyncio.new_event_loop() +- ... loop.run_until_complete(test_main()) +- ... loop.close() +- ... asyncio.set_event_loop_policy(None) ++ ... run_yielding_async_fn(test_main) + ... print("finished") + + >>> with PdbTestInput(['step', +@@ -3022,6 +3009,57 @@ + (Pdb) continue + """ + ++def test_pdb_frame_refleak(): ++ """ ++ pdb should not leak reference to frames ++ ++ >>> def frame_leaker(container): ++ ... import sys ++ ... container.append(sys._getframe()) ++ ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() ++ ... pass ++ ++ >>> def test_function(): ++ ... import gc ++ ... container = [] ++ ... frame_leaker(container) # c ++ ... print(len(gc.get_referrers(container[0]))) ++ ... container = [] ++ ... frame_leaker(container) # n c ++ ... print(len(gc.get_referrers(container[0]))) ++ ... container = [] ++ ... frame_leaker(container) # r c ++ ... print(len(gc.get_referrers(container[0]))) ++ ++ >>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE ++ ... 'continue', ++ ... 'next', ++ ... 'continue', ++ ... 'return', ++ ... 'continue', ++ ... ]): ++ ... test_function() ++ > (4)frame_leaker() ++ -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() ++ (Pdb) continue ++ 1 ++ > (4)frame_leaker() ++ -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() ++ (Pdb) next ++ > (5)frame_leaker() ++ -> pass ++ (Pdb) continue ++ 1 ++ > (4)frame_leaker() ++ -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() ++ (Pdb) return ++ --Return-- ++ > (5)frame_leaker()->None ++ -> pass ++ (Pdb) continue ++ 1 ++ """ ++ + def test_pdb_function_break(): + """Testing the line number of break on function + +@@ -3165,16 +3203,12 @@ + self.addCleanup(os_helper.unlink, '.pdbrc') + self.addCleanup(os_helper.unlink, filename) + +- homesave = None +- if remove_home: +- homesave = os.environ.pop('HOME', None) +- try: ++ with os_helper.EnvironmentVarGuard() as env: ++ if remove_home: ++ env.unset('HOME') + if script_args is None: + script_args = [] + stdout, stderr = self._run_pdb([filename] + script_args, commands, expected_returncode, extra_env) +- finally: +- if homesave is not None: +- os.environ['HOME'] = homesave + return stdout, stderr + + def run_pdb_module(self, script, commands): +@@ -3598,17 +3632,14 @@ + self.assertIn("NameError: name 'invalid' is not defined", stdout) + + def test_readrc_homedir(self): +- save_home = os.environ.pop("HOME", None) +- with os_helper.temp_dir() as temp_dir, patch("os.path.expanduser"): +- rc_path = os.path.join(temp_dir, ".pdbrc") +- os.path.expanduser.return_value = rc_path +- try: ++ with os_helper.EnvironmentVarGuard() as env: ++ env.unset("HOME") ++ with os_helper.temp_dir() as temp_dir, patch("os.path.expanduser"): ++ rc_path = os.path.join(temp_dir, ".pdbrc") ++ os.path.expanduser.return_value = rc_path + with open(rc_path, "w") as f: + f.write("invalid") + self.assertEqual(pdb.Pdb().rcLines[0], "invalid") +- finally: +- if save_home is not None: +- os.environ["HOME"] = save_home + + def test_header(self): + stdout = StringIO() +@@ -4206,6 +4237,62 @@ + self.assertFalse(db.checkline(os_helper.TESTFN, lineno)) + + ++@support.requires_subprocess() ++class PdbTestInline(unittest.TestCase): ++ @unittest.skipIf(sys.flags.safe_path, ++ 'PYTHONSAFEPATH changes default sys.path') ++ def _run_script(self, script, commands, ++ expected_returncode=0, ++ extra_env=None): ++ self.addCleanup(os_helper.rmtree, '__pycache__') ++ filename = 'main.py' ++ with open(filename, 'w') as f: ++ f.write(textwrap.dedent(script)) ++ self.addCleanup(os_helper.unlink, filename) ++ ++ commands = textwrap.dedent(commands) ++ ++ cmd = [sys.executable, 'main.py'] ++ if extra_env is not None: ++ env = os.environ | extra_env ++ else: ++ env = os.environ ++ with subprocess.Popen( ++ cmd, ++ stdout=subprocess.PIPE, ++ stdin=subprocess.PIPE, ++ stderr=subprocess.PIPE, ++ env = {**env, 'PYTHONIOENCODING': 'utf-8'} ++ ) as proc: ++ stdout, stderr = proc.communicate(str.encode(commands)) ++ stdout = bytes.decode(stdout) if isinstance(stdout, bytes) else stdout ++ stderr = bytes.decode(stderr) if isinstance(stderr, bytes) else stderr ++ self.assertEqual( ++ proc.returncode, ++ expected_returncode, ++ f"Unexpected return code\nstdout: {stdout}\nstderr: {stderr}" ++ ) ++ return stdout, stderr ++ ++ def test_quit(self): ++ script = """ ++ x = 1 ++ breakpoint() ++ """ ++ ++ commands = """ ++ quit ++ n ++ p x + 1 ++ quit ++ y ++ """ ++ ++ stdout, stderr = self._run_script(script, commands) ++ self.assertIn("2", stdout) ++ self.assertIn("Quit anyway", stdout) ++ ++ + @support.requires_subprocess() + class PdbTestReadline(unittest.TestCase): + def setUpClass(): +diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py +index c7da151dce3..ed92e5257df 100644 +--- a/Lib/test/test_peepholer.py ++++ b/Lib/test/test_peepholer.py +@@ -1,5 +1,6 @@ + import dis + from itertools import combinations, product ++import opcode + import sys + import textwrap + import unittest +@@ -35,6 +36,13 @@ + return count + + ++def get_binop_argval(arg): ++ for i, nb_op in enumerate(opcode._nb_ops): ++ if arg == nb_op[0]: ++ return i ++ assert False, f"{arg} is not a valid BINARY_OP argument." ++ ++ + class TestTranforms(BytecodeTestCase): + + def check_jump_targets(self, code): +@@ -280,23 +288,23 @@ + # valid code get optimized + code = compile('"foo"[0]', '', 'single') + self.assertInBytecode(code, 'LOAD_CONST', 'f') +- self.assertNotInBytecode(code, 'BINARY_SUBSCR') ++ self.assertNotInBytecode(code, 'BINARY_OP') + self.check_lnotab(code) + code = compile('"\u0061\uffff"[1]', '', 'single') + self.assertInBytecode(code, 'LOAD_CONST', '\uffff') +- self.assertNotInBytecode(code,'BINARY_SUBSCR') ++ self.assertNotInBytecode(code,'BINARY_OP') + self.check_lnotab(code) + + # With PEP 393, non-BMP char get optimized + code = compile('"\U00012345"[0]', '', 'single') + self.assertInBytecode(code, 'LOAD_CONST', '\U00012345') +- self.assertNotInBytecode(code, 'BINARY_SUBSCR') ++ self.assertNotInBytecode(code, 'BINARY_OP') + self.check_lnotab(code) + + # invalid code doesn't get optimized + # out of range + code = compile('"fuu"[10]', '', 'single') +- self.assertInBytecode(code, 'BINARY_SUBSCR') ++ self.assertInBytecode(code, 'BINARY_OP') + self.check_lnotab(code) + + def test_folding_of_unaryops_on_constants(self): +@@ -473,6 +481,60 @@ + self.assertFalse(instr.opname.startswith('BUILD_')) + self.check_lnotab(code) + ++ def test_constant_folding_small_int(self): ++ tests = [ ++ # subscript ++ ('(0, )[0]', 0), ++ ('(1 + 2, )[0]', 3), ++ ('(2 + 2 * 2, )[0]', 6), ++ ('(1, (1 + 2 + 3, ))[1][0]', 6), ++ ('(255, )[0]', 255), ++ ('(256, )[0]', None), ++ ('(1000, )[0]', None), ++ ('(1 - 2, )[0]', None), ++ ] ++ for expr, oparg in tests: ++ with self.subTest(expr=expr, oparg=oparg): ++ code = compile(expr, '', 'single') ++ if oparg is not None: ++ self.assertInBytecode(code, 'LOAD_SMALL_INT', oparg) ++ else: ++ self.assertNotInBytecode(code, 'LOAD_SMALL_INT') ++ self.check_lnotab(code) ++ ++ def test_folding_subscript(self): ++ tests = [ ++ ('(1, )[0]', False), ++ ('(1, )[-1]', False), ++ ('(1 + 2, )[0]', False), ++ ('(1, (1, 2))[1][1]', False), ++ ('(1, 2)[2-1]', False), ++ ('(1, (1, 2))[1][2-1]', False), ++ ('(1, (1, 2))[1:6][0][2-1]', False), ++ ('"a"[0]', False), ++ ('("a" + "b")[1]', False), ++ ('("a" + "b", )[0][1]', False), ++ ('("a" * 10)[9]', False), ++ ('(1, )[1]', True), ++ ('(1, )[-2]', True), ++ ('"a"[1]', True), ++ ('"a"[-2]', True), ++ ('("a" + "b")[2]', True), ++ ('("a" + "b", )[0][2]', True), ++ ('("a" + "b", )[1][0]', True), ++ ('("a" * 10)[10]', True), ++ ('(1, (1, 2))[2:6][0][2-1]', True), ++ ] ++ subscr_argval = get_binop_argval('NB_SUBSCR') ++ for expr, has_error in tests: ++ with self.subTest(expr=expr, has_error=has_error): ++ code = compile(expr, '', 'single') ++ if not has_error: ++ self.assertNotInBytecode(code, 'BINARY_OP', argval=subscr_argval) ++ else: ++ self.assertInBytecode(code, 'BINARY_OP', argval=subscr_argval) ++ self.check_lnotab(code) ++ + def test_in_literal_list(self): + def containtest(): + return x in [a, b] +@@ -1006,6 +1068,200 @@ + consts=[0, 1, 2, 3, 4], + expected_consts=[0, 2, 3]) + ++ def test_list_exceeding_stack_use_guideline(self): ++ def f(): ++ return [ ++ 0, 1, 2, 3, 4, ++ 5, 6, 7, 8, 9, ++ 10, 11, 12, 13, 14, ++ 15, 16, 17, 18, 19, ++ 20, 21, 22, 23, 24, ++ 25, 26, 27, 28, 29, ++ 30, 31, 32, 33, 34, ++ 35, 36, 37, 38, 39 ++ ] ++ self.assertEqual(f(), list(range(40))) ++ ++ def test_set_exceeding_stack_use_guideline(self): ++ def f(): ++ return { ++ 0, 1, 2, 3, 4, ++ 5, 6, 7, 8, 9, ++ 10, 11, 12, 13, 14, ++ 15, 16, 17, 18, 19, ++ 20, 21, 22, 23, 24, ++ 25, 26, 27, 28, 29, ++ 30, 31, 32, 33, 34, ++ 35, 36, 37, 38, 39 ++ } ++ self.assertEqual(f(), frozenset(range(40))) ++ ++ def test_multiple_foldings(self): ++ before = [ ++ ('LOAD_SMALL_INT', 1, 0), ++ ('LOAD_SMALL_INT', 2, 0), ++ ('BUILD_TUPLE', 1, 0), ++ ('LOAD_SMALL_INT', 0, 0), ++ ('BINARY_OP', get_binop_argval('NB_SUBSCR'), 0), ++ ('BUILD_TUPLE', 2, 0), ++ ('RETURN_VALUE', None, 0) ++ ] ++ after = [ ++ ('LOAD_CONST', 1, 0), ++ ('RETURN_VALUE', None, 0) ++ ] ++ self.cfg_optimization_test(before, after, consts=[], expected_consts=[(2,), (1, 2)]) ++ ++ def test_build_empty_tuple(self): ++ before = [ ++ ('BUILD_TUPLE', 0, 0), ++ ('RETURN_VALUE', None, 0), ++ ] ++ after = [ ++ ('LOAD_CONST', 0, 0), ++ ('RETURN_VALUE', None, 0), ++ ] ++ self.cfg_optimization_test(before, after, consts=[], expected_consts=[()]) ++ ++ def test_fold_tuple_of_constants(self): ++ before = [ ++ ('NOP', None, 0), ++ ('LOAD_SMALL_INT', 1, 0), ++ ('NOP', None, 0), ++ ('LOAD_SMALL_INT', 2, 0), ++ ('NOP', None, 0), ++ ('NOP', None, 0), ++ ('LOAD_SMALL_INT', 3, 0), ++ ('NOP', None, 0), ++ ('BUILD_TUPLE', 3, 0), ++ ('RETURN_VALUE', None, 0), ++ ] ++ after = [ ++ ('LOAD_CONST', 0, 0), ++ ('RETURN_VALUE', None, 0), ++ ] ++ self.cfg_optimization_test(before, after, consts=[], expected_consts=[(1, 2, 3)]) ++ ++ # not enough consts ++ same = [ ++ ('LOAD_SMALL_INT', 1, 0), ++ ('LOAD_SMALL_INT', 2, 0), ++ ('BUILD_TUPLE', 3, 0), ++ ('RETURN_VALUE', None, 0) ++ ] ++ self.cfg_optimization_test(same, same, consts=[]) ++ ++ # not all consts ++ same = [ ++ ('LOAD_SMALL_INT', 1, 0), ++ ('LOAD_NAME', 0, 0), ++ ('LOAD_SMALL_INT', 2, 0), ++ ('BUILD_TUPLE', 3, 0), ++ ('RETURN_VALUE', None, 0) ++ ] ++ self.cfg_optimization_test(same, same, consts=[]) ++ ++ def test_optimize_if_const_list(self): ++ before = [ ++ ('NOP', None, 0), ++ ('LOAD_SMALL_INT', 1, 0), ++ ('NOP', None, 0), ++ ('LOAD_SMALL_INT', 2, 0), ++ ('NOP', None, 0), ++ ('NOP', None, 0), ++ ('LOAD_SMALL_INT', 3, 0), ++ ('NOP', None, 0), ++ ('BUILD_LIST', 3, 0), ++ ('RETURN_VALUE', None, 0), ++ ] ++ after = [ ++ ('BUILD_LIST', 0, 0), ++ ('LOAD_CONST', 0, 0), ++ ('LIST_EXTEND', 1, 0), ++ ('RETURN_VALUE', None, 0), ++ ] ++ self.cfg_optimization_test(before, after, consts=[], expected_consts=[(1, 2, 3)]) ++ ++ # need minimum 3 consts to optimize ++ same = [ ++ ('LOAD_SMALL_INT', 1, 0), ++ ('LOAD_SMALL_INT', 2, 0), ++ ('BUILD_LIST', 2, 0), ++ ('RETURN_VALUE', None, 0), ++ ] ++ self.cfg_optimization_test(same, same, consts=[]) ++ ++ # not enough consts ++ same = [ ++ ('LOAD_SMALL_INT', 1, 0), ++ ('LOAD_SMALL_INT', 2, 0), ++ ('LOAD_SMALL_INT', 3, 0), ++ ('BUILD_LIST', 4, 0), ++ ('RETURN_VALUE', None, 0), ++ ] ++ self.cfg_optimization_test(same, same, consts=[]) ++ ++ # not all consts ++ same = [ ++ ('LOAD_SMALL_INT', 1, 0), ++ ('LOAD_NAME', 0, 0), ++ ('LOAD_SMALL_INT', 3, 0), ++ ('BUILD_LIST', 3, 0), ++ ('RETURN_VALUE', None, 0), ++ ] ++ self.cfg_optimization_test(same, same, consts=[]) ++ ++ def test_optimize_if_const_set(self): ++ before = [ ++ ('NOP', None, 0), ++ ('LOAD_SMALL_INT', 1, 0), ++ ('NOP', None, 0), ++ ('LOAD_SMALL_INT', 2, 0), ++ ('NOP', None, 0), ++ ('NOP', None, 0), ++ ('LOAD_SMALL_INT', 3, 0), ++ ('NOP', None, 0), ++ ('BUILD_SET', 3, 0), ++ ('RETURN_VALUE', None, 0), ++ ] ++ after = [ ++ ('BUILD_SET', 0, 0), ++ ('LOAD_CONST', 0, 0), ++ ('SET_UPDATE', 1, 0), ++ ('RETURN_VALUE', None, 0), ++ ] ++ self.cfg_optimization_test(before, after, consts=[], expected_consts=[frozenset({1, 2, 3})]) ++ ++ # need minimum 3 consts to optimize ++ same = [ ++ ('LOAD_SMALL_INT', 1, 0), ++ ('LOAD_SMALL_INT', 2, 0), ++ ('BUILD_SET', 2, 0), ++ ('RETURN_VALUE', None, 0), ++ ] ++ self.cfg_optimization_test(same, same, consts=[]) ++ ++ # not enough consts ++ same = [ ++ ('LOAD_SMALL_INT', 1, 0), ++ ('LOAD_SMALL_INT', 2, 0), ++ ('LOAD_SMALL_INT', 3, 0), ++ ('BUILD_SET', 4, 0), ++ ('RETURN_VALUE', None, 0), ++ ] ++ self.cfg_optimization_test(same, same, consts=[]) ++ ++ # not all consts ++ same = [ ++ ('LOAD_SMALL_INT', 1, 0), ++ ('LOAD_NAME', 0, 0), ++ ('LOAD_SMALL_INT', 3, 0), ++ ('BUILD_SET', 3, 0), ++ ('RETURN_VALUE', None, 0), ++ ] ++ self.cfg_optimization_test(same, same, consts=[]) ++ ++ + def test_conditional_jump_forward_const_condition(self): + # The unreachable branch of the jump is removed, the jump + # becomes redundant and is replaced by a NOP (for the lineno) +@@ -1193,5 +1449,56 @@ + ] + self.cfg_optimization_test(insts, expected_insts, consts=list(range(5))) + ++ def test_list_to_tuple_get_iter(self): ++ # for _ in (*foo, *bar) -> for _ in [*foo, *bar] ++ INTRINSIC_LIST_TO_TUPLE = 6 ++ insts = [ ++ ("BUILD_LIST", 0, 1), ++ ("LOAD_FAST", 0, 2), ++ ("LIST_EXTEND", 1, 3), ++ ("LOAD_FAST", 1, 4), ++ ("LIST_EXTEND", 1, 5), ++ ("CALL_INTRINSIC_1", INTRINSIC_LIST_TO_TUPLE, 6), ++ ("GET_ITER", None, 7), ++ top := self.Label(), ++ ("FOR_ITER", end := self.Label(), 8), ++ ("STORE_FAST", 2, 9), ++ ("JUMP", top, 10), ++ end, ++ ("END_FOR", None, 11), ++ ("POP_TOP", None, 12), ++ ("LOAD_CONST", 0, 13), ++ ("RETURN_VALUE", None, 14), ++ ] ++ expected_insts = [ ++ ("BUILD_LIST", 0, 1), ++ ("LOAD_FAST", 0, 2), ++ ("LIST_EXTEND", 1, 3), ++ ("LOAD_FAST", 1, 4), ++ ("LIST_EXTEND", 1, 5), ++ ("NOP", None, 6), # ("CALL_INTRINSIC_1", INTRINSIC_LIST_TO_TUPLE, 6), ++ ("GET_ITER", None, 7), ++ top := self.Label(), ++ ("FOR_ITER", end := self.Label(), 8), ++ ("STORE_FAST", 2, 9), ++ ("JUMP", top, 10), ++ end, ++ ("END_FOR", None, 11), ++ ("POP_TOP", None, 12), ++ ("LOAD_CONST", 0, 13), ++ ("RETURN_VALUE", None, 14), ++ ] ++ self.cfg_optimization_test(insts, expected_insts, consts=[None]) ++ ++ def test_list_to_tuple_get_iter_is_safe(self): ++ a, b = [], [] ++ for item in (*(items := [0, 1, 2, 3]),): ++ a.append(item) ++ b.append(items.pop()) ++ self.assertEqual(a, [0, 1, 2, 3]) ++ self.assertEqual(b, [3, 2, 1, 0]) ++ self.assertEqual(items, []) ++ ++ + if __name__ == "__main__": + unittest.main() +diff --git a/Lib/test/test_perf_profiler.py b/Lib/test/test_perf_profiler.py +index 1e749908780..6f1fd8d38e4 100644 +--- a/Lib/test/test_perf_profiler.py ++++ b/Lib/test/test_perf_profiler.py +@@ -47,6 +47,7 @@ + for file in files_to_delete: + file.unlink() + ++ @unittest.skipIf(support.check_bolt_optimized, "fails on BOLT instrumented binaries") + def test_trampoline_works(self): + code = """if 1: + def foo(): +@@ -100,6 +101,7 @@ + "Address should contain only hex characters", + ) + ++ @unittest.skipIf(support.check_bolt_optimized, "fails on BOLT instrumented binaries") + def test_trampoline_works_with_forks(self): + code = """if 1: + import os, sys +@@ -160,6 +162,7 @@ + self.assertIn(f"py::bar_fork:{script}", child_perf_file_contents) + self.assertIn(f"py::baz_fork:{script}", child_perf_file_contents) + ++ @unittest.skipIf(support.check_bolt_optimized, "fails on BOLT instrumented binaries") + def test_sys_api(self): + code = """if 1: + import sys +diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py +index 4bf0576586c..74910980567 100644 +--- a/Lib/test/test_pyclbr.py ++++ b/Lib/test/test_pyclbr.py +@@ -31,14 +31,6 @@ + print("l1=%r\nl2=%r\nignore=%r" % (l1, l2, ignore), file=sys.stderr) + self.fail("%r missing" % missing.pop()) + +- def assertHasattr(self, obj, attr, ignore): +- ''' succeed iff hasattr(obj,attr) or attr in ignore. ''' +- if attr in ignore: return +- if not hasattr(obj, attr): print("???", attr) +- self.assertTrue(hasattr(obj, attr), +- 'expected hasattr(%r, %r)' % (obj, attr)) +- +- + def assertHaskey(self, obj, key, ignore): + ''' succeed iff key in obj or key in ignore. ''' + if key in ignore: return +@@ -86,7 +78,7 @@ + for name, value in dict.items(): + if name in ignore: + continue +- self.assertHasattr(module, name, ignore) ++ self.assertHasAttr(module, name, ignore) + py_item = getattr(module, name) + if isinstance(value, pyclbr.Function): + self.assertIsInstance(py_item, (FunctionType, BuiltinFunctionType)) +@@ -234,7 +226,7 @@ + cm( + 'pdb', + # pyclbr does not handle elegantly `typing` or properties +- ignore=('Union', '_ModuleTarget', '_ScriptTarget', '_ZipTarget'), ++ ignore=('Union', '_ModuleTarget', '_ScriptTarget', '_ZipTarget', 'curframe_locals'), + ) + cm('pydoc', ignore=('input', 'output',)) # properties + +--- /dev/null ++++ b/Lib/test/test_pydoc/module_none.py +@@ -0,0 +1,8 @@ ++def func(): ++ pass ++func.__module__ = None ++ ++class A: ++ def method(self): ++ pass ++ method.__module__ = None +diff --git a/Lib/test/test_pydoc/test_pydoc.py b/Lib/test/test_pydoc/test_pydoc.py +index 3283fde9e12..0abd36c5e07 100644 +--- a/Lib/test/test_pydoc/test_pydoc.py ++++ b/Lib/test/test_pydoc/test_pydoc.py +@@ -4,6 +4,7 @@ + import contextlib + import importlib.util + import inspect ++import io + import pydoc + import py_compile + import keyword +@@ -79,7 +80,7 @@ + class B(builtins.object) + | Methods defined here: + | +- | __annotate__(...) ++ | __annotate__(format, /) + | + | ---------------------------------------------------------------------- + | Data descriptors defined here: +@@ -180,7 +181,7 @@ + + class B(builtins.object) + Methods defined here: +- __annotate__(...) ++ __annotate__(format, /) + ---------------------------------------------------------------------- + Data descriptors defined here: + __dict__ +@@ -555,6 +556,14 @@ + | ... and 82 other subclasses + """ + doc = pydoc.TextDoc() ++ try: ++ # Make sure HeapType, which has no __module__ attribute, is one ++ # of the known subclasses of object. (doc.docclass() used to ++ # fail if HeapType was imported before running this test, like ++ # when running tests sequentially.) ++ from _testcapi import HeapType ++ except ImportError: ++ pass + text = doc.docclass(object) + snip = (" | Built-in subclasses:\n" + " | async_generator\n" +@@ -899,6 +908,82 @@ + synopsis = pydoc.synopsis(TESTFN, {}) + self.assertEqual(synopsis, 'line 1: h\xe9') + ++ def test_source_synopsis(self): ++ def check(source, expected, encoding=None): ++ if isinstance(source, str): ++ source_file = StringIO(source) ++ else: ++ source_file = io.TextIOWrapper(io.BytesIO(source), encoding=encoding) ++ with source_file: ++ result = pydoc.source_synopsis(source_file) ++ self.assertEqual(result, expected) ++ ++ check('"""Single line docstring."""', ++ 'Single line docstring.') ++ check('"""First line of docstring.\nSecond line.\nThird line."""', ++ 'First line of docstring.') ++ check('"""First line of docstring.\\nSecond line.\\nThird line."""', ++ 'First line of docstring.') ++ check('""" Whitespace around docstring. """', ++ 'Whitespace around docstring.') ++ check('import sys\n"""No docstring"""', ++ None) ++ check(' \n"""Docstring after empty line."""', ++ 'Docstring after empty line.') ++ check('# Comment\n"""Docstring after comment."""', ++ 'Docstring after comment.') ++ check(' # Indented comment\n"""Docstring after comment."""', ++ 'Docstring after comment.') ++ check('""""""', # Empty docstring ++ '') ++ check('', # Empty file ++ None) ++ check('"""Embedded\0null byte"""', ++ None) ++ check('"""Embedded null byte"""\0', ++ None) ++ check('"""Café and résumé."""', ++ 'Café and résumé.') ++ check("'''Triple single quotes'''", ++ 'Triple single quotes') ++ check('"Single double quotes"', ++ 'Single double quotes') ++ check("'Single single quotes'", ++ 'Single single quotes') ++ check('"""split\\\nline"""', ++ 'splitline') ++ check('"""Unrecognized escape \\sequence"""', ++ 'Unrecognized escape \\sequence') ++ check('"""Invalid escape seq\\uence"""', ++ None) ++ check('r"""Raw \\stri\\ng"""', ++ 'Raw \\stri\\ng') ++ check('b"""Bytes literal"""', ++ None) ++ check('f"""f-string"""', ++ None) ++ check('"""Concatenated""" \\\n"string" \'literals\'', ++ 'Concatenatedstringliterals') ++ check('"""String""" + """expression"""', ++ None) ++ check('("""In parentheses""")', ++ 'In parentheses') ++ check('("""Multiple lines """\n"""in parentheses""")', ++ 'Multiple lines in parentheses') ++ check('()', # tuple ++ None) ++ check(b'# coding: iso-8859-15\n"""\xa4uro sign"""', ++ '€uro sign', encoding='iso-8859-15') ++ check(b'"""\xa4"""', # Decoding error ++ None, encoding='utf-8') ++ ++ with tempfile.NamedTemporaryFile(mode='w+', encoding='utf-8') as temp_file: ++ temp_file.write('"""Real file test."""\n') ++ temp_file.flush() ++ temp_file.seek(0) ++ result = pydoc.source_synopsis(temp_file) ++ self.assertEqual(result, "Real file test.") ++ + @requires_docstrings + def test_synopsis_sourceless(self): + os = import_helper.import_fresh_module('os') +@@ -1818,6 +1903,11 @@ + html + ) + ++ def test_module_none(self): ++ # Issue #128772 ++ from test.test_pydoc import module_none ++ pydoc.render_doc(module_none) ++ + + class PydocFodderTest(unittest.TestCase): + def tearDown(self): +diff --git a/Lib/test/test_pyrepl/support.py b/Lib/test/test_pyrepl/support.py +index 672d4896c92..45e3bf758f1 100644 +--- a/Lib/test/test_pyrepl/support.py ++++ b/Lib/test/test_pyrepl/support.py +@@ -101,16 +101,6 @@ + ) + + +-def make_clean_env() -> dict[str, str]: +- clean_env = os.environ.copy() +- for k in clean_env.copy(): +- if k.startswith("PYTHON"): +- clean_env.pop(k) +- clean_env.pop("FORCE_COLOR", None) +- clean_env.pop("NO_COLOR", None) +- return clean_env +- +- + class FakeConsole(Console): + def __init__(self, events, encoding="utf-8") -> None: + self.events = iter(events) +diff --git a/Lib/test/test_pyrepl/test_pyrepl.py b/Lib/test/test_pyrepl/test_pyrepl.py +index f29a7ffbd7c..3540d2a5a41 100644 +--- a/Lib/test/test_pyrepl/test_pyrepl.py ++++ b/Lib/test/test_pyrepl/test_pyrepl.py +@@ -10,7 +10,7 @@ + import tempfile + from unittest import TestCase, skipUnless, skipIf + from unittest.mock import patch +-from test.support import force_not_colorized ++from test.support import force_not_colorized, make_clean_env + from test.support import SHORT_TIMEOUT + from test.support.import_helper import import_module + from test.support.os_helper import unlink +@@ -23,7 +23,6 @@ + multiline_input, + code_to_events, + clean_screen, +- make_clean_env, + ) + from _pyrepl.console import Event + from _pyrepl.readline import (ReadlineAlikeReader, ReadlineConfig, +@@ -851,7 +850,7 @@ + output = multiline_input(reader, namespace) + self.assertEqual(output, "python") + +- def test_updown_arrow_with_completion_menu(self): ++ def test_up_down_arrow_with_completion_menu(self): + """Up arrow in the middle of unfinished tab completion when the menu is displayed + should work and trigger going back in history. Down arrow should subsequently + get us back to the incomplete command.""" +@@ -861,6 +860,7 @@ + events = itertools.chain( + code_to_events(code), + [ ++ Event(evt="key", data="down", raw=bytearray(b"\x1bOB")), + Event(evt="key", data="up", raw=bytearray(b"\x1bOA")), + Event(evt="key", data="down", raw=bytearray(b"\x1bOB")), + ], +@@ -1324,23 +1324,35 @@ + if readline.backend != "editline": + self.skipTest("GNU readline is not affected by this issue") + +- hfile = tempfile.NamedTemporaryFile() +- self.addCleanup(unlink, hfile.name) +- env = os.environ.copy() +- env["PYTHON_HISTORY"] = hfile.name ++ with tempfile.NamedTemporaryFile() as hfile: ++ env = os.environ.copy() ++ env["PYTHON_HISTORY"] = hfile.name + +- env["PYTHON_BASIC_REPL"] = "1" +- output, exit_code = self.run_repl("spam \nexit()\n", env=env) +- self.assertEqual(exit_code, 0) +- self.assertIn("spam ", output) +- self.assertNotEqual(pathlib.Path(hfile.name).stat().st_size, 0) +- self.assertIn("spam\\040", pathlib.Path(hfile.name).read_text()) ++ env["PYTHON_BASIC_REPL"] = "1" ++ output, exit_code = self.run_repl("spam \nexit()\n", env=env) ++ self.assertEqual(exit_code, 0) ++ self.assertIn("spam ", output) ++ self.assertNotEqual(pathlib.Path(hfile.name).stat().st_size, 0) ++ self.assertIn("spam\\040", pathlib.Path(hfile.name).read_text()) + +- env.pop("PYTHON_BASIC_REPL", None) +- output, exit_code = self.run_repl("exit\n", env=env) +- self.assertEqual(exit_code, 0) +- self.assertNotIn("\\040", pathlib.Path(hfile.name).read_text()) ++ env.pop("PYTHON_BASIC_REPL", None) ++ output, exit_code = self.run_repl("exit\n", env=env) ++ self.assertEqual(exit_code, 0) ++ self.assertNotIn("\\040", pathlib.Path(hfile.name).read_text()) + + def test_keyboard_interrupt_after_isearch(self): + output, exit_code = self.run_repl(["\x12", "\x03", "exit"]) + self.assertEqual(exit_code, 0) ++ ++ def test_prompt_after_help(self): ++ output, exit_code = self.run_repl(["help", "q", "exit"]) ++ ++ # Regex pattern to remove ANSI escape sequences ++ ansi_escape = re.compile(r"(\x1B(=|>|(\[)[0-?]*[ -\/]*[@-~]))") ++ cleaned_output = ansi_escape.sub("", output) ++ self.assertEqual(exit_code, 0) ++ ++ # Ensure that we don't see multiple prompts after exiting `help` ++ # Extra stuff (newline and `exit` rewrites) are necessary ++ # because of how run_repl works. ++ self.assertNotIn(">>> \n>>> >>>", cleaned_output) +diff --git a/Lib/test/test_pyrepl/test_reader.py b/Lib/test/test_pyrepl/test_reader.py +index 6c72a1d39c5..27c6d6664ed 100644 +--- a/Lib/test/test_pyrepl/test_reader.py ++++ b/Lib/test/test_pyrepl/test_reader.py +@@ -4,7 +4,7 @@ + from unittest import TestCase + from unittest.mock import MagicMock + +-from .support import handle_all_events, handle_events_narrow_console, code_to_events, prepare_reader ++from .support import handle_all_events, handle_events_narrow_console, code_to_events, prepare_reader, prepare_console + from _pyrepl.console import Event + from _pyrepl.reader import Reader + +@@ -295,8 +295,8 @@ + + actual = reader.screen + self.assertEqual(len(actual), 2) +- self.assertEqual(actual[0].rstrip(), "itertools.accumulate(") +- self.assertEqual(actual[1], f"{code}a") ++ self.assertEqual(actual[0], f"{code}a") ++ self.assertEqual(actual[1].rstrip(), "itertools.accumulate(") + + def test_key_press_on_tab_press_once(self): + namespace = {"itertools": itertools} +@@ -312,3 +312,10 @@ + reader, _ = handle_all_events(events, prepare_reader=completing_reader) + + self.assert_screen_equals(reader, f"{code}a") ++ ++ def test_pos2xy_with_no_columns(self): ++ console = prepare_console([]) ++ reader = prepare_reader(console) ++ # Simulate a resize to 0 columns ++ reader.screeninfo = [] ++ self.assertEqual(reader.pos2xy(), (0, 0)) +diff --git a/Lib/test/test_pyrepl/test_unix_console.py b/Lib/test/test_pyrepl/test_unix_console.py +index e3bbabcb008..15dbf48bcf0 100644 +--- a/Lib/test/test_pyrepl/test_unix_console.py ++++ b/Lib/test/test_pyrepl/test_unix_console.py +@@ -1,7 +1,9 @@ + import itertools ++import os + import sys + import unittest + from functools import partial ++from test.support import os_helper + from unittest import TestCase + from unittest.mock import MagicMock, call, patch, ANY + +@@ -312,3 +314,14 @@ + ) + console.restore() + con.restore() ++ ++ def test_getheightwidth_with_invalid_environ(self, _os_write): ++ # gh-128636 ++ console = UnixConsole() ++ with os_helper.EnvironmentVarGuard() as env: ++ env["LINES"] = "" ++ self.assertIsInstance(console.getheightwidth(), tuple) ++ env["COLUMNS"] = "" ++ self.assertIsInstance(console.getheightwidth(), tuple) ++ os.environ = [] ++ self.assertIsInstance(console.getheightwidth(), tuple) +diff --git a/Lib/test/test_pyrepl/test_windows_console.py b/Lib/test/test_pyrepl/test_windows_console.py +index 4a3b2baf64a..07eaccd1124 100644 +--- a/Lib/test/test_pyrepl/test_windows_console.py ++++ b/Lib/test/test_pyrepl/test_windows_console.py +@@ -329,6 +329,20 @@ + def erase_in_line(self): + return ERASE_IN_LINE.encode("utf8") + ++ def test_multiline_ctrl_z(self): ++ # see gh-126332 ++ code = "abcdefghi" ++ ++ events = itertools.chain( ++ code_to_events(code), ++ [ ++ Event(evt="key", data='\x1a', raw=bytearray(b'\x1a')), ++ Event(evt="key", data='\x1a', raw=bytearray(b'\x1a')), ++ ], ++ ) ++ reader, _ = self.handle_events_narrow(events) ++ self.assertEqual(reader.cxy, (2, 3)) ++ + + if __name__ == "__main__": + unittest.main() +diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py +index 0d3599be87f..5538de60b2a 100644 +--- a/Lib/test/test_re.py ++++ b/Lib/test/test_re.py +@@ -978,18 +978,15 @@ + self.assertIsNone(re.fullmatch(br".+\B", b"abc", re.LOCALE)) + self.assertIsNone(re.fullmatch(r".+\B", "ьюÑ")) + self.assertTrue(re.fullmatch(r".+\B", "ьюÑ", re.ASCII)) +- # However, an empty string contains no word boundaries, and also no +- # non-boundaries. ++ # However, an empty string contains no word boundaries. + self.assertIsNone(re.search(r"\b", "")) + self.assertIsNone(re.search(r"\b", "", re.ASCII)) + self.assertIsNone(re.search(br"\b", b"")) + self.assertIsNone(re.search(br"\b", b"", re.LOCALE)) +- # This one is questionable and different from the perlre behaviour, +- # but describes current behavior. +- self.assertIsNone(re.search(r"\B", "")) +- self.assertIsNone(re.search(r"\B", "", re.ASCII)) +- self.assertIsNone(re.search(br"\B", b"")) +- self.assertIsNone(re.search(br"\B", b"", re.LOCALE)) ++ self.assertTrue(re.search(r"\B", "")) ++ self.assertTrue(re.search(r"\B", "", re.ASCII)) ++ self.assertTrue(re.search(br"\B", b"")) ++ self.assertTrue(re.search(br"\B", b"", re.LOCALE)) + # A single word-character string has two boundaries, but no + # non-boundary gaps. + self.assertEqual(len(re.findall(r"\b", "a")), 2) +diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py +index ab46ccbf004..969f483814d 100644 +--- a/Lib/test/test_regrtest.py ++++ b/Lib/test/test_regrtest.py +@@ -792,6 +792,7 @@ + f'{", ".join(output.splitlines())}') + + ++@support.force_not_colorized_test_class + class ProgramsTestCase(BaseTestCase): + """ + Test various ways to run the Python test suite. Use options close +@@ -905,6 +906,7 @@ + self.run_batch(script, *rt_args, *self.regrtest_args, *self.tests) + + ++@support.force_not_colorized_test_class + class ArgsTestCase(BaseTestCase): + """ + Test arguments of the Python test suite. +@@ -1183,7 +1185,7 @@ + stats=TestStats(4, 1), + forever=True) + +- @support.without_optimizer ++ @support.requires_jit_disabled + def check_leak(self, code, what, *, run_workers=False): + test = self.create_test('huntrleaks', code=code) + +@@ -2145,25 +2147,25 @@ + import unittest + from test import support + try: +- from _testinternalcapi import get_config ++ from _testcapi import config_get + except ImportError: +- get_config = None ++ config_get = None + + # WASI/WASM buildbots don't use -E option + use_environment = (support.is_emscripten or support.is_wasi) + + class WorkerTests(unittest.TestCase): +- @unittest.skipUnless(get_config is None, 'need get_config()') ++ @unittest.skipUnless(config_get is None, 'need config_get()') + def test_config(self): +- config = get_config()['config'] ++ config = config_get() + # -u option +- self.assertEqual(config['buffered_stdio'], 0) ++ self.assertEqual(config_get('buffered_stdio'), 0) + # -W default option +- self.assertTrue(config['warnoptions'], ['default']) ++ self.assertTrue(config_get('warnoptions'), ['default']) + # -bb option +- self.assertTrue(config['bytes_warning'], 2) ++ self.assertTrue(config_get('bytes_warning'), 2) + # -E option +- self.assertTrue(config['use_environment'], use_environment) ++ self.assertTrue(config_get('use_environment'), use_environment) + + def test_python_opts(self): + # -u option +diff --git a/Lib/test/test_repl.py b/Lib/test/test_repl.py +index e764e60560d..356ff5b198d 100644 +--- a/Lib/test/test_repl.py ++++ b/Lib/test/test_repl.py +@@ -70,6 +70,7 @@ + return output + + ++@support.force_not_colorized_test_class + class TestInteractiveInterpreter(unittest.TestCase): + + @cpython_only +@@ -273,6 +274,8 @@ + + self.assertEqual(exit_code, 0, "".join(output)) + ++ ++@support.force_not_colorized_test_class + class TestInteractiveModeSyntaxErrors(unittest.TestCase): + + def test_interactive_syntax_error_correct_line(self): +diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py +index b64383f6546..ada78ec8e6b 100644 +--- a/Lib/test/test_runpy.py ++++ b/Lib/test/test_runpy.py +@@ -12,8 +12,14 @@ + import textwrap + import unittest + import warnings +-from test.support import (infinite_recursion, no_tracing, verbose, +- requires_subprocess, requires_resource) ++from test.support import ( ++ force_not_colorized_test_class, ++ infinite_recursion, ++ no_tracing, ++ requires_resource, ++ requires_subprocess, ++ verbose, ++) + from test.support.import_helper import forget, make_legacy_pyc, unload + from test.support.os_helper import create_empty_file, temp_dir, FakePath + from test.support.script_helper import make_script, make_zip_script +@@ -758,6 +764,7 @@ + self.assertEqual(result['s'], "non-ASCII: h\xe9") + + ++@force_not_colorized_test_class + class TestExit(unittest.TestCase): + STATUS_CONTROL_C_EXIT = 0xC000013A + EXPECTED_CODE = ( +diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py +index 1f18b1f09b5..078ddd6c431 100644 +--- a/Lib/test/test_shutil.py ++++ b/Lib/test/test_shutil.py +@@ -3239,12 +3239,8 @@ + self.assertRaises(OSError, self.zerocopy_fun, src, dst) + + +-@unittest.skipIf(not SUPPORTS_SENDFILE, 'os.sendfile() not supported') +-class TestZeroCopySendfile(_ZeroCopyFileTest, unittest.TestCase): +- PATCHPOINT = "os.sendfile" +- +- def zerocopy_fun(self, fsrc, fdst): +- return shutil._fastcopy_sendfile(fsrc, fdst) ++class _ZeroCopyFileLinuxTest(_ZeroCopyFileTest): ++ BLOCKSIZE_INDEX = None + + def test_non_regular_file_src(self): + with io.BytesIO(self.FILEDATA) as src: +@@ -3265,65 +3261,65 @@ + self.assertEqual(dst.read(), self.FILEDATA) + + def test_exception_on_second_call(self): +- def sendfile(*args, **kwargs): ++ def syscall(*args, **kwargs): + if not flag: + flag.append(None) +- return orig_sendfile(*args, **kwargs) ++ return orig_syscall(*args, **kwargs) + else: + raise OSError(errno.EBADF, "yo") + + flag = [] +- orig_sendfile = os.sendfile +- with unittest.mock.patch('os.sendfile', create=True, +- side_effect=sendfile): ++ orig_syscall = eval(self.PATCHPOINT) ++ with unittest.mock.patch(self.PATCHPOINT, create=True, ++ side_effect=syscall): + with self.get_files() as (src, dst): + with self.assertRaises(OSError) as cm: +- shutil._fastcopy_sendfile(src, dst) ++ self.zerocopy_fun(src, dst) + assert flag + self.assertEqual(cm.exception.errno, errno.EBADF) + + def test_cant_get_size(self): + # Emulate a case where src file size cannot be determined. + # Internally bufsize will be set to a small value and +- # sendfile() will be called repeatedly. ++ # a system call will be called repeatedly. + with unittest.mock.patch('os.fstat', side_effect=OSError) as m: + with self.get_files() as (src, dst): +- shutil._fastcopy_sendfile(src, dst) ++ self.zerocopy_fun(src, dst) + assert m.called + self.assertEqual(read_file(TESTFN2, binary=True), self.FILEDATA) + + def test_small_chunks(self): + # Force internal file size detection to be smaller than the +- # actual file size. We want to force sendfile() to be called ++ # actual file size. We want to force a system call to be called + # multiple times, also in order to emulate a src fd which gets + # bigger while it is being copied. + mock = unittest.mock.Mock() + mock.st_size = 65536 + 1 + with unittest.mock.patch('os.fstat', return_value=mock) as m: + with self.get_files() as (src, dst): +- shutil._fastcopy_sendfile(src, dst) ++ self.zerocopy_fun(src, dst) + assert m.called + self.assertEqual(read_file(TESTFN2, binary=True), self.FILEDATA) + + def test_big_chunk(self): + # Force internal file size detection to be +100MB bigger than +- # the actual file size. Make sure sendfile() does not rely on ++ # the actual file size. Make sure a system call does not rely on + # file size value except for (maybe) a better throughput / + # performance. + mock = unittest.mock.Mock() + mock.st_size = self.FILESIZE + (100 * 1024 * 1024) + with unittest.mock.patch('os.fstat', return_value=mock) as m: + with self.get_files() as (src, dst): +- shutil._fastcopy_sendfile(src, dst) ++ self.zerocopy_fun(src, dst) + assert m.called + self.assertEqual(read_file(TESTFN2, binary=True), self.FILEDATA) + + def test_blocksize_arg(self): +- with unittest.mock.patch('os.sendfile', ++ with unittest.mock.patch(self.PATCHPOINT, + side_effect=ZeroDivisionError) as m: + self.assertRaises(ZeroDivisionError, + shutil.copyfile, TESTFN, TESTFN2) +- blocksize = m.call_args[0][3] ++ blocksize = m.call_args[0][self.BLOCKSIZE_INDEX] + # Make sure file size and the block size arg passed to + # sendfile() are the same. + self.assertEqual(blocksize, os.path.getsize(TESTFN)) +@@ -3333,9 +3329,19 @@ + self.addCleanup(os_helper.unlink, TESTFN2 + '3') + self.assertRaises(ZeroDivisionError, + shutil.copyfile, TESTFN2, TESTFN2 + '3') +- blocksize = m.call_args[0][3] ++ blocksize = m.call_args[0][self.BLOCKSIZE_INDEX] + self.assertEqual(blocksize, 2 ** 23) + ++ ++@unittest.skipIf(not SUPPORTS_SENDFILE, 'os.sendfile() not supported') ++@unittest.mock.patch.object(shutil, "_USE_CP_COPY_FILE_RANGE", False) ++class TestZeroCopySendfile(_ZeroCopyFileLinuxTest, unittest.TestCase): ++ PATCHPOINT = "os.sendfile" ++ BLOCKSIZE_INDEX = 3 ++ ++ def zerocopy_fun(self, fsrc, fdst): ++ return shutil._fastcopy_sendfile(fsrc, fdst) ++ + def test_file2file_not_supported(self): + # Emulate a case where sendfile() only support file->socket + # fds. In such a case copyfile() is supposed to skip the +@@ -3358,6 +3364,29 @@ + shutil._USE_CP_SENDFILE = True + + ++@unittest.skipUnless(shutil._USE_CP_COPY_FILE_RANGE, "os.copy_file_range() not supported") ++class TestZeroCopyCopyFileRange(_ZeroCopyFileLinuxTest, unittest.TestCase): ++ PATCHPOINT = "os.copy_file_range" ++ BLOCKSIZE_INDEX = 2 ++ ++ def zerocopy_fun(self, fsrc, fdst): ++ return shutil._fastcopy_copy_file_range(fsrc, fdst) ++ ++ def test_empty_file(self): ++ srcname = f"{TESTFN}src" ++ dstname = f"{TESTFN}dst" ++ self.addCleanup(lambda: os_helper.unlink(srcname)) ++ self.addCleanup(lambda: os_helper.unlink(dstname)) ++ with open(srcname, "wb"): ++ pass ++ ++ with open(srcname, "rb") as src, open(dstname, "wb") as dst: ++ # _fastcopy_copy_file_range gives up copying empty files due ++ # to a bug in older Linux. ++ with self.assertRaises(shutil._GiveupOnFastCopy): ++ self.zerocopy_fun(src, dst) ++ ++ + @unittest.skipIf(not MACOS, 'macOS only') + class TestZeroCopyMACOS(_ZeroCopyFileTest, unittest.TestCase): + PATCHPOINT = "posix._fcopyfile" +diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py +index 704a0090bdb..72a01cd1e45 100644 +--- a/Lib/test/test_signal.py ++++ b/Lib/test/test_signal.py +@@ -253,9 +253,7 @@ + self.assertRaises((ValueError, OSError), + signal.set_wakeup_fd, fd) + +- # Emscripten does not support fstat on pipes yet. +- # https://github.com/emscripten-core/emscripten/issues/16414 +- @unittest.skipIf(support.is_emscripten, "Emscripten cannot fstat pipes.") ++ @unittest.skipIf(support.is_emscripten, "Fixed in next Emscripten release after 4.0.1") + @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") + def test_set_wakeup_fd_result(self): + r1, w1 = os.pipe() +@@ -274,7 +272,7 @@ + self.assertEqual(signal.set_wakeup_fd(-1), w2) + self.assertEqual(signal.set_wakeup_fd(-1), -1) + +- @unittest.skipIf(support.is_emscripten, "Emscripten cannot fstat pipes.") ++ @unittest.skipIf(support.is_emscripten, "Fixed in next Emscripten release after 4.0.1") + @unittest.skipUnless(support.has_socket_support, "needs working sockets.") + def test_set_wakeup_fd_socket_result(self): + sock1 = socket.socket() +@@ -295,7 +293,7 @@ + # On Windows, files are always blocking and Windows does not provide a + # function to test if a socket is in non-blocking mode. + @unittest.skipIf(sys.platform == "win32", "tests specific to POSIX") +- @unittest.skipIf(support.is_emscripten, "Emscripten cannot fstat pipes.") ++ @unittest.skipIf(support.is_emscripten, "Fixed in next Emscripten release after 4.0.1") + @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") + def test_set_wakeup_fd_blocking(self): + rfd, wfd = os.pipe() +@@ -385,7 +383,7 @@ + except ZeroDivisionError: + # An ignored exception should have been printed out on stderr + err = err.getvalue() +- if ('Exception ignored when trying to write to the signal wakeup fd' ++ if ('Exception ignored while trying to write to the signal wakeup fd' + not in err): + raise AssertionError(err) + if ('OSError: [Errno %d]' % errno.EBADF) not in err: +@@ -574,7 +572,7 @@ + signal.raise_signal(signum) + + err = err.getvalue() +- if ('Exception ignored when trying to {action} to the signal wakeup fd' ++ if ('Exception ignored while trying to {action} to the signal wakeup fd' + not in err): + raise AssertionError(err) + """.format(action=action) +@@ -644,7 +642,7 @@ + "buffer" % written) + + # By default, we get a warning when a signal arrives +- msg = ('Exception ignored when trying to {action} ' ++ msg = ('Exception ignored while trying to {action} ' + 'to the signal wakeup fd') + signal.set_wakeup_fd(write.fileno()) + +diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py +index 307d6e886c6..b77fa3cb215 100644 +--- a/Lib/test/test_socket.py ++++ b/Lib/test/test_socket.py +@@ -520,6 +520,8 @@ + @unittest.skipIf(WSL, 'VSOCK does not work on Microsoft WSL') + @unittest.skipUnless(HAVE_SOCKET_VSOCK, + 'VSOCK sockets required for this test.') ++@unittest.skipUnless(get_cid() != 2, # VMADDR_CID_HOST ++ "This test can only be run on a virtual guest.") + class ThreadedVSOCKSocketStreamTest(unittest.TestCase, ThreadableTest): + + def __init__(self, methodName='runTest'): +@@ -547,7 +549,10 @@ + self.cli.connect((cid, VSOCKPORT)) + + def testStream(self): +- msg = self.conn.recv(1024) ++ try: ++ msg = self.conn.recv(1024) ++ except PermissionError as exc: ++ self.skipTest(repr(exc)) + self.assertEqual(msg, MSG) + + def _testStream(self): +@@ -7072,6 +7077,26 @@ + self.assertEqual(data, str(index).encode()) + + ++class FreeThreadingTests(unittest.TestCase): ++ ++ def test_close_detach_race(self): ++ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ++ ++ def close(): ++ for _ in range(1000): ++ s.close() ++ ++ def detach(): ++ for _ in range(1000): ++ s.detach() ++ ++ t1 = threading.Thread(target=close) ++ t2 = threading.Thread(target=detach) ++ ++ with threading_helper.start_threads([t1, t2]): ++ pass ++ ++ + def setUpModule(): + thread_info = threading_helper.threading_setup() + unittest.addModuleCleanup(threading_helper.threading_cleanup, *thread_info) +diff --git a/Lib/test/test_sqlite3/test_cli.py b/Lib/test/test_sqlite3/test_cli.py +index d014a9ce841..dcd90d11d46 100644 +--- a/Lib/test/test_sqlite3/test_cli.py ++++ b/Lib/test/test_sqlite3/test_cli.py +@@ -90,14 +90,14 @@ + out, err = self.run_cli() + self.assertIn(self.MEMORY_DB_MSG, err) + self.assertIn(self.MEMORY_DB_MSG, err) +- self.assertTrue(out.endswith(self.PS1)) ++ self.assertEndsWith(out, self.PS1) + self.assertEqual(out.count(self.PS1), 1) + self.assertEqual(out.count(self.PS2), 0) + + def test_interact_quit(self): + out, err = self.run_cli(commands=(".quit",)) + self.assertIn(self.MEMORY_DB_MSG, err) +- self.assertTrue(out.endswith(self.PS1)) ++ self.assertEndsWith(out, self.PS1) + self.assertEqual(out.count(self.PS1), 1) + self.assertEqual(out.count(self.PS2), 0) + +@@ -105,7 +105,7 @@ + out, err = self.run_cli(commands=(".version",)) + self.assertIn(self.MEMORY_DB_MSG, err) + self.assertIn(sqlite3.sqlite_version + "\n", out) +- self.assertTrue(out.endswith(self.PS1)) ++ self.assertEndsWith(out, self.PS1) + self.assertEqual(out.count(self.PS1), 2) + self.assertEqual(out.count(self.PS2), 0) + self.assertIn(sqlite3.sqlite_version, out) +@@ -114,14 +114,14 @@ + out, err = self.run_cli(commands=("SELECT 1;",)) + self.assertIn(self.MEMORY_DB_MSG, err) + self.assertIn("(1,)\n", out) +- self.assertTrue(out.endswith(self.PS1)) ++ self.assertEndsWith(out, self.PS1) + self.assertEqual(out.count(self.PS1), 2) + self.assertEqual(out.count(self.PS2), 0) + + def test_interact_incomplete_multiline_sql(self): + out, err = self.run_cli(commands=("SELECT 1",)) + self.assertIn(self.MEMORY_DB_MSG, err) +- self.assertTrue(out.endswith(self.PS2)) ++ self.assertEndsWith(out, self.PS2) + self.assertEqual(out.count(self.PS1), 1) + self.assertEqual(out.count(self.PS2), 1) + +@@ -130,7 +130,7 @@ + self.assertIn(self.MEMORY_DB_MSG, err) + self.assertIn(self.PS2, out) + self.assertIn("(1,)\n", out) +- self.assertTrue(out.endswith(self.PS1)) ++ self.assertEndsWith(out, self.PS1) + self.assertEqual(out.count(self.PS1), 2) + self.assertEqual(out.count(self.PS2), 1) + +@@ -138,7 +138,7 @@ + out, err = self.run_cli(commands=("sel;",)) + self.assertIn(self.MEMORY_DB_MSG, err) + self.assertIn("OperationalError (SQLITE_ERROR)", err) +- self.assertTrue(out.endswith(self.PS1)) ++ self.assertEndsWith(out, self.PS1) + self.assertEqual(out.count(self.PS1), 2) + self.assertEqual(out.count(self.PS2), 0) + +@@ -147,7 +147,7 @@ + + out, err = self.run_cli(TESTFN, commands=("CREATE TABLE t(t);",)) + self.assertIn(TESTFN, err) +- self.assertTrue(out.endswith(self.PS1)) ++ self.assertEndsWith(out, self.PS1) + + out, _ = self.run_cli(TESTFN, commands=("SELECT count(t) FROM t;",)) + self.assertIn("(0,)\n", out) +diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py +index 488b401fb00..c3aa3bf2d7b 100644 +--- a/Lib/test/test_sqlite3/test_dbapi.py ++++ b/Lib/test/test_sqlite3/test_dbapi.py +@@ -59,45 +59,34 @@ + sqlite.paramstyle) + + def test_warning(self): +- self.assertTrue(issubclass(sqlite.Warning, Exception), +- "Warning is not a subclass of Exception") ++ self.assertIsSubclass(sqlite.Warning, Exception) + + def test_error(self): +- self.assertTrue(issubclass(sqlite.Error, Exception), +- "Error is not a subclass of Exception") ++ self.assertIsSubclass(sqlite.Error, Exception) + + def test_interface_error(self): +- self.assertTrue(issubclass(sqlite.InterfaceError, sqlite.Error), +- "InterfaceError is not a subclass of Error") ++ self.assertIsSubclass(sqlite.InterfaceError, sqlite.Error) + + def test_database_error(self): +- self.assertTrue(issubclass(sqlite.DatabaseError, sqlite.Error), +- "DatabaseError is not a subclass of Error") ++ self.assertIsSubclass(sqlite.DatabaseError, sqlite.Error) + + def test_data_error(self): +- self.assertTrue(issubclass(sqlite.DataError, sqlite.DatabaseError), +- "DataError is not a subclass of DatabaseError") ++ self.assertIsSubclass(sqlite.DataError, sqlite.DatabaseError) + + def test_operational_error(self): +- self.assertTrue(issubclass(sqlite.OperationalError, sqlite.DatabaseError), +- "OperationalError is not a subclass of DatabaseError") ++ self.assertIsSubclass(sqlite.OperationalError, sqlite.DatabaseError) + + def test_integrity_error(self): +- self.assertTrue(issubclass(sqlite.IntegrityError, sqlite.DatabaseError), +- "IntegrityError is not a subclass of DatabaseError") ++ self.assertIsSubclass(sqlite.IntegrityError, sqlite.DatabaseError) + + def test_internal_error(self): +- self.assertTrue(issubclass(sqlite.InternalError, sqlite.DatabaseError), +- "InternalError is not a subclass of DatabaseError") ++ self.assertIsSubclass(sqlite.InternalError, sqlite.DatabaseError) + + def test_programming_error(self): +- self.assertTrue(issubclass(sqlite.ProgrammingError, sqlite.DatabaseError), +- "ProgrammingError is not a subclass of DatabaseError") ++ self.assertIsSubclass(sqlite.ProgrammingError, sqlite.DatabaseError) + + def test_not_supported_error(self): +- self.assertTrue(issubclass(sqlite.NotSupportedError, +- sqlite.DatabaseError), +- "NotSupportedError is not a subclass of DatabaseError") ++ self.assertIsSubclass(sqlite.NotSupportedError, sqlite.DatabaseError) + + def test_module_constants(self): + consts = [ +@@ -274,7 +263,7 @@ + consts.append("SQLITE_IOERR_CORRUPTFS") + for const in consts: + with self.subTest(const=const): +- self.assertTrue(hasattr(sqlite, const)) ++ self.assertHasAttr(sqlite, const) + + def test_error_code_on_exception(self): + err_msg = "unable to open database file" +@@ -288,7 +277,7 @@ + sqlite.connect(db) + e = cm.exception + self.assertEqual(e.sqlite_errorcode, err_code) +- self.assertTrue(e.sqlite_errorname.startswith("SQLITE_CANTOPEN")) ++ self.assertStartsWith(e.sqlite_errorname, "SQLITE_CANTOPEN") + + def test_extended_error_code_on_exception(self): + with memory_database() as con: +@@ -425,7 +414,7 @@ + ] + for exc in exceptions: + with self.subTest(exc=exc): +- self.assertTrue(hasattr(self.cx, exc)) ++ self.assertHasAttr(self.cx, exc) + self.assertIs(getattr(sqlite, exc), getattr(self.cx, exc)) + + def test_interrupt_on_closed_db(self): +@@ -1935,5 +1924,70 @@ + self.assertEqual(proc.returncode, 0) + + ++class RowTests(unittest.TestCase): ++ ++ def setUp(self): ++ self.cx = sqlite.connect(":memory:") ++ self.cx.row_factory = sqlite.Row ++ ++ def tearDown(self): ++ self.cx.close() ++ ++ def test_row_keys(self): ++ cu = self.cx.execute("SELECT 1 as first, 2 as second") ++ row = cu.fetchone() ++ self.assertEqual(row.keys(), ["first", "second"]) ++ ++ def test_row_length(self): ++ cu = self.cx.execute("SELECT 1, 2, 3") ++ row = cu.fetchone() ++ self.assertEqual(len(row), 3) ++ ++ def test_row_getitem(self): ++ cu = self.cx.execute("SELECT 1 as a, 2 as b") ++ row = cu.fetchone() ++ self.assertEqual(row[0], 1) ++ self.assertEqual(row[1], 2) ++ self.assertEqual(row["a"], 1) ++ self.assertEqual(row["b"], 2) ++ for key in "nokey", 4, 1.2: ++ with self.subTest(key=key): ++ with self.assertRaises(IndexError): ++ row[key] ++ ++ def test_row_equality(self): ++ c1 = self.cx.execute("SELECT 1 as a") ++ r1 = c1.fetchone() ++ ++ c2 = self.cx.execute("SELECT 1 as a") ++ r2 = c2.fetchone() ++ ++ self.assertIsNot(r1, r2) ++ self.assertEqual(r1, r2) ++ ++ c3 = self.cx.execute("SELECT 1 as b") ++ r3 = c3.fetchone() ++ ++ self.assertNotEqual(r1, r3) ++ ++ def test_row_no_description(self): ++ cu = self.cx.cursor() ++ self.assertIsNone(cu.description) ++ ++ row = sqlite.Row(cu, ()) ++ self.assertEqual(row.keys(), []) ++ with self.assertRaisesRegex(IndexError, "nokey"): ++ row["nokey"] ++ ++ def test_row_is_a_sequence(self): ++ from collections.abc import Sequence ++ ++ cu = self.cx.execute("SELECT 1") ++ row = cu.fetchone() ++ ++ self.assertIsSubclass(sqlite.Row, Sequence) ++ self.assertIsInstance(row, Sequence) ++ ++ + if __name__ == "__main__": + unittest.main() +diff --git a/Lib/test/test_sqlite3/test_dump.py b/Lib/test/test_sqlite3/test_dump.py +index 550cea41976..e18a207e9f6 100644 +--- a/Lib/test/test_sqlite3/test_dump.py ++++ b/Lib/test/test_sqlite3/test_dump.py +@@ -4,6 +4,7 @@ + + from .util import memory_database + from .util import MemoryDatabaseMixin ++from .util import requires_virtual_table + + + class DumpTests(MemoryDatabaseMixin, unittest.TestCase): +@@ -206,6 +207,7 @@ + self.assertEqual(expected, actual) + self.assertEqual(self.cx.row_factory, dict_factory) + ++ @requires_virtual_table("fts4") + def test_dump_virtual_tables(self): + # gh-64662 + expected = [ +diff --git a/Lib/test/test_sqlite3/test_factory.py b/Lib/test/test_sqlite3/test_factory.py +index 48d35b54a2e..cc9f1ec5c4b 100644 +--- a/Lib/test/test_sqlite3/test_factory.py ++++ b/Lib/test/test_sqlite3/test_factory.py +@@ -280,7 +280,7 @@ + austria = "Österreich" + row = self.con.execute("select ?", (austria,)).fetchone() + self.assertEqual(type(row[0]), str, "type of row[0] must be unicode") +- self.assertTrue(row[0].endswith("reich"), "column must contain original data") ++ self.assertEndsWith(row[0], "reich", "column must contain original data") + + + class TextFactoryTestsWithEmbeddedZeroBytes(unittest.TestCase): +diff --git a/Lib/test/test_sqlite3/test_hooks.py b/Lib/test/test_sqlite3/test_hooks.py +index 49e72f8fcfb..53b8a39bf29 100644 +--- a/Lib/test/test_sqlite3/test_hooks.py ++++ b/Lib/test/test_sqlite3/test_hooks.py +@@ -196,7 +196,7 @@ + con.execute("select 1 union select 2 union select 3").fetchall() + self.assertEqual(action, 0, "progress handler was not cleared") + +- @with_tracebacks(ZeroDivisionError, name="bad_progress") ++ @with_tracebacks(ZeroDivisionError, msg_regex="bad_progress") + def test_error_in_progress_handler(self): + def bad_progress(): + 1 / 0 +@@ -206,7 +206,7 @@ + create table foo(a, b) + """) + +- @with_tracebacks(ZeroDivisionError, name="bad_progress") ++ @with_tracebacks(ZeroDivisionError, msg_regex="bad_progress") + def test_error_in_progress_handler_result(self): + class BadBool: + def __bool__(self): +diff --git a/Lib/test/test_sqlite3/test_userfunctions.py b/Lib/test/test_sqlite3/test_userfunctions.py +index c6c3db159ad..3abc43a3b1a 100644 +--- a/Lib/test/test_sqlite3/test_userfunctions.py ++++ b/Lib/test/test_sqlite3/test_userfunctions.py +@@ -171,7 +171,7 @@ + self.con.close() + + def test_func_error_on_create(self): +- with self.assertRaises(sqlite.OperationalError): ++ with self.assertRaisesRegex(sqlite.ProgrammingError, "not -100"): + self.con.create_function("bla", -100, lambda x: 2*x) + + def test_func_too_many_args(self): +@@ -254,7 +254,7 @@ + cur.execute("select returnnan()") + self.assertIsNone(cur.fetchone()[0]) + +- @with_tracebacks(ZeroDivisionError, name="func_raiseexception") ++ @with_tracebacks(ZeroDivisionError, msg_regex="func_raiseexception") + def test_func_exception(self): + cur = self.con.cursor() + with self.assertRaises(sqlite.OperationalError) as cm: +@@ -262,14 +262,14 @@ + cur.fetchone() + self.assertEqual(str(cm.exception), 'user-defined function raised exception') + +- @with_tracebacks(MemoryError, name="func_memoryerror") ++ @with_tracebacks(MemoryError, msg_regex="func_memoryerror") + def test_func_memory_error(self): + cur = self.con.cursor() + with self.assertRaises(MemoryError): + cur.execute("select memoryerror()") + cur.fetchone() + +- @with_tracebacks(OverflowError, name="func_overflowerror") ++ @with_tracebacks(OverflowError, msg_regex="func_overflowerror") + def test_func_overflow_error(self): + cur = self.con.cursor() + with self.assertRaises(sqlite.DataError): +@@ -389,7 +389,7 @@ + with self.assertRaisesRegex(sqlite.DataError, msg): + cur.execute("select largeint()") + +- @with_tracebacks(UnicodeEncodeError, "surrogates not allowed", "chr") ++ @with_tracebacks(UnicodeEncodeError, "surrogates not allowed") + def test_func_return_text_with_surrogates(self): + cur = self.con.cursor() + self.con.create_function("pychr", 1, chr) +@@ -507,9 +507,8 @@ + self.assertEqual(self.cur.fetchall(), self.expected) + + def test_win_error_on_create(self): +- self.assertRaises(sqlite.ProgrammingError, +- self.con.create_window_function, +- "shouldfail", -100, WindowSumInt) ++ with self.assertRaisesRegex(sqlite.ProgrammingError, "not -100"): ++ self.con.create_window_function("shouldfail", -100, WindowSumInt) + + @with_tracebacks(BadWindow) + def test_win_exception_in_method(self): +@@ -638,10 +637,10 @@ + self.con.close() + + def test_aggr_error_on_create(self): +- with self.assertRaises(sqlite.OperationalError): ++ with self.assertRaisesRegex(sqlite.ProgrammingError, "not -100"): + self.con.create_function("bla", -100, AggrSum) + +- @with_tracebacks(AttributeError, name="AggrNoStep") ++ @with_tracebacks(AttributeError, msg_regex="AggrNoStep") + def test_aggr_no_step(self): + cur = self.con.cursor() + with self.assertRaises(sqlite.OperationalError) as cm: +@@ -656,7 +655,7 @@ + cur.execute("select nofinalize(t) from test") + val = cur.fetchone()[0] + +- @with_tracebacks(ZeroDivisionError, name="AggrExceptionInInit") ++ @with_tracebacks(ZeroDivisionError, msg_regex="AggrExceptionInInit") + def test_aggr_exception_in_init(self): + cur = self.con.cursor() + with self.assertRaises(sqlite.OperationalError) as cm: +@@ -664,7 +663,7 @@ + val = cur.fetchone()[0] + self.assertEqual(str(cm.exception), "user-defined aggregate's '__init__' method raised error") + +- @with_tracebacks(ZeroDivisionError, name="AggrExceptionInStep") ++ @with_tracebacks(ZeroDivisionError, msg_regex="AggrExceptionInStep") + def test_aggr_exception_in_step(self): + cur = self.con.cursor() + with self.assertRaises(sqlite.OperationalError) as cm: +@@ -672,7 +671,7 @@ + val = cur.fetchone()[0] + self.assertEqual(str(cm.exception), "user-defined aggregate's 'step' method raised error") + +- @with_tracebacks(ZeroDivisionError, name="AggrExceptionInFinalize") ++ @with_tracebacks(ZeroDivisionError, msg_regex="AggrExceptionInFinalize") + def test_aggr_exception_in_finalize(self): + cur = self.con.cursor() + with self.assertRaises(sqlite.OperationalError) as cm: +@@ -822,11 +821,11 @@ + raise ValueError + return sqlite.SQLITE_OK + +- @with_tracebacks(ValueError, name="authorizer_cb") ++ @with_tracebacks(ValueError, msg_regex="authorizer_cb") + def test_table_access(self): + super().test_table_access() + +- @with_tracebacks(ValueError, name="authorizer_cb") ++ @with_tracebacks(ValueError, msg_regex="authorizer_cb") + def test_column_access(self): + super().test_table_access() + +diff --git a/Lib/test/test_sqlite3/util.py b/Lib/test/test_sqlite3/util.py +index 5599823838b..cccd062160f 100644 +--- a/Lib/test/test_sqlite3/util.py ++++ b/Lib/test/test_sqlite3/util.py +@@ -4,6 +4,7 @@ + import re + import sqlite3 + import test.support ++import unittest + + + # Helper for temporary memory databases +@@ -22,15 +23,16 @@ + cx.setlimit(category, _prev) + + +-def with_tracebacks(exc, regex="", name=""): ++def with_tracebacks(exc, regex="", name="", msg_regex=""): + """Convenience decorator for testing callback tracebacks.""" + def decorator(func): +- _regex = re.compile(regex) if regex else None ++ exc_regex = re.compile(regex) if regex else None ++ _msg_regex = re.compile(msg_regex) if msg_regex else None + @functools.wraps(func) + def wrapper(self, *args, **kwargs): + with test.support.catch_unraisable_exception() as cm: + # First, run the test with traceback enabled. +- with check_tracebacks(self, cm, exc, _regex, name): ++ with check_tracebacks(self, cm, exc, exc_regex, _msg_regex, name): + func(self, *args, **kwargs) + + # Then run the test with traceback disabled. +@@ -40,7 +42,7 @@ + + + @contextlib.contextmanager +-def check_tracebacks(self, cm, exc, regex, obj_name): ++def check_tracebacks(self, cm, exc, exc_regex, msg_regex, obj_name): + """Convenience context manager for testing callback tracebacks.""" + sqlite3.enable_callback_tracebacks(True) + try: +@@ -49,9 +51,12 @@ + yield + + self.assertEqual(cm.unraisable.exc_type, exc) +- if regex: ++ if exc_regex: + msg = str(cm.unraisable.exc_value) +- self.assertIsNotNone(regex.search(msg)) ++ self.assertIsNotNone(exc_regex.search(msg), (exc_regex, msg)) ++ if msg_regex: ++ msg = cm.unraisable.err_msg ++ self.assertIsNotNone(msg_regex.search(msg), (msg_regex, msg)) + if obj_name: + self.assertEqual(cm.unraisable.object.__name__, obj_name) + finally: +@@ -75,3 +80,10 @@ + @property + def cu(self): + return self.cur ++ ++ ++def requires_virtual_table(module): ++ with memory_database() as cx: ++ supported = (module,) in list(cx.execute("PRAGMA module_list")) ++ reason = f"Requires {module!r} virtual table support" ++ return unittest.skipUnless(supported, reason) +diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py +index 3f6f890bbdc..9863f3ffe97 100644 +--- a/Lib/test/test_ssl.py ++++ b/Lib/test/test_ssl.py +@@ -1325,8 +1325,7 @@ + def test_load_dh_params(self): + ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + ctx.load_dh_params(DHFILE) +- if os.name != 'nt': +- ctx.load_dh_params(BYTES_DHFILE) ++ ctx.load_dh_params(BYTES_DHFILE) + self.assertRaises(TypeError, ctx.load_dh_params) + self.assertRaises(TypeError, ctx.load_dh_params, None) + with self.assertRaises(FileNotFoundError) as cm: +@@ -4494,7 +4493,8 @@ + s.connect((HOST, server.port)) + + +-@unittest.skipUnless(has_tls_version('TLSv1_3'), "Test needs TLS 1.3") ++@unittest.skipUnless(has_tls_version('TLSv1_3') and ssl.HAS_PHA, ++ "Test needs TLS 1.3 PHA") + class TestPostHandshakeAuth(unittest.TestCase): + def test_pha_setter(self): + protocols = [ +diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py +index fa08dc6a25b..f3724ce6d4d 100644 +--- a/Lib/test/test_stable_abi_ctypes.py ++++ b/Lib/test/test_stable_abi_ctypes.py +@@ -901,6 +901,8 @@ + "Py_MakePendingCalls", + "Py_NewInterpreter", + "Py_NewRef", ++ "Py_PACK_FULL_VERSION", ++ "Py_PACK_VERSION", + "Py_REFCNT", + "Py_ReprEnter", + "Py_ReprLeave", +diff --git a/Lib/test/test_str.py b/Lib/test/test_str.py +index 4de6c1cba15..d1c9542c7d1 100644 +--- a/Lib/test/test_str.py ++++ b/Lib/test/test_str.py +@@ -7,6 +7,7 @@ + """ + import _string + import codecs ++import datetime + import itertools + import operator + import pickle +@@ -1908,6 +1909,12 @@ + self.assertRaises(UnicodeDecodeError, + (b'\xF4'+cb+b'\xBF\xBF').decode, 'utf-8') + ++ def test_issue127903(self): ++ # gh-127903: ``_copy_characters`` crashes on DEBUG builds when ++ # there is nothing to copy. ++ d = datetime.datetime(2013, 11, 10, 14, 20, 59) ++ self.assertEqual(d.strftime('%z'), '') ++ + def test_issue8271(self): + # Issue #8271: during the decoding of an invalid UTF-8 byte sequence, + # only the start byte and the continuation byte(s) are now considered +diff --git a/Lib/test/test_string.py b/Lib/test/test_string.py +index 824b89ad517..f6d112d8a93 100644 +--- a/Lib/test/test_string.py ++++ b/Lib/test/test_string.py +@@ -1,6 +1,7 @@ + import unittest + import string + from string import Template ++import types + + + class ModuleTest(unittest.TestCase): +@@ -101,6 +102,24 @@ + with self.assertRaises(KeyError): + fmt.format("{0[2]}{0[0]}", {}) + ++ def test_auto_numbering_lookup(self): ++ fmt = string.Formatter() ++ namespace = types.SimpleNamespace(foo=types.SimpleNamespace(bar='baz')) ++ widths = [None, types.SimpleNamespace(qux=4)] ++ self.assertEqual( ++ fmt.format("{.foo.bar:{[1].qux}}", namespace, widths), 'baz ') ++ ++ def test_auto_numbering_reenterability(self): ++ class ReenteringFormatter(string.Formatter): ++ def format_field(self, value, format_spec): ++ if format_spec.isdigit() and int(format_spec) > 0: ++ return self.format('{:{}}!', value, int(format_spec) - 1) ++ else: ++ return super().format_field(value, format_spec) ++ fmt = ReenteringFormatter() ++ x = types.SimpleNamespace(a='X') ++ self.assertEqual(fmt.format('{.a:{}}', x, 3), 'X!!!') ++ + def test_override_get_value(self): + class NamespaceFormatter(string.Formatter): + def __init__(self, namespace={}): +diff --git a/Lib/test/test_string_literals.py b/Lib/test/test_string_literals.py +index c7c6f684cd3..f56195ca276 100644 +--- a/Lib/test/test_string_literals.py ++++ b/Lib/test/test_string_literals.py +@@ -116,7 +116,9 @@ + warnings.simplefilter('always', category=SyntaxWarning) + eval("'''\n\\z'''") + self.assertEqual(len(w), 1) +- self.assertEqual(str(w[0].message), r"invalid escape sequence '\z'") ++ self.assertEqual(str(w[0].message), r'"\z" is an invalid escape sequence. ' ++ r'Such sequences will not work in the future. ' ++ r'Did you mean "\\z"? A raw string is also an option.') + self.assertEqual(w[0].filename, '') + self.assertEqual(w[0].lineno, 1) + +@@ -126,7 +128,8 @@ + eval("'''\n\\z'''") + exc = cm.exception + self.assertEqual(w, []) +- self.assertEqual(exc.msg, r"invalid escape sequence '\z'") ++ self.assertEqual(exc.msg, r'"\z" is an invalid escape sequence. ' ++ r'Did you mean "\\z"? A raw string is also an option.') + self.assertEqual(exc.filename, '') + self.assertEqual(exc.lineno, 1) + self.assertEqual(exc.offset, 1) +@@ -153,7 +156,9 @@ + eval("'''\n\\407'''") + self.assertEqual(len(w), 1) + self.assertEqual(str(w[0].message), +- r"invalid octal escape sequence '\407'") ++ r'"\407" is an invalid octal escape sequence. ' ++ r'Such sequences will not work in the future. ' ++ r'Did you mean "\\407"? A raw string is also an option.') + self.assertEqual(w[0].filename, '') + self.assertEqual(w[0].lineno, 1) + +@@ -163,7 +168,8 @@ + eval("'''\n\\407'''") + exc = cm.exception + self.assertEqual(w, []) +- self.assertEqual(exc.msg, r"invalid octal escape sequence '\407'") ++ self.assertEqual(exc.msg, r'"\407" is an invalid octal escape sequence. ' ++ r'Did you mean "\\407"? A raw string is also an option.') + self.assertEqual(exc.filename, '') + self.assertEqual(exc.lineno, 1) + self.assertEqual(exc.offset, 1) +@@ -205,7 +211,9 @@ + warnings.simplefilter('always', category=SyntaxWarning) + eval("b'''\n\\z'''") + self.assertEqual(len(w), 1) +- self.assertEqual(str(w[0].message), r"invalid escape sequence '\z'") ++ self.assertEqual(str(w[0].message), r'"\z" is an invalid escape sequence. ' ++ r'Such sequences will not work in the future. ' ++ r'Did you mean "\\z"? A raw string is also an option.') + self.assertEqual(w[0].filename, '') + self.assertEqual(w[0].lineno, 1) + +@@ -215,7 +223,8 @@ + eval("b'''\n\\z'''") + exc = cm.exception + self.assertEqual(w, []) +- self.assertEqual(exc.msg, r"invalid escape sequence '\z'") ++ self.assertEqual(exc.msg, r'"\z" is an invalid escape sequence. ' ++ r'Did you mean "\\z"? A raw string is also an option.') + self.assertEqual(exc.filename, '') + self.assertEqual(exc.lineno, 1) + +@@ -228,8 +237,9 @@ + warnings.simplefilter('always', category=SyntaxWarning) + eval("b'''\n\\407'''") + self.assertEqual(len(w), 1) +- self.assertEqual(str(w[0].message), +- r"invalid octal escape sequence '\407'") ++ self.assertEqual(str(w[0].message), r'"\407" is an invalid octal escape sequence. ' ++ r'Such sequences will not work in the future. ' ++ r'Did you mean "\\407"? A raw string is also an option.') + self.assertEqual(w[0].filename, '') + self.assertEqual(w[0].lineno, 1) + +@@ -239,7 +249,8 @@ + eval("b'''\n\\407'''") + exc = cm.exception + self.assertEqual(w, []) +- self.assertEqual(exc.msg, r"invalid octal escape sequence '\407'") ++ self.assertEqual(exc.msg, r'"\407" is an invalid octal escape sequence. ' ++ r'Did you mean "\\407"? A raw string is also an option.') + self.assertEqual(exc.filename, '') + self.assertEqual(exc.lineno, 1) + +diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py +index 5fee9fbb92a..b99391e482f 100644 +--- a/Lib/test/test_struct.py ++++ b/Lib/test/test_struct.py +@@ -694,7 +694,7 @@ + rc, stdout, stderr = assert_python_ok("-c", code) + self.assertEqual(rc, 0) + self.assertEqual(stdout.rstrip(), b"") +- self.assertIn(b"Exception ignored in:", stderr) ++ self.assertIn(b"Exception ignored while calling deallocator", stderr) + self.assertIn(b"C.__del__", stderr) + + def test__struct_reference_cycle_cleaned_up(self): +diff --git a/Lib/test/test_super.py b/Lib/test/test_super.py +index 14901663552..5cef612a340 100644 +--- a/Lib/test/test_super.py ++++ b/Lib/test/test_super.py +@@ -9,9 +9,6 @@ + from test.support import import_helper, threading_helper + + +-ADAPTIVE_WARMUP_DELAY = 2 +- +- + class A: + def f(self): + return 'A' +@@ -466,7 +463,8 @@ + super(MyType, type(mytype)).__setattr__(mytype, "bar", 1) + self.assertEqual(mytype.bar, 1) + +- for _ in range(ADAPTIVE_WARMUP_DELAY): ++ _testinternalcapi = import_helper.import_module("_testinternalcapi") ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + test("foo1") + + def test_reassigned_new(self): +@@ -485,7 +483,8 @@ + def __new__(cls): + return super().__new__(cls) + +- for _ in range(ADAPTIVE_WARMUP_DELAY): ++ _testinternalcapi = import_helper.import_module("_testinternalcapi") ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + C() + + def test_mixed_staticmethod_hierarchy(self): +@@ -505,7 +504,8 @@ + def some(cls): + return super().some(cls) + +- for _ in range(ADAPTIVE_WARMUP_DELAY): ++ _testinternalcapi = import_helper.import_module("_testinternalcapi") ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + C.some(C) + + @threading_helper.requires_working_threading() +diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py +index d839893d2c6..39857445a02 100644 +--- a/Lib/test/test_sys.py ++++ b/Lib/test/test_sys.py +@@ -1621,7 +1621,7 @@ + return sys._getframe() + x = func() + if support.Py_GIL_DISABLED: +- INTERPRETER_FRAME = '10PhcP' ++ INTERPRETER_FRAME = '9PihcP' + else: + INTERPRETER_FRAME = '9PhcP' + check(x, size('3PiccPP' + INTERPRETER_FRAME + 'P')) +diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py +index 95cf0d1ec2d..28c2c681bab 100644 +--- a/Lib/test/test_sys_settrace.py ++++ b/Lib/test/test_sys_settrace.py +@@ -6,8 +6,7 @@ + import difflib + import gc + from functools import wraps +-import asyncio +-from test.support import import_helper, requires_subprocess ++from test.support import import_helper, requires_subprocess, run_no_yield_async_fn + import contextlib + import os + import tempfile +@@ -19,8 +18,6 @@ + except ImportError: + _testinternalcapi = None + +-support.requires_working_socket(module=True) +- + class tracecontext: + """Context manager that traces its enter and exit.""" + def __init__(self, output, value): +@@ -2067,10 +2064,9 @@ + stack.enter_context(self.assertRaisesRegex(*error)) + if warning is not None: + stack.enter_context(self.assertWarnsRegex(*warning)) +- asyncio.run(func(output)) ++ run_no_yield_async_fn(func, output) + + sys.settrace(None) +- asyncio.set_event_loop_policy(None) + self.compare_jump_output(expected, output) + + def jump_test(jumpFrom, jumpTo, expected, error=None, event='line', warning=None): +diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py +index ce504dc21af..3738914cf17 100644 +--- a/Lib/test/test_sysconfig.py ++++ b/Lib/test/test_sysconfig.py +@@ -20,7 +20,7 @@ + from test.support.import_helper import import_module + from test.support.os_helper import (TESTFN, unlink, skip_unless_symlink, + change_cwd) +-from test.support.venv import VirtualEnvironment ++from test.support.venv import VirtualEnvironmentMixin + + import sysconfig + from sysconfig import (get_paths, get_platform, get_config_vars, +@@ -37,7 +37,7 @@ + HAS_USER_BASE = sysconfig._HAS_USER_BASE + + +-class TestSysConfig(unittest.TestCase): ++class TestSysConfig(unittest.TestCase, VirtualEnvironmentMixin): + + def setUp(self): + super(TestSysConfig, self).setUp() +@@ -111,13 +111,6 @@ + elif os.path.isdir(path): + shutil.rmtree(path) + +- def venv(self, **venv_create_args): +- return VirtualEnvironment.from_tmpdir( +- prefix=f'{self.id()}-venv-', +- **venv_create_args, +- ) +- +- + def test_get_path_names(self): + self.assertEqual(get_path_names(), sysconfig._SCHEME_KEYS) + +@@ -650,8 +643,21 @@ + + system_config_vars = get_config_vars() + +- # Ignore keys in the check +- for key in ('projectbase', 'srcdir'): ++ ignore_keys = set() ++ # Keys dependent on Python being run outside the build directrory ++ if sysconfig.is_python_build(): ++ ignore_keys |= {'srcdir'} ++ # Keys dependent on the executable location ++ if os.path.dirname(sys.executable) != system_config_vars['BINDIR']: ++ ignore_keys |= {'projectbase'} ++ # Keys dependent on the environment (different inside virtual environments) ++ if sys.prefix != sys.base_prefix: ++ ignore_keys |= {'prefix', 'exec_prefix', 'base', 'platbase'} ++ # Keys dependent on Python being run from the prefix targetted when building (different on relocatable installs) ++ if sysconfig._installation_is_relocated(): ++ ignore_keys |= {'prefix', 'exec_prefix', 'base', 'platbase', 'installed_base', 'installed_platbase'} ++ ++ for key in ignore_keys: + json_config_vars.pop(key) + system_config_vars.pop(key) + +@@ -711,5 +717,38 @@ + }) + + ++class DeprecationTests(unittest.TestCase): ++ def deprecated(self, removal_version, deprecation_msg=None, error=Exception, error_msg=None): ++ if sys.version_info >= removal_version: ++ return self.assertRaises(error, msg=error_msg) ++ else: ++ return self.assertWarns(DeprecationWarning, msg=deprecation_msg) ++ ++ def test_expand_makefile_vars(self): ++ with self.deprecated( ++ removal_version=(3, 16), ++ deprecation_msg=( ++ 'sysconfig.expand_makefile_vars is deprecated and will be removed in ' ++ 'Python 3.16. Use sysconfig.get_paths(vars=...) instead.', ++ ), ++ error=AttributeError, ++ error_msg="module 'sysconfig' has no attribute 'expand_makefile_vars'", ++ ): ++ sysconfig.expand_makefile_vars('', {}) ++ ++ def test_is_python_build_check_home(self): ++ with self.deprecated( ++ removal_version=(3, 15), ++ deprecation_msg=( ++ 'The check_home argument of sysconfig.is_python_build is ' ++ 'deprecated and its value is ignored. ' ++ 'It will be removed in Python 3.15.' ++ ), ++ error=TypeError, ++ error_msg="is_python_build() takes 0 positional arguments but 1 were given", ++ ): ++ sysconfig.is_python_build('foo') ++ ++ + if __name__ == "__main__": + unittest.main() +diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py +index 57e9bd20c77..7adc021d298 100644 +--- a/Lib/test/test_tempfile.py ++++ b/Lib/test/test_tempfile.py +@@ -1112,11 +1112,14 @@ + # Testing extreme case, where the file is not explicitly closed + # f.close() + return tmp_name +- # Make sure that the garbage collector has finalized the file object. +- gc.collect() + dir = tempfile.mkdtemp() + try: +- tmp_name = my_func(dir) ++ with self.assertWarnsRegex( ++ expected_warning=ResourceWarning, ++ expected_regex=r"Implicitly cleaning up <_TemporaryFileWrapper file=.*>", ++ ): ++ tmp_name = my_func(dir) ++ support.gc_collect() + self.assertFalse(os.path.exists(tmp_name), + f"NamedTemporaryFile {tmp_name!r} " + f"exists after finalizer ") +diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py +index 3e164a12581..214e1ba0b53 100644 +--- a/Lib/test/test_threading.py ++++ b/Lib/test/test_threading.py +@@ -2130,6 +2130,15 @@ + + # Test long non-ASCII name (truncated) + "x" * (limit - 1) + "é€", ++ ++ # Test long non-BMP names (truncated) creating surrogate pairs ++ # on Windows ++ "x" * (limit - 1) + "\U0010FFFF", ++ "x" * (limit - 2) + "\U0010FFFF" * 2, ++ "x" + "\U0001f40d" * limit, ++ "xx" + "\U0001f40d" * limit, ++ "xxx" + "\U0001f40d" * limit, ++ "xxxx" + "\U0001f40d" * limit, + ] + if os_helper.FS_NONASCII: + tests.append(f"nonascii:{os_helper.FS_NONASCII}") +@@ -2146,15 +2155,31 @@ + work_name = _thread._get_name() + + for name in tests: +- encoded = name.encode(encoding, "replace") +- if b'\0' in encoded: +- encoded = encoded.split(b'\0', 1)[0] +- if truncate is not None: +- encoded = encoded[:truncate] +- if sys.platform.startswith("solaris"): +- expected = encoded.decode("utf-8", "surrogateescape") ++ if not support.MS_WINDOWS: ++ encoded = name.encode(encoding, "replace") ++ if b'\0' in encoded: ++ encoded = encoded.split(b'\0', 1)[0] ++ if truncate is not None: ++ encoded = encoded[:truncate] ++ if sys.platform.startswith("solaris"): ++ expected = encoded.decode("utf-8", "surrogateescape") ++ else: ++ expected = os.fsdecode(encoded) + else: +- expected = os.fsdecode(encoded) ++ size = 0 ++ chars = [] ++ for ch in name: ++ if ord(ch) > 0xFFFF: ++ size += 2 ++ else: ++ size += 1 ++ if size > truncate: ++ break ++ chars.append(ch) ++ expected = ''.join(chars) ++ ++ if '\0' in expected: ++ expected = expected.split('\0', 1)[0] + + with self.subTest(name=name, expected=expected): + work_name = None +diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py +index 1c540bed33c..1147997d8d8 100644 +--- a/Lib/test/test_time.py ++++ b/Lib/test/test_time.py +@@ -158,10 +158,19 @@ + self.assertEqual(int(time.mktime(time.localtime(self.t))), + int(self.t)) + +- def test_sleep(self): ++ def test_sleep_exceptions(self): ++ self.assertRaises(TypeError, time.sleep, []) ++ self.assertRaises(TypeError, time.sleep, "a") ++ self.assertRaises(TypeError, time.sleep, complex(0, 0)) ++ + self.assertRaises(ValueError, time.sleep, -2) + self.assertRaises(ValueError, time.sleep, -1) +- time.sleep(1.2) ++ self.assertRaises(ValueError, time.sleep, -0.1) ++ ++ def test_sleep(self): ++ for value in [-0.0, 0, 0.0, 1e-100, 1e-9, 1e-6, 1, 1.2]: ++ with self.subTest(value=value): ++ time.sleep(value) + + def test_epoch(self): + # bpo-43869: Make sure that Python use the same Epoch on all platforms: +diff --git a/Lib/test/test_tkinter/test_misc.py b/Lib/test/test_tkinter/test_misc.py +index 475edcbd533..96ea3f0117c 100644 +--- a/Lib/test/test_tkinter/test_misc.py ++++ b/Lib/test/test_tkinter/test_misc.py +@@ -4,7 +4,8 @@ + from tkinter import TclError + import enum + from test import support +-from test.test_tkinter.support import AbstractTkTest, AbstractDefaultRootTest, requires_tk ++from test.test_tkinter.support import (AbstractTkTest, AbstractDefaultRootTest, ++ requires_tk, get_tk_patchlevel) + + support.requires('gui') + +@@ -30,12 +31,20 @@ + self.assertEqual(repr(f), '') + + def test_generated_names(self): ++ class Button2(tkinter.Button): ++ pass ++ + t = tkinter.Toplevel(self.root) + f = tkinter.Frame(t) + f2 = tkinter.Frame(t) ++ self.assertNotEqual(str(f), str(f2)) + b = tkinter.Button(f2) +- for name in str(b).split('.'): ++ b2 = Button2(f2) ++ for name in str(b).split('.') + str(b2).split('.'): + self.assertFalse(name.isidentifier(), msg=repr(name)) ++ b3 = tkinter.Button(f2) ++ b4 = Button2(f2) ++ self.assertEqual(len({str(b), str(b2), str(b3), str(b4)}), 4) + + @requires_tk(8, 6, 6) + def test_tk_busy(self): +@@ -554,6 +563,31 @@ + self.assertEqual(w.wm_attributes('alpha'), + 1.0 if self.wantobjects else '1.0') + ++ def test_wm_iconbitmap(self): ++ t = tkinter.Toplevel(self.root) ++ self.assertEqual(t.wm_iconbitmap(), '') ++ t.wm_iconbitmap('hourglass') ++ bug = False ++ if t._windowingsystem == 'aqua': ++ # Tk bug 13ac26b35dc55f7c37f70b39d59d7ef3e63017c8. ++ patchlevel = get_tk_patchlevel(t) ++ if patchlevel < (8, 6, 17) or (9, 0) <= patchlevel < (9, 0, 2): ++ bug = True ++ if not bug: ++ self.assertEqual(t.wm_iconbitmap(), 'hourglass') ++ self.assertEqual(self.root.wm_iconbitmap(), '') ++ t.wm_iconbitmap('') ++ self.assertEqual(t.wm_iconbitmap(), '') ++ ++ if t._windowingsystem == 'win32': ++ t.wm_iconbitmap(default='hourglass') ++ self.assertEqual(t.wm_iconbitmap(), 'hourglass') ++ self.assertEqual(self.root.wm_iconbitmap(), '') ++ t.wm_iconbitmap(default='') ++ self.assertEqual(t.wm_iconbitmap(), '') ++ ++ t.destroy() ++ + + class EventTest(AbstractTkTest, unittest.TestCase): + +diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py +index 75710db7d05..52d33419750 100644 +--- a/Lib/test/test_tokenize.py ++++ b/Lib/test/test_tokenize.py +@@ -1,4 +1,5 @@ + import os ++import re + import token + import tokenize + import unittest +@@ -1537,6 +1538,7 @@ + self.assertEqual(encoding, 'utf-8') + self.assertEqual(consumed_lines, [b'print("#coding=fake")']) + ++ @support.thread_unsafe + def test_open(self): + filename = os_helper.TESTFN + '.py' + self.addCleanup(os_helper.unlink, filename) +@@ -1819,6 +1821,22 @@ + self.assertEqual(tokenize.untokenize(iter(tokens)), b'Hello ') + + ++def contains_ambiguous_backslash(source): ++ """Return `True` if the source contains a backslash on a ++ line by itself. For example: ++ ++ a = (1 ++ \\ ++ ) ++ ++ Code like this cannot be untokenized exactly. This is because ++ the tokenizer does not produce any tokens for the line containing ++ the backslash and so there is no way to know its indent. ++ """ ++ pattern = re.compile(br'\n\s*\\\r?\n') ++ return pattern.search(source) is not None ++ ++ + class TestRoundtrip(TestCase): + + def check_roundtrip(self, f): +@@ -1829,6 +1847,9 @@ + tokenize.untokenize(), and the latter tokenized again to 2-tuples. + The test fails if the 3 pair tokenizations do not match. + ++ If the source code can be untokenized unambiguously, the ++ untokenized code must match the original code exactly. ++ + When untokenize bugs are fixed, untokenize with 5-tuples should + reproduce code that does not contain a backslash continuation + following spaces. A proper test should test this. +@@ -1852,6 +1873,13 @@ + tokens2_from5 = [tok[:2] for tok in tokenize.tokenize(readline5)] + self.assertEqual(tokens2_from5, tokens2) + ++ if not contains_ambiguous_backslash(code): ++ # The BOM does not produce a token so there is no way to preserve it. ++ code_without_bom = code.removeprefix(b'\xef\xbb\xbf') ++ readline = iter(code_without_bom.splitlines(keepends=True)).__next__ ++ untokenized_code = tokenize.untokenize(tokenize.tokenize(readline)) ++ self.assertEqual(code_without_bom, untokenized_code) ++ + def check_line_extraction(self, f): + if isinstance(f, str): + code = f.encode('utf-8') +diff --git a/Lib/test/test_tomllib/test_misc.py b/Lib/test/test_tomllib/test_misc.py +index 9e677a337a2..59116afa1f3 100644 +--- a/Lib/test/test_tomllib/test_misc.py ++++ b/Lib/test/test_tomllib/test_misc.py +@@ -5,6 +5,7 @@ + import copy + import datetime + from decimal import Decimal as D ++import importlib + from pathlib import Path + import sys + import tempfile +@@ -113,3 +114,11 @@ + nest_count=nest_count): + recursive_table_toml = nest_count * "key = {" + nest_count * "}" + tomllib.loads(recursive_table_toml) ++ ++ def test_types_import(self): ++ """Test that `_types` module runs. ++ ++ The module is for type annotations only, so it is otherwise ++ never imported by tests. ++ """ ++ importlib.import_module(f"{tomllib.__name__}._types") +diff --git a/Lib/test/test_tools/i18n_data/docstrings.pot b/Lib/test/test_tools/i18n_data/docstrings.pot +index 5af1d41422f..387db2413a5 100644 +--- a/Lib/test/test_tools/i18n_data/docstrings.pot ++++ b/Lib/test/test_tools/i18n_data/docstrings.pot +@@ -15,26 +15,40 @@ + "Generated-By: pygettext.py 1.5\n" + + +-#: docstrings.py:7 ++#: docstrings.py:1 ++#, docstring ++msgid "Module docstring" ++msgstr "" ++ ++#: docstrings.py:9 + #, docstring + msgid "" + msgstr "" + +-#: docstrings.py:18 ++#: docstrings.py:15 ++#, docstring ++msgid "docstring" ++msgstr "" ++ ++#: docstrings.py:20 + #, docstring + msgid "" + "multiline\n" +-" docstring\n" +-" " ++"docstring" + msgstr "" + +-#: docstrings.py:25 ++#: docstrings.py:27 + #, docstring + msgid "docstring1" + msgstr "" + +-#: docstrings.py:30 ++#: docstrings.py:38 ++#, docstring ++msgid "nested docstring" ++msgstr "" ++ ++#: docstrings.py:43 + #, docstring +-msgid "Hello, {}!" ++msgid "nested class docstring" + msgstr "" + +diff --git a/Lib/test/test_tools/i18n_data/docstrings.py b/Lib/test/test_tools/i18n_data/docstrings.py +index 85d7f159d37..151a55a4b56 100644 +--- a/Lib/test/test_tools/i18n_data/docstrings.py ++++ b/Lib/test/test_tools/i18n_data/docstrings.py +@@ -1,3 +1,5 @@ ++"""Module docstring""" ++ + # Test docstring extraction + from gettext import gettext as _ + +@@ -10,10 +12,10 @@ + # Leading empty line + def test2(x): + +- """docstring""" # XXX This should be extracted but isn't. ++ """docstring""" + + +-# XXX Multiline docstrings should be cleaned with `inspect.cleandoc`. ++# Multiline docstrings are cleaned with `inspect.cleandoc`. + def test3(x): + """multiline + docstring +@@ -27,15 +29,15 @@ + + + def test5(x): +- """Hello, {}!""".format("world!") # XXX This should not be extracted. ++ """Hello, {}!""".format("world!") # This should not be extracted. + + + # Nested docstrings + def test6(x): + def inner(y): +- """nested docstring""" # XXX This should be extracted but isn't. ++ """nested docstring""" + + + class Outer: + class Inner: +- "nested class docstring" # XXX This should be extracted but isn't. ++ "nested class docstring" +diff --git a/Lib/test/test_tools/i18n_data/messages.pot b/Lib/test/test_tools/i18n_data/messages.pot +index 8d66fbc4f3a..e8167acfc07 100644 +--- a/Lib/test/test_tools/i18n_data/messages.pot ++++ b/Lib/test/test_tools/i18n_data/messages.pot +@@ -19,22 +19,22 @@ + msgid "" + msgstr "" + +-#: messages.py:19 messages.py:20 ++#: messages.py:19 messages.py:20 messages.py:21 + msgid "parentheses" + msgstr "" + +-#: messages.py:23 ++#: messages.py:24 + msgid "Hello, world!" + msgstr "" + +-#: messages.py:26 ++#: messages.py:27 + msgid "" + "Hello,\n" + " multiline!\n" + msgstr "" + + #: messages.py:46 messages.py:89 messages.py:90 messages.py:93 messages.py:94 +-#: messages.py:99 ++#: messages.py:99 messages.py:100 messages.py:101 + msgid "foo" + msgid_plural "foos" + msgstr[0] "" +@@ -68,7 +68,7 @@ + msgid "set" + msgstr "" + +-#: messages.py:63 ++#: messages.py:62 messages.py:63 + msgid "nested string" + msgstr "" + +@@ -76,6 +76,10 @@ + msgid "baz" + msgstr "" + ++#: messages.py:71 messages.py:75 ++msgid "default value" ++msgstr "" ++ + #: messages.py:91 messages.py:92 messages.py:95 messages.py:96 + msgctxt "context" + msgid "foo" +@@ -83,7 +87,13 @@ + msgstr[0] "" + msgstr[1] "" + +-#: messages.py:100 ++#: messages.py:102 + msgid "domain foo" + msgstr "" + ++#: messages.py:118 messages.py:119 ++msgid "world" ++msgid_plural "worlds" ++msgstr[0] "" ++msgstr[1] "" ++ +diff --git a/Lib/test/test_tools/i18n_data/messages.py b/Lib/test/test_tools/i18n_data/messages.py +index 1e03f4e5568..9457bcb8611 100644 +--- a/Lib/test/test_tools/i18n_data/messages.py ++++ b/Lib/test/test_tools/i18n_data/messages.py +@@ -18,6 +18,7 @@ + # Extra parentheses + (_("parentheses")) + ((_("parentheses"))) ++_(("parentheses")) + + # Multiline strings + _("Hello, " +@@ -32,7 +33,6 @@ + _(None) + _(1) + _(False) +-_(("invalid")) + _(["invalid"]) + _({"invalid"}) + _("string"[3]) +@@ -40,7 +40,7 @@ + _({"string": "foo"}) + + # pygettext does not allow keyword arguments, but both xgettext and pybabel do +-_(x="kwargs work!") ++_(x="kwargs are not allowed!") + + # Unusual, but valid arguments + _("foo", "bar") +@@ -48,7 +48,7 @@ + + # .format() + _("Hello, {}!").format("world") # valid +-_("Hello, {}!".format("world")) # invalid, but xgettext and pybabel extract the first string ++_("Hello, {}!".format("world")) # invalid, but xgettext extracts the first string + + # Nested structures + _("1"), _("2") +@@ -59,7 +59,7 @@ + + # Nested functions and classes + def test(): +- _("nested string") # XXX This should be extracted but isn't. ++ _("nested string") + [_("nested string")] + + +@@ -68,11 +68,11 @@ + return _("baz") + + +-def bar(x=_('default value')): # XXX This should be extracted but isn't. ++def bar(x=_('default value')): + pass + + +-def baz(x=[_('default value')]): # XXX This should be extracted but isn't. ++def baz(x=[_('default value')]): + pass + + +@@ -97,6 +97,8 @@ + + # Complex arguments + ngettext("foo", "foos", 42 + (10 - 20)) ++ngettext("foo", "foos", *args) ++ngettext("foo", "foos", **kwargs) + dgettext(["some", {"complex"}, ("argument",)], "domain foo") + + # Invalid calls which are not extracted +@@ -108,3 +110,10 @@ + dngettext('domain', 'foo') + dpgettext('domain', 'context') + dnpgettext('domain', 'context', 'foo') ++dgettext(*args, 'foo') ++dpgettext(*args, 'context', 'foo') ++dnpgettext(*args, 'context', 'foo', 'foos') ++ ++# f-strings ++f"Hello, {_('world')}!" ++f"Hello, {ngettext('world', 'worlds', 3)}!" +diff --git a/Lib/test/test_tools/test_i18n.py b/Lib/test/test_tools/test_i18n.py +index 29c3423e234..d23479104d4 100644 +--- a/Lib/test/test_tools/test_i18n.py ++++ b/Lib/test/test_tools/test_i18n.py +@@ -87,7 +87,7 @@ + self.maxDiff = None + self.assertEqual(normalize_POT_file(expected), normalize_POT_file(actual)) + +- def extract_from_str(self, module_content, *, args=(), strict=True): ++ def extract_from_str(self, module_content, *, args=(), strict=True, with_stderr=False): + """Return all msgids extracted from module_content.""" + filename = 'test.py' + with temp_cwd(None): +@@ -98,12 +98,18 @@ + self.assertEqual(res.err, b'') + with open('messages.pot', encoding='utf-8') as fp: + data = fp.read() +- return self.get_msgids(data) ++ msgids = self.get_msgids(data) ++ if not with_stderr: ++ return msgids ++ return msgids, res.err + + def extract_docstrings_from_str(self, module_content): + """Return all docstrings extracted from module_content.""" + return self.extract_from_str(module_content, args=('--docstrings',), strict=False) + ++ def get_stderr(self, module_content): ++ return self.extract_from_str(module_content, strict=False, with_stderr=True)[1] ++ + def test_header(self): + """Make sure the required fields are in the header, according to: + http://www.gnu.org/software/gettext/manual/gettext.html#Header-Entry +@@ -407,6 +413,24 @@ + self.assertIn(f'msgid "{text2}"', data) + self.assertNotIn(text3, data) + ++ def test_error_messages(self): ++ """Test that pygettext outputs error messages to stderr.""" ++ stderr = self.get_stderr(dedent('''\ ++ _(1+2) ++ ngettext('foo') ++ dgettext(*args, 'foo') ++ ''')) ++ ++ # Normalize line endings on Windows ++ stderr = stderr.decode('utf-8').replace('\r', '') ++ ++ self.assertEqual( ++ stderr, ++ "*** test.py:1: Expected a string constant for argument 1, got 1 + 2\n" ++ "*** test.py:2: Expected at least 2 positional argument(s) in gettext call, got 1\n" ++ "*** test.py:3: Variable positional arguments are not allowed in gettext calls\n" ++ ) ++ + + def update_POT_snapshots(): + for input_file in DATA_DIR.glob('*.py'): +diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py +index 31f0a61d6a9..89980ae6f85 100644 +--- a/Lib/test/test_traceback.py ++++ b/Lib/test/test_traceback.py +@@ -21,7 +21,7 @@ + from test.support.os_helper import TESTFN, unlink + from test.support.script_helper import assert_python_ok, assert_python_failure + from test.support.import_helper import forget +-from test.support import force_not_colorized ++from test.support import force_not_colorized, force_not_colorized_test_class + + import json + import textwrap +@@ -86,7 +86,7 @@ + err = self.get_exception_format(self.syntax_error_with_caret, + SyntaxError) + self.assertEqual(len(err), 4) +- self.assertTrue(err[1].strip() == "return x!") ++ self.assertEqual(err[1].strip(), "return x!") + self.assertIn("^", err[2]) # third line has caret + self.assertEqual(err[1].find("!"), err[2].find("^")) # in the right place + self.assertEqual(err[2].count("^"), 1) +@@ -376,6 +376,30 @@ + ' ValueError: 0\n', + ]) + ++ def test_format_exception_group_syntax_error_with_custom_values(self): ++ # See https://github.com/python/cpython/issues/128894 ++ for exc in [ ++ SyntaxError('error', 'abcd'), ++ SyntaxError('error', [None] * 4), ++ SyntaxError('error', (1, 2, 3, 4)), ++ SyntaxError('error', (1, 2, 3, 4)), ++ SyntaxError('error', (1, 'a', 'b', 2)), ++ # with end_lineno and end_offset: ++ SyntaxError('error', 'abcdef'), ++ SyntaxError('error', [None] * 6), ++ SyntaxError('error', (1, 2, 3, 4, 5, 6)), ++ SyntaxError('error', (1, 'a', 'b', 2, 'c', 'd')), ++ ]: ++ with self.subTest(exc=exc): ++ err = traceback.format_exception_only(exc, show_group=True) ++ # Should not raise an exception: ++ if exc.lineno is not None: ++ self.assertEqual(len(err), 2) ++ self.assertTrue(err[0].startswith(' File')) ++ else: ++ self.assertEqual(len(err), 1) ++ self.assertEqual(err[-1], 'SyntaxError: error\n') ++ + @requires_subprocess() + @force_not_colorized + def test_encoded_file(self): +@@ -419,16 +443,10 @@ + err_line = "raise RuntimeError('{0}')".format(message_ascii) + err_msg = "RuntimeError: {0}".format(message_ascii) + +- self.assertIn(("line %s" % lineno), stdout[1], +- "Invalid line number: {0!r} instead of {1}".format( +- stdout[1], lineno)) +- self.assertTrue(stdout[2].endswith(err_line), +- "Invalid traceback line: {0!r} instead of {1!r}".format( +- stdout[2], err_line)) ++ self.assertIn("line %s" % lineno, stdout[1]) ++ self.assertEndsWith(stdout[2], err_line) + actual_err_msg = stdout[3] +- self.assertTrue(actual_err_msg == err_msg, +- "Invalid error message: {0!r} instead of {1!r}".format( +- actual_err_msg, err_msg)) ++ self.assertEqual(actual_err_msg, err_msg) + + do_test("", "foo", "ascii", 3) + for charset in ("ascii", "iso-8859-1", "utf-8", "GBK"): +@@ -1712,6 +1730,7 @@ + + + @requires_debug_ranges() ++@force_not_colorized_test_class + class PurePythonTracebackErrorCaretTests( + PurePythonExceptionFormattingMixin, + TracebackErrorLocationCaretTestBase, +@@ -1725,6 +1744,7 @@ + + @cpython_only + @requires_debug_ranges() ++@force_not_colorized_test_class + class CPythonTracebackErrorCaretTests( + CAPIExceptionFormattingMixin, + TracebackErrorLocationCaretTestBase, +@@ -1736,6 +1756,7 @@ + + @cpython_only + @requires_debug_ranges() ++@force_not_colorized_test_class + class CPythonTracebackLegacyErrorCaretTests( + CAPIExceptionFormattingLegacyMixin, + TracebackErrorLocationCaretTestBase, +@@ -1806,9 +1827,9 @@ + banner = tb_lines[0] + self.assertEqual(len(tb_lines), 5) + location, source_line = tb_lines[-2], tb_lines[-1] +- self.assertTrue(banner.startswith('Traceback')) +- self.assertTrue(location.startswith(' File')) +- self.assertTrue(source_line.startswith(' raise')) ++ self.assertStartsWith(banner, 'Traceback') ++ self.assertStartsWith(location, ' File') ++ self.assertStartsWith(source_line, ' raise') + + def test_traceback_format(self): + self.check_traceback_format() +@@ -2149,10 +2170,12 @@ + boundaries = re.compile( + '(%s|%s)' % (re.escape(cause_message), re.escape(context_message))) + ++@force_not_colorized_test_class + class TestTracebackFormat(unittest.TestCase, TracebackFormatMixin): + pass + + @cpython_only ++@force_not_colorized_test_class + class TestFallbackTracebackFormat(unittest.TestCase, TracebackFormatMixin): + DEBUG_RANGES = False + def setUp(self) -> None: +@@ -2185,12 +2208,12 @@ + def check_zero_div(self, msg): + lines = msg.splitlines() + if has_no_debug_ranges(): +- self.assertTrue(lines[-3].startswith(' File')) ++ self.assertStartsWith(lines[-3], ' File') + self.assertIn('1/0 # In zero_div', lines[-2]) + else: +- self.assertTrue(lines[-4].startswith(' File')) ++ self.assertStartsWith(lines[-4], ' File') + self.assertIn('1/0 # In zero_div', lines[-3]) +- self.assertTrue(lines[-1].startswith('ZeroDivisionError'), lines[-1]) ++ self.assertStartsWith(lines[-1], 'ZeroDivisionError') + + def test_simple(self): + try: +@@ -2200,12 +2223,12 @@ + lines = self.get_report(e).splitlines() + if has_no_debug_ranges(): + self.assertEqual(len(lines), 4) +- self.assertTrue(lines[3].startswith('ZeroDivisionError')) ++ self.assertStartsWith(lines[3], 'ZeroDivisionError') + else: + self.assertEqual(len(lines), 5) +- self.assertTrue(lines[4].startswith('ZeroDivisionError')) +- self.assertTrue(lines[0].startswith('Traceback')) +- self.assertTrue(lines[1].startswith(' File')) ++ self.assertStartsWith(lines[4], 'ZeroDivisionError') ++ self.assertStartsWith(lines[0], 'Traceback') ++ self.assertStartsWith(lines[1], ' File') + self.assertIn('1/0 # Marker', lines[2]) + + def test_cause(self): +@@ -2246,9 +2269,9 @@ + e = _ + lines = self.get_report(e).splitlines() + self.assertEqual(len(lines), 4) +- self.assertTrue(lines[3].startswith('ZeroDivisionError')) +- self.assertTrue(lines[0].startswith('Traceback')) +- self.assertTrue(lines[1].startswith(' File')) ++ self.assertStartsWith(lines[3], 'ZeroDivisionError') ++ self.assertStartsWith(lines[0], 'Traceback') ++ self.assertStartsWith(lines[1], ' File') + self.assertIn('ZeroDivisionError from None', lines[2]) + + def test_cause_and_context(self): +@@ -2914,6 +2937,33 @@ + report = self.get_report(exc) + self.assertEqual(report, expected) + ++ def test_exception_group_wrapped_naked(self): ++ # See gh-128799 ++ ++ def exc(): ++ try: ++ raise Exception(42) ++ except* Exception as e: ++ raise ++ ++ expected = (f' + Exception Group Traceback (most recent call last):\n' ++ f' | File "{__file__}", line {self.callable_line}, in get_exception\n' ++ f' | exception_or_callable()\n' ++ f' | ~~~~~~~~~~~~~~~~~~~~~^^\n' ++ f' | File "{__file__}", line {exc.__code__.co_firstlineno + 3}, in exc\n' ++ f' | except* Exception as e:\n' ++ f' | raise\n' ++ f' | ExceptionGroup: (1 sub-exception)\n' ++ f' +-+---------------- 1 ----------------\n' ++ f' | Traceback (most recent call last):\n' ++ f' | File "{__file__}", line {exc.__code__.co_firstlineno + 2}, in exc\n' ++ f' | raise Exception(42)\n' ++ f' | Exception: 42\n' ++ f' +------------------------------------\n') ++ ++ report = self.get_report(exc) ++ self.assertEqual(report, expected) ++ + def test_KeyboardInterrupt_at_first_line_of_frame(self): + # see GH-93249 + def f(): +@@ -2940,6 +2990,7 @@ + self.assertEqual(report, expected) + + ++@force_not_colorized_test_class + class PyExcReportingTests(BaseExceptionReportingTests, unittest.TestCase): + # + # This checks reporting through the 'traceback' module, with both +@@ -2956,6 +3007,7 @@ + return s + + ++@force_not_colorized_test_class + class CExcReportingTests(BaseExceptionReportingTests, unittest.TestCase): + # + # This checks built-in reporting by the interpreter. +diff --git a/Lib/test/test_tracemalloc.py b/Lib/test/test_tracemalloc.py +index 5755f7697de..0220a83d24b 100644 +--- a/Lib/test/test_tracemalloc.py ++++ b/Lib/test/test_tracemalloc.py +@@ -1,14 +1,16 @@ + import contextlib + import os + import sys ++import textwrap + import tracemalloc + import unittest + from unittest.mock import patch + from test.support.script_helper import (assert_python_ok, assert_python_failure, + interpreter_requires_environment) + from test import support +-from test.support import os_helper + from test.support import force_not_colorized ++from test.support import os_helper ++from test.support import threading_helper + + try: + import _testcapi +@@ -18,6 +20,7 @@ + _testinternalcapi = None + + ++DEFAULT_DOMAIN = 0 + EMPTY_STRING_SIZE = sys.getsizeof(b'') + INVALID_NFRAME = (-1, 2**30) + +@@ -952,7 +955,6 @@ + return + self.fail(f"unexpected output: {stderr!a}") + +- + def test_env_var_invalid(self): + for nframe in INVALID_NFRAME: + with self.subTest(nframe=nframe): +@@ -981,6 +983,7 @@ + return + self.fail(f"unexpected output: {stderr!a}") + ++ @force_not_colorized + def test_sys_xoptions_invalid(self): + for nframe in INVALID_NFRAME: + with self.subTest(nframe=nframe): +@@ -1026,8 +1029,8 @@ + release_gil) + return frames + +- def untrack(self): +- _testcapi.tracemalloc_untrack(self.domain, self.ptr) ++ def untrack(self, release_gil=False): ++ _testcapi.tracemalloc_untrack(self.domain, self.ptr, release_gil) + + def get_traced_memory(self): + # Get the traced size in the domain +@@ -1069,7 +1072,7 @@ + self.assertEqual(self.get_traceback(), + tracemalloc.Traceback(frames)) + +- def test_untrack(self): ++ def check_untrack(self, release_gil): + tracemalloc.start() + + self.track() +@@ -1077,13 +1080,19 @@ + self.assertEqual(self.get_traced_memory(), self.size) + + # untrack must remove the trace +- self.untrack() ++ self.untrack(release_gil) + self.assertIsNone(self.get_traceback()) + self.assertEqual(self.get_traced_memory(), 0) + + # calling _PyTraceMalloc_Untrack() multiple times must not crash +- self.untrack() +- self.untrack() ++ self.untrack(release_gil) ++ self.untrack(release_gil) ++ ++ def test_untrack(self): ++ self.check_untrack(False) ++ ++ def test_untrack_without_gil(self): ++ self.check_untrack(True) + + def test_stop_track(self): + tracemalloc.start() +@@ -1101,6 +1110,37 @@ + with self.assertRaises(RuntimeError): + self.untrack() + ++ @unittest.skipIf(_testcapi is None, 'need _testcapi') ++ @threading_helper.requires_working_threading() ++ # gh-128679: Test crash on a debug build (especially on FreeBSD). ++ @unittest.skipIf(support.Py_DEBUG, 'need release build') ++ def test_tracemalloc_track_race(self): ++ # gh-128679: Test fix for tracemalloc.stop() race condition ++ _testcapi.tracemalloc_track_race() ++ ++ def test_late_untrack(self): ++ code = textwrap.dedent(f""" ++ from test import support ++ import tracemalloc ++ import _testcapi ++ ++ class Tracked: ++ def __init__(self, domain, size): ++ self.domain = domain ++ self.ptr = id(self) ++ self.size = size ++ _testcapi.tracemalloc_track(self.domain, self.ptr, self.size) ++ ++ def __del__(self, untrack=_testcapi.tracemalloc_untrack): ++ untrack(self.domain, self.ptr, 1) ++ ++ domain = {DEFAULT_DOMAIN} ++ tracemalloc.start() ++ obj = Tracked(domain, 1024 * 1024) ++ support.late_deletion(obj) ++ """) ++ assert_python_ok("-c", code) ++ + + if __name__ == "__main__": + unittest.main() +diff --git a/Lib/test/test_turtle.py b/Lib/test/test_turtle.py +index c75a002a89b..d02cac284a9 100644 +--- a/Lib/test/test_turtle.py ++++ b/Lib/test/test_turtle.py +@@ -1,9 +1,9 @@ + import os + import pickle + import re ++import tempfile + import unittest + import unittest.mock +-import tempfile + from test import support + from test.support import import_helper + from test.support import os_helper +@@ -54,6 +54,21 @@ + """ + + ++def patch_screen(): ++ """Patch turtle._Screen for testing without a display. ++ ++ We must patch the _Screen class itself instead of the _Screen ++ instance because instantiating it requires a display. ++ """ ++ return unittest.mock.patch( ++ "turtle._Screen.__new__", ++ **{ ++ "return_value.__class__": turtle._Screen, ++ "return_value.mode.return_value": "standard", ++ }, ++ ) ++ ++ + class TurtleConfigTest(unittest.TestCase): + + def get_cfg_file(self, cfg_str): +@@ -513,7 +528,7 @@ + + turtle.TurtleScreen.save(screen, file_path, overwrite=True) + with open(file_path) as f: +- assert f.read() == "postscript" ++ self.assertEqual(f.read(), "postscript") + + def test_save(self) -> None: + screen = unittest.mock.Mock() +@@ -524,7 +539,101 @@ + + turtle.TurtleScreen.save(screen, file_path) + with open(file_path) as f: +- assert f.read() == "postscript" ++ self.assertEqual(f.read(), "postscript") ++ ++ def test_no_animation_sets_tracer_0(self): ++ s = turtle.TurtleScreen(cv=unittest.mock.MagicMock()) ++ ++ with s.no_animation(): ++ self.assertEqual(s.tracer(), 0) ++ ++ def test_no_animation_resets_tracer_to_old_value(self): ++ s = turtle.TurtleScreen(cv=unittest.mock.MagicMock()) ++ ++ for tracer in [0, 1, 5]: ++ s.tracer(tracer) ++ with s.no_animation(): ++ pass ++ self.assertEqual(s.tracer(), tracer) ++ ++ def test_no_animation_calls_update_at_exit(self): ++ s = turtle.TurtleScreen(cv=unittest.mock.MagicMock()) ++ s.update = unittest.mock.MagicMock() ++ ++ with s.no_animation(): ++ s.update.assert_not_called() ++ s.update.assert_called_once() ++ ++ ++class TestTurtle(unittest.TestCase): ++ def setUp(self): ++ with patch_screen(): ++ self.turtle = turtle.Turtle() ++ ++ # Reset the Screen singleton to avoid reference leaks ++ self.addCleanup(setattr, turtle.Turtle, '_screen', None) ++ ++ def test_begin_end_fill(self): ++ self.assertFalse(self.turtle.filling()) ++ self.turtle.begin_fill() ++ self.assertTrue(self.turtle.filling()) ++ self.turtle.end_fill() ++ self.assertFalse(self.turtle.filling()) ++ ++ def test_fill(self): ++ # The context manager behaves like begin_fill and end_fill. ++ self.assertFalse(self.turtle.filling()) ++ with self.turtle.fill(): ++ self.assertTrue(self.turtle.filling()) ++ self.assertFalse(self.turtle.filling()) ++ ++ def test_fill_resets_after_exception(self): ++ # The context manager cleans up correctly after exceptions. ++ try: ++ with self.turtle.fill(): ++ self.assertTrue(self.turtle.filling()) ++ raise ValueError ++ except ValueError: ++ self.assertFalse(self.turtle.filling()) ++ ++ def test_fill_context_when_filling(self): ++ # The context manager works even when the turtle is already filling. ++ self.turtle.begin_fill() ++ self.assertTrue(self.turtle.filling()) ++ with self.turtle.fill(): ++ self.assertTrue(self.turtle.filling()) ++ self.assertFalse(self.turtle.filling()) ++ ++ def test_begin_end_poly(self): ++ self.assertFalse(self.turtle._creatingPoly) ++ self.turtle.begin_poly() ++ self.assertTrue(self.turtle._creatingPoly) ++ self.turtle.end_poly() ++ self.assertFalse(self.turtle._creatingPoly) ++ ++ def test_poly(self): ++ # The context manager behaves like begin_poly and end_poly. ++ self.assertFalse(self.turtle._creatingPoly) ++ with self.turtle.poly(): ++ self.assertTrue(self.turtle._creatingPoly) ++ self.assertFalse(self.turtle._creatingPoly) ++ ++ def test_poly_resets_after_exception(self): ++ # The context manager cleans up correctly after exceptions. ++ try: ++ with self.turtle.poly(): ++ self.assertTrue(self.turtle._creatingPoly) ++ raise ValueError ++ except ValueError: ++ self.assertFalse(self.turtle._creatingPoly) ++ ++ def test_poly_context_when_creating_poly(self): ++ # The context manager works when the turtle is already creating poly. ++ self.turtle.begin_poly() ++ self.assertTrue(self.turtle._creatingPoly) ++ with self.turtle.poly(): ++ self.assertTrue(self.turtle._creatingPoly) ++ self.assertFalse(self.turtle._creatingPoly) + + + class TestModuleLevel(unittest.TestCase): +diff --git a/Lib/test/test_type_annotations.py b/Lib/test/test_type_annotations.py +index 7d88f4cdfa3..0afcd76af15 100644 +--- a/Lib/test/test_type_annotations.py ++++ b/Lib/test/test_type_annotations.py +@@ -1,4 +1,5 @@ + import annotationlib ++import inspect + import textwrap + import types + import unittest +@@ -380,6 +381,11 @@ + annotate(None) + self.assertEqual(annotate(annotationlib.Format.VALUE), {"x": int}) + ++ sig = inspect.signature(annotate) ++ self.assertEqual(sig, inspect.Signature([ ++ inspect.Parameter("format", inspect.Parameter.POSITIONAL_ONLY) ++ ])) ++ + def test_comprehension_in_annotation(self): + # This crashed in an earlier version of the code + ns = run_code("x: [y for y in range(10)]") +@@ -400,6 +406,7 @@ + + def test_name_clash_with_format(self): + # this test would fail if __annotate__'s parameter was called "format" ++ # during symbol table construction + code = """ + class format: pass + +@@ -408,3 +415,45 @@ + ns = run_code(code) + f = ns["f"] + self.assertEqual(f.__annotations__, {"x": ns["format"]}) ++ ++ code = """ ++ class Outer: ++ class format: pass ++ ++ def meth(self, x: format): ... ++ """ ++ ns = run_code(code) ++ self.assertEqual(ns["Outer"].meth.__annotations__, {"x": ns["Outer"].format}) ++ ++ code = """ ++ def f(format): ++ def inner(x: format): pass ++ return inner ++ res = f("closure var") ++ """ ++ ns = run_code(code) ++ self.assertEqual(ns["res"].__annotations__, {"x": "closure var"}) ++ ++ code = """ ++ def f(x: format): ++ pass ++ """ ++ ns = run_code(code) ++ # picks up the format() builtin ++ self.assertEqual(ns["f"].__annotations__, {"x": format}) ++ ++ code = """ ++ def outer(): ++ def f(x: format): ++ pass ++ if False: ++ class format: pass ++ return f ++ f = outer() ++ """ ++ ns = run_code(code) ++ with self.assertRaisesRegex( ++ NameError, ++ "cannot access free variable 'format' where it is not associated with a value in enclosing scope", ++ ): ++ ns["f"].__annotations__ +diff --git a/Lib/test/test_type_cache.py b/Lib/test/test_type_cache.py +index e109a657413..ee64f89358e 100644 +--- a/Lib/test/test_type_cache.py ++++ b/Lib/test/test_type_cache.py +@@ -131,7 +131,7 @@ + return set(instr.opname for instr in dis.Bytecode(func, adaptive=True)) + + def _check_specialization(self, func, arg, opname, *, should_specialize): +- for _ in range(100): ++ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): + func(arg) + + if should_specialize: +diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py +index 433b19593bd..0f393def827 100644 +--- a/Lib/test/test_type_params.py ++++ b/Lib/test/test_type_params.py +@@ -1,11 +1,10 @@ + import annotationlib +-import asyncio + import textwrap + import types + import unittest + import pickle + import weakref +-from test.support import requires_working_socket, check_syntax_error, run_code ++from test.support import check_syntax_error, run_code, run_no_yield_async_fn + + from typing import Generic, NoDefault, Sequence, TypeAliasType, TypeVar, TypeVarTuple, ParamSpec, get_args + +@@ -1051,7 +1050,6 @@ + self.assertIsInstance(c, TypeVar) + self.assertEqual(c.__name__, "C") + +- @requires_working_socket() + def test_typevar_coroutine(self): + def get_coroutine[A](): + async def coroutine[B](): +@@ -1060,8 +1058,7 @@ + + co = get_coroutine() + +- self.addCleanup(asyncio.set_event_loop_policy, None) +- a, b = asyncio.run(co()) ++ a, b = run_no_yield_async_fn(co) + + self.assertIsInstance(a, TypeVar) + self.assertEqual(a.__name__, "A") +diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py +index aa42beca5f9..f002d28df60 100644 +--- a/Lib/test/test_typing.py ++++ b/Lib/test/test_typing.py +@@ -45,6 +45,7 @@ + import textwrap + import typing + import weakref ++import warnings + import types + + from test.support import captured_stderr, cpython_only, infinite_recursion, requires_docstrings, import_helper, run_code +@@ -58,20 +59,6 @@ + + class BaseTestCase(TestCase): + +- def assertIsSubclass(self, cls, class_or_tuple, msg=None): +- if not issubclass(cls, class_or_tuple): +- message = '%r is not a subclass of %r' % (cls, class_or_tuple) +- if msg is not None: +- message += ' : %s' % msg +- raise self.failureException(message) +- +- def assertNotIsSubclass(self, cls, class_or_tuple, msg=None): +- if issubclass(cls, class_or_tuple): +- message = '%r is a subclass of %r' % (cls, class_or_tuple) +- if msg is not None: +- message += ' : %s' % msg +- raise self.failureException(message) +- + def clear_caches(self): + for f in typing._cleanups: + f() +@@ -122,21 +109,24 @@ + + def test_errors(self): + with self.assertRaises(TypeError): +- issubclass(42, Any) ++ isinstance(42, Any) + with self.assertRaises(TypeError): + Any[int] # Any is not a generic type. + + def test_can_subclass(self): + class Mock(Any): pass +- self.assertTrue(issubclass(Mock, Any)) ++ self.assertIsSubclass(Mock, Any) + self.assertIsInstance(Mock(), Mock) + + class Something: pass +- self.assertFalse(issubclass(Something, Any)) ++ self.assertNotIsSubclass(Something, Any) + self.assertNotIsInstance(Something(), Mock) + + class MockSomething(Something, Mock): pass +- self.assertTrue(issubclass(MockSomething, Any)) ++ self.assertIsSubclass(MockSomething, Any) ++ self.assertIsSubclass(MockSomething, MockSomething) ++ self.assertIsSubclass(MockSomething, Something) ++ self.assertIsSubclass(MockSomething, Mock) + ms = MockSomething() + self.assertIsInstance(ms, MockSomething) + self.assertIsInstance(ms, Something) +@@ -1248,10 +1238,6 @@ + + class TypeVarTupleTests(BaseTestCase): + +- def assertEndsWith(self, string, tail): +- if not string.endswith(tail): +- self.fail(f"String {string!r} does not end with {tail!r}") +- + def test_name(self): + Ts = TypeVarTuple('Ts') + self.assertEqual(Ts.__name__, 'Ts') +@@ -2010,13 +1996,81 @@ + u = Union[int, float] + self.assertNotEqual(u, Union) + +- def test_subclass_error(self): ++ def test_union_isinstance(self): ++ self.assertIsInstance(42, Union[int, str]) ++ self.assertIsInstance('abc', Union[int, str]) ++ self.assertNotIsInstance(3.14, Union[int, str]) ++ self.assertIsInstance(42, Union[int, list[int]]) ++ self.assertIsInstance(42, Union[int, Any]) ++ ++ def test_union_isinstance_type_error(self): ++ with self.assertRaises(TypeError): ++ isinstance(42, Union[str, list[int]]) ++ with self.assertRaises(TypeError): ++ isinstance(42, Union[list[int], int]) ++ with self.assertRaises(TypeError): ++ isinstance(42, Union[list[int], str]) ++ with self.assertRaises(TypeError): ++ isinstance(42, Union[str, Any]) ++ with self.assertRaises(TypeError): ++ isinstance(42, Union[Any, int]) ++ with self.assertRaises(TypeError): ++ isinstance(42, Union[Any, str]) ++ ++ def test_optional_isinstance(self): ++ self.assertIsInstance(42, Optional[int]) ++ self.assertIsInstance(None, Optional[int]) ++ self.assertNotIsInstance('abc', Optional[int]) ++ ++ def test_optional_isinstance_type_error(self): ++ with self.assertRaises(TypeError): ++ isinstance(42, Optional[list[int]]) ++ with self.assertRaises(TypeError): ++ isinstance(None, Optional[list[int]]) ++ with self.assertRaises(TypeError): ++ isinstance(42, Optional[Any]) ++ with self.assertRaises(TypeError): ++ isinstance(None, Optional[Any]) ++ ++ def test_union_issubclass(self): ++ self.assertIsSubclass(int, Union[int, str]) ++ self.assertIsSubclass(str, Union[int, str]) ++ self.assertNotIsSubclass(float, Union[int, str]) ++ self.assertIsSubclass(int, Union[int, list[int]]) ++ self.assertIsSubclass(int, Union[int, Any]) ++ self.assertNotIsSubclass(int, Union[str, Any]) ++ self.assertIsSubclass(int, Union[Any, int]) ++ self.assertNotIsSubclass(int, Union[Any, str]) ++ ++ def test_union_issubclass_type_error(self): + with self.assertRaises(TypeError): + issubclass(int, Union) + with self.assertRaises(TypeError): + issubclass(Union, int) + with self.assertRaises(TypeError): + issubclass(Union[int, str], int) ++ with self.assertRaises(TypeError): ++ issubclass(int, Union[str, list[int]]) ++ with self.assertRaises(TypeError): ++ issubclass(int, Union[list[int], int]) ++ with self.assertRaises(TypeError): ++ issubclass(int, Union[list[int], str]) ++ ++ def test_optional_issubclass(self): ++ self.assertIsSubclass(int, Optional[int]) ++ self.assertIsSubclass(type(None), Optional[int]) ++ self.assertNotIsSubclass(str, Optional[int]) ++ self.assertIsSubclass(Any, Optional[Any]) ++ self.assertIsSubclass(type(None), Optional[Any]) ++ self.assertNotIsSubclass(int, Optional[Any]) ++ ++ def test_optional_issubclass_type_error(self): ++ with self.assertRaises(TypeError): ++ issubclass(list[int], Optional[list[int]]) ++ with self.assertRaises(TypeError): ++ issubclass(type(None), Optional[list[int]]) ++ with self.assertRaises(TypeError): ++ issubclass(int, Optional[list[int]]) + + def test_union_any(self): + u = Union[Any] +@@ -3996,8 +4050,8 @@ + + class P(Protocol[T, S]): pass + +- self.assertTrue(repr(P[T, S]).endswith('P[~T, ~S]')) +- self.assertTrue(repr(P[int, str]).endswith('P[int, str]')) ++ self.assertEndsWith(repr(P[T, S]), 'P[~T, ~S]') ++ self.assertEndsWith(repr(P[int, str]), 'P[int, str]') + + def test_generic_protocols_eq(self): + T = TypeVar('T') +@@ -4587,8 +4641,7 @@ + self.assertNotEqual(Z, Y[int]) + self.assertNotEqual(Z, Y[T]) + +- self.assertTrue(str(Z).endswith( +- '.C[typing.Tuple[str, int]]')) ++ self.assertEndsWith(str(Z), '.C[typing.Tuple[str, int]]') + + def test_new_repr(self): + T = TypeVar('T') +@@ -4816,12 +4869,12 @@ + self.assertNotEqual(typing.FrozenSet[A[str]], + typing.FrozenSet[mod_generics_cache.B.A[str]]) + +- self.assertTrue(repr(Tuple[A[str]]).endswith('.A[str]]')) +- self.assertTrue(repr(Tuple[B.A[str]]).endswith('.B.A[str]]')) +- self.assertTrue(repr(Tuple[mod_generics_cache.A[str]]) +- .endswith('mod_generics_cache.A[str]]')) +- self.assertTrue(repr(Tuple[mod_generics_cache.B.A[str]]) +- .endswith('mod_generics_cache.B.A[str]]')) ++ self.assertEndsWith(repr(Tuple[A[str]]), '.A[str]]') ++ self.assertEndsWith(repr(Tuple[B.A[str]]), '.B.A[str]]') ++ self.assertEndsWith(repr(Tuple[mod_generics_cache.A[str]]), ++ 'mod_generics_cache.A[str]]') ++ self.assertEndsWith(repr(Tuple[mod_generics_cache.B.A[str]]), ++ 'mod_generics_cache.B.A[str]]') + + def test_extended_generic_rules_eq(self): + T = TypeVar('T') +@@ -5111,6 +5164,18 @@ + x = pickle.loads(z) + self.assertEqual(s, x) + ++ # Test ParamSpec args and kwargs ++ global PP ++ PP = ParamSpec('PP') ++ for thing in [PP.args, PP.kwargs]: ++ for proto in range(pickle.HIGHEST_PROTOCOL + 1): ++ with self.subTest(thing=thing, proto=proto): ++ self.assertEqual( ++ pickle.loads(pickle.dumps(thing, proto)), ++ thing, ++ ) ++ del PP ++ + def test_copy_and_deepcopy(self): + T = TypeVar('T') + class Node(Generic[T]): ... +@@ -5751,7 +5816,7 @@ + @Wrapper + def wrapped(): ... + self.assertIsInstance(wrapped, Wrapper) +- self.assertIs(False, hasattr(wrapped, "__final__")) ++ self.assertNotHasAttr(wrapped, "__final__") + + class Meta(type): + @property +@@ -5763,7 +5828,7 @@ + # Builtin classes throw TypeError if you try to set an + # attribute. + final(int) +- self.assertIs(False, hasattr(int, "__final__")) ++ self.assertNotHasAttr(int, "__final__") + + # Make sure it works with common builtin decorators + class Methods: +@@ -5844,19 +5909,19 @@ + self.assertEqual(Derived.class_method_good_order(), 42) + self.assertIs(True, Derived.class_method_good_order.__override__) + self.assertEqual(Derived.class_method_bad_order(), 42) +- self.assertIs(False, hasattr(Derived.class_method_bad_order, "__override__")) ++ self.assertNotHasAttr(Derived.class_method_bad_order, "__override__") + + self.assertEqual(Derived.static_method_good_order(), 42) + self.assertIs(True, Derived.static_method_good_order.__override__) + self.assertEqual(Derived.static_method_bad_order(), 42) +- self.assertIs(False, hasattr(Derived.static_method_bad_order, "__override__")) ++ self.assertNotHasAttr(Derived.static_method_bad_order, "__override__") + + # Base object is not changed: +- self.assertIs(False, hasattr(Base.normal_method, "__override__")) +- self.assertIs(False, hasattr(Base.class_method_good_order, "__override__")) +- self.assertIs(False, hasattr(Base.class_method_bad_order, "__override__")) +- self.assertIs(False, hasattr(Base.static_method_good_order, "__override__")) +- self.assertIs(False, hasattr(Base.static_method_bad_order, "__override__")) ++ self.assertNotHasAttr(Base.normal_method, "__override__") ++ self.assertNotHasAttr(Base.class_method_good_order, "__override__") ++ self.assertNotHasAttr(Base.class_method_bad_order, "__override__") ++ self.assertNotHasAttr(Base.static_method_good_order, "__override__") ++ self.assertNotHasAttr(Base.static_method_bad_order, "__override__") + + def test_property(self): + class Base: +@@ -5881,8 +5946,8 @@ + self.assertEqual(instance.correct, 2) + self.assertTrue(Child.correct.fget.__override__) + self.assertEqual(instance.wrong, 2) +- self.assertFalse(hasattr(Child.wrong, "__override__")) +- self.assertFalse(hasattr(Child.wrong.fset, "__override__")) ++ self.assertNotHasAttr(Child.wrong, "__override__") ++ self.assertNotHasAttr(Child.wrong.fset, "__override__") + + def test_silent_failure(self): + class CustomProp: +@@ -5899,7 +5964,7 @@ + return 1 + + self.assertEqual(WithOverride.some, 1) +- self.assertFalse(hasattr(WithOverride.some, "__override__")) ++ self.assertNotHasAttr(WithOverride.some, "__override__") + + def test_multiple_decorators(self): + def with_wraps(f): # similar to `lru_cache` definition +@@ -7069,6 +7134,25 @@ + self.assertEqual(get_type_hints(C, format=annotationlib.Format.STRING), + {'x': 'undefined'}) + ++ def test_get_type_hints_format_function(self): ++ def func(x: undefined) -> undefined: ... ++ ++ # VALUE ++ with self.assertRaises(NameError): ++ get_type_hints(func) ++ with self.assertRaises(NameError): ++ get_type_hints(func, format=annotationlib.Format.VALUE) ++ ++ # FORWARDREF ++ self.assertEqual( ++ get_type_hints(func, format=annotationlib.Format.FORWARDREF), ++ {'x': ForwardRef('undefined'), 'return': ForwardRef('undefined')}, ++ ) ++ ++ # STRING ++ self.assertEqual(get_type_hints(func, format=annotationlib.Format.STRING), ++ {'x': 'undefined', 'return': 'undefined'}) ++ + + class GetUtilitiesTestCase(TestCase): + def test_get_origin(self): +@@ -7171,6 +7255,51 @@ + self.assertEqual(get_args(Unpack[tuple[Unpack[Ts]]]), (tuple[Unpack[Ts]],)) + + ++class EvaluateForwardRefTests(BaseTestCase): ++ def test_evaluate_forward_ref(self): ++ int_ref = ForwardRef('int') ++ missing = ForwardRef('missing') ++ self.assertIs( ++ typing.evaluate_forward_ref(int_ref, type_params=()), ++ int, ++ ) ++ self.assertIs( ++ typing.evaluate_forward_ref( ++ int_ref, type_params=(), format=annotationlib.Format.FORWARDREF, ++ ), ++ int, ++ ) ++ self.assertIs( ++ typing.evaluate_forward_ref( ++ missing, type_params=(), format=annotationlib.Format.FORWARDREF, ++ ), ++ missing, ++ ) ++ self.assertEqual( ++ typing.evaluate_forward_ref( ++ int_ref, type_params=(), format=annotationlib.Format.STRING, ++ ), ++ 'int', ++ ) ++ ++ def test_evaluate_forward_ref_no_type_params(self): ++ ref = ForwardRef('int') ++ with self.assertWarnsRegex( ++ DeprecationWarning, ++ ( ++ "Failing to pass a value to the 'type_params' parameter " ++ "of 'typing.evaluate_forward_ref' is deprecated, " ++ "as it leads to incorrect behaviour" ++ ), ++ ): ++ typing.evaluate_forward_ref(ref) ++ ++ # No warnings when `type_params` is passed: ++ with warnings.catch_warnings(record=True) as w: ++ typing.evaluate_forward_ref(ref, type_params=()) ++ self.assertEqual(w, []) ++ ++ + class CollectionsAbcTests(BaseTestCase): + + def test_hashable(self): +@@ -8841,13 +8970,13 @@ + self.assertEqual(Child1.__mutable_keys__, frozenset({'b'})) + + class Base2(TypedDict): +- a: ReadOnly[int] ++ a: int + + class Child2(Base2): +- b: str ++ b: ReadOnly[str] + +- self.assertEqual(Child1.__readonly_keys__, frozenset({'a'})) +- self.assertEqual(Child1.__mutable_keys__, frozenset({'b'})) ++ self.assertEqual(Child2.__readonly_keys__, frozenset({'b'})) ++ self.assertEqual(Child2.__mutable_keys__, frozenset({'a'})) + + def test_cannot_make_mutable_key_readonly(self): + class Base(TypedDict): +@@ -10058,6 +10187,18 @@ + self.assertEqual(C4.__args__, (Concatenate[int, T, P], T)) + self.assertEqual(C4.__parameters__, (T, P)) + ++ def test_invalid_uses(self): ++ with self.assertRaisesRegex(TypeError, 'Concatenate of no types'): ++ Concatenate[()] ++ with self.assertRaisesRegex( ++ TypeError, ++ ( ++ 'The last parameter to Concatenate should be a ' ++ 'ParamSpec variable or ellipsis' ++ ), ++ ): ++ Concatenate[int] ++ + def test_var_substitution(self): + T = TypeVar('T') + P = ParamSpec('P') +@@ -10332,7 +10473,7 @@ + # to the variable name to which it is assigned". Thus, providing + # __qualname__ is unnecessary. + self.assertEqual(SpecialAttrsT.__name__, 'SpecialAttrsT') +- self.assertFalse(hasattr(SpecialAttrsT, '__qualname__')) ++ self.assertNotHasAttr(SpecialAttrsT, '__qualname__') + self.assertEqual(SpecialAttrsT.__module__, __name__) + # Module-level type variables are picklable. + for proto in range(pickle.HIGHEST_PROTOCOL + 1): +@@ -10341,7 +10482,7 @@ + self.assertIs(SpecialAttrsT, loaded) + + self.assertEqual(SpecialAttrsP.__name__, 'SpecialAttrsP') +- self.assertFalse(hasattr(SpecialAttrsP, '__qualname__')) ++ self.assertNotHasAttr(SpecialAttrsP, '__qualname__') + self.assertEqual(SpecialAttrsP.__module__, __name__) + # Module-level ParamSpecs are picklable. + for proto in range(pickle.HIGHEST_PROTOCOL + 1): +diff --git a/Lib/test/test_unicodedata.py b/Lib/test/test_unicodedata.py +index c7d09a6b460..0285f0d51f2 100644 +--- a/Lib/test/test_unicodedata.py ++++ b/Lib/test/test_unicodedata.py +@@ -11,8 +11,14 @@ + import sys + import unicodedata + import unittest +-from test.support import (open_urlresource, requires_resource, script_helper, +- cpython_only, check_disallow_instantiation) ++from test.support import ( ++ open_urlresource, ++ requires_resource, ++ script_helper, ++ cpython_only, ++ check_disallow_instantiation, ++ force_not_colorized, ++) + + + class UnicodeMethodsTest(unittest.TestCase): +@@ -277,6 +283,7 @@ + # Ensure that the type disallows instantiation (bpo-43916) + check_disallow_instantiation(self, unicodedata.UCD) + ++ @force_not_colorized + def test_failed_import_during_compiling(self): + # Issue 4367 + # Decoding \N escapes requires the unicodedata module. If it can't be +diff --git a/Lib/test/test_unittest/test_async_case.py b/Lib/test/test_unittest/test_async_case.py +index 8ea244bff05..fc996b42149 100644 +--- a/Lib/test/test_unittest/test_async_case.py ++++ b/Lib/test/test_unittest/test_async_case.py +@@ -12,7 +12,7 @@ + + + def tearDownModule(): +- asyncio.set_event_loop_policy(None) ++ asyncio._set_event_loop_policy(None) + + + class TestCM: +@@ -476,11 +476,11 @@ + def test_setup_get_event_loop(self): + # See https://github.com/python/cpython/issues/95736 + # Make sure the default event loop is not used +- asyncio.set_event_loop(None) ++ asyncio._set_event_loop(None) + + class TestCase1(unittest.IsolatedAsyncioTestCase): + def setUp(self): +- asyncio.get_event_loop_policy().get_event_loop() ++ asyncio._get_event_loop_policy().get_event_loop() + + async def test_demo1(self): + pass +@@ -490,7 +490,7 @@ + self.assertTrue(result.wasSuccessful()) + + def test_loop_factory(self): +- asyncio.set_event_loop_policy(None) ++ asyncio._set_event_loop_policy(None) + + class TestCase1(unittest.IsolatedAsyncioTestCase): + loop_factory = asyncio.EventLoop +diff --git a/Lib/test/test_unittest/test_case.py b/Lib/test/test_unittest/test_case.py +index b4b2194a09c..a04af55f3fc 100644 +--- a/Lib/test/test_unittest/test_case.py ++++ b/Lib/test/test_unittest/test_case.py +@@ -10,6 +10,7 @@ + import inspect + import types + ++from collections import UserString + from copy import deepcopy + from test import support + +@@ -54,6 +55,10 @@ + self.events.append('tearDown') + + ++class List(list): ++ pass ++ ++ + class Test_TestCase(unittest.TestCase, TestEquality, TestHashing): + + ### Set up attributes used by inherited tests +@@ -85,7 +90,7 @@ + def runTest(self): raise MyException() + def test(self): pass + +- self.assertEqual(Test().id()[-13:], '.Test.runTest') ++ self.assertEndsWith(Test().id(), '.Test.runTest') + + # test that TestCase can be instantiated with no args + # primarily for use at the interactive interpreter +@@ -106,7 +111,7 @@ + def runTest(self): raise MyException() + def test(self): pass + +- self.assertEqual(Test('test').id()[-10:], '.Test.test') ++ self.assertEndsWith(Test('test').id(), '.Test.test') + + # "class TestCase([methodName])" + # ... +@@ -347,7 +352,10 @@ + return 1 + + with self.assertWarns(DeprecationWarning) as w: ++ warnings.filterwarnings('ignore', ++ 'coroutine .* was never awaited', RuntimeWarning) + Foo('test1').run() ++ support.gc_collect() + self.assertIn('It is deprecated to return a value that is not None', str(w.warning)) + self.assertIn('test1', str(w.warning)) + self.assertEqual(w.filename, __file__) +@@ -697,16 +705,136 @@ + self.assertRaises(self.failureException, self.assertIsNot, thing, thing) + + def testAssertIsInstance(self): +- thing = [] ++ thing = List() + self.assertIsInstance(thing, list) +- self.assertRaises(self.failureException, self.assertIsInstance, +- thing, dict) ++ self.assertIsInstance(thing, (int, list)) ++ with self.assertRaises(self.failureException) as cm: ++ self.assertIsInstance(thing, int) ++ self.assertEqual(str(cm.exception), ++ "[] is not an instance of ") ++ with self.assertRaises(self.failureException) as cm: ++ self.assertIsInstance(thing, (int, float)) ++ self.assertEqual(str(cm.exception), ++ "[] is not an instance of any of (, )") ++ ++ with self.assertRaises(self.failureException) as cm: ++ self.assertIsInstance(thing, int, 'ababahalamaha') ++ self.assertIn('ababahalamaha', str(cm.exception)) ++ with self.assertRaises(self.failureException) as cm: ++ self.assertIsInstance(thing, int, msg='ababahalamaha') ++ self.assertIn('ababahalamaha', str(cm.exception)) + + def testAssertNotIsInstance(self): +- thing = [] +- self.assertNotIsInstance(thing, dict) +- self.assertRaises(self.failureException, self.assertNotIsInstance, +- thing, list) ++ thing = List() ++ self.assertNotIsInstance(thing, int) ++ self.assertNotIsInstance(thing, (int, float)) ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotIsInstance(thing, list) ++ self.assertEqual(str(cm.exception), ++ "[] is an instance of ") ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotIsInstance(thing, (int, list)) ++ self.assertEqual(str(cm.exception), ++ "[] is an instance of ") ++ ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotIsInstance(thing, list, 'ababahalamaha') ++ self.assertIn('ababahalamaha', str(cm.exception)) ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotIsInstance(thing, list, msg='ababahalamaha') ++ self.assertIn('ababahalamaha', str(cm.exception)) ++ ++ def testAssertIsSubclass(self): ++ self.assertIsSubclass(List, list) ++ self.assertIsSubclass(List, (int, list)) ++ with self.assertRaises(self.failureException) as cm: ++ self.assertIsSubclass(List, int) ++ self.assertEqual(str(cm.exception), ++ f"{List!r} is not a subclass of ") ++ with self.assertRaises(self.failureException) as cm: ++ self.assertIsSubclass(List, (int, float)) ++ self.assertEqual(str(cm.exception), ++ f"{List!r} is not a subclass of any of (, )") ++ with self.assertRaises(self.failureException) as cm: ++ self.assertIsSubclass(1, int) ++ self.assertEqual(str(cm.exception), "1 is not a class") ++ ++ with self.assertRaises(self.failureException) as cm: ++ self.assertIsSubclass(List, int, 'ababahalamaha') ++ self.assertIn('ababahalamaha', str(cm.exception)) ++ with self.assertRaises(self.failureException) as cm: ++ self.assertIsSubclass(List, int, msg='ababahalamaha') ++ self.assertIn('ababahalamaha', str(cm.exception)) ++ ++ def testAssertNotIsSubclass(self): ++ self.assertNotIsSubclass(List, int) ++ self.assertNotIsSubclass(List, (int, float)) ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotIsSubclass(List, list) ++ self.assertEqual(str(cm.exception), ++ f"{List!r} is a subclass of ") ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotIsSubclass(List, (int, list)) ++ self.assertEqual(str(cm.exception), ++ f"{List!r} is a subclass of ") ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotIsSubclass(1, int) ++ self.assertEqual(str(cm.exception), "1 is not a class") ++ ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotIsSubclass(List, list, 'ababahalamaha') ++ self.assertIn('ababahalamaha', str(cm.exception)) ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotIsSubclass(List, list, msg='ababahalamaha') ++ self.assertIn('ababahalamaha', str(cm.exception)) ++ ++ def testAssertHasAttr(self): ++ a = List() ++ a.x = 1 ++ self.assertHasAttr(a, 'x') ++ with self.assertRaises(self.failureException) as cm: ++ self.assertHasAttr(a, 'y') ++ self.assertEqual(str(cm.exception), ++ "'List' object has no attribute 'y'") ++ with self.assertRaises(self.failureException) as cm: ++ self.assertHasAttr(List, 'spam') ++ self.assertEqual(str(cm.exception), ++ "type object 'List' has no attribute 'spam'") ++ with self.assertRaises(self.failureException) as cm: ++ self.assertHasAttr(sys, 'nonexistent') ++ self.assertEqual(str(cm.exception), ++ "module 'sys' has no attribute 'nonexistent'") ++ ++ with self.assertRaises(self.failureException) as cm: ++ self.assertHasAttr(a, 'y', 'ababahalamaha') ++ self.assertIn('ababahalamaha', str(cm.exception)) ++ with self.assertRaises(self.failureException) as cm: ++ self.assertHasAttr(a, 'y', msg='ababahalamaha') ++ self.assertIn('ababahalamaha', str(cm.exception)) ++ ++ def testAssertNotHasAttr(self): ++ a = List() ++ a.x = 1 ++ self.assertNotHasAttr(a, 'y') ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotHasAttr(a, 'x') ++ self.assertEqual(str(cm.exception), ++ "'List' object has unexpected attribute 'x'") ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotHasAttr(List, 'append') ++ self.assertEqual(str(cm.exception), ++ "type object 'List' has unexpected attribute 'append'") ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotHasAttr(sys, 'modules') ++ self.assertEqual(str(cm.exception), ++ "module 'sys' has unexpected attribute 'modules'") ++ ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotHasAttr(a, 'x', 'ababahalamaha') ++ self.assertIn('ababahalamaha', str(cm.exception)) ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotHasAttr(a, 'x', msg='ababahalamaha') ++ self.assertIn('ababahalamaha', str(cm.exception)) + + def testAssertIn(self): + animals = {'monkey': 'banana', 'cow': 'grass', 'seal': 'fish'} +@@ -1861,6 +1989,186 @@ + pass + self.assertIsNone(value) + ++ def testAssertStartswith(self): ++ self.assertStartsWith('ababahalamaha', 'ababa') ++ self.assertStartsWith('ababahalamaha', ('x', 'ababa', 'y')) ++ self.assertStartsWith(UserString('ababahalamaha'), 'ababa') ++ self.assertStartsWith(UserString('ababahalamaha'), ('x', 'ababa', 'y')) ++ self.assertStartsWith(bytearray(b'ababahalamaha'), b'ababa') ++ self.assertStartsWith(bytearray(b'ababahalamaha'), (b'x', b'ababa', b'y')) ++ self.assertStartsWith(b'ababahalamaha', bytearray(b'ababa')) ++ self.assertStartsWith(b'ababahalamaha', ++ (bytearray(b'x'), bytearray(b'ababa'), bytearray(b'y'))) ++ ++ with self.assertRaises(self.failureException) as cm: ++ self.assertStartsWith('ababahalamaha', 'amaha') ++ self.assertEqual(str(cm.exception), ++ "'ababahalamaha' doesn't start with 'amaha'") ++ with self.assertRaises(self.failureException) as cm: ++ self.assertStartsWith('ababahalamaha', ('x', 'y')) ++ self.assertEqual(str(cm.exception), ++ "'ababahalamaha' doesn't start with any of ('x', 'y')") ++ ++ with self.assertRaises(self.failureException) as cm: ++ self.assertStartsWith(b'ababahalamaha', 'ababa') ++ self.assertEqual(str(cm.exception), 'Expected str, not bytes') ++ with self.assertRaises(self.failureException) as cm: ++ self.assertStartsWith(b'ababahalamaha', ('amaha', 'ababa')) ++ self.assertEqual(str(cm.exception), 'Expected str, not bytes') ++ with self.assertRaises(self.failureException) as cm: ++ self.assertStartsWith([], 'ababa') ++ self.assertEqual(str(cm.exception), 'Expected str, not list') ++ with self.assertRaises(self.failureException) as cm: ++ self.assertStartsWith('ababahalamaha', b'ababa') ++ self.assertEqual(str(cm.exception), 'Expected bytes, not str') ++ with self.assertRaises(self.failureException) as cm: ++ self.assertStartsWith('ababahalamaha', (b'amaha', b'ababa')) ++ self.assertEqual(str(cm.exception), 'Expected bytes, not str') ++ with self.assertRaises(TypeError): ++ self.assertStartsWith('ababahalamaha', ord('a')) ++ ++ with self.assertRaises(self.failureException) as cm: ++ self.assertStartsWith('ababahalamaha', 'amaha', 'abracadabra') ++ self.assertIn('ababahalamaha', str(cm.exception)) ++ with self.assertRaises(self.failureException) as cm: ++ self.assertStartsWith('ababahalamaha', 'amaha', msg='abracadabra') ++ self.assertIn('ababahalamaha', str(cm.exception)) ++ ++ def testAssertNotStartswith(self): ++ self.assertNotStartsWith('ababahalamaha', 'amaha') ++ self.assertNotStartsWith('ababahalamaha', ('x', 'amaha', 'y')) ++ self.assertNotStartsWith(UserString('ababahalamaha'), 'amaha') ++ self.assertNotStartsWith(UserString('ababahalamaha'), ('x', 'amaha', 'y')) ++ self.assertNotStartsWith(bytearray(b'ababahalamaha'), b'amaha') ++ self.assertNotStartsWith(bytearray(b'ababahalamaha'), (b'x', b'amaha', b'y')) ++ self.assertNotStartsWith(b'ababahalamaha', bytearray(b'amaha')) ++ self.assertNotStartsWith(b'ababahalamaha', ++ (bytearray(b'x'), bytearray(b'amaha'), bytearray(b'y'))) ++ ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotStartsWith('ababahalamaha', 'ababa') ++ self.assertEqual(str(cm.exception), ++ "'ababahalamaha' starts with 'ababa'") ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotStartsWith('ababahalamaha', ('x', 'ababa', 'y')) ++ self.assertEqual(str(cm.exception), ++ "'ababahalamaha' starts with 'ababa'") ++ ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotStartsWith(b'ababahalamaha', 'ababa') ++ self.assertEqual(str(cm.exception), 'Expected str, not bytes') ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotStartsWith(b'ababahalamaha', ('amaha', 'ababa')) ++ self.assertEqual(str(cm.exception), 'Expected str, not bytes') ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotStartsWith([], 'ababa') ++ self.assertEqual(str(cm.exception), 'Expected str, not list') ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotStartsWith('ababahalamaha', b'ababa') ++ self.assertEqual(str(cm.exception), 'Expected bytes, not str') ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotStartsWith('ababahalamaha', (b'amaha', b'ababa')) ++ self.assertEqual(str(cm.exception), 'Expected bytes, not str') ++ with self.assertRaises(TypeError): ++ self.assertNotStartsWith('ababahalamaha', ord('a')) ++ ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotStartsWith('ababahalamaha', 'ababa', 'abracadabra') ++ self.assertIn('ababahalamaha', str(cm.exception)) ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotStartsWith('ababahalamaha', 'ababa', msg='abracadabra') ++ self.assertIn('ababahalamaha', str(cm.exception)) ++ ++ def testAssertEndswith(self): ++ self.assertEndsWith('ababahalamaha', 'amaha') ++ self.assertEndsWith('ababahalamaha', ('x', 'amaha', 'y')) ++ self.assertEndsWith(UserString('ababahalamaha'), 'amaha') ++ self.assertEndsWith(UserString('ababahalamaha'), ('x', 'amaha', 'y')) ++ self.assertEndsWith(bytearray(b'ababahalamaha'), b'amaha') ++ self.assertEndsWith(bytearray(b'ababahalamaha'), (b'x', b'amaha', b'y')) ++ self.assertEndsWith(b'ababahalamaha', bytearray(b'amaha')) ++ self.assertEndsWith(b'ababahalamaha', ++ (bytearray(b'x'), bytearray(b'amaha'), bytearray(b'y'))) ++ ++ with self.assertRaises(self.failureException) as cm: ++ self.assertEndsWith('ababahalamaha', 'ababa') ++ self.assertEqual(str(cm.exception), ++ "'ababahalamaha' doesn't end with 'ababa'") ++ with self.assertRaises(self.failureException) as cm: ++ self.assertEndsWith('ababahalamaha', ('x', 'y')) ++ self.assertEqual(str(cm.exception), ++ "'ababahalamaha' doesn't end with any of ('x', 'y')") ++ ++ with self.assertRaises(self.failureException) as cm: ++ self.assertEndsWith(b'ababahalamaha', 'amaha') ++ self.assertEqual(str(cm.exception), 'Expected str, not bytes') ++ with self.assertRaises(self.failureException) as cm: ++ self.assertEndsWith(b'ababahalamaha', ('ababa', 'amaha')) ++ self.assertEqual(str(cm.exception), 'Expected str, not bytes') ++ with self.assertRaises(self.failureException) as cm: ++ self.assertEndsWith([], 'amaha') ++ self.assertEqual(str(cm.exception), 'Expected str, not list') ++ with self.assertRaises(self.failureException) as cm: ++ self.assertEndsWith('ababahalamaha', b'amaha') ++ self.assertEqual(str(cm.exception), 'Expected bytes, not str') ++ with self.assertRaises(self.failureException) as cm: ++ self.assertEndsWith('ababahalamaha', (b'ababa', b'amaha')) ++ self.assertEqual(str(cm.exception), 'Expected bytes, not str') ++ with self.assertRaises(TypeError): ++ self.assertEndsWith('ababahalamaha', ord('a')) ++ ++ with self.assertRaises(self.failureException) as cm: ++ self.assertEndsWith('ababahalamaha', 'ababa', 'abracadabra') ++ self.assertIn('ababahalamaha', str(cm.exception)) ++ with self.assertRaises(self.failureException) as cm: ++ self.assertEndsWith('ababahalamaha', 'ababa', msg='abracadabra') ++ self.assertIn('ababahalamaha', str(cm.exception)) ++ ++ def testAssertNotEndswith(self): ++ self.assertNotEndsWith('ababahalamaha', 'ababa') ++ self.assertNotEndsWith('ababahalamaha', ('x', 'ababa', 'y')) ++ self.assertNotEndsWith(UserString('ababahalamaha'), 'ababa') ++ self.assertNotEndsWith(UserString('ababahalamaha'), ('x', 'ababa', 'y')) ++ self.assertNotEndsWith(bytearray(b'ababahalamaha'), b'ababa') ++ self.assertNotEndsWith(bytearray(b'ababahalamaha'), (b'x', b'ababa', b'y')) ++ self.assertNotEndsWith(b'ababahalamaha', bytearray(b'ababa')) ++ self.assertNotEndsWith(b'ababahalamaha', ++ (bytearray(b'x'), bytearray(b'ababa'), bytearray(b'y'))) ++ ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotEndsWith('ababahalamaha', 'amaha') ++ self.assertEqual(str(cm.exception), ++ "'ababahalamaha' ends with 'amaha'") ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotEndsWith('ababahalamaha', ('x', 'amaha', 'y')) ++ self.assertEqual(str(cm.exception), ++ "'ababahalamaha' ends with 'amaha'") ++ ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotEndsWith(b'ababahalamaha', 'amaha') ++ self.assertEqual(str(cm.exception), 'Expected str, not bytes') ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotEndsWith(b'ababahalamaha', ('ababa', 'amaha')) ++ self.assertEqual(str(cm.exception), 'Expected str, not bytes') ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotEndsWith([], 'amaha') ++ self.assertEqual(str(cm.exception), 'Expected str, not list') ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotEndsWith('ababahalamaha', b'amaha') ++ self.assertEqual(str(cm.exception), 'Expected bytes, not str') ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotEndsWith('ababahalamaha', (b'ababa', b'amaha')) ++ self.assertEqual(str(cm.exception), 'Expected bytes, not str') ++ with self.assertRaises(TypeError): ++ self.assertNotEndsWith('ababahalamaha', ord('a')) ++ ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotEndsWith('ababahalamaha', 'amaha', 'abracadabra') ++ self.assertIn('ababahalamaha', str(cm.exception)) ++ with self.assertRaises(self.failureException) as cm: ++ self.assertNotEndsWith('ababahalamaha', 'amaha', msg='abracadabra') ++ self.assertIn('ababahalamaha', str(cm.exception)) ++ + def testDeprecatedFailMethods(self): + """Test that the deprecated fail* methods get removed in 3.12""" + deprecated_names = [ +diff --git a/Lib/test/test_unittest/test_loader.py b/Lib/test/test_unittest/test_loader.py +index 83dd25ca546..cdff6d1a20c 100644 +--- a/Lib/test/test_unittest/test_loader.py ++++ b/Lib/test/test_unittest/test_loader.py +@@ -76,7 +76,7 @@ + + loader = unittest.TestLoader() + # This has to be false for the test to succeed +- self.assertFalse('runTest'.startswith(loader.testMethodPrefix)) ++ self.assertNotStartsWith('runTest', loader.testMethodPrefix) + + suite = loader.loadTestsFromTestCase(Foo) + self.assertIsInstance(suite, loader.suiteClass) +diff --git a/Lib/test/test_unittest/test_program.py b/Lib/test/test_unittest/test_program.py +index 0b46f338ac7..6092ed292d8 100644 +--- a/Lib/test/test_unittest/test_program.py ++++ b/Lib/test/test_unittest/test_program.py +@@ -4,10 +4,10 @@ + from test import support + import unittest + import test.test_unittest +-from test.support import force_not_colorized + from test.test_unittest.test_result import BufferedWriter + + ++@support.force_not_colorized_test_class + class Test_TestProgram(unittest.TestCase): + + def test_discovery_from_dotted_path(self): +@@ -121,23 +121,21 @@ + self.assertEqual(['test.test_unittest', 'test.test_unittest2'], + program.testNames) + +- @force_not_colorized + def test_NonExit(self): + stream = BufferedWriter() + program = unittest.main(exit=False, + argv=["foobar"], + testRunner=unittest.TextTestRunner(stream=stream), + testLoader=self.TestLoader(self.FooBar)) +- self.assertTrue(hasattr(program, 'result')) ++ self.assertHasAttr(program, 'result') + out = stream.getvalue() + self.assertIn('\nFAIL: testFail ', out) + self.assertIn('\nERROR: testError ', out) + self.assertIn('\nUNEXPECTED SUCCESS: testUnexpectedSuccess ', out) + expected = ('\n\nFAILED (failures=1, errors=1, skipped=1, ' + 'expected failures=1, unexpected successes=1)\n') +- self.assertTrue(out.endswith(expected)) ++ self.assertEndsWith(out, expected) + +- @force_not_colorized + def test_Exit(self): + stream = BufferedWriter() + with self.assertRaises(SystemExit) as cm: +@@ -153,9 +151,8 @@ + self.assertIn('\nUNEXPECTED SUCCESS: testUnexpectedSuccess ', out) + expected = ('\n\nFAILED (failures=1, errors=1, skipped=1, ' + 'expected failures=1, unexpected successes=1)\n') +- self.assertTrue(out.endswith(expected)) ++ self.assertEndsWith(out, expected) + +- @force_not_colorized + def test_ExitAsDefault(self): + stream = BufferedWriter() + with self.assertRaises(SystemExit): +@@ -169,9 +166,8 @@ + self.assertIn('\nUNEXPECTED SUCCESS: testUnexpectedSuccess ', out) + expected = ('\n\nFAILED (failures=1, errors=1, skipped=1, ' + 'expected failures=1, unexpected successes=1)\n') +- self.assertTrue(out.endswith(expected)) ++ self.assertEndsWith(out, expected) + +- @force_not_colorized + def test_ExitSkippedSuite(self): + stream = BufferedWriter() + with self.assertRaises(SystemExit) as cm: +@@ -182,9 +178,8 @@ + self.assertEqual(cm.exception.code, 0) + out = stream.getvalue() + expected = '\n\nOK (skipped=1)\n' +- self.assertTrue(out.endswith(expected)) ++ self.assertEndsWith(out, expected) + +- @force_not_colorized + def test_ExitEmptySuite(self): + stream = BufferedWriter() + with self.assertRaises(SystemExit) as cm: +diff --git a/Lib/test/test_unittest/test_result.py b/Lib/test/test_unittest/test_result.py +index 746b9fa2677..9ac4c52449c 100644 +--- a/Lib/test/test_unittest/test_result.py ++++ b/Lib/test/test_unittest/test_result.py +@@ -1,13 +1,11 @@ + import io + import sys + import textwrap +- +-from test.support import warnings_helper, captured_stdout +- + import traceback + import unittest + from unittest.util import strclass +-from test.support import force_not_colorized ++from test.support import warnings_helper ++from test.support import captured_stdout, force_not_colorized_test_class + from test.test_unittest.support import BufferedWriter + + +@@ -35,6 +33,7 @@ + raise ValueError('bad cleanup2') + + ++@force_not_colorized_test_class + class Test_TestResult(unittest.TestCase): + # Note: there are not separate tests for TestResult.wasSuccessful(), + # TestResult.errors, TestResult.failures, TestResult.testsRun or +@@ -206,7 +205,6 @@ + self.assertIs(test_case, test) + self.assertIsInstance(formatted_exc, str) + +- @force_not_colorized + def test_addFailure_filter_traceback_frames(self): + class Foo(unittest.TestCase): + def test_1(self): +@@ -233,7 +231,6 @@ + self.assertEqual(len(dropped), 1) + self.assertIn("raise self.failureException(msg)", dropped[0]) + +- @force_not_colorized + def test_addFailure_filter_traceback_frames_context(self): + class Foo(unittest.TestCase): + def test_1(self): +@@ -263,7 +260,6 @@ + self.assertEqual(len(dropped), 1) + self.assertIn("raise self.failureException(msg)", dropped[0]) + +- @force_not_colorized + def test_addFailure_filter_traceback_frames_chained_exception_self_loop(self): + class Foo(unittest.TestCase): + def test_1(self): +@@ -289,7 +285,6 @@ + formatted_exc = result.failures[0][1] + self.assertEqual(formatted_exc.count("Exception: Loop\n"), 1) + +- @force_not_colorized + def test_addFailure_filter_traceback_frames_chained_exception_cycle(self): + class Foo(unittest.TestCase): + def test_1(self): +@@ -451,7 +446,6 @@ + result.addUnexpectedSuccess(None) + self.assertTrue(result.shouldStop) + +- @force_not_colorized + def testFailFastSetByRunner(self): + stream = BufferedWriter() + runner = unittest.TextTestRunner(stream=stream, failfast=True) +@@ -460,9 +454,10 @@ + self.assertTrue(result.failfast) + result = runner.run(test) + stream.flush() +- self.assertTrue(stream.getvalue().endswith('\n\nOK\n')) ++ self.assertEndsWith(stream.getvalue(), '\n\nOK\n') + + ++@force_not_colorized_test_class + class Test_TextTestResult(unittest.TestCase): + maxDiff = None + +@@ -625,7 +620,6 @@ + test.run(result) + return stream.getvalue() + +- @force_not_colorized + def testDotsOutput(self): + self.assertEqual(self._run_test('testSuccess', 1), '.') + self.assertEqual(self._run_test('testSkip', 1), 's') +@@ -634,7 +628,6 @@ + self.assertEqual(self._run_test('testExpectedFailure', 1), 'x') + self.assertEqual(self._run_test('testUnexpectedSuccess', 1), 'u') + +- @force_not_colorized + def testLongOutput(self): + classname = f'{__name__}.{self.Test.__qualname__}' + self.assertEqual(self._run_test('testSuccess', 2), +@@ -650,21 +643,17 @@ + self.assertEqual(self._run_test('testUnexpectedSuccess', 2), + f'testUnexpectedSuccess ({classname}.testUnexpectedSuccess) ... unexpected success\n') + +- @force_not_colorized + def testDotsOutputSubTestSuccess(self): + self.assertEqual(self._run_test('testSubTestSuccess', 1), '.') + +- @force_not_colorized + def testLongOutputSubTestSuccess(self): + classname = f'{__name__}.{self.Test.__qualname__}' + self.assertEqual(self._run_test('testSubTestSuccess', 2), + f'testSubTestSuccess ({classname}.testSubTestSuccess) ... ok\n') + +- @force_not_colorized + def testDotsOutputSubTestMixed(self): + self.assertEqual(self._run_test('testSubTestMixed', 1), 'sFE') + +- @force_not_colorized + def testLongOutputSubTestMixed(self): + classname = f'{__name__}.{self.Test.__qualname__}' + self.assertEqual(self._run_test('testSubTestMixed', 2), +@@ -673,7 +662,6 @@ + f' testSubTestMixed ({classname}.testSubTestMixed) [fail] (c=3) ... FAIL\n' + f' testSubTestMixed ({classname}.testSubTestMixed) [error] (d=4) ... ERROR\n') + +- @force_not_colorized + def testDotsOutputTearDownFail(self): + out = self._run_test('testSuccess', 1, AssertionError('fail')) + self.assertEqual(out, 'F') +@@ -684,7 +672,6 @@ + out = self._run_test('testSkip', 1, AssertionError('fail')) + self.assertEqual(out, 'sF') + +- @force_not_colorized + def testLongOutputTearDownFail(self): + classname = f'{__name__}.{self.Test.__qualname__}' + out = self._run_test('testSuccess', 2, AssertionError('fail')) +@@ -772,6 +759,7 @@ + runner.run(Test('testFoo')) + + ++@force_not_colorized_test_class + class TestOutputBuffering(unittest.TestCase): + + def setUp(self): +diff --git a/Lib/test/test_unittest/test_runner.py b/Lib/test/test_unittest/test_runner.py +index 1131cd73128..4d3cfd60b8d 100644 +--- a/Lib/test/test_unittest/test_runner.py ++++ b/Lib/test/test_unittest/test_runner.py +@@ -4,7 +4,6 @@ + import pickle + import subprocess + from test import support +-from test.support import force_not_colorized + + import unittest + from unittest.case import _Outcome +@@ -107,7 +106,7 @@ + self.assertTrue(test.doCleanups()) + self.assertEqual(cleanups, [(2, (), {}), (1, (1, 2, 3), dict(four='hello', five='goodbye'))]) + +- @force_not_colorized ++ @support.force_not_colorized + def testCleanUpWithErrors(self): + class TestableTest(unittest.TestCase): + def testNothing(self): +@@ -251,6 +250,7 @@ + self.assertEqual(test._cleanups, []) + + ++@support.force_not_colorized_test_class + class TestClassCleanup(unittest.TestCase): + def test_addClassCleanUp(self): + class TestableTest(unittest.TestCase): +@@ -418,7 +418,6 @@ + self.assertIsInstance(e2[1], CustomError) + self.assertEqual(str(e2[1]), 'cleanup1') + +- @force_not_colorized + def test_with_errors_addCleanUp(self): + ordering = [] + class TestableTest(unittest.TestCase): +@@ -442,7 +441,6 @@ + ['setUpClass', 'setUp', 'cleanup_exc', + 'tearDownClass', 'cleanup_good']) + +- @force_not_colorized + def test_run_with_errors_addClassCleanUp(self): + ordering = [] + class TestableTest(unittest.TestCase): +@@ -466,7 +464,6 @@ + ['setUpClass', 'setUp', 'test', 'cleanup_good', + 'tearDownClass', 'cleanup_exc']) + +- @force_not_colorized + def test_with_errors_in_addClassCleanup_and_setUps(self): + ordering = [] + class_blow_up = False +@@ -519,7 +516,6 @@ + ['setUpClass', 'setUp', 'tearDownClass', + 'cleanup_exc']) + +- @force_not_colorized + def test_with_errors_in_tearDownClass(self): + ordering = [] + class TestableTest(unittest.TestCase): +@@ -596,7 +592,6 @@ + 'inner setup', 'inner test', 'inner cleanup', + 'end outer test', 'outer cleanup']) + +- @force_not_colorized + def test_run_empty_suite_error_message(self): + class EmptyTest(unittest.TestCase): + pass +@@ -608,6 +603,7 @@ + self.assertIn("\nNO TESTS RAN\n", runner.stream.getvalue()) + + ++@support.force_not_colorized_test_class + class TestModuleCleanUp(unittest.TestCase): + def test_add_and_do_ModuleCleanup(self): + module_cleanups = [] +@@ -670,7 +666,6 @@ + self.assertEqual(cleanups, + [((1, 2), {'function': 'hello'})]) + +- @force_not_colorized + def test_run_module_cleanUp(self): + blowUp = True + ordering = [] +@@ -810,7 +805,6 @@ + 'tearDownClass', 'cleanup_good']) + self.assertEqual(unittest.case._module_cleanups, []) + +- @force_not_colorized + def test_run_module_cleanUp_when_teardown_exception(self): + ordering = [] + class Module(object): +@@ -972,7 +966,6 @@ + self.assertEqual(cleanups, + [((1, 2), {'function': 3, 'self': 4})]) + +- @force_not_colorized + def test_with_errors_in_addClassCleanup(self): + ordering = [] + +@@ -1006,7 +999,6 @@ + ['setUpModule', 'setUpClass', 'test', 'tearDownClass', + 'cleanup_exc', 'tearDownModule', 'cleanup_good']) + +- @force_not_colorized + def test_with_errors_in_addCleanup(self): + ordering = [] + class Module(object): +@@ -1037,7 +1029,6 @@ + ['setUpModule', 'setUp', 'test', 'tearDown', + 'cleanup_exc', 'tearDownModule', 'cleanup_good']) + +- @force_not_colorized + def test_with_errors_in_addModuleCleanup_and_setUps(self): + ordering = [] + module_blow_up = False +@@ -1330,7 +1321,7 @@ + expectedresult = (runner.stream, DESCRIPTIONS, VERBOSITY) + self.assertEqual(runner._makeResult(), expectedresult) + +- @force_not_colorized ++ @support.force_not_colorized + @support.requires_subprocess() + def test_warnings(self): + """ +diff --git a/Lib/test/test_unittest/testmock/testasync.py b/Lib/test/test_unittest/testmock/testasync.py +index 73f04291373..0791675b540 100644 +--- a/Lib/test/test_unittest/testmock/testasync.py ++++ b/Lib/test/test_unittest/testmock/testasync.py +@@ -15,7 +15,7 @@ + + + def tearDownModule(): +- asyncio.set_event_loop_policy(None) ++ asyncio._set_event_loop_policy(None) + + + class AsyncClass: +@@ -586,16 +586,16 @@ + + def test_magicmock_has_async_magic_methods(self): + m_mock = MagicMock() +- self.assertTrue(hasattr(m_mock, "__aenter__")) +- self.assertTrue(hasattr(m_mock, "__aexit__")) +- self.assertTrue(hasattr(m_mock, "__anext__")) ++ self.assertHasAttr(m_mock, "__aenter__") ++ self.assertHasAttr(m_mock, "__aexit__") ++ self.assertHasAttr(m_mock, "__anext__") + + def test_asyncmock_has_sync_magic_methods(self): + a_mock = AsyncMock() +- self.assertTrue(hasattr(a_mock, "__enter__")) +- self.assertTrue(hasattr(a_mock, "__exit__")) +- self.assertTrue(hasattr(a_mock, "__next__")) +- self.assertTrue(hasattr(a_mock, "__len__")) ++ self.assertHasAttr(a_mock, "__enter__") ++ self.assertHasAttr(a_mock, "__exit__") ++ self.assertHasAttr(a_mock, "__next__") ++ self.assertHasAttr(a_mock, "__len__") + + def test_magic_methods_are_async_functions(self): + m_mock = MagicMock() +diff --git a/Lib/test/test_unittest/testmock/testcallable.py b/Lib/test/test_unittest/testmock/testcallable.py +index ca88511f639..03cb983e447 100644 +--- a/Lib/test/test_unittest/testmock/testcallable.py ++++ b/Lib/test/test_unittest/testmock/testcallable.py +@@ -23,21 +23,21 @@ + def test_non_callable(self): + for mock in NonCallableMagicMock(), NonCallableMock(): + self.assertRaises(TypeError, mock) +- self.assertFalse(hasattr(mock, '__call__')) ++ self.assertNotHasAttr(mock, '__call__') + self.assertIn(mock.__class__.__name__, repr(mock)) + + + def test_hierarchy(self): +- self.assertTrue(issubclass(MagicMock, Mock)) +- self.assertTrue(issubclass(NonCallableMagicMock, NonCallableMock)) ++ self.assertIsSubclass(MagicMock, Mock) ++ self.assertIsSubclass(NonCallableMagicMock, NonCallableMock) + + + def test_attributes(self): + one = NonCallableMock() +- self.assertTrue(issubclass(type(one.one), Mock)) ++ self.assertIsSubclass(type(one.one), Mock) + + two = NonCallableMagicMock() +- self.assertTrue(issubclass(type(two.two), MagicMock)) ++ self.assertIsSubclass(type(two.two), MagicMock) + + + def test_subclasses(self): +@@ -45,13 +45,13 @@ + pass + + one = MockSub() +- self.assertTrue(issubclass(type(one.one), MockSub)) ++ self.assertIsSubclass(type(one.one), MockSub) + + class MagicSub(MagicMock): + pass + + two = MagicSub() +- self.assertTrue(issubclass(type(two.two), MagicSub)) ++ self.assertIsSubclass(type(two.two), MagicSub) + + + def test_patch_spec(self): +diff --git a/Lib/test/test_unittest/testmock/testhelpers.py b/Lib/test/test_unittest/testmock/testhelpers.py +index f260769eb8c..8d0f3ebc5cb 100644 +--- a/Lib/test/test_unittest/testmock/testhelpers.py ++++ b/Lib/test/test_unittest/testmock/testhelpers.py +@@ -951,7 +951,7 @@ + + proxy = Foo() + autospec = create_autospec(proxy) +- self.assertFalse(hasattr(autospec, '__name__')) ++ self.assertNotHasAttr(autospec, '__name__') + + + def test_autospec_signature_staticmethod(self): +diff --git a/Lib/test/test_unittest/testmock/testmagicmethods.py b/Lib/test/test_unittest/testmock/testmagicmethods.py +index 2a8aa11b328..acdbd699d18 100644 +--- a/Lib/test/test_unittest/testmock/testmagicmethods.py ++++ b/Lib/test/test_unittest/testmock/testmagicmethods.py +@@ -10,13 +10,13 @@ + + def test_deleting_magic_methods(self): + mock = Mock() +- self.assertFalse(hasattr(mock, '__getitem__')) ++ self.assertNotHasAttr(mock, '__getitem__') + + mock.__getitem__ = Mock() +- self.assertTrue(hasattr(mock, '__getitem__')) ++ self.assertHasAttr(mock, '__getitem__') + + del mock.__getitem__ +- self.assertFalse(hasattr(mock, '__getitem__')) ++ self.assertNotHasAttr(mock, '__getitem__') + + + def test_magicmock_del(self): +@@ -252,12 +252,12 @@ + self.assertEqual(list(mock), [1, 2, 3]) + + getattr(mock, '__bool__').return_value = False +- self.assertFalse(hasattr(mock, '__nonzero__')) ++ self.assertNotHasAttr(mock, '__nonzero__') + self.assertFalse(bool(mock)) + + for entry in _magics: +- self.assertTrue(hasattr(mock, entry)) +- self.assertFalse(hasattr(mock, '__imaginary__')) ++ self.assertHasAttr(mock, entry) ++ self.assertNotHasAttr(mock, '__imaginary__') + + + def test_magic_mock_equality(self): +diff --git a/Lib/test/test_unittest/testmock/testmock.py b/Lib/test/test_unittest/testmock/testmock.py +index e1b108f81e5..5d1bf4258af 100644 +--- a/Lib/test/test_unittest/testmock/testmock.py ++++ b/Lib/test/test_unittest/testmock/testmock.py +@@ -2215,13 +2215,13 @@ + def test_attribute_deletion(self): + for mock in (Mock(), MagicMock(), NonCallableMagicMock(), + NonCallableMock()): +- self.assertTrue(hasattr(mock, 'm')) ++ self.assertHasAttr(mock, 'm') + + del mock.m +- self.assertFalse(hasattr(mock, 'm')) ++ self.assertNotHasAttr(mock, 'm') + + del mock.f +- self.assertFalse(hasattr(mock, 'f')) ++ self.assertNotHasAttr(mock, 'f') + self.assertRaises(AttributeError, getattr, mock, 'f') + + +@@ -2230,18 +2230,18 @@ + for mock in (Mock(), MagicMock(), NonCallableMagicMock(), + NonCallableMock()): + mock.foo = 3 +- self.assertTrue(hasattr(mock, 'foo')) ++ self.assertHasAttr(mock, 'foo') + self.assertEqual(mock.foo, 3) + + del mock.foo +- self.assertFalse(hasattr(mock, 'foo')) ++ self.assertNotHasAttr(mock, 'foo') + + mock.foo = 4 +- self.assertTrue(hasattr(mock, 'foo')) ++ self.assertHasAttr(mock, 'foo') + self.assertEqual(mock.foo, 4) + + del mock.foo +- self.assertFalse(hasattr(mock, 'foo')) ++ self.assertNotHasAttr(mock, 'foo') + + + def test_mock_raises_when_deleting_nonexistent_attribute(self): +@@ -2259,7 +2259,7 @@ + mock.child = True + del mock.child + mock.reset_mock() +- self.assertFalse(hasattr(mock, 'child')) ++ self.assertNotHasAttr(mock, 'child') + + + def test_class_assignable(self): +diff --git a/Lib/test/test_unittest/testmock/testpatch.py b/Lib/test/test_unittest/testmock/testpatch.py +index 037c021e6ea..7c5fc3deed2 100644 +--- a/Lib/test/test_unittest/testmock/testpatch.py ++++ b/Lib/test/test_unittest/testmock/testpatch.py +@@ -366,7 +366,7 @@ + self.assertEqual(SomeClass.frooble, sentinel.Frooble) + + test() +- self.assertFalse(hasattr(SomeClass, 'frooble')) ++ self.assertNotHasAttr(SomeClass, 'frooble') + + + def test_patch_wont_create_by_default(self): +@@ -383,7 +383,7 @@ + @patch.object(SomeClass, 'ord', sentinel.Frooble) + def test(): pass + test() +- self.assertFalse(hasattr(SomeClass, 'ord')) ++ self.assertNotHasAttr(SomeClass, 'ord') + + + def test_patch_builtins_without_create(self): +@@ -1477,7 +1477,7 @@ + finally: + patcher.stop() + +- self.assertFalse(hasattr(Foo, 'blam')) ++ self.assertNotHasAttr(Foo, 'blam') + + + def test_patch_multiple_spec_set(self): +diff --git a/Lib/test/test_unparse.py b/Lib/test/test_unparse.py +index 35394f29fbe..f6c4f1f3f64 100644 +--- a/Lib/test/test_unparse.py ++++ b/Lib/test/test_unparse.py +@@ -513,11 +513,13 @@ + self.check_src_roundtrip("class X(*args, **kwargs):\n pass") + + def test_fstrings(self): +- self.check_src_roundtrip("f'-{f'*{f'+{f'.{x}.'}+'}*'}-'") +- self.check_src_roundtrip("f'\\u2028{'x'}'") ++ self.check_src_roundtrip('''f\'\'\'-{f"""*{f"+{f'.{x}.'}+"}*"""}-\'\'\'''') ++ self.check_src_roundtrip('''f\'-{f\'\'\'*{f"""+{f".{f'{x}'}."}+"""}*\'\'\'}-\'''') ++ self.check_src_roundtrip('''f\'-{f\'*{f\'\'\'+{f""".{f"{f'{x}'}"}."""}+\'\'\'}*\'}-\'''') ++ self.check_src_roundtrip('''f"\\u2028{'x'}"''') + self.check_src_roundtrip(r"f'{x}\n'") +- self.check_src_roundtrip("f'{'\\n'}\\n'") +- self.check_src_roundtrip("f'{f'{x}\\n'}\\n'") ++ self.check_src_roundtrip('''f"{'\\n'}\\n"''') ++ self.check_src_roundtrip('''f"{f'{x}\\n'}\\n"''') + + def test_docstrings(self): + docstrings = ( +@@ -651,7 +653,9 @@ + + def test_backslash_in_format_spec(self): + import re +- msg = re.escape("invalid escape sequence '\\ '") ++ msg = re.escape('"\\ " is an invalid escape sequence. ' ++ 'Such sequences will not work in the future. ' ++ 'Did you mean "\\\\ "? A raw string is also an option.') + with self.assertWarnsRegex(SyntaxWarning, msg): + self.check_ast_roundtrip("""f"{x:\\ }" """) + self.check_ast_roundtrip("""f"{x:\\n}" """) +diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py +index 042d3b35b77..4842428d6fd 100644 +--- a/Lib/test/test_urllib.py ++++ b/Lib/test/test_urllib.py +@@ -419,7 +419,9 @@ + Content-Type: text/html; charset=iso-8859-1 + ''', mock_close=True) + try: +- self.assertRaises(OSError, urllib.request.urlopen, "http://python.org/") ++ with self.assertRaises(urllib.error.HTTPError) as cm: ++ urllib.request.urlopen("http://python.org/") ++ cm.exception.close() + finally: + self.unfakehttp() + +@@ -434,8 +436,9 @@ + ''', mock_close=True) + try: + msg = "Redirection to url 'file:" +- with self.assertRaisesRegex(urllib.error.HTTPError, msg): ++ with self.assertRaisesRegex(urllib.error.HTTPError, msg) as cm: + urllib.request.urlopen("http://python.org/") ++ cm.exception.close() + finally: + self.unfakehttp() + +@@ -448,8 +451,9 @@ + Connection: close + ''', mock_close=True) + try: +- self.assertRaises(urllib.error.HTTPError, urllib.request.urlopen, +- "http://something") ++ with self.assertRaises(urllib.error.HTTPError) as cm: ++ urllib.request.urlopen("http://something") ++ cm.exception.close() + finally: + self.unfakehttp() + +@@ -529,10 +533,11 @@ + "QOjdAAAAAXNSR0IArs4c6QAAAA9JREFUCNdj%0AYGBg%2BP//PwAGAQL%2BCm8 " + "vHgAAAABJRU5ErkJggg%3D%3D%0A%20") + +- self.text_url_resp = urllib.request.urlopen(self.text_url) +- self.text_url_base64_resp = urllib.request.urlopen( +- self.text_url_base64) +- self.image_url_resp = urllib.request.urlopen(self.image_url) ++ self.text_url_resp = self.enterContext( ++ urllib.request.urlopen(self.text_url)) ++ self.text_url_base64_resp = self.enterContext( ++ urllib.request.urlopen(self.text_url_base64)) ++ self.image_url_resp = self.enterContext(urllib.request.urlopen(self.image_url)) + + def test_interface(self): + # Make sure object returned by urlopen() has the specified methods +@@ -548,8 +553,10 @@ + [('text/plain', ''), ('charset', 'ISO-8859-1')]) + self.assertEqual(self.image_url_resp.info()['content-length'], + str(len(self.image))) +- self.assertEqual(urllib.request.urlopen("data:,").info().get_params(), ++ r = urllib.request.urlopen("data:,") ++ self.assertEqual(r.info().get_params(), + [('text/plain', ''), ('charset', 'US-ASCII')]) ++ r.close() + + def test_geturl(self): + self.assertEqual(self.text_url_resp.geturl(), self.text_url) +diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py +index 4a9e653515b..44e6af8c6b6 100644 +--- a/Lib/test/test_urllib2.py ++++ b/Lib/test/test_urllib2.py +@@ -27,6 +27,7 @@ + import urllib.error + import http.client + ++ + support.requires_working_socket(module=True) + + # XXX +@@ -781,6 +782,7 @@ + headers = r.info() + self.assertEqual(headers.get("Content-type"), mimetype) + self.assertEqual(int(headers["Content-length"]), len(data)) ++ r.close() + + @support.requires_resource("network") + def test_ftp_error(self): +@@ -1246,10 +1248,11 @@ + try: + method(req, MockFile(), code, "Blah", + MockHeaders({"location": to_url})) +- except urllib.error.HTTPError: ++ except urllib.error.HTTPError as err: + # 307 and 308 in response to POST require user OK + self.assertIn(code, (307, 308)) + self.assertIsNotNone(data) ++ err.close() + self.assertEqual(o.req.get_full_url(), to_url) + try: + self.assertEqual(o.req.get_method(), "GET") +@@ -1285,9 +1288,10 @@ + while 1: + redirect(h, req, "http://example.com/") + count = count + 1 +- except urllib.error.HTTPError: ++ except urllib.error.HTTPError as err: + # don't stop until max_repeats, because cookies may introduce state + self.assertEqual(count, urllib.request.HTTPRedirectHandler.max_repeats) ++ err.close() + + # detect endless non-repeating chain of redirects + req = Request(from_url, origin_req_host="example.com") +@@ -1297,9 +1301,10 @@ + while 1: + redirect(h, req, "http://example.com/%d" % count) + count = count + 1 +- except urllib.error.HTTPError: ++ except urllib.error.HTTPError as err: + self.assertEqual(count, + urllib.request.HTTPRedirectHandler.max_redirections) ++ err.close() + + def test_invalid_redirect(self): + from_url = "http://example.com/a.html" +@@ -1313,9 +1318,11 @@ + + for scheme in invalid_schemes: + invalid_url = scheme + '://' + schemeless_url +- self.assertRaises(urllib.error.HTTPError, h.http_error_302, ++ with self.assertRaises(urllib.error.HTTPError) as cm: ++ h.http_error_302( + req, MockFile(), 302, "Security Loophole", + MockHeaders({"location": invalid_url})) ++ cm.exception.close() + + for scheme in valid_schemes: + valid_url = scheme + '://' + schemeless_url +@@ -1911,11 +1918,13 @@ + self.assertEqual(str(err), expected_errmsg) + expected_errmsg = '' % (err.code, err.msg) + self.assertEqual(repr(err), expected_errmsg) ++ err.close() + + def test_gh_98778(self): + x = urllib.error.HTTPError("url", 405, "METHOD NOT ALLOWED", None, None) + self.assertEqual(getattr(x, "__notes__", ()), ()) + self.assertIsInstance(x.fp.read(), bytes) ++ x.close() + + def test_parse_proxy(self): + parse_proxy_test_cases = [ +@@ -1962,10 +1971,38 @@ + + self.assertRaises(ValueError, _parse_proxy, 'file:/ftp.example.com'), + +- def test_unsupported_algorithm(self): +- handler = AbstractDigestAuthHandler() ++ ++skip_libssl_fips_mode = unittest.skipIf( ++ support.is_libssl_fips_mode(), ++ "conservative skip due to OpenSSL FIPS mode possible algorithm nerfing", ++) ++ ++ ++class TestDigestAuthAlgorithms(unittest.TestCase): ++ def setUp(self): ++ self.handler = AbstractDigestAuthHandler() ++ ++ @skip_libssl_fips_mode ++ def test_md5_algorithm(self): ++ H, KD = self.handler.get_algorithm_impls('MD5') ++ self.assertEqual(H("foo"), "acbd18db4cc2f85cedef654fccc4a4d8") ++ self.assertEqual(KD("foo", "bar"), "4e99e8c12de7e01535248d2bac85e732") ++ ++ @skip_libssl_fips_mode ++ def test_sha_algorithm(self): ++ H, KD = self.handler.get_algorithm_impls('SHA') ++ self.assertEqual(H("foo"), "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33") ++ self.assertEqual(KD("foo", "bar"), "54dcbe67d21d5eb39493d46d89ae1f412d3bd6de") ++ ++ @skip_libssl_fips_mode ++ def test_sha256_algorithm(self): ++ H, KD = self.handler.get_algorithm_impls('SHA-256') ++ self.assertEqual(H("foo"), "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae") ++ self.assertEqual(KD("foo", "bar"), "a765a8beaa9d561d4c5cbed29d8f4e30870297fdfa9cb7d6e9848a95fec9f937") ++ ++ def test_invalid_algorithm(self): + with self.assertRaises(ValueError) as exc: +- handler.get_algorithm_impls('invalid') ++ self.handler.get_algorithm_impls('invalid') + self.assertEqual( + str(exc.exception), + "Unsupported digest authentication algorithm 'invalid'" +diff --git a/Lib/test/test_urllib2_localnet.py b/Lib/test/test_urllib2_localnet.py +index 50c491a3cfd..9cb15d61c2a 100644 +--- a/Lib/test/test_urllib2_localnet.py ++++ b/Lib/test/test_urllib2_localnet.py +@@ -316,7 +316,9 @@ + ah = urllib.request.HTTPBasicAuthHandler() + ah.add_password(self.REALM, self.server_url, self.USER, self.INCORRECT_PASSWD) + urllib.request.install_opener(urllib.request.build_opener(ah)) +- self.assertRaises(urllib.error.HTTPError, urllib.request.urlopen, self.server_url) ++ with self.assertRaises(urllib.error.HTTPError) as cm: ++ urllib.request.urlopen(self.server_url) ++ cm.exception.close() + + + @hashlib_helper.requires_hashdigest("md5", openssl=True) +@@ -362,15 +364,15 @@ + self.proxy_digest_handler.add_password(self.REALM, self.URL, + self.USER, self.PASSWD+"bad") + self.digest_auth_handler.set_qop("auth") +- self.assertRaises(urllib.error.HTTPError, +- self.opener.open, +- self.URL) ++ with self.assertRaises(urllib.error.HTTPError) as cm: ++ self.opener.open(self.URL) ++ cm.exception.close() + + def test_proxy_with_no_password_raises_httperror(self): + self.digest_auth_handler.set_qop("auth") +- self.assertRaises(urllib.error.HTTPError, +- self.opener.open, +- self.URL) ++ with self.assertRaises(urllib.error.HTTPError) as cm: ++ self.opener.open(self.URL) ++ cm.exception.close() + + def test_proxy_qop_auth_works(self): + self.proxy_digest_handler.add_password(self.REALM, self.URL, +diff --git a/Lib/test/test_urllib_response.py b/Lib/test/test_urllib_response.py +index b76763f4ed8..d949fa38bfc 100644 +--- a/Lib/test/test_urllib_response.py ++++ b/Lib/test/test_urllib_response.py +@@ -48,6 +48,7 @@ + info = urllib.response.addinfo(self.fp, self.test_headers) + self.assertEqual(info.info(), self.test_headers) + self.assertEqual(info.headers, self.test_headers) ++ info.close() + + def test_addinfourl(self): + url = "http://www.python.org" +@@ -60,6 +61,7 @@ + self.assertEqual(infourl.headers, self.test_headers) + self.assertEqual(infourl.url, url) + self.assertEqual(infourl.status, code) ++ infourl.close() + + def tearDown(self): + self.sock.close() +diff --git a/Lib/test/test_urllibnet.py b/Lib/test/test_urllibnet.py +index f824dddf711..ce4e60e3a80 100644 +--- a/Lib/test/test_urllibnet.py ++++ b/Lib/test/test_urllibnet.py +@@ -106,6 +106,7 @@ + with urllib.request.urlopen(URL): + pass + self.assertEqual(e.exception.code, 404) ++ e.exception.close() + + @support.requires_resource('walltime') + def test_bad_address(self): +diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py +index 4516bdea6ad..b51cc006b73 100644 +--- a/Lib/test/test_urlparse.py ++++ b/Lib/test/test_urlparse.py +@@ -1412,16 +1412,51 @@ + self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[0439:23af::2309::fae7:1234]/Path?Query') + self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[0439:23af:2309::fae7:1234:2342:438e:192.0.2.146]/Path?Query') + self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@]v6a.ip[/Path') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[v6a.ip]') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[v6a.ip].suffix') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[v6a.ip]/') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[v6a.ip].suffix/') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[v6a.ip]?') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[v6a.ip].suffix?') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]/') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix/') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]?') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix?') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]:a') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix:a') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]:a1') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix:a1') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]:1a') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix:1a') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]:') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix:/') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]:?') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://user@prefix.[v6a.ip]') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://user@[v6a.ip].suffix') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[v6a.ip') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://v6a.ip]') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://]v6a.ip[') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://]v6a.ip') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://v6a.ip[') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[v6a.ip') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://v6a.ip].suffix') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix]v6a.ip[suffix') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix]v6a.ip') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://v6a.ip[suffix') + + def test_splitting_bracketed_hosts(self): +- p1 = urllib.parse.urlsplit('scheme://user@[v6a.ip]/path?query') ++ p1 = urllib.parse.urlsplit('scheme://user@[v6a.ip]:1234/path?query') + self.assertEqual(p1.hostname, 'v6a.ip') + self.assertEqual(p1.username, 'user') + self.assertEqual(p1.path, '/path') ++ self.assertEqual(p1.port, 1234) + p2 = urllib.parse.urlsplit('scheme://user@[0439:23af:2309::fae7%test]/path?query') + self.assertEqual(p2.hostname, '0439:23af:2309::fae7%test') + self.assertEqual(p2.username, 'user') + self.assertEqual(p2.path, '/path') ++ self.assertIs(p2.port, None) + p3 = urllib.parse.urlsplit('scheme://user@[0439:23af:2309::fae7:1234:192.0.2.146%test]/path?query') + self.assertEqual(p3.hostname, '0439:23af:2309::fae7:1234:192.0.2.146%test') + self.assertEqual(p3.username, 'user') +diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py +index 7bd26a8ca34..8216c4dd00e 100755 +--- a/Lib/test/test_uuid.py ++++ b/Lib/test/test_uuid.py +@@ -21,7 +21,7 @@ + try: + __import__(name) + return True +- except: ++ except ModuleNotFoundError: + return False + + +@@ -34,6 +34,47 @@ + class BaseTestUUID: + uuid = None + ++ def test_nil_uuid(self): ++ nil_uuid = self.uuid.NIL ++ ++ s = '00000000-0000-0000-0000-000000000000' ++ i = 0 ++ self.assertEqual(nil_uuid, self.uuid.UUID(s)) ++ self.assertEqual(nil_uuid, self.uuid.UUID(int=i)) ++ self.assertEqual(nil_uuid.int, i) ++ self.assertEqual(str(nil_uuid), s) ++ # The Nil UUID falls within the range of the Apollo NCS variant as per ++ # RFC 9562. ++ # See https://www.rfc-editor.org/rfc/rfc9562.html#section-5.9-4 ++ self.assertEqual(nil_uuid.variant, self.uuid.RESERVED_NCS) ++ # A version field of all zeros is "Unused" in RFC 9562, but the version ++ # field also only applies to the 10xx variant, i.e. the variant ++ # specified in RFC 9562. As such, because the Nil UUID falls under a ++ # different variant, its version is considered undefined. ++ # See https://www.rfc-editor.org/rfc/rfc9562.html#table2 ++ self.assertIsNone(nil_uuid.version) ++ ++ def test_max_uuid(self): ++ max_uuid = self.uuid.MAX ++ ++ s = 'ffffffff-ffff-ffff-ffff-ffffffffffff' ++ i = (1 << 128) - 1 ++ self.assertEqual(max_uuid, self.uuid.UUID(s)) ++ self.assertEqual(max_uuid, self.uuid.UUID(int=i)) ++ self.assertEqual(max_uuid.int, i) ++ self.assertEqual(str(max_uuid), s) ++ # The Max UUID falls within the range of the "yet-to-be defined" future ++ # UUID variant as per RFC 9562. ++ # See https://www.rfc-editor.org/rfc/rfc9562.html#section-5.10-4 ++ self.assertEqual(max_uuid.variant, self.uuid.RESERVED_FUTURE) ++ # A version field of all ones is "Reserved for future definition" in ++ # RFC 9562, but the version field also only applies to the 10xx ++ # variant, i.e. the variant specified in RFC 9562. As such, because the ++ # Max UUID falls under a different variant, its version is considered ++ # undefined. ++ # See https://www.rfc-editor.org/rfc/rfc9562.html#table2 ++ self.assertIsNone(max_uuid.version) ++ + def test_safe_uuid_enum(self): + class CheckedSafeUUID(enum.Enum): + safe = 0 +@@ -707,12 +748,16 @@ + equal(u.int & 0x3fffffffffffffff, lo) + + def test_uuid8_uniqueness(self): +- # Test that UUIDv8-generated values are unique +- # (up to a negligible probability of failure). +- u1 = self.uuid.uuid8() +- u2 = self.uuid.uuid8() +- self.assertNotEqual(u1.int, u2.int) +- self.assertEqual(u1.version, u2.version) ++ # Test that UUIDv8-generated values are unique (up to a negligible ++ # probability of failure). There are 122 bits of entropy and assuming ++ # that the underlying mt-19937-based random generator is sufficiently ++ # good, it is unlikely to have a collision of two UUIDs. ++ N = 1000 ++ uuids = {self.uuid.uuid8() for _ in range(N)} ++ self.assertEqual(len(uuids), N) ++ ++ versions = {u.version for u in uuids} ++ self.assertSetEqual(versions, {8}) + + @support.requires_fork() + def testIssue8621(self): +diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py +index 0b09010c69d..6e23097deaf 100644 +--- a/Lib/test/test_venv.py ++++ b/Lib/test/test_venv.py +@@ -111,10 +111,6 @@ + result = f.read() + return result + +- def assertEndsWith(self, string, tail): +- if not string.endswith(tail): +- self.fail(f"String {string!r} does not end with {tail!r}") +- + class BasicTest(BaseTest): + """Test venv module functionality.""" + +diff --git a/Lib/test/test_warnings/__init__.py b/Lib/test/test_warnings/__init__.py +index 4e3c877896f..6f4c569d247 100644 +--- a/Lib/test/test_warnings/__init__.py ++++ b/Lib/test/test_warnings/__init__.py +@@ -1432,6 +1432,17 @@ + module = py_warnings + + ++class LocksTest(unittest.TestCase): ++ @support.cpython_only ++ @unittest.skipUnless(c_warnings, 'C module is required') ++ def test_release_lock_no_lock(self): ++ with self.assertRaisesRegex( ++ RuntimeError, ++ 'cannot release un-acquired lock', ++ ): ++ c_warnings._release_lock() ++ ++ + class _DeprecatedTest(BaseTest, unittest.TestCase): + + """Test _deprecated().""" +@@ -1521,7 +1532,7 @@ + self.assertTrue(err.startswith(expected), ascii(err)) + + +-class DeprecatedTests(unittest.TestCase): ++class DeprecatedTests(PyPublicAPITests): + def test_dunder_deprecated(self): + @deprecated("A will go away soon") + class A: +--- /dev/null ++++ b/Lib/test/test_xml_dom_xmlbuilder.py +@@ -0,0 +1,88 @@ ++import io ++import unittest ++from http import client ++from test.test_httplib import FakeSocket ++from unittest import mock ++from xml.dom import getDOMImplementation, minidom, xmlbuilder ++ ++SMALL_SAMPLE = b""" ++ ++ ++Introduction to XSL ++
++

A. Namespace

++""" ++ ++ ++class XMLBuilderTest(unittest.TestCase): ++ def test_entity_resolver(self): ++ body = ( ++ b"HTTP/1.1 200 OK\r\nContent-Type: text/xml; charset=utf-8\r\n\r\n" ++ + SMALL_SAMPLE ++ ) ++ ++ sock = FakeSocket(body) ++ response = client.HTTPResponse(sock) ++ response.begin() ++ attrs = {"open.return_value": response} ++ opener = mock.Mock(**attrs) ++ ++ resolver = xmlbuilder.DOMEntityResolver() ++ ++ with mock.patch("urllib.request.build_opener") as mock_build: ++ mock_build.return_value = opener ++ source = resolver.resolveEntity(None, "http://example.com/2000/svg") ++ ++ self.assertIsInstance(source, xmlbuilder.DOMInputSource) ++ self.assertIsNone(source.publicId) ++ self.assertEqual(source.systemId, "http://example.com/2000/svg") ++ self.assertEqual(source.baseURI, "http://example.com/2000/") ++ self.assertEqual(source.encoding, "utf-8") ++ self.assertIs(source.byteStream, response) ++ ++ self.assertIsNone(source.characterStream) ++ self.assertIsNone(source.stringData) ++ ++ def test_builder(self): ++ imp = getDOMImplementation() ++ self.assertIsInstance(imp, xmlbuilder.DOMImplementationLS) ++ ++ builder = imp.createDOMBuilder(imp.MODE_SYNCHRONOUS, None) ++ self.assertIsInstance(builder, xmlbuilder.DOMBuilder) ++ ++ def test_parse_uri(self): ++ body = ( ++ b"HTTP/1.1 200 OK\r\nContent-Type: text/xml; charset=utf-8\r\n\r\n" ++ + SMALL_SAMPLE ++ ) ++ ++ sock = FakeSocket(body) ++ response = client.HTTPResponse(sock) ++ response.begin() ++ attrs = {"open.return_value": response} ++ opener = mock.Mock(**attrs) ++ ++ with mock.patch("urllib.request.build_opener") as mock_build: ++ mock_build.return_value = opener ++ ++ imp = getDOMImplementation() ++ builder = imp.createDOMBuilder(imp.MODE_SYNCHRONOUS, None) ++ document = builder.parseURI("http://example.com/2000/svg") ++ ++ self.assertIsInstance(document, minidom.Document) ++ self.assertEqual(len(document.childNodes), 1) ++ ++ def test_parse_with_systemId(self): ++ response = io.BytesIO(SMALL_SAMPLE) ++ ++ with mock.patch("urllib.request.urlopen") as mock_open: ++ mock_open.return_value = response ++ ++ imp = getDOMImplementation() ++ source = imp.createDOMInputSource() ++ builder = imp.createDOMBuilder(imp.MODE_SYNCHRONOUS, None) ++ source.systemId = "http://example.com/2000/svg" ++ document = builder.parse(source) ++ ++ self.assertIsInstance(document, minidom.Document) ++ self.assertEqual(len(document.childNodes), 1) +diff --git a/Lib/test/test_zipfile/_path/test_path.py b/Lib/test/test_zipfile/_path/test_path.py +index aba515536f0..1ee45f5fc57 100644 +--- a/Lib/test/test_zipfile/_path/test_path.py ++++ b/Lib/test/test_zipfile/_path/test_path.py +@@ -634,7 +634,7 @@ + """ + data = io.BytesIO() + zf = zipfile.ZipFile(data, "w") +- zf.writestr(DirtyZipInfo.for_name("foo\\bar", zf), b"content") ++ zf.writestr(DirtyZipInfo("foo\\bar")._for_archive(zf), b"content") + zf.filename = '' + root = zipfile.Path(zf) + (first,) = root.iterdir() +@@ -657,20 +657,3 @@ + def __init__(self, filename, *args, **kwargs): + super().__init__(filename, *args, **kwargs) + self.filename = filename +- +- @classmethod +- def for_name(cls, name, archive): +- """ +- Construct the same way that ZipFile.writestr does. +- +- TODO: extract this functionality and re-use +- """ +- self = cls(filename=name, date_time=time.localtime(time.time())[:6]) +- self.compress_type = archive.compression +- self.compress_level = archive.compresslevel +- if self.filename.endswith('/'): # pragma: no cover +- self.external_attr = 0o40775 << 16 # drwxrwxr-x +- self.external_attr |= 0x10 # MS-DOS directory flag +- else: +- self.external_attr = 0o600 << 16 # ?rw------- +- return self +diff --git a/Lib/test/test_zipfile/test_core.py b/Lib/test/test_zipfile/test_core.py +index c36228c033a..6b1fe56074d 100644 +--- a/Lib/test/test_zipfile/test_core.py ++++ b/Lib/test/test_zipfile/test_core.py +@@ -1,3 +1,4 @@ ++import _pyio + import array + import contextlib + import importlib.util +@@ -5,6 +6,7 @@ + import itertools + import os + import posixpath ++import stat + import struct + import subprocess + import sys +@@ -18,10 +20,11 @@ + from random import randint, random, randbytes + + from test import archiver_tests +-from test.support import script_helper ++from test.support import script_helper, os_helper + from test.support import ( + findfile, requires_zlib, requires_bz2, requires_lzma, +- captured_stdout, captured_stderr, requires_subprocess ++ captured_stdout, captured_stderr, requires_subprocess, ++ is_emscripten + ) + from test.support.os_helper import ( + TESTFN, unlink, rmtree, temp_dir, temp_cwd, fd_count, FakePath +@@ -1780,6 +1783,35 @@ + zinfo.flag_bits |= zipfile._MASK_USE_DATA_DESCRIPTOR # Include an extended local header. + orig_zip.writestr(zinfo, data) + ++ def test_write_with_source_date_epoch(self): ++ with os_helper.EnvironmentVarGuard() as env: ++ # Set the SOURCE_DATE_EPOCH environment variable to a specific timestamp ++ env['SOURCE_DATE_EPOCH'] = "1735715999" ++ ++ with zipfile.ZipFile(TESTFN, "w") as zf: ++ zf.writestr("test_source_date_epoch.txt", "Testing SOURCE_DATE_EPOCH") ++ ++ with zipfile.ZipFile(TESTFN, "r") as zf: ++ zip_info = zf.getinfo("test_source_date_epoch.txt") ++ get_time = time.localtime(int(os.environ['SOURCE_DATE_EPOCH']))[:6] ++ # Compare each element of the date_time tuple ++ # Allow for a 1-second difference ++ for z_time, g_time in zip(zip_info.date_time, get_time): ++ self.assertAlmostEqual(z_time, g_time, delta=1) ++ ++ def test_write_without_source_date_epoch(self): ++ with os_helper.EnvironmentVarGuard() as env: ++ del env['SOURCE_DATE_EPOCH'] ++ ++ with zipfile.ZipFile(TESTFN, "w") as zf: ++ zf.writestr("test_no_source_date_epoch.txt", "Testing without SOURCE_DATE_EPOCH") ++ ++ with zipfile.ZipFile(TESTFN, "r") as zf: ++ zip_info = zf.getinfo("test_no_source_date_epoch.txt") ++ current_time = time.localtime()[:6] ++ for z_time, c_time in zip(zip_info.date_time, current_time): ++ self.assertAlmostEqual(z_time, c_time, delta=1) ++ + def test_close(self): + """Check that the zipfile is closed after the 'with' block.""" + with zipfile.ZipFile(TESTFN2, "w") as zipfp: +@@ -2211,6 +2243,34 @@ + zi = zipfile.ZipInfo(filename="empty") + self.assertEqual(repr(zi), "") + ++ def test_for_archive(self): ++ base_filename = TESTFN2.rstrip('/') ++ ++ with zipfile.ZipFile(TESTFN, mode="w", compresslevel=1, ++ compression=zipfile.ZIP_STORED) as zf: ++ # no trailing forward slash ++ zi = zipfile.ZipInfo(base_filename)._for_archive(zf) ++ self.assertEqual(zi.compress_level, 1) ++ self.assertEqual(zi.compress_type, zipfile.ZIP_STORED) ++ # ?rw- --- --- ++ filemode = stat.S_IRUSR | stat.S_IWUSR ++ # filemode is stored as the highest 16 bits of external_attr ++ self.assertEqual(zi.external_attr >> 16, filemode) ++ self.assertEqual(zi.external_attr & 0xFF, 0) # no MS-DOS flag ++ ++ with zipfile.ZipFile(TESTFN, mode="w", compresslevel=1, ++ compression=zipfile.ZIP_STORED) as zf: ++ # with a trailing slash ++ zi = zipfile.ZipInfo(f'{base_filename}/')._for_archive(zf) ++ self.assertEqual(zi.compress_level, 1) ++ self.assertEqual(zi.compress_type, zipfile.ZIP_STORED) ++ # d rwx rwx r-x ++ filemode = stat.S_IFDIR ++ filemode |= stat.S_IRWXU | stat.S_IRWXG ++ filemode |= stat.S_IROTH | stat.S_IXOTH ++ self.assertEqual(zi.external_attr >> 16, filemode) ++ self.assertEqual(zi.external_attr & 0xFF, 0x10) # MS-DOS flag ++ + def test_create_empty_zipinfo_default_attributes(self): + """Ensure all required attributes are set.""" + zi = zipfile.ZipInfo() +@@ -2333,6 +2393,18 @@ + fp.seek(1, os.SEEK_CUR) + self.assertEqual(fp.read(-1), b'men!') + ++ def test_uncompressed_interleaved_seek_read(self): ++ # gh-127847: Make sure the position in the archive is correct ++ # in the special case of seeking in a ZIP_STORED entry. ++ with zipfile.ZipFile(TESTFN, "w") as zipf: ++ zipf.writestr("a.txt", "123") ++ zipf.writestr("b.txt", "456") ++ with zipfile.ZipFile(TESTFN, "r") as zipf: ++ with zipf.open("a.txt", "r") as a, zipf.open("b.txt", "r") as b: ++ self.assertEqual(a.read(1), b"1") ++ self.assertEqual(b.seek(1), 1) ++ self.assertEqual(b.read(1), b"5") ++ + @requires_bz2() + def test_decompress_without_3rd_party_library(self): + data = b'PK\x05\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' +@@ -3448,5 +3520,87 @@ + b"zzz", zipfile._Extra.strip(b"zzz", (self.ZIP64_EXTRA,))) + + ++class StatIO(_pyio.BytesIO): ++ """Buffer which remembers the number of bytes that were read.""" ++ ++ def __init__(self): ++ super().__init__() ++ self.bytes_read = 0 ++ ++ def read(self, size=-1): ++ bs = super().read(size) ++ self.bytes_read += len(bs) ++ return bs ++ ++ ++class StoredZipExtFileRandomReadTest(unittest.TestCase): ++ """Tests whether an uncompressed, unencrypted zip entry can be randomly ++ seek and read without reading redundant bytes.""" ++ def test_stored_seek_and_read(self): ++ ++ sio = StatIO() ++ # 20000 bytes ++ txt = b'0123456789' * 2000 ++ ++ # The seek length must be greater than ZipExtFile.MIN_READ_SIZE ++ # as `ZipExtFile._read2()` reads in blocks of this size and we ++ # need to seek out of the buffered data ++ read_buffer_size = zipfile.ZipExtFile.MIN_READ_SIZE ++ self.assertGreaterEqual(10002, read_buffer_size) # for forward seek test ++ self.assertGreaterEqual(5003, read_buffer_size) # for backward seek test ++ # The read length must be less than MIN_READ_SIZE, since we assume that ++ # only 1 block is read in the test. ++ read_length = 100 ++ self.assertGreaterEqual(read_buffer_size, read_length) # for read() calls ++ ++ with zipfile.ZipFile(sio, "w", compression=zipfile.ZIP_STORED) as zipf: ++ zipf.writestr("foo.txt", txt) ++ ++ # check random seek and read on a file ++ with zipfile.ZipFile(sio, "r") as zipf: ++ with zipf.open("foo.txt", "r") as fp: ++ # Test this optimized read hasn't rewound and read from the ++ # start of the file (as in the case of the unoptimized path) ++ ++ # forward seek ++ old_count = sio.bytes_read ++ forward_seek_len = 10002 ++ current_pos = 0 ++ fp.seek(forward_seek_len, os.SEEK_CUR) ++ current_pos += forward_seek_len ++ self.assertEqual(fp.tell(), current_pos) ++ self.assertEqual(fp._left, fp._compress_left) ++ arr = fp.read(read_length) ++ current_pos += read_length ++ self.assertEqual(fp.tell(), current_pos) ++ self.assertEqual(arr, txt[current_pos - read_length:current_pos]) ++ self.assertEqual(fp._left, fp._compress_left) ++ read_count = sio.bytes_read - old_count ++ self.assertLessEqual(read_count, read_buffer_size) ++ ++ # backward seek ++ old_count = sio.bytes_read ++ backward_seek_len = 5003 ++ fp.seek(-backward_seek_len, os.SEEK_CUR) ++ current_pos -= backward_seek_len ++ self.assertEqual(fp.tell(), current_pos) ++ self.assertEqual(fp._left, fp._compress_left) ++ arr = fp.read(read_length) ++ current_pos += read_length ++ self.assertEqual(fp.tell(), current_pos) ++ self.assertEqual(arr, txt[current_pos - read_length:current_pos]) ++ self.assertEqual(fp._left, fp._compress_left) ++ read_count = sio.bytes_read - old_count ++ self.assertLessEqual(read_count, read_buffer_size) ++ ++ # eof flags test ++ fp.seek(0, os.SEEK_END) ++ fp.seek(12345, os.SEEK_SET) ++ current_pos = 12345 ++ arr = fp.read(read_length) ++ current_pos += read_length ++ self.assertEqual(arr, txt[current_pos - read_length:current_pos]) ++ ++ + if __name__ == "__main__": + unittest.main() +diff --git a/Lib/threading.py b/Lib/threading.py +index 78e59112427..da9cdf0b09d 100644 +--- a/Lib/threading.py ++++ b/Lib/threading.py +@@ -3,7 +3,6 @@ + import os as _os + import sys as _sys + import _thread +-import warnings + + from time import monotonic as _time + from _weakrefset import WeakSet +@@ -133,6 +132,7 @@ + + """ + if args or kwargs: ++ import warnings + warnings.warn( + 'Passing arguments to RLock is deprecated and will be removed in 3.15', + DeprecationWarning, +@@ -694,7 +694,7 @@ + + """ + if parties < 1: +- raise ValueError("parties must be > 0") ++ raise ValueError("parties must be >= 1") + self._cond = Condition(Lock()) + self._action = action + self._timeout = timeout +diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py +index bfec04bb6c1..0baed8b569e 100644 +--- a/Lib/tkinter/__init__.py ++++ b/Lib/tkinter/__init__.py +@@ -2265,7 +2265,7 @@ + explicitly. DEFAULT can be the relative path to a .ico file + (example: root.iconbitmap(default='myicon.ico') ). See Tk + documentation for more information.""" +- if default: ++ if default is not None: + return self.tk.call('wm', 'iconbitmap', self._w, '-default', default) + else: + return self.tk.call('wm', 'iconbitmap', self._w, bitmap) +@@ -2741,6 +2741,8 @@ + del cnf['name'] + if not name: + name = self.__class__.__name__.lower() ++ if name[-1].isdigit(): ++ name += "!" # Avoid duplication when calculating names below + if master._last_child_ids is None: + master._last_child_ids = {} + count = master._last_child_ids.get(name, 0) + 1 +diff --git a/Lib/tokenize.py b/Lib/tokenize.py +index 7ece4e9b70d..9ce95a62d96 100644 +--- a/Lib/tokenize.py ++++ b/Lib/tokenize.py +@@ -169,6 +169,7 @@ + self.prev_row = 1 + self.prev_col = 0 + self.prev_type = None ++ self.prev_line = "" + self.encoding = None + + def add_whitespace(self, start): +@@ -176,14 +177,28 @@ + if row < self.prev_row or row == self.prev_row and col < self.prev_col: + raise ValueError("start ({},{}) precedes previous end ({},{})" + .format(row, col, self.prev_row, self.prev_col)) +- row_offset = row - self.prev_row +- if row_offset: +- self.tokens.append("\\\n" * row_offset) +- self.prev_col = 0 ++ self.add_backslash_continuation(start) + col_offset = col - self.prev_col + if col_offset: + self.tokens.append(" " * col_offset) + ++ def add_backslash_continuation(self, start): ++ """Add backslash continuation characters if the row has increased ++ without encountering a newline token. ++ ++ This also inserts the correct amount of whitespace before the backslash. ++ """ ++ row = start[0] ++ row_offset = row - self.prev_row ++ if row_offset == 0: ++ return ++ ++ newline = '\r\n' if self.prev_line.endswith('\r\n') else '\n' ++ line = self.prev_line.rstrip('\\\r\n') ++ ws = ''.join(_itertools.takewhile(str.isspace, reversed(line))) ++ self.tokens.append(ws + f"\\{newline}" * row_offset) ++ self.prev_col = 0 ++ + def escape_brackets(self, token): + characters = [] + consume_until_next_bracket = False +@@ -243,8 +258,6 @@ + end_line, end_col = end + extra_chars = last_line.count("{{") + last_line.count("}}") + end = (end_line, end_col + extra_chars) +- elif tok_type in (STRING, FSTRING_START) and self.prev_type in (STRING, FSTRING_END): +- self.tokens.append(" ") + + self.add_whitespace(start) + self.tokens.append(token) +@@ -253,6 +266,7 @@ + self.prev_row += 1 + self.prev_col = 0 + self.prev_type = tok_type ++ self.prev_line = line + return "".join(self.tokens) + + def compat(self, token, iterable): +@@ -318,16 +332,10 @@ + with at least two elements, a token number and token value. If + only two tokens are passed, the resulting output is poor. + +- Round-trip invariant for full input: +- Untokenized source will match input source exactly +- +- Round-trip invariant for limited input: +- # Output bytes will tokenize back to the input +- t1 = [tok[:2] for tok in tokenize(f.readline)] +- newcode = untokenize(t1) +- readline = BytesIO(newcode).readline +- t2 = [tok[:2] for tok in tokenize(readline)] +- assert t1 == t2 ++ The result is guaranteed to tokenize back to match the input so ++ that the conversion is lossless and round-trips are assured. ++ The guarantee applies only to the token type and token string as ++ the spacing between tokens (column positions) may change. + """ + ut = Untokenizer() + out = ut.untokenize(iterable) +diff --git a/Lib/tomllib/_parser.py b/Lib/tomllib/_parser.py +index 4d208bcfb4a..0e522c3a69e 100644 +--- a/Lib/tomllib/_parser.py ++++ b/Lib/tomllib/_parser.py +@@ -4,11 +4,7 @@ + + from __future__ import annotations + +-from collections.abc import Iterable +-import string + from types import MappingProxyType +-from typing import Any, BinaryIO, NamedTuple +-import warnings + + from ._re import ( + RE_DATETIME, +@@ -18,7 +14,13 @@ + match_to_localtime, + match_to_number, + ) +-from ._types import Key, ParseFloat, Pos ++ ++TYPE_CHECKING = False ++if TYPE_CHECKING: ++ from collections.abc import Iterable ++ from typing import IO, Any ++ ++ from ._types import Key, ParseFloat, Pos + + ASCII_CTRL = frozenset(chr(i) for i in range(32)) | frozenset(chr(127)) + +@@ -34,9 +36,11 @@ + + TOML_WS = frozenset(" \t") + TOML_WS_AND_NEWLINE = TOML_WS | frozenset("\n") +-BARE_KEY_CHARS = frozenset(string.ascii_letters + string.digits + "-_") ++BARE_KEY_CHARS = frozenset( ++ "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789" "-_" ++) + KEY_INITIAL_CHARS = BARE_KEY_CHARS | frozenset("\"'") +-HEXDIGIT_CHARS = frozenset(string.hexdigits) ++HEXDIGIT_CHARS = frozenset("abcdef" "ABCDEF" "0123456789") + + BASIC_STR_ESCAPE_REPLACEMENTS = MappingProxyType( + { +@@ -80,6 +84,8 @@ + or not isinstance(doc, str) + or not isinstance(pos, int) + ): ++ import warnings ++ + warnings.warn( + "Free-form arguments for TOMLDecodeError are deprecated. " + "Please set 'msg' (str), 'doc' (str) and 'pos' (int) arguments only.", +@@ -115,7 +121,7 @@ + self.colno = colno + + +-def load(fp: BinaryIO, /, *, parse_float: ParseFloat = float) -> dict[str, Any]: ++def load(fp: IO[bytes], /, *, parse_float: ParseFloat = float) -> dict[str, Any]: + """Parse TOML from a binary file object.""" + b = fp.read() + try: +@@ -139,7 +145,7 @@ + f"Expected str object, not '{type(s).__qualname__}'" + ) from None + pos = 0 +- out = Output(NestedDict(), Flags()) ++ out = Output() + header: Key = () + parse_float = make_safe_parse_float(parse_float) + +@@ -290,9 +296,10 @@ + cont[last_key] = [{}] + + +-class Output(NamedTuple): +- data: NestedDict +- flags: Flags ++class Output: ++ def __init__(self) -> None: ++ self.data = NestedDict() ++ self.flags = Flags() + + + def skip_chars(src: str, pos: Pos, chars: Iterable[str]) -> Pos: +diff --git a/Lib/tomllib/_re.py b/Lib/tomllib/_re.py +index 9eacefc7295..1ca6bef77a0 100644 +--- a/Lib/tomllib/_re.py ++++ b/Lib/tomllib/_re.py +@@ -7,9 +7,12 @@ + from datetime import date, datetime, time, timedelta, timezone, tzinfo + from functools import lru_cache + import re +-from typing import Any + +-from ._types import ParseFloat ++TYPE_CHECKING = False ++if TYPE_CHECKING: ++ from typing import Any ++ ++ from ._types import ParseFloat + + # E.g. + # - 00:32:00.999999 +diff --git a/Lib/traceback.py b/Lib/traceback.py +index 6367c00e4d4..31c73efcef5 100644 +--- a/Lib/traceback.py ++++ b/Lib/traceback.py +@@ -135,7 +135,7 @@ + + def _print_exception_bltin(exc, /): + file = sys.stderr if sys.stderr is not None else sys.__stderr__ +- colorize = _colorize.can_colorize() ++ colorize = _colorize.can_colorize(file=file) + return print_exception(exc, limit=BUILTIN_EXCEPTION_LIMIT, file=file, colorize=colorize) + + +@@ -1283,7 +1283,7 @@ + filename_suffix = ' ({})'.format(self.filename) + + text = self.text +- if text is not None: ++ if isinstance(text, str): + # text = " foo\n" + # rtext = " foo" + # ltext = "foo" +@@ -1292,10 +1292,17 @@ + spaces = len(rtext) - len(ltext) + if self.offset is None: + yield ' {}\n'.format(ltext) +- else: ++ elif isinstance(self.offset, int): + offset = self.offset + if self.lineno == self.end_lineno: +- end_offset = self.end_offset if self.end_offset not in {None, 0} else offset ++ end_offset = ( ++ self.end_offset ++ if ( ++ isinstance(self.end_offset, int) ++ and self.end_offset != 0 ++ ) ++ else offset ++ ) + else: + end_offset = len(rtext) + 1 + +diff --git a/Lib/turtle.py b/Lib/turtle.py +index 8a5801f2efe..e88981d298a 100644 +--- a/Lib/turtle.py ++++ b/Lib/turtle.py +@@ -51,7 +51,7 @@ + turtle. So the turtles can more easily be used as a visual feedback + instrument by the (beginning) programmer. + +-- Different turtle shapes, gif-images as turtle shapes, user defined ++- Different turtle shapes, image files as turtle shapes, user defined + and user controllable turtle shapes, among them compound + (multicolored) shapes. Turtle shapes can be stretched and tilted, which + makes turtles very versatile geometrical objects. +@@ -107,6 +107,7 @@ + + from os.path import isfile, split, join + from pathlib import Path ++from contextlib import contextmanager + from copy import deepcopy + from tkinter import simpledialog + +@@ -114,23 +115,24 @@ + 'RawTurtle', 'Turtle', 'RawPen', 'Pen', 'Shape', 'Vec2D'] + _tg_screen_functions = ['addshape', 'bgcolor', 'bgpic', 'bye', + 'clearscreen', 'colormode', 'delay', 'exitonclick', 'getcanvas', +- 'getshapes', 'listen', 'mainloop', 'mode', 'numinput', ++ 'getshapes', 'listen', 'mainloop', 'mode', 'no_animation', 'numinput', + 'onkey', 'onkeypress', 'onkeyrelease', 'onscreenclick', 'ontimer', + 'register_shape', 'resetscreen', 'screensize', 'save', 'setup', +- 'setworldcoordinates', 'textinput', 'title', 'tracer', 'turtles', 'update', +- 'window_height', 'window_width'] ++ 'setworldcoordinates', 'textinput', 'title', 'tracer', 'turtles', ++ 'update', 'window_height', 'window_width'] + _tg_turtle_functions = ['back', 'backward', 'begin_fill', 'begin_poly', 'bk', + 'circle', 'clear', 'clearstamp', 'clearstamps', 'clone', 'color', + 'degrees', 'distance', 'dot', 'down', 'end_fill', 'end_poly', 'fd', +- 'fillcolor', 'filling', 'forward', 'get_poly', 'getpen', 'getscreen', 'get_shapepoly', +- 'getturtle', 'goto', 'heading', 'hideturtle', 'home', 'ht', 'isdown', +- 'isvisible', 'left', 'lt', 'onclick', 'ondrag', 'onrelease', 'pd', +- 'pen', 'pencolor', 'pendown', 'pensize', 'penup', 'pos', 'position', +- 'pu', 'radians', 'right', 'reset', 'resizemode', 'rt', +- 'seth', 'setheading', 'setpos', 'setposition', +- 'setundobuffer', 'setx', 'sety', 'shape', 'shapesize', 'shapetransform', 'shearfactor', 'showturtle', +- 'speed', 'st', 'stamp', 'teleport', 'tilt', 'tiltangle', 'towards', +- 'turtlesize', 'undo', 'undobufferentries', 'up', 'width', ++ 'fillcolor', 'fill', 'filling', 'forward', 'get_poly', 'getpen', ++ 'getscreen', 'get_shapepoly', 'getturtle', 'goto', 'heading', ++ 'hideturtle', 'home', 'ht', 'isdown', 'isvisible', 'left', 'lt', ++ 'onclick', 'ondrag', 'onrelease', 'pd', 'pen', 'pencolor', 'pendown', ++ 'pensize', 'penup', 'poly', 'pos', 'position', 'pu', 'radians', 'right', ++ 'reset', 'resizemode', 'rt', 'seth', 'setheading', 'setpos', ++ 'setposition', 'setundobuffer', 'setx', 'sety', 'shape', 'shapesize', ++ 'shapetransform', 'shearfactor', 'showturtle', 'speed', 'st', 'stamp', ++ 'teleport', 'tilt', 'tiltangle', 'towards', 'turtlesize', 'undo', ++ 'undobufferentries', 'up', 'width', + 'write', 'xcor', 'ycor'] + _tg_utilities = ['write_docstringdict', 'done'] + +@@ -468,7 +470,7 @@ + + def _image(self, filename): + """return an image object containing the +- imagedata from a gif-file named filename. ++ imagedata from an image file named filename. + """ + return TK.PhotoImage(file=filename, master=self.cv) + +@@ -872,10 +874,7 @@ + if isinstance(data, list): + data = tuple(data) + elif type_ == "image": +- if isinstance(data, str): +- if data.lower().endswith(".gif") and isfile(data): +- data = TurtleScreen._image(data) +- # else data assumed to be PhotoImage ++ assert(isinstance(data, TK.PhotoImage)) + elif type_ == "compound": + data = [] + else: +@@ -1100,14 +1099,18 @@ + """Adds a turtle shape to TurtleScreen's shapelist. + + Arguments: +- (1) name is the name of a gif-file and shape is None. ++ (1) name is the name of an image file (PNG, GIF, PGM, and PPM) and shape is None. + Installs the corresponding image shape. + !! Image-shapes DO NOT rotate when turning the turtle, + !! so they do not display the heading of the turtle! +- (2) name is an arbitrary string and shape is a tuple ++ (2) name is an arbitrary string and shape is the name of an image file (PNG, GIF, PGM, and PPM). ++ Installs the corresponding image shape. ++ !! Image-shapes DO NOT rotate when turning the turtle, ++ !! so they do not display the heading of the turtle! ++ (3) name is an arbitrary string and shape is a tuple + of pairs of coordinates. Installs the corresponding + polygon shape +- (3) name is an arbitrary string and shape is a ++ (4) name is an arbitrary string and shape is a + (compound) Shape object. Installs the corresponding + compound shape. + To use a shape, you have to issue the command shape(shapename). +@@ -1120,12 +1123,9 @@ + + """ + if shape is None: +- # image +- if name.lower().endswith(".gif"): +- shape = Shape("image", self._image(name)) +- else: +- raise TurtleGraphicsError("Bad arguments for register_shape.\n" +- + "Use help(register_shape)" ) ++ shape = Shape("image", self._image(name)) ++ elif isinstance(shape, str): ++ shape = Shape("image", self._image(shape)) + elif isinstance(shape, tuple): + shape = Shape("polygon", shape) + ## else shape assumed to be Shape-instance +@@ -1277,6 +1277,26 @@ + return self._delayvalue + self._delayvalue = int(delay) + ++ @contextmanager ++ def no_animation(self): ++ """Temporarily turn off auto-updating the screen. ++ ++ This is useful for drawing complex shapes where even the fastest setting ++ is too slow. Once this context manager is exited, the drawing will ++ be displayed. ++ ++ Example (for a TurtleScreen instance named screen ++ and a Turtle instance named turtle): ++ >>> with screen.no_animation(): ++ ... turtle.circle(50) ++ """ ++ tracer = self.tracer() ++ try: ++ self.tracer(0) ++ yield ++ finally: ++ self.tracer(tracer) ++ + def _incrementudc(self): + """Increment update counter.""" + if not TurtleScreen._RUNNING: +@@ -1454,7 +1474,7 @@ + """Set background image or return name of current backgroundimage. + + Optional argument: +- picname -- a string, name of a gif-file or "nopic". ++ picname -- a string, name of an image file (PNG, GIF, PGM, and PPM) or "nopic". + + If picname is a filename, set the corresponding image as background. + If picname is "nopic", delete backgroundimage, if present. +@@ -3382,6 +3402,24 @@ + """ + return isinstance(self._fillpath, list) + ++ @contextmanager ++ def fill(self): ++ """A context manager for filling a shape. ++ ++ Implicitly ensures the code block is wrapped with ++ begin_fill() and end_fill(). ++ ++ Example (for a Turtle instance named turtle): ++ >>> turtle.color("black", "red") ++ >>> with turtle.fill(): ++ ... turtle.circle(60) ++ """ ++ self.begin_fill() ++ try: ++ yield ++ finally: ++ self.end_fill() ++ + def begin_fill(self): + """Called just before drawing a shape to be filled. + +@@ -3402,7 +3440,6 @@ + self.undobuffer.push(("beginfill", self._fillitem)) + self._update() + +- + def end_fill(self): + """Fill the shape drawn after the call begin_fill(). + +@@ -3506,6 +3543,27 @@ + if self.undobuffer: + self.undobuffer.cumulate = False + ++ @contextmanager ++ def poly(self): ++ """A context manager for recording the vertices of a polygon. ++ ++ Implicitly ensures that the code block is wrapped with ++ begin_poly() and end_poly() ++ ++ Example (for a Turtle instance named turtle) where we create a ++ triangle as the polygon and move the turtle 100 steps forward: ++ >>> with turtle.poly(): ++ ... for side in range(3) ++ ... turtle.forward(50) ++ ... turtle.right(60) ++ >>> turtle.forward(100) ++ """ ++ self.begin_poly() ++ try: ++ yield ++ finally: ++ self.end_poly() ++ + def begin_poly(self): + """Start recording the vertices of a polygon. + +diff --git a/Lib/turtledemo/__main__.py b/Lib/turtledemo/__main__.py +index 9c15916fb66..b49c0beab3c 100644 +--- a/Lib/turtledemo/__main__.py ++++ b/Lib/turtledemo/__main__.py +@@ -105,7 +105,6 @@ + DONE = 4 + EVENTDRIVEN = 5 + +-menufont = ("Arial", 12, NORMAL) + btnfont = ("Arial", 12, 'bold') + txtfont = ['Lucida Console', 10, 'normal'] + +@@ -297,23 +296,21 @@ + for entry in getExampleEntries(): + def load(entry=entry): + self.loadfile(entry) +- menu.add_command(label=entry, underline=0, +- font=menufont, command=load) ++ menu.add_command(label=entry, underline=0, command=load) + return menu + + def makeFontMenu(self, master): + menu = Menu(master, tearoff=0) +- menu.add_command(label="Decrease (C-'-')", command=self.decrease_size, +- font=menufont) +- menu.add_command(label="Increase (C-'+')", command=self.increase_size, +- font=menufont) ++ menu.add_command(label="Decrease", command=self.decrease_size, ++ accelerator=f"{'Command' if darwin else 'Ctrl'}+-") ++ menu.add_command(label="Increase", command=self.increase_size, ++ accelerator=f"{'Command' if darwin else 'Ctrl'}+=") + menu.add_separator() + + for size in font_sizes: + def resize(size=size): + self.set_txtsize(size) +- menu.add_command(label=str(size), underline=0, +- font=menufont, command=resize) ++ menu.add_command(label=str(size), underline=0, command=resize) + return menu + + def makeHelpMenu(self, master): +@@ -322,7 +319,7 @@ + for help_label, help_file in help_entries: + def show(help_label=help_label, help_file=help_file): + view_text(self.root, help_label, help_file) +- menu.add_command(label=help_label, font=menufont, command=show) ++ menu.add_command(label=help_label, command=show) + return menu + + def refreshCanvas(self): +diff --git a/Lib/typing.py b/Lib/typing.py +index 5f3aacd8772..66570db7a5b 100644 +--- a/Lib/typing.py ++++ b/Lib/typing.py +@@ -1024,7 +1024,7 @@ + owner=None, + globals=None, + locals=None, +- type_params=None, ++ type_params=_sentinel, + format=annotationlib.Format.VALUE, + _recursive_guard=frozenset(), + ): +@@ -1733,12 +1733,16 @@ + return super().__repr__() + + def __instancecheck__(self, obj): +- return self.__subclasscheck__(type(obj)) ++ for arg in self.__args__: ++ if isinstance(obj, arg): ++ return True ++ return False + + def __subclasscheck__(self, cls): + for arg in self.__args__: + if issubclass(cls, arg): + return True ++ return False + + def __reduce__(self): + func, (origin, args) = super().__reduce__() +diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py +index 55c79d35353..10c3b7e1223 100644 +--- a/Lib/unittest/case.py ++++ b/Lib/unittest/case.py +@@ -1321,13 +1321,71 @@ + """Same as self.assertTrue(isinstance(obj, cls)), with a nicer + default message.""" + if not isinstance(obj, cls): +- standardMsg = '%s is not an instance of %r' % (safe_repr(obj), cls) ++ if isinstance(cls, tuple): ++ standardMsg = f'{safe_repr(obj)} is not an instance of any of {cls!r}' ++ else: ++ standardMsg = f'{safe_repr(obj)} is not an instance of {cls!r}' + self.fail(self._formatMessage(msg, standardMsg)) + + def assertNotIsInstance(self, obj, cls, msg=None): + """Included for symmetry with assertIsInstance.""" + if isinstance(obj, cls): +- standardMsg = '%s is an instance of %r' % (safe_repr(obj), cls) ++ if isinstance(cls, tuple): ++ for x in cls: ++ if isinstance(obj, x): ++ cls = x ++ break ++ standardMsg = f'{safe_repr(obj)} is an instance of {cls!r}' ++ self.fail(self._formatMessage(msg, standardMsg)) ++ ++ def assertIsSubclass(self, cls, superclass, msg=None): ++ try: ++ if issubclass(cls, superclass): ++ return ++ except TypeError: ++ if not isinstance(cls, type): ++ self.fail(self._formatMessage(msg, f'{cls!r} is not a class')) ++ raise ++ if isinstance(superclass, tuple): ++ standardMsg = f'{cls!r} is not a subclass of any of {superclass!r}' ++ else: ++ standardMsg = f'{cls!r} is not a subclass of {superclass!r}' ++ self.fail(self._formatMessage(msg, standardMsg)) ++ ++ def assertNotIsSubclass(self, cls, superclass, msg=None): ++ try: ++ if not issubclass(cls, superclass): ++ return ++ except TypeError: ++ if not isinstance(cls, type): ++ self.fail(self._formatMessage(msg, f'{cls!r} is not a class')) ++ raise ++ if isinstance(superclass, tuple): ++ for x in superclass: ++ if issubclass(cls, x): ++ superclass = x ++ break ++ standardMsg = f'{cls!r} is a subclass of {superclass!r}' ++ self.fail(self._formatMessage(msg, standardMsg)) ++ ++ def assertHasAttr(self, obj, name, msg=None): ++ if not hasattr(obj, name): ++ if isinstance(obj, types.ModuleType): ++ standardMsg = f'module {obj.__name__!r} has no attribute {name!r}' ++ elif isinstance(obj, type): ++ standardMsg = f'type object {obj.__name__!r} has no attribute {name!r}' ++ else: ++ standardMsg = f'{type(obj).__name__!r} object has no attribute {name!r}' ++ self.fail(self._formatMessage(msg, standardMsg)) ++ ++ def assertNotHasAttr(self, obj, name, msg=None): ++ if hasattr(obj, name): ++ if isinstance(obj, types.ModuleType): ++ standardMsg = f'module {obj.__name__!r} has unexpected attribute {name!r}' ++ elif isinstance(obj, type): ++ standardMsg = f'type object {obj.__name__!r} has unexpected attribute {name!r}' ++ else: ++ standardMsg = f'{type(obj).__name__!r} object has unexpected attribute {name!r}' + self.fail(self._formatMessage(msg, standardMsg)) + + def assertRaisesRegex(self, expected_exception, expected_regex, +@@ -1391,6 +1449,80 @@ + msg = self._formatMessage(msg, standardMsg) + raise self.failureException(msg) + ++ def _tail_type_check(self, s, tails, msg): ++ if not isinstance(tails, tuple): ++ tails = (tails,) ++ for tail in tails: ++ if isinstance(tail, str): ++ if not isinstance(s, str): ++ self.fail(self._formatMessage(msg, ++ f'Expected str, not {type(s).__name__}')) ++ elif isinstance(tail, (bytes, bytearray)): ++ if not isinstance(s, (bytes, bytearray)): ++ self.fail(self._formatMessage(msg, ++ f'Expected bytes, not {type(s).__name__}')) ++ ++ def assertStartsWith(self, s, prefix, msg=None): ++ try: ++ if s.startswith(prefix): ++ return ++ except (AttributeError, TypeError): ++ self._tail_type_check(s, prefix, msg) ++ raise ++ a = safe_repr(s, short=True) ++ b = safe_repr(prefix) ++ if isinstance(prefix, tuple): ++ standardMsg = f"{a} doesn't start with any of {b}" ++ else: ++ standardMsg = f"{a} doesn't start with {b}" ++ self.fail(self._formatMessage(msg, standardMsg)) ++ ++ def assertNotStartsWith(self, s, prefix, msg=None): ++ try: ++ if not s.startswith(prefix): ++ return ++ except (AttributeError, TypeError): ++ self._tail_type_check(s, prefix, msg) ++ raise ++ if isinstance(prefix, tuple): ++ for x in prefix: ++ if s.startswith(x): ++ prefix = x ++ break ++ a = safe_repr(s, short=True) ++ b = safe_repr(prefix) ++ self.fail(self._formatMessage(msg, f"{a} starts with {b}")) ++ ++ def assertEndsWith(self, s, suffix, msg=None): ++ try: ++ if s.endswith(suffix): ++ return ++ except (AttributeError, TypeError): ++ self._tail_type_check(s, suffix, msg) ++ raise ++ a = safe_repr(s, short=True) ++ b = safe_repr(suffix) ++ if isinstance(suffix, tuple): ++ standardMsg = f"{a} doesn't end with any of {b}" ++ else: ++ standardMsg = f"{a} doesn't end with {b}" ++ self.fail(self._formatMessage(msg, standardMsg)) ++ ++ def assertNotEndsWith(self, s, suffix, msg=None): ++ try: ++ if not s.endswith(suffix): ++ return ++ except (AttributeError, TypeError): ++ self._tail_type_check(s, suffix, msg) ++ raise ++ if isinstance(suffix, tuple): ++ for x in suffix: ++ if s.endswith(x): ++ suffix = x ++ break ++ a = safe_repr(s, short=True) ++ b = safe_repr(suffix) ++ self.fail(self._formatMessage(msg, f"{a} ends with {b}")) + + + class FunctionTestCase(TestCase): +diff --git a/Lib/unittest/result.py b/Lib/unittest/result.py +index 97262735aa8..b8ea396db67 100644 +--- a/Lib/unittest/result.py ++++ b/Lib/unittest/result.py +@@ -191,7 +191,8 @@ + capture_locals=self.tb_locals, compact=True) + from _colorize import can_colorize + +- msgLines = list(tb_e.format(colorize=can_colorize())) ++ colorize = hasattr(self, "stream") and can_colorize(file=self.stream) ++ msgLines = list(tb_e.format(colorize=colorize)) + + if self.buffer: + output = sys.stdout.getvalue() +diff --git a/Lib/unittest/runner.py b/Lib/unittest/runner.py +index d60c295a1ed..eb0234a2617 100644 +--- a/Lib/unittest/runner.py ++++ b/Lib/unittest/runner.py +@@ -45,7 +45,7 @@ + self.showAll = verbosity > 1 + self.dots = verbosity == 1 + self.descriptions = descriptions +- self._ansi = get_colors() ++ self._ansi = get_colors(file=stream) + self._newline = True + self.durations = durations + +@@ -286,7 +286,7 @@ + expected_fails, unexpected_successes, skipped = results + + infos = [] +- ansi = get_colors() ++ ansi = get_colors(file=self.stream) + bold_red = ansi.BOLD_RED + green = ansi.GREEN + red = ansi.RED +diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py +index c412c729852..9d51f4c6812 100644 +--- a/Lib/urllib/parse.py ++++ b/Lib/urllib/parse.py +@@ -439,6 +439,23 @@ + raise ValueError("netloc '" + netloc + "' contains invalid " + + "characters under NFKC normalization") + ++def _check_bracketed_netloc(netloc): ++ # Note that this function must mirror the splitting ++ # done in NetlocResultMixins._hostinfo(). ++ hostname_and_port = netloc.rpartition('@')[2] ++ before_bracket, have_open_br, bracketed = hostname_and_port.partition('[') ++ if have_open_br: ++ # No data is allowed before a bracket. ++ if before_bracket: ++ raise ValueError("Invalid IPv6 URL") ++ hostname, _, port = bracketed.partition(']') ++ # No data is allowed after the bracket but before the port delimiter. ++ if port and not port.startswith(":"): ++ raise ValueError("Invalid IPv6 URL") ++ else: ++ hostname, _, port = hostname_and_port.partition(':') ++ _check_bracketed_host(hostname) ++ + # Valid bracketed hosts are defined in + # https://www.rfc-editor.org/rfc/rfc3986#page-49 and https://url.spec.whatwg.org/ + def _check_bracketed_host(hostname): +@@ -505,8 +522,7 @@ + (']' in netloc and '[' not in netloc)): + raise ValueError("Invalid IPv6 URL") + if '[' in netloc and ']' in netloc: +- bracketed_host = netloc.partition('[')[2].partition(']')[0] +- _check_bracketed_host(bracketed_host) ++ _check_bracketed_netloc(netloc) + if allow_fragments and '#' in url: + url, fragment = url.split('#', 1) + if '?' in url: +diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py +index c5a6a18a32b..0d1b594b8cf 100644 +--- a/Lib/urllib/request.py ++++ b/Lib/urllib/request.py +@@ -1048,7 +1048,7 @@ + + + class AbstractDigestAuthHandler: +- # Digest authentication is specified in RFC 2617. ++ # Digest authentication is specified in RFC 2617/7616. + + # XXX The client does not inspect the Authentication-Info header + # in a successful response. +@@ -1176,11 +1176,14 @@ + return base + + def get_algorithm_impls(self, algorithm): ++ # algorithm names taken from RFC 7616 Section 6.1 + # lambdas assume digest modules are imported at the top level + if algorithm == 'MD5': + H = lambda x: hashlib.md5(x.encode("ascii")).hexdigest() +- elif algorithm == 'SHA': ++ elif algorithm == 'SHA': # non-standard, retained for compatibility. + H = lambda x: hashlib.sha1(x.encode("ascii")).hexdigest() ++ elif algorithm == 'SHA-256': ++ H = lambda x: hashlib.sha256(x.encode("ascii")).hexdigest() + # XXX MD5-sess + else: + raise ValueError("Unsupported digest authentication " +diff --git a/Lib/urllib/robotparser.py b/Lib/urllib/robotparser.py +index c58565e3945..409f2b2e48d 100644 +--- a/Lib/urllib/robotparser.py ++++ b/Lib/urllib/robotparser.py +@@ -11,6 +11,7 @@ + """ + + import collections ++import urllib.error + import urllib.parse + import urllib.request + +@@ -65,6 +66,7 @@ + self.disallow_all = True + elif err.code >= 400 and err.code < 500: + self.allow_all = True ++ err.close() + else: + raw = f.read() + self.parse(raw.decode("utf-8").splitlines()) +diff --git a/Lib/uuid.py b/Lib/uuid.py +index 9c6ad9643cf..36809b85cb8 100644 +--- a/Lib/uuid.py ++++ b/Lib/uuid.py +@@ -42,6 +42,14 @@ + # make a UUID from a 16-byte string + >>> uuid.UUID(bytes=x.bytes) + UUID('00010203-0405-0607-0809-0a0b0c0d0e0f') ++ ++ # get the Nil UUID ++ >>> uuid.NIL ++ UUID('00000000-0000-0000-0000-000000000000') ++ ++ # get the Max UUID ++ >>> uuid.MAX ++ UUID('ffffffff-ffff-ffff-ffff-ffffffffffff') + """ + + import os +@@ -85,6 +93,17 @@ + unknown = None + + ++_UINT_128_MAX = (1 << 128) - 1 ++# 128-bit mask to clear the variant and version bits of a UUID integral value ++_RFC_4122_CLEARFLAGS_MASK = ~((0xf000 << 64) | (0xc000 << 48)) ++# RFC 4122 variant bits and version bits to activate on a UUID integral value. ++_RFC_4122_VERSION_1_FLAGS = ((1 << 76) | (0x8000 << 48)) ++_RFC_4122_VERSION_3_FLAGS = ((3 << 76) | (0x8000 << 48)) ++_RFC_4122_VERSION_4_FLAGS = ((4 << 76) | (0x8000 << 48)) ++_RFC_4122_VERSION_5_FLAGS = ((5 << 76) | (0x8000 << 48)) ++_RFC_4122_VERSION_8_FLAGS = ((8 << 76) | (0x8000 << 48)) ++ ++ + class UUID: + """Instances of the UUID class represent UUIDs as specified in RFC 4122. + UUID objects are immutable, hashable, and usable as dictionary keys. +@@ -174,57 +193,69 @@ + if [hex, bytes, bytes_le, fields, int].count(None) != 4: + raise TypeError('one of the hex, bytes, bytes_le, fields, ' + 'or int arguments must be given') +- if hex is not None: ++ if int is not None: ++ pass ++ elif hex is not None: + hex = hex.replace('urn:', '').replace('uuid:', '') + hex = hex.strip('{}').replace('-', '') + if len(hex) != 32: + raise ValueError('badly formed hexadecimal UUID string') + int = int_(hex, 16) +- if bytes_le is not None: ++ elif bytes_le is not None: + if len(bytes_le) != 16: + raise ValueError('bytes_le is not a 16-char string') ++ assert isinstance(bytes_le, bytes_), repr(bytes_le) + bytes = (bytes_le[4-1::-1] + bytes_le[6-1:4-1:-1] + + bytes_le[8-1:6-1:-1] + bytes_le[8:]) +- if bytes is not None: ++ int = int_.from_bytes(bytes) # big endian ++ elif bytes is not None: + if len(bytes) != 16: + raise ValueError('bytes is not a 16-char string') + assert isinstance(bytes, bytes_), repr(bytes) + int = int_.from_bytes(bytes) # big endian +- if fields is not None: ++ elif fields is not None: + if len(fields) != 6: + raise ValueError('fields is not a 6-tuple') + (time_low, time_mid, time_hi_version, + clock_seq_hi_variant, clock_seq_low, node) = fields +- if not 0 <= time_low < 1<<32: ++ if not 0 <= time_low < (1 << 32): + raise ValueError('field 1 out of range (need a 32-bit value)') +- if not 0 <= time_mid < 1<<16: ++ if not 0 <= time_mid < (1 << 16): + raise ValueError('field 2 out of range (need a 16-bit value)') +- if not 0 <= time_hi_version < 1<<16: ++ if not 0 <= time_hi_version < (1 << 16): + raise ValueError('field 3 out of range (need a 16-bit value)') +- if not 0 <= clock_seq_hi_variant < 1<<8: ++ if not 0 <= clock_seq_hi_variant < (1 << 8): + raise ValueError('field 4 out of range (need an 8-bit value)') +- if not 0 <= clock_seq_low < 1<<8: ++ if not 0 <= clock_seq_low < (1 << 8): + raise ValueError('field 5 out of range (need an 8-bit value)') +- if not 0 <= node < 1<<48: ++ if not 0 <= node < (1 << 48): + raise ValueError('field 6 out of range (need a 48-bit value)') + clock_seq = (clock_seq_hi_variant << 8) | clock_seq_low + int = ((time_low << 96) | (time_mid << 80) | + (time_hi_version << 64) | (clock_seq << 48) | node) +- if int is not None: +- if not 0 <= int < 1<<128: +- raise ValueError('int is out of range (need a 128-bit value)') ++ if not 0 <= int <= _UINT_128_MAX: ++ raise ValueError('int is out of range (need a 128-bit value)') + if version is not None: + if not 1 <= version <= 8: + raise ValueError('illegal version number') ++ # clear the variant and the version number bits ++ int &= _RFC_4122_CLEARFLAGS_MASK + # Set the variant to RFC 4122/9562. +- int &= ~(0xc000 << 48) +- int |= 0x8000 << 48 ++ int |= 0x8000_0000_0000_0000 # (0x8000 << 48) + # Set the version number. +- int &= ~(0xf000 << 64) + int |= version << 76 + object.__setattr__(self, 'int', int) + object.__setattr__(self, 'is_safe', is_safe) + ++ @classmethod ++ def _from_int(cls, value): ++ """Create a UUID from an integer *value*. Internal use only.""" ++ assert 0 <= value <= _UINT_128_MAX, repr(value) ++ self = object.__new__(cls) ++ object.__setattr__(self, 'int', value) ++ object.__setattr__(self, 'is_safe', SafeUUID.unknown) ++ return self ++ + def __getstate__(self): + d = {'int': self.int} + if self.is_safe != SafeUUID.unknown: +@@ -700,24 +731,30 @@ + """Generate a UUID from the MD5 hash of a namespace UUID and a name.""" + if isinstance(name, str): + name = bytes(name, "utf-8") +- from hashlib import md5 +- digest = md5( +- namespace.bytes + name, +- usedforsecurity=False +- ).digest() +- return UUID(bytes=digest[:16], version=3) ++ import hashlib ++ h = hashlib.md5(namespace.bytes + name, usedforsecurity=False) ++ int_uuid_3 = int.from_bytes(h.digest()) ++ int_uuid_3 &= _RFC_4122_CLEARFLAGS_MASK ++ int_uuid_3 |= _RFC_4122_VERSION_3_FLAGS ++ return UUID._from_int(int_uuid_3) + + def uuid4(): + """Generate a random UUID.""" +- return UUID(bytes=os.urandom(16), version=4) ++ int_uuid_4 = int.from_bytes(os.urandom(16)) ++ int_uuid_4 &= _RFC_4122_CLEARFLAGS_MASK ++ int_uuid_4 |= _RFC_4122_VERSION_4_FLAGS ++ return UUID._from_int(int_uuid_4) + + def uuid5(namespace, name): + """Generate a UUID from the SHA-1 hash of a namespace UUID and a name.""" + if isinstance(name, str): + name = bytes(name, "utf-8") +- from hashlib import sha1 +- hash = sha1(namespace.bytes + name).digest() +- return UUID(bytes=hash[:16], version=5) ++ import hashlib ++ h = hashlib.sha1(namespace.bytes + name, usedforsecurity=False) ++ int_uuid_5 = int.from_bytes(h.digest()[:16]) ++ int_uuid_5 &= _RFC_4122_CLEARFLAGS_MASK ++ int_uuid_5 |= _RFC_4122_VERSION_5_FLAGS ++ return UUID._from_int(int_uuid_5) + + def uuid8(a=None, b=None, c=None): + """Generate a UUID from three custom blocks. +@@ -740,7 +777,9 @@ + int_uuid_8 = (a & 0xffff_ffff_ffff) << 80 + int_uuid_8 |= (b & 0xfff) << 64 + int_uuid_8 |= c & 0x3fff_ffff_ffff_ffff +- return UUID(int=int_uuid_8, version=8) ++ # by construction, the variant and version bits are already cleared ++ int_uuid_8 |= _RFC_4122_VERSION_8_FLAGS ++ return UUID._from_int(int_uuid_8) + + def main(): + """Run the uuid command line interface.""" +@@ -799,5 +838,10 @@ + NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8') + NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8') + ++# RFC 9562 Sections 5.9 and 5.10 define the special Nil and Max UUID formats. ++ ++NIL = UUID('00000000-0000-0000-0000-000000000000') ++MAX = UUID('ffffffff-ffff-ffff-ffff-ffffffffffff') ++ + if __name__ == "__main__": + main() +diff --git a/Lib/warnings.py b/Lib/warnings.py +index e83cde37ab2..13ad6c8aacb 100644 +--- a/Lib/warnings.py ++++ b/Lib/warnings.py +@@ -185,24 +185,32 @@ + raise ValueError("lineno must be an int >= 0") + _add_filter(action, None, category, None, lineno, append=append) + ++def _filters_mutated(): ++ # Even though this function is not part of the public API, it's used by ++ # a fair amount of user code. ++ with _lock: ++ _filters_mutated_lock_held() ++ + def _add_filter(*item, append): +- # Remove possible duplicate filters, so new one will be placed +- # in correct place. If append=True and duplicate exists, do nothing. +- if not append: +- try: +- filters.remove(item) +- except ValueError: +- pass +- filters.insert(0, item) +- else: +- if item not in filters: +- filters.append(item) +- _filters_mutated() ++ with _lock: ++ if not append: ++ # Remove possible duplicate filters, so new one will be placed ++ # in correct place. If append=True and duplicate exists, do nothing. ++ try: ++ filters.remove(item) ++ except ValueError: ++ pass ++ filters.insert(0, item) ++ else: ++ if item not in filters: ++ filters.append(item) ++ _filters_mutated_lock_held() + + def resetwarnings(): + """Clear the list of warning filters, so that no filters are active.""" +- filters[:] = [] +- _filters_mutated() ++ with _lock: ++ filters[:] = [] ++ _filters_mutated_lock_held() + + class _OptionError(Exception): + """Exception used by option processing helpers.""" +@@ -353,11 +361,6 @@ + module = filename or "" + if module[-3:].lower() == ".py": + module = module[:-3] # XXX What about leading pathname? +- if registry is None: +- registry = {} +- if registry.get('version', 0) != _filters_version: +- registry.clear() +- registry['version'] = _filters_version + if isinstance(message, Warning): + text = str(message) + category = message.__class__ +@@ -365,52 +368,59 @@ + text = message + message = category(message) + key = (text, category, lineno) +- # Quick test for common case +- if registry.get(key): +- return +- # Search the filters +- for item in filters: +- action, msg, cat, mod, ln = item +- if ((msg is None or msg.match(text)) and +- issubclass(category, cat) and +- (mod is None or mod.match(module)) and +- (ln == 0 or lineno == ln)): +- break +- else: +- action = defaultaction +- # Early exit actions +- if action == "ignore": +- return ++ with _lock: ++ if registry is None: ++ registry = {} ++ if registry.get('version', 0) != _filters_version: ++ registry.clear() ++ registry['version'] = _filters_version ++ # Quick test for common case ++ if registry.get(key): ++ return ++ # Search the filters ++ for item in filters: ++ action, msg, cat, mod, ln = item ++ if ((msg is None or msg.match(text)) and ++ issubclass(category, cat) and ++ (mod is None or mod.match(module)) and ++ (ln == 0 or lineno == ln)): ++ break ++ else: ++ action = defaultaction ++ # Early exit actions ++ if action == "ignore": ++ return ++ ++ if action == "error": ++ raise message ++ # Other actions ++ if action == "once": ++ registry[key] = 1 ++ oncekey = (text, category) ++ if onceregistry.get(oncekey): ++ return ++ onceregistry[oncekey] = 1 ++ elif action in {"always", "all"}: ++ pass ++ elif action == "module": ++ registry[key] = 1 ++ altkey = (text, category, 0) ++ if registry.get(altkey): ++ return ++ registry[altkey] = 1 ++ elif action == "default": ++ registry[key] = 1 ++ else: ++ # Unrecognized actions are errors ++ raise RuntimeError( ++ "Unrecognized action (%r) in warnings.filters:\n %s" % ++ (action, item)) + + # Prime the linecache for formatting, in case the + # "file" is actually in a zipfile or something. + import linecache + linecache.getlines(filename, module_globals) + +- if action == "error": +- raise message +- # Other actions +- if action == "once": +- registry[key] = 1 +- oncekey = (text, category) +- if onceregistry.get(oncekey): +- return +- onceregistry[oncekey] = 1 +- elif action in {"always", "all"}: +- pass +- elif action == "module": +- registry[key] = 1 +- altkey = (text, category, 0) +- if registry.get(altkey): +- return +- registry[altkey] = 1 +- elif action == "default": +- registry[key] = 1 +- else: +- # Unrecognized actions are errors +- raise RuntimeError( +- "Unrecognized action (%r) in warnings.filters:\n %s" % +- (action, item)) + # Print message and context + msg = WarningMessage(message, category, filename, lineno, source) + _showwarnmsg(msg) +@@ -463,9 +473,6 @@ + """Specify whether to record warnings and if an alternative module + should be used other than sys.modules['warnings']. + +- For compatibility with Python 3.0, please consider all arguments to be +- keyword-only. +- + """ + self._record = record + self._module = sys.modules['warnings'] if module is None else module +@@ -488,30 +495,32 @@ + if self._entered: + raise RuntimeError("Cannot enter %r twice" % self) + self._entered = True +- self._filters = self._module.filters +- self._module.filters = self._filters[:] +- self._module._filters_mutated() +- self._showwarning = self._module.showwarning +- self._showwarnmsg_impl = self._module._showwarnmsg_impl ++ with _lock: ++ self._filters = self._module.filters ++ self._module.filters = self._filters[:] ++ self._module._filters_mutated_lock_held() ++ self._showwarning = self._module.showwarning ++ self._showwarnmsg_impl = self._module._showwarnmsg_impl ++ if self._record: ++ log = [] ++ self._module._showwarnmsg_impl = log.append ++ # Reset showwarning() to the default implementation to make sure ++ # that _showwarnmsg() calls _showwarnmsg_impl() ++ self._module.showwarning = self._module._showwarning_orig ++ else: ++ log = None + if self._filter is not None: + simplefilter(*self._filter) +- if self._record: +- log = [] +- self._module._showwarnmsg_impl = log.append +- # Reset showwarning() to the default implementation to make sure +- # that _showwarnmsg() calls _showwarnmsg_impl() +- self._module.showwarning = self._module._showwarning_orig +- return log +- else: +- return None ++ return log + + def __exit__(self, *exc_info): + if not self._entered: + raise RuntimeError("Cannot exit %r without entering first" % self) +- self._module.filters = self._filters +- self._module._filters_mutated() +- self._module.showwarning = self._showwarning +- self._module._showwarnmsg_impl = self._showwarnmsg_impl ++ with _lock: ++ self._module.filters = self._filters ++ self._module._filters_mutated_lock_held() ++ self._module.showwarning = self._showwarning ++ self._module._showwarnmsg_impl = self._showwarnmsg_impl + + + class deprecated: +@@ -701,18 +710,36 @@ + # If either if the compiled regexs are None, match anything. + try: + from _warnings import (filters, _defaultaction, _onceregistry, +- warn, warn_explicit, _filters_mutated) ++ warn, warn_explicit, ++ _filters_mutated_lock_held, ++ _acquire_lock, _release_lock, ++ ) + defaultaction = _defaultaction + onceregistry = _onceregistry + _warnings_defaults = True ++ ++ class _Lock: ++ def __enter__(self): ++ _acquire_lock() ++ return self ++ ++ def __exit__(self, *args): ++ _release_lock() ++ ++ _lock = _Lock() ++ + except ImportError: + filters = [] + defaultaction = "default" + onceregistry = {} + ++ import _thread ++ ++ _lock = _thread.RLock() ++ + _filters_version = 1 + +- def _filters_mutated(): ++ def _filters_mutated_lock_held(): + global _filters_version + _filters_version += 1 + +diff --git a/Lib/xml/dom/xmlbuilder.py b/Lib/xml/dom/xmlbuilder.py +index 8a200263497..a8852625a2f 100644 +--- a/Lib/xml/dom/xmlbuilder.py ++++ b/Lib/xml/dom/xmlbuilder.py +@@ -189,7 +189,7 @@ + options.filter = self.filter + options.errorHandler = self.errorHandler + fp = input.byteStream +- if fp is None and options.systemId: ++ if fp is None and input.systemId: + import urllib.request + fp = urllib.request.urlopen(input.systemId) + return self._parse_bytestream(fp, options) +@@ -247,10 +247,12 @@ + + def _guess_media_encoding(self, source): + info = source.byteStream.info() +- if "Content-Type" in info: +- for param in info.getplist(): +- if param.startswith("charset="): +- return param.split("=", 1)[1].lower() ++ # import email.message ++ # assert isinstance(info, email.message.Message) ++ charset = info.get_param('charset') ++ if charset is not None: ++ return charset.lower() ++ return None + + + class DOMInputSource(object): +diff --git a/Lib/zipfile/__init__.py b/Lib/zipfile/__init__.py +index 6907ae6d5b7..b8b496ad947 100644 +--- a/Lib/zipfile/__init__.py ++++ b/Lib/zipfile/__init__.py +@@ -605,6 +605,28 @@ + + return zinfo + ++ def _for_archive(self, archive): ++ """Resolve suitable defaults from the archive. ++ ++ Resolve the date_time, compression attributes, and external attributes ++ to suitable defaults as used by :method:`ZipFile.writestr`. ++ ++ Return self. ++ """ ++ # gh-91279: Set the SOURCE_DATE_EPOCH to a specific timestamp ++ epoch = os.environ.get('SOURCE_DATE_EPOCH') ++ get_time = int(epoch) if epoch else time.time() ++ self.date_time = time.localtime(get_time)[:6] ++ ++ self.compress_type = archive.compression ++ self.compress_level = archive.compresslevel ++ if self.filename.endswith('/'): # pragma: no cover ++ self.external_attr = 0o40775 << 16 # drwxrwxr-x ++ self.external_attr |= 0x10 # MS-DOS directory flag ++ else: ++ self.external_attr = 0o600 << 16 # ?rw------- ++ return self ++ + def is_dir(self): + """Return True if this archive member is a directory.""" + if self.filename.endswith('/'): +@@ -819,7 +841,10 @@ + raise ValueError("Can't reposition in the ZIP file while " + "there is an open writing handle on it. " + "Close the writing handle before trying to read.") +- self._file.seek(offset, whence) ++ if whence == os.SEEK_CUR: ++ self._file.seek(self._pos + offset) ++ else: ++ self._file.seek(offset, whence) + self._pos = self._file.tell() + return self._pos + +@@ -1162,13 +1187,15 @@ + self._offset = buff_offset + read_offset = 0 + # Fast seek uncompressed unencrypted file +- elif self._compress_type == ZIP_STORED and self._decrypter is None and read_offset > 0: ++ elif self._compress_type == ZIP_STORED and self._decrypter is None and read_offset != 0: + # disable CRC checking after first seeking - it would be invalid + self._expected_crc = None + # seek actual file taking already buffered data into account + read_offset -= len(self._readbuffer) - self._offset + self._fileobj.seek(read_offset, os.SEEK_CUR) + self._left -= read_offset ++ self._compress_left -= read_offset ++ self._eof = self._left <= 0 + read_offset = 0 + # flush read buffer + self._readbuffer = b'' +@@ -1905,18 +1932,10 @@ + the name of the file in the archive.""" + if isinstance(data, str): + data = data.encode("utf-8") +- if not isinstance(zinfo_or_arcname, ZipInfo): +- zinfo = ZipInfo(filename=zinfo_or_arcname, +- date_time=time.localtime(time.time())[:6]) +- zinfo.compress_type = self.compression +- zinfo.compress_level = self.compresslevel +- if zinfo.filename.endswith('/'): +- zinfo.external_attr = 0o40775 << 16 # drwxrwxr-x +- zinfo.external_attr |= 0x10 # MS-DOS directory flag +- else: +- zinfo.external_attr = 0o600 << 16 # ?rw------- +- else: ++ if isinstance(zinfo_or_arcname, ZipInfo): + zinfo = zinfo_or_arcname ++ else: ++ zinfo = ZipInfo(zinfo_or_arcname)._for_archive(self) + + if not self.fp: + raise ValueError( +diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py +index f5f0ed44884..cb2484767e6 100755 +--- a/Mac/BuildScript/build-installer.py ++++ b/Mac/BuildScript/build-installer.py +@@ -325,32 +325,32 @@ + + result.extend([ + dict( +- name="NCurses 5.9", +- url="http://ftp.gnu.org/pub/gnu/ncurses/ncurses-5.9.tar.gz", +- checksum='8cb9c412e5f2d96bc6f459aa8c6282a1', ++ name="NCurses 6.5", ++ url="https://ftp.gnu.org/gnu/ncurses/ncurses-6.5.tar.gz", ++ checksum="136d91bc269a9a5785e5f9e980bc76ab57428f604ce3e5a5a90cebc767971cc6", + configure_pre=[ ++ "--datadir=/usr/share", ++ "--disable-lib-suffixes", ++ "--disable-db-install", ++ "--disable-mixed-case", ++ "--enable-overwrite", + "--enable-widec", ++ f"--libdir=/Library/Frameworks/Python.framework/Versions/{getVersion()}/lib", ++ "--sharedstatedir=/usr/com", ++ "--sysconfdir=/etc", ++ "--with-default-terminfo-dir=/usr/share/terminfo", ++ "--with-shared", ++ "--with-terminfo-dirs=/usr/share/terminfo", ++ "--without-ada", + "--without-cxx", + "--without-cxx-binding", +- "--without-ada", +- "--without-curses-h", +- "--enable-shared", +- "--with-shared", ++ "--without-cxx-shared", + "--without-debug", ++ "--without-manpages", + "--without-normal", ++ "--without-progs", + "--without-tests", +- "--without-manpages", +- "--datadir=/usr/share", +- "--sysconfdir=/etc", +- "--sharedstatedir=/usr/com", +- "--with-terminfo-dirs=/usr/share/terminfo", +- "--with-default-terminfo-dir=/usr/share/terminfo", +- "--libdir=/Library/Frameworks/Python.framework/Versions/%s/lib"%(getVersion(),), + ], +- patchscripts=[ +- ("ftp://ftp.invisible-island.net/ncurses//5.9/ncurses-5.9-20120616-patch.sh.bz2", +- "f54bf02a349f96a7c4f0d00922f3a0d4"), +- ], + useLDFlags=False, + install='make && make install DESTDIR=%s && cd %s/usr/local/lib && ln -fs ../../../Library/Frameworks/Python.framework/Versions/%s/lib/lib* .'%( + shellQuote(os.path.join(WORKDIR, 'libraries')), +diff --git a/Makefile.pre.in b/Makefile.pre.in +index 3e880f7800f..67acf0fc520 100644 +--- a/Makefile.pre.in ++++ b/Makefile.pre.in +@@ -488,6 +488,7 @@ + Python/qsbr.o \ + Python/bootstrap_hash.o \ + Python/specialize.o \ ++ Python/stackrefs.o \ + Python/structmember.o \ + Python/symtable.o \ + Python/sysmodule.o \ +diff --git a/Misc/ACKS b/Misc/ACKS +index 08693066682..2a68b69f161 100644 +--- a/Misc/ACKS ++++ b/Misc/ACKS +@@ -189,6 +189,7 @@ + Eric Blossom + Sergey Bobrov + Finn Bock ++VojtÄ›ch BoÄek + Paul Boddie + Matthew Boedicker + Robin Boerdijk +@@ -258,6 +259,7 @@ + Erik de Bueger + Jan-Hein Bührman + Marc Bürg ++Calvin Bui + Lars Buitinck + Artem Bulgakov + Dick Bulterman +@@ -574,6 +576,7 @@ + Artem Fokin + Arnaud Fontaine + Michael Foord ++Forest + Amaury Forgeot d'Arc + Doug Fort + Daniel Fortunov +@@ -1037,6 +1040,7 @@ + Kabir Kwatra + Ross Lagerwall + Cameron Laird ++Filipe Laíns + Loïc Lajeanne + Alexander Lakeev + David Lam +@@ -1128,6 +1132,7 @@ + Everett Lipman + Mirko Liss + Alexander Liu ++Hui Liu + Yuan Liu + Nick Lockwood + Stephanie Lockwood +@@ -1472,6 +1477,7 @@ + Martin Pool + Iustin Pop + Claudiu Popa ++Nick Pope + John Popplewell + Matheus Vieira Portela + Davin Potts +@@ -1919,6 +1925,7 @@ + Fraser Tweedale + Doobee R. Tzeck + Eren Türkay ++Stan Ulbrych + Lionel Ulmer + Adnan Umer + Utkarsh Upadhyay +@@ -1966,6 +1973,7 @@ + Michael Vogt + Radu Voicilas + Alex Volkov ++Illia Volochii + Ruben Vorderman + Guido Vranken + Martijn Vries +@@ -1985,6 +1993,7 @@ + Jiahua Wang + Ke Wang + Liang-Bo Wang ++Brian Ward + Greg Ward + Tom Wardill + Zachary Ware +diff --git a/Misc/SpecialBuilds.txt b/Misc/SpecialBuilds.txt +index 78201bfbd67..23fa36af78c 100644 +--- a/Misc/SpecialBuilds.txt ++++ b/Misc/SpecialBuilds.txt +@@ -78,22 +78,16 @@ + + This is what is generally meant by "a debug build" of Python. + +-Py_DEBUG implies LLTRACE and Py_REF_DEBUG. In addition, C assert()s are enabled ++Py_DEBUG implies Py_REF_DEBUG. In addition, C assert()s are enabled + (via the C way: by not defining NDEBUG), and some routines do additional sanity + checks inside "#ifdef Py_DEBUG" blocks. + +- +-LLTRACE +-------- +- +-Compile in support for Low Level TRACE-ing of the main interpreter loop. +- +-When this preprocessor symbol is defined, before PyEval_EvalFrame executes a +-frame's code it checks the frame's global namespace for a variable +-"__lltrace__". If such a variable is found, mounds of information about what +-the interpreter is doing are sprayed to stdout, such as every opcode and opcode +-argument and values pushed onto and popped off the value stack. +- +-Not useful very often, but very useful when needed. +- +-Py_DEBUG implies LLTRACE. ++Also, compile in support for "lltrace" (Low Level TRACE-ing) of the main ++interpreter loop. Before _PyEval_EvalFrameDefault executes a frame's code, it ++checks the frame's global namespace for a variable "__lltrace__" (as well as for ++the environment variable PYTHON_LLTRACE"). If such a variable is found, mounds ++of information about what the interpreter is doing are sprayed to stdout, such ++as every opcode and opcode argument and values pushed onto and popped off the ++value stack. Higher integer values for the environment variable result in more ++and more detail being printed (the global __lltrace__ always enables the maximum ++output). Not useful very often, but *very* useful when needed. +diff --git a/Misc/platform_triplet.c b/Misc/platform_triplet.c +index ec0857a4a99..190670f271d 100644 +--- a/Misc/platform_triplet.c ++++ b/Misc/platform_triplet.c +@@ -254,9 +254,55 @@ + # else + PLATFORM_TRIPLET=arm64-iphonesimulator + # endif ++# elif defined(TARGET_OS_MACCATALYST) && TARGET_OS_MACCATALYST ++# if __x86_64__ ++PLATFORM_TRIPLET=x86_64-iphoneos-macabi ++# else ++PLATFORM_TRIPLET=arm64-iphoneos-macabi ++# endif + # else + PLATFORM_TRIPLET=arm64-iphoneos + # endif ++# elif defined(TARGET_OS_TV) && TARGET_OS_TV ++# if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR ++# if __x86_64__ ++PLATFORM_TRIPLET=x86_64-appletvsimulator ++# else ++PLATFORM_TRIPLET=arm64-appletvsimulator ++# endif ++# else ++PLATFORM_TRIPLET=arm64-appletvos ++# endif ++# elif defined(TARGET_OS_WATCH) && TARGET_OS_WATCH ++# if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR ++# if __x86_64__ ++PLATFORM_TRIPLET=x86_64-watchsimulator ++# else ++PLATFORM_TRIPLET=arm64-watchsimulator ++# endif ++# else ++PLATFORM_TRIPLET=arm64_32-watchos ++# endif ++# elif defined(TARGET_OS_TV) && TARGET_OS_TV ++# if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR ++# if __x86_64__ ++PLATFORM_TRIPLET=x86_64-appletvsimulator ++# else ++PLATFORM_TRIPLET=arm64-appletvsimulator ++# endif ++# else ++PLATFORM_TRIPLET=arm64-appletvos ++# endif ++# elif defined(TARGET_OS_WATCH) && TARGET_OS_WATCH ++# if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR ++# if __x86_64__ ++PLATFORM_TRIPLET=x86_64-watchsimulator ++# else ++PLATFORM_TRIPLET=arm64-watchsimulator ++# endif ++# else ++PLATFORM_TRIPLET=arm64_32-watchos ++# endif + // Older macOS SDKs do not define TARGET_OS_OSX + # elif !defined(TARGET_OS_OSX) || TARGET_OS_OSX + PLATFORM_TRIPLET=darwin +diff --git a/Misc/sbom.spdx.json b/Misc/sbom.spdx.json +index 739e005646b..316c266b7e4 100644 +--- a/Misc/sbom.spdx.json ++++ b/Misc/sbom.spdx.json +@@ -566,11 +566,11 @@ + "checksums": [ + { + "algorithm": "SHA1", +- "checksumValue": "2e08072c0c57dac02b67f3f71d77068c537ac02e" ++ "checksumValue": "118dc712780ea680affa8d9794470440eb87ff10" + }, + { + "algorithm": "SHA256", +- "checksumValue": "e69fd3e84f77873ecb414f5300761b686321d01f5710ccf2517765236b08fc25" ++ "checksumValue": "b017e7d5662a308c938cf4e4b919680c8f3e27f42975ca152b62fe65c5f7fb0c" + } + ], + "fileName": "Modules/_hacl/Lib_Memzero0.c" +@@ -622,11 +622,11 @@ + "checksums": [ + { + "algorithm": "SHA1", +- "checksumValue": "9881567f43deb32bae77a84b2d349858a24b6685" ++ "checksumValue": "9c5cac1582dcd6e0d0a4142e6e8b285b4cb7d9e6" + }, + { + "algorithm": "SHA256", +- "checksumValue": "3382156e32fcb376009177d3d2dc9712ff7c8c02afb97b3e16d98b41a2114f84" ++ "checksumValue": "b1e32138ac8c262e872f7da43ec80c1e54c08bcbdec4b7be17117aa25807f87e" + } + ], + "fileName": "Modules/_hacl/include/krml/internal/target.h" +@@ -1280,11 +1280,11 @@ + "checksums": [ + { + "algorithm": "SHA1", +- "checksumValue": "9dcb50e3f9c3245972731be5da0b28e7583198d9" ++ "checksumValue": "5d6fdd98730584f74f7b731da6e488fe234504b3" + }, + { + "algorithm": "SHA256", +- "checksumValue": "7cac49fef5e9d952ec9390bf81c54d83f1b5da32fdf76091c2f0770ed943b7fe" ++ "checksumValue": "d74f365463166891f62e1326d22b2d39d865776b7ea5e0df2aea5eede4d85b0f" + } + ], + "fileName": "Modules/_decimal/libmpdec/io.c" +diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml +index f9e51f0683c..9317be605f0 100644 +--- a/Misc/stable_abi.toml ++++ b/Misc/stable_abi.toml +@@ -1253,6 +1253,7 @@ + added = '3.2' + [function.PySequence_Fast] + added = '3.2' ++ abi_only = true + [function.PySequence_GetItem] + added = '3.2' + [function.PySequence_GetSlice] +@@ -2540,3 +2541,7 @@ + added = '3.14' + [function.PyType_Freeze] + added = '3.14' ++[function.Py_PACK_FULL_VERSION] ++ added = '3.14' ++[function.Py_PACK_VERSION] ++ added = '3.14' +diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in +index 52c0f883d38..6bb05a06a34 100644 +--- a/Modules/Setup.stdlib.in ++++ b/Modules/Setup.stdlib.in +@@ -162,8 +162,8 @@ + @MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c + @MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c + @MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c _testinternalcapi/set.c _testinternalcapi/test_critical_sections.c +-@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/monitoring.c _testcapi/config.c +-@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/codec.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/sys.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c ++@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/monitoring.c _testcapi/config.c _testcapi/import.c _testcapi/frame.c _testcapi/type.c _testcapi/function.c ++@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/codec.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/import.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/sys.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c _testlimitedcapi/version.c _testlimitedcapi/file.c + @MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c + @MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c + +diff --git a/Modules/_abc.c b/Modules/_abc.c +index 4f4b24b035d..d6a953b3360 100644 +--- a/Modules/_abc.c ++++ b/Modules/_abc.c +@@ -67,6 +67,8 @@ + uint64_t _abc_negative_cache_version; + } _abc_data; + ++#define _abc_data_CAST(op) ((_abc_data *)(op)) ++ + static inline uint64_t + get_cache_version(_abc_data *impl) + { +@@ -88,8 +90,9 @@ + } + + static int +-abc_data_traverse(_abc_data *self, visitproc visit, void *arg) ++abc_data_traverse(PyObject *op, visitproc visit, void *arg) + { ++ _abc_data *self = _abc_data_CAST(op); + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->_abc_registry); + Py_VISIT(self->_abc_cache); +@@ -98,8 +101,9 @@ + } + + static int +-abc_data_clear(_abc_data *self) ++abc_data_clear(PyObject *op) + { ++ _abc_data *self = _abc_data_CAST(op); + Py_CLEAR(self->_abc_registry); + Py_CLEAR(self->_abc_cache); + Py_CLEAR(self->_abc_negative_cache); +@@ -107,7 +111,7 @@ + } + + static void +-abc_data_dealloc(_abc_data *self) ++abc_data_dealloc(PyObject *self) + { + PyObject_GC_UnTrack(self); + PyTypeObject *tp = Py_TYPE(self); +@@ -212,7 +216,7 @@ + } + + static PyMethodDef _destroy_def = { +- "_destroy", (PyCFunction) _destroy, METH_O ++ "_destroy", _destroy, METH_O + }; + + static int +@@ -964,7 +968,7 @@ + static void + _abcmodule_free(void *module) + { +- _abcmodule_clear((PyObject *)module); ++ (void)_abcmodule_clear((PyObject *)module); + } + + static PyModuleDef_Slot _abcmodule_slots[] = { +diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c +index f883125a2c7..5a4e65636e4 100644 +--- a/Modules/_asynciomodule.c ++++ b/Modules/_asynciomodule.c +@@ -6,9 +6,10 @@ + #include "pycore_critical_section.h" // Py_BEGIN_CRITICAL_SECTION_MUT() + #include "pycore_dict.h" // _PyDict_GetItem_KnownHash() + #include "pycore_freelist.h" // _Py_FREELIST_POP() ++#include "pycore_llist.h" // struct llist_node + #include "pycore_modsupport.h" // _PyArg_CheckPositional() + #include "pycore_moduleobject.h" // _PyModule_GetState() +-#include "pycore_object.h" // _Py_SetImmortalUntracked() ++#include "pycore_object.h" // _PyObject_SetMaybeWeakref + #include "pycore_pyerrors.h" // _PyErr_ClearExcState() + #include "pycore_pylifecycle.h" // _Py_IsInterpreterFinalizing() + #include "pycore_pystate.h" // _PyThreadState_GET() +@@ -40,12 +41,17 @@ + PyObject *prefix##_source_tb; \ + PyObject *prefix##_cancel_msg; \ + PyObject *prefix##_cancelled_exc; \ ++ PyObject *prefix##_awaited_by; \ + fut_state prefix##_state; \ +- /* These bitfields need to be at the end of the struct +- so that these and bitfields from TaskObj are contiguous. ++ /* Used by profilers to make traversing the stack from an external \ ++ process faster. */ \ ++ char prefix##_is_task; \ ++ char prefix##_awaited_by_is_set; \ ++ /* These bitfields need to be at the end of the struct \ ++ so that these and bitfields from TaskObj are contiguous. \ + */ \ + unsigned prefix##_log_tb: 1; \ +- unsigned prefix##_blocking: 1; ++ unsigned prefix##_blocking: 1; \ + + typedef struct { + FutureObj_HEAD(fut) +@@ -60,8 +66,11 @@ + PyObject *task_coro; + PyObject *task_name; + PyObject *task_context; +- struct TaskObj *next; +- struct TaskObj *prev; ++ struct llist_node task_node; ++#ifdef Py_GIL_DISABLED ++ // thread id of the thread where this task was created ++ uintptr_t task_tid; ++#endif + } TaskObj; + + typedef struct { +@@ -70,26 +79,58 @@ + PyObject *sw_arg; + } TaskStepMethWrapper; + +- + #define Future_CheckExact(state, obj) Py_IS_TYPE(obj, state->FutureType) + #define Task_CheckExact(state, obj) Py_IS_TYPE(obj, state->TaskType) + +-#define Future_Check(state, obj) PyObject_TypeCheck(obj, state->FutureType) +-#define Task_Check(state, obj) PyObject_TypeCheck(obj, state->TaskType) +- +-#ifdef Py_GIL_DISABLED +-# define ASYNCIO_STATE_LOCK(state) Py_BEGIN_CRITICAL_SECTION_MUT(&state->mutex) +-# define ASYNCIO_STATE_UNLOCK(state) Py_END_CRITICAL_SECTION() +-#else +-# define ASYNCIO_STATE_LOCK(state) ((void)state) +-# define ASYNCIO_STATE_UNLOCK(state) ((void)state) +-#endif ++#define Future_Check(state, obj) \ ++ (Future_CheckExact(state, obj) \ ++ || PyObject_TypeCheck(obj, state->FutureType)) ++ ++#define Task_Check(state, obj) \ ++ (Task_CheckExact(state, obj) \ ++ || PyObject_TypeCheck(obj, state->TaskType)) ++ ++// This macro is optimized to quickly return for native Future *or* Task ++// objects by inlining fast "exact" checks to be called first. ++#define TaskOrFuture_Check(state, obj) \ ++ (Task_CheckExact(state, obj) \ ++ || Future_CheckExact(state, obj) \ ++ || PyObject_TypeCheck(obj, state->FutureType) \ ++ || PyObject_TypeCheck(obj, state->TaskType)) ++ ++typedef struct _Py_AsyncioModuleDebugOffsets { ++ struct _asyncio_task_object { ++ uint64_t size; ++ uint64_t task_name; ++ uint64_t task_awaited_by; ++ uint64_t task_is_task; ++ uint64_t task_awaited_by_is_set; ++ uint64_t task_coro; ++ } asyncio_task_object; ++ struct _asyncio_thread_state { ++ uint64_t size; ++ uint64_t asyncio_running_loop; ++ uint64_t asyncio_running_task; ++ } asyncio_thread_state; ++} Py_AsyncioModuleDebugOffsets; ++ ++GENERATE_DEBUG_SECTION(AsyncioDebug, Py_AsyncioModuleDebugOffsets AsyncioDebug) ++ = {.asyncio_task_object = { ++ .size = sizeof(TaskObj), ++ .task_name = offsetof(TaskObj, task_name), ++ .task_awaited_by = offsetof(TaskObj, task_awaited_by), ++ .task_is_task = offsetof(TaskObj, task_is_task), ++ .task_awaited_by_is_set = offsetof(TaskObj, task_awaited_by_is_set), ++ .task_coro = offsetof(TaskObj, task_coro), ++ }, ++ .asyncio_thread_state = { ++ .size = sizeof(_PyThreadStateImpl), ++ .asyncio_running_loop = offsetof(_PyThreadStateImpl, asyncio_running_loop), ++ .asyncio_running_task = offsetof(_PyThreadStateImpl, asyncio_running_task), ++ }}; + + /* State of the _asyncio module */ + typedef struct { +-#ifdef Py_GIL_DISABLED +- PyMutex mutex; +-#endif + PyTypeObject *FutureIterType; + PyTypeObject *TaskStepMethWrapper_Type; + PyTypeObject *FutureType; +@@ -136,21 +177,6 @@ + /* Counter for autogenerated Task names */ + uint64_t task_name_counter; + +- /* Circular linked-list of all tasks which are instances of asyncio.Task or subclasses +- of it. Third party tasks implementations which don't inherit from +- asyncio.Task are tracked separately using the 'non_asyncio_tasks' WeakSet. +- `first` is used as a sentinel to mark the end of the linked-list. It avoids one +- branch in checking for empty list when adding a new task, the list is +- initialized with `head`, `head->next` and `head->prev` pointing to `first` +- to mark an empty list. +- +- */ +- +- struct { +- TaskObj first; +- TaskObj *head; +- } asyncio_tasks; +- + } asyncio_state; + + static inline asyncio_state * +@@ -196,6 +222,22 @@ + task_step_handle_result_impl(asyncio_state *state, TaskObj *task, PyObject *result); + + ++static void ++clear_task_coro(TaskObj *task) ++{ ++ Py_CLEAR(task->task_coro); ++} ++ ++ ++static void ++set_task_coro(TaskObj *task, PyObject *coro) ++{ ++ assert(coro != NULL); ++ Py_INCREF(coro); ++ Py_XSETREF(task->task_coro, coro); ++} ++ ++ + static int + _is_coroutine(asyncio_state *state, PyObject *coro) + { +@@ -375,6 +417,8 @@ + static int + future_schedule_callbacks(asyncio_state *state, FutureObj *fut) + { ++ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(fut); ++ + if (fut->fut_callback0 != NULL) { + /* There's a 1st callback */ + +@@ -446,10 +490,13 @@ + Py_CLEAR(fut->fut_source_tb); + Py_CLEAR(fut->fut_cancel_msg); + Py_CLEAR(fut->fut_cancelled_exc); ++ Py_CLEAR(fut->fut_awaited_by); + + fut->fut_state = STATE_PENDING; + fut->fut_log_tb = 0; + fut->fut_blocking = 0; ++ fut->fut_awaited_by_is_set = 0; ++ fut->fut_is_task = 0; + + if (loop == Py_None) { + asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut); +@@ -489,9 +536,86 @@ + return 0; + } + ++static int ++future_awaited_by_add(asyncio_state *state, FutureObj *fut, PyObject *thing) ++{ ++ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(fut); ++ // We only want to support native asyncio Futures. ++ // For further insight see the comment in the Python ++ // implementation of "future_add_to_awaited_by()". ++ assert(TaskOrFuture_Check(state, fut)); ++ assert(TaskOrFuture_Check(state, thing)); ++ ++ /* Most futures/task are only awaited by one entity, so we want ++ to avoid always creating a set for `fut_awaited_by`. ++ */ ++ if (fut->fut_awaited_by == NULL) { ++ assert(!fut->fut_awaited_by_is_set); ++ Py_INCREF(thing); ++ fut->fut_awaited_by = thing; ++ return 0; ++ } ++ ++ if (fut->fut_awaited_by_is_set) { ++ assert(PySet_CheckExact(fut->fut_awaited_by)); ++ return PySet_Add(fut->fut_awaited_by, thing); ++ } ++ ++ PyObject *set = PySet_New(NULL); ++ if (set == NULL) { ++ return -1; ++ } ++ if (PySet_Add(set, thing)) { ++ Py_DECREF(set); ++ return -1; ++ } ++ if (PySet_Add(set, fut->fut_awaited_by)) { ++ Py_DECREF(set); ++ return -1; ++ } ++ Py_SETREF(fut->fut_awaited_by, set); ++ fut->fut_awaited_by_is_set = 1; ++ return 0; ++} ++ ++static int ++future_awaited_by_discard(asyncio_state *state, FutureObj *fut, PyObject *thing) ++{ ++ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(fut); ++ // We only want to support native asyncio Futures. ++ // For further insight see the comment in the Python ++ // implementation of "future_add_to_awaited_by()". ++ assert(TaskOrFuture_Check(state, fut)); ++ assert(TaskOrFuture_Check(state, thing)); ++ ++ /* Following the semantics of 'set.discard()' here in not ++ raising an error if `thing` isn't in the `awaited_by` "set". ++ */ ++ if (fut->fut_awaited_by == NULL) { ++ return 0; ++ } ++ if (fut->fut_awaited_by == thing) { ++ Py_CLEAR(fut->fut_awaited_by); ++ return 0; ++ } ++ if (fut->fut_awaited_by_is_set) { ++ assert(PySet_CheckExact(fut->fut_awaited_by)); ++ int err = PySet_Discard(fut->fut_awaited_by, thing); ++ if (err < 0) { ++ return -1; ++ } else { ++ return 0; ++ } ++ } ++ return 0; ++} ++ ++ + static PyObject * + future_set_result(asyncio_state *state, FutureObj *fut, PyObject *res) + { ++ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(fut); ++ + if (future_ensure_alive(fut)) { + return NULL; + } +@@ -514,6 +638,8 @@ + static PyObject * + future_set_exception(asyncio_state *state, FutureObj *fut, PyObject *exc) + { ++ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(fut); ++ + PyObject *exc_val = NULL; + + if (fut->fut_state != STATE_PENDING) { +@@ -580,6 +706,8 @@ + static PyObject * + create_cancelled_error(asyncio_state *state, FutureObj *fut) + { ++ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(fut); ++ + PyObject *exc; + if (fut->fut_cancelled_exc != NULL) { + /* transfer ownership */ +@@ -599,6 +727,8 @@ + static void + future_set_cancelled_error(asyncio_state *state, FutureObj *fut) + { ++ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(fut); ++ + PyObject *exc = create_cancelled_error(state, fut); + if (exc == NULL) { + return; +@@ -610,6 +740,8 @@ + static int + future_get_result(asyncio_state *state, FutureObj *fut, PyObject **result) + { ++ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(fut); ++ + if (fut->fut_state == STATE_CANCELLED) { + future_set_cancelled_error(state, fut); + return -1; +@@ -643,6 +775,8 @@ + future_add_done_callback(asyncio_state *state, FutureObj *fut, PyObject *arg, + PyObject *ctx) + { ++ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(fut); ++ + if (!future_is_alive(fut)) { + PyErr_SetString(PyExc_RuntimeError, "uninitialized Future object"); + return NULL; +@@ -717,6 +851,8 @@ + static PyObject * + future_cancel(asyncio_state *state, FutureObj *fut, PyObject *msg) + { ++ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(fut); ++ + fut->fut_log_tb = 0; + + if (fut->fut_state != STATE_PENDING) { +@@ -775,6 +911,8 @@ + Py_CLEAR(fut->fut_source_tb); + Py_CLEAR(fut->fut_cancel_msg); + Py_CLEAR(fut->fut_cancelled_exc); ++ Py_CLEAR(fut->fut_awaited_by); ++ fut->fut_awaited_by_is_set = 0; + PyObject_ClearManagedDict((PyObject *)fut); + return 0; + } +@@ -793,11 +931,13 @@ + Py_VISIT(fut->fut_source_tb); + Py_VISIT(fut->fut_cancel_msg); + Py_VISIT(fut->fut_cancelled_exc); ++ Py_VISIT(fut->fut_awaited_by); + PyObject_VisitManagedDict((PyObject *)fut, visit, arg); + return 0; + } + + /*[clinic input] ++@critical_section + _asyncio.Future.result + + Return the result this future represents. +@@ -809,7 +949,7 @@ + + static PyObject * + _asyncio_Future_result_impl(FutureObj *self) +-/*[clinic end generated code: output=f35f940936a4b1e5 input=49ecf9cf5ec50dc5]*/ ++/*[clinic end generated code: output=f35f940936a4b1e5 input=61d89f48e4c8b670]*/ + { + asyncio_state *state = get_asyncio_state_by_def((PyObject *)self); + PyObject *result; +@@ -838,6 +978,7 @@ + } + + /*[clinic input] ++@critical_section + _asyncio.Future.exception + + cls: defining_class +@@ -853,7 +994,7 @@ + + static PyObject * + _asyncio_Future_exception_impl(FutureObj *self, PyTypeObject *cls) +-/*[clinic end generated code: output=ce75576b187c905b input=3faf15c22acdb60d]*/ ++/*[clinic end generated code: output=ce75576b187c905b input=647d1fd1fc403301]*/ + { + if (!future_is_alive(self)) { + asyncio_state *state = get_asyncio_state_by_cls(cls); +@@ -884,6 +1025,7 @@ + } + + /*[clinic input] ++@critical_section + _asyncio.Future.set_result + + cls: defining_class +@@ -899,7 +1041,7 @@ + static PyObject * + _asyncio_Future_set_result_impl(FutureObj *self, PyTypeObject *cls, + PyObject *result) +-/*[clinic end generated code: output=99afbbe78f99c32d input=d5a41c1e353acc2e]*/ ++/*[clinic end generated code: output=99afbbe78f99c32d input=4069306f03a3b6ee]*/ + { + asyncio_state *state = get_asyncio_state_by_cls(cls); + ENSURE_FUTURE_ALIVE(state, self) +@@ -907,6 +1049,7 @@ + } + + /*[clinic input] ++@critical_section + _asyncio.Future.set_exception + + cls: defining_class +@@ -922,7 +1065,7 @@ + static PyObject * + _asyncio_Future_set_exception_impl(FutureObj *self, PyTypeObject *cls, + PyObject *exception) +-/*[clinic end generated code: output=0a5e8b5a52f058d6 input=a245cd49d3df939b]*/ ++/*[clinic end generated code: output=0a5e8b5a52f058d6 input=b6eab43a389bc966]*/ + { + asyncio_state *state = get_asyncio_state_by_cls(cls); + ENSURE_FUTURE_ALIVE(state, self) +@@ -930,6 +1073,7 @@ + } + + /*[clinic input] ++@critical_section + _asyncio.Future.add_done_callback + + cls: defining_class +@@ -948,7 +1092,7 @@ + static PyObject * + _asyncio_Future_add_done_callback_impl(FutureObj *self, PyTypeObject *cls, + PyObject *fn, PyObject *context) +-/*[clinic end generated code: output=922e9a4cbd601167 input=599261c521458cc2]*/ ++/*[clinic end generated code: output=922e9a4cbd601167 input=37d97f941beb7b3e]*/ + { + asyncio_state *state = get_asyncio_state_by_cls(cls); + if (context == NULL) { +@@ -964,6 +1108,7 @@ + } + + /*[clinic input] ++@critical_section + _asyncio.Future.remove_done_callback + + cls: defining_class +@@ -978,7 +1123,7 @@ + static PyObject * + _asyncio_Future_remove_done_callback_impl(FutureObj *self, PyTypeObject *cls, + PyObject *fn) +-/*[clinic end generated code: output=2da35ccabfe41b98 input=c7518709b86fc747]*/ ++/*[clinic end generated code: output=2da35ccabfe41b98 input=3afbc9f6a673091b]*/ + { + PyObject *newlist; + Py_ssize_t len, i, j=0; +@@ -1087,6 +1232,7 @@ + } + + /*[clinic input] ++@critical_section + _asyncio.Future.cancel + + cls: defining_class +@@ -1103,7 +1249,7 @@ + static PyObject * + _asyncio_Future_cancel_impl(FutureObj *self, PyTypeObject *cls, + PyObject *msg) +-/*[clinic end generated code: output=074956f35904b034 input=bba8f8b786941a94]*/ ++/*[clinic end generated code: output=074956f35904b034 input=44ab4003da839970]*/ + { + asyncio_state *state = get_asyncio_state_by_cls(cls); + ENSURE_FUTURE_ALIVE(state, self) +@@ -1111,6 +1257,7 @@ + } + + /*[clinic input] ++@critical_section + _asyncio.Future.cancelled + + Return True if the future was cancelled. +@@ -1118,7 +1265,7 @@ + + static PyObject * + _asyncio_Future_cancelled_impl(FutureObj *self) +-/*[clinic end generated code: output=145197ced586357d input=943ab8b7b7b17e45]*/ ++/*[clinic end generated code: output=145197ced586357d input=9b8644819a675416]*/ + { + if (future_is_alive(self) && self->fut_state == STATE_CANCELLED) { + Py_RETURN_TRUE; +@@ -1129,6 +1276,7 @@ + } + + /*[clinic input] ++@critical_section + _asyncio.Future.done + + Return True if the future is done. +@@ -1139,7 +1287,7 @@ + + static PyObject * + _asyncio_Future_done_impl(FutureObj *self) +-/*[clinic end generated code: output=244c5ac351145096 input=28d7b23fdb65d2ac]*/ ++/*[clinic end generated code: output=244c5ac351145096 input=7204d3cc63bef7f3]*/ + { + if (!future_is_alive(self) || self->fut_state == STATE_PENDING) { + Py_RETURN_FALSE; +@@ -1150,6 +1298,7 @@ + } + + /*[clinic input] ++@critical_section + _asyncio.Future.get_loop + + cls: defining_class +@@ -1160,17 +1309,56 @@ + + static PyObject * + _asyncio_Future_get_loop_impl(FutureObj *self, PyTypeObject *cls) +-/*[clinic end generated code: output=f50ea6c374d9ee97 input=163c2c498b45a1f0]*/ ++/*[clinic end generated code: output=f50ea6c374d9ee97 input=f3ce629bfd9f45c1]*/ + { + asyncio_state *state = get_asyncio_state_by_cls(cls); + ENSURE_FUTURE_ALIVE(state, self) + return Py_NewRef(self->fut_loop); + } + ++/*[clinic input] ++@critical_section ++@getter ++_asyncio.Future._asyncio_awaited_by ++[clinic start generated code]*/ ++ ++static PyObject * ++_asyncio_Future__asyncio_awaited_by_get_impl(FutureObj *self) ++/*[clinic end generated code: output=932af76d385d2e2a input=64c1783df2d44d2b]*/ ++{ ++ /* Implementation of a Python getter. */ ++ if (self->fut_awaited_by == NULL) { ++ Py_RETURN_NONE; ++ } ++ if (self->fut_awaited_by_is_set) { ++ /* Already a set, just wrap it into a frozen set and return. */ ++ assert(PySet_CheckExact(self->fut_awaited_by)); ++ return PyFrozenSet_New(self->fut_awaited_by); ++ } ++ ++ PyObject *set = PyFrozenSet_New(NULL); ++ if (set == NULL) { ++ return NULL; ++ } ++ if (PySet_Add(set, self->fut_awaited_by)) { ++ Py_DECREF(set); ++ return NULL; ++ } ++ return set; ++} ++ ++ ++/*[clinic input] ++@critical_section ++@getter ++_asyncio.Future._asyncio_future_blocking ++[clinic start generated code]*/ ++ + static PyObject * +-FutureObj_get_blocking(FutureObj *fut, void *Py_UNUSED(ignored)) ++_asyncio_Future__asyncio_future_blocking_get_impl(FutureObj *self) ++/*[clinic end generated code: output=a558a2c51e38823b input=58da92efc03b617d]*/ + { +- if (future_is_alive(fut) && fut->fut_blocking) { ++ if (future_is_alive(self) && self->fut_blocking) { + Py_RETURN_TRUE; + } + else { +@@ -1178,31 +1366,47 @@ + } + } + ++/*[clinic input] ++@critical_section ++@setter ++_asyncio.Future._asyncio_future_blocking ++[clinic start generated code]*/ ++ + static int +-FutureObj_set_blocking(FutureObj *fut, PyObject *val, void *Py_UNUSED(ignored)) ++_asyncio_Future__asyncio_future_blocking_set_impl(FutureObj *self, ++ PyObject *value) ++/*[clinic end generated code: output=0686d1cb024a7453 input=3fd4a5f95df788b7]*/ ++ + { +- if (future_ensure_alive(fut)) { ++ if (future_ensure_alive(self)) { + return -1; + } +- if (val == NULL) { ++ if (value == NULL) { + PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); + return -1; + } + +- int is_true = PyObject_IsTrue(val); ++ int is_true = PyObject_IsTrue(value); + if (is_true < 0) { + return -1; + } +- fut->fut_blocking = is_true; ++ self->fut_blocking = is_true; + return 0; + } + ++/*[clinic input] ++@critical_section ++@getter ++_asyncio.Future._log_traceback ++[clinic start generated code]*/ ++ + static PyObject * +-FutureObj_get_log_traceback(FutureObj *fut, void *Py_UNUSED(ignored)) ++_asyncio_Future__log_traceback_get_impl(FutureObj *self) ++/*[clinic end generated code: output=2724433b238593c7 input=91e5144ea4117d8e]*/ + { +- asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut); +- ENSURE_FUTURE_ALIVE(state, fut) +- if (fut->fut_log_tb) { ++ asyncio_state *state = get_asyncio_state_by_def((PyObject *)self); ++ ENSURE_FUTURE_ALIVE(state, self) ++ if (self->fut_log_tb) { + Py_RETURN_TRUE; + } + else { +@@ -1210,14 +1414,21 @@ + } + } + ++/*[clinic input] ++@critical_section ++@setter ++_asyncio.Future._log_traceback ++[clinic start generated code]*/ ++ + static int +-FutureObj_set_log_traceback(FutureObj *fut, PyObject *val, void *Py_UNUSED(ignored)) ++_asyncio_Future__log_traceback_set_impl(FutureObj *self, PyObject *value) ++/*[clinic end generated code: output=9ce8e19504f42f54 input=30ac8217754b08c2]*/ + { +- if (val == NULL) { ++ if (value == NULL) { + PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); + return -1; + } +- int is_true = PyObject_IsTrue(val); ++ int is_true = PyObject_IsTrue(value); + if (is_true < 0) { + return -1; + } +@@ -1226,31 +1437,44 @@ + "_log_traceback can only be set to False"); + return -1; + } +- fut->fut_log_tb = is_true; ++ self->fut_log_tb = is_true; + return 0; + } ++/*[clinic input] ++@critical_section ++@getter ++_asyncio.Future._loop ++[clinic start generated code]*/ + + static PyObject * +-FutureObj_get_loop(FutureObj *fut, void *Py_UNUSED(ignored)) ++_asyncio_Future__loop_get_impl(FutureObj *self) ++/*[clinic end generated code: output=5ba31563eecfeedf input=0337130bc5781670]*/ + { +- if (!future_is_alive(fut)) { ++ if (!future_is_alive(self)) { + Py_RETURN_NONE; + } +- return Py_NewRef(fut->fut_loop); ++ return Py_NewRef(self->fut_loop); + } + ++/*[clinic input] ++@critical_section ++@getter ++_asyncio.Future._callbacks ++[clinic start generated code]*/ ++ + static PyObject * +-FutureObj_get_callbacks(FutureObj *fut, void *Py_UNUSED(ignored)) ++_asyncio_Future__callbacks_get_impl(FutureObj *self) ++/*[clinic end generated code: output=b40d360505fcc583 input=7a466649530c01bb]*/ + { +- asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut); +- ENSURE_FUTURE_ALIVE(state, fut) ++ asyncio_state *state = get_asyncio_state_by_def((PyObject *)self); ++ ENSURE_FUTURE_ALIVE(state, self) + + Py_ssize_t len = 0; +- if (fut->fut_callback0 != NULL) { ++ if (self->fut_callback0 != NULL) { + len++; + } +- if (fut->fut_callbacks != NULL) { +- len += PyList_GET_SIZE(fut->fut_callbacks); ++ if (self->fut_callbacks != NULL) { ++ len += PyList_GET_SIZE(self->fut_callbacks); + } + + if (len == 0) { +@@ -1263,22 +1487,22 @@ + } + + Py_ssize_t i = 0; +- if (fut->fut_callback0 != NULL) { ++ if (self->fut_callback0 != NULL) { + PyObject *tup0 = PyTuple_New(2); + if (tup0 == NULL) { + Py_DECREF(callbacks); + return NULL; + } +- PyTuple_SET_ITEM(tup0, 0, Py_NewRef(fut->fut_callback0)); +- assert(fut->fut_context0 != NULL); +- PyTuple_SET_ITEM(tup0, 1, Py_NewRef(fut->fut_context0)); ++ PyTuple_SET_ITEM(tup0, 0, Py_NewRef(self->fut_callback0)); ++ assert(self->fut_context0 != NULL); ++ PyTuple_SET_ITEM(tup0, 1, Py_NewRef(self->fut_context0)); + PyList_SET_ITEM(callbacks, i, tup0); + i++; + } + +- if (fut->fut_callbacks != NULL) { +- for (Py_ssize_t j = 0; j < PyList_GET_SIZE(fut->fut_callbacks); j++) { +- PyObject *cb = PyList_GET_ITEM(fut->fut_callbacks, j); ++ if (self->fut_callbacks != NULL) { ++ for (Py_ssize_t j = 0; j < PyList_GET_SIZE(self->fut_callbacks); j++) { ++ PyObject *cb = PyList_GET_ITEM(self->fut_callbacks, j); + Py_INCREF(cb); + PyList_SET_ITEM(callbacks, i, cb); + i++; +@@ -1288,68 +1512,110 @@ + return callbacks; + } + ++/*[clinic input] ++@critical_section ++@getter ++_asyncio.Future._result ++[clinic start generated code]*/ ++ + static PyObject * +-FutureObj_get_result(FutureObj *fut, void *Py_UNUSED(ignored)) ++_asyncio_Future__result_get_impl(FutureObj *self) ++/*[clinic end generated code: output=6877e8ce97333873 input=624f8e28e67f2636]*/ ++ + { +- asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut); +- ENSURE_FUTURE_ALIVE(state, fut) +- if (fut->fut_result == NULL) { ++ asyncio_state *state = get_asyncio_state_by_def((PyObject *)self); ++ ENSURE_FUTURE_ALIVE(state, self) ++ if (self->fut_result == NULL) { + Py_RETURN_NONE; + } +- return Py_NewRef(fut->fut_result); ++ return Py_NewRef(self->fut_result); + } + ++/*[clinic input] ++@critical_section ++@getter ++_asyncio.Future._exception ++[clinic start generated code]*/ ++ + static PyObject * +-FutureObj_get_exception(FutureObj *fut, void *Py_UNUSED(ignored)) ++_asyncio_Future__exception_get_impl(FutureObj *self) ++/*[clinic end generated code: output=32f2c93b9e021a9b input=1828a1fcac929710]*/ + { +- asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut); +- ENSURE_FUTURE_ALIVE(state, fut) +- if (fut->fut_exception == NULL) { ++ asyncio_state *state = get_asyncio_state_by_def((PyObject *)self); ++ ENSURE_FUTURE_ALIVE(state, self) ++ if (self->fut_exception == NULL) { + Py_RETURN_NONE; + } +- return Py_NewRef(fut->fut_exception); ++ return Py_NewRef(self->fut_exception); + } + ++/*[clinic input] ++@critical_section ++@getter ++_asyncio.Future._source_traceback ++[clinic start generated code]*/ ++ + static PyObject * +-FutureObj_get_source_traceback(FutureObj *fut, void *Py_UNUSED(ignored)) ++_asyncio_Future__source_traceback_get_impl(FutureObj *self) ++/*[clinic end generated code: output=d4f12b09af22f61b input=3c831fbde5da90d0]*/ + { +- if (!future_is_alive(fut) || fut->fut_source_tb == NULL) { ++ if (!future_is_alive(self) || self->fut_source_tb == NULL) { + Py_RETURN_NONE; + } +- return Py_NewRef(fut->fut_source_tb); ++ return Py_NewRef(self->fut_source_tb); + } + ++/*[clinic input] ++@critical_section ++@getter ++_asyncio.Future._cancel_message ++[clinic start generated code]*/ ++ + static PyObject * +-FutureObj_get_cancel_message(FutureObj *fut, void *Py_UNUSED(ignored)) ++_asyncio_Future__cancel_message_get_impl(FutureObj *self) ++/*[clinic end generated code: output=52ef6444f92cedac input=54c12c67082e4eea]*/ + { +- if (fut->fut_cancel_msg == NULL) { ++ if (self->fut_cancel_msg == NULL) { + Py_RETURN_NONE; + } +- return Py_NewRef(fut->fut_cancel_msg); ++ return Py_NewRef(self->fut_cancel_msg); + } + ++/*[clinic input] ++@critical_section ++@setter ++_asyncio.Future._cancel_message ++[clinic start generated code]*/ ++ + static int +-FutureObj_set_cancel_message(FutureObj *fut, PyObject *msg, +- void *Py_UNUSED(ignored)) ++_asyncio_Future__cancel_message_set_impl(FutureObj *self, PyObject *value) ++/*[clinic end generated code: output=0854b2f77bff2209 input=f461d17f2d891fad]*/ + { +- if (msg == NULL) { ++ if (value == NULL) { + PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); + return -1; + } +- Py_INCREF(msg); +- Py_XSETREF(fut->fut_cancel_msg, msg); ++ Py_INCREF(value); ++ Py_XSETREF(self->fut_cancel_msg, value); + return 0; + } + ++/*[clinic input] ++@critical_section ++@getter ++_asyncio.Future._state ++[clinic start generated code]*/ ++ + static PyObject * +-FutureObj_get_state(FutureObj *fut, void *Py_UNUSED(ignored)) ++_asyncio_Future__state_get_impl(FutureObj *self) ++/*[clinic end generated code: output=622f560a3fa69c63 input=7c5ad023a93423ff]*/ + { +- asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut); ++ asyncio_state *state = get_asyncio_state_by_def((PyObject *)self); + PyObject *ret = NULL; + +- ENSURE_FUTURE_ALIVE(state, fut) ++ ENSURE_FUTURE_ALIVE(state, self) + +- switch (fut->fut_state) { ++ switch (self->fut_state) { + case STATE_PENDING: + ret = &_Py_ID(PENDING); + break; +@@ -1375,6 +1641,7 @@ + } + + /*[clinic input] ++@critical_section + _asyncio.Future._make_cancelled_error + + Create the CancelledError to raise if the Future is cancelled. +@@ -1385,7 +1652,7 @@ + + static PyObject * + _asyncio_Future__make_cancelled_error_impl(FutureObj *self) +-/*[clinic end generated code: output=a5df276f6c1213de input=ac6effe4ba795ecc]*/ ++/*[clinic end generated code: output=a5df276f6c1213de input=ccb90df8c3c18bcd]*/ + { + asyncio_state *state = get_asyncio_state_by_def((PyObject *)self); + return create_cancelled_error(state, self); +@@ -1434,7 +1701,8 @@ + if (func != NULL) { + PyObject *res = PyObject_CallOneArg(func, context); + if (res == NULL) { +- PyErr_WriteUnraisable(func); ++ PyErr_FormatUnraisable("Exception ignored while calling asyncio " ++ "function %R", func); + } + else { + Py_DECREF(res); +@@ -1466,23 +1734,17 @@ + {NULL, NULL} /* Sentinel */ + }; + +-#define FUTURE_COMMON_GETSETLIST \ +- {"_state", (getter)FutureObj_get_state, NULL, NULL}, \ +- {"_asyncio_future_blocking", (getter)FutureObj_get_blocking, \ +- (setter)FutureObj_set_blocking, NULL}, \ +- {"_loop", (getter)FutureObj_get_loop, NULL, NULL}, \ +- {"_callbacks", (getter)FutureObj_get_callbacks, NULL, NULL}, \ +- {"_result", (getter)FutureObj_get_result, NULL, NULL}, \ +- {"_exception", (getter)FutureObj_get_exception, NULL, NULL}, \ +- {"_log_traceback", (getter)FutureObj_get_log_traceback, \ +- (setter)FutureObj_set_log_traceback, NULL}, \ +- {"_source_traceback", (getter)FutureObj_get_source_traceback, \ +- NULL, NULL}, \ +- {"_cancel_message", (getter)FutureObj_get_cancel_message, \ +- (setter)FutureObj_set_cancel_message, NULL}, +- + static PyGetSetDef FutureType_getsetlist[] = { +- FUTURE_COMMON_GETSETLIST ++ _ASYNCIO_FUTURE__STATE_GETSETDEF ++ _ASYNCIO_FUTURE__ASYNCIO_FUTURE_BLOCKING_GETSETDEF ++ _ASYNCIO_FUTURE__LOOP_GETSETDEF ++ _ASYNCIO_FUTURE__CALLBACKS_GETSETDEF ++ _ASYNCIO_FUTURE__RESULT_GETSETDEF ++ _ASYNCIO_FUTURE__EXCEPTION_GETSETDEF ++ _ASYNCIO_FUTURE__LOG_TRACEBACK_GETSETDEF ++ _ASYNCIO_FUTURE__SOURCE_TRACEBACK_GETSETDEF ++ _ASYNCIO_FUTURE__CANCEL_MESSAGE_GETSETDEF ++ _ASYNCIO_FUTURE__ASYNCIO_AWAITED_BY_GETSETDEF + {NULL} /* Sentinel */ + }; + +@@ -1561,19 +1823,13 @@ + } + + static PySendResult +-FutureIter_am_send(futureiterobject *it, +- PyObject *Py_UNUSED(arg), +- PyObject **result) ++FutureIter_am_send_lock_held(futureiterobject *it, PyObject **result) + { +- /* arg is unused, see the comment on FutureIter_send for clarification */ +- + PyObject *res; + FutureObj *fut = it->future; ++ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(fut); + + *result = NULL; +- if (fut == NULL) { +- return PYGEN_ERROR; +- } + + if (fut->fut_state == STATE_PENDING) { + if (!fut->fut_blocking) { +@@ -1586,18 +1842,29 @@ + return PYGEN_ERROR; + } + +- it->future = NULL; + res = _asyncio_Future_result_impl(fut); + if (res != NULL) { +- Py_DECREF(fut); + *result = res; + return PYGEN_RETURN; + } + +- Py_DECREF(fut); + return PYGEN_ERROR; + } + ++static PySendResult ++FutureIter_am_send(futureiterobject *it, ++ PyObject *Py_UNUSED(arg), ++ PyObject **result) ++{ ++ /* arg is unused, see the comment on FutureIter_send for clarification */ ++ PySendResult res; ++ Py_BEGIN_CRITICAL_SECTION(it->future); ++ res = FutureIter_am_send_lock_held(it, result); ++ Py_END_CRITICAL_SECTION(); ++ return res; ++} ++ ++ + static PyObject * + FutureIter_iternext(futureiterobject *it) + { +@@ -1784,6 +2051,8 @@ + static PyObject * task_wakeup(TaskObj *, PyObject *); + static PyObject * task_step(asyncio_state *, TaskObj *, PyObject *); + static int task_eager_start(asyncio_state *state, TaskObj *task); ++static inline void clear_ts_asyncio_running_task(PyObject *loop); ++static inline void set_ts_asyncio_running_task(PyObject *loop, PyObject *task); + + /* ----- Task._step wrapper */ + +@@ -1818,7 +2087,11 @@ + return NULL; + } + asyncio_state *state = get_asyncio_state_by_def((PyObject *)o); +- return task_step(state, o->sw_task, o->sw_arg); ++ PyObject *res; ++ Py_BEGIN_CRITICAL_SECTION(o->sw_task); ++ res = task_step(state, o->sw_task, o->sw_arg); ++ Py_END_CRITICAL_SECTION(); ++ return res; + } + + static int +@@ -1894,23 +2167,15 @@ + static void + register_task(asyncio_state *state, TaskObj *task) + { +- ASYNCIO_STATE_LOCK(state); + assert(Task_Check(state, task)); +- assert(task != &state->asyncio_tasks.first); +- if (task->next != NULL) { ++ if (task->task_node.next != NULL) { + // already registered +- goto exit; ++ assert(task->task_node.prev != NULL); ++ return; + } +- assert(task->prev == NULL); +- assert(state->asyncio_tasks.head != NULL); +- +- task->next = state->asyncio_tasks.head; +- task->prev = state->asyncio_tasks.head->prev; +- state->asyncio_tasks.head->prev->next = task; +- state->asyncio_tasks.head->prev = task; +- +-exit: +- ASYNCIO_STATE_UNLOCK(state); ++ _PyThreadStateImpl *tstate = (_PyThreadStateImpl *) _PyThreadState_GET(); ++ struct llist_node *head = &tstate->asyncio_tasks_head; ++ llist_insert_tail(head, &task->task_node); + } + + static int +@@ -1919,25 +2184,38 @@ + return PySet_Add(state->eager_tasks, task); + } + ++static inline void ++unregister_task_safe(TaskObj *task) ++{ ++ if (task->task_node.next == NULL) { ++ // not registered ++ assert(task->task_node.prev == NULL); ++ return; ++ } ++ llist_remove(&task->task_node); ++} ++ + static void + unregister_task(asyncio_state *state, TaskObj *task) + { +- ASYNCIO_STATE_LOCK(state); + assert(Task_Check(state, task)); +- assert(task != &state->asyncio_tasks.first); +- if (task->next == NULL) { +- // not registered +- assert(task->prev == NULL); +- assert(state->asyncio_tasks.head != task); +- goto exit; +- } +- task->next->prev = task->prev; +- task->prev->next = task->next; +- task->next = NULL; +- task->prev = NULL; +- assert(state->asyncio_tasks.head != task); +-exit: +- ASYNCIO_STATE_UNLOCK(state); ++#ifdef Py_GIL_DISABLED ++ // check if we are in the same thread ++ // if so, we can avoid locking ++ if (task->task_tid == _Py_ThreadId()) { ++ unregister_task_safe(task); ++ } ++ else { ++ // we are in a different thread ++ // stop the world then check and remove the task ++ PyThreadState *tstate = _PyThreadState_GET(); ++ _PyEval_StopTheWorld(tstate->interp); ++ unregister_task_safe(task); ++ _PyEval_StartTheWorld(tstate->interp); ++ } ++#else ++ unregister_task_safe(task); ++#endif + } + + static int +@@ -1963,7 +2241,10 @@ + Py_DECREF(item); + return -1; + } +- Py_DECREF(item); ++ ++ assert(task == item); ++ Py_CLEAR(item); ++ set_ts_asyncio_running_task(loop, task); + return 0; + } + +@@ -1988,7 +2269,6 @@ + + static int + leave_task(asyncio_state *state, PyObject *loop, PyObject *task) +-/*[clinic end generated code: output=0ebf6db4b858fb41 input=51296a46313d1ad8]*/ + { + int res = _PyDict_DelItemIf(state->current_tasks, loop, + leave_task_predicate, task); +@@ -1996,6 +2276,7 @@ + // task was not found + return err_leave_task(Py_None, task); + } ++ clear_ts_asyncio_running_task(loop); + return res; + } + +@@ -2022,6 +2303,7 @@ + { + PyObject *prev_task; + ++ clear_ts_asyncio_running_task(loop); + if (task == Py_None) { + if (PyDict_Pop(state->current_tasks, loop, &prev_task) < 0) { + return NULL; +@@ -2041,9 +2323,63 @@ + Py_BEGIN_CRITICAL_SECTION(current_tasks); + prev_task = swap_current_task_lock_held(current_tasks, loop, hash, task); + Py_END_CRITICAL_SECTION(); ++ set_ts_asyncio_running_task(loop, task); + return prev_task; + } + ++static inline void ++set_ts_asyncio_running_task(PyObject *loop, PyObject *task) ++{ ++ // We want to enable debuggers and profilers to be able to quickly ++ // introspect the asyncio running state from another process. ++ // When we do that, we need to essentially traverse the address space ++ // of a Python process and understand what every Python thread in it is ++ // currently doing, mainly: ++ // ++ // * current frame ++ // * current asyncio task ++ // ++ // A naive solution would be to require profilers and debuggers to ++ // find the current task in the "_asynciomodule" module state, but ++ // unfortunately that would require a lot of complicated remote ++ // memory reads and logic, as Python's dict is a notoriously complex ++ // and ever-changing data structure. ++ // ++ // So the easier solution is to put a strong reference to the currently ++ // running `asyncio.Task` on the current thread state (the current loop ++ // is also stored there.) ++ _PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET(); ++ if (ts->asyncio_running_loop == loop) { ++ // Protect from a situation when someone calls this method ++ // from another thread. This shouldn't ever happen though, ++ // as `enter_task` and `leave_task` can either be called by: ++ // ++ // - `asyncio.Task` itself, in `Task.__step()`. That method ++ // can only be called by the event loop itself. ++ // ++ // - third-party Task "from scratch" implementations, that ++ // our `capture_call_graph` API doesn't support anyway. ++ // ++ // That said, we still want to make sure we don't end up in ++ // a broken state, so we check that we're in the correct thread ++ // by comparing the *loop* argument to the event loop running ++ // in the current thread. If they match we know we're in the ++ // right thread, as asyncio event loops don't change threads. ++ assert(ts->asyncio_running_task == NULL); ++ ts->asyncio_running_task = Py_NewRef(task); ++ } ++} ++ ++static inline void ++clear_ts_asyncio_running_task(PyObject *loop) ++{ ++ // See comment in set_ts_asyncio_running_task() for details. ++ _PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET(); ++ if (ts->asyncio_running_loop == NULL || ts->asyncio_running_loop == loop) { ++ Py_CLEAR(ts->asyncio_running_task); ++ } ++} ++ + /* ----- Task */ + + /*[clinic input] +@@ -2068,6 +2404,7 @@ + if (future_init((FutureObj*)self, loop)) { + return -1; + } ++ self->task_is_task = 1; + + asyncio_state *state = get_asyncio_state_by_def((PyObject *)self); + int is_coro = is_coroutine(state, coro); +@@ -2092,11 +2429,13 @@ + } + + Py_CLEAR(self->task_fut_waiter); ++#ifdef Py_GIL_DISABLED ++ self->task_tid = _Py_ThreadId(); ++#endif + self->task_must_cancel = 0; + self->task_log_destroy_pending = 1; + self->task_num_cancels_requested = 0; +- Py_INCREF(coro); +- Py_XSETREF(self->task_coro, coro); ++ set_task_coro(self, coro); + + if (name == Py_None) { + // optimization: defer task name formatting +@@ -2136,6 +2475,11 @@ + if (task_call_step_soon(state, self, NULL)) { + return -1; + } ++#ifdef Py_GIL_DISABLED ++ // This is required so that _Py_TryIncref(self) ++ // works correctly in non-owning threads. ++ _PyObject_SetMaybeWeakref((PyObject *)self); ++#endif + register_task(state, self); + return 0; + } +@@ -2144,8 +2488,8 @@ + TaskObj_clear(TaskObj *task) + { + (void)FutureObj_clear((FutureObj*) task); ++ clear_task_coro(task); + Py_CLEAR(task->task_context); +- Py_CLEAR(task->task_coro); + Py_CLEAR(task->task_name); + Py_CLEAR(task->task_fut_waiter); + return 0; +@@ -2170,14 +2514,22 @@ + Py_VISIT(fut->fut_source_tb); + Py_VISIT(fut->fut_cancel_msg); + Py_VISIT(fut->fut_cancelled_exc); ++ Py_VISIT(fut->fut_awaited_by); + PyObject_VisitManagedDict((PyObject *)fut, visit, arg); + return 0; + } + ++/*[clinic input] ++@critical_section ++@getter ++_asyncio.Task._log_destroy_pending ++[clinic start generated code]*/ ++ + static PyObject * +-TaskObj_get_log_destroy_pending(TaskObj *task, void *Py_UNUSED(ignored)) ++_asyncio_Task__log_destroy_pending_get_impl(TaskObj *self) ++/*[clinic end generated code: output=e6c2a47d029ac93b input=17127298cd4c720b]*/ + { +- if (task->task_log_destroy_pending) { ++ if (self->task_log_destroy_pending) { + Py_RETURN_TRUE; + } + else { +@@ -2185,25 +2537,40 @@ + } + } + ++/*[clinic input] ++@critical_section ++@setter ++_asyncio.Task._log_destroy_pending ++[clinic start generated code]*/ ++ + static int +-TaskObj_set_log_destroy_pending(TaskObj *task, PyObject *val, void *Py_UNUSED(ignored)) ++_asyncio_Task__log_destroy_pending_set_impl(TaskObj *self, PyObject *value) ++/*[clinic end generated code: output=7ebc030bb92ec5ce input=49b759c97d1216a4]*/ + { +- if (val == NULL) { ++ if (value == NULL) { + PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); + return -1; + } +- int is_true = PyObject_IsTrue(val); ++ int is_true = PyObject_IsTrue(value); + if (is_true < 0) { + return -1; + } +- task->task_log_destroy_pending = is_true; ++ self->task_log_destroy_pending = is_true; + return 0; + } + ++ ++/*[clinic input] ++@critical_section ++@getter ++_asyncio.Task._must_cancel ++[clinic start generated code]*/ ++ + static PyObject * +-TaskObj_get_must_cancel(TaskObj *task, void *Py_UNUSED(ignored)) ++_asyncio_Task__must_cancel_get_impl(TaskObj *self) ++/*[clinic end generated code: output=70e79b900996c363 input=2d04529fb23feedf]*/ + { +- if (task->task_must_cancel) { ++ if (self->task_must_cancel) { + Py_RETURN_TRUE; + } + else { +@@ -2211,21 +2578,36 @@ + } + } + ++/*[clinic input] ++@critical_section ++@getter ++_asyncio.Task._coro ++[clinic start generated code]*/ ++ + static PyObject * +-TaskObj_get_coro(TaskObj *task, void *Py_UNUSED(ignored)) ++_asyncio_Task__coro_get_impl(TaskObj *self) ++/*[clinic end generated code: output=a2726012ab5fd531 input=323c31a272020624]*/ + { +- if (task->task_coro) { +- return Py_NewRef(task->task_coro); ++ if (self->task_coro) { ++ return Py_NewRef(self->task_coro); + } + + Py_RETURN_NONE; + } + ++ ++/*[clinic input] ++@critical_section ++@getter ++_asyncio.Task._fut_waiter ++[clinic start generated code]*/ ++ + static PyObject * +-TaskObj_get_fut_waiter(TaskObj *task, void *Py_UNUSED(ignored)) ++_asyncio_Task__fut_waiter_get_impl(TaskObj *self) ++/*[clinic end generated code: output=c4f966b847fefcdf input=4d1005d725e72db7]*/ + { +- if (task->task_fut_waiter) { +- return Py_NewRef(task->task_fut_waiter); ++ if (self->task_fut_waiter) { ++ return Py_NewRef(self->task_fut_waiter); + } + + Py_RETURN_NONE; +@@ -2241,6 +2623,7 @@ + + + /*[clinic input] ++@critical_section + _asyncio.Task._make_cancelled_error + + Create the CancelledError to raise if the Task is cancelled. +@@ -2251,7 +2634,7 @@ + + static PyObject * + _asyncio_Task__make_cancelled_error_impl(TaskObj *self) +-/*[clinic end generated code: output=55a819e8b4276fab input=52c0e32de8e2f840]*/ ++/*[clinic end generated code: output=55a819e8b4276fab input=2d3213be0cb02390]*/ + { + FutureObj *fut = (FutureObj*)self; + return _asyncio_Future__make_cancelled_error_impl(fut); +@@ -2259,6 +2642,7 @@ + + + /*[clinic input] ++@critical_section + _asyncio.Task.cancel + + msg: object = None +@@ -2287,7 +2671,7 @@ + + static PyObject * + _asyncio_Task_cancel_impl(TaskObj *self, PyObject *msg) +-/*[clinic end generated code: output=c66b60d41c74f9f1 input=7bb51bf25974c783]*/ ++/*[clinic end generated code: output=c66b60d41c74f9f1 input=6125d45b9a6a5abd]*/ + { + self->task_log_tb = 0; + +@@ -2332,6 +2716,7 @@ + } + + /*[clinic input] ++@critical_section + _asyncio.Task.cancelling + + Return the count of the task's cancellation requests. +@@ -2342,13 +2727,14 @@ + + static PyObject * + _asyncio_Task_cancelling_impl(TaskObj *self) +-/*[clinic end generated code: output=803b3af96f917d7e input=b625224d310cbb17]*/ ++/*[clinic end generated code: output=803b3af96f917d7e input=5ef89b1b38f080ee]*/ + /*[clinic end generated code]*/ + { + return PyLong_FromLong(self->task_num_cancels_requested); + } + + /*[clinic input] ++@critical_section + _asyncio.Task.uncancel + + Decrement the task's count of cancellation requests. +@@ -2361,7 +2747,7 @@ + + static PyObject * + _asyncio_Task_uncancel_impl(TaskObj *self) +-/*[clinic end generated code: output=58184d236a817d3c input=68f81a4b90b46be2]*/ ++/*[clinic end generated code: output=58184d236a817d3c input=cb3220b0e5afd61d]*/ + /*[clinic end generated code]*/ + { + if (self->task_num_cancels_requested > 0) { +@@ -2475,12 +2861,13 @@ + } + + /*[clinic input] ++@critical_section + _asyncio.Task.get_coro + [clinic start generated code]*/ + + static PyObject * + _asyncio_Task_get_coro_impl(TaskObj *self) +-/*[clinic end generated code: output=bcac27c8cc6c8073 input=d2e8606c42a7b403]*/ ++/*[clinic end generated code: output=bcac27c8cc6c8073 input=a47f81427e39fe0c]*/ + { + if (self->task_coro) { + return Py_NewRef(self->task_coro); +@@ -2501,12 +2888,13 @@ + } + + /*[clinic input] ++@critical_section + _asyncio.Task.get_name + [clinic start generated code]*/ + + static PyObject * + _asyncio_Task_get_name_impl(TaskObj *self) +-/*[clinic end generated code: output=0ecf1570c3b37a8f input=a4a6595d12f4f0f8]*/ ++/*[clinic end generated code: output=0ecf1570c3b37a8f input=92a8f30c85034249]*/ + { + if (self->task_name) { + if (PyLong_CheckExact(self->task_name)) { +@@ -2523,6 +2911,7 @@ + } + + /*[clinic input] ++@critical_section + _asyncio.Task.set_name + + value: object +@@ -2530,8 +2919,8 @@ + [clinic start generated code]*/ + + static PyObject * +-_asyncio_Task_set_name(TaskObj *self, PyObject *value) +-/*[clinic end generated code: output=138a8d51e32057d6 input=a8359b6e65f8fd31]*/ ++_asyncio_Task_set_name_impl(TaskObj *self, PyObject *value) ++/*[clinic end generated code: output=f88ff4c0d64a9a6f input=e8d400ad64bad799]*/ + { + if (!PyUnicode_CheckExact(value)) { + value = PyObject_Str(value); +@@ -2549,15 +2938,6 @@ + static void + TaskObj_finalize(TaskObj *task) + { +- asyncio_state *state = get_asyncio_state_by_def((PyObject *)task); +- // Unregister the task from the linked list of tasks. +- // Since task is a native task, we directly call the +- // unregister_task function. Third party event loops +- // should use the asyncio._unregister_task function. +- // See https://docs.python.org/3/library/asyncio-extending.html#task-lifetime-support +- +- unregister_task(state, task); +- + PyObject *context; + PyObject *message = NULL; + PyObject *func; +@@ -2597,7 +2977,8 @@ + if (func != NULL) { + PyObject *res = PyObject_CallOneArg(func, context); + if (res == NULL) { +- PyErr_WriteUnraisable(func); ++ PyErr_FormatUnraisable("Exception ignored while calling asyncio " ++ "function %R", func); + } + else { + Py_DECREF(res); +@@ -2642,12 +3023,10 @@ + }; + + static PyGetSetDef TaskType_getsetlist[] = { +- FUTURE_COMMON_GETSETLIST +- {"_log_destroy_pending", (getter)TaskObj_get_log_destroy_pending, +- (setter)TaskObj_set_log_destroy_pending, NULL}, +- {"_must_cancel", (getter)TaskObj_get_must_cancel, NULL, NULL}, +- {"_coro", (getter)TaskObj_get_coro, NULL, NULL}, +- {"_fut_waiter", (getter)TaskObj_get_fut_waiter, NULL, NULL}, ++ _ASYNCIO_TASK__LOG_DESTROY_PENDING_GETSETDEF ++ _ASYNCIO_TASK__MUST_CANCEL_GETSETDEF ++ _ASYNCIO_TASK__CORO_GETSETDEF ++ _ASYNCIO_TASK__FUT_WAITER_GETSETDEF + {NULL} /* Sentinel */ + }; + +@@ -2683,8 +3062,15 @@ + { + TaskObj *task = (TaskObj *)self; + +- if (PyObject_CallFinalizerFromDealloc(self) < 0) { +- // resurrected. ++ _PyObject_ResurrectStart(self); ++ // Unregister the task here so that even if any subclass of Task ++ // which doesn't end up calling TaskObj_finalize not crashes. ++ asyncio_state *state = get_asyncio_state_by_def(self); ++ unregister_task(state, task); ++ ++ PyObject_CallFinalizer(self); ++ ++ if (_PyObject_ResurrectEnd(self)) { + return; + } + +@@ -2762,6 +3148,8 @@ + static PyObject * + task_step_impl(asyncio_state *state, TaskObj *task, PyObject *exc) + { ++ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(task); ++ + int clear_exc = 0; + PyObject *result = NULL; + PyObject *coro; +@@ -2891,6 +3279,8 @@ + static PyObject * + task_step_handle_result_impl(asyncio_state *state, TaskObj *task, PyObject *result) + { ++ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(task); ++ + int res; + PyObject *o; + +@@ -2913,6 +3303,13 @@ + if (!fut->fut_blocking) { + goto yield_insteadof_yf; + } ++ int res; ++ Py_BEGIN_CRITICAL_SECTION(result); ++ res = future_awaited_by_add(state, (FutureObj *)result, (PyObject *)task); ++ Py_END_CRITICAL_SECTION(); ++ if (res) { ++ goto fail; ++ } + + fut->fut_blocking = 0; + +@@ -2921,8 +3318,10 @@ + if (wrapper == NULL) { + goto fail; + } ++ Py_BEGIN_CRITICAL_SECTION(result); + tmp = future_add_done_callback(state, + (FutureObj*)result, wrapper, task->task_context); ++ Py_END_CRITICAL_SECTION(); + Py_DECREF(wrapper); + if (tmp == NULL) { + goto fail; +@@ -3001,6 +3400,16 @@ + goto yield_insteadof_yf; + } + ++ if (TaskOrFuture_Check(state, result)) { ++ int res; ++ Py_BEGIN_CRITICAL_SECTION(result); ++ res = future_awaited_by_add(state, (FutureObj *)result, (PyObject *)task); ++ Py_END_CRITICAL_SECTION(); ++ if (res) { ++ goto fail; ++ } ++ } ++ + /* result._asyncio_future_blocking = False */ + if (PyObject_SetAttr( + result, &_Py_ID(_asyncio_future_blocking), Py_False) == -1) { +@@ -3164,7 +3573,10 @@ + + int retval = 0; + +- PyObject *stepres = task_step_impl(state, task, NULL); ++ PyObject *stepres; ++ Py_BEGIN_CRITICAL_SECTION(task); ++ stepres = task_step_impl(state, task, NULL); ++ Py_END_CRITICAL_SECTION(); + if (stepres == NULL) { + PyObject *exc = PyErr_GetRaisedException(); + _PyErr_ChainExceptions1(exc); +@@ -3194,23 +3606,38 @@ + register_task(state, task); + } else { + // This seems to really help performance on pyperformance benchmarks +- Py_CLEAR(task->task_coro); ++ clear_task_coro(task); + } + + return retval; + } + + static PyObject * +-task_wakeup(TaskObj *task, PyObject *o) ++task_wakeup_lock_held(TaskObj *task, PyObject *o) + { ++ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(task); ++ + PyObject *result; + assert(o); + + asyncio_state *state = get_asyncio_state_by_def((PyObject *)task); ++ ++ if (TaskOrFuture_Check(state, o)) { ++ int res; ++ Py_BEGIN_CRITICAL_SECTION(o); ++ res = future_awaited_by_discard(state, (FutureObj *)o, (PyObject *)task); ++ Py_END_CRITICAL_SECTION(); ++ if (res) { ++ return NULL; ++ } ++ } ++ + if (Future_CheckExact(state, o) || Task_CheckExact(state, o)) { + PyObject *fut_result = NULL; +- int res = future_get_result(state, (FutureObj*)o, &fut_result); +- ++ int res; ++ Py_BEGIN_CRITICAL_SECTION(o); ++ res = future_get_result(state, (FutureObj*)o, &fut_result); ++ Py_END_CRITICAL_SECTION(); + switch(res) { + case -1: + assert(fut_result == NULL); +@@ -3244,6 +3671,16 @@ + return result; + } + ++static PyObject * ++task_wakeup(TaskObj *task, PyObject *o) ++{ ++ PyObject *res; ++ Py_BEGIN_CRITICAL_SECTION(task); ++ res = task_wakeup_lock_held(task, o); ++ Py_END_CRITICAL_SECTION(); ++ return res; ++} ++ + + /*********************** Functions **************************/ + +@@ -3551,6 +3988,20 @@ + static inline int + add_one_task(asyncio_state *state, PyObject *tasks, PyObject *task, PyObject *loop) + { ++ assert(PySet_CheckExact(tasks)); ++ if (Task_CheckExact(state, task)) { ++ int pending = 0; ++ Py_BEGIN_CRITICAL_SECTION(task); ++ pending = ((TaskObj *)task)->task_state == STATE_PENDING && ((TaskObj *)task)->task_loop == loop; ++ Py_END_CRITICAL_SECTION(); ++ if (pending) { ++ if (PySet_Add(tasks, task) < 0) { ++ return -1; ++ } ++ } ++ return 0; ++ } ++ + PyObject *done = PyObject_CallMethodNoArgs(task, &_Py_ID(done)); + if (done == NULL) { + return -1; +@@ -3573,6 +4024,57 @@ + return 0; + } + ++static inline int ++add_tasks_llist(struct llist_node *head, PyListObject *tasks) ++{ ++ struct llist_node *node; ++ llist_for_each_safe(node, head) { ++ TaskObj *task = llist_data(node, TaskObj, task_node); ++ // The linked list holds borrowed references to task ++ // as such it is possible that the task is concurrently ++ // deallocated while added to this list. ++ // To protect against concurrent deallocations, ++ // we first try to incref the task which would fail ++ // if it is concurrently getting deallocated in another thread, ++ // otherwise it gets added to the list. ++ if (_Py_TryIncref((PyObject *)task)) { ++ if (_PyList_AppendTakeRef(tasks, (PyObject *)task) < 0) { ++ // do not call any escaping calls here while the world is stopped. ++ return -1; ++ } ++ } ++ } ++ return 0; ++} ++ ++static inline int ++add_tasks_interp(PyInterpreterState *interp, PyListObject *tasks) ++{ ++#ifdef Py_GIL_DISABLED ++ assert(interp->stoptheworld.world_stopped); ++#endif ++ // Start traversing from interpreter's linked list ++ struct llist_node *head = &interp->asyncio_tasks_head; ++ ++ if (add_tasks_llist(head, tasks) < 0) { ++ return -1; ++ } ++ ++ int ret = 0; ++ // traverse the task lists of thread states ++ _Py_FOR_EACH_TSTATE_BEGIN(interp, p) { ++ _PyThreadStateImpl *ts = (_PyThreadStateImpl *)p; ++ head = &ts->asyncio_tasks_head; ++ if (add_tasks_llist(head, tasks) < 0) { ++ ret = -1; ++ goto exit; ++ } ++ } ++exit: ++ _Py_FOR_EACH_TSTATE_END(interp); ++ return ret; ++} ++ + /*********************** Module **************************/ + + /*[clinic input] +@@ -3588,81 +4090,138 @@ + _asyncio_all_tasks_impl(PyObject *module, PyObject *loop) + /*[clinic end generated code: output=0e107cbb7f72aa7b input=43a1b423c2d95bfa]*/ + { +- + asyncio_state *state = get_asyncio_state(module); +- PyObject *tasks = PySet_New(NULL); +- if (tasks == NULL) { +- return NULL; +- } + if (loop == Py_None) { + loop = _asyncio_get_running_loop_impl(module); + if (loop == NULL) { +- Py_DECREF(tasks); + return NULL; + } + } else { + Py_INCREF(loop); + } +- // First add eager tasks to the set so that we don't miss ++ // First add eager tasks to the list so that we don't miss + // any tasks which graduates from eager to non-eager +- PyObject *eager_iter = PyObject_GetIter(state->eager_tasks); +- if (eager_iter == NULL) { +- Py_DECREF(tasks); ++ // We first add all the tasks to `tasks` list and then filter ++ // out the tasks which are done and return it as a set. ++ PyObject *tasks = PyList_New(0); ++ if (tasks == NULL) { + Py_DECREF(loop); + return NULL; + } +- PyObject *item; +- while ((item = PyIter_Next(eager_iter)) != NULL) { +- if (add_one_task(state, tasks, item, loop) < 0) { +- Py_DECREF(tasks); +- Py_DECREF(loop); +- Py_DECREF(item); +- Py_DECREF(eager_iter); +- return NULL; +- } +- Py_DECREF(item); ++ if (PyList_Extend(tasks, state->eager_tasks) < 0) { ++ Py_DECREF(tasks); ++ Py_DECREF(loop); ++ return NULL; + } +- Py_DECREF(eager_iter); +- int err = 0; +- ASYNCIO_STATE_LOCK(state); +- TaskObj *first = &state->asyncio_tasks.first; +- TaskObj *head = state->asyncio_tasks.head->next; +- Py_INCREF(head); +- while (head != first) +- { +- if (add_one_task(state, tasks, (PyObject *)head, loop) < 0) { +- Py_DECREF(tasks); +- Py_DECREF(loop); +- Py_DECREF(head); +- err = 1; +- break; +- } +- Py_INCREF(head->next); +- Py_SETREF(head, head->next); ++ if (PyList_Extend(tasks, state->non_asyncio_tasks) < 0) { ++ Py_DECREF(tasks); ++ Py_DECREF(loop); ++ return NULL; + } +- ASYNCIO_STATE_UNLOCK(state); +- if (err) { ++ ++ PyInterpreterState *interp = PyInterpreterState_Get(); ++ // Stop the world and traverse the per-thread linked list ++ // of asyncio tasks for every thread, as well as the ++ // interpreter's linked list, and add them to `tasks`. ++ // The interpreter linked list is used for any lingering tasks ++ // whose thread state has been deallocated while the task was ++ // still alive. This can happen if a task is referenced by ++ // a different thread, in which case the task is moved to ++ // the interpreter's linked list from the thread's linked ++ // list before deallocation. See PyThreadState_Clear. ++ // ++ // The stop-the-world pause is required so that no thread ++ // modifies its linked list while being iterated here ++ // in parallel. This design allows for lock-free ++ // register_task/unregister_task for loops running in parallel ++ // in different threads (the general case). ++ _PyEval_StopTheWorld(interp); ++ int ret = add_tasks_interp(interp, (PyListObject *)tasks); ++ _PyEval_StartTheWorld(interp); ++ if (ret < 0) { ++ // call any escaping calls after starting the world to avoid any deadlocks. ++ Py_DECREF(tasks); ++ Py_DECREF(loop); + return NULL; + } +- PyObject *scheduled_iter = PyObject_GetIter(state->non_asyncio_tasks); +- if (scheduled_iter == NULL) { ++ ++ // All the tasks are now in the list, now filter the tasks which are done ++ PyObject *res = PySet_New(NULL); ++ if (res == NULL) { + Py_DECREF(tasks); + Py_DECREF(loop); + return NULL; + } +- while ((item = PyIter_Next(scheduled_iter)) != NULL) { +- if (add_one_task(state, tasks, item, loop) < 0) { ++ ++ for (Py_ssize_t i = 0; i < PyList_GET_SIZE(tasks); i++) { ++ PyObject *task = PyList_GET_ITEM(tasks, i); ++ if (add_one_task(state, res, task, loop) < 0) { ++ Py_DECREF(res); + Py_DECREF(tasks); + Py_DECREF(loop); +- Py_DECREF(item); +- Py_DECREF(scheduled_iter); + return NULL; + } +- Py_DECREF(item); + } +- Py_DECREF(scheduled_iter); ++ ++ Py_DECREF(tasks); + Py_DECREF(loop); +- return tasks; ++ return res; ++} ++ ++/*[clinic input] ++_asyncio.future_add_to_awaited_by ++ ++ fut: object ++ waiter: object ++ / ++ ++Record that `fut` is awaited on by `waiter`. ++ ++[clinic start generated code]*/ ++ ++static PyObject * ++_asyncio_future_add_to_awaited_by_impl(PyObject *module, PyObject *fut, ++ PyObject *waiter) ++/*[clinic end generated code: output=0ab9a1a63389e4df input=06e6eaac51f532b9]*/ ++{ ++ asyncio_state *state = get_asyncio_state(module); ++ if (TaskOrFuture_Check(state, fut) && TaskOrFuture_Check(state, waiter)) { ++ int res; ++ Py_BEGIN_CRITICAL_SECTION(fut); ++ res = future_awaited_by_add(state, (FutureObj *)fut, waiter); ++ Py_END_CRITICAL_SECTION(); ++ if (res) { ++ return NULL; ++ } ++ } ++ Py_RETURN_NONE; ++} ++ ++/*[clinic input] ++_asyncio.future_discard_from_awaited_by ++ ++ fut: object ++ waiter: object ++ / ++ ++[clinic start generated code]*/ ++ ++static PyObject * ++_asyncio_future_discard_from_awaited_by_impl(PyObject *module, PyObject *fut, ++ PyObject *waiter) ++/*[clinic end generated code: output=a03b0b4323b779de input=3833f7639e88e483]*/ ++{ ++ asyncio_state *state = get_asyncio_state(module); ++ if (TaskOrFuture_Check(state, fut) && TaskOrFuture_Check(state, waiter)) { ++ int res; ++ Py_BEGIN_CRITICAL_SECTION(fut); ++ res = future_awaited_by_discard(state, (FutureObj *)fut, waiter); ++ Py_END_CRITICAL_SECTION(); ++ if (res) { ++ return NULL; ++ } ++ } ++ Py_RETURN_NONE; + } + + static int +@@ -3723,6 +4282,12 @@ + Py_CLEAR(state->iscoroutine_typecache); + + Py_CLEAR(state->context_kwname); ++ // Clear the ref to running loop so that finalizers can run early. ++ // If there are other running loops in different threads, ++ // those get cleared in PyThreadState_Clear. ++ _PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET(); ++ Py_CLEAR(ts->asyncio_running_loop); ++ Py_CLEAR(ts->asyncio_running_task); + + return 0; + } +@@ -3753,7 +4318,6 @@ + goto fail; + } + +- + state->context_kwname = Py_BuildValue("(s)", "context"); + if (state->context_kwname == NULL) { + goto fail; +@@ -3773,7 +4337,7 @@ + } + + WITH_MOD("asyncio.events") +- GET_MOD_ATTR(state->asyncio_get_event_loop_policy, "get_event_loop_policy") ++ GET_MOD_ATTR(state->asyncio_get_event_loop_policy, "_get_event_loop_policy") + + WITH_MOD("asyncio.base_futures") + GET_MOD_ATTR(state->asyncio_future_repr_func, "_future_repr") +@@ -3834,6 +4398,8 @@ + _ASYNCIO__LEAVE_TASK_METHODDEF + _ASYNCIO__SWAP_CURRENT_TASK_METHODDEF + _ASYNCIO_ALL_TASKS_METHODDEF ++ _ASYNCIO_FUTURE_ADD_TO_AWAITED_BY_METHODDEF ++ _ASYNCIO_FUTURE_DISCARD_FROM_AWAITED_BY_METHODDEF + {NULL, NULL} + }; + +@@ -3842,11 +4408,6 @@ + { + asyncio_state *state = get_asyncio_state(mod); + +- Py_SET_TYPE(&state->asyncio_tasks.first, state->TaskType); +- _Py_SetImmortalUntracked((PyObject *)&state->asyncio_tasks.first); +- state->asyncio_tasks.head = &state->asyncio_tasks.first; +- state->asyncio_tasks.head->next = &state->asyncio_tasks.first; +- state->asyncio_tasks.head->prev = &state->asyncio_tasks.first; + + #define CREATE_TYPE(m, tp, spec, base) \ + do { \ +diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c +index 661847ad267..9e85e0de42c 100644 +--- a/Modules/_bz2module.c ++++ b/Modules/_bz2module.c +@@ -129,6 +129,9 @@ + PyThread_type_lock lock; + } BZ2Decompressor; + ++#define _BZ2Compressor_CAST(op) ((BZ2Compressor *)(op)) ++#define _BZ2Decompressor_CAST(op) ((BZ2Decompressor *)(op)) ++ + /* Helper functions. */ + + static int +@@ -376,8 +379,9 @@ + } + + static void +-BZ2Compressor_dealloc(BZ2Compressor *self) ++BZ2Compressor_dealloc(PyObject *op) + { ++ BZ2Compressor *self = _BZ2Compressor_CAST(op); + BZ2_bzCompressEnd(&self->bzs); + if (self->lock != NULL) { + PyThread_free_lock(self->lock); +@@ -388,7 +392,7 @@ + } + + static int +-BZ2Compressor_traverse(BZ2Compressor *self, visitproc visit, void *arg) ++BZ2Compressor_traverse(PyObject *self, visitproc visit, void *arg) + { + Py_VISIT(Py_TYPE(self)); + return 0; +@@ -680,8 +684,10 @@ + } + + static void +-BZ2Decompressor_dealloc(BZ2Decompressor *self) ++BZ2Decompressor_dealloc(PyObject *op) + { ++ BZ2Decompressor *self = _BZ2Decompressor_CAST(op); ++ + if(self->input_buffer != NULL) { + PyMem_Free(self->input_buffer); + } +@@ -697,7 +703,7 @@ + } + + static int +-BZ2Decompressor_traverse(BZ2Decompressor *self, visitproc visit, void *arg) ++BZ2Decompressor_traverse(PyObject *self, visitproc visit, void *arg) + { + Py_VISIT(Py_TYPE(self)); + return 0; +diff --git a/Modules/_csv.c b/Modules/_csv.c +index 1a4dc3f1f55..e5ae853590b 100644 +--- a/Modules/_csv.c ++++ b/Modules/_csv.c +@@ -77,7 +77,7 @@ + static void + _csv_free(void *module) + { +- _csv_clear((PyObject *)module); ++ (void)_csv_clear((PyObject *)module); + } + + typedef enum { +@@ -151,6 +151,10 @@ + PyObject *error_obj; /* cached error object */ + } WriterObj; + ++#define _DialectObj_CAST(op) ((DialectObj *)(op)) ++#define _ReaderObj_CAST(op) ((ReaderObj *)(op)) ++#define _WriterObj_CAST(op) ((WriterObj *)(op)) ++ + /* + * DIALECT class + */ +@@ -176,32 +180,37 @@ + } + + static PyObject * +-Dialect_get_lineterminator(DialectObj *self, void *Py_UNUSED(ignored)) ++Dialect_get_lineterminator(PyObject *op, void *Py_UNUSED(ignored)) + { ++ DialectObj *self = _DialectObj_CAST(op); + return Py_XNewRef(self->lineterminator); + } + + static PyObject * +-Dialect_get_delimiter(DialectObj *self, void *Py_UNUSED(ignored)) ++Dialect_get_delimiter(PyObject *op, void *Py_UNUSED(ignored)) + { ++ DialectObj *self = _DialectObj_CAST(op); + return get_char_or_None(self->delimiter); + } + + static PyObject * +-Dialect_get_escapechar(DialectObj *self, void *Py_UNUSED(ignored)) ++Dialect_get_escapechar(PyObject *op, void *Py_UNUSED(ignored)) + { ++ DialectObj *self = _DialectObj_CAST(op); + return get_char_or_None(self->escapechar); + } + + static PyObject * +-Dialect_get_quotechar(DialectObj *self, void *Py_UNUSED(ignored)) ++Dialect_get_quotechar(PyObject *op, void *Py_UNUSED(ignored)) + { ++ DialectObj *self = _DialectObj_CAST(op); + return get_char_or_None(self->quotechar); + } + + static PyObject * +-Dialect_get_quoting(DialectObj *self, void *Py_UNUSED(ignored)) ++Dialect_get_quoting(PyObject *op, void *Py_UNUSED(ignored)) + { ++ DialectObj *self = _DialectObj_CAST(op); + return PyLong_FromLong(self->quoting); + } + +@@ -371,16 +380,16 @@ + #undef D_OFF + + static PyGetSetDef Dialect_getsetlist[] = { +- { "delimiter", (getter)Dialect_get_delimiter}, +- { "escapechar", (getter)Dialect_get_escapechar}, +- { "lineterminator", (getter)Dialect_get_lineterminator}, +- { "quotechar", (getter)Dialect_get_quotechar}, +- { "quoting", (getter)Dialect_get_quoting}, ++ {"delimiter", Dialect_get_delimiter}, ++ {"escapechar", Dialect_get_escapechar}, ++ {"lineterminator", Dialect_get_lineterminator}, ++ {"quotechar", Dialect_get_quotechar}, ++ {"quoting", Dialect_get_quoting}, + {NULL}, + }; + + static void +-Dialect_dealloc(DialectObj *self) ++Dialect_dealloc(PyObject *self) + { + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); +@@ -594,15 +603,17 @@ + "The Dialect type records CSV parsing and generation options.\n"); + + static int +-Dialect_clear(DialectObj *self) ++Dialect_clear(PyObject *op) + { ++ DialectObj *self = _DialectObj_CAST(op); + Py_CLEAR(self->lineterminator); + return 0; + } + + static int +-Dialect_traverse(DialectObj *self, visitproc visit, void *arg) ++Dialect_traverse(PyObject *op, visitproc visit, void *arg) + { ++ DialectObj *self = _DialectObj_CAST(op); + Py_VISIT(self->lineterminator); + Py_VISIT(Py_TYPE(self)); + return 0; +@@ -916,8 +927,10 @@ + } + + static PyObject * +-Reader_iternext(ReaderObj *self) ++Reader_iternext(PyObject *op) + { ++ ReaderObj *self = _ReaderObj_CAST(op); ++ + PyObject *fields = NULL; + Py_UCS4 c; + Py_ssize_t pos, linelen; +@@ -982,11 +995,12 @@ + } + + static void +-Reader_dealloc(ReaderObj *self) ++Reader_dealloc(PyObject *op) + { ++ ReaderObj *self = _ReaderObj_CAST(op); + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); +- tp->tp_clear((PyObject *)self); ++ (void)tp->tp_clear(op); + if (self->field != NULL) { + PyMem_Free(self->field); + self->field = NULL; +@@ -996,8 +1010,9 @@ + } + + static int +-Reader_traverse(ReaderObj *self, visitproc visit, void *arg) ++Reader_traverse(PyObject *op, visitproc visit, void *arg) + { ++ ReaderObj *self = _ReaderObj_CAST(op); + Py_VISIT(self->dialect); + Py_VISIT(self->input_iter); + Py_VISIT(self->fields); +@@ -1006,8 +1021,9 @@ + } + + static int +-Reader_clear(ReaderObj *self) ++Reader_clear(PyObject *op) + { ++ ReaderObj *self = _ReaderObj_CAST(op); + Py_CLEAR(self->dialect); + Py_CLEAR(self->input_iter); + Py_CLEAR(self->fields); +@@ -1122,7 +1138,7 @@ + int copy_phase) + { + DialectObj *dialect = self->dialect; +- int i; ++ Py_ssize_t i; + Py_ssize_t rec_len; + + #define INCLEN \ +@@ -1303,8 +1319,9 @@ + "elements will be converted to string."); + + static PyObject * +-csv_writerow(WriterObj *self, PyObject *seq) ++csv_writerow(PyObject *op, PyObject *seq) + { ++ WriterObj *self = _WriterObj_CAST(op); + DialectObj *dialect = self->dialect; + PyObject *iter, *field, *line, *result; + bool null_field = false; +@@ -1412,7 +1429,7 @@ + "elements will be converted to string."); + + static PyObject * +-csv_writerows(WriterObj *self, PyObject *seqseq) ++csv_writerows(PyObject *self, PyObject *seqseq) + { + PyObject *row_iter, *row_obj, *result; + +@@ -1437,9 +1454,9 @@ + } + + static struct PyMethodDef Writer_methods[] = { +- { "writerow", (PyCFunction)csv_writerow, METH_O, csv_writerow_doc}, +- { "writerows", (PyCFunction)csv_writerows, METH_O, csv_writerows_doc}, +- { NULL, NULL } ++ {"writerow", csv_writerow, METH_O, csv_writerow_doc}, ++ {"writerows", csv_writerows, METH_O, csv_writerows_doc}, ++ {NULL, NULL, 0, NULL} /* sentinel */ + }; + + #define W_OFF(x) offsetof(WriterObj, x) +@@ -1452,8 +1469,9 @@ + #undef W_OFF + + static int +-Writer_traverse(WriterObj *self, visitproc visit, void *arg) ++Writer_traverse(PyObject *op, visitproc visit, void *arg) + { ++ WriterObj *self = _WriterObj_CAST(op); + Py_VISIT(self->dialect); + Py_VISIT(self->write); + Py_VISIT(self->error_obj); +@@ -1462,8 +1480,9 @@ + } + + static int +-Writer_clear(WriterObj *self) ++Writer_clear(PyObject *op) + { ++ WriterObj *self = _WriterObj_CAST(op); + Py_CLEAR(self->dialect); + Py_CLEAR(self->write); + Py_CLEAR(self->error_obj); +@@ -1471,11 +1490,12 @@ + } + + static void +-Writer_dealloc(WriterObj *self) ++Writer_dealloc(PyObject *op) + { ++ WriterObj *self = _WriterObj_CAST(op); + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); +- tp->tp_clear((PyObject *)self); ++ tp->tp_clear(op); + if (self->rec != NULL) { + PyMem_Free(self->rec); + } +diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c +index bb469988405..7c0ac1a57f5 100644 +--- a/Modules/_ctypes/_ctypes.c ++++ b/Modules/_ctypes/_ctypes.c +@@ -128,8 +128,9 @@ + + /*[clinic input] + module _ctypes ++class _ctypes.CFuncPtr "PyCFuncPtrObject *" "&PyCFuncPtr_Type" + [clinic start generated code]*/ +-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=476a19c49b31a75c]*/ ++/*[clinic end generated code: output=da39a3ee5e6b4b0d input=58e8c99474bc631e]*/ + + #define clinic_state() (get_module_state_by_class(cls)) + #define clinic_state_sub() (get_module_state_by_class(cls->tp_base)) +@@ -145,9 +146,12 @@ + PyObject *dict; + } DictRemoverObject; + ++#define _DictRemoverObject_CAST(op) ((DictRemoverObject *)(op)) ++ + static int +-_DictRemover_traverse(DictRemoverObject *self, visitproc visit, void *arg) ++_DictRemover_traverse(PyObject *myself, visitproc visit, void *arg) + { ++ DictRemoverObject *self = _DictRemoverObject_CAST(myself); + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->key); + Py_VISIT(self->dict); +@@ -155,8 +159,9 @@ + } + + static int +-_DictRemover_clear(DictRemoverObject *self) ++_DictRemover_clear(PyObject *myself) + { ++ DictRemoverObject *self = _DictRemoverObject_CAST(myself); + Py_CLEAR(self->key); + Py_CLEAR(self->dict); + return 0; +@@ -166,9 +171,8 @@ + _DictRemover_dealloc(PyObject *myself) + { + PyTypeObject *tp = Py_TYPE(myself); +- DictRemoverObject *self = (DictRemoverObject *)myself; + PyObject_GC_UnTrack(myself); +- (void)_DictRemover_clear(self); ++ (void)_DictRemover_clear(myself); + tp->tp_free(myself); + Py_DECREF(tp); + } +@@ -176,10 +180,11 @@ + static PyObject * + _DictRemover_call(PyObject *myself, PyObject *args, PyObject *kw) + { +- DictRemoverObject *self = (DictRemoverObject *)myself; ++ DictRemoverObject *self = _DictRemoverObject_CAST(myself); + if (self->key && self->dict) { + if (-1 == PyDict_DelItem(self->dict, self->key)) { +- PyErr_FormatUnraisable("Exception ignored on calling _ctypes.DictRemover"); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "calling _ctypes.DictRemover"); + } + Py_CLEAR(self->key); + Py_CLEAR(self->dict); +@@ -401,16 +406,19 @@ + PyObject *keep; // If set, a reference to the original CDataObject. + } StructParamObject; + ++#define _StructParamObject_CAST(op) ((StructParamObject *)(op)) ++ + static int +-StructParam_traverse(StructParamObject *self, visitproc visit, void *arg) ++StructParam_traverse(PyObject *self, visitproc visit, void *arg) + { + Py_VISIT(Py_TYPE(self)); + return 0; + } + + static int +-StructParam_clear(StructParamObject *self) ++StructParam_clear(PyObject *myself) + { ++ StructParamObject *self = _StructParamObject_CAST(myself); + Py_CLEAR(self->keep); + return 0; + } +@@ -418,10 +426,10 @@ + static void + StructParam_dealloc(PyObject *myself) + { +- StructParamObject *self = (StructParamObject *)myself; ++ StructParamObject *self = _StructParamObject_CAST(myself); + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(myself); +- (void)StructParam_clear(self); ++ (void)StructParam_clear(myself); + PyMem_Free(self->ptr); + tp->tp_free(myself); + Py_DECREF(tp); +@@ -456,7 +464,8 @@ + { + StgInfo *info = _PyStgInfo_FromType_NoState(self); + if (!info) { +- PyErr_WriteUnraisable(self); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "calling ctypes traverse function %R", self); + } + if (info) { + Py_VISIT(info->proto); +@@ -487,7 +496,8 @@ + { + StgInfo *info = _PyStgInfo_FromType_NoState(self); + if (!info) { +- PyErr_WriteUnraisable(self); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "clearing ctypes %R", self); + } + if (info) { + ctype_clear_stginfo(info); +@@ -500,7 +510,8 @@ + { + StgInfo *info = _PyStgInfo_FromType_NoState(self); + if (!info) { +- PyErr_WriteUnraisable(NULL); // NULL avoids segfault here ++ PyErr_FormatUnraisable("Exception ignored while " ++ "deallocating ctypes %R", self); + } + if (info) { + PyMem_Free(info->ffi_type_pointer.elements); +@@ -597,7 +608,7 @@ + if (ptr == NULL) { + return NULL; + } +- memcpy(ptr, self->b_ptr, self->b_size); ++ locked_memcpy_from(ptr, self, self->b_size); + + /* Create a Python object which calls PyMem_Free(ptr) in + its deallocator. The object will be destroyed +@@ -674,7 +685,7 @@ + + info->paramfunc = StructUnionType_paramfunc; + +- if (PyDict_GetItemRef((PyObject *)attrdict, &_Py_ID(_fields_), &fields) < 0) { ++ if (PyDict_GetItemRef(attrdict, &_Py_ID(_fields_), &fields) < 0) { + Py_DECREF(attrdict); + return -1; + } +@@ -906,8 +917,7 @@ + + result = generic_pycdata_new(st, (PyTypeObject *)type, NULL, NULL); + if (result != NULL) { +- memcpy(((CDataObject *)result)->b_ptr, +- (char *)buffer->buf + offset, info->size); ++ locked_memcpy_to((CDataObject *) result, (char *)buffer->buf + offset, info->size); + } + return result; + } +@@ -984,15 +994,8 @@ + #ifdef USE_DLERROR + const char *dlerr = dlerror(); + if (dlerr) { +- PyObject *message = PyUnicode_DecodeLocale(dlerr, "surrogateescape"); +- if (message) { +- PyErr_SetObject(PyExc_ValueError, message); +- Py_DECREF(message); +- return NULL; +- } +- // Ignore errors from PyUnicode_DecodeLocale, +- // fall back to the generic error below. +- PyErr_Clear(); ++ _PyErr_SetLocaleString(PyExc_ValueError, dlerr); ++ return NULL; + } + #endif + #undef USE_DLERROR +@@ -1201,7 +1204,7 @@ + parg->tag = 'P'; + parg->pffi_type = &ffi_type_pointer; + parg->obj = Py_NewRef(self); +- parg->value.p = *(void **)self->b_ptr; ++ parg->value.p = locked_deref(self); + return parg; + } + +@@ -1418,11 +1421,12 @@ + */ + + static int +-CharArray_set_raw(CDataObject *self, PyObject *value, void *Py_UNUSED(ignored)) ++CharArray_set_raw(PyObject *op, PyObject *value, void *Py_UNUSED(ignored)) + { + char *ptr; + Py_ssize_t size; + Py_buffer view; ++ CDataObject *self = _CDataObject_CAST(op); + + if (value == NULL) { + PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); +@@ -1438,7 +1442,7 @@ + goto fail; + } + +- memcpy(self->b_ptr, ptr, size); ++ locked_memcpy_to(self, ptr, size); + + PyBuffer_Release(&view); + return 0; +@@ -1448,27 +1452,38 @@ + } + + static PyObject * +-CharArray_get_raw(CDataObject *self, void *Py_UNUSED(ignored)) ++CharArray_get_raw(PyObject *op, void *Py_UNUSED(ignored)) + { +- return PyBytes_FromStringAndSize(self->b_ptr, self->b_size); ++ PyObject *res; ++ CDataObject *self = _CDataObject_CAST(op); ++ LOCK_PTR(self); ++ res = PyBytes_FromStringAndSize(self->b_ptr, self->b_size); ++ UNLOCK_PTR(self); ++ return res; + } + + static PyObject * +-CharArray_get_value(CDataObject *self, void *Py_UNUSED(ignored)) ++CharArray_get_value(PyObject *op, void *Py_UNUSED(ignored)) + { + Py_ssize_t i; ++ PyObject *res; ++ CDataObject *self = _CDataObject_CAST(op); ++ LOCK_PTR(self); + char *ptr = self->b_ptr; + for (i = 0; i < self->b_size; ++i) + if (*ptr++ == '\0') + break; +- return PyBytes_FromStringAndSize(self->b_ptr, i); ++ res = PyBytes_FromStringAndSize(self->b_ptr, i); ++ UNLOCK_PTR(self); ++ return res; + } + + static int +-CharArray_set_value(CDataObject *self, PyObject *value, void *Py_UNUSED(ignored)) ++CharArray_set_value(PyObject *op, PyObject *value, void *Py_UNUSED(ignored)) + { + const char *ptr; + Py_ssize_t size; ++ CDataObject *self = _CDataObject_CAST(op); + + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, +@@ -1492,36 +1507,43 @@ + } + + ptr = PyBytes_AS_STRING(value); ++ LOCK_PTR(self); + memcpy(self->b_ptr, ptr, size); + if (size < self->b_size) + self->b_ptr[size] = '\0'; ++ UNLOCK_PTR(self); + Py_DECREF(value); + + return 0; + } + + static PyGetSetDef CharArray_getsets[] = { +- { "raw", (getter)CharArray_get_raw, (setter)CharArray_set_raw, +- "value", NULL }, +- { "value", (getter)CharArray_get_value, (setter)CharArray_set_value, +- "string value"}, ++ { "raw", CharArray_get_raw, CharArray_set_raw, "value", NULL }, ++ { "value", CharArray_get_value, CharArray_set_value, "string value" }, + { NULL, NULL } + }; + + static PyObject * +-WCharArray_get_value(CDataObject *self, void *Py_UNUSED(ignored)) ++WCharArray_get_value(PyObject *op, void *Py_UNUSED(ignored)) + { + Py_ssize_t i; ++ PyObject *res; ++ CDataObject *self = _CDataObject_CAST(op); + wchar_t *ptr = (wchar_t *)self->b_ptr; ++ LOCK_PTR(self); + for (i = 0; i < self->b_size/(Py_ssize_t)sizeof(wchar_t); ++i) + if (*ptr++ == (wchar_t)0) + break; +- return PyUnicode_FromWideChar((wchar_t *)self->b_ptr, i); ++ res = PyUnicode_FromWideChar((wchar_t *)self->b_ptr, i); ++ UNLOCK_PTR(self); ++ return res; + } + + static int +-WCharArray_set_value(CDataObject *self, PyObject *value, void *Py_UNUSED(ignored)) ++WCharArray_set_value(PyObject *op, PyObject *value, void *Py_UNUSED(ignored)) + { ++ CDataObject *self = _CDataObject_CAST(op); ++ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, + "can't delete attribute"); +@@ -1546,15 +1568,15 @@ + PyErr_SetString(PyExc_ValueError, "string too long"); + return -1; + } +- if (PyUnicode_AsWideChar(value, (wchar_t *)self->b_ptr, size) < 0) { +- return -1; +- } +- return 0; ++ Py_ssize_t rc; ++ LOCK_PTR(self); ++ rc = PyUnicode_AsWideChar(value, (wchar_t *)self->b_ptr, size); ++ UNLOCK_PTR(self); ++ return rc < 0 ? -1 : 0; + } + + static PyGetSetDef WCharArray_getsets[] = { +- { "value", (getter)WCharArray_get_value, (setter)WCharArray_set_value, +- "string value"}, ++ { "value", WCharArray_get_value, WCharArray_set_value, "string value" }, + { NULL, NULL } + }; + +@@ -1768,11 +1790,6 @@ + [clinic start generated code]*/ + /*[clinic end generated code: output=da39a3ee5e6b4b0d input=dd4d9646c56f43a9]*/ + +-#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX) +-static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdCEFfuzZqQPXOv?g"; +-#else +-static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdfuzZqQPXOv?g"; +-#endif + + /*[clinic input] + _ctypes.c_wchar_p.from_param as c_wchar_p_from_param +@@ -1985,7 +2002,7 @@ + return NULL; + parg->pffi_type = &ffi_type_pointer; + parg->tag = 'P'; +- parg->obj = fd->setfunc(&parg->value, value, 0); ++ parg->obj = fd->setfunc(&parg->value, value, sizeof(void*)); + if (parg->obj == NULL) { + Py_DECREF(parg); + return NULL; +@@ -2059,6 +2076,7 @@ + parg->pffi_type = &ffi_type_pointer; + parg->tag = 'P'; + Py_INCREF(value); ++ // Function pointers don't change their contents, no need to lock + parg->value.p = *(void **)func->b_ptr; + parg->obj = value; + return (PyObject *)parg; +@@ -2085,7 +2103,7 @@ + parg->tag = 'Z'; + parg->obj = Py_NewRef(value); + /* Remember: b_ptr points to where the pointer is stored! */ +- parg->value.p = *(void **)(((CDataObject *)value)->b_ptr); ++ parg->value.p = locked_deref((CDataObject *)value); + return (PyObject *)parg; + } + } +@@ -2202,7 +2220,7 @@ + parg->tag = fmt[0]; + parg->pffi_type = fd->pffi_type; + parg->obj = Py_NewRef(self); +- memcpy(&parg->value, self->b_ptr, self->b_size); ++ locked_memcpy_from(&parg->value, self, self->b_size); + return parg; + } + +@@ -2243,17 +2261,13 @@ + "which must be a string of length 1"); + goto error; + } +- if (!strchr(SIMPLE_TYPE_CHARS, *proto_str)) { ++ 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 '%s'.", +- SIMPLE_TYPE_CHARS); +- goto error; +- } +- fmt = _ctypes_get_fielddesc(proto_str); +- if (fmt == NULL) { +- PyErr_Format(PyExc_ValueError, +- "_type_ '%s' not supported", proto_str); ++ "a single character string containing one of the\n" ++ "supported types: '%s'.", ++ _ctypes_get_simple_type_chars()); + goto error; + } + +@@ -2450,7 +2464,7 @@ + + parg->tag = fmt[0]; + parg->pffi_type = fd->pffi_type; +- parg->obj = fd->setfunc(&parg->value, value, 0); ++ parg->obj = fd->setfunc(&parg->value, value, info->size); + if (parg->obj) + return (PyObject *)parg; + PyObject *exc = PyErr_GetRaisedException(); +@@ -2627,7 +2641,7 @@ + stginfo->getfunc = NULL; + stginfo->ffi_type_pointer = ffi_type_pointer; + +- if (PyDict_GetItemRef((PyObject *)attrdict, &_Py_ID(_flags_), &ob) < 0) { ++ if (PyDict_GetItemRef(attrdict, &_Py_ID(_flags_), &ob) < 0) { + return -1; + } + if (!ob || !PyLong_Check(ob)) { +@@ -2640,7 +2654,7 @@ + Py_DECREF(ob); + + /* _argtypes_ is optional... */ +- if (PyDict_GetItemRef((PyObject *)attrdict, &_Py_ID(_argtypes_), &ob) < 0) { ++ if (PyDict_GetItemRef(attrdict, &_Py_ID(_argtypes_), &ob) < 0) { + return -1; + } + if (ob) { +@@ -2653,7 +2667,7 @@ + stginfo->converters = converters; + } + +- if (PyDict_GetItemRef((PyObject *)attrdict, &_Py_ID(_restype_), &ob) < 0) { ++ if (PyDict_GetItemRef(attrdict, &_Py_ID(_restype_), &ob) < 0) { + return -1; + } + if (ob) { +@@ -2675,7 +2689,7 @@ + } + } + /* XXX later, maybe. +- if (PyDict_GetItemRef((PyObject *)attrdict, &_Py _ID(_errcheck_), &ob) < 0) { ++ if (PyDict_GetItemRef(attrdict, &_Py _ID(_errcheck_), &ob) < 0) { + return -1; + } + if (ob) { +@@ -2703,7 +2717,7 @@ + parg->tag = 'P'; + parg->pffi_type = &ffi_type_pointer; + parg->obj = Py_NewRef(self); +- parg->value.p = *(void **)self->b_ptr; ++ parg->value.p = locked_deref(self); + return parg; + } + +@@ -2877,8 +2891,9 @@ + + + static int +-PyCData_traverse(CDataObject *self, visitproc visit, void *arg) ++PyCData_traverse(PyObject *op, visitproc visit, void *arg) + { ++ CDataObject *self = _CDataObject_CAST(op); + Py_VISIT(self->b_objects); + Py_VISIT((PyObject *)self->b_base); + PyTypeObject *type = Py_TYPE(self); +@@ -2887,8 +2902,9 @@ + } + + static int +-PyCData_clear(CDataObject *self) ++PyCData_clear(PyObject *op) + { ++ CDataObject *self = _CDataObject_CAST(op); + Py_CLEAR(self->b_objects); + if ((self->b_needsfree) + && _CDataObject_HasExternalBuffer(self)) +@@ -2903,7 +2919,7 @@ + { + PyTypeObject *type = Py_TYPE(self); + PyObject_GC_UnTrack(self); +- PyCData_clear((CDataObject *)self); ++ (void)PyCData_clear(self); + type->tp_free(self); + Py_DECREF(type); + } +@@ -2946,7 +2962,7 @@ + static int + PyCData_NewGetBuffer(PyObject *myself, Py_buffer *view, int flags) + { +- CDataObject *self = (CDataObject *)myself; ++ CDataObject *self = _CDataObject_CAST(myself); + + ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(myself))); + StgInfo *info; +@@ -3005,7 +3021,7 @@ + PyCData_reduce_impl(PyObject *myself, PyTypeObject *cls) + /*[clinic end generated code: output=1a025ccfdd8c935d input=34097a5226ea63c1]*/ + { +- CDataObject *self = (CDataObject *)myself; ++ CDataObject *self = _CDataObject_CAST(myself); + + ctypes_state *st = get_module_state_by_class(cls); + StgInfo *info; +@@ -3023,8 +3039,12 @@ + if (dict == NULL) { + return NULL; + } ++ PyObject *bytes; ++ LOCK_PTR(self); ++ bytes = PyBytes_FromStringAndSize(self->b_ptr, self->b_size); ++ UNLOCK_PTR(self); + return Py_BuildValue("O(O(NN))", st->_unpickle, Py_TYPE(myself), dict, +- PyBytes_FromStringAndSize(self->b_ptr, self->b_size)); ++ bytes); + } + + static PyObject * +@@ -3034,7 +3054,7 @@ + Py_ssize_t len; + int res; + PyObject *dict, *mydict; +- CDataObject *self = (CDataObject *)myself; ++ CDataObject *self = _CDataObject_CAST(myself); + if (!PyArg_ParseTuple(args, "O!s#", + &PyDict_Type, &dict, &data, &len)) + { +@@ -3042,7 +3062,10 @@ + } + if (len > self->b_size) + len = self->b_size; ++ // XXX Can we use locked_memcpy_to()? ++ LOCK_PTR(self); + memmove(self->b_ptr, data, len); ++ UNLOCK_PTR(self); + mydict = PyObject_GetAttrString(myself, "__dict__"); + if (mydict == NULL) { + return NULL; +@@ -3100,6 +3123,12 @@ + static int + PyCData_MallocBuffer(CDataObject *obj, StgInfo *info) + { ++ /* We don't have to lock in this function, because it's only ++ * used in constructors and therefore does not have concurrent ++ * access. ++ */ ++ assert (Py_REFCNT(obj) == 1); ++ + if ((size_t)info->size <= sizeof(obj->b_value)) { + /* No need to call malloc, can use the default buffer */ + obj->b_ptr = (char *)&obj->b_value; +@@ -3225,15 +3254,25 @@ + PyCData_get(ctypes_state *st, PyObject *type, GETFUNC getfunc, PyObject *src, + Py_ssize_t index, Py_ssize_t size, char *adr) + { +- if (getfunc) +- return getfunc(adr, size); ++ CDataObject *cdata = _CDataObject_CAST(src); ++ if (getfunc) { ++ PyObject *res; ++ LOCK_PTR(cdata); ++ res = getfunc(adr, size); ++ UNLOCK_PTR(cdata); ++ return res; ++ } + assert(type); + StgInfo *info; + if (PyStgInfo_FromType(st, type, &info) < 0) { + return NULL; + } + if (info && info->getfunc && !_ctypes_simple_instance(st, type)) { +- return info->getfunc(adr, size); ++ PyObject *res; ++ LOCK_PTR(cdata); ++ res = info->getfunc(adr, size); ++ UNLOCK_PTR(cdata); ++ return res; + } + return PyCData_FromBaseObj(st, type, src, index, adr); + } +@@ -3250,15 +3289,24 @@ + int err; + + if (setfunc) { +- return setfunc(ptr, value, size); ++ PyObject *res; ++ LOCK_PTR(dst); ++ res = setfunc(ptr, value, size); ++ UNLOCK_PTR(dst); ++ return res; + } + if (!CDataObject_Check(st, value)) { + StgInfo *info; + if (PyStgInfo_FromType(st, type, &info) < 0) { + return NULL; + } +- if (info && info->setfunc) +- return info->setfunc(ptr, value, size); ++ if (info && info->setfunc) { ++ PyObject *res; ++ LOCK_PTR(dst); ++ res = info->setfunc(ptr, value, size); ++ UNLOCK_PTR(dst); ++ return res; ++ } + /* + If value is a tuple, we try to call the type with the tuple + and use the result! +@@ -3278,7 +3326,9 @@ + Py_DECREF(ob); + return result; + } else if (value == Py_None && PyCPointerTypeObject_Check(st, type)) { ++ LOCK_PTR(dst); + *(void **)ptr = NULL; ++ UNLOCK_PTR(dst); + Py_RETURN_NONE; + } else { + PyErr_Format(PyExc_TypeError, +@@ -3294,9 +3344,7 @@ + if (err == -1) + return NULL; + if (err) { +- memcpy(ptr, +- src->b_ptr, +- size); ++ locked_memcpy_from(ptr, src, size); + + if (PyCPointerTypeObject_Check(st, type)) { + /* XXX */ +@@ -3330,7 +3378,9 @@ + ((PyTypeObject *)type)->tp_name); + return NULL; + } ++ LOCK_PTR(src); + *(void **)ptr = src->b_ptr; ++ UNLOCK_PTR(src); + + keep = GetKeepedObjects(src); + if (keep == NULL) +@@ -3429,21 +3479,37 @@ + PyCFuncPtr_Type + */ + ++/*[clinic input] ++@critical_section ++@setter ++_ctypes.CFuncPtr.errcheck ++[clinic start generated code]*/ ++ + static int +-PyCFuncPtr_set_errcheck(PyCFuncPtrObject *self, PyObject *ob, void *Py_UNUSED(ignored)) ++_ctypes_CFuncPtr_errcheck_set_impl(PyCFuncPtrObject *self, PyObject *value) ++/*[clinic end generated code: output=6580cf1ffdf3b9fb input=84930bb16c490b33]*/ + { +- if (ob && !PyCallable_Check(ob)) { ++ if (value && !PyCallable_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "the errcheck attribute must be callable"); + return -1; + } +- Py_XINCREF(ob); +- Py_XSETREF(self->errcheck, ob); ++ Py_XINCREF(value); ++ Py_XSETREF(self->errcheck, value); + return 0; + } + ++/*[clinic input] ++@critical_section ++@getter ++_ctypes.CFuncPtr.errcheck ++ ++a function to check for errors ++[clinic start generated code]*/ ++ + static PyObject * +-PyCFuncPtr_get_errcheck(PyCFuncPtrObject *self, void *Py_UNUSED(ignored)) ++_ctypes_CFuncPtr_errcheck_get_impl(PyCFuncPtrObject *self) ++/*[clinic end generated code: output=dfa6fb5c6f90fd14 input=4672135fef37819f]*/ + { + if (self->errcheck) { + return Py_NewRef(self->errcheck); +@@ -3451,11 +3517,18 @@ + Py_RETURN_NONE; + } + ++/*[clinic input] ++@setter ++@critical_section ++_ctypes.CFuncPtr.restype ++[clinic start generated code]*/ ++ + static int +-PyCFuncPtr_set_restype(PyCFuncPtrObject *self, PyObject *ob, void *Py_UNUSED(ignored)) ++_ctypes_CFuncPtr_restype_set_impl(PyCFuncPtrObject *self, PyObject *value) ++/*[clinic end generated code: output=0be0a086abbabf18 input=683c3bef4562ccc6]*/ + { + PyObject *checker, *oldchecker; +- if (ob == NULL) { ++ if (value == NULL) { + oldchecker = self->checker; + self->checker = NULL; + Py_CLEAR(self->restype); +@@ -3464,27 +3537,36 @@ + } + ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self))); + StgInfo *info; +- if (PyStgInfo_FromType(st, ob, &info) < 0) { ++ if (PyStgInfo_FromType(st, value, &info) < 0) { + return -1; + } +- if (ob != Py_None && !info && !PyCallable_Check(ob)) { ++ if (value != Py_None && !info && !PyCallable_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "restype must be a type, a callable, or None"); + return -1; + } +- if (PyObject_GetOptionalAttr(ob, &_Py_ID(_check_retval_), &checker) < 0) { ++ if (PyObject_GetOptionalAttr(value, &_Py_ID(_check_retval_), &checker) < 0) { + return -1; + } + oldchecker = self->checker; + self->checker = checker; +- Py_INCREF(ob); +- Py_XSETREF(self->restype, ob); ++ Py_INCREF(value); ++ Py_XSETREF(self->restype, value); + Py_XDECREF(oldchecker); + return 0; + } + ++/*[clinic input] ++@getter ++@critical_section ++_ctypes.CFuncPtr.restype ++ ++specify the result type ++[clinic start generated code]*/ ++ + static PyObject * +-PyCFuncPtr_get_restype(PyCFuncPtrObject *self, void *Py_UNUSED(ignored)) ++_ctypes_CFuncPtr_restype_get_impl(PyCFuncPtrObject *self) ++/*[clinic end generated code: output=c8f44cd16f1dee5e input=5e3ed95116204fd2]*/ + { + if (self->restype) { + return Py_NewRef(self->restype); +@@ -3502,28 +3584,44 @@ + } + } + ++/*[clinic input] ++@setter ++@critical_section ++_ctypes.CFuncPtr.argtypes ++[clinic start generated code]*/ ++ + static int +-PyCFuncPtr_set_argtypes(PyCFuncPtrObject *self, PyObject *ob, void *Py_UNUSED(ignored)) ++_ctypes_CFuncPtr_argtypes_set_impl(PyCFuncPtrObject *self, PyObject *value) ++/*[clinic end generated code: output=596a36e2ae89d7d1 input=c4627573e980aa8b]*/ + { + PyObject *converters; + +- if (ob == NULL || ob == Py_None) { ++ if (value == NULL || value == Py_None) { + Py_CLEAR(self->converters); + Py_CLEAR(self->argtypes); + } else { + ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self))); +- converters = converters_from_argtypes(st, ob); ++ converters = converters_from_argtypes(st, value); + if (!converters) + return -1; + Py_XSETREF(self->converters, converters); +- Py_INCREF(ob); +- Py_XSETREF(self->argtypes, ob); ++ Py_INCREF(value); ++ Py_XSETREF(self->argtypes, value); + } + return 0; + } + ++/*[clinic input] ++@getter ++@critical_section ++_ctypes.CFuncPtr.argtypes ++ ++specify the argument types ++[clinic start generated code]*/ ++ + static PyObject * +-PyCFuncPtr_get_argtypes(PyCFuncPtrObject *self, void *Py_UNUSED(ignored)) ++_ctypes_CFuncPtr_argtypes_get_impl(PyCFuncPtrObject *self) ++/*[clinic end generated code: output=c46b05a1b0f99172 input=37a8a545a56f8ae2]*/ + { + if (self->argtypes) { + return Py_NewRef(self->argtypes); +@@ -3542,13 +3640,9 @@ + } + + static PyGetSetDef PyCFuncPtr_getsets[] = { +- { "errcheck", (getter)PyCFuncPtr_get_errcheck, (setter)PyCFuncPtr_set_errcheck, +- "a function to check for errors", NULL }, +- { "restype", (getter)PyCFuncPtr_get_restype, (setter)PyCFuncPtr_set_restype, +- "specify the result type", NULL }, +- { "argtypes", (getter)PyCFuncPtr_get_argtypes, +- (setter)PyCFuncPtr_set_argtypes, +- "specify the argument types", NULL }, ++ _CTYPES_CFUNCPTR_ERRCHECK_GETSETDEF ++ _CTYPES_CFUNCPTR_RESTYPE_GETSETDEF ++ _CTYPES_CFUNCPTR_ARGTYPES_GETSETDEF + { NULL, NULL } + }; + +@@ -3825,21 +3919,14 @@ + address = (PPROC)dlsym(handle, name); + + if (!address) { +- #ifdef USE_DLERROR ++ #ifdef USE_DLERROR + const char *dlerr = dlerror(); + if (dlerr) { +- PyObject *message = PyUnicode_DecodeLocale(dlerr, "surrogateescape"); +- if (message) { +- PyErr_SetObject(PyExc_AttributeError, message); +- Py_DECREF(ftuple); +- Py_DECREF(message); +- return NULL; +- } +- // Ignore errors from PyUnicode_DecodeLocale, +- // fall back to the generic error below. +- PyErr_Clear(); ++ _PyErr_SetLocaleString(PyExc_AttributeError, dlerr); ++ Py_DECREF(ftuple); ++ return NULL; + } +- #endif ++ #endif + PyErr_Format(PyExc_AttributeError, "function '%s' not found", name); + Py_DECREF(ftuple); + return NULL; +@@ -3860,6 +3947,8 @@ + + self->paramflags = Py_XNewRef(paramflags); + ++ // No other threads can have this object, no need to ++ // lock it. + *(void **)self->b_ptr = address; + Py_INCREF(dll); + Py_DECREF(ftuple); +@@ -4318,7 +4407,7 @@ + } + + static PyObject * +-PyCFuncPtr_call(PyCFuncPtrObject *self, PyObject *inargs, PyObject *kwds) ++PyCFuncPtr_call(PyObject *op, PyObject *inargs, PyObject *kwds) + { + PyObject *restype; + PyObject *converters; +@@ -4331,6 +4420,7 @@ + IUnknown *piunk = NULL; + #endif + void *pProc = NULL; ++ PyCFuncPtrObject *self = _PyCFuncPtrObject_CAST(op); + + int inoutmask; + int outmask; +@@ -4338,7 +4428,7 @@ + + ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self))); + StgInfo *info; +- if (PyStgInfo_FromObject(st, (PyObject *)self, &info) < 0) { ++ if (PyStgInfo_FromObject(st, op, &info) < 0) { + return NULL; + } + assert(info); /* Cannot be NULL for PyCFuncPtrObject instances */ +@@ -4456,8 +4546,9 @@ + } + + static int +-PyCFuncPtr_traverse(PyCFuncPtrObject *self, visitproc visit, void *arg) ++PyCFuncPtr_traverse(PyObject *op, visitproc visit, void *arg) + { ++ PyCFuncPtrObject *self = _PyCFuncPtrObject_CAST(op); + Py_VISIT(self->callable); + Py_VISIT(self->restype); + Py_VISIT(self->checker); +@@ -4466,12 +4557,13 @@ + Py_VISIT(self->converters); + Py_VISIT(self->paramflags); + Py_VISIT(self->thunk); +- return PyCData_traverse((CDataObject *)self, visit, arg); ++ return PyCData_traverse(op, visit, arg); + } + + static int +-PyCFuncPtr_clear(PyCFuncPtrObject *self) ++PyCFuncPtr_clear(PyObject *op) + { ++ PyCFuncPtrObject *self = _PyCFuncPtrObject_CAST(op); + Py_CLEAR(self->callable); + Py_CLEAR(self->restype); + Py_CLEAR(self->checker); +@@ -4480,22 +4572,23 @@ + Py_CLEAR(self->converters); + Py_CLEAR(self->paramflags); + Py_CLEAR(self->thunk); +- return PyCData_clear((CDataObject *)self); ++ return PyCData_clear(op); + } + + static void +-PyCFuncPtr_dealloc(PyCFuncPtrObject *self) ++PyCFuncPtr_dealloc(PyObject *self) + { + PyObject_GC_UnTrack(self); +- PyCFuncPtr_clear(self); ++ (void)PyCFuncPtr_clear(self); + PyTypeObject *type = Py_TYPE(self); +- type->tp_free((PyObject *)self); ++ type->tp_free(self); + Py_DECREF(type); + } + + static PyObject * +-PyCFuncPtr_repr(PyCFuncPtrObject *self) ++PyCFuncPtr_repr(PyObject *op) + { ++ PyCFuncPtrObject *self = _PyCFuncPtrObject_CAST(op); + #ifdef MS_WIN32 + if (self->index) + return PyUnicode_FromFormat("", +@@ -4509,8 +4602,9 @@ + } + + static int +-PyCFuncPtr_bool(PyCFuncPtrObject *self) ++PyCFuncPtr_bool(PyObject *op) + { ++ PyCFuncPtrObject *self = _PyCFuncPtrObject_CAST(op); + return ((*(void **)self->b_ptr != NULL) + #ifdef MS_WIN32 + || (self->index != 0) +@@ -4698,7 +4792,7 @@ + PyCArray_Type + */ + static int +-Array_init(CDataObject *self, PyObject *args, PyObject *kw) ++Array_init(PyObject *self, PyObject *args, PyObject *kw) + { + Py_ssize_t i; + Py_ssize_t n; +@@ -4712,7 +4806,7 @@ + for (i = 0; i < n; ++i) { + PyObject *v; + v = PyTuple_GET_ITEM(args, i); +- if (-1 == PySequence_SetItem((PyObject *)self, i, v)) ++ if (-1 == PySequence_SetItem(self, i, v)) + return -1; + } + return 0; +@@ -4721,7 +4815,7 @@ + static PyObject * + Array_item(PyObject *myself, Py_ssize_t index) + { +- CDataObject *self = (CDataObject *)myself; ++ CDataObject *self = _CDataObject_CAST(myself); + Py_ssize_t offset, size; + + if (index < 0 || index >= self->b_length) { +@@ -4732,7 +4826,7 @@ + + ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self))); + StgInfo *stginfo; +- if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) { ++ if (PyStgInfo_FromObject(st, myself, &stginfo) < 0) { + return NULL; + } + +@@ -4742,14 +4836,14 @@ + size = stginfo->size / stginfo->length; + offset = index * size; + +- return PyCData_get(st, stginfo->proto, stginfo->getfunc, (PyObject *)self, +- index, size, self->b_ptr + offset); ++ return PyCData_get(st, stginfo->proto, stginfo->getfunc, myself, ++ index, size, self->b_ptr + offset); + } + + static PyObject * + Array_subscript(PyObject *myself, PyObject *item) + { +- CDataObject *self = (CDataObject *)myself; ++ CDataObject *self = _CDataObject_CAST(myself); + + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); +@@ -4773,7 +4867,7 @@ + + ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self))); + StgInfo *stginfo; +- if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) { ++ if (PyStgInfo_FromObject(st, myself, &stginfo) < 0) { + return NULL; + } + assert(stginfo); /* Cannot be NULL for array object instances */ +@@ -4792,18 +4886,24 @@ + if (slicelen <= 0) + return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); + if (step == 1) { +- return PyBytes_FromStringAndSize(ptr + start, +- slicelen); ++ PyObject *res; ++ LOCK_PTR(self); ++ res = PyBytes_FromStringAndSize(ptr + start, ++ slicelen); ++ UNLOCK_PTR(self); ++ return res; + } + dest = (char *)PyMem_Malloc(slicelen); + + if (dest == NULL) + return PyErr_NoMemory(); + ++ LOCK_PTR(self); + for (cur = start, i = 0; i < slicelen; + cur += step, i++) { + dest[i] = ptr[cur]; + } ++ UNLOCK_PTR(self); + + np = PyBytes_FromStringAndSize(dest, slicelen); + PyMem_Free(dest); +@@ -4816,8 +4916,12 @@ + if (slicelen <= 0) + return Py_GetConstant(Py_CONSTANT_EMPTY_STR); + if (step == 1) { +- return PyUnicode_FromWideChar(ptr + start, +- slicelen); ++ PyObject *res; ++ LOCK_PTR(self); ++ res = PyUnicode_FromWideChar(ptr + start, ++ slicelen); ++ UNLOCK_PTR(self); ++ return res; + } + + dest = PyMem_New(wchar_t, slicelen); +@@ -4826,10 +4930,12 @@ + return NULL; + } + ++ LOCK_PTR(self); + for (cur = start, i = 0; i < slicelen; + cur += step, i++) { + dest[i] = ptr[cur]; + } ++ UNLOCK_PTR(self); + + np = PyUnicode_FromWideChar(dest, slicelen); + PyMem_Free(dest); +@@ -4862,7 +4968,7 @@ + static int + Array_ass_item(PyObject *myself, Py_ssize_t index, PyObject *value) + { +- CDataObject *self = (CDataObject *)myself; ++ CDataObject *self = _CDataObject_CAST(myself); + Py_ssize_t size, offset; + char *ptr; + +@@ -4874,7 +4980,7 @@ + + ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self))); + StgInfo *stginfo; +- if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) { ++ if (PyStgInfo_FromObject(st, myself, &stginfo) < 0) { + return -1; + } + assert(stginfo); /* Cannot be NULL for array object instances */ +@@ -4888,14 +4994,14 @@ + offset = index * size; + ptr = self->b_ptr + offset; + +- return PyCData_set(st, (PyObject *)self, stginfo->proto, stginfo->setfunc, value, +- index, size, ptr); ++ return PyCData_set(st, myself, stginfo->proto, stginfo->setfunc, value, ++ index, size, ptr); + } + + static int + Array_ass_subscript(PyObject *myself, PyObject *item, PyObject *value) + { +- CDataObject *self = (CDataObject *)myself; ++ CDataObject *self = _CDataObject_CAST(myself); + + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, +@@ -4952,7 +5058,7 @@ + static Py_ssize_t + Array_length(PyObject *myself) + { +- CDataObject *self = (CDataObject *)myself; ++ CDataObject *self = _CDataObject_CAST(myself); + return self->b_length; + } + +@@ -5068,11 +5174,11 @@ + [clinic start generated code]*/ + /*[clinic end generated code: output=da39a3ee5e6b4b0d input=016c476c7aa8b8a8]*/ + +- + static int +-Simple_set_value(CDataObject *self, PyObject *value, void *Py_UNUSED(ignored)) ++Simple_set_value(PyObject *op, PyObject *value, void *Py_UNUSED(ignored)) + { + PyObject *result; ++ CDataObject *self = _CDataObject_CAST(op); + + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, +@@ -5082,13 +5188,15 @@ + + ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self))); + StgInfo *info; +- if (PyStgInfo_FromObject(st, (PyObject *)self, &info) < 0) { ++ if (PyStgInfo_FromObject(st, op, &info) < 0) { + return -1; + } + assert(info); /* Cannot be NULL for CDataObject instances */ + assert(info->setfunc); + ++ LOCK_PTR(self); + result = info->setfunc(self->b_ptr, value, info->size); ++ UNLOCK_PTR(self); + if (!result) + return -1; + +@@ -5097,7 +5205,7 @@ + } + + static int +-Simple_init(CDataObject *self, PyObject *args, PyObject *kw) ++Simple_init(PyObject *self, PyObject *args, PyObject *kw) + { + PyObject *value = NULL; + if (!PyArg_UnpackTuple(args, "__init__", 0, 1, &value)) +@@ -5108,20 +5216,25 @@ + } + + static PyObject * +-Simple_get_value(CDataObject *self, void *Py_UNUSED(ignored)) ++Simple_get_value(PyObject *op, void *Py_UNUSED(ignored)) + { ++ CDataObject *self = _CDataObject_CAST(op); + ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self))); + StgInfo *info; +- if (PyStgInfo_FromObject(st, (PyObject *)self, &info) < 0) { ++ if (PyStgInfo_FromObject(st, op, &info) < 0) { + return NULL; + } + assert(info); /* Cannot be NULL for CDataObject instances */ + assert(info->getfunc); +- return info->getfunc(self->b_ptr, self->b_size); ++ PyObject *res; ++ LOCK_PTR(self); ++ res = info->getfunc(self->b_ptr, self->b_size); ++ UNLOCK_PTR(self); ++ return res; + } + + static PyGetSetDef Simple_getsets[] = { +- { "value", (getter)Simple_get_value, (setter)Simple_set_value, ++ { "value", Simple_get_value, Simple_set_value, + "current value", NULL }, + { NULL, NULL } + }; +@@ -5143,7 +5256,7 @@ + return Py_NewRef(self); + } + /* call stginfo->getfunc */ +- return Simple_get_value((CDataObject *)self, NULL); ++ return Simple_get_value(self, NULL); + } + + static PyMethodDef Simple_methods[] = { +@@ -5151,14 +5264,20 @@ + { NULL, NULL }, + }; + +-static int Simple_bool(CDataObject *self) ++static int ++Simple_bool(PyObject *op) + { +- return memcmp(self->b_ptr, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", self->b_size); ++ int cmp; ++ CDataObject *self = _CDataObject_CAST(op); ++ LOCK_PTR(self); ++ cmp = memcmp(self->b_ptr, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", self->b_size); ++ UNLOCK_PTR(self); ++ return cmp; + } + + /* "%s(%s)" % (self.__class__.__name__, self.value) */ + static PyObject * +-Simple_repr(CDataObject *self) ++Simple_repr(PyObject *self) + { + PyObject *val, *result; + ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self))); +@@ -5205,12 +5324,13 @@ + static PyObject * + Pointer_item(PyObject *myself, Py_ssize_t index) + { +- CDataObject *self = (CDataObject *)myself; ++ CDataObject *self = _CDataObject_CAST(myself); + Py_ssize_t size; + Py_ssize_t offset; + PyObject *proto; ++ void *deref = locked_deref(self); + +- if (*(void **)self->b_ptr == NULL) { ++ if (deref == NULL) { + PyErr_SetString(PyExc_ValueError, + "NULL pointer access"); + return NULL; +@@ -5218,7 +5338,7 @@ + + ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(myself))); + StgInfo *stginfo; +- if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) { ++ if (PyStgInfo_FromObject(st, myself, &stginfo) < 0) { + return NULL; + } + assert(stginfo); /* Cannot be NULL for pointer object instances */ +@@ -5236,14 +5356,14 @@ + size = iteminfo->size; + offset = index * iteminfo->size; + +- return PyCData_get(st, proto, stginfo->getfunc, (PyObject *)self, +- index, size, (*(char **)self->b_ptr) + offset); ++ return PyCData_get(st, proto, stginfo->getfunc, myself, ++ index, size, (char *)((char *)deref + offset)); + } + + static int + Pointer_ass_item(PyObject *myself, Py_ssize_t index, PyObject *value) + { +- CDataObject *self = (CDataObject *)myself; ++ CDataObject *self = _CDataObject_CAST(myself); + Py_ssize_t size; + Py_ssize_t offset; + PyObject *proto; +@@ -5254,7 +5374,8 @@ + return -1; + } + +- if (*(void **)self->b_ptr == NULL) { ++ void *deref = locked_deref(self); ++ if (deref == NULL) { + PyErr_SetString(PyExc_ValueError, + "NULL pointer access"); + return -1; +@@ -5262,7 +5383,7 @@ + + ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(myself))); + StgInfo *stginfo; +- if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) { ++ if (PyStgInfo_FromObject(st, myself, &stginfo) < 0) { + return -1; + } + assert(stginfo); /* Cannot be NULL for pointer instances */ +@@ -5280,14 +5401,15 @@ + size = iteminfo->size; + offset = index * iteminfo->size; + +- return PyCData_set(st, (PyObject *)self, proto, stginfo->setfunc, value, +- index, size, (*(char **)self->b_ptr) + offset); ++ return PyCData_set(st, myself, proto, stginfo->setfunc, value, ++ index, size, ((char *)deref + offset)); + } + + static PyObject * +-Pointer_get_contents(CDataObject *self, void *closure) ++Pointer_get_contents(PyObject *self, void *closure) + { +- if (*(void **)self->b_ptr == NULL) { ++ void *deref = locked_deref(_CDataObject_CAST(self)); ++ if (deref == NULL) { + PyErr_SetString(PyExc_ValueError, + "NULL pointer access"); + return NULL; +@@ -5295,21 +5417,20 @@ + + ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self))); + StgInfo *stginfo; +- if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) { ++ if (PyStgInfo_FromObject(st, self, &stginfo) < 0) { + return NULL; + } + assert(stginfo); /* Cannot be NULL for pointer instances */ + +- return PyCData_FromBaseObj(st, stginfo->proto, +- (PyObject *)self, 0, +- *(void **)self->b_ptr); ++ return PyCData_FromBaseObj(st, stginfo->proto, self, 0, deref); + } + + static int +-Pointer_set_contents(CDataObject *self, PyObject *value, void *closure) ++Pointer_set_contents(PyObject *op, PyObject *value, void *closure) + { + CDataObject *dst; + PyObject *keep; ++ CDataObject *self = _CDataObject_CAST(op); + + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, +@@ -5318,7 +5439,7 @@ + } + ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self))); + StgInfo *stginfo; +- if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) { ++ if (PyStgInfo_FromObject(st, op, &stginfo) < 0) { + return -1; + } + assert(stginfo); /* Cannot be NULL for pointer instances */ +@@ -5337,7 +5458,7 @@ + } + + dst = (CDataObject *)value; +- *(void **)self->b_ptr = dst->b_ptr; ++ locked_deref_assign(self, dst->b_ptr); + + /* + A Pointer instance must keep the value it points to alive. So, a +@@ -5357,17 +5478,15 @@ + } + + static PyGetSetDef Pointer_getsets[] = { +- { "contents", (getter)Pointer_get_contents, +- (setter)Pointer_set_contents, ++ { "contents", Pointer_get_contents, Pointer_set_contents, + "the object this pointer points to (read-write)", NULL }, + { NULL, NULL } + }; + + static int +-Pointer_init(CDataObject *self, PyObject *args, PyObject *kw) ++Pointer_init(PyObject *self, PyObject *args, PyObject *kw) + { + PyObject *value = NULL; +- + if (!PyArg_UnpackTuple(args, "POINTER", 0, 1, &value)) + return -1; + if (value == NULL) +@@ -5394,7 +5513,7 @@ + static PyObject * + Pointer_subscript(PyObject *myself, PyObject *item) + { +- CDataObject *self = (CDataObject *)myself; ++ CDataObject *self = _CDataObject_CAST(myself); + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) +@@ -5460,7 +5579,7 @@ + + ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(myself))); + StgInfo *stginfo; +- if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) { ++ if (PyStgInfo_FromObject(st, myself, &stginfo) < 0) { + return NULL; + } + assert(stginfo); /* Cannot be NULL for pointer instances */ +@@ -5472,41 +5591,53 @@ + } + assert(iteminfo); + if (iteminfo->getfunc == _ctypes_get_fielddesc("c")->getfunc) { +- char *ptr = *(char **)self->b_ptr; ++ char *ptr = locked_deref(self); + char *dest; + + if (len <= 0) + return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); + if (step == 1) { +- return PyBytes_FromStringAndSize(ptr + start, +- len); ++ PyObject *res; ++ LOCK_PTR(self); ++ res = PyBytes_FromStringAndSize(ptr + start, ++ len); ++ UNLOCK_PTR(self); ++ return res; + } + dest = (char *)PyMem_Malloc(len); + if (dest == NULL) + return PyErr_NoMemory(); ++ LOCK_PTR(self); + for (cur = start, i = 0; i < len; cur += step, i++) { + dest[i] = ptr[cur]; + } ++ UNLOCK_PTR(self); + np = PyBytes_FromStringAndSize(dest, len); + PyMem_Free(dest); + return np; + } + if (iteminfo->getfunc == _ctypes_get_fielddesc("u")->getfunc) { +- wchar_t *ptr = *(wchar_t **)self->b_ptr; ++ wchar_t *ptr = locked_deref(self); + wchar_t *dest; + + if (len <= 0) + return Py_GetConstant(Py_CONSTANT_EMPTY_STR); + if (step == 1) { +- return PyUnicode_FromWideChar(ptr + start, +- len); ++ PyObject *res; ++ LOCK_PTR(self); ++ res = PyUnicode_FromWideChar(ptr + start, ++ len); ++ UNLOCK_PTR(self); ++ return res; + } + dest = PyMem_New(wchar_t, len); + if (dest == NULL) + return PyErr_NoMemory(); ++ LOCK_PTR(self); + for (cur = start, i = 0; i < len; cur += step, i++) { + dest[i] = ptr[cur]; + } ++ UNLOCK_PTR(self); + np = PyUnicode_FromWideChar(dest, len); + PyMem_Free(dest); + return np; +@@ -5530,13 +5661,13 @@ + } + + static int +-Pointer_bool(CDataObject *self) ++Pointer_bool(PyObject *self) + { +- return (*(void **)self->b_ptr != NULL); ++ return locked_deref(_CDataObject_CAST(self)) != NULL; + } + + static PyType_Slot pycpointer_slots[] = { +- {Py_tp_doc, PyDoc_STR("XXX to be provided")}, ++ {Py_tp_doc, (void *)PyDoc_STR("XXX to be provided")}, + {Py_tp_getset, Pointer_getsets}, + {Py_tp_init, Pointer_init}, + {Py_tp_new, Pointer_new}, +@@ -5740,7 +5871,7 @@ + } + } + /* Should we assert that result is a pointer type? */ +- memcpy(result->b_ptr, &ptr, sizeof(void *)); ++ locked_memcpy_to(result, &ptr, sizeof(void *)); + return (PyObject *)result; + + failed: +@@ -5761,6 +5892,22 @@ + return PyUnicode_FromWideChar(ptr, ssize); + } + ++static PyObject * ++memoryview_at(void *ptr, Py_ssize_t size, int readonly) ++{ ++ if (PySys_Audit("ctypes.memoryview_at", "nni", ++ (Py_ssize_t)ptr, size, readonly) < 0) { ++ return NULL; ++ } ++ if (size < 0) { ++ PyErr_Format(PyExc_ValueError, ++ "memoryview_at: size is negative (or overflowed): %zd", ++ size); ++ return NULL; ++ } ++ return PyMemoryView_FromMemory(ptr, size, ++ readonly ? PyBUF_READ : PyBUF_WRITE); ++} + + static int + _ctypes_add_types(PyObject *mod) +@@ -5889,6 +6036,7 @@ + MOD_ADD("_string_at_addr", PyLong_FromVoidPtr(string_at)); + MOD_ADD("_cast_addr", PyLong_FromVoidPtr(cast)); + MOD_ADD("_wstring_at_addr", PyLong_FromVoidPtr(wstring_at)); ++ MOD_ADD("_memoryview_at_addr", PyLong_FromVoidPtr(memoryview_at)); + + /* If RTLD_LOCAL is not defined (Windows!), set it to zero. */ + #if !HAVE_DECL_RTLD_LOCAL +diff --git a/Modules/_ctypes/_ctypes_test_generated.c.h b/Modules/_ctypes/_ctypes_test_generated.c.h +index 46a3e4b01e2..d70b33eaa8b 100644 +--- a/Modules/_ctypes/_ctypes_test_generated.c.h ++++ b/Modules/_ctypes/_ctypes_test_generated.c.h +@@ -56,7 +56,8 @@ + struct SingleInt { + int a; + }; +- struct SingleInt value = {0}; ++ struct SingleInt value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("SingleInt")); + APPEND(PyLong_FromLong(sizeof(struct SingleInt))); + APPEND(PyLong_FromLong(_Alignof(struct SingleInt))); +@@ -69,7 +70,8 @@ + union SingleInt_Union { + int a; + }; +- union SingleInt_Union value = {0}; ++ union SingleInt_Union value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("SingleInt_Union")); + APPEND(PyLong_FromLong(sizeof(union SingleInt_Union))); + APPEND(PyLong_FromLong(_Alignof(union SingleInt_Union))); +@@ -82,7 +84,8 @@ + struct SingleU32 { + uint32_t a; + }; +- struct SingleU32 value = {0}; ++ struct SingleU32 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("SingleU32")); + APPEND(PyLong_FromLong(sizeof(struct SingleU32))); + APPEND(PyLong_FromLong(_Alignof(struct SingleU32))); +@@ -97,7 +100,8 @@ + int8_t y; + uint16_t z; + }; +- struct SimpleStruct value = {0}; ++ struct SimpleStruct value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("SimpleStruct")); + APPEND(PyLong_FromLong(sizeof(struct SimpleStruct))); + APPEND(PyLong_FromLong(_Alignof(struct SimpleStruct))); +@@ -114,7 +118,8 @@ + int8_t y; + uint16_t z; + }; +- union SimpleUnion value = {0}; ++ union SimpleUnion value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("SimpleUnion")); + APPEND(PyLong_FromLong(sizeof(union SimpleUnion))); + APPEND(PyLong_FromLong(_Alignof(union SimpleUnion))); +@@ -136,7 +141,8 @@ + int64_t i64; + uint64_t u64; + }; +- struct ManyTypes value = {0}; ++ struct ManyTypes value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("ManyTypes")); + APPEND(PyLong_FromLong(sizeof(struct ManyTypes))); + APPEND(PyLong_FromLong(_Alignof(struct ManyTypes))); +@@ -163,7 +169,8 @@ + int64_t i64; + uint64_t u64; + }; +- union ManyTypesU value = {0}; ++ union ManyTypesU value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("ManyTypesU")); + APPEND(PyLong_FromLong(sizeof(union ManyTypesU))); + APPEND(PyLong_FromLong(_Alignof(union ManyTypesU))); +@@ -197,7 +204,8 @@ + uint16_t z; + }; + }; +- struct Nested value = {0}; ++ struct Nested value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Nested")); + APPEND(PyLong_FromLong(sizeof(struct Nested))); + APPEND(PyLong_FromLong(_Alignof(struct Nested))); +@@ -223,7 +231,8 @@ + int64_t b; + }; + #pragma pack(pop) +- struct Packed1 value = {0}; ++ struct Packed1 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Packed1")); + APPEND(PyLong_FromLong(sizeof(struct Packed1))); + APPEND(PyLong_FromLong(_Alignof(struct Packed1))); +@@ -247,7 +256,8 @@ + int64_t b; + }; + #pragma pack(pop) +- struct Packed2 value = {0}; ++ struct Packed2 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Packed2")); + APPEND(PyLong_FromLong(sizeof(struct Packed2))); + APPEND(PyLong_FromLong(_Alignof(struct Packed2))); +@@ -271,7 +281,8 @@ + int64_t b; + }; + #pragma pack(pop) +- struct Packed3 value = {0}; ++ struct Packed3 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Packed3")); + APPEND(PyLong_FromLong(sizeof(struct Packed3))); + APPEND(PyLong_FromLong(_Alignof(struct Packed3))); +@@ -295,7 +306,8 @@ + int64_t b; + }; + #pragma pack(pop) +- struct Packed4 value = {0}; ++ struct Packed4 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Packed4")); + APPEND(PyLong_FromLong(sizeof(struct Packed4))); + APPEND(PyLong_FromLong(_Alignof(struct Packed4))); +@@ -316,7 +328,8 @@ + int64_t b; + int32_t c; + }; +- struct X86_32EdgeCase value = {0}; ++ struct X86_32EdgeCase value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("X86_32EdgeCase")); + APPEND(PyLong_FromLong(sizeof(struct X86_32EdgeCase))); + APPEND(PyLong_FromLong(_Alignof(struct X86_32EdgeCase))); +@@ -333,7 +346,8 @@ + unsigned int b :5; + unsigned int c :7; + }; +- struct MSBitFieldExample value = {0}; ++ struct MSBitFieldExample value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("MSBitFieldExample")); + APPEND(PyLong_FromLong(sizeof(struct MSBitFieldExample))); + APPEND(PyLong_FromLong(_Alignof(struct MSBitFieldExample))); +@@ -351,7 +365,8 @@ + unsigned int may_straddle :30; + unsigned int last :18; + }; +- struct MSStraddlingExample value = {0}; ++ struct MSStraddlingExample value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("MSStraddlingExample")); + APPEND(PyLong_FromLong(sizeof(struct MSStraddlingExample))); + APPEND(PyLong_FromLong(_Alignof(struct MSStraddlingExample))); +@@ -375,7 +390,8 @@ + int H :8; + int I :9; + }; +- struct IntBits value = {0}; ++ struct IntBits value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("IntBits")); + APPEND(PyLong_FromLong(sizeof(struct IntBits))); + APPEND(PyLong_FromLong(_Alignof(struct IntBits))); +@@ -413,7 +429,8 @@ + short R :6; + short S :7; + }; +- struct Bits value = {0}; ++ struct Bits value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Bits")); + APPEND(PyLong_FromLong(sizeof(struct Bits))); + APPEND(PyLong_FromLong(_Alignof(struct Bits))); +@@ -456,7 +473,8 @@ + int H :8; + int I :9; + }; +- struct IntBits_MSVC value = {0}; ++ struct IntBits_MSVC value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("IntBits_MSVC")); + APPEND(PyLong_FromLong(sizeof(struct IntBits_MSVC))); + APPEND(PyLong_FromLong(_Alignof(struct IntBits_MSVC))); +@@ -499,7 +517,8 @@ + short R :6; + short S :7; + }; +- struct Bits_MSVC value = {0}; ++ struct Bits_MSVC value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Bits_MSVC")); + APPEND(PyLong_FromLong(sizeof(struct Bits_MSVC))); + APPEND(PyLong_FromLong(_Alignof(struct Bits_MSVC))); +@@ -536,7 +555,8 @@ + int64_t b :62; + int64_t c :1; + }; +- struct I64Bits value = {0}; ++ struct I64Bits value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("I64Bits")); + APPEND(PyLong_FromLong(sizeof(struct I64Bits))); + APPEND(PyLong_FromLong(_Alignof(struct I64Bits))); +@@ -560,7 +580,8 @@ + uint64_t b :62; + uint64_t c :1; + }; +- struct U64Bits value = {0}; ++ struct U64Bits value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("U64Bits")); + APPEND(PyLong_FromLong(sizeof(struct U64Bits))); + APPEND(PyLong_FromLong(_Alignof(struct U64Bits))); +@@ -584,7 +605,8 @@ + int8_t b :3; + int8_t c :1; + }; +- struct Struct331_8 value = {0}; ++ struct Struct331_8 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct331_8")); + APPEND(PyLong_FromLong(sizeof(struct Struct331_8))); + APPEND(PyLong_FromLong(_Alignof(struct Struct331_8))); +@@ -608,7 +630,8 @@ + int8_t b :6; + int8_t c :1; + }; +- struct Struct1x1_8 value = {0}; ++ struct Struct1x1_8 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct1x1_8")); + APPEND(PyLong_FromLong(sizeof(struct Struct1x1_8))); + APPEND(PyLong_FromLong(_Alignof(struct Struct1x1_8))); +@@ -633,7 +656,8 @@ + int8_t b :6; + int8_t c :1; + }; +- struct Struct1nx1_8 value = {0}; ++ struct Struct1nx1_8 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct1nx1_8")); + APPEND(PyLong_FromLong(sizeof(struct Struct1nx1_8))); + APPEND(PyLong_FromLong(_Alignof(struct Struct1nx1_8))); +@@ -658,7 +682,8 @@ + int8_t b :6; + int8_t c :6; + }; +- struct Struct3xx_8 value = {0}; ++ struct Struct3xx_8 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct3xx_8")); + APPEND(PyLong_FromLong(sizeof(struct Struct3xx_8))); + APPEND(PyLong_FromLong(_Alignof(struct Struct3xx_8))); +@@ -682,7 +707,8 @@ + uint8_t b :3; + uint8_t c :1; + }; +- struct Struct331_u8 value = {0}; ++ struct Struct331_u8 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct331_u8")); + APPEND(PyLong_FromLong(sizeof(struct Struct331_u8))); + APPEND(PyLong_FromLong(_Alignof(struct Struct331_u8))); +@@ -706,7 +732,8 @@ + uint8_t b :6; + uint8_t c :1; + }; +- struct Struct1x1_u8 value = {0}; ++ struct Struct1x1_u8 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct1x1_u8")); + APPEND(PyLong_FromLong(sizeof(struct Struct1x1_u8))); + APPEND(PyLong_FromLong(_Alignof(struct Struct1x1_u8))); +@@ -731,7 +758,8 @@ + uint8_t b :6; + uint8_t c :1; + }; +- struct Struct1nx1_u8 value = {0}; ++ struct Struct1nx1_u8 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct1nx1_u8")); + APPEND(PyLong_FromLong(sizeof(struct Struct1nx1_u8))); + APPEND(PyLong_FromLong(_Alignof(struct Struct1nx1_u8))); +@@ -756,7 +784,8 @@ + uint8_t b :6; + uint8_t c :6; + }; +- struct Struct3xx_u8 value = {0}; ++ struct Struct3xx_u8 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct3xx_u8")); + APPEND(PyLong_FromLong(sizeof(struct Struct3xx_u8))); + APPEND(PyLong_FromLong(_Alignof(struct Struct3xx_u8))); +@@ -780,7 +809,8 @@ + int16_t b :3; + int16_t c :1; + }; +- struct Struct331_16 value = {0}; ++ struct Struct331_16 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct331_16")); + APPEND(PyLong_FromLong(sizeof(struct Struct331_16))); + APPEND(PyLong_FromLong(_Alignof(struct Struct331_16))); +@@ -804,7 +834,8 @@ + int16_t b :14; + int16_t c :1; + }; +- struct Struct1x1_16 value = {0}; ++ struct Struct1x1_16 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct1x1_16")); + APPEND(PyLong_FromLong(sizeof(struct Struct1x1_16))); + APPEND(PyLong_FromLong(_Alignof(struct Struct1x1_16))); +@@ -829,7 +860,8 @@ + int16_t b :14; + int16_t c :1; + }; +- struct Struct1nx1_16 value = {0}; ++ struct Struct1nx1_16 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct1nx1_16")); + APPEND(PyLong_FromLong(sizeof(struct Struct1nx1_16))); + APPEND(PyLong_FromLong(_Alignof(struct Struct1nx1_16))); +@@ -854,7 +886,8 @@ + int16_t b :14; + int16_t c :14; + }; +- struct Struct3xx_16 value = {0}; ++ struct Struct3xx_16 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct3xx_16")); + APPEND(PyLong_FromLong(sizeof(struct Struct3xx_16))); + APPEND(PyLong_FromLong(_Alignof(struct Struct3xx_16))); +@@ -878,7 +911,8 @@ + uint16_t b :3; + uint16_t c :1; + }; +- struct Struct331_u16 value = {0}; ++ struct Struct331_u16 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct331_u16")); + APPEND(PyLong_FromLong(sizeof(struct Struct331_u16))); + APPEND(PyLong_FromLong(_Alignof(struct Struct331_u16))); +@@ -902,7 +936,8 @@ + uint16_t b :14; + uint16_t c :1; + }; +- struct Struct1x1_u16 value = {0}; ++ struct Struct1x1_u16 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct1x1_u16")); + APPEND(PyLong_FromLong(sizeof(struct Struct1x1_u16))); + APPEND(PyLong_FromLong(_Alignof(struct Struct1x1_u16))); +@@ -927,7 +962,8 @@ + uint16_t b :14; + uint16_t c :1; + }; +- struct Struct1nx1_u16 value = {0}; ++ struct Struct1nx1_u16 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct1nx1_u16")); + APPEND(PyLong_FromLong(sizeof(struct Struct1nx1_u16))); + APPEND(PyLong_FromLong(_Alignof(struct Struct1nx1_u16))); +@@ -952,7 +988,8 @@ + uint16_t b :14; + uint16_t c :14; + }; +- struct Struct3xx_u16 value = {0}; ++ struct Struct3xx_u16 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct3xx_u16")); + APPEND(PyLong_FromLong(sizeof(struct Struct3xx_u16))); + APPEND(PyLong_FromLong(_Alignof(struct Struct3xx_u16))); +@@ -976,7 +1013,8 @@ + int32_t b :3; + int32_t c :1; + }; +- struct Struct331_32 value = {0}; ++ struct Struct331_32 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct331_32")); + APPEND(PyLong_FromLong(sizeof(struct Struct331_32))); + APPEND(PyLong_FromLong(_Alignof(struct Struct331_32))); +@@ -1000,7 +1038,8 @@ + int32_t b :30; + int32_t c :1; + }; +- struct Struct1x1_32 value = {0}; ++ struct Struct1x1_32 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct1x1_32")); + APPEND(PyLong_FromLong(sizeof(struct Struct1x1_32))); + APPEND(PyLong_FromLong(_Alignof(struct Struct1x1_32))); +@@ -1025,7 +1064,8 @@ + int32_t b :30; + int32_t c :1; + }; +- struct Struct1nx1_32 value = {0}; ++ struct Struct1nx1_32 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct1nx1_32")); + APPEND(PyLong_FromLong(sizeof(struct Struct1nx1_32))); + APPEND(PyLong_FromLong(_Alignof(struct Struct1nx1_32))); +@@ -1050,7 +1090,8 @@ + int32_t b :30; + int32_t c :30; + }; +- struct Struct3xx_32 value = {0}; ++ struct Struct3xx_32 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct3xx_32")); + APPEND(PyLong_FromLong(sizeof(struct Struct3xx_32))); + APPEND(PyLong_FromLong(_Alignof(struct Struct3xx_32))); +@@ -1074,7 +1115,8 @@ + uint32_t b :3; + uint32_t c :1; + }; +- struct Struct331_u32 value = {0}; ++ struct Struct331_u32 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct331_u32")); + APPEND(PyLong_FromLong(sizeof(struct Struct331_u32))); + APPEND(PyLong_FromLong(_Alignof(struct Struct331_u32))); +@@ -1098,7 +1140,8 @@ + uint32_t b :30; + uint32_t c :1; + }; +- struct Struct1x1_u32 value = {0}; ++ struct Struct1x1_u32 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct1x1_u32")); + APPEND(PyLong_FromLong(sizeof(struct Struct1x1_u32))); + APPEND(PyLong_FromLong(_Alignof(struct Struct1x1_u32))); +@@ -1123,7 +1166,8 @@ + uint32_t b :30; + uint32_t c :1; + }; +- struct Struct1nx1_u32 value = {0}; ++ struct Struct1nx1_u32 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct1nx1_u32")); + APPEND(PyLong_FromLong(sizeof(struct Struct1nx1_u32))); + APPEND(PyLong_FromLong(_Alignof(struct Struct1nx1_u32))); +@@ -1148,7 +1192,8 @@ + uint32_t b :30; + uint32_t c :30; + }; +- struct Struct3xx_u32 value = {0}; ++ struct Struct3xx_u32 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct3xx_u32")); + APPEND(PyLong_FromLong(sizeof(struct Struct3xx_u32))); + APPEND(PyLong_FromLong(_Alignof(struct Struct3xx_u32))); +@@ -1172,7 +1217,8 @@ + int64_t b :3; + int64_t c :1; + }; +- struct Struct331_64 value = {0}; ++ struct Struct331_64 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct331_64")); + APPEND(PyLong_FromLong(sizeof(struct Struct331_64))); + APPEND(PyLong_FromLong(_Alignof(struct Struct331_64))); +@@ -1196,7 +1242,8 @@ + int64_t b :62; + int64_t c :1; + }; +- struct Struct1x1_64 value = {0}; ++ struct Struct1x1_64 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct1x1_64")); + APPEND(PyLong_FromLong(sizeof(struct Struct1x1_64))); + APPEND(PyLong_FromLong(_Alignof(struct Struct1x1_64))); +@@ -1221,7 +1268,8 @@ + int64_t b :62; + int64_t c :1; + }; +- struct Struct1nx1_64 value = {0}; ++ struct Struct1nx1_64 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct1nx1_64")); + APPEND(PyLong_FromLong(sizeof(struct Struct1nx1_64))); + APPEND(PyLong_FromLong(_Alignof(struct Struct1nx1_64))); +@@ -1246,7 +1294,8 @@ + int64_t b :62; + int64_t c :62; + }; +- struct Struct3xx_64 value = {0}; ++ struct Struct3xx_64 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct3xx_64")); + APPEND(PyLong_FromLong(sizeof(struct Struct3xx_64))); + APPEND(PyLong_FromLong(_Alignof(struct Struct3xx_64))); +@@ -1270,7 +1319,8 @@ + uint64_t b :3; + uint64_t c :1; + }; +- struct Struct331_u64 value = {0}; ++ struct Struct331_u64 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct331_u64")); + APPEND(PyLong_FromLong(sizeof(struct Struct331_u64))); + APPEND(PyLong_FromLong(_Alignof(struct Struct331_u64))); +@@ -1294,7 +1344,8 @@ + uint64_t b :62; + uint64_t c :1; + }; +- struct Struct1x1_u64 value = {0}; ++ struct Struct1x1_u64 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct1x1_u64")); + APPEND(PyLong_FromLong(sizeof(struct Struct1x1_u64))); + APPEND(PyLong_FromLong(_Alignof(struct Struct1x1_u64))); +@@ -1319,7 +1370,8 @@ + uint64_t b :62; + uint64_t c :1; + }; +- struct Struct1nx1_u64 value = {0}; ++ struct Struct1nx1_u64 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct1nx1_u64")); + APPEND(PyLong_FromLong(sizeof(struct Struct1nx1_u64))); + APPEND(PyLong_FromLong(_Alignof(struct Struct1nx1_u64))); +@@ -1344,7 +1396,8 @@ + uint64_t b :62; + uint64_t c :62; + }; +- struct Struct3xx_u64 value = {0}; ++ struct Struct3xx_u64 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Struct3xx_u64")); + APPEND(PyLong_FromLong(sizeof(struct Struct3xx_u64))); + APPEND(PyLong_FromLong(_Alignof(struct Struct3xx_u64))); +@@ -1367,7 +1420,8 @@ + signed char a :4; + int b :4; + }; +- struct Mixed1 value = {0}; ++ struct Mixed1 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Mixed1")); + APPEND(PyLong_FromLong(sizeof(struct Mixed1))); + APPEND(PyLong_FromLong(_Alignof(struct Mixed1))); +@@ -1389,7 +1443,8 @@ + signed char a :4; + int32_t b :32; + }; +- struct Mixed2 value = {0}; ++ struct Mixed2 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Mixed2")); + APPEND(PyLong_FromLong(sizeof(struct Mixed2))); + APPEND(PyLong_FromLong(_Alignof(struct Mixed2))); +@@ -1411,7 +1466,8 @@ + signed char a :4; + unsigned char b :4; + }; +- struct Mixed3 value = {0}; ++ struct Mixed3 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Mixed3")); + APPEND(PyLong_FromLong(sizeof(struct Mixed3))); + APPEND(PyLong_FromLong(_Alignof(struct Mixed3))); +@@ -1437,7 +1493,8 @@ + short e :4; + int f :24; + }; +- struct Mixed4 value = {0}; ++ struct Mixed4 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Mixed4")); + APPEND(PyLong_FromLong(sizeof(struct Mixed4))); + APPEND(PyLong_FromLong(_Alignof(struct Mixed4))); +@@ -1463,7 +1520,8 @@ + unsigned int A :1; + unsigned short B :16; + }; +- struct Mixed5 value = {0}; ++ struct Mixed5 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Mixed5")); + APPEND(PyLong_FromLong(sizeof(struct Mixed5))); + APPEND(PyLong_FromLong(_Alignof(struct Mixed5))); +@@ -1485,7 +1543,8 @@ + unsigned long long A :1; + unsigned int B :32; + }; +- struct Mixed6 value = {0}; ++ struct Mixed6 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Mixed6")); + APPEND(PyLong_FromLong(sizeof(struct Mixed6))); + APPEND(PyLong_FromLong(_Alignof(struct Mixed6))); +@@ -1508,7 +1567,8 @@ + uint32_t B :20; + uint64_t C :24; + }; +- struct Mixed7 value = {0}; ++ struct Mixed7 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Mixed7")); + APPEND(PyLong_FromLong(sizeof(struct Mixed7))); + APPEND(PyLong_FromLong(_Alignof(struct Mixed7))); +@@ -1532,7 +1592,8 @@ + uint32_t B :32; + unsigned long long C :1; + }; +- struct Mixed8_a value = {0}; ++ struct Mixed8_a value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Mixed8_a")); + APPEND(PyLong_FromLong(sizeof(struct Mixed8_a))); + APPEND(PyLong_FromLong(_Alignof(struct Mixed8_a))); +@@ -1556,7 +1617,8 @@ + uint32_t B; + unsigned long long C :1; + }; +- struct Mixed8_b value = {0}; ++ struct Mixed8_b value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Mixed8_b")); + APPEND(PyLong_FromLong(sizeof(struct Mixed8_b))); + APPEND(PyLong_FromLong(_Alignof(struct Mixed8_b))); +@@ -1579,7 +1641,8 @@ + uint8_t A; + uint32_t B :1; + }; +- struct Mixed9 value = {0}; ++ struct Mixed9 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Mixed9")); + APPEND(PyLong_FromLong(sizeof(struct Mixed9))); + APPEND(PyLong_FromLong(_Alignof(struct Mixed9))); +@@ -1601,7 +1664,8 @@ + uint32_t A :1; + uint64_t B :1; + }; +- struct Mixed10 value = {0}; ++ struct Mixed10 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Mixed10")); + APPEND(PyLong_FromLong(sizeof(struct Mixed10))); + APPEND(PyLong_FromLong(_Alignof(struct Mixed10))); +@@ -1623,7 +1687,8 @@ + uint32_t A :1; + uint64_t B :1; + }; +- struct Example_gh_95496 value = {0}; ++ struct Example_gh_95496 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Example_gh_95496")); + APPEND(PyLong_FromLong(sizeof(struct Example_gh_95496))); + APPEND(PyLong_FromLong(_Alignof(struct Example_gh_95496))); +@@ -1655,7 +1720,8 @@ + uint16_t b1 :12; + }; + #pragma pack(pop) +- struct Example_gh_84039_bad value = {0}; ++ struct Example_gh_84039_bad value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Example_gh_84039_bad")); + APPEND(PyLong_FromLong(sizeof(struct Example_gh_84039_bad))); + APPEND(PyLong_FromLong(_Alignof(struct Example_gh_84039_bad))); +@@ -1693,7 +1759,8 @@ + uint8_t a7 :1; + }; + #pragma pack(pop) +- struct Example_gh_84039_good_a value = {0}; ++ struct Example_gh_84039_good_a value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Example_gh_84039_good_a")); + APPEND(PyLong_FromLong(sizeof(struct Example_gh_84039_good_a))); + APPEND(PyLong_FromLong(_Alignof(struct Example_gh_84039_good_a))); +@@ -1735,7 +1802,8 @@ + uint16_t b1 :12; + }; + #pragma pack(pop) +- struct Example_gh_84039_good value = {0}; ++ struct Example_gh_84039_good value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Example_gh_84039_good")); + APPEND(PyLong_FromLong(sizeof(struct Example_gh_84039_good))); + APPEND(PyLong_FromLong(_Alignof(struct Example_gh_84039_good))); +@@ -1775,7 +1843,8 @@ + uint32_t R2 :2; + }; + #pragma pack(pop) +- struct Example_gh_73939 value = {0}; ++ struct Example_gh_73939 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Example_gh_73939")); + APPEND(PyLong_FromLong(sizeof(struct Example_gh_73939))); + APPEND(PyLong_FromLong(_Alignof(struct Example_gh_73939))); +@@ -1806,7 +1875,8 @@ + uint8_t b :8; + uint32_t c :16; + }; +- struct Example_gh_86098 value = {0}; ++ struct Example_gh_86098 value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Example_gh_86098")); + APPEND(PyLong_FromLong(sizeof(struct Example_gh_86098))); + APPEND(PyLong_FromLong(_Alignof(struct Example_gh_86098))); +@@ -1832,7 +1902,8 @@ + uint32_t c :16; + }; + #pragma pack(pop) +- struct Example_gh_86098_pack value = {0}; ++ struct Example_gh_86098_pack value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("Example_gh_86098_pack")); + APPEND(PyLong_FromLong(sizeof(struct Example_gh_86098_pack))); + APPEND(PyLong_FromLong(_Alignof(struct Example_gh_86098_pack))); +@@ -1858,7 +1929,8 @@ + }; + signed char y; + }; +- struct AnonBitfields value = {0}; ++ struct AnonBitfields value; ++ memset(&value, 0, sizeof(value)); + APPEND(PyUnicode_FromString("AnonBitfields")); + APPEND(PyLong_FromLong(sizeof(struct AnonBitfields))); + APPEND(PyLong_FromLong(_Alignof(struct AnonBitfields))); +diff --git a/Modules/_ctypes/callbacks.c b/Modules/_ctypes/callbacks.c +index 7b9f6437c7d..6dd6f6ec56d 100644 +--- a/Modules/_ctypes/callbacks.c ++++ b/Modules/_ctypes/callbacks.c +@@ -81,22 +81,6 @@ + + /**************************************************************/ + +-static void +-PrintError(const char *msg, ...) +-{ +- char buf[512]; +- PyObject *f = PySys_GetObject("stderr"); +- va_list marker; +- +- va_start(marker, msg); +- PyOS_vsnprintf(buf, sizeof(buf), msg, marker); +- va_end(marker); +- if (f != NULL && f != Py_None) +- PyFile_WriteString(buf, f); +- PyErr_Print(); +-} +- +- + #ifdef MS_WIN32 + /* + * We must call AddRef() on non-NULL COM pointers we receive as arguments +@@ -108,26 +92,23 @@ + * after checking for PyObject_IsTrue(), but this would probably be somewhat + * slower. + */ +-static void ++static int + TryAddRef(PyObject *cnv, CDataObject *obj) + { + IUnknown *punk; + PyObject *attrdict = _PyType_GetDict((PyTypeObject *)cnv); + if (!attrdict) { +- return; ++ return 0; + } + int r = PyDict_Contains(attrdict, &_Py_ID(_needs_com_addref_)); + if (r <= 0) { +- if (r < 0) { +- PrintError("getting _needs_com_addref_"); +- } +- return; ++ return r; + } + + punk = *(IUnknown **)obj->b_ptr; + if (punk) + punk->lpVtbl->AddRef(punk); +- return; ++ return 0; + } + #endif + +@@ -162,14 +143,13 @@ + + StgInfo *info; + if (PyStgInfo_FromType(st, cnv, &info) < 0) { +- goto Done; ++ goto Error; + } + + if (info && info->getfunc && !_ctypes_simple_instance(st, cnv)) { + PyObject *v = info->getfunc(*pArgs, info->size); + if (!v) { +- PrintError("create argument %zd:\n", i); +- goto Done; ++ goto Error; + } + args[i] = v; + /* XXX XXX XX +@@ -182,24 +162,25 @@ + /* Hm, shouldn't we use PyCData_AtAddress() or something like that instead? */ + CDataObject *obj = (CDataObject *)_PyObject_CallNoArgs(cnv); + if (!obj) { +- PrintError("create argument %zd:\n", i); +- goto Done; ++ goto Error; + } + if (!CDataObject_Check(st, obj)) { ++ PyErr_Format(PyExc_TypeError, ++ "%R returned unexpected result of type %T", cnv, obj); + Py_DECREF(obj); +- PrintError("unexpected result of create argument %zd:\n", i); +- goto Done; ++ goto Error; + } + memcpy(obj->b_ptr, *pArgs, info->size); + args[i] = (PyObject *)obj; + #ifdef MS_WIN32 +- TryAddRef(cnv, obj); ++ if (TryAddRef(cnv, obj) < 0) { ++ goto Error; ++ } + #endif + } else { +- PyErr_SetString(PyExc_TypeError, +- "cannot build parameter"); +- PrintError("Parsing argument %zd\n", i); +- goto Done; ++ PyErr_Format(PyExc_TypeError, ++ "cannot build parameter of type %R", cnv); ++ goto Error; + } + /* XXX error handling! */ + pArgs++; +@@ -207,8 +188,13 @@ + + if (flags & (FUNCFLAG_USE_ERRNO | FUNCFLAG_USE_LASTERROR)) { + error_object = _ctypes_get_errobj(st, &space); +- if (error_object == NULL) ++ if (error_object == NULL) { ++ PyErr_FormatUnraisable( ++ "Exception ignored while setting error for " ++ "ctypes callback function %R", ++ callable); + goto Done; ++ } + if (flags & FUNCFLAG_USE_ERRNO) { + int temp = space[0]; + space[0] = errno; +@@ -225,9 +211,9 @@ + + result = PyObject_Vectorcall(callable, args, nargs, NULL); + if (result == NULL) { +- PyErr_FormatUnraisable( +- "Exception ignored on calling ctypes callback function %R", +- callable); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "calling ctypes callback function %R", ++ callable); + } + + #ifdef MS_WIN32 +@@ -264,12 +250,12 @@ + be the result. EXCEPT when restype is py_object - Python + itself knows how to manage the refcount of these objects. + */ +- PyObject *keep = setfunc(mem, result, 0); ++ PyObject *keep = setfunc(mem, result, restype->size); + + if (keep == NULL) { + /* Could not convert callback result. */ + PyErr_FormatUnraisable( +- "Exception ignored on converting result " ++ "Exception ignored while converting result " + "of ctypes callback function %R", + callable); + } +@@ -282,7 +268,7 @@ + "memory leak in callback function.", + 1) == -1) { + PyErr_FormatUnraisable( +- "Exception ignored on converting result " ++ "Exception ignored while converting result " + "of ctypes callback function %R", + callable); + } +@@ -295,6 +281,14 @@ + for (j = 0; j < i; j++) { + Py_DECREF(args[j]); + } ++ return; ++ ++ Error: ++ PyErr_FormatUnraisable( ++ "Exception ignored while creating argument %zd for " ++ "ctypes callback function %R", ++ i, callable); ++ goto Done; + } + + static void closure_fcn(ffi_cif *cif, +@@ -487,39 +481,31 @@ + { + PyObject *func, *result; + long retval; +- static PyObject *context; +- +- if (context == NULL) +- context = PyUnicode_InternFromString("_ctypes.DllGetClassObject"); + +- func = _PyImport_GetModuleAttrString("ctypes", "DllGetClassObject"); ++ func = PyImport_ImportModuleAttrString("ctypes", "DllGetClassObject"); + if (!func) { +- PyErr_WriteUnraisable(context ? context : Py_None); + /* There has been a warning before about this already */ +- return E_FAIL; ++ goto error; + } + + { + PyObject *py_rclsid = PyLong_FromVoidPtr((void *)rclsid); + if (py_rclsid == NULL) { + Py_DECREF(func); +- PyErr_WriteUnraisable(context ? context : Py_None); +- return E_FAIL; ++ goto error; + } + PyObject *py_riid = PyLong_FromVoidPtr((void *)riid); + if (py_riid == NULL) { + Py_DECREF(func); + Py_DECREF(py_rclsid); +- PyErr_WriteUnraisable(context ? context : Py_None); +- return E_FAIL; ++ goto error; + } + PyObject *py_ppv = PyLong_FromVoidPtr(ppv); + if (py_ppv == NULL) { + Py_DECREF(py_rclsid); + Py_DECREF(py_riid); + Py_DECREF(func); +- PyErr_WriteUnraisable(context ? context : Py_None); +- return E_FAIL; ++ goto error; + } + result = PyObject_CallFunctionObjArgs(func, + py_rclsid, +@@ -532,17 +518,21 @@ + } + Py_DECREF(func); + if (!result) { +- PyErr_WriteUnraisable(context ? context : Py_None); +- return E_FAIL; ++ goto error; + } + + retval = PyLong_AsLong(result); + if (PyErr_Occurred()) { +- PyErr_WriteUnraisable(context ? context : Py_None); +- retval = E_FAIL; ++ Py_DECREF(result); ++ goto error; + } + Py_DECREF(result); + return retval; ++ ++error: ++ PyErr_FormatUnraisable("Exception ignored while calling " ++ "ctypes.DllGetClassObject"); ++ return E_FAIL; + } + + STDAPI DllGetClassObject(REFCLSID rclsid, +@@ -561,43 +551,30 @@ + + long Call_CanUnloadNow(void) + { +- PyObject *mod, *func, *result; +- long retval; +- static PyObject *context; +- +- if (context == NULL) +- context = PyUnicode_InternFromString("_ctypes.DllCanUnloadNow"); +- +- mod = PyImport_ImportModule("ctypes"); +- if (!mod) { +-/* OutputDebugString("Could not import ctypes"); */ +- /* We assume that this error can only occur when shutting +- down, so we silently ignore it */ +- PyErr_Clear(); +- return E_FAIL; +- } +- /* Other errors cannot be raised, but are printed to stderr */ +- func = PyObject_GetAttrString(mod, "DllCanUnloadNow"); +- Py_DECREF(mod); ++ PyObject *func = PyImport_ImportModuleAttrString("ctypes", ++ "DllCanUnloadNow"); + if (!func) { +- PyErr_WriteUnraisable(context ? context : Py_None); +- return E_FAIL; ++ goto error; + } + +- result = _PyObject_CallNoArgs(func); ++ PyObject *result = _PyObject_CallNoArgs(func); + Py_DECREF(func); + if (!result) { +- PyErr_WriteUnraisable(context ? context : Py_None); +- return E_FAIL; ++ goto error; + } + +- retval = PyLong_AsLong(result); ++ long retval = PyLong_AsLong(result); + if (PyErr_Occurred()) { +- PyErr_WriteUnraisable(context ? context : Py_None); +- retval = E_FAIL; ++ Py_DECREF(result); ++ goto error; + } + Py_DECREF(result); + return retval; ++ ++error: ++ PyErr_FormatUnraisable("Exception ignored while calling " ++ "ctypes.DllCanUnloadNow"); ++ return E_FAIL; + } + + /* +diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c +index 218c3a9c81e..c6b6460126c 100644 +--- a/Modules/_ctypes/callproc.c ++++ b/Modules/_ctypes/callproc.c +@@ -493,27 +493,29 @@ + } + + static int +-PyCArg_traverse(PyCArgObject *self, visitproc visit, void *arg) ++PyCArg_traverse(PyObject *op, visitproc visit, void *arg) + { ++ PyCArgObject *self = _PyCArgObject_CAST(op); + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->obj); + return 0; + } + + static int +-PyCArg_clear(PyCArgObject *self) ++PyCArg_clear(PyObject *op) + { ++ PyCArgObject *self = _PyCArgObject_CAST(op); + Py_CLEAR(self->obj); + return 0; + } + + static void +-PyCArg_dealloc(PyCArgObject *self) ++PyCArg_dealloc(PyObject *self) + { + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + (void)PyCArg_clear(self); +- tp->tp_free((PyObject *)self); ++ tp->tp_free(self); + Py_DECREF(tp); + } + +@@ -524,8 +526,9 @@ + } + + static PyObject * +-PyCArg_repr(PyCArgObject *self) ++PyCArg_repr(PyObject *op) + { ++ PyCArgObject *self = _PyCArgObject_CAST(op); + switch(self->tag) { + case 'b': + case 'B': +@@ -1588,10 +1591,11 @@ + Py_XDECREF(name2); + if (!handle) { + const char *errmsg = dlerror(); +- if (!errmsg) +- errmsg = "dlopen() error"; +- PyErr_SetString(PyExc_OSError, +- errmsg); ++ if (errmsg) { ++ _PyErr_SetLocaleString(PyExc_OSError, errmsg); ++ return NULL; ++ } ++ PyErr_SetString(PyExc_OSError, "dlopen() error"); + return NULL; + } + return PyLong_FromVoidPtr(handle); +@@ -1604,8 +1608,12 @@ + if (!PyArg_ParseTuple(args, "O&:dlclose", &_parse_voidp, &handle)) + return NULL; + if (dlclose(handle)) { +- PyErr_SetString(PyExc_OSError, +- dlerror()); ++ const char *errmsg = dlerror(); ++ if (errmsg) { ++ _PyErr_SetLocaleString(PyExc_OSError, errmsg); ++ return NULL; ++ } ++ PyErr_SetString(PyExc_OSError, "dlclose() error"); + return NULL; + } + Py_RETURN_NONE; +@@ -1639,21 +1647,14 @@ + if (ptr) { + return PyLong_FromVoidPtr(ptr); + } +- #ifdef USE_DLERROR +- const char *dlerr = dlerror(); +- if (dlerr) { +- PyObject *message = PyUnicode_DecodeLocale(dlerr, "surrogateescape"); +- if (message) { +- PyErr_SetObject(PyExc_OSError, message); +- Py_DECREF(message); +- return NULL; +- } +- // Ignore errors from PyUnicode_DecodeLocale, +- // fall back to the generic error below. +- PyErr_Clear(); ++ #ifdef USE_DLERROR ++ const char *errmsg = dlerror(); ++ if (errmsg) { ++ _PyErr_SetLocaleString(PyExc_OSError, errmsg); ++ return NULL; + } +- #endif +- #undef USE_DLERROR ++ #endif ++ #undef USE_DLERROR + PyErr_Format(PyExc_OSError, "symbol '%s' not found", name); + return NULL; + } +diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c +index 2b9e8a1a10d..9924d62c088 100644 +--- a/Modules/_ctypes/cfield.c ++++ b/Modules/_ctypes/cfield.c +@@ -10,6 +10,7 @@ + + #include "pycore_bitutils.h" // _Py_bswap32() + #include "pycore_call.h" // _PyObject_CallNoArgs() ++#include // bool + + #include + #include "ctypes.h" +@@ -193,17 +194,18 @@ + + + static int +-PyCField_set(CFieldObject *self, PyObject *inst, PyObject *value) ++PyCField_set(PyObject *op, PyObject *inst, PyObject *value) + { + CDataObject *dst; + char *ptr; ++ CFieldObject *self = _CFieldObject_CAST(op); + ctypes_state *st = get_module_state_by_class(Py_TYPE(self)); + if (!CDataObject_Check(st, inst)) { + PyErr_SetString(PyExc_TypeError, + "not a ctype instance"); + return -1; + } +- dst = (CDataObject *)inst; ++ dst = _CDataObject_CAST(inst); + ptr = dst->b_ptr + self->offset; + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, +@@ -211,13 +213,14 @@ + return -1; + } + return PyCData_set(st, inst, self->proto, self->setfunc, value, +- self->index, self->size, ptr); ++ self->index, self->size, ptr); + } + + static PyObject * +-PyCField_get(CFieldObject *self, PyObject *inst, PyTypeObject *type) ++PyCField_get(PyObject *op, PyObject *inst, PyTypeObject *type) + { + CDataObject *src; ++ CFieldObject *self = _CFieldObject_CAST(op); + if (inst == NULL) { + return Py_NewRef(self); + } +@@ -227,21 +230,21 @@ + "not a ctype instance"); + return NULL; + } +- src = (CDataObject *)inst; ++ src = _CDataObject_CAST(inst); + return PyCData_get(st, self->proto, self->getfunc, inst, +- self->index, self->size, src->b_ptr + self->offset); ++ self->index, self->size, src->b_ptr + self->offset); + } + + static PyObject * + PyCField_get_offset(PyObject *self, void *data) + { +- return PyLong_FromSsize_t(((CFieldObject *)self)->offset); ++ return PyLong_FromSsize_t(_CFieldObject_CAST(self)->offset); + } + + static PyObject * + PyCField_get_size(PyObject *self, void *data) + { +- return PyLong_FromSsize_t(((CFieldObject *)self)->size); ++ return PyLong_FromSsize_t(_CFieldObject_CAST(self)->size); + } + + static PyGetSetDef PyCField_getset[] = { +@@ -251,17 +254,20 @@ + }; + + static int +-PyCField_traverse(CFieldObject *self, visitproc visit, void *arg) ++PyCField_traverse(PyObject *op, visitproc visit, void *arg) + { ++ CFieldObject *self = _CFieldObject_CAST(op); + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->proto); + return 0; + } + + static int +-PyCField_clear(CFieldObject *self) ++PyCField_clear(PyObject *op) + { ++ CFieldObject *self = _CFieldObject_CAST(op); + Py_CLEAR(self->proto); ++ Py_CLEAR(self->name); + return 0; + } + +@@ -270,17 +276,16 @@ + { + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); +- CFieldObject *self_cf = (CFieldObject *)self; +- (void)PyCField_clear(self_cf); +- Py_CLEAR(self_cf->name); ++ (void)PyCField_clear(self); + Py_TYPE(self)->tp_free(self); + Py_DECREF(tp); + } + + static PyObject * +-PyCField_repr(CFieldObject *self) ++PyCField_repr(PyObject *op) + { + PyObject *result; ++ CFieldObject *self = _CFieldObject_CAST(op); + Py_ssize_t bits = NUM_BITS(self->size); + Py_ssize_t size = LOW_BIT(self->size); + const char *name; +@@ -320,61 +325,6 @@ + }; + + +-/******************************************************************/ +-/* +- Accessor functions +-*/ +- +-/* Derived from Modules/structmodule.c: +- Helper routine to get a Python integer and raise the appropriate error +- if it isn't one */ +- +-static int +-get_long(PyObject *v, long *p) +-{ +- long x = PyLong_AsUnsignedLongMask(v); +- if (x == -1 && PyErr_Occurred()) +- return -1; +- *p = x; +- return 0; +-} +- +-/* Same, but handling unsigned long */ +- +-static int +-get_ulong(PyObject *v, unsigned long *p) +-{ +- unsigned long x = PyLong_AsUnsignedLongMask(v); +- if (x == (unsigned long)-1 && PyErr_Occurred()) +- return -1; +- *p = x; +- return 0; +-} +- +-/* Same, but handling native long long. */ +- +-static int +-get_longlong(PyObject *v, long long *p) +-{ +- long long x = PyLong_AsUnsignedLongLongMask(v); +- if (x == -1 && PyErr_Occurred()) +- return -1; +- *p = x; +- return 0; +-} +- +-/* Same, but handling native unsigned long long. */ +- +-static int +-get_ulonglong(PyObject *v, unsigned long long *p) +-{ +- unsigned long long x = PyLong_AsUnsignedLongLongMask(v); +- if (x == (unsigned long long)-1 && PyErr_Occurred()) +- return -1; +- *p = x; +- return 0; +-} +- + /***************************************************************** + * Integer fields, with bitfield support + */ +@@ -404,34 +354,8 @@ + /* This macro RETURNS the first parameter with the bit field CHANGED. */ + #define SET(type, x, v, size) \ + (NUM_BITS(size) ? \ +- ( ( (type)x & ~(BIT_MASK(type, size) << LOW_BIT(size)) ) | ( ((type)v & BIT_MASK(type, size)) << LOW_BIT(size) ) ) \ +- : (type)v) +- +-#if SIZEOF_SHORT == 2 +-# define SWAP_SHORT _Py_bswap16 +-#else +-# error "unsupported short size" +-#endif +- +-#if SIZEOF_INT == 4 +-# define SWAP_INT _Py_bswap32 +-#else +-# error "unsupported int size" +-#endif +- +-#if SIZEOF_LONG == 4 +-# define SWAP_LONG _Py_bswap32 +-#elif SIZEOF_LONG == 8 +-# define SWAP_LONG _Py_bswap64 +-#else +-# error "unsupported long size" +-#endif +- +-#if SIZEOF_LONG_LONG == 8 +-# define SWAP_LONG_LONG _Py_bswap64 +-#else +-# error "unsupported long long size" +-#endif ++ ( ( (type)(x) & ~(BIT_MASK(type, size) << LOW_BIT(size)) ) | ( ((type)(v) & BIT_MASK(type, size)) << LOW_BIT(size) ) ) \ ++ : (type)(v)) + + /***************************************************************** + * The setter methods return an object which must be kept alive, to keep the +@@ -454,203 +378,145 @@ + #endif + + /***************************************************************** +- * integer accessor methods, supporting bit fields ++ * accessor methods for fixed-width integers (e.g. int8_t, uint64_t), ++ * supporting bit fields. ++ * These are named e.g. `i8_set`/`i8_get` or `u64_set`/`u64_get`, ++ * and are all alike, so they're defined using a macro. + */ + +-static PyObject * +-b_set(void *ptr, PyObject *value, Py_ssize_t size) +-{ +- long val; +- if (get_long(value, &val) < 0) +- return NULL; +- *(signed char *)ptr = SET(signed char, *(signed char *)ptr, val, size); +- _RET(value); +-} +- +- +-static PyObject * +-b_get(void *ptr, Py_ssize_t size) +-{ +- signed char val = *(signed char *)ptr; +- GET_BITFIELD(val, size); +- return PyLong_FromLong(val); +-} +- +-static PyObject * +-B_set(void *ptr, PyObject *value, Py_ssize_t size) +-{ +- unsigned long val; +- if (get_ulong(value, &val) < 0) +- return NULL; +- *(unsigned char *)ptr = SET(unsigned char, *(unsigned char*)ptr, val, size); +- _RET(value); +-} +- +- +-static PyObject * +-B_get(void *ptr, Py_ssize_t size) +-{ +- unsigned char val = *(unsigned char *)ptr; +- GET_BITFIELD(val, size); +- return PyLong_FromLong(val); +-} +- +-static PyObject * +-h_set(void *ptr, PyObject *value, Py_ssize_t size) +-{ +- long val; +- short x; +- if (get_long(value, &val) < 0) +- return NULL; +- memcpy(&x, ptr, sizeof(x)); +- x = SET(short, x, val, size); +- memcpy(ptr, &x, sizeof(x)); +- _RET(value); +-} +- +- +-static PyObject * +-h_set_sw(void *ptr, PyObject *value, Py_ssize_t size) +-{ +- long val; +- short field; +- if (get_long(value, &val) < 0) { +- return NULL; +- } +- memcpy(&field, ptr, sizeof(field)); +- field = SWAP_SHORT(field); +- field = SET(short, field, val, size); +- field = SWAP_SHORT(field); +- memcpy(ptr, &field, sizeof(field)); +- _RET(value); +-} +- +-static PyObject * +-h_get(void *ptr, Py_ssize_t size) +-{ +- short val; +- memcpy(&val, ptr, sizeof(val)); +- GET_BITFIELD(val, size); +- return PyLong_FromLong((long)val); +-} +- +-static PyObject * +-h_get_sw(void *ptr, Py_ssize_t size) +-{ +- short val; +- memcpy(&val, ptr, sizeof(val)); +- val = SWAP_SHORT(val); +- GET_BITFIELD(val, size); +- return PyLong_FromLong(val); +-} +- +-static PyObject * +-H_set(void *ptr, PyObject *value, Py_ssize_t size) +-{ +- unsigned long val; +- unsigned short x; +- if (get_ulong(value, &val) < 0) +- return NULL; +- memcpy(&x, ptr, sizeof(x)); +- x = SET(unsigned short, x, val, size); +- memcpy(ptr, &x, sizeof(x)); +- _RET(value); +-} +- +-static PyObject * +-H_set_sw(void *ptr, PyObject *value, Py_ssize_t size) +-{ +- unsigned long val; +- unsigned short field; +- if (get_ulong(value, &val) < 0) { +- return NULL; +- } +- memcpy(&field, ptr, sizeof(field)); +- field = SWAP_SHORT(field); +- field = SET(unsigned short, field, val, size); +- field = SWAP_SHORT(field); +- memcpy(ptr, &field, sizeof(field)); +- _RET(value); +-} +- +- +-static PyObject * +-H_get(void *ptr, Py_ssize_t size) +-{ +- unsigned short val; +- memcpy(&val, ptr, sizeof(val)); +- GET_BITFIELD(val, size); +- return PyLong_FromLong(val); +-} +- +-static PyObject * +-H_get_sw(void *ptr, Py_ssize_t size) +-{ +- unsigned short val; +- memcpy(&val, ptr, sizeof(val)); +- val = SWAP_SHORT(val); +- GET_BITFIELD(val, size); +- return PyLong_FromLong(val); +-} +- +-static PyObject * +-i_set(void *ptr, PyObject *value, Py_ssize_t size) +-{ +- long val; +- int x; +- if (get_long(value, &val) < 0) +- return NULL; +- memcpy(&x, ptr, sizeof(x)); +- x = SET(int, x, val, size); +- memcpy(ptr, &x, sizeof(x)); +- _RET(value); +-} +- +-static PyObject * +-i_set_sw(void *ptr, PyObject *value, Py_ssize_t size) +-{ +- long val; +- int field; +- if (get_long(value, &val) < 0) { +- return NULL; +- } +- memcpy(&field, ptr, sizeof(field)); +- field = SWAP_INT(field); +- field = SET(int, field, val, size); +- field = SWAP_INT(field); +- memcpy(ptr, &field, sizeof(field)); +- _RET(value); +-} +- ++#define FIXINT_GETSET(TAG, CTYPE, NBITS, PYAPI_FROMFUNC) \ ++ static PyObject * \ ++ TAG ## _set(void *ptr, PyObject *value, Py_ssize_t size_arg) \ ++ { \ ++ assert(NUM_BITS(size_arg) || (size_arg == (NBITS) / 8)); \ ++ CTYPE val; \ ++ if (PyLong_Check(value) \ ++ && PyUnstable_Long_IsCompact((PyLongObject *)value)) \ ++ { \ ++ val = (CTYPE)PyUnstable_Long_CompactValue( \ ++ (PyLongObject *)value); \ ++ } \ ++ else { \ ++ Py_ssize_t res = PyLong_AsNativeBytes( \ ++ value, &val, (NBITS) / 8, \ ++ Py_ASNATIVEBYTES_NATIVE_ENDIAN \ ++ | Py_ASNATIVEBYTES_ALLOW_INDEX); \ ++ if (res < 0) { \ ++ return NULL; \ ++ } \ ++ } \ ++ CTYPE prev; \ ++ memcpy(&prev, ptr, (NBITS) / 8); \ ++ val = SET(CTYPE, prev, val, size_arg); \ ++ memcpy(ptr, &val, (NBITS) / 8); \ ++ _RET(value); \ ++ } \ ++ \ ++ static PyObject * \ ++ TAG ## _get(void *ptr, Py_ssize_t size_arg) \ ++ { \ ++ assert(NUM_BITS(size_arg) || (size_arg == (NBITS) / 8)); \ ++ CTYPE val; \ ++ memcpy(&val, ptr, sizeof(val)); \ ++ GET_BITFIELD(val, size_arg); \ ++ return PYAPI_FROMFUNC(val); \ ++ } \ ++ /////////////////////////////////////////////////////////////////////////// ++ ++/* Another macro for byte-swapped variants (e.g. `i8_set_sw`/`i8_get_sw`) */ ++ ++#define FIXINT_GETSET_SW(TAG, CTYPE, NBITS, PYAPI_FROMFUNC, PY_SWAPFUNC) \ ++ static PyObject * \ ++ TAG ## _set_sw(void *ptr, PyObject *value, Py_ssize_t size_arg) \ ++ { \ ++ CTYPE val; \ ++ PyObject *res = TAG ## _set(&val, value, (NBITS) / 8); \ ++ if (res == NULL) { \ ++ return NULL; \ ++ } \ ++ Py_DECREF(res); \ ++ CTYPE field; \ ++ memcpy(&field, ptr, sizeof(field)); \ ++ field = PY_SWAPFUNC(field); \ ++ field = SET(CTYPE, field, val, size_arg); \ ++ field = PY_SWAPFUNC(field); \ ++ memcpy(ptr, &field, sizeof(field)); \ ++ _RET(value); \ ++ } \ ++ \ ++ static PyObject * \ ++ TAG ## _get_sw(void *ptr, Py_ssize_t size_arg) \ ++ { \ ++ assert(NUM_BITS(size_arg) || (size_arg == (NBITS) / 8)); \ ++ CTYPE val; \ ++ memcpy(&val, ptr, sizeof(val)); \ ++ val = PY_SWAPFUNC(val); \ ++ GET_BITFIELD(val, size_arg); \ ++ return PYAPI_FROMFUNC(val); \ ++ } \ ++ /////////////////////////////////////////////////////////////////////////// ++ ++/* These macros are expanded for all supported combinations of byte sizes ++ * (1, 2, 4, 8), signed and unsigned, native and swapped byteorder. ++ * That's a lot, so generate the list with Argument Clinic (`make clinic`). ++ */ + +-static PyObject * +-i_get(void *ptr, Py_ssize_t size) +-{ +- int val; +- memcpy(&val, ptr, sizeof(val)); +- GET_BITFIELD(val, size); +- return PyLong_FromLong(val); +-} ++/*[python input] ++for nbits in 8, 16, 32, 64: ++ for sgn in 'i', 'u': ++ u = 'u' if sgn == 'u' else '' ++ U = u.upper() ++ apibits = max(nbits, 32) ++ parts = [ ++ f'{sgn}{nbits}', ++ f'{u}int{nbits}_t', ++ f'{nbits}', ++ f'PyLong_From{U}Int{apibits}', ++ ] ++ print(f'FIXINT_GETSET({", ".join(parts)})') ++ if nbits > 8: ++ parts.append(f'_Py_bswap{nbits}') ++ print(f'FIXINT_GETSET_SW({", ".join(parts)})') ++[python start generated code]*/ ++FIXINT_GETSET(i8, int8_t, 8, PyLong_FromInt32) ++FIXINT_GETSET(u8, uint8_t, 8, PyLong_FromUInt32) ++FIXINT_GETSET(i16, int16_t, 16, PyLong_FromInt32) ++FIXINT_GETSET_SW(i16, int16_t, 16, PyLong_FromInt32, _Py_bswap16) ++FIXINT_GETSET(u16, uint16_t, 16, PyLong_FromUInt32) ++FIXINT_GETSET_SW(u16, uint16_t, 16, PyLong_FromUInt32, _Py_bswap16) ++FIXINT_GETSET(i32, int32_t, 32, PyLong_FromInt32) ++FIXINT_GETSET_SW(i32, int32_t, 32, PyLong_FromInt32, _Py_bswap32) ++FIXINT_GETSET(u32, uint32_t, 32, PyLong_FromUInt32) ++FIXINT_GETSET_SW(u32, uint32_t, 32, PyLong_FromUInt32, _Py_bswap32) ++FIXINT_GETSET(i64, int64_t, 64, PyLong_FromInt64) ++FIXINT_GETSET_SW(i64, int64_t, 64, PyLong_FromInt64, _Py_bswap64) ++FIXINT_GETSET(u64, uint64_t, 64, PyLong_FromUInt64) ++FIXINT_GETSET_SW(u64, uint64_t, 64, PyLong_FromUInt64, _Py_bswap64) ++/*[python end generated code: output=3d60c96fa58e07d5 input=0b7e166f2ea18e70]*/ ++ ++// For one-byte types, swapped variants are the same as native ++#define i8_set_sw i8_set ++#define i8_get_sw i8_get ++#define u8_set_sw u8_set ++#define u8_get_sw u8_get ++ ++#undef FIXINT_GETSET ++#undef FIXINT_GETSET_SW + +-static PyObject * +-i_get_sw(void *ptr, Py_ssize_t size) +-{ +- int val; +- memcpy(&val, ptr, sizeof(val)); +- val = SWAP_INT(val); +- GET_BITFIELD(val, size); +- return PyLong_FromLong(val); +-} ++/***************************************************************** ++ * non-integer accessor methods, not supporting bit fields ++ */ + + #ifndef MS_WIN32 + /* http://msdn.microsoft.com/en-us/library/cc237864.aspx */ + #define VARIANT_FALSE 0x0000 + #define VARIANT_TRUE 0xFFFF + #endif +-/* short BOOL - VARIANT_BOOL */ ++/* v: short BOOL - VARIANT_BOOL */ + static PyObject * +-vBOOL_set(void *ptr, PyObject *value, Py_ssize_t size) ++v_set(void *ptr, PyObject *value, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(short int))); + switch (PyObject_IsTrue(value)) { + case -1: + return NULL; +@@ -664,22 +530,25 @@ + } + + static PyObject * +-vBOOL_get(void *ptr, Py_ssize_t size) ++v_get(void *ptr, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(short int))); + return PyBool_FromLong((long)*(short int *)ptr); + } + ++/* bool ('?'): bool (i.e. _Bool) */ + static PyObject * + bool_set(void *ptr, PyObject *value, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(bool))); + switch (PyObject_IsTrue(value)) { + case -1: + return NULL; + case 0: +- *(_Bool *)ptr = 0; ++ *(bool *)ptr = 0; + _RET(value); + default: +- *(_Bool *)ptr = 1; ++ *(bool *)ptr = 1; + _RET(value); + } + } +@@ -687,260 +556,15 @@ + static PyObject * + bool_get(void *ptr, Py_ssize_t size) + { +- return PyBool_FromLong((long)*(_Bool *)ptr); +-} +- +-static PyObject * +-I_set(void *ptr, PyObject *value, Py_ssize_t size) +-{ +- unsigned long val; +- unsigned int x; +- if (get_ulong(value, &val) < 0) +- return NULL; +- memcpy(&x, ptr, sizeof(x)); +- x = SET(unsigned int, x, val, size); +- memcpy(ptr, &x, sizeof(x)); +- _RET(value); +-} +- +-static PyObject * +-I_set_sw(void *ptr, PyObject *value, Py_ssize_t size) +-{ +- unsigned long val; +- unsigned int field; +- if (get_ulong(value, &val) < 0) { +- return NULL; +- } +- memcpy(&field, ptr, sizeof(field)); +- field = SWAP_INT(field); +- field = SET(unsigned int, field, (unsigned int)val, size); +- field = SWAP_INT(field); +- memcpy(ptr, &field, sizeof(field)); +- _RET(value); ++ assert(NUM_BITS(size) || (size == sizeof(bool))); ++ return PyBool_FromLong((long)*(bool *)ptr); + } + +- +-static PyObject * +-I_get(void *ptr, Py_ssize_t size) +-{ +- unsigned int val; +- memcpy(&val, ptr, sizeof(val)); +- GET_BITFIELD(val, size); +- return PyLong_FromUnsignedLong(val); +-} +- +-static PyObject * +-I_get_sw(void *ptr, Py_ssize_t size) +-{ +- unsigned int val; +- memcpy(&val, ptr, sizeof(val)); +- val = SWAP_INT(val); +- GET_BITFIELD(val, size); +- return PyLong_FromUnsignedLong(val); +-} +- +-static PyObject * +-l_set(void *ptr, PyObject *value, Py_ssize_t size) +-{ +- long val; +- long x; +- if (get_long(value, &val) < 0) +- return NULL; +- memcpy(&x, ptr, sizeof(x)); +- x = SET(long, x, val, size); +- memcpy(ptr, &x, sizeof(x)); +- _RET(value); +-} +- +-static PyObject * +-l_set_sw(void *ptr, PyObject *value, Py_ssize_t size) +-{ +- long val; +- long field; +- if (get_long(value, &val) < 0) { +- return NULL; +- } +- memcpy(&field, ptr, sizeof(field)); +- field = SWAP_LONG(field); +- field = SET(long, field, val, size); +- field = SWAP_LONG(field); +- memcpy(ptr, &field, sizeof(field)); +- _RET(value); +-} +- +- +-static PyObject * +-l_get(void *ptr, Py_ssize_t size) +-{ +- long val; +- memcpy(&val, ptr, sizeof(val)); +- GET_BITFIELD(val, size); +- return PyLong_FromLong(val); +-} +- +-static PyObject * +-l_get_sw(void *ptr, Py_ssize_t size) +-{ +- long val; +- memcpy(&val, ptr, sizeof(val)); +- val = SWAP_LONG(val); +- GET_BITFIELD(val, size); +- return PyLong_FromLong(val); +-} +- +-static PyObject * +-L_set(void *ptr, PyObject *value, Py_ssize_t size) +-{ +- unsigned long val; +- unsigned long x; +- if (get_ulong(value, &val) < 0) +- return NULL; +- memcpy(&x, ptr, sizeof(x)); +- x = SET(unsigned long, x, val, size); +- memcpy(ptr, &x, sizeof(x)); +- _RET(value); +-} +- +-static PyObject * +-L_set_sw(void *ptr, PyObject *value, Py_ssize_t size) +-{ +- unsigned long val; +- unsigned long field; +- if (get_ulong(value, &val) < 0) { +- return NULL; +- } +- memcpy(&field, ptr, sizeof(field)); +- field = SWAP_LONG(field); +- field = SET(unsigned long, field, val, size); +- field = SWAP_LONG(field); +- memcpy(ptr, &field, sizeof(field)); +- _RET(value); +-} +- +- +-static PyObject * +-L_get(void *ptr, Py_ssize_t size) +-{ +- unsigned long val; +- memcpy(&val, ptr, sizeof(val)); +- GET_BITFIELD(val, size); +- return PyLong_FromUnsignedLong(val); +-} +- +-static PyObject * +-L_get_sw(void *ptr, Py_ssize_t size) +-{ +- unsigned long val; +- memcpy(&val, ptr, sizeof(val)); +- val = SWAP_LONG(val); +- GET_BITFIELD(val, size); +- return PyLong_FromUnsignedLong(val); +-} +- +-static PyObject * +-q_set(void *ptr, PyObject *value, Py_ssize_t size) +-{ +- long long val; +- long long x; +- if (get_longlong(value, &val) < 0) +- return NULL; +- memcpy(&x, ptr, sizeof(x)); +- x = SET(long long, x, val, size); +- memcpy(ptr, &x, sizeof(x)); +- _RET(value); +-} +- +-static PyObject * +-q_set_sw(void *ptr, PyObject *value, Py_ssize_t size) +-{ +- long long val; +- long long field; +- if (get_longlong(value, &val) < 0) { +- return NULL; +- } +- memcpy(&field, ptr, sizeof(field)); +- field = SWAP_LONG_LONG(field); +- field = SET(long long, field, val, size); +- field = SWAP_LONG_LONG(field); +- memcpy(ptr, &field, sizeof(field)); +- _RET(value); +-} +- +-static PyObject * +-q_get(void *ptr, Py_ssize_t size) +-{ +- long long val; +- memcpy(&val, ptr, sizeof(val)); +- GET_BITFIELD(val, size); +- return PyLong_FromLongLong(val); +-} +- +-static PyObject * +-q_get_sw(void *ptr, Py_ssize_t size) +-{ +- long long val; +- memcpy(&val, ptr, sizeof(val)); +- val = SWAP_LONG_LONG(val); +- GET_BITFIELD(val, size); +- return PyLong_FromLongLong(val); +-} +- +-static PyObject * +-Q_set(void *ptr, PyObject *value, Py_ssize_t size) +-{ +- unsigned long long val; +- unsigned long long x; +- if (get_ulonglong(value, &val) < 0) +- return NULL; +- memcpy(&x, ptr, sizeof(x)); +- x = SET(long long, x, val, size); +- memcpy(ptr, &x, sizeof(x)); +- _RET(value); +-} +- +-static PyObject * +-Q_set_sw(void *ptr, PyObject *value, Py_ssize_t size) +-{ +- unsigned long long val; +- unsigned long long field; +- if (get_ulonglong(value, &val) < 0) { +- return NULL; +- } +- memcpy(&field, ptr, sizeof(field)); +- field = SWAP_LONG_LONG(field); +- field = SET(unsigned long long, field, val, size); +- field = SWAP_LONG_LONG(field); +- memcpy(ptr, &field, sizeof(field)); +- _RET(value); +-} +- +-static PyObject * +-Q_get(void *ptr, Py_ssize_t size) +-{ +- unsigned long long val; +- memcpy(&val, ptr, sizeof(val)); +- GET_BITFIELD(val, size); +- return PyLong_FromUnsignedLongLong(val); +-} +- +-static PyObject * +-Q_get_sw(void *ptr, Py_ssize_t size) +-{ +- unsigned long long val; +- memcpy(&val, ptr, sizeof(val)); +- val = SWAP_LONG_LONG(val); +- GET_BITFIELD(val, size); +- return PyLong_FromUnsignedLongLong(val); +-} +- +-/***************************************************************** +- * non-integer accessor methods, not supporting bit fields +- */ +- +- ++/* g: long double */ + static PyObject * + g_set(void *ptr, PyObject *value, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(long double))); + long double x; + + x = PyFloat_AsDouble(value); +@@ -953,14 +577,17 @@ + static PyObject * + g_get(void *ptr, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(long double))); + long double val; + memcpy(&val, ptr, sizeof(long double)); + return PyFloat_FromDouble(val); + } + ++/* d: double */ + static PyObject * + d_set(void *ptr, PyObject *value, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(double))); + double x; + + x = PyFloat_AsDouble(value); +@@ -973,15 +600,18 @@ + static PyObject * + d_get(void *ptr, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(double))); + double val; + memcpy(&val, ptr, sizeof(val)); + return PyFloat_FromDouble(val); + } + + #if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX) ++/* C: double complex */ + static PyObject * + C_set(void *ptr, PyObject *value, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(double complex))); + Py_complex c = PyComplex_AsCComplex(value); + + if (c.real == -1 && PyErr_Occurred()) { +@@ -995,15 +625,18 @@ + static PyObject * + C_get(void *ptr, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(double complex))); + double complex x; + + memcpy(&x, ptr, sizeof(x)); + return PyComplex_FromDoubles(creal(x), cimag(x)); + } + ++/* E: float complex */ + static PyObject * + E_set(void *ptr, PyObject *value, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(float complex))); + Py_complex c = PyComplex_AsCComplex(value); + + if (c.real == -1 && PyErr_Occurred()) { +@@ -1017,15 +650,18 @@ + static PyObject * + E_get(void *ptr, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(float complex))); + float complex x; + + memcpy(&x, ptr, sizeof(x)); + return PyComplex_FromDoubles(crealf(x), cimagf(x)); + } + ++/* F: long double complex */ + static PyObject * + F_set(void *ptr, PyObject *value, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(long double complex))); + Py_complex c = PyComplex_AsCComplex(value); + + if (c.real == -1 && PyErr_Occurred()) { +@@ -1039,6 +675,7 @@ + static PyObject * + F_get(void *ptr, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(long double complex))); + long double complex x; + + memcpy(&x, ptr, sizeof(x)); +@@ -1046,9 +683,11 @@ + } + #endif + ++/* d: double */ + static PyObject * + d_set_sw(void *ptr, PyObject *value, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(double))); + double x; + + x = PyFloat_AsDouble(value); +@@ -1067,6 +706,7 @@ + static PyObject * + d_get_sw(void *ptr, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(double))); + #ifdef WORDS_BIGENDIAN + return PyFloat_FromDouble(PyFloat_Unpack8(ptr, 1)); + #else +@@ -1074,9 +714,11 @@ + #endif + } + ++/* f: float */ + static PyObject * + f_set(void *ptr, PyObject *value, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(float))); + float x; + + x = (float)PyFloat_AsDouble(value); +@@ -1089,6 +731,7 @@ + static PyObject * + f_get(void *ptr, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(float))); + float val; + memcpy(&val, ptr, sizeof(val)); + return PyFloat_FromDouble(val); +@@ -1097,6 +740,7 @@ + static PyObject * + f_set_sw(void *ptr, PyObject *value, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(float))); + float x; + + x = (float)PyFloat_AsDouble(value); +@@ -1115,6 +759,7 @@ + static PyObject * + f_get_sw(void *ptr, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(float))); + #ifdef WORDS_BIGENDIAN + return PyFloat_FromDouble(PyFloat_Unpack4(ptr, 1)); + #else +@@ -1122,6 +767,7 @@ + #endif + } + ++/* O: Python object */ + /* + py_object refcounts: + +@@ -1135,6 +781,7 @@ + static PyObject * + O_get(void *ptr, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(PyObject *))); + PyObject *ob = *(PyObject **)ptr; + if (ob == NULL) { + if (!PyErr_Occurred()) +@@ -1149,15 +796,18 @@ + static PyObject * + O_set(void *ptr, PyObject *value, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(PyObject *))); + /* Hm, does the memory block need it's own refcount or not? */ + *(PyObject **)ptr = value; + return Py_NewRef(value); + } + + ++/* c: a single byte-character */ + static PyObject * + c_set(void *ptr, PyObject *value, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(char))); + if (PyBytes_Check(value)) { + if (PyBytes_GET_SIZE(value) != 1) { + PyErr_Format(PyExc_TypeError, +@@ -1204,13 +854,15 @@ + static PyObject * + c_get(void *ptr, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(char))); + return PyBytes_FromStringAndSize((char *)ptr, 1); + } + +-/* u - a single wchar_t character */ ++/* u: a single wchar_t character */ + static PyObject * + u_set(void *ptr, PyObject *value, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(wchar_t))); + Py_ssize_t len; + wchar_t chars[2]; + if (!PyUnicode_Check(value)) { +@@ -1244,10 +896,11 @@ + static PyObject * + u_get(void *ptr, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(wchar_t))); + return PyUnicode_FromWideChar((wchar_t *)ptr, 1); + } + +-/* U - a unicode string */ ++/* U: a wchar_t* unicode string */ + static PyObject * + U_get(void *ptr, Py_ssize_t size) + { +@@ -1306,6 +959,7 @@ + } + + ++/* s: a byte string */ + static PyObject * + s_get(void *ptr, Py_ssize_t size) + { +@@ -1355,6 +1009,7 @@ + _RET(value); + } + ++/* z: a byte string, can be set from integer pointer */ + static PyObject * + z_set(void *ptr, PyObject *value, Py_ssize_t size) + { +@@ -1391,6 +1046,7 @@ + } + } + ++/* Z: a wchar* string, can be set from integer pointer */ + static PyObject * + Z_set(void *ptr, PyObject *value, Py_ssize_t size) + { +@@ -1445,8 +1101,9 @@ + + + #ifdef MS_WIN32 ++/* X: COM BSTR (wide-char string to be handled handled using Windows API) */ + static PyObject * +-BSTR_set(void *ptr, PyObject *value, Py_ssize_t size) ++X_set(void *ptr, PyObject *value, Py_ssize_t size) + { + BSTR bstr; + +@@ -1490,7 +1147,7 @@ + + + static PyObject * +-BSTR_get(void *ptr, Py_ssize_t size) ++X_get(void *ptr, Py_ssize_t size) + { + BSTR p; + p = *(BSTR *)ptr; +@@ -1505,9 +1162,11 @@ + } + #endif + ++/* P: generic pointer */ + static PyObject * + P_set(void *ptr, PyObject *value, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(void *))); + void *v; + if (value == Py_None) { + *(void **)ptr = NULL; +@@ -1539,154 +1198,399 @@ + static PyObject * + P_get(void *ptr, Py_ssize_t size) + { ++ assert(NUM_BITS(size) || (size == sizeof(void *))); + if (*(void **)ptr == NULL) { + Py_RETURN_NONE; + } + return PyLong_FromVoidPtr(*(void **)ptr); + } + +-static struct fielddesc formattable[] = { +- { 's', s_set, s_get, NULL}, +- { 'b', b_set, b_get, NULL}, +- { 'B', B_set, B_get, NULL}, +- { 'c', c_set, c_get, NULL}, +- { 'd', d_set, d_get, NULL, d_set_sw, d_get_sw}, +-#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX) +- { 'C', C_set, C_get, NULL}, +- { 'E', E_set, E_get, NULL}, +- { 'F', F_set, F_get, NULL}, +-#endif +- { 'g', g_set, g_get, NULL}, +- { 'f', f_set, f_get, NULL, f_set_sw, f_get_sw}, +- { 'h', h_set, h_get, NULL, h_set_sw, h_get_sw}, +- { 'H', H_set, H_get, NULL, H_set_sw, H_get_sw}, +- { 'i', i_set, i_get, NULL, i_set_sw, i_get_sw}, +- { 'I', I_set, I_get, NULL, I_set_sw, I_get_sw}, +- { 'l', l_set, l_get, NULL, l_set_sw, l_get_sw}, +- { 'L', L_set, L_get, NULL, L_set_sw, L_get_sw}, +- { 'q', q_set, q_get, NULL, q_set_sw, q_get_sw}, +- { 'Q', Q_set, Q_get, NULL, Q_set_sw, Q_get_sw}, +- { 'P', P_set, P_get, NULL}, +- { 'z', z_set, z_get, NULL}, +- { 'u', u_set, u_get, NULL}, +- { 'U', U_set, U_get, NULL}, +- { 'Z', Z_set, Z_get, NULL}, +-#ifdef MS_WIN32 +- { 'X', BSTR_set, BSTR_get, NULL}, +-#endif +- { 'v', vBOOL_set, vBOOL_get, NULL}, +-#if SIZEOF__BOOL == SIZEOF_INT +- { '?', bool_set, bool_get, NULL, I_set_sw, I_get_sw}, +-#elif SIZEOF__BOOL == SIZEOF_LONG +- { '?', bool_set, bool_get, NULL, L_set_sw, L_get_sw}, +-#elif SIZEOF__BOOL == SIZEOF_LONG_LONG +- { '?', bool_set, bool_get, NULL, Q_set_sw, Q_get_sw}, +-#else +- { '?', bool_set, bool_get, NULL}, +-#endif /* SIZEOF__BOOL */ +- { 'O', O_set, O_get, NULL}, +- { 0, NULL, NULL, NULL}, ++/* Table with info about all formats. ++ * Must be accessed via _ctypes_get_fielddesc, which initializes it on ++ * first use. After initialization it's treated as constant & read-only. ++ */ ++ ++struct formattable { ++/*[python input] ++for nbytes in 8, 16, 32, 64: ++ for sgn in 'i', 'u': ++ print(f' struct fielddesc fmt_{sgn}{nbytes};') ++for code in 'sbBcdCEFgfhHiIlLqQPzuUZXvO': ++ print(f' struct fielddesc fmt_{code};') ++[python start generated code]*/ ++ struct fielddesc fmt_i8; ++ struct fielddesc fmt_u8; ++ struct fielddesc fmt_i16; ++ struct fielddesc fmt_u16; ++ struct fielddesc fmt_i32; ++ struct fielddesc fmt_u32; ++ struct fielddesc fmt_i64; ++ struct fielddesc fmt_u64; ++ struct fielddesc fmt_s; ++ struct fielddesc fmt_b; ++ struct fielddesc fmt_B; ++ struct fielddesc fmt_c; ++ struct fielddesc fmt_d; ++ struct fielddesc fmt_C; ++ struct fielddesc fmt_E; ++ struct fielddesc fmt_F; ++ struct fielddesc fmt_g; ++ struct fielddesc fmt_f; ++ struct fielddesc fmt_h; ++ struct fielddesc fmt_H; ++ struct fielddesc fmt_i; ++ struct fielddesc fmt_I; ++ struct fielddesc fmt_l; ++ struct fielddesc fmt_L; ++ struct fielddesc fmt_q; ++ struct fielddesc fmt_Q; ++ struct fielddesc fmt_P; ++ struct fielddesc fmt_z; ++ struct fielddesc fmt_u; ++ struct fielddesc fmt_U; ++ struct fielddesc fmt_Z; ++ struct fielddesc fmt_X; ++ struct fielddesc fmt_v; ++ struct fielddesc fmt_O; ++/*[python end generated code: output=fa648744ec7f919d input=087d58357d4bf2c5]*/ ++ ++ // bool has code '?': ++ struct fielddesc fmt_bool; ++ ++ // always contains NULLs: ++ struct fielddesc fmt_nil; ++ ++ // Result of _ctypes_get_simple_type_chars. Initialized just after ++ // the rest of formattable, so we stash it here. ++ char simple_type_chars[26]; + }; + +-/* +- Ideas: Implement VARIANT in this table, using 'V' code. +- Use '?' as code for BOOL. +-*/ ++static struct formattable formattable; ++ ++ ++/* Get fielddesc info for a fixed-width integer. ++ * N.B: - must be called after (or from) _ctypes_init_fielddesc! ++ * - nbytes must be one of the supported values ++ */ ++ ++static inline struct fielddesc * ++_ctypes_fixint_fielddesc(Py_ssize_t nbytes, bool is_signed) ++{ ++#define _PACK(NBYTES, SGN) ((NBYTES<<2) + (SGN ? 1 : 0)) ++ switch (_PACK(nbytes, is_signed)) { ++/*[python input] ++for nbytes in 8, 16, 32, 64: ++ for sgn in 'i', 'u': ++ is_signed = sgn == 'i' ++ print(f' case (_PACK({nbytes // 8}, {int(is_signed)})): ' ++ + f'return &formattable.fmt_{sgn}{nbytes};') ++[python start generated code]*/ ++ case (_PACK(1, 1)): return &formattable.fmt_i8; ++ case (_PACK(1, 0)): return &formattable.fmt_u8; ++ case (_PACK(2, 1)): return &formattable.fmt_i16; ++ case (_PACK(2, 0)): return &formattable.fmt_u16; ++ case (_PACK(4, 1)): return &formattable.fmt_i32; ++ case (_PACK(4, 0)): return &formattable.fmt_u32; ++ case (_PACK(8, 1)): return &formattable.fmt_i64; ++ case (_PACK(8, 0)): return &formattable.fmt_u64; ++/*[python end generated code: output=0194ba35c4d64ff3 input=ee9f6f5bb872d645]*/ ++#undef _PACK ++ } ++ /* ctypes currently only supports platforms where the basic integer types ++ * (`char`, `short`, `int`, `long`, `long long`) have 1, 2, 4, or 8 bytes ++ * (i.e. 8 to 64 bits). ++ */ ++ Py_UNREACHABLE(); ++} ++ ++ ++/* Macro to call _ctypes_fixint_fielddesc for a given C type. */ ++ ++_Py_COMP_DIAG_PUSH ++#if defined(__GNUC__) && (__GNUC__ < 14) ++/* The signedness check expands to an expression that's always true or false. ++ * Older GCC gives a '-Wtype-limits' warning for this, which is a GCC bug ++ * (docs say it should "not warn for constant expressions"): ++ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86647 ++ * Silence that warning. ++ */ ++#pragma GCC diagnostic ignored "-Wtype-limits" ++#endif ++ ++#define FIXINT_FIELDDESC_FOR(C_TYPE) \ ++ _ctypes_fixint_fielddesc(sizeof(C_TYPE), (C_TYPE)-1 < 0) ++ + + /* Delayed initialization. Windows cannot statically reference dynamically + loaded addresses from DLLs. */ +-void +-_ctypes_init_fielddesc(void) +-{ +- struct fielddesc *fd = formattable; +- for (; fd->code; ++fd) { +- switch (fd->code) { +- case 's': fd->pffi_type = &ffi_type_pointer; break; +- case 'b': fd->pffi_type = &ffi_type_schar; break; +- case 'B': fd->pffi_type = &ffi_type_uchar; break; +- case 'c': fd->pffi_type = &ffi_type_schar; break; +- case 'd': fd->pffi_type = &ffi_type_double; break; ++static void ++_ctypes_init_fielddesc_locked(void) ++{ ++ /* Fixed-width integers */ ++ ++/*[python input] ++for nbytes in 8, 16, 32, 64: ++ for sgn in 'i', 'u': ++ is_signed = sgn == 'i' ++ u = 'u' if sgn == 'u' else 's' ++ parts = [ ++ f"0", ++ f'&ffi_type_{u}int{nbytes}', ++ f'{sgn}{nbytes}_set', ++ f'{sgn}{nbytes}_get', ++ f'{sgn}{nbytes}_set_sw', ++ f'{sgn}{nbytes}_get_sw', ++ ] ++ print(f' formattable.fmt_{sgn}{nbytes} = (struct fielddesc){{') ++ print(f' {', '.join(parts)} }};') ++[python start generated code]*/ ++ formattable.fmt_i8 = (struct fielddesc){ ++ 0, &ffi_type_sint8, i8_set, i8_get, i8_set_sw, i8_get_sw }; ++ formattable.fmt_u8 = (struct fielddesc){ ++ 0, &ffi_type_uint8, u8_set, u8_get, u8_set_sw, u8_get_sw }; ++ formattable.fmt_i16 = (struct fielddesc){ ++ 0, &ffi_type_sint16, i16_set, i16_get, i16_set_sw, i16_get_sw }; ++ formattable.fmt_u16 = (struct fielddesc){ ++ 0, &ffi_type_uint16, u16_set, u16_get, u16_set_sw, u16_get_sw }; ++ formattable.fmt_i32 = (struct fielddesc){ ++ 0, &ffi_type_sint32, i32_set, i32_get, i32_set_sw, i32_get_sw }; ++ formattable.fmt_u32 = (struct fielddesc){ ++ 0, &ffi_type_uint32, u32_set, u32_get, u32_set_sw, u32_get_sw }; ++ formattable.fmt_i64 = (struct fielddesc){ ++ 0, &ffi_type_sint64, i64_set, i64_get, i64_set_sw, i64_get_sw }; ++ formattable.fmt_u64 = (struct fielddesc){ ++ 0, &ffi_type_uint64, u64_set, u64_get, u64_set_sw, u64_get_sw }; ++/*[python end generated code: output=16806fe0ca3a9c4c input=850b8dd6388b1b10]*/ ++ ++ ++ /* Native C integers. ++ * These use getters/setters for fixed-width ints but have their own ++ * `code` and `pffi_type`. ++ */ ++ ++/*[python input] ++for base_code, base_c_type in [ ++ ('b', 'char'), ++ ('h', 'short'), ++ ('i', 'int'), ++ ('l', 'long'), ++ ('q', 'long long'), ++]: ++ for code, c_type, ffi_type in [ ++ (base_code, 'signed ' + base_c_type, 's' + base_c_type), ++ (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}';") ++ if base_code == 'q': ++ # ffi doesn't have `long long`; keep use the fixint type ++ pass ++ else: ++ 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.pffi_type = &ffi_type_schar; ++ formattable.fmt_B = *FIXINT_FIELDDESC_FOR(unsigned char); ++ 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.pffi_type = &ffi_type_sshort; ++ formattable.fmt_H = *FIXINT_FIELDDESC_FOR(unsigned short); ++ 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.pffi_type = &ffi_type_sint; ++ formattable.fmt_I = *FIXINT_FIELDDESC_FOR(unsigned int); ++ 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.pffi_type = &ffi_type_slong; ++ formattable.fmt_L = *FIXINT_FIELDDESC_FOR(unsigned long); ++ 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 = *FIXINT_FIELDDESC_FOR(unsigned long long); ++ formattable.fmt_Q.code = 'Q'; ++/*[python end generated code: output=873c87a2e6b5075a input=ee814ca263aac18e]*/ ++ ++ ++ /* Other types have bespoke setters and getters named `@_set` and `@_get`, ++ * where `@` is the type code. ++ * Some have swapped variants, `@_set_sw` and `@_get_sw` ++ */ ++ ++#define _TABLE_ENTRY(SYMBOL, FFI_TYPE, ...) \ ++ formattable.fmt_ ## SYMBOL = \ ++ (struct fielddesc){(#SYMBOL)[0], (FFI_TYPE), __VA_ARGS__}; \ ++ /////////////////////////////////////////////////////////////////////////// ++ ++#define TABLE_ENTRY(SYMBOL, FFI_TYPE) \ ++ _TABLE_ENTRY(SYMBOL, FFI_TYPE, SYMBOL ## _set, SYMBOL ## _get) \ ++ /////////////////////////////////////////////////////////////////////////// ++ ++#define TABLE_ENTRY_SW(SYMBOL, FFI_TYPE) \ ++ _TABLE_ENTRY(SYMBOL, FFI_TYPE, SYMBOL ## _set, \ ++ SYMBOL ## _get, SYMBOL ## _set_sw, SYMBOL ## _get_sw) \ ++ /////////////////////////////////////////////////////////////////////////// ++ ++ TABLE_ENTRY_SW(d, &ffi_type_double); + #if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX) +- case 'C': fd->pffi_type = &ffi_type_complex_double; break; +- case 'E': fd->pffi_type = &ffi_type_complex_float; break; +- case 'F': fd->pffi_type = &ffi_type_complex_longdouble; break; ++ if (Py_FFI_COMPLEX_AVAILABLE) { ++ TABLE_ENTRY(C, &ffi_type_complex_double); ++ TABLE_ENTRY(E, &ffi_type_complex_float); ++ TABLE_ENTRY(F, &ffi_type_complex_longdouble); ++ } + #endif +- case 'g': fd->pffi_type = &ffi_type_longdouble; break; +- case 'f': fd->pffi_type = &ffi_type_float; break; +- case 'h': fd->pffi_type = &ffi_type_sshort; break; +- case 'H': fd->pffi_type = &ffi_type_ushort; break; +- case 'i': fd->pffi_type = &ffi_type_sint; break; +- case 'I': fd->pffi_type = &ffi_type_uint; break; +- /* XXX Hm, sizeof(int) == sizeof(long) doesn't hold on every platform */ +- /* As soon as we can get rid of the type codes, this is no longer a problem */ +- #if SIZEOF_LONG == 4 +- case 'l': fd->pffi_type = &ffi_type_sint32; break; +- case 'L': fd->pffi_type = &ffi_type_uint32; break; +- #elif SIZEOF_LONG == 8 +- case 'l': fd->pffi_type = &ffi_type_sint64; break; +- case 'L': fd->pffi_type = &ffi_type_uint64; break; +- #else +- #error +- #endif +- #if SIZEOF_LONG_LONG == 8 +- case 'q': fd->pffi_type = &ffi_type_sint64; break; +- case 'Q': fd->pffi_type = &ffi_type_uint64; break; +- #else +- #error +- #endif +- case 'P': fd->pffi_type = &ffi_type_pointer; break; +- case 'z': fd->pffi_type = &ffi_type_pointer; break; +- case 'u': +- if (sizeof(wchar_t) == sizeof(short)) +- fd->pffi_type = &ffi_type_sshort; +- else if (sizeof(wchar_t) == sizeof(int)) +- fd->pffi_type = &ffi_type_sint; +- else if (sizeof(wchar_t) == sizeof(long)) +- fd->pffi_type = &ffi_type_slong; +- else +- Py_UNREACHABLE(); +- break; +- case 'U': fd->pffi_type = &ffi_type_pointer; break; +- case 'Z': fd->pffi_type = &ffi_type_pointer; break; +- #ifdef MS_WIN32 +- case 'X': fd->pffi_type = &ffi_type_pointer; break; +- #endif +- case 'v': fd->pffi_type = &ffi_type_sshort; break; +- #if SIZEOF__BOOL == 1 +- case '?': fd->pffi_type = &ffi_type_uchar; break; /* Also fallback for no native _Bool support */ +- #elif SIZEOF__BOOL == SIZEOF_SHORT +- case '?': fd->pffi_type = &ffi_type_ushort; break; +- #elif SIZEOF__BOOL == SIZEOF_INT +- case '?': fd->pffi_type = &ffi_type_uint; break; +- #elif SIZEOF__BOOL == SIZEOF_LONG +- case '?': fd->pffi_type = &ffi_type_ulong; break; +- #elif SIZEOF__BOOL == SIZEOF_LONG_LONG +- case '?': fd->pffi_type = &ffi_type_ulong; break; +- #endif /* SIZEOF__BOOL */ +- case 'O': fd->pffi_type = &ffi_type_pointer; break; +- default: +- Py_UNREACHABLE(); +- } ++ TABLE_ENTRY(g, &ffi_type_longdouble); ++ TABLE_ENTRY_SW(f, &ffi_type_float); ++ TABLE_ENTRY(v, &ffi_type_sshort); /* vBOOL */ ++ ++ // ctypes.c_char is signed for FFI, even where C wchar_t is unsigned. ++ TABLE_ENTRY(c, _ctypes_fixint_fielddesc(sizeof(char), true)->pffi_type); ++ // ctypes.c_wchar is signed for FFI, even where C wchar_t is unsigned. ++ TABLE_ENTRY(u, _ctypes_fixint_fielddesc(sizeof(wchar_t), true)->pffi_type); ++ ++ TABLE_ENTRY(s, &ffi_type_pointer); ++ TABLE_ENTRY(P, &ffi_type_pointer); ++ TABLE_ENTRY(z, &ffi_type_pointer); ++ TABLE_ENTRY(U, &ffi_type_pointer); ++ TABLE_ENTRY(Z, &ffi_type_pointer); ++#ifdef MS_WIN32 ++ TABLE_ENTRY(X, &ffi_type_pointer); ++#endif ++ TABLE_ENTRY(O, &ffi_type_pointer); ++ ++#undef TABLE_ENTRY_SW ++#undef TABLE_ENTRY ++#undef _TABLE_ENTRY ++ ++ /* bool has code '?', fill it in manually */ ++ ++ // 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.setfunc = bool_set; ++ formattable.fmt_bool.getfunc = bool_get; ++ ++/*[python input] ++all_chars = "cbBhHiIlLdCEFfuzZqQPXOv?g" ++print(f' assert(sizeof(formattable.simple_type_chars) == {len(all_chars)+1});') ++print(f' int i = 0;') ++for char in all_chars: ++ ident_char = {'?': 'bool'}.get(char, char) ++ print(f" if (formattable.fmt_{ident_char}.code) " ++ + 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); ++ 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'; ++ if (formattable.fmt_B.code) formattable.simple_type_chars[i++] = 'B'; ++ if (formattable.fmt_h.code) formattable.simple_type_chars[i++] = 'h'; ++ if (formattable.fmt_H.code) formattable.simple_type_chars[i++] = 'H'; ++ if (formattable.fmt_i.code) formattable.simple_type_chars[i++] = 'i'; ++ if (formattable.fmt_I.code) formattable.simple_type_chars[i++] = 'I'; ++ 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_C.code) formattable.simple_type_chars[i++] = 'C'; ++ if (formattable.fmt_E.code) formattable.simple_type_chars[i++] = 'E'; ++ if (formattable.fmt_F.code) formattable.simple_type_chars[i++] = 'F'; ++ 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'; ++ if (formattable.fmt_Z.code) formattable.simple_type_chars[i++] = 'Z'; ++ if (formattable.fmt_q.code) formattable.simple_type_chars[i++] = 'q'; ++ if (formattable.fmt_Q.code) formattable.simple_type_chars[i++] = 'Q'; ++ if (formattable.fmt_P.code) formattable.simple_type_chars[i++] = 'P'; ++ if (formattable.fmt_X.code) formattable.simple_type_chars[i++] = 'X'; ++ if (formattable.fmt_O.code) formattable.simple_type_chars[i++] = 'O'; ++ if (formattable.fmt_v.code) formattable.simple_type_chars[i++] = 'v'; ++ 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=e6e5098a02f4b606 input=72031a625eac00c1]*/ ++ ++} ++#undef FIXINT_FIELDDESC_FOR ++_Py_COMP_DIAG_POP ++ ++static void ++_ctypes_init_fielddesc(void) ++{ ++ static bool initialized = false; ++ static PyMutex mutex = {0}; ++ PyMutex_Lock(&mutex); ++ if (!initialized) { ++ _ctypes_init_fielddesc_locked(); ++ initialized = true; + } ++ PyMutex_Unlock(&mutex); ++} + ++char * ++_ctypes_get_simple_type_chars(void) { ++ _ctypes_init_fielddesc(); ++ return formattable.simple_type_chars; + } + + struct fielddesc * + _ctypes_get_fielddesc(const char *fmt) + { +- static int initialized = 0; +- struct fielddesc *table = formattable; +- +- if (!initialized) { +- initialized = 1; +- _ctypes_init_fielddesc(); ++ _ctypes_init_fielddesc(); ++ ++ struct fielddesc *result = NULL; ++ switch(fmt[0]) { ++/*[python input] ++for code in 'sbBcdCEFgfhHiIlLqQPzuUZXvO': ++ print(f" case '{code}': result = &formattable.fmt_{code}; break;") ++[python start generated code]*/ ++ case 's': result = &formattable.fmt_s; break; ++ case 'b': result = &formattable.fmt_b; break; ++ case 'B': result = &formattable.fmt_B; break; ++ case 'c': result = &formattable.fmt_c; break; ++ case 'd': result = &formattable.fmt_d; break; ++ case 'C': result = &formattable.fmt_C; break; ++ case 'E': result = &formattable.fmt_E; break; ++ case 'F': result = &formattable.fmt_F; break; ++ case 'g': result = &formattable.fmt_g; break; ++ case 'f': result = &formattable.fmt_f; break; ++ case 'h': result = &formattable.fmt_h; break; ++ case 'H': result = &formattable.fmt_H; break; ++ case 'i': result = &formattable.fmt_i; break; ++ case 'I': result = &formattable.fmt_I; break; ++ case 'l': result = &formattable.fmt_l; break; ++ case 'L': result = &formattable.fmt_L; break; ++ case 'q': result = &formattable.fmt_q; break; ++ case 'Q': result = &formattable.fmt_Q; break; ++ case 'P': result = &formattable.fmt_P; break; ++ 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=81a8223dda9f81f7 input=2f59666d3c024edf]*/ ++ case '?': result = &formattable.fmt_bool; break; + } +- +- for (; table->code; ++table) { +- if (table->code == fmt[0]) +- return table; ++ if (!result || !result->code) { ++ return NULL; + } +- return NULL; ++ assert(result->pffi_type); ++ assert(result->setfunc); ++ assert(result->getfunc); ++ return result; + } + ++/* ++ Ideas: Implement VARIANT in this table, using 'V' code. ++*/ ++ + /*---------------- EOF ----------------*/ +diff --git a/Modules/_ctypes/clinic/_ctypes.c.h b/Modules/_ctypes/clinic/_ctypes.c.h +index 1332ba04cdf..1f2e871137e 100644 +--- a/Modules/_ctypes/clinic/_ctypes.c.h ++++ b/Modules/_ctypes/clinic/_ctypes.c.h +@@ -6,6 +6,7 @@ + # include "pycore_runtime.h" // _Py_SINGLETON() + #endif + #include "pycore_abstract.h" // _PyNumber_Index() ++#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() + #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() + + PyDoc_STRVAR(_ctypes_CType_Type___sizeof____doc__, +@@ -330,7 +331,7 @@ + PyObject *type); + + static PyObject * +-PyCPointerType_set_type(PyTypeObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++PyCPointerType_set_type(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -355,7 +356,7 @@ + goto exit; + } + type = args[0]; +- return_value = PyCPointerType_set_type_impl(self, cls, type); ++ return_value = PyCPointerType_set_type_impl((PyTypeObject *)self, cls, type); + + exit: + return return_value; +@@ -601,6 +602,177 @@ + return PyCData_reduce_impl(myself, cls); + } + ++#if !defined(_ctypes_CFuncPtr_errcheck_DOCSTR) ++# define _ctypes_CFuncPtr_errcheck_DOCSTR NULL ++#endif ++#if defined(_CTYPES_CFUNCPTR_ERRCHECK_GETSETDEF) ++# undef _CTYPES_CFUNCPTR_ERRCHECK_GETSETDEF ++# define _CTYPES_CFUNCPTR_ERRCHECK_GETSETDEF {"errcheck", (getter)_ctypes_CFuncPtr_errcheck_get, (setter)_ctypes_CFuncPtr_errcheck_set, _ctypes_CFuncPtr_errcheck_DOCSTR}, ++#else ++# define _CTYPES_CFUNCPTR_ERRCHECK_GETSETDEF {"errcheck", NULL, (setter)_ctypes_CFuncPtr_errcheck_set, NULL}, ++#endif ++ ++static int ++_ctypes_CFuncPtr_errcheck_set_impl(PyCFuncPtrObject *self, PyObject *value); ++ ++static int ++_ctypes_CFuncPtr_errcheck_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) ++{ ++ int return_value; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _ctypes_CFuncPtr_errcheck_set_impl((PyCFuncPtrObject *)self, value); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++PyDoc_STRVAR(_ctypes_CFuncPtr_errcheck__doc__, ++"a function to check for errors"); ++#if defined(_ctypes_CFuncPtr_errcheck_DOCSTR) ++# undef _ctypes_CFuncPtr_errcheck_DOCSTR ++#endif ++#define _ctypes_CFuncPtr_errcheck_DOCSTR _ctypes_CFuncPtr_errcheck__doc__ ++ ++#if !defined(_ctypes_CFuncPtr_errcheck_DOCSTR) ++# define _ctypes_CFuncPtr_errcheck_DOCSTR NULL ++#endif ++#if defined(_CTYPES_CFUNCPTR_ERRCHECK_GETSETDEF) ++# undef _CTYPES_CFUNCPTR_ERRCHECK_GETSETDEF ++# define _CTYPES_CFUNCPTR_ERRCHECK_GETSETDEF {"errcheck", (getter)_ctypes_CFuncPtr_errcheck_get, (setter)_ctypes_CFuncPtr_errcheck_set, _ctypes_CFuncPtr_errcheck_DOCSTR}, ++#else ++# define _CTYPES_CFUNCPTR_ERRCHECK_GETSETDEF {"errcheck", (getter)_ctypes_CFuncPtr_errcheck_get, NULL, _ctypes_CFuncPtr_errcheck_DOCSTR}, ++#endif ++ ++static PyObject * ++_ctypes_CFuncPtr_errcheck_get_impl(PyCFuncPtrObject *self); ++ ++static PyObject * ++_ctypes_CFuncPtr_errcheck_get(PyObject *self, void *Py_UNUSED(context)) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _ctypes_CFuncPtr_errcheck_get_impl((PyCFuncPtrObject *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(_ctypes_CFuncPtr_restype_DOCSTR) ++# define _ctypes_CFuncPtr_restype_DOCSTR NULL ++#endif ++#if defined(_CTYPES_CFUNCPTR_RESTYPE_GETSETDEF) ++# undef _CTYPES_CFUNCPTR_RESTYPE_GETSETDEF ++# define _CTYPES_CFUNCPTR_RESTYPE_GETSETDEF {"restype", (getter)_ctypes_CFuncPtr_restype_get, (setter)_ctypes_CFuncPtr_restype_set, _ctypes_CFuncPtr_restype_DOCSTR}, ++#else ++# define _CTYPES_CFUNCPTR_RESTYPE_GETSETDEF {"restype", NULL, (setter)_ctypes_CFuncPtr_restype_set, NULL}, ++#endif ++ ++static int ++_ctypes_CFuncPtr_restype_set_impl(PyCFuncPtrObject *self, PyObject *value); ++ ++static int ++_ctypes_CFuncPtr_restype_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) ++{ ++ int return_value; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _ctypes_CFuncPtr_restype_set_impl((PyCFuncPtrObject *)self, value); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++PyDoc_STRVAR(_ctypes_CFuncPtr_restype__doc__, ++"specify the result type"); ++#if defined(_ctypes_CFuncPtr_restype_DOCSTR) ++# undef _ctypes_CFuncPtr_restype_DOCSTR ++#endif ++#define _ctypes_CFuncPtr_restype_DOCSTR _ctypes_CFuncPtr_restype__doc__ ++ ++#if !defined(_ctypes_CFuncPtr_restype_DOCSTR) ++# define _ctypes_CFuncPtr_restype_DOCSTR NULL ++#endif ++#if defined(_CTYPES_CFUNCPTR_RESTYPE_GETSETDEF) ++# undef _CTYPES_CFUNCPTR_RESTYPE_GETSETDEF ++# define _CTYPES_CFUNCPTR_RESTYPE_GETSETDEF {"restype", (getter)_ctypes_CFuncPtr_restype_get, (setter)_ctypes_CFuncPtr_restype_set, _ctypes_CFuncPtr_restype_DOCSTR}, ++#else ++# define _CTYPES_CFUNCPTR_RESTYPE_GETSETDEF {"restype", (getter)_ctypes_CFuncPtr_restype_get, NULL, _ctypes_CFuncPtr_restype_DOCSTR}, ++#endif ++ ++static PyObject * ++_ctypes_CFuncPtr_restype_get_impl(PyCFuncPtrObject *self); ++ ++static PyObject * ++_ctypes_CFuncPtr_restype_get(PyObject *self, void *Py_UNUSED(context)) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _ctypes_CFuncPtr_restype_get_impl((PyCFuncPtrObject *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(_ctypes_CFuncPtr_argtypes_DOCSTR) ++# define _ctypes_CFuncPtr_argtypes_DOCSTR NULL ++#endif ++#if defined(_CTYPES_CFUNCPTR_ARGTYPES_GETSETDEF) ++# undef _CTYPES_CFUNCPTR_ARGTYPES_GETSETDEF ++# define _CTYPES_CFUNCPTR_ARGTYPES_GETSETDEF {"argtypes", (getter)_ctypes_CFuncPtr_argtypes_get, (setter)_ctypes_CFuncPtr_argtypes_set, _ctypes_CFuncPtr_argtypes_DOCSTR}, ++#else ++# define _CTYPES_CFUNCPTR_ARGTYPES_GETSETDEF {"argtypes", NULL, (setter)_ctypes_CFuncPtr_argtypes_set, NULL}, ++#endif ++ ++static int ++_ctypes_CFuncPtr_argtypes_set_impl(PyCFuncPtrObject *self, PyObject *value); ++ ++static int ++_ctypes_CFuncPtr_argtypes_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) ++{ ++ int return_value; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _ctypes_CFuncPtr_argtypes_set_impl((PyCFuncPtrObject *)self, value); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++PyDoc_STRVAR(_ctypes_CFuncPtr_argtypes__doc__, ++"specify the argument types"); ++#if defined(_ctypes_CFuncPtr_argtypes_DOCSTR) ++# undef _ctypes_CFuncPtr_argtypes_DOCSTR ++#endif ++#define _ctypes_CFuncPtr_argtypes_DOCSTR _ctypes_CFuncPtr_argtypes__doc__ ++ ++#if !defined(_ctypes_CFuncPtr_argtypes_DOCSTR) ++# define _ctypes_CFuncPtr_argtypes_DOCSTR NULL ++#endif ++#if defined(_CTYPES_CFUNCPTR_ARGTYPES_GETSETDEF) ++# undef _CTYPES_CFUNCPTR_ARGTYPES_GETSETDEF ++# define _CTYPES_CFUNCPTR_ARGTYPES_GETSETDEF {"argtypes", (getter)_ctypes_CFuncPtr_argtypes_get, (setter)_ctypes_CFuncPtr_argtypes_set, _ctypes_CFuncPtr_argtypes_DOCSTR}, ++#else ++# define _CTYPES_CFUNCPTR_ARGTYPES_GETSETDEF {"argtypes", (getter)_ctypes_CFuncPtr_argtypes_get, NULL, _ctypes_CFuncPtr_argtypes_DOCSTR}, ++#endif ++ ++static PyObject * ++_ctypes_CFuncPtr_argtypes_get_impl(PyCFuncPtrObject *self); ++ ++static PyObject * ++_ctypes_CFuncPtr_argtypes_get(PyObject *self, void *Py_UNUSED(context)) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _ctypes_CFuncPtr_argtypes_get_impl((PyCFuncPtrObject *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ + PyDoc_STRVAR(Simple_from_outparm__doc__, + "__ctypes_from_outparam__($self, /)\n" + "--\n" +@@ -621,4 +793,4 @@ + } + return Simple_from_outparm_impl(self, cls); + } +-/*[clinic end generated code: output=52724c091e3a8b8d input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=a18d87239b6fb8ca input=a9049054013a1b77]*/ +diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h +index 7e0804054cd..07049d0968c 100644 +--- a/Modules/_ctypes/ctypes.h ++++ b/Modules/_ctypes/ctypes.h +@@ -5,8 +5,21 @@ + #include "pycore_moduleobject.h" // _PyModule_GetState() + #include "pycore_typeobject.h" // _PyType_GetModuleState() + ++// Do we support C99 complex types in ffi? ++// For Apple's libffi, this must be determined at runtime (see gh-128156). + #if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX) + # include "../_complex.h" // complex ++# if USING_APPLE_OS_LIBFFI && defined(__has_builtin) ++# if __has_builtin(__builtin_available) ++# define Py_FFI_COMPLEX_AVAILABLE __builtin_available(macOS 10.15, *) ++# else ++# define Py_FFI_COMPLEX_AVAILABLE 1 ++# endif ++# else ++# define Py_FFI_COMPLEX_AVAILABLE 1 ++# endif ++#else ++# define Py_FFI_COMPLEX_AVAILABLE 0 + #endif + + #ifndef MS_WIN32 +@@ -112,9 +125,21 @@ + extern PyType_Spec cthunk_spec; + + typedef struct tagPyCArgObject PyCArgObject; ++#define _PyCArgObject_CAST(op) ((PyCArgObject *)(op)) ++ + typedef struct tagCDataObject CDataObject; +-typedef PyObject *(* GETFUNC)(void *, Py_ssize_t size); +-typedef PyObject *(* SETFUNC)(void *, PyObject *value, Py_ssize_t size); ++#define _CDataObject_CAST(op) ((CDataObject *)(op)) ++ ++// GETFUNC: convert the C value at *ptr* to Python object, return the object ++// SETFUNC: write content of the PyObject *value* to the location at *ptr*; ++// return a new reference to either *value*, or None for simple types ++// (see _CTYPES_DEBUG_KEEP). ++// Note that the *size* arg can have different meanings depending on context: ++// for string-like arrays it's the size in bytes ++// for int-style fields it's either the type size, or bitfiled info ++// that can be unpacked using the LOW_BIT & NUM_BITS macros. ++typedef PyObject *(* GETFUNC)(void *ptr, Py_ssize_t size); ++typedef PyObject *(* SETFUNC)(void *ptr, PyObject *value, Py_ssize_t size); + typedef PyCArgObject *(* PARAMFUNC)(ctypes_state *st, CDataObject *obj); + + /* A default buffer in CDataObject, which can be used for small C types. If +@@ -167,6 +192,8 @@ + ffi_type *ffi_restype; + ffi_type *atypes[1]; + } CThunkObject; ++ ++#define _CThunkObject_CAST(op) ((CThunkObject *)(op)) + #define CThunk_CheckExact(st, v) Py_IS_TYPE(v, st->PyCThunk_Type) + + typedef struct { +@@ -200,6 +227,8 @@ + PyObject *paramflags; + } PyCFuncPtrObject; + ++#define _PyCFuncPtrObject_CAST(op) ((PyCFuncPtrObject *)(op)) ++ + extern int PyCStructUnionType_update_stginfo(PyObject *fields, PyObject *type, int isStruct); + extern int PyType_stginfo(PyTypeObject *self, Py_ssize_t *psize, Py_ssize_t *palign, Py_ssize_t *plength); + extern int PyObject_stginfo(PyObject *self, Py_ssize_t *psize, Py_ssize_t *palign, Py_ssize_t *plength); +@@ -239,13 +268,16 @@ + /* a table entry describing a predefined ctypes type */ + struct fielddesc { + char code; ++ ffi_type *pffi_type; /* always statically allocated */ + SETFUNC setfunc; + GETFUNC getfunc; +- ffi_type *pffi_type; /* always statically allocated */ + SETFUNC setfunc_swapped; + GETFUNC getfunc_swapped; + }; + ++// Get all single-character type codes (for use in error messages) ++extern char *_ctypes_get_simple_type_chars(void); ++ + typedef struct CFieldObject { + PyObject_HEAD + Py_ssize_t offset; +@@ -260,6 +292,8 @@ + PyObject *name; /* exact PyUnicode */ + } CFieldObject; + ++#define _CFieldObject_CAST(op) ((CFieldObject *)(op)) ++ + /**************************************************************** + StgInfo + +@@ -396,6 +430,8 @@ + Py_ssize_t size; /* for the 'V' tag */ + }; + ++#define _PyCArgObject_CAST(op) ((PyCArgObject *)(op)) ++ + #define PyCArg_CheckExact(st, v) Py_IS_TYPE(v, st->PyCArg_Type) + extern PyCArgObject *PyCArgObject_new(ctypes_state *st); + +@@ -534,3 +570,51 @@ + info->initialized = 1; + return info; + } ++ ++/* See discussion in gh-128490. The plan here is to eventually use a per-object ++ * lock rather than a critical section, but that work is for later. */ ++#ifdef Py_GIL_DISABLED ++# define LOCK_PTR(self) Py_BEGIN_CRITICAL_SECTION(self) ++# define UNLOCK_PTR(self) Py_END_CRITICAL_SECTION() ++#else ++/* ++ * Dummy functions instead of macros so that 'self' can be ++ * unused in the caller without triggering a compiler warning. ++ */ ++static inline void LOCK_PTR(CDataObject *Py_UNUSED(self)) {} ++static inline void UNLOCK_PTR(CDataObject *Py_UNUSED(self)) {} ++#endif ++ ++static inline void ++locked_memcpy_to(CDataObject *self, void *buf, Py_ssize_t size) ++{ ++ LOCK_PTR(self); ++ (void)memcpy(self->b_ptr, buf, size); ++ UNLOCK_PTR(self); ++} ++ ++static inline void ++locked_memcpy_from(void *buf, CDataObject *self, Py_ssize_t size) ++{ ++ LOCK_PTR(self); ++ (void)memcpy(buf, self->b_ptr, size); ++ UNLOCK_PTR(self); ++} ++ ++static inline void * ++locked_deref(CDataObject *self) ++{ ++ void *ptr; ++ LOCK_PTR(self); ++ ptr = *(void **)self->b_ptr; ++ UNLOCK_PTR(self); ++ return ptr; ++} ++ ++static inline void ++locked_deref_assign(CDataObject *self, void *new_ptr) ++{ ++ LOCK_PTR(self); ++ *(void **)self->b_ptr = new_ptr; ++ UNLOCK_PTR(self); ++} +diff --git a/Modules/_ctypes/stgdict.c b/Modules/_ctypes/stgdict.c +index 5ca5b624276..05239d85c44 100644 +--- a/Modules/_ctypes/stgdict.c ++++ b/Modules/_ctypes/stgdict.c +@@ -257,8 +257,8 @@ + goto error; + } + +- PyObject *layout_func = _PyImport_GetModuleAttrString("ctypes._layout", +- "get_layout"); ++ PyObject *layout_func = PyImport_ImportModuleAttrString("ctypes._layout", ++ "get_layout"); + if (!layout_func) { + goto error; + } +diff --git a/Modules/_curses_panel.c b/Modules/_curses_panel.c +index bbbb62c9066..eecf7a1c8a1 100644 +--- a/Modules/_curses_panel.c ++++ b/Modules/_curses_panel.c +@@ -62,7 +62,7 @@ + static void + _curses_panel_free(void *mod) + { +- _curses_panel_clear((PyObject *) mod); ++ (void)_curses_panel_clear((PyObject *)mod); + } + + /* Utility Functions */ +@@ -101,6 +101,8 @@ + PyCursesWindowObject *wo; /* for reference counts */ + } PyCursesPanelObject; + ++#define _PyCursesPanelObject_CAST(op) ((PyCursesPanelObject *)(op)) ++ + /* Some helper functions. The problem is that there's always a window + associated with a panel. To ensure that Python's GC doesn't pull + this window from under our feet we need to keep track of references +@@ -277,9 +279,10 @@ + } + + static void +-PyCursesPanel_Dealloc(PyCursesPanelObject *po) ++PyCursesPanel_Dealloc(PyObject *self) + { + PyObject *tp, *obj; ++ PyCursesPanelObject *po = _PyCursesPanelObject_CAST(self); + + tp = (PyObject *) Py_TYPE(po); + obj = (PyObject *) panel_userptr(po->pan); +diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c +index 040ffa81153..7213a5be07d 100644 +--- a/Modules/_cursesmodule.c ++++ b/Modules/_cursesmodule.c +@@ -138,7 +138,7 @@ + #define STRICT_SYSV_CURSES + #endif + +-#if NCURSES_EXT_FUNCS+0 >= 20170401 && NCURSES_EXT_COLORS+0 >= 20170401 ++#if defined(HAVE_NCURSESW) && NCURSES_EXT_FUNCS+0 >= 20170401 && NCURSES_EXT_COLORS+0 >= 20170401 + #define _NCURSES_EXTENDED_COLOR_FUNCS 1 + #else + #define _NCURSES_EXTENDED_COLOR_FUNCS 0 +@@ -187,6 +187,8 @@ + return get_cursesmodule_state_by_cls(Py_TYPE(win)); + } + ++#define _PyCursesWindowObject_CAST(op) ((PyCursesWindowObject *)(op)) ++ + /*[clinic input] + module _curses + class _curses.window "PyCursesWindowObject *" "clinic_state()->window_type" +@@ -224,7 +226,7 @@ + if (called == TRUE) { + return 1; + } +- PyObject *exc = _PyImport_GetModuleAttrString("_curses", "error"); ++ PyObject *exc = PyImport_ImportModuleAttrString("_curses", "error"); + if (exc != NULL) { + PyErr_Format(exc, "must call %s() first", funcname); + Py_DECREF(exc); +@@ -654,53 +656,80 @@ + PARSESTR - format string for argument parsing + */ + +-#define Window_NoArgNoReturnFunction(X) \ +- static PyObject *PyCursesWindow_ ## X \ +- (PyCursesWindowObject *self, PyObject *Py_UNUSED(ignored)) \ +- { return PyCursesCheckERR_ForWin(self, X(self->win), # X); } ++#define Window_NoArgNoReturnFunction(X) \ ++ static PyObject *PyCursesWindow_ ## X \ ++ (PyObject *op, PyObject *Py_UNUSED(ignored)) \ ++ { \ ++ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); \ ++ int code = X(self->win); \ ++ return PyCursesCheckERR_ForWin(self, code, # X); \ ++ } + + #define Window_NoArgTrueFalseFunction(X) \ + static PyObject * PyCursesWindow_ ## X \ +- (PyCursesWindowObject *self, PyObject *Py_UNUSED(ignored)) \ ++ (PyObject *op, PyObject *Py_UNUSED(ignored)) \ + { \ +- return PyBool_FromLong(X(self->win)); } ++ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); \ ++ return PyBool_FromLong(X(self->win)); \ ++ } + +-#define Window_NoArgNoReturnVoidFunction(X) \ +- static PyObject * PyCursesWindow_ ## X \ +- (PyCursesWindowObject *self, PyObject *Py_UNUSED(ignored)) \ +- { \ +- X(self->win); Py_RETURN_NONE; } ++#define Window_NoArgNoReturnVoidFunction(X) \ ++ static PyObject * PyCursesWindow_ ## X \ ++ (PyObject *op, PyObject *Py_UNUSED(ignored)) \ ++ { \ ++ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); \ ++ X(self->win); \ ++ Py_RETURN_NONE; \ ++ } + + #define Window_NoArg2TupleReturnFunction(X, TYPE, ERGSTR) \ + static PyObject * PyCursesWindow_ ## X \ +- (PyCursesWindowObject *self, PyObject *Py_UNUSED(ignored)) \ ++ (PyObject *op, PyObject *Py_UNUSED(ignored)) \ + { \ + TYPE arg1, arg2; \ +- X(self->win,arg1,arg2); return Py_BuildValue(ERGSTR, arg1, arg2); } ++ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); \ ++ X(self->win, arg1, arg2); \ ++ return Py_BuildValue(ERGSTR, arg1, arg2); \ ++ } + + #define Window_OneArgNoReturnVoidFunction(X, TYPE, PARSESTR) \ + static PyObject * PyCursesWindow_ ## X \ +- (PyCursesWindowObject *self, PyObject *args) \ ++ (PyObject *op, PyObject *args) \ + { \ + TYPE arg1; \ +- if (!PyArg_ParseTuple(args, PARSESTR, &arg1)) return NULL; \ +- X(self->win,arg1); Py_RETURN_NONE; } ++ if (!PyArg_ParseTuple(args, PARSESTR, &arg1)) { \ ++ return NULL; \ ++ } \ ++ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); \ ++ X(self->win, arg1); \ ++ Py_RETURN_NONE; \ ++ } + + #define Window_OneArgNoReturnFunction(X, TYPE, PARSESTR) \ + static PyObject * PyCursesWindow_ ## X \ +- (PyCursesWindowObject *self, PyObject *args) \ ++ (PyObject *op, PyObject *args) \ + { \ + TYPE arg1; \ +- if (!PyArg_ParseTuple(args,PARSESTR, &arg1)) return NULL; \ +- return PyCursesCheckERR_ForWin(self, X(self->win, arg1), # X); } ++ if (!PyArg_ParseTuple(args, PARSESTR, &arg1)) { \ ++ return NULL; \ ++ } \ ++ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); \ ++ int code = X(self->win, arg1); \ ++ return PyCursesCheckERR_ForWin(self, code, # X); \ ++ } + + #define Window_TwoArgNoReturnFunction(X, TYPE, PARSESTR) \ + static PyObject * PyCursesWindow_ ## X \ +- (PyCursesWindowObject *self, PyObject *args) \ ++ (PyObject *op, PyObject *args) \ + { \ + TYPE arg1, arg2; \ +- if (!PyArg_ParseTuple(args,PARSESTR, &arg1, &arg2)) return NULL; \ +- return PyCursesCheckERR_ForWin(self, X(self->win, arg1, arg2), # X); } ++ if (!PyArg_ParseTuple(args,PARSESTR, &arg1, &arg2)) { \ ++ return NULL; \ ++ } \ ++ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); \ ++ int code = X(self->win, arg1, arg2); \ ++ return PyCursesCheckERR_ForWin(self, code, # X); \ ++ } + + /* ------------- WINDOW routines --------------- */ + +@@ -1302,8 +1331,10 @@ + window refresh. + [-clinic start generated code]*/ + static PyObject * +-PyCursesWindow_ChgAt(PyCursesWindowObject *self, PyObject *args) ++PyCursesWindow_ChgAt(PyObject *op, PyObject *args) + { ++ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); ++ + int rtn; + int x, y; + int num = -1; +@@ -1656,8 +1687,10 @@ + [-clinic start generated code]*/ + + static PyObject * +-PyCursesWindow_GetStr(PyCursesWindowObject *self, PyObject *args) ++PyCursesWindow_GetStr(PyObject *op, PyObject *args) + { ++ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); ++ + int x, y, n; + char rtn[1024]; /* This should be big enough.. I hope */ + int rtn2; +@@ -1860,8 +1893,10 @@ + n characters long (exclusive of the trailing NUL). + [-clinic start generated code]*/ + static PyObject * +-PyCursesWindow_InStr(PyCursesWindowObject *self, PyObject *args) ++PyCursesWindow_InStr(PyObject *op, PyObject *args) + { ++ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); ++ + int x, y, n; + char rtn[1024]; /* This should be big enough.. I hope */ + int rtn2; +@@ -2557,14 +2592,17 @@ + } + + static PyObject * +-PyCursesWindow_get_encoding(PyCursesWindowObject *self, void *closure) ++PyCursesWindow_get_encoding(PyObject *op, void *closure) + { ++ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); + return PyUnicode_FromString(self->encoding); + } + + static int +-PyCursesWindow_set_encoding(PyCursesWindowObject *self, PyObject *value, void *Py_UNUSED(ignored)) ++PyCursesWindow_set_encoding(PyObject *op, PyObject *value, void *Py_UNUSED(ignored)) + { ++ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); ++ + PyObject *ascii; + char *encoding; + +@@ -2607,88 +2645,90 @@ + _CURSES_WINDOW_ATTRSET_METHODDEF + _CURSES_WINDOW_BKGD_METHODDEF + #ifdef HAVE_CURSES_WCHGAT +- {"chgat", (PyCFunction)PyCursesWindow_ChgAt, METH_VARARGS}, ++ {"chgat", PyCursesWindow_ChgAt, METH_VARARGS}, + #endif + _CURSES_WINDOW_BKGDSET_METHODDEF + _CURSES_WINDOW_BORDER_METHODDEF + _CURSES_WINDOW_BOX_METHODDEF +- {"clear", (PyCFunction)PyCursesWindow_wclear, METH_NOARGS}, +- {"clearok", (PyCFunction)PyCursesWindow_clearok, METH_VARARGS}, +- {"clrtobot", (PyCFunction)PyCursesWindow_wclrtobot, METH_NOARGS}, +- {"clrtoeol", (PyCFunction)PyCursesWindow_wclrtoeol, METH_NOARGS}, +- {"cursyncup", (PyCFunction)PyCursesWindow_wcursyncup, METH_NOARGS}, ++ {"clear", PyCursesWindow_wclear, METH_NOARGS}, ++ {"clearok", PyCursesWindow_clearok, METH_VARARGS}, ++ {"clrtobot", PyCursesWindow_wclrtobot, METH_NOARGS}, ++ {"clrtoeol", PyCursesWindow_wclrtoeol, METH_NOARGS}, ++ {"cursyncup", PyCursesWindow_wcursyncup, METH_NOARGS}, + _CURSES_WINDOW_DELCH_METHODDEF +- {"deleteln", (PyCFunction)PyCursesWindow_wdeleteln, METH_NOARGS}, ++ {"deleteln", PyCursesWindow_wdeleteln, METH_NOARGS}, + _CURSES_WINDOW_DERWIN_METHODDEF + _CURSES_WINDOW_ECHOCHAR_METHODDEF + _CURSES_WINDOW_ENCLOSE_METHODDEF +- {"erase", (PyCFunction)PyCursesWindow_werase, METH_NOARGS}, +- {"getbegyx", (PyCFunction)PyCursesWindow_getbegyx, METH_NOARGS}, ++ {"erase", PyCursesWindow_werase, METH_NOARGS}, ++ {"getbegyx", PyCursesWindow_getbegyx, METH_NOARGS}, + _CURSES_WINDOW_GETBKGD_METHODDEF + _CURSES_WINDOW_GETCH_METHODDEF + _CURSES_WINDOW_GETKEY_METHODDEF + _CURSES_WINDOW_GET_WCH_METHODDEF +- {"getmaxyx", (PyCFunction)PyCursesWindow_getmaxyx, METH_NOARGS}, +- {"getparyx", (PyCFunction)PyCursesWindow_getparyx, METH_NOARGS}, +- {"getstr", (PyCFunction)PyCursesWindow_GetStr, METH_VARARGS}, +- {"getyx", (PyCFunction)PyCursesWindow_getyx, METH_NOARGS}, ++ {"getmaxyx", PyCursesWindow_getmaxyx, METH_NOARGS}, ++ {"getparyx", PyCursesWindow_getparyx, METH_NOARGS}, ++ {"getstr", PyCursesWindow_GetStr, METH_VARARGS}, ++ {"getyx", PyCursesWindow_getyx, METH_NOARGS}, + _CURSES_WINDOW_HLINE_METHODDEF +- {"idcok", (PyCFunction)PyCursesWindow_idcok, METH_VARARGS}, +- {"idlok", (PyCFunction)PyCursesWindow_idlok, METH_VARARGS}, ++ {"idcok", PyCursesWindow_idcok, METH_VARARGS}, ++ {"idlok", PyCursesWindow_idlok, METH_VARARGS}, + #ifdef HAVE_CURSES_IMMEDOK +- {"immedok", (PyCFunction)PyCursesWindow_immedok, METH_VARARGS}, ++ {"immedok", PyCursesWindow_immedok, METH_VARARGS}, + #endif + _CURSES_WINDOW_INCH_METHODDEF + _CURSES_WINDOW_INSCH_METHODDEF +- {"insdelln", (PyCFunction)PyCursesWindow_winsdelln, METH_VARARGS}, +- {"insertln", (PyCFunction)PyCursesWindow_winsertln, METH_NOARGS}, ++ {"insdelln", PyCursesWindow_winsdelln, METH_VARARGS}, ++ {"insertln", PyCursesWindow_winsertln, METH_NOARGS}, + _CURSES_WINDOW_INSNSTR_METHODDEF + _CURSES_WINDOW_INSSTR_METHODDEF +- {"instr", (PyCFunction)PyCursesWindow_InStr, METH_VARARGS}, ++ {"instr", PyCursesWindow_InStr, METH_VARARGS}, + _CURSES_WINDOW_IS_LINETOUCHED_METHODDEF +- {"is_wintouched", (PyCFunction)PyCursesWindow_is_wintouched, METH_NOARGS}, +- {"keypad", (PyCFunction)PyCursesWindow_keypad, METH_VARARGS}, +- {"leaveok", (PyCFunction)PyCursesWindow_leaveok, METH_VARARGS}, +- {"move", (PyCFunction)PyCursesWindow_wmove, METH_VARARGS}, +- {"mvderwin", (PyCFunction)PyCursesWindow_mvderwin, METH_VARARGS}, +- {"mvwin", (PyCFunction)PyCursesWindow_mvwin, METH_VARARGS}, +- {"nodelay", (PyCFunction)PyCursesWindow_nodelay, METH_VARARGS}, +- {"notimeout", (PyCFunction)PyCursesWindow_notimeout, METH_VARARGS}, ++ {"is_wintouched", PyCursesWindow_is_wintouched, METH_NOARGS}, ++ {"keypad", PyCursesWindow_keypad, METH_VARARGS}, ++ {"leaveok", PyCursesWindow_leaveok, METH_VARARGS}, ++ {"move", PyCursesWindow_wmove, METH_VARARGS}, ++ {"mvderwin", PyCursesWindow_mvderwin, METH_VARARGS}, ++ {"mvwin", PyCursesWindow_mvwin, METH_VARARGS}, ++ {"nodelay", PyCursesWindow_nodelay, METH_VARARGS}, ++ {"notimeout", PyCursesWindow_notimeout, METH_VARARGS}, + _CURSES_WINDOW_NOUTREFRESH_METHODDEF + _CURSES_WINDOW_OVERLAY_METHODDEF + _CURSES_WINDOW_OVERWRITE_METHODDEF + _CURSES_WINDOW_PUTWIN_METHODDEF + _CURSES_WINDOW_REDRAWLN_METHODDEF +- {"redrawwin", (PyCFunction)PyCursesWindow_redrawwin, METH_NOARGS}, ++ {"redrawwin", PyCursesWindow_redrawwin, METH_NOARGS}, + _CURSES_WINDOW_REFRESH_METHODDEF + #ifndef STRICT_SYSV_CURSES +- {"resize", (PyCFunction)PyCursesWindow_wresize, METH_VARARGS}, ++ {"resize", PyCursesWindow_wresize, METH_VARARGS}, + #endif + _CURSES_WINDOW_SCROLL_METHODDEF +- {"scrollok", (PyCFunction)PyCursesWindow_scrollok, METH_VARARGS}, ++ {"scrollok", PyCursesWindow_scrollok, METH_VARARGS}, + _CURSES_WINDOW_SETSCRREG_METHODDEF +- {"standend", (PyCFunction)PyCursesWindow_wstandend, METH_NOARGS}, +- {"standout", (PyCFunction)PyCursesWindow_wstandout, METH_NOARGS}, ++ {"standend", PyCursesWindow_wstandend, METH_NOARGS}, ++ {"standout", PyCursesWindow_wstandout, METH_NOARGS}, + {"subpad", (PyCFunction)_curses_window_subwin, METH_VARARGS, _curses_window_subwin__doc__}, + _CURSES_WINDOW_SUBWIN_METHODDEF +- {"syncdown", (PyCFunction)PyCursesWindow_wsyncdown, METH_NOARGS}, ++ {"syncdown", PyCursesWindow_wsyncdown, METH_NOARGS}, + #ifdef HAVE_CURSES_SYNCOK +- {"syncok", (PyCFunction)PyCursesWindow_syncok, METH_VARARGS}, ++ {"syncok", PyCursesWindow_syncok, METH_VARARGS}, + #endif +- {"syncup", (PyCFunction)PyCursesWindow_wsyncup, METH_NOARGS}, +- {"timeout", (PyCFunction)PyCursesWindow_wtimeout, METH_VARARGS}, ++ {"syncup", PyCursesWindow_wsyncup, METH_NOARGS}, ++ {"timeout", PyCursesWindow_wtimeout, METH_VARARGS}, + _CURSES_WINDOW_TOUCHLINE_METHODDEF +- {"touchwin", (PyCFunction)PyCursesWindow_touchwin, METH_NOARGS}, +- {"untouchwin", (PyCFunction)PyCursesWindow_untouchwin, METH_NOARGS}, ++ {"touchwin", PyCursesWindow_touchwin, METH_NOARGS}, ++ {"untouchwin", PyCursesWindow_untouchwin, METH_NOARGS}, + _CURSES_WINDOW_VLINE_METHODDEF + {NULL, NULL} /* sentinel */ + }; + + static PyGetSetDef PyCursesWindow_getsets[] = { +- {"encoding", +- (getter)PyCursesWindow_get_encoding, +- (setter)PyCursesWindow_set_encoding, +- "the typecode character used to create the array"}, ++ { ++ "encoding", ++ PyCursesWindow_get_encoding, ++ PyCursesWindow_set_encoding, ++ "the typecode character used to create the array" ++ }, + {NULL, NULL, NULL, NULL } /* sentinel */ + }; + +diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c +index b1102984cb5..bcbf4217d41 100644 +--- a/Modules/_datetimemodule.c ++++ b/Modules/_datetimemodule.c +@@ -226,7 +226,7 @@ + goto finally; + + error: +- PyErr_WriteUnraisable(NULL); ++ PyErr_FormatUnraisable("Exception ignored while clearing _datetime module"); + + finally: + PyErr_SetRaisedException(exc); +@@ -1839,7 +1839,7 @@ + assert(object && format && timetuple); + assert(PyUnicode_Check(format)); + +- PyObject *strftime = _PyImport_GetModuleAttrString("time", "strftime"); ++ PyObject *strftime = PyImport_ImportModuleAttrString("time", "strftime"); + if (strftime == NULL) { + return NULL; + } +@@ -1849,9 +1849,10 @@ + * is expensive, don't unless they're actually used. + */ + +- _PyUnicodeWriter writer; +- _PyUnicodeWriter_Init(&writer); +- writer.overallocate = 1; ++ PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); ++ if (writer == NULL) { ++ goto Error; ++ } + + Py_ssize_t flen = PyUnicode_GET_LENGTH(format); + Py_ssize_t i = 0; +@@ -1912,9 +1913,7 @@ + } + #ifdef Py_NORMALIZE_CENTURY + else if (ch == 'Y' || ch == 'G' +-#ifdef Py_STRFTIME_C99_SUPPORT + || ch == 'F' || ch == 'C' +-#endif + ) { + /* 0-pad year with century as necessary */ + PyObject *item = PySequence_GetItem(timetuple, 0); +@@ -1952,20 +1951,16 @@ + * +6 to accommodate dashes, 2-digit month and day for %F. */ + char buf[SIZEOF_LONG * 5 / 2 + 2 + 6]; + Py_ssize_t n = PyOS_snprintf(buf, sizeof(buf), +-#ifdef Py_STRFTIME_C99_SUPPORT + ch == 'F' ? "%04ld-%%m-%%d" : +-#endif + "%04ld", year_long); +-#ifdef Py_STRFTIME_C99_SUPPORT + if (ch == 'C') { + n -= 2; + } +-#endif +- if (_PyUnicodeWriter_WriteSubstring(&writer, format, start, end) < 0) { ++ if (PyUnicodeWriter_WriteSubstring(writer, format, start, end) < 0) { + goto Error; + } + start = i; +- if (_PyUnicodeWriter_WriteASCIIString(&writer, buf, n) < 0) { ++ if (PyUnicodeWriter_WriteUTF8(writer, buf, n) < 0) { + goto Error; + } + continue; +@@ -1977,25 +1972,25 @@ + } + assert(replacement != NULL); + assert(PyUnicode_Check(replacement)); +- if (_PyUnicodeWriter_WriteSubstring(&writer, format, start, end) < 0) { ++ if (PyUnicodeWriter_WriteSubstring(writer, format, start, end) < 0) { + goto Error; + } + start = i; +- if (_PyUnicodeWriter_WriteStr(&writer, replacement) < 0) { ++ if (PyUnicodeWriter_WriteStr(writer, replacement) < 0) { + goto Error; + } + } /* end while() */ + + PyObject *newformat; + if (start == 0) { +- _PyUnicodeWriter_Dealloc(&writer); ++ PyUnicodeWriter_Discard(writer); + newformat = Py_NewRef(format); + } + else { +- if (_PyUnicodeWriter_WriteSubstring(&writer, format, start, flen) < 0) { ++ if (PyUnicodeWriter_WriteSubstring(writer, format, start, flen) < 0) { + goto Error; + } +- newformat = _PyUnicodeWriter_Finish(&writer); ++ newformat = PyUnicodeWriter_Finish(writer); + if (newformat == NULL) { + goto Done; + } +@@ -2013,7 +2008,7 @@ + return result; + + Error: +- _PyUnicodeWriter_Dealloc(&writer); ++ PyUnicodeWriter_Discard(writer); + goto Done; + } + +@@ -2027,7 +2022,7 @@ + time_time(void) + { + PyObject *result = NULL; +- PyObject *time = _PyImport_GetModuleAttrString("time", "time"); ++ PyObject *time = PyImport_ImportModuleAttrString("time", "time"); + + if (time != NULL) { + result = PyObject_CallNoArgs(time); +@@ -2045,7 +2040,7 @@ + PyObject *struct_time; + PyObject *result; + +- struct_time = _PyImport_GetModuleAttrString("time", "struct_time"); ++ struct_time = PyImport_ImportModuleAttrString("time", "struct_time"); + if (struct_time == NULL) { + return NULL; + } +@@ -4953,7 +4948,7 @@ + minute: int(c_default="TIME_GET_MINUTE(self)") = unchanged + second: int(c_default="TIME_GET_SECOND(self)") = unchanged + microsecond: int(c_default="TIME_GET_MICROSECOND(self)") = unchanged +- tzinfo: object(c_default="HASTZINFO(self) ? self->tzinfo : Py_None") = unchanged ++ tzinfo: object(c_default="HASTZINFO(self) ? ((PyDateTime_Time *)self)->tzinfo : Py_None") = unchanged + * + fold: int(c_default="TIME_GET_FOLD(self)") = unchanged + +@@ -4964,7 +4959,7 @@ + datetime_time_replace_impl(PyDateTime_Time *self, int hour, int minute, + int second, int microsecond, PyObject *tzinfo, + int fold) +-/*[clinic end generated code: output=0b89a44c299e4f80 input=9b6a35b1e704b0ca]*/ ++/*[clinic end generated code: output=0b89a44c299e4f80 input=abf23656e8df4e97]*/ + { + return new_time_subclass_fold_ex(hour, minute, second, microsecond, tzinfo, + fold, (PyObject *)Py_TYPE(self)); +@@ -6455,7 +6450,7 @@ + minute: int(c_default="DATE_GET_MINUTE(self)") = unchanged + second: int(c_default="DATE_GET_SECOND(self)") = unchanged + microsecond: int(c_default="DATE_GET_MICROSECOND(self)") = unchanged +- tzinfo: object(c_default="HASTZINFO(self) ? self->tzinfo : Py_None") = unchanged ++ tzinfo: object(c_default="HASTZINFO(self) ? ((PyDateTime_DateTime *)self)->tzinfo : Py_None") = unchanged + * + fold: int(c_default="DATE_GET_FOLD(self)") = unchanged + +@@ -6467,7 +6462,7 @@ + int month, int day, int hour, int minute, + int second, int microsecond, PyObject *tzinfo, + int fold) +-/*[clinic end generated code: output=00bc96536833fddb input=9b38253d56d9bcad]*/ ++/*[clinic end generated code: output=00bc96536833fddb input=fd972762d604d3e7]*/ + { + return new_datetime_subclass_fold_ex(year, month, day, hour, minute, + second, microsecond, tzinfo, fold, +diff --git a/Modules/_dbmmodule.c b/Modules/_dbmmodule.c +index 1be4234aad3..cc65cbd98d7 100644 +--- a/Modules/_dbmmodule.c ++++ b/Modules/_dbmmodule.c +@@ -64,6 +64,8 @@ + DBM *di_dbm; + } dbmobject; + ++#define dbmobject_CAST(op) ((dbmobject *)(op)) ++ + #include "clinic/_dbmmodule.c.h" + + #define check_dbmobject_open(v, err) \ +@@ -94,15 +96,16 @@ + + /* Methods */ + static int +-dbm_traverse(dbmobject *dp, visitproc visit, void *arg) ++dbm_traverse(PyObject *dp, visitproc visit, void *arg) + { + Py_VISIT(Py_TYPE(dp)); + return 0; + } + + static void +-dbm_dealloc(dbmobject *dp) ++dbm_dealloc(PyObject *self) + { ++ dbmobject *dp = dbmobject_CAST(self); + PyObject_GC_UnTrack(dp); + if (dp->di_dbm) { + dbm_close(dp->di_dbm); +@@ -113,8 +116,9 @@ + } + + static Py_ssize_t +-dbm_length(dbmobject *dp) ++dbm_length(PyObject *self) + { ++ dbmobject *dp = dbmobject_CAST(self); + _dbm_state *state = PyType_GetModuleState(Py_TYPE(dp)); + assert(state != NULL); + if (dp->di_dbm == NULL) { +@@ -135,8 +139,9 @@ + } + + static int +-dbm_bool(dbmobject *dp) ++dbm_bool(PyObject *self) + { ++ dbmobject *dp = dbmobject_CAST(self); + _dbm_state *state = PyType_GetModuleState(Py_TYPE(dp)); + assert(state != NULL); + +@@ -166,10 +171,11 @@ + } + + static PyObject * +-dbm_subscript(dbmobject *dp, PyObject *key) ++dbm_subscript(PyObject *self, PyObject *key) + { + datum drec, krec; + Py_ssize_t tmp_size; ++ dbmobject *dp = dbmobject_CAST(self); + _dbm_state *state = PyType_GetModuleState(Py_TYPE(dp)); + assert(state != NULL); + if (!PyArg_Parse(key, "s#", &krec.dptr, &tmp_size)) { +@@ -192,10 +198,11 @@ + } + + static int +-dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w) ++dbm_ass_sub(PyObject *self, PyObject *v, PyObject *w) + { + datum krec, drec; + Py_ssize_t tmp_size; ++ dbmobject *dp = dbmobject_CAST(self); + + if ( !PyArg_Parse(v, "s#", &krec.dptr, &tmp_size) ) { + PyErr_SetString(PyExc_TypeError, +@@ -305,7 +312,7 @@ + static int + dbm_contains(PyObject *self, PyObject *arg) + { +- dbmobject *dp = (dbmobject *)self; ++ dbmobject *dp = dbmobject_CAST(self); + datum key, val; + Py_ssize_t size; + +@@ -452,15 +459,16 @@ + } + + static PyObject * +-dbm__enter__(PyObject *self, PyObject *args) ++dbm__enter__(PyObject *self, PyObject *Py_UNUSED(dummy)) + { + return Py_NewRef(self); + } + + static PyObject * +-dbm__exit__(PyObject *self, PyObject *args) ++dbm__exit__(PyObject *self, PyObject *Py_UNUSED(args)) + { +- return _dbm_dbm_close_impl((dbmobject *)self); ++ dbmobject *dp = dbmobject_CAST(self); ++ return _dbm_dbm_close_impl(dp); + } + + static PyMethodDef dbm_methods[] = { +@@ -610,7 +618,7 @@ + static void + _dbm_module_free(void *module) + { +- _dbm_module_clear((PyObject *)module); ++ (void)_dbm_module_clear((PyObject *)module); + } + + static PyModuleDef_Slot _dbmmodule_slots[] = { +diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c +index c564813036e..3dcb3e9870c 100644 +--- a/Modules/_decimal/_decimal.c ++++ b/Modules/_decimal/_decimal.c +@@ -30,7 +30,6 @@ + #endif + + #include +-#include "pycore_long.h" // _PyLong_IsZero() + #include "pycore_pystate.h" // _PyThreadState_GET() + #include "pycore_typeobject.h" + #include "complexobject.h" +@@ -179,11 +178,15 @@ + mpd_uint_t data[_Py_DEC_MINALLOC]; + } PyDecObject; + ++#define _PyDecObject_CAST(op) ((PyDecObject *)(op)) ++ + typedef struct { + PyObject_HEAD + uint32_t *flags; + } PyDecSignalDictObject; + ++#define _PyDecSignalDictObject_CAST(op) ((PyDecSignalDictObject *)(op)) ++ + typedef struct PyDecContextObject { + PyObject_HEAD + mpd_context_t ctx; +@@ -194,23 +197,27 @@ + decimal_state *modstate; + } PyDecContextObject; + ++#define _PyDecContextObject_CAST(op) ((PyDecContextObject *)(op)) ++ + typedef struct { + PyObject_HEAD + PyObject *local; + PyObject *global; + } PyDecContextManagerObject; + ++#define _PyDecContextManagerObject_CAST(op) ((PyDecContextManagerObject *)(op)) ++ + #undef MPD + #undef CTX + #define PyDec_CheckExact(st, v) Py_IS_TYPE(v, (st)->PyDec_Type) + #define PyDec_Check(st, v) PyObject_TypeCheck(v, (st)->PyDec_Type) + #define PyDecSignalDict_Check(st, v) Py_IS_TYPE(v, (st)->PyDecSignalDict_Type) + #define PyDecContext_Check(st, v) PyObject_TypeCheck(v, (st)->PyDecContext_Type) +-#define MPD(v) (&((PyDecObject *)v)->dec) +-#define SdFlagAddr(v) (((PyDecSignalDictObject *)v)->flags) +-#define SdFlags(v) (*((PyDecSignalDictObject *)v)->flags) +-#define CTX(v) (&((PyDecContextObject *)v)->ctx) +-#define CtxCaps(v) (((PyDecContextObject *)v)->capitals) ++#define MPD(v) (&_PyDecObject_CAST(v)->dec) ++#define SdFlagAddr(v) (_PyDecSignalDictObject_CAST(v)->flags) ++#define SdFlags(v) (*_PyDecSignalDictObject_CAST(v)->flags) ++#define CTX(v) (&_PyDecContextObject_CAST(v)->ctx) ++#define CtxCaps(v) (_PyDecContextObject_CAST(v)->capitals) + + static inline decimal_state * + get_module_state_from_ctx(PyObject *v) +@@ -1414,8 +1421,9 @@ + } + + static int +-context_traverse(PyDecContextObject *self, visitproc visit, void *arg) ++context_traverse(PyObject *op, visitproc visit, void *arg) + { ++ PyDecContextObject *self = _PyDecContextObject_CAST(op); + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->traps); + Py_VISIT(self->flags); +@@ -1423,15 +1431,16 @@ + } + + static int +-context_clear(PyDecContextObject *self) ++context_clear(PyObject *op) + { ++ PyDecContextObject *self = _PyDecContextObject_CAST(op); + Py_CLEAR(self->traps); + Py_CLEAR(self->flags); + return 0; + } + + static void +-context_dealloc(PyDecContextObject *self) ++context_dealloc(PyObject *self) + { + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); +@@ -1474,7 +1483,7 @@ + } + + static PyObject * +-context_repr(PyDecContextObject *self) ++context_repr(PyObject *self) + { + mpd_context_t *ctx; + char flags[MPD_MAX_SIGNAL_LIST]; +@@ -1482,7 +1491,7 @@ + int n, mem; + + #ifdef Py_DEBUG +- decimal_state *state = get_module_state_from_ctx((PyObject *)self); ++ decimal_state *state = get_module_state_from_ctx(self); + assert(PyDecContext_Check(state, self)); + #endif + ctx = CTX(self); +@@ -1502,7 +1511,7 @@ + "Context(prec=%zd, rounding=%s, Emin=%zd, Emax=%zd, " + "capitals=%d, clamp=%d, flags=%s, traps=%s)", + ctx->prec, mpd_round_string[ctx->round], ctx->emin, ctx->emax, +- self->capitals, ctx->clamp, flags, traps); ++ CtxCaps(self), ctx->clamp, flags, traps); + } + + static void +@@ -1622,16 +1631,16 @@ + + static PyGetSetDef context_getsets [] = + { +- { "prec", (getter)context_getprec, (setter)context_setprec, NULL, NULL}, +- { "Emax", (getter)context_getemax, (setter)context_setemax, NULL, NULL}, +- { "Emin", (getter)context_getemin, (setter)context_setemin, NULL, NULL}, +- { "rounding", (getter)context_getround, (setter)context_setround, NULL, NULL}, +- { "capitals", (getter)context_getcapitals, (setter)context_setcapitals, NULL, NULL}, +- { "clamp", (getter)context_getclamp, (setter)context_setclamp, NULL, NULL}, ++ { "prec", context_getprec, context_setprec, NULL, NULL}, ++ { "Emax", context_getemax, context_setemax, NULL, NULL}, ++ { "Emin", context_getemin, context_setemin, NULL, NULL}, ++ { "rounding", context_getround, context_setround, NULL, NULL}, ++ { "capitals", context_getcapitals, context_setcapitals, NULL, NULL}, ++ { "clamp", context_getclamp, context_setclamp, NULL, NULL}, + #ifdef EXTRA_FUNCTIONALITY +- { "_allcr", (getter)context_getallcr, (setter)context_setallcr, NULL, NULL}, +- { "_traps", (getter)context_gettraps, (setter)context_settraps, NULL, NULL}, +- { "_flags", (getter)context_getstatus, (setter)context_setstatus, NULL, NULL}, ++ { "_allcr", context_getallcr, context_setallcr, NULL, NULL}, ++ { "_traps", context_gettraps, context_settraps, NULL, NULL}, ++ { "_flags", context_getstatus, context_setstatus, NULL, NULL}, + #endif + {NULL} + }; +@@ -1947,9 +1956,9 @@ + } + + static int +-ctxmanager_traverse(PyDecContextManagerObject *self, visitproc visit, +- void *arg) ++ctxmanager_traverse(PyObject *op, visitproc visit, void *arg) + { ++ PyDecContextManagerObject *self = _PyDecContextManagerObject_CAST(op); + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->local); + Py_VISIT(self->global); +@@ -1957,29 +1966,29 @@ + } + + static int +-ctxmanager_clear(PyDecContextManagerObject *self) ++ctxmanager_clear(PyObject *op) + { ++ PyDecContextManagerObject *self = _PyDecContextManagerObject_CAST(op); + Py_CLEAR(self->local); + Py_CLEAR(self->global); + return 0; + } + + static void +-ctxmanager_dealloc(PyDecContextManagerObject *self) ++ctxmanager_dealloc(PyObject *self) + { + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + (void)ctxmanager_clear(self); +- tp->tp_free((PyObject *)self); ++ tp->tp_free(self); + Py_DECREF(tp); + } + + static PyObject * +-ctxmanager_set_local(PyDecContextManagerObject *self, +- PyObject *Py_UNUSED(dummy)) ++ctxmanager_set_local(PyObject *op, PyObject *Py_UNUSED(dummy)) + { + PyObject *ret; +- ++ PyDecContextManagerObject *self = _PyDecContextManagerObject_CAST(op); + ret = PyDec_SetCurrentContext(PyType_GetModule(Py_TYPE(self)), self->local); + if (ret == NULL) { + return NULL; +@@ -1990,11 +1999,10 @@ + } + + static PyObject * +-ctxmanager_restore_global(PyDecContextManagerObject *self, +- PyObject *Py_UNUSED(args)) ++ctxmanager_restore_global(PyObject *op, PyObject *Py_UNUSED(args)) + { + PyObject *ret; +- ++ PyDecContextManagerObject *self = _PyDecContextManagerObject_CAST(op); + ret = PyDec_SetCurrentContext(PyType_GetModule(Py_TYPE(self)), self->global); + if (ret == NULL) { + return NULL; +@@ -2006,8 +2014,8 @@ + + + static PyMethodDef ctxmanager_methods[] = { +- {"__enter__", (PyCFunction)ctxmanager_set_local, METH_NOARGS, NULL}, +- {"__exit__", (PyCFunction)ctxmanager_restore_global, METH_VARARGS, NULL}, ++ {"__enter__", ctxmanager_set_local, METH_NOARGS, NULL}, ++ {"__exit__", ctxmanager_restore_global, METH_VARARGS, NULL}, + {NULL, NULL} + }; + +@@ -2323,38 +2331,43 @@ + dec_from_long(decimal_state *state, PyTypeObject *type, PyObject *v, + const mpd_context_t *ctx, uint32_t *status) + { +- PyObject *dec; +- PyLongObject *l = (PyLongObject *)v; ++ PyObject *dec = PyDecType_New(state, type); + +- dec = PyDecType_New(state, type); + if (dec == NULL) { + return NULL; + } + +- if (_PyLong_IsZero(l)) { +- _dec_settriple(dec, MPD_POS, 0, 0); +- return dec; +- } +- +- uint8_t sign = _PyLong_IsNegative(l) ? MPD_NEG : MPD_POS; ++ PyLongExport export_long; + +- if (_PyLong_IsCompact(l)) { +- _dec_settriple(dec, sign, l->long_value.ob_digit[0], 0); +- mpd_qfinalize(MPD(dec), ctx, status); +- return dec; ++ if (PyLong_Export(v, &export_long) == -1) { ++ Py_DECREF(dec); ++ return NULL; + } +- size_t len = _PyLong_DigitCount(l); ++ if (export_long.digits) { ++ const PyLongLayout *layout = PyLong_GetNativeLayout(); + +-#if PYLONG_BITS_IN_DIGIT == 30 +- mpd_qimport_u32(MPD(dec), l->long_value.ob_digit, len, sign, PyLong_BASE, +- ctx, status); +-#elif PYLONG_BITS_IN_DIGIT == 15 +- mpd_qimport_u16(MPD(dec), l->long_value.ob_digit, len, sign, PyLong_BASE, +- ctx, status); +-#else +- #error "PYLONG_BITS_IN_DIGIT should be 15 or 30" +-#endif ++ assert(layout->bits_per_digit < 32); ++ assert(layout->digits_order == -1); ++ assert(layout->digit_endianness == (PY_LITTLE_ENDIAN ? -1 : 1)); ++ assert(layout->digit_size == 2 || layout->digit_size == 4); + ++ uint32_t base = (uint32_t)1 << layout->bits_per_digit; ++ uint8_t sign = export_long.negative ? MPD_NEG : MPD_POS; ++ Py_ssize_t len = export_long.ndigits; ++ ++ if (layout->digit_size == 4) { ++ mpd_qimport_u32(MPD(dec), export_long.digits, len, sign, ++ base, ctx, status); ++ } ++ else { ++ mpd_qimport_u16(MPD(dec), export_long.digits, len, sign, ++ base, ctx, status); ++ } ++ PyLong_FreeExport(&export_long); ++ } ++ else { ++ mpd_qset_i64(MPD(dec), export_long.value, ctx, status); ++ } + return dec; + } + +@@ -3461,7 +3474,7 @@ + PyObject *u; + + if (state->PyDecimal == NULL) { +- state->PyDecimal = _PyImport_GetModuleAttrString("_pydecimal", "Decimal"); ++ state->PyDecimal = PyImport_ImportModuleAttrString("_pydecimal", "Decimal"); + if (state->PyDecimal == NULL) { + return NULL; + } +@@ -3639,13 +3652,6 @@ + static PyObject * + dec_as_long(PyObject *dec, PyObject *context, int round) + { +- PyLongObject *pylong; +- digit *ob_digit; +- size_t n; +- mpd_t *x; +- mpd_context_t workctx; +- uint32_t status = 0; +- + if (mpd_isspecial(MPD(dec))) { + if (mpd_isnan(MPD(dec))) { + PyErr_SetString(PyExc_ValueError, +@@ -3658,12 +3664,16 @@ + return NULL; + } + +- x = mpd_qnew(); ++ mpd_t *x = mpd_qnew(); ++ + if (x == NULL) { + PyErr_NoMemory(); + return NULL; + } +- workctx = *CTX(context); ++ ++ mpd_context_t workctx = *CTX(context); ++ uint32_t status = 0; ++ + workctx.round = round; + mpd_qround_to_int(x, MPD(dec), &workctx, &status); + if (dec_addstatus(context, status)) { +@@ -3672,34 +3682,56 @@ + } + + status = 0; +- ob_digit = NULL; +-#if PYLONG_BITS_IN_DIGIT == 30 +- n = mpd_qexport_u32(&ob_digit, 0, PyLong_BASE, x, &status); +-#elif PYLONG_BITS_IN_DIGIT == 15 +- n = mpd_qexport_u16(&ob_digit, 0, PyLong_BASE, x, &status); +-#else +- #error "PYLONG_BITS_IN_DIGIT should be 15 or 30" +-#endif ++ int64_t val = mpd_qget_i64(x, &status); ++ ++ if (!status) { ++ mpd_del(x); ++ return PyLong_FromInt64(val); ++ } ++ assert(!mpd_iszero(x)); ++ ++ const PyLongLayout *layout = PyLong_GetNativeLayout(); ++ ++ assert(layout->bits_per_digit < 32); ++ assert(layout->digits_order == -1); ++ assert(layout->digit_endianness == (PY_LITTLE_ENDIAN ? -1 : 1)); ++ assert(layout->digit_size == 2 || layout->digit_size == 4); ++ ++ uint32_t base = (uint32_t)1 << layout->bits_per_digit; ++ /* We use a temporary buffer for digits for now, as for nonzero rdata ++ mpd_qexport_u32/u16() require either space "allocated by one of ++ libmpdec’s allocation functions" or "rlen MUST be correct" (to avoid ++ reallocation). This can be further optimized by using rlen from ++ mpd_sizeinbase(). See gh-127925. */ ++ void *tmp_digits = NULL; ++ size_t n; ++ ++ status = 0; ++ if (layout->digit_size == 4) { ++ n = mpd_qexport_u32((uint32_t **)&tmp_digits, 0, base, x, &status); ++ } ++ else { ++ n = mpd_qexport_u16((uint16_t **)&tmp_digits, 0, base, x, &status); ++ } + + if (n == SIZE_MAX) { + PyErr_NoMemory(); + mpd_del(x); ++ mpd_free(tmp_digits); + return NULL; + } + +- if (n == 1) { +- sdigit val = mpd_arith_sign(x) * ob_digit[0]; +- mpd_free(ob_digit); +- mpd_del(x); +- return PyLong_FromLong(val); +- } ++ void *digits; ++ PyLongWriter *writer = PyLongWriter_Create(mpd_isnegative(x), n, &digits); + +- assert(n > 0); +- assert(!mpd_iszero(x)); +- pylong = _PyLong_FromDigits(mpd_isnegative(x), n, ob_digit); +- mpd_free(ob_digit); + mpd_del(x); +- return (PyObject *) pylong; ++ if (writer == NULL) { ++ mpd_free(tmp_digits); ++ return NULL; ++ } ++ memcpy(digits, tmp_digits, layout->digit_size*n); ++ mpd_free(tmp_digits); ++ return PyLongWriter_Finish(writer); + } + + /* Convert a Decimal to its exact integer ratio representation. */ +@@ -5018,8 +5050,8 @@ + + static PyGetSetDef dec_getsets [] = + { +- { "real", (getter)dec_real, NULL, NULL, NULL}, +- { "imag", (getter)dec_imag, NULL, NULL, NULL}, ++ { "real", dec_real, NULL, NULL, NULL}, ++ { "imag", dec_imag, NULL, NULL, NULL}, + {NULL} + }; + +diff --git a/Modules/_decimal/libmpdec/io.c b/Modules/_decimal/libmpdec/io.c +index 4e95b8964c8..bdcca001659 100644 +--- a/Modules/_decimal/libmpdec/io.c ++++ b/Modules/_decimal/libmpdec/io.c +@@ -347,6 +347,10 @@ + or the location of a decimal point. */ + #define EXTRACT_DIGIT(s, x, d, dot) \ + if (s == dot) *s++ = '.'; *s++ = '0' + (char)(x / d); x %= d ++#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && __GNUC__ >= 12 ++ #pragma GCC diagnostic push ++ #pragma GCC diagnostic ignored "-Wstringop-overflow" ++#endif + static inline char * + word_to_string(char *s, mpd_uint_t x, int n, char *dot) + { +@@ -378,6 +382,9 @@ + *s = '\0'; + return s; + } ++#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && __GNUC__ >= 12 ++ #pragma GCC diagnostic pop ++#endif + + /* Print exponent x to string s. Undefined for MPD_SSIZE_MIN. */ + static inline char * +diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c +index 355f322d304..b5b0b82571f 100644 +--- a/Modules/_elementtree.c ++++ b/Modules/_elementtree.c +@@ -16,7 +16,6 @@ + #endif + + #include "Python.h" +-#include "pycore_import.h" // _PyImport_GetModuleAttrString() + #include "pycore_pyhash.h" // _Py_HashSecret + + #include // offsetof() +@@ -4393,7 +4392,7 @@ + CREATE_TYPE(m, st->Element_Type, &element_spec); + CREATE_TYPE(m, st->XMLParser_Type, &xmlparser_spec); + +- st->deepcopy_obj = _PyImport_GetModuleAttrString("copy", "deepcopy"); ++ st->deepcopy_obj = PyImport_ImportModuleAttrString("copy", "deepcopy"); + if (st->deepcopy_obj == NULL) { + goto error; + } +@@ -4403,7 +4402,7 @@ + goto error; + + /* link against pyexpat */ +- if (!(st->expat_capsule = _PyImport_GetModuleAttrString("pyexpat", "expat_CAPI"))) ++ if (!(st->expat_capsule = PyImport_ImportModuleAttrString("pyexpat", "expat_CAPI"))) + goto error; + if (!(st->expat_capi = PyCapsule_GetPointer(st->expat_capsule, PyExpat_CAPSULE_NAME))) + goto error; +diff --git a/Modules/_gdbmmodule.c b/Modules/_gdbmmodule.c +index df7fba67810..ab2ebdba924 100644 +--- a/Modules/_gdbmmodule.c ++++ b/Modules/_gdbmmodule.c +@@ -8,10 +8,11 @@ + #endif + + #include "Python.h" ++#include "pycore_pyerrors.h" // _PyErr_SetLocaleString() + #include "gdbm.h" + + #include +-#include // free() ++#include // free() + #include + #include + +@@ -33,6 +34,24 @@ + return (_gdbm_state *)state; + } + ++/* ++ * Set the gdbm error obtained by gdbm_strerror(gdbm_errno). ++ * ++ * If no error message exists, a generic (UTF-8) error message ++ * is used instead. ++ */ ++static void ++set_gdbm_error(_gdbm_state *state, const char *generic_error) ++{ ++ const char *gdbm_errmsg = gdbm_strerror(gdbm_errno); ++ if (gdbm_errmsg) { ++ _PyErr_SetLocaleString(state->gdbm_error, gdbm_errmsg); ++ } ++ else { ++ PyErr_SetString(state->gdbm_error, generic_error); ++ } ++} ++ + /*[clinic input] + module _gdbm + class _gdbm.gdbm "gdbmobject *" "&Gdbmtype" +@@ -57,6 +76,8 @@ + GDBM_FILE di_dbm; + } gdbmobject; + ++#define _gdbmobject_CAST(op) ((gdbmobject *)(op)) ++ + #include "clinic/_gdbmmodule.c.h" + + #define check_gdbmobject_open(v, err) \ +@@ -91,7 +112,7 @@ + PyErr_SetFromErrnoWithFilename(state->gdbm_error, file); + } + else { +- PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno)); ++ set_gdbm_error(state, "gdbm_open() error"); + } + Py_DECREF(dp); + return NULL; +@@ -101,27 +122,29 @@ + + /* Methods */ + static int +-gdbm_traverse(gdbmobject *dp, visitproc visit, void *arg) ++gdbm_traverse(PyObject *op, visitproc visit, void *arg) + { +- Py_VISIT(Py_TYPE(dp)); ++ Py_VISIT(Py_TYPE(op)); + return 0; + } + + static void +-gdbm_dealloc(gdbmobject *dp) ++gdbm_dealloc(PyObject *op) + { ++ gdbmobject *dp = _gdbmobject_CAST(op); ++ PyTypeObject *tp = Py_TYPE(dp); + PyObject_GC_UnTrack(dp); + if (dp->di_dbm) { + gdbm_close(dp->di_dbm); + } +- PyTypeObject *tp = Py_TYPE(dp); + tp->tp_free(dp); + Py_DECREF(tp); + } + + static Py_ssize_t +-gdbm_length(gdbmobject *dp) ++gdbm_length(PyObject *op) + { ++ gdbmobject *dp = _gdbmobject_CAST(op); + _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp)); + if (dp->di_dbm == NULL) { + PyErr_SetString(state->gdbm_error, "GDBM object has already been closed"); +@@ -136,7 +159,7 @@ + PyErr_SetFromErrno(state->gdbm_error); + } + else { +- PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno)); ++ set_gdbm_error(state, "gdbm_count() error"); + } + return -1; + } +@@ -166,8 +189,9 @@ + } + + static int +-gdbm_bool(gdbmobject *dp) ++gdbm_bool(PyObject *op) + { ++ gdbmobject *dp = _gdbmobject_CAST(op); + _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp)); + if (dp->di_dbm == NULL) { + PyErr_SetString(state->gdbm_error, "GDBM object has already been closed"); +@@ -216,10 +240,11 @@ + } + + static PyObject * +-gdbm_subscript(gdbmobject *dp, PyObject *key) ++gdbm_subscript(PyObject *op, PyObject *key) + { + PyObject *v; + datum drec, krec; ++ gdbmobject *dp = _gdbmobject_CAST(op); + _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp)); + + if (!parse_datum(key, &krec, NULL)) { +@@ -256,7 +281,7 @@ + { + PyObject *res; + +- res = gdbm_subscript(self, key); ++ res = gdbm_subscript((PyObject *)self, key); + if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) { + PyErr_Clear(); + return Py_NewRef(default_value); +@@ -265,10 +290,11 @@ + } + + static int +-gdbm_ass_sub(gdbmobject *dp, PyObject *v, PyObject *w) ++gdbm_ass_sub(PyObject *op, PyObject *v, PyObject *w) + { + datum krec, drec; + const char *failmsg = "gdbm mappings have bytes or string indices only"; ++ gdbmobject *dp = _gdbmobject_CAST(op); + _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp)); + + if (!parse_datum(v, &krec, failmsg)) { +@@ -286,7 +312,7 @@ + PyErr_SetObject(PyExc_KeyError, v); + } + else { +- PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno)); ++ set_gdbm_error(state, "gdbm_delete() error"); + } + return -1; + } +@@ -297,11 +323,12 @@ + } + errno = 0; + if (gdbm_store(dp->di_dbm, krec, drec, GDBM_REPLACE) < 0) { +- if (errno != 0) ++ if (errno != 0) { + PyErr_SetFromErrno(state->gdbm_error); +- else +- PyErr_SetString(state->gdbm_error, +- gdbm_strerror(gdbm_errno)); ++ } ++ else { ++ set_gdbm_error(state, "gdbm_store() error"); ++ } + return -1; + } + } +@@ -325,12 +352,12 @@ + { + PyObject *res; + +- res = gdbm_subscript(self, key); ++ res = gdbm_subscript((PyObject *)self, key); + if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) { + PyErr_Clear(); +- if (gdbm_ass_sub(self, key, default_value) < 0) ++ if (gdbm_ass_sub((PyObject *)self, key, default_value) < 0) + return NULL; +- return gdbm_subscript(self, key); ++ return gdbm_subscript((PyObject *)self, key); + } + return res; + } +@@ -534,10 +561,12 @@ + check_gdbmobject_open(self, state->gdbm_error); + errno = 0; + if (gdbm_reorganize(self->di_dbm) < 0) { +- if (errno != 0) ++ if (errno != 0) { + PyErr_SetFromErrno(state->gdbm_error); +- else +- PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno)); ++ } ++ else { ++ set_gdbm_error(state, "gdbm_reorganize() error"); ++ } + return NULL; + } + Py_RETURN_NONE; +@@ -819,7 +848,7 @@ + static void + _gdbm_module_free(void *module) + { +- _gdbm_module_clear((PyObject *)module); ++ (void)_gdbm_module_clear((PyObject *)module); + } + + static PyModuleDef_Slot _gdbm_module_slots[] = { +diff --git a/Modules/_hacl/Lib_Memzero0.c b/Modules/_hacl/Lib_Memzero0.c +index 5c269d231de..f01568a1386 100644 +--- a/Modules/_hacl/Lib_Memzero0.c ++++ b/Modules/_hacl/Lib_Memzero0.c +@@ -8,6 +8,10 @@ + #include + #endif + ++#if defined(__APPLE__) && defined(__MACH__) ++#include ++#endif ++ + #if (defined(__APPLE__) && defined(__MACH__)) || defined(__linux__) + #define __STDC_WANT_LIB_EXT1__ 1 + #include +@@ -37,7 +41,7 @@ + + #ifdef _WIN32 + SecureZeroMemory(dst, len_); +- #elif defined(__APPLE__) && defined(__MACH__) ++ #elif defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_MIN_REQUIRED) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1090) + memset_s(dst, len_, 0, len_); + #elif (defined(__linux__) && !defined(LINUX_NO_EXPLICIT_BZERO)) || defined(__FreeBSD__) + explicit_bzero(dst, len_); +diff --git a/Modules/_hacl/include/krml/internal/target.h b/Modules/_hacl/include/krml/internal/target.h +index fd74d3da684..9b403c36cec 100644 +--- a/Modules/_hacl/include/krml/internal/target.h ++++ b/Modules/_hacl/include/krml/internal/target.h +@@ -19,6 +19,20 @@ + # define inline __inline__ + #endif + ++/* There is no support for aligned_alloc() in macOS before Catalina, so ++ * let's make a macro to use _mm_malloc() and _mm_free() functions ++ * from mm_malloc.h. */ ++#if defined(__APPLE__) && defined(__MACH__) ++# include ++# if defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \ ++ (MAC_OS_X_VERSION_MIN_REQUIRED < 101500) ++# include ++# define LEGACY_MACOS ++# else ++# undef LEGACY_MACOS ++#endif ++#endif ++ + /******************************************************************************/ + /* Macros that KaRaMeL will generate. */ + /******************************************************************************/ +@@ -133,6 +147,8 @@ + defined(_MSC_VER) || \ + (defined(__MINGW32__) && defined(__MINGW64_VERSION_MAJOR))) + # define KRML_ALIGNED_MALLOC(X, Y) _aligned_malloc(Y, X) ++# elif defined(LEGACY_MACOS) ++# define KRML_ALIGNED_MALLOC(X, Y) _mm_malloc(Y, X) + # else + # define KRML_ALIGNED_MALLOC(X, Y) aligned_alloc(X, Y) + # endif +@@ -150,6 +166,8 @@ + defined(_MSC_VER) || \ + (defined(__MINGW32__) && defined(__MINGW64_VERSION_MAJOR))) + # define KRML_ALIGNED_FREE(X) _aligned_free(X) ++# elif defined(LEGACY_MACOS) ++# define KRML_ALIGNED_FREE(X) _mm_free(X) + # else + # define KRML_ALIGNED_FREE(X) free(X) + # endif +diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c +index 2c9a9feecc7..d7586feea3e 100644 +--- a/Modules/_hashopenssl.c ++++ b/Modules/_hashopenssl.c +@@ -25,13 +25,14 @@ + #include + #include "Python.h" + #include "pycore_hashtable.h" +-#include "pycore_strhex.h" // _Py_strhex() ++#include "pycore_strhex.h" // _Py_strhex() ++#include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_LOAD_PTR_RELAXED + #include "hashlib.h" + + /* EVP is the preferred interface to hashing in OpenSSL */ + #include + #include +-#include // FIPS_mode() ++#include // FIPS_mode() + /* We use the object interface to discover what hashes OpenSSL supports. */ + #include + #include +@@ -319,6 +320,7 @@ + va_end(vargs); + ERR_clear_error(); + ++ /* ERR_ERROR_STRING(3) ensures that the messages below are ASCII */ + lib = ERR_lib_error_string(errcode); + func = ERR_func_error_string(errcode); + reason = ERR_reason_error_string(errcode); +@@ -368,6 +370,7 @@ + py_digest_by_name(PyObject *module, const char *name, enum Py_hash_type py_ht) + { + PY_EVP_MD *digest = NULL; ++ PY_EVP_MD *other_digest = NULL; + _hashlibstate *state = get_hashlib_state(module); + py_hashentry_t *entry = (py_hashentry_t *)_Py_hashtable_get( + state->hashtable, (const void*)name +@@ -378,20 +381,36 @@ + case Py_ht_evp: + case Py_ht_mac: + case Py_ht_pbkdf2: +- if (entry->evp == NULL) { +- entry->evp = PY_EVP_MD_fetch(entry->ossl_name, NULL); ++ digest = FT_ATOMIC_LOAD_PTR_RELAXED(entry->evp); ++ if (digest == NULL) { ++ digest = PY_EVP_MD_fetch(entry->ossl_name, NULL); ++#ifdef Py_GIL_DISABLED ++ // exchange just in case another thread did same thing at same time ++ other_digest = _Py_atomic_exchange_ptr(&entry->evp, digest); ++#else ++ entry->evp = digest; ++#endif + } +- digest = entry->evp; + break; + case Py_ht_evp_nosecurity: +- if (entry->evp_nosecurity == NULL) { +- entry->evp_nosecurity = PY_EVP_MD_fetch(entry->ossl_name, "-fips"); ++ digest = FT_ATOMIC_LOAD_PTR_RELAXED(entry->evp_nosecurity); ++ if (digest == NULL) { ++ digest = PY_EVP_MD_fetch(entry->ossl_name, "-fips"); ++#ifdef Py_GIL_DISABLED ++ // exchange just in case another thread did same thing at same time ++ other_digest = _Py_atomic_exchange_ptr(&entry->evp_nosecurity, digest); ++#else ++ entry->evp_nosecurity = digest; ++#endif + } +- digest = entry->evp_nosecurity; + break; + } ++ // if another thread same thing at same time make sure we got same ptr ++ assert(other_digest == NULL || other_digest == digest); + if (digest != NULL) { +- PY_EVP_MD_up_ref(digest); ++ if (other_digest == NULL) { ++ PY_EVP_MD_up_ref(digest); ++ } + } + } else { + // Fall back for looking up an unindexed OpenSSL specific name. +diff --git a/Modules/_interpretersmodule.c b/Modules/_interpretersmodule.c +index a36823c4bb9..fcd0baf696f 100644 +--- a/Modules/_interpretersmodule.c ++++ b/Modules/_interpretersmodule.c +@@ -459,7 +459,12 @@ + + // Prep and switch interpreters. + if (_PyXI_Enter(&session, interp, shareables) < 0) { +- assert(!PyErr_Occurred()); ++ if (PyErr_Occurred()) { ++ // If an error occured at this step, it means that interp ++ // was not prepared and switched. ++ return -1; ++ } ++ // Now, apply the error from another interpreter: + PyObject *excinfo = _PyXI_ApplyError(session.error); + if (excinfo != NULL) { + *p_excinfo = excinfo; +diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c +index bc5fff54a62..53c4702f673 100644 +--- a/Modules/_io/bufferedio.c ++++ b/Modules/_io/bufferedio.c +@@ -261,6 +261,8 @@ + PyObject *weakreflist; + } buffered; + ++#define buffered_CAST(op) ((buffered *)(op)) ++ + /* + Implementation notes: + +@@ -399,8 +401,9 @@ + + + static int +-buffered_clear(buffered *self) ++buffered_clear(PyObject *op) + { ++ buffered *self = buffered_CAST(op); + self->ok = 0; + Py_CLEAR(self->raw); + Py_CLEAR(self->dict); +@@ -408,16 +411,17 @@ + } + + static void +-buffered_dealloc(buffered *self) ++buffered_dealloc(PyObject *op) + { ++ buffered *self = buffered_CAST(op); + PyTypeObject *tp = Py_TYPE(self); + self->finalizing = 1; +- if (_PyIOBase_finalize((PyObject *) self) < 0) ++ if (_PyIOBase_finalize(op) < 0) + return; + _PyObject_GC_UNTRACK(self); + self->ok = 0; + if (self->weakreflist != NULL) +- PyObject_ClearWeakRefs((PyObject *)self); ++ PyObject_ClearWeakRefs(op); + if (self->buffer) { + PyMem_Free(self->buffer); + self->buffer = NULL; +@@ -426,8 +430,8 @@ + PyThread_free_lock(self->lock); + self->lock = NULL; + } +- (void)buffered_clear(self); +- tp->tp_free((PyObject *)self); ++ (void)buffered_clear(op); ++ tp->tp_free(self); + Py_DECREF(tp); + } + +@@ -2227,6 +2231,8 @@ + PyObject *weakreflist; + } rwpair; + ++#define rwpair_CAST(op) ((rwpair *)(op)) ++ + /*[clinic input] + _io.BufferedRWPair.__init__ + reader: object +@@ -2276,8 +2282,9 @@ + } + + static int +-bufferedrwpair_traverse(rwpair *self, visitproc visit, void *arg) ++bufferedrwpair_traverse(PyObject *op, visitproc visit, void *arg) + { ++ rwpair *self = rwpair_CAST(op); + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->dict); + Py_VISIT(self->reader); +@@ -2286,8 +2293,9 @@ + } + + static int +-bufferedrwpair_clear(rwpair *self) ++bufferedrwpair_clear(PyObject *op) + { ++ rwpair *self = rwpair_CAST(op); + Py_CLEAR(self->reader); + Py_CLEAR(self->writer); + Py_CLEAR(self->dict); +@@ -2295,14 +2303,15 @@ + } + + static void +-bufferedrwpair_dealloc(rwpair *self) ++bufferedrwpair_dealloc(PyObject *op) + { ++ rwpair *self = rwpair_CAST(op); + PyTypeObject *tp = Py_TYPE(self); + _PyObject_GC_UNTRACK(self); + if (self->weakreflist != NULL) +- PyObject_ClearWeakRefs((PyObject *)self); +- (void)bufferedrwpair_clear(self); +- tp->tp_free((PyObject *) self); ++ PyObject_ClearWeakRefs(op); ++ (void)bufferedrwpair_clear(op); ++ tp->tp_free(self); + Py_DECREF(tp); + } + +@@ -2328,62 +2337,72 @@ + } + + static PyObject * +-bufferedrwpair_read(rwpair *self, PyObject *args) ++bufferedrwpair_read(PyObject *op, PyObject *args) + { ++ rwpair *self = rwpair_CAST(op); + return _forward_call(self->reader, &_Py_ID(read), args); + } + + static PyObject * +-bufferedrwpair_peek(rwpair *self, PyObject *args) ++bufferedrwpair_peek(PyObject *op, PyObject *args) + { ++ rwpair *self = rwpair_CAST(op); + return _forward_call(self->reader, &_Py_ID(peek), args); + } + + static PyObject * +-bufferedrwpair_read1(rwpair *self, PyObject *args) ++bufferedrwpair_read1(PyObject *op, PyObject *args) + { ++ rwpair *self = rwpair_CAST(op); + return _forward_call(self->reader, &_Py_ID(read1), args); + } + + static PyObject * +-bufferedrwpair_readinto(rwpair *self, PyObject *args) ++bufferedrwpair_readinto(PyObject *op, PyObject *args) + { ++ rwpair *self = rwpair_CAST(op); + return _forward_call(self->reader, &_Py_ID(readinto), args); + } + + static PyObject * +-bufferedrwpair_readinto1(rwpair *self, PyObject *args) ++bufferedrwpair_readinto1(PyObject *op, PyObject *args) + { ++ rwpair *self = rwpair_CAST(op); + return _forward_call(self->reader, &_Py_ID(readinto1), args); + } + + static PyObject * +-bufferedrwpair_write(rwpair *self, PyObject *args) ++bufferedrwpair_write(PyObject *op, PyObject *args) + { ++ rwpair *self = rwpair_CAST(op); + return _forward_call(self->writer, &_Py_ID(write), args); + } + + static PyObject * +-bufferedrwpair_flush(rwpair *self, PyObject *Py_UNUSED(ignored)) ++bufferedrwpair_flush(PyObject *op, PyObject *Py_UNUSED(dummy)) + { ++ rwpair *self = rwpair_CAST(op); + return _forward_call(self->writer, &_Py_ID(flush), NULL); + } + + static PyObject * +-bufferedrwpair_readable(rwpair *self, PyObject *Py_UNUSED(ignored)) ++bufferedrwpair_readable(PyObject *op, PyObject *Py_UNUSED(dummy)) + { ++ rwpair *self = rwpair_CAST(op); + return _forward_call(self->reader, &_Py_ID(readable), NULL); + } + + static PyObject * +-bufferedrwpair_writable(rwpair *self, PyObject *Py_UNUSED(ignored)) ++bufferedrwpair_writable(PyObject *op, PyObject *Py_UNUSED(dummy)) + { ++ rwpair *self = rwpair_CAST(op); + return _forward_call(self->writer, &_Py_ID(writable), NULL); + } + + static PyObject * +-bufferedrwpair_close(rwpair *self, PyObject *Py_UNUSED(ignored)) ++bufferedrwpair_close(PyObject *op, PyObject *Py_UNUSED(dummy)) + { ++ rwpair *self = rwpair_CAST(op); + PyObject *exc = NULL; + PyObject *ret = _forward_call(self->writer, &_Py_ID(close), NULL); + if (ret == NULL) { +@@ -2401,8 +2420,9 @@ + } + + static PyObject * +-bufferedrwpair_isatty(rwpair *self, PyObject *Py_UNUSED(ignored)) ++bufferedrwpair_isatty(PyObject *op, PyObject *Py_UNUSED(dummy)) + { ++ rwpair *self = rwpair_CAST(op); + PyObject *ret = _forward_call(self->writer, &_Py_ID(isatty), NULL); + + if (ret != Py_False) { +@@ -2415,8 +2435,9 @@ + } + + static PyObject * +-bufferedrwpair_closed_get(rwpair *self, void *context) ++bufferedrwpair_closed_get(PyObject *op, void *Py_UNUSED(dummy)) + { ++ rwpair *self = rwpair_CAST(op); + if (self->writer == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "the BufferedRWPair object is being garbage-collected"); +@@ -2633,20 +2654,20 @@ + }; + + static PyMethodDef bufferedrwpair_methods[] = { +- {"read", (PyCFunction)bufferedrwpair_read, METH_VARARGS}, +- {"peek", (PyCFunction)bufferedrwpair_peek, METH_VARARGS}, +- {"read1", (PyCFunction)bufferedrwpair_read1, METH_VARARGS}, +- {"readinto", (PyCFunction)bufferedrwpair_readinto, METH_VARARGS}, +- {"readinto1", (PyCFunction)bufferedrwpair_readinto1, METH_VARARGS}, ++ {"read", bufferedrwpair_read, METH_VARARGS}, ++ {"peek", bufferedrwpair_peek, METH_VARARGS}, ++ {"read1", bufferedrwpair_read1, METH_VARARGS}, ++ {"readinto", bufferedrwpair_readinto, METH_VARARGS}, ++ {"readinto1", bufferedrwpair_readinto1, METH_VARARGS}, + +- {"write", (PyCFunction)bufferedrwpair_write, METH_VARARGS}, +- {"flush", (PyCFunction)bufferedrwpair_flush, METH_NOARGS}, ++ {"write", bufferedrwpair_write, METH_VARARGS}, ++ {"flush", bufferedrwpair_flush, METH_NOARGS}, + +- {"readable", (PyCFunction)bufferedrwpair_readable, METH_NOARGS}, +- {"writable", (PyCFunction)bufferedrwpair_writable, METH_NOARGS}, ++ {"readable", bufferedrwpair_readable, METH_NOARGS}, ++ {"writable", bufferedrwpair_writable, METH_NOARGS}, + +- {"close", (PyCFunction)bufferedrwpair_close, METH_NOARGS}, +- {"isatty", (PyCFunction)bufferedrwpair_isatty, METH_NOARGS}, ++ {"close", bufferedrwpair_close, METH_NOARGS}, ++ {"isatty", bufferedrwpair_isatty, METH_NOARGS}, + + {NULL, NULL} + }; +@@ -2658,7 +2679,7 @@ + }; + + static PyGetSetDef bufferedrwpair_getset[] = { +- {"closed", (getter)bufferedrwpair_closed_get, NULL, NULL}, ++ {"closed", bufferedrwpair_closed_get, NULL, NULL}, + {NULL} + }; + +diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c +index fb66d3db0f7..dc4e40b9f09 100644 +--- a/Modules/_io/bytesio.c ++++ b/Modules/_io/bytesio.c +@@ -21,11 +21,15 @@ + Py_ssize_t exports; + } bytesio; + ++#define bytesio_CAST(op) ((bytesio *)(op)) ++ + typedef struct { + PyObject_HEAD + bytesio *source; + } bytesiobuf; + ++#define bytesiobuf_CAST(op) ((bytesiobuf *)(op)) ++ + /* The bytesio object can be in three states: + * Py_REFCNT(buf) == 1, exports == 0. + * Py_REFCNT(buf) > 1. exports == 0, +@@ -239,8 +243,9 @@ + } + + static PyObject * +-bytesio_get_closed(bytesio *self, void *Py_UNUSED(ignored)) ++bytesio_get_closed(PyObject *op, void *Py_UNUSED(closure)) + { ++ bytesio *self = bytesio_CAST(op); + if (self->buf == NULL) { + Py_RETURN_TRUE; + } +@@ -588,7 +593,7 @@ + + /*[clinic input] + _io.BytesIO.truncate +- size: Py_ssize_t(accept={int, NoneType}, c_default="self->pos") = None ++ size: Py_ssize_t(accept={int, NoneType}, c_default="((bytesio *)self)->pos") = None + / + + Truncate the file to at most size bytes. +@@ -599,7 +604,7 @@ + + static PyObject * + _io_BytesIO_truncate_impl(bytesio *self, Py_ssize_t size) +-/*[clinic end generated code: output=9ad17650c15fa09b input=423759dd42d2f7c1]*/ ++/*[clinic end generated code: output=9ad17650c15fa09b input=dae4295e11c1bbb4]*/ + { + CHECK_CLOSED(self); + CHECK_EXPORTS(self); +@@ -620,9 +625,10 @@ + } + + static PyObject * +-bytesio_iternext(bytesio *self) ++bytesio_iternext(PyObject *op) + { + Py_ssize_t n; ++ bytesio *self = bytesio_CAST(op); + + CHECK_CLOSED(self); + +@@ -783,8 +789,9 @@ + */ + + static PyObject * +-bytesio_getstate(bytesio *self, PyObject *Py_UNUSED(ignored)) ++bytesio_getstate(PyObject *op, PyObject *Py_UNUSED(dummy)) + { ++ bytesio *self = bytesio_CAST(op); + PyObject *initvalue = _io_BytesIO_getvalue_impl(self); + PyObject *dict; + PyObject *state; +@@ -808,12 +815,13 @@ + } + + static PyObject * +-bytesio_setstate(bytesio *self, PyObject *state) ++bytesio_setstate(PyObject *op, PyObject *state) + { + PyObject *result; + PyObject *position_obj; + PyObject *dict; + Py_ssize_t pos; ++ bytesio *self = bytesio_CAST(op); + + assert(state != NULL); + +@@ -883,8 +891,9 @@ + } + + static void +-bytesio_dealloc(bytesio *self) ++bytesio_dealloc(PyObject *op) + { ++ bytesio *self = bytesio_CAST(op); + PyTypeObject *tp = Py_TYPE(self); + _PyObject_GC_UNTRACK(self); + if (self->exports > 0) { +@@ -895,7 +904,7 @@ + Py_CLEAR(self->buf); + Py_CLEAR(self->dict); + if (self->weakreflist != NULL) +- PyObject_ClearWeakRefs((PyObject *) self); ++ PyObject_ClearWeakRefs(op); + tp->tp_free(self); + Py_DECREF(tp); + } +@@ -961,8 +970,9 @@ + } + + static PyObject * +-bytesio_sizeof(bytesio *self, void *unused) ++bytesio_sizeof(PyObject *op, PyObject *Py_UNUSED(dummy)) + { ++ bytesio *self = bytesio_CAST(op); + size_t res = _PyObject_SIZE(Py_TYPE(self)); + if (self->buf && !SHARED_BUF(self)) { + size_t s = _PySys_GetSizeOf(self->buf); +@@ -975,8 +985,9 @@ + } + + static int +-bytesio_traverse(bytesio *self, visitproc visit, void *arg) ++bytesio_traverse(PyObject *op, visitproc visit, void *arg) + { ++ bytesio *self = bytesio_CAST(op); + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->dict); + Py_VISIT(self->buf); +@@ -984,8 +995,9 @@ + } + + static int +-bytesio_clear(bytesio *self) ++bytesio_clear(PyObject *op) + { ++ bytesio *self = bytesio_CAST(op); + Py_CLEAR(self->dict); + if (self->exports == 0) { + Py_CLEAR(self->buf); +@@ -999,7 +1011,7 @@ + #undef clinic_state + + static PyGetSetDef bytesio_getsetlist[] = { +- {"closed", (getter)bytesio_get_closed, NULL, ++ {"closed", bytesio_get_closed, NULL, + "True if the file is closed."}, + {NULL}, /* sentinel */ + }; +@@ -1023,9 +1035,9 @@ + _IO_BYTESIO_GETVALUE_METHODDEF + _IO_BYTESIO_SEEK_METHODDEF + _IO_BYTESIO_TRUNCATE_METHODDEF +- {"__getstate__", (PyCFunction)bytesio_getstate, METH_NOARGS, NULL}, +- {"__setstate__", (PyCFunction)bytesio_setstate, METH_O, NULL}, +- {"__sizeof__", (PyCFunction)bytesio_sizeof, METH_NOARGS, NULL}, ++ {"__getstate__", bytesio_getstate, METH_NOARGS, NULL}, ++ {"__setstate__", bytesio_setstate, METH_O, NULL}, ++ {"__sizeof__", bytesio_sizeof, METH_NOARGS, NULL}, + {NULL, NULL} /* sentinel */ + }; + +@@ -1065,9 +1077,10 @@ + */ + + static int +-bytesiobuf_getbuffer(bytesiobuf *obj, Py_buffer *view, int flags) ++bytesiobuf_getbuffer(PyObject *op, Py_buffer *view, int flags) + { +- bytesio *b = (bytesio *) obj->source; ++ bytesiobuf *obj = bytesiobuf_CAST(op); ++ bytesio *b = bytesio_CAST(obj->source); + + if (view == NULL) { + PyErr_SetString(PyExc_BufferError, +@@ -1080,7 +1093,7 @@ + } + + /* cannot fail if view != NULL and readonly == 0 */ +- (void)PyBuffer_FillInfo(view, (PyObject*)obj, ++ (void)PyBuffer_FillInfo(view, op, + PyBytes_AS_STRING(b->buf), b->string_size, + 0, flags); + b->exports++; +@@ -1088,26 +1101,29 @@ + } + + static void +-bytesiobuf_releasebuffer(bytesiobuf *obj, Py_buffer *view) ++bytesiobuf_releasebuffer(PyObject *op, Py_buffer *Py_UNUSED(view)) + { +- bytesio *b = (bytesio *) obj->source; ++ bytesiobuf *obj = bytesiobuf_CAST(op); ++ bytesio *b = bytesio_CAST(obj->source); + b->exports--; + } + + static int +-bytesiobuf_traverse(bytesiobuf *self, visitproc visit, void *arg) ++bytesiobuf_traverse(PyObject *op, visitproc visit, void *arg) + { ++ bytesiobuf *self = bytesiobuf_CAST(op); + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->source); + return 0; + } + + static void +-bytesiobuf_dealloc(bytesiobuf *self) ++bytesiobuf_dealloc(PyObject *op) + { ++ bytesiobuf *self = bytesiobuf_CAST(op); + PyTypeObject *tp = Py_TYPE(self); + /* bpo-31095: UnTrack is needed before calling any callbacks */ +- PyObject_GC_UnTrack(self); ++ PyObject_GC_UnTrack(op); + Py_CLEAR(self->source); + tp->tp_free(self); + Py_DECREF(tp); +diff --git a/Modules/_io/clinic/bufferedio.c.h b/Modules/_io/clinic/bufferedio.c.h +index e035bd99bac..8ab8000fafe 100644 +--- a/Modules/_io/clinic/bufferedio.c.h ++++ b/Modules/_io/clinic/bufferedio.c.h +@@ -288,12 +288,12 @@ + _io__Buffered___sizeof___impl(buffered *self); + + static PyObject * +-_io__Buffered___sizeof__(buffered *self, PyObject *Py_UNUSED(ignored)) ++_io__Buffered___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io__Buffered___sizeof___impl(self); ++ return_value = _io__Buffered___sizeof___impl((buffered *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -319,12 +319,12 @@ + _io__Buffered_simple_flush_impl(buffered *self); + + static PyObject * +-_io__Buffered_simple_flush(buffered *self, PyObject *Py_UNUSED(ignored)) ++_io__Buffered_simple_flush(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io__Buffered_simple_flush_impl(self); ++ return_value = _io__Buffered_simple_flush_impl((buffered *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -344,12 +344,12 @@ + _io__Buffered_closed_get_impl(buffered *self); + + static PyObject * +-_io__Buffered_closed_get(buffered *self, void *Py_UNUSED(context)) ++_io__Buffered_closed_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io__Buffered_closed_get_impl(self); ++ return_value = _io__Buffered_closed_get_impl((buffered *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -367,12 +367,12 @@ + _io__Buffered_close_impl(buffered *self); + + static PyObject * +-_io__Buffered_close(buffered *self, PyObject *Py_UNUSED(ignored)) ++_io__Buffered_close(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io__Buffered_close_impl(self); ++ return_value = _io__Buffered_close_impl((buffered *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -390,12 +390,12 @@ + _io__Buffered_detach_impl(buffered *self); + + static PyObject * +-_io__Buffered_detach(buffered *self, PyObject *Py_UNUSED(ignored)) ++_io__Buffered_detach(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io__Buffered_detach_impl(self); ++ return_value = _io__Buffered_detach_impl((buffered *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -413,12 +413,12 @@ + _io__Buffered_seekable_impl(buffered *self); + + static PyObject * +-_io__Buffered_seekable(buffered *self, PyObject *Py_UNUSED(ignored)) ++_io__Buffered_seekable(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io__Buffered_seekable_impl(self); ++ return_value = _io__Buffered_seekable_impl((buffered *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -436,12 +436,12 @@ + _io__Buffered_readable_impl(buffered *self); + + static PyObject * +-_io__Buffered_readable(buffered *self, PyObject *Py_UNUSED(ignored)) ++_io__Buffered_readable(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io__Buffered_readable_impl(self); ++ return_value = _io__Buffered_readable_impl((buffered *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -459,12 +459,12 @@ + _io__Buffered_writable_impl(buffered *self); + + static PyObject * +-_io__Buffered_writable(buffered *self, PyObject *Py_UNUSED(ignored)) ++_io__Buffered_writable(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io__Buffered_writable_impl(self); ++ return_value = _io__Buffered_writable_impl((buffered *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -484,12 +484,12 @@ + _io__Buffered_name_get_impl(buffered *self); + + static PyObject * +-_io__Buffered_name_get(buffered *self, void *Py_UNUSED(context)) ++_io__Buffered_name_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io__Buffered_name_get_impl(self); ++ return_value = _io__Buffered_name_get_impl((buffered *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -509,12 +509,12 @@ + _io__Buffered_mode_get_impl(buffered *self); + + static PyObject * +-_io__Buffered_mode_get(buffered *self, void *Py_UNUSED(context)) ++_io__Buffered_mode_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io__Buffered_mode_get_impl(self); ++ return_value = _io__Buffered_mode_get_impl((buffered *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -532,12 +532,12 @@ + _io__Buffered_fileno_impl(buffered *self); + + static PyObject * +-_io__Buffered_fileno(buffered *self, PyObject *Py_UNUSED(ignored)) ++_io__Buffered_fileno(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io__Buffered_fileno_impl(self); ++ return_value = _io__Buffered_fileno_impl((buffered *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -555,12 +555,12 @@ + _io__Buffered_isatty_impl(buffered *self); + + static PyObject * +-_io__Buffered_isatty(buffered *self, PyObject *Py_UNUSED(ignored)) ++_io__Buffered_isatty(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io__Buffered_isatty_impl(self); ++ return_value = _io__Buffered_isatty_impl((buffered *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -578,12 +578,12 @@ + _io__Buffered_flush_impl(buffered *self); + + static PyObject * +-_io__Buffered_flush(buffered *self, PyObject *Py_UNUSED(ignored)) ++_io__Buffered_flush(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io__Buffered_flush_impl(self); ++ return_value = _io__Buffered_flush_impl((buffered *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -601,7 +601,7 @@ + _io__Buffered_peek_impl(buffered *self, Py_ssize_t size); + + static PyObject * +-_io__Buffered_peek(buffered *self, PyObject *const *args, Py_ssize_t nargs) ++_io__Buffered_peek(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + Py_ssize_t size = 0; +@@ -626,7 +626,7 @@ + } + skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io__Buffered_peek_impl(self, size); ++ return_value = _io__Buffered_peek_impl((buffered *)self, size); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -645,7 +645,7 @@ + _io__Buffered_read_impl(buffered *self, Py_ssize_t n); + + static PyObject * +-_io__Buffered_read(buffered *self, PyObject *const *args, Py_ssize_t nargs) ++_io__Buffered_read(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + Py_ssize_t n = -1; +@@ -661,7 +661,7 @@ + } + skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io__Buffered_read_impl(self, n); ++ return_value = _io__Buffered_read_impl((buffered *)self, n); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -680,7 +680,7 @@ + _io__Buffered_read1_impl(buffered *self, Py_ssize_t n); + + static PyObject * +-_io__Buffered_read1(buffered *self, PyObject *const *args, Py_ssize_t nargs) ++_io__Buffered_read1(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + Py_ssize_t n = -1; +@@ -705,7 +705,7 @@ + } + skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io__Buffered_read1_impl(self, n); ++ return_value = _io__Buffered_read1_impl((buffered *)self, n); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -724,7 +724,7 @@ + _io__Buffered_readinto_impl(buffered *self, Py_buffer *buffer); + + static PyObject * +-_io__Buffered_readinto(buffered *self, PyObject *arg) ++_io__Buffered_readinto(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + Py_buffer buffer = {NULL, NULL}; +@@ -734,7 +734,7 @@ + goto exit; + } + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io__Buffered_readinto_impl(self, &buffer); ++ return_value = _io__Buffered_readinto_impl((buffered *)self, &buffer); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -758,7 +758,7 @@ + _io__Buffered_readinto1_impl(buffered *self, Py_buffer *buffer); + + static PyObject * +-_io__Buffered_readinto1(buffered *self, PyObject *arg) ++_io__Buffered_readinto1(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + Py_buffer buffer = {NULL, NULL}; +@@ -768,7 +768,7 @@ + goto exit; + } + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io__Buffered_readinto1_impl(self, &buffer); ++ return_value = _io__Buffered_readinto1_impl((buffered *)self, &buffer); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -792,7 +792,7 @@ + _io__Buffered_readline_impl(buffered *self, Py_ssize_t size); + + static PyObject * +-_io__Buffered_readline(buffered *self, PyObject *const *args, Py_ssize_t nargs) ++_io__Buffered_readline(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + Py_ssize_t size = -1; +@@ -808,7 +808,7 @@ + } + skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io__Buffered_readline_impl(self, size); ++ return_value = _io__Buffered_readline_impl((buffered *)self, size); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -827,12 +827,12 @@ + _io__Buffered_tell_impl(buffered *self); + + static PyObject * +-_io__Buffered_tell(buffered *self, PyObject *Py_UNUSED(ignored)) ++_io__Buffered_tell(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io__Buffered_tell_impl(self); ++ return_value = _io__Buffered_tell_impl((buffered *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -850,7 +850,7 @@ + _io__Buffered_seek_impl(buffered *self, PyObject *targetobj, int whence); + + static PyObject * +-_io__Buffered_seek(buffered *self, PyObject *const *args, Py_ssize_t nargs) ++_io__Buffered_seek(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *targetobj; +@@ -869,7 +869,7 @@ + } + skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io__Buffered_seek_impl(self, targetobj, whence); ++ return_value = _io__Buffered_seek_impl((buffered *)self, targetobj, whence); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -888,7 +888,7 @@ + _io__Buffered_truncate_impl(buffered *self, PyTypeObject *cls, PyObject *pos); + + static PyObject * +-_io__Buffered_truncate(buffered *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_io__Buffered_truncate(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -918,7 +918,7 @@ + pos = args[0]; + skip_optional_posonly: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io__Buffered_truncate_impl(self, cls, pos); ++ return_value = _io__Buffered_truncate_impl((buffered *)self, cls, pos); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -1089,7 +1089,7 @@ + _io_BufferedWriter_write_impl(buffered *self, Py_buffer *buffer); + + static PyObject * +-_io_BufferedWriter_write(buffered *self, PyObject *arg) ++_io_BufferedWriter_write(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + Py_buffer buffer = {NULL, NULL}; +@@ -1098,7 +1098,7 @@ + goto exit; + } + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_BufferedWriter_write_impl(self, &buffer); ++ return_value = _io_BufferedWriter_write_impl((buffered *)self, &buffer); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -1246,4 +1246,4 @@ + exit: + return return_value; + } +-/*[clinic end generated code: output=8f28a97987a9fbe1 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=f019d29701ba2556 input=a9049054013a1b77]*/ +diff --git a/Modules/_io/clinic/bytesio.c.h b/Modules/_io/clinic/bytesio.c.h +index 98d88698c5e..5528df952c3 100644 +--- a/Modules/_io/clinic/bytesio.c.h ++++ b/Modules/_io/clinic/bytesio.c.h +@@ -22,9 +22,9 @@ + _io_BytesIO_readable_impl(bytesio *self); + + static PyObject * +-_io_BytesIO_readable(bytesio *self, PyObject *Py_UNUSED(ignored)) ++_io_BytesIO_readable(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _io_BytesIO_readable_impl(self); ++ return _io_BytesIO_readable_impl((bytesio *)self); + } + + PyDoc_STRVAR(_io_BytesIO_writable__doc__, +@@ -40,9 +40,9 @@ + _io_BytesIO_writable_impl(bytesio *self); + + static PyObject * +-_io_BytesIO_writable(bytesio *self, PyObject *Py_UNUSED(ignored)) ++_io_BytesIO_writable(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _io_BytesIO_writable_impl(self); ++ return _io_BytesIO_writable_impl((bytesio *)self); + } + + PyDoc_STRVAR(_io_BytesIO_seekable__doc__, +@@ -58,9 +58,9 @@ + _io_BytesIO_seekable_impl(bytesio *self); + + static PyObject * +-_io_BytesIO_seekable(bytesio *self, PyObject *Py_UNUSED(ignored)) ++_io_BytesIO_seekable(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _io_BytesIO_seekable_impl(self); ++ return _io_BytesIO_seekable_impl((bytesio *)self); + } + + PyDoc_STRVAR(_io_BytesIO_flush__doc__, +@@ -76,9 +76,9 @@ + _io_BytesIO_flush_impl(bytesio *self); + + static PyObject * +-_io_BytesIO_flush(bytesio *self, PyObject *Py_UNUSED(ignored)) ++_io_BytesIO_flush(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _io_BytesIO_flush_impl(self); ++ return _io_BytesIO_flush_impl((bytesio *)self); + } + + PyDoc_STRVAR(_io_BytesIO_getbuffer__doc__, +@@ -94,13 +94,13 @@ + _io_BytesIO_getbuffer_impl(bytesio *self, PyTypeObject *cls); + + static PyObject * +-_io_BytesIO_getbuffer(bytesio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_io_BytesIO_getbuffer(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "getbuffer() takes no arguments"); + return NULL; + } +- return _io_BytesIO_getbuffer_impl(self, cls); ++ return _io_BytesIO_getbuffer_impl((bytesio *)self, cls); + } + + PyDoc_STRVAR(_io_BytesIO_getvalue__doc__, +@@ -116,9 +116,9 @@ + _io_BytesIO_getvalue_impl(bytesio *self); + + static PyObject * +-_io_BytesIO_getvalue(bytesio *self, PyObject *Py_UNUSED(ignored)) ++_io_BytesIO_getvalue(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _io_BytesIO_getvalue_impl(self); ++ return _io_BytesIO_getvalue_impl((bytesio *)self); + } + + PyDoc_STRVAR(_io_BytesIO_isatty__doc__, +@@ -136,9 +136,9 @@ + _io_BytesIO_isatty_impl(bytesio *self); + + static PyObject * +-_io_BytesIO_isatty(bytesio *self, PyObject *Py_UNUSED(ignored)) ++_io_BytesIO_isatty(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _io_BytesIO_isatty_impl(self); ++ return _io_BytesIO_isatty_impl((bytesio *)self); + } + + PyDoc_STRVAR(_io_BytesIO_tell__doc__, +@@ -154,9 +154,9 @@ + _io_BytesIO_tell_impl(bytesio *self); + + static PyObject * +-_io_BytesIO_tell(bytesio *self, PyObject *Py_UNUSED(ignored)) ++_io_BytesIO_tell(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _io_BytesIO_tell_impl(self); ++ return _io_BytesIO_tell_impl((bytesio *)self); + } + + PyDoc_STRVAR(_io_BytesIO_read__doc__, +@@ -175,7 +175,7 @@ + _io_BytesIO_read_impl(bytesio *self, Py_ssize_t size); + + static PyObject * +-_io_BytesIO_read(bytesio *self, PyObject *const *args, Py_ssize_t nargs) ++_io_BytesIO_read(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + Py_ssize_t size = -1; +@@ -190,7 +190,7 @@ + goto exit; + } + skip_optional: +- return_value = _io_BytesIO_read_impl(self, size); ++ return_value = _io_BytesIO_read_impl((bytesio *)self, size); + + exit: + return return_value; +@@ -212,7 +212,7 @@ + _io_BytesIO_read1_impl(bytesio *self, Py_ssize_t size); + + static PyObject * +-_io_BytesIO_read1(bytesio *self, PyObject *const *args, Py_ssize_t nargs) ++_io_BytesIO_read1(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + Py_ssize_t size = -1; +@@ -227,7 +227,7 @@ + goto exit; + } + skip_optional: +- return_value = _io_BytesIO_read1_impl(self, size); ++ return_value = _io_BytesIO_read1_impl((bytesio *)self, size); + + exit: + return return_value; +@@ -250,7 +250,7 @@ + _io_BytesIO_readline_impl(bytesio *self, Py_ssize_t size); + + static PyObject * +-_io_BytesIO_readline(bytesio *self, PyObject *const *args, Py_ssize_t nargs) ++_io_BytesIO_readline(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + Py_ssize_t size = -1; +@@ -265,7 +265,7 @@ + goto exit; + } + skip_optional: +- return_value = _io_BytesIO_readline_impl(self, size); ++ return_value = _io_BytesIO_readline_impl((bytesio *)self, size); + + exit: + return return_value; +@@ -288,7 +288,7 @@ + _io_BytesIO_readlines_impl(bytesio *self, PyObject *arg); + + static PyObject * +-_io_BytesIO_readlines(bytesio *self, PyObject *const *args, Py_ssize_t nargs) ++_io_BytesIO_readlines(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *arg = Py_None; +@@ -301,7 +301,7 @@ + } + arg = args[0]; + skip_optional: +- return_value = _io_BytesIO_readlines_impl(self, arg); ++ return_value = _io_BytesIO_readlines_impl((bytesio *)self, arg); + + exit: + return return_value; +@@ -323,7 +323,7 @@ + _io_BytesIO_readinto_impl(bytesio *self, Py_buffer *buffer); + + static PyObject * +-_io_BytesIO_readinto(bytesio *self, PyObject *arg) ++_io_BytesIO_readinto(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + Py_buffer buffer = {NULL, NULL}; +@@ -332,7 +332,7 @@ + _PyArg_BadArgument("readinto", "argument", "read-write bytes-like object", arg); + goto exit; + } +- return_value = _io_BytesIO_readinto_impl(self, &buffer); ++ return_value = _io_BytesIO_readinto_impl((bytesio *)self, &buffer); + + exit: + /* Cleanup for buffer */ +@@ -359,10 +359,10 @@ + _io_BytesIO_truncate_impl(bytesio *self, Py_ssize_t size); + + static PyObject * +-_io_BytesIO_truncate(bytesio *self, PyObject *const *args, Py_ssize_t nargs) ++_io_BytesIO_truncate(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; +- Py_ssize_t size = self->pos; ++ Py_ssize_t size = ((bytesio *)self)->pos; + + if (!_PyArg_CheckPositional("truncate", nargs, 0, 1)) { + goto exit; +@@ -374,7 +374,7 @@ + goto exit; + } + skip_optional: +- return_value = _io_BytesIO_truncate_impl(self, size); ++ return_value = _io_BytesIO_truncate_impl((bytesio *)self, size); + + exit: + return return_value; +@@ -399,7 +399,7 @@ + _io_BytesIO_seek_impl(bytesio *self, Py_ssize_t pos, int whence); + + static PyObject * +-_io_BytesIO_seek(bytesio *self, PyObject *const *args, Py_ssize_t nargs) ++_io_BytesIO_seek(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + Py_ssize_t pos; +@@ -428,7 +428,7 @@ + goto exit; + } + skip_optional: +- return_value = _io_BytesIO_seek_impl(self, pos, whence); ++ return_value = _io_BytesIO_seek_impl((bytesio *)self, pos, whence); + + exit: + return return_value; +@@ -471,9 +471,9 @@ + _io_BytesIO_close_impl(bytesio *self); + + static PyObject * +-_io_BytesIO_close(bytesio *self, PyObject *Py_UNUSED(ignored)) ++_io_BytesIO_close(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _io_BytesIO_close_impl(self); ++ return _io_BytesIO_close_impl((bytesio *)self); + } + + PyDoc_STRVAR(_io_BytesIO___init____doc__, +@@ -535,4 +535,4 @@ + exit: + return return_value; + } +-/*[clinic end generated code: output=985ff54e89f6036e input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=8a5e153bc7584b55 input=a9049054013a1b77]*/ +diff --git a/Modules/_io/clinic/fileio.c.h b/Modules/_io/clinic/fileio.c.h +index 0b8b4a49ac2..22d27bce677 100644 +--- a/Modules/_io/clinic/fileio.c.h ++++ b/Modules/_io/clinic/fileio.c.h +@@ -25,13 +25,13 @@ + _io_FileIO_close_impl(fileio *self, PyTypeObject *cls); + + static PyObject * +-_io_FileIO_close(fileio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_io_FileIO_close(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "close() takes no arguments"); + return NULL; + } +- return _io_FileIO_close_impl(self, cls); ++ return _io_FileIO_close_impl((fileio *)self, cls); + } + + PyDoc_STRVAR(_io_FileIO___init____doc__, +@@ -151,9 +151,9 @@ + _io_FileIO_fileno_impl(fileio *self); + + static PyObject * +-_io_FileIO_fileno(fileio *self, PyObject *Py_UNUSED(ignored)) ++_io_FileIO_fileno(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _io_FileIO_fileno_impl(self); ++ return _io_FileIO_fileno_impl((fileio *)self); + } + + PyDoc_STRVAR(_io_FileIO_readable__doc__, +@@ -169,9 +169,9 @@ + _io_FileIO_readable_impl(fileio *self); + + static PyObject * +-_io_FileIO_readable(fileio *self, PyObject *Py_UNUSED(ignored)) ++_io_FileIO_readable(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _io_FileIO_readable_impl(self); ++ return _io_FileIO_readable_impl((fileio *)self); + } + + PyDoc_STRVAR(_io_FileIO_writable__doc__, +@@ -187,9 +187,9 @@ + _io_FileIO_writable_impl(fileio *self); + + static PyObject * +-_io_FileIO_writable(fileio *self, PyObject *Py_UNUSED(ignored)) ++_io_FileIO_writable(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _io_FileIO_writable_impl(self); ++ return _io_FileIO_writable_impl((fileio *)self); + } + + PyDoc_STRVAR(_io_FileIO_seekable__doc__, +@@ -205,9 +205,9 @@ + _io_FileIO_seekable_impl(fileio *self); + + static PyObject * +-_io_FileIO_seekable(fileio *self, PyObject *Py_UNUSED(ignored)) ++_io_FileIO_seekable(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _io_FileIO_seekable_impl(self); ++ return _io_FileIO_seekable_impl((fileio *)self); + } + + PyDoc_STRVAR(_io_FileIO_readinto__doc__, +@@ -223,7 +223,7 @@ + _io_FileIO_readinto_impl(fileio *self, PyTypeObject *cls, Py_buffer *buffer); + + static PyObject * +-_io_FileIO_readinto(fileio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_io_FileIO_readinto(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -251,7 +251,7 @@ + _PyArg_BadArgument("readinto", "argument 1", "read-write bytes-like object", args[0]); + goto exit; + } +- return_value = _io_FileIO_readinto_impl(self, cls, &buffer); ++ return_value = _io_FileIO_readinto_impl((fileio *)self, cls, &buffer); + + exit: + /* Cleanup for buffer */ +@@ -278,9 +278,9 @@ + _io_FileIO_readall_impl(fileio *self); + + static PyObject * +-_io_FileIO_readall(fileio *self, PyObject *Py_UNUSED(ignored)) ++_io_FileIO_readall(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _io_FileIO_readall_impl(self); ++ return _io_FileIO_readall_impl((fileio *)self); + } + + PyDoc_STRVAR(_io_FileIO_read__doc__, +@@ -300,7 +300,7 @@ + _io_FileIO_read_impl(fileio *self, PyTypeObject *cls, Py_ssize_t size); + + static PyObject * +-_io_FileIO_read(fileio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_io_FileIO_read(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -331,7 +331,7 @@ + goto exit; + } + skip_optional_posonly: +- return_value = _io_FileIO_read_impl(self, cls, size); ++ return_value = _io_FileIO_read_impl((fileio *)self, cls, size); + + exit: + return return_value; +@@ -354,7 +354,7 @@ + _io_FileIO_write_impl(fileio *self, PyTypeObject *cls, Py_buffer *b); + + static PyObject * +-_io_FileIO_write(fileio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_io_FileIO_write(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -381,7 +381,7 @@ + if (PyObject_GetBuffer(args[0], &b, PyBUF_SIMPLE) != 0) { + goto exit; + } +- return_value = _io_FileIO_write_impl(self, cls, &b); ++ return_value = _io_FileIO_write_impl((fileio *)self, cls, &b); + + exit: + /* Cleanup for b */ +@@ -413,7 +413,7 @@ + _io_FileIO_seek_impl(fileio *self, PyObject *pos, int whence); + + static PyObject * +-_io_FileIO_seek(fileio *self, PyObject *const *args, Py_ssize_t nargs) ++_io_FileIO_seek(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *pos; +@@ -431,7 +431,7 @@ + goto exit; + } + skip_optional: +- return_value = _io_FileIO_seek_impl(self, pos, whence); ++ return_value = _io_FileIO_seek_impl((fileio *)self, pos, whence); + + exit: + return return_value; +@@ -452,9 +452,9 @@ + _io_FileIO_tell_impl(fileio *self); + + static PyObject * +-_io_FileIO_tell(fileio *self, PyObject *Py_UNUSED(ignored)) ++_io_FileIO_tell(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _io_FileIO_tell_impl(self); ++ return _io_FileIO_tell_impl((fileio *)self); + } + + #if defined(HAVE_FTRUNCATE) +@@ -475,7 +475,7 @@ + _io_FileIO_truncate_impl(fileio *self, PyTypeObject *cls, PyObject *posobj); + + static PyObject * +-_io_FileIO_truncate(fileio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_io_FileIO_truncate(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -504,7 +504,7 @@ + } + posobj = args[0]; + skip_optional_posonly: +- return_value = _io_FileIO_truncate_impl(self, cls, posobj); ++ return_value = _io_FileIO_truncate_impl((fileio *)self, cls, posobj); + + exit: + return return_value; +@@ -525,12 +525,12 @@ + _io_FileIO_isatty_impl(fileio *self); + + static PyObject * +-_io_FileIO_isatty(fileio *self, PyObject *Py_UNUSED(ignored)) ++_io_FileIO_isatty(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _io_FileIO_isatty_impl(self); ++ return _io_FileIO_isatty_impl((fileio *)self); + } + + #ifndef _IO_FILEIO_TRUNCATE_METHODDEF + #define _IO_FILEIO_TRUNCATE_METHODDEF + #endif /* !defined(_IO_FILEIO_TRUNCATE_METHODDEF) */ +-/*[clinic end generated code: output=1c262ae135da4dcb input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=dcbeb6a0b13e4b1f input=a9049054013a1b77]*/ +diff --git a/Modules/_io/clinic/stringio.c.h b/Modules/_io/clinic/stringio.c.h +index 6f9205af32f..bc571698806 100644 +--- a/Modules/_io/clinic/stringio.c.h ++++ b/Modules/_io/clinic/stringio.c.h +@@ -23,12 +23,12 @@ + _io_StringIO_getvalue_impl(stringio *self); + + static PyObject * +-_io_StringIO_getvalue(stringio *self, PyObject *Py_UNUSED(ignored)) ++_io_StringIO_getvalue(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_StringIO_getvalue_impl(self); ++ return_value = _io_StringIO_getvalue_impl((stringio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -47,12 +47,12 @@ + _io_StringIO_tell_impl(stringio *self); + + static PyObject * +-_io_StringIO_tell(stringio *self, PyObject *Py_UNUSED(ignored)) ++_io_StringIO_tell(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_StringIO_tell_impl(self); ++ return_value = _io_StringIO_tell_impl((stringio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -74,7 +74,7 @@ + _io_StringIO_read_impl(stringio *self, Py_ssize_t size); + + static PyObject * +-_io_StringIO_read(stringio *self, PyObject *const *args, Py_ssize_t nargs) ++_io_StringIO_read(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + Py_ssize_t size = -1; +@@ -90,7 +90,7 @@ + } + skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_StringIO_read_impl(self, size); ++ return_value = _io_StringIO_read_impl((stringio *)self, size); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -112,7 +112,7 @@ + _io_StringIO_readline_impl(stringio *self, Py_ssize_t size); + + static PyObject * +-_io_StringIO_readline(stringio *self, PyObject *const *args, Py_ssize_t nargs) ++_io_StringIO_readline(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + Py_ssize_t size = -1; +@@ -128,7 +128,7 @@ + } + skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_StringIO_readline_impl(self, size); ++ return_value = _io_StringIO_readline_impl((stringio *)self, size); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -152,10 +152,10 @@ + _io_StringIO_truncate_impl(stringio *self, Py_ssize_t size); + + static PyObject * +-_io_StringIO_truncate(stringio *self, PyObject *const *args, Py_ssize_t nargs) ++_io_StringIO_truncate(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; +- Py_ssize_t size = self->pos; ++ Py_ssize_t size = ((stringio *)self)->pos; + + if (!_PyArg_CheckPositional("truncate", nargs, 0, 1)) { + goto exit; +@@ -168,7 +168,7 @@ + } + skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_StringIO_truncate_impl(self, size); ++ return_value = _io_StringIO_truncate_impl((stringio *)self, size); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -194,7 +194,7 @@ + _io_StringIO_seek_impl(stringio *self, Py_ssize_t pos, int whence); + + static PyObject * +-_io_StringIO_seek(stringio *self, PyObject *const *args, Py_ssize_t nargs) ++_io_StringIO_seek(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + Py_ssize_t pos; +@@ -224,7 +224,7 @@ + } + skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_StringIO_seek_impl(self, pos, whence); ++ return_value = _io_StringIO_seek_impl((stringio *)self, pos, whence); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -252,7 +252,7 @@ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_StringIO_write_impl(self, obj); ++ return_value = _io_StringIO_write_impl((stringio *)self, obj); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -276,12 +276,12 @@ + _io_StringIO_close_impl(stringio *self); + + static PyObject * +-_io_StringIO_close(stringio *self, PyObject *Py_UNUSED(ignored)) ++_io_StringIO_close(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_StringIO_close_impl(self); ++ return_value = _io_StringIO_close_impl((stringio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -371,12 +371,12 @@ + _io_StringIO_readable_impl(stringio *self); + + static PyObject * +-_io_StringIO_readable(stringio *self, PyObject *Py_UNUSED(ignored)) ++_io_StringIO_readable(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_StringIO_readable_impl(self); ++ return_value = _io_StringIO_readable_impl((stringio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -395,12 +395,12 @@ + _io_StringIO_writable_impl(stringio *self); + + static PyObject * +-_io_StringIO_writable(stringio *self, PyObject *Py_UNUSED(ignored)) ++_io_StringIO_writable(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_StringIO_writable_impl(self); ++ return_value = _io_StringIO_writable_impl((stringio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -419,12 +419,12 @@ + _io_StringIO_seekable_impl(stringio *self); + + static PyObject * +-_io_StringIO_seekable(stringio *self, PyObject *Py_UNUSED(ignored)) ++_io_StringIO_seekable(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_StringIO_seekable_impl(self); ++ return_value = _io_StringIO_seekable_impl((stringio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -442,12 +442,12 @@ + _io_StringIO___getstate___impl(stringio *self); + + static PyObject * +-_io_StringIO___getstate__(stringio *self, PyObject *Py_UNUSED(ignored)) ++_io_StringIO___getstate__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_StringIO___getstate___impl(self); ++ return_value = _io_StringIO___getstate___impl((stringio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -470,7 +470,7 @@ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_StringIO___setstate___impl(self, state); ++ return_value = _io_StringIO___setstate___impl((stringio *)self, state); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -490,12 +490,12 @@ + _io_StringIO_closed_get_impl(stringio *self); + + static PyObject * +-_io_StringIO_closed_get(stringio *self, void *Py_UNUSED(context)) ++_io_StringIO_closed_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_StringIO_closed_get_impl(self); ++ return_value = _io_StringIO_closed_get_impl((stringio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -515,12 +515,12 @@ + _io_StringIO_line_buffering_get_impl(stringio *self); + + static PyObject * +-_io_StringIO_line_buffering_get(stringio *self, void *Py_UNUSED(context)) ++_io_StringIO_line_buffering_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_StringIO_line_buffering_get_impl(self); ++ return_value = _io_StringIO_line_buffering_get_impl((stringio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -540,14 +540,14 @@ + _io_StringIO_newlines_get_impl(stringio *self); + + static PyObject * +-_io_StringIO_newlines_get(stringio *self, void *Py_UNUSED(context)) ++_io_StringIO_newlines_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_StringIO_newlines_get_impl(self); ++ return_value = _io_StringIO_newlines_get_impl((stringio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; + } +-/*[clinic end generated code: output=9d2b092274469d42 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=7796e223e778a214 input=a9049054013a1b77]*/ +diff --git a/Modules/_io/clinic/textio.c.h b/Modules/_io/clinic/textio.c.h +index 160f80ada43..9ce1d70ad71 100644 +--- a/Modules/_io/clinic/textio.c.h ++++ b/Modules/_io/clinic/textio.c.h +@@ -208,6 +208,9 @@ + "Encoding of the text stream.\n" + "\n" + "Subclasses should override."); ++#if defined(_io__TextIOBase_encoding_DOCSTR) ++# undef _io__TextIOBase_encoding_DOCSTR ++#endif + #define _io__TextIOBase_encoding_DOCSTR _io__TextIOBase_encoding__doc__ + + #if !defined(_io__TextIOBase_encoding_DOCSTR) +@@ -235,6 +238,9 @@ + "Only line endings translated during reading are considered.\n" + "\n" + "Subclasses should override."); ++#if defined(_io__TextIOBase_newlines_DOCSTR) ++# undef _io__TextIOBase_newlines_DOCSTR ++#endif + #define _io__TextIOBase_newlines_DOCSTR _io__TextIOBase_newlines__doc__ + + #if !defined(_io__TextIOBase_newlines_DOCSTR) +@@ -260,6 +266,9 @@ + "The error setting of the decoder or encoder.\n" + "\n" + "Subclasses should override."); ++#if defined(_io__TextIOBase_errors_DOCSTR) ++# undef _io__TextIOBase_errors_DOCSTR ++#endif + #define _io__TextIOBase_errors_DOCSTR _io__TextIOBase_errors__doc__ + + #if !defined(_io__TextIOBase_errors_DOCSTR) +@@ -370,7 +379,7 @@ + PyObject *input, int final); + + static PyObject * +-_io_IncrementalNewlineDecoder_decode(nldecoder_object *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_io_IncrementalNewlineDecoder_decode(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -417,7 +426,7 @@ + goto exit; + } + skip_optional_pos: +- return_value = _io_IncrementalNewlineDecoder_decode_impl(self, input, final); ++ return_value = _io_IncrementalNewlineDecoder_decode_impl((nldecoder_object *)self, input, final); + + exit: + return return_value; +@@ -435,9 +444,9 @@ + _io_IncrementalNewlineDecoder_getstate_impl(nldecoder_object *self); + + static PyObject * +-_io_IncrementalNewlineDecoder_getstate(nldecoder_object *self, PyObject *Py_UNUSED(ignored)) ++_io_IncrementalNewlineDecoder_getstate(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _io_IncrementalNewlineDecoder_getstate_impl(self); ++ return _io_IncrementalNewlineDecoder_getstate_impl((nldecoder_object *)self); + } + + PyDoc_STRVAR(_io_IncrementalNewlineDecoder_setstate__doc__, +@@ -460,9 +469,9 @@ + _io_IncrementalNewlineDecoder_reset_impl(nldecoder_object *self); + + static PyObject * +-_io_IncrementalNewlineDecoder_reset(nldecoder_object *self, PyObject *Py_UNUSED(ignored)) ++_io_IncrementalNewlineDecoder_reset(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _io_IncrementalNewlineDecoder_reset_impl(self); ++ return _io_IncrementalNewlineDecoder_reset_impl((nldecoder_object *)self); + } + + PyDoc_STRVAR(_io_TextIOWrapper___init____doc__, +@@ -645,7 +654,7 @@ + PyObject *write_through_obj); + + static PyObject * +-_io_TextIOWrapper_reconfigure(textio *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_io_TextIOWrapper_reconfigure(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -716,7 +725,7 @@ + write_through_obj = args[4]; + skip_optional_kwonly: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_TextIOWrapper_reconfigure_impl(self, encoding, errors, newline_obj, line_buffering_obj, write_through_obj); ++ return_value = _io_TextIOWrapper_reconfigure_impl((textio *)self, encoding, errors, newline_obj, line_buffering_obj, write_through_obj); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -735,12 +744,12 @@ + _io_TextIOWrapper_detach_impl(textio *self); + + static PyObject * +-_io_TextIOWrapper_detach(textio *self, PyObject *Py_UNUSED(ignored)) ++_io_TextIOWrapper_detach(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_TextIOWrapper_detach_impl(self); ++ return_value = _io_TextIOWrapper_detach_impl((textio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -758,7 +767,7 @@ + _io_TextIOWrapper_write_impl(textio *self, PyObject *text); + + static PyObject * +-_io_TextIOWrapper_write(textio *self, PyObject *arg) ++_io_TextIOWrapper_write(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + PyObject *text; +@@ -769,7 +778,7 @@ + } + text = arg; + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_TextIOWrapper_write_impl(self, text); ++ return_value = _io_TextIOWrapper_write_impl((textio *)self, text); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -788,7 +797,7 @@ + _io_TextIOWrapper_read_impl(textio *self, Py_ssize_t n); + + static PyObject * +-_io_TextIOWrapper_read(textio *self, PyObject *const *args, Py_ssize_t nargs) ++_io_TextIOWrapper_read(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + Py_ssize_t n = -1; +@@ -804,7 +813,7 @@ + } + skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_TextIOWrapper_read_impl(self, n); ++ return_value = _io_TextIOWrapper_read_impl((textio *)self, n); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -823,7 +832,7 @@ + _io_TextIOWrapper_readline_impl(textio *self, Py_ssize_t size); + + static PyObject * +-_io_TextIOWrapper_readline(textio *self, PyObject *const *args, Py_ssize_t nargs) ++_io_TextIOWrapper_readline(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + Py_ssize_t size = -1; +@@ -848,7 +857,7 @@ + } + skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_TextIOWrapper_readline_impl(self, size); ++ return_value = _io_TextIOWrapper_readline_impl((textio *)self, size); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -885,7 +894,7 @@ + _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence); + + static PyObject * +-_io_TextIOWrapper_seek(textio *self, PyObject *const *args, Py_ssize_t nargs) ++_io_TextIOWrapper_seek(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *cookieObj; +@@ -904,7 +913,7 @@ + } + skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_TextIOWrapper_seek_impl(self, cookieObj, whence); ++ return_value = _io_TextIOWrapper_seek_impl((textio *)self, cookieObj, whence); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -927,12 +936,12 @@ + _io_TextIOWrapper_tell_impl(textio *self); + + static PyObject * +-_io_TextIOWrapper_tell(textio *self, PyObject *Py_UNUSED(ignored)) ++_io_TextIOWrapper_tell(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_TextIOWrapper_tell_impl(self); ++ return_value = _io_TextIOWrapper_tell_impl((textio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -950,7 +959,7 @@ + _io_TextIOWrapper_truncate_impl(textio *self, PyObject *pos); + + static PyObject * +-_io_TextIOWrapper_truncate(textio *self, PyObject *const *args, Py_ssize_t nargs) ++_io_TextIOWrapper_truncate(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *pos = Py_None; +@@ -964,7 +973,7 @@ + pos = args[0]; + skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_TextIOWrapper_truncate_impl(self, pos); ++ return_value = _io_TextIOWrapper_truncate_impl((textio *)self, pos); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -983,12 +992,12 @@ + _io_TextIOWrapper_fileno_impl(textio *self); + + static PyObject * +-_io_TextIOWrapper_fileno(textio *self, PyObject *Py_UNUSED(ignored)) ++_io_TextIOWrapper_fileno(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_TextIOWrapper_fileno_impl(self); ++ return_value = _io_TextIOWrapper_fileno_impl((textio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1006,12 +1015,12 @@ + _io_TextIOWrapper_seekable_impl(textio *self); + + static PyObject * +-_io_TextIOWrapper_seekable(textio *self, PyObject *Py_UNUSED(ignored)) ++_io_TextIOWrapper_seekable(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_TextIOWrapper_seekable_impl(self); ++ return_value = _io_TextIOWrapper_seekable_impl((textio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1029,12 +1038,12 @@ + _io_TextIOWrapper_readable_impl(textio *self); + + static PyObject * +-_io_TextIOWrapper_readable(textio *self, PyObject *Py_UNUSED(ignored)) ++_io_TextIOWrapper_readable(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_TextIOWrapper_readable_impl(self); ++ return_value = _io_TextIOWrapper_readable_impl((textio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1052,12 +1061,12 @@ + _io_TextIOWrapper_writable_impl(textio *self); + + static PyObject * +-_io_TextIOWrapper_writable(textio *self, PyObject *Py_UNUSED(ignored)) ++_io_TextIOWrapper_writable(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_TextIOWrapper_writable_impl(self); ++ return_value = _io_TextIOWrapper_writable_impl((textio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1075,12 +1084,12 @@ + _io_TextIOWrapper_isatty_impl(textio *self); + + static PyObject * +-_io_TextIOWrapper_isatty(textio *self, PyObject *Py_UNUSED(ignored)) ++_io_TextIOWrapper_isatty(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_TextIOWrapper_isatty_impl(self); ++ return_value = _io_TextIOWrapper_isatty_impl((textio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1098,12 +1107,12 @@ + _io_TextIOWrapper_flush_impl(textio *self); + + static PyObject * +-_io_TextIOWrapper_flush(textio *self, PyObject *Py_UNUSED(ignored)) ++_io_TextIOWrapper_flush(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_TextIOWrapper_flush_impl(self); ++ return_value = _io_TextIOWrapper_flush_impl((textio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1121,12 +1130,12 @@ + _io_TextIOWrapper_close_impl(textio *self); + + static PyObject * +-_io_TextIOWrapper_close(textio *self, PyObject *Py_UNUSED(ignored)) ++_io_TextIOWrapper_close(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_TextIOWrapper_close_impl(self); ++ return_value = _io_TextIOWrapper_close_impl((textio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1146,12 +1155,12 @@ + _io_TextIOWrapper_name_get_impl(textio *self); + + static PyObject * +-_io_TextIOWrapper_name_get(textio *self, void *Py_UNUSED(context)) ++_io_TextIOWrapper_name_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_TextIOWrapper_name_get_impl(self); ++ return_value = _io_TextIOWrapper_name_get_impl((textio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1171,12 +1180,12 @@ + _io_TextIOWrapper_closed_get_impl(textio *self); + + static PyObject * +-_io_TextIOWrapper_closed_get(textio *self, void *Py_UNUSED(context)) ++_io_TextIOWrapper_closed_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_TextIOWrapper_closed_get_impl(self); ++ return_value = _io_TextIOWrapper_closed_get_impl((textio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1196,12 +1205,12 @@ + _io_TextIOWrapper_newlines_get_impl(textio *self); + + static PyObject * +-_io_TextIOWrapper_newlines_get(textio *self, void *Py_UNUSED(context)) ++_io_TextIOWrapper_newlines_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_TextIOWrapper_newlines_get_impl(self); ++ return_value = _io_TextIOWrapper_newlines_get_impl((textio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1221,12 +1230,12 @@ + _io_TextIOWrapper_errors_get_impl(textio *self); + + static PyObject * +-_io_TextIOWrapper_errors_get(textio *self, void *Py_UNUSED(context)) ++_io_TextIOWrapper_errors_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_TextIOWrapper_errors_get_impl(self); ++ return_value = _io_TextIOWrapper_errors_get_impl((textio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1246,12 +1255,12 @@ + _io_TextIOWrapper__CHUNK_SIZE_get_impl(textio *self); + + static PyObject * +-_io_TextIOWrapper__CHUNK_SIZE_get(textio *self, void *Py_UNUSED(context)) ++_io_TextIOWrapper__CHUNK_SIZE_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_TextIOWrapper__CHUNK_SIZE_get_impl(self); ++ return_value = _io_TextIOWrapper__CHUNK_SIZE_get_impl((textio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1271,14 +1280,14 @@ + _io_TextIOWrapper__CHUNK_SIZE_set_impl(textio *self, PyObject *value); + + static int +-_io_TextIOWrapper__CHUNK_SIZE_set(textio *self, PyObject *value, void *Py_UNUSED(context)) ++_io_TextIOWrapper__CHUNK_SIZE_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) + { + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _io_TextIOWrapper__CHUNK_SIZE_set_impl(self, value); ++ return_value = _io_TextIOWrapper__CHUNK_SIZE_set_impl((textio *)self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; + } +-/*[clinic end generated code: output=1172c500a022c65d input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=6e64e43113a97340 input=a9049054013a1b77]*/ +diff --git a/Modules/_io/clinic/winconsoleio.c.h b/Modules/_io/clinic/winconsoleio.c.h +index df281dfeb13..ba6dcde6e01 100644 +--- a/Modules/_io/clinic/winconsoleio.c.h ++++ b/Modules/_io/clinic/winconsoleio.c.h +@@ -27,13 +27,13 @@ + _io__WindowsConsoleIO_close_impl(winconsoleio *self, PyTypeObject *cls); + + static PyObject * +-_io__WindowsConsoleIO_close(winconsoleio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_io__WindowsConsoleIO_close(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "close() takes no arguments"); + return NULL; + } +- return _io__WindowsConsoleIO_close_impl(self, cls); ++ return _io__WindowsConsoleIO_close_impl((winconsoleio *)self, cls); + } + + #endif /* defined(HAVE_WINDOWS_CONSOLE_IO) */ +@@ -154,9 +154,9 @@ + _io__WindowsConsoleIO_fileno_impl(winconsoleio *self); + + static PyObject * +-_io__WindowsConsoleIO_fileno(winconsoleio *self, PyObject *Py_UNUSED(ignored)) ++_io__WindowsConsoleIO_fileno(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _io__WindowsConsoleIO_fileno_impl(self); ++ return _io__WindowsConsoleIO_fileno_impl((winconsoleio *)self); + } + + #endif /* defined(HAVE_WINDOWS_CONSOLE_IO) */ +@@ -176,9 +176,9 @@ + _io__WindowsConsoleIO_readable_impl(winconsoleio *self); + + static PyObject * +-_io__WindowsConsoleIO_readable(winconsoleio *self, PyObject *Py_UNUSED(ignored)) ++_io__WindowsConsoleIO_readable(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _io__WindowsConsoleIO_readable_impl(self); ++ return _io__WindowsConsoleIO_readable_impl((winconsoleio *)self); + } + + #endif /* defined(HAVE_WINDOWS_CONSOLE_IO) */ +@@ -198,9 +198,9 @@ + _io__WindowsConsoleIO_writable_impl(winconsoleio *self); + + static PyObject * +-_io__WindowsConsoleIO_writable(winconsoleio *self, PyObject *Py_UNUSED(ignored)) ++_io__WindowsConsoleIO_writable(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _io__WindowsConsoleIO_writable_impl(self); ++ return _io__WindowsConsoleIO_writable_impl((winconsoleio *)self); + } + + #endif /* defined(HAVE_WINDOWS_CONSOLE_IO) */ +@@ -221,7 +221,7 @@ + Py_buffer *buffer); + + static PyObject * +-_io__WindowsConsoleIO_readinto(winconsoleio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_io__WindowsConsoleIO_readinto(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -249,7 +249,7 @@ + _PyArg_BadArgument("readinto", "argument 1", "read-write bytes-like object", args[0]); + goto exit; + } +- return_value = _io__WindowsConsoleIO_readinto_impl(self, cls, &buffer); ++ return_value = _io__WindowsConsoleIO_readinto_impl((winconsoleio *)self, cls, &buffer); + + exit: + /* Cleanup for buffer */ +@@ -279,9 +279,9 @@ + _io__WindowsConsoleIO_readall_impl(winconsoleio *self); + + static PyObject * +-_io__WindowsConsoleIO_readall(winconsoleio *self, PyObject *Py_UNUSED(ignored)) ++_io__WindowsConsoleIO_readall(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _io__WindowsConsoleIO_readall_impl(self); ++ return _io__WindowsConsoleIO_readall_impl((winconsoleio *)self); + } + + #endif /* defined(HAVE_WINDOWS_CONSOLE_IO) */ +@@ -306,7 +306,7 @@ + Py_ssize_t size); + + static PyObject * +-_io__WindowsConsoleIO_read(winconsoleio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_io__WindowsConsoleIO_read(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -337,7 +337,7 @@ + goto exit; + } + skip_optional_posonly: +- return_value = _io__WindowsConsoleIO_read_impl(self, cls, size); ++ return_value = _io__WindowsConsoleIO_read_impl((winconsoleio *)self, cls, size); + + exit: + return return_value; +@@ -364,7 +364,7 @@ + Py_buffer *b); + + static PyObject * +-_io__WindowsConsoleIO_write(winconsoleio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_io__WindowsConsoleIO_write(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -391,7 +391,7 @@ + if (PyObject_GetBuffer(args[0], &b, PyBUF_SIMPLE) != 0) { + goto exit; + } +- return_value = _io__WindowsConsoleIO_write_impl(self, cls, &b); ++ return_value = _io__WindowsConsoleIO_write_impl((winconsoleio *)self, cls, &b); + + exit: + /* Cleanup for b */ +@@ -419,9 +419,9 @@ + _io__WindowsConsoleIO_isatty_impl(winconsoleio *self); + + static PyObject * +-_io__WindowsConsoleIO_isatty(winconsoleio *self, PyObject *Py_UNUSED(ignored)) ++_io__WindowsConsoleIO_isatty(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _io__WindowsConsoleIO_isatty_impl(self); ++ return _io__WindowsConsoleIO_isatty_impl((winconsoleio *)self); + } + + #endif /* defined(HAVE_WINDOWS_CONSOLE_IO) */ +@@ -461,4 +461,4 @@ + #ifndef _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF + #define _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF + #endif /* !defined(_IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF) */ +-/*[clinic end generated code: output=78e0f6abf4de2d6d input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=edc47f5c49589045 input=a9049054013a1b77]*/ +diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c +index cf0f1d671b5..89f1cfe6b20 100644 +--- a/Modules/_io/fileio.c ++++ b/Modules/_io/fileio.c +@@ -83,7 +83,7 @@ + } fileio; + + #define PyFileIO_Check(state, op) (PyObject_TypeCheck((op), state->PyFileIO_Type)) +-#define _PyFileIO_CAST(op) _Py_CAST(fileio*, (op)) ++#define PyFileIO_CAST(op) ((fileio *)(op)) + + /* Forward declarations */ + static PyObject* portable_lseek(fileio *self, PyObject *posobj, int whence, bool suppress_pipe_error); +@@ -91,7 +91,7 @@ + int + _PyFileIO_closed(PyObject *self) + { +- return (_PyFileIO_CAST(self)->fd < 0); ++ return (PyFileIO_CAST(self)->fd < 0); + } + + /* Because this can call arbitrary code, it shouldn't be called when +@@ -100,13 +100,15 @@ + static PyObject * + fileio_dealloc_warn(PyObject *op, PyObject *source) + { +- fileio *self = _PyFileIO_CAST(op); ++ fileio *self = PyFileIO_CAST(op); + if (self->fd >= 0 && self->closefd) { + PyObject *exc = PyErr_GetRaisedException(); + if (PyErr_ResourceWarning(source, 1, "unclosed file %R", source)) { + /* Spurious errors can appear at shutdown */ +- if (PyErr_ExceptionMatches(PyExc_Warning)) +- PyErr_WriteUnraisable((PyObject *) self); ++ if (PyErr_ExceptionMatches(PyExc_Warning)) { ++ PyErr_FormatUnraisable("Exception ignored " ++ "while finalizing file %R", self); ++ } + } + PyErr_SetRaisedException(exc); + } +@@ -540,7 +542,7 @@ + static int + fileio_traverse(PyObject *op, visitproc visit, void *arg) + { +- fileio *self = _PyFileIO_CAST(op); ++ fileio *self = PyFileIO_CAST(op); + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->dict); + return 0; +@@ -549,7 +551,7 @@ + static int + fileio_clear(PyObject *op) + { +- fileio *self = _PyFileIO_CAST(op); ++ fileio *self = PyFileIO_CAST(op); + Py_CLEAR(self->dict); + return 0; + } +@@ -557,7 +559,7 @@ + static void + fileio_dealloc(PyObject *op) + { +- fileio *self = _PyFileIO_CAST(op); ++ fileio *self = PyFileIO_CAST(op); + self->finalizing = 1; + if (_PyIOBase_finalize(op) < 0) { + return; +@@ -1159,7 +1161,7 @@ + static PyObject * + fileio_repr(PyObject *op) + { +- fileio *self = _PyFileIO_CAST(op); ++ fileio *self = PyFileIO_CAST(op); + const char *type_name = Py_TYPE(self)->tp_name; + + if (self->fd < 0) { +@@ -1225,9 +1227,9 @@ + context TOCTOU issues (the fd could be arbitrarily modified by + surrounding code). */ + static PyObject * +-_io_FileIO_isatty_open_only(PyObject *op, PyObject *Py_UNUSED(ignored)) ++_io_FileIO_isatty_open_only(PyObject *op, PyObject *Py_UNUSED(dummy)) + { +- fileio *self = _PyFileIO_CAST(op); ++ fileio *self = PyFileIO_CAST(op); + if (self->stat_atopen != NULL && !S_ISCHR(self->stat_atopen->st_mode)) { + Py_RETURN_FALSE; + } +@@ -1262,28 +1264,28 @@ + static PyObject * + fileio_get_closed(PyObject *op, void *closure) + { +- fileio *self = _PyFileIO_CAST(op); ++ fileio *self = PyFileIO_CAST(op); + return PyBool_FromLong((long)(self->fd < 0)); + } + + static PyObject * + fileio_get_closefd(PyObject *op, void *closure) + { +- fileio *self = _PyFileIO_CAST(op); ++ fileio *self = PyFileIO_CAST(op); + return PyBool_FromLong((long)(self->closefd)); + } + + static PyObject * + fileio_get_mode(PyObject *op, void *closure) + { +- fileio *self = _PyFileIO_CAST(op); ++ fileio *self = PyFileIO_CAST(op); + return PyUnicode_FromString(mode_string(self)); + } + + static PyObject * + fileio_get_blksize(PyObject *op, void *closure) + { +- fileio *self = _PyFileIO_CAST(op); ++ fileio *self = PyFileIO_CAST(op); + #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + if (self->stat_atopen != NULL && self->stat_atopen->st_blksize > 1) { + return PyLong_FromLong(self->stat_atopen->st_blksize); +diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c +index 419e5516b5c..7e0822e3350 100644 +--- a/Modules/_io/iobase.c ++++ b/Modules/_io/iobase.c +@@ -35,6 +35,8 @@ + PyObject *weakreflist; + } iobase; + ++#define iobase_CAST(op) ((iobase *)(op)) ++ + PyDoc_STRVAR(iobase_doc, + "The abstract base class for all I/O classes.\n" + "\n" +@@ -314,7 +316,8 @@ + PyErr_Clear(); + res = PyObject_CallMethodNoArgs((PyObject *)self, &_Py_ID(close)); + if (res == NULL) { +- PyErr_WriteUnraisable(self); ++ PyErr_FormatUnraisable("Exception ignored " ++ "while finalizing file %R", self); + } + else { + Py_DECREF(res); +@@ -342,16 +345,18 @@ + } + + static int +-iobase_traverse(iobase *self, visitproc visit, void *arg) ++iobase_traverse(PyObject *op, visitproc visit, void *arg) + { ++ iobase *self = iobase_CAST(op); + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->dict); + return 0; + } + + static int +-iobase_clear(iobase *self) ++iobase_clear(PyObject *op) + { ++ iobase *self = iobase_CAST(op); + Py_CLEAR(self->dict); + return 0; + } +@@ -359,14 +364,15 @@ + /* Destructor */ + + static void +-iobase_dealloc(iobase *self) ++iobase_dealloc(PyObject *op) + { + /* NOTE: since IOBaseObject has its own dict, Python-defined attributes + are still available here for close() to use. + However, if the derived class declares a __slots__, those slots are + already gone. + */ +- if (_PyIOBase_finalize((PyObject *) self) < 0) { ++ iobase *self = iobase_CAST(op); ++ if (_PyIOBase_finalize(op) < 0) { + /* When called from a heap type's dealloc, the type will be + decref'ed on return (see e.g. subtype_dealloc in typeobject.c). */ + if (_PyType_HasFeature(Py_TYPE(self), Py_TPFLAGS_HEAPTYPE)) { +@@ -377,9 +383,9 @@ + PyTypeObject *tp = Py_TYPE(self); + _PyObject_GC_UNTRACK(self); + if (self->weakreflist != NULL) +- PyObject_ClearWeakRefs((PyObject *) self); ++ PyObject_ClearWeakRefs(op); + Py_CLEAR(self->dict); +- tp->tp_free((PyObject *)self); ++ tp->tp_free(self); + Py_DECREF(tp); + } + +@@ -852,7 +858,7 @@ + + static PyGetSetDef iobase_getset[] = { + {"__dict__", PyObject_GenericGetDict, NULL, NULL}, +- {"closed", (getter)iobase_closed_get, NULL, NULL}, ++ {"closed", iobase_closed_get, NULL, NULL}, + {NULL} + }; + +diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c +index 65e8d97aa8a..9d1bfa3ea05 100644 +--- a/Modules/_io/stringio.c ++++ b/Modules/_io/stringio.c +@@ -30,7 +30,7 @@ + _PyUnicodeWriter is destroyed. + */ + int state; +- _PyUnicodeWriter writer; ++ PyUnicodeWriter *writer; + + char ok; /* initialized? */ + char closed; +@@ -45,6 +45,8 @@ + _PyIO_State *module_state; + } stringio; + ++#define stringio_CAST(op) ((stringio *)(op)) ++ + #define clinic_state() (find_io_state_by_def(Py_TYPE(self))) + #include "clinic/stringio.c.h" + #undef clinic_state +@@ -129,14 +131,18 @@ + static PyObject * + make_intermediate(stringio *self) + { +- PyObject *intermediate = _PyUnicodeWriter_Finish(&self->writer); ++ PyObject *intermediate = PyUnicodeWriter_Finish(self->writer); ++ self->writer = NULL; + self->state = STATE_REALIZED; + if (intermediate == NULL) + return NULL; + +- _PyUnicodeWriter_Init(&self->writer); +- self->writer.overallocate = 1; +- if (_PyUnicodeWriter_WriteStr(&self->writer, intermediate)) { ++ self->writer = PyUnicodeWriter_Create(0); ++ if (self->writer == NULL) { ++ Py_DECREF(intermediate); ++ return NULL; ++ } ++ if (PyUnicodeWriter_WriteStr(self->writer, intermediate)) { + Py_DECREF(intermediate); + return NULL; + } +@@ -155,7 +161,8 @@ + assert(self->state == STATE_ACCUMULATING); + self->state = STATE_REALIZED; + +- intermediate = _PyUnicodeWriter_Finish(&self->writer); ++ intermediate = PyUnicodeWriter_Finish(self->writer); ++ self->writer = NULL; + if (intermediate == NULL) + return -1; + +@@ -217,7 +224,7 @@ + + if (self->state == STATE_ACCUMULATING) { + if (self->string_size == self->pos) { +- if (_PyUnicodeWriter_WriteStr(&self->writer, decoded)) ++ if (PyUnicodeWriter_WriteStr(self->writer, decoded)) + goto fail; + goto success; + } +@@ -397,9 +404,10 @@ + } + + static PyObject * +-stringio_iternext(stringio *self) ++stringio_iternext(PyObject *op) + { + PyObject *line; ++ stringio *self = stringio_CAST(op); + + CHECK_INITIALIZED(self); + CHECK_CLOSED(self); +@@ -411,8 +419,7 @@ + } + else { + /* XXX is subclassing StringIO really supported? */ +- line = PyObject_CallMethodNoArgs((PyObject *)self, +- &_Py_ID(readline)); ++ line = PyObject_CallMethodNoArgs(op, &_Py_ID(readline)); + if (line && !PyUnicode_Check(line)) { + PyErr_Format(PyExc_OSError, + "readline() should have returned a str object, " +@@ -437,7 +444,7 @@ + /*[clinic input] + @critical_section + _io.StringIO.truncate +- pos as size: Py_ssize_t(accept={int, NoneType}, c_default="self->pos") = None ++ pos as size: Py_ssize_t(accept={int, NoneType}, c_default="((stringio *)self)->pos") = None + / + + Truncate size to pos. +@@ -449,7 +456,7 @@ + + static PyObject * + _io_StringIO_truncate_impl(stringio *self, Py_ssize_t size) +-/*[clinic end generated code: output=eb3aef8e06701365 input=461b872dce238452]*/ ++/*[clinic end generated code: output=eb3aef8e06701365 input=fa8a6c98bb2ba780]*/ + { + CHECK_INITIALIZED(self); + CHECK_CLOSED(self); +@@ -577,7 +584,8 @@ + /* Free up some memory */ + if (resize_buffer(self, 0) < 0) + return NULL; +- _PyUnicodeWriter_Dealloc(&self->writer); ++ PyUnicodeWriter_Discard(self->writer); ++ self->writer = NULL; + Py_CLEAR(self->readnl); + Py_CLEAR(self->writenl); + Py_CLEAR(self->decoder); +@@ -585,8 +593,9 @@ + } + + static int +-stringio_traverse(stringio *self, visitproc visit, void *arg) ++stringio_traverse(PyObject *op, visitproc visit, void *arg) + { ++ stringio *self = stringio_CAST(op); + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->readnl); + Py_VISIT(self->writenl); +@@ -596,8 +605,9 @@ + } + + static int +-stringio_clear(stringio *self) ++stringio_clear(PyObject *op) + { ++ stringio *self = stringio_CAST(op); + Py_CLEAR(self->readnl); + Py_CLEAR(self->writenl); + Py_CLEAR(self->decoder); +@@ -606,8 +616,9 @@ + } + + static void +-stringio_dealloc(stringio *self) ++stringio_dealloc(PyObject *op) + { ++ stringio *self = stringio_CAST(op); + PyTypeObject *tp = Py_TYPE(self); + _PyObject_GC_UNTRACK(self); + self->ok = 0; +@@ -615,10 +626,10 @@ + PyMem_Free(self->buf); + self->buf = NULL; + } +- _PyUnicodeWriter_Dealloc(&self->writer); +- (void)stringio_clear(self); ++ PyUnicodeWriter_Discard(self->writer); ++ (void)stringio_clear(op); + if (self->weakreflist != NULL) { +- PyObject_ClearWeakRefs((PyObject *) self); ++ PyObject_ClearWeakRefs(op); + } + tp->tp_free(self); + Py_DECREF(tp); +@@ -699,7 +710,8 @@ + + self->ok = 0; + +- _PyUnicodeWriter_Dealloc(&self->writer); ++ PyUnicodeWriter_Discard(self->writer); ++ self->writer = NULL; + Py_CLEAR(self->readnl); + Py_CLEAR(self->writenl); + Py_CLEAR(self->decoder); +@@ -754,8 +766,10 @@ + /* Empty stringio object, we can start by accumulating */ + if (resize_buffer(self, 0) < 0) + return -1; +- _PyUnicodeWriter_Init(&self->writer); +- self->writer.overallocate = 1; ++ self->writer = PyUnicodeWriter_Create(0); ++ if (self->writer == NULL) { ++ return -1; ++ } + self->state = STATE_ACCUMULATING; + } + self->pos = 0; +diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c +index 791ee070401..935aaab20a0 100644 +--- a/Modules/_io/textio.c ++++ b/Modules/_io/textio.c +@@ -223,6 +223,8 @@ + unsigned int seennl: 3; + }; + ++#define nldecoder_object_CAST(op) ((nldecoder_object *)(op)) ++ + /*[clinic input] + _io.IncrementalNewlineDecoder.__init__ + decoder: object +@@ -263,9 +265,9 @@ + } + + static int +-incrementalnewlinedecoder_traverse(nldecoder_object *self, visitproc visit, +- void *arg) ++incrementalnewlinedecoder_traverse(PyObject *op, visitproc visit, void *arg) + { ++ nldecoder_object *self = nldecoder_object_CAST(op); + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->decoder); + Py_VISIT(self->errors); +@@ -273,20 +275,22 @@ + } + + static int +-incrementalnewlinedecoder_clear(nldecoder_object *self) ++incrementalnewlinedecoder_clear(PyObject *op) + { ++ nldecoder_object *self = nldecoder_object_CAST(op); + Py_CLEAR(self->decoder); + Py_CLEAR(self->errors); + return 0; + } + + static void +-incrementalnewlinedecoder_dealloc(nldecoder_object *self) ++incrementalnewlinedecoder_dealloc(PyObject *op) + { ++ nldecoder_object *self = nldecoder_object_CAST(op); + PyTypeObject *tp = Py_TYPE(self); + _PyObject_GC_UNTRACK(self); +- (void)incrementalnewlinedecoder_clear(self); +- tp->tp_free((PyObject *)self); ++ (void)incrementalnewlinedecoder_clear(op); ++ tp->tp_free(self); + Py_DECREF(tp); + } + +@@ -323,7 +327,7 @@ + { + PyObject *output; + Py_ssize_t output_len; +- nldecoder_object *self = (nldecoder_object *) myself; ++ nldecoder_object *self = nldecoder_object_CAST(myself); + + CHECK_INITIALIZED_DECODER(self); + +@@ -625,8 +629,9 @@ + } + + static PyObject * +-incrementalnewlinedecoder_newlines_get(nldecoder_object *self, void *context) ++incrementalnewlinedecoder_newlines_get(PyObject *op, void *Py_UNUSED(context)) + { ++ nldecoder_object *self = nldecoder_object_CAST(op); + CHECK_INITIALIZED_DECODER(self); + + switch (self->seennl) { +@@ -652,8 +657,7 @@ + + /* TextIOWrapper */ + +-typedef PyObject * +- (*encodefunc_t)(PyObject *, PyObject *); ++typedef PyObject *(*encodefunc_t)(PyObject *, PyObject *); + + struct textio + { +@@ -716,6 +720,8 @@ + _PyIO_State *state; + }; + ++#define textio_CAST(op) ((textio *)(op)) ++ + static void + textiowrapper_set_decoded_chars(textio *self, PyObject *chars); + +@@ -723,78 +729,81 @@ + encoding methods for the most popular encodings. */ + + static PyObject * +-ascii_encode(textio *self, PyObject *text) ++ascii_encode(PyObject *op, PyObject *text) + { ++ textio *self = textio_CAST(op); + return _PyUnicode_AsASCIIString(text, PyUnicode_AsUTF8(self->errors)); + } + + static PyObject * +-utf16be_encode(textio *self, PyObject *text) ++utf16be_encode(PyObject *op, PyObject *text) + { +- return _PyUnicode_EncodeUTF16(text, +- PyUnicode_AsUTF8(self->errors), 1); ++ textio *self = textio_CAST(op); ++ return _PyUnicode_EncodeUTF16(text, PyUnicode_AsUTF8(self->errors), 1); + } + + static PyObject * +-utf16le_encode(textio *self, PyObject *text) ++utf16le_encode(PyObject *op, PyObject *text) + { +- return _PyUnicode_EncodeUTF16(text, +- PyUnicode_AsUTF8(self->errors), -1); ++ textio *self = textio_CAST(op); ++ return _PyUnicode_EncodeUTF16(text, PyUnicode_AsUTF8(self->errors), -1); + } + + static PyObject * +-utf16_encode(textio *self, PyObject *text) ++utf16_encode(PyObject *op, PyObject *text) + { ++ textio *self = textio_CAST(op); + if (!self->encoding_start_of_stream) { + /* Skip the BOM and use native byte ordering */ + #if PY_BIG_ENDIAN +- return utf16be_encode(self, text); ++ return utf16be_encode(op, text); + #else +- return utf16le_encode(self, text); ++ return utf16le_encode(op, text); + #endif + } +- return _PyUnicode_EncodeUTF16(text, +- PyUnicode_AsUTF8(self->errors), 0); ++ return _PyUnicode_EncodeUTF16(text, PyUnicode_AsUTF8(self->errors), 0); + } + + static PyObject * +-utf32be_encode(textio *self, PyObject *text) ++utf32be_encode(PyObject *op, PyObject *text) + { +- return _PyUnicode_EncodeUTF32(text, +- PyUnicode_AsUTF8(self->errors), 1); ++ textio *self = textio_CAST(op); ++ return _PyUnicode_EncodeUTF32(text, PyUnicode_AsUTF8(self->errors), 1); + } + + static PyObject * +-utf32le_encode(textio *self, PyObject *text) ++utf32le_encode(PyObject *op, PyObject *text) + { +- return _PyUnicode_EncodeUTF32(text, +- PyUnicode_AsUTF8(self->errors), -1); ++ textio *self = textio_CAST(op); ++ return _PyUnicode_EncodeUTF32(text, PyUnicode_AsUTF8(self->errors), -1); + } + + static PyObject * +-utf32_encode(textio *self, PyObject *text) ++utf32_encode(PyObject *op, PyObject *text) + { ++ textio *self = textio_CAST(op); + if (!self->encoding_start_of_stream) { + /* Skip the BOM and use native byte ordering */ + #if PY_BIG_ENDIAN +- return utf32be_encode(self, text); ++ return utf32be_encode(op, text); + #else +- return utf32le_encode(self, text); ++ return utf32le_encode(op, text); + #endif + } +- return _PyUnicode_EncodeUTF32(text, +- PyUnicode_AsUTF8(self->errors), 0); ++ return _PyUnicode_EncodeUTF32(text, PyUnicode_AsUTF8(self->errors), 0); + } + + static PyObject * +-utf8_encode(textio *self, PyObject *text) ++utf8_encode(PyObject *op, PyObject *text) + { ++ textio *self = textio_CAST(op); + return _PyUnicode_AsUTF8String(text, PyUnicode_AsUTF8(self->errors)); + } + + static PyObject * +-latin1_encode(textio *self, PyObject *text) ++latin1_encode(PyObject *op, PyObject *text) + { ++ textio *self = textio_CAST(op); + return _PyUnicode_AsLatin1String(text, PyUnicode_AsUTF8(self->errors)); + } + +@@ -802,9 +811,7 @@ + static inline int + is_asciicompat_encoding(encodefunc_t f) + { +- return f == (encodefunc_t) ascii_encode +- || f == (encodefunc_t) latin1_encode +- || f == (encodefunc_t) utf8_encode; ++ return f == ascii_encode || f == latin1_encode || f == utf8_encode; + } + + /* Map normalized encoding names onto the specialized encoding funcs */ +@@ -815,15 +822,15 @@ + } encodefuncentry; + + static const encodefuncentry encodefuncs[] = { +- {"ascii", (encodefunc_t) ascii_encode}, +- {"iso8859-1", (encodefunc_t) latin1_encode}, +- {"utf-8", (encodefunc_t) utf8_encode}, +- {"utf-16-be", (encodefunc_t) utf16be_encode}, +- {"utf-16-le", (encodefunc_t) utf16le_encode}, +- {"utf-16", (encodefunc_t) utf16_encode}, +- {"utf-32-be", (encodefunc_t) utf32be_encode}, +- {"utf-32-le", (encodefunc_t) utf32le_encode}, +- {"utf-32", (encodefunc_t) utf32_encode}, ++ {"ascii", ascii_encode}, ++ {"iso8859-1", latin1_encode}, ++ {"utf-8", utf8_encode}, ++ {"utf-16-be", utf16be_encode}, ++ {"utf-16-le", utf16le_encode}, ++ {"utf-16", utf16_encode}, ++ {"utf-32-be", utf32be_encode}, ++ {"utf-32-le", utf32le_encode}, ++ {"utf-32", utf32_encode}, + {NULL, NULL} + }; + +@@ -1433,8 +1440,9 @@ + } + + static int +-textiowrapper_clear(textio *self) ++textiowrapper_clear(PyObject *op) + { ++ textio *self = textio_CAST(op); + self->ok = 0; + Py_CLEAR(self->buffer); + Py_CLEAR(self->encoding); +@@ -1452,24 +1460,26 @@ + } + + static void +-textiowrapper_dealloc(textio *self) ++textiowrapper_dealloc(PyObject *op) + { ++ textio *self = textio_CAST(op); + PyTypeObject *tp = Py_TYPE(self); + self->finalizing = 1; +- if (_PyIOBase_finalize((PyObject *) self) < 0) ++ if (_PyIOBase_finalize(op) < 0) + return; + self->ok = 0; + _PyObject_GC_UNTRACK(self); + if (self->weakreflist != NULL) +- PyObject_ClearWeakRefs((PyObject *)self); +- (void)textiowrapper_clear(self); +- tp->tp_free((PyObject *)self); ++ PyObject_ClearWeakRefs(op); ++ (void)textiowrapper_clear(op); ++ tp->tp_free(self); + Py_DECREF(tp); + } + + static int +-textiowrapper_traverse(textio *self, visitproc visit, void *arg) ++textiowrapper_traverse(PyObject *op, visitproc visit, void *arg) + { ++ textio *self = textio_CAST(op); + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->buffer); + Py_VISIT(self->encoding); +@@ -2963,10 +2973,11 @@ + } + + static PyObject * +-textiowrapper_repr(textio *self) ++textiowrapper_repr(PyObject *op) + { + PyObject *nameobj, *modeobj, *res, *s; + int status; ++ textio *self = textio_CAST(op); + const char *type_name = Py_TYPE(self)->tp_name; + + CHECK_INITIALIZED(self); +@@ -2975,7 +2986,7 @@ + if (res == NULL) + return NULL; + +- status = Py_ReprEnter((PyObject *)self); ++ status = Py_ReprEnter(op); + if (status != 0) { + if (status > 0) { + PyErr_Format(PyExc_RuntimeError, +@@ -2984,7 +2995,7 @@ + } + goto error; + } +- if (PyObject_GetOptionalAttr((PyObject *) self, &_Py_ID(name), &nameobj) < 0) { ++ if (PyObject_GetOptionalAttr(op, &_Py_ID(name), &nameobj) < 0) { + if (!PyErr_ExceptionMatches(PyExc_ValueError)) { + goto error; + } +@@ -3000,7 +3011,7 @@ + if (res == NULL) + goto error; + } +- if (PyObject_GetOptionalAttr((PyObject *) self, &_Py_ID(mode), &modeobj) < 0) { ++ if (PyObject_GetOptionalAttr(op, &_Py_ID(mode), &modeobj) < 0) { + goto error; + } + if (modeobj != NULL) { +@@ -3016,14 +3027,14 @@ + res, self->encoding); + Py_DECREF(res); + if (status == 0) { +- Py_ReprLeave((PyObject *)self); ++ Py_ReprLeave(op); + } + return s; + + error: + Py_XDECREF(res); + if (status == 0) { +- Py_ReprLeave((PyObject *)self); ++ Py_ReprLeave(op); + } + return NULL; + } +@@ -3163,9 +3174,10 @@ + } + + static PyObject * +-textiowrapper_iternext(textio *self) ++textiowrapper_iternext(PyObject *op) + { + PyObject *line; ++ textio *self = textio_CAST(op); + + CHECK_ATTACHED(self); + +@@ -3175,8 +3187,7 @@ + line = _textiowrapper_readline(self, -1); + } + else { +- line = PyObject_CallMethodNoArgs((PyObject *)self, +- &_Py_ID(readline)); ++ line = PyObject_CallMethodNoArgs(op, &_Py_ID(readline)); + if (line && !PyUnicode_Check(line)) { + PyErr_Format(PyExc_OSError, + "readline() should have returned a str object, " +@@ -3313,7 +3324,7 @@ + }; + + static PyGetSetDef incrementalnewlinedecoder_getset[] = { +- {"newlines", (getter)incrementalnewlinedecoder_newlines_get, NULL, NULL}, ++ {"newlines", incrementalnewlinedecoder_newlines_get, NULL, NULL}, + {NULL} + }; + +diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c +index 3fa0301e337..27c320ed073 100644 +--- a/Modules/_io/winconsoleio.c ++++ b/Modules/_io/winconsoleio.c +@@ -221,6 +221,8 @@ + wchar_t wbuf; + } winconsoleio; + ++#define winconsoleio_CAST(op) ((winconsoleio *)(op)) ++ + int + _PyWindowsConsoleIO_closed(PyObject *self) + { +@@ -492,32 +494,35 @@ + } + + static int +-winconsoleio_traverse(winconsoleio *self, visitproc visit, void *arg) ++winconsoleio_traverse(PyObject *op, visitproc visit, void *arg) + { ++ winconsoleio *self = winconsoleio_CAST(op); + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->dict); + return 0; + } + + static int +-winconsoleio_clear(winconsoleio *self) ++winconsoleio_clear(PyObject *op) + { ++ winconsoleio *self = winconsoleio_CAST(op); + Py_CLEAR(self->dict); + return 0; + } + + static void +-winconsoleio_dealloc(winconsoleio *self) ++winconsoleio_dealloc(PyObject *op) + { ++ winconsoleio *self = winconsoleio_CAST(op); + PyTypeObject *tp = Py_TYPE(self); + self->finalizing = 1; +- if (_PyIOBase_finalize((PyObject *) self) < 0) ++ if (_PyIOBase_finalize(op) < 0) + return; + _PyObject_GC_UNTRACK(self); + if (self->weakreflist != NULL) +- PyObject_ClearWeakRefs((PyObject *) self); ++ PyObject_ClearWeakRefs(op); + Py_CLEAR(self->dict); +- tp->tp_free((PyObject *)self); ++ tp->tp_free(self); + Py_DECREF(tp); + } + +@@ -1137,9 +1142,10 @@ + } + + static PyObject * +-winconsoleio_repr(winconsoleio *self) ++winconsoleio_repr(PyObject *op) + { +- const char *type_name = (Py_TYPE((PyObject *)self)->tp_name); ++ winconsoleio *self = winconsoleio_CAST(op); ++ const char *type_name = Py_TYPE(self)->tp_name; + + if (self->fd == -1) { + return PyUnicode_FromFormat("<%.100s [closed]>", type_name); +@@ -1197,28 +1203,31 @@ + /* 'closed' and 'mode' are attributes for compatibility with FileIO. */ + + static PyObject * +-get_closed(winconsoleio *self, void *closure) ++get_closed(PyObject *op, void *Py_UNUSED(closure)) + { ++ winconsoleio *self = winconsoleio_CAST(op); + return PyBool_FromLong((long)(self->fd == -1)); + } + + static PyObject * +-get_closefd(winconsoleio *self, void *closure) ++get_closefd(PyObject *op, void *Py_UNUSED(closure)) + { ++ winconsoleio *self = winconsoleio_CAST(op); + return PyBool_FromLong((long)(self->closefd)); + } + + static PyObject * +-get_mode(winconsoleio *self, void *closure) ++get_mode(PyObject *op, void *Py_UNUSED(closure)) + { ++ winconsoleio *self = winconsoleio_CAST(op); + return PyUnicode_FromString(self->readable ? "rb" : "wb"); + } + + static PyGetSetDef winconsoleio_getsetlist[] = { +- {"closed", (getter)get_closed, NULL, "True if the file is closed"}, +- {"closefd", (getter)get_closefd, NULL, ++ {"closed", get_closed, NULL, "True if the file is closed"}, ++ {"closefd", get_closefd, NULL, + "True if the file descriptor will be closed by close()."}, +- {"mode", (getter)get_mode, NULL, "String giving the file mode"}, ++ {"mode", get_mode, NULL, "String giving the file mode"}, + {NULL}, + }; + +diff --git a/Modules/_json.c b/Modules/_json.c +index a99abbe72bf..5532e252819 100644 +--- a/Modules/_json.c ++++ b/Modules/_json.c +@@ -302,7 +302,7 @@ + /* Use JSONDecodeError exception to raise a nice looking ValueError subclass */ + _Py_DECLARE_STR(json_decoder, "json.decoder"); + PyObject *JSONDecodeError = +- _PyImport_GetModuleAttr(&_Py_STR(json_decoder), &_Py_ID(JSONDecodeError)); ++ PyImport_ImportModuleAttr(&_Py_STR(json_decoder), &_Py_ID(JSONDecodeError)); + if (JSONDecodeError == NULL) { + return; + } +@@ -353,6 +353,13 @@ + return tpl; + } + ++static inline int ++_PyUnicodeWriter_IsEmpty(PyUnicodeWriter *writer_pub) ++{ ++ _PyUnicodeWriter *writer = (_PyUnicodeWriter*)writer_pub; ++ return (writer->pos == 0); ++} ++ + static PyObject * + scanstring_unicode(PyObject *pystr, Py_ssize_t end, int strict, Py_ssize_t *next_end_ptr) + { +@@ -371,9 +378,10 @@ + const void *buf; + int kind; + +- _PyUnicodeWriter writer; +- _PyUnicodeWriter_Init(&writer); +- writer.overallocate = 1; ++ PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); ++ if (writer == NULL) { ++ goto bail; ++ } + + len = PyUnicode_GET_LENGTH(pystr); + buf = PyUnicode_DATA(pystr); +@@ -404,11 +412,12 @@ + + if (c == '"') { + // Fast path for simple case. +- if (writer.buffer == NULL) { ++ if (_PyUnicodeWriter_IsEmpty(writer)) { + PyObject *ret = PyUnicode_Substring(pystr, end, next); + if (ret == NULL) { + goto bail; + } ++ PyUnicodeWriter_Discard(writer); + *next_end_ptr = next + 1;; + return ret; + } +@@ -420,7 +429,7 @@ + + /* Pick up this chunk if it's not zero length */ + if (next != end) { +- if (_PyUnicodeWriter_WriteSubstring(&writer, pystr, end, next) < 0) { ++ if (PyUnicodeWriter_WriteSubstring(writer, pystr, end, next) < 0) { + goto bail; + } + } +@@ -511,18 +520,18 @@ + end -= 6; + } + } +- if (_PyUnicodeWriter_WriteChar(&writer, c) < 0) { ++ if (PyUnicodeWriter_WriteChar(writer, c) < 0) { + goto bail; + } + } + +- rval = _PyUnicodeWriter_Finish(&writer); ++ rval = PyUnicodeWriter_Finish(writer); + *next_end_ptr = end; + return rval; + + bail: + *next_end_ptr = -1; +- _PyUnicodeWriter_Dealloc(&writer); ++ PyUnicodeWriter_Discard(writer); + return NULL; + } + +diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c +index 51ad9fc7da8..eab26b39be1 100644 +--- a/Modules/_lsprof.c ++++ b/Modules/_lsprof.c +@@ -97,7 +97,8 @@ + pObj->flags &= ~POF_EXT_TIMER; + + if (o == NULL) { +- PyErr_WriteUnraisable(pObj->externalTimer); ++ PyErr_FormatUnraisable("Exception ignored while calling " ++ "_lsprof timer %R", pObj->externalTimer); + return 0; + } + +@@ -116,7 +117,8 @@ + } + Py_DECREF(o); + if (err < 0) { +- PyErr_WriteUnraisable(pObj->externalTimer); ++ PyErr_FormatUnraisable("Exception ignored while calling " ++ "_lsprof timer %R", pObj->externalTimer); + return 0; + } + return result; +@@ -775,7 +777,7 @@ + return NULL; + } + +- PyObject* monitoring = _PyImport_GetModuleAttrString("sys", "monitoring"); ++ PyObject* monitoring = PyImport_ImportModuleAttrString("sys", "monitoring"); + if (!monitoring) { + return NULL; + } +@@ -857,7 +859,7 @@ + } + if (self->flags & POF_ENABLED) { + PyObject* result = NULL; +- PyObject* monitoring = _PyImport_GetModuleAttrString("sys", "monitoring"); ++ PyObject* monitoring = PyImport_ImportModuleAttrString("sys", "monitoring"); + + if (!monitoring) { + return NULL; +@@ -933,7 +935,8 @@ + if (op->flags & POF_ENABLED) { + PyThreadState *tstate = _PyThreadState_GET(); + if (_PyEval_SetProfile(tstate, NULL, NULL) < 0) { +- PyErr_FormatUnraisable("Exception ignored when destroying _lsprof profiler"); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "destroying _lsprof profiler"); + } + } + +@@ -973,7 +976,7 @@ + Py_XSETREF(self->externalTimer, Py_XNewRef(timer)); + self->tool_id = PY_MONITORING_PROFILER_ID; + +- PyObject* monitoring = _PyImport_GetModuleAttrString("sys", "monitoring"); ++ PyObject* monitoring = PyImport_ImportModuleAttrString("sys", "monitoring"); + if (!monitoring) { + return -1; + } +diff --git a/Modules/_multiprocessing/clinic/semaphore.c.h b/Modules/_multiprocessing/clinic/semaphore.c.h +index 2702c3369c7..e789137ec1e 100644 +--- a/Modules/_multiprocessing/clinic/semaphore.c.h ++++ b/Modules/_multiprocessing/clinic/semaphore.c.h +@@ -25,7 +25,7 @@ + PyObject *timeout_obj); + + static PyObject * +-_multiprocessing_SemLock_acquire(SemLockObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_multiprocessing_SemLock_acquire(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -78,7 +78,7 @@ + timeout_obj = args[1]; + skip_optional_pos: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _multiprocessing_SemLock_acquire_impl(self, blocking, timeout_obj); ++ return_value = _multiprocessing_SemLock_acquire_impl((SemLockObject *)self, blocking, timeout_obj); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -102,12 +102,12 @@ + _multiprocessing_SemLock_release_impl(SemLockObject *self); + + static PyObject * +-_multiprocessing_SemLock_release(SemLockObject *self, PyObject *Py_UNUSED(ignored)) ++_multiprocessing_SemLock_release(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _multiprocessing_SemLock_release_impl(self); ++ return_value = _multiprocessing_SemLock_release_impl((SemLockObject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -131,7 +131,7 @@ + PyObject *timeout_obj); + + static PyObject * +-_multiprocessing_SemLock_acquire(SemLockObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_multiprocessing_SemLock_acquire(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -184,7 +184,7 @@ + timeout_obj = args[1]; + skip_optional_pos: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _multiprocessing_SemLock_acquire_impl(self, blocking, timeout_obj); ++ return_value = _multiprocessing_SemLock_acquire_impl((SemLockObject *)self, blocking, timeout_obj); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -208,12 +208,12 @@ + _multiprocessing_SemLock_release_impl(SemLockObject *self); + + static PyObject * +-_multiprocessing_SemLock_release(SemLockObject *self, PyObject *Py_UNUSED(ignored)) ++_multiprocessing_SemLock_release(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _multiprocessing_SemLock_release_impl(self); ++ return_value = _multiprocessing_SemLock_release_impl((SemLockObject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -358,12 +358,12 @@ + _multiprocessing_SemLock__count_impl(SemLockObject *self); + + static PyObject * +-_multiprocessing_SemLock__count(SemLockObject *self, PyObject *Py_UNUSED(ignored)) ++_multiprocessing_SemLock__count(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _multiprocessing_SemLock__count_impl(self); ++ return_value = _multiprocessing_SemLock__count_impl((SemLockObject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -386,9 +386,9 @@ + _multiprocessing_SemLock__is_mine_impl(SemLockObject *self); + + static PyObject * +-_multiprocessing_SemLock__is_mine(SemLockObject *self, PyObject *Py_UNUSED(ignored)) ++_multiprocessing_SemLock__is_mine(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _multiprocessing_SemLock__is_mine_impl(self); ++ return _multiprocessing_SemLock__is_mine_impl((SemLockObject *)self); + } + + #endif /* defined(HAVE_MP_SEMAPHORE) */ +@@ -408,9 +408,9 @@ + _multiprocessing_SemLock__get_value_impl(SemLockObject *self); + + static PyObject * +-_multiprocessing_SemLock__get_value(SemLockObject *self, PyObject *Py_UNUSED(ignored)) ++_multiprocessing_SemLock__get_value(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _multiprocessing_SemLock__get_value_impl(self); ++ return _multiprocessing_SemLock__get_value_impl((SemLockObject *)self); + } + + #endif /* defined(HAVE_MP_SEMAPHORE) */ +@@ -430,9 +430,9 @@ + _multiprocessing_SemLock__is_zero_impl(SemLockObject *self); + + static PyObject * +-_multiprocessing_SemLock__is_zero(SemLockObject *self, PyObject *Py_UNUSED(ignored)) ++_multiprocessing_SemLock__is_zero(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _multiprocessing_SemLock__is_zero_impl(self); ++ return _multiprocessing_SemLock__is_zero_impl((SemLockObject *)self); + } + + #endif /* defined(HAVE_MP_SEMAPHORE) */ +@@ -452,9 +452,9 @@ + _multiprocessing_SemLock__after_fork_impl(SemLockObject *self); + + static PyObject * +-_multiprocessing_SemLock__after_fork(SemLockObject *self, PyObject *Py_UNUSED(ignored)) ++_multiprocessing_SemLock__after_fork(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _multiprocessing_SemLock__after_fork_impl(self); ++ return _multiprocessing_SemLock__after_fork_impl((SemLockObject *)self); + } + + #endif /* defined(HAVE_MP_SEMAPHORE) */ +@@ -474,12 +474,12 @@ + _multiprocessing_SemLock___enter___impl(SemLockObject *self); + + static PyObject * +-_multiprocessing_SemLock___enter__(SemLockObject *self, PyObject *Py_UNUSED(ignored)) ++_multiprocessing_SemLock___enter__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _multiprocessing_SemLock___enter___impl(self); ++ return_value = _multiprocessing_SemLock___enter___impl((SemLockObject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -504,7 +504,7 @@ + PyObject *exc_value, PyObject *exc_tb); + + static PyObject * +-_multiprocessing_SemLock___exit__(SemLockObject *self, PyObject *const *args, Py_ssize_t nargs) ++_multiprocessing_SemLock___exit__(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *exc_type = Py_None; +@@ -528,7 +528,7 @@ + exc_tb = args[2]; + skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _multiprocessing_SemLock___exit___impl(self, exc_type, exc_value, exc_tb); ++ return_value = _multiprocessing_SemLock___exit___impl((SemLockObject *)self, exc_type, exc_value, exc_tb); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -576,4 +576,4 @@ + #ifndef _MULTIPROCESSING_SEMLOCK___EXIT___METHODDEF + #define _MULTIPROCESSING_SEMLOCK___EXIT___METHODDEF + #endif /* !defined(_MULTIPROCESSING_SEMLOCK___EXIT___METHODDEF) */ +-/*[clinic end generated code: output=9023d3e48a24afd2 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=e28d0fdbfefd1235 input=a9049054013a1b77]*/ +diff --git a/Modules/_multiprocessing/semaphore.c b/Modules/_multiprocessing/semaphore.c +index 9eef7c25636..036db2cd4c6 100644 +--- a/Modules/_multiprocessing/semaphore.c ++++ b/Modules/_multiprocessing/semaphore.c +@@ -28,6 +28,8 @@ + char *name; + } SemLockObject; + ++#define _SemLockObject_CAST(op) ((SemLockObject *)(op)) ++ + /*[python input] + class SEM_HANDLE_converter(CConverter): + type = "SEM_HANDLE" +@@ -576,8 +578,9 @@ + } + + static void +-semlock_dealloc(SemLockObject* self) ++semlock_dealloc(PyObject *op) + { ++ SemLockObject *self = _SemLockObject_CAST(op); + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + if (self->handle != SEM_FAILED) +@@ -718,7 +721,7 @@ + } + + static int +-semlock_traverse(SemLockObject *s, visitproc visit, void *arg) ++semlock_traverse(PyObject *s, visitproc visit, void *arg) + { + Py_VISIT(Py_TYPE(s)); + return 0; +diff --git a/Modules/_opcode.c b/Modules/_opcode.c +index 7ccf7af6bf9..c295f7b3152 100644 +--- a/Modules/_opcode.c ++++ b/Modules/_opcode.c +@@ -274,6 +274,7 @@ + ADD_NB_OP(NB_INPLACE_SUBTRACT, "-="); + ADD_NB_OP(NB_INPLACE_TRUE_DIVIDE, "/="); + ADD_NB_OP(NB_INPLACE_XOR, "^="); ++ ADD_NB_OP(NB_SUBSCR, "[]"); + + #undef ADD_NB_OP + +diff --git a/Modules/_operator.c b/Modules/_operator.c +index ce3ef015710..59987b8f143 100644 +--- a/Modules/_operator.c ++++ b/Modules/_operator.c +@@ -1868,7 +1868,7 @@ + PyObject *constructor; + PyObject *newargs[2]; + +- partial = _PyImport_GetModuleAttrString("functools", "partial"); ++ partial = PyImport_ImportModuleAttrString("functools", "partial"); + if (!partial) + return NULL; + +diff --git a/Modules/_pickle.c b/Modules/_pickle.c +index 599b5f92c2a..5641f93391c 100644 +--- a/Modules/_pickle.c ++++ b/Modules/_pickle.c +@@ -362,7 +362,7 @@ + } + Py_CLEAR(compat_pickle); + +- st->codecs_encode = _PyImport_GetModuleAttrString("codecs", "encode"); ++ st->codecs_encode = PyImport_ImportModuleAttrString("codecs", "encode"); + if (st->codecs_encode == NULL) { + goto error; + } +@@ -373,7 +373,7 @@ + goto error; + } + +- st->partial = _PyImport_GetModuleAttrString("functools", "partial"); ++ st->partial = PyImport_ImportModuleAttrString("functools", "partial"); + if (!st->partial) + goto error; + +@@ -2159,8 +2159,10 @@ + unsigned char *pdata; + char header[5]; + int i; +- int sign = _PyLong_Sign(obj); + ++ int sign; ++ assert(PyLong_Check(obj)); ++ (void)PyLong_GetSign(obj, &sign); + if (sign == 0) { + header[0] = LONG1; + header[1] = 0; /* It's 0 -- an empty bytestring. */ +diff --git a/Modules/_sqlite/blob.c b/Modules/_sqlite/blob.c +index d1a549a971c..35d090e3ca2 100644 +--- a/Modules/_sqlite/blob.c ++++ b/Modules/_sqlite/blob.c +@@ -9,6 +9,8 @@ + #include "clinic/blob.c.h" + #undef clinic_state + ++#define _pysqlite_Blob_CAST(op) ((pysqlite_Blob *)(op)) ++ + /*[clinic input] + module _sqlite3 + class _sqlite3.Blob "pysqlite_Blob *" "clinic_state()->BlobType" +@@ -29,32 +31,35 @@ + } + + static int +-blob_traverse(pysqlite_Blob *self, visitproc visit, void *arg) ++blob_traverse(PyObject *op, visitproc visit, void *arg) + { ++ pysqlite_Blob *self = _pysqlite_Blob_CAST(op); + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->connection); + return 0; + } + + static int +-blob_clear(pysqlite_Blob *self) ++blob_clear(PyObject *op) + { ++ pysqlite_Blob *self = _pysqlite_Blob_CAST(op); + Py_CLEAR(self->connection); + return 0; + } + + static void +-blob_dealloc(pysqlite_Blob *self) ++blob_dealloc(PyObject *op) + { ++ pysqlite_Blob *self = _pysqlite_Blob_CAST(op); + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + + close_blob(self); + + if (self->in_weakreflist != NULL) { +- PyObject_ClearWeakRefs((PyObject*)self); ++ PyObject_ClearWeakRefs(op); + } +- tp->tp_clear((PyObject *)self); ++ (void)tp->tp_clear(op); + tp->tp_free(self); + Py_DECREF(tp); + } +@@ -114,7 +119,7 @@ + blob_seterror(pysqlite_Blob *self, int rc) + { + assert(self->connection != NULL); +- _pysqlite_seterror(self->connection->state, self->connection->db); ++ set_error_from_db(self->connection->state, self->connection->db); + } + + static PyObject * +@@ -373,8 +378,9 @@ + } + + static Py_ssize_t +-blob_length(pysqlite_Blob *self) ++blob_length(PyObject *op) + { ++ pysqlite_Blob *self = _pysqlite_Blob_CAST(op); + if (!check_blob(self)) { + return -1; + } +@@ -449,8 +455,9 @@ + } + + static PyObject * +-blob_subscript(pysqlite_Blob *self, PyObject *item) ++blob_subscript(PyObject *op, PyObject *item) + { ++ pysqlite_Blob *self = _pysqlite_Blob_CAST(op); + if (!check_blob(self)) { + return NULL; + } +@@ -546,8 +553,9 @@ + } + + static int +-blob_ass_subscript(pysqlite_Blob *self, PyObject *item, PyObject *value) ++blob_ass_subscript(PyObject *op, PyObject *item, PyObject *value) + { ++ pysqlite_Blob *self = _pysqlite_Blob_CAST(op); + if (!check_blob(self)) { + return -1; + } +diff --git a/Modules/_sqlite/clinic/blob.c.h b/Modules/_sqlite/clinic/blob.c.h +index b95ba948aaf..921e7cbd7ff 100644 +--- a/Modules/_sqlite/clinic/blob.c.h ++++ b/Modules/_sqlite/clinic/blob.c.h +@@ -17,9 +17,9 @@ + blob_close_impl(pysqlite_Blob *self); + + static PyObject * +-blob_close(pysqlite_Blob *self, PyObject *Py_UNUSED(ignored)) ++blob_close(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return blob_close_impl(self); ++ return blob_close_impl((pysqlite_Blob *)self); + } + + PyDoc_STRVAR(blob_read__doc__, +@@ -42,7 +42,7 @@ + blob_read_impl(pysqlite_Blob *self, int length); + + static PyObject * +-blob_read(pysqlite_Blob *self, PyObject *const *args, Py_ssize_t nargs) ++blob_read(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + int length = -1; +@@ -58,7 +58,7 @@ + goto exit; + } + skip_optional: +- return_value = blob_read_impl(self, length); ++ return_value = blob_read_impl((pysqlite_Blob *)self, length); + + exit: + return return_value; +@@ -80,7 +80,7 @@ + blob_write_impl(pysqlite_Blob *self, Py_buffer *data); + + static PyObject * +-blob_write(pysqlite_Blob *self, PyObject *arg) ++blob_write(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; +@@ -88,7 +88,7 @@ + if (PyObject_GetBuffer(arg, &data, PyBUF_SIMPLE) != 0) { + goto exit; + } +- return_value = blob_write_impl(self, &data); ++ return_value = blob_write_impl((pysqlite_Blob *)self, &data); + + exit: + /* Cleanup for data */ +@@ -116,7 +116,7 @@ + blob_seek_impl(pysqlite_Blob *self, int offset, int origin); + + static PyObject * +-blob_seek(pysqlite_Blob *self, PyObject *const *args, Py_ssize_t nargs) ++blob_seek(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + int offset; +@@ -137,7 +137,7 @@ + goto exit; + } + skip_optional: +- return_value = blob_seek_impl(self, offset, origin); ++ return_value = blob_seek_impl((pysqlite_Blob *)self, offset, origin); + + exit: + return return_value; +@@ -156,9 +156,9 @@ + blob_tell_impl(pysqlite_Blob *self); + + static PyObject * +-blob_tell(pysqlite_Blob *self, PyObject *Py_UNUSED(ignored)) ++blob_tell(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return blob_tell_impl(self); ++ return blob_tell_impl((pysqlite_Blob *)self); + } + + PyDoc_STRVAR(blob_enter__doc__, +@@ -174,9 +174,9 @@ + blob_enter_impl(pysqlite_Blob *self); + + static PyObject * +-blob_enter(pysqlite_Blob *self, PyObject *Py_UNUSED(ignored)) ++blob_enter(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return blob_enter_impl(self); ++ return blob_enter_impl((pysqlite_Blob *)self); + } + + PyDoc_STRVAR(blob_exit__doc__, +@@ -193,7 +193,7 @@ + PyObject *tb); + + static PyObject * +-blob_exit(pysqlite_Blob *self, PyObject *const *args, Py_ssize_t nargs) ++blob_exit(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *type; +@@ -206,9 +206,9 @@ + type = args[0]; + val = args[1]; + tb = args[2]; +- return_value = blob_exit_impl(self, type, val, tb); ++ return_value = blob_exit_impl((pysqlite_Blob *)self, type, val, tb); + + exit: + return return_value; + } +-/*[clinic end generated code: output=31abd55660e0c5af input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=f03f4ba622b67ae0 input=a9049054013a1b77]*/ +diff --git a/Modules/_sqlite/clinic/connection.c.h b/Modules/_sqlite/clinic/connection.c.h +index 42eb6eb2f12..82fba44eb1b 100644 +--- a/Modules/_sqlite/clinic/connection.c.h ++++ b/Modules/_sqlite/clinic/connection.c.h +@@ -182,7 +182,7 @@ + pysqlite_connection_cursor_impl(pysqlite_Connection *self, PyObject *factory); + + static PyObject * +-pysqlite_connection_cursor(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++pysqlite_connection_cursor(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -224,7 +224,7 @@ + } + factory = args[0]; + skip_optional_pos: +- return_value = pysqlite_connection_cursor_impl(self, factory); ++ return_value = pysqlite_connection_cursor_impl((pysqlite_Connection *)self, factory); + + exit: + return return_value; +@@ -255,7 +255,7 @@ + sqlite3_int64 row, int readonly, const char *name); + + static PyObject * +-blobopen(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++blobopen(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -351,7 +351,7 @@ + goto exit; + } + skip_optional_kwonly: +- return_value = blobopen_impl(self, table, col, row, readonly, name); ++ return_value = blobopen_impl((pysqlite_Connection *)self, table, col, row, readonly, name); + + exit: + return return_value; +@@ -372,9 +372,9 @@ + pysqlite_connection_close_impl(pysqlite_Connection *self); + + static PyObject * +-pysqlite_connection_close(pysqlite_Connection *self, PyObject *Py_UNUSED(ignored)) ++pysqlite_connection_close(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return pysqlite_connection_close_impl(self); ++ return pysqlite_connection_close_impl((pysqlite_Connection *)self); + } + + PyDoc_STRVAR(pysqlite_connection_commit__doc__, +@@ -392,9 +392,9 @@ + pysqlite_connection_commit_impl(pysqlite_Connection *self); + + static PyObject * +-pysqlite_connection_commit(pysqlite_Connection *self, PyObject *Py_UNUSED(ignored)) ++pysqlite_connection_commit(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return pysqlite_connection_commit_impl(self); ++ return pysqlite_connection_commit_impl((pysqlite_Connection *)self); + } + + PyDoc_STRVAR(pysqlite_connection_rollback__doc__, +@@ -412,9 +412,9 @@ + pysqlite_connection_rollback_impl(pysqlite_Connection *self); + + static PyObject * +-pysqlite_connection_rollback(pysqlite_Connection *self, PyObject *Py_UNUSED(ignored)) ++pysqlite_connection_rollback(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return pysqlite_connection_rollback_impl(self); ++ return pysqlite_connection_rollback_impl((pysqlite_Connection *)self); + } + + PyDoc_STRVAR(pysqlite_connection_create_function__doc__, +@@ -449,7 +449,7 @@ + #endif + + static PyObject * +-pysqlite_connection_create_function(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++pysqlite_connection_create_function(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -525,7 +525,7 @@ + goto exit; + } + skip_optional_kwonly: +- return_value = pysqlite_connection_create_function_impl(self, cls, name, narg, func, deterministic); ++ return_value = pysqlite_connection_create_function_impl((pysqlite_Connection *)self, cls, name, narg, func, deterministic); + + exit: + return return_value; +@@ -557,7 +557,7 @@ + PyObject *aggregate_class); + + static PyObject * +-create_window_function(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++create_window_function(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -601,7 +601,7 @@ + goto exit; + } + aggregate_class = args[2]; +- return_value = create_window_function_impl(self, cls, name, num_params, aggregate_class); ++ return_value = create_window_function_impl((pysqlite_Connection *)self, cls, name, num_params, aggregate_class); + + exit: + return return_value; +@@ -642,7 +642,7 @@ + #endif + + static PyObject * +-pysqlite_connection_create_aggregate(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++pysqlite_connection_create_aggregate(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -708,7 +708,7 @@ + goto exit; + } + aggregate_class = args[2]; +- return_value = pysqlite_connection_create_aggregate_impl(self, cls, name, n_arg, aggregate_class); ++ return_value = pysqlite_connection_create_aggregate_impl((pysqlite_Connection *)self, cls, name, n_arg, aggregate_class); + + exit: + return return_value; +@@ -745,7 +745,7 @@ + #endif + + static PyObject * +-pysqlite_connection_set_authorizer(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++pysqlite_connection_set_authorizer(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -792,7 +792,7 @@ + } + } + callable = args[0]; +- return_value = pysqlite_connection_set_authorizer_impl(self, cls, callable); ++ return_value = pysqlite_connection_set_authorizer_impl((pysqlite_Connection *)self, cls, callable); + + exit: + return return_value; +@@ -839,7 +839,7 @@ + #endif + + static PyObject * +-pysqlite_connection_set_progress_handler(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++pysqlite_connection_set_progress_handler(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -891,7 +891,7 @@ + if (n == -1 && PyErr_Occurred()) { + goto exit; + } +- return_value = pysqlite_connection_set_progress_handler_impl(self, cls, callable, n); ++ return_value = pysqlite_connection_set_progress_handler_impl((pysqlite_Connection *)self, cls, callable, n); + + exit: + return return_value; +@@ -928,7 +928,7 @@ + #endif + + static PyObject * +-pysqlite_connection_set_trace_callback(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++pysqlite_connection_set_trace_callback(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -975,7 +975,7 @@ + } + } + callable = args[0]; +- return_value = pysqlite_connection_set_trace_callback_impl(self, cls, callable); ++ return_value = pysqlite_connection_set_trace_callback_impl((pysqlite_Connection *)self, cls, callable); + + exit: + return return_value; +@@ -997,7 +997,7 @@ + int onoff); + + static PyObject * +-pysqlite_connection_enable_load_extension(pysqlite_Connection *self, PyObject *arg) ++pysqlite_connection_enable_load_extension(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + int onoff; +@@ -1006,7 +1006,7 @@ + if (onoff < 0) { + goto exit; + } +- return_value = pysqlite_connection_enable_load_extension_impl(self, onoff); ++ return_value = pysqlite_connection_enable_load_extension_impl((pysqlite_Connection *)self, onoff); + + exit: + return return_value; +@@ -1031,7 +1031,7 @@ + const char *entrypoint); + + static PyObject * +-pysqlite_connection_load_extension(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++pysqlite_connection_load_extension(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -1104,7 +1104,7 @@ + goto exit; + } + skip_optional_kwonly: +- return_value = pysqlite_connection_load_extension_impl(self, extension_name, entrypoint); ++ return_value = pysqlite_connection_load_extension_impl((pysqlite_Connection *)self, extension_name, entrypoint); + + exit: + return return_value; +@@ -1126,7 +1126,7 @@ + PyObject *parameters); + + static PyObject * +-pysqlite_connection_execute(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs) ++pysqlite_connection_execute(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *sql; +@@ -1145,7 +1145,7 @@ + } + parameters = args[1]; + skip_optional: +- return_value = pysqlite_connection_execute_impl(self, sql, parameters); ++ return_value = pysqlite_connection_execute_impl((pysqlite_Connection *)self, sql, parameters); + + exit: + return return_value; +@@ -1165,7 +1165,7 @@ + PyObject *sql, PyObject *parameters); + + static PyObject * +-pysqlite_connection_executemany(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs) ++pysqlite_connection_executemany(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *sql; +@@ -1180,7 +1180,7 @@ + } + sql = args[0]; + parameters = args[1]; +- return_value = pysqlite_connection_executemany_impl(self, sql, parameters); ++ return_value = pysqlite_connection_executemany_impl((pysqlite_Connection *)self, sql, parameters); + + exit: + return return_value; +@@ -1208,9 +1208,9 @@ + pysqlite_connection_interrupt_impl(pysqlite_Connection *self); + + static PyObject * +-pysqlite_connection_interrupt(pysqlite_Connection *self, PyObject *Py_UNUSED(ignored)) ++pysqlite_connection_interrupt(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return pysqlite_connection_interrupt_impl(self); ++ return pysqlite_connection_interrupt_impl((pysqlite_Connection *)self); + } + + PyDoc_STRVAR(pysqlite_connection_iterdump__doc__, +@@ -1230,7 +1230,7 @@ + PyObject *filter); + + static PyObject * +-pysqlite_connection_iterdump(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++pysqlite_connection_iterdump(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -1272,7 +1272,7 @@ + } + filter = args[0]; + skip_optional_kwonly: +- return_value = pysqlite_connection_iterdump_impl(self, filter); ++ return_value = pysqlite_connection_iterdump_impl((pysqlite_Connection *)self, filter); + + exit: + return return_value; +@@ -1295,7 +1295,7 @@ + double sleep); + + static PyObject * +-pysqlite_connection_backup(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++pysqlite_connection_backup(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -1388,7 +1388,7 @@ + } + } + skip_optional_kwonly: +- return_value = pysqlite_connection_backup_impl(self, target, pages, progress, name, sleep); ++ return_value = pysqlite_connection_backup_impl((pysqlite_Connection *)self, target, pages, progress, name, sleep); + + exit: + return return_value; +@@ -1410,7 +1410,7 @@ + PyObject *callable); + + static PyObject * +-pysqlite_connection_create_collation(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++pysqlite_connection_create_collation(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -1449,7 +1449,7 @@ + goto exit; + } + callable = args[1]; +- return_value = pysqlite_connection_create_collation_impl(self, cls, name, callable); ++ return_value = pysqlite_connection_create_collation_impl((pysqlite_Connection *)self, cls, name, callable); + + exit: + return return_value; +@@ -1478,7 +1478,7 @@ + serialize_impl(pysqlite_Connection *self, const char *name); + + static PyObject * +-serialize(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++serialize(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -1532,7 +1532,7 @@ + goto exit; + } + skip_optional_kwonly: +- return_value = serialize_impl(self, name); ++ return_value = serialize_impl((pysqlite_Connection *)self, name); + + exit: + return return_value; +@@ -1568,7 +1568,7 @@ + const char *name); + + static PyObject * +-deserialize(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++deserialize(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -1638,7 +1638,7 @@ + goto exit; + } + skip_optional_kwonly: +- return_value = deserialize_impl(self, &data, name); ++ return_value = deserialize_impl((pysqlite_Connection *)self, &data, name); + + exit: + /* Cleanup for data */ +@@ -1666,9 +1666,9 @@ + pysqlite_connection_enter_impl(pysqlite_Connection *self); + + static PyObject * +-pysqlite_connection_enter(pysqlite_Connection *self, PyObject *Py_UNUSED(ignored)) ++pysqlite_connection_enter(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return pysqlite_connection_enter_impl(self); ++ return pysqlite_connection_enter_impl((pysqlite_Connection *)self); + } + + PyDoc_STRVAR(pysqlite_connection_exit__doc__, +@@ -1687,7 +1687,7 @@ + PyObject *exc_value, PyObject *exc_tb); + + static PyObject * +-pysqlite_connection_exit(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs) ++pysqlite_connection_exit(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *exc_type; +@@ -1700,7 +1700,7 @@ + exc_type = args[0]; + exc_value = args[1]; + exc_tb = args[2]; +- return_value = pysqlite_connection_exit_impl(self, exc_type, exc_value, exc_tb); ++ return_value = pysqlite_connection_exit_impl((pysqlite_Connection *)self, exc_type, exc_value, exc_tb); + + exit: + return return_value; +@@ -1729,7 +1729,7 @@ + setlimit_impl(pysqlite_Connection *self, int category, int limit); + + static PyObject * +-setlimit(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs) ++setlimit(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + int category; +@@ -1746,7 +1746,7 @@ + if (limit == -1 && PyErr_Occurred()) { + goto exit; + } +- return_value = setlimit_impl(self, category, limit); ++ return_value = setlimit_impl((pysqlite_Connection *)self, category, limit); + + exit: + return return_value; +@@ -1768,7 +1768,7 @@ + getlimit_impl(pysqlite_Connection *self, int category); + + static PyObject * +-getlimit(pysqlite_Connection *self, PyObject *arg) ++getlimit(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + int category; +@@ -1777,7 +1777,7 @@ + if (category == -1 && PyErr_Occurred()) { + goto exit; + } +- return_value = getlimit_impl(self, category); ++ return_value = getlimit_impl((pysqlite_Connection *)self, category); + + exit: + return return_value; +@@ -1799,7 +1799,7 @@ + setconfig_impl(pysqlite_Connection *self, int op, int enable); + + static PyObject * +-setconfig(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs) ++setconfig(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + int op; +@@ -1820,7 +1820,7 @@ + goto exit; + } + skip_optional: +- return_value = setconfig_impl(self, op, enable); ++ return_value = setconfig_impl((pysqlite_Connection *)self, op, enable); + + exit: + return return_value; +@@ -1842,7 +1842,7 @@ + getconfig_impl(pysqlite_Connection *self, int op); + + static PyObject * +-getconfig(pysqlite_Connection *self, PyObject *arg) ++getconfig(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + int op; +@@ -1852,7 +1852,7 @@ + if (op == -1 && PyErr_Occurred()) { + goto exit; + } +- _return_value = getconfig_impl(self, op); ++ _return_value = getconfig_impl((pysqlite_Connection *)self, op); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } +@@ -1881,4 +1881,4 @@ + #ifndef DESERIALIZE_METHODDEF + #define DESERIALIZE_METHODDEF + #endif /* !defined(DESERIALIZE_METHODDEF) */ +-/*[clinic end generated code: output=a8fd19301c7390cc input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=c59effb407b8ea4d input=a9049054013a1b77]*/ +diff --git a/Modules/_sqlite/clinic/cursor.c.h b/Modules/_sqlite/clinic/cursor.c.h +index ca7823cf5ae..590e429e913 100644 +--- a/Modules/_sqlite/clinic/cursor.c.h ++++ b/Modules/_sqlite/clinic/cursor.c.h +@@ -52,7 +52,7 @@ + PyObject *parameters); + + static PyObject * +-pysqlite_cursor_execute(pysqlite_Cursor *self, PyObject *const *args, Py_ssize_t nargs) ++pysqlite_cursor_execute(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *sql; +@@ -71,7 +71,7 @@ + } + parameters = args[1]; + skip_optional: +- return_value = pysqlite_cursor_execute_impl(self, sql, parameters); ++ return_value = pysqlite_cursor_execute_impl((pysqlite_Cursor *)self, sql, parameters); + + exit: + return return_value; +@@ -91,7 +91,7 @@ + PyObject *seq_of_parameters); + + static PyObject * +-pysqlite_cursor_executemany(pysqlite_Cursor *self, PyObject *const *args, Py_ssize_t nargs) ++pysqlite_cursor_executemany(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *sql; +@@ -106,7 +106,7 @@ + } + sql = args[0]; + seq_of_parameters = args[1]; +- return_value = pysqlite_cursor_executemany_impl(self, sql, seq_of_parameters); ++ return_value = pysqlite_cursor_executemany_impl((pysqlite_Cursor *)self, sql, seq_of_parameters); + + exit: + return return_value; +@@ -126,7 +126,7 @@ + const char *sql_script); + + static PyObject * +-pysqlite_cursor_executescript(pysqlite_Cursor *self, PyObject *arg) ++pysqlite_cursor_executescript(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + const char *sql_script; +@@ -144,7 +144,7 @@ + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } +- return_value = pysqlite_cursor_executescript_impl(self, sql_script); ++ return_value = pysqlite_cursor_executescript_impl((pysqlite_Cursor *)self, sql_script); + + exit: + return return_value; +@@ -163,9 +163,9 @@ + pysqlite_cursor_fetchone_impl(pysqlite_Cursor *self); + + static PyObject * +-pysqlite_cursor_fetchone(pysqlite_Cursor *self, PyObject *Py_UNUSED(ignored)) ++pysqlite_cursor_fetchone(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return pysqlite_cursor_fetchone_impl(self); ++ return pysqlite_cursor_fetchone_impl((pysqlite_Cursor *)self); + } + + PyDoc_STRVAR(pysqlite_cursor_fetchmany__doc__, +@@ -184,7 +184,7 @@ + pysqlite_cursor_fetchmany_impl(pysqlite_Cursor *self, int maxrows); + + static PyObject * +-pysqlite_cursor_fetchmany(pysqlite_Cursor *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++pysqlite_cursor_fetchmany(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -214,7 +214,7 @@ + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; +- int maxrows = self->arraysize; ++ int maxrows = ((pysqlite_Cursor *)self)->arraysize; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); +@@ -229,7 +229,7 @@ + goto exit; + } + skip_optional_pos: +- return_value = pysqlite_cursor_fetchmany_impl(self, maxrows); ++ return_value = pysqlite_cursor_fetchmany_impl((pysqlite_Cursor *)self, maxrows); + + exit: + return return_value; +@@ -248,9 +248,9 @@ + pysqlite_cursor_fetchall_impl(pysqlite_Cursor *self); + + static PyObject * +-pysqlite_cursor_fetchall(pysqlite_Cursor *self, PyObject *Py_UNUSED(ignored)) ++pysqlite_cursor_fetchall(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return pysqlite_cursor_fetchall_impl(self); ++ return pysqlite_cursor_fetchall_impl((pysqlite_Cursor *)self); + } + + PyDoc_STRVAR(pysqlite_cursor_setinputsizes__doc__, +@@ -276,7 +276,7 @@ + PyObject *column); + + static PyObject * +-pysqlite_cursor_setoutputsize(pysqlite_Cursor *self, PyObject *const *args, Py_ssize_t nargs) ++pysqlite_cursor_setoutputsize(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *size; +@@ -291,7 +291,7 @@ + } + column = args[1]; + skip_optional: +- return_value = pysqlite_cursor_setoutputsize_impl(self, size, column); ++ return_value = pysqlite_cursor_setoutputsize_impl((pysqlite_Cursor *)self, size, column); + + exit: + return return_value; +@@ -310,8 +310,8 @@ + pysqlite_cursor_close_impl(pysqlite_Cursor *self); + + static PyObject * +-pysqlite_cursor_close(pysqlite_Cursor *self, PyObject *Py_UNUSED(ignored)) ++pysqlite_cursor_close(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return pysqlite_cursor_close_impl(self); ++ return pysqlite_cursor_close_impl((pysqlite_Cursor *)self); + } +-/*[clinic end generated code: output=f0804afc5f8646c1 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=82620ca7622b547c input=a9049054013a1b77]*/ +diff --git a/Modules/_sqlite/clinic/row.c.h b/Modules/_sqlite/clinic/row.c.h +index e8d1dbf2ba8..068906744e4 100644 +--- a/Modules/_sqlite/clinic/row.c.h ++++ b/Modules/_sqlite/clinic/row.c.h +@@ -52,8 +52,8 @@ + pysqlite_row_keys_impl(pysqlite_Row *self); + + static PyObject * +-pysqlite_row_keys(pysqlite_Row *self, PyObject *Py_UNUSED(ignored)) ++pysqlite_row_keys(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return pysqlite_row_keys_impl(self); ++ return pysqlite_row_keys_impl((pysqlite_Row *)self); + } +-/*[clinic end generated code: output=788bf817acc02b8e input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=6c1acbb48f386468 input=a9049054013a1b77]*/ +diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c +index fc03e4a085c..7997e5f4d98 100644 +--- a/Modules/_sqlite/connection.c ++++ b/Modules/_sqlite/connection.c +@@ -34,7 +34,6 @@ + #include "prepare_protocol.h" + #include "util.h" + +-#include "pycore_import.h" // _PyImport_GetModuleAttrString() + #include "pycore_modsupport.h" // _PyArg_NoKeywords() + #include "pycore_pyerrors.h" // _PyErr_ChainExceptions1() + #include "pycore_pylifecycle.h" // _Py_IsInterpreterFinalizing() +@@ -136,6 +135,8 @@ + #include "clinic/connection.c.h" + #undef clinic_state + ++#define _pysqlite_Connection_CAST(op) ((pysqlite_Connection *)(op)) ++ + /*[clinic input] + module _sqlite3 + class _sqlite3.Connection "pysqlite_Connection *" "clinic_state()->ConnectionType" +@@ -187,7 +188,7 @@ + Py_END_ALLOW_THREADS + + if (rc != SQLITE_OK) { +- (void)_pysqlite_seterror(self->state, self->db); ++ set_error_from_db(self->state, self->db); + return -1; + } + return 0; +@@ -273,7 +274,7 @@ + + pysqlite_state *state = pysqlite_get_state_by_type(Py_TYPE(self)); + if (rc != SQLITE_OK) { +- _pysqlite_seterror(state, db); ++ set_error_from_db(state, db); + goto error; + } + +@@ -385,8 +386,9 @@ + } while (0) + + static int +-connection_traverse(pysqlite_Connection *self, visitproc visit, void *arg) ++connection_traverse(PyObject *op, visitproc visit, void *arg) + { ++ pysqlite_Connection *self = _pysqlite_Connection_CAST(op); + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->statement_cache); + Py_VISIT(self->cursors); +@@ -410,8 +412,9 @@ + } + + static int +-connection_clear(pysqlite_Connection *self) ++connection_clear(PyObject *op) + { ++ pysqlite_Connection *self = _pysqlite_Connection_CAST(op); + Py_CLEAR(self->statement_cache); + Py_CLEAR(self->cursors); + Py_CLEAR(self->blobs); +@@ -494,7 +497,8 @@ + if (PyErr_ResourceWarning(self, 1, "unclosed database in %R", self)) { + /* Spurious errors can appear at shutdown */ + if (PyErr_ExceptionMatches(PyExc_Warning)) { +- PyErr_WriteUnraisable(self); ++ PyErr_FormatUnraisable("Exception ignored while finalizing " ++ "database connection %R", self); + } + } + } +@@ -503,7 +507,8 @@ + PyErr_Clear(); + } + else { +- PyErr_WriteUnraisable((PyObject *)self); ++ PyErr_FormatUnraisable("Exception ignored while closing database %R", ++ self); + } + } + +@@ -518,7 +523,7 @@ + } + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); +- tp->tp_clear(self); ++ (void)tp->tp_clear(self); + tp->tp_free(self); + Py_DECREF(tp); + } +@@ -602,11 +607,11 @@ + Py_END_ALLOW_THREADS + + if (rc == SQLITE_MISUSE) { +- PyErr_Format(self->state->InterfaceError, sqlite3_errstr(rc)); ++ set_error_from_code(self->state, rc); + return NULL; + } + else if (rc != SQLITE_OK) { +- _pysqlite_seterror(self->state, self->db); ++ set_error_from_db(self->state, self->db); + return NULL; + } + +@@ -890,7 +895,8 @@ + assert(ctx != NULL); + assert(ctx->state != NULL); + if (ctx->state->enable_callback_tracebacks) { +- PyErr_WriteUnraisable(ctx->callable); ++ PyErr_FormatUnraisable("Exception ignored on sqlite3 callback %R", ++ ctx->callable); + } + else { + PyErr_Clear(); +@@ -958,6 +964,11 @@ + assert(ctx != NULL); + + aggregate_instance = (PyObject**)sqlite3_aggregate_context(context, sizeof(PyObject*)); ++ if (aggregate_instance == NULL) { ++ (void)PyErr_NoMemory(); ++ set_sqlite_error(context, "unable to allocate SQLite aggregate context"); ++ goto error; ++ } + if (*aggregate_instance == NULL) { + *aggregate_instance = PyObject_CallNoArgs(ctx->callable); + if (!*aggregate_instance) { +@@ -1128,6 +1139,20 @@ + } + } + ++static int ++check_num_params(pysqlite_Connection *self, const int n, const char *name) ++{ ++ int limit = sqlite3_limit(self->db, SQLITE_LIMIT_FUNCTION_ARG, -1); ++ assert(limit >= 0); ++ if (n < -1 || n > limit) { ++ PyErr_Format(self->ProgrammingError, ++ "'%s' must be between -1 and %d, not %d", ++ name, limit, n); ++ return -1; ++ } ++ return 0; ++} ++ + /*[clinic input] + _sqlite3.Connection.create_function as pysqlite_connection_create_function + +@@ -1156,6 +1181,9 @@ + if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { + return NULL; + } ++ if (check_num_params(self, narg, "narg") < 0) { ++ return NULL; ++ } + + if (deterministic) { + flags |= SQLITE_DETERMINISTIC; +@@ -1296,10 +1324,12 @@ + "SQLite 3.25.0 or higher"); + return NULL; + } +- + if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { + return NULL; + } ++ if (check_num_params(self, num_params, "num_params") < 0) { ++ return NULL; ++ } + + int flags = SQLITE_UTF8; + int rc; +@@ -1322,9 +1352,9 @@ + } + + if (rc != SQLITE_OK) { +- // Errors are not set on the database connection, so we cannot +- // use _pysqlite_seterror(). +- PyErr_SetString(self->ProgrammingError, sqlite3_errstr(rc)); ++ /* Errors are not set on the database connection; use result code ++ * instead. */ ++ set_error_from_code(self->state, rc); + return NULL; + } + Py_RETURN_NONE; +@@ -1356,6 +1386,9 @@ + if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { + return NULL; + } ++ if (check_num_params(self, n_arg, "n_arg") < 0) { ++ return NULL; ++ } + + callback_context *ctx = create_callback_context(cls, aggregate_class); + if (ctx == NULL) { +@@ -1711,8 +1744,10 @@ + return 1; + } + +-static PyObject* pysqlite_connection_get_isolation_level(pysqlite_Connection* self, void* unused) ++static PyObject * ++pysqlite_connection_get_isolation_level(PyObject *op, void *Py_UNUSED(closure)) + { ++ pysqlite_Connection *self = _pysqlite_Connection_CAST(op); + if (!pysqlite_check_connection(self)) { + return NULL; + } +@@ -1722,16 +1757,20 @@ + Py_RETURN_NONE; + } + +-static PyObject* pysqlite_connection_get_total_changes(pysqlite_Connection* self, void* unused) ++static PyObject * ++pysqlite_connection_get_total_changes(PyObject *op, void *Py_UNUSED(closure)) + { ++ pysqlite_Connection *self = _pysqlite_Connection_CAST(op); + if (!pysqlite_check_connection(self)) { + return NULL; + } + return PyLong_FromLong(sqlite3_total_changes(self->db)); + } + +-static PyObject* pysqlite_connection_get_in_transaction(pysqlite_Connection* self, void* unused) ++static PyObject * ++pysqlite_connection_get_in_transaction(PyObject *op, void *Py_UNUSED(closure)) + { ++ pysqlite_Connection *self = _pysqlite_Connection_CAST(op); + if (!pysqlite_check_connection(self)) { + return NULL; + } +@@ -1742,8 +1781,11 @@ + } + + static int +-pysqlite_connection_set_isolation_level(pysqlite_Connection* self, PyObject* isolation_level, void *Py_UNUSED(ignored)) ++pysqlite_connection_set_isolation_level(PyObject *op, ++ PyObject *isolation_level, ++ void *Py_UNUSED(ignored)) + { ++ pysqlite_Connection *self = _pysqlite_Connection_CAST(op); + if (isolation_level == NULL) { + PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); + return -1; +@@ -1766,11 +1808,11 @@ + } + + static PyObject * +-pysqlite_connection_call(pysqlite_Connection *self, PyObject *args, +- PyObject *kwargs) ++pysqlite_connection_call(PyObject *op, PyObject *args, PyObject *kwargs) + { + PyObject* sql; + pysqlite_Statement* statement; ++ pysqlite_Connection *self = _pysqlite_Connection_CAST(op); + + if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { + return NULL; +@@ -1995,7 +2037,7 @@ + return NULL; + } + +- PyObject *iterdump = _PyImport_GetModuleAttrString(MODULE_NAME ".dump", "_iterdump"); ++ PyObject *iterdump = PyImport_ImportModuleAttrString(MODULE_NAME ".dump", "_iterdump"); + if (!iterdump) { + if (!PyErr_Occurred()) { + PyErr_SetString(self->OperationalError, +@@ -2070,7 +2112,7 @@ + Py_END_ALLOW_THREADS + + if (bck_handle == NULL) { +- _pysqlite_seterror(self->state, bck_conn); ++ set_error_from_db(self->state, bck_conn); + return NULL; + } + +@@ -2108,7 +2150,7 @@ + Py_END_ALLOW_THREADS + + if (rc != SQLITE_OK) { +- _pysqlite_seterror(self->state, bck_conn); ++ set_error_from_db(self->state, bck_conn); + return NULL; + } + +@@ -2166,7 +2208,7 @@ + if (callable != Py_None) { + free_callback_context(ctx); + } +- _pysqlite_seterror(self->state, self->db); ++ set_error_from_db(self->state, self->db); + return NULL; + } + +@@ -2284,7 +2326,7 @@ + Py_END_ALLOW_THREADS + + if (rc != SQLITE_OK) { +- (void)_pysqlite_seterror(self->state, self->db); ++ set_error_from_db(self->state, self->db); + return NULL; + } + Py_RETURN_NONE; +@@ -2479,7 +2521,7 @@ + int actual; + int rc = sqlite3_db_config(self->db, op, enable, &actual); + if (rc != SQLITE_OK) { +- (void)_pysqlite_seterror(self->state, self->db); ++ set_error_from_db(self->state, self->db); + return NULL; + } + if (enable != actual) { +@@ -2514,15 +2556,16 @@ + int current; + int rc = sqlite3_db_config(self->db, op, -1, ¤t); + if (rc != SQLITE_OK) { +- (void)_pysqlite_seterror(self->state, self->db); ++ set_error_from_db(self->state, self->db); + return -1; + } + return current; + } + + static PyObject * +-get_autocommit(pysqlite_Connection *self, void *Py_UNUSED(ctx)) ++get_autocommit(PyObject *op, void *Py_UNUSED(closure)) + { ++ pysqlite_Connection *self = _pysqlite_Connection_CAST(op); + if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { + return NULL; + } +@@ -2536,8 +2579,9 @@ + } + + static int +-set_autocommit(pysqlite_Connection *self, PyObject *val, void *Py_UNUSED(ctx)) ++set_autocommit(PyObject *op, PyObject *val, void *Py_UNUSED(closure)) + { ++ pysqlite_Connection *self = _pysqlite_Connection_CAST(op); + if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { + return -1; + } +@@ -2562,7 +2606,7 @@ + } + + static PyObject * +-get_sig(PyObject *self, void *Py_UNUSED(ctx)) ++get_sig(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) + { + return PyUnicode_FromString("(sql, /)"); + } +@@ -2572,11 +2616,12 @@ + PyDoc_STR("SQLite database connection object."); + + static PyGetSetDef connection_getset[] = { +- {"isolation_level", (getter)pysqlite_connection_get_isolation_level, (setter)pysqlite_connection_set_isolation_level}, +- {"total_changes", (getter)pysqlite_connection_get_total_changes, (setter)0}, +- {"in_transaction", (getter)pysqlite_connection_get_in_transaction, (setter)0}, +- {"autocommit", (getter)get_autocommit, (setter)set_autocommit}, +- {"__text_signature__", get_sig, (setter)0}, ++ {"isolation_level", pysqlite_connection_get_isolation_level, ++ pysqlite_connection_set_isolation_level}, ++ {"total_changes", pysqlite_connection_get_total_changes, NULL}, ++ {"in_transaction", pysqlite_connection_get_in_transaction, NULL}, ++ {"autocommit", get_autocommit, set_autocommit}, ++ {"__text_signature__", get_sig, NULL}, + {NULL} + }; + +diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c +index 0fbd408f18c..ad3587d88dd 100644 +--- a/Modules/_sqlite/cursor.c ++++ b/Modules/_sqlite/cursor.c +@@ -44,6 +44,8 @@ + #include "clinic/cursor.c.h" + #undef clinic_state + ++#define _pysqlite_Cursor_CAST(op) ((pysqlite_Cursor *)(op)) ++ + static inline int + check_cursor_locked(pysqlite_Cursor *cur) + { +@@ -146,8 +148,9 @@ + } + + static int +-cursor_traverse(pysqlite_Cursor *self, visitproc visit, void *arg) ++cursor_traverse(PyObject *op, visitproc visit, void *arg) + { ++ pysqlite_Cursor *self = _pysqlite_Cursor_CAST(op); + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->connection); + Py_VISIT(self->description); +@@ -159,8 +162,9 @@ + } + + static int +-cursor_clear(pysqlite_Cursor *self) ++cursor_clear(PyObject *op) + { ++ pysqlite_Cursor *self = _pysqlite_Cursor_CAST(op); + Py_CLEAR(self->connection); + Py_CLEAR(self->description); + Py_CLEAR(self->row_cast_map); +@@ -176,14 +180,15 @@ + } + + static void +-cursor_dealloc(pysqlite_Cursor *self) ++cursor_dealloc(PyObject *op) + { ++ pysqlite_Cursor *self = _pysqlite_Cursor_CAST(op); + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + if (self->in_weakreflist != NULL) { +- PyObject_ClearWeakRefs((PyObject*)self); ++ PyObject_ClearWeakRefs(op); + } +- tp->tp_clear((PyObject *)self); ++ (void)tp->tp_clear(op); + tp->tp_free(self); + Py_DECREF(tp); + } +@@ -500,7 +505,7 @@ + Py_END_ALLOW_THREADS + + if (rc != SQLITE_OK) { +- (void)_pysqlite_seterror(self->state, self->db); ++ set_error_from_db(self->state, self->db); + return -1; + } + +@@ -710,7 +715,7 @@ + if (rc != SQLITE_OK) { + PyObject *exc = PyErr_GetRaisedException(); + sqlite3 *db = sqlite3_db_handle(self->st); +- _pysqlite_seterror(state, db); ++ set_error_from_db(state, db); + _PyErr_ChainExceptions1(exc); + return; + } +@@ -759,7 +764,7 @@ + if (rc != SQLITE_OK) { + PyObject *exc = PyErr_GetRaisedException(); + sqlite3 *db = sqlite3_db_handle(self->st); +- _pysqlite_seterror(state, db); ++ set_error_from_db(state, db); + _PyErr_ChainExceptions1(exc); + return; + } +@@ -891,7 +896,7 @@ + PyErr_Clear(); + } + } +- _pysqlite_seterror(state, self->connection->db); ++ set_error_from_db(state, self->connection->db); + goto error; + } + +@@ -1082,13 +1087,14 @@ + return Py_NewRef((PyObject *)self); + + error: +- _pysqlite_seterror(self->connection->state, db); ++ set_error_from_db(self->connection->state, db); + return NULL; + } + + static PyObject * +-pysqlite_cursor_iternext(pysqlite_Cursor *self) ++pysqlite_cursor_iternext(PyObject *op) + { ++ pysqlite_Cursor *self = _pysqlite_Cursor_CAST(op); + if (!check_cursor(self)) { + return NULL; + } +@@ -1116,8 +1122,7 @@ + Py_CLEAR(self->statement); + } + else if (rc != SQLITE_ROW) { +- (void)_pysqlite_seterror(self->connection->state, +- self->connection->db); ++ set_error_from_db(self->connection->state, self->connection->db); + (void)stmt_reset(self->statement); + Py_CLEAR(self->statement); + Py_DECREF(row); +@@ -1125,7 +1130,7 @@ + } + if (!Py_IsNone(self->row_factory)) { + PyObject *factory = self->row_factory; +- PyObject *args[] = { (PyObject *)self, row, }; ++ PyObject *args[] = { op, row, }; + PyObject *new_row = PyObject_Vectorcall(factory, args, 2, NULL); + Py_SETREF(row, new_row); + } +@@ -1144,7 +1149,7 @@ + { + PyObject* row; + +- row = pysqlite_cursor_iternext(self); ++ row = pysqlite_cursor_iternext((PyObject *)self); + if (!row && !PyErr_Occurred()) { + Py_RETURN_NONE; + } +@@ -1155,7 +1160,7 @@ + /*[clinic input] + _sqlite3.Cursor.fetchmany as pysqlite_cursor_fetchmany + +- size as maxrows: int(c_default='self->arraysize') = 1 ++ size as maxrows: int(c_default='((pysqlite_Cursor *)self)->arraysize') = 1 + The default value is set by the Cursor.arraysize attribute. + + Fetches several rows from the resultset. +@@ -1163,7 +1168,7 @@ + + static PyObject * + pysqlite_cursor_fetchmany_impl(pysqlite_Cursor *self, int maxrows) +-/*[clinic end generated code: output=a8ef31fea64d0906 input=c26e6ca3f34debd0]*/ ++/*[clinic end generated code: output=a8ef31fea64d0906 input=035dbe44a1005bf2]*/ + { + PyObject* row; + PyObject* list; +@@ -1174,7 +1179,7 @@ + return NULL; + } + +- while ((row = pysqlite_cursor_iternext(self))) { ++ while ((row = pysqlite_cursor_iternext((PyObject *)self))) { + if (PyList_Append(list, row) < 0) { + Py_DECREF(row); + break; +@@ -1212,7 +1217,7 @@ + return NULL; + } + +- while ((row = pysqlite_cursor_iternext(self))) { ++ while ((row = pysqlite_cursor_iternext((PyObject *)self))) { + if (PyList_Append(list, row) < 0) { + Py_DECREF(row); + break; +diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c +index 698e81d9b89..27e8dab92e0 100644 +--- a/Modules/_sqlite/module.c ++++ b/Modules/_sqlite/module.c +@@ -33,8 +33,6 @@ + #include "row.h" + #include "blob.h" + +-#include "pycore_import.h" // _PyImport_GetModuleAttrString() +- + #if SQLITE_VERSION_NUMBER < 3015002 + #error "SQLite 3.15.2 or higher required" + #endif +@@ -234,7 +232,7 @@ + load_functools_lru_cache(PyObject *module) + { + pysqlite_state *state = pysqlite_get_state(module); +- state->lru_cache = _PyImport_GetModuleAttrString("functools", "lru_cache"); ++ state->lru_cache = PyImport_ImportModuleAttrString("functools", "lru_cache"); + if (state->lru_cache == NULL) { + return -1; + } +@@ -619,7 +617,7 @@ + static void + module_free(void *module) + { +- module_clear((PyObject *)module); ++ (void)module_clear((PyObject *)module); + } + + #define ADD_TYPE(module, type) \ +diff --git a/Modules/_sqlite/prepare_protocol.c b/Modules/_sqlite/prepare_protocol.c +index 44533225665..31092417cb4 100644 +--- a/Modules/_sqlite/prepare_protocol.c ++++ b/Modules/_sqlite/prepare_protocol.c +@@ -24,8 +24,7 @@ + #include "prepare_protocol.h" + + static int +-pysqlite_prepare_protocol_init(pysqlite_PrepareProtocol *self, PyObject *args, +- PyObject *kwargs) ++pysqlite_prepare_protocol_init(PyObject *self, PyObject *args, PyObject *kwargs) + { + return 0; + } +@@ -38,7 +37,7 @@ + } + + static void +-pysqlite_prepare_protocol_dealloc(pysqlite_PrepareProtocol *self) ++pysqlite_prepare_protocol_dealloc(PyObject *self) + { + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); +diff --git a/Modules/_sqlite/row.c b/Modules/_sqlite/row.c +index 14555076a7e..94565a01d18 100644 +--- a/Modules/_sqlite/row.c ++++ b/Modules/_sqlite/row.c +@@ -32,6 +32,8 @@ + #include "clinic/row.c.h" + #undef clinic_state + ++#define _pysqlite_Row_CAST(op) ((pysqlite_Row *)(op)) ++ + /*[clinic input] + module _sqlite3 + class _sqlite3.Row "pysqlite_Row *" "clinic_state()->RowType" +@@ -39,16 +41,18 @@ + /*[clinic end generated code: output=da39a3ee5e6b4b0d input=966c53403d7f3a40]*/ + + static int +-row_clear(pysqlite_Row *self) ++row_clear(PyObject *op) + { ++ pysqlite_Row *self = _pysqlite_Row_CAST(op); + Py_CLEAR(self->data); + Py_CLEAR(self->description); + return 0; + } + + static int +-row_traverse(pysqlite_Row *self, visitproc visit, void *arg) ++row_traverse(PyObject *op, visitproc visit, void *arg) + { ++ pysqlite_Row *self = _pysqlite_Row_CAST(op); + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->data); + Py_VISIT(self->description); +@@ -60,7 +64,7 @@ + { + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); +- tp->tp_clear(self); ++ (void)tp->tp_clear(self); + tp->tp_free(self); + Py_DECREF(tp); + } +@@ -94,10 +98,12 @@ + return (PyObject *) self; + } + +-PyObject* pysqlite_row_item(pysqlite_Row* self, Py_ssize_t idx) ++static PyObject * ++pysqlite_row_item(PyObject *op, Py_ssize_t idx) + { +- PyObject *item = PyTuple_GetItem(self->data, idx); +- return Py_XNewRef(item); ++ pysqlite_Row *self = _pysqlite_Row_CAST(op); ++ PyObject *item = PyTuple_GetItem(self->data, idx); ++ return Py_XNewRef(item); + } + + static int +@@ -129,10 +135,10 @@ + } + + static PyObject * +-pysqlite_row_subscript(pysqlite_Row *self, PyObject *idx) ++pysqlite_row_subscript(PyObject *op, PyObject *idx) + { + Py_ssize_t _idx; +- Py_ssize_t nitems, i; ++ pysqlite_Row *self = _pysqlite_Row_CAST(op); + + if (PyLong_Check(idx)) { + _idx = PyNumber_AsSsize_t(idx, PyExc_IndexError); +@@ -144,9 +150,13 @@ + PyObject *item = PyTuple_GetItem(self->data, _idx); + return Py_XNewRef(item); + } else if (PyUnicode_Check(idx)) { +- nitems = PyTuple_Size(self->description); ++ if (Py_IsNone(self->description)) { ++ PyErr_Format(PyExc_IndexError, "No item with key %R", idx); ++ return NULL; ++ } ++ Py_ssize_t nitems = PyTuple_GET_SIZE(self->description); + +- for (i = 0; i < nitems; i++) { ++ for (Py_ssize_t i = 0; i < nitems; i++) { + PyObject *obj; + obj = PyTuple_GET_ITEM(self->description, i); + obj = PyTuple_GET_ITEM(obj, 0); +@@ -174,8 +184,9 @@ + } + + static Py_ssize_t +-pysqlite_row_length(pysqlite_Row* self) ++pysqlite_row_length(PyObject *op) + { ++ pysqlite_Row *self = _pysqlite_Row_CAST(op); + return PyTuple_GET_SIZE(self->data); + } + +@@ -189,17 +200,19 @@ + pysqlite_row_keys_impl(pysqlite_Row *self) + /*[clinic end generated code: output=efe3dfb3af6edc07 input=7549a122827c5563]*/ + { +- PyObject* list; +- Py_ssize_t nitems, i; +- +- list = PyList_New(0); ++ PyObject *list = PyList_New(0); + if (!list) { + return NULL; + } +- nitems = PyTuple_Size(self->description); ++ if (Py_IsNone(self->description)) { ++ return list; ++ } + +- for (i = 0; i < nitems; i++) { +- if (PyList_Append(list, PyTuple_GET_ITEM(PyTuple_GET_ITEM(self->description, i), 0)) != 0) { ++ Py_ssize_t nitems = PyTuple_GET_SIZE(self->description); ++ for (Py_ssize_t i = 0; i < nitems; i++) { ++ PyObject *descr = PyTuple_GET_ITEM(self->description, i); ++ PyObject *name = PyTuple_GET_ITEM(descr, 0); ++ if (PyList_Append(list, name) < 0) { + Py_DECREF(list); + return NULL; + } +@@ -208,24 +221,30 @@ + return list; + } + +-static PyObject* pysqlite_iter(pysqlite_Row* self) ++static PyObject * ++pysqlite_iter(PyObject *op) + { ++ pysqlite_Row *self = _pysqlite_Row_CAST(op); + return PyObject_GetIter(self->data); + } + +-static Py_hash_t pysqlite_row_hash(pysqlite_Row *self) ++static Py_hash_t ++pysqlite_row_hash(PyObject *op) + { ++ pysqlite_Row *self = _pysqlite_Row_CAST(op); + return PyObject_Hash(self->description) ^ PyObject_Hash(self->data); + } + +-static PyObject* pysqlite_row_richcompare(pysqlite_Row *self, PyObject *_other, int opid) ++static PyObject * ++pysqlite_row_richcompare(PyObject *op, PyObject *opother, int opid) + { + if (opid != Py_EQ && opid != Py_NE) + Py_RETURN_NOTIMPLEMENTED; + ++ pysqlite_Row *self = _pysqlite_Row_CAST(op); + pysqlite_state *state = pysqlite_get_state_by_type(Py_TYPE(self)); +- if (PyObject_TypeCheck(_other, state->RowType)) { +- pysqlite_Row *other = (pysqlite_Row *)_other; ++ if (PyObject_TypeCheck(opother, state->RowType)) { ++ pysqlite_Row *other = (pysqlite_Row *)opother; + int eq = PyObject_RichCompareBool(self->description, other->description, Py_EQ); + if (eq < 0) { + return NULL; +diff --git a/Modules/_sqlite/statement.c b/Modules/_sqlite/statement.c +index 229bfc3b504..736e60fd778 100644 +--- a/Modules/_sqlite/statement.c ++++ b/Modules/_sqlite/statement.c +@@ -25,6 +25,8 @@ + #include "statement.h" + #include "util.h" + ++#define _pysqlite_Statement_CAST(op) ((pysqlite_Statement *)(op)) ++ + /* prototypes */ + static const char *lstrip_sql(const char *sql); + +@@ -60,7 +62,7 @@ + Py_END_ALLOW_THREADS + + if (rc != SQLITE_OK) { +- _pysqlite_seterror(state, db); ++ set_error_from_db(state, db); + return NULL; + } + +@@ -99,10 +101,11 @@ + } + + static void +-stmt_dealloc(pysqlite_Statement *self) ++stmt_dealloc(PyObject *op) + { ++ pysqlite_Statement *self = _pysqlite_Statement_CAST(op); + PyTypeObject *tp = Py_TYPE(self); +- PyObject_GC_UnTrack(self); ++ PyObject_GC_UnTrack(op); + if (self->st) { + Py_BEGIN_ALLOW_THREADS + sqlite3_finalize(self->st); +@@ -114,7 +117,7 @@ + } + + static int +-stmt_traverse(pysqlite_Statement *self, visitproc visit, void *arg) ++stmt_traverse(PyObject *self, visitproc visit, void *arg) + { + Py_VISIT(Py_TYPE(self)); + return 0; +diff --git a/Modules/_sqlite/util.c b/Modules/_sqlite/util.c +index 9e8613ef679..103248ff55a 100644 +--- a/Modules/_sqlite/util.c ++++ b/Modules/_sqlite/util.c +@@ -118,25 +118,38 @@ + Py_XDECREF(exc); + } + ++void ++set_error_from_code(pysqlite_state *state, int code) ++{ ++ PyObject *exc_class = get_exception_class(state, code); ++ if (exc_class == NULL) { ++ // No new exception need be raised. ++ return; ++ } ++ ++ const char *errmsg = sqlite3_errstr(code); ++ assert(errmsg != NULL); ++ raise_exception(exc_class, code, errmsg); ++} ++ + /** + * Checks the SQLite error code and sets the appropriate DB-API exception. +- * Returns the error code (0 means no error occurred). + */ +-int +-_pysqlite_seterror(pysqlite_state *state, sqlite3 *db) ++void ++set_error_from_db(pysqlite_state *state, sqlite3 *db) + { + int errorcode = sqlite3_errcode(db); + PyObject *exc_class = get_exception_class(state, errorcode); + if (exc_class == NULL) { +- // No new exception need be raised; just pass the error code +- return errorcode; ++ // No new exception need be raised. ++ return; + } + + /* Create and set the exception. */ + int extended_errcode = sqlite3_extended_errcode(db); ++ // sqlite3_errmsg() always returns an UTF-8 encoded message + const char *errmsg = sqlite3_errmsg(db); + raise_exception(exc_class, extended_errcode, errmsg); +- return extended_errcode; + } + + #ifdef WORDS_BIGENDIAN +diff --git a/Modules/_sqlite/util.h b/Modules/_sqlite/util.h +index 68b1a8cb67a..f8e45baffae 100644 +--- a/Modules/_sqlite/util.h ++++ b/Modules/_sqlite/util.h +@@ -30,9 +30,9 @@ + + /** + * Checks the SQLite error code and sets the appropriate DB-API exception. +- * Returns the error code (0 means no error occurred). + */ +-int _pysqlite_seterror(pysqlite_state *state, sqlite3 *db); ++void set_error_from_db(pysqlite_state *state, sqlite3 *db); ++void set_error_from_code(pysqlite_state *state, int code); + + sqlite_int64 _pysqlite_long_as_int64(PyObject * value); + +diff --git a/Modules/_sre/clinic/sre.c.h b/Modules/_sre/clinic/sre.c.h +index 87e4785a428..cfc6813f37f 100644 +--- a/Modules/_sre/clinic/sre.c.h ++++ b/Modules/_sre/clinic/sre.c.h +@@ -179,7 +179,7 @@ + Py_ssize_t endpos); + + static PyObject * +-_sre_SRE_Pattern_match(PatternObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_sre_SRE_Pattern_match(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -252,7 +252,7 @@ + endpos = ival; + } + skip_optional_pos: +- return_value = _sre_SRE_Pattern_match_impl(self, cls, string, pos, endpos); ++ return_value = _sre_SRE_Pattern_match_impl((PatternObject *)self, cls, string, pos, endpos); + + exit: + return return_value; +@@ -273,7 +273,7 @@ + Py_ssize_t endpos); + + static PyObject * +-_sre_SRE_Pattern_fullmatch(PatternObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_sre_SRE_Pattern_fullmatch(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -346,7 +346,7 @@ + endpos = ival; + } + skip_optional_pos: +- return_value = _sre_SRE_Pattern_fullmatch_impl(self, cls, string, pos, endpos); ++ return_value = _sre_SRE_Pattern_fullmatch_impl((PatternObject *)self, cls, string, pos, endpos); + + exit: + return return_value; +@@ -369,7 +369,7 @@ + Py_ssize_t endpos); + + static PyObject * +-_sre_SRE_Pattern_search(PatternObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_sre_SRE_Pattern_search(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -442,7 +442,7 @@ + endpos = ival; + } + skip_optional_pos: +- return_value = _sre_SRE_Pattern_search_impl(self, cls, string, pos, endpos); ++ return_value = _sre_SRE_Pattern_search_impl((PatternObject *)self, cls, string, pos, endpos); + + exit: + return return_value; +@@ -462,7 +462,7 @@ + Py_ssize_t pos, Py_ssize_t endpos); + + static PyObject * +-_sre_SRE_Pattern_findall(PatternObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_sre_SRE_Pattern_findall(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -535,7 +535,7 @@ + endpos = ival; + } + skip_optional_pos: +- return_value = _sre_SRE_Pattern_findall_impl(self, string, pos, endpos); ++ return_value = _sre_SRE_Pattern_findall_impl((PatternObject *)self, string, pos, endpos); + + exit: + return return_value; +@@ -558,7 +558,7 @@ + Py_ssize_t endpos); + + static PyObject * +-_sre_SRE_Pattern_finditer(PatternObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_sre_SRE_Pattern_finditer(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -631,7 +631,7 @@ + endpos = ival; + } + skip_optional_pos: +- return_value = _sre_SRE_Pattern_finditer_impl(self, cls, string, pos, endpos); ++ return_value = _sre_SRE_Pattern_finditer_impl((PatternObject *)self, cls, string, pos, endpos); + + exit: + return return_value; +@@ -651,7 +651,7 @@ + Py_ssize_t endpos); + + static PyObject * +-_sre_SRE_Pattern_scanner(PatternObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_sre_SRE_Pattern_scanner(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -724,7 +724,7 @@ + endpos = ival; + } + skip_optional_pos: +- return_value = _sre_SRE_Pattern_scanner_impl(self, cls, string, pos, endpos); ++ return_value = _sre_SRE_Pattern_scanner_impl((PatternObject *)self, cls, string, pos, endpos); + + exit: + return return_value; +@@ -744,7 +744,7 @@ + Py_ssize_t maxsplit); + + static PyObject * +-_sre_SRE_Pattern_split(PatternObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_sre_SRE_Pattern_split(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -799,7 +799,7 @@ + maxsplit = ival; + } + skip_optional_pos: +- return_value = _sre_SRE_Pattern_split_impl(self, string, maxsplit); ++ return_value = _sre_SRE_Pattern_split_impl((PatternObject *)self, string, maxsplit); + + exit: + return return_value; +@@ -819,7 +819,7 @@ + PyObject *repl, PyObject *string, Py_ssize_t count); + + static PyObject * +-_sre_SRE_Pattern_sub(PatternObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_sre_SRE_Pattern_sub(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -876,7 +876,7 @@ + count = ival; + } + skip_optional_pos: +- return_value = _sre_SRE_Pattern_sub_impl(self, cls, repl, string, count); ++ return_value = _sre_SRE_Pattern_sub_impl((PatternObject *)self, cls, repl, string, count); + + exit: + return return_value; +@@ -897,7 +897,7 @@ + Py_ssize_t count); + + static PyObject * +-_sre_SRE_Pattern_subn(PatternObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_sre_SRE_Pattern_subn(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -954,7 +954,7 @@ + count = ival; + } + skip_optional_pos: +- return_value = _sre_SRE_Pattern_subn_impl(self, cls, repl, string, count); ++ return_value = _sre_SRE_Pattern_subn_impl((PatternObject *)self, cls, repl, string, count); + + exit: + return return_value; +@@ -972,9 +972,9 @@ + _sre_SRE_Pattern___copy___impl(PatternObject *self); + + static PyObject * +-_sre_SRE_Pattern___copy__(PatternObject *self, PyObject *Py_UNUSED(ignored)) ++_sre_SRE_Pattern___copy__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _sre_SRE_Pattern___copy___impl(self); ++ return _sre_SRE_Pattern___copy___impl((PatternObject *)self); + } + + PyDoc_STRVAR(_sre_SRE_Pattern___deepcopy____doc__, +@@ -1001,7 +1001,7 @@ + PyObject *exception); + + static PyObject * +-_sre_SRE_Pattern__fail_after(PatternObject *self, PyObject *const *args, Py_ssize_t nargs) ++_sre_SRE_Pattern__fail_after(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + int count; +@@ -1015,7 +1015,7 @@ + goto exit; + } + exception = args[1]; +- return_value = _sre_SRE_Pattern__fail_after_impl(self, count, exception); ++ return_value = _sre_SRE_Pattern__fail_after_impl((PatternObject *)self, count, exception); + + exit: + return return_value; +@@ -1169,7 +1169,7 @@ + _sre_SRE_Match_expand_impl(MatchObject *self, PyObject *template); + + static PyObject * +-_sre_SRE_Match_expand(MatchObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_sre_SRE_Match_expand(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -1206,7 +1206,7 @@ + goto exit; + } + template = args[0]; +- return_value = _sre_SRE_Match_expand_impl(self, template); ++ return_value = _sre_SRE_Match_expand_impl((MatchObject *)self, template); + + exit: + return return_value; +@@ -1228,7 +1228,7 @@ + _sre_SRE_Match_groups_impl(MatchObject *self, PyObject *default_value); + + static PyObject * +-_sre_SRE_Match_groups(MatchObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_sre_SRE_Match_groups(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -1270,7 +1270,7 @@ + } + default_value = args[0]; + skip_optional_pos: +- return_value = _sre_SRE_Match_groups_impl(self, default_value); ++ return_value = _sre_SRE_Match_groups_impl((MatchObject *)self, default_value); + + exit: + return return_value; +@@ -1292,7 +1292,7 @@ + _sre_SRE_Match_groupdict_impl(MatchObject *self, PyObject *default_value); + + static PyObject * +-_sre_SRE_Match_groupdict(MatchObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_sre_SRE_Match_groupdict(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -1334,7 +1334,7 @@ + } + default_value = args[0]; + skip_optional_pos: +- return_value = _sre_SRE_Match_groupdict_impl(self, default_value); ++ return_value = _sre_SRE_Match_groupdict_impl((MatchObject *)self, default_value); + + exit: + return return_value; +@@ -1353,7 +1353,7 @@ + _sre_SRE_Match_start_impl(MatchObject *self, PyObject *group); + + static PyObject * +-_sre_SRE_Match_start(MatchObject *self, PyObject *const *args, Py_ssize_t nargs) ++_sre_SRE_Match_start(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *group = NULL; +@@ -1367,7 +1367,7 @@ + } + group = args[0]; + skip_optional: +- _return_value = _sre_SRE_Match_start_impl(self, group); ++ _return_value = _sre_SRE_Match_start_impl((MatchObject *)self, group); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } +@@ -1390,7 +1390,7 @@ + _sre_SRE_Match_end_impl(MatchObject *self, PyObject *group); + + static PyObject * +-_sre_SRE_Match_end(MatchObject *self, PyObject *const *args, Py_ssize_t nargs) ++_sre_SRE_Match_end(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *group = NULL; +@@ -1404,7 +1404,7 @@ + } + group = args[0]; + skip_optional: +- _return_value = _sre_SRE_Match_end_impl(self, group); ++ _return_value = _sre_SRE_Match_end_impl((MatchObject *)self, group); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } +@@ -1427,7 +1427,7 @@ + _sre_SRE_Match_span_impl(MatchObject *self, PyObject *group); + + static PyObject * +-_sre_SRE_Match_span(MatchObject *self, PyObject *const *args, Py_ssize_t nargs) ++_sre_SRE_Match_span(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *group = NULL; +@@ -1440,7 +1440,7 @@ + } + group = args[0]; + skip_optional: +- return_value = _sre_SRE_Match_span_impl(self, group); ++ return_value = _sre_SRE_Match_span_impl((MatchObject *)self, group); + + exit: + return return_value; +@@ -1458,9 +1458,9 @@ + _sre_SRE_Match___copy___impl(MatchObject *self); + + static PyObject * +-_sre_SRE_Match___copy__(MatchObject *self, PyObject *Py_UNUSED(ignored)) ++_sre_SRE_Match___copy__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _sre_SRE_Match___copy___impl(self); ++ return _sre_SRE_Match___copy___impl((MatchObject *)self); + } + + PyDoc_STRVAR(_sre_SRE_Match___deepcopy____doc__, +@@ -1483,13 +1483,13 @@ + _sre_SRE_Scanner_match_impl(ScannerObject *self, PyTypeObject *cls); + + static PyObject * +-_sre_SRE_Scanner_match(ScannerObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_sre_SRE_Scanner_match(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "match() takes no arguments"); + return NULL; + } +- return _sre_SRE_Scanner_match_impl(self, cls); ++ return _sre_SRE_Scanner_match_impl((ScannerObject *)self, cls); + } + + PyDoc_STRVAR(_sre_SRE_Scanner_search__doc__, +@@ -1504,16 +1504,16 @@ + _sre_SRE_Scanner_search_impl(ScannerObject *self, PyTypeObject *cls); + + static PyObject * +-_sre_SRE_Scanner_search(ScannerObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_sre_SRE_Scanner_search(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "search() takes no arguments"); + return NULL; + } +- return _sre_SRE_Scanner_search_impl(self, cls); ++ return _sre_SRE_Scanner_search_impl((ScannerObject *)self, cls); + } + + #ifndef _SRE_SRE_PATTERN__FAIL_AFTER_METHODDEF + #define _SRE_SRE_PATTERN__FAIL_AFTER_METHODDEF + #endif /* !defined(_SRE_SRE_PATTERN__FAIL_AFTER_METHODDEF) */ +-/*[clinic end generated code: output=f8cb77f2261f0b2e input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=3654103c87eb4830 input=a9049054013a1b77]*/ +diff --git a/Modules/_sre/sre.c b/Modules/_sre/sre.c +index 36f542ddb4d..0d8d4843d33 100644 +--- a/Modules/_sre/sre.c ++++ b/Modules/_sre/sre.c +@@ -395,6 +395,11 @@ + static PyObject*pattern_new_match(_sremodulestate *, PatternObject*, SRE_STATE*, Py_ssize_t); + static PyObject *pattern_scanner(_sremodulestate *, PatternObject *, PyObject *, Py_ssize_t, Py_ssize_t); + ++#define _PatternObject_CAST(op) ((PatternObject *)(op)) ++#define _MatchObject_CAST(op) ((MatchObject *)(op)) ++#define _TemplateObject_CAST(op) ((TemplateObject *)(op)) ++#define _ScannerObject_CAST(op) ((ScannerObject *)(op)) ++ + /*[clinic input] + module _sre + class _sre.SRE_Pattern "PatternObject *" "get_sre_module_state_by_class(tp)->Pattern_Type" +@@ -699,8 +704,9 @@ + } + + static int +-pattern_traverse(PatternObject *self, visitproc visit, void *arg) ++pattern_traverse(PyObject *op, visitproc visit, void *arg) + { ++ PatternObject *self = _PatternObject_CAST(op); + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->groupindex); + Py_VISIT(self->indexgroup); +@@ -712,8 +718,9 @@ + } + + static int +-pattern_clear(PatternObject *self) ++pattern_clear(PyObject *op) + { ++ PatternObject *self = _PatternObject_CAST(op); + Py_CLEAR(self->groupindex); + Py_CLEAR(self->indexgroup); + Py_CLEAR(self->pattern); +@@ -724,13 +731,13 @@ + } + + static void +-pattern_dealloc(PatternObject* self) ++pattern_dealloc(PyObject *self) + { + PyTypeObject *tp = Py_TYPE(self); +- + PyObject_GC_UnTrack(self); +- if (self->weakreflist != NULL) { +- PyObject_ClearWeakRefs((PyObject *) self); ++ PatternObject *obj = _PatternObject_CAST(self); ++ if (obj->weakreflist != NULL) { ++ PyObject_ClearWeakRefs(self); + } + (void)pattern_clear(self); + tp->tp_free(self); +@@ -1162,7 +1169,7 @@ + /* delegate to Python code */ + PyObject *func = module_state->compile_template; + if (func == NULL) { +- func = _PyImport_GetModuleAttrString("re", "_compile_template"); ++ func = PyImport_ImportModuleAttrString("re", "_compile_template"); + if (func == NULL) { + return NULL; + } +@@ -1497,7 +1504,7 @@ + #endif /* Py_DEBUG */ + + static PyObject * +-pattern_repr(PatternObject *obj) ++pattern_repr(PyObject *self) + { + static const struct { + const char *name; +@@ -1512,6 +1519,8 @@ + {"re.DEBUG", SRE_FLAG_DEBUG}, + {"re.ASCII", SRE_FLAG_ASCII}, + }; ++ ++ PatternObject *obj = _PatternObject_CAST(self); + PyObject *result = NULL; + PyObject *flag_items; + size_t i; +@@ -1579,8 +1588,9 @@ + + /* PatternObject's 'groupindex' method. */ + static PyObject * +-pattern_groupindex(PatternObject *self, void *Py_UNUSED(ignored)) ++pattern_groupindex(PyObject *op, void *Py_UNUSED(ignored)) + { ++ PatternObject *self = _PatternObject_CAST(op); + if (self->groupindex == NULL) + return PyDict_New(); + return PyDictProxy_New(self->groupindex); +@@ -2245,8 +2255,9 @@ + /* match methods */ + + static int +-match_traverse(MatchObject *self, visitproc visit, void *arg) ++match_traverse(PyObject *op, visitproc visit, void *arg) + { ++ MatchObject *self = _MatchObject_CAST(op); + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->string); + Py_VISIT(self->regs); +@@ -2255,8 +2266,9 @@ + } + + static int +-match_clear(MatchObject *self) ++match_clear(PyObject *op) + { ++ MatchObject *self = _MatchObject_CAST(op); + Py_CLEAR(self->string); + Py_CLEAR(self->regs); + Py_CLEAR(self->pattern); +@@ -2264,10 +2276,9 @@ + } + + static void +-match_dealloc(MatchObject* self) ++match_dealloc(PyObject *self) + { + PyTypeObject *tp = Py_TYPE(self); +- + PyObject_GC_UnTrack(self); + (void)match_clear(self); + tp->tp_free(self); +@@ -2376,8 +2387,9 @@ + } + + static PyObject* +-match_group(MatchObject* self, PyObject* args) ++match_group(PyObject *op, PyObject* args) + { ++ MatchObject *self = _MatchObject_CAST(op); + PyObject* result; + Py_ssize_t i, size; + +@@ -2411,8 +2423,9 @@ + } + + static PyObject* +-match_getitem(MatchObject* self, PyObject* name) ++match_getitem(PyObject *op, PyObject* name) + { ++ MatchObject *self = _MatchObject_CAST(op); + return match_getslice(self, name, Py_None); + } + +@@ -2654,16 +2667,18 @@ + For 0 returns the entire match."); + + static PyObject * +-match_lastindex_get(MatchObject *self, void *Py_UNUSED(ignored)) ++match_lastindex_get(PyObject *op, void *Py_UNUSED(ignored)) + { ++ MatchObject *self = _MatchObject_CAST(op); + if (self->lastindex >= 0) + return PyLong_FromSsize_t(self->lastindex); + Py_RETURN_NONE; + } + + static PyObject * +-match_lastgroup_get(MatchObject *self, void *Py_UNUSED(ignored)) ++match_lastgroup_get(PyObject *op, void *Py_UNUSED(ignored)) + { ++ MatchObject *self = _MatchObject_CAST(op); + if (self->pattern->indexgroup && + self->lastindex >= 0 && + self->lastindex < PyTuple_GET_SIZE(self->pattern->indexgroup)) +@@ -2676,8 +2691,9 @@ + } + + static PyObject * +-match_regs_get(MatchObject *self, void *Py_UNUSED(ignored)) ++match_regs_get(PyObject *op, void *Py_UNUSED(ignored)) + { ++ MatchObject *self = _MatchObject_CAST(op); + if (self->regs) { + return Py_NewRef(self->regs); + } else +@@ -2780,27 +2796,29 @@ + /* scanner methods (experimental) */ + + static int +-scanner_traverse(ScannerObject *self, visitproc visit, void *arg) ++scanner_traverse(PyObject *op, visitproc visit, void *arg) + { ++ ScannerObject *self = _ScannerObject_CAST(op); + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->pattern); + return 0; + } + + static int +-scanner_clear(ScannerObject *self) ++scanner_clear(PyObject *op) + { ++ ScannerObject *self = _ScannerObject_CAST(op); + Py_CLEAR(self->pattern); + return 0; + } + + static void +-scanner_dealloc(ScannerObject* self) ++scanner_dealloc(PyObject *self) + { + PyTypeObject *tp = Py_TYPE(self); +- + PyObject_GC_UnTrack(self); +- state_fini(&self->state); ++ ScannerObject *scanner = _ScannerObject_CAST(self); ++ state_fini(&scanner->state); + (void)scanner_clear(self); + tp->tp_free(self); + Py_DECREF(tp); +@@ -2957,8 +2975,9 @@ + /* template methods */ + + static int +-template_traverse(TemplateObject *self, visitproc visit, void *arg) ++template_traverse(PyObject *op, visitproc visit, void *arg) + { ++ TemplateObject *self = _TemplateObject_CAST(op); + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->literal); + for (Py_ssize_t i = 0, n = Py_SIZE(self); i < n; i++) { +@@ -2968,8 +2987,9 @@ + } + + static int +-template_clear(TemplateObject *self) ++template_clear(PyObject *op) + { ++ TemplateObject *self = _TemplateObject_CAST(op); + Py_CLEAR(self->literal); + for (Py_ssize_t i = 0, n = Py_SIZE(self); i < n; i++) { + Py_CLEAR(self->items[i].literal); +@@ -2978,10 +2998,9 @@ + } + + static void +-template_dealloc(TemplateObject *self) ++template_dealloc(PyObject *self) + { + PyTypeObject *tp = Py_TYPE(self); +- + PyObject_GC_UnTrack(self); + (void)template_clear(self); + tp->tp_free(self); +@@ -3056,8 +3075,10 @@ + + + static Py_hash_t +-pattern_hash(PatternObject *self) ++pattern_hash(PyObject *op) + { ++ PatternObject *self = _PatternObject_CAST(op); ++ + Py_hash_t hash, hash2; + + hash = PyObject_Hash(self->pattern); +@@ -3148,7 +3169,7 @@ + }; + + static PyGetSetDef pattern_getset[] = { +- {"groupindex", (getter)pattern_groupindex, (setter)NULL, ++ {"groupindex", pattern_groupindex, NULL, + "A dictionary mapping group names to group numbers."}, + {NULL} /* Sentinel */ + }; +@@ -3166,9 +3187,9 @@ + }; + + static PyType_Slot pattern_slots[] = { +- {Py_tp_dealloc, (destructor)pattern_dealloc}, +- {Py_tp_repr, (reprfunc)pattern_repr}, +- {Py_tp_hash, (hashfunc)pattern_hash}, ++ {Py_tp_dealloc, pattern_dealloc}, ++ {Py_tp_repr, pattern_repr}, ++ {Py_tp_hash, pattern_hash}, + {Py_tp_doc, (void *)pattern_doc}, + {Py_tp_richcompare, pattern_richcompare}, + {Py_tp_methods, pattern_methods}, +@@ -3189,7 +3210,7 @@ + }; + + static PyMethodDef match_methods[] = { +- {"group", (PyCFunction) match_group, METH_VARARGS, match_group_doc}, ++ {"group", match_group, METH_VARARGS, match_group_doc}, + _SRE_SRE_MATCH_START_METHODDEF + _SRE_SRE_MATCH_END_METHODDEF + _SRE_SRE_MATCH_SPAN_METHODDEF +@@ -3204,11 +3225,11 @@ + }; + + static PyGetSetDef match_getset[] = { +- {"lastindex", (getter)match_lastindex_get, (setter)NULL, ++ {"lastindex", match_lastindex_get, NULL, + "The integer index of the last matched capturing group."}, +- {"lastgroup", (getter)match_lastgroup_get, (setter)NULL, ++ {"lastgroup", match_lastgroup_get, NULL, + "The name of the last matched capturing group."}, +- {"regs", (getter)match_regs_get, (setter)NULL}, ++ {"regs", match_regs_get, NULL, NULL}, + {NULL} + }; + +diff --git a/Modules/_sre/sre_lib.h b/Modules/_sre/sre_lib.h +index af4bfc56083..df377905bfa 100644 +--- a/Modules/_sre/sre_lib.h ++++ b/Modules/_sre/sre_lib.h +@@ -42,8 +42,6 @@ + return ((void*) ptr == state->end); + + case SRE_AT_BOUNDARY: +- if (state->beginning == state->end) +- return 0; + thatp = ((void*) ptr > state->beginning) ? + SRE_IS_WORD((int) ptr[-1]) : 0; + thisp = ((void*) ptr < state->end) ? +@@ -51,8 +49,6 @@ + return thisp != thatp; + + case SRE_AT_NON_BOUNDARY: +- if (state->beginning == state->end) +- return 0; + thatp = ((void*) ptr > state->beginning) ? + SRE_IS_WORD((int) ptr[-1]) : 0; + thisp = ((void*) ptr < state->end) ? +@@ -60,8 +56,6 @@ + return thisp == thatp; + + case SRE_AT_LOC_BOUNDARY: +- if (state->beginning == state->end) +- return 0; + thatp = ((void*) ptr > state->beginning) ? + SRE_LOC_IS_WORD((int) ptr[-1]) : 0; + thisp = ((void*) ptr < state->end) ? +@@ -69,8 +63,6 @@ + return thisp != thatp; + + case SRE_AT_LOC_NON_BOUNDARY: +- if (state->beginning == state->end) +- return 0; + thatp = ((void*) ptr > state->beginning) ? + SRE_LOC_IS_WORD((int) ptr[-1]) : 0; + thisp = ((void*) ptr < state->end) ? +@@ -78,8 +70,6 @@ + return thisp == thatp; + + case SRE_AT_UNI_BOUNDARY: +- if (state->beginning == state->end) +- return 0; + thatp = ((void*) ptr > state->beginning) ? + SRE_UNI_IS_WORD((int) ptr[-1]) : 0; + thisp = ((void*) ptr < state->end) ? +@@ -87,8 +77,6 @@ + return thisp != thatp; + + case SRE_AT_UNI_NON_BOUNDARY: +- if (state->beginning == state->end) +- return 0; + thatp = ((void*) ptr > state->beginning) ? + SRE_UNI_IS_WORD((int) ptr[-1]) : 0; + thisp = ((void*) ptr < state->end) ? +diff --git a/Modules/_ssl.c b/Modules/_ssl.c +index e7df132869f..85e917fbbb7 100644 +--- a/Modules/_ssl.c ++++ b/Modules/_ssl.c +@@ -473,6 +473,7 @@ + PyObject *err_value = NULL, *reason_obj = NULL, *lib_obj = NULL; + PyObject *verify_obj = NULL, *verify_code_obj = NULL; + PyObject *init_value, *msg, *key; ++ PyUnicodeWriter *writer = NULL; + + if (errcode != 0) { + int lib, reason; +@@ -495,11 +496,10 @@ + if (lib_obj == NULL && PyErr_Occurred()) { + goto fail; + } +- if (errstr == NULL) ++ if (errstr == NULL) { + errstr = ERR_reason_error_string(errcode); ++ } + } +- if (errstr == NULL) +- errstr = "unknown error"; + + /* verify code for cert validation error */ + if ((sslsock != NULL) && (type == state->PySSLCertVerificationErrorObject)) { +@@ -539,20 +539,50 @@ + } + } + +- if (verify_obj && reason_obj && lib_obj) +- msg = PyUnicode_FromFormat("[%S: %S] %s: %S (_ssl.c:%d)", +- lib_obj, reason_obj, errstr, verify_obj, +- lineno); +- else if (reason_obj && lib_obj) +- msg = PyUnicode_FromFormat("[%S: %S] %s (_ssl.c:%d)", +- lib_obj, reason_obj, errstr, lineno); +- else if (lib_obj) +- msg = PyUnicode_FromFormat("[%S] %s (_ssl.c:%d)", +- lib_obj, errstr, lineno); +- else +- msg = PyUnicode_FromFormat("%s (_ssl.c:%d)", errstr, lineno); +- if (msg == NULL) ++ // Format message roughly as: ++ // [lib_obj: reason_obj] errstr: verify_obj (_ssl.c:lineno) ++ // with parts missing/replaced if unavailable ++ writer = PyUnicodeWriter_Create(64); ++ if (!writer) { + goto fail; ++ } ++ if (lib_obj) { ++ if (PyUnicodeWriter_Format(writer, "[%S", lib_obj) < 0) { ++ goto fail; ++ } ++ if (reason_obj) { ++ if (PyUnicodeWriter_Format(writer, ": %S", reason_obj) < 0) { ++ goto fail; ++ } ++ } ++ if (PyUnicodeWriter_WriteUTF8(writer, "] ", 2) < 0) { ++ goto fail; ++ } ++ } ++ if (errstr) { ++ if (PyUnicodeWriter_Format(writer, "%s", errstr) < 0) { ++ goto fail; ++ } ++ } ++ else { ++ if (PyUnicodeWriter_Format( ++ writer, "unknown error (0x%x)", errcode) < 0) { ++ goto fail; ++ } ++ } ++ if (verify_obj) { ++ if (PyUnicodeWriter_Format(writer, ": %S", verify_obj) < 0) { ++ goto fail; ++ } ++ } ++ if (PyUnicodeWriter_Format(writer, " (_ssl.c:%d)", lineno) < 0) { ++ goto fail; ++ } ++ msg = PyUnicodeWriter_Finish(writer); ++ writer = NULL; ++ if (!msg) { ++ goto fail; ++ } + + init_value = Py_BuildValue("iN", ERR_GET_REASON(ssl_errno), msg); + if (init_value == NULL) +@@ -587,6 +617,7 @@ + Py_XDECREF(err_value); + Py_XDECREF(verify_code_obj); + Py_XDECREF(verify_obj); ++ PyUnicodeWriter_Discard(writer); + } + + static int +@@ -934,13 +965,13 @@ + } + } + if (owner && owner != Py_None) { +- if (_ssl__SSLSocket_owner_set(self, owner, NULL) == -1) { ++ if (_ssl__SSLSocket_owner_set((PyObject *)self, owner, NULL) < 0) { + Py_DECREF(self); + return NULL; + } + } + if (session && session != Py_None) { +- if (_ssl__SSLSocket_session_set(self, session, NULL) == -1) { ++ if (_ssl__SSLSocket_session_set((PyObject *)self, session, NULL) < 0) { + Py_DECREF(self); + return NULL; + } +@@ -4377,7 +4408,7 @@ + FILE *f; + DH *dh; + +- f = _Py_fopen_obj(filepath, "rb"); ++ f = Py_fopen(filepath, "rb"); + if (f == NULL) + return NULL; + +@@ -4635,7 +4666,8 @@ + + servername_bytes = PyBytes_FromString(servername); + if (servername_bytes == NULL) { +- PyErr_WriteUnraisable((PyObject *) sslctx); ++ PyErr_FormatUnraisable("Exception ignored " ++ "in ssl servername callback"); + goto error; + } + /* server_hostname was encoded to an A-label by our caller; put it +@@ -4643,7 +4675,10 @@ + */ + servername_str = PyUnicode_FromEncodedObject(servername_bytes, "ascii", NULL); + if (servername_str == NULL) { +- PyErr_WriteUnraisable(servername_bytes); ++ PyErr_FormatUnraisable("Exception ignored " ++ "in ssl servername callback " ++ "while decoding name %R", ++ servername_bytes); + Py_DECREF(servername_bytes); + goto error; + } +@@ -4656,7 +4691,10 @@ + Py_DECREF(ssl_socket); + + if (result == NULL) { +- PyErr_WriteUnraisable(sslctx->set_sni_cb); ++ PyErr_FormatUnraisable("Exception ignored " ++ "in ssl servername callback " ++ "while calling set SNI callback %R", ++ sslctx->set_sni_cb); + *al = SSL_AD_HANDSHAKE_FAILURE; + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + } +@@ -4669,7 +4707,11 @@ + } else { + *al = (int) PyLong_AsLong(result); + if (PyErr_Occurred()) { +- PyErr_WriteUnraisable(result); ++ PyErr_FormatUnraisable("Exception ignored " ++ "in ssl servername callback " ++ "while calling set SNI callback " ++ "(result=%R)", ++ result); + *al = SSL_AD_INTERNAL_ERROR; + } + ret = SSL_TLSEXT_ERR_ALERT_FATAL; +@@ -4976,7 +5018,8 @@ + + error: + if (PyErr_Occurred()) { +- PyErr_WriteUnraisable(callback); ++ PyErr_FormatUnraisable("Exception ignored in ssl PSK client callback " ++ "while calling callback %R", callback); + } + PyGILState_Release(gstate); + return 0; +@@ -5085,7 +5128,8 @@ + + error: + if (PyErr_Occurred()) { +- PyErr_WriteUnraisable(callback); ++ PyErr_FormatUnraisable("Exception ignored in ssl PSK server callback " ++ "while calling callback %R", callback); + } + PyGILState_Release(gstate); + return 0; +@@ -6553,6 +6597,12 @@ + addbool(m, "HAS_PSK", 1); + #endif + ++#ifdef SSL_VERIFY_POST_HANDSHAKE ++ addbool(m, "HAS_PHA", 1); ++#else ++ addbool(m, "HAS_PHA", 0); ++#endif ++ + #undef addbool + #undef ADD_INT_CONST + +diff --git a/Modules/_ssl/cert.c b/Modules/_ssl/cert.c +index bda66dc4d94..c11ed8e3a28 100644 +--- a/Modules/_ssl/cert.c ++++ b/Modules/_ssl/cert.c +@@ -153,10 +153,13 @@ + * PySSLCertificate_Type + */ + ++#define _PySSLCertificate_CAST(op) ((PySSLCertificate *)(op)) ++ + static PyObject * +-certificate_repr(PySSLCertificate *self) ++certificate_repr(PyObject *op) + { + PyObject *osubject, *result; ++ PySSLCertificate *self = _PySSLCertificate_CAST(op); + + /* subject string is ASCII encoded, UTF-8 chars are quoted */ + osubject = _x509name_print( +@@ -176,8 +179,9 @@ + } + + static Py_hash_t +-certificate_hash(PySSLCertificate *self) ++certificate_hash(PyObject *op) + { ++ PySSLCertificate *self = _PySSLCertificate_CAST(op); + if (self->hash == (Py_hash_t)-1) { + unsigned long hash; + hash = X509_subject_name_hash(self->cert); +@@ -191,19 +195,20 @@ + } + + static PyObject * +-certificate_richcompare(PySSLCertificate *self, PyObject *other, int op) ++certificate_richcompare(PyObject *lhs, PyObject *rhs, int op) + { + int cmp; ++ PySSLCertificate *self = _PySSLCertificate_CAST(lhs); + _sslmodulestate *state = get_state_cert(self); + +- if (Py_TYPE(other) != state->PySSLCertificate_Type) { ++ if (Py_TYPE(rhs) != state->PySSLCertificate_Type) { + Py_RETURN_NOTIMPLEMENTED; + } + /* only support == and != */ + if ((op != Py_EQ) && (op != Py_NE)) { + Py_RETURN_NOTIMPLEMENTED; + } +- cmp = X509_cmp(self->cert, ((PySSLCertificate*)other)->cert); ++ cmp = X509_cmp(self->cert, ((PySSLCertificate*)rhs)->cert); + if (((op == Py_EQ) && (cmp == 0)) || ((op == Py_NE) && (cmp != 0))) { + Py_RETURN_TRUE; + } else { +@@ -212,11 +217,12 @@ + } + + static void +-certificate_dealloc(PySSLCertificate *self) ++certificate_dealloc(PyObject *op) + { ++ PySSLCertificate *self = _PySSLCertificate_CAST(op); + PyTypeObject *tp = Py_TYPE(self); + X509_free(self->cert); +- Py_TYPE(self)->tp_free(self); ++ (void)Py_TYPE(self)->tp_free(self); + Py_DECREF(tp); + } + +diff --git a/Modules/_ssl/clinic/cert.c.h b/Modules/_ssl/clinic/cert.c.h +index 19559442cd9..3e0c5b40509 100644 +--- a/Modules/_ssl/clinic/cert.c.h ++++ b/Modules/_ssl/clinic/cert.c.h +@@ -20,7 +20,7 @@ + _ssl_Certificate_public_bytes_impl(PySSLCertificate *self, int format); + + static PyObject * +-_ssl_Certificate_public_bytes(PySSLCertificate *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_ssl_Certificate_public_bytes(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -65,7 +65,7 @@ + goto exit; + } + skip_optional_pos: +- return_value = _ssl_Certificate_public_bytes_impl(self, format); ++ return_value = _ssl_Certificate_public_bytes_impl((PySSLCertificate *)self, format); + + exit: + return return_value; +@@ -83,8 +83,8 @@ + _ssl_Certificate_get_info_impl(PySSLCertificate *self); + + static PyObject * +-_ssl_Certificate_get_info(PySSLCertificate *self, PyObject *Py_UNUSED(ignored)) ++_ssl_Certificate_get_info(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _ssl_Certificate_get_info_impl(self); ++ return _ssl_Certificate_get_info_impl((PySSLCertificate *)self); + } +-/*[clinic end generated code: output=e5fa354db5fc56b4 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=51365b498b975ee0 input=a9049054013a1b77]*/ +diff --git a/Modules/_ssl/debughelpers.c b/Modules/_ssl/debughelpers.c +index 9c87f8b4d21..318c045a0ee 100644 +--- a/Modules/_ssl/debughelpers.c ++++ b/Modules/_ssl/debughelpers.c +@@ -180,8 +180,8 @@ + return 0; + } + +- /* _Py_fopen_obj() also checks that arg is of proper type. */ +- fp = _Py_fopen_obj(arg, "a" PY_STDIOTEXTMODE); ++ /* Py_fopen() also checks that arg is of proper type. */ ++ fp = Py_fopen(arg, "a" PY_STDIOTEXTMODE); + if (fp == NULL) + return -1; + +--- /dev/null ++++ b/Modules/_testcapi/clinic/file.c.h +@@ -0,0 +1,64 @@ ++/*[clinic input] ++preserve ++[clinic start generated code]*/ ++ ++#include "pycore_modsupport.h" // _PyArg_CheckPositional() ++ ++PyDoc_STRVAR(_testcapi_pyfile_newstdprinter__doc__, ++"pyfile_newstdprinter($module, fd, /)\n" ++"--\n" ++"\n"); ++ ++#define _TESTCAPI_PYFILE_NEWSTDPRINTER_METHODDEF \ ++ {"pyfile_newstdprinter", (PyCFunction)_testcapi_pyfile_newstdprinter, METH_O, _testcapi_pyfile_newstdprinter__doc__}, ++ ++static PyObject * ++_testcapi_pyfile_newstdprinter_impl(PyObject *module, int fd); ++ ++static PyObject * ++_testcapi_pyfile_newstdprinter(PyObject *module, PyObject *arg) ++{ ++ PyObject *return_value = NULL; ++ int fd; ++ ++ fd = PyLong_AsInt(arg); ++ if (fd == -1 && PyErr_Occurred()) { ++ goto exit; ++ } ++ return_value = _testcapi_pyfile_newstdprinter_impl(module, fd); ++ ++exit: ++ return return_value; ++} ++ ++PyDoc_STRVAR(_testcapi_py_fopen__doc__, ++"py_fopen($module, path, mode, /)\n" ++"--\n" ++"\n" ++"Call Py_fopen(), fread(256) and Py_fclose(). Return read bytes."); ++ ++#define _TESTCAPI_PY_FOPEN_METHODDEF \ ++ {"py_fopen", _PyCFunction_CAST(_testcapi_py_fopen), METH_FASTCALL, _testcapi_py_fopen__doc__}, ++ ++static PyObject * ++_testcapi_py_fopen_impl(PyObject *module, PyObject *path, const char *mode, ++ Py_ssize_t mode_length); ++ ++static PyObject * ++_testcapi_py_fopen(PyObject *module, PyObject *const *args, Py_ssize_t nargs) ++{ ++ PyObject *return_value = NULL; ++ PyObject *path; ++ const char *mode; ++ Py_ssize_t mode_length; ++ ++ if (!_PyArg_ParseStack(args, nargs, "Oz#:py_fopen", ++ &path, &mode, &mode_length)) { ++ goto exit; ++ } ++ return_value = _testcapi_py_fopen_impl(module, path, mode, mode_length); ++ ++exit: ++ return return_value; ++} ++/*[clinic end generated code: output=e943bbd7f181d079 input=a9049054013a1b77]*/ +diff --git a/Modules/_testcapi/code.c b/Modules/_testcapi/code.c +index c0193489b6f..94f752c9726 100644 +--- a/Modules/_testcapi/code.c ++++ b/Modules/_testcapi/code.c +@@ -47,7 +47,6 @@ + test_code_extra(PyObject* self, PyObject *Py_UNUSED(callable)) + { + PyObject *result = NULL; +- PyObject *test_module = NULL; + PyObject *test_func = NULL; + + // Get or initialize interpreter-specific code object storage index +@@ -62,11 +61,8 @@ + + // Get a function to test with + // This can be any Python function. Use `test.test_misc.testfunction`. +- test_module = PyImport_ImportModule("test.test_capi.test_misc"); +- if (!test_module) { +- goto finally; +- } +- test_func = PyObject_GetAttrString(test_module, "testfunction"); ++ test_func = PyImport_ImportModuleAttrString("test.test_capi.test_misc", ++ "testfunction"); + if (!test_func) { + goto finally; + } +@@ -102,7 +98,6 @@ + } + result = Py_NewRef(Py_None); + finally: +- Py_XDECREF(test_module); + Py_XDECREF(test_func); + return result; + } +diff --git a/Modules/_testcapi/dict.c b/Modules/_testcapi/dict.c +index 307797f98f1..b7c73d7332b 100644 +--- a/Modules/_testcapi/dict.c ++++ b/Modules/_testcapi/dict.c +@@ -181,6 +181,83 @@ + RETURN_INT(PyDict_PopString(dict, key, NULL)); + } + ++ ++static int ++test_dict_inner(PyObject *self, int count) ++{ ++ Py_ssize_t pos = 0, iterations = 0; ++ int i; ++ PyObject *dict = PyDict_New(); ++ PyObject *v, *k; ++ ++ if (dict == NULL) ++ return -1; ++ ++ for (i = 0; i < count; i++) { ++ v = PyLong_FromLong(i); ++ if (v == NULL) { ++ goto error; ++ } ++ if (PyDict_SetItem(dict, v, v) < 0) { ++ Py_DECREF(v); ++ goto error; ++ } ++ Py_DECREF(v); ++ } ++ ++ k = v = UNINITIALIZED_PTR; ++ while (PyDict_Next(dict, &pos, &k, &v)) { ++ PyObject *o; ++ iterations++; ++ ++ assert(k != UNINITIALIZED_PTR); ++ assert(v != UNINITIALIZED_PTR); ++ i = PyLong_AS_LONG(v) + 1; ++ o = PyLong_FromLong(i); ++ if (o == NULL) { ++ goto error; ++ } ++ if (PyDict_SetItem(dict, k, o) < 0) { ++ Py_DECREF(o); ++ goto error; ++ } ++ Py_DECREF(o); ++ k = v = UNINITIALIZED_PTR; ++ } ++ assert(k == UNINITIALIZED_PTR); ++ assert(v == UNINITIALIZED_PTR); ++ ++ Py_DECREF(dict); ++ ++ if (iterations != count) { ++ PyErr_SetString( ++ PyExc_AssertionError, ++ "test_dict_iteration: dict iteration went wrong "); ++ return -1; ++ } else { ++ return 0; ++ } ++error: ++ Py_DECREF(dict); ++ return -1; ++} ++ ++ ++static PyObject* ++test_dict_iteration(PyObject* self, PyObject *Py_UNUSED(ignored)) ++{ ++ int i; ++ ++ for (i = 0; i < 200; i++) { ++ if (test_dict_inner(self, i) < 0) { ++ return NULL; ++ } ++ } ++ ++ Py_RETURN_NONE; ++} ++ ++ + static PyMethodDef test_methods[] = { + {"dict_containsstring", dict_containsstring, METH_VARARGS}, + {"dict_getitemref", dict_getitemref, METH_VARARGS}, +@@ -191,6 +268,7 @@ + {"dict_pop_null", dict_pop_null, METH_VARARGS}, + {"dict_popstring", dict_popstring, METH_VARARGS}, + {"dict_popstring_null", dict_popstring_null, METH_VARARGS}, ++ {"test_dict_iteration", test_dict_iteration, METH_NOARGS}, + {NULL}, + }; + +diff --git a/Modules/_testcapi/exceptions.c b/Modules/_testcapi/exceptions.c +index e92d9670e7c..b647bfc71ea 100644 +--- a/Modules/_testcapi/exceptions.c ++++ b/Modules/_testcapi/exceptions.c +@@ -3,6 +3,7 @@ + + #include "parts.h" + #include "util.h" ++ + #include "clinic/exceptions.c.h" + + +diff --git a/Modules/_testcapi/file.c b/Modules/_testcapi/file.c +index 634563f6ea1..060e0f50598 100644 +--- a/Modules/_testcapi/file.c ++++ b/Modules/_testcapi/file.c +@@ -1,17 +1,70 @@ ++// clinic/file.c.h uses internal pycore_modsupport.h API ++#define PYTESTCAPI_NEED_INTERNAL_API ++ + #include "parts.h" + #include "util.h" ++#include "clinic/file.c.h" ++ ++ ++/*[clinic input] ++module _testcapi ++[clinic start generated code]*/ ++/*[clinic end generated code: output=da39a3ee5e6b4b0d input=6361033e795369fc]*/ ++ ++ ++/*[clinic input] ++_testcapi.pyfile_newstdprinter ++ ++ fd: int ++ / ++ ++[clinic start generated code]*/ ++ ++static PyObject * ++_testcapi_pyfile_newstdprinter_impl(PyObject *module, int fd) ++/*[clinic end generated code: output=8a2d1c57b6892db3 input=442f1824142262ea]*/ ++{ ++ return PyFile_NewStdPrinter(fd); ++} ++ ++ ++/*[clinic input] ++_testcapi.py_fopen ++ ++ path: object ++ mode: str(zeroes=True, accept={robuffer, str, NoneType}) ++ / ++ ++Call Py_fopen(), fread(256) and Py_fclose(). Return read bytes. ++[clinic start generated code]*/ ++ ++static PyObject * ++_testcapi_py_fopen_impl(PyObject *module, PyObject *path, const char *mode, ++ Py_ssize_t mode_length) ++/*[clinic end generated code: output=69840d0cfd8b7fbb input=f3a579dd7eb60926]*/ ++{ ++ NULLABLE(path); ++ FILE *fp = Py_fopen(path, mode); ++ if (fp == NULL) { ++ return NULL; ++ } ++ ++ char buffer[256]; ++ size_t size = fread(buffer, 1, Py_ARRAY_LENGTH(buffer), fp); ++ Py_fclose(fp); ++ ++ return PyBytes_FromStringAndSize(buffer, size); ++} + + + static PyMethodDef test_methods[] = { ++ _TESTCAPI_PYFILE_NEWSTDPRINTER_METHODDEF ++ _TESTCAPI_PY_FOPEN_METHODDEF + {NULL}, + }; + + int + _PyTestCapi_Init_File(PyObject *m) + { +- if (PyModule_AddFunctions(m, test_methods) < 0){ +- return -1; +- } +- +- return 0; ++ return PyModule_AddFunctions(m, test_methods); + } +diff --git a/Modules/_testcapi/float.c b/Modules/_testcapi/float.c +index 15ea97ec452..e3869134c84 100644 +--- a/Modules/_testcapi/float.c ++++ b/Modules/_testcapi/float.c +@@ -99,9 +99,68 @@ + return PyFloat_FromDouble(d); + } + ++ ++/* Test PyOS_string_to_double. */ ++static PyObject * ++test_string_to_double(PyObject *self, PyObject *Py_UNUSED(ignored)) ++{ ++ double result; ++ const char *msg; ++ ++#define CHECK_STRING(STR, expected) \ ++ do { \ ++ result = PyOS_string_to_double(STR, NULL, NULL); \ ++ if (result == -1.0 && PyErr_Occurred()) { \ ++ return NULL; \ ++ } \ ++ if (result != (double)expected) { \ ++ msg = "conversion of " STR " to float failed"; \ ++ goto fail; \ ++ } \ ++ } while (0) ++ ++#define CHECK_INVALID(STR) \ ++ do { \ ++ result = PyOS_string_to_double(STR, NULL, NULL); \ ++ if (result == -1.0 && PyErr_Occurred()) { \ ++ if (PyErr_ExceptionMatches(PyExc_ValueError)) { \ ++ PyErr_Clear(); \ ++ } \ ++ else { \ ++ return NULL; \ ++ } \ ++ } \ ++ else { \ ++ msg = "conversion of " STR " didn't raise ValueError"; \ ++ goto fail; \ ++ } \ ++ } while (0) ++ ++ CHECK_STRING("0.1", 0.1); ++ CHECK_STRING("1.234", 1.234); ++ CHECK_STRING("-1.35", -1.35); ++ CHECK_STRING(".1e01", 1.0); ++ CHECK_STRING("2.e-2", 0.02); ++ ++ CHECK_INVALID(" 0.1"); ++ CHECK_INVALID("\t\n-3"); ++ CHECK_INVALID(".123 "); ++ CHECK_INVALID("3\n"); ++ CHECK_INVALID("123abc"); ++ ++ Py_RETURN_NONE; ++ fail: ++ PyErr_Format(PyExc_AssertionError, "test_string_to_double: %s", msg); ++ return NULL; ++#undef CHECK_STRING ++#undef CHECK_INVALID ++} ++ ++ + static PyMethodDef test_methods[] = { + _TESTCAPI_FLOAT_PACK_METHODDEF + _TESTCAPI_FLOAT_UNPACK_METHODDEF ++ {"test_string_to_double", test_string_to_double, METH_NOARGS}, + {NULL}, + }; + +--- /dev/null ++++ b/Modules/_testcapi/frame.c +@@ -0,0 +1,134 @@ ++#include "parts.h" ++#include "util.h" ++ ++#include "frameobject.h" // PyFrame_New() ++ ++ ++static PyObject * ++frame_getlocals(PyObject *self, PyObject *frame) ++{ ++ if (!PyFrame_Check(frame)) { ++ PyErr_SetString(PyExc_TypeError, "argument must be a frame"); ++ return NULL; ++ } ++ return PyFrame_GetLocals((PyFrameObject *)frame); ++} ++ ++ ++static PyObject * ++frame_getglobals(PyObject *self, PyObject *frame) ++{ ++ if (!PyFrame_Check(frame)) { ++ PyErr_SetString(PyExc_TypeError, "argument must be a frame"); ++ return NULL; ++ } ++ return PyFrame_GetGlobals((PyFrameObject *)frame); ++} ++ ++ ++static PyObject * ++frame_getgenerator(PyObject *self, PyObject *frame) ++{ ++ if (!PyFrame_Check(frame)) { ++ PyErr_SetString(PyExc_TypeError, "argument must be a frame"); ++ return NULL; ++ } ++ return PyFrame_GetGenerator((PyFrameObject *)frame); ++} ++ ++ ++static PyObject * ++frame_getbuiltins(PyObject *self, PyObject *frame) ++{ ++ if (!PyFrame_Check(frame)) { ++ PyErr_SetString(PyExc_TypeError, "argument must be a frame"); ++ return NULL; ++ } ++ return PyFrame_GetBuiltins((PyFrameObject *)frame); ++} ++ ++ ++static PyObject * ++frame_getlasti(PyObject *self, PyObject *frame) ++{ ++ if (!PyFrame_Check(frame)) { ++ PyErr_SetString(PyExc_TypeError, "argument must be a frame"); ++ return NULL; ++ } ++ int lasti = PyFrame_GetLasti((PyFrameObject *)frame); ++ if (lasti < 0) { ++ assert(lasti == -1); ++ Py_RETURN_NONE; ++ } ++ return PyLong_FromLong(lasti); ++} ++ ++ ++static PyObject * ++frame_new(PyObject *self, PyObject *args) ++{ ++ PyObject *code, *globals, *locals; ++ if (!PyArg_ParseTuple(args, "OOO", &code, &globals, &locals)) { ++ return NULL; ++ } ++ if (!PyCode_Check(code)) { ++ PyErr_SetString(PyExc_TypeError, "argument must be a code object"); ++ return NULL; ++ } ++ PyThreadState *tstate = PyThreadState_Get(); ++ ++ return (PyObject *)PyFrame_New(tstate, (PyCodeObject *)code, globals, locals); ++} ++ ++ ++static PyObject * ++frame_getvar(PyObject *self, PyObject *args) ++{ ++ PyObject *frame, *name; ++ if (!PyArg_ParseTuple(args, "OO", &frame, &name)) { ++ return NULL; ++ } ++ if (!PyFrame_Check(frame)) { ++ PyErr_SetString(PyExc_TypeError, "argument must be a frame"); ++ return NULL; ++ } ++ ++ return PyFrame_GetVar((PyFrameObject *)frame, name); ++} ++ ++ ++static PyObject * ++frame_getvarstring(PyObject *self, PyObject *args) ++{ ++ PyObject *frame; ++ const char *name; ++ if (!PyArg_ParseTuple(args, "Oy", &frame, &name)) { ++ return NULL; ++ } ++ if (!PyFrame_Check(frame)) { ++ PyErr_SetString(PyExc_TypeError, "argument must be a frame"); ++ return NULL; ++ } ++ ++ return PyFrame_GetVarString((PyFrameObject *)frame, name); ++} ++ ++ ++static PyMethodDef test_methods[] = { ++ {"frame_getlocals", frame_getlocals, METH_O, NULL}, ++ {"frame_getglobals", frame_getglobals, METH_O, NULL}, ++ {"frame_getgenerator", frame_getgenerator, METH_O, NULL}, ++ {"frame_getbuiltins", frame_getbuiltins, METH_O, NULL}, ++ {"frame_getlasti", frame_getlasti, METH_O, NULL}, ++ {"frame_new", frame_new, METH_VARARGS, NULL}, ++ {"frame_getvar", frame_getvar, METH_VARARGS, NULL}, ++ {"frame_getvarstring", frame_getvarstring, METH_VARARGS, NULL}, ++ {NULL}, ++}; ++ ++int ++_PyTestCapi_Init_Frame(PyObject *m) ++{ ++ return PyModule_AddFunctions(m, test_methods); ++} ++ +--- /dev/null ++++ b/Modules/_testcapi/function.c +@@ -0,0 +1,143 @@ ++#include "parts.h" ++#include "util.h" ++ ++ ++static PyObject * ++function_get_code(PyObject *self, PyObject *func) ++{ ++ PyObject *code = PyFunction_GetCode(func); ++ if (code != NULL) { ++ return Py_NewRef(code); ++ } else { ++ return NULL; ++ } ++} ++ ++ ++static PyObject * ++function_get_globals(PyObject *self, PyObject *func) ++{ ++ PyObject *globals = PyFunction_GetGlobals(func); ++ if (globals != NULL) { ++ return Py_NewRef(globals); ++ } else { ++ return NULL; ++ } ++} ++ ++ ++static PyObject * ++function_get_module(PyObject *self, PyObject *func) ++{ ++ PyObject *module = PyFunction_GetModule(func); ++ if (module != NULL) { ++ return Py_NewRef(module); ++ } else { ++ return NULL; ++ } ++} ++ ++ ++static PyObject * ++function_get_defaults(PyObject *self, PyObject *func) ++{ ++ PyObject *defaults = PyFunction_GetDefaults(func); ++ if (defaults != NULL) { ++ return Py_NewRef(defaults); ++ } else if (PyErr_Occurred()) { ++ return NULL; ++ } else { ++ Py_RETURN_NONE; // This can happen when `defaults` are set to `None` ++ } ++} ++ ++ ++static PyObject * ++function_set_defaults(PyObject *self, PyObject *args) ++{ ++ PyObject *func = NULL, *defaults = NULL; ++ if (!PyArg_ParseTuple(args, "OO", &func, &defaults)) { ++ return NULL; ++ } ++ int result = PyFunction_SetDefaults(func, defaults); ++ if (result == -1) ++ return NULL; ++ Py_RETURN_NONE; ++} ++ ++ ++static PyObject * ++function_get_kw_defaults(PyObject *self, PyObject *func) ++{ ++ PyObject *defaults = PyFunction_GetKwDefaults(func); ++ if (defaults != NULL) { ++ return Py_NewRef(defaults); ++ } else if (PyErr_Occurred()) { ++ return NULL; ++ } else { ++ Py_RETURN_NONE; // This can happen when `kwdefaults` are set to `None` ++ } ++} ++ ++ ++static PyObject * ++function_set_kw_defaults(PyObject *self, PyObject *args) ++{ ++ PyObject *func = NULL, *defaults = NULL; ++ if (!PyArg_ParseTuple(args, "OO", &func, &defaults)) { ++ return NULL; ++ } ++ int result = PyFunction_SetKwDefaults(func, defaults); ++ if (result == -1) ++ return NULL; ++ Py_RETURN_NONE; ++} ++ ++ ++static PyObject * ++function_get_closure(PyObject *self, PyObject *func) ++{ ++ PyObject *closure = PyFunction_GetClosure(func); ++ if (closure != NULL) { ++ return Py_NewRef(closure); ++ } else if (PyErr_Occurred()) { ++ return NULL; ++ } else { ++ Py_RETURN_NONE; // This can happen when `closure` is set to `None` ++ } ++} ++ ++ ++static PyObject * ++function_set_closure(PyObject *self, PyObject *args) ++{ ++ PyObject *func = NULL, *closure = NULL; ++ if (!PyArg_ParseTuple(args, "OO", &func, &closure)) { ++ return NULL; ++ } ++ int result = PyFunction_SetClosure(func, closure); ++ if (result == -1) { ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} ++ ++ ++static PyMethodDef test_methods[] = { ++ {"function_get_code", function_get_code, METH_O, NULL}, ++ {"function_get_globals", function_get_globals, METH_O, NULL}, ++ {"function_get_module", function_get_module, METH_O, NULL}, ++ {"function_get_defaults", function_get_defaults, METH_O, NULL}, ++ {"function_set_defaults", function_set_defaults, METH_VARARGS, NULL}, ++ {"function_get_kw_defaults", function_get_kw_defaults, METH_O, NULL}, ++ {"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL}, ++ {"function_get_closure", function_get_closure, METH_O, NULL}, ++ {"function_set_closure", function_set_closure, METH_VARARGS, NULL}, ++ {NULL}, ++}; ++ ++int ++_PyTestCapi_Init_Function(PyObject *m) ++{ ++ return PyModule_AddFunctions(m, test_methods); ++} +diff --git a/Modules/_testcapi/gc.c b/Modules/_testcapi/gc.c +index 7e33e0d4861..3691796302e 100644 +--- a/Modules/_testcapi/gc.c ++++ b/Modules/_testcapi/gc.c +@@ -94,7 +94,7 @@ + + PyObject *tp_del = PyUnicode_InternFromString("__tp_del__"); + if (tp_del == NULL) { +- PyErr_WriteUnraisable(NULL); ++ PyErr_FormatUnraisable("Exception ignored while deallocating"); + PyErr_SetRaisedException(exc); + return; + } +@@ -104,10 +104,13 @@ + if (del != NULL) { + res = PyObject_CallOneArg(del, self); + Py_DECREF(del); +- if (res == NULL) +- PyErr_WriteUnraisable(del); +- else ++ if (res == NULL) { ++ PyErr_FormatUnraisable("Exception ignored while calling " ++ "deallocator %R", del); ++ } ++ else { + Py_DECREF(res); ++ } + } + + /* Restore the saved exception. */ +diff --git a/Modules/_testcapi/immortal.c b/Modules/_testcapi/immortal.c +index 9f81389811c..0663c3781d4 100644 +--- a/Modules/_testcapi/immortal.c ++++ b/Modules/_testcapi/immortal.c +@@ -1,5 +1,8 @@ + #include "parts.h" + ++#define Py_BUILD_CORE ++#include "internal/pycore_long.h" // IMMORTALITY_BIT_MASK ++ + int verify_immortality(PyObject *object) + { + assert(_Py_IsImmortal(object)); +@@ -26,14 +29,31 @@ + test_immortal_small_ints(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + for (int i = -5; i <= 256; i++) { +- assert(verify_immortality(PyLong_FromLong(i))); ++ PyObject *obj = PyLong_FromLong(i); ++ assert(verify_immortality(obj)); ++ int has_int_immortal_bit = ((PyLongObject *)obj)->long_value.lv_tag & IMMORTALITY_BIT_MASK; ++ assert(has_int_immortal_bit); ++ } ++ for (int i = 257; i <= 260; i++) { ++ PyObject *obj = PyLong_FromLong(i); ++ assert(obj); ++ int has_int_immortal_bit = ((PyLongObject *)obj)->long_value.lv_tag & IMMORTALITY_BIT_MASK; ++ assert(!has_int_immortal_bit); ++ Py_DECREF(obj); + } + Py_RETURN_NONE; + } + ++static PyObject * ++is_immortal(PyObject *self, PyObject *op) ++{ ++ return PyBool_FromLong(PyUnstable_IsImmortal(op)); ++} ++ + static PyMethodDef test_methods[] = { + {"test_immortal_builtins", test_immortal_builtins, METH_NOARGS}, + {"test_immortal_small_ints", test_immortal_small_ints, METH_NOARGS}, ++ {"is_immortal", is_immortal, METH_O}, + {NULL}, + }; + +--- /dev/null ++++ b/Modules/_testcapi/import.c +@@ -0,0 +1,44 @@ ++#include "parts.h" ++#include "util.h" ++ ++// Test PyImport_ImportModuleAttr() ++static PyObject * ++pyimport_importmoduleattr(PyObject *self, PyObject *args) ++{ ++ PyObject *mod_name, *attr_name; ++ if (!PyArg_ParseTuple(args, "OO", &mod_name, &attr_name)) { ++ return NULL; ++ } ++ NULLABLE(mod_name); ++ NULLABLE(attr_name); ++ ++ return PyImport_ImportModuleAttr(mod_name, attr_name); ++} ++ ++ ++// Test PyImport_ImportModuleAttrString() ++static PyObject * ++pyimport_importmoduleattrstring(PyObject *self, PyObject *args) ++{ ++ const char *mod_name, *attr_name; ++ Py_ssize_t len; ++ if (!PyArg_ParseTuple(args, "z#z#", &mod_name, &len, &attr_name, &len)) { ++ return NULL; ++ } ++ ++ return PyImport_ImportModuleAttrString(mod_name, attr_name); ++} ++ ++ ++static PyMethodDef test_methods[] = { ++ {"PyImport_ImportModuleAttr", pyimport_importmoduleattr, METH_VARARGS}, ++ {"PyImport_ImportModuleAttrString", pyimport_importmoduleattrstring, METH_VARARGS}, ++ {NULL}, ++}; ++ ++int ++_PyTestCapi_Init_Import(PyObject *m) ++{ ++ return PyModule_AddFunctions(m, test_methods); ++} ++ +diff --git a/Modules/_testcapi/list.c b/Modules/_testcapi/list.c +index 09cec4c30c8..530b47780ac 100644 +--- a/Modules/_testcapi/list.c ++++ b/Modules/_testcapi/list.c +@@ -60,22 +60,61 @@ + } + + ++static PyObject* ++test_list_api(PyObject *self, PyObject *Py_UNUSED(ignored)) ++{ ++ PyObject* list; ++ int i; ++ ++ /* SF bug 132008: PyList_Reverse segfaults */ ++#define NLIST 30 ++ list = PyList_New(NLIST); ++ if (list == (PyObject*)NULL) ++ return (PyObject*)NULL; ++ /* list = range(NLIST) */ ++ for (i = 0; i < NLIST; ++i) { ++ PyObject* anint = PyLong_FromLong(i); ++ if (anint == (PyObject*)NULL) { ++ Py_DECREF(list); ++ return (PyObject*)NULL; ++ } ++ PyList_SET_ITEM(list, i, anint); ++ } ++ /* list.reverse(), via PyList_Reverse() */ ++ i = PyList_Reverse(list); /* should not blow up! */ ++ if (i != 0) { ++ Py_DECREF(list); ++ return (PyObject*)NULL; ++ } ++ /* Check that list == range(29, -1, -1) now */ ++ for (i = 0; i < NLIST; ++i) { ++ PyObject* anint = PyList_GET_ITEM(list, i); ++ if (PyLong_AS_LONG(anint) != NLIST-1-i) { ++ PyErr_SetString(PyExc_AssertionError, ++ "test_list_api: reverse screwed up"); ++ Py_DECREF(list); ++ return (PyObject*)NULL; ++ } ++ } ++ Py_DECREF(list); ++#undef NLIST ++ ++ Py_RETURN_NONE; ++} ++ ++ + static PyMethodDef test_methods[] = { + {"list_get_size", list_get_size, METH_O}, + {"list_get_item", list_get_item, METH_VARARGS}, + {"list_set_item", list_set_item, METH_VARARGS}, + {"list_clear", list_clear, METH_O}, + {"list_extend", list_extend, METH_VARARGS}, +- ++ {"test_list_api", test_list_api, METH_NOARGS}, + {NULL}, + }; + + int + _PyTestCapi_Init_List(PyObject *m) + { +- if (PyModule_AddFunctions(m, test_methods) < 0) { +- return -1; +- } +- +- return 0; ++ return PyModule_AddFunctions(m, test_methods); + } +diff --git a/Modules/_testcapi/mem.c b/Modules/_testcapi/mem.c +index ab4ad934644..7237fb94c3f 100644 +--- a/Modules/_testcapi/mem.c ++++ b/Modules/_testcapi/mem.c +@@ -557,8 +557,9 @@ + { + unsigned int domain; + PyObject *ptr_obj; ++ int release_gil = 0; + +- if (!PyArg_ParseTuple(args, "IO", &domain, &ptr_obj)) { ++ if (!PyArg_ParseTuple(args, "IO|i", &domain, &ptr_obj, &release_gil)) { + return NULL; + } + void *ptr = PyLong_AsVoidPtr(ptr_obj); +@@ -566,7 +567,15 @@ + return NULL; + } + +- int res = PyTraceMalloc_Untrack(domain, (uintptr_t)ptr); ++ int res; ++ if (release_gil) { ++ Py_BEGIN_ALLOW_THREADS ++ res = PyTraceMalloc_Untrack(domain, (uintptr_t)ptr); ++ Py_END_ALLOW_THREADS ++ } ++ else { ++ res = PyTraceMalloc_Untrack(domain, (uintptr_t)ptr); ++ } + if (res < 0) { + PyErr_SetString(PyExc_RuntimeError, "PyTraceMalloc_Untrack error"); + return NULL; +@@ -575,6 +584,106 @@ + Py_RETURN_NONE; + } + ++ ++static void ++tracemalloc_track_race_thread(void *data) ++{ ++ PyTraceMalloc_Track(123, 10, 1); ++ PyTraceMalloc_Untrack(123, 10); ++ ++ PyThread_type_lock lock = (PyThread_type_lock)data; ++ PyThread_release_lock(lock); ++} ++ ++// gh-128679: Test fix for tracemalloc.stop() race condition ++static PyObject * ++tracemalloc_track_race(PyObject *self, PyObject *args) ++{ ++#define NTHREAD 50 ++ PyObject *tracemalloc = NULL; ++ PyObject *stop = NULL; ++ PyThread_type_lock locks[NTHREAD]; ++ memset(locks, 0, sizeof(locks)); ++ ++ // Call tracemalloc.start() ++ tracemalloc = PyImport_ImportModule("tracemalloc"); ++ if (tracemalloc == NULL) { ++ goto error; ++ } ++ PyObject *start = PyObject_GetAttrString(tracemalloc, "start"); ++ if (start == NULL) { ++ goto error; ++ } ++ PyObject *res = PyObject_CallNoArgs(start); ++ Py_DECREF(start); ++ if (res == NULL) { ++ goto error; ++ } ++ Py_DECREF(res); ++ ++ stop = PyObject_GetAttrString(tracemalloc, "stop"); ++ Py_CLEAR(tracemalloc); ++ if (stop == NULL) { ++ goto error; ++ } ++ ++ // Start threads ++ for (size_t i = 0; i < NTHREAD; i++) { ++ PyThread_type_lock lock = PyThread_allocate_lock(); ++ if (!lock) { ++ PyErr_NoMemory(); ++ goto error; ++ } ++ locks[i] = lock; ++ PyThread_acquire_lock(lock, 1); ++ ++ unsigned long thread; ++ thread = PyThread_start_new_thread(tracemalloc_track_race_thread, ++ (void*)lock); ++ if (thread == (unsigned long)-1) { ++ PyErr_SetString(PyExc_RuntimeError, "can't start new thread"); ++ goto error; ++ } ++ } ++ ++ // Call tracemalloc.stop() while threads are running ++ res = PyObject_CallNoArgs(stop); ++ Py_CLEAR(stop); ++ if (res == NULL) { ++ goto error; ++ } ++ Py_DECREF(res); ++ ++ // Wait until threads complete with the GIL released ++ Py_BEGIN_ALLOW_THREADS ++ for (size_t i = 0; i < NTHREAD; i++) { ++ PyThread_type_lock lock = locks[i]; ++ PyThread_acquire_lock(lock, 1); ++ PyThread_release_lock(lock); ++ } ++ Py_END_ALLOW_THREADS ++ ++ // Free threads locks ++ for (size_t i=0; i < NTHREAD; i++) { ++ PyThread_type_lock lock = locks[i]; ++ PyThread_free_lock(lock); ++ } ++ Py_RETURN_NONE; ++ ++error: ++ Py_CLEAR(tracemalloc); ++ Py_CLEAR(stop); ++ for (size_t i=0; i < NTHREAD; i++) { ++ PyThread_type_lock lock = locks[i]; ++ if (lock) { ++ PyThread_free_lock(lock); ++ } ++ } ++ return NULL; ++#undef NTHREAD ++} ++ ++ + static PyMethodDef test_methods[] = { + {"pymem_api_misuse", pymem_api_misuse, METH_NOARGS}, + {"pymem_buffer_overflow", pymem_buffer_overflow, METH_NOARGS}, +@@ -593,6 +702,7 @@ + // Tracemalloc tests + {"tracemalloc_track", tracemalloc_track, METH_VARARGS}, + {"tracemalloc_untrack", tracemalloc_untrack, METH_VARARGS}, ++ {"tracemalloc_track_race", tracemalloc_track_race, METH_NOARGS}, + {NULL}, + }; + +diff --git a/Modules/_testcapi/monitoring.c b/Modules/_testcapi/monitoring.c +index 6fd4a405688..e475e3b5937 100644 +--- a/Modules/_testcapi/monitoring.c ++++ b/Modules/_testcapi/monitoring.c +@@ -286,7 +286,7 @@ + } + + static PyObject * +-fire_event_branch(PyObject *self, PyObject *args) ++fire_event_branch_right(PyObject *self, PyObject *args) + { + PyObject *codelike; + int offset; +@@ -299,7 +299,25 @@ + if (state == NULL) { + return NULL; + } +- int res = PyMonitoring_FireBranchEvent(state, codelike, offset, target_offset); ++ int res = PyMonitoring_FireBranchRightEvent(state, codelike, offset, target_offset); ++ RETURN_INT(teardown_fire(res, state, exception)); ++} ++ ++static PyObject * ++fire_event_branch_left(PyObject *self, PyObject *args) ++{ ++ PyObject *codelike; ++ int offset; ++ PyObject *target_offset; ++ if (!PyArg_ParseTuple(args, "OiO", &codelike, &offset, &target_offset)) { ++ return NULL; ++ } ++ PyObject *exception = NULL; ++ PyMonitoringState *state = setup_fire(codelike, offset, exception); ++ if (state == NULL) { ++ return NULL; ++ } ++ int res = PyMonitoring_FireBranchLeftEvent(state, codelike, offset, target_offset); + RETURN_INT(teardown_fire(res, state, exception)); + } + +@@ -478,7 +496,8 @@ + {"fire_event_call", fire_event_call, METH_VARARGS}, + {"fire_event_line", fire_event_line, METH_VARARGS}, + {"fire_event_jump", fire_event_jump, METH_VARARGS}, +- {"fire_event_branch", fire_event_branch, METH_VARARGS}, ++ {"fire_event_branch_left", fire_event_branch_left, METH_VARARGS}, ++ {"fire_event_branch_right", fire_event_branch_right, METH_VARARGS}, + {"fire_event_py_throw", fire_event_py_throw, METH_VARARGS}, + {"fire_event_raise", fire_event_raise, METH_VARARGS}, + {"fire_event_c_raise", fire_event_c_raise, METH_VARARGS}, +diff --git a/Modules/_testcapi/object.c b/Modules/_testcapi/object.c +index 3af5429ef00..2d538627d21 100644 +--- a/Modules/_testcapi/object.c ++++ b/Modules/_testcapi/object.c +@@ -15,7 +15,7 @@ + return NULL; + } + +- fp = _Py_fopen_obj(filename, "w+"); ++ fp = Py_fopen(filename, "w+"); + + if (Py_IsTrue(print_raw)) { + flags = Py_PRINT_RAW; +@@ -41,7 +41,7 @@ + return NULL; + } + +- fp = _Py_fopen_obj(filename, "w+"); ++ fp = Py_fopen(filename, "w+"); + + if (PyObject_Print(NULL, fp, 0) < 0) { + fclose(fp); +@@ -72,7 +72,7 @@ + return NULL; + } + +- fp = _Py_fopen_obj(filename, "w+"); ++ fp = Py_fopen(filename, "w+"); + + if (PyObject_Print(test_string, fp, 0) < 0){ + fclose(fp); +@@ -103,7 +103,7 @@ + } + + // open file in read mode to induce OSError +- fp = _Py_fopen_obj(filename, "r"); ++ fp = Py_fopen(filename, "r"); + + if (PyObject_Print(test_string, fp, 0) < 0) { + fclose(fp); +@@ -131,6 +131,346 @@ + return PyLong_FromLong(result); + } + ++static int MyObject_dealloc_called = 0; ++ ++static void ++MyObject_dealloc(PyObject *op) ++{ ++ // PyUnstable_TryIncRef should return 0 if object is being deallocated ++ assert(Py_REFCNT(op) == 0); ++ assert(!PyUnstable_TryIncRef(op)); ++ assert(Py_REFCNT(op) == 0); ++ ++ MyObject_dealloc_called++; ++ Py_TYPE(op)->tp_free(op); ++} ++ ++static PyTypeObject MyType = { ++ PyVarObject_HEAD_INIT(NULL, 0) ++ .tp_name = "MyType", ++ .tp_basicsize = sizeof(PyObject), ++ .tp_dealloc = MyObject_dealloc, ++}; ++ ++static PyObject * ++test_py_try_inc_ref(PyObject *self, PyObject *unused) ++{ ++ if (PyType_Ready(&MyType) < 0) { ++ return NULL; ++ } ++ ++ MyObject_dealloc_called = 0; ++ ++ PyObject *op = PyObject_New(PyObject, &MyType); ++ if (op == NULL) { ++ return NULL; ++ } ++ ++ PyUnstable_EnableTryIncRef(op); ++#ifdef Py_GIL_DISABLED ++ // PyUnstable_EnableTryIncRef sets the shared flags to ++ // `_Py_REF_MAYBE_WEAKREF` if the flags are currently zero to ensure that ++ // the shared reference count is merged on deallocation. ++ assert((op->ob_ref_shared & _Py_REF_SHARED_FLAG_MASK) >= _Py_REF_MAYBE_WEAKREF); ++#endif ++ ++ if (!PyUnstable_TryIncRef(op)) { ++ PyErr_SetString(PyExc_AssertionError, "PyUnstable_TryIncRef failed"); ++ Py_DECREF(op); ++ return NULL; ++ } ++ Py_DECREF(op); // undo try-incref ++ Py_DECREF(op); // dealloc ++ assert(MyObject_dealloc_called == 1); ++ Py_RETURN_NONE; ++} ++ ++ ++static PyObject * ++_test_incref(PyObject *ob) ++{ ++ return Py_NewRef(ob); ++} ++ ++static PyObject * ++test_xincref_doesnt_leak(PyObject *ob, PyObject *Py_UNUSED(ignored)) ++{ ++ PyObject *obj = PyLong_FromLong(0); ++ Py_XINCREF(_test_incref(obj)); ++ Py_DECREF(obj); ++ Py_DECREF(obj); ++ Py_DECREF(obj); ++ Py_RETURN_NONE; ++} ++ ++ ++static PyObject * ++test_incref_doesnt_leak(PyObject *ob, PyObject *Py_UNUSED(ignored)) ++{ ++ PyObject *obj = PyLong_FromLong(0); ++ Py_INCREF(_test_incref(obj)); ++ Py_DECREF(obj); ++ Py_DECREF(obj); ++ Py_DECREF(obj); ++ Py_RETURN_NONE; ++} ++ ++ ++static PyObject * ++test_xdecref_doesnt_leak(PyObject *ob, PyObject *Py_UNUSED(ignored)) ++{ ++ Py_XDECREF(PyLong_FromLong(0)); ++ Py_RETURN_NONE; ++} ++ ++ ++static PyObject * ++test_decref_doesnt_leak(PyObject *ob, PyObject *Py_UNUSED(ignored)) ++{ ++ Py_DECREF(PyLong_FromLong(0)); ++ Py_RETURN_NONE; ++} ++ ++ ++static PyObject * ++test_incref_decref_API(PyObject *ob, PyObject *Py_UNUSED(ignored)) ++{ ++ PyObject *obj = PyLong_FromLong(0); ++ Py_IncRef(obj); ++ Py_DecRef(obj); ++ Py_DecRef(obj); ++ Py_RETURN_NONE; ++} ++ ++ ++#ifdef Py_REF_DEBUG ++static PyObject * ++negative_refcount(PyObject *self, PyObject *Py_UNUSED(args)) ++{ ++ PyObject *obj = PyUnicode_FromString("negative_refcount"); ++ if (obj == NULL) { ++ return NULL; ++ } ++ assert(Py_REFCNT(obj) == 1); ++ ++ Py_SET_REFCNT(obj, 0); ++ /* Py_DECREF() must call _Py_NegativeRefcount() and abort Python */ ++ Py_DECREF(obj); ++ ++ Py_RETURN_NONE; ++} ++ ++ ++static PyObject * ++decref_freed_object(PyObject *self, PyObject *Py_UNUSED(args)) ++{ ++ PyObject *obj = PyUnicode_FromString("decref_freed_object"); ++ if (obj == NULL) { ++ return NULL; ++ } ++ assert(Py_REFCNT(obj) == 1); ++ ++ // Deallocate the memory ++ Py_DECREF(obj); ++ // obj is a now a dangling pointer ++ ++ // gh-109496: If Python is built in debug mode, Py_DECREF() must call ++ // _Py_NegativeRefcount() and abort Python. ++ Py_DECREF(obj); ++ ++ Py_RETURN_NONE; ++} ++#endif ++ ++ ++// Test Py_CLEAR() macro ++static PyObject* ++test_py_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) ++{ ++ // simple case with a variable ++ PyObject *obj = PyList_New(0); ++ if (obj == NULL) { ++ return NULL; ++ } ++ Py_CLEAR(obj); ++ assert(obj == NULL); ++ ++ // gh-98724: complex case, Py_CLEAR() argument has a side effect ++ PyObject* array[1]; ++ array[0] = PyList_New(0); ++ if (array[0] == NULL) { ++ return NULL; ++ } ++ ++ PyObject **p = array; ++ Py_CLEAR(*p++); ++ assert(array[0] == NULL); ++ assert(p == array + 1); ++ ++ Py_RETURN_NONE; ++} ++ ++ ++// Test Py_SETREF() and Py_XSETREF() macros, similar to test_py_clear() ++static PyObject* ++test_py_setref(PyObject *self, PyObject *Py_UNUSED(ignored)) ++{ ++ // Py_SETREF() simple case with a variable ++ PyObject *obj = PyList_New(0); ++ if (obj == NULL) { ++ return NULL; ++ } ++ Py_SETREF(obj, NULL); ++ assert(obj == NULL); ++ ++ // Py_XSETREF() simple case with a variable ++ PyObject *obj2 = PyList_New(0); ++ if (obj2 == NULL) { ++ return NULL; ++ } ++ Py_XSETREF(obj2, NULL); ++ assert(obj2 == NULL); ++ // test Py_XSETREF() when the argument is NULL ++ Py_XSETREF(obj2, NULL); ++ assert(obj2 == NULL); ++ ++ // gh-98724: complex case, Py_SETREF() argument has a side effect ++ PyObject* array[1]; ++ array[0] = PyList_New(0); ++ if (array[0] == NULL) { ++ return NULL; ++ } ++ ++ PyObject **p = array; ++ Py_SETREF(*p++, NULL); ++ assert(array[0] == NULL); ++ assert(p == array + 1); ++ ++ // gh-98724: complex case, Py_XSETREF() argument has a side effect ++ PyObject* array2[1]; ++ array2[0] = PyList_New(0); ++ if (array2[0] == NULL) { ++ return NULL; ++ } ++ ++ PyObject **p2 = array2; ++ Py_XSETREF(*p2++, NULL); ++ assert(array2[0] == NULL); ++ assert(p2 == array2 + 1); ++ ++ // test Py_XSETREF() when the argument is NULL ++ p2 = array2; ++ Py_XSETREF(*p2++, NULL); ++ assert(array2[0] == NULL); ++ assert(p2 == array2 + 1); ++ ++ Py_RETURN_NONE; ++} ++ ++ ++#define TEST_REFCOUNT() \ ++ do { \ ++ PyObject *obj = PyList_New(0); \ ++ if (obj == NULL) { \ ++ return NULL; \ ++ } \ ++ assert(Py_REFCNT(obj) == 1); \ ++ \ ++ /* test Py_NewRef() */ \ ++ PyObject *ref = Py_NewRef(obj); \ ++ assert(ref == obj); \ ++ assert(Py_REFCNT(obj) == 2); \ ++ Py_DECREF(ref); \ ++ \ ++ /* test Py_XNewRef() */ \ ++ PyObject *xref = Py_XNewRef(obj); \ ++ assert(xref == obj); \ ++ assert(Py_REFCNT(obj) == 2); \ ++ Py_DECREF(xref); \ ++ \ ++ assert(Py_XNewRef(NULL) == NULL); \ ++ \ ++ Py_DECREF(obj); \ ++ Py_RETURN_NONE; \ ++ } while (0) ++ ++ ++// Test Py_NewRef() and Py_XNewRef() macros ++static PyObject* ++test_refcount_macros(PyObject *self, PyObject *Py_UNUSED(ignored)) ++{ ++ TEST_REFCOUNT(); ++} ++ ++#undef Py_NewRef ++#undef Py_XNewRef ++ ++// Test Py_NewRef() and Py_XNewRef() functions, after undefining macros. ++static PyObject* ++test_refcount_funcs(PyObject *self, PyObject *Py_UNUSED(ignored)) ++{ ++ TEST_REFCOUNT(); ++} ++ ++ ++// Test Py_Is() function ++#define TEST_PY_IS() \ ++ do { \ ++ PyObject *o_none = Py_None; \ ++ PyObject *o_true = Py_True; \ ++ PyObject *o_false = Py_False; \ ++ PyObject *obj = PyList_New(0); \ ++ if (obj == NULL) { \ ++ return NULL; \ ++ } \ ++ \ ++ /* test Py_Is() */ \ ++ assert(Py_Is(obj, obj)); \ ++ assert(!Py_Is(obj, o_none)); \ ++ \ ++ /* test Py_None */ \ ++ assert(Py_Is(o_none, o_none)); \ ++ assert(!Py_Is(obj, o_none)); \ ++ \ ++ /* test Py_True */ \ ++ assert(Py_Is(o_true, o_true)); \ ++ assert(!Py_Is(o_false, o_true)); \ ++ assert(!Py_Is(obj, o_true)); \ ++ \ ++ /* test Py_False */ \ ++ assert(Py_Is(o_false, o_false)); \ ++ assert(!Py_Is(o_true, o_false)); \ ++ assert(!Py_Is(obj, o_false)); \ ++ \ ++ Py_DECREF(obj); \ ++ Py_RETURN_NONE; \ ++ } while (0) ++ ++// Test Py_Is() macro ++static PyObject* ++test_py_is_macros(PyObject *self, PyObject *Py_UNUSED(ignored)) ++{ ++ TEST_PY_IS(); ++} ++ ++#undef Py_Is ++ ++// Test Py_Is() function, after undefining its macro. ++static PyObject* ++test_py_is_funcs(PyObject *self, PyObject *Py_UNUSED(ignored)) ++{ ++ TEST_PY_IS(); ++} ++ ++ ++static PyObject * ++clear_managed_dict(PyObject *self, PyObject *obj) ++{ ++ PyObject_ClearManagedDict(obj); ++ Py_RETURN_NONE; ++} ++ ++ + static PyMethodDef test_methods[] = { + {"call_pyobject_print", call_pyobject_print, METH_VARARGS}, + {"pyobject_print_null", pyobject_print_null, METH_VARARGS}, +@@ -138,15 +478,28 @@ + {"pyobject_print_os_error", pyobject_print_os_error, METH_VARARGS}, + {"pyobject_clear_weakrefs_no_callbacks", pyobject_clear_weakrefs_no_callbacks, METH_O}, + {"pyobject_enable_deferred_refcount", pyobject_enable_deferred_refcount, METH_O}, ++ {"test_py_try_inc_ref", test_py_try_inc_ref, METH_NOARGS}, ++ {"test_xincref_doesnt_leak",test_xincref_doesnt_leak, METH_NOARGS}, ++ {"test_incref_doesnt_leak", test_incref_doesnt_leak, METH_NOARGS}, ++ {"test_xdecref_doesnt_leak",test_xdecref_doesnt_leak, METH_NOARGS}, ++ {"test_decref_doesnt_leak", test_decref_doesnt_leak, METH_NOARGS}, ++ {"test_incref_decref_API", test_incref_decref_API, METH_NOARGS}, ++#ifdef Py_REF_DEBUG ++ {"negative_refcount", negative_refcount, METH_NOARGS}, ++ {"decref_freed_object", decref_freed_object, METH_NOARGS}, ++#endif ++ {"test_py_clear", test_py_clear, METH_NOARGS}, ++ {"test_py_setref", test_py_setref, METH_NOARGS}, ++ {"test_refcount_macros", test_refcount_macros, METH_NOARGS}, ++ {"test_refcount_funcs", test_refcount_funcs, METH_NOARGS}, ++ {"test_py_is_macros", test_py_is_macros, METH_NOARGS}, ++ {"test_py_is_funcs", test_py_is_funcs, METH_NOARGS}, ++ {"clear_managed_dict", clear_managed_dict, METH_O, NULL}, + {NULL}, + }; + + int + _PyTestCapi_Init_Object(PyObject *m) + { +- if (PyModule_AddFunctions(m, test_methods) < 0) { +- return -1; +- } +- +- return 0; ++ return PyModule_AddFunctions(m, test_methods); + } +diff --git a/Modules/_testcapi/parts.h b/Modules/_testcapi/parts.h +index 65ba77596c7..af6400162da 100644 +--- a/Modules/_testcapi/parts.h ++++ b/Modules/_testcapi/parts.h +@@ -61,5 +61,9 @@ + int _PyTestCapi_Init_Monitoring(PyObject *module); + int _PyTestCapi_Init_Object(PyObject *module); + int _PyTestCapi_Init_Config(PyObject *mod); ++int _PyTestCapi_Init_Import(PyObject *mod); ++int _PyTestCapi_Init_Frame(PyObject *mod); ++int _PyTestCapi_Init_Type(PyObject *mod); ++int _PyTestCapi_Init_Function(PyObject *mod); + + #endif // Py_TESTCAPI_PARTS_H +diff --git a/Modules/_testcapi/set.c b/Modules/_testcapi/set.c +index 31b52cee5e9..092715ab7d0 100644 +--- a/Modules/_testcapi/set.c ++++ b/Modules/_testcapi/set.c +@@ -8,18 +8,37 @@ + RETURN_SIZE(PySet_GET_SIZE(obj)); + } + ++ ++static PyObject* ++test_set_type_size(PyObject *self, PyObject *Py_UNUSED(ignored)) ++{ ++ PyObject *obj = PyList_New(0); ++ if (obj == NULL) { ++ return NULL; ++ } ++ ++ // Ensure that following tests don't modify the object, ++ // to ensure that Py_DECREF() will not crash. ++ assert(Py_TYPE(obj) == &PyList_Type); ++ assert(Py_SIZE(obj) == 0); ++ ++ // bpo-39573: Test Py_SET_TYPE() and Py_SET_SIZE() functions. ++ Py_SET_TYPE(obj, &PyList_Type); ++ Py_SET_SIZE(obj, 0); ++ ++ Py_DECREF(obj); ++ Py_RETURN_NONE; ++} ++ ++ + static PyMethodDef test_methods[] = { + {"set_get_size", set_get_size, METH_O}, +- ++ {"test_set_type_size", test_set_type_size, METH_NOARGS}, + {NULL}, + }; + + int + _PyTestCapi_Init_Set(PyObject *m) + { +- if (PyModule_AddFunctions(m, test_methods) < 0) { +- return -1; +- } +- +- return 0; ++ return PyModule_AddFunctions(m, test_methods); + } +--- /dev/null ++++ b/Modules/_testcapi/type.c +@@ -0,0 +1,251 @@ ++#include "parts.h" ++#include "util.h" ++ ++ ++static PyType_Slot HeapTypeNameType_slots[] = { ++ {0}, ++}; ++ ++static PyType_Spec HeapTypeNameType_Spec = { ++ .name = "_testcapi.HeapTypeNameType", ++ .basicsize = sizeof(PyObject), ++ .flags = Py_TPFLAGS_DEFAULT, ++ .slots = HeapTypeNameType_slots, ++}; ++ ++static PyObject * ++get_heaptype_for_name(PyObject *self, PyObject *Py_UNUSED(ignored)) ++{ ++ return PyType_FromSpec(&HeapTypeNameType_Spec); ++} ++ ++ ++static PyObject * ++get_type_name(PyObject *self, PyObject *type) ++{ ++ assert(PyType_Check(type)); ++ return PyType_GetName((PyTypeObject *)type); ++} ++ ++ ++static PyObject * ++get_type_qualname(PyObject *self, PyObject *type) ++{ ++ assert(PyType_Check(type)); ++ return PyType_GetQualName((PyTypeObject *)type); ++} ++ ++ ++static PyObject * ++get_type_fullyqualname(PyObject *self, PyObject *type) ++{ ++ assert(PyType_Check(type)); ++ return PyType_GetFullyQualifiedName((PyTypeObject *)type); ++} ++ ++ ++static PyObject * ++get_type_module_name(PyObject *self, PyObject *type) ++{ ++ assert(PyType_Check(type)); ++ return PyType_GetModuleName((PyTypeObject *)type); ++} ++ ++ ++static PyObject * ++test_get_type_dict(PyObject *self, PyObject *Py_UNUSED(ignored)) ++{ ++ /* Test for PyType_GetDict */ ++ ++ // Assert ints have a `to_bytes` method ++ PyObject *long_dict = PyType_GetDict(&PyLong_Type); ++ assert(long_dict); ++ assert(PyDict_GetItemString(long_dict, "to_bytes")); // borrowed ref ++ Py_DECREF(long_dict); ++ ++ // Make a new type, add an attribute to it and assert it's there ++ PyObject *HeapTypeNameType = PyType_FromSpec(&HeapTypeNameType_Spec); ++ assert(HeapTypeNameType); ++ assert(PyObject_SetAttrString( ++ HeapTypeNameType, "new_attr", Py_NewRef(Py_None)) >= 0); ++ PyObject *type_dict = PyType_GetDict((PyTypeObject*)HeapTypeNameType); ++ assert(type_dict); ++ assert(PyDict_GetItemString(type_dict, "new_attr")); // borrowed ref ++ Py_DECREF(HeapTypeNameType); ++ Py_DECREF(type_dict); ++ Py_RETURN_NONE; ++} ++ ++ ++static PyObject * ++test_get_statictype_slots(PyObject *self, PyObject *Py_UNUSED(ignored)) ++{ ++ newfunc tp_new = PyType_GetSlot(&PyLong_Type, Py_tp_new); ++ if (PyLong_Type.tp_new != tp_new) { ++ PyErr_SetString(PyExc_AssertionError, "mismatch: tp_new of long"); ++ return NULL; ++ } ++ ++ reprfunc tp_repr = PyType_GetSlot(&PyLong_Type, Py_tp_repr); ++ if (PyLong_Type.tp_repr != tp_repr) { ++ PyErr_SetString(PyExc_AssertionError, "mismatch: tp_repr of long"); ++ return NULL; ++ } ++ ++ ternaryfunc tp_call = PyType_GetSlot(&PyLong_Type, Py_tp_call); ++ if (tp_call != NULL) { ++ PyErr_SetString(PyExc_AssertionError, "mismatch: tp_call of long"); ++ return NULL; ++ } ++ ++ binaryfunc nb_add = PyType_GetSlot(&PyLong_Type, Py_nb_add); ++ if (PyLong_Type.tp_as_number->nb_add != nb_add) { ++ PyErr_SetString(PyExc_AssertionError, "mismatch: nb_add of long"); ++ return NULL; ++ } ++ ++ lenfunc mp_length = PyType_GetSlot(&PyLong_Type, Py_mp_length); ++ if (mp_length != NULL) { ++ PyErr_SetString(PyExc_AssertionError, "mismatch: mp_length of long"); ++ return NULL; ++ } ++ ++ void *over_value = PyType_GetSlot(&PyLong_Type, Py_bf_releasebuffer + 1); ++ if (over_value != NULL) { ++ PyErr_SetString(PyExc_AssertionError, "mismatch: max+1 of long"); ++ return NULL; ++ } ++ ++ tp_new = PyType_GetSlot(&PyLong_Type, 0); ++ if (tp_new != NULL) { ++ PyErr_SetString(PyExc_AssertionError, "mismatch: slot 0 of long"); ++ return NULL; ++ } ++ if (PyErr_ExceptionMatches(PyExc_SystemError)) { ++ // This is the right exception ++ PyErr_Clear(); ++ } ++ else { ++ return NULL; ++ } ++ ++ Py_RETURN_NONE; ++} ++ ++ ++// Get type->tp_version_tag ++static PyObject * ++type_get_version(PyObject *self, PyObject *type) ++{ ++ if (!PyType_Check(type)) { ++ PyErr_SetString(PyExc_TypeError, "argument must be a type"); ++ return NULL; ++ } ++ PyObject *res = PyLong_FromUnsignedLong( ++ ((PyTypeObject *)type)->tp_version_tag); ++ if (res == NULL) { ++ assert(PyErr_Occurred()); ++ return NULL; ++ } ++ return res; ++} ++ ++static PyObject * ++type_modified(PyObject *self, PyObject *arg) ++{ ++ if (!PyType_Check(arg)) { ++ PyErr_SetString(PyExc_TypeError, "argument must be a type"); ++ return NULL; ++ } ++ PyTypeObject *type = (PyTypeObject*)arg; ++ ++ PyType_Modified(type); ++ Py_RETURN_NONE; ++} ++ ++ ++static PyObject * ++type_assign_version(PyObject *self, PyObject *arg) ++{ ++ if (!PyType_Check(arg)) { ++ PyErr_SetString(PyExc_TypeError, "argument must be a type"); ++ return NULL; ++ } ++ PyTypeObject *type = (PyTypeObject*)arg; ++ ++ int res = PyUnstable_Type_AssignVersionTag(type); ++ return PyLong_FromLong(res); ++} ++ ++ ++static PyObject * ++type_get_tp_bases(PyObject *self, PyObject *arg) ++{ ++ if (!PyType_Check(arg)) { ++ PyErr_SetString(PyExc_TypeError, "argument must be a type"); ++ return NULL; ++ } ++ PyTypeObject *type = (PyTypeObject*)arg; ++ ++ PyObject *bases = type->tp_bases; ++ if (bases == NULL) { ++ Py_RETURN_NONE; ++ } ++ return Py_NewRef(bases); ++} ++ ++static PyObject * ++type_get_tp_mro(PyObject *self, PyObject *arg) ++{ ++ if (!PyType_Check(arg)) { ++ PyErr_SetString(PyExc_TypeError, "argument must be a type"); ++ return NULL; ++ } ++ PyTypeObject *type = (PyTypeObject*)arg; ++ ++ PyObject *mro = ((PyTypeObject *)type)->tp_mro; ++ if (mro == NULL) { ++ Py_RETURN_NONE; ++ } ++ return Py_NewRef(mro); ++} ++ ++ ++static PyObject * ++type_freeze(PyObject *module, PyObject *arg) ++{ ++ if (!PyType_Check(arg)) { ++ PyErr_SetString(PyExc_TypeError, "argument must be a type"); ++ return NULL; ++ } ++ PyTypeObject *type = (PyTypeObject*)arg; ++ ++ if (PyType_Freeze(type) < 0) { ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} ++ ++ ++static PyMethodDef test_methods[] = { ++ {"get_heaptype_for_name", get_heaptype_for_name, METH_NOARGS}, ++ {"get_type_name", get_type_name, METH_O}, ++ {"get_type_qualname", get_type_qualname, METH_O}, ++ {"get_type_fullyqualname", get_type_fullyqualname, METH_O}, ++ {"get_type_module_name", get_type_module_name, METH_O}, ++ {"test_get_type_dict", test_get_type_dict, METH_NOARGS}, ++ {"test_get_statictype_slots", test_get_statictype_slots, METH_NOARGS}, ++ {"type_get_version", type_get_version, METH_O, PyDoc_STR("type->tp_version_tag")}, ++ {"type_modified", type_modified, METH_O, PyDoc_STR("PyType_Modified")}, ++ {"type_assign_version", type_assign_version, METH_O, PyDoc_STR("PyUnstable_Type_AssignVersionTag")}, ++ {"type_get_tp_bases", type_get_tp_bases, METH_O}, ++ {"type_get_tp_mro", type_get_tp_mro, METH_O}, ++ {"type_freeze", type_freeze, METH_O}, ++ {NULL}, ++}; ++ ++int ++_PyTestCapi_Init_Type(PyObject *m) ++{ ++ return PyModule_AddFunctions(m, test_methods); ++} +diff --git a/Modules/_testcapi/watchers.c b/Modules/_testcapi/watchers.c +index 321d3aeffb6..f7440769b95 100644 +--- a/Modules/_testcapi/watchers.c ++++ b/Modules/_testcapi/watchers.c +@@ -428,7 +428,8 @@ + PyObject *exc = PyErr_GetRaisedException(); + for (int i = 0; i < num_watchers; i++) { + if (PyCode_ClearWatcher(watcher_ids[i]) < 0) { +- PyErr_WriteUnraisable(Py_None); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "clearing code watcher"); + break; + } + } +@@ -609,7 +610,8 @@ + PyObject *exc = PyErr_GetRaisedException(); + for (int i = 0; i < num_watchers; i++) { + if (PyFunction_ClearWatcher(watcher_ids[i]) < 0) { +- PyErr_WriteUnraisable(Py_None); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "clearing function watcher"); + break; + } + } +@@ -755,7 +757,8 @@ + PyObject *exc = PyErr_GetRaisedException(); + for (int i = 0; i < num_watchers; i++) { + if (PyContext_ClearWatcher(watcher_ids[i]) < 0) { +- PyErr_WriteUnraisable(Py_None); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "clearing context watcher"); + break; + } + } +diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c +index 8d86b535eff..c84646ccf03 100644 +--- a/Modules/_testcapimodule.c ++++ b/Modules/_testcapimodule.c +@@ -163,124 +163,6 @@ + #endif + } + +-static PyObject* +-test_list_api(PyObject *self, PyObject *Py_UNUSED(ignored)) +-{ +- PyObject* list; +- int i; +- +- /* SF bug 132008: PyList_Reverse segfaults */ +-#define NLIST 30 +- list = PyList_New(NLIST); +- if (list == (PyObject*)NULL) +- return (PyObject*)NULL; +- /* list = range(NLIST) */ +- for (i = 0; i < NLIST; ++i) { +- PyObject* anint = PyLong_FromLong(i); +- if (anint == (PyObject*)NULL) { +- Py_DECREF(list); +- return (PyObject*)NULL; +- } +- PyList_SET_ITEM(list, i, anint); +- } +- /* list.reverse(), via PyList_Reverse() */ +- i = PyList_Reverse(list); /* should not blow up! */ +- if (i != 0) { +- Py_DECREF(list); +- return (PyObject*)NULL; +- } +- /* Check that list == range(29, -1, -1) now */ +- for (i = 0; i < NLIST; ++i) { +- PyObject* anint = PyList_GET_ITEM(list, i); +- if (PyLong_AS_LONG(anint) != NLIST-1-i) { +- PyErr_SetString(get_testerror(self), +- "test_list_api: reverse screwed up"); +- Py_DECREF(list); +- return (PyObject*)NULL; +- } +- } +- Py_DECREF(list); +-#undef NLIST +- +- Py_RETURN_NONE; +-} +- +-static int +-test_dict_inner(PyObject *self, int count) +-{ +- Py_ssize_t pos = 0, iterations = 0; +- int i; +- PyObject *dict = PyDict_New(); +- PyObject *v, *k; +- +- if (dict == NULL) +- return -1; +- +- for (i = 0; i < count; i++) { +- v = PyLong_FromLong(i); +- if (v == NULL) { +- goto error; +- } +- if (PyDict_SetItem(dict, v, v) < 0) { +- Py_DECREF(v); +- goto error; +- } +- Py_DECREF(v); +- } +- +- k = v = UNINITIALIZED_PTR; +- while (PyDict_Next(dict, &pos, &k, &v)) { +- PyObject *o; +- iterations++; +- +- assert(k != UNINITIALIZED_PTR); +- assert(v != UNINITIALIZED_PTR); +- i = PyLong_AS_LONG(v) + 1; +- o = PyLong_FromLong(i); +- if (o == NULL) { +- goto error; +- } +- if (PyDict_SetItem(dict, k, o) < 0) { +- Py_DECREF(o); +- goto error; +- } +- Py_DECREF(o); +- k = v = UNINITIALIZED_PTR; +- } +- assert(k == UNINITIALIZED_PTR); +- assert(v == UNINITIALIZED_PTR); +- +- Py_DECREF(dict); +- +- if (iterations != count) { +- PyErr_SetString( +- get_testerror(self), +- "test_dict_iteration: dict iteration went wrong "); +- return -1; +- } else { +- return 0; +- } +-error: +- Py_DECREF(dict); +- return -1; +-} +- +- +- +-static PyObject* +-test_dict_iteration(PyObject* self, PyObject *Py_UNUSED(ignored)) +-{ +- int i; +- +- for (i = 0; i < 200; i++) { +- if (test_dict_inner(self, i) < 0) { +- return NULL; +- } +- } +- +- Py_RETURN_NONE; +-} +- + /* Issue #4701: Check that PyObject_Hash implicitly calls + * PyType_Ready if it hasn't already been called + */ +@@ -530,136 +412,6 @@ + } + + +-static PyObject * +-test_get_statictype_slots(PyObject *self, PyObject *Py_UNUSED(ignored)) +-{ +- newfunc tp_new = PyType_GetSlot(&PyLong_Type, Py_tp_new); +- if (PyLong_Type.tp_new != tp_new) { +- PyErr_SetString(PyExc_AssertionError, "mismatch: tp_new of long"); +- return NULL; +- } +- +- reprfunc tp_repr = PyType_GetSlot(&PyLong_Type, Py_tp_repr); +- if (PyLong_Type.tp_repr != tp_repr) { +- PyErr_SetString(PyExc_AssertionError, "mismatch: tp_repr of long"); +- return NULL; +- } +- +- ternaryfunc tp_call = PyType_GetSlot(&PyLong_Type, Py_tp_call); +- if (tp_call != NULL) { +- PyErr_SetString(PyExc_AssertionError, "mismatch: tp_call of long"); +- return NULL; +- } +- +- binaryfunc nb_add = PyType_GetSlot(&PyLong_Type, Py_nb_add); +- if (PyLong_Type.tp_as_number->nb_add != nb_add) { +- PyErr_SetString(PyExc_AssertionError, "mismatch: nb_add of long"); +- return NULL; +- } +- +- lenfunc mp_length = PyType_GetSlot(&PyLong_Type, Py_mp_length); +- if (mp_length != NULL) { +- PyErr_SetString(PyExc_AssertionError, "mismatch: mp_length of long"); +- return NULL; +- } +- +- void *over_value = PyType_GetSlot(&PyLong_Type, Py_bf_releasebuffer + 1); +- if (over_value != NULL) { +- PyErr_SetString(PyExc_AssertionError, "mismatch: max+1 of long"); +- return NULL; +- } +- +- tp_new = PyType_GetSlot(&PyLong_Type, 0); +- if (tp_new != NULL) { +- PyErr_SetString(PyExc_AssertionError, "mismatch: slot 0 of long"); +- return NULL; +- } +- if (PyErr_ExceptionMatches(PyExc_SystemError)) { +- // This is the right exception +- PyErr_Clear(); +- } +- else { +- return NULL; +- } +- +- Py_RETURN_NONE; +-} +- +- +-static PyType_Slot HeapTypeNameType_slots[] = { +- {0}, +-}; +- +-static PyType_Spec HeapTypeNameType_Spec = { +- .name = "_testcapi.HeapTypeNameType", +- .basicsize = sizeof(PyObject), +- .flags = Py_TPFLAGS_DEFAULT, +- .slots = HeapTypeNameType_slots, +-}; +- +-static PyObject * +-get_heaptype_for_name(PyObject *self, PyObject *Py_UNUSED(ignored)) +-{ +- return PyType_FromSpec(&HeapTypeNameType_Spec); +-} +- +- +-static PyObject * +-get_type_name(PyObject *self, PyObject *type) +-{ +- assert(PyType_Check(type)); +- return PyType_GetName((PyTypeObject *)type); +-} +- +- +-static PyObject * +-get_type_qualname(PyObject *self, PyObject *type) +-{ +- assert(PyType_Check(type)); +- return PyType_GetQualName((PyTypeObject *)type); +-} +- +- +-static PyObject * +-get_type_fullyqualname(PyObject *self, PyObject *type) +-{ +- assert(PyType_Check(type)); +- return PyType_GetFullyQualifiedName((PyTypeObject *)type); +-} +- +- +-static PyObject * +-get_type_module_name(PyObject *self, PyObject *type) +-{ +- assert(PyType_Check(type)); +- return PyType_GetModuleName((PyTypeObject *)type); +-} +- +- +-static PyObject * +-test_get_type_dict(PyObject *self, PyObject *Py_UNUSED(ignored)) +-{ +- /* Test for PyType_GetDict */ +- +- // Assert ints have a `to_bytes` method +- PyObject *long_dict = PyType_GetDict(&PyLong_Type); +- assert(long_dict); +- assert(PyDict_GetItemString(long_dict, "to_bytes")); // borrowed ref +- Py_DECREF(long_dict); +- +- // Make a new type, add an attribute to it and assert it's there +- PyObject *HeapTypeNameType = PyType_FromSpec(&HeapTypeNameType_Spec); +- assert(HeapTypeNameType); +- assert(PyObject_SetAttrString( +- HeapTypeNameType, "new_attr", Py_NewRef(Py_None)) >= 0); +- PyObject *type_dict = PyType_GetDict((PyTypeObject*)HeapTypeNameType); +- assert(type_dict); +- assert(PyDict_GetItemString(type_dict, "new_attr")); // borrowed ref +- Py_DECREF(HeapTypeNameType); +- Py_DECREF(type_dict); +- Py_RETURN_NONE; +-} +- + static PyObject * + pyobject_repr_from_null(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +@@ -885,61 +637,6 @@ + return PyLong_FromUnsignedLong((unsigned long)num_added); + } + +-/* Test PyOS_string_to_double. */ +-static PyObject * +-test_string_to_double(PyObject *self, PyObject *Py_UNUSED(ignored)) { +- double result; +- const char *msg; +- +-#define CHECK_STRING(STR, expected) \ +- do { \ +- result = PyOS_string_to_double(STR, NULL, NULL); \ +- if (result == -1.0 && PyErr_Occurred()) { \ +- return NULL; \ +- } \ +- if (result != (double)expected) { \ +- msg = "conversion of " STR " to float failed"; \ +- goto fail; \ +- } \ +- } while (0) +- +-#define CHECK_INVALID(STR) \ +- do { \ +- result = PyOS_string_to_double(STR, NULL, NULL); \ +- if (result == -1.0 && PyErr_Occurred()) { \ +- if (PyErr_ExceptionMatches(PyExc_ValueError)) { \ +- PyErr_Clear(); \ +- } \ +- else { \ +- return NULL; \ +- } \ +- } \ +- else { \ +- msg = "conversion of " STR " didn't raise ValueError"; \ +- goto fail; \ +- } \ +- } while (0) +- +- CHECK_STRING("0.1", 0.1); +- CHECK_STRING("1.234", 1.234); +- CHECK_STRING("-1.35", -1.35); +- CHECK_STRING(".1e01", 1.0); +- CHECK_STRING("2.e-2", 0.02); +- +- CHECK_INVALID(" 0.1"); +- CHECK_INVALID("\t\n-3"); +- CHECK_INVALID(".123 "); +- CHECK_INVALID("3\n"); +- CHECK_INVALID("123abc"); +- +- Py_RETURN_NONE; +- fail: +- return raiseTestError(self, "test_string_to_double", msg); +-#undef CHECK_STRING +-#undef CHECK_INVALID +-} +- +- + /* Coverage testing of capsule objects. */ + + static const char *capsule_name = "capsule name"; +@@ -1360,15 +1057,10 @@ + if (ret != -1 || match == 0) + goto error; + +- PyObject *mod_io = PyImport_ImportModule("_io"); +- if (mod_io == NULL) { +- return NULL; +- } +- + /* bytesiobuf_getbuffer() */ +- PyTypeObject *type = (PyTypeObject *)PyObject_GetAttrString( +- mod_io, "_BytesIOBuffer"); +- Py_DECREF(mod_io); ++ PyTypeObject *type = (PyTypeObject *)PyImport_ImportModuleAttrString( ++ "_io", ++ "_BytesIOBuffer"); + if (type == NULL) { + return NULL; + } +@@ -1521,48 +1213,6 @@ + NULL + }; + +-static PyObject * +-_test_incref(PyObject *ob) +-{ +- return Py_NewRef(ob); +-} +- +-static PyObject * +-test_xincref_doesnt_leak(PyObject *ob, PyObject *Py_UNUSED(ignored)) +-{ +- PyObject *obj = PyLong_FromLong(0); +- Py_XINCREF(_test_incref(obj)); +- Py_DECREF(obj); +- Py_DECREF(obj); +- Py_DECREF(obj); +- Py_RETURN_NONE; +-} +- +-static PyObject * +-test_incref_doesnt_leak(PyObject *ob, PyObject *Py_UNUSED(ignored)) +-{ +- PyObject *obj = PyLong_FromLong(0); +- Py_INCREF(_test_incref(obj)); +- Py_DECREF(obj); +- Py_DECREF(obj); +- Py_DECREF(obj); +- Py_RETURN_NONE; +-} +- +-static PyObject * +-test_xdecref_doesnt_leak(PyObject *ob, PyObject *Py_UNUSED(ignored)) +-{ +- Py_XDECREF(PyLong_FromLong(0)); +- Py_RETURN_NONE; +-} +- +-static PyObject * +-test_decref_doesnt_leak(PyObject *ob, PyObject *Py_UNUSED(ignored)) +-{ +- Py_DECREF(PyLong_FromLong(0)); +- Py_RETURN_NONE; +-} +- + static PyObject * + test_structseq_newtype_doesnt_leak(PyObject *Py_UNUSED(self), + PyObject *Py_UNUSED(args)) +@@ -1609,16 +1259,6 @@ + Py_RETURN_NONE; + } + +-static PyObject * +-test_incref_decref_API(PyObject *ob, PyObject *Py_UNUSED(ignored)) +-{ +- PyObject *obj = PyLong_FromLong(0); +- Py_IncRef(obj); +- Py_DecRef(obj); +- Py_DecRef(obj); +- Py_RETURN_NONE; +-} +- + typedef struct { + PyThread_type_lock start_event; + PyThread_type_lock exit_event; +@@ -1744,7 +1384,7 @@ + &value, &filename, &version)) + return NULL; + +- fp = _Py_fopen_obj(filename, "wb"); ++ fp = Py_fopen(filename, "wb"); + if (fp == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +@@ -1769,7 +1409,7 @@ + &obj, &filename, &version)) + return NULL; + +- fp = _Py_fopen_obj(filename, "wb"); ++ fp = Py_fopen(filename, "wb"); + if (fp == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +@@ -1793,7 +1433,7 @@ + if (!PyArg_ParseTuple(args, "O:pymarshal_read_short_from_file", &filename)) + return NULL; + +- fp = _Py_fopen_obj(filename, "rb"); ++ fp = Py_fopen(filename, "rb"); + if (fp == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +@@ -1818,7 +1458,7 @@ + if (!PyArg_ParseTuple(args, "O:pymarshal_read_long_from_file", &filename)) + return NULL; + +- fp = _Py_fopen_obj(filename, "rb"); ++ fp = Py_fopen(filename, "rb"); + if (fp == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +@@ -1840,7 +1480,7 @@ + if (!PyArg_ParseTuple(args, "O:pymarshal_read_last_object_from_file", &filename)) + return NULL; + +- FILE *fp = _Py_fopen_obj(filename, "rb"); ++ FILE *fp = Py_fopen(filename, "rb"); + if (fp == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +@@ -1863,7 +1503,7 @@ + if (!PyArg_ParseTuple(args, "O:pymarshal_read_object_from_file", &filename)) + return NULL; + +- FILE *fp = _Py_fopen_obj(filename, "rb"); ++ FILE *fp = Py_fopen(filename, "rb"); + if (fp == NULL) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +@@ -2036,45 +1676,6 @@ + } + + +-#ifdef Py_REF_DEBUG +-static PyObject * +-negative_refcount(PyObject *self, PyObject *Py_UNUSED(args)) +-{ +- PyObject *obj = PyUnicode_FromString("negative_refcount"); +- if (obj == NULL) { +- return NULL; +- } +- assert(Py_REFCNT(obj) == 1); +- +- Py_SET_REFCNT(obj, 0); +- /* Py_DECREF() must call _Py_NegativeRefcount() and abort Python */ +- Py_DECREF(obj); +- +- Py_RETURN_NONE; +-} +- +-static PyObject * +-decref_freed_object(PyObject *self, PyObject *Py_UNUSED(args)) +-{ +- PyObject *obj = PyUnicode_FromString("decref_freed_object"); +- if (obj == NULL) { +- return NULL; +- } +- assert(Py_REFCNT(obj) == 1); +- +- // Deallocate the memory +- Py_DECREF(obj); +- // obj is a now a dangling pointer +- +- // gh-109496: If Python is built in debug mode, Py_DECREF() must call +- // _Py_NegativeRefcount() and abort Python. +- Py_DECREF(obj); +- +- Py_RETURN_NONE; +-} +-#endif +- +- + /* Functions for testing C calling conventions (METH_*) are named meth_*, + * e.g. "meth_varargs" for METH_VARARGS. + * +@@ -2178,319 +1779,55 @@ + return PyNumber_ToBase(obj, base); + } + +-static PyObject* +-test_set_type_size(PyObject *self, PyObject *Py_UNUSED(ignored)) +-{ +- PyObject *obj = PyList_New(0); +- if (obj == NULL) { +- return NULL; ++/* We only use 2 in test_capi/test_misc.py. */ ++#define NUM_BASIC_STATIC_TYPES 2 ++static PyTypeObject BasicStaticTypes[NUM_BASIC_STATIC_TYPES] = { ++#define INIT_BASIC_STATIC_TYPE \ ++ { \ ++ PyVarObject_HEAD_INIT(NULL, 0) \ ++ .tp_name = "BasicStaticType", \ ++ .tp_basicsize = sizeof(PyObject), \ + } ++ INIT_BASIC_STATIC_TYPE, ++ INIT_BASIC_STATIC_TYPE, ++#undef INIT_BASIC_STATIC_TYPE ++}; ++static int num_basic_static_types_used = 0; + +- // Ensure that following tests don't modify the object, +- // to ensure that Py_DECREF() will not crash. +- assert(Py_TYPE(obj) == &PyList_Type); +- assert(Py_SIZE(obj) == 0); +- +- // bpo-39573: Test Py_SET_TYPE() and Py_SET_SIZE() functions. +- Py_SET_TYPE(obj, &PyList_Type); +- Py_SET_SIZE(obj, 0); +- +- Py_DECREF(obj); +- Py_RETURN_NONE; +-} +- +- +-// Test Py_CLEAR() macro +-static PyObject* +-test_py_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) ++static PyObject * ++get_basic_static_type(PyObject *self, PyObject *args) + { +- // simple case with a variable +- PyObject *obj = PyList_New(0); +- if (obj == NULL) { ++ PyObject *base = NULL; ++ if (!PyArg_ParseTuple(args, "|O", &base)) { + return NULL; + } +- Py_CLEAR(obj); +- assert(obj == NULL); ++ assert(base == NULL || PyType_Check(base)); + +- // gh-98724: complex case, Py_CLEAR() argument has a side effect +- PyObject* array[1]; +- array[0] = PyList_New(0); +- if (array[0] == NULL) { ++ if(num_basic_static_types_used >= NUM_BASIC_STATIC_TYPES) { ++ PyErr_SetString(PyExc_RuntimeError, "no more available basic static types"); + return NULL; + } ++ PyTypeObject *cls = &BasicStaticTypes[num_basic_static_types_used++]; + +- PyObject **p = array; +- Py_CLEAR(*p++); +- assert(array[0] == NULL); +- assert(p == array + 1); +- +- Py_RETURN_NONE; ++ if (base != NULL) { ++ cls->tp_bases = PyTuple_Pack(1, base); ++ if (cls->tp_bases == NULL) { ++ return NULL; ++ } ++ cls->tp_base = (PyTypeObject *)Py_NewRef(base); ++ } ++ if (PyType_Ready(cls) < 0) { ++ Py_DECREF(cls->tp_bases); ++ Py_DECREF(cls->tp_base); ++ return NULL; ++ } ++ return (PyObject *)cls; + } + + +-// Test Py_SETREF() and Py_XSETREF() macros, similar to test_py_clear() +-static PyObject* +-test_py_setref(PyObject *self, PyObject *Py_UNUSED(ignored)) +-{ +- // Py_SETREF() simple case with a variable +- PyObject *obj = PyList_New(0); +- if (obj == NULL) { +- return NULL; +- } +- Py_SETREF(obj, NULL); +- assert(obj == NULL); +- +- // Py_XSETREF() simple case with a variable +- PyObject *obj2 = PyList_New(0); +- if (obj2 == NULL) { +- return NULL; +- } +- Py_XSETREF(obj2, NULL); +- assert(obj2 == NULL); +- // test Py_XSETREF() when the argument is NULL +- Py_XSETREF(obj2, NULL); +- assert(obj2 == NULL); +- +- // gh-98724: complex case, Py_SETREF() argument has a side effect +- PyObject* array[1]; +- array[0] = PyList_New(0); +- if (array[0] == NULL) { +- return NULL; +- } +- +- PyObject **p = array; +- Py_SETREF(*p++, NULL); +- assert(array[0] == NULL); +- assert(p == array + 1); +- +- // gh-98724: complex case, Py_XSETREF() argument has a side effect +- PyObject* array2[1]; +- array2[0] = PyList_New(0); +- if (array2[0] == NULL) { +- return NULL; +- } +- +- PyObject **p2 = array2; +- Py_XSETREF(*p2++, NULL); +- assert(array2[0] == NULL); +- assert(p2 == array2 + 1); +- +- // test Py_XSETREF() when the argument is NULL +- p2 = array2; +- Py_XSETREF(*p2++, NULL); +- assert(array2[0] == NULL); +- assert(p2 == array2 + 1); +- +- Py_RETURN_NONE; +-} +- +- +-#define TEST_REFCOUNT() \ +- do { \ +- PyObject *obj = PyList_New(0); \ +- if (obj == NULL) { \ +- return NULL; \ +- } \ +- assert(Py_REFCNT(obj) == 1); \ +- \ +- /* test Py_NewRef() */ \ +- PyObject *ref = Py_NewRef(obj); \ +- assert(ref == obj); \ +- assert(Py_REFCNT(obj) == 2); \ +- Py_DECREF(ref); \ +- \ +- /* test Py_XNewRef() */ \ +- PyObject *xref = Py_XNewRef(obj); \ +- assert(xref == obj); \ +- assert(Py_REFCNT(obj) == 2); \ +- Py_DECREF(xref); \ +- \ +- assert(Py_XNewRef(NULL) == NULL); \ +- \ +- Py_DECREF(obj); \ +- Py_RETURN_NONE; \ +- } while (0) +- +- +-// Test Py_NewRef() and Py_XNewRef() macros +-static PyObject* +-test_refcount_macros(PyObject *self, PyObject *Py_UNUSED(ignored)) +-{ +- TEST_REFCOUNT(); +-} +- +-#undef Py_NewRef +-#undef Py_XNewRef +- +-// Test Py_NewRef() and Py_XNewRef() functions, after undefining macros. +-static PyObject* +-test_refcount_funcs(PyObject *self, PyObject *Py_UNUSED(ignored)) +-{ +- TEST_REFCOUNT(); +-} +- +- +-// Test Py_Is() function +-#define TEST_PY_IS() \ +- do { \ +- PyObject *o_none = Py_None; \ +- PyObject *o_true = Py_True; \ +- PyObject *o_false = Py_False; \ +- PyObject *obj = PyList_New(0); \ +- if (obj == NULL) { \ +- return NULL; \ +- } \ +- \ +- /* test Py_Is() */ \ +- assert(Py_Is(obj, obj)); \ +- assert(!Py_Is(obj, o_none)); \ +- \ +- /* test Py_None */ \ +- assert(Py_Is(o_none, o_none)); \ +- assert(!Py_Is(obj, o_none)); \ +- \ +- /* test Py_True */ \ +- assert(Py_Is(o_true, o_true)); \ +- assert(!Py_Is(o_false, o_true)); \ +- assert(!Py_Is(obj, o_true)); \ +- \ +- /* test Py_False */ \ +- assert(Py_Is(o_false, o_false)); \ +- assert(!Py_Is(o_true, o_false)); \ +- assert(!Py_Is(obj, o_false)); \ +- \ +- Py_DECREF(obj); \ +- Py_RETURN_NONE; \ +- } while (0) +- +-// Test Py_Is() macro +-static PyObject* +-test_py_is_macros(PyObject *self, PyObject *Py_UNUSED(ignored)) +-{ +- TEST_PY_IS(); +-} +- +-#undef Py_Is +- +-// Test Py_Is() function, after undefining its macro. +-static PyObject* +-test_py_is_funcs(PyObject *self, PyObject *Py_UNUSED(ignored)) +-{ +- TEST_PY_IS(); +-} +- +- +-// type->tp_version_tag +-static PyObject * +-type_get_version(PyObject *self, PyObject *type) +-{ +- if (!PyType_Check(type)) { +- PyErr_SetString(PyExc_TypeError, "argument must be a type"); +- return NULL; +- } +- PyObject *res = PyLong_FromUnsignedLong( +- ((PyTypeObject *)type)->tp_version_tag); +- if (res == NULL) { +- assert(PyErr_Occurred()); +- return NULL; +- } +- return res; +-} +- +-static PyObject * +-type_modified(PyObject *self, PyObject *type) +-{ +- if (!PyType_Check(type)) { +- PyErr_SetString(PyExc_TypeError, "argument must be a type"); +- return NULL; +- } +- PyType_Modified((PyTypeObject *)type); +- Py_RETURN_NONE; +-} +- +- +-static PyObject * +-type_assign_version(PyObject *self, PyObject *type) +-{ +- if (!PyType_Check(type)) { +- PyErr_SetString(PyExc_TypeError, "argument must be a type"); +- return NULL; +- } +- int res = PyUnstable_Type_AssignVersionTag((PyTypeObject *)type); +- return PyLong_FromLong(res); +-} +- +- +-static PyObject * +-type_get_tp_bases(PyObject *self, PyObject *type) +-{ +- PyObject *bases = ((PyTypeObject *)type)->tp_bases; +- if (bases == NULL) { +- Py_RETURN_NONE; +- } +- return Py_NewRef(bases); +-} +- +-static PyObject * +-type_get_tp_mro(PyObject *self, PyObject *type) +-{ +- PyObject *mro = ((PyTypeObject *)type)->tp_mro; +- if (mro == NULL) { +- Py_RETURN_NONE; +- } +- return Py_NewRef(mro); +-} +- +- +-/* We only use 2 in test_capi/test_misc.py. */ +-#define NUM_BASIC_STATIC_TYPES 2 +-static PyTypeObject BasicStaticTypes[NUM_BASIC_STATIC_TYPES] = { +-#define INIT_BASIC_STATIC_TYPE \ +- { \ +- PyVarObject_HEAD_INIT(NULL, 0) \ +- .tp_name = "BasicStaticType", \ +- .tp_basicsize = sizeof(PyObject), \ +- } +- INIT_BASIC_STATIC_TYPE, +- INIT_BASIC_STATIC_TYPE, +-#undef INIT_BASIC_STATIC_TYPE +-}; +-static int num_basic_static_types_used = 0; +- +-static PyObject * +-get_basic_static_type(PyObject *self, PyObject *args) +-{ +- PyObject *base = NULL; +- if (!PyArg_ParseTuple(args, "|O", &base)) { +- return NULL; +- } +- assert(base == NULL || PyType_Check(base)); +- +- if(num_basic_static_types_used >= NUM_BASIC_STATIC_TYPES) { +- PyErr_SetString(PyExc_RuntimeError, "no more available basic static types"); +- return NULL; +- } +- PyTypeObject *cls = &BasicStaticTypes[num_basic_static_types_used++]; +- +- if (base != NULL) { +- cls->tp_bases = PyTuple_Pack(1, base); +- if (cls->tp_bases == NULL) { +- return NULL; +- } +- cls->tp_base = (PyTypeObject *)Py_NewRef(base); +- } +- if (PyType_Ready(cls) < 0) { +- Py_DECREF(cls->tp_bases); +- Py_DECREF(cls->tp_base); +- return NULL; +- } +- return (PyObject *)cls; +-} +- +- +-// Test PyThreadState C API +-static PyObject * +-test_tstate_capi(PyObject *self, PyObject *Py_UNUSED(args)) ++// Test PyThreadState C API ++static PyObject * ++test_tstate_capi(PyObject *self, PyObject *Py_UNUSED(args)) + { + // PyThreadState_Get() + PyThreadState *tstate = PyThreadState_Get(); +@@ -2533,109 +1870,6 @@ + Py_RETURN_NONE; + } + +-static PyObject * +-frame_getlocals(PyObject *self, PyObject *frame) +-{ +- if (!PyFrame_Check(frame)) { +- PyErr_SetString(PyExc_TypeError, "argument must be a frame"); +- return NULL; +- } +- return PyFrame_GetLocals((PyFrameObject *)frame); +-} +- +-static PyObject * +-frame_getglobals(PyObject *self, PyObject *frame) +-{ +- if (!PyFrame_Check(frame)) { +- PyErr_SetString(PyExc_TypeError, "argument must be a frame"); +- return NULL; +- } +- return PyFrame_GetGlobals((PyFrameObject *)frame); +-} +- +-static PyObject * +-frame_getgenerator(PyObject *self, PyObject *frame) +-{ +- if (!PyFrame_Check(frame)) { +- PyErr_SetString(PyExc_TypeError, "argument must be a frame"); +- return NULL; +- } +- return PyFrame_GetGenerator((PyFrameObject *)frame); +-} +- +-static PyObject * +-frame_getbuiltins(PyObject *self, PyObject *frame) +-{ +- if (!PyFrame_Check(frame)) { +- PyErr_SetString(PyExc_TypeError, "argument must be a frame"); +- return NULL; +- } +- return PyFrame_GetBuiltins((PyFrameObject *)frame); +-} +- +-static PyObject * +-frame_getlasti(PyObject *self, PyObject *frame) +-{ +- if (!PyFrame_Check(frame)) { +- PyErr_SetString(PyExc_TypeError, "argument must be a frame"); +- return NULL; +- } +- int lasti = PyFrame_GetLasti((PyFrameObject *)frame); +- if (lasti < 0) { +- assert(lasti == -1); +- Py_RETURN_NONE; +- } +- return PyLong_FromLong(lasti); +-} +- +-static PyObject * +-frame_new(PyObject *self, PyObject *args) +-{ +- PyObject *code, *globals, *locals; +- if (!PyArg_ParseTuple(args, "OOO", &code, &globals, &locals)) { +- return NULL; +- } +- if (!PyCode_Check(code)) { +- PyErr_SetString(PyExc_TypeError, "argument must be a code object"); +- return NULL; +- } +- PyThreadState *tstate = PyThreadState_Get(); +- +- return (PyObject *)PyFrame_New(tstate, (PyCodeObject *)code, globals, locals); +-} +- +-static PyObject * +-test_frame_getvar(PyObject *self, PyObject *args) +-{ +- PyObject *frame, *name; +- if (!PyArg_ParseTuple(args, "OO", &frame, &name)) { +- return NULL; +- } +- if (!PyFrame_Check(frame)) { +- PyErr_SetString(PyExc_TypeError, "argument must be a frame"); +- return NULL; +- } +- +- return PyFrame_GetVar((PyFrameObject *)frame, name); +-} +- +-static PyObject * +-test_frame_getvarstring(PyObject *self, PyObject *args) +-{ +- PyObject *frame; +- const char *name; +- if (!PyArg_ParseTuple(args, "Oy", &frame, &name)) { +- return NULL; +- } +- if (!PyFrame_Check(frame)) { +- PyErr_SetString(PyExc_TypeError, "argument must be a frame"); +- return NULL; +- } +- +- return PyFrame_GetVarString((PyFrameObject *)frame, name); +-} +- +- + static PyObject * + gen_get_code(PyObject *self, PyObject *gen) + { +@@ -2903,14 +2137,6 @@ + Py_RETURN_NONE; + } + +-static PyObject * +-clear_managed_dict(PyObject *self, PyObject *obj) +-{ +- PyObject_ClearManagedDict(obj); +- Py_RETURN_NONE; +-} +- +- + static PyObject * + test_macros(PyObject *self, PyObject *Py_UNUSED(args)) + { +@@ -2947,165 +2173,6 @@ + Py_RETURN_NONE; + } + +-static PyObject * +-function_get_code(PyObject *self, PyObject *func) +-{ +- PyObject *code = PyFunction_GetCode(func); +- if (code != NULL) { +- return Py_NewRef(code); +- } else { +- return NULL; +- } +-} +- +-static PyObject * +-function_get_globals(PyObject *self, PyObject *func) +-{ +- PyObject *globals = PyFunction_GetGlobals(func); +- if (globals != NULL) { +- return Py_NewRef(globals); +- } else { +- return NULL; +- } +-} +- +-static PyObject * +-function_get_module(PyObject *self, PyObject *func) +-{ +- PyObject *module = PyFunction_GetModule(func); +- if (module != NULL) { +- return Py_NewRef(module); +- } else { +- return NULL; +- } +-} +- +-static PyObject * +-function_get_defaults(PyObject *self, PyObject *func) +-{ +- PyObject *defaults = PyFunction_GetDefaults(func); +- if (defaults != NULL) { +- return Py_NewRef(defaults); +- } else if (PyErr_Occurred()) { +- return NULL; +- } else { +- Py_RETURN_NONE; // This can happen when `defaults` are set to `None` +- } +-} +- +-static PyObject * +-function_set_defaults(PyObject *self, PyObject *args) +-{ +- PyObject *func = NULL, *defaults = NULL; +- if (!PyArg_ParseTuple(args, "OO", &func, &defaults)) { +- return NULL; +- } +- int result = PyFunction_SetDefaults(func, defaults); +- if (result == -1) +- return NULL; +- Py_RETURN_NONE; +-} +- +-static PyObject * +-function_get_kw_defaults(PyObject *self, PyObject *func) +-{ +- PyObject *defaults = PyFunction_GetKwDefaults(func); +- if (defaults != NULL) { +- return Py_NewRef(defaults); +- } else if (PyErr_Occurred()) { +- return NULL; +- } else { +- Py_RETURN_NONE; // This can happen when `kwdefaults` are set to `None` +- } +-} +- +-static PyObject * +-function_set_kw_defaults(PyObject *self, PyObject *args) +-{ +- PyObject *func = NULL, *defaults = NULL; +- if (!PyArg_ParseTuple(args, "OO", &func, &defaults)) { +- return NULL; +- } +- int result = PyFunction_SetKwDefaults(func, defaults); +- if (result == -1) +- return NULL; +- Py_RETURN_NONE; +-} +- +-static PyObject * +-function_get_closure(PyObject *self, PyObject *func) +-{ +- PyObject *closure = PyFunction_GetClosure(func); +- if (closure != NULL) { +- return Py_NewRef(closure); +- } else if (PyErr_Occurred()) { +- return NULL; +- } else { +- Py_RETURN_NONE; // This can happen when `closure` is set to `None` +- } +-} +- +-static PyObject * +-function_set_closure(PyObject *self, PyObject *args) +-{ +- PyObject *func = NULL, *closure = NULL; +- if (!PyArg_ParseTuple(args, "OO", &func, &closure)) { +- return NULL; +- } +- int result = PyFunction_SetClosure(func, closure); +- if (result == -1) { +- return NULL; +- } +- Py_RETURN_NONE; +-} +- +-static PyObject * +-check_pyimport_addmodule(PyObject *self, PyObject *args) +-{ +- const char *name; +- if (!PyArg_ParseTuple(args, "s", &name)) { +- return NULL; +- } +- +- // test PyImport_AddModuleRef() +- PyObject *module = PyImport_AddModuleRef(name); +- if (module == NULL) { +- return NULL; +- } +- assert(PyModule_Check(module)); +- // module is a strong reference +- +- // test PyImport_AddModule() +- PyObject *module2 = PyImport_AddModule(name); +- if (module2 == NULL) { +- goto error; +- } +- assert(PyModule_Check(module2)); +- assert(module2 == module); +- // module2 is a borrowed ref +- +- // test PyImport_AddModuleObject() +- PyObject *name_obj = PyUnicode_FromString(name); +- if (name_obj == NULL) { +- goto error; +- } +- PyObject *module3 = PyImport_AddModuleObject(name_obj); +- Py_DECREF(name_obj); +- if (module3 == NULL) { +- goto error; +- } +- assert(PyModule_Check(module3)); +- assert(module3 == module); +- // module3 is a borrowed ref +- +- return module; +- +-error: +- Py_DECREF(module); +- return NULL; +-} +- +- + static PyObject * + test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) + { +@@ -3144,6 +2211,7 @@ + PyObject *ref = UNINITIALIZED_PTR; + assert(PyWeakref_GetRef(weakref, &ref) == 1); + assert(ref == obj); ++ assert(!PyWeakref_IsDead(weakref)); + assert(Py_REFCNT(obj) == (refcnt + 1)); + Py_DECREF(ref); + +@@ -3159,6 +2227,8 @@ + assert(Py_REFCNT(obj) == 1); + Py_DECREF(obj); + ++ assert(PyWeakref_IsDead(weakref)); ++ + // test PyWeakref_GET_OBJECT(), reference is dead + assert(PyWeakref_GET_OBJECT(weakref) == Py_None); + +@@ -3181,6 +2251,12 @@ + PyErr_Clear(); + assert(ref == NULL); + ++ // test PyWeakRef_IsDead(), invalid type ++ assert(!PyErr_Occurred()); ++ assert(PyWeakref_IsDead(invalid_weakref) == -1); ++ assert(PyErr_ExceptionMatches(PyExc_TypeError)); ++ PyErr_Clear(); ++ + // test PyWeakref_GetObject(), invalid type + assert(PyWeakref_GetObject(invalid_weakref) == NULL); + assert(PyErr_ExceptionMatches(PyExc_SystemError)); +@@ -3193,6 +2269,11 @@ + assert(ref == NULL); + PyErr_Clear(); + ++ // test PyWeakref_IsDead(NULL) ++ assert(PyWeakref_IsDead(NULL) == -1); ++ assert(PyErr_ExceptionMatches(PyExc_SystemError)); ++ PyErr_Clear(); ++ + // test PyWeakref_GetObject(NULL) + assert(PyWeakref_GetObject(NULL) == NULL); + assert(PyErr_ExceptionMatches(PyExc_SystemError)); +@@ -3340,19 +2421,6 @@ + } + + +-static PyObject * +-type_freeze(PyObject *module, PyObject *args) +-{ +- PyTypeObject *type; +- if (!PyArg_ParseTuple(args, "O!", &PyType_Type, &type)) { +- return NULL; +- } +- if (PyType_Freeze(type) < 0) { +- return NULL; +- } +- Py_RETURN_NONE; +-} +- + struct atexit_data { + int called; + PyThreadState *tstate; +@@ -3401,26 +2469,39 @@ + Py_RETURN_NONE; + } + ++static PyObject* ++code_offset_to_line(PyObject* self, PyObject* const* args, Py_ssize_t nargsf) ++{ ++ Py_ssize_t nargs = _PyVectorcall_NARGS(nargsf); ++ if (nargs != 2) { ++ PyErr_SetString(PyExc_TypeError, "code_offset_to_line takes 2 arguments"); ++ return NULL; ++ } ++ int offset; ++ if (PyLong_AsInt32(args[1], &offset) < 0) { ++ return NULL; ++ } ++ PyCodeObject *code = (PyCodeObject *)args[0]; ++ if (!PyCode_Check(code)) { ++ PyErr_SetString(PyExc_TypeError, "first arg must be a code object"); ++ return NULL; ++ } ++ return PyLong_FromInt32(PyCode_Addr2Line(code, offset)); ++} ++ ++ + static PyMethodDef TestMethods[] = { + {"set_errno", set_errno, METH_VARARGS}, + {"test_config", test_config, METH_NOARGS}, + {"test_sizeof_c_types", test_sizeof_c_types, METH_NOARGS}, +- {"test_list_api", test_list_api, METH_NOARGS}, +- {"test_dict_iteration", test_dict_iteration, METH_NOARGS}, + {"test_lazy_hash_inheritance", test_lazy_hash_inheritance,METH_NOARGS}, +- {"test_xincref_doesnt_leak",test_xincref_doesnt_leak, METH_NOARGS}, +- {"test_incref_doesnt_leak", test_incref_doesnt_leak, METH_NOARGS}, +- {"test_xdecref_doesnt_leak",test_xdecref_doesnt_leak, METH_NOARGS}, +- {"test_decref_doesnt_leak", test_decref_doesnt_leak, METH_NOARGS}, + {"test_structseq_newtype_doesnt_leak", + test_structseq_newtype_doesnt_leak, METH_NOARGS}, + {"test_structseq_newtype_null_descr_doc", + test_structseq_newtype_null_descr_doc, METH_NOARGS}, +- {"test_incref_decref_API", test_incref_decref_API, METH_NOARGS}, + {"pyobject_repr_from_null", pyobject_repr_from_null, METH_NOARGS}, + {"pyobject_str_from_null", pyobject_str_from_null, METH_NOARGS}, + {"pyobject_bytes_from_null", pyobject_bytes_from_null, METH_NOARGS}, +- {"test_string_to_double", test_string_to_double, METH_NOARGS}, + {"test_capsule", (PyCFunction)test_capsule, METH_NOARGS}, + {"test_from_contiguous", (PyCFunction)test_from_contiguous, METH_NOARGS}, + #if (defined(__linux__) || defined(__FreeBSD__)) && defined(__GNUC__) +@@ -3431,13 +2512,6 @@ + {"py_buildvalue", py_buildvalue, METH_VARARGS}, + {"py_buildvalue_ints", py_buildvalue_ints, METH_VARARGS}, + {"test_buildvalue_N", test_buildvalue_N, METH_NOARGS}, +- {"test_get_statictype_slots", test_get_statictype_slots, METH_NOARGS}, +- {"get_heaptype_for_name", get_heaptype_for_name, METH_NOARGS}, +- {"get_type_name", get_type_name, METH_O}, +- {"get_type_qualname", get_type_qualname, METH_O}, +- {"get_type_fullyqualname", get_type_fullyqualname, METH_O}, +- {"get_type_module_name", get_type_module_name, METH_O}, +- {"test_get_type_dict", test_get_type_dict, METH_NOARGS}, + {"test_reftracer", test_reftracer, METH_NOARGS}, + {"_test_thread_state", test_thread_state, METH_VARARGS}, + {"gilstate_ensure_release", gilstate_ensure_release, METH_NOARGS}, +@@ -3486,10 +2560,6 @@ + #endif + {"test_pythread_tss_key_state", test_pythread_tss_key_state, METH_VARARGS}, + {"bad_get", bad_get, METH_VARARGS}, +-#ifdef Py_REF_DEBUG +- {"negative_refcount", negative_refcount, METH_NOARGS}, +- {"decref_freed_object", decref_freed_object, METH_NOARGS}, +-#endif + {"meth_varargs", meth_varargs, METH_VARARGS}, + {"meth_varargs_keywords", _PyCFunction_CAST(meth_varargs_keywords), METH_VARARGS|METH_KEYWORDS}, + {"meth_o", meth_o, METH_O}, +@@ -3498,51 +2568,20 @@ + {"meth_fastcall_keywords", _PyCFunction_CAST(meth_fastcall_keywords), METH_FASTCALL|METH_KEYWORDS}, + {"pycfunction_call", test_pycfunction_call, METH_VARARGS}, + {"pynumber_tobase", pynumber_tobase, METH_VARARGS}, +- {"test_set_type_size", test_set_type_size, METH_NOARGS}, +- {"test_py_clear", test_py_clear, METH_NOARGS}, +- {"test_py_setref", test_py_setref, METH_NOARGS}, +- {"test_refcount_macros", test_refcount_macros, METH_NOARGS}, +- {"test_refcount_funcs", test_refcount_funcs, METH_NOARGS}, +- {"test_py_is_macros", test_py_is_macros, METH_NOARGS}, +- {"test_py_is_funcs", test_py_is_funcs, METH_NOARGS}, +- {"type_get_version", type_get_version, METH_O, PyDoc_STR("type->tp_version_tag")}, +- {"type_modified", type_modified, METH_O, PyDoc_STR("PyType_Modified")}, +- {"type_assign_version", type_assign_version, METH_O, PyDoc_STR("PyUnstable_Type_AssignVersionTag")}, +- {"type_get_tp_bases", type_get_tp_bases, METH_O}, +- {"type_get_tp_mro", type_get_tp_mro, METH_O}, + {"get_basic_static_type", get_basic_static_type, METH_VARARGS, NULL}, + {"test_tstate_capi", test_tstate_capi, METH_NOARGS, NULL}, +- {"frame_getlocals", frame_getlocals, METH_O, NULL}, +- {"frame_getglobals", frame_getglobals, METH_O, NULL}, +- {"frame_getgenerator", frame_getgenerator, METH_O, NULL}, +- {"frame_getbuiltins", frame_getbuiltins, METH_O, NULL}, +- {"frame_getlasti", frame_getlasti, METH_O, NULL}, +- {"frame_new", frame_new, METH_VARARGS, NULL}, +- {"frame_getvar", test_frame_getvar, METH_VARARGS, NULL}, +- {"frame_getvarstring", test_frame_getvarstring, METH_VARARGS, NULL}, + {"gen_get_code", gen_get_code, METH_O, NULL}, + {"get_feature_macros", get_feature_macros, METH_NOARGS, NULL}, + {"test_code_api", test_code_api, METH_NOARGS, NULL}, + {"settrace_to_error", settrace_to_error, METH_O, NULL}, + {"settrace_to_record", settrace_to_record, METH_O, NULL}, + {"test_macros", test_macros, METH_NOARGS, NULL}, +- {"clear_managed_dict", clear_managed_dict, METH_O, NULL}, +- {"function_get_code", function_get_code, METH_O, NULL}, +- {"function_get_globals", function_get_globals, METH_O, NULL}, +- {"function_get_module", function_get_module, METH_O, NULL}, +- {"function_get_defaults", function_get_defaults, METH_O, NULL}, +- {"function_set_defaults", function_set_defaults, METH_VARARGS, NULL}, +- {"function_get_kw_defaults", function_get_kw_defaults, METH_O, NULL}, +- {"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL}, +- {"function_get_closure", function_get_closure, METH_O, NULL}, +- {"function_set_closure", function_set_closure, METH_VARARGS, NULL}, +- {"check_pyimport_addmodule", check_pyimport_addmodule, METH_VARARGS}, + {"test_weakref_capi", test_weakref_capi, METH_NOARGS}, + {"function_set_warning", function_set_warning, METH_NOARGS}, + {"test_critical_sections", test_critical_sections, METH_NOARGS}, + {"finalize_thread_hang", finalize_thread_hang, METH_O, NULL}, +- {"type_freeze", type_freeze, METH_VARARGS}, + {"test_atexit", test_atexit, METH_NOARGS}, ++ {"code_offset_to_line", _PyCFunction_CAST(code_offset_to_line), METH_FASTCALL}, + {NULL, NULL} /* sentinel */ + }; + +@@ -4015,6 +3054,61 @@ + .tp_new = ContainerNoGC_new, + }; + ++/* Manually allocated heap type */ ++ ++typedef struct { ++ PyObject_HEAD ++ PyObject *dict; ++} ManualHeapType; ++ ++static int ++ManualHeapType_traverse(PyObject *self, visitproc visit, void *arg) ++{ ++ ManualHeapType *mht = (ManualHeapType *)self; ++ Py_VISIT(mht->dict); ++ return 0; ++} ++ ++static void ++ManualHeapType_dealloc(PyObject *self) ++{ ++ ManualHeapType *mht = (ManualHeapType *)self; ++ PyObject_GC_UnTrack(self); ++ Py_XDECREF(mht->dict); ++ PyTypeObject *type = Py_TYPE(self); ++ Py_TYPE(self)->tp_free(self); ++ Py_DECREF(type); ++} ++ ++static PyObject * ++create_manual_heap_type(void) ++{ ++ // gh-128923: Ensure that a heap type allocated through PyType_Type.tp_alloc ++ // with minimal initialization works correctly. ++ PyHeapTypeObject *heap_type = (PyHeapTypeObject *)PyType_Type.tp_alloc(&PyType_Type, 0); ++ if (heap_type == NULL) { ++ return NULL; ++ } ++ PyTypeObject* type = &heap_type->ht_type; ++ type->tp_basicsize = sizeof(ManualHeapType); ++ type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE | Py_TPFLAGS_HAVE_GC; ++ type->tp_new = PyType_GenericNew; ++ type->tp_name = "ManualHeapType"; ++ type->tp_dictoffset = offsetof(ManualHeapType, dict); ++ type->tp_traverse = ManualHeapType_traverse; ++ type->tp_dealloc = ManualHeapType_dealloc; ++ heap_type->ht_name = PyUnicode_FromString(type->tp_name); ++ if (!heap_type->ht_name) { ++ Py_DECREF(type); ++ return NULL; ++ } ++ heap_type->ht_qualname = Py_NewRef(heap_type->ht_name); ++ if (PyType_Ready(type) < 0) { ++ Py_DECREF(type); ++ return NULL; ++ } ++ return (PyObject *)type; ++} + + static struct PyModuleDef _testcapimodule = { + PyModuleDef_HEAD_INIT, +@@ -4149,6 +3243,15 @@ + (PyObject *) &ContainerNoGC_type) < 0) + return NULL; + ++ PyObject *manual_heap_type = create_manual_heap_type(); ++ if (manual_heap_type == NULL) { ++ return NULL; ++ } ++ if (PyModule_Add(m, "ManualHeapType", manual_heap_type) < 0) { ++ return NULL; ++ } ++ ++ + /* Include tests from the _testcapi/ directory */ + if (_PyTestCapi_Init_Vectorcall(m) < 0) { + return NULL; +@@ -4249,6 +3352,18 @@ + if (_PyTestCapi_Init_Config(m) < 0) { + return NULL; + } ++ if (_PyTestCapi_Init_Import(m) < 0) { ++ return NULL; ++ } ++ if (_PyTestCapi_Init_Frame(m) < 0) { ++ return NULL; ++ } ++ if (_PyTestCapi_Init_Type(m) < 0) { ++ return NULL; ++ } ++ if (_PyTestCapi_Init_Function(m) < 0) { ++ return NULL; ++ } + + PyState_AddModule(m, &_testcapimodule); + return m; +diff --git a/Modules/_testexternalinspection.c b/Modules/_testexternalinspection.c +index 0807d1e47b6..22074c81b74 100644 +--- a/Modules/_testexternalinspection.c ++++ b/Modules/_testexternalinspection.c +@@ -59,10 +59,30 @@ + # define HAVE_PROCESS_VM_READV 0 + #endif + ++struct _Py_AsyncioModuleDebugOffsets { ++ struct _asyncio_task_object { ++ uint64_t size; ++ uint64_t task_name; ++ uint64_t task_awaited_by; ++ uint64_t task_is_task; ++ uint64_t task_awaited_by_is_set; ++ uint64_t task_coro; ++ } asyncio_task_object; ++ struct _asyncio_thread_state { ++ uint64_t size; ++ uint64_t asyncio_running_loop; ++ uint64_t asyncio_running_task; ++ } asyncio_thread_state; ++}; ++ + #if defined(__APPLE__) && TARGET_OS_OSX +-static void* +-analyze_macho64(mach_port_t proc_ref, void* base, void* map) +-{ ++static uintptr_t ++return_section_address( ++ const char* section, ++ mach_port_t proc_ref, ++ uintptr_t base, ++ void* map ++) { + struct mach_header_64* hdr = (struct mach_header_64*)map; + int ncmds = hdr->ncmds; + +@@ -72,35 +92,40 @@ + mach_vm_size_t size = 0; + mach_msg_type_number_t count = sizeof(vm_region_basic_info_data_64_t); + mach_vm_address_t address = (mach_vm_address_t)base; +- vm_region_basic_info_data_64_t region_info; ++ vm_region_basic_info_data_64_t r_info; + mach_port_t object_name; ++ uintptr_t vmaddr = 0; + + for (int i = 0; cmd_cnt < 2 && i < ncmds; i++) { ++ if (cmd->cmd == LC_SEGMENT_64 && strcmp(cmd->segname, "__TEXT") == 0) { ++ vmaddr = cmd->vmaddr; ++ } + if (cmd->cmd == LC_SEGMENT_64 && strcmp(cmd->segname, "__DATA") == 0) { + while (cmd->filesize != size) { + address += size; +- if (mach_vm_region( +- proc_ref, +- &address, +- &size, +- VM_REGION_BASIC_INFO_64, +- (vm_region_info_t)®ion_info, // cppcheck-suppress [uninitvar] +- &count, +- &object_name) +- != KERN_SUCCESS) +- { +- PyErr_SetString(PyExc_RuntimeError, "Cannot get any more VM maps.\n"); +- return NULL; ++ kern_return_t ret = mach_vm_region( ++ proc_ref, ++ &address, ++ &size, ++ VM_REGION_BASIC_INFO_64, ++ (vm_region_info_t)&r_info, // cppcheck-suppress [uninitvar] ++ &count, ++ &object_name ++ ); ++ if (ret != KERN_SUCCESS) { ++ PyErr_SetString( ++ PyExc_RuntimeError, "Cannot get any more VM maps.\n"); ++ return 0; + } + } +- base = (void*)address - cmd->vmaddr; + + int nsects = cmd->nsects; +- struct section_64* sec = +- (struct section_64*)((void*)cmd + sizeof(struct segment_command_64)); ++ struct section_64* sec = (struct section_64*)( ++ (void*)cmd + sizeof(struct segment_command_64) ++ ); + for (int j = 0; j < nsects; j++) { +- if (strcmp(sec[j].sectname, "PyRuntime") == 0) { +- return base + sec[j].addr; ++ if (strcmp(sec[j].sectname, section) == 0) { ++ return base + sec[j].addr - vmaddr; + } + } + cmd_cnt++; +@@ -108,33 +133,39 @@ + + cmd = (struct segment_command_64*)((void*)cmd + cmd->cmdsize); + } +- return NULL; ++ return 0; + } + +-static void* +-analyze_macho(char* path, void* base, mach_vm_size_t size, mach_port_t proc_ref) +-{ ++static uintptr_t ++search_section_in_file( ++ const char* secname, ++ char* path, ++ uintptr_t base, ++ mach_vm_size_t size, ++ mach_port_t proc_ref ++) { + int fd = open(path, O_RDONLY); + if (fd == -1) { + PyErr_Format(PyExc_RuntimeError, "Cannot open binary %s\n", path); +- return NULL; ++ return 0; + } + + struct stat fs; + if (fstat(fd, &fs) == -1) { +- PyErr_Format(PyExc_RuntimeError, "Cannot get size of binary %s\n", path); ++ PyErr_Format( ++ PyExc_RuntimeError, "Cannot get size of binary %s\n", path); + close(fd); +- return NULL; ++ return 0; + } + + void* map = mmap(0, fs.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (map == MAP_FAILED) { + PyErr_Format(PyExc_RuntimeError, "Cannot map binary %s\n", path); + close(fd); +- return NULL; ++ return 0; + } + +- void* result = NULL; ++ uintptr_t result = 0; + + struct mach_header_64* hdr = (struct mach_header_64*)map; + switch (hdr->magic) { +@@ -142,11 +173,13 @@ + case MH_CIGAM: + case FAT_MAGIC: + case FAT_CIGAM: +- PyErr_SetString(PyExc_RuntimeError, "32-bit Mach-O binaries are not supported"); ++ PyErr_SetString( ++ PyExc_RuntimeError, ++ "32-bit Mach-O binaries are not supported"); + break; + case MH_MAGIC_64: + case MH_CIGAM_64: +- result = analyze_macho64(proc_ref, base, map); ++ result = return_section_address(secname, proc_ref, base, map); + break; + default: + PyErr_SetString(PyExc_RuntimeError, "Unknown Mach-O magic"); +@@ -174,9 +207,8 @@ + return task; + } + +-static void* +-get_py_runtime_macos(pid_t pid) +-{ ++static uintptr_t ++search_map_for_section(pid_t pid, const char* secname, const char* substr) { + mach_vm_address_t address = 0; + mach_vm_size_t size = 0; + mach_msg_type_number_t count = sizeof(vm_region_basic_info_data_64_t); +@@ -186,12 +218,11 @@ + mach_port_t proc_ref = pid_to_task(pid); + if (proc_ref == 0) { + PyErr_SetString(PyExc_PermissionError, "Cannot get task for PID"); +- return NULL; ++ return 0; + } + + int match_found = 0; + char map_filename[MAXPATHLEN + 1]; +- void* result_address = NULL; + while (mach_vm_region( + proc_ref, + &address, +@@ -199,10 +230,16 @@ + VM_REGION_BASIC_INFO_64, + (vm_region_info_t)®ion_info, + &count, +- &object_name) +- == KERN_SUCCESS) ++ &object_name) == KERN_SUCCESS) + { +- int path_len = proc_regionfilename(pid, address, map_filename, MAXPATHLEN); ++ if ((region_info.protection & VM_PROT_READ) == 0 ++ || (region_info.protection & VM_PROT_EXECUTE) == 0) { ++ address += size; ++ continue; ++ } ++ ++ int path_len = proc_regionfilename( ++ pid, address, map_filename, MAXPATHLEN); + if (path_len == 0) { + address += size; + continue; +@@ -215,26 +252,20 @@ + filename = map_filename; // No path, use the whole string + } + +- // Check if the filename starts with "python" or "libpython" +- if (!match_found && strncmp(filename, "python", 6) == 0) { +- match_found = 1; +- result_address = analyze_macho(map_filename, (void*)address, size, proc_ref); +- } +- if (strncmp(filename, "libpython", 9) == 0) { ++ if (!match_found && strncmp(filename, substr, strlen(substr)) == 0) { + match_found = 1; +- result_address = analyze_macho(map_filename, (void*)address, size, proc_ref); +- break; ++ return search_section_in_file( ++ secname, map_filename, address, size, proc_ref); + } + + address += size; + } +- return result_address; ++ return 0; + } +-#endif + +-#ifdef __linux__ +-void* +-find_python_map_start_address(pid_t pid, char* result_filename) ++#elif defined(__linux__) ++static uintptr_t ++find_map_start_address(pid_t pid, char* result_filename, const char* map) + { + char maps_file_path[64]; + sprintf(maps_file_path, "/proc/%d/maps", pid); +@@ -242,17 +273,20 @@ + FILE* maps_file = fopen(maps_file_path, "r"); + if (maps_file == NULL) { + PyErr_SetFromErrno(PyExc_OSError); +- return NULL; ++ return 0; + } + + int match_found = 0; + + char line[256]; + char map_filename[PATH_MAX]; +- void* result_address = 0; ++ uintptr_t result_address = 0; + while (fgets(line, sizeof(line), maps_file) != NULL) { + unsigned long start_address = 0; +- sscanf(line, "%lx-%*x %*s %*s %*s %*s %s", &start_address, map_filename); ++ sscanf( ++ line, "%lx-%*x %*s %*s %*s %*s %s", ++ &start_address, map_filename ++ ); + char* filename = strrchr(map_filename, '/'); + if (filename != NULL) { + filename++; // Move past the '/' +@@ -260,15 +294,9 @@ + filename = map_filename; // No path, use the whole string + } + +- // Check if the filename starts with "python" or "libpython" +- if (!match_found && strncmp(filename, "python", 6) == 0) { +- match_found = 1; +- result_address = (void*)start_address; +- strcpy(result_filename, map_filename); +- } +- if (strncmp(filename, "libpython", 9) == 0) { ++ if (!match_found && strncmp(filename, map, strlen(map)) == 0) { + match_found = 1; +- result_address = (void*)start_address; ++ result_address = start_address; + strcpy(result_filename, map_filename); + break; + } +@@ -283,18 +311,17 @@ + return result_address; + } + +-void* +-get_py_runtime_linux(pid_t pid) ++static uintptr_t ++search_map_for_section(pid_t pid, const char* secname, const char* map) + { + char elf_file[256]; +- void* start_address = (void*)find_python_map_start_address(pid, elf_file); ++ uintptr_t start_address = find_map_start_address(pid, elf_file, map); + + if (start_address == 0) { +- PyErr_SetString(PyExc_RuntimeError, "No memory map associated with python or libpython found"); +- return NULL; ++ return 0; + } + +- void* result = NULL; ++ uintptr_t result = 0; + void* file_memory = NULL; + + int fd = open(elf_file, O_RDONLY); +@@ -317,20 +344,29 @@ + + Elf_Ehdr* elf_header = (Elf_Ehdr*)file_memory; + +- Elf_Shdr* section_header_table = (Elf_Shdr*)(file_memory + elf_header->e_shoff); ++ Elf_Shdr* section_header_table = ++ (Elf_Shdr*)(file_memory + elf_header->e_shoff); + + Elf_Shdr* shstrtab_section = §ion_header_table[elf_header->e_shstrndx]; + char* shstrtab = (char*)(file_memory + shstrtab_section->sh_offset); + +- Elf_Shdr* py_runtime_section = NULL; ++ Elf_Shdr* section = NULL; + for (int i = 0; i < elf_header->e_shnum; i++) { +- if (strcmp(".PyRuntime", shstrtab + section_header_table[i].sh_name) == 0) { +- py_runtime_section = §ion_header_table[i]; ++ const char* this_sec_name = ( ++ shstrtab + ++ section_header_table[i].sh_name + ++ 1 // "+1" accounts for the leading "." ++ ); ++ ++ if (strcmp(secname, this_sec_name) == 0) { ++ section = §ion_header_table[i]; + break; + } + } + +- Elf_Phdr* program_header_table = (Elf_Phdr*)(file_memory + elf_header->e_phoff); ++ Elf_Phdr* program_header_table = ++ (Elf_Phdr*)(file_memory + elf_header->e_phoff); ++ + // Find the first PT_LOAD segment + Elf_Phdr* first_load_segment = NULL; + for (int i = 0; i < elf_header->e_phnum; i++) { +@@ -340,10 +376,16 @@ + } + } + +- if (py_runtime_section != NULL && first_load_segment != NULL) { +- uintptr_t elf_load_addr = first_load_segment->p_vaddr +- - (first_load_segment->p_vaddr % first_load_segment->p_align); +- result = start_address + py_runtime_section->sh_addr - elf_load_addr; ++ if (section != NULL && first_load_segment != NULL) { ++ uintptr_t elf_load_addr = ++ first_load_segment->p_vaddr - ( ++ first_load_segment->p_vaddr % first_load_segment->p_align ++ ); ++ result = start_address + (uintptr_t)section->sh_addr - elf_load_addr; ++ } ++ else { ++ PyErr_Format(PyExc_KeyError, ++ "cannot find map for section %s", secname); + } + + exit: +@@ -355,10 +397,37 @@ + } + return result; + } ++#else ++static uintptr_t ++search_map_for_section(pid_t pid, const char* secname, const char* map) ++{ ++ return 0; ++} + #endif + +-ssize_t +-read_memory(pid_t pid, void* remote_address, size_t len, void* dst) ++static uintptr_t ++get_py_runtime(pid_t pid) ++{ ++ uintptr_t address = search_map_for_section(pid, "PyRuntime", "libpython"); ++ if (address == 0) { ++ address = search_map_for_section(pid, "PyRuntime", "python"); ++ } ++ return address; ++} ++ ++static uintptr_t ++get_async_debug(pid_t pid) ++{ ++ uintptr_t result = search_map_for_section(pid, "AsyncioDebug", "_asyncio.cpython"); ++ if (result == 0 && !PyErr_Occurred()) { ++ PyErr_SetString(PyExc_RuntimeError, "Cannot find AsyncioDebug section"); ++ } ++ return result; ++} ++ ++ ++static ssize_t ++read_memory(pid_t pid, uintptr_t remote_address, size_t len, void* dst) + { + ssize_t total_bytes_read = 0; + #if defined(__linux__) && HAVE_PROCESS_VM_READV +@@ -394,13 +463,19 @@ + if (kr != KERN_SUCCESS) { + switch (kr) { + case KERN_PROTECTION_FAILURE: +- PyErr_SetString(PyExc_PermissionError, "Not enough permissions to read memory"); ++ PyErr_SetString( ++ PyExc_PermissionError, ++ "Not enough permissions to read memory"); + break; + case KERN_INVALID_ARGUMENT: +- PyErr_SetString(PyExc_PermissionError, "Invalid argument to mach_vm_read_overwrite"); ++ PyErr_SetString( ++ PyExc_PermissionError, ++ "Invalid argument to mach_vm_read_overwrite"); + break; + default: +- PyErr_SetString(PyExc_RuntimeError, "Unknown error reading memory"); ++ PyErr_SetString( ++ PyExc_RuntimeError, ++ "Unknown error reading memory"); + } + return -1; + } +@@ -411,13 +486,22 @@ + return total_bytes_read; + } + +-int +-read_string(pid_t pid, _Py_DebugOffsets* debug_offsets, void* address, char* buffer, Py_ssize_t size) +-{ ++static int ++read_string( ++ pid_t pid, ++ _Py_DebugOffsets* debug_offsets, ++ uintptr_t address, ++ char* buffer, ++ Py_ssize_t size ++) { + Py_ssize_t len; +- ssize_t bytes_read = +- read_memory(pid, address + debug_offsets->unicode_object.length, sizeof(Py_ssize_t), &len); +- if (bytes_read == -1) { ++ ssize_t bytes_read = read_memory( ++ pid, ++ address + debug_offsets->unicode_object.length, ++ sizeof(Py_ssize_t), ++ &len ++ ); ++ if (bytes_read < 0) { + return -1; + } + if (len >= size) { +@@ -426,51 +510,652 @@ + } + size_t offset = debug_offsets->unicode_object.asciiobject_size; + bytes_read = read_memory(pid, address + offset, len, buffer); +- if (bytes_read == -1) { ++ if (bytes_read < 0) { + return -1; + } + buffer[len] = '\0'; + return 0; + } + +-void* +-get_py_runtime(pid_t pid) ++ ++static inline int ++read_ptr(pid_t pid, uintptr_t address, uintptr_t *ptr_addr) + { +-#if defined(__linux__) +- return get_py_runtime_linux(pid); +-#elif defined(__APPLE__) && TARGET_OS_OSX +- return get_py_runtime_macos(pid); +-#else +- return NULL; +-#endif ++ int bytes_read = read_memory(pid, address, sizeof(void*), ptr_addr); ++ if (bytes_read < 0) { ++ return -1; ++ } ++ return 0; ++} ++ ++static inline int ++read_ssize_t(pid_t pid, uintptr_t address, Py_ssize_t *size) ++{ ++ int bytes_read = read_memory(pid, address, sizeof(Py_ssize_t), size); ++ if (bytes_read < 0) { ++ return -1; ++ } ++ return 0; + } + + static int +-parse_code_object( +- int pid, +- PyObject* result, +- struct _Py_DebugOffsets* offsets, +- void* address, +- void** previous_frame) ++read_py_ptr(pid_t pid, uintptr_t address, uintptr_t *ptr_addr) ++{ ++ if (read_ptr(pid, address, ptr_addr)) { ++ return -1; ++ } ++ *ptr_addr &= ~Py_TAG_BITS; ++ return 0; ++} ++ ++static int ++read_char(pid_t pid, uintptr_t address, char *result) ++{ ++ int bytes_read = read_memory(pid, address, sizeof(char), result); ++ if (bytes_read < 0) { ++ return -1; ++ } ++ return 0; ++} ++ ++static int ++read_int(pid_t pid, uintptr_t address, int *result) ++{ ++ int bytes_read = read_memory(pid, address, sizeof(int), result); ++ if (bytes_read < 0) { ++ return -1; ++ } ++ return 0; ++} ++ ++static int ++read_unsigned_long(pid_t pid, uintptr_t address, unsigned long *result) ++{ ++ int bytes_read = read_memory(pid, address, sizeof(unsigned long), result); ++ if (bytes_read < 0) { ++ return -1; ++ } ++ return 0; ++} ++ ++static int ++read_pyobj(pid_t pid, uintptr_t address, PyObject *ptr_addr) + { +- void* address_of_function_name; +- read_memory( ++ int bytes_read = read_memory(pid, address, sizeof(PyObject), ptr_addr); ++ if (bytes_read < 0) { ++ return -1; ++ } ++ return 0; ++} ++ ++static PyObject * ++read_py_str( ++ pid_t pid, ++ _Py_DebugOffsets* debug_offsets, ++ uintptr_t address, ++ ssize_t max_len ++) { ++ assert(max_len > 0); ++ ++ PyObject *result = NULL; ++ ++ char *buf = (char *)PyMem_RawMalloc(max_len); ++ if (buf == NULL) { ++ PyErr_NoMemory(); ++ return NULL; ++ } ++ if (read_string(pid, debug_offsets, address, buf, max_len)) { ++ goto err; ++ } ++ ++ result = PyUnicode_FromString(buf); ++ if (result == NULL) { ++ goto err; ++ } ++ ++ PyMem_RawFree(buf); ++ assert(result != NULL); ++ return result; ++ ++err: ++ PyMem_RawFree(buf); ++ return NULL; ++} ++ ++static long ++read_py_long(pid_t pid, _Py_DebugOffsets* offsets, uintptr_t address) ++{ ++ unsigned int shift = PYLONG_BITS_IN_DIGIT; ++ ++ ssize_t size; ++ uintptr_t lv_tag; ++ ++ int bytes_read = read_memory( ++ pid, address + offsets->long_object.lv_tag, ++ sizeof(uintptr_t), ++ &lv_tag); ++ if (bytes_read < 0) { ++ return -1; ++ } ++ ++ int negative = (lv_tag & 3) == 2; ++ size = lv_tag >> 3; ++ ++ if (size == 0) { ++ return 0; ++ } ++ ++ digit *digits = (digit *)PyMem_RawMalloc(size * sizeof(digit)); ++ if (!digits) { ++ PyErr_NoMemory(); ++ return -1; ++ } ++ ++ bytes_read = read_memory( ++ pid, ++ address + offsets->long_object.ob_digit, ++ sizeof(digit) * size, ++ digits ++ ); ++ if (bytes_read < 0) { ++ goto error; ++ } ++ ++ long value = 0; ++ ++ // In theory this can overflow, but because of llvm/llvm-project#16778 ++ // we can't use __builtin_mul_overflow because it fails to link with ++ // __muloti4 on aarch64. In practice this is fine because all we're ++ // testing here are task numbers that would fit in a single byte. ++ for (ssize_t i = 0; i < size; ++i) { ++ long long factor = digits[i] * (1UL << (ssize_t)(shift * i)); ++ value += factor; ++ } ++ PyMem_RawFree(digits); ++ if (negative) { ++ value *= -1; ++ } ++ return value; ++error: ++ PyMem_RawFree(digits); ++ return -1; ++} ++ ++static PyObject * ++parse_task_name( ++ int pid, ++ _Py_DebugOffsets* offsets, ++ struct _Py_AsyncioModuleDebugOffsets* async_offsets, ++ uintptr_t task_address ++) { ++ uintptr_t task_name_addr; ++ int err = read_py_ptr( ++ pid, ++ task_address + async_offsets->asyncio_task_object.task_name, ++ &task_name_addr); ++ if (err) { ++ return NULL; ++ } ++ ++ // The task name can be a long or a string so we need to check the type ++ ++ PyObject task_name_obj; ++ err = read_pyobj( ++ pid, ++ task_name_addr, ++ &task_name_obj); ++ if (err) { ++ return NULL; ++ } ++ ++ unsigned long flags; ++ err = read_unsigned_long( ++ pid, ++ (uintptr_t)task_name_obj.ob_type + offsets->type_object.tp_flags, ++ &flags); ++ if (err) { ++ return NULL; ++ } ++ ++ if ((flags & Py_TPFLAGS_LONG_SUBCLASS)) { ++ long res = read_py_long(pid, offsets, task_name_addr); ++ if (res == -1) { ++ PyErr_SetString(PyExc_RuntimeError, "Failed to get task name"); ++ return NULL; ++ } ++ return PyUnicode_FromFormat("Task-%d", res); ++ } ++ ++ if(!(flags & Py_TPFLAGS_UNICODE_SUBCLASS)) { ++ PyErr_SetString(PyExc_RuntimeError, "Invalid task name object"); ++ return NULL; ++ } ++ ++ return read_py_str( ++ pid, ++ offsets, ++ task_name_addr, ++ 255 ++ ); ++} ++ ++static int ++parse_coro_chain( ++ int pid, ++ struct _Py_DebugOffsets* offsets, ++ struct _Py_AsyncioModuleDebugOffsets* async_offsets, ++ uintptr_t coro_address, ++ PyObject *render_to ++) { ++ assert((void*)coro_address != NULL); ++ ++ uintptr_t gen_type_addr; ++ int err = read_ptr( ++ pid, ++ coro_address + sizeof(void*), ++ &gen_type_addr); ++ if (err) { ++ return -1; ++ } ++ ++ uintptr_t gen_name_addr; ++ err = read_py_ptr( ++ pid, ++ coro_address + offsets->gen_object.gi_name, ++ &gen_name_addr); ++ if (err) { ++ return -1; ++ } ++ ++ PyObject *name = read_py_str( ++ pid, ++ offsets, ++ gen_name_addr, ++ 255 ++ ); ++ if (name == NULL) { ++ return -1; ++ } ++ ++ if (PyList_Append(render_to, name)) { ++ return -1; ++ } ++ Py_DECREF(name); ++ ++ int gi_frame_state; ++ err = read_int( ++ pid, ++ coro_address + offsets->gen_object.gi_frame_state, ++ &gi_frame_state); ++ ++ if (gi_frame_state == FRAME_SUSPENDED_YIELD_FROM) { ++ char owner; ++ err = read_char( + pid, +- (void*)(address + offsets->code_object.name), +- sizeof(void*), +- &address_of_function_name); ++ coro_address + offsets->gen_object.gi_iframe + ++ offsets->interpreter_frame.owner, ++ &owner ++ ); ++ if (err) { ++ return -1; ++ } ++ if (owner != FRAME_OWNED_BY_GENERATOR) { ++ PyErr_SetString( ++ PyExc_RuntimeError, ++ "generator doesn't own its frame \\_o_/"); ++ return -1; ++ } + +- if (address_of_function_name == NULL) { +- PyErr_SetString(PyExc_RuntimeError, "No function name found"); ++ uintptr_t stackpointer_addr; ++ err = read_py_ptr( ++ pid, ++ coro_address + offsets->gen_object.gi_iframe + ++ offsets->interpreter_frame.stackpointer, ++ &stackpointer_addr); ++ if (err) { ++ return -1; ++ } ++ ++ if ((void*)stackpointer_addr != NULL) { ++ uintptr_t gi_await_addr; ++ err = read_py_ptr( ++ pid, ++ stackpointer_addr - sizeof(void*), ++ &gi_await_addr); ++ if (err) { ++ return -1; ++ } ++ ++ if ((void*)gi_await_addr != NULL) { ++ uintptr_t gi_await_addr_type_addr; ++ int err = read_ptr( ++ pid, ++ gi_await_addr + sizeof(void*), ++ &gi_await_addr_type_addr); ++ if (err) { ++ return -1; ++ } ++ ++ if (gen_type_addr == gi_await_addr_type_addr) { ++ /* This needs an explanation. We always start with parsing ++ native coroutine / generator frames. Ultimately they ++ are awaiting on something. That something can be ++ a native coroutine frame or... an iterator. ++ If it's the latter -- we can't continue building ++ our chain. So the condition to bail out of this is ++ to do that when the type of the current coroutine ++ doesn't match the type of whatever it points to ++ in its cr_await. ++ */ ++ err = parse_coro_chain( ++ pid, ++ offsets, ++ async_offsets, ++ gi_await_addr, ++ render_to ++ ); ++ if (err) { ++ return -1; ++ } ++ } ++ } ++ } ++ ++ } ++ ++ return 0; ++} ++ ++ ++static int ++parse_task_awaited_by( ++ int pid, ++ struct _Py_DebugOffsets* offsets, ++ struct _Py_AsyncioModuleDebugOffsets* async_offsets, ++ uintptr_t task_address, ++ PyObject *awaited_by ++); ++ ++ ++static int ++parse_task( ++ int pid, ++ struct _Py_DebugOffsets* offsets, ++ struct _Py_AsyncioModuleDebugOffsets* async_offsets, ++ uintptr_t task_address, ++ PyObject *render_to ++) { ++ char is_task; ++ int err = read_char( ++ pid, ++ task_address + async_offsets->asyncio_task_object.task_is_task, ++ &is_task); ++ if (err) { ++ return -1; ++ } ++ ++ uintptr_t refcnt; ++ read_ptr(pid, task_address + sizeof(Py_ssize_t), &refcnt); ++ ++ PyObject* result = PyList_New(0); ++ if (result == NULL) { ++ return -1; ++ } ++ ++ PyObject *call_stack = PyList_New(0); ++ if (call_stack == NULL) { ++ goto err; ++ } ++ if (PyList_Append(result, call_stack)) { ++ Py_DECREF(call_stack); ++ goto err; ++ } ++ /* we can operate on a borrowed one to simplify cleanup */ ++ Py_DECREF(call_stack); ++ ++ if (is_task) { ++ PyObject *tn = parse_task_name( ++ pid, offsets, async_offsets, task_address); ++ if (tn == NULL) { ++ goto err; ++ } ++ if (PyList_Append(result, tn)) { ++ Py_DECREF(tn); ++ goto err; ++ } ++ Py_DECREF(tn); ++ ++ uintptr_t coro_addr; ++ err = read_py_ptr( ++ pid, ++ task_address + async_offsets->asyncio_task_object.task_coro, ++ &coro_addr); ++ if (err) { ++ goto err; ++ } ++ ++ if ((void*)coro_addr != NULL) { ++ err = parse_coro_chain( ++ pid, ++ offsets, ++ async_offsets, ++ coro_addr, ++ call_stack ++ ); ++ if (err) { ++ goto err; ++ } ++ ++ if (PyList_Reverse(call_stack)) { ++ goto err; ++ } ++ } ++ } ++ ++ if (PyList_Append(render_to, result)) { ++ goto err; ++ } ++ Py_DECREF(result); ++ ++ PyObject *awaited_by = PyList_New(0); ++ if (awaited_by == NULL) { ++ goto err; ++ } ++ if (PyList_Append(result, awaited_by)) { ++ Py_DECREF(awaited_by); ++ goto err; ++ } ++ /* we can operate on a borrowed one to simplify cleanup */ ++ Py_DECREF(awaited_by); ++ ++ if (parse_task_awaited_by(pid, offsets, async_offsets, ++ task_address, awaited_by) ++ ) { ++ goto err; ++ } ++ ++ return 0; ++ ++err: ++ Py_DECREF(result); ++ return -1; ++} ++ ++static int ++parse_tasks_in_set( ++ int pid, ++ struct _Py_DebugOffsets* offsets, ++ struct _Py_AsyncioModuleDebugOffsets* async_offsets, ++ uintptr_t set_addr, ++ PyObject *awaited_by ++) { ++ uintptr_t set_obj; ++ if (read_py_ptr( ++ pid, ++ set_addr, ++ &set_obj) ++ ) { ++ return -1; ++ } ++ ++ Py_ssize_t num_els; ++ if (read_ssize_t( ++ pid, ++ set_obj + offsets->set_object.used, ++ &num_els) ++ ) { ++ return -1; ++ } ++ ++ Py_ssize_t set_len; ++ if (read_ssize_t( ++ pid, ++ set_obj + offsets->set_object.mask, ++ &set_len) ++ ) { ++ return -1; ++ } ++ set_len++; // The set contains the `mask+1` element slots. ++ ++ uintptr_t table_ptr; ++ if (read_ptr( ++ pid, ++ set_obj + offsets->set_object.table, ++ &table_ptr) ++ ) { ++ return -1; ++ } ++ ++ Py_ssize_t i = 0; ++ Py_ssize_t els = 0; ++ while (i < set_len) { ++ uintptr_t key_addr; ++ if (read_py_ptr(pid, table_ptr, &key_addr)) { ++ return -1; ++ } ++ ++ if ((void*)key_addr != NULL) { ++ Py_ssize_t ref_cnt; ++ if (read_ssize_t(pid, table_ptr, &ref_cnt)) { ++ return -1; ++ } ++ ++ if (ref_cnt) { ++ // if 'ref_cnt=0' it's a set dummy marker ++ ++ if (parse_task( ++ pid, ++ offsets, ++ async_offsets, ++ key_addr, ++ awaited_by) ++ ) { ++ return -1; ++ } ++ ++ if (++els == num_els) { ++ break; ++ } ++ } ++ } ++ ++ table_ptr += sizeof(void*) * 2; ++ i++; ++ } ++ return 0; ++} ++ ++ ++static int ++parse_task_awaited_by( ++ int pid, ++ struct _Py_DebugOffsets* offsets, ++ struct _Py_AsyncioModuleDebugOffsets* async_offsets, ++ uintptr_t task_address, ++ PyObject *awaited_by ++) { ++ uintptr_t task_ab_addr; ++ int err = read_py_ptr( ++ pid, ++ task_address + async_offsets->asyncio_task_object.task_awaited_by, ++ &task_ab_addr); ++ if (err) { ++ return -1; ++ } ++ ++ if ((void*)task_ab_addr == NULL) { ++ return 0; ++ } ++ ++ char awaited_by_is_a_set; ++ err = read_char( ++ pid, ++ task_address + async_offsets->asyncio_task_object.task_awaited_by_is_set, ++ &awaited_by_is_a_set); ++ if (err) { ++ return -1; ++ } ++ ++ if (awaited_by_is_a_set) { ++ if (parse_tasks_in_set( ++ pid, ++ offsets, ++ async_offsets, ++ task_address + async_offsets->asyncio_task_object.task_awaited_by, ++ awaited_by) ++ ) { ++ return -1; ++ } ++ } else { ++ uintptr_t sub_task; ++ if (read_py_ptr( ++ pid, ++ task_address + async_offsets->asyncio_task_object.task_awaited_by, ++ &sub_task) ++ ) { ++ return -1; ++ } ++ ++ if (parse_task( ++ pid, ++ offsets, ++ async_offsets, ++ sub_task, ++ awaited_by) ++ ) { ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++static int ++parse_code_object( ++ int pid, ++ PyObject* result, ++ struct _Py_DebugOffsets* offsets, ++ uintptr_t address, ++ uintptr_t* previous_frame ++) { ++ uintptr_t address_of_function_name; ++ int bytes_read = read_memory( ++ pid, ++ address + offsets->code_object.name, ++ sizeof(void*), ++ &address_of_function_name ++ ); ++ if (bytes_read < 0) { + return -1; + } + +- char function_name[256]; +- if (read_string(pid, offsets, address_of_function_name, function_name, sizeof(function_name)) != 0) { ++ if ((void*)address_of_function_name == NULL) { ++ PyErr_SetString(PyExc_RuntimeError, "No function name found"); + return -1; + } + +- PyObject* py_function_name = PyUnicode_FromString(function_name); ++ PyObject* py_function_name = read_py_str( ++ pid, offsets, address_of_function_name, 256); + if (py_function_name == NULL) { + return -1; + } +@@ -486,54 +1171,283 @@ + + static int + parse_frame_object( +- int pid, +- PyObject* result, +- struct _Py_DebugOffsets* offsets, +- void* address, +- void** previous_frame) +-{ ++ int pid, ++ PyObject* result, ++ struct _Py_DebugOffsets* offsets, ++ uintptr_t address, ++ uintptr_t* previous_frame ++) { ++ int err; ++ ++ ssize_t bytes_read = read_memory( ++ pid, ++ address + offsets->interpreter_frame.previous, ++ sizeof(void*), ++ previous_frame ++ ); ++ if (bytes_read < 0) { ++ return -1; ++ } ++ ++ char owner; ++ if (read_char(pid, address + offsets->interpreter_frame.owner, &owner)) { ++ return -1; ++ } ++ ++ if (owner >= FRAME_OWNED_BY_INTERPRETER) { ++ return 0; ++ } ++ ++ uintptr_t address_of_code_object; ++ err = read_py_ptr( ++ pid, ++ address + offsets->interpreter_frame.executable, ++ &address_of_code_object ++ ); ++ if (err) { ++ return -1; ++ } ++ ++ if ((void*)address_of_code_object == NULL) { ++ return 0; ++ } ++ ++ return parse_code_object( ++ pid, result, offsets, address_of_code_object, previous_frame); ++} ++ ++static int ++parse_async_frame_object( ++ int pid, ++ PyObject* result, ++ struct _Py_DebugOffsets* offsets, ++ uintptr_t address, ++ uintptr_t* previous_frame, ++ uintptr_t* code_object ++) { ++ int err; ++ ++ ssize_t bytes_read = read_memory( ++ pid, ++ address + offsets->interpreter_frame.previous, ++ sizeof(void*), ++ previous_frame ++ ); ++ if (bytes_read < 0) { ++ return -1; ++ } ++ ++ char owner; ++ bytes_read = read_memory( ++ pid, address + offsets->interpreter_frame.owner, sizeof(char), &owner); ++ if (bytes_read < 0) { ++ return -1; ++ } ++ ++ if (owner == FRAME_OWNED_BY_CSTACK || owner == FRAME_OWNED_BY_INTERPRETER) { ++ return 0; // C frame ++ } ++ ++ if (owner != FRAME_OWNED_BY_GENERATOR ++ && owner != FRAME_OWNED_BY_THREAD) { ++ PyErr_Format(PyExc_RuntimeError, "Unhandled frame owner %d.\n", owner); ++ return -1; ++ } ++ ++ err = read_py_ptr( ++ pid, ++ address + offsets->interpreter_frame.executable, ++ code_object ++ ); ++ if (err) { ++ return -1; ++ } ++ ++ assert(code_object != NULL); ++ if ((void*)*code_object == NULL) { ++ return 0; ++ } ++ ++ if (parse_code_object( ++ pid, result, offsets, *code_object, previous_frame)) { ++ return -1; ++ } ++ ++ return 1; ++} ++ ++static int ++read_offsets( ++ int pid, ++ uintptr_t *runtime_start_address, ++ _Py_DebugOffsets* debug_offsets ++) { ++ *runtime_start_address = get_py_runtime(pid); ++ if ((void*)*runtime_start_address == NULL) { ++ if (!PyErr_Occurred()) { ++ PyErr_SetString( ++ PyExc_RuntimeError, "Failed to get .PyRuntime address"); ++ } ++ return -1; ++ } ++ size_t size = sizeof(struct _Py_DebugOffsets); ++ ssize_t bytes_read = read_memory( ++ pid, *runtime_start_address, size, debug_offsets); ++ if (bytes_read < 0) { ++ return -1; ++ } ++ return 0; ++} ++ ++static int ++read_async_debug( ++ int pid, ++ struct _Py_AsyncioModuleDebugOffsets* async_debug ++) { ++ uintptr_t async_debug_addr = get_async_debug(pid); ++ if (!async_debug_addr) { ++ return -1; ++ } ++ size_t size = sizeof(struct _Py_AsyncioModuleDebugOffsets); + ssize_t bytes_read = read_memory( ++ pid, async_debug_addr, size, async_debug); ++ if (bytes_read < 0) { ++ return -1; ++ } ++ return 0; ++} ++ ++static int ++find_running_frame( ++ int pid, ++ uintptr_t runtime_start_address, ++ _Py_DebugOffsets* local_debug_offsets, ++ uintptr_t *frame ++) { ++ off_t interpreter_state_list_head = ++ local_debug_offsets->runtime_state.interpreters_head; ++ ++ uintptr_t address_of_interpreter_state; ++ int bytes_read = read_memory( + pid, +- (void*)(address + offsets->interpreter_frame.previous), ++ runtime_start_address + interpreter_state_list_head, + sizeof(void*), +- previous_frame); +- if (bytes_read == -1) { ++ &address_of_interpreter_state); ++ if (bytes_read < 0) { + return -1; + } + +- char owner; +- bytes_read = +- read_memory(pid, (void*)(address + offsets->interpreter_frame.owner), sizeof(char), &owner); ++ if (address_of_interpreter_state == 0) { ++ PyErr_SetString(PyExc_RuntimeError, "No interpreter state found"); ++ return -1; ++ } ++ ++ uintptr_t address_of_thread; ++ bytes_read = read_memory( ++ pid, ++ address_of_interpreter_state + ++ local_debug_offsets->interpreter_state.threads_head, ++ sizeof(void*), ++ &address_of_thread); + if (bytes_read < 0) { + return -1; + } + +- if (owner == FRAME_OWNED_BY_CSTACK) { ++ // No Python frames are available for us (can happen at tear-down). ++ if ((void*)address_of_thread != NULL) { ++ int err = read_ptr( ++ pid, ++ address_of_thread + local_debug_offsets->thread_state.current_frame, ++ frame); ++ if (err) { ++ return -1; ++ } + return 0; + } + +- uintptr_t address_of_code_object; ++ *frame = (uintptr_t)NULL; ++ return 0; ++} ++ ++static int ++find_running_task( ++ int pid, ++ uintptr_t runtime_start_address, ++ _Py_DebugOffsets *local_debug_offsets, ++ struct _Py_AsyncioModuleDebugOffsets *async_offsets, ++ uintptr_t *running_task_addr ++) { ++ *running_task_addr = (uintptr_t)NULL; ++ ++ off_t interpreter_state_list_head = ++ local_debug_offsets->runtime_state.interpreters_head; ++ ++ uintptr_t address_of_interpreter_state; ++ int bytes_read = read_memory( ++ pid, ++ runtime_start_address + interpreter_state_list_head, ++ sizeof(void*), ++ &address_of_interpreter_state); ++ if (bytes_read < 0) { ++ return -1; ++ } ++ ++ if (address_of_interpreter_state == 0) { ++ PyErr_SetString(PyExc_RuntimeError, "No interpreter state found"); ++ return -1; ++ } ++ ++ uintptr_t address_of_thread; + bytes_read = read_memory( + pid, +- (void*)(address + offsets->interpreter_frame.executable), ++ address_of_interpreter_state + ++ local_debug_offsets->interpreter_state.threads_head, + sizeof(void*), +- &address_of_code_object); ++ &address_of_thread); ++ if (bytes_read < 0) { ++ return -1; ++ } ++ ++ uintptr_t address_of_running_loop; ++ // No Python frames are available for us (can happen at tear-down). ++ if ((void*)address_of_thread == NULL) { ++ return 0; ++ } ++ ++ bytes_read = read_py_ptr( ++ pid, ++ address_of_thread ++ + async_offsets->asyncio_thread_state.asyncio_running_loop, ++ &address_of_running_loop); + if (bytes_read == -1) { + return -1; + } + +- if (address_of_code_object == 0) { ++ // no asyncio loop is now running ++ if ((void*)address_of_running_loop == NULL) { + return 0; + } +- address_of_code_object &= ~Py_TAG_BITS; +- return parse_code_object(pid, result, offsets, (void *)address_of_code_object, previous_frame); ++ ++ int err = read_ptr( ++ pid, ++ address_of_thread ++ + async_offsets->asyncio_thread_state.asyncio_running_task, ++ running_task_addr); ++ if (err) { ++ return -1; ++ } ++ ++ return 0; + } + + static PyObject* + get_stack_trace(PyObject* self, PyObject* args) + { +-#if (!defined(__linux__) && !defined(__APPLE__)) || (defined(__linux__) && !HAVE_PROCESS_VM_READV) +- PyErr_SetString(PyExc_RuntimeError, "get_stack_trace is not supported on this platform"); ++#if (!defined(__linux__) && !defined(__APPLE__)) || \ ++ (defined(__linux__) && !HAVE_PROCESS_VM_READV) ++ PyErr_SetString( ++ PyExc_RuntimeError, ++ "get_stack_trace is not supported on this platform"); + return NULL; + #endif + int pid; +@@ -542,88 +1456,205 @@ + return NULL; + } + +- void* runtime_start_address = get_py_runtime(pid); +- if (runtime_start_address == NULL) { +- if (!PyErr_Occurred()) { +- PyErr_SetString(PyExc_RuntimeError, "Failed to get .PyRuntime address"); +- } ++ uintptr_t runtime_start_address = get_py_runtime(pid); ++ struct _Py_DebugOffsets local_debug_offsets; ++ ++ if (read_offsets(pid, &runtime_start_address, &local_debug_offsets)) { + return NULL; + } +- size_t size = sizeof(struct _Py_DebugOffsets); +- struct _Py_DebugOffsets local_debug_offsets; + +- ssize_t bytes_read = read_memory(pid, runtime_start_address, size, &local_debug_offsets); +- if (bytes_read == -1) { ++ uintptr_t address_of_current_frame; ++ if (find_running_frame( ++ pid, runtime_start_address, &local_debug_offsets, ++ &address_of_current_frame) ++ ) { + return NULL; + } +- off_t interpreter_state_list_head = local_debug_offsets.runtime_state.interpreters_head; + +- void* address_of_interpreter_state; +- bytes_read = read_memory( +- pid, +- (void*)(runtime_start_address + interpreter_state_list_head), +- sizeof(void*), +- &address_of_interpreter_state); +- if (bytes_read == -1) { ++ PyObject* result = PyList_New(0); ++ if (result == NULL) { + return NULL; + } + +- if (address_of_interpreter_state == NULL) { +- PyErr_SetString(PyExc_RuntimeError, "No interpreter state found"); ++ while ((void*)address_of_current_frame != NULL) { ++ if (parse_frame_object( ++ pid, ++ result, ++ &local_debug_offsets, ++ address_of_current_frame, ++ &address_of_current_frame) ++ < 0) ++ { ++ Py_DECREF(result); ++ return NULL; ++ } ++ } ++ ++ return result; ++} ++ ++static PyObject* ++get_async_stack_trace(PyObject* self, PyObject* args) ++{ ++#if (!defined(__linux__) && !defined(__APPLE__)) || \ ++ (defined(__linux__) && !HAVE_PROCESS_VM_READV) ++ PyErr_SetString( ++ PyExc_RuntimeError, ++ "get_stack_trace is not supported on this platform"); ++ return NULL; ++#endif ++ int pid; ++ ++ if (!PyArg_ParseTuple(args, "i", &pid)) { + return NULL; + } + +- void* address_of_thread; +- bytes_read = read_memory( +- pid, +- (void*)(address_of_interpreter_state + local_debug_offsets.interpreter_state.threads_head), +- sizeof(void*), +- &address_of_thread); +- if (bytes_read == -1) { ++ uintptr_t runtime_start_address = get_py_runtime(pid); ++ struct _Py_DebugOffsets local_debug_offsets; ++ ++ if (read_offsets(pid, &runtime_start_address, &local_debug_offsets)) { + return NULL; + } + +- PyObject* result = PyList_New(0); ++ struct _Py_AsyncioModuleDebugOffsets local_async_debug; ++ if (read_async_debug(pid, &local_async_debug)) { ++ return NULL; ++ } ++ ++ PyObject* result = PyList_New(1); + if (result == NULL) { + return NULL; + } ++ PyObject* calls = PyList_New(0); ++ if (calls == NULL) { ++ return NULL; ++ } ++ if (PyList_SetItem(result, 0, calls)) { /* steals ref to 'calls' */ ++ Py_DECREF(result); ++ Py_DECREF(calls); ++ return NULL; ++ } + +- // No Python frames are available for us (can happen at tear-down). +- if (address_of_thread != NULL) { +- void* address_of_current_frame; +- (void)read_memory( +- pid, +- (void*)(address_of_thread + local_debug_offsets.thread_state.current_frame), +- sizeof(void*), +- &address_of_current_frame); +- while (address_of_current_frame != NULL) { +- if (parse_frame_object( +- pid, +- result, +- &local_debug_offsets, +- address_of_current_frame, +- &address_of_current_frame) +- < 0) +- { +- Py_DECREF(result); +- return NULL; +- } ++ uintptr_t running_task_addr = (uintptr_t)NULL; ++ if (find_running_task( ++ pid, runtime_start_address, &local_debug_offsets, &local_async_debug, ++ &running_task_addr) ++ ) { ++ goto result_err; ++ } ++ ++ if ((void*)running_task_addr == NULL) { ++ PyErr_SetString(PyExc_RuntimeError, "No running task found"); ++ goto result_err; ++ } ++ ++ uintptr_t running_coro_addr; ++ if (read_py_ptr( ++ pid, ++ running_task_addr + local_async_debug.asyncio_task_object.task_coro, ++ &running_coro_addr ++ )) { ++ goto result_err; ++ } ++ ++ if ((void*)running_coro_addr == NULL) { ++ PyErr_SetString(PyExc_RuntimeError, "Running task coro is NULL"); ++ goto result_err; ++ } ++ ++ // note: genobject's gi_iframe is an embedded struct so the address to ++ // the offset leads directly to its first field: f_executable ++ uintptr_t address_of_running_task_code_obj; ++ if (read_py_ptr( ++ pid, ++ running_coro_addr + local_debug_offsets.gen_object.gi_iframe, ++ &address_of_running_task_code_obj ++ )) { ++ goto result_err; ++ } ++ ++ if ((void*)address_of_running_task_code_obj == NULL) { ++ PyErr_SetString(PyExc_RuntimeError, "Running task code object is NULL"); ++ goto result_err; ++ } ++ ++ uintptr_t address_of_current_frame; ++ if (find_running_frame( ++ pid, runtime_start_address, &local_debug_offsets, ++ &address_of_current_frame) ++ ) { ++ goto result_err; ++ } ++ ++ uintptr_t address_of_code_object; ++ while ((void*)address_of_current_frame != NULL) { ++ int res = parse_async_frame_object( ++ pid, ++ calls, ++ &local_debug_offsets, ++ address_of_current_frame, ++ &address_of_current_frame, ++ &address_of_code_object ++ ); ++ ++ if (res < 0) { ++ goto result_err; ++ } ++ ++ if (address_of_code_object == address_of_running_task_code_obj) { ++ break; + } + } + ++ PyObject *tn = parse_task_name( ++ pid, &local_debug_offsets, &local_async_debug, running_task_addr); ++ if (tn == NULL) { ++ goto result_err; ++ } ++ if (PyList_Append(result, tn)) { ++ Py_DECREF(tn); ++ goto result_err; ++ } ++ Py_DECREF(tn); ++ ++ PyObject* awaited_by = PyList_New(0); ++ if (awaited_by == NULL) { ++ goto result_err; ++ } ++ if (PyList_Append(result, awaited_by)) { ++ Py_DECREF(awaited_by); ++ goto result_err; ++ } ++ Py_DECREF(awaited_by); ++ ++ if (parse_task_awaited_by( ++ pid, &local_debug_offsets, &local_async_debug, ++ running_task_addr, awaited_by) ++ ) { ++ goto result_err; ++ } ++ + return result; ++ ++result_err: ++ Py_DECREF(result); ++ return NULL; + } + ++ + static PyMethodDef methods[] = { +- {"get_stack_trace", get_stack_trace, METH_VARARGS, "Get the Python stack from a given PID"}, +- {NULL, NULL, 0, NULL}, ++ {"get_stack_trace", get_stack_trace, METH_VARARGS, ++ "Get the Python stack from a given PID"}, ++ {"get_async_stack_trace", get_async_stack_trace, METH_VARARGS, ++ "Get the asyncio stack from a given PID"}, ++ {NULL, NULL, 0, NULL}, + }; + + static struct PyModuleDef module = { +- .m_base = PyModuleDef_HEAD_INIT, +- .m_name = "_testexternalinspection", +- .m_size = -1, +- .m_methods = methods, ++ .m_base = PyModuleDef_HEAD_INIT, ++ .m_name = "_testexternalinspection", ++ .m_size = -1, ++ .m_methods = methods, + }; + + PyMODINIT_FUNC +@@ -636,7 +1667,8 @@ + #ifdef Py_GIL_DISABLED + PyUnstable_Module_SetGIL(mod, Py_MOD_GIL_NOT_USED); + #endif +- int rc = PyModule_AddIntConstant(mod, "PROCESS_VM_READV_SUPPORTED", HAVE_PROCESS_VM_READV); ++ int rc = PyModule_AddIntConstant( ++ mod, "PROCESS_VM_READV_SUPPORTED", HAVE_PROCESS_VM_READV); + if (rc < 0) { + Py_DECREF(mod); + return NULL; +diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c +index 014f89997f7..e44b629897c 100644 +--- a/Modules/_testinternalcapi.c ++++ b/Modules/_testinternalcapi.c +@@ -25,10 +25,8 @@ + #include "pycore_hashtable.h" // _Py_hashtable_new() + #include "pycore_initconfig.h" // _Py_GetConfigsAsDict() + #include "pycore_instruction_sequence.h" // _PyInstructionSequence_New() +-#include "pycore_interp.h" // _PyInterpreterState_GetConfigCopy() +-#include "pycore_long.h" // _PyLong_Sign() + #include "pycore_object.h" // _PyObject_IsFreed() +-#include "pycore_optimizer.h" // _Py_UopsSymbol, etc. ++#include "pycore_optimizer.h" // JitOptSymbol, etc. + #include "pycore_pathconfig.h" // _PyPathConfig_ClearGlobal() + #include "pycore_pyerrors.h" // _PyErr_ChainExceptions1() + #include "pycore_pylifecycle.h" // _PyInterpreterConfig_AsDict() +@@ -318,41 +316,6 @@ + } + + +-static PyObject * +-test_get_config(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) +-{ +- PyConfig config; +- PyConfig_InitIsolatedConfig(&config); +- if (_PyInterpreterState_GetConfigCopy(&config) < 0) { +- PyConfig_Clear(&config); +- return NULL; +- } +- PyObject *dict = _PyConfig_AsDict(&config); +- PyConfig_Clear(&config); +- return dict; +-} +- +- +-static PyObject * +-test_set_config(PyObject *Py_UNUSED(self), PyObject *dict) +-{ +- PyConfig config; +- PyConfig_InitIsolatedConfig(&config); +- if (_PyConfig_FromDict(&config, dict) < 0) { +- goto error; +- } +- if (_PyInterpreterState_SetConfig(&config) < 0) { +- goto error; +- } +- PyConfig_Clear(&config); +- Py_RETURN_NONE; +- +-error: +- PyConfig_Clear(&config); +- return NULL; +-} +- +- + static PyObject * + test_reset_path_config(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(arg)) + { +@@ -987,44 +950,13 @@ + return PyLong_FromLong(code->co_framesize); + } + +-#ifdef _Py_TIER2 +- +-static PyObject * +-new_counter_optimizer(PyObject *self, PyObject *arg) +-{ +- return _PyOptimizer_NewCounter(); +-} +- + static PyObject * +-new_uop_optimizer(PyObject *self, PyObject *arg) ++jit_enabled(PyObject *self, PyObject *arg) + { +- return _PyOptimizer_NewUOpOptimizer(); ++ return PyBool_FromLong(_PyInterpreterState_GET()->jit); + } + +-static PyObject * +-set_optimizer(PyObject *self, PyObject *opt) +-{ +- if (opt == Py_None) { +- opt = NULL; +- } +- if (_Py_SetTier2Optimizer((_PyOptimizerObject*)opt) < 0) { +- return NULL; +- } +- Py_RETURN_NONE; +-} +- +-static PyObject * +-get_optimizer(PyObject *self, PyObject *Py_UNUSED(ignored)) +-{ +- PyObject *opt = NULL; + #ifdef _Py_TIER2 +- opt = (PyObject *)_Py_GetOptimizer(); +-#endif +- if (opt == NULL) { +- Py_RETURN_NONE; +- } +- return opt; +-} + + static PyObject * + add_executor_dependency(PyObject *self, PyObject *args) +@@ -1034,12 +966,6 @@ + if (!PyArg_ParseTuple(args, "OO", &exec, &obj)) { + return NULL; + } +- /* No way to tell in general if exec is an executor, so we only accept +- * counting_executor */ +- if (strcmp(Py_TYPE(exec)->tp_name, "counting_executor")) { +- PyErr_SetString(PyExc_TypeError, "argument must be a counting_executor"); +- return NULL; +- } + _Py_Executor_DependsOn((_PyExecutorObject *)exec, obj); + Py_RETURN_NONE; + } +@@ -1846,14 +1772,14 @@ + + for (i = 0; i < Py_ARRAY_LENGTH(testcases); ++i) { + uint64_t nbits; +- int sign; ++ int sign = -7; + PyObject *plong; + + plong = PyLong_FromLong(testcases[i].input); + if (plong == NULL) + return NULL; + nbits = _PyLong_NumBits(plong); +- sign = _PyLong_Sign(plong); ++ (void)PyLong_GetSign(plong, &sign); + + Py_DECREF(plong); + if (nbits != testcases[i].nbits) +@@ -1861,7 +1787,7 @@ + "wrong result for _PyLong_NumBits"); + if (sign != testcases[i].sign) + return raiseTestError("test_long_numbits", +- "wrong result for _PyLong_Sign"); ++ "wrong result for PyLong_GetSign()"); + } + Py_RETURN_NONE; + } +@@ -1989,6 +1915,14 @@ + Py_RETURN_FALSE; + } + ++static PyObject * ++has_split_table(PyObject *self, PyObject *obj) ++{ ++ if (PyDict_Check(obj) && _PyDict_HasSplitTable((PyDictObject *)obj)) { ++ Py_RETURN_TRUE; ++ } ++ Py_RETURN_FALSE; ++} + + // Circumvents standard version assignment machinery - use with caution and only on + // short-lived heap types +@@ -2066,8 +2000,6 @@ + {"test_popcount", test_popcount, METH_NOARGS}, + {"test_bit_length", test_bit_length, METH_NOARGS}, + {"test_hashtable", test_hashtable, METH_NOARGS}, +- {"get_config", test_get_config, METH_NOARGS}, +- {"set_config", test_set_config, METH_O}, + {"reset_path_config", test_reset_path_config, METH_NOARGS}, + {"test_edit_cost", test_edit_cost, METH_NOARGS}, + {"test_bytes_find", test_bytes_find, METH_NOARGS}, +@@ -2090,11 +2022,8 @@ + {"iframe_getline", iframe_getline, METH_O, NULL}, + {"iframe_getlasti", iframe_getlasti, METH_O, NULL}, + {"get_co_framesize", get_co_framesize, METH_O, NULL}, ++ {"jit_enabled", jit_enabled, METH_NOARGS, NULL}, + #ifdef _Py_TIER2 +- {"get_optimizer", get_optimizer, METH_NOARGS, NULL}, +- {"set_optimizer", set_optimizer, METH_O, NULL}, +- {"new_counter_optimizer", new_counter_optimizer, METH_NOARGS, NULL}, +- {"new_uop_optimizer", new_uop_optimizer, METH_NOARGS, NULL}, + {"add_executor_dependency", add_executor_dependency, METH_VARARGS, NULL}, + {"invalidate_executors", invalidate_executors, METH_O, NULL}, + #endif +@@ -2139,6 +2068,7 @@ + {"get_rare_event_counters", get_rare_event_counters, METH_NOARGS}, + {"reset_rare_event_counters", reset_rare_event_counters, METH_NOARGS}, + {"has_inline_values", has_inline_values, METH_O}, ++ {"has_split_table", has_split_table, METH_O}, + {"type_assign_specific_version_unsafe", type_assign_specific_version_unsafe, METH_VARARGS, + PyDoc_STR("forcefully assign type->tp_version_tag")}, + +@@ -2208,6 +2138,21 @@ + return 1; + } + ++ if (PyModule_Add(module, "SPECIALIZATION_THRESHOLD", ++ PyLong_FromLong(ADAPTIVE_WARMUP_VALUE + 1)) < 0) { ++ return 1; ++ } ++ ++ if (PyModule_Add(module, "SPECIALIZATION_COOLDOWN", ++ PyLong_FromLong(ADAPTIVE_COOLDOWN_VALUE + 1)) < 0) { ++ return 1; ++ } ++ ++ if (PyModule_Add(module, "SHARED_KEYS_MAX_SIZE", ++ PyLong_FromLong(SHARED_KEYS_MAX_SIZE)) < 0) { ++ return 1; ++ } ++ + return 0; + } + +diff --git a/Modules/_testlimitedcapi.c b/Modules/_testlimitedcapi.c +index ba83a23117b..4dae99ec92a 100644 +--- a/Modules/_testlimitedcapi.c ++++ b/Modules/_testlimitedcapi.c +@@ -56,6 +56,9 @@ + if (_PyTestLimitedCAPI_Init_HeaptypeRelative(mod) < 0) { + return NULL; + } ++ if (_PyTestLimitedCAPI_Init_Import(mod) < 0) { ++ return NULL; ++ } + if (_PyTestLimitedCAPI_Init_List(mod) < 0) { + return NULL; + } +@@ -83,5 +86,11 @@ + if (_PyTestLimitedCAPI_Init_VectorcallLimited(mod) < 0) { + return NULL; + } ++ if (_PyTestLimitedCAPI_Init_Version(mod) < 0) { ++ return NULL; ++ } ++ if (_PyTestLimitedCAPI_Init_File(mod) < 0) { ++ return NULL; ++ } + return mod; + } +--- /dev/null ++++ b/Modules/_testlimitedcapi/clinic/file.c.h +@@ -0,0 +1,81 @@ ++/*[clinic input] ++preserve ++[clinic start generated code]*/ ++ ++PyDoc_STRVAR(_testcapi_pyfile_getline__doc__, ++"pyfile_getline($module, file, n, /)\n" ++"--\n" ++"\n"); ++ ++#define _TESTCAPI_PYFILE_GETLINE_METHODDEF \ ++ {"pyfile_getline", (PyCFunction)(void(*)(void))_testcapi_pyfile_getline, METH_FASTCALL, _testcapi_pyfile_getline__doc__}, ++ ++static PyObject * ++_testcapi_pyfile_getline_impl(PyObject *module, PyObject *file, int n); ++ ++static PyObject * ++_testcapi_pyfile_getline(PyObject *module, PyObject *const *args, Py_ssize_t nargs) ++{ ++ PyObject *return_value = NULL; ++ PyObject *file; ++ int n; ++ ++ if (nargs != 2) { ++ PyErr_Format(PyExc_TypeError, "pyfile_getline expected 2 arguments, got %zd", nargs); ++ goto exit; ++ } ++ file = args[0]; ++ n = PyLong_AsInt(args[1]); ++ if (n == -1 && PyErr_Occurred()) { ++ goto exit; ++ } ++ return_value = _testcapi_pyfile_getline_impl(module, file, n); ++ ++exit: ++ return return_value; ++} ++ ++PyDoc_STRVAR(_testcapi_pyfile_writeobject__doc__, ++"pyfile_writeobject($module, obj, file, flags, /)\n" ++"--\n" ++"\n"); ++ ++#define _TESTCAPI_PYFILE_WRITEOBJECT_METHODDEF \ ++ {"pyfile_writeobject", (PyCFunction)(void(*)(void))_testcapi_pyfile_writeobject, METH_FASTCALL, _testcapi_pyfile_writeobject__doc__}, ++ ++static PyObject * ++_testcapi_pyfile_writeobject_impl(PyObject *module, PyObject *obj, ++ PyObject *file, int flags); ++ ++static PyObject * ++_testcapi_pyfile_writeobject(PyObject *module, PyObject *const *args, Py_ssize_t nargs) ++{ ++ PyObject *return_value = NULL; ++ PyObject *obj; ++ PyObject *file; ++ int flags; ++ ++ if (nargs != 3) { ++ PyErr_Format(PyExc_TypeError, "pyfile_writeobject expected 3 arguments, got %zd", nargs); ++ goto exit; ++ } ++ obj = args[0]; ++ file = args[1]; ++ flags = PyLong_AsInt(args[2]); ++ if (flags == -1 && PyErr_Occurred()) { ++ goto exit; ++ } ++ return_value = _testcapi_pyfile_writeobject_impl(module, obj, file, flags); ++ ++exit: ++ return return_value; ++} ++ ++PyDoc_STRVAR(_testcapi_pyobject_asfiledescriptor__doc__, ++"pyobject_asfiledescriptor($module, obj, /)\n" ++"--\n" ++"\n"); ++ ++#define _TESTCAPI_PYOBJECT_ASFILEDESCRIPTOR_METHODDEF \ ++ {"pyobject_asfiledescriptor", (PyCFunction)_testcapi_pyobject_asfiledescriptor, METH_O, _testcapi_pyobject_asfiledescriptor__doc__}, ++/*[clinic end generated code: output=ea572aaaa01aec7b input=a9049054013a1b77]*/ +--- /dev/null ++++ b/Modules/_testlimitedcapi/clinic/version.c.h +@@ -0,0 +1,93 @@ ++/*[clinic input] ++preserve ++[clinic start generated code]*/ ++ ++PyDoc_STRVAR(_testlimitedcapi_pack_full_version__doc__, ++"pack_full_version($module, major, minor, micro, level, serial, /)\n" ++"--\n" ++"\n"); ++ ++#define _TESTLIMITEDCAPI_PACK_FULL_VERSION_METHODDEF \ ++ {"pack_full_version", (PyCFunction)(void(*)(void))_testlimitedcapi_pack_full_version, METH_FASTCALL, _testlimitedcapi_pack_full_version__doc__}, ++ ++static PyObject * ++_testlimitedcapi_pack_full_version_impl(PyObject *module, int major, ++ int minor, int micro, int level, ++ int serial); ++ ++static PyObject * ++_testlimitedcapi_pack_full_version(PyObject *module, PyObject *const *args, Py_ssize_t nargs) ++{ ++ PyObject *return_value = NULL; ++ int major; ++ int minor; ++ int micro; ++ int level; ++ int serial; ++ ++ if (nargs != 5) { ++ PyErr_Format(PyExc_TypeError, "pack_full_version expected 5 arguments, got %zd", nargs); ++ goto exit; ++ } ++ major = PyLong_AsInt(args[0]); ++ if (major == -1 && PyErr_Occurred()) { ++ goto exit; ++ } ++ minor = PyLong_AsInt(args[1]); ++ if (minor == -1 && PyErr_Occurred()) { ++ goto exit; ++ } ++ micro = PyLong_AsInt(args[2]); ++ if (micro == -1 && PyErr_Occurred()) { ++ goto exit; ++ } ++ level = PyLong_AsInt(args[3]); ++ if (level == -1 && PyErr_Occurred()) { ++ goto exit; ++ } ++ serial = PyLong_AsInt(args[4]); ++ if (serial == -1 && PyErr_Occurred()) { ++ goto exit; ++ } ++ return_value = _testlimitedcapi_pack_full_version_impl(module, major, minor, micro, level, serial); ++ ++exit: ++ return return_value; ++} ++ ++PyDoc_STRVAR(_testlimitedcapi_pack_version__doc__, ++"pack_version($module, major, minor, /)\n" ++"--\n" ++"\n"); ++ ++#define _TESTLIMITEDCAPI_PACK_VERSION_METHODDEF \ ++ {"pack_version", (PyCFunction)(void(*)(void))_testlimitedcapi_pack_version, METH_FASTCALL, _testlimitedcapi_pack_version__doc__}, ++ ++static PyObject * ++_testlimitedcapi_pack_version_impl(PyObject *module, int major, int minor); ++ ++static PyObject * ++_testlimitedcapi_pack_version(PyObject *module, PyObject *const *args, Py_ssize_t nargs) ++{ ++ PyObject *return_value = NULL; ++ int major; ++ int minor; ++ ++ if (nargs != 2) { ++ PyErr_Format(PyExc_TypeError, "pack_version expected 2 arguments, got %zd", nargs); ++ goto exit; ++ } ++ major = PyLong_AsInt(args[0]); ++ if (major == -1 && PyErr_Occurred()) { ++ goto exit; ++ } ++ minor = PyLong_AsInt(args[1]); ++ if (minor == -1 && PyErr_Occurred()) { ++ goto exit; ++ } ++ return_value = _testlimitedcapi_pack_version_impl(module, major, minor); ++ ++exit: ++ return return_value; ++} ++/*[clinic end generated code: output=aed3e226da77f2d2 input=a9049054013a1b77]*/ +--- /dev/null ++++ b/Modules/_testlimitedcapi/file.c +@@ -0,0 +1,128 @@ ++#include "pyconfig.h" // Py_GIL_DISABLED ++#ifndef Py_GIL_DISABLED ++ // Need limited C API 3.13 for PyLong_AsInt() ++# define Py_LIMITED_API 0x030d0000 ++#endif ++ ++#include "parts.h" ++#include "util.h" ++#include "clinic/file.c.h" ++ ++ ++/*[clinic input] ++module _testcapi ++[clinic start generated code]*/ ++/*[clinic end generated code: output=da39a3ee5e6b4b0d input=6361033e795369fc]*/ ++ ++ ++static PyObject * ++pyfile_fromfd(PyObject *module, PyObject *args) ++{ ++ int fd; ++ const char *name; ++ Py_ssize_t size; ++ const char *mode; ++ int buffering; ++ const char *encoding; ++ const char *errors; ++ const char *newline; ++ int closefd; ++ if (!PyArg_ParseTuple(args, ++ "iz#z#" ++ "iz#z#" ++ "z#i", ++ &fd, &name, &size, &mode, &size, ++ &buffering, &encoding, &size, &errors, &size, ++ &newline, &size, &closefd)) { ++ return NULL; ++ } ++ ++ return PyFile_FromFd(fd, name, mode, buffering, ++ encoding, errors, newline, closefd); ++} ++ ++ ++/*[clinic input] ++_testcapi.pyfile_getline ++ ++ file: object ++ n: int ++ / ++ ++[clinic start generated code]*/ ++ ++static PyObject * ++_testcapi_pyfile_getline_impl(PyObject *module, PyObject *file, int n) ++/*[clinic end generated code: output=137fde2774563266 input=df26686148b3657e]*/ ++{ ++ return PyFile_GetLine(file, n); ++} ++ ++ ++/*[clinic input] ++_testcapi.pyfile_writeobject ++ ++ obj: object ++ file: object ++ flags: int ++ / ++ ++[clinic start generated code]*/ ++ ++static PyObject * ++_testcapi_pyfile_writeobject_impl(PyObject *module, PyObject *obj, ++ PyObject *file, int flags) ++/*[clinic end generated code: output=ebb4d802e3db489c input=64a34a3e75b9935a]*/ ++{ ++ NULLABLE(obj); ++ NULLABLE(file); ++ RETURN_INT(PyFile_WriteObject(obj, file, flags)); ++} ++ ++ ++static PyObject * ++pyfile_writestring(PyObject *module, PyObject *args) ++{ ++ const char *str; ++ Py_ssize_t size; ++ PyObject *file; ++ if (!PyArg_ParseTuple(args, "z#O", &str, &size, &file)) { ++ return NULL; ++ } ++ NULLABLE(file); ++ ++ RETURN_INT(PyFile_WriteString(str, file)); ++} ++ ++ ++/*[clinic input] ++_testcapi.pyobject_asfiledescriptor ++ ++ obj: object ++ / ++ ++[clinic start generated code]*/ ++ ++static PyObject * ++_testcapi_pyobject_asfiledescriptor(PyObject *module, PyObject *obj) ++/*[clinic end generated code: output=2d640c6a1970c721 input=45fa1171d62b18d7]*/ ++{ ++ NULLABLE(obj); ++ RETURN_INT(PyObject_AsFileDescriptor(obj)); ++} ++ ++ ++static PyMethodDef test_methods[] = { ++ {"pyfile_fromfd", pyfile_fromfd, METH_VARARGS}, ++ _TESTCAPI_PYFILE_GETLINE_METHODDEF ++ _TESTCAPI_PYFILE_WRITEOBJECT_METHODDEF ++ {"pyfile_writestring", pyfile_writestring, METH_VARARGS}, ++ _TESTCAPI_PYOBJECT_ASFILEDESCRIPTOR_METHODDEF ++ {NULL}, ++}; ++ ++int ++_PyTestLimitedCAPI_Init_File(PyObject *m) ++{ ++ return PyModule_AddFunctions(m, test_methods); ++} +--- /dev/null ++++ b/Modules/_testlimitedcapi/import.c +@@ -0,0 +1,306 @@ ++// Need limited C API version 3.13 for PyImport_AddModuleRef() ++#include "pyconfig.h" // Py_GIL_DISABLED ++#if !defined(Py_GIL_DISABLED) && !defined(Py_LIMITED_API) ++# define Py_LIMITED_API 0x030d0000 ++#endif ++ ++#include "parts.h" ++#include "util.h" ++ ++ ++/* Test PyImport_GetMagicNumber() */ ++static PyObject * ++pyimport_getmagicnumber(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) ++{ ++ long magic = PyImport_GetMagicNumber(); ++ return PyLong_FromLong(magic); ++} ++ ++ ++/* Test PyImport_GetMagicTag() */ ++static PyObject * ++pyimport_getmagictag(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) ++{ ++ const char *tag = PyImport_GetMagicTag(); ++ return PyUnicode_FromString(tag); ++} ++ ++ ++/* Test PyImport_GetModuleDict() */ ++static PyObject * ++pyimport_getmoduledict(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) ++{ ++ return Py_XNewRef(PyImport_GetModuleDict()); ++} ++ ++ ++/* Test PyImport_GetModule() */ ++static PyObject * ++pyimport_getmodule(PyObject *Py_UNUSED(module), PyObject *name) ++{ ++ assert(!PyErr_Occurred()); ++ NULLABLE(name); ++ PyObject *module = PyImport_GetModule(name); ++ if (module == NULL && !PyErr_Occurred()) { ++ return Py_NewRef(PyExc_KeyError); ++ } ++ return module; ++} ++ ++ ++/* Test PyImport_AddModuleObject() */ ++static PyObject * ++pyimport_addmoduleobject(PyObject *Py_UNUSED(module), PyObject *name) ++{ ++ NULLABLE(name); ++ return Py_XNewRef(PyImport_AddModuleObject(name)); ++} ++ ++ ++/* Test PyImport_AddModule() */ ++static PyObject * ++pyimport_addmodule(PyObject *Py_UNUSED(module), PyObject *args) ++{ ++ const char *name; ++ Py_ssize_t size; ++ if (!PyArg_ParseTuple(args, "z#", &name, &size)) { ++ return NULL; ++ } ++ ++ return Py_XNewRef(PyImport_AddModule(name)); ++} ++ ++ ++/* Test PyImport_AddModuleRef() */ ++static PyObject * ++pyimport_addmoduleref(PyObject *Py_UNUSED(module), PyObject *args) ++{ ++ const char *name; ++ Py_ssize_t size; ++ if (!PyArg_ParseTuple(args, "z#", &name, &size)) { ++ return NULL; ++ } ++ ++ return PyImport_AddModuleRef(name); ++} ++ ++ ++/* Test PyImport_Import() */ ++static PyObject * ++pyimport_import(PyObject *Py_UNUSED(module), PyObject *name) ++{ ++ NULLABLE(name); ++ return PyImport_Import(name); ++} ++ ++ ++/* Test PyImport_ImportModule() */ ++static PyObject * ++pyimport_importmodule(PyObject *Py_UNUSED(module), PyObject *args) ++{ ++ const char *name; ++ Py_ssize_t size; ++ if (!PyArg_ParseTuple(args, "z#", &name, &size)) { ++ return NULL; ++ } ++ ++ return PyImport_ImportModule(name); ++} ++ ++ ++/* Test PyImport_ImportModuleNoBlock() */ ++static PyObject * ++pyimport_importmodulenoblock(PyObject *Py_UNUSED(module), PyObject *args) ++{ ++ const char *name; ++ Py_ssize_t size; ++ if (!PyArg_ParseTuple(args, "z#", &name, &size)) { ++ return NULL; ++ } ++ ++ _Py_COMP_DIAG_PUSH ++ _Py_COMP_DIAG_IGNORE_DEPR_DECLS ++ return PyImport_ImportModuleNoBlock(name); ++ _Py_COMP_DIAG_POP ++} ++ ++ ++/* Test PyImport_ImportModuleEx() */ ++static PyObject * ++pyimport_importmoduleex(PyObject *Py_UNUSED(module), PyObject *args) ++{ ++ const char *name; ++ Py_ssize_t size; ++ PyObject *globals, *locals, *fromlist; ++ if (!PyArg_ParseTuple(args, "z#OOO", ++ &name, &size, &globals, &locals, &fromlist)) { ++ return NULL; ++ } ++ NULLABLE(globals); ++ NULLABLE(locals); ++ NULLABLE(fromlist); ++ ++ return PyImport_ImportModuleEx(name, globals, locals, fromlist); ++} ++ ++ ++/* Test PyImport_ImportModuleLevel() */ ++static PyObject * ++pyimport_importmodulelevel(PyObject *Py_UNUSED(module), PyObject *args) ++{ ++ const char *name; ++ Py_ssize_t size; ++ PyObject *globals, *locals, *fromlist; ++ int level; ++ if (!PyArg_ParseTuple(args, "z#OOOi", ++ &name, &size, &globals, &locals, &fromlist, &level)) { ++ return NULL; ++ } ++ NULLABLE(globals); ++ NULLABLE(locals); ++ NULLABLE(fromlist); ++ ++ return PyImport_ImportModuleLevel(name, globals, locals, fromlist, level); ++} ++ ++ ++/* Test PyImport_ImportModuleLevelObject() */ ++static PyObject * ++pyimport_importmodulelevelobject(PyObject *Py_UNUSED(module), PyObject *args) ++{ ++ PyObject *name, *globals, *locals, *fromlist; ++ int level; ++ if (!PyArg_ParseTuple(args, "OOOOi", ++ &name, &globals, &locals, &fromlist, &level)) { ++ return NULL; ++ } ++ NULLABLE(name); ++ NULLABLE(globals); ++ NULLABLE(locals); ++ NULLABLE(fromlist); ++ ++ return PyImport_ImportModuleLevelObject(name, globals, locals, fromlist, level); ++} ++ ++ ++/* Test PyImport_ImportFrozenModule() */ ++static PyObject * ++pyimport_importfrozenmodule(PyObject *Py_UNUSED(module), PyObject *args) ++{ ++ const char *name; ++ Py_ssize_t size; ++ if (!PyArg_ParseTuple(args, "z#", &name, &size)) { ++ return NULL; ++ } ++ ++ RETURN_INT(PyImport_ImportFrozenModule(name)); ++} ++ ++ ++/* Test PyImport_ImportFrozenModuleObject() */ ++static PyObject * ++pyimport_importfrozenmoduleobject(PyObject *Py_UNUSED(module), PyObject *name) ++{ ++ NULLABLE(name); ++ RETURN_INT(PyImport_ImportFrozenModuleObject(name)); ++} ++ ++ ++/* Test PyImport_ExecCodeModule() */ ++static PyObject * ++pyimport_executecodemodule(PyObject *Py_UNUSED(module), PyObject *args) ++{ ++ const char *name; ++ Py_ssize_t size; ++ PyObject *code; ++ if (!PyArg_ParseTuple(args, "z#O", &name, &size, &code)) { ++ return NULL; ++ } ++ NULLABLE(code); ++ ++ return PyImport_ExecCodeModule(name, code); ++} ++ ++ ++/* Test PyImport_ExecCodeModuleEx() */ ++static PyObject * ++pyimport_executecodemoduleex(PyObject *Py_UNUSED(module), PyObject *args) ++{ ++ const char *name; ++ Py_ssize_t size; ++ PyObject *code; ++ const char *pathname; ++ if (!PyArg_ParseTuple(args, "z#Oz#", &name, &size, &code, &pathname, &size)) { ++ return NULL; ++ } ++ NULLABLE(code); ++ ++ return PyImport_ExecCodeModuleEx(name, code, pathname); ++} ++ ++ ++/* Test PyImport_ExecCodeModuleWithPathnames() */ ++static PyObject * ++pyimport_executecodemodulewithpathnames(PyObject *Py_UNUSED(module), PyObject *args) ++{ ++ const char *name; ++ Py_ssize_t size; ++ PyObject *code; ++ const char *pathname; ++ const char *cpathname; ++ if (!PyArg_ParseTuple(args, "z#Oz#z#", &name, &size, &code, &pathname, &size, &cpathname, &size)) { ++ return NULL; ++ } ++ NULLABLE(code); ++ ++ return PyImport_ExecCodeModuleWithPathnames(name, code, ++ pathname, cpathname); ++} ++ ++ ++/* Test PyImport_ExecCodeModuleObject() */ ++static PyObject * ++pyimport_executecodemoduleobject(PyObject *Py_UNUSED(module), PyObject *args) ++{ ++ PyObject *name, *code, *pathname, *cpathname; ++ if (!PyArg_ParseTuple(args, "OOOO", &name, &code, &pathname, &cpathname)) { ++ return NULL; ++ } ++ NULLABLE(name); ++ NULLABLE(code); ++ NULLABLE(pathname); ++ NULLABLE(cpathname); ++ ++ return PyImport_ExecCodeModuleObject(name, code, pathname, cpathname); ++} ++ ++ ++static PyMethodDef test_methods[] = { ++ {"PyImport_GetMagicNumber", pyimport_getmagicnumber, METH_NOARGS}, ++ {"PyImport_GetMagicTag", pyimport_getmagictag, METH_NOARGS}, ++ {"PyImport_GetModuleDict", pyimport_getmoduledict, METH_NOARGS}, ++ {"PyImport_GetModule", pyimport_getmodule, METH_O}, ++ {"PyImport_AddModuleObject", pyimport_addmoduleobject, METH_O}, ++ {"PyImport_AddModule", pyimport_addmodule, METH_VARARGS}, ++ {"PyImport_AddModuleRef", pyimport_addmoduleref, METH_VARARGS}, ++ {"PyImport_Import", pyimport_import, METH_O}, ++ {"PyImport_ImportModule", pyimport_importmodule, METH_VARARGS}, ++ {"PyImport_ImportModuleNoBlock", pyimport_importmodulenoblock, METH_VARARGS}, ++ {"PyImport_ImportModuleEx", pyimport_importmoduleex, METH_VARARGS}, ++ {"PyImport_ImportModuleLevel", pyimport_importmodulelevel, METH_VARARGS}, ++ {"PyImport_ImportModuleLevelObject", pyimport_importmodulelevelobject, METH_VARARGS}, ++ {"PyImport_ImportFrozenModule", pyimport_importfrozenmodule, METH_VARARGS}, ++ {"PyImport_ImportFrozenModuleObject", pyimport_importfrozenmoduleobject, METH_O}, ++ {"PyImport_ExecCodeModule", pyimport_executecodemodule, METH_VARARGS}, ++ {"PyImport_ExecCodeModuleEx", pyimport_executecodemoduleex, METH_VARARGS}, ++ {"PyImport_ExecCodeModuleWithPathnames", pyimport_executecodemodulewithpathnames, METH_VARARGS}, ++ {"PyImport_ExecCodeModuleObject", pyimport_executecodemoduleobject, METH_VARARGS}, ++ {NULL}, ++}; ++ ++ ++int ++_PyTestLimitedCAPI_Init_Import(PyObject *module) ++{ ++ return PyModule_AddFunctions(module, test_methods); ++} +diff --git a/Modules/_testlimitedcapi/parts.h b/Modules/_testlimitedcapi/parts.h +index 4107b150c5b..60f6f03011a 100644 +--- a/Modules/_testlimitedcapi/parts.h ++++ b/Modules/_testlimitedcapi/parts.h +@@ -31,6 +31,7 @@ + int _PyTestLimitedCAPI_Init_Eval(PyObject *module); + int _PyTestLimitedCAPI_Init_Float(PyObject *module); + int _PyTestLimitedCAPI_Init_HeaptypeRelative(PyObject *module); ++int _PyTestLimitedCAPI_Init_Import(PyObject *module); + int _PyTestLimitedCAPI_Init_Object(PyObject *module); + int _PyTestLimitedCAPI_Init_List(PyObject *module); + int _PyTestLimitedCAPI_Init_Long(PyObject *module); +@@ -40,5 +41,7 @@ + int _PyTestLimitedCAPI_Init_Tuple(PyObject *module); + int _PyTestLimitedCAPI_Init_Unicode(PyObject *module); + int _PyTestLimitedCAPI_Init_VectorcallLimited(PyObject *module); ++int _PyTestLimitedCAPI_Init_Version(PyObject *module); ++int _PyTestLimitedCAPI_Init_File(PyObject *module); + + #endif // Py_TESTLIMITEDCAPI_PARTS_H +--- /dev/null ++++ b/Modules/_testlimitedcapi/version.c +@@ -0,0 +1,77 @@ ++/* Test version macros in the limited API */ ++ ++#include "pyconfig.h" // Py_GIL_DISABLED ++#ifndef Py_GIL_DISABLED ++# define Py_LIMITED_API 0x030e0000 // Added in 3.14 ++#endif ++ ++#include "parts.h" ++#include "clinic/version.c.h" ++#include ++ ++/*[clinic input] ++module _testlimitedcapi ++[clinic start generated code]*/ ++/*[clinic end generated code: output=da39a3ee5e6b4b0d input=2700057f9c1135ba]*/ ++ ++/*[clinic input] ++_testlimitedcapi.pack_full_version ++ ++ major: int ++ minor: int ++ micro: int ++ level: int ++ serial: int ++ / ++[clinic start generated code]*/ ++ ++static PyObject * ++_testlimitedcapi_pack_full_version_impl(PyObject *module, int major, ++ int minor, int micro, int level, ++ int serial) ++/*[clinic end generated code: output=b87a1e9805648861 input=2a304423be61d2ac]*/ ++{ ++ uint32_t macro_result = Py_PACK_FULL_VERSION( ++ major, minor, micro, level, serial); ++#undef Py_PACK_FULL_VERSION ++ uint32_t func_result = Py_PACK_FULL_VERSION( ++ major, minor, micro, level, serial); ++ ++ assert(macro_result == func_result); ++ return PyLong_FromUnsignedLong((unsigned long)func_result); ++} ++ ++/*[clinic input] ++_testlimitedcapi.pack_version ++ ++ major: int ++ minor: int ++ / ++[clinic start generated code]*/ ++ ++static PyObject * ++_testlimitedcapi_pack_version_impl(PyObject *module, int major, int minor) ++/*[clinic end generated code: output=771247bbd06e7883 input=3e39e9dcbc09e86a]*/ ++{ ++ uint32_t macro_result = Py_PACK_VERSION(major, minor); ++#undef Py_PACK_VERSION ++ uint32_t func_result = Py_PACK_VERSION(major, minor); ++ ++ assert(macro_result == func_result); ++ return PyLong_FromUnsignedLong((unsigned long)func_result); ++} ++ ++static PyMethodDef TestMethods[] = { ++ _TESTLIMITEDCAPI_PACK_FULL_VERSION_METHODDEF ++ _TESTLIMITEDCAPI_PACK_VERSION_METHODDEF ++ {NULL}, ++}; ++ ++int ++_PyTestLimitedCAPI_Init_Version(PyObject *m) ++{ ++ if (PyModule_AddFunctions(m, TestMethods) < 0) { ++ return -1; ++ } ++ return 0; ++} +diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c +index 75b34a8df76..e251736fb36 100644 +--- a/Modules/_threadmodule.c ++++ b/Modules/_threadmodule.c +@@ -47,6 +47,14 @@ + } + + ++#ifdef MS_WINDOWS ++typedef HRESULT (WINAPI *PF_GET_THREAD_DESCRIPTION)(HANDLE, PCWSTR*); ++typedef HRESULT (WINAPI *PF_SET_THREAD_DESCRIPTION)(HANDLE, PCWSTR); ++static PF_GET_THREAD_DESCRIPTION pGetThreadDescription = NULL; ++static PF_SET_THREAD_DESCRIPTION pSetThreadDescription = NULL; ++#endif ++ ++ + /*[clinic input] + module _thread + [clinic start generated code]*/ +@@ -1414,6 +1422,10 @@ + return NULL; + } + ++ // gh-128691: Use deferred reference counting for thread-locals to avoid ++ // contention on the shared object. ++ _PyObject_SetDeferredRefcount((PyObject *)self); ++ + self->args = Py_XNewRef(args); + self->kw = Py_XNewRef(kw); + +@@ -1527,17 +1539,20 @@ + goto err; + } + +- if (PyDict_SetItem(self->localdicts, tstate->threading_local_key, ldict) < +- 0) { ++ if (PyDict_SetItem(self->localdicts, tstate->threading_local_key, ++ ldict) < 0) ++ { + goto err; + } + + wr = create_sentinel_wr(self); + if (wr == NULL) { + PyObject *exc = PyErr_GetRaisedException(); +- if (PyDict_DelItem(self->localdicts, tstate->threading_local_key) < +- 0) { +- PyErr_WriteUnraisable((PyObject *)self); ++ if (PyDict_DelItem(self->localdicts, ++ tstate->threading_local_key) < 0) ++ { ++ PyErr_FormatUnraisable("Exception ignored while deleting " ++ "thread local of %R", self); + } + PyErr_SetRaisedException(exc); + goto err; +@@ -1545,9 +1560,11 @@ + + if (PySet_Add(self->thread_watchdogs, wr) < 0) { + PyObject *exc = PyErr_GetRaisedException(); +- if (PyDict_DelItem(self->localdicts, tstate->threading_local_key) < +- 0) { +- PyErr_WriteUnraisable((PyObject *)self); ++ if (PyDict_DelItem(self->localdicts, ++ tstate->threading_local_key) < 0) ++ { ++ PyErr_FormatUnraisable("Exception ignored while deleting " ++ "thread local of %R", self); + } + PyErr_SetRaisedException(exc); + goto err; +@@ -1597,13 +1614,16 @@ + we create a new one the next time we do an attr + access */ + PyObject *exc = PyErr_GetRaisedException(); +- if (PyDict_DelItem(self->localdicts, tstate->threading_local_key) < +- 0) { +- PyErr_WriteUnraisable((PyObject *)self); +- PyErr_Clear(); ++ if (PyDict_DelItem(self->localdicts, ++ tstate->threading_local_key) < 0) ++ { ++ PyErr_FormatUnraisable("Exception ignored while deleting " ++ "thread local of %R", self); ++ assert(!PyErr_Occurred()); + } + if (PySet_Discard(self->thread_watchdogs, wr) < 0) { +- PyErr_WriteUnraisable((PyObject *)self); ++ PyErr_FormatUnraisable("Exception ignored while discarding " ++ "thread watchdog of %R", self); + } + PyErr_SetRaisedException(exc); + Py_DECREF(ldict); +@@ -1734,12 +1754,14 @@ + if (self->localdicts != NULL) { + PyObject *key = PyTuple_GetItem(locals_and_key, 1); + if (PyDict_Pop(self->localdicts, key, NULL) < 0) { +- PyErr_WriteUnraisable((PyObject*)self); ++ PyErr_FormatUnraisable("Exception ignored while clearing " ++ "thread local %R", (PyObject *)self); + } + } + if (self->thread_watchdogs != NULL) { + if (PySet_Discard(self->thread_watchdogs, dummyweakref) < 0) { +- PyErr_WriteUnraisable((PyObject *)self); ++ PyErr_FormatUnraisable("Exception ignored while clearing " ++ "thread local %R", (PyObject *)self); + } + } + +@@ -2302,7 +2324,8 @@ + // Wait for the thread to finish. If we're interrupted, such + // as by a ctrl-c we print the error and exit early. + if (ThreadHandle_join(handle, -1) < 0) { +- PyErr_WriteUnraisable(NULL); ++ PyErr_FormatUnraisable("Exception ignored while joining a thread " ++ "in _thread._shutdown()"); + ThreadHandle_decref(handle); + Py_RETURN_NONE; + } +@@ -2364,7 +2387,7 @@ + of the main interpreter."); + + +-#ifdef HAVE_PTHREAD_GETNAME_NP ++#if defined(HAVE_PTHREAD_GETNAME_NP) || defined(MS_WINDOWS) + /*[clinic input] + _thread._get_name + +@@ -2375,6 +2398,7 @@ + _thread__get_name_impl(PyObject *module) + /*[clinic end generated code: output=20026e7ee3da3dd7 input=35cec676833d04c8]*/ + { ++#ifndef MS_WINDOWS + // Linux and macOS are limited to respectively 16 and 64 bytes + char name[100]; + pthread_t thread = pthread_self(); +@@ -2389,11 +2413,26 @@ + #else + return PyUnicode_DecodeFSDefault(name); + #endif ++#else ++ // Windows implementation ++ assert(pGetThreadDescription != NULL); ++ ++ wchar_t *name; ++ HRESULT hr = pGetThreadDescription(GetCurrentThread(), &name); ++ if (FAILED(hr)) { ++ PyErr_SetFromWindowsErr(0); ++ return NULL; ++ } ++ ++ PyObject *name_obj = PyUnicode_FromWideChar(name, -1); ++ LocalFree(name); ++ return name_obj; ++#endif + } + #endif // HAVE_PTHREAD_GETNAME_NP + + +-#ifdef HAVE_PTHREAD_SETNAME_NP ++#if defined(HAVE_PTHREAD_SETNAME_NP) || defined(MS_WINDOWS) + /*[clinic input] + _thread.set_name + +@@ -2406,6 +2445,7 @@ + _thread_set_name_impl(PyObject *module, PyObject *name_obj) + /*[clinic end generated code: output=402b0c68e0c0daed input=7e7acd98261be82f]*/ + { ++#ifndef MS_WINDOWS + #ifdef __sun + // Solaris always uses UTF-8 + const char *encoding = "utf-8"; +@@ -2421,12 +2461,12 @@ + return NULL; + } + +-#ifdef PYTHREAD_NAME_MAXLEN +- // Truncate to PYTHREAD_NAME_MAXLEN bytes + the NUL byte if needed +- if (PyBytes_GET_SIZE(name_encoded) > PYTHREAD_NAME_MAXLEN) { ++#ifdef _PYTHREAD_NAME_MAXLEN ++ // Truncate to _PYTHREAD_NAME_MAXLEN bytes + the NUL byte if needed ++ if (PyBytes_GET_SIZE(name_encoded) > _PYTHREAD_NAME_MAXLEN) { + PyObject *truncated; + truncated = PyBytes_FromStringAndSize(PyBytes_AS_STRING(name_encoded), +- PYTHREAD_NAME_MAXLEN); ++ _PYTHREAD_NAME_MAXLEN); + if (truncated == NULL) { + Py_DECREF(name_encoded); + return NULL; +@@ -2438,6 +2478,9 @@ + const char *name = PyBytes_AS_STRING(name_encoded); + #ifdef __APPLE__ + int rc = pthread_setname_np(name); ++#elif defined(__NetBSD__) ++ pthread_t thread = pthread_self(); ++ int rc = pthread_setname_np(thread, "%s", (void *)name); + #else + pthread_t thread = pthread_self(); + int rc = pthread_setname_np(thread, name); +@@ -2448,6 +2491,35 @@ + return PyErr_SetFromErrno(PyExc_OSError); + } + Py_RETURN_NONE; ++#else ++ // Windows implementation ++ assert(pSetThreadDescription != NULL); ++ ++ Py_ssize_t len; ++ wchar_t *name = PyUnicode_AsWideCharString(name_obj, &len); ++ if (name == NULL) { ++ return NULL; ++ } ++ ++ if (len > _PYTHREAD_NAME_MAXLEN) { ++ // Truncate the name ++ Py_UCS4 ch = name[_PYTHREAD_NAME_MAXLEN-1]; ++ if (Py_UNICODE_IS_HIGH_SURROGATE(ch)) { ++ name[_PYTHREAD_NAME_MAXLEN-1] = 0; ++ } ++ else { ++ name[_PYTHREAD_NAME_MAXLEN] = 0; ++ } ++ } ++ ++ HRESULT hr = pSetThreadDescription(GetCurrentThread(), name); ++ PyMem_Free(name); ++ if (FAILED(hr)) { ++ PyErr_SetFromWindowsErr((int)hr); ++ return NULL; ++ } ++ Py_RETURN_NONE; ++#endif + } + #endif // HAVE_PTHREAD_SETNAME_NP + +@@ -2584,13 +2656,38 @@ + + llist_init(&state->shutdown_handles); + +-#ifdef PYTHREAD_NAME_MAXLEN ++#ifdef _PYTHREAD_NAME_MAXLEN + if (PyModule_AddIntConstant(module, "_NAME_MAXLEN", +- PYTHREAD_NAME_MAXLEN) < 0) { ++ _PYTHREAD_NAME_MAXLEN) < 0) { + return -1; + } + #endif + ++#ifdef MS_WINDOWS ++ HMODULE kernelbase = GetModuleHandleW(L"kernelbase.dll"); ++ if (kernelbase != NULL) { ++ if (pGetThreadDescription == NULL) { ++ pGetThreadDescription = (PF_GET_THREAD_DESCRIPTION)GetProcAddress( ++ kernelbase, "GetThreadDescription"); ++ } ++ if (pSetThreadDescription == NULL) { ++ pSetThreadDescription = (PF_SET_THREAD_DESCRIPTION)GetProcAddress( ++ kernelbase, "SetThreadDescription"); ++ } ++ } ++ ++ if (pGetThreadDescription == NULL) { ++ if (PyObject_DelAttrString(module, "_get_name") < 0) { ++ return -1; ++ } ++ } ++ if (pSetThreadDescription == NULL) { ++ if (PyObject_DelAttrString(module, "set_name") < 0) { ++ return -1; ++ } ++ } ++#endif ++ + return 0; + } + +diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c +index 887a1e820e2..be71fc9fc9c 100644 +--- a/Modules/_tracemalloc.c ++++ b/Modules/_tracemalloc.c +@@ -215,18 +215,14 @@ + PyMODINIT_FUNC + PyInit__tracemalloc(void) + { +- PyObject *m; +- m = PyModule_Create(&module_def); +- if (m == NULL) ++ PyObject *mod = PyModule_Create(&module_def); ++ if (mod == NULL) { + return NULL; ++ } ++ + #ifdef Py_GIL_DISABLED +- PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED); ++ PyUnstable_Module_SetGIL(mod, Py_MOD_GIL_NOT_USED); + #endif + +- if (_PyTraceMalloc_Init() < 0) { +- Py_DECREF(m); +- return NULL; +- } +- +- return m; ++ return mod; + } +diff --git a/Modules/_winapi.c b/Modules/_winapi.c +index 4ce689fe30e..786a828f009 100644 +--- a/Modules/_winapi.c ++++ b/Modules/_winapi.c +@@ -171,17 +171,16 @@ + { + /* The operation is no longer pending -- nothing to do. */ + } +- else if (_Py_IsInterpreterFinalizing(_PyInterpreterState_GET())) +- { ++ else if (_Py_IsInterpreterFinalizing(_PyInterpreterState_GET())) { + /* The operation is still pending -- give a warning. This + will probably only happen on Windows XP. */ + PyErr_SetString(PyExc_PythonFinalizationError, + "I/O operations still in flight while destroying " + "Overlapped object, the process may crash"); +- PyErr_WriteUnraisable(NULL); ++ PyErr_FormatUnraisable("Exception ignored while deallocating " ++ "overlapped operation %R", self); + } +- else +- { ++ else { + /* The operation is still pending, but the process is + probably about to exit, so we need not worry too much + about memory leaks. Leaking self prevents a potential +@@ -1048,7 +1047,7 @@ + } + + normalized_environment = normalize_environment(environment); +- if (normalize_environment == NULL) { ++ if (normalized_environment == NULL) { + return NULL; + } + +diff --git a/Modules/_zoneinfo.c b/Modules/_zoneinfo.c +index c5292575c22..1fcea9ce8b1 100644 +--- a/Modules/_zoneinfo.c ++++ b/Modules/_zoneinfo.c +@@ -782,7 +782,7 @@ + if (self->source == SOURCE_FILE) { + // Objects constructed from files cannot be pickled. + PyObject *pickle_error = +- _PyImport_GetModuleAttrString("pickle", "PicklingError"); ++ PyImport_ImportModuleAttrString("pickle", "PicklingError"); + if (pickle_error == NULL) { + return NULL; + } +@@ -2554,7 +2554,7 @@ + new_weak_cache(void) + { + PyObject *WeakValueDictionary = +- _PyImport_GetModuleAttrString("weakref", "WeakValueDictionary"); ++ PyImport_ImportModuleAttrString("weakref", "WeakValueDictionary"); + if (WeakValueDictionary == NULL) { + return NULL; + } +@@ -2732,12 +2732,12 @@ + + /* Populate imports */ + state->_tzpath_find_tzfile = +- _PyImport_GetModuleAttrString("zoneinfo._tzpath", "find_tzfile"); ++ PyImport_ImportModuleAttrString("zoneinfo._tzpath", "find_tzfile"); + if (state->_tzpath_find_tzfile == NULL) { + goto error; + } + +- state->io_open = _PyImport_GetModuleAttrString("io", "open"); ++ state->io_open = PyImport_ImportModuleAttrString("io", "open"); + if (state->io_open == NULL) { + goto error; + } +diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c +index b80c964f20d..5b86ec98393 100644 +--- a/Modules/arraymodule.c ++++ b/Modules/arraymodule.c +@@ -79,6 +79,9 @@ + #define get_array_state_by_class(cls) \ + (get_array_state(PyType_GetModule(cls))) + ++#define arrayobject_CAST(op) ((arrayobject *)(op)) ++#define arrayiterobject_CAST(op) ((arrayiterobject *)(op)) ++ + enum machine_format_code { + UNKNOWN_FORMAT = -1, + /* UNKNOWN_FORMAT is used to indicate that the machine format for an +@@ -712,22 +715,25 @@ + /* Methods */ + + static int +-array_tp_traverse(arrayobject *op, visitproc visit, void *arg) ++array_tp_traverse(PyObject *op, visitproc visit, void *arg) + { + Py_VISIT(Py_TYPE(op)); + return 0; + } + + static void +-array_dealloc(arrayobject *op) ++array_dealloc(PyObject *op) + { + PyTypeObject *tp = Py_TYPE(op); + PyObject_GC_UnTrack(op); + +- if (op->weakreflist != NULL) +- PyObject_ClearWeakRefs((PyObject *) op); +- if (op->ob_item != NULL) +- PyMem_Free(op->ob_item); ++ arrayobject *self = arrayobject_CAST(op); ++ if (self->weakreflist != NULL) { ++ PyObject_ClearWeakRefs(op); ++ } ++ if (self->ob_item != NULL) { ++ PyMem_Free(self->ob_item); ++ } + tp->tp_free(op); + Py_DECREF(tp); + } +@@ -843,19 +849,19 @@ + } + + static Py_ssize_t +-array_length(arrayobject *a) ++array_length(PyObject *op) + { +- return Py_SIZE(a); ++ return Py_SIZE(op); + } + + static PyObject * +-array_item(arrayobject *a, Py_ssize_t i) ++array_item(PyObject *op, Py_ssize_t i) + { +- if (i < 0 || i >= Py_SIZE(a)) { ++ if (i < 0 || i >= Py_SIZE(op)) { + PyErr_SetString(PyExc_IndexError, "array index out of range"); + return NULL; + } +- return getarrayitem((PyObject *)a, i); ++ return getarrayitem(op, i); + } + + static PyObject * +@@ -930,8 +936,9 @@ + } + + static PyObject * +-array_concat(arrayobject *a, PyObject *bb) ++array_concat(PyObject *op, PyObject *bb) + { ++ arrayobject *a = arrayobject_CAST(op); + array_state *state = find_array_state_by_type(Py_TYPE(a)); + Py_ssize_t size; + arrayobject *np; +@@ -966,8 +973,9 @@ + } + + static PyObject * +-array_repeat(arrayobject *a, Py_ssize_t n) ++array_repeat(PyObject *op, Py_ssize_t n) + { ++ arrayobject *a = arrayobject_CAST(op); + array_state *state = find_array_state_by_type(Py_TYPE(a)); + + if (n < 0) +@@ -1026,8 +1034,9 @@ + } + + static int +-array_ass_item(arrayobject *a, Py_ssize_t i, PyObject *v) ++array_ass_item(PyObject *op, Py_ssize_t i, PyObject *v) + { ++ arrayobject *a = arrayobject_CAST(op); + if (i < 0 || i >= Py_SIZE(a)) { + PyErr_SetString(PyExc_IndexError, + "array assignment index out of range"); +@@ -1045,7 +1054,7 @@ + array_state *state = find_array_state_by_type(Py_TYPE(a)); + assert(array_Check(a, state)); + #endif +- return array_ass_item((arrayobject *)a, i, v); ++ return array_ass_item(a, i, v); + } + + static int +@@ -1105,8 +1114,9 @@ + } + + static PyObject * +-array_inplace_concat(arrayobject *self, PyObject *bb) ++array_inplace_concat(PyObject *op, PyObject *bb) + { ++ arrayobject *self = arrayobject_CAST(op); + array_state *state = find_array_state_by_type(Py_TYPE(self)); + + if (!array_Check(bb, state)) { +@@ -1121,8 +1131,9 @@ + } + + static PyObject * +-array_inplace_repeat(arrayobject *self, Py_ssize_t n) ++array_inplace_repeat(PyObject *op, Py_ssize_t n) + { ++ arrayobject *self = arrayobject_CAST(op); + const Py_ssize_t array_size = Py_SIZE(self); + + if (array_size > 0 && n != 1 ) { +@@ -1236,13 +1247,13 @@ + } + + static int +-array_contains(arrayobject *self, PyObject *v) ++array_contains(PyObject *self, PyObject *v) + { + Py_ssize_t i; + int cmp; + + for (i = 0, cmp = 0 ; cmp == 0 && i < Py_SIZE(self); i++) { +- PyObject *selfi = getarrayitem((PyObject *)self, i); ++ PyObject *selfi = getarrayitem(self, i); + if (selfi == NULL) + return -1; + cmp = PyObject_RichCompareBool(selfi, v, Py_EQ); +@@ -1557,7 +1568,7 @@ + + not_enough_bytes = (PyBytes_GET_SIZE(b) != nbytes); + +- res = array_array_frombytes(self, b); ++ res = array_array_frombytes((PyObject *)self, b); + Py_DECREF(b); + if (res == NULL) + return NULL; +@@ -2285,7 +2296,7 @@ + assert(state != NULL); + + if (state->array_reconstructor == NULL) { +- state->array_reconstructor = _PyImport_GetModuleAttrString( ++ state->array_reconstructor = PyImport_ImportModuleAttrString( + "array", "_array_reconstructor"); + if (state->array_reconstructor == NULL) { + return NULL; +@@ -2349,22 +2360,24 @@ + } + + static PyObject * +-array_get_typecode(arrayobject *a, void *closure) ++array_get_typecode(PyObject *op, void *Py_UNUSED(closure)) + { ++ arrayobject *a = arrayobject_CAST(op); + char typecode = a->ob_descr->typecode; + return PyUnicode_FromOrdinal(typecode); + } + + static PyObject * +-array_get_itemsize(arrayobject *a, void *closure) ++array_get_itemsize(PyObject *op, void *Py_UNUSED(closure)) + { ++ arrayobject *a = arrayobject_CAST(op); + return PyLong_FromLong((long)a->ob_descr->itemsize); + } + + static PyGetSetDef array_getsets [] = { +- {"typecode", (getter) array_get_typecode, NULL, ++ {"typecode", array_get_typecode, NULL, + "the typecode character used to create the array"}, +- {"itemsize", (getter) array_get_itemsize, NULL, ++ {"itemsize", array_get_itemsize, NULL, + "the size, in bytes, of one array item"}, + {NULL} + }; +@@ -2398,11 +2411,12 @@ + }; + + static PyObject * +-array_repr(arrayobject *a) ++array_repr(PyObject *op) + { + char typecode; + PyObject *s, *v = NULL; + Py_ssize_t len; ++ arrayobject *a = arrayobject_CAST(op); + + len = Py_SIZE(a); + typecode = a->ob_descr->typecode; +@@ -2425,8 +2439,9 @@ + } + + static PyObject* +-array_subscr(arrayobject* self, PyObject* item) ++array_subscr(PyObject *op, PyObject *item) + { ++ arrayobject *self = arrayobject_CAST(op); + array_state *state = find_array_state_by_type(Py_TYPE(self)); + + if (PyIndex_Check(item)) { +@@ -2436,7 +2451,7 @@ + } + if (i < 0) + i += Py_SIZE(self); +- return array_item(self, i); ++ return array_item(op, i); + } + else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength, i; +@@ -2488,9 +2503,10 @@ + } + + static int +-array_ass_subscr(arrayobject* self, PyObject* item, PyObject* value) ++array_ass_subscr(PyObject *op, PyObject *item, PyObject *value) + { + Py_ssize_t start, stop, step, slicelength, needed; ++ arrayobject *self = arrayobject_CAST(op); + array_state* state = find_array_state_by_type(Py_TYPE(self)); + arrayobject* other; + int itemsize; +@@ -2542,7 +2558,7 @@ + value = array_slice(other, 0, needed); + if (value == NULL) + return -1; +- ret = array_ass_subscr(self, item, value); ++ ret = array_ass_subscr(op, item, value); + Py_DECREF(value); + return ret; + } +@@ -2649,7 +2665,7 @@ + + + static int +-array_buffer_getbuf(arrayobject *self, Py_buffer *view, int flags) ++array_buffer_getbuf(PyObject *op, Py_buffer *view, int flags) + { + if (view == NULL) { + PyErr_SetString(PyExc_BufferError, +@@ -2657,6 +2673,7 @@ + return -1; + } + ++ arrayobject *self = arrayobject_CAST(op); + view->buf = (void *)self->ob_item; + view->obj = Py_NewRef(self); + if (view->buf == NULL) +@@ -2689,8 +2706,9 @@ + } + + static void +-array_buffer_relbuf(arrayobject *self, Py_buffer *view) ++array_buffer_relbuf(PyObject *op, Py_buffer *Py_UNUSED(view)) + { ++ arrayobject *self = arrayobject_CAST(op); + self->ob_exports--; + } + +@@ -2797,8 +2815,7 @@ + else if (initial != NULL && (PyByteArray_Check(initial) || + PyBytes_Check(initial))) { + PyObject *v; +- v = array_array_frombytes((arrayobject *)a, +- initial); ++ v = array_array_frombytes((PyObject *)a, initial); + if (v == NULL) { + Py_DECREF(a); + return NULL; +@@ -2926,7 +2943,7 @@ + itemsize -- the length in bytes of one array item\n\ + "); + +-static PyObject *array_iter(arrayobject *ao); ++static PyObject *array_iter(PyObject *op); + + static struct PyMemberDef array_members[] = { + {"__weaklistoffset__", Py_T_PYSSIZET, offsetof(arrayobject, weakreflist), Py_READONLY}, +@@ -2986,8 +3003,9 @@ + /*[clinic end generated code: output=da39a3ee5e6b4b0d input=fb46d5ef98dd95ff]*/ + + static PyObject * +-array_iter(arrayobject *ao) ++array_iter(PyObject *op) + { ++ arrayobject *ao = arrayobject_CAST(op); + array_state *state = find_array_state_by_type(Py_TYPE(ao)); + arrayiterobject *it; + +@@ -3008,16 +3026,15 @@ + } + + static PyObject * +-arrayiter_next(arrayiterobject *it) ++arrayiter_next(PyObject *op) + { +- arrayobject *ao; +- ++ arrayiterobject *it = arrayiterobject_CAST(op); + assert(it != NULL); + #ifndef NDEBUG + array_state *state = find_array_state_by_type(Py_TYPE(it)); + assert(PyObject_TypeCheck(it, state->ArrayIterType)); + #endif +- ao = it->ao; ++ arrayobject *ao = it->ao; + if (ao == NULL) { + return NULL; + } +@@ -3033,10 +3050,10 @@ + } + + static void +-arrayiter_dealloc(arrayiterobject *it) ++arrayiter_dealloc(PyObject *op) + { ++ arrayiterobject *it = arrayiterobject_CAST(op); + PyTypeObject *tp = Py_TYPE(it); +- + PyObject_GC_UnTrack(it); + Py_XDECREF(it->ao); + PyObject_GC_Del(it); +@@ -3044,8 +3061,9 @@ + } + + static int +-arrayiter_traverse(arrayiterobject *it, visitproc visit, void *arg) ++arrayiter_traverse(PyObject *op, visitproc visit, void *arg) + { ++ arrayiterobject *it = arrayiterobject_CAST(op); + Py_VISIT(Py_TYPE(it)); + Py_VISIT(it->ao); + return 0; +@@ -3090,11 +3108,16 @@ + Py_ssize_t index = PyLong_AsSsize_t(state); + if (index == -1 && PyErr_Occurred()) + return NULL; +- if (index < 0) +- index = 0; +- else if (index > Py_SIZE(self->ao)) +- index = Py_SIZE(self->ao); /* iterator exhausted */ +- self->index = index; ++ arrayobject *ao = self->ao; ++ if (ao != NULL) { ++ if (index < 0) { ++ index = 0; ++ } ++ else if (index > Py_SIZE(ao)) { ++ index = Py_SIZE(ao); /* iterator exhausted */ ++ } ++ self->index = index; ++ } + Py_RETURN_NONE; + } + +@@ -3152,7 +3175,7 @@ + static void + array_free(void *module) + { +- array_clear((PyObject *)module); ++ (void)array_clear((PyObject *)module); + } + + /* No functions in array module. */ +@@ -3202,7 +3225,7 @@ + return -1; + } + +- PyObject *mutablesequence = _PyImport_GetModuleAttrString( ++ PyObject *mutablesequence = PyImport_ImportModuleAttrString( + "collections.abc", "MutableSequence"); + if (!mutablesequence) { + Py_DECREF((PyObject *)state->ArrayType); +diff --git a/Modules/atexitmodule.c b/Modules/atexitmodule.c +index 1b89b32ba90..2bfdda53af8 100644 +--- a/Modules/atexitmodule.c ++++ b/Modules/atexitmodule.c +@@ -110,7 +110,8 @@ + PyObject *copy = PyList_GetSlice(state->callbacks, 0, PyList_GET_SIZE(state->callbacks)); + if (copy == NULL) + { +- PyErr_WriteUnraisable(NULL); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "copying atexit callbacks"); + return; + } + +diff --git a/Modules/blake2module.c b/Modules/blake2module.c +index 94cdfe7fd2e..016c834c01b 100644 +--- a/Modules/blake2module.c ++++ b/Modules/blake2module.c +@@ -366,6 +366,8 @@ + PyMutex mutex; + } Blake2Object; + ++#define _Blake2Object_CAST(op) ((Blake2Object *)(op)) ++ + #include "clinic/blake2module.c.h" + + /*[clinic input] +@@ -379,13 +381,13 @@ + static Blake2Object * + new_Blake2Object(PyTypeObject *type) + { +- Blake2Object *self; +- self = (Blake2Object *)type->tp_alloc(type, 0); ++ Blake2Object *self = PyObject_GC_New(Blake2Object, type); + if (self == NULL) { + return NULL; + } + HASHLIB_INIT_MUTEX(self); + ++ PyObject_GC_Track(self); + return self; + } + +@@ -454,7 +456,28 @@ + } + + self->impl = type_to_impl(type); +- ++ // Ensure that the states are NULL-initialized in case of an error. ++ // See: py_blake2_clear() for more details. ++ switch (self->impl) { ++#if HACL_CAN_COMPILE_SIMD256 ++ case Blake2b_256: ++ self->blake2b_256_state = NULL; ++ break; ++#endif ++#if HACL_CAN_COMPILE_SIMD128 ++ case Blake2s_128: ++ self->blake2s_128_state = NULL; ++ break; ++#endif ++ case Blake2b: ++ self->blake2b_state = NULL; ++ break; ++ case Blake2s: ++ self->blake2s_state = NULL; ++ break; ++ default: ++ Py_UNREACHABLE(); ++ } + // Using Blake2b because we statically know that these are greater than the + // Blake2s sizes -- this avoids a VLA. + uint8_t salt_[HACL_HASH_BLAKE2B_SALT_BYTES] = { 0 }; +@@ -595,7 +618,7 @@ + + return (PyObject *)self; + error: +- Py_XDECREF(self); ++ Py_XDECREF(self); + return NULL; + } + +@@ -828,24 +851,27 @@ + + + static PyObject * +-py_blake2b_get_name(Blake2Object *self, void *closure) ++py_blake2b_get_name(PyObject *op, void *Py_UNUSED(closure)) + { ++ Blake2Object *self = _Blake2Object_CAST(op); + return PyUnicode_FromString(is_blake2b(self->impl) ? "blake2b" : "blake2s"); + } + + + + static PyObject * +-py_blake2b_get_block_size(Blake2Object *self, void *closure) ++py_blake2b_get_block_size(PyObject *op, void *Py_UNUSED(closure)) + { ++ Blake2Object *self = _Blake2Object_CAST(op); + return PyLong_FromLong(is_blake2b(self->impl) ? HACL_HASH_BLAKE2B_BLOCK_BYTES : HACL_HASH_BLAKE2S_BLOCK_BYTES); + } + + + + static PyObject * +-py_blake2b_get_digest_size(Blake2Object *self, void *closure) ++py_blake2b_get_digest_size(PyObject *op, void *Py_UNUSED(closure)) + { ++ Blake2Object *self = _Blake2Object_CAST(op); + switch (self->impl) { + #if HACL_CAN_COMPILE_SIMD256 + case Blake2b_256: +@@ -866,55 +892,77 @@ + + + static PyGetSetDef py_blake2b_getsetters[] = { +- {"name", (getter)py_blake2b_get_name, +- NULL, NULL, NULL}, +- {"block_size", (getter)py_blake2b_get_block_size, +- NULL, NULL, NULL}, +- {"digest_size", (getter)py_blake2b_get_digest_size, +- NULL, NULL, NULL}, +- {NULL} ++ {"name", py_blake2b_get_name, NULL, NULL, NULL}, ++ {"block_size", py_blake2b_get_block_size, NULL, NULL, NULL}, ++ {"digest_size", py_blake2b_get_digest_size, NULL, NULL, NULL}, ++ {NULL} /* Sentinel */ + }; + + +-static void +-py_blake2b_dealloc(Blake2Object *self) ++static int ++py_blake2_clear(PyObject *op) + { ++ Blake2Object *self = (Blake2Object *)op; ++ // The initialization function uses PyObject_GC_New() but explicitly ++ // initializes the HACL* internal state to NULL before allocating ++ // it. If an error occurs in the constructor, we should only free ++ // states that were allocated (i.e. that are not NULL). + switch (self->impl) { + #if HACL_CAN_COMPILE_SIMD256 + case Blake2b_256: +- if (self->blake2b_256_state != NULL) ++ if (self->blake2b_256_state != NULL) { + Hacl_Hash_Blake2b_Simd256_free(self->blake2b_256_state); ++ self->blake2b_256_state = NULL; ++ } + break; + #endif + #if HACL_CAN_COMPILE_SIMD128 + case Blake2s_128: +- if (self->blake2s_128_state != NULL) ++ if (self->blake2s_128_state != NULL) { + Hacl_Hash_Blake2s_Simd128_free(self->blake2s_128_state); ++ self->blake2s_128_state = NULL; ++ } + break; + #endif + case Blake2b: +- // This happens if we hit "goto error" in the middle of the +- // initialization function. We leverage the fact that tp_alloc +- // guarantees that the contents of the object are NULL-initialized +- // (see documentation for PyType_GenericAlloc) to detect this case. +- if (self->blake2b_state != NULL) ++ if (self->blake2b_state != NULL) { + Hacl_Hash_Blake2b_free(self->blake2b_state); ++ self->blake2b_state = NULL; ++ } + break; + case Blake2s: +- if (self->blake2s_state != NULL) ++ if (self->blake2s_state != NULL) { + Hacl_Hash_Blake2s_free(self->blake2s_state); ++ self->blake2s_state = NULL; ++ } + break; + default: + Py_UNREACHABLE(); + } ++ return 0; ++} + ++static void ++py_blake2_dealloc(PyObject *self) ++{ + PyTypeObject *type = Py_TYPE(self); +- PyObject_Free(self); ++ PyObject_GC_UnTrack(self); ++ (void)py_blake2_clear(self); ++ type->tp_free(self); + Py_DECREF(type); + } + ++static int ++py_blake2_traverse(PyObject *self, visitproc visit, void *arg) ++{ ++ Py_VISIT(Py_TYPE(self)); ++ return 0; ++} ++ + static PyType_Slot blake2b_type_slots[] = { +- {Py_tp_dealloc, py_blake2b_dealloc}, ++ {Py_tp_clear, py_blake2_clear}, ++ {Py_tp_dealloc, py_blake2_dealloc}, ++ {Py_tp_traverse, py_blake2_traverse}, + {Py_tp_doc, (char *)py_blake2b_new__doc__}, + {Py_tp_methods, py_blake2b_methods}, + {Py_tp_getset, py_blake2b_getsetters}, +@@ -923,7 +971,9 @@ + }; + + static PyType_Slot blake2s_type_slots[] = { +- {Py_tp_dealloc, py_blake2b_dealloc}, ++ {Py_tp_clear, py_blake2_clear}, ++ {Py_tp_dealloc, py_blake2_dealloc}, ++ {Py_tp_traverse, py_blake2_traverse}, + {Py_tp_doc, (char *)py_blake2s_new__doc__}, + {Py_tp_methods, py_blake2b_methods}, + {Py_tp_getset, py_blake2b_getsetters}, +@@ -936,13 +986,15 @@ + static PyType_Spec blake2b_type_spec = { + .name = "_blake2.blake2b", + .basicsize = sizeof(Blake2Object), +- .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE, ++ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE ++ | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HEAPTYPE, + .slots = blake2b_type_slots + }; + + static PyType_Spec blake2s_type_spec = { + .name = "_blake2.blake2s", + .basicsize = sizeof(Blake2Object), +- .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE, ++ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE ++ | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HEAPTYPE, + .slots = blake2s_type_slots + }; +diff --git a/Modules/cjkcodecs/cjkcodecs.h b/Modules/cjkcodecs/cjkcodecs.h +index 2b446ba5226..737a7a04275 100644 +--- a/Modules/cjkcodecs/cjkcodecs.h ++++ b/Modules/cjkcodecs/cjkcodecs.h +@@ -13,7 +13,6 @@ + + #include "Python.h" + #include "multibytecodec.h" +-#include "pycore_import.h" // _PyImport_GetModuleAttrString() + + + /* a unicode "undefined" code point */ +@@ -299,7 +298,7 @@ + static PyObject * + getmultibytecodec(void) + { +- return _PyImport_GetModuleAttrString("_multibytecodec", "__create_codec"); ++ return PyImport_ImportModuleAttrString("_multibytecodec", "__create_codec"); + } + + static void +diff --git a/Modules/cjkcodecs/clinic/multibytecodec.c.h b/Modules/cjkcodecs/clinic/multibytecodec.c.h +index 7e7ea9e0fdf..d77bbd48066 100644 +--- a/Modules/cjkcodecs/clinic/multibytecodec.c.h ++++ b/Modules/cjkcodecs/clinic/multibytecodec.c.h +@@ -28,7 +28,7 @@ + const char *errors); + + static PyObject * +-_multibytecodec_MultibyteCodec_encode(MultibyteCodecObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_multibytecodec_MultibyteCodec_encode(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -89,7 +89,7 @@ + goto exit; + } + skip_optional_pos: +- return_value = _multibytecodec_MultibyteCodec_encode_impl(self, input, errors); ++ return_value = _multibytecodec_MultibyteCodec_encode_impl((MultibyteCodecObject *)self, input, errors); + + exit: + return return_value; +@@ -115,7 +115,7 @@ + const char *errors); + + static PyObject * +-_multibytecodec_MultibyteCodec_decode(MultibyteCodecObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_multibytecodec_MultibyteCodec_decode(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -178,7 +178,7 @@ + goto exit; + } + skip_optional_pos: +- return_value = _multibytecodec_MultibyteCodec_decode_impl(self, &input, errors); ++ return_value = _multibytecodec_MultibyteCodec_decode_impl((MultibyteCodecObject *)self, &input, errors); + + exit: + /* Cleanup for input */ +@@ -203,7 +203,7 @@ + int final); + + static PyObject * +-_multibytecodec_MultibyteIncrementalEncoder_encode(MultibyteIncrementalEncoderObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_multibytecodec_MultibyteIncrementalEncoder_encode(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -250,7 +250,7 @@ + goto exit; + } + skip_optional_pos: +- return_value = _multibytecodec_MultibyteIncrementalEncoder_encode_impl(self, input, final); ++ return_value = _multibytecodec_MultibyteIncrementalEncoder_encode_impl((MultibyteIncrementalEncoderObject *)self, input, final); + + exit: + return return_value; +@@ -268,9 +268,9 @@ + _multibytecodec_MultibyteIncrementalEncoder_getstate_impl(MultibyteIncrementalEncoderObject *self); + + static PyObject * +-_multibytecodec_MultibyteIncrementalEncoder_getstate(MultibyteIncrementalEncoderObject *self, PyObject *Py_UNUSED(ignored)) ++_multibytecodec_MultibyteIncrementalEncoder_getstate(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _multibytecodec_MultibyteIncrementalEncoder_getstate_impl(self); ++ return _multibytecodec_MultibyteIncrementalEncoder_getstate_impl((MultibyteIncrementalEncoderObject *)self); + } + + PyDoc_STRVAR(_multibytecodec_MultibyteIncrementalEncoder_setstate__doc__, +@@ -286,7 +286,7 @@ + PyLongObject *statelong); + + static PyObject * +-_multibytecodec_MultibyteIncrementalEncoder_setstate(MultibyteIncrementalEncoderObject *self, PyObject *arg) ++_multibytecodec_MultibyteIncrementalEncoder_setstate(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + PyLongObject *statelong; +@@ -296,7 +296,7 @@ + goto exit; + } + statelong = (PyLongObject *)arg; +- return_value = _multibytecodec_MultibyteIncrementalEncoder_setstate_impl(self, statelong); ++ return_value = _multibytecodec_MultibyteIncrementalEncoder_setstate_impl((MultibyteIncrementalEncoderObject *)self, statelong); + + exit: + return return_value; +@@ -314,9 +314,9 @@ + _multibytecodec_MultibyteIncrementalEncoder_reset_impl(MultibyteIncrementalEncoderObject *self); + + static PyObject * +-_multibytecodec_MultibyteIncrementalEncoder_reset(MultibyteIncrementalEncoderObject *self, PyObject *Py_UNUSED(ignored)) ++_multibytecodec_MultibyteIncrementalEncoder_reset(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _multibytecodec_MultibyteIncrementalEncoder_reset_impl(self); ++ return _multibytecodec_MultibyteIncrementalEncoder_reset_impl((MultibyteIncrementalEncoderObject *)self); + } + + PyDoc_STRVAR(_multibytecodec_MultibyteIncrementalDecoder_decode__doc__, +@@ -333,7 +333,7 @@ + int final); + + static PyObject * +-_multibytecodec_MultibyteIncrementalDecoder_decode(MultibyteIncrementalDecoderObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_multibytecodec_MultibyteIncrementalDecoder_decode(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -382,7 +382,7 @@ + goto exit; + } + skip_optional_pos: +- return_value = _multibytecodec_MultibyteIncrementalDecoder_decode_impl(self, &input, final); ++ return_value = _multibytecodec_MultibyteIncrementalDecoder_decode_impl((MultibyteIncrementalDecoderObject *)self, &input, final); + + exit: + /* Cleanup for input */ +@@ -405,9 +405,9 @@ + _multibytecodec_MultibyteIncrementalDecoder_getstate_impl(MultibyteIncrementalDecoderObject *self); + + static PyObject * +-_multibytecodec_MultibyteIncrementalDecoder_getstate(MultibyteIncrementalDecoderObject *self, PyObject *Py_UNUSED(ignored)) ++_multibytecodec_MultibyteIncrementalDecoder_getstate(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _multibytecodec_MultibyteIncrementalDecoder_getstate_impl(self); ++ return _multibytecodec_MultibyteIncrementalDecoder_getstate_impl((MultibyteIncrementalDecoderObject *)self); + } + + PyDoc_STRVAR(_multibytecodec_MultibyteIncrementalDecoder_setstate__doc__, +@@ -423,7 +423,7 @@ + PyObject *state); + + static PyObject * +-_multibytecodec_MultibyteIncrementalDecoder_setstate(MultibyteIncrementalDecoderObject *self, PyObject *arg) ++_multibytecodec_MultibyteIncrementalDecoder_setstate(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + PyObject *state; +@@ -433,7 +433,7 @@ + goto exit; + } + state = arg; +- return_value = _multibytecodec_MultibyteIncrementalDecoder_setstate_impl(self, state); ++ return_value = _multibytecodec_MultibyteIncrementalDecoder_setstate_impl((MultibyteIncrementalDecoderObject *)self, state); + + exit: + return return_value; +@@ -451,9 +451,9 @@ + _multibytecodec_MultibyteIncrementalDecoder_reset_impl(MultibyteIncrementalDecoderObject *self); + + static PyObject * +-_multibytecodec_MultibyteIncrementalDecoder_reset(MultibyteIncrementalDecoderObject *self, PyObject *Py_UNUSED(ignored)) ++_multibytecodec_MultibyteIncrementalDecoder_reset(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _multibytecodec_MultibyteIncrementalDecoder_reset_impl(self); ++ return _multibytecodec_MultibyteIncrementalDecoder_reset_impl((MultibyteIncrementalDecoderObject *)self); + } + + PyDoc_STRVAR(_multibytecodec_MultibyteStreamReader_read__doc__, +@@ -469,7 +469,7 @@ + PyObject *sizeobj); + + static PyObject * +-_multibytecodec_MultibyteStreamReader_read(MultibyteStreamReaderObject *self, PyObject *const *args, Py_ssize_t nargs) ++_multibytecodec_MultibyteStreamReader_read(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *sizeobj = Py_None; +@@ -482,7 +482,7 @@ + } + sizeobj = args[0]; + skip_optional: +- return_value = _multibytecodec_MultibyteStreamReader_read_impl(self, sizeobj); ++ return_value = _multibytecodec_MultibyteStreamReader_read_impl((MultibyteStreamReaderObject *)self, sizeobj); + + exit: + return return_value; +@@ -501,7 +501,7 @@ + PyObject *sizeobj); + + static PyObject * +-_multibytecodec_MultibyteStreamReader_readline(MultibyteStreamReaderObject *self, PyObject *const *args, Py_ssize_t nargs) ++_multibytecodec_MultibyteStreamReader_readline(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *sizeobj = Py_None; +@@ -514,7 +514,7 @@ + } + sizeobj = args[0]; + skip_optional: +- return_value = _multibytecodec_MultibyteStreamReader_readline_impl(self, sizeobj); ++ return_value = _multibytecodec_MultibyteStreamReader_readline_impl((MultibyteStreamReaderObject *)self, sizeobj); + + exit: + return return_value; +@@ -533,7 +533,7 @@ + PyObject *sizehintobj); + + static PyObject * +-_multibytecodec_MultibyteStreamReader_readlines(MultibyteStreamReaderObject *self, PyObject *const *args, Py_ssize_t nargs) ++_multibytecodec_MultibyteStreamReader_readlines(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *sizehintobj = Py_None; +@@ -546,7 +546,7 @@ + } + sizehintobj = args[0]; + skip_optional: +- return_value = _multibytecodec_MultibyteStreamReader_readlines_impl(self, sizehintobj); ++ return_value = _multibytecodec_MultibyteStreamReader_readlines_impl((MultibyteStreamReaderObject *)self, sizehintobj); + + exit: + return return_value; +@@ -564,9 +564,9 @@ + _multibytecodec_MultibyteStreamReader_reset_impl(MultibyteStreamReaderObject *self); + + static PyObject * +-_multibytecodec_MultibyteStreamReader_reset(MultibyteStreamReaderObject *self, PyObject *Py_UNUSED(ignored)) ++_multibytecodec_MultibyteStreamReader_reset(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _multibytecodec_MultibyteStreamReader_reset_impl(self); ++ return _multibytecodec_MultibyteStreamReader_reset_impl((MultibyteStreamReaderObject *)self); + } + + PyDoc_STRVAR(_multibytecodec_MultibyteStreamWriter_write__doc__, +@@ -583,7 +583,7 @@ + PyObject *strobj); + + static PyObject * +-_multibytecodec_MultibyteStreamWriter_write(MultibyteStreamWriterObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_multibytecodec_MultibyteStreamWriter_write(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -608,7 +608,7 @@ + goto exit; + } + strobj = args[0]; +- return_value = _multibytecodec_MultibyteStreamWriter_write_impl(self, cls, strobj); ++ return_value = _multibytecodec_MultibyteStreamWriter_write_impl((MultibyteStreamWriterObject *)self, cls, strobj); + + exit: + return return_value; +@@ -628,7 +628,7 @@ + PyObject *lines); + + static PyObject * +-_multibytecodec_MultibyteStreamWriter_writelines(MultibyteStreamWriterObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_multibytecodec_MultibyteStreamWriter_writelines(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -653,7 +653,7 @@ + goto exit; + } + lines = args[0]; +- return_value = _multibytecodec_MultibyteStreamWriter_writelines_impl(self, cls, lines); ++ return_value = _multibytecodec_MultibyteStreamWriter_writelines_impl((MultibyteStreamWriterObject *)self, cls, lines); + + exit: + return return_value; +@@ -672,13 +672,13 @@ + PyTypeObject *cls); + + static PyObject * +-_multibytecodec_MultibyteStreamWriter_reset(MultibyteStreamWriterObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_multibytecodec_MultibyteStreamWriter_reset(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "reset() takes no arguments"); + return NULL; + } +- return _multibytecodec_MultibyteStreamWriter_reset_impl(self, cls); ++ return _multibytecodec_MultibyteStreamWriter_reset_impl((MultibyteStreamWriterObject *)self, cls); + } + + PyDoc_STRVAR(_multibytecodec___create_codec__doc__, +@@ -688,4 +688,4 @@ + + #define _MULTIBYTECODEC___CREATE_CODEC_METHODDEF \ + {"__create_codec", (PyCFunction)_multibytecodec___create_codec, METH_O, _multibytecodec___create_codec__doc__}, +-/*[clinic end generated code: output=60e1fa3a7615c148 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=6571941b8e45b013 input=a9049054013a1b77]*/ +diff --git a/Modules/cjkcodecs/multibytecodec.c b/Modules/cjkcodecs/multibytecodec.c +index 53135ae4aa7..08b74740bda 100644 +--- a/Modules/cjkcodecs/multibytecodec.c ++++ b/Modules/cjkcodecs/multibytecodec.c +@@ -56,6 +56,27 @@ + /*[clinic end generated code: output=da39a3ee5e6b4b0d input=305a76dfdd24b99c]*/ + #undef clinic_get_state + ++#define _MultibyteCodec_CAST(op) ((MultibyteCodec *)(op)) ++#define _MultibyteCodecObject_CAST(op) ((MultibyteCodecObject *)(op)) ++ ++#define _MultibyteStatefulCodecContext_CAST(op) \ ++ ((MultibyteStatefulCodecContext *)(op)) ++ ++#define _MultibyteStatefulEncoderContext_CAST(op) \ ++ ((MultibyteStatefulEncoderContext *)(op)) ++#define _MultibyteStatefulDecoderContext_CAST(op) \ ++ ((MultibyteStatefulDecoderContext *)(op)) ++ ++#define _MultibyteIncrementalEncoderObject_CAST(op) \ ++ ((MultibyteIncrementalEncoderObject *)(op)) ++#define _MultibyteIncrementalDecoderObject_CAST(op) \ ++ ((MultibyteIncrementalDecoderObject *)(op)) ++ ++#define _MultibyteStreamReaderObject_CAST(op) \ ++ ((MultibyteStreamReaderObject *)(op)) ++#define _MultibyteStreamWriterObject_CAST(op) \ ++ ((MultibyteStreamWriterObject *)(op)) ++ + typedef struct { + PyObject *inobj; + Py_ssize_t inpos, inlen; +@@ -136,9 +157,10 @@ + } + + static PyObject * +-codecctx_errors_get(MultibyteStatefulCodecContext *self, void *Py_UNUSED(ignored)) ++codecctx_errors_get(PyObject *op, void *Py_UNUSED(closure)) + { + const char *errors; ++ MultibyteStatefulCodecContext *self = _MultibyteStatefulCodecContext_CAST(op); + + if (self->errors == ERROR_STRICT) + errors = "strict"; +@@ -154,11 +176,11 @@ + } + + static int +-codecctx_errors_set(MultibyteStatefulCodecContext *self, PyObject *value, +- void *closure) ++codecctx_errors_set(PyObject *op, PyObject *value, void *Py_UNUSED(closure)) + { + PyObject *cb; + const char *str; ++ MultibyteStatefulCodecContext *self = _MultibyteStatefulCodecContext_CAST(op); + + if (value == NULL) { + PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); +@@ -184,9 +206,8 @@ + + /* This getset handlers list is used by all the stateful codec objects */ + static PyGetSetDef codecctx_getsets[] = { +- {"errors", (getter)codecctx_errors_get, +- (setter)codecctx_errors_set, +- PyDoc_STR("how to treat errors")}, ++ {"errors", codecctx_errors_get, codecctx_errors_set, ++ PyDoc_STR("how to treat errors")}, + {NULL,} + }; + +@@ -719,22 +740,24 @@ + }; + + static int +-multibytecodec_clear(MultibyteCodecObject *self) ++multibytecodec_clear(PyObject *op) + { ++ MultibyteCodecObject *self = _MultibyteCodecObject_CAST(op); + Py_CLEAR(self->cjk_module); + return 0; + } + + static int +-multibytecodec_traverse(MultibyteCodecObject *self, visitproc visit, void *arg) ++multibytecodec_traverse(PyObject *op, visitproc visit, void *arg) + { ++ MultibyteCodecObject *self = _MultibyteCodecObject_CAST(op); + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->cjk_module); + return 0; + } + + static void +-multibytecodec_dealloc(MultibyteCodecObject *self) ++multibytecodec_dealloc(PyObject *self) + { + PyObject_GC_UnTrack(self); + PyTypeObject *tp = Py_TYPE(self); +@@ -1106,17 +1129,18 @@ + } + + static int +-mbiencoder_traverse(MultibyteIncrementalEncoderObject *self, +- visitproc visit, void *arg) ++mbiencoder_traverse(PyObject *op, visitproc visit, void *arg) + { ++ MultibyteIncrementalEncoderObject *self = _MultibyteIncrementalEncoderObject_CAST(op); + if (ERROR_ISCUSTOM(self->errors)) + Py_VISIT(self->errors); + return 0; + } + + static void +-mbiencoder_dealloc(MultibyteIncrementalEncoderObject *self) ++mbiencoder_dealloc(PyObject *op) + { ++ MultibyteIncrementalEncoderObject *self = _MultibyteIncrementalEncoderObject_CAST(op); + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + ERROR_DECREF(self->errors); +@@ -1388,17 +1412,18 @@ + } + + static int +-mbidecoder_traverse(MultibyteIncrementalDecoderObject *self, +- visitproc visit, void *arg) ++mbidecoder_traverse(PyObject *op, visitproc visit, void *arg) + { ++ MultibyteIncrementalDecoderObject *self = _MultibyteIncrementalDecoderObject_CAST(op); + if (ERROR_ISCUSTOM(self->errors)) + Py_VISIT(self->errors); + return 0; + } + + static void +-mbidecoder_dealloc(MultibyteIncrementalDecoderObject *self) ++mbidecoder_dealloc(PyObject *op) + { ++ MultibyteIncrementalDecoderObject *self = _MultibyteIncrementalDecoderObject_CAST(op); + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + ERROR_DECREF(self->errors); +@@ -1704,9 +1729,9 @@ + } + + static int +-mbstreamreader_traverse(MultibyteStreamReaderObject *self, +- visitproc visit, void *arg) ++mbstreamreader_traverse(PyObject *op, visitproc visit, void *arg) + { ++ MultibyteStreamReaderObject *self = _MultibyteStreamReaderObject_CAST(op); + if (ERROR_ISCUSTOM(self->errors)) + Py_VISIT(self->errors); + Py_VISIT(self->stream); +@@ -1714,8 +1739,9 @@ + } + + static void +-mbstreamreader_dealloc(MultibyteStreamReaderObject *self) ++mbstreamreader_dealloc(PyObject *op) + { ++ MultibyteStreamReaderObject *self = _MultibyteStreamReaderObject_CAST(op); + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + ERROR_DECREF(self->errors); +@@ -1927,9 +1953,9 @@ + } + + static int +-mbstreamwriter_traverse(MultibyteStreamWriterObject *self, +- visitproc visit, void *arg) ++mbstreamwriter_traverse(PyObject *op, visitproc visit, void *arg) + { ++ MultibyteStreamWriterObject *self = _MultibyteStreamWriterObject_CAST(op); + if (ERROR_ISCUSTOM(self->errors)) + Py_VISIT(self->errors); + Py_VISIT(self->stream); +@@ -1937,8 +1963,9 @@ + } + + static void +-mbstreamwriter_dealloc(MultibyteStreamWriterObject *self) ++mbstreamwriter_dealloc(PyObject *op) + { ++ MultibyteStreamWriterObject *self = _MultibyteStreamWriterObject_CAST(op); + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + ERROR_DECREF(self->errors); +@@ -2044,7 +2071,7 @@ + static void + _multibytecodec_free(void *mod) + { +- _multibytecodec_clear((PyObject *)mod); ++ (void)_multibytecodec_clear((PyObject *)mod); + } + + #define CREATE_TYPE(module, type, spec) \ +diff --git a/Modules/clinic/_asynciomodule.c.h b/Modules/clinic/_asynciomodule.c.h +index 32045804c35..d25411ee995 100644 +--- a/Modules/clinic/_asynciomodule.c.h ++++ b/Modules/clinic/_asynciomodule.c.h +@@ -6,6 +6,7 @@ + # include "pycore_gc.h" // PyGC_Head + # include "pycore_runtime.h" // _Py_ID() + #endif ++#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() + #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() + + PyDoc_STRVAR(_asyncio_Future___init____doc__, +@@ -96,9 +97,15 @@ + _asyncio_Future_result_impl(FutureObj *self); + + static PyObject * +-_asyncio_Future_result(FutureObj *self, PyObject *Py_UNUSED(ignored)) ++_asyncio_Future_result(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _asyncio_Future_result_impl(self); ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Future_result_impl((FutureObj *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; + } + + PyDoc_STRVAR(_asyncio_Future_exception__doc__, +@@ -119,13 +126,20 @@ + _asyncio_Future_exception_impl(FutureObj *self, PyTypeObject *cls); + + static PyObject * +-_asyncio_Future_exception(FutureObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_asyncio_Future_exception(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { ++ PyObject *return_value = NULL; ++ + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "exception() takes no arguments"); +- return NULL; ++ goto exit; + } +- return _asyncio_Future_exception_impl(self, cls); ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Future_exception_impl((FutureObj *)self, cls); ++ Py_END_CRITICAL_SECTION(); ++ ++exit: ++ return return_value; + } + + PyDoc_STRVAR(_asyncio_Future_set_result__doc__, +@@ -145,7 +159,7 @@ + PyObject *result); + + static PyObject * +-_asyncio_Future_set_result(FutureObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_asyncio_Future_set_result(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -170,7 +184,9 @@ + goto exit; + } + result = args[0]; +- return_value = _asyncio_Future_set_result_impl(self, cls, result); ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Future_set_result_impl((FutureObj *)self, cls, result); ++ Py_END_CRITICAL_SECTION(); + + exit: + return return_value; +@@ -193,7 +209,7 @@ + PyObject *exception); + + static PyObject * +-_asyncio_Future_set_exception(FutureObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_asyncio_Future_set_exception(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -218,7 +234,9 @@ + goto exit; + } + exception = args[0]; +- return_value = _asyncio_Future_set_exception_impl(self, cls, exception); ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Future_set_exception_impl((FutureObj *)self, cls, exception); ++ Py_END_CRITICAL_SECTION(); + + exit: + return return_value; +@@ -242,7 +260,7 @@ + PyObject *fn, PyObject *context); + + static PyObject * +-_asyncio_Future_add_done_callback(FutureObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_asyncio_Future_add_done_callback(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -286,7 +304,9 @@ + } + context = args[1]; + skip_optional_kwonly: +- return_value = _asyncio_Future_add_done_callback_impl(self, cls, fn, context); ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Future_add_done_callback_impl((FutureObj *)self, cls, fn, context); ++ Py_END_CRITICAL_SECTION(); + + exit: + return return_value; +@@ -308,7 +328,7 @@ + PyObject *fn); + + static PyObject * +-_asyncio_Future_remove_done_callback(FutureObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_asyncio_Future_remove_done_callback(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -333,7 +353,9 @@ + goto exit; + } + fn = args[0]; +- return_value = _asyncio_Future_remove_done_callback_impl(self, cls, fn); ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Future_remove_done_callback_impl((FutureObj *)self, cls, fn); ++ Py_END_CRITICAL_SECTION(); + + exit: + return return_value; +@@ -357,7 +379,7 @@ + PyObject *msg); + + static PyObject * +-_asyncio_Future_cancel(FutureObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_asyncio_Future_cancel(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -399,7 +421,9 @@ + } + msg = args[0]; + skip_optional_pos: +- return_value = _asyncio_Future_cancel_impl(self, cls, msg); ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Future_cancel_impl((FutureObj *)self, cls, msg); ++ Py_END_CRITICAL_SECTION(); + + exit: + return return_value; +@@ -418,9 +442,15 @@ + _asyncio_Future_cancelled_impl(FutureObj *self); + + static PyObject * +-_asyncio_Future_cancelled(FutureObj *self, PyObject *Py_UNUSED(ignored)) ++_asyncio_Future_cancelled(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _asyncio_Future_cancelled_impl(self); ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Future_cancelled_impl((FutureObj *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; + } + + PyDoc_STRVAR(_asyncio_Future_done__doc__, +@@ -439,9 +469,15 @@ + _asyncio_Future_done_impl(FutureObj *self); + + static PyObject * +-_asyncio_Future_done(FutureObj *self, PyObject *Py_UNUSED(ignored)) ++_asyncio_Future_done(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _asyncio_Future_done_impl(self); ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Future_done_impl((FutureObj *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; + } + + PyDoc_STRVAR(_asyncio_Future_get_loop__doc__, +@@ -457,13 +493,346 @@ + _asyncio_Future_get_loop_impl(FutureObj *self, PyTypeObject *cls); + + static PyObject * +-_asyncio_Future_get_loop(FutureObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_asyncio_Future_get_loop(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { ++ PyObject *return_value = NULL; ++ + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "get_loop() takes no arguments"); +- return NULL; ++ goto exit; + } +- return _asyncio_Future_get_loop_impl(self, cls); ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Future_get_loop_impl((FutureObj *)self, cls); ++ Py_END_CRITICAL_SECTION(); ++ ++exit: ++ return return_value; ++} ++ ++#if !defined(_asyncio_Future__asyncio_awaited_by_DOCSTR) ++# define _asyncio_Future__asyncio_awaited_by_DOCSTR NULL ++#endif ++#if defined(_ASYNCIO_FUTURE__ASYNCIO_AWAITED_BY_GETSETDEF) ++# undef _ASYNCIO_FUTURE__ASYNCIO_AWAITED_BY_GETSETDEF ++# define _ASYNCIO_FUTURE__ASYNCIO_AWAITED_BY_GETSETDEF {"_asyncio_awaited_by", (getter)_asyncio_Future__asyncio_awaited_by_get, (setter)_asyncio_Future__asyncio_awaited_by_set, _asyncio_Future__asyncio_awaited_by_DOCSTR}, ++#else ++# define _ASYNCIO_FUTURE__ASYNCIO_AWAITED_BY_GETSETDEF {"_asyncio_awaited_by", (getter)_asyncio_Future__asyncio_awaited_by_get, NULL, _asyncio_Future__asyncio_awaited_by_DOCSTR}, ++#endif ++ ++static PyObject * ++_asyncio_Future__asyncio_awaited_by_get_impl(FutureObj *self); ++ ++static PyObject * ++_asyncio_Future__asyncio_awaited_by_get(PyObject *self, void *Py_UNUSED(context)) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Future__asyncio_awaited_by_get_impl((FutureObj *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(_asyncio_Future__asyncio_future_blocking_DOCSTR) ++# define _asyncio_Future__asyncio_future_blocking_DOCSTR NULL ++#endif ++#if defined(_ASYNCIO_FUTURE__ASYNCIO_FUTURE_BLOCKING_GETSETDEF) ++# undef _ASYNCIO_FUTURE__ASYNCIO_FUTURE_BLOCKING_GETSETDEF ++# define _ASYNCIO_FUTURE__ASYNCIO_FUTURE_BLOCKING_GETSETDEF {"_asyncio_future_blocking", (getter)_asyncio_Future__asyncio_future_blocking_get, (setter)_asyncio_Future__asyncio_future_blocking_set, _asyncio_Future__asyncio_future_blocking_DOCSTR}, ++#else ++# define _ASYNCIO_FUTURE__ASYNCIO_FUTURE_BLOCKING_GETSETDEF {"_asyncio_future_blocking", (getter)_asyncio_Future__asyncio_future_blocking_get, NULL, _asyncio_Future__asyncio_future_blocking_DOCSTR}, ++#endif ++ ++static PyObject * ++_asyncio_Future__asyncio_future_blocking_get_impl(FutureObj *self); ++ ++static PyObject * ++_asyncio_Future__asyncio_future_blocking_get(PyObject *self, void *Py_UNUSED(context)) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Future__asyncio_future_blocking_get_impl((FutureObj *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(_asyncio_Future__asyncio_future_blocking_DOCSTR) ++# define _asyncio_Future__asyncio_future_blocking_DOCSTR NULL ++#endif ++#if defined(_ASYNCIO_FUTURE__ASYNCIO_FUTURE_BLOCKING_GETSETDEF) ++# undef _ASYNCIO_FUTURE__ASYNCIO_FUTURE_BLOCKING_GETSETDEF ++# define _ASYNCIO_FUTURE__ASYNCIO_FUTURE_BLOCKING_GETSETDEF {"_asyncio_future_blocking", (getter)_asyncio_Future__asyncio_future_blocking_get, (setter)_asyncio_Future__asyncio_future_blocking_set, _asyncio_Future__asyncio_future_blocking_DOCSTR}, ++#else ++# define _ASYNCIO_FUTURE__ASYNCIO_FUTURE_BLOCKING_GETSETDEF {"_asyncio_future_blocking", NULL, (setter)_asyncio_Future__asyncio_future_blocking_set, NULL}, ++#endif ++ ++static int ++_asyncio_Future__asyncio_future_blocking_set_impl(FutureObj *self, ++ PyObject *value); ++ ++static int ++_asyncio_Future__asyncio_future_blocking_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) ++{ ++ int return_value; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Future__asyncio_future_blocking_set_impl((FutureObj *)self, value); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(_asyncio_Future__log_traceback_DOCSTR) ++# define _asyncio_Future__log_traceback_DOCSTR NULL ++#endif ++#if defined(_ASYNCIO_FUTURE__LOG_TRACEBACK_GETSETDEF) ++# undef _ASYNCIO_FUTURE__LOG_TRACEBACK_GETSETDEF ++# define _ASYNCIO_FUTURE__LOG_TRACEBACK_GETSETDEF {"_log_traceback", (getter)_asyncio_Future__log_traceback_get, (setter)_asyncio_Future__log_traceback_set, _asyncio_Future__log_traceback_DOCSTR}, ++#else ++# define _ASYNCIO_FUTURE__LOG_TRACEBACK_GETSETDEF {"_log_traceback", (getter)_asyncio_Future__log_traceback_get, NULL, _asyncio_Future__log_traceback_DOCSTR}, ++#endif ++ ++static PyObject * ++_asyncio_Future__log_traceback_get_impl(FutureObj *self); ++ ++static PyObject * ++_asyncio_Future__log_traceback_get(PyObject *self, void *Py_UNUSED(context)) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Future__log_traceback_get_impl((FutureObj *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(_asyncio_Future__log_traceback_DOCSTR) ++# define _asyncio_Future__log_traceback_DOCSTR NULL ++#endif ++#if defined(_ASYNCIO_FUTURE__LOG_TRACEBACK_GETSETDEF) ++# undef _ASYNCIO_FUTURE__LOG_TRACEBACK_GETSETDEF ++# define _ASYNCIO_FUTURE__LOG_TRACEBACK_GETSETDEF {"_log_traceback", (getter)_asyncio_Future__log_traceback_get, (setter)_asyncio_Future__log_traceback_set, _asyncio_Future__log_traceback_DOCSTR}, ++#else ++# define _ASYNCIO_FUTURE__LOG_TRACEBACK_GETSETDEF {"_log_traceback", NULL, (setter)_asyncio_Future__log_traceback_set, NULL}, ++#endif ++ ++static int ++_asyncio_Future__log_traceback_set_impl(FutureObj *self, PyObject *value); ++ ++static int ++_asyncio_Future__log_traceback_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) ++{ ++ int return_value; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Future__log_traceback_set_impl((FutureObj *)self, value); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(_asyncio_Future__loop_DOCSTR) ++# define _asyncio_Future__loop_DOCSTR NULL ++#endif ++#if defined(_ASYNCIO_FUTURE__LOOP_GETSETDEF) ++# undef _ASYNCIO_FUTURE__LOOP_GETSETDEF ++# define _ASYNCIO_FUTURE__LOOP_GETSETDEF {"_loop", (getter)_asyncio_Future__loop_get, (setter)_asyncio_Future__loop_set, _asyncio_Future__loop_DOCSTR}, ++#else ++# define _ASYNCIO_FUTURE__LOOP_GETSETDEF {"_loop", (getter)_asyncio_Future__loop_get, NULL, _asyncio_Future__loop_DOCSTR}, ++#endif ++ ++static PyObject * ++_asyncio_Future__loop_get_impl(FutureObj *self); ++ ++static PyObject * ++_asyncio_Future__loop_get(PyObject *self, void *Py_UNUSED(context)) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Future__loop_get_impl((FutureObj *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(_asyncio_Future__callbacks_DOCSTR) ++# define _asyncio_Future__callbacks_DOCSTR NULL ++#endif ++#if defined(_ASYNCIO_FUTURE__CALLBACKS_GETSETDEF) ++# undef _ASYNCIO_FUTURE__CALLBACKS_GETSETDEF ++# define _ASYNCIO_FUTURE__CALLBACKS_GETSETDEF {"_callbacks", (getter)_asyncio_Future__callbacks_get, (setter)_asyncio_Future__callbacks_set, _asyncio_Future__callbacks_DOCSTR}, ++#else ++# define _ASYNCIO_FUTURE__CALLBACKS_GETSETDEF {"_callbacks", (getter)_asyncio_Future__callbacks_get, NULL, _asyncio_Future__callbacks_DOCSTR}, ++#endif ++ ++static PyObject * ++_asyncio_Future__callbacks_get_impl(FutureObj *self); ++ ++static PyObject * ++_asyncio_Future__callbacks_get(PyObject *self, void *Py_UNUSED(context)) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Future__callbacks_get_impl((FutureObj *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(_asyncio_Future__result_DOCSTR) ++# define _asyncio_Future__result_DOCSTR NULL ++#endif ++#if defined(_ASYNCIO_FUTURE__RESULT_GETSETDEF) ++# undef _ASYNCIO_FUTURE__RESULT_GETSETDEF ++# define _ASYNCIO_FUTURE__RESULT_GETSETDEF {"_result", (getter)_asyncio_Future__result_get, (setter)_asyncio_Future__result_set, _asyncio_Future__result_DOCSTR}, ++#else ++# define _ASYNCIO_FUTURE__RESULT_GETSETDEF {"_result", (getter)_asyncio_Future__result_get, NULL, _asyncio_Future__result_DOCSTR}, ++#endif ++ ++static PyObject * ++_asyncio_Future__result_get_impl(FutureObj *self); ++ ++static PyObject * ++_asyncio_Future__result_get(PyObject *self, void *Py_UNUSED(context)) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Future__result_get_impl((FutureObj *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(_asyncio_Future__exception_DOCSTR) ++# define _asyncio_Future__exception_DOCSTR NULL ++#endif ++#if defined(_ASYNCIO_FUTURE__EXCEPTION_GETSETDEF) ++# undef _ASYNCIO_FUTURE__EXCEPTION_GETSETDEF ++# define _ASYNCIO_FUTURE__EXCEPTION_GETSETDEF {"_exception", (getter)_asyncio_Future__exception_get, (setter)_asyncio_Future__exception_set, _asyncio_Future__exception_DOCSTR}, ++#else ++# define _ASYNCIO_FUTURE__EXCEPTION_GETSETDEF {"_exception", (getter)_asyncio_Future__exception_get, NULL, _asyncio_Future__exception_DOCSTR}, ++#endif ++ ++static PyObject * ++_asyncio_Future__exception_get_impl(FutureObj *self); ++ ++static PyObject * ++_asyncio_Future__exception_get(PyObject *self, void *Py_UNUSED(context)) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Future__exception_get_impl((FutureObj *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(_asyncio_Future__source_traceback_DOCSTR) ++# define _asyncio_Future__source_traceback_DOCSTR NULL ++#endif ++#if defined(_ASYNCIO_FUTURE__SOURCE_TRACEBACK_GETSETDEF) ++# undef _ASYNCIO_FUTURE__SOURCE_TRACEBACK_GETSETDEF ++# define _ASYNCIO_FUTURE__SOURCE_TRACEBACK_GETSETDEF {"_source_traceback", (getter)_asyncio_Future__source_traceback_get, (setter)_asyncio_Future__source_traceback_set, _asyncio_Future__source_traceback_DOCSTR}, ++#else ++# define _ASYNCIO_FUTURE__SOURCE_TRACEBACK_GETSETDEF {"_source_traceback", (getter)_asyncio_Future__source_traceback_get, NULL, _asyncio_Future__source_traceback_DOCSTR}, ++#endif ++ ++static PyObject * ++_asyncio_Future__source_traceback_get_impl(FutureObj *self); ++ ++static PyObject * ++_asyncio_Future__source_traceback_get(PyObject *self, void *Py_UNUSED(context)) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Future__source_traceback_get_impl((FutureObj *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(_asyncio_Future__cancel_message_DOCSTR) ++# define _asyncio_Future__cancel_message_DOCSTR NULL ++#endif ++#if defined(_ASYNCIO_FUTURE__CANCEL_MESSAGE_GETSETDEF) ++# undef _ASYNCIO_FUTURE__CANCEL_MESSAGE_GETSETDEF ++# define _ASYNCIO_FUTURE__CANCEL_MESSAGE_GETSETDEF {"_cancel_message", (getter)_asyncio_Future__cancel_message_get, (setter)_asyncio_Future__cancel_message_set, _asyncio_Future__cancel_message_DOCSTR}, ++#else ++# define _ASYNCIO_FUTURE__CANCEL_MESSAGE_GETSETDEF {"_cancel_message", (getter)_asyncio_Future__cancel_message_get, NULL, _asyncio_Future__cancel_message_DOCSTR}, ++#endif ++ ++static PyObject * ++_asyncio_Future__cancel_message_get_impl(FutureObj *self); ++ ++static PyObject * ++_asyncio_Future__cancel_message_get(PyObject *self, void *Py_UNUSED(context)) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Future__cancel_message_get_impl((FutureObj *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(_asyncio_Future__cancel_message_DOCSTR) ++# define _asyncio_Future__cancel_message_DOCSTR NULL ++#endif ++#if defined(_ASYNCIO_FUTURE__CANCEL_MESSAGE_GETSETDEF) ++# undef _ASYNCIO_FUTURE__CANCEL_MESSAGE_GETSETDEF ++# define _ASYNCIO_FUTURE__CANCEL_MESSAGE_GETSETDEF {"_cancel_message", (getter)_asyncio_Future__cancel_message_get, (setter)_asyncio_Future__cancel_message_set, _asyncio_Future__cancel_message_DOCSTR}, ++#else ++# define _ASYNCIO_FUTURE__CANCEL_MESSAGE_GETSETDEF {"_cancel_message", NULL, (setter)_asyncio_Future__cancel_message_set, NULL}, ++#endif ++ ++static int ++_asyncio_Future__cancel_message_set_impl(FutureObj *self, PyObject *value); ++ ++static int ++_asyncio_Future__cancel_message_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) ++{ ++ int return_value; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Future__cancel_message_set_impl((FutureObj *)self, value); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(_asyncio_Future__state_DOCSTR) ++# define _asyncio_Future__state_DOCSTR NULL ++#endif ++#if defined(_ASYNCIO_FUTURE__STATE_GETSETDEF) ++# undef _ASYNCIO_FUTURE__STATE_GETSETDEF ++# define _ASYNCIO_FUTURE__STATE_GETSETDEF {"_state", (getter)_asyncio_Future__state_get, (setter)_asyncio_Future__state_set, _asyncio_Future__state_DOCSTR}, ++#else ++# define _ASYNCIO_FUTURE__STATE_GETSETDEF {"_state", (getter)_asyncio_Future__state_get, NULL, _asyncio_Future__state_DOCSTR}, ++#endif ++ ++static PyObject * ++_asyncio_Future__state_get_impl(FutureObj *self); ++ ++static PyObject * ++_asyncio_Future__state_get(PyObject *self, void *Py_UNUSED(context)) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Future__state_get_impl((FutureObj *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; + } + + PyDoc_STRVAR(_asyncio_Future__make_cancelled_error__doc__, +@@ -482,9 +851,15 @@ + _asyncio_Future__make_cancelled_error_impl(FutureObj *self); + + static PyObject * +-_asyncio_Future__make_cancelled_error(FutureObj *self, PyObject *Py_UNUSED(ignored)) ++_asyncio_Future__make_cancelled_error(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _asyncio_Future__make_cancelled_error_impl(self); ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Future__make_cancelled_error_impl((FutureObj *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; + } + + PyDoc_STRVAR(_asyncio_Task___init____doc__, +@@ -575,6 +950,131 @@ + return return_value; + } + ++#if !defined(_asyncio_Task__log_destroy_pending_DOCSTR) ++# define _asyncio_Task__log_destroy_pending_DOCSTR NULL ++#endif ++#if defined(_ASYNCIO_TASK__LOG_DESTROY_PENDING_GETSETDEF) ++# undef _ASYNCIO_TASK__LOG_DESTROY_PENDING_GETSETDEF ++# define _ASYNCIO_TASK__LOG_DESTROY_PENDING_GETSETDEF {"_log_destroy_pending", (getter)_asyncio_Task__log_destroy_pending_get, (setter)_asyncio_Task__log_destroy_pending_set, _asyncio_Task__log_destroy_pending_DOCSTR}, ++#else ++# define _ASYNCIO_TASK__LOG_DESTROY_PENDING_GETSETDEF {"_log_destroy_pending", (getter)_asyncio_Task__log_destroy_pending_get, NULL, _asyncio_Task__log_destroy_pending_DOCSTR}, ++#endif ++ ++static PyObject * ++_asyncio_Task__log_destroy_pending_get_impl(TaskObj *self); ++ ++static PyObject * ++_asyncio_Task__log_destroy_pending_get(PyObject *self, void *Py_UNUSED(context)) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Task__log_destroy_pending_get_impl((TaskObj *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(_asyncio_Task__log_destroy_pending_DOCSTR) ++# define _asyncio_Task__log_destroy_pending_DOCSTR NULL ++#endif ++#if defined(_ASYNCIO_TASK__LOG_DESTROY_PENDING_GETSETDEF) ++# undef _ASYNCIO_TASK__LOG_DESTROY_PENDING_GETSETDEF ++# define _ASYNCIO_TASK__LOG_DESTROY_PENDING_GETSETDEF {"_log_destroy_pending", (getter)_asyncio_Task__log_destroy_pending_get, (setter)_asyncio_Task__log_destroy_pending_set, _asyncio_Task__log_destroy_pending_DOCSTR}, ++#else ++# define _ASYNCIO_TASK__LOG_DESTROY_PENDING_GETSETDEF {"_log_destroy_pending", NULL, (setter)_asyncio_Task__log_destroy_pending_set, NULL}, ++#endif ++ ++static int ++_asyncio_Task__log_destroy_pending_set_impl(TaskObj *self, PyObject *value); ++ ++static int ++_asyncio_Task__log_destroy_pending_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) ++{ ++ int return_value; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Task__log_destroy_pending_set_impl((TaskObj *)self, value); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(_asyncio_Task__must_cancel_DOCSTR) ++# define _asyncio_Task__must_cancel_DOCSTR NULL ++#endif ++#if defined(_ASYNCIO_TASK__MUST_CANCEL_GETSETDEF) ++# undef _ASYNCIO_TASK__MUST_CANCEL_GETSETDEF ++# define _ASYNCIO_TASK__MUST_CANCEL_GETSETDEF {"_must_cancel", (getter)_asyncio_Task__must_cancel_get, (setter)_asyncio_Task__must_cancel_set, _asyncio_Task__must_cancel_DOCSTR}, ++#else ++# define _ASYNCIO_TASK__MUST_CANCEL_GETSETDEF {"_must_cancel", (getter)_asyncio_Task__must_cancel_get, NULL, _asyncio_Task__must_cancel_DOCSTR}, ++#endif ++ ++static PyObject * ++_asyncio_Task__must_cancel_get_impl(TaskObj *self); ++ ++static PyObject * ++_asyncio_Task__must_cancel_get(PyObject *self, void *Py_UNUSED(context)) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Task__must_cancel_get_impl((TaskObj *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(_asyncio_Task__coro_DOCSTR) ++# define _asyncio_Task__coro_DOCSTR NULL ++#endif ++#if defined(_ASYNCIO_TASK__CORO_GETSETDEF) ++# undef _ASYNCIO_TASK__CORO_GETSETDEF ++# define _ASYNCIO_TASK__CORO_GETSETDEF {"_coro", (getter)_asyncio_Task__coro_get, (setter)_asyncio_Task__coro_set, _asyncio_Task__coro_DOCSTR}, ++#else ++# define _ASYNCIO_TASK__CORO_GETSETDEF {"_coro", (getter)_asyncio_Task__coro_get, NULL, _asyncio_Task__coro_DOCSTR}, ++#endif ++ ++static PyObject * ++_asyncio_Task__coro_get_impl(TaskObj *self); ++ ++static PyObject * ++_asyncio_Task__coro_get(PyObject *self, void *Py_UNUSED(context)) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Task__coro_get_impl((TaskObj *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(_asyncio_Task__fut_waiter_DOCSTR) ++# define _asyncio_Task__fut_waiter_DOCSTR NULL ++#endif ++#if defined(_ASYNCIO_TASK__FUT_WAITER_GETSETDEF) ++# undef _ASYNCIO_TASK__FUT_WAITER_GETSETDEF ++# define _ASYNCIO_TASK__FUT_WAITER_GETSETDEF {"_fut_waiter", (getter)_asyncio_Task__fut_waiter_get, (setter)_asyncio_Task__fut_waiter_set, _asyncio_Task__fut_waiter_DOCSTR}, ++#else ++# define _ASYNCIO_TASK__FUT_WAITER_GETSETDEF {"_fut_waiter", (getter)_asyncio_Task__fut_waiter_get, NULL, _asyncio_Task__fut_waiter_DOCSTR}, ++#endif ++ ++static PyObject * ++_asyncio_Task__fut_waiter_get_impl(TaskObj *self); ++ ++static PyObject * ++_asyncio_Task__fut_waiter_get(PyObject *self, void *Py_UNUSED(context)) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Task__fut_waiter_get_impl((TaskObj *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ + PyDoc_STRVAR(_asyncio_Task__make_cancelled_error__doc__, + "_make_cancelled_error($self, /)\n" + "--\n" +@@ -591,9 +1091,15 @@ + _asyncio_Task__make_cancelled_error_impl(TaskObj *self); + + static PyObject * +-_asyncio_Task__make_cancelled_error(TaskObj *self, PyObject *Py_UNUSED(ignored)) ++_asyncio_Task__make_cancelled_error(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _asyncio_Task__make_cancelled_error_impl(self); ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Task__make_cancelled_error_impl((TaskObj *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; + } + + PyDoc_STRVAR(_asyncio_Task_cancel__doc__, +@@ -628,7 +1134,7 @@ + _asyncio_Task_cancel_impl(TaskObj *self, PyObject *msg); + + static PyObject * +-_asyncio_Task_cancel(TaskObj *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_asyncio_Task_cancel(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -670,7 +1176,9 @@ + } + msg = args[0]; + skip_optional_pos: +- return_value = _asyncio_Task_cancel_impl(self, msg); ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Task_cancel_impl((TaskObj *)self, msg); ++ Py_END_CRITICAL_SECTION(); + + exit: + return return_value; +@@ -692,9 +1200,15 @@ + _asyncio_Task_cancelling_impl(TaskObj *self); + + static PyObject * +-_asyncio_Task_cancelling(TaskObj *self, PyObject *Py_UNUSED(ignored)) ++_asyncio_Task_cancelling(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _asyncio_Task_cancelling_impl(self); ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Task_cancelling_impl((TaskObj *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; + } + + PyDoc_STRVAR(_asyncio_Task_uncancel__doc__, +@@ -715,9 +1229,15 @@ + _asyncio_Task_uncancel_impl(TaskObj *self); + + static PyObject * +-_asyncio_Task_uncancel(TaskObj *self, PyObject *Py_UNUSED(ignored)) ++_asyncio_Task_uncancel(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _asyncio_Task_uncancel_impl(self); ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Task_uncancel_impl((TaskObj *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; + } + + PyDoc_STRVAR(_asyncio_Task_get_stack__doc__, +@@ -752,7 +1272,7 @@ + PyObject *limit); + + static PyObject * +-_asyncio_Task_get_stack(TaskObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_asyncio_Task_get_stack(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -794,7 +1314,7 @@ + } + limit = args[0]; + skip_optional_kwonly: +- return_value = _asyncio_Task_get_stack_impl(self, cls, limit); ++ return_value = _asyncio_Task_get_stack_impl((TaskObj *)self, cls, limit); + + exit: + return return_value; +@@ -820,7 +1340,7 @@ + PyObject *limit, PyObject *file); + + static PyObject * +-_asyncio_Task_print_stack(TaskObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_asyncio_Task_print_stack(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -869,7 +1389,7 @@ + } + file = args[1]; + skip_optional_kwonly: +- return_value = _asyncio_Task_print_stack_impl(self, cls, limit, file); ++ return_value = _asyncio_Task_print_stack_impl((TaskObj *)self, cls, limit, file); + + exit: + return return_value; +@@ -903,9 +1423,15 @@ + _asyncio_Task_get_coro_impl(TaskObj *self); + + static PyObject * +-_asyncio_Task_get_coro(TaskObj *self, PyObject *Py_UNUSED(ignored)) ++_asyncio_Task_get_coro(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _asyncio_Task_get_coro_impl(self); ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Task_get_coro_impl((TaskObj *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; + } + + PyDoc_STRVAR(_asyncio_Task_get_context__doc__, +@@ -920,9 +1446,9 @@ + _asyncio_Task_get_context_impl(TaskObj *self); + + static PyObject * +-_asyncio_Task_get_context(TaskObj *self, PyObject *Py_UNUSED(ignored)) ++_asyncio_Task_get_context(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _asyncio_Task_get_context_impl(self); ++ return _asyncio_Task_get_context_impl((TaskObj *)self); + } + + PyDoc_STRVAR(_asyncio_Task_get_name__doc__, +@@ -937,9 +1463,15 @@ + _asyncio_Task_get_name_impl(TaskObj *self); + + static PyObject * +-_asyncio_Task_get_name(TaskObj *self, PyObject *Py_UNUSED(ignored)) ++_asyncio_Task_get_name(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _asyncio_Task_get_name_impl(self); ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Task_get_name_impl((TaskObj *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; + } + + PyDoc_STRVAR(_asyncio_Task_set_name__doc__, +@@ -950,6 +1482,21 @@ + #define _ASYNCIO_TASK_SET_NAME_METHODDEF \ + {"set_name", (PyCFunction)_asyncio_Task_set_name, METH_O, _asyncio_Task_set_name__doc__}, + ++static PyObject * ++_asyncio_Task_set_name_impl(TaskObj *self, PyObject *value); ++ ++static PyObject * ++_asyncio_Task_set_name(TaskObj *self, PyObject *value) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = _asyncio_Task_set_name_impl((TaskObj *)self, value); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ + PyDoc_STRVAR(_asyncio__get_running_loop__doc__, + "_get_running_loop($module, /)\n" + "--\n" +@@ -1566,4 +2113,65 @@ + exit: + return return_value; + } +-/*[clinic end generated code: output=e5d95a0ec229ffcd input=a9049054013a1b77]*/ ++ ++PyDoc_STRVAR(_asyncio_future_add_to_awaited_by__doc__, ++"future_add_to_awaited_by($module, fut, waiter, /)\n" ++"--\n" ++"\n" ++"Record that `fut` is awaited on by `waiter`."); ++ ++#define _ASYNCIO_FUTURE_ADD_TO_AWAITED_BY_METHODDEF \ ++ {"future_add_to_awaited_by", _PyCFunction_CAST(_asyncio_future_add_to_awaited_by), METH_FASTCALL, _asyncio_future_add_to_awaited_by__doc__}, ++ ++static PyObject * ++_asyncio_future_add_to_awaited_by_impl(PyObject *module, PyObject *fut, ++ PyObject *waiter); ++ ++static PyObject * ++_asyncio_future_add_to_awaited_by(PyObject *module, PyObject *const *args, Py_ssize_t nargs) ++{ ++ PyObject *return_value = NULL; ++ PyObject *fut; ++ PyObject *waiter; ++ ++ if (!_PyArg_CheckPositional("future_add_to_awaited_by", nargs, 2, 2)) { ++ goto exit; ++ } ++ fut = args[0]; ++ waiter = args[1]; ++ return_value = _asyncio_future_add_to_awaited_by_impl(module, fut, waiter); ++ ++exit: ++ return return_value; ++} ++ ++PyDoc_STRVAR(_asyncio_future_discard_from_awaited_by__doc__, ++"future_discard_from_awaited_by($module, fut, waiter, /)\n" ++"--\n" ++"\n"); ++ ++#define _ASYNCIO_FUTURE_DISCARD_FROM_AWAITED_BY_METHODDEF \ ++ {"future_discard_from_awaited_by", _PyCFunction_CAST(_asyncio_future_discard_from_awaited_by), METH_FASTCALL, _asyncio_future_discard_from_awaited_by__doc__}, ++ ++static PyObject * ++_asyncio_future_discard_from_awaited_by_impl(PyObject *module, PyObject *fut, ++ PyObject *waiter); ++ ++static PyObject * ++_asyncio_future_discard_from_awaited_by(PyObject *module, PyObject *const *args, Py_ssize_t nargs) ++{ ++ PyObject *return_value = NULL; ++ PyObject *fut; ++ PyObject *waiter; ++ ++ if (!_PyArg_CheckPositional("future_discard_from_awaited_by", nargs, 2, 2)) { ++ goto exit; ++ } ++ fut = args[0]; ++ waiter = args[1]; ++ return_value = _asyncio_future_discard_from_awaited_by_impl(module, fut, waiter); ++ ++exit: ++ return return_value; ++} ++/*[clinic end generated code: output=f14ff14c29c691ec input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/_bz2module.c.h b/Modules/clinic/_bz2module.c.h +index 93988bf48a1..a599bd1a8be 100644 +--- a/Modules/clinic/_bz2module.c.h ++++ b/Modules/clinic/_bz2module.c.h +@@ -27,7 +27,7 @@ + _bz2_BZ2Compressor_compress_impl(BZ2Compressor *self, Py_buffer *data); + + static PyObject * +-_bz2_BZ2Compressor_compress(BZ2Compressor *self, PyObject *arg) ++_bz2_BZ2Compressor_compress(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; +@@ -35,7 +35,7 @@ + if (PyObject_GetBuffer(arg, &data, PyBUF_SIMPLE) != 0) { + goto exit; + } +- return_value = _bz2_BZ2Compressor_compress_impl(self, &data); ++ return_value = _bz2_BZ2Compressor_compress_impl((BZ2Compressor *)self, &data); + + exit: + /* Cleanup for data */ +@@ -63,9 +63,9 @@ + _bz2_BZ2Compressor_flush_impl(BZ2Compressor *self); + + static PyObject * +-_bz2_BZ2Compressor_flush(BZ2Compressor *self, PyObject *Py_UNUSED(ignored)) ++_bz2_BZ2Compressor_flush(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _bz2_BZ2Compressor_flush_impl(self); ++ return _bz2_BZ2Compressor_flush_impl((BZ2Compressor *)self); + } + + PyDoc_STRVAR(_bz2_BZ2Compressor__doc__, +@@ -137,7 +137,7 @@ + Py_ssize_t max_length); + + static PyObject * +-_bz2_BZ2Decompressor_decompress(BZ2Decompressor *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_bz2_BZ2Decompressor_decompress(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -194,7 +194,7 @@ + max_length = ival; + } + skip_optional_pos: +- return_value = _bz2_BZ2Decompressor_decompress_impl(self, &data, max_length); ++ return_value = _bz2_BZ2Decompressor_decompress_impl((BZ2Decompressor *)self, &data, max_length); + + exit: + /* Cleanup for data */ +@@ -235,4 +235,4 @@ + exit: + return return_value; + } +-/*[clinic end generated code: output=701a383434374c36 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=0fc5a6292c5fd2c5 input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/_collectionsmodule.c.h b/Modules/clinic/_collectionsmodule.c.h +index b4e3325e895..ddf18c2c77a 100644 +--- a/Modules/clinic/_collectionsmodule.c.h ++++ b/Modules/clinic/_collectionsmodule.c.h +@@ -23,12 +23,12 @@ + deque_pop_impl(dequeobject *deque); + + static PyObject * +-deque_pop(dequeobject *deque, PyObject *Py_UNUSED(ignored)) ++deque_pop(PyObject *deque, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(deque); +- return_value = deque_pop_impl(deque); ++ return_value = deque_pop_impl((dequeobject *)deque); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -47,12 +47,12 @@ + deque_popleft_impl(dequeobject *deque); + + static PyObject * +-deque_popleft(dequeobject *deque, PyObject *Py_UNUSED(ignored)) ++deque_popleft(PyObject *deque, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(deque); +- return_value = deque_popleft_impl(deque); ++ return_value = deque_popleft_impl((dequeobject *)deque); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -76,7 +76,7 @@ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(deque); +- return_value = deque_append_impl(deque, item); ++ return_value = deque_append_impl((dequeobject *)deque, item); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -100,7 +100,7 @@ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(deque); +- return_value = deque_appendleft_impl(deque, item); ++ return_value = deque_appendleft_impl((dequeobject *)deque, item); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -124,7 +124,7 @@ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(deque); +- return_value = deque_extend_impl(deque, iterable); ++ return_value = deque_extend_impl((dequeobject *)deque, iterable); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -148,7 +148,7 @@ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(deque); +- return_value = deque_extendleft_impl(deque, iterable); ++ return_value = deque_extendleft_impl((dequeobject *)deque, iterable); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -167,12 +167,12 @@ + deque_copy_impl(dequeobject *deque); + + static PyObject * +-deque_copy(dequeobject *deque, PyObject *Py_UNUSED(ignored)) ++deque_copy(PyObject *deque, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(deque); +- return_value = deque_copy_impl(deque); ++ return_value = deque_copy_impl((dequeobject *)deque); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -191,12 +191,12 @@ + deque___copy___impl(dequeobject *deque); + + static PyObject * +-deque___copy__(dequeobject *deque, PyObject *Py_UNUSED(ignored)) ++deque___copy__(PyObject *deque, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(deque); +- return_value = deque___copy___impl(deque); ++ return_value = deque___copy___impl((dequeobject *)deque); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -215,12 +215,12 @@ + deque_clearmethod_impl(dequeobject *deque); + + static PyObject * +-deque_clearmethod(dequeobject *deque, PyObject *Py_UNUSED(ignored)) ++deque_clearmethod(PyObject *deque, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(deque); +- return_value = deque_clearmethod_impl(deque); ++ return_value = deque_clearmethod_impl((dequeobject *)deque); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -239,7 +239,7 @@ + deque_rotate_impl(dequeobject *deque, Py_ssize_t n); + + static PyObject * +-deque_rotate(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) ++deque_rotate(PyObject *deque, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + Py_ssize_t n = 1; +@@ -264,7 +264,7 @@ + } + skip_optional: + Py_BEGIN_CRITICAL_SECTION(deque); +- return_value = deque_rotate_impl(deque, n); ++ return_value = deque_rotate_impl((dequeobject *)deque, n); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -284,12 +284,12 @@ + deque_reverse_impl(dequeobject *deque); + + static PyObject * +-deque_reverse(dequeobject *deque, PyObject *Py_UNUSED(ignored)) ++deque_reverse(PyObject *deque, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(deque); +- return_value = deque_reverse_impl(deque); ++ return_value = deque_reverse_impl((dequeobject *)deque); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -313,7 +313,7 @@ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(deque); +- return_value = deque_count_impl(deque, v); ++ return_value = deque_count_impl((dequeobject *)deque, v); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -335,7 +335,7 @@ + Py_ssize_t stop); + + static PyObject * +-deque_index(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) ++deque_index(PyObject *deque, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *v; +@@ -360,7 +360,7 @@ + } + skip_optional: + Py_BEGIN_CRITICAL_SECTION(deque); +- return_value = deque_index_impl(deque, v, start, stop); ++ return_value = deque_index_impl((dequeobject *)deque, v, start, stop); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -380,7 +380,7 @@ + deque_insert_impl(dequeobject *deque, Py_ssize_t index, PyObject *value); + + static PyObject * +-deque_insert(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) ++deque_insert(PyObject *deque, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + Py_ssize_t index; +@@ -403,7 +403,7 @@ + } + value = args[1]; + Py_BEGIN_CRITICAL_SECTION(deque); +- return_value = deque_insert_impl(deque, index, value); ++ return_value = deque_insert_impl((dequeobject *)deque, index, value); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -428,7 +428,7 @@ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(deque); +- return_value = deque_remove_impl(deque, value); ++ return_value = deque_remove_impl((dequeobject *)deque, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -447,9 +447,9 @@ + deque___reduce___impl(dequeobject *deque); + + static PyObject * +-deque___reduce__(dequeobject *deque, PyObject *Py_UNUSED(ignored)) ++deque___reduce__(PyObject *deque, PyObject *Py_UNUSED(ignored)) + { +- return deque___reduce___impl(deque); ++ return deque___reduce___impl((dequeobject *)deque); + } + + PyDoc_STRVAR(deque_init__doc__, +@@ -534,12 +534,12 @@ + deque___sizeof___impl(dequeobject *deque); + + static PyObject * +-deque___sizeof__(dequeobject *deque, PyObject *Py_UNUSED(ignored)) ++deque___sizeof__(PyObject *deque, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(deque); +- return_value = deque___sizeof___impl(deque); ++ return_value = deque___sizeof___impl((dequeobject *)deque); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -558,9 +558,9 @@ + deque___reversed___impl(dequeobject *deque); + + static PyObject * +-deque___reversed__(dequeobject *deque, PyObject *Py_UNUSED(ignored)) ++deque___reversed__(PyObject *deque, PyObject *Py_UNUSED(ignored)) + { +- return deque___reversed___impl(deque); ++ return deque___reversed___impl((dequeobject *)deque); + } + + PyDoc_STRVAR(_collections__count_elements__doc__, +@@ -630,4 +630,4 @@ + exit: + return return_value; + } +-/*[clinic end generated code: output=65f896fb13902f6d input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=2d89c39288fc7389 input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/_curses_panel.c.h b/Modules/clinic/_curses_panel.c.h +index b6bff5274a3..6f4966825ec 100644 +--- a/Modules/clinic/_curses_panel.c.h ++++ b/Modules/clinic/_curses_panel.c.h +@@ -20,13 +20,13 @@ + _curses_panel_panel_bottom_impl(PyCursesPanelObject *self, PyTypeObject *cls); + + static PyObject * +-_curses_panel_panel_bottom(PyCursesPanelObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_curses_panel_panel_bottom(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "bottom() takes no arguments"); + return NULL; + } +- return _curses_panel_panel_bottom_impl(self, cls); ++ return _curses_panel_panel_bottom_impl((PyCursesPanelObject *)self, cls); + } + + PyDoc_STRVAR(_curses_panel_panel_hide__doc__, +@@ -44,13 +44,13 @@ + _curses_panel_panel_hide_impl(PyCursesPanelObject *self, PyTypeObject *cls); + + static PyObject * +-_curses_panel_panel_hide(PyCursesPanelObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_curses_panel_panel_hide(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "hide() takes no arguments"); + return NULL; + } +- return _curses_panel_panel_hide_impl(self, cls); ++ return _curses_panel_panel_hide_impl((PyCursesPanelObject *)self, cls); + } + + PyDoc_STRVAR(_curses_panel_panel_show__doc__, +@@ -66,13 +66,13 @@ + _curses_panel_panel_show_impl(PyCursesPanelObject *self, PyTypeObject *cls); + + static PyObject * +-_curses_panel_panel_show(PyCursesPanelObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_curses_panel_panel_show(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "show() takes no arguments"); + return NULL; + } +- return _curses_panel_panel_show_impl(self, cls); ++ return _curses_panel_panel_show_impl((PyCursesPanelObject *)self, cls); + } + + PyDoc_STRVAR(_curses_panel_panel_top__doc__, +@@ -88,13 +88,13 @@ + _curses_panel_panel_top_impl(PyCursesPanelObject *self, PyTypeObject *cls); + + static PyObject * +-_curses_panel_panel_top(PyCursesPanelObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_curses_panel_panel_top(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "top() takes no arguments"); + return NULL; + } +- return _curses_panel_panel_top_impl(self, cls); ++ return _curses_panel_panel_top_impl((PyCursesPanelObject *)self, cls); + } + + PyDoc_STRVAR(_curses_panel_panel_above__doc__, +@@ -110,9 +110,9 @@ + _curses_panel_panel_above_impl(PyCursesPanelObject *self); + + static PyObject * +-_curses_panel_panel_above(PyCursesPanelObject *self, PyObject *Py_UNUSED(ignored)) ++_curses_panel_panel_above(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _curses_panel_panel_above_impl(self); ++ return _curses_panel_panel_above_impl((PyCursesPanelObject *)self); + } + + PyDoc_STRVAR(_curses_panel_panel_below__doc__, +@@ -128,9 +128,9 @@ + _curses_panel_panel_below_impl(PyCursesPanelObject *self); + + static PyObject * +-_curses_panel_panel_below(PyCursesPanelObject *self, PyObject *Py_UNUSED(ignored)) ++_curses_panel_panel_below(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _curses_panel_panel_below_impl(self); ++ return _curses_panel_panel_below_impl((PyCursesPanelObject *)self); + } + + PyDoc_STRVAR(_curses_panel_panel_hidden__doc__, +@@ -146,9 +146,9 @@ + _curses_panel_panel_hidden_impl(PyCursesPanelObject *self); + + static PyObject * +-_curses_panel_panel_hidden(PyCursesPanelObject *self, PyObject *Py_UNUSED(ignored)) ++_curses_panel_panel_hidden(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _curses_panel_panel_hidden_impl(self); ++ return _curses_panel_panel_hidden_impl((PyCursesPanelObject *)self); + } + + PyDoc_STRVAR(_curses_panel_panel_move__doc__, +@@ -165,7 +165,7 @@ + int y, int x); + + static PyObject * +-_curses_panel_panel_move(PyCursesPanelObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_curses_panel_panel_move(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -198,7 +198,7 @@ + if (x == -1 && PyErr_Occurred()) { + goto exit; + } +- return_value = _curses_panel_panel_move_impl(self, cls, y, x); ++ return_value = _curses_panel_panel_move_impl((PyCursesPanelObject *)self, cls, y, x); + + exit: + return return_value; +@@ -217,9 +217,9 @@ + _curses_panel_panel_window_impl(PyCursesPanelObject *self); + + static PyObject * +-_curses_panel_panel_window(PyCursesPanelObject *self, PyObject *Py_UNUSED(ignored)) ++_curses_panel_panel_window(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _curses_panel_panel_window_impl(self); ++ return _curses_panel_panel_window_impl((PyCursesPanelObject *)self); + } + + PyDoc_STRVAR(_curses_panel_panel_replace__doc__, +@@ -237,7 +237,7 @@ + PyCursesWindowObject *win); + + static PyObject * +-_curses_panel_panel_replace(PyCursesPanelObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_curses_panel_panel_replace(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -266,7 +266,7 @@ + goto exit; + } + win = (PyCursesWindowObject *)args[0]; +- return_value = _curses_panel_panel_replace_impl(self, cls, win); ++ return_value = _curses_panel_panel_replace_impl((PyCursesPanelObject *)self, cls, win); + + exit: + return return_value; +@@ -286,7 +286,7 @@ + PyTypeObject *cls, PyObject *obj); + + static PyObject * +-_curses_panel_panel_set_userptr(PyCursesPanelObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_curses_panel_panel_set_userptr(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -311,7 +311,7 @@ + goto exit; + } + obj = args[0]; +- return_value = _curses_panel_panel_set_userptr_impl(self, cls, obj); ++ return_value = _curses_panel_panel_set_userptr_impl((PyCursesPanelObject *)self, cls, obj); + + exit: + return return_value; +@@ -331,13 +331,13 @@ + PyTypeObject *cls); + + static PyObject * +-_curses_panel_panel_userptr(PyCursesPanelObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_curses_panel_panel_userptr(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "userptr() takes no arguments"); + return NULL; + } +- return _curses_panel_panel_userptr_impl(self, cls); ++ return _curses_panel_panel_userptr_impl((PyCursesPanelObject *)self, cls); + } + + PyDoc_STRVAR(_curses_panel_bottom_panel__doc__, +@@ -424,4 +424,4 @@ + { + return _curses_panel_update_panels_impl(module); + } +-/*[clinic end generated code: output=298e49d54c0b14a0 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=36853ecb4a979814 input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h +index 524a114aba9..8291d5d635c 100644 +--- a/Modules/clinic/_cursesmodule.c.h ++++ b/Modules/clinic/_cursesmodule.c.h +@@ -35,7 +35,7 @@ + long attr); + + static PyObject * +-_curses_window_addch(PyCursesWindowObject *self, PyObject *args) ++_curses_window_addch(PyObject *self, PyObject *args) + { + PyObject *return_value = NULL; + int group_left_1 = 0; +@@ -74,7 +74,7 @@ + PyErr_SetString(PyExc_TypeError, "_curses.window.addch requires 1 to 4 arguments"); + goto exit; + } +- return_value = _curses_window_addch_impl(self, group_left_1, y, x, ch, group_right_1, attr); ++ return_value = _curses_window_addch_impl((PyCursesWindowObject *)self, group_left_1, y, x, ch, group_right_1, attr); + + exit: + return return_value; +@@ -107,7 +107,7 @@ + long attr); + + static PyObject * +-_curses_window_addstr(PyCursesWindowObject *self, PyObject *args) ++_curses_window_addstr(PyObject *self, PyObject *args) + { + PyObject *return_value = NULL; + int group_left_1 = 0; +@@ -146,7 +146,7 @@ + PyErr_SetString(PyExc_TypeError, "_curses.window.addstr requires 1 to 4 arguments"); + goto exit; + } +- return_value = _curses_window_addstr_impl(self, group_left_1, y, x, str, group_right_1, attr); ++ return_value = _curses_window_addstr_impl((PyCursesWindowObject *)self, group_left_1, y, x, str, group_right_1, attr); + + exit: + return return_value; +@@ -181,7 +181,7 @@ + int group_right_1, long attr); + + static PyObject * +-_curses_window_addnstr(PyCursesWindowObject *self, PyObject *args) ++_curses_window_addnstr(PyObject *self, PyObject *args) + { + PyObject *return_value = NULL; + int group_left_1 = 0; +@@ -221,7 +221,7 @@ + PyErr_SetString(PyExc_TypeError, "_curses.window.addnstr requires 2 to 5 arguments"); + goto exit; + } +- return_value = _curses_window_addnstr_impl(self, group_left_1, y, x, str, n, group_right_1, attr); ++ return_value = _curses_window_addnstr_impl((PyCursesWindowObject *)self, group_left_1, y, x, str, n, group_right_1, attr); + + exit: + return return_value; +@@ -245,7 +245,7 @@ + _curses_window_bkgd_impl(PyCursesWindowObject *self, PyObject *ch, long attr); + + static PyObject * +-_curses_window_bkgd(PyCursesWindowObject *self, PyObject *const *args, Py_ssize_t nargs) ++_curses_window_bkgd(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *ch; +@@ -263,7 +263,7 @@ + goto exit; + } + skip_optional: +- return_value = _curses_window_bkgd_impl(self, ch, attr); ++ return_value = _curses_window_bkgd_impl((PyCursesWindowObject *)self, ch, attr); + + exit: + return return_value; +@@ -282,7 +282,7 @@ + _curses_window_attroff_impl(PyCursesWindowObject *self, long attr); + + static PyObject * +-_curses_window_attroff(PyCursesWindowObject *self, PyObject *arg) ++_curses_window_attroff(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + long attr; +@@ -291,7 +291,7 @@ + if (attr == -1 && PyErr_Occurred()) { + goto exit; + } +- return_value = _curses_window_attroff_impl(self, attr); ++ return_value = _curses_window_attroff_impl((PyCursesWindowObject *)self, attr); + + exit: + return return_value; +@@ -310,7 +310,7 @@ + _curses_window_attron_impl(PyCursesWindowObject *self, long attr); + + static PyObject * +-_curses_window_attron(PyCursesWindowObject *self, PyObject *arg) ++_curses_window_attron(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + long attr; +@@ -319,7 +319,7 @@ + if (attr == -1 && PyErr_Occurred()) { + goto exit; + } +- return_value = _curses_window_attron_impl(self, attr); ++ return_value = _curses_window_attron_impl((PyCursesWindowObject *)self, attr); + + exit: + return return_value; +@@ -338,7 +338,7 @@ + _curses_window_attrset_impl(PyCursesWindowObject *self, long attr); + + static PyObject * +-_curses_window_attrset(PyCursesWindowObject *self, PyObject *arg) ++_curses_window_attrset(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + long attr; +@@ -347,7 +347,7 @@ + if (attr == -1 && PyErr_Occurred()) { + goto exit; + } +- return_value = _curses_window_attrset_impl(self, attr); ++ return_value = _curses_window_attrset_impl((PyCursesWindowObject *)self, attr); + + exit: + return return_value; +@@ -372,7 +372,7 @@ + long attr); + + static PyObject * +-_curses_window_bkgdset(PyCursesWindowObject *self, PyObject *const *args, Py_ssize_t nargs) ++_curses_window_bkgdset(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *ch; +@@ -390,7 +390,7 @@ + goto exit; + } + skip_optional: +- return_value = _curses_window_bkgdset_impl(self, ch, attr); ++ return_value = _curses_window_bkgdset_impl((PyCursesWindowObject *)self, ch, attr); + + exit: + return return_value; +@@ -437,7 +437,7 @@ + PyObject *br); + + static PyObject * +-_curses_window_border(PyCursesWindowObject *self, PyObject *const *args, Py_ssize_t nargs) ++_curses_window_border(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *ls = NULL; +@@ -485,7 +485,7 @@ + } + br = args[7]; + skip_optional: +- return_value = _curses_window_border_impl(self, ls, rs, ts, bs, tl, tr, bl, br); ++ return_value = _curses_window_border_impl((PyCursesWindowObject *)self, ls, rs, ts, bs, tl, tr, bl, br); + + exit: + return return_value; +@@ -511,7 +511,7 @@ + PyObject *verch, PyObject *horch); + + static PyObject * +-_curses_window_box(PyCursesWindowObject *self, PyObject *args) ++_curses_window_box(PyObject *self, PyObject *args) + { + PyObject *return_value = NULL; + int group_right_1 = 0; +@@ -531,7 +531,7 @@ + PyErr_SetString(PyExc_TypeError, "_curses.window.box requires 0 to 2 arguments"); + goto exit; + } +- return_value = _curses_window_box_impl(self, group_right_1, verch, horch); ++ return_value = _curses_window_box_impl((PyCursesWindowObject *)self, group_right_1, verch, horch); + + exit: + return return_value; +@@ -554,7 +554,7 @@ + int y, int x); + + static PyObject * +-_curses_window_delch(PyCursesWindowObject *self, PyObject *args) ++_curses_window_delch(PyObject *self, PyObject *args) + { + PyObject *return_value = NULL; + int group_right_1 = 0; +@@ -574,7 +574,7 @@ + PyErr_SetString(PyExc_TypeError, "_curses.window.delch requires 0 to 2 arguments"); + goto exit; + } +- return_value = _curses_window_delch_impl(self, group_right_1, y, x); ++ return_value = _curses_window_delch_impl((PyCursesWindowObject *)self, group_right_1, y, x); + + exit: + return return_value; +@@ -605,7 +605,7 @@ + int nlines, int ncols, int begin_y, int begin_x); + + static PyObject * +-_curses_window_derwin(PyCursesWindowObject *self, PyObject *args) ++_curses_window_derwin(PyObject *self, PyObject *args) + { + PyObject *return_value = NULL; + int group_left_1 = 0; +@@ -630,7 +630,7 @@ + PyErr_SetString(PyExc_TypeError, "_curses.window.derwin requires 2 to 4 arguments"); + goto exit; + } +- return_value = _curses_window_derwin_impl(self, group_left_1, nlines, ncols, begin_y, begin_x); ++ return_value = _curses_window_derwin_impl((PyCursesWindowObject *)self, group_left_1, nlines, ncols, begin_y, begin_x); + + exit: + return return_value; +@@ -655,7 +655,7 @@ + long attr); + + static PyObject * +-_curses_window_echochar(PyCursesWindowObject *self, PyObject *const *args, Py_ssize_t nargs) ++_curses_window_echochar(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *ch; +@@ -673,7 +673,7 @@ + goto exit; + } + skip_optional: +- return_value = _curses_window_echochar_impl(self, ch, attr); ++ return_value = _curses_window_echochar_impl((PyCursesWindowObject *)self, ch, attr); + + exit: + return return_value; +@@ -699,7 +699,7 @@ + _curses_window_enclose_impl(PyCursesWindowObject *self, int y, int x); + + static PyObject * +-_curses_window_enclose(PyCursesWindowObject *self, PyObject *const *args, Py_ssize_t nargs) ++_curses_window_enclose(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + int y; +@@ -716,7 +716,7 @@ + if (x == -1 && PyErr_Occurred()) { + goto exit; + } +- return_value = _curses_window_enclose_impl(self, y, x); ++ return_value = _curses_window_enclose_impl((PyCursesWindowObject *)self, y, x); + + exit: + return return_value; +@@ -737,12 +737,12 @@ + _curses_window_getbkgd_impl(PyCursesWindowObject *self); + + static PyObject * +-_curses_window_getbkgd(PyCursesWindowObject *self, PyObject *Py_UNUSED(ignored)) ++_curses_window_getbkgd(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + long _return_value; + +- _return_value = _curses_window_getbkgd_impl(self); ++ _return_value = _curses_window_getbkgd_impl((PyCursesWindowObject *)self); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } +@@ -773,7 +773,7 @@ + int y, int x); + + static PyObject * +-_curses_window_getch(PyCursesWindowObject *self, PyObject *args) ++_curses_window_getch(PyObject *self, PyObject *args) + { + PyObject *return_value = NULL; + int group_right_1 = 0; +@@ -794,7 +794,7 @@ + PyErr_SetString(PyExc_TypeError, "_curses.window.getch requires 0 to 2 arguments"); + goto exit; + } +- _return_value = _curses_window_getch_impl(self, group_right_1, y, x); ++ _return_value = _curses_window_getch_impl((PyCursesWindowObject *)self, group_right_1, y, x); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } +@@ -825,7 +825,7 @@ + int y, int x); + + static PyObject * +-_curses_window_getkey(PyCursesWindowObject *self, PyObject *args) ++_curses_window_getkey(PyObject *self, PyObject *args) + { + PyObject *return_value = NULL; + int group_right_1 = 0; +@@ -845,7 +845,7 @@ + PyErr_SetString(PyExc_TypeError, "_curses.window.getkey requires 0 to 2 arguments"); + goto exit; + } +- return_value = _curses_window_getkey_impl(self, group_right_1, y, x); ++ return_value = _curses_window_getkey_impl((PyCursesWindowObject *)self, group_right_1, y, x); + + exit: + return return_value; +@@ -873,7 +873,7 @@ + int y, int x); + + static PyObject * +-_curses_window_get_wch(PyCursesWindowObject *self, PyObject *args) ++_curses_window_get_wch(PyObject *self, PyObject *args) + { + PyObject *return_value = NULL; + int group_right_1 = 0; +@@ -893,7 +893,7 @@ + PyErr_SetString(PyExc_TypeError, "_curses.window.get_wch requires 0 to 2 arguments"); + goto exit; + } +- return_value = _curses_window_get_wch_impl(self, group_right_1, y, x); ++ return_value = _curses_window_get_wch_impl((PyCursesWindowObject *)self, group_right_1, y, x); + + exit: + return return_value; +@@ -925,7 +925,7 @@ + int group_right_1, long attr); + + static PyObject * +-_curses_window_hline(PyCursesWindowObject *self, PyObject *args) ++_curses_window_hline(PyObject *self, PyObject *args) + { + PyObject *return_value = NULL; + int group_left_1 = 0; +@@ -965,7 +965,7 @@ + PyErr_SetString(PyExc_TypeError, "_curses.window.hline requires 2 to 5 arguments"); + goto exit; + } +- return_value = _curses_window_hline_impl(self, group_left_1, y, x, ch, n, group_right_1, attr); ++ return_value = _curses_window_hline_impl((PyCursesWindowObject *)self, group_left_1, y, x, ch, n, group_right_1, attr); + + exit: + return return_value; +@@ -996,7 +996,7 @@ + long attr); + + static PyObject * +-_curses_window_insch(PyCursesWindowObject *self, PyObject *args) ++_curses_window_insch(PyObject *self, PyObject *args) + { + PyObject *return_value = NULL; + int group_left_1 = 0; +@@ -1035,7 +1035,7 @@ + PyErr_SetString(PyExc_TypeError, "_curses.window.insch requires 1 to 4 arguments"); + goto exit; + } +- return_value = _curses_window_insch_impl(self, group_left_1, y, x, ch, group_right_1, attr); ++ return_value = _curses_window_insch_impl((PyCursesWindowObject *)self, group_left_1, y, x, ch, group_right_1, attr); + + exit: + return return_value; +@@ -1060,7 +1060,7 @@ + int y, int x); + + static PyObject * +-_curses_window_inch(PyCursesWindowObject *self, PyObject *args) ++_curses_window_inch(PyObject *self, PyObject *args) + { + PyObject *return_value = NULL; + int group_right_1 = 0; +@@ -1081,7 +1081,7 @@ + PyErr_SetString(PyExc_TypeError, "_curses.window.inch requires 0 to 2 arguments"); + goto exit; + } +- _return_value = _curses_window_inch_impl(self, group_right_1, y, x); ++ _return_value = _curses_window_inch_impl((PyCursesWindowObject *)self, group_right_1, y, x); + if ((_return_value == (unsigned long)-1) && PyErr_Occurred()) { + goto exit; + } +@@ -1119,7 +1119,7 @@ + long attr); + + static PyObject * +-_curses_window_insstr(PyCursesWindowObject *self, PyObject *args) ++_curses_window_insstr(PyObject *self, PyObject *args) + { + PyObject *return_value = NULL; + int group_left_1 = 0; +@@ -1158,7 +1158,7 @@ + PyErr_SetString(PyExc_TypeError, "_curses.window.insstr requires 1 to 4 arguments"); + goto exit; + } +- return_value = _curses_window_insstr_impl(self, group_left_1, y, x, str, group_right_1, attr); ++ return_value = _curses_window_insstr_impl((PyCursesWindowObject *)self, group_left_1, y, x, str, group_right_1, attr); + + exit: + return return_value; +@@ -1195,7 +1195,7 @@ + int group_right_1, long attr); + + static PyObject * +-_curses_window_insnstr(PyCursesWindowObject *self, PyObject *args) ++_curses_window_insnstr(PyObject *self, PyObject *args) + { + PyObject *return_value = NULL; + int group_left_1 = 0; +@@ -1235,7 +1235,7 @@ + PyErr_SetString(PyExc_TypeError, "_curses.window.insnstr requires 2 to 5 arguments"); + goto exit; + } +- return_value = _curses_window_insnstr_impl(self, group_left_1, y, x, str, n, group_right_1, attr); ++ return_value = _curses_window_insnstr_impl((PyCursesWindowObject *)self, group_left_1, y, x, str, n, group_right_1, attr); + + exit: + return return_value; +@@ -1259,7 +1259,7 @@ + _curses_window_is_linetouched_impl(PyCursesWindowObject *self, int line); + + static PyObject * +-_curses_window_is_linetouched(PyCursesWindowObject *self, PyObject *arg) ++_curses_window_is_linetouched(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + int line; +@@ -1268,7 +1268,7 @@ + if (line == -1 && PyErr_Occurred()) { + goto exit; + } +- return_value = _curses_window_is_linetouched_impl(self, line); ++ return_value = _curses_window_is_linetouched_impl((PyCursesWindowObject *)self, line); + + exit: + return return_value; +@@ -1294,7 +1294,7 @@ + int smaxcol); + + static PyObject * +-_curses_window_noutrefresh(PyCursesWindowObject *self, PyObject *args) ++_curses_window_noutrefresh(PyObject *self, PyObject *args) + { + PyObject *return_value = NULL; + int group_right_1 = 0; +@@ -1318,7 +1318,7 @@ + PyErr_SetString(PyExc_TypeError, "_curses.window.noutrefresh requires 0 to 6 arguments"); + goto exit; + } +- return_value = _curses_window_noutrefresh_impl(self, group_right_1, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol); ++ return_value = _curses_window_noutrefresh_impl((PyCursesWindowObject *)self, group_right_1, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol); + + exit: + return return_value; +@@ -1345,9 +1345,9 @@ + _curses_window_noutrefresh_impl(PyCursesWindowObject *self); + + static PyObject * +-_curses_window_noutrefresh(PyCursesWindowObject *self, PyObject *Py_UNUSED(ignored)) ++_curses_window_noutrefresh(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _curses_window_noutrefresh_impl(self); ++ return _curses_window_noutrefresh_impl((PyCursesWindowObject *)self); + } + + #endif /* !defined(py_is_pad) */ +@@ -1375,7 +1375,7 @@ + int dmincol, int dmaxrow, int dmaxcol); + + static PyObject * +-_curses_window_overlay(PyCursesWindowObject *self, PyObject *args) ++_curses_window_overlay(PyObject *self, PyObject *args) + { + PyObject *return_value = NULL; + PyCursesWindowObject *destwin; +@@ -1403,7 +1403,7 @@ + PyErr_SetString(PyExc_TypeError, "_curses.window.overlay requires 1 to 7 arguments"); + goto exit; + } +- return_value = _curses_window_overlay_impl(self, destwin, group_right_1, sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol); ++ return_value = _curses_window_overlay_impl((PyCursesWindowObject *)self, destwin, group_right_1, sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol); + + exit: + return return_value; +@@ -1434,7 +1434,7 @@ + int dmaxcol); + + static PyObject * +-_curses_window_overwrite(PyCursesWindowObject *self, PyObject *args) ++_curses_window_overwrite(PyObject *self, PyObject *args) + { + PyObject *return_value = NULL; + PyCursesWindowObject *destwin; +@@ -1462,7 +1462,7 @@ + PyErr_SetString(PyExc_TypeError, "_curses.window.overwrite requires 1 to 7 arguments"); + goto exit; + } +- return_value = _curses_window_overwrite_impl(self, destwin, group_right_1, sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol); ++ return_value = _curses_window_overwrite_impl((PyCursesWindowObject *)self, destwin, group_right_1, sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol); + + exit: + return return_value; +@@ -1499,7 +1499,7 @@ + _curses_window_redrawln_impl(PyCursesWindowObject *self, int beg, int num); + + static PyObject * +-_curses_window_redrawln(PyCursesWindowObject *self, PyObject *const *args, Py_ssize_t nargs) ++_curses_window_redrawln(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + int beg; +@@ -1516,7 +1516,7 @@ + if (num == -1 && PyErr_Occurred()) { + goto exit; + } +- return_value = _curses_window_redrawln_impl(self, beg, num); ++ return_value = _curses_window_redrawln_impl((PyCursesWindowObject *)self, beg, num); + + exit: + return return_value; +@@ -1547,7 +1547,7 @@ + int smincol, int smaxrow, int smaxcol); + + static PyObject * +-_curses_window_refresh(PyCursesWindowObject *self, PyObject *args) ++_curses_window_refresh(PyObject *self, PyObject *args) + { + PyObject *return_value = NULL; + int group_right_1 = 0; +@@ -1571,7 +1571,7 @@ + PyErr_SetString(PyExc_TypeError, "_curses.window.refresh requires 0 to 6 arguments"); + goto exit; + } +- return_value = _curses_window_refresh_impl(self, group_right_1, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol); ++ return_value = _curses_window_refresh_impl((PyCursesWindowObject *)self, group_right_1, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol); + + exit: + return return_value; +@@ -1598,7 +1598,7 @@ + int bottom); + + static PyObject * +-_curses_window_setscrreg(PyCursesWindowObject *self, PyObject *const *args, Py_ssize_t nargs) ++_curses_window_setscrreg(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + int top; +@@ -1615,7 +1615,7 @@ + if (bottom == -1 && PyErr_Occurred()) { + goto exit; + } +- return_value = _curses_window_setscrreg_impl(self, top, bottom); ++ return_value = _curses_window_setscrreg_impl((PyCursesWindowObject *)self, top, bottom); + + exit: + return return_value; +@@ -1645,7 +1645,7 @@ + int nlines, int ncols, int begin_y, int begin_x); + + static PyObject * +-_curses_window_subwin(PyCursesWindowObject *self, PyObject *args) ++_curses_window_subwin(PyObject *self, PyObject *args) + { + PyObject *return_value = NULL; + int group_left_1 = 0; +@@ -1670,7 +1670,7 @@ + PyErr_SetString(PyExc_TypeError, "_curses.window.subwin requires 2 to 4 arguments"); + goto exit; + } +- return_value = _curses_window_subwin_impl(self, group_left_1, nlines, ncols, begin_y, begin_x); ++ return_value = _curses_window_subwin_impl((PyCursesWindowObject *)self, group_left_1, nlines, ncols, begin_y, begin_x); + + exit: + return return_value; +@@ -1693,7 +1693,7 @@ + int lines); + + static PyObject * +-_curses_window_scroll(PyCursesWindowObject *self, PyObject *args) ++_curses_window_scroll(PyObject *self, PyObject *args) + { + PyObject *return_value = NULL; + int group_right_1 = 0; +@@ -1712,7 +1712,7 @@ + PyErr_SetString(PyExc_TypeError, "_curses.window.scroll requires 0 to 1 arguments"); + goto exit; + } +- return_value = _curses_window_scroll_impl(self, group_right_1, lines); ++ return_value = _curses_window_scroll_impl((PyCursesWindowObject *)self, group_right_1, lines); + + exit: + return return_value; +@@ -1733,7 +1733,7 @@ + int count, int group_right_1, int changed); + + static PyObject * +-_curses_window_touchline(PyCursesWindowObject *self, PyObject *args) ++_curses_window_touchline(PyObject *self, PyObject *args) + { + PyObject *return_value = NULL; + int start; +@@ -1757,7 +1757,7 @@ + PyErr_SetString(PyExc_TypeError, "_curses.window.touchline requires 2 to 3 arguments"); + goto exit; + } +- return_value = _curses_window_touchline_impl(self, start, count, group_right_1, changed); ++ return_value = _curses_window_touchline_impl((PyCursesWindowObject *)self, start, count, group_right_1, changed); + + exit: + return return_value; +@@ -1787,7 +1787,7 @@ + int group_right_1, long attr); + + static PyObject * +-_curses_window_vline(PyCursesWindowObject *self, PyObject *args) ++_curses_window_vline(PyObject *self, PyObject *args) + { + PyObject *return_value = NULL; + int group_left_1 = 0; +@@ -1827,7 +1827,7 @@ + PyErr_SetString(PyExc_TypeError, "_curses.window.vline requires 2 to 5 arguments"); + goto exit; + } +- return_value = _curses_window_vline_impl(self, group_left_1, y, x, ch, n, group_right_1, attr); ++ return_value = _curses_window_vline_impl((PyCursesWindowObject *)self, group_left_1, y, x, ch, n, group_right_1, attr); + + exit: + return return_value; +@@ -4379,4 +4379,4 @@ + #ifndef _CURSES_USE_DEFAULT_COLORS_METHODDEF + #define _CURSES_USE_DEFAULT_COLORS_METHODDEF + #endif /* !defined(_CURSES_USE_DEFAULT_COLORS_METHODDEF) */ +-/*[clinic end generated code: output=26fe38c09ff8ca44 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=c4211865ed96c2af input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/_datetimemodule.c.h b/Modules/clinic/_datetimemodule.c.h +index 72c230fc8ae..8f33c9e7d4e 100644 +--- a/Modules/clinic/_datetimemodule.c.h ++++ b/Modules/clinic/_datetimemodule.c.h +@@ -97,7 +97,7 @@ + int day); + + static PyObject * +-datetime_date_replace(PyDateTime_Date *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++datetime_date_replace(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -162,7 +162,7 @@ + goto exit; + } + skip_optional_pos: +- return_value = datetime_date_replace_impl(self, year, month, day); ++ return_value = datetime_date_replace_impl((PyDateTime_Date *)self, year, month, day); + + exit: + return return_value; +@@ -184,7 +184,7 @@ + int fold); + + static PyObject * +-datetime_time_replace(PyDateTime_Time *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++datetime_time_replace(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -218,7 +218,7 @@ + int minute = TIME_GET_MINUTE(self); + int second = TIME_GET_SECOND(self); + int microsecond = TIME_GET_MICROSECOND(self); +- PyObject *tzinfo = HASTZINFO(self) ? self->tzinfo : Py_None; ++ PyObject *tzinfo = HASTZINFO(self) ? ((PyDateTime_Time *)self)->tzinfo : Py_None; + int fold = TIME_GET_FOLD(self); + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, +@@ -280,7 +280,7 @@ + goto exit; + } + skip_optional_kwonly: +- return_value = datetime_time_replace_impl(self, hour, minute, second, microsecond, tzinfo, fold); ++ return_value = datetime_time_replace_impl((PyDateTime_Time *)self, hour, minute, second, microsecond, tzinfo, fold); + + exit: + return return_value; +@@ -370,7 +370,7 @@ + int fold); + + static PyObject * +-datetime_datetime_replace(PyDateTime_DateTime *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++datetime_datetime_replace(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -407,7 +407,7 @@ + int minute = DATE_GET_MINUTE(self); + int second = DATE_GET_SECOND(self); + int microsecond = DATE_GET_MICROSECOND(self); +- PyObject *tzinfo = HASTZINFO(self) ? self->tzinfo : Py_None; ++ PyObject *tzinfo = HASTZINFO(self) ? ((PyDateTime_DateTime *)self)->tzinfo : Py_None; + int fold = DATE_GET_FOLD(self); + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, +@@ -496,9 +496,9 @@ + goto exit; + } + skip_optional_kwonly: +- return_value = datetime_datetime_replace_impl(self, year, month, day, hour, minute, second, microsecond, tzinfo, fold); ++ return_value = datetime_datetime_replace_impl((PyDateTime_DateTime *)self, year, month, day, hour, minute, second, microsecond, tzinfo, fold); + + exit: + return return_value; + } +-/*[clinic end generated code: output=203217a61ea14171 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=8acf62fbc7328f79 input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/_dbmmodule.c.h b/Modules/clinic/_dbmmodule.c.h +index 4379b433db3..5e503194408 100644 +--- a/Modules/clinic/_dbmmodule.c.h ++++ b/Modules/clinic/_dbmmodule.c.h +@@ -20,9 +20,9 @@ + _dbm_dbm_close_impl(dbmobject *self); + + static PyObject * +-_dbm_dbm_close(dbmobject *self, PyObject *Py_UNUSED(ignored)) ++_dbm_dbm_close(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _dbm_dbm_close_impl(self); ++ return _dbm_dbm_close_impl((dbmobject *)self); + } + + PyDoc_STRVAR(_dbm_dbm_keys__doc__, +@@ -38,13 +38,13 @@ + _dbm_dbm_keys_impl(dbmobject *self, PyTypeObject *cls); + + static PyObject * +-_dbm_dbm_keys(dbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_dbm_dbm_keys(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "keys() takes no arguments"); + return NULL; + } +- return _dbm_dbm_keys_impl(self, cls); ++ return _dbm_dbm_keys_impl((dbmobject *)self, cls); + } + + PyDoc_STRVAR(_dbm_dbm_get__doc__, +@@ -61,7 +61,7 @@ + Py_ssize_t key_length, PyObject *default_value); + + static PyObject * +-_dbm_dbm_get(dbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_dbm_dbm_get(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -85,7 +85,7 @@ + &key, &key_length, &default_value)) { + goto exit; + } +- return_value = _dbm_dbm_get_impl(self, cls, key, key_length, default_value); ++ return_value = _dbm_dbm_get_impl((dbmobject *)self, cls, key, key_length, default_value); + + exit: + return return_value; +@@ -107,7 +107,7 @@ + Py_ssize_t key_length, PyObject *default_value); + + static PyObject * +-_dbm_dbm_setdefault(dbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_dbm_dbm_setdefault(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -131,7 +131,7 @@ + &key, &key_length, &default_value)) { + goto exit; + } +- return_value = _dbm_dbm_setdefault_impl(self, cls, key, key_length, default_value); ++ return_value = _dbm_dbm_setdefault_impl((dbmobject *)self, cls, key, key_length, default_value); + + exit: + return return_value; +@@ -150,13 +150,13 @@ + _dbm_dbm_clear_impl(dbmobject *self, PyTypeObject *cls); + + static PyObject * +-_dbm_dbm_clear(dbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_dbm_dbm_clear(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "clear() takes no arguments"); + return NULL; + } +- return _dbm_dbm_clear_impl(self, cls); ++ return _dbm_dbm_clear_impl((dbmobject *)self, cls); + } + + PyDoc_STRVAR(dbmopen__doc__, +@@ -221,4 +221,4 @@ + exit: + return return_value; + } +-/*[clinic end generated code: output=f7d9a87d80a64278 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=3b456118f231b160 input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/_elementtree.c.h b/Modules/clinic/_elementtree.c.h +index 07045e72040..78391887b61 100644 +--- a/Modules/clinic/_elementtree.c.h ++++ b/Modules/clinic/_elementtree.c.h +@@ -22,7 +22,7 @@ + PyObject *subelement); + + static PyObject * +-_elementtree_Element_append(ElementObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_elementtree_Element_append(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -51,7 +51,7 @@ + goto exit; + } + subelement = args[0]; +- return_value = _elementtree_Element_append_impl(self, cls, subelement); ++ return_value = _elementtree_Element_append_impl((ElementObject *)self, cls, subelement); + + exit: + return return_value; +@@ -69,9 +69,9 @@ + _elementtree_Element_clear_impl(ElementObject *self); + + static PyObject * +-_elementtree_Element_clear(ElementObject *self, PyObject *Py_UNUSED(ignored)) ++_elementtree_Element_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _elementtree_Element_clear_impl(self); ++ return _elementtree_Element_clear_impl((ElementObject *)self); + } + + PyDoc_STRVAR(_elementtree_Element___copy____doc__, +@@ -86,13 +86,13 @@ + _elementtree_Element___copy___impl(ElementObject *self, PyTypeObject *cls); + + static PyObject * +-_elementtree_Element___copy__(ElementObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_elementtree_Element___copy__(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "__copy__() takes no arguments"); + return NULL; + } +- return _elementtree_Element___copy___impl(self, cls); ++ return _elementtree_Element___copy___impl((ElementObject *)self, cls); + } + + PyDoc_STRVAR(_elementtree_Element___deepcopy____doc__, +@@ -107,7 +107,7 @@ + _elementtree_Element___deepcopy___impl(ElementObject *self, PyObject *memo); + + static PyObject * +-_elementtree_Element___deepcopy__(ElementObject *self, PyObject *arg) ++_elementtree_Element___deepcopy__(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + PyObject *memo; +@@ -117,7 +117,7 @@ + goto exit; + } + memo = arg; +- return_value = _elementtree_Element___deepcopy___impl(self, memo); ++ return_value = _elementtree_Element___deepcopy___impl((ElementObject *)self, memo); + + exit: + return return_value; +@@ -135,12 +135,12 @@ + _elementtree_Element___sizeof___impl(ElementObject *self); + + static PyObject * +-_elementtree_Element___sizeof__(ElementObject *self, PyObject *Py_UNUSED(ignored)) ++_elementtree_Element___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + size_t _return_value; + +- _return_value = _elementtree_Element___sizeof___impl(self); ++ _return_value = _elementtree_Element___sizeof___impl((ElementObject *)self); + if ((_return_value == (size_t)-1) && PyErr_Occurred()) { + goto exit; + } +@@ -162,9 +162,9 @@ + _elementtree_Element___getstate___impl(ElementObject *self); + + static PyObject * +-_elementtree_Element___getstate__(ElementObject *self, PyObject *Py_UNUSED(ignored)) ++_elementtree_Element___getstate__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _elementtree_Element___getstate___impl(self); ++ return _elementtree_Element___getstate___impl((ElementObject *)self); + } + + PyDoc_STRVAR(_elementtree_Element___setstate____doc__, +@@ -180,7 +180,7 @@ + PyTypeObject *cls, PyObject *state); + + static PyObject * +-_elementtree_Element___setstate__(ElementObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_elementtree_Element___setstate__(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -205,7 +205,7 @@ + goto exit; + } + state = args[0]; +- return_value = _elementtree_Element___setstate___impl(self, cls, state); ++ return_value = _elementtree_Element___setstate___impl((ElementObject *)self, cls, state); + + exit: + return return_value; +@@ -224,7 +224,7 @@ + PyObject *elements); + + static PyObject * +-_elementtree_Element_extend(ElementObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_elementtree_Element_extend(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -249,7 +249,7 @@ + goto exit; + } + elements = args[0]; +- return_value = _elementtree_Element_extend_impl(self, cls, elements); ++ return_value = _elementtree_Element_extend_impl((ElementObject *)self, cls, elements); + + exit: + return return_value; +@@ -268,7 +268,7 @@ + PyObject *path, PyObject *namespaces); + + static PyObject * +-_elementtree_Element_find(ElementObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_elementtree_Element_find(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -312,7 +312,7 @@ + } + namespaces = args[1]; + skip_optional_pos: +- return_value = _elementtree_Element_find_impl(self, cls, path, namespaces); ++ return_value = _elementtree_Element_find_impl((ElementObject *)self, cls, path, namespaces); + + exit: + return return_value; +@@ -332,7 +332,7 @@ + PyObject *namespaces); + + static PyObject * +-_elementtree_Element_findtext(ElementObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_elementtree_Element_findtext(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -383,7 +383,7 @@ + } + namespaces = args[2]; + skip_optional_pos: +- return_value = _elementtree_Element_findtext_impl(self, cls, path, default_value, namespaces); ++ return_value = _elementtree_Element_findtext_impl((ElementObject *)self, cls, path, default_value, namespaces); + + exit: + return return_value; +@@ -402,7 +402,7 @@ + PyObject *path, PyObject *namespaces); + + static PyObject * +-_elementtree_Element_findall(ElementObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_elementtree_Element_findall(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -446,7 +446,7 @@ + } + namespaces = args[1]; + skip_optional_pos: +- return_value = _elementtree_Element_findall_impl(self, cls, path, namespaces); ++ return_value = _elementtree_Element_findall_impl((ElementObject *)self, cls, path, namespaces); + + exit: + return return_value; +@@ -465,7 +465,7 @@ + PyObject *path, PyObject *namespaces); + + static PyObject * +-_elementtree_Element_iterfind(ElementObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_elementtree_Element_iterfind(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -509,7 +509,7 @@ + } + namespaces = args[1]; + skip_optional_pos: +- return_value = _elementtree_Element_iterfind_impl(self, cls, path, namespaces); ++ return_value = _elementtree_Element_iterfind_impl((ElementObject *)self, cls, path, namespaces); + + exit: + return return_value; +@@ -528,7 +528,7 @@ + PyObject *default_value); + + static PyObject * +-_elementtree_Element_get(ElementObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_elementtree_Element_get(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -572,7 +572,7 @@ + } + default_value = args[1]; + skip_optional_pos: +- return_value = _elementtree_Element_get_impl(self, key, default_value); ++ return_value = _elementtree_Element_get_impl((ElementObject *)self, key, default_value); + + exit: + return return_value; +@@ -591,7 +591,7 @@ + PyObject *tag); + + static PyObject * +-_elementtree_Element_iter(ElementObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_elementtree_Element_iter(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -633,7 +633,7 @@ + } + tag = args[0]; + skip_optional_pos: +- return_value = _elementtree_Element_iter_impl(self, cls, tag); ++ return_value = _elementtree_Element_iter_impl((ElementObject *)self, cls, tag); + + exit: + return return_value; +@@ -651,13 +651,13 @@ + _elementtree_Element_itertext_impl(ElementObject *self, PyTypeObject *cls); + + static PyObject * +-_elementtree_Element_itertext(ElementObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_elementtree_Element_itertext(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "itertext() takes no arguments"); + return NULL; + } +- return _elementtree_Element_itertext_impl(self, cls); ++ return _elementtree_Element_itertext_impl((ElementObject *)self, cls); + } + + PyDoc_STRVAR(_elementtree_Element_insert__doc__, +@@ -673,7 +673,7 @@ + PyObject *subelement); + + static PyObject * +-_elementtree_Element_insert(ElementObject *self, PyObject *const *args, Py_ssize_t nargs) ++_elementtree_Element_insert(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + Py_ssize_t index; +@@ -699,7 +699,7 @@ + goto exit; + } + subelement = args[1]; +- return_value = _elementtree_Element_insert_impl(self, index, subelement); ++ return_value = _elementtree_Element_insert_impl((ElementObject *)self, index, subelement); + + exit: + return return_value; +@@ -717,9 +717,9 @@ + _elementtree_Element_items_impl(ElementObject *self); + + static PyObject * +-_elementtree_Element_items(ElementObject *self, PyObject *Py_UNUSED(ignored)) ++_elementtree_Element_items(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _elementtree_Element_items_impl(self); ++ return _elementtree_Element_items_impl((ElementObject *)self); + } + + PyDoc_STRVAR(_elementtree_Element_keys__doc__, +@@ -734,9 +734,9 @@ + _elementtree_Element_keys_impl(ElementObject *self); + + static PyObject * +-_elementtree_Element_keys(ElementObject *self, PyObject *Py_UNUSED(ignored)) ++_elementtree_Element_keys(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _elementtree_Element_keys_impl(self); ++ return _elementtree_Element_keys_impl((ElementObject *)self); + } + + PyDoc_STRVAR(_elementtree_Element_makeelement__doc__, +@@ -752,7 +752,7 @@ + PyObject *tag, PyObject *attrib); + + static PyObject * +-_elementtree_Element_makeelement(ElementObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_elementtree_Element_makeelement(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -783,7 +783,7 @@ + goto exit; + } + attrib = args[1]; +- return_value = _elementtree_Element_makeelement_impl(self, cls, tag, attrib); ++ return_value = _elementtree_Element_makeelement_impl((ElementObject *)self, cls, tag, attrib); + + exit: + return return_value; +@@ -801,7 +801,7 @@ + _elementtree_Element_remove_impl(ElementObject *self, PyObject *subelement); + + static PyObject * +-_elementtree_Element_remove(ElementObject *self, PyObject *arg) ++_elementtree_Element_remove(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + PyObject *subelement; +@@ -811,7 +811,7 @@ + goto exit; + } + subelement = arg; +- return_value = _elementtree_Element_remove_impl(self, subelement); ++ return_value = _elementtree_Element_remove_impl((ElementObject *)self, subelement); + + exit: + return return_value; +@@ -830,7 +830,7 @@ + PyObject *value); + + static PyObject * +-_elementtree_Element_set(ElementObject *self, PyObject *const *args, Py_ssize_t nargs) ++_elementtree_Element_set(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *key; +@@ -841,7 +841,7 @@ + } + key = args[0]; + value = args[1]; +- return_value = _elementtree_Element_set_impl(self, key, value); ++ return_value = _elementtree_Element_set_impl((ElementObject *)self, key, value); + + exit: + return return_value; +@@ -1013,7 +1013,7 @@ + PyObject *text); + + static PyObject * +-_elementtree_TreeBuilder_pi(TreeBuilderObject *self, PyObject *const *args, Py_ssize_t nargs) ++_elementtree_TreeBuilder_pi(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *target; +@@ -1028,7 +1028,7 @@ + } + text = args[1]; + skip_optional: +- return_value = _elementtree_TreeBuilder_pi_impl(self, target, text); ++ return_value = _elementtree_TreeBuilder_pi_impl((TreeBuilderObject *)self, target, text); + + exit: + return return_value; +@@ -1046,9 +1046,9 @@ + _elementtree_TreeBuilder_close_impl(TreeBuilderObject *self); + + static PyObject * +-_elementtree_TreeBuilder_close(TreeBuilderObject *self, PyObject *Py_UNUSED(ignored)) ++_elementtree_TreeBuilder_close(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _elementtree_TreeBuilder_close_impl(self); ++ return _elementtree_TreeBuilder_close_impl((TreeBuilderObject *)self); + } + + PyDoc_STRVAR(_elementtree_TreeBuilder_start__doc__, +@@ -1064,7 +1064,7 @@ + PyObject *attrs); + + static PyObject * +-_elementtree_TreeBuilder_start(TreeBuilderObject *self, PyObject *const *args, Py_ssize_t nargs) ++_elementtree_TreeBuilder_start(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *tag; +@@ -1079,7 +1079,7 @@ + goto exit; + } + attrs = args[1]; +- return_value = _elementtree_TreeBuilder_start_impl(self, tag, attrs); ++ return_value = _elementtree_TreeBuilder_start_impl((TreeBuilderObject *)self, tag, attrs); + + exit: + return return_value; +@@ -1176,9 +1176,9 @@ + _elementtree_XMLParser_close_impl(XMLParserObject *self); + + static PyObject * +-_elementtree_XMLParser_close(XMLParserObject *self, PyObject *Py_UNUSED(ignored)) ++_elementtree_XMLParser_close(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _elementtree_XMLParser_close_impl(self); ++ return _elementtree_XMLParser_close_impl((XMLParserObject *)self); + } + + PyDoc_STRVAR(_elementtree_XMLParser_flush__doc__, +@@ -1193,9 +1193,9 @@ + _elementtree_XMLParser_flush_impl(XMLParserObject *self); + + static PyObject * +-_elementtree_XMLParser_flush(XMLParserObject *self, PyObject *Py_UNUSED(ignored)) ++_elementtree_XMLParser_flush(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _elementtree_XMLParser_flush_impl(self); ++ return _elementtree_XMLParser_flush_impl((XMLParserObject *)self); + } + + PyDoc_STRVAR(_elementtree_XMLParser_feed__doc__, +@@ -1228,7 +1228,7 @@ + PyObject *events_to_report); + + static PyObject * +-_elementtree_XMLParser__setevents(XMLParserObject *self, PyObject *const *args, Py_ssize_t nargs) ++_elementtree_XMLParser__setevents(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *events_queue; +@@ -1243,9 +1243,9 @@ + } + events_to_report = args[1]; + skip_optional: +- return_value = _elementtree_XMLParser__setevents_impl(self, events_queue, events_to_report); ++ return_value = _elementtree_XMLParser__setevents_impl((XMLParserObject *)self, events_queue, events_to_report); + + exit: + return return_value; + } +-/*[clinic end generated code: output=b713bf59fd0fef9b input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=e5c758958f14f102 input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/_gdbmmodule.c.h b/Modules/clinic/_gdbmmodule.c.h +index bbf4365114c..00950f18e53 100644 +--- a/Modules/clinic/_gdbmmodule.c.h ++++ b/Modules/clinic/_gdbmmodule.c.h +@@ -20,7 +20,7 @@ + _gdbm_gdbm_get_impl(gdbmobject *self, PyObject *key, PyObject *default_value); + + static PyObject * +-_gdbm_gdbm_get(gdbmobject *self, PyObject *const *args, Py_ssize_t nargs) ++_gdbm_gdbm_get(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *key; +@@ -35,7 +35,7 @@ + } + default_value = args[1]; + skip_optional: +- return_value = _gdbm_gdbm_get_impl(self, key, default_value); ++ return_value = _gdbm_gdbm_get_impl((gdbmobject *)self, key, default_value); + + exit: + return return_value; +@@ -55,7 +55,7 @@ + PyObject *default_value); + + static PyObject * +-_gdbm_gdbm_setdefault(gdbmobject *self, PyObject *const *args, Py_ssize_t nargs) ++_gdbm_gdbm_setdefault(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *key; +@@ -70,7 +70,7 @@ + } + default_value = args[1]; + skip_optional: +- return_value = _gdbm_gdbm_setdefault_impl(self, key, default_value); ++ return_value = _gdbm_gdbm_setdefault_impl((gdbmobject *)self, key, default_value); + + exit: + return return_value; +@@ -89,9 +89,9 @@ + _gdbm_gdbm_close_impl(gdbmobject *self); + + static PyObject * +-_gdbm_gdbm_close(gdbmobject *self, PyObject *Py_UNUSED(ignored)) ++_gdbm_gdbm_close(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _gdbm_gdbm_close_impl(self); ++ return _gdbm_gdbm_close_impl((gdbmobject *)self); + } + + PyDoc_STRVAR(_gdbm_gdbm_keys__doc__, +@@ -107,13 +107,13 @@ + _gdbm_gdbm_keys_impl(gdbmobject *self, PyTypeObject *cls); + + static PyObject * +-_gdbm_gdbm_keys(gdbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_gdbm_gdbm_keys(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "keys() takes no arguments"); + return NULL; + } +- return _gdbm_gdbm_keys_impl(self, cls); ++ return _gdbm_gdbm_keys_impl((gdbmobject *)self, cls); + } + + PyDoc_STRVAR(_gdbm_gdbm_firstkey__doc__, +@@ -133,13 +133,13 @@ + _gdbm_gdbm_firstkey_impl(gdbmobject *self, PyTypeObject *cls); + + static PyObject * +-_gdbm_gdbm_firstkey(gdbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_gdbm_gdbm_firstkey(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "firstkey() takes no arguments"); + return NULL; + } +- return _gdbm_gdbm_firstkey_impl(self, cls); ++ return _gdbm_gdbm_firstkey_impl((gdbmobject *)self, cls); + } + + PyDoc_STRVAR(_gdbm_gdbm_nextkey__doc__, +@@ -164,7 +164,7 @@ + Py_ssize_t key_length); + + static PyObject * +-_gdbm_gdbm_nextkey(gdbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_gdbm_gdbm_nextkey(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -187,7 +187,7 @@ + &key, &key_length)) { + goto exit; + } +- return_value = _gdbm_gdbm_nextkey_impl(self, cls, key, key_length); ++ return_value = _gdbm_gdbm_nextkey_impl((gdbmobject *)self, cls, key, key_length); + + exit: + return return_value; +@@ -212,13 +212,13 @@ + _gdbm_gdbm_reorganize_impl(gdbmobject *self, PyTypeObject *cls); + + static PyObject * +-_gdbm_gdbm_reorganize(gdbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_gdbm_gdbm_reorganize(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "reorganize() takes no arguments"); + return NULL; + } +- return _gdbm_gdbm_reorganize_impl(self, cls); ++ return _gdbm_gdbm_reorganize_impl((gdbmobject *)self, cls); + } + + PyDoc_STRVAR(_gdbm_gdbm_sync__doc__, +@@ -237,13 +237,13 @@ + _gdbm_gdbm_sync_impl(gdbmobject *self, PyTypeObject *cls); + + static PyObject * +-_gdbm_gdbm_sync(gdbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_gdbm_gdbm_sync(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "sync() takes no arguments"); + return NULL; + } +- return _gdbm_gdbm_sync_impl(self, cls); ++ return _gdbm_gdbm_sync_impl((gdbmobject *)self, cls); + } + + PyDoc_STRVAR(_gdbm_gdbm_clear__doc__, +@@ -259,13 +259,13 @@ + _gdbm_gdbm_clear_impl(gdbmobject *self, PyTypeObject *cls); + + static PyObject * +-_gdbm_gdbm_clear(gdbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_gdbm_gdbm_clear(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "clear() takes no arguments"); + return NULL; + } +- return _gdbm_gdbm_clear_impl(self, cls); ++ return _gdbm_gdbm_clear_impl((gdbmobject *)self, cls); + } + + PyDoc_STRVAR(dbmopen__doc__, +@@ -343,4 +343,4 @@ + exit: + return return_value; + } +-/*[clinic end generated code: output=07bdeb4a8ecb328e input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=d974cb39e4ee5d67 input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/_hashopenssl.c.h b/Modules/clinic/_hashopenssl.c.h +index f54f065f7d2..d219b80b791 100644 +--- a/Modules/clinic/_hashopenssl.c.h ++++ b/Modules/clinic/_hashopenssl.c.h +@@ -22,9 +22,9 @@ + EVP_copy_impl(EVPobject *self); + + static PyObject * +-EVP_copy(EVPobject *self, PyObject *Py_UNUSED(ignored)) ++EVP_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return EVP_copy_impl(self); ++ return EVP_copy_impl((EVPobject *)self); + } + + PyDoc_STRVAR(EVP_digest__doc__, +@@ -40,9 +40,9 @@ + EVP_digest_impl(EVPobject *self); + + static PyObject * +-EVP_digest(EVPobject *self, PyObject *Py_UNUSED(ignored)) ++EVP_digest(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return EVP_digest_impl(self); ++ return EVP_digest_impl((EVPobject *)self); + } + + PyDoc_STRVAR(EVP_hexdigest__doc__, +@@ -58,9 +58,9 @@ + EVP_hexdigest_impl(EVPobject *self); + + static PyObject * +-EVP_hexdigest(EVPobject *self, PyObject *Py_UNUSED(ignored)) ++EVP_hexdigest(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return EVP_hexdigest_impl(self); ++ return EVP_hexdigest_impl((EVPobject *)self); + } + + PyDoc_STRVAR(EVP_update__doc__, +@@ -87,7 +87,7 @@ + EVPXOF_digest_impl(EVPobject *self, Py_ssize_t length); + + static PyObject * +-EVPXOF_digest(EVPobject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++EVPXOF_digest(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -135,7 +135,7 @@ + } + length = ival; + } +- return_value = EVPXOF_digest_impl(self, length); ++ return_value = EVPXOF_digest_impl((EVPobject *)self, length); + + exit: + return return_value; +@@ -158,7 +158,7 @@ + EVPXOF_hexdigest_impl(EVPobject *self, Py_ssize_t length); + + static PyObject * +-EVPXOF_hexdigest(EVPobject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++EVPXOF_hexdigest(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -206,7 +206,7 @@ + } + length = ival; + } +- return_value = EVPXOF_hexdigest_impl(self, length); ++ return_value = EVPXOF_hexdigest_impl((EVPobject *)self, length); + + exit: + return return_value; +@@ -1634,9 +1634,9 @@ + _hashlib_HMAC_copy_impl(HMACobject *self); + + static PyObject * +-_hashlib_HMAC_copy(HMACobject *self, PyObject *Py_UNUSED(ignored)) ++_hashlib_HMAC_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _hashlib_HMAC_copy_impl(self); ++ return _hashlib_HMAC_copy_impl((HMACobject *)self); + } + + PyDoc_STRVAR(_hashlib_HMAC_update__doc__, +@@ -1652,7 +1652,7 @@ + _hashlib_HMAC_update_impl(HMACobject *self, PyObject *msg); + + static PyObject * +-_hashlib_HMAC_update(HMACobject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_hashlib_HMAC_update(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -1689,7 +1689,7 @@ + goto exit; + } + msg = args[0]; +- return_value = _hashlib_HMAC_update_impl(self, msg); ++ return_value = _hashlib_HMAC_update_impl((HMACobject *)self, msg); + + exit: + return return_value; +@@ -1708,9 +1708,9 @@ + _hashlib_HMAC_digest_impl(HMACobject *self); + + static PyObject * +-_hashlib_HMAC_digest(HMACobject *self, PyObject *Py_UNUSED(ignored)) ++_hashlib_HMAC_digest(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _hashlib_HMAC_digest_impl(self); ++ return _hashlib_HMAC_digest_impl((HMACobject *)self); + } + + PyDoc_STRVAR(_hashlib_HMAC_hexdigest__doc__, +@@ -1729,9 +1729,9 @@ + _hashlib_HMAC_hexdigest_impl(HMACobject *self); + + static PyObject * +-_hashlib_HMAC_hexdigest(HMACobject *self, PyObject *Py_UNUSED(ignored)) ++_hashlib_HMAC_hexdigest(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _hashlib_HMAC_hexdigest_impl(self); ++ return _hashlib_HMAC_hexdigest_impl((HMACobject *)self); + } + + PyDoc_STRVAR(_hashlib_get_fips_mode__doc__, +@@ -1844,4 +1844,4 @@ + #ifndef _HASHLIB_SCRYPT_METHODDEF + #define _HASHLIB_SCRYPT_METHODDEF + #endif /* !defined(_HASHLIB_SCRYPT_METHODDEF) */ +-/*[clinic end generated code: output=c3ef67e4a573cc7a input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=811a8b50beae1018 input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/_lsprof.c.h b/Modules/clinic/_lsprof.c.h +index e19840f97e5..6a75a8f9833 100644 +--- a/Modules/clinic/_lsprof.c.h ++++ b/Modules/clinic/_lsprof.c.h +@@ -43,13 +43,13 @@ + _lsprof_Profiler_getstats_impl(ProfilerObject *self, PyTypeObject *cls); + + static PyObject * +-_lsprof_Profiler_getstats(ProfilerObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_lsprof_Profiler_getstats(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "getstats() takes no arguments"); + return NULL; + } +- return _lsprof_Profiler_getstats_impl(self, cls); ++ return _lsprof_Profiler_getstats_impl((ProfilerObject *)self, cls); + } + + PyDoc_STRVAR(_lsprof_Profiler__pystart_callback__doc__, +@@ -65,7 +65,7 @@ + PyObject *instruction_offset); + + static PyObject * +-_lsprof_Profiler__pystart_callback(ProfilerObject *self, PyObject *const *args, Py_ssize_t nargs) ++_lsprof_Profiler__pystart_callback(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *code; +@@ -76,7 +76,7 @@ + } + code = args[0]; + instruction_offset = args[1]; +- return_value = _lsprof_Profiler__pystart_callback_impl(self, code, instruction_offset); ++ return_value = _lsprof_Profiler__pystart_callback_impl((ProfilerObject *)self, code, instruction_offset); + + exit: + return return_value; +@@ -97,7 +97,7 @@ + PyObject *retval); + + static PyObject * +-_lsprof_Profiler__pyreturn_callback(ProfilerObject *self, PyObject *const *args, Py_ssize_t nargs) ++_lsprof_Profiler__pyreturn_callback(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *code; +@@ -110,7 +110,7 @@ + code = args[0]; + instruction_offset = args[1]; + retval = args[2]; +- return_value = _lsprof_Profiler__pyreturn_callback_impl(self, code, instruction_offset, retval); ++ return_value = _lsprof_Profiler__pyreturn_callback_impl((ProfilerObject *)self, code, instruction_offset, retval); + + exit: + return return_value; +@@ -130,7 +130,7 @@ + PyObject *callable, PyObject *self_arg); + + static PyObject * +-_lsprof_Profiler__ccall_callback(ProfilerObject *self, PyObject *const *args, Py_ssize_t nargs) ++_lsprof_Profiler__ccall_callback(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *code; +@@ -145,7 +145,7 @@ + instruction_offset = args[1]; + callable = args[2]; + self_arg = args[3]; +- return_value = _lsprof_Profiler__ccall_callback_impl(self, code, instruction_offset, callable, self_arg); ++ return_value = _lsprof_Profiler__ccall_callback_impl((ProfilerObject *)self, code, instruction_offset, callable, self_arg); + + exit: + return return_value; +@@ -167,7 +167,7 @@ + PyObject *self_arg); + + static PyObject * +-_lsprof_Profiler__creturn_callback(ProfilerObject *self, PyObject *const *args, Py_ssize_t nargs) ++_lsprof_Profiler__creturn_callback(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *code; +@@ -182,7 +182,7 @@ + instruction_offset = args[1]; + callable = args[2]; + self_arg = args[3]; +- return_value = _lsprof_Profiler__creturn_callback_impl(self, code, instruction_offset, callable, self_arg); ++ return_value = _lsprof_Profiler__creturn_callback_impl((ProfilerObject *)self, code, instruction_offset, callable, self_arg); + + exit: + return return_value; +@@ -209,7 +209,7 @@ + int builtins); + + static PyObject * +-_lsprof_Profiler_enable(ProfilerObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_lsprof_Profiler_enable(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -264,7 +264,7 @@ + goto exit; + } + skip_optional_pos: +- return_value = _lsprof_Profiler_enable_impl(self, subcalls, builtins); ++ return_value = _lsprof_Profiler_enable_impl((ProfilerObject *)self, subcalls, builtins); + + exit: + return return_value; +@@ -283,9 +283,9 @@ + _lsprof_Profiler_disable_impl(ProfilerObject *self); + + static PyObject * +-_lsprof_Profiler_disable(ProfilerObject *self, PyObject *Py_UNUSED(ignored)) ++_lsprof_Profiler_disable(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _lsprof_Profiler_disable_impl(self); ++ return _lsprof_Profiler_disable_impl((ProfilerObject *)self); + } + + PyDoc_STRVAR(_lsprof_Profiler_clear__doc__, +@@ -301,9 +301,9 @@ + _lsprof_Profiler_clear_impl(ProfilerObject *self); + + static PyObject * +-_lsprof_Profiler_clear(ProfilerObject *self, PyObject *Py_UNUSED(ignored)) ++_lsprof_Profiler_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _lsprof_Profiler_clear_impl(self); ++ return _lsprof_Profiler_clear_impl((ProfilerObject *)self); + } + + PyDoc_STRVAR(profiler_init__doc__, +@@ -407,4 +407,4 @@ + exit: + return return_value; + } +-/*[clinic end generated code: output=e56d849e35d005a5 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=d983dbf23fd8ac3b input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/_lzmamodule.c.h b/Modules/clinic/_lzmamodule.c.h +index 187f7b183dc..c7c81d8d1f1 100644 +--- a/Modules/clinic/_lzmamodule.c.h ++++ b/Modules/clinic/_lzmamodule.c.h +@@ -27,7 +27,7 @@ + _lzma_LZMACompressor_compress_impl(Compressor *self, Py_buffer *data); + + static PyObject * +-_lzma_LZMACompressor_compress(Compressor *self, PyObject *arg) ++_lzma_LZMACompressor_compress(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; +@@ -35,7 +35,7 @@ + if (PyObject_GetBuffer(arg, &data, PyBUF_SIMPLE) != 0) { + goto exit; + } +- return_value = _lzma_LZMACompressor_compress_impl(self, &data); ++ return_value = _lzma_LZMACompressor_compress_impl((Compressor *)self, &data); + + exit: + /* Cleanup for data */ +@@ -63,9 +63,9 @@ + _lzma_LZMACompressor_flush_impl(Compressor *self); + + static PyObject * +-_lzma_LZMACompressor_flush(Compressor *self, PyObject *Py_UNUSED(ignored)) ++_lzma_LZMACompressor_flush(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _lzma_LZMACompressor_flush_impl(self); ++ return _lzma_LZMACompressor_flush_impl((Compressor *)self); + } + + PyDoc_STRVAR(_lzma_LZMADecompressor_decompress__doc__, +@@ -95,7 +95,7 @@ + Py_ssize_t max_length); + + static PyObject * +-_lzma_LZMADecompressor_decompress(Decompressor *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_lzma_LZMADecompressor_decompress(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -152,7 +152,7 @@ + max_length = ival; + } + skip_optional_pos: +- return_value = _lzma_LZMADecompressor_decompress_impl(self, &data, max_length); ++ return_value = _lzma_LZMADecompressor_decompress_impl((Decompressor *)self, &data, max_length); + + exit: + /* Cleanup for data */ +@@ -329,4 +329,4 @@ + + return return_value; + } +-/*[clinic end generated code: output=52e1b68d0886cebb input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=19ed9b1182f5ddf9 input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/_pickle.c.h b/Modules/clinic/_pickle.c.h +index 2e84bb83e21..91d355c5afb 100644 +--- a/Modules/clinic/_pickle.c.h ++++ b/Modules/clinic/_pickle.c.h +@@ -26,9 +26,9 @@ + _pickle_Pickler_clear_memo_impl(PicklerObject *self); + + static PyObject * +-_pickle_Pickler_clear_memo(PicklerObject *self, PyObject *Py_UNUSED(ignored)) ++_pickle_Pickler_clear_memo(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _pickle_Pickler_clear_memo_impl(self); ++ return _pickle_Pickler_clear_memo_impl((PicklerObject *)self); + } + + PyDoc_STRVAR(_pickle_Pickler_dump__doc__, +@@ -45,7 +45,7 @@ + PyObject *obj); + + static PyObject * +-_pickle_Pickler_dump(PicklerObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_pickle_Pickler_dump(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -70,7 +70,7 @@ + goto exit; + } + obj = args[0]; +- return_value = _pickle_Pickler_dump_impl(self, cls, obj); ++ return_value = _pickle_Pickler_dump_impl((PicklerObject *)self, cls, obj); + + exit: + return return_value; +@@ -89,12 +89,12 @@ + _pickle_Pickler___sizeof___impl(PicklerObject *self); + + static PyObject * +-_pickle_Pickler___sizeof__(PicklerObject *self, PyObject *Py_UNUSED(ignored)) ++_pickle_Pickler___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + size_t _return_value; + +- _return_value = _pickle_Pickler___sizeof___impl(self); ++ _return_value = _pickle_Pickler___sizeof___impl((PicklerObject *)self); + if ((_return_value == (size_t)-1) && PyErr_Occurred()) { + goto exit; + } +@@ -227,9 +227,9 @@ + _pickle_PicklerMemoProxy_clear_impl(PicklerMemoProxyObject *self); + + static PyObject * +-_pickle_PicklerMemoProxy_clear(PicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) ++_pickle_PicklerMemoProxy_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _pickle_PicklerMemoProxy_clear_impl(self); ++ return _pickle_PicklerMemoProxy_clear_impl((PicklerMemoProxyObject *)self); + } + + PyDoc_STRVAR(_pickle_PicklerMemoProxy_copy__doc__, +@@ -245,9 +245,9 @@ + _pickle_PicklerMemoProxy_copy_impl(PicklerMemoProxyObject *self); + + static PyObject * +-_pickle_PicklerMemoProxy_copy(PicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) ++_pickle_PicklerMemoProxy_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _pickle_PicklerMemoProxy_copy_impl(self); ++ return _pickle_PicklerMemoProxy_copy_impl((PicklerMemoProxyObject *)self); + } + + PyDoc_STRVAR(_pickle_PicklerMemoProxy___reduce____doc__, +@@ -263,9 +263,9 @@ + _pickle_PicklerMemoProxy___reduce___impl(PicklerMemoProxyObject *self); + + static PyObject * +-_pickle_PicklerMemoProxy___reduce__(PicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) ++_pickle_PicklerMemoProxy___reduce__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _pickle_PicklerMemoProxy___reduce___impl(self); ++ return _pickle_PicklerMemoProxy___reduce___impl((PicklerMemoProxyObject *)self); + } + + PyDoc_STRVAR(_pickle_Unpickler_persistent_load__doc__, +@@ -281,7 +281,7 @@ + PyTypeObject *cls, PyObject *pid); + + static PyObject * +-_pickle_Unpickler_persistent_load(UnpicklerObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_pickle_Unpickler_persistent_load(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -306,7 +306,7 @@ + goto exit; + } + pid = args[0]; +- return_value = _pickle_Unpickler_persistent_load_impl(self, cls, pid); ++ return_value = _pickle_Unpickler_persistent_load_impl((UnpicklerObject *)self, cls, pid); + + exit: + return return_value; +@@ -329,13 +329,13 @@ + _pickle_Unpickler_load_impl(UnpicklerObject *self, PyTypeObject *cls); + + static PyObject * +-_pickle_Unpickler_load(UnpicklerObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_pickle_Unpickler_load(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "load() takes no arguments"); + return NULL; + } +- return _pickle_Unpickler_load_impl(self, cls); ++ return _pickle_Unpickler_load_impl((UnpicklerObject *)self, cls); + } + + PyDoc_STRVAR(_pickle_Unpickler_find_class__doc__, +@@ -360,7 +360,7 @@ + PyObject *global_name); + + static PyObject * +-_pickle_Unpickler_find_class(UnpicklerObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_pickle_Unpickler_find_class(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -387,7 +387,7 @@ + } + module_name = args[0]; + global_name = args[1]; +- return_value = _pickle_Unpickler_find_class_impl(self, cls, module_name, global_name); ++ return_value = _pickle_Unpickler_find_class_impl((UnpicklerObject *)self, cls, module_name, global_name); + + exit: + return return_value; +@@ -406,12 +406,12 @@ + _pickle_Unpickler___sizeof___impl(UnpicklerObject *self); + + static PyObject * +-_pickle_Unpickler___sizeof__(UnpicklerObject *self, PyObject *Py_UNUSED(ignored)) ++_pickle_Unpickler___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + size_t _return_value; + +- _return_value = _pickle_Unpickler___sizeof___impl(self); ++ _return_value = _pickle_Unpickler___sizeof___impl((UnpicklerObject *)self); + if ((_return_value == (size_t)-1) && PyErr_Occurred()) { + goto exit; + } +@@ -566,9 +566,9 @@ + _pickle_UnpicklerMemoProxy_clear_impl(UnpicklerMemoProxyObject *self); + + static PyObject * +-_pickle_UnpicklerMemoProxy_clear(UnpicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) ++_pickle_UnpicklerMemoProxy_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _pickle_UnpicklerMemoProxy_clear_impl(self); ++ return _pickle_UnpicklerMemoProxy_clear_impl((UnpicklerMemoProxyObject *)self); + } + + PyDoc_STRVAR(_pickle_UnpicklerMemoProxy_copy__doc__, +@@ -584,9 +584,9 @@ + _pickle_UnpicklerMemoProxy_copy_impl(UnpicklerMemoProxyObject *self); + + static PyObject * +-_pickle_UnpicklerMemoProxy_copy(UnpicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) ++_pickle_UnpicklerMemoProxy_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _pickle_UnpicklerMemoProxy_copy_impl(self); ++ return _pickle_UnpicklerMemoProxy_copy_impl((UnpicklerMemoProxyObject *)self); + } + + PyDoc_STRVAR(_pickle_UnpicklerMemoProxy___reduce____doc__, +@@ -602,9 +602,9 @@ + _pickle_UnpicklerMemoProxy___reduce___impl(UnpicklerMemoProxyObject *self); + + static PyObject * +-_pickle_UnpicklerMemoProxy___reduce__(UnpicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) ++_pickle_UnpicklerMemoProxy___reduce__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _pickle_UnpicklerMemoProxy___reduce___impl(self); ++ return _pickle_UnpicklerMemoProxy___reduce___impl((UnpicklerMemoProxyObject *)self); + } + + PyDoc_STRVAR(_pickle_dump__doc__, +@@ -1086,4 +1086,4 @@ + exit: + return return_value; + } +-/*[clinic end generated code: output=48ceb6687a8e716c input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=d71dc73af298ebe8 input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/_queuemodule.c.h b/Modules/clinic/_queuemodule.c.h +index f0d4a3a164c..2dfc3e6be19 100644 +--- a/Modules/clinic/_queuemodule.c.h ++++ b/Modules/clinic/_queuemodule.c.h +@@ -55,7 +55,7 @@ + int block, PyObject *timeout); + + static PyObject * +-_queue_SimpleQueue_put(simplequeueobject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_queue_SimpleQueue_put(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -110,7 +110,7 @@ + timeout = args[2]; + skip_optional_pos: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _queue_SimpleQueue_put_impl(self, item, block, timeout); ++ return_value = _queue_SimpleQueue_put_impl((simplequeueobject *)self, item, block, timeout); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -133,7 +133,7 @@ + _queue_SimpleQueue_put_nowait_impl(simplequeueobject *self, PyObject *item); + + static PyObject * +-_queue_SimpleQueue_put_nowait(simplequeueobject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_queue_SimpleQueue_put_nowait(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -171,7 +171,7 @@ + } + item = args[0]; + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _queue_SimpleQueue_put_nowait_impl(self, item); ++ return_value = _queue_SimpleQueue_put_nowait_impl((simplequeueobject *)self, item); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -200,7 +200,7 @@ + int block, PyObject *timeout_obj); + + static PyObject * +-_queue_SimpleQueue_get(simplequeueobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_queue_SimpleQueue_get(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -253,7 +253,7 @@ + timeout_obj = args[1]; + skip_optional_pos: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _queue_SimpleQueue_get_impl(self, cls, block, timeout_obj); ++ return_value = _queue_SimpleQueue_get_impl((simplequeueobject *)self, cls, block, timeout_obj); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -277,7 +277,7 @@ + PyTypeObject *cls); + + static PyObject * +-_queue_SimpleQueue_get_nowait(simplequeueobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_queue_SimpleQueue_get_nowait(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + +@@ -286,7 +286,7 @@ + goto exit; + } + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _queue_SimpleQueue_get_nowait_impl(self, cls); ++ return_value = _queue_SimpleQueue_get_nowait_impl((simplequeueobject *)self, cls); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -306,13 +306,13 @@ + _queue_SimpleQueue_empty_impl(simplequeueobject *self); + + static PyObject * +-_queue_SimpleQueue_empty(simplequeueobject *self, PyObject *Py_UNUSED(ignored)) ++_queue_SimpleQueue_empty(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + int _return_value; + + Py_BEGIN_CRITICAL_SECTION(self); +- _return_value = _queue_SimpleQueue_empty_impl(self); ++ _return_value = _queue_SimpleQueue_empty_impl((simplequeueobject *)self); + Py_END_CRITICAL_SECTION(); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; +@@ -336,13 +336,13 @@ + _queue_SimpleQueue_qsize_impl(simplequeueobject *self); + + static PyObject * +-_queue_SimpleQueue_qsize(simplequeueobject *self, PyObject *Py_UNUSED(ignored)) ++_queue_SimpleQueue_qsize(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + Py_ssize_t _return_value; + + Py_BEGIN_CRITICAL_SECTION(self); +- _return_value = _queue_SimpleQueue_qsize_impl(self); ++ _return_value = _queue_SimpleQueue_qsize_impl((simplequeueobject *)self); + Py_END_CRITICAL_SECTION(); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; +@@ -352,4 +352,4 @@ + exit: + return return_value; + } +-/*[clinic end generated code: output=07b5742dca7692d9 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=e04e15a1b959c700 input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/_randommodule.c.h b/Modules/clinic/_randommodule.c.h +index 6193acac67e..b2d67e11c63 100644 +--- a/Modules/clinic/_randommodule.c.h ++++ b/Modules/clinic/_randommodule.c.h +@@ -18,12 +18,12 @@ + _random_Random_random_impl(RandomObject *self); + + static PyObject * +-_random_Random_random(RandomObject *self, PyObject *Py_UNUSED(ignored)) ++_random_Random_random(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _random_Random_random_impl(self); ++ return_value = _random_Random_random_impl((RandomObject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -45,7 +45,7 @@ + _random_Random_seed_impl(RandomObject *self, PyObject *n); + + static PyObject * +-_random_Random_seed(RandomObject *self, PyObject *const *args, Py_ssize_t nargs) ++_random_Random_seed(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *n = Py_None; +@@ -59,7 +59,7 @@ + n = args[0]; + skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _random_Random_seed_impl(self, n); ++ return_value = _random_Random_seed_impl((RandomObject *)self, n); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -79,12 +79,12 @@ + _random_Random_getstate_impl(RandomObject *self); + + static PyObject * +-_random_Random_getstate(RandomObject *self, PyObject *Py_UNUSED(ignored)) ++_random_Random_getstate(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _random_Random_getstate_impl(self); ++ return_value = _random_Random_getstate_impl((RandomObject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -108,7 +108,7 @@ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _random_Random_setstate_impl(self, state); ++ return_value = _random_Random_setstate_impl((RandomObject *)self, state); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -127,7 +127,7 @@ + _random_Random_getrandbits_impl(RandomObject *self, int k); + + static PyObject * +-_random_Random_getrandbits(RandomObject *self, PyObject *arg) ++_random_Random_getrandbits(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + int k; +@@ -137,10 +137,10 @@ + goto exit; + } + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _random_Random_getrandbits_impl(self, k); ++ return_value = _random_Random_getrandbits_impl((RandomObject *)self, k); + Py_END_CRITICAL_SECTION(); + + exit: + return return_value; + } +-/*[clinic end generated code: output=bf49ece1d341b1b6 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=859cfbf59c133a4e input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/_ssl.c.h b/Modules/clinic/_ssl.c.h +index 1ff85e32ffe..73c5d304f1a 100644 +--- a/Modules/clinic/_ssl.c.h ++++ b/Modules/clinic/_ssl.c.h +@@ -21,12 +21,12 @@ + _ssl__SSLSocket_do_handshake_impl(PySSLSocket *self); + + static PyObject * +-_ssl__SSLSocket_do_handshake(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) ++_ssl__SSLSocket_do_handshake(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLSocket_do_handshake_impl(self); ++ return_value = _ssl__SSLSocket_do_handshake_impl((PySSLSocket *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -79,7 +79,7 @@ + _ssl__SSLSocket_getpeercert_impl(PySSLSocket *self, int binary_mode); + + static PyObject * +-_ssl__SSLSocket_getpeercert(PySSLSocket *self, PyObject *const *args, Py_ssize_t nargs) ++_ssl__SSLSocket_getpeercert(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + int binary_mode = 0; +@@ -96,7 +96,7 @@ + } + skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLSocket_getpeercert_impl(self, binary_mode); ++ return_value = _ssl__SSLSocket_getpeercert_impl((PySSLSocket *)self, binary_mode); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -115,12 +115,12 @@ + _ssl__SSLSocket_get_verified_chain_impl(PySSLSocket *self); + + static PyObject * +-_ssl__SSLSocket_get_verified_chain(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) ++_ssl__SSLSocket_get_verified_chain(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLSocket_get_verified_chain_impl(self); ++ return_value = _ssl__SSLSocket_get_verified_chain_impl((PySSLSocket *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -138,12 +138,12 @@ + _ssl__SSLSocket_get_unverified_chain_impl(PySSLSocket *self); + + static PyObject * +-_ssl__SSLSocket_get_unverified_chain(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) ++_ssl__SSLSocket_get_unverified_chain(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLSocket_get_unverified_chain_impl(self); ++ return_value = _ssl__SSLSocket_get_unverified_chain_impl((PySSLSocket *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -161,12 +161,12 @@ + _ssl__SSLSocket_shared_ciphers_impl(PySSLSocket *self); + + static PyObject * +-_ssl__SSLSocket_shared_ciphers(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) ++_ssl__SSLSocket_shared_ciphers(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLSocket_shared_ciphers_impl(self); ++ return_value = _ssl__SSLSocket_shared_ciphers_impl((PySSLSocket *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -184,12 +184,12 @@ + _ssl__SSLSocket_cipher_impl(PySSLSocket *self); + + static PyObject * +-_ssl__SSLSocket_cipher(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) ++_ssl__SSLSocket_cipher(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLSocket_cipher_impl(self); ++ return_value = _ssl__SSLSocket_cipher_impl((PySSLSocket *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -207,12 +207,12 @@ + _ssl__SSLSocket_version_impl(PySSLSocket *self); + + static PyObject * +-_ssl__SSLSocket_version(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) ++_ssl__SSLSocket_version(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLSocket_version_impl(self); ++ return_value = _ssl__SSLSocket_version_impl((PySSLSocket *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -230,12 +230,12 @@ + _ssl__SSLSocket_selected_alpn_protocol_impl(PySSLSocket *self); + + static PyObject * +-_ssl__SSLSocket_selected_alpn_protocol(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) ++_ssl__SSLSocket_selected_alpn_protocol(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLSocket_selected_alpn_protocol_impl(self); ++ return_value = _ssl__SSLSocket_selected_alpn_protocol_impl((PySSLSocket *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -253,9 +253,9 @@ + _ssl__SSLSocket_compression_impl(PySSLSocket *self); + + static PyObject * +-_ssl__SSLSocket_compression(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) ++_ssl__SSLSocket_compression(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _ssl__SSLSocket_compression_impl(self); ++ return _ssl__SSLSocket_compression_impl((PySSLSocket *)self); + } + + PyDoc_STRVAR(_ssl__SSLSocket_context__doc__, +@@ -264,6 +264,9 @@ + "This is typically used from within a callback function set by the sni_callback\n" + "on the SSLContext to change the certificate information associated with the\n" + "SSLSocket before the cryptographic exchange handshake messages."); ++#if defined(_ssl__SSLSocket_context_DOCSTR) ++# undef _ssl__SSLSocket_context_DOCSTR ++#endif + #define _ssl__SSLSocket_context_DOCSTR _ssl__SSLSocket_context__doc__ + + #if !defined(_ssl__SSLSocket_context_DOCSTR) +@@ -280,12 +283,12 @@ + _ssl__SSLSocket_context_get_impl(PySSLSocket *self); + + static PyObject * +-_ssl__SSLSocket_context_get(PySSLSocket *self, void *Py_UNUSED(context)) ++_ssl__SSLSocket_context_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLSocket_context_get_impl(self); ++ return_value = _ssl__SSLSocket_context_get_impl((PySSLSocket *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -305,12 +308,12 @@ + _ssl__SSLSocket_context_set_impl(PySSLSocket *self, PyObject *value); + + static int +-_ssl__SSLSocket_context_set(PySSLSocket *self, PyObject *value, void *Py_UNUSED(context)) ++_ssl__SSLSocket_context_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) + { + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLSocket_context_set_impl(self, value); ++ return_value = _ssl__SSLSocket_context_set_impl((PySSLSocket *)self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -318,6 +321,9 @@ + + PyDoc_STRVAR(_ssl__SSLSocket_server_side__doc__, + "Whether this is a server-side socket."); ++#if defined(_ssl__SSLSocket_server_side_DOCSTR) ++# undef _ssl__SSLSocket_server_side_DOCSTR ++#endif + #define _ssl__SSLSocket_server_side_DOCSTR _ssl__SSLSocket_server_side__doc__ + + #if !defined(_ssl__SSLSocket_server_side_DOCSTR) +@@ -334,12 +340,12 @@ + _ssl__SSLSocket_server_side_get_impl(PySSLSocket *self); + + static PyObject * +-_ssl__SSLSocket_server_side_get(PySSLSocket *self, void *Py_UNUSED(context)) ++_ssl__SSLSocket_server_side_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLSocket_server_side_get_impl(self); ++ return_value = _ssl__SSLSocket_server_side_get_impl((PySSLSocket *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -347,6 +353,9 @@ + + PyDoc_STRVAR(_ssl__SSLSocket_server_hostname__doc__, + "The currently set server hostname (for SNI)."); ++#if defined(_ssl__SSLSocket_server_hostname_DOCSTR) ++# undef _ssl__SSLSocket_server_hostname_DOCSTR ++#endif + #define _ssl__SSLSocket_server_hostname_DOCSTR _ssl__SSLSocket_server_hostname__doc__ + + #if !defined(_ssl__SSLSocket_server_hostname_DOCSTR) +@@ -363,12 +372,12 @@ + _ssl__SSLSocket_server_hostname_get_impl(PySSLSocket *self); + + static PyObject * +-_ssl__SSLSocket_server_hostname_get(PySSLSocket *self, void *Py_UNUSED(context)) ++_ssl__SSLSocket_server_hostname_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLSocket_server_hostname_get_impl(self); ++ return_value = _ssl__SSLSocket_server_hostname_get_impl((PySSLSocket *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -378,6 +387,9 @@ + "The Python-level owner of this object.\n" + "\n" + "Passed as \"self\" in servername callback."); ++#if defined(_ssl__SSLSocket_owner_DOCSTR) ++# undef _ssl__SSLSocket_owner_DOCSTR ++#endif + #define _ssl__SSLSocket_owner_DOCSTR _ssl__SSLSocket_owner__doc__ + + #if !defined(_ssl__SSLSocket_owner_DOCSTR) +@@ -394,12 +406,12 @@ + _ssl__SSLSocket_owner_get_impl(PySSLSocket *self); + + static PyObject * +-_ssl__SSLSocket_owner_get(PySSLSocket *self, void *Py_UNUSED(context)) ++_ssl__SSLSocket_owner_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLSocket_owner_get_impl(self); ++ return_value = _ssl__SSLSocket_owner_get_impl((PySSLSocket *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -419,12 +431,12 @@ + _ssl__SSLSocket_owner_set_impl(PySSLSocket *self, PyObject *value); + + static int +-_ssl__SSLSocket_owner_set(PySSLSocket *self, PyObject *value, void *Py_UNUSED(context)) ++_ssl__SSLSocket_owner_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) + { + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLSocket_owner_set_impl(self, value); ++ return_value = _ssl__SSLSocket_owner_set_impl((PySSLSocket *)self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -445,7 +457,7 @@ + _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b); + + static PyObject * +-_ssl__SSLSocket_write(PySSLSocket *self, PyObject *arg) ++_ssl__SSLSocket_write(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + Py_buffer b = {NULL, NULL}; +@@ -454,7 +466,7 @@ + goto exit; + } + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLSocket_write_impl(self, &b); ++ return_value = _ssl__SSLSocket_write_impl((PySSLSocket *)self, &b); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -479,12 +491,12 @@ + _ssl__SSLSocket_pending_impl(PySSLSocket *self); + + static PyObject * +-_ssl__SSLSocket_pending(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) ++_ssl__SSLSocket_pending(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLSocket_pending_impl(self); ++ return_value = _ssl__SSLSocket_pending_impl((PySSLSocket *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -502,7 +514,7 @@ + int group_right_1, Py_buffer *buffer); + + static PyObject * +-_ssl__SSLSocket_read(PySSLSocket *self, PyObject *args) ++_ssl__SSLSocket_read(PyObject *self, PyObject *args) + { + PyObject *return_value = NULL; + Py_ssize_t len; +@@ -526,7 +538,7 @@ + goto exit; + } + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLSocket_read_impl(self, len, group_right_1, &buffer); ++ return_value = _ssl__SSLSocket_read_impl((PySSLSocket *)self, len, group_right_1, &buffer); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -551,12 +563,12 @@ + _ssl__SSLSocket_shutdown_impl(PySSLSocket *self); + + static PyObject * +-_ssl__SSLSocket_shutdown(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) ++_ssl__SSLSocket_shutdown(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLSocket_shutdown_impl(self); ++ return_value = _ssl__SSLSocket_shutdown_impl((PySSLSocket *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -580,7 +592,7 @@ + const char *cb_type); + + static PyObject * +-_ssl__SSLSocket_get_channel_binding(PySSLSocket *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_ssl__SSLSocket_get_channel_binding(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -635,7 +647,7 @@ + } + skip_optional_pos: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLSocket_get_channel_binding_impl(self, cb_type); ++ return_value = _ssl__SSLSocket_get_channel_binding_impl((PySSLSocket *)self, cb_type); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -655,12 +667,12 @@ + _ssl__SSLSocket_verify_client_post_handshake_impl(PySSLSocket *self); + + static PyObject * +-_ssl__SSLSocket_verify_client_post_handshake(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) ++_ssl__SSLSocket_verify_client_post_handshake(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLSocket_verify_client_post_handshake_impl(self); ++ return_value = _ssl__SSLSocket_verify_client_post_handshake_impl((PySSLSocket *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -668,6 +680,9 @@ + + PyDoc_STRVAR(_ssl__SSLSocket_session__doc__, + "The underlying SSLSession object."); ++#if defined(_ssl__SSLSocket_session_DOCSTR) ++# undef _ssl__SSLSocket_session_DOCSTR ++#endif + #define _ssl__SSLSocket_session_DOCSTR _ssl__SSLSocket_session__doc__ + + #if !defined(_ssl__SSLSocket_session_DOCSTR) +@@ -684,12 +699,12 @@ + _ssl__SSLSocket_session_get_impl(PySSLSocket *self); + + static PyObject * +-_ssl__SSLSocket_session_get(PySSLSocket *self, void *Py_UNUSED(context)) ++_ssl__SSLSocket_session_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLSocket_session_get_impl(self); ++ return_value = _ssl__SSLSocket_session_get_impl((PySSLSocket *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -709,12 +724,12 @@ + _ssl__SSLSocket_session_set_impl(PySSLSocket *self, PyObject *value); + + static int +-_ssl__SSLSocket_session_set(PySSLSocket *self, PyObject *value, void *Py_UNUSED(context)) ++_ssl__SSLSocket_session_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) + { + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLSocket_session_set_impl(self, value); ++ return_value = _ssl__SSLSocket_session_set_impl((PySSLSocket *)self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -722,6 +737,9 @@ + + PyDoc_STRVAR(_ssl__SSLSocket_session_reused__doc__, + "Was the client session reused during handshake?"); ++#if defined(_ssl__SSLSocket_session_reused_DOCSTR) ++# undef _ssl__SSLSocket_session_reused_DOCSTR ++#endif + #define _ssl__SSLSocket_session_reused_DOCSTR _ssl__SSLSocket_session_reused__doc__ + + #if !defined(_ssl__SSLSocket_session_reused_DOCSTR) +@@ -738,12 +756,12 @@ + _ssl__SSLSocket_session_reused_get_impl(PySSLSocket *self); + + static PyObject * +-_ssl__SSLSocket_session_reused_get(PySSLSocket *self, void *Py_UNUSED(context)) ++_ssl__SSLSocket_session_reused_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLSocket_session_reused_get_impl(self); ++ return_value = _ssl__SSLSocket_session_reused_get_impl((PySSLSocket *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -790,7 +808,7 @@ + _ssl__SSLContext_set_ciphers_impl(PySSLContext *self, const char *cipherlist); + + static PyObject * +-_ssl__SSLContext_set_ciphers(PySSLContext *self, PyObject *arg) ++_ssl__SSLContext_set_ciphers(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + const char *cipherlist; +@@ -809,7 +827,7 @@ + goto exit; + } + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_set_ciphers_impl(self, cipherlist); ++ return_value = _ssl__SSLContext_set_ciphers_impl((PySSLContext *)self, cipherlist); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -828,12 +846,12 @@ + _ssl__SSLContext_get_ciphers_impl(PySSLContext *self); + + static PyObject * +-_ssl__SSLContext_get_ciphers(PySSLContext *self, PyObject *Py_UNUSED(ignored)) ++_ssl__SSLContext_get_ciphers(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_get_ciphers_impl(self); ++ return_value = _ssl__SSLContext_get_ciphers_impl((PySSLContext *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -852,7 +870,7 @@ + Py_buffer *protos); + + static PyObject * +-_ssl__SSLContext__set_alpn_protocols(PySSLContext *self, PyObject *arg) ++_ssl__SSLContext__set_alpn_protocols(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + Py_buffer protos = {NULL, NULL}; +@@ -861,7 +879,7 @@ + goto exit; + } + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext__set_alpn_protocols_impl(self, &protos); ++ return_value = _ssl__SSLContext__set_alpn_protocols_impl((PySSLContext *)self, &protos); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -887,12 +905,12 @@ + _ssl__SSLContext_verify_mode_get_impl(PySSLContext *self); + + static PyObject * +-_ssl__SSLContext_verify_mode_get(PySSLContext *self, void *Py_UNUSED(context)) ++_ssl__SSLContext_verify_mode_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_verify_mode_get_impl(self); ++ return_value = _ssl__SSLContext_verify_mode_get_impl((PySSLContext *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -912,12 +930,12 @@ + _ssl__SSLContext_verify_mode_set_impl(PySSLContext *self, PyObject *value); + + static int +-_ssl__SSLContext_verify_mode_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) ++_ssl__SSLContext_verify_mode_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) + { + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_verify_mode_set_impl(self, value); ++ return_value = _ssl__SSLContext_verify_mode_set_impl((PySSLContext *)self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -937,12 +955,12 @@ + _ssl__SSLContext_verify_flags_get_impl(PySSLContext *self); + + static PyObject * +-_ssl__SSLContext_verify_flags_get(PySSLContext *self, void *Py_UNUSED(context)) ++_ssl__SSLContext_verify_flags_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_verify_flags_get_impl(self); ++ return_value = _ssl__SSLContext_verify_flags_get_impl((PySSLContext *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -962,12 +980,12 @@ + _ssl__SSLContext_verify_flags_set_impl(PySSLContext *self, PyObject *value); + + static int +-_ssl__SSLContext_verify_flags_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) ++_ssl__SSLContext_verify_flags_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) + { + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_verify_flags_set_impl(self, value); ++ return_value = _ssl__SSLContext_verify_flags_set_impl((PySSLContext *)self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -987,12 +1005,12 @@ + _ssl__SSLContext_minimum_version_get_impl(PySSLContext *self); + + static PyObject * +-_ssl__SSLContext_minimum_version_get(PySSLContext *self, void *Py_UNUSED(context)) ++_ssl__SSLContext_minimum_version_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_minimum_version_get_impl(self); ++ return_value = _ssl__SSLContext_minimum_version_get_impl((PySSLContext *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1013,12 +1031,12 @@ + PyObject *value); + + static int +-_ssl__SSLContext_minimum_version_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) ++_ssl__SSLContext_minimum_version_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) + { + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_minimum_version_set_impl(self, value); ++ return_value = _ssl__SSLContext_minimum_version_set_impl((PySSLContext *)self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1038,12 +1056,12 @@ + _ssl__SSLContext_maximum_version_get_impl(PySSLContext *self); + + static PyObject * +-_ssl__SSLContext_maximum_version_get(PySSLContext *self, void *Py_UNUSED(context)) ++_ssl__SSLContext_maximum_version_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_maximum_version_get_impl(self); ++ return_value = _ssl__SSLContext_maximum_version_get_impl((PySSLContext *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1064,12 +1082,12 @@ + PyObject *value); + + static int +-_ssl__SSLContext_maximum_version_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) ++_ssl__SSLContext_maximum_version_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) + { + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_maximum_version_set_impl(self, value); ++ return_value = _ssl__SSLContext_maximum_version_set_impl((PySSLContext *)self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1077,6 +1095,9 @@ + + PyDoc_STRVAR(_ssl__SSLContext_num_tickets__doc__, + "Control the number of TLSv1.3 session tickets."); ++#if defined(_ssl__SSLContext_num_tickets_DOCSTR) ++# undef _ssl__SSLContext_num_tickets_DOCSTR ++#endif + #define _ssl__SSLContext_num_tickets_DOCSTR _ssl__SSLContext_num_tickets__doc__ + + #if !defined(_ssl__SSLContext_num_tickets_DOCSTR) +@@ -1093,12 +1114,12 @@ + _ssl__SSLContext_num_tickets_get_impl(PySSLContext *self); + + static PyObject * +-_ssl__SSLContext_num_tickets_get(PySSLContext *self, void *Py_UNUSED(context)) ++_ssl__SSLContext_num_tickets_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_num_tickets_get_impl(self); ++ return_value = _ssl__SSLContext_num_tickets_get_impl((PySSLContext *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1118,12 +1139,12 @@ + _ssl__SSLContext_num_tickets_set_impl(PySSLContext *self, PyObject *value); + + static int +-_ssl__SSLContext_num_tickets_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) ++_ssl__SSLContext_num_tickets_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) + { + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_num_tickets_set_impl(self, value); ++ return_value = _ssl__SSLContext_num_tickets_set_impl((PySSLContext *)self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1131,6 +1152,9 @@ + + PyDoc_STRVAR(_ssl__SSLContext_security_level__doc__, + "The current security level."); ++#if defined(_ssl__SSLContext_security_level_DOCSTR) ++# undef _ssl__SSLContext_security_level_DOCSTR ++#endif + #define _ssl__SSLContext_security_level_DOCSTR _ssl__SSLContext_security_level__doc__ + + #if !defined(_ssl__SSLContext_security_level_DOCSTR) +@@ -1147,12 +1171,12 @@ + _ssl__SSLContext_security_level_get_impl(PySSLContext *self); + + static PyObject * +-_ssl__SSLContext_security_level_get(PySSLContext *self, void *Py_UNUSED(context)) ++_ssl__SSLContext_security_level_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_security_level_get_impl(self); ++ return_value = _ssl__SSLContext_security_level_get_impl((PySSLContext *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1172,12 +1196,12 @@ + _ssl__SSLContext_options_get_impl(PySSLContext *self); + + static PyObject * +-_ssl__SSLContext_options_get(PySSLContext *self, void *Py_UNUSED(context)) ++_ssl__SSLContext_options_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_options_get_impl(self); ++ return_value = _ssl__SSLContext_options_get_impl((PySSLContext *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1197,12 +1221,12 @@ + _ssl__SSLContext_options_set_impl(PySSLContext *self, PyObject *value); + + static int +-_ssl__SSLContext_options_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) ++_ssl__SSLContext_options_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) + { + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_options_set_impl(self, value); ++ return_value = _ssl__SSLContext_options_set_impl((PySSLContext *)self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1222,12 +1246,12 @@ + _ssl__SSLContext__host_flags_get_impl(PySSLContext *self); + + static PyObject * +-_ssl__SSLContext__host_flags_get(PySSLContext *self, void *Py_UNUSED(context)) ++_ssl__SSLContext__host_flags_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext__host_flags_get_impl(self); ++ return_value = _ssl__SSLContext__host_flags_get_impl((PySSLContext *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1247,12 +1271,12 @@ + _ssl__SSLContext__host_flags_set_impl(PySSLContext *self, PyObject *value); + + static int +-_ssl__SSLContext__host_flags_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) ++_ssl__SSLContext__host_flags_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) + { + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext__host_flags_set_impl(self, value); ++ return_value = _ssl__SSLContext__host_flags_set_impl((PySSLContext *)self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1272,12 +1296,12 @@ + _ssl__SSLContext_check_hostname_get_impl(PySSLContext *self); + + static PyObject * +-_ssl__SSLContext_check_hostname_get(PySSLContext *self, void *Py_UNUSED(context)) ++_ssl__SSLContext_check_hostname_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_check_hostname_get_impl(self); ++ return_value = _ssl__SSLContext_check_hostname_get_impl((PySSLContext *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1297,12 +1321,12 @@ + _ssl__SSLContext_check_hostname_set_impl(PySSLContext *self, PyObject *value); + + static int +-_ssl__SSLContext_check_hostname_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) ++_ssl__SSLContext_check_hostname_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) + { + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_check_hostname_set_impl(self, value); ++ return_value = _ssl__SSLContext_check_hostname_set_impl((PySSLContext *)self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1322,12 +1346,12 @@ + _ssl__SSLContext_protocol_get_impl(PySSLContext *self); + + static PyObject * +-_ssl__SSLContext_protocol_get(PySSLContext *self, void *Py_UNUSED(context)) ++_ssl__SSLContext_protocol_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_protocol_get_impl(self); ++ return_value = _ssl__SSLContext_protocol_get_impl((PySSLContext *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1346,7 +1370,7 @@ + PyObject *keyfile, PyObject *password); + + static PyObject * +-_ssl__SSLContext_load_cert_chain(PySSLContext *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_ssl__SSLContext_load_cert_chain(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -1398,7 +1422,7 @@ + password = args[2]; + skip_optional_pos: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_load_cert_chain_impl(self, certfile, keyfile, password); ++ return_value = _ssl__SSLContext_load_cert_chain_impl((PySSLContext *)self, certfile, keyfile, password); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -1420,7 +1444,7 @@ + PyObject *cadata); + + static PyObject * +-_ssl__SSLContext_load_verify_locations(PySSLContext *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_ssl__SSLContext_load_verify_locations(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -1477,7 +1501,7 @@ + cadata = args[2]; + skip_optional_pos: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_load_verify_locations_impl(self, cafile, capath, cadata); ++ return_value = _ssl__SSLContext_load_verify_locations_impl((PySSLContext *)self, cafile, capath, cadata); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -1501,7 +1525,7 @@ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_load_dh_params_impl(self, filepath); ++ return_value = _ssl__SSLContext_load_dh_params_impl((PySSLContext *)self, filepath); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1522,7 +1546,7 @@ + PyObject *owner, PyObject *session); + + static PyObject * +-_ssl__SSLContext__wrap_socket(PySSLContext *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_ssl__SSLContext__wrap_socket(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -1594,7 +1618,7 @@ + session = args[4]; + skip_optional_kwonly: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext__wrap_socket_impl(self, sock, server_side, hostname_obj, owner, session); ++ return_value = _ssl__SSLContext__wrap_socket_impl((PySSLContext *)self, sock, server_side, hostname_obj, owner, session); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -1617,7 +1641,7 @@ + PyObject *session); + + static PyObject * +-_ssl__SSLContext__wrap_bio(PySSLContext *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_ssl__SSLContext__wrap_bio(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -1695,7 +1719,7 @@ + session = args[5]; + skip_optional_kwonly: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext__wrap_bio_impl(self, incoming, outgoing, server_side, hostname_obj, owner, session); ++ return_value = _ssl__SSLContext__wrap_bio_impl((PySSLContext *)self, incoming, outgoing, server_side, hostname_obj, owner, session); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -1714,12 +1738,12 @@ + _ssl__SSLContext_session_stats_impl(PySSLContext *self); + + static PyObject * +-_ssl__SSLContext_session_stats(PySSLContext *self, PyObject *Py_UNUSED(ignored)) ++_ssl__SSLContext_session_stats(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_session_stats_impl(self); ++ return_value = _ssl__SSLContext_session_stats_impl((PySSLContext *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1737,12 +1761,12 @@ + _ssl__SSLContext_set_default_verify_paths_impl(PySSLContext *self); + + static PyObject * +-_ssl__SSLContext_set_default_verify_paths(PySSLContext *self, PyObject *Py_UNUSED(ignored)) ++_ssl__SSLContext_set_default_verify_paths(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_set_default_verify_paths_impl(self); ++ return_value = _ssl__SSLContext_set_default_verify_paths_impl((PySSLContext *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1765,7 +1789,7 @@ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_set_ecdh_curve_impl(self, name); ++ return_value = _ssl__SSLContext_set_ecdh_curve_impl((PySSLContext *)self, name); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1778,6 +1802,9 @@ + "with the SSLSocket, the server name as a string, and the SSLContext object.\n" + "\n" + "See RFC 6066 for details of the SNI extension."); ++#if defined(_ssl__SSLContext_sni_callback_DOCSTR) ++# undef _ssl__SSLContext_sni_callback_DOCSTR ++#endif + #define _ssl__SSLContext_sni_callback_DOCSTR _ssl__SSLContext_sni_callback__doc__ + + #if !defined(_ssl__SSLContext_sni_callback_DOCSTR) +@@ -1794,12 +1821,12 @@ + _ssl__SSLContext_sni_callback_get_impl(PySSLContext *self); + + static PyObject * +-_ssl__SSLContext_sni_callback_get(PySSLContext *self, void *Py_UNUSED(context)) ++_ssl__SSLContext_sni_callback_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_sni_callback_get_impl(self); ++ return_value = _ssl__SSLContext_sni_callback_get_impl((PySSLContext *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1819,12 +1846,12 @@ + _ssl__SSLContext_sni_callback_set_impl(PySSLContext *self, PyObject *value); + + static int +-_ssl__SSLContext_sni_callback_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) ++_ssl__SSLContext_sni_callback_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) + { + int return_value; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_sni_callback_set_impl(self, value); ++ return_value = _ssl__SSLContext_sni_callback_set_impl((PySSLContext *)self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1849,12 +1876,12 @@ + _ssl__SSLContext_cert_store_stats_impl(PySSLContext *self); + + static PyObject * +-_ssl__SSLContext_cert_store_stats(PySSLContext *self, PyObject *Py_UNUSED(ignored)) ++_ssl__SSLContext_cert_store_stats(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_cert_store_stats_impl(self); ++ return_value = _ssl__SSLContext_cert_store_stats_impl((PySSLContext *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1879,7 +1906,7 @@ + _ssl__SSLContext_get_ca_certs_impl(PySSLContext *self, int binary_form); + + static PyObject * +-_ssl__SSLContext_get_ca_certs(PySSLContext *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_ssl__SSLContext_get_ca_certs(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -1925,7 +1952,7 @@ + } + skip_optional_pos: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_get_ca_certs_impl(self, binary_form); ++ return_value = _ssl__SSLContext_get_ca_certs_impl((PySSLContext *)self, binary_form); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -1945,7 +1972,7 @@ + PyObject *callback); + + static PyObject * +-_ssl__SSLContext_set_psk_client_callback(PySSLContext *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_ssl__SSLContext_set_psk_client_callback(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -1983,7 +2010,7 @@ + } + callback = args[0]; + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_set_psk_client_callback_impl(self, callback); ++ return_value = _ssl__SSLContext_set_psk_client_callback_impl((PySSLContext *)self, callback); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -2004,7 +2031,7 @@ + const char *identity_hint); + + static PyObject * +-_ssl__SSLContext_set_psk_server_callback(PySSLContext *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_ssl__SSLContext_set_psk_server_callback(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -2066,7 +2093,7 @@ + } + skip_optional_pos: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl__SSLContext_set_psk_server_callback_impl(self, callback, identity_hint); ++ return_value = _ssl__SSLContext_set_psk_server_callback_impl((PySSLContext *)self, callback, identity_hint); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -2100,6 +2127,9 @@ + + PyDoc_STRVAR(_ssl_MemoryBIO_pending__doc__, + "The number of bytes pending in the memory BIO."); ++#if defined(_ssl_MemoryBIO_pending_DOCSTR) ++# undef _ssl_MemoryBIO_pending_DOCSTR ++#endif + #define _ssl_MemoryBIO_pending_DOCSTR _ssl_MemoryBIO_pending__doc__ + + #if !defined(_ssl_MemoryBIO_pending_DOCSTR) +@@ -2116,12 +2146,12 @@ + _ssl_MemoryBIO_pending_get_impl(PySSLMemoryBIO *self); + + static PyObject * +-_ssl_MemoryBIO_pending_get(PySSLMemoryBIO *self, void *Py_UNUSED(context)) ++_ssl_MemoryBIO_pending_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl_MemoryBIO_pending_get_impl(self); ++ return_value = _ssl_MemoryBIO_pending_get_impl((PySSLMemoryBIO *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -2129,6 +2159,9 @@ + + PyDoc_STRVAR(_ssl_MemoryBIO_eof__doc__, + "Whether the memory BIO is at EOF."); ++#if defined(_ssl_MemoryBIO_eof_DOCSTR) ++# undef _ssl_MemoryBIO_eof_DOCSTR ++#endif + #define _ssl_MemoryBIO_eof_DOCSTR _ssl_MemoryBIO_eof__doc__ + + #if !defined(_ssl_MemoryBIO_eof_DOCSTR) +@@ -2145,12 +2178,12 @@ + _ssl_MemoryBIO_eof_get_impl(PySSLMemoryBIO *self); + + static PyObject * +-_ssl_MemoryBIO_eof_get(PySSLMemoryBIO *self, void *Py_UNUSED(context)) ++_ssl_MemoryBIO_eof_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl_MemoryBIO_eof_get_impl(self); ++ return_value = _ssl_MemoryBIO_eof_get_impl((PySSLMemoryBIO *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -2174,7 +2207,7 @@ + _ssl_MemoryBIO_read_impl(PySSLMemoryBIO *self, int len); + + static PyObject * +-_ssl_MemoryBIO_read(PySSLMemoryBIO *self, PyObject *const *args, Py_ssize_t nargs) ++_ssl_MemoryBIO_read(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + int len = -1; +@@ -2191,7 +2224,7 @@ + } + skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl_MemoryBIO_read_impl(self, len); ++ return_value = _ssl_MemoryBIO_read_impl((PySSLMemoryBIO *)self, len); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -2213,7 +2246,7 @@ + _ssl_MemoryBIO_write_impl(PySSLMemoryBIO *self, Py_buffer *b); + + static PyObject * +-_ssl_MemoryBIO_write(PySSLMemoryBIO *self, PyObject *arg) ++_ssl_MemoryBIO_write(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + Py_buffer b = {NULL, NULL}; +@@ -2222,7 +2255,7 @@ + goto exit; + } + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl_MemoryBIO_write_impl(self, &b); ++ return_value = _ssl_MemoryBIO_write_impl((PySSLMemoryBIO *)self, &b); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -2249,12 +2282,12 @@ + _ssl_MemoryBIO_write_eof_impl(PySSLMemoryBIO *self); + + static PyObject * +-_ssl_MemoryBIO_write_eof(PySSLMemoryBIO *self, PyObject *Py_UNUSED(ignored)) ++_ssl_MemoryBIO_write_eof(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl_MemoryBIO_write_eof_impl(self); ++ return_value = _ssl_MemoryBIO_write_eof_impl((PySSLMemoryBIO *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -2262,6 +2295,9 @@ + + PyDoc_STRVAR(_ssl_SSLSession_time__doc__, + "Session creation time (seconds since epoch)."); ++#if defined(_ssl_SSLSession_time_DOCSTR) ++# undef _ssl_SSLSession_time_DOCSTR ++#endif + #define _ssl_SSLSession_time_DOCSTR _ssl_SSLSession_time__doc__ + + #if !defined(_ssl_SSLSession_time_DOCSTR) +@@ -2278,12 +2314,12 @@ + _ssl_SSLSession_time_get_impl(PySSLSession *self); + + static PyObject * +-_ssl_SSLSession_time_get(PySSLSession *self, void *Py_UNUSED(context)) ++_ssl_SSLSession_time_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl_SSLSession_time_get_impl(self); ++ return_value = _ssl_SSLSession_time_get_impl((PySSLSession *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -2291,6 +2327,9 @@ + + PyDoc_STRVAR(_ssl_SSLSession_timeout__doc__, + "Session timeout (delta in seconds)."); ++#if defined(_ssl_SSLSession_timeout_DOCSTR) ++# undef _ssl_SSLSession_timeout_DOCSTR ++#endif + #define _ssl_SSLSession_timeout_DOCSTR _ssl_SSLSession_timeout__doc__ + + #if !defined(_ssl_SSLSession_timeout_DOCSTR) +@@ -2307,12 +2346,12 @@ + _ssl_SSLSession_timeout_get_impl(PySSLSession *self); + + static PyObject * +-_ssl_SSLSession_timeout_get(PySSLSession *self, void *Py_UNUSED(context)) ++_ssl_SSLSession_timeout_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl_SSLSession_timeout_get_impl(self); ++ return_value = _ssl_SSLSession_timeout_get_impl((PySSLSession *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -2320,6 +2359,9 @@ + + PyDoc_STRVAR(_ssl_SSLSession_ticket_lifetime_hint__doc__, + "Ticket life time hint."); ++#if defined(_ssl_SSLSession_ticket_lifetime_hint_DOCSTR) ++# undef _ssl_SSLSession_ticket_lifetime_hint_DOCSTR ++#endif + #define _ssl_SSLSession_ticket_lifetime_hint_DOCSTR _ssl_SSLSession_ticket_lifetime_hint__doc__ + + #if !defined(_ssl_SSLSession_ticket_lifetime_hint_DOCSTR) +@@ -2336,12 +2378,12 @@ + _ssl_SSLSession_ticket_lifetime_hint_get_impl(PySSLSession *self); + + static PyObject * +-_ssl_SSLSession_ticket_lifetime_hint_get(PySSLSession *self, void *Py_UNUSED(context)) ++_ssl_SSLSession_ticket_lifetime_hint_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl_SSLSession_ticket_lifetime_hint_get_impl(self); ++ return_value = _ssl_SSLSession_ticket_lifetime_hint_get_impl((PySSLSession *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -2349,6 +2391,9 @@ + + PyDoc_STRVAR(_ssl_SSLSession_id__doc__, + "Session ID."); ++#if defined(_ssl_SSLSession_id_DOCSTR) ++# undef _ssl_SSLSession_id_DOCSTR ++#endif + #define _ssl_SSLSession_id_DOCSTR _ssl_SSLSession_id__doc__ + + #if !defined(_ssl_SSLSession_id_DOCSTR) +@@ -2365,12 +2410,12 @@ + _ssl_SSLSession_id_get_impl(PySSLSession *self); + + static PyObject * +-_ssl_SSLSession_id_get(PySSLSession *self, void *Py_UNUSED(context)) ++_ssl_SSLSession_id_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl_SSLSession_id_get_impl(self); ++ return_value = _ssl_SSLSession_id_get_impl((PySSLSession *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -2378,6 +2423,9 @@ + + PyDoc_STRVAR(_ssl_SSLSession_has_ticket__doc__, + "Does the session contain a ticket?"); ++#if defined(_ssl_SSLSession_has_ticket_DOCSTR) ++# undef _ssl_SSLSession_has_ticket_DOCSTR ++#endif + #define _ssl_SSLSession_has_ticket_DOCSTR _ssl_SSLSession_has_ticket__doc__ + + #if !defined(_ssl_SSLSession_has_ticket_DOCSTR) +@@ -2394,12 +2442,12 @@ + _ssl_SSLSession_has_ticket_get_impl(PySSLSession *self); + + static PyObject * +-_ssl_SSLSession_has_ticket_get(PySSLSession *self, void *Py_UNUSED(context)) ++_ssl_SSLSession_has_ticket_get(PyObject *self, void *Py_UNUSED(context)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = _ssl_SSLSession_has_ticket_get_impl(self); ++ return_value = _ssl_SSLSession_has_ticket_get_impl((PySSLSession *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -2830,4 +2878,4 @@ + #ifndef _SSL_ENUM_CRLS_METHODDEF + #define _SSL_ENUM_CRLS_METHODDEF + #endif /* !defined(_SSL_ENUM_CRLS_METHODDEF) */ +-/*[clinic end generated code: output=654d6d7af659f6cd input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=bededfb2b927bd41 input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/_struct.c.h b/Modules/clinic/_struct.c.h +index cfc2fe7fc1d..7cf179f7a69 100644 +--- a/Modules/clinic/_struct.c.h ++++ b/Modules/clinic/_struct.c.h +@@ -87,7 +87,7 @@ + Struct_unpack_impl(PyStructObject *self, Py_buffer *buffer); + + static PyObject * +-Struct_unpack(PyStructObject *self, PyObject *arg) ++Struct_unpack(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + Py_buffer buffer = {NULL, NULL}; +@@ -95,7 +95,7 @@ + if (PyObject_GetBuffer(arg, &buffer, PyBUF_SIMPLE) != 0) { + goto exit; + } +- return_value = Struct_unpack_impl(self, &buffer); ++ return_value = Struct_unpack_impl((PyStructObject *)self, &buffer); + + exit: + /* Cleanup for buffer */ +@@ -127,7 +127,7 @@ + Py_ssize_t offset); + + static PyObject * +-Struct_unpack_from(PyStructObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++Struct_unpack_from(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -184,7 +184,7 @@ + offset = ival; + } + skip_optional_pos: +- return_value = Struct_unpack_from_impl(self, &buffer, offset); ++ return_value = Struct_unpack_from_impl((PyStructObject *)self, &buffer, offset); + + exit: + /* Cleanup for buffer */ +@@ -439,4 +439,4 @@ + + return return_value; + } +-/*[clinic end generated code: output=faff90f99c6bd09f input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=ec540c21be08e1d0 input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/_testmultiphase.c.h b/Modules/clinic/_testmultiphase.c.h +index 5a432a6f703..01c29c0753a 100644 +--- a/Modules/clinic/_testmultiphase.c.h ++++ b/Modules/clinic/_testmultiphase.c.h +@@ -25,13 +25,13 @@ + PyTypeObject *cls); + + static PyObject * +-_testmultiphase_StateAccessType_get_defining_module(StateAccessTypeObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_testmultiphase_StateAccessType_get_defining_module(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "get_defining_module() takes no arguments"); + return NULL; + } +- return _testmultiphase_StateAccessType_get_defining_module_impl(self, cls); ++ return _testmultiphase_StateAccessType_get_defining_module_impl((StateAccessTypeObject *)self, cls); + } + + PyDoc_STRVAR(_testmultiphase_StateAccessType_getmodulebydef_bad_def__doc__, +@@ -48,13 +48,13 @@ + PyTypeObject *cls); + + static PyObject * +-_testmultiphase_StateAccessType_getmodulebydef_bad_def(StateAccessTypeObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_testmultiphase_StateAccessType_getmodulebydef_bad_def(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "getmodulebydef_bad_def() takes no arguments"); + return NULL; + } +- return _testmultiphase_StateAccessType_getmodulebydef_bad_def_impl(self, cls); ++ return _testmultiphase_StateAccessType_getmodulebydef_bad_def_impl((StateAccessTypeObject *)self, cls); + } + + PyDoc_STRVAR(_testmultiphase_StateAccessType_increment_count_clinic__doc__, +@@ -76,7 +76,7 @@ + int n, int twice); + + static PyObject * +-_testmultiphase_StateAccessType_increment_count_clinic(StateAccessTypeObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_testmultiphase_StateAccessType_increment_count_clinic(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -135,7 +135,7 @@ + goto exit; + } + skip_optional_kwonly: +- return_value = _testmultiphase_StateAccessType_increment_count_clinic_impl(self, cls, n, twice); ++ return_value = _testmultiphase_StateAccessType_increment_count_clinic_impl((StateAccessTypeObject *)self, cls, n, twice); + + exit: + return return_value; +@@ -155,12 +155,12 @@ + PyTypeObject *cls); + + static PyObject * +-_testmultiphase_StateAccessType_get_count(StateAccessTypeObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++_testmultiphase_StateAccessType_get_count(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "get_count() takes no arguments"); + return NULL; + } +- return _testmultiphase_StateAccessType_get_count_impl(self, cls); ++ return _testmultiphase_StateAccessType_get_count_impl((StateAccessTypeObject *)self, cls); + } +-/*[clinic end generated code: output=c1aa0af3572bf059 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=ea0ca98e467e53c2 input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/_threadmodule.c.h b/Modules/clinic/_threadmodule.c.h +index 8f0507d4028..09b7afebd6d 100644 +--- a/Modules/clinic/_threadmodule.c.h ++++ b/Modules/clinic/_threadmodule.c.h +@@ -8,7 +8,7 @@ + #endif + #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() + +-#if defined(HAVE_PTHREAD_GETNAME_NP) ++#if (defined(HAVE_PTHREAD_GETNAME_NP) || defined(MS_WINDOWS)) + + PyDoc_STRVAR(_thread__get_name__doc__, + "_get_name($module, /)\n" +@@ -28,9 +28,9 @@ + return _thread__get_name_impl(module); + } + +-#endif /* defined(HAVE_PTHREAD_GETNAME_NP) */ ++#endif /* (defined(HAVE_PTHREAD_GETNAME_NP) || defined(MS_WINDOWS)) */ + +-#if defined(HAVE_PTHREAD_SETNAME_NP) ++#if (defined(HAVE_PTHREAD_SETNAME_NP) || defined(MS_WINDOWS)) + + PyDoc_STRVAR(_thread_set_name__doc__, + "set_name($module, /, name)\n" +@@ -92,7 +92,7 @@ + return return_value; + } + +-#endif /* defined(HAVE_PTHREAD_SETNAME_NP) */ ++#endif /* (defined(HAVE_PTHREAD_SETNAME_NP) || defined(MS_WINDOWS)) */ + + #ifndef _THREAD__GET_NAME_METHODDEF + #define _THREAD__GET_NAME_METHODDEF +@@ -101,4 +101,4 @@ + #ifndef _THREAD_SET_NAME_METHODDEF + #define _THREAD_SET_NAME_METHODDEF + #endif /* !defined(_THREAD_SET_NAME_METHODDEF) */ +-/*[clinic end generated code: output=b5cb85aaccc45bf6 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=6e88ef6b126cece8 input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/_tkinter.c.h b/Modules/clinic/_tkinter.c.h +index 2b1ac954b4d..d6e783b04fe 100644 +--- a/Modules/clinic/_tkinter.c.h ++++ b/Modules/clinic/_tkinter.c.h +@@ -16,7 +16,7 @@ + _tkinter_tkapp_eval_impl(TkappObject *self, const char *script); + + static PyObject * +-_tkinter_tkapp_eval(TkappObject *self, PyObject *arg) ++_tkinter_tkapp_eval(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + const char *script; +@@ -34,7 +34,7 @@ + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } +- return_value = _tkinter_tkapp_eval_impl(self, script); ++ return_value = _tkinter_tkapp_eval_impl((TkappObject *)self, script); + + exit: + return return_value; +@@ -52,7 +52,7 @@ + _tkinter_tkapp_evalfile_impl(TkappObject *self, const char *fileName); + + static PyObject * +-_tkinter_tkapp_evalfile(TkappObject *self, PyObject *arg) ++_tkinter_tkapp_evalfile(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + const char *fileName; +@@ -70,7 +70,7 @@ + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } +- return_value = _tkinter_tkapp_evalfile_impl(self, fileName); ++ return_value = _tkinter_tkapp_evalfile_impl((TkappObject *)self, fileName); + + exit: + return return_value; +@@ -88,7 +88,7 @@ + _tkinter_tkapp_record_impl(TkappObject *self, const char *script); + + static PyObject * +-_tkinter_tkapp_record(TkappObject *self, PyObject *arg) ++_tkinter_tkapp_record(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + const char *script; +@@ -106,7 +106,7 @@ + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } +- return_value = _tkinter_tkapp_record_impl(self, script); ++ return_value = _tkinter_tkapp_record_impl((TkappObject *)self, script); + + exit: + return return_value; +@@ -124,7 +124,7 @@ + _tkinter_tkapp_adderrorinfo_impl(TkappObject *self, const char *msg); + + static PyObject * +-_tkinter_tkapp_adderrorinfo(TkappObject *self, PyObject *arg) ++_tkinter_tkapp_adderrorinfo(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + const char *msg; +@@ -142,7 +142,7 @@ + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } +- return_value = _tkinter_tkapp_adderrorinfo_impl(self, msg); ++ return_value = _tkinter_tkapp_adderrorinfo_impl((TkappObject *)self, msg); + + exit: + return return_value; +@@ -184,7 +184,7 @@ + _tkinter_tkapp_exprstring_impl(TkappObject *self, const char *s); + + static PyObject * +-_tkinter_tkapp_exprstring(TkappObject *self, PyObject *arg) ++_tkinter_tkapp_exprstring(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + const char *s; +@@ -202,7 +202,7 @@ + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } +- return_value = _tkinter_tkapp_exprstring_impl(self, s); ++ return_value = _tkinter_tkapp_exprstring_impl((TkappObject *)self, s); + + exit: + return return_value; +@@ -220,7 +220,7 @@ + _tkinter_tkapp_exprlong_impl(TkappObject *self, const char *s); + + static PyObject * +-_tkinter_tkapp_exprlong(TkappObject *self, PyObject *arg) ++_tkinter_tkapp_exprlong(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + const char *s; +@@ -238,7 +238,7 @@ + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } +- return_value = _tkinter_tkapp_exprlong_impl(self, s); ++ return_value = _tkinter_tkapp_exprlong_impl((TkappObject *)self, s); + + exit: + return return_value; +@@ -256,7 +256,7 @@ + _tkinter_tkapp_exprdouble_impl(TkappObject *self, const char *s); + + static PyObject * +-_tkinter_tkapp_exprdouble(TkappObject *self, PyObject *arg) ++_tkinter_tkapp_exprdouble(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + const char *s; +@@ -274,7 +274,7 @@ + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } +- return_value = _tkinter_tkapp_exprdouble_impl(self, s); ++ return_value = _tkinter_tkapp_exprdouble_impl((TkappObject *)self, s); + + exit: + return return_value; +@@ -292,7 +292,7 @@ + _tkinter_tkapp_exprboolean_impl(TkappObject *self, const char *s); + + static PyObject * +-_tkinter_tkapp_exprboolean(TkappObject *self, PyObject *arg) ++_tkinter_tkapp_exprboolean(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + const char *s; +@@ -310,7 +310,7 @@ + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } +- return_value = _tkinter_tkapp_exprboolean_impl(self, s); ++ return_value = _tkinter_tkapp_exprboolean_impl((TkappObject *)self, s); + + exit: + return return_value; +@@ -337,7 +337,7 @@ + PyObject *func); + + static PyObject * +-_tkinter_tkapp_createcommand(TkappObject *self, PyObject *const *args, Py_ssize_t nargs) ++_tkinter_tkapp_createcommand(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + const char *name; +@@ -360,7 +360,7 @@ + goto exit; + } + func = args[1]; +- return_value = _tkinter_tkapp_createcommand_impl(self, name, func); ++ return_value = _tkinter_tkapp_createcommand_impl((TkappObject *)self, name, func); + + exit: + return return_value; +@@ -378,7 +378,7 @@ + _tkinter_tkapp_deletecommand_impl(TkappObject *self, const char *name); + + static PyObject * +-_tkinter_tkapp_deletecommand(TkappObject *self, PyObject *arg) ++_tkinter_tkapp_deletecommand(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + const char *name; +@@ -396,7 +396,7 @@ + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } +- return_value = _tkinter_tkapp_deletecommand_impl(self, name); ++ return_value = _tkinter_tkapp_deletecommand_impl((TkappObject *)self, name); + + exit: + return return_value; +@@ -417,7 +417,7 @@ + int mask, PyObject *func); + + static PyObject * +-_tkinter_tkapp_createfilehandler(TkappObject *self, PyObject *const *args, Py_ssize_t nargs) ++_tkinter_tkapp_createfilehandler(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *file; +@@ -433,7 +433,7 @@ + goto exit; + } + func = args[2]; +- return_value = _tkinter_tkapp_createfilehandler_impl(self, file, mask, func); ++ return_value = _tkinter_tkapp_createfilehandler_impl((TkappObject *)self, file, mask, func); + + exit: + return return_value; +@@ -465,9 +465,9 @@ + _tkinter_tktimertoken_deletetimerhandler_impl(TkttObject *self); + + static PyObject * +-_tkinter_tktimertoken_deletetimerhandler(TkttObject *self, PyObject *Py_UNUSED(ignored)) ++_tkinter_tktimertoken_deletetimerhandler(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _tkinter_tktimertoken_deletetimerhandler_impl(self); ++ return _tkinter_tktimertoken_deletetimerhandler_impl((TkttObject *)self); + } + + PyDoc_STRVAR(_tkinter_tkapp_createtimerhandler__doc__, +@@ -483,7 +483,7 @@ + PyObject *func); + + static PyObject * +-_tkinter_tkapp_createtimerhandler(TkappObject *self, PyObject *const *args, Py_ssize_t nargs) ++_tkinter_tkapp_createtimerhandler(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + int milliseconds; +@@ -497,7 +497,7 @@ + goto exit; + } + func = args[1]; +- return_value = _tkinter_tkapp_createtimerhandler_impl(self, milliseconds, func); ++ return_value = _tkinter_tkapp_createtimerhandler_impl((TkappObject *)self, milliseconds, func); + + exit: + return return_value; +@@ -515,7 +515,7 @@ + _tkinter_tkapp_mainloop_impl(TkappObject *self, int threshold); + + static PyObject * +-_tkinter_tkapp_mainloop(TkappObject *self, PyObject *const *args, Py_ssize_t nargs) ++_tkinter_tkapp_mainloop(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + int threshold = 0; +@@ -531,7 +531,7 @@ + goto exit; + } + skip_optional: +- return_value = _tkinter_tkapp_mainloop_impl(self, threshold); ++ return_value = _tkinter_tkapp_mainloop_impl((TkappObject *)self, threshold); + + exit: + return return_value; +@@ -549,7 +549,7 @@ + _tkinter_tkapp_dooneevent_impl(TkappObject *self, int flags); + + static PyObject * +-_tkinter_tkapp_dooneevent(TkappObject *self, PyObject *const *args, Py_ssize_t nargs) ++_tkinter_tkapp_dooneevent(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + int flags = 0; +@@ -565,7 +565,7 @@ + goto exit; + } + skip_optional: +- return_value = _tkinter_tkapp_dooneevent_impl(self, flags); ++ return_value = _tkinter_tkapp_dooneevent_impl((TkappObject *)self, flags); + + exit: + return return_value; +@@ -583,9 +583,9 @@ + _tkinter_tkapp_quit_impl(TkappObject *self); + + static PyObject * +-_tkinter_tkapp_quit(TkappObject *self, PyObject *Py_UNUSED(ignored)) ++_tkinter_tkapp_quit(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _tkinter_tkapp_quit_impl(self); ++ return _tkinter_tkapp_quit_impl((TkappObject *)self); + } + + PyDoc_STRVAR(_tkinter_tkapp_interpaddr__doc__, +@@ -600,9 +600,9 @@ + _tkinter_tkapp_interpaddr_impl(TkappObject *self); + + static PyObject * +-_tkinter_tkapp_interpaddr(TkappObject *self, PyObject *Py_UNUSED(ignored)) ++_tkinter_tkapp_interpaddr(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _tkinter_tkapp_interpaddr_impl(self); ++ return _tkinter_tkapp_interpaddr_impl((TkappObject *)self); + } + + PyDoc_STRVAR(_tkinter_tkapp_loadtk__doc__, +@@ -617,9 +617,9 @@ + _tkinter_tkapp_loadtk_impl(TkappObject *self); + + static PyObject * +-_tkinter_tkapp_loadtk(TkappObject *self, PyObject *Py_UNUSED(ignored)) ++_tkinter_tkapp_loadtk(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _tkinter_tkapp_loadtk_impl(self); ++ return _tkinter_tkapp_loadtk_impl((TkappObject *)self); + } + + PyDoc_STRVAR(_tkinter_tkapp_settrace__doc__, +@@ -644,9 +644,9 @@ + _tkinter_tkapp_gettrace_impl(TkappObject *self); + + static PyObject * +-_tkinter_tkapp_gettrace(TkappObject *self, PyObject *Py_UNUSED(ignored)) ++_tkinter_tkapp_gettrace(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _tkinter_tkapp_gettrace_impl(self); ++ return _tkinter_tkapp_gettrace_impl((TkappObject *)self); + } + + PyDoc_STRVAR(_tkinter_tkapp_willdispatch__doc__, +@@ -661,9 +661,9 @@ + _tkinter_tkapp_willdispatch_impl(TkappObject *self); + + static PyObject * +-_tkinter_tkapp_willdispatch(TkappObject *self, PyObject *Py_UNUSED(ignored)) ++_tkinter_tkapp_willdispatch(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _tkinter_tkapp_willdispatch_impl(self); ++ return _tkinter_tkapp_willdispatch_impl((TkappObject *)self); + } + + PyDoc_STRVAR(_tkinter__flatten__doc__, +@@ -888,4 +888,4 @@ + #ifndef _TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF + #define _TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF + #endif /* !defined(_TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF) */ +-/*[clinic end generated code: output=d90c1a9850c63249 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=172a98df5f209a84 input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/_winapi.c.h b/Modules/clinic/_winapi.c.h +index 8bbecc44dc9..6a2f8d45cd4 100644 +--- a/Modules/clinic/_winapi.c.h ++++ b/Modules/clinic/_winapi.c.h +@@ -21,7 +21,7 @@ + _winapi_Overlapped_GetOverlappedResult_impl(OverlappedObject *self, int wait); + + static PyObject * +-_winapi_Overlapped_GetOverlappedResult(OverlappedObject *self, PyObject *arg) ++_winapi_Overlapped_GetOverlappedResult(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + int wait; +@@ -30,7 +30,7 @@ + if (wait < 0) { + goto exit; + } +- return_value = _winapi_Overlapped_GetOverlappedResult_impl(self, wait); ++ return_value = _winapi_Overlapped_GetOverlappedResult_impl((OverlappedObject *)self, wait); + + exit: + return return_value; +@@ -48,9 +48,9 @@ + _winapi_Overlapped_getbuffer_impl(OverlappedObject *self); + + static PyObject * +-_winapi_Overlapped_getbuffer(OverlappedObject *self, PyObject *Py_UNUSED(ignored)) ++_winapi_Overlapped_getbuffer(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _winapi_Overlapped_getbuffer_impl(self); ++ return _winapi_Overlapped_getbuffer_impl((OverlappedObject *)self); + } + + PyDoc_STRVAR(_winapi_Overlapped_cancel__doc__, +@@ -65,9 +65,9 @@ + _winapi_Overlapped_cancel_impl(OverlappedObject *self); + + static PyObject * +-_winapi_Overlapped_cancel(OverlappedObject *self, PyObject *Py_UNUSED(ignored)) ++_winapi_Overlapped_cancel(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _winapi_Overlapped_cancel_impl(self); ++ return _winapi_Overlapped_cancel_impl((OverlappedObject *)self); + } + + PyDoc_STRVAR(_winapi_CloseHandle__doc__, +@@ -2127,4 +2127,4 @@ + + return return_value; + } +-/*[clinic end generated code: output=b2a178bde6868e88 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=06b56212b2186250 input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/arraymodule.c.h b/Modules/clinic/arraymodule.c.h +index 4a7266ecb8b..c5b62b16699 100644 +--- a/Modules/clinic/arraymodule.c.h ++++ b/Modules/clinic/arraymodule.c.h +@@ -21,9 +21,9 @@ + array_array_clear_impl(arrayobject *self); + + static PyObject * +-array_array_clear(arrayobject *self, PyObject *Py_UNUSED(ignored)) ++array_array_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return array_array_clear_impl(self); ++ return array_array_clear_impl((arrayobject *)self); + } + + PyDoc_STRVAR(array_array___copy____doc__, +@@ -39,9 +39,9 @@ + array_array___copy___impl(arrayobject *self); + + static PyObject * +-array_array___copy__(arrayobject *self, PyObject *Py_UNUSED(ignored)) ++array_array___copy__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return array_array___copy___impl(self); ++ return array_array___copy___impl((arrayobject *)self); + } + + PyDoc_STRVAR(array_array___deepcopy____doc__, +@@ -78,7 +78,7 @@ + Py_ssize_t stop); + + static PyObject * +-array_array_index(arrayobject *self, PyObject *const *args, Py_ssize_t nargs) ++array_array_index(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *v; +@@ -102,7 +102,7 @@ + goto exit; + } + skip_optional: +- return_value = array_array_index_impl(self, v, start, stop); ++ return_value = array_array_index_impl((arrayobject *)self, v, start, stop); + + exit: + return return_value; +@@ -132,7 +132,7 @@ + array_array_pop_impl(arrayobject *self, Py_ssize_t i); + + static PyObject * +-array_array_pop(arrayobject *self, PyObject *const *args, Py_ssize_t nargs) ++array_array_pop(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + Py_ssize_t i = -1; +@@ -156,7 +156,7 @@ + i = ival; + } + skip_optional: +- return_value = array_array_pop_impl(self, i); ++ return_value = array_array_pop_impl((arrayobject *)self, i); + + exit: + return return_value; +@@ -175,7 +175,7 @@ + array_array_extend_impl(arrayobject *self, PyTypeObject *cls, PyObject *bb); + + static PyObject * +-array_array_extend(arrayobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++array_array_extend(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -200,7 +200,7 @@ + goto exit; + } + bb = args[0]; +- return_value = array_array_extend_impl(self, cls, bb); ++ return_value = array_array_extend_impl((arrayobject *)self, cls, bb); + + exit: + return return_value; +@@ -219,7 +219,7 @@ + array_array_insert_impl(arrayobject *self, Py_ssize_t i, PyObject *v); + + static PyObject * +-array_array_insert(arrayobject *self, PyObject *const *args, Py_ssize_t nargs) ++array_array_insert(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + Py_ssize_t i; +@@ -241,7 +241,7 @@ + i = ival; + } + v = args[1]; +- return_value = array_array_insert_impl(self, i, v); ++ return_value = array_array_insert_impl((arrayobject *)self, i, v); + + exit: + return return_value; +@@ -263,9 +263,9 @@ + array_array_buffer_info_impl(arrayobject *self); + + static PyObject * +-array_array_buffer_info(arrayobject *self, PyObject *Py_UNUSED(ignored)) ++array_array_buffer_info(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return array_array_buffer_info_impl(self); ++ return array_array_buffer_info_impl((arrayobject *)self); + } + + PyDoc_STRVAR(array_array_append__doc__, +@@ -293,9 +293,9 @@ + array_array_byteswap_impl(arrayobject *self); + + static PyObject * +-array_array_byteswap(arrayobject *self, PyObject *Py_UNUSED(ignored)) ++array_array_byteswap(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return array_array_byteswap_impl(self); ++ return array_array_byteswap_impl((arrayobject *)self); + } + + PyDoc_STRVAR(array_array_reverse__doc__, +@@ -311,9 +311,9 @@ + array_array_reverse_impl(arrayobject *self); + + static PyObject * +-array_array_reverse(arrayobject *self, PyObject *Py_UNUSED(ignored)) ++array_array_reverse(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return array_array_reverse_impl(self); ++ return array_array_reverse_impl((arrayobject *)self); + } + + PyDoc_STRVAR(array_array_fromfile__doc__, +@@ -330,7 +330,7 @@ + Py_ssize_t n); + + static PyObject * +-array_array_fromfile(arrayobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++array_array_fromfile(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -368,7 +368,7 @@ + } + n = ival; + } +- return_value = array_array_fromfile_impl(self, cls, f, n); ++ return_value = array_array_fromfile_impl((arrayobject *)self, cls, f, n); + + exit: + return return_value; +@@ -387,7 +387,7 @@ + array_array_tofile_impl(arrayobject *self, PyTypeObject *cls, PyObject *f); + + static PyObject * +-array_array_tofile(arrayobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++array_array_tofile(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -412,7 +412,7 @@ + goto exit; + } + f = args[0]; +- return_value = array_array_tofile_impl(self, cls, f); ++ return_value = array_array_tofile_impl((arrayobject *)self, cls, f); + + exit: + return return_value; +@@ -440,9 +440,9 @@ + array_array_tolist_impl(arrayobject *self); + + static PyObject * +-array_array_tolist(arrayobject *self, PyObject *Py_UNUSED(ignored)) ++array_array_tolist(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return array_array_tolist_impl(self); ++ return array_array_tolist_impl((arrayobject *)self); + } + + PyDoc_STRVAR(array_array_frombytes__doc__, +@@ -458,7 +458,7 @@ + array_array_frombytes_impl(arrayobject *self, Py_buffer *buffer); + + static PyObject * +-array_array_frombytes(arrayobject *self, PyObject *arg) ++array_array_frombytes(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + Py_buffer buffer = {NULL, NULL}; +@@ -466,7 +466,7 @@ + if (PyObject_GetBuffer(arg, &buffer, PyBUF_SIMPLE) != 0) { + goto exit; + } +- return_value = array_array_frombytes_impl(self, &buffer); ++ return_value = array_array_frombytes_impl((arrayobject *)self, &buffer); + + exit: + /* Cleanup for buffer */ +@@ -490,9 +490,9 @@ + array_array_tobytes_impl(arrayobject *self); + + static PyObject * +-array_array_tobytes(arrayobject *self, PyObject *Py_UNUSED(ignored)) ++array_array_tobytes(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return array_array_tobytes_impl(self); ++ return array_array_tobytes_impl((arrayobject *)self); + } + + PyDoc_STRVAR(array_array_fromunicode__doc__, +@@ -512,7 +512,7 @@ + array_array_fromunicode_impl(arrayobject *self, PyObject *ustr); + + static PyObject * +-array_array_fromunicode(arrayobject *self, PyObject *arg) ++array_array_fromunicode(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + PyObject *ustr; +@@ -522,7 +522,7 @@ + goto exit; + } + ustr = arg; +- return_value = array_array_fromunicode_impl(self, ustr); ++ return_value = array_array_fromunicode_impl((arrayobject *)self, ustr); + + exit: + return return_value; +@@ -545,9 +545,9 @@ + array_array_tounicode_impl(arrayobject *self); + + static PyObject * +-array_array_tounicode(arrayobject *self, PyObject *Py_UNUSED(ignored)) ++array_array_tounicode(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return array_array_tounicode_impl(self); ++ return array_array_tounicode_impl((arrayobject *)self); + } + + PyDoc_STRVAR(array_array___sizeof____doc__, +@@ -563,9 +563,9 @@ + array_array___sizeof___impl(arrayobject *self); + + static PyObject * +-array_array___sizeof__(arrayobject *self, PyObject *Py_UNUSED(ignored)) ++array_array___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return array_array___sizeof___impl(self); ++ return array_array___sizeof___impl((arrayobject *)self); + } + + PyDoc_STRVAR(array__array_reconstructor__doc__, +@@ -634,7 +634,7 @@ + PyObject *value); + + static PyObject * +-array_array___reduce_ex__(arrayobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++array_array___reduce_ex__(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -659,7 +659,7 @@ + goto exit; + } + value = args[0]; +- return_value = array_array___reduce_ex___impl(self, cls, value); ++ return_value = array_array___reduce_ex___impl((arrayobject *)self, cls, value); + + exit: + return return_value; +@@ -678,13 +678,13 @@ + array_arrayiterator___reduce___impl(arrayiterobject *self, PyTypeObject *cls); + + static PyObject * +-array_arrayiterator___reduce__(arrayiterobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++array_arrayiterator___reduce__(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "__reduce__() takes no arguments"); + return NULL; + } +- return array_arrayiterator___reduce___impl(self, cls); ++ return array_arrayiterator___reduce___impl((arrayiterobject *)self, cls); + } + + PyDoc_STRVAR(array_arrayiterator___setstate____doc__, +@@ -695,4 +695,4 @@ + + #define ARRAY_ARRAYITERATOR___SETSTATE___METHODDEF \ + {"__setstate__", (PyCFunction)array_arrayiterator___setstate__, METH_O, array_arrayiterator___setstate____doc__}, +-/*[clinic end generated code: output=22dbe12826bfa86f input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=8120dc5c4fa414b9 input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/blake2module.c.h b/Modules/clinic/blake2module.c.h +index f695f27e9e6..b5ac90143a1 100644 +--- a/Modules/clinic/blake2module.c.h ++++ b/Modules/clinic/blake2module.c.h +@@ -412,9 +412,9 @@ + _blake2_blake2b_copy_impl(Blake2Object *self); + + static PyObject * +-_blake2_blake2b_copy(Blake2Object *self, PyObject *Py_UNUSED(ignored)) ++_blake2_blake2b_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _blake2_blake2b_copy_impl(self); ++ return _blake2_blake2b_copy_impl((Blake2Object *)self); + } + + PyDoc_STRVAR(_blake2_blake2b_update__doc__, +@@ -439,9 +439,9 @@ + _blake2_blake2b_digest_impl(Blake2Object *self); + + static PyObject * +-_blake2_blake2b_digest(Blake2Object *self, PyObject *Py_UNUSED(ignored)) ++_blake2_blake2b_digest(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _blake2_blake2b_digest_impl(self); ++ return _blake2_blake2b_digest_impl((Blake2Object *)self); + } + + PyDoc_STRVAR(_blake2_blake2b_hexdigest__doc__, +@@ -457,8 +457,8 @@ + _blake2_blake2b_hexdigest_impl(Blake2Object *self); + + static PyObject * +-_blake2_blake2b_hexdigest(Blake2Object *self, PyObject *Py_UNUSED(ignored)) ++_blake2_blake2b_hexdigest(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _blake2_blake2b_hexdigest_impl(self); ++ return _blake2_blake2b_hexdigest_impl((Blake2Object *)self); + } +-/*[clinic end generated code: output=e0aaaf112d023b79 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=6e03c947b7e0d973 input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/md5module.c.h b/Modules/clinic/md5module.c.h +index 7721616862e..1f0acebf47b 100644 +--- a/Modules/clinic/md5module.c.h ++++ b/Modules/clinic/md5module.c.h +@@ -21,13 +21,13 @@ + MD5Type_copy_impl(MD5object *self, PyTypeObject *cls); + + static PyObject * +-MD5Type_copy(MD5object *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++MD5Type_copy(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "copy() takes no arguments"); + return NULL; + } +- return MD5Type_copy_impl(self, cls); ++ return MD5Type_copy_impl((MD5object *)self, cls); + } + + PyDoc_STRVAR(MD5Type_digest__doc__, +@@ -43,9 +43,9 @@ + MD5Type_digest_impl(MD5object *self); + + static PyObject * +-MD5Type_digest(MD5object *self, PyObject *Py_UNUSED(ignored)) ++MD5Type_digest(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return MD5Type_digest_impl(self); ++ return MD5Type_digest_impl((MD5object *)self); + } + + PyDoc_STRVAR(MD5Type_hexdigest__doc__, +@@ -61,9 +61,9 @@ + MD5Type_hexdigest_impl(MD5object *self); + + static PyObject * +-MD5Type_hexdigest(MD5object *self, PyObject *Py_UNUSED(ignored)) ++MD5Type_hexdigest(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return MD5Type_hexdigest_impl(self); ++ return MD5Type_hexdigest_impl((MD5object *)self); + } + + PyDoc_STRVAR(MD5Type_update__doc__, +@@ -149,4 +149,4 @@ + exit: + return return_value; + } +-/*[clinic end generated code: output=62ebf28802ae8b5f input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=a4292eab710dcb60 input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/overlapped.c.h b/Modules/clinic/overlapped.c.h +index 9d5adb5193f..7e571566002 100644 +--- a/Modules/clinic/overlapped.c.h ++++ b/Modules/clinic/overlapped.c.h +@@ -516,9 +516,9 @@ + _overlapped_Overlapped_cancel_impl(OverlappedObject *self); + + static PyObject * +-_overlapped_Overlapped_cancel(OverlappedObject *self, PyObject *Py_UNUSED(ignored)) ++_overlapped_Overlapped_cancel(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _overlapped_Overlapped_cancel_impl(self); ++ return _overlapped_Overlapped_cancel_impl((OverlappedObject *)self); + } + + PyDoc_STRVAR(_overlapped_Overlapped_getresult__doc__, +@@ -537,7 +537,7 @@ + _overlapped_Overlapped_getresult_impl(OverlappedObject *self, BOOL wait); + + static PyObject * +-_overlapped_Overlapped_getresult(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) ++_overlapped_Overlapped_getresult(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + BOOL wait = FALSE; +@@ -553,7 +553,7 @@ + goto exit; + } + skip_optional: +- return_value = _overlapped_Overlapped_getresult_impl(self, wait); ++ return_value = _overlapped_Overlapped_getresult_impl((OverlappedObject *)self, wait); + + exit: + return return_value; +@@ -573,7 +573,7 @@ + DWORD size); + + static PyObject * +-_overlapped_Overlapped_ReadFile(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) ++_overlapped_Overlapped_ReadFile(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + HANDLE handle; +@@ -589,7 +589,7 @@ + if (!_PyLong_UnsignedLong_Converter(args[1], &size)) { + goto exit; + } +- return_value = _overlapped_Overlapped_ReadFile_impl(self, handle, size); ++ return_value = _overlapped_Overlapped_ReadFile_impl((OverlappedObject *)self, handle, size); + + exit: + return return_value; +@@ -609,7 +609,7 @@ + HANDLE handle, Py_buffer *bufobj); + + static PyObject * +-_overlapped_Overlapped_ReadFileInto(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) ++_overlapped_Overlapped_ReadFileInto(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + HANDLE handle; +@@ -625,7 +625,7 @@ + if (PyObject_GetBuffer(args[1], &bufobj, PyBUF_SIMPLE) != 0) { + goto exit; + } +- return_value = _overlapped_Overlapped_ReadFileInto_impl(self, handle, &bufobj); ++ return_value = _overlapped_Overlapped_ReadFileInto_impl((OverlappedObject *)self, handle, &bufobj); + + exit: + /* Cleanup for bufobj */ +@@ -650,7 +650,7 @@ + DWORD size, DWORD flags); + + static PyObject * +-_overlapped_Overlapped_WSARecv(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) ++_overlapped_Overlapped_WSARecv(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + HANDLE handle; +@@ -674,7 +674,7 @@ + goto exit; + } + skip_optional: +- return_value = _overlapped_Overlapped_WSARecv_impl(self, handle, size, flags); ++ return_value = _overlapped_Overlapped_WSARecv_impl((OverlappedObject *)self, handle, size, flags); + + exit: + return return_value; +@@ -695,7 +695,7 @@ + DWORD flags); + + static PyObject * +-_overlapped_Overlapped_WSARecvInto(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) ++_overlapped_Overlapped_WSARecvInto(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + HANDLE handle; +@@ -715,7 +715,7 @@ + if (!_PyLong_UnsignedLong_Converter(args[2], &flags)) { + goto exit; + } +- return_value = _overlapped_Overlapped_WSARecvInto_impl(self, handle, &bufobj, flags); ++ return_value = _overlapped_Overlapped_WSARecvInto_impl((OverlappedObject *)self, handle, &bufobj, flags); + + exit: + /* Cleanup for bufobj */ +@@ -740,7 +740,7 @@ + Py_buffer *bufobj); + + static PyObject * +-_overlapped_Overlapped_WriteFile(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) ++_overlapped_Overlapped_WriteFile(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + HANDLE handle; +@@ -756,7 +756,7 @@ + if (PyObject_GetBuffer(args[1], &bufobj, PyBUF_SIMPLE) != 0) { + goto exit; + } +- return_value = _overlapped_Overlapped_WriteFile_impl(self, handle, &bufobj); ++ return_value = _overlapped_Overlapped_WriteFile_impl((OverlappedObject *)self, handle, &bufobj); + + exit: + /* Cleanup for bufobj */ +@@ -781,7 +781,7 @@ + Py_buffer *bufobj, DWORD flags); + + static PyObject * +-_overlapped_Overlapped_WSASend(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) ++_overlapped_Overlapped_WSASend(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + HANDLE handle; +@@ -801,7 +801,7 @@ + if (!_PyLong_UnsignedLong_Converter(args[2], &flags)) { + goto exit; + } +- return_value = _overlapped_Overlapped_WSASend_impl(self, handle, &bufobj, flags); ++ return_value = _overlapped_Overlapped_WSASend_impl((OverlappedObject *)self, handle, &bufobj, flags); + + exit: + /* Cleanup for bufobj */ +@@ -827,7 +827,7 @@ + HANDLE AcceptSocket); + + static PyObject * +-_overlapped_Overlapped_AcceptEx(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) ++_overlapped_Overlapped_AcceptEx(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + HANDLE ListenSocket; +@@ -844,7 +844,7 @@ + if (!AcceptSocket && PyErr_Occurred()) { + goto exit; + } +- return_value = _overlapped_Overlapped_AcceptEx_impl(self, ListenSocket, AcceptSocket); ++ return_value = _overlapped_Overlapped_AcceptEx_impl((OverlappedObject *)self, ListenSocket, AcceptSocket); + + exit: + return return_value; +@@ -867,7 +867,7 @@ + PyObject *AddressObj); + + static PyObject * +-_overlapped_Overlapped_ConnectEx(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) ++_overlapped_Overlapped_ConnectEx(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + HANDLE ConnectSocket; +@@ -885,7 +885,7 @@ + goto exit; + } + AddressObj = args[1]; +- return_value = _overlapped_Overlapped_ConnectEx_impl(self, ConnectSocket, AddressObj); ++ return_value = _overlapped_Overlapped_ConnectEx_impl((OverlappedObject *)self, ConnectSocket, AddressObj); + + exit: + return return_value; +@@ -904,7 +904,7 @@ + HANDLE Socket, DWORD flags); + + static PyObject * +-_overlapped_Overlapped_DisconnectEx(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) ++_overlapped_Overlapped_DisconnectEx(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + HANDLE Socket; +@@ -920,7 +920,7 @@ + if (!_PyLong_UnsignedLong_Converter(args[1], &flags)) { + goto exit; + } +- return_value = _overlapped_Overlapped_DisconnectEx_impl(self, Socket, flags); ++ return_value = _overlapped_Overlapped_DisconnectEx_impl((OverlappedObject *)self, Socket, flags); + + exit: + return return_value; +@@ -944,7 +944,7 @@ + DWORD count_per_send, DWORD flags); + + static PyObject * +-_overlapped_Overlapped_TransmitFile(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) ++_overlapped_Overlapped_TransmitFile(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + HANDLE Socket; +@@ -981,7 +981,7 @@ + if (!_PyLong_UnsignedLong_Converter(args[6], &flags)) { + goto exit; + } +- return_value = _overlapped_Overlapped_TransmitFile_impl(self, Socket, File, offset, offset_high, count_to_write, count_per_send, flags); ++ return_value = _overlapped_Overlapped_TransmitFile_impl((OverlappedObject *)self, Socket, File, offset, offset_high, count_to_write, count_per_send, flags); + + exit: + return return_value; +@@ -1001,7 +1001,7 @@ + HANDLE Pipe); + + static PyObject * +-_overlapped_Overlapped_ConnectNamedPipe(OverlappedObject *self, PyObject *arg) ++_overlapped_Overlapped_ConnectNamedPipe(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + HANDLE Pipe; +@@ -1010,7 +1010,7 @@ + if (!Pipe && PyErr_Occurred()) { + goto exit; + } +- return_value = _overlapped_Overlapped_ConnectNamedPipe_impl(self, Pipe); ++ return_value = _overlapped_Overlapped_ConnectNamedPipe_impl((OverlappedObject *)self, Pipe); + + exit: + return return_value; +@@ -1030,7 +1030,7 @@ + const wchar_t *Address); + + static PyObject * +-_overlapped_Overlapped_ConnectPipe(OverlappedObject *self, PyObject *arg) ++_overlapped_Overlapped_ConnectPipe(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + const wchar_t *Address = NULL; +@@ -1043,7 +1043,7 @@ + if (Address == NULL) { + goto exit; + } +- return_value = _overlapped_Overlapped_ConnectPipe_impl(self, Address); ++ return_value = _overlapped_Overlapped_ConnectPipe_impl((OverlappedObject *)self, Address); + + exit: + /* Cleanup for Address */ +@@ -1105,7 +1105,7 @@ + PyObject *AddressObj); + + static PyObject * +-_overlapped_Overlapped_WSASendTo(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) ++_overlapped_Overlapped_WSASendTo(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + HANDLE handle; +@@ -1131,7 +1131,7 @@ + goto exit; + } + AddressObj = args[3]; +- return_value = _overlapped_Overlapped_WSASendTo_impl(self, handle, &bufobj, flags, AddressObj); ++ return_value = _overlapped_Overlapped_WSASendTo_impl((OverlappedObject *)self, handle, &bufobj, flags, AddressObj); + + exit: + /* Cleanup for bufobj */ +@@ -1157,7 +1157,7 @@ + DWORD flags); + + static PyObject * +-_overlapped_Overlapped_WSARecvFrom(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) ++_overlapped_Overlapped_WSARecvFrom(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + HANDLE handle; +@@ -1181,7 +1181,7 @@ + goto exit; + } + skip_optional: +- return_value = _overlapped_Overlapped_WSARecvFrom_impl(self, handle, size, flags); ++ return_value = _overlapped_Overlapped_WSARecvFrom_impl((OverlappedObject *)self, handle, size, flags); + + exit: + return return_value; +@@ -1202,7 +1202,7 @@ + DWORD size, DWORD flags); + + static PyObject * +-_overlapped_Overlapped_WSARecvFromInto(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) ++_overlapped_Overlapped_WSARecvFromInto(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + HANDLE handle; +@@ -1230,7 +1230,7 @@ + goto exit; + } + skip_optional: +- return_value = _overlapped_Overlapped_WSARecvFromInto_impl(self, handle, &bufobj, size, flags); ++ return_value = _overlapped_Overlapped_WSARecvFromInto_impl((OverlappedObject *)self, handle, &bufobj, size, flags); + + exit: + /* Cleanup for bufobj */ +@@ -1240,4 +1240,4 @@ + + return return_value; + } +-/*[clinic end generated code: output=14c4f87906f28dc5 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=d009cc9e53d9732a input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h +index 554299b8598..abeb9c3e3e1 100644 +--- a/Modules/clinic/posixmodule.c.h ++++ b/Modules/clinic/posixmodule.c.h +@@ -309,7 +309,7 @@ + return return_value; + } + +-#if defined(HAVE_TTYNAME) ++#if defined(HAVE_TTYNAME_R) + + PyDoc_STRVAR(os_ttyname__doc__, + "ttyname($module, fd, /)\n" +@@ -342,7 +342,7 @@ + return return_value; + } + +-#endif /* defined(HAVE_TTYNAME) */ ++#endif /* defined(HAVE_TTYNAME_R) */ + + #if defined(HAVE_CTERMID) + +@@ -7577,6 +7577,62 @@ + return return_value; + } + ++PyDoc_STRVAR(os_readinto__doc__, ++"readinto($module, fd, buffer, /)\n" ++"--\n" ++"\n" ++"Read into a buffer object from a file descriptor.\n" ++"\n" ++"The buffer should be mutable and bytes-like. On success, returns the number of\n" ++"bytes read. Less bytes may be read than the size of the buffer. The underlying\n" ++"system call will be retried when interrupted by a signal, unless the signal\n" ++"handler raises an exception. Other errors will not be retried and an error will\n" ++"be raised.\n" ++"\n" ++"Returns 0 if *fd* is at end of file or if the provided *buffer* has length 0\n" ++"(which can be used to check for errors without reading data). Never returns\n" ++"negative."); ++ ++#define OS_READINTO_METHODDEF \ ++ {"readinto", _PyCFunction_CAST(os_readinto), METH_FASTCALL, os_readinto__doc__}, ++ ++static Py_ssize_t ++os_readinto_impl(PyObject *module, int fd, Py_buffer *buffer); ++ ++static PyObject * ++os_readinto(PyObject *module, PyObject *const *args, Py_ssize_t nargs) ++{ ++ PyObject *return_value = NULL; ++ int fd; ++ Py_buffer buffer = {NULL, NULL}; ++ Py_ssize_t _return_value; ++ ++ if (!_PyArg_CheckPositional("readinto", nargs, 2, 2)) { ++ goto exit; ++ } ++ fd = PyLong_AsInt(args[0]); ++ if (fd == -1 && PyErr_Occurred()) { ++ goto exit; ++ } ++ if (PyObject_GetBuffer(args[1], &buffer, PyBUF_WRITABLE) < 0) { ++ _PyArg_BadArgument("readinto", "argument 2", "read-write bytes-like object", args[1]); ++ goto exit; ++ } ++ _return_value = os_readinto_impl(module, fd, &buffer); ++ if ((_return_value == -1) && PyErr_Occurred()) { ++ goto exit; ++ } ++ return_value = PyLong_FromSsize_t(_return_value); ++ ++exit: ++ /* Cleanup for buffer */ ++ if (buffer.obj) { ++ PyBuffer_Release(&buffer); ++ } ++ ++ return return_value; ++} ++ + #if defined(HAVE_READV) + + PyDoc_STRVAR(os_readv__doc__, +@@ -11662,7 +11718,7 @@ + os_DirEntry_is_symlink_impl(DirEntry *self, PyTypeObject *defining_class); + + static PyObject * +-os_DirEntry_is_symlink(DirEntry *self, PyTypeObject *defining_class, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++os_DirEntry_is_symlink(PyObject *self, PyTypeObject *defining_class, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + int _return_value; +@@ -11671,7 +11727,7 @@ + PyErr_SetString(PyExc_TypeError, "is_symlink() takes no arguments"); + goto exit; + } +- _return_value = os_DirEntry_is_symlink_impl(self, defining_class); ++ _return_value = os_DirEntry_is_symlink_impl((DirEntry *)self, defining_class); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } +@@ -11694,12 +11750,12 @@ + os_DirEntry_is_junction_impl(DirEntry *self); + + static PyObject * +-os_DirEntry_is_junction(DirEntry *self, PyObject *Py_UNUSED(ignored)) ++os_DirEntry_is_junction(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + int _return_value; + +- _return_value = os_DirEntry_is_junction_impl(self); ++ _return_value = os_DirEntry_is_junction_impl((DirEntry *)self); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } +@@ -11723,7 +11779,7 @@ + int follow_symlinks); + + static PyObject * +-os_DirEntry_stat(DirEntry *self, PyTypeObject *defining_class, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++os_DirEntry_stat(PyObject *self, PyTypeObject *defining_class, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -11768,7 +11824,7 @@ + goto exit; + } + skip_optional_kwonly: +- return_value = os_DirEntry_stat_impl(self, defining_class, follow_symlinks); ++ return_value = os_DirEntry_stat_impl((DirEntry *)self, defining_class, follow_symlinks); + + exit: + return return_value; +@@ -11788,7 +11844,7 @@ + int follow_symlinks); + + static PyObject * +-os_DirEntry_is_dir(DirEntry *self, PyTypeObject *defining_class, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++os_DirEntry_is_dir(PyObject *self, PyTypeObject *defining_class, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -11834,7 +11890,7 @@ + goto exit; + } + skip_optional_kwonly: +- _return_value = os_DirEntry_is_dir_impl(self, defining_class, follow_symlinks); ++ _return_value = os_DirEntry_is_dir_impl((DirEntry *)self, defining_class, follow_symlinks); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } +@@ -11858,7 +11914,7 @@ + int follow_symlinks); + + static PyObject * +-os_DirEntry_is_file(DirEntry *self, PyTypeObject *defining_class, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++os_DirEntry_is_file(PyObject *self, PyTypeObject *defining_class, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -11904,7 +11960,7 @@ + goto exit; + } + skip_optional_kwonly: +- _return_value = os_DirEntry_is_file_impl(self, defining_class, follow_symlinks); ++ _return_value = os_DirEntry_is_file_impl((DirEntry *)self, defining_class, follow_symlinks); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } +@@ -11927,9 +11983,9 @@ + os_DirEntry_inode_impl(DirEntry *self); + + static PyObject * +-os_DirEntry_inode(DirEntry *self, PyObject *Py_UNUSED(ignored)) ++os_DirEntry_inode(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return os_DirEntry_inode_impl(self); ++ return os_DirEntry_inode_impl((DirEntry *)self); + } + + PyDoc_STRVAR(os_DirEntry___fspath____doc__, +@@ -11945,9 +12001,9 @@ + os_DirEntry___fspath___impl(DirEntry *self); + + static PyObject * +-os_DirEntry___fspath__(DirEntry *self, PyObject *Py_UNUSED(ignored)) ++os_DirEntry___fspath__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return os_DirEntry___fspath___impl(self); ++ return os_DirEntry___fspath___impl((DirEntry *)self); + } + + PyDoc_STRVAR(os_scandir__doc__, +@@ -13140,4 +13196,4 @@ + #ifndef OS__EMSCRIPTEN_DEBUGGER_METHODDEF + #define OS__EMSCRIPTEN_DEBUGGER_METHODDEF + #endif /* !defined(OS__EMSCRIPTEN_DEBUGGER_METHODDEF) */ +-/*[clinic end generated code: output=9c2ca1dbf986c62c input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=8318c26fc2cd236c input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/pyexpat.c.h b/Modules/clinic/pyexpat.c.h +index e57aa8a07d7..9eba59731c3 100644 +--- a/Modules/clinic/pyexpat.c.h ++++ b/Modules/clinic/pyexpat.c.h +@@ -22,7 +22,7 @@ + int enabled); + + static PyObject * +-pyexpat_xmlparser_SetReparseDeferralEnabled(xmlparseobject *self, PyObject *arg) ++pyexpat_xmlparser_SetReparseDeferralEnabled(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + int enabled; +@@ -31,7 +31,7 @@ + if (enabled < 0) { + goto exit; + } +- return_value = pyexpat_xmlparser_SetReparseDeferralEnabled_impl(self, enabled); ++ return_value = pyexpat_xmlparser_SetReparseDeferralEnabled_impl((xmlparseobject *)self, enabled); + + exit: + return return_value; +@@ -50,9 +50,9 @@ + pyexpat_xmlparser_GetReparseDeferralEnabled_impl(xmlparseobject *self); + + static PyObject * +-pyexpat_xmlparser_GetReparseDeferralEnabled(xmlparseobject *self, PyObject *Py_UNUSED(ignored)) ++pyexpat_xmlparser_GetReparseDeferralEnabled(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return pyexpat_xmlparser_GetReparseDeferralEnabled_impl(self); ++ return pyexpat_xmlparser_GetReparseDeferralEnabled_impl((xmlparseobject *)self); + } + + PyDoc_STRVAR(pyexpat_xmlparser_Parse__doc__, +@@ -71,7 +71,7 @@ + PyObject *data, int isfinal); + + static PyObject * +-pyexpat_xmlparser_Parse(xmlparseobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++pyexpat_xmlparser_Parse(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -105,7 +105,7 @@ + goto exit; + } + skip_optional_posonly: +- return_value = pyexpat_xmlparser_Parse_impl(self, cls, data, isfinal); ++ return_value = pyexpat_xmlparser_Parse_impl((xmlparseobject *)self, cls, data, isfinal); + + exit: + return return_value; +@@ -125,7 +125,7 @@ + PyObject *file); + + static PyObject * +-pyexpat_xmlparser_ParseFile(xmlparseobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++pyexpat_xmlparser_ParseFile(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -150,7 +150,7 @@ + goto exit; + } + file = args[0]; +- return_value = pyexpat_xmlparser_ParseFile_impl(self, cls, file); ++ return_value = pyexpat_xmlparser_ParseFile_impl((xmlparseobject *)self, cls, file); + + exit: + return return_value; +@@ -169,7 +169,7 @@ + pyexpat_xmlparser_SetBase_impl(xmlparseobject *self, const char *base); + + static PyObject * +-pyexpat_xmlparser_SetBase(xmlparseobject *self, PyObject *arg) ++pyexpat_xmlparser_SetBase(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + const char *base; +@@ -187,7 +187,7 @@ + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } +- return_value = pyexpat_xmlparser_SetBase_impl(self, base); ++ return_value = pyexpat_xmlparser_SetBase_impl((xmlparseobject *)self, base); + + exit: + return return_value; +@@ -206,9 +206,9 @@ + pyexpat_xmlparser_GetBase_impl(xmlparseobject *self); + + static PyObject * +-pyexpat_xmlparser_GetBase(xmlparseobject *self, PyObject *Py_UNUSED(ignored)) ++pyexpat_xmlparser_GetBase(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return pyexpat_xmlparser_GetBase_impl(self); ++ return pyexpat_xmlparser_GetBase_impl((xmlparseobject *)self); + } + + PyDoc_STRVAR(pyexpat_xmlparser_GetInputContext__doc__, +@@ -227,9 +227,9 @@ + pyexpat_xmlparser_GetInputContext_impl(xmlparseobject *self); + + static PyObject * +-pyexpat_xmlparser_GetInputContext(xmlparseobject *self, PyObject *Py_UNUSED(ignored)) ++pyexpat_xmlparser_GetInputContext(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return pyexpat_xmlparser_GetInputContext_impl(self); ++ return pyexpat_xmlparser_GetInputContext_impl((xmlparseobject *)self); + } + + PyDoc_STRVAR(pyexpat_xmlparser_ExternalEntityParserCreate__doc__, +@@ -249,7 +249,7 @@ + const char *encoding); + + static PyObject * +-pyexpat_xmlparser_ExternalEntityParserCreate(xmlparseobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++pyexpat_xmlparser_ExternalEntityParserCreate(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -309,7 +309,7 @@ + goto exit; + } + skip_optional_posonly: +- return_value = pyexpat_xmlparser_ExternalEntityParserCreate_impl(self, cls, context, encoding); ++ return_value = pyexpat_xmlparser_ExternalEntityParserCreate_impl((xmlparseobject *)self, cls, context, encoding); + + exit: + return return_value; +@@ -333,7 +333,7 @@ + pyexpat_xmlparser_SetParamEntityParsing_impl(xmlparseobject *self, int flag); + + static PyObject * +-pyexpat_xmlparser_SetParamEntityParsing(xmlparseobject *self, PyObject *arg) ++pyexpat_xmlparser_SetParamEntityParsing(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + int flag; +@@ -342,7 +342,7 @@ + if (flag == -1 && PyErr_Occurred()) { + goto exit; + } +- return_value = pyexpat_xmlparser_SetParamEntityParsing_impl(self, flag); ++ return_value = pyexpat_xmlparser_SetParamEntityParsing_impl((xmlparseobject *)self, flag); + + exit: + return return_value; +@@ -368,7 +368,7 @@ + int flag); + + static PyObject * +-pyexpat_xmlparser_UseForeignDTD(xmlparseobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++pyexpat_xmlparser_UseForeignDTD(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -400,7 +400,7 @@ + goto exit; + } + skip_optional_posonly: +- return_value = pyexpat_xmlparser_UseForeignDTD_impl(self, cls, flag); ++ return_value = pyexpat_xmlparser_UseForeignDTD_impl((xmlparseobject *)self, cls, flag); + + exit: + return return_value; +@@ -550,4 +550,4 @@ + #ifndef PYEXPAT_XMLPARSER_USEFOREIGNDTD_METHODDEF + #define PYEXPAT_XMLPARSER_USEFOREIGNDTD_METHODDEF + #endif /* !defined(PYEXPAT_XMLPARSER_USEFOREIGNDTD_METHODDEF) */ +-/*[clinic end generated code: output=63be65cb1823b5f8 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=7ee30ae5b666d0a8 input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/selectmodule.c.h b/Modules/clinic/selectmodule.c.h +index 806a888d6b8..d8bdd6f95f3 100644 +--- a/Modules/clinic/selectmodule.c.h ++++ b/Modules/clinic/selectmodule.c.h +@@ -91,7 +91,7 @@ + select_poll_register_impl(pollObject *self, int fd, unsigned short eventmask); + + static PyObject * +-select_poll_register(pollObject *self, PyObject *const *args, Py_ssize_t nargs) ++select_poll_register(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + int fd; +@@ -112,7 +112,7 @@ + } + skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = select_poll_register_impl(self, fd, eventmask); ++ return_value = select_poll_register_impl((pollObject *)self, fd, eventmask); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -142,7 +142,7 @@ + select_poll_modify_impl(pollObject *self, int fd, unsigned short eventmask); + + static PyObject * +-select_poll_modify(pollObject *self, PyObject *const *args, Py_ssize_t nargs) ++select_poll_modify(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + int fd; +@@ -159,7 +159,7 @@ + goto exit; + } + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = select_poll_modify_impl(self, fd, eventmask); ++ return_value = select_poll_modify_impl((pollObject *)self, fd, eventmask); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -183,7 +183,7 @@ + select_poll_unregister_impl(pollObject *self, int fd); + + static PyObject * +-select_poll_unregister(pollObject *self, PyObject *arg) ++select_poll_unregister(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + int fd; +@@ -193,7 +193,7 @@ + goto exit; + } + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = select_poll_unregister_impl(self, fd); ++ return_value = select_poll_unregister_impl((pollObject *)self, fd); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -224,7 +224,7 @@ + select_poll_poll_impl(pollObject *self, PyObject *timeout_obj); + + static PyObject * +-select_poll_poll(pollObject *self, PyObject *const *args, Py_ssize_t nargs) ++select_poll_poll(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *timeout_obj = Py_None; +@@ -238,7 +238,7 @@ + timeout_obj = args[0]; + skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = select_poll_poll_impl(self, timeout_obj); ++ return_value = select_poll_poll_impl((pollObject *)self, timeout_obj); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -270,7 +270,7 @@ + unsigned short eventmask); + + static PyObject * +-select_devpoll_register(devpollObject *self, PyObject *const *args, Py_ssize_t nargs) ++select_devpoll_register(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + int fd; +@@ -291,7 +291,7 @@ + } + skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = select_devpoll_register_impl(self, fd, eventmask); ++ return_value = select_devpoll_register_impl((devpollObject *)self, fd, eventmask); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -323,7 +323,7 @@ + unsigned short eventmask); + + static PyObject * +-select_devpoll_modify(devpollObject *self, PyObject *const *args, Py_ssize_t nargs) ++select_devpoll_modify(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + int fd; +@@ -344,7 +344,7 @@ + } + skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = select_devpoll_modify_impl(self, fd, eventmask); ++ return_value = select_devpoll_modify_impl((devpollObject *)self, fd, eventmask); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -368,7 +368,7 @@ + select_devpoll_unregister_impl(devpollObject *self, int fd); + + static PyObject * +-select_devpoll_unregister(devpollObject *self, PyObject *arg) ++select_devpoll_unregister(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + int fd; +@@ -378,7 +378,7 @@ + goto exit; + } + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = select_devpoll_unregister_impl(self, fd); ++ return_value = select_devpoll_unregister_impl((devpollObject *)self, fd); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -409,7 +409,7 @@ + select_devpoll_poll_impl(devpollObject *self, PyObject *timeout_obj); + + static PyObject * +-select_devpoll_poll(devpollObject *self, PyObject *const *args, Py_ssize_t nargs) ++select_devpoll_poll(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *timeout_obj = Py_None; +@@ -423,7 +423,7 @@ + timeout_obj = args[0]; + skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = select_devpoll_poll_impl(self, timeout_obj); ++ return_value = select_devpoll_poll_impl((devpollObject *)self, timeout_obj); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -449,12 +449,12 @@ + select_devpoll_close_impl(devpollObject *self); + + static PyObject * +-select_devpoll_close(devpollObject *self, PyObject *Py_UNUSED(ignored)) ++select_devpoll_close(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = select_devpoll_close_impl(self); ++ return_value = select_devpoll_close_impl((devpollObject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -477,12 +477,12 @@ + select_devpoll_fileno_impl(devpollObject *self); + + static PyObject * +-select_devpoll_fileno(devpollObject *self, PyObject *Py_UNUSED(ignored)) ++select_devpoll_fileno(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = select_devpoll_fileno_impl(self); ++ return_value = select_devpoll_fileno_impl((devpollObject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -643,12 +643,12 @@ + select_epoll_close_impl(pyEpoll_Object *self); + + static PyObject * +-select_epoll_close(pyEpoll_Object *self, PyObject *Py_UNUSED(ignored)) ++select_epoll_close(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = select_epoll_close_impl(self); ++ return_value = select_epoll_close_impl((pyEpoll_Object *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -671,9 +671,9 @@ + select_epoll_fileno_impl(pyEpoll_Object *self); + + static PyObject * +-select_epoll_fileno(pyEpoll_Object *self, PyObject *Py_UNUSED(ignored)) ++select_epoll_fileno(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return select_epoll_fileno_impl(self); ++ return select_epoll_fileno_impl((pyEpoll_Object *)self); + } + + #endif /* defined(HAVE_EPOLL) */ +@@ -734,7 +734,7 @@ + unsigned int eventmask); + + static PyObject * +-select_epoll_register(pyEpoll_Object *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++select_epoll_register(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -784,7 +784,7 @@ + goto exit; + } + skip_optional_pos: +- return_value = select_epoll_register_impl(self, fd, eventmask); ++ return_value = select_epoll_register_impl((pyEpoll_Object *)self, fd, eventmask); + + exit: + return return_value; +@@ -813,7 +813,7 @@ + unsigned int eventmask); + + static PyObject * +-select_epoll_modify(pyEpoll_Object *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++select_epoll_modify(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -858,7 +858,7 @@ + if (eventmask == (unsigned int)-1 && PyErr_Occurred()) { + goto exit; + } +- return_value = select_epoll_modify_impl(self, fd, eventmask); ++ return_value = select_epoll_modify_impl((pyEpoll_Object *)self, fd, eventmask); + + exit: + return return_value; +@@ -884,7 +884,7 @@ + select_epoll_unregister_impl(pyEpoll_Object *self, int fd); + + static PyObject * +-select_epoll_unregister(pyEpoll_Object *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++select_epoll_unregister(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -924,7 +924,7 @@ + if (fd < 0) { + goto exit; + } +- return_value = select_epoll_unregister_impl(self, fd); ++ return_value = select_epoll_unregister_impl((pyEpoll_Object *)self, fd); + + exit: + return return_value; +@@ -957,7 +957,7 @@ + int maxevents); + + static PyObject * +-select_epoll_poll(pyEpoll_Object *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++select_epoll_poll(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -1009,7 +1009,7 @@ + goto exit; + } + skip_optional_pos: +- return_value = select_epoll_poll_impl(self, timeout_obj, maxevents); ++ return_value = select_epoll_poll_impl((pyEpoll_Object *)self, timeout_obj, maxevents); + + exit: + return return_value; +@@ -1031,9 +1031,9 @@ + select_epoll___enter___impl(pyEpoll_Object *self); + + static PyObject * +-select_epoll___enter__(pyEpoll_Object *self, PyObject *Py_UNUSED(ignored)) ++select_epoll___enter__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return select_epoll___enter___impl(self); ++ return select_epoll___enter___impl((pyEpoll_Object *)self); + } + + #endif /* defined(HAVE_EPOLL) */ +@@ -1053,7 +1053,7 @@ + PyObject *exc_value, PyObject *exc_tb); + + static PyObject * +-select_epoll___exit__(pyEpoll_Object *self, PyObject *const *args, Py_ssize_t nargs) ++select_epoll___exit__(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *exc_type = Py_None; +@@ -1076,7 +1076,7 @@ + } + exc_tb = args[2]; + skip_optional: +- return_value = select_epoll___exit___impl(self, exc_type, exc_value, exc_tb); ++ return_value = select_epoll___exit___impl((pyEpoll_Object *)self, exc_type, exc_value, exc_tb); + + exit: + return return_value; +@@ -1146,12 +1146,12 @@ + select_kqueue_close_impl(kqueue_queue_Object *self); + + static PyObject * +-select_kqueue_close(kqueue_queue_Object *self, PyObject *Py_UNUSED(ignored)) ++select_kqueue_close(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = select_kqueue_close_impl(self); ++ return_value = select_kqueue_close_impl((kqueue_queue_Object *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -1174,9 +1174,9 @@ + select_kqueue_fileno_impl(kqueue_queue_Object *self); + + static PyObject * +-select_kqueue_fileno(kqueue_queue_Object *self, PyObject *Py_UNUSED(ignored)) ++select_kqueue_fileno(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return select_kqueue_fileno_impl(self); ++ return select_kqueue_fileno_impl((kqueue_queue_Object *)self); + } + + #endif /* defined(HAVE_KQUEUE) */ +@@ -1238,7 +1238,7 @@ + int maxevents, PyObject *otimeout); + + static PyObject * +-select_kqueue_control(kqueue_queue_Object *self, PyObject *const *args, Py_ssize_t nargs) ++select_kqueue_control(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *changelist; +@@ -1258,7 +1258,7 @@ + } + otimeout = args[2]; + skip_optional: +- return_value = select_kqueue_control_impl(self, changelist, maxevents, otimeout); ++ return_value = select_kqueue_control_impl((kqueue_queue_Object *)self, changelist, maxevents, otimeout); + + exit: + return return_value; +@@ -1365,4 +1365,4 @@ + #ifndef SELECT_KQUEUE_CONTROL_METHODDEF + #define SELECT_KQUEUE_CONTROL_METHODDEF + #endif /* !defined(SELECT_KQUEUE_CONTROL_METHODDEF) */ +-/*[clinic end generated code: output=78b4e67f7d401b5e input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=c18fd93efc5f4dce input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/sha1module.c.h b/Modules/clinic/sha1module.c.h +index 6af77ba64ec..ddd8e66a41d 100644 +--- a/Modules/clinic/sha1module.c.h ++++ b/Modules/clinic/sha1module.c.h +@@ -21,13 +21,13 @@ + SHA1Type_copy_impl(SHA1object *self, PyTypeObject *cls); + + static PyObject * +-SHA1Type_copy(SHA1object *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++SHA1Type_copy(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "copy() takes no arguments"); + return NULL; + } +- return SHA1Type_copy_impl(self, cls); ++ return SHA1Type_copy_impl((SHA1object *)self, cls); + } + + PyDoc_STRVAR(SHA1Type_digest__doc__, +@@ -43,9 +43,9 @@ + SHA1Type_digest_impl(SHA1object *self); + + static PyObject * +-SHA1Type_digest(SHA1object *self, PyObject *Py_UNUSED(ignored)) ++SHA1Type_digest(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return SHA1Type_digest_impl(self); ++ return SHA1Type_digest_impl((SHA1object *)self); + } + + PyDoc_STRVAR(SHA1Type_hexdigest__doc__, +@@ -61,9 +61,9 @@ + SHA1Type_hexdigest_impl(SHA1object *self); + + static PyObject * +-SHA1Type_hexdigest(SHA1object *self, PyObject *Py_UNUSED(ignored)) ++SHA1Type_hexdigest(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return SHA1Type_hexdigest_impl(self); ++ return SHA1Type_hexdigest_impl((SHA1object *)self); + } + + PyDoc_STRVAR(SHA1Type_update__doc__, +@@ -149,4 +149,4 @@ + exit: + return return_value; + } +-/*[clinic end generated code: output=917e2789f1f5ebf9 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=ad6f3788a6e7ff6f input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/sha2module.c.h b/Modules/clinic/sha2module.c.h +index fec655a0dfa..d86f5510d75 100644 +--- a/Modules/clinic/sha2module.c.h ++++ b/Modules/clinic/sha2module.c.h +@@ -21,13 +21,13 @@ + SHA256Type_copy_impl(SHA256object *self, PyTypeObject *cls); + + static PyObject * +-SHA256Type_copy(SHA256object *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++SHA256Type_copy(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "copy() takes no arguments"); + return NULL; + } +- return SHA256Type_copy_impl(self, cls); ++ return SHA256Type_copy_impl((SHA256object *)self, cls); + } + + PyDoc_STRVAR(SHA512Type_copy__doc__, +@@ -43,13 +43,13 @@ + SHA512Type_copy_impl(SHA512object *self, PyTypeObject *cls); + + static PyObject * +-SHA512Type_copy(SHA512object *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++SHA512Type_copy(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "copy() takes no arguments"); + return NULL; + } +- return SHA512Type_copy_impl(self, cls); ++ return SHA512Type_copy_impl((SHA512object *)self, cls); + } + + PyDoc_STRVAR(SHA256Type_digest__doc__, +@@ -65,9 +65,9 @@ + SHA256Type_digest_impl(SHA256object *self); + + static PyObject * +-SHA256Type_digest(SHA256object *self, PyObject *Py_UNUSED(ignored)) ++SHA256Type_digest(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return SHA256Type_digest_impl(self); ++ return SHA256Type_digest_impl((SHA256object *)self); + } + + PyDoc_STRVAR(SHA512Type_digest__doc__, +@@ -83,9 +83,9 @@ + SHA512Type_digest_impl(SHA512object *self); + + static PyObject * +-SHA512Type_digest(SHA512object *self, PyObject *Py_UNUSED(ignored)) ++SHA512Type_digest(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return SHA512Type_digest_impl(self); ++ return SHA512Type_digest_impl((SHA512object *)self); + } + + PyDoc_STRVAR(SHA256Type_hexdigest__doc__, +@@ -101,9 +101,9 @@ + SHA256Type_hexdigest_impl(SHA256object *self); + + static PyObject * +-SHA256Type_hexdigest(SHA256object *self, PyObject *Py_UNUSED(ignored)) ++SHA256Type_hexdigest(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return SHA256Type_hexdigest_impl(self); ++ return SHA256Type_hexdigest_impl((SHA256object *)self); + } + + PyDoc_STRVAR(SHA512Type_hexdigest__doc__, +@@ -119,9 +119,9 @@ + SHA512Type_hexdigest_impl(SHA512object *self); + + static PyObject * +-SHA512Type_hexdigest(SHA512object *self, PyObject *Py_UNUSED(ignored)) ++SHA512Type_hexdigest(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return SHA512Type_hexdigest_impl(self); ++ return SHA512Type_hexdigest_impl((SHA512object *)self); + } + + PyDoc_STRVAR(SHA256Type_update__doc__, +@@ -441,4 +441,4 @@ + exit: + return return_value; + } +-/*[clinic end generated code: output=602a6939b8ec0927 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=1d7fec114eb6b6e3 input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/sha3module.c.h b/Modules/clinic/sha3module.c.h +index d9f4b66f81a..729e216ce02 100644 +--- a/Modules/clinic/sha3module.c.h ++++ b/Modules/clinic/sha3module.c.h +@@ -92,9 +92,9 @@ + _sha3_sha3_224_copy_impl(SHA3object *self); + + static PyObject * +-_sha3_sha3_224_copy(SHA3object *self, PyObject *Py_UNUSED(ignored)) ++_sha3_sha3_224_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _sha3_sha3_224_copy_impl(self); ++ return _sha3_sha3_224_copy_impl((SHA3object *)self); + } + + PyDoc_STRVAR(_sha3_sha3_224_digest__doc__, +@@ -110,9 +110,9 @@ + _sha3_sha3_224_digest_impl(SHA3object *self); + + static PyObject * +-_sha3_sha3_224_digest(SHA3object *self, PyObject *Py_UNUSED(ignored)) ++_sha3_sha3_224_digest(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _sha3_sha3_224_digest_impl(self); ++ return _sha3_sha3_224_digest_impl((SHA3object *)self); + } + + PyDoc_STRVAR(_sha3_sha3_224_hexdigest__doc__, +@@ -128,9 +128,9 @@ + _sha3_sha3_224_hexdigest_impl(SHA3object *self); + + static PyObject * +-_sha3_sha3_224_hexdigest(SHA3object *self, PyObject *Py_UNUSED(ignored)) ++_sha3_sha3_224_hexdigest(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _sha3_sha3_224_hexdigest_impl(self); ++ return _sha3_sha3_224_hexdigest_impl((SHA3object *)self); + } + + PyDoc_STRVAR(_sha3_sha3_224_update__doc__, +@@ -155,7 +155,7 @@ + _sha3_shake_128_digest_impl(SHA3object *self, unsigned long length); + + static PyObject * +-_sha3_shake_128_digest(SHA3object *self, PyObject *arg) ++_sha3_shake_128_digest(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + unsigned long length; +@@ -163,7 +163,7 @@ + if (!_PyLong_UnsignedLong_Converter(arg, &length)) { + goto exit; + } +- return_value = _sha3_shake_128_digest_impl(self, length); ++ return_value = _sha3_shake_128_digest_impl((SHA3object *)self, length); + + exit: + return return_value; +@@ -182,7 +182,7 @@ + _sha3_shake_128_hexdigest_impl(SHA3object *self, unsigned long length); + + static PyObject * +-_sha3_shake_128_hexdigest(SHA3object *self, PyObject *arg) ++_sha3_shake_128_hexdigest(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + unsigned long length; +@@ -190,9 +190,9 @@ + if (!_PyLong_UnsignedLong_Converter(arg, &length)) { + goto exit; + } +- return_value = _sha3_shake_128_hexdigest_impl(self, length); ++ return_value = _sha3_shake_128_hexdigest_impl((SHA3object *)self, length); + + exit: + return return_value; + } +-/*[clinic end generated code: output=5c644eb0ed42b993 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=21da06d9570969d8 input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/socketmodule.c.h b/Modules/clinic/socketmodule.c.h +index db1a28b86c8..dc62c4290d3 100644 +--- a/Modules/clinic/socketmodule.c.h ++++ b/Modules/clinic/socketmodule.c.h +@@ -6,7 +6,6 @@ + # include "pycore_gc.h" // PyGC_Head + # include "pycore_runtime.h" // _Py_ID() + #endif +-#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() + #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() + + PyDoc_STRVAR(_socket_socket_close__doc__, +@@ -24,15 +23,9 @@ + _socket_socket_close_impl(PySocketSockObject *s); + + static PyObject * +-_socket_socket_close(PySocketSockObject *s, PyObject *Py_UNUSED(ignored)) ++_socket_socket_close(PyObject *s, PyObject *Py_UNUSED(ignored)) + { +- PyObject *return_value = NULL; +- +- Py_BEGIN_CRITICAL_SECTION(s); +- return_value = _socket_socket_close_impl(s); +- Py_END_CRITICAL_SECTION(); +- +- return return_value; ++ return _socket_socket_close_impl((PySocketSockObject *)s); + } + + static int +@@ -133,7 +126,7 @@ + _socket_socket_ntohs_impl(PySocketSockObject *self, int x); + + static PyObject * +-_socket_socket_ntohs(PySocketSockObject *self, PyObject *arg) ++_socket_socket_ntohs(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + int x; +@@ -142,7 +135,7 @@ + if (x == -1 && PyErr_Occurred()) { + goto exit; + } +- return_value = _socket_socket_ntohs_impl(self, x); ++ return_value = _socket_socket_ntohs_impl((PySocketSockObject *)self, x); + + exit: + return return_value; +@@ -161,7 +154,7 @@ + _socket_socket_htons_impl(PySocketSockObject *self, int x); + + static PyObject * +-_socket_socket_htons(PySocketSockObject *self, PyObject *arg) ++_socket_socket_htons(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + int x; +@@ -170,7 +163,7 @@ + if (x == -1 && PyErr_Occurred()) { + goto exit; + } +- return_value = _socket_socket_htons_impl(self, x); ++ return_value = _socket_socket_htons_impl((PySocketSockObject *)self, x); + + exit: + return return_value; +@@ -189,7 +182,7 @@ + _socket_socket_inet_aton_impl(PySocketSockObject *self, const char *ip_addr); + + static PyObject * +-_socket_socket_inet_aton(PySocketSockObject *self, PyObject *arg) ++_socket_socket_inet_aton(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + const char *ip_addr; +@@ -207,7 +200,7 @@ + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } +- return_value = _socket_socket_inet_aton_impl(self, ip_addr); ++ return_value = _socket_socket_inet_aton_impl((PySocketSockObject *)self, ip_addr); + + exit: + return return_value; +@@ -228,7 +221,7 @@ + _socket_socket_inet_ntoa_impl(PySocketSockObject *self, Py_buffer *packed_ip); + + static PyObject * +-_socket_socket_inet_ntoa(PySocketSockObject *self, PyObject *arg) ++_socket_socket_inet_ntoa(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + Py_buffer packed_ip = {NULL, NULL}; +@@ -236,7 +229,7 @@ + if (PyObject_GetBuffer(arg, &packed_ip, PyBUF_SIMPLE) != 0) { + goto exit; + } +- return_value = _socket_socket_inet_ntoa_impl(self, &packed_ip); ++ return_value = _socket_socket_inet_ntoa_impl((PySocketSockObject *)self, &packed_ip); + + exit: + /* Cleanup for packed_ip */ +@@ -264,7 +257,7 @@ + _socket_socket_if_nametoindex_impl(PySocketSockObject *self, PyObject *oname); + + static PyObject * +-_socket_socket_if_nametoindex(PySocketSockObject *self, PyObject *arg) ++_socket_socket_if_nametoindex(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + PyObject *oname; +@@ -272,7 +265,7 @@ + if (!PyUnicode_FSConverter(arg, &oname)) { + goto exit; + } +- return_value = _socket_socket_if_nametoindex_impl(self, oname); ++ return_value = _socket_socket_if_nametoindex_impl((PySocketSockObject *)self, oname); + + exit: + return return_value; +@@ -287,4 +280,4 @@ + #ifndef _SOCKET_SOCKET_IF_NAMETOINDEX_METHODDEF + #define _SOCKET_SOCKET_IF_NAMETOINDEX_METHODDEF + #endif /* !defined(_SOCKET_SOCKET_IF_NAMETOINDEX_METHODDEF) */ +-/*[clinic end generated code: output=59c36bb31b05de68 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=d39efc30d811e74b input=a9049054013a1b77]*/ +diff --git a/Modules/clinic/zlibmodule.c.h b/Modules/clinic/zlibmodule.c.h +index 19906dc328d..91a3ac76bcf 100644 +--- a/Modules/clinic/zlibmodule.c.h ++++ b/Modules/clinic/zlibmodule.c.h +@@ -439,7 +439,7 @@ + Py_buffer *data); + + static PyObject * +-zlib_Compress_compress(compobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++zlib_Compress_compress(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -466,7 +466,7 @@ + if (PyObject_GetBuffer(args[0], &data, PyBUF_SIMPLE) != 0) { + goto exit; + } +- return_value = zlib_Compress_compress_impl(self, cls, &data); ++ return_value = zlib_Compress_compress_impl((compobject *)self, cls, &data); + + exit: + /* Cleanup for data */ +@@ -502,7 +502,7 @@ + Py_buffer *data, Py_ssize_t max_length); + + static PyObject * +-zlib_Decompress_decompress(compobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++zlib_Decompress_decompress(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -559,7 +559,7 @@ + max_length = ival; + } + skip_optional_pos: +- return_value = zlib_Decompress_decompress_impl(self, cls, &data, max_length); ++ return_value = zlib_Decompress_decompress_impl((compobject *)self, cls, &data, max_length); + + exit: + /* Cleanup for data */ +@@ -589,7 +589,7 @@ + zlib_Compress_flush_impl(compobject *self, PyTypeObject *cls, int mode); + + static PyObject * +-zlib_Compress_flush(compobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++zlib_Compress_flush(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -621,7 +621,7 @@ + goto exit; + } + skip_optional_posonly: +- return_value = zlib_Compress_flush_impl(self, cls, mode); ++ return_value = zlib_Compress_flush_impl((compobject *)self, cls, mode); + + exit: + return return_value; +@@ -642,13 +642,13 @@ + zlib_Compress_copy_impl(compobject *self, PyTypeObject *cls); + + static PyObject * +-zlib_Compress_copy(compobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++zlib_Compress_copy(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "copy() takes no arguments"); + return NULL; + } +- return zlib_Compress_copy_impl(self, cls); ++ return zlib_Compress_copy_impl((compobject *)self, cls); + } + + #endif /* defined(HAVE_ZLIB_COPY) */ +@@ -667,13 +667,13 @@ + zlib_Compress___copy___impl(compobject *self, PyTypeObject *cls); + + static PyObject * +-zlib_Compress___copy__(compobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++zlib_Compress___copy__(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "__copy__() takes no arguments"); + return NULL; + } +- return zlib_Compress___copy___impl(self, cls); ++ return zlib_Compress___copy___impl((compobject *)self, cls); + } + + #endif /* defined(HAVE_ZLIB_COPY) */ +@@ -693,7 +693,7 @@ + PyObject *memo); + + static PyObject * +-zlib_Compress___deepcopy__(compobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++zlib_Compress___deepcopy__(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -718,7 +718,7 @@ + goto exit; + } + memo = args[0]; +- return_value = zlib_Compress___deepcopy___impl(self, cls, memo); ++ return_value = zlib_Compress___deepcopy___impl((compobject *)self, cls, memo); + + exit: + return return_value; +@@ -741,13 +741,13 @@ + zlib_Decompress_copy_impl(compobject *self, PyTypeObject *cls); + + static PyObject * +-zlib_Decompress_copy(compobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++zlib_Decompress_copy(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "copy() takes no arguments"); + return NULL; + } +- return zlib_Decompress_copy_impl(self, cls); ++ return zlib_Decompress_copy_impl((compobject *)self, cls); + } + + #endif /* defined(HAVE_ZLIB_COPY) */ +@@ -766,13 +766,13 @@ + zlib_Decompress___copy___impl(compobject *self, PyTypeObject *cls); + + static PyObject * +-zlib_Decompress___copy__(compobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++zlib_Decompress___copy__(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "__copy__() takes no arguments"); + return NULL; + } +- return zlib_Decompress___copy___impl(self, cls); ++ return zlib_Decompress___copy___impl((compobject *)self, cls); + } + + #endif /* defined(HAVE_ZLIB_COPY) */ +@@ -792,7 +792,7 @@ + PyObject *memo); + + static PyObject * +-zlib_Decompress___deepcopy__(compobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++zlib_Decompress___deepcopy__(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -817,7 +817,7 @@ + goto exit; + } + memo = args[0]; +- return_value = zlib_Decompress___deepcopy___impl(self, cls, memo); ++ return_value = zlib_Decompress___deepcopy___impl((compobject *)self, cls, memo); + + exit: + return return_value; +@@ -842,7 +842,7 @@ + Py_ssize_t length); + + static PyObject * +-zlib_Decompress_flush(compobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++zlib_Decompress_flush(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -882,7 +882,7 @@ + length = ival; + } + skip_optional_posonly: +- return_value = zlib_Decompress_flush_impl(self, cls, length); ++ return_value = zlib_Decompress_flush_impl((compobject *)self, cls, length); + + exit: + return return_value; +@@ -915,7 +915,7 @@ + Py_buffer *data, Py_ssize_t max_length); + + static PyObject * +-zlib_ZlibDecompressor_decompress(ZlibDecompressor *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++zlib_ZlibDecompressor_decompress(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -972,7 +972,7 @@ + max_length = ival; + } + skip_optional_pos: +- return_value = zlib_ZlibDecompressor_decompress_impl(self, &data, max_length); ++ return_value = zlib_ZlibDecompressor_decompress_impl((ZlibDecompressor *)self, &data, max_length); + + exit: + /* Cleanup for data */ +@@ -1109,4 +1109,4 @@ + #ifndef ZLIB_DECOMPRESS___DEEPCOPY___METHODDEF + #define ZLIB_DECOMPRESS___DEEPCOPY___METHODDEF + #endif /* !defined(ZLIB_DECOMPRESS___DEEPCOPY___METHODDEF) */ +-/*[clinic end generated code: output=2fef49f168842b17 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=969872868c303e8a input=a9049054013a1b77]*/ +diff --git a/Modules/config.c.in b/Modules/config.c.in +index 53b4fb28549..c578cd103dc 100644 +--- a/Modules/config.c.in ++++ b/Modules/config.c.in +@@ -1,13 +1,3 @@ +-/* -*- C -*- *********************************************** +-Copyright (c) 2000, BeOpen.com. +-Copyright (c) 1995-2000, Corporation for National Research Initiatives. +-Copyright (c) 1990-1995, Stichting Mathematisch Centrum. +-All rights reserved. +- +-See the file "Misc/COPYRIGHT" for information on usage and +-redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. +-******************************************************************/ +- + /* Module configuration */ + + /* !!! !!! !!! This file is edited by the makesetup script !!! !!! !!! */ +diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c +index b62362f2777..a15ced22677 100644 +--- a/Modules/faulthandler.c ++++ b/Modules/faulthandler.c +@@ -1,4 +1,5 @@ + #include "Python.h" ++#include "pycore_ceval.h" // _PyEval_IsGILEnabled + #include "pycore_initconfig.h" // _PyStatus_ERR + #include "pycore_pyerrors.h" // _Py_DumpExtensionModules + #include "pycore_pystate.h" // _PyThreadState_GET() +@@ -27,6 +28,8 @@ + # include // getauxval() + #endif + ++/* Sentinel to ignore all_threads on free-threading */ ++#define FT_IGNORE_ALL_THREADS 2 + + /* Allocate at maximum 100 MiB of the stack to raise the stack overflow */ + #define STACK_OVERFLOW_MAX_SIZE (100 * 1024 * 1024) +@@ -201,10 +204,13 @@ + PyGILState_GetThisThreadState(). */ + PyThreadState *tstate = PyGILState_GetThisThreadState(); + +- if (all_threads) { ++ if (all_threads == 1) { + (void)_Py_DumpTracebackThreads(fd, NULL, tstate); + } + else { ++ if (all_threads == FT_IGNORE_ALL_THREADS) { ++ PUTS(fd, "\n"); ++ } + if (tstate != NULL) + _Py_DumpTraceback(fd, tstate); + } +@@ -237,7 +243,12 @@ + return NULL; + + if (all_threads) { ++ PyInterpreterState *interp = _PyInterpreterState_GET(); ++ /* gh-128400: Accessing other thread states while they're running ++ * isn't safe if those threads are running. */ ++ _PyEval_StopTheWorld(interp); + errmsg = _Py_DumpTracebackThreads(fd, NULL, tstate); ++ _PyEval_StartTheWorld(interp); + if (errmsg != NULL) { + PyErr_SetString(PyExc_RuntimeError, errmsg); + return NULL; +@@ -266,6 +277,27 @@ + #endif + } + ++static int ++deduce_all_threads(void) ++{ ++#ifndef Py_GIL_DISABLED ++ return fatal_error.all_threads; ++#else ++ if (fatal_error.all_threads == 0) { ++ return 0; ++ } ++ // We can't use _PyThreadState_GET, so use the stored GILstate one ++ PyThreadState *tstate = PyGILState_GetThisThreadState(); ++ if (tstate == NULL) { ++ return 0; ++ } ++ ++ /* In theory, it's safe to dump all threads if the GIL is enabled */ ++ return _PyEval_IsGILEnabled(tstate) ++ ? fatal_error.all_threads ++ : FT_IGNORE_ALL_THREADS; ++#endif ++} + + /* Handler for SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL signals. + +@@ -320,7 +352,7 @@ + PUTS(fd, "\n\n"); + } + +- faulthandler_dump_traceback(fd, fatal_error.all_threads, ++ faulthandler_dump_traceback(fd, deduce_all_threads(), + fatal_error.interp); + + _Py_DumpExtensionModules(fd, fatal_error.interp); +@@ -396,7 +428,7 @@ + } + } + +- faulthandler_dump_traceback(fd, fatal_error.all_threads, ++ faulthandler_dump_traceback(fd, deduce_all_threads(), + fatal_error.interp); + + /* call the next exception handler */ +@@ -1314,7 +1346,7 @@ + static int + faulthandler_init_enable(void) + { +- PyObject *enable = _PyImport_GetModuleAttrString("faulthandler", "enable"); ++ PyObject *enable = PyImport_ImportModuleAttrString("faulthandler", "enable"); + if (enable == NULL) { + return -1; + } +diff --git a/Modules/getpath.c b/Modules/getpath.c +index 18ddfaf8dbc..e2478da021f 100644 +--- a/Modules/getpath.c ++++ b/Modules/getpath.c +@@ -17,10 +17,13 @@ + #endif + + #ifdef __APPLE__ +-# include + # include + #endif + ++#ifdef HAVE_DLFCN_H ++# include ++#endif ++ + /* Reference the precompiled getpath.py */ + #include "Python/frozen_modules/getpath.h" + +@@ -803,36 +806,25 @@ + static int + library_to_dict(PyObject *dict, const char *key) + { ++/* macOS framework builds do not link against a libpython dynamic library, but ++ instead link against a macOS Framework. */ ++#if defined(Py_ENABLE_SHARED) || defined(WITH_NEXT_FRAMEWORK) ++ + #ifdef MS_WINDOWS +-#ifdef Py_ENABLE_SHARED + extern HMODULE PyWin_DLLhModule; + if (PyWin_DLLhModule) { + return winmodule_to_dict(dict, key, PyWin_DLLhModule); + } + #endif +-#elif defined(WITH_NEXT_FRAMEWORK) +- static char modPath[MAXPATHLEN + 1]; +- static int modPathInitialized = -1; +- if (modPathInitialized < 0) { +- modPathInitialized = 0; +- +- /* On Mac OS X we have a special case if we're running from a framework. +- This is because the python home should be set relative to the library, +- which is in the framework, not relative to the executable, which may +- be outside of the framework. Except when we're in the build +- directory... */ +- Dl_info pythonInfo; +- if (dladdr(&Py_Initialize, &pythonInfo)) { +- if (pythonInfo.dli_fname) { +- strncpy(modPath, pythonInfo.dli_fname, MAXPATHLEN); +- modPathInitialized = 1; +- } +- } +- } +- if (modPathInitialized > 0) { +- return decode_to_dict(dict, key, modPath); ++ ++#if HAVE_DLADDR ++ Dl_info libpython_info; ++ if (dladdr(&Py_Initialize, &libpython_info) && libpython_info.dli_fname) { ++ return decode_to_dict(dict, key, libpython_info.dli_fname); + } + #endif ++#endif ++ + return PyDict_SetItemString(dict, key, Py_None) == 0; + } + +@@ -963,7 +955,7 @@ + ) { + Py_DECREF(co); + Py_DECREF(dict); +- PyErr_FormatUnraisable("Exception ignored in preparing getpath"); ++ PyErr_FormatUnraisable("Exception ignored while preparing getpath"); + return PyStatus_Error("error evaluating initial values"); + } + +@@ -972,13 +964,13 @@ + + if (!r) { + Py_DECREF(dict); +- PyErr_FormatUnraisable("Exception ignored in running getpath"); ++ PyErr_FormatUnraisable("Exception ignored while running getpath"); + return PyStatus_Error("error evaluating path"); + } + Py_DECREF(r); + + if (_PyConfig_FromDict(config, configDict) < 0) { +- PyErr_FormatUnraisable("Exception ignored in reading getpath results"); ++ PyErr_FormatUnraisable("Exception ignored while reading getpath results"); + Py_DECREF(dict); + return PyStatus_Error("error getting getpath results"); + } +diff --git a/Modules/getpath.py b/Modules/getpath.py +index c34101e7208..be2210345af 100644 +--- a/Modules/getpath.py ++++ b/Modules/getpath.py +@@ -625,6 +625,8 @@ + # gh-100320: Our PYDs are assumed to be relative to the Lib directory + # (that is, prefix) rather than the executable (that is, executable_dir) + exec_prefix = prefix ++ if not exec_prefix and prefix and isdir(joinpath(prefix, PLATSTDLIB_LANDMARK)): ++ exec_prefix = prefix + if not exec_prefix and executable_dir: + exec_prefix = search_up(executable_dir, PLATSTDLIB_LANDMARK, test=isdir) + if not exec_prefix and EXEC_PREFIX: +diff --git a/Modules/main.c b/Modules/main.c +index 15ea49a1bad..f8a2438cdd0 100644 +--- a/Modules/main.c ++++ b/Modules/main.c +@@ -314,25 +314,19 @@ + static int + pymain_run_module(const wchar_t *modname, int set_argv0) + { +- PyObject *module, *runpy, *runmodule, *runargs, *result; ++ PyObject *module, *runmodule, *runargs, *result; + if (PySys_Audit("cpython.run_module", "u", modname) < 0) { + return pymain_exit_err_print(); + } +- runpy = PyImport_ImportModule("runpy"); +- if (runpy == NULL) { +- fprintf(stderr, "Could not import runpy module\n"); +- return pymain_exit_err_print(); +- } +- runmodule = PyObject_GetAttrString(runpy, "_run_module_as_main"); ++ runmodule = PyImport_ImportModuleAttrString("runpy", ++ "_run_module_as_main"); + if (runmodule == NULL) { +- fprintf(stderr, "Could not access runpy._run_module_as_main\n"); +- Py_DECREF(runpy); ++ fprintf(stderr, "Could not import runpy._run_module_as_main\n"); + return pymain_exit_err_print(); + } + module = PyUnicode_FromWideChar(modname, wcslen(modname)); + if (module == NULL) { + fprintf(stderr, "Could not convert module name to unicode\n"); +- Py_DECREF(runpy); + Py_DECREF(runmodule); + return pymain_exit_err_print(); + } +@@ -340,7 +334,6 @@ + if (runargs == NULL) { + fprintf(stderr, + "Could not create arguments for runpy._run_module_as_main\n"); +- Py_DECREF(runpy); + Py_DECREF(runmodule); + Py_DECREF(module); + return pymain_exit_err_print(); +@@ -350,7 +343,6 @@ + if (!result && PyErr_Occurred() == PyExc_KeyboardInterrupt) { + _PyRuntime.signals.unhandled_keyboard_interrupt = 1; + } +- Py_DECREF(runpy); + Py_DECREF(runmodule); + Py_DECREF(module); + Py_DECREF(runargs); +@@ -370,10 +362,11 @@ + return pymain_exit_err_print(); + } + +- FILE *fp = _Py_fopen_obj(filename, "rb"); ++ FILE *fp = Py_fopen(filename, "rb"); + if (fp == NULL) { + // Ignore the OSError + PyErr_Clear(); ++ // TODO(picnixz): strerror() is locale dependent but not PySys_FormatStderr(). + PySys_FormatStderr("%S: can't open file %R: [Errno %d] %s\n", + program_name, filename, errno, strerror(errno)); + return 2; +@@ -464,7 +457,7 @@ + goto error; + } + +- FILE *fp = _Py_fopen_obj(startup, "r"); ++ FILE *fp = Py_fopen(startup, "r"); + if (fp == NULL) { + int save_errno = errno; + PyErr_Clear(); +@@ -496,24 +489,22 @@ + static int + pymain_run_interactive_hook(int *exitcode) + { +- PyObject *sys, *hook, *result; +- sys = PyImport_ImportModule("sys"); +- if (sys == NULL) { +- goto error; +- } +- +- hook = PyObject_GetAttrString(sys, "__interactivehook__"); +- Py_DECREF(sys); ++ PyObject *hook = PyImport_ImportModuleAttrString("sys", ++ "__interactivehook__"); + if (hook == NULL) { +- PyErr_Clear(); +- return 0; ++ if (PyErr_ExceptionMatches(PyExc_AttributeError)) { ++ // no sys.__interactivehook__ attribute ++ PyErr_Clear(); ++ return 0; ++ } ++ goto error; + } + + if (PySys_Audit("cpython.run_interactivehook", "O", hook) < 0) { + goto error; + } + +- result = _PyObject_CallNoArgs(hook); ++ PyObject *result = _PyObject_CallNoArgs(hook); + Py_DECREF(hook); + if (result == NULL) { + goto error; +diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c +index 29638114dd9..b4c15a143f9 100644 +--- a/Modules/mathmodule.c ++++ b/Modules/mathmodule.c +@@ -858,12 +858,15 @@ + * true (1), but may return false (0) without setting up an exception. + */ + static int +-is_error(double x) ++is_error(double x, int raise_edom) + { + int result = 1; /* presumption of guilt */ + assert(errno); /* non-zero errno is a precondition for calling */ +- if (errno == EDOM) +- PyErr_SetString(PyExc_ValueError, "math domain error"); ++ if (errno == EDOM) { ++ if (raise_edom) { ++ PyErr_SetString(PyExc_ValueError, "math domain error"); ++ } ++ } + + else if (errno == ERANGE) { + /* ANSI C generally requires libm functions to set ERANGE +@@ -928,7 +931,8 @@ + */ + + static PyObject * +-math_1(PyObject *arg, double (*func) (double), int can_overflow) ++math_1(PyObject *arg, double (*func) (double), int can_overflow, ++ const char *err_msg) + { + double x, r; + x = PyFloat_AsDouble(arg); +@@ -936,25 +940,34 @@ + return NULL; + errno = 0; + r = (*func)(x); +- if (isnan(r) && !isnan(x)) { +- PyErr_SetString(PyExc_ValueError, +- "math domain error"); /* invalid arg */ +- return NULL; +- } ++ if (isnan(r) && !isnan(x)) ++ goto domain_err; /* domain error */ + if (isinf(r) && isfinite(x)) { + if (can_overflow) + PyErr_SetString(PyExc_OverflowError, + "math range error"); /* overflow */ + else +- PyErr_SetString(PyExc_ValueError, +- "math domain error"); /* singularity */ ++ goto domain_err; /* singularity */ + return NULL; + } +- if (isfinite(r) && errno && is_error(r)) ++ if (isfinite(r) && errno && is_error(r, 1)) + /* this branch unnecessary on most platforms */ + return NULL; + + return PyFloat_FromDouble(r); ++ ++domain_err: ++ if (err_msg) { ++ char *buf = PyOS_double_to_string(x, 'r', 0, Py_DTSF_ADD_DOT_0, NULL); ++ if (buf) { ++ PyErr_Format(PyExc_ValueError, err_msg, buf); ++ PyMem_Free(buf); ++ } ++ } ++ else { ++ PyErr_SetString(PyExc_ValueError, "math domain error"); ++ } ++ return NULL; + } + + /* variant of math_1, to be used when the function being wrapped is known to +@@ -962,7 +975,7 @@ + errno = ERANGE for overflow). */ + + static PyObject * +-math_1a(PyObject *arg, double (*func) (double)) ++math_1a(PyObject *arg, double (*func) (double), const char *err_msg) + { + double x, r; + x = PyFloat_AsDouble(arg); +@@ -970,8 +983,17 @@ + return NULL; + errno = 0; + r = (*func)(x); +- if (errno && is_error(r)) ++ if (errno && is_error(r, err_msg ? 0 : 1)) { ++ if (err_msg && errno == EDOM) { ++ assert(!PyErr_Occurred()); /* exception is not set by is_error() */ ++ char *buf = PyOS_double_to_string(x, 'r', 0, Py_DTSF_ADD_DOT_0, NULL); ++ if (buf) { ++ PyErr_Format(PyExc_ValueError, err_msg, buf); ++ PyMem_Free(buf); ++ } ++ } + return NULL; ++ } + return PyFloat_FromDouble(r); + } + +@@ -1031,7 +1053,7 @@ + else + errno = 0; + } +- if (errno && is_error(r)) ++ if (errno && is_error(r, 1)) + return NULL; + else + return PyFloat_FromDouble(r); +@@ -1039,13 +1061,25 @@ + + #define FUNC1(funcname, func, can_overflow, docstring) \ + static PyObject * math_##funcname(PyObject *self, PyObject *args) { \ +- return math_1(args, func, can_overflow); \ ++ return math_1(args, func, can_overflow, NULL); \ ++ }\ ++ PyDoc_STRVAR(math_##funcname##_doc, docstring); ++ ++#define FUNC1D(funcname, func, can_overflow, docstring, err_msg) \ ++ static PyObject * math_##funcname(PyObject *self, PyObject *args) { \ ++ return math_1(args, func, can_overflow, err_msg); \ + }\ + PyDoc_STRVAR(math_##funcname##_doc, docstring); + + #define FUNC1A(funcname, func, docstring) \ + static PyObject * math_##funcname(PyObject *self, PyObject *args) { \ +- return math_1a(args, func); \ ++ return math_1a(args, func, NULL); \ ++ }\ ++ PyDoc_STRVAR(math_##funcname##_doc, docstring); ++ ++#define FUNC1AD(funcname, func, docstring, err_msg) \ ++ static PyObject * math_##funcname(PyObject *self, PyObject *args) { \ ++ return math_1a(args, func, err_msg); \ + }\ + PyDoc_STRVAR(math_##funcname##_doc, docstring); + +@@ -1077,9 +1111,10 @@ + "atan2($module, y, x, /)\n--\n\n" + "Return the arc tangent (measured in radians) of y/x.\n\n" + "Unlike atan(y/x), the signs of both x and y are considered.") +-FUNC1(atanh, atanh, 0, ++FUNC1D(atanh, atanh, 0, + "atanh($module, x, /)\n--\n\n" +- "Return the inverse hyperbolic tangent of x.") ++ "Return the inverse hyperbolic tangent of x.", ++ "expected a number between -1 and 1, got %s") + FUNC1(cbrt, cbrt, 0, + "cbrt($module, x, /)\n--\n\n" + "Return the cube root of x.") +@@ -1190,9 +1225,10 @@ + return PyLong_FromDouble(floor(x)); + } + +-FUNC1A(gamma, m_tgamma, ++FUNC1AD(gamma, m_tgamma, + "gamma($module, x, /)\n--\n\n" +- "Gamma function at x.") ++ "Gamma function at x.", ++ "expected a float or nonnegative integer, got %s") + FUNC1A(lgamma, m_lgamma, + "lgamma($module, x, /)\n--\n\n" + "Natural logarithm of absolute value of Gamma function at x.") +@@ -1212,9 +1248,10 @@ + FUNC1(sinh, sinh, 1, + "sinh($module, x, /)\n--\n\n" + "Return the hyperbolic sine of x.") +-FUNC1(sqrt, sqrt, 0, ++FUNC1D(sqrt, sqrt, 0, + "sqrt($module, x, /)\n--\n\n" +- "Return the square root of x.") ++ "Return the square root of x.", ++ "expected a nonnegative input, got %s") + FUNC1(tan, tan, 0, + "tan($module, x, /)\n--\n\n" + "Return the tangent of x (measured in radians).") +@@ -2141,7 +2178,7 @@ + errno = ERANGE; + } + +- if (errno && is_error(r)) ++ if (errno && is_error(r, 1)) + return NULL; + return PyFloat_FromDouble(r); + } +@@ -2195,8 +2232,8 @@ + + /* Negative or zero inputs give a ValueError. */ + if (!_PyLong_IsPositive((PyLongObject *)arg)) { +- PyErr_SetString(PyExc_ValueError, +- "math domain error"); ++ PyErr_Format(PyExc_ValueError, ++ "expected a positive input, got %S", arg); + return NULL; + } + +@@ -2220,7 +2257,7 @@ + } + + /* Else let libm handle it by itself. */ +- return math_1(arg, func, 0); ++ return math_1(arg, func, 0, "expected a positive input, got %s"); + } + + +@@ -2369,7 +2406,7 @@ + else + errno = 0; + } +- if (errno && is_error(r)) ++ if (errno && is_error(r, 1)) + return NULL; + else + return PyFloat_FromDouble(r); +@@ -3010,7 +3047,7 @@ + } + } + +- if (errno && is_error(r)) ++ if (errno && is_error(r, 1)) + return NULL; + else + return PyFloat_FromDouble(r); +diff --git a/Modules/md5module.c b/Modules/md5module.c +index ef9163e8be5..d86c8e55501 100644 +--- a/Modules/md5module.c ++++ b/Modules/md5module.c +@@ -54,6 +54,8 @@ + Hacl_Hash_MD5_state_t *hash_state; + } MD5object; + ++#define _MD5object_CAST(op) ((MD5object *)(op)) ++ + #include "clinic/md5module.c.h" + + +@@ -72,7 +74,7 @@ + static MD5object * + newMD5object(MD5State * st) + { +- MD5object *md5 = (MD5object *)PyObject_GC_New(MD5object, st->md5_type); ++ MD5object *md5 = PyObject_GC_New(MD5object, st->md5_type); + if (!md5) { + return NULL; + } +@@ -91,10 +93,11 @@ + } + + static void +-MD5_dealloc(MD5object *ptr) ++MD5_dealloc(PyObject *op) + { ++ MD5object *ptr = _MD5object_CAST(op); + Hacl_Hash_MD5_free(ptr->hash_state); +- PyTypeObject *tp = Py_TYPE((PyObject*)ptr); ++ PyTypeObject *tp = Py_TYPE(op); + PyObject_GC_UnTrack(ptr); + PyObject_GC_Del(ptr); + Py_DECREF(tp); +@@ -224,36 +227,27 @@ + }; + + static PyObject * +-MD5_get_block_size(PyObject *self, void *closure) ++MD5_get_block_size(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) + { + return PyLong_FromLong(MD5_BLOCKSIZE); + } + + static PyObject * +-MD5_get_name(PyObject *self, void *closure) ++MD5_get_name(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) + { + return PyUnicode_FromStringAndSize("md5", 3); + } + + static PyObject * +-md5_get_digest_size(PyObject *self, void *closure) ++md5_get_digest_size(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) + { + return PyLong_FromLong(MD5_DIGESTSIZE); + } + + static PyGetSetDef MD5_getseters[] = { +- {"block_size", +- (getter)MD5_get_block_size, NULL, +- NULL, +- NULL}, +- {"name", +- (getter)MD5_get_name, NULL, +- NULL, +- NULL}, +- {"digest_size", +- (getter)md5_get_digest_size, NULL, +- NULL, +- NULL}, ++ {"block_size", MD5_get_block_size, NULL, NULL, NULL}, ++ {"name", MD5_get_name, NULL, NULL, NULL}, ++ {"digest_size", md5_get_digest_size, NULL, NULL, NULL}, + {NULL} /* Sentinel */ + }; + +diff --git a/Modules/overlapped.c b/Modules/overlapped.c +index 308a0dab7fa..806ebee7a70 100644 +--- a/Modules/overlapped.c ++++ b/Modules/overlapped.c +@@ -759,7 +759,8 @@ + PyExc_RuntimeError, + "%R still has pending operation at " + "deallocation, the process may crash", self); +- PyErr_WriteUnraisable(NULL); ++ PyErr_FormatUnraisable("Exception ignored while deallocating " ++ "overlapped operation %R", self); + } + } + +diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c +index 2045c6065b8..6dfe73017ab 100644 +--- a/Modules/posixmodule.c ++++ b/Modules/posixmodule.c +@@ -7,6 +7,8 @@ + of the compiler used. Different compilers define their own feature + test macro, e.g. '_MSC_VER'. */ + ++// --- Python includes ------------------------------------------------------ ++ + #include "Python.h" + + #ifdef __VXWORKS__ +@@ -26,255 +28,63 @@ + #include "pycore_time.h" // _PyLong_FromTime_t() + #include "pycore_typeobject.h" // _PyType_AddMethod() + +-#ifdef HAVE_UNISTD_H +-# include // symlink() +-#endif +- +-#ifdef MS_WINDOWS +-# include +-# if !defined(MS_WINDOWS_GAMES) || defined(MS_WINDOWS_DESKTOP) +-# include +-# endif +-# include +-# include // UNLEN +-# include "osdefs.h" // SEP +-# include // SetEntriesInAcl +-# include // SDDL_REVISION_1 +-# if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) +-# define HAVE_SYMLINK +-# endif /* MS_WINDOWS_DESKTOP | MS_WINDOWS_SYSTEM */ +-#endif +- + #ifndef MS_WINDOWS +-# include "posixmodule.h" ++# include "posixmodule.h" // _PyLong_FromUid() + #else +-# include "pycore_fileutils_windows.h" +-# include "winreparse.h" ++# include "pycore_fileutils_windows.h" // _Py_GetFileInformationByName() ++# include "osdefs.h" // SEP ++# include "winreparse.h" // _Py_REPARSE_DATA_BUFFER + #endif + +-#if !defined(EX_OK) && defined(EXIT_SUCCESS) +-# define EX_OK EXIT_SUCCESS ++ ++// --- System includes ------------------------------------------------------ ++ ++#include // ctermid() ++#include // system() ++ ++#ifdef HAVE_UNISTD_H ++# include // symlink() + #endif + + #ifdef __APPLE__ +- /* Needed for the implementation of os.statvfs */ ++ /* Needed for the implementation of os.statvfs */ + # include + # include + #endif + +-/* On android API level 21, 'AT_EACCESS' is not declared although +- * HAVE_FACCESSAT is defined. */ +-#ifdef __ANDROID__ +-# undef HAVE_FACCESSAT +-#endif +- +-#include // ctermid() +-#include // system() + #ifdef HAVE_SYS_TIME_H + # include // futimes() + #endif ++ + #ifdef HAVE_SYS_PIDFD_H + # include // PIDFD_NONBLOCK + #endif + +- +-// SGI apparently needs this forward declaration +-#ifdef HAVE__GETPTY +-# include // mode_t +- extern char * _getpty(int *, int, mode_t, int); +-#endif +- + #ifdef __EMSCRIPTEN__ +-#include "emscripten.h" // emscripten_debugger() +-#endif +- +-/* +- * A number of APIs are available on macOS from a certain macOS version. +- * To support building with a new SDK while deploying to older versions +- * the availability test is split into two: +- * - HAVE_: The configure check for compile time availability +- * - HAVE__RUNTIME: Runtime check for availability +- * +- * The latter is always true when not on macOS, or when using a compiler +- * that does not support __has_builtin (older versions of Xcode). +- * +- * Due to compiler restrictions there is one valid use of HAVE__RUNTIME: +- * if (HAVE__RUNTIME) { ... } +- * +- * In mixing the test with other tests or using negations will result in compile +- * errors. +- */ +-#if defined(__APPLE__) +- +-#include +- +-#if defined(__has_builtin) +-#if __has_builtin(__builtin_available) +-#define HAVE_BUILTIN_AVAILABLE 1 +-#endif +-#endif +- +-#ifdef HAVE_BUILTIN_AVAILABLE +-# define HAVE_FSTATAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) +-# define HAVE_FACCESSAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) +-# define HAVE_FCHMODAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) +-# define HAVE_FCHOWNAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) +-# define HAVE_LINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) +-# define HAVE_FDOPENDIR_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) +-# define HAVE_MKDIRAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) +-# define HAVE_RENAMEAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) +-# define HAVE_UNLINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) +-# define HAVE_OPENAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) +-# define HAVE_READLINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) +-# define HAVE_SYMLINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) +-# define HAVE_FUTIMENS_RUNTIME __builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *) +-# define HAVE_UTIMENSAT_RUNTIME __builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *) +-# define HAVE_PWRITEV_RUNTIME __builtin_available(macOS 11.0, iOS 14.0, tvOS 14.0, watchOS 7.0, *) +-# define HAVE_MKFIFOAT_RUNTIME __builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) +-# define HAVE_MKNODAT_RUNTIME __builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) +-# define HAVE_PTSNAME_R_RUNTIME __builtin_available(macOS 10.13.4, iOS 11.3, tvOS 11.3, watchOS 4.3, *) +- +-# define HAVE_POSIX_SPAWN_SETSID_RUNTIME __builtin_available(macOS 10.15, *) +- +-#else /* Xcode 8 or earlier */ +- +- /* __builtin_available is not present in these compilers, but +- * some of the symbols might be weak linked (10.10 SDK or later +- * deploying on 10.9. +- * +- * Fall back to the older style of availability checking for +- * symbols introduced in macOS 10.10. +- */ +- +-# ifdef HAVE_FSTATAT +-# define HAVE_FSTATAT_RUNTIME (fstatat != NULL) +-# endif +- +-# ifdef HAVE_FACCESSAT +-# define HAVE_FACCESSAT_RUNTIME (faccessat != NULL) +-# endif +- +-# ifdef HAVE_FCHMODAT +-# define HAVE_FCHMODAT_RUNTIME (fchmodat != NULL) +-# endif +- +-# ifdef HAVE_FCHOWNAT +-# define HAVE_FCHOWNAT_RUNTIME (fchownat != NULL) +-# endif +- +-# ifdef HAVE_LINKAT +-# define HAVE_LINKAT_RUNTIME (linkat != NULL) +-# endif +- +-# ifdef HAVE_FDOPENDIR +-# define HAVE_FDOPENDIR_RUNTIME (fdopendir != NULL) +-# endif +- +-# ifdef HAVE_MKDIRAT +-# define HAVE_MKDIRAT_RUNTIME (mkdirat != NULL) +-# endif +- +-# ifdef HAVE_RENAMEAT +-# define HAVE_RENAMEAT_RUNTIME (renameat != NULL) +-# endif +- +-# ifdef HAVE_UNLINKAT +-# define HAVE_UNLINKAT_RUNTIME (unlinkat != NULL) +-# endif +- +-# ifdef HAVE_OPENAT +-# define HAVE_OPENAT_RUNTIME (openat != NULL) +-# endif +- +-# ifdef HAVE_READLINKAT +-# define HAVE_READLINKAT_RUNTIME (readlinkat != NULL) +-# endif +- +-# ifdef HAVE_SYMLINKAT +-# define HAVE_SYMLINKAT_RUNTIME (symlinkat != NULL) +-# endif +- +-# ifdef HAVE_UTIMENSAT +-# define HAVE_UTIMENSAT_RUNTIME (utimensat != NULL) +-# endif +- +-# ifdef HAVE_FUTIMENS +-# define HAVE_FUTIMENS_RUNTIME (futimens != NULL) +-# endif +- +-# ifdef HAVE_PWRITEV +-# define HAVE_PWRITEV_RUNTIME (pwritev != NULL) +-# endif +- +-# ifdef HAVE_MKFIFOAT +-# define HAVE_MKFIFOAT_RUNTIME (mkfifoat != NULL) +-# endif +- +-# ifdef HAVE_MKNODAT +-# define HAVE_MKNODAT_RUNTIME (mknodat != NULL) +-# endif +- +-# ifdef HAVE_PTSNAME_R +-# define HAVE_PTSNAME_R_RUNTIME (ptsname_r != NULL) +-# endif +- +-#endif +- +-#ifdef HAVE_FUTIMESAT +-/* Some of the logic for weak linking depends on this assertion */ +-# error "HAVE_FUTIMESAT unexpectedly defined" ++# include "emscripten.h" // emscripten_debugger() + #endif + +-#else +-# define HAVE_FSTATAT_RUNTIME 1 +-# define HAVE_FACCESSAT_RUNTIME 1 +-# define HAVE_FCHMODAT_RUNTIME 1 +-# define HAVE_FCHOWNAT_RUNTIME 1 +-# define HAVE_LINKAT_RUNTIME 1 +-# define HAVE_FDOPENDIR_RUNTIME 1 +-# define HAVE_MKDIRAT_RUNTIME 1 +-# define HAVE_RENAMEAT_RUNTIME 1 +-# define HAVE_UNLINKAT_RUNTIME 1 +-# define HAVE_OPENAT_RUNTIME 1 +-# define HAVE_READLINKAT_RUNTIME 1 +-# define HAVE_SYMLINKAT_RUNTIME 1 +-# define HAVE_FUTIMENS_RUNTIME 1 +-# define HAVE_UTIMENSAT_RUNTIME 1 +-# define HAVE_PWRITEV_RUNTIME 1 +-# define HAVE_MKFIFOAT_RUNTIME 1 +-# define HAVE_MKNODAT_RUNTIME 1 +-# define HAVE_PTSNAME_R_RUNTIME 1 +-#endif +- +- +-PyDoc_STRVAR(posix__doc__, +-"This module provides access to operating system functionality that is\n\ +-standardized by the C Standard and the POSIX standard (a thinly\n\ +-disguised Unix interface). Refer to the library manual and\n\ +-corresponding Unix manual entries for more information on calls."); +- +- + #ifdef HAVE_SYS_UIO_H + # include + #endif + + #ifdef HAVE_SYS_TYPES_H +-/* Should be included before on HP-UX v3 */ ++ /* Should be included before on HP-UX v3 */ + # include +-#endif /* HAVE_SYS_TYPES_H */ +- ++#endif + #ifdef HAVE_SYS_SYSMACROS_H +-/* GNU C Library: major(), minor(), makedev() */ ++ /* GNU C Library: major(), minor(), makedev() */ + # include + #endif + + #ifdef HAVE_SYS_STAT_H + # include +-#endif /* HAVE_SYS_STAT_H */ ++#endif + + #ifdef HAVE_SYS_WAIT_H + # include // WNOHANG + #endif ++ + #ifdef HAVE_LINUX_WAIT_H + # include // P_PIDFD + #endif +@@ -284,50 +94,34 @@ + #endif + + #ifdef HAVE_FCNTL_H +-# include ++# include // fcntl() + #endif + + #ifdef HAVE_GRP_H +-# include ++# include // setgroups() + #endif + + #ifdef HAVE_SYSEXITS_H +-# include ++# include // EX_OK + #endif + + #ifdef HAVE_SYS_LOADAVG_H +-# include ++# include // getloadavg() + #endif + + #ifdef HAVE_SYS_SENDFILE_H +-# include ++# include // sendfile() + #endif + + #if defined(__APPLE__) +-# include ++# include // fcopyfile() + #endif + + #ifdef HAVE_SCHED_H +-# include +-#endif +- +-#if !defined(CPU_ALLOC) && defined(HAVE_SCHED_SETAFFINITY) +-# undef HAVE_SCHED_SETAFFINITY +-#endif +- +-#if defined(HAVE_SYS_XATTR_H) +-# if defined(HAVE_LINUX_LIMITS_H) && !defined(__FreeBSD_kernel__) && !defined(__GNU__) +-# define USE_XATTRS +-# include // Needed for XATTR_SIZE_MAX on musl libc. +-# endif +-# if defined(__CYGWIN__) +-# define USE_XATTRS +-# include // Needed for XATTR_SIZE_MAX and XATTR_LIST_MAX. +-# endif ++# include // sched_setscheduler() + #endif +- +-#ifdef USE_XATTRS +-# include ++#ifdef HAVE_LINUX_SCHED_H ++# include // SCHED_IDLE, SCHED_RR + #endif + + #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__APPLE__) +@@ -353,23 +147,128 @@ + #endif + + #ifdef HAVE_LINUX_RANDOM_H +-# include ++# include // GRND_RANDOM + #endif + #ifdef HAVE_GETRANDOM_SYSCALL +-# include ++# include // syscall() ++#endif ++ ++#ifdef HAVE_POSIX_SPAWN ++# include // posix_spawn() ++#endif ++ ++#ifdef HAVE_UTIME_H ++# include // utime() + #endif + ++#ifdef HAVE_SYS_UTIME_H ++# include ++# define HAVE_UTIME_H /* pretend we do for the rest of this file */ ++#endif ++ ++#ifdef HAVE_SYS_TIMES_H ++# include // times() ++#endif ++ ++#ifdef HAVE_SYS_PARAM_H ++# include ++#endif ++ ++#ifdef HAVE_SYS_UTSNAME_H ++# include // uname() ++#endif ++ ++/* memfd_create is either defined in sys/mman.h or sys/memfd.h ++ * linux/memfd.h defines additional flags ++ */ ++#ifdef HAVE_SYS_MMAN_H ++# include // memfd_create() ++#endif ++#ifdef HAVE_SYS_MEMFD_H ++# include // memfd_create() ++#endif ++#ifdef HAVE_LINUX_MEMFD_H ++# include // memfd_create(), MFD_CLOEXEC ++#endif ++ ++#ifdef HAVE_SYS_EVENTFD_H ++# include // eventfd() ++#endif ++ ++#ifdef HAVE_SYS_TIMERFD_H ++# include // timerfd_create() ++#endif ++ ++#ifdef _Py_MEMORY_SANITIZER ++# include // __msan_unpoison() ++#endif ++ ++ ++// --- More complex system includes ----------------------------------------- ++ ++#ifdef MS_WINDOWS ++# include ++# if !defined(MS_WINDOWS_GAMES) || defined(MS_WINDOWS_DESKTOP) ++# include // PathCchSkipRoot() ++# endif ++# include // SetEntriesInAcl ++# include // UNLEN ++# include // SDDL_REVISION_1 ++# include // FSCTL_GET_REPARSE_POINT ++# if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) ++# define HAVE_SYMLINK ++# endif /* MS_WINDOWS_DESKTOP | MS_WINDOWS_SYSTEM */ ++#endif ++ ++ ++#ifdef _MSC_VER ++# ifdef HAVE_DIRECT_H ++# include ++# endif ++# ifdef HAVE_IO_H ++# include ++# endif ++# ifdef HAVE_PROCESS_H ++# include // getpid(), _cwait() ++# endif ++# include ++#endif /* _MSC_VER */ ++ ++ ++#ifdef HAVE__GETPTY ++# include // mode_t ++ // SGI apparently needs this forward declaration ++ extern char * _getpty(int *, int, mode_t, int); ++#endif ++ ++ ++#if defined(HAVE_SYS_XATTR_H) ++# if defined(HAVE_LINUX_LIMITS_H) && !defined(__FreeBSD_kernel__) && !defined(__GNU__) ++# define USE_XATTRS ++# include // Needed for XATTR_SIZE_MAX on musl libc. ++# endif ++# if defined(__CYGWIN__) ++# define USE_XATTRS ++# include // Needed for XATTR_SIZE_MAX and XATTR_LIST_MAX. ++# endif ++#endif ++#ifdef USE_XATTRS ++# include // fgetxattr() ++#endif ++ ++ + #ifdef HAVE_WINDOWS_CONSOLE_IO + # define TERMSIZE_USE_CONIO + #elif defined(HAVE_SYS_IOCTL_H) +-# include ++# include // ioctl(), TIOCGWINSZ + # if defined(HAVE_TERMIOS_H) + # include + # endif + # if defined(TIOCGWINSZ) + # define TERMSIZE_USE_IOCTL + # endif +-#endif /* HAVE_WINDOWS_CONSOLE_IO */ ++#endif ++ + + /* Various compilers have only certain posix functions */ + /* XXX Gosh I wish these were all moved into pyconfig.h */ +@@ -396,23 +295,15 @@ + # define HAVE_PIPE 1 + # define HAVE_FSYNC 1 + # define fsync _commit +-#endif /* ! __WATCOMC__ || __QNX__ */ +- +-/*[clinic input] +-# one of the few times we lie about this name! +-module os +-[clinic start generated code]*/ +-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=94a0f0f978acae17]*/ ++#endif + +-#ifndef _MSC_VER + +-#if defined(__sgi)&&_COMPILER_VERSION>=700 ++#if !defined(_MSC_VER) && defined(__sgi) && _COMPILER_VERSION>=700 + /* declare ctermid_r if compiling with MIPSPro 7.x in ANSI C mode + (default) */ +-extern char *ctermid_r(char *); ++extern char *ctermid_r(char *); + #endif + +-#endif /* !_MSC_VER */ + + #if defined(__VXWORKS__) + # include +@@ -426,33 +317,9 @@ + # endif + #endif /* __VXWORKS__ */ + +-#ifdef HAVE_POSIX_SPAWN +-# include +-#endif +- +-#ifdef HAVE_UTIME_H +-# include +-#endif /* HAVE_UTIME_H */ +- +-#ifdef HAVE_SYS_UTIME_H +-# include +-# define HAVE_UTIME_H /* pretend we do for the rest of this file */ +-#endif /* HAVE_SYS_UTIME_H */ +- +-#ifdef HAVE_SYS_TIMES_H +-# include +-#endif /* HAVE_SYS_TIMES_H */ +- +-#ifdef HAVE_SYS_PARAM_H +-# include +-#endif /* HAVE_SYS_PARAM_H */ +- +-#ifdef HAVE_SYS_UTSNAME_H +-# include +-#endif /* HAVE_SYS_UTSNAME_H */ + + #ifdef HAVE_DIRENT_H +-# include ++# include // opendir() + # define NAMLEN(dirent) strlen((dirent)->d_name) + #else + # if defined(__WATCOMC__) && !defined(__QNX__) +@@ -473,18 +340,20 @@ + # endif + #endif + +-#ifdef _MSC_VER +-# ifdef HAVE_DIRECT_H +-# include +-# endif +-# ifdef HAVE_IO_H +-# include ++ ++#if defined(MAJOR_IN_MKDEV) ++# include ++#else ++# if defined(MAJOR_IN_SYSMACROS) ++# include + # endif +-# ifdef HAVE_PROCESS_H +-# include ++# if defined(HAVE_MKNOD) && defined(HAVE_SYS_MKDEV_H) ++# include + # endif +-# include +-#endif /* _MSC_VER */ ++#endif ++ ++ ++// --- Macros --------------------------------------------------------------- + + #ifndef MAXPATHLEN + # if defined(PATH_MAX) && PATH_MAX > 1024 +@@ -494,6 +363,7 @@ + # endif + #endif /* MAXPATHLEN */ + ++ + #ifdef UNION_WAIT + /* Emulate some macros on systems that have a union instead of macros */ + # ifndef WIFEXITED +@@ -513,12 +383,14 @@ + # define WAIT_STATUS_INT(s) (s) + #endif /* UNION_WAIT */ + ++ + /* Don't use the "_r" form if we don't need it (also, won't have a + prototype for it, at least on Solaris -- maybe others as well?). */ + #if defined(HAVE_CTERMID_R) + # define USE_CTERMID_R + #endif + ++ + /* choose the appropriate stat and fstat functions and return structs */ + #undef STAT + #undef FSTAT +@@ -535,25 +407,19 @@ + # define STRUCT_STAT struct stat + #endif + +-#if defined(MAJOR_IN_MKDEV) +-# include +-#else +-# if defined(MAJOR_IN_SYSMACROS) +-# include +-# endif +-# if defined(HAVE_MKNOD) && defined(HAVE_SYS_MKDEV_H) +-# include +-# endif ++ ++#if !defined(EX_OK) && defined(EXIT_SUCCESS) ++# define EX_OK EXIT_SUCCESS + #endif + +-#ifdef MS_WINDOWS +-# define INITFUNC PyInit_nt +-# define MODNAME "nt" +-# define MODNAME_OBJ &_Py_ID(nt) +-#else +-# define INITFUNC PyInit_posix +-# define MODNAME "posix" +-# define MODNAME_OBJ &_Py_ID(posix) ++#if !defined(CPU_ALLOC) && defined(HAVE_SCHED_SETAFFINITY) ++# undef HAVE_SCHED_SETAFFINITY ++#endif ++ ++/* On android API level 21, 'AT_EACCESS' is not declared although ++ * HAVE_FACCESSAT is defined. */ ++#ifdef __ANDROID__ ++# undef HAVE_FACCESSAT + #endif + + #if defined(__sun) +@@ -561,33 +427,195 @@ + # define HAVE_STRUCT_STAT_ST_FSTYPE 1 + #endif + +-/* memfd_create is either defined in sys/mman.h or sys/memfd.h +- * linux/memfd.h defines additional flags ++ ++// --- Apple __builtin_available() macros ----------------------------------- ++ ++/* ++ * A number of APIs are available on macOS from a certain macOS version. ++ * To support building with a new SDK while deploying to older versions ++ * the availability test is split into two: ++ * - HAVE_: The configure check for compile time availability ++ * - HAVE__RUNTIME: Runtime check for availability ++ * ++ * The latter is always true when not on macOS, or when using a compiler ++ * that does not support __has_builtin (older versions of Xcode). ++ * ++ * Due to compiler restrictions there is one valid use of HAVE__RUNTIME: ++ * if (HAVE__RUNTIME) { ... } ++ * ++ * In mixing the test with other tests or using negations will result in compile ++ * errors. + */ +-#ifdef HAVE_SYS_MMAN_H +-# include ++#if defined(__APPLE__) ++ ++#include ++ ++#if defined(__has_builtin) ++#if __has_builtin(__builtin_available) ++#define HAVE_BUILTIN_AVAILABLE 1 + #endif +-#ifdef HAVE_SYS_MEMFD_H +-# include + #endif +-#ifdef HAVE_LINUX_MEMFD_H +-# include ++ ++#ifdef HAVE_BUILTIN_AVAILABLE ++# define HAVE_FSTATAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) ++# define HAVE_FACCESSAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) ++# define HAVE_FCHMODAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) ++# define HAVE_FCHOWNAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) ++# define HAVE_LINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) ++# define HAVE_FDOPENDIR_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) ++# define HAVE_MKDIRAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) ++# define HAVE_RENAMEAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) ++# define HAVE_UNLINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) ++# define HAVE_OPENAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) ++# define HAVE_READLINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) ++# define HAVE_SYMLINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) ++# define HAVE_FUTIMENS_RUNTIME __builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *) ++# define HAVE_UTIMENSAT_RUNTIME __builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *) ++# define HAVE_PWRITEV_RUNTIME __builtin_available(macOS 11.0, iOS 14.0, tvOS 14.0, watchOS 7.0, *) ++# define HAVE_MKFIFOAT_RUNTIME __builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) ++# define HAVE_MKNODAT_RUNTIME __builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) ++# define HAVE_PTSNAME_R_RUNTIME __builtin_available(macOS 10.13.4, iOS 11.3, tvOS 11.3, watchOS 4.3, *) ++ ++# define HAVE_POSIX_SPAWN_SETSID_RUNTIME __builtin_available(macOS 10.15, *) ++ ++#else /* Xcode 8 or earlier */ ++ ++ /* __builtin_available is not present in these compilers, but ++ * some of the symbols might be weak linked (10.10 SDK or later ++ * deploying on 10.9. ++ * ++ * Fall back to the older style of availability checking for ++ * symbols introduced in macOS 10.10. ++ */ ++ ++# ifdef HAVE_FSTATAT ++# define HAVE_FSTATAT_RUNTIME (fstatat != NULL) ++# endif ++ ++# ifdef HAVE_FACCESSAT ++# define HAVE_FACCESSAT_RUNTIME (faccessat != NULL) ++# endif ++ ++# ifdef HAVE_FCHMODAT ++# define HAVE_FCHMODAT_RUNTIME (fchmodat != NULL) ++# endif ++ ++# ifdef HAVE_FCHOWNAT ++# define HAVE_FCHOWNAT_RUNTIME (fchownat != NULL) ++# endif ++ ++# ifdef HAVE_LINKAT ++# define HAVE_LINKAT_RUNTIME (linkat != NULL) ++# endif ++ ++# ifdef HAVE_FDOPENDIR ++# define HAVE_FDOPENDIR_RUNTIME (fdopendir != NULL) ++# endif ++ ++# ifdef HAVE_MKDIRAT ++# define HAVE_MKDIRAT_RUNTIME (mkdirat != NULL) ++# endif ++ ++# ifdef HAVE_RENAMEAT ++# define HAVE_RENAMEAT_RUNTIME (renameat != NULL) ++# endif ++ ++# ifdef HAVE_UNLINKAT ++# define HAVE_UNLINKAT_RUNTIME (unlinkat != NULL) ++# endif ++ ++# ifdef HAVE_OPENAT ++# define HAVE_OPENAT_RUNTIME (openat != NULL) ++# endif ++ ++# ifdef HAVE_READLINKAT ++# define HAVE_READLINKAT_RUNTIME (readlinkat != NULL) ++# endif ++ ++# ifdef HAVE_SYMLINKAT ++# define HAVE_SYMLINKAT_RUNTIME (symlinkat != NULL) ++# endif ++ ++# ifdef HAVE_UTIMENSAT ++# define HAVE_UTIMENSAT_RUNTIME (utimensat != NULL) ++# endif ++ ++# ifdef HAVE_FUTIMENS ++# define HAVE_FUTIMENS_RUNTIME (futimens != NULL) ++# endif ++ ++# ifdef HAVE_PWRITEV ++# define HAVE_PWRITEV_RUNTIME (pwritev != NULL) ++# endif ++ ++# ifdef HAVE_MKFIFOAT ++# define HAVE_MKFIFOAT_RUNTIME (mkfifoat != NULL) ++# endif ++ ++# ifdef HAVE_MKNODAT ++# define HAVE_MKNODAT_RUNTIME (mknodat != NULL) ++# endif ++ ++# ifdef HAVE_PTSNAME_R ++# define HAVE_PTSNAME_R_RUNTIME (ptsname_r != NULL) ++# endif ++ + #endif + +-/* eventfd() */ +-#ifdef HAVE_SYS_EVENTFD_H +-# include ++#ifdef HAVE_FUTIMESAT ++/* Some of the logic for weak linking depends on this assertion */ ++# error "HAVE_FUTIMESAT unexpectedly defined" + #endif + +-/* timerfd_create() */ +-#ifdef HAVE_SYS_TIMERFD_H +-# include ++#else ++# define HAVE_FSTATAT_RUNTIME 1 ++# define HAVE_FACCESSAT_RUNTIME 1 ++# define HAVE_FCHMODAT_RUNTIME 1 ++# define HAVE_FCHOWNAT_RUNTIME 1 ++# define HAVE_LINKAT_RUNTIME 1 ++# define HAVE_FDOPENDIR_RUNTIME 1 ++# define HAVE_MKDIRAT_RUNTIME 1 ++# define HAVE_RENAMEAT_RUNTIME 1 ++# define HAVE_UNLINKAT_RUNTIME 1 ++# define HAVE_OPENAT_RUNTIME 1 ++# define HAVE_READLINKAT_RUNTIME 1 ++# define HAVE_SYMLINKAT_RUNTIME 1 ++# define HAVE_FUTIMENS_RUNTIME 1 ++# define HAVE_UTIMENSAT_RUNTIME 1 ++# define HAVE_PWRITEV_RUNTIME 1 ++# define HAVE_MKFIFOAT_RUNTIME 1 ++# define HAVE_MKNODAT_RUNTIME 1 ++# define HAVE_PTSNAME_R_RUNTIME 1 + #endif + +-#ifdef _Py_MEMORY_SANITIZER +-# include ++ ++// --- os module ------------------------------------------------------------ ++ ++#ifdef MS_WINDOWS ++# define INITFUNC PyInit_nt ++# define MODNAME "nt" ++# define MODNAME_OBJ &_Py_ID(nt) ++#else ++# define INITFUNC PyInit_posix ++# define MODNAME "posix" ++# define MODNAME_OBJ &_Py_ID(posix) + #endif + ++/*[clinic input] ++# one of the few times we lie about this name! ++module os ++[clinic start generated code]*/ ++/*[clinic end generated code: output=da39a3ee5e6b4b0d input=94a0f0f978acae17]*/ ++ ++PyDoc_STRVAR(posix__doc__, ++"This module provides access to operating system functionality that is\n\ ++standardized by the C Standard and the POSIX standard (a thinly\n\ ++disguised Unix interface). Refer to the library manual and\n\ ++corresponding Unix manual entries for more information on calls."); ++ ++ ++// --- Functions ------------------------------------------------------------ ++ + #ifdef HAVE_FORK + static void + run_at_forkers(PyObject *lst, int reverse) +@@ -602,8 +630,10 @@ + * one of the callbacks. + */ + cpy = PyList_GetSlice(lst, 0, PyList_GET_SIZE(lst)); +- if (cpy == NULL) +- PyErr_WriteUnraisable(lst); ++ if (cpy == NULL) { ++ PyErr_FormatUnraisable("Exception ignored in atfork callback " ++ "while copying list %R", lst); ++ } + else { + if (reverse) + PyList_Reverse(cpy); +@@ -611,10 +641,13 @@ + PyObject *func, *res; + func = PyList_GET_ITEM(cpy, i); + res = _PyObject_CallNoArgs(func); +- if (res == NULL) +- PyErr_WriteUnraisable(func); +- else ++ if (res == NULL) { ++ PyErr_FormatUnraisable("Exception ignored " ++ "in atfork callback %R", func); ++ } ++ else { + Py_DECREF(res); ++ } + } + Py_DECREF(cpy); + } +@@ -3343,7 +3376,7 @@ + #endif + + +-#ifdef HAVE_TTYNAME ++#ifdef HAVE_TTYNAME_R + /*[clinic input] + os.ttyname + +@@ -9578,42 +9611,33 @@ + + Py_RETURN_NONE; + #else /* !MS_WINDOWS */ +- PyObject *result; + DWORD sig = (DWORD)signal; +- DWORD err; +- HANDLE handle; + + #ifdef HAVE_WINDOWS_CONSOLE_IO + /* Console processes which share a common console can be sent CTRL+C or + CTRL+BREAK events, provided they handle said events. */ + if (sig == CTRL_C_EVENT || sig == CTRL_BREAK_EVENT) { + if (GenerateConsoleCtrlEvent(sig, (DWORD)pid) == 0) { +- err = GetLastError(); +- PyErr_SetFromWindowsErr(err); +- } +- else { +- Py_RETURN_NONE; ++ return PyErr_SetFromWindowsErr(0); + } ++ Py_RETURN_NONE; + } + #endif /* HAVE_WINDOWS_CONSOLE_IO */ + + /* If the signal is outside of what GenerateConsoleCtrlEvent can use, + attempt to open and terminate the process. */ +- handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)pid); ++ HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)pid); + if (handle == NULL) { +- err = GetLastError(); +- return PyErr_SetFromWindowsErr(err); ++ return PyErr_SetFromWindowsErr(0); + } + +- if (TerminateProcess(handle, sig) == 0) { +- err = GetLastError(); +- result = PyErr_SetFromWindowsErr(err); +- } else { +- result = Py_NewRef(Py_None); ++ BOOL res = TerminateProcess(handle, sig); ++ CloseHandle(handle); ++ if (res == 0) { ++ return PyErr_SetFromWindowsErr(0); + } + +- CloseHandle(handle); +- return result; ++ Py_RETURN_NONE; + #endif /* !MS_WINDOWS */ + } + #endif /* HAVE_KILL */ +@@ -9882,7 +9906,7 @@ + memset(ru, 0, sizeof(*ru)); + } + +- struct_rusage = _PyImport_GetModuleAttrString("resource", "struct_rusage"); ++ struct_rusage = PyImport_ImportModuleAttrString("resource", "struct_rusage"); + if (struct_rusage == NULL) + return NULL; + +@@ -11438,6 +11462,38 @@ + return buffer; + } + ++/*[clinic input] ++os.readinto -> Py_ssize_t ++ fd: int ++ buffer: Py_buffer(accept={rwbuffer}) ++ / ++ ++Read into a buffer object from a file descriptor. ++ ++The buffer should be mutable and bytes-like. On success, returns the number of ++bytes read. Less bytes may be read than the size of the buffer. The underlying ++system call will be retried when interrupted by a signal, unless the signal ++handler raises an exception. Other errors will not be retried and an error will ++be raised. ++ ++Returns 0 if *fd* is at end of file or if the provided *buffer* has length 0 ++(which can be used to check for errors without reading data). Never returns ++negative. ++[clinic start generated code]*/ ++ ++static Py_ssize_t ++os_readinto_impl(PyObject *module, int fd, Py_buffer *buffer) ++/*[clinic end generated code: output=8091a3513c683a80 input=d40074d0a68de575]*/ ++{ ++ assert(buffer->len >= 0); ++ Py_ssize_t result = _Py_read(fd, buffer->buf, buffer->len); ++ /* Ensure negative is never returned without an error. Simplifies calling ++ code. _Py_read should succeed, possibly reading 0 bytes, _or_ set an ++ error. */ ++ assert(result >= 0 || (result == -1 && PyErr_Occurred())); ++ return result; ++} ++ + #if (defined(HAVE_SENDFILE) && (defined(__FreeBSD__) || defined(__DragonFly__) \ + || defined(__APPLE__))) \ + || defined(HAVE_READV) || defined(HAVE_PREADV) || defined (HAVE_PREADV2) \ +@@ -16303,7 +16359,8 @@ + "unclosed scandir iterator %R", iterator)) { + /* Spurious errors can appear at shutdown */ + if (PyErr_ExceptionMatches(PyExc_Warning)) { +- PyErr_WriteUnraisable((PyObject *) iterator); ++ PyErr_FormatUnraisable("Exception ignored while finalizing " ++ "scandir iterator %R", iterator); + } + } + } +@@ -16978,6 +17035,7 @@ + OS_LOCKF_METHODDEF + OS_LSEEK_METHODDEF + OS_READ_METHODDEF ++ OS_READINTO_METHODDEF + OS_READV_METHODDEF + OS_PREAD_METHODDEF + OS_PREADV_METHODDEF +@@ -17523,9 +17581,15 @@ + #ifdef SCHED_OTHER + if (PyModule_AddIntMacro(m, SCHED_OTHER)) return -1; + #endif ++#ifdef SCHED_DEADLINE ++ if (PyModule_AddIntMacro(m, SCHED_DEADLINE)) return -1; ++#endif + #ifdef SCHED_FIFO + if (PyModule_AddIntMacro(m, SCHED_FIFO)) return -1; + #endif ++#ifdef SCHED_NORMAL ++ if (PyModule_AddIntMacro(m, SCHED_NORMAL)) return -1; ++#endif + #ifdef SCHED_RR + if (PyModule_AddIntMacro(m, SCHED_RR)) return -1; + #endif +diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c +index 9733bc34f7c..3290706f143 100644 +--- a/Modules/pyexpat.c ++++ b/Modules/pyexpat.c +@@ -1767,7 +1767,10 @@ + {"XML_ERROR_NO_BUFFER", "a successful prior call to function XML_GetBuffer is required"}, + + /* Added in 2.4.0. */ +- {"XML_ERROR_AMPLIFICATION_LIMIT_BREACH", "limit on input amplification factor (from DTD and entities) breached"} ++ {"XML_ERROR_AMPLIFICATION_LIMIT_BREACH", "limit on input amplification factor (from DTD and entities) breached"}, ++ ++ /* Added in 2.6.4. */ ++ {"XML_ERROR_NOT_STARTED", "parser not started"}, + }; + + static int +@@ -1782,7 +1785,12 @@ + * with the other uses of the XML_ErrorString function + * elsewhere within this file. pyexpat's copy of the messages + * only acts as a fallback in case of outdated runtime libexpat, +- * where it returns NULL. */ ++ * where it returns NULL. ++ * ++ * In addition, XML_ErrorString is assumed to return UTF-8 encoded ++ * strings (in conv_string_to_unicode, we decode them using 'strict' ++ * error handling). ++ */ + const char *error_string = XML_ErrorString(error_code); + if (error_string == NULL) { + error_string = error_info_of[error_index].description; +@@ -1940,7 +1948,8 @@ + { + void *p = PyCapsule_GetPointer(capsule, PyExpat_CAPSULE_NAME); + if (p == NULL) { +- PyErr_WriteUnraisable(capsule); ++ PyErr_FormatUnraisable("Exception ignored while destroying " ++ "pyexact capsule"); + return; + } + PyMem_Free(p); +diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c +index e14e114a6da..c75e2ba28c5 100644 +--- a/Modules/selectmodule.c ++++ b/Modules/selectmodule.c +@@ -14,7 +14,6 @@ + + #include "Python.h" + #include "pycore_fileutils.h" // _Py_set_inheritable() +-#include "pycore_import.h" // _PyImport_GetModuleAttrString() + #include "pycore_time.h" // _PyTime_FromSecondsObject() + + #include +@@ -1996,7 +1995,7 @@ + // Register a callback to invalidate kqueues with open fds after fork. + PyObject *register_at_fork = NULL, *cb = NULL, *args = NULL, + *kwargs = NULL, *result = NULL; +- register_at_fork = _PyImport_GetModuleAttrString("posix", ++ register_at_fork = PyImport_ImportModuleAttrString("posix", + "register_at_fork"); + if (register_at_fork == NULL) { + goto finally; +diff --git a/Modules/sha1module.c b/Modules/sha1module.c +index 34a427a39b5..d0b1e825077 100644 +--- a/Modules/sha1module.c ++++ b/Modules/sha1module.c +@@ -55,6 +55,8 @@ + Hacl_Hash_SHA1_state_t *hash_state; + } SHA1object; + ++#define _SHA1object_CAST(op) ((SHA1object *)(op)) ++ + #include "clinic/sha1module.c.h" + + +@@ -73,7 +75,7 @@ + static SHA1object * + newSHA1object(SHA1State *st) + { +- SHA1object *sha = (SHA1object *)PyObject_GC_New(SHA1object, st->sha1_type); ++ SHA1object *sha = PyObject_GC_New(SHA1object, st->sha1_type); + if (sha == NULL) { + return NULL; + } +@@ -93,8 +95,9 @@ + } + + static void +-SHA1_dealloc(SHA1object *ptr) ++SHA1_dealloc(PyObject *op) + { ++ SHA1object *ptr = _SHA1object_CAST(op); + Hacl_Hash_SHA1_free(ptr->hash_state); + PyTypeObject *tp = Py_TYPE(ptr); + PyObject_GC_UnTrack(ptr); +@@ -217,36 +220,27 @@ + }; + + static PyObject * +-SHA1_get_block_size(PyObject *self, void *closure) ++SHA1_get_block_size(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) + { + return PyLong_FromLong(SHA1_BLOCKSIZE); + } + + static PyObject * +-SHA1_get_name(PyObject *self, void *closure) ++SHA1_get_name(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) + { + return PyUnicode_FromStringAndSize("sha1", 4); + } + + static PyObject * +-sha1_get_digest_size(PyObject *self, void *closure) ++sha1_get_digest_size(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) + { + return PyLong_FromLong(SHA1_DIGESTSIZE); + } + + static PyGetSetDef SHA1_getseters[] = { +- {"block_size", +- (getter)SHA1_get_block_size, NULL, +- NULL, +- NULL}, +- {"name", +- (getter)SHA1_get_name, NULL, +- NULL, +- NULL}, +- {"digest_size", +- (getter)sha1_get_digest_size, NULL, +- NULL, +- NULL}, ++ {"block_size", SHA1_get_block_size, NULL, NULL, NULL}, ++ {"name", SHA1_get_name, NULL, NULL, NULL}, ++ {"digest_size", sha1_get_digest_size, NULL, NULL, NULL}, + {NULL} /* Sentinel */ + }; + +@@ -346,7 +340,7 @@ + static void + _sha1_free(void *module) + { +- _sha1_clear((PyObject *)module); ++ (void)_sha1_clear((PyObject *)module); + } + + static int +diff --git a/Modules/sha2module.c b/Modules/sha2module.c +index 7d6a1e40243..45fa120cf76 100644 +--- a/Modules/sha2module.c ++++ b/Modules/sha2module.c +@@ -67,6 +67,9 @@ + Hacl_Hash_SHA2_state_t_512 *state; + } SHA512object; + ++#define _SHA256object_CAST(op) ((SHA256object *)(op)) ++#define _SHA512object_CAST(op) ((SHA512object *)(op)) ++ + #include "clinic/sha2module.c.h" + + /* We shall use run-time type information in the remainder of this module to +@@ -101,8 +104,7 @@ + static SHA256object * + newSHA224object(sha2_state *state) + { +- SHA256object *sha = (SHA256object *)PyObject_GC_New( +- SHA256object, state->sha224_type); ++ SHA256object *sha = PyObject_GC_New(SHA256object, state->sha224_type); + if (!sha) { + return NULL; + } +@@ -115,8 +117,7 @@ + static SHA256object * + newSHA256object(sha2_state *state) + { +- SHA256object *sha = (SHA256object *)PyObject_GC_New( +- SHA256object, state->sha256_type); ++ SHA256object *sha = PyObject_GC_New(SHA256object, state->sha256_type); + if (!sha) { + return NULL; + } +@@ -129,8 +130,7 @@ + static SHA512object * + newSHA384object(sha2_state *state) + { +- SHA512object *sha = (SHA512object *)PyObject_GC_New( +- SHA512object, state->sha384_type); ++ SHA512object *sha = PyObject_GC_New(SHA512object, state->sha384_type); + if (!sha) { + return NULL; + } +@@ -143,8 +143,7 @@ + static SHA512object * + newSHA512object(sha2_state *state) + { +- SHA512object *sha = (SHA512object *)PyObject_GC_New( +- SHA512object, state->sha512_type); ++ SHA512object *sha = PyObject_GC_New(SHA512object, state->sha512_type); + if (!sha) { + return NULL; + } +@@ -164,8 +163,9 @@ + } + + static void +-SHA256_dealloc(SHA256object *ptr) ++SHA256_dealloc(PyObject *op) + { ++ SHA256object *ptr = _SHA256object_CAST(op); + Hacl_Hash_SHA2_free_256(ptr->state); + PyTypeObject *tp = Py_TYPE(ptr); + PyObject_GC_UnTrack(ptr); +@@ -174,8 +174,9 @@ + } + + static void +-SHA512_dealloc(SHA512object *ptr) ++SHA512_dealloc(PyObject *op) + { ++ SHA512object *ptr = _SHA512object_CAST(op); + Hacl_Hash_SHA2_free_512(ptr->state); + PyTypeObject *tp = Py_TYPE(ptr); + PyObject_GC_UnTrack(ptr); +@@ -442,32 +443,35 @@ + }; + + static PyObject * +-SHA256_get_block_size(PyObject *self, void *closure) ++SHA256_get_block_size(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) + { + return PyLong_FromLong(SHA256_BLOCKSIZE); + } + + static PyObject * +-SHA512_get_block_size(PyObject *self, void *closure) ++SHA512_get_block_size(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) + { + return PyLong_FromLong(SHA512_BLOCKSIZE); + } + + static PyObject * +-SHA256_get_digest_size(SHA256object *self, void *closure) ++SHA256_get_digest_size(PyObject *op, void *Py_UNUSED(closure)) + { ++ SHA256object *self = _SHA256object_CAST(op); + return PyLong_FromLong(self->digestsize); + } + + static PyObject * +-SHA512_get_digest_size(SHA512object *self, void *closure) ++SHA512_get_digest_size(PyObject *op, void *Py_UNUSED(closure)) + { ++ SHA512object *self = _SHA512object_CAST(op); + return PyLong_FromLong(self->digestsize); + } + + static PyObject * +-SHA256_get_name(SHA256object *self, void *closure) ++SHA256_get_name(PyObject *op, void *Py_UNUSED(closure)) + { ++ SHA256object *self = _SHA256object_CAST(op); + if (self->digestsize == 28) { + return PyUnicode_FromStringAndSize("sha224", 6); + } +@@ -475,8 +479,9 @@ + } + + static PyObject * +-SHA512_get_name(SHA512object *self, void *closure) ++SHA512_get_name(PyObject *op, void *Py_UNUSED(closure)) + { ++ SHA512object *self = _SHA512object_CAST(op); + if (self->digestsize == 64) { + return PyUnicode_FromStringAndSize("sha512", 6); + } +@@ -484,34 +489,16 @@ + } + + static PyGetSetDef SHA256_getseters[] = { +- {"block_size", +- (getter)SHA256_get_block_size, NULL, +- NULL, +- NULL}, +- {"name", +- (getter)SHA256_get_name, NULL, +- NULL, +- NULL}, +- {"digest_size", +- (getter)SHA256_get_digest_size, NULL, +- NULL, +- NULL}, ++ {"block_size", SHA256_get_block_size, NULL, NULL, NULL}, ++ {"name", SHA256_get_name, NULL, NULL, NULL}, ++ {"digest_size", SHA256_get_digest_size, NULL, NULL, NULL}, + {NULL} /* Sentinel */ + }; + + static PyGetSetDef SHA512_getseters[] = { +- {"block_size", +- (getter)SHA512_get_block_size, NULL, +- NULL, +- NULL}, +- {"name", +- (getter)SHA512_get_name, NULL, +- NULL, +- NULL}, +- {"digest_size", +- (getter)SHA512_get_digest_size, NULL, +- NULL, +- NULL}, ++ {"block_size", SHA512_get_block_size, NULL, NULL, NULL}, ++ {"name", SHA512_get_name, NULL, NULL, NULL}, ++ {"digest_size", SHA512_get_digest_size, NULL, NULL, NULL}, + {NULL} /* Sentinel */ + }; + +@@ -818,7 +805,7 @@ + static void + _sha2_free(void *module) + { +- _sha2_clear((PyObject *)module); ++ (void)_sha2_clear((PyObject *)module); + } + + /* Initialize this module. */ +diff --git a/Modules/sha3module.c b/Modules/sha3module.c +index b13e6a9de10..72a11602b0e 100644 +--- a/Modules/sha3module.c ++++ b/Modules/sha3module.c +@@ -66,6 +66,8 @@ + Hacl_Hash_SHA3_state_t *hash_state; + } SHA3object; + ++#define _SHA3object_CAST(op) ((SHA3object *)(op)) ++ + #include "clinic/sha3module.c.h" + + static SHA3object * +@@ -167,8 +169,9 @@ + /* Internal methods for a hash object */ + + static int +-SHA3_clear(SHA3object *self) ++SHA3_clear(PyObject *op) + { ++ SHA3object *self = _SHA3object_CAST(op); + if (self->hash_state != NULL) { + Hacl_Hash_SHA3_free(self->hash_state); + self->hash_state = NULL; +@@ -177,7 +180,7 @@ + } + + static void +-SHA3_dealloc(SHA3object *self) ++SHA3_dealloc(PyObject *self) + { + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); +@@ -303,15 +306,16 @@ + + + static PyObject * +-SHA3_get_block_size(SHA3object *self, void *closure) ++SHA3_get_block_size(PyObject *op, void *Py_UNUSED(closure)) + { ++ SHA3object *self = _SHA3object_CAST(op); + uint32_t rate = Hacl_Hash_SHA3_block_len(self->hash_state); + return PyLong_FromLong(rate); + } + + + static PyObject * +-SHA3_get_name(SHA3object *self, void *closure) ++SHA3_get_name(PyObject *self, void *Py_UNUSED(closure)) + { + PyTypeObject *type = Py_TYPE(self); + +@@ -338,9 +342,10 @@ + + + static PyObject * +-SHA3_get_digest_size(SHA3object *self, void *closure) ++SHA3_get_digest_size(PyObject *op, void *Py_UNUSED(closure)) + { + // Preserving previous behavior: variable-length algorithms return 0 ++ SHA3object *self = _SHA3object_CAST(op); + if (Hacl_Hash_SHA3_is_shake(self->hash_state)) + return PyLong_FromLong(0); + else +@@ -349,8 +354,9 @@ + + + static PyObject * +-SHA3_get_capacity_bits(SHA3object *self, void *closure) ++SHA3_get_capacity_bits(PyObject *op, void *Py_UNUSED(closure)) + { ++ SHA3object *self = _SHA3object_CAST(op); + uint32_t rate = Hacl_Hash_SHA3_block_len(self->hash_state) * 8; + assert(rate <= 1600); + int capacity = 1600 - rate; +@@ -359,26 +365,27 @@ + + + static PyObject * +-SHA3_get_rate_bits(SHA3object *self, void *closure) ++SHA3_get_rate_bits(PyObject *op, void *Py_UNUSED(closure)) + { ++ SHA3object *self = _SHA3object_CAST(op); + uint32_t rate = Hacl_Hash_SHA3_block_len(self->hash_state) * 8; + return PyLong_FromLong(rate); + } + + static PyObject * +-SHA3_get_suffix(SHA3object *self, void *closure) ++SHA3_get_suffix(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) + { + unsigned char suffix[2] = {0x06, 0}; + return PyBytes_FromStringAndSize((const char *)suffix, 1); + } + + static PyGetSetDef SHA3_getseters[] = { +- {"block_size", (getter)SHA3_get_block_size, NULL, NULL, NULL}, +- {"name", (getter)SHA3_get_name, NULL, NULL, NULL}, +- {"digest_size", (getter)SHA3_get_digest_size, NULL, NULL, NULL}, +- {"_capacity_bits", (getter)SHA3_get_capacity_bits, NULL, NULL, NULL}, +- {"_rate_bits", (getter)SHA3_get_rate_bits, NULL, NULL, NULL}, +- {"_suffix", (getter)SHA3_get_suffix, NULL, NULL, NULL}, ++ {"block_size", SHA3_get_block_size, NULL, NULL, NULL}, ++ {"name", SHA3_get_name, NULL, NULL, NULL}, ++ {"digest_size", SHA3_get_digest_size, NULL, NULL, NULL}, ++ {"_capacity_bits", SHA3_get_capacity_bits, NULL, NULL, NULL}, ++ {"_rate_bits", SHA3_get_rate_bits, NULL, NULL, NULL}, ++ {"_suffix", SHA3_get_suffix, NULL, NULL, NULL}, + {NULL} /* Sentinel */ + }; + +@@ -438,10 +445,11 @@ + SHA3_TYPE_SPEC(sha3_512_spec, "sha3_512", sha3_512_slots); + + static PyObject * +-_SHAKE_digest(SHA3object *self, unsigned long digestlen, int hex) ++_SHAKE_digest(PyObject *op, unsigned long digestlen, int hex) + { + unsigned char *digest = NULL; + PyObject *result = NULL; ++ SHA3object *self = _SHA3object_CAST(op); + + if (digestlen >= (1 << 29)) { + PyErr_SetString(PyExc_ValueError, "length is too large"); +@@ -483,7 +491,7 @@ + _sha3_shake_128_digest_impl(SHA3object *self, unsigned long length) + /*[clinic end generated code: output=2313605e2f87bb8f input=418ef6a36d2e6082]*/ + { +- return _SHAKE_digest(self, length, 0); ++ return _SHAKE_digest((PyObject *)self, length, 0); + } + + +@@ -500,17 +508,17 @@ + _sha3_shake_128_hexdigest_impl(SHA3object *self, unsigned long length) + /*[clinic end generated code: output=bf8e2f1e490944a8 input=69fb29b0926ae321]*/ + { +- return _SHAKE_digest(self, length, 1); ++ return _SHAKE_digest((PyObject *)self, length, 1); + } + + static PyObject * +-SHAKE_get_digest_size(SHA3object *self, void *closure) ++SHAKE_get_digest_size(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) + { + return PyLong_FromLong(0); + } + + static PyObject * +-SHAKE_get_suffix(SHA3object *self, void *closure) ++SHAKE_get_suffix(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) + { + unsigned char suffix[2] = {0x1f, 0}; + return PyBytes_FromStringAndSize((const char *)suffix, 1); +@@ -518,12 +526,12 @@ + + + static PyGetSetDef SHAKE_getseters[] = { +- {"block_size", (getter)SHA3_get_block_size, NULL, NULL, NULL}, +- {"name", (getter)SHA3_get_name, NULL, NULL, NULL}, +- {"digest_size", (getter)SHAKE_get_digest_size, NULL, NULL, NULL}, +- {"_capacity_bits", (getter)SHA3_get_capacity_bits, NULL, NULL, NULL}, +- {"_rate_bits", (getter)SHA3_get_rate_bits, NULL, NULL, NULL}, +- {"_suffix", (getter)SHAKE_get_suffix, NULL, NULL, NULL}, ++ {"block_size", SHA3_get_block_size, NULL, NULL, NULL}, ++ {"name", SHA3_get_name, NULL, NULL, NULL}, ++ {"digest_size", SHAKE_get_digest_size, NULL, NULL, NULL}, ++ {"_capacity_bits", SHA3_get_capacity_bits, NULL, NULL, NULL}, ++ {"_rate_bits", SHA3_get_rate_bits, NULL, NULL, NULL}, ++ {"_suffix", SHAKE_get_suffix, NULL, NULL, NULL}, + {NULL} /* Sentinel */ + }; + +diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c +index 0e53a36bca5..b679b83bed5 100644 +--- a/Modules/signalmodule.c ++++ b/Modules/signalmodule.c +@@ -245,7 +245,8 @@ + errno = (int) (intptr_t) data; + PyObject *exc = PyErr_GetRaisedException(); + PyErr_SetFromErrno(PyExc_OSError); +- PyErr_FormatUnraisable("Exception ignored when trying to write to the signal wakeup fd"); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "trying to write to the signal wakeup fd"); + PyErr_SetRaisedException(exc); + errno = save_errno; + return 0; +@@ -262,7 +263,8 @@ + recognizes the error codes used by both GetLastError() and + WSAGetLastError */ + PyErr_SetExcFromWindowsErr(PyExc_OSError, send_errno); +- PyErr_FormatUnraisable("Exception ignored when trying to send to the signal wakeup fd"); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "trying to send to the signal wakeup fd"); + PyErr_SetRaisedException(exc); + return 0; + } +@@ -1837,7 +1839,8 @@ + PyErr_Format(PyExc_OSError, + "Signal %i ignored due to race condition", + i); +- PyErr_WriteUnraisable(Py_None); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "calling signal handler"); + continue; + } + PyObject *arglist = NULL; +diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c +index 9394f1c940b..4b6d2dd1c5f 100644 +--- a/Modules/socketmodule.c ++++ b/Modules/socketmodule.c +@@ -110,6 +110,8 @@ + #include "pycore_fileutils.h" // _Py_set_inheritable() + #include "pycore_moduleobject.h" // _PyModule_GetState + #include "pycore_time.h" // _PyTime_AsMilliseconds() ++#include "pycore_pystate.h" // _Py_AssertHoldsTstate() ++#include "pycore_pyatomic_ft_wrappers.h" + + #ifdef _Py_MEMORY_SANITIZER + # include +@@ -549,20 +551,58 @@ + + /* Default timeout for new sockets */ + PyTime_t defaulttimeout; ++} socket_state; + + #if defined(HAVE_ACCEPT) || defined(HAVE_ACCEPT4) + #if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) +- /* accept4() is available on Linux 2.6.28+ and glibc 2.10 */ +- int accept4_works; ++/* accept4() is available on Linux 2.6.28+ and glibc 2.10 */ ++static int accept4_works = -1; + #endif + #endif + + #ifdef SOCK_CLOEXEC +- /* socket() and socketpair() fail with EINVAL on Linux kernel older +- * than 2.6.27 if SOCK_CLOEXEC flag is set in the socket type. */ +- int sock_cloexec_works; ++/* socket() and socketpair() fail with EINVAL on Linux kernel older ++ * than 2.6.27 if SOCK_CLOEXEC flag is set in the socket type. */ ++static int sock_cloexec_works = -1; + #endif +-} socket_state; ++ ++static inline void ++set_sock_fd(PySocketSockObject *s, SOCKET_T fd) ++{ ++#ifdef Py_GIL_DISABLED ++#if SIZEOF_SOCKET_T == SIZEOF_INT ++ _Py_atomic_store_int_relaxed((int *)&s->sock_fd, (int)fd); ++#elif SIZEOF_SOCKET_T == SIZEOF_LONG ++ _Py_atomic_store_long_relaxed((long *)&s->sock_fd, (long)fd); ++#elif SIZEOF_SOCKET_T == SIZEOF_LONG_LONG ++ _Py_atomic_store_llong_relaxed((long long *)&s->sock_fd, (long long)fd); ++#else ++ #error "Unsupported SIZEOF_SOCKET_T" ++#endif ++#else ++ s->sock_fd = fd; ++#endif ++} ++ ++static inline SOCKET_T ++get_sock_fd(PySocketSockObject *s) ++{ ++#ifdef Py_GIL_DISABLED ++#if SIZEOF_SOCKET_T == SIZEOF_INT ++ return (SOCKET_T)_Py_atomic_load_int_relaxed((int *)&s->sock_fd); ++#elif SIZEOF_SOCKET_T == SIZEOF_LONG ++ return (SOCKET_T)_Py_atomic_load_long_relaxed((long *)&s->sock_fd); ++#elif SIZEOF_SOCKET_T == SIZEOF_LONG_LONG ++ return (SOCKET_T)_Py_atomic_load_llong_relaxed((long long *)&s->sock_fd); ++#else ++ #error "Unsupported SIZEOF_SOCKET_T" ++#endif ++#else ++ return s->sock_fd; ++#endif ++} ++ ++#define _PySocketSockObject_CAST(op) ((PySocketSockObject *)(op)) + + static inline socket_state * + get_module_state(PyObject *mod) +@@ -736,10 +776,10 @@ + #ifndef MS_WINDOWS + #if (defined(HAVE_SYS_IOCTL_H) && defined(FIONBIO)) + block = !block; +- if (ioctl(s->sock_fd, FIONBIO, (unsigned int *)&block) == -1) ++ if (ioctl(get_sock_fd(s), FIONBIO, (unsigned int *)&block) == -1) + goto done; + #else +- delay_flag = fcntl(s->sock_fd, F_GETFL, 0); ++ delay_flag = fcntl(get_sock_fd(s), F_GETFL, 0); + if (delay_flag == -1) + goto done; + if (block) +@@ -747,12 +787,12 @@ + else + new_delay_flag = delay_flag | O_NONBLOCK; + if (new_delay_flag != delay_flag) +- if (fcntl(s->sock_fd, F_SETFL, new_delay_flag) == -1) ++ if (fcntl(get_sock_fd(s), F_SETFL, new_delay_flag) == -1) + goto done; + #endif + #else /* MS_WINDOWS */ + arg = !block; +- if (ioctlsocket(s->sock_fd, FIONBIO, &arg) != 0) ++ if (ioctlsocket(get_sock_fd(s), FIONBIO, &arg) != 0) + goto done; + #endif /* MS_WINDOWS */ + +@@ -785,20 +825,20 @@ + struct timeval tv, *tvp; + #endif + +- /* must be called with the GIL held */ +- assert(PyGILState_Check()); ++ /* must be called with a thread state */ ++ _Py_AssertHoldsTstate(); + + /* Error condition is for output only */ + assert(!(connect && !writing)); + + /* Guard against closed socket */ +- if (s->sock_fd == INVALID_SOCKET) ++ if (get_sock_fd(s) == INVALID_SOCKET) + return 0; + + /* Prefer poll, if available, since you can poll() any fd + * which can't be done with select(). */ + #ifdef HAVE_POLL +- pollfd.fd = s->sock_fd; ++ pollfd.fd = get_sock_fd(s); + pollfd.events = writing ? POLLOUT : POLLIN; + if (connect) { + /* On Windows, the socket becomes writable on connection success, +@@ -838,23 +878,23 @@ + tvp = NULL; + + FD_ZERO(&fds); +- FD_SET(s->sock_fd, &fds); ++ FD_SET(get_sock_fd(s), &fds); + FD_ZERO(&efds); + if (connect) { + /* On Windows, the socket becomes writable on connection success, + but a connection failure is notified as an error. On POSIX, the + socket becomes writable on connection success or on connection + failure. */ +- FD_SET(s->sock_fd, &efds); ++ FD_SET(get_sock_fd(s), &efds); + } + + /* See if the socket is ready */ + Py_BEGIN_ALLOW_THREADS; + if (writing) +- n = select(Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int), ++ n = select(Py_SAFE_DOWNCAST(get_sock_fd(s)+1, SOCKET_T, int), + NULL, &fds, &efds, tvp); + else +- n = select(Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int), ++ n = select(Py_SAFE_DOWNCAST(get_sock_fd(s)+1, SOCKET_T, int), + &fds, NULL, &efds, tvp); + Py_END_ALLOW_THREADS; + #endif +@@ -899,8 +939,8 @@ + int deadline_initialized = 0; + int res; + +- /* sock_call() must be called with the GIL held. */ +- assert(PyGILState_Check()); ++ /* sock_call() must be called with a thread state. */ ++ _Py_AssertHoldsTstate(); + + /* outer loop to retry select() when select() is interrupted by a signal + or to retry select()+sock_func() on false positive (see above) */ +@@ -1030,7 +1070,7 @@ + init_sockobject(socket_state *state, PySocketSockObject *s, + SOCKET_T fd, int family, int type, int proto) + { +- s->sock_fd = fd; ++ set_sock_fd(s, fd); + s->sock_family = family; + + s->sock_type = type; +@@ -2127,7 +2167,7 @@ + } + strncpy(ifr.ifr_name, interfaceName, sizeof(ifr.ifr_name)); + ifr.ifr_name[(sizeof(ifr.ifr_name))-1] = '\0'; +- if (ioctl(s->sock_fd, SIOCGIFINDEX, &ifr) < 0) { ++ if (ioctl(get_sock_fd(s), SIOCGIFINDEX, &ifr) < 0) { + s->errorhandler(); + PyBuffer_Release(&haddr); + return 0; +@@ -2252,7 +2292,7 @@ + } else if ((size_t)len < sizeof(ifr.ifr_name)) { + strncpy(ifr.ifr_name, PyBytes_AS_STRING(interfaceName), sizeof(ifr.ifr_name)); + ifr.ifr_name[(sizeof(ifr.ifr_name))-1] = '\0'; +- if (ioctl(s->sock_fd, SIOCGIFINDEX, &ifr) < 0) { ++ if (ioctl(get_sock_fd(s), SIOCGIFINDEX, &ifr) < 0) { + s->errorhandler(); + Py_DECREF(interfaceName); + return 0; +@@ -2296,7 +2336,7 @@ + } else if ((size_t)len < sizeof(ifr.ifr_name)) { + strncpy(ifr.ifr_name, PyBytes_AS_STRING(interfaceName), sizeof(ifr.ifr_name)); + ifr.ifr_name[(sizeof(ifr.ifr_name))-1] = '\0'; +- if (ioctl(s->sock_fd, SIOCGIFINDEX, &ifr) < 0) { ++ if (ioctl(get_sock_fd(s), SIOCGIFINDEX, &ifr) < 0) { + s->errorhandler(); + Py_DECREF(interfaceName); + return 0; +@@ -2344,7 +2384,7 @@ + } else if ((size_t)len < sizeof(ifr.ifr_name)) { + strncpy(ifr.ifr_name, PyBytes_AS_STRING(interfaceName), sizeof(ifr.ifr_name)); + ifr.ifr_name[(sizeof(ifr.ifr_name))-1] = '\0'; +- if (ioctl(s->sock_fd, SIOCGIFINDEX, &ifr) < 0) { ++ if (ioctl(get_sock_fd(s), SIOCGIFINDEX, &ifr) < 0) { + s->errorhandler(); + Py_DECREF(interfaceName); + return 0; +@@ -2403,7 +2443,7 @@ + sizeof(info.ctl_name)); + Py_DECREF(ctl_name); + +- if (ioctl(s->sock_fd, CTLIOCGINFO, &info)) { ++ if (ioctl(get_sock_fd(s), CTLIOCGINFO, &info)) { + PyErr_SetString(PyExc_OSError, + "cannot find kernel control with provided name"); + return 0; +@@ -2867,19 +2907,18 @@ + #endif + + #if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) +- socket_state *state = s->state; +- if (state->accept4_works != 0) { +- ctx->result = accept4(s->sock_fd, addr, paddrlen, ++ if (_Py_atomic_load_int_relaxed(&accept4_works) != 0) { ++ ctx->result = accept4(get_sock_fd(s), addr, paddrlen, + SOCK_CLOEXEC); +- if (ctx->result == INVALID_SOCKET && state->accept4_works == -1) { ++ if (ctx->result == INVALID_SOCKET && _Py_atomic_load_int_relaxed(&accept4_works) == -1) { + /* On Linux older than 2.6.28, accept4() fails with ENOSYS */ +- state->accept4_works = (errno != ENOSYS); ++ _Py_atomic_store_int_relaxed(&accept4_works, errno != ENOSYS); + } + } +- if (state->accept4_works == 0) +- ctx->result = accept(s->sock_fd, addr, paddrlen); ++ if (_Py_atomic_load_int_relaxed(&accept4_works) == 0) ++ ctx->result = accept(get_sock_fd(s), addr, paddrlen); + #else +- ctx->result = accept(s->sock_fd, addr, paddrlen); ++ ctx->result = accept(get_sock_fd(s), addr, paddrlen); + #endif + + #ifdef MS_WINDOWS +@@ -2892,8 +2931,10 @@ + /* s._accept() -> (fd, address) */ + + static PyObject * +-sock_accept(PySocketSockObject *s, PyObject *Py_UNUSED(ignored)) ++sock_accept(PyObject *self, PyObject *Py_UNUSED(ignored)) + { ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); ++ + sock_addr_t addrbuf; + SOCKET_T newfd; + socklen_t addrlen; +@@ -2911,6 +2952,8 @@ + + ctx.addrlen = &addrlen; + ctx.addrbuf = &addrbuf; ++ ctx.result = INVALID_SOCKET; ++ + if (sock_call(s, 0, sock_accept_impl, &ctx) < 0) + return NULL; + newfd = ctx.result; +@@ -2929,8 +2972,7 @@ + #else + + #if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) +- socket_state *state = s->state; +- if (!state->accept4_works) ++ if (!_Py_atomic_load_int_relaxed(&accept4_works)) + #endif + { + if (_Py_set_inheritable(newfd, 0, NULL) < 0) { +@@ -2946,7 +2988,7 @@ + goto finally; + } + +- addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf), ++ addr = makesockaddr(get_sock_fd(s), SAS2SA(&addrbuf), + addrlen, s->sock_proto); + if (addr == NULL) + goto finally; +@@ -2974,7 +3016,7 @@ + */ + + static PyObject * +-sock_setblocking(PySocketSockObject *s, PyObject *arg) ++sock_setblocking(PyObject *self, PyObject *arg) + { + long block; + +@@ -2982,6 +3024,7 @@ + if (block < 0) + return NULL; + ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); + s->sock_timeout = _PyTime_FromSeconds(block ? -1 : 0); + if (internal_setblocking(s, block) == -1) { + return NULL; +@@ -3001,8 +3044,9 @@ + False if it is in non-blocking mode. + */ + static PyObject * +-sock_getblocking(PySocketSockObject *s, PyObject *Py_UNUSED(ignored)) ++sock_getblocking(PyObject *self, PyObject *Py_UNUSED(ignored)) + { ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); + if (s->sock_timeout) { + Py_RETURN_TRUE; + } +@@ -3065,13 +3109,14 @@ + < 0 -- illegal; raises an exception + */ + static PyObject * +-sock_settimeout(PySocketSockObject *s, PyObject *arg) ++sock_settimeout(PyObject *self, PyObject *arg) + { + PyTime_t timeout; + + if (socket_parse_timeout(&timeout, arg) < 0) + return NULL; + ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); + s->sock_timeout = timeout; + + int block = timeout < 0; +@@ -3113,8 +3158,9 @@ + /* s.gettimeout() method. + Returns the timeout associated with a socket. */ + static PyObject * +-sock_gettimeout(PySocketSockObject *s, PyObject *Py_UNUSED(ignored)) ++sock_gettimeout_impl(PyObject *self, void *Py_UNUSED(ignored)) + { ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); + if (s->sock_timeout < 0) { + Py_RETURN_NONE; + } +@@ -3124,6 +3170,18 @@ + } + } + ++static inline PyObject * ++sock_gettimeout_method(PyObject *self, PyObject *Py_UNUSED(ignored)) ++{ ++ return sock_gettimeout_impl(self, NULL); ++} ++ ++static inline PyObject * ++sock_gettimeout_getter(PyObject *self, void *Py_UNUSED(closure)) ++{ ++ return sock_gettimeout_impl(self, NULL); ++} ++ + PyDoc_STRVAR(gettimeout_doc, + "gettimeout() -> timeout\n\ + \n\ +@@ -3141,8 +3199,10 @@ + */ + + static PyObject * +-sock_setsockopt(PySocketSockObject *s, PyObject *args) ++sock_setsockopt(PyObject *self, PyObject *args) + { ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); ++ + int level; + int optname; + int res; +@@ -3158,7 +3218,7 @@ + if (PyArg_ParseTuple(args, "iiK:setsockopt", + &level, &optname, &vflag)) { + // level should always be set to AF_VSOCK +- res = setsockopt(s->sock_fd, level, optname, ++ res = setsockopt(get_sock_fd(s), level, optname, + (void*)&vflag, sizeof vflag); + goto done; + } +@@ -3172,7 +3232,7 @@ + #ifdef MS_WINDOWS + if (optname == SIO_TCP_SET_ACK_FREQUENCY) { + int dummy; +- res = WSAIoctl(s->sock_fd, SIO_TCP_SET_ACK_FREQUENCY, &flag, ++ res = WSAIoctl(get_sock_fd(s), SIO_TCP_SET_ACK_FREQUENCY, &flag, + sizeof(flag), NULL, 0, &dummy, NULL, NULL); + if (res >= 0) { + s->quickack = flag; +@@ -3180,7 +3240,7 @@ + goto done; + } + #endif +- res = setsockopt(s->sock_fd, level, optname, ++ res = setsockopt(get_sock_fd(s), level, optname, + (char*)&flag, sizeof flag); + goto done; + } +@@ -3190,7 +3250,7 @@ + if (PyArg_ParseTuple(args, "iiO!I:setsockopt", + &level, &optname, Py_TYPE(Py_None), &none, &optlen)) { + assert(sizeof(socklen_t) >= sizeof(unsigned int)); +- res = setsockopt(s->sock_fd, level, optname, ++ res = setsockopt(get_sock_fd(s), level, optname, + NULL, (socklen_t)optlen); + goto done; + } +@@ -3209,10 +3269,10 @@ + INT_MAX); + return NULL; + } +- res = setsockopt(s->sock_fd, level, optname, ++ res = setsockopt(get_sock_fd(s), level, optname, + optval.buf, (int)optval.len); + #else +- res = setsockopt(s->sock_fd, level, optname, optval.buf, optval.len); ++ res = setsockopt(get_sock_fd(s), level, optname, optval.buf, optval.len); + #endif + PyBuffer_Release(&optval); + +@@ -3240,8 +3300,10 @@ + use optional built-in module 'struct' to decode the string. */ + + static PyObject * +-sock_getsockopt(PySocketSockObject *s, PyObject *args) ++sock_getsockopt(PyObject *self, PyObject *args) + { ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); ++ + int level; + int optname; + int res; +@@ -3259,7 +3321,7 @@ + if (s->sock_family == AF_VSOCK) { + uint64_t vflag = 0; // Must be set width of 64 bits + flagsize = sizeof vflag; +- res = getsockopt(s->sock_fd, level, optname, ++ res = getsockopt(get_sock_fd(s), level, optname, + (void *)&vflag, &flagsize); + if (res < 0) + return s->errorhandler(); +@@ -3272,7 +3334,7 @@ + } + #endif + flagsize = sizeof flag; +- res = getsockopt(s->sock_fd, level, optname, ++ res = getsockopt(get_sock_fd(s), level, optname, + (void *)&flag, &flagsize); + if (res < 0) + return s->errorhandler(); +@@ -3293,7 +3355,7 @@ + buf = PyBytes_FromStringAndSize((char *)NULL, buflen); + if (buf == NULL) + return NULL; +- res = getsockopt(s->sock_fd, level, optname, ++ res = getsockopt(get_sock_fd(s), level, optname, + (void *)PyBytes_AS_STRING(buf), &buflen); + if (res < 0) { + Py_DECREF(buf); +@@ -3315,8 +3377,10 @@ + /* s.bind(sockaddr) method */ + + static PyObject * +-sock_bind(PySocketSockObject *s, PyObject *addro) ++sock_bind(PyObject *self, PyObject *addro) + { ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); ++ + sock_addr_t addrbuf; + int addrlen; + int res; +@@ -3330,7 +3394,7 @@ + } + + Py_BEGIN_ALLOW_THREADS +- res = bind(s->sock_fd, SAS2SA(&addrbuf), addrlen); ++ res = bind(get_sock_fd(s), SAS2SA(&addrbuf), addrlen); + Py_END_ALLOW_THREADS + if (res < 0) + return s->errorhandler(); +@@ -3351,7 +3415,6 @@ + will surely fail. */ + + /*[clinic input] +-@critical_section + _socket.socket.close + self as s: self(type="PySocketSockObject *") + +@@ -3362,14 +3425,14 @@ + + static PyObject * + _socket_socket_close_impl(PySocketSockObject *s) +-/*[clinic end generated code: output=038b2418e07f6f6c input=9839a261e05bcb97]*/ ++/*[clinic end generated code: output=038b2418e07f6f6c input=dc487e470e55a83c]*/ + { + SOCKET_T fd; + int res; + +- fd = s->sock_fd; ++ fd = get_sock_fd(s); + if (fd != INVALID_SOCKET) { +- s->sock_fd = INVALID_SOCKET; ++ set_sock_fd(s, INVALID_SOCKET); + + /* We do not want to retry upon EINTR: see + http://lwn.net/Articles/576478/ and +@@ -3388,10 +3451,11 @@ + } + + static PyObject * +-sock_detach(PySocketSockObject *s, PyObject *Py_UNUSED(ignored)) ++sock_detach(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- SOCKET_T fd = s->sock_fd; +- s->sock_fd = INVALID_SOCKET; ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); ++ SOCKET_T fd = get_sock_fd(s); ++ set_sock_fd(s, INVALID_SOCKET); + return PyLong_FromSocket_t(fd); + } + +@@ -3409,7 +3473,7 @@ + int err; + socklen_t size = sizeof err; + +- if (getsockopt(s->sock_fd, SOL_SOCKET, SO_ERROR, (void *)&err, &size)) { ++ if (getsockopt(get_sock_fd(s), SOL_SOCKET, SO_ERROR, (void *)&err, &size)) { + /* getsockopt() failed */ + return 0; + } +@@ -3443,7 +3507,7 @@ + int res, err, wait_connect; + + Py_BEGIN_ALLOW_THREADS +- res = connect(s->sock_fd, addr, addrlen); ++ res = connect(get_sock_fd(s), addr, addrlen); + Py_END_ALLOW_THREADS + + if (!res) { +@@ -3505,8 +3569,10 @@ + /* s.connect(sockaddr) method */ + + static PyObject * +-sock_connect(PySocketSockObject *s, PyObject *addro) ++sock_connect(PyObject *self, PyObject *addro) + { ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); ++ + sock_addr_t addrbuf; + int addrlen; + int res; +@@ -3538,8 +3604,10 @@ + /* s.connect_ex(sockaddr) method */ + + static PyObject * +-sock_connect_ex(PySocketSockObject *s, PyObject *addro) ++sock_connect_ex(PyObject *self, PyObject *addro) + { ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); ++ + sock_addr_t addrbuf; + int addrlen; + int res; +@@ -3571,9 +3639,10 @@ + /* s.fileno() method */ + + static PyObject * +-sock_fileno(PySocketSockObject *s, PyObject *Py_UNUSED(ignored)) ++sock_fileno(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return PyLong_FromSocket_t(s->sock_fd); ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); ++ return PyLong_FromSocket_t(get_sock_fd(s)); + } + + PyDoc_STRVAR(fileno_doc, +@@ -3586,8 +3655,10 @@ + /* s.getsockname() method */ + + static PyObject * +-sock_getsockname(PySocketSockObject *s, PyObject *Py_UNUSED(ignored)) ++sock_getsockname(PyObject *self, PyObject *Py_UNUSED(ignored)) + { ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); ++ + sock_addr_t addrbuf; + int res; + socklen_t addrlen; +@@ -3596,11 +3667,11 @@ + return NULL; + memset(&addrbuf, 0, addrlen); + Py_BEGIN_ALLOW_THREADS +- res = getsockname(s->sock_fd, SAS2SA(&addrbuf), &addrlen); ++ res = getsockname(get_sock_fd(s), SAS2SA(&addrbuf), &addrlen); + Py_END_ALLOW_THREADS + if (res < 0) + return s->errorhandler(); +- return makesockaddr(s->sock_fd, SAS2SA(&addrbuf), addrlen, ++ return makesockaddr(get_sock_fd(s), SAS2SA(&addrbuf), addrlen, + s->sock_proto); + } + +@@ -3618,8 +3689,10 @@ + /* s.getpeername() method */ + + static PyObject * +-sock_getpeername(PySocketSockObject *s, PyObject *Py_UNUSED(ignored)) ++sock_getpeername(PyObject *self, PyObject *Py_UNUSED(ignored)) + { ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); ++ + sock_addr_t addrbuf; + int res; + socklen_t addrlen; +@@ -3628,11 +3701,11 @@ + return NULL; + memset(&addrbuf, 0, addrlen); + Py_BEGIN_ALLOW_THREADS +- res = getpeername(s->sock_fd, SAS2SA(&addrbuf), &addrlen); ++ res = getpeername(get_sock_fd(s), SAS2SA(&addrbuf), &addrlen); + Py_END_ALLOW_THREADS + if (res < 0) + return s->errorhandler(); +- return makesockaddr(s->sock_fd, SAS2SA(&addrbuf), addrlen, ++ return makesockaddr(get_sock_fd(s), SAS2SA(&addrbuf), addrlen, + s->sock_proto); + } + +@@ -3649,8 +3722,9 @@ + /* s.listen(n) method */ + + static PyObject * +-sock_listen(PySocketSockObject *s, PyObject *args) ++sock_listen(PyObject *self, PyObject *args) + { ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); + /* We try to choose a default backlog high enough to avoid connection drops + * for common workloads, yet not too high to limit resource usage. */ + int backlog = Py_MIN(SOMAXCONN, 128); +@@ -3664,7 +3738,7 @@ + * (which doesn't make sense anyway) we force a minimum value of 0. */ + if (backlog < 0) + backlog = 0; +- res = listen(s->sock_fd, backlog); ++ res = listen(get_sock_fd(s), backlog); + Py_END_ALLOW_THREADS + if (res < 0) + return s->errorhandler(); +@@ -3695,9 +3769,9 @@ + #ifdef MS_WINDOWS + if (ctx->len > INT_MAX) + ctx->len = INT_MAX; +- ctx->result = recv(s->sock_fd, ctx->cbuf, (int)ctx->len, ctx->flags); ++ ctx->result = recv(get_sock_fd(s), ctx->cbuf, (int)ctx->len, ctx->flags); + #else +- ctx->result = recv(s->sock_fd, ctx->cbuf, ctx->len, ctx->flags); ++ ctx->result = recv(get_sock_fd(s), ctx->cbuf, ctx->len, ctx->flags); + #endif + return (ctx->result >= 0); + } +@@ -3739,8 +3813,10 @@ + /* s.recv(nbytes [,flags]) method */ + + static PyObject * +-sock_recv(PySocketSockObject *s, PyObject *args) ++sock_recv(PyObject *self, PyObject *args) + { ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); ++ + Py_ssize_t recvlen, outlen; + int flags = 0; + PyObject *buf; +@@ -3788,9 +3864,10 @@ + /* s.recv_into(buffer, [nbytes [,flags]]) method */ + + static PyObject* +-sock_recv_into(PySocketSockObject *s, PyObject *args, PyObject *kwds) ++sock_recv_into(PyObject *self, PyObject *args, PyObject *kwds) + { + static char *kwlist[] = {"buffer", "nbytes", "flags", 0}; ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); + + int flags = 0; + Py_buffer pbuf; +@@ -3866,10 +3943,10 @@ + #ifdef MS_WINDOWS + if (ctx->len > INT_MAX) + ctx->len = INT_MAX; +- ctx->result = recvfrom(s->sock_fd, ctx->cbuf, (int)ctx->len, ctx->flags, ++ ctx->result = recvfrom(get_sock_fd(s), ctx->cbuf, (int)ctx->len, ctx->flags, + SAS2SA(ctx->addrbuf), ctx->addrlen); + #else +- ctx->result = recvfrom(s->sock_fd, ctx->cbuf, ctx->len, ctx->flags, ++ ctx->result = recvfrom(get_sock_fd(s), ctx->cbuf, ctx->len, ctx->flags, + SAS2SA(ctx->addrbuf), ctx->addrlen); + #endif + return (ctx->result >= 0); +@@ -3913,7 +3990,7 @@ + if (sock_call(s, 0, sock_recvfrom_impl, &ctx) < 0) + return -1; + +- *addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf), addrlen, ++ *addr = makesockaddr(get_sock_fd(s), SAS2SA(&addrbuf), addrlen, + s->sock_proto); + if (*addr == NULL) + return -1; +@@ -3924,8 +4001,10 @@ + /* s.recvfrom(nbytes [,flags]) method */ + + static PyObject * +-sock_recvfrom(PySocketSockObject *s, PyObject *args) ++sock_recvfrom(PyObject *self, PyObject *args) + { ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); ++ + PyObject *buf = NULL; + PyObject *addr = NULL; + PyObject *ret = NULL; +@@ -3976,9 +4055,10 @@ + /* s.recvfrom_into(buffer[, nbytes [,flags]]) method */ + + static PyObject * +-sock_recvfrom_into(PySocketSockObject *s, PyObject *args, PyObject* kwds) ++sock_recvfrom_into(PyObject *self, PyObject *args, PyObject* kwds) + { + static char *kwlist[] = {"buffer", "nbytes", "flags", 0}; ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); + + int flags = 0; + Py_buffer pbuf; +@@ -4044,7 +4124,7 @@ + { + struct sock_recvmsg *ctx = data; + +- ctx->result = recvmsg(s->sock_fd, ctx->msg, ctx->flags); ++ ctx->result = recvmsg(get_sock_fd(s), ctx->msg, ctx->flags); + return (ctx->result >= 0); + } + +@@ -4153,7 +4233,7 @@ + (*makeval)(ctx.result, makeval_data), + cmsg_list, + (int)msg.msg_flags, +- makesockaddr(s->sock_fd, SAS2SA(&addrbuf), ++ makesockaddr(get_sock_fd(s), SAS2SA(&addrbuf), + ((msg.msg_namelen > addrbuflen) ? + addrbuflen : msg.msg_namelen), + s->sock_proto)); +@@ -4204,8 +4284,10 @@ + /* s.recvmsg(bufsize[, ancbufsize[, flags]]) method */ + + static PyObject * +-sock_recvmsg(PySocketSockObject *s, PyObject *args) ++sock_recvmsg(PyObject *self, PyObject *args) + { ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); ++ + Py_ssize_t bufsize, ancbufsize = 0; + int flags = 0; + struct iovec iov; +@@ -4271,8 +4353,10 @@ + /* s.recvmsg_into(buffers[, ancbufsize[, flags]]) method */ + + static PyObject * +-sock_recvmsg_into(PySocketSockObject *s, PyObject *args) ++sock_recvmsg_into(PyObject *self, PyObject *args) + { ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); ++ + Py_ssize_t ancbufsize = 0; + int flags = 0; + struct iovec *iovs = NULL; +@@ -4372,9 +4456,9 @@ + #ifdef MS_WINDOWS + if (ctx->len > INT_MAX) + ctx->len = INT_MAX; +- ctx->result = send(s->sock_fd, ctx->buf, (int)ctx->len, ctx->flags); ++ ctx->result = send(get_sock_fd(s), ctx->buf, (int)ctx->len, ctx->flags); + #else +- ctx->result = send(s->sock_fd, ctx->buf, ctx->len, ctx->flags); ++ ctx->result = send(get_sock_fd(s), ctx->buf, ctx->len, ctx->flags); + #endif + return (ctx->result >= 0); + } +@@ -4382,8 +4466,10 @@ + /* s.send(data [,flags]) method */ + + static PyObject * +-sock_send(PySocketSockObject *s, PyObject *args) ++sock_send(PyObject *self, PyObject *args) + { ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); ++ + int flags = 0; + Py_buffer pbuf; + struct sock_send ctx; +@@ -4418,8 +4504,10 @@ + /* s.sendall(data [,flags]) method */ + + static PyObject * +-sock_sendall(PySocketSockObject *s, PyObject *args) ++sock_sendall(PyObject *self, PyObject *args) + { ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); ++ + char *buf; + Py_ssize_t len, n; + int flags = 0; +@@ -4511,10 +4599,10 @@ + #ifdef MS_WINDOWS + if (ctx->len > INT_MAX) + ctx->len = INT_MAX; +- ctx->result = sendto(s->sock_fd, ctx->buf, (int)ctx->len, ctx->flags, ++ ctx->result = sendto(get_sock_fd(s), ctx->buf, (int)ctx->len, ctx->flags, + SAS2SA(ctx->addrbuf), ctx->addrlen); + #else +- ctx->result = sendto(s->sock_fd, ctx->buf, ctx->len, ctx->flags, ++ ctx->result = sendto(get_sock_fd(s), ctx->buf, ctx->len, ctx->flags, + SAS2SA(ctx->addrbuf), ctx->addrlen); + #endif + return (ctx->result >= 0); +@@ -4523,8 +4611,10 @@ + /* s.sendto(data, [flags,] sockaddr) method */ + + static PyObject * +-sock_sendto(PySocketSockObject *s, PyObject *args) ++sock_sendto(PyObject *self, PyObject *args) + { ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); ++ + Py_buffer pbuf; + PyObject *addro; + Py_ssize_t arglen; +@@ -4660,15 +4750,17 @@ + { + struct sock_sendmsg *ctx = data; + +- ctx->result = sendmsg(s->sock_fd, ctx->msg, ctx->flags); ++ ctx->result = sendmsg(get_sock_fd(s), ctx->msg, ctx->flags); + return (ctx->result >= 0); + } + + /* s.sendmsg(buffers[, ancdata[, flags[, address]]]) method */ + + static PyObject * +-sock_sendmsg(PySocketSockObject *s, PyObject *args) ++sock_sendmsg(PyObject *self, PyObject *args) + { ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); ++ + Py_ssize_t i, ndatabufs = 0, ncmsgs, ncmsgbufs = 0; + Py_buffer *databufs = NULL; + sock_addr_t addrbuf; +@@ -4871,8 +4963,10 @@ + + #ifdef HAVE_SOCKADDR_ALG + static PyObject* +-sock_sendmsg_afalg(PySocketSockObject *self, PyObject *args, PyObject *kwds) ++sock_sendmsg_afalg(PyObject *s, PyObject *args, PyObject *kwds) + { ++ PySocketSockObject *self = _PySocketSockObject_CAST(s); ++ + PyObject *retval = NULL; + + Py_ssize_t i, ndatabufs = 0; +@@ -5039,8 +5133,10 @@ + /* s.shutdown(how) method */ + + static PyObject * +-sock_shutdown(PySocketSockObject *s, PyObject *arg) ++sock_shutdown(PyObject *self, PyObject *arg) + { ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); ++ + int how; + int res; + +@@ -5048,7 +5144,7 @@ + if (how == -1 && PyErr_Occurred()) + return NULL; + Py_BEGIN_ALLOW_THREADS +- res = shutdown(s->sock_fd, how); ++ res = shutdown(get_sock_fd(s), how); + Py_END_ALLOW_THREADS + if (res < 0) + return s->errorhandler(); +@@ -5064,8 +5160,10 @@ + + #if defined(MS_WINDOWS) && defined(SIO_RCVALL) + static PyObject* +-sock_ioctl(PySocketSockObject *s, PyObject *arg) ++sock_ioctl(PyObject *self, PyObject *arg) + { ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); ++ + unsigned long cmd = SIO_RCVALL; + PyObject *argO; + DWORD recv; +@@ -5078,7 +5176,7 @@ + unsigned int option = RCVALL_ON; + if (!PyArg_ParseTuple(arg, "kI:ioctl", &cmd, &option)) + return NULL; +- if (WSAIoctl(s->sock_fd, cmd, &option, sizeof(option), ++ if (WSAIoctl(get_sock_fd(s), cmd, &option, sizeof(option), + NULL, 0, &recv, NULL, NULL) == SOCKET_ERROR) { + return set_error(); + } +@@ -5088,7 +5186,7 @@ + if (!PyArg_ParseTuple(arg, "k(kkk):ioctl", &cmd, + &ka.onoff, &ka.keepalivetime, &ka.keepaliveinterval)) + return NULL; +- if (WSAIoctl(s->sock_fd, cmd, &ka, sizeof(ka), ++ if (WSAIoctl(get_sock_fd(s), cmd, &ka, sizeof(ka), + NULL, 0, &recv, NULL, NULL) == SOCKET_ERROR) { + return set_error(); + } +@@ -5098,7 +5196,7 @@ + unsigned int option; + if (!PyArg_ParseTuple(arg, "kI:ioctl", &cmd, &option)) + return NULL; +- if (WSAIoctl(s->sock_fd, cmd, &option, sizeof(option), ++ if (WSAIoctl(get_sock_fd(s), cmd, &option, sizeof(option), + NULL, 0, &recv, NULL, NULL) == SOCKET_ERROR) { + return set_error(); + } +@@ -5120,8 +5218,10 @@ + + #if defined(MS_WINDOWS) + static PyObject* +-sock_share(PySocketSockObject *s, PyObject *arg) ++sock_share(PyObject *self, PyObject *arg) + { ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); ++ + WSAPROTOCOL_INFOW info; + DWORD processId; + int result; +@@ -5130,7 +5230,7 @@ + return NULL; + + Py_BEGIN_ALLOW_THREADS +- result = WSADuplicateSocketW(s->sock_fd, processId, &info); ++ result = WSADuplicateSocketW(get_sock_fd(s), processId, &info); + Py_END_ALLOW_THREADS + if (result == SOCKET_ERROR) + return set_error(); +@@ -5151,93 +5251,82 @@ + + static PyMethodDef sock_methods[] = { + #if defined(HAVE_ACCEPT) || defined(HAVE_ACCEPT4) +- {"_accept", (PyCFunction)sock_accept, METH_NOARGS, +- accept_doc}, ++ {"_accept", sock_accept, METH_NOARGS, accept_doc}, + #endif + #ifdef HAVE_BIND +- {"bind", (PyCFunction)sock_bind, METH_O, +- bind_doc}, ++ {"bind", sock_bind, METH_O, bind_doc}, + #endif + _SOCKET_SOCKET_CLOSE_METHODDEF + #ifdef HAVE_CONNECT +- {"connect", (PyCFunction)sock_connect, METH_O, +- connect_doc}, +- {"connect_ex", (PyCFunction)sock_connect_ex, METH_O, +- connect_ex_doc}, +-#endif +- {"detach", (PyCFunction)sock_detach, METH_NOARGS, +- detach_doc}, +- {"fileno", (PyCFunction)sock_fileno, METH_NOARGS, +- fileno_doc}, ++ {"connect", sock_connect, METH_O, connect_doc}, ++ {"connect_ex", sock_connect_ex, METH_O, connect_ex_doc}, ++#endif ++ {"detach", sock_detach, METH_NOARGS, detach_doc}, ++ {"fileno", sock_fileno, METH_NOARGS, fileno_doc}, + #ifdef HAVE_GETPEERNAME +- {"getpeername", (PyCFunction)sock_getpeername, +- METH_NOARGS, getpeername_doc}, ++ {"getpeername", sock_getpeername, METH_NOARGS, getpeername_doc}, + #endif + #ifdef HAVE_GETSOCKNAME +- {"getsockname", (PyCFunction)sock_getsockname, +- METH_NOARGS, getsockname_doc}, ++ {"getsockname", sock_getsockname, METH_NOARGS, getsockname_doc}, + #endif +- {"getsockopt", (PyCFunction)sock_getsockopt, METH_VARARGS, +- getsockopt_doc}, ++ {"getsockopt", sock_getsockopt, METH_VARARGS, getsockopt_doc}, + #if defined(MS_WINDOWS) && defined(SIO_RCVALL) +- {"ioctl", (PyCFunction)sock_ioctl, METH_VARARGS, +- sock_ioctl_doc}, ++ {"ioctl", sock_ioctl, METH_VARARGS, sock_ioctl_doc}, + #endif + #if defined(MS_WINDOWS) +- {"share", (PyCFunction)sock_share, METH_VARARGS, +- sock_share_doc}, ++ {"share", sock_share, METH_VARARGS, sock_share_doc}, + #endif + #ifdef HAVE_LISTEN +- {"listen", (PyCFunction)sock_listen, METH_VARARGS, +- listen_doc}, ++ {"listen", sock_listen, METH_VARARGS, listen_doc}, + #endif +- {"recv", (PyCFunction)sock_recv, METH_VARARGS, +- recv_doc}, +- {"recv_into", _PyCFunction_CAST(sock_recv_into), METH_VARARGS | METH_KEYWORDS, +- recv_into_doc}, ++ {"recv", sock_recv, METH_VARARGS, recv_doc}, ++ { ++ "recv_into", ++ _PyCFunction_CAST(sock_recv_into), ++ METH_VARARGS | METH_KEYWORDS, ++ recv_into_doc ++ }, + #ifdef HAVE_RECVFROM +- {"recvfrom", (PyCFunction)sock_recvfrom, METH_VARARGS, +- recvfrom_doc}, +- {"recvfrom_into", _PyCFunction_CAST(sock_recvfrom_into), METH_VARARGS | METH_KEYWORDS, +- recvfrom_into_doc}, +-#endif +- {"send", (PyCFunction)sock_send, METH_VARARGS, +- send_doc}, +- {"sendall", (PyCFunction)sock_sendall, METH_VARARGS, +- sendall_doc}, ++ {"recvfrom", sock_recvfrom, METH_VARARGS, recvfrom_doc}, ++ { ++ "recvfrom_into", ++ _PyCFunction_CAST(sock_recvfrom_into), ++ METH_VARARGS | METH_KEYWORDS, ++ recvfrom_into_doc ++ }, ++#endif ++ {"send", sock_send, METH_VARARGS, send_doc}, ++ {"sendall", sock_sendall, METH_VARARGS, sendall_doc}, + #ifdef HAVE_SENDTO +- {"sendto", (PyCFunction)sock_sendto, METH_VARARGS, +- sendto_doc}, +-#endif +- {"setblocking", (PyCFunction)sock_setblocking, METH_O, +- setblocking_doc}, +- {"getblocking", (PyCFunction)sock_getblocking, METH_NOARGS, +- getblocking_doc}, +- {"settimeout", (PyCFunction)sock_settimeout, METH_O, +- settimeout_doc}, +- {"gettimeout", (PyCFunction)sock_gettimeout, METH_NOARGS, +- gettimeout_doc}, ++ {"sendto", sock_sendto, METH_VARARGS, sendto_doc}, ++#endif ++ {"setblocking", sock_setblocking, METH_O, setblocking_doc}, ++ {"getblocking", sock_getblocking, METH_NOARGS, getblocking_doc}, ++ {"settimeout", sock_settimeout, METH_O, settimeout_doc}, ++ { ++ "gettimeout", sock_gettimeout_method, METH_NOARGS, ++ gettimeout_doc ++ }, + #ifdef HAVE_SETSOCKOPT +- {"setsockopt", (PyCFunction)sock_setsockopt, METH_VARARGS, +- setsockopt_doc}, ++ {"setsockopt", sock_setsockopt, METH_VARARGS, setsockopt_doc}, + #endif + #ifdef HAVE_SHUTDOWN +- {"shutdown", (PyCFunction)sock_shutdown, METH_O, +- shutdown_doc}, ++ {"shutdown", sock_shutdown, METH_O, shutdown_doc}, + #endif + #ifdef CMSG_LEN +- {"recvmsg", (PyCFunction)sock_recvmsg, METH_VARARGS, +- recvmsg_doc}, +- {"recvmsg_into", (PyCFunction)sock_recvmsg_into, METH_VARARGS, +- recvmsg_into_doc,}, +- {"sendmsg", (PyCFunction)sock_sendmsg, METH_VARARGS, +- sendmsg_doc}, ++ {"recvmsg", sock_recvmsg, METH_VARARGS, recvmsg_doc}, ++ {"recvmsg_into", sock_recvmsg_into, METH_VARARGS, recvmsg_into_doc}, ++ {"sendmsg", sock_sendmsg, METH_VARARGS, sendmsg_doc}, + #endif + #ifdef HAVE_SOCKADDR_ALG +- {"sendmsg_afalg", _PyCFunction_CAST(sock_sendmsg_afalg), METH_VARARGS | METH_KEYWORDS, +- sendmsg_afalg_doc}, ++ { ++ "sendmsg_afalg", ++ _PyCFunction_CAST(sock_sendmsg_afalg), ++ METH_VARARGS | METH_KEYWORDS, ++ sendmsg_afalg_doc ++ }, + #endif +- {NULL, NULL} /* sentinel */ ++ {NULL, NULL, 0, NULL} /* sentinel */ + }; + + /* SockObject members */ +@@ -5249,7 +5338,7 @@ + }; + + static PyGetSetDef sock_getsetlist[] = { +- {"timeout", (getter)sock_gettimeout, NULL, PyDoc_STR("the socket timeout")}, ++ {"timeout", sock_gettimeout_getter, NULL, PyDoc_STR("the socket timeout")}, + {NULL} /* sentinel */ + }; + +@@ -5257,18 +5346,21 @@ + First close the file description. */ + + static void +-sock_finalize(PySocketSockObject *s) ++sock_finalize(PyObject *self) + { ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); ++ + SOCKET_T fd; + + /* Save the current exception, if any. */ + PyObject *exc = PyErr_GetRaisedException(); + +- if (s->sock_fd != INVALID_SOCKET) { ++ if (get_sock_fd(s) != INVALID_SOCKET) { + if (PyErr_ResourceWarning((PyObject *)s, 1, "unclosed %R", s)) { + /* Spurious errors can appear at shutdown */ + if (PyErr_ExceptionMatches(PyExc_Warning)) { +- PyErr_WriteUnraisable((PyObject *)s); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "finalizing socket %R", s); + } + } + +@@ -5276,8 +5368,8 @@ + to allow the logger to call socket methods like + socket.getsockname(). If the socket is closed before, socket + methods fails with the EBADF error. */ +- fd = s->sock_fd; +- s->sock_fd = INVALID_SOCKET; ++ fd = get_sock_fd(s); ++ set_sock_fd(s, INVALID_SOCKET); + + /* We do not want to retry upon EINTR: see sock_close() */ + Py_BEGIN_ALLOW_THREADS +@@ -5290,35 +5382,37 @@ + } + + static int +-sock_traverse(PySocketSockObject *s, visitproc visit, void *arg) ++sock_traverse(PyObject *s, visitproc visit, void *arg) + { + Py_VISIT(Py_TYPE(s)); + return 0; + } + + static void +-sock_dealloc(PySocketSockObject *s) ++sock_dealloc(PyObject *s) + { +- if (PyObject_CallFinalizerFromDealloc((PyObject *)s) < 0) { ++ if (PyObject_CallFinalizerFromDealloc(s) < 0) { + return; + } + PyTypeObject *tp = Py_TYPE(s); + PyObject_GC_UnTrack(s); +- tp->tp_free((PyObject *)s); ++ tp->tp_free(s); + Py_DECREF(tp); + } + + + static PyObject * +-sock_repr(PySocketSockObject *s) ++sock_repr(PyObject *self) + { ++ PySocketSockObject *s = _PySocketSockObject_CAST(self); ++ + long sock_fd; + /* On Windows, this test is needed because SOCKET_T is unsigned */ +- if (s->sock_fd == INVALID_SOCKET) { ++ if (get_sock_fd(s) == INVALID_SOCKET) { + sock_fd = -1; + } + #if SIZEOF_SOCKET_T > SIZEOF_LONG +- else if (s->sock_fd > LONG_MAX) { ++ else if (get_sock_fd(s) > LONG_MAX) { + /* this can occur on Win64, and actually there is a special + ugly printf formatter for decimal pointer length integer + printing, only bother if necessary*/ +@@ -5329,7 +5423,7 @@ + } + #endif + else +- sock_fd = (long)s->sock_fd; ++ sock_fd = (long)get_sock_fd(s); + return PyUnicode_FromFormat( + "", + sock_fd, s->sock_family, +@@ -5391,7 +5485,7 @@ + + #ifndef MS_WINDOWS + #ifdef SOCK_CLOEXEC +- int *atomic_flag_works = &state->sock_cloexec_works; ++ int *atomic_flag_works = &sock_cloexec_works; + #else + int *atomic_flag_works = NULL; + #endif +@@ -5546,15 +5640,16 @@ + /* UNIX */ + Py_BEGIN_ALLOW_THREADS + #ifdef SOCK_CLOEXEC +- if (state->sock_cloexec_works != 0) { ++ if (_Py_atomic_load_int_relaxed(&sock_cloexec_works) != 0) { + fd = socket(family, type | SOCK_CLOEXEC, proto); +- if (state->sock_cloexec_works == -1) { ++ if (_Py_atomic_load_int_relaxed(&sock_cloexec_works) == -1) { + if (fd >= 0) { +- state->sock_cloexec_works = 1; ++ _Py_atomic_store_int_relaxed(&sock_cloexec_works, 1); + } ++ + else if (errno == EINVAL) { + /* Linux older than 2.6.27 does not support SOCK_CLOEXEC */ +- state->sock_cloexec_works = 0; ++ _Py_atomic_store_int_relaxed(&sock_cloexec_works, 0); + fd = socket(family, type, proto); + } + } +@@ -6295,7 +6390,7 @@ + PyObject *res = NULL; + socket_state *state = get_module_state(self); + #ifdef SOCK_CLOEXEC +- int *atomic_flag_works = &state->sock_cloexec_works; ++ int *atomic_flag_works = &sock_cloexec_works; + #else + int *atomic_flag_works = NULL; + #endif +@@ -6313,15 +6408,15 @@ + /* Create a pair of socket fds */ + Py_BEGIN_ALLOW_THREADS + #ifdef SOCK_CLOEXEC +- if (state->sock_cloexec_works != 0) { ++ if (_Py_atomic_load_int_relaxed(&sock_cloexec_works) != 0) { + ret = socketpair(family, type | SOCK_CLOEXEC, proto, sv); +- if (state->sock_cloexec_works == -1) { ++ if (_Py_atomic_load_int_relaxed(&sock_cloexec_works) == -1) { + if (ret >= 0) { +- state->sock_cloexec_works = 1; ++ _Py_atomic_store_int_relaxed(&sock_cloexec_works, 1); + } + else if (errno == EINVAL) { + /* Linux older than 2.6.27 does not support SOCK_CLOEXEC */ +- state->sock_cloexec_works = 0; ++ _Py_atomic_store_int_relaxed(&sock_cloexec_works, 0); + ret = socketpair(family, type, proto, sv); + } + } +@@ -7429,17 +7524,8 @@ + } + + socket_state *state = get_module_state(m); +- state->defaulttimeout = _PYTIME_FROMSECONDS(-1); + +-#if defined(HAVE_ACCEPT) || defined(HAVE_ACCEPT4) +-#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) +- state->accept4_works = -1; +-#endif +-#endif +- +-#ifdef SOCK_CLOEXEC +- state->sock_cloexec_works = -1; +-#endif ++ _Py_atomic_store_int64_relaxed(&state->defaulttimeout, _PYTIME_FROMSECONDS(-1)); + + #define ADD_EXC(MOD, NAME, VAR, BASE) do { \ + VAR = PyErr_NewException("socket." NAME, BASE, NULL); \ +@@ -7916,6 +8002,9 @@ + ADD_INT_MACRO(m, SO_REUSEPORT); + #endif + #endif ++#ifdef SO_REUSEPORT_LB ++ ADD_INT_MACRO(m, SO_REUSEPORT_LB); ++#endif + #ifdef SO_SNDBUF + ADD_INT_MACRO(m, SO_SNDBUF); + #endif +diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c +index 14e7ca591a0..aa1bc9da91d 100644 +--- a/Modules/syslogmodule.c ++++ b/Modules/syslogmodule.c +@@ -176,7 +176,7 @@ + } + } + if (PySys_Audit("syslog.openlog", "Oll", ident ? ident : Py_None, logopt, facility) < 0) { +- Py_DECREF(ident); ++ Py_XDECREF(ident); + return NULL; + } + +@@ -258,7 +258,7 @@ + // Since the sys.closelog changes the process level state of syslog library, + // this operation is only allowed for the main interpreter. + if (!is_main_interpreter()) { +- PyErr_SetString(PyExc_RuntimeError, "sunbinterpreter can't use syslog.closelog()"); ++ PyErr_SetString(PyExc_RuntimeError, "subinterpreter can't use syslog.closelog()"); + return NULL; + } + +diff --git a/Modules/timemodule.c b/Modules/timemodule.c +index 340011fc08b..8d2cbff662b 100644 +--- a/Modules/timemodule.c ++++ b/Modules/timemodule.c +@@ -913,9 +913,10 @@ + PyErr_NoMemory(); + return NULL; + } +- _PyUnicodeWriter writer; +- _PyUnicodeWriter_Init(&writer); +- writer.overallocate = 1; ++ PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); ++ if (writer == NULL) { ++ goto error; ++ } + Py_ssize_t i = 0; + while (i < format_size) { + fmtlen = 0; +@@ -933,7 +934,7 @@ + if (unicode == NULL) { + goto error; + } +- if (_PyUnicodeWriter_WriteStr(&writer, unicode) < 0) { ++ if (PyUnicodeWriter_WriteStr(writer, unicode) < 0) { + Py_DECREF(unicode); + goto error; + } +@@ -947,18 +948,18 @@ + break; + } + } +- if (_PyUnicodeWriter_WriteSubstring(&writer, format_arg, start, i) < 0) { ++ if (PyUnicodeWriter_WriteSubstring(writer, format_arg, start, i) < 0) { + goto error; + } + } + + PyMem_Free(outbuf); + PyMem_Free(format); +- return _PyUnicodeWriter_Finish(&writer); ++ return PyUnicodeWriter_Finish(writer); + error: + PyMem_Free(outbuf); + PyMem_Free(format); +- _PyUnicodeWriter_Dealloc(&writer); ++ PyUnicodeWriter_Discard(writer); + return NULL; + } + +@@ -978,7 +979,7 @@ + { + PyObject *func, *result; + +- func = _PyImport_GetModuleAttrString("_strptime", "_strptime_time"); ++ func = PyImport_ImportModuleAttrString("_strptime", "_strptime_time"); + if (!func) { + return NULL; + } +diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c +index 78dcce73cda..b90665ae7ef 100644 +--- a/Modules/zlibmodule.c ++++ b/Modules/zlibmodule.c +@@ -221,6 +221,8 @@ + PyThread_type_lock lock; + } compobject; + ++#define _compobject_CAST(op) ((compobject *)op) ++ + static void + zlib_error(zlibstate *state, z_stream zst, int err, const char *msg) + { +@@ -706,7 +708,7 @@ + static void + Dealloc(compobject *self) + { +- PyObject *type = (PyObject *)Py_TYPE(self); ++ PyTypeObject *type = Py_TYPE(self); + PyThread_free_lock(self->lock); + Py_XDECREF(self->unused_data); + Py_XDECREF(self->unconsumed_tail); +@@ -716,18 +718,20 @@ + } + + static void +-Comp_dealloc(compobject *self) ++Comp_dealloc(PyObject *op) + { ++ compobject *self = _compobject_CAST(op); + if (self->is_initialised) +- deflateEnd(&self->zst); ++ (void)deflateEnd(&self->zst); + Dealloc(self); + } + + static void +-Decomp_dealloc(compobject *self) ++Decomp_dealloc(PyObject *op) + { ++ compobject *self = _compobject_CAST(op); + if (self->is_initialised) +- inflateEnd(&self->zst); ++ (void)inflateEnd(&self->zst); + Dealloc(self); + } + +diff --git a/Objects/abstract.c b/Objects/abstract.c +index c92ef10aa79..db7b9263711 100644 +--- a/Objects/abstract.c ++++ b/Objects/abstract.c +@@ -583,7 +583,7 @@ + PyObject *fmt = NULL; + Py_ssize_t itemsize = -1; + +- calcsize = _PyImport_GetModuleAttrString("struct", "calcsize"); ++ calcsize = PyImport_ImportModuleAttrString("struct", "calcsize"); + if (calcsize == NULL) { + goto done; + } +diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c +index 871f99b6f88..6133d30f499 100644 +--- a/Objects/bytearrayobject.c ++++ b/Objects/bytearrayobject.c +@@ -184,7 +184,12 @@ + assert(self != NULL); + assert(PyByteArray_Check(self)); + assert(logical_offset <= alloc); +- assert(requested_size >= 0); ++ ++ if (requested_size < 0) { ++ PyErr_Format(PyExc_ValueError, ++ "Can only resize to positive sizes, got %zd", requested_size); ++ return -1; ++ } + + if (requested_size == Py_SIZE(self)) { + return 0; +@@ -1388,6 +1393,31 @@ + } + + ++/*[clinic input] ++bytearray.resize ++ size: Py_ssize_t ++ New size to resize to.. ++ / ++Resize the internal buffer of bytearray to len. ++[clinic start generated code]*/ ++ ++static PyObject * ++bytearray_resize_impl(PyByteArrayObject *self, Py_ssize_t size) ++/*[clinic end generated code: output=f73524922990b2d9 input=75fd4d17c4aa47d3]*/ ++{ ++ Py_ssize_t start_size = PyByteArray_GET_SIZE(self); ++ int result = PyByteArray_Resize((PyObject *)self, size); ++ if (result < 0) { ++ return NULL; ++ } ++ // Set new bytes to null bytes ++ if (size > start_size) { ++ memset(PyByteArray_AS_STRING(self) + start_size, 0, size - start_size); ++ } ++ Py_RETURN_NONE; ++} ++ ++ + /*[clinic input] + bytearray.translate + +@@ -2113,8 +2143,9 @@ + Return the number of bytes actually allocated."); + + static PyObject * +-bytearray_alloc(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored)) ++bytearray_alloc(PyObject *op, PyObject *Py_UNUSED(ignored)) + { ++ PyByteArrayObject *self = _PyByteArray_CAST(op); + return PyLong_FromSsize_t(self->ob_alloc); + } + +@@ -2313,7 +2344,7 @@ + }; + + static PyMethodDef bytearray_methods[] = { +- {"__alloc__", (PyCFunction)bytearray_alloc, METH_NOARGS, alloc_doc}, ++ {"__alloc__", bytearray_alloc, METH_NOARGS, alloc_doc}, + BYTEARRAY_REDUCE_METHODDEF + BYTEARRAY_REDUCE_EX_METHODDEF + BYTEARRAY_SIZEOF_METHODDEF +@@ -2360,6 +2391,7 @@ + BYTEARRAY_REPLACE_METHODDEF + BYTEARRAY_REMOVEPREFIX_METHODDEF + BYTEARRAY_REMOVESUFFIX_METHODDEF ++ BYTEARRAY_RESIZE_METHODDEF + BYTEARRAY_REVERSE_METHODDEF + BYTEARRAY_RFIND_METHODDEF + BYTEARRAY_RINDEX_METHODDEF +@@ -2464,24 +2496,29 @@ + PyByteArrayObject *it_seq; /* Set to NULL when iterator is exhausted */ + } bytesiterobject; + ++#define _bytesiterobject_CAST(op) ((bytesiterobject *)(op)) ++ + static void +-bytearrayiter_dealloc(bytesiterobject *it) ++bytearrayiter_dealloc(PyObject *self) + { ++ bytesiterobject *it = _bytesiterobject_CAST(self); + _PyObject_GC_UNTRACK(it); + Py_XDECREF(it->it_seq); + PyObject_GC_Del(it); + } + + static int +-bytearrayiter_traverse(bytesiterobject *it, visitproc visit, void *arg) ++bytearrayiter_traverse(PyObject *self, visitproc visit, void *arg) + { ++ bytesiterobject *it = _bytesiterobject_CAST(self); + Py_VISIT(it->it_seq); + return 0; + } + + static PyObject * +-bytearrayiter_next(bytesiterobject *it) ++bytearrayiter_next(PyObject *self) + { ++ bytesiterobject *it = _bytesiterobject_CAST(self); + PyByteArrayObject *seq; + + assert(it != NULL); +@@ -2501,8 +2538,9 @@ + } + + static PyObject * +-bytearrayiter_length_hint(bytesiterobject *it, PyObject *Py_UNUSED(ignored)) ++bytearrayiter_length_hint(PyObject *self, PyObject *Py_UNUSED(ignored)) + { ++ bytesiterobject *it = _bytesiterobject_CAST(self); + Py_ssize_t len = 0; + if (it->it_seq) { + len = PyByteArray_GET_SIZE(it->it_seq) - it->it_index; +@@ -2517,14 +2555,14 @@ + "Private method returning an estimate of len(list(it))."); + + static PyObject * +-bytearrayiter_reduce(bytesiterobject *it, PyObject *Py_UNUSED(ignored)) ++bytearrayiter_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *iter = _PyEval_GetBuiltin(&_Py_ID(iter)); + + /* _PyEval_GetBuiltin can invoke arbitrary code, + * call must be before access of iterator pointers. + * see issue #101765 */ +- ++ bytesiterobject *it = _bytesiterobject_CAST(self); + if (it->it_seq != NULL) { + return Py_BuildValue("N(O)n", iter, it->it_seq, it->it_index); + } else { +@@ -2533,11 +2571,13 @@ + } + + static PyObject * +-bytearrayiter_setstate(bytesiterobject *it, PyObject *state) ++bytearrayiter_setstate(PyObject *self, PyObject *state) + { + Py_ssize_t index = PyLong_AsSsize_t(state); + if (index == -1 && PyErr_Occurred()) + return NULL; ++ ++ bytesiterobject *it = _bytesiterobject_CAST(self); + if (it->it_seq != NULL) { + if (index < 0) + index = 0; +@@ -2551,11 +2591,11 @@ + PyDoc_STRVAR(setstate_doc, "Set state information for unpickling."); + + static PyMethodDef bytearrayiter_methods[] = { +- {"__length_hint__", (PyCFunction)bytearrayiter_length_hint, METH_NOARGS, ++ {"__length_hint__", bytearrayiter_length_hint, METH_NOARGS, + length_hint_doc}, +- {"__reduce__", (PyCFunction)bytearrayiter_reduce, METH_NOARGS, ++ {"__reduce__", bytearrayiter_reduce, METH_NOARGS, + bytearray_reduce__doc__}, +- {"__setstate__", (PyCFunction)bytearrayiter_setstate, METH_O, ++ {"__setstate__", bytearrayiter_setstate, METH_O, + setstate_doc}, + {NULL, NULL} /* sentinel */ + }; +@@ -2566,7 +2606,7 @@ + sizeof(bytesiterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ +- (destructor)bytearrayiter_dealloc, /* tp_dealloc */ ++ bytearrayiter_dealloc, /* tp_dealloc */ + 0, /* tp_vectorcall_offset */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ +@@ -2583,12 +2623,12 @@ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ +- (traverseproc)bytearrayiter_traverse, /* tp_traverse */ ++ bytearrayiter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ +- (iternextfunc)bytearrayiter_next, /* tp_iternext */ ++ bytearrayiter_next, /* tp_iternext */ + bytearrayiter_methods, /* tp_methods */ + 0, + }; +diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c +index 533089d25cd..b3d1c425ad1 100644 +--- a/Objects/bytesobject.c ++++ b/Objects/bytesobject.c +@@ -51,6 +51,33 @@ + } + + ++static inline void ++set_ob_shash(PyBytesObject *a, Py_hash_t hash) ++{ ++_Py_COMP_DIAG_PUSH ++_Py_COMP_DIAG_IGNORE_DEPR_DECLS ++#ifdef Py_GIL_DISABLED ++ _Py_atomic_store_ssize_relaxed(&a->ob_shash, hash); ++#else ++ a->ob_shash = hash; ++#endif ++_Py_COMP_DIAG_POP ++} ++ ++static inline Py_hash_t ++get_ob_shash(PyBytesObject *a) ++{ ++_Py_COMP_DIAG_PUSH ++_Py_COMP_DIAG_IGNORE_DEPR_DECLS ++#ifdef Py_GIL_DISABLED ++ return _Py_atomic_load_ssize_relaxed(&a->ob_shash); ++#else ++ return a->ob_shash; ++#endif ++_Py_COMP_DIAG_POP ++} ++ ++ + /* + For PyBytes_FromString(), the parameter 'str' points to a null-terminated + string containing exactly 'size' bytes. +@@ -98,10 +125,7 @@ + return PyErr_NoMemory(); + } + _PyObject_InitVar((PyVarObject*)op, &PyBytes_Type, size); +-_Py_COMP_DIAG_PUSH +-_Py_COMP_DIAG_IGNORE_DEPR_DECLS +- op->ob_shash = -1; +-_Py_COMP_DIAG_POP ++ set_ob_shash(op, -1); + if (!use_calloc) { + op->ob_sval[size] = '\0'; + } +@@ -165,10 +189,7 @@ + return PyErr_NoMemory(); + } + _PyObject_InitVar((PyVarObject*)op, &PyBytes_Type, size); +-_Py_COMP_DIAG_PUSH +-_Py_COMP_DIAG_IGNORE_DEPR_DECLS +- op->ob_shash = -1; +-_Py_COMP_DIAG_POP ++ set_ob_shash(op, -1); + memcpy(op->ob_sval, str, size+1); + return (PyObject *) op; + } +@@ -1184,7 +1205,8 @@ + unsigned char c = *first_invalid_escape; + if ('4' <= c && c <= '7') { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, +- "invalid octal escape sequence '\\%.3s'", ++ "b\"\\%.3s\" is an invalid octal escape sequence. " ++ "Such sequences will not work in the future. ", + first_invalid_escape) < 0) + { + Py_DECREF(result); +@@ -1193,7 +1215,8 @@ + } + else { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, +- "invalid escape sequence '\\%c'", ++ "b\"\\%c\" is an invalid escape sequence. " ++ "Such sequences will not work in the future. ", + c) < 0) + { + Py_DECREF(result); +@@ -1202,7 +1225,6 @@ + } + } + return result; +- + } + /* -------------------------------------------------------------------- */ + /* object api */ +@@ -1485,10 +1507,7 @@ + return PyErr_NoMemory(); + } + _PyObject_InitVar((PyVarObject*)op, &PyBytes_Type, size); +-_Py_COMP_DIAG_PUSH +-_Py_COMP_DIAG_IGNORE_DEPR_DECLS +- op->ob_shash = -1; +-_Py_COMP_DIAG_POP ++ set_ob_shash(op, -1); + op->ob_sval[size] = '\0'; + + _PyBytes_Repeat(op->ob_sval, size, a->ob_sval, Py_SIZE(a)); +@@ -1597,14 +1616,13 @@ + bytes_hash(PyObject *self) + { + PyBytesObject *a = _PyBytes_CAST(self); +-_Py_COMP_DIAG_PUSH +-_Py_COMP_DIAG_IGNORE_DEPR_DECLS +- if (a->ob_shash == -1) { ++ Py_hash_t hash = get_ob_shash(a); ++ if (hash == -1) { + /* Can't fail */ +- a->ob_shash = Py_HashBuffer(a->ob_sval, Py_SIZE(a)); ++ hash = Py_HashBuffer(a->ob_sval, Py_SIZE(a)); ++ set_ob_shash(a, hash); + } +- return a->ob_shash; +-_Py_COMP_DIAG_POP ++ return hash; + } + + static PyObject* +@@ -3004,10 +3022,7 @@ + if (obj == NULL) { + return NULL; + } +-_Py_COMP_DIAG_PUSH +-_Py_COMP_DIAG_IGNORE_DEPR_DECLS +- obj->ob_shash = -1; +-_Py_COMP_DIAG_POP ++ set_ob_shash(obj, -1); + return (PyObject*)obj; + } + +@@ -3024,11 +3039,8 @@ + if (pnew != NULL) { + memcpy(PyBytes_AS_STRING(pnew), + PyBytes_AS_STRING(tmp), n+1); +-_Py_COMP_DIAG_PUSH +-_Py_COMP_DIAG_IGNORE_DEPR_DECLS +- ((PyBytesObject *)pnew)->ob_shash = +- ((PyBytesObject *)tmp)->ob_shash; +-_Py_COMP_DIAG_POP ++ set_ob_shash((PyBytesObject *)pnew, ++ get_ob_shash((PyBytesObject *)tmp)); + } + return pnew; + } +@@ -3074,7 +3086,7 @@ + bytes_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ +- (richcmpfunc)bytes_richcompare, /* tp_richcompare */ ++ bytes_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + bytes_iter, /* tp_iter */ + 0, /* tp_iternext */ +@@ -3221,10 +3233,7 @@ + sv = (PyBytesObject *) *pv; + Py_SET_SIZE(sv, newsize); + sv->ob_sval[newsize] = '\0'; +-_Py_COMP_DIAG_PUSH +-_Py_COMP_DIAG_IGNORE_DEPR_DECLS +- sv->ob_shash = -1; /* invalidate cached hash value */ +-_Py_COMP_DIAG_POP ++ set_ob_shash(sv, -1); /* invalidate cached hash value */ + return 0; + } + +@@ -3237,24 +3246,29 @@ + PyBytesObject *it_seq; /* Set to NULL when iterator is exhausted */ + } striterobject; + ++#define _striterobject_CAST(op) ((striterobject *)(op)) ++ + static void +-striter_dealloc(striterobject *it) ++striter_dealloc(PyObject *op) + { ++ striterobject *it = _striterobject_CAST(op); + _PyObject_GC_UNTRACK(it); + Py_XDECREF(it->it_seq); + PyObject_GC_Del(it); + } + + static int +-striter_traverse(striterobject *it, visitproc visit, void *arg) ++striter_traverse(PyObject *op, visitproc visit, void *arg) + { ++ striterobject *it = _striterobject_CAST(op); + Py_VISIT(it->it_seq); + return 0; + } + + static PyObject * +-striter_next(striterobject *it) ++striter_next(PyObject *op) + { ++ striterobject *it = _striterobject_CAST(op); + PyBytesObject *seq; + + assert(it != NULL); +@@ -3274,8 +3288,9 @@ + } + + static PyObject * +-striter_len(striterobject *it, PyObject *Py_UNUSED(ignored)) ++striter_len(PyObject *op, PyObject *Py_UNUSED(ignored)) + { ++ striterobject *it = _striterobject_CAST(op); + Py_ssize_t len = 0; + if (it->it_seq) + len = PyBytes_GET_SIZE(it->it_seq) - it->it_index; +@@ -3286,14 +3301,14 @@ + "Private method returning an estimate of len(list(it))."); + + static PyObject * +-striter_reduce(striterobject *it, PyObject *Py_UNUSED(ignored)) ++striter_reduce(PyObject *op, PyObject *Py_UNUSED(ignored)) + { + PyObject *iter = _PyEval_GetBuiltin(&_Py_ID(iter)); + + /* _PyEval_GetBuiltin can invoke arbitrary code, + * call must be before access of iterator pointers. + * see issue #101765 */ +- ++ striterobject *it = _striterobject_CAST(op); + if (it->it_seq != NULL) { + return Py_BuildValue("N(O)n", iter, it->it_seq, it->it_index); + } else { +@@ -3304,11 +3319,12 @@ + PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); + + static PyObject * +-striter_setstate(striterobject *it, PyObject *state) ++striter_setstate(PyObject *op, PyObject *state) + { + Py_ssize_t index = PyLong_AsSsize_t(state); + if (index == -1 && PyErr_Occurred()) + return NULL; ++ striterobject *it = _striterobject_CAST(op); + if (it->it_seq != NULL) { + if (index < 0) + index = 0; +@@ -3322,12 +3338,9 @@ + PyDoc_STRVAR(setstate_doc, "Set state information for unpickling."); + + static PyMethodDef striter_methods[] = { +- {"__length_hint__", (PyCFunction)striter_len, METH_NOARGS, +- length_hint_doc}, +- {"__reduce__", (PyCFunction)striter_reduce, METH_NOARGS, +- reduce_doc}, +- {"__setstate__", (PyCFunction)striter_setstate, METH_O, +- setstate_doc}, ++ {"__length_hint__", striter_len, METH_NOARGS, length_hint_doc}, ++ {"__reduce__", striter_reduce, METH_NOARGS, reduce_doc}, ++ {"__setstate__", striter_setstate, METH_O, setstate_doc}, + {NULL, NULL} /* sentinel */ + }; + +@@ -3337,7 +3350,7 @@ + sizeof(striterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ +- (destructor)striter_dealloc, /* tp_dealloc */ ++ striter_dealloc, /* tp_dealloc */ + 0, /* tp_vectorcall_offset */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ +@@ -3354,12 +3367,12 @@ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + 0, /* tp_doc */ +- (traverseproc)striter_traverse, /* tp_traverse */ ++ striter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ +- (iternextfunc)striter_next, /* tp_iternext */ ++ striter_next, /* tp_iternext */ + striter_methods, /* tp_methods */ + 0, + }; +diff --git a/Objects/capsule.c b/Objects/capsule.c +index 28965e0f21b..16ae65905ef 100644 +--- a/Objects/capsule.c ++++ b/Objects/capsule.c +@@ -18,6 +18,8 @@ + } PyCapsule; + + ++#define _PyCapsule_CAST(op) ((PyCapsule *)(op)) ++ + + static int + _is_legal_capsule(PyObject *op, const char *invalid_capsule) +@@ -284,7 +286,7 @@ + static void + capsule_dealloc(PyObject *op) + { +- PyCapsule *capsule = (PyCapsule *)op; ++ PyCapsule *capsule = _PyCapsule_CAST(op); + PyObject_GC_UnTrack(op); + if (capsule->destructor) { + capsule->destructor(op); +@@ -296,7 +298,7 @@ + static PyObject * + capsule_repr(PyObject *o) + { +- PyCapsule *capsule = (PyCapsule *)o; ++ PyCapsule *capsule = _PyCapsule_CAST(o); + const char *name; + const char *quote; + +@@ -314,28 +316,27 @@ + + + static int +-capsule_traverse(PyCapsule *capsule, visitproc visit, void *arg) ++capsule_traverse(PyObject *self, visitproc visit, void *arg) + { + // Capsule object is only tracked by the GC + // if _PyCapsule_SetTraverse() is called, but + // this can still be manually triggered by gc.get_referents() +- ++ PyCapsule *capsule = _PyCapsule_CAST(self); + if (capsule->traverse_func != NULL) { +- return capsule->traverse_func((PyObject*)capsule, visit, arg); ++ return capsule->traverse_func(self, visit, arg); + } +- + return 0; + } + + + static int +-capsule_clear(PyCapsule *capsule) ++capsule_clear(PyObject *self) + { + // Capsule object is only tracked by the GC + // if _PyCapsule_SetTraverse() is called ++ PyCapsule *capsule = _PyCapsule_CAST(self); + assert(capsule->clear_func != NULL); +- +- return capsule->clear_func((PyObject*)capsule); ++ return capsule->clear_func(self); + } + + +@@ -358,8 +359,8 @@ + .tp_dealloc = capsule_dealloc, + .tp_repr = capsule_repr, + .tp_doc = PyCapsule_Type__doc__, +- .tp_traverse = (traverseproc)capsule_traverse, +- .tp_clear = (inquiry)capsule_clear, ++ .tp_traverse = capsule_traverse, ++ .tp_clear = capsule_clear, + }; + + +diff --git a/Objects/classobject.c b/Objects/classobject.c +index 775894ad5a7..58e1d179773 100644 +--- a/Objects/classobject.c ++++ b/Objects/classobject.c +@@ -3,6 +3,7 @@ + #include "Python.h" + #include "pycore_call.h" // _PyObject_VectorcallTstate() + #include "pycore_ceval.h" // _PyEval_GetBuiltin() ++#include "pycore_freelist.h" + #include "pycore_object.h" + #include "pycore_pyerrors.h" + #include "pycore_pystate.h" // _PyThreadState_GET() +@@ -112,9 +113,12 @@ + PyErr_BadInternalCall(); + return NULL; + } +- PyMethodObject *im = PyObject_GC_New(PyMethodObject, &PyMethod_Type); ++ PyMethodObject *im = _Py_FREELIST_POP(PyMethodObject, pymethodobjects); + if (im == NULL) { +- return NULL; ++ im = PyObject_GC_New(PyMethodObject, &PyMethod_Type); ++ if (im == NULL) { ++ return NULL; ++ } + } + im->im_weakreflist = NULL; + im->im_func = Py_NewRef(func); +@@ -245,7 +249,8 @@ + PyObject_ClearWeakRefs((PyObject *)im); + Py_DECREF(im->im_func); + Py_XDECREF(im->im_self); +- PyObject_GC_Del(im); ++ assert(Py_IS_TYPE(self, &PyMethod_Type)); ++ _Py_FREELIST_FREE(pymethodobjects, (PyObject *)im, PyObject_GC_Del); + } + + static PyObject * +diff --git a/Objects/clinic/bytearrayobject.c.h b/Objects/clinic/bytearrayobject.c.h +index dee7c1e8bff..03b5a8a516c 100644 +--- a/Objects/clinic/bytearrayobject.c.h ++++ b/Objects/clinic/bytearrayobject.c.h +@@ -123,7 +123,7 @@ + Py_ssize_t end); + + static PyObject * +-bytearray_find(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) ++bytearray_find(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *sub; +@@ -147,7 +147,7 @@ + goto exit; + } + skip_optional: +- return_value = bytearray_find_impl(self, sub, start, end); ++ return_value = bytearray_find_impl((PyByteArrayObject *)self, sub, start, end); + + exit: + return return_value; +@@ -172,7 +172,7 @@ + Py_ssize_t start, Py_ssize_t end); + + static PyObject * +-bytearray_count(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) ++bytearray_count(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *sub; +@@ -196,7 +196,7 @@ + goto exit; + } + skip_optional: +- return_value = bytearray_count_impl(self, sub, start, end); ++ return_value = bytearray_count_impl((PyByteArrayObject *)self, sub, start, end); + + exit: + return return_value; +@@ -215,9 +215,9 @@ + bytearray_clear_impl(PyByteArrayObject *self); + + static PyObject * +-bytearray_clear(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored)) ++bytearray_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return bytearray_clear_impl(self); ++ return bytearray_clear_impl((PyByteArrayObject *)self); + } + + PyDoc_STRVAR(bytearray_copy__doc__, +@@ -233,9 +233,9 @@ + bytearray_copy_impl(PyByteArrayObject *self); + + static PyObject * +-bytearray_copy(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored)) ++bytearray_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return bytearray_copy_impl(self); ++ return bytearray_copy_impl((PyByteArrayObject *)self); + } + + PyDoc_STRVAR(bytearray_index__doc__, +@@ -259,7 +259,7 @@ + Py_ssize_t start, Py_ssize_t end); + + static PyObject * +-bytearray_index(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) ++bytearray_index(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *sub; +@@ -283,7 +283,7 @@ + goto exit; + } + skip_optional: +- return_value = bytearray_index_impl(self, sub, start, end); ++ return_value = bytearray_index_impl((PyByteArrayObject *)self, sub, start, end); + + exit: + return return_value; +@@ -310,7 +310,7 @@ + Py_ssize_t start, Py_ssize_t end); + + static PyObject * +-bytearray_rfind(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) ++bytearray_rfind(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *sub; +@@ -334,7 +334,7 @@ + goto exit; + } + skip_optional: +- return_value = bytearray_rfind_impl(self, sub, start, end); ++ return_value = bytearray_rfind_impl((PyByteArrayObject *)self, sub, start, end); + + exit: + return return_value; +@@ -361,7 +361,7 @@ + Py_ssize_t start, Py_ssize_t end); + + static PyObject * +-bytearray_rindex(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) ++bytearray_rindex(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *sub; +@@ -385,7 +385,7 @@ + goto exit; + } + skip_optional: +- return_value = bytearray_rindex_impl(self, sub, start, end); ++ return_value = bytearray_rindex_impl((PyByteArrayObject *)self, sub, start, end); + + exit: + return return_value; +@@ -412,7 +412,7 @@ + Py_ssize_t start, Py_ssize_t end); + + static PyObject * +-bytearray_startswith(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) ++bytearray_startswith(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *subobj; +@@ -436,7 +436,7 @@ + goto exit; + } + skip_optional: +- return_value = bytearray_startswith_impl(self, subobj, start, end); ++ return_value = bytearray_startswith_impl((PyByteArrayObject *)self, subobj, start, end); + + exit: + return return_value; +@@ -463,7 +463,7 @@ + Py_ssize_t start, Py_ssize_t end); + + static PyObject * +-bytearray_endswith(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) ++bytearray_endswith(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *subobj; +@@ -487,7 +487,7 @@ + goto exit; + } + skip_optional: +- return_value = bytearray_endswith_impl(self, subobj, start, end); ++ return_value = bytearray_endswith_impl((PyByteArrayObject *)self, subobj, start, end); + + exit: + return return_value; +@@ -510,7 +510,7 @@ + bytearray_removeprefix_impl(PyByteArrayObject *self, Py_buffer *prefix); + + static PyObject * +-bytearray_removeprefix(PyByteArrayObject *self, PyObject *arg) ++bytearray_removeprefix(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + Py_buffer prefix = {NULL, NULL}; +@@ -518,7 +518,7 @@ + if (PyObject_GetBuffer(arg, &prefix, PyBUF_SIMPLE) != 0) { + goto exit; + } +- return_value = bytearray_removeprefix_impl(self, &prefix); ++ return_value = bytearray_removeprefix_impl((PyByteArrayObject *)self, &prefix); + + exit: + /* Cleanup for prefix */ +@@ -546,7 +546,7 @@ + bytearray_removesuffix_impl(PyByteArrayObject *self, Py_buffer *suffix); + + static PyObject * +-bytearray_removesuffix(PyByteArrayObject *self, PyObject *arg) ++bytearray_removesuffix(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + Py_buffer suffix = {NULL, NULL}; +@@ -554,7 +554,7 @@ + if (PyObject_GetBuffer(arg, &suffix, PyBUF_SIMPLE) != 0) { + goto exit; + } +- return_value = bytearray_removesuffix_impl(self, &suffix); ++ return_value = bytearray_removesuffix_impl((PyByteArrayObject *)self, &suffix); + + exit: + /* Cleanup for suffix */ +@@ -565,6 +565,45 @@ + return return_value; + } + ++PyDoc_STRVAR(bytearray_resize__doc__, ++"resize($self, size, /)\n" ++"--\n" ++"\n" ++"Resize the internal buffer of bytearray to len.\n" ++"\n" ++" size\n" ++" New size to resize to.."); ++ ++#define BYTEARRAY_RESIZE_METHODDEF \ ++ {"resize", (PyCFunction)bytearray_resize, METH_O, bytearray_resize__doc__}, ++ ++static PyObject * ++bytearray_resize_impl(PyByteArrayObject *self, Py_ssize_t size); ++ ++static PyObject * ++bytearray_resize(PyObject *self, PyObject *arg) ++{ ++ PyObject *return_value = NULL; ++ Py_ssize_t size; ++ ++ { ++ Py_ssize_t ival = -1; ++ PyObject *iobj = _PyNumber_Index(arg); ++ if (iobj != NULL) { ++ ival = PyLong_AsSsize_t(iobj); ++ Py_DECREF(iobj); ++ } ++ if (ival == -1 && PyErr_Occurred()) { ++ goto exit; ++ } ++ size = ival; ++ } ++ return_value = bytearray_resize_impl((PyByteArrayObject *)self, size); ++ ++exit: ++ return return_value; ++} ++ + PyDoc_STRVAR(bytearray_translate__doc__, + "translate($self, table, /, delete=b\'\')\n" + "--\n" +@@ -585,7 +624,7 @@ + PyObject *deletechars); + + static PyObject * +-bytearray_translate(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++bytearray_translate(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -629,7 +668,7 @@ + } + deletechars = args[1]; + skip_optional_pos: +- return_value = bytearray_translate_impl(self, table, deletechars); ++ return_value = bytearray_translate_impl((PyByteArrayObject *)self, table, deletechars); + + exit: + return return_value; +@@ -704,7 +743,7 @@ + Py_buffer *new, Py_ssize_t count); + + static PyObject * +-bytearray_replace(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) ++bytearray_replace(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + Py_buffer old = {NULL, NULL}; +@@ -736,7 +775,7 @@ + count = ival; + } + skip_optional: +- return_value = bytearray_replace_impl(self, &old, &new, count); ++ return_value = bytearray_replace_impl((PyByteArrayObject *)self, &old, &new, count); + + exit: + /* Cleanup for old */ +@@ -773,7 +812,7 @@ + Py_ssize_t maxsplit); + + static PyObject * +-bytearray_split(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++bytearray_split(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -833,7 +872,7 @@ + maxsplit = ival; + } + skip_optional_pos: +- return_value = bytearray_split_impl(self, sep, maxsplit); ++ return_value = bytearray_split_impl((PyByteArrayObject *)self, sep, maxsplit); + + exit: + return return_value; +@@ -896,7 +935,7 @@ + Py_ssize_t maxsplit); + + static PyObject * +-bytearray_rsplit(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++bytearray_rsplit(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -956,7 +995,7 @@ + maxsplit = ival; + } + skip_optional_pos: +- return_value = bytearray_rsplit_impl(self, sep, maxsplit); ++ return_value = bytearray_rsplit_impl((PyByteArrayObject *)self, sep, maxsplit); + + exit: + return return_value; +@@ -975,9 +1014,9 @@ + bytearray_reverse_impl(PyByteArrayObject *self); + + static PyObject * +-bytearray_reverse(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored)) ++bytearray_reverse(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return bytearray_reverse_impl(self); ++ return bytearray_reverse_impl((PyByteArrayObject *)self); + } + + PyDoc_STRVAR(bytearray_insert__doc__, +@@ -998,7 +1037,7 @@ + bytearray_insert_impl(PyByteArrayObject *self, Py_ssize_t index, int item); + + static PyObject * +-bytearray_insert(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) ++bytearray_insert(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + Py_ssize_t index; +@@ -1022,7 +1061,7 @@ + if (!_getbytevalue(args[1], &item)) { + goto exit; + } +- return_value = bytearray_insert_impl(self, index, item); ++ return_value = bytearray_insert_impl((PyByteArrayObject *)self, index, item); + + exit: + return return_value; +@@ -1044,7 +1083,7 @@ + bytearray_append_impl(PyByteArrayObject *self, int item); + + static PyObject * +-bytearray_append(PyByteArrayObject *self, PyObject *arg) ++bytearray_append(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + int item; +@@ -1052,7 +1091,7 @@ + if (!_getbytevalue(arg, &item)) { + goto exit; + } +- return_value = bytearray_append_impl(self, item); ++ return_value = bytearray_append_impl((PyByteArrayObject *)self, item); + + exit: + return return_value; +@@ -1089,7 +1128,7 @@ + bytearray_pop_impl(PyByteArrayObject *self, Py_ssize_t index); + + static PyObject * +-bytearray_pop(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) ++bytearray_pop(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + Py_ssize_t index = -1; +@@ -1113,7 +1152,7 @@ + index = ival; + } + skip_optional: +- return_value = bytearray_pop_impl(self, index); ++ return_value = bytearray_pop_impl((PyByteArrayObject *)self, index); + + exit: + return return_value; +@@ -1135,7 +1174,7 @@ + bytearray_remove_impl(PyByteArrayObject *self, int value); + + static PyObject * +-bytearray_remove(PyByteArrayObject *self, PyObject *arg) ++bytearray_remove(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + int value; +@@ -1143,7 +1182,7 @@ + if (!_getbytevalue(arg, &value)) { + goto exit; + } +- return_value = bytearray_remove_impl(self, value); ++ return_value = bytearray_remove_impl((PyByteArrayObject *)self, value); + + exit: + return return_value; +@@ -1164,7 +1203,7 @@ + bytearray_strip_impl(PyByteArrayObject *self, PyObject *bytes); + + static PyObject * +-bytearray_strip(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) ++bytearray_strip(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *bytes = Py_None; +@@ -1177,7 +1216,7 @@ + } + bytes = args[0]; + skip_optional: +- return_value = bytearray_strip_impl(self, bytes); ++ return_value = bytearray_strip_impl((PyByteArrayObject *)self, bytes); + + exit: + return return_value; +@@ -1198,7 +1237,7 @@ + bytearray_lstrip_impl(PyByteArrayObject *self, PyObject *bytes); + + static PyObject * +-bytearray_lstrip(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) ++bytearray_lstrip(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *bytes = Py_None; +@@ -1211,7 +1250,7 @@ + } + bytes = args[0]; + skip_optional: +- return_value = bytearray_lstrip_impl(self, bytes); ++ return_value = bytearray_lstrip_impl((PyByteArrayObject *)self, bytes); + + exit: + return return_value; +@@ -1232,7 +1271,7 @@ + bytearray_rstrip_impl(PyByteArrayObject *self, PyObject *bytes); + + static PyObject * +-bytearray_rstrip(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) ++bytearray_rstrip(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *bytes = Py_None; +@@ -1245,7 +1284,7 @@ + } + bytes = args[0]; + skip_optional: +- return_value = bytearray_rstrip_impl(self, bytes); ++ return_value = bytearray_rstrip_impl((PyByteArrayObject *)self, bytes); + + exit: + return return_value; +@@ -1274,7 +1313,7 @@ + const char *errors); + + static PyObject * +-bytearray_decode(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++bytearray_decode(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -1347,7 +1386,7 @@ + goto exit; + } + skip_optional_pos: +- return_value = bytearray_decode_impl(self, encoding, errors); ++ return_value = bytearray_decode_impl((PyByteArrayObject *)self, encoding, errors); + + exit: + return return_value; +@@ -1382,7 +1421,7 @@ + bytearray_splitlines_impl(PyByteArrayObject *self, int keepends); + + static PyObject * +-bytearray_splitlines(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++bytearray_splitlines(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -1427,7 +1466,7 @@ + goto exit; + } + skip_optional_pos: +- return_value = bytearray_splitlines_impl(self, keepends); ++ return_value = bytearray_splitlines_impl((PyByteArrayObject *)self, keepends); + + exit: + return return_value; +@@ -1495,7 +1534,7 @@ + bytearray_hex_impl(PyByteArrayObject *self, PyObject *sep, int bytes_per_sep); + + static PyObject * +-bytearray_hex(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++bytearray_hex(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -1547,7 +1586,7 @@ + goto exit; + } + skip_optional_pos: +- return_value = bytearray_hex_impl(self, sep, bytes_per_sep); ++ return_value = bytearray_hex_impl((PyByteArrayObject *)self, sep, bytes_per_sep); + + exit: + return return_value; +@@ -1566,9 +1605,9 @@ + bytearray_reduce_impl(PyByteArrayObject *self); + + static PyObject * +-bytearray_reduce(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored)) ++bytearray_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return bytearray_reduce_impl(self); ++ return bytearray_reduce_impl((PyByteArrayObject *)self); + } + + PyDoc_STRVAR(bytearray_reduce_ex__doc__, +@@ -1584,7 +1623,7 @@ + bytearray_reduce_ex_impl(PyByteArrayObject *self, int proto); + + static PyObject * +-bytearray_reduce_ex(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) ++bytearray_reduce_ex(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + int proto = 0; +@@ -1600,7 +1639,7 @@ + goto exit; + } + skip_optional: +- return_value = bytearray_reduce_ex_impl(self, proto); ++ return_value = bytearray_reduce_ex_impl((PyByteArrayObject *)self, proto); + + exit: + return return_value; +@@ -1619,8 +1658,8 @@ + bytearray_sizeof_impl(PyByteArrayObject *self); + + static PyObject * +-bytearray_sizeof(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored)) ++bytearray_sizeof(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return bytearray_sizeof_impl(self); ++ return bytearray_sizeof_impl((PyByteArrayObject *)self); + } +-/*[clinic end generated code: output=4488e38e7ffcc6ec input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=41bb67a8a181e733 input=a9049054013a1b77]*/ +diff --git a/Objects/clinic/bytesobject.c.h b/Objects/clinic/bytesobject.c.h +index d2c6cc88770..9aef736428a 100644 +--- a/Objects/clinic/bytesobject.c.h ++++ b/Objects/clinic/bytesobject.c.h +@@ -22,9 +22,9 @@ + bytes___bytes___impl(PyBytesObject *self); + + static PyObject * +-bytes___bytes__(PyBytesObject *self, PyObject *Py_UNUSED(ignored)) ++bytes___bytes__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return bytes___bytes___impl(self); ++ return bytes___bytes___impl((PyBytesObject *)self); + } + + PyDoc_STRVAR(bytes_split__doc__, +@@ -48,7 +48,7 @@ + bytes_split_impl(PyBytesObject *self, PyObject *sep, Py_ssize_t maxsplit); + + static PyObject * +-bytes_split(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++bytes_split(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -108,7 +108,7 @@ + maxsplit = ival; + } + skip_optional_pos: +- return_value = bytes_split_impl(self, sep, maxsplit); ++ return_value = bytes_split_impl((PyBytesObject *)self, sep, maxsplit); + + exit: + return return_value; +@@ -134,7 +134,7 @@ + bytes_partition_impl(PyBytesObject *self, Py_buffer *sep); + + static PyObject * +-bytes_partition(PyBytesObject *self, PyObject *arg) ++bytes_partition(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + Py_buffer sep = {NULL, NULL}; +@@ -142,7 +142,7 @@ + if (PyObject_GetBuffer(arg, &sep, PyBUF_SIMPLE) != 0) { + goto exit; + } +- return_value = bytes_partition_impl(self, &sep); ++ return_value = bytes_partition_impl((PyBytesObject *)self, &sep); + + exit: + /* Cleanup for sep */ +@@ -173,7 +173,7 @@ + bytes_rpartition_impl(PyBytesObject *self, Py_buffer *sep); + + static PyObject * +-bytes_rpartition(PyBytesObject *self, PyObject *arg) ++bytes_rpartition(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + Py_buffer sep = {NULL, NULL}; +@@ -181,7 +181,7 @@ + if (PyObject_GetBuffer(arg, &sep, PyBUF_SIMPLE) != 0) { + goto exit; + } +- return_value = bytes_rpartition_impl(self, &sep); ++ return_value = bytes_rpartition_impl((PyBytesObject *)self, &sep); + + exit: + /* Cleanup for sep */ +@@ -215,7 +215,7 @@ + bytes_rsplit_impl(PyBytesObject *self, PyObject *sep, Py_ssize_t maxsplit); + + static PyObject * +-bytes_rsplit(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++bytes_rsplit(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -275,7 +275,7 @@ + maxsplit = ival; + } + skip_optional_pos: +- return_value = bytes_rsplit_impl(self, sep, maxsplit); ++ return_value = bytes_rsplit_impl((PyBytesObject *)self, sep, maxsplit); + + exit: + return return_value; +@@ -317,7 +317,7 @@ + Py_ssize_t end); + + static PyObject * +-bytes_find(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs) ++bytes_find(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *sub; +@@ -341,7 +341,7 @@ + goto exit; + } + skip_optional: +- return_value = bytes_find_impl(self, sub, start, end); ++ return_value = bytes_find_impl((PyBytesObject *)self, sub, start, end); + + exit: + return return_value; +@@ -368,7 +368,7 @@ + Py_ssize_t end); + + static PyObject * +-bytes_index(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs) ++bytes_index(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *sub; +@@ -392,7 +392,7 @@ + goto exit; + } + skip_optional: +- return_value = bytes_index_impl(self, sub, start, end); ++ return_value = bytes_index_impl((PyBytesObject *)self, sub, start, end); + + exit: + return return_value; +@@ -419,7 +419,7 @@ + Py_ssize_t end); + + static PyObject * +-bytes_rfind(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs) ++bytes_rfind(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *sub; +@@ -443,7 +443,7 @@ + goto exit; + } + skip_optional: +- return_value = bytes_rfind_impl(self, sub, start, end); ++ return_value = bytes_rfind_impl((PyBytesObject *)self, sub, start, end); + + exit: + return return_value; +@@ -470,7 +470,7 @@ + Py_ssize_t end); + + static PyObject * +-bytes_rindex(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs) ++bytes_rindex(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *sub; +@@ -494,7 +494,7 @@ + goto exit; + } + skip_optional: +- return_value = bytes_rindex_impl(self, sub, start, end); ++ return_value = bytes_rindex_impl((PyBytesObject *)self, sub, start, end); + + exit: + return return_value; +@@ -515,7 +515,7 @@ + bytes_strip_impl(PyBytesObject *self, PyObject *bytes); + + static PyObject * +-bytes_strip(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs) ++bytes_strip(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *bytes = Py_None; +@@ -528,7 +528,7 @@ + } + bytes = args[0]; + skip_optional: +- return_value = bytes_strip_impl(self, bytes); ++ return_value = bytes_strip_impl((PyBytesObject *)self, bytes); + + exit: + return return_value; +@@ -549,7 +549,7 @@ + bytes_lstrip_impl(PyBytesObject *self, PyObject *bytes); + + static PyObject * +-bytes_lstrip(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs) ++bytes_lstrip(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *bytes = Py_None; +@@ -562,7 +562,7 @@ + } + bytes = args[0]; + skip_optional: +- return_value = bytes_lstrip_impl(self, bytes); ++ return_value = bytes_lstrip_impl((PyBytesObject *)self, bytes); + + exit: + return return_value; +@@ -583,7 +583,7 @@ + bytes_rstrip_impl(PyBytesObject *self, PyObject *bytes); + + static PyObject * +-bytes_rstrip(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs) ++bytes_rstrip(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *bytes = Py_None; +@@ -596,7 +596,7 @@ + } + bytes = args[0]; + skip_optional: +- return_value = bytes_rstrip_impl(self, bytes); ++ return_value = bytes_rstrip_impl((PyBytesObject *)self, bytes); + + exit: + return return_value; +@@ -621,7 +621,7 @@ + Py_ssize_t end); + + static PyObject * +-bytes_count(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs) ++bytes_count(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *sub; +@@ -645,7 +645,7 @@ + goto exit; + } + skip_optional: +- return_value = bytes_count_impl(self, sub, start, end); ++ return_value = bytes_count_impl((PyBytesObject *)self, sub, start, end); + + exit: + return return_value; +@@ -671,7 +671,7 @@ + PyObject *deletechars); + + static PyObject * +-bytes_translate(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++bytes_translate(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -715,7 +715,7 @@ + } + deletechars = args[1]; + skip_optional_pos: +- return_value = bytes_translate_impl(self, table, deletechars); ++ return_value = bytes_translate_impl((PyBytesObject *)self, table, deletechars); + + exit: + return return_value; +@@ -790,7 +790,7 @@ + Py_ssize_t count); + + static PyObject * +-bytes_replace(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs) ++bytes_replace(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + Py_buffer old = {NULL, NULL}; +@@ -822,7 +822,7 @@ + count = ival; + } + skip_optional: +- return_value = bytes_replace_impl(self, &old, &new, count); ++ return_value = bytes_replace_impl((PyBytesObject *)self, &old, &new, count); + + exit: + /* Cleanup for old */ +@@ -853,7 +853,7 @@ + bytes_removeprefix_impl(PyBytesObject *self, Py_buffer *prefix); + + static PyObject * +-bytes_removeprefix(PyBytesObject *self, PyObject *arg) ++bytes_removeprefix(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + Py_buffer prefix = {NULL, NULL}; +@@ -861,7 +861,7 @@ + if (PyObject_GetBuffer(arg, &prefix, PyBUF_SIMPLE) != 0) { + goto exit; + } +- return_value = bytes_removeprefix_impl(self, &prefix); ++ return_value = bytes_removeprefix_impl((PyBytesObject *)self, &prefix); + + exit: + /* Cleanup for prefix */ +@@ -889,7 +889,7 @@ + bytes_removesuffix_impl(PyBytesObject *self, Py_buffer *suffix); + + static PyObject * +-bytes_removesuffix(PyBytesObject *self, PyObject *arg) ++bytes_removesuffix(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + Py_buffer suffix = {NULL, NULL}; +@@ -897,7 +897,7 @@ + if (PyObject_GetBuffer(arg, &suffix, PyBUF_SIMPLE) != 0) { + goto exit; + } +- return_value = bytes_removesuffix_impl(self, &suffix); ++ return_value = bytes_removesuffix_impl((PyBytesObject *)self, &suffix); + + exit: + /* Cleanup for suffix */ +@@ -929,7 +929,7 @@ + Py_ssize_t start, Py_ssize_t end); + + static PyObject * +-bytes_startswith(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs) ++bytes_startswith(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *subobj; +@@ -953,7 +953,7 @@ + goto exit; + } + skip_optional: +- return_value = bytes_startswith_impl(self, subobj, start, end); ++ return_value = bytes_startswith_impl((PyBytesObject *)self, subobj, start, end); + + exit: + return return_value; +@@ -980,7 +980,7 @@ + Py_ssize_t end); + + static PyObject * +-bytes_endswith(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs) ++bytes_endswith(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *subobj; +@@ -1004,7 +1004,7 @@ + goto exit; + } + skip_optional: +- return_value = bytes_endswith_impl(self, subobj, start, end); ++ return_value = bytes_endswith_impl((PyBytesObject *)self, subobj, start, end); + + exit: + return return_value; +@@ -1033,7 +1033,7 @@ + const char *errors); + + static PyObject * +-bytes_decode(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++bytes_decode(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -1106,7 +1106,7 @@ + goto exit; + } + skip_optional_pos: +- return_value = bytes_decode_impl(self, encoding, errors); ++ return_value = bytes_decode_impl((PyBytesObject *)self, encoding, errors); + + exit: + return return_value; +@@ -1128,7 +1128,7 @@ + bytes_splitlines_impl(PyBytesObject *self, int keepends); + + static PyObject * +-bytes_splitlines(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++bytes_splitlines(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -1173,7 +1173,7 @@ + goto exit; + } + skip_optional_pos: +- return_value = bytes_splitlines_impl(self, keepends); ++ return_value = bytes_splitlines_impl((PyBytesObject *)self, keepends); + + exit: + return return_value; +@@ -1241,7 +1241,7 @@ + bytes_hex_impl(PyBytesObject *self, PyObject *sep, int bytes_per_sep); + + static PyObject * +-bytes_hex(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++bytes_hex(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -1293,7 +1293,7 @@ + goto exit; + } + skip_optional_pos: +- return_value = bytes_hex_impl(self, sep, bytes_per_sep); ++ return_value = bytes_hex_impl((PyBytesObject *)self, sep, bytes_per_sep); + + exit: + return return_value; +@@ -1391,4 +1391,4 @@ + exit: + return return_value; + } +-/*[clinic end generated code: output=fb7939a1983e463a input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=96fe2d6ef9ac8f6a input=a9049054013a1b77]*/ +diff --git a/Objects/clinic/classobject.c.h b/Objects/clinic/classobject.c.h +index 3e149c97324..5934f1c2a41 100644 +--- a/Objects/clinic/classobject.c.h ++++ b/Objects/clinic/classobject.c.h +@@ -16,9 +16,9 @@ + method___reduce___impl(PyMethodObject *self); + + static PyObject * +-method___reduce__(PyMethodObject *self, PyObject *Py_UNUSED(ignored)) ++method___reduce__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return method___reduce___impl(self); ++ return method___reduce___impl((PyMethodObject *)self); + } + + PyDoc_STRVAR(method_new__doc__, +@@ -82,4 +82,4 @@ + exit: + return return_value; + } +-/*[clinic end generated code: output=5a5e3f2d0726f189 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=ab546abf90aac94e input=a9049054013a1b77]*/ +diff --git a/Objects/clinic/codeobject.c.h b/Objects/clinic/codeobject.c.h +index 45738f767df..2184742cc0d 100644 +--- a/Objects/clinic/codeobject.c.h ++++ b/Objects/clinic/codeobject.c.h +@@ -174,7 +174,7 @@ + PyObject *co_exceptiontable); + + static PyObject * +-code_replace(PyCodeObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++code_replace(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -204,24 +204,24 @@ + #undef KWTUPLE + PyObject *argsbuf[18]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; +- int co_argcount = self->co_argcount; +- int co_posonlyargcount = self->co_posonlyargcount; +- int co_kwonlyargcount = self->co_kwonlyargcount; +- int co_nlocals = self->co_nlocals; +- int co_stacksize = self->co_stacksize; +- int co_flags = self->co_flags; +- int co_firstlineno = self->co_firstlineno; ++ int co_argcount = ((PyCodeObject *)self)->co_argcount; ++ int co_posonlyargcount = ((PyCodeObject *)self)->co_posonlyargcount; ++ int co_kwonlyargcount = ((PyCodeObject *)self)->co_kwonlyargcount; ++ int co_nlocals = ((PyCodeObject *)self)->co_nlocals; ++ int co_stacksize = ((PyCodeObject *)self)->co_stacksize; ++ int co_flags = ((PyCodeObject *)self)->co_flags; ++ int co_firstlineno = ((PyCodeObject *)self)->co_firstlineno; + PyObject *co_code = NULL; +- PyObject *co_consts = self->co_consts; +- PyObject *co_names = self->co_names; ++ PyObject *co_consts = ((PyCodeObject *)self)->co_consts; ++ PyObject *co_names = ((PyCodeObject *)self)->co_names; + PyObject *co_varnames = NULL; + PyObject *co_freevars = NULL; + PyObject *co_cellvars = NULL; +- PyObject *co_filename = self->co_filename; +- PyObject *co_name = self->co_name; +- PyObject *co_qualname = self->co_qualname; +- PyObject *co_linetable = self->co_linetable; +- PyObject *co_exceptiontable = self->co_exceptiontable; ++ PyObject *co_filename = ((PyCodeObject *)self)->co_filename; ++ PyObject *co_name = ((PyCodeObject *)self)->co_name; ++ PyObject *co_qualname = ((PyCodeObject *)self)->co_qualname; ++ PyObject *co_linetable = ((PyCodeObject *)self)->co_linetable; ++ PyObject *co_exceptiontable = ((PyCodeObject *)self)->co_exceptiontable; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 0, /*minkw*/ 0, /*varpos*/ 0, argsbuf); +@@ -400,7 +400,7 @@ + } + co_exceptiontable = args[17]; + skip_optional_kwonly: +- return_value = code_replace_impl(self, co_argcount, co_posonlyargcount, co_kwonlyargcount, co_nlocals, co_stacksize, co_flags, co_firstlineno, co_code, co_consts, co_names, co_varnames, co_freevars, co_cellvars, co_filename, co_name, co_qualname, co_linetable, co_exceptiontable); ++ return_value = code_replace_impl((PyCodeObject *)self, co_argcount, co_posonlyargcount, co_kwonlyargcount, co_nlocals, co_stacksize, co_flags, co_firstlineno, co_code, co_consts, co_names, co_varnames, co_freevars, co_cellvars, co_filename, co_name, co_qualname, co_linetable, co_exceptiontable); + + exit: + return return_value; +@@ -421,7 +421,7 @@ + code__varname_from_oparg_impl(PyCodeObject *self, int oparg); + + static PyObject * +-code__varname_from_oparg(PyCodeObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++code__varname_from_oparg(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -461,9 +461,9 @@ + if (oparg == -1 && PyErr_Occurred()) { + goto exit; + } +- return_value = code__varname_from_oparg_impl(self, oparg); ++ return_value = code__varname_from_oparg_impl((PyCodeObject *)self, oparg); + + exit: + return return_value; + } +-/*[clinic end generated code: output=e919ea67a1bcf524 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=73861c79e93aaee5 input=a9049054013a1b77]*/ +diff --git a/Objects/clinic/complexobject.c.h b/Objects/clinic/complexobject.c.h +index 3c3d1071b6e..e00da1d960c 100644 +--- a/Objects/clinic/complexobject.c.h ++++ b/Objects/clinic/complexobject.c.h +@@ -21,9 +21,9 @@ + complex_conjugate_impl(PyComplexObject *self); + + static PyObject * +-complex_conjugate(PyComplexObject *self, PyObject *Py_UNUSED(ignored)) ++complex_conjugate(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return complex_conjugate_impl(self); ++ return complex_conjugate_impl((PyComplexObject *)self); + } + + PyDoc_STRVAR(complex___getnewargs____doc__, +@@ -38,9 +38,9 @@ + complex___getnewargs___impl(PyComplexObject *self); + + static PyObject * +-complex___getnewargs__(PyComplexObject *self, PyObject *Py_UNUSED(ignored)) ++complex___getnewargs__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return complex___getnewargs___impl(self); ++ return complex___getnewargs___impl((PyComplexObject *)self); + } + + PyDoc_STRVAR(complex___format____doc__, +@@ -56,7 +56,7 @@ + complex___format___impl(PyComplexObject *self, PyObject *format_spec); + + static PyObject * +-complex___format__(PyComplexObject *self, PyObject *arg) ++complex___format__(PyObject *self, PyObject *arg) + { + PyObject *return_value = NULL; + PyObject *format_spec; +@@ -66,7 +66,7 @@ + goto exit; + } + format_spec = arg; +- return_value = complex___format___impl(self, format_spec); ++ return_value = complex___format___impl((PyComplexObject *)self, format_spec); + + exit: + return return_value; +@@ -85,9 +85,9 @@ + complex___complex___impl(PyComplexObject *self); + + static PyObject * +-complex___complex__(PyComplexObject *self, PyObject *Py_UNUSED(ignored)) ++complex___complex__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return complex___complex___impl(self); ++ return complex___complex___impl((PyComplexObject *)self); + } + + PyDoc_STRVAR(complex_new__doc__, +@@ -170,4 +170,4 @@ + + #define COMPLEX_FROM_NUMBER_METHODDEF \ + {"from_number", (PyCFunction)complex_from_number, METH_O|METH_CLASS, complex_from_number__doc__}, +-/*[clinic end generated code: output=8c49a41c5a7f0aee input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=252cddef7f9169a0 input=a9049054013a1b77]*/ +diff --git a/Objects/clinic/dictobject.c.h b/Objects/clinic/dictobject.c.h +index fb46c4c6433..c66916bb33a 100644 +--- a/Objects/clinic/dictobject.c.h ++++ b/Objects/clinic/dictobject.c.h +@@ -52,9 +52,9 @@ + dict_copy_impl(PyDictObject *self); + + static PyObject * +-dict_copy(PyDictObject *self, PyObject *Py_UNUSED(ignored)) ++dict_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return dict_copy_impl(self); ++ return dict_copy_impl((PyDictObject *)self); + } + + PyDoc_STRVAR(dict___contains____doc__, +@@ -79,7 +79,7 @@ + dict_get_impl(PyDictObject *self, PyObject *key, PyObject *default_value); + + static PyObject * +-dict_get(PyDictObject *self, PyObject *const *args, Py_ssize_t nargs) ++dict_get(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *key; +@@ -94,9 +94,7 @@ + } + default_value = args[1]; + skip_optional: +- Py_BEGIN_CRITICAL_SECTION(self); +- return_value = dict_get_impl(self, key, default_value); +- Py_END_CRITICAL_SECTION(); ++ return_value = dict_get_impl((PyDictObject *)self, key, default_value); + + exit: + return return_value; +@@ -118,7 +116,7 @@ + PyObject *default_value); + + static PyObject * +-dict_setdefault(PyDictObject *self, PyObject *const *args, Py_ssize_t nargs) ++dict_setdefault(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *key; +@@ -134,7 +132,7 @@ + default_value = args[1]; + skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = dict_setdefault_impl(self, key, default_value); ++ return_value = dict_setdefault_impl((PyDictObject *)self, key, default_value); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -154,9 +152,9 @@ + dict_clear_impl(PyDictObject *self); + + static PyObject * +-dict_clear(PyDictObject *self, PyObject *Py_UNUSED(ignored)) ++dict_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return dict_clear_impl(self); ++ return dict_clear_impl((PyDictObject *)self); + } + + PyDoc_STRVAR(dict_pop__doc__, +@@ -175,7 +173,7 @@ + dict_pop_impl(PyDictObject *self, PyObject *key, PyObject *default_value); + + static PyObject * +-dict_pop(PyDictObject *self, PyObject *const *args, Py_ssize_t nargs) ++dict_pop(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *key; +@@ -190,7 +188,7 @@ + } + default_value = args[1]; + skip_optional: +- return_value = dict_pop_impl(self, key, default_value); ++ return_value = dict_pop_impl((PyDictObject *)self, key, default_value); + + exit: + return return_value; +@@ -212,12 +210,12 @@ + dict_popitem_impl(PyDictObject *self); + + static PyObject * +-dict_popitem(PyDictObject *self, PyObject *Py_UNUSED(ignored)) ++dict_popitem(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = dict_popitem_impl(self); ++ return_value = dict_popitem_impl((PyDictObject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -236,9 +234,9 @@ + dict___sizeof___impl(PyDictObject *self); + + static PyObject * +-dict___sizeof__(PyDictObject *self, PyObject *Py_UNUSED(ignored)) ++dict___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return dict___sizeof___impl(self); ++ return dict___sizeof___impl((PyDictObject *)self); + } + + PyDoc_STRVAR(dict___reversed____doc__, +@@ -254,9 +252,9 @@ + dict___reversed___impl(PyDictObject *self); + + static PyObject * +-dict___reversed__(PyDictObject *self, PyObject *Py_UNUSED(ignored)) ++dict___reversed__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return dict___reversed___impl(self); ++ return dict___reversed___impl((PyDictObject *)self); + } + + PyDoc_STRVAR(dict_keys__doc__, +@@ -272,9 +270,9 @@ + dict_keys_impl(PyDictObject *self); + + static PyObject * +-dict_keys(PyDictObject *self, PyObject *Py_UNUSED(ignored)) ++dict_keys(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return dict_keys_impl(self); ++ return dict_keys_impl((PyDictObject *)self); + } + + PyDoc_STRVAR(dict_items__doc__, +@@ -290,9 +288,9 @@ + dict_items_impl(PyDictObject *self); + + static PyObject * +-dict_items(PyDictObject *self, PyObject *Py_UNUSED(ignored)) ++dict_items(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return dict_items_impl(self); ++ return dict_items_impl((PyDictObject *)self); + } + + PyDoc_STRVAR(dict_values__doc__, +@@ -308,8 +306,8 @@ + dict_values_impl(PyDictObject *self); + + static PyObject * +-dict_values(PyDictObject *self, PyObject *Py_UNUSED(ignored)) ++dict_values(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return dict_values_impl(self); ++ return dict_values_impl((PyDictObject *)self); + } +-/*[clinic end generated code: output=f3dd5f3fb8122aef input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=0f04bf0e7e6b130f input=a9049054013a1b77]*/ +--- /dev/null ++++ b/Objects/clinic/exceptions.c.h +@@ -0,0 +1,383 @@ ++/*[clinic input] ++preserve ++[clinic start generated code]*/ ++ ++#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() ++#include "pycore_modsupport.h" // _PyArg_BadArgument() ++ ++PyDoc_STRVAR(BaseException___reduce____doc__, ++"__reduce__($self, /)\n" ++"--\n" ++"\n"); ++ ++#define BASEEXCEPTION___REDUCE___METHODDEF \ ++ {"__reduce__", (PyCFunction)BaseException___reduce__, METH_NOARGS, BaseException___reduce____doc__}, ++ ++static PyObject * ++BaseException___reduce___impl(PyBaseExceptionObject *self); ++ ++static PyObject * ++BaseException___reduce__(PyObject *self, PyObject *Py_UNUSED(ignored)) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = BaseException___reduce___impl((PyBaseExceptionObject *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++PyDoc_STRVAR(BaseException___setstate____doc__, ++"__setstate__($self, state, /)\n" ++"--\n" ++"\n"); ++ ++#define BASEEXCEPTION___SETSTATE___METHODDEF \ ++ {"__setstate__", (PyCFunction)BaseException___setstate__, METH_O, BaseException___setstate____doc__}, ++ ++static PyObject * ++BaseException___setstate___impl(PyBaseExceptionObject *self, PyObject *state); ++ ++static PyObject * ++BaseException___setstate__(PyBaseExceptionObject *self, PyObject *state) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = BaseException___setstate___impl((PyBaseExceptionObject *)self, state); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++PyDoc_STRVAR(BaseException_with_traceback__doc__, ++"with_traceback($self, tb, /)\n" ++"--\n" ++"\n" ++"Set self.__traceback__ to tb and return self."); ++ ++#define BASEEXCEPTION_WITH_TRACEBACK_METHODDEF \ ++ {"with_traceback", (PyCFunction)BaseException_with_traceback, METH_O, BaseException_with_traceback__doc__}, ++ ++static PyObject * ++BaseException_with_traceback_impl(PyBaseExceptionObject *self, PyObject *tb); ++ ++static PyObject * ++BaseException_with_traceback(PyBaseExceptionObject *self, PyObject *tb) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = BaseException_with_traceback_impl((PyBaseExceptionObject *)self, tb); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++PyDoc_STRVAR(BaseException_add_note__doc__, ++"add_note($self, note, /)\n" ++"--\n" ++"\n" ++"Add a note to the exception"); ++ ++#define BASEEXCEPTION_ADD_NOTE_METHODDEF \ ++ {"add_note", (PyCFunction)BaseException_add_note, METH_O, BaseException_add_note__doc__}, ++ ++static PyObject * ++BaseException_add_note_impl(PyBaseExceptionObject *self, PyObject *note); ++ ++static PyObject * ++BaseException_add_note(PyObject *self, PyObject *arg) ++{ ++ PyObject *return_value = NULL; ++ PyObject *note; ++ ++ if (!PyUnicode_Check(arg)) { ++ _PyArg_BadArgument("add_note", "argument", "str", arg); ++ goto exit; ++ } ++ note = arg; ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = BaseException_add_note_impl((PyBaseExceptionObject *)self, note); ++ Py_END_CRITICAL_SECTION(); ++ ++exit: ++ return return_value; ++} ++ ++#if !defined(BaseException_args_DOCSTR) ++# define BaseException_args_DOCSTR NULL ++#endif ++#if defined(BASEEXCEPTION_ARGS_GETSETDEF) ++# undef BASEEXCEPTION_ARGS_GETSETDEF ++# define BASEEXCEPTION_ARGS_GETSETDEF {"args", (getter)BaseException_args_get, (setter)BaseException_args_set, BaseException_args_DOCSTR}, ++#else ++# define BASEEXCEPTION_ARGS_GETSETDEF {"args", (getter)BaseException_args_get, NULL, BaseException_args_DOCSTR}, ++#endif ++ ++static PyObject * ++BaseException_args_get_impl(PyBaseExceptionObject *self); ++ ++static PyObject * ++BaseException_args_get(PyObject *self, void *Py_UNUSED(context)) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = BaseException_args_get_impl((PyBaseExceptionObject *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(BaseException_args_DOCSTR) ++# define BaseException_args_DOCSTR NULL ++#endif ++#if defined(BASEEXCEPTION_ARGS_GETSETDEF) ++# undef BASEEXCEPTION_ARGS_GETSETDEF ++# define BASEEXCEPTION_ARGS_GETSETDEF {"args", (getter)BaseException_args_get, (setter)BaseException_args_set, BaseException_args_DOCSTR}, ++#else ++# define BASEEXCEPTION_ARGS_GETSETDEF {"args", NULL, (setter)BaseException_args_set, NULL}, ++#endif ++ ++static int ++BaseException_args_set_impl(PyBaseExceptionObject *self, PyObject *value); ++ ++static int ++BaseException_args_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) ++{ ++ int return_value; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = BaseException_args_set_impl((PyBaseExceptionObject *)self, value); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(BaseException___traceback___DOCSTR) ++# define BaseException___traceback___DOCSTR NULL ++#endif ++#if defined(BASEEXCEPTION___TRACEBACK___GETSETDEF) ++# undef BASEEXCEPTION___TRACEBACK___GETSETDEF ++# define BASEEXCEPTION___TRACEBACK___GETSETDEF {"__traceback__", (getter)BaseException___traceback___get, (setter)BaseException___traceback___set, BaseException___traceback___DOCSTR}, ++#else ++# define BASEEXCEPTION___TRACEBACK___GETSETDEF {"__traceback__", (getter)BaseException___traceback___get, NULL, BaseException___traceback___DOCSTR}, ++#endif ++ ++static PyObject * ++BaseException___traceback___get_impl(PyBaseExceptionObject *self); ++ ++static PyObject * ++BaseException___traceback___get(PyObject *self, void *Py_UNUSED(context)) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = BaseException___traceback___get_impl((PyBaseExceptionObject *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(BaseException___traceback___DOCSTR) ++# define BaseException___traceback___DOCSTR NULL ++#endif ++#if defined(BASEEXCEPTION___TRACEBACK___GETSETDEF) ++# undef BASEEXCEPTION___TRACEBACK___GETSETDEF ++# define BASEEXCEPTION___TRACEBACK___GETSETDEF {"__traceback__", (getter)BaseException___traceback___get, (setter)BaseException___traceback___set, BaseException___traceback___DOCSTR}, ++#else ++# define BASEEXCEPTION___TRACEBACK___GETSETDEF {"__traceback__", NULL, (setter)BaseException___traceback___set, NULL}, ++#endif ++ ++static int ++BaseException___traceback___set_impl(PyBaseExceptionObject *self, ++ PyObject *value); ++ ++static int ++BaseException___traceback___set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) ++{ ++ int return_value; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = BaseException___traceback___set_impl((PyBaseExceptionObject *)self, value); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(BaseException___context___DOCSTR) ++# define BaseException___context___DOCSTR NULL ++#endif ++#if defined(BASEEXCEPTION___CONTEXT___GETSETDEF) ++# undef BASEEXCEPTION___CONTEXT___GETSETDEF ++# define BASEEXCEPTION___CONTEXT___GETSETDEF {"__context__", (getter)BaseException___context___get, (setter)BaseException___context___set, BaseException___context___DOCSTR}, ++#else ++# define BASEEXCEPTION___CONTEXT___GETSETDEF {"__context__", (getter)BaseException___context___get, NULL, BaseException___context___DOCSTR}, ++#endif ++ ++static PyObject * ++BaseException___context___get_impl(PyBaseExceptionObject *self); ++ ++static PyObject * ++BaseException___context___get(PyObject *self, void *Py_UNUSED(context)) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = BaseException___context___get_impl((PyBaseExceptionObject *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(BaseException___context___DOCSTR) ++# define BaseException___context___DOCSTR NULL ++#endif ++#if defined(BASEEXCEPTION___CONTEXT___GETSETDEF) ++# undef BASEEXCEPTION___CONTEXT___GETSETDEF ++# define BASEEXCEPTION___CONTEXT___GETSETDEF {"__context__", (getter)BaseException___context___get, (setter)BaseException___context___set, BaseException___context___DOCSTR}, ++#else ++# define BASEEXCEPTION___CONTEXT___GETSETDEF {"__context__", NULL, (setter)BaseException___context___set, NULL}, ++#endif ++ ++static int ++BaseException___context___set_impl(PyBaseExceptionObject *self, ++ PyObject *value); ++ ++static int ++BaseException___context___set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) ++{ ++ int return_value; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = BaseException___context___set_impl((PyBaseExceptionObject *)self, value); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(BaseException___cause___DOCSTR) ++# define BaseException___cause___DOCSTR NULL ++#endif ++#if defined(BASEEXCEPTION___CAUSE___GETSETDEF) ++# undef BASEEXCEPTION___CAUSE___GETSETDEF ++# define BASEEXCEPTION___CAUSE___GETSETDEF {"__cause__", (getter)BaseException___cause___get, (setter)BaseException___cause___set, BaseException___cause___DOCSTR}, ++#else ++# define BASEEXCEPTION___CAUSE___GETSETDEF {"__cause__", (getter)BaseException___cause___get, NULL, BaseException___cause___DOCSTR}, ++#endif ++ ++static PyObject * ++BaseException___cause___get_impl(PyBaseExceptionObject *self); ++ ++static PyObject * ++BaseException___cause___get(PyObject *self, void *Py_UNUSED(context)) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = BaseException___cause___get_impl((PyBaseExceptionObject *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(BaseException___cause___DOCSTR) ++# define BaseException___cause___DOCSTR NULL ++#endif ++#if defined(BASEEXCEPTION___CAUSE___GETSETDEF) ++# undef BASEEXCEPTION___CAUSE___GETSETDEF ++# define BASEEXCEPTION___CAUSE___GETSETDEF {"__cause__", (getter)BaseException___cause___get, (setter)BaseException___cause___set, BaseException___cause___DOCSTR}, ++#else ++# define BASEEXCEPTION___CAUSE___GETSETDEF {"__cause__", NULL, (setter)BaseException___cause___set, NULL}, ++#endif ++ ++static int ++BaseException___cause___set_impl(PyBaseExceptionObject *self, ++ PyObject *value); ++ ++static int ++BaseException___cause___set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) ++{ ++ int return_value; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = BaseException___cause___set_impl((PyBaseExceptionObject *)self, value); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++PyDoc_STRVAR(BaseExceptionGroup_derive__doc__, ++"derive($self, excs, /)\n" ++"--\n" ++"\n"); ++ ++#define BASEEXCEPTIONGROUP_DERIVE_METHODDEF \ ++ {"derive", (PyCFunction)BaseExceptionGroup_derive, METH_O, BaseExceptionGroup_derive__doc__}, ++ ++static PyObject * ++BaseExceptionGroup_derive_impl(PyBaseExceptionGroupObject *self, ++ PyObject *excs); ++ ++static PyObject * ++BaseExceptionGroup_derive(PyBaseExceptionGroupObject *self, PyObject *excs) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = BaseExceptionGroup_derive_impl((PyBaseExceptionGroupObject *)self, excs); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++PyDoc_STRVAR(BaseExceptionGroup_split__doc__, ++"split($self, matcher_value, /)\n" ++"--\n" ++"\n"); ++ ++#define BASEEXCEPTIONGROUP_SPLIT_METHODDEF \ ++ {"split", (PyCFunction)BaseExceptionGroup_split, METH_O, BaseExceptionGroup_split__doc__}, ++ ++static PyObject * ++BaseExceptionGroup_split_impl(PyBaseExceptionGroupObject *self, ++ PyObject *matcher_value); ++ ++static PyObject * ++BaseExceptionGroup_split(PyBaseExceptionGroupObject *self, PyObject *matcher_value) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = BaseExceptionGroup_split_impl((PyBaseExceptionGroupObject *)self, matcher_value); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++PyDoc_STRVAR(BaseExceptionGroup_subgroup__doc__, ++"subgroup($self, matcher_value, /)\n" ++"--\n" ++"\n"); ++ ++#define BASEEXCEPTIONGROUP_SUBGROUP_METHODDEF \ ++ {"subgroup", (PyCFunction)BaseExceptionGroup_subgroup, METH_O, BaseExceptionGroup_subgroup__doc__}, ++ ++static PyObject * ++BaseExceptionGroup_subgroup_impl(PyBaseExceptionGroupObject *self, ++ PyObject *matcher_value); ++ ++static PyObject * ++BaseExceptionGroup_subgroup(PyBaseExceptionGroupObject *self, PyObject *matcher_value) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = BaseExceptionGroup_subgroup_impl((PyBaseExceptionGroupObject *)self, matcher_value); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++/*[clinic end generated code: output=19aed708dcaf7184 input=a9049054013a1b77]*/ +diff --git a/Objects/clinic/funcobject.c.h b/Objects/clinic/funcobject.c.h +index 3f95a1db7b2..efc579dc259 100644 +--- a/Objects/clinic/funcobject.c.h ++++ b/Objects/clinic/funcobject.c.h +@@ -6,8 +6,180 @@ + # include "pycore_gc.h" // PyGC_Head + # include "pycore_runtime.h" // _Py_ID() + #endif ++#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() + #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() + ++PyDoc_STRVAR(function___annotate____doc__, ++"Get the code object for a function."); ++#if defined(function___annotate___DOCSTR) ++# undef function___annotate___DOCSTR ++#endif ++#define function___annotate___DOCSTR function___annotate____doc__ ++ ++#if !defined(function___annotate___DOCSTR) ++# define function___annotate___DOCSTR NULL ++#endif ++#if defined(FUNCTION___ANNOTATE___GETSETDEF) ++# undef FUNCTION___ANNOTATE___GETSETDEF ++# define FUNCTION___ANNOTATE___GETSETDEF {"__annotate__", (getter)function___annotate___get, (setter)function___annotate___set, function___annotate___DOCSTR}, ++#else ++# define FUNCTION___ANNOTATE___GETSETDEF {"__annotate__", (getter)function___annotate___get, NULL, function___annotate___DOCSTR}, ++#endif ++ ++static PyObject * ++function___annotate___get_impl(PyFunctionObject *self); ++ ++static PyObject * ++function___annotate___get(PyObject *self, void *Py_UNUSED(context)) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = function___annotate___get_impl((PyFunctionObject *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(function___annotate___DOCSTR) ++# define function___annotate___DOCSTR NULL ++#endif ++#if defined(FUNCTION___ANNOTATE___GETSETDEF) ++# undef FUNCTION___ANNOTATE___GETSETDEF ++# define FUNCTION___ANNOTATE___GETSETDEF {"__annotate__", (getter)function___annotate___get, (setter)function___annotate___set, function___annotate___DOCSTR}, ++#else ++# define FUNCTION___ANNOTATE___GETSETDEF {"__annotate__", NULL, (setter)function___annotate___set, NULL}, ++#endif ++ ++static int ++function___annotate___set_impl(PyFunctionObject *self, PyObject *value); ++ ++static int ++function___annotate___set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) ++{ ++ int return_value; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = function___annotate___set_impl((PyFunctionObject *)self, value); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++PyDoc_STRVAR(function___annotations____doc__, ++"Dict of annotations in a function object."); ++#if defined(function___annotations___DOCSTR) ++# undef function___annotations___DOCSTR ++#endif ++#define function___annotations___DOCSTR function___annotations____doc__ ++ ++#if !defined(function___annotations___DOCSTR) ++# define function___annotations___DOCSTR NULL ++#endif ++#if defined(FUNCTION___ANNOTATIONS___GETSETDEF) ++# undef FUNCTION___ANNOTATIONS___GETSETDEF ++# define FUNCTION___ANNOTATIONS___GETSETDEF {"__annotations__", (getter)function___annotations___get, (setter)function___annotations___set, function___annotations___DOCSTR}, ++#else ++# define FUNCTION___ANNOTATIONS___GETSETDEF {"__annotations__", (getter)function___annotations___get, NULL, function___annotations___DOCSTR}, ++#endif ++ ++static PyObject * ++function___annotations___get_impl(PyFunctionObject *self); ++ ++static PyObject * ++function___annotations___get(PyObject *self, void *Py_UNUSED(context)) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = function___annotations___get_impl((PyFunctionObject *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(function___annotations___DOCSTR) ++# define function___annotations___DOCSTR NULL ++#endif ++#if defined(FUNCTION___ANNOTATIONS___GETSETDEF) ++# undef FUNCTION___ANNOTATIONS___GETSETDEF ++# define FUNCTION___ANNOTATIONS___GETSETDEF {"__annotations__", (getter)function___annotations___get, (setter)function___annotations___set, function___annotations___DOCSTR}, ++#else ++# define FUNCTION___ANNOTATIONS___GETSETDEF {"__annotations__", NULL, (setter)function___annotations___set, NULL}, ++#endif ++ ++static int ++function___annotations___set_impl(PyFunctionObject *self, PyObject *value); ++ ++static int ++function___annotations___set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) ++{ ++ int return_value; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = function___annotations___set_impl((PyFunctionObject *)self, value); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++PyDoc_STRVAR(function___type_params____doc__, ++"Get the declared type parameters for a function."); ++#if defined(function___type_params___DOCSTR) ++# undef function___type_params___DOCSTR ++#endif ++#define function___type_params___DOCSTR function___type_params____doc__ ++ ++#if !defined(function___type_params___DOCSTR) ++# define function___type_params___DOCSTR NULL ++#endif ++#if defined(FUNCTION___TYPE_PARAMS___GETSETDEF) ++# undef FUNCTION___TYPE_PARAMS___GETSETDEF ++# define FUNCTION___TYPE_PARAMS___GETSETDEF {"__type_params__", (getter)function___type_params___get, (setter)function___type_params___set, function___type_params___DOCSTR}, ++#else ++# define FUNCTION___TYPE_PARAMS___GETSETDEF {"__type_params__", (getter)function___type_params___get, NULL, function___type_params___DOCSTR}, ++#endif ++ ++static PyObject * ++function___type_params___get_impl(PyFunctionObject *self); ++ ++static PyObject * ++function___type_params___get(PyObject *self, void *Py_UNUSED(context)) ++{ ++ PyObject *return_value = NULL; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = function___type_params___get_impl((PyFunctionObject *)self); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ ++#if !defined(function___type_params___DOCSTR) ++# define function___type_params___DOCSTR NULL ++#endif ++#if defined(FUNCTION___TYPE_PARAMS___GETSETDEF) ++# undef FUNCTION___TYPE_PARAMS___GETSETDEF ++# define FUNCTION___TYPE_PARAMS___GETSETDEF {"__type_params__", (getter)function___type_params___get, (setter)function___type_params___set, function___type_params___DOCSTR}, ++#else ++# define FUNCTION___TYPE_PARAMS___GETSETDEF {"__type_params__", NULL, (setter)function___type_params___set, NULL}, ++#endif ++ ++static int ++function___type_params___set_impl(PyFunctionObject *self, PyObject *value); ++ ++static int ++function___type_params___set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) ++{ ++ int return_value; ++ ++ Py_BEGIN_CRITICAL_SECTION(self); ++ return_value = function___type_params___set_impl((PyFunctionObject *)self, value); ++ Py_END_CRITICAL_SECTION(); ++ ++ return return_value; ++} ++ + PyDoc_STRVAR(func_new__doc__, + "function(code, globals, name=None, argdefs=None, closure=None,\n" + " kwdefaults=None)\n" +@@ -116,4 +288,4 @@ + exit: + return return_value; + } +-/*[clinic end generated code: output=bad4e19757dd26c3 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=3cdce22867efe617 input=a9049054013a1b77]*/ +diff --git a/Objects/clinic/listobject.c.h b/Objects/clinic/listobject.c.h +index 975f253c096..a29ed9f7088 100644 +--- a/Objects/clinic/listobject.c.h ++++ b/Objects/clinic/listobject.c.h +@@ -23,7 +23,7 @@ + list_insert_impl(PyListObject *self, Py_ssize_t index, PyObject *object); + + static PyObject * +-list_insert(PyListObject *self, PyObject *const *args, Py_ssize_t nargs) ++list_insert(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + Py_ssize_t index; +@@ -46,7 +46,7 @@ + } + object = args[1]; + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = list_insert_impl(self, index, object); ++ return_value = list_insert_impl((PyListObject *)self, index, object); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -66,12 +66,12 @@ + py_list_clear_impl(PyListObject *self); + + static PyObject * +-py_list_clear(PyListObject *self, PyObject *Py_UNUSED(ignored)) ++py_list_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = py_list_clear_impl(self); ++ return_value = py_list_clear_impl((PyListObject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -90,12 +90,12 @@ + list_copy_impl(PyListObject *self); + + static PyObject * +-list_copy(PyListObject *self, PyObject *Py_UNUSED(ignored)) ++list_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = list_copy_impl(self); ++ return_value = list_copy_impl((PyListObject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -119,7 +119,7 @@ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = list_append_impl(self, object); ++ return_value = list_append_impl((PyListObject *)self, object); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -149,7 +149,7 @@ + list_pop_impl(PyListObject *self, Py_ssize_t index); + + static PyObject * +-list_pop(PyListObject *self, PyObject *const *args, Py_ssize_t nargs) ++list_pop(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + Py_ssize_t index = -1; +@@ -174,7 +174,7 @@ + } + skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = list_pop_impl(self, index); ++ return_value = list_pop_impl((PyListObject *)self, index); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -202,7 +202,7 @@ + list_sort_impl(PyListObject *self, PyObject *keyfunc, int reverse); + + static PyObject * +-list_sort(PyListObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++list_sort(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -255,7 +255,7 @@ + } + skip_optional_kwonly: + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = list_sort_impl(self, keyfunc, reverse); ++ return_value = list_sort_impl((PyListObject *)self, keyfunc, reverse); + Py_END_CRITICAL_SECTION(); + + exit: +@@ -275,12 +275,12 @@ + list_reverse_impl(PyListObject *self); + + static PyObject * +-list_reverse(PyListObject *self, PyObject *Py_UNUSED(ignored)) ++list_reverse(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = list_reverse_impl(self); ++ return_value = list_reverse_impl((PyListObject *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -302,7 +302,7 @@ + Py_ssize_t stop); + + static PyObject * +-list_index(PyListObject *self, PyObject *const *args, Py_ssize_t nargs) ++list_index(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *value; +@@ -326,7 +326,7 @@ + goto exit; + } + skip_optional: +- return_value = list_index_impl(self, value, start, stop); ++ return_value = list_index_impl((PyListObject *)self, value, start, stop); + + exit: + return return_value; +@@ -361,7 +361,7 @@ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); +- return_value = list_remove_impl(self, value); ++ return_value = list_remove_impl((PyListObject *)self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -418,9 +418,9 @@ + list___sizeof___impl(PyListObject *self); + + static PyObject * +-list___sizeof__(PyListObject *self, PyObject *Py_UNUSED(ignored)) ++list___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return list___sizeof___impl(self); ++ return list___sizeof___impl((PyListObject *)self); + } + + PyDoc_STRVAR(list___reversed____doc__, +@@ -436,8 +436,8 @@ + list___reversed___impl(PyListObject *self); + + static PyObject * +-list___reversed__(PyListObject *self, PyObject *Py_UNUSED(ignored)) ++list___reversed__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return list___reversed___impl(self); ++ return list___reversed___impl((PyListObject *)self); + } +-/*[clinic end generated code: output=9357151278d77ea1 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=35c43dc33f9ba521 input=a9049054013a1b77]*/ +diff --git a/Objects/clinic/memoryobject.c.h b/Objects/clinic/memoryobject.c.h +index a6cf1f431a1..4706c920519 100644 +--- a/Objects/clinic/memoryobject.c.h ++++ b/Objects/clinic/memoryobject.c.h +@@ -137,9 +137,9 @@ + memoryview_release_impl(PyMemoryViewObject *self); + + static PyObject * +-memoryview_release(PyMemoryViewObject *self, PyObject *Py_UNUSED(ignored)) ++memoryview_release(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return memoryview_release_impl(self); ++ return memoryview_release_impl((PyMemoryViewObject *)self); + } + + PyDoc_STRVAR(memoryview_cast__doc__, +@@ -156,7 +156,7 @@ + PyObject *shape); + + static PyObject * +-memoryview_cast(PyMemoryViewObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++memoryview_cast(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -204,7 +204,7 @@ + } + shape = args[1]; + skip_optional_pos: +- return_value = memoryview_cast_impl(self, format, shape); ++ return_value = memoryview_cast_impl((PyMemoryViewObject *)self, format, shape); + + exit: + return return_value; +@@ -223,9 +223,9 @@ + memoryview_toreadonly_impl(PyMemoryViewObject *self); + + static PyObject * +-memoryview_toreadonly(PyMemoryViewObject *self, PyObject *Py_UNUSED(ignored)) ++memoryview_toreadonly(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return memoryview_toreadonly_impl(self); ++ return memoryview_toreadonly_impl((PyMemoryViewObject *)self); + } + + PyDoc_STRVAR(memoryview_tolist__doc__, +@@ -241,9 +241,9 @@ + memoryview_tolist_impl(PyMemoryViewObject *self); + + static PyObject * +-memoryview_tolist(PyMemoryViewObject *self, PyObject *Py_UNUSED(ignored)) ++memoryview_tolist(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return memoryview_tolist_impl(self); ++ return memoryview_tolist_impl((PyMemoryViewObject *)self); + } + + PyDoc_STRVAR(memoryview_tobytes__doc__, +@@ -265,7 +265,7 @@ + memoryview_tobytes_impl(PyMemoryViewObject *self, const char *order); + + static PyObject * +-memoryview_tobytes(PyMemoryViewObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++memoryview_tobytes(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -324,7 +324,7 @@ + goto exit; + } + skip_optional_pos: +- return_value = memoryview_tobytes_impl(self, order); ++ return_value = memoryview_tobytes_impl((PyMemoryViewObject *)self, order); + + exit: + return return_value; +@@ -361,7 +361,7 @@ + int bytes_per_sep); + + static PyObject * +-memoryview_hex(PyMemoryViewObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++memoryview_hex(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -413,7 +413,7 @@ + goto exit; + } + skip_optional_pos: +- return_value = memoryview_hex_impl(self, sep, bytes_per_sep); ++ return_value = memoryview_hex_impl((PyMemoryViewObject *)self, sep, bytes_per_sep); + + exit: + return return_value; +@@ -444,7 +444,7 @@ + Py_ssize_t start, Py_ssize_t stop); + + static PyObject * +-memoryview_index(PyMemoryViewObject *self, PyObject *const *args, Py_ssize_t nargs) ++memoryview_index(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *value; +@@ -468,9 +468,9 @@ + goto exit; + } + skip_optional: +- return_value = memoryview_index_impl(self, value, start, stop); ++ return_value = memoryview_index_impl((PyMemoryViewObject *)self, value, start, stop); + + exit: + return return_value; + } +-/*[clinic end generated code: output=132893ef5f67ad73 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=2ef6c061d9c4e3dc input=a9049054013a1b77]*/ +diff --git a/Objects/clinic/odictobject.c.h b/Objects/clinic/odictobject.c.h +index 4b97596e5db..44d89c4e0ef 100644 +--- a/Objects/clinic/odictobject.c.h ++++ b/Objects/clinic/odictobject.c.h +@@ -87,7 +87,7 @@ + PyObject *default_value); + + static PyObject * +-OrderedDict_setdefault(PyODictObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++OrderedDict_setdefault(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -131,7 +131,7 @@ + } + default_value = args[1]; + skip_optional_pos: +- return_value = OrderedDict_setdefault_impl(self, key, default_value); ++ return_value = OrderedDict_setdefault_impl((PyODictObject *)self, key, default_value); + + exit: + return return_value; +@@ -154,7 +154,7 @@ + PyObject *default_value); + + static PyObject * +-OrderedDict_pop(PyODictObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++OrderedDict_pop(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -198,7 +198,7 @@ + } + default_value = args[1]; + skip_optional_pos: +- return_value = OrderedDict_pop_impl(self, key, default_value); ++ return_value = OrderedDict_pop_impl((PyODictObject *)self, key, default_value); + + exit: + return return_value; +@@ -219,7 +219,7 @@ + OrderedDict_popitem_impl(PyODictObject *self, int last); + + static PyObject * +-OrderedDict_popitem(PyODictObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++OrderedDict_popitem(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -264,7 +264,7 @@ + goto exit; + } + skip_optional_pos: +- return_value = OrderedDict_popitem_impl(self, last); ++ return_value = OrderedDict_popitem_impl((PyODictObject *)self, last); + + exit: + return return_value; +@@ -285,7 +285,7 @@ + OrderedDict_move_to_end_impl(PyODictObject *self, PyObject *key, int last); + + static PyObject * +-OrderedDict_move_to_end(PyODictObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++OrderedDict_move_to_end(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -332,9 +332,9 @@ + goto exit; + } + skip_optional_pos: +- return_value = OrderedDict_move_to_end_impl(self, key, last); ++ return_value = OrderedDict_move_to_end_impl((PyODictObject *)self, key, last); + + exit: + return return_value; + } +-/*[clinic end generated code: output=2aa6fc0567c9252c input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=55bd390bb516e997 input=a9049054013a1b77]*/ +diff --git a/Objects/clinic/setobject.c.h b/Objects/clinic/setobject.c.h +index 986993b4aa9..bf7e604e4b0 100644 +--- a/Objects/clinic/setobject.c.h ++++ b/Objects/clinic/setobject.c.h +@@ -19,12 +19,12 @@ + set_pop_impl(PySetObject *so); + + static PyObject * +-set_pop(PySetObject *so, PyObject *Py_UNUSED(ignored)) ++set_pop(PyObject *so, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(so); +- return_value = set_pop_impl(so); ++ return_value = set_pop_impl((PySetObject *)so); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -44,7 +44,7 @@ + Py_ssize_t others_length); + + static PyObject * +-set_update(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) ++set_update(PyObject *so, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject * const *others; +@@ -52,7 +52,7 @@ + + others = args; + others_length = nargs; +- return_value = set_update_impl(so, others, others_length); ++ return_value = set_update_impl((PySetObject *)so, others, others_length); + + return return_value; + } +@@ -70,12 +70,12 @@ + set_copy_impl(PySetObject *so); + + static PyObject * +-set_copy(PySetObject *so, PyObject *Py_UNUSED(ignored)) ++set_copy(PyObject *so, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(so); +- return_value = set_copy_impl(so); ++ return_value = set_copy_impl((PySetObject *)so); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -94,12 +94,12 @@ + frozenset_copy_impl(PySetObject *so); + + static PyObject * +-frozenset_copy(PySetObject *so, PyObject *Py_UNUSED(ignored)) ++frozenset_copy(PyObject *so, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(so); +- return_value = frozenset_copy_impl(so); ++ return_value = frozenset_copy_impl((PySetObject *)so); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -118,12 +118,12 @@ + set_clear_impl(PySetObject *so); + + static PyObject * +-set_clear(PySetObject *so, PyObject *Py_UNUSED(ignored)) ++set_clear(PyObject *so, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(so); +- return_value = set_clear_impl(so); ++ return_value = set_clear_impl((PySetObject *)so); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -143,7 +143,7 @@ + Py_ssize_t others_length); + + static PyObject * +-set_union(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) ++set_union(PyObject *so, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject * const *others; +@@ -151,7 +151,7 @@ + + others = args; + others_length = nargs; +- return_value = set_union_impl(so, others, others_length); ++ return_value = set_union_impl((PySetObject *)so, others, others_length); + + return return_value; + } +@@ -170,7 +170,7 @@ + Py_ssize_t others_length); + + static PyObject * +-set_intersection_multi(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) ++set_intersection_multi(PyObject *so, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject * const *others; +@@ -178,7 +178,7 @@ + + others = args; + others_length = nargs; +- return_value = set_intersection_multi_impl(so, others, others_length); ++ return_value = set_intersection_multi_impl((PySetObject *)so, others, others_length); + + return return_value; + } +@@ -197,7 +197,7 @@ + Py_ssize_t others_length); + + static PyObject * +-set_intersection_update_multi(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) ++set_intersection_update_multi(PyObject *so, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject * const *others; +@@ -205,7 +205,7 @@ + + others = args; + others_length = nargs; +- return_value = set_intersection_update_multi_impl(so, others, others_length); ++ return_value = set_intersection_update_multi_impl((PySetObject *)so, others, others_length); + + return return_value; + } +@@ -228,7 +228,7 @@ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION2(so, other); +- return_value = set_isdisjoint_impl(so, other); ++ return_value = set_isdisjoint_impl((PySetObject *)so, other); + Py_END_CRITICAL_SECTION2(); + + return return_value; +@@ -248,7 +248,7 @@ + Py_ssize_t others_length); + + static PyObject * +-set_difference_update(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) ++set_difference_update(PyObject *so, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject * const *others; +@@ -256,7 +256,7 @@ + + others = args; + others_length = nargs; +- return_value = set_difference_update_impl(so, others, others_length); ++ return_value = set_difference_update_impl((PySetObject *)so, others, others_length); + + return return_value; + } +@@ -275,7 +275,7 @@ + Py_ssize_t others_length); + + static PyObject * +-set_difference_multi(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) ++set_difference_multi(PyObject *so, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject * const *others; +@@ -283,7 +283,7 @@ + + others = args; + others_length = nargs; +- return_value = set_difference_multi_impl(so, others, others_length); ++ return_value = set_difference_multi_impl((PySetObject *)so, others, others_length); + + return return_value; + } +@@ -315,7 +315,7 @@ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION2(so, other); +- return_value = set_symmetric_difference_impl(so, other); ++ return_value = set_symmetric_difference_impl((PySetObject *)so, other); + Py_END_CRITICAL_SECTION2(); + + return return_value; +@@ -339,7 +339,7 @@ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION2(so, other); +- return_value = set_issubset_impl(so, other); ++ return_value = set_issubset_impl((PySetObject *)so, other); + Py_END_CRITICAL_SECTION2(); + + return return_value; +@@ -363,7 +363,7 @@ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION2(so, other); +- return_value = set_issuperset_impl(so, other); ++ return_value = set_issuperset_impl((PySetObject *)so, other); + Py_END_CRITICAL_SECTION2(); + + return return_value; +@@ -389,7 +389,7 @@ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(so); +- return_value = set_add_impl(so, key); ++ return_value = set_add_impl((PySetObject *)so, key); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -413,7 +413,7 @@ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(so); +- return_value = set___contains___impl(so, key); ++ return_value = set___contains___impl((PySetObject *)so, key); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -439,7 +439,7 @@ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(so); +- return_value = set_remove_impl(so, key); ++ return_value = set_remove_impl((PySetObject *)so, key); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -466,7 +466,7 @@ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(so); +- return_value = set_discard_impl(so, key); ++ return_value = set_discard_impl((PySetObject *)so, key); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -485,12 +485,12 @@ + set___reduce___impl(PySetObject *so); + + static PyObject * +-set___reduce__(PySetObject *so, PyObject *Py_UNUSED(ignored)) ++set___reduce__(PyObject *so, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(so); +- return_value = set___reduce___impl(so); ++ return_value = set___reduce___impl((PySetObject *)so); + Py_END_CRITICAL_SECTION(); + + return return_value; +@@ -509,14 +509,14 @@ + set___sizeof___impl(PySetObject *so); + + static PyObject * +-set___sizeof__(PySetObject *so, PyObject *Py_UNUSED(ignored)) ++set___sizeof__(PyObject *so, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(so); +- return_value = set___sizeof___impl(so); ++ return_value = set___sizeof___impl((PySetObject *)so); + Py_END_CRITICAL_SECTION(); + + return return_value; + } +-/*[clinic end generated code: output=4b65e7709927f31f input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=83b7742a762ce465 input=a9049054013a1b77]*/ +diff --git a/Objects/clinic/tupleobject.c.h b/Objects/clinic/tupleobject.c.h +index 5d6a2c481a5..40ffd4c1755 100644 +--- a/Objects/clinic/tupleobject.c.h ++++ b/Objects/clinic/tupleobject.c.h +@@ -20,7 +20,7 @@ + Py_ssize_t stop); + + static PyObject * +-tuple_index(PyTupleObject *self, PyObject *const *args, Py_ssize_t nargs) ++tuple_index(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *value; +@@ -44,7 +44,7 @@ + goto exit; + } + skip_optional: +- return_value = tuple_index_impl(self, value, start, stop); ++ return_value = tuple_index_impl((PyTupleObject *)self, value, start, stop); + + exit: + return return_value; +@@ -110,8 +110,8 @@ + tuple___getnewargs___impl(PyTupleObject *self); + + static PyObject * +-tuple___getnewargs__(PyTupleObject *self, PyObject *Py_UNUSED(ignored)) ++tuple___getnewargs__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return tuple___getnewargs___impl(self); ++ return tuple___getnewargs___impl((PyTupleObject *)self); + } +-/*[clinic end generated code: output=a6a9abba5d121f4c input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=779cb4a13db67397 input=a9049054013a1b77]*/ +diff --git a/Objects/clinic/typeobject.c.h b/Objects/clinic/typeobject.c.h +index 1fa153598db..5e8187b3f5b 100644 +--- a/Objects/clinic/typeobject.c.h ++++ b/Objects/clinic/typeobject.c.h +@@ -22,7 +22,7 @@ + PyObject *return_value = NULL; + int _return_value; + +- _return_value = type___instancecheck___impl(self, instance); ++ _return_value = type___instancecheck___impl((PyTypeObject *)self, instance); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } +@@ -50,7 +50,7 @@ + PyObject *return_value = NULL; + int _return_value; + +- _return_value = type___subclasscheck___impl(self, subclass); ++ _return_value = type___subclasscheck___impl((PyTypeObject *)self, subclass); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } +@@ -73,9 +73,9 @@ + type_mro_impl(PyTypeObject *self); + + static PyObject * +-type_mro(PyTypeObject *self, PyObject *Py_UNUSED(ignored)) ++type_mro(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return type_mro_impl(self); ++ return type_mro_impl((PyTypeObject *)self); + } + + PyDoc_STRVAR(type___subclasses____doc__, +@@ -91,9 +91,9 @@ + type___subclasses___impl(PyTypeObject *self); + + static PyObject * +-type___subclasses__(PyTypeObject *self, PyObject *Py_UNUSED(ignored)) ++type___subclasses__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return type___subclasses___impl(self); ++ return type___subclasses___impl((PyTypeObject *)self); + } + + PyDoc_STRVAR(type___dir____doc__, +@@ -109,9 +109,9 @@ + type___dir___impl(PyTypeObject *self); + + static PyObject * +-type___dir__(PyTypeObject *self, PyObject *Py_UNUSED(ignored)) ++type___dir__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return type___dir___impl(self); ++ return type___dir___impl((PyTypeObject *)self); + } + + PyDoc_STRVAR(type___sizeof____doc__, +@@ -127,9 +127,9 @@ + type___sizeof___impl(PyTypeObject *self); + + static PyObject * +-type___sizeof__(PyTypeObject *self, PyObject *Py_UNUSED(ignored)) ++type___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return type___sizeof___impl(self); ++ return type___sizeof___impl((PyTypeObject *)self); + } + + PyDoc_STRVAR(object___getstate____doc__, +@@ -262,4 +262,4 @@ + { + return object___dir___impl(self); + } +-/*[clinic end generated code: output=b56c87f9cace1921 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=f7db85fd11818c63 input=a9049054013a1b77]*/ +diff --git a/Objects/clinic/typevarobject.c.h b/Objects/clinic/typevarobject.c.h +index c17998830b0..e50ed7d95b9 100644 +--- a/Objects/clinic/typevarobject.c.h ++++ b/Objects/clinic/typevarobject.c.h +@@ -143,7 +143,7 @@ + PyObject *args); + + static PyObject * +-typevar_typing_prepare_subst(typevarobject *self, PyObject *const *args, Py_ssize_t nargs) ++typevar_typing_prepare_subst(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *alias; +@@ -154,7 +154,7 @@ + } + alias = args[0]; + __clinic_args = args[1]; +- return_value = typevar_typing_prepare_subst_impl(self, alias, __clinic_args); ++ return_value = typevar_typing_prepare_subst_impl((typevarobject *)self, alias, __clinic_args); + + exit: + return return_value; +@@ -172,9 +172,9 @@ + typevar_reduce_impl(typevarobject *self); + + static PyObject * +-typevar_reduce(typevarobject *self, PyObject *Py_UNUSED(ignored)) ++typevar_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return typevar_reduce_impl(self); ++ return typevar_reduce_impl((typevarobject *)self); + } + + PyDoc_STRVAR(typevar_has_default__doc__, +@@ -189,9 +189,9 @@ + typevar_has_default_impl(typevarobject *self); + + static PyObject * +-typevar_has_default(typevarobject *self, PyObject *Py_UNUSED(ignored)) ++typevar_has_default(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return typevar_has_default_impl(self); ++ return typevar_has_default_impl((typevarobject *)self); + } + + PyDoc_STRVAR(paramspecargs_new__doc__, +@@ -431,7 +431,7 @@ + PyObject *args); + + static PyObject * +-paramspec_typing_prepare_subst(paramspecobject *self, PyObject *const *args, Py_ssize_t nargs) ++paramspec_typing_prepare_subst(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *alias; +@@ -442,7 +442,7 @@ + } + alias = args[0]; + __clinic_args = args[1]; +- return_value = paramspec_typing_prepare_subst_impl(self, alias, __clinic_args); ++ return_value = paramspec_typing_prepare_subst_impl((paramspecobject *)self, alias, __clinic_args); + + exit: + return return_value; +@@ -460,9 +460,9 @@ + paramspec_reduce_impl(paramspecobject *self); + + static PyObject * +-paramspec_reduce(paramspecobject *self, PyObject *Py_UNUSED(ignored)) ++paramspec_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return paramspec_reduce_impl(self); ++ return paramspec_reduce_impl((paramspecobject *)self); + } + + PyDoc_STRVAR(paramspec_has_default__doc__, +@@ -477,9 +477,9 @@ + paramspec_has_default_impl(paramspecobject *self); + + static PyObject * +-paramspec_has_default(paramspecobject *self, PyObject *Py_UNUSED(ignored)) ++paramspec_has_default(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return paramspec_has_default_impl(self); ++ return paramspec_has_default_impl((paramspecobject *)self); + } + + PyDoc_STRVAR(typevartuple__doc__, +@@ -570,7 +570,7 @@ + PyObject *alias, PyObject *args); + + static PyObject * +-typevartuple_typing_prepare_subst(typevartupleobject *self, PyObject *const *args, Py_ssize_t nargs) ++typevartuple_typing_prepare_subst(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *alias; +@@ -581,7 +581,7 @@ + } + alias = args[0]; + __clinic_args = args[1]; +- return_value = typevartuple_typing_prepare_subst_impl(self, alias, __clinic_args); ++ return_value = typevartuple_typing_prepare_subst_impl((typevartupleobject *)self, alias, __clinic_args); + + exit: + return return_value; +@@ -599,9 +599,9 @@ + typevartuple_reduce_impl(typevartupleobject *self); + + static PyObject * +-typevartuple_reduce(typevartupleobject *self, PyObject *Py_UNUSED(ignored)) ++typevartuple_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return typevartuple_reduce_impl(self); ++ return typevartuple_reduce_impl((typevartupleobject *)self); + } + + PyDoc_STRVAR(typevartuple_has_default__doc__, +@@ -616,9 +616,9 @@ + typevartuple_has_default_impl(typevartupleobject *self); + + static PyObject * +-typevartuple_has_default(typevartupleobject *self, PyObject *Py_UNUSED(ignored)) ++typevartuple_has_default(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return typevartuple_has_default_impl(self); ++ return typevartuple_has_default_impl((typevartupleobject *)self); + } + + PyDoc_STRVAR(typealias_reduce__doc__, +@@ -633,9 +633,9 @@ + typealias_reduce_impl(typealiasobject *self); + + static PyObject * +-typealias_reduce(typealiasobject *self, PyObject *Py_UNUSED(ignored)) ++typealias_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return typealias_reduce_impl(self); ++ return typealias_reduce_impl((typealiasobject *)self); + } + + PyDoc_STRVAR(typealias_new__doc__, +@@ -706,4 +706,4 @@ + exit: + return return_value; + } +-/*[clinic end generated code: output=26351c3549f5ad83 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=f499d959a942c599 input=a9049054013a1b77]*/ +diff --git a/Objects/clinic/unicodeobject.c.h b/Objects/clinic/unicodeobject.c.h +index 361f20c0fa4..5c6a425b0f8 100644 +--- a/Objects/clinic/unicodeobject.c.h ++++ b/Objects/clinic/unicodeobject.c.h +@@ -22,9 +22,9 @@ + EncodingMap_size_impl(struct encoding_map *self); + + static PyObject * +-EncodingMap_size(struct encoding_map *self, PyObject *Py_UNUSED(ignored)) ++EncodingMap_size(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return EncodingMap_size_impl(self); ++ return EncodingMap_size_impl((struct encoding_map *)self); + } + + PyDoc_STRVAR(unicode_title__doc__, +@@ -1895,4 +1895,4 @@ + exit: + return return_value; + } +-/*[clinic end generated code: output=30efbf79c5a07dd2 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=4d1cecd6d08498a4 input=a9049054013a1b77]*/ +diff --git a/Objects/codeobject.c b/Objects/codeobject.c +index eb8de136ee6..a7b46aa2dfb 100644 +--- a/Objects/codeobject.c ++++ b/Objects/codeobject.c +@@ -108,6 +108,8 @@ + * generic helpers + ******************/ + ++#define _PyCodeObject_CAST(op) (assert(PyCode_Check(op)), (PyCodeObject *)(op)) ++ + static int + should_intern_string(PyObject *o) + { +@@ -457,8 +459,7 @@ + } + + extern void +-_PyCode_Quicken(_Py_CODEUNIT *instructions, Py_ssize_t size, PyObject *consts, +- int enable_counters); ++_PyCode_Quicken(_Py_CODEUNIT *instructions, Py_ssize_t size, int enable_counters); + + #ifdef Py_GIL_DISABLED + static _PyCodeArray * _PyCodeArray_New(Py_ssize_t size); +@@ -541,10 +542,9 @@ + } + co->_co_firsttraceable = entry_point; + #ifdef Py_GIL_DISABLED +- _PyCode_Quicken(_PyCode_CODE(co), Py_SIZE(co), co->co_consts, +- interp->config.tlbc_enabled); ++ _PyCode_Quicken(_PyCode_CODE(co), Py_SIZE(co), interp->config.tlbc_enabled); + #else +- _PyCode_Quicken(_PyCode_CODE(co), Py_SIZE(co), co->co_consts, 1); ++ _PyCode_Quicken(_PyCode_CODE(co), Py_SIZE(co), 1); + #endif + notify_code_watchers(PY_CODE_EVENT_CREATE, co); + return 0; +@@ -977,6 +977,9 @@ + if (addrq < 0) { + return co->co_firstlineno; + } ++ if (co->_co_monitoring && co->_co_monitoring->lines) { ++ return _Py_Instrumentation_GetLine(co, addrq/sizeof(_Py_CODEUNIT)); ++ } + assert(addrq >= 0 && addrq < _PyCode_NBYTES(co)); + PyCodeAddressRange bounds; + _PyCode_InitAddressRange(co, &bounds); +@@ -1865,11 +1868,12 @@ + } + + static void +-code_dealloc(PyCodeObject *co) ++code_dealloc(PyObject *self) + { +- _PyObject_ResurrectStart((PyObject *)co); ++ PyCodeObject *co = _PyCodeObject_CAST(self); ++ _PyObject_ResurrectStart(self); + notify_code_watchers(PY_CODE_EVENT_DESTROY, co); +- if (_PyObject_ResurrectEnd((PyObject *)co)) { ++ if (_PyObject_ResurrectEnd(self)) { + return; + } + +@@ -1908,7 +1912,7 @@ + Py_XDECREF(co->co_linetable); + Py_XDECREF(co->co_exceptiontable); + #ifdef Py_GIL_DISABLED +- assert(co->_co_unique_id == -1); ++ assert(co->_co_unique_id == _Py_INVALID_UNIQUE_ID); + #endif + if (co->_co_cached != NULL) { + Py_XDECREF(co->_co_cached->_co_code); +@@ -1918,7 +1922,7 @@ + PyMem_Free(co->_co_cached); + } + if (co->co_weakreflist != NULL) { +- PyObject_ClearWeakRefs((PyObject*)co); ++ PyObject_ClearWeakRefs(self); + } + free_monitoring_data(co->_co_monitoring); + #ifdef Py_GIL_DISABLED +@@ -1939,7 +1943,7 @@ + static int + code_traverse(PyObject *self, visitproc visit, void *arg) + { +- PyCodeObject *co = (PyCodeObject*)self; ++ PyCodeObject *co = _PyCodeObject_CAST(self); + Py_VISIT(co->co_consts); + return 0; + } +@@ -1948,7 +1952,7 @@ + static PyObject * + code_repr(PyObject *self) + { +- PyCodeObject *co = (PyCodeObject*)self; ++ PyCodeObject *co = _PyCodeObject_CAST(self); + int lineno; + if (co->co_firstlineno != 0) + lineno = co->co_firstlineno; +@@ -2057,7 +2061,7 @@ + static Py_hash_t + code_hash(PyObject *self) + { +- PyCodeObject *co = (PyCodeObject*)self; ++ PyCodeObject *co = _PyCodeObject_CAST(self); + Py_uhash_t uhash = 20221211; + #define SCRAMBLE_IN(H) do { \ + uhash ^= (Py_uhash_t)(H); \ +@@ -2120,7 +2124,7 @@ + static PyObject * + code_getlnotab(PyObject *self, void *closure) + { +- PyCodeObject *code = (PyCodeObject*)self; ++ PyCodeObject *code = _PyCodeObject_CAST(self); + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "co_lnotab is deprecated, use co_lines instead.", + 1) < 0) { +@@ -2132,28 +2136,28 @@ + static PyObject * + code_getvarnames(PyObject *self, void *closure) + { +- PyCodeObject *code = (PyCodeObject*)self; ++ PyCodeObject *code = _PyCodeObject_CAST(self); + return _PyCode_GetVarnames(code); + } + + static PyObject * + code_getcellvars(PyObject *self, void *closure) + { +- PyCodeObject *code = (PyCodeObject*)self; ++ PyCodeObject *code = _PyCodeObject_CAST(self); + return _PyCode_GetCellvars(code); + } + + static PyObject * + code_getfreevars(PyObject *self, void *closure) + { +- PyCodeObject *code = (PyCodeObject*)self; ++ PyCodeObject *code = _PyCodeObject_CAST(self); + return _PyCode_GetFreevars(code); + } + + static PyObject * + code_getcodeadaptive(PyObject *self, void *closure) + { +- PyCodeObject *code = (PyCodeObject*)self; ++ PyCodeObject *code = _PyCodeObject_CAST(self); + return PyBytes_FromStringAndSize(code->co_code_adaptive, + _PyCode_NBYTES(code)); + } +@@ -2161,7 +2165,7 @@ + static PyObject * + code_getcode(PyObject *self, void *closure) + { +- PyCodeObject *code = (PyCodeObject*)self; ++ PyCodeObject *code = _PyCodeObject_CAST(self); + return _PyCode_GetCode(code); + } + +@@ -2180,7 +2184,7 @@ + static PyObject * + code_sizeof(PyObject *self, PyObject *Py_UNUSED(args)) + { +- PyCodeObject *co = (PyCodeObject*)self; ++ PyCodeObject *co = _PyCodeObject_CAST(self); + size_t res = _PyObject_VAR_SIZE(Py_TYPE(co), Py_SIZE(co)); + _PyCodeObjectExtra *co_extra = (_PyCodeObjectExtra*) co->co_extra; + if (co_extra != NULL) { +@@ -2193,33 +2197,40 @@ + static PyObject * + code_linesiterator(PyObject *self, PyObject *Py_UNUSED(args)) + { +- PyCodeObject *code = (PyCodeObject*)self; ++ PyCodeObject *code = _PyCodeObject_CAST(self); + return (PyObject *)new_linesiterator(code); + } + ++static PyObject * ++code_branchesiterator(PyObject *self, PyObject *Py_UNUSED(args)) ++{ ++ PyCodeObject *code = _PyCodeObject_CAST(self); ++ return _PyInstrumentation_BranchesIterator(code); ++} ++ + /*[clinic input] + @text_signature "($self, /, **changes)" + code.replace + + * +- co_argcount: int(c_default="self->co_argcount") = unchanged +- co_posonlyargcount: int(c_default="self->co_posonlyargcount") = unchanged +- co_kwonlyargcount: int(c_default="self->co_kwonlyargcount") = unchanged +- co_nlocals: int(c_default="self->co_nlocals") = unchanged +- co_stacksize: int(c_default="self->co_stacksize") = unchanged +- co_flags: int(c_default="self->co_flags") = unchanged +- co_firstlineno: int(c_default="self->co_firstlineno") = unchanged ++ co_argcount: int(c_default="((PyCodeObject *)self)->co_argcount") = unchanged ++ co_posonlyargcount: int(c_default="((PyCodeObject *)self)->co_posonlyargcount") = unchanged ++ co_kwonlyargcount: int(c_default="((PyCodeObject *)self)->co_kwonlyargcount") = unchanged ++ co_nlocals: int(c_default="((PyCodeObject *)self)->co_nlocals") = unchanged ++ co_stacksize: int(c_default="((PyCodeObject *)self)->co_stacksize") = unchanged ++ co_flags: int(c_default="((PyCodeObject *)self)->co_flags") = unchanged ++ co_firstlineno: int(c_default="((PyCodeObject *)self)->co_firstlineno") = unchanged + co_code: object(subclass_of="&PyBytes_Type", c_default="NULL") = unchanged +- co_consts: object(subclass_of="&PyTuple_Type", c_default="self->co_consts") = unchanged +- co_names: object(subclass_of="&PyTuple_Type", c_default="self->co_names") = unchanged ++ co_consts: object(subclass_of="&PyTuple_Type", c_default="((PyCodeObject *)self)->co_consts") = unchanged ++ co_names: object(subclass_of="&PyTuple_Type", c_default="((PyCodeObject *)self)->co_names") = unchanged + co_varnames: object(subclass_of="&PyTuple_Type", c_default="NULL") = unchanged + co_freevars: object(subclass_of="&PyTuple_Type", c_default="NULL") = unchanged + co_cellvars: object(subclass_of="&PyTuple_Type", c_default="NULL") = unchanged +- co_filename: unicode(c_default="self->co_filename") = unchanged +- co_name: unicode(c_default="self->co_name") = unchanged +- co_qualname: unicode(c_default="self->co_qualname") = unchanged +- co_linetable: object(subclass_of="&PyBytes_Type", c_default="self->co_linetable") = unchanged +- co_exceptiontable: object(subclass_of="&PyBytes_Type", c_default="self->co_exceptiontable") = unchanged ++ co_filename: unicode(c_default="((PyCodeObject *)self)->co_filename") = unchanged ++ co_name: unicode(c_default="((PyCodeObject *)self)->co_name") = unchanged ++ co_qualname: unicode(c_default="((PyCodeObject *)self)->co_qualname") = unchanged ++ co_linetable: object(subclass_of="&PyBytes_Type", c_default="((PyCodeObject *)self)->co_linetable") = unchanged ++ co_exceptiontable: object(subclass_of="&PyBytes_Type", c_default="((PyCodeObject *)self)->co_exceptiontable") = unchanged + + Return a copy of the code object with new values for the specified fields. + [clinic start generated code]*/ +@@ -2234,7 +2245,7 @@ + PyObject *co_filename, PyObject *co_name, + PyObject *co_qualname, PyObject *co_linetable, + PyObject *co_exceptiontable) +-/*[clinic end generated code: output=e75c48a15def18b9 input=18e280e07846c122]*/ ++/*[clinic end generated code: output=e75c48a15def18b9 input=a455a89c57ac9d42]*/ + { + #define CHECK_INT_ARG(ARG) \ + if (ARG < 0) { \ +@@ -2337,6 +2348,7 @@ + static struct PyMethodDef code_methods[] = { + {"__sizeof__", code_sizeof, METH_NOARGS}, + {"co_lines", code_linesiterator, METH_NOARGS}, ++ {"co_branches", code_branchesiterator, METH_NOARGS}, + {"co_positions", code_positionsiterator, METH_NOARGS}, + CODE_REPLACE_METHODDEF + CODE__VARNAME_FROM_OPARG_METHODDEF +@@ -2351,7 +2363,7 @@ + "code", + offsetof(PyCodeObject, co_code_adaptive), + sizeof(_Py_CODEUNIT), +- (destructor)code_dealloc, /* tp_dealloc */ ++ code_dealloc, /* tp_dealloc */ + 0, /* tp_vectorcall_offset */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ +@@ -2805,7 +2817,7 @@ + for (int i = 0; i < code_len; i += _PyInstruction_GetLength(co, i)) { + dst[i] = _Py_GetBaseCodeUnit(co, i); + } +- _PyCode_Quicken(dst, code_len, co->co_consts, 1); ++ _PyCode_Quicken(dst, code_len, 1); + } + + static Py_ssize_t +diff --git a/Objects/complexobject.c b/Objects/complexobject.c +index bf6187efac9..5d9b3c9f0e3 100644 +--- a/Objects/complexobject.c ++++ b/Objects/complexobject.c +@@ -14,6 +14,8 @@ + #include "pycore_pymath.h" // _Py_ADJUST_ERANGE2() + + ++#define _PyComplexObject_CAST(op) ((PyComplexObject *)(op)) ++ + + /*[clinic input] + class complex "PyComplexObject *" "&PyComplex_Type" +@@ -553,11 +555,12 @@ + } + + static PyObject * +-complex_repr(PyComplexObject *v) ++complex_repr(PyObject *op) + { + int precision = 0; + char format_code = 'r'; + PyObject *result = NULL; ++ PyComplexObject *v = _PyComplexObject_CAST(op); + + /* If these are non-NULL, they'll need to be freed. */ + char *pre = NULL; +@@ -609,13 +612,14 @@ + } + + static Py_hash_t +-complex_hash(PyComplexObject *v) ++complex_hash(PyObject *op) + { + Py_uhash_t hashreal, hashimag, combined; +- hashreal = (Py_uhash_t)_Py_HashDouble((PyObject *) v, v->cval.real); ++ PyComplexObject *v = _PyComplexObject_CAST(op); ++ hashreal = (Py_uhash_t)_Py_HashDouble(op, v->cval.real); + if (hashreal == (Py_uhash_t)-1) + return -1; +- hashimag = (Py_uhash_t)_Py_HashDouble((PyObject *)v, v->cval.imag); ++ hashimag = (Py_uhash_t)_Py_HashDouble(op, v->cval.imag); + if (hashimag == (Py_uhash_t)-1) + return -1; + /* Note: if the imaginary part is 0, hashimag is 0 now, +@@ -753,8 +757,9 @@ + } + + static PyObject * +-complex_neg(PyComplexObject *v) ++complex_neg(PyObject *op) + { ++ PyComplexObject *v = _PyComplexObject_CAST(op); + Py_complex neg; + neg.real = -v->cval.real; + neg.imag = -v->cval.imag; +@@ -762,22 +767,20 @@ + } + + static PyObject * +-complex_pos(PyComplexObject *v) ++complex_pos(PyObject *op) + { ++ PyComplexObject *v = _PyComplexObject_CAST(op); + if (PyComplex_CheckExact(v)) { + return Py_NewRef(v); + } +- else +- return PyComplex_FromCComplex(v->cval); ++ return PyComplex_FromCComplex(v->cval); + } + + static PyObject * +-complex_abs(PyComplexObject *v) ++complex_abs(PyObject *op) + { +- double result; +- +- result = _Py_c_abs(v->cval); +- ++ PyComplexObject *v = _PyComplexObject_CAST(op); ++ double result = _Py_c_abs(v->cval); + if (errno == ERANGE) { + PyErr_SetString(PyExc_OverflowError, + "absolute value too large"); +@@ -787,8 +790,9 @@ + } + + static int +-complex_bool(PyComplexObject *v) ++complex_bool(PyObject *op) + { ++ PyComplexObject *v = _PyComplexObject_CAST(op); + return v->cval.real != 0.0 || v->cval.imag != 0.0; + } + +@@ -1339,16 +1343,16 @@ + }; + + static PyNumberMethods complex_as_number = { +- (binaryfunc)complex_add, /* nb_add */ +- (binaryfunc)complex_sub, /* nb_subtract */ +- (binaryfunc)complex_mul, /* nb_multiply */ ++ complex_add, /* nb_add */ ++ complex_sub, /* nb_subtract */ ++ complex_mul, /* nb_multiply */ + 0, /* nb_remainder */ + 0, /* nb_divmod */ +- (ternaryfunc)complex_pow, /* nb_power */ +- (unaryfunc)complex_neg, /* nb_negative */ +- (unaryfunc)complex_pos, /* nb_positive */ +- (unaryfunc)complex_abs, /* nb_absolute */ +- (inquiry)complex_bool, /* nb_bool */ ++ complex_pow, /* nb_power */ ++ complex_neg, /* nb_negative */ ++ complex_pos, /* nb_positive */ ++ complex_abs, /* nb_absolute */ ++ complex_bool, /* nb_bool */ + 0, /* nb_invert */ + 0, /* nb_lshift */ + 0, /* nb_rshift */ +@@ -1369,7 +1373,7 @@ + 0, /* nb_inplace_xor */ + 0, /* nb_inplace_or */ + 0, /* nb_floor_divide */ +- (binaryfunc)complex_div, /* nb_true_divide */ ++ complex_div, /* nb_true_divide */ + 0, /* nb_inplace_floor_divide */ + 0, /* nb_inplace_true_divide */ + }; +@@ -1384,11 +1388,11 @@ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_as_async */ +- (reprfunc)complex_repr, /* tp_repr */ ++ complex_repr, /* tp_repr */ + &complex_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ +- (hashfunc)complex_hash, /* tp_hash */ ++ complex_hash, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ +diff --git a/Objects/descrobject.c b/Objects/descrobject.c +index 4eccd1704eb..238becee241 100644 +--- a/Objects/descrobject.c ++++ b/Objects/descrobject.c +@@ -1349,7 +1349,7 @@ + wrapperobject *wp = (wrapperobject *)self; + Py_hash_t x, y; + x = PyObject_GenericHash(wp->self); +- y = _Py_HashPointer(wp->descr); ++ y = Py_HashPointer(wp->descr); + x = x ^ y; + if (x == -1) + x = -2; +@@ -1508,6 +1508,8 @@ + + /* A built-in 'property' type */ + ++#define _propertyobject_CAST(op) ((propertyobject *)(op)) ++ + /* + class property(object): + +@@ -1911,8 +1913,9 @@ + } + + static PyObject * +-property_get__name__(propertyobject *prop, void *Py_UNUSED(ignored)) ++property_get__name__(PyObject *op, void *Py_UNUSED(ignored)) + { ++ propertyobject *prop = _propertyobject_CAST(op); + PyObject *name; + if (property_name(prop, &name) < 0) { + return NULL; +@@ -1925,16 +1928,17 @@ + } + + static int +-property_set__name__(propertyobject *prop, PyObject *value, +- void *Py_UNUSED(ignored)) ++property_set__name__(PyObject *op, PyObject *value, void *Py_UNUSED(ignored)) + { ++ propertyobject *prop = _propertyobject_CAST(op); + Py_XSETREF(prop->prop_name, Py_XNewRef(value)); + return 0; + } + + static PyObject * +-property_get___isabstractmethod__(propertyobject *prop, void *closure) ++property_get___isabstractmethod__(PyObject *op, void *closure) + { ++ propertyobject *prop = _propertyobject_CAST(op); + int res = _PyObject_IsAbstract(prop->prop_get); + if (res == -1) { + return NULL; +@@ -1962,9 +1966,8 @@ + } + + static PyGetSetDef property_getsetlist[] = { +- {"__name__", (getter)property_get__name__, (setter)property_set__name__}, +- {"__isabstractmethod__", +- (getter)property_get___isabstractmethod__, NULL, ++ {"__name__", property_get__name__, property_set__name__, NULL, NULL}, ++ {"__isabstractmethod__", property_get___isabstractmethod__, NULL, + NULL, + NULL}, + {NULL} /* Sentinel */ +diff --git a/Objects/dictobject.c b/Objects/dictobject.c +index 05c93a3e448..d979cd72b48 100644 +--- a/Objects/dictobject.c ++++ b/Objects/dictobject.c +@@ -1129,6 +1129,53 @@ + return do_lookup(mp, dk, key, hash, compare_generic); + } + ++static bool ++check_keys_unicode(PyDictKeysObject *dk, PyObject *key) ++{ ++ return PyUnicode_CheckExact(key) && (dk->dk_kind != DICT_KEYS_GENERAL); ++} ++ ++static Py_ssize_t ++hash_unicode_key(PyObject *key) ++{ ++ assert(PyUnicode_CheckExact(key)); ++ Py_hash_t hash = unicode_get_hash(key); ++ if (hash == -1) { ++ hash = PyUnicode_Type.tp_hash(key); ++ assert(hash != -1); ++ } ++ return hash; ++} ++ ++#ifdef Py_GIL_DISABLED ++static Py_ssize_t ++unicodekeys_lookup_unicode_threadsafe(PyDictKeysObject* dk, PyObject *key, ++ Py_hash_t hash); ++#endif ++ ++static Py_ssize_t ++unicodekeys_lookup_split(PyDictKeysObject* dk, PyObject *key, Py_hash_t hash) ++{ ++ Py_ssize_t ix; ++ assert(dk->dk_kind == DICT_KEYS_SPLIT); ++ assert(PyUnicode_CheckExact(key)); ++ ++#ifdef Py_GIL_DISABLED ++ // A split dictionaries keys can be mutated by other dictionaries ++ // but if we have a unicode key we can avoid locking the shared ++ // keys. ++ ix = unicodekeys_lookup_unicode_threadsafe(dk, key, hash); ++ if (ix == DKIX_KEY_CHANGED) { ++ LOCK_KEYS(dk); ++ ix = unicodekeys_lookup_unicode(dk, key, hash); ++ UNLOCK_KEYS(dk); ++ } ++#else ++ ix = unicodekeys_lookup_unicode(dk, key, hash); ++#endif ++ return ix; ++} ++ + /* Lookup a string in a (all unicode) dict keys. + * Returns DKIX_ERROR if key is not a string, + * or if the dict keys is not all strings. +@@ -1138,10 +1185,36 @@ + Py_ssize_t + _PyDictKeys_StringLookup(PyDictKeysObject* dk, PyObject *key) + { +- DictKeysKind kind = dk->dk_kind; +- if (!PyUnicode_CheckExact(key) || kind == DICT_KEYS_GENERAL) { ++ if (!check_keys_unicode(dk, key)) { ++ return DKIX_ERROR; ++ } ++ Py_hash_t hash = hash_unicode_key(key); ++ return unicodekeys_lookup_unicode(dk, key, hash); ++} ++ ++Py_ssize_t ++_PyDictKeys_StringLookupAndVersion(PyDictKeysObject *dk, PyObject *key, uint32_t *version) ++{ ++ if (!check_keys_unicode(dk, key)) { + return DKIX_ERROR; + } ++ Py_ssize_t ix; ++ Py_hash_t hash = hash_unicode_key(key); ++ LOCK_KEYS(dk); ++ ix = unicodekeys_lookup_unicode(dk, key, hash); ++ *version = _PyDictKeys_GetVersionForCurrentState(_PyInterpreterState_GET(), dk); ++ UNLOCK_KEYS(dk); ++ return ix; ++} ++ ++/* Like _PyDictKeys_StringLookup() but only works on split keys. Note ++ * that in free-threaded builds this locks the keys object as required. ++ */ ++Py_ssize_t ++_PyDictKeys_StringLookupSplit(PyDictKeysObject* dk, PyObject *key) ++{ ++ assert(dk->dk_kind == DICT_KEYS_SPLIT); ++ assert(PyUnicode_CheckExact(key)); + Py_hash_t hash = unicode_get_hash(key); + if (hash == -1) { + hash = PyUnicode_Type.tp_hash(key); +@@ -1150,17 +1223,9 @@ + return DKIX_ERROR; + } + } +- return unicodekeys_lookup_unicode(dk, key, hash); ++ return unicodekeys_lookup_split(dk, key, hash); + } + +-#ifdef Py_GIL_DISABLED +- +-static Py_ssize_t +-unicodekeys_lookup_unicode_threadsafe(PyDictKeysObject* dk, PyObject *key, +- Py_hash_t hash); +- +-#endif +- + /* + The basic lookup function used by all operations. + This is based on Algorithm D from Knuth Vol. 3, Sec. 6.4. +@@ -1192,15 +1257,7 @@ + if (PyUnicode_CheckExact(key)) { + #ifdef Py_GIL_DISABLED + if (kind == DICT_KEYS_SPLIT) { +- // A split dictionaries keys can be mutated by other +- // dictionaries but if we have a unicode key we can avoid +- // locking the shared keys. +- ix = unicodekeys_lookup_unicode_threadsafe(dk, key, hash); +- if (ix == DKIX_KEY_CHANGED) { +- LOCK_KEYS(dk); +- ix = unicodekeys_lookup_unicode(dk, key, hash); +- UNLOCK_KEYS(dk); +- } ++ ix = unicodekeys_lookup_split(dk, key, hash); + } + else { + ix = unicodekeys_lookup_unicode(dk, key, hash); +@@ -1602,6 +1659,9 @@ + assert(PyDict_Check(op)); + #ifdef Py_GIL_DISABLED + Py_ssize_t id = _PyObject_AssignUniqueId(op); ++ if (id == _Py_INVALID_UNIQUE_ID) { ++ return; ++ } + if ((uint64_t)id >= (uint64_t)DICT_UNIQUE_ID_MAX) { + _PyObject_ReleaseUniqueId(id); + return; +@@ -1609,8 +1669,7 @@ + + PyDictObject *mp = (PyDictObject *)op; + assert((mp->_ma_watcher_tag >> DICT_UNIQUE_ID_SHIFT) == 0); +- // Plus 1 so that _ma_watcher_tag=0 represents an unassigned id +- mp->_ma_watcher_tag += ((uint64_t)id + 1) << DICT_UNIQUE_ID_SHIFT; ++ mp->_ma_watcher_tag += (uint64_t)id << DICT_UNIQUE_ID_SHIFT; + #endif + } + +@@ -1894,6 +1953,16 @@ + } + } + ++static void ++invalidate_and_clear_inline_values(PyDictValues *values) ++{ ++ assert(values->embedded); ++ FT_ATOMIC_STORE_UINT8(values->valid, 0); ++ for (int i = 0; i < values->capacity; i++) { ++ FT_ATOMIC_STORE_PTR_RELEASE(values->values[i], NULL); ++ } ++} ++ + /* + Restructure the table by allocating a new table and reinserting all + items again. When entries have been deleted, the new table may +@@ -1985,7 +2054,7 @@ + if (oldvalues->embedded) { + assert(oldvalues->embedded == 1); + assert(oldvalues->valid == 1); +- FT_ATOMIC_STORE_UINT8(oldvalues->valid, 0); ++ invalidate_and_clear_inline_values(oldvalues); + } + else { + free_values(oldvalues, IS_DICT_SHARED(mp)); +@@ -3021,8 +3090,8 @@ + } + + +-PyObject * +-_PyDict_Pop(PyObject *dict, PyObject *key, PyObject *default_value) ++static PyObject * ++dict_pop_default(PyObject *dict, PyObject *key, PyObject *default_value) + { + PyObject *result; + if (PyDict_Pop(dict, key, &result) == 0) { +@@ -3035,6 +3104,12 @@ + return result; + } + ++PyObject * ++_PyDict_Pop(PyObject *dict, PyObject *key, PyObject *default_value) ++{ ++ return dict_pop_default(dict, key, default_value); ++} ++ + static PyDictObject * + dict_dict_fromkeys(PyInterpreterState *interp, PyDictObject *mp, + PyObject *iterable, PyObject *value) +@@ -3718,7 +3793,7 @@ + + ensure_shared_on_resize(mp); + dictkeys_decref(interp, mp->ma_keys, IS_DICT_SHARED(mp)); +- mp->ma_keys = keys; ++ set_keys(mp, keys); + STORE_USED(mp, other->ma_used); + ASSERT_CONSISTENT(mp); + +@@ -4173,7 +4248,6 @@ + } + + /*[clinic input] +-@critical_section + dict.get + + key: object +@@ -4185,7 +4259,7 @@ + + static PyObject * + dict_get_impl(PyDictObject *self, PyObject *key, PyObject *default_value) +-/*[clinic end generated code: output=bba707729dee05bf input=a631d3f18f584c60]*/ ++/*[clinic end generated code: output=bba707729dee05bf input=279ddb5790b6b107]*/ + { + PyObject *val = NULL; + Py_hash_t hash; +@@ -4396,7 +4470,7 @@ + dict_pop_impl(PyDictObject *self, PyObject *key, PyObject *default_value) + /*[clinic end generated code: output=3abb47b89f24c21c input=e221baa01044c44c]*/ + { +- return _PyDict_Pop((PyObject*)self, key, default_value); ++ return dict_pop_default((PyObject*)self, key, default_value); + } + + /*[clinic input] +@@ -6967,7 +7041,7 @@ + + PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj)); + assert(keys != NULL); +- Py_ssize_t ix = _PyDictKeys_StringLookup(keys, name); ++ Py_ssize_t ix = _PyDictKeys_StringLookupSplit(keys, name); + if (ix == DKIX_EMPTY) { + *attr = NULL; + return true; +@@ -6975,7 +7049,13 @@ + + #ifdef Py_GIL_DISABLED + PyObject *value = _Py_atomic_load_ptr_acquire(&values->values[ix]); +- if (value == NULL || _Py_TryIncrefCompare(&values->values[ix], value)) { ++ if (value == NULL) { ++ if (FT_ATOMIC_LOAD_UINT8(values->valid)) { ++ *attr = NULL; ++ return true; ++ } ++ } ++ else if (_Py_TryIncrefCompare(&values->values[ix], value)) { + *attr = value; + return true; + } +@@ -7271,7 +7351,8 @@ + if (set_or_clear_managed_dict(obj, NULL, true) < 0) { + /* Must be out of memory */ + assert(PyErr_Occurred() == PyExc_MemoryError); +- PyErr_WriteUnraisable(NULL); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "clearing an object managed dict"); + /* Clear the dict */ + PyDictObject *dict = _PyObject_GetManagedDict(obj); + Py_BEGIN_CRITICAL_SECTION2(dict, obj); +@@ -7313,7 +7394,7 @@ + } + mp->ma_values = values; + +- FT_ATOMIC_STORE_UINT8(_PyObject_InlineValues(obj)->valid, 0); ++ invalidate_and_clear_inline_values(_PyObject_InlineValues(obj)); + + assert(_PyObject_InlineValuesConsistencyCheck(obj)); + ASSERT_CONSISTENT(mp); +diff --git a/Objects/enumobject.c b/Objects/enumobject.c +index 556666779d8..eb895267526 100644 +--- a/Objects/enumobject.c ++++ b/Objects/enumobject.c +@@ -23,6 +23,7 @@ + PyObject* one; /* borrowed reference */ + } enumobject; + ++#define _enumobject_CAST(op) ((enumobject *)(op)) + + /*[clinic input] + @classmethod +@@ -150,8 +151,9 @@ + } + + static void +-enum_dealloc(enumobject *en) ++enum_dealloc(PyObject *op) + { ++ enumobject *en = _enumobject_CAST(op); + PyObject_GC_UnTrack(en); + Py_XDECREF(en->en_sit); + Py_XDECREF(en->en_result); +@@ -160,8 +162,9 @@ + } + + static int +-enum_traverse(enumobject *en, visitproc visit, void *arg) ++enum_traverse(PyObject *op, visitproc visit, void *arg) + { ++ enumobject *en = _enumobject_CAST(op); + Py_VISIT(en->en_sit); + Py_VISIT(en->en_result); + Py_VISIT(en->en_longindex); +@@ -220,8 +223,9 @@ + } + + static PyObject * +-enum_next(enumobject *en) ++enum_next(PyObject *op) + { ++ enumobject *en = _enumobject_CAST(op); + PyObject *next_index; + PyObject *next_item; + PyObject *result = en->en_result; +@@ -270,8 +274,9 @@ + } + + static PyObject * +-enum_reduce(enumobject *en, PyObject *Py_UNUSED(ignored)) ++enum_reduce(PyObject *op, PyObject *Py_UNUSED(ignored)) + { ++ enumobject *en = _enumobject_CAST(op); + if (en->en_longindex != NULL) + return Py_BuildValue("O(OO)", Py_TYPE(en), en->en_sit, en->en_longindex); + else +@@ -281,7 +286,7 @@ + PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); + + static PyMethodDef enum_methods[] = { +- {"__reduce__", (PyCFunction)enum_reduce, METH_NOARGS, reduce_doc}, ++ {"__reduce__", enum_reduce, METH_NOARGS, reduce_doc}, + {"__class_getitem__", Py_GenericAlias, + METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + {NULL, NULL} /* sentinel */ +@@ -293,7 +298,7 @@ + sizeof(enumobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ +- (destructor)enum_dealloc, /* tp_dealloc */ ++ enum_dealloc, /* tp_dealloc */ + 0, /* tp_vectorcall_offset */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ +@@ -311,12 +316,12 @@ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + enum_new__doc__, /* tp_doc */ +- (traverseproc)enum_traverse, /* tp_traverse */ ++ enum_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ +- (iternextfunc)enum_next, /* tp_iternext */ ++ enum_next, /* tp_iternext */ + enum_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ +@@ -329,7 +334,7 @@ + PyType_GenericAlloc, /* tp_alloc */ + enum_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +- .tp_vectorcall = (vectorcallfunc)enumerate_vectorcall ++ .tp_vectorcall = enumerate_vectorcall + }; + + /* Reversed Object ***************************************************************/ +@@ -340,6 +345,8 @@ + PyObject* seq; + } reversedobject; + ++#define _reversedobject_CAST(op) ((reversedobject *)(op)) ++ + /*[clinic input] + @classmethod + reversed.__new__ as reversed_new +@@ -411,23 +418,26 @@ + } + + static void +-reversed_dealloc(reversedobject *ro) ++reversed_dealloc(PyObject *op) + { ++ reversedobject *ro = _reversedobject_CAST(op); + PyObject_GC_UnTrack(ro); + Py_XDECREF(ro->seq); + Py_TYPE(ro)->tp_free(ro); + } + + static int +-reversed_traverse(reversedobject *ro, visitproc visit, void *arg) ++reversed_traverse(PyObject *op, visitproc visit, void *arg) + { ++ reversedobject *ro = _reversedobject_CAST(op); + Py_VISIT(ro->seq); + return 0; + } + + static PyObject * +-reversed_next(reversedobject *ro) ++reversed_next(PyObject *op) + { ++ reversedobject *ro = _reversedobject_CAST(op); + PyObject *item; + Py_ssize_t index = ro->index; + +@@ -447,8 +457,9 @@ + } + + static PyObject * +-reversed_len(reversedobject *ro, PyObject *Py_UNUSED(ignored)) ++reversed_len(PyObject *op, PyObject *Py_UNUSED(ignored)) + { ++ reversedobject *ro = _reversedobject_CAST(op); + Py_ssize_t position, seqsize; + + if (ro->seq == NULL) +@@ -463,8 +474,9 @@ + PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it))."); + + static PyObject * +-reversed_reduce(reversedobject *ro, PyObject *Py_UNUSED(ignored)) ++reversed_reduce(PyObject *op, PyObject *Py_UNUSED(ignored)) + { ++ reversedobject *ro = _reversedobject_CAST(op); + if (ro->seq) + return Py_BuildValue("O(O)n", Py_TYPE(ro), ro->seq, ro->index); + else +@@ -472,8 +484,9 @@ + } + + static PyObject * +-reversed_setstate(reversedobject *ro, PyObject *state) ++reversed_setstate(PyObject *op, PyObject *state) + { ++ reversedobject *ro = _reversedobject_CAST(op); + Py_ssize_t index = PyLong_AsSsize_t(state); + if (index == -1 && PyErr_Occurred()) + return NULL; +@@ -493,9 +506,9 @@ + PyDoc_STRVAR(setstate_doc, "Set state information for unpickling."); + + static PyMethodDef reversediter_methods[] = { +- {"__length_hint__", (PyCFunction)reversed_len, METH_NOARGS, length_hint_doc}, +- {"__reduce__", (PyCFunction)reversed_reduce, METH_NOARGS, reduce_doc}, +- {"__setstate__", (PyCFunction)reversed_setstate, METH_O, setstate_doc}, ++ {"__length_hint__", reversed_len, METH_NOARGS, length_hint_doc}, ++ {"__reduce__", reversed_reduce, METH_NOARGS, reduce_doc}, ++ {"__setstate__", reversed_setstate, METH_O, setstate_doc}, + {NULL, NULL} /* sentinel */ + }; + +@@ -505,7 +518,7 @@ + sizeof(reversedobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ +- (destructor)reversed_dealloc, /* tp_dealloc */ ++ reversed_dealloc, /* tp_dealloc */ + 0, /* tp_vectorcall_offset */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ +@@ -523,12 +536,12 @@ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + reversed_new__doc__, /* tp_doc */ +- (traverseproc)reversed_traverse,/* tp_traverse */ ++ reversed_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ +- (iternextfunc)reversed_next, /* tp_iternext */ ++ reversed_next, /* tp_iternext */ + reversediter_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ +@@ -541,5 +554,5 @@ + PyType_GenericAlloc, /* tp_alloc */ + reversed_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +- .tp_vectorcall = (vectorcallfunc)reversed_vectorcall, ++ .tp_vectorcall = reversed_vectorcall, + }; +diff --git a/Objects/exceptions.c b/Objects/exceptions.c +index 6880c24196c..154cde93168 100644 +--- a/Objects/exceptions.c ++++ b/Objects/exceptions.c +@@ -16,6 +16,14 @@ + + #include "osdefs.h" // SEP + ++#include "clinic/exceptions.c.h" ++ ++/*[clinic input] ++class BaseException "PyBaseExceptionObject *" "&PyExc_BaseException" ++class BaseExceptionGroup "PyBaseExceptionGroupObject *" "&PyExc_BaseExceptionGroup" ++[clinic start generated code]*/ ++/*[clinic end generated code: output=da39a3ee5e6b4b0d input=b7c45e78cff8edc3]*/ ++ + + /* Compatibility aliases */ + PyObject *PyExc_EnvironmentError = NULL; // borrowed ref +@@ -152,30 +160,50 @@ + static PyObject * + BaseException_str(PyBaseExceptionObject *self) + { ++ PyObject *res; ++ Py_BEGIN_CRITICAL_SECTION(self); + switch (PyTuple_GET_SIZE(self->args)) { + case 0: +- return Py_GetConstant(Py_CONSTANT_EMPTY_STR); ++ res = Py_GetConstant(Py_CONSTANT_EMPTY_STR); ++ break; + case 1: +- return PyObject_Str(PyTuple_GET_ITEM(self->args, 0)); ++ res = PyObject_Str(PyTuple_GET_ITEM(self->args, 0)); ++ break; + default: +- return PyObject_Str(self->args); ++ res = PyObject_Str(self->args); ++ break; + } ++ Py_END_CRITICAL_SECTION(); ++ return res; + } + + static PyObject * + BaseException_repr(PyBaseExceptionObject *self) + { ++ PyObject *res; ++ Py_BEGIN_CRITICAL_SECTION(self); + const char *name = _PyType_Name(Py_TYPE(self)); +- if (PyTuple_GET_SIZE(self->args) == 1) +- return PyUnicode_FromFormat("%s(%R)", name, ++ if (PyTuple_GET_SIZE(self->args) == 1) { ++ res = PyUnicode_FromFormat("%s(%R)", name, + PyTuple_GET_ITEM(self->args, 0)); +- else +- return PyUnicode_FromFormat("%s%R", name, self->args); ++ } ++ else { ++ res = PyUnicode_FromFormat("%s%R", name, self->args); ++ } ++ Py_END_CRITICAL_SECTION(); ++ return res; + } + + /* Pickling support */ ++ ++/*[clinic input] ++@critical_section ++BaseException.__reduce__ ++[clinic start generated code]*/ ++ + static PyObject * +-BaseException_reduce(PyBaseExceptionObject *self, PyObject *Py_UNUSED(ignored)) ++BaseException___reduce___impl(PyBaseExceptionObject *self) ++/*[clinic end generated code: output=af87c1247ef98748 input=283be5a10d9c964f]*/ + { + if (self->args && self->dict) + return PyTuple_Pack(3, Py_TYPE(self), self->args, self->dict); +@@ -188,8 +216,17 @@ + * all their attributes in the __dict__. Code is taken from cPickle's + * load_build function. + */ ++ ++/*[clinic input] ++@critical_section ++BaseException.__setstate__ ++ state: object ++ / ++[clinic start generated code]*/ ++ + static PyObject * +-BaseException_setstate(PyObject *self, PyObject *state) ++BaseException___setstate___impl(PyBaseExceptionObject *self, PyObject *state) ++/*[clinic end generated code: output=f3834889950453ab input=5524b61cfe9b9856]*/ + { + PyObject *d_key, *d_value; + Py_ssize_t i = 0; +@@ -202,7 +239,7 @@ + while (PyDict_Next(state, &i, &d_key, &d_value)) { + Py_INCREF(d_key); + Py_INCREF(d_value); +- int res = PyObject_SetAttr(self, d_key, d_value); ++ int res = PyObject_SetAttr((PyObject *)self, d_key, d_value); + Py_DECREF(d_value); + Py_DECREF(d_key); + if (res < 0) { +@@ -213,18 +250,26 @@ + Py_RETURN_NONE; + } + ++ ++/*[clinic input] ++@critical_section ++BaseException.with_traceback ++ tb: object ++ / ++ ++Set self.__traceback__ to tb and return self. ++[clinic start generated code]*/ ++ + static PyObject * +-BaseException_with_traceback(PyObject *self, PyObject *tb) { +- if (PyException_SetTraceback(self, tb)) ++BaseException_with_traceback_impl(PyBaseExceptionObject *self, PyObject *tb) ++/*[clinic end generated code: output=81e92f2387927f10 input=b5fb64d834717e36]*/ ++{ ++ if (BaseException___traceback___set_impl(self, tb) < 0){ + return NULL; +- ++ } + return Py_NewRef(self); + } + +-PyDoc_STRVAR(with_traceback_doc, +-"Exception.with_traceback(tb) --\n\ +- set self.__traceback__ to tb and return self."); +- + static inline PyBaseExceptionObject* + _PyBaseExceptionObject_cast(PyObject *exc) + { +@@ -232,18 +277,21 @@ + return (PyBaseExceptionObject *)exc; + } + ++/*[clinic input] ++@critical_section ++BaseException.add_note ++ note: object(subclass_of="&PyUnicode_Type") ++ / ++ ++Add a note to the exception ++[clinic start generated code]*/ ++ + static PyObject * +-BaseException_add_note(PyObject *self, PyObject *note) ++BaseException_add_note_impl(PyBaseExceptionObject *self, PyObject *note) ++/*[clinic end generated code: output=fb7cbcba611c187b input=e60a6b6e9596acaf]*/ + { +- if (!PyUnicode_Check(note)) { +- PyErr_Format(PyExc_TypeError, +- "note must be a str, not '%s'", +- Py_TYPE(note)->tp_name); +- return NULL; +- } +- + PyObject *notes; +- if (PyObject_GetOptionalAttr(self, &_Py_ID(__notes__), ¬es) < 0) { ++ if (PyObject_GetOptionalAttr((PyObject *)self, &_Py_ID(__notes__), ¬es) < 0) { + return NULL; + } + if (notes == NULL) { +@@ -251,7 +299,7 @@ + if (notes == NULL) { + return NULL; + } +- if (PyObject_SetAttr(self, &_Py_ID(__notes__), notes) < 0) { ++ if (PyObject_SetAttr((PyObject *)self, &_Py_ID(__notes__), notes) < 0) { + Py_DECREF(notes); + return NULL; + } +@@ -269,22 +317,23 @@ + Py_RETURN_NONE; + } + +-PyDoc_STRVAR(add_note_doc, +-"Exception.add_note(note) --\n\ +- add a note to the exception"); +- + static PyMethodDef BaseException_methods[] = { +- {"__reduce__", (PyCFunction)BaseException_reduce, METH_NOARGS }, +- {"__setstate__", (PyCFunction)BaseException_setstate, METH_O }, +- {"with_traceback", (PyCFunction)BaseException_with_traceback, METH_O, +- with_traceback_doc}, +- {"add_note", (PyCFunction)BaseException_add_note, METH_O, +- add_note_doc}, +- {NULL, NULL, 0, NULL}, ++ BASEEXCEPTION___REDUCE___METHODDEF ++ BASEEXCEPTION___SETSTATE___METHODDEF ++ BASEEXCEPTION_WITH_TRACEBACK_METHODDEF ++ BASEEXCEPTION_ADD_NOTE_METHODDEF ++ {NULL, NULL, 0, NULL}, + }; + ++/*[clinic input] ++@critical_section ++@getter ++BaseException.args ++[clinic start generated code]*/ ++ + static PyObject * +-BaseException_get_args(PyBaseExceptionObject *self, void *Py_UNUSED(ignored)) ++BaseException_args_get_impl(PyBaseExceptionObject *self) ++/*[clinic end generated code: output=e02e34e35cf4d677 input=64282386e4d7822d]*/ + { + if (self->args == NULL) { + Py_RETURN_NONE; +@@ -292,23 +341,37 @@ + return Py_NewRef(self->args); + } + ++/*[clinic input] ++@critical_section ++@setter ++BaseException.args ++[clinic start generated code]*/ ++ + static int +-BaseException_set_args(PyBaseExceptionObject *self, PyObject *val, void *Py_UNUSED(ignored)) ++BaseException_args_set_impl(PyBaseExceptionObject *self, PyObject *value) ++/*[clinic end generated code: output=331137e11d8f9e80 input=2400047ea5970a84]*/ + { + PyObject *seq; +- if (val == NULL) { ++ if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "args may not be deleted"); + return -1; + } +- seq = PySequence_Tuple(val); ++ seq = PySequence_Tuple(value); + if (!seq) + return -1; + Py_XSETREF(self->args, seq); + return 0; + } + ++/*[clinic input] ++@critical_section ++@getter ++BaseException.__traceback__ ++[clinic start generated code]*/ ++ + static PyObject * +-BaseException_get_tb(PyBaseExceptionObject *self, void *Py_UNUSED(ignored)) ++BaseException___traceback___get_impl(PyBaseExceptionObject *self) ++/*[clinic end generated code: output=17cf874a52339398 input=a2277f0de62170cf]*/ + { + if (self->traceback == NULL) { + Py_RETURN_NONE; +@@ -316,17 +379,26 @@ + return Py_NewRef(self->traceback); + } + ++ ++/*[clinic input] ++@critical_section ++@setter ++BaseException.__traceback__ ++[clinic start generated code]*/ ++ + static int +-BaseException_set_tb(PyBaseExceptionObject *self, PyObject *tb, void *Py_UNUSED(ignored)) ++BaseException___traceback___set_impl(PyBaseExceptionObject *self, ++ PyObject *value) ++/*[clinic end generated code: output=a82c86d9f29f48f0 input=12676035676badad]*/ + { +- if (tb == NULL) { ++ if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "__traceback__ may not be deleted"); + return -1; + } +- if (PyTraceBack_Check(tb)) { +- Py_XSETREF(self->traceback, Py_NewRef(tb)); ++ if (PyTraceBack_Check(value)) { ++ Py_XSETREF(self->traceback, Py_NewRef(value)); + } +- else if (tb == Py_None) { ++ else if (value == Py_None) { + Py_CLEAR(self->traceback); + } + else { +@@ -337,73 +409,100 @@ + return 0; + } + ++/*[clinic input] ++@critical_section ++@getter ++BaseException.__context__ ++[clinic start generated code]*/ ++ + static PyObject * +-BaseException_get_context(PyObject *self, void *Py_UNUSED(ignored)) ++BaseException___context___get_impl(PyBaseExceptionObject *self) ++/*[clinic end generated code: output=6ec5d296ce8d1c93 input=b2d22687937e66ab]*/ + { +- PyObject *res = PyException_GetContext(self); +- if (res) +- return res; /* new reference already returned above */ +- Py_RETURN_NONE; ++ if (self->context == NULL) { ++ Py_RETURN_NONE; ++ } ++ return Py_NewRef(self->context); + } + ++/*[clinic input] ++@critical_section ++@setter ++BaseException.__context__ ++[clinic start generated code]*/ ++ + static int +-BaseException_set_context(PyObject *self, PyObject *arg, void *Py_UNUSED(ignored)) ++BaseException___context___set_impl(PyBaseExceptionObject *self, ++ PyObject *value) ++/*[clinic end generated code: output=b4cb52dcca1da3bd input=c0971adf47fa1858]*/ + { +- if (arg == NULL) { ++ if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "__context__ may not be deleted"); + return -1; +- } else if (arg == Py_None) { +- arg = NULL; +- } else if (!PyExceptionInstance_Check(arg)) { ++ } else if (value == Py_None) { ++ value = NULL; ++ } else if (!PyExceptionInstance_Check(value)) { + PyErr_SetString(PyExc_TypeError, "exception context must be None " + "or derive from BaseException"); + return -1; + } else { +- /* PyException_SetContext steals this reference */ +- Py_INCREF(arg); ++ Py_INCREF(value); + } +- PyException_SetContext(self, arg); ++ Py_XSETREF(self->context, value); + return 0; + } + ++/*[clinic input] ++@critical_section ++@getter ++BaseException.__cause__ ++[clinic start generated code]*/ ++ + static PyObject * +-BaseException_get_cause(PyObject *self, void *Py_UNUSED(ignored)) ++BaseException___cause___get_impl(PyBaseExceptionObject *self) ++/*[clinic end generated code: output=987f6c4d8a0bdbab input=40e0eac427b6e602]*/ + { +- PyObject *res = PyException_GetCause(self); +- if (res) +- return res; /* new reference already returned above */ +- Py_RETURN_NONE; ++ if (self->cause == NULL) { ++ Py_RETURN_NONE; ++ } ++ return Py_NewRef(self->cause); + } + ++/*[clinic input] ++@critical_section ++@setter ++BaseException.__cause__ ++[clinic start generated code]*/ ++ + static int +-BaseException_set_cause(PyObject *self, PyObject *arg, void *Py_UNUSED(ignored)) ++BaseException___cause___set_impl(PyBaseExceptionObject *self, ++ PyObject *value) ++/*[clinic end generated code: output=6161315398aaf541 input=e1b403c0bde3f62a]*/ + { +- if (arg == NULL) { ++ if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "__cause__ may not be deleted"); + return -1; +- } else if (arg == Py_None) { +- arg = NULL; +- } else if (!PyExceptionInstance_Check(arg)) { ++ } else if (value == Py_None) { ++ value = NULL; ++ } else if (!PyExceptionInstance_Check(value)) { + PyErr_SetString(PyExc_TypeError, "exception cause must be None " + "or derive from BaseException"); + return -1; + } else { + /* PyException_SetCause steals this reference */ +- Py_INCREF(arg); ++ Py_INCREF(value); + } +- PyException_SetCause(self, arg); ++ PyException_SetCause((PyObject *)self, value); + return 0; + } + + + static PyGetSetDef BaseException_getset[] = { + {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict}, +- {"args", (getter)BaseException_get_args, (setter)BaseException_set_args}, +- {"__traceback__", (getter)BaseException_get_tb, (setter)BaseException_set_tb}, +- {"__context__", BaseException_get_context, +- BaseException_set_context, PyDoc_STR("exception context")}, +- {"__cause__", BaseException_get_cause, +- BaseException_set_cause, PyDoc_STR("exception cause")}, ++ BASEEXCEPTION_ARGS_GETSETDEF ++ BASEEXCEPTION___TRACEBACK___GETSETDEF ++ BASEEXCEPTION___CONTEXT___GETSETDEF ++ BASEEXCEPTION___CAUSE___GETSETDEF + {NULL}, + }; + +@@ -411,59 +510,81 @@ + PyObject * + PyException_GetTraceback(PyObject *self) + { +- PyBaseExceptionObject *base_self = _PyBaseExceptionObject_cast(self); +- return Py_XNewRef(base_self->traceback); ++ PyObject *traceback; ++ Py_BEGIN_CRITICAL_SECTION(self); ++ traceback = Py_XNewRef(_PyBaseExceptionObject_cast(self)->traceback); ++ Py_END_CRITICAL_SECTION(); ++ return traceback; + } + + + int + PyException_SetTraceback(PyObject *self, PyObject *tb) + { +- return BaseException_set_tb(_PyBaseExceptionObject_cast(self), tb, NULL); ++ int res; ++ Py_BEGIN_CRITICAL_SECTION(self); ++ res = BaseException___traceback___set_impl(_PyBaseExceptionObject_cast(self), tb); ++ Py_END_CRITICAL_SECTION(); ++ return res; + } + + PyObject * + PyException_GetCause(PyObject *self) + { +- PyObject *cause = _PyBaseExceptionObject_cast(self)->cause; +- return Py_XNewRef(cause); ++ PyObject *cause; ++ Py_BEGIN_CRITICAL_SECTION(self); ++ cause = Py_XNewRef(_PyBaseExceptionObject_cast(self)->cause); ++ Py_END_CRITICAL_SECTION(); ++ return cause; + } + + /* Steals a reference to cause */ + void + PyException_SetCause(PyObject *self, PyObject *cause) + { ++ Py_BEGIN_CRITICAL_SECTION(self); + PyBaseExceptionObject *base_self = _PyBaseExceptionObject_cast(self); + base_self->suppress_context = 1; + Py_XSETREF(base_self->cause, cause); ++ Py_END_CRITICAL_SECTION(); + } + + PyObject * + PyException_GetContext(PyObject *self) + { +- PyObject *context = _PyBaseExceptionObject_cast(self)->context; +- return Py_XNewRef(context); ++ PyObject *context; ++ Py_BEGIN_CRITICAL_SECTION(self); ++ context = Py_XNewRef(_PyBaseExceptionObject_cast(self)->context); ++ Py_END_CRITICAL_SECTION(); ++ return context; + } + + /* Steals a reference to context */ + void + PyException_SetContext(PyObject *self, PyObject *context) + { ++ Py_BEGIN_CRITICAL_SECTION(self); + Py_XSETREF(_PyBaseExceptionObject_cast(self)->context, context); ++ Py_END_CRITICAL_SECTION(); + } + + PyObject * + PyException_GetArgs(PyObject *self) + { +- PyObject *args = _PyBaseExceptionObject_cast(self)->args; +- return Py_NewRef(args); ++ PyObject *args; ++ Py_BEGIN_CRITICAL_SECTION(self); ++ args = Py_NewRef(_PyBaseExceptionObject_cast(self)->args); ++ Py_END_CRITICAL_SECTION(); ++ return args; + } + + void + PyException_SetArgs(PyObject *self, PyObject *args) + { ++ Py_BEGIN_CRITICAL_SECTION(self); + Py_INCREF(args); + Py_XSETREF(_PyBaseExceptionObject_cast(self)->args, args); ++ Py_END_CRITICAL_SECTION(); + } + + const char * +@@ -914,10 +1035,18 @@ + self->msg, num_excs, num_excs > 1 ? "s" : ""); + } + ++/*[clinic input] ++@critical_section ++BaseExceptionGroup.derive ++ excs: object ++ / ++[clinic start generated code]*/ ++ + static PyObject * +-BaseExceptionGroup_derive(PyObject *self_, PyObject *excs) ++BaseExceptionGroup_derive_impl(PyBaseExceptionGroupObject *self, ++ PyObject *excs) ++/*[clinic end generated code: output=4307564218dfbf06 input=f72009d38e98cec1]*/ + { +- PyBaseExceptionGroupObject *self = _PyBaseExceptionGroupObject_cast(self_); + PyObject *init_args = PyTuple_Pack(2, self->msg, excs); + if (!init_args) { + return NULL; +@@ -1210,8 +1339,17 @@ + return retval; + } + ++/*[clinic input] ++@critical_section ++BaseExceptionGroup.split ++ matcher_value: object ++ / ++[clinic start generated code]*/ ++ + static PyObject * +-BaseExceptionGroup_split(PyObject *self, PyObject *matcher_value) ++BaseExceptionGroup_split_impl(PyBaseExceptionGroupObject *self, ++ PyObject *matcher_value) ++/*[clinic end generated code: output=d74db579da4df6e2 input=0c5cfbfed57e0052]*/ + { + _exceptiongroup_split_matcher_type matcher_type; + if (get_matcher_type(matcher_value, &matcher_type) < 0) { +@@ -1221,7 +1359,7 @@ + _exceptiongroup_split_result split_result; + bool construct_rest = true; + if (exceptiongroup_split_recursive( +- self, matcher_type, matcher_value, ++ (PyObject *)self, matcher_type, matcher_value, + construct_rest, &split_result) < 0) { + return NULL; + } +@@ -1236,8 +1374,17 @@ + return result; + } + ++/*[clinic input] ++@critical_section ++BaseExceptionGroup.subgroup ++ matcher_value: object ++ / ++[clinic start generated code]*/ ++ + static PyObject * +-BaseExceptionGroup_subgroup(PyObject *self, PyObject *matcher_value) ++BaseExceptionGroup_subgroup_impl(PyBaseExceptionGroupObject *self, ++ PyObject *matcher_value) ++/*[clinic end generated code: output=07dbec8f77d4dd8e input=988ffdd755a151ce]*/ + { + _exceptiongroup_split_matcher_type matcher_type; + if (get_matcher_type(matcher_value, &matcher_type) < 0) { +@@ -1247,7 +1394,7 @@ + _exceptiongroup_split_result split_result; + bool construct_rest = false; + if (exceptiongroup_split_recursive( +- self, matcher_type, matcher_value, ++ (PyObject *)self, matcher_type, matcher_value, + construct_rest, &split_result) < 0) { + return NULL; + } +@@ -1513,9 +1660,9 @@ + static PyMethodDef BaseExceptionGroup_methods[] = { + {"__class_getitem__", (PyCFunction)Py_GenericAlias, + METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, +- {"derive", (PyCFunction)BaseExceptionGroup_derive, METH_O}, +- {"split", (PyCFunction)BaseExceptionGroup_split, METH_O}, +- {"subgroup", (PyCFunction)BaseExceptionGroup_subgroup, METH_O}, ++ BASEEXCEPTIONGROUP_DERIVE_METHODDEF ++ BASEEXCEPTIONGROUP_SPLIT_METHODDEF ++ BASEEXCEPTIONGROUP_SUBGROUP_METHODDEF + {NULL} + }; + +@@ -2667,55 +2814,177 @@ + SimpleExtendsException(PyExc_ValueError, UnicodeError, + "Unicode related error."); + ++ ++/* ++ * Check the validity of 'attr' as a unicode or bytes object depending ++ * on 'as_bytes' and return a new reference on it if it is the case. ++ * ++ * The 'name' is the attribute name and is only used for error reporting. ++ * ++ * On success, this returns a strong reference on 'attr'. ++ * On failure, this sets a TypeError and returns NULL. ++ */ + static PyObject * +-get_bytes(PyObject *attr, const char *name) ++as_unicode_error_attribute(PyObject *attr, const char *name, int as_bytes) + { +- if (!attr) { +- PyErr_Format(PyExc_TypeError, "%.200s attribute not set", name); ++ assert(as_bytes == 0 || as_bytes == 1); ++ if (attr == NULL) { ++ PyErr_Format(PyExc_TypeError, "%s attribute not set", name); + return NULL; + } +- +- if (!PyBytes_Check(attr)) { +- PyErr_Format(PyExc_TypeError, "%.200s attribute must be bytes", name); ++ if (!(as_bytes ? PyBytes_Check(attr) : PyUnicode_Check(attr))) { ++ PyErr_Format(PyExc_TypeError, ++ "%s attribute must be %s", ++ name, ++ as_bytes ? "bytes" : "unicode"); + return NULL; + } + return Py_NewRef(attr); + } + +-static PyObject * +-get_unicode(PyObject *attr, const char *name) +-{ +- if (!attr) { +- PyErr_Format(PyExc_TypeError, "%.200s attribute not set", name); +- return NULL; +- } + +- if (!PyUnicode_Check(attr)) { ++#define PyUnicodeError_Check(PTR) \ ++ PyObject_TypeCheck((PTR), (PyTypeObject *)PyExc_UnicodeError) ++#define PyUnicodeError_CAST(PTR) \ ++ (assert(PyUnicodeError_Check(PTR)), ((PyUnicodeErrorObject *)(PTR))) ++ ++ ++/* class names to use when reporting errors */ ++#define Py_UNICODE_ENCODE_ERROR_NAME "UnicodeEncodeError" ++#define Py_UNICODE_DECODE_ERROR_NAME "UnicodeDecodeError" ++#define Py_UNICODE_TRANSLATE_ERROR_NAME "UnicodeTranslateError" ++ ++ ++/* ++ * Check that 'self' is a UnicodeError object. ++ * ++ * On success, this returns 0. ++ * On failure, this sets a TypeError exception and returns -1. ++ * ++ * The 'expect_type' is the name of the expected type, which is ++ * only used for error reporting. ++ * ++ * As an implementation detail, the `PyUnicode*Error_*` functions ++ * currently allow *any* subclass of UnicodeError as 'self'. ++ * ++ * Use one of the `Py_UNICODE_*_ERROR_NAME` macros to avoid typos. ++ */ ++static inline int ++check_unicode_error_type(PyObject *self, const char *expect_type) ++{ ++ assert(self != NULL); ++ if (!PyUnicodeError_Check(self)) { + PyErr_Format(PyExc_TypeError, +- "%.200s attribute must be unicode", name); +- return NULL; ++ "expecting a %s object, got %T", expect_type, self); ++ return -1; + } +- return Py_NewRef(attr); ++ return 0; + } + +-static int +-set_unicodefromstring(PyObject **attr, const char *value) ++ ++// --- PyUnicodeEncodeObject: internal helpers -------------------------------- ++// ++// In the helpers below, the caller is responsible to ensure that 'self' ++// is a PyUnicodeErrorObject, although this is verified on DEBUG builds ++// through PyUnicodeError_CAST(). ++ ++/* ++ * Return the underlying (str) 'encoding' attribute of a UnicodeError object. ++ */ ++static inline PyObject * ++unicode_error_get_encoding_impl(PyObject *self) ++{ ++ assert(self != NULL); ++ PyUnicodeErrorObject *exc = PyUnicodeError_CAST(self); ++ return as_unicode_error_attribute(exc->encoding, "encoding", false); ++} ++ ++ ++/* ++ * Return the underlying 'object' attribute of a UnicodeError object ++ * as a bytes or a string instance, depending on the 'as_bytes' flag. ++ */ ++static inline PyObject * ++unicode_error_get_object_impl(PyObject *self, int as_bytes) ++{ ++ assert(self != NULL); ++ PyUnicodeErrorObject *exc = PyUnicodeError_CAST(self); ++ return as_unicode_error_attribute(exc->object, "object", as_bytes); ++} ++ ++ ++/* ++ * Return the underlying (str) 'reason' attribute of a UnicodeError object. ++ */ ++static inline PyObject * ++unicode_error_get_reason_impl(PyObject *self) ++{ ++ assert(self != NULL); ++ PyUnicodeErrorObject *exc = PyUnicodeError_CAST(self); ++ return as_unicode_error_attribute(exc->reason, "reason", false); ++} ++ ++ ++/* ++ * Set the underlying (str) 'reason' attribute of a UnicodeError object. ++ * ++ * Return 0 on success and -1 on failure. ++ */ ++static inline int ++unicode_error_set_reason_impl(PyObject *self, const char *reason) + { +- PyObject *obj = PyUnicode_FromString(value); +- if (!obj) ++ assert(self != NULL); ++ PyObject *value = PyUnicode_FromString(reason); ++ if (value == NULL) { + return -1; +- Py_XSETREF(*attr, obj); ++ } ++ PyUnicodeErrorObject *exc = PyUnicodeError_CAST(self); ++ Py_XSETREF(exc->reason, value); + return 0; + } + ++ ++/* ++ * Set the 'start' attribute of a UnicodeError object. ++ * ++ * Return 0 on success and -1 on failure. ++ */ ++static inline int ++unicode_error_set_start_impl(PyObject *self, Py_ssize_t start) ++{ ++ assert(self != NULL); ++ PyUnicodeErrorObject *exc = PyUnicodeError_CAST(self); ++ exc->start = start; ++ return 0; ++} ++ ++ ++/* ++ * Set the 'end' attribute of a UnicodeError object. ++ * ++ * Return 0 on success and -1 on failure. ++ */ ++static inline int ++unicode_error_set_end_impl(PyObject *self, Py_ssize_t end) ++{ ++ assert(self != NULL); ++ PyUnicodeErrorObject *exc = PyUnicodeError_CAST(self); ++ exc->end = end; ++ return 0; ++} ++ ++// --- PyUnicodeEncodeObject: internal getters -------------------------------- ++ + /* + * Adjust the (inclusive) 'start' value of a UnicodeError object. + * + * The 'start' can be negative or not, but when adjusting the value, + * we clip it in [0, max(0, objlen - 1)] and do not interpret it as + * a relative offset. ++ * ++ * This function always succeeds. + */ +-static inline Py_ssize_t ++static Py_ssize_t + unicode_error_adjust_start(Py_ssize_t start, Py_ssize_t objlen) + { + assert(objlen >= 0); +@@ -2728,14 +2997,35 @@ + return start; + } + ++ ++/* Assert some properties of the adjusted 'start' value. */ ++#ifndef NDEBUG ++static void ++assert_adjusted_unicode_error_start(Py_ssize_t start, Py_ssize_t objlen) ++{ ++ assert(objlen >= 0); ++ /* in the future, `min_start` may be something else */ ++ Py_ssize_t min_start = 0; ++ assert(start >= min_start); ++ /* in the future, `max_start` may be something else */ ++ Py_ssize_t max_start = Py_MAX(min_start, objlen - 1); ++ assert(start <= max_start); ++} ++#else ++#define assert_adjusted_unicode_error_start(...) ++#endif ++ ++ + /* + * Adjust the (exclusive) 'end' value of a UnicodeError object. + * + * The 'end' can be negative or not, but when adjusting the value, + * we clip it in [min(1, objlen), max(min(1, objlen), objlen)] and + * do not interpret it as a relative offset. ++ * ++ * This function always succeeds. + */ +-static inline Py_ssize_t ++static Py_ssize_t + unicode_error_adjust_end(Py_ssize_t end, Py_ssize_t objlen) + { + assert(objlen >= 0); +@@ -2748,134 +3038,233 @@ + return end; + } + +-#define _PyUnicodeError_CAST(PTR) ((PyUnicodeErrorObject *)(PTR)) +-#define PyUnicodeError_Check(PTR) \ +- PyObject_TypeCheck((PTR), (PyTypeObject *)PyExc_UnicodeError) +-#define PyUnicodeError_CAST(PTR) \ +- (assert(PyUnicodeError_Check(PTR)), _PyUnicodeError_CAST(PTR)) + ++/* Assert some properties of the adjusted 'end' value. */ ++#ifndef NDEBUG ++static void ++assert_adjusted_unicode_error_end(Py_ssize_t end, Py_ssize_t objlen) ++{ ++ assert(objlen >= 0); ++ /* in the future, `min_end` may be something else */ ++ Py_ssize_t min_end = Py_MIN(1, objlen); ++ assert(end >= min_end); ++ /* in the future, `max_end` may be something else */ ++ Py_ssize_t max_end = Py_MAX(min_end, objlen); ++ assert(end <= max_end); ++} ++#else ++#define assert_adjusted_unicode_error_end(...) ++#endif + +-static inline int +-check_unicode_error_type(PyObject *self, const char *expect_type) ++ ++/* ++ * Adjust the length of the range described by a UnicodeError object. ++ * ++ * The 'start' and 'end' arguments must have been obtained by ++ * unicode_error_adjust_start() and unicode_error_adjust_end(). ++ * ++ * The result is clipped in [0, objlen]. By construction, it ++ * will always be smaller than 'objlen' as 'start' and 'end' ++ * are smaller than 'objlen'. ++ */ ++static Py_ssize_t ++unicode_error_adjust_len(Py_ssize_t start, Py_ssize_t end, Py_ssize_t objlen) + { +- if (!PyUnicodeError_Check(self)) { +- PyErr_Format(PyExc_TypeError, +- "expecting a %s object, got %T", expect_type, self); ++ assert_adjusted_unicode_error_start(start, objlen); ++ assert_adjusted_unicode_error_end(end, objlen); ++ Py_ssize_t ranlen = end - start; ++ assert(ranlen <= objlen); ++ return ranlen < 0 ? 0 : ranlen; ++} ++ ++ ++/* Assert some properties of the adjusted range 'len' value. */ ++#ifndef NDEBUG ++static void ++assert_adjusted_unicode_error_len(Py_ssize_t ranlen, Py_ssize_t objlen) ++{ ++ assert(objlen >= 0); ++ assert(ranlen >= 0); ++ assert(ranlen <= objlen); ++} ++#else ++#define assert_adjusted_unicode_error_len(...) ++#endif ++ ++ ++/* ++ * Get various common parameters of a UnicodeError object. ++ * ++ * The caller is responsible to ensure that 'self' is a PyUnicodeErrorObject, ++ * although this condition is verified by this function on DEBUG builds. ++ * ++ * Return 0 on success and -1 on failure. ++ * ++ * Output parameters: ++ * ++ * obj A strong reference to the 'object' attribute. ++ * objlen The 'object' length. ++ * start The clipped 'start' attribute. ++ * end The clipped 'end' attribute. ++ * slen The length of the slice described by the clipped 'start' ++ * and 'end' values. It always lies in [0, objlen]. ++ * ++ * An output parameter can be NULL to indicate that ++ * the corresponding value does not need to be stored. ++ * ++ * Input parameter: ++ * ++ * as_bytes If true, the error's 'object' attribute must be a `bytes`, ++ * i.e. 'self' is a `UnicodeDecodeError` instance. Otherwise, ++ * the 'object' attribute must be a string. ++ * ++ * A TypeError is raised if the 'object' type is incompatible. ++ */ ++int ++_PyUnicodeError_GetParams(PyObject *self, ++ PyObject **obj, Py_ssize_t *objlen, ++ Py_ssize_t *start, Py_ssize_t *end, Py_ssize_t *slen, ++ int as_bytes) ++{ ++ assert(self != NULL); ++ assert(as_bytes == 0 || as_bytes == 1); ++ PyUnicodeErrorObject *exc = PyUnicodeError_CAST(self); ++ PyObject *r = as_unicode_error_attribute(exc->object, "object", as_bytes); ++ if (r == NULL) { + return -1; + } ++ ++ Py_ssize_t n = as_bytes ? PyBytes_GET_SIZE(r) : PyUnicode_GET_LENGTH(r); ++ if (objlen != NULL) { ++ *objlen = n; ++ } ++ ++ Py_ssize_t start_value = -1; ++ if (start != NULL || slen != NULL) { ++ start_value = unicode_error_adjust_start(exc->start, n); ++ } ++ if (start != NULL) { ++ assert_adjusted_unicode_error_start(start_value, n); ++ *start = start_value; ++ } ++ ++ Py_ssize_t end_value = -1; ++ if (end != NULL || slen != NULL) { ++ end_value = unicode_error_adjust_end(exc->end, n); ++ } ++ if (end != NULL) { ++ assert_adjusted_unicode_error_end(end_value, n); ++ *end = end_value; ++ } ++ ++ if (slen != NULL) { ++ *slen = unicode_error_adjust_len(start_value, end_value, n); ++ assert_adjusted_unicode_error_len(*slen, n); ++ } ++ ++ if (obj != NULL) { ++ *obj = r; ++ } ++ else { ++ Py_DECREF(r); ++ } + return 0; + } + + +-static inline PyUnicodeErrorObject * +-as_unicode_error(PyObject *self, const char *expect_type) +-{ +- int rc = check_unicode_error_type(self, expect_type); +- return rc < 0 ? NULL : _PyUnicodeError_CAST(self); +-} ++// --- PyUnicodeEncodeObject: 'encoding' getters ------------------------------ ++// Note: PyUnicodeTranslateError does not have an 'encoding' attribute. + + PyObject * + PyUnicodeEncodeError_GetEncoding(PyObject *self) + { +- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeEncodeError"); +- return exc == NULL ? NULL : get_unicode(exc->encoding, "encoding"); ++ int rc = check_unicode_error_type(self, Py_UNICODE_ENCODE_ERROR_NAME); ++ return rc < 0 ? NULL : unicode_error_get_encoding_impl(self); + } + ++ + PyObject * + PyUnicodeDecodeError_GetEncoding(PyObject *self) + { +- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeDecodeError"); +- return exc == NULL ? NULL : get_unicode(exc->encoding, "encoding"); ++ int rc = check_unicode_error_type(self, Py_UNICODE_DECODE_ERROR_NAME); ++ return rc < 0 ? NULL : unicode_error_get_encoding_impl(self); + } + ++ ++// --- PyUnicodeEncodeObject: 'object' getters -------------------------------- ++ + PyObject * + PyUnicodeEncodeError_GetObject(PyObject *self) + { +- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeEncodeError"); +- return exc == NULL ? NULL : get_unicode(exc->object, "object"); ++ int rc = check_unicode_error_type(self, Py_UNICODE_ENCODE_ERROR_NAME); ++ return rc < 0 ? NULL : unicode_error_get_object_impl(self, false); + } + ++ + PyObject * + PyUnicodeDecodeError_GetObject(PyObject *self) + { +- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeDecodeError"); +- return exc == NULL ? NULL : get_bytes(exc->object, "object"); ++ int rc = check_unicode_error_type(self, Py_UNICODE_DECODE_ERROR_NAME); ++ return rc < 0 ? NULL : unicode_error_get_object_impl(self, true); + } + ++ + PyObject * + PyUnicodeTranslateError_GetObject(PyObject *self) + { +- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeTranslateError"); +- return exc == NULL ? NULL : get_unicode(exc->object, "object"); ++ int rc = check_unicode_error_type(self, Py_UNICODE_TRANSLATE_ERROR_NAME); ++ return rc < 0 ? NULL : unicode_error_get_object_impl(self, false); ++} ++ ++ ++// --- PyUnicodeEncodeObject: 'start' getters --------------------------------- ++ ++/* ++ * Specialization of _PyUnicodeError_GetParams() for the 'start' attribute. ++ * ++ * The caller is responsible to ensure that 'self' is a PyUnicodeErrorObject, ++ * although this condition is verified by this function on DEBUG builds. ++ */ ++static inline int ++unicode_error_get_start_impl(PyObject *self, Py_ssize_t *start, int as_bytes) ++{ ++ assert(self != NULL); ++ return _PyUnicodeError_GetParams(self, NULL, NULL, ++ start, NULL, NULL, ++ as_bytes); + } + ++ + int + PyUnicodeEncodeError_GetStart(PyObject *self, Py_ssize_t *start) + { +- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeEncodeError"); +- if (exc == NULL) { +- return -1; +- } +- PyObject *obj = get_unicode(exc->object, "object"); +- if (obj == NULL) { +- return -1; +- } +- Py_ssize_t size = PyUnicode_GET_LENGTH(obj); +- Py_DECREF(obj); +- *start = unicode_error_adjust_start(exc->start, size); +- return 0; ++ int rc = check_unicode_error_type(self, Py_UNICODE_ENCODE_ERROR_NAME); ++ return rc < 0 ? -1 : unicode_error_get_start_impl(self, start, false); + } + + + int + PyUnicodeDecodeError_GetStart(PyObject *self, Py_ssize_t *start) + { +- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeDecodeError"); +- if (exc == NULL) { +- return -1; +- } +- PyObject *obj = get_bytes(exc->object, "object"); +- if (obj == NULL) { +- return -1; +- } +- Py_ssize_t size = PyBytes_GET_SIZE(obj); +- Py_DECREF(obj); +- *start = unicode_error_adjust_start(exc->start, size); +- return 0; ++ int rc = check_unicode_error_type(self, Py_UNICODE_DECODE_ERROR_NAME); ++ return rc < 0 ? -1 : unicode_error_get_start_impl(self, start, true); + } + + + int + PyUnicodeTranslateError_GetStart(PyObject *self, Py_ssize_t *start) + { +- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeTranslateError"); +- if (exc == NULL) { +- return -1; +- } +- PyObject *obj = get_unicode(exc->object, "object"); +- if (obj == NULL) { +- return -1; +- } +- Py_ssize_t size = PyUnicode_GET_LENGTH(obj); +- Py_DECREF(obj); +- *start = unicode_error_adjust_start(exc->start, size); +- return 0; ++ int rc = check_unicode_error_type(self, Py_UNICODE_TRANSLATE_ERROR_NAME); ++ return rc < 0 ? -1 : unicode_error_get_start_impl(self, start, false); + } + + +-static inline int +-unicode_error_set_start_impl(PyObject *self, Py_ssize_t start) +-{ +- PyUnicodeErrorObject *exc = _PyUnicodeError_CAST(self); +- exc->start = start; +- return 0; +-} +- ++// --- PyUnicodeEncodeObject: 'start' setters --------------------------------- + + int + PyUnicodeEncodeError_SetStart(PyObject *self, Py_ssize_t start) + { +- int rc = check_unicode_error_type(self, "UnicodeEncodeError"); ++ int rc = check_unicode_error_type(self, Py_UNICODE_ENCODE_ERROR_NAME); + return rc < 0 ? -1 : unicode_error_set_start_impl(self, start); + } + +@@ -2883,7 +3272,7 @@ + int + PyUnicodeDecodeError_SetStart(PyObject *self, Py_ssize_t start) + { +- int rc = check_unicode_error_type(self, "UnicodeDecodeError"); ++ int rc = check_unicode_error_type(self, Py_UNICODE_DECODE_ERROR_NAME); + return rc < 0 ? -1 : unicode_error_set_start_impl(self, start); + } + +@@ -2891,78 +3280,59 @@ + int + PyUnicodeTranslateError_SetStart(PyObject *self, Py_ssize_t start) + { +- int rc = check_unicode_error_type(self, "UnicodeTranslateError"); ++ int rc = check_unicode_error_type(self, Py_UNICODE_TRANSLATE_ERROR_NAME); + return rc < 0 ? -1 : unicode_error_set_start_impl(self, start); + } + + ++// --- PyUnicodeEncodeObject: 'end' getters ----------------------------------- ++ ++/* ++ * Specialization of _PyUnicodeError_GetParams() for the 'end' attribute. ++ * ++ * The caller is responsible to ensure that 'self' is a PyUnicodeErrorObject, ++ * although this condition is verified by this function on DEBUG builds. ++ */ ++static inline int ++unicode_error_get_end_impl(PyObject *self, Py_ssize_t *end, int as_bytes) ++{ ++ assert(self != NULL); ++ return _PyUnicodeError_GetParams(self, NULL, NULL, ++ NULL, end, NULL, ++ as_bytes); ++} ++ ++ + int + PyUnicodeEncodeError_GetEnd(PyObject *self, Py_ssize_t *end) + { +- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeEncodeError"); +- if (exc == NULL) { +- return -1; +- } +- PyObject *obj = get_unicode(exc->object, "object"); +- if (obj == NULL) { +- return -1; +- } +- Py_ssize_t size = PyUnicode_GET_LENGTH(obj); +- Py_DECREF(obj); +- *end = unicode_error_adjust_end(exc->end, size); +- return 0; ++ int rc = check_unicode_error_type(self, Py_UNICODE_ENCODE_ERROR_NAME); ++ return rc < 0 ? -1 : unicode_error_get_end_impl(self, end, false); + } + + + int + PyUnicodeDecodeError_GetEnd(PyObject *self, Py_ssize_t *end) + { +- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeDecodeError"); +- if (exc == NULL) { +- return -1; +- } +- PyObject *obj = get_bytes(exc->object, "object"); +- if (obj == NULL) { +- return -1; +- } +- Py_ssize_t size = PyBytes_GET_SIZE(obj); +- Py_DECREF(obj); +- *end = unicode_error_adjust_end(exc->end, size); +- return 0; ++ int rc = check_unicode_error_type(self, Py_UNICODE_DECODE_ERROR_NAME); ++ return rc < 0 ? -1 : unicode_error_get_end_impl(self, end, true); + } + + + int + PyUnicodeTranslateError_GetEnd(PyObject *self, Py_ssize_t *end) + { +- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeTranslateError"); +- if (exc == NULL) { +- return -1; +- } +- PyObject *obj = get_unicode(exc->object, "object"); +- if (obj == NULL) { +- return -1; +- } +- Py_ssize_t size = PyUnicode_GET_LENGTH(obj); +- Py_DECREF(obj); +- *end = unicode_error_adjust_end(exc->end, size); +- return 0; ++ int rc = check_unicode_error_type(self, Py_UNICODE_TRANSLATE_ERROR_NAME); ++ return rc < 0 ? -1 : unicode_error_get_end_impl(self, end, false); + } + + +-static inline int +-unicode_error_set_end_impl(PyObject *self, Py_ssize_t end) +-{ +- PyUnicodeErrorObject *exc = _PyUnicodeError_CAST(self); +- exc->end = end; +- return 0; +-} +- ++// --- PyUnicodeEncodeObject: 'end' setters ----------------------------------- + + int + PyUnicodeEncodeError_SetEnd(PyObject *self, Py_ssize_t end) + { +- int rc = check_unicode_error_type(self, "UnicodeEncodeError"); ++ int rc = check_unicode_error_type(self, Py_UNICODE_ENCODE_ERROR_NAME); + return rc < 0 ? -1 : unicode_error_set_end_impl(self, end); + } + +@@ -2970,7 +3340,7 @@ + int + PyUnicodeDecodeError_SetEnd(PyObject *self, Py_ssize_t end) + { +- int rc = check_unicode_error_type(self, "UnicodeDecodeError"); ++ int rc = check_unicode_error_type(self, Py_UNICODE_DECODE_ERROR_NAME); + return rc < 0 ? -1 : unicode_error_set_end_impl(self, end); + } + +@@ -2978,56 +3348,60 @@ + int + PyUnicodeTranslateError_SetEnd(PyObject *self, Py_ssize_t end) + { +- int rc = check_unicode_error_type(self, "UnicodeTranslateError"); ++ int rc = check_unicode_error_type(self, Py_UNICODE_TRANSLATE_ERROR_NAME); + return rc < 0 ? -1 : unicode_error_set_end_impl(self, end); + } + + ++// --- PyUnicodeEncodeObject: 'reason' getters -------------------------------- ++ + PyObject * + PyUnicodeEncodeError_GetReason(PyObject *self) + { +- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeEncodeError"); +- return exc == NULL ? NULL : get_unicode(exc->reason, "reason"); ++ int rc = check_unicode_error_type(self, Py_UNICODE_ENCODE_ERROR_NAME); ++ return rc < 0 ? NULL : unicode_error_get_reason_impl(self); + } + + + PyObject * + PyUnicodeDecodeError_GetReason(PyObject *self) + { +- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeDecodeError"); +- return exc == NULL ? NULL : get_unicode(exc->reason, "reason"); ++ int rc = check_unicode_error_type(self, Py_UNICODE_DECODE_ERROR_NAME); ++ return rc < 0 ? NULL : unicode_error_get_reason_impl(self); + } + + + PyObject * + PyUnicodeTranslateError_GetReason(PyObject *self) + { +- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeTranslateError"); +- return exc == NULL ? NULL : get_unicode(exc->reason, "reason"); ++ int rc = check_unicode_error_type(self, Py_UNICODE_TRANSLATE_ERROR_NAME); ++ return rc < 0 ? NULL : unicode_error_get_reason_impl(self); + } + + ++// --- PyUnicodeEncodeObject: 'reason' setters -------------------------------- ++ + int + PyUnicodeEncodeError_SetReason(PyObject *self, const char *reason) + { +- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeEncodeError"); +- return exc == NULL ? -1 : set_unicodefromstring(&exc->reason, reason); ++ int rc = check_unicode_error_type(self, Py_UNICODE_ENCODE_ERROR_NAME); ++ return rc < 0 ? -1 : unicode_error_set_reason_impl(self, reason); + } + + + int + PyUnicodeDecodeError_SetReason(PyObject *self, const char *reason) + { +- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeDecodeError"); +- return exc == NULL ? -1 : set_unicodefromstring(&exc->reason, reason); ++ int rc = check_unicode_error_type(self, Py_UNICODE_DECODE_ERROR_NAME); ++ return rc < 0 ? -1 : unicode_error_set_reason_impl(self, reason); + } + + + int + PyUnicodeTranslateError_SetReason(PyObject *self, const char *reason) + { +- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeTranslateError"); +- return exc == NULL ? -1 : set_unicodefromstring(&exc->reason, reason); ++ int rc = check_unicode_error_type(self, Py_UNICODE_TRANSLATE_ERROR_NAME); ++ return rc < 0 ? -1 : unicode_error_set_reason_impl(self, reason); + } + + +@@ -3458,36 +3832,43 @@ + + #define MEMERRORS_SAVE 16 + ++#ifdef Py_GIL_DISABLED ++# define MEMERRORS_LOCK(state) PyMutex_LockFlags(&state->memerrors_lock, _Py_LOCK_DONT_DETACH) ++# define MEMERRORS_UNLOCK(state) PyMutex_Unlock(&state->memerrors_lock) ++#else ++# define MEMERRORS_LOCK(state) ((void)0) ++# define MEMERRORS_UNLOCK(state) ((void)0) ++#endif ++ + static PyObject * + get_memory_error(int allow_allocation, PyObject *args, PyObject *kwds) + { +- PyBaseExceptionObject *self; ++ PyBaseExceptionObject *self = NULL; + struct _Py_exc_state *state = get_exc_state(); +- if (state->memerrors_freelist == NULL) { +- if (!allow_allocation) { +- PyInterpreterState *interp = _PyInterpreterState_GET(); +- return Py_NewRef( +- &_Py_INTERP_SINGLETON(interp, last_resort_memory_error)); +- } +- PyObject *result = BaseException_new((PyTypeObject *)PyExc_MemoryError, args, kwds); +- return result; +- } + +- /* Fetch object from freelist and revive it */ +- self = state->memerrors_freelist; +- self->args = PyTuple_New(0); +- /* This shouldn't happen since the empty tuple is persistent */ ++ MEMERRORS_LOCK(state); ++ if (state->memerrors_freelist != NULL) { ++ /* Fetch MemoryError from freelist and initialize it */ ++ self = state->memerrors_freelist; ++ state->memerrors_freelist = (PyBaseExceptionObject *) self->dict; ++ state->memerrors_numfree--; ++ self->dict = NULL; ++ self->args = (PyObject *)&_Py_SINGLETON(tuple_empty); ++ _Py_NewReference((PyObject *)self); ++ _PyObject_GC_TRACK(self); ++ } ++ MEMERRORS_UNLOCK(state); + +- if (self->args == NULL) { +- return NULL; ++ if (self != NULL) { ++ return (PyObject *)self; + } + +- state->memerrors_freelist = (PyBaseExceptionObject *) self->dict; +- state->memerrors_numfree--; +- self->dict = NULL; +- _Py_NewReference((PyObject *)self); +- _PyObject_GC_TRACK(self); +- return (PyObject *)self; ++ if (!allow_allocation) { ++ PyInterpreterState *interp = _PyInterpreterState_GET(); ++ return Py_NewRef( ++ &_Py_INTERP_SINGLETON(interp, last_resort_memory_error)); ++ } ++ return BaseException_new((PyTypeObject *)PyExc_MemoryError, args, kwds); + } + + static PyObject * +@@ -3533,14 +3914,17 @@ + } + + struct _Py_exc_state *state = get_exc_state(); +- if (state->memerrors_numfree >= MEMERRORS_SAVE) { +- Py_TYPE(self)->tp_free((PyObject *)self); +- } +- else { ++ MEMERRORS_LOCK(state); ++ if (state->memerrors_numfree < MEMERRORS_SAVE) { + self->dict = (PyObject *) state->memerrors_freelist; + state->memerrors_freelist = self; + state->memerrors_numfree++; ++ MEMERRORS_UNLOCK(state); ++ return; + } ++ MEMERRORS_UNLOCK(state); ++ ++ Py_TYPE(self)->tp_free((PyObject *)self); + } + + static int +diff --git a/Objects/fileobject.c b/Objects/fileobject.c +index c377d1bb28b..7025b5bcffc 100644 +--- a/Objects/fileobject.c ++++ b/Objects/fileobject.c +@@ -34,7 +34,7 @@ + PyObject *open, *stream; + + /* import _io in case we are being used to open io.py */ +- open = _PyImport_GetModuleAttrString("_io", "open"); ++ open = PyImport_ImportModuleAttrString("_io", "open"); + if (open == NULL) + return NULL; + stream = PyObject_CallFunction(open, "isisssO", fd, mode, +@@ -506,7 +506,7 @@ + if (hook) { + f = hook(path, _PyRuntime.open_code_userdata); + } else { +- PyObject *open = _PyImport_GetModuleAttrString("_io", "open"); ++ PyObject *open = PyImport_ImportModuleAttrString("_io", "open"); + if (open) { + f = PyObject_CallFunction(open, "Os", path, "rb"); + Py_DECREF(open); +diff --git a/Objects/floatobject.c b/Objects/floatobject.c +index bcc77287454..3b72a1e7c37 100644 +--- a/Objects/floatobject.c ++++ b/Objects/floatobject.c +@@ -369,8 +369,9 @@ + } + + static PyObject * +-float_repr(PyFloatObject *v) ++float_repr(PyObject *op) + { ++ PyFloatObject *v = _PyFloat_CAST(op); + PyObject *result; + char *buf; + +@@ -428,9 +429,10 @@ + + else if (PyLong_Check(w)) { + int vsign = i == 0.0 ? 0 : i < 0.0 ? -1 : 1; +- int wsign = _PyLong_Sign(w); ++ int wsign; + int exponent; + ++ (void)PyLong_GetSign(w, &wsign); + if (vsign != wsign) { + /* Magnitudes are irrelevant -- the signs alone + * determine the outcome. +@@ -578,9 +580,10 @@ + } + + static Py_hash_t +-float_hash(PyFloatObject *v) ++float_hash(PyObject *op) + { +- return _Py_HashDouble((PyObject *)v, v->ob_fval); ++ PyFloatObject *v = _PyFloat_CAST(op); ++ return _Py_HashDouble(op, v->ob_fval); + } + + static PyObject * +@@ -850,20 +853,23 @@ + #undef DOUBLE_IS_ODD_INTEGER + + static PyObject * +-float_neg(PyFloatObject *v) ++float_neg(PyObject *op) + { ++ PyFloatObject *v = _PyFloat_CAST(op); + return PyFloat_FromDouble(-v->ob_fval); + } + + static PyObject * +-float_abs(PyFloatObject *v) ++float_abs(PyObject *op) + { ++ PyFloatObject *v = _PyFloat_CAST(op); + return PyFloat_FromDouble(fabs(v->ob_fval)); + } + + static int +-float_bool(PyFloatObject *v) ++float_bool(PyObject *op) + { ++ PyFloatObject *v = _PyFloat_CAST(op); + return v->ob_fval != 0.0; + } + +@@ -1205,7 +1211,7 @@ + CONVERT_TO_DOUBLE(self, x); + + if (isnan(x) || isinf(x)) +- return float_repr((PyFloatObject *)self); ++ return float_repr(self); + + if (x == 0.0) { + if (copysign(1.0, x) == -1.0) +@@ -1650,7 +1656,7 @@ + } + + static PyObject * +-float_vectorcall(PyObject *type, PyObject * const*args, ++float_vectorcall(PyObject *type, PyObject *const *args, + size_t nargsf, PyObject *kwnames) + { + if (!_PyArg_NoKwnames("float", kwnames)) { +@@ -1770,13 +1776,13 @@ + + + static PyObject * +-float_getreal(PyObject *v, void *closure) ++float_getreal(PyObject *v, void *Py_UNUSED(closure)) + { + return float_float(v); + } + + static PyObject * +-float_getimag(PyObject *v, void *closure) ++float_getimag(PyObject *Py_UNUSED(v), void *Py_UNUSED(closure)) + { + return PyFloat_FromDouble(0.0); + } +@@ -1828,11 +1834,11 @@ + + static PyGetSetDef float_getset[] = { + {"real", +- float_getreal, (setter)NULL, ++ float_getreal, NULL, + "the real part of a complex number", + NULL}, + {"imag", +- float_getimag, (setter)NULL, ++ float_getimag, NULL, + "the imaginary part of a complex number", + NULL}, + {NULL} /* Sentinel */ +@@ -1846,10 +1852,10 @@ + float_rem, /* nb_remainder */ + float_divmod, /* nb_divmod */ + float_pow, /* nb_power */ +- (unaryfunc)float_neg, /* nb_negative */ ++ float_neg, /* nb_negative */ + float_float, /* nb_positive */ +- (unaryfunc)float_abs, /* nb_absolute */ +- (inquiry)float_bool, /* nb_bool */ ++ float_abs, /* nb_absolute */ ++ float_bool, /* nb_bool */ + 0, /* nb_invert */ + 0, /* nb_lshift */ + 0, /* nb_rshift */ +@@ -1880,16 +1886,16 @@ + "float", + sizeof(PyFloatObject), + 0, +- (destructor)float_dealloc, /* tp_dealloc */ ++ float_dealloc, /* tp_dealloc */ + 0, /* tp_vectorcall_offset */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_as_async */ +- (reprfunc)float_repr, /* tp_repr */ ++ float_repr, /* tp_repr */ + &float_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ +- (hashfunc)float_hash, /* tp_hash */ ++ float_hash, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ +@@ -1915,7 +1921,7 @@ + 0, /* tp_init */ + 0, /* tp_alloc */ + float_new, /* tp_new */ +- .tp_vectorcall = (vectorcallfunc)float_vectorcall, ++ .tp_vectorcall = float_vectorcall, + .tp_version_tag = _Py_TYPE_VERSION_FLOAT, + }; + +diff --git a/Objects/frameobject.c b/Objects/frameobject.c +index 03ed2b9480f..8ebcc1a4b5e 100644 +--- a/Objects/frameobject.c ++++ b/Objects/frameobject.c +@@ -16,6 +16,14 @@ + #include "pycore_frame.h" + #include "opcode.h" // EXTENDED_ARG + ++#define PyFrameObject_CAST(op) \ ++ (assert(PyObject_TypeCheck((op), &PyFrame_Type)), (PyFrameObject *)(op)) ++ ++#define PyFrameLocalsProxyObject_CAST(op) \ ++ ( \ ++ assert(PyObject_TypeCheck((op), &PyFrameLocalsProxy_Type)), \ ++ (PyFrameLocalsProxyObject *)(op) \ ++ ) + + #define OFF(x) offsetof(PyFrameObject, x) + +@@ -126,8 +134,8 @@ + static PyObject * + framelocalsproxy_getitem(PyObject *self, PyObject *key) + { +- PyFrameObject* frame = ((PyFrameLocalsProxyObject*)self)->frame; +- PyCodeObject* co = _PyFrame_GetCode(frame->f_frame); ++ PyFrameObject *frame = PyFrameLocalsProxyObject_CAST(self)->frame; ++ PyCodeObject *co = _PyFrame_GetCode(frame->f_frame); + + int i = framelocalsproxy_getkeyindex(frame, key, true); + if (i == -2) { +@@ -157,7 +165,7 @@ + framelocalsproxy_setitem(PyObject *self, PyObject *key, PyObject *value) + { + /* Merge locals into fast locals */ +- PyFrameObject *frame = ((PyFrameLocalsProxyObject*)self)->frame; ++ PyFrameObject *frame = PyFrameLocalsProxyObject_CAST(self)->frame; + _PyStackRef *fast = _PyFrame_GetLocalsArray(frame->f_frame); + PyCodeObject *co = _PyFrame_GetCode(frame->f_frame); + +@@ -179,9 +187,9 @@ + if (kind == CO_FAST_FREE) { + // The cell was set when the frame was created from + // the function's closure. +- assert(oldvalue.bits != 0 && PyCell_Check(PyStackRef_AsPyObjectBorrow(oldvalue))); ++ assert(!PyStackRef_IsNull(oldvalue) && PyCell_Check(PyStackRef_AsPyObjectBorrow(oldvalue))); + cell = PyStackRef_AsPyObjectBorrow(oldvalue); +- } else if (kind & CO_FAST_CELL && oldvalue.bits != 0) { ++ } else if (kind & CO_FAST_CELL && !PyStackRef_IsNull(oldvalue)) { + PyObject *as_obj = PyStackRef_AsPyObjectBorrow(oldvalue); + if (PyCell_Check(as_obj)) { + cell = as_obj; +@@ -264,13 +272,17 @@ + + Py_DECREF(iter); + ++ if (PyErr_Occurred()) { ++ return -1; ++ } ++ + return 0; + } + + static PyObject * +-framelocalsproxy_keys(PyObject *self, void *Py_UNUSED(ignored)) ++framelocalsproxy_keys(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- PyFrameObject *frame = ((PyFrameLocalsProxyObject*)self)->frame; ++ PyFrameObject *frame = PyFrameLocalsProxyObject_CAST(self)->frame; + PyCodeObject *co = _PyFrame_GetCode(frame->f_frame); + PyObject *names = PyList_New(0); + if (names == NULL) { +@@ -310,8 +322,9 @@ + static void + framelocalsproxy_dealloc(PyObject *self) + { ++ PyFrameLocalsProxyObject *proxy = PyFrameLocalsProxyObject_CAST(self); + PyObject_GC_UnTrack(self); +- Py_CLEAR(((PyFrameLocalsProxyObject*)self)->frame); ++ Py_CLEAR(proxy->frame); + Py_TYPE(self)->tp_free(self); + } + +@@ -351,14 +364,16 @@ + static int + framelocalsproxy_tp_clear(PyObject *self) + { +- Py_CLEAR(((PyFrameLocalsProxyObject*)self)->frame); ++ PyFrameLocalsProxyObject *proxy = PyFrameLocalsProxyObject_CAST(self); ++ Py_CLEAR(proxy->frame); + return 0; + } + + static int + framelocalsproxy_visit(PyObject *self, visitproc visit, void *arg) + { +- Py_VISIT(((PyFrameLocalsProxyObject*)self)->frame); ++ PyFrameLocalsProxyObject *proxy = PyFrameLocalsProxyObject_CAST(self); ++ Py_VISIT(proxy->frame); + return 0; + } + +@@ -377,27 +392,29 @@ + } + + static PyObject * +-framelocalsproxy_richcompare(PyObject *self, PyObject *other, int op) ++framelocalsproxy_richcompare(PyObject *lhs, PyObject *rhs, int op) + { +- if (PyFrameLocalsProxy_Check(other)) { +- bool result = ((PyFrameLocalsProxyObject*)self)->frame == ((PyFrameLocalsProxyObject*)other)->frame; ++ PyFrameLocalsProxyObject *self = PyFrameLocalsProxyObject_CAST(lhs); ++ if (PyFrameLocalsProxy_Check(rhs)) { ++ PyFrameLocalsProxyObject *other = (PyFrameLocalsProxyObject *)rhs; ++ bool result = self->frame == other->frame; + if (op == Py_EQ) { + return PyBool_FromLong(result); + } else if (op == Py_NE) { + return PyBool_FromLong(!result); + } +- } else if (PyDict_Check(other)) { ++ } else if (PyDict_Check(rhs)) { + PyObject *dct = PyDict_New(); + if (dct == NULL) { + return NULL; + } + +- if (PyDict_Update(dct, self) < 0) { ++ if (PyDict_Update(dct, lhs) < 0) { + Py_DECREF(dct); + return NULL; + } + +- PyObject *result = PyObject_RichCompare(dct, other, op); ++ PyObject *result = PyObject_RichCompare(dct, rhs, op); + Py_DECREF(dct); + return result; + } +@@ -472,10 +489,10 @@ + return Py_NewRef(self); + } + +-static PyObject* +-framelocalsproxy_values(PyObject *self, void *Py_UNUSED(ignored)) ++static PyObject * ++framelocalsproxy_values(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- PyFrameObject *frame = ((PyFrameLocalsProxyObject*)self)->frame; ++ PyFrameObject *frame = PyFrameLocalsProxyObject_CAST(self)->frame; + PyCodeObject *co = _PyFrame_GetCode(frame->f_frame); + PyObject *values = PyList_New(0); + if (values == NULL) { +@@ -509,9 +526,9 @@ + } + + static PyObject * +-framelocalsproxy_items(PyObject *self, void *Py_UNUSED(ignored)) ++framelocalsproxy_items(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- PyFrameObject *frame = ((PyFrameLocalsProxyObject*)self)->frame; ++ PyFrameObject *frame = PyFrameLocalsProxyObject_CAST(self)->frame; + PyCodeObject *co = _PyFrame_GetCode(frame->f_frame); + PyObject *items = PyList_New(0); + if (items == NULL) { +@@ -567,7 +584,7 @@ + static Py_ssize_t + framelocalsproxy_length(PyObject *self) + { +- PyFrameObject *frame = ((PyFrameLocalsProxyObject*)self)->frame; ++ PyFrameObject *frame = PyFrameLocalsProxyObject_CAST(self)->frame; + PyCodeObject *co = _PyFrame_GetCode(frame->f_frame); + Py_ssize_t size = 0; + +@@ -587,7 +604,7 @@ + static int + framelocalsproxy_contains(PyObject *self, PyObject *key) + { +- PyFrameObject *frame = ((PyFrameLocalsProxyObject*)self)->frame; ++ PyFrameObject *frame = PyFrameLocalsProxyObject_CAST(self)->frame; + + int i = framelocalsproxy_getkeyindex(frame, key, true); + if (i == -2) { +@@ -597,7 +614,7 @@ + return 1; + } + +- PyObject *extra = ((PyFrameObject*)frame)->f_extra_locals; ++ PyObject *extra = frame->f_extra_locals; + if (extra != NULL) { + return PyDict_Contains(extra, key); + } +@@ -698,7 +715,7 @@ + default_value = args[1]; + } + +- PyFrameObject *frame = ((PyFrameLocalsProxyObject*)self)->frame; ++ PyFrameObject *frame = PyFrameLocalsProxyObject_CAST(self)->frame; + + int i = framelocalsproxy_getkeyindex(frame, key, false); + if (i == -2) { +@@ -755,7 +772,7 @@ + } + + static PyObject* +-framelocalsproxy_reversed(PyObject *self, void *Py_UNUSED(ignored)) ++framelocalsproxy_reversed(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *result = framelocalsproxy_keys(self, NULL); + +@@ -780,42 +797,36 @@ + }; + + static PyMappingMethods framelocalsproxy_as_mapping = { +- framelocalsproxy_length, // mp_length +- framelocalsproxy_getitem, // mp_subscript +- framelocalsproxy_setitem, // mp_ass_subscript ++ .mp_length = framelocalsproxy_length, ++ .mp_subscript = framelocalsproxy_getitem, ++ .mp_ass_subscript = framelocalsproxy_setitem, + }; + + static PyMethodDef framelocalsproxy_methods[] = { +- {"__contains__", framelocalsproxy___contains__, METH_O | METH_COEXIST, +- NULL}, +- {"__getitem__", framelocalsproxy_getitem, METH_O | METH_COEXIST, +- NULL}, +- {"update", framelocalsproxy_update, METH_O, +- NULL}, +- {"__reversed__", _PyCFunction_CAST(framelocalsproxy_reversed), METH_NOARGS, +- NULL}, +- {"copy", _PyCFunction_CAST(framelocalsproxy_copy), METH_NOARGS, +- NULL}, +- {"keys", _PyCFunction_CAST(framelocalsproxy_keys), METH_NOARGS, +- NULL}, +- {"values", _PyCFunction_CAST(framelocalsproxy_values), METH_NOARGS, +- NULL}, +- {"items", _PyCFunction_CAST(framelocalsproxy_items), METH_NOARGS, +- NULL}, +- {"get", _PyCFunction_CAST(framelocalsproxy_get), METH_FASTCALL, +- NULL}, +- {"pop", _PyCFunction_CAST(framelocalsproxy_pop), METH_FASTCALL, +- NULL}, +- {"setdefault", _PyCFunction_CAST(framelocalsproxy_setdefault), METH_FASTCALL, +- NULL}, +- {NULL, NULL} /* sentinel */ ++ {"__contains__", framelocalsproxy___contains__, METH_O | METH_COEXIST, NULL}, ++ {"__getitem__", framelocalsproxy_getitem, METH_O | METH_COEXIST, NULL}, ++ {"update", framelocalsproxy_update, METH_O, NULL}, ++ {"__reversed__", framelocalsproxy_reversed, METH_NOARGS, NULL}, ++ {"copy", framelocalsproxy_copy, METH_NOARGS, NULL}, ++ {"keys", framelocalsproxy_keys, METH_NOARGS, NULL}, ++ {"values", framelocalsproxy_values, METH_NOARGS, NULL}, ++ {"items", _PyCFunction_CAST(framelocalsproxy_items), METH_NOARGS, NULL}, ++ {"get", _PyCFunction_CAST(framelocalsproxy_get), METH_FASTCALL, NULL}, ++ {"pop", _PyCFunction_CAST(framelocalsproxy_pop), METH_FASTCALL, NULL}, ++ { ++ "setdefault", ++ _PyCFunction_CAST(framelocalsproxy_setdefault), ++ METH_FASTCALL, ++ NULL ++ }, ++ {NULL, NULL} /* sentinel */ + }; + + PyTypeObject PyFrameLocalsProxy_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + .tp_name = "FrameLocalsProxy", + .tp_basicsize = sizeof(PyFrameLocalsProxyObject), +- .tp_dealloc = (destructor)framelocalsproxy_dealloc, ++ .tp_dealloc = framelocalsproxy_dealloc, + .tp_repr = &framelocalsproxy_repr, + .tp_as_number = &framelocalsproxy_as_number, + .tp_as_sequence = &framelocalsproxy_as_sequence, +@@ -841,7 +852,7 @@ + return NULL; + } + +- PyObject* proxy = (PyObject*)framelocalsproxy_new(&PyFrameLocalsProxy_Type, args, NULL); ++ PyObject* proxy = framelocalsproxy_new(&PyFrameLocalsProxy_Type, args, NULL); + Py_DECREF(args); + return proxy; + } +@@ -852,8 +863,9 @@ + }; + + static PyObject * +-frame_getlocals(PyFrameObject *f, void *closure) ++frame_getlocals(PyObject *op, void *Py_UNUSED(closure)) + { ++ PyFrameObject *f = PyFrameObject_CAST(op); + if (f == NULL) { + PyErr_BadInternalCall(); + return NULL; +@@ -899,8 +911,9 @@ + } + + static PyObject * +-frame_getlineno(PyFrameObject *f, void *closure) ++frame_getlineno(PyObject *op, void *Py_UNUSED(closure)) + { ++ PyFrameObject *f = PyFrameObject_CAST(op); + int lineno = PyFrame_GetLineNumber(f); + if (lineno < 0) { + Py_RETURN_NONE; +@@ -911,8 +924,9 @@ + } + + static PyObject * +-frame_getlasti(PyFrameObject *f, void *closure) ++frame_getlasti(PyObject *op, void *Py_UNUSED(closure)) + { ++ PyFrameObject *f = PyFrameObject_CAST(op); + int lasti = _PyInterpreterFrame_LASTI(f->f_frame); + if (lasti < 0) { + return PyLong_FromLong(-1); +@@ -921,8 +935,9 @@ + } + + static PyObject * +-frame_getglobals(PyFrameObject *f, void *closure) ++frame_getglobals(PyObject *op, void *Py_UNUSED(closure)) + { ++ PyFrameObject *f = PyFrameObject_CAST(op); + PyObject *globals = f->f_frame->f_globals; + if (globals == NULL) { + globals = Py_None; +@@ -931,8 +946,9 @@ + } + + static PyObject * +-frame_getbuiltins(PyFrameObject *f, void *closure) ++frame_getbuiltins(PyObject *op, void *Py_UNUSED(closure)) + { ++ PyFrameObject *f = PyFrameObject_CAST(op); + PyObject *builtins = f->f_frame->f_builtins; + if (builtins == NULL) { + builtins = Py_None; +@@ -941,8 +957,9 @@ + } + + static PyObject * +-frame_getcode(PyFrameObject *f, void *closure) ++frame_getcode(PyObject *op, void *Py_UNUSED(closure)) + { ++ PyFrameObject *f = PyFrameObject_CAST(op); + if (PySys_Audit("object.__getattr__", "Os", f, "f_code") < 0) { + return NULL; + } +@@ -950,8 +967,9 @@ + } + + static PyObject * +-frame_getback(PyFrameObject *f, void *closure) ++frame_getback(PyObject *op, void *Py_UNUSED(closure)) + { ++ PyFrameObject *f = PyFrameObject_CAST(op); + PyObject *res = (PyObject *)PyFrame_GetBack(f); + if (res == NULL) { + Py_RETURN_NONE; +@@ -960,15 +978,17 @@ + } + + static PyObject * +-frame_gettrace_opcodes(PyFrameObject *f, void *closure) ++frame_gettrace_opcodes(PyObject *op, void *Py_UNUSED(closure)) + { ++ PyFrameObject *f = PyFrameObject_CAST(op); + PyObject *result = f->f_trace_opcodes ? Py_True : Py_False; + return Py_NewRef(result); + } + + static int +-frame_settrace_opcodes(PyFrameObject *f, PyObject* value, void *Py_UNUSED(ignored)) ++frame_settrace_opcodes(PyObject *op, PyObject* value, void *Py_UNUSED(closure)) + { ++ PyFrameObject *f = PyFrameObject_CAST(op); + if (!PyBool_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "attribute value type must be bool"); +@@ -1460,8 +1480,9 @@ + * that time. + */ + static int +-frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignored)) ++frame_setlineno(PyObject *op, PyObject* p_new_lineno, void *Py_UNUSED(closure)) + { ++ PyFrameObject *f = PyFrameObject_CAST(op); + PyCodeObject *code = _PyFrame_GetCode(f->f_frame); + if (p_new_lineno == NULL) { + PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); +@@ -1654,8 +1675,9 @@ + } + + static PyObject * +-frame_gettrace(PyFrameObject *f, void *closure) ++frame_gettrace(PyObject *op, void *Py_UNUSED(closure)) + { ++ PyFrameObject *f = PyFrameObject_CAST(op); + PyObject* trace = f->f_trace; + if (trace == NULL) + trace = Py_None; +@@ -1663,8 +1685,9 @@ + } + + static int +-frame_settrace(PyFrameObject *f, PyObject* v, void *closure) ++frame_settrace(PyObject *op, PyObject* v, void *Py_UNUSED(closure)) + { ++ PyFrameObject *f = PyFrameObject_CAST(op); + if (v == Py_None) { + v = NULL; + } +@@ -1677,27 +1700,37 @@ + return 0; + } + ++static PyObject * ++frame_getgenerator(PyObject *op, void *Py_UNUSED(closure)) { ++ PyFrameObject *f = PyFrameObject_CAST(op); ++ if (f->f_frame->owner == FRAME_OWNED_BY_GENERATOR) { ++ PyObject *gen = (PyObject *)_PyGen_GetGeneratorFromFrame(f->f_frame); ++ return Py_NewRef(gen); ++ } ++ Py_RETURN_NONE; ++} ++ + + static PyGetSetDef frame_getsetlist[] = { +- {"f_back", (getter)frame_getback, NULL, NULL}, +- {"f_locals", (getter)frame_getlocals, NULL, NULL}, +- {"f_lineno", (getter)frame_getlineno, +- (setter)frame_setlineno, NULL}, +- {"f_trace", (getter)frame_gettrace, (setter)frame_settrace, NULL}, +- {"f_lasti", (getter)frame_getlasti, NULL, NULL}, +- {"f_globals", (getter)frame_getglobals, NULL, NULL}, +- {"f_builtins", (getter)frame_getbuiltins, NULL, NULL}, +- {"f_code", (getter)frame_getcode, NULL, NULL}, +- {"f_trace_opcodes", (getter)frame_gettrace_opcodes, (setter)frame_settrace_opcodes, NULL}, ++ {"f_back", frame_getback, NULL, NULL}, ++ {"f_locals", frame_getlocals, NULL, NULL}, ++ {"f_lineno", frame_getlineno, frame_setlineno, NULL}, ++ {"f_trace", frame_gettrace, frame_settrace, NULL}, ++ {"f_lasti", frame_getlasti, NULL, NULL}, ++ {"f_globals", frame_getglobals, NULL, NULL}, ++ {"f_builtins", frame_getbuiltins, NULL, NULL}, ++ {"f_code", frame_getcode, NULL, NULL}, ++ {"f_trace_opcodes", frame_gettrace_opcodes, frame_settrace_opcodes, NULL}, ++ {"f_generator", frame_getgenerator, NULL, NULL}, + {0} + }; + + static void +-frame_dealloc(PyFrameObject *f) ++frame_dealloc(PyObject *op) + { + /* It is the responsibility of the owning generator/coroutine + * to have cleared the generator pointer */ +- ++ PyFrameObject *f = PyFrameObject_CAST(op); + if (_PyObject_GC_IS_TRACKED(f)) { + _PyObject_GC_UNTRACK(f); + } +@@ -1730,8 +1763,9 @@ + } + + static int +-frame_traverse(PyFrameObject *f, visitproc visit, void *arg) ++frame_traverse(PyObject *op, visitproc visit, void *arg) + { ++ PyFrameObject *f = PyFrameObject_CAST(op); + Py_VISIT(f->f_back); + Py_VISIT(f->f_trace); + Py_VISIT(f->f_extra_locals); +@@ -1744,8 +1778,9 @@ + } + + static int +-frame_tp_clear(PyFrameObject *f) ++frame_tp_clear(PyObject *op) + { ++ PyFrameObject *f = PyFrameObject_CAST(op); + Py_CLEAR(f->f_trace); + Py_CLEAR(f->f_extra_locals); + Py_CLEAR(f->f_locals_cache); +@@ -1764,8 +1799,9 @@ + } + + static PyObject * +-frame_clear(PyFrameObject *f, PyObject *Py_UNUSED(ignored)) ++frame_clear(PyObject *op, PyObject *Py_UNUSED(ignored)) + { ++ PyFrameObject *f = PyFrameObject_CAST(op); + if (f->f_frame->owner == FRAME_OWNED_BY_GENERATOR) { + PyGenObject *gen = _PyGen_GetGeneratorFromFrame(f->f_frame); + if (gen->gi_frame_state == FRAME_EXECUTING) { +@@ -1781,7 +1817,7 @@ + } + else { + assert(f->f_frame->owner == FRAME_OWNED_BY_FRAME_OBJECT); +- (void)frame_tp_clear(f); ++ (void)frame_tp_clear(op); + } + Py_RETURN_NONE; + running: +@@ -1798,8 +1834,9 @@ + "F.clear(): clear all references held by the frame"); + + static PyObject * +-frame_sizeof(PyFrameObject *f, PyObject *Py_UNUSED(ignored)) ++frame_sizeof(PyObject *op, PyObject *Py_UNUSED(ignored)) + { ++ PyFrameObject *f = PyFrameObject_CAST(op); + Py_ssize_t res; + res = offsetof(PyFrameObject, _f_frame_data) + offsetof(_PyInterpreterFrame, localsplus); + PyCodeObject *code = _PyFrame_GetCode(f->f_frame); +@@ -1811,8 +1848,9 @@ + "F.__sizeof__() -> size of F in memory, in bytes"); + + static PyObject * +-frame_repr(PyFrameObject *f) ++frame_repr(PyObject *op) + { ++ PyFrameObject *f = PyFrameObject_CAST(op); + int lineno = PyFrame_GetLineNumber(f); + PyCodeObject *code = _PyFrame_GetCode(f->f_frame); + return PyUnicode_FromFormat( +@@ -1821,11 +1859,9 @@ + } + + static PyMethodDef frame_methods[] = { +- {"clear", (PyCFunction)frame_clear, METH_NOARGS, +- clear__doc__}, +- {"__sizeof__", (PyCFunction)frame_sizeof, METH_NOARGS, +- sizeof__doc__}, +- {NULL, NULL} /* sentinel */ ++ {"clear", frame_clear, METH_NOARGS, clear__doc__}, ++ {"__sizeof__", frame_sizeof, METH_NOARGS, sizeof__doc__}, ++ {NULL, NULL} /* sentinel */ + }; + + PyTypeObject PyFrame_Type = { +@@ -1834,12 +1870,12 @@ + offsetof(PyFrameObject, _f_frame_data) + + offsetof(_PyInterpreterFrame, localsplus), + sizeof(PyObject *), +- (destructor)frame_dealloc, /* tp_dealloc */ ++ frame_dealloc, /* tp_dealloc */ + 0, /* tp_vectorcall_offset */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_as_async */ +- (reprfunc)frame_repr, /* tp_repr */ ++ frame_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ +@@ -1851,8 +1887,8 @@ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + 0, /* tp_doc */ +- (traverseproc)frame_traverse, /* tp_traverse */ +- (inquiry)frame_tp_clear, /* tp_clear */ ++ frame_traverse, /* tp_traverse */ ++ frame_tp_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ +@@ -2138,7 +2174,7 @@ + assert(frame != NULL); + _PyInterpreterFrame *f = frame->f_frame; + assert(!_PyFrame_IsIncomplete(f)); +- return f->previous && f->previous->owner == FRAME_OWNED_BY_CSTACK; ++ return f->previous && f->previous->owner == FRAME_OWNED_BY_INTERPRETER; + } + + PyCodeObject * +@@ -2172,21 +2208,21 @@ + PyFrame_GetLocals(PyFrameObject *frame) + { + assert(!_PyFrame_IsIncomplete(frame->f_frame)); +- return frame_getlocals(frame, NULL); ++ return frame_getlocals((PyObject *)frame, NULL); + } + + PyObject* + PyFrame_GetGlobals(PyFrameObject *frame) + { + assert(!_PyFrame_IsIncomplete(frame->f_frame)); +- return frame_getglobals(frame, NULL); ++ return frame_getglobals((PyObject *)frame, NULL); + } + + PyObject* + PyFrame_GetBuiltins(PyFrameObject *frame) + { + assert(!_PyFrame_IsIncomplete(frame->f_frame)); +- return frame_getbuiltins(frame, NULL); ++ return frame_getbuiltins((PyObject *)frame, NULL); + } + + int +diff --git a/Objects/funcobject.c b/Objects/funcobject.c +index cca7f014980..169db2048c6 100644 +--- a/Objects/funcobject.c ++++ b/Objects/funcobject.c +@@ -2,11 +2,11 @@ + /* Function object implementation */ + + #include "Python.h" +-#include "pycore_dict.h" // _Py_INCREF_DICT() +-#include "pycore_long.h" // _PyLong_GetOne() +-#include "pycore_modsupport.h" // _PyArg_NoKeywords() +-#include "pycore_object.h" // _PyObject_GC_UNTRACK() +-#include "pycore_pyerrors.h" // _PyErr_Occurred() ++#include "pycore_dict.h" // _Py_INCREF_DICT() ++#include "pycore_long.h" // _PyLong_GetOne() ++#include "pycore_modsupport.h" // _PyArg_NoKeywords() ++#include "pycore_object.h" // _PyObject_GC_UNTRACK() ++#include "pycore_pyerrors.h" // _PyErr_Occurred() + + + static const char * +@@ -210,10 +210,14 @@ + op->func_typeparams = NULL; + op->vectorcall = _PyFunction_Vectorcall; + op->func_version = FUNC_VERSION_UNSET; +- if ((code_obj->co_flags & CO_NESTED) == 0) { ++ if (((code_obj->co_flags & CO_NESTED) == 0) || ++ (code_obj->co_flags & CO_METHOD)) { + // Use deferred reference counting for top-level functions, but not + // nested functions because they are more likely to capture variables, + // which makes prompt deallocation more important. ++ // ++ // Nested methods (functions defined in class scope) are also deferred, ++ // since they will likely be cleaned up by GC anyway. + _PyObject_SetDeferredRefcount((PyObject *)op); + } + _PyObject_GC_TRACK(op); +@@ -631,6 +635,13 @@ + {NULL} /* Sentinel */ + }; + ++/*[clinic input] ++class function "PyFunctionObject *" "&PyFunction_Type" ++[clinic start generated code]*/ ++/*[clinic end generated code: output=da39a3ee5e6b4b0d input=70af9c90aa2e71b0]*/ ++ ++#include "clinic/funcobject.c.h" ++ + static PyObject * + func_get_code(PyObject *self, void *Py_UNUSED(ignored)) + { +@@ -820,32 +831,46 @@ + return 0; + } + ++/*[clinic input] ++@critical_section ++@getter ++function.__annotate__ ++ ++Get the code object for a function. ++[clinic start generated code]*/ ++ + static PyObject * +-func_get_annotate(PyObject *self, void *Py_UNUSED(ignored)) ++function___annotate___get_impl(PyFunctionObject *self) ++/*[clinic end generated code: output=5ec7219ff2bda9e6 input=7f3db11e3c3329f3]*/ + { +- PyFunctionObject *op = _PyFunction_CAST(self); +- if (op->func_annotate == NULL) { ++ if (self->func_annotate == NULL) { + Py_RETURN_NONE; + } +- return Py_NewRef(op->func_annotate); ++ return Py_NewRef(self->func_annotate); + } + ++/*[clinic input] ++@critical_section ++@setter ++function.__annotate__ ++[clinic start generated code]*/ ++ + static int +-func_set_annotate(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) ++function___annotate___set_impl(PyFunctionObject *self, PyObject *value) ++/*[clinic end generated code: output=05b7dfc07ada66cd input=eb6225e358d97448]*/ + { +- PyFunctionObject *op = _PyFunction_CAST(self); + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, + "__annotate__ cannot be deleted"); + return -1; + } + if (Py_IsNone(value)) { +- Py_XSETREF(op->func_annotate, value); ++ Py_XSETREF(self->func_annotate, value); + return 0; + } + else if (PyCallable_Check(value)) { +- Py_XSETREF(op->func_annotate, Py_XNewRef(value)); +- Py_CLEAR(op->func_annotations); ++ Py_XSETREF(self->func_annotate, Py_XNewRef(value)); ++ Py_CLEAR(self->func_annotations); + return 0; + } + else { +@@ -855,24 +880,39 @@ + } + } + ++/*[clinic input] ++@critical_section ++@getter ++function.__annotations__ ++ ++Dict of annotations in a function object. ++[clinic start generated code]*/ ++ + static PyObject * +-func_get_annotations(PyObject *self, void *Py_UNUSED(ignored)) +-{ +- PyFunctionObject *op = _PyFunction_CAST(self); +- if (op->func_annotations == NULL && +- (op->func_annotate == NULL || !PyCallable_Check(op->func_annotate))) { +- op->func_annotations = PyDict_New(); +- if (op->func_annotations == NULL) ++function___annotations___get_impl(PyFunctionObject *self) ++/*[clinic end generated code: output=a4cf4c884c934cbb input=92643d7186c1ad0c]*/ ++{ ++ PyObject *d = NULL; ++ if (self->func_annotations == NULL && ++ (self->func_annotate == NULL || !PyCallable_Check(self->func_annotate))) { ++ self->func_annotations = PyDict_New(); ++ if (self->func_annotations == NULL) + return NULL; + } +- PyObject *d = func_get_annotation_dict(op); ++ d = func_get_annotation_dict(self); + return Py_XNewRef(d); + } + ++/*[clinic input] ++@critical_section ++@setter ++function.__annotations__ ++[clinic start generated code]*/ ++ + static int +-func_set_annotations(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) ++function___annotations___set_impl(PyFunctionObject *self, PyObject *value) ++/*[clinic end generated code: output=a61795d4a95eede4 input=5302641f686f0463]*/ + { +- PyFunctionObject *op = _PyFunction_CAST(self); + if (value == Py_None) + value = NULL; + /* Legal to del f.func_annotations. +@@ -883,35 +923,49 @@ + "__annotations__ must be set to a dict object"); + return -1; + } +- Py_XSETREF(op->func_annotations, Py_XNewRef(value)); +- Py_CLEAR(op->func_annotate); ++ Py_XSETREF(self->func_annotations, Py_XNewRef(value)); ++ Py_CLEAR(self->func_annotate); + return 0; + } + ++/*[clinic input] ++@critical_section ++@getter ++function.__type_params__ ++ ++Get the declared type parameters for a function. ++[clinic start generated code]*/ ++ + static PyObject * +-func_get_type_params(PyObject *self, void *Py_UNUSED(ignored)) ++function___type_params___get_impl(PyFunctionObject *self) ++/*[clinic end generated code: output=eb844d7ffca517a8 input=0864721484293724]*/ + { +- PyFunctionObject *op = _PyFunction_CAST(self); +- if (op->func_typeparams == NULL) { ++ if (self->func_typeparams == NULL) { + return PyTuple_New(0); + } + +- assert(PyTuple_Check(op->func_typeparams)); +- return Py_NewRef(op->func_typeparams); ++ assert(PyTuple_Check(self->func_typeparams)); ++ return Py_NewRef(self->func_typeparams); + } + ++/*[clinic input] ++@critical_section ++@setter ++function.__type_params__ ++[clinic start generated code]*/ ++ + static int +-func_set_type_params(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) ++function___type_params___set_impl(PyFunctionObject *self, PyObject *value) ++/*[clinic end generated code: output=038b4cda220e56fb input=3862fbd4db2b70e8]*/ + { + /* Not legal to del f.__type_params__ or to set it to anything + * other than a tuple object. */ +- PyFunctionObject *op = _PyFunction_CAST(self); + if (value == NULL || !PyTuple_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "__type_params__ must be set to a tuple"); + return -1; + } +- Py_XSETREF(op->func_typeparams, Py_NewRef(value)); ++ Py_XSETREF(self->func_typeparams, Py_NewRef(value)); + return 0; + } + +@@ -930,22 +984,15 @@ + {"__code__", func_get_code, func_set_code}, + {"__defaults__", func_get_defaults, func_set_defaults}, + {"__kwdefaults__", func_get_kwdefaults, func_set_kwdefaults}, +- {"__annotations__", func_get_annotations, func_set_annotations}, +- {"__annotate__", func_get_annotate, func_set_annotate}, ++ FUNCTION___ANNOTATIONS___GETSETDEF ++ FUNCTION___ANNOTATE___GETSETDEF + {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict}, + {"__name__", func_get_name, func_set_name}, + {"__qualname__", func_get_qualname, func_set_qualname}, +- {"__type_params__", func_get_type_params, func_set_type_params}, ++ FUNCTION___TYPE_PARAMS___GETSETDEF + {NULL} /* Sentinel */ + }; + +-/*[clinic input] +-class function "PyFunctionObject *" "&PyFunction_Type" +-[clinic start generated code]*/ +-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=70af9c90aa2e71b0]*/ +- +-#include "clinic/funcobject.c.h" +- + /* function.__new__() maintains the following invariants for closures. + The closure must correspond to the free variables of the code object. + +diff --git a/Objects/genobject.c b/Objects/genobject.c +index e87f199c250..79aed8571c3 100644 +--- a/Objects/genobject.c ++++ b/Objects/genobject.c +@@ -97,8 +97,10 @@ + + PyObject *res = PyObject_CallOneArg(finalizer, self); + if (res == NULL) { +- PyErr_WriteUnraisable(self); +- } else { ++ PyErr_FormatUnraisable("Exception ignored while " ++ "finalizing generator %R", self); ++ } ++ else { + Py_DECREF(res); + } + /* Restore the saved exception. */ +@@ -122,7 +124,8 @@ + PyObject *res = gen_close((PyObject*)gen, NULL); + if (res == NULL) { + if (PyErr_Occurred()) { +- PyErr_WriteUnraisable(self); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "closing generator %R", self); + } + } + else { +@@ -134,6 +137,19 @@ + PyErr_SetRaisedException(exc); + } + ++static void ++gen_clear_frame(PyGenObject *gen) ++{ ++ if (gen->gi_frame_state == FRAME_CLEARED) ++ return; ++ ++ gen->gi_frame_state = FRAME_CLEARED; ++ _PyInterpreterFrame *frame = &gen->gi_iframe; ++ frame->previous = NULL; ++ _PyFrame_ClearExceptCode(frame); ++ _PyErr_ClearExcState(&gen->gi_exc_state); ++} ++ + static void + gen_dealloc(PyObject *self) + { +@@ -159,13 +175,7 @@ + if (PyCoro_CheckExact(gen)) { + Py_CLEAR(((PyCoroObject *)gen)->cr_origin_or_finalizer); + } +- if (gen->gi_frame_state != FRAME_CLEARED) { +- _PyInterpreterFrame *frame = &gen->gi_iframe; +- gen->gi_frame_state = FRAME_CLEARED; +- frame->previous = NULL; +- _PyFrame_ClearExceptCode(frame); +- _PyErr_ClearExcState(&gen->gi_exc_state); +- } ++ gen_clear_frame(gen); + assert(gen->gi_exc_state.exc_value == NULL); + PyStackRef_CLEAR(gen->gi_iframe.f_executable); + Py_CLEAR(gen->gi_name); +@@ -331,7 +341,8 @@ + else { + PyObject *meth; + if (PyObject_GetOptionalAttr(yf, &_Py_ID(close), &meth) < 0) { +- PyErr_WriteUnraisable(yf); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "closing generator %R", yf); + } + if (meth) { + retval = _PyObject_CallNoArgs(meth); +@@ -400,7 +411,7 @@ + // RESUME after YIELD_VALUE and exception depth is 1 + assert((oparg & RESUME_OPARG_LOCATION_MASK) != RESUME_AT_FUNC_START); + gen->gi_frame_state = FRAME_COMPLETED; +- _PyFrame_ClearLocals(&gen->gi_iframe); ++ gen_clear_frame(gen); + Py_RETURN_NONE; + } + } +@@ -633,30 +644,19 @@ + int + _PyGen_SetStopIterationValue(PyObject *value) + { +- PyObject *e; +- +- if (value == NULL || +- (!PyTuple_Check(value) && !PyExceptionInstance_Check(value))) +- { +- /* Delay exception instantiation if we can */ +- PyErr_SetObject(PyExc_StopIteration, value); +- return 0; +- } +- /* Construct an exception instance manually with +- * PyObject_CallOneArg and pass it to PyErr_SetObject. +- * +- * We do this to handle a situation when "value" is a tuple, in which +- * case PyErr_SetObject would set the value of StopIteration to +- * the first element of the tuple. +- * +- * (See PyErr_SetObject/_PyErr_CreateException code for details.) +- */ +- e = PyObject_CallOneArg(PyExc_StopIteration, value); +- if (e == NULL) { ++ assert(!PyErr_Occurred()); ++ // Construct an exception instance manually with PyObject_CallOneArg() ++ // but use PyErr_SetRaisedException() instead of PyErr_SetObject() as ++ // PyErr_SetObject(exc_type, value) has a fast path when 'value' ++ // is a tuple, where the value of the StopIteration exception would be ++ // set to 'value[0]' instead of 'value'. ++ PyObject *exc = value == NULL ++ ? PyObject_CallNoArgs(PyExc_StopIteration) ++ : PyObject_CallOneArg(PyExc_StopIteration, value); ++ if (exc == NULL) { + return -1; + } +- PyErr_SetObject(PyExc_StopIteration, e); +- Py_DECREF(e); ++ PyErr_SetRaisedException(exc /* stolen */); + return 0; + } + +@@ -1157,7 +1157,6 @@ + return _gen_getcode(_PyGen_CAST(coro), "cr_code"); + } + +- + static PyGetSetDef coro_getsetlist[] = { + {"__name__", gen_get_name, gen_set_name, + PyDoc_STR("name of the coroutine")}, +diff --git a/Objects/iterobject.c b/Objects/iterobject.c +index 135ced9ea1f..ebb342ff109 100644 +--- a/Objects/iterobject.c ++++ b/Objects/iterobject.c +@@ -384,6 +384,7 @@ + return result; + } + if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration)) { ++ PyErr_Clear(); + _PyGen_SetStopIterationValue(obj->default_value); + } + return NULL; +@@ -407,6 +408,7 @@ + * exception we replace it with a `StopIteration(default)`, as if + * it was the return value of `__anext__()` coroutine. + */ ++ PyErr_Clear(); + _PyGen_SetStopIterationValue(obj->default_value); + } + return NULL; +diff --git a/Objects/listobject.c b/Objects/listobject.c +index a877bad66be..120e353b709 100644 +--- a/Objects/listobject.c ++++ b/Objects/listobject.c +@@ -335,11 +335,7 @@ + if (!valid_index(idx, size)) { + goto exit; + } +-#ifdef Py_GIL_DISABLED + item = _Py_NewRefWithLock(self->ob_item[idx]); +-#else +- item = Py_NewRef(self->ob_item[idx]); +-#endif + exit: + Py_END_CRITICAL_SECTION(); + return item; +@@ -423,7 +419,6 @@ + PyList_SetItem(PyObject *op, Py_ssize_t i, + PyObject *newitem) + { +- PyObject **p; + if (!PyList_Check(op)) { + Py_XDECREF(newitem); + PyErr_BadInternalCall(); +@@ -439,8 +434,9 @@ + ret = -1; + goto end; + } +- p = self->ob_item + i; +- Py_XSETREF(*p, newitem); ++ PyObject *tmp = self->ob_item[i]; ++ FT_ATOMIC_STORE_PTR_RELEASE(self->ob_item[i], newitem); ++ Py_XDECREF(tmp); + ret = 0; + end:; + Py_END_CRITICAL_SECTION(); +@@ -470,8 +466,8 @@ + where = n; + items = self->ob_item; + for (i = n; --i >= where; ) +- items[i+1] = items[i]; +- items[where] = Py_NewRef(v); ++ FT_ATOMIC_STORE_PTR_RELAXED(items[i+1], items[i]); ++ FT_ATOMIC_STORE_PTR_RELEASE(items[where], Py_NewRef(v)); + return 0; + } + +@@ -3194,7 +3190,7 @@ + } + + PyObject * +-_PyList_FromStackRefSteal(const _PyStackRef *src, Py_ssize_t n) ++_PyList_FromStackRefStealOnSuccess(const _PyStackRef *src, Py_ssize_t n) + { + if (n == 0) { + return PyList_New(0); +@@ -3202,9 +3198,6 @@ + + PyListObject *list = (PyListObject *)PyList_New(n); + if (list == NULL) { +- for (Py_ssize_t i = 0; i < n; i++) { +- PyStackRef_CLOSE(src[i]); +- } + return NULL; + } + +@@ -3910,15 +3903,17 @@ + static PyObject * + list_iter(PyObject *seq) + { +- _PyListIterObject *it; +- + if (!PyList_Check(seq)) { + PyErr_BadInternalCall(); + return NULL; + } +- it = PyObject_GC_New(_PyListIterObject, &PyListIter_Type); +- if (it == NULL) +- return NULL; ++ _PyListIterObject *it = _Py_FREELIST_POP(_PyListIterObject, list_iters); ++ if (it == NULL) { ++ it = PyObject_GC_New(_PyListIterObject, &PyListIter_Type); ++ if (it == NULL) { ++ return NULL; ++ } ++ } + it->it_index = 0; + it->it_seq = (PyListObject *)Py_NewRef(seq); + _PyObject_GC_TRACK(it); +@@ -3931,7 +3926,8 @@ + _PyListIterObject *it = (_PyListIterObject *)self; + _PyObject_GC_UNTRACK(it); + Py_XDECREF(it->it_seq); +- PyObject_GC_Del(it); ++ assert(Py_IS_TYPE(self, &PyListIter_Type)); ++ _Py_FREELIST_FREE(list_iters, it, PyObject_GC_Del); + } + + static int +diff --git a/Objects/longobject.c b/Objects/longobject.c +index bd7ff68d089..370328dcfe8 100644 +--- a/Objects/longobject.c ++++ b/Objects/longobject.c +@@ -152,11 +152,11 @@ + # define MAX_LONG_DIGITS ((INT64_MAX-1) / PyLong_SHIFT) + #endif + +-PyLongObject * +-_PyLong_New(Py_ssize_t size) ++static PyLongObject * ++long_alloc(Py_ssize_t size) + { + assert(size >= 0); +- PyLongObject *result; ++ PyLongObject *result = NULL; + if (size > (Py_ssize_t)MAX_LONG_DIGITS) { + PyErr_SetString(PyExc_OverflowError, + "too many digits in integer"); +@@ -165,25 +165,37 @@ + /* Fast operations for single digit integers (including zero) + * assume that there is always at least one digit present. */ + Py_ssize_t ndigits = size ? size : 1; +- /* Number of bytes needed is: offsetof(PyLongObject, ob_digit) + +- sizeof(digit)*size. Previous incarnations of this code used +- sizeof() instead of the offsetof, but this risks being +- incorrect in the presence of padding between the header +- and the digits. */ +- result = PyObject_Malloc(offsetof(PyLongObject, long_value.ob_digit) + +- ndigits*sizeof(digit)); +- if (!result) { +- PyErr_NoMemory(); +- return NULL; ++ ++ if (ndigits == 1) { ++ result = (PyLongObject *)_Py_FREELIST_POP(PyLongObject, ints); ++ } ++ if (result == NULL) { ++ /* Number of bytes needed is: offsetof(PyLongObject, ob_digit) + ++ sizeof(digit)*size. Previous incarnations of this code used ++ sizeof() instead of the offsetof, but this risks being ++ incorrect in the presence of padding between the header ++ and the digits. */ ++ result = PyObject_Malloc(offsetof(PyLongObject, long_value.ob_digit) + ++ ndigits*sizeof(digit)); ++ if (!result) { ++ PyErr_NoMemory(); ++ return NULL; ++ } ++ _PyObject_Init((PyObject*)result, &PyLong_Type); + } + _PyLong_SetSignAndDigitCount(result, size != 0, size); +- _PyObject_Init((PyObject*)result, &PyLong_Type); + /* The digit has to be initialized explicitly to avoid + * use-of-uninitialized-value. */ + result->long_value.ob_digit[0] = 0; + return result; + } + ++PyLongObject * ++_PyLong_New(Py_ssize_t size) ++{ ++ return long_alloc(size); ++} ++ + PyLongObject * + _PyLong_FromDigits(int negative, Py_ssize_t digit_count, digit *digits) + { +@@ -191,9 +203,8 @@ + if (digit_count == 0) { + return (PyLongObject *)_PyLong_GetZero(); + } +- PyLongObject *result = _PyLong_New(digit_count); ++ PyLongObject *result = long_alloc(digit_count); + if (result == NULL) { +- PyErr_NoMemory(); + return NULL; + } + _PyLong_SetSignAndDigitCount(result, negative?-1:1, digit_count); +@@ -205,15 +216,29 @@ + _PyLong_Copy(PyLongObject *src) + { + assert(src != NULL); ++ int sign; + + if (_PyLong_IsCompact(src)) { + stwodigits ival = medium_value(src); + if (IS_SMALL_INT(ival)) { + return get_small_int((sdigit)ival); + } ++ sign = _PyLong_CompactSign(src); ++ } ++ else { ++ sign = _PyLong_NonCompactSign(src); + } ++ + Py_ssize_t size = _PyLong_DigitCount(src); +- return (PyObject *)_PyLong_FromDigits(_PyLong_IsNegative(src), size, src->long_value.ob_digit); ++ PyLongObject *result = long_alloc(size); ++ ++ if (result == NULL) { ++ return NULL; ++ } ++ _PyLong_SetSignAndDigitCount(result, sign, size); ++ memcpy(result->long_value.ob_digit, src->long_value.ob_digit, ++ size * sizeof(digit)); ++ return (PyObject *)result; + } + + static PyObject * +@@ -262,7 +287,7 @@ + ++ndigits; + t >>= PyLong_SHIFT; + } +- PyLongObject *v = _PyLong_New(ndigits); ++ PyLongObject *v = long_alloc(ndigits); + if (v != NULL) { + digit *p = v->long_value.ob_digit; + _PyLong_SetSignAndDigitCount(v, sign, ndigits); +@@ -335,7 +360,7 @@ + } + + /* Construct output value. */ +- v = _PyLong_New(ndigits); ++ v = long_alloc(ndigits); + if (v != NULL) { + digit *p = v->long_value.ob_digit; + _PyLong_SetSignAndDigitCount(v, ival < 0 ? -1 : 1, ndigits); +@@ -353,14 +378,18 @@ + if (IS_SMALL_UINT(ival)) { \ + return get_small_int((sdigit)(ival)); \ + } \ ++ if ((ival) <= PyLong_MASK) { \ ++ return _PyLong_FromMedium((sdigit)(ival)); \ ++ } \ ++ /* Do shift in two steps to avoid possible undefined behavior. */ \ ++ INT_TYPE t = (ival) >> PyLong_SHIFT >> PyLong_SHIFT; \ + /* Count the number of Python digits. */ \ +- Py_ssize_t ndigits = 0; \ +- INT_TYPE t = (ival); \ ++ Py_ssize_t ndigits = 2; \ + while (t) { \ + ++ndigits; \ + t >>= PyLong_SHIFT; \ + } \ +- PyLongObject *v = _PyLong_New(ndigits); \ ++ PyLongObject *v = long_alloc(ndigits); \ + if (v == NULL) { \ + return NULL; \ + } \ +@@ -437,7 +466,7 @@ + frac = frexp(dval, &expo); /* dval = frac*2**expo; 0.0 <= frac < 1.0 */ + assert(expo > 0); + ndig = (expo-1) / PyLong_SHIFT + 1; /* Number of 'digits' in result */ +- v = _PyLong_New(ndig); ++ v = long_alloc(ndig); + if (v == NULL) + return NULL; + frac = ldexp(frac, (expo-1) % PyLong_SHIFT + 1); +@@ -821,19 +850,25 @@ + return _PyLong_IsZero((PyLongObject *)obj); + } + +-int +-_PyLong_Sign(PyObject *vv) ++static int ++long_sign(PyObject *vv) + { ++ assert(vv != NULL); ++ assert(PyLong_Check(vv)); + PyLongObject *v = (PyLongObject *)vv; + +- assert(v != NULL); +- assert(PyLong_Check(v)); + if (_PyLong_IsCompact(v)) { + return _PyLong_CompactSign(v); + } + return _PyLong_NonCompactSign(v); + } + ++int ++_PyLong_Sign(PyObject *vv) ++{ ++ return long_sign(vv); ++} ++ + int + PyLong_GetSign(PyObject *vv, int *sign) + { +@@ -842,7 +877,7 @@ + return -1; + } + +- *sign = _PyLong_Sign(vv); ++ *sign = long_sign(vv); + return 0; + } + +@@ -940,7 +975,7 @@ + return NULL; + } + ndigits = (numsignificantbytes * 8 + PyLong_SHIFT - 1) / PyLong_SHIFT; +- v = _PyLong_New(ndigits); ++ v = long_alloc(ndigits); + if (v == NULL) + return NULL; + +@@ -1470,7 +1505,7 @@ + } + + /* Construct output value. */ +- v = _PyLong_New(ndigits); ++ v = long_alloc(ndigits); + if (v != NULL) { + digit *p = v->long_value.ob_digit; + _PyLong_SetSignAndDigitCount(v, ival < 0 ? -1 : 1, ndigits); +@@ -1513,7 +1548,7 @@ + ++ndigits; + t >>= PyLong_SHIFT; + } +- v = _PyLong_New(ndigits); ++ v = long_alloc(ndigits); + if (v != NULL) { + digit *p = v->long_value.ob_digit; + _PyLong_SetSignAndDigitCount(v, negative ? -1 : 1, ndigits); +@@ -2003,7 +2038,7 @@ + PyLongObject *z; + + assert(n > 0 && n <= PyLong_MASK); +- z = _PyLong_New(size); ++ z = long_alloc(size); + if (z == NULL) + return NULL; + *prem = inplace_divrem1(z->long_value.ob_digit, a->long_value.ob_digit, size, n); +@@ -2180,7 +2215,7 @@ + (10 * PyLong_SHIFT - 33 * _PyLong_DECIMAL_SHIFT); + assert(size_a < PY_SSIZE_T_MAX/2); + size = 1 + size_a + size_a / d; +- scratch = _PyLong_New(size); ++ scratch = long_alloc(size); + if (scratch == NULL) + return -1; + +@@ -2623,7 +2658,7 @@ + return 0; + } + n = (digits * bits_per_char + PyLong_SHIFT - 1) / PyLong_SHIFT; +- z = _PyLong_New(n); ++ z = long_alloc(n); + if (z == NULL) { + *res = NULL; + return 0; +@@ -2827,7 +2862,7 @@ + */ + double fsize_z = (double)digits * log_base_BASE[base] + 1.0; + if (fsize_z > (double)MAX_LONG_DIGITS) { +- /* The same exception as in _PyLong_New(). */ ++ /* The same exception as in long_alloc(). */ + PyErr_SetString(PyExc_OverflowError, + "too many digits in integer"); + *res = NULL; +@@ -2837,7 +2872,7 @@ + /* Uncomment next line to test exceedingly rare copy code */ + /* size_z = 1; */ + assert(size_z > 0); +- z = _PyLong_New(size_z); ++ z = long_alloc(size_z); + if (z == NULL) { + *res = NULL; + return 0; +@@ -2900,7 +2935,7 @@ + PyLongObject *tmp; + /* Extremely rare. Get more space. */ + assert(_PyLong_DigitCount(z) == size_z); +- tmp = _PyLong_New(size_z + 1); ++ tmp = long_alloc(size_z + 1); + if (tmp == NULL) { + Py_DECREF(z); + *res = NULL; +@@ -3321,12 +3356,12 @@ + size_v = _PyLong_DigitCount(v1); + size_w = _PyLong_DigitCount(w1); + assert(size_v >= size_w && size_w >= 2); /* Assert checks by div() */ +- v = _PyLong_New(size_v+1); ++ v = long_alloc(size_v+1); + if (v == NULL) { + *prem = NULL; + return NULL; + } +- w = _PyLong_New(size_w); ++ w = long_alloc(size_w); + if (w == NULL) { + Py_DECREF(v); + *prem = NULL; +@@ -3348,7 +3383,7 @@ + at most (and usually exactly) k = size_v - size_w digits. */ + k = size_v - size_w; + assert(k >= 0); +- a = _PyLong_New(k); ++ a = long_alloc(k); + if (a == NULL) { + Py_DECREF(w); + Py_DECREF(v); +@@ -3616,32 +3651,25 @@ + } + + static inline int +-compact_int_is_small(PyObject *self) ++/// Return 1 if the object is one of the immortal small ints ++_long_is_small_int(PyObject *op) + { +- PyLongObject *pylong = (PyLongObject *)self; +- assert(_PyLong_IsCompact(pylong)); +- stwodigits ival = medium_value(pylong); +- if (IS_SMALL_INT(ival)) { +- PyLongObject *small_pylong = (PyLongObject *)get_small_int((sdigit)ival); +- if (pylong == small_pylong) { +- return 1; +- } +- } +- return 0; ++ PyLongObject *long_object = (PyLongObject *)op; ++ int is_small_int = (long_object->long_value.lv_tag & IMMORTALITY_BIT_MASK) != 0; ++ assert((!is_small_int) || PyLong_CheckExact(op)); ++ return is_small_int; + } + + void + _PyLong_ExactDealloc(PyObject *self) + { + assert(PyLong_CheckExact(self)); ++ if (_long_is_small_int(self)) { ++ // See PEP 683, section Accidental De-Immortalizing for details ++ _Py_SetImmortal(self); ++ return; ++ } + if (_PyLong_IsCompact((PyLongObject *)self)) { +- #ifndef Py_GIL_DISABLED +- if (compact_int_is_small(self)) { +- // See PEP 683, section Accidental De-Immortalizing for details +- _Py_SetImmortal(self); +- return; +- } +- #endif + _Py_FREELIST_FREE(ints, self, PyObject_Free); + return; + } +@@ -3651,24 +3679,20 @@ + static void + long_dealloc(PyObject *self) + { +- assert(self); +- if (_PyLong_IsCompact((PyLongObject *)self)) { +- if (compact_int_is_small(self)) { +- /* This should never get called, but we also don't want to SEGV if +- * we accidentally decref small Ints out of existence. Instead, +- * since small Ints are immortal, re-set the reference count. +- * +- * See PEP 683, section Accidental De-Immortalizing for details +- */ +- _Py_SetImmortal(self); +- return; +- } +- if (PyLong_CheckExact(self)) { +- _Py_FREELIST_FREE(ints, self, PyObject_Free); +- return; +- } ++ if (_long_is_small_int(self)) { ++ /* This should never get called, but we also don't want to SEGV if ++ * we accidentally decref small Ints out of existence. Instead, ++ * since small Ints are immortal, re-set the reference count. ++ * ++ * See PEP 683, section Accidental De-Immortalizing for details ++ */ ++ _Py_SetImmortal(self); ++ return; ++ } ++ if (PyLong_CheckExact(self) && _PyLong_IsCompact((PyLongObject *)self)) { ++ _Py_FREELIST_FREE(ints, self, PyObject_Free); ++ return; + } +- + Py_TYPE(self)->tp_free(self); + } + +@@ -3746,7 +3770,7 @@ + size_a = size_b; + size_b = size_temp; } + } +- z = _PyLong_New(size_a+1); ++ z = long_alloc(size_a+1); + if (z == NULL) + return NULL; + for (i = 0; i < size_b; ++i) { +@@ -3795,7 +3819,7 @@ + } + size_a = size_b = i+1; + } +- z = _PyLong_New(size_a); ++ z = long_alloc(size_a); + if (z == NULL) + return NULL; + for (i = 0; i < size_b; ++i) { +@@ -3920,7 +3944,7 @@ + Py_ssize_t size_b = _PyLong_DigitCount(b); + Py_ssize_t i; + +- z = _PyLong_New(size_a + size_b); ++ z = long_alloc(size_a + size_b); + if (z == NULL) + return NULL; + +@@ -4030,9 +4054,9 @@ + size_lo = Py_MIN(size_n, size); + size_hi = size_n - size_lo; + +- if ((hi = _PyLong_New(size_hi)) == NULL) ++ if ((hi = long_alloc(size_hi)) == NULL) + return -1; +- if ((lo = _PyLong_New(size_lo)) == NULL) { ++ if ((lo = long_alloc(size_lo)) == NULL) { + Py_DECREF(hi); + return -1; + } +@@ -4132,7 +4156,7 @@ + */ + + /* 1. Allocate result space. */ +- ret = _PyLong_New(asize + bsize); ++ ret = long_alloc(asize + bsize); + if (ret == NULL) goto fail; + #ifdef Py_DEBUG + /* Fill with trash, to catch reference to uninitialized digits. */ +@@ -4282,13 +4306,13 @@ + assert(2 * asize <= bsize); + + /* Allocate result space, and zero it out. */ +- ret = _PyLong_New(asize + bsize); ++ ret = long_alloc(asize + bsize); + if (ret == NULL) + return NULL; + memset(ret->long_value.ob_digit, 0, _PyLong_DigitCount(ret) * sizeof(digit)); + + /* Successive slices of b are copied into bslice. */ +- bslice = _PyLong_New(asize); ++ bslice = long_alloc(asize); + if (bslice == NULL) + goto fail; + +@@ -4754,7 +4778,7 @@ + "intermediate overflow during division"); + goto error; + } +- x = _PyLong_New(a_size + shift_digits + 1); ++ x = long_alloc(a_size + shift_digits + 1); + if (x == NULL) + goto error; + for (i = 0; i < shift_digits; i++) +@@ -4768,7 +4792,7 @@ + digit rem; + /* x = a >> shift */ + assert(a_size >= shift_digits); +- x = _PyLong_New(a_size - shift_digits); ++ x = long_alloc(a_size - shift_digits); + if (x == NULL) + goto error; + rem = v_rshift(x->long_value.ob_digit, a->long_value.ob_digit + shift_digits, +@@ -5348,7 +5372,7 @@ + /* Shifting all the bits of 'a' out gives either -1 or 0. */ + return PyLong_FromLong(-a_negative); + } +- z = _PyLong_New(newsize); ++ z = long_alloc(newsize); + if (z == NULL) { + return NULL; + } +@@ -5463,7 +5487,7 @@ + newsize = oldsize + wordshift; + if (remshift) + ++newsize; +- z = _PyLong_New(newsize); ++ z = long_alloc(newsize); + if (z == NULL) + return NULL; + if (_PyLong_IsNegative(a)) { +@@ -5578,7 +5602,7 @@ + size_a = _PyLong_DigitCount(a); + nega = _PyLong_IsNegative(a); + if (nega) { +- z = _PyLong_New(size_a); ++ z = long_alloc(size_a); + if (z == NULL) + return NULL; + v_complement(z->long_value.ob_digit, a->long_value.ob_digit, size_a); +@@ -5592,7 +5616,7 @@ + size_b = _PyLong_DigitCount(b); + negb = _PyLong_IsNegative(b); + if (negb) { +- z = _PyLong_New(size_b); ++ z = long_alloc(size_b); + if (z == NULL) { + Py_DECREF(a); + return NULL; +@@ -5636,7 +5660,7 @@ + + /* We allow an extra digit if z is negative, to make sure that + the final two's complement of z doesn't overflow. */ +- z = _PyLong_New(size_z + negz); ++ z = long_alloc(size_z + negz); + if (z == NULL) { + Py_DECREF(a); + Py_DECREF(b); +@@ -5834,7 +5858,7 @@ + } + else { + alloc_a = size_a; +- c = _PyLong_New(size_a); ++ c = long_alloc(size_a); + if (c == NULL) + goto error; + } +@@ -5850,7 +5874,7 @@ + } + else { + alloc_b = size_a; +- d = _PyLong_New(size_a); ++ d = long_alloc(size_a); + if (d == NULL) + goto error; + } +@@ -6030,7 +6054,7 @@ + return NULL; + } + assert(PyLong_Check(newobj)); +- newobj->long_value.lv_tag = tmp->long_value.lv_tag; ++ newobj->long_value.lv_tag = tmp->long_value.lv_tag & ~IMMORTALITY_BIT_MASK; + for (i = 0; i < n; i++) { + newobj->long_value.ob_digit[i] = tmp->long_value.ob_digit[i]; + } +@@ -6898,7 +6922,7 @@ + } + assert(digits != NULL); + +- PyLongObject *obj = _PyLong_New(ndigits); ++ PyLongObject *obj = long_alloc(ndigits); + if (obj == NULL) { + goto error; + } +@@ -6918,6 +6942,10 @@ + void + PyLongWriter_Discard(PyLongWriter *writer) + { ++ if (writer == NULL) { ++ return; ++ } ++ + PyLongObject *obj = (PyLongObject *)writer; + assert(Py_REFCNT(obj) == 1); + Py_DECREF(obj); +diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c +index ea4d24dc690..331363b2bab 100644 +--- a/Objects/memoryobject.c ++++ b/Objects/memoryobject.c +@@ -2083,7 +2083,7 @@ + PyObject *format = NULL; + struct unpacker *x = NULL; + +- Struct = _PyImport_GetModuleAttrString("struct", "Struct"); ++ Struct = PyImport_ImportModuleAttrString("struct", "Struct"); + if (Struct == NULL) + return NULL; + +diff --git a/Objects/methodobject.c b/Objects/methodobject.c +index 345da460742..ecec0f7205a 100644 +--- a/Objects/methodobject.c ++++ b/Objects/methodobject.c +@@ -331,7 +331,7 @@ + { + PyCFunctionObject *a = _PyCFunctionObject_CAST(self); + Py_hash_t x = PyObject_GenericHash(a->m_self); +- Py_hash_t y = _Py_HashPointer((void*)(a->m_ml->ml_meth)); ++ Py_hash_t y = Py_HashPointer((void*)(a->m_ml->ml_meth)); + x ^= y; + if (x == -1) { + x = -2; +diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c +index a8d64c9aefa..740392b061b 100644 +--- a/Objects/moduleobject.c ++++ b/Objects/moduleobject.c +@@ -703,7 +703,8 @@ + PyErr_Clear(); + } + if (PyDict_SetItem(d, key, Py_None) != 0) { +- PyErr_FormatUnraisable("Exception ignored on clearing module dict"); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "clearing module dict"); + } + } + } +@@ -724,7 +725,8 @@ + PyErr_Clear(); + } + if (PyDict_SetItem(d, key, Py_None) != 0) { +- PyErr_FormatUnraisable("Exception ignored on clearing module dict"); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "clearing module dict"); + } + } + } +diff --git a/Objects/namespaceobject.c b/Objects/namespaceobject.c +index 5b7547103a2..4ef3bd92f5a 100644 +--- a/Objects/namespaceobject.c ++++ b/Objects/namespaceobject.c +@@ -141,6 +141,10 @@ + goto error; + } + ++ if (PyErr_Occurred()) { ++ goto error; ++ } ++ + separator = PyUnicode_FromString(", "); + if (separator == NULL) + goto error; +diff --git a/Objects/object.c b/Objects/object.c +index d584414c559..f3c7fa6d906 100644 +--- a/Objects/object.c ++++ b/Objects/object.c +@@ -19,7 +19,7 @@ + #include "pycore_object.h" // PyAPI_DATA() _Py_SwappedOp definition + #include "pycore_object_state.h" // struct _reftracer_runtime_state + #include "pycore_long.h" // _PyLong_GetZero() +-#include "pycore_optimizer.h" // _PyUOpExecutor_Type, _PyUOpOptimizer_Type, ... ++#include "pycore_optimizer.h" // _PyUOpExecutor_Type, ... + #include "pycore_pyerrors.h" // _PyErr_Occurred() + #include "pycore_pymem.h" // _PyMem_IsPtrFreed() + #include "pycore_pystate.h" // _PyThreadState_GET() +@@ -923,6 +923,8 @@ + clear_freelist(&freelists->tuples[i], is_finalization, free_object); + } + clear_freelist(&freelists->lists, is_finalization, free_object); ++ clear_freelist(&freelists->list_iters, is_finalization, free_object); ++ clear_freelist(&freelists->tuple_iters, is_finalization, free_object); + clear_freelist(&freelists->dicts, is_finalization, free_object); + clear_freelist(&freelists->dictkeys, is_finalization, PyMem_Free); + clear_freelist(&freelists->slices, is_finalization, free_object); +@@ -937,6 +939,7 @@ + } + clear_freelist(&freelists->unicode_writers, is_finalization, PyMem_Free); + clear_freelist(&freelists->ints, is_finalization, free_object); ++ clear_freelist(&freelists->pymethodobjects, is_finalization, free_object); + } + + /* +@@ -1717,7 +1720,11 @@ + else { + PyObject **dictptr = _PyObject_ComputedDictPointer(obj); + if (dictptr) { ++#ifdef Py_GIL_DISABLED ++ dict = _Py_atomic_load_ptr_acquire(dictptr); ++#else + dict = *dictptr; ++#endif + } + } + } +@@ -2374,11 +2381,6 @@ + &_PyBufferWrapper_Type, + &_PyContextTokenMissing_Type, + &_PyCoroWrapper_Type, +-#ifdef _Py_TIER2 +- &_PyCounterExecutor_Type, +- &_PyCounterOptimizer_Type, +- &_PyDefaultOptimizer_Type, +-#endif + &_Py_GenericAliasIterType, + &_PyHamtItems_Type, + &_PyHamtKeys_Type, +@@ -2401,7 +2403,6 @@ + &_PyUnion_Type, + #ifdef _Py_TIER2 + &_PyUOpExecutor_Type, +- &_PyUOpOptimizer_Type, + #endif + &_PyWeakref_CallableProxyType, + &_PyWeakref_ProxyType, +@@ -2484,13 +2485,20 @@ + op->ob_refcnt = 1; + #endif + #else +- op->ob_tid = _Py_ThreadId(); + op->ob_flags = 0; + op->ob_mutex = (PyMutex){ 0 }; ++#ifdef _Py_THREAD_SANITIZER ++ _Py_atomic_store_uintptr_relaxed(&op->ob_tid, _Py_ThreadId()); ++ _Py_atomic_store_uint8_relaxed(&op->ob_gc_bits, 0); ++ _Py_atomic_store_uint32_relaxed(&op->ob_ref_local, 1); ++ _Py_atomic_store_ssize_relaxed(&op->ob_ref_shared, 0); ++#else ++ op->ob_tid = _Py_ThreadId(); + op->ob_gc_bits = 0; + op->ob_ref_local = 1; + op->ob_ref_shared = 0; + #endif ++#endif + #ifdef Py_TRACE_REFS + _Py_AddToAllObjects(op); + #endif +@@ -2585,6 +2593,20 @@ + #endif + } + ++int ++PyUnstable_TryIncRef(PyObject *op) ++{ ++ return _Py_TryIncref(op); ++} ++ ++void ++PyUnstable_EnableTryIncRef(PyObject *op) ++{ ++#ifdef Py_GIL_DISABLED ++ _PyObject_SetMaybeWeakref(op); ++#endif ++} ++ + void + _Py_ResurrectReference(PyObject *op) + { +@@ -3070,14 +3092,14 @@ + } + + int PyRefTracer_SetTracer(PyRefTracer tracer, void *data) { +- assert(PyGILState_Check()); ++ _Py_AssertHoldsTstate(); + _PyRuntime.ref_tracer.tracer_func = tracer; + _PyRuntime.ref_tracer.tracer_data = data; + return 0; + } + + PyRefTracer PyRefTracer_GetTracer(void** data) { +- assert(PyGILState_Check()); ++ _Py_AssertHoldsTstate(); + if (data != NULL) { + *data = _PyRuntime.ref_tracer.tracer_data; + } +@@ -3152,3 +3174,12 @@ + { + return _Py_REFCNT(ob); + } ++ ++int ++PyUnstable_IsImmortal(PyObject *op) ++{ ++ /* Checking a reference count requires a thread state */ ++ _Py_AssertHoldsTstate(); ++ assert(op != NULL); ++ return _Py_IsImmortal(op); ++} +diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c +index b103deb01ca..5688049b024 100644 +--- a/Objects/obmalloc.c ++++ b/Objects/obmalloc.c +@@ -2909,7 +2909,8 @@ + static inline void + _PyMem_DebugCheckGIL(const char *func) + { +- if (!PyGILState_Check()) { ++ PyThreadState *tstate = _PyThreadState_GET(); ++ if (tstate == NULL) { + #ifndef Py_GIL_DISABLED + _Py_FatalErrorFunc(func, + "Python memory allocator called " +diff --git a/Objects/odictobject.c b/Objects/odictobject.c +index e151023dd76..f2d8da0c567 100644 +--- a/Objects/odictobject.c ++++ b/Objects/odictobject.c +@@ -260,7 +260,7 @@ + mp_subscript __getitem__ - dict_subscript + mp_ass_subscript __setitem__ - dict_ass_sub + __delitem__ +-tp_hash __hash__ _Py_HashPointer ..._HashNotImpl ++tp_hash __hash__ Py_HashPointer ..._HashNotImpl + tp_str __str__ object_str - + tp_getattro __getattribute__ ..._GenericGetAttr (repeated) + __getattr__ +diff --git a/Objects/setobject.c b/Objects/setobject.c +index 955ccbebf74..26ab352ca6d 100644 +--- a/Objects/setobject.c ++++ b/Objects/setobject.c +@@ -1298,7 +1298,7 @@ + PyObject *other; + Py_ssize_t i; + +- result = (PySetObject *)set_copy(so, NULL); ++ result = (PySetObject *)set_copy((PyObject *)so, NULL); + if (result == NULL) + return NULL; + +@@ -1321,13 +1321,12 @@ + + if (!PyAnySet_Check(self) || !PyAnySet_Check(other)) + Py_RETURN_NOTIMPLEMENTED; +- PySetObject *so = _PySet_CAST(self); + +- result = (PySetObject *)set_copy(so, NULL); ++ result = (PySetObject *)set_copy(self, NULL); + if (result == NULL) { + return NULL; + } +- if (Py_Is((PyObject *)so, other)) { ++ if (Py_Is(self, other)) { + return (PyObject *)result; + } + if (set_update_local(result, other)) { +@@ -1449,7 +1448,7 @@ + Py_ssize_t i; + + if (others_length == 0) { +- return set_copy(so, NULL); ++ return set_copy((PyObject *)so, NULL); + } + + PyObject *result = Py_NewRef(so); +@@ -1806,7 +1805,7 @@ + PyObject *result, *other; + + if (others_length == 0) { +- return set_copy(so, NULL); ++ return set_copy((PyObject *)so, NULL); + } + + other = others[0]; +@@ -1929,7 +1928,7 @@ + /*[clinic end generated code: output=fbb049c0806028de input=a50acf0365e1f0a5]*/ + { + if (Py_Is((PyObject *)so, other)) { +- return set_clear(so, NULL); ++ return set_clear((PyObject *)so, NULL); + } + + int rv; +@@ -2646,7 +2645,7 @@ + PyErr_BadInternalCall(); + return -1; + } +- (void)set_clear((PySetObject *)set, NULL); ++ (void)set_clear(set, NULL); + return 0; + } + +@@ -2742,7 +2741,7 @@ + PyErr_BadInternalCall(); + return NULL; + } +- return set_pop((PySetObject *)set, NULL); ++ return set_pop(set, NULL); + } + + int +diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c +index 4fef0af93fe..1b07c2a2c49 100644 +--- a/Objects/sliceobject.c ++++ b/Objects/sliceobject.c +@@ -399,11 +399,14 @@ + step_is_negative = 0; + } + else { +- int step_sign; + step = evaluate_slice_index(self->step); +- if (step == NULL) ++ if (step == NULL) { + goto error; +- step_sign = _PyLong_Sign(step); ++ } ++ assert(PyLong_Check(step)); ++ ++ int step_sign; ++ (void)PyLong_GetSign(step, &step_sign); + if (step_sign == 0) { + PyErr_SetString(PyExc_ValueError, + "slice step cannot be zero"); +diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c +index 49977726ead..60af9e40e3f 100644 +--- a/Objects/tupleobject.c ++++ b/Objects/tupleobject.c +@@ -391,16 +391,13 @@ + } + + PyObject * +-_PyTuple_FromStackRefSteal(const _PyStackRef *src, Py_ssize_t n) ++_PyTuple_FromStackRefStealOnSuccess(const _PyStackRef *src, Py_ssize_t n) + { + if (n == 0) { + return tuple_get_empty(); + } + PyTupleObject *tuple = tuple_alloc(n); + if (tuple == NULL) { +- for (Py_ssize_t i = 0; i < n; i++) { +- PyStackRef_CLOSE(src[i]); +- } + return NULL; + } + PyObject **dst = tuple->ob_item; +@@ -988,26 +985,30 @@ + + /*********************** Tuple Iterator **************************/ + ++#define _PyTupleIterObject_CAST(op) ((_PyTupleIterObject *)(op)) + + static void +-tupleiter_dealloc(_PyTupleIterObject *it) ++tupleiter_dealloc(PyObject *self) + { ++ _PyTupleIterObject *it = _PyTupleIterObject_CAST(self); + _PyObject_GC_UNTRACK(it); + Py_XDECREF(it->it_seq); +- PyObject_GC_Del(it); ++ assert(Py_IS_TYPE(self, &PyTupleIter_Type)); ++ _Py_FREELIST_FREE(tuple_iters, it, PyObject_GC_Del); + } + + static int +-tupleiter_traverse(_PyTupleIterObject *it, visitproc visit, void *arg) ++tupleiter_traverse(PyObject *self, visitproc visit, void *arg) + { ++ _PyTupleIterObject *it = _PyTupleIterObject_CAST(self); + Py_VISIT(it->it_seq); + return 0; + } + + static PyObject * +-tupleiter_next(PyObject *obj) ++tupleiter_next(PyObject *self) + { +- _PyTupleIterObject *it = (_PyTupleIterObject *)obj; ++ _PyTupleIterObject *it = _PyTupleIterObject_CAST(self); + PyTupleObject *seq; + PyObject *item; + +@@ -1029,8 +1030,9 @@ + } + + static PyObject * +-tupleiter_len(_PyTupleIterObject *it, PyObject *Py_UNUSED(ignored)) ++tupleiter_len(PyObject *self, PyObject *Py_UNUSED(ignored)) + { ++ _PyTupleIterObject *it = _PyTupleIterObject_CAST(self); + Py_ssize_t len = 0; + if (it->it_seq) + len = PyTuple_GET_SIZE(it->it_seq) - it->it_index; +@@ -1040,13 +1042,14 @@ + PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it))."); + + static PyObject * +-tupleiter_reduce(_PyTupleIterObject *it, PyObject *Py_UNUSED(ignored)) ++tupleiter_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *iter = _PyEval_GetBuiltin(&_Py_ID(iter)); + + /* _PyEval_GetBuiltin can invoke arbitrary code, + * call must be before access of iterator pointers. + * see issue #101765 */ ++ _PyTupleIterObject *it = _PyTupleIterObject_CAST(self); + + if (it->it_seq) + return Py_BuildValue("N(O)n", iter, it->it_seq, it->it_index); +@@ -1055,8 +1058,9 @@ + } + + static PyObject * +-tupleiter_setstate(_PyTupleIterObject *it, PyObject *state) ++tupleiter_setstate(PyObject *self, PyObject *state) + { ++ _PyTupleIterObject *it = _PyTupleIterObject_CAST(self); + Py_ssize_t index = PyLong_AsSsize_t(state); + if (index == -1 && PyErr_Occurred()) + return NULL; +@@ -1074,19 +1078,19 @@ + PyDoc_STRVAR(setstate_doc, "Set state information for unpickling."); + + static PyMethodDef tupleiter_methods[] = { +- {"__length_hint__", (PyCFunction)tupleiter_len, METH_NOARGS, length_hint_doc}, +- {"__reduce__", (PyCFunction)tupleiter_reduce, METH_NOARGS, reduce_doc}, +- {"__setstate__", (PyCFunction)tupleiter_setstate, METH_O, setstate_doc}, +- {NULL, NULL} /* sentinel */ ++ {"__length_hint__", tupleiter_len, METH_NOARGS, length_hint_doc}, ++ {"__reduce__", tupleiter_reduce, METH_NOARGS, reduce_doc}, ++ {"__setstate__", tupleiter_setstate, METH_O, setstate_doc}, ++ {NULL, NULL, 0, NULL} /* sentinel */ + }; + + PyTypeObject PyTupleIter_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "tuple_iterator", /* tp_name */ +- sizeof(_PyTupleIterObject), /* tp_basicsize */ ++ sizeof(_PyTupleIterObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ +- (destructor)tupleiter_dealloc, /* tp_dealloc */ ++ tupleiter_dealloc, /* tp_dealloc */ + 0, /* tp_vectorcall_offset */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ +@@ -1103,7 +1107,7 @@ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + 0, /* tp_doc */ +- (traverseproc)tupleiter_traverse, /* tp_traverse */ ++ tupleiter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ +@@ -1116,15 +1120,16 @@ + static PyObject * + tuple_iter(PyObject *seq) + { +- _PyTupleIterObject *it; +- + if (!PyTuple_Check(seq)) { + PyErr_BadInternalCall(); + return NULL; + } +- it = PyObject_GC_New(_PyTupleIterObject, &PyTupleIter_Type); +- if (it == NULL) +- return NULL; ++ _PyTupleIterObject *it = _Py_FREELIST_POP(_PyTupleIterObject, tuple_iters); ++ if (it == NULL) { ++ it = PyObject_GC_New(_PyTupleIterObject, &PyTupleIter_Type); ++ if (it == NULL) ++ return NULL; ++ } + it->it_index = 0; + it->it_seq = (PyTupleObject *)Py_NewRef(seq); + _PyObject_GC_TRACK(it); +diff --git a/Objects/typeobject.c b/Objects/typeobject.c +index 2068d6aa9be..f3238da8a64 100644 +--- a/Objects/typeobject.c ++++ b/Objects/typeobject.c +@@ -992,6 +992,7 @@ + set_version_unlocked(PyTypeObject *tp, unsigned int version) + { + ASSERT_TYPE_LOCK_HELD(); ++ assert(version == 0 || (tp->tp_versions_used != _Py_ATTR_CACHE_UNUSED)); + #ifndef Py_GIL_DISABLED + PyInterpreterState *interp = _PyInterpreterState_GET(); + // lookup the old version and set to null +@@ -1038,7 +1039,7 @@ + We don't assign new version tags eagerly, but only as + needed. + */ +- if (type->tp_version_tag == 0) { ++ if (FT_ATOMIC_LOAD_UINT_RELAXED(type->tp_version_tag) == 0) { + return; + } + // Cannot modify static builtin types. +@@ -1148,6 +1149,10 @@ + PyObject *b = PyTuple_GET_ITEM(bases, i); + PyTypeObject *cls = _PyType_CAST(b); + ++ if (cls->tp_versions_used >= _Py_ATTR_CACHE_UNUSED) { ++ goto clear; ++ } ++ + if (!is_subtype_with_mro(lookup_tp_mro(type), type, cls)) { + goto clear; + } +@@ -1156,7 +1161,8 @@ + + clear: + assert(!(type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN)); +- set_version_unlocked(type, 0); /* 0 is not a valid version tag */ ++ set_version_unlocked(type, 0); /* 0 is not a valid version tag */ ++ type->tp_versions_used = _Py_ATTR_CACHE_UNUSED; + if (PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) { + // This field *must* be invalidated if the type is modified (see the + // comment on struct _specialization_cache): +@@ -1208,6 +1214,9 @@ + + + #define MAX_VERSIONS_PER_CLASS 1000 ++#if _Py_ATTR_CACHE_UNUSED < MAX_VERSIONS_PER_CLASS ++#error "_Py_ATTR_CACHE_UNUSED must be bigger than max" ++#endif + + static int + assign_version_tag(PyInterpreterState *interp, PyTypeObject *type) +@@ -1225,6 +1234,7 @@ + return 0; + } + if (type->tp_versions_used >= MAX_VERSIONS_PER_CLASS) { ++ /* (this includes `tp_versions_used == _Py_ATTR_CACHE_UNUSED`) */ + return 0; + } + +@@ -2860,7 +2870,7 @@ + */ + + static int +-tail_contains(PyObject *tuple, int whence, PyObject *o) ++tail_contains(PyObject *tuple, Py_ssize_t whence, PyObject *o) + { + Py_ssize_t j, size; + size = PyTuple_GET_SIZE(tuple); +@@ -2923,7 +2933,7 @@ + */ + + static void +-set_mro_error(PyObject **to_merge, Py_ssize_t to_merge_size, int *remain) ++set_mro_error(PyObject **to_merge, Py_ssize_t to_merge_size, Py_ssize_t *remain) + { + Py_ssize_t i, n, off; + char buf[1000]; +@@ -2978,13 +2988,13 @@ + { + int res = 0; + Py_ssize_t i, j, empty_cnt; +- int *remain; ++ Py_ssize_t *remain; + + /* remain stores an index into each sublist of to_merge. + remain[i] is the index of the next base in to_merge[i] + that is not included in acc. + */ +- remain = PyMem_New(int, to_merge_size); ++ remain = PyMem_New(Py_ssize_t, to_merge_size); + if (remain == NULL) { + PyErr_NoMemory(); + return -1; +@@ -5679,6 +5689,31 @@ + return can_cache; + } + ++int ++_PyType_CacheGetItemForSpecialization(PyHeapTypeObject *ht, PyObject *descriptor, uint32_t tp_version) ++{ ++ if (!descriptor || !tp_version) { ++ return 0; ++ } ++ int can_cache; ++ BEGIN_TYPE_LOCK(); ++ can_cache = ((PyTypeObject*)ht)->tp_version_tag == tp_version; ++ // This pointer is invalidated by PyType_Modified (see the comment on ++ // struct _specialization_cache): ++ PyFunctionObject *func = (PyFunctionObject *)descriptor; ++ uint32_t version = _PyFunction_GetVersionForCurrentState(func); ++ can_cache = can_cache && _PyFunction_IsVersionValid(version); ++#ifdef Py_GIL_DISABLED ++ can_cache = can_cache && _PyObject_HasDeferredRefcount(descriptor); ++#endif ++ if (can_cache) { ++ FT_ATOMIC_STORE_PTR_RELEASE(ht->_spec_cache.getitem, descriptor); ++ FT_ATOMIC_STORE_UINT32_RELAXED(ht->_spec_cache.getitem_version, version); ++ } ++ END_TYPE_LOCK(); ++ return can_cache; ++} ++ + static void + set_flags(PyTypeObject *self, unsigned long mask, unsigned long flags) + { +@@ -6125,7 +6160,7 @@ + Py_XDECREF(et->ht_module); + PyMem_Free(et->_ht_tpname); + #ifdef Py_GIL_DISABLED +- assert(et->unique_id == -1); ++ assert(et->unique_id == _Py_INVALID_UNIQUE_ID); + #endif + et->ht_token = NULL; + Py_TYPE(type)->tp_free((PyObject *)type); +@@ -10253,10 +10288,13 @@ + del = lookup_maybe_method(self, &_Py_ID(__del__), &unbound); + if (del != NULL) { + res = call_unbound_noarg(unbound, del, self); +- if (res == NULL) +- PyErr_WriteUnraisable(del); +- else ++ if (res == NULL) { ++ PyErr_FormatUnraisable("Exception ignored while " ++ "calling deallocator %R", del); ++ } ++ else { + Py_DECREF(res); ++ } + Py_DECREF(del); + } + +diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c +index b7aeb06d32b..75967d69ed3 100644 +--- a/Objects/unicodeobject.c ++++ b/Objects/unicodeobject.c +@@ -112,20 +112,42 @@ + # define _PyUnicode_CHECK(op) PyUnicode_Check(op) + #endif + +-#define _PyUnicode_UTF8(op) \ +- (_PyCompactUnicodeObject_CAST(op)->utf8) +-#define PyUnicode_UTF8(op) \ +- (assert(_PyUnicode_CHECK(op)), \ +- PyUnicode_IS_COMPACT_ASCII(op) ? \ +- ((char*)(_PyASCIIObject_CAST(op) + 1)) : \ +- _PyUnicode_UTF8(op)) +-#define _PyUnicode_UTF8_LENGTH(op) \ +- (_PyCompactUnicodeObject_CAST(op)->utf8_length) +-#define PyUnicode_UTF8_LENGTH(op) \ +- (assert(_PyUnicode_CHECK(op)), \ +- PyUnicode_IS_COMPACT_ASCII(op) ? \ +- _PyASCIIObject_CAST(op)->length : \ +- _PyUnicode_UTF8_LENGTH(op)) ++static inline char* _PyUnicode_UTF8(PyObject *op) ++{ ++ return FT_ATOMIC_LOAD_PTR_ACQUIRE(_PyCompactUnicodeObject_CAST(op)->utf8); ++} ++ ++static inline char* PyUnicode_UTF8(PyObject *op) ++{ ++ assert(_PyUnicode_CHECK(op)); ++ if (PyUnicode_IS_COMPACT_ASCII(op)) { ++ return ((char*)(_PyASCIIObject_CAST(op) + 1)); ++ } ++ else { ++ return _PyUnicode_UTF8(op); ++ } ++} ++ ++static inline void PyUnicode_SET_UTF8(PyObject *op, char *utf8) ++{ ++ FT_ATOMIC_STORE_PTR_RELEASE(_PyCompactUnicodeObject_CAST(op)->utf8, utf8); ++} ++ ++static inline Py_ssize_t PyUnicode_UTF8_LENGTH(PyObject *op) ++{ ++ assert(_PyUnicode_CHECK(op)); ++ if (PyUnicode_IS_COMPACT_ASCII(op)) { ++ return _PyASCIIObject_CAST(op)->length; ++ } ++ else { ++ return _PyCompactUnicodeObject_CAST(op)->utf8_length; ++ } ++} ++ ++static inline void PyUnicode_SET_UTF8_LENGTH(PyObject *op, Py_ssize_t length) ++{ ++ _PyCompactUnicodeObject_CAST(op)->utf8_length = length; ++} + + #define _PyUnicode_LENGTH(op) \ + (_PyASCIIObject_CAST(op)->length) +@@ -133,26 +155,37 @@ + (_PyASCIIObject_CAST(op)->state) + #define _PyUnicode_HASH(op) \ + (_PyASCIIObject_CAST(op)->hash) +-#define _PyUnicode_KIND(op) \ +- (assert(_PyUnicode_CHECK(op)), \ +- _PyASCIIObject_CAST(op)->state.kind) +-#define _PyUnicode_GET_LENGTH(op) \ +- (assert(_PyUnicode_CHECK(op)), \ +- _PyASCIIObject_CAST(op)->length) ++ ++static inline Py_hash_t PyUnicode_HASH(PyObject *op) ++{ ++ assert(_PyUnicode_CHECK(op)); ++ return FT_ATOMIC_LOAD_SSIZE_RELAXED(_PyASCIIObject_CAST(op)->hash); ++} ++ ++static inline void PyUnicode_SET_HASH(PyObject *op, Py_hash_t hash) ++{ ++ FT_ATOMIC_STORE_SSIZE_RELAXED(_PyASCIIObject_CAST(op)->hash, hash); ++} ++ + #define _PyUnicode_DATA_ANY(op) \ + (_PyUnicodeObject_CAST(op)->data.any) + +-#define _PyUnicode_SHARE_UTF8(op) \ +- (assert(_PyUnicode_CHECK(op)), \ +- assert(!PyUnicode_IS_COMPACT_ASCII(op)), \ +- (_PyUnicode_UTF8(op) == PyUnicode_DATA(op))) ++static inline int _PyUnicode_SHARE_UTF8(PyObject *op) ++{ ++ assert(_PyUnicode_CHECK(op)); ++ assert(!PyUnicode_IS_COMPACT_ASCII(op)); ++ return (_PyUnicode_UTF8(op) == PyUnicode_DATA(op)); ++} + + /* true if the Unicode object has an allocated UTF-8 memory block + (not shared with other data) */ +-#define _PyUnicode_HAS_UTF8_MEMORY(op) \ +- ((!PyUnicode_IS_COMPACT_ASCII(op) \ +- && _PyUnicode_UTF8(op) \ +- && _PyUnicode_UTF8(op) != PyUnicode_DATA(op))) ++static inline int _PyUnicode_HAS_UTF8_MEMORY(PyObject *op) ++{ ++ return (!PyUnicode_IS_COMPACT_ASCII(op) ++ && _PyUnicode_UTF8(op) != NULL ++ && _PyUnicode_UTF8(op) != PyUnicode_DATA(op)); ++} ++ + + /* Generic helper macro to convert characters of different types. + from_type and to_type have to be valid type names, begin and end +@@ -655,7 +688,7 @@ + || kind == PyUnicode_2BYTE_KIND + || kind == PyUnicode_4BYTE_KIND); + CHECK(ascii->state.ascii == 0); +- CHECK(compact->utf8 != data); ++ CHECK(_PyUnicode_UTF8(op) != data); + } + else { + PyUnicodeObject *unicode = _PyUnicodeObject_CAST(op); +@@ -667,16 +700,17 @@ + CHECK(ascii->state.compact == 0); + CHECK(data != NULL); + if (ascii->state.ascii) { +- CHECK(compact->utf8 == data); ++ CHECK(_PyUnicode_UTF8(op) == data); + CHECK(compact->utf8_length == ascii->length); + } + else { +- CHECK(compact->utf8 != data); ++ CHECK(_PyUnicode_UTF8(op) != data); + } + } +- +- if (compact->utf8 == NULL) ++#ifndef Py_GIL_DISABLED ++ if (_PyUnicode_UTF8(op) == NULL) + CHECK(compact->utf8_length == 0); ++#endif + } + + /* check that the best kind is used: O(n) operation */ +@@ -1123,8 +1157,8 @@ + + if (_PyUnicode_HAS_UTF8_MEMORY(unicode)) { + PyMem_Free(_PyUnicode_UTF8(unicode)); +- _PyUnicode_UTF8(unicode) = NULL; +- _PyUnicode_UTF8_LENGTH(unicode) = 0; ++ PyUnicode_SET_UTF8_LENGTH(unicode, 0); ++ PyUnicode_SET_UTF8(unicode, NULL); + } + #ifdef Py_TRACE_REFS + _Py_ForgetReference(unicode); +@@ -1177,8 +1211,8 @@ + if (!share_utf8 && _PyUnicode_HAS_UTF8_MEMORY(unicode)) + { + PyMem_Free(_PyUnicode_UTF8(unicode)); +- _PyUnicode_UTF8(unicode) = NULL; +- _PyUnicode_UTF8_LENGTH(unicode) = 0; ++ PyUnicode_SET_UTF8_LENGTH(unicode, 0); ++ PyUnicode_SET_UTF8(unicode, NULL); + } + + data = (PyObject *)PyObject_Realloc(data, new_size); +@@ -1188,8 +1222,8 @@ + } + _PyUnicode_DATA_ANY(unicode) = data; + if (share_utf8) { +- _PyUnicode_UTF8(unicode) = data; +- _PyUnicode_UTF8_LENGTH(unicode) = length; ++ PyUnicode_SET_UTF8_LENGTH(unicode, length); ++ PyUnicode_SET_UTF8(unicode, data); + } + _PyUnicode_LENGTH(unicode) = length; + PyUnicode_WRITE(PyUnicode_KIND(unicode), data, length, 0); +@@ -1429,11 +1463,14 @@ + assert(PyUnicode_Check(from)); + assert(from_start + how_many <= PyUnicode_GET_LENGTH(from)); + +- assert(PyUnicode_Check(to)); +- assert(to_start + how_many <= PyUnicode_GET_LENGTH(to)); ++ assert(to == NULL || PyUnicode_Check(to)); + +- if (how_many == 0) ++ if (how_many == 0) { + return 0; ++ } ++ ++ assert(to != NULL); ++ assert(to_start + how_many <= PyUnicode_GET_LENGTH(to)); + + from_kind = PyUnicode_KIND(from); + from_data = PyUnicode_DATA(from); +@@ -1698,7 +1735,9 @@ + PyObject *popped; + int r = PyDict_Pop(interned, unicode, &popped); + if (r == -1) { +- PyErr_WriteUnraisable(unicode); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "removing an interned string %R", ++ unicode); + // We don't know what happened to the string. It's probably + // best to leak it: + // - if it was popped, there are no more references to it +@@ -1769,7 +1808,7 @@ + assert(_PyUnicode_CHECK(unicode)); + if (Py_REFCNT(unicode) != 1) + return 0; +- if (FT_ATOMIC_LOAD_SSIZE_RELAXED(_PyUnicode_HASH(unicode)) != -1) ++ if (PyUnicode_HASH(unicode) != -1) + return 0; + if (PyUnicode_CHECK_INTERNED(unicode)) + return 0; +@@ -4183,6 +4222,21 @@ + + static int unicode_fill_utf8(PyObject *unicode); + ++ ++static int ++unicode_ensure_utf8(PyObject *unicode) ++{ ++ int err = 0; ++ if (PyUnicode_UTF8(unicode) == NULL) { ++ Py_BEGIN_CRITICAL_SECTION(unicode); ++ if (PyUnicode_UTF8(unicode) == NULL) { ++ err = unicode_fill_utf8(unicode); ++ } ++ Py_END_CRITICAL_SECTION(); ++ } ++ return err; ++} ++ + const char * + PyUnicode_AsUTF8AndSize(PyObject *unicode, Py_ssize_t *psize) + { +@@ -4194,13 +4248,11 @@ + return NULL; + } + +- if (PyUnicode_UTF8(unicode) == NULL) { +- if (unicode_fill_utf8(unicode) == -1) { +- if (psize) { +- *psize = -1; +- } +- return NULL; ++ if (unicode_ensure_utf8(unicode) == -1) { ++ if (psize) { ++ *psize = -1; + } ++ return NULL; + } + + if (psize) { +@@ -5821,6 +5873,7 @@ + static int + unicode_fill_utf8(PyObject *unicode) + { ++ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(unicode); + /* the string cannot be ASCII, or PyUnicode_UTF8() would be set */ + assert(!PyUnicode_IS_ASCII(unicode)); + +@@ -5862,10 +5915,10 @@ + PyErr_NoMemory(); + return -1; + } +- _PyUnicode_UTF8(unicode) = cache; +- _PyUnicode_UTF8_LENGTH(unicode) = len; + memcpy(cache, start, len); + cache[len] = '\0'; ++ PyUnicode_SET_UTF8_LENGTH(unicode, len); ++ PyUnicode_SET_UTF8(unicode, cache); + _PyBytesWriter_Dealloc(&writer); + return 0; + } +@@ -6802,7 +6855,8 @@ + unsigned char c = *first_invalid_escape; + if ('4' <= c && c <= '7') { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, +- "invalid octal escape sequence '\\%.3s'", ++ "\"\\%.3s\" is an invalid octal escape sequence. " ++ "Such sequences will not work in the future. ", + first_invalid_escape) < 0) + { + Py_DECREF(result); +@@ -6811,7 +6865,8 @@ + } + else { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, +- "invalid escape sequence '\\%c'", ++ "\"\\%c\" is an invalid escape sequence. " ++ "Such sequences will not work in the future. ", + c) < 0) + { + Py_DECREF(result); +@@ -11434,9 +11489,9 @@ + return 0; + } + +- Py_hash_t right_hash = FT_ATOMIC_LOAD_SSIZE_RELAXED(_PyUnicode_HASH(right_uni)); ++ Py_hash_t right_hash = PyUnicode_HASH(right_uni); + assert(right_hash != -1); +- Py_hash_t hash = FT_ATOMIC_LOAD_SSIZE_RELAXED(_PyUnicode_HASH(left)); ++ Py_hash_t hash = PyUnicode_HASH(left); + if (hash != -1 && hash != right_hash) { + return 0; + } +@@ -11916,14 +11971,14 @@ + #ifdef Py_DEBUG + assert(_Py_HashSecret_Initialized); + #endif +- Py_hash_t hash = FT_ATOMIC_LOAD_SSIZE_RELAXED(_PyUnicode_HASH(self)); ++ Py_hash_t hash = PyUnicode_HASH(self); + if (hash != -1) { + return hash; + } + x = Py_HashBuffer(PyUnicode_DATA(self), + PyUnicode_GET_LENGTH(self) * PyUnicode_KIND(self)); + +- FT_ATOMIC_STORE_SSIZE_RELAXED(_PyUnicode_HASH(self), x); ++ PyUnicode_SET_HASH(self, x); + return x; + } + +@@ -15427,8 +15482,8 @@ + _PyUnicode_STATE(self).compact = 0; + _PyUnicode_STATE(self).ascii = _PyUnicode_STATE(unicode).ascii; + _PyUnicode_STATE(self).statically_allocated = 0; +- _PyUnicode_UTF8_LENGTH(self) = 0; +- _PyUnicode_UTF8(self) = NULL; ++ PyUnicode_SET_UTF8_LENGTH(self, 0); ++ PyUnicode_SET_UTF8(self, NULL); + _PyUnicode_DATA_ANY(self) = NULL; + + share_utf8 = 0; +@@ -15458,8 +15513,8 @@ + + _PyUnicode_DATA_ANY(self) = data; + if (share_utf8) { +- _PyUnicode_UTF8_LENGTH(self) = length; +- _PyUnicode_UTF8(self) = data; ++ PyUnicode_SET_UTF8_LENGTH(self, length); ++ PyUnicode_SET_UTF8(self, data); + } + + memcpy(data, PyUnicode_DATA(unicode), kind * (length + 1)); +@@ -15678,7 +15733,7 @@ + _Py_DecRefTotal(_PyThreadState_GET()); + } + #endif +- _PyUnicode_STATE(s).interned = SSTATE_INTERNED_IMMORTAL; ++ FT_ATOMIC_STORE_UINT16_RELAXED(_PyUnicode_STATE(s).interned, SSTATE_INTERNED_IMMORTAL); + _Py_SetImmortal(s); + } + +@@ -15797,7 +15852,7 @@ + _Py_DecRefTotal(_PyThreadState_GET()); + #endif + } +- _PyUnicode_STATE(s).interned = SSTATE_INTERNED_MORTAL; ++ FT_ATOMIC_STORE_UINT16_RELAXED(_PyUnicode_STATE(s).interned, SSTATE_INTERNED_MORTAL); + + /* INTERNED_MORTAL -> INTERNED_IMMORTAL (if needed) */ + +@@ -15933,7 +15988,7 @@ + Py_UNREACHABLE(); + } + if (!shared) { +- _PyUnicode_STATE(s).interned = SSTATE_NOT_INTERNED; ++ FT_ATOMIC_STORE_UINT16_RELAXED(_PyUnicode_STATE(s).interned, SSTATE_NOT_INTERNED); + } + } + #ifdef INTERNED_STATS +@@ -16433,3 +16488,24 @@ + { + return PyModuleDef_Init(&_string_module); + } ++ ++ ++#undef PyUnicode_KIND ++int PyUnicode_KIND(PyObject *op) ++{ ++ if (!PyUnicode_Check(op)) { ++ PyErr_Format(PyExc_TypeError, "expect str, got %T", op); ++ return -1; ++ } ++ return _PyASCIIObject_CAST(op)->state.kind; ++} ++ ++#undef PyUnicode_DATA ++void* PyUnicode_DATA(PyObject *op) ++{ ++ if (!PyUnicode_Check(op)) { ++ PyErr_Format(PyExc_TypeError, "expect str, got %T", op); ++ return NULL; ++ } ++ return _PyUnicode_DATA(op); ++} +diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c +index 9e3da1c3394..bd4c4ac9b34 100644 +--- a/Objects/weakrefobject.c ++++ b/Objects/weakrefobject.c +@@ -932,6 +932,19 @@ + return (PyObject *)get_or_create_weakref(type, ob, callback); + } + ++int ++PyWeakref_IsDead(PyObject *ref) ++{ ++ if (ref == NULL) { ++ PyErr_BadInternalCall(); ++ return -1; ++ } ++ if (!PyWeakref_Check(ref)) { ++ PyErr_Format(PyExc_TypeError, "expected a weakref, got %T", ref); ++ return -1; ++ } ++ return _PyWeakref_IS_DEAD(ref); ++} + + int + PyWeakref_GetRef(PyObject *ref, PyObject **pobj) +@@ -974,10 +987,13 @@ + { + PyObject *cbresult = PyObject_CallOneArg(callback, (PyObject *)ref); + +- if (cbresult == NULL) +- PyErr_WriteUnraisable(callback); +- else ++ if (cbresult == NULL) { ++ PyErr_FormatUnraisable("Exception ignored while " ++ "calling weakref callback %R", callback); ++ } ++ else { + Py_DECREF(cbresult); ++ } + } + + /* This function is called by the tp_dealloc handler to clear weak references. +@@ -1029,7 +1045,8 @@ + PyObject *tuple = PyTuple_New(num_weakrefs * 2); + if (tuple == NULL) { + _PyWeakref_ClearWeakRefsNoCallbacks(object); +- PyErr_WriteUnraisable(NULL); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "clearing object weakrefs"); + PyErr_SetRaisedException(exc); + return; + } +diff --git a/PC/clinic/winreg.c.h b/PC/clinic/winreg.c.h +index b14913366b7..00fa6a75ec1 100644 +--- a/PC/clinic/winreg.c.h ++++ b/PC/clinic/winreg.c.h +@@ -26,9 +26,9 @@ + winreg_HKEYType_Close_impl(PyHKEYObject *self); + + static PyObject * +-winreg_HKEYType_Close(PyHKEYObject *self, PyObject *Py_UNUSED(ignored)) ++winreg_HKEYType_Close(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return winreg_HKEYType_Close_impl(self); ++ return winreg_HKEYType_Close_impl((PyHKEYObject *)self); + } + + #endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) */ +@@ -56,9 +56,9 @@ + winreg_HKEYType_Detach_impl(PyHKEYObject *self); + + static PyObject * +-winreg_HKEYType_Detach(PyHKEYObject *self, PyObject *Py_UNUSED(ignored)) ++winreg_HKEYType_Detach(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return winreg_HKEYType_Detach_impl(self); ++ return winreg_HKEYType_Detach_impl((PyHKEYObject *)self); + } + + #endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) */ +@@ -77,12 +77,12 @@ + winreg_HKEYType___enter___impl(PyHKEYObject *self); + + static PyObject * +-winreg_HKEYType___enter__(PyHKEYObject *self, PyObject *Py_UNUSED(ignored)) ++winreg_HKEYType___enter__(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + PyHKEYObject *_return_value; + +- _return_value = winreg_HKEYType___enter___impl(self); ++ _return_value = winreg_HKEYType___enter___impl((PyHKEYObject *)self); + return_value = (PyObject *)_return_value; + + return return_value; +@@ -105,7 +105,7 @@ + PyObject *exc_value, PyObject *traceback); + + static PyObject * +-winreg_HKEYType___exit__(PyHKEYObject *self, PyObject *const *args, Py_ssize_t nargs) ++winreg_HKEYType___exit__(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *exc_type; +@@ -118,7 +118,7 @@ + exc_type = args[0]; + exc_value = args[1]; + traceback = args[2]; +- return_value = winreg_HKEYType___exit___impl(self, exc_type, exc_value, traceback); ++ return_value = winreg_HKEYType___exit___impl((PyHKEYObject *)self, exc_type, exc_value, traceback); + + exit: + return return_value; +@@ -1766,4 +1766,4 @@ + #ifndef WINREG_QUERYREFLECTIONKEY_METHODDEF + #define WINREG_QUERYREFLECTIONKEY_METHODDEF + #endif /* !defined(WINREG_QUERYREFLECTIONKEY_METHODDEF) */ +-/*[clinic end generated code: output=aef4aa8ab8ddf38f input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=fbe9b075cd2fa833 input=a9049054013a1b77]*/ +diff --git a/PC/pyconfig.h.in b/PC/pyconfig.h.in +index 010f5fe5646..f4f57c5d270 100644 +--- a/PC/pyconfig.h.in ++++ b/PC/pyconfig.h.in +@@ -753,4 +753,7 @@ + /* Define if libssl has X509_VERIFY_PARAM_set1_host and related function */ + #define HAVE_X509_VERIFY_PARAM_SET1_HOST 1 + ++// Truncate the thread name to 32766 characters. ++#define _PYTHREAD_NAME_MAXLEN 32766 ++ + #endif /* !Py_CONFIG_H */ +diff --git a/PC/python.manifest b/PC/python.manifest +index 8e1bc022adf..19c9fc1b80a 100644 +--- a/PC/python.manifest ++++ b/PC/python.manifest +@@ -9,10 +9,15 @@ + + + ++ + ++ + ++ + ++ + ++ + + + +diff --git a/PC/python3dll.c b/PC/python3dll.c +index 8657ddb9fa5..84b3c735240 100755 +--- a/PC/python3dll.c ++++ b/PC/python3dll.c +@@ -81,6 +81,8 @@ + EXPORT_FUNC(Py_MakePendingCalls) + EXPORT_FUNC(Py_NewInterpreter) + EXPORT_FUNC(Py_NewRef) ++EXPORT_FUNC(Py_PACK_FULL_VERSION) ++EXPORT_FUNC(Py_PACK_VERSION) + EXPORT_FUNC(Py_REFCNT) + EXPORT_FUNC(Py_ReprEnter) + EXPORT_FUNC(Py_ReprLeave) +diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c +index 5ac1dd78136..2fe8d11badc 100644 +--- a/Parser/action_helpers.c ++++ b/Parser/action_helpers.c +@@ -969,8 +969,6 @@ + return result_token_with_metadata(p, conv, conv_token->metadata); + } + +-static asdl_expr_seq * +-unpack_top_level_joined_strs(Parser *p, asdl_expr_seq *raw_expressions); + ResultTokenWithMetadata * + _PyPegen_setup_full_format_spec(Parser *p, Token *colon, asdl_expr_seq *spec, int lineno, int col_offset, + int end_lineno, int end_col_offset, PyArena *arena) +@@ -1279,9 +1277,9 @@ + p->arena); + } + +-static asdl_expr_seq * +-unpack_top_level_joined_strs(Parser *p, asdl_expr_seq *raw_expressions) +-{ ++expr_ty ++_PyPegen_joined_str(Parser *p, Token* a, asdl_expr_seq* expr, Token*b) { ++ + /* The parser might put multiple f-string values into an individual + * JoinedStr node at the top level due to stuff like f-string debugging + * expressions. This function flattens those and promotes them to the +@@ -1289,44 +1287,14 @@ + * of the regular output, so this is not necessary if you are not going + * to expose the output AST to Python level. */ + +- Py_ssize_t i, req_size, raw_size; +- +- req_size = raw_size = asdl_seq_LEN(raw_expressions); +- expr_ty expr; +- for (i = 0; i < raw_size; i++) { +- expr = asdl_seq_GET(raw_expressions, i); +- if (expr->kind == JoinedStr_kind) { +- req_size += asdl_seq_LEN(expr->v.JoinedStr.values) - 1; +- } +- } +- +- asdl_expr_seq *expressions = _Py_asdl_expr_seq_new(req_size, p->arena); +- if (expressions == NULL) { +- return NULL; +- } +- +- Py_ssize_t raw_index, req_index = 0; +- for (raw_index = 0; raw_index < raw_size; raw_index++) { +- expr = asdl_seq_GET(raw_expressions, raw_index); +- if (expr->kind == JoinedStr_kind) { +- asdl_expr_seq *values = expr->v.JoinedStr.values; +- for (Py_ssize_t n = 0; n < asdl_seq_LEN(values); n++) { +- asdl_seq_SET(expressions, req_index, asdl_seq_GET(values, n)); +- req_index++; +- } +- } else { +- asdl_seq_SET(expressions, req_index, expr); +- req_index++; ++ Py_ssize_t n_items = asdl_seq_LEN(expr); ++ Py_ssize_t total_items = n_items; ++ for (Py_ssize_t i = 0; i < n_items; i++) { ++ expr_ty item = asdl_seq_GET(expr, i); ++ if (item->kind == JoinedStr_kind) { ++ total_items += asdl_seq_LEN(item->v.JoinedStr.values) - 1; + } + } +- return expressions; +-} +- +-expr_ty +-_PyPegen_joined_str(Parser *p, Token* a, asdl_expr_seq* raw_expressions, Token*b) { +- +- asdl_expr_seq *expr = unpack_top_level_joined_strs(p, raw_expressions); +- Py_ssize_t n_items = asdl_seq_LEN(expr); + + const char* quote_str = PyBytes_AsString(a->bytes); + if (quote_str == NULL) { +@@ -1334,7 +1302,7 @@ + } + int is_raw = strpbrk(quote_str, "rR") != NULL; + +- asdl_expr_seq *seq = _Py_asdl_expr_seq_new(n_items, p->arena); ++ asdl_expr_seq *seq = _Py_asdl_expr_seq_new(total_items, p->arena); + if (seq == NULL) { + return NULL; + } +@@ -1342,6 +1310,31 @@ + Py_ssize_t index = 0; + for (Py_ssize_t i = 0; i < n_items; i++) { + expr_ty item = asdl_seq_GET(expr, i); ++ ++ // This should correspond to a JoinedStr node of two elements ++ // created _PyPegen_formatted_value. This situation can only be the result of ++ // a f-string debug expression where the first element is a constant with the text and the second ++ // a formatted value with the expression. ++ if (item->kind == JoinedStr_kind) { ++ asdl_expr_seq *values = item->v.JoinedStr.values; ++ if (asdl_seq_LEN(values) != 2) { ++ PyErr_Format(PyExc_SystemError, ++ "unexpected JoinedStr node without debug data in f-string at line %d", ++ item->lineno); ++ return NULL; ++ } ++ ++ expr_ty first = asdl_seq_GET(values, 0); ++ assert(first->kind == Constant_kind); ++ asdl_seq_SET(seq, index++, first); ++ ++ expr_ty second = asdl_seq_GET(values, 1); ++ assert(second->kind == FormattedValue_kind); ++ asdl_seq_SET(seq, index++, second); ++ ++ continue; ++ } ++ + if (item->kind == Constant_kind) { + item = _PyPegen_decode_fstring_part(p, is_raw, item, b); + if (item == NULL) { +@@ -1360,7 +1353,7 @@ + } + + asdl_expr_seq *resized_exprs; +- if (index != n_items) { ++ if (index != total_items) { + resized_exprs = _Py_asdl_expr_seq_new(index, p->arena); + if (resized_exprs == NULL) { + return NULL; +diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py +index 853a3e99807..7b2df738119 100755 +--- a/Parser/asdl_c.py ++++ b/Parser/asdl_c.py +@@ -1462,10 +1462,11 @@ + return PyObject_Repr(list); + } + +- _PyUnicodeWriter writer; +- _PyUnicodeWriter_Init(&writer); +- writer.overallocate = 1; + PyObject *items[2] = {NULL, NULL}; ++ PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); ++ if (writer == NULL) { ++ goto error; ++ } + + items[0] = PySequence_GetItem(list, 0); + if (!items[0]) { +@@ -1479,52 +1480,54 @@ + } + + bool is_list = PyList_Check(list); +- if (_PyUnicodeWriter_WriteChar(&writer, is_list ? '[' : '(') < 0) { ++ if (PyUnicodeWriter_WriteChar(writer, is_list ? '[' : '(') < 0) { + goto error; + } + + for (Py_ssize_t i = 0; i < Py_MIN(length, 2); i++) { +- PyObject *item = items[i]; +- PyObject *item_repr; ++ if (i > 0) { ++ if (PyUnicodeWriter_WriteUTF8(writer, ", ", 2) < 0) { ++ goto error; ++ } ++ } + ++ PyObject *item = items[i]; + if (PyType_IsSubtype(Py_TYPE(item), (PyTypeObject *)state->AST_type)) { ++ PyObject *item_repr; + item_repr = ast_repr_max_depth((AST_object*)item, depth - 1); +- } else { +- item_repr = PyObject_Repr(item); +- } +- if (!item_repr) { +- goto error; +- } +- if (i > 0) { +- if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) { ++ if (!item_repr) { ++ goto error; ++ } ++ if (PyUnicodeWriter_WriteStr(writer, item_repr) < 0) { ++ Py_DECREF(item_repr); + goto error; + } +- } +- if (_PyUnicodeWriter_WriteStr(&writer, item_repr) < 0) { + Py_DECREF(item_repr); +- goto error; ++ } else { ++ if (PyUnicodeWriter_WriteRepr(writer, item) < 0) { ++ goto error; ++ } + } ++ + if (i == 0 && length > 2) { +- if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ...", 5) < 0) { +- Py_DECREF(item_repr); ++ if (PyUnicodeWriter_WriteUTF8(writer, ", ...", 5) < 0) { + goto error; + } + } +- Py_DECREF(item_repr); + } + +- if (_PyUnicodeWriter_WriteChar(&writer, is_list ? ']' : ')') < 0) { ++ if (PyUnicodeWriter_WriteChar(writer, is_list ? ']' : ')') < 0) { + goto error; + } + + Py_XDECREF(items[0]); + Py_XDECREF(items[1]); +- return _PyUnicodeWriter_Finish(&writer); ++ return PyUnicodeWriter_Finish(writer); + + error: + Py_XDECREF(items[0]); + Py_XDECREF(items[1]); +- _PyUnicodeWriter_Dealloc(&writer); ++ PyUnicodeWriter_Discard(writer); + return NULL; + } + +@@ -1568,14 +1571,15 @@ + } + + const char* tp_name = Py_TYPE(self)->tp_name; +- _PyUnicodeWriter writer; +- _PyUnicodeWriter_Init(&writer); +- writer.overallocate = 1; ++ PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); ++ if (writer == NULL) { ++ goto error; ++ } + +- if (_PyUnicodeWriter_WriteASCIIString(&writer, tp_name, strlen(tp_name)) < 0) { ++ if (PyUnicodeWriter_WriteUTF8(writer, tp_name, -1) < 0) { + goto error; + } +- if (_PyUnicodeWriter_WriteChar(&writer, '(') < 0) { ++ if (PyUnicodeWriter_WriteChar(writer, '(') < 0) { + goto error; + } + +@@ -1610,13 +1614,13 @@ + } + + if (i > 0) { +- if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) { ++ if (PyUnicodeWriter_WriteUTF8(writer, ", ", 2) < 0) { + Py_DECREF(name); + Py_DECREF(value_repr); + goto error; + } + } +- if (_PyUnicodeWriter_WriteStr(&writer, name) < 0) { ++ if (PyUnicodeWriter_WriteStr(writer, name) < 0) { + Py_DECREF(name); + Py_DECREF(value_repr); + goto error; +@@ -1624,11 +1628,11 @@ + + Py_DECREF(name); + +- if (_PyUnicodeWriter_WriteChar(&writer, '=') < 0) { ++ if (PyUnicodeWriter_WriteChar(writer, '=') < 0) { + Py_DECREF(value_repr); + goto error; + } +- if (_PyUnicodeWriter_WriteStr(&writer, value_repr) < 0) { ++ if (PyUnicodeWriter_WriteStr(writer, value_repr) < 0) { + Py_DECREF(value_repr); + goto error; + } +@@ -1636,17 +1640,17 @@ + Py_DECREF(value_repr); + } + +- if (_PyUnicodeWriter_WriteChar(&writer, ')') < 0) { ++ if (PyUnicodeWriter_WriteChar(writer, ')') < 0) { + goto error; + } + Py_ReprLeave((PyObject *)self); + Py_DECREF(fields); +- return _PyUnicodeWriter_Finish(&writer); ++ return PyUnicodeWriter_Finish(writer); + + error: + Py_ReprLeave((PyObject *)self); + Py_DECREF(fields); +- _PyUnicodeWriter_Dealloc(&writer); ++ PyUnicodeWriter_Discard(writer); + return NULL; + } + +diff --git a/Parser/lexer/lexer.c b/Parser/lexer/lexer.c +index 8c868593f94..8c5ae37fa90 100644 +--- a/Parser/lexer/lexer.c ++++ b/Parser/lexer/lexer.c +@@ -212,9 +212,7 @@ + case '}': + case '!': + case ':': +- if (tok_mode->last_expr_end == -1) { +- tok_mode->last_expr_end = strlen(tok->start); +- } ++ tok_mode->last_expr_end = strlen(tok->start); + break; + default: + Py_UNREACHABLE(); +@@ -329,11 +327,7 @@ + return 0; + } + Py_ssize_t invalid = _PyUnicode_ScanIdentifier(s); +- if (invalid < 0) { +- Py_DECREF(s); +- tok->done = E_ERROR; +- return 0; +- } ++ assert(invalid >= 0); + assert(PyUnicode_GET_LENGTH(s) > 0); + if (invalid < PyUnicode_GET_LENGTH(s)) { + Py_UCS4 ch = PyUnicode_READ_CHAR(s, invalid); +diff --git a/Parser/pegen.c b/Parser/pegen.c +index bb98e7b184a..83b0022e47d 100644 +--- a/Parser/pegen.c ++++ b/Parser/pegen.c +@@ -111,7 +111,7 @@ + if (p->normalize) { + return 1; + } +- p->normalize = _PyImport_GetModuleAttrString("unicodedata", "normalize"); ++ p->normalize = PyImport_ImportModuleAttrString("unicodedata", "normalize"); + if (!p->normalize) + { + return 0; +diff --git a/Parser/string_parser.c b/Parser/string_parser.c +index 9537c543b0e..9dd8f9ef28b 100644 +--- a/Parser/string_parser.c ++++ b/Parser/string_parser.c +@@ -28,9 +28,16 @@ + int octal = ('4' <= c && c <= '7'); + PyObject *msg = + octal +- ? PyUnicode_FromFormat("invalid octal escape sequence '\\%.3s'", +- first_invalid_escape) +- : PyUnicode_FromFormat("invalid escape sequence '\\%c'", c); ++ ? PyUnicode_FromFormat( ++ "\"\\%.3s\" is an invalid octal escape sequence. " ++ "Such sequences will not work in the future. " ++ "Did you mean \"\\\\%.3s\"? A raw string is also an option.", ++ first_invalid_escape, first_invalid_escape) ++ : PyUnicode_FromFormat( ++ "\"\\%c\" is an invalid escape sequence. " ++ "Such sequences will not work in the future. " ++ "Did you mean \"\\\\%c\"? A raw string is also an option.", ++ c, c); + if (msg == NULL) { + return -1; + } +@@ -53,11 +60,16 @@ + error location, if p->known_err_token is not set. */ + p->known_err_token = t; + if (octal) { +- RAISE_SYNTAX_ERROR("invalid octal escape sequence '\\%.3s'", +- first_invalid_escape); ++ RAISE_SYNTAX_ERROR( ++ "\"\\%.3s\" is an invalid octal escape sequence. " ++ "Did you mean \"\\\\%.3s\"? A raw string is also an option.", ++ first_invalid_escape, first_invalid_escape); + } + else { +- RAISE_SYNTAX_ERROR("invalid escape sequence '\\%c'", c); ++ RAISE_SYNTAX_ERROR( ++ "\"\\%c\" is an invalid escape sequence. " ++ "Did you mean \"\\\\%c\"? A raw string is also an option.", ++ c, c); + } + } + Py_DECREF(msg); +diff --git a/Parser/tokenizer/file_tokenizer.c b/Parser/tokenizer/file_tokenizer.c +index 2750527da48..efe9fb9b56a 100644 +--- a/Parser/tokenizer/file_tokenizer.c ++++ b/Parser/tokenizer/file_tokenizer.c +@@ -158,7 +158,7 @@ + return 0; + } + +- open = _PyImport_GetModuleAttrString("io", "open"); ++ open = PyImport_ImportModuleAttrString("io", "open"); + if (open == NULL) { + return 0; + } +diff --git a/Parser/tokenizer/helpers.c b/Parser/tokenizer/helpers.c +index 9c9d05bbef0..5a416adb875 100644 +--- a/Parser/tokenizer/helpers.c ++++ b/Parser/tokenizer/helpers.c +@@ -113,7 +113,10 @@ + } + + PyObject *msg = PyUnicode_FromFormat( +- "invalid escape sequence '\\%c'", ++ "\"\\%c\" is an invalid escape sequence. " ++ "Such sequences will not work in the future. " ++ "Did you mean \"\\\\%c\"? A raw string is also an option.", ++ (char) first_invalid_escape_char, + (char) first_invalid_escape_char + ); + +@@ -129,7 +132,12 @@ + /* Replace the SyntaxWarning exception with a SyntaxError + to get a more accurate error report */ + PyErr_Clear(); +- return _PyTokenizer_syntaxerror(tok, "invalid escape sequence '\\%c'", (char) first_invalid_escape_char); ++ ++ return _PyTokenizer_syntaxerror(tok, ++ "\"\\%c\" is an invalid escape sequence. " ++ "Did you mean \"\\\\%c\"? A raw string is also an option.", ++ (char) first_invalid_escape_char, ++ (char) first_invalid_escape_char); + } + + return -1; +diff --git a/Programs/_testembed.c b/Programs/_testembed.c +index d15dd519dbf..6f6d0cae580 100644 +--- a/Programs/_testembed.c ++++ b/Programs/_testembed.c +@@ -1791,55 +1791,6 @@ + } + + +-static int tune_config(void) +-{ +- PyConfig config; +- PyConfig_InitPythonConfig(&config); +- if (_PyInterpreterState_GetConfigCopy(&config) < 0) { +- PyConfig_Clear(&config); +- PyErr_Print(); +- return -1; +- } +- +- config.bytes_warning = 2; +- +- if (_PyInterpreterState_SetConfig(&config) < 0) { +- PyConfig_Clear(&config); +- return -1; +- } +- PyConfig_Clear(&config); +- return 0; +-} +- +- +-static int test_init_set_config(void) +-{ +- // Initialize core +- PyConfig config; +- PyConfig_InitIsolatedConfig(&config); +- config_set_string(&config, &config.program_name, PROGRAM_NAME); +- config._init_main = 0; +- config.bytes_warning = 0; +- init_from_config_clear(&config); +- +- // Tune the configuration using _PyInterpreterState_SetConfig() +- if (tune_config() < 0) { +- PyErr_Print(); +- return 1; +- } +- +- // Finish initialization: main part +- PyStatus status = _Py_InitializeMain(); +- if (PyStatus_Exception(status)) { +- Py_ExitStatusException(status); +- } +- +- dump_config(); +- Py_Finalize(); +- return 0; +-} +- +- + static int initconfig_getint(PyInitConfig *config, const char *name) + { + int64_t value; +@@ -2089,33 +2040,6 @@ + } + + +-static int test_init_main(void) +-{ +- PyConfig config; +- PyConfig_InitPythonConfig(&config); +- +- configure_init_main(&config); +- config._init_main = 0; +- init_from_config_clear(&config); +- +- /* sys.stdout don't exist yet: it is created by _Py_InitializeMain() */ +- int res = PyRun_SimpleString( +- "import sys; " +- "print('Run Python code before _Py_InitializeMain', " +- "file=sys.stderr)"); +- if (res < 0) { +- exit(1); +- } +- +- PyStatus status = _Py_InitializeMain(); +- if (PyStatus_Exception(status)) { +- Py_ExitStatusException(status); +- } +- +- return Py_RunMain(); +-} +- +- + static int test_run_main(void) + { + PyConfig config; +@@ -2473,14 +2397,12 @@ + {"test_preinit_dont_parse_argv", test_preinit_dont_parse_argv}, + {"test_init_read_set", test_init_read_set}, + {"test_init_run_main", test_init_run_main}, +- {"test_init_main", test_init_main}, + {"test_init_sys_add", test_init_sys_add}, + {"test_init_setpath", test_init_setpath}, + {"test_init_setpath_config", test_init_setpath_config}, + {"test_init_setpythonhome", test_init_setpythonhome}, + {"test_init_is_python_build", test_init_is_python_build}, + {"test_init_warnoptions", test_init_warnoptions}, +- {"test_init_set_config", test_init_set_config}, + {"test_initconfig_api", test_initconfig_api}, + {"test_initconfig_get_api", test_initconfig_get_api}, + {"test_initconfig_exit", test_initconfig_exit}, +diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h +index c936622c020..0fe8d3d3f7d 100644 +--- a/Programs/test_frozenmain.h ++++ b/Programs/test_frozenmain.h +@@ -1,18 +1,19 @@ + // Auto-generated by Programs/freeze_test_frozenmain.py + unsigned char M_test_frozenmain[] = { +- 227,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +- 0,0,0,0,0,243,168,0,0,0,149,0,89,0,79,0, +- 70,0,111,0,89,0,79,0,70,1,111,1,88,2,31,0, +- 79,1,49,1,0,0,0,0,0,0,29,0,88,2,31,0, +- 79,2,88,0,77,6,0,0,0,0,0,0,0,0,0,0, +- 0,0,0,0,0,0,0,0,49,2,0,0,0,0,0,0, +- 29,0,88,1,77,8,0,0,0,0,0,0,0,0,0,0, +- 0,0,0,0,0,0,0,0,31,0,49,0,0,0,0,0, +- 0,0,79,3,2,0,0,0,111,5,79,4,16,0,67,20, +- 0,0,111,6,88,2,31,0,79,5,88,6,12,0,79,6, +- 88,5,88,6,2,0,0,0,12,0,47,4,49,1,0,0, +- 0,0,0,0,29,0,72,22,0,0,9,0,29,0,79,0, +- 33,0,41,7,78,122,18,70,114,111,122,101,110,32,72,101, ++ 227,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0, ++ 0,0,0,0,0,243,184,0,0,0,149,0,90,0,80,0, ++ 71,0,112,0,90,0,80,0,71,1,112,1,89,2,33,0, ++ 80,1,51,1,0,0,0,0,0,0,31,0,89,2,33,0, ++ 80,2,89,0,78,6,0,0,0,0,0,0,0,0,0,0, ++ 0,0,0,0,0,0,0,0,51,2,0,0,0,0,0,0, ++ 31,0,89,1,78,8,0,0,0,0,0,0,0,0,0,0, ++ 0,0,0,0,0,0,0,0,33,0,51,0,0,0,0,0, ++ 0,0,80,3,44,26,0,0,0,0,0,0,0,0,0,0, ++ 112,5,80,4,16,0,68,24,0,0,112,6,89,2,33,0, ++ 80,5,89,6,12,0,80,6,89,5,89,6,44,26,0,0, ++ 0,0,0,0,0,0,0,0,12,0,49,4,51,1,0,0, ++ 0,0,0,0,31,0,73,26,0,0,9,0,30,0,80,0, ++ 35,0,41,7,78,122,18,70,114,111,122,101,110,32,72,101, + 108,108,111,32,87,111,114,108,100,122,8,115,121,115,46,97, + 114,103,118,218,6,99,111,110,102,105,103,41,5,218,12,112, + 114,111,103,114,97,109,95,110,97,109,101,218,10,101,120,101, +@@ -30,8 +31,8 @@ + 1,0,0,0,115,94,0,0,0,240,3,1,1,1,243,8, + 0,1,11,219,0,24,225,0,5,208,6,26,212,0,27,217, + 0,5,128,106,144,35,151,40,145,40,212,0,27,216,9,26, +- 215,9,38,210,9,38,211,9,40,168,24,209,9,50,128,6, ++ 215,9,38,210,9,38,211,9,40,168,24,213,9,50,128,6, + 243,2,6,12,2,128,67,241,14,0,5,10,136,71,144,67, +- 144,53,152,2,152,54,160,35,153,59,152,45,208,10,40,214, ++ 144,53,152,2,152,54,160,35,157,59,152,45,208,10,40,214, + 4,41,243,15,6,12,2,114,15,0,0,0, + }; +diff --git a/Python/Python-ast.c b/Python/Python-ast.c +index 41299b29705..7038e3c92ab 100644 +--- a/Python/Python-ast.c ++++ b/Python/Python-ast.c +@@ -5661,10 +5661,11 @@ + return PyObject_Repr(list); + } + +- _PyUnicodeWriter writer; +- _PyUnicodeWriter_Init(&writer); +- writer.overallocate = 1; + PyObject *items[2] = {NULL, NULL}; ++ PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); ++ if (writer == NULL) { ++ goto error; ++ } + + items[0] = PySequence_GetItem(list, 0); + if (!items[0]) { +@@ -5678,52 +5679,54 @@ + } + + bool is_list = PyList_Check(list); +- if (_PyUnicodeWriter_WriteChar(&writer, is_list ? '[' : '(') < 0) { ++ if (PyUnicodeWriter_WriteChar(writer, is_list ? '[' : '(') < 0) { + goto error; + } + + for (Py_ssize_t i = 0; i < Py_MIN(length, 2); i++) { +- PyObject *item = items[i]; +- PyObject *item_repr; ++ if (i > 0) { ++ if (PyUnicodeWriter_WriteUTF8(writer, ", ", 2) < 0) { ++ goto error; ++ } ++ } + ++ PyObject *item = items[i]; + if (PyType_IsSubtype(Py_TYPE(item), (PyTypeObject *)state->AST_type)) { ++ PyObject *item_repr; + item_repr = ast_repr_max_depth((AST_object*)item, depth - 1); +- } else { +- item_repr = PyObject_Repr(item); +- } +- if (!item_repr) { +- goto error; +- } +- if (i > 0) { +- if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) { ++ if (!item_repr) { ++ goto error; ++ } ++ if (PyUnicodeWriter_WriteStr(writer, item_repr) < 0) { ++ Py_DECREF(item_repr); + goto error; + } +- } +- if (_PyUnicodeWriter_WriteStr(&writer, item_repr) < 0) { + Py_DECREF(item_repr); +- goto error; ++ } else { ++ if (PyUnicodeWriter_WriteRepr(writer, item) < 0) { ++ goto error; ++ } + } ++ + if (i == 0 && length > 2) { +- if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ...", 5) < 0) { +- Py_DECREF(item_repr); ++ if (PyUnicodeWriter_WriteUTF8(writer, ", ...", 5) < 0) { + goto error; + } + } +- Py_DECREF(item_repr); + } + +- if (_PyUnicodeWriter_WriteChar(&writer, is_list ? ']' : ')') < 0) { ++ if (PyUnicodeWriter_WriteChar(writer, is_list ? ']' : ')') < 0) { + goto error; + } + + Py_XDECREF(items[0]); + Py_XDECREF(items[1]); +- return _PyUnicodeWriter_Finish(&writer); ++ return PyUnicodeWriter_Finish(writer); + + error: + Py_XDECREF(items[0]); + Py_XDECREF(items[1]); +- _PyUnicodeWriter_Dealloc(&writer); ++ PyUnicodeWriter_Discard(writer); + return NULL; + } + +@@ -5767,14 +5770,15 @@ + } + + const char* tp_name = Py_TYPE(self)->tp_name; +- _PyUnicodeWriter writer; +- _PyUnicodeWriter_Init(&writer); +- writer.overallocate = 1; ++ PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); ++ if (writer == NULL) { ++ goto error; ++ } + +- if (_PyUnicodeWriter_WriteASCIIString(&writer, tp_name, strlen(tp_name)) < 0) { ++ if (PyUnicodeWriter_WriteUTF8(writer, tp_name, -1) < 0) { + goto error; + } +- if (_PyUnicodeWriter_WriteChar(&writer, '(') < 0) { ++ if (PyUnicodeWriter_WriteChar(writer, '(') < 0) { + goto error; + } + +@@ -5809,13 +5813,13 @@ + } + + if (i > 0) { +- if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) { ++ if (PyUnicodeWriter_WriteUTF8(writer, ", ", 2) < 0) { + Py_DECREF(name); + Py_DECREF(value_repr); + goto error; + } + } +- if (_PyUnicodeWriter_WriteStr(&writer, name) < 0) { ++ if (PyUnicodeWriter_WriteStr(writer, name) < 0) { + Py_DECREF(name); + Py_DECREF(value_repr); + goto error; +@@ -5823,11 +5827,11 @@ + + Py_DECREF(name); + +- if (_PyUnicodeWriter_WriteChar(&writer, '=') < 0) { ++ if (PyUnicodeWriter_WriteChar(writer, '=') < 0) { + Py_DECREF(value_repr); + goto error; + } +- if (_PyUnicodeWriter_WriteStr(&writer, value_repr) < 0) { ++ if (PyUnicodeWriter_WriteStr(writer, value_repr) < 0) { + Py_DECREF(value_repr); + goto error; + } +@@ -5835,17 +5839,17 @@ + Py_DECREF(value_repr); + } + +- if (_PyUnicodeWriter_WriteChar(&writer, ')') < 0) { ++ if (PyUnicodeWriter_WriteChar(writer, ')') < 0) { + goto error; + } + Py_ReprLeave((PyObject *)self); + Py_DECREF(fields); +- return _PyUnicodeWriter_Finish(&writer); ++ return PyUnicodeWriter_Finish(writer); + + error: + Py_ReprLeave((PyObject *)self); + Py_DECREF(fields); +- _PyUnicodeWriter_Dealloc(&writer); ++ PyUnicodeWriter_Discard(writer); + return NULL; + } + +diff --git a/Python/_warnings.c b/Python/_warnings.c +index e05ba99e8ea..891db2743a2 100644 +--- a/Python/_warnings.c ++++ b/Python/_warnings.c +@@ -232,6 +232,64 @@ + return obj; + } + ++static inline void ++warnings_lock(PyInterpreterState *interp) ++{ ++ WarningsState *st = warnings_get_state(interp); ++ assert(st != NULL); ++ _PyRecursiveMutex_Lock(&st->lock); ++} ++ ++static inline int ++warnings_unlock(PyInterpreterState *interp) ++{ ++ WarningsState *st = warnings_get_state(interp); ++ assert(st != NULL); ++ return _PyRecursiveMutex_TryUnlock(&st->lock); ++} ++ ++static inline bool ++warnings_lock_held(WarningsState *st) ++{ ++ return PyMutex_IsLocked(&st->lock.mutex); ++} ++ ++/*[clinic input] ++_acquire_lock as warnings_acquire_lock ++ ++[clinic start generated code]*/ ++ ++static PyObject * ++warnings_acquire_lock_impl(PyObject *module) ++/*[clinic end generated code: output=594313457d1bf8e1 input=46ec20e55acca52f]*/ ++{ ++ PyInterpreterState *interp = get_current_interp(); ++ if (interp == NULL) { ++ return NULL; ++ } ++ warnings_lock(interp); ++ Py_RETURN_NONE; ++} ++ ++/*[clinic input] ++_release_lock as warnings_release_lock ++ ++[clinic start generated code]*/ ++ ++static PyObject * ++warnings_release_lock_impl(PyObject *module) ++/*[clinic end generated code: output=d73d5a8789396750 input=ea01bb77870c5693]*/ ++{ ++ PyInterpreterState *interp = get_current_interp(); ++ if (interp == NULL) { ++ return NULL; ++ } ++ if (warnings_unlock(interp) < 0) { ++ PyErr_SetString(PyExc_RuntimeError, "cannot release un-acquired lock"); ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} + + static PyObject * + get_once_registry(PyInterpreterState *interp) +@@ -239,7 +297,7 @@ + WarningsState *st = warnings_get_state(interp); + assert(st != NULL); + +- _Py_CRITICAL_SECTION_ASSERT_MUTEX_LOCKED(&st->mutex); ++ assert(warnings_lock_held(st)); + + PyObject *registry = GET_WARNINGS_ATTR(interp, onceregistry, 0); + if (registry == NULL) { +@@ -267,7 +325,7 @@ + WarningsState *st = warnings_get_state(interp); + assert(st != NULL); + +- _Py_CRITICAL_SECTION_ASSERT_MUTEX_LOCKED(&st->mutex); ++ assert(warnings_lock_held(st)); + + PyObject *default_action = GET_WARNINGS_ATTR(interp, defaultaction, 0); + if (default_action == NULL) { +@@ -299,7 +357,7 @@ + WarningsState *st = warnings_get_state(interp); + assert(st != NULL); + +- _Py_CRITICAL_SECTION_ASSERT_MUTEX_LOCKED(&st->mutex); ++ assert(warnings_lock_held(st)); + + PyObject *warnings_filters = GET_WARNINGS_ATTR(interp, filters, 0); + if (warnings_filters == NULL) { +@@ -399,7 +457,7 @@ + + WarningsState *st = warnings_get_state(interp); + assert(st != NULL); +- _Py_CRITICAL_SECTION_ASSERT_MUTEX_LOCKED(&st->mutex); ++ assert(warnings_lock_held(st)); + + PyObject *version_obj; + if (PyDict_GetItemRef(registry, &_Py_ID(version), &version_obj) < 0) { +@@ -994,15 +1052,10 @@ + &filename, &lineno, &module, ®istry)) + return NULL; + +-#ifdef Py_GIL_DISABLED +- WarningsState *st = warnings_get_state(tstate->interp); +- assert(st != NULL); +-#endif +- +- Py_BEGIN_CRITICAL_SECTION_MUT(&st->mutex); ++ warnings_lock(tstate->interp); + res = warn_explicit(tstate, category, message, filename, lineno, module, registry, + NULL, source); +- Py_END_CRITICAL_SECTION(); ++ warnings_unlock(tstate->interp); + Py_DECREF(filename); + Py_DECREF(registry); + Py_DECREF(module); +@@ -1151,27 +1204,22 @@ + } + } + +-#ifdef Py_GIL_DISABLED +- WarningsState *st = warnings_get_state(tstate->interp); +- assert(st != NULL); +-#endif +- +- Py_BEGIN_CRITICAL_SECTION_MUT(&st->mutex); ++ warnings_lock(tstate->interp); + returned = warn_explicit(tstate, category, message, filename, lineno, + mod, registry, source_line, sourceobj); +- Py_END_CRITICAL_SECTION(); ++ warnings_unlock(tstate->interp); + Py_XDECREF(source_line); + return returned; + } + + /*[clinic input] +-_filters_mutated as warnings_filters_mutated ++_filters_mutated_lock_held as warnings_filters_mutated_lock_held + + [clinic start generated code]*/ + + static PyObject * +-warnings_filters_mutated_impl(PyObject *module) +-/*[clinic end generated code: output=8ce517abd12b88f4 input=35ecbf08ee2491b2]*/ ++warnings_filters_mutated_lock_held_impl(PyObject *module) ++/*[clinic end generated code: output=df5c84f044e856ec input=34208bf03d70e432]*/ + { + PyInterpreterState *interp = get_current_interp(); + if (interp == NULL) { +@@ -1181,14 +1229,17 @@ + WarningsState *st = warnings_get_state(interp); + assert(st != NULL); + +- Py_BEGIN_CRITICAL_SECTION_MUT(&st->mutex); ++ // Note that the lock must be held by the caller. ++ if (!warnings_lock_held(st)) { ++ PyErr_SetString(PyExc_RuntimeError, "warnings lock is not held"); ++ return NULL; ++ } ++ + st->filters_version++; +- Py_END_CRITICAL_SECTION(); + + Py_RETURN_NONE; + } + +- + /* Function to issue a warning message; may raise an exception. */ + + static int +@@ -1303,15 +1354,10 @@ + return -1; + } + +-#ifdef Py_GIL_DISABLED +- WarningsState *st = warnings_get_state(tstate->interp); +- assert(st != NULL); +-#endif +- +- Py_BEGIN_CRITICAL_SECTION_MUT(&st->mutex); ++ warnings_lock(tstate->interp); + res = warn_explicit(tstate, category, message, filename, lineno, + module, registry, NULL, NULL); +- Py_END_CRITICAL_SECTION(); ++ warnings_unlock(tstate->interp); + if (res == NULL) + return -1; + Py_DECREF(res); +@@ -1376,15 +1422,10 @@ + PyObject *res; + PyThreadState *tstate = get_current_tstate(); + if (tstate != NULL) { +-#ifdef Py_GIL_DISABLED +- WarningsState *st = warnings_get_state(tstate->interp); +- assert(st != NULL); +-#endif +- +- Py_BEGIN_CRITICAL_SECTION_MUT(&st->mutex); ++ warnings_lock(tstate->interp); + res = warn_explicit(tstate, category, message, filename, lineno, + module, registry, NULL, NULL); +- Py_END_CRITICAL_SECTION(); ++ warnings_unlock(tstate->interp); + Py_DECREF(message); + if (res != NULL) { + Py_DECREF(res); +@@ -1407,7 +1448,8 @@ + "coroutine method %R of %R was never awaited", + method, agen->ag_qualname) < 0) + { +- PyErr_WriteUnraisable((PyObject *)agen); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "finalizing async generator %R", agen); + } + PyErr_SetRaisedException(exc); + } +@@ -1449,14 +1491,17 @@ + } + + if (PyErr_Occurred()) { +- PyErr_WriteUnraisable(coro); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "finalizing coroutine %R", coro); + } ++ + if (!warned) { + if (_PyErr_WarnFormat(coro, PyExc_RuntimeWarning, 1, + "coroutine '%S' was never awaited", + ((PyCoroObject *)coro)->cr_qualname) < 0) + { +- PyErr_WriteUnraisable(coro); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "finalizing coroutine %R", coro); + } + } + } +@@ -1464,7 +1509,9 @@ + static PyMethodDef warnings_functions[] = { + WARNINGS_WARN_METHODDEF + WARNINGS_WARN_EXPLICIT_METHODDEF +- WARNINGS_FILTERS_MUTATED_METHODDEF ++ WARNINGS_FILTERS_MUTATED_LOCK_HELD_METHODDEF ++ WARNINGS_ACQUIRE_LOCK_METHODDEF ++ WARNINGS_RELEASE_LOCK_METHODDEF + /* XXX(brett.cannon): add showwarning? */ + /* XXX(brett.cannon): Reasonable to add formatwarning? */ + {NULL, NULL} /* sentinel */ +diff --git a/Python/ast_opt.c b/Python/ast_opt.c +index 01e208b88ec..78d84002d59 100644 +--- a/Python/ast_opt.c ++++ b/Python/ast_opt.c +@@ -567,25 +567,6 @@ + return make_const(node, newval, arena); + } + +-static int +-fold_subscr(expr_ty node, PyArena *arena, _PyASTOptimizeState *state) +-{ +- PyObject *newval; +- expr_ty arg, idx; +- +- arg = node->v.Subscript.value; +- idx = node->v.Subscript.slice; +- if (node->v.Subscript.ctx != Load || +- arg->kind != Constant_kind || +- idx->kind != Constant_kind) +- { +- return 1; +- } +- +- newval = PyObject_GetItem(arg->v.Constant.value, idx->v.Constant.value); +- return make_const(node, newval, arena); +-} +- + /* Change literal list or set of constants into constant + tuple or frozenset respectively. Change literal list of + non-constants into tuple. +@@ -822,7 +803,6 @@ + case Subscript_kind: + CALL(astfold_expr, expr_ty, node_->v.Subscript.value); + CALL(astfold_expr, expr_ty, node_->v.Subscript.slice); +- CALL(fold_subscr, expr_ty, node_); + break; + case Starred_kind: + CALL(astfold_expr, expr_ty, node_->v.Starred.value); +diff --git a/Python/ast_unparse.c b/Python/ast_unparse.c +index 8017cfc7fcf..f3c669c33eb 100644 +--- a/Python/ast_unparse.c ++++ b/Python/ast_unparse.c +@@ -16,24 +16,40 @@ + static PyObject * + expr_as_unicode(expr_ty e, int level); + static int +-append_ast_expr(_PyUnicodeWriter *writer, expr_ty e, int level); ++append_ast_expr(PyUnicodeWriter *writer, expr_ty e, int level); + static int +-append_joinedstr(_PyUnicodeWriter *writer, expr_ty e, bool is_format_spec); ++append_joinedstr(PyUnicodeWriter *writer, expr_ty e, bool is_format_spec); + static int +-append_formattedvalue(_PyUnicodeWriter *writer, expr_ty e); ++append_formattedvalue(PyUnicodeWriter *writer, expr_ty e); + static int +-append_ast_slice(_PyUnicodeWriter *writer, expr_ty e); ++append_ast_slice(PyUnicodeWriter *writer, expr_ty e); + + static int +-append_charp(_PyUnicodeWriter *writer, const char *charp) ++append_char(PyUnicodeWriter *writer, Py_UCS4 ch) + { +- return _PyUnicodeWriter_WriteASCIIString(writer, charp, -1); ++ return PyUnicodeWriter_WriteChar(writer, ch); + } + ++static int ++append_charp(PyUnicodeWriter *writer, const char *charp) ++{ ++ return PyUnicodeWriter_WriteUTF8(writer, charp, -1); ++} ++ ++#define APPEND_CHAR_FINISH(ch) do { \ ++ return append_char(writer, (ch)); \ ++ } while (0) ++ + #define APPEND_STR_FINISH(str) do { \ + return append_charp(writer, (str)); \ + } while (0) + ++#define APPEND_CHAR(ch) do { \ ++ if (-1 == append_char(writer, (ch))) { \ ++ return -1; \ ++ } \ ++ } while (0) ++ + #define APPEND_STR(str) do { \ + if (-1 == append_charp(writer, (str))) { \ + return -1; \ +@@ -64,10 +80,9 @@ + } while (0) + + static int +-append_repr(_PyUnicodeWriter *writer, PyObject *obj) ++append_repr(PyUnicodeWriter *writer, PyObject *obj) + { + PyObject *repr = PyObject_Repr(obj); +- + if (!repr) { + return -1; + } +@@ -88,7 +103,8 @@ + } + repr = new_repr; + } +- int ret = _PyUnicodeWriter_WriteStr(writer, repr); ++ ++ int ret = PyUnicodeWriter_WriteStr(writer, repr); + Py_DECREF(repr); + return ret; + } +@@ -117,7 +133,7 @@ + }; + + static int +-append_ast_boolop(_PyUnicodeWriter *writer, expr_ty e, int level) ++append_ast_boolop(PyUnicodeWriter *writer, expr_ty e, int level) + { + Py_ssize_t i, value_count; + asdl_expr_seq *values; +@@ -139,7 +155,7 @@ + } + + static int +-append_ast_binop(_PyUnicodeWriter *writer, expr_ty e, int level) ++append_ast_binop(PyUnicodeWriter *writer, expr_ty e, int level) + { + const char *op; + int pr; +@@ -174,7 +190,7 @@ + } + + static int +-append_ast_unaryop(_PyUnicodeWriter *writer, expr_ty e, int level) ++append_ast_unaryop(PyUnicodeWriter *writer, expr_ty e, int level) + { + const char *op; + int pr; +@@ -198,9 +214,9 @@ + } + + static int +-append_ast_arg(_PyUnicodeWriter *writer, arg_ty arg) ++append_ast_arg(PyUnicodeWriter *writer, arg_ty arg) + { +- if (-1 == _PyUnicodeWriter_WriteStr(writer, arg->arg)) { ++ if (PyUnicodeWriter_WriteStr(writer, arg->arg) < 0) { + return -1; + } + if (arg->annotation) { +@@ -211,7 +227,7 @@ + } + + static int +-append_ast_args(_PyUnicodeWriter *writer, arguments_ty args) ++append_ast_args(PyUnicodeWriter *writer, arguments_ty args) + { + bool first; + Py_ssize_t i, di, arg_count, posonlyarg_count, default_count; +@@ -232,7 +248,7 @@ + + di = i - posonlyarg_count - arg_count + default_count; + if (di >= 0) { +- APPEND_STR("="); ++ APPEND_CHAR('='); + APPEND_EXPR((expr_ty)asdl_seq_GET(args->defaults, di), PR_TEST); + } + if (posonlyarg_count && i + 1 == posonlyarg_count) { +@@ -260,7 +276,7 @@ + if (di >= 0) { + expr_ty default_ = (expr_ty)asdl_seq_GET(args->kw_defaults, di); + if (default_) { +- APPEND_STR("="); ++ APPEND_CHAR('='); + APPEND_EXPR(default_, PR_TEST); + } + } +@@ -277,7 +293,7 @@ + } + + static int +-append_ast_lambda(_PyUnicodeWriter *writer, expr_ty e, int level) ++append_ast_lambda(PyUnicodeWriter *writer, expr_ty e, int level) + { + APPEND_STR_IF(level > PR_TEST, "("); + Py_ssize_t n_positional = (asdl_seq_LEN(e->v.Lambda.args->args) + +@@ -291,7 +307,7 @@ + } + + static int +-append_ast_ifexp(_PyUnicodeWriter *writer, expr_ty e, int level) ++append_ast_ifexp(PyUnicodeWriter *writer, expr_ty e, int level) + { + APPEND_STR_IF(level > PR_TEST, "("); + APPEND_EXPR(e->v.IfExp.body, PR_TEST + 1); +@@ -304,12 +320,12 @@ + } + + static int +-append_ast_dict(_PyUnicodeWriter *writer, expr_ty e) ++append_ast_dict(PyUnicodeWriter *writer, expr_ty e) + { + Py_ssize_t i, value_count; + expr_ty key_node; + +- APPEND_STR("{"); ++ APPEND_CHAR('{'); + value_count = asdl_seq_LEN(e->v.Dict.values); + + for (i = 0; i < value_count; i++) { +@@ -326,41 +342,41 @@ + } + } + +- APPEND_STR_FINISH("}"); ++ APPEND_CHAR_FINISH('}'); + } + + static int +-append_ast_set(_PyUnicodeWriter *writer, expr_ty e) ++append_ast_set(PyUnicodeWriter *writer, expr_ty e) + { + Py_ssize_t i, elem_count; + +- APPEND_STR("{"); ++ APPEND_CHAR('{'); + elem_count = asdl_seq_LEN(e->v.Set.elts); + for (i = 0; i < elem_count; i++) { + APPEND_STR_IF(i > 0, ", "); + APPEND_EXPR((expr_ty)asdl_seq_GET(e->v.Set.elts, i), PR_TEST); + } + +- APPEND_STR_FINISH("}"); ++ APPEND_CHAR_FINISH('}'); + } + + static int +-append_ast_list(_PyUnicodeWriter *writer, expr_ty e) ++append_ast_list(PyUnicodeWriter *writer, expr_ty e) + { + Py_ssize_t i, elem_count; + +- APPEND_STR("["); ++ APPEND_CHAR('['); + elem_count = asdl_seq_LEN(e->v.List.elts); + for (i = 0; i < elem_count; i++) { + APPEND_STR_IF(i > 0, ", "); + APPEND_EXPR((expr_ty)asdl_seq_GET(e->v.List.elts, i), PR_TEST); + } + +- APPEND_STR_FINISH("]"); ++ APPEND_CHAR_FINISH(']'); + } + + static int +-append_ast_tuple(_PyUnicodeWriter *writer, expr_ty e, int level) ++append_ast_tuple(PyUnicodeWriter *writer, expr_ty e, int level) + { + Py_ssize_t i, elem_count; + +@@ -383,7 +399,7 @@ + } + + static int +-append_ast_comprehension(_PyUnicodeWriter *writer, comprehension_ty gen) ++append_ast_comprehension(PyUnicodeWriter *writer, comprehension_ty gen) + { + Py_ssize_t i, if_count; + +@@ -401,7 +417,7 @@ + } + + static int +-append_ast_comprehensions(_PyUnicodeWriter *writer, asdl_comprehension_seq *comprehensions) ++append_ast_comprehensions(PyUnicodeWriter *writer, asdl_comprehension_seq *comprehensions) + { + Py_ssize_t i, gen_count; + gen_count = asdl_seq_LEN(comprehensions); +@@ -414,45 +430,45 @@ + } + + static int +-append_ast_genexp(_PyUnicodeWriter *writer, expr_ty e) ++append_ast_genexp(PyUnicodeWriter *writer, expr_ty e) + { +- APPEND_STR("("); ++ APPEND_CHAR('('); + APPEND_EXPR(e->v.GeneratorExp.elt, PR_TEST); + APPEND(comprehensions, e->v.GeneratorExp.generators); +- APPEND_STR_FINISH(")"); ++ APPEND_CHAR_FINISH(')'); + } + + static int +-append_ast_listcomp(_PyUnicodeWriter *writer, expr_ty e) ++append_ast_listcomp(PyUnicodeWriter *writer, expr_ty e) + { +- APPEND_STR("["); ++ APPEND_CHAR('['); + APPEND_EXPR(e->v.ListComp.elt, PR_TEST); + APPEND(comprehensions, e->v.ListComp.generators); +- APPEND_STR_FINISH("]"); ++ APPEND_CHAR_FINISH(']'); + } + + static int +-append_ast_setcomp(_PyUnicodeWriter *writer, expr_ty e) ++append_ast_setcomp(PyUnicodeWriter *writer, expr_ty e) + { +- APPEND_STR("{"); ++ APPEND_CHAR('{'); + APPEND_EXPR(e->v.SetComp.elt, PR_TEST); + APPEND(comprehensions, e->v.SetComp.generators); +- APPEND_STR_FINISH("}"); ++ APPEND_CHAR_FINISH('}'); + } + + static int +-append_ast_dictcomp(_PyUnicodeWriter *writer, expr_ty e) ++append_ast_dictcomp(PyUnicodeWriter *writer, expr_ty e) + { +- APPEND_STR("{"); ++ APPEND_CHAR('{'); + APPEND_EXPR(e->v.DictComp.key, PR_TEST); + APPEND_STR(": "); + APPEND_EXPR(e->v.DictComp.value, PR_TEST); + APPEND(comprehensions, e->v.DictComp.generators); +- APPEND_STR_FINISH("}"); ++ APPEND_CHAR_FINISH('}'); + } + + static int +-append_ast_compare(_PyUnicodeWriter *writer, expr_ty e, int level) ++append_ast_compare(PyUnicodeWriter *writer, expr_ty e, int level) + { + const char *op; + Py_ssize_t i, comparator_count; +@@ -516,17 +532,17 @@ + } + + static int +-append_ast_keyword(_PyUnicodeWriter *writer, keyword_ty kw) ++append_ast_keyword(PyUnicodeWriter *writer, keyword_ty kw) + { + if (kw->arg == NULL) { + APPEND_STR("**"); + } + else { +- if (-1 == _PyUnicodeWriter_WriteStr(writer, kw->arg)) { ++ if (-1 == PyUnicodeWriter_WriteStr(writer, kw->arg)) { + return -1; + } + +- APPEND_STR("="); ++ APPEND_CHAR('='); + } + + APPEND_EXPR(kw->value, PR_TEST); +@@ -534,7 +550,7 @@ + } + + static int +-append_ast_call(_PyUnicodeWriter *writer, expr_ty e) ++append_ast_call(PyUnicodeWriter *writer, expr_ty e) + { + bool first; + Py_ssize_t i, arg_count, kw_count; +@@ -552,7 +568,7 @@ + } + } + +- APPEND_STR("("); ++ APPEND_CHAR('('); + + first = true; + for (i = 0; i < arg_count; i++) { +@@ -565,7 +581,7 @@ + APPEND(keyword, (keyword_ty)asdl_seq_GET(e->v.Call.keywords, i)); + } + +- APPEND_STR_FINISH(")"); ++ APPEND_CHAR_FINISH(')'); + } + + static PyObject * +@@ -585,20 +601,20 @@ + } + + static int +-append_fstring_unicode(_PyUnicodeWriter *writer, PyObject *unicode) ++append_fstring_unicode(PyUnicodeWriter *writer, PyObject *unicode) + { + PyObject *escaped; + int result = -1; + escaped = escape_braces(unicode); + if (escaped) { +- result = _PyUnicodeWriter_WriteStr(writer, escaped); ++ result = PyUnicodeWriter_WriteStr(writer, escaped); + Py_DECREF(escaped); + } + return result; + } + + static int +-append_fstring_element(_PyUnicodeWriter *writer, expr_ty e, bool is_format_spec) ++append_fstring_element(PyUnicodeWriter *writer, expr_ty e, bool is_format_spec) + { + switch (e->kind) { + case Constant_kind: +@@ -619,28 +635,27 @@ + static PyObject * + build_fstring_body(asdl_expr_seq *values, bool is_format_spec) + { +- Py_ssize_t i, value_count; +- _PyUnicodeWriter body_writer; +- _PyUnicodeWriter_Init(&body_writer); +- body_writer.min_length = 256; +- body_writer.overallocate = 1; ++ PyUnicodeWriter *body_writer = PyUnicodeWriter_Create(256); ++ if (body_writer == NULL) { ++ return NULL; ++ } + +- value_count = asdl_seq_LEN(values); +- for (i = 0; i < value_count; ++i) { +- if (-1 == append_fstring_element(&body_writer, ++ Py_ssize_t value_count = asdl_seq_LEN(values); ++ for (Py_ssize_t i = 0; i < value_count; ++i) { ++ if (-1 == append_fstring_element(body_writer, + (expr_ty)asdl_seq_GET(values, i), + is_format_spec + )) { +- _PyUnicodeWriter_Dealloc(&body_writer); ++ PyUnicodeWriter_Discard(body_writer); + return NULL; + } + } + +- return _PyUnicodeWriter_Finish(&body_writer); ++ return PyUnicodeWriter_Finish(body_writer); + } + + static int +-append_joinedstr(_PyUnicodeWriter *writer, expr_ty e, bool is_format_spec) ++append_joinedstr(PyUnicodeWriter *writer, expr_ty e, bool is_format_spec) + { + int result = -1; + PyObject *body = build_fstring_body(e->v.JoinedStr.values, is_format_spec); +@@ -656,14 +671,14 @@ + } + } + else { +- result = _PyUnicodeWriter_WriteStr(writer, body); ++ result = PyUnicodeWriter_WriteStr(writer, body); + } + Py_DECREF(body); + return result; + } + + static int +-append_formattedvalue(_PyUnicodeWriter *writer, expr_ty e) ++append_formattedvalue(PyUnicodeWriter *writer, expr_ty e) + { + const char *conversion; + const char *outer_brace = "{"; +@@ -682,7 +697,7 @@ + Py_DECREF(temp_fv_str); + return -1; + } +- if (-1 == _PyUnicodeWriter_WriteStr(writer, temp_fv_str)) { ++ if (-1 == PyUnicodeWriter_WriteStr(writer, temp_fv_str)) { + Py_DECREF(temp_fv_str); + return -1; + } +@@ -707,7 +722,7 @@ + APPEND_STR(conversion); + } + if (e->v.FormattedValue.format_spec) { +- if (-1 == _PyUnicodeWriter_WriteASCIIString(writer, ":", 1) || ++ if (-1 == PyUnicodeWriter_WriteChar(writer, ':') || + -1 == append_fstring_element(writer, + e->v.FormattedValue.format_spec, + true +@@ -717,17 +732,17 @@ + } + } + +- APPEND_STR_FINISH("}"); ++ APPEND_CHAR_FINISH('}'); + } + + static int +-append_ast_constant(_PyUnicodeWriter *writer, PyObject *constant) ++append_ast_constant(PyUnicodeWriter *writer, PyObject *constant) + { + if (PyTuple_CheckExact(constant)) { + Py_ssize_t i, elem_count; + + elem_count = PyTuple_GET_SIZE(constant); +- APPEND_STR("("); ++ APPEND_CHAR('('); + for (i = 0; i < elem_count; i++) { + APPEND_STR_IF(i > 0, ", "); + if (append_ast_constant(writer, PyTuple_GET_ITEM(constant, i)) < 0) { +@@ -736,14 +751,13 @@ + } + + APPEND_STR_IF(elem_count == 1, ","); +- APPEND_STR(")"); +- return 0; ++ APPEND_CHAR_FINISH(')'); + } + return append_repr(writer, constant); + } + + static int +-append_ast_attribute(_PyUnicodeWriter *writer, expr_ty e) ++append_ast_attribute(PyUnicodeWriter *writer, expr_ty e) + { + const char *period; + expr_ty v = e->v.Attribute.value; +@@ -759,48 +773,48 @@ + } + APPEND_STR(period); + +- return _PyUnicodeWriter_WriteStr(writer, e->v.Attribute.attr); ++ return PyUnicodeWriter_WriteStr(writer, e->v.Attribute.attr); + } + + static int +-append_ast_slice(_PyUnicodeWriter *writer, expr_ty e) ++append_ast_slice(PyUnicodeWriter *writer, expr_ty e) + { + if (e->v.Slice.lower) { + APPEND_EXPR(e->v.Slice.lower, PR_TEST); + } + +- APPEND_STR(":"); ++ APPEND_CHAR(':'); + + if (e->v.Slice.upper) { + APPEND_EXPR(e->v.Slice.upper, PR_TEST); + } + + if (e->v.Slice.step) { +- APPEND_STR(":"); ++ APPEND_CHAR(':'); + APPEND_EXPR(e->v.Slice.step, PR_TEST); + } + return 0; + } + + static int +-append_ast_subscript(_PyUnicodeWriter *writer, expr_ty e) ++append_ast_subscript(PyUnicodeWriter *writer, expr_ty e) + { + APPEND_EXPR(e->v.Subscript.value, PR_ATOM); +- APPEND_STR("["); ++ APPEND_CHAR('['); + APPEND_EXPR(e->v.Subscript.slice, PR_TUPLE); +- APPEND_STR_FINISH("]"); ++ APPEND_CHAR_FINISH(']'); + } + + static int +-append_ast_starred(_PyUnicodeWriter *writer, expr_ty e) ++append_ast_starred(PyUnicodeWriter *writer, expr_ty e) + { +- APPEND_STR("*"); ++ APPEND_CHAR('*'); + APPEND_EXPR(e->v.Starred.value, PR_EXPR); + return 0; + } + + static int +-append_ast_yield(_PyUnicodeWriter *writer, expr_ty e) ++append_ast_yield(PyUnicodeWriter *writer, expr_ty e) + { + if (!e->v.Yield.value) { + APPEND_STR_FINISH("(yield)"); +@@ -808,19 +822,19 @@ + + APPEND_STR("(yield "); + APPEND_EXPR(e->v.Yield.value, PR_TEST); +- APPEND_STR_FINISH(")"); ++ APPEND_CHAR_FINISH(')'); + } + + static int +-append_ast_yield_from(_PyUnicodeWriter *writer, expr_ty e) ++append_ast_yield_from(PyUnicodeWriter *writer, expr_ty e) + { + APPEND_STR("(yield from "); + APPEND_EXPR(e->v.YieldFrom.value, PR_TEST); +- APPEND_STR_FINISH(")"); ++ APPEND_CHAR_FINISH(')'); + } + + static int +-append_ast_await(_PyUnicodeWriter *writer, expr_ty e, int level) ++append_ast_await(PyUnicodeWriter *writer, expr_ty e, int level) + { + APPEND_STR_IF(level > PR_AWAIT, "("); + APPEND_STR("await "); +@@ -830,7 +844,7 @@ + } + + static int +-append_named_expr(_PyUnicodeWriter *writer, expr_ty e, int level) ++append_named_expr(PyUnicodeWriter *writer, expr_ty e, int level) + { + APPEND_STR_IF(level > PR_TUPLE, "("); + APPEND_EXPR(e->v.NamedExpr.target, PR_ATOM); +@@ -841,7 +855,7 @@ + } + + static int +-append_ast_expr(_PyUnicodeWriter *writer, expr_ty e, int level) ++append_ast_expr(PyUnicodeWriter *writer, expr_ty e, int level) + { + switch (e->kind) { + case BoolOp_kind: +@@ -881,7 +895,7 @@ + APPEND_STR_FINISH("..."); + } + if (e->v.Constant.kind != NULL +- && -1 == _PyUnicodeWriter_WriteStr(writer, e->v.Constant.kind)) { ++ && -1 == PyUnicodeWriter_WriteStr(writer, e->v.Constant.kind)) { + return -1; + } + return append_ast_constant(writer, e->v.Constant.value); +@@ -899,7 +913,7 @@ + case Slice_kind: + return append_ast_slice(writer, e); + case Name_kind: +- return _PyUnicodeWriter_WriteStr(writer, e->v.Name.id); ++ return PyUnicodeWriter_WriteStr(writer, e->v.Name.id); + case List_kind: + return append_ast_list(writer, e); + case Tuple_kind: +@@ -916,15 +930,16 @@ + static PyObject * + expr_as_unicode(expr_ty e, int level) + { +- _PyUnicodeWriter writer; +- _PyUnicodeWriter_Init(&writer); +- writer.min_length = 256; +- writer.overallocate = 1; +- if (-1 == append_ast_expr(&writer, e, level)) { +- _PyUnicodeWriter_Dealloc(&writer); ++ PyUnicodeWriter *writer = PyUnicodeWriter_Create(256); ++ if (writer == NULL) { ++ return NULL; ++ } ++ ++ if (-1 == append_ast_expr(writer, e, level)) { ++ PyUnicodeWriter_Discard(writer); + return NULL; + } +- return _PyUnicodeWriter_Finish(&writer); ++ return PyUnicodeWriter_Finish(writer); + } + + PyObject * +diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c +index fb9868b3740..46a6fd9a8ef 100644 +--- a/Python/bltinmodule.c ++++ b/Python/bltinmodule.c +@@ -494,6 +494,8 @@ + PyObject *it; + } filterobject; + ++#define _filterobject_CAST(op) ((filterobject *)(op)) ++ + static PyObject * + filter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) + { +@@ -559,8 +561,9 @@ + } + + static void +-filter_dealloc(filterobject *lz) ++filter_dealloc(PyObject *self) + { ++ filterobject *lz = _filterobject_CAST(self); + PyObject_GC_UnTrack(lz); + Py_TRASHCAN_BEGIN(lz, filter_dealloc) + Py_XDECREF(lz->func); +@@ -570,16 +573,18 @@ + } + + static int +-filter_traverse(filterobject *lz, visitproc visit, void *arg) ++filter_traverse(PyObject *self, visitproc visit, void *arg) + { ++ filterobject *lz = _filterobject_CAST(self); + Py_VISIT(lz->it); + Py_VISIT(lz->func); + return 0; + } + + static PyObject * +-filter_next(filterobject *lz) ++filter_next(PyObject *self) + { ++ filterobject *lz = _filterobject_CAST(self); + PyObject *item; + PyObject *it = lz->it; + long ok; +@@ -613,15 +618,16 @@ + } + + static PyObject * +-filter_reduce(filterobject *lz, PyObject *Py_UNUSED(ignored)) ++filter_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) + { ++ filterobject *lz = _filterobject_CAST(self); + return Py_BuildValue("O(OO)", Py_TYPE(lz), lz->func, lz->it); + } + + PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); + + static PyMethodDef filter_methods[] = { +- {"__reduce__", _PyCFunction_CAST(filter_reduce), METH_NOARGS, reduce_doc}, ++ {"__reduce__", filter_reduce, METH_NOARGS, reduce_doc}, + {NULL, NULL} /* sentinel */ + }; + +@@ -638,7 +644,7 @@ + sizeof(filterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ +- (destructor)filter_dealloc, /* tp_dealloc */ ++ filter_dealloc, /* tp_dealloc */ + 0, /* tp_vectorcall_offset */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ +@@ -656,12 +662,12 @@ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + filter_doc, /* tp_doc */ +- (traverseproc)filter_traverse, /* tp_traverse */ ++ filter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ +- (iternextfunc)filter_next, /* tp_iternext */ ++ filter_next, /* tp_iternext */ + filter_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ +@@ -674,7 +680,7 @@ + PyType_GenericAlloc, /* tp_alloc */ + filter_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +- .tp_vectorcall = (vectorcallfunc)filter_vectorcall ++ .tp_vectorcall = filter_vectorcall + }; + + +@@ -1319,6 +1325,8 @@ + int strict; + } mapobject; + ++#define _mapobject_CAST(op) ((mapobject *)(op)) ++ + static PyObject * + map_new(PyTypeObject *type, PyObject *args, PyObject *kwds) + { +@@ -1422,8 +1430,9 @@ + } + + static void +-map_dealloc(mapobject *lz) ++map_dealloc(PyObject *self) + { ++ mapobject *lz = _mapobject_CAST(self); + PyObject_GC_UnTrack(lz); + Py_XDECREF(lz->iters); + Py_XDECREF(lz->func); +@@ -1431,16 +1440,18 @@ + } + + static int +-map_traverse(mapobject *lz, visitproc visit, void *arg) ++map_traverse(PyObject *self, visitproc visit, void *arg) + { ++ mapobject *lz = _mapobject_CAST(self); + Py_VISIT(lz->iters); + Py_VISIT(lz->func); + return 0; + } + + static PyObject * +-map_next(mapobject *lz) ++map_next(PyObject *self) + { ++ mapobject *lz = _mapobject_CAST(self); + Py_ssize_t i; + PyObject *small_stack[_PY_FASTCALL_SMALL_STACK]; + PyObject **stack; +@@ -1523,8 +1534,9 @@ + } + + static PyObject * +-map_reduce(mapobject *lz, PyObject *Py_UNUSED(ignored)) ++map_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) + { ++ mapobject *lz = _mapobject_CAST(self); + Py_ssize_t numargs = PyTuple_GET_SIZE(lz->iters); + PyObject *args = PyTuple_New(numargs+1); + Py_ssize_t i; +@@ -1545,19 +1557,20 @@ + PyDoc_STRVAR(setstate_doc, "Set state information for unpickling."); + + static PyObject * +-map_setstate(mapobject *lz, PyObject *state) ++map_setstate(PyObject *self, PyObject *state) + { + int strict = PyObject_IsTrue(state); + if (strict < 0) { + return NULL; + } ++ mapobject *lz = _mapobject_CAST(self); + lz->strict = strict; + Py_RETURN_NONE; + } + + static PyMethodDef map_methods[] = { +- {"__reduce__", _PyCFunction_CAST(map_reduce), METH_NOARGS, reduce_doc}, +- {"__setstate__", _PyCFunction_CAST(map_setstate), METH_O, setstate_doc}, ++ {"__reduce__", map_reduce, METH_NOARGS, reduce_doc}, ++ {"__setstate__", map_setstate, METH_O, setstate_doc}, + {NULL, NULL} /* sentinel */ + }; + +@@ -1578,7 +1591,7 @@ + sizeof(mapobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ +- (destructor)map_dealloc, /* tp_dealloc */ ++ map_dealloc, /* tp_dealloc */ + 0, /* tp_vectorcall_offset */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ +@@ -1596,12 +1609,12 @@ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + map_doc, /* tp_doc */ +- (traverseproc)map_traverse, /* tp_traverse */ ++ map_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ +- (iternextfunc)map_next, /* tp_iternext */ ++ map_next, /* tp_iternext */ + map_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ +@@ -1614,7 +1627,7 @@ + PyType_GenericAlloc, /* tp_alloc */ + map_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +- .tp_vectorcall = (vectorcallfunc)map_vectorcall ++ .tp_vectorcall = map_vectorcall + }; + + +@@ -2965,6 +2978,8 @@ + int strict; + } zipobject; + ++#define _zipobject_CAST(op) ((zipobject *)(op)) ++ + static PyObject * + zip_new(PyTypeObject *type, PyObject *args, PyObject *kwds) + { +@@ -3033,8 +3048,9 @@ + } + + static void +-zip_dealloc(zipobject *lz) ++zip_dealloc(PyObject *self) + { ++ zipobject *lz = _zipobject_CAST(self); + PyObject_GC_UnTrack(lz); + Py_XDECREF(lz->ittuple); + Py_XDECREF(lz->result); +@@ -3042,16 +3058,19 @@ + } + + static int +-zip_traverse(zipobject *lz, visitproc visit, void *arg) ++zip_traverse(PyObject *self, visitproc visit, void *arg) + { ++ zipobject *lz = _zipobject_CAST(self); + Py_VISIT(lz->ittuple); + Py_VISIT(lz->result); + return 0; + } + + static PyObject * +-zip_next(zipobject *lz) ++zip_next(PyObject *self) + { ++ zipobject *lz = _zipobject_CAST(self); ++ + Py_ssize_t i; + Py_ssize_t tuplesize = lz->tuplesize; + PyObject *result = lz->result; +@@ -3141,8 +3160,9 @@ + } + + static PyObject * +-zip_reduce(zipobject *lz, PyObject *Py_UNUSED(ignored)) ++zip_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) + { ++ zipobject *lz = _zipobject_CAST(self); + /* Just recreate the zip with the internal iterator tuple */ + if (lz->strict) { + return PyTuple_Pack(3, Py_TYPE(lz), lz->ittuple, Py_True); +@@ -3151,19 +3171,20 @@ + } + + static PyObject * +-zip_setstate(zipobject *lz, PyObject *state) ++zip_setstate(PyObject *self, PyObject *state) + { + int strict = PyObject_IsTrue(state); + if (strict < 0) { + return NULL; + } ++ zipobject *lz = _zipobject_CAST(self); + lz->strict = strict; + Py_RETURN_NONE; + } + + static PyMethodDef zip_methods[] = { +- {"__reduce__", _PyCFunction_CAST(zip_reduce), METH_NOARGS, reduce_doc}, +- {"__setstate__", _PyCFunction_CAST(zip_setstate), METH_O, setstate_doc}, ++ {"__reduce__", zip_reduce, METH_NOARGS, reduce_doc}, ++ {"__setstate__", zip_setstate, METH_O, setstate_doc}, + {NULL} /* sentinel */ + }; + +@@ -3188,7 +3209,7 @@ + sizeof(zipobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ +- (destructor)zip_dealloc, /* tp_dealloc */ ++ zip_dealloc, /* tp_dealloc */ + 0, /* tp_vectorcall_offset */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ +@@ -3206,12 +3227,12 @@ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + zip_doc, /* tp_doc */ +- (traverseproc)zip_traverse, /* tp_traverse */ ++ zip_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ +- (iternextfunc)zip_next, /* tp_iternext */ ++ zip_next, /* tp_iternext */ + zip_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ +diff --git a/Python/bytecodes.c b/Python/bytecodes.c +index 772b46d17ec..703d7ec61eb 100644 +--- a/Python/bytecodes.c ++++ b/Python/bytecodes.c +@@ -45,7 +45,6 @@ + #include "ceval_macros.h" + + /* Flow control macros */ +-#define GO_TO_INSTRUCTION(instname) ((void)0) + + #define inst(name, ...) case name: + #define op(name, ...) /* NAME is ignored */ +@@ -53,6 +52,7 @@ + #define super(name) static int SUPER_##name + #define family(name, ...) static int family_##name + #define pseudo(name) static int pseudo_##name ++#define label(name) name: + + /* Annotations */ + #define guard +@@ -60,6 +60,8 @@ + #define specializing + #define split + #define replicate(TIMES) ++#define tier1 ++#define no_save_ip + + // Dummy variables for stack effects. + static PyObject *value, *value1, *value2, *left, *right, *res, *sum, *prod, *sub; +@@ -101,7 +103,6 @@ + PyObject *codeobj; + PyObject *cond; + PyObject *descr; +- _PyInterpreterFrame entry_frame; + PyObject *exc; + PyObject *exit; + PyObject *fget; +@@ -148,6 +149,8 @@ + RESUME_CHECK, + }; + ++ macro(NOT_TAKEN) = NOP; ++ + op(_CHECK_PERIODIC, (--)) { + _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); + QSBR_QUIESCENT_STATE(tstate); +@@ -269,7 +272,6 @@ + + inst(LOAD_FAST_AND_CLEAR, (-- value)) { + value = GETLOCAL(oparg); +- // do not use SETLOCAL here, it decrefs the old value + GETLOCAL(oparg) = PyStackRef_NULL; + } + +@@ -281,11 +283,35 @@ + } + + family(LOAD_CONST, 0) = { ++ LOAD_CONST_MORTAL, + LOAD_CONST_IMMORTAL, + }; + +- pure inst(LOAD_CONST, (-- value)) { +- value = PyStackRef_FromPyObjectNew(GETITEM(FRAME_CO_CONSTS, oparg)); ++ inst(LOAD_CONST, (-- value)) { ++ /* We can't do this in the bytecode compiler as ++ * marshalling can intern strings and make them immortal. */ ++ PyObject *obj = GETITEM(FRAME_CO_CONSTS, oparg); ++ value = PyStackRef_FromPyObjectNew(obj); ++#if ENABLE_SPECIALIZATION_FT ++#ifdef Py_GIL_DISABLED ++ uint8_t expected = LOAD_CONST; ++ if (!_Py_atomic_compare_exchange_uint8( ++ &this_instr->op.code, &expected, ++ _Py_IsImmortal(obj) ? LOAD_CONST_IMMORTAL : LOAD_CONST_MORTAL)) { ++ // We might lose a race with instrumentation, which we don't care about. ++ assert(expected >= MIN_INSTRUMENTED_OPCODE); ++ } ++#else ++ if (this_instr->op.code == LOAD_CONST) { ++ this_instr->op.code = _Py_IsImmortal(obj) ? LOAD_CONST_IMMORTAL : LOAD_CONST_MORTAL; ++ } ++#endif ++#endif ++ } ++ ++ inst(LOAD_CONST_MORTAL, (-- value)) { ++ PyObject *obj = GETITEM(FRAME_CO_CONSTS, oparg); ++ value = PyStackRef_FromPyObjectNew(obj); + } + + inst(LOAD_CONST_IMMORTAL, (-- value)) { +@@ -301,8 +327,10 @@ + } + + replicate(8) inst(STORE_FAST, (value --)) { +- SETLOCAL(oparg, value); ++ _PyStackRef tmp = GETLOCAL(oparg); ++ GETLOCAL(oparg) = value; + DEAD(value); ++ PyStackRef_XCLOSE(tmp); + } + + pseudo(STORE_FAST_MAYBE_NULL, (unused --)) = { +@@ -312,18 +340,24 @@ + inst(STORE_FAST_LOAD_FAST, (value1 -- value2)) { + uint32_t oparg1 = oparg >> 4; + uint32_t oparg2 = oparg & 15; +- SETLOCAL(oparg1, value1); ++ _PyStackRef tmp = GETLOCAL(oparg1); ++ GETLOCAL(oparg1) = value1; + DEAD(value1); + value2 = PyStackRef_DUP(GETLOCAL(oparg2)); ++ PyStackRef_XCLOSE(tmp); + } + + inst(STORE_FAST_STORE_FAST, (value2, value1 --)) { + uint32_t oparg1 = oparg >> 4; + uint32_t oparg2 = oparg & 15; +- SETLOCAL(oparg1, value1); ++ _PyStackRef tmp = GETLOCAL(oparg1); ++ GETLOCAL(oparg1) = value1; + DEAD(value1); +- SETLOCAL(oparg2, value2); ++ PyStackRef_XCLOSE(tmp); ++ tmp = GETLOCAL(oparg2); ++ GETLOCAL(oparg2) = value2; + DEAD(value2); ++ PyStackRef_XCLOSE(tmp); + } + + pure inst(POP_TOP, (value --)) { +@@ -334,9 +368,18 @@ + res = PyStackRef_NULL; + } + +- macro(END_FOR) = POP_TOP; ++ no_save_ip inst(END_FOR, (value -- )) { ++ /* Don't update instr_ptr, so that POP_ITER sees ++ * the FOR_ITER as the previous instruction. ++ * This has the benign side effect that if value is ++ * finalized it will see the location as the FOR_ITER's. ++ */ ++ PyStackRef_CLOSE(value); ++ } ++ ++ macro(POP_ITER) = POP_TOP; + +- tier1 inst(INSTRUMENTED_END_FOR, (receiver, value -- receiver)) { ++ no_save_ip tier1 inst(INSTRUMENTED_END_FOR, (receiver, value -- receiver)) { + /* Need to create a fake StopIteration error here, + * to conform to PEP 380 */ + if (PyStackRef_GenCheck(receiver)) { +@@ -348,11 +391,16 @@ + DECREF_INPUTS(); + } + ++ tier1 inst(INSTRUMENTED_POP_ITER, (iter -- )) { ++ INSTRUMENTED_JUMP(prev_instr, this_instr+1, PY_MONITORING_EVENT_BRANCH_RIGHT); ++ PyStackRef_CLOSE(iter); ++ } ++ + pure inst(END_SEND, (receiver, value -- val)) { + (void)receiver; + val = value; + DEAD(value); +- PyStackRef_CLOSE(receiver); ++ DECREF_INPUTS(); + } + + tier1 inst(INSTRUMENTED_END_SEND, (receiver, value -- val)) { +@@ -489,7 +537,13 @@ + BINARY_OP_ADD_FLOAT, + BINARY_OP_SUBTRACT_FLOAT, + BINARY_OP_ADD_UNICODE, ++ BINARY_OP_SUBSCR_LIST_INT, ++ BINARY_OP_SUBSCR_TUPLE_INT, ++ BINARY_OP_SUBSCR_STR_INT, ++ BINARY_OP_SUBSCR_DICT, ++ BINARY_OP_SUBSCR_GETITEM, + // BINARY_OP_INPLACE_ADD_UNICODE, // See comments at that opcode. ++ BINARY_OP_EXTEND, + }; + + op(_GUARD_BOTH_INT, (left, right -- left, right)) { +@@ -512,6 +566,8 @@ + pure op(_BINARY_OP_MULTIPLY_INT, (left, right -- res)) { + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(PyLong_CheckExact(left_o)); ++ assert(PyLong_CheckExact(right_o)); + + STAT_INC(BINARY_OP, hit); + PyObject *res_o = _PyLong_Multiply((PyLongObject *)left_o, (PyLongObject *)right_o); +@@ -525,6 +581,8 @@ + pure op(_BINARY_OP_ADD_INT, (left, right -- res)) { + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(PyLong_CheckExact(left_o)); ++ assert(PyLong_CheckExact(right_o)); + + STAT_INC(BINARY_OP, hit); + PyObject *res_o = _PyLong_Add((PyLongObject *)left_o, (PyLongObject *)right_o); +@@ -538,6 +596,8 @@ + pure op(_BINARY_OP_SUBTRACT_INT, (left, right -- res)) { + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(PyLong_CheckExact(left_o)); ++ assert(PyLong_CheckExact(right_o)); + + STAT_INC(BINARY_OP, hit); + PyObject *res_o = _PyLong_Subtract((PyLongObject *)left_o, (PyLongObject *)right_o); +@@ -549,11 +609,11 @@ + } + + macro(BINARY_OP_MULTIPLY_INT) = +- _GUARD_BOTH_INT + unused/1 + _BINARY_OP_MULTIPLY_INT; ++ _GUARD_BOTH_INT + unused/5 + _BINARY_OP_MULTIPLY_INT; + macro(BINARY_OP_ADD_INT) = +- _GUARD_BOTH_INT + unused/1 + _BINARY_OP_ADD_INT; ++ _GUARD_BOTH_INT + unused/5 + _BINARY_OP_ADD_INT; + macro(BINARY_OP_SUBTRACT_INT) = +- _GUARD_BOTH_INT + unused/1 + _BINARY_OP_SUBTRACT_INT; ++ _GUARD_BOTH_INT + unused/5 + _BINARY_OP_SUBTRACT_INT; + + op(_GUARD_BOTH_FLOAT, (left, right -- left, right)) { + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); +@@ -575,6 +635,8 @@ + pure op(_BINARY_OP_MULTIPLY_FLOAT, (left, right -- res)) { + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(PyFloat_CheckExact(left_o)); ++ assert(PyFloat_CheckExact(right_o)); + + STAT_INC(BINARY_OP, hit); + double dres = +@@ -589,6 +651,8 @@ + pure op(_BINARY_OP_ADD_FLOAT, (left, right -- res)) { + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(PyFloat_CheckExact(left_o)); ++ assert(PyFloat_CheckExact(right_o)); + + STAT_INC(BINARY_OP, hit); + double dres = +@@ -603,6 +667,8 @@ + pure op(_BINARY_OP_SUBTRACT_FLOAT, (left, right -- res)) { + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(PyFloat_CheckExact(left_o)); ++ assert(PyFloat_CheckExact(right_o)); + + STAT_INC(BINARY_OP, hit); + double dres = +@@ -615,11 +681,11 @@ + } + + macro(BINARY_OP_MULTIPLY_FLOAT) = +- _GUARD_BOTH_FLOAT + unused/1 + _BINARY_OP_MULTIPLY_FLOAT; ++ _GUARD_BOTH_FLOAT + unused/5 + _BINARY_OP_MULTIPLY_FLOAT; + macro(BINARY_OP_ADD_FLOAT) = +- _GUARD_BOTH_FLOAT + unused/1 + _BINARY_OP_ADD_FLOAT; ++ _GUARD_BOTH_FLOAT + unused/5 + _BINARY_OP_ADD_FLOAT; + macro(BINARY_OP_SUBTRACT_FLOAT) = +- _GUARD_BOTH_FLOAT + unused/1 + _BINARY_OP_SUBTRACT_FLOAT; ++ _GUARD_BOTH_FLOAT + unused/5 + _BINARY_OP_SUBTRACT_FLOAT; + + op(_GUARD_BOTH_UNICODE, (left, right -- left, right)) { + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); +@@ -632,18 +698,20 @@ + pure op(_BINARY_OP_ADD_UNICODE, (left, right -- res)) { + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(PyUnicode_CheckExact(left_o)); ++ assert(PyUnicode_CheckExact(right_o)); + + STAT_INC(BINARY_OP, hit); + PyObject *res_o = PyUnicode_Concat(left_o, right_o); +- PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); ++ PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); + INPUTS_DEAD(); + ERROR_IF(res_o == NULL, error); + res = PyStackRef_FromPyObjectSteal(res_o); + } + + macro(BINARY_OP_ADD_UNICODE) = +- _GUARD_BOTH_UNICODE + unused/1 + _BINARY_OP_ADD_UNICODE; ++ _GUARD_BOTH_UNICODE + unused/5 + _BINARY_OP_ADD_UNICODE; + + // This is a subtle one. It's a super-instruction for + // BINARY_OP_ADD_UNICODE followed by STORE_FAST +@@ -654,6 +722,8 @@ + op(_BINARY_OP_INPLACE_ADD_UNICODE, (left, right --)) { + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(PyUnicode_CheckExact(left_o)); ++ assert(PyUnicode_CheckExact(right_o)); + + int next_oparg; + #if TIER_ONE +@@ -677,9 +747,9 @@ + * that the string is safe to mutate. + */ + assert(Py_REFCNT(left_o) >= 2); +- PyStackRef_CLOSE(left); ++ PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); + DEAD(left); +- PyObject *temp = PyStackRef_AsPyObjectBorrow(*target_local); ++ PyObject *temp = PyStackRef_AsPyObjectSteal(*target_local); + PyUnicode_Append(&temp, right_o); + *target_local = PyStackRef_FromPyObjectSteal(temp); + PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); +@@ -693,41 +763,34 @@ + #endif + } + +- macro(BINARY_OP_INPLACE_ADD_UNICODE) = +- _GUARD_BOTH_UNICODE + unused/1 + _BINARY_OP_INPLACE_ADD_UNICODE; +- +- family(BINARY_SUBSCR, INLINE_CACHE_ENTRIES_BINARY_SUBSCR) = { +- BINARY_SUBSCR_DICT, +- BINARY_SUBSCR_GETITEM, +- BINARY_SUBSCR_LIST_INT, +- BINARY_SUBSCR_STR_INT, +- BINARY_SUBSCR_TUPLE_INT, +- }; +- +- specializing op(_SPECIALIZE_BINARY_SUBSCR, (counter/1, container, sub -- container, sub)) { +- #if ENABLE_SPECIALIZATION_FT +- assert(frame->stackpointer == NULL); +- if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { +- next_instr = this_instr; +- _Py_Specialize_BinarySubscr(container, sub, next_instr); +- DISPATCH_SAME_OPARG(); +- } +- OPCODE_DEFERRED_INC(BINARY_SUBSCR); +- ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); +- #endif /* ENABLE_SPECIALIZATION_FT */ ++ op(_GUARD_BINARY_OP_EXTEND, (descr/4, left, right -- left, right)) { ++ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); ++ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ _PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr; ++ assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5); ++ assert(d && d->guard); ++ int res = d->guard(left_o, right_o); ++ DEOPT_IF(!res); + } + +- op(_BINARY_SUBSCR, (container, sub -- res)) { +- PyObject *container_o = PyStackRef_AsPyObjectBorrow(container); +- PyObject *sub_o = PyStackRef_AsPyObjectBorrow(sub); ++ pure op(_BINARY_OP_EXTEND, (descr/4, left, right -- res)) { ++ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); ++ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5); ++ _PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr; ++ ++ STAT_INC(BINARY_OP, hit); + +- PyObject *res_o = PyObject_GetItem(container_o, sub_o); ++ PyObject *res_o = d->action(left_o, right_o); + DECREF_INPUTS(); +- ERROR_IF(res_o == NULL, error); + res = PyStackRef_FromPyObjectSteal(res_o); + } + +- macro(BINARY_SUBSCR) = _SPECIALIZE_BINARY_SUBSCR + _BINARY_SUBSCR; ++ macro(BINARY_OP_EXTEND) = ++ unused/1 + _GUARD_BINARY_OP_EXTEND + rewind/-4 + _BINARY_OP_EXTEND; ++ ++ macro(BINARY_OP_INPLACE_ADD_UNICODE) = ++ _GUARD_BOTH_UNICODE + unused/5 + _BINARY_OP_INPLACE_ADD_UNICODE; + + specializing op(_SPECIALIZE_BINARY_SLICE, (container, start, stop -- container, start, stop)) { + // Placeholder until we implement BINARY_SLICE specialization +@@ -774,14 +837,13 @@ + err = PyObject_SetItem(PyStackRef_AsPyObjectBorrow(container), slice, PyStackRef_AsPyObjectBorrow(v)); + Py_DECREF(slice); + } +- PyStackRef_CLOSE(v); +- PyStackRef_CLOSE(container); ++ DECREF_INPUTS(); + ERROR_IF(err, error); + } + + macro(STORE_SLICE) = _SPECIALIZE_STORE_SLICE + _STORE_SLICE; + +- inst(BINARY_SUBSCR_LIST_INT, (unused/1, list_st, sub_st -- res)) { ++ inst(BINARY_OP_SUBSCR_LIST_INT, (unused/5, list_st, sub_st -- res)) { + PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); + PyObject *list = PyStackRef_AsPyObjectBorrow(list_st); + +@@ -794,10 +856,10 @@ + #ifdef Py_GIL_DISABLED + PyObject *res_o = _PyList_GetItemRef((PyListObject*)list, index); + DEOPT_IF(res_o == NULL); +- STAT_INC(BINARY_SUBSCR, hit); ++ STAT_INC(BINARY_OP, hit); + #else + DEOPT_IF(index >= PyList_GET_SIZE(list)); +- STAT_INC(BINARY_SUBSCR, hit); ++ STAT_INC(BINARY_OP, hit); + PyObject *res_o = PyList_GET_ITEM(list, index); + assert(res_o != NULL); + Py_INCREF(res_o); +@@ -808,7 +870,7 @@ + res = PyStackRef_FromPyObjectSteal(res_o); + } + +- inst(BINARY_SUBSCR_STR_INT, (unused/1, str_st, sub_st -- res)) { ++ inst(BINARY_OP_SUBSCR_STR_INT, (unused/5, str_st, sub_st -- res)) { + PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); + PyObject *str = PyStackRef_AsPyObjectBorrow(str_st); + +@@ -820,7 +882,7 @@ + // Specialize for reading an ASCII character from any string: + Py_UCS4 c = PyUnicode_READ_CHAR(str, index); + DEOPT_IF(Py_ARRAY_LENGTH(_Py_SINGLETON(strings).ascii) <= c); +- STAT_INC(BINARY_SUBSCR, hit); ++ STAT_INC(BINARY_OP, hit); + PyObject *res_o = (PyObject*)&_Py_SINGLETON(strings).ascii[c]; + PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); + DEAD(sub_st); +@@ -828,7 +890,7 @@ + res = PyStackRef_FromPyObjectSteal(res_o); + } + +- inst(BINARY_SUBSCR_TUPLE_INT, (unused/1, tuple_st, sub_st -- res)) { ++ inst(BINARY_OP_SUBSCR_TUPLE_INT, (unused/5, tuple_st, sub_st -- res)) { + PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); + PyObject *tuple = PyStackRef_AsPyObjectBorrow(tuple_st); + +@@ -839,7 +901,7 @@ + DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub)); + Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; + DEOPT_IF(index >= PyTuple_GET_SIZE(tuple)); +- STAT_INC(BINARY_SUBSCR, hit); ++ STAT_INC(BINARY_OP, hit); + PyObject *res_o = PyTuple_GET_ITEM(tuple, index); + assert(res_o != NULL); + Py_INCREF(res_o); +@@ -849,12 +911,12 @@ + res = PyStackRef_FromPyObjectSteal(res_o); + } + +- inst(BINARY_SUBSCR_DICT, (unused/1, dict_st, sub_st -- res)) { ++ inst(BINARY_OP_SUBSCR_DICT, (unused/5, dict_st, sub_st -- res)) { + PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); + PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st); + + DEOPT_IF(!PyDict_CheckExact(dict)); +- STAT_INC(BINARY_SUBSCR, hit); ++ STAT_INC(BINARY_OP, hit); + PyObject *res_o; + int rc = PyDict_GetItemRef(dict, sub, &res_o); + if (rc == 0) { +@@ -865,37 +927,35 @@ + res = PyStackRef_FromPyObjectSteal(res_o); + } + +- op(_BINARY_SUBSCR_CHECK_FUNC, (container, unused -- container, unused)) { ++ op(_BINARY_OP_SUBSCR_CHECK_FUNC, (container, unused -- container, unused, getitem)) { + PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(container)); + DEOPT_IF(!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)); + PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; +- PyObject *getitem = ht->_spec_cache.getitem; +- DEOPT_IF(getitem == NULL); +- assert(PyFunction_Check(getitem)); +- uint32_t cached_version = ht->_spec_cache.getitem_version; +- DEOPT_IF(((PyFunctionObject *)getitem)->func_version != cached_version); +- PyCodeObject *code = (PyCodeObject *)PyFunction_GET_CODE(getitem); ++ PyObject *getitem_o = FT_ATOMIC_LOAD_PTR_ACQUIRE(ht->_spec_cache.getitem); ++ DEOPT_IF(getitem_o == NULL); ++ assert(PyFunction_Check(getitem_o)); ++ uint32_t cached_version = FT_ATOMIC_LOAD_UINT32_RELAXED(ht->_spec_cache.getitem_version); ++ DEOPT_IF(((PyFunctionObject *)getitem_o)->func_version != cached_version); ++ PyCodeObject *code = (PyCodeObject *)PyFunction_GET_CODE(getitem_o); + assert(code->co_argcount == 2); + DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize)); +- STAT_INC(BINARY_SUBSCR, hit); ++ getitem = PyStackRef_FromPyObjectNew(getitem_o); ++ STAT_INC(BINARY_OP, hit); + } + +- op(_BINARY_SUBSCR_INIT_CALL, (container, sub -- new_frame: _PyInterpreterFrame* )) { +- PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(container)); +- PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; +- PyObject *getitem = ht->_spec_cache.getitem; +- new_frame = _PyFrame_PushUnchecked(tstate, PyStackRef_FromPyObjectNew(getitem), 2, frame); ++ op(_BINARY_OP_SUBSCR_INIT_CALL, (container, sub, getitem -- new_frame: _PyInterpreterFrame* )) { ++ new_frame = _PyFrame_PushUnchecked(tstate, getitem, 2, frame); + new_frame->localsplus[0] = container; + new_frame->localsplus[1] = sub; + INPUTS_DEAD(); + frame->return_offset = INSTRUCTION_SIZE; + } + +- macro(BINARY_SUBSCR_GETITEM) = +- unused/1 + // Skip over the counter ++ macro(BINARY_OP_SUBSCR_GETITEM) = ++ unused/5 + // Skip over the counter and cache + _CHECK_PEP_523 + +- _BINARY_SUBSCR_CHECK_FUNC + +- _BINARY_SUBSCR_INIT_CALL + ++ _BINARY_OP_SUBSCR_CHECK_FUNC + ++ _BINARY_OP_SUBSCR_INIT_CALL + + _PUSH_FRAME; + + inst(LIST_APPEND, (list, unused[oparg-1], v -- list, unused[oparg-1])) { +@@ -959,10 +1019,10 @@ + PyList_SET_ITEM(list, index, PyStackRef_AsPyObjectSteal(value)); + assert(old_value != NULL); + UNLOCK_OBJECT(list); // unlock before decrefs! +- Py_DECREF(old_value); + PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); + DEAD(sub_st); + PyStackRef_CLOSE(list_st); ++ Py_DECREF(old_value); + } + + inst(STORE_SUBSCR_DICT, (unused/1, value, dict_st, sub -- )) { +@@ -1018,7 +1078,7 @@ + } + + tier1 inst(INTERPRETER_EXIT, (retval --)) { +- assert(frame == &entry_frame); ++ assert(frame->owner == FRAME_OWNED_BY_INTERPRETER); + assert(_PyFrame_IsIncomplete(frame)); + /* Restore previous frame and return. */ + tstate->current_frame = frame->previous; +@@ -1033,9 +1093,7 @@ + // retval is popped from the stack, but res + // is pushed to a different frame, the callers' frame. + inst(RETURN_VALUE, (retval -- res)) { +- #if TIER_ONE +- assert(frame != &entry_frame); +- #endif ++ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); + _PyStackRef temp = retval; + DEAD(retval); + SAVE_STACK(); +@@ -1133,7 +1191,7 @@ + PyObject *receiver_o = PyStackRef_AsPyObjectBorrow(receiver); + + PyObject *retval_o; +- assert(frame != &entry_frame); ++ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); + if ((tstate->interp->eval_frame == NULL) && + (Py_TYPE(receiver_o) == &PyGen_Type || Py_TYPE(receiver_o) == &PyCoro_Type) && + ((PyGenObject *)receiver_o)->gi_frame_state < FRAME_EXECUTING) +@@ -1206,9 +1264,7 @@ + // NOTE: It's important that YIELD_VALUE never raises an exception! + // The compiler treats any exception raised here as a failed close() + // or throw() call. +- #if TIER_ONE +- assert(frame != &entry_frame); +- #endif ++ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); + frame->instr_ptr++; + PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); + assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); +@@ -1303,7 +1359,9 @@ + + tier1 inst(CLEANUP_THROW, (sub_iter_st, last_sent_val_st, exc_value_st -- none, value)) { + PyObject *exc_value = PyStackRef_AsPyObjectBorrow(exc_value_st); ++ #ifndef Py_TAIL_CALL_INTERP + assert(throwflag); ++ #endif + assert(exc_value && PyExceptionInstance_Check(exc_value)); + + int matches = PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration); +@@ -1467,7 +1525,7 @@ + }; + + specializing op(_SPECIALIZE_STORE_ATTR, (counter/1, owner -- owner)) { +- #if ENABLE_SPECIALIZATION ++ #if ENABLE_SPECIALIZATION_FT + if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + next_instr = this_instr; +@@ -1476,7 +1534,7 @@ + } + OPCODE_DEFERRED_INC(STORE_ATTR); + ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); +- #endif /* ENABLE_SPECIALIZATION */ ++ #endif /* ENABLE_SPECIALIZATION_FT */ + } + + op(_STORE_ATTR, (v, owner --)) { +@@ -1597,10 +1655,13 @@ + } + + // res[1] because we need a pointer to res to pass it to _PyEval_LoadGlobalStackRef +- op(_LOAD_GLOBAL, ( -- res[1], null if (oparg & 1))) { ++ op(_LOAD_GLOBAL, ( -- res[1])) { + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); + _PyEval_LoadGlobalStackRef(GLOBALS(), BUILTINS(), name, res); + ERROR_IF(PyStackRef_IsNull(*res), error); ++ } ++ ++ op(_PUSH_NULL_CONDITIONAL, ( -- null if (oparg & 1))) { + null = PyStackRef_NULL; + } + +@@ -1609,7 +1670,8 @@ + counter/1 + + globals_version/1 + + builtins_version/1 + +- _LOAD_GLOBAL; ++ _LOAD_GLOBAL + ++ _PUSH_NULL_CONDITIONAL; + + op(_GUARD_GLOBALS_VERSION, (version/1 --)) { + PyDictObject *dict = (PyDictObject *)GLOBALS(); +@@ -1639,7 +1701,7 @@ + assert(DK_IS_UNICODE(builtins_keys)); + } + +- op(_LOAD_GLOBAL_MODULE_FROM_KEYS, (index/1, globals_keys: PyDictKeysObject* -- res, null if (oparg & 1))) { ++ op(_LOAD_GLOBAL_MODULE_FROM_KEYS, (index/1, globals_keys: PyDictKeysObject* -- res)) { + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(globals_keys); + PyObject *res_o = FT_ATOMIC_LOAD_PTR_RELAXED(entries[index].me_value); + DEAD(globals_keys); +@@ -1653,10 +1715,9 @@ + res = PyStackRef_FromPyObjectSteal(res_o); + #endif + STAT_INC(LOAD_GLOBAL, hit); +- null = PyStackRef_NULL; + } + +- op(_LOAD_GLOBAL_BUILTINS_FROM_KEYS, (index/1, builtins_keys: PyDictKeysObject* -- res, null if (oparg & 1))) { ++ op(_LOAD_GLOBAL_BUILTINS_FROM_KEYS, (index/1, builtins_keys: PyDictKeysObject* -- res)) { + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(builtins_keys); + PyObject *res_o = FT_ATOMIC_LOAD_PTR_RELAXED(entries[index].me_value); + DEAD(builtins_keys); +@@ -1670,20 +1731,21 @@ + res = PyStackRef_FromPyObjectSteal(res_o); + #endif + STAT_INC(LOAD_GLOBAL, hit); +- null = PyStackRef_NULL; + } + + macro(LOAD_GLOBAL_MODULE) = + unused/1 + // Skip over the counter + _GUARD_GLOBALS_VERSION_PUSH_KEYS + + unused/1 + // Skip over the builtins version +- _LOAD_GLOBAL_MODULE_FROM_KEYS; ++ _LOAD_GLOBAL_MODULE_FROM_KEYS + ++ _PUSH_NULL_CONDITIONAL; + + macro(LOAD_GLOBAL_BUILTIN) = + unused/1 + // Skip over the counter + _GUARD_GLOBALS_VERSION + + _GUARD_BUILTINS_VERSION_PUSH_KEYS + +- _LOAD_GLOBAL_BUILTINS_FROM_KEYS; ++ _LOAD_GLOBAL_BUILTINS_FROM_KEYS + ++ _PUSH_NULL_CONDITIONAL; + + inst(DELETE_FAST, (--)) { + _PyStackRef v = GETLOCAL(oparg); +@@ -1694,7 +1756,9 @@ + ); + ERROR_IF(1, error); + } +- SETLOCAL(oparg, PyStackRef_NULL); ++ _PyStackRef tmp = GETLOCAL(oparg); ++ GETLOCAL(oparg) = PyStackRef_NULL; ++ PyStackRef_XCLOSE(tmp); + } + + inst(MAKE_CELL, (--)) { +@@ -1705,7 +1769,9 @@ + if (cell == NULL) { + ERROR_NO_POP(); + } +- SETLOCAL(oparg, PyStackRef_FromPyObjectSteal(cell)); ++ _PyStackRef tmp = GETLOCAL(oparg); ++ GETLOCAL(oparg) = PyStackRef_FromPyObjectSteal(cell); ++ PyStackRef_XCLOSE(tmp); + } + + inst(DELETE_DEREF, (--)) { +@@ -1787,16 +1853,20 @@ + } + + inst(BUILD_TUPLE, (values[oparg] -- tup)) { +- PyObject *tup_o = _PyTuple_FromStackRefSteal(values, oparg); ++ PyObject *tup_o = _PyTuple_FromStackRefStealOnSuccess(values, oparg); ++ if (tup_o == NULL) { ++ ERROR_NO_POP(); ++ } + INPUTS_DEAD(); +- ERROR_IF(tup_o == NULL, error); + tup = PyStackRef_FromPyObjectSteal(tup_o); + } + + inst(BUILD_LIST, (values[oparg] -- list)) { +- PyObject *list_o = _PyList_FromStackRefSteal(values, oparg); ++ PyObject *list_o = _PyList_FromStackRefStealOnSuccess(values, oparg); ++ if (list_o == NULL) { ++ ERROR_NO_POP(); ++ } + INPUTS_DEAD(); +- ERROR_IF(list_o == NULL, error); + list = PyStackRef_FromPyObjectSteal(list_o); + } + +@@ -1840,9 +1910,8 @@ + if (err == 0) { + err = PySet_Add(set_o, PyStackRef_AsPyObjectBorrow(values[i])); + } +- PyStackRef_CLOSE(values[i]); + } +- DEAD(values); ++ DECREF_INPUTS(); + if (err != 0) { + Py_DECREF(set_o); + ERROR_IF(true, error); +@@ -1934,12 +2003,10 @@ + ERROR_IF(err != 0, error); + } + +- inst(INSTRUMENTED_LOAD_SUPER_ATTR, (unused/1 -- )) { +- // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we +- // don't want to specialize instrumented instructions +- PAUSE_ADAPTIVE_COUNTER(this_instr[1].counter); +- GO_TO_INSTRUCTION(LOAD_SUPER_ATTR); +- } ++ macro(INSTRUMENTED_LOAD_SUPER_ATTR) = ++ counter/1 + ++ _LOAD_SUPER_ATTR + ++ _PUSH_NULL_CONDITIONAL; + + family(LOAD_SUPER_ATTR, INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR) = { + LOAD_SUPER_ATTR_ATTR, +@@ -1959,7 +2026,7 @@ + #endif /* ENABLE_SPECIALIZATION_FT */ + } + +- tier1 op(_LOAD_SUPER_ATTR, (global_super_st, class_st, self_st -- attr, null if (oparg & 1))) { ++ tier1 op(_LOAD_SUPER_ATTR, (global_super_st, class_st, self_st -- attr)) { + PyObject *global_super = PyStackRef_AsPyObjectBorrow(global_super_st); + PyObject *class = PyStackRef_AsPyObjectBorrow(class_st); + PyObject *self = PyStackRef_AsPyObjectBorrow(self_st); +@@ -2001,12 +2068,14 @@ + Py_DECREF(super); + ERROR_IF(attr_o == NULL, error); + attr = PyStackRef_FromPyObjectSteal(attr_o); +- null = PyStackRef_NULL; + } + +- macro(LOAD_SUPER_ATTR) = _SPECIALIZE_LOAD_SUPER_ATTR + _LOAD_SUPER_ATTR; ++ macro(LOAD_SUPER_ATTR) = ++ _SPECIALIZE_LOAD_SUPER_ATTR + ++ _LOAD_SUPER_ATTR + ++ _PUSH_NULL_CONDITIONAL; + +- inst(LOAD_SUPER_ATTR_ATTR, (unused/1, global_super_st, class_st, self_st -- attr_st, unused if (0))) { ++ inst(LOAD_SUPER_ATTR_ATTR, (unused/1, global_super_st, class_st, self_st -- attr_st)) { + PyObject *global_super = PyStackRef_AsPyObjectBorrow(global_super_st); + PyObject *class = PyStackRef_AsPyObjectBorrow(class_st); + PyObject *self = PyStackRef_AsPyObjectBorrow(self_st); +@@ -2036,11 +2105,8 @@ + int method_found = 0; + PyObject *attr_o = _PySuper_Lookup(cls, self, name, + Py_TYPE(self)->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL); +- PyStackRef_CLOSE(global_super_st); +- PyStackRef_CLOSE(class_st); + if (attr_o == NULL) { +- PyStackRef_CLOSE(self_st); +- ERROR_IF(true, error); ++ ERROR_NO_POP(); + } + if (method_found) { + self_or_null = self_st; // transfer ownership +@@ -2049,6 +2115,7 @@ + PyStackRef_CLOSE(self_st); + self_or_null = PyStackRef_NULL; + } ++ DECREF_INPUTS(); + + attr = PyStackRef_FromPyObjectSteal(attr_o); + } +@@ -2082,7 +2149,7 @@ + #endif /* ENABLE_SPECIALIZATION_FT */ + } + +- op(_LOAD_ATTR, (owner -- attr, self_or_null if (oparg & 1))) { ++ op(_LOAD_ATTR, (owner -- attr, self_or_null[oparg&1])) { + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); + PyObject *attr_o; + if (oparg & 1) { +@@ -2095,7 +2162,7 @@ + meth | self | arg1 | ... | argN + */ + assert(attr_o != NULL); // No errors on this branch +- self_or_null = owner; // Transfer ownership ++ self_or_null[0] = owner; // Transfer ownership + DEAD(owner); + } + else { +@@ -2107,7 +2174,7 @@ + */ + DECREF_INPUTS(); + ERROR_IF(attr_o == NULL, error); +- self_or_null = PyStackRef_NULL; ++ self_or_null[0] = PyStackRef_NULL; + } + } + else { +@@ -2115,12 +2182,11 @@ + attr_o = PyObject_GetAttr(PyStackRef_AsPyObjectBorrow(owner), name); + DECREF_INPUTS(); + ERROR_IF(attr_o == NULL, error); +- /* We need to define self_or_null on all paths */ +- self_or_null = PyStackRef_NULL; + } + attr = PyStackRef_FromPyObjectSteal(attr_o); + } + ++ + macro(LOAD_ATTR) = + _SPECIALIZE_LOAD_ATTR + + unused/8 + +@@ -2129,26 +2195,41 @@ + op(_GUARD_TYPE_VERSION, (type_version/2, owner -- owner)) { + PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + assert(type_version != 0); +- EXIT_IF(tp->tp_version_tag != type_version); ++ EXIT_IF(FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version); ++ } ++ ++ op(_GUARD_TYPE_VERSION_AND_LOCK, (type_version/2, owner -- owner)) { ++ PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); ++ assert(type_version != 0); ++ EXIT_IF(!LOCK_OBJECT(owner_o)); ++ PyTypeObject *tp = Py_TYPE(owner_o); ++ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { ++ UNLOCK_OBJECT(owner_o); ++ EXIT_IF(true); ++ } + } + + op(_CHECK_MANAGED_OBJECT_HAS_VALUES, (owner -- owner)) { + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + assert(Py_TYPE(owner_o)->tp_dictoffset < 0); + assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); +- DEOPT_IF(!_PyObject_InlineValues(owner_o)->valid); ++ DEOPT_IF(!FT_ATOMIC_LOAD_UINT8(_PyObject_InlineValues(owner_o)->valid)); + } + +- split op(_LOAD_ATTR_INSTANCE_VALUE, (offset/1, owner -- attr, null if (oparg & 1))) { ++ op(_LOAD_ATTR_INSTANCE_VALUE, (offset/1, owner -- attr)) { + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); +- PyObject *attr_o = *value_ptr; ++ PyObject *attr_o = FT_ATOMIC_LOAD_PTR_ACQUIRE(*value_ptr); + DEOPT_IF(attr_o == NULL); ++ #ifdef Py_GIL_DISABLED ++ if (!_Py_TryIncrefCompareStackRef(value_ptr, attr_o, &attr)) { ++ DEOPT_IF(true); ++ } ++ #else ++ attr = PyStackRef_FromPyObjectNew(attr_o); ++ #endif + STAT_INC(LOAD_ATTR, hit); +- Py_INCREF(attr_o); +- null = PyStackRef_NULL; +- attr = PyStackRef_FromPyObjectSteal(attr_o); +- DECREF_INPUTS(); ++ PyStackRef_CLOSE(owner); + } + + macro(LOAD_ATTR_INSTANCE_VALUE) = +@@ -2156,7 +2237,8 @@ + _GUARD_TYPE_VERSION + + _CHECK_MANAGED_OBJECT_HAS_VALUES + + _LOAD_ATTR_INSTANCE_VALUE + +- unused/5; // Skip over rest of cache ++ unused/5 + ++ _PUSH_NULL_CONDITIONAL; + + op(_CHECK_ATTR_MODULE_PUSH_KEYS, (dict_version/2, owner -- owner, mod_keys: PyDictKeysObject *)) { + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); +@@ -2168,14 +2250,13 @@ + mod_keys = keys; + } + +- op(_LOAD_ATTR_MODULE_FROM_KEYS, (index/1, owner, mod_keys: PyDictKeysObject * -- attr, null if (oparg & 1))) { ++ op(_LOAD_ATTR_MODULE_FROM_KEYS, (index/1, owner, mod_keys: PyDictKeysObject * -- attr)) { + assert(mod_keys->dk_kind == DICT_KEYS_UNICODE); + assert(index < FT_ATOMIC_LOAD_SSIZE_RELAXED(mod_keys->dk_nentries)); + PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(mod_keys) + index; + PyObject *attr_o = FT_ATOMIC_LOAD_PTR_RELAXED(ep->me_value); +- DEAD(mod_keys); + // Clear mod_keys from stack in case we need to deopt +- POP_DEAD_INPUTS(); ++ POP_INPUT(mod_keys); + DEOPT_IF(attr_o == NULL); + #ifdef Py_GIL_DISABLED + int increfed = _Py_TryIncrefCompareStackRef(&ep->me_value, attr_o, &attr); +@@ -2187,7 +2268,6 @@ + attr = PyStackRef_FromPyObjectSteal(attr_o); + #endif + STAT_INC(LOAD_ATTR, hit); +- null = PyStackRef_NULL; + PyStackRef_CLOSE(owner); + } + +@@ -2195,33 +2275,53 @@ + unused/1 + + _CHECK_ATTR_MODULE_PUSH_KEYS + + _LOAD_ATTR_MODULE_FROM_KEYS + +- unused/5; ++ unused/5 + ++ _PUSH_NULL_CONDITIONAL; + +- op(_CHECK_ATTR_WITH_HINT, (owner -- owner)) { ++ op(_CHECK_ATTR_WITH_HINT, (owner -- owner, dict: PyDictObject *)) { + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + + assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_MANAGED_DICT); +- PyDictObject *dict = _PyObject_GetManagedDict(owner_o); +- EXIT_IF(dict == NULL); +- assert(PyDict_CheckExact((PyObject *)dict)); ++ PyDictObject *dict_o = _PyObject_GetManagedDict(owner_o); ++ EXIT_IF(dict_o == NULL); ++ assert(PyDict_CheckExact((PyObject *)dict_o)); ++ dict = dict_o; + } + +- op(_LOAD_ATTR_WITH_HINT, (hint/1, owner -- attr, null if (oparg & 1))) { +- PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); ++ op(_LOAD_ATTR_WITH_HINT, (hint/1, owner, dict: PyDictObject * -- attr)) { + PyObject *attr_o; ++ if (!LOCK_OBJECT(dict)) { ++ POP_INPUT(dict); ++ DEOPT_IF(true); ++ } + +- PyDictObject *dict = _PyObject_GetManagedDict(owner_o); +- DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries); ++ if (hint >= (size_t)dict->ma_keys->dk_nentries) { ++ UNLOCK_OBJECT(dict); ++ POP_INPUT(dict); ++ DEOPT_IF(true); ++ } + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); +- DEOPT_IF(!DK_IS_UNICODE(dict->ma_keys)); ++ if (dict->ma_keys->dk_kind != DICT_KEYS_UNICODE) { ++ UNLOCK_OBJECT(dict); ++ POP_INPUT(dict); ++ DEOPT_IF(true); ++ } + PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; +- DEOPT_IF(ep->me_key != name); ++ if (ep->me_key != name) { ++ UNLOCK_OBJECT(dict); ++ POP_INPUT(dict); ++ DEOPT_IF(true); ++ } + attr_o = ep->me_value; +- DEOPT_IF(attr_o == NULL); ++ if (attr_o == NULL) { ++ UNLOCK_OBJECT(dict); ++ POP_INPUT(dict); ++ DEOPT_IF(true); ++ } + STAT_INC(LOAD_ATTR, hit); +- Py_INCREF(attr_o); +- attr = PyStackRef_FromPyObjectSteal(attr_o); +- null = PyStackRef_NULL; ++ attr = PyStackRef_FromPyObjectNew(attr_o); ++ UNLOCK_OBJECT(dict); ++ DEAD(dict); + DECREF_INPUTS(); + } + +@@ -2230,17 +2330,22 @@ + _GUARD_TYPE_VERSION + + _CHECK_ATTR_WITH_HINT + + _LOAD_ATTR_WITH_HINT + +- unused/5; ++ unused/5 + ++ _PUSH_NULL_CONDITIONAL; + +- split op(_LOAD_ATTR_SLOT, (index/1, owner -- attr, null if (oparg & 1))) { ++ op(_LOAD_ATTR_SLOT, (index/1, owner -- attr)) { + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + +- char *addr = (char *)owner_o + index; +- PyObject *attr_o = *(PyObject **)addr; ++ PyObject **addr = (PyObject **)((char *)owner_o + index); ++ PyObject *attr_o = FT_ATOMIC_LOAD_PTR(*addr); + DEOPT_IF(attr_o == NULL); +- STAT_INC(LOAD_ATTR, hit); +- null = PyStackRef_NULL; ++ #ifdef Py_GIL_DISABLED ++ int increfed = _Py_TryIncrefCompareStackRef(addr, attr_o, &attr); ++ DEOPT_IF(!increfed); ++ #else + attr = PyStackRef_FromPyObjectNew(attr_o); ++ #endif ++ STAT_INC(LOAD_ATTR, hit); + DECREF_INPUTS(); + } + +@@ -2248,21 +2353,21 @@ + unused/1 + + _GUARD_TYPE_VERSION + + _LOAD_ATTR_SLOT + // NOTE: This action may also deopt +- unused/5; ++ unused/5 + ++ _PUSH_NULL_CONDITIONAL; + + op(_CHECK_ATTR_CLASS, (type_version/2, owner -- owner)) { + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + + EXIT_IF(!PyType_Check(owner_o)); + assert(type_version != 0); +- EXIT_IF(((PyTypeObject *)owner_o)->tp_version_tag != type_version); ++ EXIT_IF(FT_ATOMIC_LOAD_UINT_RELAXED(((PyTypeObject *)owner_o)->tp_version_tag) != type_version); + } + +- split op(_LOAD_ATTR_CLASS, (descr/4, owner -- attr, null if (oparg & 1))) { ++ op(_LOAD_ATTR_CLASS, (descr/4, owner -- attr)) { + STAT_INC(LOAD_ATTR, hit); + assert(descr != NULL); + attr = PyStackRef_FromPyObjectNew(descr); +- null = PyStackRef_NULL; + DECREF_INPUTS(); + } + +@@ -2270,13 +2375,15 @@ + unused/1 + + _CHECK_ATTR_CLASS + + unused/2 + +- _LOAD_ATTR_CLASS; ++ _LOAD_ATTR_CLASS + ++ _PUSH_NULL_CONDITIONAL; + + macro(LOAD_ATTR_CLASS_WITH_METACLASS_CHECK) = + unused/1 + + _CHECK_ATTR_CLASS + + _GUARD_TYPE_VERSION + +- _LOAD_ATTR_CLASS; ++ _LOAD_ATTR_CLASS + ++ _PUSH_NULL_CONDITIONAL; + + op(_LOAD_ATTR_PROPERTY_FRAME, (fget/4, owner -- new_frame: _PyInterpreterFrame *)) { + assert((oparg & 1) == 0); +@@ -2302,14 +2409,14 @@ + _SAVE_RETURN_OFFSET + + _PUSH_FRAME; + +- inst(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, (unused/1, type_version/2, func_version/2, getattribute/4, owner -- unused, unused if (0))) { ++ inst(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, (unused/1, type_version/2, func_version/2, getattribute/4, owner -- unused)) { + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + + assert((oparg & 1) == 0); + DEOPT_IF(tstate->interp->eval_frame); + PyTypeObject *cls = Py_TYPE(owner_o); + assert(type_version != 0); +- DEOPT_IF(cls->tp_version_tag != type_version); ++ DEOPT_IF(FT_ATOMIC_LOAD_UINT_RELAXED(cls->tp_version_tag) != type_version); + assert(Py_IS_TYPE(getattribute, &PyFunction_Type)); + PyFunctionObject *f = (PyFunctionObject *)getattribute; + assert(func_version != 0); +@@ -2336,8 +2443,11 @@ + + assert(Py_TYPE(owner_o)->tp_dictoffset < 0); + assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); +- EXIT_IF(_PyObject_GetManagedDict(owner_o)); +- EXIT_IF(_PyObject_InlineValues(owner_o)->valid == 0); ++ if (_PyObject_GetManagedDict(owner_o) || ++ !FT_ATOMIC_LOAD_UINT8(_PyObject_InlineValues(owner_o)->valid)) { ++ UNLOCK_OBJECT(owner_o); ++ EXIT_IF(true); ++ } + } + + op(_STORE_ATTR_INSTANCE_VALUE, (offset/1, value, owner --)) { +@@ -2347,21 +2457,20 @@ + assert(_PyObject_GetManagedDict(owner_o) == NULL); + PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); + PyObject *old_value = *value_ptr; +- *value_ptr = PyStackRef_AsPyObjectSteal(value); ++ FT_ATOMIC_STORE_PTR_RELEASE(*value_ptr, PyStackRef_AsPyObjectSteal(value)); + if (old_value == NULL) { + PyDictValues *values = _PyObject_InlineValues(owner_o); + Py_ssize_t index = value_ptr - values->values; + _PyDictValues_AddToInsertionOrder(values, index); + } +- else { +- Py_DECREF(old_value); +- } ++ UNLOCK_OBJECT(owner_o); + PyStackRef_CLOSE(owner); ++ Py_XDECREF(old_value); + } + + macro(STORE_ATTR_INSTANCE_VALUE) = + unused/1 + +- _GUARD_TYPE_VERSION + ++ _GUARD_TYPE_VERSION_AND_LOCK + + _GUARD_DORV_NO_DICT + + _STORE_ATTR_INSTANCE_VALUE; + +@@ -2370,21 +2479,39 @@ + assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_MANAGED_DICT); + PyDictObject *dict = _PyObject_GetManagedDict(owner_o); + DEOPT_IF(dict == NULL); ++ DEOPT_IF(!LOCK_OBJECT(dict)); ++ #ifdef Py_GIL_DISABLED ++ if (dict != _PyObject_GetManagedDict(owner_o)) { ++ UNLOCK_OBJECT(dict); ++ DEOPT_IF(true); ++ } ++ #endif + assert(PyDict_CheckExact((PyObject *)dict)); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); +- DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries); +- DEOPT_IF(!DK_IS_UNICODE(dict->ma_keys)); ++ if (hint >= (size_t)dict->ma_keys->dk_nentries || ++ !DK_IS_UNICODE(dict->ma_keys)) { ++ UNLOCK_OBJECT(dict); ++ DEOPT_IF(true); ++ } + PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; +- DEOPT_IF(ep->me_key != name); ++ if (ep->me_key != name) { ++ UNLOCK_OBJECT(dict); ++ DEOPT_IF(true); ++ } + PyObject *old_value = ep->me_value; +- DEOPT_IF(old_value == NULL); ++ if (old_value == NULL) { ++ UNLOCK_OBJECT(dict); ++ DEOPT_IF(true); ++ } + _PyDict_NotifyEvent(tstate->interp, PyDict_EVENT_MODIFIED, dict, name, PyStackRef_AsPyObjectBorrow(value)); +- ep->me_value = PyStackRef_AsPyObjectSteal(value); ++ FT_ATOMIC_STORE_PTR_RELEASE(ep->me_value, PyStackRef_AsPyObjectSteal(value)); ++ UNLOCK_OBJECT(dict); ++ + // old_value should be DECREFed after GC track checking is done, if not, it could raise a segmentation fault, + // when dict only holds the strong reference to value in ep->me_value. +- Py_XDECREF(old_value); + STAT_INC(STORE_ATTR, hit); + PyStackRef_CLOSE(owner); ++ Py_XDECREF(old_value); + } + + macro(STORE_ATTR_WITH_HINT) = +@@ -2395,12 +2522,14 @@ + op(_STORE_ATTR_SLOT, (index/1, value, owner --)) { + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + ++ DEOPT_IF(!LOCK_OBJECT(owner_o)); + char *addr = (char *)owner_o + index; + STAT_INC(STORE_ATTR, hit); + PyObject *old_value = *(PyObject **)addr; +- *(PyObject **)addr = PyStackRef_AsPyObjectSteal(value); +- Py_XDECREF(old_value); ++ FT_ATOMIC_STORE_PTR_RELEASE(*(PyObject **)addr, PyStackRef_AsPyObjectSteal(value)); ++ UNLOCK_OBJECT(owner_o); + PyStackRef_CLOSE(owner); ++ Py_XDECREF(old_value); + } + + macro(STORE_ATTR_SLOT) = +@@ -2415,7 +2544,7 @@ + }; + + specializing op(_SPECIALIZE_COMPARE_OP, (counter/1, left, right -- left, right)) { +- #if ENABLE_SPECIALIZATION ++ #if ENABLE_SPECIALIZATION_FT + if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { + next_instr = this_instr; + _Py_Specialize_CompareOp(left, right, next_instr, oparg); +@@ -2423,7 +2552,7 @@ + } + OPCODE_DEFERRED_INC(COMPARE_OP); + ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); +- #endif /* ENABLE_SPECIALIZATION */ ++ #endif /* ENABLE_SPECIALIZATION_FT */ + } + + op(_COMPARE_OP, (left, right -- res)) { +@@ -2585,7 +2714,7 @@ + + PyObject *match_o = NULL; + PyObject *rest_o = NULL; +- int res = _PyEval_ExceptionGroupMatch(exc_value, match_type, ++ int res = _PyEval_ExceptionGroupMatch(frame, exc_value, match_type, + &match_o, &rest_o); + DECREF_INPUTS(); + ERROR_IF(res < 0, error); +@@ -2637,13 +2766,26 @@ + JUMPBY(oparg); + } + +- tier1 op(_JUMP_BACKWARD, (the_counter/1 --)) { +- assert(oparg <= INSTR_OFFSET()); +- JUMPBY(-oparg); +- #ifdef _Py_TIER2 +- #if ENABLE_SPECIALIZATION ++ family(JUMP_BACKWARD, 1) = { ++ JUMP_BACKWARD_NO_JIT, ++ JUMP_BACKWARD_JIT, ++ }; ++ ++ tier1 op(_SPECIALIZE_JUMP_BACKWARD, (--)) { ++ #if ENABLE_SPECIALIZATION ++ if (this_instr->op.code == JUMP_BACKWARD) { ++ this_instr->op.code = tstate->interp->jit ? JUMP_BACKWARD_JIT : JUMP_BACKWARD_NO_JIT; ++ // Need to re-dispatch so the warmup counter isn't off by one: ++ next_instr = this_instr; ++ DISPATCH_SAME_OPARG(); ++ } ++ #endif ++ } ++ ++ tier1 op(_JIT, (--)) { ++ #ifdef _Py_TIER2 + _Py_BackoffCounter counter = this_instr[1].counter; +- if (backoff_counter_triggers(counter) && this_instr->op.code == JUMP_BACKWARD) { ++ if (backoff_counter_triggers(counter) && this_instr->op.code == JUMP_BACKWARD_JIT) { + _Py_CODEUNIT *start = this_instr; + /* Back up over EXTENDED_ARGs so optimizer sees the whole instruction */ + while (oparg > 255) { +@@ -2651,7 +2793,7 @@ + start--; + } + _PyExecutorObject *executor; +- int optimized = _PyOptimizer_Optimize(frame, start, stack_pointer, &executor, 0); ++ int optimized = _PyOptimizer_Optimize(frame, start, &executor, 0); + if (optimized <= 0) { + this_instr[1].counter = restart_backoff_counter(counter); + ERROR_IF(optimized < 0, error); +@@ -2666,13 +2808,25 @@ + else { + ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); + } +- #endif /* ENABLE_SPECIALIZATION */ +- #endif /* _Py_TIER2 */ ++ #endif + } + + macro(JUMP_BACKWARD) = ++ unused/1 + ++ _SPECIALIZE_JUMP_BACKWARD + ++ _CHECK_PERIODIC + ++ JUMP_BACKWARD_NO_INTERRUPT; ++ ++ macro(JUMP_BACKWARD_NO_JIT) = ++ unused/1 + + _CHECK_PERIODIC + +- _JUMP_BACKWARD; ++ JUMP_BACKWARD_NO_INTERRUPT; ++ ++ macro(JUMP_BACKWARD_JIT) = ++ unused/1 + ++ _CHECK_PERIODIC + ++ JUMP_BACKWARD_NO_INTERRUPT + ++ _JIT; + + pseudo(JUMP, (--)) = { + JUMP_FORWARD, +@@ -2725,7 +2879,7 @@ + int flag = PyStackRef_IsFalse(cond); + DEAD(cond); + RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); +- JUMPBY(oparg * flag); ++ JUMPBY(flag ? oparg : next_instr->op.code == NOT_TAKEN); + } + + replaced op(_POP_JUMP_IF_TRUE, (cond -- )) { +@@ -2733,7 +2887,7 @@ + int flag = PyStackRef_IsTrue(cond); + DEAD(cond); + RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); +- JUMPBY(oparg * flag); ++ JUMPBY(flag ? oparg : next_instr->op.code == NOT_TAKEN); + } + + op(_IS_NONE, (value -- b)) { +@@ -2761,6 +2915,7 @@ + * generator or coroutine, so we deliberately do not check it here. + * (see bpo-30039). + */ ++ assert(oparg <= INSTR_OFFSET()); + JUMPBY(-oparg); + } + +@@ -2841,7 +2996,6 @@ + else { + /* `iterable` is not a generator. */ + PyObject *iter_o = PyObject_GetIter(iterable_o); +- DEAD(iterable); + if (iter_o == NULL) { + ERROR_NO_POP(); + } +@@ -2891,10 +3045,8 @@ + /* iterator ended normally */ + assert(next_instr[oparg].op.code == END_FOR || + next_instr[oparg].op.code == INSTRUMENTED_END_FOR); +- PyStackRef_CLOSE(iter); +- STACK_SHRINK(1); +- /* Jump forward oparg, then skip following END_FOR and POP_TOP instruction */ +- JUMPBY(oparg + 2); ++ /* Jump forward oparg, then skip following END_FOR */ ++ JUMPBY(oparg + 1); + DISPATCH(); + } + next = PyStackRef_FromPyObjectSteal(next_o); +@@ -2924,14 +3076,14 @@ + + macro(FOR_ITER) = _SPECIALIZE_FOR_ITER + _FOR_ITER; + ++ + inst(INSTRUMENTED_FOR_ITER, (unused/1 -- )) { +- _Py_CODEUNIT *target; + _PyStackRef iter_stackref = TOP(); + PyObject *iter = PyStackRef_AsPyObjectBorrow(iter_stackref); + PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter); + if (next != NULL) { + PUSH(PyStackRef_FromPyObjectSteal(next)); +- target = next_instr; ++ INSTRUMENTED_JUMP(this_instr, next_instr, PY_MONITORING_EVENT_BRANCH_LEFT); + } + else { + if (_PyErr_Occurred(tstate)) { +@@ -2945,14 +3097,12 @@ + /* iterator ended normally */ + assert(next_instr[oparg].op.code == END_FOR || + next_instr[oparg].op.code == INSTRUMENTED_END_FOR); +- STACK_SHRINK(1); +- PyStackRef_CLOSE(iter_stackref); +- /* Skip END_FOR and POP_TOP */ +- target = next_instr + oparg + 2; ++ /* Skip END_FOR */ ++ JUMPBY(oparg + 1); + } +- INSTRUMENTED_JUMP(this_instr, target, PY_MONITORING_EVENT_BRANCH); + } + ++ + op(_ITER_CHECK_LIST, (iter -- iter)) { + EXIT_IF(Py_TYPE(PyStackRef_AsPyObjectBorrow(iter)) != &PyListIter_Type); + } +@@ -2971,10 +3121,8 @@ + Py_DECREF(seq); + } + #endif +- PyStackRef_CLOSE(iter); +- STACK_SHRINK(1); +- /* Jump forward oparg, then skip following END_FOR and POP_TOP instructions */ +- JUMPBY(oparg + 2); ++ /* Jump forward oparg, then skip following END_FOR instruction */ ++ JUMPBY(oparg + 1); + DISPATCH(); + } + } +@@ -3023,10 +3171,8 @@ + it->it_seq = NULL; + Py_DECREF(seq); + } +- PyStackRef_CLOSE(iter); +- STACK_SHRINK(1); +- /* Jump forward oparg, then skip following END_FOR and POP_TOP instructions */ +- JUMPBY(oparg + 2); ++ /* Jump forward oparg, then skip following END_FOR instruction */ ++ JUMPBY(oparg + 1); + DISPATCH(); + } + } +@@ -3067,10 +3213,8 @@ + assert(Py_TYPE(r) == &PyRangeIter_Type); + STAT_INC(FOR_ITER, hit); + if (r->len <= 0) { +- STACK_SHRINK(1); +- PyStackRef_CLOSE(iter); +- // Jump over END_FOR and POP_TOP instructions. +- JUMPBY(oparg + 2); ++ // Jump over END_FOR instruction. ++ JUMPBY(oparg + 1); + DISPATCH(); + } + } +@@ -3216,16 +3360,18 @@ + op(_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, (owner -- owner)) { + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); +- DEOPT_IF(!_PyObject_InlineValues(owner_o)->valid); ++ PyDictValues *ivs = _PyObject_InlineValues(owner_o); ++ DEOPT_IF(!FT_ATOMIC_LOAD_UINT8(ivs->valid)); + } + + op(_GUARD_KEYS_VERSION, (keys_version/2, owner -- owner)) { + PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; +- DEOPT_IF(owner_heap_type->ht_cached_keys->dk_version != keys_version); ++ PyDictKeysObject *keys = owner_heap_type->ht_cached_keys; ++ DEOPT_IF(FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version); + } + +- split op(_LOAD_ATTR_METHOD_WITH_VALUES, (descr/4, owner -- attr, self if (1))) { ++ op(_LOAD_ATTR_METHOD_WITH_VALUES, (descr/4, owner -- attr, self)) { + assert(oparg & 1); + /* Cached method object */ + STAT_INC(LOAD_ATTR, hit); +@@ -3243,7 +3389,7 @@ + _GUARD_KEYS_VERSION + + _LOAD_ATTR_METHOD_WITH_VALUES; + +- op(_LOAD_ATTR_METHOD_NO_DICT, (descr/4, owner -- attr, self if (1))) { ++ op(_LOAD_ATTR_METHOD_NO_DICT, (descr/4, owner -- attr, self)) { + assert(oparg & 1); + assert(Py_TYPE(PyStackRef_AsPyObjectBorrow(owner))->tp_dictoffset == 0); + STAT_INC(LOAD_ATTR, hit); +@@ -3260,7 +3406,7 @@ + unused/2 + + _LOAD_ATTR_METHOD_NO_DICT; + +- op(_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, (descr/4, owner -- attr, unused if (0))) { ++ op(_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, (descr/4, owner -- attr)) { + assert((oparg & 1) == 0); + STAT_INC(LOAD_ATTR, hit); + assert(descr != NULL); +@@ -3275,7 +3421,7 @@ + _GUARD_KEYS_VERSION + + _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES; + +- op(_LOAD_ATTR_NONDESCRIPTOR_NO_DICT, (descr/4, owner -- attr, unused if (0))) { ++ op(_LOAD_ATTR_NONDESCRIPTOR_NO_DICT, (descr/4, owner -- attr)) { + assert((oparg & 1) == 0); + assert(Py_TYPE(PyStackRef_AsPyObjectBorrow(owner))->tp_dictoffset == 0); + STAT_INC(LOAD_ATTR, hit); +@@ -3292,12 +3438,12 @@ + + op(_CHECK_ATTR_METHOD_LAZY_DICT, (dictoffset/1, owner -- owner)) { + char *ptr = ((char *)PyStackRef_AsPyObjectBorrow(owner)) + MANAGED_DICT_OFFSET + dictoffset; +- PyObject *dict = *(PyObject **)ptr; ++ PyObject *dict = FT_ATOMIC_LOAD_PTR_ACQUIRE(*(PyObject **)ptr); + /* This object has a __dict__, just not yet created */ + DEOPT_IF(dict != NULL); + } + +- op(_LOAD_ATTR_METHOD_LAZY_DICT, (descr/4, owner -- attr, self if (1))) { ++ op(_LOAD_ATTR_METHOD_LAZY_DICT, (descr/4, owner -- attr, self)) { + assert(oparg & 1); + STAT_INC(LOAD_ATTR, hit); + assert(descr != NULL); +@@ -3352,6 +3498,7 @@ + } + + op(_MAYBE_EXPAND_METHOD, (callable[1], self_or_null[1], args[oparg] -- func[1], maybe_self[1], args[oparg])) { ++ (void)args; + if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + PyObject *self = ((PyMethodObject *)callable_o)->im_self; +@@ -3369,8 +3516,9 @@ + + // oparg counts all of the args, but *not* self: + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + // Check if the call can be inlined or not +@@ -3382,7 +3530,7 @@ + PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); + _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( + tstate, callable[0], locals, +- args, total_args, NULL, frame ++ arguments, total_args, NULL, frame + ); + // Manipulate stack directly since we leave using DISPATCH_INLINED(). + SYNC_SP(); +@@ -3395,13 +3543,9 @@ + DISPATCH_INLINED(new_frame); + } + /* Callable is not a normal Python function */ +- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { +- PyStackRef_CLOSE(callable[0]); +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); +- } +- DEAD(self_or_null); ++ DECREF_INPUTS(); + ERROR_IF(true, error); + } + PyObject *res_o = PyObject_Vectorcall( +@@ -3411,7 +3555,7 @@ + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + if (opcode == INSTRUMENTED_CALL) { + PyObject *arg = total_args == 0 ? +- &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(args[0]); ++ &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(arguments[0]); + if (res_o == NULL) { + _Py_call_instrumentation_exc2( + tstate, PY_MONITORING_EVENT_C_RAISE, +@@ -3427,11 +3571,7 @@ + } + } + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); +- PyStackRef_CLOSE(callable[0]); +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); +- } +- DEAD(self_or_null); ++ DECREF_INPUTS(); + ERROR_IF(res_o == NULL, error); + res = PyStackRef_FromPyObjectSteal(res_o); + } +@@ -3516,15 +3656,14 @@ + EXIT_IF(!PyStackRef_IsNull(null[0])); + } + +- op(_EXPAND_METHOD, (callable[1], null[1], unused[oparg] -- method[1], self[1], unused[oparg])) { ++ op(_EXPAND_METHOD, (callable[1], self_or_null[1], unused[oparg] -- callable[1], self_or_null[1], unused[oparg])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); +- assert(PyStackRef_IsNull(null[0])); +- DEAD(null); ++ assert(PyStackRef_IsNull(self_or_null[0])); + assert(Py_TYPE(callable_o) == &PyMethod_Type); +- self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); ++ self_or_null[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); + _PyStackRef temp = callable[0]; +- method[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); +- assert(PyStackRef_FunctionCheck(method[0])); ++ callable[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); ++ assert(PyStackRef_FunctionCheck(callable[0])); + PyStackRef_CLOSE(temp); + } + +@@ -3551,12 +3690,13 @@ + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + /* Callable is not a normal Python function */ +- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + DECREF_INPUTS(); + ERROR_IF(true, error); +@@ -3567,11 +3707,7 @@ + NULL); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); +- PyStackRef_CLOSE(callable[0]); +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); +- } +- DEAD(self_or_null); ++ DECREF_INPUTS(); + ERROR_IF(res_o == NULL, error); + res = PyStackRef_FromPyObjectSteal(res_o); + } +@@ -3588,13 +3724,13 @@ + EXIT_IF(Py_TYPE(PyStackRef_AsPyObjectBorrow(callable[0])) != &PyMethod_Type); + } + +- op(_INIT_CALL_BOUND_METHOD_EXACT_ARGS, (callable[1], null[1], unused[oparg] -- func[1], self[1], unused[oparg])) { +- DEAD(null); ++ op(_INIT_CALL_BOUND_METHOD_EXACT_ARGS, (callable[1], self_or_null[1], unused[oparg] -- callable[1], self_or_null[1], unused[oparg])) { ++ assert(PyStackRef_IsNull(self_or_null[0])); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + STAT_INC(CALL, hit); +- self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); ++ self_or_null[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); + _PyStackRef temp = callable[0]; +- func[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); ++ callable[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); + PyStackRef_CLOSE(temp); + } + +@@ -3729,18 +3865,21 @@ + _CHECK_PERIODIC; + + op(_CHECK_AND_ALLOCATE_OBJECT, (type_version/2, callable[1], null[1], args[oparg] -- init[1], self[1], args[oparg])) { ++ (void)args; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + DEOPT_IF(!PyStackRef_IsNull(null[0])); + DEOPT_IF(!PyType_Check(callable_o)); + PyTypeObject *tp = (PyTypeObject *)callable_o; + DEOPT_IF(FT_ATOMIC_LOAD_UINT32_RELAXED(tp->tp_version_tag) != type_version); +- assert(tp->tp_flags & Py_TPFLAGS_INLINE_VALUES); ++ assert(tp->tp_new == PyBaseObject_Type.tp_new); ++ assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE); ++ assert(tp->tp_alloc == PyType_GenericAlloc); + PyHeapTypeObject *cls = (PyHeapTypeObject *)callable_o; + PyFunctionObject *init_func = (PyFunctionObject *)FT_ATOMIC_LOAD_PTR_ACQUIRE(cls->_spec_cache.init); + PyCodeObject *code = (PyCodeObject *)init_func->func_code; + DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize + _Py_InitCleanup.co_framesize)); + STAT_INC(CALL, hit); +- PyObject *self_o = _PyType_NewManagedObject(tp); ++ PyObject *self_o = PyType_GenericAlloc(tp, 0); + if (self_o == NULL) { + ERROR_NO_POP(); + } +@@ -3794,29 +3933,24 @@ + + op(_CALL_BUILTIN_CLASS, (callable[1], self_or_null[1], args[oparg] -- res)) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); +- ++ DEOPT_IF(!PyType_Check(callable_o)); ++ PyTypeObject *tp = (PyTypeObject *)callable_o; + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } +- DEAD(self_or_null); +- DEOPT_IF(!PyType_Check(callable_o)); +- PyTypeObject *tp = (PyTypeObject *)callable_o; + DEOPT_IF(tp->tp_vectorcall == NULL); + STAT_INC(CALL, hit); +- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + DECREF_INPUTS(); + ERROR_IF(true, error); + } + PyObject *res_o = tp->tp_vectorcall((PyObject *)tp, args_o, total_args, NULL); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); +- /* Free the arguments. */ +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); +- } +- PyStackRef_CLOSE(callable[0]); ++ DECREF_INPUTS(); + ERROR_IF(res_o == NULL, error); + res = PyStackRef_FromPyObjectSteal(res_o); + } +@@ -3868,17 +4002,17 @@ + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } +- DEAD(self_or_null); + DEOPT_IF(!PyCFunction_CheckExact(callable_o)); + DEOPT_IF(PyCFunction_GET_FLAGS(callable_o) != METH_FASTCALL); + STAT_INC(CALL, hit); + PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable_o); + /* res = func(self, args, nargs) */ +- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + DECREF_INPUTS(); + ERROR_IF(true, error); +@@ -3889,12 +4023,7 @@ + total_args); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); +- +- /* Free the arguments. */ +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); +- } +- PyStackRef_CLOSE(callable[0]); ++ DECREF_INPUTS(); + ERROR_IF(res_o == NULL, error); + res = PyStackRef_FromPyObjectSteal(res_o); + } +@@ -3910,34 +4039,28 @@ + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + DEOPT_IF(!PyCFunction_CheckExact(callable_o)); + DEOPT_IF(PyCFunction_GET_FLAGS(callable_o) != (METH_FASTCALL | METH_KEYWORDS)); + STAT_INC(CALL, hit); +- /* res = func(self, args, nargs, kwnames) */ ++ /* res = func(self, arguments, nargs, kwnames) */ + PyCFunctionFastWithKeywords cfunc = + (PyCFunctionFastWithKeywords)(void(*)(void)) + PyCFunction_GET_FUNCTION(callable_o); + +- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + DECREF_INPUTS(); + ERROR_IF(true, error); + } + PyObject *res_o = cfunc(PyCFunction_GET_SELF(callable_o), args_o, total_args, NULL); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); +- + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); +- +- /* Free the arguments. */ +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); +- } +- DEAD(self_or_null); +- PyStackRef_CLOSE(callable[0]); ++ DECREF_INPUTS(); + ERROR_IF(res_o == NULL, error); + res = PyStackRef_FromPyObjectSteal(res_o); + } +@@ -3970,10 +4093,12 @@ + PyObject *res_o = PyLong_FromSsize_t(len_i); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + if (res_o == NULL) { +- GOTO_ERROR(error); ++ ERROR_NO_POP(); + } +- PyStackRef_CLOSE(callable[0]); + PyStackRef_CLOSE(arg_stackref); ++ DEAD(args); ++ DEAD(self_or_null); ++ PyStackRef_CLOSE(callable[0]); + res = PyStackRef_FromPyObjectSteal(res_o); + } + +@@ -3982,25 +4107,24 @@ + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + DEOPT_IF(total_args != 2); + PyInterpreterState *interp = tstate->interp; + DEOPT_IF(callable_o != interp->callable_cache.isinstance); + STAT_INC(CALL, hit); +- _PyStackRef cls_stackref = args[1]; +- _PyStackRef inst_stackref = args[0]; ++ _PyStackRef cls_stackref = arguments[1]; ++ _PyStackRef inst_stackref = arguments[0]; + int retval = PyObject_IsInstance(PyStackRef_AsPyObjectBorrow(inst_stackref), PyStackRef_AsPyObjectBorrow(cls_stackref)); + if (retval < 0) { + ERROR_NO_POP(); + } + res = retval ? PyStackRef_True : PyStackRef_False; + assert((!PyStackRef_IsNull(res)) ^ (_PyErr_Occurred(tstate) != NULL)); +- PyStackRef_CLOSE(inst_stackref); +- PyStackRef_CLOSE(cls_stackref); +- PyStackRef_CLOSE(callable[0]); ++ DECREF_INPUTS(); + } + + // This is secretly a super-instruction +@@ -4032,8 +4156,9 @@ + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + +@@ -4044,8 +4169,8 @@ + EXIT_IF(meth->ml_flags != METH_O); + // CPython promises to check all non-vectorcall function calls. + EXIT_IF(tstate->c_recursion_remaining <= 0); +- _PyStackRef arg_stackref = args[1]; +- _PyStackRef self_stackref = args[0]; ++ _PyStackRef arg_stackref = arguments[1]; ++ _PyStackRef self_stackref = arguments[0]; + EXIT_IF(!Py_IS_TYPE(PyStackRef_AsPyObjectBorrow(self_stackref), + method->d_common.d_type)); + STAT_INC(CALL, hit); +@@ -4056,11 +4181,7 @@ + PyStackRef_AsPyObjectBorrow(arg_stackref)); + _Py_LeaveRecursiveCallTstate(tstate); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); +- PyStackRef_CLOSE(self_stackref); +- PyStackRef_CLOSE(arg_stackref); +- DEAD(args); +- DEAD(self_or_null); +- PyStackRef_CLOSE(callable[0]); ++ DECREF_INPUTS(); + ERROR_IF(res_o == NULL, error); + res = PyStackRef_FromPyObjectSteal(res_o); + } +@@ -4075,8 +4196,9 @@ + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; +@@ -4084,12 +4206,12 @@ + PyMethodDef *meth = method->d_method; + EXIT_IF(meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS)); + PyTypeObject *d_type = method->d_common.d_type; +- PyObject *self = PyStackRef_AsPyObjectBorrow(args[0]); ++ PyObject *self = PyStackRef_AsPyObjectBorrow(arguments[0]); + EXIT_IF(!Py_IS_TYPE(self, d_type)); + STAT_INC(CALL, hit); + int nargs = total_args - 1; + +- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + DECREF_INPUTS(); + ERROR_IF(true, error); +@@ -4099,13 +4221,7 @@ + PyObject *res_o = cfunc(self, (args_o + 1), nargs, NULL); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); +- +- /* Free the arguments. */ +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); +- } +- DEAD(self_or_null); +- PyStackRef_CLOSE(callable[0]); ++ DECREF_INPUTS(); + ERROR_IF(res_o == NULL, error); + res = PyStackRef_FromPyObjectSteal(res_o); + } +@@ -4159,8 +4275,9 @@ + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; +@@ -4168,12 +4285,12 @@ + EXIT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type)); + PyMethodDef *meth = method->d_method; + EXIT_IF(meth->ml_flags != METH_FASTCALL); +- PyObject *self = PyStackRef_AsPyObjectBorrow(args[0]); ++ PyObject *self = PyStackRef_AsPyObjectBorrow(arguments[0]); + EXIT_IF(!Py_IS_TYPE(self, method->d_common.d_type)); + STAT_INC(CALL, hit); + int nargs = total_args - 1; + +- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + DECREF_INPUTS(); + ERROR_IF(true, error); +@@ -4183,13 +4300,7 @@ + PyObject *res_o = cfunc(self, (args_o + 1), nargs); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); +- +- /* Clear the stack of the arguments. */ +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); +- } +- DEAD(self_or_null); +- PyStackRef_CLOSE(callable[0]); ++ DECREF_INPUTS(); + ERROR_IF(res_o == NULL, error); + res = PyStackRef_FromPyObjectSteal(res_o); + } +@@ -4207,21 +4318,27 @@ + CALL_KW_NON_PY, + }; + +- inst(INSTRUMENTED_CALL_KW, (counter/1, version/2 -- )) { +- int is_meth = !PyStackRef_IsNull(PEEK(oparg + 2)); +- int total_args = oparg + is_meth; +- PyObject *function = PyStackRef_AsPyObjectBorrow(PEEK(oparg + 3)); +- PyObject *arg = total_args == 0 ? &_PyInstrumentation_MISSING +- : PyStackRef_AsPyObjectBorrow(PEEK(total_args + 1)); ++ op(_MONITOR_CALL_KW, (callable[1], self_or_null[1], args[oparg], kwnames -- callable[1], self_or_null[1], args[oparg], kwnames)) { ++ int is_meth = !PyStackRef_IsNull(self_or_null[0]); ++ PyObject *arg; ++ if (is_meth) { ++ arg = PyStackRef_AsPyObjectBorrow(self_or_null[0]); ++ } ++ else if (args) { ++ arg = PyStackRef_AsPyObjectBorrow(args[0]); ++ } ++ else { ++ arg = &_PyInstrumentation_MISSING; ++ } ++ PyObject *function = PyStackRef_AsPyObjectBorrow(callable[0]); + int err = _Py_call_instrumentation_2args( + tstate, PY_MONITORING_EVENT_CALL, + frame, this_instr, function, arg); + ERROR_IF(err, error); +- PAUSE_ADAPTIVE_COUNTER(this_instr[1].counter); +- GO_TO_INSTRUCTION(CALL_KW); + } + + op(_MAYBE_EXPAND_METHOD_KW, (callable[1], self_or_null[1], args[oparg], kwnames_in -- func[1], maybe_self[1], args[oparg], kwnames_out)) { ++ (void)args; + if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + PyObject *self = ((PyMethodObject *)callable_o)->im_self; +@@ -4241,8 +4358,9 @@ + + // oparg counts all of the args, but *not* self: + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + int positional_args = total_args - (int)PyTuple_GET_SIZE(kwnames_o); +@@ -4255,7 +4373,7 @@ + PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); + _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( + tstate, callable[0], locals, +- args, positional_args, kwnames_o, frame ++ arguments, positional_args, kwnames_o, frame + ); + PyStackRef_CLOSE(kwnames); + // Sync stack explicitly since we leave using DISPATCH_INLINED(). +@@ -4270,7 +4388,7 @@ + DISPATCH_INLINED(new_frame); + } + /* Callable is not a normal Python function */ +- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + DECREF_INPUTS(); + ERROR_IF(true, error); +@@ -4282,7 +4400,7 @@ + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + if (opcode == INSTRUMENTED_CALL_KW) { + PyObject *arg = total_args == 0 ? +- &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(args[0]); ++ &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(arguments[0]); + if (res_o == NULL) { + _Py_call_instrumentation_exc2( + tstate, PY_MONITORING_EVENT_C_RAISE, +@@ -4297,13 +4415,7 @@ + } + } + } +- PyStackRef_CLOSE(kwnames); +- assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); +- PyStackRef_CLOSE(callable[0]); +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); +- } +- DEAD(self_or_null); ++ DECREF_INPUTS(); + ERROR_IF(res_o == NULL, error); + res = PyStackRef_FromPyObjectSteal(res_o); + } +@@ -4313,8 +4425,9 @@ + + // oparg counts all of the args, but *not* self: + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); +@@ -4324,7 +4437,7 @@ + PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); + _PyInterpreterFrame *temp = _PyEvalFramePushAndInit( + tstate, callable[0], locals, +- args, positional_args, kwnames_o, frame ++ arguments, positional_args, kwnames_o, frame + ); + PyStackRef_CLOSE(kwnames); + // The frame has stolen all the arguments from the stack, +@@ -4361,15 +4474,14 @@ + EXIT_IF(!PyStackRef_IsNull(null[0])); + } + +- op(_EXPAND_METHOD_KW, (callable[1], null[1], unused[oparg], unused -- method[1], self[1], unused[oparg], unused)) { ++ op(_EXPAND_METHOD_KW, (callable[1], self_or_null[1], unused[oparg], unused -- callable[1], self_or_null[1], unused[oparg], unused)) { ++ assert(PyStackRef_IsNull(self_or_null[0])); + _PyStackRef callable_s = callable[0]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable_s); +- +- assert(PyStackRef_IsNull(null[0])); + assert(Py_TYPE(callable_o) == &PyMethod_Type); +- self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); +- method[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); +- assert(PyStackRef_FunctionCheck(method[0])); ++ self_or_null[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); ++ callable[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); ++ assert(PyStackRef_FunctionCheck(callable[0])); + PyStackRef_CLOSE(callable_s); + } + +@@ -4401,6 +4513,13 @@ + _MAYBE_EXPAND_METHOD_KW + + _DO_CALL_KW; + ++ macro(INSTRUMENTED_CALL_KW) = ++ counter/1 + ++ unused/2 + ++ _MONITOR_CALL_KW + ++ _MAYBE_EXPAND_METHOD_KW + ++ _DO_CALL_KW; ++ + op(_CHECK_IS_NOT_PY_CALLABLE_KW, (callable[1], unused[1], unused[oparg], kwnames -- callable[1], unused[1], unused[oparg], kwnames)) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + EXIT_IF(PyFunction_Check(callable_o)); +@@ -4415,12 +4534,13 @@ + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + /* Callable is not a normal Python function */ +- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + DECREF_INPUTS(); + ERROR_IF(true, error); +@@ -4434,11 +4554,7 @@ + PyStackRef_CLOSE(kwnames); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); +- } +- DEAD(self_or_null); +- PyStackRef_CLOSE(callable[0]); ++ DECREF_INPUTS(); + ERROR_IF(res_o == NULL, error); + res = PyStackRef_FromPyObjectSteal(res_o); + } +@@ -4450,14 +4566,12 @@ + _CALL_KW_NON_PY + + _CHECK_PERIODIC; + +- inst(INSTRUMENTED_CALL_FUNCTION_EX, ( -- )) { +- GO_TO_INSTRUCTION(CALL_FUNCTION_EX); +- } +- +- op(_MAKE_CALLARGS_A_TUPLE, (func, unused, callargs, kwargs_in if (oparg & 1) -- func, unused, tuple, kwargs_out if (oparg & 1))) { ++ op(_MAKE_CALLARGS_A_TUPLE, (func, unused, callargs, kwargs_in -- func, unused, tuple, kwargs_out)) { + PyObject *callargs_o = PyStackRef_AsPyObjectBorrow(callargs); + if (PyTuple_CheckExact(callargs_o)) { + tuple = callargs; ++ kwargs_out = kwargs_in; ++ DEAD(kwargs_in); + DEAD(callargs); + } + else { +@@ -4469,26 +4583,27 @@ + if (tuple_o == NULL) { + ERROR_NO_POP(); + } ++ kwargs_out = kwargs_in; ++ DEAD(kwargs_in); + PyStackRef_CLOSE(callargs); + tuple = PyStackRef_FromPyObjectSteal(tuple_o); + } +- kwargs_out = kwargs_in; +- DEAD(kwargs_in); + } + +- op(_DO_CALL_FUNCTION_EX, (func_st, unused, callargs_st, kwargs_st if (oparg & 1) -- result)) { ++ op(_DO_CALL_FUNCTION_EX, (func_st, null, callargs_st, kwargs_st -- result)) { ++ (void)null; + PyObject *func = PyStackRef_AsPyObjectBorrow(func_st); +- PyObject *callargs = PyStackRef_AsPyObjectBorrow(callargs_st); +- PyObject *kwargs = PyStackRef_AsPyObjectBorrow(kwargs_st); + + // DICT_MERGE is called before this opcode if there are kwargs. + // It converts all dict subtypes in kwargs into regular dicts. +- assert(kwargs == NULL || PyDict_CheckExact(kwargs)); +- assert(PyTuple_CheckExact(callargs)); + EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_FUNCTION_EX, func); + PyObject *result_o; + assert(!_PyErr_Occurred(tstate)); + if (opcode == INSTRUMENTED_CALL_FUNCTION_EX) { ++ PyObject *callargs = PyStackRef_AsPyObjectBorrow(callargs_st); ++ PyObject *kwargs = PyStackRef_AsPyObjectBorrow(kwargs_st); ++ assert(kwargs == NULL || PyDict_CheckExact(kwargs)); ++ assert(PyTuple_CheckExact(callargs)); + PyObject *arg = PyTuple_GET_SIZE(callargs) > 0 ? + PyTuple_GET_ITEM(callargs, 0) : &_PyInstrumentation_MISSING; + int err = _Py_call_instrumentation_2args( +@@ -4519,7 +4634,10 @@ + if (Py_TYPE(func) == &PyFunction_Type && + tstate->interp->eval_frame == NULL && + ((PyFunctionObject *)func)->vectorcall == _PyFunction_Vectorcall) { ++ PyObject *callargs = PyStackRef_AsPyObjectSteal(callargs_st); + assert(PyTuple_CheckExact(callargs)); ++ PyObject *kwargs = PyStackRef_IsNull(kwargs_st) ? NULL : PyStackRef_AsPyObjectSteal(kwargs_st); ++ assert(kwargs == NULL || PyDict_CheckExact(kwargs)); + Py_ssize_t nargs = PyTuple_GET_SIZE(callargs); + int code_flags = ((PyCodeObject *)PyFunction_GET_CODE(func))->co_flags; + PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(func)); +@@ -4537,11 +4655,15 @@ + frame->return_offset = 1; + DISPATCH_INLINED(new_frame); + } ++ PyObject *callargs = PyStackRef_AsPyObjectBorrow(callargs_st); ++ assert(PyTuple_CheckExact(callargs)); ++ PyObject *kwargs = PyStackRef_AsPyObjectBorrow(kwargs_st); ++ assert(kwargs == NULL || PyDict_CheckExact(kwargs)); + result_o = PyObject_Call(func, callargs, kwargs); + } + PyStackRef_XCLOSE(kwargs_st); +- DEAD(kwargs_st); + PyStackRef_CLOSE(callargs_st); ++ DEAD(null); + PyStackRef_CLOSE(func_st); + ERROR_IF(result_o == NULL, error); + result = PyStackRef_FromPyObjectSteal(result_o); +@@ -4552,6 +4674,10 @@ + _DO_CALL_FUNCTION_EX + + _CHECK_PERIODIC; + ++ macro(INSTRUMENTED_CALL_FUNCTION_EX) = ++ _MAKE_CALLARGS_A_TUPLE + ++ _DO_CALL_FUNCTION_EX + ++ _CHECK_PERIODIC; + + inst(MAKE_FUNCTION, (codeobj_st -- func)) { + PyObject *codeobj = PyStackRef_AsPyObjectBorrow(codeobj_st); +@@ -4603,11 +4729,10 @@ + LLTRACE_RESUME_FRAME(); + } + +- inst(BUILD_SLICE, (start, stop, step if (oparg == 3) -- slice)) { +- PyObject *start_o = PyStackRef_AsPyObjectBorrow(start); +- PyObject *stop_o = PyStackRef_AsPyObjectBorrow(stop); +- PyObject *step_o = PyStackRef_AsPyObjectBorrow(step); +- ++ inst(BUILD_SLICE, (args[oparg] -- slice)) { ++ PyObject *start_o = PyStackRef_AsPyObjectBorrow(args[0]); ++ PyObject *stop_o = PyStackRef_AsPyObjectBorrow(args[1]); ++ PyObject *step_o = oparg == 3 ? PyStackRef_AsPyObjectBorrow(args[2]) : NULL; + PyObject *slice_o = PySlice_New(start_o, stop_o, step_o); + DECREF_INPUTS(); + ERROR_IF(slice_o == NULL, error); +@@ -4642,8 +4767,7 @@ + + inst(FORMAT_WITH_SPEC, (value, fmt_spec -- res)) { + PyObject *res_o = PyObject_Format(PyStackRef_AsPyObjectBorrow(value), PyStackRef_AsPyObjectBorrow(fmt_spec)); +- PyStackRef_CLOSE(value); +- PyStackRef_CLOSE(fmt_spec); ++ DECREF_INPUTS(); + ERROR_IF(res_o == NULL, error); + res = PyStackRef_FromPyObjectSteal(res_o); + } +@@ -4664,7 +4788,7 @@ + ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); + #endif /* ENABLE_SPECIALIZATION_FT */ + assert(NB_ADD <= oparg); +- assert(oparg <= NB_INPLACE_XOR); ++ assert(oparg <= NB_OPARG_LAST); + } + + op(_BINARY_OP, (lhs, rhs -- res)) { +@@ -4678,14 +4802,13 @@ + res = PyStackRef_FromPyObjectSteal(res_o); + } + +- macro(BINARY_OP) = _SPECIALIZE_BINARY_OP + _BINARY_OP; ++ macro(BINARY_OP) = _SPECIALIZE_BINARY_OP + unused/4 + _BINARY_OP; + +- pure inst(SWAP, (bottom_in, unused[oparg-2], top_in -- +- top_out, unused[oparg-2], bottom_out)) { +- bottom_out = bottom_in; +- DEAD(bottom_in); +- top_out = top_in; +- DEAD(top_in); ++ pure inst(SWAP, (bottom[1], unused[oparg-2], top[1] -- ++ bottom[1], unused[oparg-2], top[1])) { ++ _PyStackRef temp = bottom[0]; ++ bottom[0] = top[0]; ++ top[0] = temp; + assert(oparg >= 2); + } + +@@ -4693,7 +4816,8 @@ + int original_opcode = 0; + if (tstate->tracing) { + PyCodeObject *code = _PyFrame_GetCode(frame); +- original_opcode = code->_co_monitoring->lines[(int)(this_instr - _PyFrame_GetBytecode(frame))].original_opcode; ++ int index = (int)(this_instr - _PyFrame_GetBytecode(frame)); ++ original_opcode = code->_co_monitoring->lines->data[index*code->_co_monitoring->lines->bytes_per_entry]; + next_instr = this_instr; + } else { + original_opcode = _Py_call_instrumentation_line( +@@ -4738,6 +4862,11 @@ + INSTRUMENTED_JUMP(this_instr, next_instr - oparg, PY_MONITORING_EVENT_JUMP); + } + ++ inst(INSTRUMENTED_NOT_TAKEN, ( -- )) { ++ (void)this_instr; // INSTRUMENTED_JUMP requires this_instr ++ INSTRUMENTED_JUMP(prev_instr, next_instr, PY_MONITORING_EVENT_BRANCH_LEFT); ++ } ++ + macro(INSTRUMENTED_JUMP_BACKWARD) = + unused/1 + + _CHECK_PERIODIC + +@@ -4746,51 +4875,43 @@ + inst(INSTRUMENTED_POP_JUMP_IF_TRUE, (unused/1 -- )) { + _PyStackRef cond = POP(); + assert(PyStackRef_BoolCheck(cond)); +- int flag = PyStackRef_IsTrue(cond); +- int offset = flag * oparg; +- RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); +- INSTRUMENTED_JUMP(this_instr, next_instr + offset, PY_MONITORING_EVENT_BRANCH); ++ int jump = PyStackRef_IsTrue(cond); ++ RECORD_BRANCH_TAKEN(this_instr[1].cache, jump); ++ if (jump) { ++ INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT); ++ } + } + + inst(INSTRUMENTED_POP_JUMP_IF_FALSE, (unused/1 -- )) { + _PyStackRef cond = POP(); + assert(PyStackRef_BoolCheck(cond)); +- int flag = PyStackRef_IsFalse(cond); +- int offset = flag * oparg; +- RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); +- INSTRUMENTED_JUMP(this_instr, next_instr + offset, PY_MONITORING_EVENT_BRANCH); ++ int jump = PyStackRef_IsFalse(cond); ++ RECORD_BRANCH_TAKEN(this_instr[1].cache, jump); ++ if (jump) { ++ INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT); ++ } + } + + inst(INSTRUMENTED_POP_JUMP_IF_NONE, (unused/1 -- )) { + _PyStackRef value_stackref = POP(); +- int flag = PyStackRef_IsNone(value_stackref); +- int offset; +- if (flag) { +- offset = oparg; ++ int jump = PyStackRef_IsNone(value_stackref); ++ RECORD_BRANCH_TAKEN(this_instr[1].cache, jump); ++ if (jump) { ++ INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT); + } + else { + PyStackRef_CLOSE(value_stackref); +- offset = 0; + } +- RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); +- INSTRUMENTED_JUMP(this_instr, next_instr + offset, PY_MONITORING_EVENT_BRANCH); + } + + inst(INSTRUMENTED_POP_JUMP_IF_NOT_NONE, (unused/1 -- )) { + _PyStackRef value_stackref = POP(); +- int offset; +- int nflag = PyStackRef_IsNone(value_stackref); +- if (nflag) { +- offset = 0; +- } +- else { ++ int jump = !PyStackRef_IsNone(value_stackref); ++ RECORD_BRANCH_TAKEN(this_instr[1].cache, jump); ++ if (jump) { + PyStackRef_CLOSE(value_stackref); +- offset = oparg; ++ INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT); + } +- #if ENABLE_SPECIALIZATION +- this_instr[1].cache = (this_instr[1].cache << 1) | !nflag; +- #endif +- INSTRUMENTED_JUMP(this_instr, next_instr + offset, PY_MONITORING_EVENT_BRANCH); + } + + tier1 inst(EXTENDED_ARG, ( -- )) { +@@ -4873,10 +4994,10 @@ + _Py_CODEUNIT *target = _PyFrame_GetBytecode(frame) + exit->target; + #if defined(Py_DEBUG) && !defined(_Py_JIT) + OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); +- if (lltrace >= 2) { ++ if (frame->lltrace >= 2) { + printf("SIDE EXIT: [UOp "); + _PyUOpPrint(&next_uop[-1]); +- printf(", exit %u, temp %d, target %d -> %s]\n", ++ printf(", exit %lu, temp %d, target %d -> %s]\n", + exit - current_executor->exits, exit->temperature.value_and_backoff, + (int)(target - _PyFrame_GetBytecode(frame)), + _PyOpcode_OpName[target->op.code]); +@@ -4886,11 +5007,11 @@ + exit->temperature = initial_temperature_backoff_counter(); + Py_CLEAR(exit->executor); + } ++ tstate->previous_executor = (PyObject *)current_executor; + if (exit->executor == NULL) { + _Py_BackoffCounter temperature = exit->temperature; + if (!backoff_counter_triggers(temperature)) { + exit->temperature = advance_backoff_counter(temperature); +- tstate->previous_executor = (PyObject *)current_executor; + GOTO_TIER_ONE(target); + } + _PyExecutorObject *executor; +@@ -4900,23 +5021,16 @@ + } + else { + int chain_depth = current_executor->vm_data.chain_depth + 1; +- int optimized = _PyOptimizer_Optimize(frame, target, stack_pointer, &executor, chain_depth); ++ int optimized = _PyOptimizer_Optimize(frame, target, &executor, chain_depth); + if (optimized <= 0) { + exit->temperature = restart_backoff_counter(temperature); +- if (optimized < 0) { +- GOTO_UNWIND(); +- } +- tstate->previous_executor = (PyObject *)current_executor; +- GOTO_TIER_ONE(target); +- } +- else { +- exit->temperature = initial_temperature_backoff_counter(); ++ GOTO_TIER_ONE(optimized < 0 ? NULL : target); + } ++ exit->temperature = initial_temperature_backoff_counter(); + } + exit->executor = executor; + } + Py_INCREF(exit->executor); +- tstate->previous_executor = (PyObject *)current_executor; + GOTO_TIER_TWO(exit->executor); + } + +@@ -4937,43 +5051,31 @@ + value = PyStackRef_FromPyObjectImmortal(ptr); + } + +- tier2 pure op(_LOAD_CONST_INLINE_WITH_NULL, (ptr/4 -- value, null)) { +- value = PyStackRef_FromPyObjectNew(ptr); +- null = PyStackRef_NULL; +- } +- +- tier2 pure op(_LOAD_CONST_INLINE_BORROW_WITH_NULL, (ptr/4 -- value, null)) { +- value = PyStackRef_FromPyObjectImmortal(ptr); +- null = PyStackRef_NULL; +- } +- + tier2 op(_CHECK_FUNCTION, (func_version/2 -- )) { + assert(PyStackRef_FunctionCheck(frame->f_funcobj)); + PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj); + DEOPT_IF(func->func_version != func_version); + } + +- tier2 op(_LOAD_GLOBAL_MODULE, (index/1 -- res, null if (oparg & 1))) { ++ tier2 op(_LOAD_GLOBAL_MODULE, (index/1 -- res)) { + PyDictObject *dict = (PyDictObject *)GLOBALS(); + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); + PyObject *res_o = entries[index].me_value; + DEOPT_IF(res_o == NULL); + Py_INCREF(res_o); + res = PyStackRef_FromPyObjectSteal(res_o); +- null = PyStackRef_NULL; + } + +- tier2 op(_LOAD_GLOBAL_BUILTINS, (index/1 -- res, null if (oparg & 1))) { ++ tier2 op(_LOAD_GLOBAL_BUILTINS, (index/1 -- res)) { + PyDictObject *dict = (PyDictObject *)BUILTINS(); + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); + PyObject *res_o = entries[index].me_value; + DEOPT_IF(res_o == NULL); + Py_INCREF(res_o); + res = PyStackRef_FromPyObjectSteal(res_o); +- null = PyStackRef_NULL; + } + +- tier2 op(_LOAD_ATTR_MODULE, (index/1, owner -- attr, null if (oparg & 1))) { ++ tier2 op(_LOAD_ATTR_MODULE, (index/1, owner -- attr)) { + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner_o)->md_dict; + assert(dict->ma_keys->dk_kind == DICT_KEYS_UNICODE); +@@ -4984,61 +5086,11 @@ + STAT_INC(LOAD_ATTR, hit); + Py_INCREF(attr_o); + attr = PyStackRef_FromPyObjectSteal(attr_o); +- null = PyStackRef_NULL; + DECREF_INPUTS(); + } + +- /* Internal -- for testing executors */ +- op(_INTERNAL_INCREMENT_OPT_COUNTER, (opt --)) { +- _PyCounterOptimizerObject *exe = (_PyCounterOptimizerObject *)PyStackRef_AsPyObjectBorrow(opt); +- exe->count++; +- DEAD(opt); +- } +- +- tier2 op(_DYNAMIC_EXIT, (exit_p/4 --)) { +- tstate->previous_executor = (PyObject *)current_executor; +- _PyExitData *exit = (_PyExitData *)exit_p; +- _Py_CODEUNIT *target = frame->instr_ptr; +- #if defined(Py_DEBUG) && !defined(_Py_JIT) +- OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); +- if (lltrace >= 2) { +- printf("DYNAMIC EXIT: [UOp "); +- _PyUOpPrint(&next_uop[-1]); +- printf(", exit %u, temp %d, target %d -> %s]\n", +- exit - current_executor->exits, exit->temperature.value_and_backoff, +- (int)(target - _PyFrame_GetBytecode(frame)), +- _PyOpcode_OpName[target->op.code]); +- } +- #endif +- _PyExecutorObject *executor; +- if (target->op.code == ENTER_EXECUTOR) { +- PyCodeObject *code = _PyFrame_GetCode(frame); +- executor = code->co_executors->executors[target->op.arg]; +- Py_INCREF(executor); +- } +- else { +- if (!backoff_counter_triggers(exit->temperature)) { +- exit->temperature = advance_backoff_counter(exit->temperature); +- GOTO_TIER_ONE(target); +- } +- int optimized = _PyOptimizer_Optimize(frame, target, stack_pointer, &executor, 0); +- if (optimized <= 0) { +- exit->temperature = restart_backoff_counter(exit->temperature); +- if (optimized < 0) { +- GOTO_UNWIND(); +- } +- GOTO_TIER_ONE(target); +- } +- else { +- exit->temperature = initial_temperature_backoff_counter(); +- } +- } +- GOTO_TIER_TWO(executor); +- } +- + tier2 op(_START_EXECUTOR, (executor/4 --)) { +- Py_DECREF(tstate->previous_executor); +- tstate->previous_executor = NULL; ++ Py_CLEAR(tstate->previous_executor); + #ifndef _Py_JIT + current_executor = (_PyExecutorObject*)executor; + #endif +@@ -5064,13 +5116,16 @@ + } + + tier2 op(_DEOPT, (--)) { +- EXIT_TO_TIER1(); ++ tstate->previous_executor = (PyObject *)current_executor; ++ GOTO_TIER_ONE(_PyFrame_GetBytecode(frame) + CURRENT_TARGET()); + } + +- tier2 op(_ERROR_POP_N, (target/2, unused[oparg] --)) { ++ tier2 op(_ERROR_POP_N, (target/2 --)) { ++ tstate->previous_executor = (PyObject *)current_executor; ++ assert(oparg == 0); + frame->instr_ptr = _PyFrame_GetBytecode(frame) + target; + SYNC_SP(); +- GOTO_UNWIND(); ++ GOTO_TIER_ONE(NULL); + } + + /* Progress is guaranteed if we DEOPT on the eval breaker, because +@@ -5085,6 +5140,151 @@ + assert(tstate->tracing || eval_breaker == FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version)); + } + ++ label(pop_4_error) { ++ STACK_SHRINK(4); ++ goto error; ++ } ++ ++ label(pop_3_error) { ++ STACK_SHRINK(3); ++ goto error; ++ } ++ ++ label(pop_2_error) { ++ STACK_SHRINK(2); ++ goto error; ++ } ++ ++ label(pop_1_error) { ++ STACK_SHRINK(1); ++ goto error; ++ } ++ ++ label(error) { ++ /* Double-check exception status. */ ++#ifdef NDEBUG ++ if (!_PyErr_Occurred(tstate)) { ++ _PyErr_SetString(tstate, PyExc_SystemError, ++ "error return without exception set"); ++ } ++#else ++ assert(_PyErr_Occurred(tstate)); ++#endif ++ ++ /* Log traceback info. */ ++ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); ++ if (!_PyFrame_IsIncomplete(frame)) { ++ PyFrameObject *f = _PyFrame_GetFrameObject(frame); ++ if (f != NULL) { ++ PyTraceBack_Here(f); ++ } ++ } ++ _PyEval_MonitorRaise(tstate, frame, next_instr-1); ++ goto exception_unwind; ++ } ++ ++ spilled label(exception_unwind) { ++ /* We can't use frame->instr_ptr here, as RERAISE may have set it */ ++ int offset = INSTR_OFFSET()-1; ++ int level, handler, lasti; ++ int handled = get_exception_handler(_PyFrame_GetCode(frame), offset, &level, &handler, &lasti); ++ if (handled == 0) { ++ // No handlers, so exit. ++ assert(_PyErr_Occurred(tstate)); ++ /* Pop remaining stack entries. */ ++ _PyStackRef *stackbase = _PyFrame_Stackbase(frame); ++ while (frame->stackpointer > stackbase) { ++ _PyStackRef ref = _PyFrame_StackPop(frame); ++ PyStackRef_XCLOSE(ref); ++ } ++ monitor_unwind(tstate, frame, next_instr-1); ++ goto exit_unwind; ++ } ++ assert(STACK_LEVEL() >= level); ++ _PyStackRef *new_top = _PyFrame_Stackbase(frame) + level; ++ assert(frame->stackpointer >= new_top); ++ while (frame->stackpointer > new_top) { ++ _PyStackRef ref = _PyFrame_StackPop(frame); ++ PyStackRef_XCLOSE(ref); ++ } ++ if (lasti) { ++ int frame_lasti = _PyInterpreterFrame_LASTI(frame); ++ PyObject *lasti = PyLong_FromLong(frame_lasti); ++ if (lasti == NULL) { ++ goto exception_unwind; ++ } ++ _PyFrame_StackPush(frame, PyStackRef_FromPyObjectSteal(lasti)); ++ } ++ ++ /* Make the raw exception data ++ available to the handler, ++ so a program can emulate the ++ Python main loop. */ ++ PyObject *exc = _PyErr_GetRaisedException(tstate); ++ _PyFrame_StackPush(frame, PyStackRef_FromPyObjectSteal(exc)); ++ next_instr = _PyFrame_GetBytecode(frame) + handler; ++ ++ int err = monitor_handled(tstate, frame, next_instr, exc); ++ if (err < 0) { ++ goto exception_unwind; ++ } ++ /* Resume normal execution */ ++#ifdef Py_DEBUG ++ if (frame->lltrace >= 5) { ++ lltrace_resume_frame(frame); ++ } ++#endif ++ RELOAD_STACK(); ++#ifdef Py_TAIL_CALL_INTERP ++ int opcode; ++#endif ++ DISPATCH(); ++ } ++ ++ spilled label(exit_unwind) { ++ assert(_PyErr_Occurred(tstate)); ++ _Py_LeaveRecursiveCallPy(tstate); ++ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); ++ // GH-99729: We need to unlink the frame *before* clearing it: ++ _PyInterpreterFrame *dying = frame; ++ frame = tstate->current_frame = dying->previous; ++ _PyEval_FrameClearAndPop(tstate, dying); ++ frame->return_offset = 0; ++ if (frame->owner == FRAME_OWNED_BY_INTERPRETER) { ++ /* Restore previous frame and exit */ ++ tstate->current_frame = frame->previous; ++ tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS; ++ return NULL; ++ } ++ next_instr = frame->instr_ptr; ++ RELOAD_STACK(); ++ goto error; ++ } ++ ++ spilled label(start_frame) { ++ int too_deep = _Py_EnterRecursivePy(tstate); ++ if (too_deep) { ++ goto exit_unwind; ++ } ++ next_instr = frame->instr_ptr; ++ ++ LLTRACE_RESUME_FRAME(); ++ ++ #ifdef Py_DEBUG ++ /* _PyEval_EvalFrameDefault() must not be called with an exception set, ++ because it can clear it (directly or indirectly) and so the ++ caller loses its exception */ ++ assert(!_PyErr_Occurred(tstate)); ++ #endif ++ RELOAD_STACK(); ++#ifdef Py_TAIL_CALL_INTERP ++ int opcode; ++#endif ++ DISPATCH(); ++ } ++ ++ ++ + // END BYTECODES // + + } +@@ -5094,7 +5294,6 @@ + exit_unwind: + handle_eval_breaker: + resume_frame: +- resume_with_error: + start_frame: + unbound_local_error: + ; +diff --git a/Python/ceval.c b/Python/ceval.c +index fd891d78391..5f8f0ae69ef 100644 +--- a/Python/ceval.c ++++ b/Python/ceval.c +@@ -27,6 +27,7 @@ + #include "pycore_range.h" // _PyRangeIterObject + #include "pycore_setobject.h" // _PySet_Update() + #include "pycore_sliceobject.h" // _PyBuildSlice_ConsumeRefs ++#include "pycore_traceback.h" // _PyTraceBack_FromFrame + #include "pycore_tuple.h" // _PyTuple_ITEMS() + #include "pycore_uop_ids.h" // Uops + #include "pycore_pyerrors.h" +@@ -42,11 +43,6 @@ + + #include // bool + +-#ifdef Py_DEBUG +- /* For debugging the interpreter: */ +-# define LLTRACE 1 /* Low-level trace feature */ +-#endif +- + #if !defined(Py_BUILD_CORE) + # error "ceval.c must be build with Py_BUILD_CORE define for best performance" + #endif +@@ -135,7 +131,7 @@ + #endif + + +-#ifdef LLTRACE ++#ifdef Py_DEBUG + static void + dump_stack(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer) + { +@@ -164,7 +160,7 @@ + PyErr_Clear(); + } + // Don't call __repr__(), it might recurse into the interpreter. +- printf("<%s at %p>", Py_TYPE(obj)->tp_name, (void *)(ptr->bits)); ++ printf("<%s at %p>", Py_TYPE(obj)->tp_name, PyStackRef_AsPyObjectBorrow(*ptr)); + } + printf("]\n"); + fflush(stdout); +@@ -178,7 +174,7 @@ + int opcode, + int oparg) + { +- if (frame->owner == FRAME_OWNED_BY_CSTACK) { ++ if (frame->owner >= FRAME_OWNED_BY_INTERPRETER) { + return; + } + dump_stack(frame, stack_pointer); +@@ -193,6 +189,7 @@ + } + fflush(stdout); + } ++ + static void + lltrace_resume_frame(_PyInterpreterFrame *frame) + { +@@ -229,12 +226,12 @@ + } + + static int +-maybe_lltrace_resume_frame(_PyInterpreterFrame *frame, _PyInterpreterFrame *skip_frame, PyObject *globals) ++maybe_lltrace_resume_frame(_PyInterpreterFrame *frame, PyObject *globals) + { + if (globals == NULL) { + return 0; + } +- if (frame == skip_frame) { ++ if (frame->owner >= FRAME_OWNED_BY_INTERPRETER) { + return 0; + } + int r = PyDict_Contains(globals, &_Py_ID(__lltrace__)); +@@ -294,6 +291,7 @@ + Py_SetRecursionLimit(int new_limit) + { + PyInterpreterState *interp = _PyInterpreterState_GET(); ++ _PyEval_StopTheWorld(interp); + interp->ceval.recursion_limit = new_limit; + _Py_FOR_EACH_TSTATE_BEGIN(interp, p) { + int depth = p->py_recursion_limit - p->py_recursion_remaining; +@@ -301,6 +299,7 @@ + p->py_recursion_remaining = new_limit - depth; + } + _Py_FOR_EACH_TSTATE_END(interp); ++ _PyEval_StartTheWorld(interp); + } + + /* The function _Py_EnterRecursiveCallTstate() only calls _Py_CheckRecursiveCall() +@@ -363,6 +362,7 @@ + [NB_INPLACE_SUBTRACT] = PyNumber_InPlaceSubtract, + [NB_INPLACE_TRUE_DIVIDE] = PyNumber_InPlaceTrueDivide, + [NB_INPLACE_XOR] = PyNumber_InPlaceXor, ++ [NB_SUBSCR] = PyObject_GetItem, + }; + + const conversion_func _PyEval_ConversionFuncs[4] = { +@@ -764,15 +764,10 @@ + #define PY_EVAL_C_STACK_UNITS 2 + + +-/* _PyEval_EvalFrameDefault is too large to optimize for speed with PGO on MSVC +- when the JIT is enabled or GIL is disabled. Disable that optimization around +- this function only. If this is fixed upstream, we should gate this on the +- version of MSVC. ++/* _PyEval_EvalFrameDefault is too large to optimize for speed with PGO on MSVC. + */ + #if (defined(_MSC_VER) && \ +- defined(_Py_USING_PGO) && \ +- (defined(_Py_JIT) || \ +- defined(Py_GIL_DISABLED))) ++ defined(_Py_USING_PGO)) + #define DO_NOT_OPTIMIZE_INTERP_LOOP + #endif + +@@ -781,13 +776,18 @@ + /* This setting is reversed below following _PyEval_EvalFrameDefault */ + #endif + ++#ifdef Py_TAIL_CALL_INTERP ++#include "opcode_targets.h" ++#include "generated_cases.c.h" ++#endif ++ + PyObject* _Py_HOT_FUNCTION + _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwflag) + { + _Py_EnsureTstateNotNULL(tstate); + CALL_STAT_INC(pyeval_calls); + +-#if USE_COMPUTED_GOTOS ++#if USE_COMPUTED_GOTOS && !defined(Py_TAIL_CALL_INTERP) + /* Import the static jump table */ + #include "opcode_targets.h" + #endif +@@ -795,17 +795,24 @@ + #ifdef Py_STATS + int lastopcode = 0; + #endif ++#ifndef Py_TAIL_CALL_INTERP + uint8_t opcode; /* Current opcode */ + int oparg; /* Current opcode argument, if any */ +-#ifdef LLTRACE +- int lltrace = 0; + #endif ++ _PyInterpreterFrame entry_frame; + +- _PyInterpreterFrame entry_frame; +- ++ if (_Py_EnterRecursiveCallTstate(tstate, "")) { ++ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); ++ _PyEval_FrameClearAndPop(tstate, frame); ++ return NULL; ++ } + ++ /* Local "register" variables. ++ * These are cached values from the frame and code object. */ ++ _Py_CODEUNIT *next_instr; ++ _PyStackRef *stack_pointer; + +-#ifdef Py_DEBUG ++#if defined(Py_DEBUG) && !defined(Py_STACKREF_DEBUG) + /* Set these to invalid but identifiable values for debugging. */ + entry_frame.f_funcobj = (_PyStackRef){.bits = 0xaaa0}; + entry_frame.f_locals = (PyObject*)0xaaa1; +@@ -816,218 +823,61 @@ + entry_frame.f_executable = PyStackRef_None; + entry_frame.instr_ptr = (_Py_CODEUNIT *)_Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS + 1; + entry_frame.stackpointer = entry_frame.localsplus; +- entry_frame.owner = FRAME_OWNED_BY_CSTACK; ++ entry_frame.owner = FRAME_OWNED_BY_INTERPRETER; + entry_frame.visited = 0; + entry_frame.return_offset = 0; ++#ifdef Py_DEBUG ++ entry_frame.lltrace = 0; ++#endif + /* Push frame */ + entry_frame.previous = tstate->current_frame; + frame->previous = &entry_frame; + tstate->current_frame = frame; + + tstate->c_recursion_remaining -= (PY_EVAL_C_STACK_UNITS - 1); +- if (_Py_EnterRecursiveCallTstate(tstate, "")) { +- tstate->c_recursion_remaining--; +- tstate->py_recursion_remaining--; +- goto exit_unwind; +- } + + /* support for generator.throw() */ + if (throwflag) { + if (_Py_EnterRecursivePy(tstate)) { +- goto exit_unwind; ++ goto early_exit; + } +- /* Because this avoids the RESUME, +- * we need to update instrumentation */ + #ifdef Py_GIL_DISABLED + /* Load thread-local bytecode */ + if (frame->tlbc_index != ((_PyThreadStateImpl *)tstate)->tlbc_index) { + _Py_CODEUNIT *bytecode = + _PyEval_GetExecutableCode(tstate, _PyFrame_GetCode(frame)); + if (bytecode == NULL) { +- goto error; ++ goto early_exit; + } + ptrdiff_t off = frame->instr_ptr - _PyFrame_GetBytecode(frame); + frame->tlbc_index = ((_PyThreadStateImpl *)tstate)->tlbc_index; + frame->instr_ptr = bytecode + off; + } + #endif ++ /* Because this avoids the RESUME, we need to update instrumentation */ + _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp); +- monitor_throw(tstate, frame, frame->instr_ptr); +- /* TO DO -- Monitor throw entry. */ +- goto resume_with_error; ++ next_instr = frame->instr_ptr; ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ monitor_throw(tstate, frame, next_instr); ++#ifdef Py_TAIL_CALL_INTERP ++ return _TAIL_CALL_error(frame, stack_pointer, tstate, next_instr, 0); ++#else ++ goto error; ++#endif + } + +- /* Local "register" variables. +- * These are cached values from the frame and code object. */ +- _Py_CODEUNIT *next_instr; +- _PyStackRef *stack_pointer; +- + #if defined(_Py_TIER2) && !defined(_Py_JIT) + /* Tier 2 interpreter state */ + _PyExecutorObject *current_executor = NULL; + const _PyUOpInstruction *next_uop = NULL; + #endif + +-start_frame: +- if (_Py_EnterRecursivePy(tstate)) { +- goto exit_unwind; +- } +- +- next_instr = frame->instr_ptr; +-resume_frame: +- stack_pointer = _PyFrame_GetStackPointer(frame); +- +-#ifdef LLTRACE +- lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); +- if (lltrace < 0) { +- goto exit_unwind; +- } +-#endif +- +-#ifdef Py_DEBUG +- /* _PyEval_EvalFrameDefault() must not be called with an exception set, +- because it can clear it (directly or indirectly) and so the +- caller loses its exception */ +- assert(!_PyErr_Occurred(tstate)); +-#endif +- +- DISPATCH(); +- +- { +- /* Start instructions */ +-#if !USE_COMPUTED_GOTOS +- dispatch_opcode: +- switch (opcode) +-#endif +- { +- +-#include "generated_cases.c.h" +- +- +-#if USE_COMPUTED_GOTOS +- _unknown_opcode: ++#ifdef Py_TAIL_CALL_INTERP ++ return _TAIL_CALL_start_frame(frame, NULL, tstate, NULL, 0); + #else +- EXTRA_CASES // From pycore_opcode_metadata.h, a 'case' for each unused opcode +-#endif +- /* Tell C compilers not to hold the opcode variable in the loop. +- next_instr points the current instruction without TARGET(). */ +- opcode = next_instr->op.code; +- _PyErr_Format(tstate, PyExc_SystemError, +- "%U:%d: unknown opcode %d", +- _PyFrame_GetCode(frame)->co_filename, +- PyUnstable_InterpreterFrame_GetLine(frame), +- opcode); +- goto error; +- +- } /* End instructions */ +- +- /* This should never be reached. Every opcode should end with DISPATCH() +- or goto error. */ +- Py_UNREACHABLE(); +- +-pop_4_error: +- STACK_SHRINK(1); +-pop_3_error: +- STACK_SHRINK(1); +-pop_2_error: +- STACK_SHRINK(1); +-pop_1_error: +- STACK_SHRINK(1); +-error: +- /* Double-check exception status. */ +-#ifdef NDEBUG +- if (!_PyErr_Occurred(tstate)) { +- _PyErr_SetString(tstate, PyExc_SystemError, +- "error return without exception set"); +- } +-#else +- assert(_PyErr_Occurred(tstate)); +-#endif +- +- /* Log traceback info. */ +- assert(frame != &entry_frame); +- if (!_PyFrame_IsIncomplete(frame)) { +- PyFrameObject *f = _PyFrame_GetFrameObject(frame); +- if (f != NULL) { +- PyTraceBack_Here(f); +- } +- } +- _PyEval_MonitorRaise(tstate, frame, next_instr-1); +-exception_unwind: +- { +- /* We can't use frame->instr_ptr here, as RERAISE may have set it */ +- int offset = INSTR_OFFSET()-1; +- int level, handler, lasti; +- if (get_exception_handler(_PyFrame_GetCode(frame), offset, &level, &handler, &lasti) == 0) { +- // No handlers, so exit. +- assert(_PyErr_Occurred(tstate)); +- +- /* Pop remaining stack entries. */ +- _PyStackRef *stackbase = _PyFrame_Stackbase(frame); +- while (stack_pointer > stackbase) { +- PyStackRef_XCLOSE(POP()); +- } +- assert(STACK_LEVEL() == 0); +- _PyFrame_SetStackPointer(frame, stack_pointer); +- monitor_unwind(tstate, frame, next_instr-1); +- goto exit_unwind; +- } +- +- assert(STACK_LEVEL() >= level); +- _PyStackRef *new_top = _PyFrame_Stackbase(frame) + level; +- while (stack_pointer > new_top) { +- PyStackRef_XCLOSE(POP()); +- } +- if (lasti) { +- int frame_lasti = _PyInterpreterFrame_LASTI(frame); +- PyObject *lasti = PyLong_FromLong(frame_lasti); +- if (lasti == NULL) { +- goto exception_unwind; +- } +- PUSH(PyStackRef_FromPyObjectSteal(lasti)); +- } +- +- /* Make the raw exception data +- available to the handler, +- so a program can emulate the +- Python main loop. */ +- PyObject *exc = _PyErr_GetRaisedException(tstate); +- PUSH(PyStackRef_FromPyObjectSteal(exc)); +- next_instr = _PyFrame_GetBytecode(frame) + handler; +- +- if (monitor_handled(tstate, frame, next_instr, exc) < 0) { +- goto exception_unwind; +- } +- /* Resume normal execution */ +-#ifdef LLTRACE +- if (lltrace >= 5) { +- lltrace_resume_frame(frame); +- } ++ goto start_frame; ++# include "generated_cases.c.h" + #endif +- DISPATCH(); +- } +- } +- +-exit_unwind: +- assert(_PyErr_Occurred(tstate)); +- _Py_LeaveRecursiveCallPy(tstate); +- assert(frame != &entry_frame); +- // GH-99729: We need to unlink the frame *before* clearing it: +- _PyInterpreterFrame *dying = frame; +- frame = tstate->current_frame = dying->previous; +- _PyEval_FrameClearAndPop(tstate, dying); +- frame->return_offset = 0; +- if (frame == &entry_frame) { +- /* Restore previous frame and exit */ +- tstate->current_frame = frame->previous; +- tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS; +- return NULL; +- } +- +-resume_with_error: +- next_instr = frame->instr_ptr; +- stack_pointer = _PyFrame_GetStackPointer(frame); +- goto error; + + + #ifdef _Py_TIER2 +@@ -1042,9 +892,6 @@ + #undef LOAD_IP + #define LOAD_IP(UNUSED) (void)0 + +-#undef GOTO_ERROR +-#define GOTO_ERROR(LABEL) goto LABEL ## _tier_two +- + #ifdef Py_STATS + // Disable these macros that apply to Tier 1 stats when we are in Tier 2 + #undef STAT_INC +@@ -1058,13 +905,6 @@ + #undef ENABLE_SPECIALIZATION_FT + #define ENABLE_SPECIALIZATION_FT 0 + +-#ifdef Py_DEBUG +- #define DPRINTF(level, ...) \ +- if (lltrace >= (level)) { printf(__VA_ARGS__); } +-#else +- #define DPRINTF(level, ...) +-#endif +- + ; // dummy statement after a label, before a declaration + uint16_t uopcode; + #ifdef Py_STATS +@@ -1077,7 +917,7 @@ + for (;;) { + uopcode = next_uop->opcode; + #ifdef Py_DEBUG +- if (lltrace >= 3) { ++ if (frame->lltrace >= 3) { + dump_stack(frame, stack_pointer); + if (next_uop->opcode == _START_EXECUTOR) { + printf("%4d uop: ", 0); +@@ -1119,7 +959,7 @@ + + jump_to_error_target: + #ifdef Py_DEBUG +- if (lltrace >= 2) { ++ if (frame->lltrace >= 2) { + printf("Error: [UOp "); + _PyUOpPrint(&next_uop[-1]); + printf(" @ %d -> %s]\n", +@@ -1127,50 +967,35 @@ + _PyOpcode_OpName[frame->instr_ptr->op.code]); + } + #endif +- assert (next_uop[-1].format == UOP_FORMAT_JUMP); ++ assert(next_uop[-1].format == UOP_FORMAT_JUMP); + uint16_t target = uop_get_error_target(&next_uop[-1]); + next_uop = current_executor->trace + target; + goto tier2_dispatch; + +-error_tier_two: +- OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); +- assert(next_uop[-1].format == UOP_FORMAT_TARGET); +- frame->return_offset = 0; // Don't leave this random +- _PyFrame_SetStackPointer(frame, stack_pointer); +- Py_DECREF(current_executor); +- tstate->previous_executor = NULL; +- goto resume_with_error; +- + jump_to_jump_target: + assert(next_uop[-1].format == UOP_FORMAT_JUMP); + target = uop_get_jump_target(&next_uop[-1]); + next_uop = current_executor->trace + target; + goto tier2_dispatch; + +-exit_to_tier1_dynamic: +- next_instr = frame->instr_ptr; +- goto goto_to_tier1; +-exit_to_tier1: +- assert(next_uop[-1].format == UOP_FORMAT_TARGET); +- next_instr = next_uop[-1].target + _PyFrame_GetBytecode(frame); +-goto_to_tier1: +-#ifdef Py_DEBUG +- if (lltrace >= 2) { +- printf("DEOPT: [UOp "); +- _PyUOpPrint(&next_uop[-1]); +- printf(" -> %s]\n", +- _PyOpcode_OpName[next_instr->op.code]); +- } +-#endif +- OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); +- Py_DECREF(current_executor); +- tstate->previous_executor = NULL; +- DISPATCH(); +- + #endif // _Py_JIT + + #endif // _Py_TIER2 + ++early_exit: ++ assert(_PyErr_Occurred(tstate)); ++ _Py_LeaveRecursiveCallPy(tstate); ++ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); ++ // GH-99729: We need to unlink the frame *before* clearing it: ++ _PyInterpreterFrame *dying = frame; ++ frame = tstate->current_frame = dying->previous; ++ _PyEval_FrameClearAndPop(tstate, dying); ++ frame->return_offset = 0; ++ assert(frame->owner == FRAME_OWNED_BY_INTERPRETER); ++ /* Restore previous frame and exit */ ++ tstate->current_frame = frame->previous; ++ tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS; ++ return NULL; + } + + #ifdef DO_NOT_OPTIMIZE_INTERP_LOOP +@@ -1522,7 +1347,12 @@ + u = (PyObject *)&_Py_SINGLETON(tuple_empty); + } + else { +- u = _PyTuple_FromStackRefSteal(args + n, argcount - n); ++ u = _PyTuple_FromStackRefStealOnSuccess(args + n, argcount - n); ++ if (u == NULL) { ++ for (Py_ssize_t i = n; i < argcount; i++) { ++ PyStackRef_CLOSE(args[i]); ++ } ++ } + } + if (u == NULL) { + goto fail_post_positional; +@@ -1810,27 +1640,48 @@ + { + bool has_dict = (kwargs != NULL && PyDict_GET_SIZE(kwargs) > 0); + PyObject *kwnames = NULL; +- PyObject *const *newargs; ++ _PyStackRef *newargs; ++ PyObject *const *object_array = NULL; ++ _PyStackRef stack_array[8]; + if (has_dict) { +- newargs = _PyStack_UnpackDict(tstate, _PyTuple_ITEMS(callargs), nargs, kwargs, &kwnames); +- if (newargs == NULL) { ++ object_array = _PyStack_UnpackDict(tstate, _PyTuple_ITEMS(callargs), nargs, kwargs, &kwnames); ++ if (object_array == NULL) { + PyStackRef_CLOSE(func); + goto error; + } ++ size_t total_args = nargs + PyDict_GET_SIZE(kwargs); ++ assert(sizeof(PyObject *) == sizeof(_PyStackRef)); ++ newargs = (_PyStackRef *)object_array; ++ for (size_t i = 0; i < total_args; i++) { ++ newargs[i] = PyStackRef_FromPyObjectSteal(object_array[i]); ++ } + } + else { +- newargs = &PyTuple_GET_ITEM(callargs, 0); +- /* We need to incref all our args since the new frame steals the references. */ +- for (Py_ssize_t i = 0; i < nargs; ++i) { +- Py_INCREF(PyTuple_GET_ITEM(callargs, i)); ++ if (nargs <= 8) { ++ newargs = stack_array; ++ } ++ else { ++ newargs = PyMem_Malloc(sizeof(_PyStackRef) *nargs); ++ if (newargs == NULL) { ++ PyErr_NoMemory(); ++ PyStackRef_CLOSE(func); ++ goto error; ++ } ++ } ++ /* We need to create a new reference for all our args since the new frame steals them. */ ++ for (Py_ssize_t i = 0; i < nargs; i++) { ++ newargs[i] = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(callargs, i)); + } + } + _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( + tstate, func, locals, +- (_PyStackRef const *)newargs, nargs, kwnames, previous ++ newargs, nargs, kwnames, previous + ); + if (has_dict) { +- _PyStack_UnpackDict_FreeNoDecRef(newargs, kwnames); ++ _PyStack_UnpackDict_FreeNoDecRef(object_array, kwnames); ++ } ++ else if (nargs > 8) { ++ PyMem_Free((void *)newargs); + } + /* No need to decref func here because the reference has been stolen by + _PyEvalFramePushAndInit. +@@ -1850,21 +1701,39 @@ + PyObject* const* args, size_t argcount, + PyObject *kwnames) + { ++ size_t total_args = argcount; ++ if (kwnames) { ++ total_args += PyTuple_GET_SIZE(kwnames); ++ } ++ _PyStackRef stack_array[8]; ++ _PyStackRef *arguments; ++ if (total_args <= 8) { ++ arguments = stack_array; ++ } ++ else { ++ arguments = PyMem_Malloc(sizeof(_PyStackRef) * total_args); ++ if (arguments == NULL) { ++ return PyErr_NoMemory(); ++ } ++ } + /* _PyEvalFramePushAndInit consumes the references + * to func, locals and all its arguments */ + Py_XINCREF(locals); + for (size_t i = 0; i < argcount; i++) { +- Py_INCREF(args[i]); ++ arguments[i] = PyStackRef_FromPyObjectNew(args[i]); + } + if (kwnames) { + Py_ssize_t kwcount = PyTuple_GET_SIZE(kwnames); + for (Py_ssize_t i = 0; i < kwcount; i++) { +- Py_INCREF(args[i+argcount]); ++ arguments[i+argcount] = PyStackRef_FromPyObjectNew(args[i+argcount]); + } + } + _PyInterpreterFrame *frame = _PyEvalFramePushAndInit( + tstate, PyStackRef_FromPyObjectNew(func), locals, +- (_PyStackRef const *)args, argcount, kwnames, NULL); ++ arguments, argcount, kwnames, NULL); ++ if (total_args > 8) { ++ PyMem_Free(arguments); ++ } + if (frame == NULL) { + return NULL; + } +@@ -2053,8 +1922,8 @@ + */ + + int +-_PyEval_ExceptionGroupMatch(PyObject* exc_value, PyObject *match_type, +- PyObject **match, PyObject **rest) ++_PyEval_ExceptionGroupMatch(_PyInterpreterFrame *frame, PyObject* exc_value, ++ PyObject *match_type, PyObject **match, PyObject **rest) + { + if (Py_IsNone(exc_value)) { + *match = Py_NewRef(Py_None); +@@ -2080,6 +1949,15 @@ + if (wrapped == NULL) { + return -1; + } ++ PyFrameObject *f = _PyFrame_GetFrameObject(frame); ++ if (f != NULL) { ++ PyObject *tb = _PyTraceBack_FromFrame(NULL, f); ++ if (tb == NULL) { ++ return -1; ++ } ++ PyException_SetTraceback(wrapped, tb); ++ Py_DECREF(tb); ++ } + *match = wrapped; + } + *rest = Py_NewRef(Py_None); +@@ -2095,8 +1973,25 @@ + if (pair == NULL) { + return -1; + } +- assert(PyTuple_CheckExact(pair)); +- assert(PyTuple_GET_SIZE(pair) == 2); ++ ++ if (!PyTuple_CheckExact(pair)) { ++ PyErr_Format(PyExc_TypeError, ++ "%.200s.split must return a tuple, not %.200s", ++ Py_TYPE(exc_value)->tp_name, Py_TYPE(pair)->tp_name); ++ Py_DECREF(pair); ++ return -1; ++ } ++ ++ // allow tuples of length > 2 for backwards compatibility ++ if (PyTuple_GET_SIZE(pair) < 2) { ++ PyErr_Format(PyExc_TypeError, ++ "%.200s.split must return a 2-tuple, " ++ "got tuple of size %zd", ++ Py_TYPE(exc_value)->tp_name, PyTuple_GET_SIZE(pair)); ++ Py_DECREF(pair); ++ return -1; ++ } ++ + *match = Py_NewRef(PyTuple_GET_ITEM(pair, 0)); + *rest = Py_NewRef(PyTuple_GET_ITEM(pair, 1)); + Py_DECREF(pair); +@@ -2860,7 +2755,7 @@ + } + } + +- if (origin == NULL) { ++ if (origin == NULL && PyModule_Check(v)) { + // Fall back to __file__ for diagnostics if we don't have + // an origin that is a location + origin = PyModule_GetFilenameObject(v); +diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c +index 1f811e72406..416eec01052 100644 +--- a/Python/ceval_gil.c ++++ b/Python/ceval_gil.c +@@ -995,7 +995,7 @@ + void + _Py_FinishPendingCalls(PyThreadState *tstate) + { +- assert(PyGILState_Check()); ++ _Py_AssertHoldsTstate(); + assert(_PyThreadState_CheckConsistency(tstate)); + + struct _pending_calls *pending = &tstate->interp->ceval.pending; +@@ -1056,7 +1056,7 @@ + int + Py_MakePendingCalls(void) + { +- assert(PyGILState_Check()); ++ _Py_AssertHoldsTstate(); + + PyThreadState *tstate = _PyThreadState_GET(); + assert(_PyThreadState_CheckConsistency(tstate)); +diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h +index 9250b86e42c..0a4f65feb3b 100644 +--- a/Python/ceval_macros.h ++++ b/Python/ceval_macros.h +@@ -70,29 +70,59 @@ + #define INSTRUCTION_STATS(op) ((void)0) + #endif + +-#if USE_COMPUTED_GOTOS ++#define TAIL_CALL_PARAMS _PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate, _Py_CODEUNIT *next_instr, int oparg ++#define TAIL_CALL_ARGS frame, stack_pointer, tstate, next_instr, oparg ++ ++#ifdef Py_TAIL_CALL_INTERP ++ // Note: [[clang::musttail]] works for GCC 15, but not __attribute__((musttail)) at the moment. ++# define Py_MUSTTAIL [[clang::musttail]] ++# define Py_PRESERVE_NONE_CC __attribute__((preserve_none)) ++ Py_PRESERVE_NONE_CC typedef PyObject* (*py_tail_call_funcptr)(TAIL_CALL_PARAMS); ++ ++# define TARGET(op) Py_PRESERVE_NONE_CC PyObject *_TAIL_CALL_##op(TAIL_CALL_PARAMS) ++# define DISPATCH_GOTO() \ ++ do { \ ++ Py_MUSTTAIL return (INSTRUCTION_TABLE[opcode])(TAIL_CALL_ARGS); \ ++ } while (0) ++# define JUMP_TO_LABEL(name) \ ++ do { \ ++ Py_MUSTTAIL return (_TAIL_CALL_##name)(TAIL_CALL_ARGS); \ ++ } while (0) ++# define JUMP_TO_PREDICTED(name) \ ++ do { \ ++ Py_MUSTTAIL return (_TAIL_CALL_##name)(frame, stack_pointer, tstate, this_instr, oparg); \ ++ } while (0) ++# define LABEL(name) TARGET(name) ++#elif USE_COMPUTED_GOTOS + # define TARGET(op) TARGET_##op: + # define DISPATCH_GOTO() goto *opcode_targets[opcode] ++# define JUMP_TO_LABEL(name) goto name; ++# define JUMP_TO_PREDICTED(name) goto PREDICTED_##name; ++# define LABEL(name) name: + #else + # define TARGET(op) case op: TARGET_##op: + # define DISPATCH_GOTO() goto dispatch_opcode ++# define JUMP_TO_LABEL(name) goto name; ++# define JUMP_TO_PREDICTED(name) goto PREDICTED_##name; ++# define LABEL(name) name: + #endif + + /* PRE_DISPATCH_GOTO() does lltrace if enabled. Normally a no-op */ +-#ifdef LLTRACE +-#define PRE_DISPATCH_GOTO() if (lltrace >= 5) { \ ++#ifdef Py_DEBUG ++#define PRE_DISPATCH_GOTO() if (frame->lltrace >= 5) { \ + lltrace_instruction(frame, stack_pointer, next_instr, opcode, oparg); } + #else + #define PRE_DISPATCH_GOTO() ((void)0) + #endif + +-#if LLTRACE ++#ifdef Py_DEBUG + #define LLTRACE_RESUME_FRAME() \ + do { \ +- lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); \ ++ int lltrace = maybe_lltrace_resume_frame(frame, GLOBALS()); \ + if (lltrace < 0) { \ +- goto exit_unwind; \ ++ JUMP_TO_LABEL(exit_unwind); \ + } \ ++ frame->lltrace = lltrace; \ + } while (0) + #else + #define LLTRACE_RESUME_FRAME() ((void)0) +@@ -128,12 +158,9 @@ + assert((NEW_FRAME)->previous == frame); \ + frame = tstate->current_frame = (NEW_FRAME); \ + CALL_STAT_INC(inlined_py_calls); \ +- goto start_frame; \ ++ JUMP_TO_LABEL(start_frame); \ + } while (0) + +-// Use this instead of 'goto error' so Tier 2 can go to a different label +-#define GOTO_ERROR(LABEL) goto LABEL +- + /* Tuple access macros */ + + #ifndef Py_DEBUG +@@ -165,35 +192,6 @@ + #define JUMPBY(x) (next_instr += (x)) + #define SKIP_OVER(x) (next_instr += (x)) + +-/* OpCode prediction macros +- Some opcodes tend to come in pairs thus making it possible to +- predict the second code when the first is run. For example, +- COMPARE_OP is often followed by POP_JUMP_IF_FALSE or POP_JUMP_IF_TRUE. +- +- Verifying the prediction costs a single high-speed test of a register +- variable against a constant. If the pairing was good, then the +- processor's own internal branch predication has a high likelihood of +- success, resulting in a nearly zero-overhead transition to the +- next opcode. A successful prediction saves a trip through the eval-loop +- including its unpredictable switch-case branch. Combined with the +- processor's internal branch prediction, a successful PREDICT has the +- effect of making the two opcodes run as if they were a single new opcode +- with the bodies combined. +- +- If collecting opcode statistics, your choices are to either keep the +- predictions turned-on and interpret the results as if some opcodes +- had been combined or turn-off predictions so that the opcode frequency +- counter updates for both opcodes. +- +- Opcode prediction is disabled with threaded code, since the latter allows +- the CPU to record separate branch prediction information for each +- opcode. +- +-*/ +- +-#define PREDICT_ID(op) PRED_##op +-#define PREDICTED(op) PREDICT_ID(op): +- + + /* Stack manipulation macros */ + +@@ -238,7 +236,7 @@ + #endif + + #define WITHIN_STACK_BOUNDS() \ +- (frame == &entry_frame || (STACK_LEVEL() >= 0 && STACK_LEVEL() <= STACK_SIZE())) ++ (frame->owner == FRAME_OWNED_BY_INTERPRETER || (STACK_LEVEL() >= 0 && STACK_LEVEL() <= STACK_SIZE())) + + /* Data access macros */ + #define FRAME_CO_CONSTS (_PyFrame_GetCode(frame)->co_consts) +@@ -249,17 +247,6 @@ + #define LOCALS_ARRAY (frame->localsplus) + #define GETLOCAL(i) (frame->localsplus[i]) + +-/* The SETLOCAL() macro must not DECREF the local variable in-place and +- then store the new value; it must copy the old value to a temporary +- value, then store the new value, and then DECREF the temporary value. +- This is because it is possible that during the DECREF the frame is +- accessed by other code (e.g. a __del__ method or gc.collect()) and the +- variable would be pointing to already-freed memory. */ +-#define SETLOCAL(i, value) do { _PyStackRef tmp = GETLOCAL(i); \ +- GETLOCAL(i) = value; \ +- PyStackRef_XCLOSE(tmp); } while (0) +- +-#define GO_TO_INSTRUCTION(op) goto PREDICT_ID(op) + + #ifdef Py_STATS + #define UPDATE_MISS_STATS(INSTNAME) \ +@@ -275,14 +262,6 @@ + #define UPDATE_MISS_STATS(INSTNAME) ((void)0) + #endif + +-#define DEOPT_IF(COND, INSTNAME) \ +- if ((COND)) { \ +- /* This is only a single jump on release builds! */ \ +- UPDATE_MISS_STATS((INSTNAME)); \ +- assert(_PyOpcode_Deopt[opcode] == (INSTNAME)); \ +- GO_TO_INSTRUCTION(INSTNAME); \ +- } +- + + // Try to lock an object in the free threading build, if it's not already + // locked. Use with a DEOPT_IF() to deopt if the object is already locked. +@@ -300,7 +279,7 @@ + // avoid any potentially escaping calls (like PyStackRef_CLOSE) while the + // object is locked. + #ifdef Py_GIL_DISABLED +-# define LOCK_OBJECT(op) PyMutex_LockFast(&(_PyObject_CAST(op))->ob_mutex._bits) ++# define LOCK_OBJECT(op) PyMutex_LockFast(&(_PyObject_CAST(op))->ob_mutex) + # define UNLOCK_OBJECT(op) PyMutex_Unlock(&(_PyObject_CAST(op))->ob_mutex) + #else + # define LOCK_OBJECT(op) (1) +@@ -363,11 +342,11 @@ + next_instr = dest; \ + } else { \ + _PyFrame_SetStackPointer(frame, stack_pointer); \ +- next_instr = _Py_call_instrumentation_jump(tstate, event, frame, src, dest); \ ++ next_instr = _Py_call_instrumentation_jump(this_instr, tstate, event, frame, src, dest); \ + stack_pointer = _PyFrame_GetStackPointer(frame); \ + if (next_instr == NULL) { \ + next_instr = (dest)+1; \ +- goto error; \ ++ JUMP_TO_LABEL(error); \ + } \ + } \ + } while (0); +@@ -405,15 +384,19 @@ + #define GOTO_TIER_TWO(EXECUTOR) \ + do { \ + OPT_STAT_INC(traces_executed); \ +- jit_func jitted = (EXECUTOR)->jit_code; \ ++ _PyExecutorObject *_executor = (EXECUTOR); \ ++ jit_func jitted = _executor->jit_code; \ ++ /* Keep the shim frame alive via the executor: */ \ ++ Py_INCREF(_executor); \ + next_instr = jitted(frame, stack_pointer, tstate); \ +- Py_DECREF(tstate->previous_executor); \ +- tstate->previous_executor = NULL; \ ++ Py_DECREF(_executor); \ ++ Py_CLEAR(tstate->previous_executor); \ + frame = tstate->current_frame; \ ++ stack_pointer = _PyFrame_GetStackPointer(frame); \ + if (next_instr == NULL) { \ +- goto resume_with_error; \ ++ next_instr = frame->instr_ptr; \ ++ goto error; \ + } \ +- stack_pointer = _PyFrame_GetStackPointer(frame); \ + DISPATCH(); \ + } while (0) + #else +@@ -426,31 +409,32 @@ + } while (0) + #endif + +-#define GOTO_TIER_ONE(TARGET) \ +-do { \ +- Py_DECREF(tstate->previous_executor); \ +- tstate->previous_executor = NULL; \ +- next_instr = target; \ +- DISPATCH(); \ ++#define GOTO_TIER_ONE(TARGET) \ ++do { \ ++ next_instr = (TARGET); \ ++ OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); \ ++ Py_CLEAR(tstate->previous_executor); \ ++ if (next_instr == NULL) { \ ++ next_instr = frame->instr_ptr; \ ++ goto error; \ ++ } \ ++ DISPATCH(); \ + } while (0) + +-#define CURRENT_OPARG() (next_uop[-1].oparg) +- ++#define CURRENT_OPARG() (next_uop[-1].oparg) + #define CURRENT_OPERAND0() (next_uop[-1].operand0) + #define CURRENT_OPERAND1() (next_uop[-1].operand1) ++#define CURRENT_TARGET() (next_uop[-1].target) + + #define JUMP_TO_JUMP_TARGET() goto jump_to_jump_target + #define JUMP_TO_ERROR() goto jump_to_error_target +-#define GOTO_UNWIND() goto error_tier_two +-#define EXIT_TO_TIER1() goto exit_to_tier1 +-#define EXIT_TO_TIER1_DYNAMIC() goto exit_to_tier1_dynamic; + + /* Stackref macros */ + + /* How much scratch space to give stackref to PyObject* conversion. */ + #define MAX_STACKREF_SCRATCH 10 + +-#ifdef Py_GIL_DISABLED ++#if defined(Py_GIL_DISABLED) || defined(Py_STACKREF_DEBUG) + #define STACKREFS_TO_PYOBJECTS(ARGS, ARG_COUNT, NAME) \ + /* +1 because vectorcall might use -1 to write self */ \ + PyObject *NAME##_temp[MAX_STACKREF_SCRATCH+1]; \ +@@ -461,7 +445,7 @@ + assert(NAME != NULL); + #endif + +-#ifdef Py_GIL_DISABLED ++#if defined(Py_GIL_DISABLED) || defined(Py_STACKREF_DEBUG) + #define STACKREFS_TO_PYOBJECTS_CLEANUP(NAME) \ + /* +1 because we +1 previously */ \ + _PyObjectArray_Free(NAME - 1, NAME##_temp); +@@ -470,7 +454,7 @@ + (void)(NAME); + #endif + +-#ifdef Py_GIL_DISABLED ++#if defined(Py_GIL_DISABLED) || defined(Py_STACKREF_DEBUG) + #define CONVERSION_FAILED(NAME) ((NAME) == NULL) + #else + #define CONVERSION_FAILED(NAME) (0) +diff --git a/Python/clinic/_warnings.c.h b/Python/clinic/_warnings.c.h +index 9a2c33f2ea8..bcb4b344fa4 100644 +--- a/Python/clinic/_warnings.c.h ++++ b/Python/clinic/_warnings.c.h +@@ -9,6 +9,40 @@ + #include "pycore_abstract.h" // _PyNumber_Index() + #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() + ++PyDoc_STRVAR(warnings_acquire_lock__doc__, ++"_acquire_lock($module, /)\n" ++"--\n" ++"\n"); ++ ++#define WARNINGS_ACQUIRE_LOCK_METHODDEF \ ++ {"_acquire_lock", (PyCFunction)warnings_acquire_lock, METH_NOARGS, warnings_acquire_lock__doc__}, ++ ++static PyObject * ++warnings_acquire_lock_impl(PyObject *module); ++ ++static PyObject * ++warnings_acquire_lock(PyObject *module, PyObject *Py_UNUSED(ignored)) ++{ ++ return warnings_acquire_lock_impl(module); ++} ++ ++PyDoc_STRVAR(warnings_release_lock__doc__, ++"_release_lock($module, /)\n" ++"--\n" ++"\n"); ++ ++#define WARNINGS_RELEASE_LOCK_METHODDEF \ ++ {"_release_lock", (PyCFunction)warnings_release_lock, METH_NOARGS, warnings_release_lock__doc__}, ++ ++static PyObject * ++warnings_release_lock_impl(PyObject *module); ++ ++static PyObject * ++warnings_release_lock(PyObject *module, PyObject *Py_UNUSED(ignored)) ++{ ++ return warnings_release_lock_impl(module); ++} ++ + PyDoc_STRVAR(warnings_warn__doc__, + "warn($module, /, message, category=None, stacklevel=1, source=None, *,\n" + " skip_file_prefixes=)\n" +@@ -230,20 +264,20 @@ + return return_value; + } + +-PyDoc_STRVAR(warnings_filters_mutated__doc__, +-"_filters_mutated($module, /)\n" ++PyDoc_STRVAR(warnings_filters_mutated_lock_held__doc__, ++"_filters_mutated_lock_held($module, /)\n" + "--\n" + "\n"); + +-#define WARNINGS_FILTERS_MUTATED_METHODDEF \ +- {"_filters_mutated", (PyCFunction)warnings_filters_mutated, METH_NOARGS, warnings_filters_mutated__doc__}, ++#define WARNINGS_FILTERS_MUTATED_LOCK_HELD_METHODDEF \ ++ {"_filters_mutated_lock_held", (PyCFunction)warnings_filters_mutated_lock_held, METH_NOARGS, warnings_filters_mutated_lock_held__doc__}, + + static PyObject * +-warnings_filters_mutated_impl(PyObject *module); ++warnings_filters_mutated_lock_held_impl(PyObject *module); + + static PyObject * +-warnings_filters_mutated(PyObject *module, PyObject *Py_UNUSED(ignored)) ++warnings_filters_mutated_lock_held(PyObject *module, PyObject *Py_UNUSED(ignored)) + { +- return warnings_filters_mutated_impl(module); ++ return warnings_filters_mutated_lock_held_impl(module); + } +-/*[clinic end generated code: output=ed02c0f521a03a37 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=d9d32a8b59a30683 input=a9049054013a1b77]*/ +diff --git a/Python/clinic/context.c.h b/Python/clinic/context.c.h +index 997ac6f6338..71f05aa02a5 100644 +--- a/Python/clinic/context.c.h ++++ b/Python/clinic/context.c.h +@@ -21,7 +21,7 @@ + PyObject *default_value); + + static PyObject * +-_contextvars_Context_get(PyContext *self, PyObject *const *args, Py_ssize_t nargs) ++_contextvars_Context_get(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *key; +@@ -36,7 +36,7 @@ + } + default_value = args[1]; + skip_optional: +- return_value = _contextvars_Context_get_impl(self, key, default_value); ++ return_value = _contextvars_Context_get_impl((PyContext *)self, key, default_value); + + exit: + return return_value; +@@ -57,9 +57,9 @@ + _contextvars_Context_items_impl(PyContext *self); + + static PyObject * +-_contextvars_Context_items(PyContext *self, PyObject *Py_UNUSED(ignored)) ++_contextvars_Context_items(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _contextvars_Context_items_impl(self); ++ return _contextvars_Context_items_impl((PyContext *)self); + } + + PyDoc_STRVAR(_contextvars_Context_keys__doc__, +@@ -75,9 +75,9 @@ + _contextvars_Context_keys_impl(PyContext *self); + + static PyObject * +-_contextvars_Context_keys(PyContext *self, PyObject *Py_UNUSED(ignored)) ++_contextvars_Context_keys(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _contextvars_Context_keys_impl(self); ++ return _contextvars_Context_keys_impl((PyContext *)self); + } + + PyDoc_STRVAR(_contextvars_Context_values__doc__, +@@ -93,9 +93,9 @@ + _contextvars_Context_values_impl(PyContext *self); + + static PyObject * +-_contextvars_Context_values(PyContext *self, PyObject *Py_UNUSED(ignored)) ++_contextvars_Context_values(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _contextvars_Context_values_impl(self); ++ return _contextvars_Context_values_impl((PyContext *)self); + } + + PyDoc_STRVAR(_contextvars_Context_copy__doc__, +@@ -111,9 +111,9 @@ + _contextvars_Context_copy_impl(PyContext *self); + + static PyObject * +-_contextvars_Context_copy(PyContext *self, PyObject *Py_UNUSED(ignored)) ++_contextvars_Context_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return _contextvars_Context_copy_impl(self); ++ return _contextvars_Context_copy_impl((PyContext *)self); + } + + PyDoc_STRVAR(_contextvars_ContextVar_get__doc__, +@@ -135,7 +135,7 @@ + _contextvars_ContextVar_get_impl(PyContextVar *self, PyObject *default_value); + + static PyObject * +-_contextvars_ContextVar_get(PyContextVar *self, PyObject *const *args, Py_ssize_t nargs) ++_contextvars_ContextVar_get(PyObject *self, PyObject *const *args, Py_ssize_t nargs) + { + PyObject *return_value = NULL; + PyObject *default_value = NULL; +@@ -148,7 +148,7 @@ + } + default_value = args[0]; + skip_optional: +- return_value = _contextvars_ContextVar_get_impl(self, default_value); ++ return_value = _contextvars_ContextVar_get_impl((PyContextVar *)self, default_value); + + exit: + return return_value; +@@ -179,4 +179,4 @@ + + #define _CONTEXTVARS_CONTEXTVAR_RESET_METHODDEF \ + {"reset", (PyCFunction)_contextvars_ContextVar_reset, METH_O, _contextvars_ContextVar_reset__doc__}, +-/*[clinic end generated code: output=b667826178444c3f input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=444567eaf0df25e0 input=a9049054013a1b77]*/ +diff --git a/Python/clinic/instruction_sequence.c.h b/Python/clinic/instruction_sequence.c.h +index 45693e5856f..41ab2de44e4 100644 +--- a/Python/clinic/instruction_sequence.c.h ++++ b/Python/clinic/instruction_sequence.c.h +@@ -51,7 +51,7 @@ + int label); + + static PyObject * +-InstructionSequenceType_use_label(_PyInstructionSequence *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++InstructionSequenceType_use_label(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -91,7 +91,7 @@ + if (label == -1 && PyErr_Occurred()) { + goto exit; + } +- return_value = InstructionSequenceType_use_label_impl(self, label); ++ return_value = InstructionSequenceType_use_label_impl((_PyInstructionSequence *)self, label); + + exit: + return return_value; +@@ -113,7 +113,7 @@ + int end_lineno, int end_col_offset); + + static PyObject * +-InstructionSequenceType_addop(_PyInstructionSequence *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++InstructionSequenceType_addop(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -178,7 +178,7 @@ + if (end_col_offset == -1 && PyErr_Occurred()) { + goto exit; + } +- return_value = InstructionSequenceType_addop_impl(self, opcode, oparg, lineno, col_offset, end_lineno, end_col_offset); ++ return_value = InstructionSequenceType_addop_impl((_PyInstructionSequence *)self, opcode, oparg, lineno, col_offset, end_lineno, end_col_offset); + + exit: + return return_value; +@@ -197,12 +197,12 @@ + InstructionSequenceType_new_label_impl(_PyInstructionSequence *self); + + static PyObject * +-InstructionSequenceType_new_label(_PyInstructionSequence *self, PyObject *Py_UNUSED(ignored)) ++InstructionSequenceType_new_label(PyObject *self, PyObject *Py_UNUSED(ignored)) + { + PyObject *return_value = NULL; + int _return_value; + +- _return_value = InstructionSequenceType_new_label_impl(self); ++ _return_value = InstructionSequenceType_new_label_impl((_PyInstructionSequence *)self); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } +@@ -226,7 +226,7 @@ + PyObject *nested); + + static PyObject * +-InstructionSequenceType_add_nested(_PyInstructionSequence *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) ++InstructionSequenceType_add_nested(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +@@ -263,7 +263,7 @@ + goto exit; + } + nested = args[0]; +- return_value = InstructionSequenceType_add_nested_impl(self, nested); ++ return_value = InstructionSequenceType_add_nested_impl((_PyInstructionSequence *)self, nested); + + exit: + return return_value; +@@ -282,9 +282,9 @@ + InstructionSequenceType_get_nested_impl(_PyInstructionSequence *self); + + static PyObject * +-InstructionSequenceType_get_nested(_PyInstructionSequence *self, PyObject *Py_UNUSED(ignored)) ++InstructionSequenceType_get_nested(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return InstructionSequenceType_get_nested_impl(self); ++ return InstructionSequenceType_get_nested_impl((_PyInstructionSequence *)self); + } + + PyDoc_STRVAR(InstructionSequenceType_get_instructions__doc__, +@@ -300,8 +300,8 @@ + InstructionSequenceType_get_instructions_impl(_PyInstructionSequence *self); + + static PyObject * +-InstructionSequenceType_get_instructions(_PyInstructionSequence *self, PyObject *Py_UNUSED(ignored)) ++InstructionSequenceType_get_instructions(PyObject *self, PyObject *Py_UNUSED(ignored)) + { +- return InstructionSequenceType_get_instructions_impl(self); ++ return InstructionSequenceType_get_instructions_impl((_PyInstructionSequence *)self); + } +-/*[clinic end generated code: output=35163e5b589b4446 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=e6b5d05bde008cc2 input=a9049054013a1b77]*/ +diff --git a/Python/clinic/sysmodule.c.h b/Python/clinic/sysmodule.c.h +index cfcbd55388e..1e53624d4d4 100644 +--- a/Python/clinic/sysmodule.c.h ++++ b/Python/clinic/sysmodule.c.h +@@ -373,6 +373,36 @@ + return return_value; + } + ++PyDoc_STRVAR(sys__is_immortal__doc__, ++"_is_immortal($module, op, /)\n" ++"--\n" ++"\n" ++"Return True if the given object is \"immortal\" per PEP 683.\n" ++"\n" ++"This function should be used for specialized purposes only."); ++ ++#define SYS__IS_IMMORTAL_METHODDEF \ ++ {"_is_immortal", (PyCFunction)sys__is_immortal, METH_O, sys__is_immortal__doc__}, ++ ++static int ++sys__is_immortal_impl(PyObject *module, PyObject *op); ++ ++static PyObject * ++sys__is_immortal(PyObject *module, PyObject *op) ++{ ++ PyObject *return_value = NULL; ++ int _return_value; ++ ++ _return_value = sys__is_immortal_impl(module, op); ++ if ((_return_value == -1) && PyErr_Occurred()) { ++ goto exit; ++ } ++ return_value = PyBool_FromLong((long)_return_value); ++ ++exit: ++ return return_value; ++} ++ + PyDoc_STRVAR(sys_settrace__doc__, + "settrace($module, function, /)\n" + "--\n" +@@ -1724,4 +1754,4 @@ + #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF + #define SYS_GETANDROIDAPILEVEL_METHODDEF + #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ +-/*[clinic end generated code: output=568b0a0069dc43e8 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=1e5f608092c12636 input=a9049054013a1b77]*/ +diff --git a/Python/codecs.c b/Python/codecs.c +index 2cb3875db35..6c9f8222079 100644 +--- a/Python/codecs.c ++++ b/Python/codecs.c +@@ -659,91 +659,163 @@ + return handler; + } + +-static void wrong_exception_type(PyObject *exc) ++ ++static inline void ++wrong_exception_type(PyObject *exc) + { + PyErr_Format(PyExc_TypeError, +- "don't know how to handle %.200s in error callback", +- Py_TYPE(exc)->tp_name); ++ "don't know how to handle %T in error callback", exc); ++} ++ ++ ++#define _PyIsUnicodeEncodeError(EXC) \ ++ PyObject_TypeCheck(EXC, (PyTypeObject *)PyExc_UnicodeEncodeError) ++#define _PyIsUnicodeDecodeError(EXC) \ ++ PyObject_TypeCheck(EXC, (PyTypeObject *)PyExc_UnicodeDecodeError) ++#define _PyIsUnicodeTranslateError(EXC) \ ++ PyObject_TypeCheck(EXC, (PyTypeObject *)PyExc_UnicodeTranslateError) ++ ++ ++// --- codecs handlers: utilities --------------------------------------------- ++ ++/* ++ * Return the number of characters (including special prefixes) ++ * needed to represent 'ch' by codec_handler_write_unicode_hex(). ++ */ ++static inline Py_ssize_t ++codec_handler_unicode_hex_width(Py_UCS4 ch) ++{ ++ if (ch >= 0x10000) { ++ // format: '\\' + 'U' + 8 hex digits ++ return 1 + 1 + 8; ++ } ++ else if (ch >= 0x100) { ++ // format: '\\' + 'u' + 4 hex digits ++ return 1 + 1 + 4; ++ } ++ else { ++ // format: '\\' + 'x' + 2 hex digits ++ return 1 + 1 + 2; ++ } + } + ++ ++/* ++ * Write the hexadecimal representation of 'ch' to the buffer pointed by 'p' ++ * using 2, 4, or 8 characters prefixed by '\x', '\u', or '\U' respectively. ++ */ ++static inline void ++codec_handler_write_unicode_hex(Py_UCS1 **p, Py_UCS4 ch) ++{ ++ *(*p)++ = '\\'; ++ if (ch >= 0x10000) { ++ *(*p)++ = 'U'; ++ *(*p)++ = Py_hexdigits[(ch >> 28) & 0xf]; ++ *(*p)++ = Py_hexdigits[(ch >> 24) & 0xf]; ++ *(*p)++ = Py_hexdigits[(ch >> 20) & 0xf]; ++ *(*p)++ = Py_hexdigits[(ch >> 16) & 0xf]; ++ *(*p)++ = Py_hexdigits[(ch >> 12) & 0xf]; ++ *(*p)++ = Py_hexdigits[(ch >> 8) & 0xf]; ++ } ++ else if (ch >= 0x100) { ++ *(*p)++ = 'u'; ++ *(*p)++ = Py_hexdigits[(ch >> 12) & 0xf]; ++ *(*p)++ = Py_hexdigits[(ch >> 8) & 0xf]; ++ } ++ else { ++ *(*p)++ = 'x'; ++ } ++ *(*p)++ = Py_hexdigits[(ch >> 4) & 0xf]; ++ *(*p)++ = Py_hexdigits[ch & 0xf]; ++} ++ ++ ++// --- handler: 'strict' ------------------------------------------------------ ++ + PyObject *PyCodec_StrictErrors(PyObject *exc) + { +- if (PyExceptionInstance_Check(exc)) ++ if (PyExceptionInstance_Check(exc)) { + PyErr_SetObject(PyExceptionInstance_Class(exc), exc); +- else ++ } ++ else { + PyErr_SetString(PyExc_TypeError, "codec must pass exception instance"); ++ } + return NULL; + } + + +-PyObject *PyCodec_IgnoreErrors(PyObject *exc) ++// --- handler: 'ignore' ------------------------------------------------------ ++ ++static PyObject * ++_PyCodec_IgnoreError(PyObject *exc, int as_bytes) + { + Py_ssize_t end; +- +- if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) { +- if (PyUnicodeEncodeError_GetEnd(exc, &end)) +- return NULL; ++ if (_PyUnicodeError_GetParams(exc, NULL, NULL, NULL, ++ &end, NULL, as_bytes) < 0) ++ { ++ return NULL; + } +- else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeDecodeError)) { +- if (PyUnicodeDecodeError_GetEnd(exc, &end)) +- return NULL; ++ return Py_BuildValue("(Nn)", Py_GetConstant(Py_CONSTANT_EMPTY_STR), end); ++} ++ ++ ++PyObject *PyCodec_IgnoreErrors(PyObject *exc) ++{ ++ if (_PyIsUnicodeEncodeError(exc) || _PyIsUnicodeTranslateError(exc)) { ++ return _PyCodec_IgnoreError(exc, false); + } +- else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeTranslateError)) { +- if (PyUnicodeTranslateError_GetEnd(exc, &end)) +- return NULL; ++ else if (_PyIsUnicodeDecodeError(exc)) { ++ return _PyCodec_IgnoreError(exc, true); + } + else { + wrong_exception_type(exc); + return NULL; + } +- return Py_BuildValue("(Nn)", Py_GetConstant(Py_CONSTANT_EMPTY_STR), end); + } + + + PyObject *PyCodec_ReplaceErrors(PyObject *exc) + { +- Py_ssize_t start, end, i, len; ++ Py_ssize_t start, end, slen; + + if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) { +- PyObject *res; +- Py_UCS1 *outp; +- if (PyUnicodeEncodeError_GetStart(exc, &start)) +- return NULL; +- if (PyUnicodeEncodeError_GetEnd(exc, &end)) ++ if (_PyUnicodeError_GetParams(exc, NULL, NULL, ++ &start, &end, &slen, false) < 0) { + return NULL; +- len = end - start; +- res = PyUnicode_New(len, '?'); +- if (res == NULL) ++ } ++ PyObject *res = PyUnicode_New(slen, '?'); ++ if (res == NULL) { + return NULL; ++ } + assert(PyUnicode_KIND(res) == PyUnicode_1BYTE_KIND); +- outp = PyUnicode_1BYTE_DATA(res); +- for (i = 0; i < len; ++i) +- outp[i] = '?'; ++ Py_UCS1 *outp = PyUnicode_1BYTE_DATA(res); ++ memset(outp, '?', sizeof(Py_UCS1) * slen); + assert(_PyUnicode_CheckConsistency(res, 1)); + return Py_BuildValue("(Nn)", res, end); + } + else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeDecodeError)) { +- if (PyUnicodeDecodeError_GetEnd(exc, &end)) ++ if (_PyUnicodeError_GetParams(exc, NULL, NULL, ++ NULL, &end, NULL, true) < 0) { + return NULL; ++ } + return Py_BuildValue("(Cn)", + (int)Py_UNICODE_REPLACEMENT_CHARACTER, + end); + } + else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeTranslateError)) { +- PyObject *res; +- Py_UCS2 *outp; +- if (PyUnicodeTranslateError_GetStart(exc, &start)) +- return NULL; +- if (PyUnicodeTranslateError_GetEnd(exc, &end)) ++ if (_PyUnicodeError_GetParams(exc, NULL, NULL, ++ &start, &end, &slen, false) < 0) { + return NULL; +- len = end - start; +- res = PyUnicode_New(len, Py_UNICODE_REPLACEMENT_CHARACTER); +- if (res == NULL) ++ } ++ PyObject *res = PyUnicode_New(slen, Py_UNICODE_REPLACEMENT_CHARACTER); ++ if (res == NULL) { + return NULL; +- assert(PyUnicode_KIND(res) == PyUnicode_2BYTE_KIND); +- outp = PyUnicode_2BYTE_DATA(res); +- for (i = 0; i < len; i++) ++ } ++ assert(slen == 0 || PyUnicode_KIND(res) == PyUnicode_2BYTE_KIND); ++ Py_UCS2 *outp = PyUnicode_2BYTE_DATA(res); ++ for (Py_ssize_t i = 0; i < slen; ++i) { + outp[i] = Py_UNICODE_REPLACEMENT_CHARACTER; ++ } + assert(_PyUnicode_CheckConsistency(res, 1)); + return Py_BuildValue("(Nn)", res, end); + } +@@ -755,299 +827,266 @@ + + PyObject *PyCodec_XMLCharRefReplaceErrors(PyObject *exc) + { +- if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) { +- PyObject *restuple; +- PyObject *object; +- Py_ssize_t i; +- Py_ssize_t start; +- Py_ssize_t end; +- PyObject *res; +- Py_UCS1 *outp; +- Py_ssize_t ressize; +- Py_UCS4 ch; +- if (PyUnicodeEncodeError_GetStart(exc, &start)) +- return NULL; +- if (PyUnicodeEncodeError_GetEnd(exc, &end)) +- return NULL; +- if (!(object = PyUnicodeEncodeError_GetObject(exc))) +- return NULL; +- if (end - start > PY_SSIZE_T_MAX / (2+7+1)) +- end = start + PY_SSIZE_T_MAX / (2+7+1); +- for (i = start, ressize = 0; i < end; ++i) { +- /* object is guaranteed to be "ready" */ +- ch = PyUnicode_READ_CHAR(object, i); +- if (ch<10) +- ressize += 2+1+1; +- else if (ch<100) +- ressize += 2+2+1; +- else if (ch<1000) +- ressize += 2+3+1; +- else if (ch<10000) +- ressize += 2+4+1; +- else if (ch<100000) +- ressize += 2+5+1; +- else if (ch<1000000) +- ressize += 2+6+1; +- else +- ressize += 2+7+1; ++ if (!PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) { ++ wrong_exception_type(exc); ++ return NULL; ++ } ++ ++ PyObject *obj; ++ Py_ssize_t objlen, start, end, slen; ++ if (_PyUnicodeError_GetParams(exc, ++ &obj, &objlen, ++ &start, &end, &slen, false) < 0) ++ { ++ return NULL; ++ } ++ ++ // The number of characters that each character 'ch' contributes ++ // in the result is 2 + k + 1, where k = min{t >= 1 | 10^t > ch} ++ // and will be formatted as "&#" + DIGITS + ";". Since the Unicode ++ // range is below 10^7, each "block" requires at most 2 + 7 + 1 ++ // characters. ++ if (slen > PY_SSIZE_T_MAX / (2 + 7 + 1)) { ++ end = start + PY_SSIZE_T_MAX / (2 + 7 + 1); ++ end = Py_MIN(end, objlen); ++ slen = Py_MAX(0, end - start); ++ } ++ ++ Py_ssize_t ressize = 0; ++ for (Py_ssize_t i = start; i < end; ++i) { ++ /* object is guaranteed to be "ready" */ ++ Py_UCS4 ch = PyUnicode_READ_CHAR(obj, i); ++ if (ch < 10) { ++ ressize += 2 + 1 + 1; + } +- /* allocate replacement */ +- res = PyUnicode_New(ressize, 127); +- if (res == NULL) { +- Py_DECREF(object); +- return NULL; ++ else if (ch < 100) { ++ ressize += 2 + 2 + 1; + } +- outp = PyUnicode_1BYTE_DATA(res); +- /* generate replacement */ +- for (i = start; i < end; ++i) { +- int digits; +- int base; +- ch = PyUnicode_READ_CHAR(object, i); +- *outp++ = '&'; +- *outp++ = '#'; +- if (ch<10) { +- digits = 1; +- base = 1; +- } +- else if (ch<100) { +- digits = 2; +- base = 10; +- } +- else if (ch<1000) { +- digits = 3; +- base = 100; +- } +- else if (ch<10000) { +- digits = 4; +- base = 1000; +- } +- else if (ch<100000) { +- digits = 5; +- base = 10000; +- } +- else if (ch<1000000) { +- digits = 6; +- base = 100000; +- } +- else { +- digits = 7; +- base = 1000000; +- } +- while (digits-->0) { +- *outp++ = '0' + ch/base; +- ch %= base; +- base /= 10; +- } +- *outp++ = ';'; ++ else if (ch < 1000) { ++ ressize += 2 + 3 + 1; ++ } ++ else if (ch < 10000) { ++ ressize += 2 + 4 + 1; ++ } ++ else if (ch < 100000) { ++ ressize += 2 + 5 + 1; ++ } ++ else if (ch < 1000000) { ++ ressize += 2 + 6 + 1; ++ } ++ else { ++ assert(ch < 10000000); ++ ressize += 2 + 7 + 1; + } +- assert(_PyUnicode_CheckConsistency(res, 1)); +- restuple = Py_BuildValue("(Nn)", res, end); +- Py_DECREF(object); +- return restuple; + } +- else { +- wrong_exception_type(exc); ++ ++ /* allocate replacement */ ++ PyObject *res = PyUnicode_New(ressize, 127); ++ if (res == NULL) { ++ Py_DECREF(obj); + return NULL; + } ++ Py_UCS1 *outp = PyUnicode_1BYTE_DATA(res); ++ /* generate replacement */ ++ for (Py_ssize_t i = start; i < end; ++i) { ++ int digits, base; ++ Py_UCS4 ch = PyUnicode_READ_CHAR(obj, i); ++ if (ch < 10) { ++ digits = 1; ++ base = 1; ++ } ++ else if (ch < 100) { ++ digits = 2; ++ base = 10; ++ } ++ else if (ch < 1000) { ++ digits = 3; ++ base = 100; ++ } ++ else if (ch < 10000) { ++ digits = 4; ++ base = 1000; ++ } ++ else if (ch < 100000) { ++ digits = 5; ++ base = 10000; ++ } ++ else if (ch < 1000000) { ++ digits = 6; ++ base = 100000; ++ } ++ else { ++ assert(ch < 10000000); ++ digits = 7; ++ base = 1000000; ++ } ++ *outp++ = '&'; ++ *outp++ = '#'; ++ while (digits-- > 0) { ++ assert(base >= 1); ++ *outp++ = '0' + ch / base; ++ ch %= base; ++ base /= 10; ++ } ++ *outp++ = ';'; ++ } ++ assert(_PyUnicode_CheckConsistency(res, 1)); ++ PyObject *restuple = Py_BuildValue("(Nn)", res, end); ++ Py_DECREF(obj); ++ return restuple; + } + + PyObject *PyCodec_BackslashReplaceErrors(PyObject *exc) + { +- PyObject *object; +- Py_ssize_t i; +- Py_ssize_t start; +- Py_ssize_t end; +- PyObject *res; +- Py_UCS1 *outp; +- int ressize; +- Py_UCS4 c; +- ++ PyObject *obj; ++ Py_ssize_t objlen, start, end, slen; + if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeDecodeError)) { +- const unsigned char *p; +- if (PyUnicodeDecodeError_GetStart(exc, &start)) +- return NULL; +- if (PyUnicodeDecodeError_GetEnd(exc, &end)) +- return NULL; +- if (!(object = PyUnicodeDecodeError_GetObject(exc))) ++ if (_PyUnicodeError_GetParams(exc, ++ &obj, &objlen, ++ &start, &end, &slen, true) < 0) ++ { + return NULL; +- p = (const unsigned char*)PyBytes_AS_STRING(object); +- res = PyUnicode_New(4 * (end - start), 127); ++ } ++ PyObject *res = PyUnicode_New(4 * slen, 127); + if (res == NULL) { +- Py_DECREF(object); ++ Py_DECREF(obj); + return NULL; + } +- outp = PyUnicode_1BYTE_DATA(res); +- for (i = start; i < end; i++, outp += 4) { +- unsigned char c = p[i]; ++ Py_UCS1 *outp = PyUnicode_1BYTE_DATA(res); ++ const unsigned char *p = (const unsigned char *)PyBytes_AS_STRING(obj); ++ for (Py_ssize_t i = start; i < end; i++, outp += 4) { ++ const unsigned char ch = p[i]; + outp[0] = '\\'; + outp[1] = 'x'; +- outp[2] = Py_hexdigits[(c>>4)&0xf]; +- outp[3] = Py_hexdigits[c&0xf]; ++ outp[2] = Py_hexdigits[(ch >> 4) & 0xf]; ++ outp[3] = Py_hexdigits[ch & 0xf]; + } +- + assert(_PyUnicode_CheckConsistency(res, 1)); +- Py_DECREF(object); ++ Py_DECREF(obj); + return Py_BuildValue("(Nn)", res, end); + } +- if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) { +- if (PyUnicodeEncodeError_GetStart(exc, &start)) +- return NULL; +- if (PyUnicodeEncodeError_GetEnd(exc, &end)) +- return NULL; +- if (!(object = PyUnicodeEncodeError_GetObject(exc))) +- return NULL; +- } +- else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeTranslateError)) { +- if (PyUnicodeTranslateError_GetStart(exc, &start)) +- return NULL; +- if (PyUnicodeTranslateError_GetEnd(exc, &end)) +- return NULL; +- if (!(object = PyUnicodeTranslateError_GetObject(exc))) ++ ++ if ( ++ PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError) ++ || PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeTranslateError) ++ ) { ++ if (_PyUnicodeError_GetParams(exc, ++ &obj, &objlen, ++ &start, &end, &slen, false) < 0) ++ { + return NULL; ++ } + } + else { + wrong_exception_type(exc); + return NULL; + } + +- if (end - start > PY_SSIZE_T_MAX / (1+1+8)) +- end = start + PY_SSIZE_T_MAX / (1+1+8); +- for (i = start, ressize = 0; i < end; ++i) { +- /* object is guaranteed to be "ready" */ +- c = PyUnicode_READ_CHAR(object, i); +- if (c >= 0x10000) { +- ressize += 1+1+8; +- } +- else if (c >= 0x100) { +- ressize += 1+1+4; +- } +- else +- ressize += 1+1+2; ++ // The number of characters that each character 'ch' contributes ++ // in the result is 1 + 1 + k, where k >= min{t >= 1 | 16^t > ch} ++ // and will be formatted as "\\" + ('U'|'u'|'x') + HEXDIGITS, ++ // where the number of hexdigits is either 2, 4, or 8 (not 6). ++ // Since the Unicode range is below 10^7, we choose k = 8 whence ++ // each "block" requires at most 1 + 1 + 8 characters. ++ if (slen > PY_SSIZE_T_MAX / (1 + 1 + 8)) { ++ end = start + PY_SSIZE_T_MAX / (1 + 1 + 8); ++ end = Py_MIN(end, objlen); ++ slen = Py_MAX(0, end - start); ++ } ++ ++ Py_ssize_t ressize = 0; ++ for (Py_ssize_t i = start; i < end; ++i) { ++ Py_UCS4 c = PyUnicode_READ_CHAR(obj, i); ++ ressize += codec_handler_unicode_hex_width(c); + } +- res = PyUnicode_New(ressize, 127); ++ PyObject *res = PyUnicode_New(ressize, 127); + if (res == NULL) { +- Py_DECREF(object); ++ Py_DECREF(obj); + return NULL; + } +- outp = PyUnicode_1BYTE_DATA(res); +- for (i = start; i < end; ++i) { +- c = PyUnicode_READ_CHAR(object, i); +- *outp++ = '\\'; +- if (c >= 0x00010000) { +- *outp++ = 'U'; +- *outp++ = Py_hexdigits[(c>>28)&0xf]; +- *outp++ = Py_hexdigits[(c>>24)&0xf]; +- *outp++ = Py_hexdigits[(c>>20)&0xf]; +- *outp++ = Py_hexdigits[(c>>16)&0xf]; +- *outp++ = Py_hexdigits[(c>>12)&0xf]; +- *outp++ = Py_hexdigits[(c>>8)&0xf]; +- } +- else if (c >= 0x100) { +- *outp++ = 'u'; +- *outp++ = Py_hexdigits[(c>>12)&0xf]; +- *outp++ = Py_hexdigits[(c>>8)&0xf]; +- } +- else +- *outp++ = 'x'; +- *outp++ = Py_hexdigits[(c>>4)&0xf]; +- *outp++ = Py_hexdigits[c&0xf]; ++ Py_UCS1 *outp = PyUnicode_1BYTE_DATA(res); ++ for (Py_ssize_t i = start; i < end; ++i) { ++ Py_UCS4 c = PyUnicode_READ_CHAR(obj, i); ++ codec_handler_write_unicode_hex(&outp, c); + } +- + assert(_PyUnicode_CheckConsistency(res, 1)); +- Py_DECREF(object); ++ Py_DECREF(obj); + return Py_BuildValue("(Nn)", res, end); + } + ++ ++// --- handler: 'namereplace' ------------------------------------------------- ++ + PyObject *PyCodec_NameReplaceErrors(PyObject *exc) + { +- if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) { +- PyObject *restuple; +- PyObject *object; +- Py_ssize_t i; +- Py_ssize_t start; +- Py_ssize_t end; +- PyObject *res; +- Py_UCS1 *outp; +- Py_ssize_t ressize; +- int replsize; +- Py_UCS4 c; +- char buffer[256]; /* NAME_MAXLEN */ +- if (PyUnicodeEncodeError_GetStart(exc, &start)) +- return NULL; +- if (PyUnicodeEncodeError_GetEnd(exc, &end)) +- return NULL; +- if (!(object = PyUnicodeEncodeError_GetObject(exc))) +- return NULL; +- _PyUnicode_Name_CAPI *ucnhash_capi = _PyUnicode_GetNameCAPI(); +- if (ucnhash_capi == NULL) { +- return NULL; ++ if (!_PyIsUnicodeEncodeError(exc)) { ++ wrong_exception_type(exc); ++ return NULL; ++ } ++ ++ _PyUnicode_Name_CAPI *ucnhash_capi = _PyUnicode_GetNameCAPI(); ++ if (ucnhash_capi == NULL) { ++ return NULL; ++ } ++ ++ PyObject *obj; ++ Py_ssize_t start, end; ++ if (_PyUnicodeError_GetParams(exc, ++ &obj, NULL, ++ &start, &end, NULL, false) < 0) ++ { ++ return NULL; ++ } ++ ++ char buffer[256]; /* NAME_MAXLEN in unicodename_db.h */ ++ Py_ssize_t imax = start, ressize = 0, replsize; ++ for (; imax < end; ++imax) { ++ Py_UCS4 c = PyUnicode_READ_CHAR(obj, imax); ++ if (ucnhash_capi->getname(c, buffer, sizeof(buffer), 1)) { ++ // If 'c' is recognized by getname(), the corresponding replacement ++ // is '\\' + 'N' + '{' + NAME + '}', i.e. 1 + 1 + 1 + len(NAME) + 1 ++ // characters. Failures of getname() are ignored by the handler. ++ replsize = 1 + 1 + 1 + strlen(buffer) + 1; + } +- for (i = start, ressize = 0; i < end; ++i) { +- /* object is guaranteed to be "ready" */ +- c = PyUnicode_READ_CHAR(object, i); +- if (ucnhash_capi->getname(c, buffer, sizeof(buffer), 1)) { +- replsize = 1+1+1+(int)strlen(buffer)+1; +- } +- else if (c >= 0x10000) { +- replsize = 1+1+8; +- } +- else if (c >= 0x100) { +- replsize = 1+1+4; +- } +- else +- replsize = 1+1+2; +- if (ressize > PY_SSIZE_T_MAX - replsize) +- break; +- ressize += replsize; ++ else { ++ replsize = codec_handler_unicode_hex_width(c); + } +- end = i; +- res = PyUnicode_New(ressize, 127); +- if (res==NULL) +- return NULL; +- for (i = start, outp = PyUnicode_1BYTE_DATA(res); +- i < end; ++i) { +- c = PyUnicode_READ_CHAR(object, i); +- *outp++ = '\\'; +- if (ucnhash_capi->getname(c, buffer, sizeof(buffer), 1)) { +- *outp++ = 'N'; +- *outp++ = '{'; +- strcpy((char *)outp, buffer); +- outp += strlen(buffer); +- *outp++ = '}'; +- continue; +- } +- if (c >= 0x00010000) { +- *outp++ = 'U'; +- *outp++ = Py_hexdigits[(c>>28)&0xf]; +- *outp++ = Py_hexdigits[(c>>24)&0xf]; +- *outp++ = Py_hexdigits[(c>>20)&0xf]; +- *outp++ = Py_hexdigits[(c>>16)&0xf]; +- *outp++ = Py_hexdigits[(c>>12)&0xf]; +- *outp++ = Py_hexdigits[(c>>8)&0xf]; +- } +- else if (c >= 0x100) { +- *outp++ = 'u'; +- *outp++ = Py_hexdigits[(c>>12)&0xf]; +- *outp++ = Py_hexdigits[(c>>8)&0xf]; +- } +- else +- *outp++ = 'x'; +- *outp++ = Py_hexdigits[(c>>4)&0xf]; +- *outp++ = Py_hexdigits[c&0xf]; ++ if (ressize > PY_SSIZE_T_MAX - replsize) { ++ break; + } +- +- assert(outp == PyUnicode_1BYTE_DATA(res) + ressize); +- assert(_PyUnicode_CheckConsistency(res, 1)); +- restuple = Py_BuildValue("(Nn)", res, end); +- Py_DECREF(object); +- return restuple; ++ ressize += replsize; + } +- else { +- wrong_exception_type(exc); ++ ++ PyObject *res = PyUnicode_New(ressize, 127); ++ if (res == NULL) { ++ Py_DECREF(obj); + return NULL; + } ++ ++ Py_UCS1 *outp = PyUnicode_1BYTE_DATA(res); ++ for (Py_ssize_t i = start; i < imax; ++i) { ++ Py_UCS4 c = PyUnicode_READ_CHAR(obj, i); ++ if (ucnhash_capi->getname(c, buffer, sizeof(buffer), 1)) { ++ *outp++ = '\\'; ++ *outp++ = 'N'; ++ *outp++ = '{'; ++ (void)strcpy((char *)outp, buffer); ++ outp += strlen(buffer); ++ *outp++ = '}'; ++ } ++ else { ++ codec_handler_write_unicode_hex(&outp, c); ++ } ++ } ++ ++ assert(outp == PyUnicode_1BYTE_DATA(res) + ressize); ++ assert(_PyUnicode_CheckConsistency(res, 1)); ++ PyObject *restuple = Py_BuildValue("(Nn)", res, imax); ++ Py_DECREF(obj); ++ return restuple; + } + ++ + #define ENC_UNKNOWN -1 + #define ENC_UTF8 0 + #define ENC_UTF16BE 1 +@@ -1358,13 +1397,17 @@ + } + + +-static PyObject *strict_errors(PyObject *self, PyObject *exc) ++// --- Codecs registry handlers ----------------------------------------------- ++ ++static inline PyObject * ++strict_errors(PyObject *Py_UNUSED(self), PyObject *exc) + { + return PyCodec_StrictErrors(exc); + } + + +-static PyObject *ignore_errors(PyObject *self, PyObject *exc) ++static inline PyObject * ++ignore_errors(PyObject *Py_UNUSED(self), PyObject *exc) + { + return PyCodec_IgnoreErrors(exc); + } +@@ -1387,11 +1430,14 @@ + return PyCodec_BackslashReplaceErrors(exc); + } + +-static PyObject *namereplace_errors(PyObject *self, PyObject *exc) ++ ++static inline PyObject * ++namereplace_errors(PyObject *Py_UNUSED(self), PyObject *exc) + { + return PyCodec_NameReplaceErrors(exc); + } + ++ + static PyObject *surrogatepass_errors(PyObject *self, PyObject *exc) + { + return PyCodec_SurrogatePassErrors(exc); +diff --git a/Python/codegen.c b/Python/codegen.c +index a5e550cf8c9..cd77b34c062 100644 +--- a/Python/codegen.c ++++ b/Python/codegen.c +@@ -201,9 +201,6 @@ + static int codegen_slice_two_parts(compiler *, expr_ty); + static int codegen_slice(compiler *, expr_ty); + +-static bool are_all_items_const(asdl_expr_seq *, Py_ssize_t, Py_ssize_t); +- +- + static int codegen_with(compiler *, stmt_ty, int); + static int codegen_async_with(compiler *, stmt_ty, int); + static int codegen_async_for(compiler *, stmt_ty); +@@ -287,7 +284,7 @@ + if (PyLong_CheckExact(o)) { + int overflow; + long val = PyLong_AsLongAndOverflow(o, &overflow); +- if (!overflow && val >= 0 && val < 256 && val < _PY_NSMALLPOSINTS) { ++ if (!overflow && _PY_IS_SMALL_INT(val)) { + ADDOP_I(c, loc, LOAD_SMALL_INT, val); + return SUCCESS; + } +@@ -682,7 +679,6 @@ + ADDOP_I(c, loc, COMPARE_OP, (Py_GT << 5) | compare_masks[Py_GT]); + NEW_JUMP_TARGET_LABEL(c, body); + ADDOP_JUMP(c, loc, POP_JUMP_IF_FALSE, body); +- + ADDOP_I(c, loc, LOAD_COMMON_CONSTANT, CONSTANT_NOTIMPLEMENTEDERROR); + ADDOP_I(c, loc, RAISE_VARARGS, 1); + USE_LABEL(c, body); +@@ -696,6 +692,33 @@ + ADDOP_I(c, loc, BUILD_MAP, annotations_len); + ADDOP_IN_SCOPE(c, loc, RETURN_VALUE); + PyCodeObject *co = _PyCompile_OptimizeAndAssemble(c, 1); ++ ++ // We want the parameter to __annotate__ to be named "format" in the ++ // signature shown by inspect.signature(), but we need to use a ++ // different name (.format) in the symtable; if the name ++ // "format" appears in the annotations, it doesn't get clobbered ++ // by this name. This code is essentially: ++ // co->co_localsplusnames = ("format", *co->co_localsplusnames[1:]) ++ const Py_ssize_t size = PyObject_Size(co->co_localsplusnames); ++ if (size == -1) { ++ return ERROR; ++ } ++ PyObject *new_names = PyTuple_New(size); ++ if (new_names == NULL) { ++ return ERROR; ++ } ++ PyTuple_SET_ITEM(new_names, 0, Py_NewRef(&_Py_ID(format))); ++ for (int i = 1; i < size; i++) { ++ PyObject *item = PyTuple_GetItem(co->co_localsplusnames, i); ++ if (item == NULL) { ++ Py_DECREF(new_names); ++ return ERROR; ++ } ++ Py_INCREF(item); ++ PyTuple_SET_ITEM(new_names, i, item); ++ } ++ Py_SETREF(co->co_localsplusnames, new_names); ++ + _PyCompile_ExitScope(c); + if (co == NULL) { + return ERROR; +@@ -1986,7 +2009,7 @@ + * but a non-generator will jump to a later instruction. + */ + ADDOP(c, NO_LOCATION, END_FOR); +- ADDOP(c, NO_LOCATION, POP_TOP); ++ ADDOP(c, NO_LOCATION, POP_ITER); + + _PyCompile_PopFBlock(c, COMPILE_FBLOCK_FOR_LOOP, start); + +@@ -3184,34 +3207,6 @@ + int build, int add, int extend, int tuple) + { + Py_ssize_t n = asdl_seq_LEN(elts); +- if (!injected_arg && n > 2 && are_all_items_const(elts, 0, n)) { +- PyObject *folded = PyTuple_New(n); +- if (folded == NULL) { +- return ERROR; +- } +- for (Py_ssize_t i = 0; i < n; i++) { +- PyObject *val = ((expr_ty)asdl_seq_GET(elts, i))->v.Constant.value; +- PyTuple_SET_ITEM(folded, i, Py_NewRef(val)); +- } +- if (tuple && !pushed) { +- ADDOP_LOAD_CONST_NEW(c, loc, folded); +- } else { +- if (add == SET_ADD) { +- Py_SETREF(folded, PyFrozenSet_New(folded)); +- if (folded == NULL) { +- return ERROR; +- } +- } +- ADDOP_I(c, loc, build, pushed); +- ADDOP_LOAD_CONST_NEW(c, loc, folded); +- ADDOP_I(c, loc, extend, 1); +- if (tuple) { +- ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_LIST_TO_TUPLE); +- } +- } +- return SUCCESS; +- } +- + int big = n + pushed + (injected_arg ? 1 : 0) > STACK_USE_GUIDELINE; + int seen_star = 0; + for (Py_ssize_t i = 0; i < n; i++) { +@@ -3363,18 +3358,6 @@ + BUILD_SET, SET_ADD, SET_UPDATE, 0); + } + +-static bool +-are_all_items_const(asdl_expr_seq *seq, Py_ssize_t begin, Py_ssize_t end) +-{ +- for (Py_ssize_t i = begin; i < end; i++) { +- expr_ty key = (expr_ty)asdl_seq_GET(seq, i); +- if (key == NULL || key->kind != Constant_kind) { +- return false; +- } +- } +- return true; +-} +- + static int + codegen_subdict(compiler *c, expr_ty e, Py_ssize_t begin, Py_ssize_t end) + { +@@ -4082,7 +4065,10 @@ + } + assert(have_dict); + } +- ADDOP_I(c, loc, CALL_FUNCTION_EX, nkwelts > 0); ++ if (nkwelts == 0) { ++ ADDOP(c, loc, PUSH_NULL); ++ } ++ ADDOP(c, loc, CALL_FUNCTION_EX); + return SUCCESS; + } + +@@ -4251,7 +4237,7 @@ + * but a non-generator will jump to a later instruction. + */ + ADDOP(c, NO_LOCATION, END_FOR); +- ADDOP(c, NO_LOCATION, POP_TOP); ++ ADDOP(c, NO_LOCATION, POP_ITER); + } + + return SUCCESS; +@@ -5090,7 +5076,7 @@ + VISIT(c, expr, e->v.Subscript.slice); + ADDOP_I(c, loc, COPY, 2); + ADDOP_I(c, loc, COPY, 2); +- ADDOP(c, loc, BINARY_SUBSCR); ++ ADDOP_I(c, loc, BINARY_OP, NB_SUBSCR); + } + break; + case Name_kind: +@@ -5256,7 +5242,6 @@ + { + location loc = LOC(e); + expr_context_ty ctx = e->v.Subscript.ctx; +- int op = 0; + + if (ctx == Load) { + RETURN_IF_ERROR(check_subscripter(c, e->v.Subscript.value)); +@@ -5279,12 +5264,16 @@ + else { + VISIT(c, expr, e->v.Subscript.slice); + switch (ctx) { +- case Load: op = BINARY_SUBSCR; break; +- case Store: op = STORE_SUBSCR; break; +- case Del: op = DELETE_SUBSCR; break; ++ case Load: ++ ADDOP_I(c, loc, BINARY_OP, NB_SUBSCR); ++ break; ++ case Store: ++ ADDOP(c, loc, STORE_SUBSCR); ++ break; ++ case Del: ++ ADDOP(c, loc, DELETE_SUBSCR); ++ break; + } +- assert(op); +- ADDOP(c, loc, op); + } + return SUCCESS; + } +@@ -5516,7 +5505,7 @@ + return SUCCESS; + } + +-// Like pattern_helper_sequence_unpack, but uses BINARY_SUBSCR instead of ++// Like pattern_helper_sequence_unpack, but uses BINARY_OP/NB_SUBSCR instead of + // UNPACK_SEQUENCE / UNPACK_EX. This is more efficient for patterns with a + // starred wildcard like [first, *_] / [first, *_, last] / [*_, last] / etc. + static int +@@ -5547,7 +5536,7 @@ + ADDOP_LOAD_CONST_NEW(c, loc, PyLong_FromSsize_t(size - i)); + ADDOP_BINARY(c, loc, Sub); + } +- ADDOP(c, loc, BINARY_SUBSCR); ++ ADDOP_I(c, loc, BINARY_OP, NB_SUBSCR); + RETURN_IF_ERROR(codegen_pattern_subpattern(c, pattern, pc)); + } + // Pop the subject, we're done with it: +diff --git a/Python/compile.c b/Python/compile.c +index cbfba7f493e..b58c12d4b88 100644 +--- a/Python/compile.c ++++ b/Python/compile.c +@@ -704,12 +704,12 @@ + assert(c->u); + /* we are deleting from a list so this really shouldn't fail */ + if (PySequence_DelItem(c->c_stack, n) < 0) { +- PyErr_FormatUnraisable("Exception ignored on removing " ++ PyErr_FormatUnraisable("Exception ignored while removing " + "the last compiler stack item"); + } + if (nested_seq != NULL) { + if (_PyInstructionSequence_AddNested(c->u->u_instr_sequence, nested_seq) < 0) { +- PyErr_FormatUnraisable("Exception ignored on appending " ++ PyErr_FormatUnraisable("Exception ignored while appending " + "nested instruction sequence"); + } + } +@@ -1289,6 +1289,8 @@ + flags |= CO_VARKEYWORDS; + if (ste->ste_has_docstring) + flags |= CO_HAS_DOCSTRING; ++ if (ste->ste_method) ++ flags |= CO_METHOD; + } + + if (ste->ste_coroutine && !ste->ste_generator) { +diff --git a/Python/context.c b/Python/context.c +index 95aa8220627..bb1aa42b9c5 100644 +--- a/Python/context.c ++++ b/Python/context.c +@@ -419,6 +419,9 @@ + /*[clinic end generated code: output=da39a3ee5e6b4b0d input=bdf87f8e0cb580e8]*/ + + ++#define _PyContext_CAST(op) ((PyContext *)(op)) ++ ++ + static inline PyContext * + _context_alloc(void) + { +@@ -513,28 +516,30 @@ + } + + static int +-context_tp_clear(PyContext *self) ++context_tp_clear(PyObject *op) + { ++ PyContext *self = _PyContext_CAST(op); + Py_CLEAR(self->ctx_prev); + Py_CLEAR(self->ctx_vars); + return 0; + } + + static int +-context_tp_traverse(PyContext *self, visitproc visit, void *arg) ++context_tp_traverse(PyObject *op, visitproc visit, void *arg) + { ++ PyContext *self = _PyContext_CAST(op); + Py_VISIT(self->ctx_prev); + Py_VISIT(self->ctx_vars); + return 0; + } + + static void +-context_tp_dealloc(PyContext *self) ++context_tp_dealloc(PyObject *self) + { + _PyObject_GC_UNTRACK(self); +- +- if (self->ctx_weakreflist != NULL) { +- PyObject_ClearWeakRefs((PyObject*)self); ++ PyContext *ctx = _PyContext_CAST(self); ++ if (ctx->ctx_weakreflist != NULL) { ++ PyObject_ClearWeakRefs(self); + } + (void)context_tp_clear(self); + +@@ -542,8 +547,9 @@ + } + + static PyObject * +-context_tp_iter(PyContext *self) ++context_tp_iter(PyObject *op) + { ++ PyContext *self = _PyContext_CAST(op); + return _PyHamt_NewIterKeys(self->ctx_vars); + } + +@@ -575,18 +581,20 @@ + } + + static Py_ssize_t +-context_tp_len(PyContext *self) ++context_tp_len(PyObject *op) + { ++ PyContext *self = _PyContext_CAST(op); + return _PyHamt_Len(self->ctx_vars); + } + + static PyObject * +-context_tp_subscript(PyContext *self, PyObject *key) ++context_tp_subscript(PyObject *op, PyObject *key) + { + if (context_check_key_type(key)) { + return NULL; + } + PyObject *val = NULL; ++ PyContext *self = _PyContext_CAST(op); + int found = _PyHamt_Find(self->ctx_vars, key, &val); + if (found < 0) { + return NULL; +@@ -599,12 +607,13 @@ + } + + static int +-context_tp_contains(PyContext *self, PyObject *key) ++context_tp_contains(PyObject *op, PyObject *key) + { + if (context_check_key_type(key)) { + return -1; + } + PyObject *val = NULL; ++ PyContext *self = _PyContext_CAST(op); + return _PyHamt_Find(self->ctx_vars, key, &val); + } + +@@ -701,7 +710,7 @@ + + + static PyObject * +-context_run(PyContext *self, PyObject *const *args, ++context_run(PyObject *self, PyObject *const *args, + Py_ssize_t nargs, PyObject *kwnames) + { + PyThreadState *ts = _PyThreadState_GET(); +@@ -712,14 +721,14 @@ + return NULL; + } + +- if (_PyContext_Enter(ts, (PyObject *)self)) { ++ if (_PyContext_Enter(ts, self)) { + return NULL; + } + + PyObject *call_result = _PyObject_VectorcallTstate( + ts, args[0], args + 1, nargs - 1, kwnames); + +- if (_PyContext_Exit(ts, (PyObject *)self)) { ++ if (_PyContext_Exit(ts, self)) { + Py_XDECREF(call_result); + return NULL; + } +@@ -739,21 +748,12 @@ + }; + + static PySequenceMethods PyContext_as_sequence = { +- 0, /* sq_length */ +- 0, /* sq_concat */ +- 0, /* sq_repeat */ +- 0, /* sq_item */ +- 0, /* sq_slice */ +- 0, /* sq_ass_item */ +- 0, /* sq_ass_slice */ +- (objobjproc)context_tp_contains, /* sq_contains */ +- 0, /* sq_inplace_concat */ +- 0, /* sq_inplace_repeat */ ++ .sq_contains = context_tp_contains + }; + + static PyMappingMethods PyContext_as_mapping = { +- (lenfunc)context_tp_len, /* mp_length */ +- (binaryfunc)context_tp_subscript, /* mp_subscript */ ++ .mp_length = context_tp_len, ++ .mp_subscript = context_tp_subscript + }; + + PyTypeObject PyContext_Type = { +@@ -763,13 +763,13 @@ + .tp_methods = PyContext_methods, + .tp_as_mapping = &PyContext_as_mapping, + .tp_as_sequence = &PyContext_as_sequence, +- .tp_iter = (getiterfunc)context_tp_iter, +- .tp_dealloc = (destructor)context_tp_dealloc, ++ .tp_iter = context_tp_iter, ++ .tp_dealloc = context_tp_dealloc, + .tp_getattro = PyObject_GenericGetAttr, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + .tp_richcompare = context_tp_richcompare, +- .tp_traverse = (traverseproc)context_tp_traverse, +- .tp_clear = (inquiry)context_tp_clear, ++ .tp_traverse = context_tp_traverse, ++ .tp_clear = context_tp_clear, + .tp_new = context_tp_new, + .tp_weaklistoffset = offsetof(PyContext, ctx_weakreflist), + .tp_hash = PyObject_HashNotImplemented, +@@ -860,7 +860,7 @@ + return -1; + } + +- Py_hash_t res = _Py_HashPointer(addr) ^ name_hash; ++ Py_hash_t res = Py_HashPointer(addr) ^ name_hash; + return res == -1 ? -2 : res; + } + +@@ -909,6 +909,9 @@ + /*[clinic end generated code: output=da39a3ee5e6b4b0d input=445da935fa8883c3]*/ + + ++#define _PyContextVar_CAST(op) ((PyContextVar *)(op)) ++ ++ + static PyObject * + contextvar_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) + { +@@ -926,8 +929,9 @@ + } + + static int +-contextvar_tp_clear(PyContextVar *self) ++contextvar_tp_clear(PyObject *op) + { ++ PyContextVar *self = _PyContextVar_CAST(op); + Py_CLEAR(self->var_name); + Py_CLEAR(self->var_default); + #ifndef Py_GIL_DISABLED +@@ -939,15 +943,16 @@ + } + + static int +-contextvar_tp_traverse(PyContextVar *self, visitproc visit, void *arg) ++contextvar_tp_traverse(PyObject *op, visitproc visit, void *arg) + { ++ PyContextVar *self = _PyContextVar_CAST(op); + Py_VISIT(self->var_name); + Py_VISIT(self->var_default); + return 0; + } + + static void +-contextvar_tp_dealloc(PyContextVar *self) ++contextvar_tp_dealloc(PyObject *self) + { + PyObject_GC_UnTrack(self); + (void)contextvar_tp_clear(self); +@@ -955,14 +960,16 @@ + } + + static Py_hash_t +-contextvar_tp_hash(PyContextVar *self) ++contextvar_tp_hash(PyObject *op) + { ++ PyContextVar *self = _PyContextVar_CAST(op); + return self->var_hash; + } + + static PyObject * +-contextvar_tp_repr(PyContextVar *self) ++contextvar_tp_repr(PyObject *op) + { ++ PyContextVar *self = _PyContextVar_CAST(op); + // Estimation based on the shortest name and default value, + // but maximize the pointer size. + // "" +@@ -1106,15 +1113,15 @@ + sizeof(PyContextVar), + .tp_methods = PyContextVar_methods, + .tp_members = PyContextVar_members, +- .tp_dealloc = (destructor)contextvar_tp_dealloc, ++ .tp_dealloc = contextvar_tp_dealloc, + .tp_getattro = PyObject_GenericGetAttr, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, +- .tp_traverse = (traverseproc)contextvar_tp_traverse, +- .tp_clear = (inquiry)contextvar_tp_clear, ++ .tp_traverse = contextvar_tp_traverse, ++ .tp_clear = contextvar_tp_clear, + .tp_new = contextvar_tp_new, + .tp_free = PyObject_GC_Del, +- .tp_hash = (hashfunc)contextvar_tp_hash, +- .tp_repr = (reprfunc)contextvar_tp_repr, ++ .tp_hash = contextvar_tp_hash, ++ .tp_repr = contextvar_tp_repr, + }; + + +@@ -1129,6 +1136,9 @@ + /*[clinic end generated code: output=da39a3ee5e6b4b0d input=338a5e2db13d3f5b]*/ + + ++#define _PyContextToken_CAST(op) ((PyContextToken *)(op)) ++ ++ + static PyObject * + token_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) + { +@@ -1138,8 +1148,9 @@ + } + + static int +-token_tp_clear(PyContextToken *self) ++token_tp_clear(PyObject *op) + { ++ PyContextToken *self = _PyContextToken_CAST(op); + Py_CLEAR(self->tok_ctx); + Py_CLEAR(self->tok_var); + Py_CLEAR(self->tok_oldval); +@@ -1147,8 +1158,9 @@ + } + + static int +-token_tp_traverse(PyContextToken *self, visitproc visit, void *arg) ++token_tp_traverse(PyObject *op, visitproc visit, void *arg) + { ++ PyContextToken *self = _PyContextToken_CAST(op); + Py_VISIT(self->tok_ctx); + Py_VISIT(self->tok_var); + Py_VISIT(self->tok_oldval); +@@ -1156,7 +1168,7 @@ + } + + static void +-token_tp_dealloc(PyContextToken *self) ++token_tp_dealloc(PyObject *self) + { + PyObject_GC_UnTrack(self); + (void)token_tp_clear(self); +@@ -1164,8 +1176,9 @@ + } + + static PyObject * +-token_tp_repr(PyContextToken *self) ++token_tp_repr(PyObject *op) + { ++ PyContextToken *self = _PyContextToken_CAST(op); + PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); + if (writer == NULL) { + return NULL; +@@ -1195,14 +1208,16 @@ + } + + static PyObject * +-token_get_var(PyContextToken *self, void *Py_UNUSED(ignored)) ++token_get_var(PyObject *op, void *Py_UNUSED(ignored)) + { ++ PyContextToken *self = _PyContextToken_CAST(op); + return Py_NewRef(self->tok_var);; + } + + static PyObject * +-token_get_old_value(PyContextToken *self, void *Py_UNUSED(ignored)) ++token_get_old_value(PyObject *op, void *Py_UNUSED(ignored)) + { ++ PyContextToken *self = _PyContextToken_CAST(op); + if (self->tok_oldval == NULL) { + return get_token_missing(); + } +@@ -1211,8 +1226,8 @@ + } + + static PyGetSetDef PyContextTokenType_getsetlist[] = { +- {"var", (getter)token_get_var, NULL, NULL}, +- {"old_value", (getter)token_get_old_value, NULL, NULL}, ++ {"var", token_get_var, NULL, NULL}, ++ {"old_value", token_get_old_value, NULL, NULL}, + {NULL} + }; + +@@ -1228,15 +1243,15 @@ + sizeof(PyContextToken), + .tp_methods = PyContextTokenType_methods, + .tp_getset = PyContextTokenType_getsetlist, +- .tp_dealloc = (destructor)token_tp_dealloc, ++ .tp_dealloc = token_tp_dealloc, + .tp_getattro = PyObject_GenericGetAttr, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, +- .tp_traverse = (traverseproc)token_tp_traverse, +- .tp_clear = (inquiry)token_tp_clear, ++ .tp_traverse = token_tp_traverse, ++ .tp_clear = token_tp_clear, + .tp_new = token_tp_new, + .tp_free = PyObject_GC_Del, + .tp_hash = PyObject_HashNotImplemented, +- .tp_repr = (reprfunc)token_tp_repr, ++ .tp_repr = token_tp_repr, + }; + + static PyContextToken * +@@ -1270,7 +1285,7 @@ + } + + static void +-context_token_missing_tp_dealloc(_PyContextTokenMissing *Py_UNUSED(self)) ++context_token_missing_tp_dealloc(PyObject *Py_UNUSED(self)) + { + #ifdef Py_DEBUG + /* The singleton is statically allocated. */ +@@ -1285,7 +1300,7 @@ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "Token.MISSING", + sizeof(_PyContextTokenMissing), +- .tp_dealloc = (destructor)context_token_missing_tp_dealloc, ++ .tp_dealloc = context_token_missing_tp_dealloc, + .tp_getattro = PyObject_GenericGetAttr, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_repr = context_token_missing_tp_repr, +diff --git a/Python/critical_section.c b/Python/critical_section.c +index 62ed25523fd..73857b85496 100644 +--- a/Python/critical_section.c ++++ b/Python/critical_section.c +@@ -8,11 +8,28 @@ + "critical section must be aligned to at least 4 bytes"); + #endif + ++#ifdef Py_GIL_DISABLED ++static PyCriticalSection * ++untag_critical_section(uintptr_t tag) ++{ ++ return (PyCriticalSection *)(tag & ~_Py_CRITICAL_SECTION_MASK); ++} ++#endif ++ + void + _PyCriticalSection_BeginSlow(PyCriticalSection *c, PyMutex *m) + { + #ifdef Py_GIL_DISABLED + PyThreadState *tstate = _PyThreadState_GET(); ++ // As an optimisation for locking the same object recursively, skip ++ // locking if the mutex is currently locked by the top-most critical ++ // section. ++ if (tstate->critical_section && ++ untag_critical_section(tstate->critical_section)->_cs_mutex == m) { ++ c->_cs_mutex = NULL; ++ c->_cs_prev = 0; ++ return; ++ } + c->_cs_mutex = NULL; + c->_cs_prev = (uintptr_t)tstate->critical_section; + tstate->critical_section = (uintptr_t)c; +@@ -42,13 +59,6 @@ + #endif + } + +-#ifdef Py_GIL_DISABLED +-static PyCriticalSection * +-untag_critical_section(uintptr_t tag) +-{ +- return (PyCriticalSection *)(tag & ~_Py_CRITICAL_SECTION_MASK); +-} +-#endif + + // Release all locks held by critical sections. This is called by + // _PyThreadState_Detach. +diff --git a/Python/crossinterp.c b/Python/crossinterp.c +index 0a106ad636b..aa2c1cb78bc 100644 +--- a/Python/crossinterp.c ++++ b/Python/crossinterp.c +@@ -368,12 +368,9 @@ + PyObject *create = NULL; + + // This is inspired by _PyErr_Display(). +- PyObject *tbmod = PyImport_ImportModule("traceback"); +- if (tbmod == NULL) { +- return -1; +- } +- PyObject *tbexc_type = PyObject_GetAttrString(tbmod, "TracebackException"); +- Py_DECREF(tbmod); ++ PyObject *tbexc_type = PyImport_ImportModuleAttrString( ++ "traceback", ++ "TracebackException"); + if (tbexc_type == NULL) { + return -1; + } +@@ -784,7 +781,8 @@ + PyObject *exc = PyErr_GetRaisedException(); + if (PyObject_SetAttrString(exc, "_errdisplay", tbexc) < 0) { + #ifdef Py_DEBUG +- PyErr_FormatUnraisable("Exception ignored when setting _errdisplay"); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "setting _errdisplay"); + #endif + PyErr_Clear(); + } +diff --git a/Python/emscripten_trampoline.c b/Python/emscripten_trampoline.c +index 960c6b4a2ef..0293c7ea0f3 100644 +--- a/Python/emscripten_trampoline.c ++++ b/Python/emscripten_trampoline.c +@@ -1,79 +1,203 @@ + #if defined(PY_CALL_TRAMPOLINE) + +-#include // EM_JS ++#include // EM_JS, EM_JS_DEPS + #include + #include "pycore_runtime.h" // _PyRuntime + ++typedef int (*CountArgsFunc)(PyCFunctionWithKeywords func); + +-/** +- * This is the GoogleChromeLabs approved way to feature detect type-reflection: +- * https://github.com/GoogleChromeLabs/wasm-feature-detect/blob/main/src/detectors/type-reflection/index.js +- */ +-EM_JS(int, _PyEM_detect_type_reflection, (), { +- if (!("Function" in WebAssembly)) { +- return false; +- } +- if (WebAssembly.Function.type) { +- // Node v20 +- Module.PyEM_CountArgs = (func) => WebAssembly.Function.type(wasmTable.get(func)).parameters.length; +- } else { +- // Node >= 22, v8-based browsers +- Module.PyEM_CountArgs = (func) => wasmTable.get(func).type().parameters.length; ++// Offset of emscripten_count_args_function in _PyRuntimeState. There's a couple ++// of alternatives: ++// 1. Just make emscripten_count_args_function a real C global variable instead ++// of a field of _PyRuntimeState. This would violate our rule against mutable ++// globals. ++// 2. #define a preprocessor constant equal to a hard coded number and make a ++// _Static_assert(offsetof(_PyRuntimeState, emscripten_count_args_function) ++// == OURCONSTANT) This has the disadvantage that we have to update the hard ++// coded constant when _PyRuntimeState changes ++// ++// So putting the mutable constant in _PyRuntime and using a immutable global to ++// record the offset so we can access it from JS is probably the best way. ++EMSCRIPTEN_KEEPALIVE const int _PyEM_EMSCRIPTEN_COUNT_ARGS_OFFSET = offsetof(_PyRuntimeState, emscripten_count_args_function); ++ ++EM_JS(CountArgsFunc, _PyEM_GetCountArgsPtr, (), { ++ return Module._PyEM_CountArgsPtr; // initialized below ++} ++// Binary module for the checks. It has to be done in web assembly because ++// clang/llvm have no support yet for the reference types yet. In fact, the wasm ++// binary toolkit doesn't yet support the ref.test instruction either. To ++// convert the following textual wasm to a binary, you can build wabt from this ++// branch: https://github.com/WebAssembly/wabt/pull/2529 and then use that ++// wat2wasm binary. ++// ++// (module ++// (type $type0 (func (param) (result i32))) ++// (type $type1 (func (param i32) (result i32))) ++// (type $type2 (func (param i32 i32) (result i32))) ++// (type $type3 (func (param i32 i32 i32) (result i32))) ++// (type $blocktype (func (param i32) (result))) ++// (table $funcs (import "e" "t") 0 funcref) ++// (export "f" (func $f)) ++// (func $f (param $fptr i32) (result i32) ++// (local $fref funcref) ++// local.get $fptr ++// table.get $funcs ++// local.tee $fref ++// ref.test $type3 ++// (block $b (type $blocktype) ++// i32.eqz ++// br_if $b ++// i32.const 3 ++// return ++// ) ++// local.get $fref ++// ref.test $type2 ++// (block $b (type $blocktype) ++// i32.eqz ++// br_if $b ++// i32.const 2 ++// return ++// ) ++// local.get $fref ++// ref.test $type1 ++// (block $b (type $blocktype) ++// i32.eqz ++// br_if $b ++// i32.const 1 ++// return ++// ) ++// local.get $fref ++// ref.test $type0 ++// (block $b (type $blocktype) ++// i32.eqz ++// br_if $b ++// i32.const 0 ++// return ++// ) ++// i32.const -1 ++// ) ++// ) ++addOnPreRun(() => { ++ // Try to initialize countArgsFunc ++ const code = new Uint8Array([ ++ 0x00, 0x61, 0x73, 0x6d, // \0asm magic number ++ 0x01, 0x00, 0x00, 0x00, // version 1 ++ 0x01, 0x1b, // Type section, body is 0x1b bytes ++ 0x05, // 6 entries ++ 0x60, 0x00, 0x01, 0x7f, // (type $type0 (func (param) (result i32))) ++ 0x60, 0x01, 0x7f, 0x01, 0x7f, // (type $type1 (func (param i32) (result i32))) ++ 0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f, // (type $type2 (func (param i32 i32) (result i32))) ++ 0x60, 0x03, 0x7f, 0x7f, 0x7f, 0x01, 0x7f, // (type $type3 (func (param i32 i32 i32) (result i32))) ++ 0x60, 0x01, 0x7f, 0x00, // (type $blocktype (func (param i32) (result))) ++ 0x02, 0x09, // Import section, 0x9 byte body ++ 0x01, // 1 import (table $funcs (import "e" "t") 0 funcref) ++ 0x01, 0x65, // "e" ++ 0x01, 0x74, // "t" ++ 0x01, // importing a table ++ 0x70, // of entry type funcref ++ 0x00, 0x00, // table limits: no max, min of 0 ++ 0x03, 0x02, // Function section ++ 0x01, 0x01, // We're going to define one function of type 1 (func (param i32) (result i32)) ++ 0x07, 0x05, // export section ++ 0x01, // 1 export ++ 0x01, 0x66, // called "f" ++ 0x00, // a function ++ 0x00, // at index 0 ++ ++ 0x0a, 0x44, // Code section, ++ 0x01, 0x42, // one entry of length 50 ++ 0x01, 0x01, 0x70, // one local of type funcref ++ // Body of the function ++ 0x20, 0x00, // local.get $fptr ++ 0x25, 0x00, // table.get $funcs ++ 0x22, 0x01, // local.tee $fref ++ 0xfb, 0x14, 0x03, // ref.test $type3 ++ 0x02, 0x04, // block $b (type $blocktype) ++ 0x45, // i32.eqz ++ 0x0d, 0x00, // br_if $b ++ 0x41, 0x03, // i32.const 3 ++ 0x0f, // return ++ 0x0b, // end block ++ ++ 0x20, 0x01, // local.get $fref ++ 0xfb, 0x14, 0x02, // ref.test $type2 ++ 0x02, 0x04, // block $b (type $blocktype) ++ 0x45, // i32.eqz ++ 0x0d, 0x00, // br_if $b ++ 0x41, 0x02, // i32.const 2 ++ 0x0f, // return ++ 0x0b, // end block ++ ++ 0x20, 0x01, // local.get $fref ++ 0xfb, 0x14, 0x01, // ref.test $type1 ++ 0x02, 0x04, // block $b (type $blocktype) ++ 0x45, // i32.eqz ++ 0x0d, 0x00, // br_if $b ++ 0x41, 0x01, // i32.const 1 ++ 0x0f, // return ++ 0x0b, // end block ++ ++ 0x20, 0x01, // local.get $fref ++ 0xfb, 0x14, 0x00, // ref.test $type0 ++ 0x02, 0x04, // block $b (type $blocktype) ++ 0x45, // i32.eqz ++ 0x0d, 0x00, // br_if $b ++ 0x41, 0x00, // i32.const 0 ++ 0x0f, // return ++ 0x0b, // end block ++ ++ 0x41, 0x7f, // i32.const -1 ++ 0x0b // end function ++ ]); ++ let ptr = 0; ++ try { ++ const mod = new WebAssembly.Module(code); ++ const inst = new WebAssembly.Instance(mod, { e: { t: wasmTable } }); ++ ptr = addFunction(inst.exports.f); ++ } catch (e) { ++ // If something goes wrong, we'll null out _PyEM_CountFuncParams and fall ++ // back to the JS trampoline. + } +- return true; ++ Module._PyEM_CountArgsPtr = ptr; ++ const offset = HEAP32[__PyEM_EMSCRIPTEN_COUNT_ARGS_OFFSET / 4]; ++ HEAP32[(__PyRuntime + offset) / 4] = ptr; + }); ++); + + void + _Py_EmscriptenTrampoline_Init(_PyRuntimeState *runtime) + { +- runtime->wasm_type_reflection_available = _PyEM_detect_type_reflection(); ++ runtime->emscripten_count_args_function = _PyEM_GetCountArgsPtr(); + } + ++// We have to be careful to work correctly with memory snapshots. Even if we are ++// loading a memory snapshot, we need to perform the JS initialization work. ++// That means we can't call the initialization code from C. Instead, we export ++// this function pointer to JS and then fill it in a preRun function which runs ++// unconditionally. + /** + * Backwards compatible trampoline works with all JS runtimes + */ +-EM_JS(PyObject*, +-_PyEM_TrampolineCall_JavaScript, (PyCFunctionWithKeywords func, +- PyObject *arg1, +- PyObject *arg2, +- PyObject *arg3), +-{ ++EM_JS(PyObject*, _PyEM_TrampolineCall_JS, (PyCFunctionWithKeywords func, PyObject *arg1, PyObject *arg2, PyObject *arg3), { + return wasmTable.get(func)(arg1, arg2, arg3); +-} +-); +- +-/** +- * In runtimes with WebAssembly type reflection, count the number of parameters +- * and cast to the appropriate signature +- */ +-EM_JS(int, _PyEM_CountFuncParams, (PyCFunctionWithKeywords func), +-{ +- let n = _PyEM_CountFuncParams.cache.get(func); +- +- if (n !== undefined) { +- return n; +- } +- n = Module.PyEM_CountArgs(func); +- _PyEM_CountFuncParams.cache.set(func, n); +- return n; +-} +-_PyEM_CountFuncParams.cache = new Map(); +-) +- ++}); + + typedef PyObject* (*zero_arg)(void); + typedef PyObject* (*one_arg)(PyObject*); + typedef PyObject* (*two_arg)(PyObject*, PyObject*); + typedef PyObject* (*three_arg)(PyObject*, PyObject*, PyObject*); + +- + PyObject* +-_PyEM_TrampolineCall_Reflection(PyCFunctionWithKeywords func, +- PyObject* self, +- PyObject* args, +- PyObject* kw) ++_PyEM_TrampolineCall(PyCFunctionWithKeywords func, ++ PyObject* self, ++ PyObject* args, ++ PyObject* kw) + { +- switch (_PyEM_CountFuncParams(func)) { ++ CountArgsFunc count_args = _PyRuntime.emscripten_count_args_function; ++ if (count_args == 0) { ++ return _PyEM_TrampolineCall_JS(func, self, args, kw); ++ } ++ switch (count_args(func)) { + case 0: + return ((zero_arg)func)(); + case 1: +@@ -83,8 +207,7 @@ + case 3: + return ((three_arg)func)(self, args, kw); + default: +- PyErr_SetString(PyExc_SystemError, +- "Handler takes too many arguments"); ++ PyErr_SetString(PyExc_SystemError, "Handler takes too many arguments"); + return NULL; + } + } +diff --git a/Python/errors.c b/Python/errors.c +index 7f3b4aabc43..0a19d898da7 100644 +--- a/Python/errors.c ++++ b/Python/errors.c +@@ -301,12 +301,21 @@ + _PyErr_SetString(tstate, exception, string); + } + ++void ++_PyErr_SetLocaleString(PyObject *exception, const char *string) ++{ ++ PyObject *value = PyUnicode_DecodeLocale(string, "surrogateescape"); ++ if (value != NULL) { ++ PyErr_SetObject(exception, value); ++ Py_DECREF(value); ++ } ++} + + PyObject* _Py_HOT_FUNCTION + PyErr_Occurred(void) + { +- /* The caller must hold the GIL. */ +- assert(PyGILState_Check()); ++ /* The caller must hold a thread state. */ ++ _Py_AssertHoldsTstate(); + + PyThreadState *tstate = _PyThreadState_GET(); + return _PyErr_Occurred(tstate); +@@ -1624,7 +1633,7 @@ + PyObject *hook_args = make_unraisable_hook_args( + tstate, exc_type, exc_value, exc_tb, err_msg, obj); + if (hook_args == NULL) { +- err_msg_str = ("Exception ignored on building " ++ err_msg_str = ("Exception ignored while building " + "sys.unraisablehook arguments"); + goto error; + } +@@ -1972,7 +1981,7 @@ + return NULL; + } + +- FILE *fp = _Py_fopen_obj(filename, "r" PY_STDIOTEXTMODE); ++ FILE *fp = Py_fopen(filename, "r" PY_STDIOTEXTMODE); + if (fp == NULL) { + PyErr_Clear(); + return NULL; +diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h +index 55e9c3aa2db..96b7386bd24 100644 +--- a/Python/executor_cases.c.h ++++ b/Python/executor_cases.c.h +@@ -19,7 +19,9 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err != 0) JUMP_TO_ERROR(); ++ if (err != 0) { ++ JUMP_TO_ERROR(); ++ } + } + break; + } +@@ -33,7 +35,9 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err != 0) JUMP_TO_ERROR(); ++ if (err != 0) { ++ JUMP_TO_ERROR(); ++ } + } + } + break; +@@ -81,7 +85,7 @@ + PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames, oparg) + ); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (1) JUMP_TO_ERROR(); ++ JUMP_TO_ERROR(); + } + value = PyStackRef_DUP(value_s); + stack_pointer[0] = value; +@@ -201,7 +205,6 @@ + _PyStackRef value; + oparg = CURRENT_OPARG(); + value = GETLOCAL(oparg); +- // do not use SETLOCAL here, it decrefs the old value + GETLOCAL(oparg) = PyStackRef_NULL; + stack_pointer[0] = value; + stack_pointer += 1; +@@ -209,10 +212,13 @@ + break; + } + +- case _LOAD_CONST: { ++ /* _LOAD_CONST is not a viable micro-op for tier 2 because it uses the 'this_instr' variable */ ++ ++ case _LOAD_CONST_MORTAL: { + _PyStackRef value; + oparg = CURRENT_OPARG(); +- value = PyStackRef_FromPyObjectNew(GETITEM(FRAME_CO_CONSTS, oparg)); ++ PyObject *obj = GETITEM(FRAME_CO_CONSTS, oparg); ++ value = PyStackRef_FromPyObjectNew(obj); + stack_pointer[0] = value; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); +@@ -300,9 +306,13 @@ + oparg = 0; + assert(oparg == CURRENT_OPARG()); + value = stack_pointer[-1]; +- SETLOCAL(oparg, value); ++ _PyStackRef tmp = GETLOCAL(oparg); ++ GETLOCAL(oparg) = value; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_XCLOSE(tmp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + break; + } + +@@ -311,9 +321,13 @@ + oparg = 1; + assert(oparg == CURRENT_OPARG()); + value = stack_pointer[-1]; +- SETLOCAL(oparg, value); ++ _PyStackRef tmp = GETLOCAL(oparg); ++ GETLOCAL(oparg) = value; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_XCLOSE(tmp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + break; + } + +@@ -322,9 +336,13 @@ + oparg = 2; + assert(oparg == CURRENT_OPARG()); + value = stack_pointer[-1]; +- SETLOCAL(oparg, value); ++ _PyStackRef tmp = GETLOCAL(oparg); ++ GETLOCAL(oparg) = value; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_XCLOSE(tmp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + break; + } + +@@ -333,9 +351,13 @@ + oparg = 3; + assert(oparg == CURRENT_OPARG()); + value = stack_pointer[-1]; +- SETLOCAL(oparg, value); ++ _PyStackRef tmp = GETLOCAL(oparg); ++ GETLOCAL(oparg) = value; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_XCLOSE(tmp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + break; + } + +@@ -344,9 +366,13 @@ + oparg = 4; + assert(oparg == CURRENT_OPARG()); + value = stack_pointer[-1]; +- SETLOCAL(oparg, value); ++ _PyStackRef tmp = GETLOCAL(oparg); ++ GETLOCAL(oparg) = value; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_XCLOSE(tmp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + break; + } + +@@ -355,9 +381,13 @@ + oparg = 5; + assert(oparg == CURRENT_OPARG()); + value = stack_pointer[-1]; +- SETLOCAL(oparg, value); ++ _PyStackRef tmp = GETLOCAL(oparg); ++ GETLOCAL(oparg) = value; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_XCLOSE(tmp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + break; + } + +@@ -366,9 +396,13 @@ + oparg = 6; + assert(oparg == CURRENT_OPARG()); + value = stack_pointer[-1]; +- SETLOCAL(oparg, value); ++ _PyStackRef tmp = GETLOCAL(oparg); ++ GETLOCAL(oparg) = value; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_XCLOSE(tmp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + break; + } + +@@ -377,9 +411,13 @@ + oparg = 7; + assert(oparg == CURRENT_OPARG()); + value = stack_pointer[-1]; +- SETLOCAL(oparg, value); ++ _PyStackRef tmp = GETLOCAL(oparg); ++ GETLOCAL(oparg) = value; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_XCLOSE(tmp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + break; + } + +@@ -387,9 +425,13 @@ + _PyStackRef value; + oparg = CURRENT_OPARG(); + value = stack_pointer[-1]; +- SETLOCAL(oparg, value); ++ _PyStackRef tmp = GETLOCAL(oparg); ++ GETLOCAL(oparg) = value; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_XCLOSE(tmp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + break; + } + +@@ -411,6 +453,22 @@ + break; + } + ++ case _END_FOR: { ++ _PyStackRef value; ++ value = stack_pointer[-1]; ++ /* Don't update instr_ptr, so that POP_ITER sees ++ * the FOR_ITER as the previous instruction. ++ * This has the benign side effect that if value is ++ * finalized it will see the location as the FOR_ITER's. ++ */ ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(value); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ break; ++ } ++ + case _END_SEND: { + _PyStackRef value; + _PyStackRef receiver; +@@ -434,7 +492,11 @@ + PyObject *res_o = PyNumber_Negative(PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(value); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ if (res_o == NULL) { ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-1] = res; + break; +@@ -459,7 +521,11 @@ + int err = PyObject_IsTrue(PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(value); +- if (err < 0) JUMP_TO_ERROR(); ++ if (err < 0) { ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + res = err ? PyStackRef_True : PyStackRef_False; + stack_pointer[-1] = res; + break; +@@ -570,7 +636,11 @@ + PyObject *res_o = PyNumber_Invert(PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(value); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ if (res_o == NULL) { ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-1] = res; + break; +@@ -624,11 +694,17 @@ + left = stack_pointer[-2]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(PyLong_CheckExact(left_o)); ++ assert(PyLong_CheckExact(right_o)); + STAT_INC(BINARY_OP, hit); + PyObject *res_o = _PyLong_Multiply((PyLongObject *)left_o, (PyLongObject *)right_o); + PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ if (res_o == NULL) { ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -644,11 +720,17 @@ + left = stack_pointer[-2]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(PyLong_CheckExact(left_o)); ++ assert(PyLong_CheckExact(right_o)); + STAT_INC(BINARY_OP, hit); + PyObject *res_o = _PyLong_Add((PyLongObject *)left_o, (PyLongObject *)right_o); + PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ if (res_o == NULL) { ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -664,11 +746,17 @@ + left = stack_pointer[-2]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(PyLong_CheckExact(left_o)); ++ assert(PyLong_CheckExact(right_o)); + STAT_INC(BINARY_OP, hit); + PyObject *res_o = _PyLong_Subtract((PyLongObject *)left_o, (PyLongObject *)right_o); + PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ if (res_o == NULL) { ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -724,12 +812,18 @@ + left = stack_pointer[-2]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(PyFloat_CheckExact(left_o)); ++ assert(PyFloat_CheckExact(right_o)); + STAT_INC(BINARY_OP, hit); + double dres = + ((PyFloatObject *)left_o)->ob_fval * + ((PyFloatObject *)right_o)->ob_fval; + PyObject *res_o = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ if (res_o == NULL) { ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -745,12 +839,18 @@ + left = stack_pointer[-2]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(PyFloat_CheckExact(left_o)); ++ assert(PyFloat_CheckExact(right_o)); + STAT_INC(BINARY_OP, hit); + double dres = + ((PyFloatObject *)left_o)->ob_fval + + ((PyFloatObject *)right_o)->ob_fval; + PyObject *res_o = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ if (res_o == NULL) { ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -766,12 +866,18 @@ + left = stack_pointer[-2]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(PyFloat_CheckExact(left_o)); ++ assert(PyFloat_CheckExact(right_o)); + STAT_INC(BINARY_OP, hit); + double dres = + ((PyFloatObject *)left_o)->ob_fval - + ((PyFloatObject *)right_o)->ob_fval; + PyObject *res_o = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ if (res_o == NULL) { ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -805,11 +911,17 @@ + left = stack_pointer[-2]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(PyUnicode_CheckExact(left_o)); ++ assert(PyUnicode_CheckExact(right_o)); + STAT_INC(BINARY_OP, hit); + PyObject *res_o = PyUnicode_Concat(left_o, right_o); +- PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); ++ if (res_o == NULL) { ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -824,6 +936,8 @@ + left = stack_pointer[-2]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(PyUnicode_CheckExact(left_o)); ++ assert(PyUnicode_CheckExact(right_o)); + int next_oparg; + #if TIER_ONE + assert(next_instr->op.code == STORE_FAST); +@@ -849,12 +963,16 @@ + * that the string is safe to mutate. + */ + assert(Py_REFCNT(left_o) >= 2); +- PyStackRef_CLOSE(left); +- PyObject *temp = PyStackRef_AsPyObjectBorrow(*target_local); ++ PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); ++ PyObject *temp = PyStackRef_AsPyObjectSteal(*target_local); + PyUnicode_Append(&temp, right_o); + *target_local = PyStackRef_FromPyObjectSteal(temp); + PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); +- if (PyStackRef_IsNull(*target_local)) JUMP_TO_ERROR(); ++ if (PyStackRef_IsNull(*target_local)) { ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + #if TIER_ONE + // The STORE_FAST is already done. This is done here in tier one, + // and during trace projection in tier two: +@@ -866,20 +984,44 @@ + break; + } + +- case _BINARY_SUBSCR: { +- _PyStackRef sub; +- _PyStackRef container; ++ case _GUARD_BINARY_OP_EXTEND: { ++ _PyStackRef right; ++ _PyStackRef left; ++ right = stack_pointer[-1]; ++ left = stack_pointer[-2]; ++ PyObject *descr = (PyObject *)CURRENT_OPERAND0(); ++ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); ++ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ _PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr; ++ assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5); ++ assert(d && d->guard); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ int res = d->guard(left_o, right_o); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (!res) { ++ UOP_STAT_INC(uopcode, miss); ++ JUMP_TO_JUMP_TARGET(); ++ } ++ break; ++ } ++ ++ case _BINARY_OP_EXTEND: { ++ _PyStackRef right; ++ _PyStackRef left; + _PyStackRef res; +- sub = stack_pointer[-1]; +- container = stack_pointer[-2]; +- PyObject *container_o = PyStackRef_AsPyObjectBorrow(container); +- PyObject *sub_o = PyStackRef_AsPyObjectBorrow(sub); ++ right = stack_pointer[-1]; ++ left = stack_pointer[-2]; ++ PyObject *descr = (PyObject *)CURRENT_OPERAND0(); ++ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); ++ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5); ++ _PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr; ++ STAT_INC(BINARY_OP, hit); + _PyFrame_SetStackPointer(frame, stack_pointer); +- PyObject *res_o = PyObject_GetItem(container_o, sub_o); ++ PyObject *res_o = d->action(left_o, right_o); + stack_pointer = _PyFrame_GetStackPointer(frame); +- PyStackRef_CLOSE(container); +- PyStackRef_CLOSE(sub); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ PyStackRef_CLOSE(left); ++ PyStackRef_CLOSE(right); + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -910,16 +1052,22 @@ + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + res_o = PyObject_GetItem(PyStackRef_AsPyObjectBorrow(container), slice); +- stack_pointer = _PyFrame_GetStackPointer(frame); + Py_DECREF(slice); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += 2; + assert(WITHIN_STACK_BOUNDS()); + } ++ stack_pointer += -3; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(container); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (res_o == NULL) { ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); +- stack_pointer[-3] = res; +- stack_pointer += -2; ++ stack_pointer[0] = res; ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } +@@ -946,20 +1094,24 @@ + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + err = PyObject_SetItem(PyStackRef_AsPyObjectBorrow(container), slice, PyStackRef_AsPyObjectBorrow(v)); +- stack_pointer = _PyFrame_GetStackPointer(frame); + Py_DECREF(slice); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += 2; + assert(WITHIN_STACK_BOUNDS()); + } + PyStackRef_CLOSE(v); + PyStackRef_CLOSE(container); +- if (err) JUMP_TO_ERROR(); ++ if (err) { ++ stack_pointer += -4; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + stack_pointer += -4; + assert(WITHIN_STACK_BOUNDS()); + break; + } + +- case _BINARY_SUBSCR_LIST_INT: { ++ case _BINARY_OP_SUBSCR_LIST_INT: { + _PyStackRef sub_st; + _PyStackRef list_st; + _PyStackRef res; +@@ -989,27 +1141,31 @@ + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } +- STAT_INC(BINARY_SUBSCR, hit); ++ STAT_INC(BINARY_OP, hit); + #else + if (index >= PyList_GET_SIZE(list)) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } +- STAT_INC(BINARY_SUBSCR, hit); ++ STAT_INC(BINARY_OP, hit); + PyObject *res_o = PyList_GET_ITEM(list, index); + assert(res_o != NULL); + Py_INCREF(res_o); + #endif + PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(list_st); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + res = PyStackRef_FromPyObjectSteal(res_o); +- stack_pointer[-2] = res; +- stack_pointer += -1; ++ stack_pointer[0] = res; ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } + +- case _BINARY_SUBSCR_STR_INT: { ++ case _BINARY_OP_SUBSCR_STR_INT: { + _PyStackRef sub_st; + _PyStackRef str_st; + _PyStackRef res; +@@ -1040,18 +1196,22 @@ + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } +- STAT_INC(BINARY_SUBSCR, hit); ++ STAT_INC(BINARY_OP, hit); + PyObject *res_o = (PyObject*)&_Py_SINGLETON(strings).ascii[c]; + PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(str_st); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + res = PyStackRef_FromPyObjectSteal(res_o); +- stack_pointer[-2] = res; +- stack_pointer += -1; ++ stack_pointer[0] = res; ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } + +- case _BINARY_SUBSCR_TUPLE_INT: { ++ case _BINARY_OP_SUBSCR_TUPLE_INT: { + _PyStackRef sub_st; + _PyStackRef tuple_st; + _PyStackRef res; +@@ -1077,20 +1237,24 @@ + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } +- STAT_INC(BINARY_SUBSCR, hit); ++ STAT_INC(BINARY_OP, hit); + PyObject *res_o = PyTuple_GET_ITEM(tuple, index); + assert(res_o != NULL); + Py_INCREF(res_o); + PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(tuple_st); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + res = PyStackRef_FromPyObjectSteal(res_o); +- stack_pointer[-2] = res; +- stack_pointer += -1; ++ stack_pointer[0] = res; ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } + +- case _BINARY_SUBSCR_DICT: { ++ case _BINARY_OP_SUBSCR_DICT: { + _PyStackRef sub_st; + _PyStackRef dict_st; + _PyStackRef res; +@@ -1102,7 +1266,7 @@ + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } +- STAT_INC(BINARY_SUBSCR, hit); ++ STAT_INC(BINARY_OP, hit); + PyObject *res_o; + _PyFrame_SetStackPointer(frame, stack_pointer); + int rc = PyDict_GetItemRef(dict, sub, &res_o); +@@ -1114,7 +1278,11 @@ + } + PyStackRef_CLOSE(dict_st); + PyStackRef_CLOSE(sub_st); +- if (rc <= 0) JUMP_TO_ERROR(); ++ if (rc <= 0) { ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + // not found or error + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-2] = res; +@@ -1123,8 +1291,9 @@ + break; + } + +- case _BINARY_SUBSCR_CHECK_FUNC: { ++ case _BINARY_OP_SUBSCR_CHECK_FUNC: { + _PyStackRef container; ++ _PyStackRef getitem; + container = stack_pointer[-2]; + PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(container)); + if (!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) { +@@ -1132,42 +1301,45 @@ + JUMP_TO_JUMP_TARGET(); + } + PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; +- PyObject *getitem = ht->_spec_cache.getitem; +- if (getitem == NULL) { ++ PyObject *getitem_o = FT_ATOMIC_LOAD_PTR_ACQUIRE(ht->_spec_cache.getitem); ++ if (getitem_o == NULL) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } +- assert(PyFunction_Check(getitem)); +- uint32_t cached_version = ht->_spec_cache.getitem_version; +- if (((PyFunctionObject *)getitem)->func_version != cached_version) { ++ assert(PyFunction_Check(getitem_o)); ++ uint32_t cached_version = FT_ATOMIC_LOAD_UINT32_RELAXED(ht->_spec_cache.getitem_version); ++ if (((PyFunctionObject *)getitem_o)->func_version != cached_version) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } +- PyCodeObject *code = (PyCodeObject *)PyFunction_GET_CODE(getitem); ++ PyCodeObject *code = (PyCodeObject *)PyFunction_GET_CODE(getitem_o); + assert(code->co_argcount == 2); + if (!_PyThreadState_HasStackSpace(tstate, code->co_framesize)) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } +- STAT_INC(BINARY_SUBSCR, hit); ++ getitem = PyStackRef_FromPyObjectNew(getitem_o); ++ STAT_INC(BINARY_OP, hit); ++ stack_pointer[0] = getitem; ++ stack_pointer += 1; ++ assert(WITHIN_STACK_BOUNDS()); + break; + } + +- case _BINARY_SUBSCR_INIT_CALL: { ++ case _BINARY_OP_SUBSCR_INIT_CALL: { ++ _PyStackRef getitem; + _PyStackRef sub; + _PyStackRef container; + _PyInterpreterFrame *new_frame; +- sub = stack_pointer[-1]; +- container = stack_pointer[-2]; +- PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(container)); +- PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; +- PyObject *getitem = ht->_spec_cache.getitem; +- new_frame = _PyFrame_PushUnchecked(tstate, PyStackRef_FromPyObjectNew(getitem), 2, frame); ++ getitem = stack_pointer[-1]; ++ sub = stack_pointer[-2]; ++ container = stack_pointer[-3]; ++ new_frame = _PyFrame_PushUnchecked(tstate, getitem, 2, frame); + new_frame->localsplus[0] = container; + new_frame->localsplus[1] = sub; +- frame->return_offset = 2 ; +- stack_pointer[-2].bits = (uintptr_t)new_frame; +- stack_pointer += -1; ++ frame->return_offset = 6 ; ++ stack_pointer[-3].bits = (uintptr_t)new_frame; ++ stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); + break; + } +@@ -1180,7 +1352,11 @@ + list = stack_pointer[-2 - (oparg-1)]; + int err = _PyList_AppendTakeRef((PyListObject *)PyStackRef_AsPyObjectBorrow(list), + PyStackRef_AsPyObjectSteal(v)); +- if (err < 0) JUMP_TO_ERROR(); ++ if (err < 0) { ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + break; +@@ -1197,7 +1373,11 @@ + PyStackRef_AsPyObjectBorrow(v)); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(v); +- if (err) JUMP_TO_ERROR(); ++ if (err) { ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + break; +@@ -1217,7 +1397,11 @@ + PyStackRef_CLOSE(v); + PyStackRef_CLOSE(container); + PyStackRef_CLOSE(sub); +- if (err) JUMP_TO_ERROR(); ++ if (err) { ++ stack_pointer += -3; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + stack_pointer += -3; + assert(WITHIN_STACK_BOUNDS()); + break; +@@ -1263,11 +1447,13 @@ + PyList_SET_ITEM(list, index, PyStackRef_AsPyObjectSteal(value)); + assert(old_value != NULL); + UNLOCK_OBJECT(list); // unlock before decrefs! +- Py_DECREF(old_value); + PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); +- PyStackRef_CLOSE(list_st); + stack_pointer += -3; + assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(list_st); ++ Py_DECREF(old_value); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + break; + } + +@@ -1289,10 +1475,14 @@ + PyStackRef_AsPyObjectSteal(sub), + PyStackRef_AsPyObjectSteal(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); +- PyStackRef_CLOSE(dict_st); +- if (err) JUMP_TO_ERROR(); + stack_pointer += -3; + assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(dict_st); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (err) { ++ JUMP_TO_ERROR(); ++ } + break; + } + +@@ -1308,7 +1498,11 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(container); + PyStackRef_CLOSE(sub); +- if (err) JUMP_TO_ERROR(); ++ if (err) { ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); + break; +@@ -1324,7 +1518,11 @@ + PyObject *res_o = _PyIntrinsics_UnaryFunctions[oparg].func(tstate, PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(value); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ if (res_o == NULL) { ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-1] = res; + break; +@@ -1345,7 +1543,11 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(value2_st); + PyStackRef_CLOSE(value1_st); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ if (res_o == NULL) { ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -1357,9 +1559,7 @@ + _PyStackRef retval; + _PyStackRef res; + retval = stack_pointer[-1]; +- #if TIER_ONE +- assert(frame != &entry_frame); +- #endif ++ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); + _PyStackRef temp = retval; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); +@@ -1399,13 +1599,19 @@ + type->tp_name); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(obj); +- if (true) JUMP_TO_ERROR(); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + iter_o = (*getter)(obj_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(obj); +- if (iter_o == NULL) JUMP_TO_ERROR(); ++ if (iter_o == NULL) { ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + if (Py_TYPE(iter_o)->tp_as_async == NULL || + Py_TYPE(iter_o)->tp_as_async->am_anext == NULL) { + stack_pointer += -1; +@@ -1415,9 +1621,9 @@ + "'async for' received an object from __aiter__ " + "that does not implement __anext__: %.100s", + Py_TYPE(iter_o)->tp_name); +- stack_pointer = _PyFrame_GetStackPointer(frame); + Py_DECREF(iter_o); +- if (true) JUMP_TO_ERROR(); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ JUMP_TO_ERROR(); + } + iter = PyStackRef_FromPyObjectSteal(iter_o); + stack_pointer[-1] = iter; +@@ -1450,7 +1656,11 @@ + PyObject *iter_o = _PyEval_GetAwaitable(PyStackRef_AsPyObjectBorrow(iterable), oparg); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(iterable); +- if (iter_o == NULL) JUMP_TO_ERROR(); ++ if (iter_o == NULL) { ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + iter = PyStackRef_FromPyObjectSteal(iter_o); + stack_pointer[-1] = iter; + break; +@@ -1495,9 +1705,7 @@ + // NOTE: It's important that YIELD_VALUE never raises an exception! + // The compiler treats any exception raised here as a failed close() + // or throw() call. +- #if TIER_ONE +- assert(frame != &entry_frame); +- #endif ++ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); + frame->instr_ptr++; + PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); + assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); +@@ -1573,13 +1781,15 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = PyMapping_GetOptionalItem(BUILTINS(), &_Py_ID(__build_class__), &bc_o); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err < 0) JUMP_TO_ERROR(); ++ if (err < 0) { ++ JUMP_TO_ERROR(); ++ } + if (bc_o == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyErr_SetString(tstate, PyExc_NameError, + "__build_class__ not found"); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (true) JUMP_TO_ERROR(); ++ JUMP_TO_ERROR(); + } + bc = PyStackRef_FromPyObjectSteal(bc_o); + stack_pointer[0] = bc; +@@ -1601,7 +1811,9 @@ + "no locals found when storing %R", name); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(v); +- if (true) JUMP_TO_ERROR(); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); + } + if (PyDict_CheckExact(ns)) { + _PyFrame_SetStackPointer(frame, stack_pointer); +@@ -1614,7 +1826,11 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + } + PyStackRef_CLOSE(v); +- if (err) JUMP_TO_ERROR(); ++ if (err) { ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + break; +@@ -1658,10 +1874,14 @@ + int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg, -1, top); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(seq); +- if (res == 0) JUMP_TO_ERROR(); +- stack_pointer += -1 + oparg; +- assert(WITHIN_STACK_BOUNDS()); +- break; ++ if (res == 0) { ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } ++ stack_pointer += -1 + oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ break; + } + + case _UNPACK_SEQUENCE_TWO_TUPLE: { +@@ -1762,7 +1982,11 @@ + int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg & 0xFF, oparg >> 8, top); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(seq); +- if (res == 0) JUMP_TO_ERROR(); ++ if (res == 0) { ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + stack_pointer += (oparg & 0xFF) + (oparg >> 8); + assert(WITHIN_STACK_BOUNDS()); + break; +@@ -1781,7 +2005,11 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(v); + PyStackRef_CLOSE(owner); +- if (err) JUMP_TO_ERROR(); ++ if (err) { ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); + break; +@@ -1796,7 +2024,11 @@ + int err = PyObject_DelAttr(PyStackRef_AsPyObjectBorrow(owner), name); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(owner); +- if (err) JUMP_TO_ERROR(); ++ if (err) { ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + break; +@@ -1811,7 +2043,11 @@ + int err = PyDict_SetItem(GLOBALS(), name, PyStackRef_AsPyObjectBorrow(v)); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(v); +- if (err) JUMP_TO_ERROR(); ++ if (err) { ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + break; +@@ -1845,7 +2081,7 @@ + _PyErr_SetString(tstate, PyExc_SystemError, + "no locals found"); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (true) JUMP_TO_ERROR(); ++ JUMP_TO_ERROR(); + } + locals = PyStackRef_FromPyObjectNew(l); + stack_pointer[0] = locals; +@@ -1863,7 +2099,9 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *v_o = _PyEval_LoadName(tstate, frame, name); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (v_o == NULL) JUMP_TO_ERROR(); ++ if (v_o == NULL) { ++ JUMP_TO_ERROR(); ++ } + v = PyStackRef_FromPyObjectSteal(v_o); + stack_pointer[0] = v; + stack_pointer += 1; +@@ -1873,17 +2111,26 @@ + + case _LOAD_GLOBAL: { + _PyStackRef *res; +- _PyStackRef null = PyStackRef_NULL; + oparg = CURRENT_OPARG(); + res = &stack_pointer[0]; + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyEval_LoadGlobalStackRef(GLOBALS(), BUILTINS(), name, res); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (PyStackRef_IsNull(*res)) JUMP_TO_ERROR(); ++ if (PyStackRef_IsNull(*res)) { ++ JUMP_TO_ERROR(); ++ } ++ stack_pointer += 1; ++ assert(WITHIN_STACK_BOUNDS()); ++ break; ++ } ++ ++ case _PUSH_NULL_CONDITIONAL: { ++ _PyStackRef null = PyStackRef_NULL; ++ oparg = CURRENT_OPARG(); + null = PyStackRef_NULL; +- if (oparg & 1) stack_pointer[1] = null; +- stack_pointer += 1 + (oparg & 1); ++ if (oparg & 1) stack_pointer[0] = null; ++ stack_pointer += (oparg & 1); + assert(WITHIN_STACK_BOUNDS()); + break; + } +@@ -1949,8 +2196,6 @@ + case _LOAD_GLOBAL_MODULE_FROM_KEYS: { + PyDictKeysObject *globals_keys; + _PyStackRef res; +- _PyStackRef null = PyStackRef_NULL; +- oparg = CURRENT_OPARG(); + globals_keys = (PyDictKeysObject *)stack_pointer[-1].bits; + uint16_t index = (uint16_t)CURRENT_OPERAND0(); + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(globals_keys); +@@ -1972,10 +2217,8 @@ + res = PyStackRef_FromPyObjectSteal(res_o); + #endif + STAT_INC(LOAD_GLOBAL, hit); +- null = PyStackRef_NULL; + stack_pointer[0] = res; +- if (oparg & 1) stack_pointer[1] = null; +- stack_pointer += 1 + (oparg & 1); ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } +@@ -1983,8 +2226,6 @@ + case _LOAD_GLOBAL_BUILTINS_FROM_KEYS: { + PyDictKeysObject *builtins_keys; + _PyStackRef res; +- _PyStackRef null = PyStackRef_NULL; +- oparg = CURRENT_OPARG(); + builtins_keys = (PyDictKeysObject *)stack_pointer[-1].bits; + uint16_t index = (uint16_t)CURRENT_OPERAND0(); + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(builtins_keys); +@@ -2006,10 +2247,8 @@ + res = PyStackRef_FromPyObjectSteal(res_o); + #endif + STAT_INC(LOAD_GLOBAL, hit); +- null = PyStackRef_NULL; + stack_pointer[0] = res; +- if (oparg & 1) stack_pointer[1] = null; +- stack_pointer += 1 + (oparg & 1); ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } +@@ -2024,9 +2263,13 @@ + PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames, oparg) + ); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (1) JUMP_TO_ERROR(); ++ JUMP_TO_ERROR(); + } +- SETLOCAL(oparg, PyStackRef_NULL); ++ _PyStackRef tmp = GETLOCAL(oparg); ++ GETLOCAL(oparg) = PyStackRef_NULL; ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_XCLOSE(tmp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + break; + } + +@@ -2039,7 +2282,11 @@ + if (cell == NULL) { + JUMP_TO_ERROR(); + } +- SETLOCAL(oparg, PyStackRef_FromPyObjectSteal(cell)); ++ _PyStackRef tmp = GETLOCAL(oparg); ++ GETLOCAL(oparg) = PyStackRef_FromPyObjectSteal(cell); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_XCLOSE(tmp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + break; + } + +@@ -2055,7 +2302,9 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + JUMP_TO_ERROR(); + } ++ _PyFrame_SetStackPointer(frame, stack_pointer); + Py_DECREF(oldobj); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + break; + } + +@@ -2086,9 +2335,15 @@ + JUMP_TO_ERROR(); + } + } ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(class_dict_st); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + value = PyStackRef_FromPyObjectSteal(value_o); +- stack_pointer[-1] = value; ++ stack_pointer[0] = value; ++ stack_pointer += 1; ++ assert(WITHIN_STACK_BOUNDS()); + break; + } + +@@ -2101,7 +2356,7 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (true) JUMP_TO_ERROR(); ++ JUMP_TO_ERROR(); + } + value = PyStackRef_FromPyObjectSteal(value_o); + stack_pointer[0] = value; +@@ -2149,14 +2404,20 @@ + for (int _i = oparg; --_i >= 0;) { + PyStackRef_CLOSE(pieces[_i]); + } +- if (true) JUMP_TO_ERROR(); ++ stack_pointer += -oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); + } + PyObject *str_o = _PyUnicode_JoinArray(&_Py_STR(empty), pieces_o, oparg); + STACKREFS_TO_PYOBJECTS_CLEANUP(pieces_o); + for (int _i = oparg; --_i >= 0;) { + PyStackRef_CLOSE(pieces[_i]); + } +- if (str_o == NULL) JUMP_TO_ERROR(); ++ if (str_o == NULL) { ++ stack_pointer += -oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + str = PyStackRef_FromPyObjectSteal(str_o); + stack_pointer[-oparg] = str; + stack_pointer += 1 - oparg; +@@ -2169,8 +2430,10 @@ + _PyStackRef tup; + oparg = CURRENT_OPARG(); + values = &stack_pointer[-oparg]; +- PyObject *tup_o = _PyTuple_FromStackRefSteal(values, oparg); +- if (tup_o == NULL) JUMP_TO_ERROR(); ++ PyObject *tup_o = _PyTuple_FromStackRefStealOnSuccess(values, oparg); ++ if (tup_o == NULL) { ++ JUMP_TO_ERROR(); ++ } + tup = PyStackRef_FromPyObjectSteal(tup_o); + stack_pointer[-oparg] = tup; + stack_pointer += 1 - oparg; +@@ -2183,8 +2446,10 @@ + _PyStackRef list; + oparg = CURRENT_OPARG(); + values = &stack_pointer[-oparg]; +- PyObject *list_o = _PyList_FromStackRefSteal(values, oparg); +- if (list_o == NULL) JUMP_TO_ERROR(); ++ PyObject *list_o = _PyList_FromStackRefStealOnSuccess(values, oparg); ++ if (list_o == NULL) { ++ JUMP_TO_ERROR(); ++ } + list = PyStackRef_FromPyObjectSteal(list_o); + stack_pointer[-oparg] = list; + stack_pointer += 1 - oparg; +@@ -2218,7 +2483,9 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + } + PyStackRef_CLOSE(iterable_st); +- if (true) JUMP_TO_ERROR(); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); + } + assert(Py_IsNone(none_val)); + PyStackRef_CLOSE(iterable_st); +@@ -2238,7 +2505,11 @@ + PyStackRef_AsPyObjectBorrow(iterable)); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(iterable); +- if (err < 0) JUMP_TO_ERROR(); ++ if (err < 0) { ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + break; +@@ -2256,7 +2527,9 @@ + for (int _i = oparg; --_i >= 0;) { + PyStackRef_CLOSE(values[_i]); + } +- if (true) JUMP_TO_ERROR(); ++ stack_pointer += -oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); + } + int err = 0; + for (int i = 0; i < oparg; i++) { +@@ -2265,11 +2538,17 @@ + err = PySet_Add(set_o, PyStackRef_AsPyObjectBorrow(values[i])); + stack_pointer = _PyFrame_GetStackPointer(frame); + } +- PyStackRef_CLOSE(values[i]); ++ } ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(values[_i]); + } + if (err != 0) { ++ stack_pointer += -oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + Py_DECREF(set_o); +- if (true) JUMP_TO_ERROR(); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ JUMP_TO_ERROR(); + } + set = PyStackRef_FromPyObjectSteal(set_o); + stack_pointer[-oparg] = set; +@@ -2288,7 +2567,9 @@ + for (int _i = oparg*2; --_i >= 0;) { + PyStackRef_CLOSE(values[_i]); + } +- if (true) JUMP_TO_ERROR(); ++ stack_pointer += -oparg*2; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *map_o = _PyDict_FromItems( +@@ -2300,7 +2581,11 @@ + for (int _i = oparg*2; --_i >= 0;) { + PyStackRef_CLOSE(values[_i]); + } +- if (map_o == NULL) JUMP_TO_ERROR(); ++ if (map_o == NULL) { ++ stack_pointer += -oparg*2; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + map = PyStackRef_FromPyObjectSteal(map_o); + stack_pointer[-oparg*2] = map; + stack_pointer += 1 - oparg*2; +@@ -2315,27 +2600,35 @@ + _PyErr_Format(tstate, PyExc_SystemError, + "no locals found when setting up annotations"); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (true) JUMP_TO_ERROR(); ++ JUMP_TO_ERROR(); + } + /* check if __annotations__ in locals()... */ + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = PyMapping_GetOptionalItem(LOCALS(), &_Py_ID(__annotations__), &ann_dict); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err < 0) JUMP_TO_ERROR(); ++ if (err < 0) { ++ JUMP_TO_ERROR(); ++ } + if (ann_dict == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); + ann_dict = PyDict_New(); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (ann_dict == NULL) JUMP_TO_ERROR(); ++ if (ann_dict == NULL) { ++ JUMP_TO_ERROR(); ++ } + _PyFrame_SetStackPointer(frame, stack_pointer); + err = PyObject_SetItem(LOCALS(), &_Py_ID(__annotations__), + ann_dict); +- stack_pointer = _PyFrame_GetStackPointer(frame); + Py_DECREF(ann_dict); +- if (err) JUMP_TO_ERROR(); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (err) { ++ JUMP_TO_ERROR(); ++ } + } + else { ++ _PyFrame_SetStackPointer(frame, stack_pointer); + Py_DECREF(ann_dict); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + } + break; + } +@@ -2363,7 +2656,9 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + } + PyStackRef_CLOSE(update); +- if (true) JUMP_TO_ERROR(); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); + } + PyStackRef_CLOSE(update); + stack_pointer += -1; +@@ -2390,7 +2685,9 @@ + _PyEval_FormatKwargsError(tstate, callable_o, update_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(update); +- if (true) JUMP_TO_ERROR(); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); + } + PyStackRef_CLOSE(update); + stack_pointer += -1; +@@ -2417,14 +2714,16 @@ + PyStackRef_AsPyObjectSteal(value) + ); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err != 0) JUMP_TO_ERROR(); ++ if (err != 0) { ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); + break; + } + +- /* _INSTRUMENTED_LOAD_SUPER_ATTR is not a viable micro-op for tier 2 because it is instrumented */ +- + case _LOAD_SUPER_ATTR_ATTR: { + _PyStackRef self_st; + _PyStackRef class_st; +@@ -2454,7 +2753,11 @@ + PyStackRef_CLOSE(global_super_st); + PyStackRef_CLOSE(class_st); + PyStackRef_CLOSE(self_st); +- if (attr == NULL) JUMP_TO_ERROR(); ++ if (attr == NULL) { ++ stack_pointer += -3; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + attr_st = PyStackRef_FromPyObjectSteal(attr); + stack_pointer[-3] = attr_st; + stack_pointer += -2; +@@ -2492,18 +2795,23 @@ + PyObject *attr_o = _PySuper_Lookup(cls, self, name, + Py_TYPE(self)->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); +- PyStackRef_CLOSE(global_super_st); +- PyStackRef_CLOSE(class_st); + if (attr_o == NULL) { +- PyStackRef_CLOSE(self_st); +- if (true) JUMP_TO_ERROR(); ++ JUMP_TO_ERROR(); + } + if (method_found) { + self_or_null = self_st; // transfer ownership + } else { ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(self_st); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + self_or_null = PyStackRef_NULL; ++ stack_pointer += 1; ++ assert(WITHIN_STACK_BOUNDS()); + } ++ PyStackRef_CLOSE(global_super_st); ++ PyStackRef_CLOSE(class_st); + attr = PyStackRef_FromPyObjectSteal(attr_o); + stack_pointer[-3] = attr; + stack_pointer[-2] = self_or_null; +@@ -2515,9 +2823,10 @@ + case _LOAD_ATTR: { + _PyStackRef owner; + _PyStackRef attr; +- _PyStackRef self_or_null = PyStackRef_NULL; ++ _PyStackRef *self_or_null; + oparg = CURRENT_OPARG(); + owner = stack_pointer[-1]; ++ self_or_null = &stack_pointer[0]; + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); + PyObject *attr_o; + if (oparg & 1) { +@@ -2532,7 +2841,7 @@ + meth | self | arg1 | ... | argN + */ + assert(attr_o != NULL); // No errors on this branch +- self_or_null = owner; // Transfer ownership ++ self_or_null[0] = owner; // Transfer ownership + } + else { + /* meth is not an unbound method (but a regular attr, or +@@ -2542,8 +2851,12 @@ + meth | NULL | arg1 | ... | argN + */ + PyStackRef_CLOSE(owner); +- if (attr_o == NULL) JUMP_TO_ERROR(); +- self_or_null = PyStackRef_NULL; ++ if (attr_o == NULL) { ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } ++ self_or_null[0] = PyStackRef_NULL; + } + } + else { +@@ -2552,14 +2865,15 @@ + attr_o = PyObject_GetAttr(PyStackRef_AsPyObjectBorrow(owner), name); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(owner); +- if (attr_o == NULL) JUMP_TO_ERROR(); +- /* We need to define self_or_null on all paths */ +- self_or_null = PyStackRef_NULL; ++ if (attr_o == NULL) { ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + } + attr = PyStackRef_FromPyObjectSteal(attr_o); + stack_pointer[-1] = attr; +- if (oparg & 1) stack_pointer[0] = self_or_null; +- stack_pointer += (oparg & 1); ++ stack_pointer += (oparg&1); + assert(WITHIN_STACK_BOUNDS()); + break; + } +@@ -2570,77 +2884,77 @@ + uint32_t type_version = (uint32_t)CURRENT_OPERAND0(); + PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + assert(type_version != 0); +- if (tp->tp_version_tag != type_version) { ++ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + break; + } + +- case _CHECK_MANAGED_OBJECT_HAS_VALUES: { ++ case _GUARD_TYPE_VERSION_AND_LOCK: { + _PyStackRef owner; + owner = stack_pointer[-1]; ++ uint32_t type_version = (uint32_t)CURRENT_OPERAND0(); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); +- assert(Py_TYPE(owner_o)->tp_dictoffset < 0); +- assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); +- if (!_PyObject_InlineValues(owner_o)->valid) { ++ assert(type_version != 0); ++ if (!LOCK_OBJECT(owner_o)) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } ++ PyTypeObject *tp = Py_TYPE(owner_o); ++ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { ++ UNLOCK_OBJECT(owner_o); ++ if (true) { ++ UOP_STAT_INC(uopcode, miss); ++ JUMP_TO_JUMP_TARGET(); ++ } ++ } + break; + } + +- case _LOAD_ATTR_INSTANCE_VALUE_0: { ++ case _CHECK_MANAGED_OBJECT_HAS_VALUES: { + _PyStackRef owner; +- _PyStackRef attr; +- _PyStackRef null = PyStackRef_NULL; +- (void)null; + owner = stack_pointer[-1]; +- uint16_t offset = (uint16_t)CURRENT_OPERAND0(); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); +- PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); +- PyObject *attr_o = *value_ptr; +- if (attr_o == NULL) { ++ assert(Py_TYPE(owner_o)->tp_dictoffset < 0); ++ assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); ++ if (!FT_ATOMIC_LOAD_UINT8(_PyObject_InlineValues(owner_o)->valid)) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } +- STAT_INC(LOAD_ATTR, hit); +- Py_INCREF(attr_o); +- null = PyStackRef_NULL; +- attr = PyStackRef_FromPyObjectSteal(attr_o); +- PyStackRef_CLOSE(owner); +- stack_pointer[-1] = attr; + break; + } + +- case _LOAD_ATTR_INSTANCE_VALUE_1: { ++ case _LOAD_ATTR_INSTANCE_VALUE: { + _PyStackRef owner; + _PyStackRef attr; +- _PyStackRef null = PyStackRef_NULL; +- (void)null; + owner = stack_pointer[-1]; + uint16_t offset = (uint16_t)CURRENT_OPERAND0(); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); +- PyObject *attr_o = *value_ptr; ++ PyObject *attr_o = FT_ATOMIC_LOAD_PTR_ACQUIRE(*value_ptr); + if (attr_o == NULL) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } ++ #ifdef Py_GIL_DISABLED ++ if (!_Py_TryIncrefCompareStackRef(value_ptr, attr_o, &attr)) { ++ if (true) { ++ UOP_STAT_INC(uopcode, miss); ++ JUMP_TO_JUMP_TARGET(); ++ } ++ } ++ #else ++ attr = PyStackRef_FromPyObjectNew(attr_o); ++ #endif + STAT_INC(LOAD_ATTR, hit); +- Py_INCREF(attr_o); +- null = PyStackRef_NULL; +- attr = PyStackRef_FromPyObjectSteal(attr_o); +- PyStackRef_CLOSE(owner); + stack_pointer[-1] = attr; +- stack_pointer[0] = null; +- stack_pointer += 1; +- assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(owner); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + break; + } + +- /* _LOAD_ATTR_INSTANCE_VALUE is split on (oparg & 1) */ +- + case _CHECK_ATTR_MODULE_PUSH_KEYS: { + _PyStackRef owner; + PyDictKeysObject *mod_keys; +@@ -2669,8 +2983,6 @@ + PyDictKeysObject *mod_keys; + _PyStackRef owner; + _PyStackRef attr; +- _PyStackRef null = PyStackRef_NULL; +- oparg = CURRENT_OPARG(); + mod_keys = (PyDictKeysObject *)stack_pointer[-1].bits; + owner = stack_pointer[-2]; + uint16_t index = (uint16_t)CURRENT_OPERAND0(); +@@ -2698,119 +3010,125 @@ + attr = PyStackRef_FromPyObjectSteal(attr_o); + #endif + STAT_INC(LOAD_ATTR, hit); +- null = PyStackRef_NULL; +- PyStackRef_CLOSE(owner); + stack_pointer[-1] = attr; +- if (oparg & 1) stack_pointer[0] = null; +- stack_pointer += (oparg & 1); +- assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(owner); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + break; + } + + case _CHECK_ATTR_WITH_HINT: { + _PyStackRef owner; ++ PyDictObject *dict; + owner = stack_pointer[-1]; + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_MANAGED_DICT); +- PyDictObject *dict = _PyObject_GetManagedDict(owner_o); +- if (dict == NULL) { ++ PyDictObject *dict_o = _PyObject_GetManagedDict(owner_o); ++ if (dict_o == NULL) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } +- assert(PyDict_CheckExact((PyObject *)dict)); ++ assert(PyDict_CheckExact((PyObject *)dict_o)); ++ dict = dict_o; ++ stack_pointer[0].bits = (uintptr_t)dict; ++ stack_pointer += 1; ++ assert(WITHIN_STACK_BOUNDS()); + break; + } + + case _LOAD_ATTR_WITH_HINT: { ++ PyDictObject *dict; + _PyStackRef owner; + _PyStackRef attr; +- _PyStackRef null = PyStackRef_NULL; + oparg = CURRENT_OPARG(); +- owner = stack_pointer[-1]; ++ dict = (PyDictObject *)stack_pointer[-1].bits; ++ owner = stack_pointer[-2]; + uint16_t hint = (uint16_t)CURRENT_OPERAND0(); +- PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + PyObject *attr_o; +- PyDictObject *dict = _PyObject_GetManagedDict(owner_o); ++ if (!LOCK_OBJECT(dict)) { ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ if (true) { ++ UOP_STAT_INC(uopcode, miss); ++ JUMP_TO_JUMP_TARGET(); ++ } ++ } + if (hint >= (size_t)dict->ma_keys->dk_nentries) { +- UOP_STAT_INC(uopcode, miss); +- JUMP_TO_JUMP_TARGET(); ++ UNLOCK_OBJECT(dict); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ if (true) { ++ UOP_STAT_INC(uopcode, miss); ++ JUMP_TO_JUMP_TARGET(); ++ } + } + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); +- if (!DK_IS_UNICODE(dict->ma_keys)) { +- UOP_STAT_INC(uopcode, miss); +- JUMP_TO_JUMP_TARGET(); ++ if (dict->ma_keys->dk_kind != DICT_KEYS_UNICODE) { ++ UNLOCK_OBJECT(dict); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ if (true) { ++ UOP_STAT_INC(uopcode, miss); ++ JUMP_TO_JUMP_TARGET(); ++ } + } + PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; + if (ep->me_key != name) { +- UOP_STAT_INC(uopcode, miss); +- JUMP_TO_JUMP_TARGET(); ++ UNLOCK_OBJECT(dict); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ if (true) { ++ UOP_STAT_INC(uopcode, miss); ++ JUMP_TO_JUMP_TARGET(); ++ } + } + attr_o = ep->me_value; + if (attr_o == NULL) { +- UOP_STAT_INC(uopcode, miss); +- JUMP_TO_JUMP_TARGET(); ++ UNLOCK_OBJECT(dict); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ if (true) { ++ UOP_STAT_INC(uopcode, miss); ++ JUMP_TO_JUMP_TARGET(); ++ } + } + STAT_INC(LOAD_ATTR, hit); +- Py_INCREF(attr_o); +- attr = PyStackRef_FromPyObjectSteal(attr_o); +- null = PyStackRef_NULL; ++ attr = PyStackRef_FromPyObjectNew(attr_o); ++ UNLOCK_OBJECT(dict); + PyStackRef_CLOSE(owner); +- stack_pointer[-1] = attr; +- if (oparg & 1) stack_pointer[0] = null; +- stack_pointer += (oparg & 1); ++ stack_pointer[-2] = attr; ++ stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + break; + } + +- case _LOAD_ATTR_SLOT_0: { ++ case _LOAD_ATTR_SLOT: { + _PyStackRef owner; + _PyStackRef attr; +- _PyStackRef null = PyStackRef_NULL; +- (void)null; + owner = stack_pointer[-1]; + uint16_t index = (uint16_t)CURRENT_OPERAND0(); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); +- char *addr = (char *)owner_o + index; +- PyObject *attr_o = *(PyObject **)addr; ++ PyObject **addr = (PyObject **)((char *)owner_o + index); ++ PyObject *attr_o = FT_ATOMIC_LOAD_PTR(*addr); + if (attr_o == NULL) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } +- STAT_INC(LOAD_ATTR, hit); +- null = PyStackRef_NULL; +- attr = PyStackRef_FromPyObjectNew(attr_o); +- PyStackRef_CLOSE(owner); +- stack_pointer[-1] = attr; +- break; +- } +- +- case _LOAD_ATTR_SLOT_1: { +- _PyStackRef owner; +- _PyStackRef attr; +- _PyStackRef null = PyStackRef_NULL; +- (void)null; +- owner = stack_pointer[-1]; +- uint16_t index = (uint16_t)CURRENT_OPERAND0(); +- PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); +- char *addr = (char *)owner_o + index; +- PyObject *attr_o = *(PyObject **)addr; +- if (attr_o == NULL) { ++ #ifdef Py_GIL_DISABLED ++ int increfed = _Py_TryIncrefCompareStackRef(addr, attr_o, &attr); ++ if (!increfed) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } +- STAT_INC(LOAD_ATTR, hit); +- null = PyStackRef_NULL; ++ #else + attr = PyStackRef_FromPyObjectNew(attr_o); ++ #endif ++ STAT_INC(LOAD_ATTR, hit); + PyStackRef_CLOSE(owner); + stack_pointer[-1] = attr; +- stack_pointer[0] = null; +- stack_pointer += 1; +- assert(WITHIN_STACK_BOUNDS()); + break; + } + +- /* _LOAD_ATTR_SLOT is split on (oparg & 1) */ +- + case _CHECK_ATTR_CLASS: { + _PyStackRef owner; + owner = stack_pointer[-1]; +@@ -2818,53 +3136,29 @@ + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + if (!PyType_Check(owner_o)) { + UOP_STAT_INC(uopcode, miss); +- JUMP_TO_JUMP_TARGET(); +- } +- assert(type_version != 0); +- if (((PyTypeObject *)owner_o)->tp_version_tag != type_version) { +- UOP_STAT_INC(uopcode, miss); +- JUMP_TO_JUMP_TARGET(); +- } +- break; +- } +- +- case _LOAD_ATTR_CLASS_0: { +- _PyStackRef owner; +- _PyStackRef attr; +- _PyStackRef null = PyStackRef_NULL; +- (void)null; +- owner = stack_pointer[-1]; +- PyObject *descr = (PyObject *)CURRENT_OPERAND0(); +- STAT_INC(LOAD_ATTR, hit); +- assert(descr != NULL); +- attr = PyStackRef_FromPyObjectNew(descr); +- null = PyStackRef_NULL; +- PyStackRef_CLOSE(owner); +- stack_pointer[-1] = attr; ++ JUMP_TO_JUMP_TARGET(); ++ } ++ assert(type_version != 0); ++ if (FT_ATOMIC_LOAD_UINT_RELAXED(((PyTypeObject *)owner_o)->tp_version_tag) != type_version) { ++ UOP_STAT_INC(uopcode, miss); ++ JUMP_TO_JUMP_TARGET(); ++ } + break; + } + +- case _LOAD_ATTR_CLASS_1: { ++ case _LOAD_ATTR_CLASS: { + _PyStackRef owner; + _PyStackRef attr; +- _PyStackRef null = PyStackRef_NULL; +- (void)null; + owner = stack_pointer[-1]; + PyObject *descr = (PyObject *)CURRENT_OPERAND0(); + STAT_INC(LOAD_ATTR, hit); + assert(descr != NULL); + attr = PyStackRef_FromPyObjectNew(descr); +- null = PyStackRef_NULL; + PyStackRef_CLOSE(owner); + stack_pointer[-1] = attr; +- stack_pointer[0] = null; +- stack_pointer += 1; +- assert(WITHIN_STACK_BOUNDS()); + break; + } + +- /* _LOAD_ATTR_CLASS is split on (oparg & 1) */ +- + case _LOAD_ATTR_PROPERTY_FRAME: { + _PyStackRef owner; + _PyInterpreterFrame *new_frame; +@@ -2906,13 +3200,13 @@ + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + assert(Py_TYPE(owner_o)->tp_dictoffset < 0); + assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); +- if (_PyObject_GetManagedDict(owner_o)) { +- UOP_STAT_INC(uopcode, miss); +- JUMP_TO_JUMP_TARGET(); +- } +- if (_PyObject_InlineValues(owner_o)->valid == 0) { +- UOP_STAT_INC(uopcode, miss); +- JUMP_TO_JUMP_TARGET(); ++ if (_PyObject_GetManagedDict(owner_o) || ++ !FT_ATOMIC_LOAD_UINT8(_PyObject_InlineValues(owner_o)->valid)) { ++ UNLOCK_OBJECT(owner_o); ++ if (true) { ++ UOP_STAT_INC(uopcode, miss); ++ JUMP_TO_JUMP_TARGET(); ++ } + } + break; + } +@@ -2928,18 +3222,19 @@ + assert(_PyObject_GetManagedDict(owner_o) == NULL); + PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); + PyObject *old_value = *value_ptr; +- *value_ptr = PyStackRef_AsPyObjectSteal(value); ++ FT_ATOMIC_STORE_PTR_RELEASE(*value_ptr, PyStackRef_AsPyObjectSteal(value)); + if (old_value == NULL) { + PyDictValues *values = _PyObject_InlineValues(owner_o); + Py_ssize_t index = value_ptr - values->values; + _PyDictValues_AddToInsertionOrder(values, index); + } +- else { +- Py_DECREF(old_value); +- } +- PyStackRef_CLOSE(owner); ++ UNLOCK_OBJECT(owner_o); + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(owner); ++ Py_XDECREF(old_value); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + break; + } + +@@ -2957,37 +3252,59 @@ + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } +- assert(PyDict_CheckExact((PyObject *)dict)); +- PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); +- if (hint >= (size_t)dict->ma_keys->dk_nentries) { ++ if (!LOCK_OBJECT(dict)) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } +- if (!DK_IS_UNICODE(dict->ma_keys)) { +- UOP_STAT_INC(uopcode, miss); +- JUMP_TO_JUMP_TARGET(); ++ #ifdef Py_GIL_DISABLED ++ if (dict != _PyObject_GetManagedDict(owner_o)) { ++ UNLOCK_OBJECT(dict); ++ if (true) { ++ UOP_STAT_INC(uopcode, miss); ++ JUMP_TO_JUMP_TARGET(); ++ } ++ } ++ #endif ++ assert(PyDict_CheckExact((PyObject *)dict)); ++ PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); ++ if (hint >= (size_t)dict->ma_keys->dk_nentries || ++ !DK_IS_UNICODE(dict->ma_keys)) { ++ UNLOCK_OBJECT(dict); ++ if (true) { ++ UOP_STAT_INC(uopcode, miss); ++ JUMP_TO_JUMP_TARGET(); ++ } + } + PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; + if (ep->me_key != name) { +- UOP_STAT_INC(uopcode, miss); +- JUMP_TO_JUMP_TARGET(); ++ UNLOCK_OBJECT(dict); ++ if (true) { ++ UOP_STAT_INC(uopcode, miss); ++ JUMP_TO_JUMP_TARGET(); ++ } + } + PyObject *old_value = ep->me_value; + if (old_value == NULL) { +- UOP_STAT_INC(uopcode, miss); +- JUMP_TO_JUMP_TARGET(); ++ UNLOCK_OBJECT(dict); ++ if (true) { ++ UOP_STAT_INC(uopcode, miss); ++ JUMP_TO_JUMP_TARGET(); ++ } + } + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyDict_NotifyEvent(tstate->interp, PyDict_EVENT_MODIFIED, dict, name, PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); +- ep->me_value = PyStackRef_AsPyObjectSteal(value); ++ FT_ATOMIC_STORE_PTR_RELEASE(ep->me_value, PyStackRef_AsPyObjectSteal(value)); ++ UNLOCK_OBJECT(dict); + // old_value should be DECREFed after GC track checking is done, if not, it could raise a segmentation fault, + // when dict only holds the strong reference to value in ep->me_value. +- Py_XDECREF(old_value); + STAT_INC(STORE_ATTR, hit); +- PyStackRef_CLOSE(owner); + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(owner); ++ Py_XDECREF(old_value); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + break; + } + +@@ -2998,14 +3315,21 @@ + value = stack_pointer[-2]; + uint16_t index = (uint16_t)CURRENT_OPERAND0(); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); ++ if (!LOCK_OBJECT(owner_o)) { ++ UOP_STAT_INC(uopcode, miss); ++ JUMP_TO_JUMP_TARGET(); ++ } + char *addr = (char *)owner_o + index; + STAT_INC(STORE_ATTR, hit); + PyObject *old_value = *(PyObject **)addr; +- *(PyObject **)addr = PyStackRef_AsPyObjectSteal(value); +- Py_XDECREF(old_value); +- PyStackRef_CLOSE(owner); ++ FT_ATOMIC_STORE_PTR_RELEASE(*(PyObject **)addr, PyStackRef_AsPyObjectSteal(value)); ++ UNLOCK_OBJECT(owner_o); + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(owner); ++ Py_XDECREF(old_value); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + break; + } + +@@ -3024,15 +3348,21 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(left); + PyStackRef_CLOSE(right); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ if (res_o == NULL) { ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + if (oparg & 16) { + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + int res_bool = PyObject_IsTrue(res_o); +- stack_pointer = _PyFrame_GetStackPointer(frame); + Py_DECREF(res_o); +- if (res_bool < 0) JUMP_TO_ERROR(); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (res_bool < 0) { ++ JUMP_TO_ERROR(); ++ } + res = res_bool ? PyStackRef_True : PyStackRef_False; + } + else { +@@ -3160,7 +3490,11 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(left); + PyStackRef_CLOSE(right); +- if (res < 0) JUMP_TO_ERROR(); ++ if (res < 0) { ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + b = (res ^ oparg) ? PyStackRef_True : PyStackRef_False; + stack_pointer[-2] = b; + stack_pointer += -1; +@@ -3188,7 +3522,11 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(left); + PyStackRef_CLOSE(right); +- if (res < 0) JUMP_TO_ERROR(); ++ if (res < 0) { ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + b = (res ^ oparg) ? PyStackRef_True : PyStackRef_False; + stack_pointer[-2] = b; + stack_pointer += -1; +@@ -3215,7 +3553,11 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(left); + PyStackRef_CLOSE(right); +- if (res < 0) JUMP_TO_ERROR(); ++ if (res < 0) { ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + b = (res ^ oparg) ? PyStackRef_True : PyStackRef_False; + stack_pointer[-2] = b; + stack_pointer += -1; +@@ -3238,19 +3580,29 @@ + if (err < 0) { + PyStackRef_CLOSE(exc_value_st); + PyStackRef_CLOSE(match_type_st); +- if (true) JUMP_TO_ERROR(); ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); + } + PyObject *match_o = NULL; + PyObject *rest_o = NULL; + _PyFrame_SetStackPointer(frame, stack_pointer); +- int res = _PyEval_ExceptionGroupMatch(exc_value, match_type, ++ int res = _PyEval_ExceptionGroupMatch(frame, exc_value, match_type, + &match_o, &rest_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(exc_value_st); + PyStackRef_CLOSE(match_type_st); +- if (res < 0) JUMP_TO_ERROR(); ++ if (res < 0) { ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + assert((match_o == NULL) == (rest_o == NULL)); +- if (match_o == NULL) JUMP_TO_ERROR(); ++ if (match_o == NULL) { ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + if (!Py_IsNone(match_o)) { + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); +@@ -3281,7 +3633,9 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err < 0) { + PyStackRef_CLOSE(right); +- if (true) JUMP_TO_ERROR(); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + int res = PyErr_GivenExceptionMatches(left_o, right_o); +@@ -3307,7 +3661,11 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(level); + PyStackRef_CLOSE(fromlist); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ if (res_o == NULL) { ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -3324,7 +3682,9 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *res_o = _PyEval_ImportFrom(tstate, PyStackRef_AsPyObjectBorrow(from), name); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ if (res_o == NULL) { ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[0] = res; + stack_pointer += 1; +@@ -3359,9 +3719,13 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + Py_ssize_t len_i = PyObject_Length(PyStackRef_AsPyObjectBorrow(obj)); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (len_i < 0) JUMP_TO_ERROR(); ++ if (len_i < 0) { ++ JUMP_TO_ERROR(); ++ } + PyObject *len_o = PyLong_FromSsize_t(len_i); +- if (len_o == NULL) JUMP_TO_ERROR(); ++ if (len_o == NULL) { ++ JUMP_TO_ERROR(); ++ } + len = PyStackRef_FromPyObjectSteal(len_o); + stack_pointer[0] = len; + stack_pointer += 1; +@@ -3395,7 +3759,11 @@ + attrs = PyStackRef_FromPyObjectSteal(attrs_o); + } + else { +- if (_PyErr_Occurred(tstate)) JUMP_TO_ERROR(); ++ if (_PyErr_Occurred(tstate)) { ++ stack_pointer += -3; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + // Error! + attrs = PyStackRef_None; // Failure! + } +@@ -3440,7 +3808,9 @@ + PyObject *values_or_none_o = _PyEval_MatchKeys(tstate, + PyStackRef_AsPyObjectBorrow(subject), PyStackRef_AsPyObjectBorrow(keys)); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (values_or_none_o == NULL) JUMP_TO_ERROR(); ++ if (values_or_none_o == NULL) { ++ JUMP_TO_ERROR(); ++ } + values_or_none = PyStackRef_FromPyObjectSteal(values_or_none_o); + stack_pointer[0] = values_or_none; + stack_pointer += 1; +@@ -3457,7 +3827,11 @@ + PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable)); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(iterable); +- if (iter_o == NULL) JUMP_TO_ERROR(); ++ if (iter_o == NULL) { ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + iter = PyStackRef_FromPyObjectSteal(iter_o); + stack_pointer[-1] = iter; + break; +@@ -3677,7 +4051,9 @@ + r->start = value + r->step; + r->len--; + PyObject *res = PyLong_FromLong(value); +- if (res == NULL) JUMP_TO_ERROR(); ++ if (res == NULL) { ++ JUMP_TO_ERROR(); ++ } + next = PyStackRef_FromPyObjectSteal(res); + stack_pointer[0] = next; + stack_pointer += 1; +@@ -3737,7 +4113,7 @@ + Py_TYPE(owner_o)->tp_name); + stack_pointer = _PyFrame_GetStackPointer(frame); + } +- if (true) JUMP_TO_ERROR(); ++ JUMP_TO_ERROR(); + } + attr = PyStackRef_FromPyObjectSteal(attr_o); + self_or_null = self_or_null_o == NULL ? +@@ -3778,7 +4154,9 @@ + tb = Py_None; + } + else { ++ _PyFrame_SetStackPointer(frame, stack_pointer); + Py_DECREF(tb); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + } + assert(PyStackRef_LongCheck(lasti)); + (void)lasti; // Shut up compiler warning if asserts are off +@@ -3788,7 +4166,9 @@ + PyObject *res_o = PyObject_Vectorcall(exit_func_o, stack + 2 - has_self, + (3 + has_self) | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ if (res_o == NULL) { ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[0] = res; + stack_pointer += 1; +@@ -3823,7 +4203,8 @@ + owner = stack_pointer[-1]; + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); +- if (!_PyObject_InlineValues(owner_o)->valid) { ++ PyDictValues *ivs = _PyObject_InlineValues(owner_o); ++ if (!FT_ATOMIC_LOAD_UINT8(ivs->valid)) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } +@@ -3836,7 +4217,8 @@ + uint32_t keys_version = (uint32_t)CURRENT_OPERAND0(); + PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; +- if (owner_heap_type->ht_cached_keys->dk_version != keys_version) { ++ PyDictKeysObject *keys = owner_heap_type->ht_cached_keys; ++ if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } +@@ -3846,7 +4228,7 @@ + case _LOAD_ATTR_METHOD_WITH_VALUES: { + _PyStackRef owner; + _PyStackRef attr; +- _PyStackRef self = PyStackRef_NULL; ++ _PyStackRef self; + oparg = CURRENT_OPARG(); + owner = stack_pointer[-1]; + PyObject *descr = (PyObject *)CURRENT_OPERAND0(); +@@ -3867,7 +4249,7 @@ + case _LOAD_ATTR_METHOD_NO_DICT: { + _PyStackRef owner; + _PyStackRef attr; +- _PyStackRef self = PyStackRef_NULL; ++ _PyStackRef self; + oparg = CURRENT_OPARG(); + owner = stack_pointer[-1]; + PyObject *descr = (PyObject *)CURRENT_OPERAND0(); +@@ -3921,7 +4303,7 @@ + owner = stack_pointer[-1]; + uint16_t dictoffset = (uint16_t)CURRENT_OPERAND0(); + char *ptr = ((char *)PyStackRef_AsPyObjectBorrow(owner)) + MANAGED_DICT_OFFSET + dictoffset; +- PyObject *dict = *(PyObject **)ptr; ++ PyObject *dict = FT_ATOMIC_LOAD_PTR_ACQUIRE(*(PyObject **)ptr); + /* This object has a __dict__, just not yet created */ + if (dict != NULL) { + UOP_STAT_INC(uopcode, miss); +@@ -3933,7 +4315,7 @@ + case _LOAD_ATTR_METHOD_LAZY_DICT: { + _PyStackRef owner; + _PyStackRef attr; +- _PyStackRef self = PyStackRef_NULL; ++ _PyStackRef self; + oparg = CURRENT_OPARG(); + owner = stack_pointer[-1]; + PyObject *descr = (PyObject *)CURRENT_OPERAND0(); +@@ -3962,6 +4344,8 @@ + callable = &stack_pointer[-2 - oparg]; + func = &stack_pointer[-2 - oparg]; + maybe_self = &stack_pointer[-1 - oparg]; ++ args = &stack_pointer[-oparg]; ++ (void)args; + if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + PyObject *self = ((PyMethodObject *)callable_o)->im_self; +@@ -3969,7 +4353,9 @@ + PyObject *method = ((PyMethodObject *)callable_o)->im_func; + _PyStackRef temp = callable[0]; + func[0] = PyStackRef_FromPyObjectNew(method); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(temp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + } + break; + } +@@ -4075,23 +4461,21 @@ + } + + case _EXPAND_METHOD: { +- _PyStackRef *null; ++ _PyStackRef *self_or_null; + _PyStackRef *callable; +- _PyStackRef *method; +- _PyStackRef *self; + oparg = CURRENT_OPARG(); +- null = &stack_pointer[-1 - oparg]; ++ self_or_null = &stack_pointer[-1 - oparg]; + callable = &stack_pointer[-2 - oparg]; +- method = &stack_pointer[-2 - oparg]; +- self = &stack_pointer[-1 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); +- assert(PyStackRef_IsNull(null[0])); ++ assert(PyStackRef_IsNull(self_or_null[0])); + assert(Py_TYPE(callable_o) == &PyMethod_Type); +- self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); ++ self_or_null[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); + _PyStackRef temp = callable[0]; +- method[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); +- assert(PyStackRef_FunctionCheck(method[0])); ++ callable[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); ++ assert(PyStackRef_FunctionCheck(callable[0])); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(temp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + break; + } + +@@ -4125,19 +4509,22 @@ + #endif + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + /* Callable is not a normal Python function */ +- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + PyStackRef_CLOSE(callable[0]); +- PyStackRef_CLOSE(self_or_null[0]); ++ PyStackRef_XCLOSE(self_or_null[0]); + for (int _i = oparg; --_i >= 0;) { + PyStackRef_CLOSE(args[_i]); + } +- if (true) JUMP_TO_ERROR(); ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *res_o = PyObject_Vectorcall( +@@ -4148,10 +4535,15 @@ + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + PyStackRef_CLOSE(callable[0]); +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); ++ PyStackRef_XCLOSE(self_or_null[0]); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); ++ } ++ if (res_o == NULL) { ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); + } +- if (res_o == NULL) JUMP_TO_ERROR(); + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; +@@ -4177,21 +4569,20 @@ + } + + case _INIT_CALL_BOUND_METHOD_EXACT_ARGS: { +- _PyStackRef *null; ++ _PyStackRef *self_or_null; + _PyStackRef *callable; +- _PyStackRef *func; +- _PyStackRef *self; + oparg = CURRENT_OPARG(); +- null = &stack_pointer[-1 - oparg]; ++ self_or_null = &stack_pointer[-1 - oparg]; + callable = &stack_pointer[-2 - oparg]; +- func = &stack_pointer[-2 - oparg]; +- self = &stack_pointer[-1 - oparg]; ++ assert(PyStackRef_IsNull(self_or_null[0])); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + STAT_INC(CALL, hit); +- self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); ++ self_or_null[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); + _PyStackRef temp = callable[0]; +- func[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); ++ callable[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(temp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + break; + } + +@@ -4423,10 +4814,12 @@ + } + STAT_INC(CALL, hit); + res = PyStackRef_FromPyObjectSteal(Py_NewRef(Py_TYPE(arg_o))); +- PyStackRef_CLOSE(arg); + stack_pointer[-3] = res; + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(arg); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + break; + } + +@@ -4454,11 +4847,17 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *res_o = PyObject_Str(arg_o); + stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -3; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(arg); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (res_o == NULL) { ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); +- stack_pointer[-3] = res; +- stack_pointer += -2; ++ stack_pointer[0] = res; ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } +@@ -4487,11 +4886,17 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *res_o = PySequence_Tuple(arg_o); + stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -3; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(arg); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (res_o == NULL) { ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); +- stack_pointer[-3] = res; +- stack_pointer += -2; ++ stack_pointer[0] = res; ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } +@@ -4508,7 +4913,9 @@ + callable = &stack_pointer[-2 - oparg]; + init = &stack_pointer[-2 - oparg]; + self = &stack_pointer[-1 - oparg]; ++ args = &stack_pointer[-oparg]; + uint32_t type_version = (uint32_t)CURRENT_OPERAND0(); ++ (void)args; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + if (!PyStackRef_IsNull(null[0])) { + UOP_STAT_INC(uopcode, miss); +@@ -4523,7 +4930,9 @@ + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } +- assert(tp->tp_flags & Py_TPFLAGS_INLINE_VALUES); ++ assert(tp->tp_new == PyBaseObject_Type.tp_new); ++ assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE); ++ assert(tp->tp_alloc == PyType_GenericAlloc); + PyHeapTypeObject *cls = (PyHeapTypeObject *)callable_o; + PyFunctionObject *init_func = (PyFunctionObject *)FT_ATOMIC_LOAD_PTR_ACQUIRE(cls->_spec_cache.init); + PyCodeObject *code = (PyCodeObject *)init_func->func_code; +@@ -4532,14 +4941,18 @@ + JUMP_TO_JUMP_TARGET(); + } + STAT_INC(CALL, hit); +- PyObject *self_o = _PyType_NewManagedObject(tp); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyObject *self_o = PyType_GenericAlloc(tp, 0); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + if (self_o == NULL) { + JUMP_TO_ERROR(); + } + self[0] = PyStackRef_FromPyObjectSteal(self_o); + _PyStackRef temp = callable[0]; + init[0] = PyStackRef_FromPyObjectNew(init_func); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(temp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + break; + } + +@@ -4555,9 +4968,9 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyInterpreterFrame *shim = _PyFrame_PushTrampolineUnchecked( + tstate, (PyCodeObject *)&_Py_InitCleanup, 1, frame); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + assert(_PyFrame_GetBytecode(shim)[0].op.code == EXIT_INIT_CHECK); + assert(_PyFrame_GetBytecode(shim)[1].op.code == RETURN_VALUE); +- stack_pointer = _PyFrame_GetStackPointer(frame); + /* Push self onto stack of shim */ + shim->localsplus[0] = PyStackRef_DUP(self[0]); + _PyFrame_SetStackPointer(frame, stack_pointer); +@@ -4609,40 +5022,47 @@ + self_or_null = &stack_pointer[-1 - oparg]; + callable = &stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); +- int total_args = oparg; +- if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; +- total_args++; +- } + if (!PyType_Check(callable_o)) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + PyTypeObject *tp = (PyTypeObject *)callable_o; ++ int total_args = oparg; ++ _PyStackRef *arguments = args; ++ if (!PyStackRef_IsNull(self_or_null[0])) { ++ arguments--; ++ total_args++; ++ } + if (tp->tp_vectorcall == NULL) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + STAT_INC(CALL, hit); +- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + PyStackRef_CLOSE(callable[0]); +- PyStackRef_CLOSE(self_or_null[0]); ++ PyStackRef_XCLOSE(self_or_null[0]); + for (int _i = oparg; --_i >= 0;) { + PyStackRef_CLOSE(args[_i]); + } +- if (true) JUMP_TO_ERROR(); ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *res_o = tp->tp_vectorcall((PyObject *)tp, args_o, total_args, NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); +- /* Free the arguments. */ +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); +- } + PyStackRef_CLOSE(callable[0]); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ PyStackRef_XCLOSE(self_or_null[0]); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); ++ } ++ if (res_o == NULL) { ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; +@@ -4692,12 +5112,20 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + _Py_LeaveRecursiveCallTstate(tstate); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(arg); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(callable[0]); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (res_o == NULL) { ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); +- stack_pointer[-2 - oparg] = res; +- stack_pointer += -1 - oparg; ++ stack_pointer[0] = res; ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } +@@ -4714,8 +5142,9 @@ + /* Builtin METH_FASTCALL functions, without keywords */ + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + if (!PyCFunction_CheckExact(callable_o)) { +@@ -4729,14 +5158,16 @@ + STAT_INC(CALL, hit); + PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable_o); + /* res = func(self, args, nargs) */ +- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + PyStackRef_CLOSE(callable[0]); +- PyStackRef_CLOSE(self_or_null[0]); ++ PyStackRef_XCLOSE(self_or_null[0]); + for (int _i = oparg; --_i >= 0;) { + PyStackRef_CLOSE(args[_i]); + } +- if (true) JUMP_TO_ERROR(); ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *res_o = ((PyCFunctionFast)(void(*)(void))cfunc)( +@@ -4746,12 +5177,16 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); +- /* Free the arguments. */ +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); +- } + PyStackRef_CLOSE(callable[0]); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ PyStackRef_XCLOSE(self_or_null[0]); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); ++ } ++ if (res_o == NULL) { ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; +@@ -4771,8 +5206,9 @@ + /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + if (!PyCFunction_CheckExact(callable_o)) { +@@ -4784,32 +5220,38 @@ + JUMP_TO_JUMP_TARGET(); + } + STAT_INC(CALL, hit); +- /* res = func(self, args, nargs, kwnames) */ ++ /* res = func(self, arguments, nargs, kwnames) */ + _PyFrame_SetStackPointer(frame, stack_pointer); + PyCFunctionFastWithKeywords cfunc = + (PyCFunctionFastWithKeywords)(void(*)(void)) + PyCFunction_GET_FUNCTION(callable_o); + stack_pointer = _PyFrame_GetStackPointer(frame); +- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + PyStackRef_CLOSE(callable[0]); +- PyStackRef_CLOSE(self_or_null[0]); ++ PyStackRef_XCLOSE(self_or_null[0]); + for (int _i = oparg; --_i >= 0;) { + PyStackRef_CLOSE(args[_i]); + } +- if (true) JUMP_TO_ERROR(); ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *res_o = cfunc(PyCFunction_GET_SELF(callable_o), args_o, total_args, NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); +- /* Free the arguments. */ +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); +- } + PyStackRef_CLOSE(callable[0]); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ PyStackRef_XCLOSE(self_or_null[0]); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); ++ } ++ if (res_o == NULL) { ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; +@@ -4854,13 +5296,19 @@ + PyObject *res_o = PyLong_FromSsize_t(len_i); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + if (res_o == NULL) { +- GOTO_ERROR(error); ++ JUMP_TO_ERROR(); + } +- PyStackRef_CLOSE(callable[0]); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(arg_stackref); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(callable[0]); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + res = PyStackRef_FromPyObjectSteal(res_o); +- stack_pointer[-2 - oparg] = res; +- stack_pointer += -1 - oparg; ++ stack_pointer[0] = res; ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } +@@ -4877,8 +5325,9 @@ + /* isinstance(o, o2) */ + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + if (total_args != 2) { +@@ -4891,8 +5340,8 @@ + JUMP_TO_JUMP_TARGET(); + } + STAT_INC(CALL, hit); +- _PyStackRef cls_stackref = args[1]; +- _PyStackRef inst_stackref = args[0]; ++ _PyStackRef cls_stackref = arguments[1]; ++ _PyStackRef inst_stackref = arguments[0]; + _PyFrame_SetStackPointer(frame, stack_pointer); + int retval = PyObject_IsInstance(PyStackRef_AsPyObjectBorrow(inst_stackref), PyStackRef_AsPyObjectBorrow(cls_stackref)); + stack_pointer = _PyFrame_GetStackPointer(frame); +@@ -4901,9 +5350,11 @@ + } + res = retval ? PyStackRef_True : PyStackRef_False; + assert((!PyStackRef_IsNull(res)) ^ (_PyErr_Occurred(tstate) != NULL)); +- PyStackRef_CLOSE(inst_stackref); +- PyStackRef_CLOSE(cls_stackref); + PyStackRef_CLOSE(callable[0]); ++ PyStackRef_XCLOSE(self_or_null[0]); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); ++ } + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; + assert(WITHIN_STACK_BOUNDS()); +@@ -4938,17 +5389,25 @@ + STAT_INC(CALL, hit); + int err = _PyList_AppendTakeRef((PyListObject *)self_o, PyStackRef_AsPyObjectSteal(arg)); + UNLOCK_OBJECT(self_o); ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(self); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(callable); +- if (err) JUMP_TO_ERROR(); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (err) { ++ JUMP_TO_ERROR(); ++ } + #if TIER_ONE + // Skip the following POP_TOP. This is done here in tier one, and + // during trace projection in tier two: + assert(next_instr->op.code == POP_TOP); + SKIP_OVER(1); + #endif +- stack_pointer += -3; +- assert(WITHIN_STACK_BOUNDS()); + break; + } + +@@ -4963,8 +5422,9 @@ + callable = &stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; +@@ -4986,8 +5446,8 @@ + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } +- _PyStackRef arg_stackref = args[1]; +- _PyStackRef self_stackref = args[0]; ++ _PyStackRef arg_stackref = arguments[1]; ++ _PyStackRef self_stackref = arguments[0]; + if (!Py_IS_TYPE(PyStackRef_AsPyObjectBorrow(self_stackref), + method->d_common.d_type)) { + UOP_STAT_INC(uopcode, miss); +@@ -5003,10 +5463,16 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + _Py_LeaveRecursiveCallTstate(tstate); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); +- PyStackRef_CLOSE(self_stackref); +- PyStackRef_CLOSE(arg_stackref); + PyStackRef_CLOSE(callable[0]); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ PyStackRef_XCLOSE(self_or_null[0]); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); ++ } ++ if (res_o == NULL) { ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; +@@ -5025,8 +5491,9 @@ + callable = &stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; +@@ -5040,21 +5507,23 @@ + JUMP_TO_JUMP_TARGET(); + } + PyTypeObject *d_type = method->d_common.d_type; +- PyObject *self = PyStackRef_AsPyObjectBorrow(args[0]); ++ PyObject *self = PyStackRef_AsPyObjectBorrow(arguments[0]); + if (!Py_IS_TYPE(self, d_type)) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + STAT_INC(CALL, hit); + int nargs = total_args - 1; +- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + PyStackRef_CLOSE(callable[0]); +- PyStackRef_CLOSE(self_or_null[0]); ++ PyStackRef_XCLOSE(self_or_null[0]); + for (int _i = oparg; --_i >= 0;) { + PyStackRef_CLOSE(args[_i]); + } +- if (true) JUMP_TO_ERROR(); ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyCFunctionFastWithKeywords cfunc = +@@ -5063,12 +5532,16 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); +- /* Free the arguments. */ +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); +- } + PyStackRef_CLOSE(callable[0]); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ PyStackRef_XCLOSE(self_or_null[0]); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); ++ } ++ if (res_o == NULL) { ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; +@@ -5125,12 +5598,20 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + _Py_LeaveRecursiveCallTstate(tstate); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(self_stackref); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(callable[0]); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (res_o == NULL) { ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); +- stack_pointer[-2 - oparg] = res; +- stack_pointer += -1 - oparg; ++ stack_pointer[0] = res; ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } +@@ -5146,8 +5627,9 @@ + callable = &stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; +@@ -5161,21 +5643,23 @@ + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } +- PyObject *self = PyStackRef_AsPyObjectBorrow(args[0]); ++ PyObject *self = PyStackRef_AsPyObjectBorrow(arguments[0]); + if (!Py_IS_TYPE(self, method->d_common.d_type)) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + STAT_INC(CALL, hit); + int nargs = total_args - 1; +- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + PyStackRef_CLOSE(callable[0]); +- PyStackRef_CLOSE(self_or_null[0]); ++ PyStackRef_XCLOSE(self_or_null[0]); + for (int _i = oparg; --_i >= 0;) { + PyStackRef_CLOSE(args[_i]); + } +- if (true) JUMP_TO_ERROR(); ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyCFunctionFast cfunc = +@@ -5184,12 +5668,16 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); +- /* Clear the stack of the arguments. */ +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); +- } + PyStackRef_CLOSE(callable[0]); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ PyStackRef_XCLOSE(self_or_null[0]); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); ++ } ++ if (res_o == NULL) { ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; +@@ -5197,7 +5685,7 @@ + break; + } + +- /* _INSTRUMENTED_CALL_KW is not a viable micro-op for tier 2 because it is instrumented */ ++ /* _MONITOR_CALL_KW is not a viable micro-op for tier 2 because it uses the 'this_instr' variable */ + + case _MAYBE_EXPAND_METHOD_KW: { + _PyStackRef kwnames_in; +@@ -5214,6 +5702,8 @@ + callable = &stack_pointer[-3 - oparg]; + func = &stack_pointer[-3 - oparg]; + maybe_self = &stack_pointer[-2 - oparg]; ++ args = &stack_pointer[-1 - oparg]; ++ (void)args; + if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + PyObject *self = ((PyMethodObject *)callable_o)->im_self; +@@ -5221,7 +5711,9 @@ + PyObject *method = ((PyMethodObject *)callable_o)->im_func; + _PyStackRef temp = callable[0]; + func[0] = PyStackRef_FromPyObjectNew(method); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(temp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + } + kwnames_out = kwnames_in; + stack_pointer[-1] = kwnames_out; +@@ -5244,8 +5736,9 @@ + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + // oparg counts all of the args, but *not* self: + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); +@@ -5256,13 +5749,17 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyInterpreterFrame *temp = _PyEvalFramePushAndInit( + tstate, callable[0], locals, +- args, positional_args, kwnames_o, frame ++ arguments, positional_args, kwnames_o, frame + ); + stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(kwnames); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + // The frame has stolen all the arguments from the stack, + // so there is no need to clean them up. +- stack_pointer += -3 - oparg; ++ stack_pointer += -2 - oparg; + assert(WITHIN_STACK_BOUNDS()); + if (temp == NULL) { + JUMP_TO_ERROR(); +@@ -5321,23 +5818,21 @@ + } + + case _EXPAND_METHOD_KW: { +- _PyStackRef *null; ++ _PyStackRef *self_or_null; + _PyStackRef *callable; +- _PyStackRef *method; +- _PyStackRef *self; + oparg = CURRENT_OPARG(); +- null = &stack_pointer[-2 - oparg]; ++ self_or_null = &stack_pointer[-2 - oparg]; + callable = &stack_pointer[-3 - oparg]; +- method = &stack_pointer[-3 - oparg]; +- self = &stack_pointer[-2 - oparg]; ++ assert(PyStackRef_IsNull(self_or_null[0])); + _PyStackRef callable_s = callable[0]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable_s); +- assert(PyStackRef_IsNull(null[0])); + assert(Py_TYPE(callable_o) == &PyMethod_Type); +- self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); +- method[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); +- assert(PyStackRef_FunctionCheck(method[0])); ++ self_or_null[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); ++ callable[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); ++ assert(PyStackRef_FunctionCheck(callable[0])); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(callable_s); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + break; + } + +@@ -5373,20 +5868,23 @@ + #endif + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + /* Callable is not a normal Python function */ +- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + PyStackRef_CLOSE(callable[0]); +- PyStackRef_CLOSE(self_or_null[0]); ++ PyStackRef_XCLOSE(self_or_null[0]); + for (int _i = oparg; --_i >= 0;) { + PyStackRef_CLOSE(args[_i]); + } + PyStackRef_CLOSE(kwnames); +- if (true) JUMP_TO_ERROR(); ++ stack_pointer += -3 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); + } + PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); + int positional_args = total_args - (int)PyTuple_GET_SIZE(kwnames_o); +@@ -5396,36 +5894,43 @@ + positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, + kwnames_o); + stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(kwnames); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); +- } + PyStackRef_CLOSE(callable[0]); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ PyStackRef_XCLOSE(self_or_null[0]); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); ++ } ++ if (res_o == NULL) { ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); +- stack_pointer[-3 - oparg] = res; +- stack_pointer += -2 - oparg; ++ stack_pointer[-2 - oparg] = res; ++ stack_pointer += -1 - oparg; + assert(WITHIN_STACK_BOUNDS()); + break; + } + +- /* _INSTRUMENTED_CALL_FUNCTION_EX is not a viable micro-op for tier 2 because it is instrumented */ +- + case _MAKE_CALLARGS_A_TUPLE: { +- _PyStackRef kwargs_in = PyStackRef_NULL; ++ _PyStackRef kwargs_in; + _PyStackRef callargs; + _PyStackRef func; + _PyStackRef tuple; +- _PyStackRef kwargs_out = PyStackRef_NULL; +- oparg = CURRENT_OPARG(); +- if (oparg & 1) { kwargs_in = stack_pointer[-(oparg & 1)]; } +- callargs = stack_pointer[-1 - (oparg & 1)]; +- func = stack_pointer[-3 - (oparg & 1)]; ++ _PyStackRef kwargs_out; ++ kwargs_in = stack_pointer[-1]; ++ callargs = stack_pointer[-2]; ++ func = stack_pointer[-4]; + PyObject *callargs_o = PyStackRef_AsPyObjectBorrow(callargs); + if (PyTuple_CheckExact(callargs_o)) { + tuple = callargs; ++ kwargs_out = kwargs_in; + } + else { + _PyFrame_SetStackPointer(frame, stack_pointer); +@@ -5440,12 +5945,18 @@ + if (tuple_o == NULL) { + JUMP_TO_ERROR(); + } ++ kwargs_out = kwargs_in; ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(callargs); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + tuple = PyStackRef_FromPyObjectSteal(tuple_o); ++ stack_pointer += 2; ++ assert(WITHIN_STACK_BOUNDS()); + } +- kwargs_out = kwargs_in; +- stack_pointer[-1 - (oparg & 1)] = tuple; +- if (oparg & 1) stack_pointer[-(oparg & 1)] = kwargs_out; ++ stack_pointer[-2] = tuple; ++ stack_pointer[-1] = kwargs_out; + break; + } + +@@ -5460,12 +5971,20 @@ + PyFunctionObject *func_obj = (PyFunctionObject *) + PyFunction_New(codeobj, GLOBALS()); + stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(codeobj_st); +- if (func_obj == NULL) JUMP_TO_ERROR(); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (func_obj == NULL) { ++ JUMP_TO_ERROR(); ++ } + _PyFunction_SetVersion( + func_obj, ((PyCodeObject *)codeobj)->co_version); + func = PyStackRef_FromPyObjectSteal((PyObject *)func_obj); +- stack_pointer[-1] = func; ++ stack_pointer[0] = func; ++ stack_pointer += 1; ++ assert(WITHIN_STACK_BOUNDS()); + break; + } + +@@ -5498,7 +6017,9 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (gen == NULL) JUMP_TO_ERROR(); ++ if (gen == NULL) { ++ JUMP_TO_ERROR(); ++ } + assert(EMPTY()); + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyInterpreterFrame *gen_frame = &gen->gi_iframe; +@@ -5522,25 +6043,25 @@ + } + + case _BUILD_SLICE: { +- _PyStackRef step = PyStackRef_NULL; +- _PyStackRef stop; +- _PyStackRef start; ++ _PyStackRef *args; + _PyStackRef slice; + oparg = CURRENT_OPARG(); +- if (oparg == 3) { step = stack_pointer[-((oparg == 3) ? 1 : 0)]; } +- stop = stack_pointer[-1 - ((oparg == 3) ? 1 : 0)]; +- start = stack_pointer[-2 - ((oparg == 3) ? 1 : 0)]; +- PyObject *start_o = PyStackRef_AsPyObjectBorrow(start); +- PyObject *stop_o = PyStackRef_AsPyObjectBorrow(stop); +- PyObject *step_o = PyStackRef_AsPyObjectBorrow(step); ++ args = &stack_pointer[-oparg]; ++ PyObject *start_o = PyStackRef_AsPyObjectBorrow(args[0]); ++ PyObject *stop_o = PyStackRef_AsPyObjectBorrow(args[1]); ++ PyObject *step_o = oparg == 3 ? PyStackRef_AsPyObjectBorrow(args[2]) : NULL; + PyObject *slice_o = PySlice_New(start_o, stop_o, step_o); +- PyStackRef_CLOSE(start); +- PyStackRef_CLOSE(stop); +- PyStackRef_XCLOSE(step); +- if (slice_o == NULL) JUMP_TO_ERROR(); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); ++ } ++ if (slice_o == NULL) { ++ stack_pointer += -oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + slice = PyStackRef_FromPyObjectSteal(slice_o); +- stack_pointer[-2 - ((oparg == 3) ? 1 : 0)] = slice; +- stack_pointer += -1 - ((oparg == 3) ? 1 : 0); ++ stack_pointer[-oparg] = slice; ++ stack_pointer += 1 - oparg; + assert(WITHIN_STACK_BOUNDS()); + break; + } +@@ -5556,10 +6077,18 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *result_o = conv_fn(PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(value); +- if (result_o == NULL) JUMP_TO_ERROR(); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (result_o == NULL) { ++ JUMP_TO_ERROR(); ++ } + result = PyStackRef_FromPyObjectSteal(result_o); +- stack_pointer[-1] = result; ++ stack_pointer[0] = result; ++ stack_pointer += 1; ++ assert(WITHIN_STACK_BOUNDS()); + break; + } + +@@ -5574,14 +6103,24 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *res_o = PyObject_Format(value_o, NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(value); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (res_o == NULL) { ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + } + else { + res = value; ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); + } +- stack_pointer[-1] = res; ++ stack_pointer[0] = res; ++ stack_pointer += 1; ++ assert(WITHIN_STACK_BOUNDS()); + break; + } + +@@ -5596,7 +6135,11 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(value); + PyStackRef_CLOSE(fmt_spec); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ if (res_o == NULL) { ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -5632,7 +6175,11 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(lhs); + PyStackRef_CLOSE(rhs); +- if (res_o == NULL) JUMP_TO_ERROR(); ++ if (res_o == NULL) { ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_ERROR(); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -5641,18 +6188,15 @@ + } + + case _SWAP: { +- _PyStackRef top_in; +- _PyStackRef bottom_in; +- _PyStackRef top_out; +- _PyStackRef bottom_out; ++ _PyStackRef *top; ++ _PyStackRef *bottom; + oparg = CURRENT_OPARG(); +- top_in = stack_pointer[-1]; +- bottom_in = stack_pointer[-2 - (oparg-2)]; +- bottom_out = bottom_in; +- top_out = top_in; ++ top = &stack_pointer[-1]; ++ bottom = &stack_pointer[-2 - (oparg-2)]; ++ _PyStackRef temp = bottom[0]; ++ bottom[0] = top[0]; ++ top[0] = temp; + assert(oparg >= 2); +- stack_pointer[-2 - (oparg-2)] = top_out; +- stack_pointer[-1] = bottom_out; + break; + } + +@@ -5664,6 +6208,8 @@ + + /* _MONITOR_JUMP_BACKWARD is not a viable micro-op for tier 2 because it uses the 'this_instr' variable */ + ++ /* _INSTRUMENTED_NOT_TAKEN is not a viable micro-op for tier 2 because it is instrumented */ ++ + /* _INSTRUMENTED_POP_JUMP_IF_TRUE is not a viable micro-op for tier 2 because it is instrumented */ + + /* _INSTRUMENTED_POP_JUMP_IF_FALSE is not a viable micro-op for tier 2 because it is instrumented */ +@@ -5703,9 +6249,11 @@ + val = stack_pointer[-1]; + int is_none = PyStackRef_IsNone(val); + if (!is_none) { +- PyStackRef_CLOSE(val); + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(val); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + if (1) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); +@@ -5720,9 +6268,11 @@ + _PyStackRef val; + val = stack_pointer[-1]; + int is_none = PyStackRef_IsNone(val); +- PyStackRef_CLOSE(val); + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(val); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + if (is_none) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); +@@ -5770,16 +6320,14 @@ + PyObject *exit_p = (PyObject *)CURRENT_OPERAND0(); + _PyExitData *exit = (_PyExitData *)exit_p; + PyCodeObject *code = _PyFrame_GetCode(frame); +- _PyFrame_SetStackPointer(frame, stack_pointer); + _Py_CODEUNIT *target = _PyFrame_GetBytecode(frame) + exit->target; +- stack_pointer = _PyFrame_GetStackPointer(frame); + #if defined(Py_DEBUG) && !defined(_Py_JIT) + OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); +- if (lltrace >= 2) { ++ if (frame->lltrace >= 2) { + _PyFrame_SetStackPointer(frame, stack_pointer); + printf("SIDE EXIT: [UOp "); + _PyUOpPrint(&next_uop[-1]); +- printf(", exit %u, temp %d, target %d -> %s]\n", ++ printf(", exit %lu, temp %d, target %d -> %s]\n", + exit - current_executor->exits, exit->temperature.value_and_backoff, + (int)(target - _PyFrame_GetBytecode(frame)), + _PyOpcode_OpName[target->op.code]); +@@ -5788,13 +6336,15 @@ + #endif + if (exit->executor && !exit->executor->vm_data.valid) { + exit->temperature = initial_temperature_backoff_counter(); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + Py_CLEAR(exit->executor); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + } ++ tstate->previous_executor = (PyObject *)current_executor; + if (exit->executor == NULL) { + _Py_BackoffCounter temperature = exit->temperature; + if (!backoff_counter_triggers(temperature)) { + exit->temperature = advance_backoff_counter(temperature); +- tstate->previous_executor = (PyObject *)current_executor; + GOTO_TIER_ONE(target); + } + _PyExecutorObject *executor; +@@ -5805,24 +6355,17 @@ + else { + int chain_depth = current_executor->vm_data.chain_depth + 1; + _PyFrame_SetStackPointer(frame, stack_pointer); +- int optimized = _PyOptimizer_Optimize(frame, target, stack_pointer, &executor, chain_depth); ++ int optimized = _PyOptimizer_Optimize(frame, target, &executor, chain_depth); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (optimized <= 0) { + exit->temperature = restart_backoff_counter(temperature); +- if (optimized < 0) { +- GOTO_UNWIND(); +- } +- tstate->previous_executor = (PyObject *)current_executor; +- GOTO_TIER_ONE(target); +- } +- else { +- exit->temperature = initial_temperature_backoff_counter(); ++ GOTO_TIER_ONE(optimized < 0 ? NULL : target); + } ++ exit->temperature = initial_temperature_backoff_counter(); + } + exit->executor = executor; + } + Py_INCREF(exit->executor); +- tstate->previous_executor = (PyObject *)current_executor; + GOTO_TIER_TWO(exit->executor); + break; + } +@@ -5860,34 +6403,14 @@ + _PyStackRef value; + pop = stack_pointer[-1]; + PyObject *ptr = (PyObject *)CURRENT_OPERAND0(); +- PyStackRef_CLOSE(pop); +- value = PyStackRef_FromPyObjectImmortal(ptr); +- stack_pointer[-1] = value; +- break; +- } +- +- case _LOAD_CONST_INLINE_WITH_NULL: { +- _PyStackRef value; +- _PyStackRef null; +- PyObject *ptr = (PyObject *)CURRENT_OPERAND0(); +- value = PyStackRef_FromPyObjectNew(ptr); +- null = PyStackRef_NULL; +- stack_pointer[0] = value; +- stack_pointer[1] = null; +- stack_pointer += 2; ++ stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); +- break; +- } +- +- case _LOAD_CONST_INLINE_BORROW_WITH_NULL: { +- _PyStackRef value; +- _PyStackRef null; +- PyObject *ptr = (PyObject *)CURRENT_OPERAND0(); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(pop); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + value = PyStackRef_FromPyObjectImmortal(ptr); +- null = PyStackRef_NULL; + stack_pointer[0] = value; +- stack_pointer[1] = null; +- stack_pointer += 2; ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } +@@ -5905,8 +6428,6 @@ + + case _LOAD_GLOBAL_MODULE: { + _PyStackRef res; +- _PyStackRef null = PyStackRef_NULL; +- oparg = CURRENT_OPARG(); + uint16_t index = (uint16_t)CURRENT_OPERAND0(); + PyDictObject *dict = (PyDictObject *)GLOBALS(); + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); +@@ -5917,18 +6438,14 @@ + } + Py_INCREF(res_o); + res = PyStackRef_FromPyObjectSteal(res_o); +- null = PyStackRef_NULL; + stack_pointer[0] = res; +- if (oparg & 1) stack_pointer[1] = null; +- stack_pointer += 1 + (oparg & 1); ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } + + case _LOAD_GLOBAL_BUILTINS: { + _PyStackRef res; +- _PyStackRef null = PyStackRef_NULL; +- oparg = CURRENT_OPARG(); + uint16_t index = (uint16_t)CURRENT_OPERAND0(); + PyDictObject *dict = (PyDictObject *)BUILTINS(); + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); +@@ -5939,10 +6456,8 @@ + } + Py_INCREF(res_o); + res = PyStackRef_FromPyObjectSteal(res_o); +- null = PyStackRef_NULL; + stack_pointer[0] = res; +- if (oparg & 1) stack_pointer[1] = null; +- stack_pointer += 1 + (oparg & 1); ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } +@@ -5950,8 +6465,6 @@ + case _LOAD_ATTR_MODULE: { + _PyStackRef owner; + _PyStackRef attr; +- _PyStackRef null = PyStackRef_NULL; +- oparg = CURRENT_OPARG(); + owner = stack_pointer[-1]; + uint16_t index = (uint16_t)CURRENT_OPERAND0(); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); +@@ -5967,76 +6480,16 @@ + STAT_INC(LOAD_ATTR, hit); + Py_INCREF(attr_o); + attr = PyStackRef_FromPyObjectSteal(attr_o); +- null = PyStackRef_NULL; + PyStackRef_CLOSE(owner); + stack_pointer[-1] = attr; +- if (oparg & 1) stack_pointer[0] = null; +- stack_pointer += (oparg & 1); +- assert(WITHIN_STACK_BOUNDS()); +- break; +- } +- +- case _INTERNAL_INCREMENT_OPT_COUNTER: { +- _PyStackRef opt; +- opt = stack_pointer[-1]; +- _PyCounterOptimizerObject *exe = (_PyCounterOptimizerObject *)PyStackRef_AsPyObjectBorrow(opt); +- exe->count++; +- stack_pointer += -1; +- assert(WITHIN_STACK_BOUNDS()); +- break; +- } +- +- case _DYNAMIC_EXIT: { +- PyObject *exit_p = (PyObject *)CURRENT_OPERAND0(); +- tstate->previous_executor = (PyObject *)current_executor; +- _PyExitData *exit = (_PyExitData *)exit_p; +- _Py_CODEUNIT *target = frame->instr_ptr; +- #if defined(Py_DEBUG) && !defined(_Py_JIT) +- OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); +- if (lltrace >= 2) { +- _PyFrame_SetStackPointer(frame, stack_pointer); +- printf("DYNAMIC EXIT: [UOp "); +- _PyUOpPrint(&next_uop[-1]); +- printf(", exit %u, temp %d, target %d -> %s]\n", +- exit - current_executor->exits, exit->temperature.value_and_backoff, +- (int)(target - _PyFrame_GetBytecode(frame)), +- _PyOpcode_OpName[target->op.code]); +- stack_pointer = _PyFrame_GetStackPointer(frame); +- } +- #endif +- _PyExecutorObject *executor; +- if (target->op.code == ENTER_EXECUTOR) { +- PyCodeObject *code = _PyFrame_GetCode(frame); +- executor = code->co_executors->executors[target->op.arg]; +- Py_INCREF(executor); +- } +- else { +- if (!backoff_counter_triggers(exit->temperature)) { +- exit->temperature = advance_backoff_counter(exit->temperature); +- GOTO_TIER_ONE(target); +- } +- _PyFrame_SetStackPointer(frame, stack_pointer); +- int optimized = _PyOptimizer_Optimize(frame, target, stack_pointer, &executor, 0); +- stack_pointer = _PyFrame_GetStackPointer(frame); +- if (optimized <= 0) { +- exit->temperature = restart_backoff_counter(exit->temperature); +- if (optimized < 0) { +- GOTO_UNWIND(); +- } +- GOTO_TIER_ONE(target); +- } +- else { +- exit->temperature = initial_temperature_backoff_counter(); +- } +- } +- GOTO_TIER_TWO(executor); + break; + } + + case _START_EXECUTOR: { + PyObject *executor = (PyObject *)CURRENT_OPERAND0(); +- Py_DECREF(tstate->previous_executor); +- tstate->previous_executor = NULL; ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ Py_CLEAR(tstate->previous_executor); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + #ifndef _Py_JIT + current_executor = (_PyExecutorObject*)executor; + #endif +@@ -6070,19 +6523,18 @@ + } + + case _DEOPT: { +- EXIT_TO_TIER1(); ++ tstate->previous_executor = (PyObject *)current_executor; ++ GOTO_TIER_ONE(_PyFrame_GetBytecode(frame) + CURRENT_TARGET()); + break; + } + + case _ERROR_POP_N: { + oparg = CURRENT_OPARG(); + uint32_t target = (uint32_t)CURRENT_OPERAND0(); +- stack_pointer += -oparg; +- assert(WITHIN_STACK_BOUNDS()); +- _PyFrame_SetStackPointer(frame, stack_pointer); ++ tstate->previous_executor = (PyObject *)current_executor; ++ assert(oparg == 0); + frame->instr_ptr = _PyFrame_GetBytecode(frame) + target; +- stack_pointer = _PyFrame_GetStackPointer(frame); +- GOTO_UNWIND(); ++ GOTO_TIER_ONE(NULL); + break; + } + +diff --git a/Python/fileutils.c b/Python/fileutils.c +index 9529b14d377..68d24bc6b93 100644 +--- a/Python/fileutils.c ++++ b/Python/fileutils.c +@@ -1,6 +1,7 @@ + #include "Python.h" + #include "pycore_fileutils.h" // fileutils definitions + #include "pycore_runtime.h" // _PyRuntime ++#include "pycore_pystate.h" // _Py_AssertHoldsTstate() + #include "osdefs.h" // SEP + + #include // mbstowcs() +@@ -1311,7 +1312,7 @@ + { + int res; + +- assert(PyGILState_Check()); ++ _Py_AssertHoldsTstate(); + + Py_BEGIN_ALLOW_THREADS + res = _Py_fstat_noraise(fd, status); +@@ -1468,14 +1469,14 @@ + assert(!(atomic_flag_works != NULL && inheritable)); + + if (atomic_flag_works != NULL && !inheritable) { +- if (*atomic_flag_works == -1) { ++ if (_Py_atomic_load_int_relaxed(atomic_flag_works) == -1) { + int isInheritable = get_inheritable(fd, raise); + if (isInheritable == -1) + return -1; +- *atomic_flag_works = !isInheritable; ++ _Py_atomic_store_int_relaxed(atomic_flag_works, !isInheritable); + } + +- if (*atomic_flag_works) ++ if (_Py_atomic_load_int_relaxed(atomic_flag_works)) + return 0; + } + +@@ -1691,7 +1692,7 @@ + _Py_open(const char *pathname, int flags) + { + /* _Py_open() must be called with the GIL held. */ +- assert(PyGILState_Check()); ++ _Py_AssertHoldsTstate(); + return _Py_open_impl(pathname, flags, 1); + } + +@@ -1748,8 +1749,10 @@ + } + + +-/* Open a file. Call _wfopen() on Windows, or encode the path to the filesystem +- encoding and call fopen() otherwise. ++/* Open a file. ++ ++ On Windows, if 'path' is a Unicode string, call _wfopen(). Otherwise, encode ++ the path to the filesystem encoding and call fopen(). + + Return the new file object on success. Raise an exception and return NULL + on error. +@@ -1762,32 +1765,32 @@ + Release the GIL to call _wfopen() or fopen(). The caller must hold + the GIL. */ + FILE* +-_Py_fopen_obj(PyObject *path, const char *mode) ++Py_fopen(PyObject *path, const char *mode) + { +- FILE *f; +- int async_err = 0; +-#ifdef MS_WINDOWS +- wchar_t wmode[10]; +- int usize; +- +- assert(PyGILState_Check()); ++ _Py_AssertHoldsTstate(); + + if (PySys_Audit("open", "Osi", path, mode, 0) < 0) { + return NULL; + } +- if (!PyUnicode_Check(path)) { +- PyErr_Format(PyExc_TypeError, +- "str file path expected under Windows, got %R", +- Py_TYPE(path)); ++ ++ FILE *f; ++ int async_err = 0; ++ int saved_errno; ++#ifdef MS_WINDOWS ++ PyObject *unicode; ++ if (!PyUnicode_FSDecoder(path, &unicode)) { + return NULL; + } + +- wchar_t *wpath = PyUnicode_AsWideCharString(path, NULL); +- if (wpath == NULL) ++ wchar_t *wpath = PyUnicode_AsWideCharString(unicode, NULL); ++ Py_DECREF(unicode); ++ if (wpath == NULL) { + return NULL; ++ } + +- usize = MultiByteToWideChar(CP_ACP, 0, mode, -1, +- wmode, Py_ARRAY_LENGTH(wmode)); ++ wchar_t wmode[10]; ++ int usize = MultiByteToWideChar(CP_ACP, 0, mode, -1, ++ wmode, Py_ARRAY_LENGTH(wmode)); + if (usize == 0) { + PyErr_SetFromWindowsErr(0); + PyMem_Free(wpath); +@@ -1796,26 +1799,20 @@ + + do { + Py_BEGIN_ALLOW_THREADS ++ _Py_BEGIN_SUPPRESS_IPH + f = _wfopen(wpath, wmode); ++ _Py_END_SUPPRESS_IPH + Py_END_ALLOW_THREADS + } while (f == NULL + && errno == EINTR && !(async_err = PyErr_CheckSignals())); +- int saved_errno = errno; ++ saved_errno = errno; + PyMem_Free(wpath); + #else + PyObject *bytes; +- const char *path_bytes; +- +- assert(PyGILState_Check()); +- +- if (!PyUnicode_FSConverter(path, &bytes)) +- return NULL; +- path_bytes = PyBytes_AS_STRING(bytes); +- +- if (PySys_Audit("open", "Osi", path, mode, 0) < 0) { +- Py_DECREF(bytes); ++ if (!PyUnicode_FSConverter(path, &bytes)) { + return NULL; + } ++ const char *path_bytes = PyBytes_AS_STRING(bytes); + + do { + Py_BEGIN_ALLOW_THREADS +@@ -1823,11 +1820,13 @@ + Py_END_ALLOW_THREADS + } while (f == NULL + && errno == EINTR && !(async_err = PyErr_CheckSignals())); +- int saved_errno = errno; ++ saved_errno = errno; + Py_DECREF(bytes); + #endif +- if (async_err) ++ ++ if (async_err) { + return NULL; ++ } + + if (f == NULL) { + errno = saved_errno; +@@ -1842,6 +1841,19 @@ + return f; + } + ++ ++// Call fclose(). ++// ++// On Windows, files opened by Py_fopen() in the Python DLL must be closed by ++// the Python DLL to use the same C runtime version. Otherwise, calling ++// fclose() directly can cause undefined behavior. ++int ++Py_fclose(FILE *file) ++{ ++ return fclose(file); ++} ++ ++ + /* Read count bytes from fd into buf. + + On success, return the number of read bytes, it can be lower than count. +@@ -1862,7 +1874,7 @@ + int err; + int async_err = 0; + +- assert(PyGILState_Check()); ++ _Py_AssertHoldsTstate(); + + /* _Py_read() must not be called with an exception set, otherwise the + * caller may think that read() was interrupted by a signal and the signal +@@ -2028,7 +2040,7 @@ + Py_ssize_t + _Py_write(int fd, const void *buf, size_t count) + { +- assert(PyGILState_Check()); ++ _Py_AssertHoldsTstate(); + + /* _Py_write() must not be called with an exception set, otherwise the + * caller may think that write() was interrupted by a signal and the signal +@@ -2656,7 +2668,7 @@ + HANDLE handle; + #endif + +- assert(PyGILState_Check()); ++ _Py_AssertHoldsTstate(); + + #ifdef MS_WINDOWS + handle = _Py_get_osfhandle(fd); +diff --git a/Python/flowgraph.c b/Python/flowgraph.c +index b1097b64469..308cdac3c44 100644 +--- a/Python/flowgraph.c ++++ b/Python/flowgraph.c +@@ -2,9 +2,12 @@ + #include + + #include "Python.h" ++#include "opcode.h" + #include "pycore_flowgraph.h" + #include "pycore_compile.h" ++#include "pycore_intrinsics.h" + #include "pycore_pymem.h" // _PyMem_IsPtrFreed() ++#include "pycore_long.h" // _PY_IS_SMALL_INT() + + #include "pycore_opcode_utils.h" + #include "pycore_opcode_metadata.h" // OPCODE_HAS_ARG, etc +@@ -522,14 +525,15 @@ + static int + normalize_jumps_in_block(cfg_builder *g, basicblock *b) { + cfg_instr *last = basicblock_last_instr(b); +- if (last == NULL || !is_jump(last) || +- IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)) { ++ if (last == NULL || !IS_CONDITIONAL_JUMP_OPCODE(last->i_opcode)) { + return SUCCESS; + } + assert(!IS_ASSEMBLER_OPCODE(last->i_opcode)); + + bool is_forward = last->i_target->b_visited == 0; + if (is_forward) { ++ RETURN_IF_ERROR( ++ basicblock_addop(b, NOT_TAKEN, 0, last->i_loc)); + return SUCCESS; + } + +@@ -557,6 +561,8 @@ + if (backwards_jump == NULL) { + return ERROR; + } ++ RETURN_IF_ERROR( ++ basicblock_addop(backwards_jump, NOT_TAKEN, 0, last->i_loc)); + RETURN_IF_ERROR( + basicblock_add_jump(backwards_jump, JUMP, target, last->i_loc)); + last->i_opcode = reversed_opcode; +@@ -1332,6 +1338,66 @@ + return (int)index; + } + ++/* ++ Walk basic block backwards starting from "start" trying to collect "size" number of ++ subsequent constants from instructions loading constants into new tuple ignoring NOP's in between. ++ ++ Returns ERROR on error and sets "seq" to NULL. ++ Returns SUCCESS on success and sets "seq" to NULL if failed to collect requested number of constants. ++ Returns SUCCESS on success and sets "seq" to resulting tuple if succeeded to collect requested number of constants. ++*/ ++static int ++get_constant_sequence(basicblock *bb, int start, int size, ++ PyObject *consts, PyObject **seq) ++{ ++ assert(start < bb->b_iused); ++ *seq = NULL; ++ PyObject *res = PyTuple_New((Py_ssize_t)size); ++ if (res == NULL) { ++ return ERROR; ++ } ++ for (; start >= 0 && size > 0; start--) { ++ cfg_instr *instr = &bb->b_instr[start]; ++ if (instr->i_opcode == NOP) { ++ continue; ++ } ++ if (!loads_const(instr->i_opcode)) { ++ break; ++ } ++ PyObject *constant = get_const_value(instr->i_opcode, instr->i_oparg, consts); ++ if (constant == NULL) { ++ Py_DECREF(res); ++ return ERROR; ++ } ++ PyTuple_SET_ITEM(res, --size, constant); ++ } ++ if (size > 0) { ++ Py_DECREF(res); ++ } ++ else { ++ *seq = res; ++ } ++ return SUCCESS; ++} ++ ++/* ++ Walk basic block backwards starting from "start" and change "count" number of ++ non-NOP instructions to NOP's. ++*/ ++static void ++nop_out(basicblock *bb, int start, int count) ++{ ++ assert(start < bb->b_iused); ++ for (; count > 0; start--) { ++ assert(start >= 0); ++ if (bb->b_instr[start].i_opcode == NOP) { ++ continue; ++ } ++ INSTR_SET_OP0(&bb->b_instr[start], NOP); ++ count--; ++ } ++} ++ + /* Replace LOAD_CONST c1, LOAD_CONST c2 ... LOAD_CONST cn, BUILD_TUPLE n + with LOAD_CONST (c1, c2, ... cn). + The consts table must still be in list form so that the +@@ -1339,47 +1405,159 @@ + Called with codestr pointing to the first LOAD_CONST. + */ + static int +-fold_tuple_on_constants(PyObject *const_cache, +- cfg_instr *inst, +- int n, PyObject *consts) ++fold_tuple_of_constants(basicblock *bb, int n, PyObject *consts, PyObject *const_cache) + { + /* Pre-conditions */ + assert(PyDict_CheckExact(const_cache)); + assert(PyList_CheckExact(consts)); +- assert(inst[n].i_opcode == BUILD_TUPLE); +- assert(inst[n].i_oparg == n); +- +- for (int i = 0; i < n; i++) { +- if (!loads_const(inst[i].i_opcode)) { +- return SUCCESS; +- } ++ cfg_instr *instr = &bb->b_instr[n]; ++ assert(instr->i_opcode == BUILD_TUPLE); ++ int seq_size = instr->i_oparg; ++ PyObject *newconst; ++ RETURN_IF_ERROR(get_constant_sequence(bb, n-1, seq_size, consts, &newconst)); ++ if (newconst == NULL) { ++ /* not a const sequence */ ++ return SUCCESS; + } ++ assert(PyTuple_CheckExact(newconst) && PyTuple_GET_SIZE(newconst) == seq_size); ++ int index = add_const(newconst, consts, const_cache); ++ RETURN_IF_ERROR(index); ++ nop_out(bb, n-1, seq_size); ++ INSTR_SET_OP1(&bb->b_instr[n], LOAD_CONST, index); ++ return SUCCESS; ++} + +- /* Buildup new tuple of constants */ +- PyObject *newconst = PyTuple_New(n); ++#define MIN_CONST_SEQUENCE_SIZE 3 ++/* Replace LOAD_CONST c1, LOAD_CONST c2 ... LOAD_CONST cN, BUILD_LIST N ++ with BUILD_LIST 0, LOAD_CONST (c1, c2, ... cN), LIST_EXTEND 1, ++ or BUILD_SET & SET_UPDATE respectively. ++*/ ++static int ++optimize_if_const_list_or_set(basicblock *bb, int n, PyObject *consts, PyObject *const_cache) ++{ ++ assert(PyDict_CheckExact(const_cache)); ++ assert(PyList_CheckExact(consts)); ++ cfg_instr *instr = &bb->b_instr[n]; ++ assert(instr->i_opcode == BUILD_LIST || instr->i_opcode == BUILD_SET); ++ int seq_size = instr->i_oparg; ++ if (seq_size < MIN_CONST_SEQUENCE_SIZE) { ++ return SUCCESS; ++ } ++ PyObject *newconst; ++ RETURN_IF_ERROR(get_constant_sequence(bb, n-1, seq_size, consts, &newconst)); + if (newconst == NULL) { +- return ERROR; ++ /* not a const sequence */ ++ return SUCCESS; + } +- for (int i = 0; i < n; i++) { +- int op = inst[i].i_opcode; +- int arg = inst[i].i_oparg; +- PyObject *constant = get_const_value(op, arg, consts); +- if (constant == NULL) { ++ assert(PyTuple_CheckExact(newconst) && PyTuple_GET_SIZE(newconst) == seq_size); ++ int build = instr->i_opcode; ++ int extend = build == BUILD_LIST ? LIST_EXTEND : SET_UPDATE; ++ if (build == BUILD_SET) { ++ PyObject *frozenset = PyFrozenSet_New(newconst); ++ if (frozenset == NULL) { ++ Py_DECREF(newconst); + return ERROR; + } +- PyTuple_SET_ITEM(newconst, i, constant); ++ Py_SETREF(newconst, frozenset); + } + int index = add_const(newconst, consts, const_cache); +- if (index < 0) { +- return ERROR; ++ RETURN_IF_ERROR(index); ++ nop_out(bb, n-1, seq_size); ++ assert(n >= 2); ++ INSTR_SET_OP1(&bb->b_instr[n-2], build, 0); ++ INSTR_SET_OP1(&bb->b_instr[n-1], LOAD_CONST, index); ++ INSTR_SET_OP1(&bb->b_instr[n], extend, 1); ++ return SUCCESS; ++} ++ ++/* ++ Walk basic block backwards starting from "start" to collect instruction pair ++ that loads consts skipping NOP's in between. ++*/ ++static bool ++find_load_const_pair(basicblock *bb, int start, cfg_instr **first, cfg_instr **second) ++{ ++ cfg_instr *second_load_const = NULL; ++ while (start >= 0) { ++ cfg_instr *inst = &bb->b_instr[start--]; ++ if (inst->i_opcode == NOP) { ++ continue; ++ } ++ if (!loads_const(inst->i_opcode)) { ++ return false; ++ } ++ if (second_load_const == NULL) { ++ second_load_const = inst; ++ continue; ++ } ++ *first = inst; ++ *second = second_load_const; ++ return true; + } +- for (int i = 0; i < n; i++) { +- INSTR_SET_OP0(&inst[i], NOP); ++ return false; ++} ++ ++/* Determine opcode & oparg for freshly folded constant. */ ++static int ++newop_from_folded(PyObject *newconst, PyObject *consts, ++ PyObject *const_cache, int *newopcode, int *newoparg) ++{ ++ if (PyLong_CheckExact(newconst)) { ++ int overflow; ++ long val = PyLong_AsLongAndOverflow(newconst, &overflow); ++ if (!overflow && _PY_IS_SMALL_INT(val)) { ++ *newopcode = LOAD_SMALL_INT; ++ *newoparg = val; ++ return SUCCESS; ++ } + } +- INSTR_SET_OP1(&inst[n], LOAD_CONST, index); ++ *newopcode = LOAD_CONST; ++ *newoparg = add_const(newconst, consts, const_cache); ++ RETURN_IF_ERROR(*newoparg); + return SUCCESS; + } + ++static int ++optimize_if_const_op(basicblock *bb, int n, PyObject *consts, PyObject *const_cache) ++{ ++ cfg_instr *subscr = &bb->b_instr[n]; ++ assert(subscr->i_opcode == BINARY_OP); ++ if (subscr->i_oparg != NB_SUBSCR) { ++ /* TODO: support other binary ops */ ++ return SUCCESS; ++ } ++ cfg_instr *arg, *idx; ++ if (!find_load_const_pair(bb, n-1, &arg, &idx)) { ++ return SUCCESS; ++ } ++ PyObject *o = NULL, *key = NULL; ++ if ((o = get_const_value(arg->i_opcode, arg->i_oparg, consts)) == NULL ++ || (key = get_const_value(idx->i_opcode, idx->i_oparg, consts)) == NULL) ++ { ++ goto error; ++ } ++ PyObject *newconst = PyObject_GetItem(o, key); ++ Py_DECREF(o); ++ Py_DECREF(key); ++ if (newconst == NULL) { ++ if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) { ++ return ERROR; ++ } ++ PyErr_Clear(); ++ return SUCCESS; ++ } ++ int newopcode, newoparg; ++ RETURN_IF_ERROR(newop_from_folded(newconst, consts, const_cache, &newopcode, &newoparg)); ++ INSTR_SET_OP1(subscr, newopcode, newoparg); ++ INSTR_SET_OP0(arg, NOP); ++ INSTR_SET_OP0(idx, NOP); ++ return SUCCESS; ++error: ++ Py_XDECREF(o); ++ Py_XDECREF(key); ++ return ERROR; ++} ++ + #define VISITED (-1) + + // Replace an arbitrary run of SWAPs and NOPs with an optimal one that has the +@@ -1741,11 +1919,11 @@ + continue; + } + } +- if (i >= oparg) { +- if (fold_tuple_on_constants(const_cache, inst-oparg, oparg, consts)) { +- goto error; +- } +- } ++ RETURN_IF_ERROR(fold_tuple_of_constants(bb, i, consts, const_cache)); ++ break; ++ case BUILD_LIST: ++ case BUILD_SET: ++ RETURN_IF_ERROR(optimize_if_const_list_or_set(bb, i, consts, const_cache)); + break; + case POP_JUMP_IF_NOT_NONE: + case POP_JUMP_IF_NONE: +@@ -1871,6 +2049,15 @@ + continue; + } + break; ++ case CALL_INTRINSIC_1: ++ // for _ in (*foo, *bar) -> for _ in [*foo, *bar] ++ if (oparg == INTRINSIC_LIST_TO_TUPLE && nextop == GET_ITER) { ++ INSTR_SET_OP0(inst, NOP); ++ } ++ break; ++ case BINARY_OP: ++ RETURN_IF_ERROR(optimize_if_const_op(bb, i, consts, const_cache)); ++ break; + } + } + +diff --git a/Python/frame.c b/Python/frame.c +index 9a865e57d97..68ac2acbaee 100644 +--- a/Python/frame.c ++++ b/Python/frame.c +@@ -40,7 +40,6 @@ + // here. + assert(frame->frame_obj == NULL); + assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT); +- assert(frame->owner != FRAME_CLEARED); + f->f_frame = frame; + frame->frame_obj = f; + return f; +@@ -49,9 +48,8 @@ + static void + take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame) + { +- assert(frame->owner != FRAME_OWNED_BY_CSTACK); ++ assert(frame->owner < FRAME_OWNED_BY_INTERPRETER); + assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT); +- assert(frame->owner != FRAME_CLEARED); + Py_ssize_t size = ((char*)frame->stackpointer) - (char *)frame; + memcpy((_PyInterpreterFrame *)f->_f_frame_data, frame, size); + frame = (_PyInterpreterFrame *)f->_f_frame_data; +@@ -71,7 +69,7 @@ + _PyInterpreterFrame *prev = _PyFrame_GetFirstComplete(frame->previous); + frame->previous = NULL; + if (prev) { +- assert(prev->owner != FRAME_OWNED_BY_CSTACK); ++ assert(prev->owner < FRAME_OWNED_BY_INTERPRETER); + /* Link PyFrameObjects.f_back and remove link through _PyInterpreterFrame.previous */ + PyFrameObject *back = _PyFrame_GetFrameObject(prev); + if (back == NULL) { +diff --git a/Python/gc.c b/Python/gc.c +index 5b9588c8741..0fb2f03b040 100644 +--- a/Python/gc.c ++++ b/Python/gc.c +@@ -994,7 +994,8 @@ + /* copy-paste of weakrefobject.c's handle_callback() */ + temp = PyObject_CallOneArg(callback, (PyObject *)wr); + if (temp == NULL) { +- PyErr_WriteUnraisable(callback); ++ PyErr_FormatUnraisable("Exception ignored on " ++ "calling weakref callback %R", callback); + } + else { + Py_DECREF(temp); +@@ -1476,7 +1477,7 @@ + while (ts) { + _PyInterpreterFrame *frame = ts->current_frame; + while (frame) { +- if (frame->owner == FRAME_OWNED_BY_CSTACK) { ++ if (frame->owner >= FRAME_OWNED_BY_INTERPRETER) { + frame = frame->previous; + continue; + } +@@ -1779,7 +1780,7 @@ + "collected", stats->collected, + "uncollectable", stats->uncollectable); + if (info == NULL) { +- PyErr_FormatUnraisable("Exception ignored on invoking gc callbacks"); ++ PyErr_FormatUnraisable("Exception ignored while invoking gc callbacks"); + return; + } + } +@@ -1787,7 +1788,7 @@ + PyObject *phase_obj = PyUnicode_FromString(phase); + if (phase_obj == NULL) { + Py_XDECREF(info); +- PyErr_FormatUnraisable("Exception ignored on invoking gc callbacks"); ++ PyErr_FormatUnraisable("Exception ignored while invoking gc callbacks"); + return; + } + +@@ -1797,7 +1798,8 @@ + Py_INCREF(cb); /* make sure cb doesn't go away */ + r = PyObject_Vectorcall(cb, stack, 2, NULL); + if (r == NULL) { +- PyErr_WriteUnraisable(cb); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "calling GC callback %R", cb); + } + else { + Py_DECREF(r); +@@ -2086,13 +2088,14 @@ + "gc", NULL, message, + PyList_GET_SIZE(gcstate->garbage))) + { +- PyErr_WriteUnraisable(NULL); ++ PyErr_FormatUnraisable("Exception ignored in GC shutdown"); + } + if (gcstate->debug & _PyGC_DEBUG_UNCOLLECTABLE) { + PyObject *repr = NULL, *bytes = NULL; + repr = PyObject_Repr(gcstate->garbage); + if (!repr || !(bytes = PyUnicode_EncodeFSDefault(repr))) { +- PyErr_WriteUnraisable(gcstate->garbage); ++ PyErr_FormatUnraisable("Exception ignored in GC shutdown " ++ "while formatting garbage"); + } + else { + PySys_WriteStderr( +@@ -2344,9 +2347,12 @@ + #ifdef Py_DEBUG + PyObject *exc = PyErr_GetRaisedException(); + if (PyErr_WarnExplicitFormat(PyExc_ResourceWarning, "gc", 0, +- "gc", NULL, "Object of type %s is not untracked before destruction", +- Py_TYPE(op)->tp_name)) { +- PyErr_WriteUnraisable(NULL); ++ "gc", NULL, ++ "Object of type %s is not untracked " ++ "before destruction", ++ Py_TYPE(op)->tp_name)) ++ { ++ PyErr_FormatUnraisable("Exception ignored on object deallocation"); + } + PyErr_SetRaisedException(exc); + #endif +diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c +index f7f44407494..9e459da3a44 100644 +--- a/Python/gc_free_threading.c ++++ b/Python/gc_free_threading.c +@@ -17,6 +17,20 @@ + #include "pydtrace.h" + #include "pycore_uniqueid.h" // _PyObject_MergeThreadLocalRefcounts() + ++ ++// enable the "mark alive" pass of GC ++#define GC_ENABLE_MARK_ALIVE 1 ++ ++// if true, enable the use of "prefetch" CPU instructions ++#define GC_ENABLE_PREFETCH_INSTRUCTIONS 1 ++ ++// include additional roots in "mark alive" pass ++#define GC_MARK_ALIVE_EXTRA_ROOTS 1 ++ ++// include Python stacks as set of known roots ++#define GC_MARK_ALIVE_STACKS 1 ++ ++ + #ifdef Py_GIL_DISABLED + + typedef struct _gc_runtime_state GCState; +@@ -56,6 +70,10 @@ + PyInterpreterState *interp; + GCState *gcstate; + _PyGC_Reason reason; ++ // GH-129236: If we see an active frame without a valid stack pointer, ++ // we can't collect objects with deferred references because we may not ++ // see all references. ++ int skip_deferred_objects; + Py_ssize_t collected; + Py_ssize_t uncollectable; + Py_ssize_t long_lived_total; +@@ -113,28 +131,66 @@ + iter->next = iter->ptr; + } + ++static inline int ++gc_has_bit(PyObject *op, uint8_t bit) ++{ ++ return (op->ob_gc_bits & bit) != 0; ++} ++ ++static inline void ++gc_set_bit(PyObject *op, uint8_t bit) ++{ ++ op->ob_gc_bits |= bit; ++} ++ ++static inline void ++gc_clear_bit(PyObject *op, uint8_t bit) ++{ ++ op->ob_gc_bits &= ~bit; ++} ++ + static inline int + gc_is_frozen(PyObject *op) + { +- return (op->ob_gc_bits & _PyGC_BITS_FROZEN) != 0; ++ return gc_has_bit(op, _PyGC_BITS_FROZEN); + } + + static inline int + gc_is_unreachable(PyObject *op) + { +- return (op->ob_gc_bits & _PyGC_BITS_UNREACHABLE) != 0; ++ return gc_has_bit(op, _PyGC_BITS_UNREACHABLE); + } + +-static void ++static inline void + gc_set_unreachable(PyObject *op) + { +- op->ob_gc_bits |= _PyGC_BITS_UNREACHABLE; ++ gc_set_bit(op, _PyGC_BITS_UNREACHABLE); + } + +-static void ++static inline void + gc_clear_unreachable(PyObject *op) + { +- op->ob_gc_bits &= ~_PyGC_BITS_UNREACHABLE; ++ gc_clear_bit(op, _PyGC_BITS_UNREACHABLE); ++} ++ ++static inline int ++gc_is_alive(PyObject *op) ++{ ++ return gc_has_bit(op, _PyGC_BITS_ALIVE); ++} ++ ++#ifdef GC_ENABLE_MARK_ALIVE ++static inline void ++gc_set_alive(PyObject *op) ++{ ++ gc_set_bit(op, _PyGC_BITS_ALIVE); ++} ++#endif ++ ++static inline void ++gc_clear_alive(PyObject *op) ++{ ++ gc_clear_bit(op, _PyGC_BITS_ALIVE); + } + + // Initialize the `ob_tid` field to zero if the object is not already +@@ -143,6 +199,7 @@ + gc_maybe_init_refs(PyObject *op) + { + if (!gc_is_unreachable(op)) { ++ assert(!gc_is_alive(op)); + gc_set_unreachable(op); + op->ob_tid = 0; + } +@@ -264,9 +321,13 @@ + gc_restore_refs(PyObject *op) + { + if (gc_is_unreachable(op)) { ++ assert(!gc_is_alive(op)); + gc_restore_tid(op); + gc_clear_unreachable(op); + } ++ else { ++ gc_clear_alive(op); ++ } + } + + // Given a mimalloc memory block return the PyObject stored in it or NULL if +@@ -359,9 +420,6 @@ + static inline void + gc_visit_stackref(_PyStackRef stackref) + { +- // Note: we MUST check that it is deferred before checking the rest. +- // Otherwise we might read into invalid memory due to non-deferred references +- // being dead already. + if (PyStackRef_IsDeferred(stackref) && !PyStackRef_IsNull(stackref)) { + PyObject *obj = PyStackRef_AsPyObjectBorrow(stackref); + if (_PyObject_GC_IS_TRACKED(obj) && !gc_is_frozen(obj)) { +@@ -372,25 +430,419 @@ + + // Add 1 to the gc_refs for every deferred reference on each thread's stack. + static void +-gc_visit_thread_stacks(PyInterpreterState *interp) ++gc_visit_thread_stacks(PyInterpreterState *interp, struct collection_state *state) + { + _Py_FOR_EACH_TSTATE_BEGIN(interp, p) { + for (_PyInterpreterFrame *f = p->current_frame; f != NULL; f = f->previous) { +- PyObject *executable = PyStackRef_AsPyObjectBorrow(f->f_executable); +- if (executable == NULL || !PyCode_Check(executable)) { ++ if (f->owner >= FRAME_OWNED_BY_INTERPRETER) { ++ continue; ++ } ++ ++ _PyStackRef *top = f->stackpointer; ++ if (top == NULL) { ++ // GH-129236: The stackpointer may be NULL in cases where ++ // the GC is run during a PyStackRef_CLOSE() call. Skip this ++ // frame and don't collect objects with deferred references. ++ state->skip_deferred_objects = 1; + continue; + } + +- PyCodeObject *co = (PyCodeObject *)executable; +- int max_stack = co->co_nlocalsplus + co->co_stacksize; + gc_visit_stackref(f->f_executable); +- for (int i = 0; i < max_stack; i++) { +- gc_visit_stackref(f->localsplus[i]); ++ while (top != f->localsplus) { ++ --top; ++ gc_visit_stackref(*top); ++ } ++ } ++ } ++ _Py_FOR_EACH_TSTATE_END(interp); ++} ++ ++// Untrack objects that can never create reference cycles. ++// Return true if the object was untracked. ++static bool ++gc_maybe_untrack(PyObject *op) ++{ ++ // Currently we only check for tuples containing only non-GC objects. In ++ // theory we could check other immutable objects that contain references ++ // to non-GC objects. ++ if (PyTuple_CheckExact(op)) { ++ _PyTuple_MaybeUntrack(op); ++ if (!_PyObject_GC_IS_TRACKED(op)) { ++ return true; ++ } ++ } ++ return false; ++} ++ ++#ifdef GC_ENABLE_MARK_ALIVE ++ ++// prefetch buffer and stack ////////////////////////////////// ++ ++// The buffer is a circular FIFO queue of PyObject pointers. We take ++// care to not dereference these pointers until they are taken out of ++// the buffer. A prefetch CPU instruction is issued when a pointer is ++// put into the buffer. If all is working as expected, there will be ++// enough time between the enqueue and dequeue so that the needed memory ++// for the object, most importantly ob_gc_bits and ob_type words, will ++// already be in the CPU cache. ++#define BUFFER_SIZE 256 ++#define BUFFER_HI 16 ++#define BUFFER_LO 8 ++#define BUFFER_MASK (BUFFER_SIZE - 1) ++ ++// the buffer size must be an exact power of two ++static_assert(BUFFER_SIZE > 0 && !(BUFFER_SIZE & BUFFER_MASK), ++ "Invalid BUFFER_SIZE, must be power of 2"); ++// the code below assumes these relationships are true ++static_assert(BUFFER_HI < BUFFER_SIZE && ++ BUFFER_LO < BUFFER_HI && ++ BUFFER_LO > 0, ++ "Invalid prefetch buffer level settings."); ++ ++// Prefetch intructions will fetch the line of data from memory that ++// contains the byte specified with the source operand to a location in ++// the cache hierarchy specified by a locality hint. The instruction ++// is only a hint and the CPU is free to ignore it. Instructions and ++// behaviour are CPU specific but the definitions of locality hints ++// below are mostly consistent. ++// ++// * T0 (temporal data) prefetch data into all levels of the cache hierarchy. ++// ++// * T1 (temporal data with respect to first level cache) prefetch data into ++// level 2 cache and higher. ++// ++// * T2 (temporal data with respect to second level cache) prefetch data into ++// level 3 cache and higher, or an implementation-specific choice. ++// ++// * NTA (non-temporal data with respect to all cache levels) prefetch data into ++// non-temporal cache structure and into a location close to the processor, ++// minimizing cache pollution. ++ ++#if defined(__GNUC__) || defined(__clang__) ++ #define PREFETCH_T0(ptr) __builtin_prefetch(ptr, 0, 3) ++ #define PREFETCH_T1(ptr) __builtin_prefetch(ptr, 0, 2) ++ #define PREFETCH_T2(ptr) __builtin_prefetch(ptr, 0, 1) ++ #define PREFETCH_NTA(ptr) __builtin_prefetch(ptr, 0, 0) ++#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) && !defined(_M_ARM64EC) ++ #include ++ #define PREFETCH_T0(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0) ++ #define PREFETCH_T1(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T1) ++ #define PREFETCH_T2(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T2) ++ #define PREFETCH_NTA(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_NTA) ++#elif defined (__aarch64__) ++ #define PREFETCH_T0(ptr) \ ++ do { __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr))); } while (0) ++ #define PREFETCH_T1(ptr) \ ++ do { __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr))); } while (0) ++ #define PREFETCH_T2(ptr) \ ++ do { __asm__ __volatile__("prfm pldl3keep, %0" ::"Q"(*(ptr))); } while (0) ++ #define PREFETCH_NTA(ptr) \ ++ do { __asm__ __volatile__("prfm pldl1strm, %0" ::"Q"(*(ptr))); } while (0) ++#else ++ #define PREFETCH_T0(ptr) do { (void)(ptr); } while (0) /* disabled */ ++ #define PREFETCH_T1(ptr) do { (void)(ptr); } while (0) /* disabled */ ++ #define PREFETCH_T2(ptr) do { (void)(ptr); } while (0) /* disabled */ ++ #define PREFETCH_NTA(ptr) do { (void)(ptr); } while (0) /* disabled */ ++#endif ++ ++#ifdef GC_ENABLE_PREFETCH_INSTRUCTIONS ++ #define prefetch(ptr) PREFETCH_T1(ptr) ++#else ++ #define prefetch(ptr) ++#endif ++ ++// a contigous sequence of PyObject pointers, can contain NULLs ++typedef struct { ++ PyObject **start; ++ PyObject **end; ++} gc_span_t; ++ ++typedef struct { ++ Py_ssize_t size; ++ Py_ssize_t capacity; ++ gc_span_t *stack; ++} gc_span_stack_t; ++ ++typedef struct { ++ unsigned int in; ++ unsigned int out; ++ _PyObjectStack stack; ++ gc_span_stack_t spans; ++ PyObject *buffer[BUFFER_SIZE]; ++ bool use_prefetch; ++} gc_mark_args_t; ++ ++ ++// Returns number of entries in buffer ++static inline unsigned int ++gc_mark_buffer_len(gc_mark_args_t *args) ++{ ++ return args->in - args->out; ++} ++ ++// Returns number of free entry slots in buffer ++static inline unsigned int ++gc_mark_buffer_avail(gc_mark_args_t *args) ++{ ++ return BUFFER_SIZE - gc_mark_buffer_len(args); ++} ++ ++static inline bool ++gc_mark_buffer_is_empty(gc_mark_args_t *args) ++{ ++ return args->in == args->out; ++} ++ ++static inline bool ++gc_mark_buffer_is_full(gc_mark_args_t *args) ++{ ++ return gc_mark_buffer_len(args) == BUFFER_SIZE; ++} ++ ++static inline PyObject * ++gc_mark_buffer_pop(gc_mark_args_t *args) ++{ ++ assert(!gc_mark_buffer_is_empty(args)); ++ PyObject *op = args->buffer[args->out & BUFFER_MASK]; ++ args->out++; ++ return op; ++} ++ ++// Called when there is space in the buffer for the object. Issue the ++// prefetch instruction and add it to the end of the buffer. ++static inline void ++gc_mark_buffer_push(PyObject *op, gc_mark_args_t *args) ++{ ++ assert(!gc_mark_buffer_is_full(args)); ++ prefetch(op); ++ args->buffer[args->in & BUFFER_MASK] = op; ++ args->in++; ++} ++ ++// Called when we run out of space in the buffer or if the prefetching ++// is disabled. The object will be pushed on the gc_mark_args.stack. ++static int ++gc_mark_stack_push(_PyObjectStack *ms, PyObject *op) ++{ ++ if (_PyObjectStack_Push(ms, op) < 0) { ++ return -1; ++ } ++ return 0; ++} ++ ++static int ++gc_mark_span_push(gc_span_stack_t *ss, PyObject **start, PyObject **end) ++{ ++ if (start == end) { ++ return 0; ++ } ++ if (ss->size >= ss->capacity) { ++ if (ss->capacity == 0) { ++ ss->capacity = 256; ++ } ++ else { ++ ss->capacity *= 2; ++ } ++ ss->stack = (gc_span_t *)PyMem_Realloc(ss->stack, ss->capacity * sizeof(gc_span_t)); ++ if (ss->stack == NULL) { ++ return -1; ++ } ++ } ++ assert(end > start); ++ ss->stack[ss->size].start = start; ++ ss->stack[ss->size].end = end; ++ ss->size++; ++ return 0; ++} ++ ++static int ++gc_mark_enqueue_no_buffer(PyObject *op, gc_mark_args_t *args) ++{ ++ if (op == NULL) { ++ return 0; ++ } ++ if (!gc_has_bit(op, _PyGC_BITS_TRACKED)) { ++ return 0; ++ } ++ if (gc_is_alive(op)) { ++ return 0; // already visited this object ++ } ++ if (gc_maybe_untrack(op)) { ++ return 0; // was untracked, don't visit it ++ } ++ ++ // Need to call tp_traverse on this object. Add to stack and mark it ++ // alive so we don't traverse it a second time. ++ gc_set_alive(op); ++ if (_PyObjectStack_Push(&args->stack, op) < 0) { ++ return -1; ++ } ++ return 0; ++} ++ ++static int ++gc_mark_enqueue_buffer(PyObject *op, gc_mark_args_t *args) ++{ ++ assert(op != NULL); ++ if (!gc_mark_buffer_is_full(args)) { ++ gc_mark_buffer_push(op, args); ++ return 0; ++ } ++ else { ++ return gc_mark_stack_push(&args->stack, op); ++ } ++} ++ ++// Called when we find an object that needs to be marked alive (either from a ++// root or from calling tp_traverse). ++static int ++gc_mark_enqueue(PyObject *op, gc_mark_args_t *args) ++{ ++ if (args->use_prefetch) { ++ return gc_mark_enqueue_buffer(op, args); ++ } ++ else { ++ return gc_mark_enqueue_no_buffer(op, args); ++ } ++} ++ ++// Called when we have a contigous sequence of PyObject pointers, either ++// a tuple or list object. This will add the items to the buffer if there ++// is space for them all otherwise push a new "span" on the span stack. Using ++// spans has the advantage of not creating a deep _PyObjectStack stack when ++// dealing with long sequences. Those sequences will be processed in smaller ++// chunks by the gc_prime_from_spans() function. ++static int ++gc_mark_enqueue_span(PyObject **item, Py_ssize_t size, gc_mark_args_t *args) ++{ ++ Py_ssize_t used = gc_mark_buffer_len(args); ++ Py_ssize_t free = BUFFER_SIZE - used; ++ if (free >= size) { ++ for (Py_ssize_t i = 0; i < size; i++) { ++ PyObject *op = item[i]; ++ if (op == NULL) { ++ continue; ++ } ++ gc_mark_buffer_push(op, args); ++ } ++ } ++ else { ++ assert(size > 0); ++ PyObject **end = &item[size]; ++ if (gc_mark_span_push(&args->spans, item, end) < 0) { ++ return -1; ++ } ++ } ++ return 0; ++} ++ ++static bool ++gc_clear_alive_bits(const mi_heap_t *heap, const mi_heap_area_t *area, ++ void *block, size_t block_size, void *args) ++{ ++ PyObject *op = op_from_block(block, args, false); ++ if (op == NULL) { ++ return true; ++ } ++ if (gc_is_alive(op)) { ++ gc_clear_alive(op); ++ } ++ return true; ++} ++ ++static int ++gc_mark_traverse_list(PyObject *self, void *args) ++{ ++ PyListObject *list = (PyListObject *)self; ++ if (list->ob_item == NULL) { ++ return 0; ++ } ++ if (gc_mark_enqueue_span(list->ob_item, PyList_GET_SIZE(list), args) < 0) { ++ return -1; ++ } ++ return 0; ++} ++ ++static int ++gc_mark_traverse_tuple(PyObject *self, void *args) ++{ ++ _PyTuple_MaybeUntrack(self); ++ if (!gc_has_bit(self, _PyGC_BITS_TRACKED)) { ++ gc_clear_alive(self); ++ return 0; ++ } ++ PyTupleObject *tuple = _PyTuple_CAST(self); ++ if (gc_mark_enqueue_span(tuple->ob_item, Py_SIZE(tuple), args) < 0) { ++ return -1; ++ } ++ return 0; ++} ++ ++static void ++gc_abort_mark_alive(PyInterpreterState *interp, ++ struct collection_state *state, ++ gc_mark_args_t *args) ++{ ++ // We failed to allocate memory while doing the "mark alive" phase. ++ // In that case, free the memory used for marking state and make ++ // sure that no objects have the alive bit set. ++ _PyObjectStack_Clear(&args->stack); ++ if (args->spans.stack != NULL) { ++ PyMem_Free(args->spans.stack); ++ } ++ gc_visit_heaps(interp, &gc_clear_alive_bits, &state->base); ++} ++ ++#ifdef GC_MARK_ALIVE_STACKS ++static int ++gc_visit_stackref_mark_alive(gc_mark_args_t *args, _PyStackRef stackref) ++{ ++ if (!PyStackRef_IsNull(stackref)) { ++ PyObject *op = PyStackRef_AsPyObjectBorrow(stackref); ++ if (gc_mark_enqueue(op, args) < 0) { ++ return -1; ++ } ++ } ++ return 0; ++} ++ ++static int ++gc_visit_thread_stacks_mark_alive(PyInterpreterState *interp, gc_mark_args_t *args) ++{ ++ int err = 0; ++ _Py_FOR_EACH_TSTATE_BEGIN(interp, p) { ++ for (_PyInterpreterFrame *f = p->current_frame; f != NULL; f = f->previous) { ++ if (f->owner >= FRAME_OWNED_BY_INTERPRETER) { ++ continue; ++ } ++ ++ if (f->stackpointer == NULL) { ++ // GH-129236: The stackpointer may be NULL in cases where ++ // the GC is run during a PyStackRef_CLOSE() call. Skip this ++ // frame for now. ++ continue; ++ } ++ ++ _PyStackRef *top = f->stackpointer; ++ if (gc_visit_stackref_mark_alive(args, f->f_executable) < 0) { ++ err = -1; ++ goto exit; ++ } ++ while (top != f->localsplus) { ++ --top; ++ if (gc_visit_stackref_mark_alive(args, *top) < 0) { ++ err = -1; ++ goto exit; ++ } + } + } + } ++exit: + _Py_FOR_EACH_TSTATE_END(interp); ++ return err; + } ++#endif // GC_MARK_ALIVE_STACKS ++#endif // GC_ENABLE_MARK_ALIVE + + static void + queue_untracked_obj_decref(PyObject *op, struct collection_state *state) +@@ -460,7 +912,8 @@ + { + if (_PyObject_GC_IS_TRACKED(op) + && !_Py_IsImmortal(op) +- && !gc_is_frozen(op)) ++ && !gc_is_frozen(op) ++ && !gc_is_alive(op)) + { + // If update_refs hasn't reached this object yet, mark it + // as (tentatively) unreachable and initialize ob_tid to zero. +@@ -482,6 +935,10 @@ + return true; + } + ++ if (gc_is_alive(op)) { ++ return true; ++ } ++ + // Exclude immortal objects from garbage collection + if (_Py_IsImmortal(op)) { + op->ob_tid = 0; +@@ -497,14 +954,9 @@ + _PyObject_ASSERT(op, refcount >= 0); + + if (refcount > 0 && !_PyObject_HasDeferredRefcount(op)) { +- // Untrack tuples and dicts as necessary in this pass, but not objects +- // with zero refcount, which we will want to collect. +- if (PyTuple_CheckExact(op)) { +- _PyTuple_MaybeUntrack(op); +- if (!_PyObject_GC_IS_TRACKED(op)) { +- gc_restore_refs(op); +- return true; +- } ++ if (gc_maybe_untrack(op)) { ++ gc_restore_refs(op); ++ return true; + } + } + +@@ -553,6 +1005,21 @@ + } + + #ifdef GC_DEBUG ++static bool ++validate_alive_bits(const mi_heap_t *heap, const mi_heap_area_t *area, ++ void *block, size_t block_size, void *args) ++{ ++ PyObject *op = op_from_block(block, args, false); ++ if (op == NULL) { ++ return true; ++ } ++ ++ _PyObject_ASSERT_WITH_MSG(op, !gc_is_alive(op), ++ "object should not be marked as alive yet"); ++ ++ return true; ++} ++ + static bool + validate_refcounts(const mi_heap_t *heap, const mi_heap_area_t *area, + void *block, size_t block_size, void *args) +@@ -586,6 +1053,11 @@ + return true; + } + ++ if (gc_is_alive(op)) { ++ _PyObject_ASSERT(op, !gc_is_unreachable(op)); ++ return true; ++ } ++ + _PyObject_ASSERT(op, gc_is_unreachable(op)); + _PyObject_ASSERT_WITH_MSG(op, gc_get_refs(op) >= 0, + "refcount is too small"); +@@ -605,7 +1077,20 @@ + _PyObject_ASSERT_WITH_MSG(op, gc_get_refs(op) >= 0, + "refcount is too small"); + +- if (gc_is_unreachable(op) && gc_get_refs(op) != 0) { ++ if (gc_is_alive(op) || !gc_is_unreachable(op)) { ++ // Object was already marked as reachable. ++ return true; ++ } ++ ++ // GH-129236: If we've seen an active frame without a valid stack pointer, ++ // then we can't collect objects with deferred references because we may ++ // have missed some reference to the object on the stack. In that case, ++ // treat the object as reachable even if gc_refs is zero. ++ struct collection_state *state = (struct collection_state *)args; ++ int keep_alive = (state->skip_deferred_objects && ++ _PyObject_HasDeferredRefcount(op)); ++ ++ if (gc_get_refs(op) != 0 || keep_alive) { + // Object is reachable but currently marked as unreachable. + // Mark it as reachable and traverse its pointers to find + // any other object that may be directly reachable from it. +@@ -630,6 +1115,7 @@ + } + gc_restore_tid(op); + gc_clear_unreachable(op); ++ gc_clear_alive(op); + return true; + } + +@@ -679,6 +1165,7 @@ + + // object is reachable, restore `ob_tid`; we're done with these objects + gc_restore_tid(op); ++ gc_clear_alive(op); + state->long_lived_total++; + return true; + } +@@ -686,6 +1173,207 @@ + static int + move_legacy_finalizer_reachable(struct collection_state *state); + ++#ifdef GC_ENABLE_MARK_ALIVE ++ ++static void ++gc_prime_from_spans(gc_mark_args_t *args) ++{ ++ Py_ssize_t space = BUFFER_HI - gc_mark_buffer_len(args); ++ // there should always be at least this amount of space ++ assert(space <= gc_mark_buffer_avail(args)); ++ assert(space > 0); ++ gc_span_t entry = args->spans.stack[--args->spans.size]; ++ // spans on the stack should always have one or more elements ++ assert(entry.start < entry.end); ++ do { ++ PyObject *op = *entry.start; ++ entry.start++; ++ if (op != NULL) { ++ gc_mark_buffer_push(op, args); ++ space--; ++ if (space == 0) { ++ // buffer is as full as we want and not done with span ++ gc_mark_span_push(&args->spans, entry.start, entry.end); ++ return; ++ } ++ } ++ } while (entry.start < entry.end); ++} ++ ++static void ++gc_prime_buffer(gc_mark_args_t *args) ++{ ++ if (args->spans.size > 0) { ++ gc_prime_from_spans(args); ++ } ++ else { ++ // When priming, don't fill the buffer too full since that would ++ // likely cause the stack to be used shortly after when it ++ // fills. We want to use the buffer as much as possible and so ++ // we only fill to BUFFER_HI, not BUFFER_SIZE. ++ Py_ssize_t space = BUFFER_HI - gc_mark_buffer_len(args); ++ assert(space > 0); ++ do { ++ PyObject *op = _PyObjectStack_Pop(&args->stack); ++ if (op == NULL) { ++ return; ++ } ++ gc_mark_buffer_push(op, args); ++ space--; ++ } while (space > 0); ++ } ++} ++ ++static int ++gc_propagate_alive_prefetch(gc_mark_args_t *args) ++{ ++ for (;;) { ++ Py_ssize_t buf_used = gc_mark_buffer_len(args); ++ if (buf_used <= BUFFER_LO) { ++ // The mark buffer is getting empty. If it's too empty ++ // then there will not be enough delay between issuing ++ // the prefetch and when the object is actually accessed. ++ // Prime the buffer with object pointers from the stack or ++ // from the spans, if there are any available. ++ gc_prime_buffer(args); ++ if (gc_mark_buffer_is_empty(args)) { ++ return 0; ++ } ++ } ++ PyObject *op = gc_mark_buffer_pop(args); ++ ++ if (!gc_has_bit(op, _PyGC_BITS_TRACKED)) { ++ continue; ++ } ++ ++ if (gc_is_alive(op)) { ++ continue; // already visited this object ++ } ++ ++ // Need to call tp_traverse on this object. Mark it alive so we ++ // don't traverse it a second time. ++ gc_set_alive(op); ++ ++ traverseproc traverse = Py_TYPE(op)->tp_traverse; ++ if (traverse == PyList_Type.tp_traverse) { ++ if (gc_mark_traverse_list(op, args) < 0) { ++ return -1; ++ } ++ } ++ else if (traverse == PyTuple_Type.tp_traverse) { ++ if (gc_mark_traverse_tuple(op, args) < 0) { ++ return -1; ++ } ++ } ++ else if (traverse(op, (visitproc)&gc_mark_enqueue_buffer, args) < 0) { ++ return -1; ++ } ++ } ++} ++ ++static int ++gc_propagate_alive(gc_mark_args_t *args) ++{ ++ if (args->use_prefetch) { ++ return gc_propagate_alive_prefetch(args); ++ } ++ else { ++ for (;;) { ++ PyObject *op = _PyObjectStack_Pop(&args->stack); ++ if (op == NULL) { ++ break; ++ } ++ assert(_PyObject_GC_IS_TRACKED(op)); ++ assert(gc_is_alive(op)); ++ traverseproc traverse = Py_TYPE(op)->tp_traverse; ++ if (traverse(op, (visitproc)&gc_mark_enqueue_no_buffer, args) < 0) { ++ return -1; ++ } ++ } ++ return 0; ++ } ++} ++ ++// Using tp_traverse, mark everything reachable from known root objects ++// (which must be non-garbage) as alive (_PyGC_BITS_ALIVE is set). In ++// most programs, this marks nearly all objects that are not actually ++// unreachable. ++// ++// Actually alive objects can be missed in this pass if they are alive ++// due to being referenced from an unknown root (e.g. an extension ++// module global), some tp_traverse methods are either missing or not ++// accurate, or objects that have been untracked. Objects that are only ++// reachable from the aforementioned are also missed. ++// ++// If gc.freeze() is used, this pass is disabled since it is unlikely to ++// help much. The next stages of cyclic GC will ignore objects with the ++// alive bit set. ++// ++// Returns -1 on failure (out of memory). ++static int ++gc_mark_alive_from_roots(PyInterpreterState *interp, ++ struct collection_state *state) ++{ ++#ifdef GC_DEBUG ++ // Check that all objects don't have alive bit set ++ gc_visit_heaps(interp, &validate_alive_bits, &state->base); ++#endif ++ gc_mark_args_t mark_args = { 0 }; ++ ++ // Using prefetch instructions is only a win if the set of objects being ++ // examined by the GC does not fit into CPU caches. Otherwise, using the ++ // buffer and prefetch instructions is just overhead. Using the long lived ++ // object count seems a good estimate of if things will fit in the cache. ++ // On 64-bit platforms, the minimum object size is 32 bytes. A 4MB L2 cache ++ // would hold about 130k objects. ++ mark_args.use_prefetch = interp->gc.long_lived_total > 200000; ++ ++ #define MARK_ENQUEUE(op) \ ++ if (op != NULL ) { \ ++ if (gc_mark_enqueue(op, &mark_args) < 0) { \ ++ gc_abort_mark_alive(interp, state, &mark_args); \ ++ return -1; \ ++ } \ ++ } ++ MARK_ENQUEUE(interp->sysdict); ++#ifdef GC_MARK_ALIVE_EXTRA_ROOTS ++ MARK_ENQUEUE(interp->builtins); ++ MARK_ENQUEUE(interp->dict); ++ struct types_state *types = &interp->types; ++ for (int i = 0; i < _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES; i++) { ++ MARK_ENQUEUE(types->builtins.initialized[i].tp_dict); ++ MARK_ENQUEUE(types->builtins.initialized[i].tp_subclasses); ++ } ++ for (int i = 0; i < _Py_MAX_MANAGED_STATIC_EXT_TYPES; i++) { ++ MARK_ENQUEUE(types->for_extensions.initialized[i].tp_dict); ++ MARK_ENQUEUE(types->for_extensions.initialized[i].tp_subclasses); ++ } ++#endif ++#ifdef GC_MARK_ALIVE_STACKS ++ if (gc_visit_thread_stacks_mark_alive(interp, &mark_args) < 0) { ++ gc_abort_mark_alive(interp, state, &mark_args); ++ return -1; ++ } ++#endif ++ #undef MARK_ENQUEUE ++ ++ // Use tp_traverse to find everything reachable from roots. ++ if (gc_propagate_alive(&mark_args) < 0) { ++ gc_abort_mark_alive(interp, state, &mark_args); ++ return -1; ++ } ++ ++ assert(mark_args.spans.size == 0); ++ if (mark_args.spans.stack != NULL) { ++ PyMem_Free(mark_args.spans.stack); ++ } ++ assert(mark_args.stack.head == NULL); ++ ++ return 0; ++} ++#endif // GC_ENABLE_MARK_ALIVE ++ ++ + static int + deduce_unreachable_heap(PyInterpreterState *interp, + struct collection_state *state) +@@ -709,7 +1397,7 @@ + #endif + + // Visit the thread stacks to account for any deferred references. +- gc_visit_thread_stacks(interp); ++ gc_visit_thread_stacks(interp, state); + + // Transitively mark reachable objects by clearing the + // _PyGC_BITS_UNREACHABLE flag. +@@ -828,7 +1516,8 @@ + /* copy-paste of weakrefobject.c's handle_callback() */ + PyObject *temp = PyObject_CallOneArg(callback, (PyObject *)wr); + if (temp == NULL) { +- PyErr_WriteUnraisable(callback); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "calling weakref callback %R", callback); + } + else { + Py_DECREF(temp); +@@ -1127,7 +1816,8 @@ + "collected", collected, + "uncollectable", uncollectable); + if (info == NULL) { +- PyErr_FormatUnraisable("Exception ignored on invoking gc callbacks"); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "invoking gc callbacks"); + return; + } + } +@@ -1135,7 +1825,8 @@ + PyObject *phase_obj = PyUnicode_FromString(phase); + if (phase_obj == NULL) { + Py_XDECREF(info); +- PyErr_FormatUnraisable("Exception ignored on invoking gc callbacks"); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "invoking gc callbacks"); + return; + } + +@@ -1145,7 +1836,8 @@ + Py_INCREF(cb); /* make sure cb doesn't go away */ + r = PyObject_Vectorcall(cb, stack, 2, NULL); + if (r == NULL) { +- PyErr_WriteUnraisable(cb); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "calling GC callback %R", cb); + } + else { + Py_DECREF(r); +@@ -1172,7 +1864,8 @@ + { + int count = _Py_atomic_load_int_relaxed(&gcstate->young.count); + int threshold = gcstate->young.threshold; +- if (count <= threshold || threshold == 0 || !gcstate->enabled) { ++ int gc_enabled = _Py_atomic_load_int_relaxed(&gcstate->enabled); ++ if (count <= threshold || threshold == 0 || !gc_enabled) { + return false; + } + // Avoid quadratic behavior by scaling threshold to the number of live +@@ -1245,6 +1938,25 @@ + + process_delayed_frees(interp, state); + ++ #ifdef GC_ENABLE_MARK_ALIVE ++ // If gc.freeze() was used, it seems likely that doing this "mark alive" ++ // pass will not be a performance win. Typically the majority of alive ++ // objects will be marked as frozen and will be skipped anyhow, without ++ // doing this extra work. Doing this pass also defeats one of the ++ // purposes of using freeze: avoiding writes to objects that are frozen. ++ // So, we just skip this if gc.freeze() was used. ++ if (!state->gcstate->freeze_active) { ++ // Mark objects reachable from known roots as "alive". These will ++ // be ignored for rest of the GC pass. ++ int err = gc_mark_alive_from_roots(interp, state); ++ if (err < 0) { ++ _PyEval_StartTheWorld(interp); ++ PyErr_NoMemory(); ++ return; ++ } ++ } ++ #endif ++ + // Find unreachable objects + int err = deduce_unreachable_heap(interp, state); + if (err < 0) { +@@ -1253,6 +1965,11 @@ + return; + } + ++#ifdef GC_DEBUG ++ // At this point, no object should have the alive bit set ++ gc_visit_heaps(interp, &validate_alive_bits, &state->base); ++#endif ++ + // Print debugging information. + if (interp->gc.debug & _PyGC_DEBUG_COLLECTABLE) { + PyObject *op; +@@ -1564,6 +2281,8 @@ + { + struct visitor_args args; + _PyEval_StopTheWorld(interp); ++ GCState *gcstate = get_gc_state(); ++ gcstate->freeze_active = true; + gc_visit_heaps(interp, &visit_freeze, &args); + _PyEval_StartTheWorld(interp); + } +@@ -1574,7 +2293,7 @@ + { + PyObject *op = op_from_block(block, args, true); + if (op != NULL) { +- op->ob_gc_bits &= ~_PyGC_BITS_FROZEN; ++ gc_clear_bit(op, _PyGC_BITS_FROZEN); + } + return true; + } +@@ -1584,6 +2303,8 @@ + { + struct visitor_args args; + _PyEval_StopTheWorld(interp); ++ GCState *gcstate = get_gc_state(); ++ gcstate->freeze_active = false; + gc_visit_heaps(interp, &visit_unfreeze, &args); + _PyEval_StartTheWorld(interp); + } +@@ -1620,25 +2341,21 @@ + PyGC_Enable(void) + { + GCState *gcstate = get_gc_state(); +- int old_state = gcstate->enabled; +- gcstate->enabled = 1; +- return old_state; ++ return _Py_atomic_exchange_int(&gcstate->enabled, 1); + } + + int + PyGC_Disable(void) + { + GCState *gcstate = get_gc_state(); +- int old_state = gcstate->enabled; +- gcstate->enabled = 0; +- return old_state; ++ return _Py_atomic_exchange_int(&gcstate->enabled, 0); + } + + int + PyGC_IsEnabled(void) + { + GCState *gcstate = get_gc_state(); +- return gcstate->enabled; ++ return _Py_atomic_load_int_relaxed(&gcstate->enabled); + } + + /* Public API to invoke gc.collect() from C */ +@@ -1648,7 +2365,7 @@ + PyThreadState *tstate = _PyThreadState_GET(); + GCState *gcstate = &tstate->interp->gc; + +- if (!gcstate->enabled) { ++ if (!_Py_atomic_load_int_relaxed(&gcstate->enabled)) { + return 0; + } + +@@ -1699,13 +2416,14 @@ + "gc", NULL, message, + PyList_GET_SIZE(gcstate->garbage))) + { +- PyErr_WriteUnraisable(NULL); ++ PyErr_FormatUnraisable("Exception ignored in GC shutdown"); + } + if (gcstate->debug & _PyGC_DEBUG_UNCOLLECTABLE) { + PyObject *repr = NULL, *bytes = NULL; + repr = PyObject_Repr(gcstate->garbage); + if (!repr || !(bytes = PyUnicode_EncodeFSDefault(repr))) { +- PyErr_WriteUnraisable(gcstate->garbage); ++ PyErr_FormatUnraisable("Exception ignored in GC shutdown " ++ "while formatting garbage"); + } + else { + PySys_WriteStderr( +@@ -1806,8 +2524,7 @@ + void + _Py_RunGC(PyThreadState *tstate) + { +- GCState *gcstate = get_gc_state(); +- if (!gcstate->enabled) { ++ if (!PyGC_IsEnabled()) { + return; + } + gc_collect_main(tstate, 0, _Py_GC_REASON_HEAP); +@@ -1913,9 +2630,12 @@ + #ifdef Py_DEBUG + PyObject *exc = PyErr_GetRaisedException(); + if (PyErr_WarnExplicitFormat(PyExc_ResourceWarning, "gc", 0, +- "gc", NULL, "Object of type %s is not untracked before destruction", +- ((PyObject*)op)->ob_type->tp_name)) { +- PyErr_WriteUnraisable(NULL); ++ "gc", NULL, ++ "Object of type %s is not untracked " ++ "before destruction", ++ Py_TYPE(op)->tp_name)) ++ { ++ PyErr_FormatUnraisable("Exception ignored on object deallocation"); + } + PyErr_SetRaisedException(exc); + #endif +diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h +index 94343f95322..f02e13f5e3f 100644 +--- a/Python/generated_cases.c.h ++++ b/Python/generated_cases.c.h +@@ -8,13 +8,26 @@ + #endif + #define TIER_ONE 1 + ++#ifndef Py_TAIL_CALL_INTERP ++#if !USE_COMPUTED_GOTOS ++ dispatch_opcode: ++ switch (opcode) ++#endif ++ { ++#endif /* Py_TAIL_CALL_INTERP */ ++ /* BEGIN INSTRUCTIONS */ ++ + + TARGET(BINARY_OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = BINARY_OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; +- next_instr += 2; ++ next_instr += 6; + INSTRUCTION_STATS(BINARY_OP); +- PREDICTED(BINARY_OP); +- _Py_CODEUNIT* const this_instr = next_instr - 2; ++ PREDICTED_BINARY_OP:; ++ _Py_CODEUNIT* const this_instr = next_instr - 6; + (void)this_instr; + _PyStackRef lhs; + _PyStackRef rhs; +@@ -37,8 +50,9 @@ + ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); + #endif /* ENABLE_SPECIALIZATION_FT */ + assert(NB_ADD <= oparg); +- assert(oparg <= NB_INPLACE_XOR); ++ assert(oparg <= NB_OPARG_LAST); + } ++ /* Skip 4 cache entries */ + // _BINARY_OP + { + PyObject *lhs_o = PyStackRef_AsPyObjectBorrow(lhs); +@@ -49,7 +63,9 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(lhs); + PyStackRef_CLOSE(rhs); +- if (res_o == NULL) goto pop_2_error; ++ if (res_o == NULL) { ++ JUMP_TO_LABEL(pop_2_error); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + } + stack_pointer[-2] = res; +@@ -59,10 +75,16 @@ + } + + TARGET(BINARY_OP_ADD_FLOAT) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = BINARY_OP_ADD_FLOAT; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; +- next_instr += 2; ++ next_instr += 6; + INSTRUCTION_STATS(BINARY_OP_ADD_FLOAT); +- static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); ++ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); + _PyStackRef left; + _PyStackRef right; + _PyStackRef res; +@@ -72,20 +94,32 @@ + left = stack_pointer[-2]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); +- DEOPT_IF(!PyFloat_CheckExact(left_o), BINARY_OP); +- DEOPT_IF(!PyFloat_CheckExact(right_o), BINARY_OP); ++ if (!PyFloat_CheckExact(left_o)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } ++ if (!PyFloat_CheckExact(right_o)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } + } +- /* Skip 1 cache entry */ ++ /* Skip 5 cache entries */ + // _BINARY_OP_ADD_FLOAT + { + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(PyFloat_CheckExact(left_o)); ++ assert(PyFloat_CheckExact(right_o)); + STAT_INC(BINARY_OP, hit); + double dres = + ((PyFloatObject *)left_o)->ob_fval + + ((PyFloatObject *)right_o)->ob_fval; + PyObject *res_o = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); +- if (res_o == NULL) goto pop_2_error; ++ if (res_o == NULL) { ++ JUMP_TO_LABEL(pop_2_error); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + } + stack_pointer[-2] = res; +@@ -95,10 +129,16 @@ + } + + TARGET(BINARY_OP_ADD_INT) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = BINARY_OP_ADD_INT; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; +- next_instr += 2; ++ next_instr += 6; + INSTRUCTION_STATS(BINARY_OP_ADD_INT); +- static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); ++ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); + _PyStackRef left; + _PyStackRef right; + _PyStackRef res; +@@ -108,19 +148,31 @@ + left = stack_pointer[-2]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); +- DEOPT_IF(!PyLong_CheckExact(left_o), BINARY_OP); +- DEOPT_IF(!PyLong_CheckExact(right_o), BINARY_OP); ++ if (!PyLong_CheckExact(left_o)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } ++ if (!PyLong_CheckExact(right_o)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } + } +- /* Skip 1 cache entry */ ++ /* Skip 5 cache entries */ + // _BINARY_OP_ADD_INT + { + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(PyLong_CheckExact(left_o)); ++ assert(PyLong_CheckExact(right_o)); + STAT_INC(BINARY_OP, hit); + PyObject *res_o = _PyLong_Add((PyLongObject *)left_o, (PyLongObject *)right_o); + PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); +- if (res_o == NULL) goto pop_2_error; ++ if (res_o == NULL) { ++ JUMP_TO_LABEL(pop_2_error); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + } + stack_pointer[-2] = res; +@@ -130,10 +182,16 @@ + } + + TARGET(BINARY_OP_ADD_UNICODE) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = BINARY_OP_ADD_UNICODE; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; +- next_instr += 2; ++ next_instr += 6; + INSTRUCTION_STATS(BINARY_OP_ADD_UNICODE); +- static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); ++ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); + _PyStackRef left; + _PyStackRef right; + _PyStackRef res; +@@ -143,19 +201,87 @@ + left = stack_pointer[-2]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); +- DEOPT_IF(!PyUnicode_CheckExact(left_o), BINARY_OP); +- DEOPT_IF(!PyUnicode_CheckExact(right_o), BINARY_OP); ++ if (!PyUnicode_CheckExact(left_o)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } ++ if (!PyUnicode_CheckExact(right_o)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } + } +- /* Skip 1 cache entry */ ++ /* Skip 5 cache entries */ + // _BINARY_OP_ADD_UNICODE + { + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(PyUnicode_CheckExact(left_o)); ++ assert(PyUnicode_CheckExact(right_o)); + STAT_INC(BINARY_OP, hit); + PyObject *res_o = PyUnicode_Concat(left_o, right_o); +- PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); +- if (res_o == NULL) goto pop_2_error; ++ PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); ++ if (res_o == NULL) { ++ JUMP_TO_LABEL(pop_2_error); ++ } ++ res = PyStackRef_FromPyObjectSteal(res_o); ++ } ++ stack_pointer[-2] = res; ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ DISPATCH(); ++ } ++ ++ TARGET(BINARY_OP_EXTEND) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = BINARY_OP_EXTEND; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; ++ next_instr += 6; ++ INSTRUCTION_STATS(BINARY_OP_EXTEND); ++ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); ++ _PyStackRef left; ++ _PyStackRef right; ++ _PyStackRef res; ++ /* Skip 1 cache entry */ ++ // _GUARD_BINARY_OP_EXTEND ++ { ++ right = stack_pointer[-1]; ++ left = stack_pointer[-2]; ++ PyObject *descr = read_obj(&this_instr[2].cache); ++ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); ++ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ _PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr; ++ assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5); ++ assert(d && d->guard); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ int res = d->guard(left_o, right_o); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (!res) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } ++ } ++ /* Skip -4 cache entry */ ++ // _BINARY_OP_EXTEND ++ { ++ PyObject *descr = read_obj(&this_instr[2].cache); ++ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); ++ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5); ++ _PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr; ++ STAT_INC(BINARY_OP, hit); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyObject *res_o = d->action(left_o, right_o); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ PyStackRef_CLOSE(left); ++ PyStackRef_CLOSE(right); + res = PyStackRef_FromPyObjectSteal(res_o); + } + stack_pointer[-2] = res; +@@ -165,10 +291,16 @@ + } + + TARGET(BINARY_OP_INPLACE_ADD_UNICODE) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = BINARY_OP_INPLACE_ADD_UNICODE; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; +- next_instr += 2; ++ next_instr += 6; + INSTRUCTION_STATS(BINARY_OP_INPLACE_ADD_UNICODE); +- static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); ++ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); + _PyStackRef left; + _PyStackRef right; + // _GUARD_BOTH_UNICODE +@@ -177,14 +309,24 @@ + left = stack_pointer[-2]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); +- DEOPT_IF(!PyUnicode_CheckExact(left_o), BINARY_OP); +- DEOPT_IF(!PyUnicode_CheckExact(right_o), BINARY_OP); ++ if (!PyUnicode_CheckExact(left_o)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } ++ if (!PyUnicode_CheckExact(right_o)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } + } +- /* Skip 1 cache entry */ ++ /* Skip 5 cache entries */ + // _BINARY_OP_INPLACE_ADD_UNICODE + { + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(PyUnicode_CheckExact(left_o)); ++ assert(PyUnicode_CheckExact(right_o)); + int next_oparg; + #if TIER_ONE + assert(next_instr->op.code == STORE_FAST); +@@ -193,7 +335,11 @@ + next_oparg = CURRENT_OPERAND0(); + #endif + _PyStackRef *target_local = &GETLOCAL(next_oparg); +- DEOPT_IF(PyStackRef_AsPyObjectBorrow(*target_local) != left_o, BINARY_OP); ++ if (PyStackRef_AsPyObjectBorrow(*target_local) != left_o) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } + STAT_INC(BINARY_OP, hit); + /* Handle `left = left + right` or `left += right` for str. + * +@@ -207,12 +353,14 @@ + * that the string is safe to mutate. + */ + assert(Py_REFCNT(left_o) >= 2); +- PyStackRef_CLOSE(left); +- PyObject *temp = PyStackRef_AsPyObjectBorrow(*target_local); ++ PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); ++ PyObject *temp = PyStackRef_AsPyObjectSteal(*target_local); + PyUnicode_Append(&temp, right_o); + *target_local = PyStackRef_FromPyObjectSteal(temp); + PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); +- if (PyStackRef_IsNull(*target_local)) goto pop_2_error; ++ if (PyStackRef_IsNull(*target_local)) { ++ JUMP_TO_LABEL(pop_2_error); ++ } + #if TIER_ONE + // The STORE_FAST is already done. This is done here in tier one, + // and during trace projection in tier two: +@@ -226,10 +374,16 @@ + } + + TARGET(BINARY_OP_MULTIPLY_FLOAT) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = BINARY_OP_MULTIPLY_FLOAT; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; +- next_instr += 2; ++ next_instr += 6; + INSTRUCTION_STATS(BINARY_OP_MULTIPLY_FLOAT); +- static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); ++ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); + _PyStackRef left; + _PyStackRef right; + _PyStackRef res; +@@ -239,20 +393,32 @@ + left = stack_pointer[-2]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); +- DEOPT_IF(!PyFloat_CheckExact(left_o), BINARY_OP); +- DEOPT_IF(!PyFloat_CheckExact(right_o), BINARY_OP); ++ if (!PyFloat_CheckExact(left_o)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } ++ if (!PyFloat_CheckExact(right_o)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } + } +- /* Skip 1 cache entry */ ++ /* Skip 5 cache entries */ + // _BINARY_OP_MULTIPLY_FLOAT + { + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(PyFloat_CheckExact(left_o)); ++ assert(PyFloat_CheckExact(right_o)); + STAT_INC(BINARY_OP, hit); + double dres = + ((PyFloatObject *)left_o)->ob_fval * + ((PyFloatObject *)right_o)->ob_fval; + PyObject *res_o = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); +- if (res_o == NULL) goto pop_2_error; ++ if (res_o == NULL) { ++ JUMP_TO_LABEL(pop_2_error); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + } + stack_pointer[-2] = res; +@@ -262,10 +428,16 @@ + } + + TARGET(BINARY_OP_MULTIPLY_INT) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = BINARY_OP_MULTIPLY_INT; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; +- next_instr += 2; ++ next_instr += 6; + INSTRUCTION_STATS(BINARY_OP_MULTIPLY_INT); +- static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); ++ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); + _PyStackRef left; + _PyStackRef right; + _PyStackRef res; +@@ -275,187 +447,31 @@ + left = stack_pointer[-2]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); +- DEOPT_IF(!PyLong_CheckExact(left_o), BINARY_OP); +- DEOPT_IF(!PyLong_CheckExact(right_o), BINARY_OP); ++ if (!PyLong_CheckExact(left_o)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } ++ if (!PyLong_CheckExact(right_o)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } + } +- /* Skip 1 cache entry */ ++ /* Skip 5 cache entries */ + // _BINARY_OP_MULTIPLY_INT + { + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(PyLong_CheckExact(left_o)); ++ assert(PyLong_CheckExact(right_o)); + STAT_INC(BINARY_OP, hit); + PyObject *res_o = _PyLong_Multiply((PyLongObject *)left_o, (PyLongObject *)right_o); + PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); + PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); +- if (res_o == NULL) goto pop_2_error; +- res = PyStackRef_FromPyObjectSteal(res_o); +- } +- stack_pointer[-2] = res; +- stack_pointer += -1; +- assert(WITHIN_STACK_BOUNDS()); +- DISPATCH(); +- } +- +- TARGET(BINARY_OP_SUBTRACT_FLOAT) { +- frame->instr_ptr = next_instr; +- next_instr += 2; +- INSTRUCTION_STATS(BINARY_OP_SUBTRACT_FLOAT); +- static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); +- _PyStackRef left; +- _PyStackRef right; +- _PyStackRef res; +- // _GUARD_BOTH_FLOAT +- { +- right = stack_pointer[-1]; +- left = stack_pointer[-2]; +- PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); +- PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); +- DEOPT_IF(!PyFloat_CheckExact(left_o), BINARY_OP); +- DEOPT_IF(!PyFloat_CheckExact(right_o), BINARY_OP); +- } +- /* Skip 1 cache entry */ +- // _BINARY_OP_SUBTRACT_FLOAT +- { +- PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); +- PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); +- STAT_INC(BINARY_OP, hit); +- double dres = +- ((PyFloatObject *)left_o)->ob_fval - +- ((PyFloatObject *)right_o)->ob_fval; +- PyObject *res_o = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); +- if (res_o == NULL) goto pop_2_error; +- res = PyStackRef_FromPyObjectSteal(res_o); +- } +- stack_pointer[-2] = res; +- stack_pointer += -1; +- assert(WITHIN_STACK_BOUNDS()); +- DISPATCH(); +- } +- +- TARGET(BINARY_OP_SUBTRACT_INT) { +- frame->instr_ptr = next_instr; +- next_instr += 2; +- INSTRUCTION_STATS(BINARY_OP_SUBTRACT_INT); +- static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); +- _PyStackRef left; +- _PyStackRef right; +- _PyStackRef res; +- // _GUARD_BOTH_INT +- { +- right = stack_pointer[-1]; +- left = stack_pointer[-2]; +- PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); +- PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); +- DEOPT_IF(!PyLong_CheckExact(left_o), BINARY_OP); +- DEOPT_IF(!PyLong_CheckExact(right_o), BINARY_OP); +- } +- /* Skip 1 cache entry */ +- // _BINARY_OP_SUBTRACT_INT +- { +- PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); +- PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); +- STAT_INC(BINARY_OP, hit); +- PyObject *res_o = _PyLong_Subtract((PyLongObject *)left_o, (PyLongObject *)right_o); +- PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); +- PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); +- if (res_o == NULL) goto pop_2_error; +- res = PyStackRef_FromPyObjectSteal(res_o); +- } +- stack_pointer[-2] = res; +- stack_pointer += -1; +- assert(WITHIN_STACK_BOUNDS()); +- DISPATCH(); +- } +- +- TARGET(BINARY_SLICE) { +- frame->instr_ptr = next_instr; +- next_instr += 1; +- INSTRUCTION_STATS(BINARY_SLICE); +- _PyStackRef container; +- _PyStackRef start; +- _PyStackRef stop; +- _PyStackRef res; +- // _SPECIALIZE_BINARY_SLICE +- { +- // Placeholder until we implement BINARY_SLICE specialization +- #if ENABLE_SPECIALIZATION +- OPCODE_DEFERRED_INC(BINARY_SLICE); +- #endif /* ENABLE_SPECIALIZATION */ +- } +- // _BINARY_SLICE +- { +- stop = stack_pointer[-1]; +- start = stack_pointer[-2]; +- container = stack_pointer[-3]; +- _PyFrame_SetStackPointer(frame, stack_pointer); +- PyObject *slice = _PyBuildSlice_ConsumeRefs(PyStackRef_AsPyObjectSteal(start), +- PyStackRef_AsPyObjectSteal(stop)); +- stack_pointer = _PyFrame_GetStackPointer(frame); +- PyObject *res_o; +- // Can't use ERROR_IF() here, because we haven't +- // DECREF'ed container yet, and we still own slice. +- if (slice == NULL) { +- res_o = NULL; +- } +- else { +- stack_pointer += -2; +- assert(WITHIN_STACK_BOUNDS()); +- _PyFrame_SetStackPointer(frame, stack_pointer); +- res_o = PyObject_GetItem(PyStackRef_AsPyObjectBorrow(container), slice); +- stack_pointer = _PyFrame_GetStackPointer(frame); +- Py_DECREF(slice); +- stack_pointer += 2; +- assert(WITHIN_STACK_BOUNDS()); +- } +- PyStackRef_CLOSE(container); +- if (res_o == NULL) goto pop_3_error; +- res = PyStackRef_FromPyObjectSteal(res_o); +- } +- stack_pointer[-3] = res; +- stack_pointer += -2; +- assert(WITHIN_STACK_BOUNDS()); +- DISPATCH(); +- } +- +- TARGET(BINARY_SUBSCR) { +- frame->instr_ptr = next_instr; +- next_instr += 2; +- INSTRUCTION_STATS(BINARY_SUBSCR); +- PREDICTED(BINARY_SUBSCR); +- _Py_CODEUNIT* const this_instr = next_instr - 2; +- (void)this_instr; +- _PyStackRef container; +- _PyStackRef sub; +- _PyStackRef res; +- // _SPECIALIZE_BINARY_SUBSCR +- { +- sub = stack_pointer[-1]; +- container = stack_pointer[-2]; +- uint16_t counter = read_u16(&this_instr[1].cache); +- (void)counter; +- #if ENABLE_SPECIALIZATION_FT +- assert(frame->stackpointer == NULL); +- if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { +- next_instr = this_instr; +- _PyFrame_SetStackPointer(frame, stack_pointer); +- _Py_Specialize_BinarySubscr(container, sub, next_instr); +- stack_pointer = _PyFrame_GetStackPointer(frame); +- DISPATCH_SAME_OPARG(); ++ if (res_o == NULL) { ++ JUMP_TO_LABEL(pop_2_error); + } +- OPCODE_DEFERRED_INC(BINARY_SUBSCR); +- ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); +- #endif /* ENABLE_SPECIALIZATION_FT */ +- } +- // _BINARY_SUBSCR +- { +- PyObject *container_o = PyStackRef_AsPyObjectBorrow(container); +- PyObject *sub_o = PyStackRef_AsPyObjectBorrow(sub); +- _PyFrame_SetStackPointer(frame, stack_pointer); +- PyObject *res_o = PyObject_GetItem(container_o, sub_o); +- stack_pointer = _PyFrame_GetStackPointer(frame); +- PyStackRef_CLOSE(container); +- PyStackRef_CLOSE(sub); +- if (res_o == NULL) goto pop_2_error; + res = PyStackRef_FromPyObjectSteal(res_o); + } + stack_pointer[-2] = res; +@@ -464,21 +480,31 @@ + DISPATCH(); + } + +- TARGET(BINARY_SUBSCR_DICT) { ++ TARGET(BINARY_OP_SUBSCR_DICT) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = BINARY_OP_SUBSCR_DICT; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; +- next_instr += 2; +- INSTRUCTION_STATS(BINARY_SUBSCR_DICT); +- static_assert(INLINE_CACHE_ENTRIES_BINARY_SUBSCR == 1, "incorrect cache size"); ++ next_instr += 6; ++ INSTRUCTION_STATS(BINARY_OP_SUBSCR_DICT); ++ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); + _PyStackRef dict_st; + _PyStackRef sub_st; + _PyStackRef res; +- /* Skip 1 cache entry */ ++ /* Skip 5 cache entries */ + sub_st = stack_pointer[-1]; + dict_st = stack_pointer[-2]; + PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); + PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st); +- DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); +- STAT_INC(BINARY_SUBSCR, hit); ++ if (!PyDict_CheckExact(dict)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } ++ STAT_INC(BINARY_OP, hit); + PyObject *res_o; + _PyFrame_SetStackPointer(frame, stack_pointer); + int rc = PyDict_GetItemRef(dict, sub, &res_o); +@@ -490,7 +516,9 @@ + } + PyStackRef_CLOSE(dict_st); + PyStackRef_CLOSE(sub_st); +- if (rc <= 0) goto pop_2_error; ++ if (rc <= 0) { ++ JUMP_TO_LABEL(pop_2_error); ++ } + // not found or error + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-2] = res; +@@ -499,45 +527,70 @@ + DISPATCH(); + } + +- TARGET(BINARY_SUBSCR_GETITEM) { ++ TARGET(BINARY_OP_SUBSCR_GETITEM) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = BINARY_OP_SUBSCR_GETITEM; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; +- next_instr += 2; +- INSTRUCTION_STATS(BINARY_SUBSCR_GETITEM); +- static_assert(INLINE_CACHE_ENTRIES_BINARY_SUBSCR == 1, "incorrect cache size"); ++ next_instr += 6; ++ INSTRUCTION_STATS(BINARY_OP_SUBSCR_GETITEM); ++ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); + _PyStackRef container; ++ _PyStackRef getitem; + _PyStackRef sub; + _PyInterpreterFrame *new_frame; +- /* Skip 1 cache entry */ ++ /* Skip 5 cache entries */ + // _CHECK_PEP_523 + { +- DEOPT_IF(tstate->interp->eval_frame, BINARY_SUBSCR); ++ if (tstate->interp->eval_frame) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } + } +- // _BINARY_SUBSCR_CHECK_FUNC ++ // _BINARY_OP_SUBSCR_CHECK_FUNC + { + container = stack_pointer[-2]; + PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(container)); +- DEOPT_IF(!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), BINARY_SUBSCR); ++ if (!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } + PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; +- PyObject *getitem = ht->_spec_cache.getitem; +- DEOPT_IF(getitem == NULL, BINARY_SUBSCR); +- assert(PyFunction_Check(getitem)); +- uint32_t cached_version = ht->_spec_cache.getitem_version; +- DEOPT_IF(((PyFunctionObject *)getitem)->func_version != cached_version, BINARY_SUBSCR); +- PyCodeObject *code = (PyCodeObject *)PyFunction_GET_CODE(getitem); ++ PyObject *getitem_o = FT_ATOMIC_LOAD_PTR_ACQUIRE(ht->_spec_cache.getitem); ++ if (getitem_o == NULL) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } ++ assert(PyFunction_Check(getitem_o)); ++ uint32_t cached_version = FT_ATOMIC_LOAD_UINT32_RELAXED(ht->_spec_cache.getitem_version); ++ if (((PyFunctionObject *)getitem_o)->func_version != cached_version) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } ++ PyCodeObject *code = (PyCodeObject *)PyFunction_GET_CODE(getitem_o); + assert(code->co_argcount == 2); +- DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), BINARY_SUBSCR); +- STAT_INC(BINARY_SUBSCR, hit); ++ if (!_PyThreadState_HasStackSpace(tstate, code->co_framesize)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } ++ getitem = PyStackRef_FromPyObjectNew(getitem_o); ++ STAT_INC(BINARY_OP, hit); + } +- // _BINARY_SUBSCR_INIT_CALL ++ // _BINARY_OP_SUBSCR_INIT_CALL + { + sub = stack_pointer[-1]; +- PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(container)); +- PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; +- PyObject *getitem = ht->_spec_cache.getitem; +- new_frame = _PyFrame_PushUnchecked(tstate, PyStackRef_FromPyObjectNew(getitem), 2, frame); ++ new_frame = _PyFrame_PushUnchecked(tstate, getitem, 2, frame); + new_frame->localsplus[0] = container; + new_frame->localsplus[1] = sub; +- frame->return_offset = 2 ; ++ frame->return_offset = 6 ; + } + // _PUSH_FRAME + { +@@ -559,122 +612,377 @@ + DISPATCH(); + } + +- TARGET(BINARY_SUBSCR_LIST_INT) { ++ TARGET(BINARY_OP_SUBSCR_LIST_INT) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = BINARY_OP_SUBSCR_LIST_INT; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; +- next_instr += 2; +- INSTRUCTION_STATS(BINARY_SUBSCR_LIST_INT); +- static_assert(INLINE_CACHE_ENTRIES_BINARY_SUBSCR == 1, "incorrect cache size"); ++ next_instr += 6; ++ INSTRUCTION_STATS(BINARY_OP_SUBSCR_LIST_INT); ++ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); + _PyStackRef list_st; + _PyStackRef sub_st; + _PyStackRef res; +- /* Skip 1 cache entry */ ++ /* Skip 5 cache entries */ + sub_st = stack_pointer[-1]; + list_st = stack_pointer[-2]; + PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); + PyObject *list = PyStackRef_AsPyObjectBorrow(list_st); +- DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); +- DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); ++ if (!PyLong_CheckExact(sub)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } ++ if (!PyList_CheckExact(list)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } + // Deopt unless 0 <= sub < PyList_Size(list) +- DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); ++ if (!_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } + Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; + #ifdef Py_GIL_DISABLED + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *res_o = _PyList_GetItemRef((PyListObject*)list, index); + stack_pointer = _PyFrame_GetStackPointer(frame); +- DEOPT_IF(res_o == NULL, BINARY_SUBSCR); +- STAT_INC(BINARY_SUBSCR, hit); ++ if (res_o == NULL) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } ++ STAT_INC(BINARY_OP, hit); + #else +- DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR); +- STAT_INC(BINARY_SUBSCR, hit); ++ if (index >= PyList_GET_SIZE(list)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } ++ STAT_INC(BINARY_OP, hit); + PyObject *res_o = PyList_GET_ITEM(list, index); + assert(res_o != NULL); + Py_INCREF(res_o); + #endif + PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(list_st); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + res = PyStackRef_FromPyObjectSteal(res_o); +- stack_pointer[-2] = res; +- stack_pointer += -1; ++ stack_pointer[0] = res; ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + +- TARGET(BINARY_SUBSCR_STR_INT) { ++ TARGET(BINARY_OP_SUBSCR_STR_INT) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = BINARY_OP_SUBSCR_STR_INT; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; +- next_instr += 2; +- INSTRUCTION_STATS(BINARY_SUBSCR_STR_INT); +- static_assert(INLINE_CACHE_ENTRIES_BINARY_SUBSCR == 1, "incorrect cache size"); ++ next_instr += 6; ++ INSTRUCTION_STATS(BINARY_OP_SUBSCR_STR_INT); ++ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); + _PyStackRef str_st; + _PyStackRef sub_st; + _PyStackRef res; +- /* Skip 1 cache entry */ ++ /* Skip 5 cache entries */ + sub_st = stack_pointer[-1]; + str_st = stack_pointer[-2]; + PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); + PyObject *str = PyStackRef_AsPyObjectBorrow(str_st); +- DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); +- DEOPT_IF(!PyUnicode_CheckExact(str), BINARY_SUBSCR); +- DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); ++ if (!PyLong_CheckExact(sub)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } ++ if (!PyUnicode_CheckExact(str)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } ++ if (!_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } + Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; +- DEOPT_IF(PyUnicode_GET_LENGTH(str) <= index, BINARY_SUBSCR); ++ if (PyUnicode_GET_LENGTH(str) <= index) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } + // Specialize for reading an ASCII character from any string: + Py_UCS4 c = PyUnicode_READ_CHAR(str, index); +- DEOPT_IF(Py_ARRAY_LENGTH(_Py_SINGLETON(strings).ascii) <= c, BINARY_SUBSCR); +- STAT_INC(BINARY_SUBSCR, hit); ++ if (Py_ARRAY_LENGTH(_Py_SINGLETON(strings).ascii) <= c) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } ++ STAT_INC(BINARY_OP, hit); + PyObject *res_o = (PyObject*)&_Py_SINGLETON(strings).ascii[c]; + PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(str_st); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + res = PyStackRef_FromPyObjectSteal(res_o); +- stack_pointer[-2] = res; +- stack_pointer += -1; ++ stack_pointer[0] = res; ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + +- TARGET(BINARY_SUBSCR_TUPLE_INT) { ++ TARGET(BINARY_OP_SUBSCR_TUPLE_INT) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = BINARY_OP_SUBSCR_TUPLE_INT; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; +- next_instr += 2; +- INSTRUCTION_STATS(BINARY_SUBSCR_TUPLE_INT); +- static_assert(INLINE_CACHE_ENTRIES_BINARY_SUBSCR == 1, "incorrect cache size"); ++ next_instr += 6; ++ INSTRUCTION_STATS(BINARY_OP_SUBSCR_TUPLE_INT); ++ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); + _PyStackRef tuple_st; + _PyStackRef sub_st; + _PyStackRef res; +- /* Skip 1 cache entry */ ++ /* Skip 5 cache entries */ + sub_st = stack_pointer[-1]; + tuple_st = stack_pointer[-2]; + PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); + PyObject *tuple = PyStackRef_AsPyObjectBorrow(tuple_st); +- DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); +- DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); ++ if (!PyLong_CheckExact(sub)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } ++ if (!PyTuple_CheckExact(tuple)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } + // Deopt unless 0 <= sub < PyTuple_Size(list) +- DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); ++ if (!_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } + Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; +- DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR); +- STAT_INC(BINARY_SUBSCR, hit); ++ if (index >= PyTuple_GET_SIZE(tuple)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } ++ STAT_INC(BINARY_OP, hit); + PyObject *res_o = PyTuple_GET_ITEM(tuple, index); + assert(res_o != NULL); + Py_INCREF(res_o); + PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(tuple_st); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + res = PyStackRef_FromPyObjectSteal(res_o); ++ stack_pointer[0] = res; ++ stack_pointer += 1; ++ assert(WITHIN_STACK_BOUNDS()); ++ DISPATCH(); ++ } ++ ++ TARGET(BINARY_OP_SUBTRACT_FLOAT) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = BINARY_OP_SUBTRACT_FLOAT; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; ++ next_instr += 6; ++ INSTRUCTION_STATS(BINARY_OP_SUBTRACT_FLOAT); ++ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); ++ _PyStackRef left; ++ _PyStackRef right; ++ _PyStackRef res; ++ // _GUARD_BOTH_FLOAT ++ { ++ right = stack_pointer[-1]; ++ left = stack_pointer[-2]; ++ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); ++ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ if (!PyFloat_CheckExact(left_o)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } ++ if (!PyFloat_CheckExact(right_o)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } ++ } ++ /* Skip 5 cache entries */ ++ // _BINARY_OP_SUBTRACT_FLOAT ++ { ++ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); ++ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(PyFloat_CheckExact(left_o)); ++ assert(PyFloat_CheckExact(right_o)); ++ STAT_INC(BINARY_OP, hit); ++ double dres = ++ ((PyFloatObject *)left_o)->ob_fval - ++ ((PyFloatObject *)right_o)->ob_fval; ++ PyObject *res_o = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); ++ if (res_o == NULL) { ++ JUMP_TO_LABEL(pop_2_error); ++ } ++ res = PyStackRef_FromPyObjectSteal(res_o); ++ } ++ stack_pointer[-2] = res; ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ DISPATCH(); ++ } ++ ++ TARGET(BINARY_OP_SUBTRACT_INT) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = BINARY_OP_SUBTRACT_INT; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; ++ next_instr += 6; ++ INSTRUCTION_STATS(BINARY_OP_SUBTRACT_INT); ++ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); ++ _PyStackRef left; ++ _PyStackRef right; ++ _PyStackRef res; ++ // _GUARD_BOTH_INT ++ { ++ right = stack_pointer[-1]; ++ left = stack_pointer[-2]; ++ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); ++ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ if (!PyLong_CheckExact(left_o)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } ++ if (!PyLong_CheckExact(right_o)) { ++ UPDATE_MISS_STATS(BINARY_OP); ++ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); ++ JUMP_TO_PREDICTED(BINARY_OP); ++ } ++ } ++ /* Skip 5 cache entries */ ++ // _BINARY_OP_SUBTRACT_INT ++ { ++ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); ++ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); ++ assert(PyLong_CheckExact(left_o)); ++ assert(PyLong_CheckExact(right_o)); ++ STAT_INC(BINARY_OP, hit); ++ PyObject *res_o = _PyLong_Subtract((PyLongObject *)left_o, (PyLongObject *)right_o); ++ PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); ++ PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); ++ if (res_o == NULL) { ++ JUMP_TO_LABEL(pop_2_error); ++ } ++ res = PyStackRef_FromPyObjectSteal(res_o); ++ } + stack_pointer[-2] = res; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + ++ TARGET(BINARY_SLICE) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = BINARY_SLICE; ++ (void)(opcode); ++ #endif ++ frame->instr_ptr = next_instr; ++ next_instr += 1; ++ INSTRUCTION_STATS(BINARY_SLICE); ++ _PyStackRef container; ++ _PyStackRef start; ++ _PyStackRef stop; ++ _PyStackRef res; ++ // _SPECIALIZE_BINARY_SLICE ++ { ++ // Placeholder until we implement BINARY_SLICE specialization ++ #if ENABLE_SPECIALIZATION ++ OPCODE_DEFERRED_INC(BINARY_SLICE); ++ #endif /* ENABLE_SPECIALIZATION */ ++ } ++ // _BINARY_SLICE ++ { ++ stop = stack_pointer[-1]; ++ start = stack_pointer[-2]; ++ container = stack_pointer[-3]; ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyObject *slice = _PyBuildSlice_ConsumeRefs(PyStackRef_AsPyObjectSteal(start), ++ PyStackRef_AsPyObjectSteal(stop)); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ PyObject *res_o; ++ // Can't use ERROR_IF() here, because we haven't ++ // DECREF'ed container yet, and we still own slice. ++ if (slice == NULL) { ++ res_o = NULL; ++ } ++ else { ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ res_o = PyObject_GetItem(PyStackRef_AsPyObjectBorrow(container), slice); ++ Py_DECREF(slice); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += 2; ++ assert(WITHIN_STACK_BOUNDS()); ++ } ++ stack_pointer += -3; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(container); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (res_o == NULL) { ++ JUMP_TO_LABEL(error); ++ } ++ res = PyStackRef_FromPyObjectSteal(res_o); ++ } ++ stack_pointer[0] = res; ++ stack_pointer += 1; ++ assert(WITHIN_STACK_BOUNDS()); ++ DISPATCH(); ++ } ++ + TARGET(BUILD_LIST) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = BUILD_LIST; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(BUILD_LIST); + _PyStackRef *values; + _PyStackRef list; + values = &stack_pointer[-oparg]; +- PyObject *list_o = _PyList_FromStackRefSteal(values, oparg); ++ PyObject *list_o = _PyList_FromStackRefStealOnSuccess(values, oparg); + if (list_o == NULL) { +- stack_pointer += -oparg; +- assert(WITHIN_STACK_BOUNDS()); +- goto error; ++ JUMP_TO_LABEL(error); + } + list = PyStackRef_FromPyObjectSteal(list_o); + stack_pointer[-oparg] = list; +@@ -684,6 +992,10 @@ + } + + TARGET(BUILD_MAP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = BUILD_MAP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(BUILD_MAP); +@@ -695,11 +1007,9 @@ + for (int _i = oparg*2; --_i >= 0;) { + PyStackRef_CLOSE(values[_i]); + } +- { +- stack_pointer += -oparg*2; +- assert(WITHIN_STACK_BOUNDS()); +- goto error; +- } ++ stack_pointer += -oparg*2; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_LABEL(error); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *map_o = _PyDict_FromItems( +@@ -714,7 +1024,7 @@ + if (map_o == NULL) { + stack_pointer += -oparg*2; + assert(WITHIN_STACK_BOUNDS()); +- goto error; ++ JUMP_TO_LABEL(error); + } + map = PyStackRef_FromPyObjectSteal(map_o); + stack_pointer[-oparg*2] = map; +@@ -724,6 +1034,10 @@ + } + + TARGET(BUILD_SET) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = BUILD_SET; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(BUILD_SET); +@@ -737,11 +1051,9 @@ + for (int _i = oparg; --_i >= 0;) { + PyStackRef_CLOSE(values[_i]); + } +- { +- stack_pointer += -oparg; +- assert(WITHIN_STACK_BOUNDS()); +- goto error; +- } ++ stack_pointer += -oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_LABEL(error); + } + int err = 0; + for (int i = 0; i < oparg; i++) { +@@ -750,15 +1062,17 @@ + err = PySet_Add(set_o, PyStackRef_AsPyObjectBorrow(values[i])); + stack_pointer = _PyFrame_GetStackPointer(frame); + } +- PyStackRef_CLOSE(values[i]); ++ } ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(values[_i]); + } + if (err != 0) { ++ stack_pointer += -oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + Py_DECREF(set_o); +- { +- stack_pointer += -oparg; +- assert(WITHIN_STACK_BOUNDS()); +- goto error; +- } ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ JUMP_TO_LABEL(error); + } + set = PyStackRef_FromPyObjectSteal(set_o); + stack_pointer[-oparg] = set; +@@ -768,36 +1082,40 @@ + } + + TARGET(BUILD_SLICE) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = BUILD_SLICE; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(BUILD_SLICE); +- _PyStackRef start; +- _PyStackRef stop; +- _PyStackRef step = PyStackRef_NULL; ++ _PyStackRef *args; + _PyStackRef slice; +- if (oparg == 3) { step = stack_pointer[-((oparg == 3) ? 1 : 0)]; } +- stop = stack_pointer[-1 - ((oparg == 3) ? 1 : 0)]; +- start = stack_pointer[-2 - ((oparg == 3) ? 1 : 0)]; +- PyObject *start_o = PyStackRef_AsPyObjectBorrow(start); +- PyObject *stop_o = PyStackRef_AsPyObjectBorrow(stop); +- PyObject *step_o = PyStackRef_AsPyObjectBorrow(step); ++ args = &stack_pointer[-oparg]; ++ PyObject *start_o = PyStackRef_AsPyObjectBorrow(args[0]); ++ PyObject *stop_o = PyStackRef_AsPyObjectBorrow(args[1]); ++ PyObject *step_o = oparg == 3 ? PyStackRef_AsPyObjectBorrow(args[2]) : NULL; + PyObject *slice_o = PySlice_New(start_o, stop_o, step_o); +- PyStackRef_CLOSE(start); +- PyStackRef_CLOSE(stop); +- PyStackRef_XCLOSE(step); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); ++ } + if (slice_o == NULL) { +- stack_pointer += -2 - ((oparg == 3) ? 1 : 0); ++ stack_pointer += -oparg; + assert(WITHIN_STACK_BOUNDS()); +- goto error; ++ JUMP_TO_LABEL(error); + } + slice = PyStackRef_FromPyObjectSteal(slice_o); +- stack_pointer[-2 - ((oparg == 3) ? 1 : 0)] = slice; +- stack_pointer += -1 - ((oparg == 3) ? 1 : 0); ++ stack_pointer[-oparg] = slice; ++ stack_pointer += 1 - oparg; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(BUILD_STRING) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = BUILD_STRING; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(BUILD_STRING); +@@ -809,11 +1127,9 @@ + for (int _i = oparg; --_i >= 0;) { + PyStackRef_CLOSE(pieces[_i]); + } +- { +- stack_pointer += -oparg; +- assert(WITHIN_STACK_BOUNDS()); +- goto error; +- } ++ stack_pointer += -oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_LABEL(error); + } + PyObject *str_o = _PyUnicode_JoinArray(&_Py_STR(empty), pieces_o, oparg); + STACKREFS_TO_PYOBJECTS_CLEANUP(pieces_o); +@@ -823,7 +1139,7 @@ + if (str_o == NULL) { + stack_pointer += -oparg; + assert(WITHIN_STACK_BOUNDS()); +- goto error; ++ JUMP_TO_LABEL(error); + } + str = PyStackRef_FromPyObjectSteal(str_o); + stack_pointer[-oparg] = str; +@@ -833,17 +1149,19 @@ + } + + TARGET(BUILD_TUPLE) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = BUILD_TUPLE; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(BUILD_TUPLE); + _PyStackRef *values; + _PyStackRef tup; + values = &stack_pointer[-oparg]; +- PyObject *tup_o = _PyTuple_FromStackRefSteal(values, oparg); ++ PyObject *tup_o = _PyTuple_FromStackRefStealOnSuccess(values, oparg); + if (tup_o == NULL) { +- stack_pointer += -oparg; +- assert(WITHIN_STACK_BOUNDS()); +- goto error; ++ JUMP_TO_LABEL(error); + } + tup = PyStackRef_FromPyObjectSteal(tup_o); + stack_pointer[-oparg] = tup; +@@ -853,6 +1171,10 @@ + } + + TARGET(CACHE) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CACHE; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(CACHE); +@@ -862,12 +1184,17 @@ + } + + TARGET(CALL) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL); +- PREDICTED(CALL); ++ PREDICTED_CALL:; + _Py_CODEUNIT* const this_instr = next_instr - 4; + (void)this_instr; ++ opcode = CALL; + _PyStackRef *callable; + _PyStackRef *self_or_null; + _PyStackRef *args; +@@ -898,6 +1225,8 @@ + args = &stack_pointer[-oparg]; + func = &stack_pointer[-2 - oparg]; + maybe_self = &stack_pointer[-1 - oparg]; ++ args = &stack_pointer[-oparg]; ++ (void)args; + if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + PyObject *self = ((PyMethodObject *)callable_o)->im_self; +@@ -905,7 +1234,9 @@ + PyObject *method = ((PyMethodObject *)callable_o)->im_func; + _PyStackRef temp = callable[0]; + func[0] = PyStackRef_FromPyObjectNew(method); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(temp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + } + } + // _DO_CALL +@@ -916,8 +1247,9 @@ + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + // oparg counts all of the args, but *not* self: + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + // Check if the call can be inlined or not +@@ -930,7 +1262,7 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( + tstate, callable[0], locals, +- args, total_args, NULL, frame ++ arguments, total_args, NULL, frame + ); + stack_pointer = _PyFrame_GetStackPointer(frame); + // Manipulate stack directly since we leave using DISPATCH_INLINED(). +@@ -939,23 +1271,22 @@ + // The frame has stolen all the arguments from the stack, + // so there is no need to clean them up. + if (new_frame == NULL) { +- goto error; ++ JUMP_TO_LABEL(error); + } + frame->return_offset = 4 ; + DISPATCH_INLINED(new_frame); + } + /* Callable is not a normal Python function */ +- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + PyStackRef_CLOSE(callable[0]); +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); +- } +- { +- stack_pointer += -2 - oparg; +- assert(WITHIN_STACK_BOUNDS()); +- goto error; ++ PyStackRef_XCLOSE(self_or_null[0]); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); + } ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_LABEL(error); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *res_o = PyObject_Vectorcall( +@@ -966,7 +1297,7 @@ + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + if (opcode == INSTRUMENTED_CALL) { + PyObject *arg = total_args == 0 ? +- &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(args[0]); ++ &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(arguments[0]); + if (res_o == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); + _Py_call_instrumentation_exc2( +@@ -981,19 +1312,22 @@ + frame, this_instr, callable_o, arg); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err < 0) { ++ _PyFrame_SetStackPointer(frame, stack_pointer); + Py_CLEAR(res_o); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + } + } + } + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + PyStackRef_CLOSE(callable[0]); +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); ++ PyStackRef_XCLOSE(self_or_null[0]); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); + } + if (res_o == NULL) { + stack_pointer += -2 - oparg; + assert(WITHIN_STACK_BOUNDS()); +- goto error; ++ JUMP_TO_LABEL(error); + } + res = PyStackRef_FromPyObjectSteal(res_o); + } +@@ -1008,7 +1342,9 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err != 0) goto error; ++ if (err != 0) { ++ JUMP_TO_LABEL(error); ++ } + stack_pointer += 1 + oparg; + assert(WITHIN_STACK_BOUNDS()); + } +@@ -1020,7 +1356,13 @@ + } + + TARGET(CALL_ALLOC_AND_ENTER_INIT) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_ALLOC_AND_ENTER_INIT; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_ALLOC_AND_ENTER_INIT); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); +@@ -1034,7 +1376,11 @@ + /* Skip 1 cache entry */ + // _CHECK_PEP_523 + { +- DEOPT_IF(tstate->interp->eval_frame, CALL); ++ if (tstate->interp->eval_frame) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + } + // _CHECK_AND_ALLOCATE_OBJECT + { +@@ -1043,26 +1389,50 @@ + callable = &stack_pointer[-2 - oparg]; + init = &stack_pointer[-2 - oparg]; + self = &stack_pointer[-1 - oparg]; ++ args = &stack_pointer[-oparg]; + uint32_t type_version = read_u32(&this_instr[2].cache); ++ (void)args; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); +- DEOPT_IF(!PyStackRef_IsNull(null[0]), CALL); +- DEOPT_IF(!PyType_Check(callable_o), CALL); ++ if (!PyStackRef_IsNull(null[0])) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } ++ if (!PyType_Check(callable_o)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + PyTypeObject *tp = (PyTypeObject *)callable_o; +- DEOPT_IF(FT_ATOMIC_LOAD_UINT32_RELAXED(tp->tp_version_tag) != type_version, CALL); +- assert(tp->tp_flags & Py_TPFLAGS_INLINE_VALUES); ++ if (FT_ATOMIC_LOAD_UINT32_RELAXED(tp->tp_version_tag) != type_version) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } ++ assert(tp->tp_new == PyBaseObject_Type.tp_new); ++ assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE); ++ assert(tp->tp_alloc == PyType_GenericAlloc); + PyHeapTypeObject *cls = (PyHeapTypeObject *)callable_o; + PyFunctionObject *init_func = (PyFunctionObject *)FT_ATOMIC_LOAD_PTR_ACQUIRE(cls->_spec_cache.init); + PyCodeObject *code = (PyCodeObject *)init_func->func_code; +- DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize + _Py_InitCleanup.co_framesize), CALL); ++ if (!_PyThreadState_HasStackSpace(tstate, code->co_framesize + _Py_InitCleanup.co_framesize)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + STAT_INC(CALL, hit); +- PyObject *self_o = _PyType_NewManagedObject(tp); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyObject *self_o = PyType_GenericAlloc(tp, 0); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + if (self_o == NULL) { +- goto error; ++ JUMP_TO_LABEL(error); + } + self[0] = PyStackRef_FromPyObjectSteal(self_o); + _PyStackRef temp = callable[0]; + init[0] = PyStackRef_FromPyObjectNew(init_func); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(temp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + } + // _CREATE_INIT_FRAME + { +@@ -1072,9 +1442,9 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyInterpreterFrame *shim = _PyFrame_PushTrampolineUnchecked( + tstate, (PyCodeObject *)&_Py_InitCleanup, 1, frame); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + assert(_PyFrame_GetBytecode(shim)[0].op.code == EXIT_INIT_CHECK); + assert(_PyFrame_GetBytecode(shim)[1].op.code == RETURN_VALUE); +- stack_pointer = _PyFrame_GetStackPointer(frame); + /* Push self onto stack of shim */ + shim->localsplus[0] = PyStackRef_DUP(self[0]); + _PyFrame_SetStackPointer(frame, stack_pointer); +@@ -1085,7 +1455,7 @@ + assert(WITHIN_STACK_BOUNDS()); + if (temp == NULL) { + _PyEval_FrameClearAndPop(tstate, shim); +- goto error; ++ JUMP_TO_LABEL(error); + } + init_frame = temp; + frame->return_offset = 1 + INLINE_CACHE_ENTRIES_CALL; +@@ -1114,66 +1484,102 @@ + } + + TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_BOUND_METHOD_EXACT_ARGS; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_BOUND_METHOD_EXACT_ARGS); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); + _PyStackRef *callable; + _PyStackRef *null; +- _PyStackRef *func; +- _PyStackRef *self; + _PyStackRef *self_or_null; + _PyStackRef *args; + _PyInterpreterFrame *new_frame; + /* Skip 1 cache entry */ + // _CHECK_PEP_523 + { +- DEOPT_IF(tstate->interp->eval_frame, CALL); ++ if (tstate->interp->eval_frame) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + } + // _CHECK_CALL_BOUND_METHOD_EXACT_ARGS + { + null = &stack_pointer[-1 - oparg]; + callable = &stack_pointer[-2 - oparg]; +- DEOPT_IF(!PyStackRef_IsNull(null[0]), CALL); +- DEOPT_IF(Py_TYPE(PyStackRef_AsPyObjectBorrow(callable[0])) != &PyMethod_Type, CALL); ++ if (!PyStackRef_IsNull(null[0])) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } ++ if (Py_TYPE(PyStackRef_AsPyObjectBorrow(callable[0])) != &PyMethod_Type) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + } + // _INIT_CALL_BOUND_METHOD_EXACT_ARGS + { +- func = &stack_pointer[-2 - oparg]; +- self = &stack_pointer[-1 - oparg]; ++ self_or_null = null; ++ assert(PyStackRef_IsNull(self_or_null[0])); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + STAT_INC(CALL, hit); +- self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); ++ self_or_null[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); + _PyStackRef temp = callable[0]; +- func[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); ++ callable[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(temp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + } + // flush + // _CHECK_FUNCTION_VERSION + { +- callable = &stack_pointer[-2 - oparg]; + uint32_t func_version = read_u32(&this_instr[2].cache); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); +- DEOPT_IF(!PyFunction_Check(callable_o), CALL); ++ if (!PyFunction_Check(callable_o)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + PyFunctionObject *func = (PyFunctionObject *)callable_o; +- DEOPT_IF(func->func_version != func_version, CALL); ++ if (func->func_version != func_version) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + } + // _CHECK_FUNCTION_EXACT_ARGS + { +- self_or_null = &stack_pointer[-1 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + assert(PyFunction_Check(callable_o)); + PyFunctionObject *func = (PyFunctionObject *)callable_o; + PyCodeObject *code = (PyCodeObject *)func->func_code; +- DEOPT_IF(code->co_argcount != oparg + (!PyStackRef_IsNull(self_or_null[0])), CALL); ++ if (code->co_argcount != oparg + (!PyStackRef_IsNull(self_or_null[0]))) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + } + // _CHECK_STACK_SPACE + { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + PyFunctionObject *func = (PyFunctionObject *)callable_o; + PyCodeObject *code = (PyCodeObject *)func->func_code; +- DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL); +- DEOPT_IF(tstate->py_recursion_remaining <= 1, CALL); ++ if (!_PyThreadState_HasStackSpace(tstate, code->co_framesize)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } ++ if (tstate->py_recursion_remaining <= 1) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + } + // _INIT_CALL_PY_EXACT_ARGS + { +@@ -1217,21 +1623,29 @@ + } + + TARGET(CALL_BOUND_METHOD_GENERAL) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_BOUND_METHOD_GENERAL; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_BOUND_METHOD_GENERAL); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); + _PyStackRef *callable; + _PyStackRef *null; +- _PyStackRef *method; +- _PyStackRef *self; + _PyStackRef *self_or_null; + _PyStackRef *args; + _PyInterpreterFrame *new_frame; + /* Skip 1 cache entry */ + // _CHECK_PEP_523 + { +- DEOPT_IF(tstate->interp->eval_frame, CALL); ++ if (tstate->interp->eval_frame) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + } + // _CHECK_METHOD_VERSION + { +@@ -1239,31 +1653,46 @@ + callable = &stack_pointer[-2 - oparg]; + uint32_t func_version = read_u32(&this_instr[2].cache); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); +- DEOPT_IF(Py_TYPE(callable_o) != &PyMethod_Type, CALL); ++ if (Py_TYPE(callable_o) != &PyMethod_Type) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + PyObject *func = ((PyMethodObject *)callable_o)->im_func; +- DEOPT_IF(!PyFunction_Check(func), CALL); +- DEOPT_IF(((PyFunctionObject *)func)->func_version != func_version, CALL); +- DEOPT_IF(!PyStackRef_IsNull(null[0]), CALL); ++ if (!PyFunction_Check(func)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } ++ if (((PyFunctionObject *)func)->func_version != func_version) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } ++ if (!PyStackRef_IsNull(null[0])) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + } + // _EXPAND_METHOD + { +- method = &stack_pointer[-2 - oparg]; +- self = &stack_pointer[-1 - oparg]; ++ self_or_null = null; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); +- assert(PyStackRef_IsNull(null[0])); ++ assert(PyStackRef_IsNull(self_or_null[0])); + assert(Py_TYPE(callable_o) == &PyMethod_Type); +- self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); ++ self_or_null[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); + _PyStackRef temp = callable[0]; +- method[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); +- assert(PyStackRef_FunctionCheck(method[0])); ++ callable[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); ++ assert(PyStackRef_FunctionCheck(callable[0])); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(temp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + } + // flush + // _PY_FRAME_GENERAL + { + args = &stack_pointer[-oparg]; +- self_or_null = &stack_pointer[-1 - oparg]; +- callable = &stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + // oparg counts all of the args, but *not* self: + int total_args = oparg; +@@ -1284,7 +1713,7 @@ + stack_pointer += -2 - oparg; + assert(WITHIN_STACK_BOUNDS()); + if (temp == NULL) { +- goto error; ++ JUMP_TO_LABEL(error); + } + new_frame = temp; + } +@@ -1316,6 +1745,12 @@ + } + + TARGET(CALL_BUILTIN_CLASS) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_BUILTIN_CLASS; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_BUILTIN_CLASS); +@@ -1332,41 +1767,48 @@ + self_or_null = &stack_pointer[-1 - oparg]; + callable = &stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); ++ if (!PyType_Check(callable_o)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } ++ PyTypeObject *tp = (PyTypeObject *)callable_o; + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } +- DEOPT_IF(!PyType_Check(callable_o), CALL); +- PyTypeObject *tp = (PyTypeObject *)callable_o; +- DEOPT_IF(tp->tp_vectorcall == NULL, CALL); ++ if (tp->tp_vectorcall == NULL) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + STAT_INC(CALL, hit); +- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + PyStackRef_CLOSE(callable[0]); +- PyStackRef_CLOSE(self_or_null[0]); ++ PyStackRef_XCLOSE(self_or_null[0]); + for (int _i = oparg; --_i >= 0;) { + PyStackRef_CLOSE(args[_i]); + } +- { +- stack_pointer += -2 - oparg; +- assert(WITHIN_STACK_BOUNDS()); +- goto error; +- } ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_LABEL(error); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *res_o = tp->tp_vectorcall((PyObject *)tp, args_o, total_args, NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); +- /* Free the arguments. */ +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); +- } + PyStackRef_CLOSE(callable[0]); ++ PyStackRef_XCLOSE(self_or_null[0]); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); ++ } + if (res_o == NULL) { + stack_pointer += -2 - oparg; + assert(WITHIN_STACK_BOUNDS()); +- goto error; ++ JUMP_TO_LABEL(error); + } + res = PyStackRef_FromPyObjectSteal(res_o); + } +@@ -1381,7 +1823,9 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err != 0) goto error; ++ if (err != 0) { ++ JUMP_TO_LABEL(error); ++ } + stack_pointer += 1 + oparg; + assert(WITHIN_STACK_BOUNDS()); + } +@@ -1393,6 +1837,12 @@ + } + + TARGET(CALL_BUILTIN_FAST) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_BUILTIN_FAST; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_BUILTIN_FAST); +@@ -1411,27 +1861,34 @@ + /* Builtin METH_FASTCALL functions, without keywords */ + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } +- DEOPT_IF(!PyCFunction_CheckExact(callable_o), CALL); +- DEOPT_IF(PyCFunction_GET_FLAGS(callable_o) != METH_FASTCALL, CALL); ++ if (!PyCFunction_CheckExact(callable_o)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } ++ if (PyCFunction_GET_FLAGS(callable_o) != METH_FASTCALL) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + STAT_INC(CALL, hit); + PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable_o); + /* res = func(self, args, nargs) */ +- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + PyStackRef_CLOSE(callable[0]); +- PyStackRef_CLOSE(self_or_null[0]); ++ PyStackRef_XCLOSE(self_or_null[0]); + for (int _i = oparg; --_i >= 0;) { + PyStackRef_CLOSE(args[_i]); + } +- { +- stack_pointer += -2 - oparg; +- assert(WITHIN_STACK_BOUNDS()); +- goto error; +- } ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_LABEL(error); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *res_o = ((PyCFunctionFast)(void(*)(void))cfunc)( +@@ -1441,15 +1898,15 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); +- /* Free the arguments. */ +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); +- } + PyStackRef_CLOSE(callable[0]); ++ PyStackRef_XCLOSE(self_or_null[0]); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); ++ } + if (res_o == NULL) { + stack_pointer += -2 - oparg; + assert(WITHIN_STACK_BOUNDS()); +- goto error; ++ JUMP_TO_LABEL(error); + } + res = PyStackRef_FromPyObjectSteal(res_o); + } +@@ -1464,7 +1921,9 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err != 0) goto error; ++ if (err != 0) { ++ JUMP_TO_LABEL(error); ++ } + stack_pointer += 1 + oparg; + assert(WITHIN_STACK_BOUNDS()); + } +@@ -1476,6 +1935,12 @@ + } + + TARGET(CALL_BUILTIN_FAST_WITH_KEYWORDS) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_BUILTIN_FAST_WITH_KEYWORDS; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_BUILTIN_FAST_WITH_KEYWORDS); +@@ -1494,46 +1959,53 @@ + /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } +- DEOPT_IF(!PyCFunction_CheckExact(callable_o), CALL); +- DEOPT_IF(PyCFunction_GET_FLAGS(callable_o) != (METH_FASTCALL | METH_KEYWORDS), CALL); ++ if (!PyCFunction_CheckExact(callable_o)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } ++ if (PyCFunction_GET_FLAGS(callable_o) != (METH_FASTCALL | METH_KEYWORDS)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + STAT_INC(CALL, hit); +- /* res = func(self, args, nargs, kwnames) */ ++ /* res = func(self, arguments, nargs, kwnames) */ + _PyFrame_SetStackPointer(frame, stack_pointer); + PyCFunctionFastWithKeywords cfunc = + (PyCFunctionFastWithKeywords)(void(*)(void)) + PyCFunction_GET_FUNCTION(callable_o); + stack_pointer = _PyFrame_GetStackPointer(frame); +- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + PyStackRef_CLOSE(callable[0]); +- PyStackRef_CLOSE(self_or_null[0]); ++ PyStackRef_XCLOSE(self_or_null[0]); + for (int _i = oparg; --_i >= 0;) { + PyStackRef_CLOSE(args[_i]); + } +- { +- stack_pointer += -2 - oparg; +- assert(WITHIN_STACK_BOUNDS()); +- goto error; +- } ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_LABEL(error); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *res_o = cfunc(PyCFunction_GET_SELF(callable_o), args_o, total_args, NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); +- /* Free the arguments. */ +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); +- } + PyStackRef_CLOSE(callable[0]); ++ PyStackRef_XCLOSE(self_or_null[0]); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); ++ } + if (res_o == NULL) { + stack_pointer += -2 - oparg; + assert(WITHIN_STACK_BOUNDS()); +- goto error; ++ JUMP_TO_LABEL(error); + } + res = PyStackRef_FromPyObjectSteal(res_o); + } +@@ -1548,7 +2020,9 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err != 0) goto error; ++ if (err != 0) { ++ JUMP_TO_LABEL(error); ++ } + stack_pointer += 1 + oparg; + assert(WITHIN_STACK_BOUNDS()); + } +@@ -1560,6 +2034,12 @@ + } + + TARGET(CALL_BUILTIN_O) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_BUILTIN_O; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_BUILTIN_O); +@@ -1582,11 +2062,27 @@ + args--; + total_args++; + } +- DEOPT_IF(total_args != 1, CALL); +- DEOPT_IF(!PyCFunction_CheckExact(callable_o), CALL); +- DEOPT_IF(PyCFunction_GET_FLAGS(callable_o) != METH_O, CALL); ++ if (total_args != 1) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } ++ if (!PyCFunction_CheckExact(callable_o)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } ++ if (PyCFunction_GET_FLAGS(callable_o) != METH_O) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + // CPython promises to check all non-vectorcall function calls. +- DEOPT_IF(tstate->c_recursion_remaining <= 0, CALL); ++ if (tstate->c_recursion_remaining <= 0) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + STAT_INC(CALL, hit); + PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable_o); + _PyStackRef arg = args[0]; +@@ -1596,12 +2092,16 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + _Py_LeaveRecursiveCallTstate(tstate); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(arg); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(callable[0]); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + if (res_o == NULL) { +- stack_pointer += -2 - oparg; +- assert(WITHIN_STACK_BOUNDS()); +- goto error; ++ JUMP_TO_LABEL(error); + } + res = PyStackRef_FromPyObjectSteal(res_o); + } +@@ -1610,93 +2110,109 @@ + _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); + QSBR_QUIESCENT_STATE(tstate); + if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { +- stack_pointer[-2 - oparg] = res; +- stack_pointer += -1 - oparg; ++ stack_pointer[0] = res; ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err != 0) goto error; +- stack_pointer += 1 + oparg; ++ if (err != 0) { ++ JUMP_TO_LABEL(error); ++ } ++ stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + } + } +- stack_pointer[-2 - oparg] = res; +- stack_pointer += -1 - oparg; ++ stack_pointer[0] = res; ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(CALL_FUNCTION_EX) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_FUNCTION_EX; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(CALL_FUNCTION_EX); +- PREDICTED(CALL_FUNCTION_EX); +- _Py_CODEUNIT* const this_instr = next_instr - 1; +- (void)this_instr; ++ opcode = CALL_FUNCTION_EX; + _PyStackRef func; + _PyStackRef callargs; +- _PyStackRef kwargs_in = PyStackRef_NULL; ++ _PyStackRef kwargs_in; + _PyStackRef tuple; +- _PyStackRef kwargs_out = PyStackRef_NULL; ++ _PyStackRef kwargs_out; + _PyStackRef func_st; ++ _PyStackRef null; + _PyStackRef callargs_st; +- _PyStackRef kwargs_st = PyStackRef_NULL; ++ _PyStackRef kwargs_st; + _PyStackRef result; + // _MAKE_CALLARGS_A_TUPLE + { +- if (oparg & 1) { kwargs_in = stack_pointer[-(oparg & 1)]; } +- callargs = stack_pointer[-1 - (oparg & 1)]; +- func = stack_pointer[-3 - (oparg & 1)]; ++ kwargs_in = stack_pointer[-1]; ++ callargs = stack_pointer[-2]; ++ func = stack_pointer[-4]; + PyObject *callargs_o = PyStackRef_AsPyObjectBorrow(callargs); + if (PyTuple_CheckExact(callargs_o)) { + tuple = callargs; ++ kwargs_out = kwargs_in; + } + else { + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_Check_ArgsIterable(tstate, PyStackRef_AsPyObjectBorrow(func), callargs_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err < 0) { +- goto error; ++ JUMP_TO_LABEL(error); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *tuple_o = PySequence_Tuple(callargs_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (tuple_o == NULL) { +- goto error; ++ JUMP_TO_LABEL(error); + } ++ kwargs_out = kwargs_in; ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(callargs); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + tuple = PyStackRef_FromPyObjectSteal(tuple_o); ++ stack_pointer += 2; ++ assert(WITHIN_STACK_BOUNDS()); + } +- kwargs_out = kwargs_in; + } + // _DO_CALL_FUNCTION_EX + { + kwargs_st = kwargs_out; + callargs_st = tuple; ++ null = stack_pointer[-3]; + func_st = func; ++ (void)null; + PyObject *func = PyStackRef_AsPyObjectBorrow(func_st); +- PyObject *callargs = PyStackRef_AsPyObjectBorrow(callargs_st); +- PyObject *kwargs = PyStackRef_AsPyObjectBorrow(kwargs_st); + // DICT_MERGE is called before this opcode if there are kwargs. + // It converts all dict subtypes in kwargs into regular dicts. +- assert(kwargs == NULL || PyDict_CheckExact(kwargs)); +- assert(PyTuple_CheckExact(callargs)); + EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_FUNCTION_EX, func); + PyObject *result_o; + assert(!_PyErr_Occurred(tstate)); + if (opcode == INSTRUMENTED_CALL_FUNCTION_EX) { ++ PyObject *callargs = PyStackRef_AsPyObjectBorrow(callargs_st); ++ PyObject *kwargs = PyStackRef_AsPyObjectBorrow(kwargs_st); ++ assert(kwargs == NULL || PyDict_CheckExact(kwargs)); ++ assert(PyTuple_CheckExact(callargs)); + PyObject *arg = PyTuple_GET_SIZE(callargs) > 0 ? + PyTuple_GET_ITEM(callargs, 0) : &_PyInstrumentation_MISSING; +- stack_pointer[-1 - (oparg & 1)] = callargs_st; +- if (oparg & 1) stack_pointer[-(oparg & 1)] = kwargs_st; ++ stack_pointer[-2] = callargs_st; ++ stack_pointer[-1] = kwargs_st; + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_call_instrumentation_2args( + tstate, PY_MONITORING_EVENT_CALL, + frame, this_instr, func, arg); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err) { +- goto error; ++ JUMP_TO_LABEL(error); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + result_o = PyObject_Call(func, callargs, kwargs); +@@ -1716,7 +2232,9 @@ + frame, this_instr, func, arg); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err < 0) { ++ _PyFrame_SetStackPointer(frame, stack_pointer); + Py_CLEAR(result_o); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + } + } + } +@@ -1725,42 +2243,57 @@ + if (Py_TYPE(func) == &PyFunction_Type && + tstate->interp->eval_frame == NULL && + ((PyFunctionObject *)func)->vectorcall == _PyFunction_Vectorcall) { ++ PyObject *callargs = PyStackRef_AsPyObjectSteal(callargs_st); + assert(PyTuple_CheckExact(callargs)); ++ PyObject *kwargs = PyStackRef_IsNull(kwargs_st) ? NULL : PyStackRef_AsPyObjectSteal(kwargs_st); ++ assert(kwargs == NULL || PyDict_CheckExact(kwargs)); + Py_ssize_t nargs = PyTuple_GET_SIZE(callargs); + int code_flags = ((PyCodeObject *)PyFunction_GET_CODE(func))->co_flags; + PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(func)); +- stack_pointer[-1 - (oparg & 1)] = callargs_st; +- if (oparg & 1) stack_pointer[-(oparg & 1)] = kwargs_st; ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_Ex( + tstate, func_st, locals, + nargs, callargs, kwargs, frame); + stack_pointer = _PyFrame_GetStackPointer(frame); + // Need to sync the stack since we exit with DISPATCH_INLINED. +- stack_pointer += -3 - (oparg & 1); ++ stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); + if (new_frame == NULL) { +- goto error; ++ JUMP_TO_LABEL(error); + } + assert( 1 == 1); + frame->return_offset = 1; + DISPATCH_INLINED(new_frame); + } +- stack_pointer[-1 - (oparg & 1)] = callargs_st; +- if (oparg & 1) stack_pointer[-(oparg & 1)] = kwargs_st; ++ PyObject *callargs = PyStackRef_AsPyObjectBorrow(callargs_st); ++ assert(PyTuple_CheckExact(callargs)); ++ PyObject *kwargs = PyStackRef_AsPyObjectBorrow(kwargs_st); ++ assert(kwargs == NULL || PyDict_CheckExact(kwargs)); ++ stack_pointer[-2] = callargs_st; ++ stack_pointer[-1] = kwargs_st; + _PyFrame_SetStackPointer(frame, stack_pointer); + result_o = PyObject_Call(func, callargs, kwargs); + stack_pointer = _PyFrame_GetStackPointer(frame); + } ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_XCLOSE(kwargs_st); + stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(callargs_st); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(func_st); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + if (result_o == NULL) { +- stack_pointer += -3 - (oparg & 1); +- assert(WITHIN_STACK_BOUNDS()); +- goto error; ++ JUMP_TO_LABEL(error); + } + result = PyStackRef_FromPyObjectSteal(result_o); + } +@@ -1769,24 +2302,30 @@ + _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); + QSBR_QUIESCENT_STATE(tstate); + if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { +- stack_pointer[-3 - (oparg & 1)] = result; +- stack_pointer += -2 - (oparg & 1); ++ stack_pointer[0] = result; ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err != 0) goto error; +- stack_pointer += 2 + (oparg & 1); ++ if (err != 0) { ++ JUMP_TO_LABEL(error); ++ } ++ stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + } + } +- stack_pointer[-3 - (oparg & 1)] = result; +- stack_pointer += -2 - (oparg & 1); ++ stack_pointer[0] = result; ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(CALL_INTRINSIC_1) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_INTRINSIC_1; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(CALL_INTRINSIC_1); +@@ -1798,13 +2337,19 @@ + PyObject *res_o = _PyIntrinsics_UnaryFunctions[oparg].func(tstate, PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(value); +- if (res_o == NULL) goto pop_1_error; ++ if (res_o == NULL) { ++ JUMP_TO_LABEL(pop_1_error); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-1] = res; + DISPATCH(); + } + + TARGET(CALL_INTRINSIC_2) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_INTRINSIC_2; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(CALL_INTRINSIC_2); +@@ -1821,7 +2366,9 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(value2_st); + PyStackRef_CLOSE(value1_st); +- if (res_o == NULL) goto pop_2_error; ++ if (res_o == NULL) { ++ JUMP_TO_LABEL(pop_2_error); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -1830,6 +2377,12 @@ + } + + TARGET(CALL_ISINSTANCE) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_ISINSTANCE; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_ISINSTANCE); +@@ -1846,27 +2399,38 @@ + /* isinstance(o, o2) */ + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } +- DEOPT_IF(total_args != 2, CALL); ++ if (total_args != 2) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + PyInterpreterState *interp = tstate->interp; +- DEOPT_IF(callable_o != interp->callable_cache.isinstance, CALL); ++ if (callable_o != interp->callable_cache.isinstance) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + STAT_INC(CALL, hit); +- _PyStackRef cls_stackref = args[1]; +- _PyStackRef inst_stackref = args[0]; ++ _PyStackRef cls_stackref = arguments[1]; ++ _PyStackRef inst_stackref = arguments[0]; + _PyFrame_SetStackPointer(frame, stack_pointer); + int retval = PyObject_IsInstance(PyStackRef_AsPyObjectBorrow(inst_stackref), PyStackRef_AsPyObjectBorrow(cls_stackref)); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (retval < 0) { +- goto error; ++ JUMP_TO_LABEL(error); + } + res = retval ? PyStackRef_True : PyStackRef_False; + assert((!PyStackRef_IsNull(res)) ^ (_PyErr_Occurred(tstate) != NULL)); +- PyStackRef_CLOSE(inst_stackref); +- PyStackRef_CLOSE(cls_stackref); + PyStackRef_CLOSE(callable[0]); ++ PyStackRef_XCLOSE(self_or_null[0]); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); ++ } + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; + assert(WITHIN_STACK_BOUNDS()); +@@ -1874,12 +2438,17 @@ + } + + TARGET(CALL_KW) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_KW; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_KW); +- PREDICTED(CALL_KW); ++ PREDICTED_CALL_KW:; + _Py_CODEUNIT* const this_instr = next_instr - 4; + (void)this_instr; ++ opcode = CALL_KW; + _PyStackRef *callable; + _PyStackRef *self_or_null; + _PyStackRef *args; +@@ -1914,6 +2483,8 @@ + args = &stack_pointer[-1 - oparg]; + func = &stack_pointer[-3 - oparg]; + maybe_self = &stack_pointer[-2 - oparg]; ++ args = &stack_pointer[-1 - oparg]; ++ (void)args; + if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + PyObject *self = ((PyMethodObject *)callable_o)->im_self; +@@ -1921,7 +2492,9 @@ + PyObject *method = ((PyMethodObject *)callable_o)->im_func; + _PyStackRef temp = callable[0]; + func[0] = PyStackRef_FromPyObjectNew(method); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(temp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + } + kwnames_out = kwnames_in; + } +@@ -1935,8 +2508,9 @@ + PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); + // oparg counts all of the args, but *not* self: + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + int positional_args = total_args - (int)PyTuple_GET_SIZE(kwnames_o); +@@ -1951,36 +2525,38 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( + tstate, callable[0], locals, +- args, positional_args, kwnames_o, frame ++ arguments, positional_args, kwnames_o, frame + ); + stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(kwnames); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + // Sync stack explicitly since we leave using DISPATCH_INLINED(). +- stack_pointer += -3 - oparg; ++ stack_pointer += -2 - oparg; + assert(WITHIN_STACK_BOUNDS()); + // The frame has stolen all the arguments from the stack, + // so there is no need to clean them up. + if (new_frame == NULL) { +- goto error; ++ JUMP_TO_LABEL(error); + } + assert( 4 == 1 + INLINE_CACHE_ENTRIES_CALL_KW); + frame->return_offset = 4 ; + DISPATCH_INLINED(new_frame); + } + /* Callable is not a normal Python function */ +- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + PyStackRef_CLOSE(callable[0]); +- PyStackRef_CLOSE(self_or_null[0]); ++ PyStackRef_XCLOSE(self_or_null[0]); + for (int _i = oparg; --_i >= 0;) { + PyStackRef_CLOSE(args[_i]); + } + PyStackRef_CLOSE(kwnames); +- { +- stack_pointer += -3 - oparg; +- assert(WITHIN_STACK_BOUNDS()); +- goto error; +- } ++ stack_pointer += -3 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_LABEL(error); + } + stack_pointer[-1] = kwnames; + _PyFrame_SetStackPointer(frame, stack_pointer); +@@ -1992,7 +2568,7 @@ + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + if (opcode == INSTRUMENTED_CALL_KW) { + PyObject *arg = total_args == 0 ? +- &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(args[0]); ++ &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(arguments[0]); + if (res_o == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); + _Py_call_instrumentation_exc2( +@@ -2007,20 +2583,22 @@ + frame, this_instr, callable_o, arg); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err < 0) { ++ _PyFrame_SetStackPointer(frame, stack_pointer); + Py_CLEAR(res_o); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + } + } + } +- PyStackRef_CLOSE(kwnames); +- assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + PyStackRef_CLOSE(callable[0]); +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); ++ PyStackRef_XCLOSE(self_or_null[0]); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); + } ++ PyStackRef_CLOSE(kwnames); + if (res_o == NULL) { + stack_pointer += -3 - oparg; + assert(WITHIN_STACK_BOUNDS()); +- goto error; ++ JUMP_TO_LABEL(error); + } + res = PyStackRef_FromPyObjectSteal(res_o); + } +@@ -2031,22 +2609,30 @@ + } + + TARGET(CALL_KW_BOUND_METHOD) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_KW_BOUND_METHOD; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_KW_BOUND_METHOD); + static_assert(INLINE_CACHE_ENTRIES_CALL_KW == 3, "incorrect cache size"); + _PyStackRef *callable; + _PyStackRef *null; + _PyStackRef kwnames; +- _PyStackRef *method; +- _PyStackRef *self; + _PyStackRef *self_or_null; + _PyStackRef *args; + _PyInterpreterFrame *new_frame; + /* Skip 1 cache entry */ + // _CHECK_PEP_523 + { +- DEOPT_IF(tstate->interp->eval_frame, CALL_KW); ++ if (tstate->interp->eval_frame) { ++ UPDATE_MISS_STATS(CALL_KW); ++ assert(_PyOpcode_Deopt[opcode] == (CALL_KW)); ++ JUMP_TO_PREDICTED(CALL_KW); ++ } + } + // _CHECK_METHOD_VERSION_KW + { +@@ -2054,37 +2640,53 @@ + callable = &stack_pointer[-3 - oparg]; + uint32_t func_version = read_u32(&this_instr[2].cache); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); +- DEOPT_IF(Py_TYPE(callable_o) != &PyMethod_Type, CALL_KW); ++ if (Py_TYPE(callable_o) != &PyMethod_Type) { ++ UPDATE_MISS_STATS(CALL_KW); ++ assert(_PyOpcode_Deopt[opcode] == (CALL_KW)); ++ JUMP_TO_PREDICTED(CALL_KW); ++ } + PyObject *func = ((PyMethodObject *)callable_o)->im_func; +- DEOPT_IF(!PyFunction_Check(func), CALL_KW); +- DEOPT_IF(((PyFunctionObject *)func)->func_version != func_version, CALL_KW); +- DEOPT_IF(!PyStackRef_IsNull(null[0]), CALL_KW); ++ if (!PyFunction_Check(func)) { ++ UPDATE_MISS_STATS(CALL_KW); ++ assert(_PyOpcode_Deopt[opcode] == (CALL_KW)); ++ JUMP_TO_PREDICTED(CALL_KW); ++ } ++ if (((PyFunctionObject *)func)->func_version != func_version) { ++ UPDATE_MISS_STATS(CALL_KW); ++ assert(_PyOpcode_Deopt[opcode] == (CALL_KW)); ++ JUMP_TO_PREDICTED(CALL_KW); ++ } ++ if (!PyStackRef_IsNull(null[0])) { ++ UPDATE_MISS_STATS(CALL_KW); ++ assert(_PyOpcode_Deopt[opcode] == (CALL_KW)); ++ JUMP_TO_PREDICTED(CALL_KW); ++ } + } + // _EXPAND_METHOD_KW + { +- method = &stack_pointer[-3 - oparg]; +- self = &stack_pointer[-2 - oparg]; ++ self_or_null = null; ++ assert(PyStackRef_IsNull(self_or_null[0])); + _PyStackRef callable_s = callable[0]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable_s); +- assert(PyStackRef_IsNull(null[0])); + assert(Py_TYPE(callable_o) == &PyMethod_Type); +- self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); +- method[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); +- assert(PyStackRef_FunctionCheck(method[0])); ++ self_or_null[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); ++ callable[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); ++ assert(PyStackRef_FunctionCheck(callable[0])); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(callable_s); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + } + // flush + // _PY_FRAME_KW + { + kwnames = stack_pointer[-1]; + args = &stack_pointer[-1 - oparg]; +- self_or_null = &stack_pointer[-2 - oparg]; +- callable = &stack_pointer[-3 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + // oparg counts all of the args, but *not* self: + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); +@@ -2095,16 +2697,20 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyInterpreterFrame *temp = _PyEvalFramePushAndInit( + tstate, callable[0], locals, +- args, positional_args, kwnames_o, frame ++ arguments, positional_args, kwnames_o, frame + ); + stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(kwnames); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + // The frame has stolen all the arguments from the stack, + // so there is no need to clean them up. +- stack_pointer += -3 - oparg; ++ stack_pointer += -2 - oparg; + assert(WITHIN_STACK_BOUNDS()); + if (temp == NULL) { +- goto error; ++ JUMP_TO_LABEL(error); + } + new_frame = temp; + } +@@ -2136,9 +2742,16 @@ + } + + TARGET(CALL_KW_NON_PY) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_KW_NON_PY; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_KW_NON_PY); ++ opcode = CALL_KW_NON_PY; + static_assert(INLINE_CACHE_ENTRIES_CALL_KW == 3, "incorrect cache size"); + _PyStackRef *callable; + _PyStackRef kwnames; +@@ -2151,8 +2764,16 @@ + { + callable = &stack_pointer[-3 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); +- DEOPT_IF(PyFunction_Check(callable_o), CALL_KW); +- DEOPT_IF(Py_TYPE(callable_o) == &PyMethod_Type, CALL_KW); ++ if (PyFunction_Check(callable_o)) { ++ UPDATE_MISS_STATS(CALL_KW); ++ assert(_PyOpcode_Deopt[opcode] == (CALL_KW)); ++ JUMP_TO_PREDICTED(CALL_KW); ++ } ++ if (Py_TYPE(callable_o) == &PyMethod_Type) { ++ UPDATE_MISS_STATS(CALL_KW); ++ assert(_PyOpcode_Deopt[opcode] == (CALL_KW)); ++ JUMP_TO_PREDICTED(CALL_KW); ++ } + } + // _CALL_KW_NON_PY + { +@@ -2164,24 +2785,23 @@ + #endif + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + /* Callable is not a normal Python function */ +- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + PyStackRef_CLOSE(callable[0]); +- PyStackRef_CLOSE(self_or_null[0]); ++ PyStackRef_XCLOSE(self_or_null[0]); + for (int _i = oparg; --_i >= 0;) { + PyStackRef_CLOSE(args[_i]); + } + PyStackRef_CLOSE(kwnames); +- { +- stack_pointer += -3 - oparg; +- assert(WITHIN_STACK_BOUNDS()); +- goto error; +- } ++ stack_pointer += -3 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_LABEL(error); + } + PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); + int positional_args = total_args - (int)PyTuple_GET_SIZE(kwnames_o); +@@ -2191,17 +2811,22 @@ + positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, + kwnames_o); + stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(kwnames); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); +- } + PyStackRef_CLOSE(callable[0]); ++ PyStackRef_XCLOSE(self_or_null[0]); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); ++ } + if (res_o == NULL) { +- stack_pointer += -3 - oparg; ++ stack_pointer += -2 - oparg; + assert(WITHIN_STACK_BOUNDS()); +- goto error; ++ JUMP_TO_LABEL(error); + } + res = PyStackRef_FromPyObjectSteal(res_o); + } +@@ -2210,25 +2835,33 @@ + _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); + QSBR_QUIESCENT_STATE(tstate); + if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { +- stack_pointer[-3 - oparg] = res; +- stack_pointer += -2 - oparg; ++ stack_pointer[-2 - oparg] = res; ++ stack_pointer += -1 - oparg; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err != 0) goto error; +- stack_pointer += 2 + oparg; ++ if (err != 0) { ++ JUMP_TO_LABEL(error); ++ } ++ stack_pointer += 1 + oparg; + assert(WITHIN_STACK_BOUNDS()); + } + } +- stack_pointer[-3 - oparg] = res; +- stack_pointer += -2 - oparg; ++ stack_pointer[-2 - oparg] = res; ++ stack_pointer += -1 - oparg; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(CALL_KW_PY) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_KW_PY; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_KW_PY); + static_assert(INLINE_CACHE_ENTRIES_CALL_KW == 3, "incorrect cache size"); +@@ -2240,16 +2873,28 @@ + /* Skip 1 cache entry */ + // _CHECK_PEP_523 + { +- DEOPT_IF(tstate->interp->eval_frame, CALL_KW); ++ if (tstate->interp->eval_frame) { ++ UPDATE_MISS_STATS(CALL_KW); ++ assert(_PyOpcode_Deopt[opcode] == (CALL_KW)); ++ JUMP_TO_PREDICTED(CALL_KW); ++ } + } + // _CHECK_FUNCTION_VERSION_KW + { + callable = &stack_pointer[-3 - oparg]; + uint32_t func_version = read_u32(&this_instr[2].cache); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); +- DEOPT_IF(!PyFunction_Check(callable_o), CALL_KW); ++ if (!PyFunction_Check(callable_o)) { ++ UPDATE_MISS_STATS(CALL_KW); ++ assert(_PyOpcode_Deopt[opcode] == (CALL_KW)); ++ JUMP_TO_PREDICTED(CALL_KW); ++ } + PyFunctionObject *func = (PyFunctionObject *)callable_o; +- DEOPT_IF(func->func_version != func_version, CALL_KW); ++ if (func->func_version != func_version) { ++ UPDATE_MISS_STATS(CALL_KW); ++ assert(_PyOpcode_Deopt[opcode] == (CALL_KW)); ++ JUMP_TO_PREDICTED(CALL_KW); ++ } + } + // _PY_FRAME_KW + { +@@ -2259,8 +2904,9 @@ + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + // oparg counts all of the args, but *not* self: + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); +@@ -2271,16 +2917,20 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyInterpreterFrame *temp = _PyEvalFramePushAndInit( + tstate, callable[0], locals, +- args, positional_args, kwnames_o, frame ++ arguments, positional_args, kwnames_o, frame + ); + stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(kwnames); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + // The frame has stolen all the arguments from the stack, + // so there is no need to clean them up. +- stack_pointer += -3 - oparg; ++ stack_pointer += -2 - oparg; + assert(WITHIN_STACK_BOUNDS()); + if (temp == NULL) { +- goto error; ++ JUMP_TO_LABEL(error); + } + new_frame = temp; + } +@@ -2312,6 +2962,12 @@ + } + + TARGET(CALL_LEN) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_LEN; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_LEN); +@@ -2332,9 +2988,17 @@ + args--; + total_args++; + } +- DEOPT_IF(total_args != 1, CALL); ++ if (total_args != 1) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + PyInterpreterState *interp = tstate->interp; +- DEOPT_IF(callable_o != interp->callable_cache.len, CALL); ++ if (callable_o != interp->callable_cache.len) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + STAT_INC(CALL, hit); + _PyStackRef arg_stackref = args[0]; + PyObject *arg = PyStackRef_AsPyObjectBorrow(arg_stackref); +@@ -2342,23 +3006,35 @@ + Py_ssize_t len_i = PyObject_Length(arg); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (len_i < 0) { +- goto error; ++ JUMP_TO_LABEL(error); + } + PyObject *res_o = PyLong_FromSsize_t(len_i); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + if (res_o == NULL) { +- GOTO_ERROR(error); ++ JUMP_TO_LABEL(error); + } +- PyStackRef_CLOSE(callable[0]); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(arg_stackref); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(callable[0]); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + res = PyStackRef_FromPyObjectSteal(res_o); +- stack_pointer[-2 - oparg] = res; +- stack_pointer += -1 - oparg; ++ stack_pointer[0] = res; ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(CALL_LIST_APPEND) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_LIST_APPEND; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_LIST_APPEND); +@@ -2375,28 +3051,54 @@ + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *self_o = PyStackRef_AsPyObjectBorrow(self); + PyInterpreterState *interp = tstate->interp; +- DEOPT_IF(callable_o != interp->callable_cache.list_append, CALL); ++ if (callable_o != interp->callable_cache.list_append) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + assert(self_o != NULL); +- DEOPT_IF(!PyList_Check(self_o), CALL); +- DEOPT_IF(!LOCK_OBJECT(self_o), CALL); ++ if (!PyList_Check(self_o)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } ++ if (!LOCK_OBJECT(self_o)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + STAT_INC(CALL, hit); + int err = _PyList_AppendTakeRef((PyListObject *)self_o, PyStackRef_AsPyObjectSteal(arg)); + UNLOCK_OBJECT(self_o); ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(self); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(callable); +- if (err) goto pop_3_error; ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (err) { ++ JUMP_TO_LABEL(error); ++ } + #if TIER_ONE + // Skip the following POP_TOP. This is done here in tier one, and + // during trace projection in tier two: + assert(next_instr->op.code == POP_TOP); + SKIP_OVER(1); + #endif +- stack_pointer += -3; +- assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(CALL_METHOD_DESCRIPTOR_FAST) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_METHOD_DESCRIPTOR_FAST; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_METHOD_DESCRIPTOR_FAST); +@@ -2414,31 +3116,42 @@ + callable = &stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; + /* Builtin METH_FASTCALL methods, without keywords */ +- DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL); ++ if (!Py_IS_TYPE(method, &PyMethodDescr_Type)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + PyMethodDef *meth = method->d_method; +- DEOPT_IF(meth->ml_flags != METH_FASTCALL, CALL); +- PyObject *self = PyStackRef_AsPyObjectBorrow(args[0]); +- DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL); ++ if (meth->ml_flags != METH_FASTCALL) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } ++ PyObject *self = PyStackRef_AsPyObjectBorrow(arguments[0]); ++ if (!Py_IS_TYPE(self, method->d_common.d_type)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + STAT_INC(CALL, hit); + int nargs = total_args - 1; +- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + PyStackRef_CLOSE(callable[0]); +- PyStackRef_CLOSE(self_or_null[0]); ++ PyStackRef_XCLOSE(self_or_null[0]); + for (int _i = oparg; --_i >= 0;) { + PyStackRef_CLOSE(args[_i]); + } +- { +- stack_pointer += -2 - oparg; +- assert(WITHIN_STACK_BOUNDS()); +- goto error; +- } ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_LABEL(error); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyCFunctionFast cfunc = +@@ -2447,15 +3160,15 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); +- /* Clear the stack of the arguments. */ +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); +- } + PyStackRef_CLOSE(callable[0]); ++ PyStackRef_XCLOSE(self_or_null[0]); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); ++ } + if (res_o == NULL) { + stack_pointer += -2 - oparg; + assert(WITHIN_STACK_BOUNDS()); +- goto error; ++ JUMP_TO_LABEL(error); + } + res = PyStackRef_FromPyObjectSteal(res_o); + } +@@ -2470,7 +3183,9 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err != 0) goto error; ++ if (err != 0) { ++ JUMP_TO_LABEL(error); ++ } + stack_pointer += 1 + oparg; + assert(WITHIN_STACK_BOUNDS()); + } +@@ -2482,6 +3197,12 @@ + } + + TARGET(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS); +@@ -2499,31 +3220,42 @@ + callable = &stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; +- DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL); ++ if (!Py_IS_TYPE(method, &PyMethodDescr_Type)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + PyMethodDef *meth = method->d_method; +- DEOPT_IF(meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS), CALL); ++ if (meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + PyTypeObject *d_type = method->d_common.d_type; +- PyObject *self = PyStackRef_AsPyObjectBorrow(args[0]); +- DEOPT_IF(!Py_IS_TYPE(self, d_type), CALL); ++ PyObject *self = PyStackRef_AsPyObjectBorrow(arguments[0]); ++ if (!Py_IS_TYPE(self, d_type)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + STAT_INC(CALL, hit); + int nargs = total_args - 1; +- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + PyStackRef_CLOSE(callable[0]); +- PyStackRef_CLOSE(self_or_null[0]); ++ PyStackRef_XCLOSE(self_or_null[0]); + for (int _i = oparg; --_i >= 0;) { + PyStackRef_CLOSE(args[_i]); + } +- { +- stack_pointer += -2 - oparg; +- assert(WITHIN_STACK_BOUNDS()); +- goto error; +- } ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_LABEL(error); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyCFunctionFastWithKeywords cfunc = +@@ -2532,15 +3264,15 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); +- /* Free the arguments. */ +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); +- } + PyStackRef_CLOSE(callable[0]); ++ PyStackRef_XCLOSE(self_or_null[0]); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); ++ } + if (res_o == NULL) { + stack_pointer += -2 - oparg; + assert(WITHIN_STACK_BOUNDS()); +- goto error; ++ JUMP_TO_LABEL(error); + } + res = PyStackRef_FromPyObjectSteal(res_o); + } +@@ -2555,7 +3287,9 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err != 0) goto error; ++ if (err != 0) { ++ JUMP_TO_LABEL(error); ++ } + stack_pointer += 1 + oparg; + assert(WITHIN_STACK_BOUNDS()); + } +@@ -2567,6 +3301,12 @@ + } + + TARGET(CALL_METHOD_DESCRIPTOR_NOARGS) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_METHOD_DESCRIPTOR_NOARGS; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_METHOD_DESCRIPTOR_NOARGS); +@@ -2589,16 +3329,36 @@ + args--; + total_args++; + } +- DEOPT_IF(total_args != 1, CALL); ++ if (total_args != 1) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; +- DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL); ++ if (!Py_IS_TYPE(method, &PyMethodDescr_Type)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + PyMethodDef *meth = method->d_method; + _PyStackRef self_stackref = args[0]; + PyObject *self = PyStackRef_AsPyObjectBorrow(self_stackref); +- DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL); +- DEOPT_IF(meth->ml_flags != METH_NOARGS, CALL); ++ if (!Py_IS_TYPE(self, method->d_common.d_type)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } ++ if (meth->ml_flags != METH_NOARGS) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + // CPython promises to check all non-vectorcall function calls. +- DEOPT_IF(tstate->c_recursion_remaining <= 0, CALL); ++ if (tstate->c_recursion_remaining <= 0) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + STAT_INC(CALL, hit); + PyCFunction cfunc = meth->ml_meth; + _Py_EnterRecursiveCallTstateUnchecked(tstate); +@@ -2607,12 +3367,16 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + _Py_LeaveRecursiveCallTstate(tstate); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(self_stackref); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(callable[0]); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + if (res_o == NULL) { +- stack_pointer += -2 - oparg; +- assert(WITHIN_STACK_BOUNDS()); +- goto error; ++ JUMP_TO_LABEL(error); + } + res = PyStackRef_FromPyObjectSteal(res_o); + } +@@ -2621,24 +3385,32 @@ + _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); + QSBR_QUIESCENT_STATE(tstate); + if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { +- stack_pointer[-2 - oparg] = res; +- stack_pointer += -1 - oparg; ++ stack_pointer[0] = res; ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err != 0) goto error; +- stack_pointer += 1 + oparg; ++ if (err != 0) { ++ JUMP_TO_LABEL(error); ++ } ++ stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + } + } +- stack_pointer[-2 - oparg] = res; +- stack_pointer += -1 - oparg; ++ stack_pointer[0] = res; ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(CALL_METHOD_DESCRIPTOR_O) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_METHOD_DESCRIPTOR_O; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_METHOD_DESCRIPTOR_O); +@@ -2656,21 +3428,42 @@ + callable = &stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; +- DEOPT_IF(total_args != 2, CALL); +- DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL); ++ if (total_args != 2) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } ++ if (!Py_IS_TYPE(method, &PyMethodDescr_Type)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + PyMethodDef *meth = method->d_method; +- DEOPT_IF(meth->ml_flags != METH_O, CALL); ++ if (meth->ml_flags != METH_O) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + // CPython promises to check all non-vectorcall function calls. +- DEOPT_IF(tstate->c_recursion_remaining <= 0, CALL); +- _PyStackRef arg_stackref = args[1]; +- _PyStackRef self_stackref = args[0]; +- DEOPT_IF(!Py_IS_TYPE(PyStackRef_AsPyObjectBorrow(self_stackref), +- method->d_common.d_type), CALL); ++ if (tstate->c_recursion_remaining <= 0) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } ++ _PyStackRef arg_stackref = arguments[1]; ++ _PyStackRef self_stackref = arguments[0]; ++ if (!Py_IS_TYPE(PyStackRef_AsPyObjectBorrow(self_stackref), ++ method->d_common.d_type)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + STAT_INC(CALL, hit); + PyCFunction cfunc = meth->ml_meth; + _Py_EnterRecursiveCallTstateUnchecked(tstate); +@@ -2681,13 +3474,15 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + _Py_LeaveRecursiveCallTstate(tstate); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); +- PyStackRef_CLOSE(self_stackref); +- PyStackRef_CLOSE(arg_stackref); + PyStackRef_CLOSE(callable[0]); ++ PyStackRef_XCLOSE(self_or_null[0]); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); ++ } + if (res_o == NULL) { + stack_pointer += -2 - oparg; + assert(WITHIN_STACK_BOUNDS()); +- goto error; ++ JUMP_TO_LABEL(error); + } + res = PyStackRef_FromPyObjectSteal(res_o); + } +@@ -2702,7 +3497,9 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err != 0) goto error; ++ if (err != 0) { ++ JUMP_TO_LABEL(error); ++ } + stack_pointer += 1 + oparg; + assert(WITHIN_STACK_BOUNDS()); + } +@@ -2714,9 +3511,16 @@ + } + + TARGET(CALL_NON_PY_GENERAL) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_NON_PY_GENERAL; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_NON_PY_GENERAL); ++ opcode = CALL_NON_PY_GENERAL; + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); + _PyStackRef *callable; + _PyStackRef *self_or_null; +@@ -2728,8 +3532,16 @@ + { + callable = &stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); +- DEOPT_IF(PyFunction_Check(callable_o), CALL); +- DEOPT_IF(Py_TYPE(callable_o) == &PyMethod_Type, CALL); ++ if (PyFunction_Check(callable_o)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } ++ if (Py_TYPE(callable_o) == &PyMethod_Type) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + } + // _CALL_NON_PY_GENERAL + { +@@ -2740,23 +3552,22 @@ + #endif + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + /* Callable is not a normal Python function */ +- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + PyStackRef_CLOSE(callable[0]); +- PyStackRef_CLOSE(self_or_null[0]); ++ PyStackRef_XCLOSE(self_or_null[0]); + for (int _i = oparg; --_i >= 0;) { + PyStackRef_CLOSE(args[_i]); + } +- { +- stack_pointer += -2 - oparg; +- assert(WITHIN_STACK_BOUNDS()); +- goto error; +- } ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_LABEL(error); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *res_o = PyObject_Vectorcall( +@@ -2767,13 +3578,14 @@ + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + PyStackRef_CLOSE(callable[0]); +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); ++ PyStackRef_XCLOSE(self_or_null[0]); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); + } + if (res_o == NULL) { + stack_pointer += -2 - oparg; + assert(WITHIN_STACK_BOUNDS()); +- goto error; ++ JUMP_TO_LABEL(error); + } + res = PyStackRef_FromPyObjectSteal(res_o); + } +@@ -2788,7 +3600,9 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err != 0) goto error; ++ if (err != 0) { ++ JUMP_TO_LABEL(error); ++ } + stack_pointer += 1 + oparg; + assert(WITHIN_STACK_BOUNDS()); + } +@@ -2800,7 +3614,13 @@ + } + + TARGET(CALL_PY_EXACT_ARGS) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_PY_EXACT_ARGS; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_PY_EXACT_ARGS); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); +@@ -2811,16 +3631,28 @@ + /* Skip 1 cache entry */ + // _CHECK_PEP_523 + { +- DEOPT_IF(tstate->interp->eval_frame, CALL); ++ if (tstate->interp->eval_frame) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + } + // _CHECK_FUNCTION_VERSION + { + callable = &stack_pointer[-2 - oparg]; + uint32_t func_version = read_u32(&this_instr[2].cache); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); +- DEOPT_IF(!PyFunction_Check(callable_o), CALL); ++ if (!PyFunction_Check(callable_o)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + PyFunctionObject *func = (PyFunctionObject *)callable_o; +- DEOPT_IF(func->func_version != func_version, CALL); ++ if (func->func_version != func_version) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + } + // _CHECK_FUNCTION_EXACT_ARGS + { +@@ -2829,15 +3661,27 @@ + assert(PyFunction_Check(callable_o)); + PyFunctionObject *func = (PyFunctionObject *)callable_o; + PyCodeObject *code = (PyCodeObject *)func->func_code; +- DEOPT_IF(code->co_argcount != oparg + (!PyStackRef_IsNull(self_or_null[0])), CALL); ++ if (code->co_argcount != oparg + (!PyStackRef_IsNull(self_or_null[0]))) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + } + // _CHECK_STACK_SPACE + { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + PyFunctionObject *func = (PyFunctionObject *)callable_o; + PyCodeObject *code = (PyCodeObject *)func->func_code; +- DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL); +- DEOPT_IF(tstate->py_recursion_remaining <= 1, CALL); ++ if (!_PyThreadState_HasStackSpace(tstate, code->co_framesize)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } ++ if (tstate->py_recursion_remaining <= 1) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + } + // _INIT_CALL_PY_EXACT_ARGS + { +@@ -2881,7 +3725,13 @@ + } + + TARGET(CALL_PY_GENERAL) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_PY_GENERAL; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_PY_GENERAL); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); +@@ -2892,16 +3742,28 @@ + /* Skip 1 cache entry */ + // _CHECK_PEP_523 + { +- DEOPT_IF(tstate->interp->eval_frame, CALL); ++ if (tstate->interp->eval_frame) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + } + // _CHECK_FUNCTION_VERSION + { + callable = &stack_pointer[-2 - oparg]; + uint32_t func_version = read_u32(&this_instr[2].cache); + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); +- DEOPT_IF(!PyFunction_Check(callable_o), CALL); ++ if (!PyFunction_Check(callable_o)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + PyFunctionObject *func = (PyFunctionObject *)callable_o; +- DEOPT_IF(func->func_version != func_version, CALL); ++ if (func->func_version != func_version) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + } + // _PY_FRAME_GENERAL + { +@@ -2927,7 +3789,7 @@ + stack_pointer += -2 - oparg; + assert(WITHIN_STACK_BOUNDS()); + if (temp == NULL) { +- goto error; ++ JUMP_TO_LABEL(error); + } + new_frame = temp; + } +@@ -2959,6 +3821,12 @@ + } + + TARGET(CALL_STR_1) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_STR_1; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_STR_1); +@@ -2977,14 +3845,28 @@ + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *arg_o = PyStackRef_AsPyObjectBorrow(arg); + assert(oparg == 1); +- DEOPT_IF(!PyStackRef_IsNull(null), CALL); +- DEOPT_IF(callable_o != (PyObject *)&PyUnicode_Type, CALL); ++ if (!PyStackRef_IsNull(null)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } ++ if (callable_o != (PyObject *)&PyUnicode_Type) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + STAT_INC(CALL, hit); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *res_o = PyObject_Str(arg_o); + stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -3; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(arg); +- if (res_o == NULL) goto pop_3_error; ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (res_o == NULL) { ++ JUMP_TO_LABEL(error); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + } + // _CHECK_PERIODIC +@@ -2992,24 +3874,32 @@ + _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); + QSBR_QUIESCENT_STATE(tstate); + if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { +- stack_pointer[-3] = res; +- stack_pointer += -2; ++ stack_pointer[0] = res; ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err != 0) goto error; +- stack_pointer += 2; ++ if (err != 0) { ++ JUMP_TO_LABEL(error); ++ } ++ stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + } + } +- stack_pointer[-3] = res; +- stack_pointer += -2; ++ stack_pointer[0] = res; ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(CALL_TUPLE_1) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_TUPLE_1; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_TUPLE_1); +@@ -3028,14 +3918,28 @@ + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *arg_o = PyStackRef_AsPyObjectBorrow(arg); + assert(oparg == 1); +- DEOPT_IF(!PyStackRef_IsNull(null), CALL); +- DEOPT_IF(callable_o != (PyObject *)&PyTuple_Type, CALL); ++ if (!PyStackRef_IsNull(null)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } ++ if (callable_o != (PyObject *)&PyTuple_Type) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + STAT_INC(CALL, hit); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *res_o = PySequence_Tuple(arg_o); + stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -3; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(arg); +- if (res_o == NULL) goto pop_3_error; ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (res_o == NULL) { ++ JUMP_TO_LABEL(error); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + } + // _CHECK_PERIODIC +@@ -3043,24 +3947,32 @@ + _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); + QSBR_QUIESCENT_STATE(tstate); + if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { +- stack_pointer[-3] = res; +- stack_pointer += -2; ++ stack_pointer[0] = res; ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err != 0) goto error; +- stack_pointer += 2; ++ if (err != 0) { ++ JUMP_TO_LABEL(error); ++ } ++ stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + } + } +- stack_pointer[-3] = res; +- stack_pointer += -2; ++ stack_pointer[0] = res; ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(CALL_TYPE_1) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CALL_TYPE_1; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_TYPE_1); +@@ -3077,18 +3989,32 @@ + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyObject *arg_o = PyStackRef_AsPyObjectBorrow(arg); + assert(oparg == 1); +- DEOPT_IF(!PyStackRef_IsNull(null), CALL); +- DEOPT_IF(callable_o != (PyObject *)&PyType_Type, CALL); ++ if (!PyStackRef_IsNull(null)) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } ++ if (callable_o != (PyObject *)&PyType_Type) { ++ UPDATE_MISS_STATS(CALL); ++ assert(_PyOpcode_Deopt[opcode] == (CALL)); ++ JUMP_TO_PREDICTED(CALL); ++ } + STAT_INC(CALL, hit); + res = PyStackRef_FromPyObjectSteal(Py_NewRef(Py_TYPE(arg_o))); +- PyStackRef_CLOSE(arg); + stack_pointer[-3] = res; + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(arg); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + DISPATCH(); + } + + TARGET(CHECK_EG_MATCH) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CHECK_EG_MATCH; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(CHECK_EG_MATCH); +@@ -3106,19 +4032,23 @@ + if (err < 0) { + PyStackRef_CLOSE(exc_value_st); + PyStackRef_CLOSE(match_type_st); +- goto pop_2_error; ++ JUMP_TO_LABEL(pop_2_error); + } + PyObject *match_o = NULL; + PyObject *rest_o = NULL; + _PyFrame_SetStackPointer(frame, stack_pointer); +- int res = _PyEval_ExceptionGroupMatch(exc_value, match_type, ++ int res = _PyEval_ExceptionGroupMatch(frame, exc_value, match_type, + &match_o, &rest_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(exc_value_st); + PyStackRef_CLOSE(match_type_st); +- if (res < 0) goto pop_2_error; ++ if (res < 0) { ++ JUMP_TO_LABEL(pop_2_error); ++ } + assert((match_o == NULL) == (rest_o == NULL)); +- if (match_o == NULL) goto pop_2_error; ++ if (match_o == NULL) { ++ JUMP_TO_LABEL(pop_2_error); ++ } + if (!Py_IsNone(match_o)) { + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); +@@ -3136,6 +4066,10 @@ + } + + TARGET(CHECK_EXC_MATCH) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CHECK_EXC_MATCH; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(CHECK_EXC_MATCH); +@@ -3152,7 +4086,7 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err < 0) { + PyStackRef_CLOSE(right); +- goto pop_1_error; ++ JUMP_TO_LABEL(pop_1_error); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + int res = PyErr_GivenExceptionMatches(left_o, right_o); +@@ -3164,8 +4098,13 @@ + } + + TARGET(CLEANUP_THROW) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CLEANUP_THROW; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(CLEANUP_THROW); + _PyStackRef sub_iter_st; +@@ -3177,7 +4116,9 @@ + last_sent_val_st = stack_pointer[-2]; + sub_iter_st = stack_pointer[-3]; + PyObject *exc_value = PyStackRef_AsPyObjectBorrow(exc_value_st); ++ #ifndef Py_TAIL_CALL_INTERP + assert(throwflag); ++ #endif + assert(exc_value && PyExceptionInstance_Check(exc_value)); + _PyFrame_SetStackPointer(frame, stack_pointer); + int matches = PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration); +@@ -3194,7 +4135,8 @@ + _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value)); + monitor_reraise(tstate, frame, this_instr); + stack_pointer = _PyFrame_GetStackPointer(frame); +- goto exception_unwind; ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ JUMP_TO_LABEL(exception_unwind); + } + stack_pointer[-3] = none; + stack_pointer[-2] = value; +@@ -3204,10 +4146,14 @@ + } + + TARGET(COMPARE_OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = COMPARE_OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(COMPARE_OP); +- PREDICTED(COMPARE_OP); ++ PREDICTED_COMPARE_OP:; + _Py_CODEUNIT* const this_instr = next_instr - 2; + (void)this_instr; + _PyStackRef left; +@@ -3219,7 +4165,7 @@ + left = stack_pointer[-2]; + uint16_t counter = read_u16(&this_instr[1].cache); + (void)counter; +- #if ENABLE_SPECIALIZATION ++ #if ENABLE_SPECIALIZATION_FT + if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { + next_instr = this_instr; + _PyFrame_SetStackPointer(frame, stack_pointer); +@@ -3229,7 +4175,7 @@ + } + OPCODE_DEFERRED_INC(COMPARE_OP); + ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); +- #endif /* ENABLE_SPECIALIZATION */ ++ #endif /* ENABLE_SPECIALIZATION_FT */ + } + // _COMPARE_OP + { +@@ -3241,15 +4187,19 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(left); + PyStackRef_CLOSE(right); +- if (res_o == NULL) goto pop_2_error; ++ if (res_o == NULL) { ++ JUMP_TO_LABEL(pop_2_error); ++ } + if (oparg & 16) { + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + int res_bool = PyObject_IsTrue(res_o); +- stack_pointer = _PyFrame_GetStackPointer(frame); + Py_DECREF(res_o); +- if (res_bool < 0) goto error; ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (res_bool < 0) { ++ JUMP_TO_LABEL(error); ++ } + res = res_bool ? PyStackRef_True : PyStackRef_False; + } + else { +@@ -3265,6 +4215,12 @@ + } + + TARGET(COMPARE_OP_FLOAT) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = COMPARE_OP_FLOAT; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(COMPARE_OP_FLOAT); +@@ -3278,8 +4234,16 @@ + left = stack_pointer[-2]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); +- DEOPT_IF(!PyFloat_CheckExact(left_o), COMPARE_OP); +- DEOPT_IF(!PyFloat_CheckExact(right_o), COMPARE_OP); ++ if (!PyFloat_CheckExact(left_o)) { ++ UPDATE_MISS_STATS(COMPARE_OP); ++ assert(_PyOpcode_Deopt[opcode] == (COMPARE_OP)); ++ JUMP_TO_PREDICTED(COMPARE_OP); ++ } ++ if (!PyFloat_CheckExact(right_o)) { ++ UPDATE_MISS_STATS(COMPARE_OP); ++ assert(_PyOpcode_Deopt[opcode] == (COMPARE_OP)); ++ JUMP_TO_PREDICTED(COMPARE_OP); ++ } + } + /* Skip 1 cache entry */ + // _COMPARE_OP_FLOAT +@@ -3303,6 +4267,12 @@ + } + + TARGET(COMPARE_OP_INT) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = COMPARE_OP_INT; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(COMPARE_OP_INT); +@@ -3316,16 +4286,32 @@ + left = stack_pointer[-2]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); +- DEOPT_IF(!PyLong_CheckExact(left_o), COMPARE_OP); +- DEOPT_IF(!PyLong_CheckExact(right_o), COMPARE_OP); ++ if (!PyLong_CheckExact(left_o)) { ++ UPDATE_MISS_STATS(COMPARE_OP); ++ assert(_PyOpcode_Deopt[opcode] == (COMPARE_OP)); ++ JUMP_TO_PREDICTED(COMPARE_OP); ++ } ++ if (!PyLong_CheckExact(right_o)) { ++ UPDATE_MISS_STATS(COMPARE_OP); ++ assert(_PyOpcode_Deopt[opcode] == (COMPARE_OP)); ++ JUMP_TO_PREDICTED(COMPARE_OP); ++ } + } + /* Skip 1 cache entry */ + // _COMPARE_OP_INT + { + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); +- DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left_o), COMPARE_OP); +- DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)right_o), COMPARE_OP); ++ if (!_PyLong_IsCompact((PyLongObject *)left_o)) { ++ UPDATE_MISS_STATS(COMPARE_OP); ++ assert(_PyOpcode_Deopt[opcode] == (COMPARE_OP)); ++ JUMP_TO_PREDICTED(COMPARE_OP); ++ } ++ if (!_PyLong_IsCompact((PyLongObject *)right_o)) { ++ UPDATE_MISS_STATS(COMPARE_OP); ++ assert(_PyOpcode_Deopt[opcode] == (COMPARE_OP)); ++ JUMP_TO_PREDICTED(COMPARE_OP); ++ } + STAT_INC(COMPARE_OP, hit); + assert(_PyLong_DigitCount((PyLongObject *)left_o) <= 1 && + _PyLong_DigitCount((PyLongObject *)right_o) <= 1); +@@ -3345,6 +4331,12 @@ + } + + TARGET(COMPARE_OP_STR) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = COMPARE_OP_STR; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(COMPARE_OP_STR); +@@ -3358,8 +4350,16 @@ + left = stack_pointer[-2]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); +- DEOPT_IF(!PyUnicode_CheckExact(left_o), COMPARE_OP); +- DEOPT_IF(!PyUnicode_CheckExact(right_o), COMPARE_OP); ++ if (!PyUnicode_CheckExact(left_o)) { ++ UPDATE_MISS_STATS(COMPARE_OP); ++ assert(_PyOpcode_Deopt[opcode] == (COMPARE_OP)); ++ JUMP_TO_PREDICTED(COMPARE_OP); ++ } ++ if (!PyUnicode_CheckExact(right_o)) { ++ UPDATE_MISS_STATS(COMPARE_OP); ++ assert(_PyOpcode_Deopt[opcode] == (COMPARE_OP)); ++ JUMP_TO_PREDICTED(COMPARE_OP); ++ } + } + /* Skip 1 cache entry */ + // _COMPARE_OP_STR +@@ -3384,10 +4384,14 @@ + } + + TARGET(CONTAINS_OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CONTAINS_OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(CONTAINS_OP); +- PREDICTED(CONTAINS_OP); ++ PREDICTED_CONTAINS_OP:; + _Py_CODEUNIT* const this_instr = next_instr - 2; + (void)this_instr; + _PyStackRef left; +@@ -3420,7 +4424,9 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(left); + PyStackRef_CLOSE(right); +- if (res < 0) goto pop_2_error; ++ if (res < 0) { ++ JUMP_TO_LABEL(pop_2_error); ++ } + b = (res ^ oparg) ? PyStackRef_True : PyStackRef_False; + } + stack_pointer[-2] = b; +@@ -3430,6 +4436,12 @@ + } + + TARGET(CONTAINS_OP_DICT) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CONTAINS_OP_DICT; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(CONTAINS_OP_DICT); +@@ -3442,14 +4454,20 @@ + left = stack_pointer[-2]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); +- DEOPT_IF(!PyDict_CheckExact(right_o), CONTAINS_OP); ++ if (!PyDict_CheckExact(right_o)) { ++ UPDATE_MISS_STATS(CONTAINS_OP); ++ assert(_PyOpcode_Deopt[opcode] == (CONTAINS_OP)); ++ JUMP_TO_PREDICTED(CONTAINS_OP); ++ } + STAT_INC(CONTAINS_OP, hit); + _PyFrame_SetStackPointer(frame, stack_pointer); + int res = PyDict_Contains(right_o, left_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(left); + PyStackRef_CLOSE(right); +- if (res < 0) goto pop_2_error; ++ if (res < 0) { ++ JUMP_TO_LABEL(pop_2_error); ++ } + b = (res ^ oparg) ? PyStackRef_True : PyStackRef_False; + stack_pointer[-2] = b; + stack_pointer += -1; +@@ -3458,6 +4476,12 @@ + } + + TARGET(CONTAINS_OP_SET) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CONTAINS_OP_SET; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(CONTAINS_OP_SET); +@@ -3470,7 +4494,11 @@ + left = stack_pointer[-2]; + PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); + PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); +- DEOPT_IF(!(PySet_CheckExact(right_o) || PyFrozenSet_CheckExact(right_o)), CONTAINS_OP); ++ if (!(PySet_CheckExact(right_o) || PyFrozenSet_CheckExact(right_o))) { ++ UPDATE_MISS_STATS(CONTAINS_OP); ++ assert(_PyOpcode_Deopt[opcode] == (CONTAINS_OP)); ++ JUMP_TO_PREDICTED(CONTAINS_OP); ++ } + STAT_INC(CONTAINS_OP, hit); + // Note: both set and frozenset use the same seq_contains method! + _PyFrame_SetStackPointer(frame, stack_pointer); +@@ -3478,7 +4506,9 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(left); + PyStackRef_CLOSE(right); +- if (res < 0) goto pop_2_error; ++ if (res < 0) { ++ JUMP_TO_LABEL(pop_2_error); ++ } + b = (res ^ oparg) ? PyStackRef_True : PyStackRef_False; + stack_pointer[-2] = b; + stack_pointer += -1; +@@ -3487,6 +4517,10 @@ + } + + TARGET(CONVERT_VALUE) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = CONVERT_VALUE; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(CONVERT_VALUE); +@@ -3499,14 +4533,26 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *result_o = conv_fn(PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(value); +- if (result_o == NULL) goto pop_1_error; ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (result_o == NULL) { ++ JUMP_TO_LABEL(error); ++ } + result = PyStackRef_FromPyObjectSteal(result_o); +- stack_pointer[-1] = result; ++ stack_pointer[0] = result; ++ stack_pointer += 1; ++ assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(COPY) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = COPY; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(COPY); +@@ -3522,6 +4568,10 @@ + } + + TARGET(COPY_FREE_VARS) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = COPY_FREE_VARS; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(COPY_FREE_VARS); +@@ -3540,6 +4590,10 @@ + } + + TARGET(DELETE_ATTR) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = DELETE_ATTR; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(DELETE_ATTR); +@@ -3550,13 +4604,19 @@ + int err = PyObject_DelAttr(PyStackRef_AsPyObjectBorrow(owner), name); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(owner); +- if (err) goto pop_1_error; ++ if (err) { ++ JUMP_TO_LABEL(pop_1_error); ++ } + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(DELETE_DEREF) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = DELETE_DEREF; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(DELETE_DEREF); +@@ -3568,13 +4628,19 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg); + stack_pointer = _PyFrame_GetStackPointer(frame); +- goto error; ++ JUMP_TO_LABEL(error); + } ++ _PyFrame_SetStackPointer(frame, stack_pointer); + Py_DECREF(oldobj); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + DISPATCH(); + } + + TARGET(DELETE_FAST) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = DELETE_FAST; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(DELETE_FAST); +@@ -3586,13 +4652,21 @@ + PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames, oparg) + ); + stack_pointer = _PyFrame_GetStackPointer(frame); +- goto error; ++ JUMP_TO_LABEL(error); + } +- SETLOCAL(oparg, PyStackRef_NULL); ++ _PyStackRef tmp = GETLOCAL(oparg); ++ GETLOCAL(oparg) = PyStackRef_NULL; ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_XCLOSE(tmp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + DISPATCH(); + } + + TARGET(DELETE_GLOBAL) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = DELETE_GLOBAL; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(DELETE_GLOBAL); +@@ -3602,19 +4676,23 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + // Can't use ERROR_IF here. + if (err < 0) { +- goto error; ++ JUMP_TO_LABEL(error); + } + if (err == 0) { + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + stack_pointer = _PyFrame_GetStackPointer(frame); +- goto error; ++ JUMP_TO_LABEL(error); + } + DISPATCH(); + } + + TARGET(DELETE_NAME) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = DELETE_NAME; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(DELETE_NAME); +@@ -3626,7 +4704,7 @@ + _PyErr_Format(tstate, PyExc_SystemError, + "no locals when deleting %R", name); + stack_pointer = _PyFrame_GetStackPointer(frame); +- goto error; ++ JUMP_TO_LABEL(error); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + err = PyObject_DelItem(ns, name); +@@ -3638,12 +4716,16 @@ + NAME_ERROR_MSG, + name); + stack_pointer = _PyFrame_GetStackPointer(frame); +- goto error; ++ JUMP_TO_LABEL(error); + } + DISPATCH(); + } + + TARGET(DELETE_SUBSCR) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = DELETE_SUBSCR; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(DELETE_SUBSCR); +@@ -3658,13 +4740,19 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(container); + PyStackRef_CLOSE(sub); +- if (err) goto pop_2_error; ++ if (err) { ++ JUMP_TO_LABEL(pop_2_error); ++ } + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(DICT_MERGE) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = DICT_MERGE; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(DICT_MERGE); +@@ -3685,7 +4773,7 @@ + _PyEval_FormatKwargsError(tstate, callable_o, update_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(update); +- goto pop_1_error; ++ JUMP_TO_LABEL(pop_1_error); + } + PyStackRef_CLOSE(update); + stack_pointer += -1; +@@ -3694,6 +4782,10 @@ + } + + TARGET(DICT_UPDATE) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = DICT_UPDATE; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(DICT_UPDATE); +@@ -3718,7 +4810,7 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + } + PyStackRef_CLOSE(update); +- goto pop_1_error; ++ JUMP_TO_LABEL(pop_1_error); + } + PyStackRef_CLOSE(update); + stack_pointer += -1; +@@ -3727,8 +4819,13 @@ + } + + TARGET(END_ASYNC_FOR) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = END_ASYNC_FOR; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(END_ASYNC_FOR); + _PyStackRef awaitable_st; +@@ -3750,7 +4847,8 @@ + _PyErr_SetRaisedException(tstate, exc); + monitor_reraise(tstate, frame, this_instr); + stack_pointer = _PyFrame_GetStackPointer(frame); +- goto exception_unwind; ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ JUMP_TO_LABEL(exception_unwind); + } + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); +@@ -3758,18 +4856,32 @@ + } + + TARGET(END_FOR) { +- frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = END_FOR; ++ (void)(opcode); ++ #endif + next_instr += 1; + INSTRUCTION_STATS(END_FOR); + _PyStackRef value; + value = stack_pointer[-1]; +- PyStackRef_CLOSE(value); ++ /* Don't update instr_ptr, so that POP_ITER sees ++ * the FOR_ITER as the previous instruction. ++ * This has the benign side effect that if value is ++ * finalized it will see the location as the FOR_ITER's. ++ */ + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(value); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + DISPATCH(); + } + + TARGET(END_SEND) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = END_SEND; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(END_SEND); +@@ -3788,10 +4900,16 @@ + } + + TARGET(ENTER_EXECUTOR) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = ENTER_EXECUTOR; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(ENTER_EXECUTOR); ++ opcode = ENTER_EXECUTOR; + #ifdef _Py_TIER2 + PyCodeObject *code = _PyFrame_GetCode(frame); + _PyExecutorObject *executor = code->co_executors->executors[oparg & 255]; +@@ -3821,6 +4939,10 @@ + } + + TARGET(EXIT_INIT_CHECK) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = EXIT_INIT_CHECK; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(EXIT_INIT_CHECK); +@@ -3833,7 +4955,7 @@ + "__init__() should return None, not '%.200s'", + Py_TYPE(PyStackRef_AsPyObjectBorrow(should_be_none))->tp_name); + stack_pointer = _PyFrame_GetStackPointer(frame); +- goto error; ++ JUMP_TO_LABEL(error); + } + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); +@@ -3841,9 +4963,14 @@ + } + + TARGET(EXTENDED_ARG) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = EXTENDED_ARG; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(EXTENDED_ARG); ++ opcode = EXTENDED_ARG; + assert(oparg); + opcode = next_instr->op.code; + oparg = oparg << 8 | next_instr->op.arg; +@@ -3852,6 +4979,10 @@ + } + + TARGET(FORMAT_SIMPLE) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = FORMAT_SIMPLE; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(FORMAT_SIMPLE); +@@ -3865,18 +4996,32 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *res_o = PyObject_Format(value_o, NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(value); +- if (res_o == NULL) goto pop_1_error; ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (res_o == NULL) { ++ JUMP_TO_LABEL(error); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + } + else { + res = value; ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); + } +- stack_pointer[-1] = res; ++ stack_pointer[0] = res; ++ stack_pointer += 1; ++ assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(FORMAT_WITH_SPEC) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = FORMAT_WITH_SPEC; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(FORMAT_WITH_SPEC); +@@ -3890,7 +5035,9 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(value); + PyStackRef_CLOSE(fmt_spec); +- if (res_o == NULL) goto pop_2_error; ++ if (res_o == NULL) { ++ JUMP_TO_LABEL(pop_2_error); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -3899,10 +5046,14 @@ + } + + TARGET(FOR_ITER) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = FOR_ITER; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(FOR_ITER); +- PREDICTED(FOR_ITER); ++ PREDICTED_FOR_ITER:; + _Py_CODEUNIT* const this_instr = next_instr - 2; + (void)this_instr; + _PyStackRef iter; +@@ -3937,7 +5088,7 @@ + int matches = _PyErr_ExceptionMatches(tstate, PyExc_StopIteration); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (!matches) { +- goto error; ++ JUMP_TO_LABEL(error); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyEval_MonitorRaise(tstate, frame, this_instr); +@@ -3947,10 +5098,8 @@ + /* iterator ended normally */ + assert(next_instr[oparg].op.code == END_FOR || + next_instr[oparg].op.code == INSTRUMENTED_END_FOR); +- PyStackRef_CLOSE(iter); +- STACK_SHRINK(1); +- /* Jump forward oparg, then skip following END_FOR and POP_TOP instruction */ +- JUMPBY(oparg + 2); ++ /* Jump forward oparg, then skip following END_FOR */ ++ JUMPBY(oparg + 1); + DISPATCH(); + } + next = PyStackRef_FromPyObjectSteal(next_o); +@@ -3963,6 +5112,12 @@ + } + + TARGET(FOR_ITER_GEN) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = FOR_ITER_GEN; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(FOR_ITER_GEN); +@@ -3973,14 +5128,26 @@ + /* Skip 1 cache entry */ + // _CHECK_PEP_523 + { +- DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); ++ if (tstate->interp->eval_frame) { ++ UPDATE_MISS_STATS(FOR_ITER); ++ assert(_PyOpcode_Deopt[opcode] == (FOR_ITER)); ++ JUMP_TO_PREDICTED(FOR_ITER); ++ } + } + // _FOR_ITER_GEN_FRAME + { + iter = stack_pointer[-1]; + PyGenObject *gen = (PyGenObject *)PyStackRef_AsPyObjectBorrow(iter); +- DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); +- DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, FOR_ITER); ++ if (Py_TYPE(gen) != &PyGen_Type) { ++ UPDATE_MISS_STATS(FOR_ITER); ++ assert(_PyOpcode_Deopt[opcode] == (FOR_ITER)); ++ JUMP_TO_PREDICTED(FOR_ITER); ++ } ++ if (gen->gi_frame_state >= FRAME_EXECUTING) { ++ UPDATE_MISS_STATS(FOR_ITER); ++ assert(_PyOpcode_Deopt[opcode] == (FOR_ITER)); ++ JUMP_TO_PREDICTED(FOR_ITER); ++ } + STAT_INC(FOR_ITER, hit); + gen_frame = &gen->gi_iframe; + _PyFrame_StackPush(gen_frame, PyStackRef_None); +@@ -4011,6 +5178,12 @@ + } + + TARGET(FOR_ITER_LIST) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = FOR_ITER_LIST; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(FOR_ITER_LIST); +@@ -4021,7 +5194,11 @@ + // _ITER_CHECK_LIST + { + iter = stack_pointer[-1]; +- DEOPT_IF(Py_TYPE(PyStackRef_AsPyObjectBorrow(iter)) != &PyListIter_Type, FOR_ITER); ++ if (Py_TYPE(PyStackRef_AsPyObjectBorrow(iter)) != &PyListIter_Type) { ++ UPDATE_MISS_STATS(FOR_ITER); ++ assert(_PyOpcode_Deopt[opcode] == (FOR_ITER)); ++ JUMP_TO_PREDICTED(FOR_ITER); ++ } + } + // _ITER_JUMP_LIST + { +@@ -4035,13 +5212,13 @@ + #ifndef Py_GIL_DISABLED + if (seq != NULL) { + it->it_seq = NULL; ++ _PyFrame_SetStackPointer(frame, stack_pointer); + Py_DECREF(seq); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + } + #endif +- PyStackRef_CLOSE(iter); +- STACK_SHRINK(1); +- /* Jump forward oparg, then skip following END_FOR and POP_TOP instructions */ +- JUMPBY(oparg + 2); ++ /* Jump forward oparg, then skip following END_FOR instruction */ ++ JUMPBY(oparg + 1); + DISPATCH(); + } + } +@@ -4062,6 +5239,12 @@ + } + + TARGET(FOR_ITER_RANGE) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = FOR_ITER_RANGE; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(FOR_ITER_RANGE); +@@ -4073,7 +5256,11 @@ + { + iter = stack_pointer[-1]; + _PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter); +- DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); ++ if (Py_TYPE(r) != &PyRangeIter_Type) { ++ UPDATE_MISS_STATS(FOR_ITER); ++ assert(_PyOpcode_Deopt[opcode] == (FOR_ITER)); ++ JUMP_TO_PREDICTED(FOR_ITER); ++ } + } + // _ITER_JUMP_RANGE + { +@@ -4081,10 +5268,8 @@ + assert(Py_TYPE(r) == &PyRangeIter_Type); + STAT_INC(FOR_ITER, hit); + if (r->len <= 0) { +- STACK_SHRINK(1); +- PyStackRef_CLOSE(iter); +- // Jump over END_FOR and POP_TOP instructions. +- JUMPBY(oparg + 2); ++ // Jump over END_FOR instruction. ++ JUMPBY(oparg + 1); + DISPATCH(); + } + } +@@ -4097,7 +5282,9 @@ + r->start = value + r->step; + r->len--; + PyObject *res = PyLong_FromLong(value); +- if (res == NULL) goto error; ++ if (res == NULL) { ++ JUMP_TO_LABEL(error); ++ } + next = PyStackRef_FromPyObjectSteal(res); + } + stack_pointer[0] = next; +@@ -4107,6 +5294,12 @@ + } + + TARGET(FOR_ITER_TUPLE) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = FOR_ITER_TUPLE; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(FOR_ITER_TUPLE); +@@ -4117,7 +5310,11 @@ + // _ITER_CHECK_TUPLE + { + iter = stack_pointer[-1]; +- DEOPT_IF(Py_TYPE(PyStackRef_AsPyObjectBorrow(iter)) != &PyTupleIter_Type, FOR_ITER); ++ if (Py_TYPE(PyStackRef_AsPyObjectBorrow(iter)) != &PyTupleIter_Type) { ++ UPDATE_MISS_STATS(FOR_ITER); ++ assert(_PyOpcode_Deopt[opcode] == (FOR_ITER)); ++ JUMP_TO_PREDICTED(FOR_ITER); ++ } + } + // _ITER_JUMP_TUPLE + { +@@ -4129,12 +5326,12 @@ + if (seq == NULL || it->it_index >= PyTuple_GET_SIZE(seq)) { + if (seq != NULL) { + it->it_seq = NULL; ++ _PyFrame_SetStackPointer(frame, stack_pointer); + Py_DECREF(seq); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + } +- PyStackRef_CLOSE(iter); +- STACK_SHRINK(1); +- /* Jump forward oparg, then skip following END_FOR and POP_TOP instructions */ +- JUMPBY(oparg + 2); ++ /* Jump forward oparg, then skip following END_FOR instruction */ ++ JUMPBY(oparg + 1); + DISPATCH(); + } + } +@@ -4155,6 +5352,10 @@ + } + + TARGET(GET_AITER) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = GET_AITER; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(GET_AITER); +@@ -4176,13 +5377,15 @@ + type->tp_name); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(obj); +- goto pop_1_error; ++ JUMP_TO_LABEL(pop_1_error); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + iter_o = (*getter)(obj_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(obj); +- if (iter_o == NULL) goto pop_1_error; ++ if (iter_o == NULL) { ++ JUMP_TO_LABEL(pop_1_error); ++ } + if (Py_TYPE(iter_o)->tp_as_async == NULL || + Py_TYPE(iter_o)->tp_as_async->am_anext == NULL) { + stack_pointer += -1; +@@ -4192,9 +5395,9 @@ + "'async for' received an object from __aiter__ " + "that does not implement __anext__: %.100s", + Py_TYPE(iter_o)->tp_name); +- stack_pointer = _PyFrame_GetStackPointer(frame); + Py_DECREF(iter_o); +- goto error; ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ JUMP_TO_LABEL(error); + } + iter = PyStackRef_FromPyObjectSteal(iter_o); + stack_pointer[-1] = iter; +@@ -4202,6 +5405,10 @@ + } + + TARGET(GET_ANEXT) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = GET_ANEXT; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(GET_ANEXT); +@@ -4212,7 +5419,7 @@ + PyObject *awaitable_o = _PyEval_GetANext(PyStackRef_AsPyObjectBorrow(aiter)); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (awaitable_o == NULL) { +- goto error; ++ JUMP_TO_LABEL(error); + } + awaitable = PyStackRef_FromPyObjectSteal(awaitable_o); + stack_pointer[0] = awaitable; +@@ -4222,6 +5429,10 @@ + } + + TARGET(GET_AWAITABLE) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = GET_AWAITABLE; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(GET_AWAITABLE); +@@ -4232,13 +5443,19 @@ + PyObject *iter_o = _PyEval_GetAwaitable(PyStackRef_AsPyObjectBorrow(iterable), oparg); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(iterable); +- if (iter_o == NULL) goto pop_1_error; ++ if (iter_o == NULL) { ++ JUMP_TO_LABEL(pop_1_error); ++ } + iter = PyStackRef_FromPyObjectSteal(iter_o); + stack_pointer[-1] = iter; + DISPATCH(); + } + + TARGET(GET_ITER) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = GET_ITER; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(GET_ITER); +@@ -4250,13 +5467,19 @@ + PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable)); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(iterable); +- if (iter_o == NULL) goto pop_1_error; ++ if (iter_o == NULL) { ++ JUMP_TO_LABEL(pop_1_error); ++ } + iter = PyStackRef_FromPyObjectSteal(iter_o); + stack_pointer[-1] = iter; + DISPATCH(); + } + + TARGET(GET_LEN) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = GET_LEN; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(GET_LEN); +@@ -4267,9 +5490,13 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + Py_ssize_t len_i = PyObject_Length(PyStackRef_AsPyObjectBorrow(obj)); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (len_i < 0) goto error; ++ if (len_i < 0) { ++ JUMP_TO_LABEL(error); ++ } + PyObject *len_o = PyLong_FromSsize_t(len_i); +- if (len_o == NULL) goto error; ++ if (len_o == NULL) { ++ JUMP_TO_LABEL(error); ++ } + len = PyStackRef_FromPyObjectSteal(len_o); + stack_pointer[0] = len; + stack_pointer += 1; +@@ -4278,6 +5505,10 @@ + } + + TARGET(GET_YIELD_FROM_ITER) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = GET_YIELD_FROM_ITER; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(GET_YIELD_FROM_ITER); +@@ -4296,7 +5527,7 @@ + "cannot 'yield from' a coroutine object " + "in a non-coroutine generator"); + stack_pointer = _PyFrame_GetStackPointer(frame); +- goto error; ++ JUMP_TO_LABEL(error); + } + iter = iterable; + } +@@ -4310,7 +5541,7 @@ + PyObject *iter_o = PyObject_GetIter(iterable_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (iter_o == NULL) { +- goto error; ++ JUMP_TO_LABEL(error); + } + iter = PyStackRef_FromPyObjectSteal(iter_o); + PyStackRef_CLOSE(iterable); +@@ -4321,6 +5552,10 @@ + } + + TARGET(IMPORT_FROM) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = IMPORT_FROM; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(IMPORT_FROM); +@@ -4331,7 +5566,9 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *res_o = _PyEval_ImportFrom(tstate, PyStackRef_AsPyObjectBorrow(from), name); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (res_o == NULL) goto error; ++ if (res_o == NULL) { ++ JUMP_TO_LABEL(error); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[0] = res; + stack_pointer += 1; +@@ -4340,6 +5577,10 @@ + } + + TARGET(IMPORT_NAME) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = IMPORT_NAME; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(IMPORT_NAME); +@@ -4356,7 +5597,9 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(level); + PyStackRef_CLOSE(fromlist); +- if (res_o == NULL) goto pop_2_error; ++ if (res_o == NULL) { ++ JUMP_TO_LABEL(pop_2_error); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -4365,10 +5608,16 @@ + } + + TARGET(INSTRUMENTED_CALL) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = INSTRUMENTED_CALL; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(INSTRUMENTED_CALL); ++ opcode = INSTRUMENTED_CALL; + _PyStackRef *callable; + _PyStackRef *self_or_null; + _PyStackRef *args; +@@ -4383,6 +5632,8 @@ + callable = &stack_pointer[-2 - oparg]; + func = &stack_pointer[-2 - oparg]; + maybe_self = &stack_pointer[-1 - oparg]; ++ args = &stack_pointer[-oparg]; ++ (void)args; + if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + PyObject *self = ((PyMethodObject *)callable_o)->im_self; +@@ -4390,7 +5641,9 @@ + PyObject *method = ((PyMethodObject *)callable_o)->im_func; + _PyStackRef temp = callable[0]; + func[0] = PyStackRef_FromPyObjectNew(method); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(temp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + } + } + // _MONITOR_CALL +@@ -4418,7 +5671,9 @@ + frame, this_instr, function, arg0 + ); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err) goto error; ++ if (err) { ++ JUMP_TO_LABEL(error); ++ } + } + // _DO_CALL + { +@@ -4427,8 +5682,9 @@ + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + // oparg counts all of the args, but *not* self: + int total_args = oparg; ++ _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { +- args--; ++ arguments--; + total_args++; + } + // Check if the call can be inlined or not +@@ -4441,7 +5697,7 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( + tstate, callable[0], locals, +- args, total_args, NULL, frame ++ arguments, total_args, NULL, frame + ); + stack_pointer = _PyFrame_GetStackPointer(frame); + // Manipulate stack directly since we leave using DISPATCH_INLINED(). +@@ -4450,23 +5706,22 @@ + // The frame has stolen all the arguments from the stack, + // so there is no need to clean them up. + if (new_frame == NULL) { +- goto error; ++ JUMP_TO_LABEL(error); + } + frame->return_offset = 4 ; + DISPATCH_INLINED(new_frame); + } + /* Callable is not a normal Python function */ +- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + PyStackRef_CLOSE(callable[0]); +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); +- } +- { +- stack_pointer += -2 - oparg; +- assert(WITHIN_STACK_BOUNDS()); +- goto error; ++ PyStackRef_XCLOSE(self_or_null[0]); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); + } ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_LABEL(error); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *res_o = PyObject_Vectorcall( +@@ -4477,7 +5732,7 @@ + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + if (opcode == INSTRUMENTED_CALL) { + PyObject *arg = total_args == 0 ? +- &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(args[0]); ++ &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(arguments[0]); + if (res_o == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); + _Py_call_instrumentation_exc2( +@@ -4492,19 +5747,22 @@ + frame, this_instr, callable_o, arg); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err < 0) { ++ _PyFrame_SetStackPointer(frame, stack_pointer); + Py_CLEAR(res_o); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + } + } + } + assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + PyStackRef_CLOSE(callable[0]); +- for (int i = 0; i < total_args; i++) { +- PyStackRef_CLOSE(args[i]); ++ PyStackRef_XCLOSE(self_or_null[0]); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); + } + if (res_o == NULL) { + stack_pointer += -2 - oparg; + assert(WITHIN_STACK_BOUNDS()); +- goto error; ++ JUMP_TO_LABEL(error); + } + res = PyStackRef_FromPyObjectSteal(res_o); + } +@@ -4519,7 +5777,9 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err != 0) goto error; ++ if (err != 0) { ++ JUMP_TO_LABEL(error); ++ } + stack_pointer += 1 + oparg; + assert(WITHIN_STACK_BOUNDS()); + } +@@ -4531,38 +5791,383 @@ + } + + TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = INSTRUMENTED_CALL_FUNCTION_EX; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(INSTRUMENTED_CALL_FUNCTION_EX); +- GO_TO_INSTRUCTION(CALL_FUNCTION_EX); ++ opcode = INSTRUMENTED_CALL_FUNCTION_EX; ++ _PyStackRef func; ++ _PyStackRef callargs; ++ _PyStackRef kwargs_in; ++ _PyStackRef tuple; ++ _PyStackRef kwargs_out; ++ _PyStackRef func_st; ++ _PyStackRef null; ++ _PyStackRef callargs_st; ++ _PyStackRef kwargs_st; ++ _PyStackRef result; ++ // _MAKE_CALLARGS_A_TUPLE ++ { ++ kwargs_in = stack_pointer[-1]; ++ callargs = stack_pointer[-2]; ++ func = stack_pointer[-4]; ++ PyObject *callargs_o = PyStackRef_AsPyObjectBorrow(callargs); ++ if (PyTuple_CheckExact(callargs_o)) { ++ tuple = callargs; ++ kwargs_out = kwargs_in; ++ } ++ else { ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ int err = _Py_Check_ArgsIterable(tstate, PyStackRef_AsPyObjectBorrow(func), callargs_o); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (err < 0) { ++ JUMP_TO_LABEL(error); ++ } ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyObject *tuple_o = PySequence_Tuple(callargs_o); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (tuple_o == NULL) { ++ JUMP_TO_LABEL(error); ++ } ++ kwargs_out = kwargs_in; ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(callargs); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ tuple = PyStackRef_FromPyObjectSteal(tuple_o); ++ stack_pointer += 2; ++ assert(WITHIN_STACK_BOUNDS()); ++ } ++ } ++ // _DO_CALL_FUNCTION_EX ++ { ++ kwargs_st = kwargs_out; ++ callargs_st = tuple; ++ null = stack_pointer[-3]; ++ func_st = func; ++ (void)null; ++ PyObject *func = PyStackRef_AsPyObjectBorrow(func_st); ++ // DICT_MERGE is called before this opcode if there are kwargs. ++ // It converts all dict subtypes in kwargs into regular dicts. ++ EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_FUNCTION_EX, func); ++ PyObject *result_o; ++ assert(!_PyErr_Occurred(tstate)); ++ if (opcode == INSTRUMENTED_CALL_FUNCTION_EX) { ++ PyObject *callargs = PyStackRef_AsPyObjectBorrow(callargs_st); ++ PyObject *kwargs = PyStackRef_AsPyObjectBorrow(kwargs_st); ++ assert(kwargs == NULL || PyDict_CheckExact(kwargs)); ++ assert(PyTuple_CheckExact(callargs)); ++ PyObject *arg = PyTuple_GET_SIZE(callargs) > 0 ? ++ PyTuple_GET_ITEM(callargs, 0) : &_PyInstrumentation_MISSING; ++ stack_pointer[-2] = callargs_st; ++ stack_pointer[-1] = kwargs_st; ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ int err = _Py_call_instrumentation_2args( ++ tstate, PY_MONITORING_EVENT_CALL, ++ frame, this_instr, func, arg); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (err) { ++ JUMP_TO_LABEL(error); ++ } ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ result_o = PyObject_Call(func, callargs, kwargs); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (!PyFunction_Check(func) && !PyMethod_Check(func)) { ++ if (result_o == NULL) { ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ _Py_call_instrumentation_exc2( ++ tstate, PY_MONITORING_EVENT_C_RAISE, ++ frame, this_instr, func, arg); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ } ++ else { ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ int err = _Py_call_instrumentation_2args( ++ tstate, PY_MONITORING_EVENT_C_RETURN, ++ frame, this_instr, func, arg); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (err < 0) { ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ Py_CLEAR(result_o); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ } ++ } ++ } ++ } ++ else { ++ if (Py_TYPE(func) == &PyFunction_Type && ++ tstate->interp->eval_frame == NULL && ++ ((PyFunctionObject *)func)->vectorcall == _PyFunction_Vectorcall) { ++ PyObject *callargs = PyStackRef_AsPyObjectSteal(callargs_st); ++ assert(PyTuple_CheckExact(callargs)); ++ PyObject *kwargs = PyStackRef_IsNull(kwargs_st) ? NULL : PyStackRef_AsPyObjectSteal(kwargs_st); ++ assert(kwargs == NULL || PyDict_CheckExact(kwargs)); ++ Py_ssize_t nargs = PyTuple_GET_SIZE(callargs); ++ int code_flags = ((PyCodeObject *)PyFunction_GET_CODE(func))->co_flags; ++ PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(func)); ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_Ex( ++ tstate, func_st, locals, ++ nargs, callargs, kwargs, frame); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ // Need to sync the stack since we exit with DISPATCH_INLINED. ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ if (new_frame == NULL) { ++ JUMP_TO_LABEL(error); ++ } ++ assert( 1 == 1); ++ frame->return_offset = 1; ++ DISPATCH_INLINED(new_frame); ++ } ++ PyObject *callargs = PyStackRef_AsPyObjectBorrow(callargs_st); ++ assert(PyTuple_CheckExact(callargs)); ++ PyObject *kwargs = PyStackRef_AsPyObjectBorrow(kwargs_st); ++ assert(kwargs == NULL || PyDict_CheckExact(kwargs)); ++ stack_pointer[-2] = callargs_st; ++ stack_pointer[-1] = kwargs_st; ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ result_o = PyObject_Call(func, callargs, kwargs); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ } ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_XCLOSE(kwargs_st); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(callargs_st); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(func_st); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (result_o == NULL) { ++ JUMP_TO_LABEL(error); ++ } ++ result = PyStackRef_FromPyObjectSteal(result_o); ++ } ++ // _CHECK_PERIODIC ++ { ++ _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); ++ QSBR_QUIESCENT_STATE(tstate); ++ if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { ++ stack_pointer[0] = result; ++ stack_pointer += 1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ int err = _Py_HandlePending(tstate); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (err != 0) { ++ JUMP_TO_LABEL(error); ++ } ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ } ++ } ++ stack_pointer[0] = result; ++ stack_pointer += 1; ++ assert(WITHIN_STACK_BOUNDS()); ++ DISPATCH(); + } + + TARGET(INSTRUMENTED_CALL_KW) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = INSTRUMENTED_CALL_KW; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(INSTRUMENTED_CALL_KW); +- uint16_t counter = read_u16(&this_instr[1].cache); +- (void)counter; +- uint32_t version = read_u32(&this_instr[2].cache); +- (void)version; +- int is_meth = !PyStackRef_IsNull(PEEK(oparg + 2)); +- int total_args = oparg + is_meth; +- PyObject *function = PyStackRef_AsPyObjectBorrow(PEEK(oparg + 3)); +- PyObject *arg = total_args == 0 ? &_PyInstrumentation_MISSING +- : PyStackRef_AsPyObjectBorrow(PEEK(total_args + 1)); +- _PyFrame_SetStackPointer(frame, stack_pointer); +- int err = _Py_call_instrumentation_2args( +- tstate, PY_MONITORING_EVENT_CALL, +- frame, this_instr, function, arg); +- stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err) goto error; +- PAUSE_ADAPTIVE_COUNTER(this_instr[1].counter); +- GO_TO_INSTRUCTION(CALL_KW); ++ opcode = INSTRUMENTED_CALL_KW; ++ _PyStackRef *callable; ++ _PyStackRef *self_or_null; ++ _PyStackRef *args; ++ _PyStackRef kwnames; ++ _PyStackRef kwnames_in; ++ _PyStackRef *func; ++ _PyStackRef *maybe_self; ++ _PyStackRef kwnames_out; ++ _PyStackRef res; ++ /* Skip 1 cache entry */ ++ /* Skip 2 cache entries */ ++ // _MONITOR_CALL_KW ++ { ++ args = &stack_pointer[-1 - oparg]; ++ self_or_null = &stack_pointer[-2 - oparg]; ++ callable = &stack_pointer[-3 - oparg]; ++ int is_meth = !PyStackRef_IsNull(self_or_null[0]); ++ PyObject *arg; ++ if (is_meth) { ++ arg = PyStackRef_AsPyObjectBorrow(self_or_null[0]); ++ } ++ else { ++ if (args) { ++ arg = PyStackRef_AsPyObjectBorrow(args[0]); ++ } ++ else { ++ arg = &_PyInstrumentation_MISSING; ++ } ++ } ++ PyObject *function = PyStackRef_AsPyObjectBorrow(callable[0]); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ int err = _Py_call_instrumentation_2args( ++ tstate, PY_MONITORING_EVENT_CALL, ++ frame, this_instr, function, arg); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (err) { ++ JUMP_TO_LABEL(error); ++ } ++ } ++ // _MAYBE_EXPAND_METHOD_KW ++ { ++ kwnames_in = stack_pointer[-1]; ++ func = &stack_pointer[-3 - oparg]; ++ maybe_self = &stack_pointer[-2 - oparg]; ++ args = &stack_pointer[-1 - oparg]; ++ (void)args; ++ if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { ++ PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); ++ PyObject *self = ((PyMethodObject *)callable_o)->im_self; ++ maybe_self[0] = PyStackRef_FromPyObjectNew(self); ++ PyObject *method = ((PyMethodObject *)callable_o)->im_func; ++ _PyStackRef temp = callable[0]; ++ func[0] = PyStackRef_FromPyObjectNew(method); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(temp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ } ++ kwnames_out = kwnames_in; ++ } ++ // _DO_CALL_KW ++ { ++ kwnames = kwnames_out; ++ args = &stack_pointer[-1 - oparg]; ++ self_or_null = &stack_pointer[-2 - oparg]; ++ callable = &stack_pointer[-3 - oparg]; ++ PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); ++ PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); ++ // oparg counts all of the args, but *not* self: ++ int total_args = oparg; ++ _PyStackRef *arguments = args; ++ if (!PyStackRef_IsNull(self_or_null[0])) { ++ arguments--; ++ total_args++; ++ } ++ int positional_args = total_args - (int)PyTuple_GET_SIZE(kwnames_o); ++ // Check if the call can be inlined or not ++ if (Py_TYPE(callable_o) == &PyFunction_Type && ++ tstate->interp->eval_frame == NULL && ++ ((PyFunctionObject *)callable_o)->vectorcall == _PyFunction_Vectorcall) ++ { ++ int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags; ++ PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); ++ stack_pointer[-1] = kwnames; ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( ++ tstate, callable[0], locals, ++ arguments, positional_args, kwnames_o, frame ++ ); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(kwnames); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ // Sync stack explicitly since we leave using DISPATCH_INLINED(). ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ // The frame has stolen all the arguments from the stack, ++ // so there is no need to clean them up. ++ if (new_frame == NULL) { ++ JUMP_TO_LABEL(error); ++ } ++ assert( 4 == 1 + INLINE_CACHE_ENTRIES_CALL_KW); ++ frame->return_offset = 4 ; ++ DISPATCH_INLINED(new_frame); ++ } ++ /* Callable is not a normal Python function */ ++ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); ++ if (CONVERSION_FAILED(args_o)) { ++ PyStackRef_CLOSE(callable[0]); ++ PyStackRef_XCLOSE(self_or_null[0]); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); ++ } ++ PyStackRef_CLOSE(kwnames); ++ stack_pointer += -3 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_LABEL(error); ++ } ++ stack_pointer[-1] = kwnames; ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyObject *res_o = PyObject_Vectorcall( ++ callable_o, args_o, ++ positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, ++ kwnames_o); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); ++ if (opcode == INSTRUMENTED_CALL_KW) { ++ PyObject *arg = total_args == 0 ? ++ &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(arguments[0]); ++ if (res_o == NULL) { ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ _Py_call_instrumentation_exc2( ++ tstate, PY_MONITORING_EVENT_C_RAISE, ++ frame, this_instr, callable_o, arg); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ } ++ else { ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ int err = _Py_call_instrumentation_2args( ++ tstate, PY_MONITORING_EVENT_C_RETURN, ++ frame, this_instr, callable_o, arg); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (err < 0) { ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ Py_CLEAR(res_o); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ } ++ } ++ } ++ PyStackRef_CLOSE(callable[0]); ++ PyStackRef_XCLOSE(self_or_null[0]); ++ for (int _i = oparg; --_i >= 0;) { ++ PyStackRef_CLOSE(args[_i]); ++ } ++ PyStackRef_CLOSE(kwnames); ++ if (res_o == NULL) { ++ stack_pointer += -3 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ JUMP_TO_LABEL(error); ++ } ++ res = PyStackRef_FromPyObjectSteal(res_o); ++ } ++ stack_pointer[-3 - oparg] = res; ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); ++ DISPATCH(); + } + + TARGET(INSTRUMENTED_END_FOR) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = INSTRUMENTED_END_FOR; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; + next_instr += 1; + INSTRUCTION_STATS(INSTRUMENTED_END_FOR); +@@ -4577,7 +6182,7 @@ + int err = monitor_stop_iteration(tstate, frame, this_instr, PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err) { +- goto error; ++ JUMP_TO_LABEL(error); + } + } + PyStackRef_CLOSE(value); +@@ -4587,8 +6192,13 @@ + } + + TARGET(INSTRUMENTED_END_SEND) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = INSTRUMENTED_END_SEND; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(INSTRUMENTED_END_SEND); + _PyStackRef receiver; +@@ -4602,24 +6212,30 @@ + int err = monitor_stop_iteration(tstate, frame, this_instr, PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err) { +- goto error; ++ JUMP_TO_LABEL(error); + } + } + val = value; +- PyStackRef_CLOSE(receiver); + stack_pointer[-2] = val; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(receiver); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + DISPATCH(); + } + + TARGET(INSTRUMENTED_FOR_ITER) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = INSTRUMENTED_FOR_ITER; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(INSTRUMENTED_FOR_ITER); + /* Skip 1 cache entry */ +- _Py_CODEUNIT *target; + _PyStackRef iter_stackref = TOP(); + PyObject *iter = PyStackRef_AsPyObjectBorrow(iter_stackref); + _PyFrame_SetStackPointer(frame, stack_pointer); +@@ -4627,7 +6243,7 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + if (next != NULL) { + PUSH(PyStackRef_FromPyObjectSteal(next)); +- target = next_instr; ++ INSTRUMENTED_JUMP(this_instr, next_instr, PY_MONITORING_EVENT_BRANCH_LEFT); + } + else { + if (_PyErr_Occurred(tstate)) { +@@ -4635,7 +6251,7 @@ + int matches = _PyErr_ExceptionMatches(tstate, PyExc_StopIteration); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (!matches) { +- goto error; ++ JUMP_TO_LABEL(error); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyEval_MonitorRaise(tstate, frame, this_instr); +@@ -4645,25 +6261,30 @@ + /* iterator ended normally */ + assert(next_instr[oparg].op.code == END_FOR || + next_instr[oparg].op.code == INSTRUMENTED_END_FOR); +- STACK_SHRINK(1); +- PyStackRef_CLOSE(iter_stackref); +- /* Skip END_FOR and POP_TOP */ +- target = next_instr + oparg + 2; ++ /* Skip END_FOR */ ++ JUMPBY(oparg + 1); + } +- INSTRUMENTED_JUMP(this_instr, target, PY_MONITORING_EVENT_BRANCH); + DISPATCH(); + } + + TARGET(INSTRUMENTED_INSTRUCTION) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = INSTRUMENTED_INSTRUCTION; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(INSTRUMENTED_INSTRUCTION); ++ opcode = INSTRUMENTED_INSTRUCTION; + _PyFrame_SetStackPointer(frame, stack_pointer); + int next_opcode = _Py_call_instrumentation_instruction( + tstate, frame, this_instr); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (next_opcode < 0) goto error; ++ if (next_opcode < 0) { ++ JUMP_TO_LABEL(error); ++ } + next_instr = this_instr; + if (_PyOpcode_Caches[next_opcode]) { + PAUSE_ADAPTIVE_COUNTER(next_instr[1].counter); +@@ -4674,8 +6295,13 @@ + } + + TARGET(INSTRUMENTED_JUMP_BACKWARD) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = INSTRUMENTED_JUMP_BACKWARD; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(INSTRUMENTED_JUMP_BACKWARD); + /* Skip 1 cache entry */ +@@ -4687,151 +6313,306 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err != 0) goto error; ++ if (err != 0) { ++ JUMP_TO_LABEL(error); ++ } ++ } ++ } ++ // _MONITOR_JUMP_BACKWARD ++ { ++ INSTRUMENTED_JUMP(this_instr, next_instr - oparg, PY_MONITORING_EVENT_JUMP); ++ } ++ DISPATCH(); ++ } ++ ++ TARGET(INSTRUMENTED_JUMP_FORWARD) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = INSTRUMENTED_JUMP_FORWARD; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; ++ next_instr += 1; ++ INSTRUCTION_STATS(INSTRUMENTED_JUMP_FORWARD); ++ INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_JUMP); ++ DISPATCH(); ++ } ++ ++ TARGET(INSTRUMENTED_LINE) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = INSTRUMENTED_LINE; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const prev_instr = frame->instr_ptr; ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; ++ next_instr += 1; ++ INSTRUCTION_STATS(INSTRUMENTED_LINE); ++ opcode = INSTRUMENTED_LINE; ++ int original_opcode = 0; ++ if (tstate->tracing) { ++ PyCodeObject *code = _PyFrame_GetCode(frame); ++ int index = (int)(this_instr - _PyFrame_GetBytecode(frame)); ++ original_opcode = code->_co_monitoring->lines->data[index*code->_co_monitoring->lines->bytes_per_entry]; ++ next_instr = this_instr; ++ } else { ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ original_opcode = _Py_call_instrumentation_line( ++ tstate, frame, this_instr, prev_instr); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (original_opcode < 0) { ++ next_instr = this_instr+1; ++ JUMP_TO_LABEL(error); ++ } ++ next_instr = frame->instr_ptr; ++ if (next_instr != this_instr) { ++ DISPATCH(); ++ } ++ } ++ if (_PyOpcode_Caches[original_opcode]) { ++ _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(next_instr+1); ++ /* Prevent the underlying instruction from specializing ++ * and overwriting the instrumentation. */ ++ PAUSE_ADAPTIVE_COUNTER(cache->counter); ++ } ++ opcode = original_opcode; ++ DISPATCH_GOTO(); ++ } ++ ++ TARGET(INSTRUMENTED_LOAD_SUPER_ATTR) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = INSTRUMENTED_LOAD_SUPER_ATTR; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; ++ next_instr += 2; ++ INSTRUCTION_STATS(INSTRUMENTED_LOAD_SUPER_ATTR); ++ opcode = INSTRUMENTED_LOAD_SUPER_ATTR; ++ _PyStackRef global_super_st; ++ _PyStackRef class_st; ++ _PyStackRef self_st; ++ _PyStackRef attr; ++ _PyStackRef null = PyStackRef_NULL; ++ /* Skip 1 cache entry */ ++ // _LOAD_SUPER_ATTR ++ { ++ self_st = stack_pointer[-1]; ++ class_st = stack_pointer[-2]; ++ global_super_st = stack_pointer[-3]; ++ PyObject *global_super = PyStackRef_AsPyObjectBorrow(global_super_st); ++ PyObject *class = PyStackRef_AsPyObjectBorrow(class_st); ++ PyObject *self = PyStackRef_AsPyObjectBorrow(self_st); ++ if (opcode == INSTRUMENTED_LOAD_SUPER_ATTR) { ++ PyObject *arg = oparg & 2 ? class : &_PyInstrumentation_MISSING; ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ int err = _Py_call_instrumentation_2args( ++ tstate, PY_MONITORING_EVENT_CALL, ++ frame, this_instr, global_super, arg); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (err) { ++ PyStackRef_CLOSE(global_super_st); ++ PyStackRef_CLOSE(class_st); ++ PyStackRef_CLOSE(self_st); ++ JUMP_TO_LABEL(pop_3_error); ++ } ++ } ++ // we make no attempt to optimize here; specializations should ++ // handle any case whose performance we care about ++ PyObject *stack[] = {class, self}; ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyObject *super = PyObject_Vectorcall(global_super, stack, oparg & 2, NULL); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (opcode == INSTRUMENTED_LOAD_SUPER_ATTR) { ++ PyObject *arg = oparg & 2 ? class : &_PyInstrumentation_MISSING; ++ if (super == NULL) { ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ _Py_call_instrumentation_exc2( ++ tstate, PY_MONITORING_EVENT_C_RAISE, ++ frame, this_instr, global_super, arg); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ } ++ else { ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ int err = _Py_call_instrumentation_2args( ++ tstate, PY_MONITORING_EVENT_C_RETURN, ++ frame, this_instr, global_super, arg); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (err < 0) { ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ Py_CLEAR(super); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ } ++ } ++ } ++ PyStackRef_CLOSE(global_super_st); ++ PyStackRef_CLOSE(class_st); ++ PyStackRef_CLOSE(self_st); ++ if (super == NULL) { ++ JUMP_TO_LABEL(pop_3_error); ++ } ++ PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); ++ stack_pointer += -3; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyObject *attr_o = PyObject_GetAttr(super, name); ++ Py_DECREF(super); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (attr_o == NULL) { ++ JUMP_TO_LABEL(error); + } ++ attr = PyStackRef_FromPyObjectSteal(attr_o); + } +- // _MONITOR_JUMP_BACKWARD ++ // _PUSH_NULL_CONDITIONAL + { +- INSTRUMENTED_JUMP(this_instr, next_instr - oparg, PY_MONITORING_EVENT_JUMP); ++ null = PyStackRef_NULL; + } ++ stack_pointer[0] = attr; ++ if (oparg & 1) stack_pointer[1] = null; ++ stack_pointer += 1 + (oparg & 1); ++ assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + +- TARGET(INSTRUMENTED_JUMP_FORWARD) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ TARGET(INSTRUMENTED_NOT_TAKEN) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = INSTRUMENTED_NOT_TAKEN; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const prev_instr = frame->instr_ptr; ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 1; +- INSTRUCTION_STATS(INSTRUMENTED_JUMP_FORWARD); +- INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_JUMP); ++ INSTRUCTION_STATS(INSTRUMENTED_NOT_TAKEN); ++ (void)this_instr; // INSTRUMENTED_JUMP requires this_instr ++ INSTRUMENTED_JUMP(prev_instr, next_instr, PY_MONITORING_EVENT_BRANCH_LEFT); + DISPATCH(); + } + +- TARGET(INSTRUMENTED_LINE) { ++ TARGET(INSTRUMENTED_POP_ITER) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = INSTRUMENTED_POP_ITER; ++ (void)(opcode); ++ #endif + _Py_CODEUNIT* const prev_instr = frame->instr_ptr; +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 1; +- INSTRUCTION_STATS(INSTRUMENTED_LINE); +- int original_opcode = 0; +- if (tstate->tracing) { +- PyCodeObject *code = _PyFrame_GetCode(frame); +- _PyFrame_SetStackPointer(frame, stack_pointer); +- original_opcode = code->_co_monitoring->lines[(int)(this_instr - _PyFrame_GetBytecode(frame))].original_opcode; +- stack_pointer = _PyFrame_GetStackPointer(frame); +- next_instr = this_instr; +- } else { +- _PyFrame_SetStackPointer(frame, stack_pointer); +- original_opcode = _Py_call_instrumentation_line( +- tstate, frame, this_instr, prev_instr); +- stack_pointer = _PyFrame_GetStackPointer(frame); +- if (original_opcode < 0) { +- next_instr = this_instr+1; +- goto error; +- } +- next_instr = frame->instr_ptr; +- if (next_instr != this_instr) { +- DISPATCH(); +- } +- } +- if (_PyOpcode_Caches[original_opcode]) { +- _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(next_instr+1); +- /* Prevent the underlying instruction from specializing +- * and overwriting the instrumentation. */ +- PAUSE_ADAPTIVE_COUNTER(cache->counter); +- } +- opcode = original_opcode; +- DISPATCH_GOTO(); +- } +- +- TARGET(INSTRUMENTED_LOAD_SUPER_ATTR) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; +- (void)this_instr; +- next_instr += 2; +- INSTRUCTION_STATS(INSTRUMENTED_LOAD_SUPER_ATTR); +- /* Skip 1 cache entry */ +- // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we +- // don't want to specialize instrumented instructions +- PAUSE_ADAPTIVE_COUNTER(this_instr[1].counter); +- GO_TO_INSTRUCTION(LOAD_SUPER_ATTR); ++ INSTRUCTION_STATS(INSTRUMENTED_POP_ITER); ++ _PyStackRef iter; ++ iter = stack_pointer[-1]; ++ INSTRUMENTED_JUMP(prev_instr, this_instr+1, PY_MONITORING_EVENT_BRANCH_RIGHT); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(iter); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ DISPATCH(); + } + + TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = INSTRUMENTED_POP_JUMP_IF_FALSE; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_FALSE); + /* Skip 1 cache entry */ + _PyStackRef cond = POP(); + assert(PyStackRef_BoolCheck(cond)); +- int flag = PyStackRef_IsFalse(cond); +- int offset = flag * oparg; +- RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); +- INSTRUMENTED_JUMP(this_instr, next_instr + offset, PY_MONITORING_EVENT_BRANCH); ++ int jump = PyStackRef_IsFalse(cond); ++ RECORD_BRANCH_TAKEN(this_instr[1].cache, jump); ++ if (jump) { ++ INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT); ++ } + DISPATCH(); + } + + TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = INSTRUMENTED_POP_JUMP_IF_NONE; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_NONE); + /* Skip 1 cache entry */ + _PyStackRef value_stackref = POP(); +- int flag = PyStackRef_IsNone(value_stackref); +- int offset; +- if (flag) { +- offset = oparg; ++ int jump = PyStackRef_IsNone(value_stackref); ++ RECORD_BRANCH_TAKEN(this_instr[1].cache, jump); ++ if (jump) { ++ INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT); + } + else { ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(value_stackref); +- offset = 0; ++ stack_pointer = _PyFrame_GetStackPointer(frame); + } +- RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); +- INSTRUMENTED_JUMP(this_instr, next_instr + offset, PY_MONITORING_EVENT_BRANCH); + DISPATCH(); + } + + TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = INSTRUMENTED_POP_JUMP_IF_NOT_NONE; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_NOT_NONE); + /* Skip 1 cache entry */ + _PyStackRef value_stackref = POP(); +- int offset; +- int nflag = PyStackRef_IsNone(value_stackref); +- if (nflag) { +- offset = 0; +- } +- else { ++ int jump = !PyStackRef_IsNone(value_stackref); ++ RECORD_BRANCH_TAKEN(this_instr[1].cache, jump); ++ if (jump) { ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(value_stackref); +- offset = oparg; ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT); + } +- #if ENABLE_SPECIALIZATION +- this_instr[1].cache = (this_instr[1].cache << 1) | !nflag; +- #endif +- INSTRUMENTED_JUMP(this_instr, next_instr + offset, PY_MONITORING_EVENT_BRANCH); + DISPATCH(); + } + + TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = INSTRUMENTED_POP_JUMP_IF_TRUE; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_TRUE); + /* Skip 1 cache entry */ + _PyStackRef cond = POP(); + assert(PyStackRef_BoolCheck(cond)); +- int flag = PyStackRef_IsTrue(cond); +- int offset = flag * oparg; +- RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); +- INSTRUMENTED_JUMP(this_instr, next_instr + offset, PY_MONITORING_EVENT_BRANCH); ++ int jump = PyStackRef_IsTrue(cond); ++ RECORD_BRANCH_TAKEN(this_instr[1].cache, jump); ++ if (jump) { ++ INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT); ++ } + DISPATCH(); + } + + TARGET(INSTRUMENTED_RESUME) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = INSTRUMENTED_RESUME; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(INSTRUMENTED_RESUME); + // _LOAD_BYTECODE +@@ -4843,10 +6624,10 @@ + _Py_CODEUNIT *bytecode = + _PyEval_GetExecutableCode(tstate, _PyFrame_GetCode(frame)); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (bytecode == NULL) goto error; +- _PyFrame_SetStackPointer(frame, stack_pointer); ++ if (bytecode == NULL) { ++ JUMP_TO_LABEL(error); ++ } + ptrdiff_t off = this_instr - _PyFrame_GetBytecode(frame); +- stack_pointer = _PyFrame_GetStackPointer(frame); + frame->tlbc_index = ((_PyThreadStateImpl *)tstate)->tlbc_index; + frame->instr_ptr = bytecode + off; + // Make sure this_instr gets reset correctley for any uops that +@@ -4866,7 +6647,7 @@ + int err = _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err) { +- goto error; ++ JUMP_TO_LABEL(error); + } + next_instr = this_instr; + DISPATCH(); +@@ -4882,7 +6663,9 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err != 0) goto error; ++ if (err != 0) { ++ JUMP_TO_LABEL(error); ++ } + } + } + } +@@ -4892,7 +6675,9 @@ + int err = _Py_call_instrumentation( + tstate, oparg > 0, frame, this_instr); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err) goto error; ++ if (err) { ++ JUMP_TO_LABEL(error); ++ } + if (frame->instr_ptr != this_instr) { + /* Instrumentation has jumped */ + next_instr = frame->instr_ptr; +@@ -4902,8 +6687,13 @@ + } + + TARGET(INSTRUMENTED_RETURN_VALUE) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = INSTRUMENTED_RETURN_VALUE; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(INSTRUMENTED_RETURN_VALUE); + _PyStackRef val; +@@ -4917,14 +6707,14 @@ + tstate, PY_MONITORING_EVENT_PY_RETURN, + frame, this_instr, PyStackRef_AsPyObjectBorrow(val)); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err) goto error; ++ if (err) { ++ JUMP_TO_LABEL(error); ++ } + } + // _RETURN_VALUE + { + retval = val; +- #if TIER_ONE +- assert(frame != &entry_frame); +- #endif ++ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); + _PyStackRef temp = retval; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); +@@ -4947,8 +6737,13 @@ + } + + TARGET(INSTRUMENTED_YIELD_VALUE) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = INSTRUMENTED_YIELD_VALUE; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(INSTRUMENTED_YIELD_VALUE); + _PyStackRef val; +@@ -4963,7 +6758,7 @@ + frame, this_instr, PyStackRef_AsPyObjectBorrow(val)); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err) { +- goto error; ++ JUMP_TO_LABEL(error); + } + if (frame->instr_ptr != this_instr) { + next_instr = frame->instr_ptr; +@@ -4976,9 +6771,7 @@ + // NOTE: It's important that YIELD_VALUE never raises an exception! + // The compiler treats any exception raised here as a failed close() + // or throw() call. +- #if TIER_ONE +- assert(frame != &entry_frame); +- #endif ++ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); + frame->instr_ptr++; + PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); + assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); +@@ -5016,12 +6809,16 @@ + } + + TARGET(INTERPRETER_EXIT) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = INTERPRETER_EXIT; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(INTERPRETER_EXIT); + _PyStackRef retval; + retval = stack_pointer[-1]; +- assert(frame == &entry_frame); ++ assert(frame->owner == FRAME_OWNED_BY_INTERPRETER); + assert(_PyFrame_IsIncomplete(frame)); + /* Restore previous frame and return. */ + tstate->current_frame = frame->previous; +@@ -5035,6 +6832,10 @@ + } + + TARGET(IS_OP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = IS_OP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(IS_OP); +@@ -5054,10 +6855,66 @@ + } + + TARGET(JUMP_BACKWARD) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; +- (void)this_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = JUMP_BACKWARD; ++ (void)(opcode); ++ #endif ++ frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(JUMP_BACKWARD); ++ PREDICTED_JUMP_BACKWARD:; ++ _Py_CODEUNIT* const this_instr = next_instr - 2; ++ (void)this_instr; ++ /* Skip 1 cache entry */ ++ // _SPECIALIZE_JUMP_BACKWARD ++ { ++ #if ENABLE_SPECIALIZATION ++ if (this_instr->op.code == JUMP_BACKWARD) { ++ this_instr->op.code = tstate->interp->jit ? JUMP_BACKWARD_JIT : JUMP_BACKWARD_NO_JIT; ++ // Need to re-dispatch so the warmup counter isn't off by one: ++ next_instr = this_instr; ++ DISPATCH_SAME_OPARG(); ++ } ++ #endif ++ } ++ // _CHECK_PERIODIC ++ { ++ _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); ++ QSBR_QUIESCENT_STATE(tstate); ++ if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ int err = _Py_HandlePending(tstate); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (err != 0) { ++ JUMP_TO_LABEL(error); ++ } ++ } ++ } ++ // _JUMP_BACKWARD_NO_INTERRUPT ++ { ++ /* This bytecode is used in the `yield from` or `await` loop. ++ * If there is an interrupt, we want it handled in the innermost ++ * generator or coroutine, so we deliberately do not check it here. ++ * (see bpo-30039). ++ */ ++ assert(oparg <= INSTR_OFFSET()); ++ JUMPBY(-oparg); ++ } ++ DISPATCH(); ++ } ++ ++ TARGET(JUMP_BACKWARD_JIT) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = JUMP_BACKWARD_JIT; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; ++ next_instr += 2; ++ INSTRUCTION_STATS(JUMP_BACKWARD_JIT); ++ static_assert(1 == 1, "incorrect cache size"); ++ /* Skip 1 cache entry */ + // _CHECK_PERIODIC + { + _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); +@@ -5066,19 +6923,26 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err != 0) goto error; ++ if (err != 0) { ++ JUMP_TO_LABEL(error); ++ } + } + } +- // _JUMP_BACKWARD ++ // _JUMP_BACKWARD_NO_INTERRUPT + { +- uint16_t the_counter = read_u16(&this_instr[1].cache); +- (void)the_counter; ++ /* This bytecode is used in the `yield from` or `await` loop. ++ * If there is an interrupt, we want it handled in the innermost ++ * generator or coroutine, so we deliberately do not check it here. ++ * (see bpo-30039). ++ */ + assert(oparg <= INSTR_OFFSET()); + JUMPBY(-oparg); ++ } ++ // _JIT ++ { + #ifdef _Py_TIER2 +- #if ENABLE_SPECIALIZATION + _Py_BackoffCounter counter = this_instr[1].counter; +- if (backoff_counter_triggers(counter) && this_instr->op.code == JUMP_BACKWARD) { ++ if (backoff_counter_triggers(counter) && this_instr->op.code == JUMP_BACKWARD_JIT) { + _Py_CODEUNIT *start = this_instr; + /* Back up over EXTENDED_ARGs so optimizer sees the whole instruction */ + while (oparg > 255) { +@@ -5087,11 +6951,13 @@ + } + _PyExecutorObject *executor; + _PyFrame_SetStackPointer(frame, stack_pointer); +- int optimized = _PyOptimizer_Optimize(frame, start, stack_pointer, &executor, 0); ++ int optimized = _PyOptimizer_Optimize(frame, start, &executor, 0); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (optimized <= 0) { + this_instr[1].counter = restart_backoff_counter(counter); +- if (optimized < 0) goto error; ++ if (optimized < 0) { ++ JUMP_TO_LABEL(error); ++ } + } + else { + _PyFrame_SetStackPointer(frame, stack_pointer); +@@ -5105,13 +6971,16 @@ + else { + ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); + } +- #endif /* ENABLE_SPECIALIZATION */ +- #endif /* _Py_TIER2 */ ++ #endif + } + DISPATCH(); + } + + TARGET(JUMP_BACKWARD_NO_INTERRUPT) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = JUMP_BACKWARD_NO_INTERRUPT; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(JUMP_BACKWARD_NO_INTERRUPT); +@@ -5120,11 +6989,52 @@ + * generator or coroutine, so we deliberately do not check it here. + * (see bpo-30039). + */ ++ assert(oparg <= INSTR_OFFSET()); + JUMPBY(-oparg); + DISPATCH(); + } + ++ TARGET(JUMP_BACKWARD_NO_JIT) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = JUMP_BACKWARD_NO_JIT; ++ (void)(opcode); ++ #endif ++ frame->instr_ptr = next_instr; ++ next_instr += 2; ++ INSTRUCTION_STATS(JUMP_BACKWARD_NO_JIT); ++ static_assert(1 == 1, "incorrect cache size"); ++ /* Skip 1 cache entry */ ++ // _CHECK_PERIODIC ++ { ++ _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); ++ QSBR_QUIESCENT_STATE(tstate); ++ if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ int err = _Py_HandlePending(tstate); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (err != 0) { ++ JUMP_TO_LABEL(error); ++ } ++ } ++ } ++ // _JUMP_BACKWARD_NO_INTERRUPT ++ { ++ /* This bytecode is used in the `yield from` or `await` loop. ++ * If there is an interrupt, we want it handled in the innermost ++ * generator or coroutine, so we deliberately do not check it here. ++ * (see bpo-30039). ++ */ ++ assert(oparg <= INSTR_OFFSET()); ++ JUMPBY(-oparg); ++ } ++ DISPATCH(); ++ } ++ + TARGET(JUMP_FORWARD) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = JUMP_FORWARD; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(JUMP_FORWARD); +@@ -5133,6 +7043,10 @@ + } + + TARGET(LIST_APPEND) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LIST_APPEND; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(LIST_APPEND); +@@ -5142,13 +7056,19 @@ + list = stack_pointer[-2 - (oparg-1)]; + int err = _PyList_AppendTakeRef((PyListObject *)PyStackRef_AsPyObjectBorrow(list), + PyStackRef_AsPyObjectSteal(v)); +- if (err < 0) goto pop_1_error; ++ if (err < 0) { ++ JUMP_TO_LABEL(pop_1_error); ++ } + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(LIST_EXTEND) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LIST_EXTEND; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(LIST_EXTEND); +@@ -5176,7 +7096,7 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + } + PyStackRef_CLOSE(iterable_st); +- goto pop_1_error; ++ JUMP_TO_LABEL(pop_1_error); + } + assert(Py_IsNone(none_val)); + PyStackRef_CLOSE(iterable_st); +@@ -5186,15 +7106,19 @@ + } + + TARGET(LOAD_ATTR) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_ATTR; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 10; + INSTRUCTION_STATS(LOAD_ATTR); +- PREDICTED(LOAD_ATTR); ++ PREDICTED_LOAD_ATTR:; + _Py_CODEUNIT* const this_instr = next_instr - 10; + (void)this_instr; + _PyStackRef owner; + _PyStackRef attr; +- _PyStackRef self_or_null = PyStackRef_NULL; ++ _PyStackRef *self_or_null; + // _SPECIALIZE_LOAD_ATTR + { + owner = stack_pointer[-1]; +@@ -5216,6 +7140,7 @@ + /* Skip 8 cache entries */ + // _LOAD_ATTR + { ++ self_or_null = &stack_pointer[0]; + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); + PyObject *attr_o; + if (oparg & 1) { +@@ -5230,7 +7155,7 @@ + meth | self | arg1 | ... | argN + */ + assert(attr_o != NULL); // No errors on this branch +- self_or_null = owner; // Transfer ownership ++ self_or_null[0] = owner; // Transfer ownership + } + else { + /* meth is not an unbound method (but a regular attr, or +@@ -5240,8 +7165,10 @@ + meth | NULL | arg1 | ... | argN + */ + PyStackRef_CLOSE(owner); +- if (attr_o == NULL) goto pop_1_error; +- self_or_null = PyStackRef_NULL; ++ if (attr_o == NULL) { ++ JUMP_TO_LABEL(pop_1_error); ++ } ++ self_or_null[0] = PyStackRef_NULL; + } + } + else { +@@ -5250,21 +7177,26 @@ + attr_o = PyObject_GetAttr(PyStackRef_AsPyObjectBorrow(owner), name); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(owner); +- if (attr_o == NULL) goto pop_1_error; +- /* We need to define self_or_null on all paths */ +- self_or_null = PyStackRef_NULL; ++ if (attr_o == NULL) { ++ JUMP_TO_LABEL(pop_1_error); ++ } + } + attr = PyStackRef_FromPyObjectSteal(attr_o); + } + stack_pointer[-1] = attr; +- if (oparg & 1) stack_pointer[0] = self_or_null; +- stack_pointer += (oparg & 1); ++ stack_pointer += (oparg&1); + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(LOAD_ATTR_CLASS) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_ATTR_CLASS; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 10; + INSTRUCTION_STATS(LOAD_ATTR_CLASS); + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); +@@ -5277,9 +7209,17 @@ + owner = stack_pointer[-1]; + uint32_t type_version = read_u32(&this_instr[2].cache); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); +- DEOPT_IF(!PyType_Check(owner_o), LOAD_ATTR); ++ if (!PyType_Check(owner_o)) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + assert(type_version != 0); +- DEOPT_IF(((PyTypeObject *)owner_o)->tp_version_tag != type_version, LOAD_ATTR); ++ if (FT_ATOMIC_LOAD_UINT_RELAXED(((PyTypeObject *)owner_o)->tp_version_tag) != type_version) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + } + /* Skip 2 cache entries */ + // _LOAD_ATTR_CLASS +@@ -5288,9 +7228,12 @@ + STAT_INC(LOAD_ATTR, hit); + assert(descr != NULL); + attr = PyStackRef_FromPyObjectNew(descr); +- null = PyStackRef_NULL; + PyStackRef_CLOSE(owner); + } ++ // _PUSH_NULL_CONDITIONAL ++ { ++ null = PyStackRef_NULL; ++ } + stack_pointer[-1] = attr; + if (oparg & 1) stack_pointer[0] = null; + stack_pointer += (oparg & 1); +@@ -5299,7 +7242,13 @@ + } + + TARGET(LOAD_ATTR_CLASS_WITH_METACLASS_CHECK) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_ATTR_CLASS_WITH_METACLASS_CHECK; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 10; + INSTRUCTION_STATS(LOAD_ATTR_CLASS_WITH_METACLASS_CHECK); + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); +@@ -5312,16 +7261,28 @@ + owner = stack_pointer[-1]; + uint32_t type_version = read_u32(&this_instr[2].cache); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); +- DEOPT_IF(!PyType_Check(owner_o), LOAD_ATTR); ++ if (!PyType_Check(owner_o)) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + assert(type_version != 0); +- DEOPT_IF(((PyTypeObject *)owner_o)->tp_version_tag != type_version, LOAD_ATTR); ++ if (FT_ATOMIC_LOAD_UINT_RELAXED(((PyTypeObject *)owner_o)->tp_version_tag) != type_version) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + } + // _GUARD_TYPE_VERSION + { + uint32_t type_version = read_u32(&this_instr[4].cache); + PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + assert(type_version != 0); +- DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); ++ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + } + // _LOAD_ATTR_CLASS + { +@@ -5329,9 +7290,12 @@ + STAT_INC(LOAD_ATTR, hit); + assert(descr != NULL); + attr = PyStackRef_FromPyObjectNew(descr); +- null = PyStackRef_NULL; + PyStackRef_CLOSE(owner); + } ++ // _PUSH_NULL_CONDITIONAL ++ { ++ null = PyStackRef_NULL; ++ } + stack_pointer[-1] = attr; + if (oparg & 1) stack_pointer[0] = null; + stack_pointer += (oparg & 1); +@@ -5340,7 +7304,13 @@ + } + + TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 10; + INSTRUCTION_STATS(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN); + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); +@@ -5352,17 +7322,33 @@ + PyObject *getattribute = read_obj(&this_instr[6].cache); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + assert((oparg & 1) == 0); +- DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); ++ if (tstate->interp->eval_frame) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + PyTypeObject *cls = Py_TYPE(owner_o); + assert(type_version != 0); +- DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); ++ if (FT_ATOMIC_LOAD_UINT_RELAXED(cls->tp_version_tag) != type_version) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + assert(Py_IS_TYPE(getattribute, &PyFunction_Type)); + PyFunctionObject *f = (PyFunctionObject *)getattribute; + assert(func_version != 0); +- DEOPT_IF(f->func_version != func_version, LOAD_ATTR); ++ if (f->func_version != func_version) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + PyCodeObject *code = (PyCodeObject *)f->func_code; + assert(code->co_argcount == 2); +- DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), LOAD_ATTR); ++ if (!_PyThreadState_HasStackSpace(tstate, code->co_framesize)) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + STAT_INC(LOAD_ATTR, hit); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); + _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked( +@@ -5376,7 +7362,13 @@ + } + + TARGET(LOAD_ATTR_INSTANCE_VALUE) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_ATTR_INSTANCE_VALUE; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 10; + INSTRUCTION_STATS(LOAD_ATTR_INSTANCE_VALUE); + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); +@@ -5390,30 +7382,56 @@ + uint32_t type_version = read_u32(&this_instr[2].cache); + PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + assert(type_version != 0); +- DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); ++ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + } + // _CHECK_MANAGED_OBJECT_HAS_VALUES + { + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + assert(Py_TYPE(owner_o)->tp_dictoffset < 0); + assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); +- DEOPT_IF(!_PyObject_InlineValues(owner_o)->valid, LOAD_ATTR); ++ if (!FT_ATOMIC_LOAD_UINT8(_PyObject_InlineValues(owner_o)->valid)) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + } + // _LOAD_ATTR_INSTANCE_VALUE + { + uint16_t offset = read_u16(&this_instr[4].cache); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); +- PyObject *attr_o = *value_ptr; +- DEOPT_IF(attr_o == NULL, LOAD_ATTR); ++ PyObject *attr_o = FT_ATOMIC_LOAD_PTR_ACQUIRE(*value_ptr); ++ if (attr_o == NULL) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } ++ #ifdef Py_GIL_DISABLED ++ if (!_Py_TryIncrefCompareStackRef(value_ptr, attr_o, &attr)) { ++ if (true) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } ++ } ++ #else ++ attr = PyStackRef_FromPyObjectNew(attr_o); ++ #endif + STAT_INC(LOAD_ATTR, hit); +- Py_INCREF(attr_o); +- null = PyStackRef_NULL; +- attr = PyStackRef_FromPyObjectSteal(attr_o); ++ stack_pointer[-1] = attr; ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(owner); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + } + /* Skip 5 cache entries */ +- stack_pointer[-1] = attr; ++ // _PUSH_NULL_CONDITIONAL ++ { ++ null = PyStackRef_NULL; ++ } + if (oparg & 1) stack_pointer[0] = null; + stack_pointer += (oparg & 1); + assert(WITHIN_STACK_BOUNDS()); +@@ -5421,13 +7439,19 @@ + } + + TARGET(LOAD_ATTR_METHOD_LAZY_DICT) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_ATTR_METHOD_LAZY_DICT; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 10; + INSTRUCTION_STATS(LOAD_ATTR_METHOD_LAZY_DICT); + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); + _PyStackRef owner; + _PyStackRef attr; +- _PyStackRef self = PyStackRef_NULL; ++ _PyStackRef self; + /* Skip 1 cache entry */ + // _GUARD_TYPE_VERSION + { +@@ -5435,15 +7459,23 @@ + uint32_t type_version = read_u32(&this_instr[2].cache); + PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + assert(type_version != 0); +- DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); ++ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + } + // _CHECK_ATTR_METHOD_LAZY_DICT + { + uint16_t dictoffset = read_u16(&this_instr[4].cache); + char *ptr = ((char *)PyStackRef_AsPyObjectBorrow(owner)) + MANAGED_DICT_OFFSET + dictoffset; +- PyObject *dict = *(PyObject **)ptr; ++ PyObject *dict = FT_ATOMIC_LOAD_PTR_ACQUIRE(*(PyObject **)ptr); + /* This object has a __dict__, just not yet created */ +- DEOPT_IF(dict != NULL, LOAD_ATTR); ++ if (dict != NULL) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + } + /* Skip 1 cache entry */ + // _LOAD_ATTR_METHOD_LAZY_DICT +@@ -5464,13 +7496,19 @@ + } + + TARGET(LOAD_ATTR_METHOD_NO_DICT) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_ATTR_METHOD_NO_DICT; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 10; + INSTRUCTION_STATS(LOAD_ATTR_METHOD_NO_DICT); + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); + _PyStackRef owner; + _PyStackRef attr; +- _PyStackRef self = PyStackRef_NULL; ++ _PyStackRef self; + /* Skip 1 cache entry */ + // _GUARD_TYPE_VERSION + { +@@ -5478,7 +7516,11 @@ + uint32_t type_version = read_u32(&this_instr[2].cache); + PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + assert(type_version != 0); +- DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); ++ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + } + /* Skip 2 cache entries */ + // _LOAD_ATTR_METHOD_NO_DICT +@@ -5500,13 +7542,19 @@ + } + + TARGET(LOAD_ATTR_METHOD_WITH_VALUES) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_ATTR_METHOD_WITH_VALUES; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 10; + INSTRUCTION_STATS(LOAD_ATTR_METHOD_WITH_VALUES); + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); + _PyStackRef owner; + _PyStackRef attr; +- _PyStackRef self = PyStackRef_NULL; ++ _PyStackRef self; + /* Skip 1 cache entry */ + // _GUARD_TYPE_VERSION + { +@@ -5514,20 +7562,34 @@ + uint32_t type_version = read_u32(&this_instr[2].cache); + PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + assert(type_version != 0); +- DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); ++ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + } + // _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT + { + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); +- DEOPT_IF(!_PyObject_InlineValues(owner_o)->valid, LOAD_ATTR); ++ PyDictValues *ivs = _PyObject_InlineValues(owner_o); ++ if (!FT_ATOMIC_LOAD_UINT8(ivs->valid)) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + } + // _GUARD_KEYS_VERSION + { + uint32_t keys_version = read_u32(&this_instr[4].cache); + PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; +- DEOPT_IF(owner_heap_type->ht_cached_keys->dk_version != keys_version, LOAD_ATTR); ++ PyDictKeysObject *keys = owner_heap_type->ht_cached_keys; ++ if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + } + // _LOAD_ATTR_METHOD_WITH_VALUES + { +@@ -5548,7 +7610,13 @@ + } + + TARGET(LOAD_ATTR_MODULE) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_ATTR_MODULE; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 10; + INSTRUCTION_STATS(LOAD_ATTR_MODULE); + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); +@@ -5562,11 +7630,19 @@ + owner = stack_pointer[-1]; + uint32_t dict_version = read_u32(&this_instr[2].cache); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); +- DEOPT_IF(Py_TYPE(owner_o)->tp_getattro != PyModule_Type.tp_getattro, LOAD_ATTR); ++ if (Py_TYPE(owner_o)->tp_getattro != PyModule_Type.tp_getattro) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner_o)->md_dict; + assert(dict != NULL); + PyDictKeysObject *keys = FT_ATOMIC_LOAD_PTR_ACQUIRE(dict->ma_keys); +- DEOPT_IF(FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != dict_version, LOAD_ATTR); ++ if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != dict_version) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + mod_keys = keys; + } + // _LOAD_ATTR_MODULE_FROM_KEYS +@@ -5577,22 +7653,35 @@ + PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(mod_keys) + index; + PyObject *attr_o = FT_ATOMIC_LOAD_PTR_RELAXED(ep->me_value); + // Clear mod_keys from stack in case we need to deopt +- DEOPT_IF(attr_o == NULL, LOAD_ATTR); ++ if (attr_o == NULL) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + #ifdef Py_GIL_DISABLED + int increfed = _Py_TryIncrefCompareStackRef(&ep->me_value, attr_o, &attr); + if (!increfed) { +- DEOPT_IF(true, LOAD_ATTR); ++ if (true) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + } + #else + Py_INCREF(attr_o); + attr = PyStackRef_FromPyObjectSteal(attr_o); + #endif + STAT_INC(LOAD_ATTR, hit); ++ stack_pointer[-1] = attr; ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(owner); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ } ++ /* Skip 5 cache entries */ ++ // _PUSH_NULL_CONDITIONAL ++ { + null = PyStackRef_NULL; +- PyStackRef_CLOSE(owner); + } +- /* Skip 5 cache entries */ +- stack_pointer[-1] = attr; + if (oparg & 1) stack_pointer[0] = null; + stack_pointer += (oparg & 1); + assert(WITHIN_STACK_BOUNDS()); +@@ -5600,7 +7689,13 @@ + } + + TARGET(LOAD_ATTR_NONDESCRIPTOR_NO_DICT) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_ATTR_NONDESCRIPTOR_NO_DICT; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 10; + INSTRUCTION_STATS(LOAD_ATTR_NONDESCRIPTOR_NO_DICT); + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); +@@ -5613,7 +7708,11 @@ + uint32_t type_version = read_u32(&this_instr[2].cache); + PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + assert(type_version != 0); +- DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); ++ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + } + /* Skip 2 cache entries */ + // _LOAD_ATTR_NONDESCRIPTOR_NO_DICT +@@ -5631,7 +7730,13 @@ + } + + TARGET(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 10; + INSTRUCTION_STATS(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES); + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); +@@ -5644,20 +7749,34 @@ + uint32_t type_version = read_u32(&this_instr[2].cache); + PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + assert(type_version != 0); +- DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); ++ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + } + // _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT + { + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); +- DEOPT_IF(!_PyObject_InlineValues(owner_o)->valid, LOAD_ATTR); ++ PyDictValues *ivs = _PyObject_InlineValues(owner_o); ++ if (!FT_ATOMIC_LOAD_UINT8(ivs->valid)) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + } + // _GUARD_KEYS_VERSION + { + uint32_t keys_version = read_u32(&this_instr[4].cache); + PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; +- DEOPT_IF(owner_heap_type->ht_cached_keys->dk_version != keys_version, LOAD_ATTR); ++ PyDictKeysObject *keys = owner_heap_type->ht_cached_keys; ++ if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + } + // _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES + { +@@ -5673,7 +7792,13 @@ + } + + TARGET(LOAD_ATTR_PROPERTY) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_ATTR_PROPERTY; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 10; + INSTRUCTION_STATS(LOAD_ATTR_PROPERTY); + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); +@@ -5682,7 +7807,11 @@ + /* Skip 1 cache entry */ + // _CHECK_PEP_523 + { +- DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); ++ if (tstate->interp->eval_frame) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + } + // _GUARD_TYPE_VERSION + { +@@ -5690,7 +7819,11 @@ + uint32_t type_version = read_u32(&this_instr[2].cache); + PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + assert(type_version != 0); +- DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); ++ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + } + /* Skip 2 cache entries */ + // _LOAD_ATTR_PROPERTY_FRAME +@@ -5700,10 +7833,26 @@ + assert(Py_IS_TYPE(fget, &PyFunction_Type)); + PyFunctionObject *f = (PyFunctionObject *)fget; + PyCodeObject *code = (PyCodeObject *)f->func_code; +- DEOPT_IF((code->co_flags & (CO_VARKEYWORDS | CO_VARARGS | CO_OPTIMIZED)) != CO_OPTIMIZED, LOAD_ATTR); +- DEOPT_IF(code->co_kwonlyargcount, LOAD_ATTR); +- DEOPT_IF(code->co_argcount != 1, LOAD_ATTR); +- DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), LOAD_ATTR); ++ if ((code->co_flags & (CO_VARKEYWORDS | CO_VARARGS | CO_OPTIMIZED)) != CO_OPTIMIZED) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } ++ if (code->co_kwonlyargcount) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } ++ if (code->co_argcount != 1) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } ++ if (!_PyThreadState_HasStackSpace(tstate, code->co_framesize)) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + STAT_INC(LOAD_ATTR, hit); + new_frame = _PyFrame_PushUnchecked(tstate, PyStackRef_FromPyObjectNew(fget), 1, frame); + new_frame->localsplus[0] = owner; +@@ -5738,7 +7887,13 @@ + } + + TARGET(LOAD_ATTR_SLOT) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_ATTR_SLOT; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 10; + INSTRUCTION_STATS(LOAD_ATTR_SLOT); + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); +@@ -5752,21 +7907,41 @@ + uint32_t type_version = read_u32(&this_instr[2].cache); + PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + assert(type_version != 0); +- DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); ++ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + } + // _LOAD_ATTR_SLOT + { + uint16_t index = read_u16(&this_instr[4].cache); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); +- char *addr = (char *)owner_o + index; +- PyObject *attr_o = *(PyObject **)addr; +- DEOPT_IF(attr_o == NULL, LOAD_ATTR); +- STAT_INC(LOAD_ATTR, hit); +- null = PyStackRef_NULL; ++ PyObject **addr = (PyObject **)((char *)owner_o + index); ++ PyObject *attr_o = FT_ATOMIC_LOAD_PTR(*addr); ++ if (attr_o == NULL) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } ++ #ifdef Py_GIL_DISABLED ++ int increfed = _Py_TryIncrefCompareStackRef(addr, attr_o, &attr); ++ if (!increfed) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } ++ #else + attr = PyStackRef_FromPyObjectNew(attr_o); ++ #endif ++ STAT_INC(LOAD_ATTR, hit); + PyStackRef_CLOSE(owner); + } + /* Skip 5 cache entries */ ++ // _PUSH_NULL_CONDITIONAL ++ { ++ null = PyStackRef_NULL; ++ } + stack_pointer[-1] = attr; + if (oparg & 1) stack_pointer[0] = null; + stack_pointer += (oparg & 1); +@@ -5775,11 +7950,18 @@ + } + + TARGET(LOAD_ATTR_WITH_HINT) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_ATTR_WITH_HINT; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 10; + INSTRUCTION_STATS(LOAD_ATTR_WITH_HINT); + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); + _PyStackRef owner; ++ PyDictObject *dict; + _PyStackRef attr; + _PyStackRef null = PyStackRef_NULL; + /* Skip 1 cache entry */ +@@ -5789,36 +7971,81 @@ + uint32_t type_version = read_u32(&this_instr[2].cache); + PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + assert(type_version != 0); +- DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); ++ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } + } + // _CHECK_ATTR_WITH_HINT + { + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_MANAGED_DICT); +- PyDictObject *dict = _PyObject_GetManagedDict(owner_o); +- DEOPT_IF(dict == NULL, LOAD_ATTR); +- assert(PyDict_CheckExact((PyObject *)dict)); ++ PyDictObject *dict_o = _PyObject_GetManagedDict(owner_o); ++ if (dict_o == NULL) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } ++ assert(PyDict_CheckExact((PyObject *)dict_o)); ++ dict = dict_o; + } + // _LOAD_ATTR_WITH_HINT + { + uint16_t hint = read_u16(&this_instr[4].cache); +- PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + PyObject *attr_o; +- PyDictObject *dict = _PyObject_GetManagedDict(owner_o); +- DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, LOAD_ATTR); ++ if (!LOCK_OBJECT(dict)) { ++ if (true) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } ++ } ++ if (hint >= (size_t)dict->ma_keys->dk_nentries) { ++ UNLOCK_OBJECT(dict); ++ if (true) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } ++ } + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); +- DEOPT_IF(!DK_IS_UNICODE(dict->ma_keys), LOAD_ATTR); ++ if (dict->ma_keys->dk_kind != DICT_KEYS_UNICODE) { ++ UNLOCK_OBJECT(dict); ++ if (true) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } ++ } + PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; +- DEOPT_IF(ep->me_key != name, LOAD_ATTR); ++ if (ep->me_key != name) { ++ UNLOCK_OBJECT(dict); ++ if (true) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } ++ } + attr_o = ep->me_value; +- DEOPT_IF(attr_o == NULL, LOAD_ATTR); ++ if (attr_o == NULL) { ++ UNLOCK_OBJECT(dict); ++ if (true) { ++ UPDATE_MISS_STATS(LOAD_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_ATTR); ++ } ++ } + STAT_INC(LOAD_ATTR, hit); +- Py_INCREF(attr_o); +- attr = PyStackRef_FromPyObjectSteal(attr_o); +- null = PyStackRef_NULL; ++ attr = PyStackRef_FromPyObjectNew(attr_o); ++ UNLOCK_OBJECT(dict); + PyStackRef_CLOSE(owner); + } + /* Skip 5 cache entries */ ++ // _PUSH_NULL_CONDITIONAL ++ { ++ null = PyStackRef_NULL; ++ } + stack_pointer[-1] = attr; + if (oparg & 1) stack_pointer[0] = null; + stack_pointer += (oparg & 1); +@@ -5827,6 +8054,10 @@ + } + + TARGET(LOAD_BUILD_CLASS) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_BUILD_CLASS; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(LOAD_BUILD_CLASS); +@@ -5835,13 +8066,15 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = PyMapping_GetOptionalItem(BUILTINS(), &_Py_ID(__build_class__), &bc_o); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err < 0) goto error; ++ if (err < 0) { ++ JUMP_TO_LABEL(error); ++ } + if (bc_o == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyErr_SetString(tstate, PyExc_NameError, + "__build_class__ not found"); + stack_pointer = _PyFrame_GetStackPointer(frame); +- goto error; ++ JUMP_TO_LABEL(error); + } + bc = PyStackRef_FromPyObjectSteal(bc_o); + stack_pointer[0] = bc; +@@ -5851,6 +8084,10 @@ + } + + TARGET(LOAD_COMMON_CONSTANT) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_COMMON_CONSTANT; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(LOAD_COMMON_CONSTANT); +@@ -5873,12 +8110,36 @@ + } + + TARGET(LOAD_CONST) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_CONST; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(LOAD_CONST); +- PREDICTED(LOAD_CONST); ++ PREDICTED_LOAD_CONST:; ++ _Py_CODEUNIT* const this_instr = next_instr - 1; ++ (void)this_instr; + _PyStackRef value; +- value = PyStackRef_FromPyObjectNew(GETITEM(FRAME_CO_CONSTS, oparg)); ++ /* We can't do this in the bytecode compiler as ++ * marshalling can intern strings and make them immortal. */ ++ PyObject *obj = GETITEM(FRAME_CO_CONSTS, oparg); ++ value = PyStackRef_FromPyObjectNew(obj); ++ #if ENABLE_SPECIALIZATION_FT ++ #ifdef Py_GIL_DISABLED ++ uint8_t expected = LOAD_CONST; ++ if (!_Py_atomic_compare_exchange_uint8( ++ &this_instr->op.code, &expected, ++ _Py_IsImmortal(obj) ? LOAD_CONST_IMMORTAL : LOAD_CONST_MORTAL)) { ++ // We might lose a race with instrumentation, which we don't care about. ++ assert(expected >= MIN_INSTRUMENTED_OPCODE); ++ } ++ #else ++ if (this_instr->op.code == LOAD_CONST) { ++ this_instr->op.code = _Py_IsImmortal(obj) ? LOAD_CONST_IMMORTAL : LOAD_CONST_MORTAL; ++ } ++ #endif ++ #endif + stack_pointer[0] = value; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); +@@ -5886,6 +8147,10 @@ + } + + TARGET(LOAD_CONST_IMMORTAL) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_CONST_IMMORTAL; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(LOAD_CONST_IMMORTAL); +@@ -5900,7 +8165,29 @@ + DISPATCH(); + } + ++ TARGET(LOAD_CONST_MORTAL) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_CONST_MORTAL; ++ (void)(opcode); ++ #endif ++ frame->instr_ptr = next_instr; ++ next_instr += 1; ++ INSTRUCTION_STATS(LOAD_CONST_MORTAL); ++ static_assert(0 == 0, "incorrect cache size"); ++ _PyStackRef value; ++ PyObject *obj = GETITEM(FRAME_CO_CONSTS, oparg); ++ value = PyStackRef_FromPyObjectNew(obj); ++ stack_pointer[0] = value; ++ stack_pointer += 1; ++ assert(WITHIN_STACK_BOUNDS()); ++ DISPATCH(); ++ } ++ + TARGET(LOAD_DEREF) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_DEREF; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(LOAD_DEREF); +@@ -5911,7 +8198,7 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg); + stack_pointer = _PyFrame_GetStackPointer(frame); +- goto error; ++ JUMP_TO_LABEL(error); + } + value = PyStackRef_FromPyObjectSteal(value_o); + stack_pointer[0] = value; +@@ -5921,6 +8208,10 @@ + } + + TARGET(LOAD_FAST) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_FAST; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(LOAD_FAST); +@@ -5934,12 +8225,15 @@ + } + + TARGET(LOAD_FAST_AND_CLEAR) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_FAST_AND_CLEAR; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(LOAD_FAST_AND_CLEAR); + _PyStackRef value; + value = GETLOCAL(oparg); +- // do not use SETLOCAL here, it decrefs the old value + GETLOCAL(oparg) = PyStackRef_NULL; + stack_pointer[0] = value; + stack_pointer += 1; +@@ -5948,6 +8242,10 @@ + } + + TARGET(LOAD_FAST_CHECK) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_FAST_CHECK; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(LOAD_FAST_CHECK); +@@ -5960,7 +8258,7 @@ + PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames, oparg) + ); + stack_pointer = _PyFrame_GetStackPointer(frame); +- goto error; ++ JUMP_TO_LABEL(error); + } + value = PyStackRef_DUP(value_s); + stack_pointer[0] = value; +@@ -5970,6 +8268,10 @@ + } + + TARGET(LOAD_FAST_LOAD_FAST) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_FAST_LOAD_FAST; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(LOAD_FAST_LOAD_FAST); +@@ -5987,6 +8289,10 @@ + } + + TARGET(LOAD_FROM_DICT_OR_DEREF) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_FROM_DICT_OR_DEREF; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(LOAD_FROM_DICT_OR_DEREF); +@@ -6003,7 +8309,7 @@ + int err = PyMapping_GetOptionalItem(class_dict, name, &value_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err < 0) { +- goto error; ++ JUMP_TO_LABEL(error); + } + if (!value_o) { + PyCellObject *cell = (PyCellObject *)PyStackRef_AsPyObjectBorrow(GETLOCAL(oparg)); +@@ -6012,16 +8318,26 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg); + stack_pointer = _PyFrame_GetStackPointer(frame); +- goto error; ++ JUMP_TO_LABEL(error); + } + } ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(class_dict_st); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + value = PyStackRef_FromPyObjectSteal(value_o); +- stack_pointer[-1] = value; ++ stack_pointer[0] = value; ++ stack_pointer += 1; ++ assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(LOAD_FROM_DICT_OR_GLOBALS) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_FROM_DICT_OR_GLOBALS; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(LOAD_FROM_DICT_OR_GLOBALS); +@@ -6034,7 +8350,9 @@ + int err = PyMapping_GetOptionalItem(PyStackRef_AsPyObjectBorrow(mod_or_class_dict), name, &v_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(mod_or_class_dict); +- if (err < 0) goto pop_1_error; ++ if (err < 0) { ++ JUMP_TO_LABEL(pop_1_error); ++ } + if (v_o == NULL) { + if (PyDict_CheckExact(GLOBALS()) + && PyDict_CheckExact(BUILTINS())) +@@ -6055,7 +8373,7 @@ + NAME_ERROR_MSG, name); + stack_pointer = _PyFrame_GetStackPointer(frame); + } +- goto error; ++ JUMP_TO_LABEL(error); + } + } + else { +@@ -6066,20 +8384,24 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = PyMapping_GetOptionalItem(GLOBALS(), name, &v_o); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err < 0) goto error; ++ if (err < 0) { ++ JUMP_TO_LABEL(error); ++ } + if (v_o == NULL) { + /* namespace 2: builtins */ + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = PyMapping_GetOptionalItem(BUILTINS(), name, &v_o); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err < 0) goto error; ++ if (err < 0) { ++ JUMP_TO_LABEL(error); ++ } + if (v_o == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyEval_FormatExcCheckArg( + tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + stack_pointer = _PyFrame_GetStackPointer(frame); +- goto error; ++ JUMP_TO_LABEL(error); + } + } + } +@@ -6092,10 +8414,14 @@ + } + + TARGET(LOAD_GLOBAL) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_GLOBAL; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 5; + INSTRUCTION_STATS(LOAD_GLOBAL); +- PREDICTED(LOAD_GLOBAL); ++ PREDICTED_LOAD_GLOBAL:; + _Py_CODEUNIT* const this_instr = next_instr - 5; + (void)this_instr; + _PyStackRef *res; +@@ -6127,7 +8453,12 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyEval_LoadGlobalStackRef(GLOBALS(), BUILTINS(), name, res); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (PyStackRef_IsNull(*res)) goto error; ++ if (PyStackRef_IsNull(*res)) { ++ JUMP_TO_LABEL(error); ++ } ++ } ++ // _PUSH_NULL_CONDITIONAL ++ { + null = PyStackRef_NULL; + } + if (oparg & 1) stack_pointer[1] = null; +@@ -6137,7 +8468,13 @@ + } + + TARGET(LOAD_GLOBAL_BUILTIN) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_GLOBAL_BUILTIN; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 5; + INSTRUCTION_STATS(LOAD_GLOBAL_BUILTIN); + static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); +@@ -6149,18 +8486,34 @@ + { + uint16_t version = read_u16(&this_instr[2].cache); + PyDictObject *dict = (PyDictObject *)GLOBALS(); +- DEOPT_IF(!PyDict_CheckExact(dict), LOAD_GLOBAL); ++ if (!PyDict_CheckExact(dict)) { ++ UPDATE_MISS_STATS(LOAD_GLOBAL); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL)); ++ JUMP_TO_PREDICTED(LOAD_GLOBAL); ++ } + PyDictKeysObject *keys = FT_ATOMIC_LOAD_PTR_ACQUIRE(dict->ma_keys); +- DEOPT_IF(FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != version, LOAD_GLOBAL); ++ if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != version) { ++ UPDATE_MISS_STATS(LOAD_GLOBAL); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL)); ++ JUMP_TO_PREDICTED(LOAD_GLOBAL); ++ } + assert(DK_IS_UNICODE(keys)); + } + // _GUARD_BUILTINS_VERSION_PUSH_KEYS + { + uint16_t version = read_u16(&this_instr[3].cache); + PyDictObject *dict = (PyDictObject *)BUILTINS(); +- DEOPT_IF(!PyDict_CheckExact(dict), LOAD_GLOBAL); ++ if (!PyDict_CheckExact(dict)) { ++ UPDATE_MISS_STATS(LOAD_GLOBAL); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL)); ++ JUMP_TO_PREDICTED(LOAD_GLOBAL); ++ } + PyDictKeysObject *keys = FT_ATOMIC_LOAD_PTR_ACQUIRE(dict->ma_keys); +- DEOPT_IF(FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != version, LOAD_GLOBAL); ++ if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != version) { ++ UPDATE_MISS_STATS(LOAD_GLOBAL); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL)); ++ JUMP_TO_PREDICTED(LOAD_GLOBAL); ++ } + builtins_keys = keys; + assert(DK_IS_UNICODE(builtins_keys)); + } +@@ -6169,15 +8522,26 @@ + uint16_t index = read_u16(&this_instr[4].cache); + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(builtins_keys); + PyObject *res_o = FT_ATOMIC_LOAD_PTR_RELAXED(entries[index].me_value); +- DEOPT_IF(res_o == NULL, LOAD_GLOBAL); ++ if (res_o == NULL) { ++ UPDATE_MISS_STATS(LOAD_GLOBAL); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL)); ++ JUMP_TO_PREDICTED(LOAD_GLOBAL); ++ } + #if Py_GIL_DISABLED + int increfed = _Py_TryIncrefCompareStackRef(&entries[index].me_value, res_o, &res); +- DEOPT_IF(!increfed, LOAD_GLOBAL); ++ if (!increfed) { ++ UPDATE_MISS_STATS(LOAD_GLOBAL); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL)); ++ JUMP_TO_PREDICTED(LOAD_GLOBAL); ++ } + #else + Py_INCREF(res_o); + res = PyStackRef_FromPyObjectSteal(res_o); + #endif + STAT_INC(LOAD_GLOBAL, hit); ++ } ++ // _PUSH_NULL_CONDITIONAL ++ { + null = PyStackRef_NULL; + } + stack_pointer[0] = res; +@@ -6188,7 +8552,13 @@ + } + + TARGET(LOAD_GLOBAL_MODULE) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_GLOBAL_MODULE; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 5; + INSTRUCTION_STATS(LOAD_GLOBAL_MODULE); + static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); +@@ -6200,9 +8570,17 @@ + { + uint16_t version = read_u16(&this_instr[2].cache); + PyDictObject *dict = (PyDictObject *)GLOBALS(); +- DEOPT_IF(!PyDict_CheckExact(dict), LOAD_GLOBAL); ++ if (!PyDict_CheckExact(dict)) { ++ UPDATE_MISS_STATS(LOAD_GLOBAL); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL)); ++ JUMP_TO_PREDICTED(LOAD_GLOBAL); ++ } + PyDictKeysObject *keys = FT_ATOMIC_LOAD_PTR_ACQUIRE(dict->ma_keys); +- DEOPT_IF(FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != version, LOAD_GLOBAL); ++ if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != version) { ++ UPDATE_MISS_STATS(LOAD_GLOBAL); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL)); ++ JUMP_TO_PREDICTED(LOAD_GLOBAL); ++ } + globals_keys = keys; + assert(DK_IS_UNICODE(globals_keys)); + } +@@ -6212,15 +8590,26 @@ + uint16_t index = read_u16(&this_instr[4].cache); + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(globals_keys); + PyObject *res_o = FT_ATOMIC_LOAD_PTR_RELAXED(entries[index].me_value); +- DEOPT_IF(res_o == NULL, LOAD_GLOBAL); ++ if (res_o == NULL) { ++ UPDATE_MISS_STATS(LOAD_GLOBAL); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL)); ++ JUMP_TO_PREDICTED(LOAD_GLOBAL); ++ } + #if Py_GIL_DISABLED + int increfed = _Py_TryIncrefCompareStackRef(&entries[index].me_value, res_o, &res); +- DEOPT_IF(!increfed, LOAD_GLOBAL); ++ if (!increfed) { ++ UPDATE_MISS_STATS(LOAD_GLOBAL); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL)); ++ JUMP_TO_PREDICTED(LOAD_GLOBAL); ++ } + #else + Py_INCREF(res_o); + res = PyStackRef_FromPyObjectSteal(res_o); + #endif + STAT_INC(LOAD_GLOBAL, hit); ++ } ++ // _PUSH_NULL_CONDITIONAL ++ { + null = PyStackRef_NULL; + } + stack_pointer[0] = res; +@@ -6231,6 +8620,10 @@ + } + + TARGET(LOAD_LOCALS) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_LOCALS; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(LOAD_LOCALS); +@@ -6241,7 +8634,7 @@ + _PyErr_SetString(tstate, PyExc_SystemError, + "no locals found"); + stack_pointer = _PyFrame_GetStackPointer(frame); +- goto error; ++ JUMP_TO_LABEL(error); + } + locals = PyStackRef_FromPyObjectNew(l); + stack_pointer[0] = locals; +@@ -6251,6 +8644,10 @@ + } + + TARGET(LOAD_NAME) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_NAME; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(LOAD_NAME); +@@ -6259,7 +8656,9 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *v_o = _PyEval_LoadName(tstate, frame, name); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (v_o == NULL) goto error; ++ if (v_o == NULL) { ++ JUMP_TO_LABEL(error); ++ } + v = PyStackRef_FromPyObjectSteal(v_o); + stack_pointer[0] = v; + stack_pointer += 1; +@@ -6268,6 +8667,10 @@ + } + + TARGET(LOAD_SMALL_INT) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_SMALL_INT; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(LOAD_SMALL_INT); +@@ -6282,6 +8685,10 @@ + } + + TARGET(LOAD_SPECIAL) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_SPECIAL; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(LOAD_SPECIAL); +@@ -6306,7 +8713,7 @@ + Py_TYPE(owner_o)->tp_name); + stack_pointer = _PyFrame_GetStackPointer(frame); + } +- goto error; ++ JUMP_TO_LABEL(error); + } + attr = PyStackRef_FromPyObjectSteal(attr_o); + self_or_null = self_or_null_o == NULL ? +@@ -6319,12 +8726,17 @@ + } + + TARGET(LOAD_SUPER_ATTR) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_SUPER_ATTR; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(LOAD_SUPER_ATTR); +- PREDICTED(LOAD_SUPER_ATTR); ++ PREDICTED_LOAD_SUPER_ATTR:; + _Py_CODEUNIT* const this_instr = next_instr - 2; + (void)this_instr; ++ opcode = LOAD_SUPER_ATTR; + _PyStackRef global_super_st; + _PyStackRef class_st; + _PyStackRef self_st; +@@ -6366,7 +8778,7 @@ + PyStackRef_CLOSE(global_super_st); + PyStackRef_CLOSE(class_st); + PyStackRef_CLOSE(self_st); +- goto pop_3_error; ++ JUMP_TO_LABEL(pop_3_error); + } + } + // we make no attempt to optimize here; specializations should +@@ -6391,23 +8803,32 @@ + frame, this_instr, global_super, arg); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err < 0) { ++ _PyFrame_SetStackPointer(frame, stack_pointer); + Py_CLEAR(super); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + } + } + } + PyStackRef_CLOSE(global_super_st); + PyStackRef_CLOSE(class_st); + PyStackRef_CLOSE(self_st); +- if (super == NULL) goto pop_3_error; ++ if (super == NULL) { ++ JUMP_TO_LABEL(pop_3_error); ++ } + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); + stack_pointer += -3; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *attr_o = PyObject_GetAttr(super, name); +- stack_pointer = _PyFrame_GetStackPointer(frame); + Py_DECREF(super); +- if (attr_o == NULL) goto error; ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (attr_o == NULL) { ++ JUMP_TO_LABEL(error); ++ } + attr = PyStackRef_FromPyObjectSteal(attr_o); ++ } ++ // _PUSH_NULL_CONDITIONAL ++ { + null = PyStackRef_NULL; + } + stack_pointer[0] = attr; +@@ -6418,6 +8839,12 @@ + } + + TARGET(LOAD_SUPER_ATTR_ATTR) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_SUPER_ATTR_ATTR; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(LOAD_SUPER_ATTR_ATTR); +@@ -6434,8 +8861,16 @@ + PyObject *class = PyStackRef_AsPyObjectBorrow(class_st); + PyObject *self = PyStackRef_AsPyObjectBorrow(self_st); + assert(!(oparg & 1)); +- DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); +- DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); ++ if (global_super != (PyObject *)&PySuper_Type) { ++ UPDATE_MISS_STATS(LOAD_SUPER_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_SUPER_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_SUPER_ATTR); ++ } ++ if (!PyType_Check(class)) { ++ UPDATE_MISS_STATS(LOAD_SUPER_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_SUPER_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_SUPER_ATTR); ++ } + STAT_INC(LOAD_SUPER_ATTR, hit); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); + _PyFrame_SetStackPointer(frame, stack_pointer); +@@ -6444,7 +8879,9 @@ + PyStackRef_CLOSE(global_super_st); + PyStackRef_CLOSE(class_st); + PyStackRef_CLOSE(self_st); +- if (attr == NULL) goto pop_3_error; ++ if (attr == NULL) { ++ JUMP_TO_LABEL(pop_3_error); ++ } + attr_st = PyStackRef_FromPyObjectSteal(attr); + stack_pointer[-3] = attr_st; + stack_pointer += -2; +@@ -6453,6 +8890,12 @@ + } + + TARGET(LOAD_SUPER_ATTR_METHOD) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = LOAD_SUPER_ATTR_METHOD; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(LOAD_SUPER_ATTR_METHOD); +@@ -6470,8 +8913,16 @@ + PyObject *class = PyStackRef_AsPyObjectBorrow(class_st); + PyObject *self = PyStackRef_AsPyObjectBorrow(self_st); + assert(oparg & 1); +- DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); +- DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); ++ if (global_super != (PyObject *)&PySuper_Type) { ++ UPDATE_MISS_STATS(LOAD_SUPER_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_SUPER_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_SUPER_ATTR); ++ } ++ if (!PyType_Check(class)) { ++ UPDATE_MISS_STATS(LOAD_SUPER_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (LOAD_SUPER_ATTR)); ++ JUMP_TO_PREDICTED(LOAD_SUPER_ATTR); ++ } + STAT_INC(LOAD_SUPER_ATTR, hit); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); + PyTypeObject *cls = (PyTypeObject *)class; +@@ -6480,18 +8931,23 @@ + PyObject *attr_o = _PySuper_Lookup(cls, self, name, + Py_TYPE(self)->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); +- PyStackRef_CLOSE(global_super_st); +- PyStackRef_CLOSE(class_st); + if (attr_o == NULL) { +- PyStackRef_CLOSE(self_st); +- goto pop_3_error; ++ JUMP_TO_LABEL(error); + } + if (method_found) { + self_or_null = self_st; // transfer ownership + } else { ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(self_st); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + self_or_null = PyStackRef_NULL; ++ stack_pointer += 1; ++ assert(WITHIN_STACK_BOUNDS()); + } ++ PyStackRef_CLOSE(global_super_st); ++ PyStackRef_CLOSE(class_st); + attr = PyStackRef_FromPyObjectSteal(attr_o); + stack_pointer[-3] = attr; + stack_pointer[-2] = self_or_null; +@@ -6501,6 +8957,10 @@ + } + + TARGET(MAKE_CELL) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = MAKE_CELL; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(MAKE_CELL); +@@ -6509,13 +8969,21 @@ + PyObject *initial = PyStackRef_AsPyObjectBorrow(GETLOCAL(oparg)); + PyObject *cell = PyCell_New(initial); + if (cell == NULL) { +- goto error; ++ JUMP_TO_LABEL(error); + } +- SETLOCAL(oparg, PyStackRef_FromPyObjectSteal(cell)); ++ _PyStackRef tmp = GETLOCAL(oparg); ++ GETLOCAL(oparg) = PyStackRef_FromPyObjectSteal(cell); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_XCLOSE(tmp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + DISPATCH(); + } + + TARGET(MAKE_FUNCTION) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = MAKE_FUNCTION; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(MAKE_FUNCTION); +@@ -6527,16 +8995,28 @@ + PyFunctionObject *func_obj = (PyFunctionObject *) + PyFunction_New(codeobj, GLOBALS()); + stack_pointer = _PyFrame_GetStackPointer(frame); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(codeobj_st); +- if (func_obj == NULL) goto pop_1_error; ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (func_obj == NULL) { ++ JUMP_TO_LABEL(error); ++ } + _PyFunction_SetVersion( + func_obj, ((PyCodeObject *)codeobj)->co_version); + func = PyStackRef_FromPyObjectSteal((PyObject *)func_obj); +- stack_pointer[-1] = func; ++ stack_pointer[0] = func; ++ stack_pointer += 1; ++ assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(MAP_ADD) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = MAP_ADD; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(MAP_ADD); +@@ -6557,13 +9037,19 @@ + PyStackRef_AsPyObjectSteal(value) + ); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err != 0) goto pop_2_error; ++ if (err != 0) { ++ JUMP_TO_LABEL(pop_2_error); ++ } + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(MATCH_CLASS) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = MATCH_CLASS; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(MATCH_CLASS); +@@ -6591,7 +9077,9 @@ + attrs = PyStackRef_FromPyObjectSteal(attrs_o); + } + else { +- if (_PyErr_Occurred(tstate)) goto pop_3_error; ++ if (_PyErr_Occurred(tstate)) { ++ JUMP_TO_LABEL(pop_3_error); ++ } + // Error! + attrs = PyStackRef_None; // Failure! + } +@@ -6602,6 +9090,10 @@ + } + + TARGET(MATCH_KEYS) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = MATCH_KEYS; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(MATCH_KEYS); +@@ -6615,7 +9107,9 @@ + PyObject *values_or_none_o = _PyEval_MatchKeys(tstate, + PyStackRef_AsPyObjectBorrow(subject), PyStackRef_AsPyObjectBorrow(keys)); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (values_or_none_o == NULL) goto error; ++ if (values_or_none_o == NULL) { ++ JUMP_TO_LABEL(error); ++ } + values_or_none = PyStackRef_FromPyObjectSteal(values_or_none_o); + stack_pointer[0] = values_or_none; + stack_pointer += 1; +@@ -6624,6 +9118,10 @@ + } + + TARGET(MATCH_MAPPING) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = MATCH_MAPPING; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(MATCH_MAPPING); +@@ -6639,6 +9137,10 @@ + } + + TARGET(MATCH_SEQUENCE) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = MATCH_SEQUENCE; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(MATCH_SEQUENCE); +@@ -6654,13 +9156,32 @@ + } + + TARGET(NOP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = NOP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(NOP); + DISPATCH(); + } + ++ TARGET(NOT_TAKEN) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = NOT_TAKEN; ++ (void)(opcode); ++ #endif ++ frame->instr_ptr = next_instr; ++ next_instr += 1; ++ INSTRUCTION_STATS(NOT_TAKEN); ++ DISPATCH(); ++ } ++ + TARGET(POP_EXCEPT) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = POP_EXCEPT; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(POP_EXCEPT); +@@ -6677,9 +9198,30 @@ + DISPATCH(); + } + ++ TARGET(POP_ITER) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = POP_ITER; ++ (void)(opcode); ++ #endif ++ frame->instr_ptr = next_instr; ++ next_instr += 1; ++ INSTRUCTION_STATS(POP_ITER); ++ _PyStackRef value; ++ value = stack_pointer[-1]; ++ PyStackRef_CLOSE(value); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ DISPATCH(); ++ } ++ + TARGET(POP_JUMP_IF_FALSE) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = POP_JUMP_IF_FALSE; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(POP_JUMP_IF_FALSE); + _PyStackRef cond; +@@ -6688,15 +9230,20 @@ + assert(PyStackRef_BoolCheck(cond)); + int flag = PyStackRef_IsFalse(cond); + RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); +- JUMPBY(oparg * flag); ++ JUMPBY(flag ? oparg : next_instr->op.code == NOT_TAKEN); + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(POP_JUMP_IF_NONE) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = POP_JUMP_IF_NONE; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(POP_JUMP_IF_NONE); + _PyStackRef value; +@@ -6720,7 +9267,7 @@ + assert(PyStackRef_BoolCheck(cond)); + int flag = PyStackRef_IsTrue(cond); + RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); +- JUMPBY(oparg * flag); ++ JUMPBY(flag ? oparg : next_instr->op.code == NOT_TAKEN); + } + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); +@@ -6728,8 +9275,13 @@ + } + + TARGET(POP_JUMP_IF_NOT_NONE) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = POP_JUMP_IF_NOT_NONE; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(POP_JUMP_IF_NOT_NONE); + _PyStackRef value; +@@ -6753,7 +9305,7 @@ + assert(PyStackRef_BoolCheck(cond)); + int flag = PyStackRef_IsFalse(cond); + RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); +- JUMPBY(oparg * flag); ++ JUMPBY(flag ? oparg : next_instr->op.code == NOT_TAKEN); + } + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); +@@ -6761,8 +9313,13 @@ + } + + TARGET(POP_JUMP_IF_TRUE) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = POP_JUMP_IF_TRUE; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(POP_JUMP_IF_TRUE); + _PyStackRef cond; +@@ -6771,13 +9328,17 @@ + assert(PyStackRef_BoolCheck(cond)); + int flag = PyStackRef_IsTrue(cond); + RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); +- JUMPBY(oparg * flag); ++ JUMPBY(flag ? oparg : next_instr->op.code == NOT_TAKEN); + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(POP_TOP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = POP_TOP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(POP_TOP); +@@ -6790,6 +9351,10 @@ + } + + TARGET(PUSH_EXC_INFO) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = PUSH_EXC_INFO; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(PUSH_EXC_INFO); +@@ -6815,6 +9380,10 @@ + } + + TARGET(PUSH_NULL) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = PUSH_NULL; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(PUSH_NULL); +@@ -6827,8 +9396,13 @@ + } + + TARGET(RAISE_VARARGS) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = RAISE_VARARGS; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(RAISE_VARARGS); + _PyStackRef *args; +@@ -6846,14 +9420,20 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + monitor_reraise(tstate, frame, this_instr); + stack_pointer = _PyFrame_GetStackPointer(frame); +- goto exception_unwind; ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ JUMP_TO_LABEL(exception_unwind); + } +- goto error; ++ JUMP_TO_LABEL(error); + } + + TARGET(RERAISE) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = RERAISE; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(RERAISE); + _PyStackRef *values; +@@ -6865,11 +9445,7 @@ + if (oparg) { + PyObject *lasti = PyStackRef_AsPyObjectBorrow(values[0]); + if (PyLong_Check(lasti)) { +- stack_pointer += -1; +- assert(WITHIN_STACK_BOUNDS()); +- _PyFrame_SetStackPointer(frame, stack_pointer); + frame->instr_ptr = _PyFrame_GetBytecode(frame) + PyLong_AsLong(lasti); +- stack_pointer = _PyFrame_GetStackPointer(frame); + assert(!_PyErr_Occurred(tstate)); + } + else { +@@ -6877,12 +9453,10 @@ + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyErr_SetString(tstate, PyExc_SystemError, "lasti is not an int"); +- stack_pointer = _PyFrame_GetStackPointer(frame); + Py_DECREF(exc); +- goto error; ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ JUMP_TO_LABEL(error); + } +- stack_pointer += 1; +- assert(WITHIN_STACK_BOUNDS()); + } + assert(exc && PyExceptionInstance_Check(exc)); + stack_pointer += -1; +@@ -6891,10 +9465,15 @@ + _PyErr_SetRaisedException(tstate, exc); + monitor_reraise(tstate, frame, this_instr); + stack_pointer = _PyFrame_GetStackPointer(frame); +- goto exception_unwind; ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ JUMP_TO_LABEL(exception_unwind); + } + + TARGET(RESERVED) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = RESERVED; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(RESERVED); +@@ -6904,10 +9483,14 @@ + } + + TARGET(RESUME) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = RESUME; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(RESUME); +- PREDICTED(RESUME); ++ PREDICTED_RESUME:; + _Py_CODEUNIT* const this_instr = next_instr - 1; + (void)this_instr; + // _LOAD_BYTECODE +@@ -6919,10 +9502,10 @@ + _Py_CODEUNIT *bytecode = + _PyEval_GetExecutableCode(tstate, _PyFrame_GetCode(frame)); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (bytecode == NULL) goto error; +- _PyFrame_SetStackPointer(frame, stack_pointer); ++ if (bytecode == NULL) { ++ JUMP_TO_LABEL(error); ++ } + ptrdiff_t off = this_instr - _PyFrame_GetBytecode(frame); +- stack_pointer = _PyFrame_GetStackPointer(frame); + frame->tlbc_index = ((_PyThreadStateImpl *)tstate)->tlbc_index; + frame->instr_ptr = bytecode + off; + // Make sure this_instr gets reset correctley for any uops that +@@ -6942,7 +9525,7 @@ + int err = _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err) { +- goto error; ++ JUMP_TO_LABEL(error); + } + next_instr = this_instr; + DISPATCH(); +@@ -6966,7 +9549,9 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err != 0) goto error; ++ if (err != 0) { ++ JUMP_TO_LABEL(error); ++ } + } + } + } +@@ -6974,26 +9559,48 @@ + } + + TARGET(RESUME_CHECK) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = RESUME_CHECK; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(RESUME_CHECK); + static_assert(0 == 0, "incorrect cache size"); + #if defined(__EMSCRIPTEN__) +- DEOPT_IF(_Py_emscripten_signal_clock == 0, RESUME); ++ if (_Py_emscripten_signal_clock == 0) { ++ UPDATE_MISS_STATS(RESUME); ++ assert(_PyOpcode_Deopt[opcode] == (RESUME)); ++ JUMP_TO_PREDICTED(RESUME); ++ } + _Py_emscripten_signal_clock -= Py_EMSCRIPTEN_SIGNAL_HANDLING; + #endif + uintptr_t eval_breaker = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker); + uintptr_t version = FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version); + assert((version & _PY_EVAL_EVENTS_MASK) == 0); +- DEOPT_IF(eval_breaker != version, RESUME); ++ if (eval_breaker != version) { ++ UPDATE_MISS_STATS(RESUME); ++ assert(_PyOpcode_Deopt[opcode] == (RESUME)); ++ JUMP_TO_PREDICTED(RESUME); ++ } + #ifdef Py_GIL_DISABLED +- DEOPT_IF(frame->tlbc_index != +- ((_PyThreadStateImpl *)tstate)->tlbc_index, RESUME); ++ if (frame->tlbc_index != ++ ((_PyThreadStateImpl *)tstate)->tlbc_index) { ++ UPDATE_MISS_STATS(RESUME); ++ assert(_PyOpcode_Deopt[opcode] == (RESUME)); ++ JUMP_TO_PREDICTED(RESUME); ++ } + #endif + DISPATCH(); + } + + TARGET(RETURN_GENERATOR) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = RETURN_GENERATOR; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(RETURN_GENERATOR); +@@ -7003,7 +9610,9 @@ + _PyFrame_SetStackPointer(frame, stack_pointer); + PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (gen == NULL) goto error; ++ if (gen == NULL) { ++ JUMP_TO_LABEL(error); ++ } + assert(EMPTY()); + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyInterpreterFrame *gen_frame = &gen->gi_iframe; +@@ -7027,15 +9636,17 @@ + } + + TARGET(RETURN_VALUE) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = RETURN_VALUE; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(RETURN_VALUE); + _PyStackRef retval; + _PyStackRef res; + retval = stack_pointer[-1]; +- #if TIER_ONE +- assert(frame != &entry_frame); +- #endif ++ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); + _PyStackRef temp = retval; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); +@@ -7057,10 +9668,14 @@ + } + + TARGET(SEND) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = SEND; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(SEND); +- PREDICTED(SEND); ++ PREDICTED_SEND:; + _Py_CODEUNIT* const this_instr = next_instr - 2; + (void)this_instr; + _PyStackRef receiver; +@@ -7088,7 +9703,7 @@ + v = stack_pointer[-1]; + PyObject *receiver_o = PyStackRef_AsPyObjectBorrow(receiver); + PyObject *retval_o; +- assert(frame != &entry_frame); ++ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); + if ((tstate->interp->eval_frame == NULL) && + (Py_TYPE(receiver_o) == &PyGen_Type || Py_TYPE(receiver_o) == &PyCoro_Type) && + ((PyGenObject *)receiver_o)->gi_frame_state < FRAME_EXECUTING) +@@ -7136,17 +9751,29 @@ + } + else { + PyStackRef_CLOSE(v); +- goto pop_1_error; ++ JUMP_TO_LABEL(pop_1_error); + } + } ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(v); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + retval = PyStackRef_FromPyObjectSteal(retval_o); + } +- stack_pointer[-1] = retval; ++ stack_pointer[0] = retval; ++ stack_pointer += 1; ++ assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(SEND_GEN) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = SEND_GEN; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(SEND_GEN); +@@ -7158,15 +9785,27 @@ + /* Skip 1 cache entry */ + // _CHECK_PEP_523 + { +- DEOPT_IF(tstate->interp->eval_frame, SEND); ++ if (tstate->interp->eval_frame) { ++ UPDATE_MISS_STATS(SEND); ++ assert(_PyOpcode_Deopt[opcode] == (SEND)); ++ JUMP_TO_PREDICTED(SEND); ++ } + } + // _SEND_GEN_FRAME + { + v = stack_pointer[-1]; + receiver = stack_pointer[-2]; + PyGenObject *gen = (PyGenObject *)PyStackRef_AsPyObjectBorrow(receiver); +- DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type, SEND); +- DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, SEND); ++ if (Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type) { ++ UPDATE_MISS_STATS(SEND); ++ assert(_PyOpcode_Deopt[opcode] == (SEND)); ++ JUMP_TO_PREDICTED(SEND); ++ } ++ if (gen->gi_frame_state >= FRAME_EXECUTING) { ++ UPDATE_MISS_STATS(SEND); ++ assert(_PyOpcode_Deopt[opcode] == (SEND)); ++ JUMP_TO_PREDICTED(SEND); ++ } + STAT_INC(SEND, hit); + gen_frame = &gen->gi_iframe; + _PyFrame_StackPush(gen_frame, v); +@@ -7199,6 +9838,10 @@ + } + + TARGET(SETUP_ANNOTATIONS) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = SETUP_ANNOTATIONS; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(SETUP_ANNOTATIONS); +@@ -7208,32 +9851,44 @@ + _PyErr_Format(tstate, PyExc_SystemError, + "no locals found when setting up annotations"); + stack_pointer = _PyFrame_GetStackPointer(frame); +- goto error; ++ JUMP_TO_LABEL(error); + } + /* check if __annotations__ in locals()... */ + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = PyMapping_GetOptionalItem(LOCALS(), &_Py_ID(__annotations__), &ann_dict); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (err < 0) goto error; ++ if (err < 0) { ++ JUMP_TO_LABEL(error); ++ } + if (ann_dict == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); + ann_dict = PyDict_New(); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (ann_dict == NULL) goto error; ++ if (ann_dict == NULL) { ++ JUMP_TO_LABEL(error); ++ } + _PyFrame_SetStackPointer(frame, stack_pointer); + err = PyObject_SetItem(LOCALS(), &_Py_ID(__annotations__), + ann_dict); +- stack_pointer = _PyFrame_GetStackPointer(frame); + Py_DECREF(ann_dict); +- if (err) goto error; ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (err) { ++ JUMP_TO_LABEL(error); ++ } + } + else { ++ _PyFrame_SetStackPointer(frame, stack_pointer); + Py_DECREF(ann_dict); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + } + DISPATCH(); + } + + TARGET(SET_ADD) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = SET_ADD; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(SET_ADD); +@@ -7246,13 +9901,19 @@ + PyStackRef_AsPyObjectBorrow(v)); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(v); +- if (err) goto pop_1_error; ++ if (err) { ++ JUMP_TO_LABEL(pop_1_error); ++ } + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(SET_FUNCTION_ATTRIBUTE) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = SET_FUNCTION_ATTRIBUTE; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(SET_FUNCTION_ATTRIBUTE); +@@ -7277,6 +9938,10 @@ + } + + TARGET(SET_UPDATE) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = SET_UPDATE; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(SET_UPDATE); +@@ -7289,17 +9954,23 @@ + PyStackRef_AsPyObjectBorrow(iterable)); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(iterable); +- if (err < 0) goto pop_1_error; ++ if (err < 0) { ++ JUMP_TO_LABEL(pop_1_error); ++ } + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(STORE_ATTR) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = STORE_ATTR; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 5; + INSTRUCTION_STATS(STORE_ATTR); +- PREDICTED(STORE_ATTR); ++ PREDICTED_STORE_ATTR:; + _Py_CODEUNIT* const this_instr = next_instr - 5; + (void)this_instr; + _PyStackRef owner; +@@ -7309,7 +9980,7 @@ + owner = stack_pointer[-1]; + uint16_t counter = read_u16(&this_instr[1].cache); + (void)counter; +- #if ENABLE_SPECIALIZATION ++ #if ENABLE_SPECIALIZATION_FT + if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + next_instr = this_instr; +@@ -7320,7 +9991,7 @@ + } + OPCODE_DEFERRED_INC(STORE_ATTR); + ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); +- #endif /* ENABLE_SPECIALIZATION */ ++ #endif /* ENABLE_SPECIALIZATION_FT */ + } + /* Skip 3 cache entries */ + // _STORE_ATTR +@@ -7333,7 +10004,9 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(v); + PyStackRef_CLOSE(owner); +- if (err) goto pop_2_error; ++ if (err) { ++ JUMP_TO_LABEL(pop_2_error); ++ } + } + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); +@@ -7341,28 +10014,54 @@ + } + + TARGET(STORE_ATTR_INSTANCE_VALUE) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = STORE_ATTR_INSTANCE_VALUE; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 5; + INSTRUCTION_STATS(STORE_ATTR_INSTANCE_VALUE); + static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size"); + _PyStackRef owner; + _PyStackRef value; + /* Skip 1 cache entry */ +- // _GUARD_TYPE_VERSION ++ // _GUARD_TYPE_VERSION_AND_LOCK + { + owner = stack_pointer[-1]; + uint32_t type_version = read_u32(&this_instr[2].cache); +- PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); ++ PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + assert(type_version != 0); +- DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); ++ if (!LOCK_OBJECT(owner_o)) { ++ UPDATE_MISS_STATS(STORE_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR)); ++ JUMP_TO_PREDICTED(STORE_ATTR); ++ } ++ PyTypeObject *tp = Py_TYPE(owner_o); ++ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { ++ UNLOCK_OBJECT(owner_o); ++ if (true) { ++ UPDATE_MISS_STATS(STORE_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR)); ++ JUMP_TO_PREDICTED(STORE_ATTR); ++ } ++ } + } + // _GUARD_DORV_NO_DICT + { + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + assert(Py_TYPE(owner_o)->tp_dictoffset < 0); + assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); +- DEOPT_IF(_PyObject_GetManagedDict(owner_o), STORE_ATTR); +- DEOPT_IF(_PyObject_InlineValues(owner_o)->valid == 0, STORE_ATTR); ++ if (_PyObject_GetManagedDict(owner_o) || ++ !FT_ATOMIC_LOAD_UINT8(_PyObject_InlineValues(owner_o)->valid)) { ++ UNLOCK_OBJECT(owner_o); ++ if (true) { ++ UPDATE_MISS_STATS(STORE_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR)); ++ JUMP_TO_PREDICTED(STORE_ATTR); ++ } ++ } + } + // _STORE_ATTR_INSTANCE_VALUE + { +@@ -7373,24 +10072,31 @@ + assert(_PyObject_GetManagedDict(owner_o) == NULL); + PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); + PyObject *old_value = *value_ptr; +- *value_ptr = PyStackRef_AsPyObjectSteal(value); ++ FT_ATOMIC_STORE_PTR_RELEASE(*value_ptr, PyStackRef_AsPyObjectSteal(value)); + if (old_value == NULL) { + PyDictValues *values = _PyObject_InlineValues(owner_o); + Py_ssize_t index = value_ptr - values->values; + _PyDictValues_AddToInsertionOrder(values, index); + } +- else { +- Py_DECREF(old_value); +- } ++ UNLOCK_OBJECT(owner_o); ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(owner); ++ Py_XDECREF(old_value); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + } +- stack_pointer += -2; +- assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(STORE_ATTR_SLOT) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = STORE_ATTR_SLOT; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 5; + INSTRUCTION_STATS(STORE_ATTR_SLOT); + static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size"); +@@ -7403,27 +10109,45 @@ + uint32_t type_version = read_u32(&this_instr[2].cache); + PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + assert(type_version != 0); +- DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); ++ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { ++ UPDATE_MISS_STATS(STORE_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR)); ++ JUMP_TO_PREDICTED(STORE_ATTR); ++ } + } + // _STORE_ATTR_SLOT + { + value = stack_pointer[-2]; + uint16_t index = read_u16(&this_instr[4].cache); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); ++ if (!LOCK_OBJECT(owner_o)) { ++ UPDATE_MISS_STATS(STORE_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR)); ++ JUMP_TO_PREDICTED(STORE_ATTR); ++ } + char *addr = (char *)owner_o + index; + STAT_INC(STORE_ATTR, hit); + PyObject *old_value = *(PyObject **)addr; +- *(PyObject **)addr = PyStackRef_AsPyObjectSteal(value); +- Py_XDECREF(old_value); ++ FT_ATOMIC_STORE_PTR_RELEASE(*(PyObject **)addr, PyStackRef_AsPyObjectSteal(value)); ++ UNLOCK_OBJECT(owner_o); ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(owner); ++ Py_XDECREF(old_value); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + } +- stack_pointer += -2; +- assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(STORE_ATTR_WITH_HINT) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = STORE_ATTR_WITH_HINT; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 5; + INSTRUCTION_STATS(STORE_ATTR_WITH_HINT); + static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size"); +@@ -7436,7 +10160,11 @@ + uint32_t type_version = read_u32(&this_instr[2].cache); + PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + assert(type_version != 0); +- DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); ++ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { ++ UPDATE_MISS_STATS(STORE_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR)); ++ JUMP_TO_PREDICTED(STORE_ATTR); ++ } + } + // _STORE_ATTR_WITH_HINT + { +@@ -7445,31 +10173,78 @@ + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_MANAGED_DICT); + PyDictObject *dict = _PyObject_GetManagedDict(owner_o); +- DEOPT_IF(dict == NULL, STORE_ATTR); ++ if (dict == NULL) { ++ UPDATE_MISS_STATS(STORE_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR)); ++ JUMP_TO_PREDICTED(STORE_ATTR); ++ } ++ if (!LOCK_OBJECT(dict)) { ++ UPDATE_MISS_STATS(STORE_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR)); ++ JUMP_TO_PREDICTED(STORE_ATTR); ++ } ++ #ifdef Py_GIL_DISABLED ++ if (dict != _PyObject_GetManagedDict(owner_o)) { ++ UNLOCK_OBJECT(dict); ++ if (true) { ++ UPDATE_MISS_STATS(STORE_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR)); ++ JUMP_TO_PREDICTED(STORE_ATTR); ++ } ++ } ++ #endif + assert(PyDict_CheckExact((PyObject *)dict)); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); +- DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, STORE_ATTR); +- DEOPT_IF(!DK_IS_UNICODE(dict->ma_keys), STORE_ATTR); ++ if (hint >= (size_t)dict->ma_keys->dk_nentries || ++ !DK_IS_UNICODE(dict->ma_keys)) { ++ UNLOCK_OBJECT(dict); ++ if (true) { ++ UPDATE_MISS_STATS(STORE_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR)); ++ JUMP_TO_PREDICTED(STORE_ATTR); ++ } ++ } + PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; +- DEOPT_IF(ep->me_key != name, STORE_ATTR); ++ if (ep->me_key != name) { ++ UNLOCK_OBJECT(dict); ++ if (true) { ++ UPDATE_MISS_STATS(STORE_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR)); ++ JUMP_TO_PREDICTED(STORE_ATTR); ++ } ++ } + PyObject *old_value = ep->me_value; +- DEOPT_IF(old_value == NULL, STORE_ATTR); ++ if (old_value == NULL) { ++ UNLOCK_OBJECT(dict); ++ if (true) { ++ UPDATE_MISS_STATS(STORE_ATTR); ++ assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR)); ++ JUMP_TO_PREDICTED(STORE_ATTR); ++ } ++ } + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyDict_NotifyEvent(tstate->interp, PyDict_EVENT_MODIFIED, dict, name, PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); +- ep->me_value = PyStackRef_AsPyObjectSteal(value); ++ FT_ATOMIC_STORE_PTR_RELEASE(ep->me_value, PyStackRef_AsPyObjectSteal(value)); ++ UNLOCK_OBJECT(dict); + // old_value should be DECREFed after GC track checking is done, if not, it could raise a segmentation fault, + // when dict only holds the strong reference to value in ep->me_value. +- Py_XDECREF(old_value); + STAT_INC(STORE_ATTR, hit); ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(owner); ++ Py_XDECREF(old_value); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + } +- stack_pointer += -2; +- assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(STORE_DEREF) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = STORE_DEREF; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(STORE_DEREF); +@@ -7485,18 +10260,30 @@ + } + + TARGET(STORE_FAST) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = STORE_FAST; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(STORE_FAST); + _PyStackRef value; + value = stack_pointer[-1]; +- SETLOCAL(oparg, value); ++ _PyStackRef tmp = GETLOCAL(oparg); ++ GETLOCAL(oparg) = value; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_XCLOSE(tmp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + DISPATCH(); + } + + TARGET(STORE_FAST_LOAD_FAST) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = STORE_FAST_LOAD_FAST; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(STORE_FAST_LOAD_FAST); +@@ -7505,13 +10292,21 @@ + value1 = stack_pointer[-1]; + uint32_t oparg1 = oparg >> 4; + uint32_t oparg2 = oparg & 15; +- SETLOCAL(oparg1, value1); ++ _PyStackRef tmp = GETLOCAL(oparg1); ++ GETLOCAL(oparg1) = value1; + value2 = PyStackRef_DUP(GETLOCAL(oparg2)); + stack_pointer[-1] = value2; ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_XCLOSE(tmp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + DISPATCH(); + } + + TARGET(STORE_FAST_STORE_FAST) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = STORE_FAST_STORE_FAST; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(STORE_FAST_STORE_FAST); +@@ -7521,14 +10316,28 @@ + value2 = stack_pointer[-2]; + uint32_t oparg1 = oparg >> 4; + uint32_t oparg2 = oparg & 15; +- SETLOCAL(oparg1, value1); +- SETLOCAL(oparg2, value2); +- stack_pointer += -2; ++ _PyStackRef tmp = GETLOCAL(oparg1); ++ GETLOCAL(oparg1) = value1; ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_XCLOSE(tmp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ tmp = GETLOCAL(oparg2); ++ GETLOCAL(oparg2) = value2; ++ stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_XCLOSE(tmp); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + DISPATCH(); + } + + TARGET(STORE_GLOBAL) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = STORE_GLOBAL; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(STORE_GLOBAL); +@@ -7539,13 +10348,19 @@ + int err = PyDict_SetItem(GLOBALS(), name, PyStackRef_AsPyObjectBorrow(v)); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(v); +- if (err) goto pop_1_error; ++ if (err) { ++ JUMP_TO_LABEL(pop_1_error); ++ } + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(STORE_NAME) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = STORE_NAME; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(STORE_NAME); +@@ -7560,7 +10375,7 @@ + "no locals found when storing %R", name); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(v); +- goto pop_1_error; ++ JUMP_TO_LABEL(pop_1_error); + } + if (PyDict_CheckExact(ns)) { + _PyFrame_SetStackPointer(frame, stack_pointer); +@@ -7573,13 +10388,19 @@ + stack_pointer = _PyFrame_GetStackPointer(frame); + } + PyStackRef_CLOSE(v); +- if (err) goto pop_1_error; ++ if (err) { ++ JUMP_TO_LABEL(pop_1_error); ++ } + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(STORE_SLICE) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = STORE_SLICE; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(STORE_SLICE); +@@ -7613,14 +10434,16 @@ + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + err = PyObject_SetItem(PyStackRef_AsPyObjectBorrow(container), slice, PyStackRef_AsPyObjectBorrow(v)); +- stack_pointer = _PyFrame_GetStackPointer(frame); + Py_DECREF(slice); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += 2; + assert(WITHIN_STACK_BOUNDS()); + } + PyStackRef_CLOSE(v); + PyStackRef_CLOSE(container); +- if (err) goto pop_4_error; ++ if (err) { ++ JUMP_TO_LABEL(pop_4_error); ++ } + } + stack_pointer += -4; + assert(WITHIN_STACK_BOUNDS()); +@@ -7628,10 +10451,14 @@ + } + + TARGET(STORE_SUBSCR) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = STORE_SUBSCR; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(STORE_SUBSCR); +- PREDICTED(STORE_SUBSCR); ++ PREDICTED_STORE_SUBSCR:; + _Py_CODEUNIT* const this_instr = next_instr - 2; + (void)this_instr; + _PyStackRef container; +@@ -7665,7 +10492,9 @@ + PyStackRef_CLOSE(v); + PyStackRef_CLOSE(container); + PyStackRef_CLOSE(sub); +- if (err) goto pop_3_error; ++ if (err) { ++ JUMP_TO_LABEL(pop_3_error); ++ } + } + stack_pointer += -3; + assert(WITHIN_STACK_BOUNDS()); +@@ -7673,6 +10502,12 @@ + } + + TARGET(STORE_SUBSCR_DICT) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = STORE_SUBSCR_DICT; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(STORE_SUBSCR_DICT); +@@ -7685,21 +10520,35 @@ + dict_st = stack_pointer[-2]; + value = stack_pointer[-3]; + PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st); +- DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); ++ if (!PyDict_CheckExact(dict)) { ++ UPDATE_MISS_STATS(STORE_SUBSCR); ++ assert(_PyOpcode_Deopt[opcode] == (STORE_SUBSCR)); ++ JUMP_TO_PREDICTED(STORE_SUBSCR); ++ } + STAT_INC(STORE_SUBSCR, hit); + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _PyDict_SetItem_Take2((PyDictObject *)dict, + PyStackRef_AsPyObjectSteal(sub), + PyStackRef_AsPyObjectSteal(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); +- PyStackRef_CLOSE(dict_st); +- if (err) goto pop_3_error; + stack_pointer += -3; + assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(dict_st); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (err) { ++ JUMP_TO_LABEL(error); ++ } + DISPATCH(); + } + + TARGET(STORE_SUBSCR_LIST_INT) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = STORE_SUBSCR_LIST_INT; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(STORE_SUBSCR_LIST_INT); +@@ -7713,53 +10562,80 @@ + value = stack_pointer[-3]; + PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); + PyObject *list = PyStackRef_AsPyObjectBorrow(list_st); +- DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); +- DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); ++ if (!PyLong_CheckExact(sub)) { ++ UPDATE_MISS_STATS(STORE_SUBSCR); ++ assert(_PyOpcode_Deopt[opcode] == (STORE_SUBSCR)); ++ JUMP_TO_PREDICTED(STORE_SUBSCR); ++ } ++ if (!PyList_CheckExact(list)) { ++ UPDATE_MISS_STATS(STORE_SUBSCR); ++ assert(_PyOpcode_Deopt[opcode] == (STORE_SUBSCR)); ++ JUMP_TO_PREDICTED(STORE_SUBSCR); ++ } + // Ensure nonnegative, zero-or-one-digit ints. +- DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), STORE_SUBSCR); ++ if (!_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) { ++ UPDATE_MISS_STATS(STORE_SUBSCR); ++ assert(_PyOpcode_Deopt[opcode] == (STORE_SUBSCR)); ++ JUMP_TO_PREDICTED(STORE_SUBSCR); ++ } + Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; +- DEOPT_IF(!LOCK_OBJECT(list), STORE_SUBSCR); ++ if (!LOCK_OBJECT(list)) { ++ UPDATE_MISS_STATS(STORE_SUBSCR); ++ assert(_PyOpcode_Deopt[opcode] == (STORE_SUBSCR)); ++ JUMP_TO_PREDICTED(STORE_SUBSCR); ++ } + // Ensure index < len(list) + if (index >= PyList_GET_SIZE(list)) { + UNLOCK_OBJECT(list); +- DEOPT_IF(true, STORE_SUBSCR); ++ if (true) { ++ UPDATE_MISS_STATS(STORE_SUBSCR); ++ assert(_PyOpcode_Deopt[opcode] == (STORE_SUBSCR)); ++ JUMP_TO_PREDICTED(STORE_SUBSCR); ++ } + } + STAT_INC(STORE_SUBSCR, hit); + PyObject *old_value = PyList_GET_ITEM(list, index); + PyList_SET_ITEM(list, index, PyStackRef_AsPyObjectSteal(value)); + assert(old_value != NULL); + UNLOCK_OBJECT(list); // unlock before decrefs! +- Py_DECREF(old_value); + PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); +- PyStackRef_CLOSE(list_st); + stack_pointer += -3; + assert(WITHIN_STACK_BOUNDS()); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyStackRef_CLOSE(list_st); ++ Py_DECREF(old_value); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + DISPATCH(); + } + + TARGET(SWAP) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = SWAP; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(SWAP); +- _PyStackRef bottom_in; +- _PyStackRef top_in; +- _PyStackRef top_out; +- _PyStackRef bottom_out; +- top_in = stack_pointer[-1]; +- bottom_in = stack_pointer[-2 - (oparg-2)]; +- bottom_out = bottom_in; +- top_out = top_in; ++ _PyStackRef *bottom; ++ _PyStackRef *top; ++ top = &stack_pointer[-1]; ++ bottom = &stack_pointer[-2 - (oparg-2)]; ++ _PyStackRef temp = bottom[0]; ++ bottom[0] = top[0]; ++ top[0] = temp; + assert(oparg >= 2); +- stack_pointer[-2 - (oparg-2)] = top_out; +- stack_pointer[-1] = bottom_out; + DISPATCH(); + } + + TARGET(TO_BOOL) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = TO_BOOL; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(TO_BOOL); +- PREDICTED(TO_BOOL); ++ PREDICTED_TO_BOOL:; + _Py_CODEUNIT* const this_instr = next_instr - 4; + (void)this_instr; + _PyStackRef value; +@@ -7788,7 +10664,9 @@ + int err = PyObject_IsTrue(PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(value); +- if (err < 0) goto pop_1_error; ++ if (err < 0) { ++ JUMP_TO_LABEL(pop_1_error); ++ } + res = err ? PyStackRef_True : PyStackRef_False; + } + stack_pointer[-1] = res; +@@ -7796,7 +10674,13 @@ + } + + TARGET(TO_BOOL_ALWAYS_TRUE) { +- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = TO_BOOL_ALWAYS_TRUE; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; ++ frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(TO_BOOL_ALWAYS_TRUE); + static_assert(INLINE_CACHE_ENTRIES_TO_BOOL == 3, "incorrect cache size"); +@@ -7810,7 +10694,11 @@ + uint32_t type_version = read_u32(&this_instr[2].cache); + PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + assert(type_version != 0); +- DEOPT_IF(tp->tp_version_tag != type_version, TO_BOOL); ++ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { ++ UPDATE_MISS_STATS(TO_BOOL); ++ assert(_PyOpcode_Deopt[opcode] == (TO_BOOL)); ++ JUMP_TO_PREDICTED(TO_BOOL); ++ } + } + // _REPLACE_WITH_TRUE + { +@@ -7823,6 +10711,12 @@ + } + + TARGET(TO_BOOL_BOOL) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = TO_BOOL_BOOL; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(TO_BOOL_BOOL); +@@ -7831,12 +10725,22 @@ + /* Skip 1 cache entry */ + /* Skip 2 cache entries */ + value = stack_pointer[-1]; +- DEOPT_IF(!PyStackRef_BoolCheck(value), TO_BOOL); ++ if (!PyStackRef_BoolCheck(value)) { ++ UPDATE_MISS_STATS(TO_BOOL); ++ assert(_PyOpcode_Deopt[opcode] == (TO_BOOL)); ++ JUMP_TO_PREDICTED(TO_BOOL); ++ } + STAT_INC(TO_BOOL, hit); + DISPATCH(); + } + + TARGET(TO_BOOL_INT) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = TO_BOOL_INT; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(TO_BOOL_INT); +@@ -7847,7 +10751,11 @@ + /* Skip 2 cache entries */ + value = stack_pointer[-1]; + PyObject *value_o = PyStackRef_AsPyObjectBorrow(value); +- DEOPT_IF(!PyLong_CheckExact(value_o), TO_BOOL); ++ if (!PyLong_CheckExact(value_o)) { ++ UPDATE_MISS_STATS(TO_BOOL); ++ assert(_PyOpcode_Deopt[opcode] == (TO_BOOL)); ++ JUMP_TO_PREDICTED(TO_BOOL); ++ } + STAT_INC(TO_BOOL, hit); + if (_PyLong_IsZero((PyLongObject *)value_o)) { + assert(_Py_IsImmortal(value_o)); +@@ -7862,6 +10770,12 @@ + } + + TARGET(TO_BOOL_LIST) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = TO_BOOL_LIST; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(TO_BOOL_LIST); +@@ -7872,7 +10786,11 @@ + /* Skip 2 cache entries */ + value = stack_pointer[-1]; + PyObject *value_o = PyStackRef_AsPyObjectBorrow(value); +- DEOPT_IF(!PyList_CheckExact(value_o), TO_BOOL); ++ if (!PyList_CheckExact(value_o)) { ++ UPDATE_MISS_STATS(TO_BOOL); ++ assert(_PyOpcode_Deopt[opcode] == (TO_BOOL)); ++ JUMP_TO_PREDICTED(TO_BOOL); ++ } + STAT_INC(TO_BOOL, hit); + res = PyList_GET_SIZE(value_o) ? PyStackRef_True : PyStackRef_False; + PyStackRef_CLOSE(value); +@@ -7881,6 +10799,12 @@ + } + + TARGET(TO_BOOL_NONE) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = TO_BOOL_NONE; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(TO_BOOL_NONE); +@@ -7891,7 +10815,11 @@ + /* Skip 2 cache entries */ + value = stack_pointer[-1]; + // This one is a bit weird, because we expect *some* failures: +- DEOPT_IF(!PyStackRef_IsNone(value), TO_BOOL); ++ if (!PyStackRef_IsNone(value)) { ++ UPDATE_MISS_STATS(TO_BOOL); ++ assert(_PyOpcode_Deopt[opcode] == (TO_BOOL)); ++ JUMP_TO_PREDICTED(TO_BOOL); ++ } + STAT_INC(TO_BOOL, hit); + res = PyStackRef_False; + stack_pointer[-1] = res; +@@ -7899,6 +10827,12 @@ + } + + TARGET(TO_BOOL_STR) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = TO_BOOL_STR; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(TO_BOOL_STR); +@@ -7909,7 +10843,11 @@ + /* Skip 2 cache entries */ + value = stack_pointer[-1]; + PyObject *value_o = PyStackRef_AsPyObjectBorrow(value); +- DEOPT_IF(!PyUnicode_CheckExact(value_o), TO_BOOL); ++ if (!PyUnicode_CheckExact(value_o)) { ++ UPDATE_MISS_STATS(TO_BOOL); ++ assert(_PyOpcode_Deopt[opcode] == (TO_BOOL)); ++ JUMP_TO_PREDICTED(TO_BOOL); ++ } + STAT_INC(TO_BOOL, hit); + if (value_o == &_Py_STR(empty)) { + assert(_Py_IsImmortal(value_o)); +@@ -7925,6 +10863,10 @@ + } + + TARGET(UNARY_INVERT) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = UNARY_INVERT; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(UNARY_INVERT); +@@ -7935,13 +10877,19 @@ + PyObject *res_o = PyNumber_Invert(PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(value); +- if (res_o == NULL) goto pop_1_error; ++ if (res_o == NULL) { ++ JUMP_TO_LABEL(pop_1_error); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-1] = res; + DISPATCH(); + } + + TARGET(UNARY_NEGATIVE) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = UNARY_NEGATIVE; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(UNARY_NEGATIVE); +@@ -7952,13 +10900,19 @@ + PyObject *res_o = PyNumber_Negative(PyStackRef_AsPyObjectBorrow(value)); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(value); +- if (res_o == NULL) goto pop_1_error; ++ if (res_o == NULL) { ++ JUMP_TO_LABEL(pop_1_error); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[-1] = res; + DISPATCH(); + } + + TARGET(UNARY_NOT) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = UNARY_NOT; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(UNARY_NOT); +@@ -7973,6 +10927,10 @@ + } + + TARGET(UNPACK_EX) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = UNPACK_EX; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(UNPACK_EX); +@@ -7985,17 +10943,23 @@ + int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg & 0xFF, oparg >> 8, top); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(seq); +- if (res == 0) goto pop_1_error; ++ if (res == 0) { ++ JUMP_TO_LABEL(pop_1_error); ++ } + stack_pointer += (oparg & 0xFF) + (oparg >> 8); + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(UNPACK_SEQUENCE) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = UNPACK_SEQUENCE; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(UNPACK_SEQUENCE); +- PREDICTED(UNPACK_SEQUENCE); ++ PREDICTED_UNPACK_SEQUENCE:; + _Py_CODEUNIT* const this_instr = next_instr - 2; + (void)this_instr; + _PyStackRef seq; +@@ -8027,7 +10991,9 @@ + int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg, -1, top); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(seq); +- if (res == 0) goto pop_1_error; ++ if (res == 0) { ++ JUMP_TO_LABEL(pop_1_error); ++ } + } + stack_pointer += -1 + oparg; + assert(WITHIN_STACK_BOUNDS()); +@@ -8035,6 +11001,12 @@ + } + + TARGET(UNPACK_SEQUENCE_LIST) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = UNPACK_SEQUENCE_LIST; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(UNPACK_SEQUENCE_LIST); +@@ -8045,11 +11017,23 @@ + seq = stack_pointer[-1]; + values = &stack_pointer[-1]; + PyObject *seq_o = PyStackRef_AsPyObjectBorrow(seq); +- DEOPT_IF(!PyList_CheckExact(seq_o), UNPACK_SEQUENCE); +- DEOPT_IF(!LOCK_OBJECT(seq_o), UNPACK_SEQUENCE); ++ if (!PyList_CheckExact(seq_o)) { ++ UPDATE_MISS_STATS(UNPACK_SEQUENCE); ++ assert(_PyOpcode_Deopt[opcode] == (UNPACK_SEQUENCE)); ++ JUMP_TO_PREDICTED(UNPACK_SEQUENCE); ++ } ++ if (!LOCK_OBJECT(seq_o)) { ++ UPDATE_MISS_STATS(UNPACK_SEQUENCE); ++ assert(_PyOpcode_Deopt[opcode] == (UNPACK_SEQUENCE)); ++ JUMP_TO_PREDICTED(UNPACK_SEQUENCE); ++ } + if (PyList_GET_SIZE(seq_o) != oparg) { + UNLOCK_OBJECT(seq_o); +- DEOPT_IF(true, UNPACK_SEQUENCE); ++ if (true) { ++ UPDATE_MISS_STATS(UNPACK_SEQUENCE); ++ assert(_PyOpcode_Deopt[opcode] == (UNPACK_SEQUENCE)); ++ JUMP_TO_PREDICTED(UNPACK_SEQUENCE); ++ } + } + STAT_INC(UNPACK_SEQUENCE, hit); + PyObject **items = _PyList_ITEMS(seq_o); +@@ -8064,6 +11048,12 @@ + } + + TARGET(UNPACK_SEQUENCE_TUPLE) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = UNPACK_SEQUENCE_TUPLE; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(UNPACK_SEQUENCE_TUPLE); +@@ -8074,8 +11064,16 @@ + seq = stack_pointer[-1]; + values = &stack_pointer[-1]; + PyObject *seq_o = PyStackRef_AsPyObjectBorrow(seq); +- DEOPT_IF(!PyTuple_CheckExact(seq_o), UNPACK_SEQUENCE); +- DEOPT_IF(PyTuple_GET_SIZE(seq_o) != oparg, UNPACK_SEQUENCE); ++ if (!PyTuple_CheckExact(seq_o)) { ++ UPDATE_MISS_STATS(UNPACK_SEQUENCE); ++ assert(_PyOpcode_Deopt[opcode] == (UNPACK_SEQUENCE)); ++ JUMP_TO_PREDICTED(UNPACK_SEQUENCE); ++ } ++ if (PyTuple_GET_SIZE(seq_o) != oparg) { ++ UPDATE_MISS_STATS(UNPACK_SEQUENCE); ++ assert(_PyOpcode_Deopt[opcode] == (UNPACK_SEQUENCE)); ++ JUMP_TO_PREDICTED(UNPACK_SEQUENCE); ++ } + STAT_INC(UNPACK_SEQUENCE, hit); + PyObject **items = _PyTuple_ITEMS(seq_o); + for (int i = oparg; --i >= 0; ) { +@@ -8088,6 +11086,12 @@ + } + + TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = UNPACK_SEQUENCE_TWO_TUPLE; ++ (void)(opcode); ++ #endif ++ _Py_CODEUNIT* const this_instr = next_instr; ++ (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(UNPACK_SEQUENCE_TWO_TUPLE); +@@ -8099,8 +11103,16 @@ + seq = stack_pointer[-1]; + assert(oparg == 2); + PyObject *seq_o = PyStackRef_AsPyObjectBorrow(seq); +- DEOPT_IF(!PyTuple_CheckExact(seq_o), UNPACK_SEQUENCE); +- DEOPT_IF(PyTuple_GET_SIZE(seq_o) != 2, UNPACK_SEQUENCE); ++ if (!PyTuple_CheckExact(seq_o)) { ++ UPDATE_MISS_STATS(UNPACK_SEQUENCE); ++ assert(_PyOpcode_Deopt[opcode] == (UNPACK_SEQUENCE)); ++ JUMP_TO_PREDICTED(UNPACK_SEQUENCE); ++ } ++ if (PyTuple_GET_SIZE(seq_o) != 2) { ++ UPDATE_MISS_STATS(UNPACK_SEQUENCE); ++ assert(_PyOpcode_Deopt[opcode] == (UNPACK_SEQUENCE)); ++ JUMP_TO_PREDICTED(UNPACK_SEQUENCE); ++ } + STAT_INC(UNPACK_SEQUENCE, hit); + val0 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 0)); + val1 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 1)); +@@ -8113,6 +11125,10 @@ + } + + TARGET(WITH_EXCEPT_START) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = WITH_EXCEPT_START; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(WITH_EXCEPT_START); +@@ -8144,7 +11160,9 @@ + tb = Py_None; + } + else { ++ _PyFrame_SetStackPointer(frame, stack_pointer); + Py_DECREF(tb); ++ stack_pointer = _PyFrame_GetStackPointer(frame); + } + assert(PyStackRef_LongCheck(lasti)); + (void)lasti; // Shut up compiler warning if asserts are off +@@ -8154,7 +11172,9 @@ + PyObject *res_o = PyObject_Vectorcall(exit_func_o, stack + 2 - has_self, + (3 + has_self) | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); +- if (res_o == NULL) goto error; ++ if (res_o == NULL) { ++ JUMP_TO_LABEL(error); ++ } + res = PyStackRef_FromPyObjectSteal(res_o); + stack_pointer[0] = res; + stack_pointer += 1; +@@ -8163,6 +11183,10 @@ + } + + TARGET(YIELD_VALUE) { ++ #if defined(Py_TAIL_CALL_INTERP) ++ int opcode = YIELD_VALUE; ++ (void)(opcode); ++ #endif + frame->instr_ptr = next_instr; + next_instr += 1; + INSTRUCTION_STATS(YIELD_VALUE); +@@ -8172,9 +11196,7 @@ + // NOTE: It's important that YIELD_VALUE never raises an exception! + // The compiler treats any exception raised here as a failed close() + // or throw() call. +- #if TIER_ONE +- assert(frame != &entry_frame); +- #endif ++ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); + frame->instr_ptr++; + PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); + assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); +@@ -8209,4 +11231,191 @@ + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } ++ ++ /* END INSTRUCTIONS */ ++#ifndef Py_TAIL_CALL_INTERP ++#if USE_COMPUTED_GOTOS ++ _unknown_opcode: ++#else ++ EXTRA_CASES // From pycore_opcode_metadata.h, a 'case' for each unused opcode ++#endif ++ /* Tell C compilers not to hold the opcode variable in the loop. ++ next_instr points the current instruction without TARGET(). */ ++ opcode = next_instr->op.code; ++ _PyErr_Format(tstate, PyExc_SystemError, ++ "%U:%d: unknown opcode %d", ++ _PyFrame_GetCode(frame)->co_filename, ++ PyUnstable_InterpreterFrame_GetLine(frame), ++ opcode); ++JUMP_TO_LABEL(error); ++ ++ ++ } ++ ++ /* This should never be reached. Every opcode should end with DISPATCH() ++ or goto error. */ ++ Py_UNREACHABLE(); ++#endif /* Py_TAIL_CALL_INTERP */ ++ /* BEGIN LABELS */ ++ ++ LABEL(pop_4_error) ++ { ++ STACK_SHRINK(4); ++ JUMP_TO_LABEL(error); ++ } ++ ++ LABEL(pop_3_error) ++ { ++ STACK_SHRINK(3); ++ JUMP_TO_LABEL(error); ++ } ++ ++ LABEL(pop_2_error) ++ { ++ STACK_SHRINK(2); ++ JUMP_TO_LABEL(error); ++ } ++ ++ LABEL(pop_1_error) ++ { ++ STACK_SHRINK(1); ++ JUMP_TO_LABEL(error); ++ } ++ ++ LABEL(error) ++ { ++ /* Double-check exception status. */ ++ #ifdef NDEBUG ++ if (!_PyErr_Occurred(tstate)) { ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ _PyErr_SetString(tstate, PyExc_SystemError, ++ "error return without exception set"); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ } ++ #else ++ assert(_PyErr_Occurred(tstate)); ++ #endif ++ ++ /* Log traceback info. */ ++ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); ++ if (!_PyFrame_IsIncomplete(frame)) { ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyFrameObject *f = _PyFrame_GetFrameObject(frame); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ if (f != NULL) { ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ PyTraceBack_Here(f); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ } ++ } ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ _PyEval_MonitorRaise(tstate, frame, next_instr-1); ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ _PyFrame_SetStackPointer(frame, stack_pointer); ++ JUMP_TO_LABEL(exception_unwind); ++ } ++ ++ LABEL(exception_unwind) ++ { ++ /* STACK SPILLED */ ++ /* We can't use frame->instr_ptr here, as RERAISE may have set it */ ++ int offset = INSTR_OFFSET()-1; ++ int level, handler, lasti; ++ int handled = get_exception_handler(_PyFrame_GetCode(frame), offset, &level, &handler, &lasti); ++ if (handled == 0) { ++ // No handlers, so exit. ++ assert(_PyErr_Occurred(tstate)); ++ /* Pop remaining stack entries. */ ++ _PyStackRef *stackbase = _PyFrame_Stackbase(frame); ++ while (frame->stackpointer > stackbase) { ++ _PyStackRef ref = _PyFrame_StackPop(frame); ++ PyStackRef_XCLOSE(ref); ++ } ++ monitor_unwind(tstate, frame, next_instr-1); ++ JUMP_TO_LABEL(exit_unwind); ++ } ++ assert(STACK_LEVEL() >= level); ++ _PyStackRef *new_top = _PyFrame_Stackbase(frame) + level; ++ assert(frame->stackpointer >= new_top); ++ while (frame->stackpointer > new_top) { ++ _PyStackRef ref = _PyFrame_StackPop(frame); ++ PyStackRef_XCLOSE(ref); ++ } ++ if (lasti) { ++ int frame_lasti = _PyInterpreterFrame_LASTI(frame); ++ PyObject *lasti = PyLong_FromLong(frame_lasti); ++ if (lasti == NULL) { ++ JUMP_TO_LABEL(exception_unwind); ++ } ++ _PyFrame_StackPush(frame, PyStackRef_FromPyObjectSteal(lasti)); ++ } ++ /* Make the raw exception data ++ available to the handler, ++ so a program can emulate the ++ Python main loop. */ ++ PyObject *exc = _PyErr_GetRaisedException(tstate); ++ _PyFrame_StackPush(frame, PyStackRef_FromPyObjectSteal(exc)); ++ next_instr = _PyFrame_GetBytecode(frame) + handler; ++ int err = monitor_handled(tstate, frame, next_instr, exc); ++ if (err < 0) { ++ JUMP_TO_LABEL(exception_unwind); ++ } ++ /* Resume normal execution */ ++ #ifdef Py_DEBUG ++ if (frame->lltrace >= 5) { ++ lltrace_resume_frame(frame); ++ } ++ #endif ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ #ifdef Py_TAIL_CALL_INTERP ++ int opcode; ++ #endif ++ DISPATCH(); ++ } ++ ++ LABEL(exit_unwind) ++ { ++ /* STACK SPILLED */ ++ assert(_PyErr_Occurred(tstate)); ++ _Py_LeaveRecursiveCallPy(tstate); ++ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); ++ // GH-99729: We need to unlink the frame *before* clearing it: ++ _PyInterpreterFrame *dying = frame; ++ frame = tstate->current_frame = dying->previous; ++ _PyEval_FrameClearAndPop(tstate, dying); ++ frame->return_offset = 0; ++ if (frame->owner == FRAME_OWNED_BY_INTERPRETER) { ++ /* Restore previous frame and exit */ ++ tstate->current_frame = frame->previous; ++ tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS; ++ return NULL; ++ } ++ next_instr = frame->instr_ptr; ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ JUMP_TO_LABEL(error); ++ } ++ ++ LABEL(start_frame) ++ { ++ /* STACK SPILLED */ ++ int too_deep = _Py_EnterRecursivePy(tstate); ++ if (too_deep) { ++ JUMP_TO_LABEL(exit_unwind); ++ } ++ next_instr = frame->instr_ptr; ++ LLTRACE_RESUME_FRAME(); ++ #ifdef Py_DEBUG ++ /* _PyEval_EvalFrameDefault() must not be called with an exception set, ++ because it can clear it (directly or indirectly) and so the ++ caller loses its exception */ ++ assert(!_PyErr_Occurred(tstate)); ++ #endif ++ stack_pointer = _PyFrame_GetStackPointer(frame); ++ #ifdef Py_TAIL_CALL_INTERP ++ int opcode; ++ #endif ++ DISPATCH(); ++ } ++ ++/* END LABELS */ + #undef TIER_ONE +diff --git a/Python/getopt.c b/Python/getopt.c +index f64c89fa227..39a6938dec7 100644 +--- a/Python/getopt.c ++++ b/Python/getopt.c +@@ -102,7 +102,7 @@ + // Parse long option. + if (*opt_ptr == L'\0') { + if (_PyOS_opterr) { +- fprintf(stderr, "expected long option\n"); ++ fprintf(stderr, "Expected long option\n"); + } + return -1; + } +@@ -114,7 +114,7 @@ + } + if (!opt->name) { + if (_PyOS_opterr) { +- fprintf(stderr, "unknown option %ls\n", argv[_PyOS_optind - 1]); ++ fprintf(stderr, "Unknown option: %ls\n", argv[_PyOS_optind - 1]); + } + return '_'; + } +diff --git a/Python/hamt.c b/Python/hamt.c +index cfd211f4541..ed43a0449d7 100644 +--- a/Python/hamt.c ++++ b/Python/hamt.c +@@ -319,6 +319,8 @@ + Py_ssize_t a_count; + } PyHamtNode_Array; + ++#define _PyHamtNode_Array_CAST(op) ((PyHamtNode_Array *)(op)) ++ + + typedef struct { + PyObject_VAR_HEAD +@@ -326,6 +328,8 @@ + PyObject *c_array[1]; + } PyHamtNode_Collision; + ++#define _PyHamtNode_Collision_CAST(op) ((PyHamtNode_Collision *)(op)) ++ + + static PyHamtObject * + hamt_alloc(void); +@@ -479,6 +483,8 @@ + #endif /* Py_DEBUG */ + /////////////////////////////////// Bitmap Node + ++#define _PyHamtNode_Bitmap_CAST(op) ((PyHamtNode_Bitmap *)(op)) ++ + + static PyHamtNode * + hamt_node_bitmap_new(Py_ssize_t size) +@@ -1083,30 +1089,27 @@ + } + + static int +-hamt_node_bitmap_traverse(PyHamtNode_Bitmap *self, visitproc visit, void *arg) ++hamt_node_bitmap_traverse(PyObject *op, visitproc visit, void *arg) + { + /* Bitmap's tp_traverse */ +- +- Py_ssize_t i; +- +- for (i = Py_SIZE(self); --i >= 0; ) { ++ PyHamtNode_Bitmap *self = _PyHamtNode_Bitmap_CAST(op); ++ for (Py_ssize_t i = Py_SIZE(self); --i >= 0;) { + Py_VISIT(self->b_array[i]); + } +- + return 0; + } + + static void +-hamt_node_bitmap_dealloc(PyHamtNode_Bitmap *self) ++hamt_node_bitmap_dealloc(PyObject *self) + { + /* Bitmap's tp_dealloc */ + +- Py_ssize_t len = Py_SIZE(self); +- Py_ssize_t i; ++ PyHamtNode_Bitmap *node = _PyHamtNode_Bitmap_CAST(self); ++ Py_ssize_t i, len = Py_SIZE(self); + +- if (Py_SIZE(self) == 0) { ++ if (len == 0) { + /* The empty node is statically allocated. */ +- assert(self == &_Py_SINGLETON(hamt_bitmap_node_empty)); ++ assert(node == &_Py_SINGLETON(hamt_bitmap_node_empty)); + #ifdef Py_DEBUG + _Py_FatalRefcountError("deallocating the empty hamt node bitmap singleton"); + #else +@@ -1120,11 +1123,11 @@ + if (len > 0) { + i = len; + while (--i >= 0) { +- Py_XDECREF(self->b_array[i]); ++ Py_XDECREF(node->b_array[i]); + } + } + +- Py_TYPE(self)->tp_free((PyObject *)self); ++ Py_TYPE(self)->tp_free(self); + Py_TRASHCAN_END + } + +@@ -1489,38 +1492,30 @@ + + + static int +-hamt_node_collision_traverse(PyHamtNode_Collision *self, +- visitproc visit, void *arg) ++hamt_node_collision_traverse(PyObject *op, visitproc visit, void *arg) + { + /* Collision's tp_traverse */ +- +- Py_ssize_t i; +- +- for (i = Py_SIZE(self); --i >= 0; ) { ++ PyHamtNode_Collision *self = _PyHamtNode_Collision_CAST(op); ++ for (Py_ssize_t i = Py_SIZE(self); --i >= 0; ) { + Py_VISIT(self->c_array[i]); + } +- + return 0; + } + + static void +-hamt_node_collision_dealloc(PyHamtNode_Collision *self) ++hamt_node_collision_dealloc(PyObject *self) + { + /* Collision's tp_dealloc */ +- + Py_ssize_t len = Py_SIZE(self); +- + PyObject_GC_UnTrack(self); + Py_TRASHCAN_BEGIN(self, hamt_node_collision_dealloc) +- + if (len > 0) { +- ++ PyHamtNode_Collision *node = _PyHamtNode_Collision_CAST(self); + while (--len >= 0) { +- Py_XDECREF(self->c_array[len]); ++ Py_XDECREF(node->c_array[len]); + } + } +- +- Py_TYPE(self)->tp_free((PyObject *)self); ++ Py_TYPE(self)->tp_free(self); + Py_TRASHCAN_END + } + +@@ -1868,35 +1863,27 @@ + } + + static int +-hamt_node_array_traverse(PyHamtNode_Array *self, +- visitproc visit, void *arg) ++hamt_node_array_traverse(PyObject *op, visitproc visit, void *arg) + { + /* Array's tp_traverse */ +- +- Py_ssize_t i; +- +- for (i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) { ++ PyHamtNode_Array *self = _PyHamtNode_Array_CAST(op); ++ for (Py_ssize_t i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) { + Py_VISIT(self->a_array[i]); + } +- + return 0; + } + + static void +-hamt_node_array_dealloc(PyHamtNode_Array *self) ++hamt_node_array_dealloc(PyObject *self) + { + /* Array's tp_dealloc */ +- +- Py_ssize_t i; +- + PyObject_GC_UnTrack(self); + Py_TRASHCAN_BEGIN(self, hamt_node_array_dealloc) +- +- for (i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) { +- Py_XDECREF(self->a_array[i]); ++ PyHamtNode_Array *obj = _PyHamtNode_Array_CAST(self); ++ for (Py_ssize_t i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) { ++ Py_XDECREF(obj->a_array[i]); + } +- +- Py_TYPE(self)->tp_free((PyObject *)self); ++ Py_TYPE(self)->tp_free(self); + Py_TRASHCAN_END + } + +@@ -2605,6 +2592,8 @@ + hamt_dump(PyHamtObject *self); + #endif + ++#define _PyHamtObject_CAST(op) ((PyHamtObject *)(op)) ++ + + static PyObject * + hamt_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +@@ -2613,24 +2602,27 @@ + } + + static int +-hamt_tp_clear(PyHamtObject *self) ++hamt_tp_clear(PyObject *op) + { ++ PyHamtObject *self = _PyHamtObject_CAST(op); + Py_CLEAR(self->h_root); + return 0; + } + + + static int +-hamt_tp_traverse(PyHamtObject *self, visitproc visit, void *arg) ++hamt_tp_traverse(PyObject *op, visitproc visit, void *arg) + { ++ PyHamtObject *self = _PyHamtObject_CAST(op); + Py_VISIT(self->h_root); + return 0; + } + + static void +-hamt_tp_dealloc(PyHamtObject *self) ++hamt_tp_dealloc(PyObject *self) + { +- if (self == _empty_hamt) { ++ PyHamtObject *obj = _PyHamtObject_CAST(self); ++ if (obj == _empty_hamt) { + /* The empty one is statically allocated. */ + #ifdef Py_DEBUG + _Py_FatalRefcountError("deallocating the empty hamt singleton"); +@@ -2640,8 +2632,8 @@ + } + + PyObject_GC_UnTrack(self); +- if (self->h_weakreflist != NULL) { +- PyObject_ClearWeakRefs((PyObject*)self); ++ if (obj->h_weakreflist != NULL) { ++ PyObject_ClearWeakRefs(self); + } + (void)hamt_tp_clear(self); + Py_TYPE(self)->tp_free(self); +@@ -2673,16 +2665,18 @@ + } + + static int +-hamt_tp_contains(PyHamtObject *self, PyObject *key) ++hamt_tp_contains(PyObject *op, PyObject *key) + { + PyObject *val; ++ PyHamtObject *self = _PyHamtObject_CAST(op); + return _PyHamt_Find(self, key, &val); + } + + static PyObject * +-hamt_tp_subscript(PyHamtObject *self, PyObject *key) ++hamt_tp_subscript(PyObject *op, PyObject *key) + { + PyObject *val; ++ PyHamtObject *self = _PyHamtObject_CAST(op); + hamt_find_t res = hamt_find(self, key, &val); + switch (res) { + case F_ERROR: +@@ -2698,19 +2692,21 @@ + } + + static Py_ssize_t +-hamt_tp_len(PyHamtObject *self) ++hamt_tp_len(PyObject *op) + { ++ PyHamtObject *self = _PyHamtObject_CAST(op); + return _PyHamt_Len(self); + } + + static PyObject * +-hamt_tp_iter(PyHamtObject *self) ++hamt_tp_iter(PyObject *op) + { ++ PyHamtObject *self = _PyHamtObject_CAST(op); + return _PyHamt_NewIterKeys(self); + } + + static PyObject * +-hamt_py_set(PyHamtObject *self, PyObject *args) ++hamt_py_set(PyObject *op, PyObject *args) + { + PyObject *key; + PyObject *val; +@@ -2719,11 +2715,12 @@ + return NULL; + } + ++ PyHamtObject *self = _PyHamtObject_CAST(op); + return (PyObject *)_PyHamt_Assoc(self, key, val); + } + + static PyObject * +-hamt_py_get(PyHamtObject *self, PyObject *args) ++hamt_py_get(PyObject *op, PyObject *args) + { + PyObject *key; + PyObject *def = NULL; +@@ -2733,6 +2730,7 @@ + } + + PyObject *val = NULL; ++ PyHamtObject *self = _PyHamtObject_CAST(op); + hamt_find_t res = hamt_find(self, key, &val); + switch (res) { + case F_ERROR: +@@ -2750,67 +2748,63 @@ + } + + static PyObject * +-hamt_py_delete(PyHamtObject *self, PyObject *key) ++hamt_py_delete(PyObject *op, PyObject *key) + { ++ PyHamtObject *self = _PyHamtObject_CAST(op); + return (PyObject *)_PyHamt_Without(self, key); + } + + static PyObject * +-hamt_py_items(PyHamtObject *self, PyObject *args) ++hamt_py_items(PyObject *op, PyObject *args) + { ++ PyHamtObject *self = _PyHamtObject_CAST(op); + return _PyHamt_NewIterItems(self); + } + + static PyObject * +-hamt_py_values(PyHamtObject *self, PyObject *args) ++hamt_py_values(PyObject *op, PyObject *args) + { ++ PyHamtObject *self = _PyHamtObject_CAST(op); + return _PyHamt_NewIterValues(self); + } + + static PyObject * +-hamt_py_keys(PyHamtObject *self, PyObject *Py_UNUSED(args)) ++hamt_py_keys(PyObject *op, PyObject *Py_UNUSED(args)) + { ++ PyHamtObject *self = _PyHamtObject_CAST(op); + return _PyHamt_NewIterKeys(self); + } + + #ifdef Py_DEBUG + static PyObject * +-hamt_py_dump(PyHamtObject *self, PyObject *Py_UNUSED(args)) ++hamt_py_dump(PyObject *op, PyObject *Py_UNUSED(args)) + { ++ PyHamtObject *self = _PyHamtObject_CAST(op); + return hamt_dump(self); + } + #endif + + + static PyMethodDef PyHamt_methods[] = { +- {"set", _PyCFunction_CAST(hamt_py_set), METH_VARARGS, NULL}, +- {"get", _PyCFunction_CAST(hamt_py_get), METH_VARARGS, NULL}, +- {"delete", _PyCFunction_CAST(hamt_py_delete), METH_O, NULL}, +- {"items", _PyCFunction_CAST(hamt_py_items), METH_NOARGS, NULL}, +- {"keys", _PyCFunction_CAST(hamt_py_keys), METH_NOARGS, NULL}, +- {"values", _PyCFunction_CAST(hamt_py_values), METH_NOARGS, NULL}, ++ {"set", hamt_py_set, METH_VARARGS, NULL}, ++ {"get", hamt_py_get, METH_VARARGS, NULL}, ++ {"delete", hamt_py_delete, METH_O, NULL}, ++ {"items", hamt_py_items, METH_NOARGS, NULL}, ++ {"keys", hamt_py_keys, METH_NOARGS, NULL}, ++ {"values", hamt_py_values, METH_NOARGS, NULL}, + #ifdef Py_DEBUG +- {"__dump__", _PyCFunction_CAST(hamt_py_dump), METH_NOARGS, NULL}, ++ {"__dump__", hamt_py_dump, METH_NOARGS, NULL}, + #endif + {NULL, NULL} + }; + + static PySequenceMethods PyHamt_as_sequence = { +- 0, /* sq_length */ +- 0, /* sq_concat */ +- 0, /* sq_repeat */ +- 0, /* sq_item */ +- 0, /* sq_slice */ +- 0, /* sq_ass_item */ +- 0, /* sq_ass_slice */ +- (objobjproc)hamt_tp_contains, /* sq_contains */ +- 0, /* sq_inplace_concat */ +- 0, /* sq_inplace_repeat */ ++ .sq_contains = hamt_tp_contains, + }; + + static PyMappingMethods PyHamt_as_mapping = { +- (lenfunc)hamt_tp_len, /* mp_length */ +- (binaryfunc)hamt_tp_subscript, /* mp_subscript */ ++ .mp_length = hamt_tp_len, ++ .mp_subscript = hamt_tp_subscript, + }; + + PyTypeObject _PyHamt_Type = { +@@ -2820,13 +2814,13 @@ + .tp_methods = PyHamt_methods, + .tp_as_mapping = &PyHamt_as_mapping, + .tp_as_sequence = &PyHamt_as_sequence, +- .tp_iter = (getiterfunc)hamt_tp_iter, +- .tp_dealloc = (destructor)hamt_tp_dealloc, ++ .tp_iter = hamt_tp_iter, ++ .tp_dealloc = hamt_tp_dealloc, + .tp_getattro = PyObject_GenericGetAttr, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + .tp_richcompare = hamt_tp_richcompare, +- .tp_traverse = (traverseproc)hamt_tp_traverse, +- .tp_clear = (inquiry)hamt_tp_clear, ++ .tp_traverse = hamt_tp_traverse, ++ .tp_clear = hamt_tp_clear, + .tp_new = hamt_tp_new, + .tp_weaklistoffset = offsetof(PyHamtObject, h_weakreflist), + .tp_hash = PyObject_HashNotImplemented, +@@ -2841,10 +2835,10 @@ + "hamt_array_node", + sizeof(PyHamtNode_Array), + 0, +- .tp_dealloc = (destructor)hamt_node_array_dealloc, ++ .tp_dealloc = hamt_node_array_dealloc, + .tp_getattro = PyObject_GenericGetAttr, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, +- .tp_traverse = (traverseproc)hamt_node_array_traverse, ++ .tp_traverse = hamt_node_array_traverse, + .tp_free = PyObject_GC_Del, + .tp_hash = PyObject_HashNotImplemented, + }; +@@ -2854,10 +2848,10 @@ + "hamt_bitmap_node", + sizeof(PyHamtNode_Bitmap) - sizeof(PyObject *), + sizeof(PyObject *), +- .tp_dealloc = (destructor)hamt_node_bitmap_dealloc, ++ .tp_dealloc = hamt_node_bitmap_dealloc, + .tp_getattro = PyObject_GenericGetAttr, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, +- .tp_traverse = (traverseproc)hamt_node_bitmap_traverse, ++ .tp_traverse = hamt_node_bitmap_traverse, + .tp_free = PyObject_GC_Del, + .tp_hash = PyObject_HashNotImplemented, + }; +@@ -2867,10 +2861,10 @@ + "hamt_collision_node", + sizeof(PyHamtNode_Collision) - sizeof(PyObject *), + sizeof(PyObject *), +- .tp_dealloc = (destructor)hamt_node_collision_dealloc, ++ .tp_dealloc = hamt_node_collision_dealloc, + .tp_getattro = PyObject_GenericGetAttr, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, +- .tp_traverse = (traverseproc)hamt_node_collision_traverse, ++ .tp_traverse = hamt_node_collision_traverse, + .tp_free = PyObject_GC_Del, + .tp_hash = PyObject_HashNotImplemented, + }; +diff --git a/Python/import.c b/Python/import.c +index a9282dde633..8cc8d3a503b 100644 +--- a/Python/import.c ++++ b/Python/import.c +@@ -594,7 +594,8 @@ + if (PyList_SetSlice(MODULES_BY_INDEX(interp), + 0, PyList_GET_SIZE(MODULES_BY_INDEX(interp)), + NULL)) { +- PyErr_FormatUnraisable("Exception ignored on clearing interpreters module list"); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "clearing interpreters module list"); + } + } + +@@ -4080,13 +4081,15 @@ + int verbose = _PyInterpreterState_GetConfig(interp)->verbose; + + if (_PySys_ClearAttrString(interp, "meta_path", verbose) < 0) { +- PyErr_FormatUnraisable("Exception ignored on clearing sys.meta_path"); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "clearing sys.meta_path"); + } + + // XXX Pull in most of finalize_modules() in pylifecycle.c. + + if (_PySys_ClearAttrString(interp, "modules", verbose) < 0) { +- PyErr_FormatUnraisable("Exception ignored on clearing sys.modules"); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "clearing sys.modules"); + } + + _PyImport_ClearCore(interp); +@@ -4111,7 +4114,7 @@ + PySys_WriteStderr("# installing zipimport hook\n"); + } + +- PyObject *zipimporter = _PyImport_GetModuleAttrString("zipimport", "zipimporter"); ++ PyObject *zipimporter = PyImport_ImportModuleAttrString("zipimport", "zipimporter"); + if (zipimporter == NULL) { + _PyErr_Clear(tstate); /* No zipimporter object -- okay */ + if (verbose) { +@@ -4161,10 +4164,12 @@ + // XXX Uninstall importlib metapath importers here? + + if (_PySys_ClearAttrString(interp, "path_importer_cache", verbose) < 0) { +- PyErr_FormatUnraisable("Exception ignored on clearing sys.path_importer_cache"); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "clearing sys.path_importer_cache"); + } + if (_PySys_ClearAttrString(interp, "path_hooks", verbose) < 0) { +- PyErr_FormatUnraisable("Exception ignored on clearing sys.path_hooks"); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "clearing sys.path_hooks"); + } + } + +@@ -4174,7 +4179,7 @@ + /******************/ + + PyObject * +-_PyImport_GetModuleAttr(PyObject *modname, PyObject *attrname) ++PyImport_ImportModuleAttr(PyObject *modname, PyObject *attrname) + { + PyObject *mod = PyImport_Import(modname); + if (mod == NULL) { +@@ -4186,7 +4191,7 @@ + } + + PyObject * +-_PyImport_GetModuleAttrString(const char *modname, const char *attrname) ++PyImport_ImportModuleAttrString(const char *modname, const char *attrname) + { + PyObject *pmodname = PyUnicode_FromString(modname); + if (pmodname == NULL) { +@@ -4197,7 +4202,7 @@ + Py_DECREF(pmodname); + return NULL; + } +- PyObject *result = _PyImport_GetModuleAttr(pmodname, pattrname); ++ PyObject *result = PyImport_ImportModuleAttr(pmodname, pattrname); + Py_DECREF(pattrname); + Py_DECREF(pmodname); + return result; +@@ -4688,7 +4693,7 @@ + * code relies on fp still being open. */ + FILE *fp; + if (file != NULL) { +- fp = _Py_fopen_obj(info.filename, "r"); ++ fp = Py_fopen(info.filename, "r"); + if (fp == NULL) { + goto finally; + } +diff --git a/Python/initconfig.c b/Python/initconfig.c +index 7851b86db1f..4db77ef47d2 100644 +--- a/Python/initconfig.c ++++ b/Python/initconfig.c +@@ -169,7 +169,7 @@ + SPEC(use_frozen_modules, BOOL, READ_ONLY, NO_SYS), + SPEC(use_hash_seed, BOOL, READ_ONLY, NO_SYS), + #ifdef __APPLE__ +- SPEC(use_system_logger, BOOL, PUBLIC, NO_SYS), ++ SPEC(use_system_logger, BOOL, READ_ONLY, NO_SYS), + #endif + SPEC(user_site_directory, BOOL, READ_ONLY, NO_SYS), // sys.flags.no_user_site + SPEC(warn_default_encoding, BOOL, READ_ONLY, NO_SYS), +diff --git a/Python/instrumentation.c b/Python/instrumentation.c +index 3503809e330..0e7b4810726 100644 +--- a/Python/instrumentation.c ++++ b/Python/instrumentation.c +@@ -14,6 +14,7 @@ + #include "pycore_namespace.h" + #include "pycore_object.h" + #include "pycore_opcode_metadata.h" // IS_VALID_OPCODE, _PyOpcode_Caches ++#include "pycore_opcode_utils.h" // IS_CONDITIONAL_JUMP_OPCODE + #include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_STORE_UINTPTR_RELEASE + #include "pycore_pyerrors.h" + #include "pycore_pystate.h" // _PyInterpreterState_GET() +@@ -52,7 +53,7 @@ + if (bc == NULL) { \ + continue; \ + } \ +- (func)((_Py_CODEUNIT *)bc, __VA_ARGS__); \ ++ (func)(code, (_Py_CODEUNIT *)bc, __VA_ARGS__); \ + } \ + } while (0) + +@@ -61,7 +62,7 @@ + #define LOCK_CODE(code) + #define UNLOCK_CODE() + #define MODIFY_BYTECODE(code, func, ...) \ +- (func)(_PyCode_CODE(code), __VA_ARGS__) ++ (func)(code, _PyCode_CODE(code), __VA_ARGS__) + + #endif + +@@ -85,22 +86,26 @@ + [INSTRUMENTED_YIELD_VALUE] = PY_MONITORING_EVENT_PY_YIELD, + [JUMP_FORWARD] = PY_MONITORING_EVENT_JUMP, + [JUMP_BACKWARD] = PY_MONITORING_EVENT_JUMP, +- [POP_JUMP_IF_FALSE] = PY_MONITORING_EVENT_BRANCH, +- [POP_JUMP_IF_TRUE] = PY_MONITORING_EVENT_BRANCH, +- [POP_JUMP_IF_NONE] = PY_MONITORING_EVENT_BRANCH, +- [POP_JUMP_IF_NOT_NONE] = PY_MONITORING_EVENT_BRANCH, ++ [POP_JUMP_IF_FALSE] = PY_MONITORING_EVENT_BRANCH_RIGHT, ++ [POP_JUMP_IF_TRUE] = PY_MONITORING_EVENT_BRANCH_RIGHT, ++ [POP_JUMP_IF_NONE] = PY_MONITORING_EVENT_BRANCH_RIGHT, ++ [POP_JUMP_IF_NOT_NONE] = PY_MONITORING_EVENT_BRANCH_RIGHT, + [INSTRUMENTED_JUMP_FORWARD] = PY_MONITORING_EVENT_JUMP, + [INSTRUMENTED_JUMP_BACKWARD] = PY_MONITORING_EVENT_JUMP, +- [INSTRUMENTED_POP_JUMP_IF_FALSE] = PY_MONITORING_EVENT_BRANCH, +- [INSTRUMENTED_POP_JUMP_IF_TRUE] = PY_MONITORING_EVENT_BRANCH, +- [INSTRUMENTED_POP_JUMP_IF_NONE] = PY_MONITORING_EVENT_BRANCH, +- [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = PY_MONITORING_EVENT_BRANCH, +- [FOR_ITER] = PY_MONITORING_EVENT_BRANCH, +- [INSTRUMENTED_FOR_ITER] = PY_MONITORING_EVENT_BRANCH, ++ [INSTRUMENTED_POP_JUMP_IF_FALSE] = PY_MONITORING_EVENT_BRANCH_RIGHT, ++ [INSTRUMENTED_POP_JUMP_IF_TRUE] = PY_MONITORING_EVENT_BRANCH_RIGHT, ++ [INSTRUMENTED_POP_JUMP_IF_NONE] = PY_MONITORING_EVENT_BRANCH_RIGHT, ++ [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = PY_MONITORING_EVENT_BRANCH_RIGHT, ++ [FOR_ITER] = PY_MONITORING_EVENT_BRANCH_LEFT, ++ [INSTRUMENTED_FOR_ITER] = PY_MONITORING_EVENT_BRANCH_LEFT, ++ [POP_ITER] = PY_MONITORING_EVENT_BRANCH_RIGHT, ++ [INSTRUMENTED_POP_ITER] = PY_MONITORING_EVENT_BRANCH_RIGHT, + [END_FOR] = PY_MONITORING_EVENT_STOP_ITERATION, + [INSTRUMENTED_END_FOR] = PY_MONITORING_EVENT_STOP_ITERATION, + [END_SEND] = PY_MONITORING_EVENT_STOP_ITERATION, + [INSTRUMENTED_END_SEND] = PY_MONITORING_EVENT_STOP_ITERATION, ++ [NOT_TAKEN] = PY_MONITORING_EVENT_BRANCH_LEFT, ++ [INSTRUMENTED_NOT_TAKEN] = PY_MONITORING_EVENT_BRANCH_LEFT, + }; + + static const uint8_t DE_INSTRUMENT[256] = { +@@ -117,9 +122,11 @@ + [INSTRUMENTED_POP_JUMP_IF_NONE] = POP_JUMP_IF_NONE, + [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = POP_JUMP_IF_NOT_NONE, + [INSTRUMENTED_FOR_ITER] = FOR_ITER, ++ [INSTRUMENTED_POP_ITER] = POP_ITER, + [INSTRUMENTED_END_FOR] = END_FOR, + [INSTRUMENTED_END_SEND] = END_SEND, + [INSTRUMENTED_LOAD_SUPER_ATTR] = LOAD_SUPER_ATTR, ++ [INSTRUMENTED_NOT_TAKEN] = NOT_TAKEN, + }; + + static const uint8_t INSTRUMENTED_OPCODES[256] = { +@@ -153,8 +160,12 @@ + [INSTRUMENTED_END_SEND] = INSTRUMENTED_END_SEND, + [FOR_ITER] = INSTRUMENTED_FOR_ITER, + [INSTRUMENTED_FOR_ITER] = INSTRUMENTED_FOR_ITER, ++ [POP_ITER] = INSTRUMENTED_POP_ITER, ++ [INSTRUMENTED_POP_ITER] = INSTRUMENTED_POP_ITER, + [LOAD_SUPER_ATTR] = INSTRUMENTED_LOAD_SUPER_ATTR, + [INSTRUMENTED_LOAD_SUPER_ATTR] = INSTRUMENTED_LOAD_SUPER_ATTR, ++ [NOT_TAKEN] = INSTRUMENTED_NOT_TAKEN, ++ [INSTRUMENTED_NOT_TAKEN] = INSTRUMENTED_NOT_TAKEN, + + [INSTRUMENTED_LINE] = INSTRUMENTED_LINE, + [INSTRUMENTED_INSTRUCTION] = INSTRUMENTED_INSTRUCTION, +@@ -274,48 +285,36 @@ + return result; + } + +-/* Line delta. +- * 8 bit value. +- * if line_delta == -128: +- * line = None # represented as -1 +- * elif line_delta == -127 or line_delta == -126: +- * line = PyCode_Addr2Line(code, offset * sizeof(_Py_CODEUNIT)); ++/* Module code can have line 0, even though modules start at line 1, ++ * so -1 is a legal delta. */ ++#define NO_LINE (-2) ++ ++/* Returns the line delta. Defined as: ++ * if line is None: ++ * line_delta = NO_LINE + * else: +- * line = first_line + (offset >> OFFSET_SHIFT) + line_delta; ++ * line_delta = line - first_line + */ +- +-#define NO_LINE -128 +-#define COMPUTED_LINE_LINENO_CHANGE -127 +-#define COMPUTED_LINE -126 +- +-#define OFFSET_SHIFT 4 +- +-static int8_t +-compute_line_delta(PyCodeObject *code, int offset, int line) ++static int ++compute_line_delta(PyCodeObject *code, int line) + { + if (line < 0) { ++ assert(line == -1); + return NO_LINE; + } +- int delta = line - code->co_firstlineno - (offset >> OFFSET_SHIFT); +- if (delta <= INT8_MAX && delta > COMPUTED_LINE) { +- return delta; +- } +- return COMPUTED_LINE; ++ int delta = line - code->co_firstlineno; ++ assert(delta > NO_LINE); ++ return delta; + } + + static int +-compute_line(PyCodeObject *code, int offset, int8_t line_delta) ++compute_line(PyCodeObject *code, int line_delta) + { +- if (line_delta > COMPUTED_LINE) { +- return code->co_firstlineno + (offset >> OFFSET_SHIFT) + line_delta; +- } + if (line_delta == NO_LINE) { +- + return -1; + } +- assert(line_delta == COMPUTED_LINE || line_delta == COMPUTED_LINE_LINENO_CHANGE); +- /* Look it up */ +- return PyCode_Addr2Line(code, offset * sizeof(_Py_CODEUNIT)); ++ assert(line_delta > NO_LINE); ++ return code->co_firstlineno + line_delta; + } + + int +@@ -323,33 +322,59 @@ + { + ASSERT_WORLD_STOPPED_OR_LOCKED(code); + +- int opcode = +- FT_ATOMIC_LOAD_UINT8_RELAXED(_PyCode_CODE(code)[offset].op.code); +- assert(opcode != 0); +- assert(opcode != RESERVED); +- if (opcode == INSTRUMENTED_LINE) { +- opcode = code->_co_monitoring->lines[offset].original_opcode; +- } +- if (opcode == INSTRUMENTED_INSTRUCTION) { +- opcode = code->_co_monitoring->per_instruction_opcodes[offset]; +- } +- int deinstrumented = DE_INSTRUMENT[opcode]; +- if (deinstrumented) { +- opcode = deinstrumented; +- } +- else { +- opcode = _PyOpcode_Deopt[opcode]; ++ _Py_CODEUNIT inst = _Py_GetBaseCodeUnit(code, offset); ++ return 1 + _PyOpcode_Caches[inst.op.code]; ++} ++ ++static inline uint8_t ++get_original_opcode(_PyCoLineInstrumentationData *line_data, int index) ++{ ++ return line_data->data[index*line_data->bytes_per_entry]; ++} ++ ++static inline uint8_t * ++get_original_opcode_ptr(_PyCoLineInstrumentationData *line_data, int index) ++{ ++ return &line_data->data[index*line_data->bytes_per_entry]; ++} ++ ++static inline void ++set_original_opcode(_PyCoLineInstrumentationData *line_data, int index, uint8_t opcode) ++{ ++ line_data->data[index*line_data->bytes_per_entry] = opcode; ++} ++ ++static inline int ++get_line_delta(_PyCoLineInstrumentationData *line_data, int index) ++{ ++ uint8_t *ptr = &line_data->data[index*line_data->bytes_per_entry+1]; ++ assert(line_data->bytes_per_entry >= 2); ++ uint32_t value = *ptr; ++ for (int idx = 2; idx < line_data->bytes_per_entry; idx++) { ++ ptr++; ++ int shift = (idx-1)*8; ++ value |= ((uint32_t)(*ptr)) << shift; + } +- assert(opcode != 0); +- if (opcode == ENTER_EXECUTOR) { +- int exec_index = _PyCode_CODE(code)[offset].op.arg; +- _PyExecutorObject *exec = code->co_executors->executors[exec_index]; +- opcode = _PyOpcode_Deopt[exec->vm_data.opcode]; ++ assert(value < INT_MAX); ++ /* NO_LINE is stored as zero. */ ++ return ((int)value) + NO_LINE; ++} ++ ++static inline void ++set_line_delta(_PyCoLineInstrumentationData *line_data, int index, int line_delta) ++{ ++ /* Store line_delta + 2 as we need -2 to represent no line number */ ++ assert(line_delta >= NO_LINE); ++ uint32_t adjusted = line_delta - NO_LINE; ++ uint8_t *ptr = &line_data->data[index*line_data->bytes_per_entry+1]; ++ assert(adjusted < (1ULL << ((line_data->bytes_per_entry-1)*8))); ++ assert(line_data->bytes_per_entry >= 2); ++ *ptr = adjusted & 0xff; ++ for (int idx = 2; idx < line_data->bytes_per_entry; idx++) { ++ ptr++; ++ adjusted >>= 8; ++ *ptr = adjusted & 0xff; + } +- assert(!is_instrumented(opcode)); +- assert(opcode != ENTER_EXECUTOR); +- assert(opcode == _PyOpcode_Deopt[opcode]); +- return 1 + _PyOpcode_Caches[opcode]; + } + + #ifdef INSTRUMENT_DEBUG +@@ -371,11 +396,15 @@ + if (lines == NULL) { + fprintf(out, ", lines = NULL"); + } +- else if (lines[i].original_opcode == 0) { +- fprintf(out, ", lines = {original_opcode = No LINE (0), line_delta = %d)", lines[i].line_delta); +- } + else { +- fprintf(out, ", lines = {original_opcode = %s, line_delta = %d)", _PyOpcode_OpName[lines[i].original_opcode], lines[i].line_delta); ++ int opcode = get_original_opcode(lines, i); ++ int line_delta = get_line_delta(lines, i); ++ if (opcode == 0) { ++ fprintf(out, ", lines = {original_opcode = No LINE (0), line_delta = %d)", line_delta); ++ } ++ else { ++ fprintf(out, ", lines = {original_opcode = %s, line_delta = %d)", _PyOpcode_OpName[opcode], line_delta); ++ } + } + } + +@@ -425,6 +454,12 @@ + } + } + ++/** NOTE: ++ * Do not use PyCode_Addr2Line to determine the line number in instrumentation, ++ * as `PyCode_Addr2Line` uses the monitoring data if it is available. ++ */ ++ ++ + /* No error checking -- Don't use this for anything but experimental debugging */ + static void + dump_instrumentation_data(PyCodeObject *code, int star, FILE*out) +@@ -442,6 +477,8 @@ + dump_local_monitors("Active", data->active_monitors, out); + int code_len = (int)Py_SIZE(code); + bool starred = false; ++ PyCodeAddressRange range; ++ _PyCode_InitAddressRange(code, &range); + for (int i = 0; i < code_len; i += _PyInstruction_GetLength(code, i)) { + _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; + int opcode = instr->op.code; +@@ -449,7 +486,7 @@ + fprintf(out, "** "); + starred = true; + } +- fprintf(out, "Offset: %d, line: %d %s: ", i, PyCode_Addr2Line(code, i*2), _PyOpcode_OpName[opcode]); ++ fprintf(out, "Offset: %d, line: %d %s: ", i, _PyCode_CheckLineNumber(i*2, &range), _PyOpcode_OpName[opcode]); + dump_instrumentation_data_tools(code, data->tools, i, out); + dump_instrumentation_data_lines(code, data->lines, i, out); + dump_instrumentation_data_line_tools(code, data->line_tools, i, out); +@@ -514,10 +551,12 @@ + code->_co_monitoring->active_monitors, + active_monitors)); + int code_len = (int)Py_SIZE(code); ++ PyCodeAddressRange range; ++ _PyCode_InitAddressRange(co, &range); + for (int i = 0; i < code_len;) { + _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; + int opcode = instr->op.code; +- int base_opcode = _Py_GetBaseCodeUnit(code, offset).op.code; ++ int base_opcode = _Py_GetBaseCodeUnit(code, i).op.code; + CHECK(valid_opcode(opcode)); + CHECK(valid_opcode(base_opcode)); + if (opcode == INSTRUMENTED_INSTRUCTION) { +@@ -528,8 +567,8 @@ + } + if (opcode == INSTRUMENTED_LINE) { + CHECK(data->lines); +- CHECK(valid_opcode(data->lines[i].original_opcode)); +- opcode = data->lines[i].original_opcode; ++ opcode = get_original_opcode(data->lines, i); ++ CHECK(valid_opcode(opcode)); + CHECK(opcode != END_FOR); + CHECK(opcode != RESUME); + CHECK(opcode != RESUME_CHECK); +@@ -544,7 +583,7 @@ + * *and* we are executing a INSTRUMENTED_LINE instruction + * that has de-instrumented itself, then we will execute + * an invalid INSTRUMENTED_INSTRUCTION */ +- CHECK(data->lines[i].original_opcode != INSTRUMENTED_INSTRUCTION); ++ CHECK(get_original_opcode(data->lines, i) != INSTRUMENTED_INSTRUCTION); + } + if (opcode == INSTRUMENTED_INSTRUCTION) { + CHECK(data->per_instruction_opcodes[i] != 0); +@@ -559,9 +598,9 @@ + } + CHECK(active_monitors.tools[event] != 0); + } +- if (data->lines && base_opcode != END_FOR) { +- int line1 = compute_line(code, i, data->lines[i].line_delta); +- int line2 = PyCode_Addr2Line(code, i*sizeof(_Py_CODEUNIT)); ++ if (data->lines && get_original_opcode(data->lines, i)) { ++ int line1 = compute_line(code, get_line_delta(data->lines, i)); ++ int line2 = _PyCode_CheckLineNumber(i*sizeof(_Py_CODEUNIT), &range); + CHECK(line1 == line2); + } + CHECK(valid_opcode(opcode)); +@@ -599,20 +638,19 @@ + int opcode = inst.op.code; + if (opcode < MIN_INSTRUMENTED_OPCODE) { + inst.op.code = _PyOpcode_Deopt[opcode]; +- assert(inst.op.code <= RESUME); ++ assert(inst.op.code < MIN_SPECIALIZED_OPCODE); + return inst; + } + if (opcode == ENTER_EXECUTOR) { + _PyExecutorObject *exec = code->co_executors->executors[inst.op.arg]; + opcode = _PyOpcode_Deopt[exec->vm_data.opcode]; + inst.op.code = opcode; +- assert(opcode <= RESUME); + inst.op.arg = exec->vm_data.oparg; +- assert(inst.op.code <= RESUME); ++ assert(inst.op.code < MIN_SPECIALIZED_OPCODE); + return inst; + } + if (opcode == INSTRUMENTED_LINE) { +- opcode = code->_co_monitoring->lines[i].original_opcode; ++ opcode = get_original_opcode(code->_co_monitoring->lines, i); + } + if (opcode == INSTRUMENTED_INSTRUCTION) { + opcode = code->_co_monitoring->per_instruction_opcodes[i]; +@@ -631,7 +669,7 @@ + } + + static void +-de_instrument(_Py_CODEUNIT *bytecode, _PyCoMonitoringData *monitoring, int i, ++de_instrument(PyCodeObject *code, _Py_CODEUNIT *bytecode, _PyCoMonitoringData *monitoring, int i, + int event) + { + assert(event != PY_MONITORING_EVENT_INSTRUCTION); +@@ -642,7 +680,7 @@ + int opcode = *opcode_ptr; + assert(opcode != ENTER_EXECUTOR); + if (opcode == INSTRUMENTED_LINE) { +- opcode_ptr = &monitoring->lines[i].original_opcode; ++ opcode_ptr = get_original_opcode_ptr(monitoring->lines, i); + opcode = *opcode_ptr; + } + if (opcode == INSTRUMENTED_INSTRUCTION) { +@@ -662,7 +700,7 @@ + } + + static void +-de_instrument_line(_Py_CODEUNIT *bytecode, _PyCoMonitoringData *monitoring, ++de_instrument_line(PyCodeObject *code, _Py_CODEUNIT *bytecode, _PyCoMonitoringData *monitoring, + int i) + { + _Py_CODEUNIT *instr = &bytecode[i]; +@@ -670,10 +708,10 @@ + if (opcode != INSTRUMENTED_LINE) { + return; + } +- _PyCoLineInstrumentationData *lines = &monitoring->lines[i]; +- int original_opcode = lines->original_opcode; ++ _PyCoLineInstrumentationData *lines = monitoring->lines; ++ int original_opcode = get_original_opcode(lines, i); + if (original_opcode == INSTRUMENTED_INSTRUCTION) { +- lines->original_opcode = monitoring->per_instruction_opcodes[i]; ++ set_original_opcode(lines, i, monitoring->per_instruction_opcodes[i]); + } + CHECK(original_opcode != 0); + CHECK(original_opcode == _PyOpcode_Deopt[original_opcode]); +@@ -686,14 +724,14 @@ + } + + static void +-de_instrument_per_instruction(_Py_CODEUNIT *bytecode, ++de_instrument_per_instruction(PyCodeObject *code, _Py_CODEUNIT *bytecode, + _PyCoMonitoringData *monitoring, int i) + { + _Py_CODEUNIT *instr = &bytecode[i]; + uint8_t *opcode_ptr = &instr->op.code; + int opcode = *opcode_ptr; + if (opcode == INSTRUMENTED_LINE) { +- opcode_ptr = &monitoring->lines[i].original_opcode; ++ opcode_ptr = get_original_opcode_ptr(monitoring->lines, i); + opcode = *opcode_ptr; + } + if (opcode != INSTRUMENTED_INSTRUCTION) { +@@ -712,14 +750,13 @@ + } + + static void +-instrument(_Py_CODEUNIT *bytecode, _PyCoMonitoringData *monitoring, int i) ++instrument(PyCodeObject *code, _Py_CODEUNIT *bytecode, _PyCoMonitoringData *monitoring, int i) + { + _Py_CODEUNIT *instr = &bytecode[i]; + uint8_t *opcode_ptr = &instr->op.code; + int opcode =*opcode_ptr; + if (opcode == INSTRUMENTED_LINE) { +- _PyCoLineInstrumentationData *lines = &monitoring->lines[i]; +- opcode_ptr = &lines->original_opcode; ++ opcode_ptr = get_original_opcode_ptr(monitoring->lines, i); + opcode = *opcode_ptr; + } + if (opcode == INSTRUMENTED_INSTRUCTION) { +@@ -742,29 +779,27 @@ + } + + static void +-instrument_line(_Py_CODEUNIT *bytecode, _PyCoMonitoringData *monitoring, int i) ++instrument_line(PyCodeObject *code, _Py_CODEUNIT *bytecode, _PyCoMonitoringData *monitoring, int i) + { + uint8_t *opcode_ptr = &bytecode[i].op.code; + int opcode = *opcode_ptr; + if (opcode == INSTRUMENTED_LINE) { + return; + } +- _PyCoLineInstrumentationData *lines = &monitoring->lines[i]; +- lines->original_opcode = _PyOpcode_Deopt[opcode]; +- CHECK(lines->original_opcode > 0); ++ set_original_opcode(monitoring->lines, i, _PyOpcode_Deopt[opcode]); ++ CHECK(get_line_delta(monitoring->lines, i) > NO_LINE); + FT_ATOMIC_STORE_UINT8_RELAXED(*opcode_ptr, INSTRUMENTED_LINE); + } + + static void +-instrument_per_instruction(_Py_CODEUNIT *bytecode, ++instrument_per_instruction(PyCodeObject *code, _Py_CODEUNIT *bytecode, + _PyCoMonitoringData *monitoring, int i) + { + _Py_CODEUNIT *instr = &bytecode[i]; + uint8_t *opcode_ptr = &instr->op.code; + int opcode = *opcode_ptr; + if (opcode == INSTRUMENTED_LINE) { +- _PyCoLineInstrumentationData *lines = &monitoring->lines[i]; +- opcode_ptr = &lines->original_opcode; ++ opcode_ptr = get_original_opcode_ptr(monitoring->lines, i); + opcode = *opcode_ptr; + } + if (opcode == INSTRUMENTED_INSTRUCTION) { +@@ -1084,6 +1119,8 @@ + [PY_MONITORING_EVENT_INSTRUCTION] = "INSTRUCTION", + [PY_MONITORING_EVENT_JUMP] = "JUMP", + [PY_MONITORING_EVENT_BRANCH] = "BRANCH", ++ [PY_MONITORING_EVENT_BRANCH_LEFT] = "BRANCH_LEFT", ++ [PY_MONITORING_EVENT_BRANCH_RIGHT] = "BRANCH_RIGHT", + [PY_MONITORING_EVENT_C_RETURN] = "C_RETURN", + [PY_MONITORING_EVENT_PY_THROW] = "PY_THROW", + [PY_MONITORING_EVENT_RAISE] = "RAISE", +@@ -1096,8 +1133,8 @@ + + static int + call_instrumentation_vector( +- PyThreadState *tstate, int event, +- _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, Py_ssize_t nargs, PyObject *args[]) ++ _Py_CODEUNIT *instr, PyThreadState *tstate, int event, ++ _PyInterpreterFrame *frame, _Py_CODEUNIT *arg2, Py_ssize_t nargs, PyObject *args[]) + { + if (tstate->tracing) { + return 0; +@@ -1110,13 +1147,13 @@ + int offset = (int)(instr - _PyFrame_GetBytecode(frame)); + /* Offset visible to user should be the offset in bytes, as that is the + * convention for APIs involving code offsets. */ +- int bytes_offset = offset * (int)sizeof(_Py_CODEUNIT); +- PyObject *offset_obj = PyLong_FromLong(bytes_offset); +- if (offset_obj == NULL) { ++ int bytes_arg2 = (int)(arg2 - _PyFrame_GetBytecode(frame)) * (int)sizeof(_Py_CODEUNIT); ++ PyObject *arg2_obj = PyLong_FromLong(bytes_arg2); ++ if (arg2_obj == NULL) { + return -1; + } + assert(args[2] == NULL); +- args[2] = offset_obj; ++ args[2] = arg2_obj; + PyInterpreterState *interp = tstate->interp; + uint8_t tools = get_tools_for_instruction(code, interp, offset, event); + size_t nargsf = (size_t) nargs | PY_VECTORCALL_ARGUMENTS_OFFSET; +@@ -1154,7 +1191,7 @@ + } + } + } +- Py_DECREF(offset_obj); ++ Py_DECREF(arg2_obj); + return err; + } + +@@ -1164,7 +1201,7 @@ + _PyInterpreterFrame *frame, _Py_CODEUNIT *instr) + { + PyObject *args[3] = { NULL, NULL, NULL }; +- return call_instrumentation_vector(tstate, event, frame, instr, 2, args); ++ return call_instrumentation_vector(instr, tstate, event, frame, instr, 2, args); + } + + int +@@ -1173,7 +1210,7 @@ + _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg) + { + PyObject *args[4] = { NULL, NULL, NULL, arg }; +- return call_instrumentation_vector(tstate, event, frame, instr, 3, args); ++ return call_instrumentation_vector(instr, tstate, event, frame, instr, 3, args); + } + + int +@@ -1182,33 +1219,34 @@ + _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1) + { + PyObject *args[5] = { NULL, NULL, NULL, arg0, arg1 }; +- return call_instrumentation_vector(tstate, event, frame, instr, 4, args); ++ return call_instrumentation_vector(instr, tstate, event, frame, instr, 4, args); + } + + _Py_CODEUNIT * + _Py_call_instrumentation_jump( +- PyThreadState *tstate, int event, +- _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *target) ++ _Py_CODEUNIT *instr, PyThreadState *tstate, int event, ++ _PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNIT *dest) + { + assert(event == PY_MONITORING_EVENT_JUMP || +- event == PY_MONITORING_EVENT_BRANCH); +- assert(frame->instr_ptr == instr); +- int to = (int)(target - _PyFrame_GetBytecode(frame)); ++ event == PY_MONITORING_EVENT_BRANCH_RIGHT || ++ event == PY_MONITORING_EVENT_BRANCH_LEFT); ++ int to = (int)(dest - _PyFrame_GetBytecode(frame)); + PyObject *to_obj = PyLong_FromLong(to * (int)sizeof(_Py_CODEUNIT)); + if (to_obj == NULL) { + return NULL; + } + PyObject *args[4] = { NULL, NULL, NULL, to_obj }; +- int err = call_instrumentation_vector(tstate, event, frame, instr, 3, args); ++ _Py_CODEUNIT *instr_ptr = frame->instr_ptr; ++ int err = call_instrumentation_vector(instr, tstate, event, frame, src, 3, args); + Py_DECREF(to_obj); + if (err) { + return NULL; + } +- if (frame->instr_ptr != instr) { ++ if (frame->instr_ptr != instr_ptr) { + /* The callback has caused a jump (by setting the line number) */ + return frame->instr_ptr; + } +- return target; ++ return dest; + } + + static void +@@ -1218,7 +1256,7 @@ + { + assert(_PyErr_Occurred(tstate)); + PyObject *exc = _PyErr_GetRaisedException(tstate); +- int err = call_instrumentation_vector(tstate, event, frame, instr, nargs, args); ++ int err = call_instrumentation_vector(instr, tstate, event, frame, instr, nargs, args); + if (err) { + Py_XDECREF(exc); + } +@@ -1238,18 +1276,16 @@ + call_instrumentation_vector_protected(tstate, event, frame, instr, 4, args); + } + +- + int + _Py_Instrumentation_GetLine(PyCodeObject *code, int index) + { + _PyCoMonitoringData *monitoring = code->_co_monitoring; + assert(monitoring != NULL); + assert(monitoring->lines != NULL); +- assert(index >= code->_co_firsttraceable); + assert(index < Py_SIZE(code)); +- _PyCoLineInstrumentationData *line_data = &monitoring->lines[index]; +- int8_t line_delta = line_data->line_delta; +- int line = compute_line(code, index, line_delta); ++ _PyCoLineInstrumentationData *line_data = monitoring->lines; ++ int line_delta = get_line_delta(line_data, index); ++ int line = compute_line(code, line_delta); + return line; + } + +@@ -1263,29 +1299,20 @@ + int i = (int)(instr - bytecode); + + _PyCoMonitoringData *monitoring = code->_co_monitoring; +- _PyCoLineInstrumentationData *line_data = &monitoring->lines[i]; ++ _PyCoLineInstrumentationData *line_data = monitoring->lines; + PyInterpreterState *interp = tstate->interp; +- int8_t line_delta = line_data->line_delta; +- int line = 0; +- +- if (line_delta == COMPUTED_LINE_LINENO_CHANGE) { +- // We know the line number must have changed, don't need to calculate +- // the line number for now because we might not need it. +- line = -1; +- } else { +- line = compute_line(code, i, line_delta); +- assert(line >= 0); +- assert(prev != NULL); +- int prev_index = (int)(prev - bytecode); +- int prev_line = _Py_Instrumentation_GetLine(code, prev_index); +- if (prev_line == line) { +- int prev_opcode = bytecode[prev_index].op.code; +- /* RESUME and INSTRUMENTED_RESUME are needed for the operation of +- * instrumentation, so must never be hidden by an INSTRUMENTED_LINE. +- */ +- if (prev_opcode != RESUME && prev_opcode != INSTRUMENTED_RESUME) { +- goto done; +- } ++ int line = _Py_Instrumentation_GetLine(code, i); ++ assert(line >= 0); ++ assert(prev != NULL); ++ int prev_index = (int)(prev - bytecode); ++ int prev_line = _Py_Instrumentation_GetLine(code, prev_index); ++ if (prev_line == line) { ++ int prev_opcode = bytecode[prev_index].op.code; ++ /* RESUME and INSTRUMENTED_RESUME are needed for the operation of ++ * instrumentation, so must never be hidden by an INSTRUMENTED_LINE. ++ */ ++ if (prev_opcode != RESUME && prev_opcode != INSTRUMENTED_RESUME) { ++ goto done; + } + } + +@@ -1310,12 +1337,6 @@ + tstate->tracing++; + /* Call c_tracefunc directly, having set the line number. */ + Py_INCREF(frame_obj); +- if (line == -1 && line_delta > COMPUTED_LINE) { +- /* Only assign f_lineno if it's easy to calculate, otherwise +- * do lazy calculation by setting the f_lineno to 0. +- */ +- line = compute_line(code, i, line_delta); +- } + frame_obj->f_lineno = line; + int err = tstate->c_tracefunc(tstate->c_traceobj, frame_obj, PyTrace_LINE, Py_None); + frame_obj->f_lineno = 0; +@@ -1332,11 +1353,6 @@ + if (tools == 0) { + goto done; + } +- +- if (line == -1) { +- /* Need to calculate the line number now for monitoring events */ +- line = compute_line(code, i, line_delta); +- } + PyObject *line_obj = PyLong_FromLong(line); + if (line_obj == NULL) { + return -1; +@@ -1368,7 +1384,7 @@ + Py_DECREF(line_obj); + uint8_t original_opcode; + done: +- original_opcode = line_data->original_opcode; ++ original_opcode = get_original_opcode(line_data, i); + assert(original_opcode != 0); + assert(original_opcode != INSTRUMENTED_LINE); + assert(_PyOpcode_Deopt[original_opcode] == original_opcode); +@@ -1427,19 +1443,6 @@ + return next_opcode; + } + +- +-PyObject * +-_PyMonitoring_RegisterCallback(int tool_id, int event_id, PyObject *obj) +-{ +- PyInterpreterState *is = _PyInterpreterState_GET(); +- assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); +- assert(0 <= event_id && event_id < _PY_MONITORING_EVENTS); +- PyObject *callback = _Py_atomic_exchange_ptr(&is->monitoring_callables[tool_id][event_id], +- Py_XNewRef(obj)); +- +- return callback; +-} +- + static void + initialize_tools(PyCodeObject *code) + { +@@ -1453,7 +1456,7 @@ + int opcode = instr->op.code; + assert(opcode != ENTER_EXECUTOR); + if (opcode == INSTRUMENTED_LINE) { +- opcode = code->_co_monitoring->lines[i].original_opcode; ++ opcode = get_original_opcode(code->_co_monitoring->lines, i); + } + if (opcode == INSTRUMENTED_INSTRUCTION) { + opcode = code->_co_monitoring->per_instruction_opcodes[i]; +@@ -1496,63 +1499,58 @@ + } + } + +-#define NO_LINE -128 +- + static void +-initialize_lines(PyCodeObject *code) ++initialize_lines(PyCodeObject *code, int bytes_per_entry) + { + ASSERT_WORLD_STOPPED_OR_LOCKED(code); + _PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines; + + assert(line_data != NULL); ++ line_data->bytes_per_entry = bytes_per_entry; + int code_len = (int)Py_SIZE(code); + PyCodeAddressRange range; + _PyCode_InitAddressRange(code, &range); +- for (int i = 0; i < code->_co_firsttraceable && i < code_len; i++) { +- line_data[i].original_opcode = 0; +- line_data[i].line_delta = -127; +- } + int current_line = -1; +- for (int i = code->_co_firsttraceable; i < code_len; ) { ++ for (int i = 0; i < code_len; ) { + int opcode = _Py_GetBaseCodeUnit(code, i).op.code; + int line = _PyCode_CheckLineNumber(i*(int)sizeof(_Py_CODEUNIT), &range); +- line_data[i].line_delta = compute_line_delta(code, i, line); ++ set_line_delta(line_data, i, compute_line_delta(code, line)); + int length = _PyInstruction_GetLength(code, i); +- switch (opcode) { +- case END_ASYNC_FOR: +- case END_FOR: +- case END_SEND: +- case RESUME: +- /* END_FOR cannot start a line, as it is skipped by FOR_ITER +- * END_SEND cannot start a line, as it is skipped by SEND +- * RESUME must not be instrumented with INSTRUMENT_LINE */ +- line_data[i].original_opcode = 0; +- break; +- default: +- /* Set original_opcode to the opcode iff the instruction +- * starts a line, and thus should be instrumented. +- * This saves having to perform this check every time the +- * we turn instrumentation on or off, and serves as a sanity +- * check when debugging. +- */ +- if (line != current_line && line >= 0) { +- line_data[i].original_opcode = opcode; +- if (line_data[i].line_delta == COMPUTED_LINE) { +- /* Label this line as a line with a line number change +- * which could help the monitoring callback to quickly +- * identify the line number change. +- */ +- line_data[i].line_delta = COMPUTED_LINE_LINENO_CHANGE; ++ if (i < code->_co_firsttraceable) { ++ set_original_opcode(line_data, i, 0); ++ } ++ else { ++ switch (opcode) { ++ case END_ASYNC_FOR: ++ case END_FOR: ++ case END_SEND: ++ case RESUME: ++ case POP_ITER: ++ /* END_FOR cannot start a line, as it is skipped by FOR_ITER ++ * END_SEND cannot start a line, as it is skipped by SEND ++ * RESUME and POP_ITER must not be instrumented with INSTRUMENTED_LINE */ ++ set_original_opcode(line_data, i, 0); ++ break; ++ default: ++ /* Set original_opcode to the opcode iff the instruction ++ * starts a line, and thus should be instrumented. ++ * This saves having to perform this check every time the ++ * we turn instrumentation on or off, and serves as a sanity ++ * check when debugging. ++ */ ++ if (line != current_line && line >= 0) { ++ set_original_opcode(line_data, i, opcode); ++ CHECK(get_line_delta(line_data, i) != NO_LINE); + } +- } +- else { +- line_data[i].original_opcode = 0; +- } +- current_line = line; ++ else { ++ set_original_opcode(line_data, i, 0); ++ } ++ current_line = line; ++ } + } + for (int j = 1; j < length; j++) { +- line_data[i+j].original_opcode = 0; +- line_data[i+j].line_delta = NO_LINE; ++ set_original_opcode(line_data, i+j, 0); ++ set_line_delta(line_data, i+j, NO_LINE); + } + i += length; + } +@@ -1596,12 +1594,10 @@ + continue; + } + assert(target >= 0); +- if (line_data[target].line_delta != NO_LINE) { +- line_data[target].original_opcode = _Py_GetBaseCodeUnit(code, target).op.code; +- if (line_data[target].line_delta == COMPUTED_LINE_LINENO_CHANGE) { +- // If the line is a jump target, we are not sure if the line +- // number changes, so we set it to COMPUTED_LINE. +- line_data[target].line_delta = COMPUTED_LINE; ++ if (get_line_delta(line_data, target) != NO_LINE) { ++ int opcode = _Py_GetBaseCodeUnit(code, target).op.code; ++ if (opcode != POP_ITER) { ++ set_original_opcode(line_data, target, opcode); + } + } + } +@@ -1624,9 +1620,8 @@ + * END_ASYNC_FOR is a bit special as it marks the end of + * an `async for` loop, which should not generate its own + * line event. */ +- if (line_data[handler].line_delta != NO_LINE && +- original_opcode != END_ASYNC_FOR) { +- line_data[handler].original_opcode = original_opcode; ++ if (get_line_delta(line_data, handler) != NO_LINE && original_opcode != END_ASYNC_FOR) { ++ set_original_opcode(line_data, handler, original_opcode); + } + } + } +@@ -1699,12 +1694,39 @@ + } + if (all_events.tools[PY_MONITORING_EVENT_LINE]) { + if (code->_co_monitoring->lines == NULL) { +- code->_co_monitoring->lines = PyMem_Malloc(code_len * sizeof(_PyCoLineInstrumentationData)); ++ PyCodeAddressRange range; ++ _PyCode_InitAddressRange(code, &range); ++ int max_line = code->co_firstlineno + 1; ++ _PyCode_InitAddressRange(code, &range); ++ for (int i = code->_co_firsttraceable; i < code_len; ) { ++ int line = _PyCode_CheckLineNumber(i*(int)sizeof(_Py_CODEUNIT), &range); ++ if (line > max_line) { ++ max_line = line; ++ } ++ int length = _PyInstruction_GetLength(code, i); ++ i += length; ++ } ++ int bytes_per_entry; ++ int max_delta = max_line - code->co_firstlineno; ++ /* We store delta+2 in the table, so 253 is max for one byte */ ++ if (max_delta < 256+NO_LINE) { ++ bytes_per_entry = 2; ++ } ++ else if (max_delta < (1 << 16)+NO_LINE) { ++ bytes_per_entry = 3; ++ } ++ else if (max_delta < (1 << 24)+NO_LINE) { ++ bytes_per_entry = 4; ++ } ++ else { ++ bytes_per_entry = 5; ++ } ++ code->_co_monitoring->lines = PyMem_Malloc(1 + code_len * bytes_per_entry); + if (code->_co_monitoring->lines == NULL) { + PyErr_NoMemory(); + return -1; + } +- initialize_lines(code); ++ initialize_lines(code, bytes_per_entry); + } + if (multitools && code->_co_monitoring->line_tools == NULL) { + code->_co_monitoring->line_tools = PyMem_Malloc(code_len); +@@ -1819,7 +1841,7 @@ + if (removed_line_tools) { + _PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines; + for (int i = code->_co_firsttraceable; i < code_len;) { +- if (line_data[i].original_opcode) { ++ if (get_original_opcode(line_data, i)) { + remove_line_tools(code, i, removed_line_tools); + } + i += _PyInstruction_GetLength(code, i); +@@ -1846,7 +1868,7 @@ + if (new_line_tools) { + _PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines; + for (int i = code->_co_firsttraceable; i < code_len;) { +- if (line_data[i].original_opcode) { ++ if (get_original_opcode(line_data, i)) { + add_line_tools(code, i, new_line_tools); + } + i += _PyInstruction_GetLength(code, i); +@@ -1919,7 +1941,7 @@ + while (ts) { + _PyInterpreterFrame *frame = ts->current_frame; + while (frame) { +- if (frame->owner != FRAME_OWNED_BY_CSTACK) { ++ if (frame->owner < FRAME_OWNED_BY_INTERPRETER) { + if (instrument_lock_held(_PyFrame_GetCode(frame), interp)) { + return -1; + } +@@ -2312,6 +2334,10 @@ + return NULL; + } + event_set &= ~C_RETURN_EVENTS; ++ if (event_set & (1 << PY_MONITORING_EVENT_BRANCH)) { ++ event_set &= ~(1 << PY_MONITORING_EVENT_BRANCH); ++ event_set |= (1 << PY_MONITORING_EVENT_BRANCH_RIGHT) | (1 << PY_MONITORING_EVENT_BRANCH_LEFT); ++ } + if (_PyMonitoring_SetEvents(tool_id, event_set)) { + return NULL; + } +@@ -2384,6 +2410,10 @@ + return NULL; + } + event_set &= ~C_RETURN_EVENTS; ++ if (event_set & (1 << PY_MONITORING_EVENT_BRANCH)) { ++ event_set &= ~(1 << PY_MONITORING_EVENT_BRANCH); ++ event_set |= (1 << PY_MONITORING_EVENT_BRANCH_RIGHT) | (1 << PY_MONITORING_EVENT_BRANCH_LEFT); ++ } + if (event_set < 0 || event_set >= (1 << _PY_MONITORING_LOCAL_EVENTS)) { + PyErr_Format(PyExc_ValueError, "invalid local event set 0x%x", event_set); + return NULL; +@@ -2711,7 +2741,27 @@ + assert(state->active); + PyObject *args[4] = { NULL, NULL, NULL, target_offset }; + return capi_call_instrumentation(state, codelike, offset, args, 3, +- PY_MONITORING_EVENT_BRANCH); ++ PY_MONITORING_EVENT_BRANCH_RIGHT); ++} ++ ++int ++_PyMonitoring_FireBranchRightEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, ++ PyObject *target_offset) ++{ ++ assert(state->active); ++ PyObject *args[4] = { NULL, NULL, NULL, target_offset }; ++ return capi_call_instrumentation(state, codelike, offset, args, 3, ++ PY_MONITORING_EVENT_BRANCH_RIGHT); ++} ++ ++int ++_PyMonitoring_FireBranchLeftEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, ++ PyObject *target_offset) ++{ ++ assert(state->active); ++ PyObject *args[4] = { NULL, NULL, NULL, target_offset }; ++ return capi_call_instrumentation(state, codelike, offset, args, 3, ++ PY_MONITORING_EVENT_BRANCH_LEFT); + } + + int +@@ -2849,3 +2899,250 @@ + Py_DECREF(exc); + return exception_event_teardown(err, NULL); + } ++ ++ ++ ++/* Handle legacy BRANCH event */ ++ ++typedef struct _PyLegacyBranchEventHandler { ++ PyObject_HEAD ++ vectorcallfunc vectorcall; ++ PyObject *handler; ++ bool right; ++ int tool_id; ++} _PyLegacyBranchEventHandler; ++ ++static void ++dealloc_branch_handler(_PyLegacyBranchEventHandler *self) ++{ ++ Py_CLEAR(self->handler); ++ PyObject_Free((PyObject *)self); ++} ++ ++static PyTypeObject _PyLegacyBranchEventHandler_Type = { ++ PyVarObject_HEAD_INIT(&PyType_Type, 0) ++ "sys.monitoring.branch_event_handler", ++ sizeof(_PyLegacyBranchEventHandler), ++ .tp_dealloc = (destructor)dealloc_branch_handler, ++ .tp_vectorcall_offset = offsetof(_PyLegacyBranchEventHandler, vectorcall), ++ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | ++ Py_TPFLAGS_HAVE_VECTORCALL | Py_TPFLAGS_DISALLOW_INSTANTIATION, ++ .tp_call = PyVectorcall_Call, ++}; ++ ++ ++static PyObject * ++branch_handler( ++ _PyLegacyBranchEventHandler *self, PyObject *const *args, ++ size_t nargsf, PyObject *kwnames ++) { ++ // Find the other instrumented instruction and remove tool ++ // The spec (PEP 669) allows spurious events after a DISABLE, ++ // so a best effort is good enough. ++ assert(PyVectorcall_NARGS(nargsf) >= 3); ++ PyCodeObject *code = (PyCodeObject *)args[0]; ++ int src_offset = PyLong_AsLong(args[1]); ++ if (PyErr_Occurred()) { ++ return NULL; ++ } ++ _Py_CODEUNIT instr = _PyCode_CODE(code)[src_offset/2]; ++ if (!is_instrumented(instr.op.code)) { ++ /* Already disabled */ ++ return &_PyInstrumentation_DISABLE; ++ } ++ PyObject *res = PyObject_Vectorcall(self->handler, args, nargsf, kwnames); ++ if (res == &_PyInstrumentation_DISABLE) { ++ /* We need FOR_ITER and POP_JUMP_ to be the same size */ ++ assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1); ++ int offset; ++ int other_event; ++ if (instr.op.code == FOR_ITER) { ++ if (self->right) { ++ offset = src_offset/2; ++ other_event = PY_MONITORING_EVENT_BRANCH_LEFT; ++ } ++ else { ++ // We don't know where the POP_ITER is, so ++ // we cannot de-instrument it. ++ return res; ++ } ++ } ++ else if (IS_CONDITIONAL_JUMP_OPCODE(instr.op.code)) { ++ if (self->right) { ++ offset = src_offset/2 + 2; ++ other_event = PY_MONITORING_EVENT_BRANCH_LEFT; ++ assert(_Py_GetBaseCodeUnit(code, offset).op.code == NOT_TAKEN); ++ } ++ else { ++ offset = src_offset/2; ++ other_event = PY_MONITORING_EVENT_BRANCH_RIGHT; ++ } ++ } ++ else { ++ // Orphaned NOT_TAKEN -- Jump removed by the compiler ++ return res; ++ } ++ LOCK_CODE(code); ++ remove_tools(code, offset, other_event, 1 << self->tool_id); ++ UNLOCK_CODE(); ++ } ++ return res; ++} ++ ++static PyObject *make_branch_handler(int tool_id, PyObject *handler, bool right) ++{ ++ _PyLegacyBranchEventHandler *callback = ++ PyObject_NEW(_PyLegacyBranchEventHandler, &_PyLegacyBranchEventHandler_Type); ++ if (callback == NULL) { ++ return NULL; ++ } ++ callback->vectorcall = (vectorcallfunc)branch_handler; ++ callback->handler = Py_NewRef(handler); ++ callback->right = right; ++ callback->tool_id = tool_id; ++ return (PyObject *)callback; ++} ++ ++/* Consumes a reference to obj */ ++static PyObject *exchange_callables(int tool_id, int event_id, PyObject *obj) ++{ ++ PyInterpreterState *is = _PyInterpreterState_GET(); ++ return _Py_atomic_exchange_ptr(&is->monitoring_callables[tool_id][event_id], obj); ++} ++ ++PyObject * ++_PyMonitoring_RegisterCallback(int tool_id, int event_id, PyObject *obj) ++{ ++ assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); ++ assert(0 <= event_id && event_id < _PY_MONITORING_EVENTS); ++ PyObject *res; ++ if (event_id == PY_MONITORING_EVENT_BRANCH) { ++ PyObject *left, *right; ++ if (obj == NULL) { ++ left = NULL; ++ right = NULL; ++ } ++ else { ++ right = make_branch_handler(tool_id, obj, true); ++ if (right == NULL) { ++ return NULL; ++ } ++ left = make_branch_handler(tool_id, obj, false); ++ if (left == NULL) { ++ Py_DECREF(right); ++ return NULL; ++ } ++ } ++ Py_XDECREF(exchange_callables(tool_id, PY_MONITORING_EVENT_BRANCH_RIGHT, right)); ++ res = exchange_callables(tool_id, PY_MONITORING_EVENT_BRANCH_LEFT, left); ++ } ++ else { ++ res = exchange_callables(tool_id, event_id, Py_XNewRef(obj)); ++ } ++ if (res != NULL && Py_TYPE(res) == &_PyLegacyBranchEventHandler_Type) { ++ _PyLegacyBranchEventHandler *wrapper = (_PyLegacyBranchEventHandler *)res; ++ res = Py_NewRef(wrapper->handler); ++ Py_DECREF(wrapper); ++ } ++ return res; ++} ++ ++/* Branch Iterator */ ++ ++typedef struct { ++ PyObject_HEAD ++ PyCodeObject *bi_code; ++ int bi_offset; ++} branchesiterator; ++ ++static PyObject * ++int_triple(int a, int b, int c) { ++ PyObject *obja = PyLong_FromLong(a); ++ PyObject *objb = NULL; ++ PyObject *objc = NULL; ++ if (obja == NULL) { ++ goto error; ++ } ++ objb = PyLong_FromLong(b); ++ if (objb == NULL) { ++ goto error; ++ } ++ objc = PyLong_FromLong(c); ++ if (objc == NULL) { ++ goto error; ++ } ++ PyObject *array[3] = { obja, objb, objc }; ++ return _PyTuple_FromArraySteal(array, 3); ++error: ++ Py_XDECREF(obja); ++ Py_XDECREF(objb); ++ Py_XDECREF(objc); ++ return NULL; ++} ++ ++static PyObject * ++branchesiter_next(branchesiterator *bi) ++{ ++ int offset = bi->bi_offset; ++ int oparg = 0; ++ while (offset < Py_SIZE(bi->bi_code)) { ++ _Py_CODEUNIT inst = _Py_GetBaseCodeUnit(bi->bi_code, offset); ++ int next_offset = offset + 1 + _PyOpcode_Caches[inst.op.code]; ++ switch(inst.op.code) { ++ case EXTENDED_ARG: ++ oparg = (oparg << 8) | inst.op.arg; ++ break; ++ case FOR_ITER: ++ oparg = (oparg << 8) | inst.op.arg; ++ bi->bi_offset = next_offset; ++ int target = next_offset + oparg+2; // Skips END_FOR and POP_ITER ++ return int_triple(offset*2, next_offset*2, target*2); ++ case POP_JUMP_IF_FALSE: ++ case POP_JUMP_IF_TRUE: ++ case POP_JUMP_IF_NONE: ++ case POP_JUMP_IF_NOT_NONE: ++ oparg = (oparg << 8) | inst.op.arg; ++ /* Skip NOT_TAKEN */ ++ int not_taken = next_offset + 1; ++ bi->bi_offset = not_taken; ++ return int_triple(offset*2, not_taken*2, (next_offset + oparg)*2); ++ default: ++ oparg = 0; ++ } ++ offset = next_offset; ++ } ++ return NULL; ++} ++ ++static void ++branchesiter_dealloc(branchesiterator *bi) ++{ ++ Py_DECREF(bi->bi_code); ++ PyObject_Free(bi); ++} ++ ++static PyTypeObject _PyBranchesIterator = { ++ PyVarObject_HEAD_INIT(&PyType_Type, 0) ++ "line_iterator", /* tp_name */ ++ sizeof(branchesiterator), /* tp_basicsize */ ++ 0, /* tp_itemsize */ ++ /* methods */ ++ .tp_dealloc = (destructor)branchesiter_dealloc, ++ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, ++ .tp_iter = PyObject_SelfIter, ++ .tp_iternext = (iternextfunc)branchesiter_next, ++ .tp_free = PyObject_Del, ++}; ++ ++PyObject * ++_PyInstrumentation_BranchesIterator(PyCodeObject *code) ++{ ++ ++ branchesiterator *bi = (branchesiterator *)PyType_GenericAlloc(&_PyBranchesIterator, 0); ++ if (bi == NULL) { ++ return NULL; ++ } ++ bi->bi_code = (PyCodeObject*)Py_NewRef(code); ++ bi->bi_offset = 0; ++ return (PyObject *)bi; ++} +diff --git a/Python/jit.c b/Python/jit.c +index 7dd0da7a450..092b873bc73 100644 +--- a/Python/jit.c ++++ b/Python/jit.c +@@ -87,6 +87,7 @@ + jit_error("unable to free memory"); + return -1; + } ++ OPT_STAT_ADD(jit_freed_memory_size, size); + return 0; + } + +@@ -501,8 +502,8 @@ + // Round up to the nearest page: + size_t page_size = get_page_size(); + assert((page_size & (page_size - 1)) == 0); +- size_t padding = page_size - ((code_size + data_size + state.trampolines.size) & (page_size - 1)); +- size_t total_size = code_size + data_size + state.trampolines.size + padding; ++ size_t padding = page_size - ((code_size + state.trampolines.size + data_size) & (page_size - 1)); ++ size_t total_size = code_size + state.trampolines.size + data_size + padding; + unsigned char *memory = jit_alloc(total_size); + if (memory == NULL) { + return -1; +@@ -510,14 +511,21 @@ + #ifdef MAP_JIT + pthread_jit_write_protect_np(0); + #endif ++ // Collect memory stats ++ OPT_STAT_ADD(jit_total_memory_size, total_size); ++ OPT_STAT_ADD(jit_code_size, code_size); ++ OPT_STAT_ADD(jit_trampoline_size, state.trampolines.size); ++ OPT_STAT_ADD(jit_data_size, data_size); ++ OPT_STAT_ADD(jit_padding_size, padding); ++ OPT_HIST(total_size, trace_total_memory_hist); + // Update the offsets of each instruction: + for (size_t i = 0; i < length; i++) { + state.instruction_starts[i] += (uintptr_t)memory; + } + // Loop again to emit the code: + unsigned char *code = memory; +- unsigned char *data = memory + code_size; +- state.trampolines.mem = memory + code_size + data_size; ++ state.trampolines.mem = memory + code_size; ++ unsigned char *data = memory + code_size + state.trampolines.size; + // Compile the shim, which handles converting between the native + // calling convention and the calling convention used by jitted code + // (which may be different for efficiency reasons). +@@ -539,7 +547,7 @@ + code += group->code_size; + data += group->data_size; + assert(code == memory + code_size); +- assert(data == memory + code_size + data_size); ++ assert(data == memory + code_size + state.trampolines.size + data_size); + #ifdef MAP_JIT + pthread_jit_write_protect_np(1); + #endif +@@ -563,7 +571,8 @@ + executor->jit_side_entry = NULL; + executor->jit_size = 0; + if (jit_free(memory, size)) { +- PyErr_WriteUnraisable(NULL); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "freeing JIT memory"); + } + } + } +diff --git a/Python/legacy_tracing.c b/Python/legacy_tracing.c +index 45af275f1f6..97634f9183c 100644 +--- a/Python/legacy_tracing.c ++++ b/Python/legacy_tracing.c +@@ -491,8 +491,8 @@ + _PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) + { + assert(is_tstate_valid(tstate)); +- /* The caller must hold the GIL */ +- assert(PyGILState_Check()); ++ /* The caller must hold a thread state */ ++ _Py_AssertHoldsTstate(); + + /* Call _PySys_Audit() in the context of the current thread state, + even if tstate is not the current thread state. */ +@@ -586,8 +586,8 @@ + _PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) + { + assert(is_tstate_valid(tstate)); +- /* The caller must hold the GIL */ +- assert(PyGILState_Check()); ++ /* The caller must hold a thread state */ ++ _Py_AssertHoldsTstate(); + + /* Call _PySys_Audit() in the context of the current thread state, + even if tstate is not the current thread state. */ +diff --git a/Python/marshal.c b/Python/marshal.c +index 72afa4ff894..cf701165251 100644 +--- a/Python/marshal.c ++++ b/Python/marshal.c +@@ -240,10 +240,6 @@ + #define PyLong_MARSHAL_SHIFT 15 + #define PyLong_MARSHAL_BASE ((short)1 << PyLong_MARSHAL_SHIFT) + #define PyLong_MARSHAL_MASK (PyLong_MARSHAL_BASE - 1) +-#if PyLong_SHIFT % PyLong_MARSHAL_SHIFT != 0 +-#error "PyLong_SHIFT must be a multiple of PyLong_MARSHAL_SHIFT" +-#endif +-#define PyLong_MARSHAL_RATIO (PyLong_SHIFT / PyLong_MARSHAL_SHIFT) + + #define W_TYPE(t, p) do { \ + w_byte((t) | flag, (p)); \ +@@ -252,47 +248,106 @@ + static PyObject * + _PyMarshal_WriteObjectToString(PyObject *x, int version, int allow_code); + ++#define _r_digits(bitsize) \ ++static void \ ++_r_digits##bitsize(const uint ## bitsize ## _t *digits, Py_ssize_t n, \ ++ uint8_t negative, Py_ssize_t marshal_ratio, WFILE *p) \ ++{ \ ++ /* set l to number of base PyLong_MARSHAL_BASE digits */ \ ++ Py_ssize_t l = (n - 1)*marshal_ratio; \ ++ uint ## bitsize ## _t d = digits[n - 1]; \ ++ \ ++ assert(marshal_ratio > 0); \ ++ assert(n >= 1); \ ++ assert(d != 0); /* a PyLong is always normalized */ \ ++ do { \ ++ d >>= PyLong_MARSHAL_SHIFT; \ ++ l++; \ ++ } while (d != 0); \ ++ if (l > SIZE32_MAX) { \ ++ p->depth--; \ ++ p->error = WFERR_UNMARSHALLABLE; \ ++ return; \ ++ } \ ++ w_long((long)(negative ? -l : l), p); \ ++ \ ++ for (Py_ssize_t i = 0; i < n - 1; i++) { \ ++ d = digits[i]; \ ++ for (Py_ssize_t j = 0; j < marshal_ratio; j++) { \ ++ w_short(d & PyLong_MARSHAL_MASK, p); \ ++ d >>= PyLong_MARSHAL_SHIFT; \ ++ } \ ++ assert(d == 0); \ ++ } \ ++ d = digits[n - 1]; \ ++ do { \ ++ w_short(d & PyLong_MARSHAL_MASK, p); \ ++ d >>= PyLong_MARSHAL_SHIFT; \ ++ } while (d != 0); \ ++} ++_r_digits(16) ++_r_digits(32) ++#undef _r_digits ++ + static void + w_PyLong(const PyLongObject *ob, char flag, WFILE *p) + { +- Py_ssize_t i, j, n, l; +- digit d; +- + W_TYPE(TYPE_LONG, p); + if (_PyLong_IsZero(ob)) { + w_long((long)0, p); + return; + } + +- /* set l to number of base PyLong_MARSHAL_BASE digits */ +- n = _PyLong_DigitCount(ob); +- l = (n-1) * PyLong_MARSHAL_RATIO; +- d = ob->long_value.ob_digit[n-1]; +- assert(d != 0); /* a PyLong is always normalized */ +- do { +- d >>= PyLong_MARSHAL_SHIFT; +- l++; +- } while (d != 0); +- if (l > SIZE32_MAX) { ++ PyLongExport long_export; ++ ++ if (PyLong_Export((PyObject *)ob, &long_export) < 0) { + p->depth--; + p->error = WFERR_UNMARSHALLABLE; + return; + } +- w_long((long)(_PyLong_IsNegative(ob) ? -l : l), p); ++ if (!long_export.digits) { ++ int8_t sign = long_export.value < 0 ? -1 : 1; ++ uint64_t abs_value = Py_ABS(long_export.value); ++ uint64_t d = abs_value; ++ long l = 0; + +- for (i=0; i < n-1; i++) { +- d = ob->long_value.ob_digit[i]; +- for (j=0; j < PyLong_MARSHAL_RATIO; j++) { ++ /* set l to number of base PyLong_MARSHAL_BASE digits */ ++ do { ++ d >>= PyLong_MARSHAL_SHIFT; ++ l += sign; ++ } while (d); ++ w_long(l, p); ++ ++ d = abs_value; ++ do { + w_short(d & PyLong_MARSHAL_MASK, p); + d >>= PyLong_MARSHAL_SHIFT; +- } +- assert (d == 0); ++ } while (d); ++ return; + } +- d = ob->long_value.ob_digit[n-1]; +- do { +- w_short(d & PyLong_MARSHAL_MASK, p); +- d >>= PyLong_MARSHAL_SHIFT; +- } while (d != 0); ++ ++ const PyLongLayout *layout = PyLong_GetNativeLayout(); ++ Py_ssize_t marshal_ratio = layout->bits_per_digit/PyLong_MARSHAL_SHIFT; ++ ++ /* must be a multiple of PyLong_MARSHAL_SHIFT */ ++ assert(layout->bits_per_digit % PyLong_MARSHAL_SHIFT == 0); ++ assert(layout->bits_per_digit >= PyLong_MARSHAL_SHIFT); ++ ++ /* other assumptions on PyLongObject internals */ ++ assert(layout->bits_per_digit <= 32); ++ assert(layout->digits_order == -1); ++ assert(layout->digit_endianness == (PY_LITTLE_ENDIAN ? -1 : 1)); ++ assert(layout->digit_size == 2 || layout->digit_size == 4); ++ ++ if (layout->digit_size == 4) { ++ _r_digits32(long_export.digits, long_export.ndigits, ++ long_export.negative, marshal_ratio, p); ++ } ++ else { ++ _r_digits16(long_export.digits, long_export.ndigits, ++ long_export.negative, marshal_ratio, p); ++ } ++ PyLong_FreeExport(&long_export); + } + + static void +@@ -875,17 +930,62 @@ + 1 /* signed */); + } + ++#define _w_digits(bitsize) \ ++static int \ ++_w_digits##bitsize(uint ## bitsize ## _t *digits, Py_ssize_t size, \ ++ Py_ssize_t marshal_ratio, \ ++ int shorts_in_top_digit, RFILE *p) \ ++{ \ ++ uint ## bitsize ## _t d; \ ++ \ ++ assert(size >= 1); \ ++ for (Py_ssize_t i = 0; i < size - 1; i++) { \ ++ d = 0; \ ++ for (Py_ssize_t j = 0; j < marshal_ratio; j++) { \ ++ int md = r_short(p); \ ++ if (md < 0 || md > PyLong_MARSHAL_BASE) { \ ++ goto bad_digit; \ ++ } \ ++ d += (uint ## bitsize ## _t)md << j*PyLong_MARSHAL_SHIFT; \ ++ } \ ++ digits[i] = d; \ ++ } \ ++ \ ++ d = 0; \ ++ for (Py_ssize_t j = 0; j < shorts_in_top_digit; j++) { \ ++ int md = r_short(p); \ ++ if (md < 0 || md > PyLong_MARSHAL_BASE) { \ ++ goto bad_digit; \ ++ } \ ++ /* topmost marshal digit should be nonzero */ \ ++ if (md == 0 && j == shorts_in_top_digit - 1) { \ ++ PyErr_SetString(PyExc_ValueError, \ ++ "bad marshal data (unnormalized long data)"); \ ++ return -1; \ ++ } \ ++ d += (uint ## bitsize ## _t)md << j*PyLong_MARSHAL_SHIFT; \ ++ } \ ++ assert(!PyErr_Occurred()); \ ++ /* top digit should be nonzero, else the resulting PyLong won't be \ ++ normalized */ \ ++ digits[size - 1] = d; \ ++ return 0; \ ++ \ ++bad_digit: \ ++ if (!PyErr_Occurred()) { \ ++ PyErr_SetString(PyExc_ValueError, \ ++ "bad marshal data (digit out of range in long)"); \ ++ } \ ++ return -1; \ ++} ++_w_digits(32) ++_w_digits(16) ++#undef _w_digits ++ + static PyObject * + r_PyLong(RFILE *p) + { +- PyLongObject *ob; +- long n, size, i; +- int j, md, shorts_in_top_digit; +- digit d; +- +- n = r_long(p); +- if (n == 0) +- return (PyObject *)_PyLong_New(0); ++ long n = r_long(p); + if (n == -1 && PyErr_Occurred()) { + return NULL; + } +@@ -895,51 +995,44 @@ + return NULL; + } + +- size = 1 + (Py_ABS(n) - 1) / PyLong_MARSHAL_RATIO; +- shorts_in_top_digit = 1 + (Py_ABS(n) - 1) % PyLong_MARSHAL_RATIO; +- ob = _PyLong_New(size); +- if (ob == NULL) +- return NULL; ++ const PyLongLayout *layout = PyLong_GetNativeLayout(); ++ Py_ssize_t marshal_ratio = layout->bits_per_digit/PyLong_MARSHAL_SHIFT; + +- _PyLong_SetSignAndDigitCount(ob, n < 0 ? -1 : 1, size); ++ /* must be a multiple of PyLong_MARSHAL_SHIFT */ ++ assert(layout->bits_per_digit % PyLong_MARSHAL_SHIFT == 0); ++ assert(layout->bits_per_digit >= PyLong_MARSHAL_SHIFT); + +- for (i = 0; i < size-1; i++) { +- d = 0; +- for (j=0; j < PyLong_MARSHAL_RATIO; j++) { +- md = r_short(p); +- if (md < 0 || md > PyLong_MARSHAL_BASE) +- goto bad_digit; +- d += (digit)md << j*PyLong_MARSHAL_SHIFT; +- } +- ob->long_value.ob_digit[i] = d; ++ /* other assumptions on PyLongObject internals */ ++ assert(layout->bits_per_digit <= 32); ++ assert(layout->digits_order == -1); ++ assert(layout->digit_endianness == (PY_LITTLE_ENDIAN ? -1 : 1)); ++ assert(layout->digit_size == 2 || layout->digit_size == 4); ++ ++ Py_ssize_t size = 1 + (Py_ABS(n) - 1) / marshal_ratio; ++ ++ assert(size >= 1); ++ ++ int shorts_in_top_digit = 1 + (Py_ABS(n) - 1) % marshal_ratio; ++ void *digits; ++ PyLongWriter *writer = PyLongWriter_Create(n < 0, size, &digits); ++ ++ if (writer == NULL) { ++ return NULL; + } + +- d = 0; +- for (j=0; j < shorts_in_top_digit; j++) { +- md = r_short(p); +- if (md < 0 || md > PyLong_MARSHAL_BASE) +- goto bad_digit; +- /* topmost marshal digit should be nonzero */ +- if (md == 0 && j == shorts_in_top_digit - 1) { +- Py_DECREF(ob); +- PyErr_SetString(PyExc_ValueError, +- "bad marshal data (unnormalized long data)"); +- return NULL; +- } +- d += (digit)md << j*PyLong_MARSHAL_SHIFT; ++ int ret; ++ ++ if (layout->digit_size == 4) { ++ ret = _w_digits32(digits, size, marshal_ratio, shorts_in_top_digit, p); + } +- assert(!PyErr_Occurred()); +- /* top digit should be nonzero, else the resulting PyLong won't be +- normalized */ +- ob->long_value.ob_digit[size-1] = d; +- return (PyObject *)ob; +- bad_digit: +- Py_DECREF(ob); +- if (!PyErr_Occurred()) { +- PyErr_SetString(PyExc_ValueError, +- "bad marshal data (digit out of range in long)"); ++ else { ++ ret = _w_digits16(digits, size, marshal_ratio, shorts_in_top_digit, p); ++ } ++ if (ret < 0) { ++ PyLongWriter_Discard(writer); ++ return NULL; + } +- return NULL; ++ return PyLongWriter_Finish(writer); + } + + static double +diff --git a/Python/modsupport.c b/Python/modsupport.c +index 0fb7783345c..517dc971f88 100644 +--- a/Python/modsupport.c ++++ b/Python/modsupport.c +@@ -648,3 +648,20 @@ + + return PyModule_AddObjectRef(module, name, (PyObject *)type); + } ++ ++ ++/* Exported functions for version helper macros */ ++ ++#undef Py_PACK_FULL_VERSION ++uint32_t ++Py_PACK_FULL_VERSION(int x, int y, int z, int level, int serial) ++{ ++ return _Py_PACK_FULL_VERSION(x, y, z, level, serial); ++} ++ ++#undef Py_PACK_VERSION ++uint32_t ++Py_PACK_VERSION(int x, int y) ++{ ++ return Py_PACK_FULL_VERSION(x, y, 0, 0, 0); ++} +diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h +index c93941dcac4..039a6eee379 100644 +--- a/Python/opcode_targets.h ++++ b/Python/opcode_targets.h +@@ -1,7 +1,8 @@ ++#ifndef Py_TAIL_CALL_INTERP + static void *opcode_targets[256] = { + &&TARGET_CACHE, + &&TARGET_BINARY_SLICE, +- &&TARGET_BINARY_SUBSCR, ++ &&TARGET_CALL_FUNCTION_EX, + &&TARGET_BINARY_OP_INPLACE_ADD_UNICODE, + &&TARGET_CHECK_EG_MATCH, + &&TARGET_CHECK_EXC_MATCH, +@@ -27,7 +28,9 @@ + &&TARGET_MATCH_MAPPING, + &&TARGET_MATCH_SEQUENCE, + &&TARGET_NOP, ++ &&TARGET_NOT_TAKEN, + &&TARGET_POP_EXCEPT, ++ &&TARGET_POP_ITER, + &&TARGET_POP_TOP, + &&TARGET_PUSH_EXC_INFO, + &&TARGET_PUSH_NULL, +@@ -49,7 +52,6 @@ + &&TARGET_BUILD_STRING, + &&TARGET_BUILD_TUPLE, + &&TARGET_CALL, +- &&TARGET_CALL_FUNCTION_EX, + &&TARGET_CALL_INTRINSIC_1, + &&TARGET_CALL_INTRINSIC_2, + &&TARGET_CALL_KW, +@@ -147,20 +149,20 @@ + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, +- &&_unknown_opcode, + &&TARGET_RESUME, + &&TARGET_BINARY_OP_ADD_FLOAT, + &&TARGET_BINARY_OP_ADD_INT, + &&TARGET_BINARY_OP_ADD_UNICODE, ++ &&TARGET_BINARY_OP_EXTEND, + &&TARGET_BINARY_OP_MULTIPLY_FLOAT, + &&TARGET_BINARY_OP_MULTIPLY_INT, ++ &&TARGET_BINARY_OP_SUBSCR_DICT, ++ &&TARGET_BINARY_OP_SUBSCR_GETITEM, ++ &&TARGET_BINARY_OP_SUBSCR_LIST_INT, ++ &&TARGET_BINARY_OP_SUBSCR_STR_INT, ++ &&TARGET_BINARY_OP_SUBSCR_TUPLE_INT, + &&TARGET_BINARY_OP_SUBTRACT_FLOAT, + &&TARGET_BINARY_OP_SUBTRACT_INT, +- &&TARGET_BINARY_SUBSCR_DICT, +- &&TARGET_BINARY_SUBSCR_GETITEM, +- &&TARGET_BINARY_SUBSCR_LIST_INT, +- &&TARGET_BINARY_SUBSCR_STR_INT, +- &&TARGET_BINARY_SUBSCR_TUPLE_INT, + &&TARGET_CALL_ALLOC_AND_ENTER_INIT, + &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS, + &&TARGET_CALL_BOUND_METHOD_GENERAL, +@@ -193,6 +195,8 @@ + &&TARGET_FOR_ITER_LIST, + &&TARGET_FOR_ITER_RANGE, + &&TARGET_FOR_ITER_TUPLE, ++ &&TARGET_JUMP_BACKWARD_JIT, ++ &&TARGET_JUMP_BACKWARD_NO_JIT, + &&TARGET_LOAD_ATTR_CLASS, + &&TARGET_LOAD_ATTR_CLASS_WITH_METACLASS_CHECK, + &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, +@@ -207,6 +211,7 @@ + &&TARGET_LOAD_ATTR_SLOT, + &&TARGET_LOAD_ATTR_WITH_HINT, + &&TARGET_LOAD_CONST_IMMORTAL, ++ &&TARGET_LOAD_CONST_MORTAL, + &&TARGET_LOAD_GLOBAL_BUILTIN, + &&TARGET_LOAD_GLOBAL_MODULE, + &&TARGET_LOAD_SUPER_ATTR_ATTR, +@@ -230,20 +235,13 @@ + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, +- &&_unknown_opcode, +- &&_unknown_opcode, +- &&_unknown_opcode, +- &&_unknown_opcode, +- &&_unknown_opcode, +- &&_unknown_opcode, + &&TARGET_INSTRUMENTED_END_FOR, ++ &&TARGET_INSTRUMENTED_POP_ITER, + &&TARGET_INSTRUMENTED_END_SEND, +- &&TARGET_INSTRUMENTED_LOAD_SUPER_ATTR, + &&TARGET_INSTRUMENTED_FOR_ITER, +- &&TARGET_INSTRUMENTED_CALL_KW, +- &&TARGET_INSTRUMENTED_CALL_FUNCTION_EX, + &&TARGET_INSTRUMENTED_INSTRUCTION, + &&TARGET_INSTRUMENTED_JUMP_FORWARD, ++ &&TARGET_INSTRUMENTED_NOT_TAKEN, + &&TARGET_INSTRUMENTED_POP_JUMP_IF_TRUE, + &&TARGET_INSTRUMENTED_POP_JUMP_IF_FALSE, + &&TARGET_INSTRUMENTED_POP_JUMP_IF_NONE, +@@ -251,8 +249,514 @@ + &&TARGET_INSTRUMENTED_RESUME, + &&TARGET_INSTRUMENTED_RETURN_VALUE, + &&TARGET_INSTRUMENTED_YIELD_VALUE, ++ &&TARGET_INSTRUMENTED_LOAD_SUPER_ATTR, + &&TARGET_INSTRUMENTED_CALL, ++ &&TARGET_INSTRUMENTED_CALL_KW, ++ &&TARGET_INSTRUMENTED_CALL_FUNCTION_EX, + &&TARGET_INSTRUMENTED_JUMP_BACKWARD, + &&TARGET_INSTRUMENTED_LINE, + &&TARGET_ENTER_EXECUTOR, + }; ++#else /* Py_TAIL_CALL_INTERP */ ++static py_tail_call_funcptr INSTRUCTION_TABLE[256]; ++ ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_pop_4_error(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_pop_3_error(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_pop_2_error(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_pop_1_error(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_error(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_exception_unwind(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_exit_unwind(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_start_frame(TAIL_CALL_PARAMS); ++ ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_ADD_FLOAT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_ADD_INT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_ADD_UNICODE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_EXTEND(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_INPLACE_ADD_UNICODE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_MULTIPLY_FLOAT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_MULTIPLY_INT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_SUBSCR_DICT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_SUBSCR_GETITEM(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_SUBSCR_LIST_INT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_SUBSCR_STR_INT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_SUBSCR_TUPLE_INT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_SUBTRACT_FLOAT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_SUBTRACT_INT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_SLICE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BUILD_LIST(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BUILD_MAP(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BUILD_SET(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BUILD_SLICE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BUILD_STRING(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BUILD_TUPLE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CACHE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_ALLOC_AND_ENTER_INIT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_BOUND_METHOD_EXACT_ARGS(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_BOUND_METHOD_GENERAL(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_BUILTIN_CLASS(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_BUILTIN_FAST(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_BUILTIN_FAST_WITH_KEYWORDS(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_BUILTIN_O(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_FUNCTION_EX(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_INTRINSIC_1(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_INTRINSIC_2(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_ISINSTANCE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_KW(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_KW_BOUND_METHOD(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_KW_NON_PY(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_KW_PY(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_LEN(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_LIST_APPEND(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_METHOD_DESCRIPTOR_FAST(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_METHOD_DESCRIPTOR_NOARGS(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_METHOD_DESCRIPTOR_O(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_NON_PY_GENERAL(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_PY_EXACT_ARGS(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_PY_GENERAL(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_STR_1(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_TUPLE_1(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_TYPE_1(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CHECK_EG_MATCH(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CHECK_EXC_MATCH(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CLEANUP_THROW(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_COMPARE_OP(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_COMPARE_OP_FLOAT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_COMPARE_OP_INT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_COMPARE_OP_STR(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CONTAINS_OP(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CONTAINS_OP_DICT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CONTAINS_OP_SET(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CONVERT_VALUE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_COPY(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_COPY_FREE_VARS(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_DELETE_ATTR(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_DELETE_DEREF(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_DELETE_FAST(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_DELETE_GLOBAL(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_DELETE_NAME(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_DELETE_SUBSCR(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_DICT_MERGE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_DICT_UPDATE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_END_ASYNC_FOR(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_END_FOR(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_END_SEND(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_ENTER_EXECUTOR(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_EXIT_INIT_CHECK(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_EXTENDED_ARG(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_FORMAT_SIMPLE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_FORMAT_WITH_SPEC(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_FOR_ITER(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_FOR_ITER_GEN(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_FOR_ITER_LIST(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_FOR_ITER_RANGE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_FOR_ITER_TUPLE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_AITER(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_ANEXT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_AWAITABLE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_ITER(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_LEN(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_YIELD_FROM_ITER(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_IMPORT_FROM(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_IMPORT_NAME(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_CALL(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_CALL_FUNCTION_EX(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_CALL_KW(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_END_FOR(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_END_SEND(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_FOR_ITER(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_INSTRUCTION(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_JUMP_BACKWARD(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_JUMP_FORWARD(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_LINE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_LOAD_SUPER_ATTR(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_NOT_TAKEN(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_POP_ITER(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_FALSE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_NONE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_NOT_NONE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_TRUE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_RESUME(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_RETURN_VALUE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_YIELD_VALUE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INTERPRETER_EXIT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_IS_OP(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_JUMP_BACKWARD(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_JUMP_BACKWARD_JIT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_JUMP_BACKWARD_NO_INTERRUPT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_JUMP_BACKWARD_NO_JIT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_JUMP_FORWARD(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LIST_APPEND(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LIST_EXTEND(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_CLASS(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_CLASS_WITH_METACLASS_CHECK(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_INSTANCE_VALUE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_METHOD_LAZY_DICT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_METHOD_NO_DICT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_METHOD_WITH_VALUES(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_MODULE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_NONDESCRIPTOR_NO_DICT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_PROPERTY(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_SLOT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_WITH_HINT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_BUILD_CLASS(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_COMMON_CONSTANT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_CONST(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_CONST_IMMORTAL(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_CONST_MORTAL(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_DEREF(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_FAST(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_FAST_AND_CLEAR(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_FAST_CHECK(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_FAST_LOAD_FAST(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_FROM_DICT_OR_DEREF(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_FROM_DICT_OR_GLOBALS(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_GLOBAL(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_GLOBAL_BUILTIN(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_GLOBAL_MODULE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_LOCALS(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_NAME(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_SMALL_INT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_SPECIAL(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_SUPER_ATTR(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_SUPER_ATTR_ATTR(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_SUPER_ATTR_METHOD(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_MAKE_CELL(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_MAKE_FUNCTION(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_MAP_ADD(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_MATCH_CLASS(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_MATCH_KEYS(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_MATCH_MAPPING(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_MATCH_SEQUENCE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_NOP(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_NOT_TAKEN(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_POP_EXCEPT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_POP_ITER(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_POP_JUMP_IF_FALSE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_POP_JUMP_IF_NONE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_POP_JUMP_IF_NOT_NONE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_POP_JUMP_IF_TRUE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_POP_TOP(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_PUSH_EXC_INFO(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_PUSH_NULL(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_RAISE_VARARGS(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_RERAISE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_RESERVED(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_RESUME(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_RESUME_CHECK(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_RETURN_GENERATOR(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_RETURN_VALUE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_SEND(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_SEND_GEN(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_SETUP_ANNOTATIONS(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_SET_ADD(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_SET_FUNCTION_ATTRIBUTE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_SET_UPDATE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_ATTR(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_ATTR_INSTANCE_VALUE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_ATTR_SLOT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_ATTR_WITH_HINT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_DEREF(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_FAST(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_FAST_LOAD_FAST(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_FAST_STORE_FAST(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_GLOBAL(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_NAME(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_SLICE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_SUBSCR(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_SUBSCR_DICT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_SUBSCR_LIST_INT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_SWAP(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_TO_BOOL(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_TO_BOOL_ALWAYS_TRUE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_TO_BOOL_BOOL(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_TO_BOOL_INT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_TO_BOOL_LIST(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_TO_BOOL_NONE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_TO_BOOL_STR(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNARY_INVERT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNARY_NEGATIVE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNARY_NOT(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNPACK_EX(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNPACK_SEQUENCE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNPACK_SEQUENCE_LIST(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNPACK_SEQUENCE_TUPLE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNPACK_SEQUENCE_TWO_TUPLE(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_WITH_EXCEPT_START(TAIL_CALL_PARAMS); ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_YIELD_VALUE(TAIL_CALL_PARAMS); ++ ++Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNKNOWN_OPCODE(TAIL_CALL_PARAMS) { ++ int opcode = next_instr->op.code; ++ _PyErr_Format(tstate, PyExc_SystemError, ++ "%U:%d: unknown opcode %d", ++ _PyFrame_GetCode(frame)->co_filename, ++ PyUnstable_InterpreterFrame_GetLine(frame), ++ opcode); ++JUMP_TO_LABEL(error); ++} ++ ++static py_tail_call_funcptr INSTRUCTION_TABLE[256] = { ++ [BINARY_OP] = _TAIL_CALL_BINARY_OP, ++ [BINARY_OP_ADD_FLOAT] = _TAIL_CALL_BINARY_OP_ADD_FLOAT, ++ [BINARY_OP_ADD_INT] = _TAIL_CALL_BINARY_OP_ADD_INT, ++ [BINARY_OP_ADD_UNICODE] = _TAIL_CALL_BINARY_OP_ADD_UNICODE, ++ [BINARY_OP_EXTEND] = _TAIL_CALL_BINARY_OP_EXTEND, ++ [BINARY_OP_INPLACE_ADD_UNICODE] = _TAIL_CALL_BINARY_OP_INPLACE_ADD_UNICODE, ++ [BINARY_OP_MULTIPLY_FLOAT] = _TAIL_CALL_BINARY_OP_MULTIPLY_FLOAT, ++ [BINARY_OP_MULTIPLY_INT] = _TAIL_CALL_BINARY_OP_MULTIPLY_INT, ++ [BINARY_OP_SUBSCR_DICT] = _TAIL_CALL_BINARY_OP_SUBSCR_DICT, ++ [BINARY_OP_SUBSCR_GETITEM] = _TAIL_CALL_BINARY_OP_SUBSCR_GETITEM, ++ [BINARY_OP_SUBSCR_LIST_INT] = _TAIL_CALL_BINARY_OP_SUBSCR_LIST_INT, ++ [BINARY_OP_SUBSCR_STR_INT] = _TAIL_CALL_BINARY_OP_SUBSCR_STR_INT, ++ [BINARY_OP_SUBSCR_TUPLE_INT] = _TAIL_CALL_BINARY_OP_SUBSCR_TUPLE_INT, ++ [BINARY_OP_SUBTRACT_FLOAT] = _TAIL_CALL_BINARY_OP_SUBTRACT_FLOAT, ++ [BINARY_OP_SUBTRACT_INT] = _TAIL_CALL_BINARY_OP_SUBTRACT_INT, ++ [BINARY_SLICE] = _TAIL_CALL_BINARY_SLICE, ++ [BUILD_LIST] = _TAIL_CALL_BUILD_LIST, ++ [BUILD_MAP] = _TAIL_CALL_BUILD_MAP, ++ [BUILD_SET] = _TAIL_CALL_BUILD_SET, ++ [BUILD_SLICE] = _TAIL_CALL_BUILD_SLICE, ++ [BUILD_STRING] = _TAIL_CALL_BUILD_STRING, ++ [BUILD_TUPLE] = _TAIL_CALL_BUILD_TUPLE, ++ [CACHE] = _TAIL_CALL_CACHE, ++ [CALL] = _TAIL_CALL_CALL, ++ [CALL_ALLOC_AND_ENTER_INIT] = _TAIL_CALL_CALL_ALLOC_AND_ENTER_INIT, ++ [CALL_BOUND_METHOD_EXACT_ARGS] = _TAIL_CALL_CALL_BOUND_METHOD_EXACT_ARGS, ++ [CALL_BOUND_METHOD_GENERAL] = _TAIL_CALL_CALL_BOUND_METHOD_GENERAL, ++ [CALL_BUILTIN_CLASS] = _TAIL_CALL_CALL_BUILTIN_CLASS, ++ [CALL_BUILTIN_FAST] = _TAIL_CALL_CALL_BUILTIN_FAST, ++ [CALL_BUILTIN_FAST_WITH_KEYWORDS] = _TAIL_CALL_CALL_BUILTIN_FAST_WITH_KEYWORDS, ++ [CALL_BUILTIN_O] = _TAIL_CALL_CALL_BUILTIN_O, ++ [CALL_FUNCTION_EX] = _TAIL_CALL_CALL_FUNCTION_EX, ++ [CALL_INTRINSIC_1] = _TAIL_CALL_CALL_INTRINSIC_1, ++ [CALL_INTRINSIC_2] = _TAIL_CALL_CALL_INTRINSIC_2, ++ [CALL_ISINSTANCE] = _TAIL_CALL_CALL_ISINSTANCE, ++ [CALL_KW] = _TAIL_CALL_CALL_KW, ++ [CALL_KW_BOUND_METHOD] = _TAIL_CALL_CALL_KW_BOUND_METHOD, ++ [CALL_KW_NON_PY] = _TAIL_CALL_CALL_KW_NON_PY, ++ [CALL_KW_PY] = _TAIL_CALL_CALL_KW_PY, ++ [CALL_LEN] = _TAIL_CALL_CALL_LEN, ++ [CALL_LIST_APPEND] = _TAIL_CALL_CALL_LIST_APPEND, ++ [CALL_METHOD_DESCRIPTOR_FAST] = _TAIL_CALL_CALL_METHOD_DESCRIPTOR_FAST, ++ [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = _TAIL_CALL_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, ++ [CALL_METHOD_DESCRIPTOR_NOARGS] = _TAIL_CALL_CALL_METHOD_DESCRIPTOR_NOARGS, ++ [CALL_METHOD_DESCRIPTOR_O] = _TAIL_CALL_CALL_METHOD_DESCRIPTOR_O, ++ [CALL_NON_PY_GENERAL] = _TAIL_CALL_CALL_NON_PY_GENERAL, ++ [CALL_PY_EXACT_ARGS] = _TAIL_CALL_CALL_PY_EXACT_ARGS, ++ [CALL_PY_GENERAL] = _TAIL_CALL_CALL_PY_GENERAL, ++ [CALL_STR_1] = _TAIL_CALL_CALL_STR_1, ++ [CALL_TUPLE_1] = _TAIL_CALL_CALL_TUPLE_1, ++ [CALL_TYPE_1] = _TAIL_CALL_CALL_TYPE_1, ++ [CHECK_EG_MATCH] = _TAIL_CALL_CHECK_EG_MATCH, ++ [CHECK_EXC_MATCH] = _TAIL_CALL_CHECK_EXC_MATCH, ++ [CLEANUP_THROW] = _TAIL_CALL_CLEANUP_THROW, ++ [COMPARE_OP] = _TAIL_CALL_COMPARE_OP, ++ [COMPARE_OP_FLOAT] = _TAIL_CALL_COMPARE_OP_FLOAT, ++ [COMPARE_OP_INT] = _TAIL_CALL_COMPARE_OP_INT, ++ [COMPARE_OP_STR] = _TAIL_CALL_COMPARE_OP_STR, ++ [CONTAINS_OP] = _TAIL_CALL_CONTAINS_OP, ++ [CONTAINS_OP_DICT] = _TAIL_CALL_CONTAINS_OP_DICT, ++ [CONTAINS_OP_SET] = _TAIL_CALL_CONTAINS_OP_SET, ++ [CONVERT_VALUE] = _TAIL_CALL_CONVERT_VALUE, ++ [COPY] = _TAIL_CALL_COPY, ++ [COPY_FREE_VARS] = _TAIL_CALL_COPY_FREE_VARS, ++ [DELETE_ATTR] = _TAIL_CALL_DELETE_ATTR, ++ [DELETE_DEREF] = _TAIL_CALL_DELETE_DEREF, ++ [DELETE_FAST] = _TAIL_CALL_DELETE_FAST, ++ [DELETE_GLOBAL] = _TAIL_CALL_DELETE_GLOBAL, ++ [DELETE_NAME] = _TAIL_CALL_DELETE_NAME, ++ [DELETE_SUBSCR] = _TAIL_CALL_DELETE_SUBSCR, ++ [DICT_MERGE] = _TAIL_CALL_DICT_MERGE, ++ [DICT_UPDATE] = _TAIL_CALL_DICT_UPDATE, ++ [END_ASYNC_FOR] = _TAIL_CALL_END_ASYNC_FOR, ++ [END_FOR] = _TAIL_CALL_END_FOR, ++ [END_SEND] = _TAIL_CALL_END_SEND, ++ [ENTER_EXECUTOR] = _TAIL_CALL_ENTER_EXECUTOR, ++ [EXIT_INIT_CHECK] = _TAIL_CALL_EXIT_INIT_CHECK, ++ [EXTENDED_ARG] = _TAIL_CALL_EXTENDED_ARG, ++ [FORMAT_SIMPLE] = _TAIL_CALL_FORMAT_SIMPLE, ++ [FORMAT_WITH_SPEC] = _TAIL_CALL_FORMAT_WITH_SPEC, ++ [FOR_ITER] = _TAIL_CALL_FOR_ITER, ++ [FOR_ITER_GEN] = _TAIL_CALL_FOR_ITER_GEN, ++ [FOR_ITER_LIST] = _TAIL_CALL_FOR_ITER_LIST, ++ [FOR_ITER_RANGE] = _TAIL_CALL_FOR_ITER_RANGE, ++ [FOR_ITER_TUPLE] = _TAIL_CALL_FOR_ITER_TUPLE, ++ [GET_AITER] = _TAIL_CALL_GET_AITER, ++ [GET_ANEXT] = _TAIL_CALL_GET_ANEXT, ++ [GET_AWAITABLE] = _TAIL_CALL_GET_AWAITABLE, ++ [GET_ITER] = _TAIL_CALL_GET_ITER, ++ [GET_LEN] = _TAIL_CALL_GET_LEN, ++ [GET_YIELD_FROM_ITER] = _TAIL_CALL_GET_YIELD_FROM_ITER, ++ [IMPORT_FROM] = _TAIL_CALL_IMPORT_FROM, ++ [IMPORT_NAME] = _TAIL_CALL_IMPORT_NAME, ++ [INSTRUMENTED_CALL] = _TAIL_CALL_INSTRUMENTED_CALL, ++ [INSTRUMENTED_CALL_FUNCTION_EX] = _TAIL_CALL_INSTRUMENTED_CALL_FUNCTION_EX, ++ [INSTRUMENTED_CALL_KW] = _TAIL_CALL_INSTRUMENTED_CALL_KW, ++ [INSTRUMENTED_END_FOR] = _TAIL_CALL_INSTRUMENTED_END_FOR, ++ [INSTRUMENTED_END_SEND] = _TAIL_CALL_INSTRUMENTED_END_SEND, ++ [INSTRUMENTED_FOR_ITER] = _TAIL_CALL_INSTRUMENTED_FOR_ITER, ++ [INSTRUMENTED_INSTRUCTION] = _TAIL_CALL_INSTRUMENTED_INSTRUCTION, ++ [INSTRUMENTED_JUMP_BACKWARD] = _TAIL_CALL_INSTRUMENTED_JUMP_BACKWARD, ++ [INSTRUMENTED_JUMP_FORWARD] = _TAIL_CALL_INSTRUMENTED_JUMP_FORWARD, ++ [INSTRUMENTED_LINE] = _TAIL_CALL_INSTRUMENTED_LINE, ++ [INSTRUMENTED_LOAD_SUPER_ATTR] = _TAIL_CALL_INSTRUMENTED_LOAD_SUPER_ATTR, ++ [INSTRUMENTED_NOT_TAKEN] = _TAIL_CALL_INSTRUMENTED_NOT_TAKEN, ++ [INSTRUMENTED_POP_ITER] = _TAIL_CALL_INSTRUMENTED_POP_ITER, ++ [INSTRUMENTED_POP_JUMP_IF_FALSE] = _TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_FALSE, ++ [INSTRUMENTED_POP_JUMP_IF_NONE] = _TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_NONE, ++ [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = _TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_NOT_NONE, ++ [INSTRUMENTED_POP_JUMP_IF_TRUE] = _TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_TRUE, ++ [INSTRUMENTED_RESUME] = _TAIL_CALL_INSTRUMENTED_RESUME, ++ [INSTRUMENTED_RETURN_VALUE] = _TAIL_CALL_INSTRUMENTED_RETURN_VALUE, ++ [INSTRUMENTED_YIELD_VALUE] = _TAIL_CALL_INSTRUMENTED_YIELD_VALUE, ++ [INTERPRETER_EXIT] = _TAIL_CALL_INTERPRETER_EXIT, ++ [IS_OP] = _TAIL_CALL_IS_OP, ++ [JUMP_BACKWARD] = _TAIL_CALL_JUMP_BACKWARD, ++ [JUMP_BACKWARD_JIT] = _TAIL_CALL_JUMP_BACKWARD_JIT, ++ [JUMP_BACKWARD_NO_INTERRUPT] = _TAIL_CALL_JUMP_BACKWARD_NO_INTERRUPT, ++ [JUMP_BACKWARD_NO_JIT] = _TAIL_CALL_JUMP_BACKWARD_NO_JIT, ++ [JUMP_FORWARD] = _TAIL_CALL_JUMP_FORWARD, ++ [LIST_APPEND] = _TAIL_CALL_LIST_APPEND, ++ [LIST_EXTEND] = _TAIL_CALL_LIST_EXTEND, ++ [LOAD_ATTR] = _TAIL_CALL_LOAD_ATTR, ++ [LOAD_ATTR_CLASS] = _TAIL_CALL_LOAD_ATTR_CLASS, ++ [LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = _TAIL_CALL_LOAD_ATTR_CLASS_WITH_METACLASS_CHECK, ++ [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = _TAIL_CALL_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, ++ [LOAD_ATTR_INSTANCE_VALUE] = _TAIL_CALL_LOAD_ATTR_INSTANCE_VALUE, ++ [LOAD_ATTR_METHOD_LAZY_DICT] = _TAIL_CALL_LOAD_ATTR_METHOD_LAZY_DICT, ++ [LOAD_ATTR_METHOD_NO_DICT] = _TAIL_CALL_LOAD_ATTR_METHOD_NO_DICT, ++ [LOAD_ATTR_METHOD_WITH_VALUES] = _TAIL_CALL_LOAD_ATTR_METHOD_WITH_VALUES, ++ [LOAD_ATTR_MODULE] = _TAIL_CALL_LOAD_ATTR_MODULE, ++ [LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = _TAIL_CALL_LOAD_ATTR_NONDESCRIPTOR_NO_DICT, ++ [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = _TAIL_CALL_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, ++ [LOAD_ATTR_PROPERTY] = _TAIL_CALL_LOAD_ATTR_PROPERTY, ++ [LOAD_ATTR_SLOT] = _TAIL_CALL_LOAD_ATTR_SLOT, ++ [LOAD_ATTR_WITH_HINT] = _TAIL_CALL_LOAD_ATTR_WITH_HINT, ++ [LOAD_BUILD_CLASS] = _TAIL_CALL_LOAD_BUILD_CLASS, ++ [LOAD_COMMON_CONSTANT] = _TAIL_CALL_LOAD_COMMON_CONSTANT, ++ [LOAD_CONST] = _TAIL_CALL_LOAD_CONST, ++ [LOAD_CONST_IMMORTAL] = _TAIL_CALL_LOAD_CONST_IMMORTAL, ++ [LOAD_CONST_MORTAL] = _TAIL_CALL_LOAD_CONST_MORTAL, ++ [LOAD_DEREF] = _TAIL_CALL_LOAD_DEREF, ++ [LOAD_FAST] = _TAIL_CALL_LOAD_FAST, ++ [LOAD_FAST_AND_CLEAR] = _TAIL_CALL_LOAD_FAST_AND_CLEAR, ++ [LOAD_FAST_CHECK] = _TAIL_CALL_LOAD_FAST_CHECK, ++ [LOAD_FAST_LOAD_FAST] = _TAIL_CALL_LOAD_FAST_LOAD_FAST, ++ [LOAD_FROM_DICT_OR_DEREF] = _TAIL_CALL_LOAD_FROM_DICT_OR_DEREF, ++ [LOAD_FROM_DICT_OR_GLOBALS] = _TAIL_CALL_LOAD_FROM_DICT_OR_GLOBALS, ++ [LOAD_GLOBAL] = _TAIL_CALL_LOAD_GLOBAL, ++ [LOAD_GLOBAL_BUILTIN] = _TAIL_CALL_LOAD_GLOBAL_BUILTIN, ++ [LOAD_GLOBAL_MODULE] = _TAIL_CALL_LOAD_GLOBAL_MODULE, ++ [LOAD_LOCALS] = _TAIL_CALL_LOAD_LOCALS, ++ [LOAD_NAME] = _TAIL_CALL_LOAD_NAME, ++ [LOAD_SMALL_INT] = _TAIL_CALL_LOAD_SMALL_INT, ++ [LOAD_SPECIAL] = _TAIL_CALL_LOAD_SPECIAL, ++ [LOAD_SUPER_ATTR] = _TAIL_CALL_LOAD_SUPER_ATTR, ++ [LOAD_SUPER_ATTR_ATTR] = _TAIL_CALL_LOAD_SUPER_ATTR_ATTR, ++ [LOAD_SUPER_ATTR_METHOD] = _TAIL_CALL_LOAD_SUPER_ATTR_METHOD, ++ [MAKE_CELL] = _TAIL_CALL_MAKE_CELL, ++ [MAKE_FUNCTION] = _TAIL_CALL_MAKE_FUNCTION, ++ [MAP_ADD] = _TAIL_CALL_MAP_ADD, ++ [MATCH_CLASS] = _TAIL_CALL_MATCH_CLASS, ++ [MATCH_KEYS] = _TAIL_CALL_MATCH_KEYS, ++ [MATCH_MAPPING] = _TAIL_CALL_MATCH_MAPPING, ++ [MATCH_SEQUENCE] = _TAIL_CALL_MATCH_SEQUENCE, ++ [NOP] = _TAIL_CALL_NOP, ++ [NOT_TAKEN] = _TAIL_CALL_NOT_TAKEN, ++ [POP_EXCEPT] = _TAIL_CALL_POP_EXCEPT, ++ [POP_ITER] = _TAIL_CALL_POP_ITER, ++ [POP_JUMP_IF_FALSE] = _TAIL_CALL_POP_JUMP_IF_FALSE, ++ [POP_JUMP_IF_NONE] = _TAIL_CALL_POP_JUMP_IF_NONE, ++ [POP_JUMP_IF_NOT_NONE] = _TAIL_CALL_POP_JUMP_IF_NOT_NONE, ++ [POP_JUMP_IF_TRUE] = _TAIL_CALL_POP_JUMP_IF_TRUE, ++ [POP_TOP] = _TAIL_CALL_POP_TOP, ++ [PUSH_EXC_INFO] = _TAIL_CALL_PUSH_EXC_INFO, ++ [PUSH_NULL] = _TAIL_CALL_PUSH_NULL, ++ [RAISE_VARARGS] = _TAIL_CALL_RAISE_VARARGS, ++ [RERAISE] = _TAIL_CALL_RERAISE, ++ [RESERVED] = _TAIL_CALL_RESERVED, ++ [RESUME] = _TAIL_CALL_RESUME, ++ [RESUME_CHECK] = _TAIL_CALL_RESUME_CHECK, ++ [RETURN_GENERATOR] = _TAIL_CALL_RETURN_GENERATOR, ++ [RETURN_VALUE] = _TAIL_CALL_RETURN_VALUE, ++ [SEND] = _TAIL_CALL_SEND, ++ [SEND_GEN] = _TAIL_CALL_SEND_GEN, ++ [SETUP_ANNOTATIONS] = _TAIL_CALL_SETUP_ANNOTATIONS, ++ [SET_ADD] = _TAIL_CALL_SET_ADD, ++ [SET_FUNCTION_ATTRIBUTE] = _TAIL_CALL_SET_FUNCTION_ATTRIBUTE, ++ [SET_UPDATE] = _TAIL_CALL_SET_UPDATE, ++ [STORE_ATTR] = _TAIL_CALL_STORE_ATTR, ++ [STORE_ATTR_INSTANCE_VALUE] = _TAIL_CALL_STORE_ATTR_INSTANCE_VALUE, ++ [STORE_ATTR_SLOT] = _TAIL_CALL_STORE_ATTR_SLOT, ++ [STORE_ATTR_WITH_HINT] = _TAIL_CALL_STORE_ATTR_WITH_HINT, ++ [STORE_DEREF] = _TAIL_CALL_STORE_DEREF, ++ [STORE_FAST] = _TAIL_CALL_STORE_FAST, ++ [STORE_FAST_LOAD_FAST] = _TAIL_CALL_STORE_FAST_LOAD_FAST, ++ [STORE_FAST_STORE_FAST] = _TAIL_CALL_STORE_FAST_STORE_FAST, ++ [STORE_GLOBAL] = _TAIL_CALL_STORE_GLOBAL, ++ [STORE_NAME] = _TAIL_CALL_STORE_NAME, ++ [STORE_SLICE] = _TAIL_CALL_STORE_SLICE, ++ [STORE_SUBSCR] = _TAIL_CALL_STORE_SUBSCR, ++ [STORE_SUBSCR_DICT] = _TAIL_CALL_STORE_SUBSCR_DICT, ++ [STORE_SUBSCR_LIST_INT] = _TAIL_CALL_STORE_SUBSCR_LIST_INT, ++ [SWAP] = _TAIL_CALL_SWAP, ++ [TO_BOOL] = _TAIL_CALL_TO_BOOL, ++ [TO_BOOL_ALWAYS_TRUE] = _TAIL_CALL_TO_BOOL_ALWAYS_TRUE, ++ [TO_BOOL_BOOL] = _TAIL_CALL_TO_BOOL_BOOL, ++ [TO_BOOL_INT] = _TAIL_CALL_TO_BOOL_INT, ++ [TO_BOOL_LIST] = _TAIL_CALL_TO_BOOL_LIST, ++ [TO_BOOL_NONE] = _TAIL_CALL_TO_BOOL_NONE, ++ [TO_BOOL_STR] = _TAIL_CALL_TO_BOOL_STR, ++ [UNARY_INVERT] = _TAIL_CALL_UNARY_INVERT, ++ [UNARY_NEGATIVE] = _TAIL_CALL_UNARY_NEGATIVE, ++ [UNARY_NOT] = _TAIL_CALL_UNARY_NOT, ++ [UNPACK_EX] = _TAIL_CALL_UNPACK_EX, ++ [UNPACK_SEQUENCE] = _TAIL_CALL_UNPACK_SEQUENCE, ++ [UNPACK_SEQUENCE_LIST] = _TAIL_CALL_UNPACK_SEQUENCE_LIST, ++ [UNPACK_SEQUENCE_TUPLE] = _TAIL_CALL_UNPACK_SEQUENCE_TUPLE, ++ [UNPACK_SEQUENCE_TWO_TUPLE] = _TAIL_CALL_UNPACK_SEQUENCE_TWO_TUPLE, ++ [WITH_EXCEPT_START] = _TAIL_CALL_WITH_EXCEPT_START, ++ [YIELD_VALUE] = _TAIL_CALL_YIELD_VALUE, ++ [117] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [118] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [119] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [120] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [121] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [122] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [123] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [124] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [125] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [126] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [127] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [128] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [129] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [130] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [131] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [132] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [133] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [134] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [135] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [136] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [137] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [138] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [139] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [140] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [141] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [142] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [143] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [144] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [145] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [146] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [147] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [148] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [232] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [233] = _TAIL_CALL_UNKNOWN_OPCODE, ++ [234] = _TAIL_CALL_UNKNOWN_OPCODE, ++}; ++#endif /* Py_TAIL_CALL_INTERP */ +diff --git a/Python/optimizer.c b/Python/optimizer.c +index 6a4d20fad76..bef5728349a 100644 +--- a/Python/optimizer.c ++++ b/Python/optimizer.c +@@ -91,72 +91,13 @@ + instr->op.arg = index; + } + +- +-static int +-never_optimize( +- _PyOptimizerObject* self, +- _PyInterpreterFrame *frame, +- _Py_CODEUNIT *instr, +- _PyExecutorObject **exec, +- int Py_UNUSED(stack_entries), +- bool Py_UNUSED(progress_needed)) +-{ +- // This may be called if the optimizer is reset +- return 0; +-} +- +-PyTypeObject _PyDefaultOptimizer_Type = { +- PyVarObject_HEAD_INIT(&PyType_Type, 0) +- .tp_name = "noop_optimizer", +- .tp_basicsize = sizeof(_PyOptimizerObject), +- .tp_itemsize = 0, +- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, +-}; +- +-static _PyOptimizerObject _PyOptimizer_Default = { +- PyObject_HEAD_INIT(&_PyDefaultOptimizer_Type) +- .optimize = never_optimize, +-}; +- +-_PyOptimizerObject * +-_Py_GetOptimizer(void) +-{ +- PyInterpreterState *interp = _PyInterpreterState_GET(); +- if (interp->optimizer == &_PyOptimizer_Default) { +- return NULL; +- } +- Py_INCREF(interp->optimizer); +- return interp->optimizer; +-} +- + static _PyExecutorObject * + make_executor_from_uops(_PyUOpInstruction *buffer, int length, const _PyBloomFilter *dependencies); + +-static const _PyBloomFilter EMPTY_FILTER = { 0 }; +- +-_PyOptimizerObject * +-_Py_SetOptimizer(PyInterpreterState *interp, _PyOptimizerObject *optimizer) +-{ +- if (optimizer == NULL) { +- optimizer = &_PyOptimizer_Default; +- } +- _PyOptimizerObject *old = interp->optimizer; +- if (old == NULL) { +- old = &_PyOptimizer_Default; +- } +- Py_INCREF(optimizer); +- interp->optimizer = optimizer; +- return old; +-} +- +-int +-_Py_SetTier2Optimizer(_PyOptimizerObject *optimizer) +-{ +- PyInterpreterState *interp = _PyInterpreterState_GET(); +- _PyOptimizerObject *old = _Py_SetOptimizer(interp, optimizer); +- Py_XDECREF(old); +- return old == NULL ? -1 : 0; +-} ++static int ++uop_optimize(_PyInterpreterFrame *frame, _Py_CODEUNIT *instr, ++ _PyExecutorObject **exec_ptr, int curr_stackentries, ++ bool progress_needed); + + /* Returns 1 if optimized, 0 if not optimized, and -1 for an error. + * If optimized, *executor_ptr contains a new reference to the executor +@@ -164,8 +105,10 @@ + int + _PyOptimizer_Optimize( + _PyInterpreterFrame *frame, _Py_CODEUNIT *start, +- _PyStackRef *stack_pointer, _PyExecutorObject **executor_ptr, int chain_depth) ++ _PyExecutorObject **executor_ptr, int chain_depth) + { ++ _PyStackRef *stack_pointer = frame->stackpointer; ++ assert(_PyInterpreterState_GET()->jit); + // The first executor in a chain and the MAX_CHAIN_DEPTH'th executor *must* + // make progress in order to avoid infinite loops or excessively-long + // side-exit chains. We can only insert the executor into the bytecode if +@@ -174,12 +117,10 @@ + bool progress_needed = chain_depth == 0; + PyCodeObject *code = _PyFrame_GetCode(frame); + assert(PyCode_Check(code)); +- PyInterpreterState *interp = _PyInterpreterState_GET(); + if (progress_needed && !has_space_for_executor(code, start)) { + return 0; + } +- _PyOptimizerObject *opt = interp->optimizer; +- int err = opt->optimize(opt, frame, start, executor_ptr, (int)(stack_pointer - _PyFrame_Stackbase(frame)), progress_needed); ++ int err = uop_optimize(frame, start, executor_ptr, (int)(stack_pointer - _PyFrame_Stackbase(frame)), progress_needed); + if (err <= 0) { + return err; + } +@@ -251,13 +192,6 @@ + return PyLong_FromUnsignedLong(((_PyExecutorObject *)self)->vm_data.oparg); + } + +-static PyMethodDef executor_methods[] = { +- { "is_valid", is_valid, METH_NOARGS, NULL }, +- { "get_opcode", get_opcode, METH_NOARGS, NULL }, +- { "get_oparg", get_oparg, METH_NOARGS, NULL }, +- { NULL, NULL }, +-}; +- + ///////////////////// Experimental UOp Optimizer ///////////////////// + + static int executor_clear(_PyExecutorObject *executor); +@@ -622,8 +556,14 @@ + goto done; + } + assert(opcode != ENTER_EXECUTOR && opcode != EXTENDED_ARG); +- RESERVE_RAW(2, "_CHECK_VALIDITY_AND_SET_IP"); +- ADD_TO_TRACE(_CHECK_VALIDITY_AND_SET_IP, 0, (uintptr_t)instr, target); ++ if (OPCODE_HAS_NO_SAVE_IP(opcode)) { ++ RESERVE_RAW(2, "_CHECK_VALIDITY"); ++ ADD_TO_TRACE(_CHECK_VALIDITY, 0, 0, target); ++ } ++ else { ++ RESERVE_RAW(2, "_CHECK_VALIDITY_AND_SET_IP"); ++ ADD_TO_TRACE(_CHECK_VALIDITY_AND_SET_IP, 0, (uintptr_t)instr, target); ++ } + + /* Special case the first instruction, + * so that we can guarantee forward progress */ +@@ -687,6 +627,7 @@ + } + + case JUMP_BACKWARD: ++ case JUMP_BACKWARD_JIT: + ADD_TO_TRACE(_CHECK_PERIODIC, 0, 0, target); + _Py_FALLTHROUGH; + case JUMP_BACKWARD_NO_INTERRUPT: +@@ -771,7 +712,7 @@ + uint32_t next_inst = target + 1 + INLINE_CACHE_ENTRIES_FOR_ITER + (oparg > 255); + uint32_t jump_target = next_inst + oparg; + assert(_Py_GetBaseCodeUnit(code, jump_target).op.code == END_FOR); +- assert(_Py_GetBaseCodeUnit(code, jump_target+1).op.code == POP_TOP); ++ assert(_Py_GetBaseCodeUnit(code, jump_target+1).op.code == POP_ITER); + } + #endif + break; +@@ -812,13 +753,12 @@ + assert(i + 1 == nuops); + if (opcode == FOR_ITER_GEN || + opcode == LOAD_ATTR_PROPERTY || +- opcode == BINARY_SUBSCR_GETITEM || ++ opcode == BINARY_OP_SUBSCR_GETITEM || + opcode == SEND_GEN) + { + DPRINTF(2, "Bailing due to dynamic target\n"); +- ADD_TO_TRACE(uop, oparg, 0, target); +- ADD_TO_TRACE(_DYNAMIC_EXIT, 0, 0, 0); +- goto done; ++ OPT_STAT_INC(unknown_callee); ++ return 0; + } + assert(_PyOpcode_Deopt[opcode] == CALL || _PyOpcode_Deopt[opcode] == CALL_KW); + int func_version_offset = +@@ -884,9 +824,8 @@ + goto top; + } + DPRINTF(2, "Bail, new_code == NULL\n"); +- ADD_TO_TRACE(uop, oparg, 0, target); +- ADD_TO_TRACE(_DYNAMIC_EXIT, 0, 0, 0); +- goto done; ++ OPT_STAT_INC(unknown_callee); ++ return 0; + } + + if (uop == _BINARY_OP_INPLACE_ADD_UNICODE) { +@@ -973,7 +912,7 @@ + int exit_count = 0; + for (int i = 0; i < length; i++) { + int opcode = buffer[i].opcode; +- if (opcode == _EXIT_TRACE || opcode == _DYNAMIC_EXIT) { ++ if (opcode == _EXIT_TRACE) { + exit_count++; + } + } +@@ -1049,7 +988,6 @@ + current_error = next_spare; + current_error_target = target; + make_exit(&buffer[next_spare], _ERROR_POP_N, 0); +- buffer[next_spare].oparg = popped; + buffer[next_spare].operand0 = target; + next_spare++; + } +@@ -1179,12 +1117,6 @@ + dest->operand0 = (uint64_t)exit; + next_exit--; + } +- if (opcode == _DYNAMIC_EXIT) { +- _PyExitData *exit = &executor->exits[next_exit]; +- exit->target = 0; +- dest->operand0 = (uint64_t)exit; +- next_exit--; +- } + } + assert(next_exit == -1); + assert(dest == executor->trace); +@@ -1244,7 +1176,6 @@ + + static int + uop_optimize( +- _PyOptimizerObject *self, + _PyInterpreterFrame *frame, + _Py_CODEUNIT *instr, + _PyExecutorObject **exec_ptr, +@@ -1279,15 +1210,16 @@ + int oparg = buffer[pc].oparg; + if (_PyUop_Flags[opcode] & HAS_OPARG_AND_1_FLAG) { + buffer[pc].opcode = opcode + 1 + (oparg & 1); ++ assert(strncmp(_PyOpcode_uop_name[buffer[pc].opcode], _PyOpcode_uop_name[opcode], strlen(_PyOpcode_uop_name[opcode])) == 0); + } + else if (oparg < _PyUop_Replication[opcode]) { + buffer[pc].opcode = opcode + oparg + 1; ++ assert(strncmp(_PyOpcode_uop_name[buffer[pc].opcode], _PyOpcode_uop_name[opcode], strlen(_PyOpcode_uop_name[opcode])) == 0); + } + else if (is_terminator(&buffer[pc])) { + break; + } + assert(_PyOpcode_uop_name[buffer[pc].opcode]); +- assert(strncmp(_PyOpcode_uop_name[buffer[pc].opcode], _PyOpcode_uop_name[opcode], strlen(_PyOpcode_uop_name[opcode])) == 0); + } + OPT_HIST(effective_trace_length(buffer, length), optimized_trace_length_hist); + length = prepare_for_execution(buffer, length); +@@ -1301,121 +1233,6 @@ + return 1; + } + +-static void +-uop_opt_dealloc(PyObject *self) { +- PyObject_Free(self); +-} +- +-PyTypeObject _PyUOpOptimizer_Type = { +- PyVarObject_HEAD_INIT(&PyType_Type, 0) +- .tp_name = "uop_optimizer", +- .tp_basicsize = sizeof(_PyOptimizerObject), +- .tp_itemsize = 0, +- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, +- .tp_dealloc = uop_opt_dealloc, +-}; +- +-PyObject * +-_PyOptimizer_NewUOpOptimizer(void) +-{ +- _PyOptimizerObject *opt = PyObject_New(_PyOptimizerObject, &_PyUOpOptimizer_Type); +- if (opt == NULL) { +- return NULL; +- } +- opt->optimize = uop_optimize; +- return (PyObject *)opt; +-} +- +-static void +-counter_dealloc(_PyExecutorObject *self) { +- /* The optimizer is the operand of the second uop. */ +- PyObject *opt = (PyObject *)self->trace[1].operand0; +- Py_DECREF(opt); +- uop_dealloc(self); +-} +- +-PyTypeObject _PyCounterExecutor_Type = { +- PyVarObject_HEAD_INIT(&PyType_Type, 0) +- .tp_name = "counting_executor", +- .tp_basicsize = offsetof(_PyExecutorObject, exits), +- .tp_itemsize = 1, +- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION | Py_TPFLAGS_HAVE_GC, +- .tp_dealloc = (destructor)counter_dealloc, +- .tp_methods = executor_methods, +- .tp_traverse = executor_traverse, +- .tp_clear = (inquiry)executor_clear, +-}; +- +-static int +-counter_optimize( +- _PyOptimizerObject* self, +- _PyInterpreterFrame *frame, +- _Py_CODEUNIT *instr, +- _PyExecutorObject **exec_ptr, +- int Py_UNUSED(curr_stackentries), +- bool Py_UNUSED(progress_needed) +-) +-{ +- PyCodeObject *code = _PyFrame_GetCode(frame); +- int oparg = instr->op.arg; +- while (instr->op.code == EXTENDED_ARG) { +- instr++; +- oparg = (oparg << 8) | instr->op.arg; +- } +- if (instr->op.code != JUMP_BACKWARD) { +- /* Counter optimizer can only handle backward edges */ +- return 0; +- } +- _Py_CODEUNIT *target = instr + 1 + _PyOpcode_Caches[JUMP_BACKWARD] - oparg; +- _PyUOpInstruction buffer[4] = { +- { .opcode = _START_EXECUTOR, .jump_target = 3, .format=UOP_FORMAT_JUMP }, +- { .opcode = _LOAD_CONST_INLINE, .operand0 = (uintptr_t)self }, +- { .opcode = _INTERNAL_INCREMENT_OPT_COUNTER }, +- { .opcode = _EXIT_TRACE, .target = (uint32_t)(target - _PyCode_CODE(code)), .format=UOP_FORMAT_TARGET } +- }; +- _PyExecutorObject *executor = make_executor_from_uops(buffer, 4, &EMPTY_FILTER); +- if (executor == NULL) { +- return -1; +- } +- Py_INCREF(self); +- Py_SET_TYPE(executor, &_PyCounterExecutor_Type); +- *exec_ptr = executor; +- return 1; +-} +- +-static PyObject * +-counter_get_counter(PyObject *self, PyObject *args) +-{ +- return PyLong_FromLongLong(((_PyCounterOptimizerObject *)self)->count); +-} +- +-static PyMethodDef counter_optimizer_methods[] = { +- { "get_count", counter_get_counter, METH_NOARGS, NULL }, +- { NULL, NULL }, +-}; +- +-PyTypeObject _PyCounterOptimizer_Type = { +- PyVarObject_HEAD_INIT(&PyType_Type, 0) +- .tp_name = "Counter optimizer", +- .tp_basicsize = sizeof(_PyCounterOptimizerObject), +- .tp_itemsize = 0, +- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, +- .tp_methods = counter_optimizer_methods, +- .tp_dealloc = (destructor)PyObject_Free, +-}; +- +-PyObject * +-_PyOptimizer_NewCounter(void) +-{ +- _PyCounterOptimizerObject *opt = (_PyCounterOptimizerObject *)_PyObject_New(&_PyCounterOptimizer_Type); +- if (opt == NULL) { +- return NULL; +- } +- opt->base.optimize = counter_optimize; +- opt->count = 0; +- return (PyObject *)opt; +-} +- + + /***************************************** + * Executor management +diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c +index 0ef15c630e9..6c0aadb87e6 100644 +--- a/Python/optimizer_analysis.c ++++ b/Python/optimizer_analysis.c +@@ -109,10 +109,14 @@ + return NULL; + } + if (_Py_IsImmortal(res)) { +- inst->opcode = (inst->oparg & 1) ? _LOAD_CONST_INLINE_BORROW_WITH_NULL : _LOAD_CONST_INLINE_BORROW; ++ inst->opcode = _LOAD_CONST_INLINE_BORROW; + } + else { +- inst->opcode = (inst->oparg & 1) ? _LOAD_CONST_INLINE_WITH_NULL : _LOAD_CONST_INLINE; ++ inst->opcode = _LOAD_CONST_INLINE; ++ } ++ if (inst->oparg & 1) { ++ assert(inst[1].opcode == _PUSH_NULL_CONDITIONAL); ++ assert(inst[1].oparg & 1); + } + inst->operand0 = (uint64_t)res; + return res; +@@ -368,13 +372,17 @@ + #define sym_truthiness _Py_uop_sym_truthiness + #define frame_new _Py_uop_frame_new + #define frame_pop _Py_uop_frame_pop ++#define sym_new_tuple _Py_uop_sym_new_tuple ++#define sym_tuple_getitem _Py_uop_sym_tuple_getitem ++#define sym_tuple_length _Py_uop_sym_tuple_length ++#define sym_is_immortal _Py_uop_sym_is_immortal + + static int + optimize_to_bool( + _PyUOpInstruction *this_instr, +- _Py_UOpsContext *ctx, +- _Py_UopsSymbol *value, +- _Py_UopsSymbol **result_ptr) ++ JitOptContext *ctx, ++ JitOptSymbol *value, ++ JitOptSymbol **result_ptr) + { + if (sym_matches_type(value, &PyBool_Type)) { + REPLACE_OP(this_instr, _NOP, 0, 0); +@@ -460,8 +468,8 @@ + ) + { + +- _Py_UOpsContext context; +- _Py_UOpsContext *ctx = &context; ++ JitOptContext context; ++ JitOptContext *ctx = &context; + uint32_t opcode = UINT16_MAX; + int curr_space = 0; + int max_space = 0; +@@ -486,7 +494,7 @@ + + int oparg = this_instr->oparg; + opcode = this_instr->opcode; +- _Py_UopsSymbol **stack_pointer = ctx->frame->stack_pointer; ++ JitOptSymbol **stack_pointer = ctx->frame->stack_pointer; + + #ifdef Py_DEBUG + if (get_lltrace() >= 3) { +@@ -608,7 +616,6 @@ + } + case _JUMP_TO_TOP: + case _EXIT_TRACE: +- case _DYNAMIC_EXIT: + return pc + 1; + default: + { +diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c +index 0b8aff02367..41eb59c931a 100644 +--- a/Python/optimizer_bytecodes.c ++++ b/Python/optimizer_bytecodes.c +@@ -6,8 +6,6 @@ + + #define op(name, ...) /* NAME is ignored */ + +-typedef struct _Py_UopsSymbol _Py_UopsSymbol; +-typedef struct _Py_UOpsContext _Py_UOpsContext; + typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame; + + /* Shortened forms for convenience */ +@@ -32,13 +30,17 @@ + #define sym_is_bottom _Py_uop_sym_is_bottom + #define frame_new _Py_uop_frame_new + #define frame_pop _Py_uop_frame_pop ++#define sym_new_tuple _Py_uop_sym_new_tuple ++#define sym_tuple_getitem _Py_uop_sym_tuple_getitem ++#define sym_tuple_length _Py_uop_sym_tuple_length ++#define sym_is_immortal _Py_uop_sym_is_immortal + + extern int + optimize_to_bool( + _PyUOpInstruction *this_instr, +- _Py_UOpsContext *ctx, +- _Py_UopsSymbol *value, +- _Py_UopsSymbol **result_ptr); ++ JitOptContext *ctx, ++ JitOptSymbol *value, ++ JitOptSymbol **result_ptr); + + extern void + eliminate_pop_guard(_PyUOpInstruction *this_instr, bool exit); +@@ -50,17 +52,17 @@ + + PyCodeObject *co; + int oparg; +- _Py_UopsSymbol *flag; +- _Py_UopsSymbol *left; +- _Py_UopsSymbol *right; +- _Py_UopsSymbol *value; +- _Py_UopsSymbol *res; +- _Py_UopsSymbol *iter; +- _Py_UopsSymbol *top; +- _Py_UopsSymbol *bottom; ++ JitOptSymbol *flag; ++ JitOptSymbol *left; ++ JitOptSymbol *right; ++ JitOptSymbol *value; ++ JitOptSymbol *res; ++ JitOptSymbol *iter; ++ JitOptSymbol *top; ++ JitOptSymbol *bottom; + _Py_UOpsAbstractFrame *frame; + _Py_UOpsAbstractFrame *new_frame; +- _Py_UOpsContext *ctx; ++ JitOptContext *ctx; + _PyUOpInstruction *this_instr; + _PyBloomFilter *dependencies; + int modified; +@@ -85,7 +87,7 @@ + + op(_LOAD_FAST_AND_CLEAR, (-- value)) { + value = GETLOCAL(oparg); +- _Py_UopsSymbol *temp = sym_new_null(ctx); ++ JitOptSymbol *temp = sym_new_null(ctx); + GETLOCAL(oparg) = temp; + } + +@@ -167,23 +169,56 @@ + } + + op(_BINARY_OP, (left, right -- res)) { +- PyTypeObject *ltype = sym_get_type(left); +- PyTypeObject *rtype = sym_get_type(right); +- if (ltype != NULL && (ltype == &PyLong_Type || ltype == &PyFloat_Type) && +- rtype != NULL && (rtype == &PyLong_Type || rtype == &PyFloat_Type)) +- { +- if (oparg != NB_TRUE_DIVIDE && oparg != NB_INPLACE_TRUE_DIVIDE && +- ltype == &PyLong_Type && rtype == &PyLong_Type) { +- /* If both inputs are ints and the op is not division the result is an int */ +- res = sym_new_type(ctx, &PyLong_Type); ++ bool lhs_int = sym_matches_type(left, &PyLong_Type); ++ bool rhs_int = sym_matches_type(right, &PyLong_Type); ++ bool lhs_float = sym_matches_type(left, &PyFloat_Type); ++ bool rhs_float = sym_matches_type(right, &PyFloat_Type); ++ if (!((lhs_int || lhs_float) && (rhs_int || rhs_float))) { ++ // There's something other than an int or float involved: ++ res = sym_new_unknown(ctx); ++ } ++ else if (oparg == NB_POWER || oparg == NB_INPLACE_POWER) { ++ // This one's fun... the *type* of the result depends on the ++ // *values* being exponentiated. However, exponents with one ++ // constant part are reasonably common, so it's probably worth ++ // trying to infer some simple cases: ++ // - A: 1 ** 1 -> 1 (int ** int -> int) ++ // - B: 1 ** -1 -> 1.0 (int ** int -> float) ++ // - C: 1.0 ** 1 -> 1.0 (float ** int -> float) ++ // - D: 1 ** 1.0 -> 1.0 (int ** float -> float) ++ // - E: -1 ** 0.5 ~> 1j (int ** float -> complex) ++ // - F: 1.0 ** 1.0 -> 1.0 (float ** float -> float) ++ // - G: -1.0 ** 0.5 ~> 1j (float ** float -> complex) ++ if (rhs_float) { ++ // Case D, E, F, or G... can't know without the sign of the LHS ++ // or whether the RHS is whole, which isn't worth the effort: ++ res = sym_new_unknown(ctx); + } +- else { +- /* For any other op combining ints/floats the result is a float */ ++ else if (lhs_float) { ++ // Case C: ++ res = sym_new_type(ctx, &PyFloat_Type); ++ } ++ else if (!sym_is_const(right)) { ++ // Case A or B... can't know without the sign of the RHS: ++ res = sym_new_unknown(ctx); ++ } ++ else if (_PyLong_IsNegative((PyLongObject *)sym_get_const(right))) { ++ // Case B: + res = sym_new_type(ctx, &PyFloat_Type); + } ++ else { ++ // Case A: ++ res = sym_new_type(ctx, &PyLong_Type); ++ } ++ } ++ else if (oparg == NB_TRUE_DIVIDE || oparg == NB_INPLACE_TRUE_DIVIDE) { ++ res = sym_new_type(ctx, &PyFloat_Type); ++ } ++ else if (lhs_int && rhs_int) { ++ res = sym_new_type(ctx, &PyLong_Type); + } + else { +- res = sym_new_unknown(ctx); ++ res = sym_new_type(ctx, &PyFloat_Type); + } + } + +@@ -332,7 +367,7 @@ + } + + op(_BINARY_OP_INPLACE_ADD_UNICODE, (left, right -- )) { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + if (sym_is_const(left) && sym_is_const(right) && + sym_matches_type(left, &PyUnicode_Type) && sym_matches_type(right, &PyUnicode_Type)) { + PyObject *temp = PyUnicode_Concat(sym_get_const(left), sym_get_const(right)); +@@ -349,9 +384,7 @@ + GETLOCAL(this_instr->operand0) = res; + } + +- op(_BINARY_SUBSCR_INIT_CALL, (container, sub -- new_frame: _Py_UOpsAbstractFrame *)) { +- (void)container; +- (void)sub; ++ op(_BINARY_OP_SUBSCR_INIT_CALL, (container, sub, getitem -- new_frame: _Py_UOpsAbstractFrame *)) { + new_frame = NULL; + ctx->done = true; + } +@@ -398,8 +431,6 @@ + } + + op(_COMPARE_OP, (left, right -- res)) { +- (void)left; +- (void)right; + if (oparg & 16) { + res = sym_new_type(ctx, &PyBool_Type); + } +@@ -409,32 +440,22 @@ + } + + op(_COMPARE_OP_INT, (left, right -- res)) { +- (void)left; +- (void)right; + res = sym_new_type(ctx, &PyBool_Type); + } + + op(_COMPARE_OP_FLOAT, (left, right -- res)) { +- (void)left; +- (void)right; + res = sym_new_type(ctx, &PyBool_Type); + } + + op(_COMPARE_OP_STR, (left, right -- res)) { +- (void)left; +- (void)right; + res = sym_new_type(ctx, &PyBool_Type); + } + + op(_IS_OP, (left, right -- res)) { +- (void)left; +- (void)right; + res = sym_new_type(ctx, &PyBool_Type); + } + + op(_CONTAINS_OP, (left, right -- res)) { +- (void)left; +- (void)right; + res = sym_new_type(ctx, &PyBool_Type); + } + +@@ -445,6 +466,13 @@ + value = sym_new_const(ctx, val); + } + ++ op(_LOAD_CONST_MORTAL, (-- value)) { ++ PyObject *val = PyTuple_GET_ITEM(co->co_consts, this_instr->oparg); ++ int opcode = _Py_IsImmortal(val) ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE; ++ REPLACE_OP(this_instr, opcode, 0, (uintptr_t)val); ++ value = sym_new_const(ctx, val); ++ } ++ + op(_LOAD_CONST_IMMORTAL, (-- value)) { + PyObject *val = PyTuple_GET_ITEM(co->co_consts, this_instr->oparg); + REPLACE_OP(this_instr, _LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val); +@@ -464,32 +492,21 @@ + value = sym_new_const(ctx, ptr); + } + +- op(_LOAD_CONST_INLINE_WITH_NULL, (ptr/4 -- value, null)) { +- value = sym_new_const(ctx, ptr); +- null = sym_new_null(ctx); +- } +- +- op(_LOAD_CONST_INLINE_BORROW_WITH_NULL, (ptr/4 -- value, null)) { +- value = sym_new_const(ctx, ptr); +- null = sym_new_null(ctx); +- } +- + op(_COPY, (bottom, unused[oparg-1] -- bottom, unused[oparg-1], top)) { + assert(oparg > 0); + top = bottom; + } + +- op(_SWAP, (bottom_in, unused[oparg-2], top_in -- +- top_out, unused[oparg-2], bottom_out)) { +- bottom_out = bottom_in; +- top_out = top_in; ++ op(_SWAP, (bottom[1], unused[oparg-2], top[1] -- bottom[1], unused[oparg-2], top[1])) { ++ JitOptSymbol *temp = bottom[0]; ++ bottom[0] = top[0]; ++ top[0] = temp; ++ assert(oparg >= 2); + } + +- op(_LOAD_ATTR_INSTANCE_VALUE, (offset/1, owner -- attr, null if (oparg & 1))) { ++ op(_LOAD_ATTR_INSTANCE_VALUE, (offset/1, owner -- attr)) { + attr = sym_new_not_null(ctx); +- null = sym_new_null(ctx); + (void)offset; +- (void)owner; + } + + op(_CHECK_ATTR_MODULE_PUSH_KEYS, (dict_version/2, owner -- owner, mod_keys)) { +@@ -510,15 +527,22 @@ + } + } + +- op(_LOAD_ATTR, (owner -- attr, self_or_null if (oparg & 1))) { ++ op (_PUSH_NULL_CONDITIONAL, ( -- null if (oparg & 1))) { ++ int opcode = (oparg & 1) ? _PUSH_NULL : _NOP; ++ REPLACE_OP(this_instr, opcode, 0, 0); ++ null = sym_new_null(ctx); ++ } ++ ++ op(_LOAD_ATTR, (owner -- attr, self_or_null[oparg&1])) { + (void)owner; + attr = sym_new_not_null(ctx); +- self_or_null = sym_new_unknown(ctx); ++ if (oparg &1) { ++ self_or_null[0] = sym_new_unknown(ctx); ++ } + } + +- op(_LOAD_ATTR_MODULE_FROM_KEYS, (index/1, owner, mod_keys -- attr, null if (oparg & 1))) { ++ op(_LOAD_ATTR_MODULE_FROM_KEYS, (index/1, owner, mod_keys -- attr)) { + (void)index; +- null = sym_new_null(ctx); + attr = NULL; + if (this_instr[-1].opcode == _NOP) { + // Preceding _CHECK_ATTR_MODULE_PUSH_KEYS was removed: mod is const and dict is watched. +@@ -541,40 +565,38 @@ + } + } + +- op(_LOAD_ATTR_WITH_HINT, (hint/1, owner -- attr, null if (oparg & 1))) { ++ op(_CHECK_ATTR_WITH_HINT, (owner -- owner, dict)) { ++ dict = sym_new_not_null(ctx); ++ } ++ ++ op(_LOAD_ATTR_WITH_HINT, (hint/1, owner, dict -- attr)) { + attr = sym_new_not_null(ctx); +- null = sym_new_null(ctx); + (void)hint; +- (void)owner; + } + +- op(_LOAD_ATTR_SLOT, (index/1, owner -- attr, null if (oparg & 1))) { ++ op(_LOAD_ATTR_SLOT, (index/1, owner -- attr)) { + attr = sym_new_not_null(ctx); +- null = sym_new_null(ctx); + (void)index; +- (void)owner; + } + +- op(_LOAD_ATTR_CLASS, (descr/4, owner -- attr, null if (oparg & 1))) { ++ op(_LOAD_ATTR_CLASS, (descr/4, owner -- attr)) { + attr = sym_new_not_null(ctx); +- null = sym_new_null(ctx); + (void)descr; +- (void)owner; + } + +- op(_LOAD_ATTR_METHOD_WITH_VALUES, (descr/4, owner -- attr, self if (1))) { ++ op(_LOAD_ATTR_METHOD_WITH_VALUES, (descr/4, owner -- attr, self)) { + (void)descr; + attr = sym_new_not_null(ctx); + self = owner; + } + +- op(_LOAD_ATTR_METHOD_NO_DICT, (descr/4, owner -- attr, self if (1))) { ++ op(_LOAD_ATTR_METHOD_NO_DICT, (descr/4, owner -- attr, self)) { + (void)descr; + attr = sym_new_not_null(ctx); + self = owner; + } + +- op(_LOAD_ATTR_METHOD_LAZY_DICT, (descr/4, owner -- attr, self if (1))) { ++ op(_LOAD_ATTR_METHOD_LAZY_DICT, (descr/4, owner -- attr, self)) { + (void)descr; + attr = sym_new_not_null(ctx); + self = owner; +@@ -582,19 +604,16 @@ + + op(_LOAD_ATTR_PROPERTY_FRAME, (fget/4, owner -- new_frame: _Py_UOpsAbstractFrame *)) { + (void)fget; +- (void)owner; + new_frame = NULL; + ctx->done = true; + } + +- op(_INIT_CALL_BOUND_METHOD_EXACT_ARGS, (callable, unused, unused[oparg] -- func, self, unused[oparg])) { +- (void)callable; +- func = sym_new_not_null(ctx); +- self = sym_new_not_null(ctx); ++ op(_INIT_CALL_BOUND_METHOD_EXACT_ARGS, (callable[1], self_or_null[1], unused[oparg] -- callable[1], self_or_null[1], unused[oparg])) { ++ callable[0] = sym_new_not_null(ctx); ++ self_or_null[0] = sym_new_not_null(ctx); + } + + op(_CHECK_FUNCTION_VERSION, (func_version/2, callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) { +- (void)self_or_null; + if (sym_is_const(callable) && sym_matches_type(callable, &PyFunction_Type)) { + assert(PyFunction_Check(sym_get_const(callable))); + REPLACE_OP(this_instr, _CHECK_FUNCTION_VERSION_INLINE, 0, func_version); +@@ -614,7 +633,6 @@ + } + } + } +- (void)self_or_null; + } + + op(_CHECK_CALL_BOUND_METHOD_EXACT_ARGS, (callable, null, unused[oparg] -- callable, null, unused[oparg])) { +@@ -624,7 +642,6 @@ + + op(_INIT_CALL_PY_EXACT_ARGS, (callable, self_or_null, args[oparg] -- new_frame: _Py_UOpsAbstractFrame *)) { + int argcount = oparg; +- (void)callable; + + PyCodeObject *co = NULL; + assert((this_instr + 2)->opcode == _PUSH_FRAME); +@@ -652,16 +669,12 @@ + } + + op(_MAYBE_EXPAND_METHOD, (callable, self_or_null, args[oparg] -- func, maybe_self, args[oparg])) { +- (void)callable; +- (void)self_or_null; + (void)args; + func = sym_new_not_null(ctx); + maybe_self = sym_new_not_null(ctx); + } + + op(_PY_FRAME_GENERAL, (callable, self_or_null, args[oparg] -- new_frame: _Py_UOpsAbstractFrame *)) { +- (void)(self_or_null); +- (void)(callable); + PyCodeObject *co = NULL; + assert((this_instr + 2)->opcode == _PUSH_FRAME); + co = get_code_with_logging((this_instr + 2)); +@@ -674,27 +687,18 @@ + } + + op(_PY_FRAME_KW, (callable, self_or_null, args[oparg], kwnames -- new_frame: _Py_UOpsAbstractFrame *)) { +- (void)callable; +- (void)self_or_null; +- (void)args; +- (void)kwnames; + new_frame = NULL; + ctx->done = true; + } + + op(_CHECK_AND_ALLOCATE_OBJECT, (type_version/2, callable, null, args[oparg] -- self, init, args[oparg])) { + (void)type_version; +- (void)callable; +- (void)null; + (void)args; + self = sym_new_not_null(ctx); + init = sym_new_not_null(ctx); + } + + op(_CREATE_INIT_FRAME, (self, init, args[oparg] -- init_frame: _Py_UOpsAbstractFrame *)) { +- (void)self; +- (void)init; +- (void)args; + init_frame = NULL; + ctx->done = true; + } +@@ -763,7 +767,7 @@ + corresponding_check_stack = this_instr; + } + +- op (_CHECK_STACK_SPACE_OPERAND, ( -- )) { ++ op (_CHECK_STACK_SPACE_OPERAND, (framesize/2 -- )) { + (void)framesize; + /* We should never see _CHECK_STACK_SPACE_OPERANDs. + * They are only created at the end of this pass. */ +@@ -805,7 +809,6 @@ + + op(_UNPACK_SEQUENCE, (seq -- values[oparg])) { + /* This has to be done manually */ +- (void)seq; + for (int i = 0; i < oparg; i++) { + values[i] = sym_new_unknown(ctx); + } +@@ -813,7 +816,6 @@ + + op(_UNPACK_EX, (seq -- values[oparg & 0xFF], unused, unused[oparg >> 8])) { + /* This has to be done manually */ +- (void)seq; + int totalargs = (oparg & 0xFF) + (oparg >> 8) + 1; + for (int i = 0; i < totalargs; i++) { + values[i] = sym_new_unknown(ctx); +@@ -822,7 +824,6 @@ + + op(_ITER_NEXT_RANGE, (iter -- iter, next)) { + next = sym_new_type(ctx, &PyLong_Type); +- (void)iter; + } + + op(_GUARD_IS_TRUE_POP, (flag -- )) { +@@ -874,7 +875,6 @@ + } + + op(_LOAD_SPECIAL, (owner -- attr, self_or_null)) { +- (void)owner; + attr = sym_new_not_null(ctx); + self_or_null = sym_new_unknown(ctx); + } +@@ -898,6 +898,26 @@ + (void)version; + } + ++ op(_REPLACE_WITH_TRUE, (value -- res)) { ++ res = sym_new_const(ctx, Py_True); ++ } ++ ++ op(_BUILD_TUPLE, (values[oparg] -- tup)) { ++ tup = sym_new_tuple(ctx, oparg, values); ++ } ++ ++ op(_UNPACK_SEQUENCE_TWO_TUPLE, (seq -- val1, val0)) { ++ val0 = sym_tuple_getitem(ctx, seq, 0); ++ val1 = sym_tuple_getitem(ctx, seq, 1); ++ } ++ ++ op(_UNPACK_SEQUENCE_TUPLE, (seq -- values[oparg])) { ++ for (int i = 0; i < oparg; i++) { ++ values[i] = sym_tuple_getitem(ctx, seq, i); ++ } ++ } ++ ++ + // END BYTECODES // + + } +diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h +index f4fbe8c8aa0..fd8486785ed 100644 +--- a/Python/optimizer_cases.c.h ++++ b/Python/optimizer_cases.c.h +@@ -26,7 +26,7 @@ + /* _MONITOR_RESUME is not a viable micro-op for tier 2 */ + + case _LOAD_FAST_CHECK: { +- _Py_UopsSymbol *value; ++ JitOptSymbol *value; + value = GETLOCAL(oparg); + // We guarantee this will error - just bail and don't optimize it. + if (sym_is_null(value)) { +@@ -39,7 +39,7 @@ + } + + case _LOAD_FAST: { +- _Py_UopsSymbol *value; ++ JitOptSymbol *value; + value = GETLOCAL(oparg); + stack_pointer[0] = value; + stack_pointer += 1; +@@ -48,9 +48,9 @@ + } + + case _LOAD_FAST_AND_CLEAR: { +- _Py_UopsSymbol *value; ++ JitOptSymbol *value; + value = GETLOCAL(oparg); +- _Py_UopsSymbol *temp = sym_new_null(ctx); ++ JitOptSymbol *temp = sym_new_null(ctx); + GETLOCAL(oparg) = temp; + stack_pointer[0] = value; + stack_pointer += 1; +@@ -58,8 +58,10 @@ + break; + } + +- case _LOAD_CONST: { +- _Py_UopsSymbol *value; ++ /* _LOAD_CONST is not a viable micro-op for tier 2 */ ++ ++ case _LOAD_CONST_MORTAL: { ++ JitOptSymbol *value; + PyObject *val = PyTuple_GET_ITEM(co->co_consts, this_instr->oparg); + int opcode = _Py_IsImmortal(val) ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE; + REPLACE_OP(this_instr, opcode, 0, (uintptr_t)val); +@@ -71,7 +73,7 @@ + } + + case _LOAD_CONST_IMMORTAL: { +- _Py_UopsSymbol *value; ++ JitOptSymbol *value; + PyObject *val = PyTuple_GET_ITEM(co->co_consts, this_instr->oparg); + REPLACE_OP(this_instr, _LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val); + value = sym_new_const(ctx, val); +@@ -82,7 +84,7 @@ + } + + case _LOAD_SMALL_INT: { +- _Py_UopsSymbol *value; ++ JitOptSymbol *value; + PyObject *val = PyLong_FromLong(this_instr->oparg); + value = sym_new_const(ctx, val); + stack_pointer[0] = value; +@@ -92,7 +94,7 @@ + } + + case _STORE_FAST: { +- _Py_UopsSymbol *value; ++ JitOptSymbol *value; + value = stack_pointer[-1]; + GETLOCAL(oparg) = value; + stack_pointer += -1; +@@ -107,7 +109,7 @@ + } + + case _PUSH_NULL: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_null(ctx); + stack_pointer[0] = res; + stack_pointer += 1; +@@ -115,8 +117,14 @@ + break; + } + ++ case _END_FOR: { ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); ++ break; ++ } ++ + case _END_SEND: { +- _Py_UopsSymbol *val; ++ JitOptSymbol *val; + val = sym_new_not_null(ctx); + stack_pointer[-2] = val; + stack_pointer += -1; +@@ -125,22 +133,22 @@ + } + + case _UNARY_NEGATIVE: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-1] = res; + break; + } + + case _UNARY_NOT: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-1] = res; + break; + } + + case _TO_BOOL: { +- _Py_UopsSymbol *value; +- _Py_UopsSymbol *res; ++ JitOptSymbol *value; ++ JitOptSymbol *res; + value = stack_pointer[-1]; + if (!optimize_to_bool(this_instr, ctx, value, &res)) { + res = sym_new_type(ctx, &PyBool_Type); +@@ -150,8 +158,8 @@ + } + + case _TO_BOOL_BOOL: { +- _Py_UopsSymbol *value; +- _Py_UopsSymbol *res; ++ JitOptSymbol *value; ++ JitOptSymbol *res; + value = stack_pointer[-1]; + if (!optimize_to_bool(this_instr, ctx, value, &res)) { + sym_set_type(value, &PyBool_Type); +@@ -162,8 +170,8 @@ + } + + case _TO_BOOL_INT: { +- _Py_UopsSymbol *value; +- _Py_UopsSymbol *res; ++ JitOptSymbol *value; ++ JitOptSymbol *res; + value = stack_pointer[-1]; + if (!optimize_to_bool(this_instr, ctx, value, &res)) { + sym_set_type(value, &PyLong_Type); +@@ -174,8 +182,8 @@ + } + + case _TO_BOOL_LIST: { +- _Py_UopsSymbol *value; +- _Py_UopsSymbol *res; ++ JitOptSymbol *value; ++ JitOptSymbol *res; + value = stack_pointer[-1]; + if (!optimize_to_bool(this_instr, ctx, value, &res)) { + sym_set_type(value, &PyList_Type); +@@ -186,8 +194,8 @@ + } + + case _TO_BOOL_NONE: { +- _Py_UopsSymbol *value; +- _Py_UopsSymbol *res; ++ JitOptSymbol *value; ++ JitOptSymbol *res; + value = stack_pointer[-1]; + if (!optimize_to_bool(this_instr, ctx, value, &res)) { + sym_set_const(value, Py_None); +@@ -198,8 +206,8 @@ + } + + case _TO_BOOL_STR: { +- _Py_UopsSymbol *value; +- _Py_UopsSymbol *res; ++ JitOptSymbol *value; ++ JitOptSymbol *res; + value = stack_pointer[-1]; + if (!optimize_to_bool(this_instr, ctx, value, &res)) { + res = sym_new_type(ctx, &PyBool_Type); +@@ -210,22 +218,22 @@ + } + + case _REPLACE_WITH_TRUE: { +- _Py_UopsSymbol *res; +- res = sym_new_not_null(ctx); ++ JitOptSymbol *res; ++ res = sym_new_const(ctx, Py_True); + stack_pointer[-1] = res; + break; + } + + case _UNARY_INVERT: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-1] = res; + break; + } + + case _GUARD_BOTH_INT: { +- _Py_UopsSymbol *right; +- _Py_UopsSymbol *left; ++ JitOptSymbol *right; ++ JitOptSymbol *left; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + if (sym_matches_type(left, &PyLong_Type)) { +@@ -255,9 +263,9 @@ + } + + case _BINARY_OP_MULTIPLY_INT: { +- _Py_UopsSymbol *right; +- _Py_UopsSymbol *left; +- _Py_UopsSymbol *res; ++ JitOptSymbol *right; ++ JitOptSymbol *left; ++ JitOptSymbol *res; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + if (sym_is_const(left) && sym_is_const(right) && +@@ -271,23 +279,26 @@ + goto error; + } + res = sym_new_const(ctx, temp); ++ stack_pointer[-2] = res; ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); + Py_DECREF(temp); + // TODO gh-115506: + // replace opcode with constant propagated one and add tests! + } + else { + res = sym_new_type(ctx, &PyLong_Type); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); + } +- stack_pointer[-2] = res; +- stack_pointer += -1; +- assert(WITHIN_STACK_BOUNDS()); ++ stack_pointer[-1] = res; + break; + } + + case _BINARY_OP_ADD_INT: { +- _Py_UopsSymbol *right; +- _Py_UopsSymbol *left; +- _Py_UopsSymbol *res; ++ JitOptSymbol *right; ++ JitOptSymbol *left; ++ JitOptSymbol *res; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + if (sym_is_const(left) && sym_is_const(right) && +@@ -301,23 +312,26 @@ + goto error; + } + res = sym_new_const(ctx, temp); ++ stack_pointer[-2] = res; ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); + Py_DECREF(temp); + // TODO gh-115506: + // replace opcode with constant propagated one and add tests! + } + else { + res = sym_new_type(ctx, &PyLong_Type); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); + } +- stack_pointer[-2] = res; +- stack_pointer += -1; +- assert(WITHIN_STACK_BOUNDS()); ++ stack_pointer[-1] = res; + break; + } + + case _BINARY_OP_SUBTRACT_INT: { +- _Py_UopsSymbol *right; +- _Py_UopsSymbol *left; +- _Py_UopsSymbol *res; ++ JitOptSymbol *right; ++ JitOptSymbol *left; ++ JitOptSymbol *res; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + if (sym_is_const(left) && sym_is_const(right) && +@@ -331,22 +345,25 @@ + goto error; + } + res = sym_new_const(ctx, temp); ++ stack_pointer[-2] = res; ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); + Py_DECREF(temp); + // TODO gh-115506: + // replace opcode with constant propagated one and add tests! + } + else { + res = sym_new_type(ctx, &PyLong_Type); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); + } +- stack_pointer[-2] = res; +- stack_pointer += -1; +- assert(WITHIN_STACK_BOUNDS()); ++ stack_pointer[-1] = res; + break; + } + + case _GUARD_BOTH_FLOAT: { +- _Py_UopsSymbol *right; +- _Py_UopsSymbol *left; ++ JitOptSymbol *right; ++ JitOptSymbol *left; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + if (sym_matches_type(left, &PyFloat_Type)) { +@@ -376,9 +393,9 @@ + } + + case _BINARY_OP_MULTIPLY_FLOAT: { +- _Py_UopsSymbol *right; +- _Py_UopsSymbol *left; +- _Py_UopsSymbol *res; ++ JitOptSymbol *right; ++ JitOptSymbol *left; ++ JitOptSymbol *res; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + if (sym_is_const(left) && sym_is_const(right) && +@@ -393,23 +410,26 @@ + goto error; + } + res = sym_new_const(ctx, temp); ++ stack_pointer[-2] = res; ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); + Py_DECREF(temp); + // TODO gh-115506: + // replace opcode with constant propagated one and update tests! + } + else { + res = sym_new_type(ctx, &PyFloat_Type); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); + } +- stack_pointer[-2] = res; +- stack_pointer += -1; +- assert(WITHIN_STACK_BOUNDS()); ++ stack_pointer[-1] = res; + break; + } + + case _BINARY_OP_ADD_FLOAT: { +- _Py_UopsSymbol *right; +- _Py_UopsSymbol *left; +- _Py_UopsSymbol *res; ++ JitOptSymbol *right; ++ JitOptSymbol *left; ++ JitOptSymbol *res; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + if (sym_is_const(left) && sym_is_const(right) && +@@ -424,23 +444,26 @@ + goto error; + } + res = sym_new_const(ctx, temp); ++ stack_pointer[-2] = res; ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); + Py_DECREF(temp); + // TODO gh-115506: + // replace opcode with constant propagated one and update tests! + } + else { + res = sym_new_type(ctx, &PyFloat_Type); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); + } +- stack_pointer[-2] = res; +- stack_pointer += -1; +- assert(WITHIN_STACK_BOUNDS()); ++ stack_pointer[-1] = res; + break; + } + + case _BINARY_OP_SUBTRACT_FLOAT: { +- _Py_UopsSymbol *right; +- _Py_UopsSymbol *left; +- _Py_UopsSymbol *res; ++ JitOptSymbol *right; ++ JitOptSymbol *left; ++ JitOptSymbol *res; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + if (sym_is_const(left) && sym_is_const(right) && +@@ -455,22 +478,25 @@ + goto error; + } + res = sym_new_const(ctx, temp); ++ stack_pointer[-2] = res; ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); + Py_DECREF(temp); + // TODO gh-115506: + // replace opcode with constant propagated one and update tests! + } + else { + res = sym_new_type(ctx, &PyFloat_Type); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); + } +- stack_pointer[-2] = res; +- stack_pointer += -1; +- assert(WITHIN_STACK_BOUNDS()); ++ stack_pointer[-1] = res; + break; + } + + case _GUARD_BOTH_UNICODE: { +- _Py_UopsSymbol *right; +- _Py_UopsSymbol *left; ++ JitOptSymbol *right; ++ JitOptSymbol *left; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + if (sym_matches_type(left, &PyUnicode_Type) && +@@ -483,9 +509,9 @@ + } + + case _BINARY_OP_ADD_UNICODE: { +- _Py_UopsSymbol *right; +- _Py_UopsSymbol *left; +- _Py_UopsSymbol *res; ++ JitOptSymbol *right; ++ JitOptSymbol *left; ++ JitOptSymbol *res; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + if (sym_is_const(left) && sym_is_const(right) && +@@ -495,23 +521,26 @@ + goto error; + } + res = sym_new_const(ctx, temp); ++ stack_pointer[-2] = res; ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); + Py_DECREF(temp); + } + else { + res = sym_new_type(ctx, &PyUnicode_Type); ++ stack_pointer += -1; ++ assert(WITHIN_STACK_BOUNDS()); + } +- stack_pointer[-2] = res; +- stack_pointer += -1; +- assert(WITHIN_STACK_BOUNDS()); ++ stack_pointer[-1] = res; + break; + } + + case _BINARY_OP_INPLACE_ADD_UNICODE: { +- _Py_UopsSymbol *right; +- _Py_UopsSymbol *left; ++ JitOptSymbol *right; ++ JitOptSymbol *left; + right = stack_pointer[-1]; + left = stack_pointer[-2]; +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + if (sym_is_const(left) && sym_is_const(right) && + sym_matches_type(left, &PyUnicode_Type) && sym_matches_type(right, &PyUnicode_Type)) { + PyObject *temp = PyUnicode_Concat(sym_get_const(left), sym_get_const(right)); +@@ -519,20 +548,26 @@ + goto error; + } + res = sym_new_const(ctx, temp); ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); + Py_DECREF(temp); + } + else { + res = sym_new_type(ctx, &PyUnicode_Type); ++ stack_pointer += -2; ++ assert(WITHIN_STACK_BOUNDS()); + } + // _STORE_FAST: + GETLOCAL(this_instr->operand0) = res; +- stack_pointer += -2; +- assert(WITHIN_STACK_BOUNDS()); + break; + } + +- case _BINARY_SUBSCR: { +- _Py_UopsSymbol *res; ++ case _GUARD_BINARY_OP_EXTEND: { ++ break; ++ } ++ ++ case _BINARY_OP_EXTEND: { ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -541,7 +576,7 @@ + } + + case _BINARY_SLICE: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-3] = res; + stack_pointer += -2; +@@ -555,8 +590,8 @@ + break; + } + +- case _BINARY_SUBSCR_LIST_INT: { +- _Py_UopsSymbol *res; ++ case _BINARY_OP_SUBSCR_LIST_INT: { ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -564,8 +599,8 @@ + break; + } + +- case _BINARY_SUBSCR_STR_INT: { +- _Py_UopsSymbol *res; ++ case _BINARY_OP_SUBSCR_STR_INT: { ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -573,8 +608,8 @@ + break; + } + +- case _BINARY_SUBSCR_TUPLE_INT: { +- _Py_UopsSymbol *res; ++ case _BINARY_OP_SUBSCR_TUPLE_INT: { ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -582,8 +617,8 @@ + break; + } + +- case _BINARY_SUBSCR_DICT: { +- _Py_UopsSymbol *res; ++ case _BINARY_OP_SUBSCR_DICT: { ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -591,22 +626,21 @@ + break; + } + +- case _BINARY_SUBSCR_CHECK_FUNC: { ++ case _BINARY_OP_SUBSCR_CHECK_FUNC: { ++ JitOptSymbol *getitem; ++ getitem = sym_new_not_null(ctx); ++ stack_pointer[0] = getitem; ++ stack_pointer += 1; ++ assert(WITHIN_STACK_BOUNDS()); + break; + } + +- case _BINARY_SUBSCR_INIT_CALL: { +- _Py_UopsSymbol *sub; +- _Py_UopsSymbol *container; ++ case _BINARY_OP_SUBSCR_INIT_CALL: { + _Py_UOpsAbstractFrame *new_frame; +- sub = stack_pointer[-1]; +- container = stack_pointer[-2]; +- (void)container; +- (void)sub; + new_frame = NULL; + ctx->done = true; +- stack_pointer[-2] = (_Py_UopsSymbol *)new_frame; +- stack_pointer += -1; ++ stack_pointer[-3] = (JitOptSymbol *)new_frame; ++ stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); + break; + } +@@ -648,14 +682,14 @@ + } + + case _CALL_INTRINSIC_1: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-1] = res; + break; + } + + case _CALL_INTRINSIC_2: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -664,8 +698,8 @@ + } + + case _RETURN_VALUE: { +- _Py_UopsSymbol *retval; +- _Py_UopsSymbol *res; ++ JitOptSymbol *retval; ++ JitOptSymbol *res; + retval = stack_pointer[-1]; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); +@@ -692,14 +726,14 @@ + } + + case _GET_AITER: { +- _Py_UopsSymbol *iter; ++ JitOptSymbol *iter; + iter = sym_new_not_null(ctx); + stack_pointer[-1] = iter; + break; + } + + case _GET_ANEXT: { +- _Py_UopsSymbol *awaitable; ++ JitOptSymbol *awaitable; + awaitable = sym_new_not_null(ctx); + stack_pointer[0] = awaitable; + stack_pointer += 1; +@@ -708,7 +742,7 @@ + } + + case _GET_AWAITABLE: { +- _Py_UopsSymbol *iter; ++ JitOptSymbol *iter; + iter = sym_new_not_null(ctx); + stack_pointer[-1] = iter; + break; +@@ -723,7 +757,7 @@ + } + + case _YIELD_VALUE: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_unknown(ctx); + stack_pointer[-1] = res; + break; +@@ -736,7 +770,7 @@ + } + + case _LOAD_COMMON_CONSTANT: { +- _Py_UopsSymbol *value; ++ JitOptSymbol *value; + value = sym_new_not_null(ctx); + stack_pointer[0] = value; + stack_pointer += 1; +@@ -745,7 +779,7 @@ + } + + case _LOAD_BUILD_CLASS: { +- _Py_UopsSymbol *bc; ++ JitOptSymbol *bc; + bc = sym_new_not_null(ctx); + stack_pointer[0] = bc; + stack_pointer += 1; +@@ -764,12 +798,9 @@ + } + + case _UNPACK_SEQUENCE: { +- _Py_UopsSymbol *seq; +- _Py_UopsSymbol **values; +- seq = stack_pointer[-1]; ++ JitOptSymbol **values; + values = &stack_pointer[-1]; + /* This has to be done manually */ +- (void)seq; + for (int i = 0; i < oparg; i++) { + values[i] = sym_new_unknown(ctx); + } +@@ -779,10 +810,12 @@ + } + + case _UNPACK_SEQUENCE_TWO_TUPLE: { +- _Py_UopsSymbol *val1; +- _Py_UopsSymbol *val0; +- val1 = sym_new_not_null(ctx); +- val0 = sym_new_not_null(ctx); ++ JitOptSymbol *seq; ++ JitOptSymbol *val1; ++ JitOptSymbol *val0; ++ seq = stack_pointer[-1]; ++ val0 = sym_tuple_getitem(ctx, seq, 0); ++ val1 = sym_tuple_getitem(ctx, seq, 1); + stack_pointer[-1] = val1; + stack_pointer[0] = val0; + stack_pointer += 1; +@@ -791,10 +824,12 @@ + } + + case _UNPACK_SEQUENCE_TUPLE: { +- _Py_UopsSymbol **values; ++ JitOptSymbol *seq; ++ JitOptSymbol **values; ++ seq = stack_pointer[-1]; + values = &stack_pointer[-1]; +- for (int _i = oparg; --_i >= 0;) { +- values[_i] = sym_new_not_null(ctx); ++ for (int i = 0; i < oparg; i++) { ++ values[i] = sym_tuple_getitem(ctx, seq, i); + } + stack_pointer += -1 + oparg; + assert(WITHIN_STACK_BOUNDS()); +@@ -802,7 +837,7 @@ + } + + case _UNPACK_SEQUENCE_LIST: { +- _Py_UopsSymbol **values; ++ JitOptSymbol **values; + values = &stack_pointer[-1]; + for (int _i = oparg; --_i >= 0;) { + values[_i] = sym_new_not_null(ctx); +@@ -813,12 +848,9 @@ + } + + case _UNPACK_EX: { +- _Py_UopsSymbol *seq; +- _Py_UopsSymbol **values; +- seq = stack_pointer[-1]; ++ JitOptSymbol **values; + values = &stack_pointer[-1]; + /* This has to be done manually */ +- (void)seq; + int totalargs = (oparg & 0xFF) + (oparg >> 8) + 1; + for (int i = 0; i < totalargs; i++) { + values[i] = sym_new_unknown(ctx); +@@ -851,7 +883,7 @@ + } + + case _LOAD_LOCALS: { +- _Py_UopsSymbol *locals; ++ JitOptSymbol *locals; + locals = sym_new_not_null(ctx); + stack_pointer[0] = locals; + stack_pointer += 1; +@@ -862,7 +894,7 @@ + /* _LOAD_FROM_DICT_OR_GLOBALS is not a viable micro-op for tier 2 */ + + case _LOAD_NAME: { +- _Py_UopsSymbol *v; ++ JitOptSymbol *v; + v = sym_new_not_null(ctx); + stack_pointer[0] = v; + stack_pointer += 1; +@@ -871,13 +903,21 @@ + } + + case _LOAD_GLOBAL: { +- _Py_UopsSymbol **res; +- _Py_UopsSymbol *null = NULL; ++ JitOptSymbol **res; + res = &stack_pointer[0]; + res[0] = sym_new_not_null(ctx); ++ stack_pointer += 1; ++ assert(WITHIN_STACK_BOUNDS()); ++ break; ++ } ++ ++ case _PUSH_NULL_CONDITIONAL: { ++ JitOptSymbol *null = NULL; ++ int opcode = (oparg & 1) ? _PUSH_NULL : _NOP; ++ REPLACE_OP(this_instr, opcode, 0, 0); + null = sym_new_null(ctx); +- if (oparg & 1) stack_pointer[1] = null; +- stack_pointer += 1 + (oparg & 1); ++ if (oparg & 1) stack_pointer[0] = null; ++ stack_pointer += (oparg & 1); + assert(WITHIN_STACK_BOUNDS()); + break; + } +@@ -887,7 +927,7 @@ + } + + case _GUARD_GLOBALS_VERSION_PUSH_KEYS: { +- _Py_UopsSymbol *globals_keys; ++ JitOptSymbol *globals_keys; + uint16_t version = (uint16_t)this_instr->operand0; + globals_keys = sym_new_unknown(ctx); + (void)version; +@@ -898,7 +938,7 @@ + } + + case _GUARD_BUILTINS_VERSION_PUSH_KEYS: { +- _Py_UopsSymbol *builtins_keys; ++ JitOptSymbol *builtins_keys; + uint16_t version = (uint16_t)this_instr->operand0; + builtins_keys = sym_new_unknown(ctx); + (void)version; +@@ -909,26 +949,16 @@ + } + + case _LOAD_GLOBAL_MODULE_FROM_KEYS: { +- _Py_UopsSymbol *res; +- _Py_UopsSymbol *null = NULL; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); +- null = sym_new_null(ctx); + stack_pointer[-1] = res; +- if (oparg & 1) stack_pointer[0] = null; +- stack_pointer += (oparg & 1); +- assert(WITHIN_STACK_BOUNDS()); + break; + } + + case _LOAD_GLOBAL_BUILTINS_FROM_KEYS: { +- _Py_UopsSymbol *res; +- _Py_UopsSymbol *null = NULL; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); +- null = sym_new_null(ctx); + stack_pointer[-1] = res; +- if (oparg & 1) stack_pointer[0] = null; +- stack_pointer += (oparg & 1); +- assert(WITHIN_STACK_BOUNDS()); + break; + } + +@@ -945,14 +975,14 @@ + } + + case _LOAD_FROM_DICT_OR_DEREF: { +- _Py_UopsSymbol *value; ++ JitOptSymbol *value; + value = sym_new_not_null(ctx); + stack_pointer[-1] = value; + break; + } + + case _LOAD_DEREF: { +- _Py_UopsSymbol *value; ++ JitOptSymbol *value; + value = sym_new_not_null(ctx); + stack_pointer[0] = value; + stack_pointer += 1; +@@ -971,7 +1001,7 @@ + } + + case _BUILD_STRING: { +- _Py_UopsSymbol *str; ++ JitOptSymbol *str; + str = sym_new_not_null(ctx); + stack_pointer[-oparg] = str; + stack_pointer += 1 - oparg; +@@ -980,8 +1010,10 @@ + } + + case _BUILD_TUPLE: { +- _Py_UopsSymbol *tup; +- tup = sym_new_not_null(ctx); ++ JitOptSymbol **values; ++ JitOptSymbol *tup; ++ values = &stack_pointer[-oparg]; ++ tup = sym_new_tuple(ctx, oparg, values); + stack_pointer[-oparg] = tup; + stack_pointer += 1 - oparg; + assert(WITHIN_STACK_BOUNDS()); +@@ -989,7 +1021,7 @@ + } + + case _BUILD_LIST: { +- _Py_UopsSymbol *list; ++ JitOptSymbol *list; + list = sym_new_not_null(ctx); + stack_pointer[-oparg] = list; + stack_pointer += 1 - oparg; +@@ -1010,7 +1042,7 @@ + } + + case _BUILD_SET: { +- _Py_UopsSymbol *set; ++ JitOptSymbol *set; + set = sym_new_not_null(ctx); + stack_pointer[-oparg] = set; + stack_pointer += 1 - oparg; +@@ -1019,7 +1051,7 @@ + } + + case _BUILD_MAP: { +- _Py_UopsSymbol *map; ++ JitOptSymbol *map; + map = sym_new_not_null(ctx); + stack_pointer[-oparg*2] = map; + stack_pointer += 1 - oparg*2; +@@ -1049,10 +1081,8 @@ + break; + } + +- /* _INSTRUMENTED_LOAD_SUPER_ATTR is not a viable micro-op for tier 2 */ +- + case _LOAD_SUPER_ATTR_ATTR: { +- _Py_UopsSymbol *attr_st; ++ JitOptSymbol *attr_st; + attr_st = sym_new_not_null(ctx); + stack_pointer[-3] = attr_st; + stack_pointer += -2; +@@ -1061,8 +1091,8 @@ + } + + case _LOAD_SUPER_ATTR_METHOD: { +- _Py_UopsSymbol *attr; +- _Py_UopsSymbol *self_or_null; ++ JitOptSymbol *attr; ++ JitOptSymbol *self_or_null; + attr = sym_new_not_null(ctx); + self_or_null = sym_new_not_null(ctx); + stack_pointer[-3] = attr; +@@ -1073,22 +1103,24 @@ + } + + case _LOAD_ATTR: { +- _Py_UopsSymbol *owner; +- _Py_UopsSymbol *attr; +- _Py_UopsSymbol *self_or_null = NULL; ++ JitOptSymbol *owner; ++ JitOptSymbol *attr; ++ JitOptSymbol **self_or_null; + owner = stack_pointer[-1]; ++ self_or_null = &stack_pointer[0]; + (void)owner; + attr = sym_new_not_null(ctx); +- self_or_null = sym_new_unknown(ctx); ++ if (oparg &1) { ++ self_or_null[0] = sym_new_unknown(ctx); ++ } + stack_pointer[-1] = attr; +- if (oparg & 1) stack_pointer[0] = self_or_null; +- stack_pointer += (oparg & 1); ++ stack_pointer += (oparg&1); + assert(WITHIN_STACK_BOUNDS()); + break; + } + + case _GUARD_TYPE_VERSION: { +- _Py_UopsSymbol *owner; ++ JitOptSymbol *owner; + owner = stack_pointer[-1]; + uint32_t type_version = (uint32_t)this_instr->operand0; + assert(type_version); +@@ -1113,30 +1145,26 @@ + break; + } + ++ case _GUARD_TYPE_VERSION_AND_LOCK: { ++ break; ++ } ++ + case _CHECK_MANAGED_OBJECT_HAS_VALUES: { + break; + } + + case _LOAD_ATTR_INSTANCE_VALUE: { +- _Py_UopsSymbol *owner; +- _Py_UopsSymbol *attr; +- _Py_UopsSymbol *null = NULL; +- owner = stack_pointer[-1]; ++ JitOptSymbol *attr; + uint16_t offset = (uint16_t)this_instr->operand0; + attr = sym_new_not_null(ctx); +- null = sym_new_null(ctx); + (void)offset; +- (void)owner; + stack_pointer[-1] = attr; +- if (oparg & 1) stack_pointer[0] = null; +- stack_pointer += (oparg & 1); +- assert(WITHIN_STACK_BOUNDS()); + break; + } + + case _CHECK_ATTR_MODULE_PUSH_KEYS: { +- _Py_UopsSymbol *owner; +- _Py_UopsSymbol *mod_keys; ++ JitOptSymbol *owner; ++ JitOptSymbol *mod_keys; + owner = stack_pointer[-1]; + uint32_t dict_version = (uint32_t)this_instr->operand0; + (void)dict_version; +@@ -1166,13 +1194,11 @@ + } + + case _LOAD_ATTR_MODULE_FROM_KEYS: { +- _Py_UopsSymbol *owner; +- _Py_UopsSymbol *attr; +- _Py_UopsSymbol *null = NULL; ++ JitOptSymbol *owner; ++ JitOptSymbol *attr; + owner = stack_pointer[-2]; + uint16_t index = (uint16_t)this_instr->operand0; + (void)index; +- null = sym_new_null(ctx); + attr = NULL; + if (this_instr[-1].opcode == _NOP) { + // Preceding _CHECK_ATTR_MODULE_PUSH_KEYS was removed: mod is const and dict is watched. +@@ -1181,8 +1207,7 @@ + assert(PyModule_CheckExact(mod)); + PyObject *dict = mod->md_dict; + stack_pointer[-2] = attr; +- if (oparg & 1) stack_pointer[-1] = null; +- stack_pointer += -1 + (oparg & 1); ++ stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + PyObject *res = convert_global_to_const(this_instr, dict); + if (res != NULL) { +@@ -1192,7 +1217,7 @@ + else { + this_instr->opcode = _LOAD_ATTR_MODULE; + } +- stack_pointer += 1 - (oparg & 1); ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + } + if (attr == NULL) { +@@ -1200,47 +1225,37 @@ + attr = sym_new_not_null(ctx); + } + stack_pointer[-2] = attr; +- if (oparg & 1) stack_pointer[-1] = null; +- stack_pointer += -1 + (oparg & 1); ++ stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + break; + } + + case _CHECK_ATTR_WITH_HINT: { ++ JitOptSymbol *dict; ++ dict = sym_new_not_null(ctx); ++ stack_pointer[0] = dict; ++ stack_pointer += 1; ++ assert(WITHIN_STACK_BOUNDS()); + break; + } + + case _LOAD_ATTR_WITH_HINT: { +- _Py_UopsSymbol *owner; +- _Py_UopsSymbol *attr; +- _Py_UopsSymbol *null = NULL; +- owner = stack_pointer[-1]; ++ JitOptSymbol *attr; + uint16_t hint = (uint16_t)this_instr->operand0; + attr = sym_new_not_null(ctx); +- null = sym_new_null(ctx); + (void)hint; +- (void)owner; +- stack_pointer[-1] = attr; +- if (oparg & 1) stack_pointer[0] = null; +- stack_pointer += (oparg & 1); ++ stack_pointer[-2] = attr; ++ stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + break; + } + + case _LOAD_ATTR_SLOT: { +- _Py_UopsSymbol *owner; +- _Py_UopsSymbol *attr; +- _Py_UopsSymbol *null = NULL; +- owner = stack_pointer[-1]; ++ JitOptSymbol *attr; + uint16_t index = (uint16_t)this_instr->operand0; + attr = sym_new_not_null(ctx); +- null = sym_new_null(ctx); + (void)index; +- (void)owner; + stack_pointer[-1] = attr; +- if (oparg & 1) stack_pointer[0] = null; +- stack_pointer += (oparg & 1); +- assert(WITHIN_STACK_BOUNDS()); + break; + } + +@@ -1249,32 +1264,21 @@ + } + + case _LOAD_ATTR_CLASS: { +- _Py_UopsSymbol *owner; +- _Py_UopsSymbol *attr; +- _Py_UopsSymbol *null = NULL; +- owner = stack_pointer[-1]; ++ JitOptSymbol *attr; + PyObject *descr = (PyObject *)this_instr->operand0; + attr = sym_new_not_null(ctx); +- null = sym_new_null(ctx); + (void)descr; +- (void)owner; + stack_pointer[-1] = attr; +- if (oparg & 1) stack_pointer[0] = null; +- stack_pointer += (oparg & 1); +- assert(WITHIN_STACK_BOUNDS()); + break; + } + + case _LOAD_ATTR_PROPERTY_FRAME: { +- _Py_UopsSymbol *owner; + _Py_UOpsAbstractFrame *new_frame; +- owner = stack_pointer[-1]; + PyObject *fget = (PyObject *)this_instr->operand0; + (void)fget; +- (void)owner; + new_frame = NULL; + ctx->done = true; +- stack_pointer[-1] = (_Py_UopsSymbol *)new_frame; ++ stack_pointer[-1] = (JitOptSymbol *)new_frame; + break; + } + +@@ -1303,13 +1307,7 @@ + } + + case _COMPARE_OP: { +- _Py_UopsSymbol *right; +- _Py_UopsSymbol *left; +- _Py_UopsSymbol *res; +- right = stack_pointer[-1]; +- left = stack_pointer[-2]; +- (void)left; +- (void)right; ++ JitOptSymbol *res; + if (oparg & 16) { + res = sym_new_type(ctx, &PyBool_Type); + } +@@ -1327,13 +1325,7 @@ + } + + case _COMPARE_OP_FLOAT: { +- _Py_UopsSymbol *right; +- _Py_UopsSymbol *left; +- _Py_UopsSymbol *res; +- right = stack_pointer[-1]; +- left = stack_pointer[-2]; +- (void)left; +- (void)right; ++ JitOptSymbol *res; + res = sym_new_type(ctx, &PyBool_Type); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -1342,13 +1334,7 @@ + } + + case _COMPARE_OP_INT: { +- _Py_UopsSymbol *right; +- _Py_UopsSymbol *left; +- _Py_UopsSymbol *res; +- right = stack_pointer[-1]; +- left = stack_pointer[-2]; +- (void)left; +- (void)right; ++ JitOptSymbol *res; + res = sym_new_type(ctx, &PyBool_Type); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -1357,13 +1343,7 @@ + } + + case _COMPARE_OP_STR: { +- _Py_UopsSymbol *right; +- _Py_UopsSymbol *left; +- _Py_UopsSymbol *res; +- right = stack_pointer[-1]; +- left = stack_pointer[-2]; +- (void)left; +- (void)right; ++ JitOptSymbol *res; + res = sym_new_type(ctx, &PyBool_Type); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -1372,13 +1352,7 @@ + } + + case _IS_OP: { +- _Py_UopsSymbol *right; +- _Py_UopsSymbol *left; +- _Py_UopsSymbol *res; +- right = stack_pointer[-1]; +- left = stack_pointer[-2]; +- (void)left; +- (void)right; ++ JitOptSymbol *res; + res = sym_new_type(ctx, &PyBool_Type); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -1387,13 +1361,7 @@ + } + + case _CONTAINS_OP: { +- _Py_UopsSymbol *right; +- _Py_UopsSymbol *left; +- _Py_UopsSymbol *res; +- right = stack_pointer[-1]; +- left = stack_pointer[-2]; +- (void)left; +- (void)right; ++ JitOptSymbol *res; + res = sym_new_type(ctx, &PyBool_Type); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -1402,7 +1370,7 @@ + } + + case _CONTAINS_OP_SET: { +- _Py_UopsSymbol *b; ++ JitOptSymbol *b; + b = sym_new_not_null(ctx); + stack_pointer[-2] = b; + stack_pointer += -1; +@@ -1411,7 +1379,7 @@ + } + + case _CONTAINS_OP_DICT: { +- _Py_UopsSymbol *b; ++ JitOptSymbol *b; + b = sym_new_not_null(ctx); + stack_pointer[-2] = b; + stack_pointer += -1; +@@ -1420,8 +1388,8 @@ + } + + case _CHECK_EG_MATCH: { +- _Py_UopsSymbol *rest; +- _Py_UopsSymbol *match; ++ JitOptSymbol *rest; ++ JitOptSymbol *match; + rest = sym_new_not_null(ctx); + match = sym_new_not_null(ctx); + stack_pointer[-2] = rest; +@@ -1430,14 +1398,14 @@ + } + + case _CHECK_EXC_MATCH: { +- _Py_UopsSymbol *b; ++ JitOptSymbol *b; + b = sym_new_not_null(ctx); + stack_pointer[-1] = b; + break; + } + + case _IMPORT_NAME: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -1446,7 +1414,7 @@ + } + + case _IMPORT_FROM: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[0] = res; + stack_pointer += 1; +@@ -1459,14 +1427,14 @@ + /* _POP_JUMP_IF_TRUE is not a viable micro-op for tier 2 */ + + case _IS_NONE: { +- _Py_UopsSymbol *b; ++ JitOptSymbol *b; + b = sym_new_not_null(ctx); + stack_pointer[-1] = b; + break; + } + + case _GET_LEN: { +- _Py_UopsSymbol *len; ++ JitOptSymbol *len; + len = sym_new_not_null(ctx); + stack_pointer[0] = len; + stack_pointer += 1; +@@ -1475,7 +1443,7 @@ + } + + case _MATCH_CLASS: { +- _Py_UopsSymbol *attrs; ++ JitOptSymbol *attrs; + attrs = sym_new_not_null(ctx); + stack_pointer[-3] = attrs; + stack_pointer += -2; +@@ -1484,7 +1452,7 @@ + } + + case _MATCH_MAPPING: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[0] = res; + stack_pointer += 1; +@@ -1493,7 +1461,7 @@ + } + + case _MATCH_SEQUENCE: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[0] = res; + stack_pointer += 1; +@@ -1502,7 +1470,7 @@ + } + + case _MATCH_KEYS: { +- _Py_UopsSymbol *values_or_none; ++ JitOptSymbol *values_or_none; + values_or_none = sym_new_not_null(ctx); + stack_pointer[0] = values_or_none; + stack_pointer += 1; +@@ -1511,14 +1479,14 @@ + } + + case _GET_ITER: { +- _Py_UopsSymbol *iter; ++ JitOptSymbol *iter; + iter = sym_new_not_null(ctx); + stack_pointer[-1] = iter; + break; + } + + case _GET_YIELD_FROM_ITER: { +- _Py_UopsSymbol *iter; ++ JitOptSymbol *iter; + iter = sym_new_not_null(ctx); + stack_pointer[-1] = iter; + break; +@@ -1527,7 +1495,7 @@ + /* _FOR_ITER is not a viable micro-op for tier 2 */ + + case _FOR_ITER_TIER_TWO: { +- _Py_UopsSymbol *next; ++ JitOptSymbol *next; + next = sym_new_not_null(ctx); + stack_pointer[0] = next; + stack_pointer += 1; +@@ -1548,7 +1516,7 @@ + } + + case _ITER_NEXT_LIST: { +- _Py_UopsSymbol *next; ++ JitOptSymbol *next; + next = sym_new_not_null(ctx); + stack_pointer[0] = next; + stack_pointer += 1; +@@ -1567,7 +1535,7 @@ + } + + case _ITER_NEXT_TUPLE: { +- _Py_UopsSymbol *next; ++ JitOptSymbol *next; + next = sym_new_not_null(ctx); + stack_pointer[0] = next; + stack_pointer += 1; +@@ -1586,11 +1554,8 @@ + } + + case _ITER_NEXT_RANGE: { +- _Py_UopsSymbol *iter; +- _Py_UopsSymbol *next; +- iter = stack_pointer[-1]; ++ JitOptSymbol *next; + next = sym_new_type(ctx, &PyLong_Type); +- (void)iter; + stack_pointer[0] = next; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); +@@ -1604,11 +1569,8 @@ + } + + case _LOAD_SPECIAL: { +- _Py_UopsSymbol *owner; +- _Py_UopsSymbol *attr; +- _Py_UopsSymbol *self_or_null; +- owner = stack_pointer[-1]; +- (void)owner; ++ JitOptSymbol *attr; ++ JitOptSymbol *self_or_null; + attr = sym_new_not_null(ctx); + self_or_null = sym_new_unknown(ctx); + stack_pointer[-1] = attr; +@@ -1619,7 +1581,7 @@ + } + + case _WITH_EXCEPT_START: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[0] = res; + stack_pointer += 1; +@@ -1628,8 +1590,8 @@ + } + + case _PUSH_EXC_INFO: { +- _Py_UopsSymbol *prev_exc; +- _Py_UopsSymbol *new_exc; ++ JitOptSymbol *prev_exc; ++ JitOptSymbol *new_exc; + prev_exc = sym_new_not_null(ctx); + new_exc = sym_new_not_null(ctx); + stack_pointer[-1] = prev_exc; +@@ -1648,9 +1610,9 @@ + } + + case _LOAD_ATTR_METHOD_WITH_VALUES: { +- _Py_UopsSymbol *owner; +- _Py_UopsSymbol *attr; +- _Py_UopsSymbol *self = NULL; ++ JitOptSymbol *owner; ++ JitOptSymbol *attr; ++ JitOptSymbol *self; + owner = stack_pointer[-1]; + PyObject *descr = (PyObject *)this_instr->operand0; + (void)descr; +@@ -1664,9 +1626,9 @@ + } + + case _LOAD_ATTR_METHOD_NO_DICT: { +- _Py_UopsSymbol *owner; +- _Py_UopsSymbol *attr; +- _Py_UopsSymbol *self = NULL; ++ JitOptSymbol *owner; ++ JitOptSymbol *attr; ++ JitOptSymbol *self; + owner = stack_pointer[-1]; + PyObject *descr = (PyObject *)this_instr->operand0; + (void)descr; +@@ -1680,14 +1642,14 @@ + } + + case _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES: { +- _Py_UopsSymbol *attr; ++ JitOptSymbol *attr; + attr = sym_new_not_null(ctx); + stack_pointer[-1] = attr; + break; + } + + case _LOAD_ATTR_NONDESCRIPTOR_NO_DICT: { +- _Py_UopsSymbol *attr; ++ JitOptSymbol *attr; + attr = sym_new_not_null(ctx); + stack_pointer[-1] = attr; + break; +@@ -1698,9 +1660,9 @@ + } + + case _LOAD_ATTR_METHOD_LAZY_DICT: { +- _Py_UopsSymbol *owner; +- _Py_UopsSymbol *attr; +- _Py_UopsSymbol *self = NULL; ++ JitOptSymbol *owner; ++ JitOptSymbol *attr; ++ JitOptSymbol *self; + owner = stack_pointer[-1]; + PyObject *descr = (PyObject *)this_instr->operand0; + (void)descr; +@@ -1714,17 +1676,11 @@ + } + + case _MAYBE_EXPAND_METHOD: { +- _Py_UopsSymbol **args; +- _Py_UopsSymbol *self_or_null; +- _Py_UopsSymbol *callable; +- _Py_UopsSymbol *func; +- _Py_UopsSymbol *maybe_self; ++ JitOptSymbol **args; ++ JitOptSymbol *func; ++ JitOptSymbol *maybe_self; + args = &stack_pointer[-oparg]; +- self_or_null = stack_pointer[-1 - oparg]; +- callable = stack_pointer[-2 - oparg]; + args = &stack_pointer[-oparg]; +- (void)callable; +- (void)self_or_null; + (void)args; + func = sym_new_not_null(ctx); + maybe_self = sym_new_not_null(ctx); +@@ -1738,36 +1694,27 @@ + /* _MONITOR_CALL is not a viable micro-op for tier 2 */ + + case _PY_FRAME_GENERAL: { +- _Py_UopsSymbol *self_or_null; +- _Py_UopsSymbol *callable; + _Py_UOpsAbstractFrame *new_frame; +- self_or_null = stack_pointer[-1 - oparg]; +- callable = stack_pointer[-2 - oparg]; +- stack_pointer += -2 - oparg; +- assert(WITHIN_STACK_BOUNDS()); +- (void)(self_or_null); +- (void)(callable); + PyCodeObject *co = NULL; + assert((this_instr + 2)->opcode == _PUSH_FRAME); ++ stack_pointer += -2 - oparg; ++ assert(WITHIN_STACK_BOUNDS()); + co = get_code_with_logging((this_instr + 2)); + if (co == NULL) { + ctx->done = true; + break; + } + new_frame = frame_new(ctx, co, 0, NULL, 0); +- stack_pointer[0] = (_Py_UopsSymbol *)new_frame; ++ stack_pointer[0] = (JitOptSymbol *)new_frame; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } + + case _CHECK_FUNCTION_VERSION: { +- _Py_UopsSymbol *self_or_null; +- _Py_UopsSymbol *callable; +- self_or_null = stack_pointer[-1 - oparg]; ++ JitOptSymbol *callable; + callable = stack_pointer[-2 - oparg]; + uint32_t func_version = (uint32_t)this_instr->operand0; +- (void)self_or_null; + if (sym_is_const(callable) && sym_matches_type(callable, &PyFunction_Type)) { + assert(PyFunction_Check(sym_get_const(callable))); + REPLACE_OP(this_instr, _CHECK_FUNCTION_VERSION_INLINE, 0, func_version); +@@ -1786,12 +1733,6 @@ + } + + case _EXPAND_METHOD: { +- _Py_UopsSymbol **method; +- _Py_UopsSymbol **self; +- method = &stack_pointer[-2 - oparg]; +- self = &stack_pointer[-1 - oparg]; +- method[0] = sym_new_not_null(ctx); +- self[0] = sym_new_not_null(ctx); + break; + } + +@@ -1800,7 +1741,7 @@ + } + + case _CALL_NON_PY_GENERAL: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; +@@ -1809,8 +1750,8 @@ + } + + case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: { +- _Py_UopsSymbol *null; +- _Py_UopsSymbol *callable; ++ JitOptSymbol *null; ++ JitOptSymbol *callable; + null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + sym_set_null(null); +@@ -1819,15 +1760,12 @@ + } + + case _INIT_CALL_BOUND_METHOD_EXACT_ARGS: { +- _Py_UopsSymbol *callable; +- _Py_UopsSymbol *func; +- _Py_UopsSymbol *self; +- callable = stack_pointer[-2 - oparg]; +- (void)callable; +- func = sym_new_not_null(ctx); +- self = sym_new_not_null(ctx); +- stack_pointer[-2 - oparg] = func; +- stack_pointer[-1 - oparg] = self; ++ JitOptSymbol **self_or_null; ++ JitOptSymbol **callable; ++ self_or_null = &stack_pointer[-1 - oparg]; ++ callable = &stack_pointer[-2 - oparg]; ++ callable[0] = sym_new_not_null(ctx); ++ self_or_null[0] = sym_new_not_null(ctx); + break; + } + +@@ -1841,8 +1779,8 @@ + } + + case _CHECK_FUNCTION_EXACT_ARGS: { +- _Py_UopsSymbol *self_or_null; +- _Py_UopsSymbol *callable; ++ JitOptSymbol *self_or_null; ++ JitOptSymbol *callable; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + assert(sym_matches_type(callable, &PyFunction_Type)); +@@ -1855,7 +1793,6 @@ + } + } + } +- (void)self_or_null; + break; + } + +@@ -1866,15 +1803,12 @@ + } + + case _INIT_CALL_PY_EXACT_ARGS: { +- _Py_UopsSymbol **args; +- _Py_UopsSymbol *self_or_null; +- _Py_UopsSymbol *callable; ++ JitOptSymbol **args; ++ JitOptSymbol *self_or_null; + _Py_UOpsAbstractFrame *new_frame; + args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; +- callable = stack_pointer[-2 - oparg]; + int argcount = oparg; +- (void)callable; + PyCodeObject *co = NULL; + assert((this_instr + 2)->opcode == _PUSH_FRAME); + stack_pointer += -2 - oparg; +@@ -1896,7 +1830,7 @@ + } else { + new_frame = frame_new(ctx, co, 0, NULL, 0); + } +- stack_pointer[0] = (_Py_UopsSymbol *)new_frame; ++ stack_pointer[0] = (JitOptSymbol *)new_frame; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; +@@ -1941,7 +1875,7 @@ + } + + case _CALL_TYPE_1: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-3] = res; + stack_pointer += -2; +@@ -1950,7 +1884,7 @@ + } + + case _CALL_STR_1: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-3] = res; + stack_pointer += -2; +@@ -1959,7 +1893,7 @@ + } + + case _CALL_TUPLE_1: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-3] = res; + stack_pointer += -2; +@@ -1968,19 +1902,13 @@ + } + + case _CHECK_AND_ALLOCATE_OBJECT: { +- _Py_UopsSymbol **args; +- _Py_UopsSymbol *null; +- _Py_UopsSymbol *callable; +- _Py_UopsSymbol *self; +- _Py_UopsSymbol *init; ++ JitOptSymbol **args; ++ JitOptSymbol *self; ++ JitOptSymbol *init; + args = &stack_pointer[-oparg]; +- null = stack_pointer[-1 - oparg]; +- callable = stack_pointer[-2 - oparg]; + args = &stack_pointer[-oparg]; + uint32_t type_version = (uint32_t)this_instr->operand0; + (void)type_version; +- (void)callable; +- (void)null; + (void)args; + self = sym_new_not_null(ctx); + init = sym_new_not_null(ctx); +@@ -1990,19 +1918,10 @@ + } + + case _CREATE_INIT_FRAME: { +- _Py_UopsSymbol **args; +- _Py_UopsSymbol *init; +- _Py_UopsSymbol *self; + _Py_UOpsAbstractFrame *init_frame; +- args = &stack_pointer[-oparg]; +- init = stack_pointer[-1 - oparg]; +- self = stack_pointer[-2 - oparg]; +- (void)self; +- (void)init; +- (void)args; + init_frame = NULL; + ctx->done = true; +- stack_pointer[-2 - oparg] = (_Py_UopsSymbol *)init_frame; ++ stack_pointer[-2 - oparg] = (JitOptSymbol *)init_frame; + stack_pointer += -1 - oparg; + assert(WITHIN_STACK_BOUNDS()); + break; +@@ -2015,7 +1934,7 @@ + } + + case _CALL_BUILTIN_CLASS: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; +@@ -2024,7 +1943,7 @@ + } + + case _CALL_BUILTIN_O: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; +@@ -2033,7 +1952,7 @@ + } + + case _CALL_BUILTIN_FAST: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; +@@ -2042,7 +1961,7 @@ + } + + case _CALL_BUILTIN_FAST_WITH_KEYWORDS: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; +@@ -2051,7 +1970,7 @@ + } + + case _CALL_LEN: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; +@@ -2060,7 +1979,7 @@ + } + + case _CALL_ISINSTANCE: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; +@@ -2075,7 +1994,7 @@ + } + + case _CALL_METHOD_DESCRIPTOR_O: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; +@@ -2084,7 +2003,7 @@ + } + + case _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; +@@ -2093,7 +2012,7 @@ + } + + case _CALL_METHOD_DESCRIPTOR_NOARGS: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; +@@ -2102,7 +2021,7 @@ + } + + case _CALL_METHOD_DESCRIPTOR_FAST: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; +@@ -2110,13 +2029,13 @@ + break; + } + +- /* _INSTRUMENTED_CALL_KW is not a viable micro-op for tier 2 */ ++ /* _MONITOR_CALL_KW is not a viable micro-op for tier 2 */ + + case _MAYBE_EXPAND_METHOD_KW: { +- _Py_UopsSymbol **func; +- _Py_UopsSymbol **maybe_self; +- _Py_UopsSymbol **args; +- _Py_UopsSymbol *kwnames_out; ++ JitOptSymbol **func; ++ JitOptSymbol **maybe_self; ++ JitOptSymbol **args; ++ JitOptSymbol *kwnames_out; + func = &stack_pointer[-3 - oparg]; + maybe_self = &stack_pointer[-2 - oparg]; + args = &stack_pointer[-1 - oparg]; +@@ -2133,22 +2052,10 @@ + /* _DO_CALL_KW is not a viable micro-op for tier 2 */ + + case _PY_FRAME_KW: { +- _Py_UopsSymbol *kwnames; +- _Py_UopsSymbol **args; +- _Py_UopsSymbol *self_or_null; +- _Py_UopsSymbol *callable; + _Py_UOpsAbstractFrame *new_frame; +- kwnames = stack_pointer[-1]; +- args = &stack_pointer[-1 - oparg]; +- self_or_null = stack_pointer[-2 - oparg]; +- callable = stack_pointer[-3 - oparg]; +- (void)callable; +- (void)self_or_null; +- (void)args; +- (void)kwnames; + new_frame = NULL; + ctx->done = true; +- stack_pointer[-3 - oparg] = (_Py_UopsSymbol *)new_frame; ++ stack_pointer[-3 - oparg] = (JitOptSymbol *)new_frame; + stack_pointer += -2 - oparg; + assert(WITHIN_STACK_BOUNDS()); + break; +@@ -2163,12 +2070,6 @@ + } + + case _EXPAND_METHOD_KW: { +- _Py_UopsSymbol **method; +- _Py_UopsSymbol **self; +- method = &stack_pointer[-3 - oparg]; +- self = &stack_pointer[-2 - oparg]; +- method[0] = sym_new_not_null(ctx); +- self[0] = sym_new_not_null(ctx); + break; + } + +@@ -2177,7 +2078,7 @@ + } + + case _CALL_KW_NON_PY: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-3 - oparg] = res; + stack_pointer += -2 - oparg; +@@ -2185,29 +2086,27 @@ + break; + } + +- /* _INSTRUMENTED_CALL_FUNCTION_EX is not a viable micro-op for tier 2 */ +- + case _MAKE_CALLARGS_A_TUPLE: { +- _Py_UopsSymbol *tuple; +- _Py_UopsSymbol *kwargs_out = NULL; ++ JitOptSymbol *tuple; ++ JitOptSymbol *kwargs_out; + tuple = sym_new_not_null(ctx); + kwargs_out = sym_new_not_null(ctx); +- stack_pointer[-1 - (oparg & 1)] = tuple; +- if (oparg & 1) stack_pointer[-(oparg & 1)] = kwargs_out; ++ stack_pointer[-2] = tuple; ++ stack_pointer[-1] = kwargs_out; + break; + } + + /* _DO_CALL_FUNCTION_EX is not a viable micro-op for tier 2 */ + + case _MAKE_FUNCTION: { +- _Py_UopsSymbol *func; ++ JitOptSymbol *func; + func = sym_new_not_null(ctx); + stack_pointer[-1] = func; + break; + } + + case _SET_FUNCTION_ATTRIBUTE: { +- _Py_UopsSymbol *func_out; ++ JitOptSymbol *func_out; + func_out = sym_new_not_null(ctx); + stack_pointer[-2] = func_out; + stack_pointer += -1; +@@ -2216,7 +2115,7 @@ + } + + case _RETURN_GENERATOR: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + ctx->frame->stack_pointer = stack_pointer; + frame_pop(ctx); + stack_pointer = ctx->frame->stack_pointer; +@@ -2240,30 +2139,30 @@ + } + + case _BUILD_SLICE: { +- _Py_UopsSymbol *slice; ++ JitOptSymbol *slice; + slice = sym_new_not_null(ctx); +- stack_pointer[-2 - ((oparg == 3) ? 1 : 0)] = slice; +- stack_pointer += -1 - ((oparg == 3) ? 1 : 0); ++ stack_pointer[-oparg] = slice; ++ stack_pointer += 1 - oparg; + assert(WITHIN_STACK_BOUNDS()); + break; + } + + case _CONVERT_VALUE: { +- _Py_UopsSymbol *result; ++ JitOptSymbol *result; + result = sym_new_not_null(ctx); + stack_pointer[-1] = result; + break; + } + + case _FORMAT_SIMPLE: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-1] = res; + break; + } + + case _FORMAT_WITH_SPEC: { +- _Py_UopsSymbol *res; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); + stack_pointer[-2] = res; + stack_pointer += -1; +@@ -2272,8 +2171,8 @@ + } + + case _COPY: { +- _Py_UopsSymbol *bottom; +- _Py_UopsSymbol *top; ++ JitOptSymbol *bottom; ++ JitOptSymbol *top; + bottom = stack_pointer[-1 - (oparg-1)]; + assert(oparg > 0); + top = bottom; +@@ -2284,29 +2183,74 @@ + } + + case _BINARY_OP: { +- _Py_UopsSymbol *right; +- _Py_UopsSymbol *left; +- _Py_UopsSymbol *res; ++ JitOptSymbol *right; ++ JitOptSymbol *left; ++ JitOptSymbol *res; + right = stack_pointer[-1]; + left = stack_pointer[-2]; +- PyTypeObject *ltype = sym_get_type(left); +- PyTypeObject *rtype = sym_get_type(right); +- if (ltype != NULL && (ltype == &PyLong_Type || ltype == &PyFloat_Type) && +- rtype != NULL && (rtype == &PyLong_Type || rtype == &PyFloat_Type)) +- { +- if (oparg != NB_TRUE_DIVIDE && oparg != NB_INPLACE_TRUE_DIVIDE && +- ltype == &PyLong_Type && rtype == &PyLong_Type) { +- /* If both inputs are ints and the op is not division the result is an int */ +- res = sym_new_type(ctx, &PyLong_Type); ++ bool lhs_int = sym_matches_type(left, &PyLong_Type); ++ bool rhs_int = sym_matches_type(right, &PyLong_Type); ++ bool lhs_float = sym_matches_type(left, &PyFloat_Type); ++ bool rhs_float = sym_matches_type(right, &PyFloat_Type); ++ if (!((lhs_int || lhs_float) && (rhs_int || rhs_float))) { ++ // There's something other than an int or float involved: ++ res = sym_new_unknown(ctx); ++ } ++ else { ++ if (oparg == NB_POWER || oparg == NB_INPLACE_POWER) { ++ // This one's fun... the *type* of the result depends on the ++ // *values* being exponentiated. However, exponents with one ++ // constant part are reasonably common, so it's probably worth ++ // trying to infer some simple cases: ++ // - A: 1 ** 1 -> 1 (int ** int -> int) ++ // - B: 1 ** -1 -> 1.0 (int ** int -> float) ++ // - C: 1.0 ** 1 -> 1.0 (float ** int -> float) ++ // - D: 1 ** 1.0 -> 1.0 (int ** float -> float) ++ // - E: -1 ** 0.5 ~> 1j (int ** float -> complex) ++ // - F: 1.0 ** 1.0 -> 1.0 (float ** float -> float) ++ // - G: -1.0 ** 0.5 ~> 1j (float ** float -> complex) ++ if (rhs_float) { ++ // Case D, E, F, or G... can't know without the sign of the LHS ++ // or whether the RHS is whole, which isn't worth the effort: ++ res = sym_new_unknown(ctx); ++ } ++ else { ++ if (lhs_float) { ++ // Case C: ++ res = sym_new_type(ctx, &PyFloat_Type); ++ } ++ else { ++ if (!sym_is_const(right)) { ++ // Case A or B... can't know without the sign of the RHS: ++ res = sym_new_unknown(ctx); ++ } ++ else { ++ if (_PyLong_IsNegative((PyLongObject *)sym_get_const(right))) { ++ // Case B: ++ res = sym_new_type(ctx, &PyFloat_Type); ++ } ++ else { ++ // Case A: ++ res = sym_new_type(ctx, &PyLong_Type); ++ } ++ } ++ } ++ } + } + else { +- /* For any other op combining ints/floats the result is a float */ +- res = sym_new_type(ctx, &PyFloat_Type); ++ if (oparg == NB_TRUE_DIVIDE || oparg == NB_INPLACE_TRUE_DIVIDE) { ++ res = sym_new_type(ctx, &PyFloat_Type); ++ } ++ else { ++ if (lhs_int && rhs_int) { ++ res = sym_new_type(ctx, &PyLong_Type); ++ } ++ else { ++ res = sym_new_type(ctx, &PyFloat_Type); ++ } ++ } + } + } +- else { +- res = sym_new_unknown(ctx); +- } + stack_pointer[-2] = res; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); +@@ -2314,16 +2258,14 @@ + } + + case _SWAP: { +- _Py_UopsSymbol *top_in; +- _Py_UopsSymbol *bottom_in; +- _Py_UopsSymbol *top_out; +- _Py_UopsSymbol *bottom_out; +- top_in = stack_pointer[-1]; +- bottom_in = stack_pointer[-2 - (oparg-2)]; +- bottom_out = bottom_in; +- top_out = top_in; +- stack_pointer[-2 - (oparg-2)] = top_out; +- stack_pointer[-1] = bottom_out; ++ JitOptSymbol **top; ++ JitOptSymbol **bottom; ++ top = &stack_pointer[-1]; ++ bottom = &stack_pointer[-2 - (oparg-2)]; ++ JitOptSymbol *temp = bottom[0]; ++ bottom[0] = top[0]; ++ top[0] = temp; ++ assert(oparg >= 2); + break; + } + +@@ -2335,6 +2277,8 @@ + + /* _MONITOR_JUMP_BACKWARD is not a viable micro-op for tier 2 */ + ++ /* _INSTRUMENTED_NOT_TAKEN is not a viable micro-op for tier 2 */ ++ + /* _INSTRUMENTED_POP_JUMP_IF_TRUE is not a viable micro-op for tier 2 */ + + /* _INSTRUMENTED_POP_JUMP_IF_FALSE is not a viable micro-op for tier 2 */ +@@ -2344,7 +2288,7 @@ + /* _INSTRUMENTED_POP_JUMP_IF_NOT_NONE is not a viable micro-op for tier 2 */ + + case _GUARD_IS_TRUE_POP: { +- _Py_UopsSymbol *flag; ++ JitOptSymbol *flag; + flag = stack_pointer[-1]; + if (sym_is_const(flag)) { + PyObject *value = sym_get_const(flag); +@@ -2361,7 +2305,7 @@ + } + + case _GUARD_IS_FALSE_POP: { +- _Py_UopsSymbol *flag; ++ JitOptSymbol *flag; + flag = stack_pointer[-1]; + if (sym_is_const(flag)) { + PyObject *value = sym_get_const(flag); +@@ -2378,7 +2322,7 @@ + } + + case _GUARD_IS_NONE_POP: { +- _Py_UopsSymbol *flag; ++ JitOptSymbol *flag; + flag = stack_pointer[-1]; + if (sym_is_const(flag)) { + PyObject *value = sym_get_const(flag); +@@ -2403,7 +2347,7 @@ + } + + case _GUARD_IS_NOT_NONE_POP: { +- _Py_UopsSymbol *flag; ++ JitOptSymbol *flag; + flag = stack_pointer[-1]; + if (sym_is_const(flag)) { + PyObject *value = sym_get_const(flag); +@@ -2461,7 +2405,7 @@ + } + + case _LOAD_CONST_INLINE: { +- _Py_UopsSymbol *value; ++ JitOptSymbol *value; + PyObject *ptr = (PyObject *)this_instr->operand0; + value = sym_new_const(ctx, ptr); + stack_pointer[0] = value; +@@ -2471,7 +2415,7 @@ + } + + case _LOAD_CONST_INLINE_BORROW: { +- _Py_UopsSymbol *value; ++ JitOptSymbol *value; + PyObject *ptr = (PyObject *)this_instr->operand0; + value = sym_new_const(ctx, ptr); + stack_pointer[0] = value; +@@ -2481,85 +2425,38 @@ + } + + case _POP_TOP_LOAD_CONST_INLINE_BORROW: { +- _Py_UopsSymbol *value; ++ JitOptSymbol *value; + value = sym_new_not_null(ctx); + stack_pointer[-1] = value; + break; + } + +- case _LOAD_CONST_INLINE_WITH_NULL: { +- _Py_UopsSymbol *value; +- _Py_UopsSymbol *null; +- PyObject *ptr = (PyObject *)this_instr->operand0; +- value = sym_new_const(ctx, ptr); +- null = sym_new_null(ctx); +- stack_pointer[0] = value; +- stack_pointer[1] = null; +- stack_pointer += 2; +- assert(WITHIN_STACK_BOUNDS()); +- break; +- } +- +- case _LOAD_CONST_INLINE_BORROW_WITH_NULL: { +- _Py_UopsSymbol *value; +- _Py_UopsSymbol *null; +- PyObject *ptr = (PyObject *)this_instr->operand0; +- value = sym_new_const(ctx, ptr); +- null = sym_new_null(ctx); +- stack_pointer[0] = value; +- stack_pointer[1] = null; +- stack_pointer += 2; +- assert(WITHIN_STACK_BOUNDS()); +- break; +- } +- + case _CHECK_FUNCTION: { + break; + } + + case _LOAD_GLOBAL_MODULE: { +- _Py_UopsSymbol *res; +- _Py_UopsSymbol *null = NULL; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); +- null = sym_new_null(ctx); + stack_pointer[0] = res; +- if (oparg & 1) stack_pointer[1] = null; +- stack_pointer += 1 + (oparg & 1); ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } + + case _LOAD_GLOBAL_BUILTINS: { +- _Py_UopsSymbol *res; +- _Py_UopsSymbol *null = NULL; ++ JitOptSymbol *res; + res = sym_new_not_null(ctx); +- null = sym_new_null(ctx); + stack_pointer[0] = res; +- if (oparg & 1) stack_pointer[1] = null; +- stack_pointer += 1 + (oparg & 1); ++ stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } + + case _LOAD_ATTR_MODULE: { +- _Py_UopsSymbol *attr; +- _Py_UopsSymbol *null = NULL; ++ JitOptSymbol *attr; + attr = sym_new_not_null(ctx); +- null = sym_new_null(ctx); + stack_pointer[-1] = attr; +- if (oparg & 1) stack_pointer[0] = null; +- stack_pointer += (oparg & 1); +- assert(WITHIN_STACK_BOUNDS()); +- break; +- } +- +- case _INTERNAL_INCREMENT_OPT_COUNTER: { +- stack_pointer += -1; +- assert(WITHIN_STACK_BOUNDS()); +- break; +- } +- +- case _DYNAMIC_EXIT: { + break; + } + +@@ -2584,8 +2481,6 @@ + } + + case _ERROR_POP_N: { +- stack_pointer += -oparg; +- assert(WITHIN_STACK_BOUNDS()); + break; + } + +diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c +index 40cbf95e3d6..dcde8e7ce81 100644 +--- a/Python/optimizer_symbols.c ++++ b/Python/optimizer_symbols.c +@@ -28,11 +28,6 @@ + - Bottom: IS_NULL and NOT_NULL flags set, type and const_val NULL. + */ + +-// Flags for below. +-#define IS_NULL 1 << 0 +-#define NOT_NULL 1 << 1 +-#define NO_SPACE 1 << 2 +- + #ifdef Py_DEBUG + static inline int get_lltrace(void) { + char *uop_debug = Py_GETENV("PYTHON_OPT_DEBUG"); +@@ -48,187 +43,254 @@ + #define DPRINTF(level, ...) + #endif + +-static _Py_UopsSymbol NO_SPACE_SYMBOL = { +- .flags = IS_NULL | NOT_NULL | NO_SPACE, +- .typ = NULL, +- .const_val = NULL, +- .type_version = 0, ++ ++static JitOptSymbol NO_SPACE_SYMBOL = { ++ .tag = JIT_SYM_BOTTOM_TAG + }; + +-_Py_UopsSymbol * +-out_of_space(_Py_UOpsContext *ctx) ++JitOptSymbol * ++out_of_space(JitOptContext *ctx) + { + ctx->done = true; + ctx->out_of_space = true; + return &NO_SPACE_SYMBOL; + } + +-static _Py_UopsSymbol * +-sym_new(_Py_UOpsContext *ctx) ++static JitOptSymbol * ++sym_new(JitOptContext *ctx) + { +- _Py_UopsSymbol *self = &ctx->t_arena.arena[ctx->t_arena.ty_curr_number]; ++ JitOptSymbol *self = &ctx->t_arena.arena[ctx->t_arena.ty_curr_number]; + if (ctx->t_arena.ty_curr_number >= ctx->t_arena.ty_max_number) { + OPT_STAT_INC(optimizer_failure_reason_no_memory); + DPRINTF(1, "out of space for symbolic expression type\n"); + return NULL; + } + ctx->t_arena.ty_curr_number++; +- self->flags = 0; +- self->typ = NULL; +- self->const_val = NULL; +- self->type_version = 0; +- ++ self->tag = JIT_SYM_UNKNOWN_TAG; + return self; + } + + static inline void +-sym_set_flag(_Py_UopsSymbol *sym, int flag) +-{ +- sym->flags |= flag; +-} +- +-static inline void +-sym_set_bottom(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym) ++sym_set_bottom(JitOptContext *ctx, JitOptSymbol *sym) + { +- sym_set_flag(sym, IS_NULL | NOT_NULL); +- sym->typ = NULL; +- Py_CLEAR(sym->const_val); ++ sym->tag = JIT_SYM_BOTTOM_TAG; + ctx->done = true; + ctx->contradiction = true; + } + + bool +-_Py_uop_sym_is_bottom(_Py_UopsSymbol *sym) ++_Py_uop_sym_is_bottom(JitOptSymbol *sym) + { +- if ((sym->flags & IS_NULL) && (sym->flags & NOT_NULL)) { +- assert(sym->flags == (IS_NULL | NOT_NULL)); +- assert(sym->typ == NULL); +- assert(sym->const_val == NULL); +- return true; +- } +- return false; ++ return sym->tag == JIT_SYM_BOTTOM_TAG; + } + + bool +-_Py_uop_sym_is_not_null(_Py_UopsSymbol *sym) +-{ +- return sym->flags == NOT_NULL; ++_Py_uop_sym_is_not_null(JitOptSymbol *sym) { ++ return sym->tag == JIT_SYM_NON_NULL_TAG || sym->tag > JIT_SYM_BOTTOM_TAG; + } + + bool +-_Py_uop_sym_is_null(_Py_UopsSymbol *sym) ++_Py_uop_sym_is_const(JitOptSymbol *sym) + { +- return sym->flags == IS_NULL; ++ return sym->tag == JIT_SYM_KNOWN_VALUE_TAG; + } + + bool +-_Py_uop_sym_is_const(_Py_UopsSymbol *sym) ++_Py_uop_sym_is_null(JitOptSymbol *sym) + { +- return sym->const_val != NULL; ++ return sym->tag == JIT_SYM_NULL_TAG; + } + ++ + PyObject * +-_Py_uop_sym_get_const(_Py_UopsSymbol *sym) ++_Py_uop_sym_get_const(JitOptSymbol *sym) + { +- return sym->const_val; ++ if (sym->tag == JIT_SYM_KNOWN_VALUE_TAG) { ++ return sym->value.value; ++ } ++ return NULL; + } + + void +-_Py_uop_sym_set_type(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym, PyTypeObject *typ) ++_Py_uop_sym_set_type(JitOptContext *ctx, JitOptSymbol *sym, PyTypeObject *typ) + { +- assert(typ != NULL && PyType_Check(typ)); +- if (sym->flags & IS_NULL) { +- sym_set_bottom(ctx, sym); +- return; +- } +- if (sym->typ != NULL) { +- if (sym->typ != typ) { ++ JitSymType tag = sym->tag; ++ switch(tag) { ++ case JIT_SYM_NULL_TAG: + sym_set_bottom(ctx, sym); + return; +- } +- } +- else { +- sym_set_flag(sym, NOT_NULL); +- sym->typ = typ; ++ case JIT_SYM_KNOWN_CLASS_TAG: ++ if (sym->cls.type != typ) { ++ sym_set_bottom(ctx, sym); ++ } ++ return; ++ case JIT_SYM_TYPE_VERSION_TAG: ++ if (sym->version.version == typ->tp_version_tag) { ++ sym->tag = JIT_SYM_KNOWN_CLASS_TAG; ++ sym->cls.type = typ; ++ sym->cls.version = typ->tp_version_tag; ++ } ++ else { ++ sym_set_bottom(ctx, sym); ++ } ++ return; ++ case JIT_SYM_KNOWN_VALUE_TAG: ++ if (Py_TYPE(sym->value.value) != typ) { ++ Py_CLEAR(sym->value.value); ++ sym_set_bottom(ctx, sym); ++ } ++ return; ++ case JIT_SYM_TUPLE_TAG: ++ if (typ != &PyTuple_Type) { ++ sym_set_bottom(ctx, sym); ++ } ++ return; ++ case JIT_SYM_BOTTOM_TAG: ++ return; ++ case JIT_SYM_NON_NULL_TAG: ++ case JIT_SYM_UNKNOWN_TAG: ++ sym->tag = JIT_SYM_KNOWN_CLASS_TAG; ++ sym->cls.version = 0; ++ sym->cls.type = typ; ++ return; + } + } + + bool +-_Py_uop_sym_set_type_version(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym, unsigned int version) ++_Py_uop_sym_set_type_version(JitOptContext *ctx, JitOptSymbol *sym, unsigned int version) + { +- // if the type version was already set, then it must be different and we should set it to bottom +- if (sym->type_version) { +- sym_set_bottom(ctx, sym); +- return false; ++ JitSymType tag = sym->tag; ++ switch(tag) { ++ case JIT_SYM_NULL_TAG: ++ sym_set_bottom(ctx, sym); ++ return false; ++ case JIT_SYM_KNOWN_CLASS_TAG: ++ if (sym->cls.type->tp_version_tag != version) { ++ sym_set_bottom(ctx, sym); ++ return false; ++ } ++ else { ++ sym->cls.version = version; ++ return true; ++ } ++ case JIT_SYM_KNOWN_VALUE_TAG: ++ Py_CLEAR(sym->value.value); ++ sym_set_bottom(ctx, sym); ++ return false; ++ case JIT_SYM_TUPLE_TAG: ++ sym_set_bottom(ctx, sym); ++ return false; ++ case JIT_SYM_TYPE_VERSION_TAG: ++ if (sym->version.version == version) { ++ return true; ++ } ++ sym_set_bottom(ctx, sym); ++ return false; ++ case JIT_SYM_BOTTOM_TAG: ++ return false; ++ case JIT_SYM_NON_NULL_TAG: ++ case JIT_SYM_UNKNOWN_TAG: ++ sym->tag = JIT_SYM_TYPE_VERSION_TAG; ++ sym->version.version = version; ++ return true; + } +- sym->type_version = version; +- return true; ++ Py_UNREACHABLE(); ++} ++ ++static void make_const(JitOptSymbol *sym, PyObject *val) ++{ ++ sym->tag = JIT_SYM_KNOWN_VALUE_TAG; ++ sym->value.value = Py_NewRef(val); + } + + void +-_Py_uop_sym_set_const(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym, PyObject *const_val) ++_Py_uop_sym_set_const(JitOptContext *ctx, JitOptSymbol *sym, PyObject *const_val) + { +- assert(const_val != NULL); +- if (sym->flags & IS_NULL) { +- sym_set_bottom(ctx, sym); +- } +- PyTypeObject *typ = Py_TYPE(const_val); +- if (sym->typ != NULL && sym->typ != typ) { +- sym_set_bottom(ctx, sym); +- } +- if (sym->const_val != NULL) { +- if (sym->const_val != const_val) { +- // TODO: What if they're equal? ++ JitSymType tag = sym->tag; ++ switch(tag) { ++ case JIT_SYM_NULL_TAG: + sym_set_bottom(ctx, sym); +- } +- } +- else { +- sym_set_flag(sym, NOT_NULL); +- sym->typ = typ; +- sym->const_val = Py_NewRef(const_val); ++ return; ++ case JIT_SYM_KNOWN_CLASS_TAG: ++ if (sym->cls.type != Py_TYPE(const_val)) { ++ sym_set_bottom(ctx, sym); ++ return; ++ } ++ make_const(sym, const_val); ++ return; ++ case JIT_SYM_KNOWN_VALUE_TAG: ++ if (sym->value.value != const_val) { ++ Py_CLEAR(sym->value.value); ++ sym_set_bottom(ctx, sym); ++ } ++ return; ++ case JIT_SYM_TUPLE_TAG: ++ sym_set_bottom(ctx, sym); ++ return; ++ case JIT_SYM_TYPE_VERSION_TAG: ++ if (sym->version.version != Py_TYPE(const_val)->tp_version_tag) { ++ sym_set_bottom(ctx, sym); ++ return; ++ } ++ make_const(sym, const_val); ++ return; ++ case JIT_SYM_BOTTOM_TAG: ++ return; ++ case JIT_SYM_NON_NULL_TAG: ++ case JIT_SYM_UNKNOWN_TAG: ++ make_const(sym, const_val); ++ return; + } + } + + void +-_Py_uop_sym_set_null(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym) ++_Py_uop_sym_set_null(JitOptContext *ctx, JitOptSymbol *sym) + { +- if (_Py_uop_sym_is_not_null(sym)) { ++ if (sym->tag == JIT_SYM_UNKNOWN_TAG) { ++ sym->tag = JIT_SYM_NULL_TAG; ++ } ++ else if (sym->tag > JIT_SYM_NULL_TAG) { + sym_set_bottom(ctx, sym); + } +- sym_set_flag(sym, IS_NULL); + } + + void +-_Py_uop_sym_set_non_null(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym) ++_Py_uop_sym_set_non_null(JitOptContext *ctx, JitOptSymbol *sym) + { +- if (_Py_uop_sym_is_null(sym)) { ++ if (sym->tag == JIT_SYM_UNKNOWN_TAG) { ++ sym->tag = JIT_SYM_NON_NULL_TAG; ++ } ++ else if (sym->tag == JIT_SYM_NULL_TAG) { + sym_set_bottom(ctx, sym); + } +- sym_set_flag(sym, NOT_NULL); + } + + +-_Py_UopsSymbol * +-_Py_uop_sym_new_unknown(_Py_UOpsContext *ctx) ++JitOptSymbol * ++_Py_uop_sym_new_unknown(JitOptContext *ctx) + { +- return sym_new(ctx); ++ JitOptSymbol *res = sym_new(ctx); ++ if (res == NULL) { ++ return out_of_space(ctx); ++ } ++ return res; + } + +-_Py_UopsSymbol * +-_Py_uop_sym_new_not_null(_Py_UOpsContext *ctx) ++JitOptSymbol * ++_Py_uop_sym_new_not_null(JitOptContext *ctx) + { +- _Py_UopsSymbol *res = _Py_uop_sym_new_unknown(ctx); ++ JitOptSymbol *res = sym_new(ctx); + if (res == NULL) { + return out_of_space(ctx); + } +- sym_set_flag(res, NOT_NULL); ++ res->tag = JIT_SYM_NON_NULL_TAG; + return res; + } + +-_Py_UopsSymbol * +-_Py_uop_sym_new_type(_Py_UOpsContext *ctx, PyTypeObject *typ) ++JitOptSymbol * ++_Py_uop_sym_new_type(JitOptContext *ctx, PyTypeObject *typ) + { +- _Py_UopsSymbol *res = sym_new(ctx); ++ JitOptSymbol *res = sym_new(ctx); + if (res == NULL) { + return out_of_space(ctx); + } +@@ -237,11 +299,11 @@ + } + + // Adds a new reference to const_val, owned by the symbol. +-_Py_UopsSymbol * +-_Py_uop_sym_new_const(_Py_UOpsContext *ctx, PyObject *const_val) ++JitOptSymbol * ++_Py_uop_sym_new_const(JitOptContext *ctx, PyObject *const_val) + { + assert(const_val != NULL); +- _Py_UopsSymbol *res = sym_new(ctx); ++ JitOptSymbol *res = sym_new(ctx); + if (res == NULL) { + return out_of_space(ctx); + } +@@ -249,10 +311,10 @@ + return res; + } + +-_Py_UopsSymbol * +-_Py_uop_sym_new_null(_Py_UOpsContext *ctx) ++JitOptSymbol * ++_Py_uop_sym_new_null(JitOptContext *ctx) + { +- _Py_UopsSymbol *null_sym = _Py_uop_sym_new_unknown(ctx); ++ JitOptSymbol *null_sym = sym_new(ctx); + if (null_sym == NULL) { + return out_of_space(ctx); + } +@@ -261,64 +323,105 @@ + } + + PyTypeObject * +-_Py_uop_sym_get_type(_Py_UopsSymbol *sym) ++_Py_uop_sym_get_type(JitOptSymbol *sym) + { +- if (_Py_uop_sym_is_bottom(sym)) { +- return NULL; +- } +- return sym->typ; ++ JitSymType tag = sym->tag; ++ switch(tag) { ++ case JIT_SYM_NULL_TAG: ++ case JIT_SYM_TYPE_VERSION_TAG: ++ case JIT_SYM_BOTTOM_TAG: ++ case JIT_SYM_NON_NULL_TAG: ++ case JIT_SYM_UNKNOWN_TAG: ++ return NULL; ++ case JIT_SYM_KNOWN_CLASS_TAG: ++ return sym->cls.type; ++ case JIT_SYM_KNOWN_VALUE_TAG: ++ return Py_TYPE(sym->value.value); ++ case JIT_SYM_TUPLE_TAG: ++ return &PyTuple_Type; ++ } ++ Py_UNREACHABLE(); + } + + unsigned int +-_Py_uop_sym_get_type_version(_Py_UopsSymbol *sym) ++_Py_uop_sym_get_type_version(JitOptSymbol *sym) + { +- return sym->type_version; ++ JitSymType tag = sym->tag; ++ switch(tag) { ++ case JIT_SYM_NULL_TAG: ++ case JIT_SYM_BOTTOM_TAG: ++ case JIT_SYM_NON_NULL_TAG: ++ case JIT_SYM_UNKNOWN_TAG: ++ return 0; ++ case JIT_SYM_TYPE_VERSION_TAG: ++ return sym->version.version; ++ case JIT_SYM_KNOWN_CLASS_TAG: ++ return sym->cls.version; ++ case JIT_SYM_KNOWN_VALUE_TAG: ++ return Py_TYPE(sym->value.value)->tp_version_tag; ++ case JIT_SYM_TUPLE_TAG: ++ return PyTuple_Type.tp_version_tag; ++ } ++ Py_UNREACHABLE(); + } + + bool +-_Py_uop_sym_has_type(_Py_UopsSymbol *sym) ++_Py_uop_sym_has_type(JitOptSymbol *sym) + { +- if (_Py_uop_sym_is_bottom(sym)) { +- return false; +- } +- return sym->typ != NULL; ++ JitSymType tag = sym->tag; ++ switch(tag) { ++ case JIT_SYM_NULL_TAG: ++ case JIT_SYM_TYPE_VERSION_TAG: ++ case JIT_SYM_BOTTOM_TAG: ++ case JIT_SYM_NON_NULL_TAG: ++ case JIT_SYM_UNKNOWN_TAG: ++ return false; ++ case JIT_SYM_KNOWN_CLASS_TAG: ++ case JIT_SYM_KNOWN_VALUE_TAG: ++ case JIT_SYM_TUPLE_TAG: ++ return true; ++ } ++ Py_UNREACHABLE(); + } + + bool +-_Py_uop_sym_matches_type(_Py_UopsSymbol *sym, PyTypeObject *typ) ++_Py_uop_sym_matches_type(JitOptSymbol *sym, PyTypeObject *typ) + { + assert(typ != NULL && PyType_Check(typ)); + return _Py_uop_sym_get_type(sym) == typ; + } + + bool +-_Py_uop_sym_matches_type_version(_Py_UopsSymbol *sym, unsigned int version) ++_Py_uop_sym_matches_type_version(JitOptSymbol *sym, unsigned int version) + { + return _Py_uop_sym_get_type_version(sym) == version; + } + +- + int +-_Py_uop_sym_truthiness(_Py_UopsSymbol *sym) +-{ +- /* There are some non-constant values for +- * which `bool(val)` always evaluates to +- * True or False, such as tuples with known +- * length, but unknown contents, or bound-methods. +- * This function will need updating +- * should we support those values. +- */ +- if (_Py_uop_sym_is_bottom(sym)) { +- return -1; +- } +- if (!_Py_uop_sym_is_const(sym)) { +- return -1; +- } +- PyObject *value = _Py_uop_sym_get_const(sym); ++_Py_uop_sym_truthiness(JitOptSymbol *sym) ++{ ++ switch(sym->tag) { ++ case JIT_SYM_NULL_TAG: ++ case JIT_SYM_TYPE_VERSION_TAG: ++ case JIT_SYM_BOTTOM_TAG: ++ case JIT_SYM_NON_NULL_TAG: ++ case JIT_SYM_UNKNOWN_TAG: ++ return -1; ++ case JIT_SYM_KNOWN_CLASS_TAG: ++ /* TODO : ++ * Instances of some classes are always ++ * true. We should return 1 in those cases */ ++ return -1; ++ case JIT_SYM_KNOWN_VALUE_TAG: ++ break; ++ case JIT_SYM_TUPLE_TAG: ++ return sym->tuple.length != 0; ++ } ++ PyObject *value = sym->value.value; ++ /* Only handle a few known safe types */ + if (value == Py_None) { + return 0; + } +- /* Only handle a few known safe types */ + PyTypeObject *tp = Py_TYPE(value); + if (tp == &PyLong_Type) { + return !_PyLong_IsZero((PyLongObject *)value); +@@ -332,13 +435,84 @@ + return -1; + } + ++static JitOptSymbol * ++allocation_base(JitOptContext *ctx) ++{ ++ return ctx->t_arena.arena; ++} ++ ++JitOptSymbol * ++_Py_uop_sym_new_tuple(JitOptContext *ctx, int size, JitOptSymbol **args) ++{ ++ JitOptSymbol *res = sym_new(ctx); ++ if (res == NULL) { ++ return out_of_space(ctx); ++ } ++ if (size > MAX_SYMBOLIC_TUPLE_SIZE) { ++ res->tag = JIT_SYM_KNOWN_CLASS_TAG; ++ res->cls.type = &PyTuple_Type; ++ } ++ else { ++ res->tag = JIT_SYM_TUPLE_TAG; ++ res->tuple.length = size; ++ for (int i = 0; i < size; i++) { ++ res->tuple.items[i] = (uint16_t)(args[i] - allocation_base(ctx)); ++ } ++ } ++ return res; ++} ++ ++JitOptSymbol * ++_Py_uop_sym_tuple_getitem(JitOptContext *ctx, JitOptSymbol *sym, int item) ++{ ++ assert(item >= 0); ++ if (sym->tag == JIT_SYM_KNOWN_VALUE_TAG) { ++ PyObject *tuple = sym->value.value; ++ if (PyTuple_CheckExact(tuple) && item < PyTuple_GET_SIZE(tuple)) { ++ return _Py_uop_sym_new_const(ctx, PyTuple_GET_ITEM(tuple, item)); ++ } ++ } ++ else if (sym->tag == JIT_SYM_TUPLE_TAG && item < sym->tuple.length) { ++ return allocation_base(ctx) + sym->tuple.items[item]; ++ } ++ return _Py_uop_sym_new_unknown(ctx); ++} ++ ++int ++_Py_uop_sym_tuple_length(JitOptSymbol *sym) ++{ ++ if (sym->tag == JIT_SYM_KNOWN_VALUE_TAG) { ++ PyObject *tuple = sym->value.value; ++ if (PyTuple_CheckExact(tuple)) { ++ return PyTuple_GET_SIZE(tuple); ++ } ++ } ++ else if (sym->tag == JIT_SYM_TUPLE_TAG) { ++ return sym->tuple.length; ++ } ++ return -1; ++} ++ ++// Return true if known to be immortal. ++bool ++_Py_uop_sym_is_immortal(JitOptSymbol *sym) ++{ ++ if (sym->tag == JIT_SYM_KNOWN_VALUE_TAG) { ++ return _Py_IsImmortal(sym->value.value); ++ } ++ if (sym->tag == JIT_SYM_KNOWN_CLASS_TAG) { ++ return sym->cls.type == &PyBool_Type; ++ } ++ return false; ++} ++ + // 0 on success, -1 on error. + _Py_UOpsAbstractFrame * + _Py_uop_frame_new( +- _Py_UOpsContext *ctx, ++ JitOptContext *ctx, + PyCodeObject *co, + int curr_stackentries, +- _Py_UopsSymbol **args, ++ JitOptSymbol **args, + int arg_len) + { + assert(ctx->curr_frame_depth < MAX_ABSTRACT_FRAME_DEPTH); +@@ -363,14 +537,14 @@ + } + + for (int i = arg_len; i < co->co_nlocalsplus; i++) { +- _Py_UopsSymbol *local = _Py_uop_sym_new_unknown(ctx); ++ JitOptSymbol *local = _Py_uop_sym_new_unknown(ctx); + frame->locals[i] = local; + } + + + // Initialize the stack as well + for (int i = 0; i < curr_stackentries; i++) { +- _Py_UopsSymbol *stackvar = _Py_uop_sym_new_unknown(ctx); ++ JitOptSymbol *stackvar = _Py_uop_sym_new_unknown(ctx); + frame->stack[i] = stackvar; + } + +@@ -378,7 +552,7 @@ + } + + void +-_Py_uop_abstractcontext_fini(_Py_UOpsContext *ctx) ++_Py_uop_abstractcontext_fini(JitOptContext *ctx) + { + if (ctx == NULL) { + return; +@@ -386,13 +560,17 @@ + ctx->curr_frame_depth = 0; + int tys = ctx->t_arena.ty_curr_number; + for (int i = 0; i < tys; i++) { +- Py_CLEAR(ctx->t_arena.arena[i].const_val); ++ JitOptSymbol *sym = &ctx->t_arena.arena[i]; ++ if (sym->tag == JIT_SYM_KNOWN_VALUE_TAG) { ++ Py_CLEAR(sym->value.value); ++ } + } + } + + void +-_Py_uop_abstractcontext_init(_Py_UOpsContext *ctx) ++_Py_uop_abstractcontext_init(JitOptContext *ctx) + { ++ static_assert(sizeof(JitOptSymbol) <= 2*sizeof(uint64_t)); + ctx->limit = ctx->locals_and_stack + MAX_ABSTRACT_INTERP_SIZE; + ctx->n_consumed = ctx->locals_and_stack; + #ifdef Py_DEBUG // Aids debugging a little. There should never be NULL in the abstract interpreter. +@@ -410,7 +588,7 @@ + } + + int +-_Py_uop_frame_pop(_Py_UOpsContext *ctx) ++_Py_uop_frame_pop(JitOptContext *ctx) + { + _Py_UOpsAbstractFrame *frame = ctx->frame; + ctx->n_consumed = frame->locals; +@@ -431,26 +609,25 @@ + } \ + } while (0) + +-static _Py_UopsSymbol * +-make_bottom(_Py_UOpsContext *ctx) ++static JitOptSymbol * ++make_bottom(JitOptContext *ctx) + { +- _Py_UopsSymbol *sym = _Py_uop_sym_new_unknown(ctx); +- _Py_uop_sym_set_null(ctx, sym); +- _Py_uop_sym_set_non_null(ctx, sym); ++ JitOptSymbol *sym = sym_new(ctx); ++ sym->tag = JIT_SYM_BOTTOM_TAG; + return sym; + } + + PyObject * + _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) + { +- _Py_UOpsContext context; +- _Py_UOpsContext *ctx = &context; ++ JitOptContext context; ++ JitOptContext *ctx = &context; + _Py_uop_abstractcontext_init(ctx); + PyObject *val_42 = NULL; + PyObject *val_43 = NULL; + + // Use a single 'sym' variable so copy-pasting tests is easier. +- _Py_UopsSymbol *sym = _Py_uop_sym_new_unknown(ctx); ++ JitOptSymbol *sym = _Py_uop_sym_new_unknown(ctx); + if (sym == NULL) { + goto fail; + } +@@ -510,6 +687,7 @@ + TEST_PREDICATE(_Py_uop_sym_is_const(sym), "42 is not a constant"); + TEST_PREDICATE(_Py_uop_sym_get_const(sym) != NULL, "42 as constant is NULL"); + TEST_PREDICATE(_Py_uop_sym_get_const(sym) == val_42, "42 as constant isn't 42"); ++ TEST_PREDICATE(_Py_uop_sym_is_immortal(sym), "42 is not immortal"); + + _Py_uop_sym_set_type(ctx, sym, &PyLong_Type); // Should be a no-op + TEST_PREDICATE(_Py_uop_sym_matches_type(sym, &PyLong_Type), "(42 and 42) isn't an int"); +@@ -518,6 +696,9 @@ + _Py_uop_sym_set_type(ctx, sym, &PyFloat_Type); // Should make it bottom + TEST_PREDICATE(_Py_uop_sym_is_bottom(sym), "(42 and float) isn't bottom"); + ++ sym = _Py_uop_sym_new_type(ctx, &PyBool_Type); ++ TEST_PREDICATE(_Py_uop_sym_is_immortal(sym), "a bool is not immortal"); ++ + sym = _Py_uop_sym_new_type(ctx, &PyLong_Type); + if (sym == NULL) { + goto fail; +@@ -534,15 +715,37 @@ + sym = _Py_uop_sym_new_const(ctx, PyLong_FromLong(0)); + TEST_PREDICATE(_Py_uop_sym_truthiness(sym) == 0, "bool(0) is not False"); + ++ JitOptSymbol *i1 = _Py_uop_sym_new_type(ctx, &PyFloat_Type); ++ JitOptSymbol *i2 = _Py_uop_sym_new_const(ctx, val_43); ++ JitOptSymbol *array[2] = { i1, i2 }; ++ sym = _Py_uop_sym_new_tuple(ctx, 2, array); ++ TEST_PREDICATE( ++ _Py_uop_sym_matches_type(_Py_uop_sym_tuple_getitem(ctx, sym, 0), &PyFloat_Type), ++ "tuple item does not match value used to create tuple" ++ ); ++ TEST_PREDICATE( ++ _Py_uop_sym_get_const(_Py_uop_sym_tuple_getitem(ctx, sym, 1)) == val_43, ++ "tuple item does not match value used to create tuple" ++ ); ++ PyObject *pair[2] = { val_42, val_43 }; ++ PyObject *tuple = _PyTuple_FromArray(pair, 2); ++ sym = _Py_uop_sym_new_const(ctx, tuple); ++ TEST_PREDICATE( ++ _Py_uop_sym_get_const(_Py_uop_sym_tuple_getitem(ctx, sym, 1)) == val_43, ++ "tuple item does not match value used to create tuple" ++ ); ++ + _Py_uop_abstractcontext_fini(ctx); + Py_DECREF(val_42); + Py_DECREF(val_43); ++ Py_DECREF(tuple); + Py_RETURN_NONE; + + fail: + _Py_uop_abstractcontext_fini(ctx); + Py_XDECREF(val_42); + Py_XDECREF(val_43); ++ Py_DECREF(tuple); + return NULL; + } + +diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c +index 06418123d6d..300a871d2cc 100644 +--- a/Python/pylifecycle.c ++++ b/Python/pylifecycle.c +@@ -46,8 +46,25 @@ + + #if defined(__APPLE__) + # include ++# include + # include +-# include ++// The os_log unified logging APIs were introduced in macOS 10.12, iOS 10.0, ++// tvOS 10.0, and watchOS 3.0; ++# if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE ++# define HAS_APPLE_SYSTEM_LOG 1 ++# elif defined(TARGET_OS_OSX) && TARGET_OS_OSX ++# if defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12 ++# define HAS_APPLE_SYSTEM_LOG 1 ++# else ++# define HAS_APPLE_SYSTEM_LOG 0 ++# endif ++# else ++# define HAS_APPLE_SYSTEM_LOG 0 ++# endif ++ ++# if HAS_APPLE_SYSTEM_LOG ++# include ++# endif + #endif + + #ifdef HAVE_SIGNAL_H +@@ -77,7 +94,7 @@ + #ifdef __ANDROID__ + static PyStatus init_android_streams(PyThreadState *tstate); + #endif +-#if defined(__APPLE__) ++#if defined(__APPLE__) && HAS_APPLE_SYSTEM_LOG + static PyStatus init_apple_streams(PyThreadState *tstate); + #endif + static void wait_for_thread_shutdown(PyThreadState *tstate); +@@ -94,23 +111,7 @@ + _Py_COMP_DIAG_PUSH + _Py_COMP_DIAG_IGNORE_DEPR_DECLS + +-#if defined(MS_WINDOWS) +- +-#pragma section("PyRuntime", read, write) +-__declspec(allocate("PyRuntime")) +- +-#elif defined(__APPLE__) +- +-__attribute__(( +- section(SEG_DATA ",PyRuntime") +-)) +- +-#endif +- +-_PyRuntimeState _PyRuntime +-#if defined(__linux__) && (defined(__GNUC__) || defined(__clang__)) +-__attribute__ ((section (".PyRuntime"))) +-#endif ++GENERATE_DEBUG_SECTION(PyRuntime, _PyRuntimeState _PyRuntime) + = _PyRuntimeState_INIT(_PyRuntime, _Py_Debug_Cookie); + _Py_COMP_DIAG_POP + +@@ -427,40 +428,6 @@ + } + + +-int +-_PyInterpreterState_SetConfig(const PyConfig *src_config) +-{ +- PyThreadState *tstate = _PyThreadState_GET(); +- int res = -1; +- +- PyConfig config; +- PyConfig_InitPythonConfig(&config); +- PyStatus status = _PyConfig_Copy(&config, src_config); +- if (_PyStatus_EXCEPTION(status)) { +- _PyErr_SetFromPyStatus(status); +- goto done; +- } +- +- status = _PyConfig_Read(&config, 1); +- if (_PyStatus_EXCEPTION(status)) { +- _PyErr_SetFromPyStatus(status); +- goto done; +- } +- +- status = _PyConfig_Copy(&tstate->interp->config, &config); +- if (_PyStatus_EXCEPTION(status)) { +- _PyErr_SetFromPyStatus(status); +- goto done; +- } +- +- res = interpreter_update_config(tstate, 0); +- +-done: +- PyConfig_Clear(&config); +- return res; +-} +- +- + /* Global initializations. Can be undone by Py_Finalize(). Don't + call this twice without an intervening Py_Finalize() call. + +@@ -690,7 +657,12 @@ + // the settings are loaded (so that feature_flags are set) but before + // any calls are made to obmalloc functions. + if (_PyMem_init_obmalloc(interp) < 0) { +- return _PyStatus_NO_MEMORY(); ++ return _PyStatus_NO_MEMORY(); ++ } ++ ++ status = _PyTraceMalloc_Init(); ++ if (_PyStatus_EXCEPTION(status)) { ++ return status; + } + + PyThreadState *tstate = _PyThreadState_New(interp, +@@ -1262,7 +1234,7 @@ + return status; + } + #endif +-#if defined(__APPLE__) ++#if defined(__APPLE__) && HAS_APPLE_SYSTEM_LOG + if (config->use_system_logger) { + status = init_apple_streams(tstate); + if (_PyStatus_EXCEPTION(status)) { +@@ -1334,14 +1306,7 @@ + } else + #endif + { +- PyObject *opt = _PyOptimizer_NewUOpOptimizer(); +- if (opt == NULL) { +- return _PyStatus_ERR("can't initialize optimizer"); +- } +- if (_Py_SetTier2Optimizer((_PyOptimizerObject *)opt)) { +- return _PyStatus_ERR("can't install optimizer"); +- } +- Py_DECREF(opt); ++ interp->jit = true; + } + } + } +@@ -1483,18 +1448,6 @@ + } + + +-PyStatus +-_Py_InitializeMain(void) +-{ +- PyStatus status = _PyRuntime_Initialize(); +- if (_PyStatus_EXCEPTION(status)) { +- return status; +- } +- PyThreadState *tstate = _PyThreadState_GET(); +- return pyinit_main(tstate); +-} +- +- + static void + finalize_modules_delete_special(PyThreadState *tstate, int verbose) + { +@@ -1522,13 +1475,15 @@ + PySys_WriteStderr("# clear builtins._\n"); + } + if (PyDict_SetItemString(interp->builtins, "_", Py_None) < 0) { +- PyErr_FormatUnraisable("Exception ignored on setting builtin variable _"); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "setting builtin variable _"); + } + + const char * const *p; + for (p = sys_deletes; *p != NULL; p++) { + if (_PySys_ClearAttrString(interp, *p, verbose) < 0) { +- PyErr_FormatUnraisable("Exception ignored on clearing sys.%s", *p); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "clearing sys.%s", *p); + } + } + for (p = sys_files; *p != NULL; p+=2) { +@@ -1539,13 +1494,15 @@ + } + PyObject *value; + if (PyDict_GetItemStringRef(interp->sysdict, orig_name, &value) < 0) { +- PyErr_FormatUnraisable("Exception ignored on restoring sys.%s", name); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "restoring sys.%s", name); + } + if (value == NULL) { + value = Py_NewRef(Py_None); + } + if (PyDict_SetItemString(interp->sysdict, name, value) < 0) { +- PyErr_FormatUnraisable("Exception ignored on restoring sys.%s", name); ++ PyErr_FormatUnraisable("Exception ignored while " ++ "restoring sys.%s", name); + } + Py_DECREF(value); + } +@@ -1557,7 +1514,7 @@ + { + PyObject *weaklist = PyList_New(0); + if (weaklist == NULL) { +- PyErr_FormatUnraisable("Exception ignored on removing modules"); ++ PyErr_FormatUnraisable("Exception ignored while removing modules"); + } + + #define STORE_MODULE_WEAKREF(name, mod) \ +@@ -1566,13 +1523,13 @@ + if (wr) { \ + PyObject *tup = PyTuple_Pack(2, name, wr); \ + if (!tup || PyList_Append(weaklist, tup) < 0) { \ +- PyErr_FormatUnraisable("Exception ignored on removing modules"); \ ++ PyErr_FormatUnraisable("Exception ignored while removing modules"); \ + } \ + Py_XDECREF(tup); \ + Py_DECREF(wr); \ + } \ + else { \ +- PyErr_FormatUnraisable("Exception ignored on removing modules"); \ ++ PyErr_FormatUnraisable("Exception ignored while removing modules"); \ + } \ + } + +@@ -1583,7 +1540,7 @@ + } \ + STORE_MODULE_WEAKREF(name, mod); \ + if (PyObject_SetItem(modules, name, Py_None) < 0) { \ +- PyErr_FormatUnraisable("Exception ignored on removing modules"); \ ++ PyErr_FormatUnraisable("Exception ignored while removing modules"); \ + } \ + } + +@@ -1597,14 +1554,14 @@ + else { + PyObject *iterator = PyObject_GetIter(modules); + if (iterator == NULL) { +- PyErr_FormatUnraisable("Exception ignored on removing modules"); ++ PyErr_FormatUnraisable("Exception ignored while removing modules"); + } + else { + PyObject *key; + while ((key = PyIter_Next(iterator))) { + PyObject *value = PyObject_GetItem(modules, key); + if (value == NULL) { +- PyErr_FormatUnraisable("Exception ignored on removing modules"); ++ PyErr_FormatUnraisable("Exception ignored while removing modules"); + continue; + } + CLEAR_MODULE(key, value); +@@ -1612,7 +1569,7 @@ + Py_DECREF(key); + } + if (PyErr_Occurred()) { +- PyErr_FormatUnraisable("Exception ignored on removing modules"); ++ PyErr_FormatUnraisable("Exception ignored while removing modules"); + } + Py_DECREF(iterator); + } +@@ -1632,7 +1589,7 @@ + } + else { + if (PyObject_CallMethodNoArgs(modules, &_Py_ID(clear)) == NULL) { +- PyErr_FormatUnraisable("Exception ignored on clearing sys.modules"); ++ PyErr_FormatUnraisable("Exception ignored while clearing sys.modules"); + } + } + } +@@ -1644,11 +1601,11 @@ + PyInterpreterState *interp = tstate->interp; + PyObject *dict = PyDict_Copy(interp->builtins); + if (dict == NULL) { +- PyErr_FormatUnraisable("Exception ignored on restoring builtins"); ++ PyErr_FormatUnraisable("Exception ignored while restoring builtins"); + } + PyDict_Clear(interp->builtins); + if (PyDict_Update(interp->builtins, interp->builtins_copy)) { +- PyErr_FormatUnraisable("Exception ignored on restoring builtins"); ++ PyErr_FormatUnraisable("Exception ignored while restoring builtins"); + } + Py_XDECREF(dict); + } +@@ -1705,11 +1662,10 @@ + { + PyInterpreterState *interp = tstate->interp; + ++ // Invalidate all executors and turn off JIT: ++ interp->jit = false; + #ifdef _Py_TIER2 +- // Invalidate all executors and turn off tier 2 optimizer + _Py_Executors_InvalidateAll(interp, 0); +- _PyOptimizerObject *old = _Py_SetOptimizer(interp, NULL); +- Py_XDECREF(old); + #endif + + // Stop watching __builtin__ modifications +@@ -1821,7 +1777,7 @@ + + if (fout != NULL && fout != Py_None && !file_is_closed(fout)) { + if (_PyFile_Flush(fout) < 0) { +- PyErr_FormatUnraisable("Exception ignored on flushing sys.stdout"); ++ PyErr_FormatUnraisable("Exception ignored while flushing sys.stdout"); + status = -1; + } + } +@@ -2206,6 +2162,7 @@ + + finalize_interp_clear(tstate); + ++ + #ifdef Py_TRACE_REFS + /* Display addresses (& refcnts) of all objects still alive. + * An address can be used to find the repr of the object, printed +@@ -2656,7 +2613,7 @@ + + #ifdef HAVE_WINDOWS_CONSOLE_IO + /* Windows console IO is always UTF-8 encoded */ +- PyTypeObject *winconsoleio_type = (PyTypeObject *)_PyImport_GetModuleAttr( ++ PyTypeObject *winconsoleio_type = (PyTypeObject *)PyImport_ImportModuleAttr( + &_Py_ID(_io), &_Py_ID(_WindowsConsoleIO)); + if (winconsoleio_type == NULL) { + goto error; +@@ -2761,7 +2718,7 @@ + goto error; + } + +- if (!(wrapper = _PyImport_GetModuleAttrString("io", "open"))) { ++ if (!(wrapper = PyImport_ImportModuleAttrString("io", "open"))) { + goto error; + } + +@@ -2946,7 +2903,7 @@ + + #endif // __ANDROID__ + +-#if defined(__APPLE__) ++#if defined(__APPLE__) && HAS_APPLE_SYSTEM_LOG + + static PyObject * + apple_log_write_impl(PyObject *self, PyObject *args) +@@ -2957,14 +2914,9 @@ + return NULL; + } + +- // Call the underlying Apple logging API. The os_log unified logging APIs +- // were introduced in macOS 10.12, iOS 10.0, tvOS 10.0, and watchOS 3.0; +- // this call is a no-op on older versions. +- #if TARGET_OS_IPHONE || (TARGET_OS_OSX && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12) + // Pass the user-provided text through explicit %s formatting + // to avoid % literals being interpreted as a formatting directive. + os_log_with_type(OS_LOG_DEFAULT, logtype, "%s", text); +- #endif + Py_RETURN_NONE; + } + +@@ -2999,7 +2951,6 @@ + if (result == NULL) { + goto error; + } +- + goto done; + + error: +@@ -3013,7 +2964,7 @@ + return status; + } + +-#endif // __APPLE__ ++#endif // __APPLE__ && HAS_APPLE_SYSTEM_LOG + + + static void +@@ -3023,7 +2974,11 @@ + PUTS(fd, "\n"); + + /* display the current Python stack */ ++#ifndef Py_GIL_DISABLED + _Py_DumpTracebackThreads(fd, interp, tstate); ++#else ++ _Py_DumpTraceback(fd, tstate); ++#endif + } + + /* Print the current exception (if an exception is set) with its traceback, +diff --git a/Python/pystate.c b/Python/pystate.c +index 839413a65a4..89a652850e9 100644 +--- a/Python/pystate.c ++++ b/Python/pystate.c +@@ -19,6 +19,7 @@ + #include "pycore_pymem.h" // _PyMem_SetDefaultAllocator() + #include "pycore_pystate.h" + #include "pycore_runtime_init.h" // _PyRuntimeState_INIT ++#include "pycore_stackref.h" // Py_STACKREF_DEBUG + #include "pycore_obmalloc.h" // _PyMem_obmalloc_state_on_heap() + #include "pycore_uniqueid.h" // _PyObject_FinalizePerThreadRefcounts() + +@@ -642,6 +643,8 @@ + _Py_brc_init_state(interp); + #endif + llist_init(&interp->mem_free_queue.head); ++ llist_init(&interp->asyncio_tasks_head); ++ interp->asyncio_tasks_lock = (PyMutex){0}; + for (int i = 0; i < _PY_MONITORING_UNGROUPED_EVENTS; i++) { + interp->monitors.tools[i] = 0; + } +@@ -654,15 +657,30 @@ + } + interp->sys_profile_initialized = false; + interp->sys_trace_initialized = false; +-#ifdef _Py_TIER2 +- (void)_Py_SetOptimizer(interp, NULL); ++ interp->jit = false; + interp->executor_list_head = NULL; + interp->trace_run_counter = JIT_CLEANUP_THRESHOLD; +-#endif + if (interp != &runtime->_main_interpreter) { + /* Fix the self-referential, statically initialized fields. */ + interp->dtoa = (struct _dtoa_state)_dtoa_state_INIT(interp); + } ++#if !defined(Py_GIL_DISABLED) && defined(Py_STACKREF_DEBUG) ++ interp->next_stackref = 1; ++ _Py_hashtable_allocator_t alloc = { ++ .malloc = malloc, ++ .free = free, ++ }; ++ interp->stackref_debug_table = _Py_hashtable_new_full( ++ _Py_hashtable_hash_ptr, ++ _Py_hashtable_compare_direct, ++ NULL, ++ NULL, ++ &alloc ++ ); ++ _Py_stackref_associate(interp, Py_None, PyStackRef_None); ++ _Py_stackref_associate(interp, Py_False, PyStackRef_False); ++ _Py_stackref_associate(interp, Py_True, PyStackRef_True); ++#endif + + interp->_initialized = 1; + return _PyStatus_OK(); +@@ -768,6 +786,11 @@ + return interp; + } + ++#if !defined(Py_GIL_DISABLED) && defined(Py_STACKREF_DEBUG) ++extern void ++_Py_stackref_report_leaks(PyInterpreterState *interp); ++#endif ++ + static void + interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) + { +@@ -806,12 +829,6 @@ + tstate->_status.cleared = 0; + } + +-#ifdef _Py_TIER2 +- _PyOptimizerObject *old = _Py_SetOptimizer(interp, NULL); +- assert(old != NULL); +- Py_DECREF(old); +-#endif +- + /* It is possible that any of the objects below have a finalizer + that runs Python code or otherwise relies on a thread state + or even the interpreter state. For now we trust that isn't +@@ -877,6 +894,12 @@ + Py_CLEAR(interp->sysdict); + Py_CLEAR(interp->builtins); + ++#if !defined(Py_GIL_DISABLED) && defined(Py_STACKREF_DEBUG) ++ _Py_stackref_report_leaks(interp); ++ _Py_hashtable_destroy(interp->stackref_debug_table); ++ interp->stackref_debug_table = NULL; ++#endif ++ + if (tstate->interp == interp) { + /* We are now safe to fix tstate->_status.cleared. */ + // XXX Do this (much) earlier? +@@ -1486,11 +1509,12 @@ + tstate->dict_global_version = 0; + + _tstate->asyncio_running_loop = NULL; ++ _tstate->asyncio_running_task = NULL; + + tstate->delete_later = NULL; + + llist_init(&_tstate->mem_free_queue); +- ++ llist_init(&_tstate->asyncio_tasks_head); + if (interp->stoptheworld.requested || _PyRuntime.stoptheworld.requested) { + // Start in the suspended state if there is an ongoing stop-the-world. + tstate->state = _Py_THREAD_SUSPENDED; +@@ -1668,6 +1692,15 @@ + Py_CLEAR(tstate->threading_local_sentinel); + + Py_CLEAR(((_PyThreadStateImpl *)tstate)->asyncio_running_loop); ++ Py_CLEAR(((_PyThreadStateImpl *)tstate)->asyncio_running_task); ++ ++ ++ PyMutex_Lock(&tstate->interp->asyncio_tasks_lock); ++ // merge any lingering tasks from thread state to interpreter's ++ // tasks list ++ llist_concat(&tstate->interp->asyncio_tasks_head, ++ &((_PyThreadStateImpl *)tstate)->asyncio_tasks_head); ++ PyMutex_Unlock(&tstate->interp->asyncio_tasks_lock); + + Py_CLEAR(tstate->dict); + Py_CLEAR(tstate->async_exc); +@@ -2851,24 +2884,9 @@ + } + + +-int +-_PyInterpreterState_GetConfigCopy(PyConfig *config) +-{ +- PyInterpreterState *interp = _PyInterpreterState_GET(); +- +- PyStatus status = _PyConfig_Copy(config, &interp->config); +- if (PyStatus_Exception(status)) { +- _PyErr_SetFromPyStatus(status); +- return -1; +- } +- return 0; +-} +- +- + const PyConfig* + _Py_GetConfig(void) + { +- assert(PyGILState_Check()); + PyThreadState *tstate = current_fast_get(); + _Py_EnsureTstateNotNULL(tstate); + return _PyInterpreterState_GetConfig(tstate->interp); +diff --git a/Python/pythonrun.c b/Python/pythonrun.c +index 31e065ff00d..ae0df9685ac 100644 +--- a/Python/pythonrun.c ++++ b/Python/pythonrun.c +@@ -467,7 +467,7 @@ + fclose(fp); + } + +- pyc_fp = _Py_fopen_obj(filename, "rb"); ++ pyc_fp = Py_fopen(filename, "rb"); + if (pyc_fp == NULL) { + fprintf(stderr, "python: Can't reopen .pyc file\n"); + goto done; +@@ -1108,22 +1108,15 @@ + int unhandled_keyboard_interrupt = _PyRuntime.signals.unhandled_keyboard_interrupt; + + // Try first with the stdlib traceback module +- PyObject *traceback_module = PyImport_ImportModule("traceback"); +- +- if (traceback_module == NULL) { +- goto fallback; +- } +- +- PyObject *print_exception_fn = PyObject_GetAttrString(traceback_module, "_print_exception_bltin"); +- ++ PyObject *print_exception_fn = PyImport_ImportModuleAttrString( ++ "traceback", ++ "_print_exception_bltin"); + if (print_exception_fn == NULL || !PyCallable_Check(print_exception_fn)) { +- Py_DECREF(traceback_module); + goto fallback; + } + + PyObject* result = PyObject_CallOneArg(print_exception_fn, value); + +- Py_DECREF(traceback_module); + Py_XDECREF(print_exception_fn); + if (result) { + Py_DECREF(result); +@@ -1371,27 +1364,18 @@ + } + + if (interactive_src) { +- PyObject *linecache_module = PyImport_ImportModule("linecache"); +- +- if (linecache_module == NULL) { +- Py_DECREF(co); +- Py_DECREF(interactive_filename); +- return NULL; +- } +- +- PyObject *print_tb_func = PyObject_GetAttrString(linecache_module, "_register_code"); +- ++ PyObject *print_tb_func = PyImport_ImportModuleAttrString( ++ "linecache", ++ "_register_code"); + if (print_tb_func == NULL) { + Py_DECREF(co); + Py_DECREF(interactive_filename); +- Py_DECREF(linecache_module); + return NULL; + } + + if (!PyCallable_Check(print_tb_func)) { + Py_DECREF(co); + Py_DECREF(interactive_filename); +- Py_DECREF(linecache_module); + Py_DECREF(print_tb_func); + PyErr_SetString(PyExc_ValueError, "linecache._register_code is not callable"); + return NULL; +@@ -1406,7 +1390,6 @@ + + Py_DECREF(interactive_filename); + +- Py_DECREF(linecache_module); + Py_XDECREF(print_tb_func); + Py_XDECREF(result); + if (!result) { +diff --git a/Python/pytime.c b/Python/pytime.c +index 2b37cd991ef..c039fc98ce4 100644 +--- a/Python/pytime.c ++++ b/Python/pytime.c +@@ -1,5 +1,6 @@ + #include "Python.h" + #include "pycore_time.h" // PyTime_t ++#include "pycore_pystate.h" // _Py_AssertHoldsTstate() + + #include // gmtime_r() + #ifdef HAVE_SYS_TIME_H +@@ -897,14 +898,14 @@ + #endif + + +-// N.B. If raise_exc=0, this may be called without the GIL. ++// N.B. If raise_exc=0, this may be called without a thread state. + static int + py_get_system_clock(PyTime_t *tp, _Py_clock_info_t *info, int raise_exc) + { + assert(info == NULL || raise_exc); + if (raise_exc) { +- // raise_exc requires to hold the GIL +- assert(PyGILState_Check()); ++ // raise_exc requires to hold a thread state ++ _Py_AssertHoldsTstate(); + } + + #ifdef MS_WINDOWS +@@ -1142,14 +1143,14 @@ + #endif + + +-// N.B. If raise_exc=0, this may be called without the GIL. ++// N.B. If raise_exc=0, this may be called without a thread state. + static int + py_get_monotonic_clock(PyTime_t *tp, _Py_clock_info_t *info, int raise_exc) + { + assert(info == NULL || raise_exc); + if (raise_exc) { +- // raise_exc requires to hold the GIL +- assert(PyGILState_Check()); ++ // raise_exc requires to hold a thread state ++ _Py_AssertHoldsTstate(); + } + + #if defined(MS_WINDOWS) +diff --git a/Python/qsbr.c b/Python/qsbr.c +index a40219acfe2..0df1285cc8e 100644 +--- a/Python/qsbr.c ++++ b/Python/qsbr.c +@@ -205,15 +205,15 @@ + } + _PyEval_StartTheWorld(interp); + } +- PyMutex_Unlock(&shared->mutex); +- +- if (qsbr == NULL) { +- return -1; +- } + + // Return an index rather than the pointer because the array may be + // resized and the pointer invalidated. +- return (struct _qsbr_pad *)qsbr - shared->array; ++ Py_ssize_t index = -1; ++ if (qsbr != NULL) { ++ index = (struct _qsbr_pad *)qsbr - shared->array; ++ } ++ PyMutex_Unlock(&shared->mutex); ++ return index; + } + + void +diff --git a/Python/specialize.c b/Python/specialize.c +index 6eb298217ec..c741c4f93f3 100644 +--- a/Python/specialize.c ++++ b/Python/specialize.c +@@ -3,6 +3,7 @@ + #include "opcode.h" + + #include "pycore_code.h" ++#include "pycore_critical_section.h" + #include "pycore_descrobject.h" // _PyMethodWrapper_Type + #include "pycore_dict.h" // DICT_KEYS_UNICODE + #include "pycore_function.h" // _PyFunction_GetVersionForCurrentState() +@@ -21,7 +22,7 @@ + extern const char *_PyUOpName(int index); + + /* For guidance on adding or extending families of instructions see +- * ./adaptive.md ++ * InternalDocs/interpreter.md `Specialization` section. + */ + + #ifdef Py_STATS +@@ -112,7 +113,6 @@ + err += add_stat_dict(stats, LOAD_SUPER_ATTR, "load_super_attr"); + err += add_stat_dict(stats, LOAD_ATTR, "load_attr"); + err += add_stat_dict(stats, LOAD_GLOBAL, "load_global"); +- err += add_stat_dict(stats, BINARY_SUBSCR, "binary_subscr"); + err += add_stat_dict(stats, STORE_SUBSCR, "store_subscr"); + err += add_stat_dict(stats, STORE_ATTR, "store_attr"); + err += add_stat_dict(stats, CALL, "call"); +@@ -259,6 +259,7 @@ + fprintf(out, "Optimization inner loop: %" PRIu64 "\n", stats->inner_loop); + fprintf(out, "Optimization recursive call: %" PRIu64 "\n", stats->recursive_call); + fprintf(out, "Optimization low confidence: %" PRIu64 "\n", stats->low_confidence); ++ fprintf(out, "Optimization unknown callee: %" PRIu64 "\n", stats->unknown_callee); + fprintf(out, "Executors invalidated: %" PRIu64 "\n", stats->executors_invalidated); + + print_histogram(out, "Trace length", stats->trace_length_hist); +@@ -308,6 +309,14 @@ + ); + } + } ++ fprintf(out, "JIT total memory size: %" PRIu64 "\n", stats->jit_total_memory_size); ++ fprintf(out, "JIT code size: %" PRIu64 "\n", stats->jit_code_size); ++ fprintf(out, "JIT trampoline size: %" PRIu64 "\n", stats->jit_trampoline_size); ++ fprintf(out, "JIT data size: %" PRIu64 "\n", stats->jit_data_size); ++ fprintf(out, "JIT padding size: %" PRIu64 "\n", stats->jit_padding_size); ++ fprintf(out, "JIT freed memory size: %" PRIu64 "\n", stats->jit_freed_memory_size); ++ ++ print_histogram(out, "Trace total memory size", stats->trace_total_memory_hist); + } + #endif + +@@ -440,8 +449,7 @@ + + // Initialize warmup counters and optimize instructions. This cannot fail. + void +-_PyCode_Quicken(_Py_CODEUNIT *instructions, Py_ssize_t size, PyObject *consts, +- int enable_counters) ++_PyCode_Quicken(_Py_CODEUNIT *instructions, Py_ssize_t size, int enable_counters) + { + #if ENABLE_SPECIALIZATION_FT + _Py_BackoffCounter jump_counter, adaptive_counter; +@@ -478,15 +486,6 @@ + } + i += caches; + } +- else if (opcode == LOAD_CONST) { +- /* We can't do this in the bytecode compiler as +- * marshalling can intern strings and make them immortal. */ +- +- PyObject *obj = PyTuple_GET_ITEM(consts, oparg); +- if (_Py_IsImmortal(obj)) { +- instructions[i].op.code = LOAD_CONST_IMMORTAL; +- } +- } + if (opcode != EXTENDED_ARG) { + oparg = 0; + } +@@ -546,17 +545,15 @@ + #define SPEC_FAIL_ATTR_BUILTIN_CLASS_METHOD_OBJ 33 + #define SPEC_FAIL_ATTR_METACLASS_OVERRIDDEN 34 + #define SPEC_FAIL_ATTR_SPLIT_DICT 35 ++#define SPEC_FAIL_ATTR_DESCR_NOT_DEFERRED 36 + + /* Binary subscr and store subscr */ + + #define SPEC_FAIL_SUBSCR_ARRAY_INT 9 + #define SPEC_FAIL_SUBSCR_ARRAY_SLICE 10 + #define SPEC_FAIL_SUBSCR_LIST_SLICE 11 +-#define SPEC_FAIL_SUBSCR_TUPLE_SLICE 12 +-#define SPEC_FAIL_SUBSCR_STRING_SLICE 14 +-#define SPEC_FAIL_SUBSCR_BUFFER_INT 15 +-#define SPEC_FAIL_SUBSCR_BUFFER_SLICE 16 +-#define SPEC_FAIL_SUBSCR_SEQUENCE_INT 17 ++#define SPEC_FAIL_SUBSCR_BUFFER_INT 12 ++#define SPEC_FAIL_SUBSCR_BUFFER_SLICE 13 + + /* Store subscr */ + #define SPEC_FAIL_SUBSCR_BYTEARRAY_INT 18 +@@ -588,6 +585,15 @@ + #define SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_FLOAT 26 + #define SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_OTHER 27 + #define SPEC_FAIL_BINARY_OP_XOR 28 ++#define SPEC_FAIL_BINARY_OP_OR_INT 29 ++#define SPEC_FAIL_BINARY_OP_OR_DIFFERENT_TYPES 30 ++#define SPEC_FAIL_BINARY_OP_XOR_INT 31 ++#define SPEC_FAIL_BINARY_OP_XOR_DIFFERENT_TYPES 32 ++#define SPEC_FAIL_BINARY_OP_SUBSCR 33 ++#define SPEC_FAIL_BINARY_OP_SUBSCR_LIST_SLICE 34 ++#define SPEC_FAIL_BINARY_OP_SUBSCR_TUPLE_SLICE 35 ++#define SPEC_FAIL_BINARY_OP_SUBSCR_STRING_SLICE 36 ++#define SPEC_FAIL_BINARY_OP_SUBSCR_NOT_HEAP_TYPE 37 + + /* Calls */ + +@@ -738,11 +744,8 @@ + } + + static int function_kind(PyCodeObject *code); +-#ifndef Py_GIL_DISABLED + static bool function_check_args(PyObject *o, int expected_argcount, int opcode); + static uint32_t function_get_version(PyObject *o, int opcode); +-#endif +-static uint32_t type_get_version(PyTypeObject *t, int opcode); + + static int + specialize_module_load_attr_lock_held(PyDictObject *dict, _Py_CODEUNIT *instr, PyObject *name) +@@ -881,71 +884,153 @@ + return NON_DESCRIPTOR; + } + +-static DescriptorClassification +-analyze_descriptor(PyTypeObject *type, PyObject *name, PyObject **descr, int store) ++static bool ++descriptor_is_class(PyObject *descriptor, PyObject *name) + { ++ return ((PyUnicode_CompareWithASCIIString(name, "__class__") == 0) && ++ (descriptor == _PyType_Lookup(&PyBaseObject_Type, name))); ++} ++ ++static DescriptorClassification ++analyze_descriptor_load(PyTypeObject *type, PyObject *name, PyObject **descr, unsigned int *tp_version) { + bool has_getattr = false; +- if (store) { +- if (type->tp_setattro != PyObject_GenericSetAttr) { ++ bool have_ga_version = false; ++ unsigned int ga_version; ++ getattrofunc getattro_slot = type->tp_getattro; ++ if (getattro_slot == PyObject_GenericGetAttr) { ++ /* Normal attribute lookup; */ ++ has_getattr = false; ++ } ++ else if (getattro_slot == _Py_slot_tp_getattr_hook || ++ getattro_slot == _Py_slot_tp_getattro) { ++ /* One or both of __getattribute__ or __getattr__ may have been ++ overridden See typeobject.c for why these functions are special. */ ++ PyObject *getattribute = _PyType_LookupRefAndVersion(type, ++ &_Py_ID(__getattribute__), &ga_version); ++ have_ga_version = true; ++ PyInterpreterState *interp = _PyInterpreterState_GET(); ++ bool has_custom_getattribute = getattribute != NULL && ++ getattribute != interp->callable_cache.object__getattribute__; ++ PyObject *getattr = _PyType_Lookup(type, &_Py_ID(__getattr__)); ++ has_getattr = getattr != NULL; ++ if (has_custom_getattribute) { ++ if (getattro_slot == _Py_slot_tp_getattro && ++ !has_getattr && ++ Py_IS_TYPE(getattribute, &PyFunction_Type)) { ++ *descr = getattribute; ++ *tp_version = ga_version; ++ return GETATTRIBUTE_IS_PYTHON_FUNCTION; ++ } ++ /* Potentially both __getattr__ and __getattribute__ are set. ++ Too complicated */ ++ Py_DECREF(getattribute); + *descr = NULL; ++ *tp_version = ga_version; + return GETSET_OVERRIDDEN; + } ++ /* Potentially has __getattr__ but no custom __getattribute__. ++ Fall through to usual descriptor analysis. ++ Usual attribute lookup should only be allowed at runtime ++ if we can guarantee that there is no way an exception can be ++ raised. This means some specializations, e.g. specializing ++ for property() isn't safe. ++ */ ++ Py_XDECREF(getattribute); + } + else { +- getattrofunc getattro_slot = type->tp_getattro; +- if (getattro_slot == PyObject_GenericGetAttr) { +- /* Normal attribute lookup; */ +- has_getattr = false; +- } +- else if (getattro_slot == _Py_slot_tp_getattr_hook || +- getattro_slot == _Py_slot_tp_getattro) { +- /* One or both of __getattribute__ or __getattr__ may have been +- overridden See typeobject.c for why these functions are special. */ +- PyObject *getattribute = _PyType_Lookup(type, +- &_Py_ID(__getattribute__)); +- PyInterpreterState *interp = _PyInterpreterState_GET(); +- bool has_custom_getattribute = getattribute != NULL && +- getattribute != interp->callable_cache.object__getattribute__; +- has_getattr = _PyType_Lookup(type, &_Py_ID(__getattr__)) != NULL; +- if (has_custom_getattribute) { +- if (getattro_slot == _Py_slot_tp_getattro && +- !has_getattr && +- Py_IS_TYPE(getattribute, &PyFunction_Type)) { +- *descr = getattribute; +- return GETATTRIBUTE_IS_PYTHON_FUNCTION; +- } +- /* Potentially both __getattr__ and __getattribute__ are set. +- Too complicated */ +- *descr = NULL; +- return GETSET_OVERRIDDEN; +- } +- /* Potentially has __getattr__ but no custom __getattribute__. +- Fall through to usual descriptor analysis. +- Usual attribute lookup should only be allowed at runtime +- if we can guarantee that there is no way an exception can be +- raised. This means some specializations, e.g. specializing +- for property() isn't safe. +- */ +- } +- else { +- *descr = NULL; +- return GETSET_OVERRIDDEN; +- } ++ *descr = NULL; ++ *tp_version = FT_ATOMIC_LOAD_UINT_RELAXED(type->tp_version_tag); ++ return GETSET_OVERRIDDEN; + } +- PyObject *descriptor = _PyType_Lookup(type, name); ++ unsigned int descr_version; ++ PyObject *descriptor = _PyType_LookupRefAndVersion(type, name, &descr_version); + *descr = descriptor; +- if (PyUnicode_CompareWithASCIIString(name, "__class__") == 0) { +- if (descriptor == _PyType_Lookup(&PyBaseObject_Type, name)) { +- return DUNDER_CLASS; +- } ++ *tp_version = have_ga_version ? ga_version : descr_version; ++ if (descriptor_is_class(descriptor, name)) { ++ return DUNDER_CLASS; + } + return classify_descriptor(descriptor, has_getattr); + } + ++static DescriptorClassification ++analyze_descriptor_store(PyTypeObject *type, PyObject *name, PyObject **descr, unsigned int *tp_version) ++{ ++ if (type->tp_setattro != PyObject_GenericSetAttr) { ++ *descr = NULL; ++ return GETSET_OVERRIDDEN; ++ } ++ PyObject *descriptor = _PyType_LookupRefAndVersion(type, name, tp_version); ++ *descr = descriptor; ++ if (descriptor_is_class(descriptor, name)) { ++ return DUNDER_CLASS; ++ } ++ return classify_descriptor(descriptor, false); ++} ++ ++static int ++specialize_dict_access_inline( ++ PyObject *owner, _Py_CODEUNIT *instr, PyTypeObject *type, ++ PyObject *name, unsigned int tp_version, ++ int base_op, int values_op) ++{ ++ _PyAttrCache *cache = (_PyAttrCache *)(instr + 1); ++ PyDictKeysObject *keys = ((PyHeapTypeObject *)type)->ht_cached_keys; ++ assert(PyUnicode_CheckExact(name)); ++ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(owner); ++ Py_ssize_t index = _PyDictKeys_StringLookupSplit(keys, name); ++ assert (index != DKIX_ERROR); ++ if (index == DKIX_EMPTY) { ++ SPECIALIZATION_FAIL(base_op, SPEC_FAIL_ATTR_NOT_IN_KEYS); ++ return 0; ++ } ++ assert(index >= 0); ++ assert(_PyObject_InlineValues(owner)->valid); ++ char *value_addr = (char *)&_PyObject_InlineValues(owner)->values[index]; ++ Py_ssize_t offset = value_addr - (char *)owner; ++ if (offset != (uint16_t)offset) { ++ SPECIALIZATION_FAIL(base_op, SPEC_FAIL_OUT_OF_RANGE); ++ return 0; ++ } ++ cache->index = (uint16_t)offset; ++ write_u32(cache->version, tp_version); ++ specialize(instr, values_op); ++ return 1; ++} ++ ++static int ++specialize_dict_access_hint( ++ PyDictObject *dict, _Py_CODEUNIT *instr, PyTypeObject *type, ++ PyObject *name, unsigned int tp_version, ++ int base_op, int hint_op) ++{ ++ _PyAttrCache *cache = (_PyAttrCache *)(instr + 1); ++ ++ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(dict); ++ ++ // We found an instance with a __dict__. ++ if (_PyDict_HasSplitTable(dict)) { ++ SPECIALIZATION_FAIL(base_op, SPEC_FAIL_ATTR_SPLIT_DICT); ++ return 0; ++ } ++ Py_ssize_t index = _PyDict_LookupIndex(dict, name); ++ if (index != (uint16_t)index) { ++ SPECIALIZATION_FAIL(base_op, ++ index == DKIX_EMPTY ? ++ SPEC_FAIL_ATTR_NOT_IN_DICT : ++ SPEC_FAIL_OUT_OF_RANGE); ++ return 0; ++ } ++ cache->index = (uint16_t)index; ++ write_u32(cache->version, tp_version); ++ specialize(instr, hint_op); ++ return 1; ++} ++ ++ + static int + specialize_dict_access( + PyObject *owner, _Py_CODEUNIT *instr, PyTypeObject *type, +- DescriptorClassification kind, PyObject *name, ++ DescriptorClassification kind, PyObject *name, unsigned int tp_version, + int base_op, int values_op, int hint_op) + { + assert(kind == NON_OVERRIDING || kind == NON_DESCRIPTOR || kind == ABSENT || +@@ -956,29 +1041,25 @@ + SPECIALIZATION_FAIL(base_op, SPEC_FAIL_ATTR_NOT_MANAGED_DICT); + return 0; + } +- _PyAttrCache *cache = (_PyAttrCache *)(instr + 1); + if (type->tp_flags & Py_TPFLAGS_INLINE_VALUES && +- _PyObject_InlineValues(owner)->valid && ++ FT_ATOMIC_LOAD_UINT8(_PyObject_InlineValues(owner)->valid) && + !(base_op == STORE_ATTR && _PyObject_GetManagedDict(owner) != NULL)) + { +- PyDictKeysObject *keys = ((PyHeapTypeObject *)type)->ht_cached_keys; +- assert(PyUnicode_CheckExact(name)); +- Py_ssize_t index = _PyDictKeys_StringLookup(keys, name); +- assert (index != DKIX_ERROR); +- if (index == DKIX_EMPTY) { +- SPECIALIZATION_FAIL(base_op, SPEC_FAIL_ATTR_NOT_IN_KEYS); +- return 0; ++ int res; ++ Py_BEGIN_CRITICAL_SECTION(owner); ++ PyDictObject *dict = _PyObject_GetManagedDict(owner); ++ if (dict == NULL) { ++ // managed dict, not materialized, inline values valid ++ res = specialize_dict_access_inline(owner, instr, type, name, ++ tp_version, base_op, values_op); + } +- assert(index >= 0); +- char *value_addr = (char *)&_PyObject_InlineValues(owner)->values[index]; +- Py_ssize_t offset = value_addr - (char *)owner; +- if (offset != (uint16_t)offset) { +- SPECIALIZATION_FAIL(base_op, SPEC_FAIL_OUT_OF_RANGE); +- return 0; ++ else { ++ // lost race and dict was created, fail specialization ++ SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_OTHER); ++ res = 0; + } +- write_u32(cache->version, type->tp_version_tag); +- cache->index = (uint16_t)offset; +- specialize(instr, values_op); ++ Py_END_CRITICAL_SECTION(); ++ return res; + } + else { + PyDictObject *dict = _PyObject_GetManagedDict(owner); +@@ -986,30 +1067,22 @@ + SPECIALIZATION_FAIL(base_op, SPEC_FAIL_NO_DICT); + return 0; + } +- // We found an instance with a __dict__. +- if (dict->ma_values) { +- SPECIALIZATION_FAIL(base_op, SPEC_FAIL_ATTR_SPLIT_DICT); +- return 0; +- } +- Py_ssize_t index = +- _PyDict_LookupIndex(dict, name); +- if (index != (uint16_t)index) { +- SPECIALIZATION_FAIL(base_op, +- index == DKIX_EMPTY ? +- SPEC_FAIL_ATTR_NOT_IN_DICT : +- SPEC_FAIL_OUT_OF_RANGE); +- return 0; +- } +- cache->index = (uint16_t)index; +- write_u32(cache->version, type->tp_version_tag); +- specialize(instr, hint_op); ++ int res; ++ Py_BEGIN_CRITICAL_SECTION(dict); ++ // materialized managed dict ++ res = specialize_dict_access_hint(dict, instr, type, name, ++ tp_version, base_op, hint_op); ++ Py_END_CRITICAL_SECTION(); ++ return res; + } +- return 1; + } + +-#ifndef Py_GIL_DISABLED +-static int specialize_attr_loadclassattr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name, +- PyObject* descr, DescriptorClassification kind, bool is_method); ++static int ++specialize_attr_loadclassattr(PyObject *owner, _Py_CODEUNIT *instr, ++ PyObject *name, PyObject *descr, ++ unsigned int tp_version, ++ DescriptorClassification kind, bool is_method, ++ uint32_t shared_keys_version); + static int specialize_class_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name); + + /* Returns true if instances of obj's class are +@@ -1018,7 +1091,7 @@ + * For other objects, we check their actual dictionary. + */ + static bool +-instance_has_key(PyObject *obj, PyObject* name) ++instance_has_key(PyObject *obj, PyObject *name, uint32_t *shared_keys_version) + { + PyTypeObject *cls = Py_TYPE(obj); + if ((cls->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) { +@@ -1026,35 +1099,38 @@ + } + if (cls->tp_flags & Py_TPFLAGS_INLINE_VALUES) { + PyDictKeysObject *keys = ((PyHeapTypeObject *)cls)->ht_cached_keys; +- Py_ssize_t index = _PyDictKeys_StringLookup(keys, name); ++ Py_ssize_t index = ++ _PyDictKeys_StringLookupAndVersion(keys, name, shared_keys_version); + return index >= 0; + } + PyDictObject *dict = _PyObject_GetManagedDict(obj); + if (dict == NULL || !PyDict_CheckExact(dict)) { + return false; + } ++ bool result; ++ Py_BEGIN_CRITICAL_SECTION(dict); + if (dict->ma_values) { +- return false; ++ result = false; + } +- Py_ssize_t index = _PyDict_LookupIndex(dict, name); +- if (index < 0) { +- return false; ++ else { ++ result = (_PyDict_LookupIndex(dict, name) >= 0); + } +- return true; ++ Py_END_CRITICAL_SECTION(); ++ return result; + } + + static int +-specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name) ++do_specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name, ++ bool shadow, uint32_t shared_keys_version, ++ DescriptorClassification kind, PyObject *descr, unsigned int tp_version) + { + _PyAttrCache *cache = (_PyAttrCache *)(instr + 1); + PyTypeObject *type = Py_TYPE(owner); +- bool shadow = instance_has_key(owner, name); +- PyObject *descr = NULL; +- DescriptorClassification kind = analyze_descriptor(type, name, &descr, 0); +- assert(descr != NULL || kind == ABSENT || kind == GETSET_OVERRIDDEN); +- if (type_get_version(type, LOAD_ATTR) == 0) { ++ if (tp_version == 0) { ++ SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS); + return -1; + } ++ uint8_t oparg = FT_ATOMIC_LOAD_UINT8_RELAXED(instr->op.arg); + switch(kind) { + case OVERRIDING: + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR); +@@ -1064,9 +1140,10 @@ + if (shadow) { + goto try_instance; + } +- int oparg = instr->op.arg; + if (oparg & 1) { +- if (specialize_attr_loadclassattr(owner, instr, name, descr, kind, true)) { ++ if (specialize_attr_loadclassattr(owner, instr, name, descr, ++ tp_version, kind, true, ++ shared_keys_version)) { + return 0; + } + else { +@@ -1092,18 +1169,25 @@ + if (!function_check_args(fget, 1, LOAD_ATTR)) { + return -1; + } +- if (instr->op.arg & 1) { ++ if (oparg & 1) { + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METHOD); + return -1; + } ++ /* Don't specialize if PEP 523 is active */ + if (_PyInterpreterState_GET()->eval_frame) { + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OTHER); + return -1; + } +- assert(type->tp_version_tag != 0); +- write_u32(lm_cache->type_version, type->tp_version_tag); ++ #ifdef Py_GIL_DISABLED ++ if (!_PyObject_HasDeferredRefcount(fget)) { ++ SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_DESCR_NOT_DEFERRED); ++ return -1; ++ } ++ #endif ++ assert(tp_version != 0); ++ write_u32(lm_cache->type_version, tp_version); + /* borrowed */ +- write_obj(lm_cache->descr, fget); ++ write_ptr(lm_cache->descr, fget); + specialize(instr, LOAD_ATTR_PROPERTY); + return 0; + } +@@ -1127,7 +1211,7 @@ + assert(dmem->type == Py_T_OBJECT_EX || dmem->type == _Py_T_OBJECT); + assert(offset > 0); + cache->index = (uint16_t)offset; +- write_u32(cache->version, type->tp_version_tag); ++ write_u32(cache->version, tp_version); + specialize(instr, LOAD_ATTR_SLOT); + return 0; + } +@@ -1136,7 +1220,7 @@ + Py_ssize_t offset = offsetof(PyObject, ob_type); + assert(offset == (uint16_t)offset); + cache->index = (uint16_t)offset; +- write_u32(cache->version, type->tp_version_tag); ++ write_u32(cache->version, tp_version); + specialize(instr, LOAD_ATTR_SLOT); + return 0; + } +@@ -1151,13 +1235,18 @@ + return -1; + case GETATTRIBUTE_IS_PYTHON_FUNCTION: + { ++ #ifndef Py_GIL_DISABLED ++ // In free-threaded builds it's possible for tp_getattro to change ++ // after the call to analyze_descriptor. That is fine: the version ++ // guard will fail. + assert(type->tp_getattro == _Py_slot_tp_getattro); ++ #endif + assert(Py_IS_TYPE(descr, &PyFunction_Type)); + _PyLoadMethodCache *lm_cache = (_PyLoadMethodCache *)(instr + 1); + if (!function_check_args(descr, 2, LOAD_ATTR)) { + return -1; + } +- if (instr->op.arg & 1) { ++ if (oparg & 1) { + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METHOD); + return -1; + } +@@ -1165,14 +1254,21 @@ + if (version == 0) { + return -1; + } ++ /* Don't specialize if PEP 523 is active */ + if (_PyInterpreterState_GET()->eval_frame) { + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OTHER); + return -1; + } ++ #ifdef Py_GIL_DISABLED ++ if (!_PyObject_HasDeferredRefcount(descr)) { ++ SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_DESCR_NOT_DEFERRED); ++ return -1; ++ } ++ #endif + write_u32(lm_cache->keys_version, version); + /* borrowed */ +- write_obj(lm_cache->descr, descr); +- write_u32(lm_cache->type_version, type->tp_version_tag); ++ write_ptr(lm_cache->descr, descr); ++ write_u32(lm_cache->type_version, tp_version); + specialize(instr, LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN); + return 0; + } +@@ -1187,8 +1283,10 @@ + if (shadow) { + goto try_instance; + } +- if ((instr->op.arg & 1) == 0) { +- if (specialize_attr_loadclassattr(owner, instr, name, descr, kind, false)) { ++ if ((oparg & 1) == 0) { ++ if (specialize_attr_loadclassattr(owner, instr, name, descr, ++ tp_version, kind, false, ++ shared_keys_version)) { + return 0; + } + } +@@ -1202,14 +1300,28 @@ + } + Py_UNREACHABLE(); + try_instance: +- if (specialize_dict_access(owner, instr, type, kind, name, LOAD_ATTR, +- LOAD_ATTR_INSTANCE_VALUE, LOAD_ATTR_WITH_HINT)) ++ if (specialize_dict_access(owner, instr, type, kind, name, tp_version, ++ LOAD_ATTR, LOAD_ATTR_INSTANCE_VALUE, LOAD_ATTR_WITH_HINT)) + { + return 0; + } + return -1; + } +-#endif // Py_GIL_DISABLED ++ ++static int ++specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name) ++{ ++ // 0 is not a valid version ++ uint32_t shared_keys_version = 0; ++ bool shadow = instance_has_key(owner, name, &shared_keys_version); ++ PyObject *descr = NULL; ++ unsigned int tp_version = 0; ++ PyTypeObject *type = Py_TYPE(owner); ++ DescriptorClassification kind = analyze_descriptor_load(type, name, &descr, &tp_version); ++ int result = do_specialize_instance_load_attr(owner, instr, name, shadow, shared_keys_version, kind, descr, tp_version); ++ Py_XDECREF(descr); ++ return result; ++} + + void + _Py_Specialize_LoadAttr(_PyStackRef owner_st, _Py_CODEUNIT *instr, PyObject *name) +@@ -1231,20 +1343,10 @@ + fail = specialize_module_load_attr(owner, instr, name); + } + else if (PyType_Check(owner)) { +- #ifdef Py_GIL_DISABLED +- SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR); +- fail = true; +- #else + fail = specialize_class_load_attr(owner, instr, name); +- #endif + } + else { +- #ifdef Py_GIL_DISABLED +- SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR); +- fail = true; +- #else + fail = specialize_instance_load_attr(owner, instr, name); +- #endif + } + + if (fail) { +@@ -1257,8 +1359,9 @@ + { + PyObject *owner = PyStackRef_AsPyObjectBorrow(owner_st); + +- assert(ENABLE_SPECIALIZATION); ++ assert(ENABLE_SPECIALIZATION_FT); + assert(_PyOpcode_Caches[STORE_ATTR] == INLINE_CACHE_ENTRIES_STORE_ATTR); ++ PyObject *descr = NULL; + _PyAttrCache *cache = (_PyAttrCache *)(instr + 1); + PyTypeObject *type = Py_TYPE(owner); + if (!_PyType_IsReady(type)) { +@@ -1272,11 +1375,12 @@ + SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_OVERRIDDEN); + goto fail; + } +- PyObject *descr; +- DescriptorClassification kind = analyze_descriptor(type, name, &descr, 1); +- if (type_get_version(type, STORE_ATTR) == 0) { ++ unsigned int tp_version = 0; ++ DescriptorClassification kind = analyze_descriptor_store(type, name, &descr, &tp_version); ++ if (tp_version == 0) { + goto fail; + } ++ assert(descr != NULL || kind == ABSENT || kind == GETSET_OVERRIDDEN); + switch(kind) { + case OVERRIDING: + SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR); +@@ -1307,8 +1411,8 @@ + assert(dmem->type == Py_T_OBJECT_EX || dmem->type == _Py_T_OBJECT); + assert(offset > 0); + cache->index = (uint16_t)offset; +- write_u32(cache->version, type->tp_version_tag); +- instr->op.code = STORE_ATTR_SLOT; ++ write_u32(cache->version, tp_version); ++ specialize(instr, STORE_ATTR_SLOT); + goto success; + } + case DUNDER_CLASS: +@@ -1335,26 +1439,21 @@ + SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_CLASS_ATTR_SIMPLE); + goto fail; + case ABSENT: +- if (specialize_dict_access(owner, instr, type, kind, name, STORE_ATTR, +- STORE_ATTR_INSTANCE_VALUE, STORE_ATTR_WITH_HINT)) +- { ++ if (specialize_dict_access(owner, instr, type, kind, name, tp_version, ++ STORE_ATTR, STORE_ATTR_INSTANCE_VALUE, ++ STORE_ATTR_WITH_HINT)) { + goto success; + } + } + fail: +- STAT_INC(STORE_ATTR, failure); +- assert(!PyErr_Occurred()); +- instr->op.code = STORE_ATTR; +- cache->counter = adaptive_counter_backoff(cache->counter); ++ Py_XDECREF(descr); ++ unspecialize(instr); + return; + success: +- STAT_INC(STORE_ATTR, success); +- assert(!PyErr_Occurred()); +- cache->counter = adaptive_counter_cooldown(); ++ Py_XDECREF(descr); ++ return; + } + +-#ifndef Py_GIL_DISABLED +- + #ifdef Py_STATS + static int + load_attr_fail_kind(DescriptorClassification kind) +@@ -1403,8 +1502,10 @@ + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METACLASS_OVERRIDDEN); + return -1; + } +- PyObject *metadescriptor = _PyType_Lookup(Py_TYPE(cls), name); ++ unsigned int meta_version = 0; ++ PyObject *metadescriptor = _PyType_LookupRefAndVersion(Py_TYPE(cls), name, &meta_version); + DescriptorClassification metakind = classify_descriptor(metadescriptor, false); ++ Py_XDECREF(metadescriptor); + switch (metakind) { + case METHOD: + case NON_DESCRIPTOR: +@@ -1419,37 +1520,52 @@ + } + PyObject *descr = NULL; + DescriptorClassification kind = 0; +- kind = analyze_descriptor(cls, name, &descr, 0); +- if (type_get_version(cls, LOAD_ATTR) == 0) { ++ unsigned int tp_version = 0; ++ kind = analyze_descriptor_load(cls, name, &descr, &tp_version); ++ if (tp_version == 0) { ++ SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS); ++ Py_XDECREF(descr); + return -1; + } + bool metaclass_check = false; + if ((Py_TYPE(cls)->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) == 0) { + metaclass_check = true; +- if (type_get_version(Py_TYPE(cls), LOAD_ATTR) == 0) { ++ if (meta_version == 0) { ++ SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS); ++ Py_XDECREF(descr); + return -1; + } + } + switch (kind) { + case METHOD: + case NON_DESCRIPTOR: +- write_u32(cache->type_version, cls->tp_version_tag); +- write_obj(cache->descr, descr); ++ #ifdef Py_GIL_DISABLED ++ if (!_PyObject_HasDeferredRefcount(descr)) { ++ SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_DESCR_NOT_DEFERRED); ++ Py_XDECREF(descr); ++ return -1; ++ } ++ #endif ++ write_u32(cache->type_version, tp_version); ++ write_ptr(cache->descr, descr); + if (metaclass_check) { +- write_u32(cache->keys_version, Py_TYPE(cls)->tp_version_tag); ++ write_u32(cache->keys_version, meta_version); + specialize(instr, LOAD_ATTR_CLASS_WITH_METACLASS_CHECK); + } + else { + specialize(instr, LOAD_ATTR_CLASS); + } ++ Py_XDECREF(descr); + return 0; + #ifdef Py_STATS + case ABSENT: + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR); ++ Py_XDECREF(descr); + return -1; + #endif + default: + SPECIALIZATION_FAIL(LOAD_ATTR, load_attr_fail_kind(kind)); ++ Py_XDECREF(descr); + return -1; + } + } +@@ -1458,29 +1574,41 @@ + // can cause a significant drop in cache hits. A possible test is + // python.exe -m test_typing test_re test_dis test_zlib. + static int +-specialize_attr_loadclassattr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, +-PyObject *descr, DescriptorClassification kind, bool is_method) ++specialize_attr_loadclassattr(PyObject *owner, _Py_CODEUNIT *instr, ++ PyObject *name, PyObject *descr, ++ unsigned int tp_version, ++ DescriptorClassification kind, bool is_method, ++ uint32_t shared_keys_version) + { + _PyLoadMethodCache *cache = (_PyLoadMethodCache *)(instr + 1); + PyTypeObject *owner_cls = Py_TYPE(owner); + + assert(descr != NULL); + assert((is_method && kind == METHOD) || (!is_method && kind == NON_DESCRIPTOR)); +- if (owner_cls->tp_flags & Py_TPFLAGS_INLINE_VALUES) { +- PyDictKeysObject *keys = ((PyHeapTypeObject *)owner_cls)->ht_cached_keys; +- assert(_PyDictKeys_StringLookup(keys, name) < 0); +- uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState( +- _PyInterpreterState_GET(), keys); +- if (keys_version == 0) { ++ ++ #ifdef Py_GIL_DISABLED ++ if (!_PyObject_HasDeferredRefcount(descr)) { ++ SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_DESCR_NOT_DEFERRED); ++ return 0; ++ } ++ #endif ++ ++ unsigned long tp_flags = PyType_GetFlags(owner_cls); ++ if (tp_flags & Py_TPFLAGS_INLINE_VALUES) { ++ #ifndef Py_GIL_DISABLED ++ assert(_PyDictKeys_StringLookup( ++ ((PyHeapTypeObject *)owner_cls)->ht_cached_keys, name) < 0); ++ #endif ++ if (shared_keys_version == 0) { + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS); + return 0; + } +- write_u32(cache->keys_version, keys_version); ++ write_u32(cache->keys_version, shared_keys_version); + specialize(instr, is_method ? LOAD_ATTR_METHOD_WITH_VALUES : LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES); + } + else { + Py_ssize_t dictoffset; +- if (owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT) { ++ if (tp_flags & Py_TPFLAGS_MANAGED_DICT) { + dictoffset = MANAGED_DICT_OFFSET; + } + else { +@@ -1526,13 +1654,11 @@ + * PyType_Modified usages in typeobject.c). The MCACHE has been + * working since Python 2.6 and it's battle-tested. + */ +- write_u32(cache->type_version, owner_cls->tp_version_tag); +- write_obj(cache->descr, descr); ++ write_u32(cache->type_version, tp_version); ++ write_ptr(cache->descr, descr); + return 1; + } + +-#endif // Py_GIL_DISABLED +- + + static void + specialize_load_global_lock_held( +@@ -1636,37 +1762,6 @@ + Py_END_CRITICAL_SECTION2(); + } + +-#ifdef Py_STATS +-static int +-binary_subscr_fail_kind(PyTypeObject *container_type, PyObject *sub) +-{ +- if (strcmp(container_type->tp_name, "array.array") == 0) { +- if (PyLong_CheckExact(sub)) { +- return SPEC_FAIL_SUBSCR_ARRAY_INT; +- } +- if (PySlice_Check(sub)) { +- return SPEC_FAIL_SUBSCR_ARRAY_SLICE; +- } +- return SPEC_FAIL_OTHER; +- } +- else if (container_type->tp_as_buffer) { +- if (PyLong_CheckExact(sub)) { +- return SPEC_FAIL_SUBSCR_BUFFER_INT; +- } +- if (PySlice_Check(sub)) { +- return SPEC_FAIL_SUBSCR_BUFFER_SLICE; +- } +- return SPEC_FAIL_OTHER; +- } +- else if (container_type->tp_as_sequence) { +- if (PyLong_CheckExact(sub) && container_type->tp_as_sequence->sq_item) { +- return SPEC_FAIL_SUBSCR_SEQUENCE_INT; +- } +- } +- return SPEC_FAIL_OTHER; +-} +-#endif // Py_STATS +- + static int + function_kind(PyCodeObject *code) { + int flags = code->co_flags; +@@ -1679,7 +1774,6 @@ + return SIMPLE_FUNCTION; + } + +-#ifndef Py_GIL_DISABLED + /* Returning false indicates a failure. */ + static bool + function_check_args(PyObject *o, int expected_argcount, int opcode) +@@ -1712,121 +1806,6 @@ + } + return version; + } +-#endif // Py_GIL_DISABLED +- +-/* Returning 0 indicates a failure. */ +-static uint32_t +-type_get_version(PyTypeObject *t, int opcode) +-{ +- uint32_t version = t->tp_version_tag; +- if (version == 0) { +- SPECIALIZATION_FAIL(opcode, SPEC_FAIL_OUT_OF_VERSIONS); +- return 0; +- } +- return version; +-} +- +-void +-_Py_Specialize_BinarySubscr( +- _PyStackRef container_st, _PyStackRef sub_st, _Py_CODEUNIT *instr) +-{ +- PyObject *container = PyStackRef_AsPyObjectBorrow(container_st); +- PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); +- +- assert(ENABLE_SPECIALIZATION_FT); +- assert(_PyOpcode_Caches[BINARY_SUBSCR] == +- INLINE_CACHE_ENTRIES_BINARY_SUBSCR); +- PyTypeObject *container_type = Py_TYPE(container); +- uint8_t specialized_op; +- if (container_type == &PyList_Type) { +- if (PyLong_CheckExact(sub)) { +- if (_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) { +- specialized_op = BINARY_SUBSCR_LIST_INT; +- goto success; +- } +- SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_OUT_OF_RANGE); +- goto fail; +- } +- SPECIALIZATION_FAIL(BINARY_SUBSCR, +- PySlice_Check(sub) ? SPEC_FAIL_SUBSCR_LIST_SLICE : SPEC_FAIL_OTHER); +- goto fail; +- } +- if (container_type == &PyTuple_Type) { +- if (PyLong_CheckExact(sub)) { +- if (_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) { +- specialized_op = BINARY_SUBSCR_TUPLE_INT; +- goto success; +- } +- SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_OUT_OF_RANGE); +- goto fail; +- } +- SPECIALIZATION_FAIL(BINARY_SUBSCR, +- PySlice_Check(sub) ? SPEC_FAIL_SUBSCR_TUPLE_SLICE : SPEC_FAIL_OTHER); +- goto fail; +- } +- if (container_type == &PyUnicode_Type) { +- if (PyLong_CheckExact(sub)) { +- if (_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) { +- specialized_op = BINARY_SUBSCR_STR_INT; +- goto success; +- } +- SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_OUT_OF_RANGE); +- goto fail; +- } +- SPECIALIZATION_FAIL(BINARY_SUBSCR, +- PySlice_Check(sub) ? SPEC_FAIL_SUBSCR_STRING_SLICE : SPEC_FAIL_OTHER); +- goto fail; +- } +- if (container_type == &PyDict_Type) { +- specialized_op = BINARY_SUBSCR_DICT; +- goto success; +- } +-#ifndef Py_GIL_DISABLED +- PyTypeObject *cls = Py_TYPE(container); +- PyObject *descriptor = _PyType_Lookup(cls, &_Py_ID(__getitem__)); +- if (descriptor && Py_TYPE(descriptor) == &PyFunction_Type) { +- if (!(container_type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { +- SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_SUBSCR_NOT_HEAP_TYPE); +- goto fail; +- } +- PyFunctionObject *func = (PyFunctionObject *)descriptor; +- PyCodeObject *fcode = (PyCodeObject *)func->func_code; +- int kind = function_kind(fcode); +- if (kind != SIMPLE_FUNCTION) { +- SPECIALIZATION_FAIL(BINARY_SUBSCR, kind); +- goto fail; +- } +- if (fcode->co_argcount != 2) { +- SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS); +- goto fail; +- } +- uint32_t version = _PyFunction_GetVersionForCurrentState(func); +- if (!_PyFunction_IsVersionValid(version)) { +- SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_OUT_OF_VERSIONS); +- goto fail; +- } +- if (_PyInterpreterState_GET()->eval_frame) { +- SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_OTHER); +- goto fail; +- } +- PyHeapTypeObject *ht = (PyHeapTypeObject *)container_type; +- // This pointer is invalidated by PyType_Modified (see the comment on +- // struct _specialization_cache): +- ht->_spec_cache.getitem = descriptor; +- ht->_spec_cache.getitem_version = version; +- specialized_op = BINARY_SUBSCR_GETITEM; +- goto success; +- } +-#endif // Py_GIL_DISABLED +- SPECIALIZATION_FAIL(BINARY_SUBSCR, +- binary_subscr_fail_kind(container_type, sub)); +-fail: +- unspecialize(instr); +- return; +-success: +- specialize(instr, specialized_op); +-} +- + + #ifdef Py_STATS + static int +@@ -1944,10 +1923,6 @@ + return NULL; + } + unsigned long tp_flags = PyType_GetFlags(tp); +- if ((tp_flags & Py_TPFLAGS_INLINE_VALUES) == 0) { +- SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_INIT_NOT_INLINE_VALUES); +- return NULL; +- } + if (!(tp_flags & Py_TPFLAGS_HEAPTYPE)) { + /* Is this possible? */ + SPECIALIZATION_FAIL(CALL, SPEC_FAIL_EXPECTED_ERROR); +@@ -2285,6 +2260,12 @@ + return SPEC_FAIL_BINARY_OP_MULTIPLY_OTHER; + case NB_OR: + case NB_INPLACE_OR: ++ if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) { ++ return SPEC_FAIL_BINARY_OP_OR_DIFFERENT_TYPES; ++ } ++ if (PyLong_CheckExact(lhs)) { ++ return SPEC_FAIL_BINARY_OP_OR_INT; ++ } + return SPEC_FAIL_BINARY_OP_OR; + case NB_POWER: + case NB_INPLACE_POWER: +@@ -2312,12 +2293,208 @@ + return SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_OTHER; + case NB_XOR: + case NB_INPLACE_XOR: ++ if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) { ++ return SPEC_FAIL_BINARY_OP_XOR_DIFFERENT_TYPES; ++ } ++ if (PyLong_CheckExact(lhs)) { ++ return SPEC_FAIL_BINARY_OP_XOR_INT; ++ } + return SPEC_FAIL_BINARY_OP_XOR; ++ case NB_SUBSCR: ++ if (PyList_CheckExact(lhs)) { ++ if (PyLong_CheckExact(rhs) && !_PyLong_IsNonNegativeCompact((PyLongObject *)rhs)) { ++ return SPEC_FAIL_OUT_OF_RANGE; ++ } ++ if (PySlice_Check(rhs)) { ++ return SPEC_FAIL_BINARY_OP_SUBSCR_LIST_SLICE; ++ } ++ } ++ if (PyTuple_CheckExact(lhs)) { ++ if (PyLong_CheckExact(rhs) && !_PyLong_IsNonNegativeCompact((PyLongObject *)rhs)) { ++ return SPEC_FAIL_OUT_OF_RANGE; ++ } ++ if (PySlice_Check(rhs)) { ++ return SPEC_FAIL_BINARY_OP_SUBSCR_TUPLE_SLICE; ++ } ++ } ++ if (PyUnicode_CheckExact(lhs)) { ++ if (PyLong_CheckExact(rhs) && !_PyLong_IsNonNegativeCompact((PyLongObject *)rhs)) { ++ return SPEC_FAIL_OUT_OF_RANGE; ++ } ++ if (PySlice_Check(rhs)) { ++ return SPEC_FAIL_BINARY_OP_SUBSCR_STRING_SLICE; ++ } ++ } ++ unsigned int tp_version; ++ PyTypeObject *container_type = Py_TYPE(lhs); ++ PyObject *descriptor = _PyType_LookupRefAndVersion(container_type, &_Py_ID(__getitem__), &tp_version); ++ if (descriptor && Py_TYPE(descriptor) == &PyFunction_Type) { ++ if (!(container_type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { ++ Py_DECREF(descriptor); ++ return SPEC_FAIL_BINARY_OP_SUBSCR_NOT_HEAP_TYPE; ++ } ++ PyFunctionObject *func = (PyFunctionObject *)descriptor; ++ PyCodeObject *fcode = (PyCodeObject *)func->func_code; ++ int kind = function_kind(fcode); ++ if (kind != SIMPLE_FUNCTION) { ++ Py_DECREF(descriptor); ++ return kind; ++ } ++ if (fcode->co_argcount != 2) { ++ Py_DECREF(descriptor); ++ return SPEC_FAIL_WRONG_NUMBER_ARGUMENTS; ++ } ++ ++ if (_PyInterpreterState_GET()->eval_frame) { ++ /* Don't specialize if PEP 523 is active */ ++ Py_DECREF(descriptor); ++ return SPEC_FAIL_OTHER; ++ } ++ } ++ Py_XDECREF(descriptor); ++ return SPEC_FAIL_BINARY_OP_SUBSCR; + } + Py_UNREACHABLE(); + } + #endif + ++/** Binary Op Specialization Extensions */ ++ ++/* long-long */ ++ ++static inline int ++is_compactlong(PyObject *v) ++{ ++ return PyLong_CheckExact(v) && ++ _PyLong_IsCompact((PyLongObject *)v); ++} ++ ++static int ++compactlongs_guard(PyObject *lhs, PyObject *rhs) ++{ ++ return (is_compactlong(lhs) && is_compactlong(rhs)); ++} ++ ++#define BITWISE_LONGS_ACTION(NAME, OP) \ ++ static PyObject * \ ++ (NAME)(PyObject *lhs, PyObject *rhs) \ ++ { \ ++ Py_ssize_t rhs_val = _PyLong_CompactValue((PyLongObject *)rhs); \ ++ Py_ssize_t lhs_val = _PyLong_CompactValue((PyLongObject *)lhs); \ ++ return PyLong_FromSsize_t(lhs_val OP rhs_val); \ ++ } ++BITWISE_LONGS_ACTION(compactlongs_or, |) ++BITWISE_LONGS_ACTION(compactlongs_and, &) ++BITWISE_LONGS_ACTION(compactlongs_xor, ^) ++#undef BITWISE_LONGS_ACTION ++ ++/* float-long */ ++ ++static inline int ++float_compactlong_guard(PyObject *lhs, PyObject *rhs) ++{ ++ return ( ++ PyFloat_CheckExact(lhs) && ++ !isnan(PyFloat_AsDouble(lhs)) && ++ PyLong_CheckExact(rhs) && ++ _PyLong_IsCompact((PyLongObject *)rhs) ++ ); ++} ++ ++static inline int ++nonzero_float_compactlong_guard(PyObject *lhs, PyObject *rhs) ++{ ++ return ( ++ float_compactlong_guard(lhs, rhs) && !PyLong_IsZero(rhs) ++ ); ++} ++ ++#define FLOAT_LONG_ACTION(NAME, OP) \ ++ static PyObject * \ ++ (NAME)(PyObject *lhs, PyObject *rhs) \ ++ { \ ++ double lhs_val = PyFloat_AsDouble(lhs); \ ++ Py_ssize_t rhs_val = _PyLong_CompactValue((PyLongObject *)rhs); \ ++ return PyFloat_FromDouble(lhs_val OP rhs_val); \ ++ } ++FLOAT_LONG_ACTION(float_compactlong_add, +) ++FLOAT_LONG_ACTION(float_compactlong_subtract, -) ++FLOAT_LONG_ACTION(float_compactlong_multiply, *) ++FLOAT_LONG_ACTION(float_compactlong_true_div, /) ++#undef FLOAT_LONG_ACTION ++ ++/* long-float */ ++ ++static inline int ++compactlong_float_guard(PyObject *lhs, PyObject *rhs) ++{ ++ return ( ++ PyLong_CheckExact(lhs) && ++ _PyLong_IsCompact((PyLongObject *)lhs) && ++ PyFloat_CheckExact(rhs) && ++ !isnan(PyFloat_AsDouble(rhs)) ++ ); ++} ++ ++static inline int ++nonzero_compactlong_float_guard(PyObject *lhs, PyObject *rhs) ++{ ++ return ( ++ compactlong_float_guard(lhs, rhs) && PyFloat_AsDouble(rhs) != 0.0 ++ ); ++} ++ ++#define LONG_FLOAT_ACTION(NAME, OP) \ ++ static PyObject * \ ++ (NAME)(PyObject *lhs, PyObject *rhs) \ ++ { \ ++ double rhs_val = PyFloat_AsDouble(rhs); \ ++ Py_ssize_t lhs_val = _PyLong_CompactValue((PyLongObject *)lhs); \ ++ return PyFloat_FromDouble(lhs_val OP rhs_val); \ ++ } ++LONG_FLOAT_ACTION(compactlong_float_add, +) ++LONG_FLOAT_ACTION(compactlong_float_subtract, -) ++LONG_FLOAT_ACTION(compactlong_float_multiply, *) ++LONG_FLOAT_ACTION(compactlong_float_true_div, /) ++#undef LONG_FLOAT_ACTION ++ ++static _PyBinaryOpSpecializationDescr binaryop_extend_descrs[] = { ++ /* long-long arithmetic */ ++ {NB_OR, compactlongs_guard, compactlongs_or}, ++ {NB_AND, compactlongs_guard, compactlongs_and}, ++ {NB_XOR, compactlongs_guard, compactlongs_xor}, ++ {NB_INPLACE_OR, compactlongs_guard, compactlongs_or}, ++ {NB_INPLACE_AND, compactlongs_guard, compactlongs_and}, ++ {NB_INPLACE_XOR, compactlongs_guard, compactlongs_xor}, ++ ++ /* float-long arithemetic */ ++ {NB_ADD, float_compactlong_guard, float_compactlong_add}, ++ {NB_SUBTRACT, float_compactlong_guard, float_compactlong_subtract}, ++ {NB_TRUE_DIVIDE, nonzero_float_compactlong_guard, float_compactlong_true_div}, ++ {NB_MULTIPLY, float_compactlong_guard, float_compactlong_multiply}, ++ ++ /* float-float arithmetic */ ++ {NB_ADD, compactlong_float_guard, compactlong_float_add}, ++ {NB_SUBTRACT, compactlong_float_guard, compactlong_float_subtract}, ++ {NB_TRUE_DIVIDE, nonzero_compactlong_float_guard, compactlong_float_true_div}, ++ {NB_MULTIPLY, compactlong_float_guard, compactlong_float_multiply}, ++}; ++ ++static int ++binary_op_extended_specialization(PyObject *lhs, PyObject *rhs, int oparg, ++ _PyBinaryOpSpecializationDescr **descr) ++{ ++ size_t n = sizeof(binaryop_extend_descrs)/sizeof(_PyBinaryOpSpecializationDescr); ++ for (size_t i = 0; i < n; i++) { ++ _PyBinaryOpSpecializationDescr *d = &binaryop_extend_descrs[i]; ++ if (d->oparg == oparg && d->guard(lhs, rhs)) { ++ *descr = d; ++ return 1; ++ } ++ } ++ return 0; ++} ++ + void + _Py_Specialize_BinaryOp(_PyStackRef lhs_st, _PyStackRef rhs_st, _Py_CODEUNIT *instr, + int oparg, _PyStackRef *locals) +@@ -2326,6 +2503,12 @@ + PyObject *rhs = PyStackRef_AsPyObjectBorrow(rhs_st); + assert(ENABLE_SPECIALIZATION_FT); + assert(_PyOpcode_Caches[BINARY_OP] == INLINE_CACHE_ENTRIES_BINARY_OP); ++ ++ _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(instr + 1); ++ if (instr->op.code == BINARY_OP_EXTEND) { ++ write_ptr(cache->external_cache, NULL); ++ } ++ + switch (oparg) { + case NB_ADD: + case NB_INPLACE_ADD: +@@ -2379,9 +2562,59 @@ + return; + } + break; ++ case NB_SUBSCR: ++ if (PyLong_CheckExact(rhs) && _PyLong_IsNonNegativeCompact((PyLongObject *)rhs)) { ++ if (PyList_CheckExact(lhs)) { ++ specialize(instr, BINARY_OP_SUBSCR_LIST_INT); ++ return; ++ } ++ if (PyTuple_CheckExact(lhs)) { ++ specialize(instr, BINARY_OP_SUBSCR_TUPLE_INT); ++ return; ++ } ++ if (PyUnicode_CheckExact(lhs)) { ++ specialize(instr, BINARY_OP_SUBSCR_STR_INT); ++ return; ++ } ++ } ++ if (PyDict_CheckExact(lhs)) { ++ specialize(instr, BINARY_OP_SUBSCR_DICT); ++ return; ++ } ++ unsigned int tp_version; ++ PyTypeObject *container_type = Py_TYPE(lhs); ++ PyObject *descriptor = _PyType_LookupRefAndVersion(container_type, &_Py_ID(__getitem__), &tp_version); ++ if (descriptor && Py_TYPE(descriptor) == &PyFunction_Type && ++ container_type->tp_flags & Py_TPFLAGS_HEAPTYPE) ++ { ++ PyFunctionObject *func = (PyFunctionObject *)descriptor; ++ PyCodeObject *fcode = (PyCodeObject *)func->func_code; ++ int kind = function_kind(fcode); ++ PyHeapTypeObject *ht = (PyHeapTypeObject *)container_type; ++ if (kind == SIMPLE_FUNCTION && ++ fcode->co_argcount == 2 && ++ !_PyInterpreterState_GET()->eval_frame && /* Don't specialize if PEP 523 is active */ ++ _PyType_CacheGetItemForSpecialization(ht, descriptor, (uint32_t)tp_version)) ++ { ++ specialize(instr, BINARY_OP_SUBSCR_GETITEM); ++ Py_DECREF(descriptor); ++ return; ++ } ++ } ++ Py_XDECREF(descriptor); ++ break; ++ } ++ ++ _PyBinaryOpSpecializationDescr *descr; ++ if (binary_op_extended_specialization(lhs, rhs, oparg, &descr)) { ++ specialize(instr, BINARY_OP_EXTEND); ++ write_ptr(cache->external_cache, (void*)descr); ++ return; + } ++ + SPECIALIZATION_FAIL(BINARY_OP, binary_op_fail_kind(oparg, lhs, rhs)); + unspecialize(instr); ++ return; + } + + +@@ -2426,23 +2659,23 @@ + { + PyObject *lhs = PyStackRef_AsPyObjectBorrow(lhs_st); + PyObject *rhs = PyStackRef_AsPyObjectBorrow(rhs_st); ++ uint8_t specialized_op; + +- assert(ENABLE_SPECIALIZATION); ++ assert(ENABLE_SPECIALIZATION_FT); + assert(_PyOpcode_Caches[COMPARE_OP] == INLINE_CACHE_ENTRIES_COMPARE_OP); + // All of these specializations compute boolean values, so they're all valid + // regardless of the fifth-lowest oparg bit. +- _PyCompareOpCache *cache = (_PyCompareOpCache *)(instr + 1); + if (Py_TYPE(lhs) != Py_TYPE(rhs)) { + SPECIALIZATION_FAIL(COMPARE_OP, compare_op_fail_kind(lhs, rhs)); + goto failure; + } + if (PyFloat_CheckExact(lhs)) { +- instr->op.code = COMPARE_OP_FLOAT; ++ specialized_op = COMPARE_OP_FLOAT; + goto success; + } + if (PyLong_CheckExact(lhs)) { + if (_PyLong_IsCompact((PyLongObject *)lhs) && _PyLong_IsCompact((PyLongObject *)rhs)) { +- instr->op.code = COMPARE_OP_INT; ++ specialized_op = COMPARE_OP_INT; + goto success; + } + else { +@@ -2457,19 +2690,16 @@ + goto failure; + } + else { +- instr->op.code = COMPARE_OP_STR; ++ specialized_op = COMPARE_OP_STR; + goto success; + } + } + SPECIALIZATION_FAIL(COMPARE_OP, compare_op_fail_kind(lhs, rhs)); + failure: +- STAT_INC(COMPARE_OP, failure); +- instr->op.code = COMPARE_OP; +- cache->counter = adaptive_counter_backoff(cache->counter); ++ unspecialize(instr); + return; + success: +- STAT_INC(COMPARE_OP, success); +- cache->counter = adaptive_counter_cooldown(); ++ specialize(instr, specialized_op); + } + + #ifdef Py_STATS +@@ -2617,6 +2847,7 @@ + assert(instr[oparg + INLINE_CACHE_ENTRIES_FOR_ITER + 1].op.code == END_FOR || + instr[oparg + INLINE_CACHE_ENTRIES_FOR_ITER + 1].op.code == INSTRUMENTED_END_FOR + ); ++ /* Don't specialize if PEP 523 is active */ + if (_PyInterpreterState_GET()->eval_frame) { + SPECIALIZATION_FAIL(FOR_ITER, SPEC_FAIL_OTHER); + goto failure; +@@ -2645,6 +2876,7 @@ + assert(_PyOpcode_Caches[SEND] == INLINE_CACHE_ENTRIES_SEND); + PyTypeObject *tp = Py_TYPE(receiver); + if (tp == &PyGen_Type || tp == &PyCoro_Type) { ++ /* Don't specialize if PEP 523 is active */ + if (_PyInterpreterState_GET()->eval_frame) { + SPECIALIZATION_FAIL(SEND, SPEC_FAIL_OTHER); + goto failure; +--- /dev/null ++++ b/Python/stackrefs.c +@@ -0,0 +1,156 @@ ++ ++#include "Python.h" ++ ++#include "pycore_stackref.h" ++ ++#if !defined(Py_GIL_DISABLED) && defined(Py_STACKREF_DEBUG) ++ ++#if SIZEOF_VOID_P < 8 ++#error "Py_STACKREF_DEBUG requires 64 bit machine" ++#endif ++ ++#include "pycore_interp.h" ++#include "pycore_hashtable.h" ++ ++typedef struct _table_entry { ++ PyObject *obj; ++ const char *classname; ++ const char *filename; ++ int linenumber; ++ const char *filename_borrow; ++ int linenumber_borrow; ++} TableEntry; ++ ++TableEntry * ++make_table_entry(PyObject *obj, const char *filename, int linenumber) ++{ ++ TableEntry *result = malloc(sizeof(TableEntry)); ++ if (result == NULL) { ++ return NULL; ++ } ++ result->obj = obj; ++ result->classname = Py_TYPE(obj)->tp_name; ++ result->filename = filename; ++ result->linenumber = linenumber; ++ result->filename_borrow = NULL; ++ return result; ++} ++ ++PyObject * ++_Py_stackref_get_object(_PyStackRef ref) ++{ ++ if (ref.index == 0) { ++ return NULL; ++ } ++ PyInterpreterState *interp = PyInterpreterState_Get(); ++ assert(interp != NULL); ++ if (ref.index >= interp->next_stackref) { ++ _Py_FatalErrorFormat(__func__, "Garbled stack ref with ID %" PRIu64 "\n", ref.index); ++ } ++ TableEntry *entry = _Py_hashtable_get(interp->stackref_debug_table, (void *)ref.index); ++ if (entry == NULL) { ++ _Py_FatalErrorFormat(__func__, "Accessing closed stack ref with ID %" PRIu64 "\n", ref.index); ++ } ++ return entry->obj; ++} ++ ++PyObject * ++_Py_stackref_close(_PyStackRef ref) ++{ ++ PyInterpreterState *interp = PyInterpreterState_Get(); ++ if (ref.index >= interp->next_stackref) { ++ _Py_FatalErrorFormat(__func__, "Garbled stack ref with ID %" PRIu64 "\n", ref.index); ++ } ++ PyObject *obj; ++ if (ref.index <= LAST_PREDEFINED_STACKREF_INDEX) { ++ // Pre-allocated reference to None, False or True -- Do not clear ++ TableEntry *entry = _Py_hashtable_get(interp->stackref_debug_table, (void *)ref.index); ++ obj = entry->obj; ++ } ++ else { ++ TableEntry *entry = _Py_hashtable_steal(interp->stackref_debug_table, (void *)ref.index); ++ if (entry == NULL) { ++ _Py_FatalErrorFormat(__func__, "Invalid StackRef with ID %" PRIu64 "\n", (void *)ref.index); ++ } ++ obj = entry->obj; ++ free(entry); ++ } ++ return obj; ++} ++ ++_PyStackRef ++_Py_stackref_create(PyObject *obj, const char *filename, int linenumber) ++{ ++ if (obj == NULL) { ++ Py_FatalError("Cannot create a stackref for NULL"); ++ } ++ PyInterpreterState *interp = PyInterpreterState_Get(); ++ uint64_t new_id = interp->next_stackref++; ++ TableEntry *entry = make_table_entry(obj, filename, linenumber); ++ if (entry == NULL) { ++ Py_FatalError("No memory left for stackref debug table"); ++ } ++ if (_Py_hashtable_set(interp->stackref_debug_table, (void *)new_id, entry) < 0) { ++ Py_FatalError("No memory left for stackref debug table"); ++ } ++ return (_PyStackRef){ .index = new_id }; ++} ++ ++void ++_Py_stackref_record_borrow(_PyStackRef ref, const char *filename, int linenumber) ++{ ++ if (ref.index <= LAST_PREDEFINED_STACKREF_INDEX) { ++ return; ++ } ++ PyInterpreterState *interp = PyInterpreterState_Get(); ++ TableEntry *entry = _Py_hashtable_get(interp->stackref_debug_table, (void *)ref.index); ++ if (entry == NULL) { ++ _Py_FatalErrorFormat(__func__, "Invalid StackRef with ID %" PRIu64 "\n", (void *)ref.index); ++ } ++ entry->filename_borrow = filename; ++ entry->linenumber_borrow = linenumber; ++} ++ ++ ++void ++_Py_stackref_associate(PyInterpreterState *interp, PyObject *obj, _PyStackRef ref) ++{ ++ assert(interp->next_stackref >= ref.index); ++ interp->next_stackref = ref.index+1; ++ TableEntry *entry = make_table_entry(obj, "builtin-object", 0); ++ if (entry == NULL) { ++ Py_FatalError("No memory left for stackref debug table"); ++ } ++ if (_Py_hashtable_set(interp->stackref_debug_table, (void *)ref.index, (void *)entry) < 0) { ++ Py_FatalError("No memory left for stackref debug table"); ++ } ++} ++ ++ ++static int ++report_leak(_Py_hashtable_t *ht, const void *key, const void *value, void *leak) ++{ ++ TableEntry *entry = (TableEntry *)value; ++ if (!_Py_IsStaticImmortal(entry->obj)) { ++ *(int *)leak = 1; ++ printf("Stackref leak. Refers to instance of %s at %p. Created at %s:%d", ++ entry->classname, entry->obj, entry->filename, entry->linenumber); ++ if (entry->filename_borrow != NULL) { ++ printf(". Last borrow at %s:%d",entry->filename_borrow, entry->linenumber_borrow); ++ } ++ printf("\n"); ++ } ++ return 0; ++} ++ ++void ++_Py_stackref_report_leaks(PyInterpreterState *interp) ++{ ++ int leak = 0; ++ _Py_hashtable_foreach(interp->stackref_debug_table, report_leak, &leak); ++ if (leak) { ++ Py_FatalError("Stackrefs leaked."); ++ } ++} ++ ++#endif +diff --git a/Python/symtable.c b/Python/symtable.c +index ebddb0b93fc..49bd01ba68a 100644 +--- a/Python/symtable.c ++++ b/Python/symtable.c +@@ -138,6 +138,13 @@ + + ste->ste_has_docstring = 0; + ++ ste->ste_method = 0; ++ if (st->st_cur != NULL && ++ st->st_cur->ste_type == ClassBlock && ++ block == FunctionBlock) { ++ ste->ste_method = 1; ++ } ++ + ste->ste_symbols = PyDict_New(); + ste->ste_varnames = PyList_New(0); + ste->ste_children = PyList_New(0); +diff --git a/Python/sysmodule.c b/Python/sysmodule.c +index d6719f9bb0a..d5cb448eb61 100644 +--- a/Python/sysmodule.c ++++ b/Python/sysmodule.c +@@ -972,6 +972,23 @@ + return PyUnicode_CHECK_INTERNED(string); + } + ++/*[clinic input] ++sys._is_immortal -> bool ++ ++ op: object ++ / ++ ++Return True if the given object is "immortal" per PEP 683. ++ ++This function should be used for specialized purposes only. ++[clinic start generated code]*/ ++ ++static int ++sys__is_immortal_impl(PyObject *module, PyObject *op) ++/*[clinic end generated code: output=c2f5d6a80efb8d1a input=4609c9bf5481db76]*/ ++{ ++ return PyUnstable_IsImmortal(op); ++} + + /* + * Cached interned string objects used for calling the profile and +@@ -2265,9 +2282,7 @@ + { + #ifdef PY_HAVE_PERF_TRAMPOLINE + #ifdef _Py_JIT +- _PyOptimizerObject* optimizer = _Py_GetOptimizer(); +- if (optimizer != NULL) { +- Py_DECREF(optimizer); ++ if (_PyInterpreterState_GET()->jit) { + PyErr_SetString(PyExc_ValueError, "Cannot activate the perf trampoline if the JIT is active"); + return NULL; + } +@@ -2356,7 +2371,7 @@ + sys__dump_tracelets_impl(PyObject *module, PyObject *outpath) + /*[clinic end generated code: output=a7fe265e2bc3b674 input=5bff6880cd28ffd1]*/ + { +- FILE *out = _Py_fopen_obj(outpath, "wb"); ++ FILE *out = Py_fopen(outpath, "wb"); + if (out == NULL) { + return NULL; + } +@@ -2590,6 +2605,7 @@ + SYS__GETFRAMEMODULENAME_METHODDEF + SYS_GETWINDOWSVERSION_METHODDEF + SYS__ENABLELEGACYWINDOWSFSENCODING_METHODDEF ++ SYS__IS_IMMORTAL_METHODDEF + SYS_INTERN_METHODDEF + SYS__IS_INTERNED_METHODDEF + SYS_IS_FINALIZING_METHODDEF +@@ -2849,6 +2865,7 @@ + static int + _PySys_AddWarnOptionWithError(PyThreadState *tstate, PyObject *option) + { ++ assert(tstate != NULL); + PyObject *warnoptions = get_warnoptions(tstate); + if (warnoptions == NULL) { + return -1; +@@ -2864,11 +2881,11 @@ + PySys_AddWarnOptionUnicode(PyObject *option) + { + PyThreadState *tstate = _PyThreadState_GET(); ++ _Py_EnsureTstateNotNULL(tstate); ++ assert(!_PyErr_Occurred(tstate)); + if (_PySys_AddWarnOptionWithError(tstate, option) < 0) { + /* No return value, therefore clear error state if possible */ +- if (tstate) { +- _PyErr_Clear(tstate); +- } ++ _PyErr_Clear(tstate); + } + } + +diff --git a/Python/traceback.c b/Python/traceback.c +index e819909b604..870ae5bcefe 100644 +--- a/Python/traceback.c ++++ b/Python/traceback.c +@@ -38,6 +38,8 @@ + [clinic start generated code]*/ + /*[clinic end generated code: output=da39a3ee5e6b4b0d input=cf96294b2bebc811]*/ + ++#define _PyTracebackObject_CAST(op) ((PyTracebackObject *)(op)) ++ + #include "clinic/traceback.c.h" + + static PyObject * +@@ -91,15 +93,16 @@ + } + + static PyObject * +-tb_dir(PyTracebackObject *self, PyObject *Py_UNUSED(ignored)) ++tb_dir(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) + { + return Py_BuildValue("[ssss]", "tb_frame", "tb_next", + "tb_lasti", "tb_lineno"); + } + + static PyObject * +-tb_next_get(PyTracebackObject *self, void *Py_UNUSED(_)) ++tb_next_get(PyObject *op, void *Py_UNUSED(_)) + { ++ PyTracebackObject *self = _PyTracebackObject_CAST(op); + PyObject* ret = (PyObject*)self->tb_next; + if (!ret) { + ret = Py_None; +@@ -108,18 +111,21 @@ + } + + static int +-tb_get_lineno(PyTracebackObject* tb) { ++tb_get_lineno(PyObject *op) ++{ ++ PyTracebackObject *tb = _PyTracebackObject_CAST(op); + _PyInterpreterFrame* frame = tb->tb_frame->f_frame; + assert(frame != NULL); + return PyCode_Addr2Line(_PyFrame_GetCode(frame), tb->tb_lasti); + } + + static PyObject * +-tb_lineno_get(PyTracebackObject *self, void *Py_UNUSED(_)) ++tb_lineno_get(PyObject *op, void *Py_UNUSED(_)) + { ++ PyTracebackObject *self = _PyTracebackObject_CAST(op); + int lineno = self->tb_lineno; + if (lineno == -1) { +- lineno = tb_get_lineno(self); ++ lineno = tb_get_lineno(op); + if (lineno < 0) { + Py_RETURN_NONE; + } +@@ -128,7 +134,7 @@ + } + + static int +-tb_next_set(PyTracebackObject *self, PyObject *new_next, void *Py_UNUSED(_)) ++tb_next_set(PyObject *op, PyObject *new_next, void *Py_UNUSED(_)) + { + if (!new_next) { + PyErr_Format(PyExc_TypeError, "can't delete tb_next attribute"); +@@ -147,6 +153,7 @@ + } + + /* Check for loops */ ++ PyTracebackObject *self = _PyTracebackObject_CAST(op); + PyTracebackObject *cursor = (PyTracebackObject *)new_next; + while (cursor) { + if (cursor == self) { +@@ -163,7 +170,7 @@ + + + static PyMethodDef tb_methods[] = { +- {"__dir__", _PyCFunction_CAST(tb_dir), METH_NOARGS}, ++ {"__dir__", tb_dir, METH_NOARGS, NULL}, + {NULL, NULL, 0, NULL}, + }; + +@@ -174,14 +181,15 @@ + }; + + static PyGetSetDef tb_getsetters[] = { +- {"tb_next", (getter)tb_next_get, (setter)tb_next_set, NULL, NULL}, +- {"tb_lineno", (getter)tb_lineno_get, NULL, NULL, NULL}, ++ {"tb_next", tb_next_get, tb_next_set, NULL, NULL}, ++ {"tb_lineno", tb_lineno_get, NULL, NULL, NULL}, + {NULL} /* Sentinel */ + }; + + static void +-tb_dealloc(PyTracebackObject *tb) ++tb_dealloc(PyObject *op) + { ++ PyTracebackObject *tb = _PyTracebackObject_CAST(op); + PyObject_GC_UnTrack(tb); + Py_TRASHCAN_BEGIN(tb, tb_dealloc) + Py_XDECREF(tb->tb_next); +@@ -191,16 +199,18 @@ + } + + static int +-tb_traverse(PyTracebackObject *tb, visitproc visit, void *arg) ++tb_traverse(PyObject *op, visitproc visit, void *arg) + { ++ PyTracebackObject *tb = _PyTracebackObject_CAST(op); + Py_VISIT(tb->tb_next); + Py_VISIT(tb->tb_frame); + return 0; + } + + static int +-tb_clear(PyTracebackObject *tb) ++tb_clear(PyObject *op) + { ++ PyTracebackObject *tb = _PyTracebackObject_CAST(op); + Py_CLEAR(tb->tb_next); + Py_CLEAR(tb->tb_frame); + return 0; +@@ -211,7 +221,7 @@ + "traceback", + sizeof(PyTracebackObject), + 0, +- (destructor)tb_dealloc, /*tp_dealloc*/ ++ tb_dealloc, /*tp_dealloc*/ + 0, /*tp_vectorcall_offset*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ +@@ -228,8 +238,8 @@ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + tb_new__doc__, /* tp_doc */ +- (traverseproc)tb_traverse, /* tp_traverse */ +- (inquiry)tb_clear, /* tp_clear */ ++ tb_traverse, /* tp_traverse */ ++ tb_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ +@@ -663,7 +673,7 @@ + code = PyFrame_GetCode(tb->tb_frame); + int tb_lineno = tb->tb_lineno; + if (tb_lineno == -1) { +- tb_lineno = tb_get_lineno(tb); ++ tb_lineno = tb_get_lineno((PyObject *)tb); + } + if (last_file == NULL || + code->co_filename != last_file || +@@ -890,7 +900,7 @@ + static void + dump_frame(int fd, _PyInterpreterFrame *frame) + { +- assert(frame->owner != FRAME_OWNED_BY_CSTACK); ++ assert(frame->owner < FRAME_OWNED_BY_INTERPRETER); + + PyCodeObject *code =_PyFrame_GetCode(frame); + PUTS(fd, " File "); +@@ -965,7 +975,7 @@ + + unsigned int depth = 0; + while (1) { +- if (frame->owner == FRAME_OWNED_BY_CSTACK) { ++ if (frame->owner == FRAME_OWNED_BY_INTERPRETER) { + /* Trampoline frame */ + frame = frame->previous; + if (frame == NULL) { +@@ -973,7 +983,7 @@ + } + + /* Can't have more than one shim frame in a row */ +- assert(frame->owner != FRAME_OWNED_BY_CSTACK); ++ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); + } + + if (MAX_FRAME_DEPTH <= depth) { +diff --git a/Python/tracemalloc.c b/Python/tracemalloc.c +index f661d69c031..d69b0ebd585 100644 +--- a/Python/tracemalloc.c ++++ b/Python/tracemalloc.c +@@ -2,6 +2,8 @@ + #include "pycore_fileutils.h" // _Py_write_noraise() + #include "pycore_gc.h" // PyGC_Head + #include "pycore_hashtable.h" // _Py_hashtable_t ++#include "pycore_initconfig.h" // _PyStatus_NO_MEMORY() ++#include "pycore_lock.h" // PyMutex_LockFlags() + #include "pycore_object.h" // _PyType_PreHeaderSize() + #include "pycore_pymem.h" // _Py_tracemalloc_config + #include "pycore_runtime.h" // _Py_ID() +@@ -19,6 +21,8 @@ + /* Forward declaration */ + static void* raw_malloc(size_t size); + static void raw_free(void *ptr); ++static int _PyTraceMalloc_TraceRef(PyObject *op, PyRefTracerEvent event, ++ void* Py_UNUSED(ignore)); + + #ifdef Py_DEBUG + # define TRACE_DEBUG +@@ -30,18 +34,12 @@ + #define allocators _PyRuntime.tracemalloc.allocators + + +-#if defined(TRACE_RAW_MALLOC) + /* This lock is needed because tracemalloc_free() is called without + the GIL held from PyMem_RawFree(). It cannot acquire the lock because it + would introduce a deadlock in _PyThreadState_DeleteCurrent(). */ +-# define tables_lock _PyRuntime.tracemalloc.tables_lock +-# define TABLES_LOCK() PyThread_acquire_lock(tables_lock, 1) +-# define TABLES_UNLOCK() PyThread_release_lock(tables_lock) +-#else +- /* variables are protected by the GIL */ +-# define TABLES_LOCK() +-# define TABLES_UNLOCK() +-#endif ++#define tables_lock _PyRuntime.tracemalloc.tables_lock ++#define TABLES_LOCK() PyMutex_LockFlags(&tables_lock, _Py_LOCK_DONT_DETACH) ++#define TABLES_UNLOCK() PyMutex_Unlock(&tables_lock) + + + #define DEFAULT_DOMAIN 0 +@@ -95,9 +93,6 @@ + #endif + + +-#if defined(TRACE_RAW_MALLOC) +-#define REENTRANT_THREADLOCAL +- + #define tracemalloc_reentrant_key _PyRuntime.tracemalloc.reentrant_key + + /* Any non-NULL pointer can be used */ +@@ -106,16 +101,16 @@ + static int + get_reentrant(void) + { +- void *ptr; +- + assert(PyThread_tss_is_created(&tracemalloc_reentrant_key)); +- ptr = PyThread_tss_get(&tracemalloc_reentrant_key); ++ ++ void *ptr = PyThread_tss_get(&tracemalloc_reentrant_key); + if (ptr != NULL) { + assert(ptr == REENTRANT); + return 1; + } +- else ++ else { + return 0; ++ } + } + + static void +@@ -134,25 +129,6 @@ + } + } + +-#else +- +-/* TRACE_RAW_MALLOC not defined: variable protected by the GIL */ +-static int tracemalloc_reentrant = 0; +- +-static int +-get_reentrant(void) +-{ +- return tracemalloc_reentrant; +-} +- +-static void +-set_reentrant(int reentrant) +-{ +- assert(reentrant != tracemalloc_reentrant); +- tracemalloc_reentrant = reentrant; +-} +-#endif +- + + static Py_uhash_t + hashtable_hash_pyobject(const void *key) +@@ -252,6 +228,7 @@ + { + assert(PyStackRef_CodeCheck(pyframe->f_executable)); + frame->filename = &_Py_STR(anon_unknown); ++ + int lineno = PyUnstable_InterpreterFrame_GetLine(pyframe); + if (lineno < 0) { + lineno = 0; +@@ -259,7 +236,6 @@ + frame->lineno = (unsigned int)lineno; + + PyObject *filename = filename = _PyFrame_GetCode(pyframe)->co_filename; +- + if (filename == NULL) { + #ifdef TRACE_DEBUG + tracemalloc_error("failed to get the filename of the code object"); +@@ -275,7 +251,7 @@ + } + if (!PyUnicode_IS_READY(filename)) { + /* Don't make a Unicode string ready to avoid reentrant calls +- to tracemalloc_malloc() or tracemalloc_realloc() */ ++ to tracemalloc_alloc() or tracemalloc_realloc() */ + #ifdef TRACE_DEBUG + tracemalloc_error("filename is not a ready unicode string"); + #endif +@@ -309,7 +285,7 @@ + static Py_uhash_t + traceback_hash(traceback_t *traceback) + { +- /* code based on tuplehash() of Objects/tupleobject.c */ ++ /* code based on tuple_hash() of Objects/tupleobject.c */ + Py_uhash_t x, y; /* Unsigned for defined overflow behavior. */ + int len = traceback->nframe; + Py_uhash_t mult = PyHASH_MULTIPLIER; +@@ -335,13 +311,8 @@ + static void + traceback_get_frames(traceback_t *traceback) + { +- PyThreadState *tstate = PyGILState_GetThisThreadState(); +- if (tstate == NULL) { +-#ifdef TRACE_DEBUG +- tracemalloc_error("failed to get the current thread state"); +-#endif +- return; +- } ++ PyThreadState *tstate = _PyThreadState_GET(); ++ assert(tstate != NULL); + + _PyInterpreterFrame *pyframe = _PyThreadState_GetFrame(tstate); + while (pyframe) { +@@ -364,7 +335,7 @@ + traceback_t *traceback; + _Py_hashtable_entry_t *entry; + +- assert(PyGILState_Check()); ++ _Py_AssertHoldsTstate(); + + /* get frames */ + traceback = tracemalloc_traceback; +@@ -440,7 +411,7 @@ + + + static void +-tracemalloc_remove_trace(unsigned int domain, uintptr_t ptr) ++tracemalloc_remove_trace_unlocked(unsigned int domain, uintptr_t ptr) + { + assert(tracemalloc_config.tracing); + +@@ -459,12 +430,12 @@ + } + + #define REMOVE_TRACE(ptr) \ +- tracemalloc_remove_trace(DEFAULT_DOMAIN, (uintptr_t)(ptr)) ++ tracemalloc_remove_trace_unlocked(DEFAULT_DOMAIN, (uintptr_t)(ptr)) + + + static int +-tracemalloc_add_trace(unsigned int domain, uintptr_t ptr, +- size_t size) ++tracemalloc_add_trace_unlocked(unsigned int domain, uintptr_t ptr, ++ size_t size) + { + assert(tracemalloc_config.tracing); + +@@ -519,82 +490,147 @@ + } + + #define ADD_TRACE(ptr, size) \ +- tracemalloc_add_trace(DEFAULT_DOMAIN, (uintptr_t)(ptr), size) ++ tracemalloc_add_trace_unlocked(DEFAULT_DOMAIN, (uintptr_t)(ptr), size) + + + static void* +-tracemalloc_alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize) ++tracemalloc_alloc(int need_gil, int use_calloc, ++ void *ctx, size_t nelem, size_t elsize) + { +- PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; +- void *ptr; +- + assert(elsize == 0 || nelem <= SIZE_MAX / elsize); + +- if (use_calloc) ++ int reentrant = get_reentrant(); ++ ++ // Ignore reentrant call. ++ // ++ // For example, PyObjet_Malloc() calls ++ // PyMem_Malloc() for allocations larger than 512 bytes: don't trace the ++ // same memory allocation twice. ++ // ++ // If reentrant calls are not ignored, PyGILState_Ensure() can call ++ // PyMem_RawMalloc() which would call PyGILState_Ensure() again in a loop. ++ if (!reentrant) { ++ set_reentrant(1); ++ } ++ ++ PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; ++ void *ptr; ++ if (use_calloc) { + ptr = alloc->calloc(alloc->ctx, nelem, elsize); +- else ++ } ++ else { + ptr = alloc->malloc(alloc->ctx, nelem * elsize); +- if (ptr == NULL) +- return NULL; ++ } ++ ++ if (ptr == NULL) { ++ goto done; ++ } ++ if (reentrant) { ++ goto done; ++ } + ++ PyGILState_STATE gil_state; ++ if (need_gil) { ++ gil_state = PyGILState_Ensure(); ++ } + TABLES_LOCK(); +- if (ADD_TRACE(ptr, nelem * elsize) < 0) { +- /* Failed to allocate a trace for the new memory block */ +- TABLES_UNLOCK(); +- alloc->free(alloc->ctx, ptr); +- return NULL; ++ ++ if (tracemalloc_config.tracing) { ++ if (ADD_TRACE(ptr, nelem * elsize) < 0) { ++ // Failed to allocate a trace for the new memory block ++ alloc->free(alloc->ctx, ptr); ++ ptr = NULL; ++ } + } ++ // else: gh-128679: tracemalloc.stop() was called by another thread ++ + TABLES_UNLOCK(); ++ if (need_gil) { ++ PyGILState_Release(gil_state); ++ } ++ ++done: ++ if (!reentrant) { ++ set_reentrant(0); ++ } + return ptr; + } + + + static void* +-tracemalloc_realloc(void *ctx, void *ptr, size_t new_size) ++tracemalloc_realloc(int need_gil, void *ctx, void *ptr, size_t new_size) + { ++ int reentrant = get_reentrant(); ++ ++ // Ignore reentrant call. PyObjet_Realloc() calls PyMem_Realloc() for ++ // allocations larger than 512 bytes: don't trace the same memory block ++ // twice. ++ if (!reentrant) { ++ set_reentrant(1); ++ } ++ + PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; +- void *ptr2; ++ void *ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); + +- ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); +- if (ptr2 == NULL) +- return NULL; ++ if (ptr2 == NULL) { ++ goto done; ++ } ++ if (reentrant) { ++ goto done; ++ } + +- if (ptr != NULL) { +- /* an existing memory block has been resized */ ++ PyGILState_STATE gil_state; ++ if (need_gil) { ++ gil_state = PyGILState_Ensure(); ++ } ++ TABLES_LOCK(); + +- TABLES_LOCK(); ++ if (!tracemalloc_config.tracing) { ++ // gh-128679: tracemalloc.stop() was called by another thread ++ goto unlock; ++ } ++ ++ if (ptr != NULL) { ++ // An existing memory block has been resized + +- /* tracemalloc_add_trace() updates the trace if there is already +- a trace at address ptr2 */ ++ // tracemalloc_add_trace_unlocked() updates the trace if there is ++ // already a trace at address ptr2. + if (ptr2 != ptr) { + REMOVE_TRACE(ptr); + } + + if (ADD_TRACE(ptr2, new_size) < 0) { +- /* Memory allocation failed. The error cannot be reported to +- the caller, because realloc() may already have shrunk the +- memory block and so removed bytes. +- +- This case is very unlikely: a hash entry has just been +- released, so the hash table should have at least one free entry. +- +- The GIL and the table lock ensures that only one thread is +- allocating memory. */ ++ // Memory allocation failed. The error cannot be reported to the ++ // caller, because realloc() already have shrunk the memory block ++ // and so removed bytes. ++ // ++ // This case is very unlikely: a hash entry has just been released, ++ // so the hash table should have at least one free entry. ++ // ++ // The GIL and the table lock ensures that only one thread is ++ // allocating memory. + Py_FatalError("tracemalloc_realloc() failed to allocate a trace"); + } +- TABLES_UNLOCK(); + } + else { +- /* new allocation */ ++ // New allocation + +- TABLES_LOCK(); + if (ADD_TRACE(ptr2, new_size) < 0) { +- /* Failed to allocate a trace for the new memory block */ +- TABLES_UNLOCK(); ++ // Failed to allocate a trace for the new memory block + alloc->free(alloc->ctx, ptr2); +- return NULL; ++ ptr2 = NULL; + } +- TABLES_UNLOCK(); ++ } ++ ++unlock: ++ TABLES_UNLOCK(); ++ if (need_gil) { ++ PyGILState_Release(gil_state); ++ } ++ ++done: ++ if (!reentrant) { ++ set_reentrant(0); + } + return ptr2; + } +@@ -603,170 +639,68 @@ + static void + tracemalloc_free(void *ctx, void *ptr) + { +- PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; +- +- if (ptr == NULL) ++ if (ptr == NULL) { + return; ++ } + +- /* GIL cannot be locked in PyMem_RawFree() because it would introduce +- a deadlock in _PyThreadState_DeleteCurrent(). */ +- ++ PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; + alloc->free(alloc->ctx, ptr); + +- TABLES_LOCK(); +- REMOVE_TRACE(ptr); +- TABLES_UNLOCK(); +-} +- +- +-static void* +-tracemalloc_alloc_gil(int use_calloc, void *ctx, size_t nelem, size_t elsize) +-{ +- void *ptr; +- + if (get_reentrant()) { +- PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; +- if (use_calloc) +- return alloc->calloc(alloc->ctx, nelem, elsize); +- else +- return alloc->malloc(alloc->ctx, nelem * elsize); ++ return; + } + +- /* Ignore reentrant call. PyObjet_Malloc() calls PyMem_Malloc() for +- allocations larger than 512 bytes, don't trace the same memory +- allocation twice. */ +- set_reentrant(1); ++ TABLES_LOCK(); + +- ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize); ++ if (tracemalloc_config.tracing) { ++ REMOVE_TRACE(ptr); ++ } ++ // else: gh-128679: tracemalloc.stop() was called by another thread + +- set_reentrant(0); +- return ptr; ++ TABLES_UNLOCK(); + } + + + static void* + tracemalloc_malloc_gil(void *ctx, size_t size) + { +- return tracemalloc_alloc_gil(0, ctx, 1, size); ++ return tracemalloc_alloc(0, 0, ctx, 1, size); + } + + + static void* + tracemalloc_calloc_gil(void *ctx, size_t nelem, size_t elsize) + { +- return tracemalloc_alloc_gil(1, ctx, nelem, elsize); ++ return tracemalloc_alloc(0, 1, ctx, nelem, elsize); + } + + + static void* + tracemalloc_realloc_gil(void *ctx, void *ptr, size_t new_size) + { +- void *ptr2; +- +- if (get_reentrant()) { +- /* Reentrant call to PyMem_Realloc() and PyMem_RawRealloc(). +- Example: PyMem_RawRealloc() is called internally by pymalloc +- (_PyObject_Malloc() and _PyObject_Realloc()) to allocate a new +- arena (new_arena()). */ +- PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; +- +- ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); +- if (ptr2 != NULL && ptr != NULL) { +- TABLES_LOCK(); +- REMOVE_TRACE(ptr); +- TABLES_UNLOCK(); +- } +- return ptr2; +- } +- +- /* Ignore reentrant call. PyObjet_Realloc() calls PyMem_Realloc() for +- allocations larger than 512 bytes. Don't trace the same memory +- allocation twice. */ +- set_reentrant(1); +- +- ptr2 = tracemalloc_realloc(ctx, ptr, new_size); +- +- set_reentrant(0); +- return ptr2; +-} +- +- +-#ifdef TRACE_RAW_MALLOC +-static void* +-tracemalloc_raw_alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize) +-{ +- PyGILState_STATE gil_state; +- void *ptr; +- +- if (get_reentrant()) { +- PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; +- if (use_calloc) +- return alloc->calloc(alloc->ctx, nelem, elsize); +- else +- return alloc->malloc(alloc->ctx, nelem * elsize); +- } +- +- /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc() +- indirectly which would call PyGILState_Ensure() if reentrant are not +- disabled. */ +- set_reentrant(1); +- +- gil_state = PyGILState_Ensure(); +- ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize); +- PyGILState_Release(gil_state); +- +- set_reentrant(0); +- return ptr; ++ return tracemalloc_realloc(0, ctx, ptr, new_size); + } + + + static void* + tracemalloc_raw_malloc(void *ctx, size_t size) + { +- return tracemalloc_raw_alloc(0, ctx, 1, size); ++ return tracemalloc_alloc(1, 0, ctx, 1, size); + } + + + static void* + tracemalloc_raw_calloc(void *ctx, size_t nelem, size_t elsize) + { +- return tracemalloc_raw_alloc(1, ctx, nelem, elsize); ++ return tracemalloc_alloc(1, 1, ctx, nelem, elsize); + } + + + static void* + tracemalloc_raw_realloc(void *ctx, void *ptr, size_t new_size) + { +- PyGILState_STATE gil_state; +- void *ptr2; +- +- if (get_reentrant()) { +- /* Reentrant call to PyMem_RawRealloc(). */ +- PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; +- +- ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); +- +- if (ptr2 != NULL && ptr != NULL) { +- TABLES_LOCK(); +- REMOVE_TRACE(ptr); +- TABLES_UNLOCK(); +- } +- return ptr2; +- } +- +- /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc() +- indirectly which would call PyGILState_Ensure() if reentrant calls are +- not disabled. */ +- set_reentrant(1); +- +- gil_state = PyGILState_Ensure(); +- ptr2 = tracemalloc_realloc(ctx, ptr, new_size); +- PyGILState_Release(gil_state); +- +- set_reentrant(0); +- return ptr2; ++ return tracemalloc_realloc(1, ctx, ptr, new_size); + } +-#endif /* TRACE_RAW_MALLOC */ + + + static void +@@ -777,60 +711,36 @@ + } + + +-/* reentrant flag must be set to call this function and GIL must be held */ + static void +-tracemalloc_clear_traces(void) ++tracemalloc_clear_traces_unlocked(void) + { +- /* The GIL protects variables against concurrent access */ +- assert(PyGILState_Check()); ++ // Clearing tracemalloc_filenames requires the GIL to call Py_DECREF() ++ _Py_AssertHoldsTstate(); ++ ++ set_reentrant(1); + +- TABLES_LOCK(); + _Py_hashtable_clear(tracemalloc_traces); + _Py_hashtable_clear(tracemalloc_domains); ++ _Py_hashtable_clear(tracemalloc_tracebacks); ++ _Py_hashtable_clear(tracemalloc_filenames); ++ + tracemalloc_traced_memory = 0; + tracemalloc_peak_traced_memory = 0; +- TABLES_UNLOCK(); +- +- _Py_hashtable_clear(tracemalloc_tracebacks); + +- _Py_hashtable_clear(tracemalloc_filenames); ++ set_reentrant(0); + } + + +-int ++PyStatus + _PyTraceMalloc_Init(void) + { +- if (tracemalloc_config.initialized == TRACEMALLOC_FINALIZED) { +- PyErr_SetString(PyExc_RuntimeError, +- "the tracemalloc module has been unloaded"); +- return -1; +- } +- +- if (tracemalloc_config.initialized == TRACEMALLOC_INITIALIZED) +- return 0; ++ assert(tracemalloc_config.initialized == TRACEMALLOC_NOT_INITIALIZED); + + PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw); + +-#ifdef REENTRANT_THREADLOCAL + if (PyThread_tss_create(&tracemalloc_reentrant_key) != 0) { +-#ifdef MS_WINDOWS +- PyErr_SetFromWindowsErr(0); +-#else +- PyErr_SetFromErrno(PyExc_OSError); +-#endif +- return -1; +- } +-#endif +- +-#if defined(TRACE_RAW_MALLOC) +- if (tables_lock == NULL) { +- tables_lock = PyThread_allocate_lock(); +- if (tables_lock == NULL) { +- PyErr_SetString(PyExc_RuntimeError, "cannot allocate lock"); +- return -1; +- } ++ return _PyStatus_NO_MEMORY(); + } +-#endif + + tracemalloc_filenames = hashtable_new(hashtable_hash_pyobject, + hashtable_compare_unicode, +@@ -844,9 +754,9 @@ + tracemalloc_domains = tracemalloc_create_domains_table(); + + if (tracemalloc_filenames == NULL || tracemalloc_tracebacks == NULL +- || tracemalloc_traces == NULL || tracemalloc_domains == NULL) { +- PyErr_NoMemory(); +- return -1; ++ || tracemalloc_traces == NULL || tracemalloc_domains == NULL) ++ { ++ return _PyStatus_NO_MEMORY(); + } + + tracemalloc_empty_traceback.nframe = 1; +@@ -857,7 +767,7 @@ + tracemalloc_empty_traceback.hash = traceback_hash(&tracemalloc_empty_traceback); + + tracemalloc_config.initialized = TRACEMALLOC_INITIALIZED; +- return 0; ++ return _PyStatus_OK(); + } + + +@@ -876,25 +786,13 @@ + _Py_hashtable_destroy(tracemalloc_tracebacks); + _Py_hashtable_destroy(tracemalloc_filenames); + +-#if defined(TRACE_RAW_MALLOC) +- if (tables_lock != NULL) { +- PyThread_free_lock(tables_lock); +- tables_lock = NULL; +- } +-#endif +- +-#ifdef REENTRANT_THREADLOCAL + PyThread_tss_delete(&tracemalloc_reentrant_key); +-#endif + } + + + int + _PyTraceMalloc_Start(int max_nframe) + { +- PyMemAllocatorEx alloc; +- size_t size; +- + if (max_nframe < 1 || (unsigned long) max_nframe > MAX_NFRAME) { + PyErr_Format(PyExc_ValueError, + "the number of frames must be in range [1; %lu]", +@@ -902,23 +800,15 @@ + return -1; + } + +- if (_PyTraceMalloc_Init() < 0) { +- return -1; +- } +- +- if (PyRefTracer_SetTracer(_PyTraceMalloc_TraceRef, NULL) < 0) { +- return -1; +- } +- +- if (tracemalloc_config.tracing) { +- /* hook already installed: do nothing */ ++ if (_PyTraceMalloc_IsTracing()) { ++ /* hooks already installed: do nothing */ + return 0; + } + + tracemalloc_config.max_nframe = max_nframe; + + /* allocate a buffer to store a new traceback */ +- size = TRACEBACK_SIZE(max_nframe); ++ size_t size = TRACEBACK_SIZE(max_nframe); + assert(tracemalloc_traceback == NULL); + tracemalloc_traceback = raw_malloc(size); + if (tracemalloc_traceback == NULL) { +@@ -926,7 +816,7 @@ + return -1; + } + +-#ifdef TRACE_RAW_MALLOC ++ PyMemAllocatorEx alloc; + alloc.malloc = tracemalloc_raw_malloc; + alloc.calloc = tracemalloc_raw_calloc; + alloc.realloc = tracemalloc_raw_realloc; +@@ -935,7 +825,6 @@ + alloc.ctx = &allocators.raw; + PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw); + PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc); +-#endif + + alloc.malloc = tracemalloc_malloc_gil; + alloc.calloc = tracemalloc_calloc_gil; +@@ -950,8 +839,14 @@ + PyMem_GetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj); + PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &alloc); + ++ if (PyRefTracer_SetTracer(_PyTraceMalloc_TraceRef, NULL) < 0) { ++ return -1; ++ } ++ + /* everything is ready: start tracing Python memory allocations */ ++ TABLES_LOCK(); + tracemalloc_config.tracing = 1; ++ TABLES_UNLOCK(); + + return 0; + } +@@ -960,24 +855,30 @@ + void + _PyTraceMalloc_Stop(void) + { +- if (!tracemalloc_config.tracing) +- return; ++ TABLES_LOCK(); ++ ++ if (!tracemalloc_config.tracing) { ++ goto done; ++ } + + /* stop tracing Python memory allocations */ + tracemalloc_config.tracing = 0; + + /* unregister the hook on memory allocators */ +-#ifdef TRACE_RAW_MALLOC + PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw); +-#endif + PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem); + PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj); + +- tracemalloc_clear_traces(); ++ tracemalloc_clear_traces_unlocked(); + + /* release memory */ + raw_free(tracemalloc_traceback); + tracemalloc_traceback = NULL; ++ ++ (void)PyRefTracer_SetTracer(NULL, NULL); ++ ++done: ++ TABLES_UNLOCK(); + } + + +@@ -985,15 +886,16 @@ + static PyObject* + frame_to_pyobject(frame_t *frame) + { +- PyObject *frame_obj, *lineno_obj; ++ assert(get_reentrant()); + +- frame_obj = PyTuple_New(2); +- if (frame_obj == NULL) ++ PyObject *frame_obj = PyTuple_New(2); ++ if (frame_obj == NULL) { + return NULL; ++ } + + PyTuple_SET_ITEM(frame_obj, 0, Py_NewRef(frame->filename)); + +- lineno_obj = PyLong_FromUnsignedLong(frame->lineno); ++ PyObject *lineno_obj = PyLong_FromUnsignedLong(frame->lineno); + if (lineno_obj == NULL) { + Py_DECREF(frame_obj); + return NULL; +@@ -1008,7 +910,6 @@ + traceback_to_pyobject(traceback_t *traceback, _Py_hashtable_t *intern_table) + { + PyObject *frames; +- + if (intern_table != NULL) { + frames = _Py_hashtable_get(intern_table, (const void *)traceback); + if (frames) { +@@ -1017,8 +918,9 @@ + } + + frames = PyTuple_New(traceback->nframe); +- if (frames == NULL) ++ if (frames == NULL) { + return NULL; ++ } + + for (int i=0; i < traceback->nframe; i++) { + PyObject *frame = frame_to_pyobject(&traceback->frames[i]); +@@ -1046,14 +948,14 @@ + trace_to_pyobject(unsigned int domain, const trace_t *trace, + _Py_hashtable_t *intern_tracebacks) + { +- PyObject *trace_obj = NULL; +- PyObject *obj; ++ assert(get_reentrant()); + +- trace_obj = PyTuple_New(4); +- if (trace_obj == NULL) ++ PyObject *trace_obj = PyTuple_New(4); ++ if (trace_obj == NULL) { + return NULL; ++ } + +- obj = PyLong_FromSize_t(domain); ++ PyObject *obj = PyLong_FromSize_t(domain); + if (obj == NULL) { + Py_DECREF(trace_obj); + return NULL; +@@ -1100,7 +1002,6 @@ + void *user_data) + { + _Py_hashtable_t *traces2 = (_Py_hashtable_t *)user_data; +- + trace_t *trace = (trace_t *)value; + + trace_t *trace2 = raw_malloc(sizeof(trace_t)); +@@ -1141,7 +1042,6 @@ + void *user_data) + { + _Py_hashtable_t *domains2 = (_Py_hashtable_t *)user_data; +- + unsigned int domain = (unsigned int)FROM_PTR(key); + _Py_hashtable_t *traces = (_Py_hashtable_t *)value; + +@@ -1182,7 +1082,6 @@ + void *user_data) + { + get_traces_t *get_traces = user_data; +- + const trace_t *trace = (const trace_t *)value; + + PyObject *tuple = trace_to_pyobject(get_traces->domain, trace, +@@ -1196,7 +1095,6 @@ + if (res < 0) { + return 1; + } +- + return 0; + } + +@@ -1207,7 +1105,6 @@ + void *user_data) + { + get_traces_t *get_traces = user_data; +- + unsigned int domain = (unsigned int)FROM_PTR(key); + _Py_hashtable_t *traces = (_Py_hashtable_t *)value; + +@@ -1227,27 +1124,21 @@ + + + static traceback_t* +-tracemalloc_get_traceback(unsigned int domain, uintptr_t ptr) ++tracemalloc_get_traceback_unlocked(unsigned int domain, uintptr_t ptr) + { +- +- if (!tracemalloc_config.tracing) ++ if (!tracemalloc_config.tracing) { + return NULL; ++ } + +- trace_t *trace; +- TABLES_LOCK(); + _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain); +- if (traces) { +- trace = _Py_hashtable_get(traces, TO_PTR(ptr)); +- } +- else { +- trace = NULL; ++ if (!traces) { ++ return NULL; + } +- TABLES_UNLOCK(); + ++ trace_t *trace = _Py_hashtable_get(traces, TO_PTR(ptr)); + if (!trace) { + return NULL; + } +- + return trace->traceback; + } + +@@ -1269,24 +1160,28 @@ + void + _PyMem_DumpTraceback(int fd, const void *ptr) + { +- traceback_t *traceback; +- int i; +- ++ TABLES_LOCK(); + if (!tracemalloc_config.tracing) { + PUTS(fd, "Enable tracemalloc to get the memory block " + "allocation traceback\n\n"); +- return; ++ goto done; + } + +- traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, (uintptr_t)ptr); +- if (traceback == NULL) +- return; ++ traceback_t *traceback; ++ traceback = tracemalloc_get_traceback_unlocked(DEFAULT_DOMAIN, ++ (uintptr_t)ptr); ++ if (traceback == NULL) { ++ goto done; ++ } + + PUTS(fd, "Memory block allocated at (most recent call first):\n"); +- for (i=0; i < traceback->nframe; i++) { ++ for (int i=0; i < traceback->nframe; i++) { + _PyMem_DumpFrame(fd, &traceback->frames[i]); + } + PUTS(fd, "\n"); ++ ++done: ++ TABLES_UNLOCK(); + } + + #undef PUTS +@@ -1307,45 +1202,48 @@ + PyTraceMalloc_Track(unsigned int domain, uintptr_t ptr, + size_t size) + { +- int res; +- PyGILState_STATE gil_state; ++ PyGILState_STATE gil_state = PyGILState_Ensure(); ++ TABLES_LOCK(); + +- if (!tracemalloc_config.tracing) { ++ int result; ++ if (tracemalloc_config.tracing) { ++ result = tracemalloc_add_trace_unlocked(domain, ptr, size); ++ } ++ else { + /* tracemalloc is not tracing: do nothing */ +- return -2; ++ result = -2; + } + +- gil_state = PyGILState_Ensure(); +- +- TABLES_LOCK(); +- res = tracemalloc_add_trace(domain, ptr, size); + TABLES_UNLOCK(); +- + PyGILState_Release(gil_state); +- return res; ++ return result; + } + + + int + PyTraceMalloc_Untrack(unsigned int domain, uintptr_t ptr) + { +- if (!tracemalloc_config.tracing) { ++ TABLES_LOCK(); ++ ++ int result; ++ if (tracemalloc_config.tracing) { ++ tracemalloc_remove_trace_unlocked(domain, ptr); ++ result = 0; ++ } ++ else { + /* tracemalloc is not tracing: do nothing */ +- return -2; ++ result = -2; + } + +- TABLES_LOCK(); +- tracemalloc_remove_trace(domain, ptr); + TABLES_UNLOCK(); +- +- return 0; ++ return result; + } + + + void + _PyTraceMalloc_Fini(void) + { +- assert(PyGILState_Check()); ++ _Py_AssertHoldsTstate(); + tracemalloc_deinit(); + } + +@@ -1355,87 +1253,102 @@ + + Do nothing if tracemalloc is not tracing memory allocations + or if the object memory block is not already traced. */ +-int +-_PyTraceMalloc_TraceRef(PyObject *op, PyRefTracerEvent event, void* Py_UNUSED(ignore)) ++static int ++_PyTraceMalloc_TraceRef(PyObject *op, PyRefTracerEvent event, ++ void* Py_UNUSED(ignore)) + { + if (event != PyRefTracer_CREATE) { + return 0; + } ++ if (get_reentrant()) { ++ return 0; ++ } + +- assert(PyGILState_Check()); ++ _Py_AssertHoldsTstate(); ++ TABLES_LOCK(); + + if (!tracemalloc_config.tracing) { +- /* tracemalloc is not tracing: do nothing */ +- return -1; ++ goto done; + } + + PyTypeObject *type = Py_TYPE(op); + const size_t presize = _PyType_PreHeaderSize(type); + uintptr_t ptr = (uintptr_t)((char *)op - presize); + +- int res = -1; +- +- TABLES_LOCK(); + trace_t *trace = _Py_hashtable_get(tracemalloc_traces, TO_PTR(ptr)); + if (trace != NULL) { + /* update the traceback of the memory block */ + traceback_t *traceback = traceback_new(); + if (traceback != NULL) { + trace->traceback = traceback; +- res = 0; + } + } + /* else: cannot track the object, its memory block size is unknown */ +- TABLES_UNLOCK(); + +- return res; ++done: ++ TABLES_UNLOCK(); ++ return 0; + } + + + PyObject* + _PyTraceMalloc_GetTraceback(unsigned int domain, uintptr_t ptr) + { +- traceback_t *traceback; ++ TABLES_LOCK(); + +- traceback = tracemalloc_get_traceback(domain, ptr); +- if (traceback == NULL) +- Py_RETURN_NONE; ++ traceback_t *traceback = tracemalloc_get_traceback_unlocked(domain, ptr); ++ PyObject *result; ++ if (traceback) { ++ set_reentrant(1); ++ result = traceback_to_pyobject(traceback, NULL); ++ set_reentrant(0); ++ } ++ else { ++ result = Py_NewRef(Py_None); ++ } + +- return traceback_to_pyobject(traceback, NULL); ++ TABLES_UNLOCK(); ++ return result; + } + + int + _PyTraceMalloc_IsTracing(void) + { +- return tracemalloc_config.tracing; ++ TABLES_LOCK(); ++ int tracing = tracemalloc_config.tracing; ++ TABLES_UNLOCK(); ++ return tracing; + } + + void + _PyTraceMalloc_ClearTraces(void) + { +- +- if (!tracemalloc_config.tracing) { +- return; ++ TABLES_LOCK(); ++ if (tracemalloc_config.tracing) { ++ tracemalloc_clear_traces_unlocked(); + } +- set_reentrant(1); +- tracemalloc_clear_traces(); +- set_reentrant(0); ++ TABLES_UNLOCK(); + } + + PyObject * + _PyTraceMalloc_GetTraces(void) + { ++ TABLES_LOCK(); ++ set_reentrant(1); ++ + get_traces_t get_traces; + get_traces.domain = DEFAULT_DOMAIN; + get_traces.traces = NULL; + get_traces.domains = NULL; + get_traces.tracebacks = NULL; + get_traces.list = PyList_New(0); +- if (get_traces.list == NULL) +- goto error; ++ if (get_traces.list == NULL) { ++ goto finally; ++ } + +- if (!tracemalloc_config.tracing) +- return get_traces.list; ++ if (!tracemalloc_config.tracing) { ++ goto finally; ++ } + + /* the traceback hash table is used temporarily to intern traceback tuple + of (filename, lineno) tuples */ +@@ -1449,24 +1362,17 @@ + // Copy all traces so tracemalloc_get_traces_fill() doesn't have to disable + // temporarily tracemalloc which would impact other threads and so would + // miss allocations while get_traces() is called. +- TABLES_LOCK(); + get_traces.traces = tracemalloc_copy_traces(tracemalloc_traces); +- TABLES_UNLOCK(); +- + if (get_traces.traces == NULL) { + goto no_memory; + } + +- TABLES_LOCK(); + get_traces.domains = tracemalloc_copy_domains(tracemalloc_domains); +- TABLES_UNLOCK(); +- + if (get_traces.domains == NULL) { + goto no_memory; + } + + // Convert traces to a list of tuples +- set_reentrant(1); + int err = _Py_hashtable_foreach(get_traces.traces, + tracemalloc_get_traces_fill, + &get_traces); +@@ -1475,20 +1381,22 @@ + tracemalloc_get_traces_domain, + &get_traces); + } +- set_reentrant(0); ++ + if (err) { +- goto error; ++ Py_CLEAR(get_traces.list); ++ goto finally; + } +- + goto finally; + + no_memory: + PyErr_NoMemory(); +- +-error: + Py_CLEAR(get_traces.list); ++ goto finally; + + finally: ++ set_reentrant(0); ++ TABLES_UNLOCK(); ++ + if (get_traces.tracebacks != NULL) { + _Py_hashtable_destroy(get_traces.tracebacks); + } +@@ -1506,37 +1414,33 @@ + _PyTraceMalloc_GetObjectTraceback(PyObject *obj) + /*[clinic end generated code: output=41ee0553a658b0aa input=29495f1b21c53212]*/ + { +- PyTypeObject *type; +- traceback_t *traceback; +- +- type = Py_TYPE(obj); ++ PyTypeObject *type = Py_TYPE(obj); + const size_t presize = _PyType_PreHeaderSize(type); + uintptr_t ptr = (uintptr_t)((char *)obj - presize); +- +- traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, ptr); +- if (traceback == NULL) { +- Py_RETURN_NONE; +- } +- +- return traceback_to_pyobject(traceback, NULL); ++ return _PyTraceMalloc_GetTraceback(DEFAULT_DOMAIN, ptr); + } + +-int _PyTraceMalloc_GetTracebackLimit(void) { ++int _PyTraceMalloc_GetTracebackLimit(void) ++{ + return tracemalloc_config.max_nframe; + } + + size_t +-_PyTraceMalloc_GetMemory(void) { +- ++_PyTraceMalloc_GetMemory(void) ++{ ++ TABLES_LOCK(); + size_t size; ++ if (tracemalloc_config.tracing) { ++ size = _Py_hashtable_size(tracemalloc_tracebacks); ++ size += _Py_hashtable_size(tracemalloc_filenames); + +- size = _Py_hashtable_size(tracemalloc_tracebacks); +- size += _Py_hashtable_size(tracemalloc_filenames); +- +- TABLES_LOCK(); +- size += _Py_hashtable_size(tracemalloc_traces); +- _Py_hashtable_foreach(tracemalloc_domains, +- tracemalloc_get_tracemalloc_memory_cb, &size); ++ size += _Py_hashtable_size(tracemalloc_traces); ++ _Py_hashtable_foreach(tracemalloc_domains, ++ tracemalloc_get_tracemalloc_memory_cb, &size); ++ } ++ else { ++ size = 0; ++ } + TABLES_UNLOCK(); + return size; + } +@@ -1545,26 +1449,27 @@ + PyObject * + _PyTraceMalloc_GetTracedMemory(void) + { +- Py_ssize_t size, peak_size; +- +- if (!tracemalloc_config.tracing) +- return Py_BuildValue("ii", 0, 0); +- + TABLES_LOCK(); +- size = tracemalloc_traced_memory; +- peak_size = tracemalloc_peak_traced_memory; ++ Py_ssize_t traced, peak; ++ if (tracemalloc_config.tracing) { ++ traced = tracemalloc_traced_memory; ++ peak = tracemalloc_peak_traced_memory; ++ } ++ else { ++ traced = 0; ++ peak = 0; ++ } + TABLES_UNLOCK(); + +- return Py_BuildValue("nn", size, peak_size); ++ return Py_BuildValue("nn", traced, peak); + } + + void + _PyTraceMalloc_ResetPeak(void) + { +- if (!tracemalloc_config.tracing) { +- return; +- } + TABLES_LOCK(); +- tracemalloc_peak_traced_memory = tracemalloc_traced_memory; ++ if (tracemalloc_config.tracing) { ++ tracemalloc_peak_traced_memory = tracemalloc_traced_memory; ++ } + TABLES_UNLOCK(); + } +diff --git a/Python/uniqueid.c b/Python/uniqueid.c +index b9f30713fee..64c3e6cfbbe 100644 +--- a/Python/uniqueid.c ++++ b/Python/uniqueid.c +@@ -86,7 +86,7 @@ + if (pool->freelist == NULL) { + if (resize_interp_type_id_pool(pool) < 0) { + UNLOCK_POOL(pool); +- return -1; ++ return _Py_INVALID_UNIQUE_ID; + } + } + +@@ -94,7 +94,9 @@ + pool->freelist = entry->next; + entry->obj = obj; + _PyObject_SetDeferredRefcount(obj); +- Py_ssize_t unique_id = (entry - pool->table); ++ // The unique id is one plus the index of the entry in the table. ++ Py_ssize_t unique_id = (entry - pool->table) + 1; ++ assert(unique_id > 0); + UNLOCK_POOL(pool); + return unique_id; + } +@@ -106,8 +108,9 @@ + struct _Py_unique_id_pool *pool = &interp->unique_ids; + + LOCK_POOL(pool); +- assert(unique_id >= 0 && unique_id < pool->size); +- _Py_unique_id_entry *entry = &pool->table[unique_id]; ++ assert(unique_id > 0 && unique_id <= pool->size); ++ Py_ssize_t idx = unique_id - 1; ++ _Py_unique_id_entry *entry = &pool->table[idx]; + entry->next = pool->freelist; + pool->freelist = entry; + UNLOCK_POOL(pool); +@@ -116,18 +119,18 @@ + static Py_ssize_t + clear_unique_id(PyObject *obj) + { +- Py_ssize_t id = -1; ++ Py_ssize_t id = _Py_INVALID_UNIQUE_ID; + if (PyType_Check(obj)) { + if (PyType_HasFeature((PyTypeObject *)obj, Py_TPFLAGS_HEAPTYPE)) { + PyHeapTypeObject *ht = (PyHeapTypeObject *)obj; + id = ht->unique_id; +- ht->unique_id = -1; ++ ht->unique_id = _Py_INVALID_UNIQUE_ID; + } + } + else if (PyCode_Check(obj)) { + PyCodeObject *co = (PyCodeObject *)obj; + id = co->_co_unique_id; +- co->_co_unique_id = -1; ++ co->_co_unique_id = _Py_INVALID_UNIQUE_ID; + } + else if (PyDict_Check(obj)) { + PyDictObject *mp = (PyDictObject *)obj; +@@ -141,23 +144,23 @@ + _PyObject_DisablePerThreadRefcounting(PyObject *obj) + { + Py_ssize_t id = clear_unique_id(obj); +- if (id >= 0) { ++ if (id != _Py_INVALID_UNIQUE_ID) { + _PyObject_ReleaseUniqueId(id); + } + } + + void +-_PyObject_ThreadIncrefSlow(PyObject *obj, Py_ssize_t unique_id) ++_PyObject_ThreadIncrefSlow(PyObject *obj, size_t idx) + { + _PyThreadStateImpl *tstate = (_PyThreadStateImpl *)_PyThreadState_GET(); +- if (unique_id < 0 || resize_local_refcounts(tstate) < 0) { ++ if (((Py_ssize_t)idx) < 0 || resize_local_refcounts(tstate) < 0) { + // just incref the object directly. + Py_INCREF(obj); + return; + } + +- assert(unique_id < tstate->refcounts.size); +- tstate->refcounts.values[unique_id]++; ++ assert(idx < (size_t)tstate->refcounts.size); ++ tstate->refcounts.values[idx]++; + #ifdef Py_REF_DEBUG + _Py_IncRefTotal((PyThreadState *)tstate); + #endif +@@ -217,7 +220,7 @@ + if (obj != NULL) { + Py_ssize_t id = clear_unique_id(obj); + (void)id; +- assert(id == i); ++ assert(id == i + 1); + } + } + PyMem_Free(pool->table); +diff --git a/README.rst b/README.rst +index 02776205e6d..0496d231ca7 100644 +--- a/README.rst ++++ b/README.rst +@@ -1,4 +1,4 @@ +-This is Python version 3.14.0 alpha 3 ++This is Python version 3.14.0 alpha 5 + ===================================== + + .. image:: https://github.com/python/cpython/actions/workflows/build.yml/badge.svg?branch=main&event=push +--- /dev/null ++++ b/Tools/build/compute-changes.py +@@ -0,0 +1,183 @@ ++"""Determine which GitHub Actions workflows to run. ++ ++Called by ``.github/workflows/reusable-context.yml``. ++We only want to run tests on PRs when related files are changed, ++or when someone triggers a manual workflow run. ++This improves developer experience by not doing (slow) ++unnecessary work in GHA, and saves CI resources. ++""" ++ ++from __future__ import annotations ++ ++import os ++import subprocess ++from dataclasses import dataclass ++from pathlib import Path ++ ++TYPE_CHECKING = False ++if TYPE_CHECKING: ++ from collections.abc import Set ++ ++GITHUB_DEFAULT_BRANCH = os.environ["GITHUB_DEFAULT_BRANCH"] ++GITHUB_CODEOWNERS_PATH = Path(".github/CODEOWNERS") ++GITHUB_WORKFLOWS_PATH = Path(".github/workflows") ++CONFIGURATION_FILE_NAMES = frozenset({ ++ ".pre-commit-config.yaml", ++ ".ruff.toml", ++ "mypy.ini", ++}) ++SUFFIXES_C_OR_CPP = frozenset({".c", ".h", ".cpp"}) ++SUFFIXES_DOCUMENTATION = frozenset({".rst", ".md"}) ++ ++ ++@dataclass(kw_only=True, slots=True) ++class Outputs: ++ run_ci_fuzz: bool = False ++ run_docs: bool = False ++ run_tests: bool = False ++ run_windows_msi: bool = False ++ ++ ++def compute_changes() -> None: ++ target_branch, head_branch = git_branches() ++ if target_branch and head_branch: ++ # Getting changed files only makes sense on a pull request ++ files = get_changed_files( ++ f"origin/{target_branch}", f"origin/{head_branch}" ++ ) ++ outputs = process_changed_files(files) ++ else: ++ # Otherwise, just run the tests ++ outputs = Outputs(run_tests=True) ++ outputs = process_target_branch(outputs, target_branch) ++ ++ if outputs.run_tests: ++ print("Run tests") ++ ++ if outputs.run_ci_fuzz: ++ print("Run CIFuzz tests") ++ else: ++ print("Branch too old for CIFuzz tests; or no C files were changed") ++ ++ if outputs.run_docs: ++ print("Build documentation") ++ ++ if outputs.run_windows_msi: ++ print("Build Windows MSI") ++ ++ print(outputs) ++ ++ write_github_output(outputs) ++ ++ ++def git_branches() -> tuple[str, str]: ++ target_branch = os.environ.get("GITHUB_BASE_REF", "") ++ target_branch = target_branch.removeprefix("refs/heads/") ++ print(f"target branch: {target_branch!r}") ++ ++ head_branch = os.environ.get("GITHUB_HEAD_REF", "") ++ head_branch = head_branch.removeprefix("refs/heads/") ++ print(f"head branch: {head_branch!r}") ++ return target_branch, head_branch ++ ++ ++def get_changed_files( ++ ref_a: str = GITHUB_DEFAULT_BRANCH, ref_b: str = "HEAD" ++) -> Set[Path]: ++ """List the files changed between two Git refs, filtered by change type.""" ++ args = ("git", "diff", "--name-only", f"{ref_a}...{ref_b}", "--") ++ print(*args) ++ changed_files_result = subprocess.run( ++ args, stdout=subprocess.PIPE, check=True, encoding="utf-8" ++ ) ++ changed_files = changed_files_result.stdout.strip().splitlines() ++ return frozenset(map(Path, filter(None, map(str.strip, changed_files)))) ++ ++ ++def process_changed_files(changed_files: Set[Path]) -> Outputs: ++ run_tests = False ++ run_ci_fuzz = False ++ run_docs = False ++ run_windows_msi = False ++ ++ for file in changed_files: ++ # Documentation files ++ doc_or_misc = file.parts[0] in {"Doc", "Misc"} ++ doc_file = file.suffix in SUFFIXES_DOCUMENTATION or doc_or_misc ++ ++ if file.parent == GITHUB_WORKFLOWS_PATH: ++ if file.name == "build.yml": ++ run_tests = run_ci_fuzz = True ++ if file.name == "reusable-docs.yml": ++ run_docs = True ++ if file.name == "reusable-windows-msi.yml": ++ run_windows_msi = True ++ ++ if not ( ++ doc_file ++ or file == GITHUB_CODEOWNERS_PATH ++ or file.name in CONFIGURATION_FILE_NAMES ++ ): ++ run_tests = True ++ ++ # The fuzz tests are pretty slow so they are executed only for PRs ++ # changing relevant files. ++ if file.suffix in SUFFIXES_C_OR_CPP: ++ run_ci_fuzz = True ++ if file.parts[:2] in { ++ ("configure",), ++ ("Modules", "_xxtestfuzz"), ++ }: ++ run_ci_fuzz = True ++ ++ # Check for changed documentation-related files ++ if doc_file: ++ run_docs = True ++ ++ # Check for changed MSI installer-related files ++ if file.parts[:2] == ("Tools", "msi"): ++ run_windows_msi = True ++ ++ return Outputs( ++ run_ci_fuzz=run_ci_fuzz, ++ run_docs=run_docs, ++ run_tests=run_tests, ++ run_windows_msi=run_windows_msi, ++ ) ++ ++ ++def process_target_branch(outputs: Outputs, git_branch: str) -> Outputs: ++ if not git_branch: ++ outputs.run_tests = True ++ ++ # CIFuzz / OSS-Fuzz compatibility with older branches may be broken. ++ if git_branch != GITHUB_DEFAULT_BRANCH: ++ outputs.run_ci_fuzz = False ++ ++ if os.environ.get("GITHUB_EVENT_NAME", "").lower() == "workflow_dispatch": ++ outputs.run_docs = True ++ outputs.run_windows_msi = True ++ ++ return outputs ++ ++ ++def write_github_output(outputs: Outputs) -> None: ++ # https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#default-environment-variables ++ # https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#setting-an-output-parameter ++ if "GITHUB_OUTPUT" not in os.environ: ++ print("GITHUB_OUTPUT not defined!") ++ return ++ ++ with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as f: ++ f.write(f"run-ci-fuzz={bool_lower(outputs.run_ci_fuzz)}\n") ++ f.write(f"run-docs={bool_lower(outputs.run_docs)}\n") ++ f.write(f"run-tests={bool_lower(outputs.run_tests)}\n") ++ f.write(f"run-windows-msi={bool_lower(outputs.run_windows_msi)}\n") ++ ++ ++def bool_lower(value: bool, /) -> str: ++ return "true" if value else "false" ++ ++ ++if __name__ == "__main__": ++ compute_changes() +diff --git a/Tools/build/mypy.ini b/Tools/build/mypy.ini +index cf1dac7fde5..06224163884 100644 +--- a/Tools/build/mypy.ini ++++ b/Tools/build/mypy.ini +@@ -1,5 +1,7 @@ + [mypy] +-files = Tools/build/generate_sbom.py ++files = ++ Tools/build/compute-changes.py, ++ Tools/build/generate_sbom.py + pretty = True + + # Make sure Python can still be built +@@ -8,6 +10,6 @@ + + # ...And be strict: + strict = True +-strict_concatenate = True ++extra_checks = True + enable_error_code = ignore-without-code,redundant-expr,truthy-bool,possibly-undefined + warn_unreachable = True +diff --git a/Tools/build/regen-configure.sh b/Tools/build/regen-configure.sh +index d2a613b1e40..c7683eb3676 100755 +--- a/Tools/build/regen-configure.sh ++++ b/Tools/build/regen-configure.sh +@@ -5,7 +5,7 @@ + # The check_autoconf_regen job of .github/workflows/build.yml must kept in + # sync with this script. Use the same container image than the job so the job + # doesn't need to run autoreconf in a container. +-IMAGE="ghcr.io/python/autoconf:2024.11.11.11786316759" ++IMAGE="ghcr.io/python/autoconf:2025.01.02.12581854023" + AUTORECONF="autoreconf -ivf -Werror" + + WORK_DIR="/src" +diff --git a/Tools/c-analyzer/TODO b/Tools/c-analyzer/TODO +index e81ceb29c64..edd0c4bc7fd 100644 +--- a/Tools/c-analyzer/TODO ++++ b/Tools/c-analyzer/TODO +@@ -69,7 +69,6 @@ + Objects/typeobject.c:next_version_tag static unsigned int next_version_tag + Python/Python-ast.c:init_types():initialized static int initialized + Python/bootstrap_hash.c:urandom_cache static struct { int fd; dev_t st_dev; ino_t st_ino; } urandom_cache +-Python/ceval.c:lltrace static int lltrace + Python/ceval.c:make_pending_calls():busy static int busy + Python/dynload_shlib.c:handles static struct { dev_t dev; ino_t ino; void *handle; } handles[128] + Python/dynload_shlib.c:nhandles static int nhandles +diff --git a/Tools/c-analyzer/c_analyzer/datafiles.py b/Tools/c-analyzer/c_analyzer/datafiles.py +index d5db3bd3ed7..79c201a5d3b 100644 +--- a/Tools/c-analyzer/c_analyzer/datafiles.py ++++ b/Tools/c-analyzer/c_analyzer/datafiles.py +@@ -104,7 +104,12 @@ + for v in varidinfo) + if reason in bogus: + reason = None +- varid = _info.DeclID.from_row(varidinfo) ++ try: ++ varid = _info.DeclID.from_row(varidinfo) ++ except BaseException as e: ++ e.add_note(f"Error occurred when processing row {varidinfo} in {infile}.") ++ e.add_note(f"Could it be that you added a row which is not tab-delimited?") ++ raise e + varid = varid.fix_filename(relroot, formatted=False, fixroot=False) + yield varid, reason + +diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv +index badd7b79102..54954cfb5f8 100644 +--- a/Tools/c-analyzer/cpython/globals-to-fix.tsv ++++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv +@@ -106,6 +106,8 @@ + Python/context.c - PyContextVar_Type - + Python/context.c - PyContext_Type - + Python/instruction_sequence.c - _PyInstructionSequence_Type - ++Python/instrumentation.c - _PyLegacyBranchEventHandler_Type - ++Python/instrumentation.c - _PyBranchesIterator - + Python/traceback.c - PyTraceBack_Type - + + ##----------------------- +@@ -405,7 +407,8 @@ + + ## other + Include/datetime.h - PyDateTimeAPI - +-Modules/_ctypes/cfield.c _ctypes_get_fielddesc initialized - ++Modules/_ctypes/cfield.c _ctypes_init_fielddesc initialized - ++Modules/_ctypes/cfield.c - formattable - + Modules/_ctypes/malloc_closure.c - _pagesize - + Modules/_cursesmodule.c - curses_module_loaded - + Modules/_cursesmodule.c - curses_initscr_called - +@@ -420,7 +423,6 @@ + ##----------------------- + ## state + +-Modules/_ctypes/cfield.c - formattable - + Modules/_ctypes/malloc_closure.c - free_list - + Modules/_curses_panel.c - lop - + Modules/_ssl/debughelpers.c _PySSL_keylog_callback lock - +@@ -442,3 +444,5 @@ + Modules/rotatingtree.c - random_stream - + Modules/rotatingtree.c - random_value - + Modules/rotatingtree.c - random_mutex - ++Modules/socketmodule.c - accept4_works - ++Modules/socketmodule.c - sock_cloexec_works - +diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv +index c8c30a7985a..df0262f9c84 100644 +--- a/Tools/c-analyzer/cpython/ignored.tsv ++++ b/Tools/c-analyzer/cpython/ignored.tsv +@@ -53,6 +53,9 @@ + ## thread-safe hashtable (internal locks) + Python/parking_lot.c - buckets - + ++## data needed for introspecting asyncio state from debuggers and profilers ++Modules/_asynciomodule.c - AsyncioDebug - ++ + + ################################## + ## state tied to Py_Main() +@@ -378,16 +381,13 @@ + Python/pystate.c - initial - + Python/specialize.c - adaptive_opcodes - + Python/specialize.c - cache_requirements - ++Python/specialize.c - binaryop_extend_descrs - + Python/stdlib_module_names.h - _Py_stdlib_module_names - + Python/sysmodule.c - perf_map_state - + Python/sysmodule.c - _PySys_ImplCacheTag - + Python/sysmodule.c - _PySys_ImplName - + Python/sysmodule.c - whatstrings - +-Python/optimizer.c - _PyDefaultOptimizer_Type - +-Python/optimizer.c - _PyCounterExecutor_Type - +-Python/optimizer.c - _PyCounterOptimizer_Type - + Python/optimizer.c - _PyUOpExecutor_Type - +-Python/optimizer.c - _PyUOpOptimizer_Type - + Python/optimizer.c - _PyOptimizer_Default - + Python/optimizer.c - _ColdExit_Type - + Python/optimizer.c - Py_FatalErrorExecutor - +@@ -444,6 +444,8 @@ + Modules/_testcapi/heaptype.c - _testcapimodule - + Modules/_testcapi/mem.c - FmData - + Modules/_testcapi/mem.c - FmHook - ++Modules/_testcapi/object.c - MyObject_dealloc_called - ++Modules/_testcapi/object.c - MyType - + Modules/_testcapi/structmember.c - test_structmembersType_OldAPI - + Modules/_testcapi/watchers.c - g_dict_watch_events - + Modules/_testcapi/watchers.c - g_dict_watchers_installed - +diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py +index eca851e6de8..c127d0334d9 100644 +--- a/Tools/cases_generator/analyzer.py ++++ b/Tools/cases_generator/analyzer.py +@@ -5,9 +5,17 @@ + import re + from typing import Optional + ++@dataclass ++class EscapingCall: ++ start: lexer.Token ++ call: lexer.Token ++ end: lexer.Token ++ kills: lexer.Token | None ++ + @dataclass + class Properties: +- escaping_calls: dict[lexer.Token, tuple[lexer.Token, lexer.Token]] ++ escaping_calls: dict[lexer.Token, EscapingCall] ++ escapes: bool + error_with_pop: bool + error_without_pop: bool + deopts: bool +@@ -23,10 +31,12 @@ + has_free: bool + side_exit: bool + pure: bool ++ uses_opcode: bool + tier: int | None = None + oparg_and_1: bool = False + const_oparg: int = -1 + needs_prev: bool = False ++ no_save_ip: bool = False + + def dump(self, indent: str) -> None: + simple_properties = self.__dict__.copy() +@@ -39,11 +49,12 @@ + + @staticmethod + def from_list(properties: list["Properties"]) -> "Properties": +- escaping_calls: dict[lexer.Token, tuple[lexer.Token, lexer.Token]] = {} ++ escaping_calls: dict[lexer.Token, EscapingCall] = {} + for p in properties: + escaping_calls.update(p.escaping_calls) + return Properties( + escaping_calls=escaping_calls, ++ escapes = any(p.escapes for p in properties), + error_with_pop=any(p.error_with_pop for p in properties), + error_without_pop=any(p.error_without_pop for p in properties), + deopts=any(p.deopts for p in properties), +@@ -56,22 +67,21 @@ + uses_co_consts=any(p.uses_co_consts for p in properties), + uses_co_names=any(p.uses_co_names for p in properties), + uses_locals=any(p.uses_locals for p in properties), ++ uses_opcode=any(p.uses_opcode for p in properties), + has_free=any(p.has_free for p in properties), + side_exit=any(p.side_exit for p in properties), + pure=all(p.pure for p in properties), + needs_prev=any(p.needs_prev for p in properties), ++ no_save_ip=all(p.no_save_ip for p in properties), + ) + + @property + def infallible(self) -> bool: + return not self.error_with_pop and not self.error_without_pop + +- @property +- def escapes(self) -> bool: +- return bool(self.escaping_calls) +- + SKIP_PROPERTIES = Properties( + escaping_calls={}, ++ escapes=False, + error_with_pop=False, + error_without_pop=False, + deopts=False, +@@ -84,9 +94,11 @@ + uses_co_consts=False, + uses_co_names=False, + uses_locals=False, ++ uses_opcode=False, + has_free=False, + side_exit=False, + pure=True, ++ no_save_ip=False, + ) + + +@@ -118,6 +130,8 @@ + return 0 + + ++ ++ + @dataclass + class StackItem: + name: str +@@ -216,7 +230,24 @@ + return False + + ++class Label: ++ ++ def __init__(self, name: str, spilled: bool, body: list[lexer.Token], properties: Properties): ++ self.name = name ++ self.spilled = spilled ++ self.body = body ++ self.properties = properties ++ ++ size:int = 0 ++ output_stores: list[lexer.Token] = [] ++ instruction_size = None ++ ++ def __str__(self) -> str: ++ return f"label({self.name})" ++ ++ + Part = Uop | Skip | Flush ++CodeSection = Uop | Label + + + @dataclass +@@ -289,6 +320,7 @@ + uops: dict[str, Uop] + families: dict[str, Family] + pseudos: dict[str, PseudoInstruction] ++ labels: dict[str, Label] + opmap: dict[str, int] + have_arg: int + min_instrumented: int +@@ -321,6 +353,17 @@ + cond = replace_op_arg_1 + return StackItem(item.name, item.type, cond, item.size) + ++def check_unused(stack: list[StackItem], input_names: dict[str, lexer.Token]) -> None: ++ "Unused items cannot be on the stack above used, non-peek items" ++ seen_unused = False ++ for item in reversed(stack): ++ if item.name == "unused": ++ seen_unused = True ++ elif item.peek: ++ break ++ elif seen_unused: ++ raise analysis_error(f"Cannot have used input '{item.name}' below an unused value on the stack", input_names[item.name]) ++ + + def analyze_stack( + op: parser.InstDef | parser.Pseudo, replace_op_arg_1: str | None = None +@@ -365,6 +408,7 @@ + for output in outputs: + if variable_used(op, output.name): + output.used = True ++ check_unused(inputs, input_names) + return StackEffect(inputs, outputs) + + +@@ -384,7 +428,7 @@ + """Find the tokens that make up the left-hand side of an assignment""" + offset = 0 + for tkn in reversed(node.block.tokens[: idx]): +- if tkn.kind in {"SEMI", "LBRACE", "RBRACE"}: ++ if tkn.kind in {"SEMI", "LBRACE", "RBRACE", "CMACRO"}: + return node.block.tokens[idx - offset : idx] + offset += 1 + return [] +@@ -472,22 +516,24 @@ + return refs + + +-def variable_used(node: parser.InstDef, name: str) -> bool: ++def variable_used(node: parser.CodeDef, name: str) -> bool: + """Determine whether a variable with a given name is used in a node.""" + return any( + token.kind == "IDENTIFIER" and token.text == name for token in node.block.tokens + ) + + +-def oparg_used(node: parser.InstDef) -> bool: ++def oparg_used(node: parser.CodeDef) -> bool: + """Determine whether `oparg` is used in a node.""" + return any( + token.kind == "IDENTIFIER" and token.text == "oparg" for token in node.tokens + ) + + +-def tier_variable(node: parser.InstDef) -> int | None: ++def tier_variable(node: parser.CodeDef) -> int | None: + """Determine whether a tier variable is used in a node.""" ++ if isinstance(node, parser.LabelDef): ++ return None + for token in node.tokens: + if token.kind == "ANNOTATION": + if token.text == "specializing": +@@ -497,21 +543,19 @@ + return None + + +-def has_error_with_pop(op: parser.InstDef) -> bool: ++def has_error_with_pop(op: parser.CodeDef) -> bool: + return ( + variable_used(op, "ERROR_IF") + or variable_used(op, "pop_1_error") + or variable_used(op, "exception_unwind") +- or variable_used(op, "resume_with_error") + ) + + +-def has_error_without_pop(op: parser.InstDef) -> bool: ++def has_error_without_pop(op: parser.CodeDef) -> bool: + return ( + variable_used(op, "ERROR_NO_POP") + or variable_used(op, "pop_1_error") + or variable_used(op, "exception_unwind") +- or variable_used(op, "resume_with_error") + ) + + +@@ -541,7 +585,6 @@ + "PyStackRef_AsPyObjectNew", + "PyStackRef_AsPyObjectSteal", + "PyStackRef_CLEAR", +- "PyStackRef_CLOSE", + "PyStackRef_CLOSE_SPECIALIZED", + "PyStackRef_DUP", + "PyStackRef_False", +@@ -564,8 +607,6 @@ + "PyUnicode_GET_LENGTH", + "PyUnicode_READ_CHAR", + "Py_ARRAY_LENGTH", +- "Py_CLEAR", +- "Py_DECREF", + "Py_FatalError", + "Py_INCREF", + "Py_IS_TYPE", +@@ -575,12 +616,12 @@ + "Py_TYPE", + "Py_UNREACHABLE", + "Py_Unicode_GET_LENGTH", +- "Py_XDECREF", + "_PyCode_CODE", + "_PyDictValues_AddToInsertionOrder", + "_PyErr_Occurred", + "_PyEval_FrameClearAndPop", + "_PyFloat_FromDouble_ConsumeInputs", ++ "_PyFrame_GetBytecode", + "_PyFrame_GetCode", + "_PyFrame_IsIncomplete", + "_PyFrame_PushUnchecked", +@@ -590,12 +631,13 @@ + "_PyGen_GetGeneratorFromFrame", + "_PyInterpreterState_GET", + "_PyList_AppendTakeRef", +- "_PyList_FromStackRefSteal", ++ "_PyList_FromStackRefStealOnSuccess", + "_PyList_ITEMS", + "_PyLong_Add", + "_PyLong_CompactValue", + "_PyLong_DigitCount", + "_PyLong_IsCompact", ++ "_PyLong_IsNegative", + "_PyLong_IsNonNegativeCompact", + "_PyLong_IsZero", + "_PyLong_Multiply", +@@ -608,8 +650,7 @@ + "_PyObject_InlineValues", + "_PyObject_ManagedDictPointer", + "_PyThreadState_HasStackSpace", +- "_PyTuple_FromArraySteal", +- "_PyTuple_FromStackRefSteal", ++ "_PyTuple_FromStackRefStealOnSuccess", + "_PyTuple_ITEMS", + "_PyType_HasFeature", + "_PyType_NewManagedObject", +@@ -617,7 +658,6 @@ + "_PyUnicode_JoinArray", + "_Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY", + "_Py_DECREF_NO_DEALLOC", +- "_Py_DECREF_SPECIALIZED", + "_Py_EnterRecursiveCallTstateUnchecked", + "_Py_ID", + "_Py_IsImmortal", +@@ -628,6 +668,7 @@ + "_Py_STR", + "_Py_TryIncrefCompare", + "_Py_TryIncrefCompareStackRef", ++ "_Py_atomic_compare_exchange_uint8", + "_Py_atomic_load_ptr_acquire", + "_Py_atomic_load_uintptr_relaxed", + "_Py_set_eval_breaker_bit", +@@ -635,11 +676,11 @@ + "assert", + "backoff_counter_triggers", + "initial_temperature_backoff_counter", +- "maybe_lltrace_resume_frame", ++ "JUMP_TO_LABEL", + "restart_backoff_counter", + ) + +-def find_stmt_start(node: parser.InstDef, idx: int) -> lexer.Token: ++def find_stmt_start(node: parser.CodeDef, idx: int) -> lexer.Token: + assert idx < len(node.block.tokens) + while True: + tkn = node.block.tokens[idx-1] +@@ -652,7 +693,7 @@ + return node.block.tokens[idx] + + +-def find_stmt_end(node: parser.InstDef, idx: int) -> lexer.Token: ++def find_stmt_end(node: parser.CodeDef, idx: int) -> lexer.Token: + assert idx < len(node.block.tokens) + while True: + idx += 1 +@@ -660,15 +701,15 @@ + if tkn.kind == "SEMI": + return node.block.tokens[idx+1] + +-def check_escaping_calls(instr: parser.InstDef, escapes: dict[lexer.Token, tuple[lexer.Token, lexer.Token]]) -> None: +- calls = {escapes[t][0] for t in escapes} ++def check_escaping_calls(instr: parser.CodeDef, escapes: dict[lexer.Token, EscapingCall]) -> None: ++ calls = {e.call for e in escapes.values()} + in_if = 0 + tkn_iter = iter(instr.block.tokens) + for tkn in tkn_iter: + if tkn.kind == "IF": + next(tkn_iter) + in_if = 1 +- if tkn.kind == "IDENTIFIER" and tkn.text in ("DEOPT_IF", "ERROR_IF"): ++ if tkn.kind == "IDENTIFIER" and tkn.text in ("DEOPT_IF", "ERROR_IF", "EXIT_IF"): + next(tkn_iter) + in_if = 1 + elif tkn.kind == "LPAREN" and in_if: +@@ -679,8 +720,8 @@ + elif tkn in calls and in_if: + raise analysis_error(f"Escaping call '{tkn.text} in condition", tkn) + +-def find_escaping_api_calls(instr: parser.InstDef) -> dict[lexer.Token, tuple[lexer.Token, lexer.Token]]: +- result: dict[lexer.Token, tuple[lexer.Token, lexer.Token]] = {} ++def find_escaping_api_calls(instr: parser.CodeDef) -> dict[lexer.Token, EscapingCall]: ++ result: dict[lexer.Token, EscapingCall] = {} + tokens = instr.block.tokens + for idx, tkn in enumerate(tokens): + try: +@@ -715,23 +756,30 @@ + continue + elif tkn.kind != "RBRACKET": + continue ++ if tkn.text in ("PyStackRef_CLOSE", "PyStackRef_XCLOSE"): ++ if len(tokens) <= idx+2: ++ raise analysis_error("Unexpected end of file", next_tkn) ++ kills = tokens[idx+2] ++ if kills.kind != "IDENTIFIER": ++ raise analysis_error(f"Expected identifier, got '{kills.text}'", kills) ++ else: ++ kills = None + start = find_stmt_start(instr, idx) + end = find_stmt_end(instr, idx) +- result[start] = tkn, end ++ result[start] = EscapingCall(start, tkn, end, kills) + check_escaping_calls(instr, result) + return result + + + EXITS = { + "DISPATCH", +- "GO_TO_INSTRUCTION", + "Py_UNREACHABLE", + "DISPATCH_INLINED", + "DISPATCH_GOTO", + } + + +-def always_exits(op: parser.InstDef) -> bool: ++def always_exits(op: parser.CodeDef) -> bool: + depth = 0 + tkn_iter = iter(op.tokens) + for tkn in tkn_iter: +@@ -790,7 +838,7 @@ + return False + + +-def compute_properties(op: parser.InstDef) -> Properties: ++def compute_properties(op: parser.CodeDef) -> Properties: + escaping_calls = find_escaping_api_calls(op) + has_free = ( + variable_used(op, "PyCell_New") +@@ -811,8 +859,12 @@ + ) + error_with_pop = has_error_with_pop(op) + error_without_pop = has_error_without_pop(op) ++ escapes = bool(escaping_calls) ++ pure = False if isinstance(op, parser.LabelDef) else "pure" in op.annotations ++ no_save_ip = False if isinstance(op, parser.LabelDef) else "no_save_ip" in op.annotations + return Properties( + escaping_calls=escaping_calls, ++ escapes=escapes, + error_with_pop=error_with_pop, + error_without_pop=error_without_pop, + deopts=deopts_if, +@@ -825,10 +877,11 @@ + stores_sp=variable_used(op, "SYNC_SP"), + uses_co_consts=variable_used(op, "FRAME_CO_CONSTS"), + uses_co_names=variable_used(op, "FRAME_CO_NAMES"), +- uses_locals=(variable_used(op, "GETLOCAL") or variable_used(op, "SETLOCAL")) +- and not has_free, ++ uses_locals=variable_used(op, "GETLOCAL") and not has_free, ++ uses_opcode=variable_used(op, "opcode"), + has_free=has_free, +- pure="pure" in op.annotations, ++ pure=pure, ++ no_save_ip=no_save_ip, + tier=tier_variable(op), + needs_prev=variable_used(op, "prev_instr"), + ) +@@ -1003,6 +1056,14 @@ + ) + + ++def add_label( ++ label: parser.LabelDef, ++ labels: dict[str, Label], ++) -> None: ++ properties = compute_properties(label) ++ labels[label.name] = Label(label.name, label.spilled, label.block.tokens, properties) ++ ++ + def assign_opcodes( + instructions: dict[str, Instruction], + families: dict[str, Family], +@@ -1121,6 +1182,7 @@ + uops: dict[str, Uop] = {} + families: dict[str, Family] = {} + pseudos: dict[str, PseudoInstruction] = {} ++ labels: dict[str, Label] = {} + for node in forest: + match node: + case parser.InstDef(name): +@@ -1135,6 +1197,8 @@ + pass + case parser.Pseudo(): + pass ++ case parser.LabelDef(): ++ pass + case _: + assert False + for node in forest: +@@ -1146,19 +1210,10 @@ + add_family(node, instructions, families) + case parser.Pseudo(): + add_pseudo(node, instructions, pseudos) ++ case parser.LabelDef(): ++ add_label(node, labels) + case _: + pass +- for uop in uops.values(): +- tkn_iter = iter(uop.body) +- for tkn in tkn_iter: +- if tkn.kind == "IDENTIFIER" and tkn.text == "GO_TO_INSTRUCTION": +- if next(tkn_iter).kind != "LPAREN": +- continue +- target = next(tkn_iter) +- if target.kind != "IDENTIFIER": +- continue +- if target.text in instructions: +- instructions[target.text].is_target = True + for uop in uops.values(): + uop.instruction_size = get_instruction_size_for_uop(instructions, uop) + # Special case BINARY_OP_INPLACE_ADD_UNICODE +@@ -1171,7 +1226,7 @@ + families["BINARY_OP"].members.append(inst) + opmap, first_arg, min_instrumented = assign_opcodes(instructions, families, pseudos) + return Analysis( +- instructions, uops, families, pseudos, opmap, first_arg, min_instrumented ++ instructions, uops, families, pseudos, labels, opmap, first_arg, min_instrumented + ) + + +diff --git a/Tools/cases_generator/generators_common.py b/Tools/cases_generator/generators_common.py +index d17617cab02..cd52f181b60 100644 +--- a/Tools/cases_generator/generators_common.py ++++ b/Tools/cases_generator/generators_common.py +@@ -1,5 +1,4 @@ + from pathlib import Path +-from typing import TextIO + + from analyzer import ( + Instruction, +@@ -7,6 +6,8 @@ + Properties, + StackItem, + analysis_error, ++ Label, ++ CodeSection, + ) + from cwriter import CWriter + from typing import Callable, TextIO, Iterator, Iterable +@@ -90,7 +91,7 @@ + + + ReplacementFunctionType = Callable[ +- [Token, TokenIterator, Uop, Storage, Instruction | None], bool ++ [Token, TokenIterator, CodeSection, Storage, Instruction | None], bool + ] + + def always_true(tkn: Token | None) -> bool: +@@ -98,12 +99,18 @@ + return False + return tkn.text in {"true", "1"} + ++NON_ESCAPING_DEALLOCS = { ++ "_PyFloat_ExactDealloc", ++ "_PyLong_ExactDealloc", ++ "_PyUnicode_ExactDealloc", ++} + + class Emitter: + out: CWriter ++ labels: dict[str, Label] + _replacers: dict[str, ReplacementFunctionType] + +- def __init__(self, out: CWriter): ++ def __init__(self, out: CWriter, labels: dict[str, Label]): + self._replacers = { + "EXIT_IF": self.exit_if, + "DEOPT_IF": self.deopt_if, +@@ -115,23 +122,26 @@ + "SYNC_SP": self.sync_sp, + "SAVE_STACK": self.save_stack, + "RELOAD_STACK": self.reload_stack, +- "PyStackRef_CLOSE": self.stackref_close, +- "PyStackRef_CLOSE_SPECIALIZED": self.stackref_close, ++ "PyStackRef_CLOSE_SPECIALIZED": self.stackref_close_specialized, + "PyStackRef_AsPyObjectSteal": self.stackref_steal, + "DISPATCH": self.dispatch, + "INSTRUCTION_SIZE": self.instruction_size, +- "POP_DEAD_INPUTS": self.pop_dead_inputs, ++ "POP_INPUT": self.pop_input, ++ "stack_pointer": self.stack_pointer, + } + self.out = out ++ self.labels = labels + + def dispatch( + self, + tkn: Token, + tkn_iter: TokenIterator, +- uop: Uop, ++ uop: CodeSection, + storage: Storage, + inst: Instruction | None, + ) -> bool: ++ if storage.spilled: ++ raise analysis_error("stack_pointer needs reloading before dispatch", tkn) + self.emit(tkn) + return False + +@@ -139,31 +149,41 @@ + self, + tkn: Token, + tkn_iter: TokenIterator, +- uop: Uop, ++ uop: CodeSection, + storage: Storage, + inst: Instruction | None, + ) -> bool: +- self.out.emit_at("DEOPT_IF", tkn) ++ self.out.start_line() ++ self.out.emit("if (") + lparen = next(tkn_iter) +- self.emit(lparen) + assert lparen.kind == "LPAREN" + first_tkn = tkn_iter.peek() + emit_to(self.out, tkn_iter, "RPAREN") ++ self.emit(") {\n") + next(tkn_iter) # Semi colon +- self.out.emit(", ") + assert inst is not None + assert inst.family is not None +- self.out.emit(inst.family.name) +- self.out.emit(");\n") ++ family_name = inst.family.name ++ self.emit(f"UPDATE_MISS_STATS({family_name});\n") ++ self.emit(f"assert(_PyOpcode_Deopt[opcode] == ({family_name}));\n") ++ self.emit(f"JUMP_TO_PREDICTED({family_name});\n") ++ self.emit("}\n") + return not always_true(first_tkn) + + exit_if = deopt_if + ++ def goto_error(self, offset: int, label: str, storage: Storage) -> str: ++ if offset > 0: ++ return f"JUMP_TO_LABEL(pop_{offset}_{label});" ++ if offset < 0: ++ storage.copy().flush(self.out) ++ return f"JUMP_TO_LABEL({label});" ++ + def error_if( + self, + tkn: Token, + tkn_iter: TokenIterator, +- uop: Uop, ++ uop: CodeSection, + storage: Storage, + inst: Instruction | None, + ) -> bool: +@@ -181,30 +201,20 @@ + self.out.emit_at("if ", tkn) + self.emit(lparen) + emit_to(self.out, tkn_iter, "COMMA") +- self.out.emit(") ") ++ self.out.emit(") {\n") + label = next(tkn_iter).text + next(tkn_iter) # RPAREN + next(tkn_iter) # Semi colon + storage.clear_inputs("at ERROR_IF") ++ + c_offset = storage.stack.peek_offset() + try: + offset = -int(c_offset) + except ValueError: + offset = -1 +- if offset > 0: +- self.out.emit(f"goto pop_{offset}_") +- self.out.emit(label) +- self.out.emit(";\n") +- elif offset == 0: +- self.out.emit("goto ") +- self.out.emit(label) +- self.out.emit(";\n") +- else: +- self.out.emit("{\n") +- storage.copy().flush(self.out) +- self.out.emit("goto ") +- self.out.emit(label) +- self.out.emit(";\n") ++ self.out.emit(self.goto_error(offset, label, storage)) ++ self.out.emit("\n") ++ if not unconditional: + self.out.emit("}\n") + return not unconditional + +@@ -212,21 +222,21 @@ + self, + tkn: Token, + tkn_iter: TokenIterator, +- uop: Uop, ++ uop: CodeSection, + storage: Storage, + inst: Instruction | None, + ) -> bool: + next(tkn_iter) # LPAREN + next(tkn_iter) # RPAREN + next(tkn_iter) # Semi colon +- self.out.emit_at("goto error;", tkn) ++ self.out.emit_at(self.goto_error(0, "error", storage), tkn) + return False + + def decref_inputs( + self, + tkn: Token, + tkn_iter: TokenIterator, +- uop: Uop, ++ uop: CodeSection, + storage: Storage, + inst: Instruction | None, + ) -> bool: +@@ -234,23 +244,26 @@ + next(tkn_iter) + next(tkn_iter) + self.out.emit_at("", tkn) +- for var in uop.stack.inputs: +- if var.name == "unused" or var.name == "null" or var.peek: ++ for var in storage.inputs: ++ if not var.defined: + continue ++ if var.name == "null": ++ continue ++ close = "PyStackRef_CLOSE" ++ if "null" in var.name or var.condition and var.condition != "1": ++ close = "PyStackRef_XCLOSE" + if var.size: + if var.size == "1": +- self.out.emit(f"PyStackRef_CLOSE({var.name}[0]);\n") ++ self.out.emit(f"{close}({var.name}[0]);\n") + else: + self.out.emit(f"for (int _i = {var.size}; --_i >= 0;) {{\n") +- self.out.emit(f"PyStackRef_CLOSE({var.name}[_i]);\n") ++ self.out.emit(f"{close}({var.name}[_i]);\n") + self.out.emit("}\n") + elif var.condition: +- if var.condition == "1": +- self.out.emit(f"PyStackRef_CLOSE({var.name});\n") +- elif var.condition != "0": +- self.out.emit(f"PyStackRef_XCLOSE({var.name});\n") ++ if var.condition != "0": ++ self.out.emit(f"{close}({var.name});\n") + else: +- self.out.emit(f"PyStackRef_CLOSE({var.name});\n") ++ self.out.emit(f"{close}({var.name});\n") + for input in storage.inputs: + input.defined = False + return True +@@ -259,7 +272,7 @@ + self, + tkn: Token, + tkn_iter: TokenIterator, +- uop: Uop, ++ uop: CodeSection, + storage: Storage, + inst: Instruction | None, + ) -> bool: +@@ -274,7 +287,7 @@ + self, + tkn: Token, + tkn_iter: TokenIterator, +- uop: Uop, ++ uop: CodeSection, + storage: Storage, + inst: Instruction | None, + ) -> bool: +@@ -291,35 +304,80 @@ + raise analysis_error(f"'{name}' is not a live input-only variable", name_tkn) + return True + +- def stackref_close( ++ def stackref_kill( ++ self, ++ name: Token, ++ storage: Storage, ++ escapes: bool ++ ) -> bool: ++ live = "" ++ for var in reversed(storage.inputs): ++ if var.name == name.text: ++ if live and escapes: ++ raise analysis_error( ++ f"Cannot close '{name.text}' when " ++ f"'{live}' is still live", name) ++ var.defined = False ++ break ++ if var.defined: ++ live = var.name ++ return True ++ ++ def stackref_close_specialized( + self, + tkn: Token, + tkn_iter: TokenIterator, +- uop: Uop, ++ uop: CodeSection, + storage: Storage, + inst: Instruction | None, + ) -> bool: ++ + self.out.emit(tkn) + tkn = next(tkn_iter) + assert tkn.kind == "LPAREN" + self.out.emit(tkn) + name = next(tkn_iter) + self.out.emit(name) ++ comma = next(tkn_iter) ++ if comma.kind != "COMMA": ++ raise analysis_error("Expected comma", comma) ++ self.out.emit(comma) ++ dealloc = next(tkn_iter) ++ if dealloc.kind != "IDENTIFIER": ++ raise analysis_error("Expected identifier", dealloc) ++ self.out.emit(dealloc) + if name.kind == "IDENTIFIER": +- for var in storage.inputs: +- if var.name == name.text: +- var.defined = False ++ escapes = dealloc.text not in NON_ESCAPING_DEALLOCS ++ return self.stackref_kill(name, storage, escapes) + rparen = emit_to(self.out, tkn_iter, "RPAREN") + self.emit(rparen) + return True + +- stackref_steal = stackref_close ++ def stackref_steal( ++ self, ++ tkn: Token, ++ tkn_iter: TokenIterator, ++ uop: CodeSection, ++ storage: Storage, ++ inst: Instruction | None, ++ ) -> bool: ++ self.out.emit(tkn) ++ tkn = next(tkn_iter) ++ assert tkn.kind == "LPAREN" ++ self.out.emit(tkn) ++ name = next(tkn_iter) ++ self.out.emit(name) ++ if name.kind == "IDENTIFIER": ++ return self.stackref_kill(name, storage, False) ++ rparen = emit_to(self.out, tkn_iter, "RPAREN") ++ self.emit(rparen) ++ return True + + def sync_sp( + self, + tkn: Token, + tkn_iter: TokenIterator, +- uop: Uop, ++ uop: CodeSection, + storage: Storage, + inst: Instruction | None, + ) -> bool: +@@ -331,6 +389,34 @@ + self._print_storage(storage) + return True + ++ def stack_pointer( ++ self, ++ tkn: Token, ++ tkn_iter: TokenIterator, ++ uop: CodeSection, ++ storage: Storage, ++ inst: Instruction | None, ++ ) -> bool: ++ if storage.spilled: ++ raise analysis_error("stack_pointer is invalid when stack is spilled to memory", tkn) ++ self.emit(tkn) ++ return True ++ ++ def goto_label(self, goto: Token, label: Token, storage: Storage) -> None: ++ if label.text not in self.labels: ++ print(self.labels.keys()) ++ raise analysis_error(f"Label '{label.text}' does not exist", label) ++ label_node = self.labels[label.text] ++ if label_node.spilled: ++ if not storage.spilled: ++ self.emit_save(storage) ++ elif storage.spilled: ++ raise analysis_error("Cannot jump from spilled label without reloading the stack pointer", goto) ++ self.out.start_line() ++ self.out.emit("JUMP_TO_LABEL(") ++ self.out.emit(label) ++ self.out.emit(")") ++ + def emit_save(self, storage: Storage) -> None: + storage.save(self.out) + self._print_storage(storage) +@@ -339,7 +425,7 @@ + self, + tkn: Token, + tkn_iter: TokenIterator, +- uop: Uop, ++ uop: CodeSection, + storage: Storage, + inst: Instruction | None, + ) -> bool: +@@ -349,18 +435,27 @@ + self.emit_save(storage) + return True + +- def pop_dead_inputs( ++ def pop_input( + self, + tkn: Token, + tkn_iter: TokenIterator, +- uop: Uop, ++ uop: CodeSection, + storage: Storage, + inst: Instruction | None, + ) -> bool: + next(tkn_iter) ++ name_tkn = next(tkn_iter) ++ name = name_tkn.text + next(tkn_iter) + next(tkn_iter) +- storage.pop_dead_inputs(self.out) ++ if not storage.inputs: ++ raise analysis_error("stack is empty", tkn) ++ tos = storage.inputs[-1] ++ if tos.name != name: ++ raise analysis_error(f"'{name} is not top of stack", name_tkn) ++ tos.defined = False ++ storage.clear_dead_inputs() ++ storage.flush(self.out) + return True + + def emit_reload(self, storage: Storage) -> None: +@@ -371,7 +466,7 @@ + self, + tkn: Token, + tkn_iter: TokenIterator, +- uop: Uop, ++ uop: CodeSection, + storage: Storage, + inst: Instruction | None, + ) -> bool: +@@ -384,7 +479,7 @@ + def instruction_size(self, + tkn: Token, + tkn_iter: TokenIterator, +- uop: Uop, ++ uop: CodeSection, + storage: Storage, + inst: Instruction | None, + ) -> bool: +@@ -403,7 +498,7 @@ + def _emit_if( + self, + tkn_iter: TokenIterator, +- uop: Uop, ++ uop: CodeSection, + storage: Storage, + inst: Instruction | None, + ) -> tuple[bool, Token, Storage]: +@@ -463,7 +558,7 @@ + def _emit_block( + self, + tkn_iter: TokenIterator, +- uop: Uop, ++ uop: CodeSection, + storage: Storage, + inst: Instruction | None, + emit_first_brace: bool +@@ -489,9 +584,15 @@ + self.out.start_line() + line = tkn.line + if tkn in escaping_calls: +- if tkn != reload: ++ escape = escaping_calls[tkn] ++ if escape.kills is not None: ++ if tkn == reload: ++ self.emit_reload(storage) ++ self.stackref_kill(escape.kills, storage, True) ++ self.emit_save(storage) ++ elif tkn != reload: + self.emit_save(storage) +- _, reload = escaping_calls[tkn] ++ reload = escape.end + elif tkn == reload: + self.emit_reload(storage) + if tkn.kind == "LBRACE": +@@ -504,8 +605,9 @@ + return reachable, tkn, storage + self.out.emit(tkn) + elif tkn.kind == "GOTO": +- reachable = False; +- self.out.emit(tkn) ++ label_tkn = next(tkn_iter) ++ self.goto_label(tkn, label_tkn, storage) ++ reachable = False + elif tkn.kind == "IDENTIFIER": + if tkn.text in self._replacers: + if not self._replacers[tkn.text](tkn, tkn_iter, uop, storage, inst): +@@ -533,22 +635,22 @@ + raise analysis_error(ex.args[0], tkn) from None + raise analysis_error("Expecting closing brace. Reached end of file", tkn) + +- + def emit_tokens( + self, +- uop: Uop, ++ code: CodeSection, + storage: Storage, + inst: Instruction | None, + ) -> Storage: +- tkn_iter = TokenIterator(uop.body) ++ tkn_iter = TokenIterator(code.body) + self.out.start_line() +- _, rbrace, storage = self._emit_block(tkn_iter, uop, storage, inst, False) ++ reachable, rbrace, storage = self._emit_block(tkn_iter, code, storage, inst, False) + try: +- self._print_storage(storage) +- storage.push_outputs() +- self._print_storage(storage) ++ if reachable: ++ self._print_storage(storage) ++ storage.push_outputs() ++ self._print_storage(storage) + except StackError as ex: +- raise analysis_error(ex.args[0], rbrace) ++ raise analysis_error(ex.args[0], rbrace) from None + return storage + + def emit(self, txt: str | Token) -> None: +@@ -583,6 +685,8 @@ + flags.append("HAS_ESCAPES_FLAG") + if p.pure: + flags.append("HAS_PURE_FLAG") ++ if p.no_save_ip: ++ flags.append("HAS_NO_SAVE_IP_FLAG") + if p.oparg_and_1: + flags.append("HAS_OPARG_AND_1_FLAG") + if flags: +diff --git a/Tools/cases_generator/lexer.py b/Tools/cases_generator/lexer.py +index 37f96398ff1..6afca750be9 100644 +--- a/Tools/cases_generator/lexer.py ++++ b/Tools/cases_generator/lexer.py +@@ -213,6 +213,11 @@ + # A macro in the DSL + MACRO = "MACRO" + kwds.append(MACRO) ++# A label in the DSL ++LABEL = "LABEL" ++kwds.append(LABEL) ++SPILLED = "SPILLED" ++kwds.append(SPILLED) + keywords = {name.lower(): name for name in kwds} + + ANNOTATION = "ANNOTATION" +@@ -226,6 +231,7 @@ + "replicate", + "tier1", + "tier2", ++ "no_save_ip", + } + + __all__ = [] +diff --git a/Tools/cases_generator/mypy.ini b/Tools/cases_generator/mypy.ini +index 8e5a31851c5..e54349bf54a 100644 +--- a/Tools/cases_generator/mypy.ini ++++ b/Tools/cases_generator/mypy.ini +@@ -8,7 +8,7 @@ + + # ...And be strict: + strict = True +-strict_concatenate = True ++extra_checks = True + enable_error_code = ignore-without-code,redundant-expr,truthy-bool,possibly-undefined + warn_unreachable = True + allow_redefinition = True +diff --git a/Tools/cases_generator/opcode_metadata_generator.py b/Tools/cases_generator/opcode_metadata_generator.py +index 1a9849c0cbb..453db6905d6 100644 +--- a/Tools/cases_generator/opcode_metadata_generator.py ++++ b/Tools/cases_generator/opcode_metadata_generator.py +@@ -53,6 +53,7 @@ + "PASSTHROUGH", + "OPARG_AND_1", + "ERROR_NO_POP", ++ "NO_SAVE_IP", + ] + + +@@ -285,8 +286,8 @@ + table_size = 256 + len(analysis.pseudos) + out.emit("struct opcode_metadata {\n") + out.emit("uint8_t valid_entry;\n") +- out.emit("int8_t instr_format;\n") +- out.emit("int16_t flags;\n") ++ out.emit("uint8_t instr_format;\n") ++ out.emit("uint16_t flags;\n") + out.emit("};\n\n") + out.emit( + f"extern const struct opcode_metadata _PyOpcode_opcode_metadata[{table_size}];\n" +diff --git a/Tools/cases_generator/optimizer_generator.py b/Tools/cases_generator/optimizer_generator.py +index d08b621aed5..6c33debd58e 100644 +--- a/Tools/cases_generator/optimizer_generator.py ++++ b/Tools/cases_generator/optimizer_generator.py +@@ -36,10 +36,10 @@ + + def type_name(var: StackItem) -> str: + if var.is_array(): +- return f"_Py_UopsSymbol **" ++ return f"JitOptSymbol **" + if var.type: + return var.type +- return f"_Py_UopsSymbol *" ++ return f"JitOptSymbol *" + + + def declare_variables(uop: Uop, out: CWriter, skip_inputs: bool) -> None: +@@ -112,6 +112,9 @@ + def emit_reload(self, storage: Storage) -> None: + pass + ++ def goto_label(self, goto: Token, label: Token, storage: Storage) -> None: ++ self.out.emit(goto) ++ self.out.emit(label) + + def write_uop( + override: Uop | None, +@@ -126,7 +129,7 @@ + try: + out.start_line() + if override: +- code_list, storage = Storage.for_uop(stack, prototype, extract_bits=False) ++ code_list, storage = Storage.for_uop(stack, prototype) + for code in code_list: + out.emit(code) + if debug: +@@ -145,17 +148,17 @@ + cast = f"uint{cache.size*16}_t" + out.emit(f"{type}{cache.name} = ({cast})this_instr->operand0;\n") + if override: +- emitter = OptimizerEmitter(out) ++ emitter = OptimizerEmitter(out, {}) + # No reference management of inputs needed. + for var in storage.inputs: # type: ignore[possibly-undefined] + var.defined = False + storage = emitter.emit_tokens(override, storage, None) + out.start_line() +- storage.flush(out, cast_type="_Py_UopsSymbol *", extract_bits=False) ++ storage.flush(out, cast_type="JitOptSymbol *") + else: + emit_default(out, uop, stack) + out.start_line() +- stack.flush(out, cast_type="_Py_UopsSymbol *", extract_bits=False) ++ stack.flush(out, cast_type="JitOptSymbol *") + except StackError as ex: + raise analysis_error(ex.args[0], prototype.body[0]) # from None + +@@ -198,7 +201,7 @@ + declare_variables(override, out, skip_inputs=False) + else: + declare_variables(uop, out, skip_inputs=True) +- stack = Stack() ++ stack = Stack(False) + write_uop(override, uop, out, stack, debug, skip_inputs=(override is None)) + out.start_line() + out.emit("break;\n") +diff --git a/Tools/cases_generator/parser.py b/Tools/cases_generator/parser.py +index db672ad5501..696c5c16432 100644 +--- a/Tools/cases_generator/parser.py ++++ b/Tools/cases_generator/parser.py +@@ -3,6 +3,7 @@ + Macro, + Pseudo, + Family, ++ LabelDef, + Parser, + Context, + CacheEffect, +@@ -12,6 +13,7 @@ + AstNode, + ) + ++CodeDef = InstDef | LabelDef + + def prettify_filename(filename: str) -> str: + # Make filename more user-friendly and less platform-specific, +diff --git a/Tools/cases_generator/parsing.py b/Tools/cases_generator/parsing.py +index de31d9b232f..011f34de288 100644 +--- a/Tools/cases_generator/parsing.py ++++ b/Tools/cases_generator/parsing.py +@@ -150,8 +150,14 @@ + targets: list[str] # opcodes this can be replaced by + as_sequence: bool + ++@dataclass ++class LabelDef(Node): ++ name: str ++ spilled: bool ++ block: Block + +-AstNode = InstDef | Macro | Pseudo | Family ++ ++AstNode = InstDef | Macro | Pseudo | Family | LabelDef + + + class Parser(PLexer): +@@ -165,6 +171,21 @@ + return pseudo + if inst := self.inst_def(): + return inst ++ if label := self.label_def(): ++ return label ++ return None ++ ++ @contextual ++ def label_def(self) -> LabelDef | None: ++ spilled = False ++ if self.expect(lx.SPILLED): ++ spilled = True ++ if self.expect(lx.LABEL): ++ if self.expect(lx.LPAREN): ++ if tkn := self.expect(lx.IDENTIFIER): ++ if self.expect(lx.RPAREN): ++ if block := self.block(): ++ return LabelDef(tkn.text, spilled, block) + return None + + @contextual +@@ -357,9 +378,12 @@ + def uop(self) -> UOp | None: + if tkn := self.expect(lx.IDENTIFIER): + if self.expect(lx.DIVIDE): ++ sign = 1 ++ if negate := self.expect(lx.MINUS): ++ sign = -1 + if num := self.expect(lx.NUMBER): + try: +- size = int(num.text) ++ size = sign * int(num.text) + except ValueError: + raise self.make_syntax_error( + f"Expected integer, got {num.text!r}" +diff --git a/Tools/cases_generator/stack.py b/Tools/cases_generator/stack.py +index 9471fe0e56f..729973f1e32 100644 +--- a/Tools/cases_generator/stack.py ++++ b/Tools/cases_generator/stack.py +@@ -224,13 +224,14 @@ + return "array" if var.is_array() else "scalar" + + class Stack: +- def __init__(self) -> None: ++ def __init__(self, extract_bits: bool=True) -> None: + self.top_offset = StackOffset.empty() + self.base_offset = StackOffset.empty() + self.variables: list[Local] = [] + self.defined: set[str] = set() ++ self.extract_bits = extract_bits + +- def pop(self, var: StackItem, extract_bits: bool = True) -> tuple[str, Local]: ++ def pop(self, var: StackItem) -> tuple[str, Local]: + self.top_offset.pop(var) + indirect = "&" if var.is_array() else "" + if self.variables: +@@ -272,7 +273,7 @@ + return "", Local.unused(var) + self.defined.add(var.name) + cast = f"({var.type})" if (not indirect and var.type) else "" +- bits = ".bits" if cast and extract_bits else "" ++ bits = ".bits" if cast and self.extract_bits else "" + assign = f"{var.name} = {cast}{indirect}stack_pointer[{self.base_offset.to_c()}]{bits};" + if var.condition: + if var.condition == "1": +@@ -315,7 +316,7 @@ + out.emit("assert(WITHIN_STACK_BOUNDS());\n") + + def flush( +- self, out: CWriter, cast_type: str = "uintptr_t", extract_bits: bool = True ++ self, out: CWriter, cast_type: str = "uintptr_t" + ) -> None: + out.start_line() + var_offset = self.base_offset.copy() +@@ -324,7 +325,7 @@ + var.defined and + not var.in_memory + ): +- Stack._do_emit(out, var.item, var_offset, cast_type, extract_bits) ++ Stack._do_emit(out, var.item, var_offset, cast_type, self.extract_bits) + var.in_memory = True + var_offset.push(var.item) + number = self.top_offset.to_c() +@@ -346,7 +347,7 @@ + ) + + def copy(self) -> "Stack": +- other = Stack() ++ other = Stack(self.extract_bits) + other.top_offset = self.top_offset.copy() + other.base_offset = self.base_offset.copy() + other.variables = [var.copy() for var in self.variables] +@@ -507,14 +508,10 @@ + return True + return False + +- def flush(self, out: CWriter, cast_type: str = "uintptr_t", extract_bits: bool = True) -> None: ++ def flush(self, out: CWriter, cast_type: str = "uintptr_t") -> None: + self.clear_dead_inputs() + self._push_defined_outputs() +- self.stack.flush(out, cast_type, extract_bits) +- +- def pop_dead_inputs(self, out: CWriter, cast_type: str = "uintptr_t", extract_bits: bool = True) -> None: +- self.clear_dead_inputs() +- self.stack.flush(out, cast_type, extract_bits) ++ self.stack.flush(out, cast_type) + + def save(self, out: CWriter) -> None: + assert self.spilled >= 0 +@@ -534,12 +531,12 @@ + out.emit("stack_pointer = _PyFrame_GetStackPointer(frame);\n") + + @staticmethod +- def for_uop(stack: Stack, uop: Uop, extract_bits: bool = True) -> tuple[list[str], "Storage"]: ++ def for_uop(stack: Stack, uop: Uop) -> tuple[list[str], "Storage"]: + code_list: list[str] = [] + inputs: list[Local] = [] + peeks: list[Local] = [] + for input in reversed(uop.stack.inputs): +- code, local = stack.pop(input, extract_bits) ++ code, local = stack.pop(input) + code_list.append(code) + if input.peek: + peeks.append(local) +@@ -573,7 +570,7 @@ + assert [v.name for v in inputs] == [v.name for v in self.inputs], (inputs, self.inputs) + return Storage( + new_stack, inputs, +- self.copy_list(self.outputs), self.copy_list(self.peeks) ++ self.copy_list(self.outputs), self.copy_list(self.peeks), self.spilled + ) + + def sanity_check(self) -> None: +diff --git a/Tools/cases_generator/target_generator.py b/Tools/cases_generator/target_generator.py +index c5097b75847..db028116db9 100644 +--- a/Tools/cases_generator/target_generator.py ++++ b/Tools/cases_generator/target_generator.py +@@ -13,6 +13,7 @@ + DEFAULT_INPUT, + ROOT, + ) ++from tier1_generator import UNKNOWN_OPCODE_HANDLER + from cwriter import CWriter + + +@@ -25,11 +26,49 @@ + for name, op in analysis.opmap.items(): + if op < 256: + targets[op] = f"&&TARGET_{name},\n" ++ out.emit("#ifndef Py_TAIL_CALL_INTERP\n") + out.emit("static void *opcode_targets[256] = {\n") + for target in targets: + out.emit(target) + out.emit("};\n") ++ out.emit("#else /* Py_TAIL_CALL_INTERP */\n") + ++def function_proto(name: str) -> str: ++ return f"Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_{name}(TAIL_CALL_PARAMS)" ++ ++ ++def write_tailcall_dispatch_table(analysis: Analysis, out: CWriter) -> None: ++ out.emit("static py_tail_call_funcptr INSTRUCTION_TABLE[256];\n") ++ out.emit("\n") ++ ++ # Emit function prototypes for labels. ++ for name in analysis.labels: ++ out.emit(f"{function_proto(name)};\n") ++ out.emit("\n") ++ ++ # Emit function prototypes for opcode handlers. ++ for name in sorted(analysis.instructions.keys()): ++ out.emit(f"{function_proto(name)};\n") ++ out.emit("\n") ++ ++ # Emit unknown opcode handler. ++ out.emit(function_proto("UNKNOWN_OPCODE")) ++ out.emit(" {\n") ++ out.emit("int opcode = next_instr->op.code;\n") ++ out.emit(UNKNOWN_OPCODE_HANDLER) ++ out.emit("}\n") ++ out.emit("\n") ++ ++ # Emit the dispatch table. ++ out.emit("static py_tail_call_funcptr INSTRUCTION_TABLE[256] = {\n") ++ for name in sorted(analysis.instructions.keys()): ++ out.emit(f"[{name}] = _TAIL_CALL_{name},\n") ++ named_values = analysis.opmap.values() ++ for rest in range(256): ++ if rest not in named_values: ++ out.emit(f"[{rest}] = _TAIL_CALL_UNKNOWN_OPCODE,\n") ++ out.emit("};\n") ++ outfile.write("#endif /* Py_TAIL_CALL_INTERP */\n") + + arg_parser = argparse.ArgumentParser( + description="Generate the file with dispatch targets.", +@@ -52,3 +91,4 @@ + with open(args.output, "w") as outfile: + out = CWriter(outfile, 0, False) + write_opcode_targets(data, out) ++ write_tailcall_dispatch_table(data, out) +diff --git a/Tools/cases_generator/tier1_generator.py b/Tools/cases_generator/tier1_generator.py +index fcdd3bdacd0..02012fb4172 100644 +--- a/Tools/cases_generator/tier1_generator.py ++++ b/Tools/cases_generator/tier1_generator.py +@@ -24,14 +24,17 @@ + Emitter, + ) + from cwriter import CWriter +-from typing import TextIO ++from typing import TextIO, Callable + from stack import Local, Stack, StackError, get_stack_effect, Storage + +- + DEFAULT_OUTPUT = ROOT / "Python/generated_cases.c.h" + + + FOOTER = "#undef TIER_ONE\n" ++INSTRUCTION_START_MARKER = "/* BEGIN INSTRUCTIONS */" ++INSTRUCTION_END_MARKER = "/* END INSTRUCTIONS */" ++LABEL_START_MARKER = "/* BEGIN LABELS */" ++LABEL_END_MARKER = "/* END LABELS */" + + + def declare_variable(var: StackItem, out: CWriter) -> None: +@@ -125,43 +128,131 @@ + for cache in uop.caches: + if cache.name != "unused": + return True ++ # Can't be merged into the loop above, because ++ # this must strictly be performed at the end. ++ for uop in inst.parts: ++ if not isinstance(uop, Uop): ++ continue ++ for tkn in uop.body: ++ if (tkn.kind == "IDENTIFIER" ++ and (tkn.text in {"DEOPT_IF", "EXIT_IF"})): ++ return True + return False + + ++UNKNOWN_OPCODE_HANDLER ="""\ ++_PyErr_Format(tstate, PyExc_SystemError, ++ "%U:%d: unknown opcode %d", ++ _PyFrame_GetCode(frame)->co_filename, ++ PyUnstable_InterpreterFrame_GetLine(frame), ++ opcode); ++JUMP_TO_LABEL(error); ++""" ++ + def generate_tier1( + filenames: list[str], analysis: Analysis, outfile: TextIO, lines: bool + ) -> None: + write_header(__file__, filenames, outfile) +- outfile.write( +- """ ++ outfile.write(""" + #ifdef TIER_TWO + #error "This file is for Tier 1 only" + #endif + #define TIER_ONE 1 ++""") ++ outfile.write(f""" ++#ifndef Py_TAIL_CALL_INTERP ++#if !USE_COMPUTED_GOTOS ++ dispatch_opcode: ++ switch (opcode) ++#endif ++ {{ ++#endif /* Py_TAIL_CALL_INTERP */ ++ {INSTRUCTION_START_MARKER} + """ + ) ++ generate_tier1_cases(analysis, outfile, lines) ++ outfile.write(f""" ++ {INSTRUCTION_END_MARKER} ++#ifndef Py_TAIL_CALL_INTERP ++#if USE_COMPUTED_GOTOS ++ _unknown_opcode: ++#else ++ EXTRA_CASES // From pycore_opcode_metadata.h, a 'case' for each unused opcode ++#endif ++ /* Tell C compilers not to hold the opcode variable in the loop. ++ next_instr points the current instruction without TARGET(). */ ++ opcode = next_instr->op.code; ++ {UNKNOWN_OPCODE_HANDLER} ++ ++ }} ++ ++ /* This should never be reached. Every opcode should end with DISPATCH() ++ or goto error. */ ++ Py_UNREACHABLE(); ++#endif /* Py_TAIL_CALL_INTERP */ ++ {LABEL_START_MARKER} ++""") + out = CWriter(outfile, 2, lines) +- emitter = Emitter(out) ++ emitter = Emitter(out, analysis.labels) ++ generate_tier1_labels(analysis, emitter) ++ outfile.write(f"{LABEL_END_MARKER}\n") ++ outfile.write(FOOTER) ++ ++ ++ ++def generate_tier1_labels( ++ analysis: Analysis, emitter: Emitter ++) -> None: ++ emitter.emit("\n") ++ # Emit tail-callable labels as function defintions ++ for name, label in analysis.labels.items(): ++ emitter.emit(f"LABEL({name})\n") ++ emitter.emit("{\n") ++ storage = Storage(Stack(), [], [], []) ++ if label.spilled: ++ storage.spilled = 1 ++ emitter.emit("/* STACK SPILLED */\n") ++ emitter.emit_tokens(label, storage, None) ++ emitter.emit("\n") ++ emitter.emit("}\n") ++ emitter.emit("\n") ++ ++ ++def generate_tier1_cases( ++ analysis: Analysis, outfile: TextIO, lines: bool ++) -> None: ++ out = CWriter(outfile, 2, lines) ++ emitter = Emitter(out, analysis.labels) + out.emit("\n") + for name, inst in sorted(analysis.instructions.items()): +- needs_this = uses_this(inst) + out.emit("\n") + out.emit(f"TARGET({name}) {{\n") +- unused_guard = "(void)this_instr;\n" if inst.family is None else "" ++ # We need to ifdef it because this breaks platforms ++ # without computed gotos/tail calling. ++ out.emit(f"#if defined(Py_TAIL_CALL_INTERP)\n") ++ out.emit(f"int opcode = {name};\n") ++ out.emit(f"(void)(opcode);\n") ++ out.emit(f"#endif\n") ++ needs_this = uses_this(inst) ++ unused_guard = "(void)this_instr;\n" + if inst.properties.needs_prev: + out.emit(f"_Py_CODEUNIT* const prev_instr = frame->instr_ptr;\n") ++ + if needs_this and not inst.is_target: +- out.emit(f"_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;\n") ++ out.emit(f"_Py_CODEUNIT* const this_instr = next_instr;\n") + out.emit(unused_guard) +- else: ++ if not inst.properties.no_save_ip: + out.emit(f"frame->instr_ptr = next_instr;\n") ++ + out.emit(f"next_instr += {inst.size};\n") + out.emit(f"INSTRUCTION_STATS({name});\n") + if inst.is_target: +- out.emit(f"PREDICTED({name});\n") ++ out.emit(f"PREDICTED_{name}:;\n") + if needs_this: + out.emit(f"_Py_CODEUNIT* const this_instr = next_instr - {inst.size};\n") + out.emit(unused_guard) ++ if inst.properties.uses_opcode: ++ out.emit(f"opcode = {name};\n") + if inst.family is not None: + out.emit( + f"static_assert({inst.family.size} == {inst.size-1}" +@@ -182,7 +273,6 @@ + out.start_line() + out.emit("}") + out.emit("\n") +- outfile.write(FOOTER) + + + arg_parser = argparse.ArgumentParser( +diff --git a/Tools/cases_generator/tier2_generator.py b/Tools/cases_generator/tier2_generator.py +index dd16a1a7eb2..5e23360cdc0 100644 +--- a/Tools/cases_generator/tier2_generator.py ++++ b/Tools/cases_generator/tier2_generator.py +@@ -9,6 +9,8 @@ + Analysis, + Instruction, + Uop, ++ Label, ++ CodeSection, + analyze_files, + StackItem, + analysis_error, +@@ -65,51 +67,21 @@ + + class Tier2Emitter(Emitter): + +- def __init__(self, out: CWriter): +- super().__init__(out) ++ def __init__(self, out: CWriter, labels: dict[str, Label]): ++ super().__init__(out, labels) + self._replacers["oparg"] = self.oparg + +- def error_if( +- self, +- tkn: Token, +- tkn_iter: TokenIterator, +- uop: Uop, +- storage: Storage, +- inst: Instruction | None, +- ) -> bool: +- self.out.emit_at("if ", tkn) +- lparen = next(tkn_iter) +- self.emit(lparen) +- assert lparen.kind == "LPAREN" +- first_tkn = next(tkn_iter) +- self.out.emit(first_tkn) +- emit_to(self.out, tkn_iter, "COMMA") +- label = next(tkn_iter).text +- next(tkn_iter) # RPAREN +- next(tkn_iter) # Semi colon +- self.emit(") JUMP_TO_ERROR();\n") +- return not always_true(first_tkn) +- +- +- def error_no_pop( +- self, +- tkn: Token, +- tkn_iter: TokenIterator, +- uop: Uop, +- storage: Storage, +- inst: Instruction | None, +- ) -> bool: +- next(tkn_iter) # LPAREN +- next(tkn_iter) # RPAREN +- next(tkn_iter) # Semi colon +- self.out.emit_at("JUMP_TO_ERROR();", tkn) +- return False ++ def goto_error(self, offset: int, label: str, storage: Storage) -> str: ++ # To do: Add jump targets for popping values. ++ if offset != 0: ++ storage.copy().flush(self.out) ++ return f"JUMP_TO_ERROR();" + + def deopt_if( + self, + tkn: Token, + tkn_iter: TokenIterator, +- uop: Uop, ++ uop: CodeSection, + storage: Storage, + inst: Instruction | None, + ) -> bool: +@@ -130,7 +102,7 @@ + self, + tkn: Token, + tkn_iter: TokenIterator, +- uop: Uop, ++ uop: CodeSection, + storage: Storage, + inst: Instruction | None, + ) -> bool: +@@ -150,7 +122,7 @@ + self, + tkn: Token, + tkn_iter: TokenIterator, +- uop: Uop, ++ uop: CodeSection, + storage: Storage, + inst: Instruction | None, + ) -> bool: +@@ -210,7 +182,7 @@ + """ + ) + out = CWriter(outfile, 2, lines) +- emitter = Tier2Emitter(out) ++ emitter = Tier2Emitter(out, analysis.labels) + out.emit("\n") + for name, uop in analysis.uops.items(): + if uop.properties.tier == 1: +diff --git a/Tools/clinic/libclinic/converters.py b/Tools/clinic/libclinic/converters.py +index a65f73ba02f..2998eb51964 100644 +--- a/Tools/clinic/libclinic/converters.py ++++ b/Tools/clinic/libclinic/converters.py +@@ -1182,10 +1182,8 @@ + @property + def parser_type(self) -> str: + assert self.type is not None +- if self.function.kind in {METHOD_INIT, METHOD_NEW, STATIC_METHOD, CLASS_METHOD}: +- tp, _ = correct_name_for_self(self.function) +- return tp +- return self.type ++ tp, _ = correct_name_for_self(self.function) ++ return tp + + def render(self, parameter: Parameter, data: CRenderData) -> None: + """ +diff --git a/Tools/clinic/libclinic/cpp.py b/Tools/clinic/libclinic/cpp.py +index e115d65a88e..3cfe99b7126 100644 +--- a/Tools/clinic/libclinic/cpp.py ++++ b/Tools/clinic/libclinic/cpp.py +@@ -132,6 +132,9 @@ + if line_comment: + line = before.rstrip() + ++ if self.in_comment: ++ return ++ + if not line.startswith('#'): + return + +diff --git a/Tools/clinic/libclinic/parse_args.py b/Tools/clinic/libclinic/parse_args.py +index a57d729bec5..ff4731e99b9 100644 +--- a/Tools/clinic/libclinic/parse_args.py ++++ b/Tools/clinic/libclinic/parse_args.py +@@ -146,6 +146,9 @@ + GETSET_DOCSTRING_PROTOTYPE_STRVAR: Final[str] = libclinic.normalize_snippet(""" + PyDoc_STRVAR({getset_basename}__doc__, + {docstring}); ++ #if defined({getset_basename}_DOCSTR) ++ # undef {getset_basename}_DOCSTR ++ #endif + #define {getset_basename}_DOCSTR {getset_basename}__doc__ + """) + IMPL_DEFINITION_PROTOTYPE: Final[str] = libclinic.normalize_snippet(""" +diff --git a/Tools/clinic/mypy.ini b/Tools/clinic/mypy.ini +index b1fdad673c6..6520e05db0b 100644 +--- a/Tools/clinic/mypy.ini ++++ b/Tools/clinic/mypy.ini +@@ -7,6 +7,6 @@ + + # and be strict! + strict = True +-strict_concatenate = True ++extra_checks = True + enable_error_code = ignore-without-code,redundant-expr,truthy-bool + warn_unreachable = True +diff --git a/Tools/ftscalingbench/ftscalingbench.py b/Tools/ftscalingbench/ftscalingbench.py +index 767aeae9349..364c465bc91 100644 +--- a/Tools/ftscalingbench/ftscalingbench.py ++++ b/Tools/ftscalingbench/ftscalingbench.py +@@ -54,8 +54,16 @@ + + @register_benchmark + def cmodule_function(): +- for i in range(1000 * WORK_SCALE): +- math.floor(i * i) ++ N = 1000 * WORK_SCALE ++ for i in range(N): ++ math.cos(i / N) ++ ++@register_benchmark ++def object_lookup_special(): ++ # round() uses `_PyObject_LookupSpecial()` internally. ++ N = 1000 * WORK_SCALE ++ for i in range(N): ++ round(i / N) + + @register_benchmark + def mult_constant(): +@@ -206,7 +214,7 @@ + color = "\x1b[33m" # yellow + reset_color = "\x1b[0m" + +- print(f"{color}{func.__name__:<18} {round(factor, 1):>4}x {direction}{reset_color}") ++ print(f"{color}{func.__name__:<25} {round(factor, 1):>4}x {direction}{reset_color}") + + def determine_num_threads_and_affinity(): + if sys.platform != "linux": +diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py +index 698ecbd3b54..27aa6b0cc26 100755 +--- a/Tools/gdb/libpython.py ++++ b/Tools/gdb/libpython.py +@@ -99,7 +99,7 @@ + Py_TPFLAGS_TYPE_SUBCLASS = (1 << 31) + + #From pycore_frame.h +-FRAME_OWNED_BY_CSTACK = 3 ++FRAME_OWNED_BY_INTERPRETER = 3 + + MAX_OUTPUT_LEN=1024 + +@@ -890,7 +890,7 @@ + + def proxyval(self, visited): + ''' +- Python's Include/longinterpr.h has this declaration: ++ Python's Include/cpython/longinterpr.h has this declaration: + + typedef struct _PyLongValue { + uintptr_t lv_tag; /* Number of digits, sign and flags */ +@@ -909,8 +909,7 @@ + - 0: Positive + - 1: Zero + - 2: Negative +- The third lowest bit of lv_tag is reserved for an immortality flag, but is +- not currently used. ++ The third lowest bit of lv_tag is set to 1 for the small ints and 0 otherwise. + + where SHIFT can be either: + #define PyLong_SHIFT 30 +@@ -1113,7 +1112,7 @@ + return int(instr_ptr - first_instr) + + def is_shim(self): +- return self._f_special("owner", int) == FRAME_OWNED_BY_CSTACK ++ return self._f_special("owner", int) == FRAME_OWNED_BY_INTERPRETER + + def previous(self): + return self._f_special("previous", PyFramePtr) +diff --git a/Tools/i18n/pygettext.py b/Tools/i18n/pygettext.py +index f78ff16bff9..4720aecbdc5 100755 +--- a/Tools/i18n/pygettext.py ++++ b/Tools/i18n/pygettext.py +@@ -1,41 +1,15 @@ + #! /usr/bin/env python3 +-# -*- coding: iso-8859-1 -*- +-# Originally written by Barry Warsaw +-# +-# Minimally patched to make it even more xgettext compatible +-# by Peter Funk +-# +-# 2002-11-22 Jürgen Hermann +-# Added checks that _() only contains string literals, and +-# command line args are resolved to module lists, i.e. you +-# can now pass a filename, a module or package name, or a +-# directory (including globbing chars, important for Win32). +-# Made docstring fit in 80 chars wide displays using pydoc. +-# + +-# for selftesting +-try: +- import fintl +- _ = fintl.gettext +-except ImportError: +- _ = lambda s: s +- +-__doc__ = _("""pygettext -- Python equivalent of xgettext(1) ++"""pygettext -- Python equivalent of xgettext(1) + + Many systems (Solaris, Linux, Gnu) provide extensive tools that ease the + internationalization of C programs. Most of these tools are independent of + the programming language and can be used from within Python programs. + Martin von Loewis' work[1] helps considerably in this regard. + +-There's one problem though; xgettext is the program that scans source code +-looking for message strings, but it groks only C (or C++). Python +-introduces a few wrinkles, such as dual quoting characters, triple quoted +-strings, and raw strings. xgettext understands none of this. +- +-Enter pygettext, which uses Python's standard tokenize module to scan +-Python source code, generating .pot files identical to what GNU xgettext[2] +-generates for C and C++ code. From there, the standard GNU tools can be +-used. ++pygettext uses Python's standard tokenize module to scan Python source ++code, generating .pot files identical to what GNU xgettext[2] generates ++for C and C++ code. From there, the standard GNU tools can be used. + + A word about marking Python strings as candidates for translation. GNU + xgettext recognizes the following keywords: gettext, dgettext, dcgettext, +@@ -61,6 +35,9 @@ + option arguments is broken, and in these cases, pygettext just defines + additional switches. + ++NOTE: The public interface of pygettext is limited to the command-line ++interface only. The internal API is subject to change without notice. ++ + Usage: pygettext [options] inputfile ... + + Options: +@@ -153,18 +130,16 @@ + conjunction with the -D option above. + + If `inputfile' is -, standard input is read. +-""") ++""" + +-import os ++import ast ++import getopt ++import glob + import importlib.machinery + import importlib.util ++import os + import sys +-import glob + import time +-import getopt +-import ast +-import tokenize +-from collections import defaultdict + from dataclasses import dataclass, field + from operator import itemgetter + +@@ -173,7 +148,7 @@ + + # The normal pot-file header. msgmerge and Emacs's po-mode work better if it's + # there. +-pot_header = _('''\ ++pot_header = '''\ + # SOME DESCRIPTIVE TITLE. + # Copyright (C) YEAR ORGANIZATION + # FIRST AUTHOR , YEAR. +@@ -190,7 +165,7 @@ + "Content-Transfer-Encoding: %(encoding)s\\n" + "Generated-By: pygettext.py %(version)s\\n" + +-''') ++''' + + + def usage(code, msg=''): +@@ -204,7 +179,7 @@ + global escapes, escape + if pass_nonascii: + # Allow non-ascii characters to pass through so that e.g. 'msgid +- # "Höhe"' would result not result in 'msgid "H\366he"'. Otherwise we ++ # "Höhe"' would result not result in 'msgid "H\366he"'. Otherwise we + # escape any character outside the 32..126 range. + mod = 128 + escape = escape_ascii +@@ -224,19 +199,11 @@ + def escape_ascii(s, encoding): + return ''.join(escapes[ord(c)] if ord(c) < 128 else c for c in s) + ++ + def escape_nonascii(s, encoding): + return ''.join(escapes[b] for b in s.encode(encoding)) + + +-def is_literal_string(s): +- return s[0] in '\'"' or (s[0] in 'rRuU' and s[1] in '\'"') +- +- +-def safe_eval(s): +- # unwrap quotes, safely +- return eval(s, {'__builtins__':{}}, {}) +- +- + def normalize(s, encoding): + # This converts the various Python string types into a format that is + # appropriate for .po files, namely much closer to C style. +@@ -318,11 +285,6 @@ + } + + +-def matches_spec(message, spec): +- """Check if a message has all the keys defined by the keyword spec.""" +- return all(key in message for key in spec.values()) +- +- + @dataclass(frozen=True) + class Location: + filename: str +@@ -347,273 +309,163 @@ + self.is_docstring |= is_docstring + + +-def key_for(msgid, msgctxt=None): +- if msgctxt is not None: +- return (msgctxt, msgid) +- return msgid ++class GettextVisitor(ast.NodeVisitor): ++ def __init__(self, options): ++ super().__init__() ++ self.options = options ++ self.filename = None ++ self.messages = {} + ++ def visit_file(self, node, filename): ++ self.filename = filename ++ self.visit(node) + +-class TokenEater: +- def __init__(self, options): +- self.__options = options +- self.__messages = {} +- self.__state = self.__waiting +- self.__data = defaultdict(str) +- self.__curr_arg = 0 +- self.__curr_keyword = None +- self.__lineno = -1 +- self.__freshmodule = 1 +- self.__curfile = None +- self.__enclosurecount = 0 +- +- def __call__(self, ttype, tstring, stup, etup, line): +- # dispatch +-## import token +-## print('ttype:', token.tok_name[ttype], 'tstring:', tstring, +-## file=sys.stderr) +- self.__state(ttype, tstring, stup[0]) +- +- def __waiting(self, ttype, tstring, lineno): +- opts = self.__options +- # Do docstring extractions, if enabled +- if opts.docstrings and not opts.nodocstrings.get(self.__curfile): +- # module docstring? +- if self.__freshmodule: +- if ttype == tokenize.STRING and is_literal_string(tstring): +- self.__addentry({'msgid': safe_eval(tstring)}, lineno, is_docstring=True) +- self.__freshmodule = 0 +- return +- if ttype in (tokenize.COMMENT, tokenize.NL, tokenize.ENCODING): +- return +- self.__freshmodule = 0 +- # class or func/method docstring? +- if ttype == tokenize.NAME and tstring in ('class', 'def'): +- self.__state = self.__suiteseen +- return +- if ttype == tokenize.NAME and tstring in ('class', 'def'): +- self.__state = self.__ignorenext ++ def visit_Module(self, node): ++ self._extract_docstring(node) ++ self.generic_visit(node) ++ ++ visit_ClassDef = visit_FunctionDef = visit_AsyncFunctionDef = visit_Module ++ ++ def visit_Call(self, node): ++ self._extract_message(node) ++ self.generic_visit(node) ++ ++ def _extract_docstring(self, node): ++ if (not self.options.docstrings or ++ self.options.nodocstrings.get(self.filename)): + return +- if ttype == tokenize.NAME and tstring in opts.keywords: +- self.__state = self.__keywordseen +- self.__curr_keyword = tstring ++ ++ docstring = ast.get_docstring(node) ++ if docstring is not None: ++ lineno = node.body[0].lineno # The first statement is the docstring ++ self._add_message(lineno, docstring, is_docstring=True) ++ ++ def _extract_message(self, node): ++ func_name = self._get_func_name(node) ++ spec = self.options.keywords.get(func_name) ++ if spec is None: ++ return ++ ++ max_index = max(spec) ++ has_var_positional = any(isinstance(arg, ast.Starred) for ++ arg in node.args[:max_index+1]) ++ if has_var_positional: ++ print(f'*** {self.filename}:{node.lineno}: Variable positional ' ++ f'arguments are not allowed in gettext calls', file=sys.stderr) + return +- if ttype == tokenize.STRING: +- maybe_fstring = ast.parse(tstring, mode='eval').body +- if not isinstance(maybe_fstring, ast.JoinedStr): +- return +- for value in filter(lambda node: isinstance(node, ast.FormattedValue), +- maybe_fstring.values): +- for call in filter(lambda node: isinstance(node, ast.Call), +- ast.walk(value)): +- func = call.func +- if isinstance(func, ast.Name): +- func_name = func.id +- elif isinstance(func, ast.Attribute): +- func_name = func.attr +- else: +- continue +- +- if func_name not in opts.keywords: +- continue +- if len(call.args) != 1: +- print(_( +- '*** %(file)s:%(lineno)s: Seen unexpected amount of' +- ' positional arguments in gettext call: %(source_segment)s' +- ) % { +- 'source_segment': ast.get_source_segment(tstring, call) or tstring, +- 'file': self.__curfile, +- 'lineno': lineno +- }, file=sys.stderr) +- continue +- if call.keywords: +- print(_( +- '*** %(file)s:%(lineno)s: Seen unexpected keyword arguments' +- ' in gettext call: %(source_segment)s' +- ) % { +- 'source_segment': ast.get_source_segment(tstring, call) or tstring, +- 'file': self.__curfile, +- 'lineno': lineno +- }, file=sys.stderr) +- continue +- arg = call.args[0] +- if not isinstance(arg, ast.Constant): +- print(_( +- '*** %(file)s:%(lineno)s: Seen unexpected argument type' +- ' in gettext call: %(source_segment)s' +- ) % { +- 'source_segment': ast.get_source_segment(tstring, call) or tstring, +- 'file': self.__curfile, +- 'lineno': lineno +- }, file=sys.stderr) +- continue +- if isinstance(arg.value, str): +- self.__curr_keyword = func_name +- self.__addentry({'msgid': arg.value}, lineno) +- +- def __suiteseen(self, ttype, tstring, lineno): +- # skip over any enclosure pairs until we see the colon +- if ttype == tokenize.OP: +- if tstring == ':' and self.__enclosurecount == 0: +- # we see a colon and we're not in an enclosure: end of def +- self.__state = self.__suitedocstring +- elif tstring in '([{': +- self.__enclosurecount += 1 +- elif tstring in ')]}': +- self.__enclosurecount -= 1 +- +- def __suitedocstring(self, ttype, tstring, lineno): +- # ignore any intervening noise +- if ttype == tokenize.STRING and is_literal_string(tstring): +- self.__addentry({'msgid': safe_eval(tstring)}, lineno, is_docstring=True) +- self.__state = self.__waiting +- elif ttype not in (tokenize.NEWLINE, tokenize.INDENT, +- tokenize.COMMENT): +- # there was no class docstring +- self.__state = self.__waiting +- +- def __keywordseen(self, ttype, tstring, lineno): +- if ttype == tokenize.OP and tstring == '(': +- self.__data.clear() +- self.__curr_arg = 0 +- self.__enclosurecount = 0 +- self.__lineno = lineno +- self.__state = self.__openseen +- else: +- self.__state = self.__waiting +- +- def __openseen(self, ttype, tstring, lineno): +- spec = self.__options.keywords[self.__curr_keyword] +- arg_type = spec.get(self.__curr_arg) +- expect_string_literal = arg_type is not None +- +- if ttype == tokenize.OP and self.__enclosurecount == 0: +- if tstring == ')': +- # We've seen the last of the translatable strings. Record the +- # line number of the first line of the strings and update the list +- # of messages seen. Reset state for the next batch. If there +- # were no strings inside _(), then just ignore this entry. +- if self.__data: +- self.__addentry(self.__data) +- self.__state = self.__waiting +- return +- elif tstring == ',': +- # Advance to the next argument +- self.__curr_arg += 1 +- return + +- if expect_string_literal: +- if ttype == tokenize.STRING and is_literal_string(tstring): +- self.__data[arg_type] += safe_eval(tstring) +- elif ttype not in (tokenize.COMMENT, tokenize.INDENT, tokenize.DEDENT, +- tokenize.NEWLINE, tokenize.NL): +- # We are inside an argument which is a translatable string and +- # we encountered a token that is not a string. This is an error. +- self.warn_unexpected_token(tstring) +- self.__enclosurecount = 0 +- self.__state = self.__waiting +- elif ttype == tokenize.OP: +- if tstring in '([{': +- self.__enclosurecount += 1 +- elif tstring in ')]}': +- self.__enclosurecount -= 1 +- +- def __ignorenext(self, ttype, tstring, lineno): +- self.__state = self.__waiting +- +- def __addentry(self, msg, lineno=None, *, is_docstring=False): +- msgid = msg.get('msgid') +- if msgid in self.__options.toexclude: ++ if max_index >= len(node.args): ++ print(f'*** {self.filename}:{node.lineno}: Expected at least ' ++ f'{max(spec) + 1} positional argument(s) in gettext call, ' ++ f'got {len(node.args)}', file=sys.stderr) + return +- if not is_docstring: +- spec = self.__options.keywords[self.__curr_keyword] +- if not matches_spec(msg, spec): ++ ++ msg_data = {} ++ for position, arg_type in spec.items(): ++ arg = node.args[position] ++ if not self._is_string_const(arg): ++ print(f'*** {self.filename}:{arg.lineno}: Expected a string ' ++ f'constant for argument {position + 1}, ' ++ f'got {ast.unparse(arg)}', file=sys.stderr) + return +- if lineno is None: +- lineno = self.__lineno +- msgctxt = msg.get('msgctxt') +- msgid_plural = msg.get('msgid_plural') +- key = key_for(msgid, msgctxt) +- if key in self.__messages: +- self.__messages[key].add_location( +- self.__curfile, ++ msg_data[arg_type] = arg.value ++ ++ lineno = node.lineno ++ self._add_message(lineno, **msg_data) ++ ++ def _add_message( ++ self, lineno, msgid, msgid_plural=None, msgctxt=None, *, ++ is_docstring=False): ++ if msgid in self.options.toexclude: ++ return ++ ++ key = self._key_for(msgid, msgctxt) ++ message = self.messages.get(key) ++ if message: ++ message.add_location( ++ self.filename, + lineno, + msgid_plural, + is_docstring=is_docstring, + ) + else: +- self.__messages[key] = Message( ++ self.messages[key] = Message( + msgid=msgid, + msgid_plural=msgid_plural, + msgctxt=msgctxt, +- locations={Location(self.__curfile, lineno)}, ++ locations={Location(self.filename, lineno)}, + is_docstring=is_docstring, + ) + +- def warn_unexpected_token(self, token): +- print(_( +- '*** %(file)s:%(lineno)s: Seen unexpected token "%(token)s"' +- ) % { +- 'token': token, +- 'file': self.__curfile, +- 'lineno': self.__lineno +- }, file=sys.stderr) +- +- def set_filename(self, filename): +- self.__curfile = filename +- self.__freshmodule = 1 +- +- def write(self, fp): +- options = self.__options +- timestamp = time.strftime('%Y-%m-%d %H:%M%z') +- encoding = fp.encoding if fp.encoding else 'UTF-8' +- print(pot_header % {'time': timestamp, 'version': __version__, +- 'charset': encoding, +- 'encoding': '8bit'}, file=fp) +- +- # Sort locations within each message by filename and lineno +- sorted_keys = [ +- (key, sorted(msg.locations)) +- for key, msg in self.__messages.items() +- ] +- # Sort messages by locations +- # For example, a message with locations [('test.py', 1), ('test.py', 2)] will +- # appear before a message with locations [('test.py', 1), ('test.py', 3)] +- sorted_keys.sort(key=itemgetter(1)) +- +- for key, locations in sorted_keys: +- msg = self.__messages[key] +- if options.writelocations: +- # location comments are different b/w Solaris and GNU: +- if options.locationstyle == options.SOLARIS: +- for location in locations: +- print(f'# File: {location.filename}, line: {location.lineno}', file=fp) +- elif options.locationstyle == options.GNU: +- # fit as many locations on one line, as long as the +- # resulting line length doesn't exceed 'options.width' +- locline = '#:' +- for location in locations: +- s = f' {location.filename}:{location.lineno}' +- if len(locline) + len(s) <= options.width: +- locline = locline + s +- else: +- print(locline, file=fp) +- locline = f'#:{s}' +- if len(locline) > 2: ++ @staticmethod ++ def _key_for(msgid, msgctxt=None): ++ if msgctxt is not None: ++ return (msgctxt, msgid) ++ return msgid ++ ++ def _get_func_name(self, node): ++ match node.func: ++ case ast.Name(id=id): ++ return id ++ case ast.Attribute(attr=attr): ++ return attr ++ case _: ++ return None ++ ++ def _is_string_const(self, node): ++ return isinstance(node, ast.Constant) and isinstance(node.value, str) ++ ++def write_pot_file(messages, options, fp): ++ timestamp = time.strftime('%Y-%m-%d %H:%M%z') ++ encoding = fp.encoding if fp.encoding else 'UTF-8' ++ print(pot_header % {'time': timestamp, 'version': __version__, ++ 'charset': encoding, ++ 'encoding': '8bit'}, file=fp) ++ ++ # Sort locations within each message by filename and lineno ++ sorted_keys = [ ++ (key, sorted(msg.locations)) ++ for key, msg in messages.items() ++ ] ++ # Sort messages by locations ++ # For example, a message with locations [('test.py', 1), ('test.py', 2)] will ++ # appear before a message with locations [('test.py', 1), ('test.py', 3)] ++ sorted_keys.sort(key=itemgetter(1)) ++ ++ for key, locations in sorted_keys: ++ msg = messages[key] ++ if options.writelocations: ++ # location comments are different b/w Solaris and GNU: ++ if options.locationstyle == options.SOLARIS: ++ for location in locations: ++ print(f'# File: {location.filename}, line: {location.lineno}', file=fp) ++ elif options.locationstyle == options.GNU: ++ # fit as many locations on one line, as long as the ++ # resulting line length doesn't exceed 'options.width' ++ locline = '#:' ++ for location in locations: ++ s = f' {location.filename}:{location.lineno}' ++ if len(locline) + len(s) <= options.width: ++ locline = locline + s ++ else: + print(locline, file=fp) +- if msg.is_docstring: +- # If the entry was gleaned out of a docstring, then add a +- # comment stating so. This is to aid translators who may wish +- # to skip translating some unimportant docstrings. +- print('#, docstring', file=fp) +- if msg.msgctxt is not None: +- print('msgctxt', normalize(msg.msgctxt, encoding), file=fp) +- print('msgid', normalize(msg.msgid, encoding), file=fp) +- if msg.msgid_plural is not None: +- print('msgid_plural', normalize(msg.msgid_plural, encoding), file=fp) +- print('msgstr[0] ""', file=fp) +- print('msgstr[1] ""\n', file=fp) +- else: +- print('msgstr ""\n', file=fp) ++ locline = f'#:{s}' ++ if len(locline) > 2: ++ print(locline, file=fp) ++ if msg.is_docstring: ++ # If the entry was gleaned out of a docstring, then add a ++ # comment stating so. This is to aid translators who may wish ++ # to skip translating some unimportant docstrings. ++ print('#, docstring', file=fp) ++ if msg.msgctxt is not None: ++ print('msgctxt', normalize(msg.msgctxt, encoding), file=fp) ++ print('msgid', normalize(msg.msgid, encoding), file=fp) ++ if msg.msgid_plural is not None: ++ print('msgid_plural', normalize(msg.msgid_plural, encoding), file=fp) ++ print('msgstr[0] ""', file=fp) ++ print('msgstr[1] ""\n', file=fp) ++ else: ++ print('msgstr ""\n', file=fp) + + + def main(): +@@ -677,7 +529,7 @@ + elif opt in ('-S', '--style'): + options.locationstyle = locations.get(arg.lower()) + if options.locationstyle is None: +- usage(1, _('Invalid value for --style: %s') % arg) ++ usage(1, f'Invalid value for --style: {arg}') + elif opt in ('-o', '--output'): + options.outfile = arg + elif opt in ('-p', '--output-dir'): +@@ -685,13 +537,13 @@ + elif opt in ('-v', '--verbose'): + options.verbose = 1 + elif opt in ('-V', '--version'): +- print(_('pygettext.py (xgettext for Python) %s') % __version__) ++ print(f'pygettext.py (xgettext for Python) {__version__}') + sys.exit(0) + elif opt in ('-w', '--width'): + try: + options.width = int(arg) + except ValueError: +- usage(1, _('--width argument must be an integer: %s') % arg) ++ usage(1, f'--width argument must be an integer: {arg}') + elif opt in ('-x', '--exclude-file'): + options.excludefilename = arg + elif opt in ('-X', '--no-docstrings'): +@@ -719,8 +571,8 @@ + with open(options.excludefilename) as fp: + options.toexclude = fp.readlines() + except IOError: +- print(_( +- "Can't read --exclude-file: %s") % options.excludefilename, file=sys.stderr) ++ print(f"Can't read --exclude-file: {options.excludefilename}", ++ file=sys.stderr) + sys.exit(1) + else: + options.toexclude = [] +@@ -735,31 +587,24 @@ + args = expanded + + # slurp through all the files +- eater = TokenEater(options) ++ visitor = GettextVisitor(options) + for filename in args: + if filename == '-': + if options.verbose: +- print(_('Reading standard input')) +- fp = sys.stdin.buffer +- closep = 0 ++ print('Reading standard input') ++ source = sys.stdin.buffer.read() + else: + if options.verbose: +- print(_('Working on %s') % filename) +- fp = open(filename, 'rb') +- closep = 1 ++ print(f'Working on {filename}') ++ with open(filename, 'rb') as fp: ++ source = fp.read() ++ + try: +- eater.set_filename(filename) +- try: +- tokens = tokenize.tokenize(fp.readline) +- for _token in tokens: +- eater(*_token) +- except tokenize.TokenError as e: +- print('%s: %s, line %d, column %d' % ( +- e.args[0], filename, e.args[1][0], e.args[1][1]), +- file=sys.stderr) +- finally: +- if closep: +- fp.close() ++ module_tree = ast.parse(source) ++ except SyntaxError: ++ continue ++ ++ visitor.visit_file(module_tree, filename) + + # write the output + if options.outfile == '-': +@@ -771,7 +616,7 @@ + fp = open(options.outfile, 'w') + closep = 1 + try: +- eater.write(fp) ++ write_pot_file(visitor.messages, options, fp) + finally: + if closep: + fp.close() +@@ -779,7 +624,3 @@ + + if __name__ == '__main__': + main() +- # some more test strings +- # this one creates a warning +- _('*** Seen unexpected token "%(token)s"') % {'token': 'test'} +- _('more' 'than' 'one' 'string') +diff --git a/Tools/jit/README.md b/Tools/jit/README.md +index 801c64e4059..4107265754f 100644 +--- a/Tools/jit/README.md ++++ b/Tools/jit/README.md +@@ -3,6 +3,8 @@ + + This version of CPython can be built with an experimental just-in-time compiler[^pep-744]. While most everything you already know about building and using CPython is unchanged, you will probably need to install a compatible version of LLVM first. + ++Python 3.11 or newer is required to build the JIT. ++ + ## Installing LLVM + + The JIT compiler does not require end users to install any third-party dependencies, but part of it must be *built* using LLVM[^why-llvm]. You are *not* required to build the rest of CPython using LLVM, or even the same version of LLVM (in fact, this is uncommon). +@@ -54,7 +56,7 @@ + + For all other builds, pass the new `--enable-experimental-jit` option to `configure`. + +-Otherwise, just configure and build as you normally would. Cross-compiling "just works", since the JIT is built for the host platform. ++Otherwise, just configure and build as you normally would. Cross-compiling "just works", since the JIT is built for the host platform. + + The JIT can also be enabled or disabled using the `PYTHON_JIT` environment variable, even on builds where it is enabled or disabled by default. More details about configuring CPython with the JIT and optional values for `--enable-experimental-jit` can be found [here](https://docs.python.org/dev/whatsnew/3.13.html#experimental-jit-compiler). + +diff --git a/Tools/jit/jit.h b/Tools/jit/jit.h +index 47da64cb12b..f767ef68127 100644 +--- a/Tools/jit/jit.h ++++ b/Tools/jit/jit.h +@@ -2,3 +2,7 @@ + // pointer with __attribute__((preserve_none)), since this attribute may not be + // supported by the compiler used to build the rest of the interpreter. + typedef jit_func __attribute__((preserve_none)) jit_func_preserve_none; ++ ++#define PATCH_VALUE(TYPE, NAME, ALIAS) \ ++ PyAPI_DATA(void) ALIAS; \ ++ TYPE NAME = (TYPE)(uintptr_t)&ALIAS; +diff --git a/Tools/jit/shim.c b/Tools/jit/shim.c +index f0cffa2f049..ebd4e9bc858 100644 +--- a/Tools/jit/shim.c ++++ b/Tools/jit/shim.c +@@ -9,16 +9,7 @@ + _Py_CODEUNIT * + _JIT_ENTRY(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate) + { +- // This is subtle. The actual trace will return to us once it exits, so we +- // need to make sure that we stay alive until then. If our trace side-exits +- // into another trace, and this trace is then invalidated, the code for +- // *this function* will be freed and we'll crash upon return: +- PyAPI_DATA(void) _JIT_EXECUTOR; +- PyObject *executor = (PyObject *)(uintptr_t)&_JIT_EXECUTOR; +- Py_INCREF(executor); + // Note that this is *not* a tail call: +- PyAPI_DATA(void) _JIT_CONTINUE; +- _Py_CODEUNIT *target = ((jit_func_preserve_none)&_JIT_CONTINUE)(frame, stack_pointer, tstate); +- Py_SETREF(tstate->previous_executor, executor); +- return target; ++ PATCH_VALUE(jit_func_preserve_none, call, _JIT_CONTINUE); ++ return call(frame, stack_pointer, tstate); + } +diff --git a/Tools/jit/template.c b/Tools/jit/template.c +index 95c90bda70f..0b7d077d78c 100644 +--- a/Tools/jit/template.c ++++ b/Tools/jit/template.c +@@ -32,36 +32,22 @@ + #undef CURRENT_OPERAND1 + #define CURRENT_OPERAND1() (_operand1) + +-#undef DEOPT_IF +-#define DEOPT_IF(COND, INSTNAME) \ +- do { \ +- if ((COND)) { \ +- goto deoptimize; \ +- } \ +- } while (0) +- +-#undef ENABLE_SPECIALIZATION +-#define ENABLE_SPECIALIZATION (0) +- +-#undef GOTO_ERROR +-#define GOTO_ERROR(LABEL) \ +- do { \ +- goto LABEL ## _tier_two; \ +- } while (0) ++#undef CURRENT_TARGET ++#define CURRENT_TARGET() (_target) + + #undef GOTO_TIER_TWO +-#define GOTO_TIER_TWO(EXECUTOR) \ +-do { \ +- OPT_STAT_INC(traces_executed); \ +- __attribute__((musttail)) \ +- return ((jit_func_preserve_none)((EXECUTOR)->jit_side_entry))(frame, stack_pointer, tstate); \ ++#define GOTO_TIER_TWO(EXECUTOR) \ ++do { \ ++ OPT_STAT_INC(traces_executed); \ ++ jit_func_preserve_none jitted = (EXECUTOR)->jit_side_entry; \ ++ __attribute__((musttail)) return jitted(frame, stack_pointer, tstate); \ + } while (0) + + #undef GOTO_TIER_ONE +-#define GOTO_TIER_ONE(TARGET) \ +-do { \ ++#define GOTO_TIER_ONE(TARGET) \ ++do { \ + _PyFrame_SetStackPointer(frame, stack_pointer); \ +- return TARGET; \ ++ return TARGET; \ + } while (0) + + #undef LOAD_IP +@@ -69,15 +55,15 @@ + do { \ + } while (0) + +-#define PATCH_VALUE(TYPE, NAME, ALIAS) \ +- PyAPI_DATA(void) ALIAS; \ +- TYPE NAME = (TYPE)(uintptr_t)&ALIAS; ++#undef LLTRACE_RESUME_FRAME ++#define LLTRACE_RESUME_FRAME() \ ++ do { \ ++ } while (0) + +-#define PATCH_JUMP(ALIAS) \ +-do { \ +- PyAPI_DATA(void) ALIAS; \ +- __attribute__((musttail)) \ +- return ((jit_func_preserve_none)&ALIAS)(frame, stack_pointer, tstate); \ ++#define PATCH_JUMP(ALIAS) \ ++do { \ ++ PATCH_VALUE(jit_func_preserve_none, jump, ALIAS); \ ++ __attribute__((musttail)) return jump(frame, stack_pointer, tstate); \ + } while (0) + + #undef JUMP_TO_JUMP_TARGET +@@ -86,9 +72,6 @@ + #undef JUMP_TO_ERROR + #define JUMP_TO_ERROR() PATCH_JUMP(_JIT_ERROR_TARGET) + +-#undef WITHIN_STACK_BOUNDS +-#define WITHIN_STACK_BOUNDS() 1 +- + #define TIER_TWO 2 + + __attribute__((preserve_none)) _Py_CODEUNIT * +@@ -109,16 +92,13 @@ + PATCH_VALUE(uint32_t, _operand0_hi, _JIT_OPERAND0_HI) + PATCH_VALUE(uint32_t, _operand0_lo, _JIT_OPERAND0_LO) + uint64_t _operand0 = ((uint64_t)_operand0_hi << 32) | _operand0_lo; +- + PATCH_VALUE(uint32_t, _operand1_hi, _JIT_OPERAND1_HI) + PATCH_VALUE(uint32_t, _operand1_lo, _JIT_OPERAND1_LO) + uint64_t _operand1 = ((uint64_t)_operand1_hi << 32) | _operand1_lo; + #endif + PATCH_VALUE(uint32_t, _target, _JIT_TARGET) +- + OPT_STAT_INC(uops_executed); + UOP_STAT_INC(uopcode, execution_count); +- + switch (uopcode) { + // The actual instruction definition gets inserted here: + CASE +@@ -126,15 +106,4 @@ + Py_UNREACHABLE(); + } + PATCH_JUMP(_JIT_CONTINUE); +- // Labels that the instruction implementations expect to exist: +- +-error_tier_two: +- tstate->previous_executor = (PyObject *)current_executor; +- GOTO_TIER_ONE(NULL); +-exit_to_tier1: +- tstate->previous_executor = (PyObject *)current_executor; +- GOTO_TIER_ONE(_PyCode_CODE(_PyFrame_GetCode(frame)) + _target); +-exit_to_tier1_dynamic: +- tstate->previous_executor = (PyObject *)current_executor; +- GOTO_TIER_ONE(frame->instr_ptr); + } +diff --git a/Tools/scripts/summarize_stats.py b/Tools/scripts/summarize_stats.py +index bc7ccfe33e7..4243b53850b 100644 +--- a/Tools/scripts/summarize_stats.py ++++ b/Tools/scripts/summarize_stats.py +@@ -457,6 +457,7 @@ + inner_loop = self._data["Optimization inner loop"] + recursive_call = self._data["Optimization recursive call"] + low_confidence = self._data["Optimization low confidence"] ++ unknown_callee = self._data["Optimization unknown callee"] + executors_invalidated = self._data["Executors invalidated"] + + return { +@@ -497,6 +498,10 @@ + "A trace is abandoned because the likelihood of the jump to top being taken " + "is too low.", + ): (low_confidence, attempts), ++ Doc( ++ "Unknown callee", ++ "A trace is abandoned because the target of a call is unknown.", ++ ): (unknown_callee, attempts), + Doc( + "Executors invalidated", + "The number of executors that were invalidated due to watched " +@@ -545,6 +550,41 @@ + ): (incorrect_keys, attempts), + } + ++ def get_jit_memory_stats(self) -> dict[Doc, tuple[int, int | None]]: ++ jit_total_memory_size = self._data["JIT total memory size"] ++ jit_code_size = self._data["JIT code size"] ++ jit_trampoline_size = self._data["JIT trampoline size"] ++ jit_data_size = self._data["JIT data size"] ++ jit_padding_size = self._data["JIT padding size"] ++ jit_freed_memory_size = self._data["JIT freed memory size"] ++ ++ return { ++ Doc( ++ "Total memory size", ++ "The total size of the memory allocated for the JIT traces", ++ ): (jit_total_memory_size, None), ++ Doc( ++ "Code size", ++ "The size of the memory allocated for the code of the JIT traces", ++ ): (jit_code_size, jit_total_memory_size), ++ Doc( ++ "Trampoline size", ++ "The size of the memory allocated for the trampolines of the JIT traces", ++ ): (jit_trampoline_size, jit_total_memory_size), ++ Doc( ++ "Data size", ++ "The size of the memory allocated for the data of the JIT traces", ++ ): (jit_data_size, jit_total_memory_size), ++ Doc( ++ "Padding size", ++ "The size of the memory allocated for the padding of the JIT traces", ++ ): (jit_padding_size, jit_total_memory_size), ++ Doc( ++ "Freed memory size", ++ "The size of the memory freed from the JIT traces", ++ ): (jit_freed_memory_size, jit_total_memory_size), ++ } ++ + def get_histogram(self, prefix: str) -> list[tuple[int, int]]: + rows = [] + for k, v in self._data.items(): +@@ -1161,16 +1201,31 @@ + for label, (value, den) in optimizer_stats.items() + ] + +- def calc_histogram_table(key: str, den: str) -> RowCalculator: ++ def calc_jit_memory_table(stats: Stats) -> Rows: ++ jit_memory_stats = stats.get_jit_memory_stats() ++ ++ return [ ++ ( ++ label, ++ Count(value), ++ Ratio(value, den, percentage=label != "Total memory size"), ++ ) ++ for label, (value, den) in jit_memory_stats.items() ++ ] ++ ++ def calc_histogram_table(key: str, den: str | None = None) -> RowCalculator: + def calc(stats: Stats) -> Rows: + histogram = stats.get_histogram(key) +- denominator = stats.get(den) ++ ++ if den: ++ denominator = stats.get(den) ++ else: ++ denominator = 0 ++ for _, v in histogram: ++ denominator += v + + rows: Rows = [] +- last_non_zero = 0 + for k, v in histogram: +- if v != 0: +- last_non_zero = len(rows) + rows.append( + ( + f"<= {k:,d}", +@@ -1178,9 +1233,19 @@ + Ratio(v, denominator), + ) + ) +- # Don't include any zero entries at the end +- rows = rows[: last_non_zero + 1] +- return rows ++ # Don't include any leading and trailing zero entries ++ start = 0 ++ end = len(rows) - 1 ++ ++ while start <= end: ++ if rows[start][1] == 0: ++ start += 1 ++ elif rows[end][1] == 0: ++ end -= 1 ++ else: ++ break ++ ++ return rows[start:end+1] + + return calc + +@@ -1214,6 +1279,28 @@ + + yield Table(("", "Count:", "Ratio:"), calc_optimization_table, JoinMode.CHANGE) + yield Table(("", "Count:", "Ratio:"), calc_optimizer_table, JoinMode.CHANGE) ++ yield Section( ++ "JIT memory stats", ++ "JIT memory stats", ++ [ ++ Table( ++ ("", "Size (bytes):", "Ratio:"), ++ calc_jit_memory_table, ++ JoinMode.CHANGE ++ ) ++ ], ++ ) ++ yield Section( ++ "JIT trace total memory histogram", ++ "JIT trace total memory histogram", ++ [ ++ Table( ++ ("Size (bytes)", "Count", "Ratio:"), ++ calc_histogram_table("Trace total memory size"), ++ JoinMode.CHANGE_NO_SORT, ++ ) ++ ], ++ ) + for name, den in [ + ("Trace length", "Optimization traces created"), + ("Optimized trace length", "Optimization traces created"), +diff --git a/Tools/tsan/suppressions_free_threading.txt b/Tools/tsan/suppressions_free_threading.txt +index e5eb665ae21..c2509cae7b9 100644 +--- a/Tools/tsan/suppressions_free_threading.txt ++++ b/Tools/tsan/suppressions_free_threading.txt +@@ -22,7 +22,6 @@ + # These warnings trigger directly in a CPython function. + + race_top:assign_version_tag +-race_top:new_reference + race_top:_multiprocessing_SemLock_acquire_impl + race_top:list_get_item_ref + race_top:_Py_slot_tp_getattr_hook +@@ -44,5 +43,11 @@ + # Only seen on macOS, sample: https://gist.github.com/aisk/dda53f5d494a4556c35dde1fce03259c + race_top:set_default_allocator_unlocked + ++# gh-129068: race on shared range iterators (test_free_threading.test_zip.ZipThreading.test_threading) ++race_top:rangeiter_next ++ ++# gh-129748: test.test_free_threading.test_slots.TestSlots.test_object ++race_top:mi_block_set_nextx ++ + # https://gist.github.com/mpage/6962e8870606cfc960e159b407a0cb40 + thread:pthread_create +diff --git a/Tools/wasm/emscripten/web_example/python.worker.mjs b/Tools/wasm/emscripten/web_example/python.worker.mjs +index 8043e419966..5f9012a492a 100644 +--- a/Tools/wasm/emscripten/web_example/python.worker.mjs ++++ b/Tools/wasm/emscripten/web_example/python.worker.mjs +@@ -70,12 +70,9 @@ + postMessage({ type: "ready", stdinBuffer: stdinBuffer.sab }); + }, + async preRun(Module) { +- const versionHex = Module.HEAPU32[Module._Py_Version / 4].toString(16); +- const versionTuple = versionHex +- .padStart(8, "0") +- .match(/.{1,2}/g) +- .map((x) => parseInt(x, 16)); +- const [major, minor, ..._] = versionTuple; ++ const versionInt = Module.HEAPU32[Module._Py_Version >>> 2]; ++ const major = (versionInt >>> 24) & 0xff; ++ const minor = (versionInt >>> 16) & 0xff; + // Prevent complaints about not finding exec-prefix by making a lib-dynload directory + Module.FS.mkdirTree(`/lib/python${major}.${minor}/lib-dynload/`); + Module.addRunDependency("install-stdlib"); +diff --git a/config.guess b/config.guess +index e81d3ae7c21..cdfc4392047 100755 +--- a/config.guess ++++ b/config.guess +@@ -1,14 +1,14 @@ + #! /bin/sh + # Attempt to guess a canonical system name. +-# Copyright 1992-2021 Free Software Foundation, Inc. ++# Copyright 1992-2023 Free Software Foundation, Inc. + + # shellcheck disable=SC2006,SC2268 # see below for rationale + +-timestamp='2021-06-03' ++timestamp='2023-08-22' + + # This file is free software; you can redistribute it and/or modify it + # under the terms of the GNU General Public License as published by +-# the Free Software Foundation; either version 3 of the License, or ++# the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, but +@@ -47,7 +47,7 @@ + usage="\ + Usage: $0 [OPTION] + +-Output the configuration name of the system \`$me' is run on. ++Output the configuration name of the system '$me' is run on. + + Options: + -h, --help print this help, then exit +@@ -60,13 +60,13 @@ + GNU config.guess ($timestamp) + + Originally written by Per Bothner. +-Copyright 1992-2021 Free Software Foundation, Inc. ++Copyright 1992-2023 Free Software Foundation, Inc. + + This is free software; see the source for copying conditions. There is NO + warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + + help=" +-Try \`$me --help' for more information." ++Try '$me --help' for more information." + + # Parse command line + while test $# -gt 0 ; do +@@ -102,8 +102,8 @@ + # temporary files to be created and, as you can see below, it is a + # headache to deal with in a portable fashion. + +-# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +-# use `HOST_CC' if defined, but it is deprecated. ++# Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still ++# use 'HOST_CC' if defined, but it is deprecated. + + # Portable tmp directory creation inspired by the Autoconf team. + +@@ -155,6 +155,9 @@ + + set_cc_for_build + cat <<-EOF > "$dummy.c" ++ #if defined(__ANDROID__) ++ LIBC=android ++ #else + #include + #if defined(__UCLIBC__) + LIBC=uclibc +@@ -169,6 +172,7 @@ + LIBC=musl + #endif + #endif ++ #endif + EOF + cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + eval "$cc_set_libc" +@@ -437,7 +441,7 @@ + # This test works for both compilers. + if test "$CC_FOR_BUILD" != no_compiler_found; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ +- (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ ++ (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH=x86_64 +@@ -459,7 +463,7 @@ + UNAME_RELEASE=`uname -v` + ;; + esac +- # Japanese Language versions have a version number like `4.1.3-JL'. ++ # Japanese Language versions have a version number like '4.1.3-JL'. + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` + GUESS=sparc-sun-sunos$SUN_REL + ;; +@@ -904,7 +908,7 @@ + fi + ;; + *:FreeBSD:*:*) +- UNAME_PROCESSOR=`/usr/bin/uname -p` ++ UNAME_PROCESSOR=`uname -p` + case $UNAME_PROCESSOR in + amd64) + UNAME_PROCESSOR=x86_64 ;; +@@ -929,6 +933,9 @@ + i*:PW*:*) + GUESS=$UNAME_MACHINE-pc-pw32 + ;; ++ *:SerenityOS:*:*) ++ GUESS=$UNAME_MACHINE-pc-serenity ++ ;; + *:Interix*:*) + case $UNAME_MACHINE in + x86) +@@ -963,11 +970,37 @@ + GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC + ;; ++ x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*) ++ GUESS="$UNAME_MACHINE-pc-managarm-mlibc" ++ ;; ++ *:[Mm]anagarm:*:*) ++ GUESS="$UNAME_MACHINE-unknown-managarm-mlibc" ++ ;; + *:Minix:*:*) + GUESS=$UNAME_MACHINE-unknown-minix + ;; + aarch64:Linux:*:*) +- GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ++ set_cc_for_build ++ CPU=$UNAME_MACHINE ++ LIBCABI=$LIBC ++ if test "$CC_FOR_BUILD" != no_compiler_found; then ++ ABI=64 ++ sed 's/^ //' << EOF > "$dummy.c" ++ #ifdef __ARM_EABI__ ++ #ifdef __ARM_PCS_VFP ++ ABI=eabihf ++ #else ++ ABI=eabi ++ #endif ++ #endif ++EOF ++ cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` ++ eval "$cc_set_abi" ++ case $ABI in ++ eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;; ++ esac ++ fi ++ GUESS=$CPU-unknown-linux-$LIBCABI + ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be +@@ -1033,7 +1066,16 @@ + k1om:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; +- loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*) ++ kvx:Linux:*:*) ++ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ++ ;; ++ kvx:cos:*:*) ++ GUESS=$UNAME_MACHINE-unknown-cos ++ ;; ++ kvx:mbr:*:*) ++ GUESS=$UNAME_MACHINE-unknown-mbr ++ ;; ++ loongarch32:Linux:*:* | loongarch64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + m32r*:Linux:*:*) +@@ -1148,16 +1190,27 @@ + ;; + x86_64:Linux:*:*) + set_cc_for_build ++ CPU=$UNAME_MACHINE + LIBCABI=$LIBC + if test "$CC_FOR_BUILD" != no_compiler_found; then +- if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \ +- (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ +- grep IS_X32 >/dev/null +- then +- LIBCABI=${LIBC}x32 +- fi ++ ABI=64 ++ sed 's/^ //' << EOF > "$dummy.c" ++ #ifdef __i386__ ++ ABI=x86 ++ #else ++ #ifdef __ILP32__ ++ ABI=x32 ++ #endif ++ #endif ++EOF ++ cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` ++ eval "$cc_set_abi" ++ case $ABI in ++ x86) CPU=i686 ;; ++ x32) LIBCABI=${LIBC}x32 ;; ++ esac + fi +- GUESS=$UNAME_MACHINE-pc-linux-$LIBCABI ++ GUESS=$CPU-pc-linux-$LIBCABI + ;; + xtensa*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC +@@ -1177,7 +1230,7 @@ + GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION + ;; + i*86:OS/2:*:*) +- # If we were able to find `uname', then EMX Unix compatibility ++ # If we were able to find 'uname', then EMX Unix compatibility + # is probably installed. + GUESS=$UNAME_MACHINE-pc-os2-emx + ;; +@@ -1318,7 +1371,7 @@ + GUESS=ns32k-sni-sysv + fi + ;; +- PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort ++ PENTIUM:*:4.0*:*) # Unisys 'ClearPath HMP IX 4000' SVR4/MP effort + # says + GUESS=i586-unisys-sysv4 + ;; +@@ -1364,8 +1417,11 @@ + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + GUESS=i586-pc-haiku + ;; +- x86_64:Haiku:*:*) +- GUESS=x86_64-unknown-haiku ++ ppc:Haiku:*:*) # Haiku running on Apple PowerPC ++ GUESS=powerpc-apple-haiku ++ ;; ++ *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat) ++ GUESS=$UNAME_MACHINE-unknown-haiku + ;; + SX-4:SUPER-UX:*:*) + GUESS=sx4-nec-superux$UNAME_RELEASE +@@ -1522,6 +1578,9 @@ + i*86:rdos:*:*) + GUESS=$UNAME_MACHINE-pc-rdos + ;; ++ i*86:Fiwix:*:*) ++ GUESS=$UNAME_MACHINE-pc-fiwix ++ ;; + *:AROS:*:*) + GUESS=$UNAME_MACHINE-unknown-aros + ;; +diff --git a/config.sub b/config.sub +index 1bb6a05dc11..7e007ac54c3 100755 +--- a/config.sub ++++ b/config.sub +@@ -1769,7 +1769,7 @@ + | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ + | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \ + | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr* \ +- | fiwix* | mlibc* | cos* | mbr* | ironclad* ) ++ | fiwix* | mlibc* | cos* | mbr* | ironclad* | macabi) + ;; + # This one is extra strict with allowed versions + sco3.2v2 | sco3.2v[4-9]* | sco5v6*) +@@ -1869,6 +1869,8 @@ + ;; + ios*-simulator- | tvos*-simulator- | watchos*-simulator- ) + ;; ++ ios*-macabi- ) ++ ;; + none--*) + # None (no kernel, i.e. freestanding / bare metal), + # can be paired with an machine code file format +diff --git a/configure b/configure +index 57be576e3ca..0a11bb50856 100755 +--- a/configure ++++ b/configure +@@ -1,11 +1,11 @@ + #! /bin/sh + # Guess values for system-dependent variables and create Makefiles. +-# Generated by GNU Autoconf 2.71 for python 3.14. ++# Generated by GNU Autoconf 2.72 for python 3.14. + # + # Report bugs to . + # + # +-# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, ++# Copyright (C) 1992-1996, 1998-2017, 2020-2023 Free Software Foundation, + # Inc. + # + # +@@ -17,7 +17,6 @@ + + # Be more Bourne compatible + DUALCASE=1; export DUALCASE # for MKS sh +-as_nop=: + if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 + then : + emulate sh +@@ -26,12 +25,13 @@ + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +-else $as_nop +- case `(set -o) 2>/dev/null` in #( ++else case e in #( ++ e) case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; ++esac ;; + esac + fi + +@@ -103,7 +103,7 @@ + + ;; + esac +-# We did not find ourselves, most probably we were run as `sh COMMAND' ++# We did not find ourselves, most probably we were run as 'sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 +@@ -133,15 +133,14 @@ + esac + exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} + # Admittedly, this is quite paranoid, since all the known shells bail +-# out after a failed `exec'. ++# out after a failed 'exec'. + printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 + exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} + if test "x$CONFIG_SHELL" = x; then +- as_bourne_compatible="as_nop=: +-if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 ++ as_bourne_compatible="if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 + then : + emulate sh + NULLCMD=: +@@ -149,12 +148,13 @@ + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +-else \$as_nop +- case \`(set -o) 2>/dev/null\` in #( ++else case e in #( ++ e) case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; ++esac ;; + esac + fi + " +@@ -172,8 +172,9 @@ + if ( set x; as_fn_ret_success y && test x = \"\$1\" ) + then : + +-else \$as_nop +- exitcode=1; echo positional parameters were not saved. ++else case e in #( ++ e) exitcode=1; echo positional parameters were not saved. ;; ++esac + fi + test x\$exitcode = x0 || exit 1 + blah=\$(echo \$(echo blah)) +@@ -187,14 +188,15 @@ + if (eval "$as_required") 2>/dev/null + then : + as_have_required=yes +-else $as_nop +- as_have_required=no ++else case e in #( ++ e) as_have_required=no ;; ++esac + fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null + then : + +-else $as_nop +- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++else case e in #( ++ e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR + as_found=false + for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH + do +@@ -227,12 +229,13 @@ + if $as_found + then : + +-else $as_nop +- if { test -f "$SHELL" || test -f "$SHELL.exe"; } && ++else case e in #( ++ e) if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null + then : + CONFIG_SHELL=$SHELL as_have_required=yes +-fi ++fi ;; ++esac + fi + + +@@ -254,7 +257,7 @@ + esac + exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} + # Admittedly, this is quite paranoid, since all the known shells bail +-# out after a failed `exec'. ++# out after a failed 'exec'. + printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 + exit 255 + fi +@@ -274,7 +277,8 @@ + $0: the script under such a shell if you do have one." + fi + exit 1 +-fi ++fi ;; ++esac + fi + fi + SHELL=${CONFIG_SHELL-/bin/sh} +@@ -313,14 +317,6 @@ + as_fn_set_status $1 + exit $1 + } # as_fn_exit +-# as_fn_nop +-# --------- +-# Do nothing but, unlike ":", preserve the value of $?. +-as_fn_nop () +-{ +- return $? +-} +-as_nop=as_fn_nop + + # as_fn_mkdir_p + # ------------- +@@ -389,11 +385,12 @@ + { + eval $1+=\$2 + }' +-else $as_nop +- as_fn_append () ++else case e in #( ++ e) as_fn_append () + { + eval $1=\$$1\$2 +- } ++ } ;; ++esac + fi # as_fn_append + + # as_fn_arith ARG... +@@ -407,21 +404,14 @@ + { + as_val=$(( $* )) + }' +-else $as_nop +- as_fn_arith () ++else case e in #( ++ e) as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` +- } ++ } ;; ++esac + fi # as_fn_arith + +-# as_fn_nop +-# --------- +-# Do nothing but, unlike ":", preserve the value of $?. +-as_fn_nop () +-{ +- return $? +-} +-as_nop=as_fn_nop + + # as_fn_error STATUS ERROR [LINENO LOG_FD] + # ---------------------------------------- +@@ -495,6 +485,8 @@ + /[$]LINENO/= + ' <$as_myself | + sed ' ++ t clear ++ :clear + s/[$]LINENO.*/&-/ + t lineno + b +@@ -543,7 +535,6 @@ + as_echo='printf %s\n' + as_echo_n='printf %s' + +- + rm -f conf$$ conf$$.exe conf$$.file + if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +@@ -555,9 +546,9 @@ + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: +- # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. +- # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. +- # In both cases, we have to default to `cp -pR'. ++ # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. ++ # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. ++ # In both cases, we have to default to 'cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then +@@ -582,10 +573,12 @@ + as_executable_p=as_fn_executable_p + + # Sed expression to map a string onto a valid CPP name. +-as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" ++as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" ++as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated + + # Sed expression to map a string onto a valid variable name. +-as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" ++as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" ++as_tr_sh="eval sed '$as_sed_sh'" # deprecated + + + test -n "$DJDIR" || exec 7<&0 /dev/null && +- as_fn_error $? "invalid feature name: \`$ac_useropt'" ++ as_fn_error $? "invalid feature name: '$ac_useropt'" + ac_useropt_orig=$ac_useropt + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in +@@ -1313,7 +1309,7 @@ + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && +- as_fn_error $? "invalid feature name: \`$ac_useropt'" ++ as_fn_error $? "invalid feature name: '$ac_useropt'" + ac_useropt_orig=$ac_useropt + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in +@@ -1526,7 +1522,7 @@ + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && +- as_fn_error $? "invalid package name: \`$ac_useropt'" ++ as_fn_error $? "invalid package name: '$ac_useropt'" + ac_useropt_orig=$ac_useropt + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in +@@ -1542,7 +1538,7 @@ + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && +- as_fn_error $? "invalid package name: \`$ac_useropt'" ++ as_fn_error $? "invalid package name: '$ac_useropt'" + ac_useropt_orig=$ac_useropt + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in +@@ -1572,8 +1568,8 @@ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + +- -*) as_fn_error $? "unrecognized option: \`$ac_option' +-Try \`$0 --help' for more information" ++ -*) as_fn_error $? "unrecognized option: '$ac_option' ++Try '$0 --help' for more information" + ;; + + *=*) +@@ -1581,7 +1577,7 @@ + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) +- as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; ++ as_fn_error $? "invalid variable name: '$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; +@@ -1631,7 +1627,7 @@ + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" + done + +-# There might be people who depend on the old broken behavior: `$host' ++# There might be people who depend on the old broken behavior: '$host' + # used to hold the argument of --host etc. + # FIXME: To remove some day. + build=$build_alias +@@ -1699,7 +1695,7 @@ + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" + fi +-ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ++ac_msg="sources are in $srcdir, but 'cd $srcdir' does not work" + ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +@@ -1727,7 +1723,7 @@ + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +-\`configure' configures python 3.14 to adapt to many kinds of systems. ++'configure' configures python 3.14 to adapt to many kinds of systems. + + Usage: $0 [OPTION]... [VAR=VALUE]... + +@@ -1741,11 +1737,11 @@ + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit +- -q, --quiet, --silent do not print \`checking ...' messages ++ -q, --quiet, --silent do not print 'checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] +- -C, --config-cache alias for \`--cache-file=config.cache' ++ -C, --config-cache alias for '--cache-file=config.cache' + -n, --no-create do not create output files +- --srcdir=DIR find the sources in DIR [configure dir or \`..'] ++ --srcdir=DIR find the sources in DIR [configure dir or '..'] + + Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX +@@ -1753,10 +1749,10 @@ + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +-By default, \`make install' will install all the files in +-\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +-an installation prefix other than \`$ac_default_prefix' using \`--prefix', +-for instance \`--prefix=\$HOME'. ++By default, 'make install' will install all the files in ++'$ac_default_prefix/bin', '$ac_default_prefix/lib' etc. You can specify ++an installation prefix other than '$ac_default_prefix' using '--prefix', ++for instance '--prefix=\$HOME'. + + For better control, use the options below. + +@@ -1934,6 +1930,8 @@ + use libedit for backend or disable readline module + --with-computed-gotos enable computed gotos in evaluation loop (enabled by + default on supported compilers) ++ --with-tail-call-interp enable tail-calling interpreter in evaluation loop ++ and rest of CPython + --with-ensurepip[=install|upgrade|no] + "install" or "upgrade" using bundled pip (default is + upgrade) +@@ -2020,7 +2018,7 @@ + C compiler flags for PANEL, overriding pkg-config + PANEL_LIBS linker flags for PANEL, overriding pkg-config + +-Use these variables to override the choices made by `configure' or to help ++Use these variables to override the choices made by 'configure' or to help + it to find libraries and programs with nonstandard names/locations. + + Report bugs to . +@@ -2088,9 +2086,9 @@ + if $ac_init_version; then + cat <<\_ACEOF + python configure 3.14 +-generated by GNU Autoconf 2.71 ++generated by GNU Autoconf 2.72 + +-Copyright (C) 2021 Free Software Foundation, Inc. ++Copyright (C) 2023 Free Software Foundation, Inc. + This configure script is free software; the Free Software Foundation + gives unlimited permission to copy, distribute and modify it. + _ACEOF +@@ -2129,11 +2127,12 @@ + } && test -s conftest.$ac_objext + then : + ac_retval=0 +-else $as_nop +- printf "%s\n" "$as_me: failed program was:" >&5 ++else case e in #( ++ e) printf "%s\n" "$as_me: failed program was:" >&5 + sed 's/^/| /' conftest.$ac_ext >&5 + +- ac_retval=1 ++ ac_retval=1 ;; ++esac + fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval +@@ -2167,11 +2166,12 @@ + } + then : + ac_retval=0 +-else $as_nop +- printf "%s\n" "$as_me: failed program was:" >&5 ++else case e in #( ++ e) printf "%s\n" "$as_me: failed program was:" >&5 + sed 's/^/| /' conftest.$ac_ext >&5 + +- ac_retval=1 ++ ac_retval=1 ;; ++esac + fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval +@@ -2190,8 +2190,8 @@ + if eval test \${$3+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + $4 + #include <$2> +@@ -2199,10 +2199,12 @@ + if ac_fn_c_try_compile "$LINENO" + then : + eval "$3=yes" +-else $as_nop +- eval "$3=no" ++else case e in #( ++ e) eval "$3=no" ;; ++esac + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + eval ac_res=\$$3 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +@@ -2242,11 +2244,12 @@ + } + then : + ac_retval=0 +-else $as_nop +- printf "%s\n" "$as_me: failed program was:" >&5 ++else case e in #( ++ e) printf "%s\n" "$as_me: failed program was:" >&5 + sed 's/^/| /' conftest.$ac_ext >&5 + +- ac_retval=1 ++ ac_retval=1 ;; ++esac + fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would +@@ -2288,12 +2291,13 @@ + test $ac_status = 0; }; } + then : + ac_retval=0 +-else $as_nop +- printf "%s\n" "$as_me: program exited with status $ac_status" >&5 ++else case e in #( ++ e) printf "%s\n" "$as_me: program exited with status $ac_status" >&5 + printf "%s\n" "$as_me: failed program was:" >&5 + sed 's/^/| /' conftest.$ac_ext >&5 + +- ac_retval=$ac_status ++ ac_retval=$ac_status ;; ++esac + fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno +@@ -2313,8 +2317,8 @@ + if eval test \${$3+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- eval "$3=no" ++else case e in #( ++ e) eval "$3=no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + $4 +@@ -2344,12 +2348,14 @@ + if ac_fn_c_try_compile "$LINENO" + then : + +-else $as_nop +- eval "$3=yes" ++else case e in #( ++ e) eval "$3=yes" ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + eval ac_res=\$$3 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +@@ -2403,18 +2409,19 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_hi=$ac_mid; break +-else $as_nop +- as_fn_arith $ac_mid + 1 && ac_lo=$as_val ++else case e in #( ++ e) as_fn_arith $ac_mid + 1 && ac_lo=$as_val + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi +- as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val ++ as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + done +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + $4 + int +@@ -2449,20 +2456,23 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_lo=$ac_mid; break +-else $as_nop +- as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val ++else case e in #( ++ e) as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi +- as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val ++ as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + done +-else $as_nop +- ac_lo= ac_hi= ++else case e in #( ++ e) ac_lo= ac_hi= ;; ++esac + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + # Binary search between lo and hi bounds. +@@ -2485,8 +2495,9 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_hi=$ac_mid +-else $as_nop +- as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val ++else case e in #( ++ e) as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + done +@@ -2534,8 +2545,9 @@ + if ac_fn_c_try_run "$LINENO" + then : + echo >>conftest.val; read $3 &6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + /* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ + #define $2 innocuous_$2 + + /* System header to define __stub macros and hopefully few prototypes, +- which can conflict with char $2 (); below. */ ++ which can conflict with char $2 (void); below. */ + + #include + #undef $2 +@@ -2577,7 +2589,7 @@ + #ifdef __cplusplus + extern "C" + #endif +-char $2 (); ++char $2 (void); + /* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +@@ -2596,11 +2608,13 @@ + if ac_fn_c_try_link "$LINENO" + then : + eval "$3=yes" +-else $as_nop +- eval "$3=no" ++else case e in #( ++ e) eval "$3=no" ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ +- conftest$ac_exeext conftest.$ac_ext ++ conftest$ac_exeext conftest.$ac_ext ;; ++esac + fi + eval ac_res=\$$3 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +@@ -2622,8 +2636,8 @@ + if eval test \${$3+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` ++else case e in #( ++ e) as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` + eval ac_save_FLAGS=\$$6 + as_fn_append $6 " $5" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -2647,12 +2661,14 @@ + if ac_fn_c_try_compile "$LINENO" + then : + eval "$3=yes" +-else $as_nop +- eval "$3=no" ++else case e in #( ++ e) eval "$3=no" ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + eval $6=\$ac_save_FLAGS +- ++ ;; ++esac + fi + eval ac_res=\$$3 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +@@ -2673,8 +2689,8 @@ + if eval test \${$4+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + $5 + int +@@ -2690,8 +2706,8 @@ + if ac_fn_c_try_compile "$LINENO" + then : + eval "$4=yes" +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + $5 + int +@@ -2707,12 +2723,15 @@ + if ac_fn_c_try_compile "$LINENO" + then : + eval "$4=yes" +-else $as_nop +- eval "$4=no" ++else case e in #( ++ e) eval "$4=no" ;; ++esac + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + eval ac_res=\$$4 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +@@ -2745,7 +2764,7 @@ + running configure, to aid debugging if configure makes a mistake. + + It was created by python $as_me 3.14, which was +-generated by GNU Autoconf 2.71. Invocation command line was ++generated by GNU Autoconf 2.72. Invocation command line was + + $ $0$ac_configure_args_raw + +@@ -2991,10 +3010,10 @@ + printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ +- || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++ || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error $? "failed to load site script $ac_site_file +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } + fi + done + +@@ -3030,9 +3049,7 @@ + /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ + struct buf { int x; }; + struct buf * (*rcsopen) (struct buf *, struct stat *, int); +-static char *e (p, i) +- char **p; +- int i; ++static char *e (char **p, int i) + { + return p[i]; + } +@@ -3046,6 +3063,21 @@ + return s; + } + ++/* C89 style stringification. */ ++#define noexpand_stringify(a) #a ++const char *stringified = noexpand_stringify(arbitrary+token=sequence); ++ ++/* C89 style token pasting. Exercises some of the corner cases that ++ e.g. old MSVC gets wrong, but not very hard. */ ++#define noexpand_concat(a,b) a##b ++#define expand_concat(a,b) noexpand_concat(a,b) ++extern int vA; ++extern int vbee; ++#define aye A ++#define bee B ++int *pvA = &expand_concat(v,aye); ++int *pvbee = &noexpand_concat(v,bee); ++ + /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not \xHH hex character constants. + These do not provoke an error unfortunately, instead are silently treated +@@ -3073,16 +3105,19 @@ + + # Test code for whether the C compiler supports C99 (global declarations) + ac_c_conftest_c99_globals=' +-// Does the compiler advertise C99 conformance? ++/* Does the compiler advertise C99 conformance? */ + #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L + # error "Compiler does not advertise C99 conformance" + #endif + ++// See if C++-style comments work. ++ + #include + extern int puts (const char *); + extern int printf (const char *, ...); + extern int dprintf (int, const char *, ...); + extern void *malloc (size_t); ++extern void free (void *); + + // Check varargs macros. These examples are taken from C99 6.10.3.5. + // dprintf is used instead of fprintf to avoid needing to declare +@@ -3132,7 +3167,6 @@ + static inline int + test_restrict (ccp restrict text) + { +- // See if C++-style comments work. + // Iterate through items via the restricted pointer. + // Also check for declarations in for loops. + for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) +@@ -3198,6 +3232,8 @@ + ia->datasize = 10; + for (int i = 0; i < ia->datasize; ++i) + ia->data[i] = i * 1.234; ++ // Work around memory leak warnings. ++ free (ia); + + // Check named initializers. + struct named_init ni = { +@@ -3219,7 +3255,7 @@ + + # Test code for whether the C compiler supports C11 (global declarations) + ac_c_conftest_c11_globals=' +-// Does the compiler advertise C11 conformance? ++/* Does the compiler advertise C11 conformance? */ + #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L + # error "Compiler does not advertise C11 conformance" + #endif +@@ -3413,8 +3449,9 @@ + if $as_found + then : + +-else $as_nop +- as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 ++else case e in #( ++ e) as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 ;; ++esac + fi + + +@@ -3442,12 +3479,12 @@ + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +-printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&5 ++printf "%s\n" "$as_me: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +-printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was not set in the previous run" >&5 ++printf "%s\n" "$as_me: error: '$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) +@@ -3456,18 +3493,18 @@ + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +-printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' has changed since the previous run:" >&5 ++printf "%s\n" "$as_me: error: '$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +-printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&5 ++printf "%s\n" "$as_me: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +-printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +-printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: '$ac_old_val'" >&5 ++printf "%s\n" "$as_me: former value: '$ac_old_val'" >&2;} ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: '$ac_new_val'" >&5 ++printf "%s\n" "$as_me: current value: '$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. +@@ -3483,11 +3520,11 @@ + fi + done + if $ac_cache_corrupted; then +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 + printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} +- as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' ++ as_fn_error $? "run '${MAKE-make} distclean' and/or 'rm $cache_file' + and start over" "$LINENO" 5 + fi + ## -------------------- ## +@@ -3538,8 +3575,8 @@ + if test ${ac_cv_prog_HAS_GIT+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test -n "$HAS_GIT"; then ++else case e in #( ++ e) if test -n "$HAS_GIT"; then + ac_cv_prog_HAS_GIT="$HAS_GIT" # Let the user override the test. + else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +@@ -3562,7 +3599,8 @@ + IFS=$as_save_IFS + + test -z "$ac_cv_prog_HAS_GIT" && ac_cv_prog_HAS_GIT="not-found" +-fi ++fi ;; ++esac + fi + HAS_GIT=$ac_cv_prog_HAS_GIT + if test -n "$HAS_GIT"; then +@@ -3604,15 +3642,16 @@ + if test ${ac_cv_build+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_build_alias=$build_alias ++else case e in #( ++ e) ac_build_alias=$build_alias + test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` + test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 + ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 + printf "%s\n" "$ac_cv_build" >&6; } +@@ -3639,14 +3678,15 @@ + if test ${ac_cv_host+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test "x$host_alias" = x; then ++else case e in #( ++ e) if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build + else + ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 + printf "%s\n" "$ac_cv_host" >&6; } +@@ -3710,8 +3750,8 @@ + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_build_python" >&5 + printf "%s\n" "$with_build_python" >&6; } + +-else $as_nop +- ++else case e in #( ++ e) + if test "x$cross_compiling" = xyes + then : + as_fn_error $? "Cross compiling requires --with-build-python" "$LINENO" 5 +@@ -3720,7 +3760,8 @@ + PYTHON_FOR_BUILD='./$(BUILDPYTHON) -E' + PYTHON_FOR_FREEZE="./_bootstrap_python" + +- ++ ;; ++esac + fi + + +@@ -3740,15 +3781,16 @@ + FREEZE_MODULE_DEPS='$(FREEZE_MODULE_BOOTSTRAP_DEPS)' + PYTHON_FOR_BUILD_DEPS='' + +-else $as_nop +- ++else case e in #( ++ e) + FREEZE_MODULE_BOOTSTRAP='./Programs/_freeze_module' + FREEZE_MODULE_BOOTSTRAP_DEPS="Programs/_freeze_module" + FREEZE_MODULE='$(PYTHON_FOR_FREEZE) $(srcdir)/Programs/_freeze_module.py' + FREEZE_MODULE_DEPS="_bootstrap_python \$(srcdir)/Programs/_freeze_module.py" + PYTHON_FOR_BUILD_DEPS='$(BUILDPYTHON)' + +- ++ ;; ++esac + fi + + +@@ -3765,8 +3807,8 @@ + if test ${ac_cv_prog_PYTHON_FOR_REGEN+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test -n "$PYTHON_FOR_REGEN"; then ++else case e in #( ++ e) if test -n "$PYTHON_FOR_REGEN"; then + ac_cv_prog_PYTHON_FOR_REGEN="$PYTHON_FOR_REGEN" # Let the user override the test. + else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +@@ -3788,7 +3830,8 @@ + done + IFS=$as_save_IFS + +-fi ++fi ;; ++esac + fi + PYTHON_FOR_REGEN=$ac_cv_prog_PYTHON_FOR_REGEN + if test -n "$PYTHON_FOR_REGEN"; then +@@ -3870,9 +3913,10 @@ + if test ${with_pkg_config+y} + then : + withval=$with_pkg_config; +-else $as_nop +- with_pkg_config=check +- ++else case e in #( ++ e) with_pkg_config=check ++ ;; ++esac + fi + + case $with_pkg_config in #( +@@ -3899,8 +3943,8 @@ + if test ${ac_cv_path_PKG_CONFIG+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- case $PKG_CONFIG in ++else case e in #( ++ e) case $PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. + ;; +@@ -3925,6 +3969,7 @@ + IFS=$as_save_IFS + + ;; ++esac ;; + esac + fi + PKG_CONFIG=$ac_cv_path_PKG_CONFIG +@@ -3947,8 +3992,8 @@ + if test ${ac_cv_path_ac_pt_PKG_CONFIG+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- case $ac_pt_PKG_CONFIG in ++else case e in #( ++ e) case $ac_pt_PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. + ;; +@@ -3973,6 +4018,7 @@ + IFS=$as_save_IFS + + ;; ++esac ;; + esac + fi + ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG +@@ -4052,6 +4098,15 @@ + *-apple-ios*) + ac_sys_system=iOS + ;; ++ *-apple-tvos*) ++ ac_sys_system=tvOS ++ ;; ++ *-apple-watchos*) ++ ac_sys_system=watchOS ++ ;; ++ *-*-darwin*) ++ ac_sys_system=Darwin ++ ;; + *-*-vxworks*) + ac_sys_system=VxWorks + ;; +@@ -4084,6 +4139,7 @@ + + case $MACHDEP in + aix*) MACHDEP="aix";; ++ freebsd*) MACHDEP="freebsd";; + linux-android*) MACHDEP="android";; + linux*) MACHDEP="linux";; + cygwin*) MACHDEP="cygwin";; +@@ -4129,7 +4185,7 @@ + # On cross-compile builds, configure will look for a host-specific compiler by + # prepending the user-provided host triple to the required binary name. + # +-# On iOS, this results in binaries like "arm64-apple-ios13.0-simulator-gcc", ++# On iOS/tvOS/watchOS, this results in binaries like "arm64-apple-ios13.0-simulator-gcc", + # which isn't a binary that exists, and isn't very convenient, as it contains the + # iOS version. As the default cross-compiler name won't exist, configure falls + # back to gcc, which *definitely* won't work. We're providing wrapper scripts for +@@ -4142,32 +4198,76 @@ + if test -z "$AR"; then + case "$host" in + aarch64-apple-ios*-simulator) AR=arm64-apple-ios-simulator-ar ;; ++ aarch64-apple-ios*-macabi) AR=arm64-apple-ios-macabi-ar ;; + aarch64-apple-ios*) AR=arm64-apple-ios-ar ;; + x86_64-apple-ios*-simulator) AR=x86_64-apple-ios-simulator-ar ;; ++ ++ aarch64-apple-tvos*-simulator) AR=arm64-apple-tvos-simulator-ar ;; ++ aarch64-apple-tvos*-macabi) AR=arm64-apple-tvos-macabi-ar ;; ++ aarch64-apple-tvos*) AR=arm64-apple-tvos-ar ;; ++ x86_64-apple-tvos*-simulator) AR=x86_64-apple-tvos-simulator-ar ;; ++ ++ aarch64-apple-watchos*-simulator) AR=arm64-apple-watchos-simulator-ar ;; ++ aarch64-apple-watchos*-macabi) AR=arm64-apple-watchos-macabi-ar ;; ++ aarch64-apple-watchos*) AR=arm64_32-apple-watchos-ar ;; ++ x86_64-apple-watchos*-simulator) AR=x86_64-apple-watchos-simulator-ar ;; + *) + esac + fi + if test -z "$CC"; then + case "$host" in + aarch64-apple-ios*-simulator) CC=arm64-apple-ios-simulator-clang ;; ++ aarch64-apple-ios*-macabi) CC=arm64-apple-ios-macabi-clang ;; + aarch64-apple-ios*) CC=arm64-apple-ios-clang ;; + x86_64-apple-ios*-simulator) CC=x86_64-apple-ios-simulator-clang ;; ++ ++ aarch64-apple-tvos*-simulator) CC=arm64-apple-tvos-simulator-clang ;; ++ aarch64-apple-tvos*-macabi) CC=arm64-apple-tvos-macabi-clang ;; ++ aarch64-apple-tvos*) CC=arm64-apple-tvos-clang ;; ++ x86_64-apple-tvos*-simulator) CC=x86_64-apple-tvos-simulator-clang ;; ++ ++ aarch64-apple-watchos*-simulator) CC=arm64-apple-watchos-simulator-clang ;; ++ aarch64-apple-watchos*-macabi) CC=arm64-apple-watchos-macabi-clang ;; ++ aarch64-apple-watchos*) CC=arm64_32-apple-watchos-clang ;; ++ x86_64-apple-watchos*-simulator) CC=x86_64-apple-watchos-simulator-clang ;; + *) + esac + fi + if test -z "$CPP"; then + case "$host" in + aarch64-apple-ios*-simulator) CPP=arm64-apple-ios-simulator-cpp ;; ++ aarch64-apple-ios*-macabi) CPP=arm64-apple-ios-macabi-cpp ;; + aarch64-apple-ios*) CPP=arm64-apple-ios-cpp ;; + x86_64-apple-ios*-simulator) CPP=x86_64-apple-ios-simulator-cpp ;; ++ ++ aarch64-apple-tvos*-simulator) CPP=arm64-apple-tvos-simulator-cpp ;; ++ aarch64-apple-tvos*-macabi) CPP=arm64-apple-tvos-macabi-cpp ;; ++ aarch64-apple-tvos*) CPP=arm64-apple-tvos-cpp ;; ++ x86_64-apple-tvos*-simulator) CPP=x86_64-apple-tvos-simulator-cpp ;; ++ ++ aarch64-apple-watchos*-simulator) CPP=arm64-apple-watchos-simulator-cpp ;; ++ aarch64-apple-watchos*-macabi) CPP=arm64-apple-watchos-macabi-cpp ;; ++ aarch64-apple-watchos*) CPP=arm64_32-apple-watchos-cpp ;; ++ x86_64-apple-watchos*-simulator) CPP=x86_64-apple-watchos-simulator-cpp ;; + *) + esac + fi + if test -z "$CXX"; then + case "$host" in + aarch64-apple-ios*-simulator) CXX=arm64-apple-ios-simulator-clang++ ;; ++ aarch64-apple-ios*-macabi) CXX=arm64-apple-ios-macabi-clang++ ;; + aarch64-apple-ios*) CXX=arm64-apple-ios-clang++ ;; + x86_64-apple-ios*-simulator) CXX=x86_64-apple-ios-simulator-clang++ ;; ++ ++ aarch64-apple-tvos*-simulator) CXX=arm64-apple-tvos-simulator-clang++ ;; ++ aarch64-apple-tvos*-macabi) CXX=arm64-apple-tvos-macabi-clang++ ;; ++ aarch64-apple-tvos*) CXX=arm64-apple-tvos-clang++ ;; ++ x86_64-apple-tvos*-simulator) CXX=x86_64-apple-tvos-simulator-clang++ ;; ++ ++ aarch64-apple-watchos*-simulator) CXX=arm64-apple-watchos-simulator-clang++ ;; ++ aarch64-apple-watchos*-macabi) CXX=arm64-apple-watchos-macabi-clang++ ;; ++ aarch64-apple-watchos*) CXX=arm64_32-apple-watchos-clang++ ;; ++ x86_64-apple-watchos*-simulator) CXX=x86_64-apple-watchos-simulator-clang++ ;; + *) + esac + fi +@@ -4208,11 +4308,12 @@ + esac + + +-else $as_nop +- ++else case e in #( ++ e) + UNIVERSALSDK= + enable_universalsdk= +- ++ ;; ++esac + fi + + if test -n "${UNIVERSALSDK}" +@@ -4273,12 +4374,13 @@ + PYTHONFRAMEWORKDIR=${withval}.framework + PYTHONFRAMEWORKIDENTIFIER=org.python.`echo $withval | tr 'A-Z' 'a-z'` + +-else $as_nop +- ++else case e in #( ++ e) + PYTHONFRAMEWORK=Python + PYTHONFRAMEWORKDIR=Python.framework + PYTHONFRAMEWORKIDENTIFIER=org.python.python +- ++ ;; ++esac + fi + + # Check whether --enable-framework was given. +@@ -4288,8 +4390,10 @@ + case $enableval in + yes) + case $ac_sys_system in +- Darwin) enableval=/Library/Frameworks ;; +- iOS) enableval=iOS/Frameworks/\$\(MULTIARCH\) ;; ++ Darwin) enableval=/Library/Frameworks ;; ++ iOS) enableval=iOS/Frameworks/\$\(MULTIARCH\) ;; ++ tvOS) enableval=tvOS/Frameworks/\$\(MULTIARCH\) ;; ++ watchOS) enableval=watchOS/Frameworks/\$\(MULTIARCH\) ;; + *) as_fn_error $? "Unknown platform for framework build" "$LINENO" 5 + esac + esac +@@ -4298,6 +4402,8 @@ + no) + case $ac_sys_system in + iOS) as_fn_error $? "iOS builds must use --enable-framework" "$LINENO" 5 ;; ++ tvOS) as_fn_error $? "tvOS builds must use --enable-framework" "$LINENO" 5 ;; ++ watchOS) as_fn_error $? "watchOS builds must use --enable-framework" "$LINENO" 5 ;; + *) + PYTHONFRAMEWORK= + PYTHONFRAMEWORKDIR=no-framework +@@ -4404,6 +4510,36 @@ + + ac_config_files="$ac_config_files iOS/Resources/Info.plist" + ++ ;; ++ tvOS) : ++ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure" ++ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure " ++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKPYTHONW= ++ INSTALLTARGETS="libinstall inclinstall sharedinstall" ++ ++ prefix=$PYTHONFRAMEWORKPREFIX ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" ++ RESSRCDIR=tvOS/Resources ++ ++ ac_config_files="$ac_config_files tvOS/Resources/Info.plist" ++ ++ ;; ++ watchOS) : ++ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure" ++ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure " ++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKPYTHONW= ++ INSTALLTARGETS="libinstall inclinstall sharedinstall" ++ ++ prefix=$PYTHONFRAMEWORKPREFIX ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" ++ RESSRCDIR=watchOS/Resources ++ ++ ac_config_files="$ac_config_files watchOS/Resources/Info.plist" ++ + ;; + *) + as_fn_error $? "Unknown platform for framework build" "$LINENO" 5 +@@ -4411,10 +4547,12 @@ + esac + esac + +-else $as_nop +- ++else case e in #( ++ e) + case $ac_sys_system in + iOS) as_fn_error $? "iOS builds must use --enable-framework" "$LINENO" 5 ;; ++ tvOS) as_fn_error $? "tvOS builds must use --enable-framework" "$LINENO" 5 ;; ++ watchOS) as_fn_error $? "watchOS builds must use --enable-framework" "$LINENO" 5 ;; + *) + PYTHONFRAMEWORK= + PYTHONFRAMEWORKDIR=no-framework +@@ -4435,7 +4573,8 @@ + fi + enable_framework= + esac +- ++ ;; ++esac + fi + + +@@ -4468,8 +4607,8 @@ + case "$withval" in + yes) + case $ac_sys_system in +- Darwin|iOS) +- # iOS is able to share the macOS patch ++ Darwin|iOS|tvOS|watchOS) ++ # iOS/tvOS/watchOS is able to share the macOS patch + APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" + ;; + *) as_fn_error $? "no default app store compliance patch available for $ac_sys_system" "$LINENO" 5 ;; +@@ -4484,11 +4623,11 @@ + ;; + esac + +-else $as_nop +- ++else case e in #( ++ e) + case $ac_sys_system in +- iOS) +- # Always apply the compliance patch on iOS; we can use the macOS patch ++ iOS|tvOS|watchOS) ++ # Always apply the compliance patch on iOS/tvOS/watchOS; we can use the macOS patch + APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: applying default app store compliance patch" >&5 + printf "%s\n" "applying default app store compliance patch" >&6; } +@@ -4500,7 +4639,8 @@ + printf "%s\n" "not patching for app store compliance" >&6; } + ;; + esac +- ++ ;; ++esac + fi + + +@@ -4542,9 +4682,65 @@ + ;; + esac + ;; ++ *-apple-tvos*) ++ _host_os=`echo $host | cut -d '-' -f3` ++ _host_device=`echo $host | cut -d '-' -f4` ++ _host_device=${_host_device:=os} ++ ++ # TVOS_DEPLOYMENT_TARGET is the minimum supported tvOS version ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking tvOS deployment target" >&5 ++printf %s "checking tvOS deployment target... " >&6; } ++ TVOS_DEPLOYMENT_TARGET=${_host_os:4} ++ TVOS_DEPLOYMENT_TARGET=${TVOS_DEPLOYMENT_TARGET:=12.0} ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $TVOS_DEPLOYMENT_TARGET" >&5 ++printf "%s\n" "$TVOS_DEPLOYMENT_TARGET" >&6; } ++ ++ case "$host_cpu" in ++ aarch64) ++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-arm64-appletv${_host_device} ++ ;; ++ *) ++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-$host_cpu-appletv${_host_device} ++ ;; ++ esac ++ ;; ++ *-apple-watchos*) ++ _host_os=`echo $host | cut -d '-' -f3` ++ _host_device=`echo $host | cut -d '-' -f4` ++ _host_device=${_host_device:=os} ++ ++ # WATCHOS_DEPLOYMENT_TARGET is the minimum supported watchOS version ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking watchOS deployment target" >&5 ++printf %s "checking watchOS deployment target... " >&6; } ++ WATCHOS_DEPLOYMENT_TARGET=${_host_os:7} ++ WATCHOS_DEPLOYMENT_TARGET=${WATCHOS_DEPLOYMENT_TARGET:=4.0} ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $WATCHOS_DEPLOYMENT_TARGET" >&5 ++printf "%s\n" "$WATCHOS_DEPLOYMENT_TARGET" >&6; } ++ ++ case "$host_cpu" in ++ aarch64) ++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-arm64-watch${_host_device} ++ ;; ++ *) ++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-$host_cpu-watch${_host_device} ++ ;; ++ esac ++ ;; ++ *-*-darwin*) ++ case "$host_cpu" in ++ arm*) ++ _host_ident=arm ++ ;; ++ *) ++ _host_ident=$host_cpu ++ esac ++ ;; + *-*-vxworks*) + _host_ident=$host_cpu + ;; ++ *-*-emscripten) ++ _host_ident=$(emcc -dumpversion | cut -f1 -d-)-$host_cpu ++ ;; + wasm32-*-* | wasm64-*-*) + _host_ident=$host_cpu + ;; +@@ -4620,9 +4816,13 @@ + define_xopen_source=no;; + Darwin/[12][0-9].*) + define_xopen_source=no;; +- # On iOS, defining _POSIX_C_SOURCE also disables platform specific features. ++ # On iOS/tvOS/watchOS, defining _POSIX_C_SOURCE also disables platform specific features. + iOS/*) + define_xopen_source=no;; ++ tvOS/*) ++ define_xopen_source=no;; ++ watchOS/*) ++ define_xopen_source=no;; + # On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from + # defining NI_NUMERICHOST. + QNX/6.3.2) +@@ -4685,7 +4885,10 @@ + CONFIGURE_MACOSX_DEPLOYMENT_TARGET= + EXPORT_MACOSX_DEPLOYMENT_TARGET='#' + +-# Record the value of IPHONEOS_DEPLOYMENT_TARGET enforced by the selected host triple. ++# Record the value of IPHONEOS_DEPLOYMENT_TARGET / TVOS_DEPLOYMENT_TARGET / ++# WATCHOS_DEPLOYMENT_TARGET enforced by the selected host triple. ++ ++ + + + # checks for alternative programs +@@ -4726,6 +4929,16 @@ + as_fn_append CFLAGS " -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}" + as_fn_append LDFLAGS " -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}" + ;; #( ++ tvOS) : ++ ++ as_fn_append CFLAGS " -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}" ++ as_fn_append LDFLAGS " -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}" ++ ;; #( ++ watchOS) : ++ ++ as_fn_append CFLAGS " -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}" ++ as_fn_append LDFLAGS " -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}" ++ ;; #( + *) : + ;; + esac +@@ -4739,8 +4952,8 @@ + if test ${ac_cv_prog_HAS_XCRUN+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test -n "$HAS_XCRUN"; then ++else case e in #( ++ e) if test -n "$HAS_XCRUN"; then + ac_cv_prog_HAS_XCRUN="$HAS_XCRUN" # Let the user override the test. + else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +@@ -4763,7 +4976,8 @@ + IFS=$as_save_IFS + + test -z "$ac_cv_prog_HAS_XCRUN" && ac_cv_prog_HAS_XCRUN="missing" +-fi ++fi ;; ++esac + fi + HAS_XCRUN=$ac_cv_prog_HAS_XCRUN + if test -n "$HAS_XCRUN"; then +@@ -4866,8 +5080,8 @@ + if test ${ac_cv_prog_CC+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test -n "$CC"; then ++else case e in #( ++ e) if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. + else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +@@ -4889,7 +5103,8 @@ + done + IFS=$as_save_IFS + +-fi ++fi ;; ++esac + fi + CC=$ac_cv_prog_CC + if test -n "$CC"; then +@@ -4911,8 +5126,8 @@ + if test ${ac_cv_prog_ac_ct_CC+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test -n "$ac_ct_CC"; then ++else case e in #( ++ e) if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. + else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +@@ -4934,7 +5149,8 @@ + done + IFS=$as_save_IFS + +-fi ++fi ;; ++esac + fi + ac_ct_CC=$ac_cv_prog_ac_ct_CC + if test -n "$ac_ct_CC"; then +@@ -4969,8 +5185,8 @@ + if test ${ac_cv_prog_CC+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test -n "$CC"; then ++else case e in #( ++ e) if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. + else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +@@ -4992,7 +5208,8 @@ + done + IFS=$as_save_IFS + +-fi ++fi ;; ++esac + fi + CC=$ac_cv_prog_CC + if test -n "$CC"; then +@@ -5014,8 +5231,8 @@ + if test ${ac_cv_prog_CC+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test -n "$CC"; then ++else case e in #( ++ e) if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. + else + ac_prog_rejected=no +@@ -5054,7 +5271,8 @@ + ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" + fi + fi +-fi ++fi ;; ++esac + fi + CC=$ac_cv_prog_CC + if test -n "$CC"; then +@@ -5078,8 +5296,8 @@ + if test ${ac_cv_prog_CC+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test -n "$CC"; then ++else case e in #( ++ e) if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. + else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +@@ -5101,7 +5319,8 @@ + done + IFS=$as_save_IFS + +-fi ++fi ;; ++esac + fi + CC=$ac_cv_prog_CC + if test -n "$CC"; then +@@ -5127,8 +5346,8 @@ + if test ${ac_cv_prog_ac_ct_CC+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test -n "$ac_ct_CC"; then ++else case e in #( ++ e) if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. + else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +@@ -5150,7 +5369,8 @@ + done + IFS=$as_save_IFS + +-fi ++fi ;; ++esac + fi + ac_ct_CC=$ac_cv_prog_ac_ct_CC + if test -n "$ac_ct_CC"; then +@@ -5188,8 +5408,8 @@ + if test ${ac_cv_prog_CC+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test -n "$CC"; then ++else case e in #( ++ e) if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. + else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +@@ -5211,7 +5431,8 @@ + done + IFS=$as_save_IFS + +-fi ++fi ;; ++esac + fi + CC=$ac_cv_prog_CC + if test -n "$CC"; then +@@ -5233,8 +5454,8 @@ + if test ${ac_cv_prog_ac_ct_CC+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test -n "$ac_ct_CC"; then ++else case e in #( ++ e) if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. + else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +@@ -5256,7 +5477,8 @@ + done + IFS=$as_save_IFS + +-fi ++fi ;; ++esac + fi + ac_ct_CC=$ac_cv_prog_ac_ct_CC + if test -n "$ac_ct_CC"; then +@@ -5285,10 +5507,10 @@ + fi + + +-test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error $? "no acceptable C compiler found in \$PATH +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } + + # Provide some information about the compiler. + printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +@@ -5360,8 +5582,8 @@ + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then : +- # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +-# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' ++ # Autoconf-2.13 could set the ac_cv_exeext variable to 'no'. ++# So ignore a value of 'no', otherwise this would lead to 'EXEEXT = no' + # in a Makefile. We should not override ac_cv_exeext if it was cached, + # so that the user can short-circuit this test for compilers unknown to + # Autoconf. +@@ -5381,7 +5603,7 @@ + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not +- # safe: cross compilers may not add the suffix if given an `-o' ++ # safe: cross compilers may not add the suffix if given an '-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. +@@ -5392,8 +5614,9 @@ + done + test "$ac_cv_exeext" = no && ac_cv_exeext= + +-else $as_nop +- ac_file='' ++else case e in #( ++ e) ac_file='' ;; ++esac + fi + if test -z "$ac_file" + then : +@@ -5402,13 +5625,14 @@ + printf "%s\n" "$as_me: failed program was:" >&5 + sed 's/^/| /' conftest.$ac_ext >&5 + +-{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error 77 "C compiler cannot create executables +-See \`config.log' for more details" "$LINENO" 5; } +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +-printf "%s\n" "yes" >&6; } ++See 'config.log' for more details" "$LINENO" 5; } ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 ++printf "%s\n" "yes" >&6; } ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 + printf %s "checking for C compiler default output file name... " >&6; } +@@ -5432,10 +5656,10 @@ + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then : +- # If both `conftest.exe' and `conftest' are `present' (well, observable) +-# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +-# work properly (i.e., refer to `conftest.exe'), while it won't with +-# `rm'. ++ # If both 'conftest.exe' and 'conftest' are 'present' (well, observable) ++# catch 'conftest.exe'. For instance with Cygwin, 'ls conftest' will ++# work properly (i.e., refer to 'conftest.exe'), while it won't with ++# 'rm'. + for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in +@@ -5445,11 +5669,12 @@ + * ) break;; + esac + done +-else $as_nop +- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++else case e in #( ++ e) { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error $? "cannot compute suffix of executables: cannot compile and link +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } ;; ++esac + fi + rm -f conftest conftest$ac_cv_exeext + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +@@ -5465,6 +5690,8 @@ + main (void) + { + FILE *f = fopen ("conftest.out", "w"); ++ if (!f) ++ return 1; + return ferror (f) || fclose (f) != 0; + + ; +@@ -5504,26 +5731,27 @@ + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else +- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error 77 "cannot run C compiled programs. +-If you meant to cross compile, use \`--host'. +-See \`config.log' for more details" "$LINENO" 5; } ++If you meant to cross compile, use '--host'. ++See 'config.log' for more details" "$LINENO" 5; } + fi + fi + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 + printf "%s\n" "$cross_compiling" >&6; } + +-rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ++rm -f conftest.$ac_ext conftest$ac_cv_exeext \ ++ conftest.o conftest.obj conftest.out + ac_clean_files=$ac_clean_files_save + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 + printf %s "checking for suffix of object files... " >&6; } + if test ${ac_cv_objext+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + int +@@ -5555,16 +5783,18 @@ + break;; + esac + done +-else $as_nop +- printf "%s\n" "$as_me: failed program was:" >&5 ++else case e in #( ++ e) printf "%s\n" "$as_me: failed program was:" >&5 + sed 's/^/| /' conftest.$ac_ext >&5 + +-{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error $? "cannot compute suffix of object files: cannot compile +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } ;; ++esac + fi +-rm -f conftest.$ac_cv_objext conftest.$ac_ext ++rm -f conftest.$ac_cv_objext conftest.$ac_ext ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 + printf "%s\n" "$ac_cv_objext" >&6; } +@@ -5575,8 +5805,8 @@ + if test ${ac_cv_c_compiler_gnu+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + int +@@ -5593,12 +5823,14 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_compiler_gnu=yes +-else $as_nop +- ac_compiler_gnu=no ++else case e in #( ++ e) ac_compiler_gnu=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_cv_c_compiler_gnu=$ac_compiler_gnu +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 + printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } +@@ -5616,8 +5848,8 @@ + if test ${ac_cv_prog_cc_g+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_save_c_werror_flag=$ac_c_werror_flag ++else case e in #( ++ e) ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" +@@ -5635,8 +5867,8 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_prog_cc_g=yes +-else $as_nop +- CFLAGS="" ++else case e in #( ++ e) CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + +@@ -5651,8 +5883,8 @@ + if ac_fn_c_try_compile "$LINENO" + then : + +-else $as_nop +- ac_c_werror_flag=$ac_save_c_werror_flag ++else case e in #( ++ e) ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ +@@ -5669,12 +5901,15 @@ + then : + ac_cv_prog_cc_g=yes + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ac_c_werror_flag=$ac_save_c_werror_flag ++ ac_c_werror_flag=$ac_save_c_werror_flag ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 + printf "%s\n" "$ac_cv_prog_cc_g" >&6; } +@@ -5701,8 +5936,8 @@ + if test ${ac_cv_prog_cc_c11+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_cv_prog_cc_c11=no ++else case e in #( ++ e) ac_cv_prog_cc_c11=no + ac_save_CC=$CC + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ +@@ -5719,25 +5954,28 @@ + test "x$ac_cv_prog_cc_c11" != "xno" && break + done + rm -f conftest.$ac_ext +-CC=$ac_save_CC ++CC=$ac_save_CC ;; ++esac + fi + + if test "x$ac_cv_prog_cc_c11" = xno + then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 + printf "%s\n" "unsupported" >&6; } +-else $as_nop +- if test "x$ac_cv_prog_cc_c11" = x ++else case e in #( ++ e) if test "x$ac_cv_prog_cc_c11" = x + then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 + printf "%s\n" "none needed" >&6; } +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 + printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } +- CC="$CC $ac_cv_prog_cc_c11" ++ CC="$CC $ac_cv_prog_cc_c11" ;; ++esac + fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 +- ac_prog_cc_stdc=c11 ++ ac_prog_cc_stdc=c11 ;; ++esac + fi + fi + if test x$ac_prog_cc_stdc = xno +@@ -5747,8 +5985,8 @@ + if test ${ac_cv_prog_cc_c99+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_cv_prog_cc_c99=no ++else case e in #( ++ e) ac_cv_prog_cc_c99=no + ac_save_CC=$CC + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ +@@ -5765,25 +6003,28 @@ + test "x$ac_cv_prog_cc_c99" != "xno" && break + done + rm -f conftest.$ac_ext +-CC=$ac_save_CC ++CC=$ac_save_CC ;; ++esac + fi + + if test "x$ac_cv_prog_cc_c99" = xno + then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 + printf "%s\n" "unsupported" >&6; } +-else $as_nop +- if test "x$ac_cv_prog_cc_c99" = x ++else case e in #( ++ e) if test "x$ac_cv_prog_cc_c99" = x + then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 + printf "%s\n" "none needed" >&6; } +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 + printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } +- CC="$CC $ac_cv_prog_cc_c99" ++ CC="$CC $ac_cv_prog_cc_c99" ;; ++esac + fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 +- ac_prog_cc_stdc=c99 ++ ac_prog_cc_stdc=c99 ;; ++esac + fi + fi + if test x$ac_prog_cc_stdc = xno +@@ -5793,8 +6034,8 @@ + if test ${ac_cv_prog_cc_c89+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_cv_prog_cc_c89=no ++else case e in #( ++ e) ac_cv_prog_cc_c89=no + ac_save_CC=$CC + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ +@@ -5811,25 +6052,28 @@ + test "x$ac_cv_prog_cc_c89" != "xno" && break + done + rm -f conftest.$ac_ext +-CC=$ac_save_CC ++CC=$ac_save_CC ;; ++esac + fi + + if test "x$ac_cv_prog_cc_c89" = xno + then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 + printf "%s\n" "unsupported" >&6; } +-else $as_nop +- if test "x$ac_cv_prog_cc_c89" = x ++else case e in #( ++ e) if test "x$ac_cv_prog_cc_c89" = x + then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 + printf "%s\n" "none needed" >&6; } +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 + printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } +- CC="$CC $ac_cv_prog_cc_c89" ++ CC="$CC $ac_cv_prog_cc_c89" ;; ++esac + fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 +- ac_prog_cc_stdc=c89 ++ ac_prog_cc_stdc=c89 ;; ++esac + fi + fi + +@@ -5854,8 +6098,8 @@ + if test ${ac_cv_prog_CPP+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- # Double quotes because $CC needs to be expanded ++else case e in #( ++ e) # Double quotes because $CC needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp + do + ac_preproc_ok=false +@@ -5873,9 +6117,10 @@ + if ac_fn_c_try_cpp "$LINENO" + then : + +-else $as_nop +- # Broken: fails on valid input. +-continue ++else case e in #( ++ e) # Broken: fails on valid input. ++continue ;; ++esac + fi + rm -f conftest.err conftest.i conftest.$ac_ext + +@@ -5889,15 +6134,16 @@ + then : + # Broken: success on invalid input. + continue +-else $as_nop +- # Passes both tests. ++else case e in #( ++ e) # Passes both tests. + ac_preproc_ok=: +-break ++break ;; ++esac + fi + rm -f conftest.err conftest.i conftest.$ac_ext + + done +-# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. ++# Because of 'break', _AC_PREPROC_IFELSE's cleaning code was skipped. + rm -f conftest.i conftest.err conftest.$ac_ext + if $ac_preproc_ok + then : +@@ -5906,7 +6152,8 @@ + + done + ac_cv_prog_CPP=$CPP +- ++ ;; ++esac + fi + CPP=$ac_cv_prog_CPP + else +@@ -5929,9 +6176,10 @@ + if ac_fn_c_try_cpp "$LINENO" + then : + +-else $as_nop +- # Broken: fails on valid input. +-continue ++else case e in #( ++ e) # Broken: fails on valid input. ++continue ;; ++esac + fi + rm -f conftest.err conftest.i conftest.$ac_ext + +@@ -5945,24 +6193,26 @@ + then : + # Broken: success on invalid input. + continue +-else $as_nop +- # Passes both tests. ++else case e in #( ++ e) # Passes both tests. + ac_preproc_ok=: +-break ++break ;; ++esac + fi + rm -f conftest.err conftest.i conftest.$ac_ext + + done +-# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. ++# Because of 'break', _AC_PREPROC_IFELSE's cleaning code was skipped. + rm -f conftest.i conftest.err conftest.$ac_ext + if $ac_preproc_ok + then : + +-else $as_nop +- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++else case e in #( ++ e) { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } ;; ++esac + fi + + ac_ext=c +@@ -5976,8 +6226,8 @@ + if test ${ac_cv_path_GREP+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test -z "$GREP"; then ++else case e in #( ++ e) if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +@@ -5996,9 +6246,10 @@ + as_fn_executable_p "$ac_path_GREP" || continue + # Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +-case `"$ac_path_GREP" --version 2>&1` in ++case `"$ac_path_GREP" --version 2>&1` in #( + *GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; ++#( + *) + ac_count=0 + printf %s 0123456789 >"conftest.in" +@@ -6033,7 +6284,8 @@ + else + ac_cv_path_GREP=$GREP + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 + printf "%s\n" "$ac_cv_path_GREP" >&6; } +@@ -6045,8 +6297,8 @@ + if test ${ac_cv_path_SED+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ ++else case e in #( ++ e) ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done +@@ -6071,9 +6323,10 @@ + as_fn_executable_p "$ac_path_SED" || continue + # Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +-case `"$ac_path_SED" --version 2>&1` in ++case `"$ac_path_SED" --version 2>&1` in #( + *GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; ++#( + *) + ac_count=0 + printf %s 0123456789 >"conftest.in" +@@ -6108,7 +6361,8 @@ + else + ac_cv_path_SED=$SED + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 + printf "%s\n" "$ac_cv_path_SED" >&6; } +@@ -6120,8 +6374,8 @@ + if test ${ac_cv_path_EGREP+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 ++else case e in #( ++ e) if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then +@@ -6143,9 +6397,10 @@ + as_fn_executable_p "$ac_path_EGREP" || continue + # Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +-case `"$ac_path_EGREP" --version 2>&1` in ++case `"$ac_path_EGREP" --version 2>&1` in #( + *GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; ++#( + *) + ac_count=0 + printf %s 0123456789 >"conftest.in" +@@ -6181,12 +6436,15 @@ + ac_cv_path_EGREP=$EGREP + fi + +- fi ++ fi ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 + printf "%s\n" "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + ++ EGREP_TRADITIONAL=$EGREP ++ ac_cv_path_EGREP_TRADITIONAL=$EGREP + + + CC_BASENAME=$(expr "//$CC" : '.*/\(.*\)') +@@ -6196,8 +6454,8 @@ + if test ${ac_cv_cc_name+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat > conftest.c <&5 + printf "%s\n" "$ac_cv_cc_name" >&6; } +@@ -6275,8 +6534,8 @@ + if test ${ac_cv_safe_to_define___extensions__+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + # define __EXTENSIONS__ 1 +@@ -6292,10 +6551,12 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_safe_to_define___extensions__=yes +-else $as_nop +- ac_cv_safe_to_define___extensions__=no ++else case e in #( ++ e) ac_cv_safe_to_define___extensions__=no ;; ++esac + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 + printf "%s\n" "$ac_cv_safe_to_define___extensions__" >&6; } +@@ -6305,8 +6566,8 @@ + if test ${ac_cv_should_define__xopen_source+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_cv_should_define__xopen_source=no ++else case e in #( ++ e) ac_cv_should_define__xopen_source=no + if test $ac_cv_header_wchar_h = yes + then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -6325,8 +6586,8 @@ + if ac_fn_c_try_compile "$LINENO" + then : + +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #define _XOPEN_SOURCE 500 +@@ -6344,10 +6605,12 @@ + then : + ac_cv_should_define__xopen_source=yes + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +-fi ++fi ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_should_define__xopen_source" >&5 + printf "%s\n" "$ac_cv_should_define__xopen_source" >&6; } +@@ -6372,6 +6635,8 @@ + + printf "%s\n" "#define __STDC_WANT_IEC_60559_DFP_EXT__ 1" >>confdefs.h + ++ printf "%s\n" "#define __STDC_WANT_IEC_60559_EXT__ 1" >>confdefs.h ++ + printf "%s\n" "#define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1" >>confdefs.h + + printf "%s\n" "#define __STDC_WANT_IEC_60559_TYPES_EXT__ 1" >>confdefs.h +@@ -6391,8 +6656,9 @@ + + printf "%s\n" "#define _POSIX_1_SOURCE 2" >>confdefs.h + +-else $as_nop +- MINIX= ++else case e in #( ++ e) MINIX= ;; ++esac + fi + if test $ac_cv_safe_to_define___extensions__ = yes + then : +@@ -6412,8 +6678,8 @@ + if test ${ac_cv_gcc_compat+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #if !defined(__GNUC__) +@@ -6426,10 +6692,12 @@ + if ac_fn_c_try_cpp "$LINENO" + then : + ac_cv_gcc_compat=yes +-else $as_nop +- ac_cv_gcc_compat=no ++else case e in #( ++ e) ac_cv_gcc_compat=no ;; ++esac + fi +-rm -f conftest.err conftest.i conftest.$ac_ext ++rm -f conftest.err conftest.i conftest.$ac_ext ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_gcc_compat" >&5 + printf "%s\n" "$ac_cv_gcc_compat" >&6; } +@@ -6448,8 +6716,8 @@ + if test ${ac_cv_path_CXX+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- case $CXX in ++else case e in #( ++ e) case $CXX in + [\\/]* | ?:[\\/]*) + ac_cv_path_CXX="$CXX" # Let the user override the test with a path. + ;; +@@ -6474,6 +6742,7 @@ + IFS=$as_save_IFS + + ;; ++esac ;; + esac + fi + CXX=$ac_cv_path_CXX +@@ -6496,8 +6765,8 @@ + if test ${ac_cv_path_ac_pt_CXX+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- case $ac_pt_CXX in ++else case e in #( ++ e) case $ac_pt_CXX in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_CXX="$ac_pt_CXX" # Let the user override the test with a path. + ;; +@@ -6522,6 +6791,7 @@ + IFS=$as_save_IFS + + ;; ++esac ;; + esac + fi + ac_pt_CXX=$ac_cv_path_ac_pt_CXX +@@ -6556,8 +6826,8 @@ + if test ${ac_cv_path_CXX+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- case $CXX in ++else case e in #( ++ e) case $CXX in + [\\/]* | ?:[\\/]*) + ac_cv_path_CXX="$CXX" # Let the user override the test with a path. + ;; +@@ -6582,6 +6852,7 @@ + IFS=$as_save_IFS + + ;; ++esac ;; + esac + fi + CXX=$ac_cv_path_CXX +@@ -6604,8 +6875,8 @@ + if test ${ac_cv_path_ac_pt_CXX+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- case $ac_pt_CXX in ++else case e in #( ++ e) case $ac_pt_CXX in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_CXX="$ac_pt_CXX" # Let the user override the test with a path. + ;; +@@ -6630,6 +6901,7 @@ + IFS=$as_save_IFS + + ;; ++esac ;; + esac + fi + ac_pt_CXX=$ac_cv_path_ac_pt_CXX +@@ -6664,8 +6936,8 @@ + if test ${ac_cv_path_CXX+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- case $CXX in ++else case e in #( ++ e) case $CXX in + [\\/]* | ?:[\\/]*) + ac_cv_path_CXX="$CXX" # Let the user override the test with a path. + ;; +@@ -6690,6 +6962,7 @@ + IFS=$as_save_IFS + + ;; ++esac ;; + esac + fi + CXX=$ac_cv_path_CXX +@@ -6712,8 +6985,8 @@ + if test ${ac_cv_path_ac_pt_CXX+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- case $ac_pt_CXX in ++else case e in #( ++ e) case $ac_pt_CXX in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_CXX="$ac_pt_CXX" # Let the user override the test with a path. + ;; +@@ -6738,6 +7011,7 @@ + IFS=$as_save_IFS + + ;; ++esac ;; + esac + fi + ac_pt_CXX=$ac_cv_path_ac_pt_CXX +@@ -6772,8 +7046,8 @@ + if test ${ac_cv_path_CXX+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- case $CXX in ++else case e in #( ++ e) case $CXX in + [\\/]* | ?:[\\/]*) + ac_cv_path_CXX="$CXX" # Let the user override the test with a path. + ;; +@@ -6798,6 +7072,7 @@ + IFS=$as_save_IFS + + ;; ++esac ;; + esac + fi + CXX=$ac_cv_path_CXX +@@ -6820,8 +7095,8 @@ + if test ${ac_cv_path_ac_pt_CXX+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- case $ac_pt_CXX in ++else case e in #( ++ e) case $ac_pt_CXX in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_CXX="$ac_pt_CXX" # Let the user override the test with a path. + ;; +@@ -6846,6 +7121,7 @@ + IFS=$as_save_IFS + + ;; ++esac ;; + esac + fi + ac_pt_CXX=$ac_cv_path_ac_pt_CXX +@@ -6890,8 +7166,8 @@ + if test ${ac_cv_prog_CXX+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test -n "$CXX"; then ++else case e in #( ++ e) if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. + else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +@@ -6913,7 +7189,8 @@ + done + IFS=$as_save_IFS + +-fi ++fi ;; ++esac + fi + CXX=$ac_cv_prog_CXX + if test -n "$CXX"; then +@@ -6939,8 +7216,8 @@ + if test ${ac_cv_prog_ac_ct_CXX+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test -n "$ac_ct_CXX"; then ++else case e in #( ++ e) if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. + else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +@@ -6962,7 +7239,8 @@ + done + IFS=$as_save_IFS + +-fi ++fi ;; ++esac + fi + ac_ct_CXX=$ac_cv_prog_ac_ct_CXX + if test -n "$ac_ct_CXX"; then +@@ -7030,6 +7308,10 @@ + MULTIARCH="" ;; #( + iOS) : + MULTIARCH="" ;; #( ++ tvOS) : ++ MULTIARCH="" ;; #( ++ watchOS) : ++ MULTIARCH="" ;; #( + FreeBSD*) : + MULTIARCH="" ;; #( + *) : +@@ -7050,7 +7332,7 @@ + printf "%s\n" "$MULTIARCH" >&6; } + + case $ac_sys_system in #( +- iOS) : ++ iOS|tvOS|watchOS) : + SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f2` ;; #( + *) : + SOABI_PLATFORM=$PLATFORM_TRIPLET +@@ -7101,6 +7383,14 @@ + PY_SUPPORT_TIER=3 ;; #( + aarch64-apple-ios*/clang) : + PY_SUPPORT_TIER=3 ;; #( ++ aarch64-apple-tvos*-simulator/clang) : ++ PY_SUPPORT_TIER=3 ;; #( ++ aarch64-apple-tvos*/clang) : ++ PY_SUPPORT_TIER=3 ;; #( ++ aarch64-apple-watchos*-simulator/clang) : ++ PY_SUPPORT_TIER=3 ;; #( ++ arm64_32-apple-watchos*/clang) : ++ PY_SUPPORT_TIER=3 ;; #( + aarch64-*-linux-android/clang) : + PY_SUPPORT_TIER=3 ;; #( + x86_64-*-linux-android/clang) : +@@ -7136,8 +7426,8 @@ + if test ${ac_cv_wl_no_as_needed+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + save_LDFLAGS="$LDFLAGS" + as_fn_append LDFLAGS " -Wl,--no-as-needed" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -7155,14 +7445,16 @@ + then : + NO_AS_NEEDED="-Wl,--no-as-needed" + ac_cv_wl_no_as_needed=yes +-else $as_nop +- NO_AS_NEEDED="" +- ac_cv_wl_no_as_needed=no ++else case e in #( ++ e) NO_AS_NEEDED="" ++ ac_cv_wl_no_as_needed=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_wl_no_as_needed" >&5 + printf "%s\n" "$ac_cv_wl_no_as_needed" >&6; } +@@ -7235,10 +7527,11 @@ + ;; + esac + +-else $as_nop +- ++else case e in #( ++ e) + enable_wasm_dynamic_linking=missing +- ++ ;; ++esac + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_wasm_dynamic_linking" >&5 +@@ -7260,10 +7553,11 @@ + ;; + esac + +-else $as_nop +- ++else case e in #( ++ e) + enable_wasm_pthreads=missing +- ++ ;; ++esac + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_wasm_pthreads" >&5 +@@ -7286,8 +7580,8 @@ + ;; + esac + +-else $as_nop +- ++else case e in #( ++ e) + case $ac_sys_system in #( + Emscripten) : + EXEEXT=.mjs ;; #( +@@ -7297,7 +7591,8 @@ + EXEEXT= + ;; + esac +- ++ ;; ++esac + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $EXEEXT" >&5 +@@ -7473,9 +7768,10 @@ + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 + printf "%s\n" "yes" >&6; }; + fi +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +-printf "%s\n" "yes" >&6; } ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 ++printf "%s\n" "yes" >&6; } ;; ++esac + fi + + +@@ -7498,8 +7794,9 @@ + if ac_fn_c_try_link "$LINENO" + then : + +-else $as_nop +- enable_profiling=no ++else case e in #( ++ e) enable_profiling=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +@@ -7530,7 +7827,7 @@ + case $ac_sys_system in + Darwin) + LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)';; +- iOS) ++ iOS|tvOS|watchOS) + LDLIBRARY='$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';; + *) + as_fn_error $? "Unknown platform for framework build" "$LINENO" 5;; +@@ -7596,7 +7893,7 @@ + BLDLIBRARY='-L. -lpython$(LDVERSION)' + RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}} + ;; +- iOS) ++ iOS|tvOS|watchOS) + LDLIBRARY='libpython$(LDVERSION).dylib' + ;; + AIX*) +@@ -7637,8 +7934,8 @@ + if test ${ac_cv_path_NODE+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- case $NODE in ++else case e in #( ++ e) case $NODE in + [\\/]* | ?:[\\/]*) + ac_cv_path_NODE="$NODE" # Let the user override the test with a path. + ;; +@@ -7663,6 +7960,7 @@ + IFS=$as_save_IFS + + ;; ++esac ;; + esac + fi + NODE=$ac_cv_path_NODE +@@ -7685,8 +7983,8 @@ + if test ${ac_cv_path_ac_pt_NODE+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- case $ac_pt_NODE in ++else case e in #( ++ e) case $ac_pt_NODE in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_NODE="$ac_pt_NODE" # Let the user override the test with a path. + ;; +@@ -7711,6 +8009,7 @@ + IFS=$as_save_IFS + + ;; ++esac ;; + esac + fi + ac_pt_NODE=$ac_cv_path_ac_pt_NODE +@@ -7795,8 +8094,8 @@ + if test ${ac_cv_prog_AR+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test -n "$AR"; then ++else case e in #( ++ e) if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. + else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +@@ -7818,7 +8117,8 @@ + done + IFS=$as_save_IFS + +-fi ++fi ;; ++esac + fi + AR=$ac_cv_prog_AR + if test -n "$AR"; then +@@ -7844,8 +8144,8 @@ + if test ${ac_cv_prog_ac_ct_AR+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test -n "$ac_ct_AR"; then ++else case e in #( ++ e) if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. + else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +@@ -7867,7 +8167,8 @@ + done + IFS=$as_save_IFS + +-fi ++fi ;; ++esac + fi + ac_ct_AR=$ac_cv_prog_ac_ct_AR + if test -n "$ac_ct_AR"; then +@@ -7932,8 +8233,8 @@ + if test ${ac_cv_path_install+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++else case e in #( ++ e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR + for as_dir in $PATH + do + IFS=$as_save_IFS +@@ -7987,7 +8288,8 @@ + IFS=$as_save_IFS + + rm -rf conftest.one conftest.two conftest.dir +- ++ ;; ++esac + fi + if test ${ac_cv_path_install+y}; then + INSTALL=$ac_cv_path_install +@@ -8017,8 +8319,8 @@ + if test ${ac_cv_path_mkdir+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++else case e in #( ++ e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR + for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin + do + IFS=$as_save_IFS +@@ -8032,7 +8334,7 @@ + as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext" || continue + case `"$as_dir$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir ('*'coreutils) '* | \ +- 'BusyBox '* | \ ++ *'BusyBox '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir$ac_prog$ac_exec_ext + break 3;; +@@ -8041,18 +8343,17 @@ + done + done + IFS=$as_save_IFS +- ++ ;; ++esac + fi + + test -d ./--version && rmdir ./--version + if test ${ac_cv_path_mkdir+y}; then + MKDIR_P="$ac_cv_path_mkdir -p" + else +- # As a last resort, use the slow shell script. Don't cache a +- # value for MKDIR_P within a source directory, because that will +- # break other packages using the cache if that directory is +- # removed, or if the value is a relative name. +- MKDIR_P="$ac_install_sh -d" ++ # As a last resort, use plain mkdir -p, ++ # in the hope it doesn't have the bugs of ancient mkdir. ++ MKDIR_P='mkdir -p' + fi + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +@@ -8084,12 +8385,14 @@ + enableval=$enable_gil; if test "x$enable_gil" = xyes + then : + disable_gil=no +-else $as_nop +- disable_gil=yes ++else case e in #( ++ e) disable_gil=yes ;; ++esac + fi +-else $as_nop +- disable_gil=no +- ++else case e in #( ++ e) disable_gil=no ++ ;; ++esac + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $disable_gil" >&5 +@@ -8125,9 +8428,10 @@ + else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + printf "%s\n" "no" >&6; }; Py_DEBUG='false' + fi +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +-printf "%s\n" "no" >&6; } ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++printf "%s\n" "no" >&6; } ;; ++esac + fi + + +@@ -8140,9 +8444,10 @@ + if test ${with_trace_refs+y} + then : + withval=$with_trace_refs; +-else $as_nop +- with_trace_refs=no +- ++else case e in #( ++ e) with_trace_refs=no ++ ;; ++esac + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_trace_refs" >&5 +@@ -8167,9 +8472,10 @@ + if test ${enable_pystats+y} + then : + enableval=$enable_pystats; +-else $as_nop +- enable_pystats=no +- ++else case e in #( ++ e) enable_pystats=no ++ ;; ++esac + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_pystats" >&5 +@@ -8219,8 +8525,9 @@ + if test ${enable_experimental_jit+y} + then : + enableval=$enable_experimental_jit; +-else $as_nop +- enable_experimental_jit=no ++else case e in #( ++ e) enable_experimental_jit=no ;; ++esac + fi + + case $enable_experimental_jit in +@@ -8234,20 +8541,22 @@ + if ${tier2_flags:+false} : + then : + +-else $as_nop +- as_fn_append CFLAGS_NODIST " $tier2_flags" ++else case e in #( ++ e) as_fn_append CFLAGS_NODIST " $tier2_flags" ;; ++esac + fi + if ${jit_flags:+false} : + then : + +-else $as_nop +- as_fn_append CFLAGS_NODIST " $jit_flags" ++else case e in #( ++ e) as_fn_append CFLAGS_NODIST " $jit_flags" + REGEN_JIT_COMMAND="\$(PYTHON_FOR_REGEN) \$(srcdir)/Tools/jit/build.py $host" + JIT_STENCILS_H="jit_stencils.h" + if test "x$Py_DEBUG" = xtrue + then : + as_fn_append REGEN_JIT_COMMAND " --debug" +-fi ++fi ;; ++esac + fi + + +@@ -8274,9 +8583,10 @@ + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + printf "%s\n" "no" >&6; }; + fi +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +-printf "%s\n" "no" >&6; } ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++printf "%s\n" "no" >&6; } ;; ++esac + fi + + +@@ -8296,8 +8606,8 @@ + if test ${ax_cv_check_cflags__Werror__fno_semantic_interposition+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + ax_check_save_flags=$CFLAGS + CFLAGS="$CFLAGS -Werror -fno-semantic-interposition" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -8314,11 +8624,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ax_cv_check_cflags__Werror__fno_semantic_interposition=yes +-else $as_nop +- ax_cv_check_cflags__Werror__fno_semantic_interposition=no ++else case e in #( ++ e) ax_cv_check_cflags__Werror__fno_semantic_interposition=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- CFLAGS=$ax_check_save_flags ++ CFLAGS=$ax_check_save_flags ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror__fno_semantic_interposition" >&5 + printf "%s\n" "$ax_cv_check_cflags__Werror__fno_semantic_interposition" >&6; } +@@ -8328,8 +8640,9 @@ + CFLAGS_NODIST="$CFLAGS_NODIST -fno-semantic-interposition" + LDFLAGS_NODIST="$LDFLAGS_NODIST -fno-semantic-interposition" + +-else $as_nop +- : ++else case e in #( ++ e) : ;; ++esac + fi + + +@@ -8416,9 +8729,10 @@ + ;; + esac + +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +-printf "%s\n" "no" >&6; } ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++printf "%s\n" "no" >&6; } ;; ++esac + fi + + if test "$Py_LTO" = 'true' ; then +@@ -8430,8 +8744,8 @@ + if test ${ax_cv_check_cflags___flto_thin+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + ax_check_save_flags=$CFLAGS + CFLAGS="$CFLAGS -flto=thin" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -8448,19 +8762,22 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ax_cv_check_cflags___flto_thin=yes +-else $as_nop +- ax_cv_check_cflags___flto_thin=no ++else case e in #( ++ e) ax_cv_check_cflags___flto_thin=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- CFLAGS=$ax_check_save_flags ++ CFLAGS=$ax_check_save_flags ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___flto_thin" >&5 + printf "%s\n" "$ax_cv_check_cflags___flto_thin" >&6; } + if test "x$ax_cv_check_cflags___flto_thin" = xyes + then : + LDFLAGS_NOLTO="-flto=thin" +-else $as_nop +- LDFLAGS_NOLTO="-flto" ++else case e in #( ++ e) LDFLAGS_NOLTO="-flto" ;; ++esac + fi + + +@@ -8472,8 +8789,8 @@ + if test ${ac_cv_path_LLVM_AR+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- case $LLVM_AR in ++else case e in #( ++ e) case $LLVM_AR in + [\\/]* | ?:[\\/]*) + ac_cv_path_LLVM_AR="$LLVM_AR" # Let the user override the test with a path. + ;; +@@ -8498,6 +8815,7 @@ + IFS=$as_save_IFS + + ;; ++esac ;; + esac + fi + LLVM_AR=$ac_cv_path_LLVM_AR +@@ -8520,8 +8838,8 @@ + if test ${ac_cv_path_ac_pt_LLVM_AR+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- case $ac_pt_LLVM_AR in ++else case e in #( ++ e) case $ac_pt_LLVM_AR in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_LLVM_AR="$ac_pt_LLVM_AR" # Let the user override the test with a path. + ;; +@@ -8546,6 +8864,7 @@ + IFS=$as_save_IFS + + ;; ++esac ;; + esac + fi + ac_pt_LLVM_AR=$ac_cv_path_ac_pt_LLVM_AR +@@ -8610,8 +8929,8 @@ + if test ${ax_cv_check_cflags___flto_thin+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + ax_check_save_flags=$CFLAGS + CFLAGS="$CFLAGS -flto=thin" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -8628,11 +8947,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ax_cv_check_cflags___flto_thin=yes +-else $as_nop +- ax_cv_check_cflags___flto_thin=no ++else case e in #( ++ e) ax_cv_check_cflags___flto_thin=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- CFLAGS=$ax_check_save_flags ++ CFLAGS=$ax_check_save_flags ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___flto_thin" >&5 + printf "%s\n" "$ax_cv_check_cflags___flto_thin" >&6; } +@@ -8642,12 +8963,13 @@ + LTOFLAGS="-flto=thin -Wl,-export_dynamic -Wl,-object_path_lto,\"\$@\".lto" + LTOCFLAGS="-flto=thin" + +-else $as_nop +- ++else case e in #( ++ e) + LTOFLAGS="-flto -Wl,-export_dynamic -Wl,-object_path_lto,\"\$@\".lto" + LTOCFLAGS="-flto" + +- ++ ;; ++esac + fi + + else +@@ -8664,8 +8986,8 @@ + if test ${ax_cv_check_cflags___flto_thin+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + ax_check_save_flags=$CFLAGS + CFLAGS="$CFLAGS -flto=thin" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -8682,19 +9004,22 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ax_cv_check_cflags___flto_thin=yes +-else $as_nop +- ax_cv_check_cflags___flto_thin=no ++else case e in #( ++ e) ax_cv_check_cflags___flto_thin=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- CFLAGS=$ax_check_save_flags ++ CFLAGS=$ax_check_save_flags ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___flto_thin" >&5 + printf "%s\n" "$ax_cv_check_cflags___flto_thin" >&6; } + if test "x$ax_cv_check_cflags___flto_thin" = xyes + then : + LTOFLAGS="-flto=thin" +-else $as_nop +- LTOFLAGS="-flto" ++else case e in #( ++ e) LTOFLAGS="-flto" ;; ++esac + fi + + else +@@ -8754,8 +9079,8 @@ + if test ${ac_cv_path_LLVM_PROFDATA+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- case $LLVM_PROFDATA in ++else case e in #( ++ e) case $LLVM_PROFDATA in + [\\/]* | ?:[\\/]*) + ac_cv_path_LLVM_PROFDATA="$LLVM_PROFDATA" # Let the user override the test with a path. + ;; +@@ -8780,6 +9105,7 @@ + IFS=$as_save_IFS + + ;; ++esac ;; + esac + fi + LLVM_PROFDATA=$ac_cv_path_LLVM_PROFDATA +@@ -8802,8 +9128,8 @@ + if test ${ac_cv_path_ac_pt_LLVM_PROFDATA+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- case $ac_pt_LLVM_PROFDATA in ++else case e in #( ++ e) case $ac_pt_LLVM_PROFDATA in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_LLVM_PROFDATA="$ac_pt_LLVM_PROFDATA" # Let the user override the test with a path. + ;; +@@ -8828,6 +9154,7 @@ + IFS=$as_save_IFS + + ;; ++esac ;; + esac + fi + ac_pt_LLVM_PROFDATA=$ac_cv_path_ac_pt_LLVM_PROFDATA +@@ -8924,9 +9251,10 @@ + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + printf "%s\n" "no" >&6; }; + fi +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +-printf "%s\n" "no" >&6; } ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++printf "%s\n" "no" >&6; } ;; ++esac + fi + + +@@ -8943,8 +9271,8 @@ + if test ${ax_cv_check_cflags___fno_reorder_blocks_and_partition+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + ax_check_save_flags=$CFLAGS + CFLAGS="$CFLAGS -fno-reorder-blocks-and-partition" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -8961,11 +9289,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ax_cv_check_cflags___fno_reorder_blocks_and_partition=yes +-else $as_nop +- ax_cv_check_cflags___fno_reorder_blocks_and_partition=no ++else case e in #( ++ e) ax_cv_check_cflags___fno_reorder_blocks_and_partition=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- CFLAGS=$ax_check_save_flags ++ CFLAGS=$ax_check_save_flags ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___fno_reorder_blocks_and_partition" >&5 + printf "%s\n" "$ax_cv_check_cflags___fno_reorder_blocks_and_partition" >&6; } +@@ -8974,8 +9304,9 @@ + + CFLAGS_NODIST="$CFLAGS_NODIST -fno-reorder-blocks-and-partition" + +-else $as_nop +- : ++else case e in #( ++ e) : ;; ++esac + fi + + +@@ -8995,8 +9326,8 @@ + if test ${ac_cv_path_LLVM_BOLT+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- case $LLVM_BOLT in ++else case e in #( ++ e) case $LLVM_BOLT in + [\\/]* | ?:[\\/]*) + ac_cv_path_LLVM_BOLT="$LLVM_BOLT" # Let the user override the test with a path. + ;; +@@ -9021,6 +9352,7 @@ + IFS=$as_save_IFS + + ;; ++esac ;; + esac + fi + LLVM_BOLT=$ac_cv_path_LLVM_BOLT +@@ -9043,8 +9375,8 @@ + if test ${ac_cv_path_ac_pt_LLVM_BOLT+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- case $ac_pt_LLVM_BOLT in ++else case e in #( ++ e) case $ac_pt_LLVM_BOLT in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_LLVM_BOLT="$ac_pt_LLVM_BOLT" # Let the user override the test with a path. + ;; +@@ -9069,6 +9401,7 @@ + IFS=$as_save_IFS + + ;; ++esac ;; + esac + fi + ac_pt_LLVM_BOLT=$ac_cv_path_ac_pt_LLVM_BOLT +@@ -9112,8 +9445,8 @@ + if test ${ac_cv_path_MERGE_FDATA+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- case $MERGE_FDATA in ++else case e in #( ++ e) case $MERGE_FDATA in + [\\/]* | ?:[\\/]*) + ac_cv_path_MERGE_FDATA="$MERGE_FDATA" # Let the user override the test with a path. + ;; +@@ -9138,6 +9471,7 @@ + IFS=$as_save_IFS + + ;; ++esac ;; + esac + fi + MERGE_FDATA=$ac_cv_path_MERGE_FDATA +@@ -9160,8 +9494,8 @@ + if test ${ac_cv_path_ac_pt_MERGE_FDATA+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- case $ac_pt_MERGE_FDATA in ++else case e in #( ++ e) case $ac_pt_MERGE_FDATA in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_MERGE_FDATA="$ac_pt_MERGE_FDATA" # Let the user override the test with a path. + ;; +@@ -9186,6 +9520,7 @@ + IFS=$as_save_IFS + + ;; ++esac ;; + esac + fi + ac_pt_MERGE_FDATA=$ac_cv_path_ac_pt_MERGE_FDATA +@@ -9271,8 +9606,8 @@ + if test ${ac_cv_cc_supports_fstrict_overflow+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + int +@@ -9286,12 +9621,14 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_cc_supports_fstrict_overflow=yes +-else $as_nop +- ac_cv_cc_supports_fstrict_overflow=no +- ++else case e in #( ++ e) ac_cv_cc_supports_fstrict_overflow=no ++ ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cc_supports_fstrict_overflow" >&5 + printf "%s\n" "$ac_cv_cc_supports_fstrict_overflow" >&6; } +@@ -9301,9 +9638,10 @@ + then : + STRICT_OVERFLOW_CFLAGS="-fstrict-overflow" + NO_STRICT_OVERFLOW_CFLAGS="-fno-strict-overflow" +-else $as_nop +- STRICT_OVERFLOW_CFLAGS="" +- NO_STRICT_OVERFLOW_CFLAGS="" ++else case e in #( ++ e) STRICT_OVERFLOW_CFLAGS="" ++ NO_STRICT_OVERFLOW_CFLAGS="" ;; ++esac + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-strict-overflow" >&5 +@@ -9319,9 +9657,10 @@ + printf "%s\n" "$as_me: WARNING: --with-strict-overflow=yes requires a compiler that supports -fstrict-overflow" >&2;} + fi + +-else $as_nop +- with_strict_overflow=no +- ++else case e in #( ++ e) with_strict_overflow=no ++ ;; ++esac + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_strict_overflow" >&5 +@@ -9335,8 +9674,8 @@ + if test ${ac_cv_cc_supports_og+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + +@@ -9354,13 +9693,15 @@ + + ac_cv_cc_supports_og=yes + +-else $as_nop +- ++else case e in #( ++ e) + ac_cv_cc_supports_og=no +- ++ ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cc_supports_og" >&5 + printf "%s\n" "$ac_cv_cc_supports_og" >&6; } +@@ -9426,8 +9767,9 @@ + if test "x$Py_DEBUG" = xyes + then : + wasm_debug=yes +-else $as_nop +- wasm_debug=no ++else case e in #( ++ e) wasm_debug=no ;; ++esac + fi + + as_fn_append LINKFORSHARED " -sALLOW_MEMORY_GROWTH -sINITIAL_MEMORY=20971520" +@@ -9436,7 +9778,7 @@ + + as_fn_append LINKFORSHARED " -sFORCE_FILESYSTEM -lidbfs.js -lnodefs.js -lproxyfs.js -lworkerfs.js" + as_fn_append LINKFORSHARED " -sEXPORTED_RUNTIME_METHODS=FS,callMain,ENV" +- as_fn_append LINKFORSHARED " -sEXPORTED_FUNCTIONS=_main,_Py_Version" ++ as_fn_append LINKFORSHARED " -sEXPORTED_FUNCTIONS=_main,_Py_Version,__PyRuntime,__PyEM_EMSCRIPTEN_COUNT_ARGS_OFFSET" + as_fn_append LINKFORSHARED " -sSTACK_SIZE=5MB" + + if test "x$enable_wasm_dynamic_linking" = xyes +@@ -9463,10 +9805,11 @@ + as_fn_append LDFLAGS_NODIST " -sASSERTIONS" + as_fn_append LINKFORSHARED " $WASM_LINKFORSHARED_DEBUG" + +-else $as_nop +- ++else case e in #( ++ e) + as_fn_append LINKFORSHARED " -O2 -g0" +- ++ ;; ++esac + fi + ;; #( + WASI) : +@@ -9539,8 +9882,9 @@ + if test "x$with_strict_overflow" = xyes + then : + BASECFLAGS="$BASECFLAGS $STRICT_OVERFLOW_CFLAGS" +-else $as_nop +- BASECFLAGS="$BASECFLAGS $NO_STRICT_OVERFLOW_CFLAGS" ++else case e in #( ++ e) BASECFLAGS="$BASECFLAGS $NO_STRICT_OVERFLOW_CFLAGS" ;; ++esac + fi + + # Enable flags that warn and protect for potential security vulnerabilities. +@@ -9554,11 +9898,13 @@ + enableval=$enable_safety; if test "x$disable_safety" = xyes + then : + enable_safety=no +-else $as_nop +- enable_safety=yes ++else case e in #( ++ e) enable_safety=yes ;; ++esac + fi +-else $as_nop +- enable_safety=no ++else case e in #( ++ e) enable_safety=no ;; ++esac + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_safety" >&5 +@@ -9571,8 +9917,8 @@ + if test ${ax_cv_check_cflags__Werror__fstack_protector_strong+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + ax_check_save_flags=$CFLAGS + CFLAGS="$CFLAGS -Werror -fstack-protector-strong" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -9589,20 +9935,23 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ax_cv_check_cflags__Werror__fstack_protector_strong=yes +-else $as_nop +- ax_cv_check_cflags__Werror__fstack_protector_strong=no ++else case e in #( ++ e) ax_cv_check_cflags__Werror__fstack_protector_strong=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- CFLAGS=$ax_check_save_flags ++ CFLAGS=$ax_check_save_flags ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror__fstack_protector_strong" >&5 + printf "%s\n" "$ax_cv_check_cflags__Werror__fstack_protector_strong" >&6; } + if test "x$ax_cv_check_cflags__Werror__fstack_protector_strong" = xyes + then : + CFLAGS_NODIST="$CFLAGS_NODIST -fstack-protector-strong" +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -fstack-protector-strong not supported" >&5 +-printf "%s\n" "$as_me: WARNING: -fstack-protector-strong not supported" >&2;} ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -fstack-protector-strong not supported" >&5 ++printf "%s\n" "$as_me: WARNING: -fstack-protector-strong not supported" >&2;} ;; ++esac + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -Wtrampolines" >&5 +@@ -9610,8 +9959,8 @@ + if test ${ax_cv_check_cflags__Werror__Wtrampolines+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + ax_check_save_flags=$CFLAGS + CFLAGS="$CFLAGS -Werror -Wtrampolines" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -9628,20 +9977,23 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ax_cv_check_cflags__Werror__Wtrampolines=yes +-else $as_nop +- ax_cv_check_cflags__Werror__Wtrampolines=no ++else case e in #( ++ e) ax_cv_check_cflags__Werror__Wtrampolines=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- CFLAGS=$ax_check_save_flags ++ CFLAGS=$ax_check_save_flags ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror__Wtrampolines" >&5 + printf "%s\n" "$ax_cv_check_cflags__Werror__Wtrampolines" >&6; } + if test "x$ax_cv_check_cflags__Werror__Wtrampolines" = xyes + then : + CFLAGS_NODIST="$CFLAGS_NODIST -Wtrampolines" +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -Wtrampolines not supported" >&5 +-printf "%s\n" "$as_me: WARNING: -Wtrampolines not supported" >&2;} ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -Wtrampolines not supported" >&5 ++printf "%s\n" "$as_me: WARNING: -Wtrampolines not supported" >&2;} ;; ++esac + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -Wimplicit-fallthrough" >&5 +@@ -9649,8 +10001,8 @@ + if test ${ax_cv_check_cflags__Werror__Wimplicit_fallthrough+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + ax_check_save_flags=$CFLAGS + CFLAGS="$CFLAGS -Werror -Wimplicit-fallthrough" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -9667,20 +10019,23 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ax_cv_check_cflags__Werror__Wimplicit_fallthrough=yes +-else $as_nop +- ax_cv_check_cflags__Werror__Wimplicit_fallthrough=no ++else case e in #( ++ e) ax_cv_check_cflags__Werror__Wimplicit_fallthrough=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- CFLAGS=$ax_check_save_flags ++ CFLAGS=$ax_check_save_flags ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror__Wimplicit_fallthrough" >&5 + printf "%s\n" "$ax_cv_check_cflags__Werror__Wimplicit_fallthrough" >&6; } + if test "x$ax_cv_check_cflags__Werror__Wimplicit_fallthrough" = xyes + then : + CFLAGS_NODIST="$CFLAGS_NODIST -Wimplicit-fallthrough" +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -Wimplicit-fallthrough not supported" >&5 +-printf "%s\n" "$as_me: WARNING: -Wimplicit-fallthrough not supported" >&2;} ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -Wimplicit-fallthrough not supported" >&5 ++printf "%s\n" "$as_me: WARNING: -Wimplicit-fallthrough not supported" >&2;} ;; ++esac + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -Werror=format-security" >&5 +@@ -9688,8 +10043,8 @@ + if test ${ax_cv_check_cflags__Werror__Werror_format_security+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + ax_check_save_flags=$CFLAGS + CFLAGS="$CFLAGS -Werror -Werror=format-security" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -9706,20 +10061,23 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ax_cv_check_cflags__Werror__Werror_format_security=yes +-else $as_nop +- ax_cv_check_cflags__Werror__Werror_format_security=no ++else case e in #( ++ e) ax_cv_check_cflags__Werror__Werror_format_security=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- CFLAGS=$ax_check_save_flags ++ CFLAGS=$ax_check_save_flags ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror__Werror_format_security" >&5 + printf "%s\n" "$ax_cv_check_cflags__Werror__Werror_format_security" >&6; } + if test "x$ax_cv_check_cflags__Werror__Werror_format_security" = xyes + then : + CFLAGS_NODIST="$CFLAGS_NODIST -Werror=format-security" +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -Werror=format-security not supported" >&5 +-printf "%s\n" "$as_me: WARNING: -Werror=format-security not supported" >&2;} ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -Werror=format-security not supported" >&5 ++printf "%s\n" "$as_me: WARNING: -Werror=format-security not supported" >&2;} ;; ++esac + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -Wbidi-chars=any" >&5 +@@ -9727,8 +10085,8 @@ + if test ${ax_cv_check_cflags__Werror__Wbidi_chars_any+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + ax_check_save_flags=$CFLAGS + CFLAGS="$CFLAGS -Werror -Wbidi-chars=any" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -9745,20 +10103,23 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ax_cv_check_cflags__Werror__Wbidi_chars_any=yes +-else $as_nop +- ax_cv_check_cflags__Werror__Wbidi_chars_any=no ++else case e in #( ++ e) ax_cv_check_cflags__Werror__Wbidi_chars_any=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- CFLAGS=$ax_check_save_flags ++ CFLAGS=$ax_check_save_flags ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror__Wbidi_chars_any" >&5 + printf "%s\n" "$ax_cv_check_cflags__Werror__Wbidi_chars_any" >&6; } + if test "x$ax_cv_check_cflags__Werror__Wbidi_chars_any" = xyes + then : + CFLAGS_NODIST="$CFLAGS_NODIST -Wbidi-chars=any" +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -Wbidi-chars=any not supported" >&5 +-printf "%s\n" "$as_me: WARNING: -Wbidi-chars=any not supported" >&2;} ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -Wbidi-chars=any not supported" >&5 ++printf "%s\n" "$as_me: WARNING: -Wbidi-chars=any not supported" >&2;} ;; ++esac + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -Wall" >&5 +@@ -9766,8 +10127,8 @@ + if test ${ax_cv_check_cflags__Werror__Wall+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + ax_check_save_flags=$CFLAGS + CFLAGS="$CFLAGS -Werror -Wall" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -9784,20 +10145,23 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ax_cv_check_cflags__Werror__Wall=yes +-else $as_nop +- ax_cv_check_cflags__Werror__Wall=no ++else case e in #( ++ e) ax_cv_check_cflags__Werror__Wall=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- CFLAGS=$ax_check_save_flags ++ CFLAGS=$ax_check_save_flags ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror__Wall" >&5 + printf "%s\n" "$ax_cv_check_cflags__Werror__Wall" >&6; } + if test "x$ax_cv_check_cflags__Werror__Wall" = xyes + then : + CFLAGS_NODIST="$CFLAGS_NODIST -Wall" +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -Wall not supported" >&5 +-printf "%s\n" "$as_me: WARNING: -Wall not supported" >&2;} ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -Wall not supported" >&5 ++printf "%s\n" "$as_me: WARNING: -Wall not supported" >&2;} ;; ++esac + fi + + fi +@@ -9810,11 +10174,13 @@ + enableval=$enable_slower_safety; if test "x$disable_slower_safety" = xyes + then : + enable_slower_safety=no +-else $as_nop +- enable_slower_safety=yes ++else case e in #( ++ e) enable_slower_safety=yes ;; ++esac + fi +-else $as_nop +- enable_slower_safety=no ++else case e in #( ++ e) enable_slower_safety=no ;; ++esac + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_slower_safety" >&5 +@@ -9827,8 +10193,8 @@ + if test ${ax_cv_check_cflags__Werror__D_FORTIFY_SOURCE_3+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + ax_check_save_flags=$CFLAGS + CFLAGS="$CFLAGS -Werror -D_FORTIFY_SOURCE=3" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -9845,20 +10211,23 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ax_cv_check_cflags__Werror__D_FORTIFY_SOURCE_3=yes +-else $as_nop +- ax_cv_check_cflags__Werror__D_FORTIFY_SOURCE_3=no ++else case e in #( ++ e) ax_cv_check_cflags__Werror__D_FORTIFY_SOURCE_3=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- CFLAGS=$ax_check_save_flags ++ CFLAGS=$ax_check_save_flags ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror__D_FORTIFY_SOURCE_3" >&5 + printf "%s\n" "$ax_cv_check_cflags__Werror__D_FORTIFY_SOURCE_3" >&6; } + if test "x$ax_cv_check_cflags__Werror__D_FORTIFY_SOURCE_3" = xyes + then : + CFLAGS_NODIST="$CFLAGS_NODIST -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3" +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -D_FORTIFY_SOURCE=3 not supported" >&5 +-printf "%s\n" "$as_me: WARNING: -D_FORTIFY_SOURCE=3 not supported" >&2;} ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -D_FORTIFY_SOURCE=3 not supported" >&5 ++printf "%s\n" "$as_me: WARNING: -D_FORTIFY_SOURCE=3 not supported" >&2;} ;; ++esac + fi + + fi +@@ -9875,8 +10244,8 @@ + if test ${ac_cv_enable_extra_warning+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + py_cflags=$CFLAGS + as_fn_append CFLAGS " -Wextra -Werror" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -9893,12 +10262,14 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_enable_extra_warning=yes +-else $as_nop +- ac_cv_enable_extra_warning=no ++else case e in #( ++ e) ac_cv_enable_extra_warning=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + CFLAGS=$py_cflags +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_enable_extra_warning" >&5 + printf "%s\n" "$ac_cv_enable_extra_warning" >&6; } +@@ -9921,8 +10292,8 @@ + if test ${ac_cv_no_strict_aliasing+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + +@@ -9958,19 +10329,22 @@ + + ac_cv_no_strict_aliasing=no + +-else $as_nop +- ++else case e in #( ++ e) + ac_cv_no_strict_aliasing=yes +- ++ ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + +-else $as_nop +- ++else case e in #( ++ e) + ac_cv_no_strict_aliasing=no +- ++ ;; ++esac + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_no_strict_aliasing" >&5 + printf "%s\n" "$ac_cv_no_strict_aliasing" >&6; } +@@ -9993,8 +10367,8 @@ + if test ${ac_cv_disable_unused_result_warning+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + py_cflags=$CFLAGS + as_fn_append CFLAGS " -Wunused-result -Werror" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -10011,12 +10385,14 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_disable_unused_result_warning=yes +-else $as_nop +- ac_cv_disable_unused_result_warning=no ++else case e in #( ++ e) ac_cv_disable_unused_result_warning=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + CFLAGS=$py_cflags +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_disable_unused_result_warning" >&5 + printf "%s\n" "$ac_cv_disable_unused_result_warning" >&6; } +@@ -10038,8 +10414,8 @@ + if test ${ac_cv_disable_unused_parameter_warning+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + py_cflags=$CFLAGS + as_fn_append CFLAGS " -Wunused-parameter -Werror" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -10056,12 +10432,14 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_disable_unused_parameter_warning=yes +-else $as_nop +- ac_cv_disable_unused_parameter_warning=no ++else case e in #( ++ e) ac_cv_disable_unused_parameter_warning=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + CFLAGS=$py_cflags +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_disable_unused_parameter_warning" >&5 + printf "%s\n" "$ac_cv_disable_unused_parameter_warning" >&6; } +@@ -10079,8 +10457,8 @@ + if test ${ac_cv_disable_int_conversion_warning+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + py_cflags=$CFLAGS + as_fn_append CFLAGS " -Wint-conversion -Werror" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -10097,12 +10475,14 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_disable_int_conversion_warning=yes +-else $as_nop +- ac_cv_disable_int_conversion_warning=no ++else case e in #( ++ e) ac_cv_disable_int_conversion_warning=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + CFLAGS=$py_cflags +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_disable_int_conversion_warning" >&5 + printf "%s\n" "$ac_cv_disable_int_conversion_warning" >&6; } +@@ -10120,8 +10500,8 @@ + if test ${ac_cv_disable_missing_field_initializers_warning+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + py_cflags=$CFLAGS + as_fn_append CFLAGS " -Wmissing-field-initializers -Werror" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -10138,12 +10518,14 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_disable_missing_field_initializers_warning=yes +-else $as_nop +- ac_cv_disable_missing_field_initializers_warning=no ++else case e in #( ++ e) ac_cv_disable_missing_field_initializers_warning=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + CFLAGS=$py_cflags +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_disable_missing_field_initializers_warning" >&5 + printf "%s\n" "$ac_cv_disable_missing_field_initializers_warning" >&6; } +@@ -10161,8 +10543,8 @@ + if test ${ac_cv_enable_sign_compare_warning+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + py_cflags=$CFLAGS + as_fn_append CFLAGS " -Wsign-compare -Werror" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -10179,12 +10561,14 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_enable_sign_compare_warning=yes +-else $as_nop +- ac_cv_enable_sign_compare_warning=no ++else case e in #( ++ e) ac_cv_enable_sign_compare_warning=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + CFLAGS=$py_cflags +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_enable_sign_compare_warning" >&5 + printf "%s\n" "$ac_cv_enable_sign_compare_warning" >&6; } +@@ -10202,8 +10586,8 @@ + if test ${ac_cv_enable_unreachable_code_warning+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + py_cflags=$CFLAGS + as_fn_append CFLAGS " -Wunreachable-code -Werror" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -10220,12 +10604,14 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_enable_unreachable_code_warning=yes +-else $as_nop +- ac_cv_enable_unreachable_code_warning=no ++else case e in #( ++ e) ac_cv_enable_unreachable_code_warning=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + CFLAGS=$py_cflags +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_enable_unreachable_code_warning" >&5 + printf "%s\n" "$ac_cv_enable_unreachable_code_warning" >&6; } +@@ -10254,8 +10640,8 @@ + if test ${ac_cv_enable_strict_prototypes_warning+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + py_cflags=$CFLAGS + as_fn_append CFLAGS " -Wstrict-prototypes -Werror" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -10272,12 +10658,14 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_enable_strict_prototypes_warning=yes +-else $as_nop +- ac_cv_enable_strict_prototypes_warning=no ++else case e in #( ++ e) ac_cv_enable_strict_prototypes_warning=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + CFLAGS=$py_cflags +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_enable_strict_prototypes_warning" >&5 + printf "%s\n" "$ac_cv_enable_strict_prototypes_warning" >&6; } +@@ -10295,8 +10683,8 @@ + if test ${ac_cv_enable_implicit_function_declaration_error+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + +@@ -10314,12 +10702,14 @@ + + ac_cv_enable_implicit_function_declaration_error=yes + +-else $as_nop +- ++else case e in #( ++ e) + ac_cv_enable_implicit_function_declaration_error=no +- ++ ;; ++esac + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_enable_implicit_function_declaration_error" >&5 + printf "%s\n" "$ac_cv_enable_implicit_function_declaration_error" >&6; } +@@ -10337,8 +10727,8 @@ + if test ${ac_cv_enable_visibility+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + +@@ -10356,12 +10746,14 @@ + + ac_cv_enable_visibility=yes + +-else $as_nop +- ++else case e in #( ++ e) + ac_cv_enable_visibility=no +- ++ ;; ++esac + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_enable_visibility" >&5 + printf "%s\n" "$ac_cv_enable_visibility" >&6; } +@@ -10403,25 +10795,69 @@ + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 + printf "%s\n" "$CC" >&6; } + +- LIPO_INTEL64_FLAGS="" +- if test "${enable_universalsdk}" +- then +- case "$UNIVERSAL_ARCHS" in +- 32-bit) +- UNIVERSAL_ARCH_FLAGS="-arch ppc -arch i386" +- LIPO_32BIT_FLAGS="" +- ARCH_RUN_32BIT="" +- ;; +- 64-bit) +- UNIVERSAL_ARCH_FLAGS="-arch ppc64 -arch x86_64" +- LIPO_32BIT_FLAGS="" +- ARCH_RUN_32BIT="true" +- ;; +- all) +- UNIVERSAL_ARCH_FLAGS="-arch i386 -arch ppc -arch ppc64 -arch x86_64" +- LIPO_32BIT_FLAGS="-extract ppc7400 -extract i386" +- ARCH_RUN_32BIT="/usr/bin/arch -i386 -ppc" +- ;; ++ # Error on unguarded use of new symbols, which will fail at runtime for ++ # users on older versions of macOS ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -Wunguarded-availability" >&5 ++printf %s "checking whether C compiler accepts -Wunguarded-availability... " >&6; } ++if test ${ax_cv_check_cflags__Werror__Wunguarded_availability+y} ++then : ++ printf %s "(cached) " >&6 ++else case e in #( ++ e) ++ ax_check_save_flags=$CFLAGS ++ CFLAGS="$CFLAGS -Werror -Wunguarded-availability" ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++int ++main (void) ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_compile "$LINENO" ++then : ++ ax_cv_check_cflags__Werror__Wunguarded_availability=yes ++else case e in #( ++ e) ax_cv_check_cflags__Werror__Wunguarded_availability=no ;; ++esac ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++ CFLAGS=$ax_check_save_flags ;; ++esac ++fi ++{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror__Wunguarded_availability" >&5 ++printf "%s\n" "$ax_cv_check_cflags__Werror__Wunguarded_availability" >&6; } ++if test "x$ax_cv_check_cflags__Werror__Wunguarded_availability" = xyes ++then : ++ as_fn_append CFLAGS_NODIST " -Werror=unguarded-availability" ++else case e in #( ++ e) : ;; ++esac ++fi ++ ++ ++ LIPO_INTEL64_FLAGS="" ++ if test "${enable_universalsdk}" ++ then ++ case "$UNIVERSAL_ARCHS" in ++ 32-bit) ++ UNIVERSAL_ARCH_FLAGS="-arch ppc -arch i386" ++ LIPO_32BIT_FLAGS="" ++ ARCH_RUN_32BIT="" ++ ;; ++ 64-bit) ++ UNIVERSAL_ARCH_FLAGS="-arch ppc64 -arch x86_64" ++ LIPO_32BIT_FLAGS="" ++ ARCH_RUN_32BIT="true" ++ ;; ++ all) ++ UNIVERSAL_ARCH_FLAGS="-arch i386 -arch ppc -arch ppc64 -arch x86_64" ++ LIPO_32BIT_FLAGS="-extract ppc7400 -extract i386" ++ ARCH_RUN_32BIT="/usr/bin/arch -i386 -ppc" ++ ;; + universal2) + UNIVERSAL_ARCH_FLAGS="-arch arm64 -arch x86_64" + LIPO_32BIT_FLAGS="" +@@ -10535,11 +10971,12 @@ + then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 + printf "%s\n" "yes" >&6; } +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + printf "%s\n" "no" >&6; } + as_fn_error $? "check config.log and use the '--with-universal-archs' option" "$LINENO" 5 +- ++ ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +@@ -10548,8 +10985,8 @@ + ;; + esac + +-else $as_nop +- ++else case e in #( ++ e) + case $ac_sys_system in + OpenUNIX*|UnixWare*) + BASECFLAGS="$BASECFLAGS -K pentium,host,inline,loop_unroll,alloca " +@@ -10558,7 +10995,8 @@ + BASECFLAGS="$BASECFLAGS -belf -Ki486 -DSCO5" + ;; + esac +- ++ ;; ++esac + fi + + case "$ac_cv_cc_name" in +@@ -10595,12 +11033,12 @@ + if test ${ac_cv_pthread_is_default+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test "$cross_compiling" = yes ++else case e in #( ++ e) if test "$cross_compiling" = yes + then : + ac_cv_pthread_is_default=no +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -10624,14 +11062,17 @@ + ac_cv_kthread=no + ac_cv_pthread=no + +-else $as_nop +- ac_cv_pthread_is_default=no ++else case e in #( ++ e) ac_cv_pthread_is_default=no ;; ++esac + fi + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_pthread_is_default" >&5 + printf "%s\n" "$ac_cv_pthread_is_default" >&6; } +@@ -10651,14 +11092,14 @@ + if test ${ac_cv_kpthread+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_save_cc="$CC" ++else case e in #( ++ e) ac_save_cc="$CC" + CC="$CC -Kpthread" + if test "$cross_compiling" = yes + then : + ac_cv_kpthread=no +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -10678,14 +11119,17 @@ + if ac_fn_c_try_run "$LINENO" + then : + ac_cv_kpthread=yes +-else $as_nop +- ac_cv_kpthread=no ++else case e in #( ++ e) ac_cv_kpthread=no ;; ++esac + fi + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + +-CC="$ac_save_cc" ++CC="$ac_save_cc" ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_kpthread" >&5 + printf "%s\n" "$ac_cv_kpthread" >&6; } +@@ -10703,14 +11147,14 @@ + if test ${ac_cv_kthread+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_save_cc="$CC" ++else case e in #( ++ e) ac_save_cc="$CC" + CC="$CC -Kthread" + if test "$cross_compiling" = yes + then : + ac_cv_kthread=no +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -10730,14 +11174,17 @@ + if ac_fn_c_try_run "$LINENO" + then : + ac_cv_kthread=yes +-else $as_nop +- ac_cv_kthread=no ++else case e in #( ++ e) ac_cv_kthread=no ;; ++esac + fi + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + +-CC="$ac_save_cc" ++CC="$ac_save_cc" ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_kthread" >&5 + printf "%s\n" "$ac_cv_kthread" >&6; } +@@ -10755,14 +11202,14 @@ + if test ${ac_cv_pthread+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_save_cc="$CC" ++else case e in #( ++ e) ac_save_cc="$CC" + CC="$CC -pthread" + if test "$cross_compiling" = yes + then : + ac_cv_pthread=no +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -10782,14 +11229,17 @@ + if ac_fn_c_try_run "$LINENO" + then : + ac_cv_pthread=yes +-else $as_nop +- ac_cv_pthread=no ++else case e in #( ++ e) ac_cv_pthread=no ;; ++esac + fi + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + +-CC="$ac_save_cc" ++CC="$ac_save_cc" ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_pthread" >&5 + printf "%s\n" "$ac_cv_pthread" >&6; } +@@ -10804,8 +11254,8 @@ + if test ${ac_cv_cxx_thread+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_save_cxx="$CXX" ++else case e in #( ++ e) ac_save_cxx="$CXX" + + if test "$ac_cv_kpthread" = "yes" + then +@@ -10836,7 +11286,8 @@ + fi + rm -fr conftest* + fi +-CXX="$ac_save_cxx" ++CXX="$ac_save_cxx" ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_thread" >&5 + printf "%s\n" "$ac_cv_cxx_thread" >&6; } +@@ -10981,6 +11432,12 @@ + then : + printf "%s\n" "#define HAVE_LINUX_SOUNDCARD_H 1" >>confdefs.h + ++fi ++ac_fn_c_check_header_compile "$LINENO" "linux/sched.h" "ac_cv_header_linux_sched_h" "$ac_includes_default" ++if test "x$ac_cv_header_linux_sched_h" = xyes ++then : ++ printf "%s\n" "#define HAVE_LINUX_SCHED_H 1" >>confdefs.h ++ + fi + ac_fn_c_check_header_compile "$LINENO" "linux/tipc.h" "ac_cv_header_linux_tipc_h" "$ac_includes_default" + if test "x$ac_cv_header_linux_tipc_h" = xyes +@@ -11179,12 +11636,6 @@ + then : + printf "%s\n" "#define HAVE_SYS_PARAM_H 1" >>confdefs.h + +-fi +-ac_fn_c_check_header_compile "$LINENO" "sys/pidfd.h" "ac_cv_header_sys_pidfd_h" "$ac_includes_default" +-if test "x$ac_cv_header_sys_pidfd_h" = xyes +-then : +- printf "%s\n" "#define HAVE_SYS_PIDFD_H 1" >>confdefs.h +- + fi + ac_fn_c_check_header_compile "$LINENO" "sys/poll.h" "ac_cv_header_sys_poll_h" "$ac_includes_default" + if test "x$ac_cv_header_sys_poll_h" = xyes +@@ -11357,14 +11808,14 @@ + + ac_header_dirent=no + for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do +- as_ac_Header=`printf "%s\n" "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` ++ as_ac_Header=`printf "%s\n" "ac_cv_header_dirent_$ac_hdr" | sed "$as_sed_sh"` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 + printf %s "checking for $ac_hdr that defines DIR... " >&6; } + if eval test \${$as_ac_Header+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + #include <$ac_hdr> +@@ -11381,10 +11832,12 @@ + if ac_fn_c_try_compile "$LINENO" + then : + eval "$as_ac_Header=yes" +-else $as_nop +- eval "$as_ac_Header=no" ++else case e in #( ++ e) eval "$as_ac_Header=no" ;; ++esac + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + eval ac_res=\$$as_ac_Header + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +@@ -11392,7 +11845,7 @@ + if eval test \"x\$"$as_ac_Header"\" = x"yes" + then : + cat >>confdefs.h <<_ACEOF +-#define `printf "%s\n" "HAVE_$ac_hdr" | $as_tr_cpp` 1 ++#define `printf "%s\n" "HAVE_$ac_hdr" | sed "$as_sed_cpp"` 1 + _ACEOF + + ac_header_dirent=$ac_hdr; break +@@ -11406,15 +11859,21 @@ + if test ${ac_cv_search_opendir+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_func_search_save_LIBS=$LIBS ++else case e in #( ++ e) ac_func_search_save_LIBS=$LIBS + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char opendir (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char opendir (void); + int + main (void) + { +@@ -11445,11 +11904,13 @@ + if test ${ac_cv_search_opendir+y} + then : + +-else $as_nop +- ac_cv_search_opendir=no ++else case e in #( ++ e) ac_cv_search_opendir=no ;; ++esac + fi + rm conftest.$ac_ext +-LIBS=$ac_func_search_save_LIBS ++LIBS=$ac_func_search_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 + printf "%s\n" "$ac_cv_search_opendir" >&6; } +@@ -11466,15 +11927,21 @@ + if test ${ac_cv_search_opendir+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_func_search_save_LIBS=$LIBS ++else case e in #( ++ e) ac_func_search_save_LIBS=$LIBS + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char opendir (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char opendir (void); + int + main (void) + { +@@ -11505,11 +11972,13 @@ + if test ${ac_cv_search_opendir+y} + then : + +-else $as_nop +- ac_cv_search_opendir=no ++else case e in #( ++ e) ac_cv_search_opendir=no ;; ++esac + fi + rm conftest.$ac_ext +-LIBS=$ac_func_search_save_LIBS ++LIBS=$ac_func_search_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 + printf "%s\n" "$ac_cv_search_opendir" >&6; } +@@ -11702,10 +12171,11 @@ + printf "%s\n" "#define HAVE_CLOCK_T 1" >>confdefs.h + + +-else $as_nop +- ++else case e in #( ++ e) + printf "%s\n" "#define clock_t long" >>confdefs.h +- ++ ;; ++esac + fi + + +@@ -11714,8 +12184,8 @@ + if test ${ac_cv_func_makedev+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + +@@ -11740,12 +12210,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_func_makedev=yes +-else $as_nop +- ac_cv_func_makedev=no ++else case e in #( ++ e) ac_cv_func_makedev=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_makedev" >&5 + printf "%s\n" "$ac_cv_func_makedev" >&6; } +@@ -11765,8 +12237,8 @@ + if test ${ac_cv_func_le64toh+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + +@@ -11789,12 +12261,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_func_le64toh=yes +-else $as_nop +- ac_cv_func_le64toh=no ++else case e in #( ++ e) ac_cv_func_le64toh=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_le64toh" >&5 + printf "%s\n" "$ac_cv_func_le64toh" >&6; } +@@ -11844,20 +12318,22 @@ + if test "x$ac_cv_type_mode_t" = xyes + then : + +-else $as_nop +- ++else case e in #( ++ e) + printf "%s\n" "#define mode_t int" >>confdefs.h +- ++ ;; ++esac + fi + + ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" + if test "x$ac_cv_type_off_t" = xyes + then : + +-else $as_nop +- ++else case e in #( ++ e) + printf "%s\n" "#define off_t long int" >>confdefs.h +- ++ ;; ++esac + fi + + +@@ -11866,8 +12342,8 @@ + if test "x$ac_cv_type_pid_t" = xyes + then : + +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #if defined _WIN64 && !defined __CYGWIN__ +@@ -11886,14 +12362,16 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_pid_type='int' +-else $as_nop +- ac_pid_type='__int64' ++else case e in #( ++ e) ac_pid_type='__int64' ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + + printf "%s\n" "#define pid_t $ac_pid_type" >>confdefs.h + +- ++ ;; ++esac + fi + + +@@ -11904,42 +12382,33 @@ + if test "x$ac_cv_type_size_t" = xyes + then : + +-else $as_nop +- ++else case e in #( ++ e) + printf "%s\n" "#define size_t unsigned int" >>confdefs.h +- ++ ;; ++esac + fi + +-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 +-printf %s "checking for uid_t in sys/types.h... " >&6; } +-if test ${ac_cv_type_uid_t+y} ++ac_fn_c_check_type "$LINENO" "uid_t" "ac_cv_type_uid_t" "$ac_includes_default" ++if test "x$ac_cv_type_uid_t" = xyes + then : +- printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext +-/* end confdefs.h. */ +-#include +- +-_ACEOF +-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | +- $EGREP "uid_t" >/dev/null 2>&1 +-then : +- ac_cv_type_uid_t=yes +-else $as_nop +- ac_cv_type_uid_t=no +-fi +-rm -rf conftest* +- +-fi +-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5 +-printf "%s\n" "$ac_cv_type_uid_t" >&6; } +-if test $ac_cv_type_uid_t = no; then + ++else case e in #( ++ e) + printf "%s\n" "#define uid_t int" >>confdefs.h ++ ;; ++esac ++fi + ++ac_fn_c_check_type "$LINENO" "gid_t" "ac_cv_type_gid_t" "$ac_includes_default" ++if test "x$ac_cv_type_gid_t" = xyes ++then : + ++else case e in #( ++ e) + printf "%s\n" "#define gid_t int" >>confdefs.h +- ++ ;; ++esac + fi + + +@@ -11968,28 +12437,30 @@ + # ANSI C requires sizeof(char) == 1, so no need to check it + # The cast to long int works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +-# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. ++# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 + printf %s "checking size of int... " >&6; } + if test ${ac_cv_sizeof_int+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default" ++else case e in #( ++ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default" + then : + +-else $as_nop +- if test "$ac_cv_type_int" = yes; then +- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++else case e in #( ++ e) if test "$ac_cv_type_int" = yes; then ++ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error 77 "cannot compute sizeof (int) +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_int=0 +- fi ++ fi ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5 + printf "%s\n" "$ac_cv_sizeof_int" >&6; } +@@ -12001,28 +12472,30 @@ + + # The cast to long int works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +-# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. ++# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 + printf %s "checking size of long... " >&6; } + if test ${ac_cv_sizeof_long+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default" ++else case e in #( ++ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default" + then : + +-else $as_nop +- if test "$ac_cv_type_long" = yes; then +- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++else case e in #( ++ e) if test "$ac_cv_type_long" = yes; then ++ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error 77 "cannot compute sizeof (long) +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_long=0 +- fi ++ fi ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 + printf "%s\n" "$ac_cv_sizeof_long" >&6; } +@@ -12039,22 +12512,24 @@ + if test ${ac_cv_alignof_long+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if ac_fn_c_compute_int "$LINENO" "(long int) offsetof (ac__type_alignof_, y)" "ac_cv_alignof_long" "$ac_includes_default ++else case e in #( ++ e) if ac_fn_c_compute_int "$LINENO" "(long int) offsetof (ac__type_alignof_, y)" "ac_cv_alignof_long" "$ac_includes_default + typedef struct { char x; long y; } ac__type_alignof_;" + then : + +-else $as_nop +- if test "$ac_cv_type_long" = yes; then +- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++else case e in #( ++ e) if test "$ac_cv_type_long" = yes; then ++ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error 77 "cannot compute alignment of long +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } + else + ac_cv_alignof_long=0 +- fi ++ fi ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_alignof_long" >&5 + printf "%s\n" "$ac_cv_alignof_long" >&6; } +@@ -12066,28 +12541,30 @@ + + # The cast to long int works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +-# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. ++# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5 + printf %s "checking size of long long... " >&6; } + if test ${ac_cv_sizeof_long_long+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default" ++else case e in #( ++ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default" + then : + +-else $as_nop +- if test "$ac_cv_type_long_long" = yes; then +- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++else case e in #( ++ e) if test "$ac_cv_type_long_long" = yes; then ++ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error 77 "cannot compute sizeof (long long) +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_long_long=0 +- fi ++ fi ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_long" >&5 + printf "%s\n" "$ac_cv_sizeof_long_long" >&6; } +@@ -12099,28 +12576,30 @@ + + # The cast to long int works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +-# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. ++# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 + printf %s "checking size of void *... " >&6; } + if test ${ac_cv_sizeof_void_p+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default" ++else case e in #( ++ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default" + then : + +-else $as_nop +- if test "$ac_cv_type_void_p" = yes; then +- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++else case e in #( ++ e) if test "$ac_cv_type_void_p" = yes; then ++ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error 77 "cannot compute sizeof (void *) +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_void_p=0 +- fi ++ fi ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 + printf "%s\n" "$ac_cv_sizeof_void_p" >&6; } +@@ -12132,28 +12611,30 @@ + + # The cast to long int works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +-# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. ++# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of short" >&5 + printf %s "checking size of short... " >&6; } + if test ${ac_cv_sizeof_short+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default" ++else case e in #( ++ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default" + then : + +-else $as_nop +- if test "$ac_cv_type_short" = yes; then +- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++else case e in #( ++ e) if test "$ac_cv_type_short" = yes; then ++ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error 77 "cannot compute sizeof (short) +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_short=0 +- fi ++ fi ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_short" >&5 + printf "%s\n" "$ac_cv_sizeof_short" >&6; } +@@ -12165,28 +12646,30 @@ + + # The cast to long int works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +-# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. ++# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of float" >&5 + printf %s "checking size of float... " >&6; } + if test ${ac_cv_sizeof_float+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (float))" "ac_cv_sizeof_float" "$ac_includes_default" ++else case e in #( ++ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (float))" "ac_cv_sizeof_float" "$ac_includes_default" + then : + +-else $as_nop +- if test "$ac_cv_type_float" = yes; then +- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++else case e in #( ++ e) if test "$ac_cv_type_float" = yes; then ++ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error 77 "cannot compute sizeof (float) +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_float=0 +- fi ++ fi ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_float" >&5 + printf "%s\n" "$ac_cv_sizeof_float" >&6; } +@@ -12198,28 +12681,30 @@ + + # The cast to long int works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +-# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. ++# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of double" >&5 + printf %s "checking size of double... " >&6; } + if test ${ac_cv_sizeof_double+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (double))" "ac_cv_sizeof_double" "$ac_includes_default" ++else case e in #( ++ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (double))" "ac_cv_sizeof_double" "$ac_includes_default" + then : + +-else $as_nop +- if test "$ac_cv_type_double" = yes; then +- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++else case e in #( ++ e) if test "$ac_cv_type_double" = yes; then ++ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error 77 "cannot compute sizeof (double) +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_double=0 +- fi ++ fi ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_double" >&5 + printf "%s\n" "$ac_cv_sizeof_double" >&6; } +@@ -12231,28 +12716,30 @@ + + # The cast to long int works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +-# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. ++# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of fpos_t" >&5 + printf %s "checking size of fpos_t... " >&6; } + if test ${ac_cv_sizeof_fpos_t+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (fpos_t))" "ac_cv_sizeof_fpos_t" "$ac_includes_default" ++else case e in #( ++ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (fpos_t))" "ac_cv_sizeof_fpos_t" "$ac_includes_default" + then : + +-else $as_nop +- if test "$ac_cv_type_fpos_t" = yes; then +- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++else case e in #( ++ e) if test "$ac_cv_type_fpos_t" = yes; then ++ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error 77 "cannot compute sizeof (fpos_t) +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_fpos_t=0 +- fi ++ fi ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_fpos_t" >&5 + printf "%s\n" "$ac_cv_sizeof_fpos_t" >&6; } +@@ -12264,28 +12751,30 @@ + + # The cast to long int works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +-# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. ++# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of size_t" >&5 + printf %s "checking size of size_t... " >&6; } + if test ${ac_cv_sizeof_size_t+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (size_t))" "ac_cv_sizeof_size_t" "$ac_includes_default" ++else case e in #( ++ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (size_t))" "ac_cv_sizeof_size_t" "$ac_includes_default" + then : + +-else $as_nop +- if test "$ac_cv_type_size_t" = yes; then +- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++else case e in #( ++ e) if test "$ac_cv_type_size_t" = yes; then ++ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error 77 "cannot compute sizeof (size_t) +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_size_t=0 +- fi ++ fi ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_size_t" >&5 + printf "%s\n" "$ac_cv_sizeof_size_t" >&6; } +@@ -12302,22 +12791,24 @@ + if test ${ac_cv_alignof_size_t+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if ac_fn_c_compute_int "$LINENO" "(long int) offsetof (ac__type_alignof_, y)" "ac_cv_alignof_size_t" "$ac_includes_default ++else case e in #( ++ e) if ac_fn_c_compute_int "$LINENO" "(long int) offsetof (ac__type_alignof_, y)" "ac_cv_alignof_size_t" "$ac_includes_default + typedef struct { char x; size_t y; } ac__type_alignof_;" + then : + +-else $as_nop +- if test "$ac_cv_type_size_t" = yes; then +- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++else case e in #( ++ e) if test "$ac_cv_type_size_t" = yes; then ++ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error 77 "cannot compute alignment of size_t +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } + else + ac_cv_alignof_size_t=0 +- fi ++ fi ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_alignof_size_t" >&5 + printf "%s\n" "$ac_cv_alignof_size_t" >&6; } +@@ -12329,28 +12820,30 @@ + + # The cast to long int works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +-# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. ++# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of pid_t" >&5 + printf %s "checking size of pid_t... " >&6; } + if test ${ac_cv_sizeof_pid_t+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pid_t))" "ac_cv_sizeof_pid_t" "$ac_includes_default" ++else case e in #( ++ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pid_t))" "ac_cv_sizeof_pid_t" "$ac_includes_default" + then : + +-else $as_nop +- if test "$ac_cv_type_pid_t" = yes; then +- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++else case e in #( ++ e) if test "$ac_cv_type_pid_t" = yes; then ++ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error 77 "cannot compute sizeof (pid_t) +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_pid_t=0 +- fi ++ fi ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_pid_t" >&5 + printf "%s\n" "$ac_cv_sizeof_pid_t" >&6; } +@@ -12362,28 +12855,30 @@ + + # The cast to long int works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +-# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. ++# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of uintptr_t" >&5 + printf %s "checking size of uintptr_t... " >&6; } + if test ${ac_cv_sizeof_uintptr_t+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (uintptr_t))" "ac_cv_sizeof_uintptr_t" "$ac_includes_default" ++else case e in #( ++ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (uintptr_t))" "ac_cv_sizeof_uintptr_t" "$ac_includes_default" + then : + +-else $as_nop +- if test "$ac_cv_type_uintptr_t" = yes; then +- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++else case e in #( ++ e) if test "$ac_cv_type_uintptr_t" = yes; then ++ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error 77 "cannot compute sizeof (uintptr_t) +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_uintptr_t=0 +- fi ++ fi ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_uintptr_t" >&5 + printf "%s\n" "$ac_cv_sizeof_uintptr_t" >&6; } +@@ -12400,22 +12895,24 @@ + if test ${ac_cv_alignof_max_align_t+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if ac_fn_c_compute_int "$LINENO" "(long int) offsetof (ac__type_alignof_, y)" "ac_cv_alignof_max_align_t" "$ac_includes_default ++else case e in #( ++ e) if ac_fn_c_compute_int "$LINENO" "(long int) offsetof (ac__type_alignof_, y)" "ac_cv_alignof_max_align_t" "$ac_includes_default + typedef struct { char x; max_align_t y; } ac__type_alignof_;" + then : + +-else $as_nop +- if test "$ac_cv_type_max_align_t" = yes; then +- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++else case e in #( ++ e) if test "$ac_cv_type_max_align_t" = yes; then ++ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error 77 "cannot compute alignment of max_align_t +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } + else + ac_cv_alignof_max_align_t=0 +- fi ++ fi ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_alignof_max_align_t" >&5 + printf "%s\n" "$ac_cv_alignof_max_align_t" >&6; } +@@ -12432,8 +12929,8 @@ + if test ${ac_cv_type_long_double+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test "$GCC" = yes; then ++else case e in #( ++ e) if test "$GCC" = yes; then + ac_cv_type_long_double=yes + else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -12456,11 +12953,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_type_long_double=yes +-else $as_nop +- ac_cv_type_long_double=no ++else case e in #( ++ e) ac_cv_type_long_double=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- fi ++ fi ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_long_double" >&5 + printf "%s\n" "$ac_cv_type_long_double" >&6; } +@@ -12472,28 +12971,30 @@ + + # The cast to long int works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +-# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. ++# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of long double" >&5 + printf %s "checking size of long double... " >&6; } + if test ${ac_cv_sizeof_long_double+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long double))" "ac_cv_sizeof_long_double" "$ac_includes_default" ++else case e in #( ++ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long double))" "ac_cv_sizeof_long_double" "$ac_includes_default" + then : + +-else $as_nop +- if test "$ac_cv_type_long_double" = yes; then +- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++else case e in #( ++ e) if test "$ac_cv_type_long_double" = yes; then ++ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error 77 "cannot compute sizeof (long double) +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_long_double=0 +- fi ++ fi ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_double" >&5 + printf "%s\n" "$ac_cv_sizeof_long_double" >&6; } +@@ -12506,28 +13007,30 @@ + + # The cast to long int works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +-# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. ++# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of _Bool" >&5 + printf %s "checking size of _Bool... " >&6; } + if test ${ac_cv_sizeof__Bool+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (_Bool))" "ac_cv_sizeof__Bool" "$ac_includes_default" ++else case e in #( ++ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (_Bool))" "ac_cv_sizeof__Bool" "$ac_includes_default" + then : + +-else $as_nop +- if test "$ac_cv_type__Bool" = yes; then +- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++else case e in #( ++ e) if test "$ac_cv_type__Bool" = yes; then ++ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error 77 "cannot compute sizeof (_Bool) +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof__Bool=0 +- fi ++ fi ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof__Bool" >&5 + printf "%s\n" "$ac_cv_sizeof__Bool" >&6; } +@@ -12540,15 +13043,15 @@ + + # The cast to long int works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +-# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. ++# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of off_t" >&5 + printf %s "checking size of off_t... " >&6; } + if test ${ac_cv_sizeof_off_t+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (off_t))" "ac_cv_sizeof_off_t" " ++else case e in #( ++ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (off_t))" "ac_cv_sizeof_off_t" " + #ifdef HAVE_SYS_TYPES_H + #include + #endif +@@ -12556,17 +13059,19 @@ + " + then : + +-else $as_nop +- if test "$ac_cv_type_off_t" = yes; then +- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++else case e in #( ++ e) if test "$ac_cv_type_off_t" = yes; then ++ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error 77 "cannot compute sizeof (off_t) +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_off_t=0 +- fi ++ fi ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_off_t" >&5 + printf "%s\n" "$ac_cv_sizeof_off_t" >&6; } +@@ -12601,24 +13106,25 @@ + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 + printf "%s\n" "yes" >&6; } + +-else $as_nop +- ++else case e in #( ++ e) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + printf "%s\n" "no" >&6; } +- ++ ;; ++esac + fi + + # The cast to long int works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +-# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. ++# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of time_t" >&5 + printf %s "checking size of time_t... " >&6; } + if test ${ac_cv_sizeof_time_t+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (time_t))" "ac_cv_sizeof_time_t" " ++else case e in #( ++ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (time_t))" "ac_cv_sizeof_time_t" " + #ifdef HAVE_SYS_TYPES_H + #include + #endif +@@ -12629,17 +13135,19 @@ + " + then : + +-else $as_nop +- if test "$ac_cv_type_time_t" = yes; then +- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++else case e in #( ++ e) if test "$ac_cv_type_time_t" = yes; then ++ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error 77 "cannot compute sizeof (time_t) +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_time_t=0 +- fi ++ fi ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_time_t" >&5 + printf "%s\n" "$ac_cv_sizeof_time_t" >&6; } +@@ -12665,8 +13173,8 @@ + if test ${ac_cv_have_pthread_t+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + +@@ -12683,11 +13191,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_have_pthread_t=yes +-else $as_nop +- ac_cv_have_pthread_t=no ++else case e in #( ++ e) ac_cv_have_pthread_t=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_pthread_t" >&5 + printf "%s\n" "$ac_cv_have_pthread_t" >&6; } +@@ -12696,15 +13206,15 @@ + + # The cast to long int works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +-# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. ++# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of pthread_t" >&5 + printf %s "checking size of pthread_t... " >&6; } + if test ${ac_cv_sizeof_pthread_t+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pthread_t))" "ac_cv_sizeof_pthread_t" " ++else case e in #( ++ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pthread_t))" "ac_cv_sizeof_pthread_t" " + #ifdef HAVE_PTHREAD_H + #include + #endif +@@ -12712,17 +13222,19 @@ + " + then : + +-else $as_nop +- if test "$ac_cv_type_pthread_t" = yes; then +- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++else case e in #( ++ e) if test "$ac_cv_type_pthread_t" = yes; then ++ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error 77 "cannot compute sizeof (pthread_t) +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_pthread_t=0 +- fi ++ fi ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_pthread_t" >&5 + printf "%s\n" "$ac_cv_sizeof_pthread_t" >&6; } +@@ -12739,29 +13251,31 @@ + # This checking will be unnecessary after removing deprecated TLS API. + # The cast to long int works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +-# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. ++# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of pthread_key_t" >&5 + printf %s "checking size of pthread_key_t... " >&6; } + if test ${ac_cv_sizeof_pthread_key_t+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pthread_key_t))" "ac_cv_sizeof_pthread_key_t" "#include ++else case e in #( ++ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pthread_key_t))" "ac_cv_sizeof_pthread_key_t" "#include + " + then : + +-else $as_nop +- if test "$ac_cv_type_pthread_key_t" = yes; then +- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++else case e in #( ++ e) if test "$ac_cv_type_pthread_key_t" = yes; then ++ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error 77 "cannot compute sizeof (pthread_key_t) +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_pthread_key_t=0 +- fi ++ fi ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_pthread_key_t" >&5 + printf "%s\n" "$ac_cv_sizeof_pthread_key_t" >&6; } +@@ -12776,8 +13290,8 @@ + if test ${ac_cv_pthread_key_t_is_arithmetic_type+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + if test "$ac_cv_sizeof_pthread_key_t" -eq "$ac_cv_sizeof_int" ; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ +@@ -12793,15 +13307,17 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_pthread_key_t_is_arithmetic_type=yes +-else $as_nop +- ac_cv_pthread_key_t_is_arithmetic_type=no +- ++else case e in #( ++ e) ac_cv_pthread_key_t_is_arithmetic_type=no ++ ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + else + ac_cv_pthread_key_t_is_arithmetic_type=no + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_pthread_key_t_is_arithmetic_type" >&5 + printf "%s\n" "$ac_cv_pthread_key_t_is_arithmetic_type" >&6; } +@@ -12860,9 +13376,10 @@ + else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + printf "%s\n" "no" >&6; }; DSYMUTIL= + fi +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +-printf "%s\n" "no" >&6; } ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++printf "%s\n" "no" >&6; } ;; ++esac + fi + + +@@ -12874,8 +13391,8 @@ + if test ${ac_cv_path_DSYMUTIL_PATH+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- case $DSYMUTIL_PATH in ++else case e in #( ++ e) case $DSYMUTIL_PATH in + [\\/]* | ?:[\\/]*) + ac_cv_path_DSYMUTIL_PATH="$DSYMUTIL_PATH" # Let the user override the test with a path. + ;; +@@ -12901,6 +13418,7 @@ + + test -z "$ac_cv_path_DSYMUTIL_PATH" && ac_cv_path_DSYMUTIL_PATH="not found" + ;; ++esac ;; + esac + fi + DSYMUTIL_PATH=$ac_cv_path_DSYMUTIL_PATH +@@ -12948,9 +13466,10 @@ + # ASan works by controlling memory allocation, our own malloc interferes. + with_pymalloc="no" + +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +-printf "%s\n" "no" >&6; } ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++printf "%s\n" "no" >&6; } ;; ++esac + fi + + +@@ -12968,8 +13487,8 @@ + if test ${ax_cv_check_cflags___fsanitize_memory+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + ax_check_save_flags=$CFLAGS + CFLAGS="$CFLAGS -fsanitize=memory" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -12986,11 +13505,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ax_cv_check_cflags___fsanitize_memory=yes +-else $as_nop +- ax_cv_check_cflags___fsanitize_memory=no ++else case e in #( ++ e) ax_cv_check_cflags___fsanitize_memory=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- CFLAGS=$ax_check_save_flags ++ CFLAGS=$ax_check_save_flags ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___fsanitize_memory" >&5 + printf "%s\n" "$ax_cv_check_cflags___fsanitize_memory" >&6; } +@@ -13000,16 +13521,18 @@ + BASECFLAGS="-fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer $BASECFLAGS" + LDFLAGS="-fsanitize=memory -fsanitize-memory-track-origins=2 $LDFLAGS" + +-else $as_nop +- as_fn_error $? "The selected compiler doesn't support memory sanitizer" "$LINENO" 5 ++else case e in #( ++ e) as_fn_error $? "The selected compiler doesn't support memory sanitizer" "$LINENO" 5 ;; ++esac + fi + + # MSan works by controlling memory allocation, our own malloc interferes. + with_pymalloc="no" + +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +-printf "%s\n" "no" >&6; } ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++printf "%s\n" "no" >&6; } ;; ++esac + fi + + +@@ -13026,12 +13549,13 @@ + LDFLAGS="-fsanitize=undefined $LDFLAGS" + with_ubsan="yes" + +-else $as_nop +- ++else case e in #( ++ e) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + printf "%s\n" "no" >&6; } + with_ubsan="no" +- ++ ;; ++esac + fi + + +@@ -13048,12 +13572,13 @@ + LDFLAGS="-fsanitize=thread $LDFLAGS" + with_tsan="yes" + +-else $as_nop +- ++else case e in #( ++ e) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + printf "%s\n" "no" >&6; } + with_tsan="no" +- ++ ;; ++esac + fi + + +@@ -13160,7 +13685,7 @@ + BLDSHARED="$LDSHARED" + fi + ;; +- iOS/*) ++ iOS/*|tvOS/*|watchOS/*) + LDSHARED='$(CC) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)' + LDCXXSHARED='$(CXX) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)' + BLDSHARED="$LDSHARED" +@@ -13293,7 +13818,7 @@ + Linux-android*) LINKFORSHARED="-pie -Xlinker -export-dynamic";; + Linux*|GNU*) LINKFORSHARED="-Xlinker -export-dynamic";; + # -u libsys_s pulls in all symbols in libsys +- Darwin/*|iOS/*) ++ Darwin/*|iOS/*|tvOS/*|watchOS/*) + LINKFORSHARED="$extra_undefs -framework CoreFoundation" + + # Issue #18075: the default maximum stack size (8MBytes) is too +@@ -13317,7 +13842,7 @@ + LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' + fi + LINKFORSHARED="$LINKFORSHARED" +- elif test $ac_sys_system = "iOS"; then ++ elif test "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "watchOS"; then + LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)' + fi + ;; +@@ -13437,16 +13962,22 @@ + if test ${ac_cv_lib_sendfile_sendfile+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lsendfile $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char sendfile (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char sendfile (void); + int + main (void) + { +@@ -13458,12 +13989,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_sendfile_sendfile=yes +-else $as_nop +- ac_cv_lib_sendfile_sendfile=no ++else case e in #( ++ e) ac_cv_lib_sendfile_sendfile=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sendfile_sendfile" >&5 + printf "%s\n" "$ac_cv_lib_sendfile_sendfile" >&6; } +@@ -13480,16 +14013,22 @@ + if test ${ac_cv_lib_dl_dlopen+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-ldl $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char dlopen (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char dlopen (void); + int + main (void) + { +@@ -13501,12 +14040,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_dl_dlopen=yes +-else $as_nop +- ac_cv_lib_dl_dlopen=no ++else case e in #( ++ e) ac_cv_lib_dl_dlopen=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 + printf "%s\n" "$ac_cv_lib_dl_dlopen" >&6; } +@@ -13523,16 +14064,22 @@ + if test ${ac_cv_lib_dld_shl_load+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-ldld $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char shl_load (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char shl_load (void); + int + main (void) + { +@@ -13544,12 +14091,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_dld_shl_load=yes +-else $as_nop +- ac_cv_lib_dld_shl_load=no ++else case e in #( ++ e) ac_cv_lib_dld_shl_load=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 + printf "%s\n" "$ac_cv_lib_dld_shl_load" >&6; } +@@ -13577,12 +14126,12 @@ + + for ac_func in uuid_create uuid_enc_be + do : +- as_ac_var=`printf "%s\n" "ac_cv_func_$ac_func" | $as_tr_sh` ++ as_ac_var=`printf "%s\n" "ac_cv_func_$ac_func" | sed "$as_sed_sh"` + ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" + if eval test \"x\$"$as_ac_var"\" = x"yes" + then : + cat >>confdefs.h <<_ACEOF +-#define `printf "%s\n" "HAVE_$ac_func" | $as_tr_cpp` 1 ++#define `printf "%s\n" "HAVE_$ac_func" | sed "$as_sed_cpp"` 1 + _ACEOF + have_uuid=yes + LIBUUID_CFLAGS=${LIBUUID_CFLAGS-""} +@@ -13680,16 +14229,22 @@ + if test ${ac_cv_lib_uuid_uuid_generate_time+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-luuid $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char uuid_generate_time (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char uuid_generate_time (void); + int + main (void) + { +@@ -13701,12 +14256,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_uuid_uuid_generate_time=yes +-else $as_nop +- ac_cv_lib_uuid_uuid_generate_time=no ++else case e in #( ++ e) ac_cv_lib_uuid_uuid_generate_time=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_generate_time" >&5 + printf "%s\n" "$ac_cv_lib_uuid_uuid_generate_time" >&6; } +@@ -13723,16 +14280,22 @@ + if test ${ac_cv_lib_uuid_uuid_generate_time_safe+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-luuid $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char uuid_generate_time_safe (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char uuid_generate_time_safe (void); + int + main (void) + { +@@ -13744,12 +14307,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_uuid_uuid_generate_time_safe=yes +-else $as_nop +- ac_cv_lib_uuid_uuid_generate_time_safe=no ++else case e in #( ++ e) ac_cv_lib_uuid_uuid_generate_time_safe=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_generate_time_safe" >&5 + printf "%s\n" "$ac_cv_lib_uuid_uuid_generate_time_safe" >&6; } +@@ -13806,16 +14371,22 @@ + if test ${ac_cv_lib_uuid_uuid_generate_time+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-luuid $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char uuid_generate_time (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char uuid_generate_time (void); + int + main (void) + { +@@ -13827,12 +14398,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_uuid_uuid_generate_time=yes +-else $as_nop +- ac_cv_lib_uuid_uuid_generate_time=no ++else case e in #( ++ e) ac_cv_lib_uuid_uuid_generate_time=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_generate_time" >&5 + printf "%s\n" "$ac_cv_lib_uuid_uuid_generate_time" >&6; } +@@ -13849,16 +14422,22 @@ + if test ${ac_cv_lib_uuid_uuid_generate_time_safe+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-luuid $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char uuid_generate_time_safe (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char uuid_generate_time_safe (void); + int + main (void) + { +@@ -13870,12 +14449,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_uuid_uuid_generate_time_safe=yes +-else $as_nop +- ac_cv_lib_uuid_uuid_generate_time_safe=no ++else case e in #( ++ e) ac_cv_lib_uuid_uuid_generate_time_safe=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_generate_time_safe" >&5 + printf "%s\n" "$ac_cv_lib_uuid_uuid_generate_time_safe" >&6; } +@@ -13970,15 +14551,21 @@ + if test ${ac_cv_search_sem_init+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_func_search_save_LIBS=$LIBS ++else case e in #( ++ e) ac_func_search_save_LIBS=$LIBS + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char sem_init (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char sem_init (void); + int + main (void) + { +@@ -14009,11 +14596,13 @@ + if test ${ac_cv_search_sem_init+y} + then : + +-else $as_nop +- ac_cv_search_sem_init=no ++else case e in #( ++ e) ac_cv_search_sem_init=no ;; ++esac + fi + rm conftest.$ac_ext +-LIBS=$ac_func_search_save_LIBS ++LIBS=$ac_func_search_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_sem_init" >&5 + printf "%s\n" "$ac_cv_search_sem_init" >&6; } +@@ -14031,16 +14620,22 @@ + if test ${ac_cv_lib_intl_textdomain+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lintl $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char textdomain (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char textdomain (void); + int + main (void) + { +@@ -14052,12 +14647,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_intl_textdomain=yes +-else $as_nop +- ac_cv_lib_intl_textdomain=no ++else case e in #( ++ e) ac_cv_lib_intl_textdomain=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_textdomain" >&5 + printf "%s\n" "$ac_cv_lib_intl_textdomain" >&6; } +@@ -14096,11 +14693,12 @@ + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 + printf "%s\n" "yes" >&6; } + +-else $as_nop +- ++else case e in #( ++ e) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + printf "%s\n" "no" >&6; } +- ++ ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +@@ -14129,8 +14727,8 @@ + if test "$cross_compiling" = yes + then : + ac_cv_c_complex_supported=no +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -14151,11 +14749,13 @@ + if ac_fn_c_try_run "$LINENO" + then : + ac_cv_c_complex_supported=yes +-else $as_nop +- ac_cv_c_complex_supported=no ++else case e in #( ++ e) ac_cv_c_complex_supported=no ;; ++esac + fi + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + + if test "$ac_cv_c_complex_supported" = "yes"; then +@@ -14170,8 +14770,8 @@ + if test ${ac_cv_aligned_required+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test "$cross_compiling" = yes ++else case e in #( ++ e) if test "$cross_compiling" = yes + then : + + # "yes" changes the hash function to FNV, which causes problems with Numba +@@ -14181,8 +14781,8 @@ + else + ac_cv_aligned_required=yes + fi +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + int main(void) +@@ -14201,14 +14801,17 @@ + if ac_fn_c_try_run "$LINENO" + then : + ac_cv_aligned_required=no +-else $as_nop +- ac_cv_aligned_required=yes ++else case e in #( ++ e) ac_cv_aligned_required=yes ;; ++esac + fi + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_aligned_required" >&5 + printf "%s\n" "$ac_cv_aligned_required" >&6; } +@@ -14248,9 +14851,10 @@ + ;; + esac + +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: default" >&5 +-printf "%s\n" "default" >&6; } ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: default" >&5 ++printf "%s\n" "default" >&6; } ;; ++esac + fi + + +@@ -14288,10 +14892,11 @@ + ;; + esac + +-else $as_nop +- validate_tzpath "$TZPATH" ++else case e in #( ++ e) validate_tzpath "$TZPATH" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: \"$TZPATH\"" >&5 +-printf "%s\n" "\"$TZPATH\"" >&6; } ++printf "%s\n" "\"$TZPATH\"" >&6; } ;; ++esac + fi + + +@@ -14302,16 +14907,22 @@ + if test ${ac_cv_lib_nsl_t_open+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lnsl $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char t_open (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char t_open (void); + int + main (void) + { +@@ -14323,12 +14934,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_nsl_t_open=yes +-else $as_nop +- ac_cv_lib_nsl_t_open=no ++else case e in #( ++ e) ac_cv_lib_nsl_t_open=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_t_open" >&5 + printf "%s\n" "$ac_cv_lib_nsl_t_open" >&6; } +@@ -14342,16 +14955,22 @@ + if test ${ac_cv_lib_socket_socket+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lsocket $LIBS $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char socket (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char socket (void); + int + main (void) + { +@@ -14363,12 +14982,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_socket_socket=yes +-else $as_nop +- ac_cv_lib_socket_socket=no ++else case e in #( ++ e) ac_cv_lib_socket_socket=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_socket" >&5 + printf "%s\n" "$ac_cv_lib_socket_socket" >&6; } +@@ -14385,16 +15006,22 @@ + if test ${ac_cv_lib_network_socket+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lnetwork $LIBS $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char socket (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char socket (void); + int + main (void) + { +@@ -14406,12 +15033,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_network_socket=yes +-else $as_nop +- ac_cv_lib_network_socket=no ++else case e in #( ++ e) ac_cv_lib_network_socket=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_network_socket" >&5 + printf "%s\n" "$ac_cv_lib_network_socket" >&6; } +@@ -14434,9 +15063,10 @@ + printf "%s\n" "$withval" >&6; } + LIBS="$withval $LIBS" + +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +-printf "%s\n" "no" >&6; } ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++printf "%s\n" "no" >&6; } ;; ++esac + fi + + +@@ -14448,8 +15078,9 @@ + if test ${with_system_expat+y} + then : + withval=$with_system_expat; +-else $as_nop +- with_system_expat="no" ++else case e in #( ++ e) with_system_expat="no" ;; ++esac + fi + + +@@ -14463,12 +15094,13 @@ + LIBEXPAT_LDFLAGS=${LIBEXPAT_LDFLAGS-"-lexpat"} + LIBEXPAT_INTERNAL= + +-else $as_nop +- ++else case e in #( ++ e) + LIBEXPAT_CFLAGS="-I\$(srcdir)/Modules/expat" + LIBEXPAT_LDFLAGS="-lm \$(LIBEXPAT_A)" + LIBEXPAT_INTERNAL="\$(LIBEXPAT_HEADERS) \$(LIBEXPAT_A)" +- ++ ;; ++esac + fi + + +@@ -14494,16 +15126,22 @@ + if test ${ac_cv_lib_ffi_ffi_call+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lffi $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char ffi_call (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char ffi_call (void); + int + main (void) + { +@@ -14515,12 +15153,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_ffi_ffi_call=yes +-else $as_nop +- ac_cv_lib_ffi_ffi_call=no ++else case e in #( ++ e) ac_cv_lib_ffi_ffi_call=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ffi_ffi_call" >&5 + printf "%s\n" "$ac_cv_lib_ffi_ffi_call" >&6; } +@@ -14625,16 +15265,22 @@ + if test ${ac_cv_lib_ffi_ffi_call+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lffi $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char ffi_call (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char ffi_call (void); + int + main (void) + { +@@ -14646,12 +15292,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_ffi_ffi_call=yes +-else $as_nop +- ac_cv_lib_ffi_ffi_call=no ++else case e in #( ++ e) ac_cv_lib_ffi_ffi_call=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ffi_ffi_call" >&5 + printf "%s\n" "$ac_cv_lib_ffi_ffi_call" >&6; } +@@ -14662,8 +15310,9 @@ + LIBFFI_CFLAGS=${LIBFFI_CFLAGS-""} + LIBFFI_LIBS=${LIBFFI_LIBS-"-lffi"} + +-else $as_nop +- have_libffi=no ++else case e in #( ++ e) have_libffi=no ;; ++esac + fi + + +@@ -14698,16 +15347,22 @@ + if test ${ac_cv_lib_ffi_ffi_call+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lffi $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char ffi_call (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char ffi_call (void); + int + main (void) + { +@@ -14719,12 +15374,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_ffi_ffi_call=yes +-else $as_nop +- ac_cv_lib_ffi_ffi_call=no ++else case e in #( ++ e) ac_cv_lib_ffi_ffi_call=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ffi_ffi_call" >&5 + printf "%s\n" "$ac_cv_lib_ffi_ffi_call" >&6; } +@@ -14735,8 +15392,9 @@ + LIBFFI_CFLAGS=${LIBFFI_CFLAGS-""} + LIBFFI_LIBS=${LIBFFI_LIBS-"-lffi"} + +-else $as_nop +- have_libffi=no ++else case e in #( ++ e) have_libffi=no ;; ++esac + fi + + +@@ -14769,7 +15427,7 @@ + + ctypes_malloc_closure=yes + ;; #( +- iOS) : ++ iOS|tvOS|watchOS) : + + ctypes_malloc_closure=yes + ;; #( +@@ -14809,8 +15467,8 @@ + if test ${ac_cv_func_ffi_prep_cif_var+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -14824,11 +15482,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_ffi_prep_cif_var=yes +-else $as_nop +- ac_cv_func_ffi_prep_cif_var=no ++else case e in #( ++ e) ac_cv_func_ffi_prep_cif_var=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_ffi_prep_cif_var" >&5 + printf "%s\n" "$ac_cv_func_ffi_prep_cif_var" >&6; } +@@ -14848,8 +15508,8 @@ + if test ${ac_cv_func_ffi_prep_closure_loc+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -14863,11 +15523,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_ffi_prep_closure_loc=yes +-else $as_nop +- ac_cv_func_ffi_prep_closure_loc=no ++else case e in #( ++ e) ac_cv_func_ffi_prep_closure_loc=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_ffi_prep_closure_loc" >&5 + printf "%s\n" "$ac_cv_func_ffi_prep_closure_loc" >&6; } +@@ -14887,8 +15549,8 @@ + if test ${ac_cv_func_ffi_closure_alloc+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -14902,11 +15564,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_ffi_closure_alloc=yes +-else $as_nop +- ac_cv_func_ffi_closure_alloc=no ++else case e in #( ++ e) ac_cv_func_ffi_closure_alloc=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_ffi_closure_alloc" >&5 + printf "%s\n" "$ac_cv_func_ffi_closure_alloc" >&6; } +@@ -14939,21 +15603,20 @@ + if test ${ac_cv_ffi_complex_double_supported+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- save_CFLAGS=$CFLAGS ++else case e in #( ++ e) save_CFLAGS=$CFLAGS + save_CPPFLAGS=$CPPFLAGS + save_LDFLAGS=$LDFLAGS + save_LIBS=$LIBS + + +- CPPFLAGS="$LIBFFI_CFLAGS $CPPFLAGS" +- LDFLAGS="$LIBFFI_LIBS $LDFLAGS" +- LIBS="$LIBFFI_LIBS $LIBS" ++ CPPFLAGS="$CPPFLAGS $LIBFFI_CFLAGS" ++ LIBS="$LIBS $LIBFFI_LIBS" + if test "$cross_compiling" = yes + then : + ac_cv_ffi_complex_double_supported=no +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -14983,11 +15646,13 @@ + if ac_fn_c_try_run "$LINENO" + then : + ac_cv_ffi_complex_double_supported=yes +-else $as_nop +- ac_cv_ffi_complex_double_supported=no ++else case e in #( ++ e) ac_cv_ffi_complex_double_supported=no ;; ++esac + fi + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + + +@@ -14996,7 +15661,8 @@ + LDFLAGS=$save_LDFLAGS + LIBS=$save_LIBS + +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_ffi_complex_double_supported" >&5 + printf "%s\n" "$ac_cv_ffi_complex_double_supported" >&6; } +@@ -15014,8 +15680,9 @@ + if test ${with_system_libmpdec+y} + then : + withval=$with_system_libmpdec; +-else $as_nop +- with_system_libmpdec="yes" ++else case e in #( ++ e) with_system_libmpdec="yes" ;; ++esac + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_system_libmpdec" >&5 +@@ -15100,12 +15767,13 @@ + printf "%s\n" "yes" >&6; } + + fi +-else $as_nop +- LIBMPDEC_CFLAGS="-I\$(srcdir)/Modules/_decimal/libmpdec" ++else case e in #( ++ e) LIBMPDEC_CFLAGS="-I\$(srcdir)/Modules/_decimal/libmpdec" + LIBMPDEC_LIBS="-lm \$(LIBMPDEC_A)" + LIBMPDEC_INTERNAL="\$(LIBMPDEC_HEADERS) \$(LIBMPDEC_A)" + have_mpdec=yes +- with_system_libmpdec=no ++ with_system_libmpdec=no ;; ++esac + fi + + if test "x$with_system_libmpdec" = xyes +@@ -15139,8 +15807,9 @@ + if ac_fn_c_try_link "$LINENO" + then : + have_mpdec=yes +-else $as_nop +- have_mpdec=no ++else case e in #( ++ e) have_mpdec=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +@@ -15151,9 +15820,10 @@ + LIBS=$save_LIBS + + +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: the bundled copy of libmpdecimal is scheduled for removal in Python 3.15; consider using a system installed mpdecimal library." >&5 +-printf "%s\n" "$as_me: WARNING: the bundled copy of libmpdecimal is scheduled for removal in Python 3.15; consider using a system installed mpdecimal library." >&2;} ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: the bundled copy of libmpdecimal is scheduled for removal in Python 3.15; consider using a system installed mpdecimal library." >&5 ++printf "%s\n" "$as_me: WARNING: the bundled copy of libmpdecimal is scheduled for removal in Python 3.15; consider using a system installed mpdecimal library." >&2;} ;; ++esac + fi + + if test "$with_system_libmpdec" = "yes" && test "$have_mpdec" = "no" +@@ -15181,8 +15851,9 @@ + if test ${with_decimal_contextvar+y} + then : + withval=$with_decimal_contextvar; +-else $as_nop +- with_decimal_contextvar="yes" ++else case e in #( ++ e) with_decimal_contextvar="yes" ;; ++esac + fi + + +@@ -15420,16 +16091,22 @@ + if test ${ac_cv_lib_sqlite3_sqlite3_bind_double+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lsqlite3 $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char sqlite3_bind_double (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char sqlite3_bind_double (void); + int + main (void) + { +@@ -15441,12 +16118,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_sqlite3_sqlite3_bind_double=yes +-else $as_nop +- ac_cv_lib_sqlite3_sqlite3_bind_double=no ++else case e in #( ++ e) ac_cv_lib_sqlite3_sqlite3_bind_double=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_bind_double" >&5 + printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_bind_double" >&6; } +@@ -15456,10 +16135,11 @@ + + LIBS="-lsqlite3 $LIBS" + +-else $as_nop +- ++else case e in #( ++ e) + have_supported_sqlite3=no +- ++ ;; ++esac + fi + + +@@ -15469,16 +16149,22 @@ + if test ${ac_cv_lib_sqlite3_sqlite3_column_decltype+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lsqlite3 $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char sqlite3_column_decltype (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char sqlite3_column_decltype (void); + int + main (void) + { +@@ -15490,12 +16176,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_sqlite3_sqlite3_column_decltype=yes +-else $as_nop +- ac_cv_lib_sqlite3_sqlite3_column_decltype=no ++else case e in #( ++ e) ac_cv_lib_sqlite3_sqlite3_column_decltype=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_column_decltype" >&5 + printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_column_decltype" >&6; } +@@ -15505,10 +16193,11 @@ + + LIBS="-lsqlite3 $LIBS" + +-else $as_nop +- ++else case e in #( ++ e) + have_supported_sqlite3=no +- ++ ;; ++esac + fi + + +@@ -15518,16 +16207,22 @@ + if test ${ac_cv_lib_sqlite3_sqlite3_column_double+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lsqlite3 $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char sqlite3_column_double (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char sqlite3_column_double (void); + int + main (void) + { +@@ -15539,12 +16234,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_sqlite3_sqlite3_column_double=yes +-else $as_nop +- ac_cv_lib_sqlite3_sqlite3_column_double=no ++else case e in #( ++ e) ac_cv_lib_sqlite3_sqlite3_column_double=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_column_double" >&5 + printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_column_double" >&6; } +@@ -15554,10 +16251,11 @@ + + LIBS="-lsqlite3 $LIBS" + +-else $as_nop +- ++else case e in #( ++ e) + have_supported_sqlite3=no +- ++ ;; ++esac + fi + + +@@ -15567,16 +16265,22 @@ + if test ${ac_cv_lib_sqlite3_sqlite3_complete+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lsqlite3 $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char sqlite3_complete (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char sqlite3_complete (void); + int + main (void) + { +@@ -15588,12 +16292,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_sqlite3_sqlite3_complete=yes +-else $as_nop +- ac_cv_lib_sqlite3_sqlite3_complete=no ++else case e in #( ++ e) ac_cv_lib_sqlite3_sqlite3_complete=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_complete" >&5 + printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_complete" >&6; } +@@ -15603,10 +16309,11 @@ + + LIBS="-lsqlite3 $LIBS" + +-else $as_nop +- ++else case e in #( ++ e) + have_supported_sqlite3=no +- ++ ;; ++esac + fi + + +@@ -15616,16 +16323,22 @@ + if test ${ac_cv_lib_sqlite3_sqlite3_progress_handler+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lsqlite3 $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char sqlite3_progress_handler (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char sqlite3_progress_handler (void); + int + main (void) + { +@@ -15637,12 +16350,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_sqlite3_sqlite3_progress_handler=yes +-else $as_nop +- ac_cv_lib_sqlite3_sqlite3_progress_handler=no ++else case e in #( ++ e) ac_cv_lib_sqlite3_sqlite3_progress_handler=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_progress_handler" >&5 + printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_progress_handler" >&6; } +@@ -15652,10 +16367,11 @@ + + LIBS="-lsqlite3 $LIBS" + +-else $as_nop +- ++else case e in #( ++ e) + have_supported_sqlite3=no +- ++ ;; ++esac + fi + + +@@ -15665,16 +16381,22 @@ + if test ${ac_cv_lib_sqlite3_sqlite3_result_double+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lsqlite3 $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char sqlite3_result_double (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char sqlite3_result_double (void); + int + main (void) + { +@@ -15686,12 +16408,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_sqlite3_sqlite3_result_double=yes +-else $as_nop +- ac_cv_lib_sqlite3_sqlite3_result_double=no ++else case e in #( ++ e) ac_cv_lib_sqlite3_sqlite3_result_double=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_result_double" >&5 + printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_result_double" >&6; } +@@ -15701,10 +16425,11 @@ + + LIBS="-lsqlite3 $LIBS" + +-else $as_nop +- ++else case e in #( ++ e) + have_supported_sqlite3=no +- ++ ;; ++esac + fi + + +@@ -15714,16 +16439,22 @@ + if test ${ac_cv_lib_sqlite3_sqlite3_set_authorizer+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lsqlite3 $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char sqlite3_set_authorizer (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char sqlite3_set_authorizer (void); + int + main (void) + { +@@ -15735,12 +16466,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_sqlite3_sqlite3_set_authorizer=yes +-else $as_nop +- ac_cv_lib_sqlite3_sqlite3_set_authorizer=no ++else case e in #( ++ e) ac_cv_lib_sqlite3_sqlite3_set_authorizer=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_set_authorizer" >&5 + printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_set_authorizer" >&6; } +@@ -15750,10 +16483,11 @@ + + LIBS="-lsqlite3 $LIBS" + +-else $as_nop +- ++else case e in #( ++ e) + have_supported_sqlite3=no +- ++ ;; ++esac + fi + + +@@ -15763,16 +16497,22 @@ + if test ${ac_cv_lib_sqlite3_sqlite3_trace_v2+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lsqlite3 $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char sqlite3_trace_v2 (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char sqlite3_trace_v2 (void); + int + main (void) + { +@@ -15784,12 +16524,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_sqlite3_sqlite3_trace_v2=yes +-else $as_nop +- ac_cv_lib_sqlite3_sqlite3_trace_v2=no ++else case e in #( ++ e) ac_cv_lib_sqlite3_sqlite3_trace_v2=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_trace_v2" >&5 + printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_trace_v2" >&6; } +@@ -15799,8 +16541,8 @@ + + LIBS="-lsqlite3 $LIBS" + +-else $as_nop +- ++else case e in #( ++ e) + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sqlite3_trace in -lsqlite3" >&5 +@@ -15808,16 +16550,22 @@ + if test ${ac_cv_lib_sqlite3_sqlite3_trace+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lsqlite3 $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char sqlite3_trace (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char sqlite3_trace (void); + int + main (void) + { +@@ -15829,12 +16577,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_sqlite3_sqlite3_trace=yes +-else $as_nop +- ac_cv_lib_sqlite3_sqlite3_trace=no ++else case e in #( ++ e) ac_cv_lib_sqlite3_sqlite3_trace=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_trace" >&5 + printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_trace" >&6; } +@@ -15844,15 +16594,17 @@ + + LIBS="-lsqlite3 $LIBS" + +-else $as_nop +- ++else case e in #( ++ e) + have_supported_sqlite3=no +- ++ ;; ++esac + fi + + + +- ++ ;; ++esac + fi + + +@@ -15862,16 +16614,22 @@ + if test ${ac_cv_lib_sqlite3_sqlite3_value_double+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lsqlite3 $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char sqlite3_value_double (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char sqlite3_value_double (void); + int + main (void) + { +@@ -15883,12 +16641,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_sqlite3_sqlite3_value_double=yes +-else $as_nop +- ac_cv_lib_sqlite3_sqlite3_value_double=no ++else case e in #( ++ e) ac_cv_lib_sqlite3_sqlite3_value_double=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_value_double" >&5 + printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_value_double" >&6; } +@@ -15898,10 +16658,11 @@ + + LIBS="-lsqlite3 $LIBS" + +-else $as_nop +- ++else case e in #( ++ e) + have_supported_sqlite3=no +- ++ ;; ++esac + fi + + +@@ -15910,16 +16671,22 @@ + if test ${ac_cv_lib_sqlite3_sqlite3_load_extension+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lsqlite3 $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char sqlite3_load_extension (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char sqlite3_load_extension (void); + int + main (void) + { +@@ -15931,21 +16698,24 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_sqlite3_sqlite3_load_extension=yes +-else $as_nop +- ac_cv_lib_sqlite3_sqlite3_load_extension=no ++else case e in #( ++ e) ac_cv_lib_sqlite3_sqlite3_load_extension=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_load_extension" >&5 + printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_load_extension" >&6; } + if test "x$ac_cv_lib_sqlite3_sqlite3_load_extension" = xyes + then : + have_sqlite3_load_extension=yes +-else $as_nop +- have_sqlite3_load_extension=no +- ++else case e in #( ++ e) have_sqlite3_load_extension=no ++ ;; ++esac + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sqlite3_serialize in -lsqlite3" >&5 +@@ -15953,16 +16723,22 @@ + if test ${ac_cv_lib_sqlite3_sqlite3_serialize+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lsqlite3 $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char sqlite3_serialize (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char sqlite3_serialize (void); + int + main (void) + { +@@ -15974,12 +16750,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_sqlite3_sqlite3_serialize=yes +-else $as_nop +- ac_cv_lib_sqlite3_sqlite3_serialize=no ++else case e in #( ++ e) ac_cv_lib_sqlite3_sqlite3_serialize=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_serialize" >&5 + printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_serialize" >&6; } +@@ -15993,10 +16771,11 @@ + fi + + +-else $as_nop +- ++else case e in #( ++ e) + have_supported_sqlite3=no +- ++ ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + +@@ -16024,22 +16803,24 @@ + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Your version of SQLite does not support loadable extensions" >&5 + printf "%s\n" "$as_me: WARNING: Your version of SQLite does not support loadable extensions" >&2;} + +-else $as_nop +- ++else case e in #( ++ e) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 + printf "%s\n" "yes" >&6; } + + printf "%s\n" "#define PY_SQLITE_ENABLE_LOAD_EXTENSION 1" >>confdefs.h + +- ++ ;; ++esac + fi + +-else $as_nop +- ++else case e in #( ++ e) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + printf "%s\n" "no" >&6; } + +- ++ ;; ++esac + fi + + +@@ -16227,8 +17008,8 @@ + elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + printf "%s\n" "no" >&6; } +- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it + is in your PATH or set the PKG_CONFIG environment variable to the full + path to pkg-config. +@@ -16238,7 +17019,7 @@ + See the pkg-config man page for more details. + + To get pkg-config, see . +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } + else + X11_CFLAGS=$pkg_cv_X11_CFLAGS + X11_LIBS=$pkg_cv_X11_LIBS +@@ -16306,10 +17087,11 @@ + have_tcltk=yes + as_fn_append TCLTK_CFLAGS " -Wno-strict-prototypes -DWITH_APPINIT=1" + +-else $as_nop +- ++else case e in #( ++ e) + have_tcltk=no +- ++ ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +@@ -16343,16 +17125,22 @@ + if test ${ac_cv_lib_gdbm_gdbm_open+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lgdbm $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char gdbm_open (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char gdbm_open (void); + int + main (void) + { +@@ -16364,12 +17152,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_gdbm_gdbm_open=yes +-else $as_nop +- ac_cv_lib_gdbm_gdbm_open=no ++else case e in #( ++ e) ac_cv_lib_gdbm_gdbm_open=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gdbm_gdbm_open" >&5 + printf "%s\n" "$ac_cv_lib_gdbm_gdbm_open" >&6; } +@@ -16379,13 +17169,15 @@ + have_gdbm=yes + GDBM_LIBS=${GDBM_LIBS-"-lgdbm"} + +-else $as_nop +- have_gdbm=no ++else case e in #( ++ e) have_gdbm=no ;; ++esac + fi + + +-else $as_nop +- have_gdbm=no ++else case e in #( ++ e) have_gdbm=no ;; ++esac + fi + + done +@@ -16415,15 +17207,21 @@ + if test ${ac_cv_search_dbm_open+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_func_search_save_LIBS=$LIBS ++else case e in #( ++ e) ac_func_search_save_LIBS=$LIBS + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char dbm_open (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char dbm_open (void); + int + main (void) + { +@@ -16454,11 +17252,13 @@ + if test ${ac_cv_search_dbm_open+y} + then : + +-else $as_nop +- ac_cv_search_dbm_open=no ++else case e in #( ++ e) ac_cv_search_dbm_open=no ;; ++esac + fi + rm conftest.$ac_ext +-LIBS=$ac_func_search_save_LIBS ++LIBS=$ac_func_search_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dbm_open" >&5 + printf "%s\n" "$ac_cv_search_dbm_open" >&6; } +@@ -16503,24 +17303,28 @@ + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $have_ndbm ($dbm_ndbm)" >&5 + printf "%s\n" "$have_ndbm ($dbm_ndbm)" >&6; } + +-{ ac_cv_header_gdbm_ndbm_h=; unset ac_cv_header_gdbm_ndbm_h;} ++{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gdbm/ndbm.h" >&5 ++printf %s "checking for gdbm/ndbm.h... " >&6; } + if test ${ac_cv_header_gdbm_slash_ndbm_h+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- +- ac_fn_c_check_header_compile "$LINENO" "gdbm/ndbm.h" "ac_cv_header_gdbm_ndbm_h" "$ac_includes_default" +-if test "x$ac_cv_header_gdbm_ndbm_h" = xyes ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#include ++_ACEOF ++if ac_fn_c_try_cpp "$LINENO" + then : + ac_cv_header_gdbm_slash_ndbm_h=yes +-else $as_nop +- ac_cv_header_gdbm_slash_ndbm_h=no +- ++else case e in #( ++ e) ac_cv_header_gdbm_slash_ndbm_h=no ;; ++esac + fi +- +- ++rm -f conftest.err conftest.i conftest.$ac_ext ;; ++esac + fi +- ++{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_gdbm_slash_ndbm_h" >&5 ++printf "%s\n" "$ac_cv_header_gdbm_slash_ndbm_h" >&6; } + if test "x$ac_cv_header_gdbm_slash_ndbm_h" = xyes + then : + +@@ -16530,24 +17334,28 @@ + + fi + +-{ ac_cv_header_gdbm_ndbm_h=; unset ac_cv_header_gdbm_ndbm_h;} ++{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gdbm-ndbm.h" >&5 ++printf %s "checking for gdbm-ndbm.h... " >&6; } + if test ${ac_cv_header_gdbm_dash_ndbm_h+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- +- ac_fn_c_check_header_compile "$LINENO" "gdbm-ndbm.h" "ac_cv_header_gdbm_ndbm_h" "$ac_includes_default" +-if test "x$ac_cv_header_gdbm_ndbm_h" = xyes ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#include ++_ACEOF ++if ac_fn_c_try_cpp "$LINENO" + then : + ac_cv_header_gdbm_dash_ndbm_h=yes +-else $as_nop +- ac_cv_header_gdbm_dash_ndbm_h=no +- ++else case e in #( ++ e) ac_cv_header_gdbm_dash_ndbm_h=no ;; ++esac + fi +- +- ++rm -f conftest.err conftest.i conftest.$ac_ext ;; ++esac + fi +- ++{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_gdbm_dash_ndbm_h" >&5 ++printf "%s\n" "$ac_cv_header_gdbm_dash_ndbm_h" >&6; } + if test "x$ac_cv_header_gdbm_dash_ndbm_h" = xyes + then : + +@@ -16556,7 +17364,6 @@ + + + fi +-{ ac_cv_header_gdbm_ndbm_h=; unset ac_cv_header_gdbm_ndbm_h;} + + if test "$ac_cv_header_gdbm_slash_ndbm_h" = yes -o "$ac_cv_header_gdbm_dash_ndbm_h" = yes; then + { ac_cv_search_dbm_open=; unset ac_cv_search_dbm_open;} +@@ -16571,15 +17378,21 @@ + if test ${ac_cv_search_dbm_open+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_func_search_save_LIBS=$LIBS ++else case e in #( ++ e) ac_func_search_save_LIBS=$LIBS + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char dbm_open (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char dbm_open (void); + int + main (void) + { +@@ -16610,11 +17423,13 @@ + if test ${ac_cv_search_dbm_open+y} + then : + +-else $as_nop +- ac_cv_search_dbm_open=no ++else case e in #( ++ e) ac_cv_search_dbm_open=no ;; ++esac + fi + rm conftest.$ac_ext +-LIBS=$ac_func_search_save_LIBS ++LIBS=$ac_func_search_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dbm_open" >&5 + printf "%s\n" "$ac_cv_search_dbm_open" >&6; } +@@ -16623,8 +17438,9 @@ + then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + have_gdbm_compat=yes +-else $as_nop +- have_gdbm_compat=no ++else case e in #( ++ e) have_gdbm_compat=no ;; ++esac + fi + + +@@ -16650,8 +17466,8 @@ + if test ${ac_cv_have_libdb+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + save_CFLAGS=$CFLAGS + save_CPPFLAGS=$CPPFLAGS + save_LDFLAGS=$LDFLAGS +@@ -16680,8 +17496,9 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_have_libdb=yes +-else $as_nop +- ac_cv_have_libdb=no ++else case e in #( ++ e) ac_cv_have_libdb=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +@@ -16692,7 +17509,8 @@ + LIBS=$save_LIBS + + +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_libdb" >&5 + printf "%s\n" "$ac_cv_have_libdb" >&6; } +@@ -16717,8 +17535,9 @@ + if test ${with_dbmliborder+y} + then : + withval=$with_dbmliborder; +-else $as_nop +- with_dbmliborder=gdbm:ndbm:bdb ++else case e in #( ++ e) with_dbmliborder=gdbm:ndbm:bdb ;; ++esac + fi + + +@@ -16835,8 +17654,8 @@ + if test ${ac_cv_defined__POSIX_THREADS_unistd_h+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -16857,18 +17676,21 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_defined__POSIX_THREADS_unistd_h=yes +-else $as_nop +- ac_cv_defined__POSIX_THREADS_unistd_h=no ++else case e in #( ++ e) ac_cv_defined__POSIX_THREADS_unistd_h=no ;; ++esac + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_defined__POSIX_THREADS_unistd_h" >&5 + printf "%s\n" "$ac_cv_defined__POSIX_THREADS_unistd_h" >&6; } + if test $ac_cv_defined__POSIX_THREADS_unistd_h != "no" + then : + unistd_defines_pthreads=yes +-else $as_nop +- unistd_defines_pthreads=no ++else case e in #( ++ e) unistd_defines_pthreads=no ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $unistd_defines_pthreads" >&5 + printf "%s\n" "$unistd_defines_pthreads" >&6; } +@@ -16906,8 +17728,8 @@ + printf "%s\n" "yes" >&6; } + posix_threads=yes + +-else $as_nop +- ++else case e in #( ++ e) + LIBS=$_libs + ac_fn_c_check_func "$LINENO" "pthread_detach" "ac_cv_func_pthread_detach" + if test "x$ac_cv_func_pthread_detach" = xyes +@@ -16915,23 +17737,29 @@ + + posix_threads=yes + +-else $as_nop +- ++else case e in #( ++ e) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthreads" >&5 + printf %s "checking for pthread_create in -lpthreads... " >&6; } + if test ${ac_cv_lib_pthreads_pthread_create+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lpthreads $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char pthread_create (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char pthread_create (void); + int + main (void) + { +@@ -16943,12 +17771,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_pthreads_pthread_create=yes +-else $as_nop +- ac_cv_lib_pthreads_pthread_create=no ++else case e in #( ++ e) ac_cv_lib_pthreads_pthread_create=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthreads_pthread_create" >&5 + printf "%s\n" "$ac_cv_lib_pthreads_pthread_create" >&6; } +@@ -16958,23 +17788,29 @@ + posix_threads=yes + LIBS="$LIBS -lpthreads" + +-else $as_nop +- ++else case e in #( ++ e) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lc_r" >&5 + printf %s "checking for pthread_create in -lc_r... " >&6; } + if test ${ac_cv_lib_c_r_pthread_create+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lc_r $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char pthread_create (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char pthread_create (void); + int + main (void) + { +@@ -16986,12 +17822,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_c_r_pthread_create=yes +-else $as_nop +- ac_cv_lib_c_r_pthread_create=no ++else case e in #( ++ e) ac_cv_lib_c_r_pthread_create=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_create" >&5 + printf "%s\n" "$ac_cv_lib_c_r_pthread_create" >&6; } +@@ -17001,23 +17839,29 @@ + posix_threads=yes + LIBS="$LIBS -lc_r" + +-else $as_nop +- ++else case e in #( ++ e) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __pthread_create_system in -lpthread" >&5 + printf %s "checking for __pthread_create_system in -lpthread... " >&6; } + if test ${ac_cv_lib_pthread___pthread_create_system+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lpthread $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char __pthread_create_system (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char __pthread_create_system (void); + int + main (void) + { +@@ -17029,12 +17873,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_pthread___pthread_create_system=yes +-else $as_nop +- ac_cv_lib_pthread___pthread_create_system=no ++else case e in #( ++ e) ac_cv_lib_pthread___pthread_create_system=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread___pthread_create_system" >&5 + printf "%s\n" "$ac_cv_lib_pthread___pthread_create_system" >&6; } +@@ -17044,23 +17890,29 @@ + posix_threads=yes + LIBS="$LIBS -lpthread" + +-else $as_nop +- ++else case e in #( ++ e) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lcma" >&5 + printf %s "checking for pthread_create in -lcma... " >&6; } + if test ${ac_cv_lib_cma_pthread_create+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lcma $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char pthread_create (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char pthread_create (void); + int + main (void) + { +@@ -17072,12 +17924,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_cma_pthread_create=yes +-else $as_nop +- ac_cv_lib_cma_pthread_create=no ++else case e in #( ++ e) ac_cv_lib_cma_pthread_create=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cma_pthread_create" >&5 + printf "%s\n" "$ac_cv_lib_cma_pthread_create" >&6; } +@@ -17087,8 +17941,8 @@ + posix_threads=yes + LIBS="$LIBS -lcma" + +-else $as_nop +- ++else case e in #( ++ e) + case $ac_sys_system in #( + WASI) : + posix_threads=stub ;; #( +@@ -17096,17 +17950,23 @@ + as_fn_error $? "could not find pthreads on your system" "$LINENO" 5 + ;; + esac +- ++ ;; ++esac + fi +- ++ ;; ++esac + fi +- ++ ;; ++esac + fi +- ++ ;; ++esac + fi +- ++ ;; ++esac + fi +- ++ ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +@@ -17116,16 +17976,22 @@ + if test ${ac_cv_lib_mpc_usconfig+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lmpc $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char usconfig (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char usconfig (void); + int + main (void) + { +@@ -17137,12 +18003,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_mpc_usconfig=yes +-else $as_nop +- ac_cv_lib_mpc_usconfig=no ++else case e in #( ++ e) ac_cv_lib_mpc_usconfig=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mpc_usconfig" >&5 + printf "%s\n" "$ac_cv_lib_mpc_usconfig" >&6; } +@@ -17188,12 +18056,12 @@ + if test ${ac_cv_pthread_system_supported+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test "$cross_compiling" = yes ++else case e in #( ++ e) if test "$cross_compiling" = yes + then : + ac_cv_pthread_system_supported=no +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -17213,14 +18081,17 @@ + if ac_fn_c_try_run "$LINENO" + then : + ac_cv_pthread_system_supported=yes +-else $as_nop +- ac_cv_pthread_system_supported=no ++else case e in #( ++ e) ac_cv_pthread_system_supported=no ;; ++esac + fi + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_pthread_system_supported" >&5 + printf "%s\n" "$ac_cv_pthread_system_supported" >&6; } +@@ -17284,8 +18155,8 @@ + ipv6=yes + ;; + esac +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + /* AF_INET6 available check */ +@@ -17304,10 +18175,11 @@ + + ipv6=yes + +-else $as_nop +- ++else case e in #( ++ e) + ipv6=no +- ++ ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + +@@ -17347,12 +18219,13 @@ + printf "%s\n" "yes" >&6; } + ipv6=yes + +-else $as_nop +- ++else case e in #( ++ e) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + printf "%s\n" "no" >&6; } + ipv6=no +- ++ ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi +@@ -17361,7 +18234,8 @@ + printf "%s\n" "#define ENABLE_IPV6 1" >>confdefs.h + + fi +- ++ ;; ++esac + fi + + +@@ -17380,8 +18254,8 @@ + if test ${ac_cv_defined_IPV6_INRIA_VERSION_netinet_in_h+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -17402,10 +18276,12 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_defined_IPV6_INRIA_VERSION_netinet_in_h=yes +-else $as_nop +- ac_cv_defined_IPV6_INRIA_VERSION_netinet_in_h=no ++else case e in #( ++ e) ac_cv_defined_IPV6_INRIA_VERSION_netinet_in_h=no ;; ++esac + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_defined_IPV6_INRIA_VERSION_netinet_in_h" >&5 + printf "%s\n" "$ac_cv_defined_IPV6_INRIA_VERSION_netinet_in_h" >&6; } +@@ -17421,8 +18297,8 @@ + if test ${ac_cv_defined___KAME___netinet_in_h+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -17443,10 +18319,12 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_defined___KAME___netinet_in_h=yes +-else $as_nop +- ac_cv_defined___KAME___netinet_in_h=no ++else case e in #( ++ e) ac_cv_defined___KAME___netinet_in_h=no ;; ++esac + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_defined___KAME___netinet_in_h" >&5 + printf "%s\n" "$ac_cv_defined___KAME___netinet_in_h" >&6; } +@@ -17465,8 +18343,8 @@ + if test ${ac_cv_defined___GLIBC___features_h+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -17487,10 +18365,12 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_defined___GLIBC___features_h=yes +-else $as_nop +- ac_cv_defined___GLIBC___features_h=no ++else case e in #( ++ e) ac_cv_defined___GLIBC___features_h=no ;; ++esac + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_defined___GLIBC___features_h" >&5 + printf "%s\n" "$ac_cv_defined___GLIBC___features_h" >&6; } +@@ -17523,8 +18403,8 @@ + if test ${ac_cv_defined__TOSHIBA_INET6_sys_param_h+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -17545,10 +18425,12 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_defined__TOSHIBA_INET6_sys_param_h=yes +-else $as_nop +- ac_cv_defined__TOSHIBA_INET6_sys_param_h=no ++else case e in #( ++ e) ac_cv_defined__TOSHIBA_INET6_sys_param_h=no ;; ++esac + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_defined__TOSHIBA_INET6_sys_param_h" >&5 + printf "%s\n" "$ac_cv_defined__TOSHIBA_INET6_sys_param_h" >&6; } +@@ -17566,8 +18448,8 @@ + if test ${ac_cv_defined___V6D____usr_local_v6_include_sys_v6config_h+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -17588,10 +18470,12 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_defined___V6D____usr_local_v6_include_sys_v6config_h=yes +-else $as_nop +- ac_cv_defined___V6D____usr_local_v6_include_sys_v6config_h=no ++else case e in #( ++ e) ac_cv_defined___V6D____usr_local_v6_include_sys_v6config_h=no ;; ++esac + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_defined___V6D____usr_local_v6_include_sys_v6config_h" >&5 + printf "%s\n" "$ac_cv_defined___V6D____usr_local_v6_include_sys_v6config_h" >&6; } +@@ -17610,8 +18494,8 @@ + if test ${ac_cv_defined__ZETA_MINAMI_INET6_sys_param_h+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -17632,10 +18516,12 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_defined__ZETA_MINAMI_INET6_sys_param_h=yes +-else $as_nop +- ac_cv_defined__ZETA_MINAMI_INET6_sys_param_h=no ++else case e in #( ++ e) ac_cv_defined__ZETA_MINAMI_INET6_sys_param_h=no ;; ++esac + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_defined__ZETA_MINAMI_INET6_sys_param_h" >&5 + printf "%s\n" "$ac_cv_defined__ZETA_MINAMI_INET6_sys_param_h" >&6; } +@@ -17671,10 +18557,11 @@ + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: libc" >&5 + printf "%s\n" "libc" >&6; } + +-else $as_nop +- ++else case e in #( ++ e) + as_fn_error $? "No $ipv6lib library found; cannot continue. You need to fetch lib$ipv6lib.a from appropriate ipv6 kit and compile beforehand." "$LINENO" 5 +- ++ ;; ++esac + fi + fi + fi +@@ -17685,8 +18572,8 @@ + if test ${ac_cv_can_raw_fd_frames+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + /* CAN_RAW_FD_FRAMES available check */ +@@ -17702,11 +18589,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_can_raw_fd_frames=yes +-else $as_nop +- ac_cv_can_raw_fd_frames=no ++else case e in #( ++ e) ac_cv_can_raw_fd_frames=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_can_raw_fd_frames" >&5 + printf "%s\n" "$ac_cv_can_raw_fd_frames" >&6; } +@@ -17724,8 +18613,8 @@ + if test ${ac_cv_can_raw_join_filters+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + +@@ -17741,11 +18630,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_can_raw_join_filters=yes +-else $as_nop +- ac_cv_can_raw_join_filters=no ++else case e in #( ++ e) ac_cv_can_raw_join_filters=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_can_raw_join_filters" >&5 + printf "%s\n" "$ac_cv_can_raw_join_filters" >&6; } +@@ -17787,8 +18678,8 @@ + if test ${ac_cv_header_stdatomic_h+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + +@@ -17808,12 +18699,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_header_stdatomic_h=yes +-else $as_nop +- ac_cv_header_stdatomic_h=no ++else case e in #( ++ e) ac_cv_header_stdatomic_h=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdatomic_h" >&5 + printf "%s\n" "$ac_cv_header_stdatomic_h" >&6; } +@@ -17833,8 +18726,8 @@ + if test ${ac_cv_builtin_atomic+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + +@@ -17851,12 +18744,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_builtin_atomic=yes +-else $as_nop +- ac_cv_builtin_atomic=no ++else case e in #( ++ e) ac_cv_builtin_atomic=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_builtin_atomic" >&5 + printf "%s\n" "$ac_cv_builtin_atomic" >&6; } +@@ -17878,9 +18773,10 @@ + if test ${with_mimalloc+y} + then : + withval=$with_mimalloc; +-else $as_nop +- with_mimalloc="$ac_cv_header_stdatomic_h" +- ++else case e in #( ++ e) with_mimalloc="$ac_cv_header_stdatomic_h" ++ ;; ++esac + fi + + +@@ -17969,9 +18865,10 @@ + if test ${with_valgrind+y} + then : + withval=$with_valgrind; +-else $as_nop +- with_valgrind=no +- ++else case e in #( ++ e) with_valgrind=no ++ ;; ++esac + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_valgrind" >&5 +@@ -17983,9 +18880,10 @@ + + printf "%s\n" "#define WITH_VALGRIND 1" >>confdefs.h + +-else $as_nop +- as_fn_error $? "Valgrind support requested but headers not available" "$LINENO" 5 +- ++else case e in #( ++ e) as_fn_error $? "Valgrind support requested but headers not available" "$LINENO" 5 ++ ;; ++esac + fi + + OPT="-DDYNAMIC_ANNOTATIONS_ENABLED=1 $OPT" +@@ -17999,8 +18897,9 @@ + if test ${with_dtrace+y} + then : + withval=$with_dtrace; +-else $as_nop +- with_dtrace=no ++else case e in #( ++ e) with_dtrace=no ;; ++esac + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_dtrace" >&5 +@@ -18023,8 +18922,8 @@ + if test ${ac_cv_path_DTRACE+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- case $DTRACE in ++else case e in #( ++ e) case $DTRACE in + [\\/]* | ?:[\\/]*) + ac_cv_path_DTRACE="$DTRACE" # Let the user override the test with a path. + ;; +@@ -18050,6 +18949,7 @@ + + test -z "$ac_cv_path_DTRACE" && ac_cv_path_DTRACE="not found" + ;; ++esac ;; + esac + fi + DTRACE=$ac_cv_path_DTRACE +@@ -18079,12 +18979,13 @@ + if test ${ac_cv_dtrace_link+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_cv_dtrace_link=no ++else case e in #( ++ e) ac_cv_dtrace_link=no + echo 'BEGIN{}' > conftest.d + "$DTRACE" $DFLAGS -G -s conftest.d -o conftest.o > /dev/null 2>&1 && \ + ac_cv_dtrace_link=yes +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_dtrace_link" >&5 + printf "%s\n" "$ac_cv_dtrace_link" >&6; } +@@ -18187,7 +19088,7 @@ + fi + + for name in $blocked_funcs; do +- as_func_var=`printf "%s\n" "ac_cv_func_$name" | $as_tr_sh` ++ as_func_var=`printf "%s\n" "ac_cv_func_$name" | sed "$as_sed_sh"` + + eval "$as_func_var=no" + +@@ -18260,6 +19161,12 @@ + then : + printf "%s\n" "#define HAVE_CTERMID 1" >>confdefs.h + ++fi ++ac_fn_c_check_func "$LINENO" "dladdr" "ac_cv_func_dladdr" ++if test "x$ac_cv_func_dladdr" = xyes ++then : ++ printf "%s\n" "#define HAVE_DLADDR 1" >>confdefs.h ++ + fi + ac_fn_c_check_func "$LINENO" "dup" "ac_cv_func_dup" + if test "x$ac_cv_func_dup" = xyes +@@ -18272,12 +19179,6 @@ + then : + printf "%s\n" "#define HAVE_DUP3 1" >>confdefs.h + +-fi +-ac_fn_c_check_func "$LINENO" "execv" "ac_cv_func_execv" +-if test "x$ac_cv_func_execv" = xyes +-then : +- printf "%s\n" "#define HAVE_EXECV 1" >>confdefs.h +- + fi + ac_fn_c_check_func "$LINENO" "explicit_bzero" "ac_cv_func_explicit_bzero" + if test "x$ac_cv_func_explicit_bzero" = xyes +@@ -18338,18 +19239,6 @@ + then : + printf "%s\n" "#define HAVE_FEXECVE 1" >>confdefs.h + +-fi +-ac_fn_c_check_func "$LINENO" "fork" "ac_cv_func_fork" +-if test "x$ac_cv_func_fork" = xyes +-then : +- printf "%s\n" "#define HAVE_FORK 1" >>confdefs.h +- +-fi +-ac_fn_c_check_func "$LINENO" "fork1" "ac_cv_func_fork1" +-if test "x$ac_cv_func_fork1" = xyes +-then : +- printf "%s\n" "#define HAVE_FORK1 1" >>confdefs.h +- + fi + ac_fn_c_check_func "$LINENO" "fpathconf" "ac_cv_func_fpathconf" + if test "x$ac_cv_func_fpathconf" = xyes +@@ -18776,24 +19665,6 @@ + then : + printf "%s\n" "#define HAVE_POSIX_OPENPT 1" >>confdefs.h + +-fi +-ac_fn_c_check_func "$LINENO" "posix_spawn" "ac_cv_func_posix_spawn" +-if test "x$ac_cv_func_posix_spawn" = xyes +-then : +- printf "%s\n" "#define HAVE_POSIX_SPAWN 1" >>confdefs.h +- +-fi +-ac_fn_c_check_func "$LINENO" "posix_spawnp" "ac_cv_func_posix_spawnp" +-if test "x$ac_cv_func_posix_spawnp" = xyes +-then : +- printf "%s\n" "#define HAVE_POSIX_SPAWNP 1" >>confdefs.h +- +-fi +-ac_fn_c_check_func "$LINENO" "posix_spawn_file_actions_addclosefrom_np" "ac_cv_func_posix_spawn_file_actions_addclosefrom_np" +-if test "x$ac_cv_func_posix_spawn_file_actions_addclosefrom_np" = xyes +-then : +- printf "%s\n" "#define HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP 1" >>confdefs.h +- + fi + ac_fn_c_check_func "$LINENO" "pread" "ac_cv_func_pread" + if test "x$ac_cv_func_pread" = xyes +@@ -19094,12 +19965,6 @@ + then : + printf "%s\n" "#define HAVE_SIGACTION 1" >>confdefs.h + +-fi +-ac_fn_c_check_func "$LINENO" "sigaltstack" "ac_cv_func_sigaltstack" +-if test "x$ac_cv_func_sigaltstack" = xyes +-then : +- printf "%s\n" "#define HAVE_SIGALTSTACK 1" >>confdefs.h +- + fi + ac_fn_c_check_func "$LINENO" "sigfillset" "ac_cv_func_sigfillset" + if test "x$ac_cv_func_sigfillset" = xyes +@@ -19368,11 +20233,11 @@ + + fi + +-# iOS defines some system methods that can be linked (so they are ++# iOS/tvOS/watchOS define some system methods that can be linked (so they are + # found by configure), but either raise a compilation error (because the + # header definition prevents usage - autoconf doesn't use the headers), or + # raise an error if used at runtime. Force these symbols off. +-if test "$ac_sys_system" != "iOS" ; then ++if test "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then + ac_fn_c_check_func "$LINENO" "getentropy" "ac_cv_func_getentropy" + if test "x$ac_cv_func_getentropy" = xyes + then : +@@ -19394,13 +20259,60 @@ + + fi + ++# tvOS/watchOS have some additional methods that can be found, but not used. ++if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then ++ ac_fn_c_check_func "$LINENO" "execv" "ac_cv_func_execv" ++if test "x$ac_cv_func_execv" = xyes ++then : ++ printf "%s\n" "#define HAVE_EXECV 1" >>confdefs.h ++ ++fi ++ac_fn_c_check_func "$LINENO" "fork" "ac_cv_func_fork" ++if test "x$ac_cv_func_fork" = xyes ++then : ++ printf "%s\n" "#define HAVE_FORK 1" >>confdefs.h ++ ++fi ++ac_fn_c_check_func "$LINENO" "fork1" "ac_cv_func_fork1" ++if test "x$ac_cv_func_fork1" = xyes ++then : ++ printf "%s\n" "#define HAVE_FORK1 1" >>confdefs.h ++ ++fi ++ac_fn_c_check_func "$LINENO" "posix_spawn" "ac_cv_func_posix_spawn" ++if test "x$ac_cv_func_posix_spawn" = xyes ++then : ++ printf "%s\n" "#define HAVE_POSIX_SPAWN 1" >>confdefs.h ++ ++fi ++ac_fn_c_check_func "$LINENO" "posix_spawnp" "ac_cv_func_posix_spawnp" ++if test "x$ac_cv_func_posix_spawnp" = xyes ++then : ++ printf "%s\n" "#define HAVE_POSIX_SPAWNP 1" >>confdefs.h ++ ++fi ++ac_fn_c_check_func "$LINENO" "posix_spawn_file_actions_addclosefrom_np" "ac_cv_func_posix_spawn_file_actions_addclosefrom_np" ++if test "x$ac_cv_func_posix_spawn_file_actions_addclosefrom_np" = xyes ++then : ++ printf "%s\n" "#define HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP 1" >>confdefs.h ++ ++fi ++ac_fn_c_check_func "$LINENO" "sigaltstack" "ac_cv_func_sigaltstack" ++if test "x$ac_cv_func_sigaltstack" = xyes ++then : ++ printf "%s\n" "#define HAVE_SIGALTSTACK 1" >>confdefs.h ++ ++fi ++ ++fi ++ + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5 + printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; } + if test ${ac_cv_c_undeclared_builtin_options+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_save_CFLAGS=$CFLAGS ++else case e in #( ++ e) ac_save_CFLAGS=$CFLAGS + ac_cv_c_undeclared_builtin_options='cannot detect' + for ac_arg in '' -fno-builtin; do + CFLAGS="$ac_save_CFLAGS $ac_arg" +@@ -19419,8 +20331,8 @@ + if ac_fn_c_try_compile "$LINENO" + then : + +-else $as_nop +- # This test program should compile successfully. ++else case e in #( ++ e) # This test program should compile successfully. + # No library function is consistently available on + # freestanding implementations, so test against a dummy + # declaration. Include always-available headers on the +@@ -19448,26 +20360,29 @@ + if test x"$ac_arg" = x + then : + ac_cv_c_undeclared_builtin_options='none needed' +-else $as_nop +- ac_cv_c_undeclared_builtin_options=$ac_arg ++else case e in #( ++ e) ac_cv_c_undeclared_builtin_options=$ac_arg ;; ++esac + fi + break + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + done + CFLAGS=$ac_save_CFLAGS +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5 + printf "%s\n" "$ac_cv_c_undeclared_builtin_options" >&6; } + case $ac_cv_c_undeclared_builtin_options in #( + 'cannot detect') : +- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error $? "cannot make $CC report undeclared builtins +-See \`config.log' for more details" "$LINENO" 5; } ;; #( ++See 'config.log' for more details" "$LINENO" 5; } ;; #( + 'none needed') : + ac_c_undeclared_builtin_options='' ;; #( + *) : +@@ -19493,8 +20408,8 @@ + if test ${ac_cv_func_chroot+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -19508,11 +20423,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_chroot=yes +-else $as_nop +- ac_cv_func_chroot=no ++else case e in #( ++ e) ac_cv_func_chroot=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_chroot" >&5 + printf "%s\n" "$ac_cv_func_chroot" >&6; } +@@ -19532,8 +20449,8 @@ + if test ${ac_cv_func_link+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -19547,11 +20464,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_link=yes +-else $as_nop +- ac_cv_func_link=no ++else case e in #( ++ e) ac_cv_func_link=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_link" >&5 + printf "%s\n" "$ac_cv_func_link" >&6; } +@@ -19571,8 +20490,8 @@ + if test ${ac_cv_func_symlink+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -19586,11 +20505,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_symlink=yes +-else $as_nop +- ac_cv_func_symlink=no ++else case e in #( ++ e) ac_cv_func_symlink=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_symlink" >&5 + printf "%s\n" "$ac_cv_func_symlink" >&6; } +@@ -19610,8 +20531,8 @@ + if test ${ac_cv_func_fchdir+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -19625,11 +20546,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_fchdir=yes +-else $as_nop +- ac_cv_func_fchdir=no ++else case e in #( ++ e) ac_cv_func_fchdir=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fchdir" >&5 + printf "%s\n" "$ac_cv_func_fchdir" >&6; } +@@ -19649,8 +20572,8 @@ + if test ${ac_cv_func_fsync+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -19664,11 +20587,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_fsync=yes +-else $as_nop +- ac_cv_func_fsync=no ++else case e in #( ++ e) ac_cv_func_fsync=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fsync" >&5 + printf "%s\n" "$ac_cv_func_fsync" >&6; } +@@ -19688,8 +20613,8 @@ + if test ${ac_cv_func_fdatasync+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -19703,11 +20628,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_fdatasync=yes +-else $as_nop +- ac_cv_func_fdatasync=no ++else case e in #( ++ e) ac_cv_func_fdatasync=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fdatasync" >&5 + printf "%s\n" "$ac_cv_func_fdatasync" >&6; } +@@ -19727,8 +20654,8 @@ + if test ${ac_cv_func_epoll_create+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -19742,11 +20669,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_epoll_create=yes +-else $as_nop +- ac_cv_func_epoll_create=no ++else case e in #( ++ e) ac_cv_func_epoll_create=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_epoll_create" >&5 + printf "%s\n" "$ac_cv_func_epoll_create" >&6; } +@@ -19766,8 +20695,8 @@ + if test ${ac_cv_func_epoll_create1+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -19781,11 +20710,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_epoll_create1=yes +-else $as_nop +- ac_cv_func_epoll_create1=no ++else case e in #( ++ e) ac_cv_func_epoll_create1=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_epoll_create1" >&5 + printf "%s\n" "$ac_cv_func_epoll_create1" >&6; } +@@ -19805,8 +20736,8 @@ + if test ${ac_cv_func_kqueue+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -19823,11 +20754,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_kqueue=yes +-else $as_nop +- ac_cv_func_kqueue=no ++else case e in #( ++ e) ac_cv_func_kqueue=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_kqueue" >&5 + printf "%s\n" "$ac_cv_func_kqueue" >&6; } +@@ -19847,8 +20780,8 @@ + if test ${ac_cv_func_prlimit+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -19865,11 +20798,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_prlimit=yes +-else $as_nop +- ac_cv_func_prlimit=no ++else case e in #( ++ e) ac_cv_func_prlimit=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_prlimit" >&5 + printf "%s\n" "$ac_cv_func_prlimit" >&6; } +@@ -19890,8 +20825,8 @@ + if test ${ac_cv_func__dyld_shared_cache_contains_path+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -19905,11 +20840,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func__dyld_shared_cache_contains_path=yes +-else $as_nop +- ac_cv_func__dyld_shared_cache_contains_path=no ++else case e in #( ++ e) ac_cv_func__dyld_shared_cache_contains_path=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func__dyld_shared_cache_contains_path" >&5 + printf "%s\n" "$ac_cv_func__dyld_shared_cache_contains_path" >&6; } +@@ -19930,8 +20867,8 @@ + if test ${ac_cv_func_memfd_create+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #ifdef HAVE_SYS_MMAN_H +@@ -19952,11 +20889,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_memfd_create=yes +-else $as_nop +- ac_cv_func_memfd_create=no ++else case e in #( ++ e) ac_cv_func_memfd_create=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_memfd_create" >&5 + printf "%s\n" "$ac_cv_func_memfd_create" >&6; } +@@ -19977,8 +20916,8 @@ + if test ${ac_cv_func_eventfd+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #ifdef HAVE_SYS_EVENTFD_H +@@ -19996,11 +20935,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_eventfd=yes +-else $as_nop +- ac_cv_func_eventfd=no ++else case e in #( ++ e) ac_cv_func_eventfd=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_eventfd" >&5 + printf "%s\n" "$ac_cv_func_eventfd" >&6; } +@@ -20021,8 +20962,8 @@ + if test ${ac_cv_func_timerfd_create+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #ifdef HAVE_SYS_TIMERFD_H +@@ -20040,11 +20981,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_timerfd_create=yes +-else $as_nop +- ac_cv_func_timerfd_create=no ++else case e in #( ++ e) ac_cv_func_timerfd_create=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_timerfd_create" >&5 + printf "%s\n" "$ac_cv_func_timerfd_create" >&6; } +@@ -20071,8 +21014,8 @@ + if test ${ac_cv_func_ctermid_r+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -20086,11 +21029,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_ctermid_r=yes +-else $as_nop +- ac_cv_func_ctermid_r=no ++else case e in #( ++ e) ac_cv_func_ctermid_r=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_ctermid_r" >&5 + printf "%s\n" "$ac_cv_func_ctermid_r" >&6; } +@@ -20109,8 +21054,8 @@ + if test ${ac_cv_flock_decl+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -20125,12 +21070,14 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_flock_decl=yes +-else $as_nop +- ac_cv_flock_decl=no +- ++else case e in #( ++ e) ac_cv_flock_decl=no ++ ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_flock_decl" >&5 + printf "%s\n" "$ac_cv_flock_decl" >&6; } +@@ -20144,22 +21091,28 @@ + then : + printf "%s\n" "#define HAVE_FLOCK 1" >>confdefs.h + +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for flock in -lbsd" >&5 ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for flock in -lbsd" >&5 + printf %s "checking for flock in -lbsd... " >&6; } + if test ${ac_cv_lib_bsd_flock+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lbsd $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char flock (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char flock (void); + int + main (void) + { +@@ -20171,12 +21124,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_bsd_flock=yes +-else $as_nop +- ac_cv_lib_bsd_flock=no ++else case e in #( ++ e) ac_cv_lib_bsd_flock=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_flock" >&5 + printf "%s\n" "$ac_cv_lib_bsd_flock" >&6; } +@@ -20184,7 +21139,8 @@ + then : + FCNTL_LIBS="-lbsd" + fi +- ++ ;; ++esac + fi + + done +@@ -20197,8 +21153,8 @@ + if test ${ac_cv_func_getpagesize+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -20212,11 +21168,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_getpagesize=yes +-else $as_nop +- ac_cv_func_getpagesize=no ++else case e in #( ++ e) ac_cv_func_getpagesize=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getpagesize" >&5 + printf "%s\n" "$ac_cv_func_getpagesize" >&6; } +@@ -20235,8 +21193,8 @@ + if test ${ac_cv_broken_unsetenv+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -20250,12 +21208,14 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_broken_unsetenv=no +-else $as_nop +- ac_cv_broken_unsetenv=yes +- ++else case e in #( ++ e) ac_cv_broken_unsetenv=yes ++ ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_broken_unsetenv" >&5 + printf "%s\n" "$ac_cv_broken_unsetenv" >&6; } +@@ -20277,8 +21237,8 @@ + if test ${ac_cv_prog_TRUE+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test -n "$TRUE"; then ++else case e in #( ++ e) if test -n "$TRUE"; then + ac_cv_prog_TRUE="$TRUE" # Let the user override the test. + else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +@@ -20300,7 +21260,8 @@ + done + IFS=$as_save_IFS + +-fi ++fi ;; ++esac + fi + TRUE=$ac_cv_prog_TRUE + if test -n "$TRUE"; then +@@ -20322,16 +21283,22 @@ + if test ${ac_cv_lib_c_inet_aton+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lc $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char inet_aton (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char inet_aton (void); + int + main (void) + { +@@ -20343,34 +21310,42 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_c_inet_aton=yes +-else $as_nop +- ac_cv_lib_c_inet_aton=no ++else case e in #( ++ e) ac_cv_lib_c_inet_aton=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_inet_aton" >&5 + printf "%s\n" "$ac_cv_lib_c_inet_aton" >&6; } + if test "x$ac_cv_lib_c_inet_aton" = xyes + then : + $ac_cv_prog_TRUE +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inet_aton in -lresolv" >&5 ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inet_aton in -lresolv" >&5 + printf %s "checking for inet_aton in -lresolv... " >&6; } + if test ${ac_cv_lib_resolv_inet_aton+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lresolv $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char inet_aton (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char inet_aton (void); + int + main (void) + { +@@ -20382,12 +21357,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_resolv_inet_aton=yes +-else $as_nop +- ac_cv_lib_resolv_inet_aton=no ++else case e in #( ++ e) ac_cv_lib_resolv_inet_aton=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_inet_aton" >&5 + printf "%s\n" "$ac_cv_lib_resolv_inet_aton" >&6; } +@@ -20396,7 +21373,8 @@ + SOCKET_LIBS="-lresolv" + fi + +- ++ ;; ++esac + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for hstrerror in -lc" >&5 +@@ -20404,16 +21382,22 @@ + if test ${ac_cv_lib_c_hstrerror+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lc $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char hstrerror (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char hstrerror (void); + int + main (void) + { +@@ -20425,34 +21409,42 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_c_hstrerror=yes +-else $as_nop +- ac_cv_lib_c_hstrerror=no ++else case e in #( ++ e) ac_cv_lib_c_hstrerror=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_hstrerror" >&5 + printf "%s\n" "$ac_cv_lib_c_hstrerror" >&6; } + if test "x$ac_cv_lib_c_hstrerror" = xyes + then : + $ac_cv_prog_TRUE +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for hstrerror in -lresolv" >&5 ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for hstrerror in -lresolv" >&5 + printf %s "checking for hstrerror in -lresolv... " >&6; } + if test ${ac_cv_lib_resolv_hstrerror+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lresolv $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char hstrerror (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char hstrerror (void); + int + main (void) + { +@@ -20464,12 +21456,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_resolv_hstrerror=yes +-else $as_nop +- ac_cv_lib_resolv_hstrerror=no ++else case e in #( ++ e) ac_cv_lib_resolv_hstrerror=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_hstrerror" >&5 + printf "%s\n" "$ac_cv_lib_resolv_hstrerror" >&6; } +@@ -20478,7 +21472,8 @@ + SOCKET_LIBS="-lresolv" + fi + +- ++ ;; ++esac + fi + + +@@ -20489,12 +21484,12 @@ + if test ${ac_cv_have_chflags+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test "$cross_compiling" = yes ++else case e in #( ++ e) if test "$cross_compiling" = yes + then : + ac_cv_have_chflags=cross +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -20510,14 +21505,17 @@ + if ac_fn_c_try_run "$LINENO" + then : + ac_cv_have_chflags=yes +-else $as_nop +- ac_cv_have_chflags=no ++else case e in #( ++ e) ac_cv_have_chflags=no ;; ++esac + fi + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_chflags" >&5 + printf "%s\n" "$ac_cv_have_chflags" >&6; } +@@ -20526,8 +21524,9 @@ + if test "x$ac_cv_func_chflags" = xyes + then : + ac_cv_have_chflags="yes" +-else $as_nop +- ac_cv_have_chflags="no" ++else case e in #( ++ e) ac_cv_have_chflags="no" ;; ++esac + fi + + fi +@@ -20542,12 +21541,12 @@ + if test ${ac_cv_have_lchflags+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test "$cross_compiling" = yes ++else case e in #( ++ e) if test "$cross_compiling" = yes + then : + ac_cv_have_lchflags=cross +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -20563,14 +21562,17 @@ + if ac_fn_c_try_run "$LINENO" + then : + ac_cv_have_lchflags=yes +-else $as_nop +- ac_cv_have_lchflags=no ++else case e in #( ++ e) ac_cv_have_lchflags=no ;; ++esac + fi + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_lchflags" >&5 + printf "%s\n" "$ac_cv_have_lchflags" >&6; } +@@ -20579,8 +21581,9 @@ + if test "x$ac_cv_func_lchflags" = xyes + then : + ac_cv_have_lchflags="yes" +-else $as_nop +- ac_cv_have_lchflags="no" ++else case e in #( ++ e) ac_cv_have_lchflags="no" ;; ++esac + fi + + fi +@@ -20687,16 +21690,22 @@ + if test ${ac_cv_lib_z_gzread+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lz $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char gzread (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char gzread (void); + int + main (void) + { +@@ -20708,27 +21717,31 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_z_gzread=yes +-else $as_nop +- ac_cv_lib_z_gzread=no ++else case e in #( ++ e) ac_cv_lib_z_gzread=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_gzread" >&5 + printf "%s\n" "$ac_cv_lib_z_gzread" >&6; } + if test "x$ac_cv_lib_z_gzread" = xyes + then : + have_zlib=yes +-else $as_nop +- have_zlib=no ++else case e in #( ++ e) have_zlib=no ;; ++esac + fi + + LIBS=$py_check_lib_save_LIBS + + +-else $as_nop +- have_zlib=no ++else case e in #( ++ e) have_zlib=no ;; ++esac + fi + + done +@@ -20743,16 +21756,22 @@ + if test ${ac_cv_lib_z_inflateCopy+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lz $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char inflateCopy (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char inflateCopy (void); + int + main (void) + { +@@ -20764,12 +21783,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_z_inflateCopy=yes +-else $as_nop +- ac_cv_lib_z_inflateCopy=no ++else case e in #( ++ e) ac_cv_lib_z_inflateCopy=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_inflateCopy" >&5 + printf "%s\n" "$ac_cv_lib_z_inflateCopy" >&6; } +@@ -20816,16 +21837,22 @@ + if test ${ac_cv_lib_z_gzread+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lz $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char gzread (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char gzread (void); + int + main (void) + { +@@ -20837,27 +21864,31 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_z_gzread=yes +-else $as_nop +- ac_cv_lib_z_gzread=no ++else case e in #( ++ e) ac_cv_lib_z_gzread=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_gzread" >&5 + printf "%s\n" "$ac_cv_lib_z_gzread" >&6; } + if test "x$ac_cv_lib_z_gzread" = xyes + then : + have_zlib=yes +-else $as_nop +- have_zlib=no ++else case e in #( ++ e) have_zlib=no ;; ++esac + fi + + LIBS=$py_check_lib_save_LIBS + + +-else $as_nop +- have_zlib=no ++else case e in #( ++ e) have_zlib=no ;; ++esac + fi + + done +@@ -20872,16 +21903,22 @@ + if test ${ac_cv_lib_z_inflateCopy+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lz $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char inflateCopy (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char inflateCopy (void); + int + main (void) + { +@@ -20893,12 +21930,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_z_inflateCopy=yes +-else $as_nop +- ac_cv_lib_z_inflateCopy=no ++else case e in #( ++ e) ac_cv_lib_z_inflateCopy=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_inflateCopy" >&5 + printf "%s\n" "$ac_cv_lib_z_inflateCopy" >&6; } +@@ -21034,16 +22073,22 @@ + if test ${ac_cv_lib_bz2_BZ2_bzCompress+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lbz2 $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char BZ2_bzCompress (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char BZ2_bzCompress (void); + int + main (void) + { +@@ -21055,25 +22100,29 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_bz2_BZ2_bzCompress=yes +-else $as_nop +- ac_cv_lib_bz2_BZ2_bzCompress=no ++else case e in #( ++ e) ac_cv_lib_bz2_BZ2_bzCompress=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bz2_BZ2_bzCompress" >&5 + printf "%s\n" "$ac_cv_lib_bz2_BZ2_bzCompress" >&6; } + if test "x$ac_cv_lib_bz2_BZ2_bzCompress" = xyes + then : + have_bzip2=yes +-else $as_nop +- have_bzip2=no ++else case e in #( ++ e) have_bzip2=no ;; ++esac + fi + + +-else $as_nop +- have_bzip2=no ++else case e in #( ++ e) have_bzip2=no ;; ++esac + fi + + done +@@ -21116,16 +22165,22 @@ + if test ${ac_cv_lib_bz2_BZ2_bzCompress+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lbz2 $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char BZ2_bzCompress (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char BZ2_bzCompress (void); + int + main (void) + { +@@ -21137,25 +22192,29 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_bz2_BZ2_bzCompress=yes +-else $as_nop +- ac_cv_lib_bz2_BZ2_bzCompress=no ++else case e in #( ++ e) ac_cv_lib_bz2_BZ2_bzCompress=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bz2_BZ2_bzCompress" >&5 + printf "%s\n" "$ac_cv_lib_bz2_BZ2_bzCompress" >&6; } + if test "x$ac_cv_lib_bz2_BZ2_bzCompress" = xyes + then : + have_bzip2=yes +-else $as_nop +- have_bzip2=no ++else case e in #( ++ e) have_bzip2=no ;; ++esac + fi + + +-else $as_nop +- have_bzip2=no ++else case e in #( ++ e) have_bzip2=no ;; ++esac + fi + + done +@@ -21262,16 +22321,22 @@ + if test ${ac_cv_lib_lzma_lzma_easy_encoder+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-llzma $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char lzma_easy_encoder (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char lzma_easy_encoder (void); + int + main (void) + { +@@ -21283,25 +22348,29 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_lzma_lzma_easy_encoder=yes +-else $as_nop +- ac_cv_lib_lzma_lzma_easy_encoder=no ++else case e in #( ++ e) ac_cv_lib_lzma_lzma_easy_encoder=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lzma_lzma_easy_encoder" >&5 + printf "%s\n" "$ac_cv_lib_lzma_lzma_easy_encoder" >&6; } + if test "x$ac_cv_lib_lzma_lzma_easy_encoder" = xyes + then : + have_liblzma=yes +-else $as_nop +- have_liblzma=no ++else case e in #( ++ e) have_liblzma=no ;; ++esac + fi + + +-else $as_nop +- have_liblzma=no ++else case e in #( ++ e) have_liblzma=no ;; ++esac + fi + + done +@@ -21344,16 +22413,22 @@ + if test ${ac_cv_lib_lzma_lzma_easy_encoder+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-llzma $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char lzma_easy_encoder (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char lzma_easy_encoder (void); + int + main (void) + { +@@ -21365,25 +22440,29 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_lzma_lzma_easy_encoder=yes +-else $as_nop +- ac_cv_lib_lzma_lzma_easy_encoder=no ++else case e in #( ++ e) ac_cv_lib_lzma_lzma_easy_encoder=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lzma_lzma_easy_encoder" >&5 + printf "%s\n" "$ac_cv_lib_lzma_lzma_easy_encoder" >&6; } + if test "x$ac_cv_lib_lzma_lzma_easy_encoder" = xyes + then : + have_liblzma=yes +-else $as_nop +- have_liblzma=no ++else case e in #( ++ e) have_liblzma=no ;; ++esac + fi + + +-else $as_nop +- have_liblzma=no ++else case e in #( ++ e) have_liblzma=no ;; ++esac + fi + + done +@@ -21419,8 +22498,8 @@ + if test ${ac_cv_func_hstrerror+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -21434,11 +22513,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_hstrerror=yes +-else $as_nop +- ac_cv_func_hstrerror=no ++else case e in #( ++ e) ac_cv_func_hstrerror=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_hstrerror" >&5 + printf "%s\n" "$ac_cv_func_hstrerror" >&6; } +@@ -21458,8 +22539,8 @@ + if test ${ac_cv_func_getservbyname+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -21473,11 +22554,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_getservbyname=yes +-else $as_nop +- ac_cv_func_getservbyname=no ++else case e in #( ++ e) ac_cv_func_getservbyname=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getservbyname" >&5 + printf "%s\n" "$ac_cv_func_getservbyname" >&6; } +@@ -21497,8 +22580,8 @@ + if test ${ac_cv_func_getservbyport+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -21512,11 +22595,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_getservbyport=yes +-else $as_nop +- ac_cv_func_getservbyport=no ++else case e in #( ++ e) ac_cv_func_getservbyport=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getservbyport" >&5 + printf "%s\n" "$ac_cv_func_getservbyport" >&6; } +@@ -21536,8 +22621,8 @@ + if test ${ac_cv_func_gethostbyname+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -21551,11 +22636,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_gethostbyname=yes +-else $as_nop +- ac_cv_func_gethostbyname=no ++else case e in #( ++ e) ac_cv_func_gethostbyname=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_gethostbyname" >&5 + printf "%s\n" "$ac_cv_func_gethostbyname" >&6; } +@@ -21575,8 +22662,8 @@ + if test ${ac_cv_func_gethostbyaddr+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -21590,11 +22677,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_gethostbyaddr=yes +-else $as_nop +- ac_cv_func_gethostbyaddr=no ++else case e in #( ++ e) ac_cv_func_gethostbyaddr=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_gethostbyaddr" >&5 + printf "%s\n" "$ac_cv_func_gethostbyaddr" >&6; } +@@ -21614,8 +22703,8 @@ + if test ${ac_cv_func_getprotobyname+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -21629,11 +22718,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_getprotobyname=yes +-else $as_nop +- ac_cv_func_getprotobyname=no ++else case e in #( ++ e) ac_cv_func_getprotobyname=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getprotobyname" >&5 + printf "%s\n" "$ac_cv_func_getprotobyname" >&6; } +@@ -21656,8 +22747,8 @@ + if test ${ac_cv_func_inet_aton+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -21676,11 +22767,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_inet_aton=yes +-else $as_nop +- ac_cv_func_inet_aton=no ++else case e in #( ++ e) ac_cv_func_inet_aton=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_inet_aton" >&5 + printf "%s\n" "$ac_cv_func_inet_aton" >&6; } +@@ -21700,8 +22793,8 @@ + if test ${ac_cv_func_inet_ntoa+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -21720,11 +22813,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_inet_ntoa=yes +-else $as_nop +- ac_cv_func_inet_ntoa=no ++else case e in #( ++ e) ac_cv_func_inet_ntoa=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_inet_ntoa" >&5 + printf "%s\n" "$ac_cv_func_inet_ntoa" >&6; } +@@ -21744,8 +22839,8 @@ + if test ${ac_cv_func_inet_pton+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -21764,11 +22859,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_inet_pton=yes +-else $as_nop +- ac_cv_func_inet_pton=no ++else case e in #( ++ e) ac_cv_func_inet_pton=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_inet_pton" >&5 + printf "%s\n" "$ac_cv_func_inet_pton" >&6; } +@@ -21788,8 +22885,8 @@ + if test ${ac_cv_func_getpeername+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -21808,11 +22905,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_getpeername=yes +-else $as_nop +- ac_cv_func_getpeername=no ++else case e in #( ++ e) ac_cv_func_getpeername=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getpeername" >&5 + printf "%s\n" "$ac_cv_func_getpeername" >&6; } +@@ -21832,8 +22931,8 @@ + if test ${ac_cv_func_getsockname+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -21852,11 +22951,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_getsockname=yes +-else $as_nop +- ac_cv_func_getsockname=no ++else case e in #( ++ e) ac_cv_func_getsockname=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getsockname" >&5 + printf "%s\n" "$ac_cv_func_getsockname" >&6; } +@@ -21876,8 +22977,8 @@ + if test ${ac_cv_func_accept+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -21896,11 +22997,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_accept=yes +-else $as_nop +- ac_cv_func_accept=no ++else case e in #( ++ e) ac_cv_func_accept=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_accept" >&5 + printf "%s\n" "$ac_cv_func_accept" >&6; } +@@ -21920,8 +23023,8 @@ + if test ${ac_cv_func_bind+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -21940,11 +23043,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_bind=yes +-else $as_nop +- ac_cv_func_bind=no ++else case e in #( ++ e) ac_cv_func_bind=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_bind" >&5 + printf "%s\n" "$ac_cv_func_bind" >&6; } +@@ -21964,8 +23069,8 @@ + if test ${ac_cv_func_connect+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -21984,11 +23089,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_connect=yes +-else $as_nop +- ac_cv_func_connect=no ++else case e in #( ++ e) ac_cv_func_connect=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_connect" >&5 + printf "%s\n" "$ac_cv_func_connect" >&6; } +@@ -22008,8 +23115,8 @@ + if test ${ac_cv_func_listen+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -22028,11 +23135,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_listen=yes +-else $as_nop +- ac_cv_func_listen=no ++else case e in #( ++ e) ac_cv_func_listen=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_listen" >&5 + printf "%s\n" "$ac_cv_func_listen" >&6; } +@@ -22052,8 +23161,8 @@ + if test ${ac_cv_func_recvfrom+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -22072,11 +23181,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_recvfrom=yes +-else $as_nop +- ac_cv_func_recvfrom=no ++else case e in #( ++ e) ac_cv_func_recvfrom=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_recvfrom" >&5 + printf "%s\n" "$ac_cv_func_recvfrom" >&6; } +@@ -22096,8 +23207,8 @@ + if test ${ac_cv_func_sendto+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -22116,11 +23227,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_sendto=yes +-else $as_nop +- ac_cv_func_sendto=no ++else case e in #( ++ e) ac_cv_func_sendto=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_sendto" >&5 + printf "%s\n" "$ac_cv_func_sendto" >&6; } +@@ -22140,8 +23253,8 @@ + if test ${ac_cv_func_setsockopt+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -22160,11 +23273,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_setsockopt=yes +-else $as_nop +- ac_cv_func_setsockopt=no ++else case e in #( ++ e) ac_cv_func_setsockopt=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_setsockopt" >&5 + printf "%s\n" "$ac_cv_func_setsockopt" >&6; } +@@ -22184,8 +23299,8 @@ + if test ${ac_cv_func_socket+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -22204,11 +23319,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_socket=yes +-else $as_nop +- ac_cv_func_socket=no ++else case e in #( ++ e) ac_cv_func_socket=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_socket" >&5 + printf "%s\n" "$ac_cv_func_socket" >&6; } +@@ -22230,8 +23347,8 @@ + if test ${ac_cv_func_setgroups+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -22250,11 +23367,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_setgroups=yes +-else $as_nop +- ac_cv_func_setgroups=no ++else case e in #( ++ e) ac_cv_func_setgroups=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_setgroups" >&5 + printf "%s\n" "$ac_cv_func_setgroups" >&6; } +@@ -22269,7 +23388,8 @@ + + + # check for openpty, login_tty, and forkpty +- ++# tvOS/watchOS have functions for tty, but can't use them ++if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then + + for ac_func in openpty + do : +@@ -22278,22 +23398,28 @@ + then : + printf "%s\n" "#define HAVE_OPENPTY 1" >>confdefs.h + +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for openpty in -lutil" >&5 ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for openpty in -lutil" >&5 + printf %s "checking for openpty in -lutil... " >&6; } + if test ${ac_cv_lib_util_openpty+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lutil $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char openpty (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char openpty (void); + int + main (void) + { +@@ -22305,12 +23431,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_util_openpty=yes +-else $as_nop +- ac_cv_lib_util_openpty=no ++else case e in #( ++ e) ac_cv_lib_util_openpty=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_util_openpty" >&5 + printf "%s\n" "$ac_cv_lib_util_openpty" >&6; } +@@ -22318,22 +23446,28 @@ + then : + printf "%s\n" "#define HAVE_OPENPTY 1" >>confdefs.h + LIBS="$LIBS -lutil" +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for openpty in -lbsd" >&5 ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for openpty in -lbsd" >&5 + printf %s "checking for openpty in -lbsd... " >&6; } + if test ${ac_cv_lib_bsd_openpty+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lbsd $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char openpty (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char openpty (void); + int + main (void) + { +@@ -22345,12 +23479,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_bsd_openpty=yes +-else $as_nop +- ac_cv_lib_bsd_openpty=no ++else case e in #( ++ e) ac_cv_lib_bsd_openpty=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_openpty" >&5 + printf "%s\n" "$ac_cv_lib_bsd_openpty" >&6; } +@@ -22359,9 +23495,11 @@ + printf "%s\n" "#define HAVE_OPENPTY 1" >>confdefs.h + LIBS="$LIBS -lbsd" + fi +- ++ ;; ++esac + fi +- ++ ;; ++esac + fi + + done +@@ -22370,15 +23508,21 @@ + if test ${ac_cv_search_login_tty+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_func_search_save_LIBS=$LIBS ++else case e in #( ++ e) ac_func_search_save_LIBS=$LIBS + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char login_tty (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char login_tty (void); + int + main (void) + { +@@ -22409,11 +23553,13 @@ + if test ${ac_cv_search_login_tty+y} + then : + +-else $as_nop +- ac_cv_search_login_tty=no ++else case e in #( ++ e) ac_cv_search_login_tty=no ;; ++esac + fi + rm conftest.$ac_ext +-LIBS=$ac_func_search_save_LIBS ++LIBS=$ac_func_search_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_login_tty" >&5 + printf "%s\n" "$ac_cv_search_login_tty" >&6; } +@@ -22435,22 +23581,28 @@ + then : + printf "%s\n" "#define HAVE_FORKPTY 1" >>confdefs.h + +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for forkpty in -lutil" >&5 ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for forkpty in -lutil" >&5 + printf %s "checking for forkpty in -lutil... " >&6; } + if test ${ac_cv_lib_util_forkpty+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lutil $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char forkpty (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char forkpty (void); + int + main (void) + { +@@ -22462,12 +23614,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_util_forkpty=yes +-else $as_nop +- ac_cv_lib_util_forkpty=no ++else case e in #( ++ e) ac_cv_lib_util_forkpty=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_util_forkpty" >&5 + printf "%s\n" "$ac_cv_lib_util_forkpty" >&6; } +@@ -22475,22 +23629,28 @@ + then : + printf "%s\n" "#define HAVE_FORKPTY 1" >>confdefs.h + LIBS="$LIBS -lutil" +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for forkpty in -lbsd" >&5 ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for forkpty in -lbsd" >&5 + printf %s "checking for forkpty in -lbsd... " >&6; } + if test ${ac_cv_lib_bsd_forkpty+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lbsd $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char forkpty (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char forkpty (void); + int + main (void) + { +@@ -22502,12 +23662,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_bsd_forkpty=yes +-else $as_nop +- ac_cv_lib_bsd_forkpty=no ++else case e in #( ++ e) ac_cv_lib_bsd_forkpty=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_forkpty" >&5 + printf "%s\n" "$ac_cv_lib_bsd_forkpty" >&6; } +@@ -22516,12 +23678,15 @@ + printf "%s\n" "#define HAVE_FORKPTY 1" >>confdefs.h + LIBS="$LIBS -lbsd" + fi +- ++ ;; ++esac + fi +- ++ ;; ++esac + fi + + done ++fi + + # check for long file support functions + ac_fn_c_check_func "$LINENO" "fseek64" "ac_cv_func_fseek64" +@@ -22567,13 +23732,14 @@ + then : + printf "%s\n" "#define HAVE_DUP2 1" >>confdefs.h + +-else $as_nop +- case " $LIBOBJS " in ++else case e in #( ++ e) case " $LIBOBJS " in + *" dup2.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS dup2.$ac_objext" + ;; + esac +- ++ ;; ++esac + fi + + +@@ -22656,23 +23822,29 @@ + then : + printf "%s\n" "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h + +-else $as_nop +- ++else case e in #( ++ e) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 + printf %s "checking for clock_gettime in -lrt... " >&6; } + if test ${ac_cv_lib_rt_clock_gettime+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lrt $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char clock_gettime (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char clock_gettime (void); + int + main (void) + { +@@ -22684,12 +23856,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_rt_clock_gettime=yes +-else $as_nop +- ac_cv_lib_rt_clock_gettime=no ++else case e in #( ++ e) ac_cv_lib_rt_clock_gettime=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 + printf "%s\n" "$ac_cv_lib_rt_clock_gettime" >&6; } +@@ -22705,7 +23879,8 @@ + + fi + +- ++ ;; ++esac + fi + + done +@@ -22718,23 +23893,29 @@ + then : + printf "%s\n" "#define HAVE_CLOCK_GETRES 1" >>confdefs.h + +-else $as_nop +- ++else case e in #( ++ e) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_getres in -lrt" >&5 + printf %s "checking for clock_getres in -lrt... " >&6; } + if test ${ac_cv_lib_rt_clock_getres+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lrt $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char clock_getres (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char clock_getres (void); + int + main (void) + { +@@ -22746,12 +23927,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_rt_clock_getres=yes +-else $as_nop +- ac_cv_lib_rt_clock_getres=no ++else case e in #( ++ e) ac_cv_lib_rt_clock_getres=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_getres" >&5 + printf "%s\n" "$ac_cv_lib_rt_clock_getres" >&6; } +@@ -22763,15 +23946,16 @@ + + fi + +- ++ ;; ++esac + fi + + done + +-# On Android and iOS, clock_settime can be linked (so it is found by ++# On Android, iOS, tvOS and watchOS, clock_settime can be linked (so it is found by + # configure), but when used in an unprivileged process, it crashes rather than + # returning an error. Force the symbol off. +-if test "$ac_sys_system" != "Linux-android" && test "$ac_sys_system" != "iOS" ++if test "$ac_sys_system" != "Linux-android" -a "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" + then + + for ac_func in clock_settime +@@ -22781,23 +23965,29 @@ + then : + printf "%s\n" "#define HAVE_CLOCK_SETTIME 1" >>confdefs.h + +-else $as_nop +- ++else case e in #( ++ e) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_settime in -lrt" >&5 + printf %s "checking for clock_settime in -lrt... " >&6; } + if test ${ac_cv_lib_rt_clock_settime+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lrt $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char clock_settime (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char clock_settime (void); + int + main (void) + { +@@ -22809,12 +23999,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_rt_clock_settime=yes +-else $as_nop +- ac_cv_lib_rt_clock_settime=no ++else case e in #( ++ e) ac_cv_lib_rt_clock_settime=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_settime" >&5 + printf "%s\n" "$ac_cv_lib_rt_clock_settime" >&6; } +@@ -22826,7 +24018,8 @@ + + fi + +- ++ ;; ++esac + fi + + done +@@ -22844,23 +24037,29 @@ + then : + printf "%s\n" "#define HAVE_CLOCK_NANOSLEEP 1" >>confdefs.h + +-else $as_nop +- ++else case e in #( ++ e) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_nanosleep in -lrt" >&5 + printf %s "checking for clock_nanosleep in -lrt... " >&6; } + if test ${ac_cv_lib_rt_clock_nanosleep+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lrt $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char clock_nanosleep (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char clock_nanosleep (void); + int + main (void) + { +@@ -22872,12 +24071,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_rt_clock_nanosleep=yes +-else $as_nop +- ac_cv_lib_rt_clock_nanosleep=no ++else case e in #( ++ e) ac_cv_lib_rt_clock_nanosleep=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_nanosleep" >&5 + printf "%s\n" "$ac_cv_lib_rt_clock_nanosleep" >&6; } +@@ -22889,7 +24090,8 @@ + + fi + +- ++ ;; ++esac + fi + + done +@@ -22903,23 +24105,29 @@ + then : + printf "%s\n" "#define HAVE_NANOSLEEP 1" >>confdefs.h + +-else $as_nop +- ++else case e in #( ++ e) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for nanosleep in -lrt" >&5 + printf %s "checking for nanosleep in -lrt... " >&6; } + if test ${ac_cv_lib_rt_nanosleep+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lrt $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char nanosleep (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char nanosleep (void); + int + main (void) + { +@@ -22931,12 +24139,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_rt_nanosleep=yes +-else $as_nop +- ac_cv_lib_rt_nanosleep=no ++else case e in #( ++ e) ac_cv_lib_rt_nanosleep=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_nanosleep" >&5 + printf "%s\n" "$ac_cv_lib_rt_nanosleep" >&6; } +@@ -22948,7 +24158,8 @@ + + fi + +- ++ ;; ++esac + fi + + done +@@ -22958,8 +24169,8 @@ + if test ${ac_cv_device_macros+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + +@@ -22985,12 +24196,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_device_macros=yes +-else $as_nop +- ac_cv_device_macros=no ++else case e in #( ++ e) ac_cv_device_macros=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_device_macros" >&5 + printf "%s\n" "$ac_cv_device_macros" >&6; } +@@ -23014,8 +24227,8 @@ + if test ${ac_cv_func_getaddrinfo+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + +@@ -23035,12 +24248,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_func_getaddrinfo=yes +-else $as_nop +- ac_cv_func_getaddrinfo=no ++else case e in #( ++ e) ac_cv_func_getaddrinfo=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getaddrinfo" >&5 + printf "%s\n" "$ac_cv_func_getaddrinfo" >&6; } +@@ -23053,8 +24268,8 @@ + if test ${ac_cv_buggy_getaddrinfo+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test "$cross_compiling" = yes ++else case e in #( ++ e) if test "$cross_compiling" = yes + then : + + if test "$ac_sys_system" = "Linux-android" || test "$ac_sys_system" = "iOS"; then +@@ -23064,8 +24279,8 @@ + else + ac_cv_buggy_getaddrinfo=yes + fi +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -23161,13 +24376,16 @@ + if ac_fn_c_try_run "$LINENO" + then : + ac_cv_buggy_getaddrinfo=no +-else $as_nop +- ac_cv_buggy_getaddrinfo=yes ++else case e in #( ++ e) ac_cv_buggy_getaddrinfo=yes ;; ++esac + fi + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_buggy_getaddrinfo" >&5 + printf "%s\n" "$ac_cv_buggy_getaddrinfo" >&6; } +@@ -23203,8 +24421,8 @@ + if test ${ac_cv_struct_tm+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + #include +@@ -23222,10 +24440,12 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_struct_tm=time.h +-else $as_nop +- ac_cv_struct_tm=sys/time.h ++else case e in #( ++ e) ac_cv_struct_tm=sys/time.h ;; ++esac + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5 + printf "%s\n" "$ac_cv_struct_tm" >&6; } +@@ -23257,8 +24477,9 @@ + if test "x$ac_cv_have_decl_tzname" = xyes + then : + ac_have_decl=1 +-else $as_nop +- ac_have_decl=0 ++else case e in #( ++ e) ac_have_decl=0 ;; ++esac + fi + printf "%s\n" "#define HAVE_DECL_TZNAME $ac_have_decl" >>confdefs.h + +@@ -23267,8 +24488,8 @@ + if test ${ac_cv_var_tzname+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + #if !HAVE_DECL_TZNAME +@@ -23286,11 +24507,13 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_var_tzname=yes +-else $as_nop +- ac_cv_var_tzname=no ++else case e in #( ++ e) ac_cv_var_tzname=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ +- conftest$ac_exeext conftest.$ac_ext ++ conftest$ac_exeext conftest.$ac_ext ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_var_tzname" >&5 + printf "%s\n" "$ac_cv_var_tzname" >&6; } +@@ -23397,8 +24620,8 @@ + if test ${ac_cv_header_time_altzone+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include +@@ -23413,11 +24636,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_header_time_altzone=yes +-else $as_nop +- ac_cv_header_time_altzone=no ++else case e in #( ++ e) ac_cv_header_time_altzone=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time_altzone" >&5 + printf "%s\n" "$ac_cv_header_time_altzone" >&6; } +@@ -23432,8 +24657,8 @@ + if test ${ac_cv_struct_addrinfo+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -23447,10 +24672,12 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_struct_addrinfo=yes +-else $as_nop +- ac_cv_struct_addrinfo=no ++else case e in #( ++ e) ac_cv_struct_addrinfo=no ;; ++esac + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_addrinfo" >&5 + printf "%s\n" "$ac_cv_struct_addrinfo" >&6; } +@@ -23465,8 +24692,8 @@ + if test ${ac_cv_struct_sockaddr_storage+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + # include +@@ -23482,10 +24709,12 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_struct_sockaddr_storage=yes +-else $as_nop +- ac_cv_struct_sockaddr_storage=no ++else case e in #( ++ e) ac_cv_struct_sockaddr_storage=no ;; ++esac + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_sockaddr_storage" >&5 + printf "%s\n" "$ac_cv_struct_sockaddr_storage" >&6; } +@@ -23500,8 +24729,8 @@ + if test ${ac_cv_struct_sockaddr_alg+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + # include +@@ -23518,10 +24747,12 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_struct_sockaddr_alg=yes +-else $as_nop +- ac_cv_struct_sockaddr_alg=no ++else case e in #( ++ e) ac_cv_struct_sockaddr_alg=no ;; ++esac + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_sockaddr_alg" >&5 + printf "%s\n" "$ac_cv_struct_sockaddr_alg" >&6; } +@@ -23538,8 +24769,8 @@ + if test ${ac_cv_c_const+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + int +@@ -23603,10 +24834,12 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_c_const=yes +-else $as_nop +- ac_cv_c_const=no ++else case e in #( ++ e) ac_cv_c_const=no ;; ++esac + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 + printf "%s\n" "$ac_cv_c_const" >&6; } +@@ -23622,8 +24855,8 @@ + if test ${ac_cv_working_signed_char_c+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + +@@ -23638,11 +24871,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_working_signed_char_c=yes +-else $as_nop +- ac_cv_working_signed_char_c=no ++else case e in #( ++ e) ac_cv_working_signed_char_c=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_signed_char_c" >&5 + printf "%s\n" "$ac_cv_working_signed_char_c" >&6; } +@@ -23660,8 +24895,8 @@ + if test ${ac_cv_function_prototypes+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + int foo(int x) { return 0; } +@@ -23676,11 +24911,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_function_prototypes=yes +-else $as_nop +- ac_cv_function_prototypes=no ++else case e in #( ++ e) ac_cv_function_prototypes=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_function_prototypes" >&5 + printf "%s\n" "$ac_cv_function_prototypes" >&6; } +@@ -23702,8 +24939,8 @@ + if test ${ac_cv_func_socketpair+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -23720,11 +24957,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_func_socketpair=yes +-else $as_nop +- ac_cv_func_socketpair=no ++else case e in #( ++ e) ac_cv_func_socketpair=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_socketpair" >&5 + printf "%s\n" "$ac_cv_func_socketpair" >&6; } +@@ -23744,8 +24983,8 @@ + if test ${ac_cv_struct_sockaddr_sa_len+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include +@@ -23762,11 +25001,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_struct_sockaddr_sa_len=yes +-else $as_nop +- ac_cv_struct_sockaddr_sa_len=no ++else case e in #( ++ e) ac_cv_struct_sockaddr_sa_len=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_sockaddr_sa_len" >&5 + printf "%s\n" "$ac_cv_struct_sockaddr_sa_len" >&6; } +@@ -23823,8 +25064,8 @@ + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 + printf "%s\n" "yes" >&6; } + +-else $as_nop +- ++else case e in #( ++ e) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + printf "%s\n" "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking gethostbyname_r with 5 args" >&5 +@@ -23861,8 +25102,8 @@ + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 + printf "%s\n" "yes" >&6; } + +-else $as_nop +- ++else case e in #( ++ e) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + printf "%s\n" "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking gethostbyname_r with 3 args" >&5 +@@ -23897,23 +25138,26 @@ + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 + printf "%s\n" "yes" >&6; } + +-else $as_nop +- ++else case e in #( ++ e) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + printf "%s\n" "no" >&6; } +- ++ ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + CFLAGS=$OLD_CFLAGS + +-else $as_nop +- ++else case e in #( ++ e) + ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" + if test "x$ac_cv_func_gethostbyname" = xyes + then : +@@ -23921,7 +25165,8 @@ + + fi + +- ++ ;; ++esac + fi + + +@@ -23938,22 +25183,28 @@ + if test "x$ac_cv_func___fpu_control" = xyes + then : + +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __fpu_control in -lieee" >&5 ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __fpu_control in -lieee" >&5 + printf %s "checking for __fpu_control in -lieee... " >&6; } + if test ${ac_cv_lib_ieee___fpu_control+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lieee $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char __fpu_control (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char __fpu_control (void); + int + main (void) + { +@@ -23965,12 +25216,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_ieee___fpu_control=yes +-else $as_nop +- ac_cv_lib_ieee___fpu_control=no ++else case e in #( ++ e) ac_cv_lib_ieee___fpu_control=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ieee___fpu_control" >&5 + printf "%s\n" "$ac_cv_lib_ieee___fpu_control" >&6; } +@@ -23982,7 +25235,8 @@ + + fi + +- ++ ;; ++esac + fi + + +@@ -24009,9 +25263,10 @@ + printf "%s\n" "set LIBM=\"$withval\"" >&6; } + else as_fn_error $? "proper usage is --with-libm=STRING" "$LINENO" 5 + fi +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: default LIBM=\"$LIBM\"" >&5 +-printf "%s\n" "default LIBM=\"$LIBM\"" >&6; } ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: default LIBM=\"$LIBM\"" >&5 ++printf "%s\n" "default LIBM=\"$LIBM\"" >&6; } ;; ++esac + fi + + +@@ -24034,9 +25289,10 @@ + printf "%s\n" "set LIBC=\"$withval\"" >&6; } + else as_fn_error $? "proper usage is --with-libc=STRING" "$LINENO" 5 + fi +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: default LIBC=\"$LIBC\"" >&5 +-printf "%s\n" "default LIBC=\"$LIBC\"" >&6; } ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: default LIBC=\"$LIBC\"" >&5 ++printf "%s\n" "default LIBC=\"$LIBC\"" >&6; } ;; ++esac + fi + + +@@ -24050,8 +25306,8 @@ + if test ${ac_cv_gcc_asm_for_x64+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + +@@ -24068,12 +25324,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_gcc_asm_for_x64=yes +-else $as_nop +- ac_cv_gcc_asm_for_x64=no ++else case e in #( ++ e) ac_cv_gcc_asm_for_x64=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_gcc_asm_for_x64" >&5 + printf "%s\n" "$ac_cv_gcc_asm_for_x64" >&6; } +@@ -24096,8 +25354,8 @@ + if test ${ax_cv_c_float_words_bigendian+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + + ax_cv_c_float_words_bigendian=unknown + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -24134,7 +25392,8 @@ + + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ +- conftest$ac_exeext conftest.$ac_ext ++ conftest$ac_exeext conftest.$ac_ext ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_c_float_words_bigendian" >&5 + printf "%s\n" "$ax_cv_c_float_words_bigendian" >&6; } +@@ -24182,8 +25441,8 @@ + if test ${ac_cv_gcc_asm_for_x87+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + +@@ -24202,12 +25461,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_gcc_asm_for_x87=yes +-else $as_nop +- ac_cv_gcc_asm_for_x87=no ++else case e in #( ++ e) ac_cv_gcc_asm_for_x87=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_gcc_asm_for_x87" >&5 + printf "%s\n" "$ac_cv_gcc_asm_for_x87" >&6; } +@@ -24225,8 +25486,8 @@ + if test ${ac_cv_gcc_asm_for_mc68881+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + +@@ -24245,12 +25506,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_gcc_asm_for_mc68881=yes +-else $as_nop +- ac_cv_gcc_asm_for_mc68881=no ++else case e in #( ++ e) ac_cv_gcc_asm_for_mc68881=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_gcc_asm_for_mc68881" >&5 + printf "%s\n" "$ac_cv_gcc_asm_for_mc68881" >&6; } +@@ -24273,16 +25536,16 @@ + if test ${ac_cv_x87_double_rounding+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + # $BASECFLAGS may affect the result + ac_save_cc="$CC" + CC="$CC $BASECFLAGS" + if test "$cross_compiling" = yes + then : + ac_cv_x87_double_rounding=no +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -24308,15 +25571,18 @@ + if ac_fn_c_try_run "$LINENO" + then : + ac_cv_x87_double_rounding=no +-else $as_nop +- ac_cv_x87_double_rounding=yes ++else case e in #( ++ e) ac_cv_x87_double_rounding=yes ;; ++esac + fi + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + + CC="$ac_save_cc" +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_x87_double_rounding" >&5 + printf "%s\n" "$ac_cv_x87_double_rounding" >&6; } +@@ -24340,17 +25606,18 @@ + + for ac_func in acosh asinh atanh erf erfc expm1 log1p log2 + do : +- as_ac_var=`printf "%s\n" "ac_cv_func_$ac_func" | $as_tr_sh` ++ as_ac_var=`printf "%s\n" "ac_cv_func_$ac_func" | sed "$as_sed_sh"` + ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" + if eval test \"x\$"$as_ac_var"\" = x"yes" + then : + cat >>confdefs.h <<_ACEOF +-#define `printf "%s\n" "HAVE_$ac_func" | $as_tr_cpp` 1 ++#define `printf "%s\n" "HAVE_$ac_func" | sed "$as_sed_cpp"` 1 + _ACEOF + +-else $as_nop +- as_fn_error $? "Python requires C99 compatible libm" "$LINENO" 5 +- ++else case e in #( ++ e) as_fn_error $? "Python requires C99 compatible libm" "$LINENO" 5 ++ ;; ++esac + fi + + done +@@ -24361,12 +25628,12 @@ + if test ${ac_cv_posix_semaphores_enabled+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test "$cross_compiling" = yes ++else case e in #( ++ e) if test "$cross_compiling" = yes + then : + ac_cv_posix_semaphores_enabled=yes +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + +@@ -24392,14 +25659,17 @@ + if ac_fn_c_try_run "$LINENO" + then : + ac_cv_posix_semaphores_enabled=yes +-else $as_nop +- ac_cv_posix_semaphores_enabled=no ++else case e in #( ++ e) ac_cv_posix_semaphores_enabled=no ;; ++esac + fi + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_posix_semaphores_enabled" >&5 + printf "%s\n" "$ac_cv_posix_semaphores_enabled" >&6; } +@@ -24417,12 +25687,12 @@ + if test ${ac_cv_broken_sem_getvalue+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test "$cross_compiling" = yes ++else case e in #( ++ e) if test "$cross_compiling" = yes + then : + ac_cv_broken_sem_getvalue=yes +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + +@@ -24452,14 +25722,17 @@ + if ac_fn_c_try_run "$LINENO" + then : + ac_cv_broken_sem_getvalue=no +-else $as_nop +- ac_cv_broken_sem_getvalue=yes ++else case e in #( ++ e) ac_cv_broken_sem_getvalue=yes ;; ++esac + fi + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_broken_sem_getvalue" >&5 + printf "%s\n" "$ac_cv_broken_sem_getvalue" >&6; } +@@ -24477,8 +25750,9 @@ + if test "x$ac_cv_have_decl_RTLD_LAZY" = xyes + then : + ac_have_decl=1 +-else $as_nop +- ac_have_decl=0 ++else case e in #( ++ e) ac_have_decl=0 ;; ++esac + fi + printf "%s\n" "#define HAVE_DECL_RTLD_LAZY $ac_have_decl" >>confdefs.h + ac_fn_check_decl "$LINENO" "RTLD_NOW" "ac_cv_have_decl_RTLD_NOW" "#include +@@ -24486,8 +25760,9 @@ + if test "x$ac_cv_have_decl_RTLD_NOW" = xyes + then : + ac_have_decl=1 +-else $as_nop +- ac_have_decl=0 ++else case e in #( ++ e) ac_have_decl=0 ;; ++esac + fi + printf "%s\n" "#define HAVE_DECL_RTLD_NOW $ac_have_decl" >>confdefs.h + ac_fn_check_decl "$LINENO" "RTLD_GLOBAL" "ac_cv_have_decl_RTLD_GLOBAL" "#include +@@ -24495,8 +25770,9 @@ + if test "x$ac_cv_have_decl_RTLD_GLOBAL" = xyes + then : + ac_have_decl=1 +-else $as_nop +- ac_have_decl=0 ++else case e in #( ++ e) ac_have_decl=0 ;; ++esac + fi + printf "%s\n" "#define HAVE_DECL_RTLD_GLOBAL $ac_have_decl" >>confdefs.h + ac_fn_check_decl "$LINENO" "RTLD_LOCAL" "ac_cv_have_decl_RTLD_LOCAL" "#include +@@ -24504,8 +25780,9 @@ + if test "x$ac_cv_have_decl_RTLD_LOCAL" = xyes + then : + ac_have_decl=1 +-else $as_nop +- ac_have_decl=0 ++else case e in #( ++ e) ac_have_decl=0 ;; ++esac + fi + printf "%s\n" "#define HAVE_DECL_RTLD_LOCAL $ac_have_decl" >>confdefs.h + ac_fn_check_decl "$LINENO" "RTLD_NODELETE" "ac_cv_have_decl_RTLD_NODELETE" "#include +@@ -24513,8 +25790,9 @@ + if test "x$ac_cv_have_decl_RTLD_NODELETE" = xyes + then : + ac_have_decl=1 +-else $as_nop +- ac_have_decl=0 ++else case e in #( ++ e) ac_have_decl=0 ;; ++esac + fi + printf "%s\n" "#define HAVE_DECL_RTLD_NODELETE $ac_have_decl" >>confdefs.h + ac_fn_check_decl "$LINENO" "RTLD_NOLOAD" "ac_cv_have_decl_RTLD_NOLOAD" "#include +@@ -24522,8 +25800,9 @@ + if test "x$ac_cv_have_decl_RTLD_NOLOAD" = xyes + then : + ac_have_decl=1 +-else $as_nop +- ac_have_decl=0 ++else case e in #( ++ e) ac_have_decl=0 ;; ++esac + fi + printf "%s\n" "#define HAVE_DECL_RTLD_NOLOAD $ac_have_decl" >>confdefs.h + ac_fn_check_decl "$LINENO" "RTLD_DEEPBIND" "ac_cv_have_decl_RTLD_DEEPBIND" "#include +@@ -24531,8 +25810,9 @@ + if test "x$ac_cv_have_decl_RTLD_DEEPBIND" = xyes + then : + ac_have_decl=1 +-else $as_nop +- ac_have_decl=0 ++else case e in #( ++ e) ac_have_decl=0 ;; ++esac + fi + printf "%s\n" "#define HAVE_DECL_RTLD_DEEPBIND $ac_have_decl" >>confdefs.h + ac_fn_check_decl "$LINENO" "RTLD_MEMBER" "ac_cv_have_decl_RTLD_MEMBER" "#include +@@ -24540,8 +25820,9 @@ + if test "x$ac_cv_have_decl_RTLD_MEMBER" = xyes + then : + ac_have_decl=1 +-else $as_nop +- ac_have_decl=0 ++else case e in #( ++ e) ac_have_decl=0 ;; ++esac + fi + printf "%s\n" "#define HAVE_DECL_RTLD_MEMBER $ac_have_decl" >>confdefs.h + +@@ -24568,9 +25849,10 @@ + printf "%s\n" "#define PYLONG_BITS_IN_DIGIT $enable_big_digits" >>confdefs.h + + +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no value specified" >&5 +-printf "%s\n" "no value specified" >&6; } ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no value specified" >&5 ++printf "%s\n" "no value specified" >&6; } ;; ++esac + fi + + +@@ -24584,9 +25866,10 @@ + + wchar_h="yes" + +-else $as_nop +- wchar_h="no" +- ++else case e in #( ++ e) wchar_h="no" ++ ;; ++esac + fi + + +@@ -24595,29 +25878,31 @@ + then + # The cast to long int works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +-# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. ++# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of wchar_t" >&5 + printf %s "checking size of wchar_t... " >&6; } + if test ${ac_cv_sizeof_wchar_t+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (wchar_t))" "ac_cv_sizeof_wchar_t" "#include ++else case e in #( ++ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (wchar_t))" "ac_cv_sizeof_wchar_t" "#include + " + then : + +-else $as_nop +- if test "$ac_cv_type_wchar_t" = yes; then +- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} ++else case e in #( ++ e) if test "$ac_cv_type_wchar_t" = yes; then ++ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 ++printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + as_fn_error 77 "cannot compute sizeof (wchar_t) +-See \`config.log' for more details" "$LINENO" 5; } ++See 'config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_wchar_t=0 +- fi ++ fi ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_wchar_t" >&5 + printf "%s\n" "$ac_cv_sizeof_wchar_t" >&6; } +@@ -24638,13 +25923,13 @@ + if test ${ac_cv_wchar_t_signed+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + if test "$cross_compiling" = yes + then : + ac_cv_wchar_t_signed=yes +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -24658,13 +25943,16 @@ + if ac_fn_c_try_run "$LINENO" + then : + ac_cv_wchar_t_signed=yes +-else $as_nop +- ac_cv_wchar_t_signed=no ++else case e in #( ++ e) ac_cv_wchar_t_signed=no ;; ++esac + fi + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_wchar_t_signed" >&5 + printf "%s\n" "$ac_cv_wchar_t_signed" >&6; } +@@ -24708,8 +25996,8 @@ + if test ${ac_cv_c_bigendian+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_cv_c_bigendian=unknown ++else case e in #( ++ e) ac_cv_c_bigendian=unknown + # See if we're dealing with a universal compiler. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ +@@ -24755,8 +26043,8 @@ + int + main (void) + { +-#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ +- && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ ++#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \\ ++ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \\ + && LITTLE_ENDIAN) + bogus endian macros + #endif +@@ -24787,8 +26075,9 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_c_bigendian=yes +-else $as_nop +- ac_cv_c_bigendian=no ++else case e in #( ++ e) ac_cv_c_bigendian=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi +@@ -24832,8 +26121,9 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_c_bigendian=yes +-else $as_nop +- ac_cv_c_bigendian=no ++else case e in #( ++ e) ac_cv_c_bigendian=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi +@@ -24860,22 +26150,23 @@ + int use_ebcdic (int i) { + return ebcdic_mm[i] + ebcdic_ii[i]; + } +- extern int foo; +- +-int +-main (void) +-{ +-return use_ascii (foo) == use_ebcdic (foo); +- ; +- return 0; +-} ++ int ++ main (int argc, char **argv) ++ { ++ /* Intimidate the compiler so that it does not ++ optimize the arrays away. */ ++ char *p = argv[0]; ++ ascii_mm[1] = *p++; ebcdic_mm[1] = *p++; ++ ascii_ii[1] = *p++; ebcdic_ii[1] = *p++; ++ return use_ascii (argc) == use_ebcdic (*p); ++ } + _ACEOF +-if ac_fn_c_try_compile "$LINENO" ++if ac_fn_c_try_link "$LINENO" + then : +- if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then ++ if grep BIGenDianSyS conftest$ac_exeext >/dev/null; then + ac_cv_c_bigendian=yes + fi +- if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then ++ if grep LiTTleEnDian conftest$ac_exeext >/dev/null ; then + if test "$ac_cv_c_bigendian" = unknown; then + ac_cv_c_bigendian=no + else +@@ -24884,9 +26175,10 @@ + fi + fi + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam \ ++ conftest$ac_exeext conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + $ac_includes_default + int +@@ -24909,14 +26201,17 @@ + if ac_fn_c_try_run "$LINENO" + then : + ac_cv_c_bigendian=no +-else $as_nop +- ac_cv_c_bigendian=yes ++else case e in #( ++ e) ac_cv_c_bigendian=yes ;; ++esac + fi + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + +- fi ++ fi ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 + printf "%s\n" "$ac_cv_c_bigendian" >&6; } +@@ -24999,8 +26294,8 @@ + LIBPYTHON="\$(BLDLIBRARY)" + fi + +-# On iOS the shared libraries must be linked with the Python framework +-if test "$ac_sys_system" = "iOS"; then ++# On iOS/tvOS/watchOS the shared libraries must be linked with the Python framework ++if test "$ac_sys_system" = "iOS" -o $ac_sys_system = "tvOS" -o $ac_sys_system = "watchOS"; then + MODULE_DEPS_SHARED="$MODULE_DEPS_SHARED \$(PYTHONFRAMEWORKDIR)/\$(PYTHONFRAMEWORK)" + fi + +@@ -25034,9 +26329,10 @@ + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + printf "%s\n" "no" >&6; } + fi +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +-printf "%s\n" "no" >&6; } ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++printf "%s\n" "no" >&6; } ;; ++esac + fi + + +@@ -25067,9 +26363,10 @@ + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + printf "%s\n" "no" >&6; } + fi +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +-printf "%s\n" "no" >&6; } ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++printf "%s\n" "no" >&6; } ;; ++esac + fi + + +@@ -25080,13 +26377,13 @@ + if test ${ac_cv_rshift_extends_sign+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + if test "$cross_compiling" = yes + then : + ac_cv_rshift_extends_sign=yes +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + int main(void) +@@ -25098,13 +26395,16 @@ + if ac_fn_c_try_run "$LINENO" + then : + ac_cv_rshift_extends_sign=yes +-else $as_nop +- ac_cv_rshift_extends_sign=no ++else case e in #( ++ e) ac_cv_rshift_extends_sign=no ;; ++esac + fi + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_rshift_extends_sign" >&5 + printf "%s\n" "$ac_cv_rshift_extends_sign" >&6; } +@@ -25121,8 +26421,8 @@ + if test ${ac_cv_have_getc_unlocked+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include +@@ -25142,11 +26442,13 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_have_getc_unlocked=yes +-else $as_nop +- ac_cv_have_getc_unlocked=no ++else case e in #( ++ e) ac_cv_have_getc_unlocked=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ +- conftest$ac_exeext conftest.$ac_ext ++ conftest$ac_exeext conftest.$ac_ext ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_getc_unlocked" >&5 + printf "%s\n" "$ac_cv_have_getc_unlocked" >&6; } +@@ -25177,9 +26479,10 @@ + ;; + esac + +-else $as_nop +- with_readline=readline +- ++else case e in #( ++ e) with_readline=readline ++ ;; ++esac + fi + + +@@ -25253,7 +26556,7 @@ + + + CPPFLAGS="$CPPFLAGS $LIBREADLINE_CFLAGS" +- LDFLAGS="$LDFLAGS $LIBREADLINE_LIBS" ++ LIBS="$LIBS $LIBREADLINE_LIBS" + for ac_header in readline/readline.h + do : + ac_fn_c_check_header_compile "$LINENO" "readline/readline.h" "ac_cv_header_readline_readline_h" "$ac_includes_default" +@@ -25266,16 +26569,22 @@ + if test ${ac_cv_lib_readline_readline+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lreadline $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char readline (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char readline (void); + int + main (void) + { +@@ -25287,12 +26596,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_readline_readline=yes +-else $as_nop +- ac_cv_lib_readline_readline=no ++else case e in #( ++ e) ac_cv_lib_readline_readline=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_readline" >&5 + printf "%s\n" "$ac_cv_lib_readline_readline" >&6; } +@@ -25303,13 +26614,15 @@ + READLINE_CFLAGS=${LIBREADLINE_CFLAGS-""} + READLINE_LIBS=${LIBREADLINE_LIBS-"-lreadline"} + +-else $as_nop +- with_readline=no ++else case e in #( ++ e) with_readline=no ;; ++esac + fi + + +-else $as_nop +- with_readline=no ++else case e in #( ++ e) with_readline=no ;; ++esac + fi + + done +@@ -25345,16 +26658,22 @@ + if test ${ac_cv_lib_readline_readline+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-lreadline $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char readline (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char readline (void); + int + main (void) + { +@@ -25366,12 +26685,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_readline_readline=yes +-else $as_nop +- ac_cv_lib_readline_readline=no ++else case e in #( ++ e) ac_cv_lib_readline_readline=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_readline" >&5 + printf "%s\n" "$ac_cv_lib_readline_readline" >&6; } +@@ -25382,13 +26703,15 @@ + READLINE_CFLAGS=${LIBREADLINE_CFLAGS-""} + READLINE_LIBS=${LIBREADLINE_LIBS-"-lreadline"} + +-else $as_nop +- with_readline=no ++else case e in #( ++ e) with_readline=no ;; ++esac + fi + + +-else $as_nop +- with_readline=no ++else case e in #( ++ e) with_readline=no ;; ++esac + fi + + done +@@ -25497,16 +26820,22 @@ + if test ${ac_cv_lib_edit_readline+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-ledit $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char readline (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char readline (void); + int + main (void) + { +@@ -25518,12 +26847,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_edit_readline=yes +-else $as_nop +- ac_cv_lib_edit_readline=no ++else case e in #( ++ e) ac_cv_lib_edit_readline=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_edit_readline" >&5 + printf "%s\n" "$ac_cv_lib_edit_readline" >&6; } +@@ -25536,13 +26867,15 @@ + READLINE_CFLAGS=${LIBEDIT_CFLAGS-""} + READLINE_LIBS=${LIBEDIT_LIBS-"-ledit"} + +-else $as_nop +- with_readline=no ++else case e in #( ++ e) with_readline=no ;; ++esac + fi + + +-else $as_nop +- with_readline=no ++else case e in #( ++ e) with_readline=no ;; ++esac + fi + + done +@@ -25578,16 +26911,22 @@ + if test ${ac_cv_lib_edit_readline+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_check_lib_save_LIBS=$LIBS ++else case e in #( ++ e) ac_check_lib_save_LIBS=$LIBS + LIBS="-ledit $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char readline (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char readline (void); + int + main (void) + { +@@ -25599,12 +26938,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_lib_edit_readline=yes +-else $as_nop +- ac_cv_lib_edit_readline=no ++else case e in #( ++ e) ac_cv_lib_edit_readline=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS ++LIBS=$ac_check_lib_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_edit_readline" >&5 + printf "%s\n" "$ac_cv_lib_edit_readline" >&6; } +@@ -25617,13 +26958,15 @@ + READLINE_CFLAGS=${LIBEDIT_CFLAGS-""} + READLINE_LIBS=${LIBEDIT_LIBS-"-ledit"} + +-else $as_nop +- with_readline=no ++else case e in #( ++ e) with_readline=no ;; ++esac + fi + + +-else $as_nop +- with_readline=no ++else case e in #( ++ e) with_readline=no ;; ++esac + fi + + done +@@ -25661,8 +27004,8 @@ + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + printf "%s\n" "no" >&6; } + +-else $as_nop +- ++else case e in #( ++ e) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_readline (CFLAGS: $READLINE_CFLAGS, LIBS: $READLINE_LIBS)" >&5 + printf "%s\n" "$with_readline (CFLAGS: $READLINE_CFLAGS, LIBS: $READLINE_LIBS)" >&6; } + +@@ -25723,8 +27066,8 @@ + if test ${ac_cv_readline_rl_pre_input_hook+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + +@@ -25747,13 +27090,15 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_readline_rl_pre_input_hook=yes +-else $as_nop +- ac_cv_readline_rl_pre_input_hook=no +- ++else case e in #( ++ e) ac_cv_readline_rl_pre_input_hook=no ++ ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_readline_rl_pre_input_hook" >&5 + printf "%s\n" "$ac_cv_readline_rl_pre_input_hook" >&6; } +@@ -25772,8 +27117,8 @@ + if test ${ac_cv_readline_rl_completion_display_matches_hook+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + +@@ -25796,13 +27141,15 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_readline_rl_completion_display_matches_hook=yes +-else $as_nop +- ac_cv_readline_rl_completion_display_matches_hook=no +- ++else case e in #( ++ e) ac_cv_readline_rl_completion_display_matches_hook=no ++ ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_readline_rl_completion_display_matches_hook" >&5 + printf "%s\n" "$ac_cv_readline_rl_completion_display_matches_hook" >&6; } +@@ -25821,8 +27168,8 @@ + if test ${ac_cv_readline_rl_resize_terminal+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + +@@ -25845,13 +27192,15 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_readline_rl_resize_terminal=yes +-else $as_nop +- ac_cv_readline_rl_resize_terminal=no +- ++else case e in #( ++ e) ac_cv_readline_rl_resize_terminal=no ++ ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_readline_rl_resize_terminal" >&5 + printf "%s\n" "$ac_cv_readline_rl_resize_terminal" >&6; } +@@ -25870,8 +27219,8 @@ + if test ${ac_cv_readline_rl_completion_matches+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + +@@ -25894,13 +27243,15 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_readline_rl_completion_matches=yes +-else $as_nop +- ac_cv_readline_rl_completion_matches=no +- ++else case e in #( ++ e) ac_cv_readline_rl_completion_matches=no ++ ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_readline_rl_completion_matches" >&5 + printf "%s\n" "$ac_cv_readline_rl_completion_matches" >&6; } +@@ -25938,8 +27289,8 @@ + if test ${ac_cv_readline_append_history+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + +@@ -25962,13 +27313,15 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_readline_append_history=yes +-else $as_nop +- ac_cv_readline_append_history=no +- ++else case e in #( ++ e) ac_cv_readline_append_history=no ++ ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_readline_append_history" >&5 + printf "%s\n" "$ac_cv_readline_append_history" >&6; } +@@ -26008,8 +27361,8 @@ + if test ${ac_cv_readline_rl_startup_hook_takes_args+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + +@@ -26033,12 +27386,14 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_readline_rl_startup_hook_takes_args=yes +-else $as_nop +- ac_cv_readline_rl_startup_hook_takes_args=no +- ++else case e in #( ++ e) ac_cv_readline_rl_startup_hook_takes_args=no ++ ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_readline_rl_startup_hook_takes_args" >&5 + printf "%s\n" "$ac_cv_readline_rl_startup_hook_takes_args" >&6; } +@@ -26058,7 +27413,8 @@ + LDFLAGS=$save_LDFLAGS + LIBS=$save_LIBS + +- ++ ;; ++esac + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for broken nice()" >&5 +@@ -26066,13 +27422,13 @@ + if test ${ac_cv_broken_nice+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + if test "$cross_compiling" = yes + then : + ac_cv_broken_nice=no +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -26089,13 +27445,16 @@ + if ac_fn_c_try_run "$LINENO" + then : + ac_cv_broken_nice=yes +-else $as_nop +- ac_cv_broken_nice=no ++else case e in #( ++ e) ac_cv_broken_nice=no ;; ++esac + fi + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_broken_nice" >&5 + printf "%s\n" "$ac_cv_broken_nice" >&6; } +@@ -26111,12 +27470,12 @@ + if test ${ac_cv_broken_poll+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test "$cross_compiling" = yes ++else case e in #( ++ e) if test "$cross_compiling" = yes + then : + ac_cv_broken_poll=no +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -26142,13 +27501,16 @@ + if ac_fn_c_try_run "$LINENO" + then : + ac_cv_broken_poll=yes +-else $as_nop +- ac_cv_broken_poll=no ++else case e in #( ++ e) ac_cv_broken_poll=no ;; ++esac + fi + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_broken_poll" >&5 + printf "%s\n" "$ac_cv_broken_poll" >&6; } +@@ -26165,13 +27527,13 @@ + if test ${ac_cv_working_tzset+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + if test "$cross_compiling" = yes + then : + ac_cv_working_tzset=no +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -26241,13 +27603,16 @@ + if ac_fn_c_try_run "$LINENO" + then : + ac_cv_working_tzset=yes +-else $as_nop +- ac_cv_working_tzset=no ++else case e in #( ++ e) ac_cv_working_tzset=no ;; ++esac + fi + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_tzset" >&5 + printf "%s\n" "$ac_cv_working_tzset" >&6; } +@@ -26264,8 +27629,8 @@ + if test ${ac_cv_stat_tv_nsec+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -26282,10 +27647,12 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_stat_tv_nsec=yes +-else $as_nop +- ac_cv_stat_tv_nsec=no ++else case e in #( ++ e) ac_cv_stat_tv_nsec=no ;; ++esac + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_stat_tv_nsec" >&5 + printf "%s\n" "$ac_cv_stat_tv_nsec" >&6; } +@@ -26302,8 +27669,8 @@ + if test ${ac_cv_stat_tv_nsec2+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include + int +@@ -26320,10 +27687,12 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_stat_tv_nsec2=yes +-else $as_nop +- ac_cv_stat_tv_nsec2=no ++else case e in #( ++ e) ac_cv_stat_tv_nsec2=no ;; ++esac + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_stat_tv_nsec2" >&5 + printf "%s\n" "$ac_cv_stat_tv_nsec2" >&6; } +@@ -26339,13 +27708,13 @@ + if test ${ac_cv_normalize_century+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + if test "$cross_compiling" = yes + then : + ac_cv_normalize_century=yes +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -26369,13 +27738,16 @@ + if ac_fn_c_try_run "$LINENO" + then : + ac_cv_normalize_century=yes +-else $as_nop +- ac_cv_normalize_century=no ++else case e in #( ++ e) ac_cv_normalize_century=no ;; ++esac + fi + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_normalize_century" >&5 + printf "%s\n" "$ac_cv_normalize_century" >&6; } +@@ -26386,18 +27758,18 @@ + + fi + +-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C99-specific strftime specifiers are supported" >&5 +-printf %s "checking whether C99-specific strftime specifiers are supported... " >&6; } ++{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C99-compatible strftime specifiers are supported" >&5 ++printf %s "checking whether C99-compatible strftime specifiers are supported... " >&6; } + if test ${ac_cv_strftime_c99_support+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + if test "$cross_compiling" = yes + then : +- ac_cv_strftime_c99_support=no +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++ ac_cv_strftime_c99_support= ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -26421,22 +27793,19 @@ + if ac_fn_c_try_run "$LINENO" + then : + ac_cv_strftime_c99_support=yes +-else $as_nop +- ac_cv_strftime_c99_support=no ++else case e in #( ++ e) as_fn_error $? "Python requires C99-compatible strftime specifiers" "$LINENO" 5 ;; ++esac + fi + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_strftime_c99_support" >&5 + printf "%s\n" "$ac_cv_strftime_c99_support" >&6; } +-if test "$ac_cv_strftime_c99_support" = yes +-then +- +-printf "%s\n" "#define Py_STRFTIME_C99_SUPPORT 1" >>confdefs.h +- +-fi + + have_curses=no + have_panel=no +@@ -26824,15 +28193,21 @@ + if test ${ac_cv_search_initscr+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_func_search_save_LIBS=$LIBS ++else case e in #( ++ e) ac_func_search_save_LIBS=$LIBS + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char initscr (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char initscr (void); + int + main (void) + { +@@ -26863,11 +28238,13 @@ + if test ${ac_cv_search_initscr+y} + then : + +-else $as_nop +- ac_cv_search_initscr=no ++else case e in #( ++ e) ac_cv_search_initscr=no ;; ++esac + fi + rm conftest.$ac_ext +-LIBS=$ac_func_search_save_LIBS ++LIBS=$ac_func_search_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_initscr" >&5 + printf "%s\n" "$ac_cv_search_initscr" >&6; } +@@ -26880,8 +28257,9 @@ + have_curses=yes + CURSES_LIBS=${CURSES_LIBS-"$ac_cv_search_initscr"} + fi +-else $as_nop +- have_curses=no ++else case e in #( ++ e) have_curses=no ;; ++esac + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing update_panels" >&5 +@@ -26889,15 +28267,21 @@ + if test ${ac_cv_search_update_panels+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_func_search_save_LIBS=$LIBS ++else case e in #( ++ e) ac_func_search_save_LIBS=$LIBS + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char update_panels (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char update_panels (void); + int + main (void) + { +@@ -26928,11 +28312,13 @@ + if test ${ac_cv_search_update_panels+y} + then : + +-else $as_nop +- ac_cv_search_update_panels=no ++else case e in #( ++ e) ac_cv_search_update_panels=no ;; ++esac + fi + rm conftest.$ac_ext +-LIBS=$ac_func_search_save_LIBS ++LIBS=$ac_func_search_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_update_panels" >&5 + printf "%s\n" "$ac_cv_search_update_panels" >&6; } +@@ -26945,8 +28331,9 @@ + have_panel=yes + PANEL_LIBS=${PANEL_LIBS-"$ac_cv_search_update_panels"} + fi +-else $as_nop +- have_panel=no ++else case e in #( ++ e) have_panel=no ;; ++esac + fi + + +@@ -26998,8 +28385,8 @@ + if test ${ac_cv_mvwdelch_is_expression+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #define NCURSES_OPAQUE 0 +@@ -27031,10 +28418,12 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_mvwdelch_is_expression=yes +-else $as_nop +- ac_cv_mvwdelch_is_expression=no ++else case e in #( ++ e) ac_cv_mvwdelch_is_expression=no ;; ++esac + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mvwdelch_is_expression" >&5 + printf "%s\n" "$ac_cv_mvwdelch_is_expression" >&6; } +@@ -27051,8 +28440,8 @@ + if test ${ac_cv_window_has_flags+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #define NCURSES_OPAQUE 0 +@@ -27084,10 +28473,12 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_window_has_flags=yes +-else $as_nop +- ac_cv_window_has_flags=no ++else case e in #( ++ e) ac_cv_window_has_flags=no ;; ++esac + fi +-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_window_has_flags" >&5 + printf "%s\n" "$ac_cv_window_has_flags" >&6; } +@@ -27109,8 +28500,8 @@ + if test ${ac_cv_lib_curses_is_pad+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #define NCURSES_OPAQUE 0 +@@ -27143,11 +28534,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_lib_curses_is_pad=yes +-else $as_nop +- ac_cv_lib_curses_is_pad=no ++else case e in #( ++ e) ac_cv_lib_curses_is_pad=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_is_pad" >&5 + printf "%s\n" "$ac_cv_lib_curses_is_pad" >&6; } +@@ -27167,8 +28560,8 @@ + if test ${ac_cv_lib_curses_is_term_resized+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #define NCURSES_OPAQUE 0 +@@ -27201,11 +28594,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_lib_curses_is_term_resized=yes +-else $as_nop +- ac_cv_lib_curses_is_term_resized=no ++else case e in #( ++ e) ac_cv_lib_curses_is_term_resized=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_is_term_resized" >&5 + printf "%s\n" "$ac_cv_lib_curses_is_term_resized" >&6; } +@@ -27225,8 +28620,8 @@ + if test ${ac_cv_lib_curses_resize_term+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #define NCURSES_OPAQUE 0 +@@ -27259,11 +28654,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_lib_curses_resize_term=yes +-else $as_nop +- ac_cv_lib_curses_resize_term=no ++else case e in #( ++ e) ac_cv_lib_curses_resize_term=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_resize_term" >&5 + printf "%s\n" "$ac_cv_lib_curses_resize_term" >&6; } +@@ -27283,8 +28680,8 @@ + if test ${ac_cv_lib_curses_resizeterm+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #define NCURSES_OPAQUE 0 +@@ -27317,11 +28714,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_lib_curses_resizeterm=yes +-else $as_nop +- ac_cv_lib_curses_resizeterm=no ++else case e in #( ++ e) ac_cv_lib_curses_resizeterm=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_resizeterm" >&5 + printf "%s\n" "$ac_cv_lib_curses_resizeterm" >&6; } +@@ -27341,8 +28740,8 @@ + if test ${ac_cv_lib_curses_immedok+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #define NCURSES_OPAQUE 0 +@@ -27375,11 +28774,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_lib_curses_immedok=yes +-else $as_nop +- ac_cv_lib_curses_immedok=no ++else case e in #( ++ e) ac_cv_lib_curses_immedok=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_immedok" >&5 + printf "%s\n" "$ac_cv_lib_curses_immedok" >&6; } +@@ -27399,8 +28800,8 @@ + if test ${ac_cv_lib_curses_syncok+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #define NCURSES_OPAQUE 0 +@@ -27433,11 +28834,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_lib_curses_syncok=yes +-else $as_nop +- ac_cv_lib_curses_syncok=no ++else case e in #( ++ e) ac_cv_lib_curses_syncok=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_syncok" >&5 + printf "%s\n" "$ac_cv_lib_curses_syncok" >&6; } +@@ -27457,8 +28860,8 @@ + if test ${ac_cv_lib_curses_wchgat+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #define NCURSES_OPAQUE 0 +@@ -27491,11 +28894,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_lib_curses_wchgat=yes +-else $as_nop +- ac_cv_lib_curses_wchgat=no ++else case e in #( ++ e) ac_cv_lib_curses_wchgat=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_wchgat" >&5 + printf "%s\n" "$ac_cv_lib_curses_wchgat" >&6; } +@@ -27515,8 +28920,8 @@ + if test ${ac_cv_lib_curses_filter+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #define NCURSES_OPAQUE 0 +@@ -27549,11 +28954,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_lib_curses_filter=yes +-else $as_nop +- ac_cv_lib_curses_filter=no ++else case e in #( ++ e) ac_cv_lib_curses_filter=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_filter" >&5 + printf "%s\n" "$ac_cv_lib_curses_filter" >&6; } +@@ -27573,8 +28980,8 @@ + if test ${ac_cv_lib_curses_has_key+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #define NCURSES_OPAQUE 0 +@@ -27607,11 +29014,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_lib_curses_has_key=yes +-else $as_nop +- ac_cv_lib_curses_has_key=no ++else case e in #( ++ e) ac_cv_lib_curses_has_key=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_has_key" >&5 + printf "%s\n" "$ac_cv_lib_curses_has_key" >&6; } +@@ -27631,8 +29040,8 @@ + if test ${ac_cv_lib_curses_typeahead+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #define NCURSES_OPAQUE 0 +@@ -27665,11 +29074,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_lib_curses_typeahead=yes +-else $as_nop +- ac_cv_lib_curses_typeahead=no ++else case e in #( ++ e) ac_cv_lib_curses_typeahead=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_typeahead" >&5 + printf "%s\n" "$ac_cv_lib_curses_typeahead" >&6; } +@@ -27689,8 +29100,8 @@ + if test ${ac_cv_lib_curses_use_env+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #define NCURSES_OPAQUE 0 +@@ -27723,11 +29134,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_lib_curses_use_env=yes +-else $as_nop +- ac_cv_lib_curses_use_env=no ++else case e in #( ++ e) ac_cv_lib_curses_use_env=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_use_env" >&5 + printf "%s\n" "$ac_cv_lib_curses_use_env" >&6; } +@@ -27752,7 +29165,7 @@ + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for device files" >&5 + printf "%s\n" "$as_me: checking for device files" >&6;} + +-if test "$ac_sys_system" = "Linux-android" || test "$ac_sys_system" = "iOS"; then ++if test "$ac_sys_system" = "Linux-android" -o "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "watchOS" ; then + ac_cv_file__dev_ptmx=no + ac_cv_file__dev_ptc=no + else +@@ -27778,14 +29191,15 @@ + if test ${ac_cv_file__dev_ptmx+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- test "$cross_compiling" = yes && ++else case e in #( ++ e) test "$cross_compiling" = yes && + as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 + if test -r "/dev/ptmx"; then + ac_cv_file__dev_ptmx=yes + else + ac_cv_file__dev_ptmx=no +-fi ++fi ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__dev_ptmx" >&5 + printf "%s\n" "$ac_cv_file__dev_ptmx" >&6; } +@@ -27804,14 +29218,15 @@ + if test ${ac_cv_file__dev_ptc+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- test "$cross_compiling" = yes && ++else case e in #( ++ e) test "$cross_compiling" = yes && + as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 + if test -r "/dev/ptc"; then + ac_cv_file__dev_ptc=yes + else + ac_cv_file__dev_ptc=no +-fi ++fi ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__dev_ptc" >&5 + printf "%s\n" "$ac_cv_file__dev_ptc" >&6; } +@@ -27847,10 +29262,11 @@ + printf "%s\n" "#define HAVE_SOCKLEN_T 1" >>confdefs.h + + +-else $as_nop +- ++else case e in #( ++ e) + printf "%s\n" "#define socklen_t int" >>confdefs.h +- ++ ;; ++esac + fi + + +@@ -27859,12 +29275,12 @@ + if test ${ac_cv_broken_mbstowcs+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test "$cross_compiling" = yes ++else case e in #( ++ e) if test "$cross_compiling" = yes + then : + ac_cv_broken_mbstowcs=no +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -27881,13 +29297,16 @@ + if ac_fn_c_try_run "$LINENO" + then : + ac_cv_broken_mbstowcs=no +-else $as_nop +- ac_cv_broken_mbstowcs=yes ++else case e in #( ++ e) ac_cv_broken_mbstowcs=yes ;; ++esac + fi + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_broken_mbstowcs" >&5 + printf "%s\n" "$ac_cv_broken_mbstowcs" >&6; } +@@ -27923,9 +29342,10 @@ + printf "%s\n" "no" >&6; } + fi + +-else $as_nop +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no value specified" >&5 +-printf "%s\n" "no value specified" >&6; } ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no value specified" >&5 ++printf "%s\n" "no value specified" >&6; } ;; ++esac + fi + + +@@ -27934,16 +29354,16 @@ + if test ${ac_cv_computed_gotos+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test "$cross_compiling" = yes ++else case e in #( ++ e) if test "$cross_compiling" = yes + then : + if test "${with_computed_gotos+set}" = set; then + ac_cv_computed_gotos="$with_computed_gotos -- configured --with(out)-computed-gotos" + else + ac_cv_computed_gotos=no + fi +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + int main(int argc, char **argv) +@@ -27961,13 +29381,16 @@ + if ac_fn_c_try_run "$LINENO" + then : + ac_cv_computed_gotos=yes +-else $as_nop +- ac_cv_computed_gotos=no ++else case e in #( ++ e) ac_cv_computed_gotos=no ;; ++esac + fi + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_computed_gotos" >&5 + printf "%s\n" "$ac_cv_computed_gotos" >&6; } +@@ -27977,6 +29400,51 @@ + + esac + ++# Check for --with-tail-call-interp ++{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-tail-call-interp" >&5 ++printf %s "checking for --with-tail-call-interp... " >&6; } ++ ++# Check whether --with-tail-call-interp was given. ++if test ${with_tail_call_interp+y} ++then : ++ withval=$with_tail_call_interp; ++if test "$withval" = yes ++then ++ ++printf "%s\n" "#define Py_TAIL_CALL_INTERP 1" >>confdefs.h ++ ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 ++printf "%s\n" "yes" >&6; } ++fi ++if test "$withval" = no ++then ++ ++printf "%s\n" "#define Py_TAIL_CALL_INTERP 0" >>confdefs.h ++ ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++printf "%s\n" "no" >&6; } ++fi ++ ++else case e in #( ++ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no value specified" >&5 ++printf "%s\n" "no value specified" >&6; } ;; ++esac ++fi ++ ++ ++# Do not enable tail-calling interpreter if tier 2 is enabled. ++if ${tier2_flags:+false} : ++then : ++ ++ case "$ac_cv_tail_call" in yes*) ++ ++printf "%s\n" "#define Py_TAIL_CALL_INTERP 1" >>confdefs.h ++ ++ esac ++ ++fi ++ ++ + case $ac_sys_system in + AIX*) + +@@ -28034,8 +29502,8 @@ + if test ${ac_cv_compile_o2+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + saved_cflags="$CFLAGS" + CFLAGS="-O2" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -28052,12 +29520,14 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ac_cv_compile_o2=yes +-else $as_nop +- ac_cv_compile_o2=no ++else case e in #( ++ e) ac_cv_compile_o2=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + CFLAGS="$saved_cflags" +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_compile_o2" >&5 + printf "%s\n" "$ac_cv_compile_o2" >&6; } +@@ -28074,8 +29544,8 @@ + if test "$cross_compiling" = yes + then : + have_glibc_memmove_bug=undefined +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + #include +@@ -28097,11 +29567,13 @@ + if ac_fn_c_try_run "$LINENO" + then : + have_glibc_memmove_bug=no +-else $as_nop +- have_glibc_memmove_bug=yes ++else case e in #( ++ e) have_glibc_memmove_bug=yes ;; ++esac + fi + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + + CFLAGS="$saved_cflags" +@@ -28126,8 +29598,8 @@ + if test "$cross_compiling" = yes + then : + have_ipa_pure_const_bug=undefined +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + __attribute__((noinline)) int +@@ -28150,11 +29622,13 @@ + if ac_fn_c_try_run "$LINENO" + then : + have_ipa_pure_const_bug=no +-else $as_nop +- have_ipa_pure_const_bug=yes ++else case e in #( ++ e) have_ipa_pure_const_bug=yes ;; ++esac + fi + rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; ++esac + fi + + CFLAGS="$saved_cflags" +@@ -28177,20 +29651,21 @@ + if test ${with_ensurepip+y} + then : + withval=$with_ensurepip; +-else $as_nop +- ++else case e in #( ++ e) + case $ac_sys_system in #( + Emscripten) : + with_ensurepip=no ;; #( + WASI) : + with_ensurepip=no ;; #( +- iOS) : ++ iOS|tvOS|watchOS) : + with_ensurepip=no ;; #( + *) : + with_ensurepip=upgrade + ;; + esac +- ++ ;; ++esac + fi + + case $with_ensurepip in #( +@@ -28213,8 +29688,8 @@ + if test ${ac_cv_dirent_d_type+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + +@@ -28231,12 +29706,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_dirent_d_type=yes +-else $as_nop +- ac_cv_dirent_d_type=no ++else case e in #( ++ e) ac_cv_dirent_d_type=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_dirent_d_type" >&5 + printf "%s\n" "$ac_cv_dirent_d_type" >&6; } +@@ -28256,8 +29733,8 @@ + if test ${ac_cv_getrandom_syscall+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + +@@ -28281,12 +29758,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_getrandom_syscall=yes +-else $as_nop +- ac_cv_getrandom_syscall=no ++else case e in #( ++ e) ac_cv_getrandom_syscall=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_getrandom_syscall" >&5 + printf "%s\n" "$ac_cv_getrandom_syscall" >&6; } +@@ -28307,8 +29786,8 @@ + if test ${ac_cv_func_getrandom+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + +@@ -28330,12 +29809,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_func_getrandom=yes +-else $as_nop +- ac_cv_func_getrandom=no ++else case e in #( ++ e) ac_cv_func_getrandom=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getrandom" >&5 + printf "%s\n" "$ac_cv_func_getrandom" >&6; } +@@ -28363,15 +29844,21 @@ + if test ${ac_cv_search_shm_open+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ac_func_search_save_LIBS=$LIBS ++else case e in #( ++ e) ac_func_search_save_LIBS=$LIBS + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + /* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-char shm_open (); ++ builtin and then its argument prototype would still apply. ++ The 'extern "C"' is for builds by C++ compilers; ++ although this is not generally supported in C code supporting it here ++ has little cost and some practical benefit (sr 110532). */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char shm_open (void); + int + main (void) + { +@@ -28402,11 +29889,13 @@ + if test ${ac_cv_search_shm_open+y} + then : + +-else $as_nop +- ac_cv_search_shm_open=no ++else case e in #( ++ e) ac_cv_search_shm_open=no ;; ++esac + fi + rm conftest.$ac_ext +-LIBS=$ac_func_search_save_LIBS ++LIBS=$ac_func_search_save_LIBS ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_shm_open" >&5 + printf "%s\n" "$ac_cv_search_shm_open" >&6; } +@@ -28434,16 +29923,17 @@ + + for ac_func in shm_open shm_unlink + do : +- as_ac_var=`printf "%s\n" "ac_cv_func_$ac_func" | $as_tr_sh` ++ as_ac_var=`printf "%s\n" "ac_cv_func_$ac_func" | sed "$as_sed_sh"` + ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" + if eval test \"x\$"$as_ac_var"\" = x"yes" + then : + cat >>confdefs.h <<_ACEOF +-#define `printf "%s\n" "HAVE_$ac_func" | $as_tr_cpp` 1 ++#define `printf "%s\n" "HAVE_$ac_func" | sed "$as_sed_cpp"` 1 + _ACEOF + have_posix_shmem=yes +-else $as_nop +- have_posix_shmem=no ++else case e in #( ++ e) have_posix_shmem=no ;; ++esac + fi + + done +@@ -28472,8 +29962,8 @@ + ;; + esac + +-else $as_nop +- ++else case e in #( ++ e) + # if pkg-config is installed and openssl has installed a .pc file, + # then use that information and don't search ssldirs + if test -n "$ac_tool_prefix"; then +@@ -28484,8 +29974,8 @@ + if test ${ac_cv_prog_PKG_CONFIG+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test -n "$PKG_CONFIG"; then ++else case e in #( ++ e) if test -n "$PKG_CONFIG"; then + ac_cv_prog_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test. + else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +@@ -28507,7 +29997,8 @@ + done + IFS=$as_save_IFS + +-fi ++fi ;; ++esac + fi + PKG_CONFIG=$ac_cv_prog_PKG_CONFIG + if test -n "$PKG_CONFIG"; then +@@ -28529,8 +30020,8 @@ + if test ${ac_cv_prog_ac_ct_PKG_CONFIG+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- if test -n "$ac_ct_PKG_CONFIG"; then ++else case e in #( ++ e) if test -n "$ac_ct_PKG_CONFIG"; then + ac_cv_prog_ac_ct_PKG_CONFIG="$ac_ct_PKG_CONFIG" # Let the user override the test. + else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +@@ -28552,7 +30043,8 @@ + done + IFS=$as_save_IFS + +-fi ++fi ;; ++esac + fi + ac_ct_PKG_CONFIG=$ac_cv_prog_ac_ct_PKG_CONFIG + if test -n "$ac_ct_PKG_CONFIG"; then +@@ -28592,7 +30084,8 @@ + ssldirs="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr" + fi + +- ++ ;; ++esac + fi + + +@@ -28655,12 +30148,13 @@ + printf "%s\n" "yes" >&6; } + have_openssl=yes + +-else $as_nop +- ++else case e in #( ++ e) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + printf "%s\n" "no" >&6; } + have_openssl=no +- ++ ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +@@ -28679,15 +30173,16 @@ + + rpath_arg="-Wl,--enable-new-dtags,-rpath=" + +-else $as_nop +- ++else case e in #( ++ e) + if test "$ac_sys_system" = "Darwin" + then + rpath_arg="-Wl,-rpath," + else + rpath_arg="-Wl,-rpath=" + fi +- ++ ;; ++esac + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-openssl-rpath" >&5 +@@ -28697,9 +30192,10 @@ + if test ${with_openssl_rpath+y} + then : + withval=$with_openssl_rpath; +-else $as_nop +- with_openssl_rpath=no +- ++else case e in #( ++ e) with_openssl_rpath=no ++ ;; ++esac + fi + + case $with_openssl_rpath in #( +@@ -28725,8 +30221,9 @@ + OPENSSL_RPATH="$with_openssl_rpath" + OPENSSL_LDFLAGS_RPATH="${rpath_arg}$with_openssl_rpath" + +-else $as_nop +- as_fn_error $? "--with-openssl-rpath \"$with_openssl_rpath\" is not a directory" "$LINENO" 5 ++else case e in #( ++ e) as_fn_error $? "--with-openssl-rpath \"$with_openssl_rpath\" is not a directory" "$LINENO" 5 ;; ++esac + fi + + ;; +@@ -28789,8 +30286,8 @@ + if test ${ac_cv_working_openssl_ssl+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + +@@ -28820,12 +30317,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_working_openssl_ssl=yes +-else $as_nop +- ac_cv_working_openssl_ssl=no ++else case e in #( ++ e) ac_cv_working_openssl_ssl=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_openssl_ssl" >&5 + printf "%s\n" "$ac_cv_working_openssl_ssl" >&6; } +@@ -28852,8 +30351,8 @@ + if test ${ac_cv_working_openssl_hashlib+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + +@@ -28880,12 +30379,14 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_working_openssl_hashlib=yes +-else $as_nop +- ac_cv_working_openssl_hashlib=no ++else case e in #( ++ e) ac_cv_working_openssl_hashlib=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +- ++ ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_openssl_hashlib" >&5 + printf "%s\n" "$ac_cv_working_openssl_hashlib" >&6; } +@@ -28927,13 +30428,14 @@ + ;; + esac + +-else $as_nop +- ++else case e in #( ++ e) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: python" >&5 + printf "%s\n" "python" >&6; } + printf "%s\n" "#define PY_SSL_DEFAULT_CIPHERS 1" >>confdefs.h + +- ++ ;; ++esac + fi + + +@@ -28956,8 +30458,9 @@ + ;; + esac + +-else $as_nop +- with_builtin_hashlib_hashes=$default_hashlib_hashes ++else case e in #( ++ e) with_builtin_hashlib_hashes=$default_hashlib_hashes ;; ++esac + fi + + +@@ -28999,12 +30502,14 @@ + if test "x$enable_test_modules" = xyes + then : + TEST_MODULES=yes +-else $as_nop +- TEST_MODULES=no ++else case e in #( ++ e) TEST_MODULES=no ;; ++esac + fi + +-else $as_nop +- TEST_MODULES=yes ++else case e in #( ++ e) TEST_MODULES=yes ;; ++esac + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $TEST_MODULES" >&5 +@@ -29033,8 +30538,8 @@ + if test ${ac_cv_libatomic_needed+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++else case e in #( ++ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + + // pyatomic.h needs uint64_t and Py_ssize_t types +@@ -29077,11 +30582,13 @@ + if ac_fn_c_try_link "$LINENO" + then : + ac_cv_libatomic_needed=no +-else $as_nop +- ac_cv_libatomic_needed=yes ++else case e in #( ++ e) ac_cv_libatomic_needed=yes ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam \ +- conftest$ac_exeext conftest.$ac_ext ++ conftest$ac_exeext conftest.$ac_ext ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libatomic_needed" >&5 + printf "%s\n" "$ac_cv_libatomic_needed" >&6; } +@@ -29096,16 +30603,17 @@ + + # gh-59705: Maximum length in bytes of a thread name + case "$ac_sys_system" in +- Linux*) PYTHREAD_NAME_MAXLEN=15;; # Linux and Android +- SunOS*) PYTHREAD_NAME_MAXLEN=31;; +- Darwin) PYTHREAD_NAME_MAXLEN=63;; +- iOS) PYTHREAD_NAME_MAXLEN=63;; +- FreeBSD*) PYTHREAD_NAME_MAXLEN=98;; +- *) PYTHREAD_NAME_MAXLEN=;; ++ Linux*) _PYTHREAD_NAME_MAXLEN=15;; # Linux and Android ++ SunOS*) _PYTHREAD_NAME_MAXLEN=31;; ++ NetBSD*) _PYTHREAD_NAME_MAXLEN=31;; ++ Darwin) _PYTHREAD_NAME_MAXLEN=63;; ++ iOS) _PYTHREAD_NAME_MAXLEN=63;; ++ FreeBSD*) _PYTHREAD_NAME_MAXLEN=98;; ++ *) _PYTHREAD_NAME_MAXLEN=;; + esac +-if test -n "$PYTHREAD_NAME_MAXLEN"; then ++if test -n "$_PYTHREAD_NAME_MAXLEN"; then + +-printf "%s\n" "#define PYTHREAD_NAME_MAXLEN $PYTHREAD_NAME_MAXLEN" >>confdefs.h ++printf "%s\n" "#define _PYTHREAD_NAME_MAXLEN $_PYTHREAD_NAME_MAXLEN" >>confdefs.h + + fi + +@@ -29130,7 +30638,7 @@ + ;; #( + Darwin) : + ;; #( +- iOS) : ++ iOS|tvOS|watchOS) : + + + +@@ -29733,11 +31241,13 @@ + if test "$ac_cv_func_sem_unlink" = "yes" + then : + py_cv_module__multiprocessing=yes +-else $as_nop +- py_cv_module__multiprocessing=missing ++else case e in #( ++ e) py_cv_module__multiprocessing=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__multiprocessing=disabled ++else case e in #( ++ e) py_cv_module__multiprocessing=disabled ;; ++esac + fi + + fi +@@ -29771,11 +31281,13 @@ + if test "$have_posix_shmem" = "yes" + then : + py_cv_module__posixshmem=yes +-else $as_nop +- py_cv_module__posixshmem=missing ++else case e in #( ++ e) py_cv_module__posixshmem=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__posixshmem=disabled ++else case e in #( ++ e) py_cv_module__posixshmem=disabled ;; ++esac + fi + + fi +@@ -29900,11 +31412,13 @@ + if test "$ac_cv_header_sys_ioctl_h" = "yes" -a "$ac_cv_header_fcntl_h" = "yes" + then : + py_cv_module_fcntl=yes +-else $as_nop +- py_cv_module_fcntl=missing ++else case e in #( ++ e) py_cv_module_fcntl=missing ;; ++esac + fi +-else $as_nop +- py_cv_module_fcntl=disabled ++else case e in #( ++ e) py_cv_module_fcntl=disabled ;; ++esac + fi + + fi +@@ -29938,11 +31452,13 @@ + if test "$ac_cv_header_sys_mman_h" = "yes" -a "$ac_cv_header_sys_stat_h" = "yes" + then : + py_cv_module_mmap=yes +-else $as_nop +- py_cv_module_mmap=missing ++else case e in #( ++ e) py_cv_module_mmap=missing ;; ++esac + fi +-else $as_nop +- py_cv_module_mmap=disabled ++else case e in #( ++ e) py_cv_module_mmap=disabled ;; ++esac + fi + + fi +@@ -29976,11 +31492,13 @@ + if test "$ac_cv_header_sys_socket_h" = "yes" -a "$ac_cv_header_sys_types_h" = "yes" -a "$ac_cv_header_netinet_in_h" = "yes" + then : + py_cv_module__socket=yes +-else $as_nop +- py_cv_module__socket=missing ++else case e in #( ++ e) py_cv_module__socket=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__socket=disabled ++else case e in #( ++ e) py_cv_module__socket=disabled ;; ++esac + fi + + fi +@@ -30016,11 +31534,13 @@ + { test "$ac_cv_func_getgrgid" = "yes" || test "$ac_cv_func_getgrgid_r" = "yes"; } + then : + py_cv_module_grp=yes +-else $as_nop +- py_cv_module_grp=missing ++else case e in #( ++ e) py_cv_module_grp=missing ;; ++esac + fi +-else $as_nop +- py_cv_module_grp=disabled ++else case e in #( ++ e) py_cv_module_grp=disabled ;; ++esac + fi + + fi +@@ -30054,11 +31574,13 @@ + if test "$ac_cv_func_getpwuid" = yes -o "$ac_cv_func_getpwuid_r" = yes + then : + py_cv_module_pwd=yes +-else $as_nop +- py_cv_module_pwd=missing ++else case e in #( ++ e) py_cv_module_pwd=missing ;; ++esac + fi +-else $as_nop +- py_cv_module_pwd=disabled ++else case e in #( ++ e) py_cv_module_pwd=disabled ;; ++esac + fi + + fi +@@ -30092,11 +31614,13 @@ + if test "$ac_cv_header_sys_resource_h" = yes + then : + py_cv_module_resource=yes +-else $as_nop +- py_cv_module_resource=missing ++else case e in #( ++ e) py_cv_module_resource=missing ;; ++esac + fi +-else $as_nop +- py_cv_module_resource=disabled ++else case e in #( ++ e) py_cv_module_resource=disabled ;; ++esac + fi + + fi +@@ -30130,11 +31654,13 @@ + if true + then : + py_cv_module__scproxy=yes +-else $as_nop +- py_cv_module__scproxy=missing ++else case e in #( ++ e) py_cv_module__scproxy=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__scproxy=disabled ++else case e in #( ++ e) py_cv_module__scproxy=disabled ;; ++esac + fi + + fi +@@ -30168,11 +31694,13 @@ + if test "$ac_cv_header_syslog_h" = yes + then : + py_cv_module_syslog=yes +-else $as_nop +- py_cv_module_syslog=missing ++else case e in #( ++ e) py_cv_module_syslog=missing ;; ++esac + fi +-else $as_nop +- py_cv_module_syslog=disabled ++else case e in #( ++ e) py_cv_module_syslog=disabled ;; ++esac + fi + + fi +@@ -30206,11 +31734,13 @@ + if test "$ac_cv_header_termios_h" = yes + then : + py_cv_module_termios=yes +-else $as_nop +- py_cv_module_termios=missing ++else case e in #( ++ e) py_cv_module_termios=missing ;; ++esac + fi +-else $as_nop +- py_cv_module_termios=disabled ++else case e in #( ++ e) py_cv_module_termios=disabled ;; ++esac + fi + + fi +@@ -30245,11 +31775,13 @@ + if test "$ac_cv_header_sys_time_h" = "yes" + then : + py_cv_module_pyexpat=yes +-else $as_nop +- py_cv_module_pyexpat=missing ++else case e in #( ++ e) py_cv_module_pyexpat=missing ;; ++esac + fi +-else $as_nop +- py_cv_module_pyexpat=disabled ++else case e in #( ++ e) py_cv_module_pyexpat=disabled ;; ++esac + fi + + fi +@@ -30283,11 +31815,13 @@ + if true + then : + py_cv_module__elementtree=yes +-else $as_nop +- py_cv_module__elementtree=missing ++else case e in #( ++ e) py_cv_module__elementtree=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__elementtree=disabled ++else case e in #( ++ e) py_cv_module__elementtree=disabled ;; ++esac + fi + + fi +@@ -30498,11 +32032,13 @@ + if true + then : + py_cv_module__md5=yes +-else $as_nop +- py_cv_module__md5=missing ++else case e in #( ++ e) py_cv_module__md5=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__md5=disabled ++else case e in #( ++ e) py_cv_module__md5=disabled ;; ++esac + fi + + fi +@@ -30536,11 +32072,13 @@ + if true + then : + py_cv_module__sha1=yes +-else $as_nop +- py_cv_module__sha1=missing ++else case e in #( ++ e) py_cv_module__sha1=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__sha1=disabled ++else case e in #( ++ e) py_cv_module__sha1=disabled ;; ++esac + fi + + fi +@@ -30574,11 +32112,13 @@ + if true + then : + py_cv_module__sha2=yes +-else $as_nop +- py_cv_module__sha2=missing ++else case e in #( ++ e) py_cv_module__sha2=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__sha2=disabled ++else case e in #( ++ e) py_cv_module__sha2=disabled ;; ++esac + fi + + fi +@@ -30612,11 +32152,13 @@ + if true + then : + py_cv_module__sha3=yes +-else $as_nop +- py_cv_module__sha3=missing ++else case e in #( ++ e) py_cv_module__sha3=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__sha3=disabled ++else case e in #( ++ e) py_cv_module__sha3=disabled ;; ++esac + fi + + fi +@@ -30650,11 +32192,13 @@ + if true + then : + py_cv_module__blake2=yes +-else $as_nop +- py_cv_module__blake2=missing ++else case e in #( ++ e) py_cv_module__blake2=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__blake2=disabled ++else case e in #( ++ e) py_cv_module__blake2=disabled ;; ++esac + fi + + fi +@@ -30697,8 +32241,8 @@ + if test ${ax_cv_check_cflags__Werror__msse__msse2__msse3__msse4_1__msse4_2+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + ax_check_save_flags=$CFLAGS + CFLAGS="$CFLAGS -Werror -msse -msse2 -msse3 -msse4.1 -msse4.2" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -30715,11 +32259,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ax_cv_check_cflags__Werror__msse__msse2__msse3__msse4_1__msse4_2=yes +-else $as_nop +- ax_cv_check_cflags__Werror__msse__msse2__msse3__msse4_1__msse4_2=no ++else case e in #( ++ e) ax_cv_check_cflags__Werror__msse__msse2__msse3__msse4_1__msse4_2=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- CFLAGS=$ax_check_save_flags ++ CFLAGS=$ax_check_save_flags ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror__msse__msse2__msse3__msse4_1__msse4_2" >&5 + printf "%s\n" "$ax_cv_check_cflags__Werror__msse__msse2__msse3__msse4_1__msse4_2" >&6; } +@@ -30748,8 +32294,9 @@ + fi + + +-else $as_nop +- : ++else case e in #( ++ e) : ;; ++esac + fi + + fi +@@ -30769,8 +32316,8 @@ + if test ${ax_cv_check_cflags__Werror__mavx2+y} + then : + printf %s "(cached) " >&6 +-else $as_nop +- ++else case e in #( ++ e) + ax_check_save_flags=$CFLAGS + CFLAGS="$CFLAGS -Werror -mavx2" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -30787,11 +32334,13 @@ + if ac_fn_c_try_compile "$LINENO" + then : + ax_cv_check_cflags__Werror__mavx2=yes +-else $as_nop +- ax_cv_check_cflags__Werror__mavx2=no ++else case e in #( ++ e) ax_cv_check_cflags__Werror__mavx2=no ;; ++esac + fi + rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +- CFLAGS=$ax_check_save_flags ++ CFLAGS=$ax_check_save_flags ;; ++esac + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror__mavx2" >&5 + printf "%s\n" "$ax_cv_check_cflags__Werror__mavx2" >&6; } +@@ -30819,8 +32368,9 @@ + printf "%s\n" "standard" >&6; } + fi + +-else $as_nop +- : ++else case e in #( ++ e) : ;; ++esac + fi + + fi +@@ -30838,11 +32388,13 @@ + if test "$have_libffi" = yes + then : + py_cv_module__ctypes=yes +-else $as_nop +- py_cv_module__ctypes=missing ++else case e in #( ++ e) py_cv_module__ctypes=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__ctypes=disabled ++else case e in #( ++ e) py_cv_module__ctypes=disabled ;; ++esac + fi + + fi +@@ -30876,11 +32428,13 @@ + if test "$have_curses" = "yes" + then : + py_cv_module__curses=yes +-else $as_nop +- py_cv_module__curses=missing ++else case e in #( ++ e) py_cv_module__curses=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__curses=disabled ++else case e in #( ++ e) py_cv_module__curses=disabled ;; ++esac + fi + + fi +@@ -30915,11 +32469,13 @@ + if test "$have_curses" = "yes" && test "$have_panel" = "yes" + then : + py_cv_module__curses_panel=yes +-else $as_nop +- py_cv_module__curses_panel=missing ++else case e in #( ++ e) py_cv_module__curses_panel=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__curses_panel=disabled ++else case e in #( ++ e) py_cv_module__curses_panel=disabled ;; ++esac + fi + + fi +@@ -30954,11 +32510,13 @@ + if test "$have_mpdec" = "yes" + then : + py_cv_module__decimal=yes +-else $as_nop +- py_cv_module__decimal=missing ++else case e in #( ++ e) py_cv_module__decimal=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__decimal=disabled ++else case e in #( ++ e) py_cv_module__decimal=disabled ;; ++esac + fi + + fi +@@ -30992,11 +32550,13 @@ + if test "$have_dbm" != "no" + then : + py_cv_module__dbm=yes +-else $as_nop +- py_cv_module__dbm=missing ++else case e in #( ++ e) py_cv_module__dbm=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__dbm=disabled ++else case e in #( ++ e) py_cv_module__dbm=disabled ;; ++esac + fi + + fi +@@ -31030,11 +32590,13 @@ + if test "$have_gdbm" = yes + then : + py_cv_module__gdbm=yes +-else $as_nop +- py_cv_module__gdbm=missing ++else case e in #( ++ e) py_cv_module__gdbm=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__gdbm=disabled ++else case e in #( ++ e) py_cv_module__gdbm=disabled ;; ++esac + fi + + fi +@@ -31068,11 +32630,13 @@ + if test "$with_readline" != "no" + then : + py_cv_module_readline=yes +-else $as_nop +- py_cv_module_readline=missing ++else case e in #( ++ e) py_cv_module_readline=missing ;; ++esac + fi +-else $as_nop +- py_cv_module_readline=disabled ++else case e in #( ++ e) py_cv_module_readline=disabled ;; ++esac + fi + + fi +@@ -31106,11 +32670,13 @@ + if test "$have_supported_sqlite3" = "yes" + then : + py_cv_module__sqlite3=yes +-else $as_nop +- py_cv_module__sqlite3=missing ++else case e in #( ++ e) py_cv_module__sqlite3=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__sqlite3=disabled ++else case e in #( ++ e) py_cv_module__sqlite3=disabled ;; ++esac + fi + + fi +@@ -31144,11 +32710,13 @@ + if test "$have_tcltk" = "yes" + then : + py_cv_module__tkinter=yes +-else $as_nop +- py_cv_module__tkinter=missing ++else case e in #( ++ e) py_cv_module__tkinter=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__tkinter=disabled ++else case e in #( ++ e) py_cv_module__tkinter=disabled ;; ++esac + fi + + fi +@@ -31182,11 +32750,13 @@ + if test "$have_uuid" = "yes" + then : + py_cv_module__uuid=yes +-else $as_nop +- py_cv_module__uuid=missing ++else case e in #( ++ e) py_cv_module__uuid=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__uuid=disabled ++else case e in #( ++ e) py_cv_module__uuid=disabled ;; ++esac + fi + + fi +@@ -31221,11 +32791,13 @@ + if test "$have_zlib" = yes + then : + py_cv_module_zlib=yes +-else $as_nop +- py_cv_module_zlib=missing ++else case e in #( ++ e) py_cv_module_zlib=missing ;; ++esac + fi +-else $as_nop +- py_cv_module_zlib=disabled ++else case e in #( ++ e) py_cv_module_zlib=disabled ;; ++esac + fi + + fi +@@ -31281,11 +32853,13 @@ + if test "$have_bzip2" = yes + then : + py_cv_module__bz2=yes +-else $as_nop +- py_cv_module__bz2=missing ++else case e in #( ++ e) py_cv_module__bz2=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__bz2=disabled ++else case e in #( ++ e) py_cv_module__bz2=disabled ;; ++esac + fi + + fi +@@ -31319,11 +32893,13 @@ + if test "$have_liblzma" = yes + then : + py_cv_module__lzma=yes +-else $as_nop +- py_cv_module__lzma=missing ++else case e in #( ++ e) py_cv_module__lzma=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__lzma=disabled ++else case e in #( ++ e) py_cv_module__lzma=disabled ;; ++esac + fi + + fi +@@ -31358,11 +32934,13 @@ + if test "$ac_cv_working_openssl_ssl" = yes + then : + py_cv_module__ssl=yes +-else $as_nop +- py_cv_module__ssl=missing ++else case e in #( ++ e) py_cv_module__ssl=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__ssl=disabled ++else case e in #( ++ e) py_cv_module__ssl=disabled ;; ++esac + fi + + fi +@@ -31396,11 +32974,13 @@ + if test "$ac_cv_working_openssl_hashlib" = yes + then : + py_cv_module__hashlib=yes +-else $as_nop +- py_cv_module__hashlib=missing ++else case e in #( ++ e) py_cv_module__hashlib=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__hashlib=disabled ++else case e in #( ++ e) py_cv_module__hashlib=disabled ;; ++esac + fi + + fi +@@ -31435,11 +33015,13 @@ + if true + then : + py_cv_module__testcapi=yes +-else $as_nop +- py_cv_module__testcapi=missing ++else case e in #( ++ e) py_cv_module__testcapi=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__testcapi=disabled ++else case e in #( ++ e) py_cv_module__testcapi=disabled ;; ++esac + fi + + fi +@@ -31473,11 +33055,13 @@ + if true + then : + py_cv_module__testclinic=yes +-else $as_nop +- py_cv_module__testclinic=missing ++else case e in #( ++ e) py_cv_module__testclinic=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__testclinic=disabled ++else case e in #( ++ e) py_cv_module__testclinic=disabled ;; ++esac + fi + + fi +@@ -31511,11 +33095,13 @@ + if true + then : + py_cv_module__testclinic_limited=yes +-else $as_nop +- py_cv_module__testclinic_limited=missing ++else case e in #( ++ e) py_cv_module__testclinic_limited=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__testclinic_limited=disabled ++else case e in #( ++ e) py_cv_module__testclinic_limited=disabled ;; ++esac + fi + + fi +@@ -31549,11 +33135,13 @@ + if true + then : + py_cv_module__testlimitedcapi=yes +-else $as_nop +- py_cv_module__testlimitedcapi=missing ++else case e in #( ++ e) py_cv_module__testlimitedcapi=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__testlimitedcapi=disabled ++else case e in #( ++ e) py_cv_module__testlimitedcapi=disabled ;; ++esac + fi + + fi +@@ -31587,11 +33175,13 @@ + if true + then : + py_cv_module__testinternalcapi=yes +-else $as_nop +- py_cv_module__testinternalcapi=missing ++else case e in #( ++ e) py_cv_module__testinternalcapi=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__testinternalcapi=disabled ++else case e in #( ++ e) py_cv_module__testinternalcapi=disabled ;; ++esac + fi + + fi +@@ -31625,11 +33215,13 @@ + if true + then : + py_cv_module__testbuffer=yes +-else $as_nop +- py_cv_module__testbuffer=missing ++else case e in #( ++ e) py_cv_module__testbuffer=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__testbuffer=disabled ++else case e in #( ++ e) py_cv_module__testbuffer=disabled ;; ++esac + fi + + fi +@@ -31663,11 +33255,13 @@ + if test "$ac_cv_func_dlopen" = yes + then : + py_cv_module__testimportmultiple=yes +-else $as_nop +- py_cv_module__testimportmultiple=missing ++else case e in #( ++ e) py_cv_module__testimportmultiple=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__testimportmultiple=disabled ++else case e in #( ++ e) py_cv_module__testimportmultiple=disabled ;; ++esac + fi + + fi +@@ -31701,11 +33295,13 @@ + if test "$ac_cv_func_dlopen" = yes + then : + py_cv_module__testmultiphase=yes +-else $as_nop +- py_cv_module__testmultiphase=missing ++else case e in #( ++ e) py_cv_module__testmultiphase=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__testmultiphase=disabled ++else case e in #( ++ e) py_cv_module__testmultiphase=disabled ;; ++esac + fi + + fi +@@ -31739,11 +33335,13 @@ + if test "$ac_cv_func_dlopen" = yes + then : + py_cv_module__testsinglephase=yes +-else $as_nop +- py_cv_module__testsinglephase=missing ++else case e in #( ++ e) py_cv_module__testsinglephase=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__testsinglephase=disabled ++else case e in #( ++ e) py_cv_module__testsinglephase=disabled ;; ++esac + fi + + fi +@@ -31777,11 +33375,13 @@ + if true + then : + py_cv_module__testexternalinspection=yes +-else $as_nop +- py_cv_module__testexternalinspection=missing ++else case e in #( ++ e) py_cv_module__testexternalinspection=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__testexternalinspection=disabled ++else case e in #( ++ e) py_cv_module__testexternalinspection=disabled ;; ++esac + fi + + fi +@@ -31815,11 +33415,13 @@ + if true + then : + py_cv_module_xxsubtype=yes +-else $as_nop +- py_cv_module_xxsubtype=missing ++else case e in #( ++ e) py_cv_module_xxsubtype=missing ;; ++esac + fi +-else $as_nop +- py_cv_module_xxsubtype=disabled ++else case e in #( ++ e) py_cv_module_xxsubtype=disabled ;; ++esac + fi + + fi +@@ -31853,11 +33455,13 @@ + if true + then : + py_cv_module__xxtestfuzz=yes +-else $as_nop +- py_cv_module__xxtestfuzz=missing ++else case e in #( ++ e) py_cv_module__xxtestfuzz=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__xxtestfuzz=disabled ++else case e in #( ++ e) py_cv_module__xxtestfuzz=disabled ;; ++esac + fi + + fi +@@ -31891,11 +33495,13 @@ + if test "$have_libffi" = yes -a "$ac_cv_func_dlopen" = yes + then : + py_cv_module__ctypes_test=yes +-else $as_nop +- py_cv_module__ctypes_test=missing ++else case e in #( ++ e) py_cv_module__ctypes_test=missing ;; ++esac + fi +-else $as_nop +- py_cv_module__ctypes_test=disabled ++else case e in #( ++ e) py_cv_module__ctypes_test=disabled ;; ++esac + fi + + fi +@@ -31930,11 +33536,13 @@ + if test "$ac_cv_func_dlopen" = yes + then : + py_cv_module_xxlimited=yes +-else $as_nop +- py_cv_module_xxlimited=missing ++else case e in #( ++ e) py_cv_module_xxlimited=missing ;; ++esac + fi +-else $as_nop +- py_cv_module_xxlimited=disabled ++else case e in #( ++ e) py_cv_module_xxlimited=disabled ;; ++esac + fi + + fi +@@ -31968,11 +33576,13 @@ + if test "$ac_cv_func_dlopen" = yes + then : + py_cv_module_xxlimited_35=yes +-else $as_nop +- py_cv_module_xxlimited_35=missing ++else case e in #( ++ e) py_cv_module_xxlimited_35=missing ;; ++esac + fi +-else $as_nop +- py_cv_module_xxlimited_35=disabled ++else case e in #( ++ e) py_cv_module_xxlimited_35=disabled ;; ++esac + fi + + fi +@@ -32017,8 +33627,8 @@ + # config.status only pays attention to the cache file if you give it + # the --recheck option to rerun configure. + # +-# `ac_cv_env_foo' variables (set or unset) will be overridden when +-# loading this file, other *unset* `ac_cv_foo' will be assigned the ++# 'ac_cv_env_foo' variables (set or unset) will be overridden when ++# loading this file, other *unset* 'ac_cv_foo' will be assigned the + # following values. + + _ACEOF +@@ -32048,14 +33658,14 @@ + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) +- # `set' does not quote correctly, so add quotes: double-quote ++ # 'set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) +- # `set' quotes correctly as required by POSIX, so do not add quotes. ++ # 'set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | +@@ -32474,7 +34084,6 @@ + + # Be more Bourne compatible + DUALCASE=1; export DUALCASE # for MKS sh +-as_nop=: + if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 + then : + emulate sh +@@ -32483,12 +34092,13 @@ + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +-else $as_nop +- case `(set -o) 2>/dev/null` in #( ++else case e in #( ++ e) case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; ++esac ;; + esac + fi + +@@ -32560,7 +34170,7 @@ + + ;; + esac +-# We did not find ourselves, most probably we were run as `sh COMMAND' ++# We did not find ourselves, most probably we were run as 'sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 +@@ -32589,7 +34199,6 @@ + } # as_fn_error + + +- + # as_fn_set_status STATUS + # ----------------------- + # Set $? to STATUS, without forking. +@@ -32629,11 +34238,12 @@ + { + eval $1+=\$2 + }' +-else $as_nop +- as_fn_append () ++else case e in #( ++ e) as_fn_append () + { + eval $1=\$$1\$2 +- } ++ } ;; ++esac + fi # as_fn_append + + # as_fn_arith ARG... +@@ -32647,11 +34257,12 @@ + { + as_val=$(( $* )) + }' +-else $as_nop +- as_fn_arith () ++else case e in #( ++ e) as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` +- } ++ } ;; ++esac + fi # as_fn_arith + + +@@ -32734,9 +34345,9 @@ + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: +- # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. +- # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. +- # In both cases, we have to default to `cp -pR'. ++ # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. ++ # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. ++ # In both cases, we have to default to 'cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then +@@ -32817,10 +34428,12 @@ + as_executable_p=as_fn_executable_p + + # Sed expression to map a string onto a valid CPP name. +-as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" ++as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" ++as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated + + # Sed expression to map a string onto a valid variable name. +-as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" ++as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" ++as_tr_sh="eval sed '$as_sed_sh'" # deprecated + + + exec 6>&1 +@@ -32836,7 +34449,7 @@ + # values after options handling. + ac_log=" + This file was extended by python $as_me 3.14, which was +-generated by GNU Autoconf 2.71. Invocation command line was ++generated by GNU Autoconf 2.72. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS +@@ -32867,7 +34480,7 @@ + + cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + ac_cs_usage="\ +-\`$as_me' instantiates files and other configuration actions ++'$as_me' instantiates files and other configuration actions + from templates according to the current configuration. Unless the files + and actions are specified as TAGs, all are instantiated by default. + +@@ -32900,10 +34513,10 @@ + ac_cs_config='$ac_cs_config_escaped' + ac_cs_version="\\ + python config.status 3.14 +-configured by $0, generated by GNU Autoconf 2.71, ++configured by $0, generated by GNU Autoconf 2.72, + with options \\"\$ac_cs_config\\" + +-Copyright (C) 2021 Free Software Foundation, Inc. ++Copyright (C) 2023 Free Software Foundation, Inc. + This config.status script is free software; the Free Software Foundation + gives unlimited permission to copy, distribute and modify it." + +@@ -32964,8 +34577,8 @@ + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header +- as_fn_error $? "ambiguous option: \`$1' +-Try \`$0 --help' for more information.";; ++ as_fn_error $? "ambiguous option: '$1' ++Try '$0 --help' for more information.";; + --help | --hel | -h ) + printf "%s\n" "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ +@@ -32973,8 +34586,8 @@ + ac_cs_silent=: ;; + + # This is an error. +- -*) as_fn_error $? "unrecognized option: \`$1' +-Try \`$0 --help' for more information." ;; ++ -*) as_fn_error $? "unrecognized option: '$1' ++Try '$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; +@@ -33028,6 +34641,8 @@ + "Mac/Resources/framework/Info.plist") CONFIG_FILES="$CONFIG_FILES Mac/Resources/framework/Info.plist" ;; + "Mac/Resources/app/Info.plist") CONFIG_FILES="$CONFIG_FILES Mac/Resources/app/Info.plist" ;; + "iOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES iOS/Resources/Info.plist" ;; ++ "tvOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES tvOS/Resources/Info.plist" ;; ++ "watchOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES watchOS/Resources/Info.plist" ;; + "Makefile.pre") CONFIG_FILES="$CONFIG_FILES Makefile.pre" ;; + "Misc/python.pc") CONFIG_FILES="$CONFIG_FILES Misc/python.pc" ;; + "Misc/python-embed.pc") CONFIG_FILES="$CONFIG_FILES Misc/python-embed.pc" ;; +@@ -33036,7 +34651,7 @@ + "Modules/Setup.stdlib") CONFIG_FILES="$CONFIG_FILES Modules/Setup.stdlib" ;; + "Modules/ld_so_aix") CONFIG_FILES="$CONFIG_FILES Modules/ld_so_aix" ;; + +- *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; ++ *) as_fn_error $? "invalid argument: '$ac_config_target'" "$LINENO" 5;; + esac + done + +@@ -33055,7 +34670,7 @@ + # creating and moving files from /tmp can sometimes cause problems. + # Hook for its removal unless debugging. + # Note that there is a small window in which the directory will not be cleaned: +-# after its creation but before its name has been assigned to `$tmp'. ++# after its creation but before its name has been assigned to '$tmp'. + $debug || + { + tmp= ac_tmp= +@@ -33079,7 +34694,7 @@ + + # Set up the scripts for CONFIG_FILES section. + # No need to generate them if there are no CONFIG_FILES. +-# This happens for instance with `./config.status config.h'. ++# This happens for instance with './config.status config.h'. + if test -n "$CONFIG_FILES"; then + + +@@ -33237,13 +34852,13 @@ + + # Set up the scripts for CONFIG_HEADERS section. + # No need to generate them if there are no CONFIG_HEADERS. +-# This happens for instance with `./config.status Makefile'. ++# This happens for instance with './config.status Makefile'. + if test -n "$CONFIG_HEADERS"; then + cat >"$ac_tmp/defines.awk" <<\_ACAWK || + BEGIN { + _ACEOF + +-# Transform confdefs.h into an awk script `defines.awk', embedded as ++# Transform confdefs.h into an awk script 'defines.awk', embedded as + # here-document in config.status, that substitutes the proper values into + # config.h.in to produce config.h. + +@@ -33353,7 +34968,7 @@ + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; +- :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; ++ :L* | :C*:*) as_fn_error $? "invalid tag '$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac +@@ -33375,19 +34990,19 @@ + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, +- # because $ac_f cannot contain `:'. ++ # because $ac_f cannot contain ':'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || +- as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; ++ as_fn_error 1 "cannot find input file: '$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + +- # Let's still pretend it is `configure' which instantiates (i.e., don't ++ # Let's still pretend it is 'configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` +@@ -33520,7 +35135,7 @@ + esac + _ACEOF + +-# Neutralize VPATH when `$srcdir' = `.'. ++# Neutralize VPATH when '$srcdir' = '.'. + # Shell code in configure.ac might set extrasub. + # FIXME: do we really want to maintain this feature? + cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +@@ -33551,9 +35166,9 @@ + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && +- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable 'datarootdir' + which seems to be undefined. Please make sure it is defined" >&5 +-printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' ++printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable 'datarootdir' + which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" +diff --git a/configure.ac b/configure.ac +index bd0221481c5..660e1c638ec 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -2,7 +2,7 @@ + dnl * Please run autoreconf -ivf -Werror to test your changes! * + dnl ************************************************************ + dnl +-dnl Python's configure script requires autoconf 2.71, autoconf-archive, ++dnl Python's configure script requires autoconf 2.72, autoconf-archive, + dnl aclocal 1.16, and pkg-config. + dnl + dnl It is recommended to use the Tools/build/regen-configure.sh shell script +@@ -12,7 +12,7 @@ + # Set VERSION so we only need to edit in one place (i.e., here) + m4_define([PYTHON_VERSION], [3.14]) + +-AC_PREREQ([2.71]) ++AC_PREREQ([2.72]) + + AC_INIT([python],[PYTHON_VERSION],[https://github.com/python/cpython/issues/]) + +@@ -330,6 +330,15 @@ + *-apple-ios*) + ac_sys_system=iOS + ;; ++ *-apple-tvos*) ++ ac_sys_system=tvOS ++ ;; ++ *-apple-watchos*) ++ ac_sys_system=watchOS ++ ;; ++ *-*-darwin*) ++ ac_sys_system=Darwin ++ ;; + *-*-vxworks*) + ac_sys_system=VxWorks + ;; +@@ -362,6 +371,7 @@ + + case $MACHDEP in + aix*) MACHDEP="aix";; ++ freebsd*) MACHDEP="freebsd";; + linux-android*) MACHDEP="android";; + linux*) MACHDEP="linux";; + cygwin*) MACHDEP="cygwin";; +@@ -401,7 +411,7 @@ + # On cross-compile builds, configure will look for a host-specific compiler by + # prepending the user-provided host triple to the required binary name. + # +-# On iOS, this results in binaries like "arm64-apple-ios13.0-simulator-gcc", ++# On iOS/tvOS/watchOS, this results in binaries like "arm64-apple-ios13.0-simulator-gcc", + # which isn't a binary that exists, and isn't very convenient, as it contains the + # iOS version. As the default cross-compiler name won't exist, configure falls + # back to gcc, which *definitely* won't work. We're providing wrapper scripts for +@@ -416,6 +426,14 @@ + aarch64-apple-ios*-simulator) AR=arm64-apple-ios-simulator-ar ;; + aarch64-apple-ios*) AR=arm64-apple-ios-ar ;; + x86_64-apple-ios*-simulator) AR=x86_64-apple-ios-simulator-ar ;; ++ ++ aarch64-apple-tvos*-simulator) AR=arm64-apple-tvos-simulator-ar ;; ++ aarch64-apple-tvos*) AR=arm64-apple-tvos-ar ;; ++ x86_64-apple-tvos*-simulator) AR=x86_64-apple-tvos-simulator-ar ;; ++ ++ aarch64-apple-watchos*-simulator) AR=arm64-apple-watchos-simulator-ar ;; ++ aarch64-apple-watchos*) AR=arm64_32-apple-watchos-ar ;; ++ x86_64-apple-watchos*-simulator) AR=x86_64-apple-watchos-simulator-ar ;; + *) + esac + fi +@@ -424,6 +442,14 @@ + aarch64-apple-ios*-simulator) CC=arm64-apple-ios-simulator-clang ;; + aarch64-apple-ios*) CC=arm64-apple-ios-clang ;; + x86_64-apple-ios*-simulator) CC=x86_64-apple-ios-simulator-clang ;; ++ ++ aarch64-apple-tvos*-simulator) CC=arm64-apple-tvos-simulator-clang ;; ++ aarch64-apple-tvos*) CC=arm64-apple-tvos-clang ;; ++ x86_64-apple-tvos*-simulator) CC=x86_64-apple-tvos-simulator-clang ;; ++ ++ aarch64-apple-watchos*-simulator) CC=arm64-apple-watchos-simulator-clang ;; ++ aarch64-apple-watchos*) CC=arm64_32-apple-watchos-clang ;; ++ x86_64-apple-watchos*-simulator) CC=x86_64-apple-watchos-simulator-clang ;; + *) + esac + fi +@@ -432,6 +458,14 @@ + aarch64-apple-ios*-simulator) CPP=arm64-apple-ios-simulator-cpp ;; + aarch64-apple-ios*) CPP=arm64-apple-ios-cpp ;; + x86_64-apple-ios*-simulator) CPP=x86_64-apple-ios-simulator-cpp ;; ++ ++ aarch64-apple-tvos*-simulator) CPP=arm64-apple-tvos-simulator-cpp ;; ++ aarch64-apple-tvos*) CPP=arm64-apple-tvos-cpp ;; ++ x86_64-apple-tvos*-simulator) CPP=x86_64-apple-tvos-simulator-cpp ;; ++ ++ aarch64-apple-watchos*-simulator) CPP=arm64-apple-watchos-simulator-cpp ;; ++ aarch64-apple-watchos*) CPP=arm64_32-apple-watchos-cpp ;; ++ x86_64-apple-watchos*-simulator) CPP=x86_64-apple-watchos-simulator-cpp ;; + *) + esac + fi +@@ -440,6 +474,14 @@ + aarch64-apple-ios*-simulator) CXX=arm64-apple-ios-simulator-clang++ ;; + aarch64-apple-ios*) CXX=arm64-apple-ios-clang++ ;; + x86_64-apple-ios*-simulator) CXX=x86_64-apple-ios-simulator-clang++ ;; ++ ++ aarch64-apple-tvos*-simulator) CXX=arm64-apple-tvos-simulator-clang++ ;; ++ aarch64-apple-tvos*) CXX=arm64-apple-tvos-clang++ ;; ++ x86_64-apple-tvos*-simulator) CXX=x86_64-apple-tvos-simulator-clang++ ;; ++ ++ aarch64-apple-watchos*-simulator) CXX=arm64-apple-watchos-simulator-clang++ ;; ++ aarch64-apple-watchos*) CXX=arm64_32-apple-watchos-clang++ ;; ++ x86_64-apple-watchos*-simulator) CXX=x86_64-apple-watchos-simulator-clang++ ;; + *) + esac + fi +@@ -554,8 +596,10 @@ + case $enableval in + yes) + case $ac_sys_system in +- Darwin) enableval=/Library/Frameworks ;; +- iOS) enableval=iOS/Frameworks/\$\(MULTIARCH\) ;; ++ Darwin) enableval=/Library/Frameworks ;; ++ iOS) enableval=iOS/Frameworks/\$\(MULTIARCH\) ;; ++ tvOS) enableval=tvOS/Frameworks/\$\(MULTIARCH\) ;; ++ watchOS) enableval=watchOS/Frameworks/\$\(MULTIARCH\) ;; + *) AC_MSG_ERROR([Unknown platform for framework build]) + esac + esac +@@ -564,6 +608,8 @@ + no) + case $ac_sys_system in + iOS) AC_MSG_ERROR([iOS builds must use --enable-framework]) ;; ++ tvOS) AC_MSG_ERROR([tvOS builds must use --enable-framework]) ;; ++ watchOS) AC_MSG_ERROR([watchOS builds must use --enable-framework]) ;; + *) + PYTHONFRAMEWORK= + PYTHONFRAMEWORKDIR=no-framework +@@ -666,6 +712,34 @@ + + AC_CONFIG_FILES([iOS/Resources/Info.plist]) + ;; ++ tvOS) : ++ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure" ++ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure " ++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKPYTHONW= ++ INSTALLTARGETS="libinstall inclinstall sharedinstall" ++ ++ prefix=$PYTHONFRAMEWORKPREFIX ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" ++ RESSRCDIR=tvOS/Resources ++ ++ AC_CONFIG_FILES([tvOS/Resources/Info.plist]) ++ ;; ++ watchOS) : ++ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure" ++ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure " ++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKPYTHONW= ++ INSTALLTARGETS="libinstall inclinstall sharedinstall" ++ ++ prefix=$PYTHONFRAMEWORKPREFIX ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" ++ RESSRCDIR=watchOS/Resources ++ ++ AC_CONFIG_FILES([watchOS/Resources/Info.plist]) ++ ;; + *) + AC_MSG_ERROR([Unknown platform for framework build]) + ;; +@@ -674,6 +748,8 @@ + ],[ + case $ac_sys_system in + iOS) AC_MSG_ERROR([iOS builds must use --enable-framework]) ;; ++ tvOS) AC_MSG_ERROR([tvOS builds must use --enable-framework]) ;; ++ watchOS) AC_MSG_ERROR([watchOS builds must use --enable-framework]) ;; + *) + PYTHONFRAMEWORK= + PYTHONFRAMEWORKDIR=no-framework +@@ -726,8 +802,8 @@ + case "$withval" in + yes) + case $ac_sys_system in +- Darwin|iOS) +- # iOS is able to share the macOS patch ++ Darwin|iOS|tvOS|watchOS) ++ # iOS/tvOS/watchOS is able to share the macOS patch + APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" + ;; + *) AC_MSG_ERROR([no default app store compliance patch available for $ac_sys_system]) ;; +@@ -741,8 +817,8 @@ + esac + ],[ + case $ac_sys_system in +- iOS) +- # Always apply the compliance patch on iOS; we can use the macOS patch ++ iOS|tvOS|watchOS) ++ # Always apply the compliance patch on iOS/tvOS/watchOS; we can use the macOS patch + APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" + AC_MSG_RESULT([applying default app store compliance patch]) + ;; +@@ -790,9 +866,61 @@ + ;; + esac + ;; ++ *-apple-tvos*) ++ _host_os=`echo $host | cut -d '-' -f3` ++ _host_device=`echo $host | cut -d '-' -f4` ++ _host_device=${_host_device:=os} ++ ++ # TVOS_DEPLOYMENT_TARGET is the minimum supported tvOS version ++ AC_MSG_CHECKING([tvOS deployment target]) ++ TVOS_DEPLOYMENT_TARGET=${_host_os:4} ++ TVOS_DEPLOYMENT_TARGET=${TVOS_DEPLOYMENT_TARGET:=12.0} ++ AC_MSG_RESULT([$TVOS_DEPLOYMENT_TARGET]) ++ ++ case "$host_cpu" in ++ aarch64) ++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-arm64-appletv${_host_device} ++ ;; ++ *) ++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-$host_cpu-appletv${_host_device} ++ ;; ++ esac ++ ;; ++ *-apple-watchos*) ++ _host_os=`echo $host | cut -d '-' -f3` ++ _host_device=`echo $host | cut -d '-' -f4` ++ _host_device=${_host_device:=os} ++ ++ # WATCHOS_DEPLOYMENT_TARGET is the minimum supported watchOS version ++ AC_MSG_CHECKING([watchOS deployment target]) ++ WATCHOS_DEPLOYMENT_TARGET=${_host_os:7} ++ WATCHOS_DEPLOYMENT_TARGET=${WATCHOS_DEPLOYMENT_TARGET:=4.0} ++ AC_MSG_RESULT([$WATCHOS_DEPLOYMENT_TARGET]) ++ ++ case "$host_cpu" in ++ aarch64) ++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-arm64-watch${_host_device} ++ ;; ++ *) ++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-$host_cpu-watch${_host_device} ++ ;; ++ esac ++ ;; ++ *-*-darwin*) ++ case "$host_cpu" in ++ arm*) ++ _host_ident=arm ++ ;; ++ *) ++ _host_ident=$host_cpu ++ esac ++ ;; + *-*-vxworks*) + _host_ident=$host_cpu + ;; ++ *-*-emscripten) ++ _host_ident=$(emcc -dumpversion | cut -f1 -d-)-$host_cpu ++ ;; + wasm32-*-* | wasm64-*-*) + _host_ident=$host_cpu + ;; +@@ -867,9 +995,13 @@ + define_xopen_source=no;; + Darwin/@<:@[12]@:>@@<:@0-9@:>@.*) + define_xopen_source=no;; +- # On iOS, defining _POSIX_C_SOURCE also disables platform specific features. ++ # On iOS/tvOS/watchOS, defining _POSIX_C_SOURCE also disables platform specific features. + iOS/*) + define_xopen_source=no;; ++ tvOS/*) ++ define_xopen_source=no;; ++ watchOS/*) ++ define_xopen_source=no;; + # On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from + # defining NI_NUMERICHOST. + QNX/6.3.2) +@@ -928,8 +1060,11 @@ + CONFIGURE_MACOSX_DEPLOYMENT_TARGET= + EXPORT_MACOSX_DEPLOYMENT_TARGET='#' + +-# Record the value of IPHONEOS_DEPLOYMENT_TARGET enforced by the selected host triple. ++# Record the value of IPHONEOS_DEPLOYMENT_TARGET / TVOS_DEPLOYMENT_TARGET / ++# WATCHOS_DEPLOYMENT_TARGET enforced by the selected host triple. + AC_SUBST([IPHONEOS_DEPLOYMENT_TARGET]) ++AC_SUBST([TVOS_DEPLOYMENT_TARGET]) ++AC_SUBST([WATCHOS_DEPLOYMENT_TARGET]) + + # checks for alternative programs + +@@ -963,11 +1098,17 @@ + ], + ) + +-dnl Add the compiler flag for the iOS minimum supported OS version. ++dnl Add the compiler flag for the iOS/tvOS/watchOS minimum supported OS version. + AS_CASE([$ac_sys_system], + [iOS], [ + AS_VAR_APPEND([CFLAGS], [" -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}"]) + AS_VAR_APPEND([LDFLAGS], [" -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}"]) ++ ],[tvOS], [ ++ AS_VAR_APPEND([CFLAGS], [" -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}"]) ++ AS_VAR_APPEND([LDFLAGS], [" -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}"]) ++ ],[watchOS], [ ++ AS_VAR_APPEND([CFLAGS], [" -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}"]) ++ AS_VAR_APPEND([LDFLAGS], [" -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}"]) + ], + ) + +@@ -1156,6 +1297,8 @@ + AS_CASE([$ac_sys_system], + [Darwin*], [MULTIARCH=""], + [iOS], [MULTIARCH=""], ++ [tvOS], [MULTIARCH=""], ++ [watchOS], [MULTIARCH=""], + [FreeBSD*], [MULTIARCH=""], + [MULTIARCH=$($CC --print-multiarch 2>/dev/null)] + ) +@@ -1177,7 +1320,7 @@ + dnl use a single "fat" binary at runtime. SOABI_PLATFORM is the component of + dnl the PLATFORM_TRIPLET that will be used in binary module extensions. + AS_CASE([$ac_sys_system], +- [iOS], [SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f2`], ++ [iOS|tvOS|watchOS], [SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f2`], + [SOABI_PLATFORM=$PLATFORM_TRIPLET] + ) + +@@ -1211,6 +1354,10 @@ + [x86_64-*-freebsd*/clang], [PY_SUPPORT_TIER=3], dnl FreeBSD on AMD64 + [aarch64-apple-ios*-simulator/clang], [PY_SUPPORT_TIER=3], dnl iOS Simulator on arm64 + [aarch64-apple-ios*/clang], [PY_SUPPORT_TIER=3], dnl iOS on ARM64 ++ [aarch64-apple-tvos*-simulator/clang], [PY_SUPPORT_TIER=3], dnl tvOS Simulator on arm64 ++ [aarch64-apple-tvos*/clang], [PY_SUPPORT_TIER=3], dnl tvOS on ARM64 ++ [aarch64-apple-watchos*-simulator/clang], [PY_SUPPORT_TIER=3], dnl watchOS Simulator on arm64 ++ [arm64_32-apple-watchos*/clang], [PY_SUPPORT_TIER=3], dnl watchOS on ARM64 + [aarch64-*-linux-android/clang], [PY_SUPPORT_TIER=3], dnl Android on ARM64 + [x86_64-*-linux-android/clang], [PY_SUPPORT_TIER=3], dnl Android on AMD64 + +@@ -1520,7 +1667,7 @@ + case $ac_sys_system in + Darwin) + LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)';; +- iOS) ++ iOS|tvOS|watchOS) + LDLIBRARY='$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';; + *) + AC_MSG_ERROR([Unknown platform for framework build]);; +@@ -1585,7 +1732,7 @@ + BLDLIBRARY='-L. -lpython$(LDVERSION)' + RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}} + ;; +- iOS) ++ iOS|tvOS|watchOS) + LDLIBRARY='libpython$(LDVERSION).dylib' + ;; + AIX*) +@@ -2157,6 +2304,27 @@ + BOLT_BINARIES="${BOLT_BINARIES} \$(INSTSONAME)" + ]) + ++AC_ARG_VAR( ++ [BOLT_COMMON_FLAGS], ++ [Common arguments to llvm-bolt when instrumenting and applying] ++) ++ ++AC_MSG_CHECKING([BOLT_COMMON_FLAGS]) ++if test -z "${BOLT_COMMON_FLAGS}" ++then ++ AS_VAR_SET( ++ [BOLT_COMMON_FLAGS], ++ [m4_normalize(" ++ [-update-debug-sections] ++ ++ dnl At least LLVM 19.x doesn't support computed gotos in PIC compiled code. ++ dnl Exclude functions containing computed gotos. ++ dnl TODO this may be fixed in LLVM 20.x via https://github.com/llvm/llvm-project/pull/120267. ++ [-skip-funcs=_PyEval_EvalFrameDefault,sre_ucs1_match/1,sre_ucs2_match/1,sre_ucs4_match/1] ++ ")] ++ ) ++fi ++ + AC_ARG_VAR( + [BOLT_INSTRUMENT_FLAGS], + [Arguments to llvm-bolt when instrumenting binaries] +@@ -2164,7 +2332,7 @@ + AC_MSG_CHECKING([BOLT_INSTRUMENT_FLAGS]) + if test -z "${BOLT_INSTRUMENT_FLAGS}" + then +- BOLT_INSTRUMENT_FLAGS= ++ BOLT_INSTRUMENT_FLAGS="${BOLT_COMMON_FLAGS}" + fi + AC_MSG_RESULT([$BOLT_INSTRUMENT_FLAGS]) + +@@ -2178,9 +2346,9 @@ + AS_VAR_SET( + [BOLT_APPLY_FLAGS], + [m4_normalize(" +- -update-debug-sections ++ ${BOLT_COMMON_FLAGS} + -reorder-blocks=ext-tsp +- -reorder-functions=hfsort+ ++ -reorder-functions=cdsort + -split-functions + -icf=1 + -inline-all +@@ -2333,7 +2501,7 @@ + dnl Include file system support + AS_VAR_APPEND([LINKFORSHARED], [" -sFORCE_FILESYSTEM -lidbfs.js -lnodefs.js -lproxyfs.js -lworkerfs.js"]) + AS_VAR_APPEND([LINKFORSHARED], [" -sEXPORTED_RUNTIME_METHODS=FS,callMain,ENV"]) +- AS_VAR_APPEND([LINKFORSHARED], [" -sEXPORTED_FUNCTIONS=_main,_Py_Version"]) ++ AS_VAR_APPEND([LINKFORSHARED], [" -sEXPORTED_FUNCTIONS=_main,_Py_Version,__PyRuntime,__PyEM_EMSCRIPTEN_COUNT_ARGS_OFFSET"]) + AS_VAR_APPEND([LINKFORSHARED], [" -sSTACK_SIZE=5MB"]) + + AS_VAR_IF([enable_wasm_dynamic_linking], [yes], [ +@@ -2600,6 +2768,13 @@ + esac + AC_MSG_RESULT([$CC]) + ++ # Error on unguarded use of new symbols, which will fail at runtime for ++ # users on older versions of macOS ++ AX_CHECK_COMPILE_FLAG([-Wunguarded-availability], ++ [AS_VAR_APPEND([CFLAGS_NODIST], [" -Werror=unguarded-availability"])], ++ [], ++ [-Werror]) ++ + LIPO_INTEL64_FLAGS="" + if test "${enable_universalsdk}" + then +@@ -2928,7 +3103,7 @@ + AC_CHECK_HEADERS([ \ + alloca.h asm/types.h bluetooth.h conio.h direct.h dlfcn.h endian.h errno.h fcntl.h grp.h \ + io.h langinfo.h libintl.h libutil.h linux/auxvec.h sys/auxv.h linux/fs.h linux/limits.h linux/memfd.h \ +- linux/netfilter_ipv4.h linux/random.h linux/soundcard.h \ ++ linux/netfilter_ipv4.h linux/random.h linux/soundcard.h linux/sched.h \ + linux/tipc.h linux/wait.h netdb.h net/ethernet.h netinet/in.h netpacket/packet.h poll.h process.h pthread.h pty.h \ + sched.h setjmp.h shadow.h signal.h spawn.h stropts.h sys/audioio.h sys/bsdtty.h sys/devpoll.h \ + sys/endian.h sys/epoll.h sys/event.h sys/eventfd.h sys/file.h sys/ioctl.h sys/kern_control.h \ +@@ -3412,7 +3587,7 @@ + BLDSHARED="$LDSHARED" + fi + ;; +- iOS/*) ++ iOS/*|tvOS/*|watchOS/*) + LDSHARED='$(CC) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)' + LDCXXSHARED='$(CXX) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)' + BLDSHARED="$LDSHARED" +@@ -3536,7 +3711,7 @@ + Linux-android*) LINKFORSHARED="-pie -Xlinker -export-dynamic";; + Linux*|GNU*) LINKFORSHARED="-Xlinker -export-dynamic";; + # -u libsys_s pulls in all symbols in libsys +- Darwin/*|iOS/*) ++ Darwin/*|iOS/*|tvOS/*|watchOS/*) + LINKFORSHARED="$extra_undefs -framework CoreFoundation" + + # Issue #18075: the default maximum stack size (8MBytes) is too +@@ -3560,7 +3735,7 @@ + LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' + fi + LINKFORSHARED="$LINKFORSHARED" +- elif test $ac_sys_system = "iOS"; then ++ elif test "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "watchOS"; then + LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)' + fi + ;; +@@ -3980,7 +4155,7 @@ + dnl when do we need USING_APPLE_OS_LIBFFI? + ctypes_malloc_closure=yes + ], +- [iOS], [ ++ [iOS|tvOS|watchOS], [ + ctypes_malloc_closure=yes + ], + [sunos5], [AS_VAR_APPEND([LIBFFI_LIBS], [" -mimpure-text"])] +@@ -3995,8 +4170,8 @@ + AS_VAR_IF([ac_cv_lib_dl_dlopen], [yes], [AS_VAR_APPEND([LIBFFI_LIBS], [" -ldl"])]) + + WITH_SAVE_ENV([ +- CFLAGS="$LIBFFI_CFLAGS $CFLAGS" +- LDFLAGS="$LIBFFI_LIBS $LDFLAGS" ++ CFLAGS="$CFLAGS $LIBFFI_CFLAGS" ++ LIBS="$LIBS $LIBFFI_LIBS" + + PY_CHECK_FUNC([ffi_prep_cif_var], [@%:@include ]) + PY_CHECK_FUNC([ffi_prep_closure_loc], [@%:@include ]) +@@ -4011,9 +4186,8 @@ + # + AC_CACHE_CHECK([libffi has complex type support], [ac_cv_ffi_complex_double_supported], + [WITH_SAVE_ENV([ +- CPPFLAGS="$LIBFFI_CFLAGS $CPPFLAGS" +- LDFLAGS="$LIBFFI_LIBS $LDFLAGS" +- LIBS="$LIBFFI_LIBS $LIBS" ++ CPPFLAGS="$CPPFLAGS $LIBFFI_CFLAGS" ++ LIBS="$LIBS $LIBFFI_LIBS" + AC_RUN_IFELSE([AC_LANG_SOURCE([[ + #include + #include +@@ -4076,8 +4250,8 @@ + + AS_VAR_IF([with_system_libmpdec], [yes], + [WITH_SAVE_ENV([ +- CPPFLAGS="$LIBMPDEC_CFLAGS $CPPFLAGS" +- LIBS="$LIBMPDEC_LIBS $LIBS" ++ CPPFLAGS="$CPPFLAGS $LIBMPDEC_CFLAGS" ++ LIBS="$LIBS $LIBMPDEC_LIBS" + + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([ +@@ -4210,7 +4384,7 @@ + dnl bpo-45774/GH-29507: The CPP check in AC_CHECK_HEADER can fail on FreeBSD, + dnl hence CPPFLAGS instead of CFLAGS. + CPPFLAGS="$CPPFLAGS $LIBSQLITE3_CFLAGS" +- LDFLAGS="$LIBSQLITE3_LIBS $LDFLAGS" ++ LIBS="$LIBS $LIBSQLITE3_LIBS" + + AC_CHECK_HEADER([sqlite3.h], [ + have_sqlite3=yes +@@ -4313,7 +4487,7 @@ + + WITH_SAVE_ENV([ + CPPFLAGS="$CPPFLAGS $TCLTK_CFLAGS" +- LIBS="$TCLTK_LIBS $LDFLAGS" ++ LIBS="$LIBS $TCLTK_LIBS" + + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([ +@@ -4355,7 +4529,7 @@ + AC_ARG_VAR([GDBM_LIBS], [additional linker flags for gdbm]) + WITH_SAVE_ENV([ + CPPFLAGS="$CPPFLAGS $GDBM_CFLAGS" +- LDFLAGS="$GDBM_LIBS $LDFLAGS" ++ LIBS="$LIBS $GDBM_LIBS" + AC_CHECK_HEADERS([gdbm.h], [ + AC_CHECK_LIB([gdbm], [gdbm_open], [ + have_gdbm=yes +@@ -4387,29 +4561,21 @@ + AC_MSG_RESULT([$have_ndbm ($dbm_ndbm)]) + + dnl "gdbm-ndbm.h" and "gdbm/ndbm.h" are both normalized to "gdbm_ndbm_h" +-dnl unset ac_cv_header_gdbm_ndbm_h to prevent false positive cache hits. +-AS_UNSET([ac_cv_header_gdbm_ndbm_h]) +-AC_CACHE_VAL([ac_cv_header_gdbm_slash_ndbm_h], [ +- AC_CHECK_HEADER( +- [gdbm/ndbm.h], +- [ac_cv_header_gdbm_slash_ndbm_h=yes], [ac_cv_header_gdbm_slash_ndbm_h=no] +- ) +-]) ++AC_CACHE_CHECK([for gdbm/ndbm.h], [ac_cv_header_gdbm_slash_ndbm_h], ++ [AC_PREPROC_IFELSE([AC_LANG_SOURCE([@%:@include ])], ++ [ac_cv_header_gdbm_slash_ndbm_h=yes], ++ [ac_cv_header_gdbm_slash_ndbm_h=no])]) + AS_VAR_IF([ac_cv_header_gdbm_slash_ndbm_h], [yes], [ + AC_DEFINE([HAVE_GDBM_NDBM_H], [1], [Define to 1 if you have the header file.]) + ]) + +-AS_UNSET([ac_cv_header_gdbm_ndbm_h]) +-AC_CACHE_VAL([ac_cv_header_gdbm_dash_ndbm_h], [ +- AC_CHECK_HEADER( +- [gdbm-ndbm.h], +- [ac_cv_header_gdbm_dash_ndbm_h=yes], [ac_cv_header_gdbm_dash_ndbm_h=no] +- ) +-]) ++AC_CACHE_CHECK([for gdbm-ndbm.h], [ac_cv_header_gdbm_dash_ndbm_h], ++ [AC_PREPROC_IFELSE([AC_LANG_SOURCE([@%:@include ])], ++ [ac_cv_header_gdbm_dash_ndbm_h=yes], ++ [ac_cv_header_gdbm_dash_ndbm_h=no])]) + AS_VAR_IF([ac_cv_header_gdbm_dash_ndbm_h], [yes], [ + AC_DEFINE([HAVE_GDBM_DASH_NDBM_H], [1], [Define to 1 if you have the header file.]) + ]) +-AS_UNSET([ac_cv_header_gdbm_ndbm_h]) + + if test "$ac_cv_header_gdbm_slash_ndbm_h" = yes -o "$ac_cv_header_gdbm_dash_ndbm_h" = yes; then + AS_UNSET([ac_cv_search_dbm_open]) +@@ -5098,9 +5264,9 @@ + # checks for library functions + AC_CHECK_FUNCS([ \ + accept4 alarm bind_textdomain_codeset chmod chown clock closefrom close_range confstr \ +- copy_file_range ctermid dup dup3 execv explicit_bzero explicit_memset \ ++ copy_file_range ctermid dladdr dup dup3 explicit_bzero explicit_memset \ + faccessat fchmod fchmodat fchown fchownat fdopendir fdwalk fexecve \ +- fork fork1 fpathconf fstatat ftime ftruncate futimens futimes futimesat \ ++ fpathconf fstatat ftime ftruncate futimens futimes futimesat \ + gai_strerror getegid geteuid getgid getgrent getgrgid getgrgid_r \ + getgrnam_r getgrouplist gethostname getitimer getloadavg getlogin \ + getpeername getpgid getpid getppid getpriority _getpty \ +@@ -5108,8 +5274,7 @@ + getspnam getuid getwd grantpt if_nameindex initgroups kill killpg lchown linkat \ + lockf lstat lutimes madvise mbrtowc memrchr mkdirat mkfifo mkfifoat \ + mknod mknodat mktime mmap mremap nice openat opendir pathconf pause pipe \ +- pipe2 plock poll posix_fadvise posix_fallocate posix_openpt posix_spawn posix_spawnp \ +- posix_spawn_file_actions_addclosefrom_np \ ++ pipe2 plock poll posix_fadvise posix_fallocate posix_openpt \ + pread preadv preadv2 process_vm_readv \ + pthread_cond_timedwait_relative_np pthread_condattr_setclock pthread_init \ + pthread_kill pthread_getname_np pthread_setname_np \ +@@ -5118,11 +5283,11 @@ + sched_setparam sched_setscheduler sem_clockwait sem_getvalue sem_open \ + sem_timedwait sem_unlink sendfile setegid seteuid setgid sethostname \ + setitimer setlocale setpgid setpgrp setpriority setregid setresgid \ +- setresuid setreuid setsid setuid setvbuf shutdown sigaction sigaltstack \ ++ setresuid setreuid setsid setuid setvbuf shutdown sigaction \ + sigfillset siginterrupt sigpending sigrelse sigtimedwait sigwait \ + sigwaitinfo snprintf splice strftime strlcpy strsignal symlinkat sync \ + sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile \ +- tmpnam tmpnam_r truncate ttyname umask uname unlinkat unlockpt utimensat utimes vfork \ ++ tmpnam tmpnam_r truncate ttyname_r umask uname unlinkat unlockpt utimensat utimes vfork \ + wait wait3 wait4 waitid waitpid wcscoll wcsftime wcsxfrm wmemcmp writev \ + ]) + +@@ -5133,12 +5298,20 @@ + AC_CHECK_FUNCS([lchmod]) + fi + +-# iOS defines some system methods that can be linked (so they are ++# iOS/tvOS/watchOS define some system methods that can be linked (so they are + # found by configure), but either raise a compilation error (because the + # header definition prevents usage - autoconf doesn't use the headers), or + # raise an error if used at runtime. Force these symbols off. +-if test "$ac_sys_system" != "iOS" ; then +- AC_CHECK_FUNCS([getentropy getgroups system]) ++if test "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then ++ AC_CHECK_FUNCS([ getentropy getgroups system ]) ++fi ++ ++# tvOS/watchOS have some additional methods that can be found, but not used. ++if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then ++ AC_CHECK_FUNCS([ \ ++ execv fork fork1 posix_spawn posix_spawnp posix_spawn_file_actions_addclosefrom_np \ ++ sigaltstack \ ++ ]) + fi + + AC_CHECK_DECL([dirfd], +@@ -5300,7 +5473,7 @@ + ], [ + WITH_SAVE_ENV([ + CPPFLAGS="$CPPFLAGS $ZLIB_CFLAGS" +- LDFLAGS="$LDFLAGS $ZLIB_LIBS" ++ LIBS="$LIBS $ZLIB_LIBS" + AC_CHECK_HEADERS([zlib.h], [ + PY_CHECK_LIB([z], [gzread], [have_zlib=yes], [have_zlib=no]) + ], [have_zlib=no]) +@@ -5324,7 +5497,7 @@ + PKG_CHECK_MODULES([BZIP2], [bzip2], [have_bzip2=yes], [ + WITH_SAVE_ENV([ + CPPFLAGS="$CPPFLAGS $BZIP2_CFLAGS" +- LDFLAGS="$LDFLAGS $BZIP2_LIBS" ++ LIBS="$LIBS $BZIP2_LIBS" + AC_CHECK_HEADERS([bzlib.h], [ + AC_CHECK_LIB([bz2], [BZ2_bzCompress], [have_bzip2=yes], [have_bzip2=no]) + ], [have_bzip2=no]) +@@ -5338,7 +5511,7 @@ + PKG_CHECK_MODULES([LIBLZMA], [liblzma], [have_liblzma=yes], [ + WITH_SAVE_ENV([ + CPPFLAGS="$CPPFLAGS $LIBLZMA_CFLAGS" +- LDFLAGS="$LDFLAGS $LIBLZMA_LIBS" ++ LIBS="$LIBS $LIBLZMA_LIBS" + AC_CHECK_HEADERS([lzma.h], [ + AC_CHECK_LIB([lzma], [lzma_easy_encoder], [have_liblzma=yes], [have_liblzma=no]) + ], [have_liblzma=no]) +@@ -5392,20 +5565,22 @@ + ]) + + # check for openpty, login_tty, and forkpty +- +-AC_CHECK_FUNCS([openpty], [], +- [AC_CHECK_LIB([util], [openpty], +- [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lutil"], +- [AC_CHECK_LIB([bsd], [openpty], +- [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lbsd"])])]) +-AC_SEARCH_LIBS([login_tty], [util], +- [AC_DEFINE([HAVE_LOGIN_TTY], [1], [Define to 1 if you have the `login_tty' function.])] +-) +-AC_CHECK_FUNCS([forkpty], [], +- [AC_CHECK_LIB([util], [forkpty], +- [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lutil"], +- [AC_CHECK_LIB([bsd], [forkpty], +- [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lbsd"])])]) ++# tvOS/watchOS have functions for tty, but can't use them ++if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then ++ AC_CHECK_FUNCS([openpty], [], ++ [AC_CHECK_LIB([util], [openpty], ++ [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lutil"], ++ [AC_CHECK_LIB([bsd], [openpty], ++ [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lbsd"])])]) ++ AC_SEARCH_LIBS([login_tty], [util], ++ [AC_DEFINE([HAVE_LOGIN_TTY], [1], [Define to 1 if you have the `login_tty' function.])] ++ ) ++ AC_CHECK_FUNCS([forkpty], [], ++ [AC_CHECK_LIB([util], [forkpty], ++ [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lutil"], ++ [AC_CHECK_LIB([bsd], [forkpty], ++ [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lbsd"])])]) ++fi + + # check for long file support functions + AC_CHECK_FUNCS([fseek64 fseeko fstatvfs ftell64 ftello statvfs]) +@@ -5444,10 +5619,10 @@ + ]) + ]) + +-# On Android and iOS, clock_settime can be linked (so it is found by ++# On Android, iOS, tvOS and watchOS, clock_settime can be linked (so it is found by + # configure), but when used in an unprivileged process, it crashes rather than + # returning an error. Force the symbol off. +-if test "$ac_sys_system" != "Linux-android" && test "$ac_sys_system" != "iOS" ++if test "$ac_sys_system" != "Linux-android" -a "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" + then + AC_CHECK_FUNCS([clock_settime], [], [ + AC_CHECK_LIB([rt], [clock_settime], [ +@@ -6198,8 +6373,8 @@ + LIBPYTHON="\$(BLDLIBRARY)" + fi + +-# On iOS the shared libraries must be linked with the Python framework +-if test "$ac_sys_system" = "iOS"; then ++# On iOS/tvOS/watchOS the shared libraries must be linked with the Python framework ++if test "$ac_sys_system" = "iOS" -o $ac_sys_system = "tvOS" -o $ac_sys_system = "watchOS"; then + MODULE_DEPS_SHARED="$MODULE_DEPS_SHARED \$(PYTHONFRAMEWORKDIR)/\$(PYTHONFRAMEWORK)" + fi + +@@ -6332,7 +6507,7 @@ + ], [ + WITH_SAVE_ENV([ + CPPFLAGS="$CPPFLAGS $LIBREADLINE_CFLAGS" +- LDFLAGS="$LDFLAGS $LIBREADLINE_LIBS" ++ LIBS="$LIBS $LIBREADLINE_LIBS" + AC_CHECK_HEADERS([readline/readline.h], [ + AC_CHECK_LIB([readline], [readline], [ + LIBREADLINE=readline +@@ -6353,7 +6528,7 @@ + ], [ + WITH_SAVE_ENV([ + CPPFLAGS="$CPPFLAGS $LIBEDIT_CFLAGS" +- LDFLAGS="$LDFLAGS $LIBEDIT_LIBS" ++ LIBS="$LIBS $LIBEDIT_LIBS" + AC_CHECK_HEADERS([editline/readline.h], [ + AC_CHECK_LIB([edit], [readline], [ + LIBREADLINE=edit +@@ -6377,7 +6552,7 @@ + + WITH_SAVE_ENV([ + CPPFLAGS="$CPPFLAGS $READLINE_CFLAGS" +- LIBS="$READLINE_LIBS $LIBS" ++ LIBS="$LIBS $READLINE_LIBS" + LIBS_SAVE=$LIBS + + m4_define([readline_includes], [ +@@ -6662,7 +6837,7 @@ + [Define if year with century should be normalized for strftime.]) + fi + +-AC_CACHE_CHECK([whether C99-specific strftime specifiers are supported], [ac_cv_strftime_c99_support], [ ++AC_CACHE_CHECK([whether C99-compatible strftime specifiers are supported], [ac_cv_strftime_c99_support], [ + AC_RUN_IFELSE([AC_LANG_SOURCE([[ + #include + #include +@@ -6682,13 +6857,8 @@ + } + ]])], + [ac_cv_strftime_c99_support=yes], +-[ac_cv_strftime_c99_support=no], +-[ac_cv_strftime_c99_support=no])]) +-if test "$ac_cv_strftime_c99_support" = yes +-then +- AC_DEFINE([Py_STRFTIME_C99_SUPPORT], [1], +- [Define if C99-specific strftime specifiers are supported.]) +-fi ++[AC_MSG_ERROR([Python requires C99-compatible strftime specifiers])], ++[ac_cv_strftime_c99_support=])]) + + dnl check for ncursesw/ncurses and panelw/panel + dnl NOTE: old curses is not detected. +@@ -6863,7 +7033,7 @@ + dnl NOTE: Inform user how to proceed with files when cross compiling. + dnl Some cross-compile builds are predictable; they won't ever + dnl have /dev/ptmx or /dev/ptc, so we can set them explicitly. +-if test "$ac_sys_system" = "Linux-android" || test "$ac_sys_system" = "iOS"; then ++if test "$ac_sys_system" = "Linux-android" -o "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "watchOS" ; then + ac_cv_file__dev_ptmx=no + ac_cv_file__dev_ptc=no + else +@@ -6979,6 +7149,44 @@ + [Define if the C compiler supports computed gotos.]) + esac + ++# Check for --with-tail-call-interp ++AC_MSG_CHECKING([for --with-tail-call-interp]) ++AC_ARG_WITH( ++ [tail-call-interp], ++ [AS_HELP_STRING( ++ [--with-tail-call-interp], ++ [enable tail-calling interpreter in evaluation loop and rest of CPython] ++ )], ++[ ++if test "$withval" = yes ++then ++ AC_DEFINE([Py_TAIL_CALL_INTERP], [1], ++ [Define if you want to use tail-calling interpreters in CPython.]) ++ AC_MSG_RESULT([yes]) ++fi ++if test "$withval" = no ++then ++ AC_DEFINE([Py_TAIL_CALL_INTERP], [0], ++ [Define if you want to use tail-calling interpreters in CPython.]) ++ AC_MSG_RESULT([no]) ++fi ++], ++[AC_MSG_RESULT([no value specified])]) ++ ++# Do not enable tail-calling interpreter if tier 2 is enabled. ++AS_VAR_IF( ++ [tier2_flags], ++ [], ++ [ ++ case "$ac_cv_tail_call" in yes*) ++ AC_DEFINE([Py_TAIL_CALL_INTERP], [1], ++ [Define if the C compiler supports efficient proper tail calls.]) ++ esac ++ ], ++ [] ++) ++ ++ + case $ac_sys_system in + AIX*) + AC_DEFINE([HAVE_BROKEN_PIPE_BUF], [1], +@@ -7119,7 +7327,7 @@ AS_CASE([$ac_sys_system], [Emscripten], [with_ensurepip=no], [WASI], [with_ensurepip=no], @@ -1241,7 +166889,36 @@ index bd0221481c5..6dca265f3cc 100644 [with_ensurepip=upgrade] ) ]) -@@ -7529,7 +7669,7 @@ +@@ -7502,18 +7710,19 @@ + + # gh-59705: Maximum length in bytes of a thread name + case "$ac_sys_system" in +- Linux*) PYTHREAD_NAME_MAXLEN=15;; # Linux and Android +- SunOS*) PYTHREAD_NAME_MAXLEN=31;; +- Darwin) PYTHREAD_NAME_MAXLEN=63;; +- iOS) PYTHREAD_NAME_MAXLEN=63;; +- FreeBSD*) PYTHREAD_NAME_MAXLEN=98;; +- *) PYTHREAD_NAME_MAXLEN=;; ++ Linux*) _PYTHREAD_NAME_MAXLEN=15;; # Linux and Android ++ SunOS*) _PYTHREAD_NAME_MAXLEN=31;; ++ NetBSD*) _PYTHREAD_NAME_MAXLEN=31;; ++ Darwin) _PYTHREAD_NAME_MAXLEN=63;; ++ iOS) _PYTHREAD_NAME_MAXLEN=63;; ++ FreeBSD*) _PYTHREAD_NAME_MAXLEN=98;; ++ *) _PYTHREAD_NAME_MAXLEN=;; + esac +-if test -n "$PYTHREAD_NAME_MAXLEN"; then +- AC_DEFINE_UNQUOTED([PYTHREAD_NAME_MAXLEN], [$PYTHREAD_NAME_MAXLEN], ++if test -n "$_PYTHREAD_NAME_MAXLEN"; then ++ AC_DEFINE_UNQUOTED([_PYTHREAD_NAME_MAXLEN], [$_PYTHREAD_NAME_MAXLEN], + [Maximum length in bytes of a thread name]) + fi +-AC_SUBST([PYTHREAD_NAME_MAXLEN]) ++AC_SUBST([_PYTHREAD_NAME_MAXLEN]) + + + # stdlib +@@ -7529,7 +7738,7 @@ [VxWorks*], [PY_STDLIB_MOD_SET_NA([_scproxy], [termios], [grp])], dnl The _scproxy module is available on macOS [Darwin], [], @@ -1270,6 +166947,1880 @@ index c3e261ecd9e..26ef7a95de4 100644 CFBundleSupportedPlatforms iPhoneOS +--- /dev/null ++++ b/iOS/Resources/bin/arm64-apple-ios-macabi-ar +@@ -0,0 +1,2 @@ ++#!/bin/sh ++xcrun --sdk macosx${MACOSX_SDK_VERSION} ar "$@" +--- /dev/null ++++ b/iOS/Resources/bin/arm64-apple-ios-macabi-clang +@@ -0,0 +1,2 @@ ++#!/bin/sh ++xcrun --sdk macosx${MACOSX_SDK_VERSION} clang -target arm64-apple-ios-macabi "$@" +--- /dev/null ++++ b/iOS/Resources/bin/arm64-apple-ios-macabi-clang++ +@@ -0,0 +1,2 @@ ++#!/bin/sh ++xcrun --sdk macosx${MACOSX_SDK_VERSION} clang++ -target arm64-apple-ios-macabi "$@" +--- /dev/null ++++ b/iOS/Resources/bin/arm64-apple-ios-macabi-cpp +@@ -0,0 +1,2 @@ ++#!/bin/sh ++xcrun --sdk macosx${MACOSX_SDK_VERSION} clang -target arm64-apple-ios-macabi "$@" +--- /dev/null ++++ b/iOS/Resources/bin/x86_64-apple-ios-macabi-ar +@@ -0,0 +1,2 @@ ++#!/bin/sh ++xcrun --sdk macosx${MACOSX_SDK_VERSION} ar "$@" +--- /dev/null ++++ b/iOS/Resources/bin/x86_64-apple-ios-macabi-clang +@@ -0,0 +1,2 @@ ++#!/bin/sh ++xcrun --sdk macosx${MACOSX_SDK_VERSION} clang -target x86_64-apple-ios-macabi "$@" +--- /dev/null ++++ b/iOS/Resources/bin/x86_64-apple-ios-macabi-clang++ +@@ -0,0 +1,2 @@ ++#!/bin/sh ++xcrun --sdk macosx${MACOSX_SDK_VERSION} clang++ -target x86_64-apple-ios-macabi "$@" +--- /dev/null ++++ b/iOS/Resources/bin/x86_64-apple-ios-macabi-cpp +@@ -0,0 +1,2 @@ ++#!/bin/sh ++xcrun --sdk macosx${MACOSX_SDK_VERSION} clang -target x86_64-apple-ios-macabi "$@" +diff --git a/iOS/testbed/__main__.py b/iOS/testbed/__main__.py +index 068272835a5..d12a5ab065b 100644 +--- a/iOS/testbed/__main__.py ++++ b/iOS/testbed/__main__.py +@@ -2,6 +2,7 @@ + import asyncio + import json + import plistlib ++import re + import shutil + import subprocess + import sys +@@ -12,6 +13,18 @@ + + DECODE_ARGS = ("UTF-8", "backslashreplace") + ++# The system log prefixes each line: ++# 2025-01-17 16:14:29.090 Df iOSTestbed[23987:1fd393b4] (Python) ... ++# 2025-01-17 16:14:29.090 E iOSTestbed[23987:1fd393b4] (Python) ... ++ ++LOG_PREFIX_REGEX = re.compile( ++ r"^\d{4}-\d{2}-\d{2}" # YYYY-MM-DD ++ r"\s+\d+:\d{2}:\d{2}\.\d+" # HH:MM:SS.sss ++ r"\s+\w+" # Df/E ++ r"\s+iOSTestbed\[\d+:\w+\]" # Process/thread ID ++ r"\s+\(Python\)\s" # Logger name ++) ++ + + # Work around a bug involving sys.exit and TaskGroups + # (https://github.com/python/cpython/issues/101515). +@@ -69,19 +82,29 @@ + + # Return a list of UDIDs associated with booted simulators + async def list_devices(): +- # List the testing simulators, in JSON format +- raw_json = await async_check_output( +- "xcrun", "simctl", "--set", "testing", "list", "-j" +- ) +- json_data = json.loads(raw_json) +- +- # Filter out the booted iOS simulators +- return [ +- simulator["udid"] +- for runtime, simulators in json_data["devices"].items() +- for simulator in simulators +- if runtime.split(".")[-1].startswith("iOS") and simulator["state"] == "Booted" +- ] ++ try: ++ # List the testing simulators, in JSON format ++ raw_json = await async_check_output( ++ "xcrun", "simctl", "--set", "testing", "list", "-j" ++ ) ++ json_data = json.loads(raw_json) ++ ++ # Filter out the booted iOS simulators ++ return [ ++ simulator["udid"] ++ for runtime, simulators in json_data["devices"].items() ++ for simulator in simulators ++ if runtime.split(".")[-1].startswith("iOS") and simulator["state"] == "Booted" ++ ] ++ except subprocess.CalledProcessError as e: ++ # If there's no ~/Library/Developer/XCTestDevices folder (which is the ++ # case on fresh installs, and in some CI environments), `simctl list` ++ # returns error code 1, rather than an empty list. Handle that case, ++ # but raise all other errors. ++ if e.returncode == 1: ++ return [] ++ else: ++ raise + + + async def find_device(initial_devices): +@@ -131,6 +154,8 @@ + ) as process: + suppress_dupes = False + while line := (await process.stdout.readline()).decode(*DECODE_ARGS): ++ # Strip the prefix from each log line ++ line = LOG_PREFIX_REGEX.sub("", line) + # The iOS log streamer can sometimes lag; when it does, it outputs + # a warning about messages being dropped... often multiple times. + # Only print the first of these duplicated warnings. +@@ -215,33 +240,69 @@ + shutil.copytree(source, target, symlinks=True) + print(" done") + ++ xc_framework_path = target / "Python.xcframework" ++ sim_framework_path = xc_framework_path / "ios-arm64_x86_64-simulator" + if framework is not None: + if framework.suffix == ".xcframework": + print(" Installing XCFramework...", end="", flush=True) +- xc_framework_path = (target / "Python.xcframework").resolve() + if xc_framework_path.is_dir(): + shutil.rmtree(xc_framework_path) + else: +- xc_framework_path.unlink() ++ xc_framework_path.unlink(missing_ok=True) + xc_framework_path.symlink_to( + framework.relative_to(xc_framework_path.parent, walk_up=True) + ) + print(" done") + else: + print(" Installing simulator framework...", end="", flush=True) +- sim_framework_path = ( +- target / "Python.xcframework" / "ios-arm64_x86_64-simulator" +- ).resolve() + if sim_framework_path.is_dir(): + shutil.rmtree(sim_framework_path) + else: +- sim_framework_path.unlink() ++ sim_framework_path.unlink(missing_ok=True) + sim_framework_path.symlink_to( + framework.relative_to(sim_framework_path.parent, walk_up=True) + ) + print(" done") + else: +- print(" Using pre-existing iOS framework.") ++ if ( ++ xc_framework_path.is_symlink() ++ and not xc_framework_path.readlink().is_absolute() ++ ): ++ # XCFramework is a relative symlink. Rewrite the symlink relative ++ # to the new location. ++ print(" Rewriting symlink to XCframework...", end="", flush=True) ++ orig_xc_framework_path = ( ++ source ++ / xc_framework_path.readlink() ++ ).resolve() ++ xc_framework_path.unlink() ++ xc_framework_path.symlink_to( ++ orig_xc_framework_path.relative_to( ++ xc_framework_path.parent, walk_up=True ++ ) ++ ) ++ print(" done") ++ elif ( ++ sim_framework_path.is_symlink() ++ and not sim_framework_path.readlink().is_absolute() ++ ): ++ print(" Rewriting symlink to simulator framework...", end="", flush=True) ++ # Simulator framework is a relative symlink. Rewrite the symlink ++ # relative to the new location. ++ orig_sim_framework_path = ( ++ source ++ / "Python.XCframework" ++ / sim_framework_path.readlink() ++ ).resolve() ++ sim_framework_path.unlink() ++ sim_framework_path.symlink_to( ++ orig_sim_framework_path.relative_to( ++ sim_framework_path.parent, walk_up=True ++ ) ++ ) ++ print(" done") ++ else: ++ print(" Using pre-existing iOS framework.") + + for app_src in apps: + print(f" Installing app {app_src.name!r}...", end="", flush=True) +@@ -357,8 +418,8 @@ + + if context.subcommand == "clone": + clone_testbed( +- source=Path(__file__).parent, +- target=Path(context.location), ++ source=Path(__file__).parent.resolve(), ++ target=Path(context.location).resolve(), + framework=Path(context.framework).resolve() if context.framework else None, + apps=[Path(app) for app in context.apps], + ) +diff --git a/install-sh b/install-sh +index ec298b53740..7c56c9c0151 100755 +--- a/install-sh ++++ b/install-sh +@@ -1,7 +1,7 @@ + #!/bin/sh + # install - install a program, script, or datafile + +-scriptversion=2020-11-14.01; # UTC ++scriptversion=2023-11-23.18; # UTC + + # This originates from X11R5 (mit/util/scripts/install.sh), which was + # later released in X11R6 (xc/config/util/install.sh) with the +@@ -124,9 +124,9 @@ + + If -S is not specified, no backups are attempted. + +-Email bug reports to bug-automake@gnu.org. +-Automake home page: https://www.gnu.org/software/automake/ +-" ++Report bugs to . ++GNU Automake home page: . ++General help using GNU software: ." + + while test $# -ne 0; do + case $1 in +diff --git a/pyconfig.h.in b/pyconfig.h.in +index 166c195a8c6..9ea01ad3fc0 100644 +--- a/pyconfig.h.in ++++ b/pyconfig.h.in +@@ -16,13 +16,13 @@ + support for AIX C++ shared extension modules. */ + #undef AIX_GENUINE_CPLUSPLUS + +-/* The normal alignment of `long', in bytes. */ ++/* The normal alignment of 'long', in bytes. */ + #undef ALIGNOF_LONG + +-/* The normal alignment of `max_align_t', in bytes. */ ++/* The normal alignment of 'max_align_t', in bytes. */ + #undef ALIGNOF_MAX_ALIGN_T + +-/* The normal alignment of `size_t', in bytes. */ ++/* The normal alignment of 'size_t', in bytes. */ + #undef ALIGNOF_SIZE_T + + /* Alternative SOABI used in debug build to load C extensions built in release +@@ -59,16 +59,16 @@ + /* Define if you have the 'accept' function. */ + #undef HAVE_ACCEPT + +-/* Define to 1 if you have the `accept4' function. */ ++/* Define to 1 if you have the 'accept4' function. */ + #undef HAVE_ACCEPT4 + +-/* Define to 1 if you have the `acosh' function. */ ++/* Define to 1 if you have the 'acosh' function. */ + #undef HAVE_ACOSH + + /* struct addrinfo (netdb.h) */ + #undef HAVE_ADDRINFO + +-/* Define to 1 if you have the `alarm' function. */ ++/* Define to 1 if you have the 'alarm' function. */ + #undef HAVE_ALARM + + /* Define if aligned memory access is required */ +@@ -80,19 +80,19 @@ + /* Define this if your time.h defines altzone. */ + #undef HAVE_ALTZONE + +-/* Define to 1 if you have the `asinh' function. */ ++/* Define to 1 if you have the 'asinh' function. */ + #undef HAVE_ASINH + + /* Define to 1 if you have the header file. */ + #undef HAVE_ASM_TYPES_H + +-/* Define to 1 if you have the `atanh' function. */ ++/* Define to 1 if you have the 'atanh' function. */ + #undef HAVE_ATANH + + /* Define if you have the 'bind' function. */ + #undef HAVE_BIND + +-/* Define to 1 if you have the `bind_textdomain_codeset' function. */ ++/* Define to 1 if you have the 'bind_textdomain_codeset' function. */ + #undef HAVE_BIND_TEXTDOMAIN_CODESET + + /* Define to 1 if you have the header file. */ +@@ -135,43 +135,43 @@ + /* Define to 1 if you have the 'chflags' function. */ + #undef HAVE_CHFLAGS + +-/* Define to 1 if you have the `chmod' function. */ ++/* Define to 1 if you have the 'chmod' function. */ + #undef HAVE_CHMOD + +-/* Define to 1 if you have the `chown' function. */ ++/* Define to 1 if you have the 'chown' function. */ + #undef HAVE_CHOWN + + /* Define if you have the 'chroot' function. */ + #undef HAVE_CHROOT + +-/* Define to 1 if you have the `clock' function. */ ++/* Define to 1 if you have the 'clock' function. */ + #undef HAVE_CLOCK + +-/* Define to 1 if you have the `clock_getres' function. */ ++/* Define to 1 if you have the 'clock_getres' function. */ + #undef HAVE_CLOCK_GETRES + +-/* Define to 1 if you have the `clock_gettime' function. */ ++/* Define to 1 if you have the 'clock_gettime' function. */ + #undef HAVE_CLOCK_GETTIME + +-/* Define to 1 if you have the `clock_nanosleep' function. */ ++/* Define to 1 if you have the 'clock_nanosleep' function. */ + #undef HAVE_CLOCK_NANOSLEEP + +-/* Define to 1 if you have the `clock_settime' function. */ ++/* Define to 1 if you have the 'clock_settime' function. */ + #undef HAVE_CLOCK_SETTIME + +-/* Define to 1 if the system has the type `clock_t'. */ ++/* Define to 1 if the system has the type 'clock_t'. */ + #undef HAVE_CLOCK_T + +-/* Define to 1 if you have the `closefrom' function. */ ++/* Define to 1 if you have the 'closefrom' function. */ + #undef HAVE_CLOSEFROM + +-/* Define to 1 if you have the `close_range' function. */ ++/* Define to 1 if you have the 'close_range' function. */ + #undef HAVE_CLOSE_RANGE + + /* Define if the C compiler supports computed gotos. */ + #undef HAVE_COMPUTED_GOTOS + +-/* Define to 1 if you have the `confstr' function. */ ++/* Define to 1 if you have the 'confstr' function. */ + #undef HAVE_CONFSTR + + /* Define to 1 if you have the header file. */ +@@ -180,10 +180,10 @@ + /* Define if you have the 'connect' function. */ + #undef HAVE_CONNECT + +-/* Define to 1 if you have the `copy_file_range' function. */ ++/* Define to 1 if you have the 'copy_file_range' function. */ + #undef HAVE_COPY_FILE_RANGE + +-/* Define to 1 if you have the `ctermid' function. */ ++/* Define to 1 if you have the 'ctermid' function. */ + #undef HAVE_CTERMID + + /* Define if you have the 'ctermid_r' function. */ +@@ -228,39 +228,39 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_DB_H + +-/* Define to 1 if you have the declaration of `RTLD_DEEPBIND', and to 0 if you ++/* Define to 1 if you have the declaration of 'RTLD_DEEPBIND', and to 0 if you + don't. */ + #undef HAVE_DECL_RTLD_DEEPBIND + +-/* Define to 1 if you have the declaration of `RTLD_GLOBAL', and to 0 if you ++/* Define to 1 if you have the declaration of 'RTLD_GLOBAL', and to 0 if you + don't. */ + #undef HAVE_DECL_RTLD_GLOBAL + +-/* Define to 1 if you have the declaration of `RTLD_LAZY', and to 0 if you ++/* Define to 1 if you have the declaration of 'RTLD_LAZY', and to 0 if you + don't. */ + #undef HAVE_DECL_RTLD_LAZY + +-/* Define to 1 if you have the declaration of `RTLD_LOCAL', and to 0 if you ++/* Define to 1 if you have the declaration of 'RTLD_LOCAL', and to 0 if you + don't. */ + #undef HAVE_DECL_RTLD_LOCAL + +-/* Define to 1 if you have the declaration of `RTLD_MEMBER', and to 0 if you ++/* Define to 1 if you have the declaration of 'RTLD_MEMBER', and to 0 if you + don't. */ + #undef HAVE_DECL_RTLD_MEMBER + +-/* Define to 1 if you have the declaration of `RTLD_NODELETE', and to 0 if you ++/* Define to 1 if you have the declaration of 'RTLD_NODELETE', and to 0 if you + don't. */ + #undef HAVE_DECL_RTLD_NODELETE + +-/* Define to 1 if you have the declaration of `RTLD_NOLOAD', and to 0 if you ++/* Define to 1 if you have the declaration of 'RTLD_NOLOAD', and to 0 if you + don't. */ + #undef HAVE_DECL_RTLD_NOLOAD + +-/* Define to 1 if you have the declaration of `RTLD_NOW', and to 0 if you ++/* Define to 1 if you have the declaration of 'RTLD_NOW', and to 0 if you + don't. */ + #undef HAVE_DECL_RTLD_NOW + +-/* Define to 1 if you have the declaration of `tzname', and to 0 if you don't. ++/* Define to 1 if you have the declaration of 'tzname', and to 0 if you don't. + */ + #undef HAVE_DECL_TZNAME + +@@ -279,26 +279,29 @@ + /* Define to 1 if the dirent structure has a d_type field */ + #undef HAVE_DIRENT_D_TYPE + +-/* Define to 1 if you have the header file, and it defines `DIR'. ++/* Define to 1 if you have the header file, and it defines 'DIR'. + */ + #undef HAVE_DIRENT_H + + /* Define if you have the 'dirfd' function or macro. */ + #undef HAVE_DIRFD + ++/* Define to 1 if you have the 'dladdr' function. */ ++#undef HAVE_DLADDR ++ + /* Define to 1 if you have the header file. */ + #undef HAVE_DLFCN_H + +-/* Define to 1 if you have the `dlopen' function. */ ++/* Define to 1 if you have the 'dlopen' function. */ + #undef HAVE_DLOPEN + +-/* Define to 1 if you have the `dup' function. */ ++/* Define to 1 if you have the 'dup' function. */ + #undef HAVE_DUP + +-/* Define to 1 if you have the `dup2' function. */ ++/* Define to 1 if you have the 'dup2' function. */ + #undef HAVE_DUP2 + +-/* Define to 1 if you have the `dup3' function. */ ++/* Define to 1 if you have the 'dup3' function. */ + #undef HAVE_DUP3 + + /* Define if you have the '_dyld_shared_cache_contains_path' function. */ +@@ -319,10 +322,10 @@ + /* Define if you have the 'epoll_create1' function. */ + #undef HAVE_EPOLL_CREATE1 + +-/* Define to 1 if you have the `erf' function. */ ++/* Define to 1 if you have the 'erf' function. */ + #undef HAVE_ERF + +-/* Define to 1 if you have the `erfc' function. */ ++/* Define to 1 if you have the 'erfc' function. */ + #undef HAVE_ERFC + + /* Define to 1 if you have the header file. */ +@@ -331,34 +334,34 @@ + /* Define if you have the 'eventfd' function. */ + #undef HAVE_EVENTFD + +-/* Define to 1 if you have the `execv' function. */ ++/* Define to 1 if you have the 'execv' function. */ + #undef HAVE_EXECV + +-/* Define to 1 if you have the `explicit_bzero' function. */ ++/* Define to 1 if you have the 'explicit_bzero' function. */ + #undef HAVE_EXPLICIT_BZERO + +-/* Define to 1 if you have the `explicit_memset' function. */ ++/* Define to 1 if you have the 'explicit_memset' function. */ + #undef HAVE_EXPLICIT_MEMSET + +-/* Define to 1 if you have the `expm1' function. */ ++/* Define to 1 if you have the 'expm1' function. */ + #undef HAVE_EXPM1 + +-/* Define to 1 if you have the `faccessat' function. */ ++/* Define to 1 if you have the 'faccessat' function. */ + #undef HAVE_FACCESSAT + + /* Define if you have the 'fchdir' function. */ + #undef HAVE_FCHDIR + +-/* Define to 1 if you have the `fchmod' function. */ ++/* Define to 1 if you have the 'fchmod' function. */ + #undef HAVE_FCHMOD + +-/* Define to 1 if you have the `fchmodat' function. */ ++/* Define to 1 if you have the 'fchmodat' function. */ + #undef HAVE_FCHMODAT + +-/* Define to 1 if you have the `fchown' function. */ ++/* Define to 1 if you have the 'fchown' function. */ + #undef HAVE_FCHOWN + +-/* Define to 1 if you have the `fchownat' function. */ ++/* Define to 1 if you have the 'fchownat' function. */ + #undef HAVE_FCHOWNAT + + /* Define to 1 if you have the header file. */ +@@ -367,13 +370,13 @@ + /* Define if you have the 'fdatasync' function. */ + #undef HAVE_FDATASYNC + +-/* Define to 1 if you have the `fdopendir' function. */ ++/* Define to 1 if you have the 'fdopendir' function. */ + #undef HAVE_FDOPENDIR + +-/* Define to 1 if you have the `fdwalk' function. */ ++/* Define to 1 if you have the 'fdwalk' function. */ + #undef HAVE_FDWALK + +-/* Define to 1 if you have the `fexecve' function. */ ++/* Define to 1 if you have the 'fexecve' function. */ + #undef HAVE_FEXECVE + + /* Define if you have the 'ffi_closure_alloc' function. */ +@@ -385,58 +388,58 @@ + /* Define if you have the 'ffi_prep_closure_loc' function. */ + #undef HAVE_FFI_PREP_CLOSURE_LOC + +-/* Define to 1 if you have the `flock' function. */ ++/* Define to 1 if you have the 'flock' function. */ + #undef HAVE_FLOCK + +-/* Define to 1 if you have the `fork' function. */ ++/* Define to 1 if you have the 'fork' function. */ + #undef HAVE_FORK + +-/* Define to 1 if you have the `fork1' function. */ ++/* Define to 1 if you have the 'fork1' function. */ + #undef HAVE_FORK1 + +-/* Define to 1 if you have the `forkpty' function. */ ++/* Define to 1 if you have the 'forkpty' function. */ + #undef HAVE_FORKPTY + +-/* Define to 1 if you have the `fpathconf' function. */ ++/* Define to 1 if you have the 'fpathconf' function. */ + #undef HAVE_FPATHCONF + +-/* Define to 1 if you have the `fseek64' function. */ ++/* Define to 1 if you have the 'fseek64' function. */ + #undef HAVE_FSEEK64 + +-/* Define to 1 if you have the `fseeko' function. */ ++/* Define to 1 if you have the 'fseeko' function. */ + #undef HAVE_FSEEKO + +-/* Define to 1 if you have the `fstatat' function. */ ++/* Define to 1 if you have the 'fstatat' function. */ + #undef HAVE_FSTATAT + +-/* Define to 1 if you have the `fstatvfs' function. */ ++/* Define to 1 if you have the 'fstatvfs' function. */ + #undef HAVE_FSTATVFS + + /* Define if you have the 'fsync' function. */ + #undef HAVE_FSYNC + +-/* Define to 1 if you have the `ftell64' function. */ ++/* Define to 1 if you have the 'ftell64' function. */ + #undef HAVE_FTELL64 + +-/* Define to 1 if you have the `ftello' function. */ ++/* Define to 1 if you have the 'ftello' function. */ + #undef HAVE_FTELLO + +-/* Define to 1 if you have the `ftime' function. */ ++/* Define to 1 if you have the 'ftime' function. */ + #undef HAVE_FTIME + +-/* Define to 1 if you have the `ftruncate' function. */ ++/* Define to 1 if you have the 'ftruncate' function. */ + #undef HAVE_FTRUNCATE + +-/* Define to 1 if you have the `futimens' function. */ ++/* Define to 1 if you have the 'futimens' function. */ + #undef HAVE_FUTIMENS + +-/* Define to 1 if you have the `futimes' function. */ ++/* Define to 1 if you have the 'futimes' function. */ + #undef HAVE_FUTIMES + +-/* Define to 1 if you have the `futimesat' function. */ ++/* Define to 1 if you have the 'futimesat' function. */ + #undef HAVE_FUTIMESAT + +-/* Define to 1 if you have the `gai_strerror' function. */ ++/* Define to 1 if you have the 'gai_strerror' function. */ + #undef HAVE_GAI_STRERROR + + /* Define if we can use gcc inline assembler to get and set mc68881 fpcr */ +@@ -467,40 +470,40 @@ + /* Define this if you have flockfile(), getc_unlocked(), and funlockfile() */ + #undef HAVE_GETC_UNLOCKED + +-/* Define to 1 if you have the `getegid' function. */ ++/* Define to 1 if you have the 'getegid' function. */ + #undef HAVE_GETEGID + +-/* Define to 1 if you have the `getentropy' function. */ ++/* Define to 1 if you have the 'getentropy' function. */ + #undef HAVE_GETENTROPY + +-/* Define to 1 if you have the `geteuid' function. */ ++/* Define to 1 if you have the 'geteuid' function. */ + #undef HAVE_GETEUID + +-/* Define to 1 if you have the `getgid' function. */ ++/* Define to 1 if you have the 'getgid' function. */ + #undef HAVE_GETGID + +-/* Define to 1 if you have the `getgrent' function. */ ++/* Define to 1 if you have the 'getgrent' function. */ + #undef HAVE_GETGRENT + +-/* Define to 1 if you have the `getgrgid' function. */ ++/* Define to 1 if you have the 'getgrgid' function. */ + #undef HAVE_GETGRGID + +-/* Define to 1 if you have the `getgrgid_r' function. */ ++/* Define to 1 if you have the 'getgrgid_r' function. */ + #undef HAVE_GETGRGID_R + +-/* Define to 1 if you have the `getgrnam_r' function. */ ++/* Define to 1 if you have the 'getgrnam_r' function. */ + #undef HAVE_GETGRNAM_R + +-/* Define to 1 if you have the `getgrouplist' function. */ ++/* Define to 1 if you have the 'getgrouplist' function. */ + #undef HAVE_GETGROUPLIST + +-/* Define to 1 if you have the `getgroups' function. */ ++/* Define to 1 if you have the 'getgroups' function. */ + #undef HAVE_GETGROUPS + + /* Define if you have the 'gethostbyaddr' function. */ + #undef HAVE_GETHOSTBYADDR + +-/* Define to 1 if you have the `gethostbyname' function. */ ++/* Define to 1 if you have the 'gethostbyname' function. */ + #undef HAVE_GETHOSTBYNAME + + /* Define this if you have some version of gethostbyname_r() */ +@@ -515,19 +518,19 @@ + /* Define this if you have the 6-arg version of gethostbyname_r(). */ + #undef HAVE_GETHOSTBYNAME_R_6_ARG + +-/* Define to 1 if you have the `gethostname' function. */ ++/* Define to 1 if you have the 'gethostname' function. */ + #undef HAVE_GETHOSTNAME + +-/* Define to 1 if you have the `getitimer' function. */ ++/* Define to 1 if you have the 'getitimer' function. */ + #undef HAVE_GETITIMER + +-/* Define to 1 if you have the `getloadavg' function. */ ++/* Define to 1 if you have the 'getloadavg' function. */ + #undef HAVE_GETLOADAVG + +-/* Define to 1 if you have the `getlogin' function. */ ++/* Define to 1 if you have the 'getlogin' function. */ + #undef HAVE_GETLOGIN + +-/* Define to 1 if you have the `getnameinfo' function. */ ++/* Define to 1 if you have the 'getnameinfo' function. */ + #undef HAVE_GETNAMEINFO + + /* Define if you have the 'getpagesize' function. */ +@@ -536,34 +539,34 @@ + /* Define if you have the 'getpeername' function. */ + #undef HAVE_GETPEERNAME + +-/* Define to 1 if you have the `getpgid' function. */ ++/* Define to 1 if you have the 'getpgid' function. */ + #undef HAVE_GETPGID + +-/* Define to 1 if you have the `getpgrp' function. */ ++/* Define to 1 if you have the 'getpgrp' function. */ + #undef HAVE_GETPGRP + +-/* Define to 1 if you have the `getpid' function. */ ++/* Define to 1 if you have the 'getpid' function. */ + #undef HAVE_GETPID + +-/* Define to 1 if you have the `getppid' function. */ ++/* Define to 1 if you have the 'getppid' function. */ + #undef HAVE_GETPPID + +-/* Define to 1 if you have the `getpriority' function. */ ++/* Define to 1 if you have the 'getpriority' function. */ + #undef HAVE_GETPRIORITY + + /* Define if you have the 'getprotobyname' function. */ + #undef HAVE_GETPROTOBYNAME + +-/* Define to 1 if you have the `getpwent' function. */ ++/* Define to 1 if you have the 'getpwent' function. */ + #undef HAVE_GETPWENT + +-/* Define to 1 if you have the `getpwnam_r' function. */ ++/* Define to 1 if you have the 'getpwnam_r' function. */ + #undef HAVE_GETPWNAM_R + +-/* Define to 1 if you have the `getpwuid' function. */ ++/* Define to 1 if you have the 'getpwuid' function. */ + #undef HAVE_GETPWUID + +-/* Define to 1 if you have the `getpwuid_r' function. */ ++/* Define to 1 if you have the 'getpwuid_r' function. */ + #undef HAVE_GETPWUID_R + + /* Define to 1 if the getrandom() function is available */ +@@ -572,13 +575,13 @@ + /* Define to 1 if the Linux getrandom() syscall is available */ + #undef HAVE_GETRANDOM_SYSCALL + +-/* Define to 1 if you have the `getresgid' function. */ ++/* Define to 1 if you have the 'getresgid' function. */ + #undef HAVE_GETRESGID + +-/* Define to 1 if you have the `getresuid' function. */ ++/* Define to 1 if you have the 'getresuid' function. */ + #undef HAVE_GETRESUID + +-/* Define to 1 if you have the `getrusage' function. */ ++/* Define to 1 if you have the 'getrusage' function. */ + #undef HAVE_GETRUSAGE + + /* Define if you have the 'getservbyname' function. */ +@@ -587,29 +590,29 @@ + /* Define if you have the 'getservbyport' function. */ + #undef HAVE_GETSERVBYPORT + +-/* Define to 1 if you have the `getsid' function. */ ++/* Define to 1 if you have the 'getsid' function. */ + #undef HAVE_GETSID + + /* Define if you have the 'getsockname' function. */ + #undef HAVE_GETSOCKNAME + +-/* Define to 1 if you have the `getspent' function. */ ++/* Define to 1 if you have the 'getspent' function. */ + #undef HAVE_GETSPENT + +-/* Define to 1 if you have the `getspnam' function. */ ++/* Define to 1 if you have the 'getspnam' function. */ + #undef HAVE_GETSPNAM + +-/* Define to 1 if you have the `getuid' function. */ ++/* Define to 1 if you have the 'getuid' function. */ + #undef HAVE_GETUID + +-/* Define to 1 if you have the `getwd' function. */ ++/* Define to 1 if you have the 'getwd' function. */ + #undef HAVE_GETWD + + /* Define if glibc has incorrect _FORTIFY_SOURCE wrappers for memmove and + bcopy. */ + #undef HAVE_GLIBC_MEMMOVE_BUG + +-/* Define to 1 if you have the `grantpt' function. */ ++/* Define to 1 if you have the 'grantpt' function. */ + #undef HAVE_GRANTPT + + /* Define to 1 if you have the header file. */ +@@ -621,7 +624,7 @@ + /* Define this if you have le64toh() */ + #undef HAVE_HTOLE64 + +-/* Define to 1 if you have the `if_nameindex' function. */ ++/* Define to 1 if you have the 'if_nameindex' function. */ + #undef HAVE_IF_NAMEINDEX + + /* Define if you have the 'inet_aton' function. */ +@@ -633,7 +636,7 @@ + /* Define if you have the 'inet_pton' function. */ + #undef HAVE_INET_PTON + +-/* Define to 1 if you have the `initgroups' function. */ ++/* Define to 1 if you have the 'initgroups' function. */ + #undef HAVE_INITGROUPS + + /* Define to 1 if you have the header file. */ +@@ -645,10 +648,10 @@ + /* Define if gcc has the ipa-pure-const bug. */ + #undef HAVE_IPA_PURE_CONST_BUG + +-/* Define to 1 if you have the `kill' function. */ ++/* Define to 1 if you have the 'kill' function. */ + #undef HAVE_KILL + +-/* Define to 1 if you have the `killpg' function. */ ++/* Define to 1 if you have the 'killpg' function. */ + #undef HAVE_KILLPG + + /* Define if you have the 'kqueue' function. */ +@@ -666,31 +669,31 @@ + /* Define to 1 if you have the 'lchflags' function. */ + #undef HAVE_LCHFLAGS + +-/* Define to 1 if you have the `lchmod' function. */ ++/* Define to 1 if you have the 'lchmod' function. */ + #undef HAVE_LCHMOD + +-/* Define to 1 if you have the `lchown' function. */ ++/* Define to 1 if you have the 'lchown' function. */ + #undef HAVE_LCHOWN + + /* Define to 1 if you have the `db' library (-ldb). */ + #undef HAVE_LIBDB + +-/* Define to 1 if you have the `dl' library (-ldl). */ ++/* Define to 1 if you have the 'dl' library (-ldl). */ + #undef HAVE_LIBDL + +-/* Define to 1 if you have the `dld' library (-ldld). */ ++/* Define to 1 if you have the 'dld' library (-ldld). */ + #undef HAVE_LIBDLD + +-/* Define to 1 if you have the `ieee' library (-lieee). */ ++/* Define to 1 if you have the 'ieee' library (-lieee). */ + #undef HAVE_LIBIEEE + + /* Define to 1 if you have the header file. */ + #undef HAVE_LIBINTL_H + +-/* Define to 1 if you have the `sendfile' library (-lsendfile). */ ++/* Define to 1 if you have the 'sendfile' library (-lsendfile). */ + #undef HAVE_LIBSENDFILE + +-/* Define to 1 if you have the `sqlite3' library (-lsqlite3). */ ++/* Define to 1 if you have the 'sqlite3' library (-lsqlite3). */ + #undef HAVE_LIBSQLITE3 + + /* Define to 1 if you have the header file. */ +@@ -699,7 +702,7 @@ + /* Define if you have the 'link' function. */ + #undef HAVE_LINK + +-/* Define to 1 if you have the `linkat' function. */ ++/* Define to 1 if you have the 'linkat' function. */ + #undef HAVE_LINKAT + + /* Define to 1 if you have the header file. */ +@@ -744,6 +747,9 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_LINUX_RANDOM_H + ++/* Define to 1 if you have the header file. */ ++#undef HAVE_LINUX_SCHED_H ++ + /* Define to 1 if you have the header file. */ + #undef HAVE_LINUX_SOUNDCARD_H + +@@ -759,73 +765,73 @@ + /* Define if you have the 'listen' function. */ + #undef HAVE_LISTEN + +-/* Define to 1 if you have the `lockf' function. */ ++/* Define to 1 if you have the 'lockf' function. */ + #undef HAVE_LOCKF + +-/* Define to 1 if you have the `log1p' function. */ ++/* Define to 1 if you have the 'log1p' function. */ + #undef HAVE_LOG1P + +-/* Define to 1 if you have the `log2' function. */ ++/* Define to 1 if you have the 'log2' function. */ + #undef HAVE_LOG2 + + /* Define to 1 if you have the `login_tty' function. */ + #undef HAVE_LOGIN_TTY + +-/* Define to 1 if the system has the type `long double'. */ ++/* Define to 1 if the system has the type 'long double'. */ + #undef HAVE_LONG_DOUBLE + +-/* Define to 1 if you have the `lstat' function. */ ++/* Define to 1 if you have the 'lstat' function. */ + #undef HAVE_LSTAT + +-/* Define to 1 if you have the `lutimes' function. */ ++/* Define to 1 if you have the 'lutimes' function. */ + #undef HAVE_LUTIMES + + /* Define to 1 if you have the header file. */ + #undef HAVE_LZMA_H + +-/* Define to 1 if you have the `madvise' function. */ ++/* Define to 1 if you have the 'madvise' function. */ + #undef HAVE_MADVISE + + /* Define this if you have the makedev macro. */ + #undef HAVE_MAKEDEV + +-/* Define to 1 if you have the `mbrtowc' function. */ ++/* Define to 1 if you have the 'mbrtowc' function. */ + #undef HAVE_MBRTOWC + + /* Define if you have the 'memfd_create' function. */ + #undef HAVE_MEMFD_CREATE + +-/* Define to 1 if you have the `memrchr' function. */ ++/* Define to 1 if you have the 'memrchr' function. */ + #undef HAVE_MEMRCHR + + /* Define to 1 if you have the header file. */ + #undef HAVE_MINIX_CONFIG_H + +-/* Define to 1 if you have the `mkdirat' function. */ ++/* Define to 1 if you have the 'mkdirat' function. */ + #undef HAVE_MKDIRAT + +-/* Define to 1 if you have the `mkfifo' function. */ ++/* Define to 1 if you have the 'mkfifo' function. */ + #undef HAVE_MKFIFO + +-/* Define to 1 if you have the `mkfifoat' function. */ ++/* Define to 1 if you have the 'mkfifoat' function. */ + #undef HAVE_MKFIFOAT + +-/* Define to 1 if you have the `mknod' function. */ ++/* Define to 1 if you have the 'mknod' function. */ + #undef HAVE_MKNOD + +-/* Define to 1 if you have the `mknodat' function. */ ++/* Define to 1 if you have the 'mknodat' function. */ + #undef HAVE_MKNODAT + +-/* Define to 1 if you have the `mktime' function. */ ++/* Define to 1 if you have the 'mktime' function. */ + #undef HAVE_MKTIME + +-/* Define to 1 if you have the `mmap' function. */ ++/* Define to 1 if you have the 'mmap' function. */ + #undef HAVE_MMAP + +-/* Define to 1 if you have the `mremap' function. */ ++/* Define to 1 if you have the 'mremap' function. */ + #undef HAVE_MREMAP + +-/* Define to 1 if you have the `nanosleep' function. */ ++/* Define to 1 if you have the 'nanosleep' function. */ + #undef HAVE_NANOSLEEP + + /* Define if you have the 'ncurses' library */ +@@ -858,7 +864,7 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_NDBM_H + +-/* Define to 1 if you have the header file, and it defines `DIR'. */ ++/* Define to 1 if you have the header file, and it defines 'DIR'. */ + #undef HAVE_NDIR_H + + /* Define to 1 if you have the header file. */ +@@ -882,20 +888,20 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_NET_IF_H + +-/* Define to 1 if you have the `nice' function. */ ++/* Define to 1 if you have the 'nice' function. */ + #undef HAVE_NICE + + /* Define if the internal form of wchar_t in non-Unicode locales is not + Unicode. */ + #undef HAVE_NON_UNICODE_WCHAR_T_REPRESENTATION + +-/* Define to 1 if you have the `openat' function. */ ++/* Define to 1 if you have the 'openat' function. */ + #undef HAVE_OPENAT + +-/* Define to 1 if you have the `opendir' function. */ ++/* Define to 1 if you have the 'opendir' function. */ + #undef HAVE_OPENDIR + +-/* Define to 1 if you have the `openpty' function. */ ++/* Define to 1 if you have the 'openpty' function. */ + #undef HAVE_OPENPTY + + /* Define if you have the 'panel' library */ +@@ -907,53 +913,53 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_PANEL_H + +-/* Define to 1 if you have the `pathconf' function. */ ++/* Define to 1 if you have the 'pathconf' function. */ + #undef HAVE_PATHCONF + +-/* Define to 1 if you have the `pause' function. */ ++/* Define to 1 if you have the 'pause' function. */ + #undef HAVE_PAUSE + +-/* Define to 1 if you have the `pipe' function. */ ++/* Define to 1 if you have the 'pipe' function. */ + #undef HAVE_PIPE + +-/* Define to 1 if you have the `pipe2' function. */ ++/* Define to 1 if you have the 'pipe2' function. */ + #undef HAVE_PIPE2 + +-/* Define to 1 if you have the `plock' function. */ ++/* Define to 1 if you have the 'plock' function. */ + #undef HAVE_PLOCK + +-/* Define to 1 if you have the `poll' function. */ ++/* Define to 1 if you have the 'poll' function. */ + #undef HAVE_POLL + + /* Define to 1 if you have the header file. */ + #undef HAVE_POLL_H + +-/* Define to 1 if you have the `posix_fadvise' function. */ ++/* Define to 1 if you have the 'posix_fadvise' function. */ + #undef HAVE_POSIX_FADVISE + +-/* Define to 1 if you have the `posix_fallocate' function. */ ++/* Define to 1 if you have the 'posix_fallocate' function. */ + #undef HAVE_POSIX_FALLOCATE + +-/* Define to 1 if you have the `posix_openpt' function. */ ++/* Define to 1 if you have the 'posix_openpt' function. */ + #undef HAVE_POSIX_OPENPT + +-/* Define to 1 if you have the `posix_spawn' function. */ ++/* Define to 1 if you have the 'posix_spawn' function. */ + #undef HAVE_POSIX_SPAWN + +-/* Define to 1 if you have the `posix_spawnp' function. */ ++/* Define to 1 if you have the 'posix_spawnp' function. */ + #undef HAVE_POSIX_SPAWNP + +-/* Define to 1 if you have the `posix_spawn_file_actions_addclosefrom_np' ++/* Define to 1 if you have the 'posix_spawn_file_actions_addclosefrom_np' + function. */ + #undef HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP + +-/* Define to 1 if you have the `pread' function. */ ++/* Define to 1 if you have the 'pread' function. */ + #undef HAVE_PREAD + +-/* Define to 1 if you have the `preadv' function. */ ++/* Define to 1 if you have the 'preadv' function. */ + #undef HAVE_PREADV + +-/* Define to 1 if you have the `preadv2' function. */ ++/* Define to 1 if you have the 'preadv2' function. */ + #undef HAVE_PREADV2 + + /* Define if you have the 'prlimit' function. */ +@@ -962,83 +968,83 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_PROCESS_H + +-/* Define to 1 if you have the `process_vm_readv' function. */ ++/* Define to 1 if you have the 'process_vm_readv' function. */ + #undef HAVE_PROCESS_VM_READV + + /* Define if your compiler supports function prototype */ + #undef HAVE_PROTOTYPES + +-/* Define to 1 if you have the `pthread_condattr_setclock' function. */ ++/* Define to 1 if you have the 'pthread_condattr_setclock' function. */ + #undef HAVE_PTHREAD_CONDATTR_SETCLOCK + +-/* Define to 1 if you have the `pthread_cond_timedwait_relative_np' function. ++/* Define to 1 if you have the 'pthread_cond_timedwait_relative_np' function. + */ + #undef HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP + + /* Defined for Solaris 2.6 bug in pthread header. */ + #undef HAVE_PTHREAD_DESTRUCTOR + +-/* Define to 1 if you have the `pthread_getcpuclockid' function. */ ++/* Define to 1 if you have the 'pthread_getcpuclockid' function. */ + #undef HAVE_PTHREAD_GETCPUCLOCKID + +-/* Define to 1 if you have the `pthread_getname_np' function. */ ++/* Define to 1 if you have the 'pthread_getname_np' function. */ + #undef HAVE_PTHREAD_GETNAME_NP + + /* Define to 1 if you have the header file. */ + #undef HAVE_PTHREAD_H + +-/* Define to 1 if you have the `pthread_init' function. */ ++/* Define to 1 if you have the 'pthread_init' function. */ + #undef HAVE_PTHREAD_INIT + +-/* Define to 1 if you have the `pthread_kill' function. */ ++/* Define to 1 if you have the 'pthread_kill' function. */ + #undef HAVE_PTHREAD_KILL + +-/* Define to 1 if you have the `pthread_setname_np' function. */ ++/* Define to 1 if you have the 'pthread_setname_np' function. */ + #undef HAVE_PTHREAD_SETNAME_NP + +-/* Define to 1 if you have the `pthread_sigmask' function. */ ++/* Define to 1 if you have the 'pthread_sigmask' function. */ + #undef HAVE_PTHREAD_SIGMASK + + /* Define if platform requires stubbed pthreads support */ + #undef HAVE_PTHREAD_STUBS + +-/* Define to 1 if you have the `ptsname' function. */ ++/* Define to 1 if you have the 'ptsname' function. */ + #undef HAVE_PTSNAME + +-/* Define to 1 if you have the `ptsname_r' function. */ ++/* Define to 1 if you have the 'ptsname_r' function. */ + #undef HAVE_PTSNAME_R + + /* Define to 1 if you have the header file. */ + #undef HAVE_PTY_H + +-/* Define to 1 if you have the `pwrite' function. */ ++/* Define to 1 if you have the 'pwrite' function. */ + #undef HAVE_PWRITE + +-/* Define to 1 if you have the `pwritev' function. */ ++/* Define to 1 if you have the 'pwritev' function. */ + #undef HAVE_PWRITEV + +-/* Define to 1 if you have the `pwritev2' function. */ ++/* Define to 1 if you have the 'pwritev2' function. */ + #undef HAVE_PWRITEV2 + + /* Define to 1 if you have the header file. */ + #undef HAVE_READLINE_READLINE_H + +-/* Define to 1 if you have the `readlink' function. */ ++/* Define to 1 if you have the 'readlink' function. */ + #undef HAVE_READLINK + +-/* Define to 1 if you have the `readlinkat' function. */ ++/* Define to 1 if you have the 'readlinkat' function. */ + #undef HAVE_READLINKAT + +-/* Define to 1 if you have the `readv' function. */ ++/* Define to 1 if you have the 'readv' function. */ + #undef HAVE_READV + +-/* Define to 1 if you have the `realpath' function. */ ++/* Define to 1 if you have the 'realpath' function. */ + #undef HAVE_REALPATH + + /* Define if you have the 'recvfrom' function. */ + #undef HAVE_RECVFROM + +-/* Define to 1 if you have the `renameat' function. */ ++/* Define to 1 if you have the 'renameat' function. */ + #undef HAVE_RENAMEAT + + /* Define if readline supports append_history */ +@@ -1047,7 +1053,7 @@ + /* Define if you can turn off readline's signal handling. */ + #undef HAVE_RL_CATCH_SIGNAL + +-/* Define to 1 if the system has the type `rl_compdisp_func_t'. */ ++/* Define to 1 if the system has the type 'rl_compdisp_func_t'. */ + #undef HAVE_RL_COMPDISP_FUNC_T + + /* Define if you have readline 2.2 */ +@@ -1068,154 +1074,154 @@ + /* Define if you have readline 4.0 */ + #undef HAVE_RL_RESIZE_TERMINAL + +-/* Define to 1 if you have the `rtpSpawn' function. */ ++/* Define to 1 if you have the 'rtpSpawn' function. */ + #undef HAVE_RTPSPAWN + +-/* Define to 1 if you have the `sched_get_priority_max' function. */ ++/* Define to 1 if you have the 'sched_get_priority_max' function. */ + #undef HAVE_SCHED_GET_PRIORITY_MAX + + /* Define to 1 if you have the header file. */ + #undef HAVE_SCHED_H + +-/* Define to 1 if you have the `sched_rr_get_interval' function. */ ++/* Define to 1 if you have the 'sched_rr_get_interval' function. */ + #undef HAVE_SCHED_RR_GET_INTERVAL + +-/* Define to 1 if you have the `sched_setaffinity' function. */ ++/* Define to 1 if you have the 'sched_setaffinity' function. */ + #undef HAVE_SCHED_SETAFFINITY + +-/* Define to 1 if you have the `sched_setparam' function. */ ++/* Define to 1 if you have the 'sched_setparam' function. */ + #undef HAVE_SCHED_SETPARAM + +-/* Define to 1 if you have the `sched_setscheduler' function. */ ++/* Define to 1 if you have the 'sched_setscheduler' function. */ + #undef HAVE_SCHED_SETSCHEDULER + +-/* Define to 1 if you have the `sem_clockwait' function. */ ++/* Define to 1 if you have the 'sem_clockwait' function. */ + #undef HAVE_SEM_CLOCKWAIT + +-/* Define to 1 if you have the `sem_getvalue' function. */ ++/* Define to 1 if you have the 'sem_getvalue' function. */ + #undef HAVE_SEM_GETVALUE + +-/* Define to 1 if you have the `sem_open' function. */ ++/* Define to 1 if you have the 'sem_open' function. */ + #undef HAVE_SEM_OPEN + +-/* Define to 1 if you have the `sem_timedwait' function. */ ++/* Define to 1 if you have the 'sem_timedwait' function. */ + #undef HAVE_SEM_TIMEDWAIT + +-/* Define to 1 if you have the `sem_unlink' function. */ ++/* Define to 1 if you have the 'sem_unlink' function. */ + #undef HAVE_SEM_UNLINK + +-/* Define to 1 if you have the `sendfile' function. */ ++/* Define to 1 if you have the 'sendfile' function. */ + #undef HAVE_SENDFILE + + /* Define if you have the 'sendto' function. */ + #undef HAVE_SENDTO + +-/* Define to 1 if you have the `setegid' function. */ ++/* Define to 1 if you have the 'setegid' function. */ + #undef HAVE_SETEGID + +-/* Define to 1 if you have the `seteuid' function. */ ++/* Define to 1 if you have the 'seteuid' function. */ + #undef HAVE_SETEUID + +-/* Define to 1 if you have the `setgid' function. */ ++/* Define to 1 if you have the 'setgid' function. */ + #undef HAVE_SETGID + + /* Define if you have the 'setgroups' function. */ + #undef HAVE_SETGROUPS + +-/* Define to 1 if you have the `sethostname' function. */ ++/* Define to 1 if you have the 'sethostname' function. */ + #undef HAVE_SETHOSTNAME + +-/* Define to 1 if you have the `setitimer' function. */ ++/* Define to 1 if you have the 'setitimer' function. */ + #undef HAVE_SETITIMER + + /* Define to 1 if you have the header file. */ + #undef HAVE_SETJMP_H + +-/* Define to 1 if you have the `setlocale' function. */ ++/* Define to 1 if you have the 'setlocale' function. */ + #undef HAVE_SETLOCALE + +-/* Define to 1 if you have the `setns' function. */ ++/* Define to 1 if you have the 'setns' function. */ + #undef HAVE_SETNS + +-/* Define to 1 if you have the `setpgid' function. */ ++/* Define to 1 if you have the 'setpgid' function. */ + #undef HAVE_SETPGID + +-/* Define to 1 if you have the `setpgrp' function. */ ++/* Define to 1 if you have the 'setpgrp' function. */ + #undef HAVE_SETPGRP + +-/* Define to 1 if you have the `setpriority' function. */ ++/* Define to 1 if you have the 'setpriority' function. */ + #undef HAVE_SETPRIORITY + +-/* Define to 1 if you have the `setregid' function. */ ++/* Define to 1 if you have the 'setregid' function. */ + #undef HAVE_SETREGID + +-/* Define to 1 if you have the `setresgid' function. */ ++/* Define to 1 if you have the 'setresgid' function. */ + #undef HAVE_SETRESGID + +-/* Define to 1 if you have the `setresuid' function. */ ++/* Define to 1 if you have the 'setresuid' function. */ + #undef HAVE_SETRESUID + +-/* Define to 1 if you have the `setreuid' function. */ ++/* Define to 1 if you have the 'setreuid' function. */ + #undef HAVE_SETREUID + +-/* Define to 1 if you have the `setsid' function. */ ++/* Define to 1 if you have the 'setsid' function. */ + #undef HAVE_SETSID + + /* Define if you have the 'setsockopt' function. */ + #undef HAVE_SETSOCKOPT + +-/* Define to 1 if you have the `setuid' function. */ ++/* Define to 1 if you have the 'setuid' function. */ + #undef HAVE_SETUID + +-/* Define to 1 if you have the `setvbuf' function. */ ++/* Define to 1 if you have the 'setvbuf' function. */ + #undef HAVE_SETVBUF + + /* Define to 1 if you have the header file. */ + #undef HAVE_SHADOW_H + +-/* Define to 1 if you have the `shm_open' function. */ ++/* Define to 1 if you have the 'shm_open' function. */ + #undef HAVE_SHM_OPEN + +-/* Define to 1 if you have the `shm_unlink' function. */ ++/* Define to 1 if you have the 'shm_unlink' function. */ + #undef HAVE_SHM_UNLINK + +-/* Define to 1 if you have the `shutdown' function. */ ++/* Define to 1 if you have the 'shutdown' function. */ + #undef HAVE_SHUTDOWN + +-/* Define to 1 if you have the `sigaction' function. */ ++/* Define to 1 if you have the 'sigaction' function. */ + #undef HAVE_SIGACTION + +-/* Define to 1 if you have the `sigaltstack' function. */ ++/* Define to 1 if you have the 'sigaltstack' function. */ + #undef HAVE_SIGALTSTACK + +-/* Define to 1 if you have the `sigfillset' function. */ ++/* Define to 1 if you have the 'sigfillset' function. */ + #undef HAVE_SIGFILLSET + +-/* Define to 1 if `si_band' is a member of `siginfo_t'. */ ++/* Define to 1 if 'si_band' is a member of 'siginfo_t'. */ + #undef HAVE_SIGINFO_T_SI_BAND + +-/* Define to 1 if you have the `siginterrupt' function. */ ++/* Define to 1 if you have the 'siginterrupt' function. */ + #undef HAVE_SIGINTERRUPT + + /* Define to 1 if you have the header file. */ + #undef HAVE_SIGNAL_H + +-/* Define to 1 if you have the `sigpending' function. */ ++/* Define to 1 if you have the 'sigpending' function. */ + #undef HAVE_SIGPENDING + +-/* Define to 1 if you have the `sigrelse' function. */ ++/* Define to 1 if you have the 'sigrelse' function. */ + #undef HAVE_SIGRELSE + +-/* Define to 1 if you have the `sigtimedwait' function. */ ++/* Define to 1 if you have the 'sigtimedwait' function. */ + #undef HAVE_SIGTIMEDWAIT + +-/* Define to 1 if you have the `sigwait' function. */ ++/* Define to 1 if you have the 'sigwait' function. */ + #undef HAVE_SIGWAIT + +-/* Define to 1 if you have the `sigwaitinfo' function. */ ++/* Define to 1 if you have the 'sigwaitinfo' function. */ + #undef HAVE_SIGWAITINFO + +-/* Define to 1 if you have the `snprintf' function. */ ++/* Define to 1 if you have the 'snprintf' function. */ + #undef HAVE_SNPRINTF + + /* struct sockaddr_alg (linux/if_alg.h) */ +@@ -1233,19 +1239,19 @@ + /* Define if you have the 'socketpair' function. */ + #undef HAVE_SOCKETPAIR + +-/* Define to 1 if the system has the type `socklen_t'. */ ++/* Define to 1 if the system has the type 'socklen_t'. */ + #undef HAVE_SOCKLEN_T + + /* Define to 1 if you have the header file. */ + #undef HAVE_SPAWN_H + +-/* Define to 1 if you have the `splice' function. */ ++/* Define to 1 if you have the 'splice' function. */ + #undef HAVE_SPLICE + +-/* Define to 1 if the system has the type `ssize_t'. */ ++/* Define to 1 if the system has the type 'ssize_t'. */ + #undef HAVE_SSIZE_T + +-/* Define to 1 if you have the `statvfs' function. */ ++/* Define to 1 if you have the 'statvfs' function. */ + #undef HAVE_STATVFS + + /* Define if you have struct stat.st_mtim.tv_nsec */ +@@ -1266,7 +1272,7 @@ + /* Has stdatomic.h with atomic_int and atomic_uintptr_t */ + #undef HAVE_STD_ATOMIC + +-/* Define to 1 if you have the `strftime' function. */ ++/* Define to 1 if you have the 'strftime' function. */ + #undef HAVE_STRFTIME + + /* Define to 1 if you have the header file. */ +@@ -1275,52 +1281,52 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_STRING_H + +-/* Define to 1 if you have the `strlcpy' function. */ ++/* Define to 1 if you have the 'strlcpy' function. */ + #undef HAVE_STRLCPY + + /* Define to 1 if you have the header file. */ + #undef HAVE_STROPTS_H + +-/* Define to 1 if you have the `strsignal' function. */ ++/* Define to 1 if you have the 'strsignal' function. */ + #undef HAVE_STRSIGNAL + +-/* Define to 1 if `pw_gecos' is a member of `struct passwd'. */ ++/* Define to 1 if 'pw_gecos' is a member of 'struct passwd'. */ + #undef HAVE_STRUCT_PASSWD_PW_GECOS + +-/* Define to 1 if `pw_passwd' is a member of `struct passwd'. */ ++/* Define to 1 if 'pw_passwd' is a member of 'struct passwd'. */ + #undef HAVE_STRUCT_PASSWD_PW_PASSWD + +-/* Define to 1 if `st_birthtime' is a member of `struct stat'. */ ++/* Define to 1 if 'st_birthtime' is a member of 'struct stat'. */ + #undef HAVE_STRUCT_STAT_ST_BIRTHTIME + +-/* Define to 1 if `st_blksize' is a member of `struct stat'. */ ++/* Define to 1 if 'st_blksize' is a member of 'struct stat'. */ + #undef HAVE_STRUCT_STAT_ST_BLKSIZE + +-/* Define to 1 if `st_blocks' is a member of `struct stat'. */ ++/* Define to 1 if 'st_blocks' is a member of 'struct stat'. */ + #undef HAVE_STRUCT_STAT_ST_BLOCKS + +-/* Define to 1 if `st_flags' is a member of `struct stat'. */ ++/* Define to 1 if 'st_flags' is a member of 'struct stat'. */ + #undef HAVE_STRUCT_STAT_ST_FLAGS + +-/* Define to 1 if `st_gen' is a member of `struct stat'. */ ++/* Define to 1 if 'st_gen' is a member of 'struct stat'. */ + #undef HAVE_STRUCT_STAT_ST_GEN + +-/* Define to 1 if `st_rdev' is a member of `struct stat'. */ ++/* Define to 1 if 'st_rdev' is a member of 'struct stat'. */ + #undef HAVE_STRUCT_STAT_ST_RDEV + +-/* Define to 1 if `tm_zone' is a member of `struct tm'. */ ++/* Define to 1 if 'tm_zone' is a member of 'struct tm'. */ + #undef HAVE_STRUCT_TM_TM_ZONE + + /* Define if you have the 'symlink' function. */ + #undef HAVE_SYMLINK + +-/* Define to 1 if you have the `symlinkat' function. */ ++/* Define to 1 if you have the 'symlinkat' function. */ + #undef HAVE_SYMLINKAT + +-/* Define to 1 if you have the `sync' function. */ ++/* Define to 1 if you have the 'sync' function. */ + #undef HAVE_SYNC + +-/* Define to 1 if you have the `sysconf' function. */ ++/* Define to 1 if you have the 'sysconf' function. */ + #undef HAVE_SYSCONF + + /* Define to 1 if you have the header file. */ +@@ -1329,7 +1335,7 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_SYSLOG_H + +-/* Define to 1 if you have the `system' function. */ ++/* Define to 1 if you have the 'system' function. */ + #undef HAVE_SYSTEM + + /* Define to 1 if you have the header file. */ +@@ -1344,7 +1350,7 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_SYS_DEVPOLL_H + +-/* Define to 1 if you have the header file, and it defines `DIR'. ++/* Define to 1 if you have the header file, and it defines 'DIR'. + */ + #undef HAVE_SYS_DIR_H + +@@ -1387,7 +1393,7 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_SYS_MODEM_H + +-/* Define to 1 if you have the header file, and it defines `DIR'. ++/* Define to 1 if you have the header file, and it defines 'DIR'. + */ + #undef HAVE_SYS_NDIR_H + +@@ -1463,13 +1469,13 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_SYS_XATTR_H + +-/* Define to 1 if you have the `tcgetpgrp' function. */ ++/* Define to 1 if you have the 'tcgetpgrp' function. */ + #undef HAVE_TCGETPGRP + +-/* Define to 1 if you have the `tcsetpgrp' function. */ ++/* Define to 1 if you have the 'tcsetpgrp' function. */ + #undef HAVE_TCSETPGRP + +-/* Define to 1 if you have the `tempnam' function. */ ++/* Define to 1 if you have the 'tempnam' function. */ + #undef HAVE_TEMPNAM + + /* Define to 1 if you have the header file. */ +@@ -1478,54 +1484,54 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_TERM_H + +-/* Define to 1 if you have the `timegm' function. */ ++/* Define to 1 if you have the 'timegm' function. */ + #undef HAVE_TIMEGM + + /* Define if you have the 'timerfd_create' function. */ + #undef HAVE_TIMERFD_CREATE + +-/* Define to 1 if you have the `times' function. */ ++/* Define to 1 if you have the 'times' function. */ + #undef HAVE_TIMES + +-/* Define to 1 if you have the `tmpfile' function. */ ++/* Define to 1 if you have the 'tmpfile' function. */ + #undef HAVE_TMPFILE + +-/* Define to 1 if you have the `tmpnam' function. */ ++/* Define to 1 if you have the 'tmpnam' function. */ + #undef HAVE_TMPNAM + +-/* Define to 1 if you have the `tmpnam_r' function. */ ++/* Define to 1 if you have the 'tmpnam_r' function. */ + #undef HAVE_TMPNAM_R + +-/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use +- `HAVE_STRUCT_TM_TM_ZONE' instead. */ ++/* Define to 1 if your 'struct tm' has 'tm_zone'. Deprecated, use ++ 'HAVE_STRUCT_TM_TM_ZONE' instead. */ + #undef HAVE_TM_ZONE + +-/* Define to 1 if you have the `truncate' function. */ ++/* Define to 1 if you have the 'truncate' function. */ + #undef HAVE_TRUNCATE + +-/* Define to 1 if you have the `ttyname' function. */ +-#undef HAVE_TTYNAME ++/* Define to 1 if you have the 'ttyname_r' function. */ ++#undef HAVE_TTYNAME_R + +-/* Define to 1 if you don't have `tm_zone' but do have the external array +- `tzname'. */ ++/* Define to 1 if you don't have 'tm_zone' but do have the external array ++ 'tzname'. */ + #undef HAVE_TZNAME + +-/* Define to 1 if you have the `umask' function. */ ++/* Define to 1 if you have the 'umask' function. */ + #undef HAVE_UMASK + +-/* Define to 1 if you have the `uname' function. */ ++/* Define to 1 if you have the 'uname' function. */ + #undef HAVE_UNAME + + /* Define to 1 if you have the header file. */ + #undef HAVE_UNISTD_H + +-/* Define to 1 if you have the `unlinkat' function. */ ++/* Define to 1 if you have the 'unlinkat' function. */ + #undef HAVE_UNLINKAT + +-/* Define to 1 if you have the `unlockpt' function. */ ++/* Define to 1 if you have the 'unlockpt' function. */ + #undef HAVE_UNLOCKPT + +-/* Define to 1 if you have the `unshare' function. */ ++/* Define to 1 if you have the 'unshare' function. */ + #undef HAVE_UNSHARE + + /* Define if you have a useable wchar_t type defined in wchar.h; useable means +@@ -1536,10 +1542,10 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_UTIL_H + +-/* Define to 1 if you have the `utimensat' function. */ ++/* Define to 1 if you have the 'utimensat' function. */ + #undef HAVE_UTIMENSAT + +-/* Define to 1 if you have the `utimes' function. */ ++/* Define to 1 if you have the 'utimes' function. */ + #undef HAVE_UTIMES + + /* Define to 1 if you have the header file. */ +@@ -1548,10 +1554,10 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_UTMP_H + +-/* Define to 1 if you have the `uuid_create' function. */ ++/* Define to 1 if you have the 'uuid_create' function. */ + #undef HAVE_UUID_CREATE + +-/* Define to 1 if you have the `uuid_enc_be' function. */ ++/* Define to 1 if you have the 'uuid_enc_be' function. */ + #undef HAVE_UUID_ENC_BE + + /* Define if uuid_generate_time_safe() exists. */ +@@ -1563,44 +1569,44 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_UUID_UUID_H + +-/* Define to 1 if you have the `vfork' function. */ ++/* Define to 1 if you have the 'vfork' function. */ + #undef HAVE_VFORK + +-/* Define to 1 if you have the `wait' function. */ ++/* Define to 1 if you have the 'wait' function. */ + #undef HAVE_WAIT + +-/* Define to 1 if you have the `wait3' function. */ ++/* Define to 1 if you have the 'wait3' function. */ + #undef HAVE_WAIT3 + +-/* Define to 1 if you have the `wait4' function. */ ++/* Define to 1 if you have the 'wait4' function. */ + #undef HAVE_WAIT4 + +-/* Define to 1 if you have the `waitid' function. */ ++/* Define to 1 if you have the 'waitid' function. */ + #undef HAVE_WAITID + +-/* Define to 1 if you have the `waitpid' function. */ ++/* Define to 1 if you have the 'waitpid' function. */ + #undef HAVE_WAITPID + + /* Define if the compiler provides a wchar.h header file. */ + #undef HAVE_WCHAR_H + +-/* Define to 1 if you have the `wcscoll' function. */ ++/* Define to 1 if you have the 'wcscoll' function. */ + #undef HAVE_WCSCOLL + +-/* Define to 1 if you have the `wcsftime' function. */ ++/* Define to 1 if you have the 'wcsftime' function. */ + #undef HAVE_WCSFTIME + +-/* Define to 1 if you have the `wcsxfrm' function. */ ++/* Define to 1 if you have the 'wcsxfrm' function. */ + #undef HAVE_WCSXFRM + +-/* Define to 1 if you have the `wmemcmp' function. */ ++/* Define to 1 if you have the 'wmemcmp' function. */ + #undef HAVE_WMEMCMP + + /* Define if tzset() actually switches the local timezone in a meaningful way. + */ + #undef HAVE_WORKING_TZSET + +-/* Define to 1 if you have the `writev' function. */ ++/* Define to 1 if you have the 'writev' function. */ + #undef HAVE_WRITEV + + /* Define if the zlib library has inflateCopy */ +@@ -1609,17 +1615,17 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_ZLIB_H + +-/* Define to 1 if you have the `_getpty' function. */ ++/* Define to 1 if you have the '_getpty' function. */ + #undef HAVE__GETPTY + +-/* Define to 1 if the system has the type `__uint128_t'. */ ++/* Define to 1 if the system has the type '__uint128_t'. */ + #undef HAVE___UINT128_T + +-/* Define to 1 if `major', `minor', and `makedev' are declared in . ++/* Define to 1 if 'major', 'minor', and 'makedev' are declared in . + */ + #undef MAJOR_IN_MKDEV + +-/* Define to 1 if `major', `minor', and `makedev' are declared in ++/* Define to 1 if 'major', 'minor', and 'makedev' are declared in + . */ + #undef MAJOR_IN_SYSMACROS + +@@ -1656,9 +1662,6 @@ + /* Define as the preferred size in bits of long digits */ + #undef PYLONG_BITS_IN_DIGIT + +-/* Maximum length in bytes of a thread name */ +-#undef PYTHREAD_NAME_MAXLEN +- + /* enabled builtin hash modules */ + #undef PY_BUILTIN_HASHLIB_HASHES + +@@ -1712,12 +1715,12 @@ + /* Define if you want to enable internal statistics gathering. */ + #undef Py_STATS + +-/* Define if C99-specific strftime specifiers are supported. */ +-#undef Py_STRFTIME_C99_SUPPORT +- + /* The version of SunOS/Solaris as reported by `uname -r' without the dot. */ + #undef Py_SUNOS_VERSION + ++/* Define if the C compiler supports efficient proper tail calls. */ ++#undef Py_TAIL_CALL_INTERP ++ + /* Define if you want to enable tracing references for debugging purpose */ + #undef Py_TRACE_REFS + +@@ -1730,58 +1733,58 @@ + /* Define if i>>j for signed int i does not extend the sign bit when i < 0 */ + #undef SIGNED_RIGHT_SHIFT_ZERO_FILLS + +-/* The size of `double', as computed by sizeof. */ ++/* The size of 'double', as computed by sizeof. */ + #undef SIZEOF_DOUBLE + +-/* The size of `float', as computed by sizeof. */ ++/* The size of 'float', as computed by sizeof. */ + #undef SIZEOF_FLOAT + +-/* The size of `fpos_t', as computed by sizeof. */ ++/* The size of 'fpos_t', as computed by sizeof. */ + #undef SIZEOF_FPOS_T + +-/* The size of `int', as computed by sizeof. */ ++/* The size of 'int', as computed by sizeof. */ + #undef SIZEOF_INT + +-/* The size of `long', as computed by sizeof. */ ++/* The size of 'long', as computed by sizeof. */ + #undef SIZEOF_LONG + +-/* The size of `long double', as computed by sizeof. */ ++/* The size of 'long double', as computed by sizeof. */ + #undef SIZEOF_LONG_DOUBLE + +-/* The size of `long long', as computed by sizeof. */ ++/* The size of 'long long', as computed by sizeof. */ + #undef SIZEOF_LONG_LONG + +-/* The size of `off_t', as computed by sizeof. */ ++/* The size of 'off_t', as computed by sizeof. */ + #undef SIZEOF_OFF_T + +-/* The size of `pid_t', as computed by sizeof. */ ++/* The size of 'pid_t', as computed by sizeof. */ + #undef SIZEOF_PID_T + +-/* The size of `pthread_key_t', as computed by sizeof. */ ++/* The size of 'pthread_key_t', as computed by sizeof. */ + #undef SIZEOF_PTHREAD_KEY_T + +-/* The size of `pthread_t', as computed by sizeof. */ ++/* The size of 'pthread_t', as computed by sizeof. */ + #undef SIZEOF_PTHREAD_T + +-/* The size of `short', as computed by sizeof. */ ++/* The size of 'short', as computed by sizeof. */ + #undef SIZEOF_SHORT + +-/* The size of `size_t', as computed by sizeof. */ ++/* The size of 'size_t', as computed by sizeof. */ + #undef SIZEOF_SIZE_T + +-/* The size of `time_t', as computed by sizeof. */ ++/* The size of 'time_t', as computed by sizeof. */ + #undef SIZEOF_TIME_T + +-/* The size of `uintptr_t', as computed by sizeof. */ ++/* The size of 'uintptr_t', as computed by sizeof. */ + #undef SIZEOF_UINTPTR_T + +-/* The size of `void *', as computed by sizeof. */ ++/* The size of 'void *', as computed by sizeof. */ + #undef SIZEOF_VOID_P + +-/* The size of `wchar_t', as computed by sizeof. */ ++/* The size of 'wchar_t', as computed by sizeof. */ + #undef SIZEOF_WCHAR_T + +-/* The size of `_Bool', as computed by sizeof. */ ++/* The size of '_Bool', as computed by sizeof. */ + #undef SIZEOF__BOOL + + /* Define to 1 if you have the ANSI C header files. */ +@@ -1797,13 +1800,13 @@ + /* Library needed by timemodule.c: librt may be needed for clock_gettime() */ + #undef TIMEMODULE_LIB + +-/* Define to 1 if your declares `struct tm'. */ ++/* Define to 1 if your declares 'struct tm'. */ + #undef TM_IN_SYS_TIME + + /* Define if you want to use computed gotos in ceval.c. */ + #undef USE_COMPUTED_GOTOS + +-/* Enable extensions on AIX 3, Interix. */ ++/* Enable extensions on AIX, Interix, z/OS. */ + #ifndef _ALL_SOURCE + # undef _ALL_SOURCE + #endif +@@ -1864,11 +1867,15 @@ + #ifndef __STDC_WANT_IEC_60559_DFP_EXT__ + # undef __STDC_WANT_IEC_60559_DFP_EXT__ + #endif ++/* Enable extensions specified by C23 Annex F. */ ++#ifndef __STDC_WANT_IEC_60559_EXT__ ++# undef __STDC_WANT_IEC_60559_EXT__ ++#endif + /* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ + #ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ + # undef __STDC_WANT_IEC_60559_FUNCS_EXT__ + #endif +-/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */ ++/* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015. */ + #ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ + # undef __STDC_WANT_IEC_60559_TYPES_EXT__ + #endif +@@ -1973,6 +1980,9 @@ + /* framework name */ + #undef _PYTHONFRAMEWORK + ++/* Maximum length in bytes of a thread name */ ++#undef _PYTHREAD_NAME_MAXLEN ++ + /* Define to force use of thread-safe errno, h_errno, and other functions */ + #undef _REENTRANT + +@@ -1997,16 +2007,16 @@ + /* Define to 'long' if does not define clock_t. */ + #undef clock_t + +-/* Define to empty if `const' does not conform to ANSI C. */ ++/* Define to empty if 'const' does not conform to ANSI C. */ + #undef const + +-/* Define to `int' if doesn't define. */ ++/* Define as 'int' if doesn't define. */ + #undef gid_t + +-/* Define to `int' if does not define. */ ++/* Define to 'int' if does not define. */ + #undef mode_t + +-/* Define to `long int' if does not define. */ ++/* Define to 'long int' if does not define. */ + #undef off_t + + /* Define as a signed integer type capable of holding a process identifier. */ +@@ -2015,13 +2025,13 @@ + /* Define to empty if the keyword does not work. */ + #undef signed + +-/* Define to `unsigned int' if does not define. */ ++/* Define as 'unsigned int' if doesn't define. */ + #undef size_t + + /* Define to 'int' if does not define. */ + #undef socklen_t + +-/* Define to `int' if doesn't define. */ ++/* Define as 'int' if doesn't define. */ + #undef uid_t + + --- /dev/null +++ b/tvOS/README.rst @@ -0,0 +1,108 @@ diff --git a/patch/Python/diff.exclude b/patch/Python/diff.exclude index f5c3faae..da24a271 100644 --- a/patch/Python/diff.exclude +++ b/patch/Python/diff.exclude @@ -3,4 +3,6 @@ .gitignore .mention-bot .travis.yml +PCbuild/* +Doc/* Misc/NEWS.d/* \ No newline at end of file diff --git a/patch/Python/sitecustomize.iOS.py b/patch/Python/sitecustomize.iOS.py index ccc291f3..48c464ab 100644 --- a/patch/Python/sitecustomize.iOS.py +++ b/patch/Python/sitecustomize.iOS.py @@ -20,11 +20,11 @@ def custom_system(): # Make platform.ios_ver() return an appropriate namedtuple IOSVersionInfo = collections.namedtuple( "IOSVersionInfo", - ["system", "release", "model", "is_simulator"] + ["system", "release", "model", "is_simulator", "abi"] ) -def custom_ios_ver(system="", release="", model="", is_simulator=False): - return IOSVersionInfo("{{os}}", "{{version_min}}", "iPhone", {{is_simulator}}) +def custom_ios_ver(system="", release="", model="", is_simulator=False, abi=""): + return IOSVersionInfo("{{os}}", "{{version_min}}", "iPhone", {{is_simulator}}, "{{abi}}") platform.ios_ver = custom_ios_ver From f85e613137b830697809e021c853595967487dd9 Mon Sep 17 00:00:00 2001 From: Andrew Savva Date: Sat, 8 Mar 2025 18:41:46 +0000 Subject: [PATCH 02/10] Add Mac Catalyst support --- patch/Python/Python.patch | 170322 +---------------------------------- 1 file changed, 1641 insertions(+), 168681 deletions(-) diff --git a/patch/Python/Python.patch b/patch/Python/Python.patch index 14d6134f..c1c0196a 100644 --- a/patch/Python/Python.patch +++ b/patch/Python/Python.patch @@ -1,168826 +1,1786 @@ -diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml -index 107f3b25573..fb44c27704d 100644 ---- a/.pre-commit-config.yaml -+++ b/.pre-commit-config.yaml -@@ -1,6 +1,6 @@ - repos: - - repo: https://github.com/astral-sh/ruff-pre-commit -- rev: v0.8.2 -+ rev: v0.9.1 - hooks: - - id: ruff - name: Run Ruff (lint) on Doc/ -@@ -29,12 +29,10 @@ - - id: black - name: Run Black on Tools/build/check_warnings.py - files: ^Tools/build/check_warnings.py -- language_version: python3.12 - args: [--line-length=79] - - id: black - name: Run Black on Tools/jit/ - files: ^Tools/jit/ -- language_version: python3.12 - - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 -@@ -51,18 +49,19 @@ - types_or: [c, inc, python, rst] - - - repo: https://github.com/python-jsonschema/check-jsonschema -- rev: 0.30.0 -+ rev: 0.31.0 - hooks: - - id: check-dependabot - - id: check-github-workflows -+ - id: check-readthedocs - - - repo: https://github.com/rhysd/actionlint -- rev: v1.7.4 -+ rev: v1.7.7 - hooks: - - id: actionlint - - - repo: https://github.com/woodruffw/zizmor-pre-commit -- rev: v0.8.0 -+ rev: v1.1.1 - hooks: - - id: zizmor - -diff --git a/Android/android-env.sh b/Android/android-env.sh -index a0f23ef8c9f..bab4130c9e9 100644 ---- a/Android/android-env.sh -+++ b/Android/android-env.sh -@@ -1,10 +1,10 @@ - # This script must be sourced with the following variables already set: --: ${ANDROID_HOME:?} # Path to Android SDK --: ${HOST:?} # GNU target triplet -+: "${ANDROID_HOME:?}" # Path to Android SDK -+: "${HOST:?}" # GNU target triplet - - # You may also override the following: --: ${api_level:=24} # Minimum Android API level the build will run on --: ${PREFIX:-} # Path in which to find required libraries -+: "${api_level:=24}" # Minimum Android API level the build will run on -+: "${PREFIX:-}" # Path in which to find required libraries - - - # Print all messages on stderr so they're visible when running within build-wheel. -@@ -27,20 +27,20 @@ - ndk_version=27.1.12297006 - - ndk=$ANDROID_HOME/ndk/$ndk_version --if ! [ -e $ndk ]; then -+if ! [ -e "$ndk" ]; then - log "Installing NDK - this may take several minutes" -- yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager "ndk;$ndk_version" -+ yes | "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" "ndk;$ndk_version" - fi - --if [ $HOST = "arm-linux-androideabi" ]; then -+if [ "$HOST" = "arm-linux-androideabi" ]; then - clang_triplet=armv7a-linux-androideabi - else -- clang_triplet=$HOST -+ clang_triplet="$HOST" - fi - - # These variables are based on BuildSystemMaintainers.md above, and - # $ndk/build/cmake/android.toolchain.cmake. --toolchain=$(echo $ndk/toolchains/llvm/prebuilt/*) -+toolchain=$(echo "$ndk"/toolchains/llvm/prebuilt/*) - export AR="$toolchain/bin/llvm-ar" - export AS="$toolchain/bin/llvm-as" - export CC="$toolchain/bin/${clang_triplet}${api_level}-clang" -@@ -72,12 +72,12 @@ - - # -mstackrealign is included where necessary in the clang launcher scripts which are - # pointed to by $CC, so we don't need to include it here. --if [ $HOST = "arm-linux-androideabi" ]; then -+if [ "$HOST" = "arm-linux-androideabi" ]; then - CFLAGS="$CFLAGS -march=armv7-a -mthumb" - fi - - if [ -n "${PREFIX:-}" ]; then -- abs_prefix=$(realpath $PREFIX) -+ abs_prefix="$(realpath "$PREFIX")" - CFLAGS="$CFLAGS -I$abs_prefix/include" - LDFLAGS="$LDFLAGS -L$abs_prefix/lib" - -@@ -87,11 +87,13 @@ - - # When compiling C++, some build systems will combine CFLAGS and CXXFLAGS, and some will - # use CXXFLAGS alone. --export CXXFLAGS=$CFLAGS -+export CXXFLAGS="$CFLAGS" - - # Use the same variable name as conda-build --if [ $(uname) = "Darwin" ]; then -- export CPU_COUNT=$(sysctl -n hw.ncpu) -+if [ "$(uname)" = "Darwin" ]; then -+ CPU_COUNT="$(sysctl -n hw.ncpu)" -+ export CPU_COUNT - else -- export CPU_COUNT=$(nproc) -+ CPU_COUNT="$(nproc)" -+ export CPU_COUNT - fi -diff --git a/Include/abstract.h b/Include/abstract.h -index 7cfee1332cc..4efe4fcb014 100644 ---- a/Include/abstract.h -+++ b/Include/abstract.h -@@ -726,31 +726,6 @@ - This is equivalent to the Python expression: list(o) */ - PyAPI_FUNC(PyObject *) PySequence_List(PyObject *o); - --/* Return the sequence 'o' as a list, unless it's already a tuple or list. -- -- Use PySequence_Fast_GET_ITEM to access the members of this list, and -- PySequence_Fast_GET_SIZE to get its length. -- -- Returns NULL on failure. If the object does not support iteration, raises a -- TypeError exception with 'm' as the message text. */ --PyAPI_FUNC(PyObject *) PySequence_Fast(PyObject *o, const char* m); -- --/* Return the size of the sequence 'o', assuming that 'o' was returned by -- PySequence_Fast and is not NULL. */ --#define PySequence_Fast_GET_SIZE(o) \ -- (PyList_Check(o) ? PyList_GET_SIZE(o) : PyTuple_GET_SIZE(o)) -- --/* Return the 'i'-th element of the sequence 'o', assuming that o was returned -- by PySequence_Fast, and that i is within bounds. */ --#define PySequence_Fast_GET_ITEM(o, i)\ -- (PyList_Check(o) ? PyList_GET_ITEM((o), (i)) : PyTuple_GET_ITEM((o), (i))) -- --/* Return a pointer to the underlying item array for -- an object returned by PySequence_Fast */ --#define PySequence_Fast_ITEMS(sf) \ -- (PyList_Check(sf) ? ((PyListObject *)(sf))->ob_item \ -- : ((PyTupleObject *)(sf))->ob_item) -- - /* Return the number of occurrences on value on 'o', that is, return - the number of keys for which o[key] == value. - -diff --git a/Include/cpython/abstract.h b/Include/cpython/abstract.h -index 4e7b7a46703..8fed1d31109 100644 ---- a/Include/cpython/abstract.h -+++ b/Include/cpython/abstract.h -@@ -85,3 +85,29 @@ - need to be corrected for a negative index. */ - #define PySequence_ITEM(o, i)\ - ( Py_TYPE(o)->tp_as_sequence->sq_item((o), (i)) ) -+ -+/* Return the sequence 'o' as a list, unless it's already a tuple or list. -+ -+ Use PySequence_Fast_GET_ITEM to access the members of this list, and -+ PySequence_Fast_GET_SIZE to get its length. -+ -+ Returns NULL on failure. If the object does not support iteration, raises a -+ TypeError exception with 'm' as the message text. */ -+PyAPI_FUNC(PyObject *) PySequence_Fast(PyObject *o, const char* m); -+ -+/* Return the size of the sequence 'o', assuming that 'o' was returned by -+ PySequence_Fast and is not NULL. */ -+#define PySequence_Fast_GET_SIZE(o) \ -+ (PyList_Check(o) ? PyList_GET_SIZE(o) : PyTuple_GET_SIZE(o)) -+ -+/* Return the 'i'-th element of the sequence 'o', assuming that o was returned -+ by PySequence_Fast, and that i is within bounds. */ -+#define PySequence_Fast_GET_ITEM(o, i)\ -+ (PyList_Check(o) ? PyList_GET_ITEM((o), (i)) : PyTuple_GET_ITEM((o), (i))) -+ -+/* Return a pointer to the underlying item array for -+ an object returned by PySequence_Fast */ -+#define PySequence_Fast_ITEMS(sf) \ -+ (PyList_Check(sf) ? ((PyListObject *)(sf))->ob_item \ -+ : ((PyTupleObject *)(sf))->ob_item) -+ -diff --git a/Include/cpython/bytesobject.h b/Include/cpython/bytesobject.h -index cf3f0387ecf..71c133f173f 100644 ---- a/Include/cpython/bytesobject.h -+++ b/Include/cpython/bytesobject.h -@@ -34,5 +34,9 @@ - - PyAPI_FUNC(PyObject*) PyBytes_Join(PyObject *sep, PyObject *iterable); - --// Alias kept for backward compatibility --#define _PyBytes_Join PyBytes_Join -+// Deprecated alias kept for backward compatibility -+Py_DEPRECATED(3.14) static inline PyObject* -+_PyBytes_Join(PyObject *sep, PyObject *iterable) -+{ -+ return PyBytes_Join(sep, iterable); -+} -diff --git a/Include/cpython/code.h b/Include/cpython/code.h -index 3899d426923..2bd3e08631f 100644 ---- a/Include/cpython/code.h -+++ b/Include/cpython/code.h -@@ -11,11 +11,11 @@ - /* Total tool ids available */ - #define _PY_MONITORING_TOOL_IDS 8 - /* Count of all local monitoring events */ --#define _PY_MONITORING_LOCAL_EVENTS 10 -+#define _PY_MONITORING_LOCAL_EVENTS 11 - /* Count of all "real" monitoring events (not derived from other events) */ --#define _PY_MONITORING_UNGROUPED_EVENTS 15 -+#define _PY_MONITORING_UNGROUPED_EVENTS 16 - /* Count of all monitoring events */ --#define _PY_MONITORING_EVENTS 17 -+#define _PY_MONITORING_EVENTS 19 - - /* Tables of which tools are active for each monitored event. */ - typedef struct _Py_LocalMonitors { -@@ -35,11 +35,12 @@ - } _PyCoCached; - - /* Ancillary data structure used for instrumentation. -- Line instrumentation creates an array of -- these. One entry per code unit.*/ -+ Line instrumentation creates this with sufficient -+ space for one entry per code unit. The total size -+ of the data will be `bytes_per_entry * Py_SIZE(code)` */ - typedef struct { -- uint8_t original_opcode; -- int8_t line_delta; -+ uint8_t bytes_per_entry; -+ uint8_t data[1]; - } _PyCoLineInstrumentationData; - - -@@ -199,6 +200,9 @@ - */ - #define CO_HAS_DOCSTRING 0x4000000 - -+/* A function defined in class scope */ -+#define CO_METHOD 0x8000000 -+ - /* This should be defined if a future statement modifies the syntax. - For example, when a keyword is added. - */ -diff --git a/Include/cpython/dictobject.h b/Include/cpython/dictobject.h -index 78473e54898..df9ec7050fc 100644 ---- a/Include/cpython/dictobject.h -+++ b/Include/cpython/dictobject.h -@@ -68,7 +68,12 @@ - - PyAPI_FUNC(int) PyDict_Pop(PyObject *dict, PyObject *key, PyObject **result); - PyAPI_FUNC(int) PyDict_PopString(PyObject *dict, const char *key, PyObject **result); --PyAPI_FUNC(PyObject *) _PyDict_Pop(PyObject *dict, PyObject *key, PyObject *default_value); -+ -+// Use PyDict_Pop() instead -+Py_DEPRECATED(3.14) PyAPI_FUNC(PyObject *) _PyDict_Pop( -+ PyObject *dict, -+ PyObject *key, -+ PyObject *default_value); - - /* Dictionary watchers */ - -diff --git a/Include/cpython/fileutils.h b/Include/cpython/fileutils.h -index b386ad107bd..626b1ad57b3 100644 ---- a/Include/cpython/fileutils.h -+++ b/Include/cpython/fileutils.h -@@ -2,7 +2,15 @@ - # error "this header file must not be included directly" - #endif - --// Used by _testcapi which must not use the internal C API --PyAPI_FUNC(FILE*) _Py_fopen_obj( -+PyAPI_FUNC(FILE*) Py_fopen( - PyObject *path, - const char *mode); -+ -+// Deprecated alias kept for backward compatibility -+Py_DEPRECATED(3.14) static inline FILE* -+_Py_fopen_obj(PyObject *path, const char *mode) -+{ -+ return Py_fopen(path, mode); -+} -+ -+PyAPI_FUNC(int) Py_fclose(FILE *file); -diff --git a/Include/cpython/import.h b/Include/cpython/import.h -index 7daf0b84fcf..0ce0b1ee6cc 100644 ---- a/Include/cpython/import.h -+++ b/Include/cpython/import.h -@@ -2,8 +2,6 @@ - # error "this header file must not be included directly" - #endif - --PyMODINIT_FUNC PyInit__imp(void); -- - struct _inittab { - const char *name; /* ASCII encoded string */ - PyObject* (*initfunc)(void); -@@ -23,3 +21,10 @@ - collection of frozen modules: */ - - PyAPI_DATA(const struct _frozen *) PyImport_FrozenModules; -+ -+PyAPI_FUNC(PyObject*) PyImport_ImportModuleAttr( -+ PyObject *mod_name, -+ PyObject *attr_name); -+PyAPI_FUNC(PyObject*) PyImport_ImportModuleAttrString( -+ const char *mod_name, -+ const char *attr_name); -diff --git a/Include/cpython/longintrepr.h b/Include/cpython/longintrepr.h -index 357477b60d9..4b6f97a5e47 100644 ---- a/Include/cpython/longintrepr.h -+++ b/Include/cpython/longintrepr.h -@@ -76,8 +76,8 @@ - - 1: Zero - - 2: Negative - -- The third lowest bit of lv_tag is reserved for an immortality flag, but is -- not currently used. -+ The third lowest bit of lv_tag is -+ set to 1 for the small ints. - - In a normalized number, ob_digit[ndigits-1] (the most significant - digit) is never zero. Also, in all cases, for all valid i, -@@ -100,12 +100,12 @@ - _PyLongValue long_value; - }; - --PyAPI_FUNC(PyLongObject*) _PyLong_New(Py_ssize_t); -+Py_DEPRECATED(3.14) PyAPI_FUNC(PyLongObject*) _PyLong_New(Py_ssize_t); - - // Return a copy of src. - PyAPI_FUNC(PyObject*) _PyLong_Copy(PyLongObject *src); - --PyAPI_FUNC(PyLongObject*) _PyLong_FromDigits( -+Py_DEPRECATED(3.14) PyAPI_FUNC(PyLongObject*) _PyLong_FromDigits( - int negative, - Py_ssize_t digit_count, - digit *digits); -diff --git a/Include/cpython/longobject.h b/Include/cpython/longobject.h -index 4d6e618f831..7f28ad60b74 100644 ---- a/Include/cpython/longobject.h -+++ b/Include/cpython/longobject.h -@@ -86,7 +86,7 @@ - - On failure, set an exception, and return -1. */ - PyAPI_FUNC(int) PyLong_GetSign(PyObject *v, int *sign); - --PyAPI_FUNC(int) _PyLong_Sign(PyObject *v); -+Py_DEPRECATED(3.14) PyAPI_FUNC(int) _PyLong_Sign(PyObject *v); - - /* _PyLong_NumBits. Return the number of bits needed to represent the - absolute value of a long. For example, this returns 1 for 1 and -1, 2 -diff --git a/Include/cpython/monitoring.h b/Include/cpython/monitoring.h -index 797ba51246b..ce92942404c 100644 ---- a/Include/cpython/monitoring.h -+++ b/Include/cpython/monitoring.h -@@ -13,25 +13,27 @@ - #define PY_MONITORING_EVENT_LINE 5 - #define PY_MONITORING_EVENT_INSTRUCTION 6 - #define PY_MONITORING_EVENT_JUMP 7 --#define PY_MONITORING_EVENT_BRANCH 8 --#define PY_MONITORING_EVENT_STOP_ITERATION 9 -+#define PY_MONITORING_EVENT_BRANCH_LEFT 8 -+#define PY_MONITORING_EVENT_BRANCH_RIGHT 9 -+#define PY_MONITORING_EVENT_STOP_ITERATION 10 - - #define PY_MONITORING_IS_INSTRUMENTED_EVENT(ev) \ - ((ev) < _PY_MONITORING_LOCAL_EVENTS) - - /* Other events, mainly exceptions */ - --#define PY_MONITORING_EVENT_RAISE 10 --#define PY_MONITORING_EVENT_EXCEPTION_HANDLED 11 --#define PY_MONITORING_EVENT_PY_UNWIND 12 --#define PY_MONITORING_EVENT_PY_THROW 13 --#define PY_MONITORING_EVENT_RERAISE 14 -+#define PY_MONITORING_EVENT_RAISE 11 -+#define PY_MONITORING_EVENT_EXCEPTION_HANDLED 12 -+#define PY_MONITORING_EVENT_PY_UNWIND 13 -+#define PY_MONITORING_EVENT_PY_THROW 14 -+#define PY_MONITORING_EVENT_RERAISE 15 - - - /* Ancillary events */ - --#define PY_MONITORING_EVENT_C_RETURN 15 --#define PY_MONITORING_EVENT_C_RAISE 16 -+#define PY_MONITORING_EVENT_C_RETURN 16 -+#define PY_MONITORING_EVENT_C_RAISE 17 -+#define PY_MONITORING_EVENT_BRANCH 18 - - - typedef struct _PyMonitoringState { -@@ -74,10 +76,18 @@ - _PyMonitoring_FireJumpEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, - PyObject *target_offset); - --PyAPI_FUNC(int) -+Py_DEPRECATED(3.14) PyAPI_FUNC(int) - _PyMonitoring_FireBranchEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, - PyObject *target_offset); - -+PyAPI_FUNC(int) -+_PyMonitoring_FireBranchRightEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, -+ PyObject *target_offset); -+ -+PyAPI_FUNC(int) -+_PyMonitoring_FireBranchLeftEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, -+ PyObject *target_offset); -+ - PyAPI_FUNC(int) - _PyMonitoring_FireCReturnEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, - PyObject *retval); -@@ -174,12 +184,21 @@ - } - - static inline int --PyMonitoring_FireBranchEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, -+PyMonitoring_FireBranchRightEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, -+ PyObject *target_offset) -+{ -+ _PYMONITORING_IF_ACTIVE( -+ state, -+ _PyMonitoring_FireBranchRightEvent(state, codelike, offset, target_offset)); -+} -+ -+static inline int -+PyMonitoring_FireBranchLeftEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, - PyObject *target_offset) - { - _PYMONITORING_IF_ACTIVE( - state, -- _PyMonitoring_FireBranchEvent(state, codelike, offset, target_offset)); -+ _PyMonitoring_FireBranchLeftEvent(state, codelike, offset, target_offset)); - } - - static inline int -diff --git a/Include/cpython/object.h b/Include/cpython/object.h -index e4797029da4..71bd0188442 100644 ---- a/Include/cpython/object.h -+++ b/Include/cpython/object.h -@@ -221,7 +221,9 @@ - PyObject *tp_weaklist; /* not used for static builtin types */ - destructor tp_del; - -- /* Type attribute cache version tag. Added in version 2.6 */ -+ /* Type attribute cache version tag. Added in version 2.6. -+ * If zero, the cache is invalid and must be initialized. -+ */ - unsigned int tp_version_tag; - - destructor tp_finalize; -@@ -229,9 +231,17 @@ - - /* bitset of which type-watchers care about this type */ - unsigned char tp_watched; -+ -+ /* Number of tp_version_tag values used. -+ * Set to _Py_ATTR_CACHE_UNUSED if the attribute cache is -+ * disabled for this type (e.g. due to custom MRO entries). -+ * Otherwise, limited to MAX_VERSIONS_PER_CLASS (defined elsewhere). -+ */ - uint16_t tp_versions_used; - }; - -+#define _Py_ATTR_CACHE_UNUSED (30000) // (see tp_versions_used) -+ - /* This struct is used by the specializer - * It should be treated as an opaque blob - * by code other than the specializer and interpreter. */ -@@ -465,9 +475,6 @@ - passed as second argument to Py_TRASHCAN_BEGIN(). - */ - --/* Python 3.9 private API, invoked by the macros below. */ --PyAPI_FUNC(int) _PyTrash_begin(PyThreadState *tstate, PyObject *op); --PyAPI_FUNC(void) _PyTrash_end(PyThreadState *tstate); - - PyAPI_FUNC(void) _PyTrash_thread_deposit_object(PyThreadState *tstate, PyObject *op); - PyAPI_FUNC(void) _PyTrash_thread_destroy_chain(PyThreadState *tstate); -@@ -534,3 +541,12 @@ - * 0 if the runtime ignored it. This function cannot fail. - */ - PyAPI_FUNC(int) PyUnstable_Object_EnableDeferredRefcount(PyObject *); -+ -+/* Check whether the object is immortal. This cannot fail. */ -+PyAPI_FUNC(int) PyUnstable_IsImmortal(PyObject *); -+ -+// Increments the reference count of the object, if it's not zero. -+// PyUnstable_EnableTryIncRef() should be called on the object -+// before calling this function in order to avoid spurious failures. -+PyAPI_FUNC(int) PyUnstable_TryIncRef(PyObject *); -+PyAPI_FUNC(void) PyUnstable_EnableTryIncRef(PyObject *); -diff --git a/Include/cpython/pyatomic.h b/Include/cpython/pyatomic.h -index 6d106c1b499..2a0c11e7b3a 100644 ---- a/Include/cpython/pyatomic.h -+++ b/Include/cpython/pyatomic.h -@@ -574,15 +574,15 @@ - - #if _Py_USE_GCC_BUILTIN_ATOMICS - # define Py_ATOMIC_GCC_H --# include "cpython/pyatomic_gcc.h" -+# include "pyatomic_gcc.h" - # undef Py_ATOMIC_GCC_H - #elif __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__) - # define Py_ATOMIC_STD_H --# include "cpython/pyatomic_std.h" -+# include "pyatomic_std.h" - # undef Py_ATOMIC_STD_H - #elif defined(_MSC_VER) - # define Py_ATOMIC_MSC_H --# include "cpython/pyatomic_msc.h" -+# include "pyatomic_msc.h" - # undef Py_ATOMIC_MSC_H - #else - # error "no available pyatomic implementation for this platform/compiler" -diff --git a/Include/cpython/pyhash.h b/Include/cpython/pyhash.h -index 876a7f0ea44..a33ba10b8d3 100644 ---- a/Include/cpython/pyhash.h -+++ b/Include/cpython/pyhash.h -@@ -29,9 +29,6 @@ - /* Helpers for hash functions */ - PyAPI_FUNC(Py_hash_t) _Py_HashDouble(PyObject *, double); - --// Kept for backward compatibility --#define _Py_HashPointer Py_HashPointer -- - - /* hash function definition */ - typedef struct { -@@ -44,6 +41,14 @@ - PyAPI_FUNC(PyHash_FuncDef*) PyHash_GetFuncDef(void); - - PyAPI_FUNC(Py_hash_t) Py_HashPointer(const void *ptr); -+ -+// Deprecated alias kept for backward compatibility -+Py_DEPRECATED(3.14) static inline Py_hash_t -+_Py_HashPointer(const void *ptr) -+{ -+ return Py_HashPointer(ptr); -+} -+ - PyAPI_FUNC(Py_hash_t) PyObject_GenericHash(PyObject *); - - PyAPI_FUNC(Py_hash_t) Py_HashBuffer(const void *ptr, Py_ssize_t len); -diff --git a/Include/cpython/pylifecycle.h b/Include/cpython/pylifecycle.h -index e46dfe59ec4..86ce6e6f798 100644 ---- a/Include/cpython/pylifecycle.h -+++ b/Include/cpython/pylifecycle.h -@@ -25,9 +25,6 @@ - PyAPI_FUNC(PyStatus) Py_InitializeFromConfig( - const PyConfig *config); - --// Python 3.8 provisional API (PEP 587) --PyAPI_FUNC(PyStatus) _Py_InitializeMain(void); -- - PyAPI_FUNC(int) Py_RunMain(void); - - -diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h -index 32f68378ea5..cd6d9582496 100644 ---- a/Include/cpython/pystate.h -+++ b/Include/cpython/pystate.h -@@ -239,8 +239,12 @@ - * if it is NULL. */ - PyAPI_FUNC(PyThreadState *) PyThreadState_GetUnchecked(void); - --// Alias kept for backward compatibility --#define _PyThreadState_UncheckedGet PyThreadState_GetUnchecked -+// Deprecated alias kept for backward compatibility -+Py_DEPRECATED(3.14) static inline PyThreadState* -+_PyThreadState_UncheckedGet(void) -+{ -+ return PyThreadState_GetUnchecked(); -+} - - - // Disable tracing and profiling. -diff --git a/Include/cpython/pystats.h b/Include/cpython/pystats.h -index 29ef0c0e4d4..4421b4d6e91 100644 ---- a/Include/cpython/pystats.h -+++ b/Include/cpython/pystats.h -@@ -31,7 +31,7 @@ - - #define PYSTATS_MAX_UOP_ID 512 - --#define SPECIALIZATION_FAILURE_KINDS 36 -+#define SPECIALIZATION_FAILURE_KINDS 37 - - /* Stats for determining who is calling PyEval_EvalFrame */ - #define EVAL_CALL_TOTAL 0 -@@ -129,6 +129,7 @@ - uint64_t inner_loop; - uint64_t recursive_call; - uint64_t low_confidence; -+ uint64_t unknown_callee; - uint64_t executors_invalidated; - UOpStats opcode[PYSTATS_MAX_UOP_ID + 1]; - uint64_t unsupported_opcode[256]; -@@ -141,6 +142,14 @@ - uint64_t remove_globals_builtins_changed; - uint64_t remove_globals_incorrect_keys; - uint64_t error_in_opcode[PYSTATS_MAX_UOP_ID + 1]; -+ // JIT memory stats -+ uint64_t jit_total_memory_size; -+ uint64_t jit_code_size; -+ uint64_t jit_trampoline_size; -+ uint64_t jit_data_size; -+ uint64_t jit_padding_size; -+ uint64_t jit_freed_memory_size; -+ uint64_t trace_total_memory_hist[_Py_UOP_HIST_SIZE]; - } OptimizationStats; - - typedef struct _rare_event_stats { -diff --git a/Include/cpython/pythread.h b/Include/cpython/pythread.h -index 03f710a9f7e..e658b35bd90 100644 ---- a/Include/cpython/pythread.h -+++ b/Include/cpython/pythread.h -@@ -22,7 +22,7 @@ - */ - # define NATIVE_TSS_KEY_T unsigned long - #elif defined(HAVE_PTHREAD_STUBS) --# include "cpython/pthread_stubs.h" -+# include "pthread_stubs.h" - # define NATIVE_TSS_KEY_T pthread_key_t - #else - # error "Require native threads. See https://bugs.python.org/issue31370" -diff --git a/Include/cpython/unicodeobject.h b/Include/cpython/unicodeobject.h -index 91799137101..cea69dd1280 100644 ---- a/Include/cpython/unicodeobject.h -+++ b/Include/cpython/unicodeobject.h -@@ -109,7 +109,7 @@ - 3: Interned, Immortal, and Static - This categorization allows the runtime to determine the right - cleanup mechanism at runtime shutdown. */ -- unsigned int interned:2; -+ uint16_t interned; - /* Character size: - - - PyUnicode_1BYTE_KIND (1): -@@ -132,21 +132,23 @@ - * all characters are in the range U+0000-U+10FFFF - * at least one character is in the range U+10000-U+10FFFF - */ -- unsigned int kind:3; -+ unsigned short kind:3; - /* Compact is with respect to the allocation scheme. Compact unicode - objects only require one memory block while non-compact objects use - one block for the PyUnicodeObject struct and another for its data - buffer. */ -- unsigned int compact:1; -+ unsigned short compact:1; - /* The string only contains characters in the range U+0000-U+007F (ASCII) - and the kind is PyUnicode_1BYTE_KIND. If ascii is set and compact is - set, use the PyASCIIObject structure. */ -- unsigned int ascii:1; -+ unsigned short ascii:1; - /* The object is statically allocated. */ -- unsigned int statically_allocated:1; -+ unsigned short statically_allocated:1; - /* Padding to ensure that PyUnicode_DATA() is always aligned to -- 4 bytes (see issue #19537 on m68k). */ -- unsigned int :24; -+ 4 bytes (see issue #19537 on m68k) and we use unsigned short to avoid -+ the extra four bytes on 32-bit Windows. This is restricted features -+ for specific compilers including GCC, MSVC, Clang and IBM's XL compiler. */ -+ unsigned short :10; - } state; - } PyASCIIObject; - -@@ -195,7 +197,11 @@ - - /* Use only if you know it's a string */ - static inline unsigned int PyUnicode_CHECK_INTERNED(PyObject *op) { -+#ifdef Py_GIL_DISABLED -+ return _Py_atomic_load_uint16_relaxed(&_PyASCIIObject_CAST(op)->state.interned); -+#else - return _PyASCIIObject_CAST(op)->state.interned; -+#endif - } - #define PyUnicode_CHECK_INTERNED(op) PyUnicode_CHECK_INTERNED(_PyObject_CAST(op)) - -@@ -234,6 +240,8 @@ - PyUnicode_4BYTE_KIND = 4 - }; +diff --git a/Lib/platform.py b/Lib/platform.py +index 1f6baed66d3..235dd98c60a 100644 +--- a/Lib/platform.py ++++ b/Lib/platform.py +@@ -521,6 +521,54 @@ + return IOSVersionInfo(system, release, model, is_simulator) -+PyAPI_FUNC(int) PyUnicode_KIND(PyObject *op); -+ - // PyUnicode_KIND(): Return one of the PyUnicode_*_KIND values defined above. - // - // gh-89653: Converting this macro to a static inline function would introduce -@@ -258,13 +266,15 @@ - return data; - } --static inline void* PyUnicode_DATA(PyObject *op) { -+PyAPI_FUNC(void*) PyUnicode_DATA(PyObject *op); ++# A namedtuple for tvOS version information. ++TVOSVersionInfo = collections.namedtuple( ++ "TVOSVersionInfo", ++ ["system", "release", "model", "is_simulator"] ++) + -+static inline void* _PyUnicode_DATA(PyObject *op) { - if (PyUnicode_IS_COMPACT(op)) { - return _PyUnicode_COMPACT_DATA(op); - } - return _PyUnicode_NONCOMPACT_DATA(op); - } --#define PyUnicode_DATA(op) PyUnicode_DATA(_PyObject_CAST(op)) -+#define PyUnicode_DATA(op) _PyUnicode_DATA(_PyObject_CAST(op)) - - /* Return pointers to the canonical representation cast to unsigned char, - Py_UCS2, or Py_UCS4 for direct character access. -@@ -624,8 +634,12 @@ - - PyAPI_FUNC(const char *) PyUnicode_AsUTF8(PyObject *unicode); - --// Alias kept for backward compatibility --#define _PyUnicode_AsString PyUnicode_AsUTF8 -+// Deprecated alias kept for backward compatibility -+Py_DEPRECATED(3.14) static inline const char* -+_PyUnicode_AsString(PyObject *unicode) -+{ -+ return PyUnicode_AsUTF8(unicode); -+} - - - /* === Characters Type APIs =============================================== */ -diff --git a/Include/cpython/weakrefobject.h b/Include/cpython/weakrefobject.h -index 9aa1a92c413..da8e77cddac 100644 ---- a/Include/cpython/weakrefobject.h -+++ b/Include/cpython/weakrefobject.h -@@ -45,6 +45,9 @@ - #define _PyWeakref_CAST(op) \ - (assert(PyWeakref_Check(op)), _Py_CAST(PyWeakReference*, (op))) - -+// Test if a weak reference is dead. -+PyAPI_FUNC(int) PyWeakref_IsDead(PyObject *ref); + - Py_DEPRECATED(3.13) static inline PyObject* PyWeakref_GET_OBJECT(PyObject *ref_obj) - { - PyWeakReference *ref = _PyWeakref_CAST(ref_obj); -diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h -index 80bd19a8878..fea8665ae39 100644 ---- a/Include/internal/pycore_ceval.h -+++ b/Include/internal/pycore_ceval.h -@@ -264,7 +264,7 @@ - - PyAPI_FUNC(int) _PyEval_CheckExceptStarTypeValid(PyThreadState *tstate, PyObject* right); - PyAPI_FUNC(int) _PyEval_CheckExceptTypeValid(PyThreadState *tstate, PyObject* right); --PyAPI_FUNC(int) _PyEval_ExceptionGroupMatch(PyObject* exc_value, PyObject *match_type, PyObject **match, PyObject **rest); -+PyAPI_FUNC(int) _PyEval_ExceptionGroupMatch(_PyInterpreterFrame *, PyObject* exc_value, PyObject *match_type, PyObject **match, PyObject **rest); - PyAPI_FUNC(void) _PyEval_FormatAwaitableError(PyThreadState *tstate, PyTypeObject *type, int oparg); - PyAPI_FUNC(void) _PyEval_FormatExcCheckArg(PyThreadState *tstate, PyObject *exc, const char *format_str, PyObject *obj); - PyAPI_FUNC(void) _PyEval_FormatExcUnbound(PyThreadState *tstate, PyCodeObject *co, int oparg); -diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h -index d607a54aa4a..6d45d5f0c40 100644 ---- a/Include/internal/pycore_code.h -+++ b/Include/internal/pycore_code.h -@@ -100,6 +100,7 @@ - - typedef struct { - _Py_BackoffCounter counter; -+ uint16_t external_cache[4]; - } _PyBinaryOpCache; - - #define INLINE_CACHE_ENTRIES_BINARY_OP CACHE_ENTRIES(_PyBinaryOpCache) -@@ -337,8 +338,6 @@ - PyObject *name); - extern void _Py_Specialize_LoadGlobal(PyObject *globals, PyObject *builtins, - _Py_CODEUNIT *instr, PyObject *name); --extern void _Py_Specialize_BinarySubscr(_PyStackRef sub, _PyStackRef container, -- _Py_CODEUNIT *instr); - extern void _Py_Specialize_StoreSubscr(_PyStackRef container, _PyStackRef sub, - _Py_CODEUNIT *instr); - extern void _Py_Specialize_Call(_PyStackRef callable, _Py_CODEUNIT *instr, -@@ -372,6 +371,7 @@ - do { if (_Py_stats && PyFunction_Check(callable)) _Py_stats->call_stats.eval_calls[name]++; } while (0) - #define GC_STAT_ADD(gen, name, n) do { if (_Py_stats) _Py_stats->gc_stats[(gen)].name += (n); } while (0) - #define OPT_STAT_INC(name) do { if (_Py_stats) _Py_stats->optimization_stats.name++; } while (0) -+#define OPT_STAT_ADD(name, n) do { if (_Py_stats) _Py_stats->optimization_stats.name += (n); } while (0) - #define UOP_STAT_INC(opname, name) do { if (_Py_stats) { assert(opname < 512); _Py_stats->optimization_stats.opcode[opname].name++; } } while (0) - #define UOP_PAIR_INC(uopcode, lastuop) \ - do { \ -@@ -407,6 +407,7 @@ - #define EVAL_CALL_STAT_INC_IF_FUNCTION(name, callable) ((void)0) - #define GC_STAT_ADD(gen, name, n) ((void)0) - #define OPT_STAT_INC(name) ((void)0) -+#define OPT_STAT_ADD(name, n) ((void)0) - #define UOP_STAT_INC(opname, name) ((void)0) - #define UOP_PAIR_INC(uopcode, lastuop) ((void)0) - #define OPT_UNSUPPORTED_OPCODE(opname) ((void)0) -@@ -438,7 +439,7 @@ - } - - static inline void --write_obj(uint16_t *p, PyObject *val) -+write_ptr(uint16_t *p, void *val) - { - memcpy(p, &val, sizeof(val)); - } -@@ -576,6 +577,17 @@ - return restart_backoff_counter(counter); - } - -+/* Specialization Extensions */ ++def tvos_ver(system="", release="", model="", is_simulator=False): ++ """Get tvOS version information, and return it as a namedtuple: ++ (system, release, model, is_simulator). + -+/* callbacks for an external specialization */ -+typedef int (*binaryopguardfunc)(PyObject *lhs, PyObject *rhs); -+typedef PyObject *(*binaryopactionfunc)(PyObject *lhs, PyObject *rhs); ++ If values can't be determined, they are set to values provided as ++ parameters. ++ """ ++ if sys.platform == "tvos": ++ # TODO: Can the iOS implementation be used here? ++ import _ios_support ++ result = _ios_support.get_platform_ios() ++ if result is not None: ++ return TVOSVersionInfo(*result) + -+typedef struct { -+ int oparg; -+ binaryopguardfunc guard; -+ binaryopactionfunc action; -+} _PyBinaryOpSpecializationDescr; - - /* Comparison bit masks. */ - -@@ -603,6 +615,8 @@ - - extern int _PyInstruction_GetLength(PyCodeObject *code, int offset); - -+extern PyObject *_PyInstrumentation_BranchesIterator(PyCodeObject *code); ++ return TVOSVersionInfo(system, release, model, is_simulator) + - struct _PyCode8 _PyCode_DEF(8); - - PyAPI_DATA(const struct _PyCode8) _Py_InitCleanup; -diff --git a/Include/internal/pycore_critical_section.h b/Include/internal/pycore_critical_section.h -index 78cd0d54972..e66d6d805c1 100644 ---- a/Include/internal/pycore_critical_section.h -+++ b/Include/internal/pycore_critical_section.h -@@ -109,7 +109,7 @@ - static inline void - _PyCriticalSection_BeginMutex(PyCriticalSection *c, PyMutex *m) - { -- if (PyMutex_LockFast(&m->_bits)) { -+ if (PyMutex_LockFast(m)) { - PyThreadState *tstate = _PyThreadState_GET(); - c->_cs_mutex = m; - c->_cs_prev = tstate->critical_section; -@@ -145,6 +145,12 @@ - static inline void - _PyCriticalSection_End(PyCriticalSection *c) - { -+ // If the mutex is NULL, we used the fast path in -+ // _PyCriticalSection_BeginSlow for locks already held in the top-most -+ // critical section, and we shouldn't unlock or pop this critical section. -+ if (c->_cs_mutex == NULL) { -+ return; -+ } - PyMutex_Unlock(c->_cs_mutex); - _PyCriticalSection_Pop(c); - } -@@ -170,8 +176,8 @@ - m2 = tmp; - } - -- if (PyMutex_LockFast(&m1->_bits)) { -- if (PyMutex_LockFast(&m2->_bits)) { -+ if (PyMutex_LockFast(m1)) { -+ if (PyMutex_LockFast(m2)) { - PyThreadState *tstate = _PyThreadState_GET(); - c->_cs_base._cs_mutex = m1; - c->_cs_mutex2 = m2; -@@ -199,6 +205,14 @@ - static inline void - _PyCriticalSection2_End(PyCriticalSection2 *c) - { -+ // if mutex1 is NULL, we used the fast path in -+ // _PyCriticalSection_BeginSlow for mutexes that are already held, -+ // which should only happen when mutex1 and mutex2 were the same mutex, -+ // and mutex2 should also be NULL. -+ if (c->_cs_base._cs_mutex == NULL) { -+ assert(c->_cs_mutex2 == NULL); -+ return; -+ } - if (c->_cs_mutex2) { - PyMutex_Unlock(c->_cs_mutex2); - } -diff --git a/Include/internal/pycore_debug_offsets.h b/Include/internal/pycore_debug_offsets.h -index 184f4b9360b..44feb079571 100644 ---- a/Include/internal/pycore_debug_offsets.h -+++ b/Include/internal/pycore_debug_offsets.h -@@ -11,6 +11,42 @@ - - #define _Py_Debug_Cookie "xdebugpy" - -+#if defined(__APPLE__) -+# include -+#endif + -+// Macros to burn global values in custom sections so out-of-process -+// profilers can locate them easily. -+#define GENERATE_DEBUG_SECTION(name, declaration) \ -+ _GENERATE_DEBUG_SECTION_WINDOWS(name) \ -+ _GENERATE_DEBUG_SECTION_APPLE(name) \ -+ declaration \ -+ _GENERATE_DEBUG_SECTION_LINUX(name) ++# A namedtuple for watchOS version information. ++WatchOSVersionInfo = collections.namedtuple( ++ "WatchOSVersionInfo", ++ ["system", "release", "model", "is_simulator"] ++) + -+#if defined(MS_WINDOWS) -+#define _GENERATE_DEBUG_SECTION_WINDOWS(name) \ -+ _Pragma(Py_STRINGIFY(section(Py_STRINGIFY(name), read, write))) \ -+ __declspec(allocate(Py_STRINGIFY(name))) -+#else -+#define _GENERATE_DEBUG_SECTION_WINDOWS(name) -+#endif + -+#if defined(__APPLE__) -+#define _GENERATE_DEBUG_SECTION_APPLE(name) \ -+ __attribute__((section(SEG_DATA "," Py_STRINGIFY(name)))) \ -+ __attribute__((used)) -+#else -+#define _GENERATE_DEBUG_SECTION_APPLE(name) -+#endif ++def watchos_ver(system="", release="", model="", is_simulator=False): ++ """Get watchOS version information, and return it as a namedtuple: ++ (system, release, model, is_simulator). + -+#if defined(__linux__) && (defined(__GNUC__) || defined(__clang__)) -+#define _GENERATE_DEBUG_SECTION_LINUX(name) \ -+ __attribute__((section("." Py_STRINGIFY(name)))) \ -+ __attribute__((used)) -+#else -+#define _GENERATE_DEBUG_SECTION_LINUX(name) -+#endif ++ If values can't be determined, they are set to values provided as ++ parameters. ++ """ ++ if sys.platform == "watchos": ++ # TODO: Can the iOS implementation be used here? ++ import _ios_support ++ result = _ios_support.get_platform_ios() ++ if result is not None: ++ return WatchOSVersionInfo(*result) + - #ifdef Py_GIL_DISABLED - # define _Py_Debug_gilruntimestate_enabled offsetof(struct _gil_runtime_state, enabled) - # define _Py_Debug_Free_Threaded 1 -@@ -69,6 +105,7 @@ - uint64_t instr_ptr; - uint64_t localsplus; - uint64_t owner; -+ uint64_t stackpointer; - } interpreter_frame; - - // Code object offset; -@@ -113,6 +150,14 @@ - uint64_t ob_size; - } list_object; - -+ // PySet object offset; -+ struct _set_object { -+ uint64_t size; -+ uint64_t used; -+ uint64_t table; -+ uint64_t mask; -+ } set_object; ++ return WatchOSVersionInfo(system, release, model, is_simulator) + - // PyDict object offset; - struct _dict_object { - uint64_t size; -@@ -153,6 +198,14 @@ - uint64_t size; - uint64_t collecting; - } gc; + -+ // Generator object offset; -+ struct _gen_object { -+ uint64_t size; -+ uint64_t gi_name; -+ uint64_t gi_iframe; -+ uint64_t gi_frame_state; -+ } gen_object; - } _Py_DebugOffsets; - - -@@ -198,6 +251,7 @@ - .instr_ptr = offsetof(_PyInterpreterFrame, instr_ptr), \ - .localsplus = offsetof(_PyInterpreterFrame, localsplus), \ - .owner = offsetof(_PyInterpreterFrame, owner), \ -+ .stackpointer = offsetof(_PyInterpreterFrame, stackpointer), \ - }, \ - .code_object = { \ - .size = sizeof(PyCodeObject), \ -@@ -231,6 +285,12 @@ - .ob_item = offsetof(PyListObject, ob_item), \ - .ob_size = offsetof(PyListObject, ob_base.ob_size), \ - }, \ -+ .set_object = { \ -+ .size = sizeof(PySetObject), \ -+ .used = offsetof(PySetObject, used), \ -+ .table = offsetof(PySetObject, table), \ -+ .mask = offsetof(PySetObject, mask), \ -+ }, \ - .dict_object = { \ - .size = sizeof(PyDictObject), \ - .ma_keys = offsetof(PyDictObject, ma_keys), \ -@@ -260,6 +320,12 @@ - .size = sizeof(struct _gc_runtime_state), \ - .collecting = offsetof(struct _gc_runtime_state, collecting), \ - }, \ -+ .gen_object = { \ -+ .size = sizeof(PyGenObject), \ -+ .gi_name = offsetof(PyGenObject, gi_name), \ -+ .gi_iframe = offsetof(PyGenObject, gi_iframe), \ -+ .gi_frame_state = offsetof(PyGenObject, gi_frame_state), \ -+ }, \ - } - + def _java_getprop(name, default): + """This private helper is deprecated in 3.13 and will be removed in 3.15""" + from java.lang import System +@@ -884,14 +932,25 @@ + csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0) + return 'Alpha' if cpu_number >= 128 else 'VAX' -diff --git a/Include/internal/pycore_dict.h b/Include/internal/pycore_dict.h -index 6e4a308226f..f4c55ca6cf6 100644 ---- a/Include/internal/pycore_dict.h -+++ b/Include/internal/pycore_dict.h -@@ -114,6 +114,17 @@ +- # On the iOS simulator, os.uname returns the architecture as uname.machine. +- # On device it returns the model name for some reason; but there's only one +- # CPU architecture for iOS devices, so we know the right answer. ++ # On the iOS/tvOS/watchOS simulator, os.uname returns the architecture as ++ # uname.machine. On device it returns the model name for some reason; but ++ # there's only one CPU architecture for devices, so we know the right ++ # answer. + def get_ios(): + if sys.implementation._multiarch.endswith("simulator"): + return os.uname().machine + return 'arm64' - extern Py_ssize_t _PyDict_LookupIndex(PyDictObject *, PyObject *); - extern Py_ssize_t _PyDictKeys_StringLookup(PyDictKeysObject* dictkeys, PyObject *key); ++ def get_tvos(): ++ if sys.implementation._multiarch.endswith("simulator"): ++ return os.uname().machine ++ return 'arm64' + -+/* Look up a string key in an all unicode dict keys, assign the keys object a version, and -+ * store it in version. -+ * -+ * Returns DKIX_ERROR if key is not a string or if the keys object is not all -+ * strings. -+ * -+ * Returns DKIX_EMPTY if the key is not present. -+ */ -+extern Py_ssize_t _PyDictKeys_StringLookupAndVersion(PyDictKeysObject* dictkeys, PyObject *key, uint32_t *version); -+extern Py_ssize_t _PyDictKeys_StringLookupSplit(PyDictKeysObject* dictkeys, PyObject *key); - PyAPI_FUNC(PyObject *)_PyDict_LoadGlobal(PyDictObject *, PyDictObject *, PyObject *); - PyAPI_FUNC(void) _PyDict_LoadGlobalStackRef(PyDictObject *, PyDictObject *, PyObject *, _PyStackRef *); - -@@ -336,8 +347,7 @@ - static inline Py_ssize_t - _PyDict_UniqueId(PyDictObject *mp) - { -- // Offset by one so that _ma_watcher_tag=0 represents an unassigned id -- return (Py_ssize_t)(mp->_ma_watcher_tag >> DICT_UNIQUE_ID_SHIFT) - 1; -+ return (Py_ssize_t)(mp->_ma_watcher_tag >> DICT_UNIQUE_ID_SHIFT); - } - - static inline void -diff --git a/Include/internal/pycore_emscripten_trampoline.h b/Include/internal/pycore_emscripten_trampoline.h -index e519c99ad86..5546ebbbfcb 100644 ---- a/Include/internal/pycore_emscripten_trampoline.h -+++ b/Include/internal/pycore_emscripten_trampoline.h -@@ -27,24 +27,14 @@ - - #if defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE) - --void _Py_EmscriptenTrampoline_Init(_PyRuntimeState *runtime); -+void -+_Py_EmscriptenTrampoline_Init(_PyRuntimeState *runtime); - - PyObject* --_PyEM_TrampolineCall_JavaScript(PyCFunctionWithKeywords func, -- PyObject* self, -- PyObject* args, -- PyObject* kw); -- --PyObject* --_PyEM_TrampolineCall_Reflection(PyCFunctionWithKeywords func, -- PyObject* self, -- PyObject* args, -- PyObject* kw); -- --#define _PyEM_TrampolineCall(meth, self, args, kw) \ -- ((_PyRuntime.wasm_type_reflection_available) ? \ -- (_PyEM_TrampolineCall_Reflection((PyCFunctionWithKeywords)(meth), (self), (args), (kw))) : \ -- (_PyEM_TrampolineCall_JavaScript((PyCFunctionWithKeywords)(meth), (self), (args), (kw)))) -+_PyEM_TrampolineCall(PyCFunctionWithKeywords func, -+ PyObject* self, -+ PyObject* args, -+ PyObject* kw); - - #define _PyCFunction_TrampolineCall(meth, self, args) \ - _PyEM_TrampolineCall( \ -@@ -62,8 +52,6 @@ - - #else // defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE) - --#define _Py_EmscriptenTrampoline_Init(runtime) -- - #define _PyCFunction_TrampolineCall(meth, self, args) \ - (meth)((self), (args)) - -diff --git a/Include/internal/pycore_exceptions.h b/Include/internal/pycore_exceptions.h -index 4a9df709131..26456d1966b 100644 ---- a/Include/internal/pycore_exceptions.h -+++ b/Include/internal/pycore_exceptions.h -@@ -24,6 +24,9 @@ - PyObject *errnomap; - PyBaseExceptionObject *memerrors_freelist; - int memerrors_numfree; -+#ifdef Py_GIL_DISABLED -+ PyMutex memerrors_lock; -+#endif - // The ExceptionGroup type - PyObject *PyExc_ExceptionGroup; - }; -diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h -index 96ae4dd22ec..8cc3504723b 100644 ---- a/Include/internal/pycore_frame.h -+++ b/Include/internal/pycore_frame.h -@@ -56,7 +56,8 @@ - FRAME_OWNED_BY_THREAD = 0, - FRAME_OWNED_BY_GENERATOR = 1, - FRAME_OWNED_BY_FRAME_OBJECT = 2, -- FRAME_OWNED_BY_CSTACK = 3, -+ FRAME_OWNED_BY_INTERPRETER = 3, -+ FRAME_OWNED_BY_CSTACK = 4, - }; - - typedef struct _PyInterpreterFrame { -@@ -68,14 +69,19 @@ - PyObject *f_locals; /* Strong reference, may be NULL. Only valid if not on C stack */ - PyFrameObject *frame_obj; /* Strong reference, may be NULL. Only valid if not on C stack */ - _Py_CODEUNIT *instr_ptr; /* Instruction currently executing (or about to begin) */ -+ _PyStackRef *stackpointer; - #ifdef Py_GIL_DISABLED - /* Index of thread-local bytecode containing instr_ptr. */ - int32_t tlbc_index; - #endif -- _PyStackRef *stackpointer; - uint16_t return_offset; /* Only relevant during a function call */ - char owner; -- char visited; -+#ifdef Py_DEBUG -+ uint8_t visited:1; -+ uint8_t lltrace:7; -+#else -+ uint8_t visited; -+#endif - /* Locals and stack */ - _PyStackRef localsplus[1]; - } _PyInterpreterFrame; -@@ -153,13 +159,6 @@ - // Don't leave a dangling pointer to the old frame when creating generators - // and coroutines: - dest->previous = NULL; -- --#ifdef Py_GIL_DISABLED -- PyCodeObject *co = _PyFrame_GetCode(dest); -- for (int i = stacktop; i < co->co_nlocalsplus + co->co_stacksize; i++) { -- dest->localsplus[i] = PyStackRef_NULL; -- } --#endif - } - - #ifdef Py_GIL_DISABLED -@@ -209,20 +208,13 @@ - frame->return_offset = 0; - frame->owner = FRAME_OWNED_BY_THREAD; - frame->visited = 0; -+#ifdef Py_DEBUG -+ frame->lltrace = 0; -+#endif - - for (int i = null_locals_from; i < code->co_nlocalsplus; i++) { - frame->localsplus[i] = PyStackRef_NULL; - } -- --#ifdef Py_GIL_DISABLED -- // On GIL disabled, we walk the entire stack in GC. Since stacktop -- // is not always in sync with the real stack pointer, we have -- // no choice but to traverse the entire stack. -- // This just makes sure we don't pass the GC invalid stack values. -- for (int i = code->co_nlocalsplus; i < code->co_nlocalsplus + code->co_stacksize; i++) { -- frame->localsplus[i] = PyStackRef_NULL; -- } --#endif - } - - /* Gets the pointer to the locals array -@@ -264,7 +256,7 @@ - static inline bool - _PyFrame_IsIncomplete(_PyInterpreterFrame *frame) - { -- if (frame->owner == FRAME_OWNED_BY_CSTACK) { -+ if (frame->owner >= FRAME_OWNED_BY_INTERPRETER) { - return true; - } - return frame->owner != FRAME_OWNED_BY_GENERATOR && -@@ -392,14 +384,10 @@ - #endif - frame->owner = FRAME_OWNED_BY_THREAD; - frame->visited = 0; -- frame->return_offset = 0; -- --#ifdef Py_GIL_DISABLED -- assert(code->co_nlocalsplus == 0); -- for (int i = 0; i < code->co_stacksize; i++) { -- frame->localsplus[i] = PyStackRef_NULL; -- } -+#ifdef Py_DEBUG -+ frame->lltrace = 0; - #endif -+ frame->return_offset = 0; - return frame; - } - -diff --git a/Include/internal/pycore_freelist_state.h b/Include/internal/pycore_freelist_state.h -index a1a94c1f2dc..7c252f5b570 100644 ---- a/Include/internal/pycore_freelist_state.h -+++ b/Include/internal/pycore_freelist_state.h -@@ -11,6 +11,8 @@ - # define PyTuple_MAXSAVESIZE 20 // Largest tuple to save on freelist - # define Py_tuple_MAXFREELIST 2000 // Maximum number of tuples of each size to save - # define Py_lists_MAXFREELIST 80 -+# define Py_list_iters_MAXFREELIST 10 -+# define Py_tuple_iters_MAXFREELIST 10 - # define Py_dicts_MAXFREELIST 80 - # define Py_dictkeys_MAXFREELIST 80 - # define Py_floats_MAXFREELIST 100 -@@ -22,6 +24,7 @@ - # define Py_futureiters_MAXFREELIST 255 - # define Py_object_stack_chunks_MAXFREELIST 4 - # define Py_unicode_writers_MAXFREELIST 1 -+# define Py_pymethodobjects_MAXFREELIST 20 - - // A generic freelist of either PyObjects or other data structures. - struct _Py_freelist { -@@ -39,6 +42,8 @@ - struct _Py_freelist ints; - struct _Py_freelist tuples[PyTuple_MAXSAVESIZE]; - struct _Py_freelist lists; -+ struct _Py_freelist list_iters; -+ struct _Py_freelist tuple_iters; - struct _Py_freelist dicts; - struct _Py_freelist dictkeys; - struct _Py_freelist slices; -@@ -48,6 +53,7 @@ - struct _Py_freelist futureiters; - struct _Py_freelist object_stack_chunks; - struct _Py_freelist unicode_writers; -+ struct _Py_freelist pymethodobjects; - }; - - #ifdef __cplusplus -diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h -index 4ff34bf8ead..b1806df2706 100644 ---- a/Include/internal/pycore_gc.h -+++ b/Include/internal/pycore_gc.h -@@ -45,12 +45,13 @@ - * the per-object lock. - */ - #ifdef Py_GIL_DISABLED --# define _PyGC_BITS_TRACKED (1) // Tracked by the GC --# define _PyGC_BITS_FINALIZED (2) // tp_finalize was called --# define _PyGC_BITS_UNREACHABLE (4) --# define _PyGC_BITS_FROZEN (8) --# define _PyGC_BITS_SHARED (16) --# define _PyGC_BITS_DEFERRED (64) // Use deferred reference counting -+# define _PyGC_BITS_TRACKED (1<<0) // Tracked by the GC -+# define _PyGC_BITS_FINALIZED (1<<1) // tp_finalize was called -+# define _PyGC_BITS_UNREACHABLE (1<<2) -+# define _PyGC_BITS_FROZEN (1<<3) -+# define _PyGC_BITS_SHARED (1<<4) -+# define _PyGC_BITS_ALIVE (1<<5) // Reachable from a known root. -+# define _PyGC_BITS_DEFERRED (1<<6) // Use deferred reference counting - #endif - - #ifdef Py_GIL_DISABLED -@@ -330,6 +331,9 @@ - collections, and are awaiting to undergo a full collection for - the first time. */ - Py_ssize_t long_lived_pending; ++ def get_watchos(): ++ if sys.implementation._multiarch.endswith("simulator"): ++ return os.uname().machine ++ return 'arm64_32' + -+ /* True if gc.freeze() has been used. */ -+ int freeze_active; - #endif - }; - -diff --git a/Include/internal/pycore_import.h b/Include/internal/pycore_import.h -index 318c712bdfa..5fe60df0a92 100644 ---- a/Include/internal/pycore_import.h -+++ b/Include/internal/pycore_import.h -@@ -31,12 +31,6 @@ - PyObject *modules - ); - --// Export for many shared extensions, like '_json' --PyAPI_FUNC(PyObject*) _PyImport_GetModuleAttr(PyObject *, PyObject *); -- --// Export for many shared extensions, like '_datetime' --PyAPI_FUNC(PyObject*) _PyImport_GetModuleAttrString(const char *, const char *); -- - - struct _import_runtime_state { - /* The builtin modules (defined in config.c). */ -diff --git a/Include/internal/pycore_instruments.h b/Include/internal/pycore_instruments.h -index 4e5b374968e..92d8f056f40 100644 ---- a/Include/internal/pycore_instruments.h -+++ b/Include/internal/pycore_instruments.h -@@ -48,8 +48,8 @@ - - _Py_CODEUNIT * - _Py_call_instrumentation_jump( -- PyThreadState *tstate, int event, -- _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *target); -+ _Py_CODEUNIT *instr, PyThreadState *tstate, int event, -+ _PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNIT *dest); + def from_subprocess(): + """ + Fall back to `uname -p` +@@ -1051,9 +1110,13 @@ + system = 'Android' + release = android_ver().release - extern int - _Py_call_instrumentation_arg(PyThreadState *tstate, int event, -diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h -index 87cdcb5b119..7fdfc790347 100644 ---- a/Include/internal/pycore_interp.h -+++ b/Include/internal/pycore_interp.h -@@ -31,9 +31,10 @@ - #include "pycore_list.h" // struct _Py_list_state - #include "pycore_mimalloc.h" // struct _mimalloc_interp_state - #include "pycore_object_state.h" // struct _py_object_state --#include "pycore_optimizer.h" // _PyOptimizerObject -+#include "pycore_optimizer.h" // _PyExecutorObject - #include "pycore_obmalloc.h" // struct _obmalloc_state - #include "pycore_qsbr.h" // struct _qsbr_state -+#include "pycore_stackref.h" // Py_STACKREF_DEBUG - #include "pycore_tstate.h" // _PyThreadStateImpl - #include "pycore_tuple.h" // struct _Py_tuple_state - #include "pycore_uniqueid.h" // struct _Py_unique_id_pool -@@ -226,6 +227,13 @@ - PyMutex weakref_locks[NUM_WEAKREF_LIST_LOCKS]; - _PyIndexPool tlbc_indices; - #endif -+ // Per-interpreter list of tasks, any lingering tasks from thread -+ // states gets added here and removed from the corresponding -+ // thread state's list. -+ struct llist_node asyncio_tasks_head; -+ // `asyncio_tasks_lock` is used when tasks are moved -+ // from thread's list to interpreter's list. -+ PyMutex asyncio_tasks_lock; +- # Normalize responses on iOS ++ # Normalize responses on Apple mobile platforms + if sys.platform == 'ios': + system, release, _, _ = ios_ver() ++ if sys.platform == 'tvos': ++ system, release, _, _ = tvos_ver() ++ if sys.platform == 'watchos': ++ system, release, _, _ = watchos_ver() - // Per-interpreter state for the obmalloc allocator. For the main - // interpreter and for all interpreters that don't have their -@@ -261,7 +269,7 @@ - struct ast_state ast; - struct types_state types; - struct callable_cache callable_cache; -- _PyOptimizerObject *optimizer; -+ bool jit; - _PyExecutorObject *executor_list_head; - size_t trace_run_counter; - _rare_events rare_events; -@@ -285,6 +293,11 @@ - _PyThreadStateImpl _initial_thread; - // _initial_thread should be the last field of PyInterpreterState. - // See https://github.com/python/cpython/issues/127117. -+ -+#if !defined(Py_GIL_DISABLED) && defined(Py_STACKREF_DEBUG) -+ uint64_t next_stackref; -+ _Py_hashtable_t *stackref_debug_table; -+#endif - }; - - -@@ -335,43 +348,6 @@ - - extern const PyConfig* _PyInterpreterState_GetConfig(PyInterpreterState *interp); - --// Get a copy of the current interpreter configuration. --// --// Return 0 on success. Raise an exception and return -1 on error. --// --// The caller must initialize 'config', using PyConfig_InitPythonConfig() --// for example. --// --// Python must be preinitialized to call this method. --// The caller must hold the GIL. --// --// Once done with the configuration, PyConfig_Clear() must be called to clear --// it. --// --// Export for '_testinternalcapi' shared extension. --PyAPI_FUNC(int) _PyInterpreterState_GetConfigCopy( -- struct PyConfig *config); -- --// Set the configuration of the current interpreter. --// --// This function should be called during or just after the Python --// initialization. --// --// Update the sys module with the new configuration. If the sys module was --// modified directly after the Python initialization, these changes are lost. --// --// Some configuration like faulthandler or warnoptions can be updated in the --// configuration, but don't reconfigure Python (don't enable/disable --// faulthandler and don't reconfigure warnings filters). --// --// Return 0 on success. Raise an exception and return -1 on error. --// --// The configuration should come from _PyInterpreterState_GetConfigCopy(). --// --// Export for '_testinternalcapi' shared extension. --PyAPI_FUNC(int) _PyInterpreterState_SetConfig( -- const struct PyConfig *config); -- - - /* - Runtime Feature Flags -diff --git a/Include/internal/pycore_list.h b/Include/internal/pycore_list.h -index 836ff30abfc..5d817891408 100644 ---- a/Include/internal/pycore_list.h -+++ b/Include/internal/pycore_list.h -@@ -61,7 +61,7 @@ - - union _PyStackRef; - --PyAPI_FUNC(PyObject *)_PyList_FromStackRefSteal(const union _PyStackRef *src, Py_ssize_t n); -+PyAPI_FUNC(PyObject *)_PyList_FromStackRefStealOnSuccess(const union _PyStackRef *src, Py_ssize_t n); - PyAPI_FUNC(PyObject *)_PyList_AsTupleAndClear(PyListObject *v); - - #ifdef __cplusplus -diff --git a/Include/internal/pycore_lock.h b/Include/internal/pycore_lock.h -index 57cbce8f126..7484b05d7f2 100644 ---- a/Include/internal/pycore_lock.h -+++ b/Include/internal/pycore_lock.h -@@ -18,9 +18,10 @@ - #define _Py_ONCE_INITIALIZED 4 - - static inline int --PyMutex_LockFast(uint8_t *lock_bits) -+PyMutex_LockFast(PyMutex *m) - { - uint8_t expected = _Py_UNLOCKED; -+ uint8_t *lock_bits = &m->_bits; - return _Py_atomic_compare_exchange_uint8(lock_bits, &expected, _Py_LOCKED); - } - -@@ -51,7 +52,7 @@ - - // Lock a mutex with an optional timeout and additional options. See - // _PyLockFlags for details. --extern PyLockStatus -+extern PyAPI_FUNC(PyLockStatus) - _PyMutex_LockTimed(PyMutex *m, PyTime_t timeout_ns, _PyLockFlags flags); - - // Lock a mutex with additional options. See _PyLockFlags for details. -diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h -index 8bead00e706..df0656a7cb8 100644 ---- a/Include/internal/pycore_long.h -+++ b/Include/internal/pycore_long.h -@@ -65,6 +65,8 @@ - # error "_PY_NSMALLPOSINTS must be greater than or equal to 257" - #endif - -+#define _PY_IS_SMALL_INT(val) ((val) >= 0 && (val) < 256 && (val) < _PY_NSMALLPOSINTS) -+ - // Return a reference to the immortal zero singleton. - // The function cannot return NULL. - static inline PyObject* _PyLong_GetZero(void) -@@ -159,13 +161,14 @@ - - /* Long value tag bits: - * 0-1: Sign bits value = (1-sign), ie. negative=2, positive=0, zero=1. -- * 2: Reserved for immortality bit -+ * 2: Set to 1 for the small ints - * 3+ Unsigned digit count - */ - #define SIGN_MASK 3 - #define SIGN_ZERO 1 - #define SIGN_NEGATIVE 2 - #define NON_SIZE_BITS 3 -+#define IMMORTALITY_BIT_MASK (1 << 2) - - /* The functions _PyLong_IsCompact and _PyLong_CompactValue are defined - * in Include/cpython/longobject.h, since they need to be inline. -@@ -196,7 +199,7 @@ - static inline int - _PyLong_IsNonNegativeCompact(const PyLongObject* op) { - assert(PyLong_Check(op)); -- return op->long_value.lv_tag <= (1 << NON_SIZE_BITS); -+ return ((op->long_value.lv_tag & ~IMMORTALITY_BIT_MASK) <= (1 << NON_SIZE_BITS)); - } - - -@@ -298,7 +301,7 @@ - .long_value = { \ - .lv_tag = TAG_FROM_SIGN_AND_SIZE( \ - (val) == 0 ? 0 : ((val) < 0 ? -1 : 1), \ -- (val) == 0 ? 0 : 1), \ -+ (val) == 0 ? 0 : 1) | IMMORTALITY_BIT_MASK, \ - { ((val) >= 0 ? (val) : -(val)) }, \ - } \ - } -diff --git a/Include/internal/pycore_magic_number.h b/Include/internal/pycore_magic_number.h -index 14e29576875..4803213e84b 100644 ---- a/Include/internal/pycore_magic_number.h -+++ b/Include/internal/pycore_magic_number.h -@@ -262,6 +262,13 @@ - Python 3.14a1 3607 (Add pseudo instructions JUMP_IF_TRUE/FALSE) - Python 3.14a1 3608 (Add support for slices) - Python 3.14a2 3609 (Add LOAD_SMALL_INT and LOAD_CONST_IMMORTAL instructions, remove RETURN_CONST) -+ Python 3.14a4 3610 (Add VALUE_WITH_FAKE_GLOBALS format to annotationlib) -+ Python 3.14a4 3611 (Add NOT_TAKEN instruction) -+ Python 3.14a4 3612 (Add POP_ITER and INSTRUMENTED_POP_ITER) -+ Python 3.14a4 3613 (Add LOAD_CONST_MORTAL instruction) -+ Python 3.14a5 3614 (Add BINARY_OP_EXTEND) -+ Python 3.14a5 3615 (CALL_FUNCTION_EX always take a kwargs argument) -+ Python 3.14a5 3616 (Remove BINARY_SUBSCR and family. Make them BINARY_OPs) - - Python 3.15 will start with 3650 - -@@ -274,7 +281,7 @@ - - */ - --#define PYC_MAGIC_NUMBER 3609 -+#define PYC_MAGIC_NUMBER 3616 - /* This is equivalent to converting PYC_MAGIC_NUMBER to 2 bytes - (little-endian) and then appending b'\r\n'. */ - #define PYC_MAGIC_NUMBER_TOKEN \ -diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h -index d7d68f938a9..49ddfd5b43b 100644 ---- a/Include/internal/pycore_object.h -+++ b/Include/internal/pycore_object.h -@@ -62,7 +62,7 @@ - PyAPI_FUNC(int) _PyObject_IsFreed(PyObject *); - - /* We need to maintain an internal copy of Py{Var}Object_HEAD_INIT to avoid -- designated initializer conflicts in C++20. If we use the deinition in -+ designated initializer conflicts in C++20. If we use the definition in - object.h, we will be mixing designated and non-designated initializers in - pycore objects which is forbiddent in C++20. However, if we then use - designated initializers in object.h then Extensions without designated break. -@@ -120,8 +120,8 @@ - PyAPI_DATA(Py_ssize_t) _Py_RefTotal; - - extern void _Py_AddRefTotal(PyThreadState *, Py_ssize_t); --extern void _Py_IncRefTotal(PyThreadState *); --extern void _Py_DecRefTotal(PyThreadState *); -+extern PyAPI_FUNC(void) _Py_IncRefTotal(PyThreadState *); -+extern PyAPI_FUNC(void) _Py_DecRefTotal(PyThreadState *); - - # define _Py_DEC_REFTOTAL(interp) \ - interp->object_state.reftotal-- -@@ -299,12 +299,6 @@ - extern int _PyType_CheckConsistency(PyTypeObject *type); - extern int _PyDict_CheckConsistency(PyObject *mp, int check_content); - --/* Update the Python traceback of an object. This function must be called -- when a memory block is reused from a free list. -- -- Internal function called by _Py_NewReference(). */ --extern int _PyTraceMalloc_TraceRef(PyObject *op, PyRefTracerEvent event, void*); -- - // Fast inlined version of PyType_HasFeature() - static inline int - _PyType_HasFeature(PyTypeObject *type, unsigned long feature) { -@@ -342,20 +336,20 @@ - { - _PyThreadStateImpl *tstate = (_PyThreadStateImpl *)_PyThreadState_GET(); - -- // Unsigned comparison so that `unique_id=-1`, which indicates that -- // per-thread refcounting has been disabled on this object, is handled by -- // the "else". -- if ((size_t)unique_id < (size_t)tstate->refcounts.size) { -+ // The table index is `unique_id - 1` because 0 is not a valid unique id. -+ // Unsigned comparison so that `idx=-1` is handled by the "else". -+ size_t idx = (size_t)(unique_id - 1); -+ if (idx < (size_t)tstate->refcounts.size) { - # ifdef Py_REF_DEBUG - _Py_INCREF_IncRefTotal(); - # endif - _Py_INCREF_STAT_INC(); -- tstate->refcounts.values[unique_id]++; -+ tstate->refcounts.values[idx]++; - } - else { - // The slow path resizes the per-thread refcount array if necessary. -- // It handles the unique_id=-1 case to keep the inlinable function smaller. -- _PyObject_ThreadIncrefSlow(obj, unique_id); -+ // It handles the unique_id=0 case to keep the inlinable function smaller. -+ _PyObject_ThreadIncrefSlow(obj, idx); - } - } - -@@ -392,15 +386,15 @@ - { - _PyThreadStateImpl *tstate = (_PyThreadStateImpl *)_PyThreadState_GET(); - -- // Unsigned comparison so that `unique_id=-1`, which indicates that -- // per-thread refcounting has been disabled on this object, is handled by -- // the "else". -- if ((size_t)unique_id < (size_t)tstate->refcounts.size) { -+ // The table index is `unique_id - 1` because 0 is not a valid unique id. -+ // Unsigned comparison so that `idx=-1` is handled by the "else". -+ size_t idx = (size_t)(unique_id - 1); -+ if (idx < (size_t)tstate->refcounts.size) { - # ifdef Py_REF_DEBUG - _Py_DECREF_DecRefTotal(); - # endif - _Py_DECREF_STAT_INC(); -- tstate->refcounts.values[unique_id]--; -+ tstate->refcounts.values[idx]--; - } - else { - // Directly decref the object if the id is not assigned or if -@@ -716,7 +710,7 @@ - } - } - --extern int _PyObject_ResurrectEndSlow(PyObject *op); -+extern PyAPI_FUNC(int) _PyObject_ResurrectEndSlow(PyObject *op); - #endif - - // Temporarily resurrects an object during deallocation. The refcount is set -diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h -index 28aa1120414..24c698adb31 100644 ---- a/Include/internal/pycore_opcode_metadata.h -+++ b/Include/internal/pycore_opcode_metadata.h -@@ -43,30 +43,30 @@ - return 2; - case BINARY_OP_ADD_UNICODE: - return 2; -+ case BINARY_OP_EXTEND: -+ return 2; - case BINARY_OP_INPLACE_ADD_UNICODE: - return 2; - case BINARY_OP_MULTIPLY_FLOAT: - return 2; - case BINARY_OP_MULTIPLY_INT: - return 2; -- case BINARY_OP_SUBTRACT_FLOAT: -+ case BINARY_OP_SUBSCR_DICT: - return 2; -- case BINARY_OP_SUBTRACT_INT: -+ case BINARY_OP_SUBSCR_GETITEM: - return 2; -- case BINARY_SLICE: -- return 3; -- case BINARY_SUBSCR: -- return 2; -- case BINARY_SUBSCR_DICT: -+ case BINARY_OP_SUBSCR_LIST_INT: - return 2; -- case BINARY_SUBSCR_GETITEM: -+ case BINARY_OP_SUBSCR_STR_INT: - return 2; -- case BINARY_SUBSCR_LIST_INT: -+ case BINARY_OP_SUBSCR_TUPLE_INT: - return 2; -- case BINARY_SUBSCR_STR_INT: -+ case BINARY_OP_SUBTRACT_FLOAT: - return 2; -- case BINARY_SUBSCR_TUPLE_INT: -+ case BINARY_OP_SUBTRACT_INT: - return 2; -+ case BINARY_SLICE: -+ return 3; - case BUILD_LIST: - return oparg; - case BUILD_MAP: -@@ -74,7 +74,7 @@ - case BUILD_SET: - return oparg; - case BUILD_SLICE: -- return 2 + ((oparg == 3) ? 1 : 0); -+ return oparg; - case BUILD_STRING: - return oparg; - case BUILD_TUPLE: -@@ -98,7 +98,7 @@ - case CALL_BUILTIN_O: - return 2 + oparg; - case CALL_FUNCTION_EX: -- return 3 + (oparg & 1); -+ return 4; - case CALL_INTRINSIC_1: - return 1; - case CALL_INTRINSIC_2: -@@ -224,9 +224,9 @@ - case INSTRUMENTED_CALL: - return 2 + oparg; - case INSTRUMENTED_CALL_FUNCTION_EX: -- return 0; -+ return 4; - case INSTRUMENTED_CALL_KW: -- return 0; -+ return 3 + oparg; - case INSTRUMENTED_END_FOR: - return 2; - case INSTRUMENTED_END_SEND: -@@ -242,7 +242,11 @@ - case INSTRUMENTED_LINE: - return 0; - case INSTRUMENTED_LOAD_SUPER_ATTR: -+ return 3; -+ case INSTRUMENTED_NOT_TAKEN: - return 0; -+ case INSTRUMENTED_POP_ITER: -+ return 1; - case INSTRUMENTED_POP_JUMP_IF_FALSE: - return 0; - case INSTRUMENTED_POP_JUMP_IF_NONE: -@@ -265,8 +269,12 @@ - return 0; - case JUMP_BACKWARD: - return 0; -+ case JUMP_BACKWARD_JIT: -+ return 0; - case JUMP_BACKWARD_NO_INTERRUPT: - return 0; -+ case JUMP_BACKWARD_NO_JIT: -+ return 0; - case JUMP_FORWARD: - return 0; - case JUMP_IF_FALSE: -@@ -317,6 +325,8 @@ - return 0; - case LOAD_CONST_IMMORTAL: - return 0; -+ case LOAD_CONST_MORTAL: -+ return 0; - case LOAD_DEREF: - return 0; - case LOAD_FAST: -@@ -367,10 +377,14 @@ - return 1; - case NOP: - return 0; -+ case NOT_TAKEN: -+ return 0; - case POP_BLOCK: - return 0; - case POP_EXCEPT: - return 1; -+ case POP_ITER: -+ return 1; - case POP_JUMP_IF_FALSE: - return 1; - case POP_JUMP_IF_NONE: -@@ -502,29 +516,29 @@ - return 1; - case BINARY_OP_ADD_UNICODE: - return 1; -+ case BINARY_OP_EXTEND: -+ return 1; - case BINARY_OP_INPLACE_ADD_UNICODE: - return 0; - case BINARY_OP_MULTIPLY_FLOAT: - return 1; - case BINARY_OP_MULTIPLY_INT: - return 1; -- case BINARY_OP_SUBTRACT_FLOAT: -- return 1; -- case BINARY_OP_SUBTRACT_INT: -+ case BINARY_OP_SUBSCR_DICT: - return 1; -- case BINARY_SLICE: -+ case BINARY_OP_SUBSCR_GETITEM: -+ return 0; -+ case BINARY_OP_SUBSCR_LIST_INT: - return 1; -- case BINARY_SUBSCR: -+ case BINARY_OP_SUBSCR_STR_INT: - return 1; -- case BINARY_SUBSCR_DICT: -+ case BINARY_OP_SUBSCR_TUPLE_INT: - return 1; -- case BINARY_SUBSCR_GETITEM: -- return 0; -- case BINARY_SUBSCR_LIST_INT: -+ case BINARY_OP_SUBTRACT_FLOAT: - return 1; -- case BINARY_SUBSCR_STR_INT: -+ case BINARY_OP_SUBTRACT_INT: - return 1; -- case BINARY_SUBSCR_TUPLE_INT: -+ case BINARY_SLICE: - return 1; - case BUILD_LIST: - return 1; -@@ -683,9 +697,9 @@ - case INSTRUMENTED_CALL: - return 1; - case INSTRUMENTED_CALL_FUNCTION_EX: -- return 0; -+ return 1; - case INSTRUMENTED_CALL_KW: -- return 0; -+ return 1; - case INSTRUMENTED_END_FOR: - return 1; - case INSTRUMENTED_END_SEND: -@@ -701,6 +715,10 @@ - case INSTRUMENTED_LINE: - return 0; - case INSTRUMENTED_LOAD_SUPER_ATTR: -+ return 1 + (oparg & 1); -+ case INSTRUMENTED_NOT_TAKEN: -+ return 0; -+ case INSTRUMENTED_POP_ITER: - return 0; - case INSTRUMENTED_POP_JUMP_IF_FALSE: - return 0; -@@ -724,8 +742,12 @@ - return 0; - case JUMP_BACKWARD: - return 0; -+ case JUMP_BACKWARD_JIT: -+ return 0; - case JUMP_BACKWARD_NO_INTERRUPT: - return 0; -+ case JUMP_BACKWARD_NO_JIT: -+ return 0; - case JUMP_FORWARD: - return 0; - case JUMP_IF_FALSE: -@@ -739,7 +761,7 @@ - case LIST_EXTEND: - return 1 + (oparg-1); - case LOAD_ATTR: -- return 1 + (oparg & 1); -+ return 1 + (oparg&1); - case LOAD_ATTR_CLASS: - return 1 + (oparg & 1); - case LOAD_ATTR_CLASS_WITH_METACLASS_CHECK: -@@ -776,6 +798,8 @@ - return 1; - case LOAD_CONST_IMMORTAL: - return 1; -+ case LOAD_CONST_MORTAL: -+ return 1; - case LOAD_DEREF: - return 1; - case LOAD_FAST: -@@ -826,10 +850,14 @@ - return 2; - case NOP: - return 0; -+ case NOT_TAKEN: -+ return 0; - case POP_BLOCK: - return 0; - case POP_EXCEPT: - return 0; -+ case POP_ITER: -+ return 0; - case POP_JUMP_IF_FALSE: - return 0; - case POP_JUMP_IF_NONE: -@@ -954,7 +982,7 @@ - int _PyOpcode_max_stack_effect(int opcode, int oparg, int *effect) { - switch(opcode) { - case BINARY_OP: { -- *effect = 0; -+ *effect = 1; - return 0; - } - case BINARY_OP_ADD_FLOAT: { -@@ -969,6 +997,10 @@ - *effect = 0; - return 0; - } -+ case BINARY_OP_EXTEND: { -+ *effect = 0; -+ return 0; -+ } - case BINARY_OP_INPLACE_ADD_UNICODE: { - *effect = 0; - return 0; -@@ -981,40 +1013,36 @@ - *effect = 0; - return 0; - } -- case BINARY_OP_SUBTRACT_FLOAT: { -- *effect = 0; -+ case BINARY_OP_SUBSCR_DICT: { -+ *effect = -1; - return 0; - } -- case BINARY_OP_SUBTRACT_INT: { -- *effect = 0; -+ case BINARY_OP_SUBSCR_GETITEM: { -+ *effect = 1; - return 0; - } -- case BINARY_SLICE: { -- *effect = 0; -+ case BINARY_OP_SUBSCR_LIST_INT: { -+ *effect = -1; - return 0; - } -- case BINARY_SUBSCR: { -- *effect = 0; -+ case BINARY_OP_SUBSCR_STR_INT: { -+ *effect = -1; - return 0; - } -- case BINARY_SUBSCR_DICT: { -+ case BINARY_OP_SUBSCR_TUPLE_INT: { - *effect = -1; - return 0; - } -- case BINARY_SUBSCR_GETITEM: { -+ case BINARY_OP_SUBTRACT_FLOAT: { - *effect = 0; - return 0; - } -- case BINARY_SUBSCR_LIST_INT: { -- *effect = -1; -- return 0; -- } -- case BINARY_SUBSCR_STR_INT: { -- *effect = -1; -+ case BINARY_OP_SUBTRACT_INT: { -+ *effect = 0; - return 0; - } -- case BINARY_SUBSCR_TUPLE_INT: { -- *effect = -1; -+ case BINARY_SLICE: { -+ *effect = 0; - return 0; - } - case BUILD_LIST: { -@@ -1030,7 +1058,7 @@ - return 0; - } - case BUILD_SLICE: { -- *effect = -1 - ((oparg == 3) ? 1 : 0); -+ *effect = 1 - oparg; - return 0; - } - case BUILD_STRING: { -@@ -1086,7 +1114,7 @@ - return 0; - } - case CALL_FUNCTION_EX: { -- *effect = Py_MAX(0, -2 - (oparg & 1)); -+ *effect = 0; - return 0; - } - case CALL_INTRINSIC_1: { -@@ -1352,7 +1380,7 @@ - return 0; - } - case INSTRUMENTED_CALL_KW: { -- *effect = 0; -+ *effect = Py_MAX(0, -2 - oparg); - return 0; - } - case INSTRUMENTED_END_FOR: { -@@ -1384,9 +1412,17 @@ - return 0; - } - case INSTRUMENTED_LOAD_SUPER_ATTR: { -+ *effect = Py_MAX(-2, -2 + (oparg & 1)); -+ return 0; -+ } -+ case INSTRUMENTED_NOT_TAKEN: { - *effect = 0; - return 0; - } -+ case INSTRUMENTED_POP_ITER: { -+ *effect = -1; -+ return 0; -+ } - case INSTRUMENTED_POP_JUMP_IF_FALSE: { - *effect = 0; - return 0; -@@ -1431,10 +1467,18 @@ - *effect = 0; - return 0; - } -+ case JUMP_BACKWARD_JIT: { -+ *effect = 0; -+ return 0; -+ } - case JUMP_BACKWARD_NO_INTERRUPT: { - *effect = 0; - return 0; - } -+ case JUMP_BACKWARD_NO_JIT: { -+ *effect = 0; -+ return 0; -+ } - case JUMP_FORWARD: { - *effect = 0; - return 0; -@@ -1460,7 +1504,9 @@ - return 0; - } - case LOAD_ATTR: { -- *effect = Py_MAX(1, (oparg & 1)); -+ int max_eff = Py_MAX(1, (oparg & 1)); -+ max_eff = Py_MAX(max_eff, (oparg&1)); -+ *effect = max_eff; - return 0; - } - case LOAD_ATTR_CLASS: { -@@ -1512,7 +1558,7 @@ - return 0; - } - case LOAD_ATTR_WITH_HINT: { -- *effect = Py_MAX(0, (oparg & 1)); -+ *effect = Py_MAX(1, (oparg & 1)); - return 0; - } - case LOAD_BUILD_CLASS: { -@@ -1535,6 +1581,10 @@ - *effect = 1; - return 0; - } -+ case LOAD_CONST_MORTAL: { -+ *effect = 1; -+ return 0; -+ } - case LOAD_DEREF: { - *effect = 1; - return 0; -@@ -1635,6 +1685,10 @@ - *effect = 0; - return 0; - } -+ case NOT_TAKEN: { -+ *effect = 0; -+ return 0; -+ } - case POP_BLOCK: { - *effect = 0; - return 0; -@@ -1643,6 +1697,10 @@ - *effect = -1; - return 0; - } -+ case POP_ITER: { -+ *effect = -1; -+ return 0; -+ } - case POP_JUMP_IF_FALSE: { - *effect = -1; - return 0; -@@ -1879,11 +1937,13 @@ - INSTR_FMT_IBC = 2, - INSTR_FMT_IBC00 = 3, - INSTR_FMT_IBC000 = 4, -- INSTR_FMT_IBC00000000 = 5, -- INSTR_FMT_IX = 6, -- INSTR_FMT_IXC = 7, -- INSTR_FMT_IXC00 = 8, -- INSTR_FMT_IXC000 = 9, -+ INSTR_FMT_IBC0000 = 5, -+ INSTR_FMT_IBC00000000 = 6, -+ INSTR_FMT_IX = 7, -+ INSTR_FMT_IXC = 8, -+ INSTR_FMT_IXC00 = 9, -+ INSTR_FMT_IXC000 = 10, -+ INSTR_FMT_IXC0000 = 11, - }; - - #define IS_VALID_OPCODE(OP) \ -@@ -1905,6 +1965,7 @@ - #define HAS_PASSTHROUGH_FLAG (4096) - #define HAS_OPARG_AND_1_FLAG (8192) - #define HAS_ERROR_NO_POP_FLAG (16384) -+#define HAS_NO_SAVE_IP_FLAG (32768) - #define OPCODE_HAS_ARG(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_ARG_FLAG)) - #define OPCODE_HAS_CONST(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_CONST_FLAG)) - #define OPCODE_HAS_NAME(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_NAME_FLAG)) -@@ -1920,6 +1981,7 @@ - #define OPCODE_HAS_PASSTHROUGH(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_PASSTHROUGH_FLAG)) - #define OPCODE_HAS_OPARG_AND_1(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_OPARG_AND_1_FLAG)) - #define OPCODE_HAS_ERROR_NO_POP(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_ERROR_NO_POP_FLAG)) -+#define OPCODE_HAS_NO_SAVE_IP(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_NO_SAVE_IP_FLAG)) - - #define OPARG_FULL 0 - #define OPARG_CACHE_1 1 -@@ -1932,45 +1994,45 @@ - - struct opcode_metadata { - uint8_t valid_entry; -- int8_t instr_format; -- int16_t flags; -+ uint8_t instr_format; -+ uint16_t flags; - }; - - extern const struct opcode_metadata _PyOpcode_opcode_metadata[266]; - #ifdef NEED_OPCODE_METADATA - const struct opcode_metadata _PyOpcode_opcode_metadata[266] = { -- [BINARY_OP] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -- [BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, -- [BINARY_OP_ADD_INT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, -- [BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, -- [BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IXC, HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG }, -- [BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, -- [BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, -- [BINARY_OP_SUBTRACT_FLOAT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, -- [BINARY_OP_SUBTRACT_INT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, -+ [BINARY_OP] = { true, INSTR_FMT_IBC0000, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -+ [BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, -+ [BINARY_OP_ADD_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, -+ [BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, -+ [BINARY_OP_EXTEND] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, -+ [BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IXC0000, HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG }, -+ [BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, -+ [BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, -+ [BINARY_OP_SUBSCR_DICT] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -+ [BINARY_OP_SUBSCR_GETITEM] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG }, -+ [BINARY_OP_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, -+ [BINARY_OP_SUBSCR_STR_INT] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, -+ [BINARY_OP_SUBSCR_TUPLE_INT] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, -+ [BINARY_OP_SUBTRACT_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, -+ [BINARY_OP_SUBTRACT_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, - [BINARY_SLICE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -- [BINARY_SUBSCR] = { true, INSTR_FMT_IXC, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -- [BINARY_SUBSCR_DICT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -- [BINARY_SUBSCR_GETITEM] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG }, -- [BINARY_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, -- [BINARY_SUBSCR_STR_INT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG }, -- [BINARY_SUBSCR_TUPLE_INT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG }, -- [BUILD_LIST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG }, -+ [BUILD_LIST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG }, - [BUILD_MAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [BUILD_SET] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [BUILD_SLICE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG }, - [BUILD_STRING] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG }, -- [BUILD_TUPLE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG }, -+ [BUILD_TUPLE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG }, - [CACHE] = { true, INSTR_FMT_IX, 0 }, - [CALL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [CALL_ALLOC_AND_ENTER_INIT] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, -- [CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, -+ [CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, - [CALL_BOUND_METHOD_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [CALL_BUILTIN_CLASS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CALL_BUILTIN_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CALL_BUILTIN_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -- [CALL_FUNCTION_EX] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, -+ [CALL_FUNCTION_EX] = { true, INSTR_FMT_IX, HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [CALL_INTRINSIC_1] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CALL_INTRINSIC_2] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CALL_ISINSTANCE] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, -@@ -1979,7 +2041,7 @@ - [CALL_KW_NON_PY] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CALL_KW_PY] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [CALL_LEN] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, -- [CALL_LIST_APPEND] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG }, -+ [CALL_LIST_APPEND] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CALL_METHOD_DESCRIPTOR_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CALL_METHOD_DESCRIPTOR_NOARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -@@ -1989,7 +2051,7 @@ - [CALL_PY_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [CALL_STR_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CALL_TUPLE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -- [CALL_TYPE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, -+ [CALL_TYPE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, - [CHECK_EG_MATCH] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CHECK_EXC_MATCH] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CLEANUP_THROW] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, -@@ -2012,7 +2074,7 @@ - [DICT_MERGE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [DICT_UPDATE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [END_ASYNC_FOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, -- [END_FOR] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, -+ [END_FOR] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG | HAS_NO_SAVE_IP_FLAG }, - [END_SEND] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, - [ENTER_EXECUTOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [EXIT_INIT_CHECK] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, -@@ -2021,9 +2083,9 @@ - [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 }, - [FOR_ITER_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, -- [FOR_ITER_LIST] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG }, -+ [FOR_ITER_LIST] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, - [FOR_ITER_RANGE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG }, -- [FOR_ITER_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG }, -+ [FOR_ITER_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, - [GET_AITER] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [GET_ANEXT] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [GET_AWAITABLE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -@@ -2033,19 +2095,21 @@ - [IMPORT_FROM] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [IMPORT_NAME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [INSTRUMENTED_CALL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, -- [INSTRUMENTED_CALL_FUNCTION_EX] = { true, INSTR_FMT_IX, 0 }, -- [INSTRUMENTED_CALL_KW] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -- [INSTRUMENTED_END_FOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, -+ [INSTRUMENTED_CALL_FUNCTION_EX] = { true, INSTR_FMT_IX, HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, -+ [INSTRUMENTED_CALL_KW] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, -+ [INSTRUMENTED_END_FOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_NO_SAVE_IP_FLAG }, - [INSTRUMENTED_END_SEND] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, -- [INSTRUMENTED_FOR_ITER] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, -+ [INSTRUMENTED_FOR_ITER] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [INSTRUMENTED_INSTRUCTION] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [INSTRUMENTED_JUMP_BACKWARD] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [INSTRUMENTED_JUMP_FORWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [INSTRUMENTED_LINE] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG }, -- [INSTRUMENTED_LOAD_SUPER_ATTR] = { true, INSTR_FMT_IXC, 0 }, -+ [INSTRUMENTED_LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -+ [INSTRUMENTED_NOT_TAKEN] = { true, INSTR_FMT_IX, 0 }, -+ [INSTRUMENTED_POP_ITER] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG }, - [INSTRUMENTED_POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, -- [INSTRUMENTED_POP_JUMP_IF_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, -- [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, -+ [INSTRUMENTED_POP_JUMP_IF_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_ESCAPES_FLAG }, -+ [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_ESCAPES_FLAG }, - [INSTRUMENTED_POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, - [INSTRUMENTED_RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [INSTRUMENTED_RETURN_VALUE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -@@ -2053,7 +2117,9 @@ - [INTERPRETER_EXIT] = { true, INSTR_FMT_IX, 0 }, - [IS_OP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [JUMP_BACKWARD] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -+ [JUMP_BACKWARD_JIT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [JUMP_BACKWARD_NO_INTERRUPT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, -+ [JUMP_BACKWARD_NO_JIT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [JUMP_FORWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, - [LIST_APPEND] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG }, - [LIST_EXTEND] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -@@ -2061,11 +2127,11 @@ - [LOAD_ATTR_CLASS] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG }, - [LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG }, - [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG }, -- [LOAD_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, -+ [LOAD_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, - [LOAD_ATTR_METHOD_LAZY_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, - [LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG }, - [LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, -- [LOAD_ATTR_MODULE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, -+ [LOAD_ATTR_MODULE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, - [LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG }, - [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, - [LOAD_ATTR_PROPERTY] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, -@@ -2073,8 +2139,9 @@ - [LOAD_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, - [LOAD_BUILD_CLASS] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [LOAD_COMMON_CONSTANT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, -- [LOAD_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG | HAS_PURE_FLAG }, -+ [LOAD_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG }, - [LOAD_CONST_IMMORTAL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG }, -+ [LOAD_CONST_MORTAL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG }, - [LOAD_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_PURE_FLAG }, - [LOAD_FAST_AND_CLEAR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, -@@ -2091,8 +2158,8 @@ - [LOAD_SPECIAL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [LOAD_SUPER_ATTR_ATTR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -- [LOAD_SUPER_ATTR_METHOD] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -- [MAKE_CELL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG }, -+ [LOAD_SUPER_ATTR_METHOD] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, -+ [MAKE_CELL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [MAKE_FUNCTION] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [MAP_ADD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [MATCH_CLASS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -@@ -2100,7 +2167,9 @@ - [MATCH_MAPPING] = { true, INSTR_FMT_IX, 0 }, - [MATCH_SEQUENCE] = { true, INSTR_FMT_IX, 0 }, - [NOP] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, -+ [NOT_TAKEN] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, - [POP_EXCEPT] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG }, -+ [POP_ITER] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, - [POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, - [POP_JUMP_IF_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, - [POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, -@@ -2122,19 +2191,19 @@ - [SET_FUNCTION_ATTRIBUTE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [SET_UPDATE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [STORE_ATTR] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -- [STORE_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IXC000, HAS_EXIT_FLAG }, -- [STORE_ATTR_SLOT] = { true, INSTR_FMT_IXC000, HAS_EXIT_FLAG }, -+ [STORE_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IXC000, HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, -+ [STORE_ATTR_SLOT] = { true, INSTR_FMT_IXC000, HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, - [STORE_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, - [STORE_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ESCAPES_FLAG }, -- [STORE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, -- [STORE_FAST_LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, -- [STORE_FAST_STORE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, -+ [STORE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG }, -+ [STORE_FAST_LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG }, -+ [STORE_FAST_STORE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG }, - [STORE_GLOBAL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [STORE_NAME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [STORE_SLICE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [STORE_SUBSCR] = { true, INSTR_FMT_IXC, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [STORE_SUBSCR_DICT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, -- [STORE_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG }, -+ [STORE_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, - [SWAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_PURE_FLAG }, - [TO_BOOL] = { true, INSTR_FMT_IXC00, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [TO_BOOL_ALWAYS_TRUE] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG }, -@@ -2162,7 +2231,7 @@ - [SETUP_CLEANUP] = { true, -1, HAS_PURE_FLAG | HAS_ARG_FLAG }, - [SETUP_FINALLY] = { true, -1, HAS_PURE_FLAG | HAS_ARG_FLAG }, - [SETUP_WITH] = { true, -1, HAS_PURE_FLAG | HAS_ARG_FLAG }, -- [STORE_FAST_MAYBE_NULL] = { true, -1, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, -+ [STORE_FAST_MAYBE_NULL] = { true, -1, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG }, - }; - #endif - -@@ -2180,18 +2249,18 @@ - [BINARY_OP_ADD_FLOAT] = { .nuops = 2, .uops = { { _GUARD_BOTH_FLOAT, 0, 0 }, { _BINARY_OP_ADD_FLOAT, 0, 0 } } }, - [BINARY_OP_ADD_INT] = { .nuops = 2, .uops = { { _GUARD_BOTH_INT, 0, 0 }, { _BINARY_OP_ADD_INT, 0, 0 } } }, - [BINARY_OP_ADD_UNICODE] = { .nuops = 2, .uops = { { _GUARD_BOTH_UNICODE, 0, 0 }, { _BINARY_OP_ADD_UNICODE, 0, 0 } } }, -+ [BINARY_OP_EXTEND] = { .nuops = 2, .uops = { { _GUARD_BINARY_OP_EXTEND, 4, 1 }, { _BINARY_OP_EXTEND, 4, 1 } } }, - [BINARY_OP_INPLACE_ADD_UNICODE] = { .nuops = 2, .uops = { { _GUARD_BOTH_UNICODE, 0, 0 }, { _BINARY_OP_INPLACE_ADD_UNICODE, 0, 0 } } }, - [BINARY_OP_MULTIPLY_FLOAT] = { .nuops = 2, .uops = { { _GUARD_BOTH_FLOAT, 0, 0 }, { _BINARY_OP_MULTIPLY_FLOAT, 0, 0 } } }, - [BINARY_OP_MULTIPLY_INT] = { .nuops = 2, .uops = { { _GUARD_BOTH_INT, 0, 0 }, { _BINARY_OP_MULTIPLY_INT, 0, 0 } } }, -+ [BINARY_OP_SUBSCR_DICT] = { .nuops = 1, .uops = { { _BINARY_OP_SUBSCR_DICT, 0, 0 } } }, -+ [BINARY_OP_SUBSCR_GETITEM] = { .nuops = 4, .uops = { { _CHECK_PEP_523, 0, 0 }, { _BINARY_OP_SUBSCR_CHECK_FUNC, 0, 0 }, { _BINARY_OP_SUBSCR_INIT_CALL, 0, 0 }, { _PUSH_FRAME, 0, 0 } } }, -+ [BINARY_OP_SUBSCR_LIST_INT] = { .nuops = 1, .uops = { { _BINARY_OP_SUBSCR_LIST_INT, 0, 0 } } }, -+ [BINARY_OP_SUBSCR_STR_INT] = { .nuops = 1, .uops = { { _BINARY_OP_SUBSCR_STR_INT, 0, 0 } } }, -+ [BINARY_OP_SUBSCR_TUPLE_INT] = { .nuops = 1, .uops = { { _BINARY_OP_SUBSCR_TUPLE_INT, 0, 0 } } }, - [BINARY_OP_SUBTRACT_FLOAT] = { .nuops = 2, .uops = { { _GUARD_BOTH_FLOAT, 0, 0 }, { _BINARY_OP_SUBTRACT_FLOAT, 0, 0 } } }, - [BINARY_OP_SUBTRACT_INT] = { .nuops = 2, .uops = { { _GUARD_BOTH_INT, 0, 0 }, { _BINARY_OP_SUBTRACT_INT, 0, 0 } } }, - [BINARY_SLICE] = { .nuops = 1, .uops = { { _BINARY_SLICE, 0, 0 } } }, -- [BINARY_SUBSCR] = { .nuops = 1, .uops = { { _BINARY_SUBSCR, 0, 0 } } }, -- [BINARY_SUBSCR_DICT] = { .nuops = 1, .uops = { { _BINARY_SUBSCR_DICT, 0, 0 } } }, -- [BINARY_SUBSCR_GETITEM] = { .nuops = 4, .uops = { { _CHECK_PEP_523, 0, 0 }, { _BINARY_SUBSCR_CHECK_FUNC, 0, 0 }, { _BINARY_SUBSCR_INIT_CALL, 0, 0 }, { _PUSH_FRAME, 0, 0 } } }, -- [BINARY_SUBSCR_LIST_INT] = { .nuops = 1, .uops = { { _BINARY_SUBSCR_LIST_INT, 0, 0 } } }, -- [BINARY_SUBSCR_STR_INT] = { .nuops = 1, .uops = { { _BINARY_SUBSCR_STR_INT, 0, 0 } } }, -- [BINARY_SUBSCR_TUPLE_INT] = { .nuops = 1, .uops = { { _BINARY_SUBSCR_TUPLE_INT, 0, 0 } } }, - [BUILD_LIST] = { .nuops = 1, .uops = { { _BUILD_LIST, 0, 0 } } }, - [BUILD_MAP] = { .nuops = 1, .uops = { { _BUILD_MAP, 0, 0 } } }, - [BUILD_SET] = { .nuops = 1, .uops = { { _BUILD_SET, 0, 0 } } }, -@@ -2243,7 +2312,7 @@ - [DELETE_SUBSCR] = { .nuops = 1, .uops = { { _DELETE_SUBSCR, 0, 0 } } }, - [DICT_MERGE] = { .nuops = 1, .uops = { { _DICT_MERGE, 0, 0 } } }, - [DICT_UPDATE] = { .nuops = 1, .uops = { { _DICT_UPDATE, 0, 0 } } }, -- [END_FOR] = { .nuops = 1, .uops = { { _POP_TOP, 0, 0 } } }, -+ [END_FOR] = { .nuops = 1, .uops = { { _END_FOR, 0, 0 } } }, - [END_SEND] = { .nuops = 1, .uops = { { _END_SEND, 0, 0 } } }, - [EXIT_INIT_CHECK] = { .nuops = 1, .uops = { { _EXIT_INIT_CHECK, 0, 0 } } }, - [FORMAT_SIMPLE] = { .nuops = 1, .uops = { { _FORMAT_SIMPLE, 0, 0 } } }, -@@ -2265,31 +2334,31 @@ - [LIST_APPEND] = { .nuops = 1, .uops = { { _LIST_APPEND, 0, 0 } } }, - [LIST_EXTEND] = { .nuops = 1, .uops = { { _LIST_EXTEND, 0, 0 } } }, - [LOAD_ATTR] = { .nuops = 1, .uops = { { _LOAD_ATTR, 0, 0 } } }, -- [LOAD_ATTR_CLASS] = { .nuops = 2, .uops = { { _CHECK_ATTR_CLASS, 2, 1 }, { _LOAD_ATTR_CLASS, 4, 5 } } }, -- [LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = { .nuops = 3, .uops = { { _CHECK_ATTR_CLASS, 2, 1 }, { _GUARD_TYPE_VERSION, 2, 3 }, { _LOAD_ATTR_CLASS, 4, 5 } } }, -- [LOAD_ATTR_INSTANCE_VALUE] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_MANAGED_OBJECT_HAS_VALUES, 0, 0 }, { _LOAD_ATTR_INSTANCE_VALUE, 1, 3 } } }, -+ [LOAD_ATTR_CLASS] = { .nuops = 3, .uops = { { _CHECK_ATTR_CLASS, 2, 1 }, { _LOAD_ATTR_CLASS, 4, 5 }, { _PUSH_NULL_CONDITIONAL, 0, 0 } } }, -+ [LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = { .nuops = 4, .uops = { { _CHECK_ATTR_CLASS, 2, 1 }, { _GUARD_TYPE_VERSION, 2, 3 }, { _LOAD_ATTR_CLASS, 4, 5 }, { _PUSH_NULL_CONDITIONAL, 0, 0 } } }, -+ [LOAD_ATTR_INSTANCE_VALUE] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_MANAGED_OBJECT_HAS_VALUES, 0, 0 }, { _LOAD_ATTR_INSTANCE_VALUE, 1, 3 }, { _PUSH_NULL_CONDITIONAL, 0, 0 } } }, - [LOAD_ATTR_METHOD_LAZY_DICT] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_ATTR_METHOD_LAZY_DICT, 1, 3 }, { _LOAD_ATTR_METHOD_LAZY_DICT, 4, 5 } } }, - [LOAD_ATTR_METHOD_NO_DICT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_METHOD_NO_DICT, 4, 5 } } }, - [LOAD_ATTR_METHOD_WITH_VALUES] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, 0, 0 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_METHOD_WITH_VALUES, 4, 5 } } }, -- [LOAD_ATTR_MODULE] = { .nuops = 2, .uops = { { _CHECK_ATTR_MODULE_PUSH_KEYS, 2, 1 }, { _LOAD_ATTR_MODULE_FROM_KEYS, 1, 3 } } }, -+ [LOAD_ATTR_MODULE] = { .nuops = 3, .uops = { { _CHECK_ATTR_MODULE_PUSH_KEYS, 2, 1 }, { _LOAD_ATTR_MODULE_FROM_KEYS, 1, 3 }, { _PUSH_NULL_CONDITIONAL, 0, 0 } } }, - [LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_NONDESCRIPTOR_NO_DICT, 4, 5 } } }, - [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, 0, 0 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, 4, 5 } } }, - [LOAD_ATTR_PROPERTY] = { .nuops = 5, .uops = { { _CHECK_PEP_523, 0, 0 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_PROPERTY_FRAME, 4, 5 }, { _SAVE_RETURN_OFFSET, 7, 9 }, { _PUSH_FRAME, 0, 0 } } }, -- [LOAD_ATTR_SLOT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_SLOT, 1, 3 } } }, -- [LOAD_ATTR_WITH_HINT] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_ATTR_WITH_HINT, 0, 0 }, { _LOAD_ATTR_WITH_HINT, 1, 3 } } }, -+ [LOAD_ATTR_SLOT] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_SLOT, 1, 3 }, { _PUSH_NULL_CONDITIONAL, 0, 0 } } }, -+ [LOAD_ATTR_WITH_HINT] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_ATTR_WITH_HINT, 0, 0 }, { _LOAD_ATTR_WITH_HINT, 1, 3 }, { _PUSH_NULL_CONDITIONAL, 0, 0 } } }, - [LOAD_BUILD_CLASS] = { .nuops = 1, .uops = { { _LOAD_BUILD_CLASS, 0, 0 } } }, - [LOAD_COMMON_CONSTANT] = { .nuops = 1, .uops = { { _LOAD_COMMON_CONSTANT, 0, 0 } } }, -- [LOAD_CONST] = { .nuops = 1, .uops = { { _LOAD_CONST, 0, 0 } } }, - [LOAD_CONST_IMMORTAL] = { .nuops = 1, .uops = { { _LOAD_CONST_IMMORTAL, 0, 0 } } }, -+ [LOAD_CONST_MORTAL] = { .nuops = 1, .uops = { { _LOAD_CONST_MORTAL, 0, 0 } } }, - [LOAD_DEREF] = { .nuops = 1, .uops = { { _LOAD_DEREF, 0, 0 } } }, - [LOAD_FAST] = { .nuops = 1, .uops = { { _LOAD_FAST, 0, 0 } } }, - [LOAD_FAST_AND_CLEAR] = { .nuops = 1, .uops = { { _LOAD_FAST_AND_CLEAR, 0, 0 } } }, - [LOAD_FAST_CHECK] = { .nuops = 1, .uops = { { _LOAD_FAST_CHECK, 0, 0 } } }, - [LOAD_FAST_LOAD_FAST] = { .nuops = 2, .uops = { { _LOAD_FAST, 5, 0 }, { _LOAD_FAST, 6, 0 } } }, - [LOAD_FROM_DICT_OR_DEREF] = { .nuops = 1, .uops = { { _LOAD_FROM_DICT_OR_DEREF, 0, 0 } } }, -- [LOAD_GLOBAL] = { .nuops = 1, .uops = { { _LOAD_GLOBAL, 0, 0 } } }, -- [LOAD_GLOBAL_BUILTIN] = { .nuops = 3, .uops = { { _GUARD_GLOBALS_VERSION, 1, 1 }, { _GUARD_BUILTINS_VERSION_PUSH_KEYS, 1, 2 }, { _LOAD_GLOBAL_BUILTINS_FROM_KEYS, 1, 3 } } }, -- [LOAD_GLOBAL_MODULE] = { .nuops = 2, .uops = { { _GUARD_GLOBALS_VERSION_PUSH_KEYS, 1, 1 }, { _LOAD_GLOBAL_MODULE_FROM_KEYS, 1, 3 } } }, -+ [LOAD_GLOBAL] = { .nuops = 2, .uops = { { _LOAD_GLOBAL, 0, 0 }, { _PUSH_NULL_CONDITIONAL, 0, 0 } } }, -+ [LOAD_GLOBAL_BUILTIN] = { .nuops = 4, .uops = { { _GUARD_GLOBALS_VERSION, 1, 1 }, { _GUARD_BUILTINS_VERSION_PUSH_KEYS, 1, 2 }, { _LOAD_GLOBAL_BUILTINS_FROM_KEYS, 1, 3 }, { _PUSH_NULL_CONDITIONAL, 0, 0 } } }, -+ [LOAD_GLOBAL_MODULE] = { .nuops = 3, .uops = { { _GUARD_GLOBALS_VERSION_PUSH_KEYS, 1, 1 }, { _LOAD_GLOBAL_MODULE_FROM_KEYS, 1, 3 }, { _PUSH_NULL_CONDITIONAL, 0, 0 } } }, - [LOAD_LOCALS] = { .nuops = 1, .uops = { { _LOAD_LOCALS, 0, 0 } } }, - [LOAD_NAME] = { .nuops = 1, .uops = { { _LOAD_NAME, 0, 0 } } }, - [LOAD_SMALL_INT] = { .nuops = 1, .uops = { { _LOAD_SMALL_INT, 0, 0 } } }, -@@ -2304,7 +2373,9 @@ - [MATCH_MAPPING] = { .nuops = 1, .uops = { { _MATCH_MAPPING, 0, 0 } } }, - [MATCH_SEQUENCE] = { .nuops = 1, .uops = { { _MATCH_SEQUENCE, 0, 0 } } }, - [NOP] = { .nuops = 1, .uops = { { _NOP, 0, 0 } } }, -+ [NOT_TAKEN] = { .nuops = 1, .uops = { { _NOP, 0, 0 } } }, - [POP_EXCEPT] = { .nuops = 1, .uops = { { _POP_EXCEPT, 0, 0 } } }, -+ [POP_ITER] = { .nuops = 1, .uops = { { _POP_TOP, 0, 0 } } }, - [POP_JUMP_IF_FALSE] = { .nuops = 1, .uops = { { _POP_JUMP_IF_FALSE, 9, 1 } } }, - [POP_JUMP_IF_NONE] = { .nuops = 2, .uops = { { _IS_NONE, 0, 0 }, { _POP_JUMP_IF_TRUE, 9, 1 } } }, - [POP_JUMP_IF_NOT_NONE] = { .nuops = 2, .uops = { { _IS_NONE, 0, 0 }, { _POP_JUMP_IF_FALSE, 9, 1 } } }, -@@ -2321,7 +2392,7 @@ - [SET_FUNCTION_ATTRIBUTE] = { .nuops = 1, .uops = { { _SET_FUNCTION_ATTRIBUTE, 0, 0 } } }, - [SET_UPDATE] = { .nuops = 1, .uops = { { _SET_UPDATE, 0, 0 } } }, - [STORE_ATTR] = { .nuops = 1, .uops = { { _STORE_ATTR, 0, 0 } } }, -- [STORE_ATTR_INSTANCE_VALUE] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_NO_DICT, 0, 0 }, { _STORE_ATTR_INSTANCE_VALUE, 1, 3 } } }, -+ [STORE_ATTR_INSTANCE_VALUE] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION_AND_LOCK, 2, 1 }, { _GUARD_DORV_NO_DICT, 0, 0 }, { _STORE_ATTR_INSTANCE_VALUE, 1, 3 } } }, - [STORE_ATTR_SLOT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _STORE_ATTR_SLOT, 1, 3 } } }, - [STORE_ATTR_WITH_HINT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _STORE_ATTR_WITH_HINT, 1, 3 } } }, - [STORE_DEREF] = { .nuops = 1, .uops = { { _STORE_DEREF, 0, 0 } } }, -@@ -2362,18 +2433,18 @@ - [BINARY_OP_ADD_FLOAT] = "BINARY_OP_ADD_FLOAT", - [BINARY_OP_ADD_INT] = "BINARY_OP_ADD_INT", - [BINARY_OP_ADD_UNICODE] = "BINARY_OP_ADD_UNICODE", -+ [BINARY_OP_EXTEND] = "BINARY_OP_EXTEND", - [BINARY_OP_INPLACE_ADD_UNICODE] = "BINARY_OP_INPLACE_ADD_UNICODE", - [BINARY_OP_MULTIPLY_FLOAT] = "BINARY_OP_MULTIPLY_FLOAT", - [BINARY_OP_MULTIPLY_INT] = "BINARY_OP_MULTIPLY_INT", -+ [BINARY_OP_SUBSCR_DICT] = "BINARY_OP_SUBSCR_DICT", -+ [BINARY_OP_SUBSCR_GETITEM] = "BINARY_OP_SUBSCR_GETITEM", -+ [BINARY_OP_SUBSCR_LIST_INT] = "BINARY_OP_SUBSCR_LIST_INT", -+ [BINARY_OP_SUBSCR_STR_INT] = "BINARY_OP_SUBSCR_STR_INT", -+ [BINARY_OP_SUBSCR_TUPLE_INT] = "BINARY_OP_SUBSCR_TUPLE_INT", - [BINARY_OP_SUBTRACT_FLOAT] = "BINARY_OP_SUBTRACT_FLOAT", - [BINARY_OP_SUBTRACT_INT] = "BINARY_OP_SUBTRACT_INT", - [BINARY_SLICE] = "BINARY_SLICE", -- [BINARY_SUBSCR] = "BINARY_SUBSCR", -- [BINARY_SUBSCR_DICT] = "BINARY_SUBSCR_DICT", -- [BINARY_SUBSCR_GETITEM] = "BINARY_SUBSCR_GETITEM", -- [BINARY_SUBSCR_LIST_INT] = "BINARY_SUBSCR_LIST_INT", -- [BINARY_SUBSCR_STR_INT] = "BINARY_SUBSCR_STR_INT", -- [BINARY_SUBSCR_TUPLE_INT] = "BINARY_SUBSCR_TUPLE_INT", - [BUILD_LIST] = "BUILD_LIST", - [BUILD_MAP] = "BUILD_MAP", - [BUILD_SET] = "BUILD_SET", -@@ -2462,6 +2533,8 @@ - [INSTRUMENTED_JUMP_FORWARD] = "INSTRUMENTED_JUMP_FORWARD", - [INSTRUMENTED_LINE] = "INSTRUMENTED_LINE", - [INSTRUMENTED_LOAD_SUPER_ATTR] = "INSTRUMENTED_LOAD_SUPER_ATTR", -+ [INSTRUMENTED_NOT_TAKEN] = "INSTRUMENTED_NOT_TAKEN", -+ [INSTRUMENTED_POP_ITER] = "INSTRUMENTED_POP_ITER", - [INSTRUMENTED_POP_JUMP_IF_FALSE] = "INSTRUMENTED_POP_JUMP_IF_FALSE", - [INSTRUMENTED_POP_JUMP_IF_NONE] = "INSTRUMENTED_POP_JUMP_IF_NONE", - [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = "INSTRUMENTED_POP_JUMP_IF_NOT_NONE", -@@ -2473,7 +2546,9 @@ - [IS_OP] = "IS_OP", - [JUMP] = "JUMP", - [JUMP_BACKWARD] = "JUMP_BACKWARD", -+ [JUMP_BACKWARD_JIT] = "JUMP_BACKWARD_JIT", - [JUMP_BACKWARD_NO_INTERRUPT] = "JUMP_BACKWARD_NO_INTERRUPT", -+ [JUMP_BACKWARD_NO_JIT] = "JUMP_BACKWARD_NO_JIT", - [JUMP_FORWARD] = "JUMP_FORWARD", - [JUMP_IF_FALSE] = "JUMP_IF_FALSE", - [JUMP_IF_TRUE] = "JUMP_IF_TRUE", -@@ -2499,6 +2574,7 @@ - [LOAD_COMMON_CONSTANT] = "LOAD_COMMON_CONSTANT", - [LOAD_CONST] = "LOAD_CONST", - [LOAD_CONST_IMMORTAL] = "LOAD_CONST_IMMORTAL", -+ [LOAD_CONST_MORTAL] = "LOAD_CONST_MORTAL", - [LOAD_DEREF] = "LOAD_DEREF", - [LOAD_FAST] = "LOAD_FAST", - [LOAD_FAST_AND_CLEAR] = "LOAD_FAST_AND_CLEAR", -@@ -2524,8 +2600,10 @@ - [MATCH_MAPPING] = "MATCH_MAPPING", - [MATCH_SEQUENCE] = "MATCH_SEQUENCE", - [NOP] = "NOP", -+ [NOT_TAKEN] = "NOT_TAKEN", - [POP_BLOCK] = "POP_BLOCK", - [POP_EXCEPT] = "POP_EXCEPT", -+ [POP_ITER] = "POP_ITER", - [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE", - [POP_JUMP_IF_NONE] = "POP_JUMP_IF_NONE", - [POP_JUMP_IF_NOT_NONE] = "POP_JUMP_IF_NOT_NONE", -@@ -2589,7 +2667,6 @@ - #ifdef NEED_OPCODE_METADATA - const uint8_t _PyOpcode_Caches[256] = { - [TO_BOOL] = 3, -- [BINARY_SUBSCR] = 1, - [STORE_SUBSCR] = 1, - [SEND] = 1, - [UNPACK_SEQUENCE] = 1, -@@ -2607,7 +2684,7 @@ - [FOR_ITER] = 1, - [CALL] = 3, - [CALL_KW] = 3, -- [BINARY_OP] = 1, -+ [BINARY_OP] = 5, - }; - #endif - -@@ -2618,18 +2695,18 @@ - [BINARY_OP_ADD_FLOAT] = BINARY_OP, - [BINARY_OP_ADD_INT] = BINARY_OP, - [BINARY_OP_ADD_UNICODE] = BINARY_OP, -+ [BINARY_OP_EXTEND] = BINARY_OP, - [BINARY_OP_INPLACE_ADD_UNICODE] = BINARY_OP, - [BINARY_OP_MULTIPLY_FLOAT] = BINARY_OP, - [BINARY_OP_MULTIPLY_INT] = BINARY_OP, -+ [BINARY_OP_SUBSCR_DICT] = BINARY_OP, -+ [BINARY_OP_SUBSCR_GETITEM] = BINARY_OP, -+ [BINARY_OP_SUBSCR_LIST_INT] = BINARY_OP, -+ [BINARY_OP_SUBSCR_STR_INT] = BINARY_OP, -+ [BINARY_OP_SUBSCR_TUPLE_INT] = BINARY_OP, - [BINARY_OP_SUBTRACT_FLOAT] = BINARY_OP, - [BINARY_OP_SUBTRACT_INT] = BINARY_OP, - [BINARY_SLICE] = BINARY_SLICE, -- [BINARY_SUBSCR] = BINARY_SUBSCR, -- [BINARY_SUBSCR_DICT] = BINARY_SUBSCR, -- [BINARY_SUBSCR_GETITEM] = BINARY_SUBSCR, -- [BINARY_SUBSCR_LIST_INT] = BINARY_SUBSCR, -- [BINARY_SUBSCR_STR_INT] = BINARY_SUBSCR, -- [BINARY_SUBSCR_TUPLE_INT] = BINARY_SUBSCR, - [BUILD_LIST] = BUILD_LIST, - [BUILD_MAP] = BUILD_MAP, - [BUILD_SET] = BUILD_SET, -@@ -2718,6 +2795,8 @@ - [INSTRUMENTED_JUMP_FORWARD] = INSTRUMENTED_JUMP_FORWARD, - [INSTRUMENTED_LINE] = INSTRUMENTED_LINE, - [INSTRUMENTED_LOAD_SUPER_ATTR] = INSTRUMENTED_LOAD_SUPER_ATTR, -+ [INSTRUMENTED_NOT_TAKEN] = INSTRUMENTED_NOT_TAKEN, -+ [INSTRUMENTED_POP_ITER] = INSTRUMENTED_POP_ITER, - [INSTRUMENTED_POP_JUMP_IF_FALSE] = INSTRUMENTED_POP_JUMP_IF_FALSE, - [INSTRUMENTED_POP_JUMP_IF_NONE] = INSTRUMENTED_POP_JUMP_IF_NONE, - [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = INSTRUMENTED_POP_JUMP_IF_NOT_NONE, -@@ -2728,7 +2807,9 @@ - [INTERPRETER_EXIT] = INTERPRETER_EXIT, - [IS_OP] = IS_OP, - [JUMP_BACKWARD] = JUMP_BACKWARD, -+ [JUMP_BACKWARD_JIT] = JUMP_BACKWARD, - [JUMP_BACKWARD_NO_INTERRUPT] = JUMP_BACKWARD_NO_INTERRUPT, -+ [JUMP_BACKWARD_NO_JIT] = JUMP_BACKWARD, - [JUMP_FORWARD] = JUMP_FORWARD, - [LIST_APPEND] = LIST_APPEND, - [LIST_EXTEND] = LIST_EXTEND, -@@ -2750,6 +2831,7 @@ - [LOAD_COMMON_CONSTANT] = LOAD_COMMON_CONSTANT, - [LOAD_CONST] = LOAD_CONST, - [LOAD_CONST_IMMORTAL] = LOAD_CONST, -+ [LOAD_CONST_MORTAL] = LOAD_CONST, - [LOAD_DEREF] = LOAD_DEREF, - [LOAD_FAST] = LOAD_FAST, - [LOAD_FAST_AND_CLEAR] = LOAD_FAST_AND_CLEAR, -@@ -2775,7 +2857,9 @@ - [MATCH_MAPPING] = MATCH_MAPPING, - [MATCH_SEQUENCE] = MATCH_SEQUENCE, - [NOP] = NOP, -+ [NOT_TAKEN] = NOT_TAKEN, - [POP_EXCEPT] = POP_EXCEPT, -+ [POP_ITER] = POP_ITER, - [POP_JUMP_IF_FALSE] = POP_JUMP_IF_FALSE, - [POP_JUMP_IF_NONE] = POP_JUMP_IF_NONE, - [POP_JUMP_IF_NOT_NONE] = POP_JUMP_IF_NOT_NONE, -@@ -2833,7 +2917,6 @@ - #endif // NEED_OPCODE_METADATA - - #define EXTRA_CASES \ -- case 116: \ - case 117: \ - case 118: \ - case 119: \ -@@ -2866,15 +2949,9 @@ - case 146: \ - case 147: \ - case 148: \ -- case 228: \ -- case 229: \ -- case 230: \ -- case 231: \ - case 232: \ - case 233: \ - case 234: \ -- case 235: \ -- case 236: \ - ; - struct pseudo_targets { - uint8_t as_sequence; -diff --git a/Include/internal/pycore_opcode_utils.h b/Include/internal/pycore_opcode_utils.h -index c6ce7e65a65..0872231d1f2 100644 ---- a/Include/internal/pycore_opcode_utils.h -+++ b/Include/internal/pycore_opcode_utils.h -@@ -45,6 +45,12 @@ - (opcode) == JUMP_BACKWARD || \ - (opcode) == JUMP_BACKWARD_NO_INTERRUPT) - -+#define IS_CONDITIONAL_JUMP_OPCODE(opcode) \ -+ ((opcode) == POP_JUMP_IF_FALSE || \ -+ (opcode) == POP_JUMP_IF_TRUE || \ -+ (opcode) == POP_JUMP_IF_NONE || \ -+ (opcode) == POP_JUMP_IF_NOT_NONE) + vals = system, node, release, version, machine + # Replace 'unknown' values with the more portable '' +@@ -1343,6 +1406,10 @@ + # macOS and iOS both report as a "Darwin" kernel + if sys.platform == "ios": + system, release, _, _ = ios_ver() ++ elif sys.platform == "tvos": ++ system, release, _, _ = tvos_ver() ++ elif sys.platform == "watchos": ++ system, release, _, _ = watchos_ver() + else: + macos_release = mac_ver()[0] + if macos_release: +diff --git a/Lib/sysconfig/__init__.py b/Lib/sysconfig/__init__.py +index 69f72452c40..34ce643340b 100644 +--- a/Lib/sysconfig/__init__.py ++++ b/Lib/sysconfig/__init__.py +@@ -719,6 +719,14 @@ + release = get_config_vars().get("IPHONEOS_DEPLOYMENT_TARGET", "13.0") + osname = sys.platform + machine = sys.implementation._multiarch ++ elif sys.platform == "tvos": ++ release = get_config_vars().get("TVOS_DEPLOYMENT_TARGET", "9.0") ++ osname = sys.platform ++ machine = sys.implementation._multiarch ++ elif sys.platform == "watchos": ++ release = get_config_vars().get("WATCHOS_DEPLOYMENT_TARGET", "4.0") ++ osname = sys.platform ++ machine = sys.implementation._multiarch + else: + import _osx_support + osname, release, machine = _osx_support.get_platform_osx( +diff --git a/Misc/platform_triplet.c b/Misc/platform_triplet.c +index ec0857a4a99..190670f271d 100644 +--- a/Misc/platform_triplet.c ++++ b/Misc/platform_triplet.c +@@ -254,9 +254,55 @@ + # else + PLATFORM_TRIPLET=arm64-iphonesimulator + # endif ++# elif defined(TARGET_OS_MACCATALYST) && TARGET_OS_MACCATALYST ++# if __x86_64__ ++PLATFORM_TRIPLET=x86_64-iphoneos-macabi ++# else ++PLATFORM_TRIPLET=arm64-iphoneos-macabi ++# endif + # else + PLATFORM_TRIPLET=arm64-iphoneos + # endif ++# elif defined(TARGET_OS_TV) && TARGET_OS_TV ++# if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR ++# if __x86_64__ ++PLATFORM_TRIPLET=x86_64-appletvsimulator ++# else ++PLATFORM_TRIPLET=arm64-appletvsimulator ++# endif ++# else ++PLATFORM_TRIPLET=arm64-appletvos ++# endif ++# elif defined(TARGET_OS_WATCH) && TARGET_OS_WATCH ++# if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR ++# if __x86_64__ ++PLATFORM_TRIPLET=x86_64-watchsimulator ++# else ++PLATFORM_TRIPLET=arm64-watchsimulator ++# endif ++# else ++PLATFORM_TRIPLET=arm64_32-watchos ++# endif ++# elif defined(TARGET_OS_TV) && TARGET_OS_TV ++# if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR ++# if __x86_64__ ++PLATFORM_TRIPLET=x86_64-appletvsimulator ++# else ++PLATFORM_TRIPLET=arm64-appletvsimulator ++# endif ++# else ++PLATFORM_TRIPLET=arm64-appletvos ++# endif ++# elif defined(TARGET_OS_WATCH) && TARGET_OS_WATCH ++# if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR ++# if __x86_64__ ++PLATFORM_TRIPLET=x86_64-watchsimulator ++# else ++PLATFORM_TRIPLET=arm64-watchsimulator ++# endif ++# else ++PLATFORM_TRIPLET=arm64_32-watchos ++# endif + // Older macOS SDKs do not define TARGET_OS_OSX + # elif !defined(TARGET_OS_OSX) || TARGET_OS_OSX + PLATFORM_TRIPLET=darwin +diff --git a/config.sub b/config.sub +index 1bb6a05dc11..7e007ac54c3 100755 +--- a/config.sub ++++ b/config.sub +@@ -1769,7 +1769,7 @@ + | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ + | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \ + | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr* \ +- | fiwix* | mlibc* | cos* | mbr* | ironclad* ) ++ | fiwix* | mlibc* | cos* | mbr* | ironclad* | macabi) + ;; + # This one is extra strict with allowed versions + sco3.2v2 | sco3.2v[4-9]* | sco5v6*) +@@ -1869,6 +1869,8 @@ + ;; + ios*-simulator- | tvos*-simulator- | watchos*-simulator- ) + ;; ++ ios*-macabi- ) ++ ;; + none--*) + # None (no kernel, i.e. freestanding / bare metal), + # can be paired with an machine code file format +diff --git a/configure b/configure +index d46bc563a67..0a11bb50856 100755 +--- a/configure ++++ b/configure +@@ -907,7 +907,6 @@ + OPT + BOLT_APPLY_FLAGS + BOLT_INSTRUMENT_FLAGS +-BOLT_COMMON_FLAGS + BOLT_BINARIES + MERGE_FDATA + LLVM_BOLT +@@ -974,6 +973,8 @@ + CFLAGS + CC + HAS_XCRUN ++WATCHOS_DEPLOYMENT_TARGET ++TVOS_DEPLOYMENT_TARGET + IPHONEOS_DEPLOYMENT_TARGET + EXPORT_MACOSX_DEPLOYMENT_TARGET + CONFIGURE_MACOSX_DEPLOYMENT_TARGET +@@ -1144,7 +1145,6 @@ + CPPFLAGS + CPP + PROFILE_TASK +-BOLT_COMMON_FLAGS + BOLT_INSTRUMENT_FLAGS + BOLT_APPLY_FLAGS + LIBUUID_CFLAGS +@@ -1968,8 +1968,6 @@ + CPP C preprocessor + PROFILE_TASK + Python args for PGO generation task +- BOLT_COMMON_FLAGS +- Common arguments to llvm-bolt when instrumenting and applying + BOLT_INSTRUMENT_FLAGS + Arguments to llvm-bolt when instrumenting binaries + BOLT_APPLY_FLAGS +@@ -4100,6 +4098,12 @@ + *-apple-ios*) + ac_sys_system=iOS + ;; ++ *-apple-tvos*) ++ ac_sys_system=tvOS ++ ;; ++ *-apple-watchos*) ++ ac_sys_system=watchOS ++ ;; + *-*-darwin*) + ac_sys_system=Darwin + ;; +@@ -4181,7 +4185,7 @@ + # On cross-compile builds, configure will look for a host-specific compiler by + # prepending the user-provided host triple to the required binary name. + # +-# On iOS, this results in binaries like "arm64-apple-ios13.0-simulator-gcc", ++# On iOS/tvOS/watchOS, this results in binaries like "arm64-apple-ios13.0-simulator-gcc", + # which isn't a binary that exists, and isn't very convenient, as it contains the + # iOS version. As the default cross-compiler name won't exist, configure falls + # back to gcc, which *definitely* won't work. We're providing wrapper scripts for +@@ -4194,32 +4198,76 @@ + if test -z "$AR"; then + case "$host" in + aarch64-apple-ios*-simulator) AR=arm64-apple-ios-simulator-ar ;; ++ aarch64-apple-ios*-macabi) AR=arm64-apple-ios-macabi-ar ;; + aarch64-apple-ios*) AR=arm64-apple-ios-ar ;; + x86_64-apple-ios*-simulator) AR=x86_64-apple-ios-simulator-ar ;; + - #define IS_SCOPE_EXIT_OPCODE(opcode) \ - ((opcode) == RETURN_VALUE || \ - (opcode) == RAISE_VARARGS || \ -diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h -index bc7cfcde613..25c3d3e5a22 100644 ---- a/Include/internal/pycore_optimizer.h -+++ b/Include/internal/pycore_optimizer.h -@@ -83,28 +83,6 @@ - _PyExitData exits[1]; - } _PyExecutorObject; - --typedef struct _PyOptimizerObject _PyOptimizerObject; -- --/* Should return > 0 if a new executor is created. O if no executor is produced and < 0 if an error occurred. */ --typedef int (*_Py_optimize_func)( -- _PyOptimizerObject* self, struct _PyInterpreterFrame *frame, -- _Py_CODEUNIT *instr, _PyExecutorObject **exec_ptr, -- int curr_stackentries, bool progress_needed); -- --struct _PyOptimizerObject { -- PyObject_HEAD -- _Py_optimize_func optimize; -- /* Data needed by the optimizer goes here, but is opaque to the VM */ --}; -- --/** Test support **/ --typedef struct { -- _PyOptimizerObject base; -- int64_t count; --} _PyCounterOptimizerObject; -- --_PyOptimizerObject *_Py_SetOptimizer(PyInterpreterState *interp, _PyOptimizerObject* optimizer); -- - - // Export for '_opcode' shared extension (JIT compiler). - PyAPI_FUNC(_PyExecutorObject*) _Py_GetExecutor(PyCodeObject *code, int offset); -@@ -115,13 +93,6 @@ - void _Py_BloomFilter_Add(_PyBloomFilter *bloom, void *obj); - PyAPI_FUNC(void) _Py_Executor_DependsOn(_PyExecutorObject *executor, void *obj); - --// For testing --// Export for '_testinternalcapi' shared extension. --PyAPI_FUNC(_PyOptimizerObject *) _Py_GetOptimizer(void); --PyAPI_FUNC(int) _Py_SetTier2Optimizer(_PyOptimizerObject* optimizer); --PyAPI_FUNC(PyObject *) _PyOptimizer_NewCounter(void); --PyAPI_FUNC(PyObject *) _PyOptimizer_NewUOpOptimizer(void); -- - #define _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS 3 - #define _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS 6 - -@@ -150,21 +121,8 @@ - _PyUOpInstruction *trace, int trace_len, int curr_stackentries, - _PyBloomFilter *dependencies); - --extern PyTypeObject _PyCounterExecutor_Type; --extern PyTypeObject _PyCounterOptimizer_Type; --extern PyTypeObject _PyDefaultOptimizer_Type; - extern PyTypeObject _PyUOpExecutor_Type; --extern PyTypeObject _PyUOpOptimizer_Type; - --/* Symbols */ --/* See explanation in optimizer_symbols.c */ -- --struct _Py_UopsSymbol { -- int flags; // 0 bits: Top; 2 or more bits: Bottom -- PyTypeObject *typ; // Borrowed reference -- PyObject *const_val; // Owned reference (!) -- unsigned int type_version; // currently stores type version --}; - - #define UOP_FORMAT_TARGET 0 - #define UOP_FORMAT_JUMP 1 -@@ -201,16 +159,63 @@ - // handle before rejoining the rest of the program. - #define MAX_CHAIN_DEPTH 4 - --typedef struct _Py_UopsSymbol _Py_UopsSymbol; -+/* Symbols */ -+/* See explanation in optimizer_symbols.c */ ++ aarch64-apple-tvos*-simulator) AR=arm64-apple-tvos-simulator-ar ;; ++ aarch64-apple-tvos*-macabi) AR=arm64-apple-tvos-macabi-ar ;; ++ aarch64-apple-tvos*) AR=arm64-apple-tvos-ar ;; ++ x86_64-apple-tvos*-simulator) AR=x86_64-apple-tvos-simulator-ar ;; + ++ aarch64-apple-watchos*-simulator) AR=arm64-apple-watchos-simulator-ar ;; ++ aarch64-apple-watchos*-macabi) AR=arm64-apple-watchos-macabi-ar ;; ++ aarch64-apple-watchos*) AR=arm64_32-apple-watchos-ar ;; ++ x86_64-apple-watchos*-simulator) AR=x86_64-apple-watchos-simulator-ar ;; + *) + esac + fi + if test -z "$CC"; then + case "$host" in + aarch64-apple-ios*-simulator) CC=arm64-apple-ios-simulator-clang ;; ++ aarch64-apple-ios*-macabi) CC=arm64-apple-ios-macabi-clang ;; + aarch64-apple-ios*) CC=arm64-apple-ios-clang ;; + x86_64-apple-ios*-simulator) CC=x86_64-apple-ios-simulator-clang ;; + -+typedef enum _JitSymType { -+ JIT_SYM_UNKNOWN_TAG = 1, -+ JIT_SYM_NULL_TAG = 2, -+ JIT_SYM_NON_NULL_TAG = 3, -+ JIT_SYM_BOTTOM_TAG = 4, -+ JIT_SYM_TYPE_VERSION_TAG = 5, -+ JIT_SYM_KNOWN_CLASS_TAG = 6, -+ JIT_SYM_KNOWN_VALUE_TAG = 7, -+ JIT_SYM_TUPLE_TAG = 8, -+} JitSymType; ++ aarch64-apple-tvos*-simulator) CC=arm64-apple-tvos-simulator-clang ;; ++ aarch64-apple-tvos*-macabi) CC=arm64-apple-tvos-macabi-clang ;; ++ aarch64-apple-tvos*) CC=arm64-apple-tvos-clang ;; ++ x86_64-apple-tvos*-simulator) CC=x86_64-apple-tvos-simulator-clang ;; + -+typedef struct _jit_opt_known_class { -+ uint8_t tag; -+ uint32_t version; -+ PyTypeObject *type; -+} JitOptKnownClass; ++ aarch64-apple-watchos*-simulator) CC=arm64-apple-watchos-simulator-clang ;; ++ aarch64-apple-watchos*-macabi) CC=arm64-apple-watchos-macabi-clang ;; ++ aarch64-apple-watchos*) CC=arm64_32-apple-watchos-clang ;; ++ x86_64-apple-watchos*-simulator) CC=x86_64-apple-watchos-simulator-clang ;; + *) + esac + fi + if test -z "$CPP"; then + case "$host" in + aarch64-apple-ios*-simulator) CPP=arm64-apple-ios-simulator-cpp ;; ++ aarch64-apple-ios*-macabi) CPP=arm64-apple-ios-macabi-cpp ;; + aarch64-apple-ios*) CPP=arm64-apple-ios-cpp ;; + x86_64-apple-ios*-simulator) CPP=x86_64-apple-ios-simulator-cpp ;; + -+typedef struct _jit_opt_known_version { -+ uint8_t tag; -+ uint32_t version; -+} JitOptKnownVersion; ++ aarch64-apple-tvos*-simulator) CPP=arm64-apple-tvos-simulator-cpp ;; ++ aarch64-apple-tvos*-macabi) CPP=arm64-apple-tvos-macabi-cpp ;; ++ aarch64-apple-tvos*) CPP=arm64-apple-tvos-cpp ;; ++ x86_64-apple-tvos*-simulator) CPP=x86_64-apple-tvos-simulator-cpp ;; + -+typedef struct _jit_opt_known_value { -+ uint8_t tag; -+ PyObject *value; -+} JitOptKnownValue; -+ -+#define MAX_SYMBOLIC_TUPLE_SIZE 7 -+ -+typedef struct _jit_opt_tuple { -+ uint8_t tag; -+ uint8_t length; -+ uint16_t items[MAX_SYMBOLIC_TUPLE_SIZE]; -+} JitOptTuple; -+ -+typedef union _jit_opt_symbol { -+ uint8_t tag; -+ JitOptKnownClass cls; -+ JitOptKnownValue value; -+ JitOptKnownVersion version; -+ JitOptTuple tuple; -+} JitOptSymbol; -+ -+ - - struct _Py_UOpsAbstractFrame { - // Max stacklen - int stack_len; - int locals_len; - -- _Py_UopsSymbol **stack_pointer; -- _Py_UopsSymbol **stack; -- _Py_UopsSymbol **locals; -+ JitOptSymbol **stack_pointer; -+ JitOptSymbol **stack; -+ JitOptSymbol **locals; - }; - - typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame; -@@ -218,10 +223,10 @@ - typedef struct ty_arena { - int ty_curr_number; - int ty_max_number; -- _Py_UopsSymbol arena[TY_ARENA_SIZE]; -+ JitOptSymbol arena[TY_ARENA_SIZE]; - } ty_arena; - --struct _Py_UOpsContext { -+typedef struct _JitOptContext { - char done; - char out_of_space; - bool contradiction; -@@ -233,58 +238,58 @@ - // Arena for the symbolic types. - ty_arena t_arena; - -- _Py_UopsSymbol **n_consumed; -- _Py_UopsSymbol **limit; -- _Py_UopsSymbol *locals_and_stack[MAX_ABSTRACT_INTERP_SIZE]; --}; -- --typedef struct _Py_UOpsContext _Py_UOpsContext; -- --extern bool _Py_uop_sym_is_null(_Py_UopsSymbol *sym); --extern bool _Py_uop_sym_is_not_null(_Py_UopsSymbol *sym); --extern bool _Py_uop_sym_is_const(_Py_UopsSymbol *sym); --extern PyObject *_Py_uop_sym_get_const(_Py_UopsSymbol *sym); --extern _Py_UopsSymbol *_Py_uop_sym_new_unknown(_Py_UOpsContext *ctx); --extern _Py_UopsSymbol *_Py_uop_sym_new_not_null(_Py_UOpsContext *ctx); --extern _Py_UopsSymbol *_Py_uop_sym_new_type( -- _Py_UOpsContext *ctx, PyTypeObject *typ); --extern _Py_UopsSymbol *_Py_uop_sym_new_const(_Py_UOpsContext *ctx, PyObject *const_val); --extern _Py_UopsSymbol *_Py_uop_sym_new_null(_Py_UOpsContext *ctx); --extern bool _Py_uop_sym_has_type(_Py_UopsSymbol *sym); --extern bool _Py_uop_sym_matches_type(_Py_UopsSymbol *sym, PyTypeObject *typ); --extern bool _Py_uop_sym_matches_type_version(_Py_UopsSymbol *sym, unsigned int version); --extern void _Py_uop_sym_set_null(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym); --extern void _Py_uop_sym_set_non_null(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym); --extern void _Py_uop_sym_set_type(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym, PyTypeObject *typ); --extern bool _Py_uop_sym_set_type_version(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym, unsigned int version); --extern void _Py_uop_sym_set_const(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym, PyObject *const_val); --extern bool _Py_uop_sym_is_bottom(_Py_UopsSymbol *sym); --extern int _Py_uop_sym_truthiness(_Py_UopsSymbol *sym); --extern PyTypeObject *_Py_uop_sym_get_type(_Py_UopsSymbol *sym); -- -- --extern void _Py_uop_abstractcontext_init(_Py_UOpsContext *ctx); --extern void _Py_uop_abstractcontext_fini(_Py_UOpsContext *ctx); -+ JitOptSymbol **n_consumed; -+ JitOptSymbol **limit; -+ JitOptSymbol *locals_and_stack[MAX_ABSTRACT_INTERP_SIZE]; -+} JitOptContext; -+ -+extern bool _Py_uop_sym_is_null(JitOptSymbol *sym); -+extern bool _Py_uop_sym_is_not_null(JitOptSymbol *sym); -+extern bool _Py_uop_sym_is_const(JitOptSymbol *sym); -+extern PyObject *_Py_uop_sym_get_const(JitOptSymbol *sym); -+extern JitOptSymbol *_Py_uop_sym_new_unknown(JitOptContext *ctx); -+extern JitOptSymbol *_Py_uop_sym_new_not_null(JitOptContext *ctx); -+extern JitOptSymbol *_Py_uop_sym_new_type( -+ JitOptContext *ctx, PyTypeObject *typ); -+extern JitOptSymbol *_Py_uop_sym_new_const(JitOptContext *ctx, PyObject *const_val); -+extern JitOptSymbol *_Py_uop_sym_new_null(JitOptContext *ctx); -+extern bool _Py_uop_sym_has_type(JitOptSymbol *sym); -+extern bool _Py_uop_sym_matches_type(JitOptSymbol *sym, PyTypeObject *typ); -+extern bool _Py_uop_sym_matches_type_version(JitOptSymbol *sym, unsigned int version); -+extern void _Py_uop_sym_set_null(JitOptContext *ctx, JitOptSymbol *sym); -+extern void _Py_uop_sym_set_non_null(JitOptContext *ctx, JitOptSymbol *sym); -+extern void _Py_uop_sym_set_type(JitOptContext *ctx, JitOptSymbol *sym, PyTypeObject *typ); -+extern bool _Py_uop_sym_set_type_version(JitOptContext *ctx, JitOptSymbol *sym, unsigned int version); -+extern void _Py_uop_sym_set_const(JitOptContext *ctx, JitOptSymbol *sym, PyObject *const_val); -+extern bool _Py_uop_sym_is_bottom(JitOptSymbol *sym); -+extern int _Py_uop_sym_truthiness(JitOptSymbol *sym); -+extern PyTypeObject *_Py_uop_sym_get_type(JitOptSymbol *sym); -+extern bool _Py_uop_sym_is_immortal(JitOptSymbol *sym); -+extern JitOptSymbol *_Py_uop_sym_new_tuple(JitOptContext *ctx, int size, JitOptSymbol **args); -+extern JitOptSymbol *_Py_uop_sym_tuple_getitem(JitOptContext *ctx, JitOptSymbol *sym, int item); -+extern int _Py_uop_sym_tuple_length(JitOptSymbol *sym); -+ -+extern void _Py_uop_abstractcontext_init(JitOptContext *ctx); -+extern void _Py_uop_abstractcontext_fini(JitOptContext *ctx); - - extern _Py_UOpsAbstractFrame *_Py_uop_frame_new( -- _Py_UOpsContext *ctx, -+ JitOptContext *ctx, - PyCodeObject *co, - int curr_stackentries, -- _Py_UopsSymbol **args, -+ JitOptSymbol **args, - int arg_len); --extern int _Py_uop_frame_pop(_Py_UOpsContext *ctx); -+extern int _Py_uop_frame_pop(JitOptContext *ctx); - - PyAPI_FUNC(PyObject *) _Py_uop_symbols_test(PyObject *self, PyObject *ignored); - --PyAPI_FUNC(int) _PyOptimizer_Optimize(struct _PyInterpreterFrame *frame, _Py_CODEUNIT *start, _PyStackRef *stack_pointer, _PyExecutorObject **exec_ptr, int chain_depth); -+PyAPI_FUNC(int) _PyOptimizer_Optimize(struct _PyInterpreterFrame *frame, _Py_CODEUNIT *start, _PyExecutorObject **exec_ptr, int chain_depth); - - static inline int is_terminator(const _PyUOpInstruction *uop) - { - int opcode = uop->opcode; - return ( - opcode == _EXIT_TRACE || -- opcode == _JUMP_TO_TOP || -- opcode == _DYNAMIC_EXIT -+ opcode == _JUMP_TO_TOP - ); - } - -diff --git a/Include/internal/pycore_pyerrors.h b/Include/internal/pycore_pyerrors.h -index 02945f0e71a..fa7d9ee36d0 100644 ---- a/Include/internal/pycore_pyerrors.h -+++ b/Include/internal/pycore_pyerrors.h -@@ -130,6 +130,18 @@ - PyObject *exception, - const char *string); - -+/* -+ * Set an exception with the error message decoded from the current locale -+ * encoding (LC_CTYPE). -+ * -+ * Exceptions occurring in decoding take priority over the desired exception. -+ * -+ * Exported for '_ctypes' shared extensions. -+ */ -+PyAPI_FUNC(void) _PyErr_SetLocaleString( -+ PyObject *exception, -+ const char *string); -+ - PyAPI_FUNC(PyObject*) _PyErr_Format( - PyThreadState *tstate, - PyObject *exception, -@@ -178,6 +190,15 @@ - PyAPI_DATA(PyTypeObject) _PyExc_IncompleteInputError; - #define PyExc_IncompleteInputError ((PyObject *)(&_PyExc_IncompleteInputError)) - -+extern int _PyUnicodeError_GetParams( -+ PyObject *self, -+ PyObject **obj, -+ Py_ssize_t *objlen, -+ Py_ssize_t *start, -+ Py_ssize_t *end, -+ Py_ssize_t *slen, -+ int as_bytes); -+ - #ifdef __cplusplus - } - #endif -diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h -index 1e73e541ef8..9ec59e60f60 100644 ---- a/Include/internal/pycore_pystate.h -+++ b/Include/internal/pycore_pystate.h -@@ -182,8 +182,8 @@ - // Perform a stop-the-world pause for threads in the specified interpreter. - // - // NOTE: This is a no-op outside of Py_GIL_DISABLED builds. --extern void _PyEval_StopTheWorld(PyInterpreterState *interp); --extern void _PyEval_StartTheWorld(PyInterpreterState *interp); -+extern PyAPI_FUNC(void) _PyEval_StopTheWorld(PyInterpreterState *interp); -+extern PyAPI_FUNC(void) _PyEval_StartTheWorld(PyInterpreterState *interp); - - - static inline void -@@ -300,6 +300,19 @@ - // See also PyInterpreterState_Get() and _PyInterpreterState_GET(). - extern PyInterpreterState* _PyGILState_GetInterpreterStateUnsafe(void); - -+#ifndef NDEBUG -+/* Modern equivalent of assert(PyGILState_Check()) */ -+static inline void -+_Py_AssertHoldsTstateFunc(const char *func) -+{ -+ PyThreadState *tstate = _PyThreadState_GET(); -+ _Py_EnsureFuncTstateNotNULL(func, tstate); -+} -+#define _Py_AssertHoldsTstate() _Py_AssertHoldsTstateFunc(__func__) -+#else -+#define _Py_AssertHoldsTstate() -+#endif -+ - #ifdef __cplusplus - } - #endif -diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h -index 86d024535fd..cf123791eba 100644 ---- a/Include/internal/pycore_runtime.h -+++ b/Include/internal/pycore_runtime.h -@@ -172,7 +172,7 @@ - #if defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE) - // Used in "Python/emscripten_trampoline.c" to choose between type - // reflection trampoline and EM_JS trampoline. -- bool wasm_type_reflection_available; -+ int (*emscripten_count_args_function)(PyCFunctionWithKeywords func); - #endif - - /* All the objects that are shared by the runtime's interpreters. */ -diff --git a/Include/internal/pycore_stackref.h b/Include/internal/pycore_stackref.h -index 90a3118352f..1ae62cc69bb 100644 ---- a/Include/internal/pycore_stackref.h -+++ b/Include/internal/pycore_stackref.h -@@ -4,6 +4,9 @@ - extern "C" { - #endif - -+// Define this to get precise tracking of stackrefs. -+// #define Py_STACKREF_DEBUG 1 -+ - #ifndef Py_BUILD_CORE - # error "this header requires Py_BUILD_CORE define" - #endif -@@ -49,6 +52,113 @@ - CPython refcounting operations on it! - */ - -+ -+#if !defined(Py_GIL_DISABLED) && defined(Py_STACKREF_DEBUG) -+ -+ -+ -+typedef union _PyStackRef { -+ uint64_t index; -+} _PyStackRef; -+ -+#define Py_TAG_BITS 0 -+ -+PyAPI_FUNC(PyObject *) _Py_stackref_get_object(_PyStackRef ref); -+PyAPI_FUNC(PyObject *) _Py_stackref_close(_PyStackRef ref); -+PyAPI_FUNC(_PyStackRef) _Py_stackref_create(PyObject *obj, const char *filename, int linenumber); -+PyAPI_FUNC(void) _Py_stackref_record_borrow(_PyStackRef ref, const char *filename, int linenumber); -+extern void _Py_stackref_associate(PyInterpreterState *interp, PyObject *obj, _PyStackRef ref); -+ -+static const _PyStackRef PyStackRef_NULL = { .index = 0 }; -+ -+#define PyStackRef_None ((_PyStackRef){ .index = 1 } ) -+#define PyStackRef_False ((_PyStackRef){ .index = 2 }) -+#define PyStackRef_True ((_PyStackRef){ .index = 3 }) -+ -+#define LAST_PREDEFINED_STACKREF_INDEX 3 -+ -+static inline int -+PyStackRef_IsNull(_PyStackRef ref) -+{ -+ return ref.index == 0; -+} -+ -+static inline int -+PyStackRef_IsTrue(_PyStackRef ref) -+{ -+ return _Py_stackref_get_object(ref) == Py_True; -+} -+ -+static inline int -+PyStackRef_IsFalse(_PyStackRef ref) -+{ -+ return _Py_stackref_get_object(ref) == Py_False; -+} -+ -+static inline int -+PyStackRef_IsNone(_PyStackRef ref) -+{ -+ return _Py_stackref_get_object(ref) == Py_None; -+} -+ -+static inline PyObject * -+_PyStackRef_AsPyObjectBorrow(_PyStackRef ref, const char *filename, int linenumber) -+{ -+ _Py_stackref_record_borrow(ref, filename, linenumber); -+ return _Py_stackref_get_object(ref); -+} -+ -+#define PyStackRef_AsPyObjectBorrow(REF) _PyStackRef_AsPyObjectBorrow((REF), __FILE__, __LINE__) -+ -+static inline PyObject * -+PyStackRef_AsPyObjectSteal(_PyStackRef ref) -+{ -+ return _Py_stackref_close(ref); -+} -+ -+static inline _PyStackRef -+_PyStackRef_FromPyObjectNew(PyObject *obj, const char *filename, int linenumber) -+{ -+ Py_INCREF(obj); -+ return _Py_stackref_create(obj, filename, linenumber); -+} -+#define PyStackRef_FromPyObjectNew(obj) _PyStackRef_FromPyObjectNew(_PyObject_CAST(obj), __FILE__, __LINE__) -+ -+static inline _PyStackRef -+_PyStackRef_FromPyObjectSteal(PyObject *obj, const char *filename, int linenumber) -+{ -+ return _Py_stackref_create(obj, filename, linenumber); -+} -+#define PyStackRef_FromPyObjectSteal(obj) _PyStackRef_FromPyObjectSteal(_PyObject_CAST(obj), __FILE__, __LINE__) -+ -+static inline _PyStackRef -+_PyStackRef_FromPyObjectImmortal(PyObject *obj, const char *filename, int linenumber) -+{ -+ assert(_Py_IsImmortal(obj)); -+ return _Py_stackref_create(obj, filename, linenumber); -+} -+#define PyStackRef_FromPyObjectImmortal(obj) _PyStackRef_FromPyObjectImmortal(_PyObject_CAST(obj), __FILE__, __LINE__) -+ -+static inline void -+PyStackRef_CLOSE(_PyStackRef ref) -+{ -+ PyObject *obj = _Py_stackref_close(ref); -+ Py_DECREF(obj); -+} -+ -+static inline _PyStackRef -+_PyStackRef_DUP(_PyStackRef ref, const char *filename, int linenumber) -+{ -+ PyObject *obj = _Py_stackref_get_object(ref); -+ Py_INCREF(obj); -+ return _Py_stackref_create(obj, filename, linenumber); -+} -+#define PyStackRef_DUP(REF) _PyStackRef_DUP(REF, __FILE__, __LINE__) -+ -+#define PyStackRef_CLOSE_SPECIALIZED(stackref, dealloc) PyStackRef_CLOSE(stackref) -+ -+#else -+ - typedef union _PyStackRef { - uintptr_t bits; - } _PyStackRef; -@@ -200,12 +310,15 @@ - #define PyStackRef_IsTrue(ref) (PyStackRef_AsPyObjectBorrow(ref) == Py_True) - #define PyStackRef_IsFalse(ref) (PyStackRef_AsPyObjectBorrow(ref) == Py_False) - -+#endif -+ - // Converts a PyStackRef back to a PyObject *, converting the - // stackref to a new reference. - #define PyStackRef_AsPyObjectNew(stackref) Py_NewRef(PyStackRef_AsPyObjectBorrow(stackref)) - - #define PyStackRef_TYPE(stackref) Py_TYPE(PyStackRef_AsPyObjectBorrow(stackref)) - -+ - #define PyStackRef_CLEAR(op) \ - do { \ - _PyStackRef *_tmp_op_ptr = &(op); \ -diff --git a/Include/internal/pycore_symtable.h b/Include/internal/pycore_symtable.h -index 91dac767d58..b7e27429611 100644 ---- a/Include/internal/pycore_symtable.h -+++ b/Include/internal/pycore_symtable.h -@@ -124,6 +124,7 @@ - unsigned ste_can_see_class_scope : 1; /* true if this block can see names bound in an - enclosing class scope */ - unsigned ste_has_docstring : 1; /* true if docstring present */ -+ unsigned ste_method : 1; /* true if block is a function block defined in class scope */ - int ste_comp_iter_expr; /* non-zero if visiting a comprehension range expression */ - _Py_SourceLocation ste_loc; /* source location of block */ - struct _symtable_entry *ste_annotation_block; /* symbol table entry for this entry's annotations */ -diff --git a/Include/internal/pycore_tracemalloc.h b/Include/internal/pycore_tracemalloc.h -index 7ddc5bac5d1..572e8025876 100644 ---- a/Include/internal/pycore_tracemalloc.h -+++ b/Include/internal/pycore_tracemalloc.h -@@ -11,10 +11,6 @@ - #include "pycore_hashtable.h" // _Py_hashtable_t - - --/* Trace memory blocks allocated by PyMem_RawMalloc() */ --#define TRACE_RAW_MALLOC -- -- - struct _PyTraceMalloc_Config { - /* Module initialized? - Variable protected by the GIL */ -@@ -25,7 +21,7 @@ - } initialized; - - /* Is tracemalloc tracing memory allocations? -- Variable protected by the GIL */ -+ Variable protected by the TABLES_LOCK(). */ - int tracing; - - /* limit of the number of frames in a traceback, 1 by default. -@@ -74,9 +70,7 @@ - PyMemAllocatorEx obj; - } allocators; - --#if defined(TRACE_RAW_MALLOC) -- PyThread_type_lock tables_lock; --#endif -+ PyMutex tables_lock; - /* Size in bytes of currently traced memory. - Protected by TABLES_LOCK(). */ - size_t traced_memory; -@@ -85,14 +79,14 @@ - size_t peak_traced_memory; - /* Hash table used as a set to intern filenames: - PyObject* => PyObject*. -- Protected by the GIL */ -+ Protected by the TABLES_LOCK(). */ - _Py_hashtable_t *filenames; - /* Buffer to store a new traceback in traceback_new(). -- Protected by the GIL. */ -+ Protected by the TABLES_LOCK(). */ - struct tracemalloc_traceback *traceback; - /* Hash table used as a set to intern tracebacks: - traceback_t* => traceback_t* -- Protected by the GIL */ -+ Protected by the TABLES_LOCK(). */ - _Py_hashtable_t *tracebacks; - /* pointer (void*) => trace (trace_t*). - Protected by TABLES_LOCK(). */ -@@ -144,7 +138,7 @@ - extern PyObject* _PyTraceMalloc_GetObjectTraceback(PyObject *obj); - - /* Initialize tracemalloc */ --extern int _PyTraceMalloc_Init(void); -+extern PyStatus _PyTraceMalloc_Init(void); - - /* Start tracemalloc */ - extern int _PyTraceMalloc_Start(int max_nframe); -diff --git a/Include/internal/pycore_tstate.h b/Include/internal/pycore_tstate.h -index b8bea72baea..932623f54c4 100644 ---- a/Include/internal/pycore_tstate.h -+++ b/Include/internal/pycore_tstate.h -@@ -22,10 +22,16 @@ - PyThreadState base; - - PyObject *asyncio_running_loop; // Strong reference -+ PyObject *asyncio_running_task; // Strong reference - -+ /* Head of circular linked-list of all tasks which are instances of `asyncio.Task` -+ or subclasses of it used in `asyncio.all_tasks`. -+ */ -+ struct llist_node asyncio_tasks_head; - struct _qsbr_thread_state *qsbr; // only used by free-threaded build - struct llist_node mem_free_queue; // delayed free queue - -+ - #ifdef Py_GIL_DISABLED - struct _gc_thread_state gc; - struct _mimalloc_thread_state mimalloc; -diff --git a/Include/internal/pycore_tuple.h b/Include/internal/pycore_tuple.h -index 82b875241f4..dc68d6648b9 100644 ---- a/Include/internal/pycore_tuple.h -+++ b/Include/internal/pycore_tuple.h -@@ -21,7 +21,7 @@ - #define _PyTuple_ITEMS(op) _Py_RVALUE(_PyTuple_CAST(op)->ob_item) - - PyAPI_FUNC(PyObject *)_PyTuple_FromArray(PyObject *const *, Py_ssize_t); --PyAPI_FUNC(PyObject *)_PyTuple_FromStackRefSteal(const union _PyStackRef *, Py_ssize_t); -+PyAPI_FUNC(PyObject *)_PyTuple_FromStackRefStealOnSuccess(const union _PyStackRef *, Py_ssize_t); - PyAPI_FUNC(PyObject *)_PyTuple_FromArraySteal(PyObject *const *, Py_ssize_t); - - typedef struct { -diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h -index 7b39d07f976..581153344a8 100644 ---- a/Include/internal/pycore_typeobject.h -+++ b/Include/internal/pycore_typeobject.h -@@ -278,6 +278,7 @@ - // and if the validation is passed, it will set the ``tp_version`` as valid - // tp_version_tag from the ``ty``. - extern int _PyType_Validate(PyTypeObject *ty, _py_validate_type validate, unsigned int *tp_version); -+extern int _PyType_CacheGetItemForSpecialization(PyHeapTypeObject *ht, PyObject *descriptor, uint32_t tp_version); - - #ifdef __cplusplus - } -diff --git a/Include/internal/pycore_uniqueid.h b/Include/internal/pycore_uniqueid.h -index d3db49ddb78..9d3c866a704 100644 ---- a/Include/internal/pycore_uniqueid.h -+++ b/Include/internal/pycore_uniqueid.h -@@ -16,7 +16,7 @@ - // Per-thread reference counting is used along with deferred reference - // counting to avoid scaling bottlenecks due to reference count contention. - // --// An id of -1 is used to indicate that an object doesn't use per-thread -+// An id of 0 is used to indicate that an object doesn't use per-thread - // refcounting. This value is used when the object is finalized by the GC - // and during interpreter shutdown to allow the object to be - // deallocated promptly when the object's refcount reaches zero. -@@ -45,6 +45,8 @@ - Py_ssize_t size; - }; - -+#define _Py_INVALID_UNIQUE_ID 0 -+ - // Assigns the next id from the pool of ids. - extern Py_ssize_t _PyObject_AssignUniqueId(PyObject *obj); - -@@ -65,7 +67,7 @@ - extern void _PyObject_FinalizeUniqueIdPool(PyInterpreterState *interp); - - // Increfs the object, resizing the thread-local refcount array if necessary. --PyAPI_FUNC(void) _PyObject_ThreadIncrefSlow(PyObject *obj, Py_ssize_t unique_id); -+PyAPI_FUNC(void) _PyObject_ThreadIncrefSlow(PyObject *obj, size_t idx); - - #endif /* Py_GIL_DISABLED */ - -diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h -index 45563585dd5..4e04dd69542 100644 ---- a/Include/internal/pycore_uop_ids.h -+++ b/Include/internal/pycore_uop_ids.h -@@ -15,19 +15,19 @@ - #define _BINARY_OP_ADD_FLOAT 303 - #define _BINARY_OP_ADD_INT 304 - #define _BINARY_OP_ADD_UNICODE 305 --#define _BINARY_OP_INPLACE_ADD_UNICODE 306 --#define _BINARY_OP_MULTIPLY_FLOAT 307 --#define _BINARY_OP_MULTIPLY_INT 308 --#define _BINARY_OP_SUBTRACT_FLOAT 309 --#define _BINARY_OP_SUBTRACT_INT 310 --#define _BINARY_SLICE 311 --#define _BINARY_SUBSCR 312 --#define _BINARY_SUBSCR_CHECK_FUNC 313 --#define _BINARY_SUBSCR_DICT BINARY_SUBSCR_DICT --#define _BINARY_SUBSCR_INIT_CALL 314 --#define _BINARY_SUBSCR_LIST_INT BINARY_SUBSCR_LIST_INT --#define _BINARY_SUBSCR_STR_INT BINARY_SUBSCR_STR_INT --#define _BINARY_SUBSCR_TUPLE_INT BINARY_SUBSCR_TUPLE_INT -+#define _BINARY_OP_EXTEND 306 -+#define _BINARY_OP_INPLACE_ADD_UNICODE 307 -+#define _BINARY_OP_MULTIPLY_FLOAT 308 -+#define _BINARY_OP_MULTIPLY_INT 309 -+#define _BINARY_OP_SUBSCR_CHECK_FUNC 310 -+#define _BINARY_OP_SUBSCR_DICT BINARY_OP_SUBSCR_DICT -+#define _BINARY_OP_SUBSCR_INIT_CALL 311 -+#define _BINARY_OP_SUBSCR_LIST_INT BINARY_OP_SUBSCR_LIST_INT -+#define _BINARY_OP_SUBSCR_STR_INT BINARY_OP_SUBSCR_STR_INT -+#define _BINARY_OP_SUBSCR_TUPLE_INT BINARY_OP_SUBSCR_TUPLE_INT -+#define _BINARY_OP_SUBTRACT_FLOAT 312 -+#define _BINARY_OP_SUBTRACT_INT 313 -+#define _BINARY_SLICE 314 - #define _BUILD_LIST BUILD_LIST - #define _BUILD_MAP BUILD_MAP - #define _BUILD_SET BUILD_SET -@@ -100,24 +100,25 @@ - #define _DO_CALL 357 - #define _DO_CALL_FUNCTION_EX 358 - #define _DO_CALL_KW 359 --#define _DYNAMIC_EXIT 360 -+#define _END_FOR END_FOR - #define _END_SEND END_SEND --#define _ERROR_POP_N 361 -+#define _ERROR_POP_N 360 - #define _EXIT_INIT_CHECK EXIT_INIT_CHECK --#define _EXPAND_METHOD 362 --#define _EXPAND_METHOD_KW 363 --#define _FATAL_ERROR 364 -+#define _EXPAND_METHOD 361 -+#define _EXPAND_METHOD_KW 362 -+#define _FATAL_ERROR 363 - #define _FORMAT_SIMPLE FORMAT_SIMPLE - #define _FORMAT_WITH_SPEC FORMAT_WITH_SPEC --#define _FOR_ITER 365 --#define _FOR_ITER_GEN_FRAME 366 --#define _FOR_ITER_TIER_TWO 367 -+#define _FOR_ITER 364 -+#define _FOR_ITER_GEN_FRAME 365 -+#define _FOR_ITER_TIER_TWO 366 - #define _GET_AITER GET_AITER - #define _GET_ANEXT GET_ANEXT - #define _GET_AWAITABLE GET_AWAITABLE - #define _GET_ITER GET_ITER - #define _GET_LEN GET_LEN - #define _GET_YIELD_FROM_ITER GET_YIELD_FROM_ITER -+#define _GUARD_BINARY_OP_EXTEND 367 - #define _GUARD_BOTH_FLOAT 368 - #define _GUARD_BOTH_INT 369 - #define _GUARD_BOTH_UNICODE 370 -@@ -139,27 +140,25 @@ - #define _GUARD_TOS_FLOAT 386 - #define _GUARD_TOS_INT 387 - #define _GUARD_TYPE_VERSION 388 -+#define _GUARD_TYPE_VERSION_AND_LOCK 389 - #define _IMPORT_FROM IMPORT_FROM - #define _IMPORT_NAME IMPORT_NAME --#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 389 --#define _INIT_CALL_PY_EXACT_ARGS 390 --#define _INIT_CALL_PY_EXACT_ARGS_0 391 --#define _INIT_CALL_PY_EXACT_ARGS_1 392 --#define _INIT_CALL_PY_EXACT_ARGS_2 393 --#define _INIT_CALL_PY_EXACT_ARGS_3 394 --#define _INIT_CALL_PY_EXACT_ARGS_4 395 --#define _INSTRUMENTED_CALL_FUNCTION_EX INSTRUMENTED_CALL_FUNCTION_EX --#define _INSTRUMENTED_CALL_KW INSTRUMENTED_CALL_KW -+#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 390 -+#define _INIT_CALL_PY_EXACT_ARGS 391 -+#define _INIT_CALL_PY_EXACT_ARGS_0 392 -+#define _INIT_CALL_PY_EXACT_ARGS_1 393 -+#define _INIT_CALL_PY_EXACT_ARGS_2 394 -+#define _INIT_CALL_PY_EXACT_ARGS_3 395 -+#define _INIT_CALL_PY_EXACT_ARGS_4 396 - #define _INSTRUMENTED_FOR_ITER INSTRUMENTED_FOR_ITER - #define _INSTRUMENTED_INSTRUCTION INSTRUMENTED_INSTRUCTION - #define _INSTRUMENTED_JUMP_FORWARD INSTRUMENTED_JUMP_FORWARD - #define _INSTRUMENTED_LINE INSTRUMENTED_LINE --#define _INSTRUMENTED_LOAD_SUPER_ATTR INSTRUMENTED_LOAD_SUPER_ATTR -+#define _INSTRUMENTED_NOT_TAKEN INSTRUMENTED_NOT_TAKEN - #define _INSTRUMENTED_POP_JUMP_IF_FALSE INSTRUMENTED_POP_JUMP_IF_FALSE - #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 _INTERNAL_INCREMENT_OPT_COUNTER 396 - #define _IS_NONE 397 - #define _IS_OP IS_OP - #define _ITER_CHECK_LIST 398 -@@ -176,126 +175,121 @@ - #define _LIST_EXTEND LIST_EXTEND - #define _LOAD_ATTR 408 - #define _LOAD_ATTR_CLASS 409 --#define _LOAD_ATTR_CLASS_0 410 --#define _LOAD_ATTR_CLASS_1 411 - #define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN --#define _LOAD_ATTR_INSTANCE_VALUE 412 --#define _LOAD_ATTR_INSTANCE_VALUE_0 413 --#define _LOAD_ATTR_INSTANCE_VALUE_1 414 --#define _LOAD_ATTR_METHOD_LAZY_DICT 415 --#define _LOAD_ATTR_METHOD_NO_DICT 416 --#define _LOAD_ATTR_METHOD_WITH_VALUES 417 --#define _LOAD_ATTR_MODULE 418 --#define _LOAD_ATTR_MODULE_FROM_KEYS 419 --#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 420 --#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 421 --#define _LOAD_ATTR_PROPERTY_FRAME 422 --#define _LOAD_ATTR_SLOT 423 --#define _LOAD_ATTR_SLOT_0 424 --#define _LOAD_ATTR_SLOT_1 425 --#define _LOAD_ATTR_WITH_HINT 426 -+#define _LOAD_ATTR_INSTANCE_VALUE 410 -+#define _LOAD_ATTR_METHOD_LAZY_DICT 411 -+#define _LOAD_ATTR_METHOD_NO_DICT 412 -+#define _LOAD_ATTR_METHOD_WITH_VALUES 413 -+#define _LOAD_ATTR_MODULE 414 -+#define _LOAD_ATTR_MODULE_FROM_KEYS 415 -+#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 416 -+#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 417 -+#define _LOAD_ATTR_PROPERTY_FRAME 418 -+#define _LOAD_ATTR_SLOT 419 -+#define _LOAD_ATTR_WITH_HINT 420 - #define _LOAD_BUILD_CLASS LOAD_BUILD_CLASS --#define _LOAD_BYTECODE 427 -+#define _LOAD_BYTECODE 421 - #define _LOAD_COMMON_CONSTANT LOAD_COMMON_CONSTANT - #define _LOAD_CONST LOAD_CONST - #define _LOAD_CONST_IMMORTAL LOAD_CONST_IMMORTAL --#define _LOAD_CONST_INLINE 428 --#define _LOAD_CONST_INLINE_BORROW 429 --#define _LOAD_CONST_INLINE_BORROW_WITH_NULL 430 --#define _LOAD_CONST_INLINE_WITH_NULL 431 -+#define _LOAD_CONST_INLINE 422 -+#define _LOAD_CONST_INLINE_BORROW 423 -+#define _LOAD_CONST_MORTAL LOAD_CONST_MORTAL - #define _LOAD_DEREF LOAD_DEREF --#define _LOAD_FAST 432 --#define _LOAD_FAST_0 433 --#define _LOAD_FAST_1 434 --#define _LOAD_FAST_2 435 --#define _LOAD_FAST_3 436 --#define _LOAD_FAST_4 437 --#define _LOAD_FAST_5 438 --#define _LOAD_FAST_6 439 --#define _LOAD_FAST_7 440 -+#define _LOAD_FAST 424 -+#define _LOAD_FAST_0 425 -+#define _LOAD_FAST_1 426 -+#define _LOAD_FAST_2 427 -+#define _LOAD_FAST_3 428 -+#define _LOAD_FAST_4 429 -+#define _LOAD_FAST_5 430 -+#define _LOAD_FAST_6 431 -+#define _LOAD_FAST_7 432 - #define _LOAD_FAST_AND_CLEAR LOAD_FAST_AND_CLEAR - #define _LOAD_FAST_CHECK LOAD_FAST_CHECK - #define _LOAD_FAST_LOAD_FAST LOAD_FAST_LOAD_FAST - #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 441 --#define _LOAD_GLOBAL_BUILTINS 442 --#define _LOAD_GLOBAL_BUILTINS_FROM_KEYS 443 --#define _LOAD_GLOBAL_MODULE 444 --#define _LOAD_GLOBAL_MODULE_FROM_KEYS 445 -+#define _LOAD_GLOBAL 433 -+#define _LOAD_GLOBAL_BUILTINS 434 -+#define _LOAD_GLOBAL_BUILTINS_FROM_KEYS 435 -+#define _LOAD_GLOBAL_MODULE 436 -+#define _LOAD_GLOBAL_MODULE_FROM_KEYS 437 - #define _LOAD_LOCALS LOAD_LOCALS - #define _LOAD_NAME LOAD_NAME --#define _LOAD_SMALL_INT 446 --#define _LOAD_SMALL_INT_0 447 --#define _LOAD_SMALL_INT_1 448 --#define _LOAD_SMALL_INT_2 449 --#define _LOAD_SMALL_INT_3 450 -+#define _LOAD_SMALL_INT 438 -+#define _LOAD_SMALL_INT_0 439 -+#define _LOAD_SMALL_INT_1 440 -+#define _LOAD_SMALL_INT_2 441 -+#define _LOAD_SMALL_INT_3 442 - #define _LOAD_SPECIAL LOAD_SPECIAL - #define _LOAD_SUPER_ATTR_ATTR LOAD_SUPER_ATTR_ATTR - #define _LOAD_SUPER_ATTR_METHOD LOAD_SUPER_ATTR_METHOD --#define _MAKE_CALLARGS_A_TUPLE 451 -+#define _MAKE_CALLARGS_A_TUPLE 443 - #define _MAKE_CELL MAKE_CELL - #define _MAKE_FUNCTION MAKE_FUNCTION --#define _MAKE_WARM 452 -+#define _MAKE_WARM 444 - #define _MAP_ADD MAP_ADD - #define _MATCH_CLASS MATCH_CLASS - #define _MATCH_KEYS MATCH_KEYS - #define _MATCH_MAPPING MATCH_MAPPING - #define _MATCH_SEQUENCE MATCH_SEQUENCE --#define _MAYBE_EXPAND_METHOD 453 --#define _MAYBE_EXPAND_METHOD_KW 454 --#define _MONITOR_CALL 455 --#define _MONITOR_JUMP_BACKWARD 456 --#define _MONITOR_RESUME 457 -+#define _MAYBE_EXPAND_METHOD 445 -+#define _MAYBE_EXPAND_METHOD_KW 446 -+#define _MONITOR_CALL 447 -+#define _MONITOR_CALL_KW 448 -+#define _MONITOR_JUMP_BACKWARD 449 -+#define _MONITOR_RESUME 450 - #define _NOP NOP - #define _POP_EXCEPT POP_EXCEPT --#define _POP_JUMP_IF_FALSE 458 --#define _POP_JUMP_IF_TRUE 459 -+#define _POP_JUMP_IF_FALSE 451 -+#define _POP_JUMP_IF_TRUE 452 - #define _POP_TOP POP_TOP --#define _POP_TOP_LOAD_CONST_INLINE_BORROW 460 -+#define _POP_TOP_LOAD_CONST_INLINE_BORROW 453 - #define _PUSH_EXC_INFO PUSH_EXC_INFO --#define _PUSH_FRAME 461 -+#define _PUSH_FRAME 454 - #define _PUSH_NULL PUSH_NULL --#define _PY_FRAME_GENERAL 462 --#define _PY_FRAME_KW 463 --#define _QUICKEN_RESUME 464 --#define _REPLACE_WITH_TRUE 465 -+#define _PUSH_NULL_CONDITIONAL 455 -+#define _PY_FRAME_GENERAL 456 -+#define _PY_FRAME_KW 457 -+#define _QUICKEN_RESUME 458 -+#define _REPLACE_WITH_TRUE 459 - #define _RESUME_CHECK RESUME_CHECK - #define _RETURN_GENERATOR RETURN_GENERATOR - #define _RETURN_VALUE RETURN_VALUE --#define _SAVE_RETURN_OFFSET 466 --#define _SEND 467 --#define _SEND_GEN_FRAME 468 -+#define _SAVE_RETURN_OFFSET 460 -+#define _SEND 461 -+#define _SEND_GEN_FRAME 462 - #define _SETUP_ANNOTATIONS SETUP_ANNOTATIONS - #define _SET_ADD SET_ADD - #define _SET_FUNCTION_ATTRIBUTE SET_FUNCTION_ATTRIBUTE - #define _SET_UPDATE SET_UPDATE --#define _START_EXECUTOR 469 --#define _STORE_ATTR 470 --#define _STORE_ATTR_INSTANCE_VALUE 471 --#define _STORE_ATTR_SLOT 472 --#define _STORE_ATTR_WITH_HINT 473 -+#define _START_EXECUTOR 463 -+#define _STORE_ATTR 464 -+#define _STORE_ATTR_INSTANCE_VALUE 465 -+#define _STORE_ATTR_SLOT 466 -+#define _STORE_ATTR_WITH_HINT 467 - #define _STORE_DEREF STORE_DEREF --#define _STORE_FAST 474 --#define _STORE_FAST_0 475 --#define _STORE_FAST_1 476 --#define _STORE_FAST_2 477 --#define _STORE_FAST_3 478 --#define _STORE_FAST_4 479 --#define _STORE_FAST_5 480 --#define _STORE_FAST_6 481 --#define _STORE_FAST_7 482 -+#define _STORE_FAST 468 -+#define _STORE_FAST_0 469 -+#define _STORE_FAST_1 470 -+#define _STORE_FAST_2 471 -+#define _STORE_FAST_3 472 -+#define _STORE_FAST_4 473 -+#define _STORE_FAST_5 474 -+#define _STORE_FAST_6 475 -+#define _STORE_FAST_7 476 - #define _STORE_FAST_LOAD_FAST STORE_FAST_LOAD_FAST - #define _STORE_FAST_STORE_FAST STORE_FAST_STORE_FAST - #define _STORE_GLOBAL STORE_GLOBAL - #define _STORE_NAME STORE_NAME --#define _STORE_SLICE 483 --#define _STORE_SUBSCR 484 -+#define _STORE_SLICE 477 -+#define _STORE_SUBSCR 478 - #define _STORE_SUBSCR_DICT STORE_SUBSCR_DICT - #define _STORE_SUBSCR_LIST_INT STORE_SUBSCR_LIST_INT - #define _SWAP SWAP --#define _TIER2_RESUME_CHECK 485 --#define _TO_BOOL 486 -+#define _TIER2_RESUME_CHECK 479 -+#define _TO_BOOL 480 - #define _TO_BOOL_BOOL TO_BOOL_BOOL - #define _TO_BOOL_INT TO_BOOL_INT - #define _TO_BOOL_LIST TO_BOOL_LIST -@@ -305,13 +299,13 @@ - #define _UNARY_NEGATIVE UNARY_NEGATIVE - #define _UNARY_NOT UNARY_NOT - #define _UNPACK_EX UNPACK_EX --#define _UNPACK_SEQUENCE 487 -+#define _UNPACK_SEQUENCE 481 - #define _UNPACK_SEQUENCE_LIST UNPACK_SEQUENCE_LIST - #define _UNPACK_SEQUENCE_TUPLE UNPACK_SEQUENCE_TUPLE - #define _UNPACK_SEQUENCE_TWO_TUPLE UNPACK_SEQUENCE_TWO_TUPLE - #define _WITH_EXCEPT_START WITH_EXCEPT_START - #define _YIELD_VALUE YIELD_VALUE --#define MAX_UOP_ID 487 -+#define MAX_UOP_ID 481 - - #ifdef __cplusplus - } -diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h -index dd775d3f7d3..86a4843ea05 100644 ---- a/Include/internal/pycore_uop_metadata.h -+++ b/Include/internal/pycore_uop_metadata.h -@@ -35,26 +35,27 @@ - [_LOAD_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_PURE_FLAG, - [_LOAD_FAST_AND_CLEAR] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, - [_LOAD_FAST_LOAD_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, -- [_LOAD_CONST] = HAS_ARG_FLAG | HAS_CONST_FLAG | HAS_PURE_FLAG, -+ [_LOAD_CONST_MORTAL] = HAS_ARG_FLAG | HAS_CONST_FLAG, - [_LOAD_CONST_IMMORTAL] = HAS_ARG_FLAG | HAS_CONST_FLAG, - [_LOAD_SMALL_INT_0] = 0, - [_LOAD_SMALL_INT_1] = 0, - [_LOAD_SMALL_INT_2] = 0, - [_LOAD_SMALL_INT_3] = 0, - [_LOAD_SMALL_INT] = HAS_ARG_FLAG, -- [_STORE_FAST_0] = HAS_LOCAL_FLAG, -- [_STORE_FAST_1] = HAS_LOCAL_FLAG, -- [_STORE_FAST_2] = HAS_LOCAL_FLAG, -- [_STORE_FAST_3] = HAS_LOCAL_FLAG, -- [_STORE_FAST_4] = HAS_LOCAL_FLAG, -- [_STORE_FAST_5] = HAS_LOCAL_FLAG, -- [_STORE_FAST_6] = HAS_LOCAL_FLAG, -- [_STORE_FAST_7] = HAS_LOCAL_FLAG, -- [_STORE_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, -- [_STORE_FAST_LOAD_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, -- [_STORE_FAST_STORE_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, -+ [_STORE_FAST_0] = HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, -+ [_STORE_FAST_1] = HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, -+ [_STORE_FAST_2] = HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, -+ [_STORE_FAST_3] = HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, -+ [_STORE_FAST_4] = HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, -+ [_STORE_FAST_5] = HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, -+ [_STORE_FAST_6] = HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, -+ [_STORE_FAST_7] = HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, -+ [_STORE_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, -+ [_STORE_FAST_LOAD_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, -+ [_STORE_FAST_STORE_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG, - [_POP_TOP] = HAS_PURE_FLAG, - [_PUSH_NULL] = HAS_PURE_FLAG, -+ [_END_FOR] = HAS_ESCAPES_FLAG | HAS_NO_SAVE_IP_FLAG, - [_END_SEND] = HAS_PURE_FLAG, - [_UNARY_NEGATIVE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_UNARY_NOT] = HAS_PURE_FLAG, -@@ -81,19 +82,20 @@ - [_GUARD_BOTH_UNICODE] = HAS_EXIT_FLAG, - [_BINARY_OP_ADD_UNICODE] = HAS_ERROR_FLAG | HAS_PURE_FLAG, - [_BINARY_OP_INPLACE_ADD_UNICODE] = HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG, -- [_BINARY_SUBSCR] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, -+ [_GUARD_BINARY_OP_EXTEND] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, -+ [_BINARY_OP_EXTEND] = HAS_ESCAPES_FLAG | HAS_PURE_FLAG, - [_BINARY_SLICE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_STORE_SLICE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, -- [_BINARY_SUBSCR_LIST_INT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, -- [_BINARY_SUBSCR_STR_INT] = HAS_DEOPT_FLAG, -- [_BINARY_SUBSCR_TUPLE_INT] = HAS_DEOPT_FLAG, -- [_BINARY_SUBSCR_DICT] = HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, -- [_BINARY_SUBSCR_CHECK_FUNC] = HAS_DEOPT_FLAG, -- [_BINARY_SUBSCR_INIT_CALL] = 0, -+ [_BINARY_OP_SUBSCR_LIST_INT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, -+ [_BINARY_OP_SUBSCR_STR_INT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, -+ [_BINARY_OP_SUBSCR_TUPLE_INT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, -+ [_BINARY_OP_SUBSCR_DICT] = HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, -+ [_BINARY_OP_SUBSCR_CHECK_FUNC] = HAS_DEOPT_FLAG, -+ [_BINARY_OP_SUBSCR_INIT_CALL] = 0, - [_LIST_APPEND] = HAS_ARG_FLAG | HAS_ERROR_FLAG, - [_SET_ADD] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_STORE_SUBSCR] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, -- [_STORE_SUBSCR_LIST_INT] = HAS_DEOPT_FLAG, -+ [_STORE_SUBSCR_LIST_INT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, - [_STORE_SUBSCR_DICT] = HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_DELETE_SUBSCR] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_CALL_INTRINSIC_1] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, -@@ -121,21 +123,22 @@ - [_LOAD_LOCALS] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_LOAD_NAME] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_LOAD_GLOBAL] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, -+ [_PUSH_NULL_CONDITIONAL] = HAS_ARG_FLAG, - [_GUARD_GLOBALS_VERSION] = HAS_DEOPT_FLAG, - [_GUARD_GLOBALS_VERSION_PUSH_KEYS] = HAS_DEOPT_FLAG, - [_GUARD_BUILTINS_VERSION_PUSH_KEYS] = HAS_DEOPT_FLAG, -- [_LOAD_GLOBAL_MODULE_FROM_KEYS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, -- [_LOAD_GLOBAL_BUILTINS_FROM_KEYS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, -+ [_LOAD_GLOBAL_MODULE_FROM_KEYS] = HAS_DEOPT_FLAG, -+ [_LOAD_GLOBAL_BUILTINS_FROM_KEYS] = HAS_DEOPT_FLAG, - [_DELETE_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, -- [_MAKE_CELL] = HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG, -+ [_MAKE_CELL] = HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, - [_DELETE_DEREF] = HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, - [_LOAD_FROM_DICT_OR_DEREF] = HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, - [_LOAD_DEREF] = HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_STORE_DEREF] = HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ESCAPES_FLAG, - [_COPY_FREE_VARS] = HAS_ARG_FLAG, - [_BUILD_STRING] = HAS_ARG_FLAG | HAS_ERROR_FLAG, -- [_BUILD_TUPLE] = HAS_ARG_FLAG | HAS_ERROR_FLAG, -- [_BUILD_LIST] = HAS_ARG_FLAG | HAS_ERROR_FLAG, -+ [_BUILD_TUPLE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG, -+ [_BUILD_LIST] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG, - [_LIST_EXTEND] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_SET_UPDATE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_BUILD_SET] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, -@@ -145,29 +148,24 @@ - [_DICT_MERGE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_MAP_ADD] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_LOAD_SUPER_ATTR_ATTR] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, -- [_LOAD_SUPER_ATTR_METHOD] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, -+ [_LOAD_SUPER_ATTR_METHOD] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, - [_LOAD_ATTR] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_GUARD_TYPE_VERSION] = HAS_EXIT_FLAG, -+ [_GUARD_TYPE_VERSION_AND_LOCK] = HAS_EXIT_FLAG, - [_CHECK_MANAGED_OBJECT_HAS_VALUES] = HAS_DEOPT_FLAG, -- [_LOAD_ATTR_INSTANCE_VALUE_0] = HAS_DEOPT_FLAG, -- [_LOAD_ATTR_INSTANCE_VALUE_1] = HAS_DEOPT_FLAG, -- [_LOAD_ATTR_INSTANCE_VALUE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_OPARG_AND_1_FLAG, -+ [_LOAD_ATTR_INSTANCE_VALUE] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, - [_CHECK_ATTR_MODULE_PUSH_KEYS] = HAS_DEOPT_FLAG, -- [_LOAD_ATTR_MODULE_FROM_KEYS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, -+ [_LOAD_ATTR_MODULE_FROM_KEYS] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, - [_CHECK_ATTR_WITH_HINT] = HAS_EXIT_FLAG, - [_LOAD_ATTR_WITH_HINT] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG, -- [_LOAD_ATTR_SLOT_0] = HAS_DEOPT_FLAG, -- [_LOAD_ATTR_SLOT_1] = HAS_DEOPT_FLAG, -- [_LOAD_ATTR_SLOT] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_OPARG_AND_1_FLAG, -+ [_LOAD_ATTR_SLOT] = HAS_DEOPT_FLAG, - [_CHECK_ATTR_CLASS] = HAS_EXIT_FLAG, -- [_LOAD_ATTR_CLASS_0] = 0, -- [_LOAD_ATTR_CLASS_1] = 0, -- [_LOAD_ATTR_CLASS] = HAS_ARG_FLAG | HAS_OPARG_AND_1_FLAG, -+ [_LOAD_ATTR_CLASS] = 0, - [_LOAD_ATTR_PROPERTY_FRAME] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, - [_GUARD_DORV_NO_DICT] = HAS_EXIT_FLAG, -- [_STORE_ATTR_INSTANCE_VALUE] = 0, -+ [_STORE_ATTR_INSTANCE_VALUE] = HAS_ESCAPES_FLAG, - [_STORE_ATTR_WITH_HINT] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, -- [_STORE_ATTR_SLOT] = 0, -+ [_STORE_ATTR_SLOT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, - [_COMPARE_OP] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_COMPARE_OP_FLOAT] = HAS_ARG_FLAG, - [_COMPARE_OP_INT] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, -@@ -210,16 +208,16 @@ - [_LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = HAS_ARG_FLAG, - [_CHECK_ATTR_METHOD_LAZY_DICT] = HAS_DEOPT_FLAG, - [_LOAD_ATTR_METHOD_LAZY_DICT] = HAS_ARG_FLAG, -- [_MAYBE_EXPAND_METHOD] = HAS_ARG_FLAG, -+ [_MAYBE_EXPAND_METHOD] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, - [_PY_FRAME_GENERAL] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, - [_CHECK_FUNCTION_VERSION] = HAS_ARG_FLAG | HAS_EXIT_FLAG, - [_CHECK_FUNCTION_VERSION_INLINE] = HAS_EXIT_FLAG, - [_CHECK_METHOD_VERSION] = HAS_ARG_FLAG | HAS_EXIT_FLAG, -- [_EXPAND_METHOD] = HAS_ARG_FLAG, -+ [_EXPAND_METHOD] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, - [_CHECK_IS_NOT_PY_CALLABLE] = HAS_ARG_FLAG | HAS_EXIT_FLAG, - [_CALL_NON_PY_GENERAL] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_CHECK_CALL_BOUND_METHOD_EXACT_ARGS] = HAS_ARG_FLAG | HAS_EXIT_FLAG, -- [_INIT_CALL_BOUND_METHOD_EXACT_ARGS] = HAS_ARG_FLAG, -+ [_INIT_CALL_BOUND_METHOD_EXACT_ARGS] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, - [_CHECK_PEP_523] = HAS_DEOPT_FLAG, - [_CHECK_FUNCTION_EXACT_ARGS] = HAS_ARG_FLAG | HAS_EXIT_FLAG, - [_CHECK_STACK_SPACE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, -@@ -230,10 +228,10 @@ - [_INIT_CALL_PY_EXACT_ARGS_4] = HAS_PURE_FLAG, - [_INIT_CALL_PY_EXACT_ARGS] = HAS_ARG_FLAG | HAS_PURE_FLAG, - [_PUSH_FRAME] = 0, -- [_CALL_TYPE_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, -+ [_CALL_TYPE_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, - [_CALL_STR_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_CALL_TUPLE_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, -- [_CHECK_AND_ALLOCATE_OBJECT] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG, -+ [_CHECK_AND_ALLOCATE_OBJECT] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, - [_CREATE_INIT_FRAME] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, - [_EXIT_INIT_CHECK] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, - [_CALL_BUILTIN_CLASS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, -@@ -242,19 +240,19 @@ - [_CALL_BUILTIN_FAST_WITH_KEYWORDS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_CALL_LEN] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, - [_CALL_ISINSTANCE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, -- [_CALL_LIST_APPEND] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG, -+ [_CALL_LIST_APPEND] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_CALL_METHOD_DESCRIPTOR_O] = HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_CALL_METHOD_DESCRIPTOR_NOARGS] = HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_CALL_METHOD_DESCRIPTOR_FAST] = HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, -- [_MAYBE_EXPAND_METHOD_KW] = HAS_ARG_FLAG, -+ [_MAYBE_EXPAND_METHOD_KW] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, - [_PY_FRAME_KW] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, - [_CHECK_FUNCTION_VERSION_KW] = HAS_ARG_FLAG | HAS_EXIT_FLAG, - [_CHECK_METHOD_VERSION_KW] = HAS_ARG_FLAG | HAS_EXIT_FLAG, -- [_EXPAND_METHOD_KW] = HAS_ARG_FLAG, -+ [_EXPAND_METHOD_KW] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, - [_CHECK_IS_NOT_PY_CALLABLE_KW] = HAS_ARG_FLAG | HAS_EXIT_FLAG, - [_CALL_KW_NON_PY] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, -- [_MAKE_CALLARGS_A_TUPLE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, -+ [_MAKE_CALLARGS_A_TUPLE] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, - [_MAKE_FUNCTION] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_SET_FUNCTION_ATTRIBUTE] = HAS_ARG_FLAG, - [_RETURN_GENERATOR] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, -@@ -267,8 +265,8 @@ - [_SWAP] = HAS_ARG_FLAG | HAS_PURE_FLAG, - [_GUARD_IS_TRUE_POP] = HAS_EXIT_FLAG, - [_GUARD_IS_FALSE_POP] = HAS_EXIT_FLAG, -- [_GUARD_IS_NONE_POP] = HAS_EXIT_FLAG, -- [_GUARD_IS_NOT_NONE_POP] = HAS_EXIT_FLAG, -+ [_GUARD_IS_NONE_POP] = HAS_EXIT_FLAG | HAS_ESCAPES_FLAG, -+ [_GUARD_IS_NOT_NONE_POP] = HAS_EXIT_FLAG | HAS_ESCAPES_FLAG, - [_JUMP_TO_TOP] = 0, - [_SET_IP] = 0, - [_CHECK_STACK_SPACE_OPERAND] = HAS_DEOPT_FLAG, -@@ -277,21 +275,17 @@ - [_CHECK_VALIDITY] = HAS_DEOPT_FLAG, - [_LOAD_CONST_INLINE] = HAS_PURE_FLAG, - [_LOAD_CONST_INLINE_BORROW] = HAS_PURE_FLAG, -- [_POP_TOP_LOAD_CONST_INLINE_BORROW] = HAS_PURE_FLAG, -- [_LOAD_CONST_INLINE_WITH_NULL] = HAS_PURE_FLAG, -- [_LOAD_CONST_INLINE_BORROW_WITH_NULL] = HAS_PURE_FLAG, -+ [_POP_TOP_LOAD_CONST_INLINE_BORROW] = HAS_ESCAPES_FLAG | HAS_PURE_FLAG, - [_CHECK_FUNCTION] = HAS_DEOPT_FLAG, -- [_LOAD_GLOBAL_MODULE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, -- [_LOAD_GLOBAL_BUILTINS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, -- [_LOAD_ATTR_MODULE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, -- [_INTERNAL_INCREMENT_OPT_COUNTER] = 0, -- [_DYNAMIC_EXIT] = HAS_ESCAPES_FLAG, -- [_START_EXECUTOR] = 0, -+ [_LOAD_GLOBAL_MODULE] = HAS_DEOPT_FLAG, -+ [_LOAD_GLOBAL_BUILTINS] = HAS_DEOPT_FLAG, -+ [_LOAD_ATTR_MODULE] = HAS_DEOPT_FLAG, -+ [_START_EXECUTOR] = HAS_ESCAPES_FLAG, - [_MAKE_WARM] = 0, - [_FATAL_ERROR] = 0, - [_CHECK_VALIDITY_AND_SET_IP] = HAS_DEOPT_FLAG, - [_DEOPT] = 0, -- [_ERROR_POP_N] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, -+ [_ERROR_POP_N] = HAS_ARG_FLAG, - [_TIER2_RESUME_CHECK] = HAS_DEOPT_FLAG, - }; - -@@ -307,19 +301,19 @@ - [_BINARY_OP_ADD_FLOAT] = "_BINARY_OP_ADD_FLOAT", - [_BINARY_OP_ADD_INT] = "_BINARY_OP_ADD_INT", - [_BINARY_OP_ADD_UNICODE] = "_BINARY_OP_ADD_UNICODE", -+ [_BINARY_OP_EXTEND] = "_BINARY_OP_EXTEND", - [_BINARY_OP_INPLACE_ADD_UNICODE] = "_BINARY_OP_INPLACE_ADD_UNICODE", - [_BINARY_OP_MULTIPLY_FLOAT] = "_BINARY_OP_MULTIPLY_FLOAT", - [_BINARY_OP_MULTIPLY_INT] = "_BINARY_OP_MULTIPLY_INT", -+ [_BINARY_OP_SUBSCR_CHECK_FUNC] = "_BINARY_OP_SUBSCR_CHECK_FUNC", -+ [_BINARY_OP_SUBSCR_DICT] = "_BINARY_OP_SUBSCR_DICT", -+ [_BINARY_OP_SUBSCR_INIT_CALL] = "_BINARY_OP_SUBSCR_INIT_CALL", -+ [_BINARY_OP_SUBSCR_LIST_INT] = "_BINARY_OP_SUBSCR_LIST_INT", -+ [_BINARY_OP_SUBSCR_STR_INT] = "_BINARY_OP_SUBSCR_STR_INT", -+ [_BINARY_OP_SUBSCR_TUPLE_INT] = "_BINARY_OP_SUBSCR_TUPLE_INT", - [_BINARY_OP_SUBTRACT_FLOAT] = "_BINARY_OP_SUBTRACT_FLOAT", - [_BINARY_OP_SUBTRACT_INT] = "_BINARY_OP_SUBTRACT_INT", - [_BINARY_SLICE] = "_BINARY_SLICE", -- [_BINARY_SUBSCR] = "_BINARY_SUBSCR", -- [_BINARY_SUBSCR_CHECK_FUNC] = "_BINARY_SUBSCR_CHECK_FUNC", -- [_BINARY_SUBSCR_DICT] = "_BINARY_SUBSCR_DICT", -- [_BINARY_SUBSCR_INIT_CALL] = "_BINARY_SUBSCR_INIT_CALL", -- [_BINARY_SUBSCR_LIST_INT] = "_BINARY_SUBSCR_LIST_INT", -- [_BINARY_SUBSCR_STR_INT] = "_BINARY_SUBSCR_STR_INT", -- [_BINARY_SUBSCR_TUPLE_INT] = "_BINARY_SUBSCR_TUPLE_INT", - [_BUILD_LIST] = "_BUILD_LIST", - [_BUILD_MAP] = "_BUILD_MAP", - [_BUILD_SET] = "_BUILD_SET", -@@ -389,7 +383,7 @@ - [_DEOPT] = "_DEOPT", - [_DICT_MERGE] = "_DICT_MERGE", - [_DICT_UPDATE] = "_DICT_UPDATE", -- [_DYNAMIC_EXIT] = "_DYNAMIC_EXIT", -+ [_END_FOR] = "_END_FOR", - [_END_SEND] = "_END_SEND", - [_ERROR_POP_N] = "_ERROR_POP_N", - [_EXIT_INIT_CHECK] = "_EXIT_INIT_CHECK", -@@ -407,6 +401,7 @@ - [_GET_ITER] = "_GET_ITER", - [_GET_LEN] = "_GET_LEN", - [_GET_YIELD_FROM_ITER] = "_GET_YIELD_FROM_ITER", -+ [_GUARD_BINARY_OP_EXTEND] = "_GUARD_BINARY_OP_EXTEND", - [_GUARD_BOTH_FLOAT] = "_GUARD_BOTH_FLOAT", - [_GUARD_BOTH_INT] = "_GUARD_BOTH_INT", - [_GUARD_BOTH_UNICODE] = "_GUARD_BOTH_UNICODE", -@@ -428,6 +423,7 @@ - [_GUARD_TOS_FLOAT] = "_GUARD_TOS_FLOAT", - [_GUARD_TOS_INT] = "_GUARD_TOS_INT", - [_GUARD_TYPE_VERSION] = "_GUARD_TYPE_VERSION", -+ [_GUARD_TYPE_VERSION_AND_LOCK] = "_GUARD_TYPE_VERSION_AND_LOCK", - [_IMPORT_FROM] = "_IMPORT_FROM", - [_IMPORT_NAME] = "_IMPORT_NAME", - [_INIT_CALL_BOUND_METHOD_EXACT_ARGS] = "_INIT_CALL_BOUND_METHOD_EXACT_ARGS", -@@ -437,7 +433,6 @@ - [_INIT_CALL_PY_EXACT_ARGS_2] = "_INIT_CALL_PY_EXACT_ARGS_2", - [_INIT_CALL_PY_EXACT_ARGS_3] = "_INIT_CALL_PY_EXACT_ARGS_3", - [_INIT_CALL_PY_EXACT_ARGS_4] = "_INIT_CALL_PY_EXACT_ARGS_4", -- [_INTERNAL_INCREMENT_OPT_COUNTER] = "_INTERNAL_INCREMENT_OPT_COUNTER", - [_IS_NONE] = "_IS_NONE", - [_IS_OP] = "_IS_OP", - [_ITER_CHECK_LIST] = "_ITER_CHECK_LIST", -@@ -451,11 +446,7 @@ - [_LIST_EXTEND] = "_LIST_EXTEND", - [_LOAD_ATTR] = "_LOAD_ATTR", - [_LOAD_ATTR_CLASS] = "_LOAD_ATTR_CLASS", -- [_LOAD_ATTR_CLASS_0] = "_LOAD_ATTR_CLASS_0", -- [_LOAD_ATTR_CLASS_1] = "_LOAD_ATTR_CLASS_1", - [_LOAD_ATTR_INSTANCE_VALUE] = "_LOAD_ATTR_INSTANCE_VALUE", -- [_LOAD_ATTR_INSTANCE_VALUE_0] = "_LOAD_ATTR_INSTANCE_VALUE_0", -- [_LOAD_ATTR_INSTANCE_VALUE_1] = "_LOAD_ATTR_INSTANCE_VALUE_1", - [_LOAD_ATTR_METHOD_LAZY_DICT] = "_LOAD_ATTR_METHOD_LAZY_DICT", - [_LOAD_ATTR_METHOD_NO_DICT] = "_LOAD_ATTR_METHOD_NO_DICT", - [_LOAD_ATTR_METHOD_WITH_VALUES] = "_LOAD_ATTR_METHOD_WITH_VALUES", -@@ -465,17 +456,13 @@ - [_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = "_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", - [_LOAD_ATTR_PROPERTY_FRAME] = "_LOAD_ATTR_PROPERTY_FRAME", - [_LOAD_ATTR_SLOT] = "_LOAD_ATTR_SLOT", -- [_LOAD_ATTR_SLOT_0] = "_LOAD_ATTR_SLOT_0", -- [_LOAD_ATTR_SLOT_1] = "_LOAD_ATTR_SLOT_1", - [_LOAD_ATTR_WITH_HINT] = "_LOAD_ATTR_WITH_HINT", - [_LOAD_BUILD_CLASS] = "_LOAD_BUILD_CLASS", - [_LOAD_COMMON_CONSTANT] = "_LOAD_COMMON_CONSTANT", -- [_LOAD_CONST] = "_LOAD_CONST", - [_LOAD_CONST_IMMORTAL] = "_LOAD_CONST_IMMORTAL", - [_LOAD_CONST_INLINE] = "_LOAD_CONST_INLINE", - [_LOAD_CONST_INLINE_BORROW] = "_LOAD_CONST_INLINE_BORROW", -- [_LOAD_CONST_INLINE_BORROW_WITH_NULL] = "_LOAD_CONST_INLINE_BORROW_WITH_NULL", -- [_LOAD_CONST_INLINE_WITH_NULL] = "_LOAD_CONST_INLINE_WITH_NULL", -+ [_LOAD_CONST_MORTAL] = "_LOAD_CONST_MORTAL", - [_LOAD_DEREF] = "_LOAD_DEREF", - [_LOAD_FAST] = "_LOAD_FAST", - [_LOAD_FAST_0] = "_LOAD_FAST_0", -@@ -523,6 +510,7 @@ - [_PUSH_EXC_INFO] = "_PUSH_EXC_INFO", - [_PUSH_FRAME] = "_PUSH_FRAME", - [_PUSH_NULL] = "_PUSH_NULL", -+ [_PUSH_NULL_CONDITIONAL] = "_PUSH_NULL_CONDITIONAL", - [_PY_FRAME_GENERAL] = "_PY_FRAME_GENERAL", - [_PY_FRAME_KW] = "_PY_FRAME_KW", - [_REPLACE_WITH_TRUE] = "_REPLACE_WITH_TRUE", -@@ -613,7 +601,7 @@ - return 0; - case _LOAD_FAST_LOAD_FAST: - return 0; -- case _LOAD_CONST: -+ case _LOAD_CONST_MORTAL: - return 0; - case _LOAD_CONST_IMMORTAL: - return 0; -@@ -653,6 +641,8 @@ - return 1; - case _PUSH_NULL: - return 0; -+ case _END_FOR: -+ return 1; - case _END_SEND: - return 2; - case _UNARY_NEGATIVE: -@@ -705,24 +695,26 @@ - return 2; - case _BINARY_OP_INPLACE_ADD_UNICODE: - return 2; -- case _BINARY_SUBSCR: -+ case _GUARD_BINARY_OP_EXTEND: -+ return 0; -+ case _BINARY_OP_EXTEND: - return 2; - case _BINARY_SLICE: - return 3; - case _STORE_SLICE: - return 4; -- case _BINARY_SUBSCR_LIST_INT: -+ case _BINARY_OP_SUBSCR_LIST_INT: - return 2; -- case _BINARY_SUBSCR_STR_INT: -+ case _BINARY_OP_SUBSCR_STR_INT: - return 2; -- case _BINARY_SUBSCR_TUPLE_INT: -+ case _BINARY_OP_SUBSCR_TUPLE_INT: - return 2; -- case _BINARY_SUBSCR_DICT: -+ case _BINARY_OP_SUBSCR_DICT: - return 2; -- case _BINARY_SUBSCR_CHECK_FUNC: -+ case _BINARY_OP_SUBSCR_CHECK_FUNC: - return 0; -- case _BINARY_SUBSCR_INIT_CALL: -- return 2; -+ case _BINARY_OP_SUBSCR_INIT_CALL: -+ return 3; - case _LIST_APPEND: - return 1; - case _SET_ADD: -@@ -785,6 +777,8 @@ - return 0; - case _LOAD_GLOBAL: - return 0; -+ case _PUSH_NULL_CONDITIONAL: -+ return 0; - case _GUARD_GLOBALS_VERSION: - return 0; - case _GUARD_GLOBALS_VERSION_PUSH_KEYS: -@@ -839,12 +833,10 @@ - return 1; - case _GUARD_TYPE_VERSION: - return 0; -+ case _GUARD_TYPE_VERSION_AND_LOCK: -+ return 0; - case _CHECK_MANAGED_OBJECT_HAS_VALUES: - return 0; -- case _LOAD_ATTR_INSTANCE_VALUE_0: -- return 1; -- case _LOAD_ATTR_INSTANCE_VALUE_1: -- return 1; - case _LOAD_ATTR_INSTANCE_VALUE: - return 1; - case _CHECK_ATTR_MODULE_PUSH_KEYS: -@@ -854,19 +846,11 @@ - case _CHECK_ATTR_WITH_HINT: - return 0; - case _LOAD_ATTR_WITH_HINT: -- return 1; -- case _LOAD_ATTR_SLOT_0: -- return 1; -- case _LOAD_ATTR_SLOT_1: -- return 1; -+ return 2; - case _LOAD_ATTR_SLOT: - return 1; - case _CHECK_ATTR_CLASS: - return 0; -- case _LOAD_ATTR_CLASS_0: -- return 1; -- case _LOAD_ATTR_CLASS_1: -- return 1; - case _LOAD_ATTR_CLASS: - return 1; - case _LOAD_ATTR_PROPERTY_FRAME: -@@ -974,7 +958,7 @@ - case _CHECK_METHOD_VERSION: - return 0; - case _EXPAND_METHOD: -- return 2 + oparg; -+ return 0; - case _CHECK_IS_NOT_PY_CALLABLE: - return 0; - case _CALL_NON_PY_GENERAL: -@@ -982,7 +966,7 @@ - case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: - return 0; - case _INIT_CALL_BOUND_METHOD_EXACT_ARGS: -- return 2 + oparg; -+ return 0; - case _CHECK_PEP_523: - return 0; - case _CHECK_FUNCTION_EXACT_ARGS: -@@ -1046,13 +1030,13 @@ - case _CHECK_METHOD_VERSION_KW: - return 0; - case _EXPAND_METHOD_KW: -- return 3 + oparg; -+ return 0; - case _CHECK_IS_NOT_PY_CALLABLE_KW: - return 0; - case _CALL_KW_NON_PY: - return 3 + oparg; - case _MAKE_CALLARGS_A_TUPLE: -- return 1 + (oparg & 1); -+ return 2; - case _MAKE_FUNCTION: - return 1; - case _SET_FUNCTION_ATTRIBUTE: -@@ -1060,7 +1044,7 @@ - case _RETURN_GENERATOR: - return 0; - case _BUILD_SLICE: -- return 2 + ((oparg == 3) ? 1 : 0); -+ return oparg; - case _CONVERT_VALUE: - return 1; - case _FORMAT_SIMPLE: -@@ -1072,7 +1056,7 @@ - case _BINARY_OP: - return 2; - case _SWAP: -- return 2 + (oparg-2); -+ return 0; - case _GUARD_IS_TRUE_POP: - return 1; - case _GUARD_IS_FALSE_POP: -@@ -1099,10 +1083,6 @@ - return 0; - case _POP_TOP_LOAD_CONST_INLINE_BORROW: - return 1; -- case _LOAD_CONST_INLINE_WITH_NULL: -- return 0; -- case _LOAD_CONST_INLINE_BORROW_WITH_NULL: -- return 0; - case _CHECK_FUNCTION: - return 0; - case _LOAD_GLOBAL_MODULE: -@@ -1111,10 +1091,6 @@ - return 0; - case _LOAD_ATTR_MODULE: - return 1; -- case _INTERNAL_INCREMENT_OPT_COUNTER: -- return 1; -- case _DYNAMIC_EXIT: -- return 0; - case _START_EXECUTOR: - return 0; - case _MAKE_WARM: -@@ -1126,7 +1102,7 @@ - case _DEOPT: - return 0; - case _ERROR_POP_N: -- return oparg; -+ return 0; - case _TIER2_RESUME_CHECK: - return 0; - default: -diff --git a/Include/internal/pycore_warnings.h b/Include/internal/pycore_warnings.h -index f9f6559312f..672228cd6fb 100644 ---- a/Include/internal/pycore_warnings.h -+++ b/Include/internal/pycore_warnings.h -@@ -14,7 +14,7 @@ - PyObject *filters; /* List */ - PyObject *once_registry; /* Dict */ - PyObject *default_action; /* String */ -- PyMutex mutex; -+ _PyRecursiveMutex lock; - long filters_version; - }; - -diff --git a/Include/opcode.h b/Include/opcode.h -index 2619b690019..fcb972f2ec2 100644 ---- a/Include/opcode.h -+++ b/Include/opcode.h -@@ -33,8 +33,9 @@ - #define NB_INPLACE_SUBTRACT 23 - #define NB_INPLACE_TRUE_DIVIDE 24 - #define NB_INPLACE_XOR 25 -+#define NB_SUBSCR 26 - --#define NB_OPARG_LAST 25 -+#define NB_OPARG_LAST 26 - - #ifdef __cplusplus - } -diff --git a/Include/opcode_ids.h b/Include/opcode_ids.h -index ce3d23eaa6d..54f543f4a8a 100644 ---- a/Include/opcode_ids.h -+++ b/Include/opcode_ids.h -@@ -12,7 +12,7 @@ - /* Instruction opcodes for compiled code */ - #define CACHE 0 - #define BINARY_SLICE 1 --#define BINARY_SUBSCR 2 -+#define CALL_FUNCTION_EX 2 - #define BINARY_OP_INPLACE_ADD_UNICODE 3 - #define CHECK_EG_MATCH 4 - #define CHECK_EXC_MATCH 5 -@@ -38,189 +38,196 @@ - #define MATCH_MAPPING 25 - #define MATCH_SEQUENCE 26 - #define NOP 27 --#define POP_EXCEPT 28 --#define POP_TOP 29 --#define PUSH_EXC_INFO 30 --#define PUSH_NULL 31 --#define RETURN_GENERATOR 32 --#define RETURN_VALUE 33 --#define SETUP_ANNOTATIONS 34 --#define STORE_SLICE 35 --#define STORE_SUBSCR 36 --#define TO_BOOL 37 --#define UNARY_INVERT 38 --#define UNARY_NEGATIVE 39 --#define UNARY_NOT 40 --#define WITH_EXCEPT_START 41 --#define BINARY_OP 42 --#define BUILD_LIST 43 --#define BUILD_MAP 44 --#define BUILD_SET 45 --#define BUILD_SLICE 46 --#define BUILD_STRING 47 --#define BUILD_TUPLE 48 --#define CALL 49 --#define CALL_FUNCTION_EX 50 --#define CALL_INTRINSIC_1 51 --#define CALL_INTRINSIC_2 52 --#define CALL_KW 53 --#define COMPARE_OP 54 --#define CONTAINS_OP 55 --#define CONVERT_VALUE 56 --#define COPY 57 --#define COPY_FREE_VARS 58 --#define DELETE_ATTR 59 --#define DELETE_DEREF 60 --#define DELETE_FAST 61 --#define DELETE_GLOBAL 62 --#define DELETE_NAME 63 --#define DICT_MERGE 64 --#define DICT_UPDATE 65 --#define EXTENDED_ARG 66 --#define FOR_ITER 67 --#define GET_AWAITABLE 68 --#define IMPORT_FROM 69 --#define IMPORT_NAME 70 --#define IS_OP 71 --#define JUMP_BACKWARD 72 --#define JUMP_BACKWARD_NO_INTERRUPT 73 --#define JUMP_FORWARD 74 --#define LIST_APPEND 75 --#define LIST_EXTEND 76 --#define LOAD_ATTR 77 --#define LOAD_COMMON_CONSTANT 78 --#define LOAD_CONST 79 --#define LOAD_DEREF 80 --#define LOAD_FAST 81 --#define LOAD_FAST_AND_CLEAR 82 --#define LOAD_FAST_CHECK 83 --#define LOAD_FAST_LOAD_FAST 84 --#define LOAD_FROM_DICT_OR_DEREF 85 --#define LOAD_FROM_DICT_OR_GLOBALS 86 --#define LOAD_GLOBAL 87 --#define LOAD_NAME 88 --#define LOAD_SMALL_INT 89 --#define LOAD_SPECIAL 90 --#define LOAD_SUPER_ATTR 91 --#define MAKE_CELL 92 --#define MAP_ADD 93 --#define MATCH_CLASS 94 --#define POP_JUMP_IF_FALSE 95 --#define POP_JUMP_IF_NONE 96 --#define POP_JUMP_IF_NOT_NONE 97 --#define POP_JUMP_IF_TRUE 98 --#define RAISE_VARARGS 99 --#define RERAISE 100 --#define SEND 101 --#define SET_ADD 102 --#define SET_FUNCTION_ATTRIBUTE 103 --#define SET_UPDATE 104 --#define STORE_ATTR 105 --#define STORE_DEREF 106 --#define STORE_FAST 107 --#define STORE_FAST_LOAD_FAST 108 --#define STORE_FAST_STORE_FAST 109 --#define STORE_GLOBAL 110 --#define STORE_NAME 111 --#define SWAP 112 --#define UNPACK_EX 113 --#define UNPACK_SEQUENCE 114 --#define YIELD_VALUE 115 -+#define NOT_TAKEN 28 -+#define POP_EXCEPT 29 -+#define POP_ITER 30 -+#define POP_TOP 31 -+#define PUSH_EXC_INFO 32 -+#define PUSH_NULL 33 -+#define RETURN_GENERATOR 34 -+#define RETURN_VALUE 35 -+#define SETUP_ANNOTATIONS 36 -+#define STORE_SLICE 37 -+#define STORE_SUBSCR 38 -+#define TO_BOOL 39 -+#define UNARY_INVERT 40 -+#define UNARY_NEGATIVE 41 -+#define UNARY_NOT 42 -+#define WITH_EXCEPT_START 43 -+#define BINARY_OP 44 -+#define BUILD_LIST 45 -+#define BUILD_MAP 46 -+#define BUILD_SET 47 -+#define BUILD_SLICE 48 -+#define BUILD_STRING 49 -+#define BUILD_TUPLE 50 -+#define CALL 51 -+#define CALL_INTRINSIC_1 52 -+#define CALL_INTRINSIC_2 53 -+#define CALL_KW 54 -+#define COMPARE_OP 55 -+#define CONTAINS_OP 56 -+#define CONVERT_VALUE 57 -+#define COPY 58 -+#define COPY_FREE_VARS 59 -+#define DELETE_ATTR 60 -+#define DELETE_DEREF 61 -+#define DELETE_FAST 62 -+#define DELETE_GLOBAL 63 -+#define DELETE_NAME 64 -+#define DICT_MERGE 65 -+#define DICT_UPDATE 66 -+#define EXTENDED_ARG 67 -+#define FOR_ITER 68 -+#define GET_AWAITABLE 69 -+#define IMPORT_FROM 70 -+#define IMPORT_NAME 71 -+#define IS_OP 72 -+#define JUMP_BACKWARD 73 -+#define JUMP_BACKWARD_NO_INTERRUPT 74 -+#define JUMP_FORWARD 75 -+#define LIST_APPEND 76 -+#define LIST_EXTEND 77 -+#define LOAD_ATTR 78 -+#define LOAD_COMMON_CONSTANT 79 -+#define LOAD_CONST 80 -+#define LOAD_DEREF 81 -+#define LOAD_FAST 82 -+#define LOAD_FAST_AND_CLEAR 83 -+#define LOAD_FAST_CHECK 84 -+#define LOAD_FAST_LOAD_FAST 85 -+#define LOAD_FROM_DICT_OR_DEREF 86 -+#define LOAD_FROM_DICT_OR_GLOBALS 87 -+#define LOAD_GLOBAL 88 -+#define LOAD_NAME 89 -+#define LOAD_SMALL_INT 90 -+#define LOAD_SPECIAL 91 -+#define LOAD_SUPER_ATTR 92 -+#define MAKE_CELL 93 -+#define MAP_ADD 94 -+#define MATCH_CLASS 95 -+#define POP_JUMP_IF_FALSE 96 -+#define POP_JUMP_IF_NONE 97 -+#define POP_JUMP_IF_NOT_NONE 98 -+#define POP_JUMP_IF_TRUE 99 -+#define RAISE_VARARGS 100 -+#define RERAISE 101 -+#define SEND 102 -+#define SET_ADD 103 -+#define SET_FUNCTION_ATTRIBUTE 104 -+#define SET_UPDATE 105 -+#define STORE_ATTR 106 -+#define STORE_DEREF 107 -+#define STORE_FAST 108 -+#define STORE_FAST_LOAD_FAST 109 -+#define STORE_FAST_STORE_FAST 110 -+#define STORE_GLOBAL 111 -+#define STORE_NAME 112 -+#define SWAP 113 -+#define UNPACK_EX 114 -+#define UNPACK_SEQUENCE 115 -+#define YIELD_VALUE 116 - #define RESUME 149 - #define BINARY_OP_ADD_FLOAT 150 - #define BINARY_OP_ADD_INT 151 - #define BINARY_OP_ADD_UNICODE 152 --#define BINARY_OP_MULTIPLY_FLOAT 153 --#define BINARY_OP_MULTIPLY_INT 154 --#define BINARY_OP_SUBTRACT_FLOAT 155 --#define BINARY_OP_SUBTRACT_INT 156 --#define BINARY_SUBSCR_DICT 157 --#define BINARY_SUBSCR_GETITEM 158 --#define BINARY_SUBSCR_LIST_INT 159 --#define BINARY_SUBSCR_STR_INT 160 --#define BINARY_SUBSCR_TUPLE_INT 161 --#define CALL_ALLOC_AND_ENTER_INIT 162 --#define CALL_BOUND_METHOD_EXACT_ARGS 163 --#define CALL_BOUND_METHOD_GENERAL 164 --#define CALL_BUILTIN_CLASS 165 --#define CALL_BUILTIN_FAST 166 --#define CALL_BUILTIN_FAST_WITH_KEYWORDS 167 --#define CALL_BUILTIN_O 168 --#define CALL_ISINSTANCE 169 --#define CALL_KW_BOUND_METHOD 170 --#define CALL_KW_NON_PY 171 --#define CALL_KW_PY 172 --#define CALL_LEN 173 --#define CALL_LIST_APPEND 174 --#define CALL_METHOD_DESCRIPTOR_FAST 175 --#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 176 --#define CALL_METHOD_DESCRIPTOR_NOARGS 177 --#define CALL_METHOD_DESCRIPTOR_O 178 --#define CALL_NON_PY_GENERAL 179 --#define CALL_PY_EXACT_ARGS 180 --#define CALL_PY_GENERAL 181 --#define CALL_STR_1 182 --#define CALL_TUPLE_1 183 --#define CALL_TYPE_1 184 --#define COMPARE_OP_FLOAT 185 --#define COMPARE_OP_INT 186 --#define COMPARE_OP_STR 187 --#define CONTAINS_OP_DICT 188 --#define CONTAINS_OP_SET 189 --#define FOR_ITER_GEN 190 --#define FOR_ITER_LIST 191 --#define FOR_ITER_RANGE 192 --#define FOR_ITER_TUPLE 193 --#define LOAD_ATTR_CLASS 194 --#define LOAD_ATTR_CLASS_WITH_METACLASS_CHECK 195 --#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 196 --#define LOAD_ATTR_INSTANCE_VALUE 197 --#define LOAD_ATTR_METHOD_LAZY_DICT 198 --#define LOAD_ATTR_METHOD_NO_DICT 199 --#define LOAD_ATTR_METHOD_WITH_VALUES 200 --#define LOAD_ATTR_MODULE 201 --#define LOAD_ATTR_NONDESCRIPTOR_NO_DICT 202 --#define LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 203 --#define LOAD_ATTR_PROPERTY 204 --#define LOAD_ATTR_SLOT 205 --#define LOAD_ATTR_WITH_HINT 206 --#define LOAD_CONST_IMMORTAL 207 --#define LOAD_GLOBAL_BUILTIN 208 --#define LOAD_GLOBAL_MODULE 209 --#define LOAD_SUPER_ATTR_ATTR 210 --#define LOAD_SUPER_ATTR_METHOD 211 --#define RESUME_CHECK 212 --#define SEND_GEN 213 --#define STORE_ATTR_INSTANCE_VALUE 214 --#define STORE_ATTR_SLOT 215 --#define STORE_ATTR_WITH_HINT 216 --#define STORE_SUBSCR_DICT 217 --#define STORE_SUBSCR_LIST_INT 218 --#define TO_BOOL_ALWAYS_TRUE 219 --#define TO_BOOL_BOOL 220 --#define TO_BOOL_INT 221 --#define TO_BOOL_LIST 222 --#define TO_BOOL_NONE 223 --#define TO_BOOL_STR 224 --#define UNPACK_SEQUENCE_LIST 225 --#define UNPACK_SEQUENCE_TUPLE 226 --#define UNPACK_SEQUENCE_TWO_TUPLE 227 --#define INSTRUMENTED_END_FOR 237 --#define INSTRUMENTED_END_SEND 238 --#define INSTRUMENTED_LOAD_SUPER_ATTR 239 --#define INSTRUMENTED_FOR_ITER 240 --#define INSTRUMENTED_CALL_KW 241 --#define INSTRUMENTED_CALL_FUNCTION_EX 242 --#define INSTRUMENTED_INSTRUCTION 243 --#define INSTRUMENTED_JUMP_FORWARD 244 --#define INSTRUMENTED_POP_JUMP_IF_TRUE 245 --#define INSTRUMENTED_POP_JUMP_IF_FALSE 246 --#define INSTRUMENTED_POP_JUMP_IF_NONE 247 --#define INSTRUMENTED_POP_JUMP_IF_NOT_NONE 248 --#define INSTRUMENTED_RESUME 249 --#define INSTRUMENTED_RETURN_VALUE 250 --#define INSTRUMENTED_YIELD_VALUE 251 --#define INSTRUMENTED_CALL 252 -+#define BINARY_OP_EXTEND 153 -+#define BINARY_OP_MULTIPLY_FLOAT 154 -+#define BINARY_OP_MULTIPLY_INT 155 -+#define BINARY_OP_SUBSCR_DICT 156 -+#define BINARY_OP_SUBSCR_GETITEM 157 -+#define BINARY_OP_SUBSCR_LIST_INT 158 -+#define BINARY_OP_SUBSCR_STR_INT 159 -+#define BINARY_OP_SUBSCR_TUPLE_INT 160 -+#define BINARY_OP_SUBTRACT_FLOAT 161 -+#define BINARY_OP_SUBTRACT_INT 162 -+#define CALL_ALLOC_AND_ENTER_INIT 163 -+#define CALL_BOUND_METHOD_EXACT_ARGS 164 -+#define CALL_BOUND_METHOD_GENERAL 165 -+#define CALL_BUILTIN_CLASS 166 -+#define CALL_BUILTIN_FAST 167 -+#define CALL_BUILTIN_FAST_WITH_KEYWORDS 168 -+#define CALL_BUILTIN_O 169 -+#define CALL_ISINSTANCE 170 -+#define CALL_KW_BOUND_METHOD 171 -+#define CALL_KW_NON_PY 172 -+#define CALL_KW_PY 173 -+#define CALL_LEN 174 -+#define CALL_LIST_APPEND 175 -+#define CALL_METHOD_DESCRIPTOR_FAST 176 -+#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 177 -+#define CALL_METHOD_DESCRIPTOR_NOARGS 178 -+#define CALL_METHOD_DESCRIPTOR_O 179 -+#define CALL_NON_PY_GENERAL 180 -+#define CALL_PY_EXACT_ARGS 181 -+#define CALL_PY_GENERAL 182 -+#define CALL_STR_1 183 -+#define CALL_TUPLE_1 184 -+#define CALL_TYPE_1 185 -+#define COMPARE_OP_FLOAT 186 -+#define COMPARE_OP_INT 187 -+#define COMPARE_OP_STR 188 -+#define CONTAINS_OP_DICT 189 -+#define CONTAINS_OP_SET 190 -+#define FOR_ITER_GEN 191 -+#define FOR_ITER_LIST 192 -+#define FOR_ITER_RANGE 193 -+#define FOR_ITER_TUPLE 194 -+#define JUMP_BACKWARD_JIT 195 -+#define JUMP_BACKWARD_NO_JIT 196 -+#define LOAD_ATTR_CLASS 197 -+#define LOAD_ATTR_CLASS_WITH_METACLASS_CHECK 198 -+#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 199 -+#define LOAD_ATTR_INSTANCE_VALUE 200 -+#define LOAD_ATTR_METHOD_LAZY_DICT 201 -+#define LOAD_ATTR_METHOD_NO_DICT 202 -+#define LOAD_ATTR_METHOD_WITH_VALUES 203 -+#define LOAD_ATTR_MODULE 204 -+#define LOAD_ATTR_NONDESCRIPTOR_NO_DICT 205 -+#define LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 206 -+#define LOAD_ATTR_PROPERTY 207 -+#define LOAD_ATTR_SLOT 208 -+#define LOAD_ATTR_WITH_HINT 209 -+#define LOAD_CONST_IMMORTAL 210 -+#define LOAD_CONST_MORTAL 211 -+#define LOAD_GLOBAL_BUILTIN 212 -+#define LOAD_GLOBAL_MODULE 213 -+#define LOAD_SUPER_ATTR_ATTR 214 -+#define LOAD_SUPER_ATTR_METHOD 215 -+#define RESUME_CHECK 216 -+#define SEND_GEN 217 -+#define STORE_ATTR_INSTANCE_VALUE 218 -+#define STORE_ATTR_SLOT 219 -+#define STORE_ATTR_WITH_HINT 220 -+#define STORE_SUBSCR_DICT 221 -+#define STORE_SUBSCR_LIST_INT 222 -+#define TO_BOOL_ALWAYS_TRUE 223 -+#define TO_BOOL_BOOL 224 -+#define TO_BOOL_INT 225 -+#define TO_BOOL_LIST 226 -+#define TO_BOOL_NONE 227 -+#define TO_BOOL_STR 228 -+#define UNPACK_SEQUENCE_LIST 229 -+#define UNPACK_SEQUENCE_TUPLE 230 -+#define UNPACK_SEQUENCE_TWO_TUPLE 231 -+#define INSTRUMENTED_END_FOR 235 -+#define INSTRUMENTED_POP_ITER 236 -+#define INSTRUMENTED_END_SEND 237 -+#define INSTRUMENTED_FOR_ITER 238 -+#define INSTRUMENTED_INSTRUCTION 239 -+#define INSTRUMENTED_JUMP_FORWARD 240 -+#define INSTRUMENTED_NOT_TAKEN 241 -+#define INSTRUMENTED_POP_JUMP_IF_TRUE 242 -+#define INSTRUMENTED_POP_JUMP_IF_FALSE 243 -+#define INSTRUMENTED_POP_JUMP_IF_NONE 244 -+#define INSTRUMENTED_POP_JUMP_IF_NOT_NONE 245 -+#define INSTRUMENTED_RESUME 246 -+#define INSTRUMENTED_RETURN_VALUE 247 -+#define INSTRUMENTED_YIELD_VALUE 248 -+#define INSTRUMENTED_LOAD_SUPER_ATTR 249 -+#define INSTRUMENTED_CALL 250 -+#define INSTRUMENTED_CALL_KW 251 -+#define INSTRUMENTED_CALL_FUNCTION_EX 252 - #define INSTRUMENTED_JUMP_BACKWARD 253 - #define INSTRUMENTED_LINE 254 - #define ENTER_EXECUTOR 255 -@@ -235,9 +242,9 @@ - #define SETUP_WITH 264 - #define STORE_FAST_MAYBE_NULL 265 - --#define HAVE_ARGUMENT 41 -+#define HAVE_ARGUMENT 43 - #define MIN_SPECIALIZED_OPCODE 150 --#define MIN_INSTRUMENTED_OPCODE 237 -+#define MIN_INSTRUMENTED_OPCODE 235 - - #ifdef __cplusplus - } -diff --git a/Include/patchlevel.h b/Include/patchlevel.h -index 1e9df2d9ebd..74b630a762f 100644 ---- a/Include/patchlevel.h -+++ b/Include/patchlevel.h -@@ -1,4 +1,5 @@ -- -+#ifndef _Py_PATCHLEVEL_H -+#define _Py_PATCHLEVEL_H - /* Python version identification scheme. - - When the major or minor version changes, the VERSION variable in -@@ -20,16 +21,29 @@ - #define PY_MINOR_VERSION 14 - #define PY_MICRO_VERSION 0 - #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_ALPHA --#define PY_RELEASE_SERIAL 3 -+#define PY_RELEASE_SERIAL 5 - - /* Version as a string */ --#define PY_VERSION "3.14.0a3" -+#define PY_VERSION "3.14.0a5" - /*--end constants--*/ - -+ -+#define _Py_PACK_FULL_VERSION(X, Y, Z, LEVEL, SERIAL) ( \ -+ (((X) & 0xff) << 24) | \ -+ (((Y) & 0xff) << 16) | \ -+ (((Z) & 0xff) << 8) | \ -+ (((LEVEL) & 0xf) << 4) | \ -+ (((SERIAL) & 0xf) << 0)) -+ - /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. - Use this for numeric comparisons, e.g. #if PY_VERSION_HEX >= ... */ --#define PY_VERSION_HEX ((PY_MAJOR_VERSION << 24) | \ -- (PY_MINOR_VERSION << 16) | \ -- (PY_MICRO_VERSION << 8) | \ -- (PY_RELEASE_LEVEL << 4) | \ -- (PY_RELEASE_SERIAL << 0)) -+#define PY_VERSION_HEX _Py_PACK_FULL_VERSION( \ -+ PY_MAJOR_VERSION, \ -+ PY_MINOR_VERSION, \ -+ PY_MICRO_VERSION, \ -+ PY_RELEASE_LEVEL, \ -+ PY_RELEASE_SERIAL) -+ -+// Public Py_PACK_VERSION is declared in pymacro.h; it needs . -+ -+#endif //_Py_PATCHLEVEL_H -diff --git a/Include/pymacro.h b/Include/pymacro.h -index e0378f9d27a..a82f347866e 100644 ---- a/Include/pymacro.h -+++ b/Include/pymacro.h -@@ -190,4 +190,13 @@ - // "comparison of unsigned expression in '< 0' is always false". - #define _Py_IS_TYPE_SIGNED(type) ((type)(-1) <= 0) - -+#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030E0000 // 3.14 -+// Version helpers. These are primarily macros, but have exported equivalents. -+PyAPI_FUNC(uint32_t) Py_PACK_FULL_VERSION(int x, int y, int z, int level, int serial); -+PyAPI_FUNC(uint32_t) Py_PACK_VERSION(int x, int y); -+#define Py_PACK_FULL_VERSION _Py_PACK_FULL_VERSION -+#define Py_PACK_VERSION(X, Y) Py_PACK_FULL_VERSION(X, Y, 0, 0, 0) -+#endif // Py_LIMITED_API < 3.14 ++ aarch64-apple-watchos*-simulator) CPP=arm64-apple-watchos-simulator-cpp ;; ++ aarch64-apple-watchos*-macabi) CPP=arm64-apple-watchos-macabi-cpp ;; ++ aarch64-apple-watchos*) CPP=arm64_32-apple-watchos-cpp ;; ++ x86_64-apple-watchos*-simulator) CPP=x86_64-apple-watchos-simulator-cpp ;; + *) + esac + fi + if test -z "$CXX"; then + case "$host" in + aarch64-apple-ios*-simulator) CXX=arm64-apple-ios-simulator-clang++ ;; ++ aarch64-apple-ios*-macabi) CXX=arm64-apple-ios-macabi-clang++ ;; + aarch64-apple-ios*) CXX=arm64-apple-ios-clang++ ;; + x86_64-apple-ios*-simulator) CXX=x86_64-apple-ios-simulator-clang++ ;; + ++ aarch64-apple-tvos*-simulator) CXX=arm64-apple-tvos-simulator-clang++ ;; ++ aarch64-apple-tvos*-macabi) CXX=arm64-apple-tvos-macabi-clang++ ;; ++ aarch64-apple-tvos*) CXX=arm64-apple-tvos-clang++ ;; ++ x86_64-apple-tvos*-simulator) CXX=x86_64-apple-tvos-simulator-clang++ ;; + - #endif /* Py_PYMACRO_H */ -diff --git a/Include/pyport.h b/Include/pyport.h -index 2b6bd4c2111..aabd094df54 100644 ---- a/Include/pyport.h -+++ b/Include/pyport.h -@@ -625,8 +625,13 @@ - // case 2: code; break; - // } - // --// __attribute__((fallthrough)) was introduced in GCC 7. --#if _Py__has_attribute(fallthrough) -+// __attribute__((fallthrough)) was introduced in GCC 7 and Clang 10 / -+// Apple Clang 12.0. Earlier Clang versions support only the C++11 -+// style fallthrough attribute, not the GCC extension syntax used here, -+// and __has_attribute(fallthrough) evaluates to 1. -+#if _Py__has_attribute(fallthrough) && (!defined(__clang__) || \ -+ (!defined(__apple_build_version__) && __clang_major__ >= 10) || \ -+ (defined(__apple_build_version__) && __clang_major__ >= 12)) - # define _Py_FALLTHROUGH __attribute__((fallthrough)) - #else - # define _Py_FALLTHROUGH do { } while (0) -diff --git a/InternalDocs/README.md b/InternalDocs/README.md -index 794b4f3c6aa..4502902307c 100644 ---- a/InternalDocs/README.md -+++ b/InternalDocs/README.md -@@ -25,7 +25,7 @@ - - - [Code Objects](code_objects.md) - --- [Generators (coming soon)](generators.md) -+- [Generators](generators.md) - - - [Frames](frames.md) - -diff --git a/InternalDocs/compiler.md b/InternalDocs/compiler.md -index c257bfd9faf..8ca19a42b91 100644 ---- a/InternalDocs/compiler.md -+++ b/InternalDocs/compiler.md -@@ -401,7 +401,7 @@ - add the `LOAD_CONST` opcode with the proper argument based on the - position of the specified PyObject in the consts table. - * `ADDOP_LOAD_CONST_NEW(struct compiler *, location, PyObject *)`: -- just like `ADDOP_LOAD_CONST_NEW`, but steals a reference to PyObject -+ just like `ADDOP_LOAD_CONST`, but steals a reference to PyObject - * `ADDOP_JUMP(struct compiler *, location, int, basicblock *)`: - create a jump to a basic block - -diff --git a/InternalDocs/frames.md b/InternalDocs/frames.md -index 2598873ca98..1a909009eea 100644 ---- a/InternalDocs/frames.md -+++ b/InternalDocs/frames.md -@@ -33,7 +33,7 @@ - * Stack - - This seems to provide the best performance without excessive complexity. --The specials have a fixed size, so the offset of the locals is know. The -+The specials have a fixed size, so the offset of the locals is known. The - interpreter needs to hold two pointers, a frame pointer and a stack pointer. - - #### Alternative layout -@@ -52,7 +52,7 @@ - ### Generators and Coroutines - - Generators and coroutines contain a `_PyInterpreterFrame` --The specials sections contains the following pointers: -+The specials section contains the following pointers: - - * Globals dict - * Builtins dict -@@ -69,7 +69,7 @@ ++ aarch64-apple-watchos*-simulator) CXX=arm64-apple-watchos-simulator-clang++ ;; ++ aarch64-apple-watchos*-macabi) CXX=arm64-apple-watchos-macabi-clang++ ;; ++ aarch64-apple-watchos*) CXX=arm64_32-apple-watchos-clang++ ;; ++ x86_64-apple-watchos*-simulator) CXX=x86_64-apple-watchos-simulator-clang++ ;; + *) + esac + fi +@@ -4342,8 +4390,10 @@ + case $enableval in + yes) + case $ac_sys_system in +- Darwin) enableval=/Library/Frameworks ;; +- iOS) enableval=iOS/Frameworks/\$\(MULTIARCH\) ;; ++ Darwin) enableval=/Library/Frameworks ;; ++ iOS) enableval=iOS/Frameworks/\$\(MULTIARCH\) ;; ++ tvOS) enableval=tvOS/Frameworks/\$\(MULTIARCH\) ;; ++ watchOS) enableval=watchOS/Frameworks/\$\(MULTIARCH\) ;; + *) as_fn_error $? "Unknown platform for framework build" "$LINENO" 5 + esac + esac +@@ -4352,6 +4402,8 @@ + no) + case $ac_sys_system in + iOS) as_fn_error $? "iOS builds must use --enable-framework" "$LINENO" 5 ;; ++ tvOS) as_fn_error $? "tvOS builds must use --enable-framework" "$LINENO" 5 ;; ++ watchOS) as_fn_error $? "watchOS builds must use --enable-framework" "$LINENO" 5 ;; + *) + PYTHONFRAMEWORK= + PYTHONFRAMEWORKDIR=no-framework +@@ -4458,6 +4510,36 @@ - When creating a backtrace or when calling `sys._getframe()` the frame becomes - visible to Python code. When this happens a new `PyFrameObject` is created --and a strong reference to it placed in the `frame_obj` field of the specials -+and a strong reference to it is placed in the `frame_obj` field of the specials - section. The `frame_obj` field is initially `NULL`. + ac_config_files="$ac_config_files iOS/Resources/Info.plist" - The `PyFrameObject` may outlive a stack-allocated `_PyInterpreterFrame`. -@@ -128,7 +128,7 @@ - relative to `instr_ptr`. It is only meaningful to the callee, so it needs to - be set in any instruction that implements a call (to a Python function), - including CALL, SEND and BINARY_SUBSCR_GETITEM, among others. If there is no --callee, then return_offset is meaningless. It is necessary to have a separate -+callee, then return_offset is meaningless. It is necessary to have a separate - field for the return offset because (1) if we apply this offset to `instr_ptr` - while executing the `RETURN`, this is too early and would lose us information - about the previous instruction which we could need for introspecting and -diff --git a/InternalDocs/generators.md b/InternalDocs/generators.md -index afa8b8f4bb8..87fbb912368 100644 ---- a/InternalDocs/generators.md -+++ b/InternalDocs/generators.md -@@ -1,8 +1,106 @@ -+ -+Generators and Coroutines -+========================= -+ - Generators --========== -+---------- -+ -+Generators in CPython are implemented with the struct `PyGenObject`. -+They consist of a [`frame`](frames.md) and metadata about the generator's -+execution state. -+ -+A generator object resumes execution in its frame when its `send()` -+method is called. This is analogous to a function executing in its own -+frame when it is called, but a function returns to the calling frame only once, -+while a generator "returns" execution to the caller's frame every time -+it emits a new item with a -+[`yield` expression](https://docs.python.org/dev/reference/expressions.html#yield-expressions). -+This is implemented by the -+[`YIELD_VALUE`](https://docs.python.org/dev/library/dis.html#opcode-YIELD_VALUE) -+bytecode, which is similar to -+[`RETURN_VALUE`](https://docs.python.org/dev/library/dis.html#opcode-RETURN_VALUE) -+in the sense that it puts a value on the stack and returns execution to the -+calling frame, but it also needs to perform additional work to leave the generator -+frame in a state that allows it to be resumed. In particular, it updates the frame's -+instruction pointer and stores the interpreter's exception state on the generator -+object. When the generator is resumed, this exception state is copied back to the -+interpreter state. -+ -+The `frame` of a generator is embedded in the generator object struct as a -+[`_PyInterpreterFrame`](frames.md) (see `_PyGenObject_HEAD` in -+[`pycore_genobject.h`](../Include/internal/pycore_genobject.h)). -+This means that we can get the frame from the generator or the generator -+from the frame (see `_PyGen_GetGeneratorFromFrame` in the same file). -+Other fields of the generator struct include metadata (such as the name of -+the generator function) and runtime state information (such as whether its -+frame is executing, suspended, cleared, etc.). -+ -+Generator Object Creation and Destruction -+----------------------------------------- -+ -+The bytecode of a generator function begins with a -+[`RETURN_GENERATOR`](https://docs.python.org/dev/library/dis.html#opcode-RETURN_GENERATOR) -+instruction, which creates a generator object, including its embedded frame. -+The generator's frame is initialized as a copy of the frame in which -+`RETURN_GENERATOR` is executing, but its `owner` field is overwritten to indicate -+that it is owned by a generator. Finally, `RETURN_GENERATOR` pushes the new generator -+object to the stack and returns to the caller of the generator function (at -+which time its frame is destroyed). When the generator is next resumed by -+[`gen_send_ex2()`](../Objects/genobject.c), `_PyEval_EvalFrame()` is called -+to continue executing the generator function, in the frame that is embedded in -+the generator object. -+ -+When a generator object is destroyed in [`gen_dealloc`](../Objects/genobject.c), -+its embedded `_PyInterpreterFrame` field may need to be preserved, if it is exposed -+to Python as part of a [`PyFrameObject`](frames.md#frame-objects). This is detected -+in [`_PyFrame_ClearExceptCode`](../Python/frame.c) by the fact that the interpreter -+frame's `frame_obj` field is set, and the frame object it points to has refcount -+greater than 1. If so, the `take_ownership()` function is called to create a new -+copy of the interpreter frame and transfer ownership of it from the generator to -+the frame object. -+ -+Iteration -+--------- -+ -+The [`FOR_ITER`](https://docs.python.org/dev/library/dis.html#opcode-FOR_ITER) -+instruction calls `__next__` on the iterator which is on the top of the stack, -+and pushes the result to the stack. It has [`specializations`](adaptive.md) -+for a few common iterator types, including `FOR_ITER_GEN`, for iterating over -+a generator. `FOR_ITER_GEN` bypasses the call to `__next__`, and instead -+directly pushes the generator stack and resumes its execution from the -+instruction that follows the last yield. ++ ;; ++ tvOS) : ++ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure" ++ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure " ++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKPYTHONW= ++ INSTALLTARGETS="libinstall inclinstall sharedinstall" + -+Chained Generators -+------------------ ++ prefix=$PYTHONFRAMEWORKPREFIX ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" ++ RESSRCDIR=tvOS/Resources + -+A `yield from` expression creates a generator that efficiently yields the -+sequence created by another generator. This is implemented with the -+[`SEND` instruction](https://docs.python.org/dev/library/dis.html#opcode-SEND), -+which pushes the value of its arg to the stack of the generator's frame, sets -+the exception state on this frame, and resumes execution of the chained generator. -+On return from `SEND`, the value at the top of the stack is sent back up -+the generator chain with a `YIELD_VALUE`. This sequence of `SEND` followed by -+`YIELD_VALUE` is repeated in a loop, until a `StopIteration` exception is -+raised to indicate that the generator has no more values to emit. ++ ac_config_files="$ac_config_files tvOS/Resources/Info.plist" + -+The [`CLEANUP_THROW`](https://docs.python.org/dev/library/dis.html#opcode-CLEANUP_THROW) -+instruction is used to handle exceptions raised from the send-yield loop. -+Exceptions of type `StopIteration` is handled, their `value` field hold the -+value to be returned by the generator's `close()` function. Any other -+exception is re-raised by `CLEANUP_THROW`. ++ ;; ++ watchOS) : ++ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure" ++ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure " ++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKPYTHONW= ++ INSTALLTARGETS="libinstall inclinstall sharedinstall" + -+Coroutines -+---------- - --Coming soon. -+Coroutines are generators that use the value returned from a `yield` expression, -+i.e., the argument that was passed to the `.send()` call that resumed it after -+it yielded. This makes it possible for data to flow in both directions: from -+the generator to the caller via the argument of the `yield` expression, and -+from the caller to the generator via the send argument to the `send()` call. -+A `yield from` expression passes the `send` argument to the chained generator, -+so this data flow works along the chain (see `gen_send_ex2()` in -+[`genobject.c`](../Objects/genobject.c)). - -- -+Recall that a generator's `__next__` function simply calls `self.send(None)`, -+so all this works the same in generators and coroutines, but only coroutines -+use the value of the argument to `send`. -diff --git a/InternalDocs/interpreter.md b/InternalDocs/interpreter.md -index fa4a54fdc54..52702792c6c 100644 ---- a/InternalDocs/interpreter.md -+++ b/InternalDocs/interpreter.md -@@ -20,7 +20,7 @@ - [`PyEval_EvalCode()`](https://docs.python.org/3.14/c-api/veryhigh.html#c.PyEval_EvalCode) - function is called to execute a `CodeObject`, it constructs a [`Frame`](frames.md) and calls - [`_PyEval_EvalFrame()`](https://docs.python.org/3.14/c-api/veryhigh.html#c.PyEval_EvalCode) --to execute the code object in this frame. The frame hold the dynamic state of the -+to execute the code object in this frame. The frame holds the dynamic state of the - `CodeObject`'s execution, including the instruction pointer, the globals and builtins. - It also has a reference to the `CodeObject` itself. - -@@ -153,9 +153,9 @@ - Most instructions read or write some data in the form of object references (`PyObject *`). - The CPython bytecode interpreter is a stack machine, meaning that its instructions operate - by pushing data onto and popping it off the stack. --The stack is forms part of the frame for the code object. Its maximum depth is calculated -+The stack forms part of the frame for the code object. Its maximum depth is calculated - by the compiler and stored in the `co_stacksize` field of the code object, so that the --stack can be pre-allocated is a contiguous array of `PyObject*` pointers, when the frame -+stack can be pre-allocated as a contiguous array of `PyObject*` pointers, when the frame - is created. - - The stack effects of each instruction are also exposed through the -@@ -462,7 +462,7 @@ - 2. Perform the operation quickly. - - This requires that the set of values is chosen such that membership can be --tested quickly and that membership is sufficient to allow the operation to -+tested quickly and that membership is sufficient to allow the operation to be - performed quickly. - - For example, `LOAD_GLOBAL_MODULE` is specialized for `globals()` -diff --git a/InternalDocs/jit.md b/InternalDocs/jit.md -index 1e9f385d5f8..2c204f39792 100644 ---- a/InternalDocs/jit.md -+++ b/InternalDocs/jit.md -@@ -38,12 +38,8 @@ - - ## The micro-op optimizer - --The optimizer that `_PyOptimizer_Optimize()` runs is configurable via the --`_Py_SetTier2Optimizer()` function (this is used in test via --`_testinternalcapi.set_optimizer()`.) -- - The micro-op (abbreviated `uop` to approximate `μop`) optimizer is defined in --[`Python/optimizer.c`](../Python/optimizer.c) as the type `_PyUOpOptimizer_Type`. -+[`Python/optimizer.c`](../Python/optimizer.c) as `_PyOptimizer_Optimize`. - It translates an instruction trace into a sequence of micro-ops by replacing - each bytecode by an equivalent sequence of micro-ops (see - `_PyOpcode_macro_expansion` in -diff --git a/InternalDocs/parser.md b/InternalDocs/parser.md -index 445b866fc0c..be47efe2435 100644 ---- a/InternalDocs/parser.md -+++ b/InternalDocs/parser.md -@@ -56,7 +56,7 @@ - - Note that "failure" results do not imply that the program is incorrect, nor do - they necessarily mean that the parsing has failed. Since the choice operator is --ordered, a failure very often merely indicates "try the following option". A -+ordered, a failure very often merely indicates "try the following option". A - direct implementation of a PEG parser as a recursive descent parser will present - exponential time performance in the worst case, because PEG parsers have - infinite lookahead (this means that they can consider an arbitrary number of -@@ -253,7 +253,7 @@ - If the action is omitted, a default action is generated: - - - If there is a single name in the rule, it gets returned. --- If there multiple names in the rule, a collection with all parsed -+- If there are multiple names in the rule, a collection with all parsed - expressions gets returned (the type of the collection will be different - in C and Python). - -@@ -447,7 +447,7 @@ - $ make regen-pegen - ``` - --using the `Makefile` in the main directory. If you are on Windows you can -+using the `Makefile` in the main directory. If you are on Windows you can - use the Visual Studio project files to regenerate the parser or to execute: - - ```dos -@@ -539,7 +539,7 @@ - The C parser used by Python is highly optimized and memoization can be expensive - both in memory and time. Although the memory cost is obvious (the parser needs - memory for storing previous results in the cache) the execution time cost comes --for continuously checking if the given rule has a cache hit or not. In many -+from continuously checking if the given rule has a cache hit or not. In many - situations, just parsing it again can be faster. Pegen **disables memoization - by default** except for rules with the special marker `memo` after the rule - name (and type, if present): -@@ -605,7 +605,7 @@ - SyntaxError: invalid syntax - ``` - --While soft keywords don't have this limitation if used in a context other the -+While soft keywords don't have this limitation if used in a context other than - one where they are defined as keywords: - - ```pycon -diff --git a/Lib/_colorize.py b/Lib/_colorize.py -index 709081e25ec..41e818f2a74 100644 ---- a/Lib/_colorize.py -+++ b/Lib/_colorize.py -@@ -6,9 +6,11 @@ - - - class ANSIColors: -+ BACKGROUND_YELLOW = "\x1b[43m" - BOLD_GREEN = "\x1b[1;32m" - BOLD_MAGENTA = "\x1b[1;35m" - BOLD_RED = "\x1b[1;31m" -+ BLACK = "\x1b[30m" - GREEN = "\x1b[32m" - GREY = "\x1b[90m" - MAGENTA = "\x1b[35m" -@@ -24,30 +26,32 @@ - setattr(NoColors, attr, "") - - --def get_colors(colorize: bool = False) -> ANSIColors: -- if colorize or can_colorize(): -+def get_colors(colorize: bool = False, *, file=None) -> ANSIColors: -+ if colorize or can_colorize(file=file): - return ANSIColors() - else: - return NoColors - - --def can_colorize() -> bool: -+def can_colorize(*, file=None) -> bool: -+ if file is None: -+ file = sys.stdout ++ prefix=$PYTHONFRAMEWORKPREFIX ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" ++ RESSRCDIR=watchOS/Resources + - if not sys.flags.ignore_environment: - if os.environ.get("PYTHON_COLORS") == "0": - return False - if os.environ.get("PYTHON_COLORS") == "1": - return True -- if "NO_COLOR" in os.environ: -- return False -+ if os.environ.get("NO_COLOR"): -+ return False - if not COLORIZE: - return False -- if not sys.flags.ignore_environment: -- if "FORCE_COLOR" in os.environ: -- return True -- if os.environ.get("TERM") == "dumb": -- return False -+ if os.environ.get("FORCE_COLOR"): -+ return True -+ if os.environ.get("TERM") == "dumb": -+ return False - -- if not hasattr(sys.stderr, "fileno"): -+ if not hasattr(file, "fileno"): - return False - - if sys.platform == "win32": -@@ -60,6 +64,6 @@ - return False - - try: -- return os.isatty(sys.stderr.fileno()) -+ return os.isatty(file.fileno()) - except io.UnsupportedOperation: -- return sys.stderr.isatty() -+ return file.isatty() -diff --git a/Lib/_markupbase.py b/Lib/_markupbase.py -index 3ad7e279960..614f0cd16dd 100644 ---- a/Lib/_markupbase.py -+++ b/Lib/_markupbase.py -@@ -13,7 +13,7 @@ - _markedsectionclose = re.compile(r']\s*]\s*>') - - # An analysis of the MS-Word extensions is available at --# http://www.planetpublish.com/xmlarena/xap/Thursday/WordtoXML.pdf -+# http://web.archive.org/web/20060321153828/http://www.planetpublish.com/xmlarena/xap/Thursday/WordtoXML.pdf - - _msmarkedsectionclose = re.compile(r']\s*>') - -diff --git a/Lib/_opcode_metadata.py b/Lib/_opcode_metadata.py -index cda3c340c32..0e18792402d 100644 ---- a/Lib/_opcode_metadata.py -+++ b/Lib/_opcode_metadata.py -@@ -7,6 +7,7 @@ - "RESUME_CHECK", - ], - "LOAD_CONST": [ -+ "LOAD_CONST_MORTAL", - "LOAD_CONST_IMMORTAL", - ], - "TO_BOOL": [ -@@ -25,15 +26,14 @@ - "BINARY_OP_ADD_FLOAT", - "BINARY_OP_SUBTRACT_FLOAT", - "BINARY_OP_ADD_UNICODE", -+ "BINARY_OP_SUBSCR_LIST_INT", -+ "BINARY_OP_SUBSCR_TUPLE_INT", -+ "BINARY_OP_SUBSCR_STR_INT", -+ "BINARY_OP_SUBSCR_DICT", -+ "BINARY_OP_SUBSCR_GETITEM", -+ "BINARY_OP_EXTEND", - "BINARY_OP_INPLACE_ADD_UNICODE", - ], -- "BINARY_SUBSCR": [ -- "BINARY_SUBSCR_DICT", -- "BINARY_SUBSCR_GETITEM", -- "BINARY_SUBSCR_LIST_INT", -- "BINARY_SUBSCR_STR_INT", -- "BINARY_SUBSCR_TUPLE_INT", -- ], - "STORE_SUBSCR": [ - "STORE_SUBSCR_DICT", - "STORE_SUBSCR_LIST_INT", -@@ -83,6 +83,10 @@ - "CONTAINS_OP_SET", - "CONTAINS_OP_DICT", - ], -+ "JUMP_BACKWARD": [ -+ "JUMP_BACKWARD_NO_JIT", -+ "JUMP_BACKWARD_JIT", -+ ], - "FOR_ITER": [ - "FOR_ITER_LIST", - "FOR_ITER_TUPLE", -@@ -122,82 +126,86 @@ - 'BINARY_OP_ADD_FLOAT': 150, - 'BINARY_OP_ADD_INT': 151, - 'BINARY_OP_ADD_UNICODE': 152, -+ 'BINARY_OP_EXTEND': 153, - 'BINARY_OP_INPLACE_ADD_UNICODE': 3, -- 'BINARY_OP_MULTIPLY_FLOAT': 153, -- 'BINARY_OP_MULTIPLY_INT': 154, -- 'BINARY_OP_SUBTRACT_FLOAT': 155, -- 'BINARY_OP_SUBTRACT_INT': 156, -- 'BINARY_SUBSCR_DICT': 157, -- 'BINARY_SUBSCR_GETITEM': 158, -- 'BINARY_SUBSCR_LIST_INT': 159, -- 'BINARY_SUBSCR_STR_INT': 160, -- 'BINARY_SUBSCR_TUPLE_INT': 161, -- 'CALL_ALLOC_AND_ENTER_INIT': 162, -- 'CALL_BOUND_METHOD_EXACT_ARGS': 163, -- 'CALL_BOUND_METHOD_GENERAL': 164, -- 'CALL_BUILTIN_CLASS': 165, -- 'CALL_BUILTIN_FAST': 166, -- 'CALL_BUILTIN_FAST_WITH_KEYWORDS': 167, -- 'CALL_BUILTIN_O': 168, -- 'CALL_ISINSTANCE': 169, -- 'CALL_KW_BOUND_METHOD': 170, -- 'CALL_KW_NON_PY': 171, -- 'CALL_KW_PY': 172, -- 'CALL_LEN': 173, -- 'CALL_LIST_APPEND': 174, -- 'CALL_METHOD_DESCRIPTOR_FAST': 175, -- 'CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS': 176, -- 'CALL_METHOD_DESCRIPTOR_NOARGS': 177, -- 'CALL_METHOD_DESCRIPTOR_O': 178, -- 'CALL_NON_PY_GENERAL': 179, -- 'CALL_PY_EXACT_ARGS': 180, -- 'CALL_PY_GENERAL': 181, -- 'CALL_STR_1': 182, -- 'CALL_TUPLE_1': 183, -- 'CALL_TYPE_1': 184, -- 'COMPARE_OP_FLOAT': 185, -- 'COMPARE_OP_INT': 186, -- 'COMPARE_OP_STR': 187, -- 'CONTAINS_OP_DICT': 188, -- 'CONTAINS_OP_SET': 189, -- 'FOR_ITER_GEN': 190, -- 'FOR_ITER_LIST': 191, -- 'FOR_ITER_RANGE': 192, -- 'FOR_ITER_TUPLE': 193, -- 'LOAD_ATTR_CLASS': 194, -- 'LOAD_ATTR_CLASS_WITH_METACLASS_CHECK': 195, -- 'LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN': 196, -- 'LOAD_ATTR_INSTANCE_VALUE': 197, -- 'LOAD_ATTR_METHOD_LAZY_DICT': 198, -- 'LOAD_ATTR_METHOD_NO_DICT': 199, -- 'LOAD_ATTR_METHOD_WITH_VALUES': 200, -- 'LOAD_ATTR_MODULE': 201, -- 'LOAD_ATTR_NONDESCRIPTOR_NO_DICT': 202, -- 'LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES': 203, -- 'LOAD_ATTR_PROPERTY': 204, -- 'LOAD_ATTR_SLOT': 205, -- 'LOAD_ATTR_WITH_HINT': 206, -- 'LOAD_CONST_IMMORTAL': 207, -- 'LOAD_GLOBAL_BUILTIN': 208, -- 'LOAD_GLOBAL_MODULE': 209, -- 'LOAD_SUPER_ATTR_ATTR': 210, -- 'LOAD_SUPER_ATTR_METHOD': 211, -- 'RESUME_CHECK': 212, -- 'SEND_GEN': 213, -- 'STORE_ATTR_INSTANCE_VALUE': 214, -- 'STORE_ATTR_SLOT': 215, -- 'STORE_ATTR_WITH_HINT': 216, -- 'STORE_SUBSCR_DICT': 217, -- 'STORE_SUBSCR_LIST_INT': 218, -- 'TO_BOOL_ALWAYS_TRUE': 219, -- 'TO_BOOL_BOOL': 220, -- 'TO_BOOL_INT': 221, -- 'TO_BOOL_LIST': 222, -- 'TO_BOOL_NONE': 223, -- 'TO_BOOL_STR': 224, -- 'UNPACK_SEQUENCE_LIST': 225, -- 'UNPACK_SEQUENCE_TUPLE': 226, -- 'UNPACK_SEQUENCE_TWO_TUPLE': 227, -+ 'BINARY_OP_MULTIPLY_FLOAT': 154, -+ 'BINARY_OP_MULTIPLY_INT': 155, -+ 'BINARY_OP_SUBSCR_DICT': 156, -+ 'BINARY_OP_SUBSCR_GETITEM': 157, -+ 'BINARY_OP_SUBSCR_LIST_INT': 158, -+ 'BINARY_OP_SUBSCR_STR_INT': 159, -+ 'BINARY_OP_SUBSCR_TUPLE_INT': 160, -+ 'BINARY_OP_SUBTRACT_FLOAT': 161, -+ 'BINARY_OP_SUBTRACT_INT': 162, -+ 'CALL_ALLOC_AND_ENTER_INIT': 163, -+ 'CALL_BOUND_METHOD_EXACT_ARGS': 164, -+ 'CALL_BOUND_METHOD_GENERAL': 165, -+ 'CALL_BUILTIN_CLASS': 166, -+ 'CALL_BUILTIN_FAST': 167, -+ 'CALL_BUILTIN_FAST_WITH_KEYWORDS': 168, -+ 'CALL_BUILTIN_O': 169, -+ 'CALL_ISINSTANCE': 170, -+ 'CALL_KW_BOUND_METHOD': 171, -+ 'CALL_KW_NON_PY': 172, -+ 'CALL_KW_PY': 173, -+ 'CALL_LEN': 174, -+ 'CALL_LIST_APPEND': 175, -+ 'CALL_METHOD_DESCRIPTOR_FAST': 176, -+ 'CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS': 177, -+ 'CALL_METHOD_DESCRIPTOR_NOARGS': 178, -+ 'CALL_METHOD_DESCRIPTOR_O': 179, -+ 'CALL_NON_PY_GENERAL': 180, -+ 'CALL_PY_EXACT_ARGS': 181, -+ 'CALL_PY_GENERAL': 182, -+ 'CALL_STR_1': 183, -+ 'CALL_TUPLE_1': 184, -+ 'CALL_TYPE_1': 185, -+ 'COMPARE_OP_FLOAT': 186, -+ 'COMPARE_OP_INT': 187, -+ 'COMPARE_OP_STR': 188, -+ 'CONTAINS_OP_DICT': 189, -+ 'CONTAINS_OP_SET': 190, -+ 'FOR_ITER_GEN': 191, -+ 'FOR_ITER_LIST': 192, -+ 'FOR_ITER_RANGE': 193, -+ 'FOR_ITER_TUPLE': 194, -+ 'JUMP_BACKWARD_JIT': 195, -+ 'JUMP_BACKWARD_NO_JIT': 196, -+ 'LOAD_ATTR_CLASS': 197, -+ 'LOAD_ATTR_CLASS_WITH_METACLASS_CHECK': 198, -+ 'LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN': 199, -+ 'LOAD_ATTR_INSTANCE_VALUE': 200, -+ 'LOAD_ATTR_METHOD_LAZY_DICT': 201, -+ 'LOAD_ATTR_METHOD_NO_DICT': 202, -+ 'LOAD_ATTR_METHOD_WITH_VALUES': 203, -+ 'LOAD_ATTR_MODULE': 204, -+ 'LOAD_ATTR_NONDESCRIPTOR_NO_DICT': 205, -+ 'LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES': 206, -+ 'LOAD_ATTR_PROPERTY': 207, -+ 'LOAD_ATTR_SLOT': 208, -+ 'LOAD_ATTR_WITH_HINT': 209, -+ 'LOAD_CONST_IMMORTAL': 210, -+ 'LOAD_CONST_MORTAL': 211, -+ 'LOAD_GLOBAL_BUILTIN': 212, -+ 'LOAD_GLOBAL_MODULE': 213, -+ 'LOAD_SUPER_ATTR_ATTR': 214, -+ 'LOAD_SUPER_ATTR_METHOD': 215, -+ 'RESUME_CHECK': 216, -+ 'SEND_GEN': 217, -+ 'STORE_ATTR_INSTANCE_VALUE': 218, -+ 'STORE_ATTR_SLOT': 219, -+ 'STORE_ATTR_WITH_HINT': 220, -+ 'STORE_SUBSCR_DICT': 221, -+ 'STORE_SUBSCR_LIST_INT': 222, -+ 'TO_BOOL_ALWAYS_TRUE': 223, -+ 'TO_BOOL_BOOL': 224, -+ 'TO_BOOL_INT': 225, -+ 'TO_BOOL_LIST': 226, -+ 'TO_BOOL_NONE': 227, -+ 'TO_BOOL_STR': 228, -+ 'UNPACK_SEQUENCE_LIST': 229, -+ 'UNPACK_SEQUENCE_TUPLE': 230, -+ 'UNPACK_SEQUENCE_TWO_TUPLE': 231, - } - - opmap = { -@@ -207,7 +215,7 @@ - 'INSTRUMENTED_LINE': 254, - 'ENTER_EXECUTOR': 255, - 'BINARY_SLICE': 1, -- 'BINARY_SUBSCR': 2, -+ 'CALL_FUNCTION_EX': 2, - 'CHECK_EG_MATCH': 4, - 'CHECK_EXC_MATCH': 5, - 'CLEANUP_THROW': 6, -@@ -231,110 +239,113 @@ - 'MATCH_MAPPING': 25, - 'MATCH_SEQUENCE': 26, - 'NOP': 27, -- 'POP_EXCEPT': 28, -- 'POP_TOP': 29, -- 'PUSH_EXC_INFO': 30, -- 'PUSH_NULL': 31, -- 'RETURN_GENERATOR': 32, -- 'RETURN_VALUE': 33, -- 'SETUP_ANNOTATIONS': 34, -- 'STORE_SLICE': 35, -- 'STORE_SUBSCR': 36, -- 'TO_BOOL': 37, -- 'UNARY_INVERT': 38, -- 'UNARY_NEGATIVE': 39, -- 'UNARY_NOT': 40, -- 'WITH_EXCEPT_START': 41, -- 'BINARY_OP': 42, -- 'BUILD_LIST': 43, -- 'BUILD_MAP': 44, -- 'BUILD_SET': 45, -- 'BUILD_SLICE': 46, -- 'BUILD_STRING': 47, -- 'BUILD_TUPLE': 48, -- 'CALL': 49, -- 'CALL_FUNCTION_EX': 50, -- 'CALL_INTRINSIC_1': 51, -- 'CALL_INTRINSIC_2': 52, -- 'CALL_KW': 53, -- 'COMPARE_OP': 54, -- 'CONTAINS_OP': 55, -- 'CONVERT_VALUE': 56, -- 'COPY': 57, -- 'COPY_FREE_VARS': 58, -- 'DELETE_ATTR': 59, -- 'DELETE_DEREF': 60, -- 'DELETE_FAST': 61, -- 'DELETE_GLOBAL': 62, -- 'DELETE_NAME': 63, -- 'DICT_MERGE': 64, -- 'DICT_UPDATE': 65, -- 'EXTENDED_ARG': 66, -- 'FOR_ITER': 67, -- 'GET_AWAITABLE': 68, -- 'IMPORT_FROM': 69, -- 'IMPORT_NAME': 70, -- 'IS_OP': 71, -- 'JUMP_BACKWARD': 72, -- 'JUMP_BACKWARD_NO_INTERRUPT': 73, -- 'JUMP_FORWARD': 74, -- 'LIST_APPEND': 75, -- 'LIST_EXTEND': 76, -- 'LOAD_ATTR': 77, -- 'LOAD_COMMON_CONSTANT': 78, -- 'LOAD_CONST': 79, -- 'LOAD_DEREF': 80, -- 'LOAD_FAST': 81, -- 'LOAD_FAST_AND_CLEAR': 82, -- 'LOAD_FAST_CHECK': 83, -- 'LOAD_FAST_LOAD_FAST': 84, -- 'LOAD_FROM_DICT_OR_DEREF': 85, -- 'LOAD_FROM_DICT_OR_GLOBALS': 86, -- 'LOAD_GLOBAL': 87, -- 'LOAD_NAME': 88, -- 'LOAD_SMALL_INT': 89, -- 'LOAD_SPECIAL': 90, -- 'LOAD_SUPER_ATTR': 91, -- 'MAKE_CELL': 92, -- 'MAP_ADD': 93, -- 'MATCH_CLASS': 94, -- 'POP_JUMP_IF_FALSE': 95, -- 'POP_JUMP_IF_NONE': 96, -- 'POP_JUMP_IF_NOT_NONE': 97, -- 'POP_JUMP_IF_TRUE': 98, -- 'RAISE_VARARGS': 99, -- 'RERAISE': 100, -- 'SEND': 101, -- 'SET_ADD': 102, -- 'SET_FUNCTION_ATTRIBUTE': 103, -- 'SET_UPDATE': 104, -- 'STORE_ATTR': 105, -- 'STORE_DEREF': 106, -- 'STORE_FAST': 107, -- 'STORE_FAST_LOAD_FAST': 108, -- 'STORE_FAST_STORE_FAST': 109, -- 'STORE_GLOBAL': 110, -- 'STORE_NAME': 111, -- 'SWAP': 112, -- 'UNPACK_EX': 113, -- 'UNPACK_SEQUENCE': 114, -- 'YIELD_VALUE': 115, -- 'INSTRUMENTED_END_FOR': 237, -- 'INSTRUMENTED_END_SEND': 238, -- 'INSTRUMENTED_LOAD_SUPER_ATTR': 239, -- 'INSTRUMENTED_FOR_ITER': 240, -- 'INSTRUMENTED_CALL_KW': 241, -- 'INSTRUMENTED_CALL_FUNCTION_EX': 242, -- 'INSTRUMENTED_INSTRUCTION': 243, -- 'INSTRUMENTED_JUMP_FORWARD': 244, -- 'INSTRUMENTED_POP_JUMP_IF_TRUE': 245, -- 'INSTRUMENTED_POP_JUMP_IF_FALSE': 246, -- 'INSTRUMENTED_POP_JUMP_IF_NONE': 247, -- 'INSTRUMENTED_POP_JUMP_IF_NOT_NONE': 248, -- 'INSTRUMENTED_RESUME': 249, -- 'INSTRUMENTED_RETURN_VALUE': 250, -- 'INSTRUMENTED_YIELD_VALUE': 251, -- 'INSTRUMENTED_CALL': 252, -+ 'NOT_TAKEN': 28, -+ 'POP_EXCEPT': 29, -+ 'POP_ITER': 30, -+ 'POP_TOP': 31, -+ 'PUSH_EXC_INFO': 32, -+ 'PUSH_NULL': 33, -+ 'RETURN_GENERATOR': 34, -+ 'RETURN_VALUE': 35, -+ 'SETUP_ANNOTATIONS': 36, -+ 'STORE_SLICE': 37, -+ 'STORE_SUBSCR': 38, -+ 'TO_BOOL': 39, -+ 'UNARY_INVERT': 40, -+ 'UNARY_NEGATIVE': 41, -+ 'UNARY_NOT': 42, -+ 'WITH_EXCEPT_START': 43, -+ 'BINARY_OP': 44, -+ 'BUILD_LIST': 45, -+ 'BUILD_MAP': 46, -+ 'BUILD_SET': 47, -+ 'BUILD_SLICE': 48, -+ 'BUILD_STRING': 49, -+ 'BUILD_TUPLE': 50, -+ 'CALL': 51, -+ 'CALL_INTRINSIC_1': 52, -+ 'CALL_INTRINSIC_2': 53, -+ 'CALL_KW': 54, -+ 'COMPARE_OP': 55, -+ 'CONTAINS_OP': 56, -+ 'CONVERT_VALUE': 57, -+ 'COPY': 58, -+ 'COPY_FREE_VARS': 59, -+ 'DELETE_ATTR': 60, -+ 'DELETE_DEREF': 61, -+ 'DELETE_FAST': 62, -+ 'DELETE_GLOBAL': 63, -+ 'DELETE_NAME': 64, -+ 'DICT_MERGE': 65, -+ 'DICT_UPDATE': 66, -+ 'EXTENDED_ARG': 67, -+ 'FOR_ITER': 68, -+ 'GET_AWAITABLE': 69, -+ 'IMPORT_FROM': 70, -+ 'IMPORT_NAME': 71, -+ 'IS_OP': 72, -+ 'JUMP_BACKWARD': 73, -+ 'JUMP_BACKWARD_NO_INTERRUPT': 74, -+ 'JUMP_FORWARD': 75, -+ 'LIST_APPEND': 76, -+ 'LIST_EXTEND': 77, -+ 'LOAD_ATTR': 78, -+ 'LOAD_COMMON_CONSTANT': 79, -+ 'LOAD_CONST': 80, -+ 'LOAD_DEREF': 81, -+ 'LOAD_FAST': 82, -+ 'LOAD_FAST_AND_CLEAR': 83, -+ 'LOAD_FAST_CHECK': 84, -+ 'LOAD_FAST_LOAD_FAST': 85, -+ 'LOAD_FROM_DICT_OR_DEREF': 86, -+ 'LOAD_FROM_DICT_OR_GLOBALS': 87, -+ 'LOAD_GLOBAL': 88, -+ 'LOAD_NAME': 89, -+ 'LOAD_SMALL_INT': 90, -+ 'LOAD_SPECIAL': 91, -+ 'LOAD_SUPER_ATTR': 92, -+ 'MAKE_CELL': 93, -+ 'MAP_ADD': 94, -+ 'MATCH_CLASS': 95, -+ 'POP_JUMP_IF_FALSE': 96, -+ 'POP_JUMP_IF_NONE': 97, -+ 'POP_JUMP_IF_NOT_NONE': 98, -+ 'POP_JUMP_IF_TRUE': 99, -+ 'RAISE_VARARGS': 100, -+ 'RERAISE': 101, -+ 'SEND': 102, -+ 'SET_ADD': 103, -+ 'SET_FUNCTION_ATTRIBUTE': 104, -+ 'SET_UPDATE': 105, -+ 'STORE_ATTR': 106, -+ 'STORE_DEREF': 107, -+ 'STORE_FAST': 108, -+ 'STORE_FAST_LOAD_FAST': 109, -+ 'STORE_FAST_STORE_FAST': 110, -+ 'STORE_GLOBAL': 111, -+ 'STORE_NAME': 112, -+ 'SWAP': 113, -+ 'UNPACK_EX': 114, -+ 'UNPACK_SEQUENCE': 115, -+ 'YIELD_VALUE': 116, -+ 'INSTRUMENTED_END_FOR': 235, -+ 'INSTRUMENTED_POP_ITER': 236, -+ 'INSTRUMENTED_END_SEND': 237, -+ 'INSTRUMENTED_FOR_ITER': 238, -+ 'INSTRUMENTED_INSTRUCTION': 239, -+ 'INSTRUMENTED_JUMP_FORWARD': 240, -+ 'INSTRUMENTED_NOT_TAKEN': 241, -+ 'INSTRUMENTED_POP_JUMP_IF_TRUE': 242, -+ 'INSTRUMENTED_POP_JUMP_IF_FALSE': 243, -+ 'INSTRUMENTED_POP_JUMP_IF_NONE': 244, -+ 'INSTRUMENTED_POP_JUMP_IF_NOT_NONE': 245, -+ 'INSTRUMENTED_RESUME': 246, -+ 'INSTRUMENTED_RETURN_VALUE': 247, -+ 'INSTRUMENTED_YIELD_VALUE': 248, -+ 'INSTRUMENTED_LOAD_SUPER_ATTR': 249, -+ 'INSTRUMENTED_CALL': 250, -+ 'INSTRUMENTED_CALL_KW': 251, -+ 'INSTRUMENTED_CALL_FUNCTION_EX': 252, - 'INSTRUMENTED_JUMP_BACKWARD': 253, - 'JUMP': 256, - 'JUMP_IF_FALSE': 257, -@@ -348,5 +359,5 @@ - 'STORE_FAST_MAYBE_NULL': 265, - } - --HAVE_ARGUMENT = 41 --MIN_INSTRUMENTED_OPCODE = 237 -+HAVE_ARGUMENT = 43 -+MIN_INSTRUMENTED_OPCODE = 235 -diff --git a/Lib/_pydatetime.py b/Lib/_pydatetime.py -index ed01670cfec..be90c9b1315 100644 ---- a/Lib/_pydatetime.py -+++ b/Lib/_pydatetime.py -@@ -2392,7 +2392,6 @@ - - def _isoweek1monday(year): - # Helper to calculate the day number of the Monday starting week 1 -- # XXX This could be done more efficiently - THURSDAY = 3 - firstday = _ymd2ord(year, 1, 1) - firstweekday = (firstday + 6) % 7 # See weekday() above -diff --git a/Lib/_pyio.py b/Lib/_pyio.py -index 14961c39d35..f7370dff19e 100644 ---- a/Lib/_pyio.py -+++ b/Lib/_pyio.py -@@ -937,10 +937,8 @@ - return 0 - pos = self._pos - if pos > len(self._buffer): -- # Inserts null bytes between the current end of the file -- # and the new write position. -- padding = b'\x00' * (pos - len(self._buffer)) -- self._buffer += padding -+ # Pad buffer to pos with null bytes. -+ self._buffer.resize(pos) - self._buffer[pos:pos + n] = b - self._pos += n - return n -@@ -1456,6 +1454,17 @@ - return BufferedWriter.write(self, b) - - -+def _new_buffersize(bytes_read): -+ # Parallels _io/fileio.c new_buffersize -+ if bytes_read > 65536: -+ addend = bytes_read >> 3 -+ else: -+ addend = 256 + bytes_read -+ if addend < DEFAULT_BUFFER_SIZE: -+ addend = DEFAULT_BUFFER_SIZE -+ return bytes_read + addend ++ ac_config_files="$ac_config_files watchOS/Resources/Info.plist" + + ;; + *) + as_fn_error $? "Unknown platform for framework build" "$LINENO" 5 +@@ -4469,6 +4551,8 @@ + e) + case $ac_sys_system in + iOS) as_fn_error $? "iOS builds must use --enable-framework" "$LINENO" 5 ;; ++ tvOS) as_fn_error $? "tvOS builds must use --enable-framework" "$LINENO" 5 ;; ++ watchOS) as_fn_error $? "watchOS builds must use --enable-framework" "$LINENO" 5 ;; + *) + PYTHONFRAMEWORK= + PYTHONFRAMEWORKDIR=no-framework +@@ -4523,8 +4607,8 @@ + case "$withval" in + yes) + case $ac_sys_system in +- Darwin|iOS) +- # iOS is able to share the macOS patch ++ Darwin|iOS|tvOS|watchOS) ++ # iOS/tvOS/watchOS is able to share the macOS patch + APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" + ;; + *) as_fn_error $? "no default app store compliance patch available for $ac_sys_system" "$LINENO" 5 ;; +@@ -4542,8 +4626,8 @@ + else case e in #( + e) + case $ac_sys_system in +- iOS) +- # Always apply the compliance patch on iOS; we can use the macOS patch ++ iOS|tvOS|watchOS) ++ # Always apply the compliance patch on iOS/tvOS/watchOS; we can use the macOS patch + APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: applying default app store compliance patch" >&5 + printf "%s\n" "applying default app store compliance patch" >&6; } +@@ -4598,6 +4682,50 @@ + ;; + esac + ;; ++ *-apple-tvos*) ++ _host_os=`echo $host | cut -d '-' -f3` ++ _host_device=`echo $host | cut -d '-' -f4` ++ _host_device=${_host_device:=os} + - class FileIO(RawIOBase): - _fd = -1 - _created = False -@@ -1674,31 +1683,30 @@ - except OSError: - pass - -- result = bytearray() -- while True: -- if len(result) >= bufsize: -- bufsize = len(result) -- bufsize += max(bufsize, DEFAULT_BUFFER_SIZE) -- n = bufsize - len(result) -- try: -- chunk = os.read(self._fd, n) -- except BlockingIOError: -- if result: -- break -+ result = bytearray(bufsize) -+ bytes_read = 0 -+ try: -+ while n := os.readinto(self._fd, memoryview(result)[bytes_read:]): -+ bytes_read += n -+ if bytes_read >= len(result): -+ result.resize(_new_buffersize(bytes_read)) -+ except BlockingIOError: -+ if not bytes_read: - return None -- if not chunk: # reached the end of the file -- break -- result += chunk - -+ assert len(result) - bytes_read >= 1, \ -+ "os.readinto buffer size 0 will result in erroneous EOF / returns 0" -+ result.resize(bytes_read) - return bytes(result) - -- def readinto(self, b): -+ def readinto(self, buffer): - """Same as RawIOBase.readinto().""" -- m = memoryview(b).cast('B') -- data = self.read(len(m)) -- n = len(data) -- m[:n] = data -- return n -+ self._checkClosed() -+ self._checkReadable() -+ try: -+ return os.readinto(self._fd, buffer) -+ except BlockingIOError: -+ return None - - def write(self, b): - """Write bytes b to file, return number written. -diff --git a/Lib/_pyrepl/commands.py b/Lib/_pyrepl/commands.py -index c3fce91013b..503ca1da329 100644 ---- a/Lib/_pyrepl/commands.py -+++ b/Lib/_pyrepl/commands.py -@@ -282,7 +282,7 @@ - x, y = r.pos2xy() - new_y = y + 1 - -- if new_y > r.max_row(): -+ if r.eol() == len(b): - if r.historyi < len(r.history): - r.select_item(r.historyi + 1) - r.pos = r.eol(0) -@@ -309,7 +309,7 @@ - class left(MotionCommand): - def do(self) -> None: - r = self.reader -- for i in range(r.get_arg()): -+ for _ in range(r.get_arg()): - p = r.pos - 1 - if p >= 0: - r.pos = p -@@ -321,7 +321,7 @@ - def do(self) -> None: - r = self.reader - b = r.buffer -- for i in range(r.get_arg()): -+ for _ in range(r.get_arg()): - p = r.pos + 1 - if p <= len(b): - r.pos = p -@@ -459,9 +459,15 @@ - from site import gethistoryfile # type: ignore[attr-defined] - - history = os.linesep.join(self.reader.history[:]) -- with self.reader.suspend(): -- pager = get_pager() -- pager(history, gethistoryfile()) -+ self.reader.console.restore() -+ pager = get_pager() -+ pager(history, gethistoryfile()) -+ self.reader.console.prepare() -+ -+ # We need to copy over the state so that it's consistent between -+ # console and reader, and console does not overwrite/append stuff -+ self.reader.console.screen = self.reader.screen.copy() -+ self.reader.console.posxy = self.reader.cxy - - - class paste_mode(Command): -diff --git a/Lib/_pyrepl/completing_reader.py b/Lib/_pyrepl/completing_reader.py -index e856bb9807c..1cd4b6367ca 100644 ---- a/Lib/_pyrepl/completing_reader.py -+++ b/Lib/_pyrepl/completing_reader.py -@@ -260,10 +260,15 @@ - def calc_screen(self) -> list[str]: - screen = super().calc_screen() - if self.cmpltn_menu_visible: -- ly = self.lxy[1] -+ # We display the completions menu below the current prompt -+ ly = self.lxy[1] + 1 - screen[ly:ly] = self.cmpltn_menu -- self.screeninfo[ly:ly] = [(0, [])]*len(self.cmpltn_menu) -- self.cxy = self.cxy[0], self.cxy[1] + len(self.cmpltn_menu) -+ # If we're not in the middle of multiline edit, don't append to screeninfo -+ # since that screws up the position calculation in pos2xy function. -+ # This is a hack to prevent the cursor jumping -+ # into the completions menu when pressing left or down arrow. -+ if self.pos != len(self.buffer): -+ self.screeninfo[ly:ly] = [(0, [])]*len(self.cmpltn_menu) - return screen - - def finish(self) -> None: -diff --git a/Lib/_pyrepl/console.py b/Lib/_pyrepl/console.py -index 03266c4dfc2..0d78890b4f4 100644 ---- a/Lib/_pyrepl/console.py -+++ b/Lib/_pyrepl/console.py -@@ -45,6 +45,7 @@ - - @dataclass - class Console(ABC): -+ posxy: tuple[int, int] - screen: list[str] = field(default_factory=list) - height: int = 25 - width: int = 80 -diff --git a/Lib/_pyrepl/fancy_termios.py b/Lib/_pyrepl/fancy_termios.py -index 5b85cb0f525..0468b9a2670 100644 ---- a/Lib/_pyrepl/fancy_termios.py -+++ b/Lib/_pyrepl/fancy_termios.py -@@ -40,7 +40,9 @@ - self.lflag, - self.ispeed, - self.ospeed, -- self.cc, -+ # Always return a copy of the control characters list to ensure -+ # there are not any additional references to self.cc -+ self.cc[:], - ] - - def copy(self): -diff --git a/Lib/_pyrepl/historical_reader.py b/Lib/_pyrepl/historical_reader.py -index 5d416f336ad..c4b95fa2e81 100644 ---- a/Lib/_pyrepl/historical_reader.py -+++ b/Lib/_pyrepl/historical_reader.py -@@ -290,13 +290,17 @@ - - @contextmanager - def suspend(self) -> SimpleContextManager: -- with super().suspend(): -- try: -- old_history = self.history[:] -- del self.history[:] -- yield -- finally: -- self.history[:] = old_history -+ with super().suspend(), self.suspend_history(): -+ yield -+ -+ @contextmanager -+ def suspend_history(self) -> SimpleContextManager: -+ try: -+ old_history = self.history[:] -+ del self.history[:] -+ yield -+ finally: -+ self.history[:] = old_history - - def prepare(self) -> None: - super().prepare() -diff --git a/Lib/_pyrepl/reader.py b/Lib/_pyrepl/reader.py -index 4b0700d069c..1252847e02b 100644 ---- a/Lib/_pyrepl/reader.py -+++ b/Lib/_pyrepl/reader.py -@@ -587,10 +587,11 @@ - def pos2xy(self) -> tuple[int, int]: - """Return the x, y coordinates of position 'pos'.""" - # this *is* incomprehensible, yes. -- y = 0 -+ p, y = 0, 0 -+ l2: list[int] = [] - pos = self.pos - assert 0 <= pos <= len(self.buffer) -- if pos == len(self.buffer): -+ if pos == len(self.buffer) and len(self.screeninfo) > 0: - y = len(self.screeninfo) - 1 - p, l2 = self.screeninfo[y] - return p + sum(l2) + l2.count(0), y -diff --git a/Lib/_pyrepl/simple_interact.py b/Lib/_pyrepl/simple_interact.py -index 342a4b58bfd..a065174ad42 100644 ---- a/Lib/_pyrepl/simple_interact.py -+++ b/Lib/_pyrepl/simple_interact.py -@@ -77,7 +77,7 @@ - "exit": _sitebuiltins.Quitter('exit', ''), - "quit": _sitebuiltins.Quitter('quit' ,''), - "copyright": _sitebuiltins._Printer('copyright', sys.copyright), -- "help": "help", -+ "help": _sitebuiltins._Helper(), - "clear": _clear_screen, - "\x1a": _sitebuiltins.Quitter('\x1a', ''), - } -@@ -124,21 +124,13 @@ - reader.history.pop() # skip internal commands in history - command = REPL_COMMANDS[statement] - if callable(command): -- command() -+ # Make sure that history does not change because of commands -+ with reader.suspend_history(): -+ command() - return True -- -- if isinstance(command, str): -- # Internal readline commands require a prepared reader like -- # inside multiline_input. -- reader.prepare() -- reader.refresh() -- reader.do_cmd((command, [statement])) -- reader.restore() -- return True -- - return False - -- while 1: -+ while True: - try: - try: - sys.stdout.flush() -diff --git a/Lib/_pyrepl/unix_console.py b/Lib/_pyrepl/unix_console.py -index 2576b938a34..96379bc20f3 100644 ---- a/Lib/_pyrepl/unix_console.py -+++ b/Lib/_pyrepl/unix_console.py -@@ -240,7 +240,7 @@ - self.__hide_cursor() - self.__move(0, len(self.screen) - 1) - self.__write("\n") -- self.__posxy = 0, len(self.screen) -+ self.posxy = 0, len(self.screen) - self.screen.append("") - else: - while len(self.screen) < len(screen): -@@ -250,7 +250,7 @@ - self.__gone_tall = 1 - self.__move = self.__move_tall - -- px, py = self.__posxy -+ px, py = self.posxy - old_offset = offset = self.__offset - height = self.height - -@@ -271,7 +271,7 @@ - if old_offset > offset and self._ri: - self.__hide_cursor() - self.__write_code(self._cup, 0, 0) -- self.__posxy = 0, old_offset -+ self.posxy = 0, old_offset - for i in range(old_offset - offset): - self.__write_code(self._ri) - oldscr.pop(-1) -@@ -279,7 +279,7 @@ - elif old_offset < offset and self._ind: - self.__hide_cursor() - self.__write_code(self._cup, self.height - 1, 0) -- self.__posxy = 0, old_offset + self.height - 1 -+ self.posxy = 0, old_offset + self.height - 1 - for i in range(offset - old_offset): - self.__write_code(self._ind) - oldscr.pop(0) -@@ -299,7 +299,7 @@ - while y < len(oldscr): - self.__hide_cursor() - self.__move(0, y) -- self.__posxy = 0, y -+ self.posxy = 0, y - self.__write_code(self._el) - y += 1 - -@@ -321,7 +321,7 @@ - self.event_queue.insert(Event("scroll", None)) - else: - self.__move(x, y) -- self.__posxy = x, y -+ self.posxy = x, y - self.flushoutput() - - def prepare(self): -@@ -350,7 +350,7 @@ - - self.__buffer = [] - -- self.__posxy = 0, 0 -+ self.posxy = 0, 0 - self.__gone_tall = 0 - self.__move = self.__move_short - self.__offset = 0 -@@ -449,10 +449,12 @@ - """ - try: - return int(os.environ["LINES"]), int(os.environ["COLUMNS"]) -- except KeyError: -- height, width = struct.unpack( -- "hhhh", ioctl(self.input_fd, TIOCGWINSZ, b"\000" * 8) -- )[0:2] -+ except (KeyError, TypeError, ValueError): -+ try: -+ size = ioctl(self.input_fd, TIOCGWINSZ, b"\000" * 8) -+ except OSError: -+ return 25, 80 -+ height, width = struct.unpack("hhhh", size)[0:2] - if not height: - return 25, 80 - return height, width -@@ -468,7 +470,7 @@ - """ - try: - return int(os.environ["LINES"]), int(os.environ["COLUMNS"]) -- except KeyError: -+ except (KeyError, TypeError, ValueError): - return 25, 80 - - def forgetinput(self): -@@ -559,7 +561,7 @@ - self.__write_code(self._clear) - self.__gone_tall = 1 - self.__move = self.__move_tall -- self.__posxy = 0, 0 -+ self.posxy = 0, 0 - self.screen = [] - - @property -@@ -644,8 +646,8 @@ - # if we need to insert a single character right after the first detected change - if oldline[x_pos:] == newline[x_pos + 1 :] and self.ich1: - if ( -- y == self.__posxy[1] -- and x_coord > self.__posxy[0] -+ y == self.posxy[1] -+ and x_coord > self.posxy[0] - and oldline[px_pos:x_pos] == newline[px_pos + 1 : x_pos + 1] - ): - x_pos = px_pos -@@ -654,7 +656,7 @@ - self.__move(x_coord, y) - self.__write_code(self.ich1) - self.__write(newline[x_pos]) -- self.__posxy = x_coord + character_width, y -+ self.posxy = x_coord + character_width, y - - # if it's a single character change in the middle of the line - elif ( -@@ -665,7 +667,7 @@ - character_width = wlen(newline[x_pos]) - self.__move(x_coord, y) - self.__write(newline[x_pos]) -- self.__posxy = x_coord + character_width, y -+ self.posxy = x_coord + character_width, y - - # if this is the last character to fit in the line and we edit in the middle of the line - elif ( -@@ -677,14 +679,14 @@ - ): - self.__hide_cursor() - self.__move(self.width - 2, y) -- self.__posxy = self.width - 2, y -+ self.posxy = self.width - 2, y - self.__write_code(self.dch1) - - character_width = wlen(newline[x_pos]) - self.__move(x_coord, y) - self.__write_code(self.ich1) - self.__write(newline[x_pos]) -- self.__posxy = character_width + 1, y -+ self.posxy = character_width + 1, y - - else: - self.__hide_cursor() -@@ -692,7 +694,7 @@ - if wlen(oldline) > wlen(newline): - self.__write_code(self._el) - self.__write(newline[x_pos:]) -- self.__posxy = wlen(newline), y -+ self.posxy = wlen(newline), y - - if "\x1b" in newline: - # ANSI escape characters are present, so we can't assume -@@ -711,32 +713,36 @@ - self.__write_code(fmt, *args) - - def __move_y_cuu1_cud1(self, y): -- dy = y - self.__posxy[1] -+ assert self._cud1 is not None -+ assert self._cuu1 is not None -+ dy = y - self.posxy[1] - if dy > 0: - self.__write_code(dy * self._cud1) - elif dy < 0: - self.__write_code((-dy) * self._cuu1) - - def __move_y_cuu_cud(self, y): -- dy = y - self.__posxy[1] -+ dy = y - self.posxy[1] - if dy > 0: - self.__write_code(self._cud, dy) - elif dy < 0: - self.__write_code(self._cuu, -dy) - - def __move_x_hpa(self, x: int) -> None: -- if x != self.__posxy[0]: -+ if x != self.posxy[0]: - self.__write_code(self._hpa, x) - - def __move_x_cub1_cuf1(self, x: int) -> None: -- dx = x - self.__posxy[0] -+ assert self._cuf1 is not None -+ assert self._cub1 is not None -+ dx = x - self.posxy[0] - if dx > 0: - self.__write_code(self._cuf1 * dx) - elif dx < 0: - self.__write_code(self._cub1 * (-dx)) - - def __move_x_cub_cuf(self, x: int) -> None: -- dx = x - self.__posxy[0] -+ dx = x - self.posxy[0] - if dx > 0: - self.__write_code(self._cuf, dx) - elif dx < 0: -@@ -766,12 +772,12 @@ - - def repaint(self): - if not self.__gone_tall: -- self.__posxy = 0, self.__posxy[1] -+ self.posxy = 0, self.posxy[1] - self.__write("\r") - ns = len(self.screen) * ["\000" * self.width] - self.screen = ns - else: -- self.__posxy = 0, self.__offset -+ self.posxy = 0, self.__offset - self.__move(0, self.__offset) - ns = self.height * ["\000" * self.width] - self.screen = ns -@@ -786,7 +792,7 @@ - # only if the bps is actually needed (which I'm - # betting is pretty unlkely) - bps = ratedict.get(self.__svtermstate.ospeed) -- while 1: -+ while True: - m = prog.search(fmt) - if not m: - os.write(self.output_fd, fmt) -diff --git a/Lib/_pyrepl/utils.py b/Lib/_pyrepl/utils.py -index 0f36083b6ff..4651717bd7e 100644 ---- a/Lib/_pyrepl/utils.py -+++ b/Lib/_pyrepl/utils.py -@@ -16,7 +16,7 @@ - - - def wlen(s: str) -> int: -- if len(s) == 1: -+ if len(s) == 1 and s != '\x1a': - return str_width(s) - length = sum(str_width(i) for i in s) - # remove lengths of any escape sequences -diff --git a/Lib/_pyrepl/windows_console.py b/Lib/_pyrepl/windows_console.py -index d457d2b5a33..e1ecd9845ae 100644 ---- a/Lib/_pyrepl/windows_console.py -+++ b/Lib/_pyrepl/windows_console.py -@@ -102,6 +102,10 @@ - MOVE_DOWN = "\x1b[{}B" - CLEAR = "\x1b[H\x1b[J" - -+# State of control keys: https://learn.microsoft.com/en-us/windows/console/key-event-record-str -+ALT_ACTIVE = 0x01 | 0x02 -+CTRL_ACTIVE = 0x04 | 0x08 -+ - - class _error(Exception): - pass -@@ -148,10 +152,10 @@ - self._hide_cursor() - self._move_relative(0, len(self.screen) - 1) - self.__write("\n") -- self.__posxy = 0, len(self.screen) -+ self.posxy = 0, len(self.screen) - self.screen.append("") - -- px, py = self.__posxy -+ px, py = self.posxy - old_offset = offset = self.__offset - height = self.height - -@@ -167,7 +171,7 @@ - # portion of the window. We need to scroll the visible portion and the - # entire history - self._scroll(scroll_lines, self._getscrollbacksize()) -- self.__posxy = self.__posxy[0], self.__posxy[1] + scroll_lines -+ self.posxy = self.posxy[0], self.posxy[1] + scroll_lines - self.__offset += scroll_lines - - for i in range(scroll_lines): -@@ -193,7 +197,7 @@ - y = len(newscr) - while y < len(oldscr): - self._move_relative(0, y) -- self.__posxy = 0, y -+ self.posxy = 0, y - self._erase_to_end() - y += 1 - -@@ -250,11 +254,11 @@ - if wlen(newline) == self.width: - # If we wrapped we want to start at the next line - self._move_relative(0, y + 1) -- self.__posxy = 0, y + 1 -+ self.posxy = 0, y + 1 - else: -- self.__posxy = wlen(newline), y -+ self.posxy = wlen(newline), y - -- if "\x1b" in newline or y != self.__posxy[1] or '\x1a' in newline: -+ if "\x1b" in newline or y != self.posxy[1] or '\x1a' in newline: - # ANSI escape characters are present, so we can't assume - # anything about the position of the cursor. Moving the cursor - # to the left margin should work to get to a known position. -@@ -316,7 +320,7 @@ - self.screen = [] - self.height, self.width = self.getheightwidth() - -- self.__posxy = 0, 0 -+ self.posxy = 0, 0 - self.__gone_tall = 0 - self.__offset = 0 - -@@ -324,9 +328,9 @@ - pass - - def _move_relative(self, x: int, y: int) -> None: -- """Moves relative to the current __posxy""" -- dx = x - self.__posxy[0] -- dy = y - self.__posxy[1] -+ """Moves relative to the current posxy""" -+ dx = x - self.posxy[0] -+ dy = y - self.posxy[1] - if dx < 0: - self.__write(MOVE_LEFT.format(-dx)) - elif dx > 0: -@@ -345,7 +349,7 @@ - self.event_queue.insert(0, Event("scroll", "")) - else: - self._move_relative(x, y) -- self.__posxy = x, y -+ self.posxy = x, y - - def set_cursor_vis(self, visible: bool) -> None: - if visible: -@@ -407,31 +411,37 @@ - continue - return None - -- key = rec.Event.KeyEvent.uChar.UnicodeChar -+ key_event = rec.Event.KeyEvent -+ raw_key = key = key_event.uChar.UnicodeChar - -- if rec.Event.KeyEvent.uChar.UnicodeChar == "\r": -- # Make enter make unix-like -+ if key == "\r": -+ # Make enter unix-like - return Event(evt="key", data="\n", raw=b"\n") -- elif rec.Event.KeyEvent.wVirtualKeyCode == 8: -+ elif key_event.wVirtualKeyCode == 8: - # Turn backspace directly into the command -- return Event( -- evt="key", -- data="backspace", -- raw=rec.Event.KeyEvent.uChar.UnicodeChar, -- ) -- elif rec.Event.KeyEvent.uChar.UnicodeChar == "\x00": -+ key = "backspace" -+ elif key == "\x00": - # Handle special keys like arrow keys and translate them into the appropriate command -- code = VK_MAP.get(rec.Event.KeyEvent.wVirtualKeyCode) -- if code: -- return Event( -- evt="key", data=code, raw=rec.Event.KeyEvent.uChar.UnicodeChar -- ) -+ key = VK_MAP.get(key_event.wVirtualKeyCode) -+ if key: -+ if key_event.dwControlKeyState & CTRL_ACTIVE: -+ key = f"ctrl {key}" -+ elif key_event.dwControlKeyState & ALT_ACTIVE: -+ # queue the key, return the meta command -+ self.event_queue.insert(0, Event(evt="key", data=key, raw=key)) -+ return Event(evt="key", data="\033") # keymap.py uses this for meta -+ return Event(evt="key", data=key, raw=key) - if block: - continue - - return None - -- return Event(evt="key", data=key, raw=rec.Event.KeyEvent.uChar.UnicodeChar) -+ if key_event.dwControlKeyState & ALT_ACTIVE: -+ # queue the key, return the meta command -+ self.event_queue.insert(0, Event(evt="key", data=key, raw=raw_key)) -+ return Event(evt="key", data="\033") # keymap.py uses this for meta -+ -+ return Event(evt="key", data=key, raw=raw_key) - - def push_char(self, char: int | bytes) -> None: - """ -@@ -445,7 +455,7 @@ - def clear(self) -> None: - """Wipe the screen""" - self.__write(CLEAR) -- self.__posxy = 0, 0 -+ self.posxy = 0, 0 - self.screen = [""] - - def finish(self) -> None: -diff --git a/Lib/ast.py b/Lib/ast.py -index 154d2c8c1f9..0937c27bdf8 100644 ---- a/Lib/ast.py -+++ b/Lib/ast.py -@@ -1196,9 +1196,14 @@ - fallback_to_repr = True - break - quote_types = new_quote_types -- elif "\n" in value: -- quote_types = [q for q in quote_types if q in _MULTI_QUOTES] -- assert quote_types -+ else: -+ if "\n" in value: -+ quote_types = [q for q in quote_types if q in _MULTI_QUOTES] -+ assert quote_types -+ -+ new_quote_types = [q for q in quote_types if q not in value] -+ if new_quote_types: -+ quote_types = new_quote_types - new_fstring_parts.append(value) - - if fallback_to_repr: -diff --git a/Lib/asyncio/__init__.py b/Lib/asyncio/__init__.py -index 03165a425eb..4be7112fa01 100644 ---- a/Lib/asyncio/__init__.py -+++ b/Lib/asyncio/__init__.py -@@ -10,6 +10,7 @@ - from .events import * - from .exceptions import * - from .futures import * -+from .graph import * - from .locks import * - from .protocols import * - from .runners import * -@@ -27,6 +28,7 @@ - events.__all__ + - exceptions.__all__ + - futures.__all__ + -+ graph.__all__ + - locks.__all__ + - protocols.__all__ + - runners.__all__ + -@@ -45,3 +47,19 @@ - else: - from .unix_events import * # pragma: no cover - __all__ += unix_events.__all__ -+ -+def __getattr__(name: str): -+ import warnings -+ -+ deprecated = { -+ "AbstractEventLoopPolicy", -+ "DefaultEventLoopPolicy", -+ "WindowsSelectorEventLoopPolicy", -+ "WindowsProactorEventLoopPolicy", -+ } -+ if name in deprecated: -+ warnings._deprecated(f"asyncio.{name}", remove=(3, 16)) -+ # deprecated things have underscores in front of them -+ return globals()["_" + name] -+ -+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}") -diff --git a/Lib/asyncio/__main__.py b/Lib/asyncio/__main__.py -index 95c636f9e02..662ba649aa0 100644 ---- a/Lib/asyncio/__main__.py -+++ b/Lib/asyncio/__main__.py -@@ -149,7 +149,7 @@ - - return_code = 0 - loop = asyncio.new_event_loop() -- asyncio.set_event_loop(loop) -+ asyncio._set_event_loop(loop) - - repl_locals = {'asyncio': asyncio} - for key in {'__name__', '__package__', -diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py -index 5dbe4b28d23..ed852421e44 100644 ---- a/Lib/asyncio/base_events.py -+++ b/Lib/asyncio/base_events.py -@@ -458,26 +458,24 @@ - """Create a Future object attached to the loop.""" - return futures.Future(loop=self) - -- def create_task(self, coro, *, name=None, context=None): -+ def create_task(self, coro, **kwargs): - """Schedule a coroutine object. - - Return a task object. - """ - self._check_closed() -- if self._task_factory is None: -- task = tasks.Task(coro, loop=self, name=name, context=context) -- if task._source_traceback: -- del task._source_traceback[-1] -- else: -- if context is None: -- # Use legacy API if context is not needed -- task = self._task_factory(self, coro) -- else: -- task = self._task_factory(self, coro, context=context) -- -- task.set_name(name) -+ if self._task_factory is not None: -+ return self._task_factory(self, coro, **kwargs) - -- return task -+ task = tasks.Task(coro, loop=self, **kwargs) -+ if task._source_traceback: -+ del task._source_traceback[-1] -+ try: -+ return task -+ finally: -+ # gh-128552: prevent a refcycle of -+ # task.exception().__traceback__->BaseEventLoop.create_task->task -+ del task - - def set_task_factory(self, factory): - """Set a task factory that will be used by loop.create_task(). -@@ -485,9 +483,10 @@ - If factory is None the default task factory will be set. - - If factory is a callable, it should have a signature matching -- '(loop, coro)', where 'loop' will be a reference to the active -- event loop, 'coro' will be a coroutine object. The callable -- must return a Future. -+ '(loop, coro, **kwargs)', where 'loop' will be a reference to the active -+ event loop, 'coro' will be a coroutine object, and **kwargs will be -+ arbitrary keyword arguments that should be passed on to Task. -+ The callable must return a Task. - """ - if factory is not None and not callable(factory): - raise TypeError('task factory must be a callable or None') -@@ -873,7 +872,10 @@ - self._check_closed() - if self._debug: - self._check_callback(callback, 'call_soon_threadsafe') -- handle = self._call_soon(callback, args, context) -+ handle = events._ThreadSafeHandle(callback, args, self, context) -+ self._ready.append(handle) -+ if handle._source_traceback: -+ del handle._source_traceback[-1] - if handle._source_traceback: - del handle._source_traceback[-1] - self._write_to_self() -@@ -1585,7 +1587,9 @@ - if reuse_address: - sock.setsockopt( - socket.SOL_SOCKET, socket.SO_REUSEADDR, True) -- if reuse_port: -+ # Since Linux 6.12.9, SO_REUSEPORT is not allowed -+ # on other address families than AF_INET/AF_INET6. -+ if reuse_port and af in (socket.AF_INET, socket.AF_INET6): - _set_reuseport(sock) - if keep_alive: - sock.setsockopt( -diff --git a/Lib/asyncio/events.py b/Lib/asyncio/events.py -index ca0a4f2fee5..2e45b4fe6fa 100644 ---- a/Lib/asyncio/events.py -+++ b/Lib/asyncio/events.py -@@ -5,13 +5,22 @@ - # SPDX-FileCopyrightText: Copyright (c) 2015-2021 MagicStack Inc. http://magic.io - - __all__ = ( -- 'AbstractEventLoopPolicy', -- 'AbstractEventLoop', 'AbstractServer', -- 'Handle', 'TimerHandle', -- 'get_event_loop_policy', 'set_event_loop_policy', -- 'get_event_loop', 'set_event_loop', 'new_event_loop', -- '_set_running_loop', 'get_running_loop', -- '_get_running_loop', -+ "_AbstractEventLoopPolicy", -+ "AbstractEventLoop", -+ "AbstractServer", -+ "Handle", -+ "TimerHandle", -+ "_get_event_loop_policy", -+ "get_event_loop_policy", -+ "_set_event_loop_policy", -+ "set_event_loop_policy", -+ "get_event_loop", -+ "_set_event_loop", -+ "set_event_loop", -+ "new_event_loop", -+ "_set_running_loop", -+ "get_running_loop", -+ "_get_running_loop", - ) - - import contextvars -@@ -21,6 +30,7 @@ - import subprocess - import sys - import threading -+import warnings - - from . import format_helpers - -@@ -103,6 +113,34 @@ - self._loop.call_exception_handler(context) - self = None # Needed to break cycles when an exception occurs. - -+# _ThreadSafeHandle is used for callbacks scheduled with call_soon_threadsafe -+# and is thread safe unlike Handle which is not thread safe. -+class _ThreadSafeHandle(Handle): -+ -+ __slots__ = ('_lock',) -+ -+ def __init__(self, callback, args, loop, context=None): -+ super().__init__(callback, args, loop, context) -+ self._lock = threading.RLock() -+ -+ def cancel(self): -+ with self._lock: -+ return super().cancel() -+ -+ def cancelled(self): -+ with self._lock: -+ return super().cancelled() -+ -+ def _run(self): -+ # The event loop checks for cancellation without holding the lock -+ # It is possible that the handle is cancelled after the check -+ # but before the callback is called so check it again after acquiring -+ # the lock and return without calling the callback if it is cancelled. -+ with self._lock: -+ if self._cancelled: -+ return -+ return super()._run() -+ - - class TimerHandle(Handle): - """Object returned by timed callback registration methods.""" -@@ -291,7 +329,7 @@ - - # Method scheduling a coroutine object: create a task. - -- def create_task(self, coro, *, name=None, context=None): -+ def create_task(self, coro, **kwargs): - raise NotImplementedError - - # Methods for interacting with threads. -@@ -628,7 +666,7 @@ - raise NotImplementedError - - --class AbstractEventLoopPolicy: -+class _AbstractEventLoopPolicy: - """Abstract policy for accessing the event loop.""" - - def get_event_loop(self): -@@ -651,7 +689,7 @@ - the current context, set_event_loop must be called explicitly.""" - raise NotImplementedError - --class BaseDefaultEventLoopPolicy(AbstractEventLoopPolicy): -+class _BaseDefaultEventLoopPolicy(_AbstractEventLoopPolicy): - """Default policy implementation for accessing the event loop. - - In this policy, each thread has its own event loop. However, we -@@ -754,26 +792,32 @@ - global _event_loop_policy - with _lock: - if _event_loop_policy is None: # pragma: no branch -- from . import DefaultEventLoopPolicy -- _event_loop_policy = DefaultEventLoopPolicy() -+ from . import _DefaultEventLoopPolicy -+ _event_loop_policy = _DefaultEventLoopPolicy() - - --def get_event_loop_policy(): -+def _get_event_loop_policy(): - """Get the current event loop policy.""" - if _event_loop_policy is None: - _init_event_loop_policy() - return _event_loop_policy - -+def get_event_loop_policy(): -+ warnings._deprecated('asyncio.get_event_loop_policy', remove=(3, 16)) -+ return _get_event_loop_policy() - --def set_event_loop_policy(policy): -+def _set_event_loop_policy(policy): - """Set the current event loop policy. - - If policy is None, the default policy is restored.""" - global _event_loop_policy -- if policy is not None and not isinstance(policy, AbstractEventLoopPolicy): -+ if policy is not None and not isinstance(policy, _AbstractEventLoopPolicy): - raise TypeError(f"policy must be an instance of AbstractEventLoopPolicy or None, not '{type(policy).__name__}'") - _event_loop_policy = policy - -+def set_event_loop_policy(policy): -+ warnings._deprecated('asyncio.set_event_loop_policy', remove=(3,16)) -+ _set_event_loop_policy(policy) - - def get_event_loop(): - """Return an asyncio event loop. -@@ -788,17 +832,21 @@ - current_loop = _get_running_loop() - if current_loop is not None: - return current_loop -- return get_event_loop_policy().get_event_loop() -+ return _get_event_loop_policy().get_event_loop() -+ - -+def _set_event_loop(loop): -+ _get_event_loop_policy().set_event_loop(loop) - - def set_event_loop(loop): - """Equivalent to calling get_event_loop_policy().set_event_loop(loop).""" -- get_event_loop_policy().set_event_loop(loop) -+ warnings._deprecated('asyncio.set_event_loop', remove=(3,16)) -+ _set_event_loop(loop) - - - def new_event_loop(): - """Equivalent to calling get_event_loop_policy().new_event_loop().""" -- return get_event_loop_policy().new_event_loop() -+ return _get_event_loop_policy().new_event_loop() - - - # Alias pure-Python implementations for testing purposes. -@@ -828,7 +876,7 @@ - def on_fork(): - # Reset the loop and wakeupfd in the forked child process. - if _event_loop_policy is not None: -- _event_loop_policy._local = BaseDefaultEventLoopPolicy._Local() -+ _event_loop_policy._local = _BaseDefaultEventLoopPolicy._Local() - _set_running_loop(None) - signal.set_wakeup_fd(-1) - -diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py -index c95fce035cd..d1df6707302 100644 ---- a/Lib/asyncio/futures.py -+++ b/Lib/asyncio/futures.py -@@ -2,6 +2,7 @@ - - __all__ = ( - 'Future', 'wrap_future', 'isfuture', -+ 'future_add_to_awaited_by', 'future_discard_from_awaited_by', - ) - - import concurrent.futures -@@ -62,10 +63,13 @@ - # that it is not compatible by setting this to None. - # - It is set by __iter__() below so that Task.__step() can tell - # the difference between -- # `await Future()` or`yield from Future()` (correct) vs. -+ # `await Future()` or `yield from Future()` (correct) vs. - # `yield Future()` (incorrect). - _asyncio_future_blocking = False - -+ # Used by the capture_call_stack() API. -+ __asyncio_awaited_by = None -+ - __log_traceback = False - - def __init__(self, *, loop=None): -@@ -115,6 +119,12 @@ - raise ValueError('_log_traceback can only be set to False') - self.__log_traceback = False - -+ @property -+ def _asyncio_awaited_by(self): -+ if self.__asyncio_awaited_by is None: -+ return None -+ return frozenset(self.__asyncio_awaited_by) -+ - def get_loop(self): - """Return the event loop the Future is bound to.""" - loop = self._loop -@@ -415,6 +425,49 @@ - return new_future - - -+def future_add_to_awaited_by(fut, waiter, /): -+ """Record that `fut` is awaited on by `waiter`.""" -+ # For the sake of keeping the implementation minimal and assuming -+ # that most of asyncio users use the built-in Futures and Tasks -+ # (or their subclasses), we only support native Future objects -+ # and their subclasses. -+ # -+ # Longer version: tracking requires storing the caller-callee -+ # dependency somewhere. One obvious choice is to store that -+ # information right in the future itself in a dedicated attribute. -+ # This means that we'd have to require all duck-type compatible -+ # futures to implement a specific attribute used by asyncio for -+ # the book keeping. Another solution would be to store that in -+ # a global dictionary. The downside here is that that would create -+ # strong references and any scenario where the "add" call isn't -+ # followed by a "discard" call would lead to a memory leak. -+ # Using WeakDict would resolve that issue, but would complicate -+ # the C code (_asynciomodule.c). The bottom line here is that -+ # it's not clear that all this work would be worth the effort. -+ # -+ # Note that there's an accelerated version of this function -+ # shadowing this implementation later in this file. -+ if isinstance(fut, _PyFuture) and isinstance(waiter, _PyFuture): -+ if fut._Future__asyncio_awaited_by is None: -+ fut._Future__asyncio_awaited_by = set() -+ fut._Future__asyncio_awaited_by.add(waiter) -+ -+ -+def future_discard_from_awaited_by(fut, waiter, /): -+ """Record that `fut` is no longer awaited on by `waiter`.""" -+ # See the comment in "future_add_to_awaited_by()" body for -+ # details on implementation. -+ # -+ # Note that there's an accelerated version of this function -+ # shadowing this implementation later in this file. -+ if isinstance(fut, _PyFuture) and isinstance(waiter, _PyFuture): -+ if fut._Future__asyncio_awaited_by is not None: -+ fut._Future__asyncio_awaited_by.discard(waiter) -+ -+ -+_py_future_add_to_awaited_by = future_add_to_awaited_by -+_py_future_discard_from_awaited_by = future_discard_from_awaited_by -+ - try: - import _asyncio - except ImportError: -@@ -422,3 +475,7 @@ - else: - # _CFuture is needed for tests. - Future = _CFuture = _asyncio.Future -+ future_add_to_awaited_by = _asyncio.future_add_to_awaited_by -+ future_discard_from_awaited_by = _asyncio.future_discard_from_awaited_by -+ _c_future_add_to_awaited_by = future_add_to_awaited_by -+ _c_future_discard_from_awaited_by = future_discard_from_awaited_by ---- /dev/null -+++ b/Lib/asyncio/graph.py -@@ -0,0 +1,278 @@ -+"""Introspection utils for tasks call graphs.""" -+ -+import dataclasses -+import sys -+import types -+ -+from . import events -+from . import futures -+from . import tasks -+ -+__all__ = ( -+ 'capture_call_graph', -+ 'format_call_graph', -+ 'print_call_graph', -+ 'FrameCallGraphEntry', -+ 'FutureCallGraph', -+) -+ -+if False: # for type checkers -+ from typing import TextIO -+ -+# Sadly, we can't re-use the traceback module's datastructures as those -+# are tailored for error reporting, whereas we need to represent an -+# async call graph. -+# -+# Going with pretty verbose names as we'd like to export them to the -+# top level asyncio namespace, and want to avoid future name clashes. -+ -+ -+@dataclasses.dataclass(frozen=True, slots=True) -+class FrameCallGraphEntry: -+ frame: types.FrameType -+ -+ -+@dataclasses.dataclass(frozen=True, slots=True) -+class FutureCallGraph: -+ future: futures.Future -+ call_stack: tuple["FrameCallGraphEntry", ...] -+ awaited_by: tuple["FutureCallGraph", ...] -+ -+ -+def _build_graph_for_future( -+ future: futures.Future, -+ *, -+ limit: int | None = None, -+) -> FutureCallGraph: -+ if not isinstance(future, futures.Future): -+ raise TypeError( -+ f"{future!r} object does not appear to be compatible " -+ f"with asyncio.Future" -+ ) -+ -+ coro = None -+ if get_coro := getattr(future, 'get_coro', None): -+ coro = get_coro() if limit != 0 else None -+ -+ st: list[FrameCallGraphEntry] = [] -+ awaited_by: list[FutureCallGraph] = [] -+ -+ while coro is not None: -+ if hasattr(coro, 'cr_await'): -+ # A native coroutine or duck-type compatible iterator -+ st.append(FrameCallGraphEntry(coro.cr_frame)) -+ coro = coro.cr_await -+ elif hasattr(coro, 'ag_await'): -+ # A native async generator or duck-type compatible iterator -+ st.append(FrameCallGraphEntry(coro.cr_frame)) -+ coro = coro.ag_await -+ else: -+ break -+ -+ if future._asyncio_awaited_by: -+ for parent in future._asyncio_awaited_by: -+ awaited_by.append(_build_graph_for_future(parent, limit=limit)) -+ -+ if limit is not None: -+ if limit > 0: -+ st = st[:limit] -+ elif limit < 0: -+ st = st[limit:] -+ st.reverse() -+ return FutureCallGraph(future, tuple(st), tuple(awaited_by)) -+ -+ -+def capture_call_graph( -+ future: futures.Future | None = None, -+ /, -+ *, -+ depth: int = 1, -+ limit: int | None = None, -+) -> FutureCallGraph | None: -+ """Capture the async call graph for the current task or the provided Future. -+ -+ The graph is represented with three data structures: -+ -+ * FutureCallGraph(future, call_stack, awaited_by) -+ -+ Where 'future' is an instance of asyncio.Future or asyncio.Task. -+ -+ 'call_stack' is a tuple of FrameGraphEntry objects. -+ -+ 'awaited_by' is a tuple of FutureCallGraph objects. -+ -+ * FrameCallGraphEntry(frame) -+ -+ Where 'frame' is a frame object of a regular Python function -+ in the call stack. -+ -+ Receives an optional 'future' argument. If not passed, -+ the current task will be used. If there's no current task, the function -+ returns None. -+ -+ If "capture_call_graph()" is introspecting *the current task*, the -+ optional keyword-only 'depth' argument can be used to skip the specified -+ number of frames from top of the stack. -+ -+ If the optional keyword-only 'limit' argument is provided, each call stack -+ in the resulting graph is truncated to include at most ``abs(limit)`` -+ entries. If 'limit' is positive, the entries left are the closest to -+ the invocation point. If 'limit' is negative, the topmost entries are -+ left. If 'limit' is omitted or None, all entries are present. -+ If 'limit' is 0, the call stack is not captured at all, only -+ "awaited by" information is present. -+ """ -+ -+ loop = events._get_running_loop() -+ -+ if future is not None: -+ # Check if we're in a context of a running event loop; -+ # if yes - check if the passed future is the currently -+ # running task or not. -+ if loop is None or future is not tasks.current_task(loop=loop): -+ return _build_graph_for_future(future, limit=limit) -+ # else: future is the current task, move on. -+ else: -+ if loop is None: -+ raise RuntimeError( -+ 'capture_call_graph() is called outside of a running ' -+ 'event loop and no *future* to introspect was provided') -+ future = tasks.current_task(loop=loop) -+ -+ if future is None: -+ # This isn't a generic call stack introspection utility. If we -+ # can't determine the current task and none was provided, we -+ # just return. -+ return None -+ -+ if not isinstance(future, futures.Future): -+ raise TypeError( -+ f"{future!r} object does not appear to be compatible " -+ f"with asyncio.Future" -+ ) -+ -+ call_stack: list[FrameCallGraphEntry] = [] -+ -+ f = sys._getframe(depth) if limit != 0 else None -+ try: -+ while f is not None: -+ is_async = f.f_generator is not None -+ call_stack.append(FrameCallGraphEntry(f)) -+ -+ if is_async: -+ if f.f_back is not None and f.f_back.f_generator is None: -+ # We've reached the bottom of the coroutine stack, which -+ # must be the Task that runs it. -+ break -+ -+ f = f.f_back -+ finally: -+ del f -+ -+ awaited_by = [] -+ if future._asyncio_awaited_by: -+ for parent in future._asyncio_awaited_by: -+ awaited_by.append(_build_graph_for_future(parent, limit=limit)) -+ -+ if limit is not None: -+ limit *= -1 -+ if limit > 0: -+ call_stack = call_stack[:limit] -+ elif limit < 0: -+ call_stack = call_stack[limit:] -+ -+ return FutureCallGraph(future, tuple(call_stack), tuple(awaited_by)) -+ -+ -+def format_call_graph( -+ future: futures.Future | None = None, -+ /, -+ *, -+ depth: int = 1, -+ limit: int | None = None, -+) -> str: -+ """Return the async call graph as a string for `future`. -+ -+ If `future` is not provided, format the call graph for the current task. -+ """ -+ -+ def render_level(st: FutureCallGraph, buf: list[str], level: int) -> None: -+ def add_line(line: str) -> None: -+ buf.append(level * ' ' + line) -+ -+ if isinstance(st.future, tasks.Task): -+ add_line( -+ f'* Task(name={st.future.get_name()!r}, id={id(st.future):#x})' -+ ) -+ else: -+ add_line( -+ f'* Future(id={id(st.future):#x})' -+ ) -+ -+ if st.call_stack: -+ add_line( -+ f' + Call stack:' -+ ) -+ for ste in st.call_stack: -+ f = ste.frame -+ -+ if f.f_generator is None: -+ f = ste.frame -+ add_line( -+ f' | File {f.f_code.co_filename!r},' -+ f' line {f.f_lineno}, in' -+ f' {f.f_code.co_qualname}()' -+ ) -+ else: -+ c = f.f_generator -+ -+ try: -+ f = c.cr_frame -+ code = c.cr_code -+ tag = 'async' -+ except AttributeError: -+ try: -+ f = c.ag_frame -+ code = c.ag_code -+ tag = 'async generator' -+ except AttributeError: -+ f = c.gi_frame -+ code = c.gi_code -+ tag = 'generator' -+ -+ add_line( -+ f' | File {f.f_code.co_filename!r},' -+ f' line {f.f_lineno}, in' -+ f' {tag} {code.co_qualname}()' -+ ) -+ -+ if st.awaited_by: -+ add_line( -+ f' + Awaited by:' -+ ) -+ for fut in st.awaited_by: -+ render_level(fut, buf, level + 1) -+ -+ graph = capture_call_graph(future, depth=depth + 1, limit=limit) -+ if graph is None: -+ return "" -+ -+ buf: list[str] = [] -+ try: -+ render_level(graph, buf, 0) -+ finally: -+ # 'graph' has references to frames so we should -+ # make sure it's GC'ed as soon as we don't need it. -+ del graph -+ return '\n'.join(buf) -+ -+def print_call_graph( -+ future: futures.Future | None = None, -+ /, -+ *, -+ file: TextIO | None = None, -+ depth: int = 1, -+ limit: int | None = None, -+) -> None: -+ """Print the async call graph for the current task or the provided Future.""" -+ print(format_call_graph(future, depth=depth, limit=limit), file=file) -diff --git a/Lib/asyncio/locks.py b/Lib/asyncio/locks.py -index f2f8b7ec858..fa3a94764b5 100644 ---- a/Lib/asyncio/locks.py -+++ b/Lib/asyncio/locks.py -@@ -485,7 +485,7 @@ - def __init__(self, parties): - """Create a barrier, initialised to 'parties' tasks.""" - if parties < 1: -- raise ValueError('parties must be > 0') -+ raise ValueError('parties must be >= 1') - - self._cond = Condition() # notify all tasks when state changes - -diff --git a/Lib/asyncio/runners.py b/Lib/asyncio/runners.py -index 0e63c34f60f..14397b4ad0c 100644 ---- a/Lib/asyncio/runners.py -+++ b/Lib/asyncio/runners.py -@@ -74,7 +74,7 @@ - loop.shutdown_default_executor(constants.THREAD_JOIN_TIMEOUT)) - finally: - if self._set_event_loop: -- events.set_event_loop(None) -+ events._set_event_loop(None) - loop.close() - self._loop = None - self._state = _State.CLOSED -@@ -147,7 +147,7 @@ - if not self._set_event_loop: - # Call set_event_loop only once to avoid calling - # attach_loop multiple times on child watchers -- events.set_event_loop(self._loop) -+ events._set_event_loop(self._loop) - self._set_event_loop = True - else: - self._loop = self._loop_factory() -@@ -177,6 +177,7 @@ - running in the same thread. - - If debug is True, the event loop will be run in debug mode. -+ If loop_factory is passed, it is used for new event loop creation. - - This function always creates a new event loop and closes it at the end. - It should be used as a main entry point for asyncio programs, and should -diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py -index f1ab9b12d69..22147451fa7 100644 ---- a/Lib/asyncio/selector_events.py -+++ b/Lib/asyncio/selector_events.py -@@ -180,9 +180,13 @@ - logger.debug("%r got a new connection from %r: %r", - server, addr, conn) - conn.setblocking(False) -- except (BlockingIOError, InterruptedError, ConnectionAbortedError): -- # Early exit because the socket accept buffer is empty. -- return None -+ except ConnectionAbortedError: -+ # Discard connections that were aborted before accept(). -+ continue -+ except (BlockingIOError, InterruptedError): -+ # Early exit because of a signal or -+ # the socket accept buffer is empty. -+ return - except OSError as exc: - # There's nowhere to send the error, so just log it. - if exc.errno in (errno.EMFILE, errno.ENFILE, -@@ -1181,10 +1185,13 @@ - return True - - def _call_connection_lost(self, exc): -- super()._call_connection_lost(exc) -- if self._empty_waiter is not None: -- self._empty_waiter.set_exception( -- ConnectionError("Connection is closed by peer")) -+ try: -+ super()._call_connection_lost(exc) -+ finally: -+ self._write_ready = None -+ if self._empty_waiter is not None: -+ self._empty_waiter.set_exception( -+ ConnectionError("Connection is closed by peer")) - - def _make_empty_waiter(self): - if self._empty_waiter is not None: -@@ -1199,7 +1206,6 @@ - - def close(self): - self._read_ready_cb = None -- self._write_ready = None - super().close() - - -diff --git a/Lib/asyncio/staggered.py b/Lib/asyncio/staggered.py -index 0f4df8855a8..2ad65d8648e 100644 ---- a/Lib/asyncio/staggered.py -+++ b/Lib/asyncio/staggered.py -@@ -8,6 +8,7 @@ - from . import exceptions as exceptions_mod - from . import locks - from . import tasks -+from . import futures - - - async def staggered_race(coro_fns, delay, *, loop=None): -@@ -63,11 +64,32 @@ - """ - # TODO: when we have aiter() and anext(), allow async iterables in coro_fns. - loop = loop or events.get_running_loop() -+ parent_task = tasks.current_task(loop) - enum_coro_fns = enumerate(coro_fns) - winner_result = None - winner_index = None -+ unhandled_exceptions = [] - exceptions = [] -- running_tasks = [] -+ running_tasks = set() -+ on_completed_fut = None -+ -+ def task_done(task): -+ running_tasks.discard(task) -+ futures.future_discard_from_awaited_by(task, parent_task) -+ if ( -+ on_completed_fut is not None -+ and not on_completed_fut.done() -+ and not running_tasks -+ ): -+ on_completed_fut.set_result(None) -+ -+ if task.cancelled(): -+ return -+ -+ exc = task.exception() -+ if exc is None: -+ return -+ unhandled_exceptions.append(exc) - - async def run_one_coro(ok_to_start, previous_failed) -> None: - # in eager tasks this waits for the calling task to append this task -@@ -91,11 +113,12 @@ - this_failed = locks.Event() - next_ok_to_start = locks.Event() - next_task = loop.create_task(run_one_coro(next_ok_to_start, this_failed)) -- running_tasks.append(next_task) -+ futures.future_add_to_awaited_by(next_task, parent_task) -+ running_tasks.add(next_task) -+ next_task.add_done_callback(task_done) - # next_task has been appended to running_tasks so next_task is ok to - # start. - next_ok_to_start.set() -- assert len(running_tasks) == this_index + 2 - # Prepare place to put this coroutine's exceptions if not won - exceptions.append(None) - assert len(exceptions) == this_index + 1 -@@ -120,31 +143,37 @@ - # up as done() == True, cancelled() == False, exception() == - # asyncio.CancelledError. This behavior is specified in - # https://bugs.python.org/issue30048 -- for i, t in enumerate(running_tasks): -- if i != this_index: -+ current_task = tasks.current_task(loop) -+ for t in running_tasks: -+ if t is not current_task: - t.cancel() - -- ok_to_start = locks.Event() -- first_task = loop.create_task(run_one_coro(ok_to_start, None)) -- running_tasks.append(first_task) -- # first_task has been appended to running_tasks so first_task is ok to start. -- ok_to_start.set() -+ propagate_cancellation_error = None - try: -- # Wait for a growing list of tasks to all finish: poor man's version of -- # curio's TaskGroup or trio's nursery -- done_count = 0 -- while done_count != len(running_tasks): -- done, _ = await tasks.wait(running_tasks) -- done_count = len(done) -+ ok_to_start = locks.Event() -+ first_task = loop.create_task(run_one_coro(ok_to_start, None)) -+ futures.future_add_to_awaited_by(first_task, parent_task) -+ running_tasks.add(first_task) -+ first_task.add_done_callback(task_done) -+ # first_task has been appended to running_tasks so first_task is ok to start. -+ ok_to_start.set() -+ propagate_cancellation_error = None -+ # Make sure no tasks are left running if we leave this function -+ while running_tasks: -+ on_completed_fut = loop.create_future() -+ try: -+ await on_completed_fut -+ except exceptions_mod.CancelledError as ex: -+ propagate_cancellation_error = ex -+ for task in running_tasks: -+ task.cancel(*ex.args) -+ on_completed_fut = None -+ if __debug__ and unhandled_exceptions: - # If run_one_coro raises an unhandled exception, it's probably a - # programming error, and I want to see it. -- if __debug__: -- for d in done: -- if d.done() and not d.cancelled() and d.exception(): -- raise d.exception() -+ raise ExceptionGroup("staggered race failed", unhandled_exceptions) -+ if propagate_cancellation_error is not None: -+ raise propagate_cancellation_error - return winner_result, winner_index, exceptions - finally: -- del exceptions -- # Make sure no tasks are left running if we leave this function -- for t in running_tasks: -- t.cancel() -+ del exceptions, propagate_cancellation_error, unhandled_exceptions, parent_task -diff --git a/Lib/asyncio/taskgroups.py b/Lib/asyncio/taskgroups.py -index 9fa772ca9d0..1633478d1c8 100644 ---- a/Lib/asyncio/taskgroups.py -+++ b/Lib/asyncio/taskgroups.py -@@ -6,6 +6,7 @@ - - from . import events - from . import exceptions -+from . import futures - from . import tasks - - -@@ -197,15 +198,20 @@ - else: - task = self._loop.create_task(coro, name=name, context=context) - -- # optimization: Immediately call the done callback if the task is -+ futures.future_add_to_awaited_by(task, self._parent_task) -+ -+ # Always schedule the done callback even if the task is - # already done (e.g. if the coro was able to complete eagerly), -- # and skip scheduling a done callback -- if task.done(): -- self._on_task_done(task) -- else: -- self._tasks.add(task) -- task.add_done_callback(self._on_task_done) -- return task -+ # otherwise if the task completes with an exception then it will cancel -+ # the current task too early. gh-128550, gh-128588 -+ self._tasks.add(task) -+ task.add_done_callback(self._on_task_done) -+ try: -+ return task -+ finally: -+ # gh-128552: prevent a refcycle of -+ # task.exception().__traceback__->TaskGroup.create_task->task -+ del task - - # Since Python 3.8 Tasks propagate all exceptions correctly, - # except for KeyboardInterrupt and SystemExit which are -@@ -225,6 +231,8 @@ - def _on_task_done(self, task): - self._tasks.discard(task) - -+ futures.future_discard_from_awaited_by(task, self._parent_task) -+ - if self._on_completed_fut is not None and not self._tasks: - if not self._on_completed_fut.done(): - self._on_completed_fut.set_result(True) -diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py -index 2112dd4b99d..2d931040e57 100644 ---- a/Lib/asyncio/tasks.py -+++ b/Lib/asyncio/tasks.py -@@ -245,23 +245,23 @@ - return self._num_cancels_requested - - def __eager_start(self): -- prev_task = _swap_current_task(self._loop, self) -+ prev_task = _py_swap_current_task(self._loop, self) - try: -- _register_eager_task(self) -+ _py_register_eager_task(self) - try: - self._context.run(self.__step_run_and_handle_result, None) - finally: -- _unregister_eager_task(self) -+ _py_unregister_eager_task(self) - finally: - try: -- curtask = _swap_current_task(self._loop, prev_task) -+ curtask = _py_swap_current_task(self._loop, prev_task) - assert curtask is self - finally: - if self.done(): - self._coro = None - self = None # Needed to break cycles when an exception occurs. - else: -- _register_task(self) -+ _py_register_task(self) - - def __step(self, exc=None): - if self.done(): -@@ -273,11 +273,11 @@ - self._must_cancel = False - self._fut_waiter = None - -- _enter_task(self._loop, self) -+ _py_enter_task(self._loop, self) - try: - self.__step_run_and_handle_result(exc) - finally: -- _leave_task(self._loop, self) -+ _py_leave_task(self._loop, self) - self = None # Needed to break cycles when an exception occurs. - - def __step_run_and_handle_result(self, exc): -@@ -322,6 +322,7 @@ - self._loop.call_soon( - self.__step, new_exc, context=self._context) - else: -+ futures.future_add_to_awaited_by(result, self) - result._asyncio_future_blocking = False - result.add_done_callback( - self.__wakeup, context=self._context) -@@ -356,6 +357,7 @@ - self = None # Needed to break cycles when an exception occurs. - - def __wakeup(self, future): -+ futures.future_discard_from_awaited_by(future, self) - try: - future.result() - except BaseException as exc: -@@ -502,6 +504,7 @@ - if timeout is not None: - timeout_handle = loop.call_later(timeout, _release_waiter, waiter) - counter = len(fs) -+ cur_task = current_task() - - def _on_completion(f): - nonlocal counter -@@ -514,9 +517,11 @@ - timeout_handle.cancel() - if not waiter.done(): - waiter.set_result(None) -+ futures.future_discard_from_awaited_by(f, cur_task) - - for f in fs: - f.add_done_callback(_on_completion) -+ futures.future_add_to_awaited_by(f, cur_task) - - try: - await waiter -@@ -802,10 +807,19 @@ - outer.set_result([]) - return outer - -- def _done_callback(fut): -+ loop = events._get_running_loop() -+ if loop is not None: -+ cur_task = current_task(loop) -+ else: -+ cur_task = None -+ -+ def _done_callback(fut, cur_task=cur_task): - nonlocal nfinished - nfinished += 1 - -+ if cur_task is not None: -+ futures.future_discard_from_awaited_by(fut, cur_task) -+ - if outer is None or outer.done(): - if not fut.cancelled(): - # Mark exception retrieved. -@@ -862,7 +876,6 @@ - nfuts = 0 - nfinished = 0 - done_futs = [] -- loop = None - outer = None # bpo-46672 - for arg in coros_or_futures: - if arg not in arg_to_fut: -@@ -875,12 +888,13 @@ - # can't control it, disable the "destroy pending task" - # warning. - fut._log_destroy_pending = False -- - nfuts += 1 - arg_to_fut[arg] = fut - if fut.done(): - done_futs.append(fut) - else: -+ if cur_task is not None: -+ futures.future_add_to_awaited_by(fut, cur_task) - fut.add_done_callback(_done_callback) - - else: -@@ -940,7 +954,15 @@ - loop = futures._get_loop(inner) - outer = loop.create_future() - -- def _inner_done_callback(inner): -+ if loop is not None and (cur_task := current_task(loop)) is not None: -+ futures.future_add_to_awaited_by(inner, cur_task) -+ else: -+ cur_task = None -+ -+ def _inner_done_callback(inner, cur_task=cur_task): -+ if cur_task is not None: -+ futures.future_discard_from_awaited_by(inner, cur_task) -+ - if outer.cancelled(): - if not inner.cancelled(): - # Mark inner's result as retrieved. -diff --git a/Lib/asyncio/timeouts.py b/Lib/asyncio/timeouts.py -index e6f5100691d..09342dc7c13 100644 ---- a/Lib/asyncio/timeouts.py -+++ b/Lib/asyncio/timeouts.py -@@ -1,7 +1,6 @@ - import enum - - from types import TracebackType --from typing import final, Optional, Type - - from . import events - from . import exceptions -@@ -23,14 +22,13 @@ - EXITED = "finished" - - --@final - class Timeout: - """Asynchronous context manager for cancelling overdue coroutines. - - Use `timeout()` or `timeout_at()` rather than instantiating this class directly. - """ - -- def __init__(self, when: Optional[float]) -> None: -+ def __init__(self, when: float | None) -> None: - """Schedule a timeout that will trigger at a given loop time. - - - If `when` is `None`, the timeout will never trigger. -@@ -39,15 +37,15 @@ - """ - self._state = _State.CREATED - -- self._timeout_handler: Optional[events.TimerHandle] = None -- self._task: Optional[tasks.Task] = None -+ self._timeout_handler: events.TimerHandle | None = None -+ self._task: tasks.Task | None = None - self._when = when - -- def when(self) -> Optional[float]: -+ def when(self) -> float | None: - """Return the current deadline.""" - return self._when - -- def reschedule(self, when: Optional[float]) -> None: -+ def reschedule(self, when: float | None) -> None: - """Reschedule the timeout.""" - if self._state is not _State.ENTERED: - if self._state is _State.CREATED: -@@ -96,10 +94,10 @@ - - async def __aexit__( - self, -- exc_type: Optional[Type[BaseException]], -- exc_val: Optional[BaseException], -- exc_tb: Optional[TracebackType], -- ) -> Optional[bool]: -+ exc_type: type[BaseException] | None, -+ exc_val: BaseException | None, -+ exc_tb: TracebackType | None, -+ ) -> bool | None: - assert self._state in (_State.ENTERED, _State.EXPIRING) - - if self._timeout_handler is not None: -@@ -142,7 +140,7 @@ - exc_val = exc_val.__context__ - - --def timeout(delay: Optional[float]) -> Timeout: -+def timeout(delay: float | None) -> Timeout: - """Timeout async context manager. - - Useful in cases when you want to apply timeout logic around block -@@ -162,7 +160,7 @@ - return Timeout(loop.time() + delay if delay is not None else None) - - --def timeout_at(when: Optional[float]) -> Timeout: -+def timeout_at(when: float | None) -> Timeout: - """Schedule the timeout at absolute time. - - Like timeout() but argument gives absolute time in the same clock system -diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py -index 0227eb506c6..f69c6a64c39 100644 ---- a/Lib/asyncio/unix_events.py -+++ b/Lib/asyncio/unix_events.py -@@ -28,7 +28,7 @@ - - __all__ = ( - 'SelectorEventLoop', -- 'DefaultEventLoopPolicy', -+ '_DefaultEventLoopPolicy', - 'EventLoop', - ) - -@@ -963,11 +963,11 @@ - return True - - --class _UnixDefaultEventLoopPolicy(events.BaseDefaultEventLoopPolicy): -+class _UnixDefaultEventLoopPolicy(events._BaseDefaultEventLoopPolicy): - """UNIX event loop policy""" - _loop_factory = _UnixSelectorEventLoop - - - SelectorEventLoop = _UnixSelectorEventLoop --DefaultEventLoopPolicy = _UnixDefaultEventLoopPolicy -+_DefaultEventLoopPolicy = _UnixDefaultEventLoopPolicy - EventLoop = SelectorEventLoop -diff --git a/Lib/asyncio/windows_events.py b/Lib/asyncio/windows_events.py -index bf99bc271c7..5f75b17d8ca 100644 ---- a/Lib/asyncio/windows_events.py -+++ b/Lib/asyncio/windows_events.py -@@ -29,8 +29,8 @@ - - __all__ = ( - 'SelectorEventLoop', 'ProactorEventLoop', 'IocpProactor', -- 'DefaultEventLoopPolicy', 'WindowsSelectorEventLoopPolicy', -- 'WindowsProactorEventLoopPolicy', 'EventLoop', -+ '_DefaultEventLoopPolicy', '_WindowsSelectorEventLoopPolicy', -+ '_WindowsProactorEventLoopPolicy', 'EventLoop', - ) - - -@@ -891,13 +891,13 @@ - SelectorEventLoop = _WindowsSelectorEventLoop - - --class WindowsSelectorEventLoopPolicy(events.BaseDefaultEventLoopPolicy): -+class _WindowsSelectorEventLoopPolicy(events._BaseDefaultEventLoopPolicy): - _loop_factory = SelectorEventLoop - - --class WindowsProactorEventLoopPolicy(events.BaseDefaultEventLoopPolicy): -+class _WindowsProactorEventLoopPolicy(events._BaseDefaultEventLoopPolicy): - _loop_factory = ProactorEventLoop - - --DefaultEventLoopPolicy = WindowsProactorEventLoopPolicy -+_DefaultEventLoopPolicy = _WindowsProactorEventLoopPolicy - EventLoop = ProactorEventLoop -diff --git a/Lib/base64.py b/Lib/base64.py -index 61be4fb856e..5d78cc09f40 100644 ---- a/Lib/base64.py -+++ b/Lib/base64.py -@@ -4,7 +4,6 @@ - # Modified 30-Dec-2003 by Barry Warsaw to add full RFC 3548 support - # Modified 22-May-2007 by Guido van Rossum to use bytes everywhere - --import re - import struct - import binascii - -@@ -284,7 +283,7 @@ - s = _bytes_from_decode_data(s) - if casefold: - s = s.upper() -- if re.search(b'[^0-9A-F]', s): -+ if s.translate(None, delete=b'0123456789ABCDEF'): - raise binascii.Error('Non-base16 digit found') - return binascii.unhexlify(s) - -diff --git a/Lib/bdb.py b/Lib/bdb.py -index 81bba8a130f..a741628e32a 100644 ---- a/Lib/bdb.py -+++ b/Lib/bdb.py -@@ -4,6 +4,7 @@ - import sys - import os - import weakref -+from contextlib import contextmanager - from inspect import CO_GENERATOR, CO_COROUTINE, CO_ASYNC_GENERATOR - - __all__ = ["BdbQuit", "Bdb", "Breakpoint"] -@@ -65,6 +66,12 @@ - self.botframe = None - self._set_stopinfo(None, None) - -+ @contextmanager -+ def set_enterframe(self, frame): -+ self.enterframe = frame -+ yield -+ self.enterframe = None -+ - def trace_dispatch(self, frame, event, arg): - """Dispatch a trace function for debugged frames based on the event. - -@@ -90,28 +97,27 @@ - The arg parameter depends on the previous event. - """ - -- self.enterframe = frame -- -- if self.quitting: -- return # None -- if event == 'line': -- return self.dispatch_line(frame) -- if event == 'call': -- return self.dispatch_call(frame, arg) -- if event == 'return': -- return self.dispatch_return(frame, arg) -- if event == 'exception': -- return self.dispatch_exception(frame, arg) -- if event == 'c_call': -- return self.trace_dispatch -- if event == 'c_exception': -- return self.trace_dispatch -- if event == 'c_return': -+ with self.set_enterframe(frame): -+ if self.quitting: -+ return # None -+ if event == 'line': -+ return self.dispatch_line(frame) -+ if event == 'call': -+ return self.dispatch_call(frame, arg) -+ if event == 'return': -+ return self.dispatch_return(frame, arg) -+ if event == 'exception': -+ return self.dispatch_exception(frame, arg) -+ if event == 'c_call': -+ return self.trace_dispatch -+ if event == 'c_exception': -+ return self.trace_dispatch -+ if event == 'c_return': -+ return self.trace_dispatch -+ if event == 'opcode': -+ return self.dispatch_opcode(frame, arg) -+ print('bdb.Bdb.dispatch: unknown debugging event:', repr(event)) - return self.trace_dispatch -- if event == 'opcode': -- return self.dispatch_opcode(frame, arg) -- print('bdb.Bdb.dispatch: unknown debugging event:', repr(event)) -- return self.trace_dispatch - - def dispatch_line(self, frame): - """Invoke user function and return trace function for line event. -@@ -395,15 +401,15 @@ - if frame is None: - frame = sys._getframe().f_back - self.reset() -- self.enterframe = frame -- while frame: -- frame.f_trace = self.trace_dispatch -- self.botframe = frame -- self.frame_trace_lines_opcodes[frame] = (frame.f_trace_lines, frame.f_trace_opcodes) -- # We need f_trace_lines == True for the debugger to work -- frame.f_trace_lines = True -- frame = frame.f_back -- self.set_stepinstr() -+ with self.set_enterframe(frame): -+ while frame: -+ frame.f_trace = self.trace_dispatch -+ self.botframe = frame -+ self.frame_trace_lines_opcodes[frame] = (frame.f_trace_lines, frame.f_trace_opcodes) -+ # We need f_trace_lines == True for the debugger to work -+ frame.f_trace_lines = True -+ frame = frame.f_back -+ self.set_stepinstr() - sys.settrace(self.trace_dispatch) - - def set_continue(self): -diff --git a/Lib/calendar.py b/Lib/calendar.py -index 8c1c646da46..1105a705a80 100644 ---- a/Lib/calendar.py -+++ b/Lib/calendar.py -@@ -428,6 +428,7 @@ - headers = (header for k in months) - a(formatstring(headers, colwidth, c).rstrip()) - a('\n'*l) -+ - # max number of weeks for this row - height = max(len(cal) for cal in row) - for j in range(height): -@@ -646,6 +647,111 @@ - with different_locale(self.locale): - return super().formatmonthname(theyear, themonth, withyear) - -+ -+class _CLIDemoCalendar(LocaleTextCalendar): -+ 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): -+ """ -+ Returns a single week in a string (no newline). -+ """ -+ if highlight_day: -+ from _colorize import get_colors -+ -+ ansi = get_colors() -+ highlight = f"{ansi.BLACK}{ansi.BACKGROUND_YELLOW}" -+ reset = ansi.RESET -+ else: -+ highlight = reset = "" -+ -+ return ' '.join( -+ ( -+ f"{highlight}{self.formatday(d, wd, width)}{reset}" -+ if d == highlight_day -+ else self.formatday(d, wd, width) -+ ) -+ for (d, wd) in theweek -+ ) -+ -+ def formatmonth(self, theyear, themonth, w=0, l=0): -+ """ -+ Return a month's calendar string (multi-line). -+ """ -+ if ( -+ self.highlight_day -+ and self.highlight_day.year == theyear -+ and self.highlight_day.month == themonth -+ ): -+ highlight_day = self.highlight_day.day -+ else: -+ highlight_day = None -+ w = max(2, w) -+ l = max(1, l) -+ s = self.formatmonthname(theyear, themonth, 7 * (w + 1) - 1) -+ s = s.rstrip() -+ s += '\n' * l -+ s += self.formatweekheader(w).rstrip() -+ s += '\n' * l -+ for week in self.monthdays2calendar(theyear, themonth): -+ s += self.formatweek(week, w, highlight_day=highlight_day).rstrip() -+ s += '\n' * l -+ return s -+ -+ def formatyear(self, theyear, w=2, l=1, c=6, m=3): -+ """ -+ Returns a year's calendar as a multi-line string. -+ """ -+ w = max(2, w) -+ l = max(1, l) -+ c = max(2, c) -+ colwidth = (w + 1) * 7 - 1 -+ v = [] -+ a = v.append -+ a(repr(theyear).center(colwidth*m+c*(m-1)).rstrip()) -+ a('\n'*l) -+ header = self.formatweekheader(w) -+ for (i, row) in enumerate(self.yeardays2calendar(theyear, m)): -+ # months in this row -+ months = range(m*i+1, min(m*(i+1)+1, 13)) -+ a('\n'*l) -+ names = (self.formatmonthname(theyear, k, colwidth, False) -+ for k in months) -+ a(formatstring(names, colwidth, c).rstrip()) -+ a('\n'*l) -+ headers = (header for k in months) -+ a(formatstring(headers, colwidth, c).rstrip()) -+ a('\n'*l) -+ -+ if ( -+ self.highlight_day -+ and self.highlight_day.year == theyear -+ and self.highlight_day.month in months -+ ): -+ month_pos = months.index(self.highlight_day.month) -+ else: -+ month_pos = None -+ -+ # max number of weeks for this row -+ height = max(len(cal) for cal in row) -+ for j in range(height): -+ weeks = [] -+ for k, cal in enumerate(row): -+ if j >= len(cal): -+ weeks.append('') -+ else: -+ day = ( -+ self.highlight_day.day if k == month_pos else None -+ ) -+ weeks.append( -+ self.formatweek(cal[j], w, highlight_day=day) -+ ) -+ a(formatstring(weeks, colwidth, c).rstrip()) -+ a('\n' * l) -+ return ''.join(v) -+ -+ - # Support for old module level interface - c = TextCalendar() - -@@ -765,6 +871,7 @@ - sys.exit(1) - - locale = options.locale, options.encoding -+ today = datetime.date.today() - - if options.type == "html": - if options.month: -@@ -781,23 +888,23 @@ - optdict = dict(encoding=encoding, css=options.css) - write = sys.stdout.buffer.write - if options.year is None: -- write(cal.formatyearpage(datetime.date.today().year, **optdict)) -+ write(cal.formatyearpage(today.year, **optdict)) - else: - write(cal.formatyearpage(options.year, **optdict)) - else: - if options.locale: -- cal = LocaleTextCalendar(locale=locale) -+ cal = _CLIDemoCalendar(highlight_day=today, locale=locale) - else: -- cal = TextCalendar() -+ cal = _CLIDemoCalendar(highlight_day=today) - cal.setfirstweekday(options.first_weekday) - optdict = dict(w=options.width, l=options.lines) - if options.month is None: - optdict["c"] = options.spacing - optdict["m"] = options.months -- if options.month is not None: -+ else: - _validate_month(options.month) - if options.year is None: -- result = cal.formatyear(datetime.date.today().year, **optdict) -+ result = cal.formatyear(today.year, **optdict) - elif options.month is None: - result = cal.formatyear(options.year, **optdict) - else: -diff --git a/Lib/configparser.py b/Lib/configparser.py -index 420dce77c23..9dc4fa515cf 100644 ---- a/Lib/configparser.py -+++ b/Lib/configparser.py -@@ -1105,11 +1105,7 @@ - def _handle_rest(self, st, line, fpname): - # a section header or option header? - if self._allow_unnamed_section and st.cursect is None: -- st.sectname = UNNAMED_SECTION -- st.cursect = self._dict() -- self._sections[st.sectname] = st.cursect -- self._proxies[st.sectname] = SectionProxy(self, st.sectname) -- st.elements_added.add(st.sectname) -+ self._handle_header(st, UNNAMED_SECTION, fpname) - - st.indent_level = st.cur_indent_level - # is it a section header? -@@ -1118,10 +1114,10 @@ - if not mo and st.cursect is None: - raise MissingSectionHeaderError(fpname, st.lineno, line) - -- self._handle_header(st, mo, fpname) if mo else self._handle_option(st, line, fpname) -+ self._handle_header(st, mo.group('header'), fpname) if mo else self._handle_option(st, line, fpname) - -- def _handle_header(self, st, mo, fpname): -- st.sectname = mo.group('header') -+ def _handle_header(self, st, sectname, fpname): -+ st.sectname = sectname - if st.sectname in self._sections: - if self._strict and st.sectname in st.elements_added: - raise DuplicateSectionError(st.sectname, fpname, -diff --git a/Lib/copy.py b/Lib/copy.py -index f27e109973c..c64fc076179 100644 ---- a/Lib/copy.py -+++ b/Lib/copy.py -@@ -67,13 +67,15 @@ - - cls = type(x) - -- copier = _copy_dispatch.get(cls) -- if copier: -- return copier(x) -+ if cls in _copy_atomic_types: -+ return x -+ if cls in _copy_builtin_containers: -+ return cls.copy(x) -+ - - if issubclass(cls, type): - # treat it as a regular class: -- return _copy_immutable(x) -+ return x - - copier = getattr(cls, "__copy__", None) - if copier is not None: -@@ -98,23 +100,12 @@ - return _reconstruct(x, None, *rv) - - --_copy_dispatch = d = {} -- --def _copy_immutable(x): -- return x --for t in (types.NoneType, int, float, bool, complex, str, tuple, -+_copy_atomic_types = {types.NoneType, int, float, bool, complex, str, tuple, - bytes, frozenset, type, range, slice, property, - types.BuiltinFunctionType, types.EllipsisType, - types.NotImplementedType, types.FunctionType, types.CodeType, -- weakref.ref, super): -- d[t] = _copy_immutable -- --d[list] = list.copy --d[dict] = dict.copy --d[set] = set.copy --d[bytearray] = bytearray.copy -- --del d, t -+ weakref.ref, super} -+_copy_builtin_containers = {list, dict, set, bytearray} - - def deepcopy(x, memo=None, _nil=[]): - """Deep copy operation on arbitrary Python objects. -diff --git a/Lib/csv.py b/Lib/csv.py -index cd202659873..0a627ba7a51 100644 ---- a/Lib/csv.py -+++ b/Lib/csv.py -@@ -63,7 +63,6 @@ - written as two quotes - """ - --import re - import types - from _csv import Error, writer, reader, register_dialect, \ - unregister_dialect, get_dialect, list_dialects, \ -@@ -281,6 +280,7 @@ - If there is no quotechar the delimiter can't be determined - this way. - """ -+ import re - - matches = [] - for restr in (r'(?P[^\w\n"\'])(?P ?)(?P["\']).*?(?P=quote)(?P=delim)', # ,".*?", -diff --git a/Lib/ctypes/__init__.py b/Lib/ctypes/__init__.py -index 2f2b0ca9f38..8e2a2926f7a 100644 ---- a/Lib/ctypes/__init__.py -+++ b/Lib/ctypes/__init__.py -@@ -524,6 +524,7 @@ - # functions - - from _ctypes import _memmove_addr, _memset_addr, _string_at_addr, _cast_addr -+from _ctypes import _memoryview_at_addr - - ## void *memmove(void *, const void *, size_t); - memmove = CFUNCTYPE(c_void_p, c_void_p, c_void_p, c_size_t)(_memmove_addr) -@@ -549,6 +550,14 @@ - Return the byte string at void *ptr.""" - return _string_at(ptr, size) - -+_memoryview_at = PYFUNCTYPE( -+ py_object, c_void_p, c_ssize_t, c_int)(_memoryview_at_addr) -+def memoryview_at(ptr, size, readonly=False): -+ """memoryview_at(ptr, size[, readonly]) -> memoryview -+ -+ Return a memoryview representing the memory at void *ptr.""" -+ return _memoryview_at(ptr, size, bool(readonly)) -+ - try: - from _ctypes import _wstring_at_addr - except ImportError: -diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py -index 117bf06cb01..99504911a3d 100644 ---- a/Lib/ctypes/util.py -+++ b/Lib/ctypes/util.py -@@ -67,6 +67,65 @@ - return fname - return None - -+ # Listing loaded DLLs on Windows relies on the following APIs: -+ # https://learn.microsoft.com/windows/win32/api/psapi/nf-psapi-enumprocessmodules -+ # https://learn.microsoft.com/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulefilenamew -+ import ctypes -+ from ctypes import wintypes -+ -+ _kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) -+ _get_current_process = _kernel32["GetCurrentProcess"] -+ _get_current_process.restype = wintypes.HANDLE -+ -+ _k32_get_module_file_name = _kernel32["GetModuleFileNameW"] -+ _k32_get_module_file_name.restype = wintypes.DWORD -+ _k32_get_module_file_name.argtypes = ( -+ wintypes.HMODULE, -+ wintypes.LPWSTR, -+ wintypes.DWORD, -+ ) -+ -+ _psapi = ctypes.WinDLL('psapi', use_last_error=True) -+ _enum_process_modules = _psapi["EnumProcessModules"] -+ _enum_process_modules.restype = wintypes.BOOL -+ _enum_process_modules.argtypes = ( -+ wintypes.HANDLE, -+ ctypes.POINTER(wintypes.HMODULE), -+ wintypes.DWORD, -+ wintypes.LPDWORD, -+ ) -+ -+ def _get_module_filename(module: wintypes.HMODULE): -+ name = (wintypes.WCHAR * 32767)() # UNICODE_STRING_MAX_CHARS -+ if _k32_get_module_file_name(module, name, len(name)): -+ return name.value -+ return None -+ -+ -+ def _get_module_handles(): -+ process = _get_current_process() -+ space_needed = wintypes.DWORD() -+ n = 1024 -+ while True: -+ modules = (wintypes.HMODULE * n)() -+ if not _enum_process_modules(process, -+ modules, -+ ctypes.sizeof(modules), -+ ctypes.byref(space_needed)): -+ err = ctypes.get_last_error() -+ msg = ctypes.FormatError(err).strip() -+ raise ctypes.WinError(err, f"EnumProcessModules failed: {msg}") -+ n = space_needed.value // ctypes.sizeof(wintypes.HMODULE) -+ if n <= len(modules): -+ return modules[:n] -+ -+ def dllist(): -+ """Return a list of loaded shared libraries in the current process.""" -+ modules = _get_module_handles() -+ libraries = [name for h in modules -+ if (name := _get_module_filename(h)) is not None] -+ return libraries -+ - elif os.name == "posix" and sys.platform in {"darwin", "ios", "tvos", "watchos"}: - from ctypes.macholib.dyld import dyld_find as _dyld_find - def find_library(name): -@@ -80,6 +139,22 @@ - continue - return None - -+ # Listing loaded libraries on Apple systems relies on the following API: -+ # https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dyld.3.html -+ import ctypes -+ -+ _libc = ctypes.CDLL(find_library("c")) -+ _dyld_get_image_name = _libc["_dyld_get_image_name"] -+ _dyld_get_image_name.restype = ctypes.c_char_p -+ -+ def dllist(): -+ """Return a list of loaded shared libraries in the current process.""" -+ num_images = _libc._dyld_image_count() -+ libraries = [os.fsdecode(name) for i in range(num_images) -+ if (name := _dyld_get_image_name(i)) is not None] -+ -+ return libraries -+ - elif sys.platform.startswith("aix"): - # AIX has two styles of storing shared libraries - # GNU auto_tools refer to these as svr4 and aix -@@ -341,6 +416,55 @@ - return _findSoname_ldconfig(name) or \ - _get_soname(_findLib_gcc(name)) or _get_soname(_findLib_ld(name)) - -+ -+# Listing loaded libraries on other systems will try to use -+# functions common to Linux and a few other Unix-like systems. -+# See the following for several platforms' documentation of the same API: -+# https://man7.org/linux/man-pages/man3/dl_iterate_phdr.3.html -+# https://man.freebsd.org/cgi/man.cgi?query=dl_iterate_phdr -+# https://man.openbsd.org/dl_iterate_phdr -+# https://docs.oracle.com/cd/E88353_01/html/E37843/dl-iterate-phdr-3c.html -+if (os.name == "posix" and -+ sys.platform not in {"darwin", "ios", "tvos", "watchos"}): -+ import ctypes -+ if hasattr((_libc := ctypes.CDLL(None)), "dl_iterate_phdr"): -+ -+ class _dl_phdr_info(ctypes.Structure): -+ _fields_ = [ -+ ("dlpi_addr", ctypes.c_void_p), -+ ("dlpi_name", ctypes.c_char_p), -+ ("dlpi_phdr", ctypes.c_void_p), -+ ("dlpi_phnum", ctypes.c_ushort), -+ ] -+ -+ _dl_phdr_callback = ctypes.CFUNCTYPE( -+ ctypes.c_int, -+ ctypes.POINTER(_dl_phdr_info), -+ ctypes.c_size_t, -+ ctypes.POINTER(ctypes.py_object), -+ ) -+ -+ @_dl_phdr_callback -+ def _info_callback(info, _size, data): -+ libraries = data.contents.value -+ name = os.fsdecode(info.contents.dlpi_name) -+ libraries.append(name) -+ return 0 -+ -+ _dl_iterate_phdr = _libc["dl_iterate_phdr"] -+ _dl_iterate_phdr.argtypes = [ -+ _dl_phdr_callback, -+ ctypes.POINTER(ctypes.py_object), -+ ] -+ _dl_iterate_phdr.restype = ctypes.c_int -+ -+ def dllist(): -+ """Return a list of loaded shared libraries in the current process.""" -+ libraries = [] -+ _dl_iterate_phdr(_info_callback, -+ ctypes.byref(ctypes.py_object(libraries))) -+ return libraries -+ - ################################################################ - # test code - -@@ -384,5 +508,12 @@ - print(cdll.LoadLibrary("libcrypt.so")) - print(find_library("crypt")) - -+ try: -+ dllist -+ except NameError: -+ print('dllist() not available') -+ else: -+ print(dllist()) -+ - if __name__ == "__main__": - test() -diff --git a/Lib/difflib.py b/Lib/difflib.py -index 7f595b6c72e..c124afdd039 100644 ---- a/Lib/difflib.py -+++ b/Lib/difflib.py -@@ -1632,13 +1632,22 @@ - """ - - _styles = """ -+ :root {color-scheme: light dark} - table.diff {font-family:Courier; border:medium;} - .diff_header {background-color:#e0e0e0} - td.diff_header {text-align:right} - .diff_next {background-color:#c0c0c0} -- .diff_add {background-color:#aaffaa} -+ .diff_add {background-color:palegreen} - .diff_chg {background-color:#ffff77} -- .diff_sub {background-color:#ffaaaa}""" -+ .diff_sub {background-color:#ffaaaa} -+ -+ @media (prefers-color-scheme: dark) { -+ .diff_header {background-color:#666} -+ .diff_next {background-color:#393939} -+ .diff_add {background-color:darkgreen} -+ .diff_chg {background-color:#847415} -+ .diff_sub {background-color:darkred} -+ }""" - - _table_template = """ -
[ \t]+) | # spaces and horizontal tabs -- (?P[0-9]+\b) | # decimal integer -- (?Pn\b) | # only n is allowed -- (?P[()]) | -- (?P[-*/%+?:]|[>, -- # <=, >=, ==, !=, &&, ||, -- # ? : -- # unary and bitwise ops -- # not allowed -- (?P\w+|.) # invalid token -- """, re.VERBOSE|re.DOTALL) -- -+_token_pattern = None - - def _tokenize(plural): -- for mo in re.finditer(_token_pattern, plural): -+ global _token_pattern -+ if _token_pattern is None: -+ import re -+ _token_pattern = re.compile(r""" -+ (?P[ \t]+) | # spaces and horizontal tabs -+ (?P[0-9]+\b) | # decimal integer -+ (?Pn\b) | # only n is allowed -+ (?P[()]) | -+ (?P[-*/%+?:]|[>, -+ # <=, >=, ==, !=, &&, ||, -+ # ? : -+ # unary and bitwise ops -+ # not allowed -+ (?P\w+|.) # invalid token -+ """, re.VERBOSE|re.DOTALL) -+ -+ for mo in _token_pattern.finditer(plural): - kind = mo.lastgroup - if kind == 'WHITESPACES': - continue -diff --git a/Lib/glob.py b/Lib/glob.py -index 690ab1b8b9f..cd8859e6331 100644 ---- a/Lib/glob.py -+++ b/Lib/glob.py -@@ -348,13 +348,7 @@ - - @staticmethod - def scandir(path): -- """Implements os.scandir(). -- """ -- raise NotImplementedError -- -- @staticmethod -- def add_slash(path): -- """Returns a path with a trailing slash added. -+ """Like os.scandir(), but generates (entry, name, path) tuples. - """ - raise NotImplementedError - -@@ -389,10 +383,12 @@ - def special_selector(self, part, parts): - """Returns a function that selects special children of the given path. - """ -+ if parts: -+ part += self.sep - select_next = self.selector(parts) - - def select_special(path, exists=False): -- path = self.concat_path(self.add_slash(path), part) -+ path = self.concat_path(path, part) - return select_next(path, exists) - return select_special - -@@ -402,14 +398,16 @@ - - # Optimization: consume and join any subsequent literal parts here, - # rather than leaving them for the next selector. This reduces the -- # number of string concatenation operations and calls to add_slash(). -+ # number of string concatenation operations. - while parts and magic_check.search(parts[-1]) is None: - part += self.sep + parts.pop() -+ if parts: -+ part += self.sep - - select_next = self.selector(parts) - - def select_literal(path, exists=False): -- path = self.concat_path(self.add_slash(path), part) -+ path = self.concat_path(path, part) - return select_next(path, exists=False) - return select_literal - -@@ -425,24 +423,19 @@ - - def select_wildcard(path, exists=False): - try: -- # We must close the scandir() object before proceeding to -- # avoid exhausting file descriptors when globbing deep trees. -- with self.scandir(path) as scandir_it: -- entries = list(scandir_it) -+ entries = self.scandir(path) - except OSError: - pass - else: -- prefix = self.add_slash(path) -- for entry in entries: -- if match is None or match(entry.name): -+ for entry, entry_name, entry_path in entries: -+ if match is None or match(entry_name): - if dir_only: - try: - if not entry.is_dir(): - continue - except OSError: - continue -- entry_path = self.concat_path(prefix, entry.name) -- if dir_only: -+ entry_path = self.concat_path(entry_path, self.sep) - yield from select_next(entry_path, exists=True) - else: - yield entry_path -@@ -472,7 +465,6 @@ - select_next = self.selector(parts) - - def select_recursive(path, exists=False): -- path = self.add_slash(path) - match_pos = len(str(path)) - if match is None or match(str(path), match_pos): - yield from select_next(path, exists) -@@ -483,15 +475,11 @@ - def select_recursive_step(stack, match_pos): - path = stack.pop() - try: -- # We must close the scandir() object before proceeding to -- # avoid exhausting file descriptors when globbing deep trees. -- with self.scandir(path) as scandir_it: -- entries = list(scandir_it) -+ entries = self.scandir(path) - except OSError: - pass - else: -- prefix = self.add_slash(path) -- for entry in entries: -+ for entry, _entry_name, entry_path in entries: - is_dir = False - try: - if entry.is_dir(follow_symlinks=follow_symlinks): -@@ -500,8 +488,10 @@ - pass - - if is_dir or not dir_only: -- entry_path = self.concat_path(prefix, entry.name) -- if match is None or match(str(entry_path), match_pos): -+ entry_path_str = str(entry_path) -+ if dir_only: -+ entry_path = self.concat_path(entry_path, self.sep) -+ if match is None or match(entry_path_str, match_pos): - if dir_only: - yield from select_next(entry_path, exists=True) - else: -@@ -528,19 +518,27 @@ - """Provides shell-style pattern matching and globbing for string paths. - """ - lexists = staticmethod(os.path.lexists) -- scandir = staticmethod(os.scandir) - concat_path = operator.add - -- if os.name == 'nt': -- @staticmethod -- def add_slash(pathname): -- tail = os.path.splitroot(pathname)[2] -- if not tail or tail[-1] in '\\/': -- return pathname -- return f'{pathname}\\' -- else: -- @staticmethod -- def add_slash(pathname): -- if not pathname or pathname[-1] == '/': -- return pathname -- return f'{pathname}/' -+ @staticmethod -+ def scandir(path): -+ # We must close the scandir() object before proceeding to -+ # avoid exhausting file descriptors when globbing deep trees. -+ with os.scandir(path) as scandir_it: -+ entries = list(scandir_it) -+ return ((entry, entry.name, entry.path) for entry in entries) -+ -+ -+class _PathGlobber(_GlobberBase): -+ """Provides shell-style pattern matching and globbing for pathlib paths. -+ """ -+ -+ lexists = operator.methodcaller('exists', follow_symlinks=False) -+ -+ @staticmethod -+ def scandir(path): -+ return ((child.info, child.name, child) for child in path.iterdir()) -+ -+ @staticmethod -+ def concat_path(path, text): -+ return path.with_segments(str(path) + text) -diff --git a/Lib/graphlib.py b/Lib/graphlib.py -index 1438a5fc54b..82f33fb5cf3 100644 ---- a/Lib/graphlib.py -+++ b/Lib/graphlib.py -@@ -154,7 +154,7 @@ - This method unblocks any successor of each node in *nodes* for being returned - in the future by a call to "get_ready". - -- Raises :exec:`ValueError` if any node in *nodes* has already been marked as -+ Raises ValueError if any node in *nodes* has already been marked as - processed by a previous call to this method, if a node was not added to the - graph by using "add" or if called without calling "prepare" previously or if - node has not yet been returned by "get_ready". -diff --git a/Lib/http/__init__.py b/Lib/http/__init__.py -index d64741ec0dd..691b4a9a367 100644 ---- a/Lib/http/__init__.py -+++ b/Lib/http/__init__.py -@@ -54,8 +54,9 @@ - CONTINUE = 100, 'Continue', 'Request received, please continue' - SWITCHING_PROTOCOLS = (101, 'Switching Protocols', - 'Switching to new protocol; obey Upgrade header') -- PROCESSING = 102, 'Processing' -- EARLY_HINTS = 103, 'Early Hints' -+ PROCESSING = 102, 'Processing', 'Server is processing the request' -+ EARLY_HINTS = (103, 'Early Hints', -+ 'Headers sent to prepare for the response') - - # success - OK = 200, 'OK', 'Request fulfilled, document follows' -@@ -67,9 +68,11 @@ - NO_CONTENT = 204, 'No Content', 'Request fulfilled, nothing follows' - RESET_CONTENT = 205, 'Reset Content', 'Clear input form for further input' - PARTIAL_CONTENT = 206, 'Partial Content', 'Partial content follows' -- MULTI_STATUS = 207, 'Multi-Status' -- ALREADY_REPORTED = 208, 'Already Reported' -- IM_USED = 226, 'IM Used' -+ MULTI_STATUS = (207, 'Multi-Status', -+ 'Response contains multiple statuses in the body') -+ ALREADY_REPORTED = (208, 'Already Reported', -+ 'Operation has already been reported') -+ IM_USED = 226, 'IM Used', 'Request completed using instance manipulations' - - # redirection - MULTIPLE_CHOICES = (300, 'Multiple Choices', -@@ -128,15 +131,19 @@ - EXPECTATION_FAILED = (417, 'Expectation Failed', - 'Expect condition could not be satisfied') - IM_A_TEAPOT = (418, 'I\'m a Teapot', -- 'Server refuses to brew coffee because it is a teapot.') -+ 'Server refuses to brew coffee because it is a teapot') - MISDIRECTED_REQUEST = (421, 'Misdirected Request', - 'Server is not able to produce a response') -- UNPROCESSABLE_CONTENT = 422, 'Unprocessable Content' -+ UNPROCESSABLE_CONTENT = (422, 'Unprocessable Content', -+ 'Server is not able to process the contained instructions') - UNPROCESSABLE_ENTITY = UNPROCESSABLE_CONTENT -- LOCKED = 423, 'Locked' -- FAILED_DEPENDENCY = 424, 'Failed Dependency' -- TOO_EARLY = 425, 'Too Early' -- UPGRADE_REQUIRED = 426, 'Upgrade Required' -+ LOCKED = 423, 'Locked', 'Resource of a method is locked' -+ FAILED_DEPENDENCY = (424, 'Failed Dependency', -+ 'Dependent action of the request failed') -+ TOO_EARLY = (425, 'Too Early', -+ 'Server refuses to process a request that might be replayed') -+ UPGRADE_REQUIRED = (426, 'Upgrade Required', -+ 'Server refuses to perform the request using the current protocol') - PRECONDITION_REQUIRED = (428, 'Precondition Required', - 'The origin server requires the request to be conditional') - TOO_MANY_REQUESTS = (429, 'Too Many Requests', -@@ -164,10 +171,14 @@ - 'The gateway server did not receive a timely response') - HTTP_VERSION_NOT_SUPPORTED = (505, 'HTTP Version Not Supported', - 'Cannot fulfill request') -- VARIANT_ALSO_NEGOTIATES = 506, 'Variant Also Negotiates' -- INSUFFICIENT_STORAGE = 507, 'Insufficient Storage' -- LOOP_DETECTED = 508, 'Loop Detected' -- NOT_EXTENDED = 510, 'Not Extended' -+ VARIANT_ALSO_NEGOTIATES = (506, 'Variant Also Negotiates', -+ 'Server has an internal configuration error') -+ INSUFFICIENT_STORAGE = (507, 'Insufficient Storage', -+ 'Server is not able to store the representation') -+ LOOP_DETECTED = (508, 'Loop Detected', -+ 'Server encountered an infinite loop while processing a request') -+ NOT_EXTENDED = (510, 'Not Extended', -+ 'Request does not meet the resource access policy') - NETWORK_AUTHENTICATION_REQUIRED = (511, - 'Network Authentication Required', - 'The client needs to authenticate to gain network access') -@@ -179,7 +190,7 @@ - - Methods from the following RFCs are all observed: - -- * RFF 9110: HTTP Semantics, obsoletes 7231, which obsoleted 2616 -+ * RFC 9110: HTTP Semantics, obsoletes 7231, which obsoleted 2616 - * RFC 5789: PATCH Method for HTTP - """ - def __new__(cls, value, description): -diff --git a/Lib/http/client.py b/Lib/http/client.py -index fab90a0ba4e..33a858d34ae 100644 ---- a/Lib/http/client.py -+++ b/Lib/http/client.py -@@ -472,7 +472,7 @@ - if self.chunked: - return self._read_chunked(amt) - -- if amt is not None: -+ if amt is not None and amt >= 0: - if self.length is not None and amt > self.length: - # clip the read to the "end of response" - amt = self.length -@@ -590,6 +590,8 @@ - - def _read_chunked(self, amt=None): - assert self.chunked != _UNKNOWN -+ if amt is not None and amt < 0: -+ amt = None - value = [] - try: - while (chunk_left := self._get_chunk_left()) is not None: -diff --git a/Lib/http/cookies.py b/Lib/http/cookies.py -index 23d5461f86f..694b1b09a05 100644 ---- a/Lib/http/cookies.py -+++ b/Lib/http/cookies.py -@@ -264,11 +264,12 @@ - "httponly" : "HttpOnly", - "version" : "Version", - "samesite" : "SameSite", -+ "partitioned": "Partitioned", - } - - _reserved_defaults = dict.fromkeys(_reserved, "") - -- _flags = {'secure', 'httponly'} -+ _flags = {'secure', 'httponly', 'partitioned'} - - def __init__(self): - # Set defaults -diff --git a/Lib/http/server.py b/Lib/http/server.py -index a6f7aecc787..a90c8d34c39 100644 ---- a/Lib/http/server.py -+++ b/Lib/http/server.py -@@ -99,7 +99,7 @@ - import posixpath - import select - import shutil --import socket # For gethostbyaddr() -+import socket - import socketserver - import sys - import time -diff --git a/Lib/idlelib/CREDITS.txt b/Lib/idlelib/CREDITS.txt -index 4a42af586a4..bea3ba7c20d 100644 ---- a/Lib/idlelib/CREDITS.txt -+++ b/Lib/idlelib/CREDITS.txt -@@ -33,15 +33,15 @@ - - - 2005: Tal Einat - - 2010: Terry Jan Reedy (current maintainer) --- 2013: Roger Serwys -+- 2013: Roger Serwy - - 2014: Saimadhav Heblikar - - 2015: Mark Roseman - - 2017: Louie Lu, Cheryl Sabella, and Serhiy Storchaka - - For additional details refer to NEWS.txt and Changelog. - --Please contact the IDLE maintainer (kbk@shore.net) to have yourself included --here if you are one of those we missed! -+If we missed you, feel free to submit a PR with a summary of -+contributions (for instance, at least 5 merged PRs). - - - -diff --git a/Lib/idlelib/News3.txt b/Lib/idlelib/News3.txt -index 37ff93f9866..74d84b38931 100644 ---- a/Lib/idlelib/News3.txt -+++ b/Lib/idlelib/News3.txt -@@ -1,8 +1,26 @@ -+What's New in IDLE 3.14.0 -+(since 3.13.0) -+Released on 2025-10-07 -+========================= -+ -+ -+gh-127060: Set TERM environment variable to 'dumb' to not add ANSI escape -+sequences for text color in tracebacks. IDLE does not understand them. -+Patch by Victor Stinner. -+ -+gh-122392: Increase currently inadequate vertical spacing for the IDLE -+browsers (path, module, and stack) on high-resolution monitors. -+ -+ - What's New in IDLE 3.13.0 - (since 3.12.0) --Released on 2024-10-xx -+Released on 2024-10-07 - ========================= - -+gh-120104: Fix padding in config and search dialog windows in IDLE. -+ -+gh-129873: Simplify displaying the IDLE doc by only copying the text -+section of idle.html to idlelib/help.html. Patch by Stan Ulbrych. - - gh-120083: Add explicit black IDLE Hovertip foreground color needed for - recent macOS. Fixes Sonoma showing unreadable white on pale yellow. -diff --git a/Lib/idlelib/__main__.py b/Lib/idlelib/__main__.py -index 6349ec75c64..ec3915b265f 100644 ---- a/Lib/idlelib/__main__.py -+++ b/Lib/idlelib/__main__.py -@@ -5,4 +5,3 @@ - """ - import idlelib.pyshell - idlelib.pyshell.main() --# This file does not work for 2.7; See issue 24212. -diff --git a/Lib/idlelib/help.html b/Lib/idlelib/help.html -index 2a4adc6a4d3..ebff9a309d9 100644 ---- a/Lib/idlelib/help.html -+++ b/Lib/idlelib/help.html -@@ -1,231 +1,7 @@ -- -- -- -- -- -- -- -- IDLE — Python 3.14.0a0 documentation -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
--
--
--
-- --
--

IDLE¶

--

Source code: Lib/idlelib/

--
-+
-+

IDLE — Python editor and shell¶

-+

Source code: Lib/idlelib/

-+
-

IDLE is Python’s Integrated Development and Learning Environment.

-

IDLE has the following features:

-
    -@@ -241,7 +17,7 @@ -
  • configuration, browsers, and other dialogs

  • -
- -
--

Editing and Navigation¶

-+

Editing and Navigation¶

-
--

Editor windows¶

-+

Editor windows¶

-

IDLE may open editor windows when it starts, depending on settings - and how you start IDLE. Thereafter, use the File menu. There can be only - one open editor window for a given file.

-@@ -548,7 +324,7 @@ - and that other files do not. Run Python code with the Run menu.

-
-
--

Key bindings¶

-+

Key bindings¶

-

The IDLE insertion cursor is a thin vertical bar between character - positions. When characters are entered, the insertion cursor and - everything to its right moves right one character and -@@ -574,7 +350,7 @@ - may work. Keybindings are selected in the Configure IDLE dialog.

-
-
--

Automatic indentation¶

-+

Automatic indentation¶

-

After a block-opening statement, the next line is indented by 4 spaces (in the - Python Shell window by one tab). After certain keywords (break, return etc.) - the next line is dedented. In leading indentation, Backspace deletes up -@@ -585,14 +361,14 @@ - Format menu.

-
-
--

Search and Replace¶

-+

Search and Replace¶

-

Any selection becomes a search target. However, only selections within - a line work because searches are only performed within lines with the - terminal newline removed. If [x] Regular expression is checked, the - target is interpreted according to the Python re module.

-
-
--

Completions¶

-+

Completions¶

-

Completions are supplied, when requested and available, for module - names, attributes of classes or functions, or filenames. Each request - method displays a completion box with existing names. (See tab -@@ -636,7 +412,7 @@ - by typing ‘_’ after ‘.’, either before or after the box is opened.

-
-
--

Calltips¶

-+

Calltips¶

-

A calltip is shown automatically when one types ( after the name - of an accessible function. A function name expression may include - dots and subscripts. A calltip remains until it is clicked, the cursor -@@ -662,7 +438,7 @@ - adding function definitions, or after opening an existing file.

-
-
--

Code Context¶

-+

Code Context¶

-

Within an editor window containing Python code, code context can be toggled - in order to show or hide a pane at the top of the window. When shown, this - pane freezes the opening lines for block code, such as those beginning with -@@ -677,7 +453,7 @@ - the Highlights tab in the Configure IDLE dialog.

-
-
--

Shell window¶

-+

Shell window¶

-

In IDLE’s Shell, enter, edit, and recall complete statements. (Most - consoles and terminals only work with a single physical line at a time).

-

Submit a single-line statement for execution by hitting Return -@@ -707,7 +483,7 @@ - -

-
--

Text colors¶

-+

Text colors¶

-

Idle defaults to black on white text, but colors text with special meanings. - For the shell, these are shell output, shell error, user output, and - user error. For Python code, at the shell prompt or in an editor, these are -@@ -726,7 +502,7 @@ -

-
-
--

Startup and Code Execution¶

-+

Startup and Code Execution¶

-

Upon startup with the -s option, IDLE will execute the file referenced by - the environment variables IDLESTARTUP or PYTHONSTARTUP. - IDLE first checks for IDLESTARTUP; if IDLESTARTUP is present the file -@@ -740,7 +516,7 @@ - executed in the Tk namespace, so this file is not useful for importing - functions to be used from IDLE’s Python shell.

-
--

Command line usage¶

-+

Command line usage¶

-
idle.py [-c command] [-d] [-e] [-h] [-i] [-r file] [-s] [-t title] [-] [arg] ...
- 
- -c command  run command in the shell window
-@@ -765,7 +541,7 @@
- 
- 
-
--

Startup failure¶

-+

Startup failure¶

-

IDLE uses a socket to communicate between the IDLE GUI process and the user - code execution process. A connection must be established whenever the Shell - starts or restarts. (The latter is indicated by a divider line that says -@@ -817,7 +593,7 @@ - then re-configure IDLE to use a font that works better.

-
-
--

Running user code¶

-+

Running user code¶

-

With rare exceptions, the result of executing Python code with IDLE is - intended to be the same as executing the same code by the default method, - directly with Python in a text-mode system console or terminal window. -@@ -861,7 +637,7 @@ - IDLE returns to a Shell prompt instead of exiting.

-
-
--

User output in Shell¶

-+

User output in Shell¶

-

When a program outputs text, the result is determined by the - corresponding output device. When IDLE executes user code, sys.stdout - and sys.stderr are connected to the display area of IDLE’s Shell. Some of -@@ -915,7 +691,7 @@ - right-clicking the label.

-
-
--

Developing tkinter applications¶

-+

Developing tkinter applications¶

-

IDLE is intentionally different from standard Python in order to - facilitate development of tkinter programs. Enter import tkinter as tk; - root = tk.Tk() in standard Python and nothing appears. Enter the same -@@ -935,7 +711,7 @@ - re-enable the mainloop call when running in standard Python.

-
-
--

Running without a subprocess¶

-+

Running without a subprocess¶

-

By default, IDLE executes user code in a separate subprocess via a socket, - which uses the internal loopback interface. This connection is not - externally visible and no data is sent to or received from the internet. -@@ -961,9 +737,9 @@ -

-
-
--

Help and Preferences¶

-+

Help and Preferences¶

-
--

Help sources¶

-+

Help sources¶

-

Help menu entry “IDLE Help†displays a formatted html version of the - IDLE chapter of the Library Reference. The result, in a read-only - tkinter text window, is close to what one sees in a web browser. -@@ -980,7 +756,7 @@ - General tab of the Configure IDLE dialog.

-
-
--

Setting preferences¶

-+

Setting preferences¶

-

The font preferences, highlighting, keys, and general preferences can be - changed via Configure IDLE on the Option menu. - Non-default user settings are saved in a .idlerc directory in the user’s -@@ -998,13 +774,13 @@ - to older IDLEs.

-
-
--

IDLE on macOS¶

-+

IDLE on macOS¶

-

Under System Preferences: Dock, one can set “Prefer tabs when opening - documents†to “Alwaysâ€. This setting is not compatible with the tk/tkinter - GUI framework used by IDLE, and it breaks a few IDLE features.

-
-
--

Extensions¶

-+

Extensions¶

-

IDLE contains an extension facility. Preferences for extensions can be - changed with the Extensions tab of the preferences dialog. See the - beginning of config-extensions.def in the idlelib directory for further -@@ -1013,8 +789,8 @@ -

-
-
--

idlelib¶

--

Source code: Lib/idlelib

-+

idlelib — implementation of IDLE application¶

-+

Source code: Lib/idlelib

-
-

The Lib/idlelib package implements the IDLE application. See the rest - of this page for how to use IDLE.

-@@ -1027,168 +803,3 @@ -
- - --
--
--
--
-- --
--
-- -- -- -- -- -diff --git a/Lib/idlelib/help.py b/Lib/idlelib/help.py -index d8613b2eadd..063a749df54 100644 ---- a/Lib/idlelib/help.py -+++ b/Lib/idlelib/help.py -@@ -20,7 +20,7 @@ - - HelpWindow - Display HelpFrame in a standalone window. - --copy_strip - Copy idle.html to help.html, rstripping each line. -+copy_strip - Copy the text part of idle.html to help.html while rstripping each line. - - show_idlehelp - Create HelpWindow. Called in EditorWindow.help_dialog. - """ -@@ -54,7 +54,6 @@ - self.text = text # Text widget we're rendering into. - self.tags = '' # Current block level text tags to apply. - self.chartags = '' # Current character level text tags. -- self.show = False # Exclude html page navigation. - self.hdrlink = False # Exclude html header links. - self.level = 0 # Track indentation level. - self.pre = False # Displaying preformatted text? -@@ -77,11 +76,7 @@ - if a == 'class': - class_ = v - s = '' -- if tag == 'section' and attrs == [('id', 'idle')]: -- self.show = True # Start main content. -- elif tag == 'div' and class_ == 'clearer': -- self.show = False # End main content. -- elif tag == 'p' and self.prevtag and not self.prevtag[0]: -+ if tag == 'p' and self.prevtag and not self.prevtag[0]: - # Begin a new block for

tags after a closed tag. - # Avoid extra lines, e.g. after

 tags.
-             lastline = self.text.get('end-1c linestart', 'end-1c')
-@@ -112,31 +107,27 @@
-             s = '\n'
-         elif tag == 'pre':
-             self.pre = True
--            if self.show:
--                self.text.insert('end', '\n\n')
-+            self.text.insert('end', '\n\n')
-             self.tags = 'preblock'
-         elif tag == 'a' and class_ == 'headerlink':
-             self.hdrlink = True
-         elif tag == 'h1':
-             self.tags = tag
-         elif tag in ['h2', 'h3']:
--            if self.show:
--                self.header = ''
--                self.text.insert('end', '\n\n')
-+            self.header = ''
-+            self.text.insert('end', '\n\n')
-             self.tags = tag
--        if self.show:
--            self.text.insert('end', s, (self.tags, self.chartags))
-+        self.text.insert('end', s, (self.tags, self.chartags))
-         self.prevtag = (True, tag)
- 
-     def handle_endtag(self, tag):
-         "Handle endtags in help.html."
-         if tag in ['h1', 'h2', 'h3']:
-             assert self.level == 0
--            if self.show:
--                indent = ('        ' if tag == 'h3' else
--                          '    ' if tag == 'h2' else
--                          '')
--                self.toc.append((indent+self.header, self.text.index('insert')))
-+            indent = ('        ' if tag == 'h3' else
-+                      '    ' if tag == 'h2' else
-+                      '')
-+            self.toc.append((indent+self.header, self.text.index('insert')))
-             self.tags = ''
-         elif tag in ['span', 'em']:
-             self.chartags = ''
-@@ -151,11 +142,13 @@
- 
-     def handle_data(self, data):
-         "Handle date segments in help.html."
--        if self.show and not self.hdrlink:
-+        if not self.hdrlink:
-             d = data if self.pre else data.replace('\n', ' ')
-             if self.tags == 'h1':
-                 try:
--                    self.hprefix = d[0:d.index(' ')]
-+                    self.hprefix = d[:d.index(' ')]
-+                    if not self.hprefix.isdigit():
-+                        self.hprefix = ''
-                 except ValueError:
-                     self.hprefix = ''
-             if self.tags in ['h1', 'h2', 'h3']:
-@@ -251,7 +244,7 @@
- 
- 
- def copy_strip():  # pragma: no cover
--    """Copy idle.html to idlelib/help.html, stripping trailing whitespace.
-+    """Copy the text part of idle.html to idlelib/help.html while stripping trailing whitespace.
- 
-     Files with trailing whitespace cannot be pushed to the git cpython
-     repository.  For 3.x (on Windows), help.html is generated, after
-@@ -263,7 +256,7 @@
- 
-     It can be worthwhile to occasionally generate help.html without
-     touching idle.rst.  Changes to the master version and to the doc
--    build system may result in changes that should not changed
-+    build system may result in changes that should not change
-     the displayed text, but might break HelpParser.
- 
-     As long as master and maintenance versions of idle.rst remain the
-@@ -276,10 +269,14 @@
-     src = join(abspath(dirname(dirname(dirname(__file__)))),
-             'Doc', 'build', 'html', 'library', 'idle.html')
-     dst = join(abspath(dirname(__file__)), 'help.html')
--    with open(src, 'rb') as inn,\
--         open(dst, 'wb') as out:
-+
-+    with open(src, 'r', encoding="utf-8") as inn, open(dst, 'w', encoding="utf-8") as out:
-+        copy = False
-         for line in inn:
--            out.write(line.rstrip() + b'\n')
-+            if '
' in line: copy = True -+ if '
' in line: break -+ if copy: out.write(line.strip() + '\n') -+ - print(f'{src} copied to {dst}') - - -diff --git a/Lib/idlelib/idle_test/test_configdialog.py b/Lib/idlelib/idle_test/test_configdialog.py -index 5099d093382..2773ed7ce61 100644 ---- a/Lib/idlelib/idle_test/test_configdialog.py -+++ b/Lib/idlelib/idle_test/test_configdialog.py -@@ -98,8 +98,8 @@ - dialog.buttons['Help'].invoke() - title, contents = view.kwds['title'], view.kwds['contents'] - self.assertEqual(title, 'Help for IDLE preferences') -- self.assertTrue(contents.startswith('When you click') and -- contents.endswith('a different name.\n')) -+ self.assertStartsWith(contents, 'When you click') -+ self.assertEndsWith(contents,'a different name.\n') - - - class FontPageTest(unittest.TestCase): -diff --git a/Lib/idlelib/idle_test/test_debugger.py b/Lib/idlelib/idle_test/test_debugger.py -index d1c9638dd5d..9ca3b332648 100644 ---- a/Lib/idlelib/idle_test/test_debugger.py -+++ b/Lib/idlelib/idle_test/test_debugger.py -@@ -256,7 +256,7 @@ - flist = None - master_window = self.root - sv = debugger.StackViewer(master_window, flist, gui) -- self.assertTrue(hasattr(sv, 'stack')) -+ self.assertHasAttr(sv, 'stack') - - def test_load_stack(self): - # Test the .load_stack() method against a fixed test stack. -diff --git a/Lib/idlelib/idle_test/test_grep.py b/Lib/idlelib/idle_test/test_grep.py -index a0b5b691718..d67dba76911 100644 ---- a/Lib/idlelib/idle_test/test_grep.py -+++ b/Lib/idlelib/idle_test/test_grep.py -@@ -143,7 +143,7 @@ - self.assertIn(pat, lines[0]) - self.assertIn('py: 1:', lines[1]) # line number 1 - self.assertIn('2', lines[3]) # hits found 2 -- self.assertTrue(lines[4].startswith('(Hint:')) -+ self.assertStartsWith(lines[4], '(Hint:') - - - class Default_commandTest(unittest.TestCase): -diff --git a/Lib/idlelib/idle_test/test_help.py b/Lib/idlelib/idle_test/test_help.py -index c528d4e77f8..ebb02b5c0d8 100644 ---- a/Lib/idlelib/idle_test/test_help.py -+++ b/Lib/idlelib/idle_test/test_help.py -@@ -29,7 +29,7 @@ - - def test_4text(self): - text = self.window.frame.text -- self.assertEqual(text.get('1.0', '1.end'), ' IDLE ') -+ self.assertEqual(text.get('1.0', '1.end'), ' IDLE — Python editor and shell ') - - - if __name__ == '__main__': -diff --git a/Lib/idlelib/idle_test/test_multicall.py b/Lib/idlelib/idle_test/test_multicall.py -index b3a3bfb88f9..67f28db6b08 100644 ---- a/Lib/idlelib/idle_test/test_multicall.py -+++ b/Lib/idlelib/idle_test/test_multicall.py -@@ -27,7 +27,7 @@ - def test_creator(self): - mc = self.mc - self.assertIs(multicall._multicall_dict[Text], mc) -- self.assertTrue(issubclass(mc, Text)) -+ self.assertIsSubclass(mc, Text) - mc2 = multicall.MultiCallCreator(Text) - self.assertIs(mc, mc2) - -diff --git a/Lib/idlelib/idle_test/test_query.py b/Lib/idlelib/idle_test/test_query.py -index bb12b2b0865..a6ef858a8c9 100644 ---- a/Lib/idlelib/idle_test/test_query.py -+++ b/Lib/idlelib/idle_test/test_query.py -@@ -134,10 +134,10 @@ - - def test_good_module_name(self): - dialog = self.Dummy_ModuleName('idlelib') -- self.assertTrue(dialog.entry_ok().endswith('__init__.py')) -+ self.assertEndsWith(dialog.entry_ok(), '__init__.py') - self.assertEqual(dialog.entry_error['text'], '') - dialog = self.Dummy_ModuleName('idlelib.idle') -- self.assertTrue(dialog.entry_ok().endswith('idle.py')) -+ self.assertEndsWith(dialog.entry_ok(), 'idle.py') - self.assertEqual(dialog.entry_error['text'], '') - - -@@ -389,7 +389,7 @@ - self.assertEqual(dialog.text0, 'idlelib') - self.assertEqual(dialog.entry.get(), 'idlelib') - dialog.button_ok.invoke() -- self.assertTrue(dialog.result.endswith('__init__.py')) -+ self.assertEndsWith(dialog.result, '__init__.py') - root.destroy() - - -diff --git a/Lib/idlelib/idle_test/test_redirector.py b/Lib/idlelib/idle_test/test_redirector.py -index a97b3002afc..bd486d7da66 100644 ---- a/Lib/idlelib/idle_test/test_redirector.py -+++ b/Lib/idlelib/idle_test/test_redirector.py -@@ -34,7 +34,7 @@ - redir.register('insert', Func) - redir.close() - self.assertEqual(redir._operations, {}) -- self.assertFalse(hasattr(self.text, 'widget')) -+ self.assertNotHasAttr(self.text, 'widget') - - - class WidgetRedirectorTest(unittest.TestCase): -diff --git a/Lib/idlelib/idle_test/test_sidebar.py b/Lib/idlelib/idle_test/test_sidebar.py -index 605e7a89257..4157a4b4dcd 100644 ---- a/Lib/idlelib/idle_test/test_sidebar.py -+++ b/Lib/idlelib/idle_test/test_sidebar.py -@@ -725,7 +725,7 @@ - - text.tag_add('sel', f'{first_line}.0', 'end-1c') - selected_text = text.get('sel.first', 'sel.last') -- self.assertTrue(selected_text.startswith('if True:\n')) -+ self.assertStartsWith(selected_text, 'if True:\n') - self.assertIn('\n1\n', selected_text) - - text.event_generate('<>') -@@ -749,7 +749,7 @@ - - text.tag_add('sel', f'{first_line}.3', 'end-1c') - selected_text = text.get('sel.first', 'sel.last') -- self.assertTrue(selected_text.startswith('True:\n')) -+ self.assertStartsWith(selected_text, 'True:\n') - - selected_lines_text = text.get('sel.first linestart', 'sel.last') - selected_lines = selected_lines_text.split('\n') -diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py -index e882c6cb3b8..295d06e4a5f 100755 ---- a/Lib/idlelib/pyshell.py -+++ b/Lib/idlelib/pyshell.py -@@ -424,7 +424,9 @@ - def spawn_subprocess(self): - if self.subprocess_arglist is None: - self.subprocess_arglist = self.build_subprocess_arglist() -- self.rpcsubproc = subprocess.Popen(self.subprocess_arglist) -+ # gh-127060: Disable traceback colors -+ env = dict(os.environ, TERM='dumb') -+ self.rpcsubproc = subprocess.Popen(self.subprocess_arglist, env=env) - - def build_subprocess_arglist(self): - assert (self.port!=0), ( -@@ -1131,8 +1133,7 @@ - def short_title(self): - return self.shell_title - -- COPYRIGHT = \ -- 'Type "help", "copyright", "credits" or "license()" for more information.' -+ SPLASHLINE = 'Enter "help" below or click "Help" above for more information.' - - def begin(self): - self.text.mark_set("iomark", "insert") -@@ -1151,7 +1152,7 @@ - sys.displayhook = rpc.displayhook - - self.write("Python %s on %s\n%s\n%s" % -- (sys.version, sys.platform, self.COPYRIGHT, nosub)) -+ (sys.version, sys.platform, self.SPLASHLINE, nosub)) - self.text.focus_force() - self.showprompt() - # User code should use separate default Tk root window -diff --git a/Lib/imaplib.py b/Lib/imaplib.py -index e576c29e67d..2c3925958d0 100644 ---- a/Lib/imaplib.py -+++ b/Lib/imaplib.py -@@ -19,8 +19,9 @@ - # GET/SETQUOTA contributed by Andreas Zeidler June 2002. - # PROXYAUTH contributed by Rick Holbert November 2002. - # GET/SETANNOTATION contributed by Tomas Lindroos June 2005. -+# IDLE contributed by Forest August 2024. - --__version__ = "2.58" -+__version__ = "2.59" - - import binascii, errno, random, re, socket, subprocess, sys, time, calendar - from datetime import datetime, timezone, timedelta -@@ -74,6 +75,7 @@ - 'GETANNOTATION':('AUTH', 'SELECTED'), - 'GETQUOTA': ('AUTH', 'SELECTED'), - 'GETQUOTAROOT': ('AUTH', 'SELECTED'), -+ 'IDLE': ('AUTH', 'SELECTED'), - 'MYRIGHTS': ('AUTH', 'SELECTED'), - 'LIST': ('AUTH', 'SELECTED'), - 'LOGIN': ('NONAUTH',), -@@ -184,6 +186,7 @@ - class error(Exception): pass # Logical errors - debug required - class abort(error): pass # Service errors - close and retry - class readonly(abort): pass # Mailbox status changed to READ-ONLY -+ class _responsetimeout(TimeoutError): pass # No response during IDLE - - def __init__(self, host='', port=IMAP4_PORT, timeout=None): - self.debug = Debug -@@ -192,10 +195,13 @@ - self.tagged_commands = {} # Tagged commands awaiting response - self.untagged_responses = {} # {typ: [data, ...], ...} - self.continuation_response = '' # Last continuation response -+ self._idle_responses = [] # Response queue for idle iteration -+ self._idle_capture = False # Whether to queue responses for idle - self.is_readonly = False # READ-ONLY desired state - self.tagnum = 0 - self._tls_established = False - self._mode_ascii() -+ self._readbuf = [] - - # Open socket to server. - -@@ -310,17 +316,97 @@ - self.host = host - self.port = port - self.sock = self._create_socket(timeout) -- self.file = self.sock.makefile('rb') -+ self._file = self.sock.makefile('rb') -+ -+ -+ @property -+ def file(self): -+ # The old 'file' attribute is no longer used now that we do our own -+ # read() and readline() buffering, with which it conflicts. -+ # As an undocumented interface, it should never have been accessed by -+ # external code, and therefore does not warrant deprecation. -+ # Nevertheless, we provide this property for now, to avoid suddenly -+ # breaking any code in the wild that might have been using it in a -+ # harmless way. -+ import warnings -+ warnings.warn( -+ 'IMAP4.file is unsupported, can cause errors, and may be removed.', -+ RuntimeWarning, -+ stacklevel=2) -+ return self._file - - - def read(self, size): - """Read 'size' bytes from remote.""" -- return self.file.read(size) -+ # We need buffered read() to continue working after socket timeouts, -+ # since we use them during IDLE. Unfortunately, the standard library's -+ # SocketIO implementation makes this impossible, by setting a permanent -+ # error condition instead of letting the caller decide how to handle a -+ # timeout. We therefore implement our own buffered read(). -+ # https://github.com/python/cpython/issues/51571 -+ # -+ # Reading in chunks instead of delegating to a single -+ # BufferedReader.read() call also means we avoid its preallocation -+ # of an unreasonably large memory block if a malicious server claims -+ # it will send a huge literal without actually sending one. -+ # https://github.com/python/cpython/issues/119511 -+ -+ parts = [] -+ -+ while size > 0: -+ -+ if len(parts) < len(self._readbuf): -+ buf = self._readbuf[len(parts)] -+ else: -+ try: -+ buf = self.sock.recv(DEFAULT_BUFFER_SIZE) -+ except ConnectionError: -+ break -+ if not buf: -+ break -+ self._readbuf.append(buf) -+ -+ if len(buf) >= size: -+ parts.append(buf[:size]) -+ self._readbuf = [buf[size:]] + self._readbuf[len(parts):] -+ break -+ parts.append(buf) -+ size -= len(buf) -+ -+ return b''.join(parts) - - - def readline(self): - """Read line from remote.""" -- line = self.file.readline(_MAXLINE + 1) -+ # The comment in read() explains why we implement our own readline(). -+ -+ LF = b'\n' -+ parts = [] -+ length = 0 -+ -+ while length < _MAXLINE: -+ -+ if len(parts) < len(self._readbuf): -+ buf = self._readbuf[len(parts)] -+ else: -+ try: -+ buf = self.sock.recv(DEFAULT_BUFFER_SIZE) -+ except ConnectionError: -+ break -+ if not buf: -+ break -+ self._readbuf.append(buf) -+ -+ pos = buf.find(LF) -+ if pos != -1: -+ pos += 1 -+ parts.append(buf[:pos]) -+ self._readbuf = [buf[pos:]] + self._readbuf[len(parts):] -+ break -+ parts.append(buf) -+ length += len(buf) -+ -+ line = b''.join(parts) - if len(line) > _MAXLINE: - raise self.error("got more than %d bytes" % _MAXLINE) - return line -@@ -334,7 +420,7 @@ - - def shutdown(self): - """Close I/O established in "open".""" -- self.file.close() -+ self._file.close() - try: - self.sock.shutdown(socket.SHUT_RDWR) - except OSError as exc: -@@ -588,6 +674,19 @@ - return typ, [quotaroot, quota] - - -+ def idle(self, duration=None): -+ """Return an iterable IDLE context manager producing untagged responses. -+ If the argument is not None, limit iteration to 'duration' seconds. -+ -+ with M.idle(duration=29 * 60) as idler: -+ for typ, data in idler: -+ print(typ, data) -+ -+ Note: 'duration' requires a socket connection (not IMAP4_stream). -+ """ -+ return Idler(self, duration) -+ -+ - def list(self, directory='""', pattern='*'): - """List mailbox names in directory matching pattern. - -@@ -821,7 +920,7 @@ - if typ == 'OK': - self.sock = ssl_context.wrap_socket(self.sock, - server_hostname=self.host) -- self.file = self.sock.makefile('rb') -+ self._file = self.sock.makefile('rb') - self._tls_established = True - self._get_capabilities() - else: -@@ -944,6 +1043,24 @@ - def _append_untagged(self, typ, dat): - if dat is None: - dat = b'' -+ -+ # During idle, queue untagged responses for delivery via iteration -+ if self._idle_capture: -+ # Responses containing literal strings are passed to us one data -+ # fragment at a time, while others arrive in a single call. -+ if (not self._idle_responses or -+ isinstance(self._idle_responses[-1][1][-1], bytes)): -+ # We are not continuing a fragmented response; start a new one -+ self._idle_responses.append((typ, [dat])) -+ else: -+ # We are continuing a fragmented response; append the fragment -+ response = self._idle_responses[-1] -+ assert response[0] == typ -+ response[1].append(dat) -+ if __debug__ and self.debug >= 5: -+ self._mesg(f'idle: queue untagged {typ} {dat!r}') -+ return -+ - ur = self.untagged_responses - if __debug__: - if self.debug >= 5: -@@ -1065,14 +1182,29 @@ - self.capabilities = tuple(dat.split()) - - -- def _get_response(self): -+ def _get_response(self, start_timeout=False): - - # Read response and store. - # - # Returns None for continuation responses, - # otherwise first response line received. -- -- resp = self._get_line() -+ # -+ # If start_timeout is given, temporarily uses it as a socket -+ # timeout while waiting for the start of a response, raising -+ # _responsetimeout if one doesn't arrive. (Used by Idler.) -+ -+ if start_timeout is not False and self.sock: -+ assert start_timeout is None or start_timeout > 0 -+ saved_timeout = self.sock.gettimeout() -+ self.sock.settimeout(start_timeout) -+ try: -+ resp = self._get_line() -+ except TimeoutError as err: -+ raise self._responsetimeout from err -+ finally: -+ self.sock.settimeout(saved_timeout) -+ else: -+ resp = self._get_line() - - # Command completion response? - -@@ -1279,6 +1411,199 @@ - n -= 1 - - -+class Idler: -+ """Iterable IDLE context manager: start IDLE & produce untagged responses. -+ -+ An object of this type is returned by the IMAP4.idle() method. -+ -+ Note: The name and structure of this class are subject to change. -+ """ -+ -+ def __init__(self, imap, duration=None): -+ if 'IDLE' not in imap.capabilities: -+ raise imap.error("Server does not support IMAP4 IDLE") -+ if duration is not None and not imap.sock: -+ # IMAP4_stream pipes don't support timeouts -+ raise imap.error('duration requires a socket connection') -+ self._duration = duration -+ self._deadline = None -+ self._imap = imap -+ self._tag = None -+ self._saved_state = None -+ -+ def __enter__(self): -+ imap = self._imap -+ assert not imap._idle_responses -+ assert not imap._idle_capture -+ -+ if __debug__ and imap.debug >= 4: -+ imap._mesg(f'idle start duration={self._duration}') -+ -+ # Start capturing untagged responses before sending IDLE, -+ # so we can deliver via iteration any that arrive while -+ # the IDLE command continuation request is still pending. -+ imap._idle_capture = True -+ -+ try: -+ self._tag = imap._command('IDLE') -+ # As with any command, the server is allowed to send us unrelated, -+ # untagged responses before acting on IDLE. These lines will be -+ # returned by _get_response(). When the server is ready, it will -+ # send an IDLE continuation request, indicated by _get_response() -+ # returning None. We therefore process responses in a loop until -+ # this occurs. -+ while resp := imap._get_response(): -+ if imap.tagged_commands[self._tag]: -+ typ, data = imap.tagged_commands.pop(self._tag) -+ if typ == 'NO': -+ raise imap.error(f'idle denied: {data}') -+ raise imap.abort(f'unexpected status response: {resp}') -+ -+ if __debug__ and imap.debug >= 4: -+ prompt = imap.continuation_response -+ imap._mesg(f'idle continuation prompt: {prompt}') -+ except BaseException: -+ imap._idle_capture = False -+ raise -+ -+ if self._duration is not None: -+ self._deadline = time.monotonic() + self._duration -+ -+ self._saved_state = imap.state -+ imap.state = 'IDLING' -+ -+ return self -+ -+ def __exit__(self, exc_type, exc_val, exc_tb): -+ imap = self._imap -+ -+ if __debug__ and imap.debug >= 4: -+ imap._mesg('idle done') -+ imap.state = self._saved_state -+ -+ # Stop intercepting untagged responses before sending DONE, -+ # since we can no longer deliver them via iteration. -+ imap._idle_capture = False -+ -+ # If we captured untagged responses while the IDLE command -+ # continuation request was still pending, but the user did not -+ # iterate over them before exiting IDLE, we must put them -+ # someplace where the user can retrieve them. The only -+ # sensible place for this is the untagged_responses dict, -+ # despite its unfortunate inability to preserve the relative -+ # order of different response types. -+ if leftovers := len(imap._idle_responses): -+ if __debug__ and imap.debug >= 4: -+ imap._mesg(f'idle quit with {leftovers} leftover responses') -+ while imap._idle_responses: -+ typ, data = imap._idle_responses.pop(0) -+ # Append one fragment at a time, just as _get_response() does -+ for datum in data: -+ imap._append_untagged(typ, datum) -+ -+ try: -+ imap.send(b'DONE' + CRLF) -+ status, [msg] = imap._command_complete('IDLE', self._tag) -+ if __debug__ and imap.debug >= 4: -+ imap._mesg(f'idle status: {status} {msg!r}') -+ except OSError: -+ if not exc_type: -+ raise -+ -+ return False # Do not suppress context body exceptions -+ -+ def __iter__(self): -+ return self -+ -+ def _pop(self, timeout, default=('', None)): -+ # Get the next response, or a default value on timeout. -+ # The timeout arg can be an int or float, or None for no timeout. -+ # Timeouts require a socket connection (not IMAP4_stream). -+ # This method ignores self._duration. -+ -+ # Historical Note: -+ # The timeout was originally implemented using select() after -+ # checking for the presence of already-buffered data. -+ # That allowed timeouts on pipe connetions like IMAP4_stream. -+ # However, it seemed possible that SSL data arriving without any -+ # IMAP data afterward could cause select() to indicate available -+ # application data when there was none, leading to a read() call -+ # that would block with no timeout. It was unclear under what -+ # conditions this would happen in practice. Our implementation was -+ # changed to use socket timeouts instead of select(), just to be -+ # safe. -+ -+ imap = self._imap -+ if imap.state != 'IDLING': -+ raise imap.error('_pop() only works during IDLE') -+ -+ if imap._idle_responses: -+ # Response is ready to return to the user -+ resp = imap._idle_responses.pop(0) -+ if __debug__ and imap.debug >= 4: -+ imap._mesg(f'idle _pop({timeout}) de-queued {resp[0]}') -+ return resp -+ -+ if __debug__ and imap.debug >= 4: -+ imap._mesg(f'idle _pop({timeout}) reading') -+ -+ if timeout is not None: -+ if timeout <= 0: -+ return default -+ timeout = float(timeout) # Required by socket.settimeout() -+ -+ try: -+ imap._get_response(timeout) # Reads line, calls _append_untagged() -+ except IMAP4._responsetimeout: -+ if __debug__ and imap.debug >= 4: -+ imap._mesg(f'idle _pop({timeout}) done') -+ return default -+ -+ resp = imap._idle_responses.pop(0) -+ -+ if __debug__ and imap.debug >= 4: -+ imap._mesg(f'idle _pop({timeout}) read {resp[0]}') -+ return resp -+ -+ def __next__(self): -+ imap = self._imap -+ -+ if self._duration is None: -+ timeout = None -+ else: -+ timeout = self._deadline - time.monotonic() -+ typ, data = self._pop(timeout) -+ -+ if not typ: -+ if __debug__ and imap.debug >= 4: -+ imap._mesg('idle iterator exhausted') -+ raise StopIteration -+ -+ return typ, data -+ -+ def burst(self, interval=0.1): -+ """Yield a burst of responses no more than 'interval' seconds apart. -+ -+ with M.idle() as idler: -+ # get a response and any others following by < 0.1 seconds -+ batch = list(idler.burst()) -+ print(f'processing {len(batch)} responses...') -+ print(batch) -+ -+ Note: This generator requires a socket connection (not IMAP4_stream). -+ """ -+ if not self._imap.sock: -+ raise self._imap.error('burst() requires a socket connection') -+ -+ try: -+ yield next(self) -+ except StopIteration: -+ return -+ -+ while response := self._pop(interval, None): -+ yield response -+ -+ - if HAVE_SSL: - - class IMAP4_SSL(IMAP4): -@@ -1346,7 +1671,7 @@ - self.host = None # For compatibility with parent class - self.port = None - self.sock = None -- self.file = None -+ self._file = None - self.process = subprocess.Popen(self.command, - bufsize=DEFAULT_BUFFER_SIZE, - stdin=subprocess.PIPE, stdout=subprocess.PIPE, -diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py -index fa361597118..8bcd741c446 100644 ---- a/Lib/importlib/_bootstrap_external.py -+++ b/Lib/importlib/_bootstrap_external.py -@@ -716,6 +716,12 @@ - - @classmethod - def find_spec(cls, fullname, path=None, target=None): -+ _warnings.warn('importlib.machinery.WindowsRegistryFinder is ' -+ 'deprecated; use site configuration instead. ' -+ 'Future versions of Python may not enable this ' -+ 'finder by default.', -+ DeprecationWarning, stacklevel=2) -+ - filepath = cls._search_registry(fullname) - if filepath is None: - return None -@@ -1238,7 +1244,7 @@ - if path == '': - try: - path = _os.getcwd() -- except FileNotFoundError: -+ except (FileNotFoundError, PermissionError): - # Don't cache the failure as the cwd can easily change to - # a valid directory later on. - return None -diff --git a/Lib/importlib/abc.py b/Lib/importlib/abc.py -index eea6b38af6f..29f01f77eff 100644 ---- a/Lib/importlib/abc.py -+++ b/Lib/importlib/abc.py -@@ -70,6 +70,15 @@ - - """ - -+ def __init__(self): -+ import warnings -+ warnings.warn('importlib.abc.ResourceLoader is deprecated in ' -+ 'favour of supporting resource loading through ' -+ 'importlib.resources.abc.TraversableResources.', -+ DeprecationWarning, stacklevel=2) -+ super().__init__() -+ -+ - @abc.abstractmethod - def get_data(self, path): - """Abstract method which when implemented should return the bytes for -@@ -199,6 +208,10 @@ - - def path_mtime(self, path): - """Return the (int) modification time for the path (str).""" -+ import warnings -+ warnings.warn('SourceLoader.path_mtime is deprecated in favour of ' -+ 'SourceLoader.path_stats().', -+ DeprecationWarning, stacklevel=2) - if self.path_stats.__func__ is SourceLoader.path_stats: - raise OSError - return int(self.path_stats(path)['mtime']) -diff --git a/Lib/importlib/machinery.py b/Lib/importlib/machinery.py -index 6e294d59bfd..63d726445c3 100644 ---- a/Lib/importlib/machinery.py -+++ b/Lib/importlib/machinery.py -@@ -3,9 +3,11 @@ - from ._bootstrap import ModuleSpec - from ._bootstrap import BuiltinImporter - from ._bootstrap import FrozenImporter --from ._bootstrap_external import (SOURCE_SUFFIXES, DEBUG_BYTECODE_SUFFIXES, -- OPTIMIZED_BYTECODE_SUFFIXES, BYTECODE_SUFFIXES, -- EXTENSION_SUFFIXES) -+from ._bootstrap_external import ( -+ SOURCE_SUFFIXES, BYTECODE_SUFFIXES, EXTENSION_SUFFIXES, -+ DEBUG_BYTECODE_SUFFIXES as _DEBUG_BYTECODE_SUFFIXES, -+ OPTIMIZED_BYTECODE_SUFFIXES as _OPTIMIZED_BYTECODE_SUFFIXES -+) - from ._bootstrap_external import WindowsRegistryFinder - from ._bootstrap_external import PathFinder - from ._bootstrap_external import FileFinder -@@ -27,3 +29,22 @@ - 'NamespaceLoader', 'OPTIMIZED_BYTECODE_SUFFIXES', 'PathFinder', - 'SOURCE_SUFFIXES', 'SourceFileLoader', 'SourcelessFileLoader', - 'WindowsRegistryFinder', 'all_suffixes'] -+ -+ -+def __getattr__(name): -+ import warnings -+ -+ if name == 'DEBUG_BYTECODE_SUFFIXES': -+ warnings.warn('importlib.machinery.DEBUG_BYTECODE_SUFFIXES is ' -+ 'deprecated; use importlib.machinery.BYTECODE_SUFFIXES ' -+ 'instead.', -+ DeprecationWarning, stacklevel=2) -+ return _DEBUG_BYTECODE_SUFFIXES -+ elif name == 'OPTIMIZED_BYTECODE_SUFFIXES': -+ warnings.warn('importlib.machinery.OPTIMIZED_BYTECODE_SUFFIXES is ' -+ 'deprecated; use importlib.machinery.BYTECODE_SUFFIXES ' -+ 'instead.', -+ DeprecationWarning, stacklevel=2) -+ return _OPTIMIZED_BYTECODE_SUFFIXES -+ -+ raise AttributeError(f'module {__name__!r} has no attribute {name!r}') -diff --git a/Lib/importlib/resources/__init__.py b/Lib/importlib/resources/__init__.py -index ec4441c9116..723c9f9eb33 100644 ---- a/Lib/importlib/resources/__init__.py -+++ b/Lib/importlib/resources/__init__.py -@@ -1,4 +1,11 @@ --"""Read resources contained within a package.""" -+""" -+Read resources contained within a package. -+ -+This codebase is shared between importlib.resources in the stdlib -+and importlib_resources in PyPI. See -+https://github.com/python/importlib_metadata/wiki/Development-Methodology -+for more detail. -+""" - - from ._common import ( - as_file, -diff --git a/Lib/importlib/resources/_common.py b/Lib/importlib/resources/_common.py -index c2c92254370..4e9014c45a0 100644 ---- a/Lib/importlib/resources/_common.py -+++ b/Lib/importlib/resources/_common.py -@@ -66,10 +66,10 @@ - # zipimport.zipimporter does not support weak references, resulting in a - # TypeError. That seems terrible. - spec = package.__spec__ -- reader = getattr(spec.loader, 'get_resource_reader', None) # type: ignore -+ reader = getattr(spec.loader, 'get_resource_reader', None) # type: ignore[union-attr] - if reader is None: - return None -- return reader(spec.name) # type: ignore -+ return reader(spec.name) # type: ignore[union-attr] - - - @functools.singledispatch -diff --git a/Lib/importlib/resources/readers.py b/Lib/importlib/resources/readers.py -index ccc5abbeb4e..70fc7e2b9c0 100644 ---- a/Lib/importlib/resources/readers.py -+++ b/Lib/importlib/resources/readers.py -@@ -1,3 +1,5 @@ -+from __future__ import annotations -+ - import collections - import contextlib - import itertools -@@ -6,6 +8,7 @@ - import re - import warnings - import zipfile -+from collections.abc import Iterator - - from . import abc - -@@ -135,27 +138,31 @@ - def __init__(self, namespace_path): - if 'NamespacePath' not in str(namespace_path): - raise ValueError('Invalid path') -- self.path = MultiplexedPath(*map(self._resolve, namespace_path)) -+ self.path = MultiplexedPath(*filter(bool, map(self._resolve, namespace_path))) - - @classmethod -- def _resolve(cls, path_str) -> abc.Traversable: -+ def _resolve(cls, path_str) -> abc.Traversable | None: - r""" - Given an item from a namespace path, resolve it to a Traversable. - - path_str might be a directory on the filesystem or a path to a - zipfile plus the path within the zipfile, e.g. ``/foo/bar`` or - ``/foo/baz.zip/inner_dir`` or ``foo\baz.zip\inner_dir\sub``. -+ -+ path_str might also be a sentinel used by editable packages to -+ trigger other behaviors (see python/importlib_resources#311). -+ In that case, return None. - """ -- (dir,) = (cand for cand in cls._candidate_paths(path_str) if cand.is_dir()) -- return dir -+ dirs = (cand for cand in cls._candidate_paths(path_str) if cand.is_dir()) -+ return next(dirs, None) - - @classmethod -- def _candidate_paths(cls, path_str): -+ def _candidate_paths(cls, path_str: str) -> Iterator[abc.Traversable]: - yield pathlib.Path(path_str) - yield from cls._resolve_zip_path(path_str) - - @staticmethod -- def _resolve_zip_path(path_str): -+ def _resolve_zip_path(path_str: str): - for match in reversed(list(re.finditer(r'[\\/]', path_str))): - with contextlib.suppress( - FileNotFoundError, -diff --git a/Lib/importlib/resources/simple.py b/Lib/importlib/resources/simple.py -index 96f117fec62..2e75299b13a 100644 ---- a/Lib/importlib/resources/simple.py -+++ b/Lib/importlib/resources/simple.py -@@ -77,7 +77,7 @@ - - def __init__(self, parent: ResourceContainer, name: str): - self.parent = parent -- self.name = name # type: ignore -+ self.name = name # type: ignore[misc] - - def is_file(self): - return True -diff --git a/Lib/inspect.py b/Lib/inspect.py -index b7d8271f8a4..facad478103 100644 ---- a/Lib/inspect.py -+++ b/Lib/inspect.py -@@ -57,6 +57,7 @@ - "CO_VARARGS", - "CO_VARKEYWORDS", - "CO_HAS_DOCSTRING", -+ "CO_METHOD", - "ClassFoundException", - "ClosureVars", - "EndOfBlock", -@@ -857,8 +858,7 @@ - Return None if no way can be identified to get the source. - """ - filename = getfile(object) -- all_bytecode_suffixes = importlib.machinery.DEBUG_BYTECODE_SUFFIXES[:] -- all_bytecode_suffixes += importlib.machinery.OPTIMIZED_BYTECODE_SUFFIXES[:] -+ all_bytecode_suffixes = importlib.machinery.BYTECODE_SUFFIXES[:] - if any(filename.endswith(s) for s in all_bytecode_suffixes): - filename = (os.path.splitext(filename)[0] + - importlib.machinery.SOURCE_SUFFIXES[0]) -diff --git a/Lib/locale.py b/Lib/locale.py -index d8c09f1123d..213d5e93418 100644 ---- a/Lib/locale.py -+++ b/Lib/locale.py -@@ -860,6 +860,24 @@ - # updated 'ca_es@valencia' -> 'ca_ES.ISO8859-15@valencia' to 'ca_ES.UTF-8@valencia' - # updated 'kk_kz' -> 'kk_KZ.RK1048' to 'kk_KZ.ptcp154' - # updated 'russian' -> 'ru_RU.ISO8859-5' to 'ru_RU.KOI8-R' -+# -+# SS 2025-02-04: -+# Updated alias mapping with glibc 2.41 supported locales and the latest -+# X lib alias mapping. -+# -+# These are the differences compared to the old mapping (Python 3.13.1 -+# and older): -+# -+# updated 'c.utf8' -> 'C.UTF-8' to 'en_US.UTF-8' -+# updated 'de_it' -> 'de_IT.ISO8859-1' to 'de_IT.UTF-8' -+# removed 'de_li.utf8' -+# updated 'en_il' -> 'en_IL.UTF-8' to 'en_IL.ISO8859-1' -+# removed 'english.iso88591' -+# updated 'es_cu' -> 'es_CU.UTF-8' to 'es_CU.ISO8859-1' -+# updated 'russian' -> 'ru_RU.KOI8-R' to 'ru_RU.ISO8859-5' -+# updated 'sr@latn' -> 'sr_CS.UTF-8@latin' to 'sr_RS.UTF-8@latin' -+# removed 'univ' -+# removed 'universal' - - locale_alias = { - 'a3': 'az_AZ.KOI8-C', -@@ -939,7 +957,7 @@ - 'c.ascii': 'C', - 'c.en': 'C', - 'c.iso88591': 'en_US.ISO8859-1', -- 'c.utf8': 'C.UTF-8', -+ 'c.utf8': 'en_US.UTF-8', - 'c_c': 'C', - 'c_c.c': 'C', - 'ca': 'ca_ES.ISO8859-1', -@@ -956,6 +974,7 @@ - 'chr_us': 'chr_US.UTF-8', - 'ckb_iq': 'ckb_IQ.UTF-8', - 'cmn_tw': 'cmn_TW.UTF-8', -+ 'crh_ru': 'crh_RU.UTF-8', - 'crh_ua': 'crh_UA.UTF-8', - 'croatian': 'hr_HR.ISO8859-2', - 'cs': 'cs_CZ.ISO8859-2', -@@ -977,11 +996,12 @@ - 'de_be': 'de_BE.ISO8859-1', - 'de_ch': 'de_CH.ISO8859-1', - 'de_de': 'de_DE.ISO8859-1', -- 'de_it': 'de_IT.ISO8859-1', -- 'de_li.utf8': 'de_LI.UTF-8', -+ 'de_it': 'de_IT.UTF-8', -+ 'de_li': 'de_LI.ISO8859-1', - 'de_lu': 'de_LU.ISO8859-1', - 'deutsch': 'de_DE.ISO8859-1', - 'doi_in': 'doi_IN.UTF-8', -+ 'dsb_de': 'dsb_DE.UTF-8', - 'dutch': 'nl_NL.ISO8859-1', - 'dutch.iso88591': 'nl_BE.ISO8859-1', - 'dv_mv': 'dv_MV.UTF-8', -@@ -1004,7 +1024,7 @@ - 'en_gb': 'en_GB.ISO8859-1', - 'en_hk': 'en_HK.ISO8859-1', - 'en_ie': 'en_IE.ISO8859-1', -- 'en_il': 'en_IL.UTF-8', -+ 'en_il': 'en_IL.ISO8859-1', - 'en_in': 'en_IN.ISO8859-1', - 'en_ng': 'en_NG.UTF-8', - 'en_nz': 'en_NZ.ISO8859-1', -@@ -1020,7 +1040,6 @@ - 'en_zw.utf8': 'en_ZS.UTF-8', - 'eng_gb': 'en_GB.ISO8859-1', - 'english': 'en_EN.ISO8859-1', -- 'english.iso88591': 'en_US.ISO8859-1', - 'english_uk': 'en_GB.ISO8859-1', - 'english_united-states': 'en_US.ISO8859-1', - 'english_united-states.437': 'C', -@@ -1036,7 +1055,7 @@ - 'es_cl': 'es_CL.ISO8859-1', - 'es_co': 'es_CO.ISO8859-1', - 'es_cr': 'es_CR.ISO8859-1', -- 'es_cu': 'es_CU.UTF-8', -+ 'es_cu': 'es_CU.ISO8859-1', - 'es_do': 'es_DO.ISO8859-1', - 'es_ec': 'es_EC.ISO8859-1', - 'es_es': 'es_ES.ISO8859-1', -@@ -1086,6 +1105,7 @@ - 'ga_ie': 'ga_IE.ISO8859-1', - 'galego': 'gl_ES.ISO8859-1', - 'galician': 'gl_ES.ISO8859-1', -+ 'gbm_in': 'gbm_IN.UTF-8', - 'gd': 'gd_GB.ISO8859-1', - 'gd_gb': 'gd_GB.ISO8859-1', - 'ger_de': 'de_DE.ISO8859-1', -@@ -1126,6 +1146,7 @@ - 'icelandic': 'is_IS.ISO8859-1', - 'id': 'id_ID.ISO8859-1', - 'id_id': 'id_ID.ISO8859-1', -+ 'ie': 'ie.UTF-8', - 'ig_ng': 'ig_NG.UTF-8', - 'ik_ca': 'ik_CA.UTF-8', - 'in': 'id_ID.ISO8859-1', -@@ -1180,6 +1201,7 @@ - 'ks_in': 'ks_IN.UTF-8', - 'ks_in@devanagari.utf8': 'ks_IN.UTF-8@devanagari', - 'ku_tr': 'ku_TR.ISO8859-9', -+ 'kv_ru': 'kv_RU.UTF-8', - 'kw': 'kw_GB.ISO8859-1', - 'kw_gb': 'kw_GB.ISO8859-1', - 'ky': 'ky_KG.UTF-8', -@@ -1198,6 +1220,7 @@ - 'lo_la.mulelao1': 'lo_LA.MULELAO-1', - 'lt': 'lt_LT.ISO8859-13', - 'lt_lt': 'lt_LT.ISO8859-13', -+ 'ltg_lv.utf8': 'ltg_LV.UTF-8', - 'lv': 'lv_LV.ISO8859-13', - 'lv_lv': 'lv_LV.ISO8859-13', - 'lzh_tw': 'lzh_TW.UTF-8', -@@ -1205,6 +1228,7 @@ - 'mai': 'mai_IN.UTF-8', - 'mai_in': 'mai_IN.UTF-8', - 'mai_np': 'mai_NP.UTF-8', -+ 'mdf_ru': 'mdf_RU.UTF-8', - 'mfe_mu': 'mfe_MU.UTF-8', - 'mg_mg': 'mg_MG.ISO8859-15', - 'mhr_ru': 'mhr_RU.UTF-8', -@@ -1218,6 +1242,7 @@ - 'ml_in': 'ml_IN.UTF-8', - 'mn_mn': 'mn_MN.UTF-8', - 'mni_in': 'mni_IN.UTF-8', -+ 'mnw_mm': 'mnw_MM.UTF-8', - 'mr': 'mr_IN.UTF-8', - 'mr_in': 'mr_IN.UTF-8', - 'ms': 'ms_MY.ISO8859-1', -@@ -1286,6 +1311,7 @@ - 'pt_pt': 'pt_PT.ISO8859-1', - 'quz_pe': 'quz_PE.UTF-8', - 'raj_in': 'raj_IN.UTF-8', -+ 'rif_ma': 'rif_MA.UTF-8', - 'ro': 'ro_RO.ISO8859-2', - 'ro_ro': 'ro_RO.ISO8859-2', - 'romanian': 'ro_RO.ISO8859-2', -@@ -1293,12 +1319,14 @@ - 'ru_ru': 'ru_RU.UTF-8', - 'ru_ua': 'ru_UA.KOI8-U', - 'rumanian': 'ro_RO.ISO8859-2', -- 'russian': 'ru_RU.KOI8-R', -+ 'russian': 'ru_RU.ISO8859-5', - 'rw': 'rw_RW.ISO8859-1', - 'rw_rw': 'rw_RW.ISO8859-1', - 'sa_in': 'sa_IN.UTF-8', -+ 'sah_ru': 'sah_RU.UTF-8', - 'sat_in': 'sat_IN.UTF-8', - 'sc_it': 'sc_IT.UTF-8', -+ 'scn_it': 'scn_IT.UTF-8', - 'sd': 'sd_IN.UTF-8', - 'sd_in': 'sd_IN.UTF-8', - 'sd_in@devanagari.utf8': 'sd_IN.UTF-8@devanagari', -@@ -1340,7 +1368,7 @@ - 'sq_mk': 'sq_MK.UTF-8', - 'sr': 'sr_RS.UTF-8', - 'sr@cyrillic': 'sr_RS.UTF-8', -- 'sr@latn': 'sr_CS.UTF-8@latin', -+ 'sr@latn': 'sr_RS.UTF-8@latin', - 'sr_cs': 'sr_CS.UTF-8', - 'sr_cs.iso88592@latn': 'sr_CS.ISO8859-2', - 'sr_cs@latn': 'sr_CS.UTF-8@latin', -@@ -1359,14 +1387,17 @@ - 'sr_yu@cyrillic': 'sr_RS.UTF-8', - 'ss': 'ss_ZA.ISO8859-1', - 'ss_za': 'ss_ZA.ISO8859-1', -+ 'ssy_er': 'ssy_ER.UTF-8', - 'st': 'st_ZA.ISO8859-1', - 'st_za': 'st_ZA.ISO8859-1', -+ 'su_id': 'su_ID.UTF-8', - 'sv': 'sv_SE.ISO8859-1', - 'sv_fi': 'sv_FI.ISO8859-1', - 'sv_se': 'sv_SE.ISO8859-1', - 'sw_ke': 'sw_KE.UTF-8', - 'sw_tz': 'sw_TZ.UTF-8', - 'swedish': 'sv_SE.ISO8859-1', -+ 'syr': 'syr.UTF-8', - 'szl_pl': 'szl_PL.UTF-8', - 'ta': 'ta_IN.TSCII-0', - 'ta_in': 'ta_IN.TSCII-0', -@@ -1393,6 +1424,7 @@ - 'tn': 'tn_ZA.ISO8859-15', - 'tn_za': 'tn_ZA.ISO8859-15', - 'to_to': 'to_TO.UTF-8', -+ 'tok': 'tok.UTF-8', - 'tpi_pg': 'tpi_PG.UTF-8', - 'tr': 'tr_TR.ISO8859-9', - 'tr_cy': 'tr_CY.ISO8859-9', -@@ -1407,8 +1439,7 @@ - 'ug_cn': 'ug_CN.UTF-8', - 'uk': 'uk_UA.KOI8-U', - 'uk_ua': 'uk_UA.KOI8-U', -- 'univ': 'en_US.utf', -- 'universal': 'en_US.utf', -+ 'univ.utf8': 'en_US.UTF-8', - 'universal.utf8@ucs4': 'en_US.UTF-8', - 'unm_us': 'unm_US.UTF-8', - 'ur': 'ur_PK.CP1256', -@@ -1437,6 +1468,7 @@ - 'yo_ng': 'yo_NG.UTF-8', - 'yue_hk': 'yue_HK.UTF-8', - 'yuw_pg': 'yuw_PG.UTF-8', -+ 'zgh_ma': 'zgh_MA.UTF-8', - 'zh': 'zh_CN.eucCN', - 'zh_cn': 'zh_CN.gb2312', - 'zh_cn.big5': 'zh_TW.big5', -diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py -index 1cba64fd554..9abadbf5cdd 100644 ---- a/Lib/logging/handlers.py -+++ b/Lib/logging/handlers.py -@@ -855,7 +855,7 @@ - } - - def __init__(self, address=('localhost', SYSLOG_UDP_PORT), -- facility=LOG_USER, socktype=None): -+ facility=LOG_USER, socktype=None, timeout=None): - """ - Initialize a handler. - -@@ -872,6 +872,7 @@ - self.address = address - self.facility = facility - self.socktype = socktype -+ self.timeout = timeout - self.socket = None - self.createSocket() - -@@ -933,6 +934,8 @@ - err = sock = None - try: - sock = socket.socket(af, socktype, proto) -+ if self.timeout: -+ sock.settimeout(self.timeout) - if socktype == socket.SOCK_STREAM: - sock.connect(sa) - break -@@ -1040,7 +1043,8 @@ - only be used when authentication credentials are supplied. The tuple - will be either an empty tuple, or a single-value tuple with the name - of a keyfile, or a 2-value tuple with the names of the keyfile and -- certificate file. (This tuple is passed to the `starttls` method). -+ certificate file. (This tuple is passed to the -+ `ssl.SSLContext.load_cert_chain` method). - A timeout in seconds can be specified for the SMTP connection (the - default is one second). - """ -@@ -1093,8 +1097,23 @@ - msg.set_content(self.format(record)) - if self.username: - if self.secure is not None: -+ import ssl -+ -+ try: -+ keyfile = self.secure[0] -+ except IndexError: -+ keyfile = None -+ -+ try: -+ certfile = self.secure[1] -+ except IndexError: -+ certfile = None -+ -+ context = ssl._create_stdlib_context( -+ certfile=certfile, keyfile=keyfile -+ ) - smtp.ehlo() -- smtp.starttls(*self.secure) -+ smtp.starttls(context=context) - smtp.ehlo() - smtp.login(self.username, self.password) - smtp.send_message(msg) -diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py -index 710aba9685e..d429212d447 100644 ---- a/Lib/multiprocessing/connection.py -+++ b/Lib/multiprocessing/connection.py -@@ -853,7 +853,7 @@ - _LEGACY_LENGTHS = (_MD5ONLY_MESSAGE_LENGTH, _MD5_DIGEST_LEN) - - --def _get_digest_name_and_payload(message: bytes) -> (str, bytes): -+def _get_digest_name_and_payload(message): # type: (bytes) -> tuple[str, bytes] - """Returns a digest name and the payload for a response hash. - - If a legacy protocol is detected based on the message length -diff --git a/Lib/multiprocessing/forkserver.py b/Lib/multiprocessing/forkserver.py -index df9b9be9d18..681af2610e9 100644 ---- a/Lib/multiprocessing/forkserver.py -+++ b/Lib/multiprocessing/forkserver.py -@@ -382,13 +382,14 @@ - # - - def read_signed(fd): -- data = b'' -- length = SIGNED_STRUCT.size -- while len(data) < length: -- s = os.read(fd, length - len(data)) -- if not s: -+ data = bytearray(SIGNED_STRUCT.size) -+ unread = memoryview(data) -+ while unread: -+ count = os.readinto(fd, unread) -+ if count == 0: - raise EOFError('unexpected EOF') -- data += s -+ unread = unread[count:] -+ - return SIGNED_STRUCT.unpack(data)[0] - - def write_signed(fd, n): -diff --git a/Lib/multiprocessing/resource_tracker.py b/Lib/multiprocessing/resource_tracker.py -index 20ddd9c50e3..90e036ae905 100644 ---- a/Lib/multiprocessing/resource_tracker.py -+++ b/Lib/multiprocessing/resource_tracker.py -@@ -155,13 +155,14 @@ - # that can make the child die before it registers signal handlers - # for SIGINT and SIGTERM. The mask is unregistered after spawning - # the child. -+ prev_sigmask = None - try: - if _HAVE_SIGMASK: -- signal.pthread_sigmask(signal.SIG_BLOCK, _IGNORED_SIGNALS) -+ prev_sigmask = signal.pthread_sigmask(signal.SIG_BLOCK, _IGNORED_SIGNALS) - pid = util.spawnv_passfds(exe, args, fds_to_pass) - finally: -- if _HAVE_SIGMASK: -- signal.pthread_sigmask(signal.SIG_UNBLOCK, _IGNORED_SIGNALS) -+ if prev_sigmask is not None: -+ signal.pthread_sigmask(signal.SIG_SETMASK, prev_sigmask) - except: - os.close(w) - raise -diff --git a/Lib/multiprocessing/synchronize.py b/Lib/multiprocessing/synchronize.py -index 4f72373c951..edd6c2543a7 100644 ---- a/Lib/multiprocessing/synchronize.py -+++ b/Lib/multiprocessing/synchronize.py -@@ -359,7 +359,7 @@ - return True - return False - -- def __repr__(self) -> str: -+ def __repr__(self): - set_status = 'set' if self.is_set() else 'unset' - return f"<{type(self).__qualname__} at {id(self):#x} {set_status}>" - # -diff --git a/Lib/opcode.py b/Lib/opcode.py -index 974f4d35e2a..4ee0d64026b 100644 ---- a/Lib/opcode.py -+++ b/Lib/opcode.py -@@ -17,8 +17,9 @@ - EXTENDED_ARG = opmap['EXTENDED_ARG'] - - opname = ['<%r>' % (op,) for op in range(max(opmap.values()) + 1)] --for op, i in opmap.items(): -- opname[i] = op -+for m in (opmap, _specialized_opmap): -+ for op, i in m.items(): -+ opname[i] = op - - cmp_op = ('<', '<=', '==', '!=', '>', '>=') - -@@ -51,6 +52,7 @@ - }, - "BINARY_OP": { - "counter": 1, -+ "descr": 4, - }, - "UNPACK_SEQUENCE": { - "counter": 1, -diff --git a/Lib/optparse.py b/Lib/optparse.py -index cbe3451ced8..38cf16d21ef 100644 ---- a/Lib/optparse.py -+++ b/Lib/optparse.py -@@ -74,7 +74,6 @@ - """ - - import sys, os --import textwrap - from gettext import gettext as _, ngettext - - -@@ -252,6 +251,7 @@ - Format a paragraph of free-form text for inclusion in the - help output at the current indentation level. - """ -+ import textwrap - text_width = max(self.width - self.current_indent, 11) - indent = " "*self.current_indent - return textwrap.fill(text, -@@ -308,6 +308,7 @@ - indent_first = 0 - result.append(opts) - if option.help: -+ import textwrap - help_text = self.expand_default(option) - help_lines = textwrap.wrap(help_text, self.help_width) - result.append("%*s%s\n" % (indent_first, "", help_lines[0])) -diff --git a/Lib/pathlib/_abc.py b/Lib/pathlib/_abc.py -index b4560295300..800d1b4503d 100644 ---- a/Lib/pathlib/_abc.py -+++ b/Lib/pathlib/_abc.py -@@ -7,17 +7,14 @@ - it's developed alongside pathlib. If it finds success and maturity as a PyPI - package, it could become a public part of the standard library. - --Two base classes are defined here -- PurePathBase and PathBase -- that --resemble pathlib's PurePath and Path respectively. -+Three base classes are defined here -- JoinablePath, ReadablePath and -+WritablePath. - """ - - import functools --import operator - import posixpath --from errno import EINVAL --from glob import _GlobberBase, _no_recurse_symlinks --from stat import S_ISDIR, S_ISLNK, S_ISREG --from pathlib._os import copyfileobj -+from glob import _PathGlobber, _no_recurse_symlinks -+from pathlib._os import magic_open, CopyReader, CopyWriter - - - @functools.cache -@@ -25,88 +22,50 @@ - return parser.normcase('Aa') == 'Aa' - - --class PathGlobber(_GlobberBase): -+def _explode_path(path): - """ -- Class providing shell-style globbing for path objects. -+ Split the path into a 2-tuple (anchor, parts), where *anchor* is the -+ uppermost parent of the path (equivalent to path.parents[-1]), and -+ *parts* is a reversed list of parts following the anchor. - """ -- -- lexists = operator.methodcaller('exists', follow_symlinks=False) -- add_slash = operator.methodcaller('joinpath', '') -- scandir = operator.methodcaller('_scandir') -- -- @staticmethod -- def concat_path(path, text): -- """Appends text to the given path.""" -- return path.with_segments(str(path) + text) -+ split = path.parser.split -+ path = str(path) -+ parent, name = split(path) -+ names = [] -+ while path != parent: -+ names.append(name) -+ path = parent -+ parent, name = split(path) -+ return path, names - - --class PurePathBase: -+class JoinablePath: - """Base class for pure path objects. - - This class *does not* provide several magic methods that are defined in -- its subclass PurePath. They are: __fspath__, __bytes__, __reduce__, -- __hash__, __eq__, __lt__, __le__, __gt__, __ge__. Its initializer and path -- joining methods accept only strings, not os.PathLike objects more broadly. -+ its subclass PurePath. They are: __init__, __fspath__, __bytes__, -+ __reduce__, __hash__, __eq__, __lt__, __le__, __gt__, __ge__. - """ - -- __slots__ = ( -- # The `_raw_paths` slot stores unjoined string paths. This is set in -- # the `__init__()` method. -- '_raw_paths', -- ) -+ __slots__ = () - parser = posixpath -- _globber = PathGlobber -- -- def __init__(self, *args): -- for arg in args: -- if not isinstance(arg, str): -- raise TypeError( -- f"argument should be a str, not {type(arg).__name__!r}") -- self._raw_paths = list(args) - - def with_segments(self, *pathsegments): - """Construct a new path object from any number of path-like objects. - Subclasses may override this method to customize how new path objects - are created from methods like `iterdir()`. - """ -- return type(self)(*pathsegments) -+ raise NotImplementedError - - def __str__(self): - """Return the string representation of the path, suitable for - passing to system calls.""" -- paths = self._raw_paths -- if len(paths) == 1: -- return paths[0] -- elif paths: -- # Join path segments from the initializer. -- path = self.parser.join(*paths) -- # Cache the joined path. -- paths.clear() -- paths.append(path) -- return path -- else: -- paths.append('') -- return '' -- -- def as_posix(self): -- """Return the string representation of the path with forward (/) -- slashes.""" -- return str(self).replace(self.parser.sep, '/') -- -- @property -- def drive(self): -- """The drive prefix (letter or UNC path), if any.""" -- return self.parser.splitdrive(self.anchor)[0] -- -- @property -- def root(self): -- """The root of the path, if any.""" -- return self.parser.splitdrive(self.anchor)[1] -+ raise NotImplementedError - - @property - def anchor(self): - """The concatenation of the drive and root, or ''.""" -- return self._stack[0] -+ return _explode_path(self)[0] - - @property - def name(self): -@@ -174,56 +133,11 @@ - else: - return self.with_name(stem + suffix) - -- def relative_to(self, other, *, walk_up=False): -- """Return the relative path to another path identified by the passed -- arguments. If the operation is not possible (because this is not -- related to the other path), raise ValueError. -- -- The *walk_up* parameter controls whether `..` may be used to resolve -- the path. -- """ -- if not isinstance(other, PurePathBase): -- other = self.with_segments(other) -- anchor0, parts0 = self._stack -- anchor1, parts1 = other._stack -- if anchor0 != anchor1: -- raise ValueError(f"{str(self)!r} and {str(other)!r} have different anchors") -- while parts0 and parts1 and parts0[-1] == parts1[-1]: -- parts0.pop() -- parts1.pop() -- for part in parts1: -- if not part or part == '.': -- pass -- elif not walk_up: -- raise ValueError(f"{str(self)!r} is not in the subpath of {str(other)!r}") -- elif part == '..': -- raise ValueError(f"'..' segment in {str(other)!r} cannot be walked") -- else: -- parts0.append('..') -- return self.with_segments(*reversed(parts0)) -- -- def is_relative_to(self, other): -- """Return True if the path is relative to another path or False. -- """ -- if not isinstance(other, PurePathBase): -- other = self.with_segments(other) -- anchor0, parts0 = self._stack -- anchor1, parts1 = other._stack -- if anchor0 != anchor1: -- return False -- while parts0 and parts1 and parts0[-1] == parts1[-1]: -- parts0.pop() -- parts1.pop() -- for part in parts1: -- if part and part != '.': -- return False -- return True -- - @property - def parts(self): - """An object providing sequence-like access to the - components in the filesystem path.""" -- anchor, parts = self._stack -+ anchor, parts = _explode_path(self) - if anchor: - parts.append(anchor) - return tuple(reversed(parts)) -@@ -234,37 +148,20 @@ - paths) or a totally different path (if one of the arguments is - anchored). - """ -- return self.with_segments(*self._raw_paths, *pathsegments) -+ return self.with_segments(str(self), *pathsegments) - - def __truediv__(self, key): - try: -- return self.with_segments(*self._raw_paths, key) -+ return self.with_segments(str(self), key) - except TypeError: - return NotImplemented - - def __rtruediv__(self, key): - try: -- return self.with_segments(key, *self._raw_paths) -+ return self.with_segments(key, str(self)) - except TypeError: - return NotImplemented - -- @property -- def _stack(self): -- """ -- Split the path into a 2-tuple (anchor, parts), where *anchor* is the -- uppermost parent of the path (equivalent to path.parents[-1]), and -- *parts* is a reversed list of parts following the anchor. -- """ -- split = self.parser.split -- path = str(self) -- parent, name = split(path) -- names = [] -- while path != parent: -- names.append(name) -- path = parent -- parent, name = split(path) -- return path, names -- - @property - def parent(self): - """The logical parent of the path.""" -@@ -287,59 +184,22 @@ - parent = split(path)[0] - return tuple(parents) - -- def is_absolute(self): -- """True if the path is absolute (has both a root and, if applicable, -- a drive).""" -- return self.parser.isabs(str(self)) -- -- @property -- def _pattern_str(self): -- """The path expressed as a string, for use in pattern-matching.""" -- return str(self) -- -- def match(self, path_pattern, *, case_sensitive=None): -- """ -- Return True if this path matches the given pattern. If the pattern is -- relative, matching is done from the right; otherwise, the entire path -- is matched. The recursive wildcard '**' is *not* supported by this -- method. -- """ -- if not isinstance(path_pattern, PurePathBase): -- path_pattern = self.with_segments(path_pattern) -- if case_sensitive is None: -- case_sensitive = _is_case_sensitive(self.parser) -- sep = path_pattern.parser.sep -- path_parts = self.parts[::-1] -- pattern_parts = path_pattern.parts[::-1] -- if not pattern_parts: -- raise ValueError("empty pattern") -- if len(path_parts) < len(pattern_parts): -- return False -- if len(path_parts) > len(pattern_parts) and path_pattern.anchor: -- return False -- globber = self._globber(sep, case_sensitive) -- for path_part, pattern_part in zip(path_parts, pattern_parts): -- match = globber.compile(pattern_part) -- if match(path_part) is None: -- return False -- return True -- - def full_match(self, pattern, *, case_sensitive=None): - """ - Return True if this path matches the given glob-style pattern. The - pattern is matched against the entire path. - """ -- if not isinstance(pattern, PurePathBase): -+ if not isinstance(pattern, JoinablePath): - pattern = self.with_segments(pattern) - if case_sensitive is None: - case_sensitive = _is_case_sensitive(self.parser) -- globber = self._globber(pattern.parser.sep, case_sensitive, recursive=True) -- match = globber.compile(pattern._pattern_str) -- return match(self._pattern_str) is not None -+ globber = _PathGlobber(pattern.parser.sep, case_sensitive, recursive=True) -+ match = globber.compile(str(pattern)) -+ return match(str(self)) is not None - - - --class PathBase(PurePathBase): -+class ReadablePath(JoinablePath): - """Base class for concrete path objects. - - This class provides dummy implementations for many methods that derived -@@ -354,15 +214,14 @@ - """ - __slots__ = () - -- def stat(self, *, follow_symlinks=True): -+ @property -+ def info(self): - """ -- Return the result of the stat() system call on this path, like -- os.stat() does. -+ A PathInfo object that exposes the file type and other file attributes -+ of this path. - """ - raise NotImplementedError - -- # Convenience functions for querying the stat results -- - def exists(self, *, follow_symlinks=True): - """ - Whether this path exists. -@@ -370,70 +229,35 @@ - This method normally follows symlinks; to check whether a symlink exists, - add the argument follow_symlinks=False. - """ -- try: -- self.stat(follow_symlinks=follow_symlinks) -- except (OSError, ValueError): -- return False -- return True -+ info = self.joinpath().info -+ return info.exists(follow_symlinks=follow_symlinks) - - def is_dir(self, *, follow_symlinks=True): - """ - Whether this path is a directory. - """ -- try: -- return S_ISDIR(self.stat(follow_symlinks=follow_symlinks).st_mode) -- except (OSError, ValueError): -- return False -+ info = self.joinpath().info -+ return info.is_dir(follow_symlinks=follow_symlinks) - - def is_file(self, *, follow_symlinks=True): - """ - Whether this path is a regular file (also True for symlinks pointing - to regular files). - """ -- try: -- return S_ISREG(self.stat(follow_symlinks=follow_symlinks).st_mode) -- except (OSError, ValueError): -- return False -+ info = self.joinpath().info -+ return info.is_file(follow_symlinks=follow_symlinks) - - def is_symlink(self): - """ - Whether this path is a symbolic link. - """ -- try: -- return S_ISLNK(self.stat(follow_symlinks=False).st_mode) -- except (OSError, ValueError): -- return False -+ info = self.joinpath().info -+ return info.is_symlink() - -- def _ensure_different_file(self, other_path): -+ def __open_rb__(self, buffering=-1): - """ -- Raise OSError(EINVAL) if both paths refer to the same file. -- """ -- pass -- -- def _ensure_distinct_path(self, other_path): -- """ -- Raise OSError(EINVAL) if the other path is within this path. -- """ -- # Note: there is no straightforward, foolproof algorithm to determine -- # if one directory is within another (a particularly perverse example -- # would be a single network share mounted in one location via NFS, and -- # in another location via CIFS), so we simply checks whether the -- # other path is lexically equal to, or within, this path. -- if self == other_path: -- err = OSError(EINVAL, "Source and target are the same path") -- elif self in other_path.parents: -- err = OSError(EINVAL, "Source path is a parent of target path") -- else: -- return -- err.filename = str(self) -- err.filename2 = str(other_path) -- raise err -- -- def open(self, mode='r', buffering=-1, encoding=None, -- errors=None, newline=None): -- """ -- Open the file pointed to by this path and return a file object, as -- the built-in open() function does. -+ Open the file pointed to by this path for reading in binary mode and -+ return a file object, like open(mode='rb'). - """ - raise NotImplementedError - -@@ -441,44 +265,16 @@ - """ - Open the file in bytes mode, read it, and close the file. - """ -- with self.open(mode='rb', buffering=0) as f: -+ with magic_open(self, mode='rb', buffering=0) as f: - return f.read() - - def read_text(self, encoding=None, errors=None, newline=None): - """ - Open the file in text mode, read it, and close the file. - """ -- with self.open(mode='r', encoding=encoding, errors=errors, newline=newline) as f: -+ with magic_open(self, mode='r', encoding=encoding, errors=errors, newline=newline) as f: - return f.read() - -- def write_bytes(self, data): -- """ -- Open the file in bytes mode, write to it, and close the file. -- """ -- # type-check for the buffer interface before truncating the file -- view = memoryview(data) -- with self.open(mode='wb') as f: -- return f.write(view) -- -- def write_text(self, data, encoding=None, errors=None, newline=None): -- """ -- Open the file in text mode, write to it, and close the file. -- """ -- if not isinstance(data, str): -- raise TypeError('data must be str, not %s' % -- data.__class__.__name__) -- with self.open(mode='w', encoding=encoding, errors=errors, newline=newline) as f: -- return f.write(data) -- -- def _scandir(self): -- """Yield os.DirEntry-like objects of the directory contents. -- -- The children are yielded in arbitrary order, and the -- special entries '.' and '..' are not included. -- """ -- import contextlib -- return contextlib.nullcontext(self.iterdir()) -- - def iterdir(self): - """Yield path objects of the directory contents. - -@@ -487,37 +283,33 @@ - """ - raise NotImplementedError - -- def _glob_selector(self, parts, case_sensitive, recurse_symlinks): -- if case_sensitive is None: -- case_sensitive = _is_case_sensitive(self.parser) -- case_pedantic = False -- else: -- # The user has expressed a case sensitivity choice, but we don't -- # know the case sensitivity of the underlying filesystem, so we -- # must use scandir() for everything, including non-wildcard parts. -- case_pedantic = True -- recursive = True if recurse_symlinks else _no_recurse_symlinks -- globber = self._globber(self.parser.sep, case_sensitive, case_pedantic, recursive) -- return globber.selector(parts) -- - def glob(self, pattern, *, case_sensitive=None, recurse_symlinks=True): - """Iterate over this subtree and yield all existing files (of any - kind, including directories) matching the given relative pattern. - """ -- if not isinstance(pattern, PurePathBase): -+ if not isinstance(pattern, JoinablePath): - pattern = self.with_segments(pattern) -- anchor, parts = pattern._stack -+ anchor, parts = _explode_path(pattern) - if anchor: - raise NotImplementedError("Non-relative patterns are unsupported") -- select = self._glob_selector(parts, case_sensitive, recurse_symlinks) -- return select(self) -+ if case_sensitive is None: -+ case_sensitive = _is_case_sensitive(self.parser) -+ case_pedantic = False -+ elif case_sensitive == _is_case_sensitive(self.parser): -+ case_pedantic = False -+ else: -+ case_pedantic = True -+ recursive = True if recurse_symlinks else _no_recurse_symlinks -+ globber = _PathGlobber(self.parser.sep, case_sensitive, case_pedantic, recursive) -+ select = globber.selector(parts) -+ return select(self.joinpath('')) - - def rglob(self, pattern, *, case_sensitive=None, recurse_symlinks=True): - """Recursively yield all existing files (of any kind, including - directories) matching the given relative pattern, anywhere in - this subtree. - """ -- if not isinstance(pattern, PurePathBase): -+ if not isinstance(pattern, JoinablePath): - pattern = self.with_segments(pattern) - pattern = '**' / pattern - return self.glob(pattern, case_sensitive=case_sensitive, recurse_symlinks=recurse_symlinks) -@@ -535,18 +327,16 @@ - if not top_down: - paths.append((path, dirnames, filenames)) - try: -- with path._scandir() as entries: -- for entry in entries: -- name = entry.name -- try: -- if entry.is_dir(follow_symlinks=follow_symlinks): -- if not top_down: -- paths.append(path.joinpath(name)) -- dirnames.append(name) -- else: -- filenames.append(name) -- except OSError: -- filenames.append(name) -+ for child in path.iterdir(): -+ try: -+ if child.info.is_dir(follow_symlinks=follow_symlinks): -+ if not top_down: -+ paths.append(child) -+ dirnames.append(child.name) -+ else: -+ filenames.append(child.name) -+ except OSError: -+ filenames.append(child.name) - except OSError as error: - if on_error is not None: - on_error(error) -@@ -564,95 +354,22 @@ - """ - raise NotImplementedError - -- def symlink_to(self, target, target_is_directory=False): -- """ -- Make this path a symlink pointing to the target path. -- Note the order of arguments (link, target) is the reverse of os.symlink. -- """ -- raise NotImplementedError -+ _copy_reader = property(CopyReader) - -- def _symlink_to_target_of(self, link): -- """ -- Make this path a symlink with the same target as the given link. This -- is used by copy(). -- """ -- self.symlink_to(link.readlink()) -- -- def mkdir(self, mode=0o777, parents=False, exist_ok=False): -- """ -- Create a new directory at this given path. -- """ -- raise NotImplementedError -- -- # Metadata keys supported by this path type. -- _readable_metadata = _writable_metadata = frozenset() -- -- def _read_metadata(self, keys=None, *, follow_symlinks=True): -- """ -- Returns path metadata as a dict with string keys. -- """ -- raise NotImplementedError -- -- def _write_metadata(self, metadata, *, follow_symlinks=True): -- """ -- Sets path metadata from the given dict with string keys. -- """ -- raise NotImplementedError -- -- def _copy_metadata(self, target, *, follow_symlinks=True): -- """ -- Copies metadata (permissions, timestamps, etc) from this path to target. -- """ -- # Metadata types supported by both source and target. -- keys = self._readable_metadata & target._writable_metadata -- if keys: -- metadata = self._read_metadata(keys, follow_symlinks=follow_symlinks) -- target._write_metadata(metadata, follow_symlinks=follow_symlinks) -- -- def _copy_file(self, target): -- """ -- Copy the contents of this file to the given target. -- """ -- self._ensure_different_file(target) -- with self.open('rb') as source_f: -- try: -- with target.open('wb') as target_f: -- copyfileobj(source_f, target_f) -- except IsADirectoryError as e: -- if not target.exists(): -- # Raise a less confusing exception. -- raise FileNotFoundError( -- f'Directory does not exist: {target}') from e -- else: -- raise -- -- def copy(self, target, *, follow_symlinks=True, dirs_exist_ok=False, -+ def copy(self, target, follow_symlinks=True, dirs_exist_ok=False, - preserve_metadata=False): - """ - Recursively copy this file or directory tree to the given destination. - """ -- if not isinstance(target, PathBase): -+ if not hasattr(target, '_copy_writer'): - target = self.with_segments(target) -- self._ensure_distinct_path(target) -- stack = [(self, target)] -- while stack: -- src, dst = stack.pop() -- if not follow_symlinks and src.is_symlink(): -- dst._symlink_to_target_of(src) -- if preserve_metadata: -- src._copy_metadata(dst, follow_symlinks=False) -- elif src.is_dir(): -- children = src.iterdir() -- dst.mkdir(exist_ok=dirs_exist_ok) -- stack.extend((child, dst.joinpath(child.name)) -- for child in children) -- if preserve_metadata: -- src._copy_metadata(dst) -- else: -- src._copy_file(dst) -- if preserve_metadata: -- src._copy_metadata(dst) -- return target -+ -+ # Delegate to the target path's CopyWriter object. -+ try: -+ create = target._copy_writer._create -+ except AttributeError: -+ raise TypeError(f"Target is not writable: {target}") from None -+ return create(self, follow_symlinks, dirs_exist_ok, preserve_metadata) - - def copy_into(self, target_dir, *, follow_symlinks=True, - dirs_exist_ok=False, preserve_metadata=False): -@@ -662,7 +379,7 @@ - name = self.name - if not name: - raise ValueError(f"{self!r} has an empty name") -- elif isinstance(target_dir, PathBase): -+ elif hasattr(target_dir, '_copy_writer'): - target = target_dir / name - else: - target = self.with_segments(target_dir, name) -@@ -670,29 +387,47 @@ - dirs_exist_ok=dirs_exist_ok, - preserve_metadata=preserve_metadata) - -- def _delete(self): -+ -+class WritablePath(JoinablePath): -+ __slots__ = () -+ -+ def symlink_to(self, target, target_is_directory=False): - """ -- Delete this file or directory (including all sub-directories). -+ Make this path a symlink pointing to the target path. -+ Note the order of arguments (link, target) is the reverse of os.symlink. - """ - raise NotImplementedError - -- def move(self, target): -+ def mkdir(self, mode=0o777, parents=False, exist_ok=False): - """ -- Recursively move this file or directory tree to the given destination. -+ Create a new directory at this given path. - """ -- target = self.copy(target, follow_symlinks=False, preserve_metadata=True) -- self._delete() -- return target -+ raise NotImplementedError - -- def move_into(self, target_dir): -+ def __open_wb__(self, buffering=-1): - """ -- Move this file or directory tree into the given existing directory. -+ Open the file pointed to by this path for writing in binary mode and -+ return a file object, like open(mode='wb'). - """ -- name = self.name -- if not name: -- raise ValueError(f"{self!r} has an empty name") -- elif isinstance(target_dir, PathBase): -- target = target_dir / name -- else: -- target = self.with_segments(target_dir, name) -- return self.move(target) -+ raise NotImplementedError -+ -+ def write_bytes(self, data): -+ """ -+ Open the file in bytes mode, write to it, and close the file. -+ """ -+ # type-check for the buffer interface before truncating the file -+ view = memoryview(data) -+ with magic_open(self, mode='wb') as f: -+ return f.write(view) -+ -+ def write_text(self, data, encoding=None, errors=None, newline=None): -+ """ -+ Open the file in text mode, write to it, and close the file. -+ """ -+ if not isinstance(data, str): -+ raise TypeError('data must be str, not %s' % -+ data.__class__.__name__) -+ with magic_open(self, mode='w', encoding=encoding, errors=errors, newline=newline) as f: -+ return f.write(data) -+ -+ _copy_writer = property(CopyWriter) -diff --git a/Lib/pathlib/_local.py b/Lib/pathlib/_local.py -index b933dd512ee..956c1920bf6 100644 ---- a/Lib/pathlib/_local.py -+++ b/Lib/pathlib/_local.py -@@ -4,10 +4,10 @@ - import os - import posixpath - import sys --from errno import EINVAL, EXDEV --from glob import _StringGlobber -+from errno import * -+from glob import _StringGlobber, _no_recurse_symlinks - from itertools import chain --from stat import S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO -+from stat import S_ISDIR, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO - from _collections_abc import Sequence - - try: -@@ -19,9 +19,8 @@ - except ImportError: - grp = None - --from pathlib._os import (copyfile, file_metadata_keys, read_file_metadata, -- write_file_metadata) --from pathlib._abc import PurePathBase, PathBase -+from pathlib._os import LocalCopyReader, LocalCopyWriter, PathInfo, DirEntryInfo -+from pathlib._abc import JoinablePath, ReadablePath, WritablePath - - - __all__ = [ -@@ -66,7 +65,7 @@ - return "<{}.parents>".format(type(self._path).__name__) - - --class PurePath(PurePathBase): -+class PurePath(JoinablePath): - """Base class for manipulating paths without I/O. - - PurePath represents a filesystem path and offers operations which -@@ -77,6 +76,10 @@ - """ - - __slots__ = ( -+ # The `_raw_paths` slot stores unjoined string paths. This is set in -+ # the `__init__()` method. -+ '_raw_paths', -+ - # The `_drv`, `_root` and `_tail_cached` slots store parsed and - # normalized parts of the path. They are set when any of the `drive`, - # `root` or `_tail` properties are accessed for the first time. The -@@ -108,7 +111,6 @@ - '_hash', - ) - parser = os.path -- _globber = _StringGlobber - - def __new__(cls, *args, **kwargs): - """Construct a PurePath from one or several strings and or existing -@@ -140,9 +142,15 @@ - "object where __fspath__ returns a str, " - f"not {type(path).__name__!r}") - paths.append(path) -- # Avoid calling super().__init__, as an optimisation - self._raw_paths = paths - -+ def with_segments(self, *pathsegments): -+ """Construct a new path object from any number of path-like objects. -+ Subclasses may override this method to customize how new path objects -+ are created from methods like `iterdir()`. -+ """ -+ return type(self)(*pathsegments) -+ - def joinpath(self, *pathsegments): - """Combine this path with one or several arguments, and return a - new path representing either a subpath (if all arguments are relative -@@ -304,14 +312,34 @@ - parts.append('') - return parts - -+ def as_posix(self): -+ """Return the string representation of the path with forward (/) -+ slashes.""" -+ return str(self).replace(self.parser.sep, '/') -+ -+ @property -+ def _raw_path(self): -+ paths = self._raw_paths -+ if len(paths) == 1: -+ return paths[0] -+ elif paths: -+ # Join path segments from the initializer. -+ path = self.parser.join(*paths) -+ # Cache the joined path. -+ paths.clear() -+ paths.append(path) -+ return path -+ else: -+ paths.append('') -+ return '' -+ - @property - def drive(self): - """The drive prefix (letter or UNC path), if any.""" - try: - return self._drv - except AttributeError: -- raw_path = PurePathBase.__str__(self) -- self._drv, self._root, self._tail_cached = self._parse_path(raw_path) -+ self._drv, self._root, self._tail_cached = self._parse_path(self._raw_path) - return self._drv - - @property -@@ -320,8 +348,7 @@ - try: - return self._root - except AttributeError: -- raw_path = PurePathBase.__str__(self) -- self._drv, self._root, self._tail_cached = self._parse_path(raw_path) -+ self._drv, self._root, self._tail_cached = self._parse_path(self._raw_path) - return self._root - - @property -@@ -329,8 +356,7 @@ - try: - return self._tail_cached - except AttributeError: -- raw_path = PurePathBase.__str__(self) -- self._drv, self._root, self._tail_cached = self._parse_path(raw_path) -+ self._drv, self._root, self._tail_cached = self._parse_path(self._raw_path) - return self._tail_cached - - @property -@@ -490,13 +516,48 @@ - from urllib.parse import quote_from_bytes - return prefix + quote_from_bytes(os.fsencode(path)) - -- @property -- def _pattern_str(self): -- """The path expressed as a string, for use in pattern-matching.""" -+ def full_match(self, pattern, *, case_sensitive=None): -+ """ -+ Return True if this path matches the given glob-style pattern. The -+ pattern is matched against the entire path. -+ """ -+ if not isinstance(pattern, PurePath): -+ pattern = self.with_segments(pattern) -+ if case_sensitive is None: -+ case_sensitive = self.parser is posixpath -+ - # The string representation of an empty path is a single dot ('.'). Empty - # paths shouldn't match wildcards, so we change it to the empty string. -- path_str = str(self) -- return '' if path_str == '.' else path_str -+ path = str(self) if self.parts else '' -+ pattern = str(pattern) if pattern.parts else '' -+ globber = _StringGlobber(self.parser.sep, case_sensitive, recursive=True) -+ return globber.compile(pattern)(path) is not None -+ -+ def match(self, path_pattern, *, case_sensitive=None): -+ """ -+ Return True if this path matches the given pattern. If the pattern is -+ relative, matching is done from the right; otherwise, the entire path -+ is matched. The recursive wildcard '**' is *not* supported by this -+ method. -+ """ -+ if not isinstance(path_pattern, PurePath): -+ path_pattern = self.with_segments(path_pattern) -+ if case_sensitive is None: -+ case_sensitive = self.parser is posixpath -+ path_parts = self.parts[::-1] -+ pattern_parts = path_pattern.parts[::-1] -+ if not pattern_parts: -+ raise ValueError("empty pattern") -+ if len(path_parts) < len(pattern_parts): -+ return False -+ if len(path_parts) > len(pattern_parts) and path_pattern.anchor: -+ return False -+ globber = _StringGlobber(self.parser.sep, case_sensitive) -+ for path_part, pattern_part in zip(path_parts, pattern_parts): -+ match = globber.compile(pattern_part) -+ if match(path_part) is None: -+ return False -+ return True - - # Subclassing os.PathLike makes isinstance() checks slower, - # which in turn makes Path construction slower. Register instead! -@@ -523,7 +584,7 @@ - __slots__ = () - - --class Path(PathBase, PurePath): -+class Path(WritablePath, ReadablePath, PurePath): - """PurePath subclass that can make system calls. - - Path represents a filesystem path but unlike PurePath, also offers -@@ -532,13 +593,25 @@ - object. You can also instantiate a PosixPath or WindowsPath directly, - but cannot instantiate a WindowsPath on a POSIX system or vice versa. - """ -- __slots__ = () -+ __slots__ = ('_info',) - - def __new__(cls, *args, **kwargs): - if cls is Path: - cls = WindowsPath if os.name == 'nt' else PosixPath - return object.__new__(cls) - -+ @property -+ def info(self): -+ """ -+ A PathInfo object that exposes the file type and other file attributes -+ of this path. -+ """ -+ try: -+ return self._info -+ except AttributeError: -+ self._info = PathInfo(self) -+ return self._info -+ - def stat(self, *, follow_symlinks=True): - """ - Return the result of the stat() system call on this path, like -@@ -570,7 +643,10 @@ - """ - if follow_symlinks: - return os.path.isdir(self) -- return PathBase.is_dir(self, follow_symlinks=follow_symlinks) -+ try: -+ return S_ISDIR(self.stat(follow_symlinks=follow_symlinks).st_mode) -+ except (OSError, ValueError): -+ return False - - def is_file(self, *, follow_symlinks=True): - """ -@@ -579,7 +655,10 @@ - """ - if follow_symlinks: - return os.path.isfile(self) -- return PathBase.is_file(self, follow_symlinks=follow_symlinks) -+ try: -+ return S_ISREG(self.stat(follow_symlinks=follow_symlinks).st_mode) -+ except (OSError, ValueError): -+ return False - - def is_mount(self): - """ -@@ -647,20 +726,6 @@ - return (st.st_ino == other_st.st_ino and - st.st_dev == other_st.st_dev) - -- def _ensure_different_file(self, other_path): -- """ -- Raise OSError(EINVAL) if both paths refer to the same file. -- """ -- try: -- if not self.samefile(other_path): -- return -- except (OSError, ValueError): -- return -- err = OSError(EINVAL, "Source and target are the same file") -- err.filename = str(self) -- err.filename2 = str(other_path) -- raise err -- - def open(self, mode='r', buffering=-1, encoding=None, - errors=None, newline=None): - """ -@@ -671,6 +736,13 @@ - encoding = io.text_encoding(encoding) - return io.open(self, mode, buffering, encoding, errors, newline) - -+ def read_bytes(self): -+ """ -+ Open the file in bytes mode, read it, and close the file. -+ """ -+ with self.open(mode='rb', buffering=0) as f: -+ return f.read() -+ - def read_text(self, encoding=None, errors=None, newline=None): - """ - Open the file in text mode, read it, and close the file. -@@ -678,7 +750,17 @@ - # Call io.text_encoding() here to ensure any warning is raised at an - # appropriate stack level. - encoding = io.text_encoding(encoding) -- return PathBase.read_text(self, encoding, errors, newline) -+ with self.open(mode='r', encoding=encoding, errors=errors, newline=newline) as f: -+ return f.read() -+ -+ def write_bytes(self, data): -+ """ -+ Open the file in bytes mode, write to it, and close the file. -+ """ -+ # type-check for the buffer interface before truncating the file -+ view = memoryview(data) -+ with self.open(mode='wb') as f: -+ return f.write(view) - - def write_text(self, data, encoding=None, errors=None, newline=None): - """ -@@ -687,7 +769,11 @@ - # Call io.text_encoding() here to ensure any warning is raised at an - # appropriate stack level. - encoding = io.text_encoding(encoding) -- return PathBase.write_text(self, data, encoding, errors, newline) -+ if not isinstance(data, str): -+ raise TypeError('data must be str, not %s' % -+ data.__class__.__name__) -+ with self.open(mode='w', encoding=encoding, errors=errors, newline=newline) as f: -+ return f.write(data) - - _remove_leading_dot = operator.itemgetter(slice(2, None)) - _remove_trailing_slash = operator.itemgetter(slice(-1)) -@@ -700,13 +786,11 @@ - path_str = path_str[:-1] - yield path_str - -- def _scandir(self): -- """Yield os.DirEntry-like objects of the directory contents. -- -- The children are yielded in arbitrary order, and the -- special entries '.' and '..' are not included. -- """ -- return os.scandir(self) -+ def _from_dir_entry(self, dir_entry, path_str): -+ path = self.with_segments(path_str) -+ path._str = path_str -+ path._info = DirEntryInfo(dir_entry) -+ return path - - def iterdir(self): - """Yield path objects of the directory contents. -@@ -716,20 +800,31 @@ - """ - root_dir = str(self) - with os.scandir(root_dir) as scandir_it: -- paths = [entry.path for entry in scandir_it] -+ entries = list(scandir_it) - if root_dir == '.': -- paths = map(self._remove_leading_dot, paths) -- return map(self._from_parsed_string, paths) -+ return (self._from_dir_entry(e, e.name) for e in entries) -+ else: -+ return (self._from_dir_entry(e, e.path) for e in entries) - - def glob(self, pattern, *, case_sensitive=None, recurse_symlinks=False): - """Iterate over this subtree and yield all existing files (of any - kind, including directories) matching the given relative pattern. - """ - sys.audit("pathlib.Path.glob", self, pattern) -+ if case_sensitive is None: -+ case_sensitive = self.parser is posixpath -+ case_pedantic = False -+ else: -+ # The user has expressed a case sensitivity choice, but we don't -+ # know the case sensitivity of the underlying filesystem, so we -+ # must use scandir() for everything, including non-wildcard parts. -+ case_pedantic = True - parts = self._parse_pattern(pattern) -- select = self._glob_selector(parts[::-1], case_sensitive, recurse_symlinks) -+ recursive = True if recurse_symlinks else _no_recurse_symlinks -+ globber = _StringGlobber(self.parser.sep, case_sensitive, case_pedantic, recursive) -+ select = globber.selector(parts[::-1]) - root = str(self) -- paths = select(root) -+ paths = select(self.parser.join(root, '')) - - # Normalize results - if root == '.': -@@ -891,24 +986,6 @@ - if not exist_ok or not self.is_dir(): - raise - -- _readable_metadata = _writable_metadata = file_metadata_keys -- _read_metadata = read_file_metadata -- _write_metadata = write_file_metadata -- -- if copyfile: -- def _copy_file(self, target): -- """ -- Copy the contents of this file to the given target. -- """ -- try: -- target = os.fspath(target) -- except TypeError: -- if not isinstance(target, PathBase): -- raise -- PathBase._copy_file(self, target) -- else: -- copyfile(os.fspath(self), target) -- - def chmod(self, mode, *, follow_symlinks=True): - """ - Change the permissions of the path, like os.chmod(). -@@ -978,21 +1055,45 @@ - os.replace(self, target) - return self.with_segments(target) - -+ _copy_reader = property(LocalCopyReader) -+ _copy_writer = property(LocalCopyWriter) -+ - def move(self, target): - """ - Recursively move this file or directory tree to the given destination. - """ -- self._ensure_different_file(target) -+ # Use os.replace() if the target is os.PathLike and on the same FS. - try: -- return self.replace(target) -+ target_str = os.fspath(target) - except TypeError: -- if not isinstance(target, PathBase): -- raise -- except OSError as err: -- if err.errno != EXDEV: -- raise -+ pass -+ else: -+ if not hasattr(target, '_copy_writer'): -+ target = self.with_segments(target_str) -+ target._copy_writer._ensure_different_file(self) -+ try: -+ os.replace(self, target_str) -+ return target -+ except OSError as err: -+ if err.errno != EXDEV: -+ raise - # Fall back to copy+delete. -- return PathBase.move(self, target) -+ target = self.copy(target, follow_symlinks=False, preserve_metadata=True) -+ self._delete() -+ return target -+ -+ def move_into(self, target_dir): -+ """ -+ Move this file or directory tree into the given existing directory. -+ """ -+ name = self.name -+ if not name: -+ raise ValueError(f"{self!r} has an empty name") -+ elif hasattr(target_dir, '_copy_writer'): -+ target = target_dir / name -+ else: -+ target = self.with_segments(target_dir, name) -+ return self.move(target) - - if hasattr(os, "symlink"): - def symlink_to(self, target, target_is_directory=False): -@@ -1010,14 +1111,6 @@ - f = f"{type(self).__name__}.symlink_to()" - raise UnsupportedOperation(f"{f} is unsupported on this system") - -- if os.name == 'nt': -- def _symlink_to_target_of(self, link): -- """ -- Make this path a symlink with the same target as the given link. -- This is used by copy(). -- """ -- self.symlink_to(link.readlink(), link.is_dir()) -- - if hasattr(os, "link"): - def hardlink_to(self, target): - """ -diff --git a/Lib/pathlib/_os.py b/Lib/pathlib/_os.py -index 642b3a57c59..c0c81ada858 100644 ---- a/Lib/pathlib/_os.py -+++ b/Lib/pathlib/_os.py -@@ -3,8 +3,9 @@ - """ - - from errno import * -+from stat import S_ISDIR, S_ISREG, S_ISLNK, S_IMODE -+import io - import os --import stat - import sys - try: - import fcntl -@@ -165,98 +166,449 @@ - write_target(buf) - - --# Kinds of metadata supported by the operating system. --file_metadata_keys = {'mode', 'times_ns'} --if hasattr(os.stat_result, 'st_flags'): -- file_metadata_keys.add('flags') --if hasattr(os, 'listxattr'): -- file_metadata_keys.add('xattrs') --file_metadata_keys = frozenset(file_metadata_keys) -+def magic_open(path, mode='r', buffering=-1, encoding=None, errors=None, -+ newline=None): -+ """ -+ Open the file pointed to by this path and return a file object, as -+ the built-in open() function does. -+ """ -+ try: -+ return io.open(path, mode, buffering, encoding, errors, newline) -+ except TypeError: -+ pass -+ cls = type(path) -+ text = 'b' not in mode -+ mode = ''.join(sorted(c for c in mode if c not in 'bt')) -+ if text: -+ try: -+ attr = getattr(cls, f'__open_{mode}__') -+ except AttributeError: -+ pass -+ else: -+ return attr(path, buffering, encoding, errors, newline) - -+ try: -+ attr = getattr(cls, f'__open_{mode}b__') -+ except AttributeError: -+ pass -+ else: -+ stream = attr(path, buffering) -+ if text: -+ stream = io.TextIOWrapper(stream, encoding, errors, newline) -+ return stream -+ -+ raise TypeError(f"{cls.__name__} can't be opened with mode {mode!r}") - --def read_file_metadata(path, keys=None, *, follow_symlinks=True): -+ -+class CopyReader: - """ -- Returns local path metadata as a dict with string keys. -+ Class that implements the "read" part of copying between path objects. -+ An instance of this class is available from the ReadablePath._copy_reader -+ property. - """ -- if keys is None: -- keys = file_metadata_keys -- assert keys.issubset(file_metadata_keys) -- result = {} -- for key in keys: -- if key == 'xattrs': -+ __slots__ = ('_path',) -+ -+ def __init__(self, path): -+ self._path = path -+ -+ _readable_metakeys = frozenset() -+ -+ def _read_metadata(self, metakeys, *, follow_symlinks=True): -+ """ -+ Returns path metadata as a dict with string keys. -+ """ -+ raise NotImplementedError -+ -+ -+class CopyWriter: -+ """ -+ Class that implements the "write" part of copying between path objects. An -+ instance of this class is available from the WritablePath._copy_writer -+ property. -+ """ -+ __slots__ = ('_path',) -+ -+ def __init__(self, path): -+ self._path = path -+ -+ _writable_metakeys = frozenset() -+ -+ def _write_metadata(self, metadata, *, follow_symlinks=True): -+ """ -+ Sets path metadata from the given dict with string keys. -+ """ -+ raise NotImplementedError -+ -+ def _create(self, source, follow_symlinks, dirs_exist_ok, preserve_metadata): -+ self._ensure_distinct_path(source) -+ if preserve_metadata: -+ metakeys = self._writable_metakeys & source._copy_reader._readable_metakeys -+ else: -+ metakeys = None -+ if not follow_symlinks and source.is_symlink(): -+ self._create_symlink(source, metakeys) -+ elif source.is_dir(): -+ self._create_dir(source, metakeys, follow_symlinks, dirs_exist_ok) -+ else: -+ self._create_file(source, metakeys) -+ return self._path -+ -+ def _create_dir(self, source, metakeys, follow_symlinks, dirs_exist_ok): -+ """Copy the given directory to our path.""" -+ children = list(source.iterdir()) -+ self._path.mkdir(exist_ok=dirs_exist_ok) -+ for src in children: -+ dst = self._path.joinpath(src.name) -+ if not follow_symlinks and src.is_symlink(): -+ dst._copy_writer._create_symlink(src, metakeys) -+ elif src.is_dir(): -+ dst._copy_writer._create_dir(src, metakeys, follow_symlinks, dirs_exist_ok) -+ else: -+ dst._copy_writer._create_file(src, metakeys) -+ if metakeys: -+ metadata = source._copy_reader._read_metadata(metakeys) -+ if metadata: -+ self._write_metadata(metadata) -+ -+ def _create_file(self, source, metakeys): -+ """Copy the given file to our path.""" -+ self._ensure_different_file(source) -+ with magic_open(source, 'rb') as source_f: -+ try: -+ with magic_open(self._path, 'wb') as target_f: -+ copyfileobj(source_f, target_f) -+ except IsADirectoryError as e: -+ if not self._path.exists(): -+ # Raise a less confusing exception. -+ raise FileNotFoundError( -+ f'Directory does not exist: {self._path}') from e -+ raise -+ if metakeys: -+ metadata = source._copy_reader._read_metadata(metakeys) -+ if metadata: -+ self._write_metadata(metadata) -+ -+ def _create_symlink(self, source, metakeys): -+ """Copy the given symbolic link to our path.""" -+ self._path.symlink_to(source.readlink()) -+ if metakeys: -+ metadata = source._copy_reader._read_metadata(metakeys, follow_symlinks=False) -+ if metadata: -+ self._write_metadata(metadata, follow_symlinks=False) -+ -+ def _ensure_different_file(self, source): -+ """ -+ Raise OSError(EINVAL) if both paths refer to the same file. -+ """ -+ pass -+ -+ def _ensure_distinct_path(self, source): -+ """ -+ Raise OSError(EINVAL) if the other path is within this path. -+ """ -+ # Note: there is no straightforward, foolproof algorithm to determine -+ # if one directory is within another (a particularly perverse example -+ # would be a single network share mounted in one location via NFS, and -+ # in another location via CIFS), so we simply checks whether the -+ # other path is lexically equal to, or within, this path. -+ if source == self._path: -+ err = OSError(EINVAL, "Source and target are the same path") -+ elif source in self._path.parents: -+ err = OSError(EINVAL, "Source path is a parent of target path") -+ else: -+ return -+ err.filename = str(source) -+ err.filename2 = str(self._path) -+ raise err -+ -+ -+class LocalCopyReader(CopyReader): -+ """This object implements the "read" part of copying local paths. Don't -+ try to construct it yourself. -+ """ -+ __slots__ = () -+ -+ _readable_metakeys = {'mode', 'times_ns'} -+ if hasattr(os.stat_result, 'st_flags'): -+ _readable_metakeys.add('flags') -+ if hasattr(os, 'listxattr'): -+ _readable_metakeys.add('xattrs') -+ _readable_metakeys = frozenset(_readable_metakeys) -+ -+ def _read_metadata(self, metakeys, *, follow_symlinks=True): -+ metadata = {} -+ if 'mode' in metakeys or 'times_ns' in metakeys or 'flags' in metakeys: -+ st = self._path.stat(follow_symlinks=follow_symlinks) -+ if 'mode' in metakeys: -+ metadata['mode'] = S_IMODE(st.st_mode) -+ if 'times_ns' in metakeys: -+ metadata['times_ns'] = st.st_atime_ns, st.st_mtime_ns -+ if 'flags' in metakeys: -+ metadata['flags'] = st.st_flags -+ if 'xattrs' in metakeys: - try: -- result['xattrs'] = [ -- (attr, os.getxattr(path, attr, follow_symlinks=follow_symlinks)) -- for attr in os.listxattr(path, follow_symlinks=follow_symlinks)] -+ metadata['xattrs'] = [ -+ (attr, os.getxattr(self._path, attr, follow_symlinks=follow_symlinks)) -+ for attr in os.listxattr(self._path, follow_symlinks=follow_symlinks)] - except OSError as err: - if err.errno not in (EPERM, ENOTSUP, ENODATA, EINVAL, EACCES): - raise -- continue -- st = os.stat(path, follow_symlinks=follow_symlinks) -- if key == 'mode': -- result['mode'] = stat.S_IMODE(st.st_mode) -- elif key == 'times_ns': -- result['times_ns'] = st.st_atime_ns, st.st_mtime_ns -- elif key == 'flags': -- result['flags'] = st.st_flags -- return result -- -- --def write_file_metadata(path, metadata, *, follow_symlinks=True): -- """ -- Sets local path metadata from the given dict with string keys. -+ return metadata -+ -+ -+class LocalCopyWriter(CopyWriter): -+ """This object implements the "write" part of copying local paths. Don't -+ try to construct it yourself. - """ -- assert frozenset(metadata.keys()).issubset(file_metadata_keys) -+ __slots__ = () - -- def _nop(*args, ns=None, follow_symlinks=None): -- pass -+ _writable_metakeys = LocalCopyReader._readable_metakeys - -- if follow_symlinks: -- # use the real function if it exists -- def lookup(name): -- return getattr(os, name, _nop) -- else: -- # use the real function only if it exists -- # *and* it supports follow_symlinks -- def lookup(name): -- fn = getattr(os, name, _nop) -- if fn in os.supports_follow_symlinks: -- return fn -- return _nop -- -- times_ns = metadata.get('times_ns') -- if times_ns is not None: -- lookup("utime")(path, ns=times_ns, follow_symlinks=follow_symlinks) -- # We must copy extended attributes before the file is (potentially) -- # chmod()'ed read-only, otherwise setxattr() will error with -EACCES. -- xattrs = metadata.get('xattrs') -- if xattrs is not None: -- for attr, value in xattrs: -+ def _write_metadata(self, metadata, *, follow_symlinks=True): -+ def _nop(*args, ns=None, follow_symlinks=None): -+ pass -+ -+ if follow_symlinks: -+ # use the real function if it exists -+ def lookup(name): -+ return getattr(os, name, _nop) -+ else: -+ # use the real function only if it exists -+ # *and* it supports follow_symlinks -+ def lookup(name): -+ fn = getattr(os, name, _nop) -+ if fn in os.supports_follow_symlinks: -+ return fn -+ return _nop -+ -+ times_ns = metadata.get('times_ns') -+ if times_ns is not None: -+ lookup("utime")(self._path, ns=times_ns, follow_symlinks=follow_symlinks) -+ # We must copy extended attributes before the file is (potentially) -+ # chmod()'ed read-only, otherwise setxattr() will error with -EACCES. -+ xattrs = metadata.get('xattrs') -+ if xattrs is not None: -+ for attr, value in xattrs: -+ try: -+ os.setxattr(self._path, attr, value, follow_symlinks=follow_symlinks) -+ except OSError as e: -+ if e.errno not in (EPERM, ENOTSUP, ENODATA, EINVAL, EACCES): -+ raise -+ mode = metadata.get('mode') -+ if mode is not None: - try: -- os.setxattr(path, attr, value, follow_symlinks=follow_symlinks) -- except OSError as e: -- if e.errno not in (EPERM, ENOTSUP, ENODATA, EINVAL, EACCES): -+ lookup("chmod")(self._path, mode, follow_symlinks=follow_symlinks) -+ except NotImplementedError: -+ # if we got a NotImplementedError, it's because -+ # * follow_symlinks=False, -+ # * lchown() is unavailable, and -+ # * either -+ # * fchownat() is unavailable or -+ # * fchownat() doesn't implement AT_SYMLINK_NOFOLLOW. -+ # (it returned ENOSUP.) -+ # therefore we're out of options--we simply cannot chown the -+ # symlink. give up, suppress the error. -+ # (which is what shutil always did in this circumstance.) -+ pass -+ flags = metadata.get('flags') -+ if flags is not None: -+ try: -+ lookup("chflags")(self._path, flags, follow_symlinks=follow_symlinks) -+ except OSError as why: -+ if why.errno not in (EOPNOTSUPP, ENOTSUP): - raise -- mode = metadata.get('mode') -- if mode is not None: -+ -+ if copyfile: -+ # Use fast OS routine for local file copying where available. -+ def _create_file(self, source, metakeys): -+ """Copy the given file to the given target.""" -+ try: -+ source = os.fspath(source) -+ except TypeError: -+ super()._create_file(source, metakeys) -+ else: -+ copyfile(source, os.fspath(self._path)) -+ -+ if os.name == 'nt': -+ # Windows: symlink target might not exist yet if we're copying several -+ # files, so ensure we pass is_dir to os.symlink(). -+ def _create_symlink(self, source, metakeys): -+ """Copy the given symlink to the given target.""" -+ self._path.symlink_to(source.readlink(), source.is_dir()) -+ if metakeys: -+ metadata = source._copy_reader._read_metadata(metakeys, follow_symlinks=False) -+ if metadata: -+ self._write_metadata(metadata, follow_symlinks=False) -+ -+ def _ensure_different_file(self, source): -+ """ -+ Raise OSError(EINVAL) if both paths refer to the same file. -+ """ - try: -- lookup("chmod")(path, mode, follow_symlinks=follow_symlinks) -- except NotImplementedError: -- # if we got a NotImplementedError, it's because -- # * follow_symlinks=False, -- # * lchown() is unavailable, and -- # * either -- # * fchownat() is unavailable or -- # * fchownat() doesn't implement AT_SYMLINK_NOFOLLOW. -- # (it returned ENOSUP.) -- # therefore we're out of options--we simply cannot chown the -- # symlink. give up, suppress the error. -- # (which is what shutil always did in this circumstance.) -- pass -- flags = metadata.get('flags') -- if flags is not None: -+ if not self._path.samefile(source): -+ return -+ except (OSError, ValueError): -+ return -+ err = OSError(EINVAL, "Source and target are the same file") -+ err.filename = str(source) -+ err.filename2 = str(self._path) -+ raise err -+ -+ -+class _PathInfoBase: -+ __slots__ = () -+ -+ def __repr__(self): -+ path_type = "WindowsPath" if os.name == "nt" else "PosixPath" -+ return f"<{path_type}.info>" -+ -+ -+class _WindowsPathInfo(_PathInfoBase): -+ """Implementation of pathlib.types.PathInfo that provides status -+ information for Windows paths. Don't try to construct it yourself.""" -+ __slots__ = ('_path', '_exists', '_is_dir', '_is_file', '_is_symlink') -+ -+ def __init__(self, path): -+ self._path = str(path) -+ -+ def exists(self, *, follow_symlinks=True): -+ """Whether this path exists.""" -+ if not follow_symlinks and self.is_symlink(): -+ return True - try: -- lookup("chflags")(path, flags, follow_symlinks=follow_symlinks) -- except OSError as why: -- if why.errno not in (EOPNOTSUPP, ENOTSUP): -- raise -+ return self._exists -+ except AttributeError: -+ if os.path.exists(self._path): -+ self._exists = True -+ return True -+ else: -+ self._exists = self._is_dir = self._is_file = False -+ return False -+ -+ def is_dir(self, *, follow_symlinks=True): -+ """Whether this path is a directory.""" -+ if not follow_symlinks and self.is_symlink(): -+ return False -+ try: -+ return self._is_dir -+ except AttributeError: -+ if os.path.isdir(self._path): -+ self._is_dir = self._exists = True -+ return True -+ else: -+ self._is_dir = False -+ return False -+ -+ def is_file(self, *, follow_symlinks=True): -+ """Whether this path is a regular file.""" -+ if not follow_symlinks and self.is_symlink(): -+ return False -+ try: -+ return self._is_file -+ except AttributeError: -+ if os.path.isfile(self._path): -+ self._is_file = self._exists = True -+ return True -+ else: -+ self._is_file = False -+ return False -+ -+ def is_symlink(self): -+ """Whether this path is a symbolic link.""" -+ try: -+ return self._is_symlink -+ except AttributeError: -+ self._is_symlink = os.path.islink(self._path) -+ return self._is_symlink -+ -+ -+class _PosixPathInfo(_PathInfoBase): -+ """Implementation of pathlib.types.PathInfo that provides status -+ information for POSIX paths. Don't try to construct it yourself.""" -+ __slots__ = ('_path', '_mode') -+ -+ def __init__(self, path): -+ self._path = str(path) -+ self._mode = [None, None] -+ -+ def _get_mode(self, *, follow_symlinks=True): -+ idx = bool(follow_symlinks) -+ mode = self._mode[idx] -+ if mode is None: -+ try: -+ st = os.stat(self._path, follow_symlinks=follow_symlinks) -+ except (OSError, ValueError): -+ mode = 0 -+ else: -+ mode = st.st_mode -+ if follow_symlinks or S_ISLNK(mode): -+ self._mode[idx] = mode -+ else: -+ # Not a symlink, so stat() will give the same result -+ self._mode = [mode, mode] -+ return mode -+ -+ def exists(self, *, follow_symlinks=True): -+ """Whether this path exists.""" -+ return self._get_mode(follow_symlinks=follow_symlinks) > 0 -+ -+ def is_dir(self, *, follow_symlinks=True): -+ """Whether this path is a directory.""" -+ return S_ISDIR(self._get_mode(follow_symlinks=follow_symlinks)) -+ -+ def is_file(self, *, follow_symlinks=True): -+ """Whether this path is a regular file.""" -+ return S_ISREG(self._get_mode(follow_symlinks=follow_symlinks)) -+ -+ def is_symlink(self): -+ """Whether this path is a symbolic link.""" -+ return S_ISLNK(self._get_mode(follow_symlinks=False)) -+ -+ -+PathInfo = _WindowsPathInfo if os.name == 'nt' else _PosixPathInfo -+ -+ -+class DirEntryInfo(_PathInfoBase): -+ """Implementation of pathlib.types.PathInfo that provides status -+ information by querying a wrapped os.DirEntry object. Don't try to -+ construct it yourself.""" -+ __slots__ = ('_entry', '_exists') -+ -+ def __init__(self, entry): -+ self._entry = entry -+ -+ def exists(self, *, follow_symlinks=True): -+ """Whether this path exists.""" -+ if not follow_symlinks: -+ return True -+ try: -+ return self._exists -+ except AttributeError: -+ try: -+ self._entry.stat() -+ except OSError: -+ self._exists = False -+ else: -+ self._exists = True -+ return self._exists -+ -+ def is_dir(self, *, follow_symlinks=True): -+ """Whether this path is a directory.""" -+ try: -+ return self._entry.is_dir(follow_symlinks=follow_symlinks) -+ except OSError: -+ return False -+ -+ def is_file(self, *, follow_symlinks=True): -+ """Whether this path is a regular file.""" -+ try: -+ return self._entry.is_file(follow_symlinks=follow_symlinks) -+ except OSError: -+ return False -+ -+ def is_symlink(self): -+ """Whether this path is a symbolic link.""" -+ try: -+ return self._entry.is_symlink() -+ except OSError: -+ return False -diff --git a/Lib/pathlib/_types.py b/Lib/pathlib/types.py -similarity index 50% -rename from Lib/pathlib/_types.py -rename to Lib/pathlib/types.py -index 60df94d0b46..b781264796b 100644 ---- a/Lib/pathlib/_types.py -+++ b/Lib/pathlib/types.py -@@ -5,18 +5,26 @@ - - - @runtime_checkable --class Parser(Protocol): -+class _PathParser(Protocol): - """Protocol for path parsers, which do low-level path manipulation. - - Path parsers provide a subset of the os.path API, specifically those -- functions needed to provide PurePathBase functionality. Each PurePathBase -+ functions needed to provide JoinablePath functionality. Each JoinablePath - subclass references its path parser via a 'parser' class attribute. - """ - - sep: str -- def join(self, path: str, *paths: str) -> str: ... - def split(self, path: str) -> tuple[str, str]: ... -- def splitdrive(self, path: str) -> tuple[str, str]: ... - def splitext(self, path: str) -> tuple[str, str]: ... - def normcase(self, path: str) -> str: ... -- def isabs(self, path: str) -> bool: ... -+ -+ -+@runtime_checkable -+class PathInfo(Protocol): -+ """Protocol for path info objects, which support querying the file type. -+ Methods may return cached results. -+ """ -+ def exists(self, *, follow_symlinks: bool = True) -> bool: ... -+ def is_dir(self, *, follow_symlinks: bool = True) -> bool: ... -+ def is_file(self, *, follow_symlinks: bool = True) -> bool: ... -+ def is_symlink(self) -> bool: ... -diff --git a/Lib/pdb.py b/Lib/pdb.py -index 10d1923cdad..4abf216b773 100644 ---- a/Lib/pdb.py -+++ b/Lib/pdb.py -@@ -90,6 +90,7 @@ - from contextlib import contextmanager - from rlcompleter import Completer - from types import CodeType -+from warnings import deprecated - - - class Restart(Exception): -@@ -421,6 +422,16 @@ - ] - self.rcLines = [] - -+ @property -+ @deprecated("The frame locals reference is no longer cached. Use 'curframe.f_locals' instead.") -+ def curframe_locals(self): -+ return self.curframe.f_locals -+ -+ @curframe_locals.setter -+ @deprecated("Setting 'curframe_locals' no longer has any effect. Update the contents of 'curframe.f_locals' instead.") -+ def curframe_locals(self, value): -+ pass -+ - # Override Bdb methods - - def user_call(self, frame, argument_list): -@@ -1725,6 +1736,19 @@ - - Quit from the debugger. The program being executed is aborted. - """ -+ if self.mode == 'inline': -+ while True: -+ try: -+ reply = input('Quitting pdb will kill the process. Quit anyway? [y/n] ') -+ reply = reply.lower().strip() -+ except EOFError: -+ reply = 'y' -+ self.message('') -+ if reply == 'y' or reply == '': -+ sys.exit(0) -+ elif reply.lower() == 'n': -+ return -+ - self._user_requested_quit = True - self.set_quit() - return 1 -@@ -1738,9 +1762,7 @@ - Handles the receipt of EOF as a command. - """ - self.message('') -- self._user_requested_quit = True -- self.set_quit() -- return 1 -+ return self.do_quit(arg) - - def do_args(self, arg): - """a(rgs) -diff --git a/Lib/pickle.py b/Lib/pickle.py -index 1920973e3f8..8afb4aa4285 100644 ---- a/Lib/pickle.py -+++ b/Lib/pickle.py -@@ -31,7 +31,6 @@ - import sys - from sys import maxsize - from struct import pack, unpack --import re - import io - import codecs - import _compat_pickle -@@ -188,7 +187,7 @@ - NEXT_BUFFER = b'\x97' # push next out-of-band buffer - READONLY_BUFFER = b'\x98' # make top of stack readonly - --__all__.extend([x for x in dir() if re.match("[A-Z][A-Z0-9_]+$", x)]) -+__all__.extend(x for x in dir() if x.isupper() and not x.startswith('_')) - - - class _Framer: -diff --git a/Lib/platform.py b/Lib/platform.py -index 1f6baed66d3..235dd98c60a 100644 ---- a/Lib/platform.py -+++ b/Lib/platform.py -@@ -521,6 +521,54 @@ - return IOSVersionInfo(system, release, model, is_simulator) - - -+# A namedtuple for tvOS version information. -+TVOSVersionInfo = collections.namedtuple( -+ "TVOSVersionInfo", -+ ["system", "release", "model", "is_simulator"] -+) -+ -+ -+def tvos_ver(system="", release="", model="", is_simulator=False): -+ """Get tvOS version information, and return it as a namedtuple: -+ (system, release, model, is_simulator). -+ -+ If values can't be determined, they are set to values provided as -+ parameters. -+ """ -+ if sys.platform == "tvos": -+ # TODO: Can the iOS implementation be used here? -+ import _ios_support -+ result = _ios_support.get_platform_ios() -+ if result is not None: -+ return TVOSVersionInfo(*result) -+ -+ return TVOSVersionInfo(system, release, model, is_simulator) -+ -+ -+# A namedtuple for watchOS version information. -+WatchOSVersionInfo = collections.namedtuple( -+ "WatchOSVersionInfo", -+ ["system", "release", "model", "is_simulator"] -+) -+ -+ -+def watchos_ver(system="", release="", model="", is_simulator=False): -+ """Get watchOS version information, and return it as a namedtuple: -+ (system, release, model, is_simulator). -+ -+ If values can't be determined, they are set to values provided as -+ parameters. -+ """ -+ if sys.platform == "watchos": -+ # TODO: Can the iOS implementation be used here? -+ import _ios_support -+ result = _ios_support.get_platform_ios() -+ if result is not None: -+ return WatchOSVersionInfo(*result) -+ -+ return WatchOSVersionInfo(system, release, model, is_simulator) -+ -+ - def _java_getprop(name, default): - """This private helper is deprecated in 3.13 and will be removed in 3.15""" - from java.lang import System -@@ -884,14 +932,25 @@ - csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0) - return 'Alpha' if cpu_number >= 128 else 'VAX' - -- # On the iOS simulator, os.uname returns the architecture as uname.machine. -- # On device it returns the model name for some reason; but there's only one -- # CPU architecture for iOS devices, so we know the right answer. -+ # On the iOS/tvOS/watchOS simulator, os.uname returns the architecture as -+ # uname.machine. On device it returns the model name for some reason; but -+ # there's only one CPU architecture for devices, so we know the right -+ # answer. - def get_ios(): - if sys.implementation._multiarch.endswith("simulator"): - return os.uname().machine - return 'arm64' - -+ def get_tvos(): -+ if sys.implementation._multiarch.endswith("simulator"): -+ return os.uname().machine -+ return 'arm64' -+ -+ def get_watchos(): -+ if sys.implementation._multiarch.endswith("simulator"): -+ return os.uname().machine -+ return 'arm64_32' -+ - def from_subprocess(): - """ - Fall back to `uname -p` -@@ -1051,9 +1110,13 @@ - system = 'Android' - release = android_ver().release - -- # Normalize responses on iOS -+ # Normalize responses on Apple mobile platforms - if sys.platform == 'ios': - system, release, _, _ = ios_ver() -+ if sys.platform == 'tvos': -+ system, release, _, _ = tvos_ver() -+ if sys.platform == 'watchos': -+ system, release, _, _ = watchos_ver() - - vals = system, node, release, version, machine - # Replace 'unknown' values with the more portable '' -@@ -1343,6 +1406,10 @@ - # macOS and iOS both report as a "Darwin" kernel - if sys.platform == "ios": - system, release, _, _ = ios_ver() -+ elif sys.platform == "tvos": -+ system, release, _, _ = tvos_ver() -+ elif sys.platform == "watchos": -+ system, release, _, _ = watchos_ver() - else: - macos_release = mac_ver()[0] - if macos_release: -diff --git a/Lib/pstats.py b/Lib/pstats.py -index 46e18fb7592..becaf35580e 100644 ---- a/Lib/pstats.py -+++ b/Lib/pstats.py -@@ -29,7 +29,6 @@ - from enum import StrEnum, _simple_enum - from functools import cmp_to_key - from dataclasses import dataclass --from typing import Dict - - __all__ = ["Stats", "SortKey", "FunctionProfile", "StatsProfile"] - -@@ -69,7 +68,7 @@ - class StatsProfile: - '''Class for keeping track of an item in inventory.''' - total_tt: float -- func_profiles: Dict[str, FunctionProfile] -+ func_profiles: dict[str, FunctionProfile] - - class Stats: - """This class is used for creating reports from data generated by the -diff --git a/Lib/pydoc.py b/Lib/pydoc.py -index c863794ea14..1839b88fec2 100644 ---- a/Lib/pydoc.py -+++ b/Lib/pydoc.py -@@ -53,6 +53,7 @@ - # the current directory is changed with os.chdir(), an incorrect - # path will be displayed. - -+import ast - import __future__ - import builtins - import importlib._bootstrap -@@ -244,7 +245,7 @@ - if necessary) or module.""" - if '.' in object.__qualname__: - name = object.__qualname__.rpartition('.')[0] -- if object.__module__ != modname: -+ if object.__module__ != modname and object.__module__ is not None: - return object.__module__ + '.' + name - else: - return name -@@ -384,21 +385,29 @@ - return False - - def source_synopsis(file): -- line = file.readline() -- while line[:1] == '#' or not line.strip(): -- line = file.readline() -- if not line: break -- line = line.strip() -- if line[:4] == 'r"""': line = line[1:] -- if line[:3] == '"""': -- line = line[3:] -- if line[-1:] == '\\': line = line[:-1] -- while not line.strip(): -- line = file.readline() -- if not line: break -- result = line.split('"""')[0].strip() -- else: result = None -- return result -+ """Return the one-line summary of a file object, if present""" -+ -+ string = '' -+ try: -+ tokens = tokenize.generate_tokens(file.readline) -+ for tok_type, tok_string, _, _, _ in tokens: -+ if tok_type == tokenize.STRING: -+ string += tok_string -+ elif tok_type == tokenize.NEWLINE: -+ with warnings.catch_warnings(): -+ # Ignore the "invalid escape sequence" warning. -+ warnings.simplefilter("ignore", SyntaxWarning) -+ docstring = ast.literal_eval(string) -+ if not isinstance(docstring, str): -+ return None -+ return docstring.strip().split('\n')[0].strip() -+ elif tok_type == tokenize.OP and tok_string in ('(', ')'): -+ string += tok_string -+ elif tok_type not in (tokenize.COMMENT, tokenize.NL, tokenize.ENCODING): -+ return None -+ except (tokenize.TokenError, UnicodeDecodeError, SyntaxError): -+ return None -+ return None - - def synopsis(filename, cache={}): - """Get the one-line summary out of a module file.""" -@@ -1426,7 +1435,8 @@ - # List the built-in subclasses, if any: - subclasses = sorted( - (str(cls.__name__) for cls in type.__subclasses__(object) -- if not cls.__name__.startswith("_") and cls.__module__ == "builtins"), -+ if (not cls.__name__.startswith("_") and -+ getattr(cls, '__module__', '') == "builtins")), - key=str.lower - ) - no_of_subclasses = len(subclasses) -diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py -index aebcef2b81d..d58f10c120a 100644 ---- a/Lib/pydoc_data/topics.py -+++ b/Lib/pydoc_data/topics.py -@@ -1,17478 +1,12795 @@ --# -*- coding: utf-8 -*- --# Autogenerated by Sphinx on Tue Dec 17 11:49:52 2024 -+# Autogenerated by Sphinx on Tue Feb 11 19:16:18 2025 - # as part of the release process. --topics = {'assert': 'The "assert" statement\n' -- '**********************\n' -- '\n' -- 'Assert statements are a convenient way to insert debugging ' -- 'assertions\n' -- 'into a program:\n' -- '\n' -- ' assert_stmt ::= "assert" expression ["," expression]\n' -- '\n' -- 'The simple form, "assert expression", is equivalent to\n' -- '\n' -- ' if __debug__:\n' -- ' if not expression: raise AssertionError\n' -- '\n' -- 'The extended form, "assert expression1, expression2", is ' -- 'equivalent to\n' -- '\n' -- ' if __debug__:\n' -- ' if not expression1: raise AssertionError(expression2)\n' -- '\n' -- 'These equivalences assume that "__debug__" and "AssertionError" ' -- 'refer\n' -- 'to the built-in variables with those names. In the current\n' -- 'implementation, the built-in variable "__debug__" is "True" under\n' -- 'normal circumstances, "False" when optimization is requested ' -- '(command\n' -- 'line option "-O"). The current code generator emits no code for ' -- 'an\n' -- '"assert" statement when optimization is requested at compile ' -- 'time.\n' -- 'Note that it is unnecessary to include the source code for the\n' -- 'expression that failed in the error message; it will be displayed ' -- 'as\n' -- 'part of the stack trace.\n' -- '\n' -- 'Assignments to "__debug__" are illegal. The value for the ' -- 'built-in\n' -- 'variable is determined when the interpreter starts.\n', -- 'assignment': 'Assignment statements\n' -- '*********************\n' -- '\n' -- 'Assignment statements are used to (re)bind names to values and ' -- 'to\n' -- 'modify attributes or items of mutable objects:\n' -- '\n' -- ' assignment_stmt ::= (target_list "=")+ (starred_expression ' -- '| yield_expression)\n' -- ' target_list ::= target ("," target)* [","]\n' -- ' target ::= identifier\n' -- ' | "(" [target_list] ")"\n' -- ' | "[" [target_list] "]"\n' -- ' | attributeref\n' -- ' | subscription\n' -- ' | slicing\n' -- ' | "*" target\n' -- '\n' -- '(See section Primaries for the syntax definitions for ' -- '*attributeref*,\n' -- '*subscription*, and *slicing*.)\n' -- '\n' -- 'An assignment statement evaluates the expression list ' -- '(remember that\n' -- 'this can be a single expression or a comma-separated list, the ' -- 'latter\n' -- 'yielding a tuple) and assigns the single resulting object to ' -- 'each of\n' -- 'the target lists, from left to right.\n' -- '\n' -- 'Assignment is defined recursively depending on the form of the ' -- 'target\n' -- '(list). When a target is part of a mutable object (an ' -- 'attribute\n' -- 'reference, subscription or slicing), the mutable object must\n' -- 'ultimately perform the assignment and decide about its ' -- 'validity, and\n' -- 'may raise an exception if the assignment is unacceptable. The ' -- 'rules\n' -- 'observed by various types and the exceptions raised are given ' -- 'with the\n' -- 'definition of the object types (see section The standard type\n' -- 'hierarchy).\n' -- '\n' -- 'Assignment of an object to a target list, optionally enclosed ' -- 'in\n' -- 'parentheses or square brackets, is recursively defined as ' -- 'follows.\n' -- '\n' -- '* If the target list is a single target with no trailing ' -- 'comma,\n' -- ' optionally in parentheses, the object is assigned to that ' -- 'target.\n' -- '\n' -- '* Else:\n' -- '\n' -- ' * If the target list contains one target prefixed with an ' -- 'asterisk,\n' -- ' called a “starred†target: The object must be an iterable ' -- 'with at\n' -- ' least as many items as there are targets in the target ' -- 'list, minus\n' -- ' one. The first items of the iterable are assigned, from ' -- 'left to\n' -- ' right, to the targets before the starred target. The ' -- 'final items\n' -- ' of the iterable are assigned to the targets after the ' -- 'starred\n' -- ' target. A list of the remaining items in the iterable is ' -- 'then\n' -- ' assigned to the starred target (the list can be empty).\n' -- '\n' -- ' * Else: The object must be an iterable with the same number ' -- 'of items\n' -- ' as there are targets in the target list, and the items ' -- 'are\n' -- ' assigned, from left to right, to the corresponding ' -- 'targets.\n' -- '\n' -- 'Assignment of an object to a single target is recursively ' -- 'defined as\n' -- 'follows.\n' -- '\n' -- '* If the target is an identifier (name):\n' -- '\n' -- ' * If the name does not occur in a "global" or "nonlocal" ' -- 'statement\n' -- ' in the current code block: the name is bound to the object ' -- 'in the\n' -- ' current local namespace.\n' -- '\n' -- ' * Otherwise: the name is bound to the object in the global ' -- 'namespace\n' -- ' or the outer namespace determined by "nonlocal", ' -- 'respectively.\n' -- '\n' -- ' The name is rebound if it was already bound. This may cause ' -- 'the\n' -- ' reference count for the object previously bound to the name ' -- 'to reach\n' -- ' zero, causing the object to be deallocated and its ' -- 'destructor (if it\n' -- ' has one) to be called.\n' -- '\n' -- '* If the target is an attribute reference: The primary ' -- 'expression in\n' -- ' the reference is evaluated. It should yield an object with\n' -- ' assignable attributes; if this is not the case, "TypeError" ' -- 'is\n' -- ' raised. That object is then asked to assign the assigned ' -- 'object to\n' -- ' the given attribute; if it cannot perform the assignment, it ' -- 'raises\n' -- ' an exception (usually but not necessarily ' -- '"AttributeError").\n' -- '\n' -- ' Note: If the object is a class instance and the attribute ' -- 'reference\n' -- ' occurs on both sides of the assignment operator, the ' -- 'right-hand side\n' -- ' expression, "a.x" can access either an instance attribute or ' -- '(if no\n' -- ' instance attribute exists) a class attribute. The left-hand ' -- 'side\n' -- ' target "a.x" is always set as an instance attribute, ' -- 'creating it if\n' -- ' necessary. Thus, the two occurrences of "a.x" do not ' -- 'necessarily\n' -- ' refer to the same attribute: if the right-hand side ' -- 'expression\n' -- ' refers to a class attribute, the left-hand side creates a ' -- 'new\n' -- ' instance attribute as the target of the assignment:\n' -- '\n' -- ' class Cls:\n' -- ' x = 3 # class variable\n' -- ' inst = Cls()\n' -- ' inst.x = inst.x + 1 # writes inst.x as 4 leaving Cls.x ' -- 'as 3\n' -- '\n' -- ' This description does not necessarily apply to descriptor\n' -- ' attributes, such as properties created with "property()".\n' -- '\n' -- '* If the target is a subscription: The primary expression in ' -- 'the\n' -- ' reference is evaluated. It should yield either a mutable ' -- 'sequence\n' -- ' object (such as a list) or a mapping object (such as a ' -- 'dictionary).\n' -- ' Next, the subscript expression is evaluated.\n' -- '\n' -- ' If the primary is a mutable sequence object (such as a ' -- 'list), the\n' -- ' subscript must yield an integer. If it is negative, the ' -- 'sequence’s\n' -- ' length is added to it. The resulting value must be a ' -- 'nonnegative\n' -- ' integer less than the sequence’s length, and the sequence is ' -- 'asked\n' -- ' to assign the assigned object to its item with that index. ' -- 'If the\n' -- ' index is out of range, "IndexError" is raised (assignment to ' -- 'a\n' -- ' subscripted sequence cannot add new items to a list).\n' -- '\n' -- ' If the primary is a mapping object (such as a dictionary), ' -- 'the\n' -- ' subscript must have a type compatible with the mapping’s key ' -- 'type,\n' -- ' and the mapping is then asked to create a key/value pair ' -- 'which maps\n' -- ' the subscript to the assigned object. This can either ' -- 'replace an\n' -- ' existing key/value pair with the same key value, or insert a ' -- 'new\n' -- ' key/value pair (if no key with the same value existed).\n' -- '\n' -- ' For user-defined objects, the "__setitem__()" method is ' -- 'called with\n' -- ' appropriate arguments.\n' -- '\n' -- '* If the target is a slicing: The primary expression in the ' -- 'reference\n' -- ' is evaluated. It should yield a mutable sequence object ' -- '(such as a\n' -- ' list). The assigned object should be a sequence object of ' -- 'the same\n' -- ' type. Next, the lower and upper bound expressions are ' -- 'evaluated,\n' -- ' insofar they are present; defaults are zero and the ' -- 'sequence’s\n' -- ' length. The bounds should evaluate to integers. If either ' -- 'bound is\n' -- ' negative, the sequence’s length is added to it. The ' -- 'resulting\n' -- ' bounds are clipped to lie between zero and the sequence’s ' -- 'length,\n' -- ' inclusive. Finally, the sequence object is asked to replace ' -- 'the\n' -- ' slice with the items of the assigned sequence. The length ' -- 'of the\n' -- ' slice may be different from the length of the assigned ' -- 'sequence,\n' -- ' thus changing the length of the target sequence, if the ' -- 'target\n' -- ' sequence allows it.\n' -- '\n' -- '**CPython implementation detail:** In the current ' -- 'implementation, the\n' -- 'syntax for targets is taken to be the same as for expressions, ' -- 'and\n' -- 'invalid syntax is rejected during the code generation phase, ' -- 'causing\n' -- 'less detailed error messages.\n' -- '\n' -- 'Although the definition of assignment implies that overlaps ' -- 'between\n' -- 'the left-hand side and the right-hand side are ‘simultaneous’ ' -- '(for\n' -- 'example "a, b = b, a" swaps two variables), overlaps *within* ' -- 'the\n' -- 'collection of assigned-to variables occur left-to-right, ' -- 'sometimes\n' -- 'resulting in confusion. For instance, the following program ' -- 'prints\n' -- '"[0, 2]":\n' -- '\n' -- ' x = [0, 1]\n' -- ' i = 0\n' -- ' i, x[i] = 1, 2 # i is updated, then x[i] is ' -- 'updated\n' -- ' print(x)\n' -- '\n' -- 'See also:\n' -- '\n' -- ' **PEP 3132** - Extended Iterable Unpacking\n' -- ' The specification for the "*target" feature.\n' -- '\n' -- '\n' -- 'Augmented assignment statements\n' -- '===============================\n' -- '\n' -- 'Augmented assignment is the combination, in a single ' -- 'statement, of a\n' -- 'binary operation and an assignment statement:\n' -- '\n' -- ' augmented_assignment_stmt ::= augtarget augop ' -- '(expression_list | yield_expression)\n' -- ' augtarget ::= identifier | attributeref | ' -- 'subscription | slicing\n' -- ' augop ::= "+=" | "-=" | "*=" | "@=" | ' -- '"/=" | "//=" | "%=" | "**="\n' -- ' | ">>=" | "<<=" | "&=" | "^=" | "|="\n' -- '\n' -- '(See section Primaries for the syntax definitions of the last ' -- 'three\n' -- 'symbols.)\n' -- '\n' -- 'An augmented assignment evaluates the target (which, unlike ' -- 'normal\n' -- 'assignment statements, cannot be an unpacking) and the ' -- 'expression\n' -- 'list, performs the binary operation specific to the type of ' -- 'assignment\n' -- 'on the two operands, and assigns the result to the original ' -- 'target.\n' -- 'The target is only evaluated once.\n' -- '\n' -- 'An augmented assignment statement like "x += 1" can be ' -- 'rewritten as "x\n' -- '= x + 1" to achieve a similar, but not exactly equal effect. ' -- 'In the\n' -- 'augmented version, "x" is only evaluated once. Also, when ' -- 'possible,\n' -- 'the actual operation is performed *in-place*, meaning that ' -- 'rather than\n' -- 'creating a new object and assigning that to the target, the ' -- 'old object\n' -- 'is modified instead.\n' -- '\n' -- 'Unlike normal assignments, augmented assignments evaluate the ' -- 'left-\n' -- 'hand side *before* evaluating the right-hand side. For ' -- 'example, "a[i]\n' -- '+= f(x)" first looks-up "a[i]", then it evaluates "f(x)" and ' -- 'performs\n' -- 'the addition, and lastly, it writes the result back to ' -- '"a[i]".\n' -- '\n' -- 'With the exception of assigning to tuples and multiple targets ' -- 'in a\n' -- 'single statement, the assignment done by augmented assignment\n' -- 'statements is handled the same way as normal assignments. ' -- 'Similarly,\n' -- 'with the exception of the possible *in-place* behavior, the ' -- 'binary\n' -- 'operation performed by augmented assignment is the same as the ' -- 'normal\n' -- 'binary operations.\n' -- '\n' -- 'For targets which are attribute references, the same caveat ' -- 'about\n' -- 'class and instance attributes applies as for regular ' -- 'assignments.\n' -- '\n' -- '\n' -- 'Annotated assignment statements\n' -- '===============================\n' -- '\n' -- '*Annotation* assignment is the combination, in a single ' -- 'statement, of\n' -- 'a variable or attribute annotation and an optional assignment\n' -- 'statement:\n' -- '\n' -- ' annotated_assignment_stmt ::= augtarget ":" expression\n' -- ' ["=" (starred_expression | ' -- 'yield_expression)]\n' -- '\n' -- 'The difference from normal Assignment statements is that only ' -- 'a single\n' -- 'target is allowed.\n' -- '\n' -- 'The assignment target is considered “simple†if it consists of ' -- 'a\n' -- 'single name that is not enclosed in parentheses. For simple ' -- 'assignment\n' -- 'targets, if in class or module scope, the annotations are ' -- 'gathered in\n' -- 'a lazily evaluated annotation scope. The annotations can be ' -- 'evaluated\n' -- 'using the "__annotations__" attribute of a class or module, or ' -- 'using\n' -- 'the facilities in the "annotationlib" module.\n' -- '\n' -- 'If the assignment target is not simple (an attribute, ' -- 'subscript node,\n' -- 'or parenthesized name), the annotation is never evaluated.\n' -- '\n' -- 'If a name is annotated in a function scope, then this name is ' -- 'local\n' -- 'for that scope. Annotations are never evaluated and stored in ' -- 'function\n' -- 'scopes.\n' -- '\n' -- 'If the right hand side is present, an annotated assignment ' -- 'performs\n' -- 'the actual assignment as if there was no annotation present. ' -- 'If the\n' -- 'right hand side is not present for an expression target, then ' -- 'the\n' -- 'interpreter evaluates the target except for the last ' -- '"__setitem__()"\n' -- 'or "__setattr__()" call.\n' -- '\n' -- 'See also:\n' -- '\n' -- ' **PEP 526** - Syntax for Variable Annotations\n' -- ' The proposal that added syntax for annotating the types ' -- 'of\n' -- ' variables (including class variables and instance ' -- 'variables),\n' -- ' instead of expressing them through comments.\n' -- '\n' -- ' **PEP 484** - Type hints\n' -- ' The proposal that added the "typing" module to provide a ' -- 'standard\n' -- ' syntax for type annotations that can be used in static ' -- 'analysis\n' -- ' tools and IDEs.\n' -- '\n' -- 'Changed in version 3.8: Now annotated assignments allow the ' -- 'same\n' -- 'expressions in the right hand side as regular assignments. ' -- 'Previously,\n' -- 'some expressions (like un-parenthesized tuple expressions) ' -- 'caused a\n' -- 'syntax error.\n' -- '\n' -- 'Changed in version 3.14: Annotations are now lazily evaluated ' -- 'in a\n' -- 'separate annotation scope. If the assignment target is not ' -- 'simple,\n' -- 'annotations are never evaluated.\n', -- 'assignment-expressions': 'Assignment expressions\n' -- '**********************\n' -- '\n' -- ' assignment_expression ::= [identifier ":="] ' -- 'expression\n' -- '\n' -- 'An assignment expression (sometimes also called a ' -- '“named expressionâ€\n' -- 'or “walrusâ€) assigns an "expression" to an ' -- '"identifier", while also\n' -- 'returning the value of the "expression".\n' -- '\n' -- 'One common use case is when handling matched ' -- 'regular expressions:\n' -- '\n' -- ' if matching := pattern.search(data):\n' -- ' do_something(matching)\n' -- '\n' -- 'Or, when processing a file stream in chunks:\n' -- '\n' -- ' while chunk := file.read(9000):\n' -- ' process(chunk)\n' -- '\n' -- 'Assignment expressions must be surrounded by ' -- 'parentheses when used as\n' -- 'expression statements and when used as ' -- 'sub-expressions in slicing,\n' -- 'conditional, lambda, keyword-argument, and ' -- 'comprehension-if\n' -- 'expressions and in "assert", "with", and ' -- '"assignment" statements. In\n' -- 'all other places where they can be used, ' -- 'parentheses are not required,\n' -- 'including in "if" and "while" statements.\n' -- '\n' -- 'Added in version 3.8: See **PEP 572** for more ' -- 'details about\n' -- 'assignment expressions.\n', -- 'async': 'Coroutines\n' -- '**********\n' -- '\n' -- 'Added in version 3.5.\n' -- '\n' -- '\n' -- 'Coroutine function definition\n' -- '=============================\n' -- '\n' -- ' async_funcdef ::= [decorators] "async" "def" funcname "(" ' -- '[parameter_list] ")"\n' -- ' ["->" expression] ":" suite\n' -- '\n' -- 'Execution of Python coroutines can be suspended and resumed at ' -- 'many\n' -- 'points (see *coroutine*). "await" expressions, "async for" and ' -- '"async\n' -- 'with" can only be used in the body of a coroutine function.\n' -- '\n' -- 'Functions defined with "async def" syntax are always coroutine\n' -- 'functions, even if they do not contain "await" or "async" ' -- 'keywords.\n' -- '\n' -- 'It is a "SyntaxError" to use a "yield from" expression inside the ' -- 'body\n' -- 'of a coroutine function.\n' -- '\n' -- 'An example of a coroutine function:\n' -- '\n' -- ' async def func(param1, param2):\n' -- ' do_stuff()\n' -- ' await some_coroutine()\n' -- '\n' -- 'Changed in version 3.7: "await" and "async" are now keywords;\n' -- 'previously they were only treated as such inside the body of a\n' -- 'coroutine function.\n' -- '\n' -- '\n' -- 'The "async for" statement\n' -- '=========================\n' -- '\n' -- ' async_for_stmt ::= "async" for_stmt\n' -- '\n' -- 'An *asynchronous iterable* provides an "__aiter__" method that\n' -- 'directly returns an *asynchronous iterator*, which can call\n' -- 'asynchronous code in its "__anext__" method.\n' -- '\n' -- 'The "async for" statement allows convenient iteration over\n' -- 'asynchronous iterables.\n' -- '\n' -- 'The following code:\n' -- '\n' -- ' async for TARGET in ITER:\n' -- ' SUITE\n' -- ' else:\n' -- ' SUITE2\n' -- '\n' -- 'Is semantically equivalent to:\n' -- '\n' -- ' iter = (ITER)\n' -- ' iter = type(iter).__aiter__(iter)\n' -- ' running = True\n' -- '\n' -- ' while running:\n' -- ' try:\n' -- ' TARGET = await type(iter).__anext__(iter)\n' -- ' except StopAsyncIteration:\n' -- ' running = False\n' -- ' else:\n' -- ' SUITE\n' -- ' else:\n' -- ' SUITE2\n' -- '\n' -- 'See also "__aiter__()" and "__anext__()" for details.\n' -- '\n' -- 'It is a "SyntaxError" to use an "async for" statement outside the ' -- 'body\n' -- 'of a coroutine function.\n' -- '\n' -- '\n' -- 'The "async with" statement\n' -- '==========================\n' -- '\n' -- ' async_with_stmt ::= "async" with_stmt\n' -- '\n' -- 'An *asynchronous context manager* is a *context manager* that is ' -- 'able\n' -- 'to suspend execution in its *enter* and *exit* methods.\n' -- '\n' -- 'The following code:\n' -- '\n' -- ' async with EXPRESSION as TARGET:\n' -- ' SUITE\n' -- '\n' -- 'is semantically equivalent to:\n' -- '\n' -- ' manager = (EXPRESSION)\n' -- ' aenter = type(manager).__aenter__\n' -- ' aexit = type(manager).__aexit__\n' -- ' value = await aenter(manager)\n' -- ' hit_except = False\n' -- '\n' -- ' try:\n' -- ' TARGET = value\n' -- ' SUITE\n' -- ' except:\n' -- ' hit_except = True\n' -- ' if not await aexit(manager, *sys.exc_info()):\n' -- ' raise\n' -- ' finally:\n' -- ' if not hit_except:\n' -- ' await aexit(manager, None, None, None)\n' -- '\n' -- 'See also "__aenter__()" and "__aexit__()" for details.\n' -- '\n' -- 'It is a "SyntaxError" to use an "async with" statement outside the\n' -- 'body of a coroutine function.\n' -- '\n' -- 'See also:\n' -- '\n' -- ' **PEP 492** - Coroutines with async and await syntax\n' -- ' The proposal that made coroutines a proper standalone concept ' -- 'in\n' -- ' Python, and added supporting syntax.\n', -- 'atom-identifiers': 'Identifiers (Names)\n' -- '*******************\n' -- '\n' -- 'An identifier occurring as an atom is a name. See ' -- 'section Identifiers\n' -- 'and keywords for lexical definition and section Naming ' -- 'and binding for\n' -- 'documentation of naming and binding.\n' -- '\n' -- 'When the name is bound to an object, evaluation of the ' -- 'atom yields\n' -- 'that object. When a name is not bound, an attempt to ' -- 'evaluate it\n' -- 'raises a "NameError" exception.\n' -- '\n' -- '\n' -- 'Private name mangling\n' -- '=====================\n' -- '\n' -- 'When an identifier that textually occurs in a class ' -- 'definition begins\n' -- 'with two or more underscore characters and does not end ' -- 'in two or more\n' -- 'underscores, it is considered a *private name* of that ' -- 'class.\n' -- '\n' -- 'See also: The class specifications.\n' -- '\n' -- 'More precisely, private names are transformed to a ' -- 'longer form before\n' -- 'code is generated for them. If the transformed name is ' -- 'longer than\n' -- '255 characters, implementation-defined truncation may ' -- 'happen.\n' -- '\n' -- 'The transformation is independent of the syntactical ' -- 'context in which\n' -- 'the identifier is used but only the following private ' -- 'identifiers are\n' -- 'mangled:\n' -- '\n' -- '* Any name used as the name of a variable that is ' -- 'assigned or read or\n' -- ' any name of an attribute being accessed.\n' -- '\n' -- ' The "__name__" attribute of nested functions, classes, ' -- 'and type\n' -- ' aliases is however not mangled.\n' -- '\n' -- '* The name of imported modules, e.g., "__spam" in ' -- '"import __spam". If\n' -- ' the module is part of a package (i.e., its name ' -- 'contains a dot), the\n' -- ' name is *not* mangled, e.g., the "__foo" in "import ' -- '__foo.bar" is\n' -- ' not mangled.\n' -- '\n' -- '* The name of an imported member, e.g., "__f" in "from ' -- 'spam import\n' -- ' __f".\n' -- '\n' -- 'The transformation rule is defined as follows:\n' -- '\n' -- '* The class name, with leading underscores removed and a ' -- 'single\n' -- ' leading underscore inserted, is inserted in front of ' -- 'the identifier,\n' -- ' e.g., the identifier "__spam" occurring in a class ' -- 'named "Foo",\n' -- ' "_Foo" or "__Foo" is transformed to "_Foo__spam".\n' -- '\n' -- '* If the class name consists only of underscores, the ' -- 'transformation\n' -- ' is the identity, e.g., the identifier "__spam" ' -- 'occurring in a class\n' -- ' named "_" or "__" is left as is.\n', -- 'atom-literals': 'Literals\n' -- '********\n' -- '\n' -- 'Python supports string and bytes literals and various ' -- 'numeric\n' -- 'literals:\n' -- '\n' -- ' literal ::= stringliteral | bytesliteral\n' -- ' | integer | floatnumber | imagnumber\n' -- '\n' -- 'Evaluation of a literal yields an object of the given type ' -- '(string,\n' -- 'bytes, integer, floating-point number, complex number) with ' -- 'the given\n' -- 'value. The value may be approximated in the case of ' -- 'floating-point\n' -- 'and imaginary (complex) literals. See section Literals for ' -- 'details.\n' -- '\n' -- 'All literals correspond to immutable data types, and hence ' -- 'the\n' -- 'object’s identity is less important than its value. ' -- 'Multiple\n' -- 'evaluations of literals with the same value (either the ' -- 'same\n' -- 'occurrence in the program text or a different occurrence) ' -- 'may obtain\n' -- 'the same object or a different object with the same ' -- 'value.\n', -- 'attribute-access': 'Customizing attribute access\n' -- '****************************\n' -- '\n' -- 'The following methods can be defined to customize the ' -- 'meaning of\n' -- 'attribute access (use of, assignment to, or deletion of ' -- '"x.name") for\n' -- 'class instances.\n' -- '\n' -- 'object.__getattr__(self, name)\n' -- '\n' -- ' Called when the default attribute access fails with ' -- 'an\n' -- ' "AttributeError" (either "__getattribute__()" raises ' -- 'an\n' -- ' "AttributeError" because *name* is not an instance ' -- 'attribute or an\n' -- ' attribute in the class tree for "self"; or ' -- '"__get__()" of a *name*\n' -- ' property raises "AttributeError"). This method ' -- 'should either\n' -- ' return the (computed) attribute value or raise an ' -- '"AttributeError"\n' -- ' exception. The "object" class itself does not provide ' -- 'this method.\n' -- '\n' -- ' Note that if the attribute is found through the ' -- 'normal mechanism,\n' -- ' "__getattr__()" is not called. (This is an ' -- 'intentional asymmetry\n' -- ' between "__getattr__()" and "__setattr__()".) This is ' -- 'done both for\n' -- ' efficiency reasons and because otherwise ' -- '"__getattr__()" would have\n' -- ' no way to access other attributes of the instance. ' -- 'Note that at\n' -- ' least for instance variables, you can take total ' -- 'control by not\n' -- ' inserting any values in the instance attribute ' -- 'dictionary (but\n' -- ' instead inserting them in another object). See the\n' -- ' "__getattribute__()" method below for a way to ' -- 'actually get total\n' -- ' control over attribute access.\n' -- '\n' -- 'object.__getattribute__(self, name)\n' -- '\n' -- ' Called unconditionally to implement attribute ' -- 'accesses for\n' -- ' instances of the class. If the class also defines ' -- '"__getattr__()",\n' -- ' the latter will not be called unless ' -- '"__getattribute__()" either\n' -- ' calls it explicitly or raises an "AttributeError". ' -- 'This method\n' -- ' should return the (computed) attribute value or raise ' -- 'an\n' -- ' "AttributeError" exception. In order to avoid ' -- 'infinite recursion in\n' -- ' this method, its implementation should always call ' -- 'the base class\n' -- ' method with the same name to access any attributes it ' -- 'needs, for\n' -- ' example, "object.__getattribute__(self, name)".\n' -- '\n' -- ' Note:\n' -- '\n' -- ' This method may still be bypassed when looking up ' -- 'special methods\n' -- ' as the result of implicit invocation via language ' -- 'syntax or\n' -- ' built-in functions. See Special method lookup.\n' -- '\n' -- ' For certain sensitive attribute accesses, raises an ' -- 'auditing event\n' -- ' "object.__getattr__" with arguments "obj" and ' -- '"name".\n' -- '\n' -- 'object.__setattr__(self, name, value)\n' -- '\n' -- ' Called when an attribute assignment is attempted. ' -- 'This is called\n' -- ' instead of the normal mechanism (i.e. store the value ' -- 'in the\n' -- ' instance dictionary). *name* is the attribute name, ' -- '*value* is the\n' -- ' value to be assigned to it.\n' -- '\n' -- ' If "__setattr__()" wants to assign to an instance ' -- 'attribute, it\n' -- ' should call the base class method with the same name, ' -- 'for example,\n' -- ' "object.__setattr__(self, name, value)".\n' -- '\n' -- ' For certain sensitive attribute assignments, raises ' -- 'an auditing\n' -- ' event "object.__setattr__" with arguments "obj", ' -- '"name", "value".\n' -- '\n' -- 'object.__delattr__(self, name)\n' -- '\n' -- ' Like "__setattr__()" but for attribute deletion ' -- 'instead of\n' -- ' assignment. This should only be implemented if "del ' -- 'obj.name" is\n' -- ' meaningful for the object.\n' -- '\n' -- ' For certain sensitive attribute deletions, raises an ' -- 'auditing event\n' -- ' "object.__delattr__" with arguments "obj" and ' -- '"name".\n' -- '\n' -- 'object.__dir__(self)\n' -- '\n' -- ' Called when "dir()" is called on the object. An ' -- 'iterable must be\n' -- ' returned. "dir()" converts the returned iterable to a ' -- 'list and\n' -- ' sorts it.\n' -- '\n' -- '\n' -- 'Customizing module attribute access\n' -- '===================================\n' -- '\n' -- 'Special names "__getattr__" and "__dir__" can be also ' -- 'used to\n' -- 'customize access to module attributes. The "__getattr__" ' -- 'function at\n' -- 'the module level should accept one argument which is the ' -- 'name of an\n' -- 'attribute and return the computed value or raise an ' -- '"AttributeError".\n' -- 'If an attribute is not found on a module object through ' -- 'the normal\n' -- 'lookup, i.e. "object.__getattribute__()", then ' -- '"__getattr__" is\n' -- 'searched in the module "__dict__" before raising an ' -- '"AttributeError".\n' -- 'If found, it is called with the attribute name and the ' -- 'result is\n' -- 'returned.\n' -- '\n' -- 'The "__dir__" function should accept no arguments, and ' -- 'return an\n' -- 'iterable of strings that represents the names accessible ' -- 'on module. If\n' -- 'present, this function overrides the standard "dir()" ' -- 'search on a\n' -- 'module.\n' -- '\n' -- 'For a more fine grained customization of the module ' -- 'behavior (setting\n' -- 'attributes, properties, etc.), one can set the ' -- '"__class__" attribute\n' -- 'of a module object to a subclass of "types.ModuleType". ' -- 'For example:\n' -- '\n' -- ' import sys\n' -- ' from types import ModuleType\n' -- '\n' -- ' class VerboseModule(ModuleType):\n' -- ' def __repr__(self):\n' -- " return f'Verbose {self.__name__}'\n" -- '\n' -- ' def __setattr__(self, attr, value):\n' -- " print(f'Setting {attr}...')\n" -- ' super().__setattr__(attr, value)\n' -- '\n' -- ' sys.modules[__name__].__class__ = VerboseModule\n' -- '\n' -- 'Note:\n' -- '\n' -- ' Defining module "__getattr__" and setting module ' -- '"__class__" only\n' -- ' affect lookups made using the attribute access syntax ' -- '– directly\n' -- ' accessing the module globals (whether by code within ' -- 'the module, or\n' -- ' via a reference to the module’s globals dictionary) is ' -- 'unaffected.\n' -- '\n' -- 'Changed in version 3.5: "__class__" module attribute is ' -- 'now writable.\n' -- '\n' -- 'Added in version 3.7: "__getattr__" and "__dir__" module ' -- 'attributes.\n' -- '\n' -- 'See also:\n' -- '\n' -- ' **PEP 562** - Module __getattr__ and __dir__\n' -- ' Describes the "__getattr__" and "__dir__" functions ' -- 'on modules.\n' -- '\n' -- '\n' -- 'Implementing Descriptors\n' -- '========================\n' -- '\n' -- 'The following methods only apply when an instance of the ' -- 'class\n' -- 'containing the method (a so-called *descriptor* class) ' -- 'appears in an\n' -- '*owner* class (the descriptor must be in either the ' -- 'owner’s class\n' -- 'dictionary or in the class dictionary for one of its ' -- 'parents). In the\n' -- 'examples below, “the attribute†refers to the attribute ' -- 'whose name is\n' -- 'the key of the property in the owner class’ "__dict__". ' -- 'The "object"\n' -- 'class itself does not implement any of these protocols.\n' -- '\n' -- 'object.__get__(self, instance, owner=None)\n' -- '\n' -- ' Called to get the attribute of the owner class (class ' -- 'attribute\n' -- ' access) or of an instance of that class (instance ' -- 'attribute\n' -- ' access). The optional *owner* argument is the owner ' -- 'class, while\n' -- ' *instance* is the instance that the attribute was ' -- 'accessed through,\n' -- ' or "None" when the attribute is accessed through the ' -- '*owner*.\n' -- '\n' -- ' This method should return the computed attribute ' -- 'value or raise an\n' -- ' "AttributeError" exception.\n' -- '\n' -- ' **PEP 252** specifies that "__get__()" is callable ' -- 'with one or two\n' -- ' arguments. Python’s own built-in descriptors support ' -- 'this\n' -- ' specification; however, it is likely that some ' -- 'third-party tools\n' -- ' have descriptors that require both arguments. ' -- 'Python’s own\n' -- ' "__getattribute__()" implementation always passes in ' -- 'both arguments\n' -- ' whether they are required or not.\n' -- '\n' -- 'object.__set__(self, instance, value)\n' -- '\n' -- ' Called to set the attribute on an instance *instance* ' -- 'of the owner\n' -- ' class to a new value, *value*.\n' -- '\n' -- ' Note, adding "__set__()" or "__delete__()" changes ' -- 'the kind of\n' -- ' descriptor to a “data descriptorâ€. See Invoking ' -- 'Descriptors for\n' -- ' more details.\n' -- '\n' -- 'object.__delete__(self, instance)\n' -- '\n' -- ' Called to delete the attribute on an instance ' -- '*instance* of the\n' -- ' owner class.\n' -- '\n' -- 'Instances of descriptors may also have the ' -- '"__objclass__" attribute\n' -- 'present:\n' -- '\n' -- 'object.__objclass__\n' -- '\n' -- ' The attribute "__objclass__" is interpreted by the ' -- '"inspect" module\n' -- ' as specifying the class where this object was defined ' -- '(setting this\n' -- ' appropriately can assist in runtime introspection of ' -- 'dynamic class\n' -- ' attributes). For callables, it may indicate that an ' -- 'instance of the\n' -- ' given type (or a subclass) is expected or required as ' -- 'the first\n' -- ' positional argument (for example, CPython sets this ' -- 'attribute for\n' -- ' unbound methods that are implemented in C).\n' -- '\n' -- '\n' -- 'Invoking Descriptors\n' -- '====================\n' -- '\n' -- 'In general, a descriptor is an object attribute with ' -- '“binding\n' -- 'behaviorâ€, one whose attribute access has been ' -- 'overridden by methods\n' -- 'in the descriptor protocol: "__get__()", "__set__()", ' -- 'and\n' -- '"__delete__()". If any of those methods are defined for ' -- 'an object, it\n' -- 'is said to be a descriptor.\n' -- '\n' -- 'The default behavior for attribute access is to get, ' -- 'set, or delete\n' -- 'the attribute from an object’s dictionary. For instance, ' -- '"a.x" has a\n' -- 'lookup chain starting with "a.__dict__[\'x\']", then\n' -- '"type(a).__dict__[\'x\']", and continuing through the ' -- 'base classes of\n' -- '"type(a)" excluding metaclasses.\n' -- '\n' -- 'However, if the looked-up value is an object defining ' -- 'one of the\n' -- 'descriptor methods, then Python may override the default ' -- 'behavior and\n' -- 'invoke the descriptor method instead. Where this occurs ' -- 'in the\n' -- 'precedence chain depends on which descriptor methods ' -- 'were defined and\n' -- 'how they were called.\n' -- '\n' -- 'The starting point for descriptor invocation is a ' -- 'binding, "a.x". How\n' -- 'the arguments are assembled depends on "a":\n' -- '\n' -- 'Direct Call\n' -- ' The simplest and least common call is when user code ' -- 'directly\n' -- ' invokes a descriptor method: "x.__get__(a)".\n' -- '\n' -- 'Instance Binding\n' -- ' If binding to an object instance, "a.x" is ' -- 'transformed into the\n' -- ' call: "type(a).__dict__[\'x\'].__get__(a, type(a))".\n' -- '\n' -- 'Class Binding\n' -- ' If binding to a class, "A.x" is transformed into the ' -- 'call:\n' -- ' "A.__dict__[\'x\'].__get__(None, A)".\n' -- '\n' -- 'Super Binding\n' -- ' A dotted lookup such as "super(A, a).x" searches\n' -- ' "a.__class__.__mro__" for a base class "B" following ' -- '"A" and then\n' -- ' returns "B.__dict__[\'x\'].__get__(a, A)". If not a ' -- 'descriptor, "x"\n' -- ' is returned unchanged.\n' -- '\n' -- 'For instance bindings, the precedence of descriptor ' -- 'invocation depends\n' -- 'on which descriptor methods are defined. A descriptor ' -- 'can define any\n' -- 'combination of "__get__()", "__set__()" and ' -- '"__delete__()". If it\n' -- 'does not define "__get__()", then accessing the ' -- 'attribute will return\n' -- 'the descriptor object itself unless there is a value in ' -- 'the object’s\n' -- 'instance dictionary. If the descriptor defines ' -- '"__set__()" and/or\n' -- '"__delete__()", it is a data descriptor; if it defines ' -- 'neither, it is\n' -- 'a non-data descriptor. Normally, data descriptors ' -- 'define both\n' -- '"__get__()" and "__set__()", while non-data descriptors ' -- 'have just the\n' -- '"__get__()" method. Data descriptors with "__get__()" ' -- 'and "__set__()"\n' -- '(and/or "__delete__()") defined always override a ' -- 'redefinition in an\n' -- 'instance dictionary. In contrast, non-data descriptors ' -- 'can be\n' -- 'overridden by instances.\n' -- '\n' -- 'Python methods (including those decorated with ' -- '"@staticmethod" and\n' -- '"@classmethod") are implemented as non-data ' -- 'descriptors. Accordingly,\n' -- 'instances can redefine and override methods. This ' -- 'allows individual\n' -- 'instances to acquire behaviors that differ from other ' -- 'instances of the\n' -- 'same class.\n' -- '\n' -- 'The "property()" function is implemented as a data ' -- 'descriptor.\n' -- 'Accordingly, instances cannot override the behavior of a ' -- 'property.\n' -- '\n' -- '\n' -- '__slots__\n' -- '=========\n' -- '\n' -- '*__slots__* allow us to explicitly declare data members ' -- '(like\n' -- 'properties) and deny the creation of "__dict__" and ' -- '*__weakref__*\n' -- '(unless explicitly declared in *__slots__* or available ' -- 'in a parent.)\n' -- '\n' -- 'The space saved over using "__dict__" can be ' -- 'significant. Attribute\n' -- 'lookup speed can be significantly improved as well.\n' -- '\n' -- 'object.__slots__\n' -- '\n' -- ' This class variable can be assigned a string, ' -- 'iterable, or sequence\n' -- ' of strings with variable names used by instances. ' -- '*__slots__*\n' -- ' reserves space for the declared variables and ' -- 'prevents the\n' -- ' automatic creation of "__dict__" and *__weakref__* ' -- 'for each\n' -- ' instance.\n' -- '\n' -- 'Notes on using *__slots__*:\n' -- '\n' -- '* When inheriting from a class without *__slots__*, the ' -- '"__dict__" and\n' -- ' *__weakref__* attribute of the instances will always ' -- 'be accessible.\n' -- '\n' -- '* Without a "__dict__" variable, instances cannot be ' -- 'assigned new\n' -- ' variables not listed in the *__slots__* definition. ' -- 'Attempts to\n' -- ' assign to an unlisted variable name raises ' -- '"AttributeError". If\n' -- ' dynamic assignment of new variables is desired, then ' -- 'add\n' -- ' "\'__dict__\'" to the sequence of strings in the ' -- '*__slots__*\n' -- ' declaration.\n' -- '\n' -- '* Without a *__weakref__* variable for each instance, ' -- 'classes defining\n' -- ' *__slots__* do not support "weak references" to its ' -- 'instances. If\n' -- ' weak reference support is needed, then add ' -- '"\'__weakref__\'" to the\n' -- ' sequence of strings in the *__slots__* declaration.\n' -- '\n' -- '* *__slots__* are implemented at the class level by ' -- 'creating\n' -- ' descriptors for each variable name. As a result, ' -- 'class attributes\n' -- ' cannot be used to set default values for instance ' -- 'variables defined\n' -- ' by *__slots__*; otherwise, the class attribute would ' -- 'overwrite the\n' -- ' descriptor assignment.\n' -- '\n' -- '* The action of a *__slots__* declaration is not limited ' -- 'to the class\n' -- ' where it is defined. *__slots__* declared in parents ' -- 'are available\n' -- ' in child classes. However, instances of a child ' -- 'subclass will get a\n' -- ' "__dict__" and *__weakref__* unless the subclass also ' -- 'defines\n' -- ' *__slots__* (which should only contain names of any ' -- '*additional*\n' -- ' slots).\n' -- '\n' -- '* If a class defines a slot also defined in a base ' -- 'class, the instance\n' -- ' variable defined by the base class slot is ' -- 'inaccessible (except by\n' -- ' retrieving its descriptor directly from the base ' -- 'class). This\n' -- ' renders the meaning of the program undefined. In the ' -- 'future, a\n' -- ' check may be added to prevent this.\n' -- '\n' -- '* "TypeError" will be raised if nonempty *__slots__* are ' -- 'defined for a\n' -- ' class derived from a ""variable-length" built-in type" ' -- 'such as\n' -- ' "int", "bytes", and "tuple".\n' -- '\n' -- '* Any non-string *iterable* may be assigned to ' -- '*__slots__*.\n' -- '\n' -- '* If a "dictionary" is used to assign *__slots__*, the ' -- 'dictionary keys\n' -- ' will be used as the slot names. The values of the ' -- 'dictionary can be\n' -- ' used to provide per-attribute docstrings that will be ' -- 'recognised by\n' -- ' "inspect.getdoc()" and displayed in the output of ' -- '"help()".\n' -- '\n' -- '* "__class__" assignment works only if both classes have ' -- 'the same\n' -- ' *__slots__*.\n' -- '\n' -- '* Multiple inheritance with multiple slotted parent ' -- 'classes can be\n' -- ' used, but only one parent is allowed to have ' -- 'attributes created by\n' -- ' slots (the other bases must have empty slot layouts) - ' -- 'violations\n' -- ' raise "TypeError".\n' -- '\n' -- '* If an *iterator* is used for *__slots__* then a ' -- '*descriptor* is\n' -- ' created for each of the iterator’s values. However, ' -- 'the *__slots__*\n' -- ' attribute will be an empty iterator.\n', -- 'attribute-references': 'Attribute references\n' -- '********************\n' -- '\n' -- 'An attribute reference is a primary followed by a ' -- 'period and a name:\n' -- '\n' -- ' attributeref ::= primary "." identifier\n' -- '\n' -- 'The primary must evaluate to an object of a type ' -- 'that supports\n' -- 'attribute references, which most objects do. This ' -- 'object is then\n' -- 'asked to produce the attribute whose name is the ' -- 'identifier. The type\n' -- 'and value produced is determined by the object. ' -- 'Multiple evaluations\n' -- 'of the same attribute reference may yield different ' -- 'objects.\n' -- '\n' -- 'This production can be customized by overriding the\n' -- '"__getattribute__()" method or the "__getattr__()" ' -- 'method. The\n' -- '"__getattribute__()" method is called first and ' -- 'either returns a value\n' -- 'or raises "AttributeError" if the attribute is not ' -- 'available.\n' -- '\n' -- 'If an "AttributeError" is raised and the object has ' -- 'a "__getattr__()"\n' -- 'method, that method is called as a fallback.\n', -- 'augassign': 'Augmented assignment statements\n' -- '*******************************\n' -- '\n' -- 'Augmented assignment is the combination, in a single statement, ' -- 'of a\n' -- 'binary operation and an assignment statement:\n' -- '\n' -- ' augmented_assignment_stmt ::= augtarget augop ' -- '(expression_list | yield_expression)\n' -- ' augtarget ::= identifier | attributeref | ' -- 'subscription | slicing\n' -- ' augop ::= "+=" | "-=" | "*=" | "@=" | ' -- '"/=" | "//=" | "%=" | "**="\n' -- ' | ">>=" | "<<=" | "&=" | "^=" | "|="\n' -- '\n' -- '(See section Primaries for the syntax definitions of the last ' -- 'three\n' -- 'symbols.)\n' -- '\n' -- 'An augmented assignment evaluates the target (which, unlike ' -- 'normal\n' -- 'assignment statements, cannot be an unpacking) and the ' -- 'expression\n' -- 'list, performs the binary operation specific to the type of ' -- 'assignment\n' -- 'on the two operands, and assigns the result to the original ' -- 'target.\n' -- 'The target is only evaluated once.\n' -- '\n' -- 'An augmented assignment statement like "x += 1" can be ' -- 'rewritten as "x\n' -- '= x + 1" to achieve a similar, but not exactly equal effect. In ' -- 'the\n' -- 'augmented version, "x" is only evaluated once. Also, when ' -- 'possible,\n' -- 'the actual operation is performed *in-place*, meaning that ' -- 'rather than\n' -- 'creating a new object and assigning that to the target, the old ' -- 'object\n' -- 'is modified instead.\n' -- '\n' -- 'Unlike normal assignments, augmented assignments evaluate the ' -- 'left-\n' -- 'hand side *before* evaluating the right-hand side. For ' -- 'example, "a[i]\n' -- '+= f(x)" first looks-up "a[i]", then it evaluates "f(x)" and ' -- 'performs\n' -- 'the addition, and lastly, it writes the result back to "a[i]".\n' -- '\n' -- 'With the exception of assigning to tuples and multiple targets ' -- 'in a\n' -- 'single statement, the assignment done by augmented assignment\n' -- 'statements is handled the same way as normal assignments. ' -- 'Similarly,\n' -- 'with the exception of the possible *in-place* behavior, the ' -- 'binary\n' -- 'operation performed by augmented assignment is the same as the ' -- 'normal\n' -- 'binary operations.\n' -- '\n' -- 'For targets which are attribute references, the same caveat ' -- 'about\n' -- 'class and instance attributes applies as for regular ' -- 'assignments.\n', -- 'await': 'Await expression\n' -- '****************\n' -- '\n' -- 'Suspend the execution of *coroutine* on an *awaitable* object. Can\n' -- 'only be used inside a *coroutine function*.\n' -- '\n' -- ' await_expr ::= "await" primary\n' -- '\n' -- 'Added in version 3.5.\n', -- 'binary': 'Binary arithmetic operations\n' -- '****************************\n' -- '\n' -- 'The binary arithmetic operations have the conventional priority\n' -- 'levels. Note that some of these operations also apply to certain ' -- 'non-\n' -- 'numeric types. Apart from the power operator, there are only two\n' -- 'levels, one for multiplicative operators and one for additive\n' -- 'operators:\n' -- '\n' -- ' m_expr ::= u_expr | m_expr "*" u_expr | m_expr "@" m_expr |\n' -- ' m_expr "//" u_expr | m_expr "/" u_expr |\n' -- ' m_expr "%" u_expr\n' -- ' a_expr ::= m_expr | a_expr "+" m_expr | a_expr "-" m_expr\n' -- '\n' -- 'The "*" (multiplication) operator yields the product of its ' -- 'arguments.\n' -- 'The arguments must either both be numbers, or one argument must be ' -- 'an\n' -- 'integer and the other must be a sequence. In the former case, the\n' -- 'numbers are converted to a common real type and then multiplied\n' -- 'together. In the latter case, sequence repetition is performed; ' -- 'a\n' -- 'negative repetition factor yields an empty sequence.\n' -- '\n' -- 'This operation can be customized using the special "__mul__()" ' -- 'and\n' -- '"__rmul__()" methods.\n' -- '\n' -- 'Changed in version 3.14: If only one operand is a complex number, ' -- 'the\n' -- 'other operand is converted to a floating-point number.\n' -- '\n' -- 'The "@" (at) operator is intended to be used for matrix\n' -- 'multiplication. No builtin Python types implement this operator.\n' -- '\n' -- 'This operation can be customized using the special "__matmul__()" ' -- 'and\n' -- '"__rmatmul__()" methods.\n' -- '\n' -- 'Added in version 3.5.\n' -- '\n' -- 'The "/" (division) and "//" (floor division) operators yield the\n' -- 'quotient of their arguments. The numeric arguments are first\n' -- 'converted to a common type. Division of integers yields a float, ' -- 'while\n' -- 'floor division of integers results in an integer; the result is ' -- 'that\n' -- 'of mathematical division with the ‘floor’ function applied to the\n' -- 'result. Division by zero raises the "ZeroDivisionError" ' -- 'exception.\n' -- '\n' -- 'The division operation can be customized using the special\n' -- '"__truediv__()" and "__rtruediv__()" methods. The floor division\n' -- 'operation can be customized using the special "__floordiv__()" ' -- 'and\n' -- '"__rfloordiv__()" methods.\n' -- '\n' -- 'The "%" (modulo) operator yields the remainder from the division ' -- 'of\n' -- 'the first argument by the second. The numeric arguments are ' -- 'first\n' -- 'converted to a common type. A zero right argument raises the\n' -- '"ZeroDivisionError" exception. The arguments may be ' -- 'floating-point\n' -- 'numbers, e.g., "3.14%0.7" equals "0.34" (since "3.14" equals ' -- '"4*0.7 +\n' -- '0.34".) The modulo operator always yields a result with the same ' -- 'sign\n' -- 'as its second operand (or zero); the absolute value of the result ' -- 'is\n' -- 'strictly smaller than the absolute value of the second operand ' -- '[1].\n' -- '\n' -- 'The floor division and modulo operators are connected by the ' -- 'following\n' -- 'identity: "x == (x//y)*y + (x%y)". Floor division and modulo are ' -- 'also\n' -- 'connected with the built-in function "divmod()": "divmod(x, y) ==\n' -- '(x//y, x%y)". [2].\n' -- '\n' -- 'In addition to performing the modulo operation on numbers, the ' -- '"%"\n' -- 'operator is also overloaded by string objects to perform ' -- 'old-style\n' -- 'string formatting (also known as interpolation). The syntax for\n' -- 'string formatting is described in the Python Library Reference,\n' -- 'section printf-style String Formatting.\n' -- '\n' -- 'The *modulo* operation can be customized using the special ' -- '"__mod__()"\n' -- 'and "__rmod__()" methods.\n' -- '\n' -- 'The floor division operator, the modulo operator, and the ' -- '"divmod()"\n' -- 'function are not defined for complex numbers. Instead, convert to ' -- 'a\n' -- 'floating-point number using the "abs()" function if appropriate.\n' -- '\n' -- 'The "+" (addition) operator yields the sum of its arguments. The\n' -- 'arguments must either both be numbers or both be sequences of the ' -- 'same\n' -- 'type. In the former case, the numbers are converted to a common ' -- 'real\n' -- 'type and then added together. In the latter case, the sequences ' -- 'are\n' -- 'concatenated.\n' -- '\n' -- 'This operation can be customized using the special "__add__()" ' -- 'and\n' -- '"__radd__()" methods.\n' -- '\n' -- 'Changed in version 3.14: If only one operand is a complex number, ' -- 'the\n' -- 'other operand is converted to a floating-point number.\n' -- '\n' -- 'The "-" (subtraction) operator yields the difference of its ' -- 'arguments.\n' -- 'The numeric arguments are first converted to a common real type.\n' -- '\n' -- 'This operation can be customized using the special "__sub__()" ' -- 'and\n' -- '"__rsub__()" methods.\n' -- '\n' -- 'Changed in version 3.14: If only one operand is a complex number, ' -- 'the\n' -- 'other operand is converted to a floating-point number.\n', -- 'bitwise': 'Binary bitwise operations\n' -- '*************************\n' -- '\n' -- 'Each of the three bitwise operations has a different priority ' -- 'level:\n' -- '\n' -- ' and_expr ::= shift_expr | and_expr "&" shift_expr\n' -- ' xor_expr ::= and_expr | xor_expr "^" and_expr\n' -- ' or_expr ::= xor_expr | or_expr "|" xor_expr\n' -- '\n' -- 'The "&" operator yields the bitwise AND of its arguments, which ' -- 'must\n' -- 'be integers or one of them must be a custom object overriding\n' -- '"__and__()" or "__rand__()" special methods.\n' -- '\n' -- 'The "^" operator yields the bitwise XOR (exclusive OR) of its\n' -- 'arguments, which must be integers or one of them must be a ' -- 'custom\n' -- 'object overriding "__xor__()" or "__rxor__()" special methods.\n' -- '\n' -- 'The "|" operator yields the bitwise (inclusive) OR of its ' -- 'arguments,\n' -- 'which must be integers or one of them must be a custom object\n' -- 'overriding "__or__()" or "__ror__()" special methods.\n', -- 'bltin-code-objects': 'Code Objects\n' -- '************\n' -- '\n' -- 'Code objects are used by the implementation to ' -- 'represent “pseudo-\n' -- 'compiled†executable Python code such as a function ' -- 'body. They differ\n' -- 'from function objects because they don’t contain a ' -- 'reference to their\n' -- 'global execution environment. Code objects are ' -- 'returned by the built-\n' -- 'in "compile()" function and can be extracted from ' -- 'function objects\n' -- 'through their "__code__" attribute. See also the ' -- '"code" module.\n' -- '\n' -- 'Accessing "__code__" raises an auditing event ' -- '"object.__getattr__"\n' -- 'with arguments "obj" and ""__code__"".\n' -- '\n' -- 'A code object can be executed or evaluated by passing ' -- 'it (instead of a\n' -- 'source string) to the "exec()" or "eval()" built-in ' -- 'functions.\n' -- '\n' -- 'See The standard type hierarchy for more ' -- 'information.\n', -- 'bltin-ellipsis-object': 'The Ellipsis Object\n' -- '*******************\n' -- '\n' -- 'This object is commonly used by slicing (see ' -- 'Slicings). It supports\n' -- 'no special operations. There is exactly one ' -- 'ellipsis object, named\n' -- '"Ellipsis" (a built-in name). "type(Ellipsis)()" ' -- 'produces the\n' -- '"Ellipsis" singleton.\n' -- '\n' -- 'It is written as "Ellipsis" or "...".\n', -- 'bltin-null-object': 'The Null Object\n' -- '***************\n' -- '\n' -- 'This object is returned by functions that don’t ' -- 'explicitly return a\n' -- 'value. It supports no special operations. There is ' -- 'exactly one null\n' -- 'object, named "None" (a built-in name). "type(None)()" ' -- 'produces the\n' -- 'same singleton.\n' -- '\n' -- 'It is written as "None".\n', -- 'bltin-type-objects': 'Type Objects\n' -- '************\n' -- '\n' -- 'Type objects represent the various object types. An ' -- 'object’s type is\n' -- 'accessed by the built-in function "type()". There are ' -- 'no special\n' -- 'operations on types. The standard module "types" ' -- 'defines names for\n' -- 'all standard built-in types.\n' -- '\n' -- 'Types are written like this: "".\n', -- 'booleans': 'Boolean operations\n' -- '******************\n' -- '\n' -- ' or_test ::= and_test | or_test "or" and_test\n' -- ' and_test ::= not_test | and_test "and" not_test\n' -- ' not_test ::= comparison | "not" not_test\n' -- '\n' -- 'In the context of Boolean operations, and also when expressions ' -- 'are\n' -- 'used by control flow statements, the following values are ' -- 'interpreted\n' -- 'as false: "False", "None", numeric zero of all types, and empty\n' -- 'strings and containers (including strings, tuples, lists,\n' -- 'dictionaries, sets and frozensets). All other values are ' -- 'interpreted\n' -- 'as true. User-defined objects can customize their truth value ' -- 'by\n' -- 'providing a "__bool__()" method.\n' -- '\n' -- 'The operator "not" yields "True" if its argument is false, ' -- '"False"\n' -- 'otherwise.\n' -- '\n' -- 'The expression "x and y" first evaluates *x*; if *x* is false, ' -- 'its\n' -- 'value is returned; otherwise, *y* is evaluated and the resulting ' -- 'value\n' -- 'is returned.\n' -- '\n' -- 'The expression "x or y" first evaluates *x*; if *x* is true, its ' -- 'value\n' -- 'is returned; otherwise, *y* is evaluated and the resulting value ' -- 'is\n' -- 'returned.\n' -- '\n' -- 'Note that neither "and" nor "or" restrict the value and type ' -- 'they\n' -- 'return to "False" and "True", but rather return the last ' -- 'evaluated\n' -- 'argument. This is sometimes useful, e.g., if "s" is a string ' -- 'that\n' -- 'should be replaced by a default value if it is empty, the ' -- 'expression\n' -- '"s or \'foo\'" yields the desired value. Because "not" has to ' -- 'create a\n' -- 'new value, it returns a boolean value regardless of the type of ' -- 'its\n' -- 'argument (for example, "not \'foo\'" produces "False" rather ' -- 'than "\'\'".)\n', -- 'break': 'The "break" statement\n' -- '*********************\n' -- '\n' -- ' break_stmt ::= "break"\n' -- '\n' -- '"break" may only occur syntactically nested in a "for" or "while"\n' -- 'loop, but not nested in a function or class definition within that\n' -- 'loop.\n' -- '\n' -- 'It terminates the nearest enclosing loop, skipping the optional ' -- '"else"\n' -- 'clause if the loop has one.\n' -- '\n' -- 'If a "for" loop is terminated by "break", the loop control target\n' -- 'keeps its current value.\n' -- '\n' -- 'When "break" passes control out of a "try" statement with a ' -- '"finally"\n' -- 'clause, that "finally" clause is executed before really leaving ' -- 'the\n' -- 'loop.\n', -- 'callable-types': 'Emulating callable objects\n' -- '**************************\n' -- '\n' -- 'object.__call__(self[, args...])\n' -- '\n' -- ' Called when the instance is “called†as a function; if ' -- 'this method\n' -- ' is defined, "x(arg1, arg2, ...)" roughly translates to\n' -- ' "type(x).__call__(x, arg1, ...)". The "object" class ' -- 'itself does\n' -- ' not provide this method.\n', -- 'calls': 'Calls\n' -- '*****\n' -- '\n' -- 'A call calls a callable object (e.g., a *function*) with a ' -- 'possibly\n' -- 'empty series of *arguments*:\n' -- '\n' -- ' call ::= primary "(" [argument_list [","] | ' -- 'comprehension] ")"\n' -- ' argument_list ::= positional_arguments ["," ' -- 'starred_and_keywords]\n' -- ' ["," keywords_arguments]\n' -- ' | starred_and_keywords ["," ' -- 'keywords_arguments]\n' -- ' | keywords_arguments\n' -- ' positional_arguments ::= positional_item ("," positional_item)*\n' -- ' positional_item ::= assignment_expression | "*" expression\n' -- ' starred_and_keywords ::= ("*" expression | keyword_item)\n' -- ' ("," "*" expression | "," ' -- 'keyword_item)*\n' -- ' keywords_arguments ::= (keyword_item | "**" expression)\n' -- ' ("," keyword_item | "," "**" ' -- 'expression)*\n' -- ' keyword_item ::= identifier "=" expression\n' -- '\n' -- 'An optional trailing comma may be present after the positional and\n' -- 'keyword arguments but does not affect the semantics.\n' -- '\n' -- 'The primary must evaluate to a callable object (user-defined\n' -- 'functions, built-in functions, methods of built-in objects, class\n' -- 'objects, methods of class instances, and all objects having a\n' -- '"__call__()" method are callable). All argument expressions are\n' -- 'evaluated before the call is attempted. Please refer to section\n' -- 'Function definitions for the syntax of formal *parameter* lists.\n' -- '\n' -- 'If keyword arguments are present, they are first converted to\n' -- 'positional arguments, as follows. First, a list of unfilled slots ' -- 'is\n' -- 'created for the formal parameters. If there are N positional\n' -- 'arguments, they are placed in the first N slots. Next, for each\n' -- 'keyword argument, the identifier is used to determine the\n' -- 'corresponding slot (if the identifier is the same as the first ' -- 'formal\n' -- 'parameter name, the first slot is used, and so on). If the slot ' -- 'is\n' -- 'already filled, a "TypeError" exception is raised. Otherwise, the\n' -- 'argument is placed in the slot, filling it (even if the expression ' -- 'is\n' -- '"None", it fills the slot). When all arguments have been ' -- 'processed,\n' -- 'the slots that are still unfilled are filled with the ' -- 'corresponding\n' -- 'default value from the function definition. (Default values are\n' -- 'calculated, once, when the function is defined; thus, a mutable ' -- 'object\n' -- 'such as a list or dictionary used as default value will be shared ' -- 'by\n' -- 'all calls that don’t specify an argument value for the ' -- 'corresponding\n' -- 'slot; this should usually be avoided.) If there are any unfilled\n' -- 'slots for which no default value is specified, a "TypeError" ' -- 'exception\n' -- 'is raised. Otherwise, the list of filled slots is used as the\n' -- 'argument list for the call.\n' -- '\n' -- '**CPython implementation detail:** An implementation may provide\n' -- 'built-in functions whose positional parameters do not have names, ' -- 'even\n' -- 'if they are ‘named’ for the purpose of documentation, and which\n' -- 'therefore cannot be supplied by keyword. In CPython, this is the ' -- 'case\n' -- 'for functions implemented in C that use "PyArg_ParseTuple()" to ' -- 'parse\n' -- 'their arguments.\n' -- '\n' -- 'If there are more positional arguments than there are formal ' -- 'parameter\n' -- 'slots, a "TypeError" exception is raised, unless a formal ' -- 'parameter\n' -- 'using the syntax "*identifier" is present; in this case, that ' -- 'formal\n' -- 'parameter receives a tuple containing the excess positional ' -- 'arguments\n' -- '(or an empty tuple if there were no excess positional arguments).\n' -- '\n' -- 'If any keyword argument does not correspond to a formal parameter\n' -- 'name, a "TypeError" exception is raised, unless a formal parameter\n' -- 'using the syntax "**identifier" is present; in this case, that ' -- 'formal\n' -- 'parameter receives a dictionary containing the excess keyword\n' -- 'arguments (using the keywords as keys and the argument values as\n' -- 'corresponding values), or a (new) empty dictionary if there were ' -- 'no\n' -- 'excess keyword arguments.\n' -- '\n' -- 'If the syntax "*expression" appears in the function call, ' -- '"expression"\n' -- 'must evaluate to an *iterable*. Elements from these iterables are\n' -- 'treated as if they were additional positional arguments. For the ' -- 'call\n' -- '"f(x1, x2, *y, x3, x4)", if *y* evaluates to a sequence *y1*, …, ' -- '*yM*,\n' -- 'this is equivalent to a call with M+4 positional arguments *x1*, ' -- '*x2*,\n' -- '*y1*, …, *yM*, *x3*, *x4*.\n' -- '\n' -- 'A consequence of this is that although the "*expression" syntax ' -- 'may\n' -- 'appear *after* explicit keyword arguments, it is processed ' -- '*before*\n' -- 'the keyword arguments (and any "**expression" arguments – see ' -- 'below).\n' -- 'So:\n' -- '\n' -- ' >>> def f(a, b):\n' -- ' ... print(a, b)\n' -- ' ...\n' -- ' >>> f(b=1, *(2,))\n' -- ' 2 1\n' -- ' >>> f(a=1, *(2,))\n' -- ' Traceback (most recent call last):\n' -- ' File "", line 1, in \n' -- " TypeError: f() got multiple values for keyword argument 'a'\n" -- ' >>> f(1, *(2,))\n' -- ' 1 2\n' -- '\n' -- 'It is unusual for both keyword arguments and the "*expression" ' -- 'syntax\n' -- 'to be used in the same call, so in practice this confusion does ' -- 'not\n' -- 'often arise.\n' -- '\n' -- 'If the syntax "**expression" appears in the function call,\n' -- '"expression" must evaluate to a *mapping*, the contents of which ' -- 'are\n' -- 'treated as additional keyword arguments. If a parameter matching a ' -- 'key\n' -- 'has already been given a value (by an explicit keyword argument, ' -- 'or\n' -- 'from another unpacking), a "TypeError" exception is raised.\n' -- '\n' -- 'When "**expression" is used, each key in this mapping must be a\n' -- 'string. Each value from the mapping is assigned to the first ' -- 'formal\n' -- 'parameter eligible for keyword assignment whose name is equal to ' -- 'the\n' -- 'key. A key need not be a Python identifier (e.g. ""max-temp °F"" ' -- 'is\n' -- 'acceptable, although it will not match any formal parameter that ' -- 'could\n' -- 'be declared). If there is no match to a formal parameter the ' -- 'key-value\n' -- 'pair is collected by the "**" parameter, if there is one, or if ' -- 'there\n' -- 'is not, a "TypeError" exception is raised.\n' -- '\n' -- 'Formal parameters using the syntax "*identifier" or "**identifier"\n' -- 'cannot be used as positional argument slots or as keyword argument\n' -- 'names.\n' -- '\n' -- 'Changed in version 3.5: Function calls accept any number of "*" ' -- 'and\n' -- '"**" unpackings, positional arguments may follow iterable ' -- 'unpackings\n' -- '("*"), and keyword arguments may follow dictionary unpackings ' -- '("**").\n' -- 'Originally proposed by **PEP 448**.\n' -- '\n' -- 'A call always returns some value, possibly "None", unless it raises ' -- 'an\n' -- 'exception. How this value is computed depends on the type of the\n' -- 'callable object.\n' -- '\n' -- 'If it is—\n' -- '\n' -- 'a user-defined function:\n' -- ' The code block for the function is executed, passing it the\n' -- ' argument list. The first thing the code block will do is bind ' -- 'the\n' -- ' formal parameters to the arguments; this is described in ' -- 'section\n' -- ' Function definitions. When the code block executes a "return"\n' -- ' statement, this specifies the return value of the function ' -- 'call.\n' -- ' If execution reaches the end of the code block without executing ' -- 'a\n' -- ' "return" statement, the return value is "None".\n' -- '\n' -- 'a built-in function or method:\n' -- ' The result is up to the interpreter; see Built-in Functions for ' -- 'the\n' -- ' descriptions of built-in functions and methods.\n' -- '\n' -- 'a class object:\n' -- ' A new instance of that class is returned.\n' -- '\n' -- 'a class instance method:\n' -- ' The corresponding user-defined function is called, with an ' -- 'argument\n' -- ' list that is one longer than the argument list of the call: the\n' -- ' instance becomes the first argument.\n' -- '\n' -- 'a class instance:\n' -- ' The class must define a "__call__()" method; the effect is then ' -- 'the\n' -- ' same as if that method was called.\n', -- 'class': 'Class definitions\n' -- '*****************\n' -- '\n' -- 'A class definition defines a class object (see section The ' -- 'standard\n' -- 'type hierarchy):\n' -- '\n' -- ' classdef ::= [decorators] "class" classname [type_params] ' -- '[inheritance] ":" suite\n' -- ' inheritance ::= "(" [argument_list] ")"\n' -- ' classname ::= identifier\n' -- '\n' -- 'A class definition is an executable statement. The inheritance ' -- 'list\n' -- 'usually gives a list of base classes (see Metaclasses for more\n' -- 'advanced uses), so each item in the list should evaluate to a ' -- 'class\n' -- 'object which allows subclassing. Classes without an inheritance ' -- 'list\n' -- 'inherit, by default, from the base class "object"; hence,\n' -- '\n' -- ' class Foo:\n' -- ' pass\n' -- '\n' -- 'is equivalent to\n' -- '\n' -- ' class Foo(object):\n' -- ' pass\n' -- '\n' -- 'The class’s suite is then executed in a new execution frame (see\n' -- 'Naming and binding), using a newly created local namespace and the\n' -- 'original global namespace. (Usually, the suite contains mostly\n' -- 'function definitions.) When the class’s suite finishes execution, ' -- 'its\n' -- 'execution frame is discarded but its local namespace is saved. [5] ' -- 'A\n' -- 'class object is then created using the inheritance list for the ' -- 'base\n' -- 'classes and the saved local namespace for the attribute ' -- 'dictionary.\n' -- 'The class name is bound to this class object in the original local\n' -- 'namespace.\n' -- '\n' -- 'The order in which attributes are defined in the class body is\n' -- 'preserved in the new class’s "__dict__". Note that this is ' -- 'reliable\n' -- 'only right after the class is created and only for classes that ' -- 'were\n' -- 'defined using the definition syntax.\n' -- '\n' -- 'Class creation can be customized heavily using metaclasses.\n' -- '\n' -- 'Classes can also be decorated: just like when decorating ' -- 'functions,\n' -- '\n' -- ' @f1(arg)\n' -- ' @f2\n' -- ' class Foo: pass\n' -- '\n' -- 'is roughly equivalent to\n' -- '\n' -- ' class Foo: pass\n' -- ' Foo = f1(arg)(f2(Foo))\n' -- '\n' -- 'The evaluation rules for the decorator expressions are the same as ' -- 'for\n' -- 'function decorators. The result is then bound to the class name.\n' -- '\n' -- 'Changed in version 3.9: Classes may be decorated with any valid\n' -- '"assignment_expression". Previously, the grammar was much more\n' -- 'restrictive; see **PEP 614** for details.\n' -- '\n' -- 'A list of type parameters may be given in square brackets ' -- 'immediately\n' -- 'after the class’s name. This indicates to static type checkers ' -- 'that\n' -- 'the class is generic. At runtime, the type parameters can be ' -- 'retrieved\n' -- 'from the class’s "__type_params__" attribute. See Generic classes ' -- 'for\n' -- 'more.\n' -- '\n' -- 'Changed in version 3.12: Type parameter lists are new in Python ' -- '3.12.\n' -- '\n' -- '**Programmer’s note:** Variables defined in the class definition ' -- 'are\n' -- 'class attributes; they are shared by instances. Instance ' -- 'attributes\n' -- 'can be set in a method with "self.name = value". Both class and\n' -- 'instance attributes are accessible through the notation ' -- '“"self.name"â€,\n' -- 'and an instance attribute hides a class attribute with the same ' -- 'name\n' -- 'when accessed in this way. Class attributes can be used as ' -- 'defaults\n' -- 'for instance attributes, but using mutable values there can lead ' -- 'to\n' -- 'unexpected results. Descriptors can be used to create instance\n' -- 'variables with different implementation details.\n' -- '\n' -- 'See also:\n' -- '\n' -- ' **PEP 3115** - Metaclasses in Python 3000\n' -- ' The proposal that changed the declaration of metaclasses to ' -- 'the\n' -- ' current syntax, and the semantics for how classes with\n' -- ' metaclasses are constructed.\n' -- '\n' -- ' **PEP 3129** - Class Decorators\n' -- ' The proposal that added class decorators. Function and ' -- 'method\n' -- ' decorators were introduced in **PEP 318**.\n', -- 'comparisons': 'Comparisons\n' -- '***********\n' -- '\n' -- 'Unlike C, all comparison operations in Python have the same ' -- 'priority,\n' -- 'which is lower than that of any arithmetic, shifting or ' -- 'bitwise\n' -- 'operation. Also unlike C, expressions like "a < b < c" have ' -- 'the\n' -- 'interpretation that is conventional in mathematics:\n' -- '\n' -- ' comparison ::= or_expr (comp_operator or_expr)*\n' -- ' comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n' -- ' | "is" ["not"] | ["not"] "in"\n' -- '\n' -- 'Comparisons yield boolean values: "True" or "False". Custom ' -- '*rich\n' -- 'comparison methods* may return non-boolean values. In this ' -- 'case Python\n' -- 'will call "bool()" on such value in boolean contexts.\n' -- '\n' -- 'Comparisons can be chained arbitrarily, e.g., "x < y <= z" ' -- 'is\n' -- 'equivalent to "x < y and y <= z", except that "y" is ' -- 'evaluated only\n' -- 'once (but in both cases "z" is not evaluated at all when "x < ' -- 'y" is\n' -- 'found to be false).\n' -- '\n' -- 'Formally, if *a*, *b*, *c*, …, *y*, *z* are expressions and ' -- '*op1*,\n' -- '*op2*, …, *opN* are comparison operators, then "a op1 b op2 c ' -- '... y\n' -- 'opN z" is equivalent to "a op1 b and b op2 c and ... y opN ' -- 'z", except\n' -- 'that each expression is evaluated at most once.\n' -- '\n' -- 'Note that "a op1 b op2 c" doesn’t imply any kind of ' -- 'comparison between\n' -- '*a* and *c*, so that, e.g., "x < y > z" is perfectly legal ' -- '(though\n' -- 'perhaps not pretty).\n' -- '\n' -- '\n' -- 'Value comparisons\n' -- '=================\n' -- '\n' -- 'The operators "<", ">", "==", ">=", "<=", and "!=" compare ' -- 'the values\n' -- 'of two objects. The objects do not need to have the same ' -- 'type.\n' -- '\n' -- 'Chapter Objects, values and types states that objects have a ' -- 'value (in\n' -- 'addition to type and identity). The value of an object is a ' -- 'rather\n' -- 'abstract notion in Python: For example, there is no canonical ' -- 'access\n' -- 'method for an object’s value. Also, there is no requirement ' -- 'that the\n' -- 'value of an object should be constructed in a particular way, ' -- 'e.g.\n' -- 'comprised of all its data attributes. Comparison operators ' -- 'implement a\n' -- 'particular notion of what the value of an object is. One can ' -- 'think of\n' -- 'them as defining the value of an object indirectly, by means ' -- 'of their\n' -- 'comparison implementation.\n' -- '\n' -- 'Because all types are (direct or indirect) subtypes of ' -- '"object", they\n' -- 'inherit the default comparison behavior from "object". Types ' -- 'can\n' -- 'customize their comparison behavior by implementing *rich ' -- 'comparison\n' -- 'methods* like "__lt__()", described in Basic customization.\n' -- '\n' -- 'The default behavior for equality comparison ("==" and "!=") ' -- 'is based\n' -- 'on the identity of the objects. Hence, equality comparison ' -- 'of\n' -- 'instances with the same identity results in equality, and ' -- 'equality\n' -- 'comparison of instances with different identities results in\n' -- 'inequality. A motivation for this default behavior is the ' -- 'desire that\n' -- 'all objects should be reflexive (i.e. "x is y" implies "x == ' -- 'y").\n' -- '\n' -- 'A default order comparison ("<", ">", "<=", and ">=") is not ' -- 'provided;\n' -- 'an attempt raises "TypeError". A motivation for this default ' -- 'behavior\n' -- 'is the lack of a similar invariant as for equality.\n' -- '\n' -- 'The behavior of the default equality comparison, that ' -- 'instances with\n' -- 'different identities are always unequal, may be in contrast ' -- 'to what\n' -- 'types will need that have a sensible definition of object ' -- 'value and\n' -- 'value-based equality. Such types will need to customize ' -- 'their\n' -- 'comparison behavior, and in fact, a number of built-in types ' -- 'have done\n' -- 'that.\n' -- '\n' -- 'The following list describes the comparison behavior of the ' -- 'most\n' -- 'important built-in types.\n' -- '\n' -- '* Numbers of built-in numeric types (Numeric Types — int, ' -- 'float,\n' -- ' complex) and of the standard library types ' -- '"fractions.Fraction" and\n' -- ' "decimal.Decimal" can be compared within and across their ' -- 'types,\n' -- ' with the restriction that complex numbers do not support ' -- 'order\n' -- ' comparison. Within the limits of the types involved, they ' -- 'compare\n' -- ' mathematically (algorithmically) correct without loss of ' -- 'precision.\n' -- '\n' -- ' The not-a-number values "float(\'NaN\')" and ' -- '"decimal.Decimal(\'NaN\')"\n' -- ' are special. Any ordered comparison of a number to a ' -- 'not-a-number\n' -- ' value is false. A counter-intuitive implication is that ' -- 'not-a-number\n' -- ' values are not equal to themselves. For example, if "x =\n' -- ' float(\'NaN\')", "3 < x", "x < 3" and "x == x" are all ' -- 'false, while "x\n' -- ' != x" is true. This behavior is compliant with IEEE 754.\n' -- '\n' -- '* "None" and "NotImplemented" are singletons. **PEP 8** ' -- 'advises that\n' -- ' comparisons for singletons should always be done with "is" ' -- 'or "is\n' -- ' not", never the equality operators.\n' -- '\n' -- '* Binary sequences (instances of "bytes" or "bytearray") can ' -- 'be\n' -- ' compared within and across their types. They compare\n' -- ' lexicographically using the numeric values of their ' -- 'elements.\n' -- '\n' -- '* Strings (instances of "str") compare lexicographically ' -- 'using the\n' -- ' numerical Unicode code points (the result of the built-in ' -- 'function\n' -- ' "ord()") of their characters. [3]\n' -- '\n' -- ' Strings and binary sequences cannot be directly compared.\n' -- '\n' -- '* Sequences (instances of "tuple", "list", or "range") can be ' -- 'compared\n' -- ' only within each of their types, with the restriction that ' -- 'ranges do\n' -- ' not support order comparison. Equality comparison across ' -- 'these\n' -- ' types results in inequality, and ordering comparison across ' -- 'these\n' -- ' types raises "TypeError".\n' -- '\n' -- ' Sequences compare lexicographically using comparison of\n' -- ' corresponding elements. The built-in containers typically ' -- 'assume\n' -- ' identical objects are equal to themselves. That lets them ' -- 'bypass\n' -- ' equality tests for identical objects to improve performance ' -- 'and to\n' -- ' maintain their internal invariants.\n' -- '\n' -- ' Lexicographical comparison between built-in collections ' -- 'works as\n' -- ' follows:\n' -- '\n' -- ' * For two collections to compare equal, they must be of the ' -- 'same\n' -- ' type, have the same length, and each pair of ' -- 'corresponding\n' -- ' elements must compare equal (for example, "[1,2] == ' -- '(1,2)" is\n' -- ' false because the type is not the same).\n' -- '\n' -- ' * Collections that support order comparison are ordered the ' -- 'same as\n' -- ' their first unequal elements (for example, "[1,2,x] <= ' -- '[1,2,y]"\n' -- ' has the same value as "x <= y"). If a corresponding ' -- 'element does\n' -- ' not exist, the shorter collection is ordered first (for ' -- 'example,\n' -- ' "[1,2] < [1,2,3]" is true).\n' -- '\n' -- '* Mappings (instances of "dict") compare equal if and only if ' -- 'they\n' -- ' have equal "(key, value)" pairs. Equality comparison of the ' -- 'keys and\n' -- ' values enforces reflexivity.\n' -- '\n' -- ' Order comparisons ("<", ">", "<=", and ">=") raise ' -- '"TypeError".\n' -- '\n' -- '* Sets (instances of "set" or "frozenset") can be compared ' -- 'within and\n' -- ' across their types.\n' -- '\n' -- ' They define order comparison operators to mean subset and ' -- 'superset\n' -- ' tests. Those relations do not define total orderings (for ' -- 'example,\n' -- ' the two sets "{1,2}" and "{2,3}" are not equal, nor subsets ' -- 'of one\n' -- ' another, nor supersets of one another). Accordingly, sets ' -- 'are not\n' -- ' appropriate arguments for functions which depend on total ' -- 'ordering\n' -- ' (for example, "min()", "max()", and "sorted()" produce ' -- 'undefined\n' -- ' results given a list of sets as inputs).\n' -- '\n' -- ' Comparison of sets enforces reflexivity of its elements.\n' -- '\n' -- '* Most other built-in types have no comparison methods ' -- 'implemented, so\n' -- ' they inherit the default comparison behavior.\n' -- '\n' -- 'User-defined classes that customize their comparison behavior ' -- 'should\n' -- 'follow some consistency rules, if possible:\n' -- '\n' -- '* Equality comparison should be reflexive. In other words, ' -- 'identical\n' -- ' objects should compare equal:\n' -- '\n' -- ' "x is y" implies "x == y"\n' -- '\n' -- '* Comparison should be symmetric. In other words, the ' -- 'following\n' -- ' expressions should have the same result:\n' -- '\n' -- ' "x == y" and "y == x"\n' -- '\n' -- ' "x != y" and "y != x"\n' -- '\n' -- ' "x < y" and "y > x"\n' -- '\n' -- ' "x <= y" and "y >= x"\n' -- '\n' -- '* Comparison should be transitive. The following ' -- '(non-exhaustive)\n' -- ' examples illustrate that:\n' -- '\n' -- ' "x > y and y > z" implies "x > z"\n' -- '\n' -- ' "x < y and y <= z" implies "x < z"\n' -- '\n' -- '* Inverse comparison should result in the boolean negation. ' -- 'In other\n' -- ' words, the following expressions should have the same ' -- 'result:\n' -- '\n' -- ' "x == y" and "not x != y"\n' -- '\n' -- ' "x < y" and "not x >= y" (for total ordering)\n' -- '\n' -- ' "x > y" and "not x <= y" (for total ordering)\n' -- '\n' -- ' The last two expressions apply to totally ordered ' -- 'collections (e.g.\n' -- ' to sequences, but not to sets or mappings). See also the\n' -- ' "total_ordering()" decorator.\n' -- '\n' -- '* The "hash()" result should be consistent with equality. ' -- 'Objects that\n' -- ' are equal should either have the same hash value, or be ' -- 'marked as\n' -- ' unhashable.\n' -- '\n' -- 'Python does not enforce these consistency rules. In fact, ' -- 'the\n' -- 'not-a-number values are an example for not following these ' -- 'rules.\n' -- '\n' -- '\n' -- 'Membership test operations\n' -- '==========================\n' -- '\n' -- 'The operators "in" and "not in" test for membership. "x in ' -- 's"\n' -- 'evaluates to "True" if *x* is a member of *s*, and "False" ' -- 'otherwise.\n' -- '"x not in s" returns the negation of "x in s". All built-in ' -- 'sequences\n' -- 'and set types support this as well as dictionary, for which ' -- '"in" tests\n' -- 'whether the dictionary has a given key. For container types ' -- 'such as\n' -- 'list, tuple, set, frozenset, dict, or collections.deque, the\n' -- 'expression "x in y" is equivalent to "any(x is e or x == e ' -- 'for e in\n' -- 'y)".\n' -- '\n' -- 'For the string and bytes types, "x in y" is "True" if and ' -- 'only if *x*\n' -- 'is a substring of *y*. An equivalent test is "y.find(x) != ' -- '-1".\n' -- 'Empty strings are always considered to be a substring of any ' -- 'other\n' -- 'string, so """ in "abc"" will return "True".\n' -- '\n' -- 'For user-defined classes which define the "__contains__()" ' -- 'method, "x\n' -- 'in y" returns "True" if "y.__contains__(x)" returns a true ' -- 'value, and\n' -- '"False" otherwise.\n' -- '\n' -- 'For user-defined classes which do not define "__contains__()" ' -- 'but do\n' -- 'define "__iter__()", "x in y" is "True" if some value "z", ' -- 'for which\n' -- 'the expression "x is z or x == z" is true, is produced while ' -- 'iterating\n' -- 'over "y". If an exception is raised during the iteration, it ' -- 'is as if\n' -- '"in" raised that exception.\n' -- '\n' -- 'Lastly, the old-style iteration protocol is tried: if a class ' -- 'defines\n' -- '"__getitem__()", "x in y" is "True" if and only if there is a ' -- 'non-\n' -- 'negative integer index *i* such that "x is y[i] or x == ' -- 'y[i]", and no\n' -- 'lower integer index raises the "IndexError" exception. (If ' -- 'any other\n' -- 'exception is raised, it is as if "in" raised that ' -- 'exception).\n' -- '\n' -- 'The operator "not in" is defined to have the inverse truth ' -- 'value of\n' -- '"in".\n' -- '\n' -- '\n' -- 'Identity comparisons\n' -- '====================\n' -- '\n' -- 'The operators "is" and "is not" test for an object’s ' -- 'identity: "x is\n' -- 'y" is true if and only if *x* and *y* are the same object. ' -- 'An\n' -- 'Object’s identity is determined using the "id()" function. ' -- '"x is not\n' -- 'y" yields the inverse truth value. [4]\n', -- 'compound': 'Compound statements\n' -- '*******************\n' -- '\n' -- 'Compound statements contain (groups of) other statements; they ' -- 'affect\n' -- 'or control the execution of those other statements in some way. ' -- 'In\n' -- 'general, compound statements span multiple lines, although in ' -- 'simple\n' -- 'incarnations a whole compound statement may be contained in one ' -- 'line.\n' -- '\n' -- 'The "if", "while" and "for" statements implement traditional ' -- 'control\n' -- 'flow constructs. "try" specifies exception handlers and/or ' -- 'cleanup\n' -- 'code for a group of statements, while the "with" statement ' -- 'allows the\n' -- 'execution of initialization and finalization code around a block ' -- 'of\n' -- 'code. Function and class definitions are also syntactically ' -- 'compound\n' -- 'statements.\n' -- '\n' -- 'A compound statement consists of one or more ‘clauses.’ A ' -- 'clause\n' -- 'consists of a header and a ‘suite.’ The clause headers of a\n' -- 'particular compound statement are all at the same indentation ' -- 'level.\n' -- 'Each clause header begins with a uniquely identifying keyword ' -- 'and ends\n' -- 'with a colon. A suite is a group of statements controlled by a\n' -- 'clause. A suite can be one or more semicolon-separated simple\n' -- 'statements on the same line as the header, following the ' -- 'header’s\n' -- 'colon, or it can be one or more indented statements on ' -- 'subsequent\n' -- 'lines. Only the latter form of a suite can contain nested ' -- 'compound\n' -- 'statements; the following is illegal, mostly because it wouldn’t ' -- 'be\n' -- 'clear to which "if" clause a following "else" clause would ' -- 'belong:\n' -- '\n' -- ' if test1: if test2: print(x)\n' -- '\n' -- 'Also note that the semicolon binds tighter than the colon in ' -- 'this\n' -- 'context, so that in the following example, either all or none of ' -- 'the\n' -- '"print()" calls are executed:\n' -- '\n' -- ' if x < y < z: print(x); print(y); print(z)\n' -- '\n' -- 'Summarizing:\n' -- '\n' -- ' compound_stmt ::= if_stmt\n' -- ' | while_stmt\n' -- ' | for_stmt\n' -- ' | try_stmt\n' -- ' | with_stmt\n' -- ' | match_stmt\n' -- ' | funcdef\n' -- ' | classdef\n' -- ' | async_with_stmt\n' -- ' | async_for_stmt\n' -- ' | async_funcdef\n' -- ' suite ::= stmt_list NEWLINE | NEWLINE INDENT ' -- 'statement+ DEDENT\n' -- ' statement ::= stmt_list NEWLINE | compound_stmt\n' -- ' stmt_list ::= simple_stmt (";" simple_stmt)* [";"]\n' -- '\n' -- 'Note that statements always end in a "NEWLINE" possibly followed ' -- 'by a\n' -- '"DEDENT". Also note that optional continuation clauses always ' -- 'begin\n' -- 'with a keyword that cannot start a statement, thus there are no\n' -- 'ambiguities (the ‘dangling "else"’ problem is solved in Python ' -- 'by\n' -- 'requiring nested "if" statements to be indented).\n' -- '\n' -- 'The formatting of the grammar rules in the following sections ' -- 'places\n' -- 'each clause on a separate line for clarity.\n' -- '\n' -- '\n' -- 'The "if" statement\n' -- '==================\n' -- '\n' -- 'The "if" statement is used for conditional execution:\n' -- '\n' -- ' if_stmt ::= "if" assignment_expression ":" suite\n' -- ' ("elif" assignment_expression ":" suite)*\n' -- ' ["else" ":" suite]\n' -- '\n' -- 'It selects exactly one of the suites by evaluating the ' -- 'expressions one\n' -- 'by one until one is found to be true (see section Boolean ' -- 'operations\n' -- 'for the definition of true and false); then that suite is ' -- 'executed\n' -- '(and no other part of the "if" statement is executed or ' -- 'evaluated).\n' -- 'If all expressions are false, the suite of the "else" clause, ' -- 'if\n' -- 'present, is executed.\n' -- '\n' -- '\n' -- 'The "while" statement\n' -- '=====================\n' -- '\n' -- 'The "while" statement is used for repeated execution as long as ' -- 'an\n' -- 'expression is true:\n' -- '\n' -- ' while_stmt ::= "while" assignment_expression ":" suite\n' -- ' ["else" ":" suite]\n' -- '\n' -- 'This repeatedly tests the expression and, if it is true, ' -- 'executes the\n' -- 'first suite; if the expression is false (which may be the first ' -- 'time\n' -- 'it is tested) the suite of the "else" clause, if present, is ' -- 'executed\n' -- 'and the loop terminates.\n' -- '\n' -- 'A "break" statement executed in the first suite terminates the ' -- 'loop\n' -- 'without executing the "else" clause’s suite. A "continue" ' -- 'statement\n' -- 'executed in the first suite skips the rest of the suite and goes ' -- 'back\n' -- 'to testing the expression.\n' -- '\n' -- '\n' -- 'The "for" statement\n' -- '===================\n' -- '\n' -- 'The "for" statement is used to iterate over the elements of a ' -- 'sequence\n' -- '(such as a string, tuple or list) or other iterable object:\n' -- '\n' -- ' for_stmt ::= "for" target_list "in" starred_list ":" suite\n' -- ' ["else" ":" suite]\n' -- '\n' -- 'The "starred_list" expression is evaluated once; it should yield ' -- 'an\n' -- '*iterable* object. An *iterator* is created for that iterable. ' -- 'The\n' -- 'first item provided by the iterator is then assigned to the ' -- 'target\n' -- 'list using the standard rules for assignments (see Assignment\n' -- 'statements), and the suite is executed. This repeats for each ' -- 'item\n' -- 'provided by the iterator. When the iterator is exhausted, the ' -- 'suite\n' -- 'in the "else" clause, if present, is executed, and the loop\n' -- 'terminates.\n' -- '\n' -- 'A "break" statement executed in the first suite terminates the ' -- 'loop\n' -- 'without executing the "else" clause’s suite. A "continue" ' -- 'statement\n' -- 'executed in the first suite skips the rest of the suite and ' -- 'continues\n' -- 'with the next item, or with the "else" clause if there is no ' -- 'next\n' -- 'item.\n' -- '\n' -- 'The for-loop makes assignments to the variables in the target ' -- 'list.\n' -- 'This overwrites all previous assignments to those variables ' -- 'including\n' -- 'those made in the suite of the for-loop:\n' -- '\n' -- ' for i in range(10):\n' -- ' print(i)\n' -- ' i = 5 # this will not affect the for-loop\n' -- ' # because i will be overwritten with ' -- 'the next\n' -- ' # index in the range\n' -- '\n' -- 'Names in the target list are not deleted when the loop is ' -- 'finished,\n' -- 'but if the sequence is empty, they will not have been assigned ' -- 'to at\n' -- 'all by the loop. Hint: the built-in type "range()" represents\n' -- 'immutable arithmetic sequences of integers. For instance, ' -- 'iterating\n' -- '"range(3)" successively yields 0, 1, and then 2.\n' -- '\n' -- 'Changed in version 3.11: Starred elements are now allowed in ' -- 'the\n' -- 'expression list.\n' -- '\n' -- '\n' -- 'The "try" statement\n' -- '===================\n' -- '\n' -- 'The "try" statement specifies exception handlers and/or cleanup ' -- 'code\n' -- 'for a group of statements:\n' -- '\n' -- ' try_stmt ::= try1_stmt | try2_stmt | try3_stmt\n' -- ' try1_stmt ::= "try" ":" suite\n' -- ' ("except" [expression ["as" identifier]] ":" ' -- 'suite)+\n' -- ' ["else" ":" suite]\n' -- ' ["finally" ":" suite]\n' -- ' try2_stmt ::= "try" ":" suite\n' -- ' ("except" "*" expression ["as" identifier] ":" ' -- 'suite)+\n' -- ' ["else" ":" suite]\n' -- ' ["finally" ":" suite]\n' -- ' try3_stmt ::= "try" ":" suite\n' -- ' "finally" ":" suite\n' -- '\n' -- 'Additional information on exceptions can be found in section\n' -- 'Exceptions, and information on using the "raise" statement to ' -- 'generate\n' -- 'exceptions may be found in section The raise statement.\n' -- '\n' -- '\n' -- '"except" clause\n' -- '---------------\n' -- '\n' -- 'The "except" clause(s) specify one or more exception handlers. ' -- 'When no\n' -- 'exception occurs in the "try" clause, no exception handler is\n' -- 'executed. When an exception occurs in the "try" suite, a search ' -- 'for an\n' -- 'exception handler is started. This search inspects the "except"\n' -- 'clauses in turn until one is found that matches the exception. ' -- 'An\n' -- 'expression-less "except" clause, if present, must be last; it ' -- 'matches\n' -- 'any exception.\n' -- '\n' -- 'For an "except" clause with an expression, the expression must\n' -- 'evaluate to an exception type or a tuple of exception types. ' -- 'The\n' -- 'raised exception matches an "except" clause whose expression ' -- 'evaluates\n' -- 'to the class or a *non-virtual base class* of the exception ' -- 'object, or\n' -- 'to a tuple that contains such a class.\n' -- '\n' -- 'If no "except" clause matches the exception, the search for an\n' -- 'exception handler continues in the surrounding code and on the\n' -- 'invocation stack. [1]\n' -- '\n' -- 'If the evaluation of an expression in the header of an "except" ' -- 'clause\n' -- 'raises an exception, the original search for a handler is ' -- 'canceled and\n' -- 'a search starts for the new exception in the surrounding code ' -- 'and on\n' -- 'the call stack (it is treated as if the entire "try" statement ' -- 'raised\n' -- 'the exception).\n' -- '\n' -- 'When a matching "except" clause is found, the exception is ' -- 'assigned to\n' -- 'the target specified after the "as" keyword in that "except" ' -- 'clause,\n' -- 'if present, and the "except" clause’s suite is executed. All ' -- '"except"\n' -- 'clauses must have an executable block. When the end of this ' -- 'block is\n' -- 'reached, execution continues normally after the entire "try"\n' -- 'statement. (This means that if two nested handlers exist for the ' -- 'same\n' -- 'exception, and the exception occurs in the "try" clause of the ' -- 'inner\n' -- 'handler, the outer handler will not handle the exception.)\n' -- '\n' -- 'When an exception has been assigned using "as target", it is ' -- 'cleared\n' -- 'at the end of the "except" clause. This is as if\n' -- '\n' -- ' except E as N:\n' -- ' foo\n' -- '\n' -- 'was translated to\n' -- '\n' -- ' except E as N:\n' -- ' try:\n' -- ' foo\n' -- ' finally:\n' -- ' del N\n' -- '\n' -- 'This means the exception must be assigned to a different name to ' -- 'be\n' -- 'able to refer to it after the "except" clause. Exceptions are ' -- 'cleared\n' -- 'because with the traceback attached to them, they form a ' -- 'reference\n' -- 'cycle with the stack frame, keeping all locals in that frame ' -- 'alive\n' -- 'until the next garbage collection occurs.\n' -- '\n' -- 'Before an "except" clause’s suite is executed, the exception is ' -- 'stored\n' -- 'in the "sys" module, where it can be accessed from within the ' -- 'body of\n' -- 'the "except" clause by calling "sys.exception()". When leaving ' -- 'an\n' -- 'exception handler, the exception stored in the "sys" module is ' -- 'reset\n' -- 'to its previous value:\n' -- '\n' -- ' >>> print(sys.exception())\n' -- ' None\n' -- ' >>> try:\n' -- ' ... raise TypeError\n' -- ' ... except:\n' -- ' ... print(repr(sys.exception()))\n' -- ' ... try:\n' -- ' ... raise ValueError\n' -- ' ... except:\n' -- ' ... print(repr(sys.exception()))\n' -- ' ... print(repr(sys.exception()))\n' -- ' ...\n' -- ' TypeError()\n' -- ' ValueError()\n' -- ' TypeError()\n' -- ' >>> print(sys.exception())\n' -- ' None\n' -- '\n' -- '\n' -- '"except*" clause\n' -- '----------------\n' -- '\n' -- 'The "except*" clause(s) are used for handling "ExceptionGroup"s. ' -- 'The\n' -- 'exception type for matching is interpreted as in the case of ' -- '"except",\n' -- 'but in the case of exception groups we can have partial matches ' -- 'when\n' -- 'the type matches some of the exceptions in the group. This means ' -- 'that\n' -- 'multiple "except*" clauses can execute, each handling part of ' -- 'the\n' -- 'exception group. Each clause executes at most once and handles ' -- 'an\n' -- 'exception group of all matching exceptions. Each exception in ' -- 'the\n' -- 'group is handled by at most one "except*" clause, the first ' -- 'that\n' -- 'matches it.\n' -- '\n' -- ' >>> try:\n' -- ' ... raise ExceptionGroup("eg",\n' -- ' ... [ValueError(1), TypeError(2), OSError(3), ' -- 'OSError(4)])\n' -- ' ... except* TypeError as e:\n' -- " ... print(f'caught {type(e)} with nested " -- "{e.exceptions}')\n" -- ' ... except* OSError as e:\n' -- " ... print(f'caught {type(e)} with nested " -- "{e.exceptions}')\n" -- ' ...\n' -- " caught with nested (TypeError(2),)\n" -- " caught with nested (OSError(3), " -- 'OSError(4))\n' -- ' + Exception Group Traceback (most recent call last):\n' -- ' | File "", line 2, in \n' -- ' | ExceptionGroup: eg\n' -- ' +-+---------------- 1 ----------------\n' -- ' | ValueError: 1\n' -- ' +------------------------------------\n' -- '\n' -- 'Any remaining exceptions that were not handled by any "except*" ' -- 'clause\n' -- 'are re-raised at the end, along with all exceptions that were ' -- 'raised\n' -- 'from within the "except*" clauses. If this list contains more ' -- 'than one\n' -- 'exception to reraise, they are combined into an exception ' -- 'group.\n' -- '\n' -- 'If the raised exception is not an exception group and its type ' -- 'matches\n' -- 'one of the "except*" clauses, it is caught and wrapped by an ' -- 'exception\n' -- 'group with an empty message string.\n' -- '\n' -- ' >>> try:\n' -- ' ... raise BlockingIOError\n' -- ' ... except* BlockingIOError as e:\n' -- ' ... print(repr(e))\n' -- ' ...\n' -- " ExceptionGroup('', (BlockingIOError()))\n" -- '\n' -- 'An "except*" clause must have a matching expression; it cannot ' -- 'be\n' -- '"except*:". Furthermore, this expression cannot contain ' -- 'exception\n' -- 'group types, because that would have ambiguous semantics.\n' -- '\n' -- 'It is not possible to mix "except" and "except*" in the same ' -- '"try".\n' -- '"break", "continue" and "return" cannot appear in an "except*" ' -- 'clause.\n' -- '\n' -- '\n' -- '"else" clause\n' -- '-------------\n' -- '\n' -- 'The optional "else" clause is executed if the control flow ' -- 'leaves the\n' -- '"try" suite, no exception was raised, and no "return", ' -- '"continue", or\n' -- '"break" statement was executed. Exceptions in the "else" clause ' -- 'are\n' -- 'not handled by the preceding "except" clauses.\n' -- '\n' -- '\n' -- '"finally" clause\n' -- '----------------\n' -- '\n' -- 'If "finally" is present, it specifies a ‘cleanup’ handler. The ' -- '"try"\n' -- 'clause is executed, including any "except" and "else" clauses. ' -- 'If an\n' -- 'exception occurs in any of the clauses and is not handled, the\n' -- 'exception is temporarily saved. The "finally" clause is ' -- 'executed. If\n' -- 'there is a saved exception it is re-raised at the end of the ' -- '"finally"\n' -- 'clause. If the "finally" clause raises another exception, the ' -- 'saved\n' -- 'exception is set as the context of the new exception. If the ' -- '"finally"\n' -- 'clause executes a "return", "break" or "continue" statement, the ' -- 'saved\n' -- 'exception is discarded:\n' -- '\n' -- ' >>> def f():\n' -- ' ... try:\n' -- ' ... 1/0\n' -- ' ... finally:\n' -- ' ... return 42\n' -- ' ...\n' -- ' >>> f()\n' -- ' 42\n' -- '\n' -- 'The exception information is not available to the program ' -- 'during\n' -- 'execution of the "finally" clause.\n' -- '\n' -- 'When a "return", "break" or "continue" statement is executed in ' -- 'the\n' -- '"try" suite of a "try"…"finally" statement, the "finally" clause ' -- 'is\n' -- 'also executed ‘on the way out.’\n' -- '\n' -- 'The return value of a function is determined by the last ' -- '"return"\n' -- 'statement executed. Since the "finally" clause always executes, ' -- 'a\n' -- '"return" statement executed in the "finally" clause will always ' -- 'be the\n' -- 'last one executed:\n' -- '\n' -- ' >>> def foo():\n' -- ' ... try:\n' -- " ... return 'try'\n" -- ' ... finally:\n' -- " ... return 'finally'\n" -- ' ...\n' -- ' >>> foo()\n' -- " 'finally'\n" -- '\n' -- 'Changed in version 3.8: Prior to Python 3.8, a "continue" ' -- 'statement\n' -- 'was illegal in the "finally" clause due to a problem with the\n' -- 'implementation.\n' -- '\n' -- '\n' -- 'The "with" statement\n' -- '====================\n' -- '\n' -- 'The "with" statement is used to wrap the execution of a block ' -- 'with\n' -- 'methods defined by a context manager (see section With ' -- 'Statement\n' -- 'Context Managers). This allows common "try"…"except"…"finally" ' -- 'usage\n' -- 'patterns to be encapsulated for convenient reuse.\n' -- '\n' -- ' with_stmt ::= "with" ( "(" with_stmt_contents ","? ' -- '")" | with_stmt_contents ) ":" suite\n' -- ' with_stmt_contents ::= with_item ("," with_item)*\n' -- ' with_item ::= expression ["as" target]\n' -- '\n' -- 'The execution of the "with" statement with one “item†proceeds ' -- 'as\n' -- 'follows:\n' -- '\n' -- '1. The context expression (the expression given in the ' -- '"with_item") is\n' -- ' evaluated to obtain a context manager.\n' -- '\n' -- '2. The context manager’s "__enter__()" is loaded for later use.\n' -- '\n' -- '3. The context manager’s "__exit__()" is loaded for later use.\n' -- '\n' -- '4. The context manager’s "__enter__()" method is invoked.\n' -- '\n' -- '5. If a target was included in the "with" statement, the return ' -- 'value\n' -- ' from "__enter__()" is assigned to it.\n' -- '\n' -- ' Note:\n' -- '\n' -- ' The "with" statement guarantees that if the "__enter__()" ' -- 'method\n' -- ' returns without an error, then "__exit__()" will always be\n' -- ' called. Thus, if an error occurs during the assignment to ' -- 'the\n' -- ' target list, it will be treated the same as an error ' -- 'occurring\n' -- ' within the suite would be. See step 7 below.\n' -- '\n' -- '6. The suite is executed.\n' -- '\n' -- '7. The context manager’s "__exit__()" method is invoked. If an\n' -- ' exception caused the suite to be exited, its type, value, ' -- 'and\n' -- ' traceback are passed as arguments to "__exit__()". Otherwise, ' -- 'three\n' -- ' "None" arguments are supplied.\n' -- '\n' -- ' If the suite was exited due to an exception, and the return ' -- 'value\n' -- ' from the "__exit__()" method was false, the exception is ' -- 'reraised.\n' -- ' If the return value was true, the exception is suppressed, ' -- 'and\n' -- ' execution continues with the statement following the "with"\n' -- ' statement.\n' -- '\n' -- ' If the suite was exited for any reason other than an ' -- 'exception, the\n' -- ' return value from "__exit__()" is ignored, and execution ' -- 'proceeds\n' -- ' at the normal location for the kind of exit that was taken.\n' -- '\n' -- 'The following code:\n' -- '\n' -- ' with EXPRESSION as TARGET:\n' -- ' SUITE\n' -- '\n' -- 'is semantically equivalent to:\n' -- '\n' -- ' manager = (EXPRESSION)\n' -- ' enter = type(manager).__enter__\n' -- ' exit = type(manager).__exit__\n' -- ' value = enter(manager)\n' -- '\n' -- ' try:\n' -- ' TARGET = value\n' -- ' SUITE\n' -- ' except:\n' -- ' if not exit(manager, *sys.exc_info()):\n' -- ' raise\n' -- ' else:\n' -- ' exit(manager, None, None, None)\n' -- '\n' -- 'With more than one item, the context managers are processed as ' -- 'if\n' -- 'multiple "with" statements were nested:\n' -- '\n' -- ' with A() as a, B() as b:\n' -- ' SUITE\n' -- '\n' -- 'is semantically equivalent to:\n' -- '\n' -- ' with A() as a:\n' -- ' with B() as b:\n' -- ' SUITE\n' -- '\n' -- 'You can also write multi-item context managers in multiple lines ' -- 'if\n' -- 'the items are surrounded by parentheses. For example:\n' -- '\n' -- ' with (\n' -- ' A() as a,\n' -- ' B() as b,\n' -- ' ):\n' -- ' SUITE\n' -- '\n' -- 'Changed in version 3.1: Support for multiple context ' -- 'expressions.\n' -- '\n' -- 'Changed in version 3.10: Support for using grouping parentheses ' -- 'to\n' -- 'break the statement in multiple lines.\n' -- '\n' -- 'See also:\n' -- '\n' -- ' **PEP 343** - The “with†statement\n' -- ' The specification, background, and examples for the Python ' -- '"with"\n' -- ' statement.\n' -- '\n' -- '\n' -- 'The "match" statement\n' -- '=====================\n' -- '\n' -- 'Added in version 3.10.\n' -- '\n' -- 'The match statement is used for pattern matching. Syntax:\n' -- '\n' -- ' match_stmt ::= \'match\' subject_expr ":" NEWLINE INDENT ' -- 'case_block+ DEDENT\n' -- ' subject_expr ::= star_named_expression "," ' -- 'star_named_expressions?\n' -- ' | named_expression\n' -- ' case_block ::= \'case\' patterns [guard] ":" block\n' -- '\n' -- 'Note:\n' -- '\n' -- ' This section uses single quotes to denote soft keywords.\n' -- '\n' -- 'Pattern matching takes a pattern as input (following "case") and ' -- 'a\n' -- 'subject value (following "match"). The pattern (which may ' -- 'contain\n' -- 'subpatterns) is matched against the subject value. The outcomes ' -- 'are:\n' -- '\n' -- '* A match success or failure (also termed a pattern success or\n' -- ' failure).\n' -- '\n' -- '* Possible binding of matched values to a name. The ' -- 'prerequisites for\n' -- ' this are further discussed below.\n' -- '\n' -- 'The "match" and "case" keywords are soft keywords.\n' -- '\n' -- 'See also:\n' -- '\n' -- ' * **PEP 634** – Structural Pattern Matching: Specification\n' -- '\n' -- ' * **PEP 636** – Structural Pattern Matching: Tutorial\n' -- '\n' -- '\n' -- 'Overview\n' -- '--------\n' -- '\n' -- 'Here’s an overview of the logical flow of a match statement:\n' -- '\n' -- '1. The subject expression "subject_expr" is evaluated and a ' -- 'resulting\n' -- ' subject value obtained. If the subject expression contains a ' -- 'comma,\n' -- ' a tuple is constructed using the standard rules.\n' -- '\n' -- '2. Each pattern in a "case_block" is attempted to match with ' -- 'the\n' -- ' subject value. The specific rules for success or failure are\n' -- ' described below. The match attempt can also bind some or all ' -- 'of the\n' -- ' standalone names within the pattern. The precise pattern ' -- 'binding\n' -- ' rules vary per pattern type and are specified below. **Name\n' -- ' bindings made during a successful pattern match outlive the\n' -- ' executed block and can be used after the match statement**.\n' -- '\n' -- ' Note:\n' -- '\n' -- ' During failed pattern matches, some subpatterns may ' -- 'succeed. Do\n' -- ' not rely on bindings being made for a failed match. ' -- 'Conversely,\n' -- ' do not rely on variables remaining unchanged after a ' -- 'failed\n' -- ' match. The exact behavior is dependent on implementation ' -- 'and may\n' -- ' vary. This is an intentional decision made to allow ' -- 'different\n' -- ' implementations to add optimizations.\n' -- '\n' -- '3. If the pattern succeeds, the corresponding guard (if present) ' -- 'is\n' -- ' evaluated. In this case all name bindings are guaranteed to ' -- 'have\n' -- ' happened.\n' -- '\n' -- ' * If the guard evaluates as true or is missing, the "block" ' -- 'inside\n' -- ' "case_block" is executed.\n' -- '\n' -- ' * Otherwise, the next "case_block" is attempted as described ' -- 'above.\n' -- '\n' -- ' * If there are no further case blocks, the match statement ' -- 'is\n' -- ' completed.\n' -- '\n' -- 'Note:\n' -- '\n' -- ' Users should generally never rely on a pattern being ' -- 'evaluated.\n' -- ' Depending on implementation, the interpreter may cache values ' -- 'or use\n' -- ' other optimizations which skip repeated evaluations.\n' -- '\n' -- 'A sample match statement:\n' -- '\n' -- ' >>> flag = False\n' -- ' >>> match (100, 200):\n' -- ' ... case (100, 300): # Mismatch: 200 != 300\n' -- " ... print('Case 1')\n" -- ' ... case (100, 200) if flag: # Successful match, but ' -- 'guard fails\n' -- " ... print('Case 2')\n" -- ' ... case (100, y): # Matches and binds y to 200\n' -- " ... print(f'Case 3, y: {y}')\n" -- ' ... case _: # Pattern not attempted\n' -- " ... print('Case 4, I match anything!')\n" -- ' ...\n' -- ' Case 3, y: 200\n' -- '\n' -- 'In this case, "if flag" is a guard. Read more about that in the ' -- 'next\n' -- 'section.\n' -- '\n' -- '\n' -- 'Guards\n' -- '------\n' -- '\n' -- ' guard ::= "if" named_expression\n' -- '\n' -- 'A "guard" (which is part of the "case") must succeed for code ' -- 'inside\n' -- 'the "case" block to execute. It takes the form: "if" followed ' -- 'by an\n' -- 'expression.\n' -- '\n' -- 'The logical flow of a "case" block with a "guard" follows:\n' -- '\n' -- '1. Check that the pattern in the "case" block succeeded. If ' -- 'the\n' -- ' pattern failed, the "guard" is not evaluated and the next ' -- '"case"\n' -- ' block is checked.\n' -- '\n' -- '2. If the pattern succeeded, evaluate the "guard".\n' -- '\n' -- ' * If the "guard" condition evaluates as true, the case block ' -- 'is\n' -- ' selected.\n' -- '\n' -- ' * If the "guard" condition evaluates as false, the case block ' -- 'is\n' -- ' not selected.\n' -- '\n' -- ' * If the "guard" raises an exception during evaluation, the\n' -- ' exception bubbles up.\n' -- '\n' -- 'Guards are allowed to have side effects as they are ' -- 'expressions.\n' -- 'Guard evaluation must proceed from the first to the last case ' -- 'block,\n' -- 'one at a time, skipping case blocks whose pattern(s) don’t all\n' -- 'succeed. (I.e., guard evaluation must happen in order.) Guard\n' -- 'evaluation must stop once a case block is selected.\n' -- '\n' -- '\n' -- 'Irrefutable Case Blocks\n' -- '-----------------------\n' -- '\n' -- 'An irrefutable case block is a match-all case block. A match\n' -- 'statement may have at most one irrefutable case block, and it ' -- 'must be\n' -- 'last.\n' -- '\n' -- 'A case block is considered irrefutable if it has no guard and ' -- 'its\n' -- 'pattern is irrefutable. A pattern is considered irrefutable if ' -- 'we can\n' -- 'prove from its syntax alone that it will always succeed. Only ' -- 'the\n' -- 'following patterns are irrefutable:\n' -- '\n' -- '* AS Patterns whose left-hand side is irrefutable\n' -- '\n' -- '* OR Patterns containing at least one irrefutable pattern\n' -- '\n' -- '* Capture Patterns\n' -- '\n' -- '* Wildcard Patterns\n' -- '\n' -- '* parenthesized irrefutable patterns\n' -- '\n' -- '\n' -- 'Patterns\n' -- '--------\n' -- '\n' -- 'Note:\n' -- '\n' -- ' This section uses grammar notations beyond standard EBNF:\n' -- '\n' -- ' * the notation "SEP.RULE+" is shorthand for "RULE (SEP ' -- 'RULE)*"\n' -- '\n' -- ' * the notation "!RULE" is shorthand for a negative lookahead\n' -- ' assertion\n' -- '\n' -- 'The top-level syntax for "patterns" is:\n' -- '\n' -- ' patterns ::= open_sequence_pattern | pattern\n' -- ' pattern ::= as_pattern | or_pattern\n' -- ' closed_pattern ::= | literal_pattern\n' -- ' | capture_pattern\n' -- ' | wildcard_pattern\n' -- ' | value_pattern\n' -- ' | group_pattern\n' -- ' | sequence_pattern\n' -- ' | mapping_pattern\n' -- ' | class_pattern\n' -- '\n' -- 'The descriptions below will include a description “in simple ' -- 'terms†of\n' -- 'what a pattern does for illustration purposes (credits to ' -- 'Raymond\n' -- 'Hettinger for a document that inspired most of the ' -- 'descriptions). Note\n' -- 'that these descriptions are purely for illustration purposes and ' -- '**may\n' -- 'not** reflect the underlying implementation. Furthermore, they ' -- 'do not\n' -- 'cover all valid forms.\n' -- '\n' -- '\n' -- 'OR Patterns\n' -- '~~~~~~~~~~~\n' -- '\n' -- 'An OR pattern is two or more patterns separated by vertical bars ' -- '"|".\n' -- 'Syntax:\n' -- '\n' -- ' or_pattern ::= "|".closed_pattern+\n' -- '\n' -- 'Only the final subpattern may be irrefutable, and each ' -- 'subpattern must\n' -- 'bind the same set of names to avoid ambiguity.\n' -- '\n' -- 'An OR pattern matches each of its subpatterns in turn to the ' -- 'subject\n' -- 'value, until one succeeds. The OR pattern is then considered\n' -- 'successful. Otherwise, if none of the subpatterns succeed, the ' -- 'OR\n' -- 'pattern fails.\n' -- '\n' -- 'In simple terms, "P1 | P2 | ..." will try to match "P1", if it ' -- 'fails\n' -- 'it will try to match "P2", succeeding immediately if any ' -- 'succeeds,\n' -- 'failing otherwise.\n' -- '\n' -- '\n' -- 'AS Patterns\n' -- '~~~~~~~~~~~\n' -- '\n' -- 'An AS pattern matches an OR pattern on the left of the "as" ' -- 'keyword\n' -- 'against a subject. Syntax:\n' -- '\n' -- ' as_pattern ::= or_pattern "as" capture_pattern\n' -- '\n' -- 'If the OR pattern fails, the AS pattern fails. Otherwise, the ' -- 'AS\n' -- 'pattern binds the subject to the name on the right of the as ' -- 'keyword\n' -- 'and succeeds. "capture_pattern" cannot be a "_".\n' -- '\n' -- 'In simple terms "P as NAME" will match with "P", and on success ' -- 'it\n' -- 'will set "NAME = ".\n' -- '\n' -- '\n' -- 'Literal Patterns\n' -- '~~~~~~~~~~~~~~~~\n' -- '\n' -- 'A literal pattern corresponds to most literals in Python. ' -- 'Syntax:\n' -- '\n' -- ' literal_pattern ::= signed_number\n' -- ' | signed_number "+" NUMBER\n' -- ' | signed_number "-" NUMBER\n' -- ' | strings\n' -- ' | "None"\n' -- ' | "True"\n' -- ' | "False"\n' -- ' signed_number ::= ["-"] NUMBER\n' -- '\n' -- 'The rule "strings" and the token "NUMBER" are defined in the ' -- 'standard\n' -- 'Python grammar. Triple-quoted strings are supported. Raw ' -- 'strings and\n' -- 'byte strings are supported. f-strings are not supported.\n' -- '\n' -- 'The forms "signed_number \'+\' NUMBER" and "signed_number \'-\' ' -- 'NUMBER"\n' -- 'are for expressing complex numbers; they require a real number ' -- 'on the\n' -- 'left and an imaginary number on the right. E.g. "3 + 4j".\n' -- '\n' -- 'In simple terms, "LITERAL" will succeed only if " ==\n' -- 'LITERAL". For the singletons "None", "True" and "False", the ' -- '"is"\n' -- 'operator is used.\n' -- '\n' -- '\n' -- 'Capture Patterns\n' -- '~~~~~~~~~~~~~~~~\n' -- '\n' -- 'A capture pattern binds the subject value to a name. Syntax:\n' -- '\n' -- " capture_pattern ::= !'_' NAME\n" -- '\n' -- 'A single underscore "_" is not a capture pattern (this is what ' -- '"!\'_\'"\n' -- 'expresses). It is instead treated as a "wildcard_pattern".\n' -- '\n' -- 'In a given pattern, a given name can only be bound once. E.g. ' -- '"case\n' -- 'x, x: ..." is invalid while "case [x] | x: ..." is allowed.\n' -- '\n' -- 'Capture patterns always succeed. The binding follows scoping ' -- 'rules\n' -- 'established by the assignment expression operator in **PEP ' -- '572**; the\n' -- 'name becomes a local variable in the closest containing function ' -- 'scope\n' -- 'unless there’s an applicable "global" or "nonlocal" statement.\n' -- '\n' -- 'In simple terms "NAME" will always succeed and it will set "NAME ' -- '=\n' -- '".\n' -- '\n' -- '\n' -- 'Wildcard Patterns\n' -- '~~~~~~~~~~~~~~~~~\n' -- '\n' -- 'A wildcard pattern always succeeds (matches anything) and binds ' -- 'no\n' -- 'name. Syntax:\n' -- '\n' -- " wildcard_pattern ::= '_'\n" -- '\n' -- '"_" is a soft keyword within any pattern, but only within ' -- 'patterns.\n' -- 'It is an identifier, as usual, even within "match" subject\n' -- 'expressions, "guard"s, and "case" blocks.\n' -- '\n' -- 'In simple terms, "_" will always succeed.\n' -- '\n' -- '\n' -- 'Value Patterns\n' -- '~~~~~~~~~~~~~~\n' -- '\n' -- 'A value pattern represents a named value in Python. Syntax:\n' -- '\n' -- ' value_pattern ::= attr\n' -- ' attr ::= name_or_attr "." NAME\n' -- ' name_or_attr ::= attr | NAME\n' -- '\n' -- 'The dotted name in the pattern is looked up using standard ' -- 'Python name\n' -- 'resolution rules. The pattern succeeds if the value found ' -- 'compares\n' -- 'equal to the subject value (using the "==" equality operator).\n' -- '\n' -- 'In simple terms "NAME1.NAME2" will succeed only if " ' -- '==\n' -- 'NAME1.NAME2"\n' -- '\n' -- 'Note:\n' -- '\n' -- ' If the same value occurs multiple times in the same match ' -- 'statement,\n' -- ' the interpreter may cache the first value found and reuse it ' -- 'rather\n' -- ' than repeat the same lookup. This cache is strictly tied to a ' -- 'given\n' -- ' execution of a given match statement.\n' -- '\n' -- '\n' -- 'Group Patterns\n' -- '~~~~~~~~~~~~~~\n' -- '\n' -- 'A group pattern allows users to add parentheses around patterns ' -- 'to\n' -- 'emphasize the intended grouping. Otherwise, it has no ' -- 'additional\n' -- 'syntax. Syntax:\n' -- '\n' -- ' group_pattern ::= "(" pattern ")"\n' -- '\n' -- 'In simple terms "(P)" has the same effect as "P".\n' -- '\n' -- '\n' -- 'Sequence Patterns\n' -- '~~~~~~~~~~~~~~~~~\n' -- '\n' -- 'A sequence pattern contains several subpatterns to be matched ' -- 'against\n' -- 'sequence elements. The syntax is similar to the unpacking of a ' -- 'list or\n' -- 'tuple.\n' -- '\n' -- ' sequence_pattern ::= "[" [maybe_sequence_pattern] "]"\n' -- ' | "(" [open_sequence_pattern] ")"\n' -- ' open_sequence_pattern ::= maybe_star_pattern "," ' -- '[maybe_sequence_pattern]\n' -- ' maybe_sequence_pattern ::= ",".maybe_star_pattern+ ","?\n' -- ' maybe_star_pattern ::= star_pattern | pattern\n' -- ' star_pattern ::= "*" (capture_pattern | ' -- 'wildcard_pattern)\n' -- '\n' -- 'There is no difference if parentheses or square brackets are ' -- 'used for\n' -- 'sequence patterns (i.e. "(...)" vs "[...]" ).\n' -- '\n' -- 'Note:\n' -- '\n' -- ' A single pattern enclosed in parentheses without a trailing ' -- 'comma\n' -- ' (e.g. "(3 | 4)") is a group pattern. While a single pattern ' -- 'enclosed\n' -- ' in square brackets (e.g. "[3 | 4]") is still a sequence ' -- 'pattern.\n' -- '\n' -- 'At most one star subpattern may be in a sequence pattern. The ' -- 'star\n' -- 'subpattern may occur in any position. If no star subpattern is\n' -- 'present, the sequence pattern is a fixed-length sequence ' -- 'pattern;\n' -- 'otherwise it is a variable-length sequence pattern.\n' -- '\n' -- 'The following is the logical flow for matching a sequence ' -- 'pattern\n' -- 'against a subject value:\n' -- '\n' -- '1. If the subject value is not a sequence [2], the sequence ' -- 'pattern\n' -- ' fails.\n' -- '\n' -- '2. If the subject value is an instance of "str", "bytes" or\n' -- ' "bytearray" the sequence pattern fails.\n' -- '\n' -- '3. The subsequent steps depend on whether the sequence pattern ' -- 'is\n' -- ' fixed or variable-length.\n' -- '\n' -- ' If the sequence pattern is fixed-length:\n' -- '\n' -- ' 1. If the length of the subject sequence is not equal to the ' -- 'number\n' -- ' of subpatterns, the sequence pattern fails\n' -- '\n' -- ' 2. Subpatterns in the sequence pattern are matched to their\n' -- ' corresponding items in the subject sequence from left to ' -- 'right.\n' -- ' Matching stops as soon as a subpattern fails. If all\n' -- ' subpatterns succeed in matching their corresponding item, ' -- 'the\n' -- ' sequence pattern succeeds.\n' -- '\n' -- ' Otherwise, if the sequence pattern is variable-length:\n' -- '\n' -- ' 1. If the length of the subject sequence is less than the ' -- 'number of\n' -- ' non-star subpatterns, the sequence pattern fails.\n' -- '\n' -- ' 2. The leading non-star subpatterns are matched to their\n' -- ' corresponding items as for fixed-length sequences.\n' -- '\n' -- ' 3. If the previous step succeeds, the star subpattern matches ' -- 'a\n' -- ' list formed of the remaining subject items, excluding the\n' -- ' remaining items corresponding to non-star subpatterns ' -- 'following\n' -- ' the star subpattern.\n' -- '\n' -- ' 4. Remaining non-star subpatterns are matched to their\n' -- ' corresponding subject items, as for a fixed-length ' -- 'sequence.\n' -- '\n' -- ' Note:\n' -- '\n' -- ' The length of the subject sequence is obtained via "len()" ' -- '(i.e.\n' -- ' via the "__len__()" protocol). This length may be cached ' -- 'by the\n' -- ' interpreter in a similar manner as value patterns.\n' -- '\n' -- 'In simple terms "[P1, P2, P3," … ", P]" matches only if all ' -- 'the\n' -- 'following happens:\n' -- '\n' -- '* check "" is a sequence\n' -- '\n' -- '* "len(subject) == "\n' -- '\n' -- '* "P1" matches "[0]" (note that this match can also ' -- 'bind\n' -- ' names)\n' -- '\n' -- '* "P2" matches "[1]" (note that this match can also ' -- 'bind\n' -- ' names)\n' -- '\n' -- '* … and so on for the corresponding pattern/element.\n' -- '\n' -- '\n' -- 'Mapping Patterns\n' -- '~~~~~~~~~~~~~~~~\n' -- '\n' -- 'A mapping pattern contains one or more key-value patterns. The ' -- 'syntax\n' -- 'is similar to the construction of a dictionary. Syntax:\n' -- '\n' -- ' mapping_pattern ::= "{" [items_pattern] "}"\n' -- ' items_pattern ::= ",".key_value_pattern+ ","?\n' -- ' key_value_pattern ::= (literal_pattern | value_pattern) ":" ' -- 'pattern\n' -- ' | double_star_pattern\n' -- ' double_star_pattern ::= "**" capture_pattern\n' -- '\n' -- 'At most one double star pattern may be in a mapping pattern. ' -- 'The\n' -- 'double star pattern must be the last subpattern in the mapping\n' -- 'pattern.\n' -- '\n' -- 'Duplicate keys in mapping patterns are disallowed. Duplicate ' -- 'literal\n' -- 'keys will raise a "SyntaxError". Two keys that otherwise have ' -- 'the same\n' -- 'value will raise a "ValueError" at runtime.\n' -- '\n' -- 'The following is the logical flow for matching a mapping ' -- 'pattern\n' -- 'against a subject value:\n' -- '\n' -- '1. If the subject value is not a mapping [3],the mapping ' -- 'pattern\n' -- ' fails.\n' -- '\n' -- '2. If every key given in the mapping pattern is present in the ' -- 'subject\n' -- ' mapping, and the pattern for each key matches the ' -- 'corresponding\n' -- ' item of the subject mapping, the mapping pattern succeeds.\n' -- '\n' -- '3. If duplicate keys are detected in the mapping pattern, the ' -- 'pattern\n' -- ' is considered invalid. A "SyntaxError" is raised for ' -- 'duplicate\n' -- ' literal values; or a "ValueError" for named keys of the same ' -- 'value.\n' -- '\n' -- 'Note:\n' -- '\n' -- ' Key-value pairs are matched using the two-argument form of ' -- 'the\n' -- ' mapping subject’s "get()" method. Matched key-value pairs ' -- 'must\n' -- ' already be present in the mapping, and not created on-the-fly ' -- 'via\n' -- ' "__missing__()" or "__getitem__()".\n' -- '\n' -- 'In simple terms "{KEY1: P1, KEY2: P2, ... }" matches only if all ' -- 'the\n' -- 'following happens:\n' -- '\n' -- '* check "" is a mapping\n' -- '\n' -- '* "KEY1 in "\n' -- '\n' -- '* "P1" matches "[KEY1]"\n' -- '\n' -- '* … and so on for the corresponding KEY/pattern pair.\n' -- '\n' -- '\n' -- 'Class Patterns\n' -- '~~~~~~~~~~~~~~\n' -- '\n' -- 'A class pattern represents a class and its positional and ' -- 'keyword\n' -- 'arguments (if any). Syntax:\n' -- '\n' -- ' class_pattern ::= name_or_attr "(" [pattern_arguments ' -- '","?] ")"\n' -- ' pattern_arguments ::= positional_patterns ["," ' -- 'keyword_patterns]\n' -- ' | keyword_patterns\n' -- ' positional_patterns ::= ",".pattern+\n' -- ' keyword_patterns ::= ",".keyword_pattern+\n' -- ' keyword_pattern ::= NAME "=" pattern\n' -- '\n' -- 'The same keyword should not be repeated in class patterns.\n' -- '\n' -- 'The following is the logical flow for matching a class pattern ' -- 'against\n' -- 'a subject value:\n' -- '\n' -- '1. If "name_or_attr" is not an instance of the builtin "type" , ' -- 'raise\n' -- ' "TypeError".\n' -- '\n' -- '2. If the subject value is not an instance of "name_or_attr" ' -- '(tested\n' -- ' via "isinstance()"), the class pattern fails.\n' -- '\n' -- '3. If no pattern arguments are present, the pattern succeeds.\n' -- ' Otherwise, the subsequent steps depend on whether keyword or\n' -- ' positional argument patterns are present.\n' -- '\n' -- ' For a number of built-in types (specified below), a single\n' -- ' positional subpattern is accepted which will match the ' -- 'entire\n' -- ' subject; for these types keyword patterns also work as for ' -- 'other\n' -- ' types.\n' -- '\n' -- ' If only keyword patterns are present, they are processed as\n' -- ' follows, one by one:\n' -- '\n' -- ' I. The keyword is looked up as an attribute on the subject.\n' -- '\n' -- ' * If this raises an exception other than "AttributeError", ' -- 'the\n' -- ' exception bubbles up.\n' -- '\n' -- ' * If this raises "AttributeError", the class pattern has ' -- 'failed.\n' -- '\n' -- ' * Else, the subpattern associated with the keyword pattern ' -- 'is\n' -- ' matched against the subject’s attribute value. If this ' -- 'fails,\n' -- ' the class pattern fails; if this succeeds, the match ' -- 'proceeds\n' -- ' to the next keyword.\n' -- '\n' -- ' II. If all keyword patterns succeed, the class pattern ' -- 'succeeds.\n' -- '\n' -- ' If any positional patterns are present, they are converted ' -- 'to\n' -- ' keyword patterns using the "__match_args__" attribute on the ' -- 'class\n' -- ' "name_or_attr" before matching:\n' -- '\n' -- ' I. The equivalent of "getattr(cls, "__match_args__", ())" is\n' -- ' called.\n' -- '\n' -- ' * If this raises an exception, the exception bubbles up.\n' -- '\n' -- ' * If the returned value is not a tuple, the conversion ' -- 'fails and\n' -- ' "TypeError" is raised.\n' -- '\n' -- ' * If there are more positional patterns than\n' -- ' "len(cls.__match_args__)", "TypeError" is raised.\n' -- '\n' -- ' * Otherwise, positional pattern "i" is converted to a ' -- 'keyword\n' -- ' pattern using "__match_args__[i]" as the keyword.\n' -- ' "__match_args__[i]" must be a string; if not "TypeError" ' -- 'is\n' -- ' raised.\n' -- '\n' -- ' * If there are duplicate keywords, "TypeError" is raised.\n' -- '\n' -- ' See also:\n' -- '\n' -- ' Customizing positional arguments in class pattern ' -- 'matching\n' -- '\n' -- ' II. Once all positional patterns have been converted to ' -- 'keyword\n' -- ' patterns,\n' -- ' the match proceeds as if there were only keyword ' -- 'patterns.\n' -- '\n' -- ' For the following built-in types the handling of positional\n' -- ' subpatterns is different:\n' -- '\n' -- ' * "bool"\n' -- '\n' -- ' * "bytearray"\n' -- '\n' -- ' * "bytes"\n' -- '\n' -- ' * "dict"\n' -- '\n' -- ' * "float"\n' -- '\n' -- ' * "frozenset"\n' -- '\n' -- ' * "int"\n' -- '\n' -- ' * "list"\n' -- '\n' -- ' * "set"\n' -- '\n' -- ' * "str"\n' -- '\n' -- ' * "tuple"\n' -- '\n' -- ' These classes accept a single positional argument, and the ' -- 'pattern\n' -- ' there is matched against the whole object rather than an ' -- 'attribute.\n' -- ' For example "int(0|1)" matches the value "0", but not the ' -- 'value\n' -- ' "0.0".\n' -- '\n' -- 'In simple terms "CLS(P1, attr=P2)" matches only if the ' -- 'following\n' -- 'happens:\n' -- '\n' -- '* "isinstance(, CLS)"\n' -- '\n' -- '* convert "P1" to a keyword pattern using "CLS.__match_args__"\n' -- '\n' -- '* For each keyword argument "attr=P2":\n' -- '\n' -- ' * "hasattr(, "attr")"\n' -- '\n' -- ' * "P2" matches ".attr"\n' -- '\n' -- '* … and so on for the corresponding keyword argument/pattern ' -- 'pair.\n' -- '\n' -- 'See also:\n' -- '\n' -- ' * **PEP 634** – Structural Pattern Matching: Specification\n' -- '\n' -- ' * **PEP 636** – Structural Pattern Matching: Tutorial\n' -- '\n' -- '\n' -- 'Function definitions\n' -- '====================\n' -- '\n' -- 'A function definition defines a user-defined function object ' -- '(see\n' -- 'section The standard type hierarchy):\n' -- '\n' -- ' funcdef ::= [decorators] "def" funcname ' -- '[type_params] "(" [parameter_list] ")"\n' -- ' ["->" expression] ":" suite\n' -- ' decorators ::= decorator+\n' -- ' decorator ::= "@" assignment_expression ' -- 'NEWLINE\n' -- ' parameter_list ::= defparameter ("," ' -- 'defparameter)* "," "/" ["," [parameter_list_no_posonly]]\n' -- ' | parameter_list_no_posonly\n' -- ' parameter_list_no_posonly ::= defparameter ("," ' -- 'defparameter)* ["," [parameter_list_starargs]]\n' -- ' | parameter_list_starargs\n' -- ' parameter_list_starargs ::= "*" [star_parameter] ("," ' -- 'defparameter)* ["," ["**" parameter [","]]]\n' -- ' | "**" parameter [","]\n' -- ' parameter ::= identifier [":" expression]\n' -- ' star_parameter ::= identifier [":" ["*"] ' -- 'expression]\n' -- ' defparameter ::= parameter ["=" expression]\n' -- ' funcname ::= identifier\n' -- '\n' -- 'A function definition is an executable statement. Its execution ' -- 'binds\n' -- 'the function name in the current local namespace to a function ' -- 'object\n' -- '(a wrapper around the executable code for the function). This\n' -- 'function object contains a reference to the current global ' -- 'namespace\n' -- 'as the global namespace to be used when the function is called.\n' -- '\n' -- 'The function definition does not execute the function body; this ' -- 'gets\n' -- 'executed only when the function is called. [4]\n' -- '\n' -- 'A function definition may be wrapped by one or more *decorator*\n' -- 'expressions. Decorator expressions are evaluated when the ' -- 'function is\n' -- 'defined, in the scope that contains the function definition. ' -- 'The\n' -- 'result must be a callable, which is invoked with the function ' -- 'object\n' -- 'as the only argument. The returned value is bound to the ' -- 'function name\n' -- 'instead of the function object. Multiple decorators are applied ' -- 'in\n' -- 'nested fashion. For example, the following code\n' -- '\n' -- ' @f1(arg)\n' -- ' @f2\n' -- ' def func(): pass\n' -- '\n' -- 'is roughly equivalent to\n' -- '\n' -- ' def func(): pass\n' -- ' func = f1(arg)(f2(func))\n' -- '\n' -- 'except that the original function is not temporarily bound to ' -- 'the name\n' -- '"func".\n' -- '\n' -- 'Changed in version 3.9: Functions may be decorated with any ' -- 'valid\n' -- '"assignment_expression". Previously, the grammar was much more\n' -- 'restrictive; see **PEP 614** for details.\n' -- '\n' -- 'A list of type parameters may be given in square brackets ' -- 'between the\n' -- 'function’s name and the opening parenthesis for its parameter ' -- 'list.\n' -- 'This indicates to static type checkers that the function is ' -- 'generic.\n' -- 'At runtime, the type parameters can be retrieved from the ' -- 'function’s\n' -- '"__type_params__" attribute. See Generic functions for more.\n' -- '\n' -- 'Changed in version 3.12: Type parameter lists are new in Python ' -- '3.12.\n' -- '\n' -- 'When one or more *parameters* have the form *parameter* "="\n' -- '*expression*, the function is said to have “default parameter ' -- 'values.â€\n' -- 'For a parameter with a default value, the corresponding ' -- '*argument* may\n' -- 'be omitted from a call, in which case the parameter’s default ' -- 'value is\n' -- 'substituted. If a parameter has a default value, all following\n' -- 'parameters up until the “"*"†must also have a default value — ' -- 'this is\n' -- 'a syntactic restriction that is not expressed by the grammar.\n' -- '\n' -- '**Default parameter values are evaluated from left to right when ' -- 'the\n' -- 'function definition is executed.** This means that the ' -- 'expression is\n' -- 'evaluated once, when the function is defined, and that the same ' -- '“pre-\n' -- 'computed†value is used for each call. This is especially ' -- 'important\n' -- 'to understand when a default parameter value is a mutable ' -- 'object, such\n' -- 'as a list or a dictionary: if the function modifies the object ' -- '(e.g.\n' -- 'by appending an item to a list), the default parameter value is ' -- 'in\n' -- 'effect modified. This is generally not what was intended. A ' -- 'way\n' -- 'around this is to use "None" as the default, and explicitly test ' -- 'for\n' -- 'it in the body of the function, e.g.:\n' -- '\n' -- ' def whats_on_the_telly(penguin=None):\n' -- ' if penguin is None:\n' -- ' penguin = []\n' -- ' penguin.append("property of the zoo")\n' -- ' return penguin\n' -- '\n' -- 'Function call semantics are described in more detail in section ' -- 'Calls.\n' -- 'A function call always assigns values to all parameters ' -- 'mentioned in\n' -- 'the parameter list, either from positional arguments, from ' -- 'keyword\n' -- 'arguments, or from default values. If the form “"*identifier"†' -- 'is\n' -- 'present, it is initialized to a tuple receiving any excess ' -- 'positional\n' -- 'parameters, defaulting to the empty tuple. If the form\n' -- '“"**identifier"†is present, it is initialized to a new ordered\n' -- 'mapping receiving any excess keyword arguments, defaulting to a ' -- 'new\n' -- 'empty mapping of the same type. Parameters after “"*"†or\n' -- '“"*identifier"†are keyword-only parameters and may only be ' -- 'passed by\n' -- 'keyword arguments. Parameters before “"/"†are positional-only\n' -- 'parameters and may only be passed by positional arguments.\n' -- '\n' -- 'Changed in version 3.8: The "/" function parameter syntax may be ' -- 'used\n' -- 'to indicate positional-only parameters. See **PEP 570** for ' -- 'details.\n' -- '\n' -- 'Parameters may have an *annotation* of the form “": ' -- 'expression"â€\n' -- 'following the parameter name. Any parameter may have an ' -- 'annotation,\n' -- 'even those of the form "*identifier" or "**identifier". (As a ' -- 'special\n' -- 'case, parameters of the form "*identifier" may have an ' -- 'annotation “":\n' -- '*expression"â€.) Functions may have “return†annotation of the ' -- 'form\n' -- '“"-> expression"†after the parameter list. These annotations ' -- 'can be\n' -- 'any valid Python expression. The presence of annotations does ' -- 'not\n' -- 'change the semantics of a function. See Annotations for more\n' -- 'information on annotations.\n' -- '\n' -- 'Changed in version 3.11: Parameters of the form “"*identifier"†' -- 'may\n' -- 'have an annotation “": *expression"â€. See **PEP 646**.\n' -- '\n' -- 'It is also possible to create anonymous functions (functions not ' -- 'bound\n' -- 'to a name), for immediate use in expressions. This uses lambda\n' -- 'expressions, described in section Lambdas. Note that the ' -- 'lambda\n' -- 'expression is merely a shorthand for a simplified function ' -- 'definition;\n' -- 'a function defined in a “"def"†statement can be passed around ' -- 'or\n' -- 'assigned to another name just like a function defined by a ' -- 'lambda\n' -- 'expression. The “"def"†form is actually more powerful since ' -- 'it\n' -- 'allows the execution of multiple statements and annotations.\n' -- '\n' -- '**Programmer’s note:** Functions are first-class objects. A ' -- '“"def"â€\n' -- 'statement executed inside a function definition defines a local\n' -- 'function that can be returned or passed around. Free variables ' -- 'used\n' -- 'in the nested function can access the local variables of the ' -- 'function\n' -- 'containing the def. See section Naming and binding for ' -- 'details.\n' -- '\n' -- 'See also:\n' -- '\n' -- ' **PEP 3107** - Function Annotations\n' -- ' The original specification for function annotations.\n' -- '\n' -- ' **PEP 484** - Type Hints\n' -- ' Definition of a standard meaning for annotations: type ' -- 'hints.\n' -- '\n' -- ' **PEP 526** - Syntax for Variable Annotations\n' -- ' Ability to type hint variable declarations, including ' -- 'class\n' -- ' variables and instance variables.\n' -- '\n' -- ' **PEP 563** - Postponed Evaluation of Annotations\n' -- ' Support for forward references within annotations by ' -- 'preserving\n' -- ' annotations in a string form at runtime instead of eager\n' -- ' evaluation.\n' -- '\n' -- ' **PEP 318** - Decorators for Functions and Methods\n' -- ' Function and method decorators were introduced. Class ' -- 'decorators\n' -- ' were introduced in **PEP 3129**.\n' -- '\n' -- '\n' -- 'Class definitions\n' -- '=================\n' -- '\n' -- 'A class definition defines a class object (see section The ' -- 'standard\n' -- 'type hierarchy):\n' -- '\n' -- ' classdef ::= [decorators] "class" classname [type_params] ' -- '[inheritance] ":" suite\n' -- ' inheritance ::= "(" [argument_list] ")"\n' -- ' classname ::= identifier\n' -- '\n' -- 'A class definition is an executable statement. The inheritance ' -- 'list\n' -- 'usually gives a list of base classes (see Metaclasses for more\n' -- 'advanced uses), so each item in the list should evaluate to a ' -- 'class\n' -- 'object which allows subclassing. Classes without an inheritance ' -- 'list\n' -- 'inherit, by default, from the base class "object"; hence,\n' -- '\n' -- ' class Foo:\n' -- ' pass\n' -- '\n' -- 'is equivalent to\n' -- '\n' -- ' class Foo(object):\n' -- ' pass\n' -- '\n' -- 'The class’s suite is then executed in a new execution frame ' -- '(see\n' -- 'Naming and binding), using a newly created local namespace and ' -- 'the\n' -- 'original global namespace. (Usually, the suite contains mostly\n' -- 'function definitions.) When the class’s suite finishes ' -- 'execution, its\n' -- 'execution frame is discarded but its local namespace is saved. ' -- '[5] A\n' -- 'class object is then created using the inheritance list for the ' -- 'base\n' -- 'classes and the saved local namespace for the attribute ' -- 'dictionary.\n' -- 'The class name is bound to this class object in the original ' -- 'local\n' -- 'namespace.\n' -- '\n' -- 'The order in which attributes are defined in the class body is\n' -- 'preserved in the new class’s "__dict__". Note that this is ' -- 'reliable\n' -- 'only right after the class is created and only for classes that ' -- 'were\n' -- 'defined using the definition syntax.\n' -- '\n' -- 'Class creation can be customized heavily using metaclasses.\n' -- '\n' -- 'Classes can also be decorated: just like when decorating ' -- 'functions,\n' -- '\n' -- ' @f1(arg)\n' -- ' @f2\n' -- ' class Foo: pass\n' -- '\n' -- 'is roughly equivalent to\n' -- '\n' -- ' class Foo: pass\n' -- ' Foo = f1(arg)(f2(Foo))\n' -- '\n' -- 'The evaluation rules for the decorator expressions are the same ' -- 'as for\n' -- 'function decorators. The result is then bound to the class ' -- 'name.\n' -- '\n' -- 'Changed in version 3.9: Classes may be decorated with any valid\n' -- '"assignment_expression". Previously, the grammar was much more\n' -- 'restrictive; see **PEP 614** for details.\n' -- '\n' -- 'A list of type parameters may be given in square brackets ' -- 'immediately\n' -- 'after the class’s name. This indicates to static type checkers ' -- 'that\n' -- 'the class is generic. At runtime, the type parameters can be ' -- 'retrieved\n' -- 'from the class’s "__type_params__" attribute. See Generic ' -- 'classes for\n' -- 'more.\n' -- '\n' -- 'Changed in version 3.12: Type parameter lists are new in Python ' -- '3.12.\n' -- '\n' -- '**Programmer’s note:** Variables defined in the class definition ' -- 'are\n' -- 'class attributes; they are shared by instances. Instance ' -- 'attributes\n' -- 'can be set in a method with "self.name = value". Both class ' -- 'and\n' -- 'instance attributes are accessible through the notation ' -- '“"self.name"â€,\n' -- 'and an instance attribute hides a class attribute with the same ' -- 'name\n' -- 'when accessed in this way. Class attributes can be used as ' -- 'defaults\n' -- 'for instance attributes, but using mutable values there can lead ' -- 'to\n' -- 'unexpected results. Descriptors can be used to create instance\n' -- 'variables with different implementation details.\n' -- '\n' -- 'See also:\n' -- '\n' -- ' **PEP 3115** - Metaclasses in Python 3000\n' -- ' The proposal that changed the declaration of metaclasses to ' -- 'the\n' -- ' current syntax, and the semantics for how classes with\n' -- ' metaclasses are constructed.\n' -- '\n' -- ' **PEP 3129** - Class Decorators\n' -- ' The proposal that added class decorators. Function and ' -- 'method\n' -- ' decorators were introduced in **PEP 318**.\n' -- '\n' -- '\n' -- 'Coroutines\n' -- '==========\n' -- '\n' -- 'Added in version 3.5.\n' -- '\n' -- '\n' -- 'Coroutine function definition\n' -- '-----------------------------\n' -- '\n' -- ' async_funcdef ::= [decorators] "async" "def" funcname "(" ' -- '[parameter_list] ")"\n' -- ' ["->" expression] ":" suite\n' -- '\n' -- 'Execution of Python coroutines can be suspended and resumed at ' -- 'many\n' -- 'points (see *coroutine*). "await" expressions, "async for" and ' -- '"async\n' -- 'with" can only be used in the body of a coroutine function.\n' -- '\n' -- 'Functions defined with "async def" syntax are always coroutine\n' -- 'functions, even if they do not contain "await" or "async" ' -- 'keywords.\n' -- '\n' -- 'It is a "SyntaxError" to use a "yield from" expression inside ' -- 'the body\n' -- 'of a coroutine function.\n' -- '\n' -- 'An example of a coroutine function:\n' -- '\n' -- ' async def func(param1, param2):\n' -- ' do_stuff()\n' -- ' await some_coroutine()\n' -- '\n' -- 'Changed in version 3.7: "await" and "async" are now keywords;\n' -- 'previously they were only treated as such inside the body of a\n' -- 'coroutine function.\n' -- '\n' -- '\n' -- 'The "async for" statement\n' -- '-------------------------\n' -- '\n' -- ' async_for_stmt ::= "async" for_stmt\n' -- '\n' -- 'An *asynchronous iterable* provides an "__aiter__" method that\n' -- 'directly returns an *asynchronous iterator*, which can call\n' -- 'asynchronous code in its "__anext__" method.\n' -- '\n' -- 'The "async for" statement allows convenient iteration over\n' -- 'asynchronous iterables.\n' -- '\n' -- 'The following code:\n' -- '\n' -- ' async for TARGET in ITER:\n' -- ' SUITE\n' -- ' else:\n' -- ' SUITE2\n' -- '\n' -- 'Is semantically equivalent to:\n' -- '\n' -- ' iter = (ITER)\n' -- ' iter = type(iter).__aiter__(iter)\n' -- ' running = True\n' -- '\n' -- ' while running:\n' -- ' try:\n' -- ' TARGET = await type(iter).__anext__(iter)\n' -- ' except StopAsyncIteration:\n' -- ' running = False\n' -- ' else:\n' -- ' SUITE\n' -- ' else:\n' -- ' SUITE2\n' -- '\n' -- 'See also "__aiter__()" and "__anext__()" for details.\n' -- '\n' -- 'It is a "SyntaxError" to use an "async for" statement outside ' -- 'the body\n' -- 'of a coroutine function.\n' -- '\n' -- '\n' -- 'The "async with" statement\n' -- '--------------------------\n' -- '\n' -- ' async_with_stmt ::= "async" with_stmt\n' -- '\n' -- 'An *asynchronous context manager* is a *context manager* that is ' -- 'able\n' -- 'to suspend execution in its *enter* and *exit* methods.\n' -- '\n' -- 'The following code:\n' -- '\n' -- ' async with EXPRESSION as TARGET:\n' -- ' SUITE\n' -- '\n' -- 'is semantically equivalent to:\n' -- '\n' -- ' manager = (EXPRESSION)\n' -- ' aenter = type(manager).__aenter__\n' -- ' aexit = type(manager).__aexit__\n' -- ' value = await aenter(manager)\n' -- ' hit_except = False\n' -- '\n' -- ' try:\n' -- ' TARGET = value\n' -- ' SUITE\n' -- ' except:\n' -- ' hit_except = True\n' -- ' if not await aexit(manager, *sys.exc_info()):\n' -- ' raise\n' -- ' finally:\n' -- ' if not hit_except:\n' -- ' await aexit(manager, None, None, None)\n' -- '\n' -- 'See also "__aenter__()" and "__aexit__()" for details.\n' -- '\n' -- 'It is a "SyntaxError" to use an "async with" statement outside ' -- 'the\n' -- 'body of a coroutine function.\n' -- '\n' -- 'See also:\n' -- '\n' -- ' **PEP 492** - Coroutines with async and await syntax\n' -- ' The proposal that made coroutines a proper standalone ' -- 'concept in\n' -- ' Python, and added supporting syntax.\n' -- '\n' -- '\n' -- 'Type parameter lists\n' -- '====================\n' -- '\n' -- 'Added in version 3.12.\n' -- '\n' -- 'Changed in version 3.13: Support for default values was added ' -- '(see\n' -- '**PEP 696**).\n' -- '\n' -- ' type_params ::= "[" type_param ("," type_param)* "]"\n' -- ' type_param ::= typevar | typevartuple | paramspec\n' -- ' typevar ::= identifier (":" expression)? ("=" ' -- 'expression)?\n' -- ' typevartuple ::= "*" identifier ("=" expression)?\n' -- ' paramspec ::= "**" identifier ("=" expression)?\n' -- '\n' -- 'Functions (including coroutines), classes and type aliases may ' -- 'contain\n' -- 'a type parameter list:\n' -- '\n' -- ' def max[T](args: list[T]) -> T:\n' -- ' ...\n' -- '\n' -- ' async def amax[T](args: list[T]) -> T:\n' -- ' ...\n' -- '\n' -- ' class Bag[T]:\n' -- ' def __iter__(self) -> Iterator[T]:\n' -- ' ...\n' -- '\n' -- ' def add(self, arg: T) -> None:\n' -- ' ...\n' -- '\n' -- ' type ListOrSet[T] = list[T] | set[T]\n' -- '\n' -- 'Semantically, this indicates that the function, class, or type ' -- 'alias\n' -- 'is generic over a type variable. This information is primarily ' -- 'used by\n' -- 'static type checkers, and at runtime, generic objects behave ' -- 'much like\n' -- 'their non-generic counterparts.\n' -- '\n' -- 'Type parameters are declared in square brackets ("[]") ' -- 'immediately\n' -- 'after the name of the function, class, or type alias. The type\n' -- 'parameters are accessible within the scope of the generic ' -- 'object, but\n' -- 'not elsewhere. Thus, after a declaration "def func[T](): pass", ' -- 'the\n' -- 'name "T" is not available in the module scope. Below, the ' -- 'semantics of\n' -- 'generic objects are described with more precision. The scope of ' -- 'type\n' -- 'parameters is modeled with a special function (technically, an\n' -- 'annotation scope) that wraps the creation of the generic ' -- 'object.\n' -- '\n' -- 'Generic functions, classes, and type aliases have a ' -- '"__type_params__"\n' -- 'attribute listing their type parameters.\n' -- '\n' -- 'Type parameters come in three kinds:\n' -- '\n' -- '* "typing.TypeVar", introduced by a plain name (e.g., "T").\n' -- ' Semantically, this represents a single type to a type ' -- 'checker.\n' -- '\n' -- '* "typing.TypeVarTuple", introduced by a name prefixed with a ' -- 'single\n' -- ' asterisk (e.g., "*Ts"). Semantically, this stands for a tuple ' -- 'of any\n' -- ' number of types.\n' -- '\n' -- '* "typing.ParamSpec", introduced by a name prefixed with two ' -- 'asterisks\n' -- ' (e.g., "**P"). Semantically, this stands for the parameters of ' -- 'a\n' -- ' callable.\n' -- '\n' -- '"typing.TypeVar" declarations can define *bounds* and ' -- '*constraints*\n' -- 'with a colon (":") followed by an expression. A single ' -- 'expression\n' -- 'after the colon indicates a bound (e.g. "T: int"). Semantically, ' -- 'this\n' -- 'means that the "typing.TypeVar" can only represent types that ' -- 'are a\n' -- 'subtype of this bound. A parenthesized tuple of expressions ' -- 'after the\n' -- 'colon indicates a set of constraints (e.g. "T: (str, bytes)"). ' -- 'Each\n' -- 'member of the tuple should be a type (again, this is not ' -- 'enforced at\n' -- 'runtime). Constrained type variables can only take on one of the ' -- 'types\n' -- 'in the list of constraints.\n' -- '\n' -- 'For "typing.TypeVar"s declared using the type parameter list ' -- 'syntax,\n' -- 'the bound and constraints are not evaluated when the generic ' -- 'object is\n' -- 'created, but only when the value is explicitly accessed through ' -- 'the\n' -- 'attributes "__bound__" and "__constraints__". To accomplish ' -- 'this, the\n' -- 'bounds or constraints are evaluated in a separate annotation ' -- 'scope.\n' -- '\n' -- '"typing.TypeVarTuple"s and "typing.ParamSpec"s cannot have ' -- 'bounds or\n' -- 'constraints.\n' -- '\n' -- 'All three flavors of type parameters can also have a *default ' -- 'value*,\n' -- 'which is used when the type parameter is not explicitly ' -- 'provided. This\n' -- 'is added by appending a single equals sign ("=") followed by an\n' -- 'expression. Like the bounds and constraints of type variables, ' -- 'the\n' -- 'default value is not evaluated when the object is created, but ' -- 'only\n' -- 'when the type parameter’s "__default__" attribute is accessed. ' -- 'To this\n' -- 'end, the default value is evaluated in a separate annotation ' -- 'scope. If\n' -- 'no default value is specified for a type parameter, the ' -- '"__default__"\n' -- 'attribute is set to the special sentinel object ' -- '"typing.NoDefault".\n' -- '\n' -- 'The following example indicates the full set of allowed type ' -- 'parameter\n' -- 'declarations:\n' -- '\n' -- ' def overly_generic[\n' -- ' SimpleTypeVar,\n' -- ' TypeVarWithDefault = int,\n' -- ' TypeVarWithBound: int,\n' -- ' TypeVarWithConstraints: (str, bytes),\n' -- ' *SimpleTypeVarTuple = (int, float),\n' -- ' **SimpleParamSpec = (str, bytearray),\n' -- ' ](\n' -- ' a: SimpleTypeVar,\n' -- ' b: TypeVarWithDefault,\n' -- ' c: TypeVarWithBound,\n' -- ' d: Callable[SimpleParamSpec, TypeVarWithConstraints],\n' -- ' *e: SimpleTypeVarTuple,\n' -- ' ): ...\n' -- '\n' -- '\n' -- 'Generic functions\n' -- '-----------------\n' -- '\n' -- 'Generic functions are declared as follows:\n' -- '\n' -- ' def func[T](arg: T): ...\n' -- '\n' -- 'This syntax is equivalent to:\n' -- '\n' -- ' annotation-def TYPE_PARAMS_OF_func():\n' -- ' T = typing.TypeVar("T")\n' -- ' def func(arg: T): ...\n' -- ' func.__type_params__ = (T,)\n' -- ' return func\n' -- ' func = TYPE_PARAMS_OF_func()\n' -- '\n' -- 'Here "annotation-def" indicates an annotation scope, which is ' -- 'not\n' -- 'actually bound to any name at runtime. (One other liberty is ' -- 'taken in\n' -- 'the translation: the syntax does not go through attribute access ' -- 'on\n' -- 'the "typing" module, but creates an instance of ' -- '"typing.TypeVar"\n' -- 'directly.)\n' -- '\n' -- 'The annotations of generic functions are evaluated within the\n' -- 'annotation scope used for declaring the type parameters, but ' -- 'the\n' -- 'function’s defaults and decorators are not.\n' -- '\n' -- 'The following example illustrates the scoping rules for these ' -- 'cases,\n' -- 'as well as for additional flavors of type parameters:\n' -- '\n' -- ' @decorator\n' -- ' def func[T: int, *Ts, **P](*args: *Ts, arg: Callable[P, T] = ' -- 'some_default):\n' -- ' ...\n' -- '\n' -- 'Except for the lazy evaluation of the "TypeVar" bound, this is\n' -- 'equivalent to:\n' -- '\n' -- ' DEFAULT_OF_arg = some_default\n' -- '\n' -- ' annotation-def TYPE_PARAMS_OF_func():\n' -- '\n' -- ' annotation-def BOUND_OF_T():\n' -- ' return int\n' -- ' # In reality, BOUND_OF_T() is evaluated only on demand.\n' -- ' T = typing.TypeVar("T", bound=BOUND_OF_T())\n' -- '\n' -- ' Ts = typing.TypeVarTuple("Ts")\n' -- ' P = typing.ParamSpec("P")\n' -- '\n' -- ' def func(*args: *Ts, arg: Callable[P, T] = ' -- 'DEFAULT_OF_arg):\n' -- ' ...\n' -- '\n' -- ' func.__type_params__ = (T, Ts, P)\n' -- ' return func\n' -- ' func = decorator(TYPE_PARAMS_OF_func())\n' -- '\n' -- 'The capitalized names like "DEFAULT_OF_arg" are not actually ' -- 'bound at\n' -- 'runtime.\n' -- '\n' -- '\n' -- 'Generic classes\n' -- '---------------\n' -- '\n' -- 'Generic classes are declared as follows:\n' -- '\n' -- ' class Bag[T]: ...\n' -- '\n' -- 'This syntax is equivalent to:\n' -- '\n' -- ' annotation-def TYPE_PARAMS_OF_Bag():\n' -- ' T = typing.TypeVar("T")\n' -- ' class Bag(typing.Generic[T]):\n' -- ' __type_params__ = (T,)\n' -- ' ...\n' -- ' return Bag\n' -- ' Bag = TYPE_PARAMS_OF_Bag()\n' -- '\n' -- 'Here again "annotation-def" (not a real keyword) indicates an\n' -- 'annotation scope, and the name "TYPE_PARAMS_OF_Bag" is not ' -- 'actually\n' -- 'bound at runtime.\n' -- '\n' -- 'Generic classes implicitly inherit from "typing.Generic". The ' -- 'base\n' -- 'classes and keyword arguments of generic classes are evaluated ' -- 'within\n' -- 'the type scope for the type parameters, and decorators are ' -- 'evaluated\n' -- 'outside that scope. This is illustrated by this example:\n' -- '\n' -- ' @decorator\n' -- ' class Bag(Base[T], arg=T): ...\n' -- '\n' -- 'This is equivalent to:\n' -- '\n' -- ' annotation-def TYPE_PARAMS_OF_Bag():\n' -- ' T = typing.TypeVar("T")\n' -- ' class Bag(Base[T], typing.Generic[T], arg=T):\n' -- ' __type_params__ = (T,)\n' -- ' ...\n' -- ' return Bag\n' -- ' Bag = decorator(TYPE_PARAMS_OF_Bag())\n' -- '\n' -- '\n' -- 'Generic type aliases\n' -- '--------------------\n' -- '\n' -- 'The "type" statement can also be used to create a generic type ' -- 'alias:\n' -- '\n' -- ' type ListOrSet[T] = list[T] | set[T]\n' -- '\n' -- 'Except for the lazy evaluation of the value, this is equivalent ' -- 'to:\n' -- '\n' -- ' annotation-def TYPE_PARAMS_OF_ListOrSet():\n' -- ' T = typing.TypeVar("T")\n' -- '\n' -- ' annotation-def VALUE_OF_ListOrSet():\n' -- ' return list[T] | set[T]\n' -- ' # In reality, the value is lazily evaluated\n' -- ' return typing.TypeAliasType("ListOrSet", ' -- 'VALUE_OF_ListOrSet(), type_params=(T,))\n' -- ' ListOrSet = TYPE_PARAMS_OF_ListOrSet()\n' -- '\n' -- 'Here, "annotation-def" (not a real keyword) indicates an ' -- 'annotation\n' -- 'scope. The capitalized names like "TYPE_PARAMS_OF_ListOrSet" are ' -- 'not\n' -- 'actually bound at runtime.\n' -- '\n' -- '\n' -- 'Annotations\n' -- '===========\n' -- '\n' -- 'Changed in version 3.14: Annotations are now lazily evaluated ' -- 'by\n' -- 'default.\n' -- '\n' -- 'Variables and function parameters may carry *annotations*, ' -- 'created by\n' -- 'adding a colon after the name, followed by an expression:\n' -- '\n' -- ' x: annotation = 1\n' -- ' def f(param: annotation): ...\n' -- '\n' -- 'Functions may also carry a return annotation following an ' -- 'arrow:\n' -- '\n' -- ' def f() -> annotation: ...\n' -- '\n' -- 'Annotations are conventionally used for *type hints*, but this ' -- 'is not\n' -- 'enforced by the language, and in general annotations may ' -- 'contain\n' -- 'arbitrary expressions. The presence of annotations does not ' -- 'change the\n' -- 'runtime semantics of the code, except if some mechanism is used ' -- 'that\n' -- 'introspects and uses the annotations (such as "dataclasses" or\n' -- '"functools.singledispatch()").\n' -- '\n' -- 'By default, annotations are lazily evaluated in a annotation ' -- 'scope.\n' -- 'This means that they are not evaluated when the code containing ' -- 'the\n' -- 'annotation is evaluated. Instead, the interpreter saves ' -- 'information\n' -- 'that can be used to evaluate the annotation later if requested. ' -- 'The\n' -- '"annotationlib" module provides tools for evaluating ' -- 'annotations.\n' -- '\n' -- 'If the future statement "from __future__ import annotations" is\n' -- 'present, all annotations are instead stored as strings:\n' -- '\n' -- ' >>> from __future__ import annotations\n' -- ' >>> def f(param: annotation): ...\n' -- ' >>> f.__annotations__\n' -- " {'param': 'annotation'}\n" -- '\n' -- '-[ Footnotes ]-\n' -- '\n' -- '[1] The exception is propagated to the invocation stack unless ' -- 'there\n' -- ' is a "finally" clause which happens to raise another ' -- 'exception.\n' -- ' That new exception causes the old one to be lost.\n' -- '\n' -- '[2] In pattern matching, a sequence is defined as one of the\n' -- ' following:\n' -- '\n' -- ' * a class that inherits from "collections.abc.Sequence"\n' -- '\n' -- ' * a Python class that has been registered as\n' -- ' "collections.abc.Sequence"\n' -- '\n' -- ' * a builtin class that has its (CPython) ' -- '"Py_TPFLAGS_SEQUENCE" bit\n' -- ' set\n' -- '\n' -- ' * a class that inherits from any of the above\n' -- '\n' -- ' The following standard library classes are sequences:\n' -- '\n' -- ' * "array.array"\n' -- '\n' -- ' * "collections.deque"\n' -- '\n' -- ' * "list"\n' -- '\n' -- ' * "memoryview"\n' -- '\n' -- ' * "range"\n' -- '\n' -- ' * "tuple"\n' -- '\n' -- ' Note:\n' -- '\n' -- ' Subject values of type "str", "bytes", and "bytearray" do ' -- 'not\n' -- ' match sequence patterns.\n' -- '\n' -- '[3] In pattern matching, a mapping is defined as one of the ' -- 'following:\n' -- '\n' -- ' * a class that inherits from "collections.abc.Mapping"\n' -- '\n' -- ' * a Python class that has been registered as\n' -- ' "collections.abc.Mapping"\n' -- '\n' -- ' * a builtin class that has its (CPython) ' -- '"Py_TPFLAGS_MAPPING" bit\n' -- ' set\n' -- '\n' -- ' * a class that inherits from any of the above\n' -- '\n' -- ' The standard library classes "dict" and ' -- '"types.MappingProxyType"\n' -- ' are mappings.\n' -- '\n' -- '[4] A string literal appearing as the first statement in the ' -- 'function\n' -- ' body is transformed into the function’s "__doc__" attribute ' -- 'and\n' -- ' therefore the function’s *docstring*.\n' -- '\n' -- '[5] A string literal appearing as the first statement in the ' -- 'class\n' -- ' body is transformed into the namespace’s "__doc__" item and\n' -- ' therefore the class’s *docstring*.\n', -- 'context-managers': 'With Statement Context Managers\n' -- '*******************************\n' -- '\n' -- 'A *context manager* is an object that defines the ' -- 'runtime context to\n' -- 'be established when executing a "with" statement. The ' -- 'context manager\n' -- 'handles the entry into, and the exit from, the desired ' -- 'runtime context\n' -- 'for the execution of the block of code. Context ' -- 'managers are normally\n' -- 'invoked using the "with" statement (described in section ' -- 'The with\n' -- 'statement), but can also be used by directly invoking ' -- 'their methods.\n' -- '\n' -- 'Typical uses of context managers include saving and ' -- 'restoring various\n' -- 'kinds of global state, locking and unlocking resources, ' -- 'closing opened\n' -- 'files, etc.\n' -- '\n' -- 'For more information on context managers, see Context ' -- 'Manager Types.\n' -- 'The "object" class itself does not provide the context ' -- 'manager\n' -- 'methods.\n' -- '\n' -- 'object.__enter__(self)\n' -- '\n' -- ' Enter the runtime context related to this object. The ' -- '"with"\n' -- ' statement will bind this method’s return value to the ' -- 'target(s)\n' -- ' specified in the "as" clause of the statement, if ' -- 'any.\n' -- '\n' -- 'object.__exit__(self, exc_type, exc_value, traceback)\n' -- '\n' -- ' Exit the runtime context related to this object. The ' -- 'parameters\n' -- ' describe the exception that caused the context to be ' -- 'exited. If the\n' -- ' context was exited without an exception, all three ' -- 'arguments will\n' -- ' be "None".\n' -- '\n' -- ' If an exception is supplied, and the method wishes to ' -- 'suppress the\n' -- ' exception (i.e., prevent it from being propagated), ' -- 'it should\n' -- ' return a true value. Otherwise, the exception will be ' -- 'processed\n' -- ' normally upon exit from this method.\n' -- '\n' -- ' Note that "__exit__()" methods should not reraise the ' -- 'passed-in\n' -- ' exception; this is the caller’s responsibility.\n' -- '\n' -- 'See also:\n' -- '\n' -- ' **PEP 343** - The “with†statement\n' -- ' The specification, background, and examples for the ' -- 'Python "with"\n' -- ' statement.\n', -- 'continue': 'The "continue" statement\n' -- '************************\n' -- '\n' -- ' continue_stmt ::= "continue"\n' -- '\n' -- '"continue" may only occur syntactically nested in a "for" or ' -- '"while"\n' -- 'loop, but not nested in a function or class definition within ' -- 'that\n' -- 'loop. It continues with the next cycle of the nearest enclosing ' -- 'loop.\n' -- '\n' -- 'When "continue" passes control out of a "try" statement with a\n' -- '"finally" clause, that "finally" clause is executed before ' -- 'really\n' -- 'starting the next loop cycle.\n', -- 'conversions': 'Arithmetic conversions\n' -- '**********************\n' -- '\n' -- 'When a description of an arithmetic operator below uses the ' -- 'phrase\n' -- '“the numeric arguments are converted to a common real typeâ€, ' -- 'this\n' -- 'means that the operator implementation for built-in types ' -- 'works as\n' -- 'follows:\n' -- '\n' -- '* If both arguments are complex numbers, no conversion is ' -- 'performed;\n' -- '\n' -- '* if either argument is a complex or a floating-point number, ' -- 'the\n' -- ' other is converted to a floating-point number;\n' -- '\n' -- '* otherwise, both must be integers and no conversion is ' -- 'necessary.\n' -- '\n' -- 'Some additional rules apply for certain operators (e.g., a ' -- 'string as a\n' -- 'left argument to the ‘%’ operator). Extensions must define ' -- 'their own\n' -- 'conversion behavior.\n', -- 'customization': 'Basic customization\n' -- '*******************\n' -- '\n' -- 'object.__new__(cls[, ...])\n' -- '\n' -- ' Called to create a new instance of class *cls*. ' -- '"__new__()" is a\n' -- ' static method (special-cased so you need not declare it ' -- 'as such)\n' -- ' that takes the class of which an instance was requested ' -- 'as its\n' -- ' first argument. The remaining arguments are those ' -- 'passed to the\n' -- ' object constructor expression (the call to the class). ' -- 'The return\n' -- ' value of "__new__()" should be the new object instance ' -- '(usually an\n' -- ' instance of *cls*).\n' -- '\n' -- ' Typical implementations create a new instance of the ' -- 'class by\n' -- ' invoking the superclass’s "__new__()" method using\n' -- ' "super().__new__(cls[, ...])" with appropriate arguments ' -- 'and then\n' -- ' modifying the newly created instance as necessary before ' -- 'returning\n' -- ' it.\n' -- '\n' -- ' If "__new__()" is invoked during object construction and ' -- 'it returns\n' -- ' an instance of *cls*, then the new instance’s ' -- '"__init__()" method\n' -- ' will be invoked like "__init__(self[, ...])", where ' -- '*self* is the\n' -- ' new instance and the remaining arguments are the same as ' -- 'were\n' -- ' passed to the object constructor.\n' -- '\n' -- ' If "__new__()" does not return an instance of *cls*, ' -- 'then the new\n' -- ' instance’s "__init__()" method will not be invoked.\n' -- '\n' -- ' "__new__()" is intended mainly to allow subclasses of ' -- 'immutable\n' -- ' types (like int, str, or tuple) to customize instance ' -- 'creation. It\n' -- ' is also commonly overridden in custom metaclasses in ' -- 'order to\n' -- ' customize class creation.\n' -- '\n' -- 'object.__init__(self[, ...])\n' -- '\n' -- ' Called after the instance has been created (by ' -- '"__new__()"), but\n' -- ' before it is returned to the caller. The arguments are ' -- 'those\n' -- ' passed to the class constructor expression. If a base ' -- 'class has an\n' -- ' "__init__()" method, the derived class’s "__init__()" ' -- 'method, if\n' -- ' any, must explicitly call it to ensure proper ' -- 'initialization of the\n' -- ' base class part of the instance; for example:\n' -- ' "super().__init__([args...])".\n' -- '\n' -- ' Because "__new__()" and "__init__()" work together in ' -- 'constructing\n' -- ' objects ("__new__()" to create it, and "__init__()" to ' -- 'customize\n' -- ' it), no non-"None" value may be returned by ' -- '"__init__()"; doing so\n' -- ' will cause a "TypeError" to be raised at runtime.\n' -- '\n' -- 'object.__del__(self)\n' -- '\n' -- ' Called when the instance is about to be destroyed. This ' -- 'is also\n' -- ' called a finalizer or (improperly) a destructor. If a ' -- 'base class\n' -- ' has a "__del__()" method, the derived class’s ' -- '"__del__()" method,\n' -- ' if any, must explicitly call it to ensure proper ' -- 'deletion of the\n' -- ' base class part of the instance.\n' -- '\n' -- ' It is possible (though not recommended!) for the ' -- '"__del__()" method\n' -- ' to postpone destruction of the instance by creating a ' -- 'new reference\n' -- ' to it. This is called object *resurrection*. It is\n' -- ' implementation-dependent whether "__del__()" is called a ' -- 'second\n' -- ' time when a resurrected object is about to be destroyed; ' -- 'the\n' -- ' current *CPython* implementation only calls it once.\n' -- '\n' -- ' It is not guaranteed that "__del__()" methods are called ' -- 'for\n' -- ' objects that still exist when the interpreter exits.\n' -- ' "weakref.finalize" provides a straightforward way to ' -- 'register a\n' -- ' cleanup function to be called when an object is garbage ' -- 'collected.\n' -- '\n' -- ' Note:\n' -- '\n' -- ' "del x" doesn’t directly call "x.__del__()" — the ' -- 'former\n' -- ' decrements the reference count for "x" by one, and the ' -- 'latter is\n' -- ' only called when "x"’s reference count reaches zero.\n' -- '\n' -- ' **CPython implementation detail:** It is possible for a ' -- 'reference\n' -- ' cycle to prevent the reference count of an object from ' -- 'going to\n' -- ' zero. In this case, the cycle will be later detected ' -- 'and deleted\n' -- ' by the *cyclic garbage collector*. A common cause of ' -- 'reference\n' -- ' cycles is when an exception has been caught in a local ' -- 'variable.\n' -- ' The frame’s locals then reference the exception, which ' -- 'references\n' -- ' its own traceback, which references the locals of all ' -- 'frames caught\n' -- ' in the traceback.\n' -- '\n' -- ' See also: Documentation for the "gc" module.\n' -- '\n' -- ' Warning:\n' -- '\n' -- ' Due to the precarious circumstances under which ' -- '"__del__()"\n' -- ' methods are invoked, exceptions that occur during ' -- 'their execution\n' -- ' are ignored, and a warning is printed to "sys.stderr" ' -- 'instead.\n' -- ' In particular:\n' -- '\n' -- ' * "__del__()" can be invoked when arbitrary code is ' -- 'being\n' -- ' executed, including from any arbitrary thread. If ' -- '"__del__()"\n' -- ' needs to take a lock or invoke any other blocking ' -- 'resource, it\n' -- ' may deadlock as the resource may already be taken by ' -- 'the code\n' -- ' that gets interrupted to execute "__del__()".\n' -- '\n' -- ' * "__del__()" can be executed during interpreter ' -- 'shutdown. As a\n' -- ' consequence, the global variables it needs to access ' -- '(including\n' -- ' other modules) may already have been deleted or set ' -- 'to "None".\n' -- ' Python guarantees that globals whose name begins ' -- 'with a single\n' -- ' underscore are deleted from their module before ' -- 'other globals\n' -- ' are deleted; if no other references to such globals ' -- 'exist, this\n' -- ' may help in assuring that imported modules are still ' -- 'available\n' -- ' at the time when the "__del__()" method is called.\n' -- '\n' -- 'object.__repr__(self)\n' -- '\n' -- ' Called by the "repr()" built-in function to compute the ' -- '“officialâ€\n' -- ' string representation of an object. If at all possible, ' -- 'this\n' -- ' should look like a valid Python expression that could be ' -- 'used to\n' -- ' recreate an object with the same value (given an ' -- 'appropriate\n' -- ' environment). If this is not possible, a string of the ' -- 'form\n' -- ' "<...some useful description...>" should be returned. ' -- 'The return\n' -- ' value must be a string object. If a class defines ' -- '"__repr__()" but\n' -- ' not "__str__()", then "__repr__()" is also used when an ' -- '“informalâ€\n' -- ' string representation of instances of that class is ' -- 'required.\n' -- '\n' -- ' This is typically used for debugging, so it is important ' -- 'that the\n' -- ' representation is information-rich and unambiguous. A ' -- 'default\n' -- ' implementation is provided by the "object" class ' -- 'itself.\n' -- '\n' -- 'object.__str__(self)\n' -- '\n' -- ' Called by "str(object)", the default "__format__()" ' -- 'implementation,\n' -- ' and the built-in function "print()", to compute the ' -- '“informal†or\n' -- ' nicely printable string representation of an object. ' -- 'The return\n' -- ' value must be a str object.\n' -- '\n' -- ' This method differs from "object.__repr__()" in that ' -- 'there is no\n' -- ' expectation that "__str__()" return a valid Python ' -- 'expression: a\n' -- ' more convenient or concise representation can be used.\n' -- '\n' -- ' The default implementation defined by the built-in type ' -- '"object"\n' -- ' calls "object.__repr__()".\n' -- '\n' -- 'object.__bytes__(self)\n' -- '\n' -- ' Called by bytes to compute a byte-string representation ' -- 'of an\n' -- ' object. This should return a "bytes" object. The ' -- '"object" class\n' -- ' itself does not provide this method.\n' -- '\n' -- 'object.__format__(self, format_spec)\n' -- '\n' -- ' Called by the "format()" built-in function, and by ' -- 'extension,\n' -- ' evaluation of formatted string literals and the ' -- '"str.format()"\n' -- ' method, to produce a “formatted†string representation ' -- 'of an\n' -- ' object. The *format_spec* argument is a string that ' -- 'contains a\n' -- ' description of the formatting options desired. The ' -- 'interpretation\n' -- ' of the *format_spec* argument is up to the type ' -- 'implementing\n' -- ' "__format__()", however most classes will either ' -- 'delegate\n' -- ' formatting to one of the built-in types, or use a ' -- 'similar\n' -- ' formatting option syntax.\n' -- '\n' -- ' See Format Specification Mini-Language for a description ' -- 'of the\n' -- ' standard formatting syntax.\n' -- '\n' -- ' The return value must be a string object.\n' -- '\n' -- ' The default implementation by the "object" class should ' -- 'be given an\n' -- ' empty *format_spec* string. It delegates to ' -- '"__str__()".\n' -- '\n' -- ' Changed in version 3.4: The __format__ method of ' -- '"object" itself\n' -- ' raises a "TypeError" if passed any non-empty string.\n' -- '\n' -- ' Changed in version 3.7: "object.__format__(x, \'\')" is ' -- 'now\n' -- ' equivalent to "str(x)" rather than "format(str(x), ' -- '\'\')".\n' -- '\n' -- 'object.__lt__(self, other)\n' -- 'object.__le__(self, other)\n' -- 'object.__eq__(self, other)\n' -- 'object.__ne__(self, other)\n' -- 'object.__gt__(self, other)\n' -- 'object.__ge__(self, other)\n' -- '\n' -- ' These are the so-called “rich comparison†methods. The\n' -- ' correspondence between operator symbols and method names ' -- 'is as\n' -- ' follows: "xy" calls\n' -- ' "x.__gt__(y)", and "x>=y" calls "x.__ge__(y)".\n' -- '\n' -- ' A rich comparison method may return the singleton ' -- '"NotImplemented"\n' -- ' if it does not implement the operation for a given pair ' -- 'of\n' -- ' arguments. By convention, "False" and "True" are ' -- 'returned for a\n' -- ' successful comparison. However, these methods can return ' -- 'any value,\n' -- ' so if the comparison operator is used in a Boolean ' -- 'context (e.g.,\n' -- ' in the condition of an "if" statement), Python will call ' -- '"bool()"\n' -- ' on the value to determine if the result is true or ' -- 'false.\n' -- '\n' -- ' By default, "object" implements "__eq__()" by using ' -- '"is", returning\n' -- ' "NotImplemented" in the case of a false comparison: ' -- '"True if x is y\n' -- ' else NotImplemented". For "__ne__()", by default it ' -- 'delegates to\n' -- ' "__eq__()" and inverts the result unless it is ' -- '"NotImplemented".\n' -- ' There are no other implied relationships among the ' -- 'comparison\n' -- ' operators or default implementations; for example, the ' -- 'truth of\n' -- ' "(x.__hash__".\n' -- '\n' -- ' If a class that does not override "__eq__()" wishes to ' -- 'suppress\n' -- ' hash support, it should include "__hash__ = None" in the ' -- 'class\n' -- ' definition. A class which defines its own "__hash__()" ' -- 'that\n' -- ' explicitly raises a "TypeError" would be incorrectly ' -- 'identified as\n' -- ' hashable by an "isinstance(obj, ' -- 'collections.abc.Hashable)" call.\n' -- '\n' -- ' Note:\n' -- '\n' -- ' By default, the "__hash__()" values of str and bytes ' -- 'objects are\n' -- ' “salted†with an unpredictable random value. Although ' -- 'they\n' -- ' remain constant within an individual Python process, ' -- 'they are not\n' -- ' predictable between repeated invocations of ' -- 'Python.This is\n' -- ' intended to provide protection against a ' -- 'denial-of-service caused\n' -- ' by carefully chosen inputs that exploit the worst ' -- 'case\n' -- ' performance of a dict insertion, *O*(*n*^2) ' -- 'complexity. See\n' -- ' http://ocert.org/advisories/ocert-2011-003.html for\n' -- ' details.Changing hash values affects the iteration ' -- 'order of sets.\n' -- ' Python has never made guarantees about this ordering ' -- '(and it\n' -- ' typically varies between 32-bit and 64-bit builds).See ' -- 'also\n' -- ' "PYTHONHASHSEED".\n' -- '\n' -- ' Changed in version 3.3: Hash randomization is enabled by ' -- 'default.\n' -- '\n' -- 'object.__bool__(self)\n' -- '\n' -- ' Called to implement truth value testing and the built-in ' -- 'operation\n' -- ' "bool()"; should return "False" or "True". When this ' -- 'method is not\n' -- ' defined, "__len__()" is called, if it is defined, and ' -- 'the object is\n' -- ' considered true if its result is nonzero. If a class ' -- 'defines\n' -- ' neither "__len__()" nor "__bool__()" (which is true of ' -- 'the "object"\n' -- ' class itself), all its instances are considered true.\n', -- 'debugger': '"pdb" — The Python Debugger\n' -- '***************************\n' -- '\n' -- '**Source code:** Lib/pdb.py\n' -- '\n' -- '======================================================================\n' -- '\n' -- 'The module "pdb" defines an interactive source code debugger ' -- 'for\n' -- 'Python programs. It supports setting (conditional) breakpoints ' -- 'and\n' -- 'single stepping at the source line level, inspection of stack ' -- 'frames,\n' -- 'source code listing, and evaluation of arbitrary Python code in ' -- 'the\n' -- 'context of any stack frame. It also supports post-mortem ' -- 'debugging\n' -- 'and can be called under program control.\n' -- '\n' -- 'The debugger is extensible – it is actually defined as the ' -- 'class\n' -- '"Pdb". This is currently undocumented but easily understood by ' -- 'reading\n' -- 'the source. The extension interface uses the modules "bdb" and ' -- '"cmd".\n' -- '\n' -- 'See also:\n' -- '\n' -- ' Module "faulthandler"\n' -- ' Used to dump Python tracebacks explicitly, on a fault, ' -- 'after a\n' -- ' timeout, or on a user signal.\n' -- '\n' -- ' Module "traceback"\n' -- ' Standard interface to extract, format and print stack ' -- 'traces of\n' -- ' Python programs.\n' -- '\n' -- 'The typical usage to break into the debugger is to insert:\n' -- '\n' -- ' import pdb; pdb.set_trace()\n' -- '\n' -- 'Or:\n' -- '\n' -- ' breakpoint()\n' -- '\n' -- 'at the location you want to break into the debugger, and then ' -- 'run the\n' -- 'program. You can then step through the code following this ' -- 'statement,\n' -- 'and continue running without the debugger using the "continue"\n' -- 'command.\n' -- '\n' -- 'Changed in version 3.7: The built-in "breakpoint()", when called ' -- 'with\n' -- 'defaults, can be used instead of "import pdb; pdb.set_trace()".\n' -- '\n' -- ' def double(x):\n' -- ' breakpoint()\n' -- ' return x * 2\n' -- ' val = 3\n' -- ' print(f"{val} * 2 is {double(val)}")\n' -- '\n' -- 'The debugger’s prompt is "(Pdb)", which is the indicator that ' -- 'you are\n' -- 'in debug mode:\n' -- '\n' -- ' > ...(2)double()\n' -- ' -> breakpoint()\n' -- ' (Pdb) p x\n' -- ' 3\n' -- ' (Pdb) continue\n' -- ' 3 * 2 is 6\n' -- '\n' -- 'Changed in version 3.3: Tab-completion via the "readline" module ' -- 'is\n' -- 'available for commands and command arguments, e.g. the current ' -- 'global\n' -- 'and local names are offered as arguments of the "p" command.\n' -- '\n' -- 'You can also invoke "pdb" from the command line to debug other\n' -- 'scripts. For example:\n' -- '\n' -- ' python -m pdb myscript.py\n' -- '\n' -- 'When invoked as a module, pdb will automatically enter ' -- 'post-mortem\n' -- 'debugging if the program being debugged exits abnormally. After ' -- 'post-\n' -- 'mortem debugging (or after normal exit of the program), pdb ' -- 'will\n' -- 'restart the program. Automatic restarting preserves pdb’s state ' -- '(such\n' -- 'as breakpoints) and in most cases is more useful than quitting ' -- 'the\n' -- 'debugger upon program’s exit.\n' -- '\n' -- 'Changed in version 3.2: Added the "-c" option to execute ' -- 'commands as\n' -- 'if given in a ".pdbrc" file; see Debugger Commands.\n' -- '\n' -- 'Changed in version 3.7: Added the "-m" option to execute ' -- 'modules\n' -- 'similar to the way "python -m" does. As with a script, the ' -- 'debugger\n' -- 'will pause execution just before the first line of the module.\n' -- '\n' -- 'Typical usage to execute a statement under control of the ' -- 'debugger is:\n' -- '\n' -- ' >>> import pdb\n' -- ' >>> def f(x):\n' -- ' ... print(1 / x)\n' -- ' >>> pdb.run("f(2)")\n' -- ' > (1)()\n' -- ' (Pdb) continue\n' -- ' 0.5\n' -- ' >>>\n' -- '\n' -- 'The typical usage to inspect a crashed program is:\n' -- '\n' -- ' >>> import pdb\n' -- ' >>> def f(x):\n' -- ' ... print(1 / x)\n' -- ' ...\n' -- ' >>> f(0)\n' -- ' Traceback (most recent call last):\n' -- ' File "", line 1, in \n' -- ' File "", line 2, in f\n' -- ' ZeroDivisionError: division by zero\n' -- ' >>> pdb.pm()\n' -- ' > (2)f()\n' -- ' (Pdb) p x\n' -- ' 0\n' -- ' (Pdb)\n' -- '\n' -- 'Changed in version 3.13: The implementation of **PEP 667** means ' -- 'that\n' -- 'name assignments made via "pdb" will immediately affect the ' -- 'active\n' -- 'scope, even when running inside an *optimized scope*.\n' -- '\n' -- 'The module defines the following functions; each enters the ' -- 'debugger\n' -- 'in a slightly different way:\n' -- '\n' -- 'pdb.run(statement, globals=None, locals=None)\n' -- '\n' -- ' Execute the *statement* (given as a string or a code object) ' -- 'under\n' -- ' debugger control. The debugger prompt appears before any ' -- 'code is\n' -- ' executed; you can set breakpoints and type "continue", or you ' -- 'can\n' -- ' step through the statement using "step" or "next" (all these\n' -- ' commands are explained below). The optional *globals* and ' -- '*locals*\n' -- ' arguments specify the environment in which the code is ' -- 'executed; by\n' -- ' default the dictionary of the module "__main__" is used. ' -- '(See the\n' -- ' explanation of the built-in "exec()" or "eval()" functions.)\n' -- '\n' -- 'pdb.runeval(expression, globals=None, locals=None)\n' -- '\n' -- ' Evaluate the *expression* (given as a string or a code ' -- 'object)\n' -- ' under debugger control. When "runeval()" returns, it returns ' -- 'the\n' -- ' value of the *expression*. Otherwise this function is ' -- 'similar to\n' -- ' "run()".\n' -- '\n' -- 'pdb.runcall(function, *args, **kwds)\n' -- '\n' -- ' Call the *function* (a function or method object, not a ' -- 'string)\n' -- ' with the given arguments. When "runcall()" returns, it ' -- 'returns\n' -- ' whatever the function call returned. The debugger prompt ' -- 'appears\n' -- ' as soon as the function is entered.\n' -- '\n' -- 'pdb.set_trace(*, header=None, commands=None)\n' -- '\n' -- ' Enter the debugger at the calling stack frame. This is ' -- 'useful to\n' -- ' hard-code a breakpoint at a given point in a program, even if ' -- 'the\n' -- ' code is not otherwise being debugged (e.g. when an assertion\n' -- ' fails). If given, *header* is printed to the console just ' -- 'before\n' -- ' debugging begins. The *commands* argument, if given, is a ' -- 'list of\n' -- ' commands to execute when the debugger starts.\n' -- '\n' -- ' Changed in version 3.7: The keyword-only argument *header*.\n' -- '\n' -- ' Changed in version 3.13: "set_trace()" will enter the ' -- 'debugger\n' -- ' immediately, rather than on the next line of code to be ' -- 'executed.\n' -- '\n' -- ' Added in version 3.14: The *commands* argument.\n' -- '\n' -- 'pdb.post_mortem(traceback=None)\n' -- '\n' -- ' Enter post-mortem debugging of the given *traceback* object. ' -- 'If no\n' -- ' *traceback* is given, it uses the one of the exception that ' -- 'is\n' -- ' currently being handled (an exception must be being handled ' -- 'if the\n' -- ' default is to be used).\n' -- '\n' -- 'pdb.pm()\n' -- '\n' -- ' Enter post-mortem debugging of the exception found in\n' -- ' "sys.last_exc".\n' -- '\n' -- 'The "run*" functions and "set_trace()" are aliases for ' -- 'instantiating\n' -- 'the "Pdb" class and calling the method of the same name. If you ' -- 'want\n' -- 'to access further features, you have to do this yourself:\n' -- '\n' -- "class pdb.Pdb(completekey='tab', stdin=None, stdout=None, " -- 'skip=None, nosigint=False, readrc=True, mode=None)\n' -- '\n' -- ' "Pdb" is the debugger class.\n' -- '\n' -- ' The *completekey*, *stdin* and *stdout* arguments are passed ' -- 'to the\n' -- ' underlying "cmd.Cmd" class; see the description there.\n' -- '\n' -- ' The *skip* argument, if given, must be an iterable of ' -- 'glob-style\n' -- ' module name patterns. The debugger will not step into frames ' -- 'that\n' -- ' originate in a module that matches one of these patterns. ' -- '[1]\n' -- '\n' -- ' By default, Pdb sets a handler for the SIGINT signal (which ' -- 'is sent\n' -- ' when the user presses "Ctrl-C" on the console) when you give ' -- 'a\n' -- ' "continue" command. This allows you to break into the ' -- 'debugger\n' -- ' again by pressing "Ctrl-C". If you want Pdb not to touch ' -- 'the\n' -- ' SIGINT handler, set *nosigint* to true.\n' -- '\n' -- ' The *readrc* argument defaults to true and controls whether ' -- 'Pdb\n' -- ' will load .pdbrc files from the filesystem.\n' -- '\n' -- ' The *mode* argument specifies how the debugger was invoked. ' -- 'It\n' -- ' impacts the workings of some debugger commands. Valid values ' -- 'are\n' -- ' "\'inline\'" (used by the breakpoint() builtin), "\'cli\'" ' -- '(used by the\n' -- ' command line invocation) or "None" (for backwards compatible\n' -- ' behaviour, as before the *mode* argument was added).\n' -- '\n' -- ' Example call to enable tracing with *skip*:\n' -- '\n' -- " import pdb; pdb.Pdb(skip=['django.*']).set_trace()\n" -- '\n' -- ' Raises an auditing event "pdb.Pdb" with no arguments.\n' -- '\n' -- ' Changed in version 3.1: Added the *skip* parameter.\n' -- '\n' -- ' Changed in version 3.2: Added the *nosigint* parameter. ' -- 'Previously,\n' -- ' a SIGINT handler was never set by Pdb.\n' -- '\n' -- ' Changed in version 3.6: The *readrc* argument.\n' -- '\n' -- ' Added in version 3.14: Added the *mode* argument.\n' -- '\n' -- ' run(statement, globals=None, locals=None)\n' -- ' runeval(expression, globals=None, locals=None)\n' -- ' runcall(function, *args, **kwds)\n' -- ' set_trace()\n' -- '\n' -- ' See the documentation for the functions explained above.\n' -- '\n' -- '\n' -- 'Debugger Commands\n' -- '=================\n' -- '\n' -- 'The commands recognized by the debugger are listed below. Most\n' -- 'commands can be abbreviated to one or two letters as indicated; ' -- 'e.g.\n' -- '"h(elp)" means that either "h" or "help" can be used to enter ' -- 'the help\n' -- 'command (but not "he" or "hel", nor "H" or "Help" or "HELP").\n' -- 'Arguments to commands must be separated by whitespace (spaces ' -- 'or\n' -- 'tabs). Optional arguments are enclosed in square brackets ' -- '("[]") in\n' -- 'the command syntax; the square brackets must not be typed.\n' -- 'Alternatives in the command syntax are separated by a vertical ' -- 'bar\n' -- '("|").\n' -- '\n' -- 'Entering a blank line repeats the last command entered. ' -- 'Exception: if\n' -- 'the last command was a "list" command, the next 11 lines are ' -- 'listed.\n' -- '\n' -- 'Commands that the debugger doesn’t recognize are assumed to be ' -- 'Python\n' -- 'statements and are executed in the context of the program being\n' -- 'debugged. Python statements can also be prefixed with an ' -- 'exclamation\n' -- 'point ("!"). This is a powerful way to inspect the program ' -- 'being\n' -- 'debugged; it is even possible to change a variable or call a ' -- 'function.\n' -- 'When an exception occurs in such a statement, the exception name ' -- 'is\n' -- 'printed but the debugger’s state is not changed.\n' -- '\n' -- 'Changed in version 3.13: Expressions/Statements whose prefix is ' -- 'a pdb\n' -- 'command are now correctly identified and executed.\n' -- '\n' -- 'The debugger supports aliases. Aliases can have parameters ' -- 'which\n' -- 'allows one a certain level of adaptability to the context under\n' -- 'examination.\n' -- '\n' -- 'Multiple commands may be entered on a single line, separated by ' -- '";;".\n' -- '(A single ";" is not used as it is the separator for multiple ' -- 'commands\n' -- 'in a line that is passed to the Python parser.) No intelligence ' -- 'is\n' -- 'applied to separating the commands; the input is split at the ' -- 'first\n' -- '";;" pair, even if it is in the middle of a quoted string. A\n' -- 'workaround for strings with double semicolons is to use ' -- 'implicit\n' -- 'string concatenation "\';\'\';\'" or "";"";"".\n' -- '\n' -- 'To set a temporary global variable, use a *convenience ' -- 'variable*. A\n' -- '*convenience variable* is a variable whose name starts with ' -- '"$". For\n' -- 'example, "$foo = 1" sets a global variable "$foo" which you can ' -- 'use in\n' -- 'the debugger session. The *convenience variables* are cleared ' -- 'when\n' -- 'the program resumes execution so it’s less likely to interfere ' -- 'with\n' -- 'your program compared to using normal variables like "foo = 1".\n' -- '\n' -- 'There are three preset *convenience variables*:\n' -- '\n' -- '* "$_frame": the current frame you are debugging\n' -- '\n' -- '* "$_retval": the return value if the frame is returning\n' -- '\n' -- '* "$_exception": the exception if the frame is raising an ' -- 'exception\n' -- '\n' -- 'Added in version 3.12: Added the *convenience variable* ' -- 'feature.\n' -- '\n' -- 'If a file ".pdbrc" exists in the user’s home directory or in ' -- 'the\n' -- 'current directory, it is read with "\'utf-8\'" encoding and ' -- 'executed as\n' -- 'if it had been typed at the debugger prompt, with the exception ' -- 'that\n' -- 'empty lines and lines starting with "#" are ignored. This is\n' -- 'particularly useful for aliases. If both files exist, the one ' -- 'in the\n' -- 'home directory is read first and aliases defined there can be\n' -- 'overridden by the local file.\n' -- '\n' -- 'Changed in version 3.2: ".pdbrc" can now contain commands that\n' -- 'continue debugging, such as "continue" or "next". Previously, ' -- 'these\n' -- 'commands had no effect.\n' -- '\n' -- 'Changed in version 3.11: ".pdbrc" is now read with "\'utf-8\'" ' -- 'encoding.\n' -- 'Previously, it was read with the system locale encoding.\n' -- '\n' -- 'h(elp) [command]\n' -- '\n' -- ' Without argument, print the list of available commands. With ' -- 'a\n' -- ' *command* as argument, print help about that command. "help ' -- 'pdb"\n' -- ' displays the full documentation (the docstring of the "pdb"\n' -- ' module). Since the *command* argument must be an identifier, ' -- '"help\n' -- ' exec" must be entered to get help on the "!" command.\n' -- '\n' -- 'w(here) [count]\n' -- '\n' -- ' Print a stack trace, with the most recent frame at the ' -- 'bottom. if\n' -- ' *count* is 0, print the current frame entry. If *count* is\n' -- ' negative, print the least recent - *count* frames. If *count* ' -- 'is\n' -- ' positive, print the most recent *count* frames. An arrow ' -- '(">")\n' -- ' indicates the current frame, which determines the context of ' -- 'most\n' -- ' commands.\n' -- '\n' -- ' Changed in version 3.14: *count* argument is added.\n' -- '\n' -- 'd(own) [count]\n' -- '\n' -- ' Move the current frame *count* (default one) levels down in ' -- 'the\n' -- ' stack trace (to a newer frame).\n' -- '\n' -- 'u(p) [count]\n' -- '\n' -- ' Move the current frame *count* (default one) levels up in the ' -- 'stack\n' -- ' trace (to an older frame).\n' -- '\n' -- 'b(reak) [([filename:]lineno | function) [, condition]]\n' -- '\n' -- ' With a *lineno* argument, set a break at line *lineno* in ' -- 'the\n' -- ' current file. The line number may be prefixed with a ' -- '*filename* and\n' -- ' a colon, to specify a breakpoint in another file (possibly ' -- 'one that\n' -- ' hasn’t been loaded yet). The file is searched on ' -- '"sys.path".\n' -- ' Acceptable forms of *filename* are "/abspath/to/file.py",\n' -- ' "relpath/file.py", "module" and "package.module".\n' -- '\n' -- ' With a *function* argument, set a break at the first ' -- 'executable\n' -- ' statement within that function. *function* can be any ' -- 'expression\n' -- ' that evaluates to a function in the current namespace.\n' -- '\n' -- ' If a second argument is present, it is an expression which ' -- 'must\n' -- ' evaluate to true before the breakpoint is honored.\n' -- '\n' -- ' Without argument, list all breaks, including for each ' -- 'breakpoint,\n' -- ' the number of times that breakpoint has been hit, the ' -- 'current\n' -- ' ignore count, and the associated condition if any.\n' -- '\n' -- ' Each breakpoint is assigned a number to which all the other\n' -- ' breakpoint commands refer.\n' -- '\n' -- 'tbreak [([filename:]lineno | function) [, condition]]\n' -- '\n' -- ' Temporary breakpoint, which is removed automatically when it ' -- 'is\n' -- ' first hit. The arguments are the same as for "break".\n' -- '\n' -- 'cl(ear) [filename:lineno | bpnumber ...]\n' -- '\n' -- ' With a *filename:lineno* argument, clear all the breakpoints ' -- 'at\n' -- ' this line. With a space separated list of breakpoint numbers, ' -- 'clear\n' -- ' those breakpoints. Without argument, clear all breaks (but ' -- 'first\n' -- ' ask confirmation).\n' -- '\n' -- 'disable bpnumber [bpnumber ...]\n' -- '\n' -- ' Disable the breakpoints given as a space separated list of\n' -- ' breakpoint numbers. Disabling a breakpoint means it cannot ' -- 'cause\n' -- ' the program to stop execution, but unlike clearing a ' -- 'breakpoint, it\n' -- ' remains in the list of breakpoints and can be (re-)enabled.\n' -- '\n' -- 'enable bpnumber [bpnumber ...]\n' -- '\n' -- ' Enable the breakpoints specified.\n' -- '\n' -- 'ignore bpnumber [count]\n' -- '\n' -- ' Set the ignore count for the given breakpoint number. If ' -- '*count*\n' -- ' is omitted, the ignore count is set to 0. A breakpoint ' -- 'becomes\n' -- ' active when the ignore count is zero. When non-zero, the ' -- '*count*\n' -- ' is decremented each time the breakpoint is reached and the\n' -- ' breakpoint is not disabled and any associated condition ' -- 'evaluates\n' -- ' to true.\n' -- '\n' -- 'condition bpnumber [condition]\n' -- '\n' -- ' Set a new *condition* for the breakpoint, an expression which ' -- 'must\n' -- ' evaluate to true before the breakpoint is honored. If ' -- '*condition*\n' -- ' is absent, any existing condition is removed; i.e., the ' -- 'breakpoint\n' -- ' is made unconditional.\n' -- '\n' -- 'commands [bpnumber]\n' -- '\n' -- ' Specify a list of commands for breakpoint number *bpnumber*. ' -- 'The\n' -- ' commands themselves appear on the following lines. Type a ' -- 'line\n' -- ' containing just "end" to terminate the commands. An example:\n' -- '\n' -- ' (Pdb) commands 1\n' -- ' (com) p some_variable\n' -- ' (com) end\n' -- ' (Pdb)\n' -- '\n' -- ' To remove all commands from a breakpoint, type "commands" ' -- 'and\n' -- ' follow it immediately with "end"; that is, give no commands.\n' -- '\n' -- ' With no *bpnumber* argument, "commands" refers to the last\n' -- ' breakpoint set.\n' -- '\n' -- ' You can use breakpoint commands to start your program up ' -- 'again.\n' -- ' Simply use the "continue" command, or "step", or any other ' -- 'command\n' -- ' that resumes execution.\n' -- '\n' -- ' Specifying any command resuming execution (currently ' -- '"continue",\n' -- ' "step", "next", "return", "until", "jump", "quit" and their\n' -- ' abbreviations) terminates the command list (as if that ' -- 'command was\n' -- ' immediately followed by end). This is because any time you ' -- 'resume\n' -- ' execution (even with a simple next or step), you may ' -- 'encounter\n' -- ' another breakpoint—which could have its own command list, ' -- 'leading\n' -- ' to ambiguities about which list to execute.\n' -- '\n' -- ' If the list of commands contains the "silent" command, or a ' -- 'command\n' -- ' that resumes execution, then the breakpoint message ' -- 'containing\n' -- ' information about the frame is not displayed.\n' -- '\n' -- ' Changed in version 3.14: Frame information will not be ' -- 'displayed if\n' -- ' a command that resumes execution is present in the command ' -- 'list.\n' -- '\n' -- 's(tep)\n' -- '\n' -- ' Execute the current line, stop at the first possible ' -- 'occasion\n' -- ' (either in a function that is called or on the next line in ' -- 'the\n' -- ' current function).\n' -- '\n' -- 'n(ext)\n' -- '\n' -- ' Continue execution until the next line in the current ' -- 'function is\n' -- ' reached or it returns. (The difference between "next" and ' -- '"step"\n' -- ' is that "step" stops inside a called function, while "next"\n' -- ' executes called functions at (nearly) full speed, only ' -- 'stopping at\n' -- ' the next line in the current function.)\n' -- '\n' -- 'unt(il) [lineno]\n' -- '\n' -- ' Without argument, continue execution until the line with a ' -- 'number\n' -- ' greater than the current one is reached.\n' -- '\n' -- ' With *lineno*, continue execution until a line with a number\n' -- ' greater or equal to *lineno* is reached. In both cases, also ' -- 'stop\n' -- ' when the current frame returns.\n' -- '\n' -- ' Changed in version 3.2: Allow giving an explicit line ' -- 'number.\n' -- '\n' -- 'r(eturn)\n' -- '\n' -- ' Continue execution until the current function returns.\n' -- '\n' -- 'c(ont(inue))\n' -- '\n' -- ' Continue execution, only stop when a breakpoint is ' -- 'encountered.\n' -- '\n' -- 'j(ump) lineno\n' -- '\n' -- ' Set the next line that will be executed. Only available in ' -- 'the\n' -- ' bottom-most frame. This lets you jump back and execute code ' -- 'again,\n' -- ' or jump forward to skip code that you don’t want to run.\n' -- '\n' -- ' It should be noted that not all jumps are allowed – for ' -- 'instance it\n' -- ' is not possible to jump into the middle of a "for" loop or ' -- 'out of a\n' -- ' "finally" clause.\n' -- '\n' -- 'l(ist) [first[, last]]\n' -- '\n' -- ' List source code for the current file. Without arguments, ' -- 'list 11\n' -- ' lines around the current line or continue the previous ' -- 'listing.\n' -- ' With "." as argument, list 11 lines around the current line. ' -- 'With\n' -- ' one argument, list 11 lines around at that line. With two\n' -- ' arguments, list the given range; if the second argument is ' -- 'less\n' -- ' than the first, it is interpreted as a count.\n' -- '\n' -- ' The current line in the current frame is indicated by "->". ' -- 'If an\n' -- ' exception is being debugged, the line where the exception ' -- 'was\n' -- ' originally raised or propagated is indicated by ">>", if it ' -- 'differs\n' -- ' from the current line.\n' -- '\n' -- ' Changed in version 3.2: Added the ">>" marker.\n' -- '\n' -- 'll | longlist\n' -- '\n' -- ' List all source code for the current function or frame.\n' -- ' Interesting lines are marked as for "list".\n' -- '\n' -- ' Added in version 3.2.\n' -- '\n' -- 'a(rgs)\n' -- '\n' -- ' Print the arguments of the current function and their ' -- 'current\n' -- ' values.\n' -- '\n' -- 'p expression\n' -- '\n' -- ' Evaluate *expression* in the current context and print its ' -- 'value.\n' -- '\n' -- ' Note:\n' -- '\n' -- ' "print()" can also be used, but is not a debugger command — ' -- 'this\n' -- ' executes the Python "print()" function.\n' -- '\n' -- 'pp expression\n' -- '\n' -- ' Like the "p" command, except the value of *expression* is ' -- 'pretty-\n' -- ' printed using the "pprint" module.\n' -- '\n' -- 'whatis expression\n' -- '\n' -- ' Print the type of *expression*.\n' -- '\n' -- 'source expression\n' -- '\n' -- ' Try to get source code of *expression* and display it.\n' -- '\n' -- ' Added in version 3.2.\n' -- '\n' -- 'display [expression]\n' -- '\n' -- ' Display the value of *expression* if it changed, each time\n' -- ' execution stops in the current frame.\n' -- '\n' -- ' Without *expression*, list all display expressions for the ' -- 'current\n' -- ' frame.\n' -- '\n' -- ' Note:\n' -- '\n' -- ' Display evaluates *expression* and compares to the result ' -- 'of the\n' -- ' previous evaluation of *expression*, so when the result is\n' -- ' mutable, display may not be able to pick up the changes.\n' -- '\n' -- ' Example:\n' -- '\n' -- ' lst = []\n' -- ' breakpoint()\n' -- ' pass\n' -- ' lst.append(1)\n' -- ' print(lst)\n' -- '\n' -- ' Display won’t realize "lst" has been changed because the ' -- 'result of\n' -- ' evaluation is modified in place by "lst.append(1)" before ' -- 'being\n' -- ' compared:\n' -- '\n' -- ' > example.py(3)()\n' -- ' -> pass\n' -- ' (Pdb) display lst\n' -- ' display lst: []\n' -- ' (Pdb) n\n' -- ' > example.py(4)()\n' -- ' -> lst.append(1)\n' -- ' (Pdb) n\n' -- ' > example.py(5)()\n' -- ' -> print(lst)\n' -- ' (Pdb)\n' -- '\n' -- ' You can do some tricks with copy mechanism to make it work:\n' -- '\n' -- ' > example.py(3)()\n' -- ' -> pass\n' -- ' (Pdb) display lst[:]\n' -- ' display lst[:]: []\n' -- ' (Pdb) n\n' -- ' > example.py(4)()\n' -- ' -> lst.append(1)\n' -- ' (Pdb) n\n' -- ' > example.py(5)()\n' -- ' -> print(lst)\n' -- ' display lst[:]: [1] [old: []]\n' -- ' (Pdb)\n' -- '\n' -- ' Added in version 3.2.\n' -- '\n' -- 'undisplay [expression]\n' -- '\n' -- ' Do not display *expression* anymore in the current frame. ' -- 'Without\n' -- ' *expression*, clear all display expressions for the current ' -- 'frame.\n' -- '\n' -- ' Added in version 3.2.\n' -- '\n' -- 'interact\n' -- '\n' -- ' Start an interactive interpreter (using the "code" module) in ' -- 'a new\n' -- ' global namespace initialised from the local and global ' -- 'namespaces\n' -- ' for the current scope. Use "exit()" or "quit()" to exit the\n' -- ' interpreter and return to the debugger.\n' -- '\n' -- ' Note:\n' -- '\n' -- ' As "interact" creates a new dedicated namespace for code\n' -- ' execution, assignments to variables will not affect the ' -- 'original\n' -- ' namespaces. However, modifications to any referenced ' -- 'mutable\n' -- ' objects will be reflected in the original namespaces as ' -- 'usual.\n' -- '\n' -- ' Added in version 3.2.\n' -- '\n' -- ' Changed in version 3.13: "exit()" and "quit()" can be used to ' -- 'exit\n' -- ' the "interact" command.\n' -- '\n' -- ' Changed in version 3.13: "interact" directs its output to ' -- 'the\n' -- ' debugger’s output channel rather than "sys.stderr".\n' -- '\n' -- 'alias [name [command]]\n' -- '\n' -- ' Create an alias called *name* that executes *command*. The\n' -- ' *command* must *not* be enclosed in quotes. Replaceable ' -- 'parameters\n' -- ' can be indicated by "%1", "%2", … and "%9", while "%*" is ' -- 'replaced\n' -- ' by all the parameters. If *command* is omitted, the current ' -- 'alias\n' -- ' for *name* is shown. If no arguments are given, all aliases ' -- 'are\n' -- ' listed.\n' -- '\n' -- ' Aliases may be nested and can contain anything that can be ' -- 'legally\n' -- ' typed at the pdb prompt. Note that internal pdb commands ' -- '*can* be\n' -- ' overridden by aliases. Such a command is then hidden until ' -- 'the\n' -- ' alias is removed. Aliasing is recursively applied to the ' -- 'first\n' -- ' word of the command line; all other words in the line are ' -- 'left\n' -- ' alone.\n' -- '\n' -- ' As an example, here are two useful aliases (especially when ' -- 'placed\n' -- ' in the ".pdbrc" file):\n' -- '\n' -- ' # Print instance variables (usage "pi classInst")\n' -- ' alias pi for k in %1.__dict__.keys(): print(f"%1.{k} = ' -- '{%1.__dict__[k]}")\n' -- ' # Print instance variables in self\n' -- ' alias ps pi self\n' -- '\n' -- 'unalias name\n' -- '\n' -- ' Delete the specified alias *name*.\n' -- '\n' -- '! statement\n' -- '\n' -- ' Execute the (one-line) *statement* in the context of the ' -- 'current\n' -- ' stack frame. The exclamation point can be omitted unless the ' -- 'first\n' -- ' word of the statement resembles a debugger command, e.g.:\n' -- '\n' -- ' (Pdb) ! n=42\n' -- ' (Pdb)\n' -- '\n' -- ' To set a global variable, you can prefix the assignment ' -- 'command\n' -- ' with a "global" statement on the same line, e.g.:\n' -- '\n' -- " (Pdb) global list_options; list_options = ['-l']\n" -- ' (Pdb)\n' -- '\n' -- 'run [args ...]\n' -- 'restart [args ...]\n' -- '\n' -- ' Restart the debugged Python program. If *args* is supplied, ' -- 'it is\n' -- ' split with "shlex" and the result is used as the new ' -- '"sys.argv".\n' -- ' History, breakpoints, actions and debugger options are ' -- 'preserved.\n' -- ' "restart" is an alias for "run".\n' -- '\n' -- ' Changed in version 3.14: "run" and "restart" commands are ' -- 'disabled\n' -- ' when the debugger is invoked in "\'inline\'" mode.\n' -- '\n' -- 'q(uit)\n' -- '\n' -- ' Quit from the debugger. The program being executed is ' -- 'aborted.\n' -- '\n' -- 'debug code\n' -- '\n' -- ' Enter a recursive debugger that steps through *code* (which ' -- 'is an\n' -- ' arbitrary expression or statement to be executed in the ' -- 'current\n' -- ' environment).\n' -- '\n' -- 'retval\n' -- '\n' -- ' Print the return value for the last return of the current ' -- 'function.\n' -- '\n' -- 'exceptions [excnumber]\n' -- '\n' -- ' List or jump between chained exceptions.\n' -- '\n' -- ' When using "pdb.pm()" or "Pdb.post_mortem(...)" with a ' -- 'chained\n' -- ' exception instead of a traceback, it allows the user to move\n' -- ' between the chained exceptions using "exceptions" command to ' -- 'list\n' -- ' exceptions, and "exception " to switch to that ' -- 'exception.\n' -- '\n' -- ' Example:\n' -- '\n' -- ' def out():\n' -- ' try:\n' -- ' middle()\n' -- ' except Exception as e:\n' -- ' raise ValueError("reraise middle() error") from e\n' -- '\n' -- ' def middle():\n' -- ' try:\n' -- ' return inner(0)\n' -- ' except Exception as e:\n' -- ' raise ValueError("Middle fail")\n' -- '\n' -- ' def inner(x):\n' -- ' 1 / x\n' -- '\n' -- ' out()\n' -- '\n' -- ' calling "pdb.pm()" will allow to move between exceptions:\n' -- '\n' -- ' > example.py(5)out()\n' -- ' -> raise ValueError("reraise middle() error") from e\n' -- '\n' -- ' (Pdb) exceptions\n' -- " 0 ZeroDivisionError('division by zero')\n" -- " 1 ValueError('Middle fail')\n" -- " > 2 ValueError('reraise middle() error')\n" -- '\n' -- ' (Pdb) exceptions 0\n' -- ' > example.py(16)inner()\n' -- ' -> 1 / x\n' -- '\n' -- ' (Pdb) up\n' -- ' > example.py(10)middle()\n' -- ' -> return inner(0)\n' -- '\n' -- ' Added in version 3.13.\n' -- '\n' -- '-[ Footnotes ]-\n' -- '\n' -- '[1] Whether a frame is considered to originate in a certain ' -- 'module is\n' -- ' determined by the "__name__" in the frame globals.\n', -- 'del': 'The "del" statement\n' -- '*******************\n' -- '\n' -- ' del_stmt ::= "del" target_list\n' -- '\n' -- 'Deletion is recursively defined very similar to the way assignment ' -- 'is\n' -- 'defined. Rather than spelling it out in full details, here are some\n' -- 'hints.\n' -- '\n' -- 'Deletion of a target list recursively deletes each target, from left\n' -- 'to right.\n' -- '\n' -- 'Deletion of a name removes the binding of that name from the local ' -- 'or\n' -- 'global namespace, depending on whether the name occurs in a "global"\n' -- 'statement in the same code block. If the name is unbound, a\n' -- '"NameError" exception will be raised.\n' -- '\n' -- 'Deletion of attribute references, subscriptions and slicings is ' -- 'passed\n' -- 'to the primary object involved; deletion of a slicing is in general\n' -- 'equivalent to assignment of an empty slice of the right type (but ' -- 'even\n' -- 'this is determined by the sliced object).\n' -- '\n' -- 'Changed in version 3.2: Previously it was illegal to delete a name\n' -- 'from the local namespace if it occurs as a free variable in a nested\n' -- 'block.\n', -- 'dict': 'Dictionary displays\n' -- '*******************\n' -- '\n' -- 'A dictionary display is a possibly empty series of dict items\n' -- '(key/value pairs) enclosed in curly braces:\n' -- '\n' -- ' dict_display ::= "{" [dict_item_list | dict_comprehension] ' -- '"}"\n' -- ' dict_item_list ::= dict_item ("," dict_item)* [","]\n' -- ' dict_item ::= expression ":" expression | "**" or_expr\n' -- ' dict_comprehension ::= expression ":" expression comp_for\n' -- '\n' -- 'A dictionary display yields a new dictionary object.\n' -- '\n' -- 'If a comma-separated sequence of dict items is given, they are\n' -- 'evaluated from left to right to define the entries of the ' -- 'dictionary:\n' -- 'each key object is used as a key into the dictionary to store the\n' -- 'corresponding value. This means that you can specify the same key\n' -- 'multiple times in the dict item list, and the final dictionary’s ' -- 'value\n' -- 'for that key will be the last one given.\n' -- '\n' -- 'A double asterisk "**" denotes *dictionary unpacking*. Its operand\n' -- 'must be a *mapping*. Each mapping item is added to the new\n' -- 'dictionary. Later values replace values already set by earlier ' -- 'dict\n' -- 'items and earlier dictionary unpackings.\n' -- '\n' -- 'Added in version 3.5: Unpacking into dictionary displays, ' -- 'originally\n' -- 'proposed by **PEP 448**.\n' -- '\n' -- 'A dict comprehension, in contrast to list and set comprehensions,\n' -- 'needs two expressions separated with a colon followed by the usual\n' -- '“for†and “if†clauses. When the comprehension is run, the ' -- 'resulting\n' -- 'key and value elements are inserted in the new dictionary in the ' -- 'order\n' -- 'they are produced.\n' -- '\n' -- 'Restrictions on the types of the key values are listed earlier in\n' -- 'section The standard type hierarchy. (To summarize, the key type\n' -- 'should be *hashable*, which excludes all mutable objects.) Clashes\n' -- 'between duplicate keys are not detected; the last value (textually\n' -- 'rightmost in the display) stored for a given key value prevails.\n' -- '\n' -- 'Changed in version 3.8: Prior to Python 3.8, in dict ' -- 'comprehensions,\n' -- 'the evaluation order of key and value was not well-defined. In\n' -- 'CPython, the value was evaluated before the key. Starting with ' -- '3.8,\n' -- 'the key is evaluated before the value, as proposed by **PEP 572**.\n', -- 'dynamic-features': 'Interaction with dynamic features\n' -- '*********************************\n' -- '\n' -- 'Name resolution of free variables occurs at runtime, not ' -- 'at compile\n' -- 'time. This means that the following code will print 42:\n' -- '\n' -- ' i = 10\n' -- ' def f():\n' -- ' print(i)\n' -- ' i = 42\n' -- ' f()\n' -- '\n' -- 'The "eval()" and "exec()" functions do not have access ' -- 'to the full\n' -- 'environment for resolving names. Names may be resolved ' -- 'in the local\n' -- 'and global namespaces of the caller. Free variables are ' -- 'not resolved\n' -- 'in the nearest enclosing namespace, but in the global ' -- 'namespace. [1]\n' -- 'The "exec()" and "eval()" functions have optional ' -- 'arguments to\n' -- 'override the global and local namespace. If only one ' -- 'namespace is\n' -- 'specified, it is used for both.\n', -- 'else': 'The "if" statement\n' -- '******************\n' -- '\n' -- 'The "if" statement is used for conditional execution:\n' -- '\n' -- ' if_stmt ::= "if" assignment_expression ":" suite\n' -- ' ("elif" assignment_expression ":" suite)*\n' -- ' ["else" ":" suite]\n' -- '\n' -- 'It selects exactly one of the suites by evaluating the expressions ' -- 'one\n' -- 'by one until one is found to be true (see section Boolean ' -- 'operations\n' -- 'for the definition of true and false); then that suite is executed\n' -- '(and no other part of the "if" statement is executed or evaluated).\n' -- 'If all expressions are false, the suite of the "else" clause, if\n' -- 'present, is executed.\n', -- 'exceptions': 'Exceptions\n' -- '**********\n' -- '\n' -- 'Exceptions are a means of breaking out of the normal flow of ' -- 'control\n' -- 'of a code block in order to handle errors or other ' -- 'exceptional\n' -- 'conditions. An exception is *raised* at the point where the ' -- 'error is\n' -- 'detected; it may be *handled* by the surrounding code block or ' -- 'by any\n' -- 'code block that directly or indirectly invoked the code block ' -- 'where\n' -- 'the error occurred.\n' -- '\n' -- 'The Python interpreter raises an exception when it detects a ' -- 'run-time\n' -- 'error (such as division by zero). A Python program can also\n' -- 'explicitly raise an exception with the "raise" statement. ' -- 'Exception\n' -- 'handlers are specified with the "try" … "except" statement. ' -- 'The\n' -- '"finally" clause of such a statement can be used to specify ' -- 'cleanup\n' -- 'code which does not handle the exception, but is executed ' -- 'whether an\n' -- 'exception occurred or not in the preceding code.\n' -- '\n' -- 'Python uses the “termination†model of error handling: an ' -- 'exception\n' -- 'handler can find out what happened and continue execution at ' -- 'an outer\n' -- 'level, but it cannot repair the cause of the error and retry ' -- 'the\n' -- 'failing operation (except by re-entering the offending piece ' -- 'of code\n' -- 'from the top).\n' -- '\n' -- 'When an exception is not handled at all, the interpreter ' -- 'terminates\n' -- 'execution of the program, or returns to its interactive main ' -- 'loop. In\n' -- 'either case, it prints a stack traceback, except when the ' -- 'exception is\n' -- '"SystemExit".\n' -- '\n' -- 'Exceptions are identified by class instances. The "except" ' -- 'clause is\n' -- 'selected depending on the class of the instance: it must ' -- 'reference the\n' -- 'class of the instance or a *non-virtual base class* thereof. ' -- 'The\n' -- 'instance can be received by the handler and can carry ' -- 'additional\n' -- 'information about the exceptional condition.\n' -- '\n' -- 'Note:\n' -- '\n' -- ' Exception messages are not part of the Python API. Their ' -- 'contents\n' -- ' may change from one version of Python to the next without ' -- 'warning\n' -- ' and should not be relied on by code which will run under ' -- 'multiple\n' -- ' versions of the interpreter.\n' -- '\n' -- 'See also the description of the "try" statement in section The ' -- 'try\n' -- 'statement and "raise" statement in section The raise ' -- 'statement.\n' -- '\n' -- '-[ Footnotes ]-\n' -- '\n' -- '[1] This limitation occurs because the code that is executed ' -- 'by these\n' -- ' operations is not available at the time the module is ' -- 'compiled.\n', -- 'execmodel': 'Execution model\n' -- '***************\n' -- '\n' -- '\n' -- 'Structure of a program\n' -- '======================\n' -- '\n' -- 'A Python program is constructed from code blocks. A *block* is ' -- 'a piece\n' -- 'of Python program text that is executed as a unit. The ' -- 'following are\n' -- 'blocks: a module, a function body, and a class definition. ' -- 'Each\n' -- 'command typed interactively is a block. A script file (a file ' -- 'given\n' -- 'as standard input to the interpreter or specified as a command ' -- 'line\n' -- 'argument to the interpreter) is a code block. A script command ' -- '(a\n' -- 'command specified on the interpreter command line with the ' -- '"-c"\n' -- 'option) is a code block. A module run as a top level script (as ' -- 'module\n' -- '"__main__") from the command line using a "-m" argument is also ' -- 'a code\n' -- 'block. The string argument passed to the built-in functions ' -- '"eval()"\n' -- 'and "exec()" is a code block.\n' -- '\n' -- 'A code block is executed in an *execution frame*. A frame ' -- 'contains\n' -- 'some administrative information (used for debugging) and ' -- 'determines\n' -- 'where and how execution continues after the code block’s ' -- 'execution has\n' -- 'completed.\n' -- '\n' -- '\n' -- 'Naming and binding\n' -- '==================\n' -- '\n' -- '\n' -- 'Binding of names\n' -- '----------------\n' -- '\n' -- '*Names* refer to objects. Names are introduced by name ' -- 'binding\n' -- 'operations.\n' -- '\n' -- 'The following constructs bind names:\n' -- '\n' -- '* formal parameters to functions,\n' -- '\n' -- '* class definitions,\n' -- '\n' -- '* function definitions,\n' -- '\n' -- '* assignment expressions,\n' -- '\n' -- '* targets that are identifiers if occurring in an assignment:\n' -- '\n' -- ' * "for" loop header,\n' -- '\n' -- ' * after "as" in a "with" statement, "except" clause, ' -- '"except*"\n' -- ' clause, or in the as-pattern in structural pattern ' -- 'matching,\n' -- '\n' -- ' * in a capture pattern in structural pattern matching\n' -- '\n' -- '* "import" statements.\n' -- '\n' -- '* "type" statements.\n' -- '\n' -- '* type parameter lists.\n' -- '\n' -- 'The "import" statement of the form "from ... import *" binds ' -- 'all names\n' -- 'defined in the imported module, except those beginning with an\n' -- 'underscore. This form may only be used at the module level.\n' -- '\n' -- 'A target occurring in a "del" statement is also considered ' -- 'bound for\n' -- 'this purpose (though the actual semantics are to unbind the ' -- 'name).\n' -- '\n' -- 'Each assignment or import statement occurs within a block ' -- 'defined by a\n' -- 'class or function definition or at the module level (the ' -- 'top-level\n' -- 'code block).\n' -- '\n' -- 'If a name is bound in a block, it is a local variable of that ' -- 'block,\n' -- 'unless declared as "nonlocal" or "global". If a name is bound ' -- 'at the\n' -- 'module level, it is a global variable. (The variables of the ' -- 'module\n' -- 'code block are local and global.) If a variable is used in a ' -- 'code\n' -- 'block but not defined there, it is a *free variable*.\n' -- '\n' -- 'Each occurrence of a name in the program text refers to the ' -- '*binding*\n' -- 'of that name established by the following name resolution ' -- 'rules.\n' -- '\n' -- '\n' -- 'Resolution of names\n' -- '-------------------\n' -- '\n' -- 'A *scope* defines the visibility of a name within a block. If ' -- 'a local\n' -- 'variable is defined in a block, its scope includes that block. ' -- 'If the\n' -- 'definition occurs in a function block, the scope extends to any ' -- 'blocks\n' -- 'contained within the defining one, unless a contained block ' -- 'introduces\n' -- 'a different binding for the name.\n' -- '\n' -- 'When a name is used in a code block, it is resolved using the ' -- 'nearest\n' -- 'enclosing scope. The set of all such scopes visible to a code ' -- 'block\n' -- 'is called the block’s *environment*.\n' -- '\n' -- 'When a name is not found at all, a "NameError" exception is ' -- 'raised. If\n' -- 'the current scope is a function scope, and the name refers to a ' -- 'local\n' -- 'variable that has not yet been bound to a value at the point ' -- 'where the\n' -- 'name is used, an "UnboundLocalError" exception is raised.\n' -- '"UnboundLocalError" is a subclass of "NameError".\n' -- '\n' -- 'If a name binding operation occurs anywhere within a code ' -- 'block, all\n' -- 'uses of the name within the block are treated as references to ' -- 'the\n' -- 'current block. This can lead to errors when a name is used ' -- 'within a\n' -- 'block before it is bound. This rule is subtle. Python lacks\n' -- 'declarations and allows name binding operations to occur ' -- 'anywhere\n' -- 'within a code block. The local variables of a code block can ' -- 'be\n' -- 'determined by scanning the entire text of the block for name ' -- 'binding\n' -- 'operations. See the FAQ entry on UnboundLocalError for ' -- 'examples.\n' -- '\n' -- 'If the "global" statement occurs within a block, all uses of ' -- 'the names\n' -- 'specified in the statement refer to the bindings of those names ' -- 'in the\n' -- 'top-level namespace. Names are resolved in the top-level ' -- 'namespace by\n' -- 'searching the global namespace, i.e. the namespace of the ' -- 'module\n' -- 'containing the code block, and the builtins namespace, the ' -- 'namespace\n' -- 'of the module "builtins". The global namespace is searched ' -- 'first. If\n' -- 'the names are not found there, the builtins namespace is ' -- 'searched\n' -- 'next. If the names are also not found in the builtins ' -- 'namespace, new\n' -- 'variables are created in the global namespace. The global ' -- 'statement\n' -- 'must precede all uses of the listed names.\n' -- '\n' -- 'The "global" statement has the same scope as a name binding ' -- 'operation\n' -- 'in the same block. If the nearest enclosing scope for a free ' -- 'variable\n' -- 'contains a global statement, the free variable is treated as a ' -- 'global.\n' -- '\n' -- 'The "nonlocal" statement causes corresponding names to refer ' -- 'to\n' -- 'previously bound variables in the nearest enclosing function ' -- 'scope.\n' -- '"SyntaxError" is raised at compile time if the given name does ' -- 'not\n' -- 'exist in any enclosing function scope. Type parameters cannot ' -- 'be\n' -- 'rebound with the "nonlocal" statement.\n' -- '\n' -- 'The namespace for a module is automatically created the first ' -- 'time a\n' -- 'module is imported. The main module for a script is always ' -- 'called\n' -- '"__main__".\n' -- '\n' -- 'Class definition blocks and arguments to "exec()" and "eval()" ' -- 'are\n' -- 'special in the context of name resolution. A class definition ' -- 'is an\n' -- 'executable statement that may use and define names. These ' -- 'references\n' -- 'follow the normal rules for name resolution with an exception ' -- 'that\n' -- 'unbound local variables are looked up in the global namespace. ' -- 'The\n' -- 'namespace of the class definition becomes the attribute ' -- 'dictionary of\n' -- 'the class. The scope of names defined in a class block is ' -- 'limited to\n' -- 'the class block; it does not extend to the code blocks of ' -- 'methods.\n' -- 'This includes comprehensions and generator expressions, but it ' -- 'does\n' -- 'not include annotation scopes, which have access to their ' -- 'enclosing\n' -- 'class scopes. This means that the following will fail:\n' -- '\n' -- ' class A:\n' -- ' a = 42\n' -- ' b = list(a + i for i in range(10))\n' -- '\n' -- 'However, the following will succeed:\n' -- '\n' -- ' class A:\n' -- ' type Alias = Nested\n' -- ' class Nested: pass\n' -- '\n' -- " print(A.Alias.__value__) # \n" -- '\n' -- '\n' -- 'Annotation scopes\n' -- '-----------------\n' -- '\n' -- '*Annotations*, type parameter lists and "type" statements ' -- 'introduce\n' -- '*annotation scopes*, which behave mostly like function scopes, ' -- 'but\n' -- 'with some exceptions discussed below.\n' -- '\n' -- 'Annotation scopes are used in the following contexts:\n' -- '\n' -- '* *Function annotations*.\n' -- '\n' -- '* *Variable annotations*.\n' -- '\n' -- '* Type parameter lists for generic type aliases.\n' -- '\n' -- '* Type parameter lists for generic functions. A generic ' -- 'function’s\n' -- ' annotations are executed within the annotation scope, but ' -- 'its\n' -- ' defaults and decorators are not.\n' -- '\n' -- '* Type parameter lists for generic classes. A generic class’s ' -- 'base\n' -- ' classes and keyword arguments are executed within the ' -- 'annotation\n' -- ' scope, but its decorators are not.\n' -- '\n' -- '* The bounds, constraints, and default values for type ' -- 'parameters\n' -- ' (lazily evaluated).\n' -- '\n' -- '* The value of type aliases (lazily evaluated).\n' -- '\n' -- 'Annotation scopes differ from function scopes in the following ' -- 'ways:\n' -- '\n' -- '* Annotation scopes have access to their enclosing class ' -- 'namespace. If\n' -- ' an annotation scope is immediately within a class scope, or ' -- 'within\n' -- ' another annotation scope that is immediately within a class ' -- 'scope,\n' -- ' the code in the annotation scope can use names defined in the ' -- 'class\n' -- ' scope as if it were executed directly within the class body. ' -- 'This\n' -- ' contrasts with regular functions defined within classes, ' -- 'which\n' -- ' cannot access names defined in the class scope.\n' -- '\n' -- '* Expressions in annotation scopes cannot contain "yield", ' -- '"yield\n' -- ' from", "await", or ":=" expressions. (These expressions are ' -- 'allowed\n' -- ' in other scopes contained within the annotation scope.)\n' -- '\n' -- '* Names defined in annotation scopes cannot be rebound with ' -- '"nonlocal"\n' -- ' statements in inner scopes. This includes only type ' -- 'parameters, as\n' -- ' no other syntactic elements that can appear within annotation ' -- 'scopes\n' -- ' can introduce new names.\n' -- '\n' -- '* While annotation scopes have an internal name, that name is ' -- 'not\n' -- ' reflected in the *qualified name* of objects defined within ' -- 'the\n' -- ' scope. Instead, the "__qualname__" of such objects is as if ' -- 'the\n' -- ' object were defined in the enclosing scope.\n' -- '\n' -- 'Added in version 3.12: Annotation scopes were introduced in ' -- 'Python\n' -- '3.12 as part of **PEP 695**.\n' -- '\n' -- 'Changed in version 3.13: Annotation scopes are also used for ' -- 'type\n' -- 'parameter defaults, as introduced by **PEP 696**.\n' -- '\n' -- 'Changed in version 3.14: Annotation scopes are now also used ' -- 'for\n' -- 'annotations, as specified in **PEP 649** and **PEP 749**.\n' -- '\n' -- '\n' -- 'Lazy evaluation\n' -- '---------------\n' -- '\n' -- 'Most annotation scopes are *lazily evaluated*. This includes\n' -- 'annotations, the values of type aliases created through the ' -- '"type"\n' -- 'statement, and the bounds, constraints, and default values of ' -- 'type\n' -- 'variables created through the type parameter syntax. This means ' -- 'that\n' -- 'they are not evaluated when the type alias or type variable is\n' -- 'created, or when the object carrying annotations is created. ' -- 'Instead,\n' -- 'they are only evaluated when necessary, for example when the\n' -- '"__value__" attribute on a type alias is accessed.\n' -- '\n' -- 'Example:\n' -- '\n' -- ' >>> type Alias = 1/0\n' -- ' >>> Alias.__value__\n' -- ' Traceback (most recent call last):\n' -- ' ...\n' -- ' ZeroDivisionError: division by zero\n' -- ' >>> def func[T: 1/0](): pass\n' -- ' >>> T = func.__type_params__[0]\n' -- ' >>> T.__bound__\n' -- ' Traceback (most recent call last):\n' -- ' ...\n' -- ' ZeroDivisionError: division by zero\n' -- '\n' -- 'Here the exception is raised only when the "__value__" ' -- 'attribute of\n' -- 'the type alias or the "__bound__" attribute of the type ' -- 'variable is\n' -- 'accessed.\n' -- '\n' -- 'This behavior is primarily useful for references to types that ' -- 'have\n' -- 'not yet been defined when the type alias or type variable is ' -- 'created.\n' -- 'For example, lazy evaluation enables creation of mutually ' -- 'recursive\n' -- 'type aliases:\n' -- '\n' -- ' from typing import Literal\n' -- '\n' -- ' type SimpleExpr = int | Parenthesized\n' -- ' type Parenthesized = tuple[Literal["("], Expr, ' -- 'Literal[")"]]\n' -- ' type Expr = SimpleExpr | tuple[SimpleExpr, Literal["+", ' -- '"-"], Expr]\n' -- '\n' -- 'Lazily evaluated values are evaluated in annotation scope, ' -- 'which means\n' -- 'that names that appear inside the lazily evaluated value are ' -- 'looked up\n' -- 'as if they were used in the immediately enclosing scope.\n' -- '\n' -- 'Added in version 3.12.\n' -- '\n' -- '\n' -- 'Builtins and restricted execution\n' -- '---------------------------------\n' -- '\n' -- '**CPython implementation detail:** Users should not touch\n' -- '"__builtins__"; it is strictly an implementation detail. ' -- 'Users\n' -- 'wanting to override values in the builtins namespace should ' -- '"import"\n' -- 'the "builtins" module and modify its attributes appropriately.\n' -- '\n' -- 'The builtins namespace associated with the execution of a code ' -- 'block\n' -- 'is actually found by looking up the name "__builtins__" in its ' -- 'global\n' -- 'namespace; this should be a dictionary or a module (in the ' -- 'latter case\n' -- 'the module’s dictionary is used). By default, when in the ' -- '"__main__"\n' -- 'module, "__builtins__" is the built-in module "builtins"; when ' -- 'in any\n' -- 'other module, "__builtins__" is an alias for the dictionary of ' -- 'the\n' -- '"builtins" module itself.\n' -- '\n' -- '\n' -- 'Interaction with dynamic features\n' -- '---------------------------------\n' -- '\n' -- 'Name resolution of free variables occurs at runtime, not at ' -- 'compile\n' -- 'time. This means that the following code will print 42:\n' -- '\n' -- ' i = 10\n' -- ' def f():\n' -- ' print(i)\n' -- ' i = 42\n' -- ' f()\n' -- '\n' -- 'The "eval()" and "exec()" functions do not have access to the ' -- 'full\n' -- 'environment for resolving names. Names may be resolved in the ' -- 'local\n' -- 'and global namespaces of the caller. Free variables are not ' -- 'resolved\n' -- 'in the nearest enclosing namespace, but in the global ' -- 'namespace. [1]\n' -- 'The "exec()" and "eval()" functions have optional arguments to\n' -- 'override the global and local namespace. If only one namespace ' -- 'is\n' -- 'specified, it is used for both.\n' -- '\n' -- '\n' -- 'Exceptions\n' -- '==========\n' -- '\n' -- 'Exceptions are a means of breaking out of the normal flow of ' -- 'control\n' -- 'of a code block in order to handle errors or other exceptional\n' -- 'conditions. An exception is *raised* at the point where the ' -- 'error is\n' -- 'detected; it may be *handled* by the surrounding code block or ' -- 'by any\n' -- 'code block that directly or indirectly invoked the code block ' -- 'where\n' -- 'the error occurred.\n' -- '\n' -- 'The Python interpreter raises an exception when it detects a ' -- 'run-time\n' -- 'error (such as division by zero). A Python program can also\n' -- 'explicitly raise an exception with the "raise" statement. ' -- 'Exception\n' -- 'handlers are specified with the "try" … "except" statement. ' -- 'The\n' -- '"finally" clause of such a statement can be used to specify ' -- 'cleanup\n' -- 'code which does not handle the exception, but is executed ' -- 'whether an\n' -- 'exception occurred or not in the preceding code.\n' -- '\n' -- 'Python uses the “termination†model of error handling: an ' -- 'exception\n' -- 'handler can find out what happened and continue execution at an ' -- 'outer\n' -- 'level, but it cannot repair the cause of the error and retry ' -- 'the\n' -- 'failing operation (except by re-entering the offending piece of ' -- 'code\n' -- 'from the top).\n' -- '\n' -- 'When an exception is not handled at all, the interpreter ' -- 'terminates\n' -- 'execution of the program, or returns to its interactive main ' -- 'loop. In\n' -- 'either case, it prints a stack traceback, except when the ' -- 'exception is\n' -- '"SystemExit".\n' -- '\n' -- 'Exceptions are identified by class instances. The "except" ' -- 'clause is\n' -- 'selected depending on the class of the instance: it must ' -- 'reference the\n' -- 'class of the instance or a *non-virtual base class* thereof. ' -- 'The\n' -- 'instance can be received by the handler and can carry ' -- 'additional\n' -- 'information about the exceptional condition.\n' -- '\n' -- 'Note:\n' -- '\n' -- ' Exception messages are not part of the Python API. Their ' -- 'contents\n' -- ' may change from one version of Python to the next without ' -- 'warning\n' -- ' and should not be relied on by code which will run under ' -- 'multiple\n' -- ' versions of the interpreter.\n' -- '\n' -- 'See also the description of the "try" statement in section The ' -- 'try\n' -- 'statement and "raise" statement in section The raise ' -- 'statement.\n' -- '\n' -- '-[ Footnotes ]-\n' -- '\n' -- '[1] This limitation occurs because the code that is executed by ' -- 'these\n' -- ' operations is not available at the time the module is ' -- 'compiled.\n', -- 'exprlists': 'Expression lists\n' -- '****************\n' -- '\n' -- ' starred_expression ::= ["*"] or_expr\n' -- ' flexible_expression ::= assignment_expression | ' -- 'starred_expression\n' -- ' flexible_expression_list ::= flexible_expression ("," ' -- 'flexible_expression)* [","]\n' -- ' starred_expression_list ::= starred_expression ("," ' -- 'starred_expression)* [","]\n' -- ' expression_list ::= expression ("," expression)* ' -- '[","]\n' -- ' yield_list ::= expression_list | ' -- 'starred_expression "," [starred_expression_list]\n' -- '\n' -- 'Except when part of a list or set display, an expression list\n' -- 'containing at least one comma yields a tuple. The length of ' -- 'the tuple\n' -- 'is the number of expressions in the list. The expressions are\n' -- 'evaluated from left to right.\n' -- '\n' -- 'An asterisk "*" denotes *iterable unpacking*. Its operand must ' -- 'be an\n' -- '*iterable*. The iterable is expanded into a sequence of items, ' -- 'which\n' -- 'are included in the new tuple, list, or set, at the site of ' -- 'the\n' -- 'unpacking.\n' -- '\n' -- 'Added in version 3.5: Iterable unpacking in expression lists,\n' -- 'originally proposed by **PEP 448**.\n' -- '\n' -- 'Added in version 3.11: Any item in an expression list may be ' -- 'starred.\n' -- 'See **PEP 646**.\n' -- '\n' -- 'A trailing comma is required only to create a one-item tuple, ' -- 'such as\n' -- '"1,"; it is optional in all other cases. A single expression ' -- 'without a\n' -- 'trailing comma doesn’t create a tuple, but rather yields the ' -- 'value of\n' -- 'that expression. (To create an empty tuple, use an empty pair ' -- 'of\n' -- 'parentheses: "()".)\n', -- 'floating': 'Floating-point literals\n' -- '***********************\n' -- '\n' -- 'Floating-point literals are described by the following lexical\n' -- 'definitions:\n' -- '\n' -- ' floatnumber ::= pointfloat | exponentfloat\n' -- ' pointfloat ::= [digitpart] fraction | digitpart "."\n' -- ' exponentfloat ::= (digitpart | pointfloat) exponent\n' -- ' digitpart ::= digit (["_"] digit)*\n' -- ' fraction ::= "." digitpart\n' -- ' exponent ::= ("e" | "E") ["+" | "-"] digitpart\n' -- '\n' -- 'Note that the integer and exponent parts are always interpreted ' -- 'using\n' -- 'radix 10. For example, "077e010" is legal, and denotes the same ' -- 'number\n' -- 'as "77e10". The allowed range of floating-point literals is\n' -- 'implementation-dependent. As in integer literals, underscores ' -- 'are\n' -- 'supported for digit grouping.\n' -- '\n' -- 'Some examples of floating-point literals:\n' -- '\n' -- ' 3.14 10. .001 1e100 3.14e-10 0e0 ' -- '3.14_15_93\n' -- '\n' -- 'Changed in version 3.6: Underscores are now allowed for ' -- 'grouping\n' -- 'purposes in literals.\n', -- 'for': 'The "for" statement\n' -- '*******************\n' -- '\n' -- 'The "for" statement is used to iterate over the elements of a ' -- 'sequence\n' -- '(such as a string, tuple or list) or other iterable object:\n' -- '\n' -- ' for_stmt ::= "for" target_list "in" starred_list ":" suite\n' -- ' ["else" ":" suite]\n' -- '\n' -- 'The "starred_list" expression is evaluated once; it should yield an\n' -- '*iterable* object. An *iterator* is created for that iterable. The\n' -- 'first item provided by the iterator is then assigned to the target\n' -- 'list using the standard rules for assignments (see Assignment\n' -- 'statements), and the suite is executed. This repeats for each item\n' -- 'provided by the iterator. When the iterator is exhausted, the suite\n' -- 'in the "else" clause, if present, is executed, and the loop\n' -- 'terminates.\n' -- '\n' -- 'A "break" statement executed in the first suite terminates the loop\n' -- 'without executing the "else" clause’s suite. A "continue" statement\n' -- 'executed in the first suite skips the rest of the suite and ' -- 'continues\n' -- 'with the next item, or with the "else" clause if there is no next\n' -- 'item.\n' -- '\n' -- 'The for-loop makes assignments to the variables in the target list.\n' -- 'This overwrites all previous assignments to those variables ' -- 'including\n' -- 'those made in the suite of the for-loop:\n' -- '\n' -- ' for i in range(10):\n' -- ' print(i)\n' -- ' i = 5 # this will not affect the for-loop\n' -- ' # because i will be overwritten with the ' -- 'next\n' -- ' # index in the range\n' -- '\n' -- 'Names in the target list are not deleted when the loop is finished,\n' -- 'but if the sequence is empty, they will not have been assigned to at\n' -- 'all by the loop. Hint: the built-in type "range()" represents\n' -- 'immutable arithmetic sequences of integers. For instance, iterating\n' -- '"range(3)" successively yields 0, 1, and then 2.\n' -- '\n' -- 'Changed in version 3.11: Starred elements are now allowed in the\n' -- 'expression list.\n', -- 'formatstrings': 'Format String Syntax\n' -- '********************\n' -- '\n' -- 'The "str.format()" method and the "Formatter" class share ' -- 'the same\n' -- 'syntax for format strings (although in the case of ' -- '"Formatter",\n' -- 'subclasses can define their own format string syntax). The ' -- 'syntax is\n' -- 'related to that of formatted string literals, but it is ' -- 'less\n' -- 'sophisticated and, in particular, does not support ' -- 'arbitrary\n' -- 'expressions.\n' -- '\n' -- 'Format strings contain “replacement fields†surrounded by ' -- 'curly braces\n' -- '"{}". Anything that is not contained in braces is ' -- 'considered literal\n' -- 'text, which is copied unchanged to the output. If you need ' -- 'to include\n' -- 'a brace character in the literal text, it can be escaped by ' -- 'doubling:\n' -- '"{{" and "}}".\n' -- '\n' -- 'The grammar for a replacement field is as follows:\n' -- '\n' -- ' replacement_field ::= "{" [field_name] ["!" conversion] ' -- '[":" format_spec] "}"\n' -- ' field_name ::= arg_name ("." attribute_name | "[" ' -- 'element_index "]")*\n' -- ' arg_name ::= [identifier | digit+]\n' -- ' attribute_name ::= identifier\n' -- ' element_index ::= digit+ | index_string\n' -- ' index_string ::= ' -- '+\n' -- ' conversion ::= "r" | "s" | "a"\n' -- ' format_spec ::= format-spec:format_spec\n' -- '\n' -- 'In less formal terms, the replacement field can start with ' -- 'a\n' -- '*field_name* that specifies the object whose value is to be ' -- 'formatted\n' -- 'and inserted into the output instead of the replacement ' -- 'field. The\n' -- '*field_name* is optionally followed by a *conversion* ' -- 'field, which is\n' -- 'preceded by an exclamation point "\'!\'", and a ' -- '*format_spec*, which is\n' -- 'preceded by a colon "\':\'". These specify a non-default ' -- 'format for the\n' -- 'replacement value.\n' -- '\n' -- 'See also the Format Specification Mini-Language section.\n' -- '\n' -- 'The *field_name* itself begins with an *arg_name* that is ' -- 'either a\n' -- 'number or a keyword. If it’s a number, it refers to a ' -- 'positional\n' -- 'argument, and if it’s a keyword, it refers to a named ' -- 'keyword\n' -- 'argument. An *arg_name* is treated as a number if a call ' -- 'to\n' -- '"str.isdecimal()" on the string would return true. If the ' -- 'numerical\n' -- 'arg_names in a format string are 0, 1, 2, … in sequence, ' -- 'they can all\n' -- 'be omitted (not just some) and the numbers 0, 1, 2, … will ' -- 'be\n' -- 'automatically inserted in that order. Because *arg_name* is ' -- 'not quote-\n' -- 'delimited, it is not possible to specify arbitrary ' -- 'dictionary keys\n' -- '(e.g., the strings "\'10\'" or "\':-]\'") within a format ' -- 'string. The\n' -- '*arg_name* can be followed by any number of index or ' -- 'attribute\n' -- 'expressions. An expression of the form "\'.name\'" selects ' -- 'the named\n' -- 'attribute using "getattr()", while an expression of the ' -- 'form\n' -- '"\'[index]\'" does an index lookup using "__getitem__()".\n' -- '\n' -- 'Changed in version 3.1: The positional argument specifiers ' -- 'can be\n' -- 'omitted for "str.format()", so "\'{} {}\'.format(a, b)" is ' -- 'equivalent to\n' -- '"\'{0} {1}\'.format(a, b)".\n' -- '\n' -- 'Changed in version 3.4: The positional argument specifiers ' -- 'can be\n' -- 'omitted for "Formatter".\n' -- '\n' -- 'Some simple format string examples:\n' -- '\n' -- ' "First, thou shalt count to {0}" # References first ' -- 'positional argument\n' -- ' "Bring me a {}" # Implicitly ' -- 'references the first positional argument\n' -- ' "From {} to {}" # Same as "From {0} to ' -- '{1}"\n' -- ' "My quest is {name}" # References keyword ' -- "argument 'name'\n" -- ' "Weight in tons {0.weight}" # \'weight\' attribute ' -- 'of first positional arg\n' -- ' "Units destroyed: {players[0]}" # First element of ' -- "keyword argument 'players'.\n" -- '\n' -- 'The *conversion* field causes a type coercion before ' -- 'formatting.\n' -- 'Normally, the job of formatting a value is done by the ' -- '"__format__()"\n' -- 'method of the value itself. However, in some cases it is ' -- 'desirable to\n' -- 'force a type to be formatted as a string, overriding its ' -- 'own\n' -- 'definition of formatting. By converting the value to a ' -- 'string before\n' -- 'calling "__format__()", the normal formatting logic is ' -- 'bypassed.\n' -- '\n' -- 'Three conversion flags are currently supported: "\'!s\'" ' -- 'which calls\n' -- '"str()" on the value, "\'!r\'" which calls "repr()" and ' -- '"\'!a\'" which\n' -- 'calls "ascii()".\n' -- '\n' -- 'Some examples:\n' -- '\n' -- ' "Harold\'s a clever {0!s}" # Calls str() on the ' -- 'argument first\n' -- ' "Bring out the holy {name!r}" # Calls repr() on the ' -- 'argument first\n' -- ' "More {!a}" # Calls ascii() on the ' -- 'argument first\n' -- '\n' -- 'The *format_spec* field contains a specification of how the ' -- 'value\n' -- 'should be presented, including such details as field width, ' -- 'alignment,\n' -- 'padding, decimal precision and so on. Each value type can ' -- 'define its\n' -- 'own “formatting mini-language†or interpretation of the ' -- '*format_spec*.\n' -- '\n' -- 'Most built-in types support a common formatting ' -- 'mini-language, which\n' -- 'is described in the next section.\n' -- '\n' -- 'A *format_spec* field can also include nested replacement ' -- 'fields\n' -- 'within it. These nested replacement fields may contain a ' -- 'field name,\n' -- 'conversion flag and format specification, but deeper ' -- 'nesting is not\n' -- 'allowed. The replacement fields within the format_spec ' -- 'are\n' -- 'substituted before the *format_spec* string is interpreted. ' -- 'This\n' -- 'allows the formatting of a value to be dynamically ' -- 'specified.\n' -- '\n' -- 'See the Format examples section for some examples.\n' -- '\n' -- '\n' -- 'Format Specification Mini-Language\n' -- '==================================\n' -- '\n' -- '“Format specifications†are used within replacement fields ' -- 'contained\n' -- 'within a format string to define how individual values are ' -- 'presented\n' -- '(see Format String Syntax and f-strings). They can also be ' -- 'passed\n' -- 'directly to the built-in "format()" function. Each ' -- 'formattable type\n' -- 'may define how the format specification is to be ' -- 'interpreted.\n' -- '\n' -- 'Most built-in types implement the following options for ' -- 'format\n' -- 'specifications, although some of the formatting options are ' -- 'only\n' -- 'supported by the numeric types.\n' -- '\n' -- 'A general convention is that an empty format specification ' -- 'produces\n' -- 'the same result as if you had called "str()" on the value. ' -- 'A non-empty\n' -- 'format specification typically modifies the result.\n' -- '\n' -- 'The general form of a *standard format specifier* is:\n' -- '\n' -- ' format_spec ::= ' -- '[[fill]align][sign]["z"]["#"]["0"][width][grouping_option]["." ' -- 'precision][type]\n' -- ' fill ::= \n' -- ' align ::= "<" | ">" | "=" | "^"\n' -- ' sign ::= "+" | "-" | " "\n' -- ' width ::= digit+\n' -- ' grouping_option ::= "_" | ","\n' -- ' precision ::= digit+\n' -- ' type ::= "b" | "c" | "d" | "e" | "E" | "f" | ' -- '"F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"\n' -- '\n' -- 'If a valid *align* value is specified, it can be preceded ' -- 'by a *fill*\n' -- 'character that can be any character and defaults to a space ' -- 'if\n' -- 'omitted. It is not possible to use a literal curly brace ' -- '(â€"{"†or\n' -- '“"}"â€) as the *fill* character in a formatted string ' -- 'literal or when\n' -- 'using the "str.format()" method. However, it is possible ' -- 'to insert a\n' -- 'curly brace with a nested replacement field. This ' -- 'limitation doesn’t\n' -- 'affect the "format()" function.\n' -- '\n' -- 'The meaning of the various alignment options is as ' -- 'follows:\n' -- '\n' -- '+-----------+------------------------------------------------------------+\n' -- '| Option | ' -- 'Meaning ' -- '|\n' -- '|===========|============================================================|\n' -- '| "\'<\'" | Forces the field to be left-aligned within ' -- 'the available |\n' -- '| | space (this is the default for most ' -- 'objects). |\n' -- '+-----------+------------------------------------------------------------+\n' -- '| "\'>\'" | Forces the field to be right-aligned within ' -- 'the available |\n' -- '| | space (this is the default for ' -- 'numbers). |\n' -- '+-----------+------------------------------------------------------------+\n' -- '| "\'=\'" | Forces the padding to be placed after the ' -- 'sign (if any) |\n' -- '| | but before the digits. This is used for ' -- 'printing fields |\n' -- '| | in the form ‘+000000120’. This alignment ' -- 'option is only |\n' -- '| | valid for numeric types, excluding "complex". ' -- 'It becomes |\n' -- '| | the default for numbers when ‘0’ immediately ' -- 'precedes the |\n' -- '| | field ' -- 'width. |\n' -- '+-----------+------------------------------------------------------------+\n' -- '| "\'^\'" | Forces the field to be centered within the ' -- 'available |\n' -- '| | ' -- 'space. ' -- '|\n' -- '+-----------+------------------------------------------------------------+\n' -- '\n' -- 'Note that unless a minimum field width is defined, the ' -- 'field width\n' -- 'will always be the same size as the data to fill it, so ' -- 'that the\n' -- 'alignment option has no meaning in this case.\n' -- '\n' -- 'The *sign* option is only valid for number types, and can ' -- 'be one of\n' -- 'the following:\n' -- '\n' -- '+-----------+------------------------------------------------------------+\n' -- '| Option | ' -- 'Meaning ' -- '|\n' -- '|===========|============================================================|\n' -- '| "\'+\'" | indicates that a sign should be used for ' -- 'both positive as |\n' -- '| | well as negative ' -- 'numbers. |\n' -- '+-----------+------------------------------------------------------------+\n' -- '| "\'-\'" | indicates that a sign should be used only ' -- 'for negative |\n' -- '| | numbers (this is the default ' -- 'behavior). |\n' -- '+-----------+------------------------------------------------------------+\n' -- '| space | indicates that a leading space should be used ' -- 'on positive |\n' -- '| | numbers, and a minus sign on negative ' -- 'numbers. |\n' -- '+-----------+------------------------------------------------------------+\n' -- '\n' -- 'The "\'z\'" option coerces negative zero floating-point ' -- 'values to\n' -- 'positive zero after rounding to the format precision. This ' -- 'option is\n' -- 'only valid for floating-point presentation types.\n' -- '\n' -- 'Changed in version 3.11: Added the "\'z\'" option (see also ' -- '**PEP\n' -- '682**).\n' -- '\n' -- 'The "\'#\'" option causes the “alternate form†to be used ' -- 'for the\n' -- 'conversion. The alternate form is defined differently for ' -- 'different\n' -- 'types. This option is only valid for integer, float and ' -- 'complex\n' -- 'types. For integers, when binary, octal, or hexadecimal ' -- 'output is\n' -- 'used, this option adds the respective prefix "\'0b\'", ' -- '"\'0o\'", "\'0x\'",\n' -- 'or "\'0X\'" to the output value. For float and complex the ' -- 'alternate\n' -- 'form causes the result of the conversion to always contain ' -- 'a decimal-\n' -- 'point character, even if no digits follow it. Normally, a ' -- 'decimal-\n' -- 'point character appears in the result of these conversions ' -- 'only if a\n' -- 'digit follows it. In addition, for "\'g\'" and "\'G\'" ' -- 'conversions,\n' -- 'trailing zeros are not removed from the result.\n' -- '\n' -- 'The "\',\'" option signals the use of a comma for a ' -- 'thousands separator\n' -- 'for floating-point presentation types and for integer ' -- 'presentation\n' -- 'type "\'d\'". For other presentation types, this option is ' -- 'an error. For\n' -- 'a locale aware separator, use the "\'n\'" integer ' -- 'presentation type\n' -- 'instead.\n' -- '\n' -- 'Changed in version 3.1: Added the "\',\'" option (see also ' -- '**PEP 378**).\n' -- '\n' -- 'The "\'_\'" option signals the use of an underscore for a ' -- 'thousands\n' -- 'separator for floating-point presentation types and for ' -- 'integer\n' -- 'presentation type "\'d\'". For integer presentation types ' -- '"\'b\'", "\'o\'",\n' -- '"\'x\'", and "\'X\'", underscores will be inserted every 4 ' -- 'digits. For\n' -- 'other presentation types, specifying this option is an ' -- 'error.\n' -- '\n' -- 'Changed in version 3.6: Added the "\'_\'" option (see also ' -- '**PEP 515**).\n' -- '\n' -- '*width* is a decimal integer defining the minimum total ' -- 'field width,\n' -- 'including any prefixes, separators, and other formatting ' -- 'characters.\n' -- 'If not specified, then the field width will be determined ' -- 'by the\n' -- 'content.\n' -- '\n' -- 'When no explicit alignment is given, preceding the *width* ' -- 'field by a\n' -- 'zero ("\'0\'") character enables sign-aware zero-padding ' -- 'for numeric\n' -- 'types, excluding "complex". This is equivalent to a *fill* ' -- 'character\n' -- 'of "\'0\'" with an *alignment* type of "\'=\'".\n' -- '\n' -- 'Changed in version 3.10: Preceding the *width* field by ' -- '"\'0\'" no\n' -- 'longer affects the default alignment for strings.\n' -- '\n' -- 'The *precision* is a decimal integer indicating how many ' -- 'digits should\n' -- 'be displayed after the decimal point for presentation types ' -- '"\'f\'" and\n' -- '"\'F\'", or before and after the decimal point for ' -- 'presentation types\n' -- '"\'g\'" or "\'G\'". For string presentation types the ' -- 'field indicates the\n' -- 'maximum field size - in other words, how many characters ' -- 'will be used\n' -- 'from the field content. The *precision* is not allowed for ' -- 'integer\n' -- 'presentation types.\n' -- '\n' -- 'Finally, the *type* determines how the data should be ' -- 'presented.\n' -- '\n' -- 'The available string presentation types are:\n' -- '\n' -- ' ' -- '+-----------+------------------------------------------------------------+\n' -- ' | Type | ' -- 'Meaning ' -- '|\n' -- ' ' -- '|===========|============================================================|\n' -- ' | "\'s\'" | String format. This is the default type ' -- 'for strings and |\n' -- ' | | may be ' -- 'omitted. |\n' -- ' ' -- '+-----------+------------------------------------------------------------+\n' -- ' | None | The same as ' -- '"\'s\'". |\n' -- ' ' -- '+-----------+------------------------------------------------------------+\n' -- '\n' -- 'The available integer presentation types are:\n' -- '\n' -- ' ' -- '+-----------+------------------------------------------------------------+\n' -- ' | Type | ' -- 'Meaning ' -- '|\n' -- ' ' -- '|===========|============================================================|\n' -- ' | "\'b\'" | Binary format. Outputs the number in ' -- 'base 2. |\n' -- ' ' -- '+-----------+------------------------------------------------------------+\n' -- ' | "\'c\'" | Character. Converts the integer to the ' -- 'corresponding |\n' -- ' | | unicode character before ' -- 'printing. |\n' -- ' ' -- '+-----------+------------------------------------------------------------+\n' -- ' | "\'d\'" | Decimal Integer. Outputs the number in ' -- 'base 10. |\n' -- ' ' -- '+-----------+------------------------------------------------------------+\n' -- ' | "\'o\'" | Octal format. Outputs the number in base ' -- '8. |\n' -- ' ' -- '+-----------+------------------------------------------------------------+\n' -- ' | "\'x\'" | Hex format. Outputs the number in base ' -- '16, using lower- |\n' -- ' | | case letters for the digits above ' -- '9. |\n' -- ' ' -- '+-----------+------------------------------------------------------------+\n' -- ' | "\'X\'" | Hex format. Outputs the number in base ' -- '16, using upper- |\n' -- ' | | case letters for the digits above 9. In ' -- 'case "\'#\'" is |\n' -- ' | | specified, the prefix "\'0x\'" will be ' -- 'upper-cased to "\'0X\'" |\n' -- ' | | as ' -- 'well. |\n' -- ' ' -- '+-----------+------------------------------------------------------------+\n' -- ' | "\'n\'" | Number. This is the same as "\'d\'", ' -- 'except that it uses the |\n' -- ' | | current locale setting to insert the ' -- 'appropriate number |\n' -- ' | | separator ' -- 'characters. |\n' -- ' ' -- '+-----------+------------------------------------------------------------+\n' -- ' | None | The same as ' -- '"\'d\'". |\n' -- ' ' -- '+-----------+------------------------------------------------------------+\n' -- '\n' -- 'In addition to the above presentation types, integers can ' -- 'be formatted\n' -- 'with the floating-point presentation types listed below ' -- '(except "\'n\'"\n' -- 'and "None"). When doing so, "float()" is used to convert ' -- 'the integer\n' -- 'to a floating-point number before formatting.\n' -- '\n' -- 'The available presentation types for "float" and "Decimal" ' -- 'values are:\n' -- '\n' -- ' ' -- '+-----------+------------------------------------------------------------+\n' -- ' | Type | ' -- 'Meaning ' -- '|\n' -- ' ' -- '|===========|============================================================|\n' -- ' | "\'e\'" | Scientific notation. For a given ' -- 'precision "p", formats |\n' -- ' | | the number in scientific notation with the ' -- 'letter ‘e’ |\n' -- ' | | separating the coefficient from the ' -- 'exponent. The |\n' -- ' | | coefficient has one digit before and "p" ' -- 'digits after the |\n' -- ' | | decimal point, for a total of "p + 1" ' -- 'significant digits. |\n' -- ' | | With no precision given, uses a precision ' -- 'of "6" digits |\n' -- ' | | after the decimal point for "float", and ' -- 'shows all |\n' -- ' | | coefficient digits for "Decimal". If ' -- '"p=0", the decimal |\n' -- ' | | point is omitted unless the "#" option is ' -- 'used. |\n' -- ' ' -- '+-----------+------------------------------------------------------------+\n' -- ' | "\'E\'" | Scientific notation. Same as "\'e\'" ' -- 'except it uses an upper |\n' -- ' | | case ‘E’ as the separator ' -- 'character. |\n' -- ' ' -- '+-----------+------------------------------------------------------------+\n' -- ' | "\'f\'" | Fixed-point notation. For a given ' -- 'precision "p", formats |\n' -- ' | | the number as a decimal number with ' -- 'exactly "p" digits |\n' -- ' | | following the decimal point. With no ' -- 'precision given, uses |\n' -- ' | | a precision of "6" digits after the ' -- 'decimal point for |\n' -- ' | | "float", and uses a precision large enough ' -- 'to show all |\n' -- ' | | coefficient digits for "Decimal". If ' -- '"p=0", the decimal |\n' -- ' | | point is omitted unless the "#" option is ' -- 'used. |\n' -- ' ' -- '+-----------+------------------------------------------------------------+\n' -- ' | "\'F\'" | Fixed-point notation. Same as "\'f\'", ' -- 'but converts "nan" to |\n' -- ' | | "NAN" and "inf" to ' -- '"INF". |\n' -- ' ' -- '+-----------+------------------------------------------------------------+\n' -- ' | "\'g\'" | General format. For a given precision ' -- '"p >= 1", this |\n' -- ' | | rounds the number to "p" significant ' -- 'digits and then |\n' -- ' | | formats the result in either fixed-point ' -- 'format or in |\n' -- ' | | scientific notation, depending on its ' -- 'magnitude. A |\n' -- ' | | precision of "0" is treated as equivalent ' -- 'to a precision |\n' -- ' | | of "1". The precise rules are as follows: ' -- 'suppose that |\n' -- ' | | the result formatted with presentation ' -- 'type "\'e\'" and |\n' -- ' | | precision "p-1" would have exponent ' -- '"exp". Then, if "m <= |\n' -- ' | | exp < p", where "m" is -4 for floats and ' -- '-6 for |\n' -- ' | | "Decimals", the number is formatted with ' -- 'presentation type |\n' -- ' | | "\'f\'" and precision "p-1-exp". ' -- 'Otherwise, the number is |\n' -- ' | | formatted with presentation type "\'e\'" ' -- 'and precision |\n' -- ' | | "p-1". In both cases insignificant ' -- 'trailing zeros are |\n' -- ' | | removed from the significand, and the ' -- 'decimal point is |\n' -- ' | | also removed if there are no remaining ' -- 'digits following |\n' -- ' | | it, unless the "\'#\'" option is used. ' -- 'With no precision |\n' -- ' | | given, uses a precision of "6" significant ' -- 'digits for |\n' -- ' | | "float". For "Decimal", the coefficient of ' -- 'the result is |\n' -- ' | | formed from the coefficient digits of the ' -- 'value; |\n' -- ' | | scientific notation is used for values ' -- 'smaller than "1e-6" |\n' -- ' | | in absolute value and values where the ' -- 'place value of the |\n' -- ' | | least significant digit is larger than 1, ' -- 'and fixed-point |\n' -- ' | | notation is used otherwise. Positive and ' -- 'negative |\n' -- ' | | infinity, positive and negative zero, and ' -- 'nans, are |\n' -- ' | | formatted as "inf", "-inf", "0", "-0" and ' -- '"nan" |\n' -- ' | | respectively, regardless of the ' -- 'precision. |\n' -- ' ' -- '+-----------+------------------------------------------------------------+\n' -- ' | "\'G\'" | General format. Same as "\'g\'" except ' -- 'switches to "\'E\'" if |\n' -- ' | | the number gets too large. The ' -- 'representations of infinity |\n' -- ' | | and NaN are uppercased, ' -- 'too. |\n' -- ' ' -- '+-----------+------------------------------------------------------------+\n' -- ' | "\'n\'" | Number. This is the same as "\'g\'", ' -- 'except that it uses the |\n' -- ' | | current locale setting to insert the ' -- 'appropriate number |\n' -- ' | | separator ' -- 'characters. |\n' -- ' ' -- '+-----------+------------------------------------------------------------+\n' -- ' | "\'%\'" | Percentage. Multiplies the number by 100 ' -- 'and displays in |\n' -- ' | | fixed ("\'f\'") format, followed by a ' -- 'percent sign. |\n' -- ' ' -- '+-----------+------------------------------------------------------------+\n' -- ' | None | For "float" this is like the "\'g\'" type, ' -- 'except that when |\n' -- ' | | fixed- point notation is used to format ' -- 'the result, it |\n' -- ' | | always includes at least one digit past ' -- 'the decimal point, |\n' -- ' | | and switches to the scientific notation ' -- 'when "exp >= p - |\n' -- ' | | 1". When the precision is not specified, ' -- 'the latter will |\n' -- ' | | be as large as needed to represent the ' -- 'given value |\n' -- ' | | faithfully. For "Decimal", this is the ' -- 'same as either |\n' -- ' | | "\'g\'" or "\'G\'" depending on the value ' -- 'of |\n' -- ' | | "context.capitals" for the current decimal ' -- 'context. The |\n' -- ' | | overall effect is to match the output of ' -- '"str()" as |\n' -- ' | | altered by the other format ' -- 'modifiers. |\n' -- ' ' -- '+-----------+------------------------------------------------------------+\n' -- '\n' -- 'The result should be correctly rounded to a given precision ' -- '"p" of\n' -- 'digits after the decimal point. The rounding mode for ' -- '"float" matches\n' -- 'that of the "round()" builtin. For "Decimal", the rounding ' -- 'mode of\n' -- 'the current context will be used.\n' -- '\n' -- 'The available presentation types for "complex" are the same ' -- 'as those\n' -- 'for "float" ("\'%\'" is not allowed). Both the real and ' -- 'imaginary\n' -- 'components of a complex number are formatted as ' -- 'floating-point\n' -- 'numbers, according to the specified presentation type. ' -- 'They are\n' -- 'separated by the mandatory sign of the imaginary part, the ' -- 'latter\n' -- 'being terminated by a "j" suffix. If the presentation type ' -- 'is\n' -- 'missing, the result will match the output of "str()" ' -- '(complex numbers\n' -- 'with a non-zero real part are also surrounded by ' -- 'parentheses),\n' -- 'possibly altered by other format modifiers.\n' -- '\n' -- '\n' -- 'Format examples\n' -- '===============\n' -- '\n' -- 'This section contains examples of the "str.format()" syntax ' -- 'and\n' -- 'comparison with the old "%"-formatting.\n' -- '\n' -- 'In most of the cases the syntax is similar to the old ' -- '"%"-formatting,\n' -- 'with the addition of the "{}" and with ":" used instead of ' -- '"%". For\n' -- 'example, "\'%03.2f\'" can be translated to "\'{:03.2f}\'".\n' -- '\n' -- 'The new format syntax also supports new and different ' -- 'options, shown\n' -- 'in the following examples.\n' -- '\n' -- 'Accessing arguments by position:\n' -- '\n' -- " >>> '{0}, {1}, {2}'.format('a', 'b', 'c')\n" -- " 'a, b, c'\n" -- " >>> '{}, {}, {}'.format('a', 'b', 'c') # 3.1+ only\n" -- " 'a, b, c'\n" -- " >>> '{2}, {1}, {0}'.format('a', 'b', 'c')\n" -- " 'c, b, a'\n" -- " >>> '{2}, {1}, {0}'.format(*'abc') # unpacking " -- 'argument sequence\n' -- " 'c, b, a'\n" -- " >>> '{0}{1}{0}'.format('abra', 'cad') # arguments' " -- 'indices can be repeated\n' -- " 'abracadabra'\n" -- '\n' -- 'Accessing arguments by name:\n' -- '\n' -- " >>> 'Coordinates: {latitude}, " -- "{longitude}'.format(latitude='37.24N', " -- "longitude='-115.81W')\n" -- " 'Coordinates: 37.24N, -115.81W'\n" -- " >>> coord = {'latitude': '37.24N', 'longitude': " -- "'-115.81W'}\n" -- " >>> 'Coordinates: {latitude}, " -- "{longitude}'.format(**coord)\n" -- " 'Coordinates: 37.24N, -115.81W'\n" -- '\n' -- 'Accessing arguments’ attributes:\n' -- '\n' -- ' >>> c = 3-5j\n' -- " >>> ('The complex number {0} is formed from the real " -- "part {0.real} '\n" -- " ... 'and the imaginary part {0.imag}.').format(c)\n" -- " 'The complex number (3-5j) is formed from the real part " -- "3.0 and the imaginary part -5.0.'\n" -- ' >>> class Point:\n' -- ' ... def __init__(self, x, y):\n' -- ' ... self.x, self.y = x, y\n' -- ' ... def __str__(self):\n' -- " ... return 'Point({self.x}, " -- "{self.y})'.format(self=self)\n" -- ' ...\n' -- ' >>> str(Point(4, 2))\n' -- " 'Point(4, 2)'\n" -- '\n' -- 'Accessing arguments’ items:\n' -- '\n' -- ' >>> coord = (3, 5)\n' -- " >>> 'X: {0[0]}; Y: {0[1]}'.format(coord)\n" -- " 'X: 3; Y: 5'\n" -- '\n' -- 'Replacing "%s" and "%r":\n' -- '\n' -- ' >>> "repr() shows quotes: {!r}; str() doesn\'t: ' -- '{!s}".format(\'test1\', \'test2\')\n' -- ' "repr() shows quotes: \'test1\'; str() doesn\'t: test2"\n' -- '\n' -- 'Aligning the text and specifying a width:\n' -- '\n' -- " >>> '{:<30}'.format('left aligned')\n" -- " 'left aligned '\n" -- " >>> '{:>30}'.format('right aligned')\n" -- " ' right aligned'\n" -- " >>> '{:^30}'.format('centered')\n" -- " ' centered '\n" -- " >>> '{:*^30}'.format('centered') # use '*' as a fill " -- 'char\n' -- " '***********centered***********'\n" -- '\n' -- 'Replacing "%+f", "%-f", and "% f" and specifying a sign:\n' -- '\n' -- " >>> '{:+f}; {:+f}'.format(3.14, -3.14) # show it " -- 'always\n' -- " '+3.140000; -3.140000'\n" -- " >>> '{: f}; {: f}'.format(3.14, -3.14) # show a space " -- 'for positive numbers\n' -- " ' 3.140000; -3.140000'\n" -- " >>> '{:-f}; {:-f}'.format(3.14, -3.14) # show only the " -- "minus -- same as '{:f}; {:f}'\n" -- " '3.140000; -3.140000'\n" -- '\n' -- 'Replacing "%x" and "%o" and converting the value to ' -- 'different bases:\n' -- '\n' -- ' >>> # format also supports binary numbers\n' -- ' >>> "int: {0:d}; hex: {0:x}; oct: {0:o}; bin: ' -- '{0:b}".format(42)\n' -- " 'int: 42; hex: 2a; oct: 52; bin: 101010'\n" -- ' >>> # with 0x, 0o, or 0b as prefix:\n' -- ' >>> "int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: ' -- '{0:#b}".format(42)\n' -- " 'int: 42; hex: 0x2a; oct: 0o52; bin: 0b101010'\n" -- '\n' -- 'Using the comma as a thousands separator:\n' -- '\n' -- " >>> '{:,}'.format(1234567890)\n" -- " '1,234,567,890'\n" -- '\n' -- 'Expressing a percentage:\n' -- '\n' -- ' >>> points = 19\n' -- ' >>> total = 22\n' -- " >>> 'Correct answers: {:.2%}'.format(points/total)\n" -- " 'Correct answers: 86.36%'\n" -- '\n' -- 'Using type-specific formatting:\n' -- '\n' -- ' >>> import datetime\n' -- ' >>> d = datetime.datetime(2010, 7, 4, 12, 15, 58)\n' -- " >>> '{:%Y-%m-%d %H:%M:%S}'.format(d)\n" -- " '2010-07-04 12:15:58'\n" -- '\n' -- 'Nesting arguments and more complex examples:\n' -- '\n' -- " >>> for align, text in zip('<^>', ['left', 'center', " -- "'right']):\n" -- " ... '{0:{fill}{align}16}'.format(text, fill=align, " -- 'align=align)\n' -- ' ...\n' -- " 'left<<<<<<<<<<<<'\n" -- " '^^^^^center^^^^^'\n" -- " '>>>>>>>>>>>right'\n" -- ' >>>\n' -- ' >>> octets = [192, 168, 0, 1]\n' -- " >>> '{:02X}{:02X}{:02X}{:02X}'.format(*octets)\n" -- " 'C0A80001'\n" -- ' >>> int(_, 16)\n' -- ' 3232235521\n' -- ' >>>\n' -- ' >>> width = 5\n' -- ' >>> for num in range(5,12): \n' -- " ... for base in 'dXob':\n" -- " ... print('{0:{width}{base}}'.format(num, " -- "base=base, width=width), end=' ')\n" -- ' ... print()\n' -- ' ...\n' -- ' 5 5 5 101\n' -- ' 6 6 6 110\n' -- ' 7 7 7 111\n' -- ' 8 8 10 1000\n' -- ' 9 9 11 1001\n' -- ' 10 A 12 1010\n' -- ' 11 B 13 1011\n', -- 'function': 'Function definitions\n' -- '********************\n' -- '\n' -- 'A function definition defines a user-defined function object ' -- '(see\n' -- 'section The standard type hierarchy):\n' -- '\n' -- ' funcdef ::= [decorators] "def" funcname ' -- '[type_params] "(" [parameter_list] ")"\n' -- ' ["->" expression] ":" suite\n' -- ' decorators ::= decorator+\n' -- ' decorator ::= "@" assignment_expression ' -- 'NEWLINE\n' -- ' parameter_list ::= defparameter ("," ' -- 'defparameter)* "," "/" ["," [parameter_list_no_posonly]]\n' -- ' | parameter_list_no_posonly\n' -- ' parameter_list_no_posonly ::= defparameter ("," ' -- 'defparameter)* ["," [parameter_list_starargs]]\n' -- ' | parameter_list_starargs\n' -- ' parameter_list_starargs ::= "*" [star_parameter] ("," ' -- 'defparameter)* ["," ["**" parameter [","]]]\n' -- ' | "**" parameter [","]\n' -- ' parameter ::= identifier [":" expression]\n' -- ' star_parameter ::= identifier [":" ["*"] ' -- 'expression]\n' -- ' defparameter ::= parameter ["=" expression]\n' -- ' funcname ::= identifier\n' -- '\n' -- 'A function definition is an executable statement. Its execution ' -- 'binds\n' -- 'the function name in the current local namespace to a function ' -- 'object\n' -- '(a wrapper around the executable code for the function). This\n' -- 'function object contains a reference to the current global ' -- 'namespace\n' -- 'as the global namespace to be used when the function is called.\n' -- '\n' -- 'The function definition does not execute the function body; this ' -- 'gets\n' -- 'executed only when the function is called. [4]\n' -- '\n' -- 'A function definition may be wrapped by one or more *decorator*\n' -- 'expressions. Decorator expressions are evaluated when the ' -- 'function is\n' -- 'defined, in the scope that contains the function definition. ' -- 'The\n' -- 'result must be a callable, which is invoked with the function ' -- 'object\n' -- 'as the only argument. The returned value is bound to the ' -- 'function name\n' -- 'instead of the function object. Multiple decorators are applied ' -- 'in\n' -- 'nested fashion. For example, the following code\n' -- '\n' -- ' @f1(arg)\n' -- ' @f2\n' -- ' def func(): pass\n' -- '\n' -- 'is roughly equivalent to\n' -- '\n' -- ' def func(): pass\n' -- ' func = f1(arg)(f2(func))\n' -- '\n' -- 'except that the original function is not temporarily bound to ' -- 'the name\n' -- '"func".\n' -- '\n' -- 'Changed in version 3.9: Functions may be decorated with any ' -- 'valid\n' -- '"assignment_expression". Previously, the grammar was much more\n' -- 'restrictive; see **PEP 614** for details.\n' -- '\n' -- 'A list of type parameters may be given in square brackets ' -- 'between the\n' -- 'function’s name and the opening parenthesis for its parameter ' -- 'list.\n' -- 'This indicates to static type checkers that the function is ' -- 'generic.\n' -- 'At runtime, the type parameters can be retrieved from the ' -- 'function’s\n' -- '"__type_params__" attribute. See Generic functions for more.\n' -- '\n' -- 'Changed in version 3.12: Type parameter lists are new in Python ' -- '3.12.\n' -- '\n' -- 'When one or more *parameters* have the form *parameter* "="\n' -- '*expression*, the function is said to have “default parameter ' -- 'values.â€\n' -- 'For a parameter with a default value, the corresponding ' -- '*argument* may\n' -- 'be omitted from a call, in which case the parameter’s default ' -- 'value is\n' -- 'substituted. If a parameter has a default value, all following\n' -- 'parameters up until the “"*"†must also have a default value — ' -- 'this is\n' -- 'a syntactic restriction that is not expressed by the grammar.\n' -- '\n' -- '**Default parameter values are evaluated from left to right when ' -- 'the\n' -- 'function definition is executed.** This means that the ' -- 'expression is\n' -- 'evaluated once, when the function is defined, and that the same ' -- '“pre-\n' -- 'computed†value is used for each call. This is especially ' -- 'important\n' -- 'to understand when a default parameter value is a mutable ' -- 'object, such\n' -- 'as a list or a dictionary: if the function modifies the object ' -- '(e.g.\n' -- 'by appending an item to a list), the default parameter value is ' -- 'in\n' -- 'effect modified. This is generally not what was intended. A ' -- 'way\n' -- 'around this is to use "None" as the default, and explicitly test ' -- 'for\n' -- 'it in the body of the function, e.g.:\n' -- '\n' -- ' def whats_on_the_telly(penguin=None):\n' -- ' if penguin is None:\n' -- ' penguin = []\n' -- ' penguin.append("property of the zoo")\n' -- ' return penguin\n' -- '\n' -- 'Function call semantics are described in more detail in section ' -- 'Calls.\n' -- 'A function call always assigns values to all parameters ' -- 'mentioned in\n' -- 'the parameter list, either from positional arguments, from ' -- 'keyword\n' -- 'arguments, or from default values. If the form “"*identifier"†' -- 'is\n' -- 'present, it is initialized to a tuple receiving any excess ' -- 'positional\n' -- 'parameters, defaulting to the empty tuple. If the form\n' -- '“"**identifier"†is present, it is initialized to a new ordered\n' -- 'mapping receiving any excess keyword arguments, defaulting to a ' -- 'new\n' -- 'empty mapping of the same type. Parameters after “"*"†or\n' -- '“"*identifier"†are keyword-only parameters and may only be ' -- 'passed by\n' -- 'keyword arguments. Parameters before “"/"†are positional-only\n' -- 'parameters and may only be passed by positional arguments.\n' -- '\n' -- 'Changed in version 3.8: The "/" function parameter syntax may be ' -- 'used\n' -- 'to indicate positional-only parameters. See **PEP 570** for ' -- 'details.\n' -- '\n' -- 'Parameters may have an *annotation* of the form “": ' -- 'expression"â€\n' -- 'following the parameter name. Any parameter may have an ' -- 'annotation,\n' -- 'even those of the form "*identifier" or "**identifier". (As a ' -- 'special\n' -- 'case, parameters of the form "*identifier" may have an ' -- 'annotation “":\n' -- '*expression"â€.) Functions may have “return†annotation of the ' -- 'form\n' -- '“"-> expression"†after the parameter list. These annotations ' -- 'can be\n' -- 'any valid Python expression. The presence of annotations does ' -- 'not\n' -- 'change the semantics of a function. See Annotations for more\n' -- 'information on annotations.\n' -- '\n' -- 'Changed in version 3.11: Parameters of the form “"*identifier"†' -- 'may\n' -- 'have an annotation “": *expression"â€. See **PEP 646**.\n' -- '\n' -- 'It is also possible to create anonymous functions (functions not ' -- 'bound\n' -- 'to a name), for immediate use in expressions. This uses lambda\n' -- 'expressions, described in section Lambdas. Note that the ' -- 'lambda\n' -- 'expression is merely a shorthand for a simplified function ' -- 'definition;\n' -- 'a function defined in a “"def"†statement can be passed around ' -- 'or\n' -- 'assigned to another name just like a function defined by a ' -- 'lambda\n' -- 'expression. The “"def"†form is actually more powerful since ' -- 'it\n' -- 'allows the execution of multiple statements and annotations.\n' -- '\n' -- '**Programmer’s note:** Functions are first-class objects. A ' -- '“"def"â€\n' -- 'statement executed inside a function definition defines a local\n' -- 'function that can be returned or passed around. Free variables ' -- 'used\n' -- 'in the nested function can access the local variables of the ' -- 'function\n' -- 'containing the def. See section Naming and binding for ' -- 'details.\n' -- '\n' -- 'See also:\n' -- '\n' -- ' **PEP 3107** - Function Annotations\n' -- ' The original specification for function annotations.\n' -- '\n' -- ' **PEP 484** - Type Hints\n' -- ' Definition of a standard meaning for annotations: type ' -- 'hints.\n' -- '\n' -- ' **PEP 526** - Syntax for Variable Annotations\n' -- ' Ability to type hint variable declarations, including ' -- 'class\n' -- ' variables and instance variables.\n' -- '\n' -- ' **PEP 563** - Postponed Evaluation of Annotations\n' -- ' Support for forward references within annotations by ' -- 'preserving\n' -- ' annotations in a string form at runtime instead of eager\n' -- ' evaluation.\n' -- '\n' -- ' **PEP 318** - Decorators for Functions and Methods\n' -- ' Function and method decorators were introduced. Class ' -- 'decorators\n' -- ' were introduced in **PEP 3129**.\n', -- 'global': 'The "global" statement\n' -- '**********************\n' -- '\n' -- ' global_stmt ::= "global" identifier ("," identifier)*\n' -- '\n' -- 'The "global" statement causes the listed identifiers to be ' -- 'interpreted\n' -- 'as globals. It would be impossible to assign to a global variable\n' -- 'without "global", although free variables may refer to globals ' -- 'without\n' -- 'being declared global.\n' -- '\n' -- 'The "global" statement applies to the entire scope of a function ' -- 'or\n' -- 'class body. A "SyntaxError" is raised if a variable is used or\n' -- 'assigned to prior to its global declaration in the scope.\n' -- '\n' -- '**Programmer’s note:** "global" is a directive to the parser. It\n' -- 'applies only to code parsed at the same time as the "global"\n' -- 'statement. In particular, a "global" statement contained in a ' -- 'string\n' -- 'or code object supplied to the built-in "exec()" function does ' -- 'not\n' -- 'affect the code block *containing* the function call, and code\n' -- 'contained in such a string is unaffected by "global" statements in ' -- 'the\n' -- 'code containing the function call. The same applies to the ' -- '"eval()"\n' -- 'and "compile()" functions.\n', -- 'id-classes': 'Reserved classes of identifiers\n' -- '*******************************\n' -- '\n' -- 'Certain classes of identifiers (besides keywords) have ' -- 'special\n' -- 'meanings. These classes are identified by the patterns of ' -- 'leading and\n' -- 'trailing underscore characters:\n' -- '\n' -- '"_*"\n' -- ' Not imported by "from module import *".\n' -- '\n' -- '"_"\n' -- ' In a "case" pattern within a "match" statement, "_" is a ' -- 'soft\n' -- ' keyword that denotes a wildcard.\n' -- '\n' -- ' Separately, the interactive interpreter makes the result of ' -- 'the\n' -- ' last evaluation available in the variable "_". (It is ' -- 'stored in the\n' -- ' "builtins" module, alongside built-in functions like ' -- '"print".)\n' -- '\n' -- ' Elsewhere, "_" is a regular identifier. It is often used to ' -- 'name\n' -- ' “special†items, but it is not special to Python itself.\n' -- '\n' -- ' Note:\n' -- '\n' -- ' The name "_" is often used in conjunction with\n' -- ' internationalization; refer to the documentation for the\n' -- ' "gettext" module for more information on this ' -- 'convention.It is\n' -- ' also commonly used for unused variables.\n' -- '\n' -- '"__*__"\n' -- ' System-defined names, informally known as “dunder†names. ' -- 'These\n' -- ' names are defined by the interpreter and its ' -- 'implementation\n' -- ' (including the standard library). Current system names are\n' -- ' discussed in the Special method names section and ' -- 'elsewhere. More\n' -- ' will likely be defined in future versions of Python. *Any* ' -- 'use of\n' -- ' "__*__" names, in any context, that does not follow ' -- 'explicitly\n' -- ' documented use, is subject to breakage without warning.\n' -- '\n' -- '"__*"\n' -- ' Class-private names. Names in this category, when used ' -- 'within the\n' -- ' context of a class definition, are re-written to use a ' -- 'mangled form\n' -- ' to help avoid name clashes between “private†attributes of ' -- 'base and\n' -- ' derived classes. See section Identifiers (Names).\n', -- 'identifiers': 'Identifiers and keywords\n' -- '************************\n' -- '\n' -- 'Identifiers (also referred to as *names*) are described by ' -- 'the\n' -- 'following lexical definitions.\n' -- '\n' -- 'The syntax of identifiers in Python is based on the Unicode ' -- 'standard\n' -- 'annex UAX-31, with elaboration and changes as defined below; ' -- 'see also\n' -- '**PEP 3131** for further details.\n' -- '\n' -- 'Within the ASCII range (U+0001..U+007F), the valid characters ' -- 'for\n' -- 'identifiers include the uppercase and lowercase letters "A" ' -- 'through\n' -- '"Z", the underscore "_" and, except for the first character, ' -- 'the\n' -- 'digits "0" through "9". Python 3.0 introduced additional ' -- 'characters\n' -- 'from outside the ASCII range (see **PEP 3131**). For these\n' -- 'characters, the classification uses the version of the ' -- 'Unicode\n' -- 'Character Database as included in the "unicodedata" module.\n' -- '\n' -- 'Identifiers are unlimited in length. Case is significant.\n' -- '\n' -- ' identifier ::= xid_start xid_continue*\n' -- ' id_start ::= \n' -- ' id_continue ::= \n' -- ' xid_start ::= \n' -- ' xid_continue ::= \n' -- '\n' -- 'The Unicode category codes mentioned above stand for:\n' -- '\n' -- '* *Lu* - uppercase letters\n' -- '\n' -- '* *Ll* - lowercase letters\n' -- '\n' -- '* *Lt* - titlecase letters\n' -- '\n' -- '* *Lm* - modifier letters\n' -- '\n' -- '* *Lo* - other letters\n' -- '\n' -- '* *Nl* - letter numbers\n' -- '\n' -- '* *Mn* - nonspacing marks\n' -- '\n' -- '* *Mc* - spacing combining marks\n' -- '\n' -- '* *Nd* - decimal numbers\n' -- '\n' -- '* *Pc* - connector punctuations\n' -- '\n' -- '* *Other_ID_Start* - explicit list of characters in ' -- 'PropList.txt to\n' -- ' support backwards compatibility\n' -- '\n' -- '* *Other_ID_Continue* - likewise\n' -- '\n' -- 'All identifiers are converted into the normal form NFKC while ' -- 'parsing;\n' -- 'comparison of identifiers is based on NFKC.\n' -- '\n' -- 'A non-normative HTML file listing all valid identifier ' -- 'characters for\n' -- 'Unicode 16.0.0 can be found at\n' -- 'https://www.unicode.org/Public/16.0.0/ucd/DerivedCoreProperties.txt\n' -- '\n' -- '\n' -- 'Keywords\n' -- '========\n' -- '\n' -- 'The following identifiers are used as reserved words, or ' -- '*keywords* of\n' -- 'the language, and cannot be used as ordinary identifiers. ' -- 'They must\n' -- 'be spelled exactly as written here:\n' -- '\n' -- ' False await else import pass\n' -- ' None break except in raise\n' -- ' True class finally is return\n' -- ' and continue for lambda try\n' -- ' as def from nonlocal while\n' -- ' assert del global not with\n' -- ' async elif if or yield\n' -- '\n' -- '\n' -- 'Soft Keywords\n' -- '=============\n' -- '\n' -- 'Added in version 3.10.\n' -- '\n' -- 'Some identifiers are only reserved under specific contexts. ' -- 'These are\n' -- 'known as *soft keywords*. The identifiers "match", "case", ' -- '"type" and\n' -- '"_" can syntactically act as keywords in certain contexts, ' -- 'but this\n' -- 'distinction is done at the parser level, not when ' -- 'tokenizing.\n' -- '\n' -- 'As soft keywords, their use in the grammar is possible while ' -- 'still\n' -- 'preserving compatibility with existing code that uses these ' -- 'names as\n' -- 'identifier names.\n' -- '\n' -- '"match", "case", and "_" are used in the "match" statement. ' -- '"type" is\n' -- 'used in the "type" statement.\n' -- '\n' -- 'Changed in version 3.12: "type" is now a soft keyword.\n' -- '\n' -- '\n' -- 'Reserved classes of identifiers\n' -- '===============================\n' -- '\n' -- 'Certain classes of identifiers (besides keywords) have ' -- 'special\n' -- 'meanings. These classes are identified by the patterns of ' -- 'leading and\n' -- 'trailing underscore characters:\n' -- '\n' -- '"_*"\n' -- ' Not imported by "from module import *".\n' -- '\n' -- '"_"\n' -- ' In a "case" pattern within a "match" statement, "_" is a ' -- 'soft\n' -- ' keyword that denotes a wildcard.\n' -- '\n' -- ' Separately, the interactive interpreter makes the result ' -- 'of the\n' -- ' last evaluation available in the variable "_". (It is ' -- 'stored in the\n' -- ' "builtins" module, alongside built-in functions like ' -- '"print".)\n' -- '\n' -- ' Elsewhere, "_" is a regular identifier. It is often used ' -- 'to name\n' -- ' “special†items, but it is not special to Python itself.\n' -- '\n' -- ' Note:\n' -- '\n' -- ' The name "_" is often used in conjunction with\n' -- ' internationalization; refer to the documentation for ' -- 'the\n' -- ' "gettext" module for more information on this ' -- 'convention.It is\n' -- ' also commonly used for unused variables.\n' -- '\n' -- '"__*__"\n' -- ' System-defined names, informally known as “dunder†names. ' -- 'These\n' -- ' names are defined by the interpreter and its ' -- 'implementation\n' -- ' (including the standard library). Current system names ' -- 'are\n' -- ' discussed in the Special method names section and ' -- 'elsewhere. More\n' -- ' will likely be defined in future versions of Python. ' -- '*Any* use of\n' -- ' "__*__" names, in any context, that does not follow ' -- 'explicitly\n' -- ' documented use, is subject to breakage without warning.\n' -- '\n' -- '"__*"\n' -- ' Class-private names. Names in this category, when used ' -- 'within the\n' -- ' context of a class definition, are re-written to use a ' -- 'mangled form\n' -- ' to help avoid name clashes between “private†attributes of ' -- 'base and\n' -- ' derived classes. See section Identifiers (Names).\n', -- 'if': 'The "if" statement\n' -- '******************\n' -- '\n' -- 'The "if" statement is used for conditional execution:\n' -- '\n' -- ' if_stmt ::= "if" assignment_expression ":" suite\n' -- ' ("elif" assignment_expression ":" suite)*\n' -- ' ["else" ":" suite]\n' -- '\n' -- 'It selects exactly one of the suites by evaluating the expressions ' -- 'one\n' -- 'by one until one is found to be true (see section Boolean operations\n' -- 'for the definition of true and false); then that suite is executed\n' -- '(and no other part of the "if" statement is executed or evaluated).\n' -- 'If all expressions are false, the suite of the "else" clause, if\n' -- 'present, is executed.\n', -- 'imaginary': 'Imaginary literals\n' -- '******************\n' -- '\n' -- 'Imaginary literals are described by the following lexical ' -- 'definitions:\n' -- '\n' -- ' imagnumber ::= (floatnumber | digitpart) ("j" | "J")\n' -- '\n' -- 'An imaginary literal yields a complex number with a real part ' -- 'of 0.0.\n' -- 'Complex numbers are represented as a pair of floating-point ' -- 'numbers\n' -- 'and have the same restrictions on their range. To create a ' -- 'complex\n' -- 'number with a nonzero real part, add a floating-point number to ' -- 'it,\n' -- 'e.g., "(3+4j)". Some examples of imaginary literals:\n' -- '\n' -- ' 3.14j 10.j 10j .001j 1e100j 3.14e-10j ' -- '3.14_15_93j\n', -- 'import': 'The "import" statement\n' -- '**********************\n' -- '\n' -- ' import_stmt ::= "import" module ["as" identifier] ("," ' -- 'module ["as" identifier])*\n' -- ' | "from" relative_module "import" identifier ' -- '["as" identifier]\n' -- ' ("," identifier ["as" identifier])*\n' -- ' | "from" relative_module "import" "(" ' -- 'identifier ["as" identifier]\n' -- ' ("," identifier ["as" identifier])* [","] ")"\n' -- ' | "from" relative_module "import" "*"\n' -- ' module ::= (identifier ".")* identifier\n' -- ' relative_module ::= "."* module | "."+\n' -- '\n' -- 'The basic import statement (no "from" clause) is executed in two\n' -- 'steps:\n' -- '\n' -- '1. find a module, loading and initializing it if necessary\n' -- '\n' -- '2. define a name or names in the local namespace for the scope ' -- 'where\n' -- ' the "import" statement occurs.\n' -- '\n' -- 'When the statement contains multiple clauses (separated by commas) ' -- 'the\n' -- 'two steps are carried out separately for each clause, just as ' -- 'though\n' -- 'the clauses had been separated out into individual import ' -- 'statements.\n' -- '\n' -- 'The details of the first step, finding and loading modules, are\n' -- 'described in greater detail in the section on the import system, ' -- 'which\n' -- 'also describes the various types of packages and modules that can ' -- 'be\n' -- 'imported, as well as all the hooks that can be used to customize ' -- 'the\n' -- 'import system. Note that failures in this step may indicate ' -- 'either\n' -- 'that the module could not be located, *or* that an error occurred\n' -- 'while initializing the module, which includes execution of the\n' -- 'module’s code.\n' -- '\n' -- 'If the requested module is retrieved successfully, it will be ' -- 'made\n' -- 'available in the local namespace in one of three ways:\n' -- '\n' -- '* If the module name is followed by "as", then the name following ' -- '"as"\n' -- ' is bound directly to the imported module.\n' -- '\n' -- '* If no other name is specified, and the module being imported is ' -- 'a\n' -- ' top level module, the module’s name is bound in the local ' -- 'namespace\n' -- ' as a reference to the imported module\n' -- '\n' -- '* If the module being imported is *not* a top level module, then ' -- 'the\n' -- ' name of the top level package that contains the module is bound ' -- 'in\n' -- ' the local namespace as a reference to the top level package. ' -- 'The\n' -- ' imported module must be accessed using its full qualified name\n' -- ' rather than directly\n' -- '\n' -- 'The "from" form uses a slightly more complex process:\n' -- '\n' -- '1. find the module specified in the "from" clause, loading and\n' -- ' initializing it if necessary;\n' -- '\n' -- '2. for each of the identifiers specified in the "import" clauses:\n' -- '\n' -- ' 1. check if the imported module has an attribute by that name\n' -- '\n' -- ' 2. if not, attempt to import a submodule with that name and ' -- 'then\n' -- ' check the imported module again for that attribute\n' -- '\n' -- ' 3. if the attribute is not found, "ImportError" is raised.\n' -- '\n' -- ' 4. otherwise, a reference to that value is stored in the local\n' -- ' namespace, using the name in the "as" clause if it is ' -- 'present,\n' -- ' otherwise using the attribute name\n' -- '\n' -- 'Examples:\n' -- '\n' -- ' import foo # foo imported and bound locally\n' -- ' import foo.bar.baz # foo, foo.bar, and foo.bar.baz ' -- 'imported, foo bound locally\n' -- ' import foo.bar.baz as fbb # foo, foo.bar, and foo.bar.baz ' -- 'imported, foo.bar.baz bound as fbb\n' -- ' from foo.bar import baz # foo, foo.bar, and foo.bar.baz ' -- 'imported, foo.bar.baz bound as baz\n' -- ' from foo import attr # foo imported and foo.attr bound as ' -- 'attr\n' -- '\n' -- 'If the list of identifiers is replaced by a star ("\'*\'"), all ' -- 'public\n' -- 'names defined in the module are bound in the local namespace for ' -- 'the\n' -- 'scope where the "import" statement occurs.\n' -- '\n' -- 'The *public names* defined by a module are determined by checking ' -- 'the\n' -- 'module’s namespace for a variable named "__all__"; if defined, it ' -- 'must\n' -- 'be a sequence of strings which are names defined or imported by ' -- 'that\n' -- 'module. The names given in "__all__" are all considered public ' -- 'and\n' -- 'are required to exist. If "__all__" is not defined, the set of ' -- 'public\n' -- 'names includes all names found in the module’s namespace which do ' -- 'not\n' -- 'begin with an underscore character ("\'_\'"). "__all__" should ' -- 'contain\n' -- 'the entire public API. It is intended to avoid accidentally ' -- 'exporting\n' -- 'items that are not part of the API (such as library modules which ' -- 'were\n' -- 'imported and used within the module).\n' -- '\n' -- 'The wild card form of import — "from module import *" — is only\n' -- 'allowed at the module level. Attempting to use it in class or\n' -- 'function definitions will raise a "SyntaxError".\n' -- '\n' -- 'When specifying what module to import you do not have to specify ' -- 'the\n' -- 'absolute name of the module. When a module or package is ' -- 'contained\n' -- 'within another package it is possible to make a relative import ' -- 'within\n' -- 'the same top package without having to mention the package name. ' -- 'By\n' -- 'using leading dots in the specified module or package after "from" ' -- 'you\n' -- 'can specify how high to traverse up the current package hierarchy\n' -- 'without specifying exact names. One leading dot means the current\n' -- 'package where the module making the import exists. Two dots means ' -- 'up\n' -- 'one package level. Three dots is up two levels, etc. So if you ' -- 'execute\n' -- '"from . import mod" from a module in the "pkg" package then you ' -- 'will\n' -- 'end up importing "pkg.mod". If you execute "from ..subpkg2 import ' -- 'mod"\n' -- 'from within "pkg.subpkg1" you will import "pkg.subpkg2.mod". The\n' -- 'specification for relative imports is contained in the Package\n' -- 'Relative Imports section.\n' -- '\n' -- '"importlib.import_module()" is provided to support applications ' -- 'that\n' -- 'determine dynamically the modules to be loaded.\n' -- '\n' -- 'Raises an auditing event "import" with arguments "module", ' -- '"filename",\n' -- '"sys.path", "sys.meta_path", "sys.path_hooks".\n' -- '\n' -- '\n' -- 'Future statements\n' -- '=================\n' -- '\n' -- 'A *future statement* is a directive to the compiler that a ' -- 'particular\n' -- 'module should be compiled using syntax or semantics that will be\n' -- 'available in a specified future release of Python where the ' -- 'feature\n' -- 'becomes standard.\n' -- '\n' -- 'The future statement is intended to ease migration to future ' -- 'versions\n' -- 'of Python that introduce incompatible changes to the language. ' -- 'It\n' -- 'allows use of the new features on a per-module basis before the\n' -- 'release in which the feature becomes standard.\n' -- '\n' -- ' future_stmt ::= "from" "__future__" "import" feature ["as" ' -- 'identifier]\n' -- ' ("," feature ["as" identifier])*\n' -- ' | "from" "__future__" "import" "(" feature ' -- '["as" identifier]\n' -- ' ("," feature ["as" identifier])* [","] ")"\n' -- ' feature ::= identifier\n' -- '\n' -- 'A future statement must appear near the top of the module. The ' -- 'only\n' -- 'lines that can appear before a future statement are:\n' -- '\n' -- '* the module docstring (if any),\n' -- '\n' -- '* comments,\n' -- '\n' -- '* blank lines, and\n' -- '\n' -- '* other future statements.\n' -- '\n' -- 'The only feature that requires using the future statement is\n' -- '"annotations" (see **PEP 563**).\n' -- '\n' -- 'All historical features enabled by the future statement are still\n' -- 'recognized by Python 3. The list includes "absolute_import",\n' -- '"division", "generators", "generator_stop", "unicode_literals",\n' -- '"print_function", "nested_scopes" and "with_statement". They are ' -- 'all\n' -- 'redundant because they are always enabled, and only kept for ' -- 'backwards\n' -- 'compatibility.\n' -- '\n' -- 'A future statement is recognized and treated specially at compile\n' -- 'time: Changes to the semantics of core constructs are often\n' -- 'implemented by generating different code. It may even be the ' -- 'case\n' -- 'that a new feature introduces new incompatible syntax (such as a ' -- 'new\n' -- 'reserved word), in which case the compiler may need to parse the\n' -- 'module differently. Such decisions cannot be pushed off until\n' -- 'runtime.\n' -- '\n' -- 'For any given release, the compiler knows which feature names ' -- 'have\n' -- 'been defined, and raises a compile-time error if a future ' -- 'statement\n' -- 'contains a feature not known to it.\n' -- '\n' -- 'The direct runtime semantics are the same as for any import ' -- 'statement:\n' -- 'there is a standard module "__future__", described later, and it ' -- 'will\n' -- 'be imported in the usual way at the time the future statement is\n' -- 'executed.\n' -- '\n' -- 'The interesting runtime semantics depend on the specific feature\n' -- 'enabled by the future statement.\n' -- '\n' -- 'Note that there is nothing special about the statement:\n' -- '\n' -- ' import __future__ [as name]\n' -- '\n' -- 'That is not a future statement; it’s an ordinary import statement ' -- 'with\n' -- 'no special semantics or syntax restrictions.\n' -- '\n' -- 'Code compiled by calls to the built-in functions "exec()" and\n' -- '"compile()" that occur in a module "M" containing a future ' -- 'statement\n' -- 'will, by default, use the new syntax or semantics associated with ' -- 'the\n' -- 'future statement. This can be controlled by optional arguments ' -- 'to\n' -- '"compile()" — see the documentation of that function for details.\n' -- '\n' -- 'A future statement typed at an interactive interpreter prompt ' -- 'will\n' -- 'take effect for the rest of the interpreter session. If an\n' -- 'interpreter is started with the "-i" option, is passed a script ' -- 'name\n' -- 'to execute, and the script includes a future statement, it will be ' -- 'in\n' -- 'effect in the interactive session started after the script is\n' -- 'executed.\n' -- '\n' -- 'See also:\n' -- '\n' -- ' **PEP 236** - Back to the __future__\n' -- ' The original proposal for the __future__ mechanism.\n', -- 'in': 'Membership test operations\n' -- '**************************\n' -- '\n' -- 'The operators "in" and "not in" test for membership. "x in s"\n' -- 'evaluates to "True" if *x* is a member of *s*, and "False" otherwise.\n' -- '"x not in s" returns the negation of "x in s". All built-in ' -- 'sequences\n' -- 'and set types support this as well as dictionary, for which "in" ' -- 'tests\n' -- 'whether the dictionary has a given key. For container types such as\n' -- 'list, tuple, set, frozenset, dict, or collections.deque, the\n' -- 'expression "x in y" is equivalent to "any(x is e or x == e for e in\n' -- 'y)".\n' -- '\n' -- 'For the string and bytes types, "x in y" is "True" if and only if *x*\n' -- 'is a substring of *y*. An equivalent test is "y.find(x) != -1".\n' -- 'Empty strings are always considered to be a substring of any other\n' -- 'string, so """ in "abc"" will return "True".\n' -- '\n' -- 'For user-defined classes which define the "__contains__()" method, "x\n' -- 'in y" returns "True" if "y.__contains__(x)" returns a true value, and\n' -- '"False" otherwise.\n' -- '\n' -- 'For user-defined classes which do not define "__contains__()" but do\n' -- 'define "__iter__()", "x in y" is "True" if some value "z", for which\n' -- 'the expression "x is z or x == z" is true, is produced while ' -- 'iterating\n' -- 'over "y". If an exception is raised during the iteration, it is as if\n' -- '"in" raised that exception.\n' -- '\n' -- 'Lastly, the old-style iteration protocol is tried: if a class defines\n' -- '"__getitem__()", "x in y" is "True" if and only if there is a non-\n' -- 'negative integer index *i* such that "x is y[i] or x == y[i]", and no\n' -- 'lower integer index raises the "IndexError" exception. (If any other\n' -- 'exception is raised, it is as if "in" raised that exception).\n' -- '\n' -- 'The operator "not in" is defined to have the inverse truth value of\n' -- '"in".\n', -- 'integers': 'Integer literals\n' -- '****************\n' -- '\n' -- 'Integer literals are described by the following lexical ' -- 'definitions:\n' -- '\n' -- ' integer ::= decinteger | bininteger | octinteger | ' -- 'hexinteger\n' -- ' decinteger ::= nonzerodigit (["_"] digit)* | "0"+ (["_"] ' -- '"0")*\n' -- ' bininteger ::= "0" ("b" | "B") (["_"] bindigit)+\n' -- ' octinteger ::= "0" ("o" | "O") (["_"] octdigit)+\n' -- ' hexinteger ::= "0" ("x" | "X") (["_"] hexdigit)+\n' -- ' nonzerodigit ::= "1"..."9"\n' -- ' digit ::= "0"..."9"\n' -- ' bindigit ::= "0" | "1"\n' -- ' octdigit ::= "0"..."7"\n' -- ' hexdigit ::= digit | "a"..."f" | "A"..."F"\n' -- '\n' -- 'There is no limit for the length of integer literals apart from ' -- 'what\n' -- 'can be stored in available memory.\n' -- '\n' -- 'Underscores are ignored for determining the numeric value of ' -- 'the\n' -- 'literal. They can be used to group digits for enhanced ' -- 'readability.\n' -- 'One underscore can occur between digits, and after base ' -- 'specifiers\n' -- 'like "0x".\n' -- '\n' -- 'Note that leading zeros in a non-zero decimal number are not ' -- 'allowed.\n' -- 'This is for disambiguation with C-style octal literals, which ' -- 'Python\n' -- 'used before version 3.0.\n' -- '\n' -- 'Some examples of integer literals:\n' -- '\n' -- ' 7 2147483647 0o177 0b100110111\n' -- ' 3 79228162514264337593543950336 0o377 0xdeadbeef\n' -- ' 100_000_000_000 0b_1110_0101\n' -- '\n' -- 'Changed in version 3.6: Underscores are now allowed for ' -- 'grouping\n' -- 'purposes in literals.\n', -- 'lambda': 'Lambdas\n' -- '*******\n' -- '\n' -- ' lambda_expr ::= "lambda" [parameter_list] ":" expression\n' -- '\n' -- 'Lambda expressions (sometimes called lambda forms) are used to ' -- 'create\n' -- 'anonymous functions. The expression "lambda parameters: ' -- 'expression"\n' -- 'yields a function object. The unnamed object behaves like a ' -- 'function\n' -- 'object defined with:\n' -- '\n' -- ' def (parameters):\n' -- ' return expression\n' -- '\n' -- 'See section Function definitions for the syntax of parameter ' -- 'lists.\n' -- 'Note that functions created with lambda expressions cannot ' -- 'contain\n' -- 'statements or annotations.\n', -- 'lists': 'List displays\n' -- '*************\n' -- '\n' -- 'A list display is a possibly empty series of expressions enclosed ' -- 'in\n' -- 'square brackets:\n' -- '\n' -- ' list_display ::= "[" [flexible_expression_list | comprehension] ' -- '"]"\n' -- '\n' -- 'A list display yields a new list object, the contents being ' -- 'specified\n' -- 'by either a list of expressions or a comprehension. When a comma-\n' -- 'separated list of expressions is supplied, its elements are ' -- 'evaluated\n' -- 'from left to right and placed into the list object in that order.\n' -- 'When a comprehension is supplied, the list is constructed from the\n' -- 'elements resulting from the comprehension.\n', -- 'naming': 'Naming and binding\n' -- '******************\n' -- '\n' -- '\n' -- 'Binding of names\n' -- '================\n' -- '\n' -- '*Names* refer to objects. Names are introduced by name binding\n' -- 'operations.\n' -- '\n' -- 'The following constructs bind names:\n' -- '\n' -- '* formal parameters to functions,\n' -- '\n' -- '* class definitions,\n' -- '\n' -- '* function definitions,\n' -- '\n' -- '* assignment expressions,\n' -- '\n' -- '* targets that are identifiers if occurring in an assignment:\n' -- '\n' -- ' * "for" loop header,\n' -- '\n' -- ' * after "as" in a "with" statement, "except" clause, "except*"\n' -- ' clause, or in the as-pattern in structural pattern matching,\n' -- '\n' -- ' * in a capture pattern in structural pattern matching\n' -- '\n' -- '* "import" statements.\n' -- '\n' -- '* "type" statements.\n' -- '\n' -- '* type parameter lists.\n' -- '\n' -- 'The "import" statement of the form "from ... import *" binds all ' -- 'names\n' -- 'defined in the imported module, except those beginning with an\n' -- 'underscore. This form may only be used at the module level.\n' -- '\n' -- 'A target occurring in a "del" statement is also considered bound ' -- 'for\n' -- 'this purpose (though the actual semantics are to unbind the ' -- 'name).\n' -- '\n' -- 'Each assignment or import statement occurs within a block defined ' -- 'by a\n' -- 'class or function definition or at the module level (the ' -- 'top-level\n' -- 'code block).\n' -- '\n' -- 'If a name is bound in a block, it is a local variable of that ' -- 'block,\n' -- 'unless declared as "nonlocal" or "global". If a name is bound at ' -- 'the\n' -- 'module level, it is a global variable. (The variables of the ' -- 'module\n' -- 'code block are local and global.) If a variable is used in a ' -- 'code\n' -- 'block but not defined there, it is a *free variable*.\n' -- '\n' -- 'Each occurrence of a name in the program text refers to the ' -- '*binding*\n' -- 'of that name established by the following name resolution rules.\n' -- '\n' -- '\n' -- 'Resolution of names\n' -- '===================\n' -- '\n' -- 'A *scope* defines the visibility of a name within a block. If a ' -- 'local\n' -- 'variable is defined in a block, its scope includes that block. If ' -- 'the\n' -- 'definition occurs in a function block, the scope extends to any ' -- 'blocks\n' -- 'contained within the defining one, unless a contained block ' -- 'introduces\n' -- 'a different binding for the name.\n' -- '\n' -- 'When a name is used in a code block, it is resolved using the ' -- 'nearest\n' -- 'enclosing scope. The set of all such scopes visible to a code ' -- 'block\n' -- 'is called the block’s *environment*.\n' -- '\n' -- 'When a name is not found at all, a "NameError" exception is ' -- 'raised. If\n' -- 'the current scope is a function scope, and the name refers to a ' -- 'local\n' -- 'variable that has not yet been bound to a value at the point where ' -- 'the\n' -- 'name is used, an "UnboundLocalError" exception is raised.\n' -- '"UnboundLocalError" is a subclass of "NameError".\n' -- '\n' -- 'If a name binding operation occurs anywhere within a code block, ' -- 'all\n' -- 'uses of the name within the block are treated as references to ' -- 'the\n' -- 'current block. This can lead to errors when a name is used within ' -- 'a\n' -- 'block before it is bound. This rule is subtle. Python lacks\n' -- 'declarations and allows name binding operations to occur anywhere\n' -- 'within a code block. The local variables of a code block can be\n' -- 'determined by scanning the entire text of the block for name ' -- 'binding\n' -- 'operations. See the FAQ entry on UnboundLocalError for examples.\n' -- '\n' -- 'If the "global" statement occurs within a block, all uses of the ' -- 'names\n' -- 'specified in the statement refer to the bindings of those names in ' -- 'the\n' -- 'top-level namespace. Names are resolved in the top-level ' -- 'namespace by\n' -- 'searching the global namespace, i.e. the namespace of the module\n' -- 'containing the code block, and the builtins namespace, the ' -- 'namespace\n' -- 'of the module "builtins". The global namespace is searched ' -- 'first. If\n' -- 'the names are not found there, the builtins namespace is searched\n' -- 'next. If the names are also not found in the builtins namespace, ' -- 'new\n' -- 'variables are created in the global namespace. The global ' -- 'statement\n' -- 'must precede all uses of the listed names.\n' -- '\n' -- 'The "global" statement has the same scope as a name binding ' -- 'operation\n' -- 'in the same block. If the nearest enclosing scope for a free ' -- 'variable\n' -- 'contains a global statement, the free variable is treated as a ' -- 'global.\n' -- '\n' -- 'The "nonlocal" statement causes corresponding names to refer to\n' -- 'previously bound variables in the nearest enclosing function ' -- 'scope.\n' -- '"SyntaxError" is raised at compile time if the given name does ' -- 'not\n' -- 'exist in any enclosing function scope. Type parameters cannot be\n' -- 'rebound with the "nonlocal" statement.\n' -- '\n' -- 'The namespace for a module is automatically created the first time ' -- 'a\n' -- 'module is imported. The main module for a script is always ' -- 'called\n' -- '"__main__".\n' -- '\n' -- 'Class definition blocks and arguments to "exec()" and "eval()" ' -- 'are\n' -- 'special in the context of name resolution. A class definition is ' -- 'an\n' -- 'executable statement that may use and define names. These ' -- 'references\n' -- 'follow the normal rules for name resolution with an exception ' -- 'that\n' -- 'unbound local variables are looked up in the global namespace. ' -- 'The\n' -- 'namespace of the class definition becomes the attribute dictionary ' -- 'of\n' -- 'the class. The scope of names defined in a class block is limited ' -- 'to\n' -- 'the class block; it does not extend to the code blocks of ' -- 'methods.\n' -- 'This includes comprehensions and generator expressions, but it ' -- 'does\n' -- 'not include annotation scopes, which have access to their ' -- 'enclosing\n' -- 'class scopes. This means that the following will fail:\n' -- '\n' -- ' class A:\n' -- ' a = 42\n' -- ' b = list(a + i for i in range(10))\n' -- '\n' -- 'However, the following will succeed:\n' -- '\n' -- ' class A:\n' -- ' type Alias = Nested\n' -- ' class Nested: pass\n' -- '\n' -- " print(A.Alias.__value__) # \n" -- '\n' -- '\n' -- 'Annotation scopes\n' -- '=================\n' -- '\n' -- '*Annotations*, type parameter lists and "type" statements ' -- 'introduce\n' -- '*annotation scopes*, which behave mostly like function scopes, ' -- 'but\n' -- 'with some exceptions discussed below.\n' -- '\n' -- 'Annotation scopes are used in the following contexts:\n' -- '\n' -- '* *Function annotations*.\n' -- '\n' -- '* *Variable annotations*.\n' -- '\n' -- '* Type parameter lists for generic type aliases.\n' -- '\n' -- '* Type parameter lists for generic functions. A generic ' -- 'function’s\n' -- ' annotations are executed within the annotation scope, but its\n' -- ' defaults and decorators are not.\n' -- '\n' -- '* Type parameter lists for generic classes. A generic class’s ' -- 'base\n' -- ' classes and keyword arguments are executed within the ' -- 'annotation\n' -- ' scope, but its decorators are not.\n' -- '\n' -- '* The bounds, constraints, and default values for type parameters\n' -- ' (lazily evaluated).\n' -- '\n' -- '* The value of type aliases (lazily evaluated).\n' -- '\n' -- 'Annotation scopes differ from function scopes in the following ' -- 'ways:\n' -- '\n' -- '* Annotation scopes have access to their enclosing class ' -- 'namespace. If\n' -- ' an annotation scope is immediately within a class scope, or ' -- 'within\n' -- ' another annotation scope that is immediately within a class ' -- 'scope,\n' -- ' the code in the annotation scope can use names defined in the ' -- 'class\n' -- ' scope as if it were executed directly within the class body. ' -- 'This\n' -- ' contrasts with regular functions defined within classes, which\n' -- ' cannot access names defined in the class scope.\n' -- '\n' -- '* Expressions in annotation scopes cannot contain "yield", "yield\n' -- ' from", "await", or ":=" expressions. (These expressions are ' -- 'allowed\n' -- ' in other scopes contained within the annotation scope.)\n' -- '\n' -- '* Names defined in annotation scopes cannot be rebound with ' -- '"nonlocal"\n' -- ' statements in inner scopes. This includes only type parameters, ' -- 'as\n' -- ' no other syntactic elements that can appear within annotation ' -- 'scopes\n' -- ' can introduce new names.\n' -- '\n' -- '* While annotation scopes have an internal name, that name is not\n' -- ' reflected in the *qualified name* of objects defined within the\n' -- ' scope. Instead, the "__qualname__" of such objects is as if the\n' -- ' object were defined in the enclosing scope.\n' -- '\n' -- 'Added in version 3.12: Annotation scopes were introduced in ' -- 'Python\n' -- '3.12 as part of **PEP 695**.\n' -- '\n' -- 'Changed in version 3.13: Annotation scopes are also used for type\n' -- 'parameter defaults, as introduced by **PEP 696**.\n' -- '\n' -- 'Changed in version 3.14: Annotation scopes are now also used for\n' -- 'annotations, as specified in **PEP 649** and **PEP 749**.\n' -- '\n' -- '\n' -- 'Lazy evaluation\n' -- '===============\n' -- '\n' -- 'Most annotation scopes are *lazily evaluated*. This includes\n' -- 'annotations, the values of type aliases created through the ' -- '"type"\n' -- 'statement, and the bounds, constraints, and default values of ' -- 'type\n' -- 'variables created through the type parameter syntax. This means ' -- 'that\n' -- 'they are not evaluated when the type alias or type variable is\n' -- 'created, or when the object carrying annotations is created. ' -- 'Instead,\n' -- 'they are only evaluated when necessary, for example when the\n' -- '"__value__" attribute on a type alias is accessed.\n' -- '\n' -- 'Example:\n' -- '\n' -- ' >>> type Alias = 1/0\n' -- ' >>> Alias.__value__\n' -- ' Traceback (most recent call last):\n' -- ' ...\n' -- ' ZeroDivisionError: division by zero\n' -- ' >>> def func[T: 1/0](): pass\n' -- ' >>> T = func.__type_params__[0]\n' -- ' >>> T.__bound__\n' -- ' Traceback (most recent call last):\n' -- ' ...\n' -- ' ZeroDivisionError: division by zero\n' -- '\n' -- 'Here the exception is raised only when the "__value__" attribute ' -- 'of\n' -- 'the type alias or the "__bound__" attribute of the type variable ' -- 'is\n' -- 'accessed.\n' -- '\n' -- 'This behavior is primarily useful for references to types that ' -- 'have\n' -- 'not yet been defined when the type alias or type variable is ' -- 'created.\n' -- 'For example, lazy evaluation enables creation of mutually ' -- 'recursive\n' -- 'type aliases:\n' -- '\n' -- ' from typing import Literal\n' -- '\n' -- ' type SimpleExpr = int | Parenthesized\n' -- ' type Parenthesized = tuple[Literal["("], Expr, Literal[")"]]\n' -- ' type Expr = SimpleExpr | tuple[SimpleExpr, Literal["+", "-"], ' -- 'Expr]\n' -- '\n' -- 'Lazily evaluated values are evaluated in annotation scope, which ' -- 'means\n' -- 'that names that appear inside the lazily evaluated value are ' -- 'looked up\n' -- 'as if they were used in the immediately enclosing scope.\n' -- '\n' -- 'Added in version 3.12.\n' -- '\n' -- '\n' -- 'Builtins and restricted execution\n' -- '=================================\n' -- '\n' -- '**CPython implementation detail:** Users should not touch\n' -- '"__builtins__"; it is strictly an implementation detail. Users\n' -- 'wanting to override values in the builtins namespace should ' -- '"import"\n' -- 'the "builtins" module and modify its attributes appropriately.\n' -- '\n' -- 'The builtins namespace associated with the execution of a code ' -- 'block\n' -- 'is actually found by looking up the name "__builtins__" in its ' -- 'global\n' -- 'namespace; this should be a dictionary or a module (in the latter ' -- 'case\n' -- 'the module’s dictionary is used). By default, when in the ' -- '"__main__"\n' -- 'module, "__builtins__" is the built-in module "builtins"; when in ' -- 'any\n' -- 'other module, "__builtins__" is an alias for the dictionary of ' -- 'the\n' -- '"builtins" module itself.\n' -- '\n' -- '\n' -- 'Interaction with dynamic features\n' -- '=================================\n' -- '\n' -- 'Name resolution of free variables occurs at runtime, not at ' -- 'compile\n' -- 'time. This means that the following code will print 42:\n' -- '\n' -- ' i = 10\n' -- ' def f():\n' -- ' print(i)\n' -- ' i = 42\n' -- ' f()\n' -- '\n' -- 'The "eval()" and "exec()" functions do not have access to the ' -- 'full\n' -- 'environment for resolving names. Names may be resolved in the ' -- 'local\n' -- 'and global namespaces of the caller. Free variables are not ' -- 'resolved\n' -- 'in the nearest enclosing namespace, but in the global namespace. ' -- '[1]\n' -- 'The "exec()" and "eval()" functions have optional arguments to\n' -- 'override the global and local namespace. If only one namespace ' -- 'is\n' -- 'specified, it is used for both.\n', -- 'nonlocal': 'The "nonlocal" statement\n' -- '************************\n' -- '\n' -- ' nonlocal_stmt ::= "nonlocal" identifier ("," identifier)*\n' -- '\n' -- 'When the definition of a function or class is nested (enclosed) ' -- 'within\n' -- 'the definitions of other functions, its nonlocal scopes are the ' -- 'local\n' -- 'scopes of the enclosing functions. The "nonlocal" statement ' -- 'causes the\n' -- 'listed identifiers to refer to names previously bound in ' -- 'nonlocal\n' -- 'scopes. It allows encapsulated code to rebind such nonlocal\n' -- 'identifiers. If a name is bound in more than one nonlocal ' -- 'scope, the\n' -- 'nearest binding is used. If a name is not bound in any nonlocal ' -- 'scope,\n' -- 'or if there is no nonlocal scope, a "SyntaxError" is raised.\n' -- '\n' -- 'The "nonlocal" statement applies to the entire scope of a ' -- 'function or\n' -- 'class body. A "SyntaxError" is raised if a variable is used or\n' -- 'assigned to prior to its nonlocal declaration in the scope.\n' -- '\n' -- 'See also:\n' -- '\n' -- ' **PEP 3104** - Access to Names in Outer Scopes\n' -- ' The specification for the "nonlocal" statement.\n' -- '\n' -- '**Programmer’s note:** "nonlocal" is a directive to the parser ' -- 'and\n' -- 'applies only to code parsed along with it. See the note for ' -- 'the\n' -- '"global" statement.\n', -- 'numbers': 'Numeric literals\n' -- '****************\n' -- '\n' -- 'There are three types of numeric literals: integers, ' -- 'floating-point\n' -- 'numbers, and imaginary numbers. There are no complex literals\n' -- '(complex numbers can be formed by adding a real number and an\n' -- 'imaginary number).\n' -- '\n' -- 'Note that numeric literals do not include a sign; a phrase like ' -- '"-1"\n' -- 'is actually an expression composed of the unary operator ‘"-"’ ' -- 'and the\n' -- 'literal "1".\n', -- 'numeric-types': 'Emulating numeric types\n' -- '***********************\n' -- '\n' -- 'The following methods can be defined to emulate numeric ' -- 'objects.\n' -- 'Methods corresponding to operations that are not supported ' -- 'by the\n' -- 'particular kind of number implemented (e.g., bitwise ' -- 'operations for\n' -- 'non-integral numbers) should be left undefined.\n' -- '\n' -- 'object.__add__(self, other)\n' -- 'object.__sub__(self, other)\n' -- 'object.__mul__(self, other)\n' -- 'object.__matmul__(self, other)\n' -- 'object.__truediv__(self, other)\n' -- 'object.__floordiv__(self, other)\n' -- 'object.__mod__(self, other)\n' -- 'object.__divmod__(self, other)\n' -- 'object.__pow__(self, other[, modulo])\n' -- 'object.__lshift__(self, other)\n' -- 'object.__rshift__(self, other)\n' -- 'object.__and__(self, other)\n' -- 'object.__xor__(self, other)\n' -- 'object.__or__(self, other)\n' -- '\n' -- ' These methods are called to implement the binary ' -- 'arithmetic\n' -- ' operations ("+", "-", "*", "@", "/", "//", "%", ' -- '"divmod()",\n' -- ' "pow()", "**", "<<", ">>", "&", "^", "|"). For ' -- 'instance, to\n' -- ' evaluate the expression "x + y", where *x* is an ' -- 'instance of a\n' -- ' class that has an "__add__()" method, ' -- '"type(x).__add__(x, y)" is\n' -- ' called. The "__divmod__()" method should be the ' -- 'equivalent to\n' -- ' using "__floordiv__()" and "__mod__()"; it should not be ' -- 'related to\n' -- ' "__truediv__()". Note that "__pow__()" should be ' -- 'defined to accept\n' -- ' an optional third argument if the ternary version of the ' -- 'built-in\n' -- ' "pow()" function is to be supported.\n' -- '\n' -- ' If one of those methods does not support the operation ' -- 'with the\n' -- ' supplied arguments, it should return "NotImplemented".\n' -- '\n' -- 'object.__radd__(self, other)\n' -- 'object.__rsub__(self, other)\n' -- 'object.__rmul__(self, other)\n' -- 'object.__rmatmul__(self, other)\n' -- 'object.__rtruediv__(self, other)\n' -- 'object.__rfloordiv__(self, other)\n' -- 'object.__rmod__(self, other)\n' -- 'object.__rdivmod__(self, other)\n' -- 'object.__rpow__(self, other[, modulo])\n' -- 'object.__rlshift__(self, other)\n' -- 'object.__rrshift__(self, other)\n' -- 'object.__rand__(self, other)\n' -- 'object.__rxor__(self, other)\n' -- 'object.__ror__(self, other)\n' -- '\n' -- ' These methods are called to implement the binary ' -- 'arithmetic\n' -- ' operations ("+", "-", "*", "@", "/", "//", "%", ' -- '"divmod()",\n' -- ' "pow()", "**", "<<", ">>", "&", "^", "|") with reflected ' -- '(swapped)\n' -- ' operands. These functions are only called if the ' -- 'operands are of\n' -- ' different types, when the left operand does not support ' -- 'the\n' -- ' corresponding operation [3], or the right operand’s ' -- 'class is\n' -- ' derived from the left operand’s class. [4] For instance, ' -- 'to\n' -- ' evaluate the expression "x - y", where *y* is an ' -- 'instance of a\n' -- ' class that has an "__rsub__()" method, ' -- '"type(y).__rsub__(y, x)" is\n' -- ' called if "type(x).__sub__(x, y)" returns ' -- '"NotImplemented" or\n' -- ' "type(y)" is a subclass of "type(x)". [5]\n' -- '\n' -- ' Note that ternary "pow()" will not try calling ' -- '"__rpow__()" (the\n' -- ' coercion rules would become too complicated).\n' -- '\n' -- ' Note:\n' -- '\n' -- ' If the right operand’s type is a subclass of the left ' -- 'operand’s\n' -- ' type and that subclass provides a different ' -- 'implementation of the\n' -- ' reflected method for the operation, this method will ' -- 'be called\n' -- ' before the left operand’s non-reflected method. This ' -- 'behavior\n' -- ' allows subclasses to override their ancestors’ ' -- 'operations.\n' -- '\n' -- 'object.__iadd__(self, other)\n' -- 'object.__isub__(self, other)\n' -- 'object.__imul__(self, other)\n' -- 'object.__imatmul__(self, other)\n' -- 'object.__itruediv__(self, other)\n' -- 'object.__ifloordiv__(self, other)\n' -- 'object.__imod__(self, other)\n' -- 'object.__ipow__(self, other[, modulo])\n' -- 'object.__ilshift__(self, other)\n' -- 'object.__irshift__(self, other)\n' -- 'object.__iand__(self, other)\n' -- 'object.__ixor__(self, other)\n' -- 'object.__ior__(self, other)\n' -- '\n' -- ' These methods are called to implement the augmented ' -- 'arithmetic\n' -- ' assignments ("+=", "-=", "*=", "@=", "/=", "//=", "%=", ' -- '"**=",\n' -- ' "<<=", ">>=", "&=", "^=", "|="). These methods should ' -- 'attempt to\n' -- ' do the operation in-place (modifying *self*) and return ' -- 'the result\n' -- ' (which could be, but does not have to be, *self*). If a ' -- 'specific\n' -- ' method is not defined, or if that method returns ' -- '"NotImplemented",\n' -- ' the augmented assignment falls back to the normal ' -- 'methods. For\n' -- ' instance, if *x* is an instance of a class with an ' -- '"__iadd__()"\n' -- ' method, "x += y" is equivalent to "x = x.__iadd__(y)" . ' -- 'If\n' -- ' "__iadd__()" does not exist, or if "x.__iadd__(y)" ' -- 'returns\n' -- ' "NotImplemented", "x.__add__(y)" and "y.__radd__(x)" ' -- 'are\n' -- ' considered, as with the evaluation of "x + y". In ' -- 'certain\n' -- ' situations, augmented assignment can result in ' -- 'unexpected errors\n' -- ' (see Why does a_tuple[i] += [‘item’] raise an exception ' -- 'when the\n' -- ' addition works?), but this behavior is in fact part of ' -- 'the data\n' -- ' model.\n' -- '\n' -- 'object.__neg__(self)\n' -- 'object.__pos__(self)\n' -- 'object.__abs__(self)\n' -- 'object.__invert__(self)\n' -- '\n' -- ' Called to implement the unary arithmetic operations ' -- '("-", "+",\n' -- ' "abs()" and "~").\n' -- '\n' -- 'object.__complex__(self)\n' -- 'object.__int__(self)\n' -- 'object.__float__(self)\n' -- '\n' -- ' Called to implement the built-in functions "complex()", ' -- '"int()" and\n' -- ' "float()". Should return a value of the appropriate ' -- 'type.\n' -- '\n' -- 'object.__index__(self)\n' -- '\n' -- ' Called to implement "operator.index()", and whenever ' -- 'Python needs\n' -- ' to losslessly convert the numeric object to an integer ' -- 'object (such\n' -- ' as in slicing, or in the built-in "bin()", "hex()" and ' -- '"oct()"\n' -- ' functions). Presence of this method indicates that the ' -- 'numeric\n' -- ' object is an integer type. Must return an integer.\n' -- '\n' -- ' If "__int__()", "__float__()" and "__complex__()" are ' -- 'not defined\n' -- ' then corresponding built-in functions "int()", "float()" ' -- 'and\n' -- ' "complex()" fall back to "__index__()".\n' -- '\n' -- 'object.__round__(self[, ndigits])\n' -- 'object.__trunc__(self)\n' -- 'object.__floor__(self)\n' -- 'object.__ceil__(self)\n' -- '\n' -- ' Called to implement the built-in function "round()" and ' -- '"math"\n' -- ' functions "trunc()", "floor()" and "ceil()". Unless ' -- '*ndigits* is\n' -- ' passed to "__round__()" all these methods should return ' -- 'the value\n' -- ' of the object truncated to an "Integral" (typically an ' -- '"int").\n' -- '\n' -- ' Changed in version 3.14: "int()" no longer delegates to ' -- 'the\n' -- ' "__trunc__()" method.\n', -- 'objects': 'Objects, values and types\n' -- '*************************\n' -- '\n' -- '*Objects* are Python’s abstraction for data. All data in a ' -- 'Python\n' -- 'program is represented by objects or by relations between ' -- 'objects. (In\n' -- 'a sense, and in conformance to Von Neumann’s model of a “stored\n' -- 'program computerâ€, code is also represented by objects.)\n' -- '\n' -- 'Every object has an identity, a type and a value. An object’s\n' -- '*identity* never changes once it has been created; you may think ' -- 'of it\n' -- 'as the object’s address in memory. The "is" operator compares ' -- 'the\n' -- 'identity of two objects; the "id()" function returns an integer\n' -- 'representing its identity.\n' -- '\n' -- '**CPython implementation detail:** For CPython, "id(x)" is the ' -- 'memory\n' -- 'address where "x" is stored.\n' -- '\n' -- 'An object’s type determines the operations that the object ' -- 'supports\n' -- '(e.g., “does it have a length?â€) and also defines the possible ' -- 'values\n' -- 'for objects of that type. The "type()" function returns an ' -- 'object’s\n' -- 'type (which is an object itself). Like its identity, an ' -- 'object’s\n' -- '*type* is also unchangeable. [1]\n' -- '\n' -- 'The *value* of some objects can change. Objects whose value can\n' -- 'change are said to be *mutable*; objects whose value is ' -- 'unchangeable\n' -- 'once they are created are called *immutable*. (The value of an\n' -- 'immutable container object that contains a reference to a ' -- 'mutable\n' -- 'object can change when the latter’s value is changed; however ' -- 'the\n' -- 'container is still considered immutable, because the collection ' -- 'of\n' -- 'objects it contains cannot be changed. So, immutability is not\n' -- 'strictly the same as having an unchangeable value, it is more ' -- 'subtle.)\n' -- 'An object’s mutability is determined by its type; for instance,\n' -- 'numbers, strings and tuples are immutable, while dictionaries ' -- 'and\n' -- 'lists are mutable.\n' -- '\n' -- 'Objects are never explicitly destroyed; however, when they ' -- 'become\n' -- 'unreachable they may be garbage-collected. An implementation is\n' -- 'allowed to postpone garbage collection or omit it altogether — it ' -- 'is a\n' -- 'matter of implementation quality how garbage collection is\n' -- 'implemented, as long as no objects are collected that are still\n' -- 'reachable.\n' -- '\n' -- '**CPython implementation detail:** CPython currently uses a ' -- 'reference-\n' -- 'counting scheme with (optional) delayed detection of cyclically ' -- 'linked\n' -- 'garbage, which collects most objects as soon as they become\n' -- 'unreachable, but is not guaranteed to collect garbage containing\n' -- 'circular references. See the documentation of the "gc" module ' -- 'for\n' -- 'information on controlling the collection of cyclic garbage. ' -- 'Other\n' -- 'implementations act differently and CPython may change. Do not ' -- 'depend\n' -- 'on immediate finalization of objects when they become unreachable ' -- '(so\n' -- 'you should always close files explicitly).\n' -- '\n' -- 'Note that the use of the implementation’s tracing or debugging\n' -- 'facilities may keep objects alive that would normally be ' -- 'collectable.\n' -- 'Also note that catching an exception with a "try"…"except" ' -- 'statement\n' -- 'may keep objects alive.\n' -- '\n' -- 'Some objects contain references to “external†resources such as ' -- 'open\n' -- 'files or windows. It is understood that these resources are ' -- 'freed\n' -- 'when the object is garbage-collected, but since garbage ' -- 'collection is\n' -- 'not guaranteed to happen, such objects also provide an explicit ' -- 'way to\n' -- 'release the external resource, usually a "close()" method. ' -- 'Programs\n' -- 'are strongly recommended to explicitly close such objects. The\n' -- '"try"…"finally" statement and the "with" statement provide ' -- 'convenient\n' -- 'ways to do this.\n' -- '\n' -- 'Some objects contain references to other objects; these are ' -- 'called\n' -- '*containers*. Examples of containers are tuples, lists and\n' -- 'dictionaries. The references are part of a container’s value. ' -- 'In\n' -- 'most cases, when we talk about the value of a container, we imply ' -- 'the\n' -- 'values, not the identities of the contained objects; however, ' -- 'when we\n' -- 'talk about the mutability of a container, only the identities of ' -- 'the\n' -- 'immediately contained objects are implied. So, if an immutable\n' -- 'container (like a tuple) contains a reference to a mutable ' -- 'object, its\n' -- 'value changes if that mutable object is changed.\n' -- '\n' -- 'Types affect almost all aspects of object behavior. Even the\n' -- 'importance of object identity is affected in some sense: for ' -- 'immutable\n' -- 'types, operations that compute new values may actually return a\n' -- 'reference to any existing object with the same type and value, ' -- 'while\n' -- 'for mutable objects this is not allowed. For example, after "a = ' -- '1; b\n' -- '= 1", *a* and *b* may or may not refer to the same object with ' -- 'the\n' -- 'value one, depending on the implementation. This is because "int" ' -- 'is\n' -- 'an immutable type, so the reference to "1" can be reused. This\n' -- 'behaviour depends on the implementation used, so should not be ' -- 'relied\n' -- 'upon, but is something to be aware of when making use of object\n' -- 'identity tests. However, after "c = []; d = []", *c* and *d* are\n' -- 'guaranteed to refer to two different, unique, newly created ' -- 'empty\n' -- 'lists. (Note that "e = f = []" assigns the *same* object to both ' -- '*e*\n' -- 'and *f*.)\n', -- 'operator-summary': 'Operator precedence\n' -- '*******************\n' -- '\n' -- 'The following table summarizes the operator precedence ' -- 'in Python, from\n' -- 'highest precedence (most binding) to lowest precedence ' -- '(least\n' -- 'binding). Operators in the same box have the same ' -- 'precedence. Unless\n' -- 'the syntax is explicitly given, operators are binary. ' -- 'Operators in\n' -- 'the same box group left to right (except for ' -- 'exponentiation and\n' -- 'conditional expressions, which group from right to ' -- 'left).\n' -- '\n' -- 'Note that comparisons, membership tests, and identity ' -- 'tests, all have\n' -- 'the same precedence and have a left-to-right chaining ' -- 'feature as\n' -- 'described in the Comparisons section.\n' -- '\n' -- '+-------------------------------------------------+---------------------------------------+\n' -- '| Operator | ' -- 'Description |\n' -- '|=================================================|=======================================|\n' -- '| "(expressions...)", "[expressions...]", "{key: | ' -- 'Binding or parenthesized expression, |\n' -- '| value...}", "{expressions...}" | list ' -- 'display, dictionary display, set |\n' -- '| | ' -- 'display |\n' -- '+-------------------------------------------------+---------------------------------------+\n' -- '| "x[index]", "x[index:index]", | ' -- 'Subscription, slicing, call, |\n' -- '| "x(arguments...)", "x.attribute" | ' -- 'attribute reference |\n' -- '+-------------------------------------------------+---------------------------------------+\n' -- '| "await x" | ' -- 'Await expression |\n' -- '+-------------------------------------------------+---------------------------------------+\n' -- '| "**" | ' -- 'Exponentiation [5] |\n' -- '+-------------------------------------------------+---------------------------------------+\n' -- '| "+x", "-x", "~x" | ' -- 'Positive, negative, bitwise NOT |\n' -- '+-------------------------------------------------+---------------------------------------+\n' -- '| "*", "@", "/", "//", "%" | ' -- 'Multiplication, matrix |\n' -- '| | ' -- 'multiplication, division, floor |\n' -- '| | ' -- 'division, remainder [6] |\n' -- '+-------------------------------------------------+---------------------------------------+\n' -- '| "+", "-" | ' -- 'Addition and subtraction |\n' -- '+-------------------------------------------------+---------------------------------------+\n' -- '| "<<", ">>" | ' -- 'Shifts |\n' -- '+-------------------------------------------------+---------------------------------------+\n' -- '| "&" | ' -- 'Bitwise AND |\n' -- '+-------------------------------------------------+---------------------------------------+\n' -- '| "^" | ' -- 'Bitwise XOR |\n' -- '+-------------------------------------------------+---------------------------------------+\n' -- '| "|" | ' -- 'Bitwise OR |\n' -- '+-------------------------------------------------+---------------------------------------+\n' -- '| "in", "not in", "is", "is not", "<", "<=", ">", | ' -- 'Comparisons, including membership |\n' -- '| ">=", "!=", "==" | ' -- 'tests and identity tests |\n' -- '+-------------------------------------------------+---------------------------------------+\n' -- '| "not x" | ' -- 'Boolean NOT |\n' -- '+-------------------------------------------------+---------------------------------------+\n' -- '| "and" | ' -- 'Boolean AND |\n' -- '+-------------------------------------------------+---------------------------------------+\n' -- '| "or" | ' -- 'Boolean OR |\n' -- '+-------------------------------------------------+---------------------------------------+\n' -- '| "if" – "else" | ' -- 'Conditional expression |\n' -- '+-------------------------------------------------+---------------------------------------+\n' -- '| "lambda" | ' -- 'Lambda expression |\n' -- '+-------------------------------------------------+---------------------------------------+\n' -- '| ":=" | ' -- 'Assignment expression |\n' -- '+-------------------------------------------------+---------------------------------------+\n' -- '\n' -- '-[ Footnotes ]-\n' -- '\n' -- '[1] While "abs(x%y) < abs(y)" is true mathematically, ' -- 'for floats it\n' -- ' may not be true numerically due to roundoff. For ' -- 'example, and\n' -- ' assuming a platform on which a Python float is an ' -- 'IEEE 754 double-\n' -- ' precision number, in order that "-1e-100 % 1e100" ' -- 'have the same\n' -- ' sign as "1e100", the computed result is "-1e-100 + ' -- '1e100", which\n' -- ' is numerically exactly equal to "1e100". The ' -- 'function\n' -- ' "math.fmod()" returns a result whose sign matches ' -- 'the sign of the\n' -- ' first argument instead, and so returns "-1e-100" in ' -- 'this case.\n' -- ' Which approach is more appropriate depends on the ' -- 'application.\n' -- '\n' -- '[2] If x is very close to an exact integer multiple of ' -- 'y, it’s\n' -- ' possible for "x//y" to be one larger than ' -- '"(x-x%y)//y" due to\n' -- ' rounding. In such cases, Python returns the latter ' -- 'result, in\n' -- ' order to preserve that "divmod(x,y)[0] * y + x % y" ' -- 'be very close\n' -- ' to "x".\n' -- '\n' -- '[3] The Unicode standard distinguishes between *code ' -- 'points* (e.g.\n' -- ' U+0041) and *abstract characters* (e.g. “LATIN ' -- 'CAPITAL LETTER Aâ€).\n' -- ' While most abstract characters in Unicode are only ' -- 'represented\n' -- ' using one code point, there is a number of abstract ' -- 'characters\n' -- ' that can in addition be represented using a sequence ' -- 'of more than\n' -- ' one code point. For example, the abstract character ' -- '“LATIN\n' -- ' CAPITAL LETTER C WITH CEDILLA†can be represented as ' -- 'a single\n' -- ' *precomposed character* at code position U+00C7, or ' -- 'as a sequence\n' -- ' of a *base character* at code position U+0043 (LATIN ' -- 'CAPITAL\n' -- ' LETTER C), followed by a *combining character* at ' -- 'code position\n' -- ' U+0327 (COMBINING CEDILLA).\n' -- '\n' -- ' The comparison operators on strings compare at the ' -- 'level of\n' -- ' Unicode code points. This may be counter-intuitive ' -- 'to humans. For\n' -- ' example, ""\\u00C7" == "\\u0043\\u0327"" is "False", ' -- 'even though both\n' -- ' strings represent the same abstract character “LATIN ' -- 'CAPITAL\n' -- ' LETTER C WITH CEDILLAâ€.\n' -- '\n' -- ' To compare strings at the level of abstract ' -- 'characters (that is,\n' -- ' in a way intuitive to humans), use ' -- '"unicodedata.normalize()".\n' -- '\n' -- '[4] Due to automatic garbage-collection, free lists, and ' -- 'the dynamic\n' -- ' nature of descriptors, you may notice seemingly ' -- 'unusual behaviour\n' -- ' in certain uses of the "is" operator, like those ' -- 'involving\n' -- ' comparisons between instance methods, or constants. ' -- 'Check their\n' -- ' documentation for more info.\n' -- '\n' -- '[5] The power operator "**" binds less tightly than an ' -- 'arithmetic or\n' -- ' bitwise unary operator on its right, that is, ' -- '"2**-1" is "0.5".\n' -- '\n' -- '[6] The "%" operator is also used for string formatting; ' -- 'the same\n' -- ' precedence applies.\n', -- 'pass': 'The "pass" statement\n' -- '********************\n' -- '\n' -- ' pass_stmt ::= "pass"\n' -- '\n' -- '"pass" is a null operation — when it is executed, nothing happens. ' -- 'It\n' -- 'is useful as a placeholder when a statement is required ' -- 'syntactically,\n' -- 'but no code needs to be executed, for example:\n' -- '\n' -- ' def f(arg): pass # a function that does nothing (yet)\n' -- '\n' -- ' class C: pass # a class with no methods (yet)\n', -- 'power': 'The power operator\n' -- '******************\n' -- '\n' -- 'The power operator binds more tightly than unary operators on its\n' -- 'left; it binds less tightly than unary operators on its right. ' -- 'The\n' -- 'syntax is:\n' -- '\n' -- ' power ::= (await_expr | primary) ["**" u_expr]\n' -- '\n' -- 'Thus, in an unparenthesized sequence of power and unary operators, ' -- 'the\n' -- 'operators are evaluated from right to left (this does not ' -- 'constrain\n' -- 'the evaluation order for the operands): "-1**2" results in "-1".\n' -- '\n' -- 'The power operator has the same semantics as the built-in "pow()"\n' -- 'function, when called with two arguments: it yields its left ' -- 'argument\n' -- 'raised to the power of its right argument. The numeric arguments ' -- 'are\n' -- 'first converted to a common type, and the result is of that type.\n' -- '\n' -- 'For int operands, the result has the same type as the operands ' -- 'unless\n' -- 'the second argument is negative; in that case, all arguments are\n' -- 'converted to float and a float result is delivered. For example,\n' -- '"10**2" returns "100", but "10**-2" returns "0.01".\n' -- '\n' -- 'Raising "0.0" to a negative power results in a ' -- '"ZeroDivisionError".\n' -- 'Raising a negative number to a fractional power results in a ' -- '"complex"\n' -- 'number. (In earlier versions it raised a "ValueError".)\n' -- '\n' -- 'This operation can be customized using the special "__pow__()" and\n' -- '"__rpow__()" methods.\n', -- 'raise': 'The "raise" statement\n' -- '*********************\n' -- '\n' -- ' raise_stmt ::= "raise" [expression ["from" expression]]\n' -- '\n' -- 'If no expressions are present, "raise" re-raises the exception that ' -- 'is\n' -- 'currently being handled, which is also known as the *active\n' -- 'exception*. If there isn’t currently an active exception, a\n' -- '"RuntimeError" exception is raised indicating that this is an ' -- 'error.\n' -- '\n' -- 'Otherwise, "raise" evaluates the first expression as the exception\n' -- 'object. It must be either a subclass or an instance of\n' -- '"BaseException". If it is a class, the exception instance will be\n' -- 'obtained when needed by instantiating the class with no arguments.\n' -- '\n' -- 'The *type* of the exception is the exception instance’s class, the\n' -- '*value* is the instance itself.\n' -- '\n' -- 'A traceback object is normally created automatically when an ' -- 'exception\n' -- 'is raised and attached to it as the "__traceback__" attribute. You ' -- 'can\n' -- 'create an exception and set your own traceback in one step using ' -- 'the\n' -- '"with_traceback()" exception method (which returns the same ' -- 'exception\n' -- 'instance, with its traceback set to its argument), like so:\n' -- '\n' -- ' raise Exception("foo occurred").with_traceback(tracebackobj)\n' -- '\n' -- 'The "from" clause is used for exception chaining: if given, the ' -- 'second\n' -- '*expression* must be another exception class or instance. If the\n' -- 'second expression is an exception instance, it will be attached to ' -- 'the\n' -- 'raised exception as the "__cause__" attribute (which is writable). ' -- 'If\n' -- 'the expression is an exception class, the class will be ' -- 'instantiated\n' -- 'and the resulting exception instance will be attached to the ' -- 'raised\n' -- 'exception as the "__cause__" attribute. If the raised exception is ' -- 'not\n' -- 'handled, both exceptions will be printed:\n' -- '\n' -- ' >>> try:\n' -- ' ... print(1 / 0)\n' -- ' ... except Exception as exc:\n' -- ' ... raise RuntimeError("Something bad happened") from exc\n' -- ' ...\n' -- ' Traceback (most recent call last):\n' -- ' File "", line 2, in \n' -- ' print(1 / 0)\n' -- ' ~~^~~\n' -- ' ZeroDivisionError: division by zero\n' -- '\n' -- ' The above exception was the direct cause of the following ' -- 'exception:\n' -- '\n' -- ' Traceback (most recent call last):\n' -- ' File "", line 4, in \n' -- ' raise RuntimeError("Something bad happened") from exc\n' -- ' RuntimeError: Something bad happened\n' -- '\n' -- 'A similar mechanism works implicitly if a new exception is raised ' -- 'when\n' -- 'an exception is already being handled. An exception may be ' -- 'handled\n' -- 'when an "except" or "finally" clause, or a "with" statement, is ' -- 'used.\n' -- 'The previous exception is then attached as the new exception’s\n' -- '"__context__" attribute:\n' -- '\n' -- ' >>> try:\n' -- ' ... print(1 / 0)\n' -- ' ... except:\n' -- ' ... raise RuntimeError("Something bad happened")\n' -- ' ...\n' -- ' Traceback (most recent call last):\n' -- ' File "", line 2, in \n' -- ' print(1 / 0)\n' -- ' ~~^~~\n' -- ' ZeroDivisionError: division by zero\n' -- '\n' -- ' During handling of the above exception, another exception ' -- 'occurred:\n' -- '\n' -- ' Traceback (most recent call last):\n' -- ' File "", line 4, in \n' -- ' raise RuntimeError("Something bad happened")\n' -- ' RuntimeError: Something bad happened\n' -- '\n' -- 'Exception chaining can be explicitly suppressed by specifying ' -- '"None"\n' -- 'in the "from" clause:\n' -- '\n' -- ' >>> try:\n' -- ' ... print(1 / 0)\n' -- ' ... except:\n' -- ' ... raise RuntimeError("Something bad happened") from None\n' -- ' ...\n' -- ' Traceback (most recent call last):\n' -- ' File "", line 4, in \n' -- ' RuntimeError: Something bad happened\n' -- '\n' -- 'Additional information on exceptions can be found in section\n' -- 'Exceptions, and information about handling exceptions is in ' -- 'section\n' -- 'The try statement.\n' -- '\n' -- 'Changed in version 3.3: "None" is now permitted as "Y" in "raise X\n' -- 'from Y".Added the "__suppress_context__" attribute to suppress\n' -- 'automatic display of the exception context.\n' -- '\n' -- 'Changed in version 3.11: If the traceback of the active exception ' -- 'is\n' -- 'modified in an "except" clause, a subsequent "raise" statement re-\n' -- 'raises the exception with the modified traceback. Previously, the\n' -- 'exception was re-raised with the traceback it had when it was ' -- 'caught.\n', -- 'return': 'The "return" statement\n' -- '**********************\n' -- '\n' -- ' return_stmt ::= "return" [expression_list]\n' -- '\n' -- '"return" may only occur syntactically nested in a function ' -- 'definition,\n' -- 'not within a nested class definition.\n' -- '\n' -- 'If an expression list is present, it is evaluated, else "None" is\n' -- 'substituted.\n' -- '\n' -- '"return" leaves the current function call with the expression list ' -- '(or\n' -- '"None") as return value.\n' -- '\n' -- 'When "return" passes control out of a "try" statement with a ' -- '"finally"\n' -- 'clause, that "finally" clause is executed before really leaving ' -- 'the\n' -- 'function.\n' -- '\n' -- 'In a generator function, the "return" statement indicates that ' -- 'the\n' -- 'generator is done and will cause "StopIteration" to be raised. ' -- 'The\n' -- 'returned value (if any) is used as an argument to construct\n' -- '"StopIteration" and becomes the "StopIteration.value" attribute.\n' -- '\n' -- 'In an asynchronous generator function, an empty "return" ' -- 'statement\n' -- 'indicates that the asynchronous generator is done and will cause\n' -- '"StopAsyncIteration" to be raised. A non-empty "return" statement ' -- 'is\n' -- 'a syntax error in an asynchronous generator function.\n', -- 'sequence-types': 'Emulating container types\n' -- '*************************\n' -- '\n' -- 'The following methods can be defined to implement ' -- 'container objects.\n' -- 'None of them are provided by the "object" class itself. ' -- 'Containers\n' -- 'usually are *sequences* (such as "lists" or "tuples") or ' -- '*mappings*\n' -- '(like *dictionaries*), but can represent other containers ' -- 'as well.\n' -- 'The first set of methods is used either to emulate a ' -- 'sequence or to\n' -- 'emulate a mapping; the difference is that for a sequence, ' -- 'the\n' -- 'allowable keys should be the integers *k* for which "0 <= ' -- 'k < N" where\n' -- '*N* is the length of the sequence, or "slice" objects, ' -- 'which define a\n' -- 'range of items. It is also recommended that mappings ' -- 'provide the\n' -- 'methods "keys()", "values()", "items()", "get()", ' -- '"clear()",\n' -- '"setdefault()", "pop()", "popitem()", "copy()", and ' -- '"update()"\n' -- 'behaving similar to those for Python’s standard ' -- '"dictionary" objects.\n' -- 'The "collections.abc" module provides a "MutableMapping" ' -- '*abstract\n' -- 'base class* to help create those methods from a base set ' -- 'of\n' -- '"__getitem__()", "__setitem__()", "__delitem__()", and ' -- '"keys()".\n' -- 'Mutable sequences should provide methods "append()", ' -- '"count()",\n' -- '"index()", "extend()", "insert()", "pop()", "remove()", ' -- '"reverse()"\n' -- 'and "sort()", like Python standard "list" objects. ' -- 'Finally, sequence\n' -- 'types should implement addition (meaning concatenation) ' -- 'and\n' -- 'multiplication (meaning repetition) by defining the ' -- 'methods\n' -- '"__add__()", "__radd__()", "__iadd__()", "__mul__()", ' -- '"__rmul__()" and\n' -- '"__imul__()" described below; they should not define other ' -- 'numerical\n' -- 'operators. It is recommended that both mappings and ' -- 'sequences\n' -- 'implement the "__contains__()" method to allow efficient ' -- 'use of the\n' -- '"in" operator; for mappings, "in" should search the ' -- 'mapping’s keys;\n' -- 'for sequences, it should search through the values. It is ' -- 'further\n' -- 'recommended that both mappings and sequences implement ' -- 'the\n' -- '"__iter__()" method to allow efficient iteration through ' -- 'the\n' -- 'container; for mappings, "__iter__()" should iterate ' -- 'through the\n' -- 'object’s keys; for sequences, it should iterate through ' -- 'the values.\n' -- '\n' -- 'object.__len__(self)\n' -- '\n' -- ' Called to implement the built-in function "len()". ' -- 'Should return\n' -- ' the length of the object, an integer ">=" 0. Also, an ' -- 'object that\n' -- ' doesn’t define a "__bool__()" method and whose ' -- '"__len__()" method\n' -- ' returns zero is considered to be false in a Boolean ' -- 'context.\n' -- '\n' -- ' **CPython implementation detail:** In CPython, the ' -- 'length is\n' -- ' required to be at most "sys.maxsize". If the length is ' -- 'larger than\n' -- ' "sys.maxsize" some features (such as "len()") may ' -- 'raise\n' -- ' "OverflowError". To prevent raising "OverflowError" by ' -- 'truth value\n' -- ' testing, an object must define a "__bool__()" method.\n' -- '\n' -- 'object.__length_hint__(self)\n' -- '\n' -- ' Called to implement "operator.length_hint()". Should ' -- 'return an\n' -- ' estimated length for the object (which may be greater ' -- 'or less than\n' -- ' the actual length). The length must be an integer ">=" ' -- '0. The\n' -- ' return value may also be "NotImplemented", which is ' -- 'treated the\n' -- ' same as if the "__length_hint__" method didn’t exist at ' -- 'all. This\n' -- ' method is purely an optimization and is never required ' -- 'for\n' -- ' correctness.\n' -- '\n' -- ' Added in version 3.4.\n' -- '\n' -- 'Note:\n' -- '\n' -- ' Slicing is done exclusively with the following three ' -- 'methods. A\n' -- ' call like\n' -- '\n' -- ' a[1:2] = b\n' -- '\n' -- ' is translated to\n' -- '\n' -- ' a[slice(1, 2, None)] = b\n' -- '\n' -- ' and so forth. Missing slice items are always filled in ' -- 'with "None".\n' -- '\n' -- 'object.__getitem__(self, key)\n' -- '\n' -- ' Called to implement evaluation of "self[key]". For ' -- '*sequence*\n' -- ' types, the accepted keys should be integers. ' -- 'Optionally, they may\n' -- ' support "slice" objects as well. Negative index ' -- 'support is also\n' -- ' optional. If *key* is of an inappropriate type, ' -- '"TypeError" may be\n' -- ' raised; if *key* is a value outside the set of indexes ' -- 'for the\n' -- ' sequence (after any special interpretation of negative ' -- 'values),\n' -- ' "IndexError" should be raised. For *mapping* types, if ' -- '*key* is\n' -- ' missing (not in the container), "KeyError" should be ' -- 'raised.\n' -- '\n' -- ' Note:\n' -- '\n' -- ' "for" loops expect that an "IndexError" will be ' -- 'raised for\n' -- ' illegal indexes to allow proper detection of the end ' -- 'of the\n' -- ' sequence.\n' -- '\n' -- ' Note:\n' -- '\n' -- ' When subscripting a *class*, the special class ' -- 'method\n' -- ' "__class_getitem__()" may be called instead of ' -- '"__getitem__()".\n' -- ' See __class_getitem__ versus __getitem__ for more ' -- 'details.\n' -- '\n' -- 'object.__setitem__(self, key, value)\n' -- '\n' -- ' Called to implement assignment to "self[key]". Same ' -- 'note as for\n' -- ' "__getitem__()". This should only be implemented for ' -- 'mappings if\n' -- ' the objects support changes to the values for keys, or ' -- 'if new keys\n' -- ' can be added, or for sequences if elements can be ' -- 'replaced. The\n' -- ' same exceptions should be raised for improper *key* ' -- 'values as for\n' -- ' the "__getitem__()" method.\n' -- '\n' -- 'object.__delitem__(self, key)\n' -- '\n' -- ' Called to implement deletion of "self[key]". Same note ' -- 'as for\n' -- ' "__getitem__()". This should only be implemented for ' -- 'mappings if\n' -- ' the objects support removal of keys, or for sequences ' -- 'if elements\n' -- ' can be removed from the sequence. The same exceptions ' -- 'should be\n' -- ' raised for improper *key* values as for the ' -- '"__getitem__()" method.\n' -- '\n' -- 'object.__missing__(self, key)\n' -- '\n' -- ' Called by "dict"."__getitem__()" to implement ' -- '"self[key]" for dict\n' -- ' subclasses when key is not in the dictionary.\n' -- '\n' -- 'object.__iter__(self)\n' -- '\n' -- ' This method is called when an *iterator* is required ' -- 'for a\n' -- ' container. This method should return a new iterator ' -- 'object that can\n' -- ' iterate over all the objects in the container. For ' -- 'mappings, it\n' -- ' should iterate over the keys of the container.\n' -- '\n' -- 'object.__reversed__(self)\n' -- '\n' -- ' Called (if present) by the "reversed()" built-in to ' -- 'implement\n' -- ' reverse iteration. It should return a new iterator ' -- 'object that\n' -- ' iterates over all the objects in the container in ' -- 'reverse order.\n' -- '\n' -- ' If the "__reversed__()" method is not provided, the ' -- '"reversed()"\n' -- ' built-in will fall back to using the sequence protocol ' -- '("__len__()"\n' -- ' and "__getitem__()"). Objects that support the ' -- 'sequence protocol\n' -- ' should only provide "__reversed__()" if they can ' -- 'provide an\n' -- ' implementation that is more efficient than the one ' -- 'provided by\n' -- ' "reversed()".\n' -- '\n' -- 'The membership test operators ("in" and "not in") are ' -- 'normally\n' -- 'implemented as an iteration through a container. However, ' -- 'container\n' -- 'objects can supply the following special method with a ' -- 'more efficient\n' -- 'implementation, which also does not require the object be ' -- 'iterable.\n' -- '\n' -- 'object.__contains__(self, item)\n' -- '\n' -- ' Called to implement membership test operators. Should ' -- 'return true\n' -- ' if *item* is in *self*, false otherwise. For mapping ' -- 'objects, this\n' -- ' should consider the keys of the mapping rather than the ' -- 'values or\n' -- ' the key-item pairs.\n' -- '\n' -- ' For objects that don’t define "__contains__()", the ' -- 'membership test\n' -- ' first tries iteration via "__iter__()", then the old ' -- 'sequence\n' -- ' iteration protocol via "__getitem__()", see this ' -- 'section in the\n' -- ' language reference.\n', -- 'shifting': 'Shifting operations\n' -- '*******************\n' -- '\n' -- 'The shifting operations have lower priority than the arithmetic\n' -- 'operations:\n' -- '\n' -- ' shift_expr ::= a_expr | shift_expr ("<<" | ">>") a_expr\n' -- '\n' -- 'These operators accept integers as arguments. They shift the ' -- 'first\n' -- 'argument to the left or right by the number of bits given by ' -- 'the\n' -- 'second argument.\n' -- '\n' -- 'The left shift operation can be customized using the special\n' -- '"__lshift__()" and "__rlshift__()" methods. The right shift ' -- 'operation\n' -- 'can be customized using the special "__rshift__()" and ' -- '"__rrshift__()"\n' -- 'methods.\n' -- '\n' -- 'A right shift by *n* bits is defined as floor division by ' -- '"pow(2,n)".\n' -- 'A left shift by *n* bits is defined as multiplication with ' -- '"pow(2,n)".\n', -- 'slicings': 'Slicings\n' -- '********\n' -- '\n' -- 'A slicing selects a range of items in a sequence object (e.g., ' -- 'a\n' -- 'string, tuple or list). Slicings may be used as expressions or ' -- 'as\n' -- 'targets in assignment or "del" statements. The syntax for a ' -- 'slicing:\n' -- '\n' -- ' slicing ::= primary "[" slice_list "]"\n' -- ' slice_list ::= slice_item ("," slice_item)* [","]\n' -- ' slice_item ::= expression | proper_slice\n' -- ' proper_slice ::= [lower_bound] ":" [upper_bound] [ ":" ' -- '[stride] ]\n' -- ' lower_bound ::= expression\n' -- ' upper_bound ::= expression\n' -- ' stride ::= expression\n' -- '\n' -- 'There is ambiguity in the formal syntax here: anything that ' -- 'looks like\n' -- 'an expression list also looks like a slice list, so any ' -- 'subscription\n' -- 'can be interpreted as a slicing. Rather than further ' -- 'complicating the\n' -- 'syntax, this is disambiguated by defining that in this case the\n' -- 'interpretation as a subscription takes priority over the\n' -- 'interpretation as a slicing (this is the case if the slice list\n' -- 'contains no proper slice).\n' -- '\n' -- 'The semantics for a slicing are as follows. The primary is ' -- 'indexed\n' -- '(using the same "__getitem__()" method as normal subscription) ' -- 'with a\n' -- 'key that is constructed from the slice list, as follows. If the ' -- 'slice\n' -- 'list contains at least one comma, the key is a tuple containing ' -- 'the\n' -- 'conversion of the slice items; otherwise, the conversion of the ' -- 'lone\n' -- 'slice item is the key. The conversion of a slice item that is ' -- 'an\n' -- 'expression is that expression. The conversion of a proper slice ' -- 'is a\n' -- 'slice object (see section The standard type hierarchy) whose ' -- '"start",\n' -- '"stop" and "step" attributes are the values of the expressions ' -- 'given\n' -- 'as lower bound, upper bound and stride, respectively, ' -- 'substituting\n' -- '"None" for missing expressions.\n', -- 'specialattrs': 'Special Attributes\n' -- '******************\n' -- '\n' -- 'The implementation adds a few special read-only attributes ' -- 'to several\n' -- 'object types, where they are relevant. Some of these are ' -- 'not reported\n' -- 'by the "dir()" built-in function.\n' -- '\n' -- 'definition.__name__\n' -- '\n' -- ' The name of the class, function, method, descriptor, or ' -- 'generator\n' -- ' instance.\n' -- '\n' -- 'definition.__qualname__\n' -- '\n' -- ' The *qualified name* of the class, function, method, ' -- 'descriptor, or\n' -- ' generator instance.\n' -- '\n' -- ' Added in version 3.3.\n' -- '\n' -- 'definition.__module__\n' -- '\n' -- ' The name of the module in which a class or function was ' -- 'defined.\n' -- '\n' -- 'definition.__doc__\n' -- '\n' -- ' The documentation string of a class or function, or ' -- '"None" if\n' -- ' undefined.\n' -- '\n' -- 'definition.__type_params__\n' -- '\n' -- ' The type parameters of generic classes, functions, and ' -- 'type\n' -- ' aliases. For classes and functions that are not generic, ' -- 'this will\n' -- ' be an empty tuple.\n' -- '\n' -- ' Added in version 3.12.\n', -- 'specialnames': 'Special method names\n' -- '********************\n' -- '\n' -- 'A class can implement certain operations that are invoked by ' -- 'special\n' -- 'syntax (such as arithmetic operations or subscripting and ' -- 'slicing) by\n' -- 'defining methods with special names. This is Python’s ' -- 'approach to\n' -- '*operator overloading*, allowing classes to define their own ' -- 'behavior\n' -- 'with respect to language operators. For instance, if a ' -- 'class defines\n' -- 'a method named "__getitem__()", and "x" is an instance of ' -- 'this class,\n' -- 'then "x[i]" is roughly equivalent to "type(x).__getitem__(x, ' -- 'i)".\n' -- 'Except where mentioned, attempts to execute an operation ' -- 'raise an\n' -- 'exception when no appropriate method is defined (typically\n' -- '"AttributeError" or "TypeError").\n' -- '\n' -- 'Setting a special method to "None" indicates that the ' -- 'corresponding\n' -- 'operation is not available. For example, if a class sets ' -- '"__iter__()"\n' -- 'to "None", the class is not iterable, so calling "iter()" on ' -- 'its\n' -- 'instances will raise a "TypeError" (without falling back to\n' -- '"__getitem__()"). [2]\n' -- '\n' -- 'When implementing a class that emulates any built-in type, ' -- 'it is\n' -- 'important that the emulation only be implemented to the ' -- 'degree that it\n' -- 'makes sense for the object being modelled. For example, ' -- 'some\n' -- 'sequences may work well with retrieval of individual ' -- 'elements, but\n' -- 'extracting a slice may not make sense. (One example of this ' -- 'is the\n' -- '"NodeList" interface in the W3C’s Document Object Model.)\n' -- '\n' -- '\n' -- 'Basic customization\n' -- '===================\n' -- '\n' -- 'object.__new__(cls[, ...])\n' -- '\n' -- ' Called to create a new instance of class *cls*. ' -- '"__new__()" is a\n' -- ' static method (special-cased so you need not declare it ' -- 'as such)\n' -- ' that takes the class of which an instance was requested ' -- 'as its\n' -- ' first argument. The remaining arguments are those passed ' -- 'to the\n' -- ' object constructor expression (the call to the class). ' -- 'The return\n' -- ' value of "__new__()" should be the new object instance ' -- '(usually an\n' -- ' instance of *cls*).\n' -- '\n' -- ' Typical implementations create a new instance of the ' -- 'class by\n' -- ' invoking the superclass’s "__new__()" method using\n' -- ' "super().__new__(cls[, ...])" with appropriate arguments ' -- 'and then\n' -- ' modifying the newly created instance as necessary before ' -- 'returning\n' -- ' it.\n' -- '\n' -- ' If "__new__()" is invoked during object construction and ' -- 'it returns\n' -- ' an instance of *cls*, then the new instance’s ' -- '"__init__()" method\n' -- ' will be invoked like "__init__(self[, ...])", where ' -- '*self* is the\n' -- ' new instance and the remaining arguments are the same as ' -- 'were\n' -- ' passed to the object constructor.\n' -- '\n' -- ' If "__new__()" does not return an instance of *cls*, then ' -- 'the new\n' -- ' instance’s "__init__()" method will not be invoked.\n' -- '\n' -- ' "__new__()" is intended mainly to allow subclasses of ' -- 'immutable\n' -- ' types (like int, str, or tuple) to customize instance ' -- 'creation. It\n' -- ' is also commonly overridden in custom metaclasses in ' -- 'order to\n' -- ' customize class creation.\n' -- '\n' -- 'object.__init__(self[, ...])\n' -- '\n' -- ' Called after the instance has been created (by ' -- '"__new__()"), but\n' -- ' before it is returned to the caller. The arguments are ' -- 'those\n' -- ' passed to the class constructor expression. If a base ' -- 'class has an\n' -- ' "__init__()" method, the derived class’s "__init__()" ' -- 'method, if\n' -- ' any, must explicitly call it to ensure proper ' -- 'initialization of the\n' -- ' base class part of the instance; for example:\n' -- ' "super().__init__([args...])".\n' -- '\n' -- ' Because "__new__()" and "__init__()" work together in ' -- 'constructing\n' -- ' objects ("__new__()" to create it, and "__init__()" to ' -- 'customize\n' -- ' it), no non-"None" value may be returned by "__init__()"; ' -- 'doing so\n' -- ' will cause a "TypeError" to be raised at runtime.\n' -- '\n' -- 'object.__del__(self)\n' -- '\n' -- ' Called when the instance is about to be destroyed. This ' -- 'is also\n' -- ' called a finalizer or (improperly) a destructor. If a ' -- 'base class\n' -- ' has a "__del__()" method, the derived class’s "__del__()" ' -- 'method,\n' -- ' if any, must explicitly call it to ensure proper deletion ' -- 'of the\n' -- ' base class part of the instance.\n' -- '\n' -- ' It is possible (though not recommended!) for the ' -- '"__del__()" method\n' -- ' to postpone destruction of the instance by creating a new ' -- 'reference\n' -- ' to it. This is called object *resurrection*. It is\n' -- ' implementation-dependent whether "__del__()" is called a ' -- 'second\n' -- ' time when a resurrected object is about to be destroyed; ' -- 'the\n' -- ' current *CPython* implementation only calls it once.\n' -- '\n' -- ' It is not guaranteed that "__del__()" methods are called ' -- 'for\n' -- ' objects that still exist when the interpreter exits.\n' -- ' "weakref.finalize" provides a straightforward way to ' -- 'register a\n' -- ' cleanup function to be called when an object is garbage ' -- 'collected.\n' -- '\n' -- ' Note:\n' -- '\n' -- ' "del x" doesn’t directly call "x.__del__()" — the ' -- 'former\n' -- ' decrements the reference count for "x" by one, and the ' -- 'latter is\n' -- ' only called when "x"’s reference count reaches zero.\n' -- '\n' -- ' **CPython implementation detail:** It is possible for a ' -- 'reference\n' -- ' cycle to prevent the reference count of an object from ' -- 'going to\n' -- ' zero. In this case, the cycle will be later detected and ' -- 'deleted\n' -- ' by the *cyclic garbage collector*. A common cause of ' -- 'reference\n' -- ' cycles is when an exception has been caught in a local ' -- 'variable.\n' -- ' The frame’s locals then reference the exception, which ' -- 'references\n' -- ' its own traceback, which references the locals of all ' -- 'frames caught\n' -- ' in the traceback.\n' -- '\n' -- ' See also: Documentation for the "gc" module.\n' -- '\n' -- ' Warning:\n' -- '\n' -- ' Due to the precarious circumstances under which ' -- '"__del__()"\n' -- ' methods are invoked, exceptions that occur during their ' -- 'execution\n' -- ' are ignored, and a warning is printed to "sys.stderr" ' -- 'instead.\n' -- ' In particular:\n' -- '\n' -- ' * "__del__()" can be invoked when arbitrary code is ' -- 'being\n' -- ' executed, including from any arbitrary thread. If ' -- '"__del__()"\n' -- ' needs to take a lock or invoke any other blocking ' -- 'resource, it\n' -- ' may deadlock as the resource may already be taken by ' -- 'the code\n' -- ' that gets interrupted to execute "__del__()".\n' -- '\n' -- ' * "__del__()" can be executed during interpreter ' -- 'shutdown. As a\n' -- ' consequence, the global variables it needs to access ' -- '(including\n' -- ' other modules) may already have been deleted or set ' -- 'to "None".\n' -- ' Python guarantees that globals whose name begins with ' -- 'a single\n' -- ' underscore are deleted from their module before other ' -- 'globals\n' -- ' are deleted; if no other references to such globals ' -- 'exist, this\n' -- ' may help in assuring that imported modules are still ' -- 'available\n' -- ' at the time when the "__del__()" method is called.\n' -- '\n' -- 'object.__repr__(self)\n' -- '\n' -- ' Called by the "repr()" built-in function to compute the ' -- '“officialâ€\n' -- ' string representation of an object. If at all possible, ' -- 'this\n' -- ' should look like a valid Python expression that could be ' -- 'used to\n' -- ' recreate an object with the same value (given an ' -- 'appropriate\n' -- ' environment). If this is not possible, a string of the ' -- 'form\n' -- ' "<...some useful description...>" should be returned. The ' -- 'return\n' -- ' value must be a string object. If a class defines ' -- '"__repr__()" but\n' -- ' not "__str__()", then "__repr__()" is also used when an ' -- '“informalâ€\n' -- ' string representation of instances of that class is ' -- 'required.\n' -- '\n' -- ' This is typically used for debugging, so it is important ' -- 'that the\n' -- ' representation is information-rich and unambiguous. A ' -- 'default\n' -- ' implementation is provided by the "object" class itself.\n' -- '\n' -- 'object.__str__(self)\n' -- '\n' -- ' Called by "str(object)", the default "__format__()" ' -- 'implementation,\n' -- ' and the built-in function "print()", to compute the ' -- '“informal†or\n' -- ' nicely printable string representation of an object. The ' -- 'return\n' -- ' value must be a str object.\n' -- '\n' -- ' This method differs from "object.__repr__()" in that ' -- 'there is no\n' -- ' expectation that "__str__()" return a valid Python ' -- 'expression: a\n' -- ' more convenient or concise representation can be used.\n' -- '\n' -- ' The default implementation defined by the built-in type ' -- '"object"\n' -- ' calls "object.__repr__()".\n' -- '\n' -- 'object.__bytes__(self)\n' -- '\n' -- ' Called by bytes to compute a byte-string representation ' -- 'of an\n' -- ' object. This should return a "bytes" object. The "object" ' -- 'class\n' -- ' itself does not provide this method.\n' -- '\n' -- 'object.__format__(self, format_spec)\n' -- '\n' -- ' Called by the "format()" built-in function, and by ' -- 'extension,\n' -- ' evaluation of formatted string literals and the ' -- '"str.format()"\n' -- ' method, to produce a “formatted†string representation of ' -- 'an\n' -- ' object. The *format_spec* argument is a string that ' -- 'contains a\n' -- ' description of the formatting options desired. The ' -- 'interpretation\n' -- ' of the *format_spec* argument is up to the type ' -- 'implementing\n' -- ' "__format__()", however most classes will either ' -- 'delegate\n' -- ' formatting to one of the built-in types, or use a ' -- 'similar\n' -- ' formatting option syntax.\n' -- '\n' -- ' See Format Specification Mini-Language for a description ' -- 'of the\n' -- ' standard formatting syntax.\n' -- '\n' -- ' The return value must be a string object.\n' -- '\n' -- ' The default implementation by the "object" class should ' -- 'be given an\n' -- ' empty *format_spec* string. It delegates to "__str__()".\n' -- '\n' -- ' Changed in version 3.4: The __format__ method of "object" ' -- 'itself\n' -- ' raises a "TypeError" if passed any non-empty string.\n' -- '\n' -- ' Changed in version 3.7: "object.__format__(x, \'\')" is ' -- 'now\n' -- ' equivalent to "str(x)" rather than "format(str(x), ' -- '\'\')".\n' -- '\n' -- 'object.__lt__(self, other)\n' -- 'object.__le__(self, other)\n' -- 'object.__eq__(self, other)\n' -- 'object.__ne__(self, other)\n' -- 'object.__gt__(self, other)\n' -- 'object.__ge__(self, other)\n' -- '\n' -- ' These are the so-called “rich comparison†methods. The\n' -- ' correspondence between operator symbols and method names ' -- 'is as\n' -- ' follows: "xy" calls\n' -- ' "x.__gt__(y)", and "x>=y" calls "x.__ge__(y)".\n' -- '\n' -- ' A rich comparison method may return the singleton ' -- '"NotImplemented"\n' -- ' if it does not implement the operation for a given pair ' -- 'of\n' -- ' arguments. By convention, "False" and "True" are returned ' -- 'for a\n' -- ' successful comparison. However, these methods can return ' -- 'any value,\n' -- ' so if the comparison operator is used in a Boolean ' -- 'context (e.g.,\n' -- ' in the condition of an "if" statement), Python will call ' -- '"bool()"\n' -- ' on the value to determine if the result is true or ' -- 'false.\n' -- '\n' -- ' By default, "object" implements "__eq__()" by using "is", ' -- 'returning\n' -- ' "NotImplemented" in the case of a false comparison: "True ' -- 'if x is y\n' -- ' else NotImplemented". For "__ne__()", by default it ' -- 'delegates to\n' -- ' "__eq__()" and inverts the result unless it is ' -- '"NotImplemented".\n' -- ' There are no other implied relationships among the ' -- 'comparison\n' -- ' operators or default implementations; for example, the ' -- 'truth of\n' -- ' "(x.__hash__".\n' -- '\n' -- ' If a class that does not override "__eq__()" wishes to ' -- 'suppress\n' -- ' hash support, it should include "__hash__ = None" in the ' -- 'class\n' -- ' definition. A class which defines its own "__hash__()" ' -- 'that\n' -- ' explicitly raises a "TypeError" would be incorrectly ' -- 'identified as\n' -- ' hashable by an "isinstance(obj, ' -- 'collections.abc.Hashable)" call.\n' -- '\n' -- ' Note:\n' -- '\n' -- ' By default, the "__hash__()" values of str and bytes ' -- 'objects are\n' -- ' “salted†with an unpredictable random value. Although ' -- 'they\n' -- ' remain constant within an individual Python process, ' -- 'they are not\n' -- ' predictable between repeated invocations of Python.This ' -- 'is\n' -- ' intended to provide protection against a ' -- 'denial-of-service caused\n' -- ' by carefully chosen inputs that exploit the worst case\n' -- ' performance of a dict insertion, *O*(*n*^2) ' -- 'complexity. See\n' -- ' http://ocert.org/advisories/ocert-2011-003.html for\n' -- ' details.Changing hash values affects the iteration ' -- 'order of sets.\n' -- ' Python has never made guarantees about this ordering ' -- '(and it\n' -- ' typically varies between 32-bit and 64-bit builds).See ' -- 'also\n' -- ' "PYTHONHASHSEED".\n' -- '\n' -- ' Changed in version 3.3: Hash randomization is enabled by ' -- 'default.\n' -- '\n' -- 'object.__bool__(self)\n' -- '\n' -- ' Called to implement truth value testing and the built-in ' -- 'operation\n' -- ' "bool()"; should return "False" or "True". When this ' -- 'method is not\n' -- ' defined, "__len__()" is called, if it is defined, and the ' -- 'object is\n' -- ' considered true if its result is nonzero. If a class ' -- 'defines\n' -- ' neither "__len__()" nor "__bool__()" (which is true of ' -- 'the "object"\n' -- ' class itself), all its instances are considered true.\n' -- '\n' -- '\n' -- 'Customizing attribute access\n' -- '============================\n' -- '\n' -- 'The following methods can be defined to customize the ' -- 'meaning of\n' -- 'attribute access (use of, assignment to, or deletion of ' -- '"x.name") for\n' -- 'class instances.\n' -- '\n' -- 'object.__getattr__(self, name)\n' -- '\n' -- ' Called when the default attribute access fails with an\n' -- ' "AttributeError" (either "__getattribute__()" raises an\n' -- ' "AttributeError" because *name* is not an instance ' -- 'attribute or an\n' -- ' attribute in the class tree for "self"; or "__get__()" of ' -- 'a *name*\n' -- ' property raises "AttributeError"). This method should ' -- 'either\n' -- ' return the (computed) attribute value or raise an ' -- '"AttributeError"\n' -- ' exception. The "object" class itself does not provide ' -- 'this method.\n' -- '\n' -- ' Note that if the attribute is found through the normal ' -- 'mechanism,\n' -- ' "__getattr__()" is not called. (This is an intentional ' -- 'asymmetry\n' -- ' between "__getattr__()" and "__setattr__()".) This is ' -- 'done both for\n' -- ' efficiency reasons and because otherwise "__getattr__()" ' -- 'would have\n' -- ' no way to access other attributes of the instance. Note ' -- 'that at\n' -- ' least for instance variables, you can take total control ' -- 'by not\n' -- ' inserting any values in the instance attribute dictionary ' -- '(but\n' -- ' instead inserting them in another object). See the\n' -- ' "__getattribute__()" method below for a way to actually ' -- 'get total\n' -- ' control over attribute access.\n' -- '\n' -- 'object.__getattribute__(self, name)\n' -- '\n' -- ' Called unconditionally to implement attribute accesses ' -- 'for\n' -- ' instances of the class. If the class also defines ' -- '"__getattr__()",\n' -- ' the latter will not be called unless "__getattribute__()" ' -- 'either\n' -- ' calls it explicitly or raises an "AttributeError". This ' -- 'method\n' -- ' should return the (computed) attribute value or raise an\n' -- ' "AttributeError" exception. In order to avoid infinite ' -- 'recursion in\n' -- ' this method, its implementation should always call the ' -- 'base class\n' -- ' method with the same name to access any attributes it ' -- 'needs, for\n' -- ' example, "object.__getattribute__(self, name)".\n' -- '\n' -- ' Note:\n' -- '\n' -- ' This method may still be bypassed when looking up ' -- 'special methods\n' -- ' as the result of implicit invocation via language ' -- 'syntax or\n' -- ' built-in functions. See Special method lookup.\n' -- '\n' -- ' For certain sensitive attribute accesses, raises an ' -- 'auditing event\n' -- ' "object.__getattr__" with arguments "obj" and "name".\n' -- '\n' -- 'object.__setattr__(self, name, value)\n' -- '\n' -- ' Called when an attribute assignment is attempted. This ' -- 'is called\n' -- ' instead of the normal mechanism (i.e. store the value in ' -- 'the\n' -- ' instance dictionary). *name* is the attribute name, ' -- '*value* is the\n' -- ' value to be assigned to it.\n' -- '\n' -- ' If "__setattr__()" wants to assign to an instance ' -- 'attribute, it\n' -- ' should call the base class method with the same name, for ' -- 'example,\n' -- ' "object.__setattr__(self, name, value)".\n' -- '\n' -- ' For certain sensitive attribute assignments, raises an ' -- 'auditing\n' -- ' event "object.__setattr__" with arguments "obj", "name", ' -- '"value".\n' -- '\n' -- 'object.__delattr__(self, name)\n' -- '\n' -- ' Like "__setattr__()" but for attribute deletion instead ' -- 'of\n' -- ' assignment. This should only be implemented if "del ' -- 'obj.name" is\n' -- ' meaningful for the object.\n' -- '\n' -- ' For certain sensitive attribute deletions, raises an ' -- 'auditing event\n' -- ' "object.__delattr__" with arguments "obj" and "name".\n' -- '\n' -- 'object.__dir__(self)\n' -- '\n' -- ' Called when "dir()" is called on the object. An iterable ' -- 'must be\n' -- ' returned. "dir()" converts the returned iterable to a ' -- 'list and\n' -- ' sorts it.\n' -- '\n' -- '\n' -- 'Customizing module attribute access\n' -- '-----------------------------------\n' -- '\n' -- 'Special names "__getattr__" and "__dir__" can be also used ' -- 'to\n' -- 'customize access to module attributes. The "__getattr__" ' -- 'function at\n' -- 'the module level should accept one argument which is the ' -- 'name of an\n' -- 'attribute and return the computed value or raise an ' -- '"AttributeError".\n' -- 'If an attribute is not found on a module object through the ' -- 'normal\n' -- 'lookup, i.e. "object.__getattribute__()", then "__getattr__" ' -- 'is\n' -- 'searched in the module "__dict__" before raising an ' -- '"AttributeError".\n' -- 'If found, it is called with the attribute name and the ' -- 'result is\n' -- 'returned.\n' -- '\n' -- 'The "__dir__" function should accept no arguments, and ' -- 'return an\n' -- 'iterable of strings that represents the names accessible on ' -- 'module. If\n' -- 'present, this function overrides the standard "dir()" search ' -- 'on a\n' -- 'module.\n' -- '\n' -- 'For a more fine grained customization of the module behavior ' -- '(setting\n' -- 'attributes, properties, etc.), one can set the "__class__" ' -- 'attribute\n' -- 'of a module object to a subclass of "types.ModuleType". For ' -- 'example:\n' -- '\n' -- ' import sys\n' -- ' from types import ModuleType\n' -- '\n' -- ' class VerboseModule(ModuleType):\n' -- ' def __repr__(self):\n' -- " return f'Verbose {self.__name__}'\n" -- '\n' -- ' def __setattr__(self, attr, value):\n' -- " print(f'Setting {attr}...')\n" -- ' super().__setattr__(attr, value)\n' -- '\n' -- ' sys.modules[__name__].__class__ = VerboseModule\n' -- '\n' -- 'Note:\n' -- '\n' -- ' Defining module "__getattr__" and setting module ' -- '"__class__" only\n' -- ' affect lookups made using the attribute access syntax – ' -- 'directly\n' -- ' accessing the module globals (whether by code within the ' -- 'module, or\n' -- ' via a reference to the module’s globals dictionary) is ' -- 'unaffected.\n' -- '\n' -- 'Changed in version 3.5: "__class__" module attribute is now ' -- 'writable.\n' -- '\n' -- 'Added in version 3.7: "__getattr__" and "__dir__" module ' -- 'attributes.\n' -- '\n' -- 'See also:\n' -- '\n' -- ' **PEP 562** - Module __getattr__ and __dir__\n' -- ' Describes the "__getattr__" and "__dir__" functions on ' -- 'modules.\n' -- '\n' -- '\n' -- 'Implementing Descriptors\n' -- '------------------------\n' -- '\n' -- 'The following methods only apply when an instance of the ' -- 'class\n' -- 'containing the method (a so-called *descriptor* class) ' -- 'appears in an\n' -- '*owner* class (the descriptor must be in either the owner’s ' -- 'class\n' -- 'dictionary or in the class dictionary for one of its ' -- 'parents). In the\n' -- 'examples below, “the attribute†refers to the attribute ' -- 'whose name is\n' -- 'the key of the property in the owner class’ "__dict__". The ' -- '"object"\n' -- 'class itself does not implement any of these protocols.\n' -- '\n' -- 'object.__get__(self, instance, owner=None)\n' -- '\n' -- ' Called to get the attribute of the owner class (class ' -- 'attribute\n' -- ' access) or of an instance of that class (instance ' -- 'attribute\n' -- ' access). The optional *owner* argument is the owner ' -- 'class, while\n' -- ' *instance* is the instance that the attribute was ' -- 'accessed through,\n' -- ' or "None" when the attribute is accessed through the ' -- '*owner*.\n' -- '\n' -- ' This method should return the computed attribute value or ' -- 'raise an\n' -- ' "AttributeError" exception.\n' -- '\n' -- ' **PEP 252** specifies that "__get__()" is callable with ' -- 'one or two\n' -- ' arguments. Python’s own built-in descriptors support ' -- 'this\n' -- ' specification; however, it is likely that some ' -- 'third-party tools\n' -- ' have descriptors that require both arguments. Python’s ' -- 'own\n' -- ' "__getattribute__()" implementation always passes in both ' -- 'arguments\n' -- ' whether they are required or not.\n' -- '\n' -- 'object.__set__(self, instance, value)\n' -- '\n' -- ' Called to set the attribute on an instance *instance* of ' -- 'the owner\n' -- ' class to a new value, *value*.\n' -- '\n' -- ' Note, adding "__set__()" or "__delete__()" changes the ' -- 'kind of\n' -- ' descriptor to a “data descriptorâ€. See Invoking ' -- 'Descriptors for\n' -- ' more details.\n' -- '\n' -- 'object.__delete__(self, instance)\n' -- '\n' -- ' Called to delete the attribute on an instance *instance* ' -- 'of the\n' -- ' owner class.\n' -- '\n' -- 'Instances of descriptors may also have the "__objclass__" ' -- 'attribute\n' -- 'present:\n' -- '\n' -- 'object.__objclass__\n' -- '\n' -- ' The attribute "__objclass__" is interpreted by the ' -- '"inspect" module\n' -- ' as specifying the class where this object was defined ' -- '(setting this\n' -- ' appropriately can assist in runtime introspection of ' -- 'dynamic class\n' -- ' attributes). For callables, it may indicate that an ' -- 'instance of the\n' -- ' given type (or a subclass) is expected or required as the ' -- 'first\n' -- ' positional argument (for example, CPython sets this ' -- 'attribute for\n' -- ' unbound methods that are implemented in C).\n' -- '\n' -- '\n' -- 'Invoking Descriptors\n' -- '--------------------\n' -- '\n' -- 'In general, a descriptor is an object attribute with ' -- '“binding\n' -- 'behaviorâ€, one whose attribute access has been overridden by ' -- 'methods\n' -- 'in the descriptor protocol: "__get__()", "__set__()", and\n' -- '"__delete__()". If any of those methods are defined for an ' -- 'object, it\n' -- 'is said to be a descriptor.\n' -- '\n' -- 'The default behavior for attribute access is to get, set, or ' -- 'delete\n' -- 'the attribute from an object’s dictionary. For instance, ' -- '"a.x" has a\n' -- 'lookup chain starting with "a.__dict__[\'x\']", then\n' -- '"type(a).__dict__[\'x\']", and continuing through the base ' -- 'classes of\n' -- '"type(a)" excluding metaclasses.\n' -- '\n' -- 'However, if the looked-up value is an object defining one of ' -- 'the\n' -- 'descriptor methods, then Python may override the default ' -- 'behavior and\n' -- 'invoke the descriptor method instead. Where this occurs in ' -- 'the\n' -- 'precedence chain depends on which descriptor methods were ' -- 'defined and\n' -- 'how they were called.\n' -- '\n' -- 'The starting point for descriptor invocation is a binding, ' -- '"a.x". How\n' -- 'the arguments are assembled depends on "a":\n' -- '\n' -- 'Direct Call\n' -- ' The simplest and least common call is when user code ' -- 'directly\n' -- ' invokes a descriptor method: "x.__get__(a)".\n' -- '\n' -- 'Instance Binding\n' -- ' If binding to an object instance, "a.x" is transformed ' -- 'into the\n' -- ' call: "type(a).__dict__[\'x\'].__get__(a, type(a))".\n' -- '\n' -- 'Class Binding\n' -- ' If binding to a class, "A.x" is transformed into the ' -- 'call:\n' -- ' "A.__dict__[\'x\'].__get__(None, A)".\n' -- '\n' -- 'Super Binding\n' -- ' A dotted lookup such as "super(A, a).x" searches\n' -- ' "a.__class__.__mro__" for a base class "B" following "A" ' -- 'and then\n' -- ' returns "B.__dict__[\'x\'].__get__(a, A)". If not a ' -- 'descriptor, "x"\n' -- ' is returned unchanged.\n' -- '\n' -- 'For instance bindings, the precedence of descriptor ' -- 'invocation depends\n' -- 'on which descriptor methods are defined. A descriptor can ' -- 'define any\n' -- 'combination of "__get__()", "__set__()" and "__delete__()". ' -- 'If it\n' -- 'does not define "__get__()", then accessing the attribute ' -- 'will return\n' -- 'the descriptor object itself unless there is a value in the ' -- 'object’s\n' -- 'instance dictionary. If the descriptor defines "__set__()" ' -- 'and/or\n' -- '"__delete__()", it is a data descriptor; if it defines ' -- 'neither, it is\n' -- 'a non-data descriptor. Normally, data descriptors define ' -- 'both\n' -- '"__get__()" and "__set__()", while non-data descriptors have ' -- 'just the\n' -- '"__get__()" method. Data descriptors with "__get__()" and ' -- '"__set__()"\n' -- '(and/or "__delete__()") defined always override a ' -- 'redefinition in an\n' -- 'instance dictionary. In contrast, non-data descriptors can ' -- 'be\n' -- 'overridden by instances.\n' -- '\n' -- 'Python methods (including those decorated with ' -- '"@staticmethod" and\n' -- '"@classmethod") are implemented as non-data descriptors. ' -- 'Accordingly,\n' -- 'instances can redefine and override methods. This allows ' -- 'individual\n' -- 'instances to acquire behaviors that differ from other ' -- 'instances of the\n' -- 'same class.\n' -- '\n' -- 'The "property()" function is implemented as a data ' -- 'descriptor.\n' -- 'Accordingly, instances cannot override the behavior of a ' -- 'property.\n' -- '\n' -- '\n' -- '__slots__\n' -- '---------\n' -- '\n' -- '*__slots__* allow us to explicitly declare data members ' -- '(like\n' -- 'properties) and deny the creation of "__dict__" and ' -- '*__weakref__*\n' -- '(unless explicitly declared in *__slots__* or available in a ' -- 'parent.)\n' -- '\n' -- 'The space saved over using "__dict__" can be significant. ' -- 'Attribute\n' -- 'lookup speed can be significantly improved as well.\n' -- '\n' -- 'object.__slots__\n' -- '\n' -- ' This class variable can be assigned a string, iterable, ' -- 'or sequence\n' -- ' of strings with variable names used by instances. ' -- '*__slots__*\n' -- ' reserves space for the declared variables and prevents ' -- 'the\n' -- ' automatic creation of "__dict__" and *__weakref__* for ' -- 'each\n' -- ' instance.\n' -- '\n' -- 'Notes on using *__slots__*:\n' -- '\n' -- '* When inheriting from a class without *__slots__*, the ' -- '"__dict__" and\n' -- ' *__weakref__* attribute of the instances will always be ' -- 'accessible.\n' -- '\n' -- '* Without a "__dict__" variable, instances cannot be ' -- 'assigned new\n' -- ' variables not listed in the *__slots__* definition. ' -- 'Attempts to\n' -- ' assign to an unlisted variable name raises ' -- '"AttributeError". If\n' -- ' dynamic assignment of new variables is desired, then add\n' -- ' "\'__dict__\'" to the sequence of strings in the ' -- '*__slots__*\n' -- ' declaration.\n' -- '\n' -- '* Without a *__weakref__* variable for each instance, ' -- 'classes defining\n' -- ' *__slots__* do not support "weak references" to its ' -- 'instances. If\n' -- ' weak reference support is needed, then add ' -- '"\'__weakref__\'" to the\n' -- ' sequence of strings in the *__slots__* declaration.\n' -- '\n' -- '* *__slots__* are implemented at the class level by ' -- 'creating\n' -- ' descriptors for each variable name. As a result, class ' -- 'attributes\n' -- ' cannot be used to set default values for instance ' -- 'variables defined\n' -- ' by *__slots__*; otherwise, the class attribute would ' -- 'overwrite the\n' -- ' descriptor assignment.\n' -- '\n' -- '* The action of a *__slots__* declaration is not limited to ' -- 'the class\n' -- ' where it is defined. *__slots__* declared in parents are ' -- 'available\n' -- ' in child classes. However, instances of a child subclass ' -- 'will get a\n' -- ' "__dict__" and *__weakref__* unless the subclass also ' -- 'defines\n' -- ' *__slots__* (which should only contain names of any ' -- '*additional*\n' -- ' slots).\n' -- '\n' -- '* If a class defines a slot also defined in a base class, ' -- 'the instance\n' -- ' variable defined by the base class slot is inaccessible ' -- '(except by\n' -- ' retrieving its descriptor directly from the base class). ' -- 'This\n' -- ' renders the meaning of the program undefined. In the ' -- 'future, a\n' -- ' check may be added to prevent this.\n' -- '\n' -- '* "TypeError" will be raised if nonempty *__slots__* are ' -- 'defined for a\n' -- ' class derived from a ""variable-length" built-in type" ' -- 'such as\n' -- ' "int", "bytes", and "tuple".\n' -- '\n' -- '* Any non-string *iterable* may be assigned to *__slots__*.\n' -- '\n' -- '* If a "dictionary" is used to assign *__slots__*, the ' -- 'dictionary keys\n' -- ' will be used as the slot names. The values of the ' -- 'dictionary can be\n' -- ' used to provide per-attribute docstrings that will be ' -- 'recognised by\n' -- ' "inspect.getdoc()" and displayed in the output of ' -- '"help()".\n' -- '\n' -- '* "__class__" assignment works only if both classes have the ' -- 'same\n' -- ' *__slots__*.\n' -- '\n' -- '* Multiple inheritance with multiple slotted parent classes ' -- 'can be\n' -- ' used, but only one parent is allowed to have attributes ' -- 'created by\n' -- ' slots (the other bases must have empty slot layouts) - ' -- 'violations\n' -- ' raise "TypeError".\n' -- '\n' -- '* If an *iterator* is used for *__slots__* then a ' -- '*descriptor* is\n' -- ' created for each of the iterator’s values. However, the ' -- '*__slots__*\n' -- ' attribute will be an empty iterator.\n' -- '\n' -- '\n' -- 'Customizing class creation\n' -- '==========================\n' -- '\n' -- 'Whenever a class inherits from another class, ' -- '"__init_subclass__()" is\n' -- 'called on the parent class. This way, it is possible to ' -- 'write classes\n' -- 'which change the behavior of subclasses. This is closely ' -- 'related to\n' -- 'class decorators, but where class decorators only affect the ' -- 'specific\n' -- 'class they’re applied to, "__init_subclass__" solely applies ' -- 'to future\n' -- 'subclasses of the class defining the method.\n' -- '\n' -- 'classmethod object.__init_subclass__(cls)\n' -- '\n' -- ' This method is called whenever the containing class is ' -- 'subclassed.\n' -- ' *cls* is then the new subclass. If defined as a normal ' -- 'instance\n' -- ' method, this method is implicitly converted to a class ' -- 'method.\n' -- '\n' -- ' Keyword arguments which are given to a new class are ' -- 'passed to the\n' -- ' parent class’s "__init_subclass__". For compatibility ' -- 'with other\n' -- ' classes using "__init_subclass__", one should take out ' -- 'the needed\n' -- ' keyword arguments and pass the others over to the base ' -- 'class, as\n' -- ' in:\n' -- '\n' -- ' class Philosopher:\n' -- ' def __init_subclass__(cls, /, default_name, ' -- '**kwargs):\n' -- ' super().__init_subclass__(**kwargs)\n' -- ' cls.default_name = default_name\n' -- '\n' -- ' class AustralianPhilosopher(Philosopher, ' -- 'default_name="Bruce"):\n' -- ' pass\n' -- '\n' -- ' The default implementation "object.__init_subclass__" ' -- 'does nothing,\n' -- ' but raises an error if it is called with any arguments.\n' -- '\n' -- ' Note:\n' -- '\n' -- ' The metaclass hint "metaclass" is consumed by the rest ' -- 'of the\n' -- ' type machinery, and is never passed to ' -- '"__init_subclass__"\n' -- ' implementations. The actual metaclass (rather than the ' -- 'explicit\n' -- ' hint) can be accessed as "type(cls)".\n' -- '\n' -- ' Added in version 3.6.\n' -- '\n' -- 'When a class is created, "type.__new__()" scans the class ' -- 'variables\n' -- 'and makes callbacks to those with a "__set_name__()" hook.\n' -- '\n' -- 'object.__set_name__(self, owner, name)\n' -- '\n' -- ' Automatically called at the time the owning class *owner* ' -- 'is\n' -- ' created. The object has been assigned to *name* in that ' -- 'class:\n' -- '\n' -- ' class A:\n' -- ' x = C() # Automatically calls: x.__set_name__(A, ' -- "'x')\n" -- '\n' -- ' If the class variable is assigned after the class is ' -- 'created,\n' -- ' "__set_name__()" will not be called automatically. If ' -- 'needed,\n' -- ' "__set_name__()" can be called directly:\n' -- '\n' -- ' class A:\n' -- ' pass\n' -- '\n' -- ' c = C()\n' -- ' A.x = c # The hook is not called\n' -- " c.__set_name__(A, 'x') # Manually invoke the hook\n" -- '\n' -- ' See Creating the class object for more details.\n' -- '\n' -- ' Added in version 3.6.\n' -- '\n' -- '\n' -- 'Metaclasses\n' -- '-----------\n' -- '\n' -- 'By default, classes are constructed using "type()". The ' -- 'class body is\n' -- 'executed in a new namespace and the class name is bound ' -- 'locally to the\n' -- 'result of "type(name, bases, namespace)".\n' -- '\n' -- 'The class creation process can be customized by passing the\n' -- '"metaclass" keyword argument in the class definition line, ' -- 'or by\n' -- 'inheriting from an existing class that included such an ' -- 'argument. In\n' -- 'the following example, both "MyClass" and "MySubclass" are ' -- 'instances\n' -- 'of "Meta":\n' -- '\n' -- ' class Meta(type):\n' -- ' pass\n' -- '\n' -- ' class MyClass(metaclass=Meta):\n' -- ' pass\n' -- '\n' -- ' class MySubclass(MyClass):\n' -- ' pass\n' -- '\n' -- 'Any other keyword arguments that are specified in the class ' -- 'definition\n' -- 'are passed through to all metaclass operations described ' -- 'below.\n' -- '\n' -- 'When a class definition is executed, the following steps ' -- 'occur:\n' -- '\n' -- '* MRO entries are resolved;\n' -- '\n' -- '* the appropriate metaclass is determined;\n' -- '\n' -- '* the class namespace is prepared;\n' -- '\n' -- '* the class body is executed;\n' -- '\n' -- '* the class object is created.\n' -- '\n' -- '\n' -- 'Resolving MRO entries\n' -- '---------------------\n' -- '\n' -- 'object.__mro_entries__(self, bases)\n' -- '\n' -- ' If a base that appears in a class definition is not an ' -- 'instance of\n' -- ' "type", then an "__mro_entries__()" method is searched on ' -- 'the base.\n' -- ' If an "__mro_entries__()" method is found, the base is ' -- 'substituted\n' -- ' with the result of a call to "__mro_entries__()" when ' -- 'creating the\n' -- ' class. The method is called with the original bases tuple ' -- 'passed to\n' -- ' the *bases* parameter, and must return a tuple of classes ' -- 'that will\n' -- ' be used instead of the base. The returned tuple may be ' -- 'empty: in\n' -- ' these cases, the original base is ignored.\n' -- '\n' -- 'See also:\n' -- '\n' -- ' "types.resolve_bases()"\n' -- ' Dynamically resolve bases that are not instances of ' -- '"type".\n' -- '\n' -- ' "types.get_original_bases()"\n' -- ' Retrieve a class’s “original bases†prior to ' -- 'modifications by\n' -- ' "__mro_entries__()".\n' -- '\n' -- ' **PEP 560**\n' -- ' Core support for typing module and generic types.\n' -- '\n' -- '\n' -- 'Determining the appropriate metaclass\n' -- '-------------------------------------\n' -- '\n' -- 'The appropriate metaclass for a class definition is ' -- 'determined as\n' -- 'follows:\n' -- '\n' -- '* if no bases and no explicit metaclass are given, then ' -- '"type()" is\n' -- ' used;\n' -- '\n' -- '* if an explicit metaclass is given and it is *not* an ' -- 'instance of\n' -- ' "type()", then it is used directly as the metaclass;\n' -- '\n' -- '* if an instance of "type()" is given as the explicit ' -- 'metaclass, or\n' -- ' bases are defined, then the most derived metaclass is ' -- 'used.\n' -- '\n' -- 'The most derived metaclass is selected from the explicitly ' -- 'specified\n' -- 'metaclass (if any) and the metaclasses (i.e. "type(cls)") of ' -- 'all\n' -- 'specified base classes. The most derived metaclass is one ' -- 'which is a\n' -- 'subtype of *all* of these candidate metaclasses. If none of ' -- 'the\n' -- 'candidate metaclasses meets that criterion, then the class ' -- 'definition\n' -- 'will fail with "TypeError".\n' -- '\n' -- '\n' -- 'Preparing the class namespace\n' -- '-----------------------------\n' -- '\n' -- 'Once the appropriate metaclass has been identified, then the ' -- 'class\n' -- 'namespace is prepared. If the metaclass has a "__prepare__" ' -- 'attribute,\n' -- 'it is called as "namespace = metaclass.__prepare__(name, ' -- 'bases,\n' -- '**kwds)" (where the additional keyword arguments, if any, ' -- 'come from\n' -- 'the class definition). The "__prepare__" method should be ' -- 'implemented\n' -- 'as a "classmethod". The namespace returned by "__prepare__" ' -- 'is passed\n' -- 'in to "__new__", but when the final class object is created ' -- 'the\n' -- 'namespace is copied into a new "dict".\n' -- '\n' -- 'If the metaclass has no "__prepare__" attribute, then the ' -- 'class\n' -- 'namespace is initialised as an empty ordered mapping.\n' -- '\n' -- 'See also:\n' -- '\n' -- ' **PEP 3115** - Metaclasses in Python 3000\n' -- ' Introduced the "__prepare__" namespace hook\n' -- '\n' -- '\n' -- 'Executing the class body\n' -- '------------------------\n' -- '\n' -- 'The class body is executed (approximately) as "exec(body, ' -- 'globals(),\n' -- 'namespace)". The key difference from a normal call to ' -- '"exec()" is that\n' -- 'lexical scoping allows the class body (including any ' -- 'methods) to\n' -- 'reference names from the current and outer scopes when the ' -- 'class\n' -- 'definition occurs inside a function.\n' -- '\n' -- 'However, even when the class definition occurs inside the ' -- 'function,\n' -- 'methods defined inside the class still cannot see names ' -- 'defined at the\n' -- 'class scope. Class variables must be accessed through the ' -- 'first\n' -- 'parameter of instance or class methods, or through the ' -- 'implicit\n' -- 'lexically scoped "__class__" reference described in the next ' -- 'section.\n' -- '\n' -- '\n' -- 'Creating the class object\n' -- '-------------------------\n' -- '\n' -- 'Once the class namespace has been populated by executing the ' -- 'class\n' -- 'body, the class object is created by calling ' -- '"metaclass(name, bases,\n' -- 'namespace, **kwds)" (the additional keywords passed here are ' -- 'the same\n' -- 'as those passed to "__prepare__").\n' -- '\n' -- 'This class object is the one that will be referenced by the ' -- 'zero-\n' -- 'argument form of "super()". "__class__" is an implicit ' -- 'closure\n' -- 'reference created by the compiler if any methods in a class ' -- 'body refer\n' -- 'to either "__class__" or "super". This allows the zero ' -- 'argument form\n' -- 'of "super()" to correctly identify the class being defined ' -- 'based on\n' -- 'lexical scoping, while the class or instance that was used ' -- 'to make the\n' -- 'current call is identified based on the first argument ' -- 'passed to the\n' -- 'method.\n' -- '\n' -- '**CPython implementation detail:** In CPython 3.6 and later, ' -- 'the\n' -- '"__class__" cell is passed to the metaclass as a ' -- '"__classcell__" entry\n' -- 'in the class namespace. If present, this must be propagated ' -- 'up to the\n' -- '"type.__new__" call in order for the class to be ' -- 'initialised\n' -- 'correctly. Failing to do so will result in a "RuntimeError" ' -- 'in Python\n' -- '3.8.\n' -- '\n' -- 'When using the default metaclass "type", or any metaclass ' -- 'that\n' -- 'ultimately calls "type.__new__", the following additional\n' -- 'customization steps are invoked after creating the class ' -- 'object:\n' -- '\n' -- '1. The "type.__new__" method collects all of the attributes ' -- 'in the\n' -- ' class namespace that define a "__set_name__()" method;\n' -- '\n' -- '2. Those "__set_name__" methods are called with the class ' -- 'being\n' -- ' defined and the assigned name of that particular ' -- 'attribute;\n' -- '\n' -- '3. The "__init_subclass__()" hook is called on the immediate ' -- 'parent of\n' -- ' the new class in its method resolution order.\n' -- '\n' -- 'After the class object is created, it is passed to the ' -- 'class\n' -- 'decorators included in the class definition (if any) and the ' -- 'resulting\n' -- 'object is bound in the local namespace as the defined ' -- 'class.\n' -- '\n' -- 'When a new class is created by "type.__new__", the object ' -- 'provided as\n' -- 'the namespace parameter is copied to a new ordered mapping ' -- 'and the\n' -- 'original object is discarded. The new copy is wrapped in a ' -- 'read-only\n' -- 'proxy, which becomes the "__dict__" attribute of the class ' -- 'object.\n' -- '\n' -- 'See also:\n' -- '\n' -- ' **PEP 3135** - New super\n' -- ' Describes the implicit "__class__" closure reference\n' -- '\n' -- '\n' -- 'Uses for metaclasses\n' -- '--------------------\n' -- '\n' -- 'The potential uses for metaclasses are boundless. Some ideas ' -- 'that have\n' -- 'been explored include enum, logging, interface checking, ' -- 'automatic\n' -- 'delegation, automatic property creation, proxies, ' -- 'frameworks, and\n' -- 'automatic resource locking/synchronization.\n' -- '\n' -- '\n' -- 'Customizing instance and subclass checks\n' -- '========================================\n' -- '\n' -- 'The following methods are used to override the default ' -- 'behavior of the\n' -- '"isinstance()" and "issubclass()" built-in functions.\n' -- '\n' -- 'In particular, the metaclass "abc.ABCMeta" implements these ' -- 'methods in\n' -- 'order to allow the addition of Abstract Base Classes (ABCs) ' -- 'as\n' -- '“virtual base classes†to any class or type (including ' -- 'built-in\n' -- 'types), including other ABCs.\n' -- '\n' -- 'type.__instancecheck__(self, instance)\n' -- '\n' -- ' Return true if *instance* should be considered a (direct ' -- 'or\n' -- ' indirect) instance of *class*. If defined, called to ' -- 'implement\n' -- ' "isinstance(instance, class)".\n' -- '\n' -- 'type.__subclasscheck__(self, subclass)\n' -- '\n' -- ' Return true if *subclass* should be considered a (direct ' -- 'or\n' -- ' indirect) subclass of *class*. If defined, called to ' -- 'implement\n' -- ' "issubclass(subclass, class)".\n' -- '\n' -- 'Note that these methods are looked up on the type ' -- '(metaclass) of a\n' -- 'class. They cannot be defined as class methods in the ' -- 'actual class.\n' -- 'This is consistent with the lookup of special methods that ' -- 'are called\n' -- 'on instances, only in this case the instance is itself a ' -- 'class.\n' -- '\n' -- 'See also:\n' -- '\n' -- ' **PEP 3119** - Introducing Abstract Base Classes\n' -- ' Includes the specification for customizing ' -- '"isinstance()" and\n' -- ' "issubclass()" behavior through "__instancecheck__()" ' -- 'and\n' -- ' "__subclasscheck__()", with motivation for this ' -- 'functionality in\n' -- ' the context of adding Abstract Base Classes (see the ' -- '"abc"\n' -- ' module) to the language.\n' -- '\n' -- '\n' -- 'Emulating generic types\n' -- '=======================\n' -- '\n' -- 'When using *type annotations*, it is often useful to ' -- '*parameterize* a\n' -- '*generic type* using Python’s square-brackets notation. For ' -- 'example,\n' -- 'the annotation "list[int]" might be used to signify a "list" ' -- 'in which\n' -- 'all the elements are of type "int".\n' -- '\n' -- 'See also:\n' -- '\n' -- ' **PEP 484** - Type Hints\n' -- ' Introducing Python’s framework for type annotations\n' -- '\n' -- ' Generic Alias Types\n' -- ' Documentation for objects representing parameterized ' -- 'generic\n' -- ' classes\n' -- '\n' -- ' Generics, user-defined generics and "typing.Generic"\n' -- ' Documentation on how to implement generic classes that ' -- 'can be\n' -- ' parameterized at runtime and understood by static ' -- 'type-checkers.\n' -- '\n' -- 'A class can *generally* only be parameterized if it defines ' -- 'the\n' -- 'special class method "__class_getitem__()".\n' -- '\n' -- 'classmethod object.__class_getitem__(cls, key)\n' -- '\n' -- ' Return an object representing the specialization of a ' -- 'generic class\n' -- ' by type arguments found in *key*.\n' -- '\n' -- ' When defined on a class, "__class_getitem__()" is ' -- 'automatically a\n' -- ' class method. As such, there is no need for it to be ' -- 'decorated with\n' -- ' "@classmethod" when it is defined.\n' -- '\n' -- '\n' -- 'The purpose of *__class_getitem__*\n' -- '----------------------------------\n' -- '\n' -- 'The purpose of "__class_getitem__()" is to allow runtime\n' -- 'parameterization of standard-library generic classes in ' -- 'order to more\n' -- 'easily apply *type hints* to these classes.\n' -- '\n' -- 'To implement custom generic classes that can be ' -- 'parameterized at\n' -- 'runtime and understood by static type-checkers, users should ' -- 'either\n' -- 'inherit from a standard library class that already ' -- 'implements\n' -- '"__class_getitem__()", or inherit from "typing.Generic", ' -- 'which has its\n' -- 'own implementation of "__class_getitem__()".\n' -- '\n' -- 'Custom implementations of "__class_getitem__()" on classes ' -- 'defined\n' -- 'outside of the standard library may not be understood by ' -- 'third-party\n' -- 'type-checkers such as mypy. Using "__class_getitem__()" on ' -- 'any class\n' -- 'for purposes other than type hinting is discouraged.\n' -- '\n' -- '\n' -- '*__class_getitem__* versus *__getitem__*\n' -- '----------------------------------------\n' -- '\n' -- 'Usually, the subscription of an object using square brackets ' -- 'will call\n' -- 'the "__getitem__()" instance method defined on the object’s ' -- 'class.\n' -- 'However, if the object being subscribed is itself a class, ' -- 'the class\n' -- 'method "__class_getitem__()" may be called instead.\n' -- '"__class_getitem__()" should return a GenericAlias object if ' -- 'it is\n' -- 'properly defined.\n' -- '\n' -- 'Presented with the *expression* "obj[x]", the Python ' -- 'interpreter\n' -- 'follows something like the following process to decide ' -- 'whether\n' -- '"__getitem__()" or "__class_getitem__()" should be called:\n' -- '\n' -- ' from inspect import isclass\n' -- '\n' -- ' def subscribe(obj, x):\n' -- ' """Return the result of the expression \'obj[x]\'"""\n' -- '\n' -- ' class_of_obj = type(obj)\n' -- '\n' -- ' # If the class of obj defines __getitem__,\n' -- ' # call class_of_obj.__getitem__(obj, x)\n' -- " if hasattr(class_of_obj, '__getitem__'):\n" -- ' return class_of_obj.__getitem__(obj, x)\n' -- '\n' -- ' # Else, if obj is a class and defines ' -- '__class_getitem__,\n' -- ' # call obj.__class_getitem__(x)\n' -- ' elif isclass(obj) and hasattr(obj, ' -- "'__class_getitem__'):\n" -- ' return obj.__class_getitem__(x)\n' -- '\n' -- ' # Else, raise an exception\n' -- ' else:\n' -- ' raise TypeError(\n' -- ' f"\'{class_of_obj.__name__}\' object is not ' -- 'subscriptable"\n' -- ' )\n' -- '\n' -- 'In Python, all classes are themselves instances of other ' -- 'classes. The\n' -- 'class of a class is known as that class’s *metaclass*, and ' -- 'most\n' -- 'classes have the "type" class as their metaclass. "type" ' -- 'does not\n' -- 'define "__getitem__()", meaning that expressions such as ' -- '"list[int]",\n' -- '"dict[str, float]" and "tuple[str, bytes]" all result in\n' -- '"__class_getitem__()" being called:\n' -- '\n' -- ' >>> # list has class "type" as its metaclass, like most ' -- 'classes:\n' -- ' >>> type(list)\n' -- " \n" -- ' >>> type(dict) == type(list) == type(tuple) == type(str) ' -- '== type(bytes)\n' -- ' True\n' -- ' >>> # "list[int]" calls "list.__class_getitem__(int)"\n' -- ' >>> list[int]\n' -- ' list[int]\n' -- ' >>> # list.__class_getitem__ returns a GenericAlias ' -- 'object:\n' -- ' >>> type(list[int])\n' -- " \n" -- '\n' -- 'However, if a class has a custom metaclass that defines\n' -- '"__getitem__()", subscribing the class may result in ' -- 'different\n' -- 'behaviour. An example of this can be found in the "enum" ' -- 'module:\n' -- '\n' -- ' >>> from enum import Enum\n' -- ' >>> class Menu(Enum):\n' -- ' ... """A breakfast menu"""\n' -- " ... SPAM = 'spam'\n" -- " ... BACON = 'bacon'\n" -- ' ...\n' -- ' >>> # Enum classes have a custom metaclass:\n' -- ' >>> type(Menu)\n' -- " \n" -- ' >>> # EnumMeta defines __getitem__,\n' -- ' >>> # so __class_getitem__ is not called,\n' -- ' >>> # and the result is not a GenericAlias object:\n' -- " >>> Menu['SPAM']\n" -- " \n" -- " >>> type(Menu['SPAM'])\n" -- " \n" -- '\n' -- 'See also:\n' -- '\n' -- ' **PEP 560** - Core Support for typing module and generic ' -- 'types\n' -- ' Introducing "__class_getitem__()", and outlining when ' -- 'a\n' -- ' subscription results in "__class_getitem__()" being ' -- 'called\n' -- ' instead of "__getitem__()"\n' -- '\n' -- '\n' -- 'Emulating callable objects\n' -- '==========================\n' -- '\n' -- 'object.__call__(self[, args...])\n' -- '\n' -- ' Called when the instance is “called†as a function; if ' -- 'this method\n' -- ' is defined, "x(arg1, arg2, ...)" roughly translates to\n' -- ' "type(x).__call__(x, arg1, ...)". The "object" class ' -- 'itself does\n' -- ' not provide this method.\n' -- '\n' -- '\n' -- 'Emulating container types\n' -- '=========================\n' -- '\n' -- 'The following methods can be defined to implement container ' -- 'objects.\n' -- 'None of them are provided by the "object" class itself. ' -- 'Containers\n' -- 'usually are *sequences* (such as "lists" or "tuples") or ' -- '*mappings*\n' -- '(like *dictionaries*), but can represent other containers as ' -- 'well.\n' -- 'The first set of methods is used either to emulate a ' -- 'sequence or to\n' -- 'emulate a mapping; the difference is that for a sequence, ' -- 'the\n' -- 'allowable keys should be the integers *k* for which "0 <= k ' -- '< N" where\n' -- '*N* is the length of the sequence, or "slice" objects, which ' -- 'define a\n' -- 'range of items. It is also recommended that mappings ' -- 'provide the\n' -- 'methods "keys()", "values()", "items()", "get()", ' -- '"clear()",\n' -- '"setdefault()", "pop()", "popitem()", "copy()", and ' -- '"update()"\n' -- 'behaving similar to those for Python’s standard "dictionary" ' -- 'objects.\n' -- 'The "collections.abc" module provides a "MutableMapping" ' -- '*abstract\n' -- 'base class* to help create those methods from a base set of\n' -- '"__getitem__()", "__setitem__()", "__delitem__()", and ' -- '"keys()".\n' -- 'Mutable sequences should provide methods "append()", ' -- '"count()",\n' -- '"index()", "extend()", "insert()", "pop()", "remove()", ' -- '"reverse()"\n' -- 'and "sort()", like Python standard "list" objects. Finally, ' -- 'sequence\n' -- 'types should implement addition (meaning concatenation) and\n' -- 'multiplication (meaning repetition) by defining the methods\n' -- '"__add__()", "__radd__()", "__iadd__()", "__mul__()", ' -- '"__rmul__()" and\n' -- '"__imul__()" described below; they should not define other ' -- 'numerical\n' -- 'operators. It is recommended that both mappings and ' -- 'sequences\n' -- 'implement the "__contains__()" method to allow efficient use ' -- 'of the\n' -- '"in" operator; for mappings, "in" should search the ' -- 'mapping’s keys;\n' -- 'for sequences, it should search through the values. It is ' -- 'further\n' -- 'recommended that both mappings and sequences implement the\n' -- '"__iter__()" method to allow efficient iteration through ' -- 'the\n' -- 'container; for mappings, "__iter__()" should iterate through ' -- 'the\n' -- 'object’s keys; for sequences, it should iterate through the ' -- 'values.\n' -- '\n' -- 'object.__len__(self)\n' -- '\n' -- ' Called to implement the built-in function "len()". ' -- 'Should return\n' -- ' the length of the object, an integer ">=" 0. Also, an ' -- 'object that\n' -- ' doesn’t define a "__bool__()" method and whose ' -- '"__len__()" method\n' -- ' returns zero is considered to be false in a Boolean ' -- 'context.\n' -- '\n' -- ' **CPython implementation detail:** In CPython, the length ' -- 'is\n' -- ' required to be at most "sys.maxsize". If the length is ' -- 'larger than\n' -- ' "sys.maxsize" some features (such as "len()") may raise\n' -- ' "OverflowError". To prevent raising "OverflowError" by ' -- 'truth value\n' -- ' testing, an object must define a "__bool__()" method.\n' -- '\n' -- 'object.__length_hint__(self)\n' -- '\n' -- ' Called to implement "operator.length_hint()". Should ' -- 'return an\n' -- ' estimated length for the object (which may be greater or ' -- 'less than\n' -- ' the actual length). The length must be an integer ">=" 0. ' -- 'The\n' -- ' return value may also be "NotImplemented", which is ' -- 'treated the\n' -- ' same as if the "__length_hint__" method didn’t exist at ' -- 'all. This\n' -- ' method is purely an optimization and is never required ' -- 'for\n' -- ' correctness.\n' -- '\n' -- ' Added in version 3.4.\n' -- '\n' -- 'Note:\n' -- '\n' -- ' Slicing is done exclusively with the following three ' -- 'methods. A\n' -- ' call like\n' -- '\n' -- ' a[1:2] = b\n' -- '\n' -- ' is translated to\n' -- '\n' -- ' a[slice(1, 2, None)] = b\n' -- '\n' -- ' and so forth. Missing slice items are always filled in ' -- 'with "None".\n' -- '\n' -- 'object.__getitem__(self, key)\n' -- '\n' -- ' Called to implement evaluation of "self[key]". For ' -- '*sequence*\n' -- ' types, the accepted keys should be integers. Optionally, ' -- 'they may\n' -- ' support "slice" objects as well. Negative index support ' -- 'is also\n' -- ' optional. If *key* is of an inappropriate type, ' -- '"TypeError" may be\n' -- ' raised; if *key* is a value outside the set of indexes ' -- 'for the\n' -- ' sequence (after any special interpretation of negative ' -- 'values),\n' -- ' "IndexError" should be raised. For *mapping* types, if ' -- '*key* is\n' -- ' missing (not in the container), "KeyError" should be ' -- 'raised.\n' -- '\n' -- ' Note:\n' -- '\n' -- ' "for" loops expect that an "IndexError" will be raised ' -- 'for\n' -- ' illegal indexes to allow proper detection of the end of ' -- 'the\n' -- ' sequence.\n' -- '\n' -- ' Note:\n' -- '\n' -- ' When subscripting a *class*, the special class method\n' -- ' "__class_getitem__()" may be called instead of ' -- '"__getitem__()".\n' -- ' See __class_getitem__ versus __getitem__ for more ' -- 'details.\n' -- '\n' -- 'object.__setitem__(self, key, value)\n' -- '\n' -- ' Called to implement assignment to "self[key]". Same note ' -- 'as for\n' -- ' "__getitem__()". This should only be implemented for ' -- 'mappings if\n' -- ' the objects support changes to the values for keys, or if ' -- 'new keys\n' -- ' can be added, or for sequences if elements can be ' -- 'replaced. The\n' -- ' same exceptions should be raised for improper *key* ' -- 'values as for\n' -- ' the "__getitem__()" method.\n' -- '\n' -- 'object.__delitem__(self, key)\n' -- '\n' -- ' Called to implement deletion of "self[key]". Same note ' -- 'as for\n' -- ' "__getitem__()". This should only be implemented for ' -- 'mappings if\n' -- ' the objects support removal of keys, or for sequences if ' -- 'elements\n' -- ' can be removed from the sequence. The same exceptions ' -- 'should be\n' -- ' raised for improper *key* values as for the ' -- '"__getitem__()" method.\n' -- '\n' -- 'object.__missing__(self, key)\n' -- '\n' -- ' Called by "dict"."__getitem__()" to implement "self[key]" ' -- 'for dict\n' -- ' subclasses when key is not in the dictionary.\n' -- '\n' -- 'object.__iter__(self)\n' -- '\n' -- ' This method is called when an *iterator* is required for ' -- 'a\n' -- ' container. This method should return a new iterator ' -- 'object that can\n' -- ' iterate over all the objects in the container. For ' -- 'mappings, it\n' -- ' should iterate over the keys of the container.\n' -- '\n' -- 'object.__reversed__(self)\n' -- '\n' -- ' Called (if present) by the "reversed()" built-in to ' -- 'implement\n' -- ' reverse iteration. It should return a new iterator ' -- 'object that\n' -- ' iterates over all the objects in the container in reverse ' -- 'order.\n' -- '\n' -- ' If the "__reversed__()" method is not provided, the ' -- '"reversed()"\n' -- ' built-in will fall back to using the sequence protocol ' -- '("__len__()"\n' -- ' and "__getitem__()"). Objects that support the sequence ' -- 'protocol\n' -- ' should only provide "__reversed__()" if they can provide ' -- 'an\n' -- ' implementation that is more efficient than the one ' -- 'provided by\n' -- ' "reversed()".\n' -- '\n' -- 'The membership test operators ("in" and "not in") are ' -- 'normally\n' -- 'implemented as an iteration through a container. However, ' -- 'container\n' -- 'objects can supply the following special method with a more ' -- 'efficient\n' -- 'implementation, which also does not require the object be ' -- 'iterable.\n' -- '\n' -- 'object.__contains__(self, item)\n' -- '\n' -- ' Called to implement membership test operators. Should ' -- 'return true\n' -- ' if *item* is in *self*, false otherwise. For mapping ' -- 'objects, this\n' -- ' should consider the keys of the mapping rather than the ' -- 'values or\n' -- ' the key-item pairs.\n' -- '\n' -- ' For objects that don’t define "__contains__()", the ' -- 'membership test\n' -- ' first tries iteration via "__iter__()", then the old ' -- 'sequence\n' -- ' iteration protocol via "__getitem__()", see this section ' -- 'in the\n' -- ' language reference.\n' -- '\n' -- '\n' -- 'Emulating numeric types\n' -- '=======================\n' -- '\n' -- 'The following methods can be defined to emulate numeric ' -- 'objects.\n' -- 'Methods corresponding to operations that are not supported ' -- 'by the\n' -- 'particular kind of number implemented (e.g., bitwise ' -- 'operations for\n' -- 'non-integral numbers) should be left undefined.\n' -- '\n' -- 'object.__add__(self, other)\n' -- 'object.__sub__(self, other)\n' -- 'object.__mul__(self, other)\n' -- 'object.__matmul__(self, other)\n' -- 'object.__truediv__(self, other)\n' -- 'object.__floordiv__(self, other)\n' -- 'object.__mod__(self, other)\n' -- 'object.__divmod__(self, other)\n' -- 'object.__pow__(self, other[, modulo])\n' -- 'object.__lshift__(self, other)\n' -- 'object.__rshift__(self, other)\n' -- 'object.__and__(self, other)\n' -- 'object.__xor__(self, other)\n' -- 'object.__or__(self, other)\n' -- '\n' -- ' These methods are called to implement the binary ' -- 'arithmetic\n' -- ' operations ("+", "-", "*", "@", "/", "//", "%", ' -- '"divmod()",\n' -- ' "pow()", "**", "<<", ">>", "&", "^", "|"). For instance, ' -- 'to\n' -- ' evaluate the expression "x + y", where *x* is an instance ' -- 'of a\n' -- ' class that has an "__add__()" method, "type(x).__add__(x, ' -- 'y)" is\n' -- ' called. The "__divmod__()" method should be the ' -- 'equivalent to\n' -- ' using "__floordiv__()" and "__mod__()"; it should not be ' -- 'related to\n' -- ' "__truediv__()". Note that "__pow__()" should be defined ' -- 'to accept\n' -- ' an optional third argument if the ternary version of the ' -- 'built-in\n' -- ' "pow()" function is to be supported.\n' -- '\n' -- ' If one of those methods does not support the operation ' -- 'with the\n' -- ' supplied arguments, it should return "NotImplemented".\n' -- '\n' -- 'object.__radd__(self, other)\n' -- 'object.__rsub__(self, other)\n' -- 'object.__rmul__(self, other)\n' -- 'object.__rmatmul__(self, other)\n' -- 'object.__rtruediv__(self, other)\n' -- 'object.__rfloordiv__(self, other)\n' -- 'object.__rmod__(self, other)\n' -- 'object.__rdivmod__(self, other)\n' -- 'object.__rpow__(self, other[, modulo])\n' -- 'object.__rlshift__(self, other)\n' -- 'object.__rrshift__(self, other)\n' -- 'object.__rand__(self, other)\n' -- 'object.__rxor__(self, other)\n' -- 'object.__ror__(self, other)\n' -- '\n' -- ' These methods are called to implement the binary ' -- 'arithmetic\n' -- ' operations ("+", "-", "*", "@", "/", "//", "%", ' -- '"divmod()",\n' -- ' "pow()", "**", "<<", ">>", "&", "^", "|") with reflected ' -- '(swapped)\n' -- ' operands. These functions are only called if the ' -- 'operands are of\n' -- ' different types, when the left operand does not support ' -- 'the\n' -- ' corresponding operation [3], or the right operand’s class ' -- 'is\n' -- ' derived from the left operand’s class. [4] For instance, ' -- 'to\n' -- ' evaluate the expression "x - y", where *y* is an instance ' -- 'of a\n' -- ' class that has an "__rsub__()" method, ' -- '"type(y).__rsub__(y, x)" is\n' -- ' called if "type(x).__sub__(x, y)" returns ' -- '"NotImplemented" or\n' -- ' "type(y)" is a subclass of "type(x)". [5]\n' -- '\n' -- ' Note that ternary "pow()" will not try calling ' -- '"__rpow__()" (the\n' -- ' coercion rules would become too complicated).\n' -- '\n' -- ' Note:\n' -- '\n' -- ' If the right operand’s type is a subclass of the left ' -- 'operand’s\n' -- ' type and that subclass provides a different ' -- 'implementation of the\n' -- ' reflected method for the operation, this method will be ' -- 'called\n' -- ' before the left operand’s non-reflected method. This ' -- 'behavior\n' -- ' allows subclasses to override their ancestors’ ' -- 'operations.\n' -- '\n' -- 'object.__iadd__(self, other)\n' -- 'object.__isub__(self, other)\n' -- 'object.__imul__(self, other)\n' -- 'object.__imatmul__(self, other)\n' -- 'object.__itruediv__(self, other)\n' -- 'object.__ifloordiv__(self, other)\n' -- 'object.__imod__(self, other)\n' -- 'object.__ipow__(self, other[, modulo])\n' -- 'object.__ilshift__(self, other)\n' -- 'object.__irshift__(self, other)\n' -- 'object.__iand__(self, other)\n' -- 'object.__ixor__(self, other)\n' -- 'object.__ior__(self, other)\n' -- '\n' -- ' These methods are called to implement the augmented ' -- 'arithmetic\n' -- ' assignments ("+=", "-=", "*=", "@=", "/=", "//=", "%=", ' -- '"**=",\n' -- ' "<<=", ">>=", "&=", "^=", "|="). These methods should ' -- 'attempt to\n' -- ' do the operation in-place (modifying *self*) and return ' -- 'the result\n' -- ' (which could be, but does not have to be, *self*). If a ' -- 'specific\n' -- ' method is not defined, or if that method returns ' -- '"NotImplemented",\n' -- ' the augmented assignment falls back to the normal ' -- 'methods. For\n' -- ' instance, if *x* is an instance of a class with an ' -- '"__iadd__()"\n' -- ' method, "x += y" is equivalent to "x = x.__iadd__(y)" . ' -- 'If\n' -- ' "__iadd__()" does not exist, or if "x.__iadd__(y)" ' -- 'returns\n' -- ' "NotImplemented", "x.__add__(y)" and "y.__radd__(x)" are\n' -- ' considered, as with the evaluation of "x + y". In ' -- 'certain\n' -- ' situations, augmented assignment can result in unexpected ' -- 'errors\n' -- ' (see Why does a_tuple[i] += [‘item’] raise an exception ' -- 'when the\n' -- ' addition works?), but this behavior is in fact part of ' -- 'the data\n' -- ' model.\n' -- '\n' -- 'object.__neg__(self)\n' -- 'object.__pos__(self)\n' -- 'object.__abs__(self)\n' -- 'object.__invert__(self)\n' -- '\n' -- ' Called to implement the unary arithmetic operations ("-", ' -- '"+",\n' -- ' "abs()" and "~").\n' -- '\n' -- 'object.__complex__(self)\n' -- 'object.__int__(self)\n' -- 'object.__float__(self)\n' -- '\n' -- ' Called to implement the built-in functions "complex()", ' -- '"int()" and\n' -- ' "float()". Should return a value of the appropriate ' -- 'type.\n' -- '\n' -- 'object.__index__(self)\n' -- '\n' -- ' Called to implement "operator.index()", and whenever ' -- 'Python needs\n' -- ' to losslessly convert the numeric object to an integer ' -- 'object (such\n' -- ' as in slicing, or in the built-in "bin()", "hex()" and ' -- '"oct()"\n' -- ' functions). Presence of this method indicates that the ' -- 'numeric\n' -- ' object is an integer type. Must return an integer.\n' -- '\n' -- ' If "__int__()", "__float__()" and "__complex__()" are not ' -- 'defined\n' -- ' then corresponding built-in functions "int()", "float()" ' -- 'and\n' -- ' "complex()" fall back to "__index__()".\n' -- '\n' -- 'object.__round__(self[, ndigits])\n' -- 'object.__trunc__(self)\n' -- 'object.__floor__(self)\n' -- 'object.__ceil__(self)\n' -- '\n' -- ' Called to implement the built-in function "round()" and ' -- '"math"\n' -- ' functions "trunc()", "floor()" and "ceil()". Unless ' -- '*ndigits* is\n' -- ' passed to "__round__()" all these methods should return ' -- 'the value\n' -- ' of the object truncated to an "Integral" (typically an ' -- '"int").\n' -- '\n' -- ' Changed in version 3.14: "int()" no longer delegates to ' -- 'the\n' -- ' "__trunc__()" method.\n' -- '\n' -- '\n' -- 'With Statement Context Managers\n' -- '===============================\n' -- '\n' -- 'A *context manager* is an object that defines the runtime ' -- 'context to\n' -- 'be established when executing a "with" statement. The ' -- 'context manager\n' -- 'handles the entry into, and the exit from, the desired ' -- 'runtime context\n' -- 'for the execution of the block of code. Context managers ' -- 'are normally\n' -- 'invoked using the "with" statement (described in section The ' -- 'with\n' -- 'statement), but can also be used by directly invoking their ' -- 'methods.\n' -- '\n' -- 'Typical uses of context managers include saving and ' -- 'restoring various\n' -- 'kinds of global state, locking and unlocking resources, ' -- 'closing opened\n' -- 'files, etc.\n' -- '\n' -- 'For more information on context managers, see Context ' -- 'Manager Types.\n' -- 'The "object" class itself does not provide the context ' -- 'manager\n' -- 'methods.\n' -- '\n' -- 'object.__enter__(self)\n' -- '\n' -- ' Enter the runtime context related to this object. The ' -- '"with"\n' -- ' statement will bind this method’s return value to the ' -- 'target(s)\n' -- ' specified in the "as" clause of the statement, if any.\n' -- '\n' -- 'object.__exit__(self, exc_type, exc_value, traceback)\n' -- '\n' -- ' Exit the runtime context related to this object. The ' -- 'parameters\n' -- ' describe the exception that caused the context to be ' -- 'exited. If the\n' -- ' context was exited without an exception, all three ' -- 'arguments will\n' -- ' be "None".\n' -- '\n' -- ' If an exception is supplied, and the method wishes to ' -- 'suppress the\n' -- ' exception (i.e., prevent it from being propagated), it ' -- 'should\n' -- ' return a true value. Otherwise, the exception will be ' -- 'processed\n' -- ' normally upon exit from this method.\n' -- '\n' -- ' Note that "__exit__()" methods should not reraise the ' -- 'passed-in\n' -- ' exception; this is the caller’s responsibility.\n' -- '\n' -- 'See also:\n' -- '\n' -- ' **PEP 343** - The “with†statement\n' -- ' The specification, background, and examples for the ' -- 'Python "with"\n' -- ' statement.\n' -- '\n' -- '\n' -- 'Customizing positional arguments in class pattern matching\n' -- '==========================================================\n' -- '\n' -- 'When using a class name in a pattern, positional arguments ' -- 'in the\n' -- 'pattern are not allowed by default, i.e. "case MyClass(x, ' -- 'y)" is\n' -- 'typically invalid without special support in "MyClass". To ' -- 'be able to\n' -- 'use that kind of pattern, the class needs to define a ' -- '*__match_args__*\n' -- 'attribute.\n' -- '\n' -- 'object.__match_args__\n' -- '\n' -- ' This class variable can be assigned a tuple of strings. ' -- 'When this\n' -- ' class is used in a class pattern with positional ' -- 'arguments, each\n' -- ' positional argument will be converted into a keyword ' -- 'argument,\n' -- ' using the corresponding value in *__match_args__* as the ' -- 'keyword.\n' -- ' The absence of this attribute is equivalent to setting it ' -- 'to "()".\n' -- '\n' -- 'For example, if "MyClass.__match_args__" is "("left", ' -- '"center",\n' -- '"right")" that means that "case MyClass(x, y)" is equivalent ' -- 'to "case\n' -- 'MyClass(left=x, center=y)". Note that the number of ' -- 'arguments in the\n' -- 'pattern must be smaller than or equal to the number of ' -- 'elements in\n' -- '*__match_args__*; if it is larger, the pattern match attempt ' -- 'will\n' -- 'raise a "TypeError".\n' -- '\n' -- 'Added in version 3.10.\n' -- '\n' -- 'See also:\n' -- '\n' -- ' **PEP 634** - Structural Pattern Matching\n' -- ' The specification for the Python "match" statement.\n' -- '\n' -- '\n' -- 'Emulating buffer types\n' -- '======================\n' -- '\n' -- 'The buffer protocol provides a way for Python objects to ' -- 'expose\n' -- 'efficient access to a low-level memory array. This protocol ' -- 'is\n' -- 'implemented by builtin types such as "bytes" and ' -- '"memoryview", and\n' -- 'third-party libraries may define additional buffer types.\n' -- '\n' -- 'While buffer types are usually implemented in C, it is also ' -- 'possible\n' -- 'to implement the protocol in Python.\n' -- '\n' -- 'object.__buffer__(self, flags)\n' -- '\n' -- ' Called when a buffer is requested from *self* (for ' -- 'example, by the\n' -- ' "memoryview" constructor). The *flags* argument is an ' -- 'integer\n' -- ' representing the kind of buffer requested, affecting for ' -- 'example\n' -- ' whether the returned buffer is read-only or writable.\n' -- ' "inspect.BufferFlags" provides a convenient way to ' -- 'interpret the\n' -- ' flags. The method must return a "memoryview" object.\n' -- '\n' -- 'object.__release_buffer__(self, buffer)\n' -- '\n' -- ' Called when a buffer is no longer needed. The *buffer* ' -- 'argument is\n' -- ' a "memoryview" object that was previously returned by\n' -- ' "__buffer__()". The method must release any resources ' -- 'associated\n' -- ' with the buffer. This method should return "None". Buffer ' -- 'objects\n' -- ' that do not need to perform any cleanup are not required ' -- 'to\n' -- ' implement this method.\n' -- '\n' -- 'Added in version 3.12.\n' -- '\n' -- 'See also:\n' -- '\n' -- ' **PEP 688** - Making the buffer protocol accessible in ' -- 'Python\n' -- ' Introduces the Python "__buffer__" and ' -- '"__release_buffer__"\n' -- ' methods.\n' -- '\n' -- ' "collections.abc.Buffer"\n' -- ' ABC for buffer types.\n' -- '\n' -- '\n' -- 'Annotations\n' -- '===========\n' -- '\n' -- 'Functions, classes, and modules may contain *annotations*, ' -- 'which are a\n' -- 'way to associate information (usually *type hints*) with a ' -- 'symbol.\n' -- '\n' -- 'object.__annotations__\n' -- '\n' -- ' This attribute contains the annotations for an object. It ' -- 'is lazily\n' -- ' evaluated, so accessing the attribute may execute ' -- 'arbitrary code\n' -- ' and raise exceptions. If evaluation is successful, the ' -- 'attribute is\n' -- ' set to a dictionary mapping from variable names to ' -- 'annotations.\n' -- '\n' -- ' Changed in version 3.14: Annotations are now lazily ' -- 'evaluated.\n' -- '\n' -- 'object.__annotate__(format)\n' -- '\n' -- ' An *annotate function*. Returns a new dictionary object ' -- 'mapping\n' -- ' attribute/parameter names to their annotation values.\n' -- '\n' -- ' Takes a format parameter specifying the format in which ' -- 'annotations\n' -- ' values should be provided. It must be a member of the\n' -- ' "annotationlib.Format" enum, or an integer with a value\n' -- ' corresponding to a member of the enum.\n' -- '\n' -- ' If an annotate function doesn’t support the requested ' -- 'format, it\n' -- ' must raise "NotImplementedError". Annotate functions must ' -- 'always\n' -- ' support "VALUE" format; they must not raise ' -- '"NotImplementedError()"\n' -- ' when called with this format.\n' -- '\n' -- ' When called with "VALUE" format, an annotate function ' -- 'may raise\n' -- ' "NameError"; it must not raise "NameError" when called ' -- 'requesting\n' -- ' any other format.\n' -- '\n' -- ' If an object does not have any annotations, ' -- '"__annotate__" should\n' -- ' preferably be set to "None" (it can’t be deleted), rather ' -- 'than set\n' -- ' to a function that returns an empty dict.\n' -- '\n' -- ' Added in version 3.14.\n' -- '\n' -- 'See also:\n' -- '\n' -- ' **PEP 649** — Deferred evaluation of annotation using ' -- 'descriptors\n' -- ' Introduces lazy evaluation of annotations and the ' -- '"__annotate__"\n' -- ' function.\n' -- '\n' -- '\n' -- 'Special method lookup\n' -- '=====================\n' -- '\n' -- 'For custom classes, implicit invocations of special methods ' -- 'are only\n' -- 'guaranteed to work correctly if defined on an object’s type, ' -- 'not in\n' -- 'the object’s instance dictionary. That behaviour is the ' -- 'reason why\n' -- 'the following code raises an exception:\n' -- '\n' -- ' >>> class C:\n' -- ' ... pass\n' -- ' ...\n' -- ' >>> c = C()\n' -- ' >>> c.__len__ = lambda: 5\n' -- ' >>> len(c)\n' -- ' Traceback (most recent call last):\n' -- ' File "", line 1, in \n' -- " TypeError: object of type 'C' has no len()\n" -- '\n' -- 'The rationale behind this behaviour lies with a number of ' -- 'special\n' -- 'methods such as "__hash__()" and "__repr__()" that are ' -- 'implemented by\n' -- 'all objects, including type objects. If the implicit lookup ' -- 'of these\n' -- 'methods used the conventional lookup process, they would ' -- 'fail when\n' -- 'invoked on the type object itself:\n' -- '\n' -- ' >>> 1 .__hash__() == hash(1)\n' -- ' True\n' -- ' >>> int.__hash__() == hash(int)\n' -- ' Traceback (most recent call last):\n' -- ' File "", line 1, in \n' -- " TypeError: descriptor '__hash__' of 'int' object needs an " -- 'argument\n' -- '\n' -- 'Incorrectly attempting to invoke an unbound method of a ' -- 'class in this\n' -- 'way is sometimes referred to as ‘metaclass confusion’, and ' -- 'is avoided\n' -- 'by bypassing the instance when looking up special methods:\n' -- '\n' -- ' >>> type(1).__hash__(1) == hash(1)\n' -- ' True\n' -- ' >>> type(int).__hash__(int) == hash(int)\n' -- ' True\n' -- '\n' -- 'In addition to bypassing any instance attributes in the ' -- 'interest of\n' -- 'correctness, implicit special method lookup generally also ' -- 'bypasses\n' -- 'the "__getattribute__()" method even of the object’s ' -- 'metaclass:\n' -- '\n' -- ' >>> class Meta(type):\n' -- ' ... def __getattribute__(*args):\n' -- ' ... print("Metaclass getattribute invoked")\n' -- ' ... return type.__getattribute__(*args)\n' -- ' ...\n' -- ' >>> class C(object, metaclass=Meta):\n' -- ' ... def __len__(self):\n' -- ' ... return 10\n' -- ' ... def __getattribute__(*args):\n' -- ' ... print("Class getattribute invoked")\n' -- ' ... return object.__getattribute__(*args)\n' -- ' ...\n' -- ' >>> c = C()\n' -- ' >>> c.__len__() # Explicit lookup via ' -- 'instance\n' -- ' Class getattribute invoked\n' -- ' 10\n' -- ' >>> type(c).__len__(c) # Explicit lookup via ' -- 'type\n' -- ' Metaclass getattribute invoked\n' -- ' 10\n' -- ' >>> len(c) # Implicit lookup\n' -- ' 10\n' -- '\n' -- 'Bypassing the "__getattribute__()" machinery in this fashion ' -- 'provides\n' -- 'significant scope for speed optimisations within the ' -- 'interpreter, at\n' -- 'the cost of some flexibility in the handling of special ' -- 'methods (the\n' -- 'special method *must* be set on the class object itself in ' -- 'order to be\n' -- 'consistently invoked by the interpreter).\n', -- 'string-methods': 'String Methods\n' -- '**************\n' -- '\n' -- 'Strings implement all of the common sequence operations, ' -- 'along with\n' -- 'the additional methods described below.\n' -- '\n' -- 'Strings also support two styles of string formatting, one ' -- 'providing a\n' -- 'large degree of flexibility and customization (see ' -- '"str.format()",\n' -- 'Format String Syntax and Custom String Formatting) and the ' -- 'other based\n' -- 'on C "printf" style formatting that handles a narrower ' -- 'range of types\n' -- 'and is slightly harder to use correctly, but is often ' -- 'faster for the\n' -- 'cases it can handle (printf-style String Formatting).\n' -- '\n' -- 'The Text Processing Services section of the standard ' -- 'library covers a\n' -- 'number of other modules that provide various text related ' -- 'utilities\n' -- '(including regular expression support in the "re" ' -- 'module).\n' -- '\n' -- 'str.capitalize()\n' -- '\n' -- ' Return a copy of the string with its first character ' -- 'capitalized\n' -- ' and the rest lowercased.\n' -- '\n' -- ' Changed in version 3.8: The first character is now put ' -- 'into\n' -- ' titlecase rather than uppercase. This means that ' -- 'characters like\n' -- ' digraphs will only have their first letter capitalized, ' -- 'instead of\n' -- ' the full character.\n' -- '\n' -- 'str.casefold()\n' -- '\n' -- ' Return a casefolded copy of the string. Casefolded ' -- 'strings may be\n' -- ' used for caseless matching.\n' -- '\n' -- ' Casefolding is similar to lowercasing but more ' -- 'aggressive because\n' -- ' it is intended to remove all case distinctions in a ' -- 'string. For\n' -- ' example, the German lowercase letter "\'ß\'" is ' -- 'equivalent to ""ss"".\n' -- ' Since it is already lowercase, "lower()" would do ' -- 'nothing to "\'ß\'";\n' -- ' "casefold()" converts it to ""ss"".\n' -- '\n' -- ' The casefolding algorithm is described in section 3.13 ' -- '‘Default\n' -- ' Case Folding’ of the Unicode Standard.\n' -- '\n' -- ' Added in version 3.3.\n' -- '\n' -- 'str.center(width[, fillchar])\n' -- '\n' -- ' Return centered in a string of length *width*. Padding ' -- 'is done\n' -- ' using the specified *fillchar* (default is an ASCII ' -- 'space). The\n' -- ' original string is returned if *width* is less than or ' -- 'equal to\n' -- ' "len(s)".\n' -- '\n' -- 'str.count(sub[, start[, end]])\n' -- '\n' -- ' Return the number of non-overlapping occurrences of ' -- 'substring *sub*\n' -- ' in the range [*start*, *end*]. Optional arguments ' -- '*start* and\n' -- ' *end* are interpreted as in slice notation.\n' -- '\n' -- ' If *sub* is empty, returns the number of empty strings ' -- 'between\n' -- ' characters which is the length of the string plus one.\n' -- '\n' -- "str.encode(encoding='utf-8', errors='strict')\n" -- '\n' -- ' Return the string encoded to "bytes".\n' -- '\n' -- ' *encoding* defaults to "\'utf-8\'"; see Standard ' -- 'Encodings for\n' -- ' possible values.\n' -- '\n' -- ' *errors* controls how encoding errors are handled. If ' -- '"\'strict\'"\n' -- ' (the default), a "UnicodeError" exception is raised. ' -- 'Other possible\n' -- ' values are "\'ignore\'", "\'replace\'", ' -- '"\'xmlcharrefreplace\'",\n' -- ' "\'backslashreplace\'" and any other name registered ' -- 'via\n' -- ' "codecs.register_error()". See Error Handlers for ' -- 'details.\n' -- '\n' -- ' For performance reasons, the value of *errors* is not ' -- 'checked for\n' -- ' validity unless an encoding error actually occurs, ' -- 'Python\n' -- ' Development Mode is enabled or a debug build is used.\n' -- '\n' -- ' Changed in version 3.1: Added support for keyword ' -- 'arguments.\n' -- '\n' -- ' Changed in version 3.9: The value of the *errors* ' -- 'argument is now\n' -- ' checked in Python Development Mode and in debug mode.\n' -- '\n' -- 'str.endswith(suffix[, start[, end]])\n' -- '\n' -- ' Return "True" if the string ends with the specified ' -- '*suffix*,\n' -- ' otherwise return "False". *suffix* can also be a tuple ' -- 'of suffixes\n' -- ' to look for. With optional *start*, test beginning at ' -- 'that\n' -- ' position. With optional *end*, stop comparing at that ' -- 'position.\n' -- '\n' -- 'str.expandtabs(tabsize=8)\n' -- '\n' -- ' Return a copy of the string where all tab characters ' -- 'are replaced\n' -- ' by one or more spaces, depending on the current column ' -- 'and the\n' -- ' given tab size. Tab positions occur every *tabsize* ' -- 'characters\n' -- ' (default is 8, giving tab positions at columns 0, 8, 16 ' -- 'and so on).\n' -- ' To expand the string, the current column is set to zero ' -- 'and the\n' -- ' string is examined character by character. If the ' -- 'character is a\n' -- ' tab ("\\t"), one or more space characters are inserted ' -- 'in the result\n' -- ' until the current column is equal to the next tab ' -- 'position. (The\n' -- ' tab character itself is not copied.) If the character ' -- 'is a newline\n' -- ' ("\\n") or return ("\\r"), it is copied and the current ' -- 'column is\n' -- ' reset to zero. Any other character is copied unchanged ' -- 'and the\n' -- ' current column is incremented by one regardless of how ' -- 'the\n' -- ' character is represented when printed.\n' -- '\n' -- " >>> '01\\t012\\t0123\\t01234'.expandtabs()\n" -- " '01 012 0123 01234'\n" -- " >>> '01\\t012\\t0123\\t01234'.expandtabs(4)\n" -- " '01 012 0123 01234'\n" -- '\n' -- 'str.find(sub[, start[, end]])\n' -- '\n' -- ' Return the lowest index in the string where substring ' -- '*sub* is\n' -- ' found within the slice "s[start:end]". Optional ' -- 'arguments *start*\n' -- ' and *end* are interpreted as in slice notation. Return ' -- '"-1" if\n' -- ' *sub* is not found.\n' -- '\n' -- ' Note:\n' -- '\n' -- ' The "find()" method should be used only if you need ' -- 'to know the\n' -- ' position of *sub*. To check if *sub* is a substring ' -- 'or not, use\n' -- ' the "in" operator:\n' -- '\n' -- " >>> 'Py' in 'Python'\n" -- ' True\n' -- '\n' -- 'str.format(*args, **kwargs)\n' -- '\n' -- ' Perform a string formatting operation. The string on ' -- 'which this\n' -- ' method is called can contain literal text or ' -- 'replacement fields\n' -- ' delimited by braces "{}". Each replacement field ' -- 'contains either\n' -- ' the numeric index of a positional argument, or the name ' -- 'of a\n' -- ' keyword argument. Returns a copy of the string where ' -- 'each\n' -- ' replacement field is replaced with the string value of ' -- 'the\n' -- ' corresponding argument.\n' -- '\n' -- ' >>> "The sum of 1 + 2 is {0}".format(1+2)\n' -- " 'The sum of 1 + 2 is 3'\n" -- '\n' -- ' See Format String Syntax for a description of the ' -- 'various\n' -- ' formatting options that can be specified in format ' -- 'strings.\n' -- '\n' -- ' Note:\n' -- '\n' -- ' When formatting a number ("int", "float", "complex",\n' -- ' "decimal.Decimal" and subclasses) with the "n" type ' -- '(ex:\n' -- ' "\'{:n}\'.format(1234)"), the function temporarily ' -- 'sets the\n' -- ' "LC_CTYPE" locale to the "LC_NUMERIC" locale to ' -- 'decode\n' -- ' "decimal_point" and "thousands_sep" fields of ' -- '"localeconv()" if\n' -- ' they are non-ASCII or longer than 1 byte, and the ' -- '"LC_NUMERIC"\n' -- ' locale is different than the "LC_CTYPE" locale. This ' -- 'temporary\n' -- ' change affects other threads.\n' -- '\n' -- ' Changed in version 3.7: When formatting a number with ' -- 'the "n" type,\n' -- ' the function sets temporarily the "LC_CTYPE" locale to ' -- 'the\n' -- ' "LC_NUMERIC" locale in some cases.\n' -- '\n' -- 'str.format_map(mapping, /)\n' -- '\n' -- ' Similar to "str.format(**mapping)", except that ' -- '"mapping" is used\n' -- ' directly and not copied to a "dict". This is useful if ' -- 'for example\n' -- ' "mapping" is a dict subclass:\n' -- '\n' -- ' >>> class Default(dict):\n' -- ' ... def __missing__(self, key):\n' -- ' ... return key\n' -- ' ...\n' -- " >>> '{name} was born in " -- "{country}'.format_map(Default(name='Guido'))\n" -- " 'Guido was born in country'\n" -- '\n' -- ' Added in version 3.2.\n' -- '\n' -- 'str.index(sub[, start[, end]])\n' -- '\n' -- ' Like "find()", but raise "ValueError" when the ' -- 'substring is not\n' -- ' found.\n' -- '\n' -- 'str.isalnum()\n' -- '\n' -- ' Return "True" if all characters in the string are ' -- 'alphanumeric and\n' -- ' there is at least one character, "False" otherwise. A ' -- 'character\n' -- ' "c" is alphanumeric if one of the following returns ' -- '"True":\n' -- ' "c.isalpha()", "c.isdecimal()", "c.isdigit()", or ' -- '"c.isnumeric()".\n' -- '\n' -- 'str.isalpha()\n' -- '\n' -- ' Return "True" if all characters in the string are ' -- 'alphabetic and\n' -- ' there is at least one character, "False" otherwise. ' -- 'Alphabetic\n' -- ' characters are those characters defined in the Unicode ' -- 'character\n' -- ' database as “Letterâ€, i.e., those with general category ' -- 'property\n' -- ' being one of “Lmâ€, “Ltâ€, “Luâ€, “Llâ€, or “Loâ€. Note ' -- 'that this is\n' -- ' different from the Alphabetic property defined in the ' -- 'section 4.10\n' -- ' ‘Letters, Alphabetic, and Ideographic’ of the Unicode ' -- 'Standard.\n' -- '\n' -- 'str.isascii()\n' -- '\n' -- ' Return "True" if the string is empty or all characters ' -- 'in the\n' -- ' string are ASCII, "False" otherwise. ASCII characters ' -- 'have code\n' -- ' points in the range U+0000-U+007F.\n' -- '\n' -- ' Added in version 3.7.\n' -- '\n' -- 'str.isdecimal()\n' -- '\n' -- ' Return "True" if all characters in the string are ' -- 'decimal\n' -- ' characters and there is at least one character, "False" ' -- 'otherwise.\n' -- ' Decimal characters are those that can be used to form ' -- 'numbers in\n' -- ' base 10, e.g. U+0660, ARABIC-INDIC DIGIT ZERO. ' -- 'Formally a decimal\n' -- ' character is a character in the Unicode General ' -- 'Category “Ndâ€.\n' -- '\n' -- 'str.isdigit()\n' -- '\n' -- ' Return "True" if all characters in the string are ' -- 'digits and there\n' -- ' is at least one character, "False" otherwise. Digits ' -- 'include\n' -- ' decimal characters and digits that need special ' -- 'handling, such as\n' -- ' the compatibility superscript digits. This covers ' -- 'digits which\n' -- ' cannot be used to form numbers in base 10, like the ' -- 'Kharosthi\n' -- ' numbers. Formally, a digit is a character that has the ' -- 'property\n' -- ' value Numeric_Type=Digit or Numeric_Type=Decimal.\n' -- '\n' -- 'str.isidentifier()\n' -- '\n' -- ' Return "True" if the string is a valid identifier ' -- 'according to the\n' -- ' language definition, section Identifiers and keywords.\n' -- '\n' -- ' "keyword.iskeyword()" can be used to test whether ' -- 'string "s" is a\n' -- ' reserved identifier, such as "def" and "class".\n' -- '\n' -- ' Example:\n' -- '\n' -- ' >>> from keyword import iskeyword\n' -- '\n' -- " >>> 'hello'.isidentifier(), iskeyword('hello')\n" -- ' (True, False)\n' -- " >>> 'def'.isidentifier(), iskeyword('def')\n" -- ' (True, True)\n' -- '\n' -- 'str.islower()\n' -- '\n' -- ' Return "True" if all cased characters [4] in the string ' -- 'are\n' -- ' lowercase and there is at least one cased character, ' -- '"False"\n' -- ' otherwise.\n' -- '\n' -- 'str.isnumeric()\n' -- '\n' -- ' Return "True" if all characters in the string are ' -- 'numeric\n' -- ' characters, and there is at least one character, ' -- '"False" otherwise.\n' -- ' Numeric characters include digit characters, and all ' -- 'characters\n' -- ' that have the Unicode numeric value property, e.g. ' -- 'U+2155, VULGAR\n' -- ' FRACTION ONE FIFTH. Formally, numeric characters are ' -- 'those with\n' -- ' the property value Numeric_Type=Digit, ' -- 'Numeric_Type=Decimal or\n' -- ' Numeric_Type=Numeric.\n' -- '\n' -- 'str.isprintable()\n' -- '\n' -- ' Return "True" if all characters in the string are ' -- 'printable or the\n' -- ' string is empty, "False" otherwise. Nonprintable ' -- 'characters are\n' -- ' those characters defined in the Unicode character ' -- 'database as\n' -- ' “Other†or “Separatorâ€, excepting the ASCII space ' -- '(0x20) which is\n' -- ' considered printable. (Note that printable characters ' -- 'in this\n' -- ' context are those which should not be escaped when ' -- '"repr()" is\n' -- ' invoked on a string. It has no bearing on the handling ' -- 'of strings\n' -- ' written to "sys.stdout" or "sys.stderr".)\n' -- '\n' -- 'str.isspace()\n' -- '\n' -- ' Return "True" if there are only whitespace characters ' -- 'in the string\n' -- ' and there is at least one character, "False" ' -- 'otherwise.\n' -- '\n' -- ' A character is *whitespace* if in the Unicode character ' -- 'database\n' -- ' (see "unicodedata"), either its general category is ' -- '"Zs"\n' -- ' (“Separator, spaceâ€), or its bidirectional class is one ' -- 'of "WS",\n' -- ' "B", or "S".\n' -- '\n' -- 'str.istitle()\n' -- '\n' -- ' Return "True" if the string is a titlecased string and ' -- 'there is at\n' -- ' least one character, for example uppercase characters ' -- 'may only\n' -- ' follow uncased characters and lowercase characters only ' -- 'cased ones.\n' -- ' Return "False" otherwise.\n' -- '\n' -- 'str.isupper()\n' -- '\n' -- ' Return "True" if all cased characters [4] in the string ' -- 'are\n' -- ' uppercase and there is at least one cased character, ' -- '"False"\n' -- ' otherwise.\n' -- '\n' -- " >>> 'BANANA'.isupper()\n" -- ' True\n' -- " >>> 'banana'.isupper()\n" -- ' False\n' -- " >>> 'baNana'.isupper()\n" -- ' False\n' -- " >>> ' '.isupper()\n" -- ' False\n' -- '\n' -- 'str.join(iterable)\n' -- '\n' -- ' Return a string which is the concatenation of the ' -- 'strings in\n' -- ' *iterable*. A "TypeError" will be raised if there are ' -- 'any non-\n' -- ' string values in *iterable*, including "bytes" ' -- 'objects. The\n' -- ' separator between elements is the string providing this ' -- 'method.\n' -- '\n' -- 'str.ljust(width[, fillchar])\n' -- '\n' -- ' Return the string left justified in a string of length ' -- '*width*.\n' -- ' Padding is done using the specified *fillchar* (default ' -- 'is an ASCII\n' -- ' space). The original string is returned if *width* is ' -- 'less than or\n' -- ' equal to "len(s)".\n' -- '\n' -- 'str.lower()\n' -- '\n' -- ' Return a copy of the string with all the cased ' -- 'characters [4]\n' -- ' converted to lowercase.\n' -- '\n' -- ' The lowercasing algorithm used is described in section ' -- '3.13\n' -- ' ‘Default Case Folding’ of the Unicode Standard.\n' -- '\n' -- 'str.lstrip([chars])\n' -- '\n' -- ' Return a copy of the string with leading characters ' -- 'removed. The\n' -- ' *chars* argument is a string specifying the set of ' -- 'characters to be\n' -- ' removed. If omitted or "None", the *chars* argument ' -- 'defaults to\n' -- ' removing whitespace. The *chars* argument is not a ' -- 'prefix; rather,\n' -- ' all combinations of its values are stripped:\n' -- '\n' -- " >>> ' spacious '.lstrip()\n" -- " 'spacious '\n" -- " >>> 'www.example.com'.lstrip('cmowz.')\n" -- " 'example.com'\n" -- '\n' -- ' See "str.removeprefix()" for a method that will remove ' -- 'a single\n' -- ' prefix string rather than all of a set of characters. ' -- 'For example:\n' -- '\n' -- " >>> 'Arthur: three!'.lstrip('Arthur: ')\n" -- " 'ee!'\n" -- " >>> 'Arthur: three!'.removeprefix('Arthur: ')\n" -- " 'three!'\n" -- '\n' -- 'static str.maketrans(x[, y[, z]])\n' -- '\n' -- ' This static method returns a translation table usable ' -- 'for\n' -- ' "str.translate()".\n' -- '\n' -- ' If there is only one argument, it must be a dictionary ' -- 'mapping\n' -- ' Unicode ordinals (integers) or characters (strings of ' -- 'length 1) to\n' -- ' Unicode ordinals, strings (of arbitrary lengths) or ' -- '"None".\n' -- ' Character keys will then be converted to ordinals.\n' -- '\n' -- ' If there are two arguments, they must be strings of ' -- 'equal length,\n' -- ' and in the resulting dictionary, each character in x ' -- 'will be mapped\n' -- ' to the character at the same position in y. If there ' -- 'is a third\n' -- ' argument, it must be a string, whose characters will be ' -- 'mapped to\n' -- ' "None" in the result.\n' -- '\n' -- 'str.partition(sep)\n' -- '\n' -- ' Split the string at the first occurrence of *sep*, and ' -- 'return a\n' -- ' 3-tuple containing the part before the separator, the ' -- 'separator\n' -- ' itself, and the part after the separator. If the ' -- 'separator is not\n' -- ' found, return a 3-tuple containing the string itself, ' -- 'followed by\n' -- ' two empty strings.\n' -- '\n' -- 'str.removeprefix(prefix, /)\n' -- '\n' -- ' If the string starts with the *prefix* string, return\n' -- ' "string[len(prefix):]". Otherwise, return a copy of the ' -- 'original\n' -- ' string:\n' -- '\n' -- " >>> 'TestHook'.removeprefix('Test')\n" -- " 'Hook'\n" -- " >>> 'BaseTestCase'.removeprefix('Test')\n" -- " 'BaseTestCase'\n" -- '\n' -- ' Added in version 3.9.\n' -- '\n' -- 'str.removesuffix(suffix, /)\n' -- '\n' -- ' If the string ends with the *suffix* string and that ' -- '*suffix* is\n' -- ' not empty, return "string[:-len(suffix)]". Otherwise, ' -- 'return a copy\n' -- ' of the original string:\n' -- '\n' -- " >>> 'MiscTests'.removesuffix('Tests')\n" -- " 'Misc'\n" -- " >>> 'TmpDirMixin'.removesuffix('Tests')\n" -- " 'TmpDirMixin'\n" -- '\n' -- ' Added in version 3.9.\n' -- '\n' -- 'str.replace(old, new, count=-1)\n' -- '\n' -- ' Return a copy of the string with all occurrences of ' -- 'substring *old*\n' -- ' replaced by *new*. If *count* is given, only the first ' -- '*count*\n' -- ' occurrences are replaced. If *count* is not specified ' -- 'or "-1", then\n' -- ' all occurrences are replaced.\n' -- '\n' -- ' Changed in version 3.13: *count* is now supported as a ' -- 'keyword\n' -- ' argument.\n' -- '\n' -- 'str.rfind(sub[, start[, end]])\n' -- '\n' -- ' Return the highest index in the string where substring ' -- '*sub* is\n' -- ' found, such that *sub* is contained within ' -- '"s[start:end]".\n' -- ' Optional arguments *start* and *end* are interpreted as ' -- 'in slice\n' -- ' notation. Return "-1" on failure.\n' -- '\n' -- 'str.rindex(sub[, start[, end]])\n' -- '\n' -- ' Like "rfind()" but raises "ValueError" when the ' -- 'substring *sub* is\n' -- ' not found.\n' -- '\n' -- 'str.rjust(width[, fillchar])\n' -- '\n' -- ' Return the string right justified in a string of length ' -- '*width*.\n' -- ' Padding is done using the specified *fillchar* (default ' -- 'is an ASCII\n' -- ' space). The original string is returned if *width* is ' -- 'less than or\n' -- ' equal to "len(s)".\n' -- '\n' -- 'str.rpartition(sep)\n' -- '\n' -- ' Split the string at the last occurrence of *sep*, and ' -- 'return a\n' -- ' 3-tuple containing the part before the separator, the ' -- 'separator\n' -- ' itself, and the part after the separator. If the ' -- 'separator is not\n' -- ' found, return a 3-tuple containing two empty strings, ' -- 'followed by\n' -- ' the string itself.\n' -- '\n' -- 'str.rsplit(sep=None, maxsplit=-1)\n' -- '\n' -- ' Return a list of the words in the string, using *sep* ' -- 'as the\n' -- ' delimiter string. If *maxsplit* is given, at most ' -- '*maxsplit* splits\n' -- ' are done, the *rightmost* ones. If *sep* is not ' -- 'specified or\n' -- ' "None", any whitespace string is a separator. Except ' -- 'for splitting\n' -- ' from the right, "rsplit()" behaves like "split()" which ' -- 'is\n' -- ' described in detail below.\n' -- '\n' -- 'str.rstrip([chars])\n' -- '\n' -- ' Return a copy of the string with trailing characters ' -- 'removed. The\n' -- ' *chars* argument is a string specifying the set of ' -- 'characters to be\n' -- ' removed. If omitted or "None", the *chars* argument ' -- 'defaults to\n' -- ' removing whitespace. The *chars* argument is not a ' -- 'suffix; rather,\n' -- ' all combinations of its values are stripped:\n' -- '\n' -- " >>> ' spacious '.rstrip()\n" -- " ' spacious'\n" -- " >>> 'mississippi'.rstrip('ipz')\n" -- " 'mississ'\n" -- '\n' -- ' See "str.removesuffix()" for a method that will remove ' -- 'a single\n' -- ' suffix string rather than all of a set of characters. ' -- 'For example:\n' -- '\n' -- " >>> 'Monty Python'.rstrip(' Python')\n" -- " 'M'\n" -- " >>> 'Monty Python'.removesuffix(' Python')\n" -- " 'Monty'\n" -- '\n' -- 'str.split(sep=None, maxsplit=-1)\n' -- '\n' -- ' Return a list of the words in the string, using *sep* ' -- 'as the\n' -- ' delimiter string. If *maxsplit* is given, at most ' -- '*maxsplit*\n' -- ' splits are done (thus, the list will have at most ' -- '"maxsplit+1"\n' -- ' elements). If *maxsplit* is not specified or "-1", ' -- 'then there is\n' -- ' no limit on the number of splits (all possible splits ' -- 'are made).\n' -- '\n' -- ' If *sep* is given, consecutive delimiters are not ' -- 'grouped together\n' -- ' and are deemed to delimit empty strings (for example,\n' -- ' "\'1,,2\'.split(\',\')" returns "[\'1\', \'\', ' -- '\'2\']"). The *sep* argument\n' -- ' may consist of multiple characters as a single ' -- 'delimiter (to split\n' -- ' with multiple delimiters, use "re.split()"). Splitting ' -- 'an empty\n' -- ' string with a specified separator returns "[\'\']".\n' -- '\n' -- ' For example:\n' -- '\n' -- " >>> '1,2,3'.split(',')\n" -- " ['1', '2', '3']\n" -- " >>> '1,2,3'.split(',', maxsplit=1)\n" -- " ['1', '2,3']\n" -- " >>> '1,2,,3,'.split(',')\n" -- " ['1', '2', '', '3', '']\n" -- " >>> '1<>2<>3<4'.split('<>')\n" -- " ['1', '2', '3<4']\n" -- '\n' -- ' If *sep* is not specified or is "None", a different ' -- 'splitting\n' -- ' algorithm is applied: runs of consecutive whitespace ' -- 'are regarded\n' -- ' as a single separator, and the result will contain no ' -- 'empty strings\n' -- ' at the start or end if the string has leading or ' -- 'trailing\n' -- ' whitespace. Consequently, splitting an empty string or ' -- 'a string\n' -- ' consisting of just whitespace with a "None" separator ' -- 'returns "[]".\n' -- '\n' -- ' For example:\n' -- '\n' -- " >>> '1 2 3'.split()\n" -- " ['1', '2', '3']\n" -- " >>> '1 2 3'.split(maxsplit=1)\n" -- " ['1', '2 3']\n" -- " >>> ' 1 2 3 '.split()\n" -- " ['1', '2', '3']\n" -- '\n' -- 'str.splitlines(keepends=False)\n' -- '\n' -- ' Return a list of the lines in the string, breaking at ' -- 'line\n' -- ' boundaries. Line breaks are not included in the ' -- 'resulting list\n' -- ' unless *keepends* is given and true.\n' -- '\n' -- ' This method splits on the following line boundaries. ' -- 'In\n' -- ' particular, the boundaries are a superset of *universal ' -- 'newlines*.\n' -- '\n' -- ' ' -- '+-------------------------+-------------------------------+\n' -- ' | Representation | ' -- 'Description |\n' -- ' ' -- '|=========================|===============================|\n' -- ' | "\\n" | Line ' -- 'Feed |\n' -- ' ' -- '+-------------------------+-------------------------------+\n' -- ' | "\\r" | Carriage ' -- 'Return |\n' -- ' ' -- '+-------------------------+-------------------------------+\n' -- ' | "\\r\\n" | Carriage Return + Line ' -- 'Feed |\n' -- ' ' -- '+-------------------------+-------------------------------+\n' -- ' | "\\v" or "\\x0b" | Line ' -- 'Tabulation |\n' -- ' ' -- '+-------------------------+-------------------------------+\n' -- ' | "\\f" or "\\x0c" | Form ' -- 'Feed |\n' -- ' ' -- '+-------------------------+-------------------------------+\n' -- ' | "\\x1c" | File ' -- 'Separator |\n' -- ' ' -- '+-------------------------+-------------------------------+\n' -- ' | "\\x1d" | Group ' -- 'Separator |\n' -- ' ' -- '+-------------------------+-------------------------------+\n' -- ' | "\\x1e" | Record ' -- 'Separator |\n' -- ' ' -- '+-------------------------+-------------------------------+\n' -- ' | "\\x85" | Next Line (C1 Control ' -- 'Code) |\n' -- ' ' -- '+-------------------------+-------------------------------+\n' -- ' | "\\u2028" | Line ' -- 'Separator |\n' -- ' ' -- '+-------------------------+-------------------------------+\n' -- ' | "\\u2029" | Paragraph ' -- 'Separator |\n' -- ' ' -- '+-------------------------+-------------------------------+\n' -- '\n' -- ' Changed in version 3.2: "\\v" and "\\f" added to list ' -- 'of line\n' -- ' boundaries.\n' -- '\n' -- ' For example:\n' -- '\n' -- " >>> 'ab c\\n\\nde fg\\rkl\\r\\n'.splitlines()\n" -- " ['ab c', '', 'de fg', 'kl']\n" -- " >>> 'ab c\\n\\nde " -- "fg\\rkl\\r\\n'.splitlines(keepends=True)\n" -- " ['ab c\\n', '\\n', 'de fg\\r', 'kl\\r\\n']\n" -- '\n' -- ' Unlike "split()" when a delimiter string *sep* is ' -- 'given, this\n' -- ' method returns an empty list for the empty string, and ' -- 'a terminal\n' -- ' line break does not result in an extra line:\n' -- '\n' -- ' >>> "".splitlines()\n' -- ' []\n' -- ' >>> "One line\\n".splitlines()\n' -- " ['One line']\n" -- '\n' -- ' For comparison, "split(\'\\n\')" gives:\n' -- '\n' -- " >>> ''.split('\\n')\n" -- " ['']\n" -- " >>> 'Two lines\\n'.split('\\n')\n" -- " ['Two lines', '']\n" -- '\n' -- 'str.startswith(prefix[, start[, end]])\n' -- '\n' -- ' Return "True" if string starts with the *prefix*, ' -- 'otherwise return\n' -- ' "False". *prefix* can also be a tuple of prefixes to ' -- 'look for.\n' -- ' With optional *start*, test string beginning at that ' -- 'position.\n' -- ' With optional *end*, stop comparing string at that ' -- 'position.\n' -- '\n' -- 'str.strip([chars])\n' -- '\n' -- ' Return a copy of the string with the leading and ' -- 'trailing\n' -- ' characters removed. The *chars* argument is a string ' -- 'specifying the\n' -- ' set of characters to be removed. If omitted or "None", ' -- 'the *chars*\n' -- ' argument defaults to removing whitespace. The *chars* ' -- 'argument is\n' -- ' not a prefix or suffix; rather, all combinations of its ' -- 'values are\n' -- ' stripped:\n' -- '\n' -- " >>> ' spacious '.strip()\n" -- " 'spacious'\n" -- " >>> 'www.example.com'.strip('cmowz.')\n" -- " 'example'\n" -- '\n' -- ' The outermost leading and trailing *chars* argument ' -- 'values are\n' -- ' stripped from the string. Characters are removed from ' -- 'the leading\n' -- ' end until reaching a string character that is not ' -- 'contained in the\n' -- ' set of characters in *chars*. A similar action takes ' -- 'place on the\n' -- ' trailing end. For example:\n' -- '\n' -- " >>> comment_string = '#....... Section 3.2.1 Issue " -- "#32 .......'\n" -- " >>> comment_string.strip('.#! ')\n" -- " 'Section 3.2.1 Issue #32'\n" -- '\n' -- 'str.swapcase()\n' -- '\n' -- ' Return a copy of the string with uppercase characters ' -- 'converted to\n' -- ' lowercase and vice versa. Note that it is not ' -- 'necessarily true that\n' -- ' "s.swapcase().swapcase() == s".\n' -- '\n' -- 'str.title()\n' -- '\n' -- ' Return a titlecased version of the string where words ' -- 'start with an\n' -- ' uppercase character and the remaining characters are ' -- 'lowercase.\n' -- '\n' -- ' For example:\n' -- '\n' -- " >>> 'Hello world'.title()\n" -- " 'Hello World'\n" -- '\n' -- ' The algorithm uses a simple language-independent ' -- 'definition of a\n' -- ' word as groups of consecutive letters. The definition ' -- 'works in\n' -- ' many contexts but it means that apostrophes in ' -- 'contractions and\n' -- ' possessives form word boundaries, which may not be the ' -- 'desired\n' -- ' result:\n' -- '\n' -- ' >>> "they\'re bill\'s friends from the UK".title()\n' -- ' "They\'Re Bill\'S Friends From The Uk"\n' -- '\n' -- ' The "string.capwords()" function does not have this ' -- 'problem, as it\n' -- ' splits words on spaces only.\n' -- '\n' -- ' Alternatively, a workaround for apostrophes can be ' -- 'constructed\n' -- ' using regular expressions:\n' -- '\n' -- ' >>> import re\n' -- ' >>> def titlecase(s):\n' -- ' ... return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n' -- ' ... lambda mo: ' -- 'mo.group(0).capitalize(),\n' -- ' ... s)\n' -- ' ...\n' -- ' >>> titlecase("they\'re bill\'s friends.")\n' -- ' "They\'re Bill\'s Friends."\n' -- '\n' -- 'str.translate(table)\n' -- '\n' -- ' Return a copy of the string in which each character has ' -- 'been mapped\n' -- ' through the given translation table. The table must be ' -- 'an object\n' -- ' that implements indexing via "__getitem__()", typically ' -- 'a *mapping*\n' -- ' or *sequence*. When indexed by a Unicode ordinal (an ' -- 'integer), the\n' -- ' table object can do any of the following: return a ' -- 'Unicode ordinal\n' -- ' or a string, to map the character to one or more other ' -- 'characters;\n' -- ' return "None", to delete the character from the return ' -- 'string; or\n' -- ' raise a "LookupError" exception, to map the character ' -- 'to itself.\n' -- '\n' -- ' You can use "str.maketrans()" to create a translation ' -- 'map from\n' -- ' character-to-character mappings in different formats.\n' -- '\n' -- ' See also the "codecs" module for a more flexible ' -- 'approach to custom\n' -- ' character mappings.\n' -- '\n' -- 'str.upper()\n' -- '\n' -- ' Return a copy of the string with all the cased ' -- 'characters [4]\n' -- ' converted to uppercase. Note that ' -- '"s.upper().isupper()" might be\n' -- ' "False" if "s" contains uncased characters or if the ' -- 'Unicode\n' -- ' category of the resulting character(s) is not “Lu†' -- '(Letter,\n' -- ' uppercase), but e.g. “Lt†(Letter, titlecase).\n' -- '\n' -- ' The uppercasing algorithm used is described in section ' -- '3.13\n' -- ' ‘Default Case Folding’ of the Unicode Standard.\n' -- '\n' -- 'str.zfill(width)\n' -- '\n' -- ' Return a copy of the string left filled with ASCII ' -- '"\'0\'" digits to\n' -- ' make a string of length *width*. A leading sign prefix\n' -- ' ("\'+\'"/"\'-\'") is handled by inserting the padding ' -- '*after* the sign\n' -- ' character rather than before. The original string is ' -- 'returned if\n' -- ' *width* is less than or equal to "len(s)".\n' -- '\n' -- ' For example:\n' -- '\n' -- ' >>> "42".zfill(5)\n' -- " '00042'\n" -- ' >>> "-42".zfill(5)\n' -- " '-0042'\n", -- 'strings': 'String and Bytes literals\n' -- '*************************\n' -- '\n' -- 'String literals are described by the following lexical ' -- 'definitions:\n' -- '\n' -- ' stringliteral ::= [stringprefix](shortstring | longstring)\n' -- ' stringprefix ::= "r" | "u" | "R" | "U" | "f" | "F"\n' -- ' | "fr" | "Fr" | "fR" | "FR" | "rf" | "rF" | ' -- '"Rf" | "RF"\n' -- ' shortstring ::= "\'" shortstringitem* "\'" | \'"\' ' -- 'shortstringitem* \'"\'\n' -- ' longstring ::= "\'\'\'" longstringitem* "\'\'\'" | ' -- '\'"""\' longstringitem* \'"""\'\n' -- ' shortstringitem ::= shortstringchar | stringescapeseq\n' -- ' longstringitem ::= longstringchar | stringescapeseq\n' -- ' shortstringchar ::= \n' -- ' longstringchar ::= \n' -- ' stringescapeseq ::= "\\" \n' -- '\n' -- ' bytesliteral ::= bytesprefix(shortbytes | longbytes)\n' -- ' bytesprefix ::= "b" | "B" | "br" | "Br" | "bR" | "BR" | ' -- '"rb" | "rB" | "Rb" | "RB"\n' -- ' shortbytes ::= "\'" shortbytesitem* "\'" | \'"\' ' -- 'shortbytesitem* \'"\'\n' -- ' longbytes ::= "\'\'\'" longbytesitem* "\'\'\'" | \'"""\' ' -- 'longbytesitem* \'"""\'\n' -- ' shortbytesitem ::= shortbyteschar | bytesescapeseq\n' -- ' longbytesitem ::= longbyteschar | bytesescapeseq\n' -- ' shortbyteschar ::= \n' -- ' longbyteschar ::= \n' -- ' bytesescapeseq ::= "\\" \n' -- '\n' -- 'One syntactic restriction not indicated by these productions is ' -- 'that\n' -- 'whitespace is not allowed between the "stringprefix" or ' -- '"bytesprefix"\n' -- 'and the rest of the literal. The source character set is defined ' -- 'by\n' -- 'the encoding declaration; it is UTF-8 if no encoding declaration ' -- 'is\n' -- 'given in the source file; see section Encoding declarations.\n' -- '\n' -- 'In plain English: Both types of literals can be enclosed in ' -- 'matching\n' -- 'single quotes ("\'") or double quotes ("""). They can also be ' -- 'enclosed\n' -- 'in matching groups of three single or double quotes (these are\n' -- 'generally referred to as *triple-quoted strings*). The backslash ' -- '("\\")\n' -- 'character is used to give special meaning to otherwise ordinary\n' -- 'characters like "n", which means ‘newline’ when escaped ("\\n"). ' -- 'It can\n' -- 'also be used to escape characters that otherwise have a special\n' -- 'meaning, such as newline, backslash itself, or the quote ' -- 'character.\n' -- 'See escape sequences below for examples.\n' -- '\n' -- 'Bytes literals are always prefixed with "\'b\'" or "\'B\'"; they ' -- 'produce\n' -- 'an instance of the "bytes" type instead of the "str" type. They ' -- 'may\n' -- 'only contain ASCII characters; bytes with a numeric value of 128 ' -- 'or\n' -- 'greater must be expressed with escapes.\n' -- '\n' -- 'Both string and bytes literals may optionally be prefixed with a\n' -- 'letter "\'r\'" or "\'R\'"; such constructs are called *raw ' -- 'string\n' -- 'literals* and *raw bytes literals* respectively and treat ' -- 'backslashes\n' -- 'as literal characters. As a result, in raw string literals, ' -- '"\'\\U\'"\n' -- 'and "\'\\u\'" escapes are not treated specially.\n' -- '\n' -- 'Added in version 3.3: The "\'rb\'" prefix of raw bytes literals ' -- 'has been\n' -- 'added as a synonym of "\'br\'".Support for the unicode legacy ' -- 'literal\n' -- '("u\'value\'") was reintroduced to simplify the maintenance of ' -- 'dual\n' -- 'Python 2.x and 3.x codebases. See **PEP 414** for more ' -- 'information.\n' -- '\n' -- 'A string literal with "\'f\'" or "\'F\'" in its prefix is a ' -- '*formatted\n' -- 'string literal*; see f-strings. The "\'f\'" may be combined with ' -- '"\'r\'",\n' -- 'but not with "\'b\'" or "\'u\'", therefore raw formatted strings ' -- 'are\n' -- 'possible, but formatted bytes literals are not.\n' -- '\n' -- 'In triple-quoted literals, unescaped newlines and quotes are ' -- 'allowed\n' -- '(and are retained), except that three unescaped quotes in a row\n' -- 'terminate the literal. (A “quote†is the character used to open ' -- 'the\n' -- 'literal, i.e. either "\'" or """.)\n' -- '\n' -- '\n' -- 'Escape sequences\n' -- '================\n' -- '\n' -- 'Unless an "\'r\'" or "\'R\'" prefix is present, escape sequences ' -- 'in string\n' -- 'and bytes literals are interpreted according to rules similar to ' -- 'those\n' -- 'used by Standard C. The recognized escape sequences are:\n' -- '\n' -- '+---------------------------+-----------------------------------+---------+\n' -- '| Escape Sequence | Meaning | ' -- 'Notes |\n' -- '|===========================|===================================|=========|\n' -- '| "\\" | Backslash and newline ignored ' -- '| (1) |\n' -- '+---------------------------+-----------------------------------+---------+\n' -- '| "\\\\" | Backslash ' -- '("\\") | |\n' -- '+---------------------------+-----------------------------------+---------+\n' -- '| "\\\'" | Single quote ' -- '("\'") | |\n' -- '+---------------------------+-----------------------------------+---------+\n' -- '| "\\"" | Double quote (""") ' -- '| |\n' -- '+---------------------------+-----------------------------------+---------+\n' -- '| "\\a" | ASCII Bell (BEL) ' -- '| |\n' -- '+---------------------------+-----------------------------------+---------+\n' -- '| "\\b" | ASCII Backspace (BS) ' -- '| |\n' -- '+---------------------------+-----------------------------------+---------+\n' -- '| "\\f" | ASCII Formfeed (FF) ' -- '| |\n' -- '+---------------------------+-----------------------------------+---------+\n' -- '| "\\n" | ASCII Linefeed (LF) ' -- '| |\n' -- '+---------------------------+-----------------------------------+---------+\n' -- '| "\\r" | ASCII Carriage Return (CR) ' -- '| |\n' -- '+---------------------------+-----------------------------------+---------+\n' -- '| "\\t" | ASCII Horizontal Tab (TAB) ' -- '| |\n' -- '+---------------------------+-----------------------------------+---------+\n' -- '| "\\v" | ASCII Vertical Tab (VT) ' -- '| |\n' -- '+---------------------------+-----------------------------------+---------+\n' -- '| "\\*ooo*" | Character with octal value *ooo* ' -- '| (2,4) |\n' -- '+---------------------------+-----------------------------------+---------+\n' -- '| "\\x*hh*" | Character with hex value *hh* ' -- '| (3,4) |\n' -- '+---------------------------+-----------------------------------+---------+\n' -- '\n' -- 'Escape sequences only recognized in string literals are:\n' -- '\n' -- '+---------------------------+-----------------------------------+---------+\n' -- '| Escape Sequence | Meaning | ' -- 'Notes |\n' -- '|===========================|===================================|=========|\n' -- '| "\\N{*name*}" | Character named *name* in the ' -- '| (5) |\n' -- '| | Unicode database ' -- '| |\n' -- '+---------------------------+-----------------------------------+---------+\n' -- '| "\\u*xxxx*" | Character with 16-bit hex value ' -- '| (6) |\n' -- '| | *xxxx* ' -- '| |\n' -- '+---------------------------+-----------------------------------+---------+\n' -- '| "\\U*xxxxxxxx*" | Character with 32-bit hex value ' -- '| (7) |\n' -- '| | *xxxxxxxx* ' -- '| |\n' -- '+---------------------------+-----------------------------------+---------+\n' -- '\n' -- 'Notes:\n' -- '\n' -- '1. A backslash can be added at the end of a line to ignore the\n' -- ' newline:\n' -- '\n' -- " >>> 'This string will not include \\\n" -- " ... backslashes or newline characters.'\n" -- " 'This string will not include backslashes or newline " -- "characters.'\n" -- '\n' -- ' The same result can be achieved using triple-quoted strings, ' -- 'or\n' -- ' parentheses and string literal concatenation.\n' -- '\n' -- '2. As in Standard C, up to three octal digits are accepted.\n' -- '\n' -- ' Changed in version 3.11: Octal escapes with value larger than\n' -- ' "0o377" produce a "DeprecationWarning".\n' -- '\n' -- ' Changed in version 3.12: Octal escapes with value larger than\n' -- ' "0o377" produce a "SyntaxWarning". In a future Python version ' -- 'they\n' -- ' will be eventually a "SyntaxError".\n' -- '\n' -- '3. Unlike in Standard C, exactly two hex digits are required.\n' -- '\n' -- '4. In a bytes literal, hexadecimal and octal escapes denote the ' -- 'byte\n' -- ' with the given value. In a string literal, these escapes ' -- 'denote a\n' -- ' Unicode character with the given value.\n' -- '\n' -- '5. Changed in version 3.3: Support for name aliases [1] has been\n' -- ' added.\n' -- '\n' -- '6. Exactly four hex digits are required.\n' -- '\n' -- '7. Any Unicode character can be encoded this way. Exactly eight ' -- 'hex\n' -- ' digits are required.\n' -- '\n' -- 'Unlike Standard C, all unrecognized escape sequences are left in ' -- 'the\n' -- 'string unchanged, i.e., *the backslash is left in the result*. ' -- '(This\n' -- 'behavior is useful when debugging: if an escape sequence is ' -- 'mistyped,\n' -- 'the resulting output is more easily recognized as broken.) It is ' -- 'also\n' -- 'important to note that the escape sequences only recognized in ' -- 'string\n' -- 'literals fall into the category of unrecognized escapes for ' -- 'bytes\n' -- 'literals.\n' -- '\n' -- 'Changed in version 3.6: Unrecognized escape sequences produce a\n' -- '"DeprecationWarning".\n' -- '\n' -- 'Changed in version 3.12: Unrecognized escape sequences produce a\n' -- '"SyntaxWarning". In a future Python version they will be ' -- 'eventually a\n' -- '"SyntaxError".\n' -- '\n' -- 'Even in a raw literal, quotes can be escaped with a backslash, ' -- 'but the\n' -- 'backslash remains in the result; for example, "r"\\""" is a ' -- 'valid\n' -- 'string literal consisting of two characters: a backslash and a ' -- 'double\n' -- 'quote; "r"\\"" is not a valid string literal (even a raw string ' -- 'cannot\n' -- 'end in an odd number of backslashes). Specifically, *a raw ' -- 'literal\n' -- 'cannot end in a single backslash* (since the backslash would ' -- 'escape\n' -- 'the following quote character). Note also that a single ' -- 'backslash\n' -- 'followed by a newline is interpreted as those two characters as ' -- 'part\n' -- 'of the literal, *not* as a line continuation.\n', -- 'subscriptions': 'Subscriptions\n' -- '*************\n' -- '\n' -- 'The subscription of an instance of a container class will ' -- 'generally\n' -- 'select an element from the container. The subscription of a ' -- '*generic\n' -- 'class* will generally return a GenericAlias object.\n' -- '\n' -- ' subscription ::= primary "[" flexible_expression_list ' -- '"]"\n' -- '\n' -- 'When an object is subscripted, the interpreter will ' -- 'evaluate the\n' -- 'primary and the expression list.\n' -- '\n' -- 'The primary must evaluate to an object that supports ' -- 'subscription. An\n' -- 'object may support subscription through defining one or ' -- 'both of\n' -- '"__getitem__()" and "__class_getitem__()". When the primary ' -- 'is\n' -- 'subscripted, the evaluated result of the expression list ' -- 'will be\n' -- 'passed to one of these methods. For more details on when\n' -- '"__class_getitem__" is called instead of "__getitem__", ' -- 'see\n' -- '__class_getitem__ versus __getitem__.\n' -- '\n' -- 'If the expression list contains at least one comma, or if ' -- 'any of the\n' -- 'expressions are starred, the expression list will evaluate ' -- 'to a\n' -- '"tuple" containing the items of the expression list. ' -- 'Otherwise, the\n' -- 'expression list will evaluate to the value of the list’s ' -- 'sole member.\n' -- '\n' -- 'Changed in version 3.11: Expressions in an expression list ' -- 'may be\n' -- 'starred. See **PEP 646**.\n' -- '\n' -- 'For built-in objects, there are two types of objects that ' -- 'support\n' -- 'subscription via "__getitem__()":\n' -- '\n' -- '1. Mappings. If the primary is a *mapping*, the expression ' -- 'list must\n' -- ' evaluate to an object whose value is one of the keys of ' -- 'the\n' -- ' mapping, and the subscription selects the value in the ' -- 'mapping that\n' -- ' corresponds to that key. An example of a builtin mapping ' -- 'class is\n' -- ' the "dict" class.\n' -- '\n' -- '2. Sequences. If the primary is a *sequence*, the ' -- 'expression list must\n' -- ' evaluate to an "int" or a "slice" (as discussed in the ' -- 'following\n' -- ' section). Examples of builtin sequence classes include ' -- 'the "str",\n' -- ' "list" and "tuple" classes.\n' -- '\n' -- 'The formal syntax makes no special provision for negative ' -- 'indices in\n' -- '*sequences*. However, built-in sequences all provide a ' -- '"__getitem__()"\n' -- 'method that interprets negative indices by adding the ' -- 'length of the\n' -- 'sequence to the index so that, for example, "x[-1]" selects ' -- 'the last\n' -- 'item of "x". The resulting value must be a nonnegative ' -- 'integer less\n' -- 'than the number of items in the sequence, and the ' -- 'subscription selects\n' -- 'the item whose index is that value (counting from zero). ' -- 'Since the\n' -- 'support for negative indices and slicing occurs in the ' -- 'object’s\n' -- '"__getitem__()" method, subclasses overriding this method ' -- 'will need to\n' -- 'explicitly add that support.\n' -- '\n' -- 'A "string" is a special kind of sequence whose items are ' -- '*characters*.\n' -- 'A character is not a separate data type but a string of ' -- 'exactly one\n' -- 'character.\n', -- 'truth': 'Truth Value Testing\n' -- '*******************\n' -- '\n' -- 'Any object can be tested for truth value, for use in an "if" or\n' -- '"while" condition or as operand of the Boolean operations below.\n' -- '\n' -- 'By default, an object is considered true unless its class defines\n' -- 'either a "__bool__()" method that returns "False" or a "__len__()"\n' -- 'method that returns zero, when called with the object. [1] Here ' -- 'are\n' -- 'most of the built-in objects considered false:\n' -- '\n' -- '* constants defined to be false: "None" and "False"\n' -- '\n' -- '* zero of any numeric type: "0", "0.0", "0j", "Decimal(0)",\n' -- ' "Fraction(0, 1)"\n' -- '\n' -- '* empty sequences and collections: "\'\'", "()", "[]", "{}", ' -- '"set()",\n' -- ' "range(0)"\n' -- '\n' -- 'Operations and built-in functions that have a Boolean result ' -- 'always\n' -- 'return "0" or "False" for false and "1" or "True" for true, unless\n' -- 'otherwise stated. (Important exception: the Boolean operations ' -- '"or"\n' -- 'and "and" always return one of their operands.)\n', -- 'try': 'The "try" statement\n' -- '*******************\n' -- '\n' -- 'The "try" statement specifies exception handlers and/or cleanup code\n' -- 'for a group of statements:\n' -- '\n' -- ' try_stmt ::= try1_stmt | try2_stmt | try3_stmt\n' -- ' try1_stmt ::= "try" ":" suite\n' -- ' ("except" [expression ["as" identifier]] ":" ' -- 'suite)+\n' -- ' ["else" ":" suite]\n' -- ' ["finally" ":" suite]\n' -- ' try2_stmt ::= "try" ":" suite\n' -- ' ("except" "*" expression ["as" identifier] ":" ' -- 'suite)+\n' -- ' ["else" ":" suite]\n' -- ' ["finally" ":" suite]\n' -- ' try3_stmt ::= "try" ":" suite\n' -- ' "finally" ":" suite\n' -- '\n' -- 'Additional information on exceptions can be found in section\n' -- 'Exceptions, and information on using the "raise" statement to ' -- 'generate\n' -- 'exceptions may be found in section The raise statement.\n' -- '\n' -- '\n' -- '"except" clause\n' -- '===============\n' -- '\n' -- 'The "except" clause(s) specify one or more exception handlers. When ' -- 'no\n' -- 'exception occurs in the "try" clause, no exception handler is\n' -- 'executed. When an exception occurs in the "try" suite, a search for ' -- 'an\n' -- 'exception handler is started. This search inspects the "except"\n' -- 'clauses in turn until one is found that matches the exception. An\n' -- 'expression-less "except" clause, if present, must be last; it ' -- 'matches\n' -- 'any exception.\n' -- '\n' -- 'For an "except" clause with an expression, the expression must\n' -- 'evaluate to an exception type or a tuple of exception types. The\n' -- 'raised exception matches an "except" clause whose expression ' -- 'evaluates\n' -- 'to the class or a *non-virtual base class* of the exception object, ' -- 'or\n' -- 'to a tuple that contains such a class.\n' -- '\n' -- 'If no "except" clause matches the exception, the search for an\n' -- 'exception handler continues in the surrounding code and on the\n' -- 'invocation stack. [1]\n' -- '\n' -- 'If the evaluation of an expression in the header of an "except" ' -- 'clause\n' -- 'raises an exception, the original search for a handler is canceled ' -- 'and\n' -- 'a search starts for the new exception in the surrounding code and on\n' -- 'the call stack (it is treated as if the entire "try" statement ' -- 'raised\n' -- 'the exception).\n' -- '\n' -- 'When a matching "except" clause is found, the exception is assigned ' -- 'to\n' -- 'the target specified after the "as" keyword in that "except" clause,\n' -- 'if present, and the "except" clause’s suite is executed. All ' -- '"except"\n' -- 'clauses must have an executable block. When the end of this block is\n' -- 'reached, execution continues normally after the entire "try"\n' -- 'statement. (This means that if two nested handlers exist for the ' -- 'same\n' -- 'exception, and the exception occurs in the "try" clause of the inner\n' -- 'handler, the outer handler will not handle the exception.)\n' -- '\n' -- 'When an exception has been assigned using "as target", it is cleared\n' -- 'at the end of the "except" clause. This is as if\n' -- '\n' -- ' except E as N:\n' -- ' foo\n' -- '\n' -- 'was translated to\n' -- '\n' -- ' except E as N:\n' -- ' try:\n' -- ' foo\n' -- ' finally:\n' -- ' del N\n' -- '\n' -- 'This means the exception must be assigned to a different name to be\n' -- 'able to refer to it after the "except" clause. Exceptions are ' -- 'cleared\n' -- 'because with the traceback attached to them, they form a reference\n' -- 'cycle with the stack frame, keeping all locals in that frame alive\n' -- 'until the next garbage collection occurs.\n' -- '\n' -- 'Before an "except" clause’s suite is executed, the exception is ' -- 'stored\n' -- 'in the "sys" module, where it can be accessed from within the body ' -- 'of\n' -- 'the "except" clause by calling "sys.exception()". When leaving an\n' -- 'exception handler, the exception stored in the "sys" module is reset\n' -- 'to its previous value:\n' -- '\n' -- ' >>> print(sys.exception())\n' -- ' None\n' -- ' >>> try:\n' -- ' ... raise TypeError\n' -- ' ... except:\n' -- ' ... print(repr(sys.exception()))\n' -- ' ... try:\n' -- ' ... raise ValueError\n' -- ' ... except:\n' -- ' ... print(repr(sys.exception()))\n' -- ' ... print(repr(sys.exception()))\n' -- ' ...\n' -- ' TypeError()\n' -- ' ValueError()\n' -- ' TypeError()\n' -- ' >>> print(sys.exception())\n' -- ' None\n' -- '\n' -- '\n' -- '"except*" clause\n' -- '================\n' -- '\n' -- 'The "except*" clause(s) are used for handling "ExceptionGroup"s. The\n' -- 'exception type for matching is interpreted as in the case of ' -- '"except",\n' -- 'but in the case of exception groups we can have partial matches when\n' -- 'the type matches some of the exceptions in the group. This means ' -- 'that\n' -- 'multiple "except*" clauses can execute, each handling part of the\n' -- 'exception group. Each clause executes at most once and handles an\n' -- 'exception group of all matching exceptions. Each exception in the\n' -- 'group is handled by at most one "except*" clause, the first that\n' -- 'matches it.\n' -- '\n' -- ' >>> try:\n' -- ' ... raise ExceptionGroup("eg",\n' -- ' ... [ValueError(1), TypeError(2), OSError(3), ' -- 'OSError(4)])\n' -- ' ... except* TypeError as e:\n' -- " ... print(f'caught {type(e)} with nested {e.exceptions}')\n" -- ' ... except* OSError as e:\n' -- " ... print(f'caught {type(e)} with nested {e.exceptions}')\n" -- ' ...\n' -- " caught with nested (TypeError(2),)\n" -- " caught with nested (OSError(3), " -- 'OSError(4))\n' -- ' + Exception Group Traceback (most recent call last):\n' -- ' | File "", line 2, in \n' -- ' | ExceptionGroup: eg\n' -- ' +-+---------------- 1 ----------------\n' -- ' | ValueError: 1\n' -- ' +------------------------------------\n' -- '\n' -- 'Any remaining exceptions that were not handled by any "except*" ' -- 'clause\n' -- 'are re-raised at the end, along with all exceptions that were raised\n' -- 'from within the "except*" clauses. If this list contains more than ' -- 'one\n' -- 'exception to reraise, they are combined into an exception group.\n' -- '\n' -- 'If the raised exception is not an exception group and its type ' -- 'matches\n' -- 'one of the "except*" clauses, it is caught and wrapped by an ' -- 'exception\n' -- 'group with an empty message string.\n' -- '\n' -- ' >>> try:\n' -- ' ... raise BlockingIOError\n' -- ' ... except* BlockingIOError as e:\n' -- ' ... print(repr(e))\n' -- ' ...\n' -- " ExceptionGroup('', (BlockingIOError()))\n" -- '\n' -- 'An "except*" clause must have a matching expression; it cannot be\n' -- '"except*:". Furthermore, this expression cannot contain exception\n' -- 'group types, because that would have ambiguous semantics.\n' -- '\n' -- 'It is not possible to mix "except" and "except*" in the same "try".\n' -- '"break", "continue" and "return" cannot appear in an "except*" ' -- 'clause.\n' -- '\n' -- '\n' -- '"else" clause\n' -- '=============\n' -- '\n' -- 'The optional "else" clause is executed if the control flow leaves ' -- 'the\n' -- '"try" suite, no exception was raised, and no "return", "continue", ' -- 'or\n' -- '"break" statement was executed. Exceptions in the "else" clause are\n' -- 'not handled by the preceding "except" clauses.\n' -- '\n' -- '\n' -- '"finally" clause\n' -- '================\n' -- '\n' -- 'If "finally" is present, it specifies a ‘cleanup’ handler. The ' -- '"try"\n' -- 'clause is executed, including any "except" and "else" clauses. If ' -- 'an\n' -- 'exception occurs in any of the clauses and is not handled, the\n' -- 'exception is temporarily saved. The "finally" clause is executed. ' -- 'If\n' -- 'there is a saved exception it is re-raised at the end of the ' -- '"finally"\n' -- 'clause. If the "finally" clause raises another exception, the saved\n' -- 'exception is set as the context of the new exception. If the ' -- '"finally"\n' -- 'clause executes a "return", "break" or "continue" statement, the ' -- 'saved\n' -- 'exception is discarded:\n' -- '\n' -- ' >>> def f():\n' -- ' ... try:\n' -- ' ... 1/0\n' -- ' ... finally:\n' -- ' ... return 42\n' -- ' ...\n' -- ' >>> f()\n' -- ' 42\n' -- '\n' -- 'The exception information is not available to the program during\n' -- 'execution of the "finally" clause.\n' -- '\n' -- 'When a "return", "break" or "continue" statement is executed in the\n' -- '"try" suite of a "try"…"finally" statement, the "finally" clause is\n' -- 'also executed ‘on the way out.’\n' -- '\n' -- 'The return value of a function is determined by the last "return"\n' -- 'statement executed. Since the "finally" clause always executes, a\n' -- '"return" statement executed in the "finally" clause will always be ' -- 'the\n' -- 'last one executed:\n' -- '\n' -- ' >>> def foo():\n' -- ' ... try:\n' -- " ... return 'try'\n" -- ' ... finally:\n' -- " ... return 'finally'\n" -- ' ...\n' -- ' >>> foo()\n' -- " 'finally'\n" -- '\n' -- 'Changed in version 3.8: Prior to Python 3.8, a "continue" statement\n' -- 'was illegal in the "finally" clause due to a problem with the\n' -- 'implementation.\n', -- 'types': 'The standard type hierarchy\n' -- '***************************\n' -- '\n' -- 'Below is a list of the types that are built into Python. ' -- 'Extension\n' -- 'modules (written in C, Java, or other languages, depending on the\n' -- 'implementation) can define additional types. Future versions of\n' -- 'Python may add types to the type hierarchy (e.g., rational ' -- 'numbers,\n' -- 'efficiently stored arrays of integers, etc.), although such ' -- 'additions\n' -- 'will often be provided via the standard library instead.\n' -- '\n' -- 'Some of the type descriptions below contain a paragraph listing\n' -- '‘special attributes.’ These are attributes that provide access to ' -- 'the\n' -- 'implementation and are not intended for general use. Their ' -- 'definition\n' -- 'may change in the future.\n' -- '\n' -- '\n' -- 'None\n' -- '====\n' -- '\n' -- 'This type has a single value. There is a single object with this\n' -- 'value. This object is accessed through the built-in name "None". It ' -- 'is\n' -- 'used to signify the absence of a value in many situations, e.g., it ' -- 'is\n' -- 'returned from functions that don’t explicitly return anything. Its\n' -- 'truth value is false.\n' -- '\n' -- '\n' -- 'NotImplemented\n' -- '==============\n' -- '\n' -- 'This type has a single value. There is a single object with this\n' -- 'value. This object is accessed through the built-in name\n' -- '"NotImplemented". Numeric methods and rich comparison methods ' -- 'should\n' -- 'return this value if they do not implement the operation for the\n' -- 'operands provided. (The interpreter will then try the reflected\n' -- 'operation, or some other fallback, depending on the operator.) It\n' -- 'should not be evaluated in a boolean context.\n' -- '\n' -- 'See Implementing the arithmetic operations for more details.\n' -- '\n' -- 'Changed in version 3.9: Evaluating "NotImplemented" in a boolean\n' -- 'context was deprecated.\n' -- '\n' -- 'Changed in version 3.14: Evaluating "NotImplemented" in a boolean\n' -- 'context now raises a "TypeError". It previously evaluated to ' -- '"True"\n' -- 'and emitted a "DeprecationWarning" since Python 3.9.\n' -- '\n' -- '\n' -- 'Ellipsis\n' -- '========\n' -- '\n' -- 'This type has a single value. There is a single object with this\n' -- 'value. This object is accessed through the literal "..." or the ' -- 'built-\n' -- 'in name "Ellipsis". Its truth value is true.\n' -- '\n' -- '\n' -- '"numbers.Number"\n' -- '================\n' -- '\n' -- 'These are created by numeric literals and returned as results by\n' -- 'arithmetic operators and arithmetic built-in functions. Numeric\n' -- 'objects are immutable; once created their value never changes. ' -- 'Python\n' -- 'numbers are of course strongly related to mathematical numbers, ' -- 'but\n' -- 'subject to the limitations of numerical representation in ' -- 'computers.\n' -- '\n' -- 'The string representations of the numeric classes, computed by\n' -- '"__repr__()" and "__str__()", have the following properties:\n' -- '\n' -- '* They are valid numeric literals which, when passed to their ' -- 'class\n' -- ' constructor, produce an object having the value of the original\n' -- ' numeric.\n' -- '\n' -- '* The representation is in base 10, when possible.\n' -- '\n' -- '* Leading zeros, possibly excepting a single zero before a decimal\n' -- ' point, are not shown.\n' -- '\n' -- '* Trailing zeros, possibly excepting a single zero after a decimal\n' -- ' point, are not shown.\n' -- '\n' -- '* A sign is shown only when the number is negative.\n' -- '\n' -- 'Python distinguishes between integers, floating-point numbers, and\n' -- 'complex numbers:\n' -- '\n' -- '\n' -- '"numbers.Integral"\n' -- '------------------\n' -- '\n' -- 'These represent elements from the mathematical set of integers\n' -- '(positive and negative).\n' -- '\n' -- 'Note:\n' -- '\n' -- ' The rules for integer representation are intended to give the ' -- 'most\n' -- ' meaningful interpretation of shift and mask operations involving\n' -- ' negative integers.\n' -- '\n' -- 'There are two types of integers:\n' -- '\n' -- 'Integers ("int")\n' -- ' These represent numbers in an unlimited range, subject to ' -- 'available\n' -- ' (virtual) memory only. For the purpose of shift and mask\n' -- ' operations, a binary representation is assumed, and negative\n' -- ' numbers are represented in a variant of 2’s complement which ' -- 'gives\n' -- ' the illusion of an infinite string of sign bits extending to ' -- 'the\n' -- ' left.\n' -- '\n' -- 'Booleans ("bool")\n' -- ' These represent the truth values False and True. The two ' -- 'objects\n' -- ' representing the values "False" and "True" are the only Boolean\n' -- ' objects. The Boolean type is a subtype of the integer type, and\n' -- ' Boolean values behave like the values 0 and 1, respectively, in\n' -- ' almost all contexts, the exception being that when converted to ' -- 'a\n' -- ' string, the strings ""False"" or ""True"" are returned,\n' -- ' respectively.\n' -- '\n' -- '\n' -- '"numbers.Real" ("float")\n' -- '------------------------\n' -- '\n' -- 'These represent machine-level double precision floating-point ' -- 'numbers.\n' -- 'You are at the mercy of the underlying machine architecture (and C ' -- 'or\n' -- 'Java implementation) for the accepted range and handling of ' -- 'overflow.\n' -- 'Python does not support single-precision floating-point numbers; ' -- 'the\n' -- 'savings in processor and memory usage that are usually the reason ' -- 'for\n' -- 'using these are dwarfed by the overhead of using objects in Python, ' -- 'so\n' -- 'there is no reason to complicate the language with two kinds of\n' -- 'floating-point numbers.\n' -- '\n' -- '\n' -- '"numbers.Complex" ("complex")\n' -- '-----------------------------\n' -- '\n' -- 'These represent complex numbers as a pair of machine-level double\n' -- 'precision floating-point numbers. The same caveats apply as for\n' -- 'floating-point numbers. The real and imaginary parts of a complex\n' -- 'number "z" can be retrieved through the read-only attributes ' -- '"z.real"\n' -- 'and "z.imag".\n' -- '\n' -- '\n' -- 'Sequences\n' -- '=========\n' -- '\n' -- 'These represent finite ordered sets indexed by non-negative ' -- 'numbers.\n' -- 'The built-in function "len()" returns the number of items of a\n' -- 'sequence. When the length of a sequence is *n*, the index set ' -- 'contains\n' -- 'the numbers 0, 1, …, *n*-1. Item *i* of sequence *a* is selected ' -- 'by\n' -- '"a[i]". Some sequences, including built-in sequences, interpret\n' -- 'negative subscripts by adding the sequence length. For example,\n' -- '"a[-2]" equals "a[n-2]", the second to last item of sequence a ' -- 'with\n' -- 'length "n".\n' -- '\n' -- 'Sequences also support slicing: "a[i:j]" selects all items with ' -- 'index\n' -- '*k* such that *i* "<=" *k* "<" *j*. When used as an expression, a\n' -- 'slice is a sequence of the same type. The comment above about ' -- 'negative\n' -- 'indexes also applies to negative slice positions.\n' -- '\n' -- 'Some sequences also support “extended slicing†with a third “stepâ€\n' -- 'parameter: "a[i:j:k]" selects all items of *a* with index *x* where ' -- '"x\n' -- '= i + n*k", *n* ">=" "0" and *i* "<=" *x* "<" *j*.\n' -- '\n' -- 'Sequences are distinguished according to their mutability:\n' -- '\n' -- '\n' -- 'Immutable sequences\n' -- '-------------------\n' -- '\n' -- 'An object of an immutable sequence type cannot change once it is\n' -- 'created. (If the object contains references to other objects, ' -- 'these\n' -- 'other objects may be mutable and may be changed; however, the\n' -- 'collection of objects directly referenced by an immutable object\n' -- 'cannot change.)\n' -- '\n' -- 'The following types are immutable sequences:\n' -- '\n' -- 'Strings\n' -- ' A string is a sequence of values that represent Unicode code\n' -- ' points. All the code points in the range "U+0000 - U+10FFFF" can ' -- 'be\n' -- ' represented in a string. Python doesn’t have a char type; ' -- 'instead,\n' -- ' every code point in the string is represented as a string ' -- 'object\n' -- ' with length "1". The built-in function "ord()" converts a code\n' -- ' point from its string form to an integer in the range "0 - ' -- '10FFFF";\n' -- ' "chr()" converts an integer in the range "0 - 10FFFF" to the\n' -- ' corresponding length "1" string object. "str.encode()" can be ' -- 'used\n' -- ' to convert a "str" to "bytes" using the given text encoding, ' -- 'and\n' -- ' "bytes.decode()" can be used to achieve the opposite.\n' -- '\n' -- 'Tuples\n' -- ' The items of a tuple are arbitrary Python objects. Tuples of two ' -- 'or\n' -- ' more items are formed by comma-separated lists of expressions. ' -- 'A\n' -- ' tuple of one item (a ‘singleton’) can be formed by affixing a ' -- 'comma\n' -- ' to an expression (an expression by itself does not create a ' -- 'tuple,\n' -- ' since parentheses must be usable for grouping of expressions). ' -- 'An\n' -- ' empty tuple can be formed by an empty pair of parentheses.\n' -- '\n' -- 'Bytes\n' -- ' A bytes object is an immutable array. The items are 8-bit ' -- 'bytes,\n' -- ' represented by integers in the range 0 <= x < 256. Bytes ' -- 'literals\n' -- ' (like "b\'abc\'") and the built-in "bytes()" constructor can be ' -- 'used\n' -- ' to create bytes objects. Also, bytes objects can be decoded to\n' -- ' strings via the "decode()" method.\n' -- '\n' -- '\n' -- 'Mutable sequences\n' -- '-----------------\n' -- '\n' -- 'Mutable sequences can be changed after they are created. The\n' -- 'subscription and slicing notations can be used as the target of\n' -- 'assignment and "del" (delete) statements.\n' -- '\n' -- 'Note:\n' -- '\n' -- ' The "collections" and "array" module provide additional examples ' -- 'of\n' -- ' mutable sequence types.\n' -- '\n' -- 'There are currently two intrinsic mutable sequence types:\n' -- '\n' -- 'Lists\n' -- ' The items of a list are arbitrary Python objects. Lists are ' -- 'formed\n' -- ' by placing a comma-separated list of expressions in square\n' -- ' brackets. (Note that there are no special cases needed to form\n' -- ' lists of length 0 or 1.)\n' -- '\n' -- 'Byte Arrays\n' -- ' A bytearray object is a mutable array. They are created by the\n' -- ' built-in "bytearray()" constructor. Aside from being mutable ' -- '(and\n' -- ' hence unhashable), byte arrays otherwise provide the same ' -- 'interface\n' -- ' and functionality as immutable "bytes" objects.\n' -- '\n' -- '\n' -- 'Set types\n' -- '=========\n' -- '\n' -- 'These represent unordered, finite sets of unique, immutable ' -- 'objects.\n' -- 'As such, they cannot be indexed by any subscript. However, they can ' -- 'be\n' -- 'iterated over, and the built-in function "len()" returns the number ' -- 'of\n' -- 'items in a set. Common uses for sets are fast membership testing,\n' -- 'removing duplicates from a sequence, and computing mathematical\n' -- 'operations such as intersection, union, difference, and symmetric\n' -- 'difference.\n' -- '\n' -- 'For set elements, the same immutability rules apply as for ' -- 'dictionary\n' -- 'keys. Note that numeric types obey the normal rules for numeric\n' -- 'comparison: if two numbers compare equal (e.g., "1" and "1.0"), ' -- 'only\n' -- 'one of them can be contained in a set.\n' -- '\n' -- 'There are currently two intrinsic set types:\n' -- '\n' -- 'Sets\n' -- ' These represent a mutable set. They are created by the built-in\n' -- ' "set()" constructor and can be modified afterwards by several\n' -- ' methods, such as "add()".\n' -- '\n' -- 'Frozen sets\n' -- ' These represent an immutable set. They are created by the ' -- 'built-in\n' -- ' "frozenset()" constructor. As a frozenset is immutable and\n' -- ' *hashable*, it can be used again as an element of another set, ' -- 'or\n' -- ' as a dictionary key.\n' -- '\n' -- '\n' -- 'Mappings\n' -- '========\n' -- '\n' -- 'These represent finite sets of objects indexed by arbitrary index\n' -- 'sets. The subscript notation "a[k]" selects the item indexed by ' -- '"k"\n' -- 'from the mapping "a"; this can be used in expressions and as the\n' -- 'target of assignments or "del" statements. The built-in function\n' -- '"len()" returns the number of items in a mapping.\n' -- '\n' -- 'There is currently a single intrinsic mapping type:\n' -- '\n' -- '\n' -- 'Dictionaries\n' -- '------------\n' -- '\n' -- 'These represent finite sets of objects indexed by nearly arbitrary\n' -- 'values. The only types of values not acceptable as keys are ' -- 'values\n' -- 'containing lists or dictionaries or other mutable types that are\n' -- 'compared by value rather than by object identity, the reason being\n' -- 'that the efficient implementation of dictionaries requires a key’s\n' -- 'hash value to remain constant. Numeric types used for keys obey ' -- 'the\n' -- 'normal rules for numeric comparison: if two numbers compare equal\n' -- '(e.g., "1" and "1.0") then they can be used interchangeably to ' -- 'index\n' -- 'the same dictionary entry.\n' -- '\n' -- 'Dictionaries preserve insertion order, meaning that keys will be\n' -- 'produced in the same order they were added sequentially over the\n' -- 'dictionary. Replacing an existing key does not change the order,\n' -- 'however removing a key and re-inserting it will add it to the end\n' -- 'instead of keeping its old place.\n' -- '\n' -- 'Dictionaries are mutable; they can be created by the "{}" notation\n' -- '(see section Dictionary displays).\n' -- '\n' -- 'The extension modules "dbm.ndbm" and "dbm.gnu" provide additional\n' -- 'examples of mapping types, as does the "collections" module.\n' -- '\n' -- 'Changed in version 3.7: Dictionaries did not preserve insertion ' -- 'order\n' -- 'in versions of Python before 3.6. In CPython 3.6, insertion order ' -- 'was\n' -- 'preserved, but it was considered an implementation detail at that ' -- 'time\n' -- 'rather than a language guarantee.\n' -- '\n' -- '\n' -- 'Callable types\n' -- '==============\n' -- '\n' -- 'These are the types to which the function call operation (see ' -- 'section\n' -- 'Calls) can be applied:\n' -- '\n' -- '\n' -- 'User-defined functions\n' -- '----------------------\n' -- '\n' -- 'A user-defined function object is created by a function definition\n' -- '(see section Function definitions). It should be called with an\n' -- 'argument list containing the same number of items as the ' -- 'function’s\n' -- 'formal parameter list.\n' -- '\n' -- '\n' -- 'Special read-only attributes\n' -- '~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n' -- '\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| Attribute | ' -- 'Meaning |\n' -- '|====================================================|====================================================|\n' -- '| function.__globals__ | A reference ' -- 'to the "dictionary" that holds the |\n' -- '| | function’s ' -- 'global variables – the global namespace |\n' -- '| | of the ' -- 'module in which the function was defined. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| function.__closure__ | "None" or a ' -- '"tuple" of cells that contain bindings |\n' -- '| | for the ' -- 'names specified in the "co_freevars" |\n' -- '| | attribute of ' -- 'the function’s "code object". A cell |\n' -- '| | object has ' -- 'the attribute "cell_contents". This can |\n' -- '| | be used to ' -- 'get the value of the cell, as well as |\n' -- '| | set the ' -- 'value. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '\n' -- '\n' -- 'Special writable attributes\n' -- '~~~~~~~~~~~~~~~~~~~~~~~~~~~\n' -- '\n' -- 'Most of these attributes check the type of the assigned value:\n' -- '\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| Attribute | ' -- 'Meaning |\n' -- '|====================================================|====================================================|\n' -- '| function.__doc__ | The ' -- 'function’s documentation string, or "None" if |\n' -- '| | ' -- 'unavailable. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| function.__name__ | The ' -- 'function’s name. See also: "__name__ |\n' -- '| | ' -- 'attributes". |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| function.__qualname__ | The ' -- 'function’s *qualified name*. See also: |\n' -- '| | ' -- '"__qualname__ attributes". Added in version 3.3. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| function.__module__ | The name of ' -- 'the module the function was defined |\n' -- '| | in, or ' -- '"None" if unavailable. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| function.__defaults__ | A "tuple" ' -- 'containing default *parameter* values |\n' -- '| | for those ' -- 'parameters that have defaults, or "None" |\n' -- '| | if no ' -- 'parameters have a default value. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| function.__code__ | The code ' -- 'object representing the compiled function |\n' -- '| | ' -- 'body. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| function.__dict__ | The ' -- 'namespace supporting arbitrary function |\n' -- '| | attributes. ' -- 'See also: "__dict__ attributes". |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| function.__annotations__ | A ' -- '"dictionary" containing annotations of |\n' -- '| | ' -- '*parameters*. The keys of the dictionary are the |\n' -- '| | parameter ' -- 'names, and "\'return\'" for the return |\n' -- '| | annotation, ' -- 'if provided. See also: |\n' -- '| | ' -- '"object.__annotations__". Changed in version |\n' -- '| | 3.14: ' -- 'Annotations are now lazily evaluated. See |\n' -- '| | **PEP ' -- '649**. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| function.__annotate__ | The ' -- '*annotate function* for this function, or |\n' -- '| | "None" if ' -- 'the function has no annotations. See |\n' -- '| | ' -- '"object.__annotate__". Added in version 3.14. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| function.__kwdefaults__ | A ' -- '"dictionary" containing defaults for keyword- |\n' -- '| | only ' -- '*parameters*. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| function.__type_params__ | A "tuple" ' -- 'containing the type parameters of a |\n' -- '| | generic ' -- 'function. Added in version 3.12. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '\n' -- 'Function objects also support getting and setting arbitrary\n' -- 'attributes, which can be used, for example, to attach metadata to\n' -- 'functions. Regular attribute dot-notation is used to get and set ' -- 'such\n' -- 'attributes.\n' -- '\n' -- '**CPython implementation detail:** CPython’s current ' -- 'implementation\n' -- 'only supports function attributes on user-defined functions. ' -- 'Function\n' -- 'attributes on built-in functions may be supported in the future.\n' -- '\n' -- 'Additional information about a function’s definition can be ' -- 'retrieved\n' -- 'from its code object (accessible via the "__code__" attribute).\n' -- '\n' -- '\n' -- 'Instance methods\n' -- '----------------\n' -- '\n' -- 'An instance method object combines a class, a class instance and ' -- 'any\n' -- 'callable object (normally a user-defined function).\n' -- '\n' -- 'Special read-only attributes:\n' -- '\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| method.__self__ | Refers to ' -- 'the class instance object to which the |\n' -- '| | method is ' -- 'bound |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| method.__func__ | Refers to ' -- 'the original function object |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| method.__doc__ | The method’s ' -- 'documentation (same as |\n' -- '| | ' -- '"method.__func__.__doc__"). A "string" if the |\n' -- '| | original ' -- 'function had a docstring, else "None". |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| method.__name__ | The name of ' -- 'the method (same as |\n' -- '| | ' -- '"method.__func__.__name__") |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| method.__module__ | The name of ' -- 'the module the method was defined in, |\n' -- '| | or "None" if ' -- 'unavailable. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '\n' -- 'Methods also support accessing (but not setting) the arbitrary\n' -- 'function attributes on the underlying function object.\n' -- '\n' -- 'User-defined method objects may be created when getting an ' -- 'attribute\n' -- 'of a class (perhaps via an instance of that class), if that ' -- 'attribute\n' -- 'is a user-defined function object or a "classmethod" object.\n' -- '\n' -- 'When an instance method object is created by retrieving a ' -- 'user-defined\n' -- 'function object from a class via one of its instances, its ' -- '"__self__"\n' -- 'attribute is the instance, and the method object is said to be\n' -- '*bound*. The new method’s "__func__" attribute is the original\n' -- 'function object.\n' -- '\n' -- 'When an instance method object is created by retrieving a\n' -- '"classmethod" object from a class or instance, its "__self__"\n' -- 'attribute is the class itself, and its "__func__" attribute is the\n' -- 'function object underlying the class method.\n' -- '\n' -- 'When an instance method object is called, the underlying function\n' -- '("__func__") is called, inserting the class instance ("__self__") ' -- 'in\n' -- 'front of the argument list. For instance, when "C" is a class ' -- 'which\n' -- 'contains a definition for a function "f()", and "x" is an instance ' -- 'of\n' -- '"C", calling "x.f(1)" is equivalent to calling "C.f(x, 1)".\n' -- '\n' -- 'When an instance method object is derived from a "classmethod" ' -- 'object,\n' -- 'the “class instance†stored in "__self__" will actually be the ' -- 'class\n' -- 'itself, so that calling either "x.f(1)" or "C.f(1)" is equivalent ' -- 'to\n' -- 'calling "f(C,1)" where "f" is the underlying function.\n' -- '\n' -- 'It is important to note that user-defined functions which are\n' -- 'attributes of a class instance are not converted to bound methods;\n' -- 'this *only* happens when the function is an attribute of the ' -- 'class.\n' -- '\n' -- '\n' -- 'Generator functions\n' -- '-------------------\n' -- '\n' -- 'A function or method which uses the "yield" statement (see section ' -- 'The\n' -- 'yield statement) is called a *generator function*. Such a ' -- 'function,\n' -- 'when called, always returns an *iterator* object which can be used ' -- 'to\n' -- 'execute the body of the function: calling the iterator’s\n' -- '"iterator.__next__()" method will cause the function to execute ' -- 'until\n' -- 'it provides a value using the "yield" statement. When the ' -- 'function\n' -- 'executes a "return" statement or falls off the end, a ' -- '"StopIteration"\n' -- 'exception is raised and the iterator will have reached the end of ' -- 'the\n' -- 'set of values to be returned.\n' -- '\n' -- '\n' -- 'Coroutine functions\n' -- '-------------------\n' -- '\n' -- 'A function or method which is defined using "async def" is called ' -- 'a\n' -- '*coroutine function*. Such a function, when called, returns a\n' -- '*coroutine* object. It may contain "await" expressions, as well ' -- 'as\n' -- '"async with" and "async for" statements. See also the Coroutine\n' -- 'Objects section.\n' -- '\n' -- '\n' -- 'Asynchronous generator functions\n' -- '--------------------------------\n' -- '\n' -- 'A function or method which is defined using "async def" and which ' -- 'uses\n' -- 'the "yield" statement is called a *asynchronous generator ' -- 'function*.\n' -- 'Such a function, when called, returns an *asynchronous iterator*\n' -- 'object which can be used in an "async for" statement to execute ' -- 'the\n' -- 'body of the function.\n' -- '\n' -- 'Calling the asynchronous iterator’s "aiterator.__anext__" method ' -- 'will\n' -- 'return an *awaitable* which when awaited will execute until it\n' -- 'provides a value using the "yield" expression. When the function\n' -- 'executes an empty "return" statement or falls off the end, a\n' -- '"StopAsyncIteration" exception is raised and the asynchronous ' -- 'iterator\n' -- 'will have reached the end of the set of values to be yielded.\n' -- '\n' -- '\n' -- 'Built-in functions\n' -- '------------------\n' -- '\n' -- 'A built-in function object is a wrapper around a C function. ' -- 'Examples\n' -- 'of built-in functions are "len()" and "math.sin()" ("math" is a\n' -- 'standard built-in module). The number and type of the arguments ' -- 'are\n' -- 'determined by the C function. Special read-only attributes:\n' -- '\n' -- '* "__doc__" is the function’s documentation string, or "None" if\n' -- ' unavailable. See "function.__doc__".\n' -- '\n' -- '* "__name__" is the function’s name. See "function.__name__".\n' -- '\n' -- '* "__self__" is set to "None" (but see the next item).\n' -- '\n' -- '* "__module__" is the name of the module the function was defined ' -- 'in\n' -- ' or "None" if unavailable. See "function.__module__".\n' -- '\n' -- '\n' -- 'Built-in methods\n' -- '----------------\n' -- '\n' -- 'This is really a different disguise of a built-in function, this ' -- 'time\n' -- 'containing an object passed to the C function as an implicit extra\n' -- 'argument. An example of a built-in method is "alist.append()",\n' -- 'assuming *alist* is a list object. In this case, the special ' -- 'read-only\n' -- 'attribute "__self__" is set to the object denoted by *alist*. (The\n' -- 'attribute has the same semantics as it does with "other instance\n' -- 'methods".)\n' -- '\n' -- '\n' -- 'Classes\n' -- '-------\n' -- '\n' -- 'Classes are callable. These objects normally act as factories for ' -- 'new\n' -- 'instances of themselves, but variations are possible for class ' -- 'types\n' -- 'that override "__new__()". The arguments of the call are passed ' -- 'to\n' -- '"__new__()" and, in the typical case, to "__init__()" to ' -- 'initialize\n' -- 'the new instance.\n' -- '\n' -- '\n' -- 'Class Instances\n' -- '---------------\n' -- '\n' -- 'Instances of arbitrary classes can be made callable by defining a\n' -- '"__call__()" method in their class.\n' -- '\n' -- '\n' -- 'Modules\n' -- '=======\n' -- '\n' -- 'Modules are a basic organizational unit of Python code, and are\n' -- 'created by the import system as invoked either by the "import"\n' -- 'statement, or by calling functions such as ' -- '"importlib.import_module()"\n' -- 'and built-in "__import__()". A module object has a namespace\n' -- 'implemented by a "dictionary" object (this is the dictionary\n' -- 'referenced by the "__globals__" attribute of functions defined in ' -- 'the\n' -- 'module). Attribute references are translated to lookups in this\n' -- 'dictionary, e.g., "m.x" is equivalent to "m.__dict__["x"]". A ' -- 'module\n' -- 'object does not contain the code object used to initialize the ' -- 'module\n' -- '(since it isn’t needed once the initialization is done).\n' -- '\n' -- 'Attribute assignment updates the module’s namespace dictionary, ' -- 'e.g.,\n' -- '"m.x = 1" is equivalent to "m.__dict__["x"] = 1".\n' -- '\n' -- '\n' -- 'Import-related attributes on module objects\n' -- '-------------------------------------------\n' -- '\n' -- 'Module objects have the following attributes that relate to the ' -- 'import\n' -- 'system. When a module is created using the machinery associated ' -- 'with\n' -- 'the import system, these attributes are filled in based on the\n' -- 'module’s *spec*, before the *loader* executes and loads the ' -- 'module.\n' -- '\n' -- 'To create a module dynamically rather than using the import ' -- 'system,\n' -- 'it’s recommended to use "importlib.util.module_from_spec()", which\n' -- 'will set the various import-controlled attributes to appropriate\n' -- 'values. It’s also possible to use the "types.ModuleType" ' -- 'constructor\n' -- 'to create modules directly, but this technique is more error-prone, ' -- 'as\n' -- 'most attributes must be manually set on the module object after it ' -- 'has\n' -- 'been created when using this approach.\n' -- '\n' -- 'Caution:\n' -- '\n' -- ' With the exception of "__name__", it is **strongly** recommended\n' -- ' that you rely on "__spec__" and its attributes instead of any of ' -- 'the\n' -- ' other individual attributes listed in this subsection. Note that\n' -- ' updating an attribute on "__spec__" will not update the\n' -- ' corresponding attribute on the module itself:\n' -- '\n' -- ' >>> import typing\n' -- ' >>> typing.__name__, typing.__spec__.name\n' -- " ('typing', 'typing')\n" -- " >>> typing.__spec__.name = 'spelling'\n" -- ' >>> typing.__name__, typing.__spec__.name\n' -- " ('typing', 'spelling')\n" -- " >>> typing.__name__ = 'keyboard_smashing'\n" -- ' >>> typing.__name__, typing.__spec__.name\n' -- " ('keyboard_smashing', 'spelling')\n" -- '\n' -- 'module.__name__\n' -- '\n' -- ' The name used to uniquely identify the module in the import ' -- 'system.\n' -- ' For a directly executed module, this will be set to ' -- '""__main__"".\n' -- '\n' -- ' This attribute must be set to the fully qualified name of the\n' -- ' module. It is expected to match the value of\n' -- ' "module.__spec__.name".\n' -- '\n' -- 'module.__spec__\n' -- '\n' -- ' A record of the module’s import-system-related state.\n' -- '\n' -- ' Set to the "module spec" that was used when importing the ' -- 'module.\n' -- ' See Module specs for more details.\n' -- '\n' -- ' Added in version 3.4.\n' -- '\n' -- 'module.__package__\n' -- '\n' -- ' The *package* a module belongs to.\n' -- '\n' -- ' If the module is top-level (that is, not a part of any specific\n' -- ' package) then the attribute should be set to "\'\'" (the empty\n' -- ' string). Otherwise, it should be set to the name of the ' -- 'module’s\n' -- ' package (which can be equal to "module.__name__" if the module\n' -- ' itself is a package). See **PEP 366** for further details.\n' -- '\n' -- ' This attribute is used instead of "__name__" to calculate ' -- 'explicit\n' -- ' relative imports for main modules. It defaults to "None" for\n' -- ' modules created dynamically using the "types.ModuleType"\n' -- ' constructor; use "importlib.util.module_from_spec()" instead to\n' -- ' ensure the attribute is set to a "str".\n' -- '\n' -- ' It is **strongly** recommended that you use\n' -- ' "module.__spec__.parent" instead of "module.__package__".\n' -- ' "__package__" is now only used as a fallback if ' -- '"__spec__.parent"\n' -- ' is not set, and this fallback path is deprecated.\n' -- '\n' -- ' Changed in version 3.4: This attribute now defaults to "None" ' -- 'for\n' -- ' modules created dynamically using the "types.ModuleType"\n' -- ' constructor. Previously the attribute was optional.\n' -- '\n' -- ' Changed in version 3.6: The value of "__package__" is expected ' -- 'to\n' -- ' be the same as "__spec__.parent". "__package__" is now only used ' -- 'as\n' -- ' a fallback during import resolution if "__spec__.parent" is not\n' -- ' defined.\n' -- '\n' -- ' Changed in version 3.10: "ImportWarning" is raised if an import\n' -- ' resolution falls back to "__package__" instead of\n' -- ' "__spec__.parent".\n' -- '\n' -- ' Changed in version 3.12: Raise "DeprecationWarning" instead of\n' -- ' "ImportWarning" when falling back to "__package__" during ' -- 'import\n' -- ' resolution.\n' -- '\n' -- ' Deprecated since version 3.13, will be removed in version 3.15:\n' -- ' "__package__" will cease to be set or taken into consideration ' -- 'by\n' -- ' the import system or standard library.\n' -- '\n' -- 'module.__loader__\n' -- '\n' -- ' The *loader* object that the import machinery used to load the\n' -- ' module.\n' -- '\n' -- ' This attribute is mostly useful for introspection, but can be ' -- 'used\n' -- ' for additional loader-specific functionality, for example ' -- 'getting\n' -- ' data associated with a loader.\n' -- '\n' -- ' "__loader__" defaults to "None" for modules created dynamically\n' -- ' using the "types.ModuleType" constructor; use\n' -- ' "importlib.util.module_from_spec()" instead to ensure the ' -- 'attribute\n' -- ' is set to a *loader* object.\n' -- '\n' -- ' It is **strongly** recommended that you use\n' -- ' "module.__spec__.loader" instead of "module.__loader__".\n' -- '\n' -- ' Changed in version 3.4: This attribute now defaults to "None" ' -- 'for\n' -- ' modules created dynamically using the "types.ModuleType"\n' -- ' constructor. Previously the attribute was optional.\n' -- '\n' -- ' Deprecated since version 3.12, will be removed in version 3.16:\n' -- ' Setting "__loader__" on a module while failing to set\n' -- ' "__spec__.loader" is deprecated. In Python 3.16, "__loader__" ' -- 'will\n' -- ' cease to be set or taken into consideration by the import system ' -- 'or\n' -- ' the standard library.\n' -- '\n' -- 'module.__path__\n' -- '\n' -- ' A (possibly empty) *sequence* of strings enumerating the ' -- 'locations\n' -- ' where the package’s submodules will be found. Non-package ' -- 'modules\n' -- ' should not have a "__path__" attribute. See __path__ attributes ' -- 'on\n' -- ' modules for more details.\n' -- '\n' -- ' It is **strongly** recommended that you use\n' -- ' "module.__spec__.submodule_search_locations" instead of\n' -- ' "module.__path__".\n' -- '\n' -- 'module.__file__\n' -- '\n' -- 'module.__cached__\n' -- '\n' -- ' "__file__" and "__cached__" are both optional attributes that ' -- 'may\n' -- ' or may not be set. Both attributes should be a "str" when they ' -- 'are\n' -- ' available.\n' -- '\n' -- ' "__file__" indicates the pathname of the file from which the ' -- 'module\n' -- ' was loaded (if loaded from a file), or the pathname of the ' -- 'shared\n' -- ' library file for extension modules loaded dynamically from a ' -- 'shared\n' -- ' library. It might be missing for certain types of modules, such ' -- 'as\n' -- ' C modules that are statically linked into the interpreter, and ' -- 'the\n' -- ' import system may opt to leave it unset if it has no semantic\n' -- ' meaning (for example, a module loaded from a database).\n' -- '\n' -- ' If "__file__" is set then the "__cached__" attribute might also ' -- 'be\n' -- ' set, which is the path to any compiled version of the code ' -- '(for\n' -- ' example, a byte-compiled file). The file does not need to exist ' -- 'to\n' -- ' set this attribute; the path can simply point to where the ' -- 'compiled\n' -- ' file *would* exist (see **PEP 3147**).\n' -- '\n' -- ' Note that "__cached__" may be set even if "__file__" is not ' -- 'set.\n' -- ' However, that scenario is quite atypical. Ultimately, the ' -- '*loader*\n' -- ' is what makes use of the module spec provided by the *finder* ' -- '(from\n' -- ' which "__file__" and "__cached__" are derived). So if a loader ' -- 'can\n' -- ' load from a cached module but otherwise does not load from a ' -- 'file,\n' -- ' that atypical scenario may be appropriate.\n' -- '\n' -- ' It is **strongly** recommended that you use\n' -- ' "module.__spec__.cached" instead of "module.__cached__".\n' -- '\n' -- ' Deprecated since version 3.13, will be removed in version 3.15:\n' -- ' Setting "__cached__" on a module while failing to set\n' -- ' "__spec__.cached" is deprecated. In Python 3.15, "__cached__" ' -- 'will\n' -- ' cease to be set or taken into consideration by the import system ' -- 'or\n' -- ' standard library.\n' -- '\n' -- '\n' -- 'Other writable attributes on module objects\n' -- '-------------------------------------------\n' -- '\n' -- 'As well as the import-related attributes listed above, module ' -- 'objects\n' -- 'also have the following writable attributes:\n' -- '\n' -- 'module.__doc__\n' -- '\n' -- ' The module’s documentation string, or "None" if unavailable. ' -- 'See\n' -- ' also: "__doc__ attributes".\n' -- '\n' -- 'module.__annotations__\n' -- '\n' -- ' A dictionary containing *variable annotations* collected during\n' -- ' module body execution. For best practices on working with\n' -- ' "__annotations__", see "annotationlib".\n' -- '\n' -- ' Changed in version 3.14: Annotations are now lazily evaluated. ' -- 'See\n' -- ' **PEP 649**.\n' -- '\n' -- 'module.__annotate__\n' -- '\n' -- ' The *annotate function* for this module, or "None" if the ' -- 'module\n' -- ' has no annotations. See also: "__annotate__" attributes.\n' -- '\n' -- ' Added in version 3.14.\n' -- '\n' -- '\n' -- 'Module dictionaries\n' -- '-------------------\n' -- '\n' -- 'Module objects also have the following special read-only ' -- 'attribute:\n' -- '\n' -- 'module.__dict__\n' -- '\n' -- ' The module’s namespace as a dictionary object. Uniquely among ' -- 'the\n' -- ' attributes listed here, "__dict__" cannot be accessed as a ' -- 'global\n' -- ' variable from within a module; it can only be accessed as an\n' -- ' attribute on module objects.\n' -- '\n' -- ' **CPython implementation detail:** Because of the way CPython\n' -- ' clears module dictionaries, the module dictionary will be ' -- 'cleared\n' -- ' when the module falls out of scope even if the dictionary still ' -- 'has\n' -- ' live references. To avoid this, copy the dictionary or keep ' -- 'the\n' -- ' module around while using its dictionary directly.\n' -- '\n' -- '\n' -- 'Custom classes\n' -- '==============\n' -- '\n' -- 'Custom class types are typically created by class definitions (see\n' -- 'section Class definitions). A class has a namespace implemented by ' -- 'a\n' -- 'dictionary object. Class attribute references are translated to\n' -- 'lookups in this dictionary, e.g., "C.x" is translated to\n' -- '"C.__dict__["x"]" (although there are a number of hooks which ' -- 'allow\n' -- 'for other means of locating attributes). When the attribute name ' -- 'is\n' -- 'not found there, the attribute search continues in the base ' -- 'classes.\n' -- 'This search of the base classes uses the C3 method resolution ' -- 'order\n' -- 'which behaves correctly even in the presence of ‘diamond’ ' -- 'inheritance\n' -- 'structures where there are multiple inheritance paths leading back ' -- 'to\n' -- 'a common ancestor. Additional details on the C3 MRO used by Python ' -- 'can\n' -- 'be found at The Python 2.3 Method Resolution Order.\n' -- '\n' -- 'When a class attribute reference (for class "C", say) would yield ' -- 'a\n' -- 'class method object, it is transformed into an instance method ' -- 'object\n' -- 'whose "__self__" attribute is "C". When it would yield a\n' -- '"staticmethod" object, it is transformed into the object wrapped ' -- 'by\n' -- 'the static method object. See section Implementing Descriptors for\n' -- 'another way in which attributes retrieved from a class may differ ' -- 'from\n' -- 'those actually contained in its "__dict__".\n' -- '\n' -- 'Class attribute assignments update the class’s dictionary, never ' -- 'the\n' -- 'dictionary of a base class.\n' -- '\n' -- 'A class object can be called (see above) to yield a class instance\n' -- '(see below).\n' -- '\n' -- '\n' -- 'Special attributes\n' -- '------------------\n' -- '\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| Attribute | ' -- 'Meaning |\n' -- '|====================================================|====================================================|\n' -- '| type.__name__ | The class’s ' -- 'name. See also: "__name__ attributes". |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| type.__qualname__ | The class’s ' -- '*qualified name*. See also: |\n' -- '| | ' -- '"__qualname__ attributes". |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| type.__module__ | The name of ' -- 'the module in which the class was |\n' -- '| | ' -- 'defined. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| type.__dict__ | A "mapping ' -- 'proxy" providing a read-only view of |\n' -- '| | the class’s ' -- 'namespace. See also: "__dict__ |\n' -- '| | ' -- 'attributes". |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| type.__bases__ | A "tuple" ' -- 'containing the class’s bases. In most |\n' -- '| | cases, for a ' -- 'class defined as "class X(A, B, C)", |\n' -- '| | ' -- '"X.__bases__" will be exactly equal to "(A, B, |\n' -- '| | ' -- 'C)". |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| type.__doc__ | The class’s ' -- 'documentation string, or "None" if |\n' -- '| | undefined. ' -- 'Not inherited by subclasses. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| type.__annotations__ | A dictionary ' -- 'containing *variable annotations* |\n' -- '| | collected ' -- 'during class body execution. See also: |\n' -- '| | ' -- '"__annotations__ attributes". For best practices |\n' -- '| | on working ' -- 'with "__annotations__", please see |\n' -- '| | ' -- '"annotationlib". Caution: Accessing the |\n' -- '| | ' -- '"__annotations__" attribute of a class object |\n' -- '| | directly may ' -- 'yield incorrect results in the |\n' -- '| | presence of ' -- 'metaclasses. In addition, the |\n' -- '| | attribute ' -- 'may not exist for some classes. Use |\n' -- '| | ' -- '"annotationlib.get_annotations()" to retrieve |\n' -- '| | class ' -- 'annotations safely. Changed in version |\n' -- '| | 3.14: ' -- 'Annotations are now lazily evaluated. See |\n' -- '| | **PEP ' -- '649**. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| type.__annotate__() | The ' -- '*annotate function* for this class, or "None" |\n' -- '| | if the class ' -- 'has no annotations. See also: |\n' -- '| | ' -- '"__annotate__ attributes". Caution: Accessing |\n' -- '| | the ' -- '"__annotate__" attribute of a class object |\n' -- '| | directly may ' -- 'yield incorrect results in the |\n' -- '| | presence of ' -- 'metaclasses. Use |\n' -- '| | ' -- '"annotationlib.get_annotate_function()" to |\n' -- '| | retrieve the ' -- 'annotate function safely. Added in |\n' -- '| | version ' -- '3.14. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| type.__type_params__ | A "tuple" ' -- 'containing the type parameters of a |\n' -- '| | generic ' -- 'class. Added in version 3.12. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| type.__static_attributes__ | A "tuple" ' -- 'containing names of attributes of this |\n' -- '| | class which ' -- 'are assigned through "self.X" from any |\n' -- '| | function in ' -- 'its body. Added in version 3.13. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| type.__firstlineno__ | The line ' -- 'number of the first line of the class |\n' -- '| | definition, ' -- 'including decorators. Setting the |\n' -- '| | "__module__" ' -- 'attribute removes the |\n' -- '| | ' -- '"__firstlineno__" item from the type’s dictionary. |\n' -- '| | Added in ' -- 'version 3.13. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| type.__mro__ | The "tuple" ' -- 'of classes that are considered when |\n' -- '| | looking for ' -- 'base classes during method resolution. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '\n' -- '\n' -- 'Special methods\n' -- '---------------\n' -- '\n' -- 'In addition to the special attributes described above, all Python\n' -- 'classes also have the following two methods available:\n' -- '\n' -- 'type.mro()\n' -- '\n' -- ' This method can be overridden by a metaclass to customize the\n' -- ' method resolution order for its instances. It is called at ' -- 'class\n' -- ' instantiation, and its result is stored in "__mro__".\n' -- '\n' -- 'type.__subclasses__()\n' -- '\n' -- ' Each class keeps a list of weak references to its immediate\n' -- ' subclasses. This method returns a list of all those references\n' -- ' still alive. The list is in definition order. Example:\n' -- '\n' -- ' >>> class A: pass\n' -- ' >>> class B(A): pass\n' -- ' >>> A.__subclasses__()\n' -- " []\n" -- '\n' -- '\n' -- 'Class instances\n' -- '===============\n' -- '\n' -- 'A class instance is created by calling a class object (see above). ' -- 'A\n' -- 'class instance has a namespace implemented as a dictionary which ' -- 'is\n' -- 'the first place in which attribute references are searched. When ' -- 'an\n' -- 'attribute is not found there, and the instance’s class has an\n' -- 'attribute by that name, the search continues with the class\n' -- 'attributes. If a class attribute is found that is a user-defined\n' -- 'function object, it is transformed into an instance method object\n' -- 'whose "__self__" attribute is the instance. Static method and ' -- 'class\n' -- 'method objects are also transformed; see above under “Classesâ€. ' -- 'See\n' -- 'section Implementing Descriptors for another way in which ' -- 'attributes\n' -- 'of a class retrieved via its instances may differ from the objects\n' -- 'actually stored in the class’s "__dict__". If no class attribute ' -- 'is\n' -- 'found, and the object’s class has a "__getattr__()" method, that ' -- 'is\n' -- 'called to satisfy the lookup.\n' -- '\n' -- 'Attribute assignments and deletions update the instance’s ' -- 'dictionary,\n' -- 'never a class’s dictionary. If the class has a "__setattr__()" or\n' -- '"__delattr__()" method, this is called instead of updating the\n' -- 'instance dictionary directly.\n' -- '\n' -- 'Class instances can pretend to be numbers, sequences, or mappings ' -- 'if\n' -- 'they have methods with certain special names. See section Special\n' -- 'method names.\n' -- '\n' -- '\n' -- 'Special attributes\n' -- '------------------\n' -- '\n' -- 'object.__class__\n' -- '\n' -- ' The class to which a class instance belongs.\n' -- '\n' -- 'object.__dict__\n' -- '\n' -- ' A dictionary or other mapping object used to store an object’s\n' -- ' (writable) attributes. Not all instances have a "__dict__"\n' -- ' attribute; see the section on __slots__ for more details.\n' -- '\n' -- '\n' -- 'I/O objects (also known as file objects)\n' -- '========================================\n' -- '\n' -- 'A *file object* represents an open file. Various shortcuts are\n' -- 'available to create file objects: the "open()" built-in function, ' -- 'and\n' -- 'also "os.popen()", "os.fdopen()", and the "makefile()" method of\n' -- 'socket objects (and perhaps by other functions or methods provided ' -- 'by\n' -- 'extension modules).\n' -- '\n' -- 'The objects "sys.stdin", "sys.stdout" and "sys.stderr" are ' -- 'initialized\n' -- 'to file objects corresponding to the interpreter’s standard input,\n' -- 'output and error streams; they are all open in text mode and ' -- 'therefore\n' -- 'follow the interface defined by the "io.TextIOBase" abstract ' -- 'class.\n' -- '\n' -- '\n' -- 'Internal types\n' -- '==============\n' -- '\n' -- 'A few types used internally by the interpreter are exposed to the\n' -- 'user. Their definitions may change with future versions of the\n' -- 'interpreter, but they are mentioned here for completeness.\n' -- '\n' -- '\n' -- 'Code objects\n' -- '------------\n' -- '\n' -- 'Code objects represent *byte-compiled* executable Python code, or\n' -- '*bytecode*. The difference between a code object and a function ' -- 'object\n' -- 'is that the function object contains an explicit reference to the\n' -- 'function’s globals (the module in which it was defined), while a ' -- 'code\n' -- 'object contains no context; also the default argument values are\n' -- 'stored in the function object, not in the code object (because ' -- 'they\n' -- 'represent values calculated at run-time). Unlike function ' -- 'objects,\n' -- 'code objects are immutable and contain no references (directly or\n' -- 'indirectly) to mutable objects.\n' -- '\n' -- '\n' -- 'Special read-only attributes\n' -- '~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n' -- '\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| codeobject.co_name | The function ' -- 'name |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| codeobject.co_qualname | The fully ' -- 'qualified function name Added in |\n' -- '| | version ' -- '3.11. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| codeobject.co_argcount | The total ' -- 'number of positional *parameters* |\n' -- '| | (including ' -- 'positional-only parameters and |\n' -- '| | parameters ' -- 'with default values) that the function |\n' -- '| | ' -- 'has |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| codeobject.co_posonlyargcount | The number ' -- 'of positional-only *parameters* |\n' -- '| | (including ' -- 'arguments with default values) that the |\n' -- '| | function ' -- 'has |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| codeobject.co_kwonlyargcount | The number ' -- 'of keyword-only *parameters* (including |\n' -- '| | arguments ' -- 'with default values) that the function |\n' -- '| | ' -- 'has |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| codeobject.co_nlocals | The number ' -- 'of local variables used by the function |\n' -- '| | (including ' -- 'parameters) |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| codeobject.co_varnames | A "tuple" ' -- 'containing the names of the local |\n' -- '| | variables in ' -- 'the function (starting with the |\n' -- '| | parameter ' -- 'names) |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| codeobject.co_cellvars | A "tuple" ' -- 'containing the names of local variables |\n' -- '| | that are ' -- 'referenced from at least one *nested |\n' -- '| | scope* ' -- 'inside the function |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| codeobject.co_freevars | A "tuple" ' -- 'containing the names of *free (closure) |\n' -- '| | variables* ' -- 'that a *nested scope* references in an |\n' -- '| | outer scope. ' -- 'See also "function.__closure__". |\n' -- '| | Note: ' -- 'references to global and builtin names are |\n' -- '| | *not* ' -- 'included. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| codeobject.co_code | A string ' -- 'representing the sequence of *bytecode* |\n' -- '| | instructions ' -- 'in the function |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| codeobject.co_consts | A "tuple" ' -- 'containing the literals used by the |\n' -- '| | *bytecode* ' -- 'in the function |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| codeobject.co_names | A "tuple" ' -- 'containing the names used by the |\n' -- '| | *bytecode* ' -- 'in the function |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| codeobject.co_filename | The name of ' -- 'the file from which the code was |\n' -- '| | ' -- 'compiled |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| codeobject.co_firstlineno | The line ' -- 'number of the first line of the function |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| codeobject.co_lnotab | A string ' -- 'encoding the mapping from *bytecode* |\n' -- '| | offsets to ' -- 'line numbers. For details, see the |\n' -- '| | source code ' -- 'of the interpreter. Deprecated since |\n' -- '| | version ' -- '3.12: This attribute of code objects is |\n' -- '| | deprecated, ' -- 'and may be removed in Python 3.15. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| codeobject.co_stacksize | The required ' -- 'stack size of the code object |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| codeobject.co_flags | An "integer" ' -- 'encoding a number of flags for the |\n' -- '| | ' -- 'interpreter. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '\n' -- 'The following flag bits are defined for "co_flags": bit "0x04" is ' -- 'set\n' -- 'if the function uses the "*arguments" syntax to accept an ' -- 'arbitrary\n' -- 'number of positional arguments; bit "0x08" is set if the function ' -- 'uses\n' -- 'the "**keywords" syntax to accept arbitrary keyword arguments; bit\n' -- '"0x20" is set if the function is a generator. See Code Objects Bit\n' -- 'Flags for details on the semantics of each flags that might be\n' -- 'present.\n' -- '\n' -- 'Future feature declarations ("from __future__ import division") ' -- 'also\n' -- 'use bits in "co_flags" to indicate whether a code object was ' -- 'compiled\n' -- 'with a particular feature enabled: bit "0x2000" is set if the ' -- 'function\n' -- 'was compiled with future division enabled; bits "0x10" and ' -- '"0x1000"\n' -- 'were used in earlier versions of Python.\n' -- '\n' -- 'Other bits in "co_flags" are reserved for internal use.\n' -- '\n' -- 'If a code object represents a function and has a docstring, the ' -- 'first\n' -- 'item in "co_consts" is the docstring of the function.\n' -- '\n' -- '\n' -- 'Methods on code objects\n' -- '~~~~~~~~~~~~~~~~~~~~~~~\n' -- '\n' -- 'codeobject.co_positions()\n' -- '\n' -- ' Returns an iterable over the source code positions of each\n' -- ' *bytecode* instruction in the code object.\n' -- '\n' -- ' The iterator returns "tuple"s containing the "(start_line,\n' -- ' end_line, start_column, end_column)". The *i-th* tuple ' -- 'corresponds\n' -- ' to the position of the source code that compiled to the *i-th* ' -- 'code\n' -- ' unit. Column information is 0-indexed utf-8 byte offsets on the\n' -- ' given source line.\n' -- '\n' -- ' This positional information can be missing. A non-exhaustive ' -- 'lists\n' -- ' of cases where this may happen:\n' -- '\n' -- ' * Running the interpreter with "-X" "no_debug_ranges".\n' -- '\n' -- ' * Loading a pyc file compiled while using "-X" ' -- '"no_debug_ranges".\n' -- '\n' -- ' * Position tuples corresponding to artificial instructions.\n' -- '\n' -- ' * Line and column numbers that can’t be represented due to\n' -- ' implementation specific limitations.\n' -- '\n' -- ' When this occurs, some or all of the tuple elements can be ' -- '"None".\n' -- '\n' -- ' Added in version 3.11.\n' -- '\n' -- ' Note:\n' -- '\n' -- ' This feature requires storing column positions in code ' -- 'objects\n' -- ' which may result in a small increase of disk usage of ' -- 'compiled\n' -- ' Python files or interpreter memory usage. To avoid storing ' -- 'the\n' -- ' extra information and/or deactivate printing the extra ' -- 'traceback\n' -- ' information, the "-X" "no_debug_ranges" command line flag or ' -- 'the\n' -- ' "PYTHONNODEBUGRANGES" environment variable can be used.\n' -- '\n' -- 'codeobject.co_lines()\n' -- '\n' -- ' Returns an iterator that yields information about successive ' -- 'ranges\n' -- ' of *bytecode*s. Each item yielded is a "(start, end, lineno)"\n' -- ' "tuple":\n' -- '\n' -- ' * "start" (an "int") represents the offset (inclusive) of the ' -- 'start\n' -- ' of the *bytecode* range\n' -- '\n' -- ' * "end" (an "int") represents the offset (exclusive) of the end ' -- 'of\n' -- ' the *bytecode* range\n' -- '\n' -- ' * "lineno" is an "int" representing the line number of the\n' -- ' *bytecode* range, or "None" if the bytecodes in the given ' -- 'range\n' -- ' have no line number\n' -- '\n' -- ' The items yielded will have the following properties:\n' -- '\n' -- ' * The first range yielded will have a "start" of 0.\n' -- '\n' -- ' * The "(start, end)" ranges will be non-decreasing and ' -- 'consecutive.\n' -- ' That is, for any pair of "tuple"s, the "start" of the second ' -- 'will\n' -- ' be equal to the "end" of the first.\n' -- '\n' -- ' * No range will be backwards: "end >= start" for all triples.\n' -- '\n' -- ' * The last "tuple" yielded will have "end" equal to the size of ' -- 'the\n' -- ' *bytecode*.\n' -- '\n' -- ' Zero-width ranges, where "start == end", are allowed. ' -- 'Zero-width\n' -- ' ranges are used for lines that are present in the source code, ' -- 'but\n' -- ' have been eliminated by the *bytecode* compiler.\n' -- '\n' -- ' Added in version 3.10.\n' -- '\n' -- ' See also:\n' -- '\n' -- ' **PEP 626** - Precise line numbers for debugging and other ' -- 'tools.\n' -- ' The PEP that introduced the "co_lines()" method.\n' -- '\n' -- 'codeobject.replace(**kwargs)\n' -- '\n' -- ' Return a copy of the code object with new values for the ' -- 'specified\n' -- ' fields.\n' -- '\n' -- ' Code objects are also supported by the generic function\n' -- ' "copy.replace()".\n' -- '\n' -- ' Added in version 3.8.\n' -- '\n' -- '\n' -- 'Frame objects\n' -- '-------------\n' -- '\n' -- 'Frame objects represent execution frames. They may occur in ' -- 'traceback\n' -- 'objects, and are also passed to registered trace functions.\n' -- '\n' -- '\n' -- 'Special read-only attributes\n' -- '~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n' -- '\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| frame.f_back | Points to ' -- 'the previous stack frame (towards the |\n' -- '| | caller), or ' -- '"None" if this is the bottom stack |\n' -- '| | ' -- 'frame |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| frame.f_code | The code ' -- 'object being executed in this frame. |\n' -- '| | Accessing ' -- 'this attribute raises an auditing event |\n' -- '| | ' -- '"object.__getattr__" with arguments "obj" and |\n' -- '| | ' -- '""f_code"". |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| frame.f_locals | The mapping ' -- 'used by the frame to look up local |\n' -- '| | variables. ' -- 'If the frame refers to an *optimized |\n' -- '| | scope*, this ' -- 'may return a write-through proxy |\n' -- '| | object. ' -- 'Changed in version 3.13: Return a proxy |\n' -- '| | for ' -- 'optimized scopes. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| frame.f_globals | The ' -- 'dictionary used by the frame to look up global |\n' -- '| | ' -- 'variables |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| frame.f_builtins | The ' -- 'dictionary used by the frame to look up built- |\n' -- '| | in ' -- '(intrinsic) names |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| frame.f_lasti | The “precise ' -- 'instruction†of the frame object |\n' -- '| | (this is an ' -- 'index into the *bytecode* string of |\n' -- '| | the code ' -- 'object) |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '\n' -- '\n' -- 'Special writable attributes\n' -- '~~~~~~~~~~~~~~~~~~~~~~~~~~~\n' -- '\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| frame.f_trace | If not ' -- '"None", this is a function called for |\n' -- '| | various ' -- 'events during code execution (this is used |\n' -- '| | by ' -- 'debuggers). Normally an event is triggered for |\n' -- '| | each new ' -- 'source line (see "f_trace_lines"). |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| frame.f_trace_lines | Set this ' -- 'attribute to "False" to disable |\n' -- '| | triggering a ' -- 'tracing event for each source line. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| frame.f_trace_opcodes | Set this ' -- 'attribute to "True" to allow per-opcode |\n' -- '| | events to be ' -- 'requested. Note that this may lead to |\n' -- '| | undefined ' -- 'interpreter behaviour if exceptions |\n' -- '| | raised by ' -- 'the trace function escape to the |\n' -- '| | function ' -- 'being traced. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| frame.f_lineno | The current ' -- 'line number of the frame – writing to |\n' -- '| | this from ' -- 'within a trace function jumps to the |\n' -- '| | given line ' -- '(only for the bottom-most frame). A |\n' -- '| | debugger can ' -- 'implement a Jump command (aka Set |\n' -- '| | Next ' -- 'Statement) by writing to this attribute. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '\n' -- '\n' -- 'Frame object methods\n' -- '~~~~~~~~~~~~~~~~~~~~\n' -- '\n' -- 'Frame objects support one method:\n' -- '\n' -- 'frame.clear()\n' -- '\n' -- ' This method clears all references to local variables held by ' -- 'the\n' -- ' frame. Also, if the frame belonged to a *generator*, the ' -- 'generator\n' -- ' is finalized. This helps break reference cycles involving ' -- 'frame\n' -- ' objects (for example when catching an exception and storing its\n' -- ' traceback for later use).\n' -- '\n' -- ' "RuntimeError" is raised if the frame is currently executing or\n' -- ' suspended.\n' -- '\n' -- ' Added in version 3.4.\n' -- '\n' -- ' Changed in version 3.13: Attempting to clear a suspended frame\n' -- ' raises "RuntimeError" (as has always been the case for ' -- 'executing\n' -- ' frames).\n' -- '\n' -- '\n' -- 'Traceback objects\n' -- '-----------------\n' -- '\n' -- 'Traceback objects represent the stack trace of an exception. A\n' -- 'traceback object is implicitly created when an exception occurs, ' -- 'and\n' -- 'may also be explicitly created by calling "types.TracebackType".\n' -- '\n' -- 'Changed in version 3.7: Traceback objects can now be explicitly\n' -- 'instantiated from Python code.\n' -- '\n' -- 'For implicitly created tracebacks, when the search for an ' -- 'exception\n' -- 'handler unwinds the execution stack, at each unwound level a ' -- 'traceback\n' -- 'object is inserted in front of the current traceback. When an\n' -- 'exception handler is entered, the stack trace is made available to ' -- 'the\n' -- 'program. (See section The try statement.) It is accessible as the\n' -- 'third item of the tuple returned by "sys.exc_info()", and as the\n' -- '"__traceback__" attribute of the caught exception.\n' -- '\n' -- 'When the program contains no suitable handler, the stack trace is\n' -- 'written (nicely formatted) to the standard error stream; if the\n' -- 'interpreter is interactive, it is also made available to the user ' -- 'as\n' -- '"sys.last_traceback".\n' -- '\n' -- 'For explicitly created tracebacks, it is up to the creator of the\n' -- 'traceback to determine how the "tb_next" attributes should be ' -- 'linked\n' -- 'to form a full stack trace.\n' -- '\n' -- 'Special read-only attributes:\n' -- '\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| traceback.tb_frame | Points to ' -- 'the execution frame of the current |\n' -- '| | level. ' -- 'Accessing this attribute raises an |\n' -- '| | auditing ' -- 'event "object.__getattr__" with arguments |\n' -- '| | "obj" and ' -- '""tb_frame"". |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| traceback.tb_lineno | Gives the ' -- 'line number where the exception occurred |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '| traceback.tb_lasti | Indicates ' -- 'the “precise instructionâ€. |\n' -- '+----------------------------------------------------+----------------------------------------------------+\n' -- '\n' -- 'The line number and last instruction in the traceback may differ ' -- 'from\n' -- 'the line number of its frame object if the exception occurred in a\n' -- '"try" statement with no matching except clause or with a "finally"\n' -- 'clause.\n' -- '\n' -- 'traceback.tb_next\n' -- '\n' -- ' The special writable attribute "tb_next" is the next level in ' -- 'the\n' -- ' stack trace (towards the frame where the exception occurred), ' -- 'or\n' -- ' "None" if there is no next level.\n' -- '\n' -- ' Changed in version 3.7: This attribute is now writable\n' -- '\n' -- '\n' -- 'Slice objects\n' -- '-------------\n' -- '\n' -- 'Slice objects are used to represent slices for "__getitem__()"\n' -- 'methods. They are also created by the built-in "slice()" ' -- 'function.\n' -- '\n' -- 'Special read-only attributes: "start" is the lower bound; "stop" ' -- 'is\n' -- 'the upper bound; "step" is the step value; each is "None" if ' -- 'omitted.\n' -- 'These attributes can have any type.\n' -- '\n' -- 'Slice objects support one method:\n' -- '\n' -- 'slice.indices(self, length)\n' -- '\n' -- ' This method takes a single integer argument *length* and ' -- 'computes\n' -- ' information about the slice that the slice object would describe ' -- 'if\n' -- ' applied to a sequence of *length* items. It returns a tuple of\n' -- ' three integers; respectively these are the *start* and *stop*\n' -- ' indices and the *step* or stride length of the slice. Missing ' -- 'or\n' -- ' out-of-bounds indices are handled in a manner consistent with\n' -- ' regular slices.\n' -- '\n' -- '\n' -- 'Static method objects\n' -- '---------------------\n' -- '\n' -- 'Static method objects provide a way of defeating the transformation ' -- 'of\n' -- 'function objects to method objects described above. A static ' -- 'method\n' -- 'object is a wrapper around any other object, usually a ' -- 'user-defined\n' -- 'method object. When a static method object is retrieved from a ' -- 'class\n' -- 'or a class instance, the object actually returned is the wrapped\n' -- 'object, which is not subject to any further transformation. Static\n' -- 'method objects are also callable. Static method objects are created ' -- 'by\n' -- 'the built-in "staticmethod()" constructor.\n' -- '\n' -- '\n' -- 'Class method objects\n' -- '--------------------\n' -- '\n' -- 'A class method object, like a static method object, is a wrapper\n' -- 'around another object that alters the way in which that object is\n' -- 'retrieved from classes and class instances. The behaviour of class\n' -- 'method objects upon such retrieval is described above, under ' -- '“instance\n' -- 'methodsâ€. Class method objects are created by the built-in\n' -- '"classmethod()" constructor.\n', -- 'typesfunctions': 'Functions\n' -- '*********\n' -- '\n' -- 'Function objects are created by function definitions. The ' -- 'only\n' -- 'operation on a function object is to call it: ' -- '"func(argument-list)".\n' -- '\n' -- 'There are really two flavors of function objects: built-in ' -- 'functions\n' -- 'and user-defined functions. Both support the same ' -- 'operation (to call\n' -- 'the function), but the implementation is different, hence ' -- 'the\n' -- 'different object types.\n' -- '\n' -- 'See Function definitions for more information.\n', -- 'typesmapping': 'Mapping Types — "dict"\n' -- '**********************\n' -- '\n' -- 'A *mapping* object maps *hashable* values to arbitrary ' -- 'objects.\n' -- 'Mappings are mutable objects. There is currently only one ' -- 'standard\n' -- 'mapping type, the *dictionary*. (For other containers see ' -- 'the built-\n' -- 'in "list", "set", and "tuple" classes, and the "collections" ' -- 'module.)\n' -- '\n' -- 'A dictionary’s keys are *almost* arbitrary values. Values ' -- 'that are\n' -- 'not *hashable*, that is, values containing lists, ' -- 'dictionaries or\n' -- 'other mutable types (that are compared by value rather than ' -- 'by object\n' -- 'identity) may not be used as keys. Values that compare equal ' -- '(such as\n' -- '"1", "1.0", and "True") can be used interchangeably to index ' -- 'the same\n' -- 'dictionary entry.\n' -- '\n' -- 'class dict(**kwargs)\n' -- 'class dict(mapping, **kwargs)\n' -- 'class dict(iterable, **kwargs)\n' -- '\n' -- ' Return a new dictionary initialized from an optional ' -- 'positional\n' -- ' argument and a possibly empty set of keyword arguments.\n' -- '\n' -- ' Dictionaries can be created by several means:\n' -- '\n' -- ' * Use a comma-separated list of "key: value" pairs within ' -- 'braces:\n' -- ' "{\'jack\': 4098, \'sjoerd\': 4127}" or "{4098: ' -- "'jack', 4127:\n" -- ' \'sjoerd\'}"\n' -- '\n' -- ' * Use a dict comprehension: "{}", "{x: x ** 2 for x in ' -- 'range(10)}"\n' -- '\n' -- ' * Use the type constructor: "dict()", "dict([(\'foo\', ' -- "100), ('bar',\n" -- ' 200)])", "dict(foo=100, bar=200)"\n' -- '\n' -- ' If no positional argument is given, an empty dictionary ' -- 'is created.\n' -- ' If a positional argument is given and it defines a ' -- '"keys()" method,\n' -- ' a dictionary is created by calling "__getitem__()" on the ' -- 'argument\n' -- ' with each returned key from the method. Otherwise, the ' -- 'positional\n' -- ' argument must be an *iterable* object. Each item in the ' -- 'iterable\n' -- ' must itself be an iterable with exactly two elements. ' -- 'The first\n' -- ' element of each item becomes a key in the new dictionary, ' -- 'and the\n' -- ' second element the corresponding value. If a key occurs ' -- 'more than\n' -- ' once, the last value for that key becomes the ' -- 'corresponding value\n' -- ' in the new dictionary.\n' -- '\n' -- ' If keyword arguments are given, the keyword arguments and ' -- 'their\n' -- ' values are added to the dictionary created from the ' -- 'positional\n' -- ' argument. If a key being added is already present, the ' -- 'value from\n' -- ' the keyword argument replaces the value from the ' -- 'positional\n' -- ' argument.\n' -- '\n' -- ' To illustrate, the following examples all return a ' -- 'dictionary equal\n' -- ' to "{"one": 1, "two": 2, "three": 3}":\n' -- '\n' -- ' >>> a = dict(one=1, two=2, three=3)\n' -- " >>> b = {'one': 1, 'two': 2, 'three': 3}\n" -- " >>> c = dict(zip(['one', 'two', 'three'], [1, 2, 3]))\n" -- " >>> d = dict([('two', 2), ('one', 1), ('three', 3)])\n" -- " >>> e = dict({'three': 3, 'one': 1, 'two': 2})\n" -- " >>> f = dict({'one': 1, 'three': 3}, two=2)\n" -- ' >>> a == b == c == d == e == f\n' -- ' True\n' -- '\n' -- ' Providing keyword arguments as in the first example only ' -- 'works for\n' -- ' keys that are valid Python identifiers. Otherwise, any ' -- 'valid keys\n' -- ' can be used.\n' -- '\n' -- ' These are the operations that dictionaries support (and ' -- 'therefore,\n' -- ' custom mapping types should support too):\n' -- '\n' -- ' list(d)\n' -- '\n' -- ' Return a list of all the keys used in the dictionary ' -- '*d*.\n' -- '\n' -- ' len(d)\n' -- '\n' -- ' Return the number of items in the dictionary *d*.\n' -- '\n' -- ' d[key]\n' -- '\n' -- ' Return the item of *d* with key *key*. Raises a ' -- '"KeyError" if\n' -- ' *key* is not in the map.\n' -- '\n' -- ' If a subclass of dict defines a method "__missing__()" ' -- 'and *key*\n' -- ' is not present, the "d[key]" operation calls that ' -- 'method with\n' -- ' the key *key* as argument. The "d[key]" operation ' -- 'then returns\n' -- ' or raises whatever is returned or raised by the\n' -- ' "__missing__(key)" call. No other operations or ' -- 'methods invoke\n' -- ' "__missing__()". If "__missing__()" is not defined, ' -- '"KeyError"\n' -- ' is raised. "__missing__()" must be a method; it cannot ' -- 'be an\n' -- ' instance variable:\n' -- '\n' -- ' >>> class Counter(dict):\n' -- ' ... def __missing__(self, key):\n' -- ' ... return 0\n' -- ' ...\n' -- ' >>> c = Counter()\n' -- " >>> c['red']\n" -- ' 0\n' -- " >>> c['red'] += 1\n" -- " >>> c['red']\n" -- ' 1\n' -- '\n' -- ' The example above shows part of the implementation of\n' -- ' "collections.Counter". A different "__missing__" ' -- 'method is used\n' -- ' by "collections.defaultdict".\n' -- '\n' -- ' d[key] = value\n' -- '\n' -- ' Set "d[key]" to *value*.\n' -- '\n' -- ' del d[key]\n' -- '\n' -- ' Remove "d[key]" from *d*. Raises a "KeyError" if ' -- '*key* is not\n' -- ' in the map.\n' -- '\n' -- ' key in d\n' -- '\n' -- ' Return "True" if *d* has a key *key*, else "False".\n' -- '\n' -- ' key not in d\n' -- '\n' -- ' Equivalent to "not key in d".\n' -- '\n' -- ' iter(d)\n' -- '\n' -- ' Return an iterator over the keys of the dictionary. ' -- 'This is a\n' -- ' shortcut for "iter(d.keys())".\n' -- '\n' -- ' clear()\n' -- '\n' -- ' Remove all items from the dictionary.\n' -- '\n' -- ' copy()\n' -- '\n' -- ' Return a shallow copy of the dictionary.\n' -- '\n' -- ' classmethod fromkeys(iterable, value=None, /)\n' -- '\n' -- ' Create a new dictionary with keys from *iterable* and ' -- 'values set\n' -- ' to *value*.\n' -- '\n' -- ' "fromkeys()" is a class method that returns a new ' -- 'dictionary.\n' -- ' *value* defaults to "None". All of the values refer ' -- 'to just a\n' -- ' single instance, so it generally doesn’t make sense ' -- 'for *value*\n' -- ' to be a mutable object such as an empty list. To get ' -- 'distinct\n' -- ' values, use a dict comprehension instead.\n' -- '\n' -- ' get(key, default=None)\n' -- '\n' -- ' Return the value for *key* if *key* is in the ' -- 'dictionary, else\n' -- ' *default*. If *default* is not given, it defaults to ' -- '"None", so\n' -- ' that this method never raises a "KeyError".\n' -- '\n' -- ' items()\n' -- '\n' -- ' Return a new view of the dictionary’s items ("(key, ' -- 'value)"\n' -- ' pairs). See the documentation of view objects.\n' -- '\n' -- ' keys()\n' -- '\n' -- ' Return a new view of the dictionary’s keys. See the\n' -- ' documentation of view objects.\n' -- '\n' -- ' pop(key[, default])\n' -- '\n' -- ' If *key* is in the dictionary, remove it and return ' -- 'its value,\n' -- ' else return *default*. If *default* is not given and ' -- '*key* is\n' -- ' not in the dictionary, a "KeyError" is raised.\n' -- '\n' -- ' popitem()\n' -- '\n' -- ' Remove and return a "(key, value)" pair from the ' -- 'dictionary.\n' -- ' Pairs are returned in LIFO (last-in, first-out) ' -- 'order.\n' -- '\n' -- ' "popitem()" is useful to destructively iterate over a\n' -- ' dictionary, as often used in set algorithms. If the ' -- 'dictionary\n' -- ' is empty, calling "popitem()" raises a "KeyError".\n' -- '\n' -- ' Changed in version 3.7: LIFO order is now guaranteed. ' -- 'In prior\n' -- ' versions, "popitem()" would return an arbitrary ' -- 'key/value pair.\n' -- '\n' -- ' reversed(d)\n' -- '\n' -- ' Return a reverse iterator over the keys of the ' -- 'dictionary. This\n' -- ' is a shortcut for "reversed(d.keys())".\n' -- '\n' -- ' Added in version 3.8.\n' -- '\n' -- ' setdefault(key, default=None)\n' -- '\n' -- ' If *key* is in the dictionary, return its value. If ' -- 'not, insert\n' -- ' *key* with a value of *default* and return *default*. ' -- '*default*\n' -- ' defaults to "None".\n' -- '\n' -- ' update([other])\n' -- '\n' -- ' Update the dictionary with the key/value pairs from ' -- '*other*,\n' -- ' overwriting existing keys. Return "None".\n' -- '\n' -- ' "update()" accepts either another object with a ' -- '"keys()" method\n' -- ' (in which case "__getitem__()" is called with every ' -- 'key returned\n' -- ' from the method) or an iterable of key/value pairs (as ' -- 'tuples or\n' -- ' other iterables of length two). If keyword arguments ' -- 'are\n' -- ' specified, the dictionary is then updated with those ' -- 'key/value\n' -- ' pairs: "d.update(red=1, blue=2)".\n' -- '\n' -- ' values()\n' -- '\n' -- ' Return a new view of the dictionary’s values. See ' -- 'the\n' -- ' documentation of view objects.\n' -- '\n' -- ' An equality comparison between one "dict.values()" ' -- 'view and\n' -- ' another will always return "False". This also applies ' -- 'when\n' -- ' comparing "dict.values()" to itself:\n' -- '\n' -- " >>> d = {'a': 1}\n" -- ' >>> d.values() == d.values()\n' -- ' False\n' -- '\n' -- ' d | other\n' -- '\n' -- ' Create a new dictionary with the merged keys and ' -- 'values of *d*\n' -- ' and *other*, which must both be dictionaries. The ' -- 'values of\n' -- ' *other* take priority when *d* and *other* share ' -- 'keys.\n' -- '\n' -- ' Added in version 3.9.\n' -- '\n' -- ' d |= other\n' -- '\n' -- ' Update the dictionary *d* with keys and values from ' -- '*other*,\n' -- ' which may be either a *mapping* or an *iterable* of ' -- 'key/value\n' -- ' pairs. The values of *other* take priority when *d* ' -- 'and *other*\n' -- ' share keys.\n' -- '\n' -- ' Added in version 3.9.\n' -- '\n' -- ' Dictionaries compare equal if and only if they have the ' -- 'same "(key,\n' -- ' value)" pairs (regardless of ordering). Order comparisons ' -- '(‘<’,\n' -- ' ‘<=’, ‘>=’, ‘>’) raise "TypeError".\n' -- '\n' -- ' Dictionaries preserve insertion order. Note that ' -- 'updating a key\n' -- ' does not affect the order. Keys added after deletion are ' -- 'inserted\n' -- ' at the end.\n' -- '\n' -- ' >>> d = {"one": 1, "two": 2, "three": 3, "four": 4}\n' -- ' >>> d\n' -- " {'one': 1, 'two': 2, 'three': 3, 'four': 4}\n" -- ' >>> list(d)\n' -- " ['one', 'two', 'three', 'four']\n" -- ' >>> list(d.values())\n' -- ' [1, 2, 3, 4]\n' -- ' >>> d["one"] = 42\n' -- ' >>> d\n' -- " {'one': 42, 'two': 2, 'three': 3, 'four': 4}\n" -- ' >>> del d["two"]\n' -- ' >>> d["two"] = None\n' -- ' >>> d\n' -- " {'one': 42, 'three': 3, 'four': 4, 'two': None}\n" -- '\n' -- ' Changed in version 3.7: Dictionary order is guaranteed to ' -- 'be\n' -- ' insertion order. This behavior was an implementation ' -- 'detail of\n' -- ' CPython from 3.6.\n' -- '\n' -- ' Dictionaries and dictionary views are reversible.\n' -- '\n' -- ' >>> d = {"one": 1, "two": 2, "three": 3, "four": 4}\n' -- ' >>> d\n' -- " {'one': 1, 'two': 2, 'three': 3, 'four': 4}\n" -- ' >>> list(reversed(d))\n' -- " ['four', 'three', 'two', 'one']\n" -- ' >>> list(reversed(d.values()))\n' -- ' [4, 3, 2, 1]\n' -- ' >>> list(reversed(d.items()))\n' -- " [('four', 4), ('three', 3), ('two', 2), ('one', 1)]\n" -- '\n' -- ' Changed in version 3.8: Dictionaries are now reversible.\n' -- '\n' -- 'See also:\n' -- '\n' -- ' "types.MappingProxyType" can be used to create a read-only ' -- 'view of a\n' -- ' "dict".\n' -- '\n' -- '\n' -- 'Dictionary view objects\n' -- '=======================\n' -- '\n' -- 'The objects returned by "dict.keys()", "dict.values()" and\n' -- '"dict.items()" are *view objects*. They provide a dynamic ' -- 'view on the\n' -- 'dictionary’s entries, which means that when the dictionary ' -- 'changes,\n' -- 'the view reflects these changes.\n' -- '\n' -- 'Dictionary views can be iterated over to yield their ' -- 'respective data,\n' -- 'and support membership tests:\n' -- '\n' -- 'len(dictview)\n' -- '\n' -- ' Return the number of entries in the dictionary.\n' -- '\n' -- 'iter(dictview)\n' -- '\n' -- ' Return an iterator over the keys, values or items ' -- '(represented as\n' -- ' tuples of "(key, value)") in the dictionary.\n' -- '\n' -- ' Keys and values are iterated over in insertion order. ' -- 'This allows\n' -- ' the creation of "(value, key)" pairs using "zip()": ' -- '"pairs =\n' -- ' zip(d.values(), d.keys())". Another way to create the ' -- 'same list is\n' -- ' "pairs = [(v, k) for (k, v) in d.items()]".\n' -- '\n' -- ' Iterating views while adding or deleting entries in the ' -- 'dictionary\n' -- ' may raise a "RuntimeError" or fail to iterate over all ' -- 'entries.\n' -- '\n' -- ' Changed in version 3.7: Dictionary order is guaranteed to ' -- 'be\n' -- ' insertion order.\n' -- '\n' -- 'x in dictview\n' -- '\n' -- ' Return "True" if *x* is in the underlying dictionary’s ' -- 'keys, values\n' -- ' or items (in the latter case, *x* should be a "(key, ' -- 'value)"\n' -- ' tuple).\n' -- '\n' -- 'reversed(dictview)\n' -- '\n' -- ' Return a reverse iterator over the keys, values or items ' -- 'of the\n' -- ' dictionary. The view will be iterated in reverse order of ' -- 'the\n' -- ' insertion.\n' -- '\n' -- ' Changed in version 3.8: Dictionary views are now ' -- 'reversible.\n' -- '\n' -- 'dictview.mapping\n' -- '\n' -- ' Return a "types.MappingProxyType" that wraps the ' -- 'original\n' -- ' dictionary to which the view refers.\n' -- '\n' -- ' Added in version 3.10.\n' -- '\n' -- 'Keys views are set-like since their entries are unique and ' -- '*hashable*.\n' -- 'Items views also have set-like operations since the (key, ' -- 'value) pairs\n' -- 'are unique and the keys are hashable. If all values in an ' -- 'items view\n' -- 'are hashable as well, then the items view can interoperate ' -- 'with other\n' -- 'sets. (Values views are not treated as set-like since the ' -- 'entries are\n' -- 'generally not unique.) For set-like views, all of the ' -- 'operations\n' -- 'defined for the abstract base class "collections.abc.Set" ' -- 'are\n' -- 'available (for example, "==", "<", or "^"). While using ' -- 'set\n' -- 'operators, set-like views accept any iterable as the other ' -- 'operand,\n' -- 'unlike sets which only accept sets as the input.\n' -- '\n' -- 'An example of dictionary view usage:\n' -- '\n' -- " >>> dishes = {'eggs': 2, 'sausage': 1, 'bacon': 1, " -- "'spam': 500}\n" -- ' >>> keys = dishes.keys()\n' -- ' >>> values = dishes.values()\n' -- '\n' -- ' >>> # iteration\n' -- ' >>> n = 0\n' -- ' >>> for val in values:\n' -- ' ... n += val\n' -- ' ...\n' -- ' >>> print(n)\n' -- ' 504\n' -- '\n' -- ' >>> # keys and values are iterated over in the same order ' -- '(insertion order)\n' -- ' >>> list(keys)\n' -- " ['eggs', 'sausage', 'bacon', 'spam']\n" -- ' >>> list(values)\n' -- ' [2, 1, 1, 500]\n' -- '\n' -- ' >>> # view objects are dynamic and reflect dict changes\n' -- " >>> del dishes['eggs']\n" -- " >>> del dishes['sausage']\n" -- ' >>> list(keys)\n' -- " ['bacon', 'spam']\n" -- '\n' -- ' >>> # set operations\n' -- " >>> keys & {'eggs', 'bacon', 'salad'}\n" -- " {'bacon'}\n" -- " >>> keys ^ {'sausage', 'juice'} == {'juice', 'sausage', " -- "'bacon', 'spam'}\n" -- ' True\n' -- " >>> keys | ['juice', 'juice', 'juice'] == {'bacon', " -- "'spam', 'juice'}\n" -- ' True\n' -- '\n' -- ' >>> # get back a read-only proxy for the original ' -- 'dictionary\n' -- ' >>> values.mapping\n' -- " mappingproxy({'bacon': 1, 'spam': 500})\n" -- " >>> values.mapping['spam']\n" -- ' 500\n', -- 'typesmethods': 'Methods\n' -- '*******\n' -- '\n' -- 'Methods are functions that are called using the attribute ' -- 'notation.\n' -- 'There are two flavors: built-in methods (such as "append()" ' -- 'on lists)\n' -- 'and class instance method. Built-in methods are described ' -- 'with the\n' -- 'types that support them.\n' -- '\n' -- 'If you access a method (a function defined in a class ' -- 'namespace)\n' -- 'through an instance, you get a special object: a *bound ' -- 'method* (also\n' -- 'called instance method) object. When called, it will add the ' -- '"self"\n' -- 'argument to the argument list. Bound methods have two ' -- 'special read-\n' -- 'only attributes: "m.__self__" is the object on which the ' -- 'method\n' -- 'operates, and "m.__func__" is the function implementing the ' -- 'method.\n' -- 'Calling "m(arg-1, arg-2, ..., arg-n)" is completely ' -- 'equivalent to\n' -- 'calling "m.__func__(m.__self__, arg-1, arg-2, ..., arg-n)".\n' -- '\n' -- 'Like function objects, bound method objects support getting ' -- 'arbitrary\n' -- 'attributes. However, since method attributes are actually ' -- 'stored on\n' -- 'the underlying function object ("method.__func__"), setting ' -- 'method\n' -- 'attributes on bound methods is disallowed. Attempting to ' -- 'set an\n' -- 'attribute on a method results in an "AttributeError" being ' -- 'raised. In\n' -- 'order to set a method attribute, you need to explicitly set ' -- 'it on the\n' -- 'underlying function object:\n' -- '\n' -- ' >>> class C:\n' -- ' ... def method(self):\n' -- ' ... pass\n' -- ' ...\n' -- ' >>> c = C()\n' -- " >>> c.method.whoami = 'my name is method' # can't set on " -- 'the method\n' -- ' Traceback (most recent call last):\n' -- ' File "", line 1, in \n' -- " AttributeError: 'method' object has no attribute " -- "'whoami'\n" -- " >>> c.method.__func__.whoami = 'my name is method'\n" -- ' >>> c.method.whoami\n' -- " 'my name is method'\n" -- '\n' -- 'See Instance methods for more information.\n', -- 'typesmodules': 'Modules\n' -- '*******\n' -- '\n' -- 'The only special operation on a module is attribute access: ' -- '"m.name",\n' -- 'where *m* is a module and *name* accesses a name defined in ' -- '*m*’s\n' -- 'symbol table. Module attributes can be assigned to. (Note ' -- 'that the\n' -- '"import" statement is not, strictly speaking, an operation ' -- 'on a module\n' -- 'object; "import foo" does not require a module object named ' -- '*foo* to\n' -- 'exist, rather it requires an (external) *definition* for a ' -- 'module\n' -- 'named *foo* somewhere.)\n' -- '\n' -- 'A special attribute of every module is "__dict__". This is ' -- 'the\n' -- 'dictionary containing the module’s symbol table. Modifying ' -- 'this\n' -- 'dictionary will actually change the module’s symbol table, ' -- 'but direct\n' -- 'assignment to the "__dict__" attribute is not possible (you ' -- 'can write\n' -- '"m.__dict__[\'a\'] = 1", which defines "m.a" to be "1", but ' -- 'you can’t\n' -- 'write "m.__dict__ = {}"). Modifying "__dict__" directly is ' -- 'not\n' -- 'recommended.\n' -- '\n' -- 'Modules built into the interpreter are written like this: ' -- '"". If loaded from a file, they are ' -- 'written as\n' -- '"".\n', -- 'typesseq': 'Sequence Types — "list", "tuple", "range"\n' -- '*****************************************\n' -- '\n' -- 'There are three basic sequence types: lists, tuples, and range\n' -- 'objects. Additional sequence types tailored for processing of ' -- 'binary\n' -- 'data and text strings are described in dedicated sections.\n' -- '\n' -- '\n' -- 'Common Sequence Operations\n' -- '==========================\n' -- '\n' -- 'The operations in the following table are supported by most ' -- 'sequence\n' -- 'types, both mutable and immutable. The ' -- '"collections.abc.Sequence" ABC\n' -- 'is provided to make it easier to correctly implement these ' -- 'operations\n' -- 'on custom sequence types.\n' -- '\n' -- 'This table lists the sequence operations sorted in ascending ' -- 'priority.\n' -- 'In the table, *s* and *t* are sequences of the same type, *n*, ' -- '*i*,\n' -- '*j* and *k* are integers and *x* is an arbitrary object that ' -- 'meets any\n' -- 'type and value restrictions imposed by *s*.\n' -- '\n' -- 'The "in" and "not in" operations have the same priorities as ' -- 'the\n' -- 'comparison operations. The "+" (concatenation) and "*" ' -- '(repetition)\n' -- 'operations have the same priority as the corresponding numeric\n' -- 'operations. [3]\n' -- '\n' -- '+----------------------------+----------------------------------+------------+\n' -- '| Operation | Result ' -- '| Notes |\n' -- '|============================|==================================|============|\n' -- '| "x in s" | "True" if an item of *s* is ' -- '| (1) |\n' -- '| | equal to *x*, else "False" ' -- '| |\n' -- '+----------------------------+----------------------------------+------------+\n' -- '| "x not in s" | "False" if an item of *s* is ' -- '| (1) |\n' -- '| | equal to *x*, else "True" ' -- '| |\n' -- '+----------------------------+----------------------------------+------------+\n' -- '| "s + t" | the concatenation of *s* and *t* ' -- '| (6)(7) |\n' -- '+----------------------------+----------------------------------+------------+\n' -- '| "s * n" or "n * s" | equivalent to adding *s* to ' -- '| (2)(7) |\n' -- '| | itself *n* times ' -- '| |\n' -- '+----------------------------+----------------------------------+------------+\n' -- '| "s[i]" | *i*th item of *s*, origin 0 ' -- '| (3) |\n' -- '+----------------------------+----------------------------------+------------+\n' -- '| "s[i:j]" | slice of *s* from *i* to *j* ' -- '| (3)(4) |\n' -- '+----------------------------+----------------------------------+------------+\n' -- '| "s[i:j:k]" | slice of *s* from *i* to *j* ' -- '| (3)(5) |\n' -- '| | with step *k* ' -- '| |\n' -- '+----------------------------+----------------------------------+------------+\n' -- '| "len(s)" | length of *s* ' -- '| |\n' -- '+----------------------------+----------------------------------+------------+\n' -- '| "min(s)" | smallest item of *s* ' -- '| |\n' -- '+----------------------------+----------------------------------+------------+\n' -- '| "max(s)" | largest item of *s* ' -- '| |\n' -- '+----------------------------+----------------------------------+------------+\n' -- '| "s.index(x[, i[, j]])" | index of the first occurrence of ' -- '| (8) |\n' -- '| | *x* in *s* (at or after index ' -- '| |\n' -- '| | *i* and before index *j*) ' -- '| |\n' -- '+----------------------------+----------------------------------+------------+\n' -- '| "s.count(x)" | total number of occurrences of ' -- '| |\n' -- '| | *x* in *s* ' -- '| |\n' -- '+----------------------------+----------------------------------+------------+\n' -- '\n' -- 'Sequences of the same type also support comparisons. In ' -- 'particular,\n' -- 'tuples and lists are compared lexicographically by comparing\n' -- 'corresponding elements. This means that to compare equal, every\n' -- 'element must compare equal and the two sequences must be of the ' -- 'same\n' -- 'type and have the same length. (For full details see ' -- 'Comparisons in\n' -- 'the language reference.)\n' -- '\n' -- 'Forward and reversed iterators over mutable sequences access ' -- 'values\n' -- 'using an index. That index will continue to march forward (or\n' -- 'backward) even if the underlying sequence is mutated. The ' -- 'iterator\n' -- 'terminates only when an "IndexError" or a "StopIteration" is\n' -- 'encountered (or when the index drops below zero).\n' -- '\n' -- 'Notes:\n' -- '\n' -- '1. While the "in" and "not in" operations are used only for ' -- 'simple\n' -- ' containment testing in the general case, some specialised ' -- 'sequences\n' -- ' (such as "str", "bytes" and "bytearray") also use them for\n' -- ' subsequence testing:\n' -- '\n' -- ' >>> "gg" in "eggs"\n' -- ' True\n' -- '\n' -- '2. Values of *n* less than "0" are treated as "0" (which yields ' -- 'an\n' -- ' empty sequence of the same type as *s*). Note that items in ' -- 'the\n' -- ' sequence *s* are not copied; they are referenced multiple ' -- 'times.\n' -- ' This often haunts new Python programmers; consider:\n' -- '\n' -- ' >>> lists = [[]] * 3\n' -- ' >>> lists\n' -- ' [[], [], []]\n' -- ' >>> lists[0].append(3)\n' -- ' >>> lists\n' -- ' [[3], [3], [3]]\n' -- '\n' -- ' What has happened is that "[[]]" is a one-element list ' -- 'containing\n' -- ' an empty list, so all three elements of "[[]] * 3" are ' -- 'references\n' -- ' to this single empty list. Modifying any of the elements of\n' -- ' "lists" modifies this single list. You can create a list of\n' -- ' different lists this way:\n' -- '\n' -- ' >>> lists = [[] for i in range(3)]\n' -- ' >>> lists[0].append(3)\n' -- ' >>> lists[1].append(5)\n' -- ' >>> lists[2].append(7)\n' -- ' >>> lists\n' -- ' [[3], [5], [7]]\n' -- '\n' -- ' Further explanation is available in the FAQ entry How do I ' -- 'create a\n' -- ' multidimensional list?.\n' -- '\n' -- '3. If *i* or *j* is negative, the index is relative to the end ' -- 'of\n' -- ' sequence *s*: "len(s) + i" or "len(s) + j" is substituted. ' -- 'But\n' -- ' note that "-0" is still "0".\n' -- '\n' -- '4. The slice of *s* from *i* to *j* is defined as the sequence ' -- 'of\n' -- ' items with index *k* such that "i <= k < j". If *i* or *j* ' -- 'is\n' -- ' greater than "len(s)", use "len(s)". If *i* is omitted or ' -- '"None",\n' -- ' use "0". If *j* is omitted or "None", use "len(s)". If *i* ' -- 'is\n' -- ' greater than or equal to *j*, the slice is empty.\n' -- '\n' -- '5. The slice of *s* from *i* to *j* with step *k* is defined as ' -- 'the\n' -- ' sequence of items with index "x = i + n*k" such that "0 <= n ' -- '<\n' -- ' (j-i)/k". In other words, the indices are "i", "i+k", ' -- '"i+2*k",\n' -- ' "i+3*k" and so on, stopping when *j* is reached (but never\n' -- ' including *j*). When *k* is positive, *i* and *j* are ' -- 'reduced to\n' -- ' "len(s)" if they are greater. When *k* is negative, *i* and ' -- '*j* are\n' -- ' reduced to "len(s) - 1" if they are greater. If *i* or *j* ' -- 'are\n' -- ' omitted or "None", they become “end†values (which end ' -- 'depends on\n' -- ' the sign of *k*). Note, *k* cannot be zero. If *k* is ' -- '"None", it\n' -- ' is treated like "1".\n' -- '\n' -- '6. Concatenating immutable sequences always results in a new ' -- 'object.\n' -- ' This means that building up a sequence by repeated ' -- 'concatenation\n' -- ' will have a quadratic runtime cost in the total sequence ' -- 'length.\n' -- ' To get a linear runtime cost, you must switch to one of the\n' -- ' alternatives below:\n' -- '\n' -- ' * if concatenating "str" objects, you can build a list and ' -- 'use\n' -- ' "str.join()" at the end or else write to an "io.StringIO"\n' -- ' instance and retrieve its value when complete\n' -- '\n' -- ' * if concatenating "bytes" objects, you can similarly use\n' -- ' "bytes.join()" or "io.BytesIO", or you can do in-place\n' -- ' concatenation with a "bytearray" object. "bytearray" ' -- 'objects are\n' -- ' mutable and have an efficient overallocation mechanism\n' -- '\n' -- ' * if concatenating "tuple" objects, extend a "list" instead\n' -- '\n' -- ' * for other types, investigate the relevant class ' -- 'documentation\n' -- '\n' -- '7. Some sequence types (such as "range") only support item ' -- 'sequences\n' -- ' that follow specific patterns, and hence don’t support ' -- 'sequence\n' -- ' concatenation or repetition.\n' -- '\n' -- '8. "index" raises "ValueError" when *x* is not found in *s*. Not ' -- 'all\n' -- ' implementations support passing the additional arguments *i* ' -- 'and\n' -- ' *j*. These arguments allow efficient searching of subsections ' -- 'of\n' -- ' the sequence. Passing the extra arguments is roughly ' -- 'equivalent to\n' -- ' using "s[i:j].index(x)", only without copying any data and ' -- 'with the\n' -- ' returned index being relative to the start of the sequence ' -- 'rather\n' -- ' than the start of the slice.\n' -- '\n' -- '\n' -- 'Immutable Sequence Types\n' -- '========================\n' -- '\n' -- 'The only operation that immutable sequence types generally ' -- 'implement\n' -- 'that is not also implemented by mutable sequence types is ' -- 'support for\n' -- 'the "hash()" built-in.\n' -- '\n' -- 'This support allows immutable sequences, such as "tuple" ' -- 'instances, to\n' -- 'be used as "dict" keys and stored in "set" and "frozenset" ' -- 'instances.\n' -- '\n' -- 'Attempting to hash an immutable sequence that contains ' -- 'unhashable\n' -- 'values will result in "TypeError".\n' -- '\n' -- '\n' -- 'Mutable Sequence Types\n' -- '======================\n' -- '\n' -- 'The operations in the following table are defined on mutable ' -- 'sequence\n' -- 'types. The "collections.abc.MutableSequence" ABC is provided to ' -- 'make\n' -- 'it easier to correctly implement these operations on custom ' -- 'sequence\n' -- 'types.\n' -- '\n' -- 'In the table *s* is an instance of a mutable sequence type, *t* ' -- 'is any\n' -- 'iterable object and *x* is an arbitrary object that meets any ' -- 'type and\n' -- 'value restrictions imposed by *s* (for example, "bytearray" ' -- 'only\n' -- 'accepts integers that meet the value restriction "0 <= x <= ' -- '255").\n' -- '\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| Operation | ' -- 'Result | Notes |\n' -- '|================================|==================================|=======================|\n' -- '| "s[i] = x" | item *i* of *s* is replaced ' -- 'by | |\n' -- '| | ' -- '*x* | |\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| "s[i:j] = t" | slice of *s* from *i* to *j* ' -- 'is | |\n' -- '| | replaced by the contents of ' -- 'the | |\n' -- '| | iterable ' -- '*t* | |\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| "del s[i:j]" | same as "s[i:j] = ' -- '[]" | |\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| "s[i:j:k] = t" | the elements of "s[i:j:k]" ' -- 'are | (1) |\n' -- '| | replaced by those of ' -- '*t* | |\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| "del s[i:j:k]" | removes the elements ' -- 'of | |\n' -- '| | "s[i:j:k]" from the ' -- 'list | |\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| "s.append(x)" | appends *x* to the end of ' -- 'the | |\n' -- '| | sequence (same ' -- 'as | |\n' -- '| | "s[len(s):len(s)] = ' -- '[x]") | |\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| "s.clear()" | removes all items from *s* ' -- '(same | (5) |\n' -- '| | as "del ' -- 's[:]") | |\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| "s.copy()" | creates a shallow copy of ' -- '*s* | (5) |\n' -- '| | (same as ' -- '"s[:]") | |\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| "s.extend(t)" or "s += t" | extends *s* with the contents ' -- 'of | |\n' -- '| | *t* (for the most part the ' -- 'same | |\n' -- '| | as "s[len(s):len(s)] = ' -- 't") | |\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| "s *= n" | updates *s* with its ' -- 'contents | (6) |\n' -- '| | repeated *n* ' -- 'times | |\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| "s.insert(i, x)" | inserts *x* into *s* at ' -- 'the | |\n' -- '| | index given by *i* (same ' -- 'as | |\n' -- '| | "s[i:i] = ' -- '[x]") | |\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| "s.pop()" or "s.pop(i)" | retrieves the item at *i* ' -- 'and | (2) |\n' -- '| | also removes it from ' -- '*s* | |\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| "s.remove(x)" | removes the first item from ' -- '*s* | (3) |\n' -- '| | where "s[i]" is equal to ' -- '*x* | |\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| "s.reverse()" | reverses the items of *s* ' -- 'in | (4) |\n' -- '| | ' -- 'place | |\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '\n' -- 'Notes:\n' -- '\n' -- '1. If *k* is not equal to "1", *t* must have the same length as ' -- 'the\n' -- ' slice it is replacing.\n' -- '\n' -- '2. The optional argument *i* defaults to "-1", so that by ' -- 'default the\n' -- ' last item is removed and returned.\n' -- '\n' -- '3. "remove()" raises "ValueError" when *x* is not found in *s*.\n' -- '\n' -- '4. The "reverse()" method modifies the sequence in place for ' -- 'economy\n' -- ' of space when reversing a large sequence. To remind users ' -- 'that it\n' -- ' operates by side effect, it does not return the reversed ' -- 'sequence.\n' -- '\n' -- '5. "clear()" and "copy()" are included for consistency with the\n' -- ' interfaces of mutable containers that don’t support slicing\n' -- ' operations (such as "dict" and "set"). "copy()" is not part ' -- 'of the\n' -- ' "collections.abc.MutableSequence" ABC, but most concrete ' -- 'mutable\n' -- ' sequence classes provide it.\n' -- '\n' -- ' Added in version 3.3: "clear()" and "copy()" methods.\n' -- '\n' -- '6. The value *n* is an integer, or an object implementing\n' -- ' "__index__()". Zero and negative values of *n* clear the ' -- 'sequence.\n' -- ' Items in the sequence are not copied; they are referenced ' -- 'multiple\n' -- ' times, as explained for "s * n" under Common Sequence ' -- 'Operations.\n' -- '\n' -- '\n' -- 'Lists\n' -- '=====\n' -- '\n' -- 'Lists are mutable sequences, typically used to store collections ' -- 'of\n' -- 'homogeneous items (where the precise degree of similarity will ' -- 'vary by\n' -- 'application).\n' -- '\n' -- 'class list([iterable])\n' -- '\n' -- ' Lists may be constructed in several ways:\n' -- '\n' -- ' * Using a pair of square brackets to denote the empty list: ' -- '"[]"\n' -- '\n' -- ' * Using square brackets, separating items with commas: "[a]", ' -- '"[a,\n' -- ' b, c]"\n' -- '\n' -- ' * Using a list comprehension: "[x for x in iterable]"\n' -- '\n' -- ' * Using the type constructor: "list()" or "list(iterable)"\n' -- '\n' -- ' The constructor builds a list whose items are the same and in ' -- 'the\n' -- ' same order as *iterable*’s items. *iterable* may be either ' -- 'a\n' -- ' sequence, a container that supports iteration, or an ' -- 'iterator\n' -- ' object. If *iterable* is already a list, a copy is made and\n' -- ' returned, similar to "iterable[:]". For example, ' -- '"list(\'abc\')"\n' -- ' returns "[\'a\', \'b\', \'c\']" and "list( (1, 2, 3) )" ' -- 'returns "[1, 2,\n' -- ' 3]". If no argument is given, the constructor creates a new ' -- 'empty\n' -- ' list, "[]".\n' -- '\n' -- ' Many other operations also produce lists, including the ' -- '"sorted()"\n' -- ' built-in.\n' -- '\n' -- ' Lists implement all of the common and mutable sequence ' -- 'operations.\n' -- ' Lists also provide the following additional method:\n' -- '\n' -- ' sort(*, key=None, reverse=False)\n' -- '\n' -- ' This method sorts the list in place, using only "<" ' -- 'comparisons\n' -- ' between items. Exceptions are not suppressed - if any ' -- 'comparison\n' -- ' operations fail, the entire sort operation will fail (and ' -- 'the\n' -- ' list will likely be left in a partially modified state).\n' -- '\n' -- ' "sort()" accepts two arguments that can only be passed by\n' -- ' keyword (keyword-only arguments):\n' -- '\n' -- ' *key* specifies a function of one argument that is used ' -- 'to\n' -- ' extract a comparison key from each list element (for ' -- 'example,\n' -- ' "key=str.lower"). The key corresponding to each item in ' -- 'the list\n' -- ' is calculated once and then used for the entire sorting ' -- 'process.\n' -- ' The default value of "None" means that list items are ' -- 'sorted\n' -- ' directly without calculating a separate key value.\n' -- '\n' -- ' The "functools.cmp_to_key()" utility is available to ' -- 'convert a\n' -- ' 2.x style *cmp* function to a *key* function.\n' -- '\n' -- ' *reverse* is a boolean value. If set to "True", then the ' -- 'list\n' -- ' elements are sorted as if each comparison were reversed.\n' -- '\n' -- ' This method modifies the sequence in place for economy of ' -- 'space\n' -- ' when sorting a large sequence. To remind users that it ' -- 'operates\n' -- ' by side effect, it does not return the sorted sequence ' -- '(use\n' -- ' "sorted()" to explicitly request a new sorted list ' -- 'instance).\n' -- '\n' -- ' The "sort()" method is guaranteed to be stable. A sort ' -- 'is\n' -- ' stable if it guarantees not to change the relative order ' -- 'of\n' -- ' elements that compare equal — this is helpful for sorting ' -- 'in\n' -- ' multiple passes (for example, sort by department, then by ' -- 'salary\n' -- ' grade).\n' -- '\n' -- ' For sorting examples and a brief sorting tutorial, see ' -- 'Sorting\n' -- ' Techniques.\n' -- '\n' -- ' **CPython implementation detail:** While a list is being ' -- 'sorted,\n' -- ' the effect of attempting to mutate, or even inspect, the ' -- 'list is\n' -- ' undefined. The C implementation of Python makes the list ' -- 'appear\n' -- ' empty for the duration, and raises "ValueError" if it can ' -- 'detect\n' -- ' that the list has been mutated during a sort.\n' -- '\n' -- '\n' -- 'Tuples\n' -- '======\n' -- '\n' -- 'Tuples are immutable sequences, typically used to store ' -- 'collections of\n' -- 'heterogeneous data (such as the 2-tuples produced by the ' -- '"enumerate()"\n' -- 'built-in). Tuples are also used for cases where an immutable ' -- 'sequence\n' -- 'of homogeneous data is needed (such as allowing storage in a ' -- '"set" or\n' -- '"dict" instance).\n' -- '\n' -- 'class tuple([iterable])\n' -- '\n' -- ' Tuples may be constructed in a number of ways:\n' -- '\n' -- ' * Using a pair of parentheses to denote the empty tuple: ' -- '"()"\n' -- '\n' -- ' * Using a trailing comma for a singleton tuple: "a," or ' -- '"(a,)"\n' -- '\n' -- ' * Separating items with commas: "a, b, c" or "(a, b, c)"\n' -- '\n' -- ' * Using the "tuple()" built-in: "tuple()" or ' -- '"tuple(iterable)"\n' -- '\n' -- ' The constructor builds a tuple whose items are the same and ' -- 'in the\n' -- ' same order as *iterable*’s items. *iterable* may be either ' -- 'a\n' -- ' sequence, a container that supports iteration, or an ' -- 'iterator\n' -- ' object. If *iterable* is already a tuple, it is returned\n' -- ' unchanged. For example, "tuple(\'abc\')" returns "(\'a\', ' -- '\'b\', \'c\')"\n' -- ' and "tuple( [1, 2, 3] )" returns "(1, 2, 3)". If no argument ' -- 'is\n' -- ' given, the constructor creates a new empty tuple, "()".\n' -- '\n' -- ' Note that it is actually the comma which makes a tuple, not ' -- 'the\n' -- ' parentheses. The parentheses are optional, except in the ' -- 'empty\n' -- ' tuple case, or when they are needed to avoid syntactic ' -- 'ambiguity.\n' -- ' For example, "f(a, b, c)" is a function call with three ' -- 'arguments,\n' -- ' while "f((a, b, c))" is a function call with a 3-tuple as the ' -- 'sole\n' -- ' argument.\n' -- '\n' -- ' Tuples implement all of the common sequence operations.\n' -- '\n' -- 'For heterogeneous collections of data where access by name is ' -- 'clearer\n' -- 'than access by index, "collections.namedtuple()" may be a more\n' -- 'appropriate choice than a simple tuple object.\n' -- '\n' -- '\n' -- 'Ranges\n' -- '======\n' -- '\n' -- 'The "range" type represents an immutable sequence of numbers and ' -- 'is\n' -- 'commonly used for looping a specific number of times in "for" ' -- 'loops.\n' -- '\n' -- 'class range(stop)\n' -- 'class range(start, stop[, step])\n' -- '\n' -- ' The arguments to the range constructor must be integers ' -- '(either\n' -- ' built-in "int" or any object that implements the ' -- '"__index__()"\n' -- ' special method). If the *step* argument is omitted, it ' -- 'defaults to\n' -- ' "1". If the *start* argument is omitted, it defaults to "0". ' -- 'If\n' -- ' *step* is zero, "ValueError" is raised.\n' -- '\n' -- ' For a positive *step*, the contents of a range "r" are ' -- 'determined\n' -- ' by the formula "r[i] = start + step*i" where "i >= 0" and ' -- '"r[i] <\n' -- ' stop".\n' -- '\n' -- ' For a negative *step*, the contents of the range are still\n' -- ' determined by the formula "r[i] = start + step*i", but the\n' -- ' constraints are "i >= 0" and "r[i] > stop".\n' -- '\n' -- ' A range object will be empty if "r[0]" does not meet the ' -- 'value\n' -- ' constraint. Ranges do support negative indices, but these ' -- 'are\n' -- ' interpreted as indexing from the end of the sequence ' -- 'determined by\n' -- ' the positive indices.\n' -- '\n' -- ' Ranges containing absolute values larger than "sys.maxsize" ' -- 'are\n' -- ' permitted but some features (such as "len()") may raise\n' -- ' "OverflowError".\n' -- '\n' -- ' Range examples:\n' -- '\n' -- ' >>> list(range(10))\n' -- ' [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n' -- ' >>> list(range(1, 11))\n' -- ' [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n' -- ' >>> list(range(0, 30, 5))\n' -- ' [0, 5, 10, 15, 20, 25]\n' -- ' >>> list(range(0, 10, 3))\n' -- ' [0, 3, 6, 9]\n' -- ' >>> list(range(0, -10, -1))\n' -- ' [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]\n' -- ' >>> list(range(0))\n' -- ' []\n' -- ' >>> list(range(1, 0))\n' -- ' []\n' -- '\n' -- ' Ranges implement all of the common sequence operations ' -- 'except\n' -- ' concatenation and repetition (due to the fact that range ' -- 'objects\n' -- ' can only represent sequences that follow a strict pattern ' -- 'and\n' -- ' repetition and concatenation will usually violate that ' -- 'pattern).\n' -- '\n' -- ' start\n' -- '\n' -- ' The value of the *start* parameter (or "0" if the ' -- 'parameter was\n' -- ' not supplied)\n' -- '\n' -- ' stop\n' -- '\n' -- ' The value of the *stop* parameter\n' -- '\n' -- ' step\n' -- '\n' -- ' The value of the *step* parameter (or "1" if the parameter ' -- 'was\n' -- ' not supplied)\n' -- '\n' -- 'The advantage of the "range" type over a regular "list" or ' -- '"tuple" is\n' -- 'that a "range" object will always take the same (small) amount ' -- 'of\n' -- 'memory, no matter the size of the range it represents (as it ' -- 'only\n' -- 'stores the "start", "stop" and "step" values, calculating ' -- 'individual\n' -- 'items and subranges as needed).\n' -- '\n' -- 'Range objects implement the "collections.abc.Sequence" ABC, and\n' -- 'provide features such as containment tests, element index ' -- 'lookup,\n' -- 'slicing and support for negative indices (see Sequence Types — ' -- 'list,\n' -- 'tuple, range):\n' -- '\n' -- '>>> r = range(0, 20, 2)\n' -- '>>> r\n' -- 'range(0, 20, 2)\n' -- '>>> 11 in r\n' -- 'False\n' -- '>>> 10 in r\n' -- 'True\n' -- '>>> r.index(10)\n' -- '5\n' -- '>>> r[5]\n' -- '10\n' -- '>>> r[:5]\n' -- 'range(0, 10, 2)\n' -- '>>> r[-1]\n' -- '18\n' -- '\n' -- 'Testing range objects for equality with "==" and "!=" compares ' -- 'them as\n' -- 'sequences. That is, two range objects are considered equal if ' -- 'they\n' -- 'represent the same sequence of values. (Note that two range ' -- 'objects\n' -- 'that compare equal might have different "start", "stop" and ' -- '"step"\n' -- 'attributes, for example "range(0) == range(2, 1, 3)" or ' -- '"range(0, 3,\n' -- '2) == range(0, 4, 2)".)\n' -- '\n' -- 'Changed in version 3.2: Implement the Sequence ABC. Support ' -- 'slicing\n' -- 'and negative indices. Test "int" objects for membership in ' -- 'constant\n' -- 'time instead of iterating through all items.\n' -- '\n' -- 'Changed in version 3.3: Define ‘==’ and ‘!=’ to compare range ' -- 'objects\n' -- 'based on the sequence of values they define (instead of ' -- 'comparing\n' -- 'based on object identity).Added the "start", "stop" and "step"\n' -- 'attributes.\n' -- '\n' -- 'See also:\n' -- '\n' -- ' * The linspace recipe shows how to implement a lazy version of ' -- 'range\n' -- ' suitable for floating-point applications.\n', -- 'typesseq-mutable': 'Mutable Sequence Types\n' -- '**********************\n' -- '\n' -- 'The operations in the following table are defined on ' -- 'mutable sequence\n' -- 'types. The "collections.abc.MutableSequence" ABC is ' -- 'provided to make\n' -- 'it easier to correctly implement these operations on ' -- 'custom sequence\n' -- 'types.\n' -- '\n' -- 'In the table *s* is an instance of a mutable sequence ' -- 'type, *t* is any\n' -- 'iterable object and *x* is an arbitrary object that ' -- 'meets any type and\n' -- 'value restrictions imposed by *s* (for example, ' -- '"bytearray" only\n' -- 'accepts integers that meet the value restriction "0 <= x ' -- '<= 255").\n' -- '\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| Operation | ' -- 'Result | Notes ' -- '|\n' -- '|================================|==================================|=======================|\n' -- '| "s[i] = x" | item *i* of *s* is ' -- 'replaced by | |\n' -- '| | ' -- '*x* | ' -- '|\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| "s[i:j] = t" | slice of *s* from *i* ' -- 'to *j* is | |\n' -- '| | replaced by the ' -- 'contents of the | |\n' -- '| | iterable ' -- '*t* | |\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| "del s[i:j]" | same as "s[i:j] = ' -- '[]" | |\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| "s[i:j:k] = t" | the elements of ' -- '"s[i:j:k]" are | (1) |\n' -- '| | replaced by those of ' -- '*t* | |\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| "del s[i:j:k]" | removes the elements ' -- 'of | |\n' -- '| | "s[i:j:k]" from the ' -- 'list | |\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| "s.append(x)" | appends *x* to the ' -- 'end of the | |\n' -- '| | sequence (same ' -- 'as | |\n' -- '| | "s[len(s):len(s)] = ' -- '[x]") | |\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| "s.clear()" | removes all items ' -- 'from *s* (same | (5) |\n' -- '| | as "del ' -- 's[:]") | |\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| "s.copy()" | creates a shallow ' -- 'copy of *s* | (5) |\n' -- '| | (same as ' -- '"s[:]") | |\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| "s.extend(t)" or "s += t" | extends *s* with the ' -- 'contents of | |\n' -- '| | *t* (for the most ' -- 'part the same | |\n' -- '| | as "s[len(s):len(s)] ' -- '= t") | |\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| "s *= n" | updates *s* with its ' -- 'contents | (6) |\n' -- '| | repeated *n* ' -- 'times | |\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| "s.insert(i, x)" | inserts *x* into *s* ' -- 'at the | |\n' -- '| | index given by *i* ' -- '(same as | |\n' -- '| | "s[i:i] = ' -- '[x]") | |\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| "s.pop()" or "s.pop(i)" | retrieves the item at ' -- '*i* and | (2) |\n' -- '| | also removes it from ' -- '*s* | |\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| "s.remove(x)" | removes the first ' -- 'item from *s* | (3) |\n' -- '| | where "s[i]" is equal ' -- 'to *x* | |\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '| "s.reverse()" | reverses the items of ' -- '*s* in | (4) |\n' -- '| | ' -- 'place | ' -- '|\n' -- '+--------------------------------+----------------------------------+-----------------------+\n' -- '\n' -- 'Notes:\n' -- '\n' -- '1. If *k* is not equal to "1", *t* must have the same ' -- 'length as the\n' -- ' slice it is replacing.\n' -- '\n' -- '2. The optional argument *i* defaults to "-1", so that ' -- 'by default the\n' -- ' last item is removed and returned.\n' -- '\n' -- '3. "remove()" raises "ValueError" when *x* is not found ' -- 'in *s*.\n' -- '\n' -- '4. The "reverse()" method modifies the sequence in place ' -- 'for economy\n' -- ' of space when reversing a large sequence. To remind ' -- 'users that it\n' -- ' operates by side effect, it does not return the ' -- 'reversed sequence.\n' -- '\n' -- '5. "clear()" and "copy()" are included for consistency ' -- 'with the\n' -- ' interfaces of mutable containers that don’t support ' -- 'slicing\n' -- ' operations (such as "dict" and "set"). "copy()" is ' -- 'not part of the\n' -- ' "collections.abc.MutableSequence" ABC, but most ' -- 'concrete mutable\n' -- ' sequence classes provide it.\n' -- '\n' -- ' Added in version 3.3: "clear()" and "copy()" ' -- 'methods.\n' -- '\n' -- '6. The value *n* is an integer, or an object ' -- 'implementing\n' -- ' "__index__()". Zero and negative values of *n* clear ' -- 'the sequence.\n' -- ' Items in the sequence are not copied; they are ' -- 'referenced multiple\n' -- ' times, as explained for "s * n" under Common Sequence ' -- 'Operations.\n', -- 'unary': 'Unary arithmetic and bitwise operations\n' -- '***************************************\n' -- '\n' -- 'All unary arithmetic and bitwise operations have the same ' -- 'priority:\n' -- '\n' -- ' u_expr ::= power | "-" u_expr | "+" u_expr | "~" u_expr\n' -- '\n' -- 'The unary "-" (minus) operator yields the negation of its numeric\n' -- 'argument; the operation can be overridden with the "__neg__()" ' -- 'special\n' -- 'method.\n' -- '\n' -- 'The unary "+" (plus) operator yields its numeric argument ' -- 'unchanged;\n' -- 'the operation can be overridden with the "__pos__()" special ' -- 'method.\n' -- '\n' -- 'The unary "~" (invert) operator yields the bitwise inversion of ' -- 'its\n' -- 'integer argument. The bitwise inversion of "x" is defined as\n' -- '"-(x+1)". It only applies to integral numbers or to custom ' -- 'objects\n' -- 'that override the "__invert__()" special method.\n' -- '\n' -- 'In all three cases, if the argument does not have the proper type, ' -- 'a\n' -- '"TypeError" exception is raised.\n', -- 'while': 'The "while" statement\n' -- '*********************\n' -- '\n' -- 'The "while" statement is used for repeated execution as long as an\n' -- 'expression is true:\n' -- '\n' -- ' while_stmt ::= "while" assignment_expression ":" suite\n' -- ' ["else" ":" suite]\n' -- '\n' -- 'This repeatedly tests the expression and, if it is true, executes ' -- 'the\n' -- 'first suite; if the expression is false (which may be the first ' -- 'time\n' -- 'it is tested) the suite of the "else" clause, if present, is ' -- 'executed\n' -- 'and the loop terminates.\n' -- '\n' -- 'A "break" statement executed in the first suite terminates the ' -- 'loop\n' -- 'without executing the "else" clause’s suite. A "continue" ' -- 'statement\n' -- 'executed in the first suite skips the rest of the suite and goes ' -- 'back\n' -- 'to testing the expression.\n', -- 'with': 'The "with" statement\n' -- '********************\n' -- '\n' -- 'The "with" statement is used to wrap the execution of a block with\n' -- 'methods defined by a context manager (see section With Statement\n' -- 'Context Managers). This allows common "try"…"except"…"finally" ' -- 'usage\n' -- 'patterns to be encapsulated for convenient reuse.\n' -- '\n' -- ' with_stmt ::= "with" ( "(" with_stmt_contents ","? ")" | ' -- 'with_stmt_contents ) ":" suite\n' -- ' with_stmt_contents ::= with_item ("," with_item)*\n' -- ' with_item ::= expression ["as" target]\n' -- '\n' -- 'The execution of the "with" statement with one “item†proceeds as\n' -- 'follows:\n' -- '\n' -- '1. The context expression (the expression given in the "with_item") ' -- 'is\n' -- ' evaluated to obtain a context manager.\n' -- '\n' -- '2. The context manager’s "__enter__()" is loaded for later use.\n' -- '\n' -- '3. The context manager’s "__exit__()" is loaded for later use.\n' -- '\n' -- '4. The context manager’s "__enter__()" method is invoked.\n' -- '\n' -- '5. If a target was included in the "with" statement, the return ' -- 'value\n' -- ' from "__enter__()" is assigned to it.\n' -- '\n' -- ' Note:\n' -- '\n' -- ' The "with" statement guarantees that if the "__enter__()" ' -- 'method\n' -- ' returns without an error, then "__exit__()" will always be\n' -- ' called. Thus, if an error occurs during the assignment to the\n' -- ' target list, it will be treated the same as an error occurring\n' -- ' within the suite would be. See step 7 below.\n' -- '\n' -- '6. The suite is executed.\n' -- '\n' -- '7. The context manager’s "__exit__()" method is invoked. If an\n' -- ' exception caused the suite to be exited, its type, value, and\n' -- ' traceback are passed as arguments to "__exit__()". Otherwise, ' -- 'three\n' -- ' "None" arguments are supplied.\n' -- '\n' -- ' If the suite was exited due to an exception, and the return ' -- 'value\n' -- ' from the "__exit__()" method was false, the exception is ' -- 'reraised.\n' -- ' If the return value was true, the exception is suppressed, and\n' -- ' execution continues with the statement following the "with"\n' -- ' statement.\n' -- '\n' -- ' If the suite was exited for any reason other than an exception, ' -- 'the\n' -- ' return value from "__exit__()" is ignored, and execution ' -- 'proceeds\n' -- ' at the normal location for the kind of exit that was taken.\n' -- '\n' -- 'The following code:\n' -- '\n' -- ' with EXPRESSION as TARGET:\n' -- ' SUITE\n' -- '\n' -- 'is semantically equivalent to:\n' -- '\n' -- ' manager = (EXPRESSION)\n' -- ' enter = type(manager).__enter__\n' -- ' exit = type(manager).__exit__\n' -- ' value = enter(manager)\n' -- '\n' -- ' try:\n' -- ' TARGET = value\n' -- ' SUITE\n' -- ' except:\n' -- ' if not exit(manager, *sys.exc_info()):\n' -- ' raise\n' -- ' else:\n' -- ' exit(manager, None, None, None)\n' -- '\n' -- 'With more than one item, the context managers are processed as if\n' -- 'multiple "with" statements were nested:\n' -- '\n' -- ' with A() as a, B() as b:\n' -- ' SUITE\n' -- '\n' -- 'is semantically equivalent to:\n' -- '\n' -- ' with A() as a:\n' -- ' with B() as b:\n' -- ' SUITE\n' -- '\n' -- 'You can also write multi-item context managers in multiple lines if\n' -- 'the items are surrounded by parentheses. For example:\n' -- '\n' -- ' with (\n' -- ' A() as a,\n' -- ' B() as b,\n' -- ' ):\n' -- ' SUITE\n' -- '\n' -- 'Changed in version 3.1: Support for multiple context expressions.\n' -- '\n' -- 'Changed in version 3.10: Support for using grouping parentheses to\n' -- 'break the statement in multiple lines.\n' -- '\n' -- 'See also:\n' -- '\n' -- ' **PEP 343** - The “with†statement\n' -- ' The specification, background, and examples for the Python ' -- '"with"\n' -- ' statement.\n', -- 'yield': 'The "yield" statement\n' -- '*********************\n' -- '\n' -- ' yield_stmt ::= yield_expression\n' -- '\n' -- 'A "yield" statement is semantically equivalent to a yield ' -- 'expression.\n' -- 'The "yield" statement can be used to omit the parentheses that ' -- 'would\n' -- 'otherwise be required in the equivalent yield expression ' -- 'statement.\n' -- 'For example, the yield statements\n' -- '\n' -- ' yield \n' -- ' yield from \n' -- '\n' -- 'are equivalent to the yield expression statements\n' -- '\n' -- ' (yield )\n' -- ' (yield from )\n' -- '\n' -- 'Yield expressions and statements are only used when defining a\n' -- '*generator* function, and are only used in the body of the ' -- 'generator\n' -- 'function. Using "yield" in a function definition is sufficient to\n' -- 'cause that definition to create a generator function instead of a\n' -- 'normal function.\n' -- '\n' -- 'For full details of "yield" semantics, refer to the Yield ' -- 'expressions\n' -- 'section.\n'} -+ -+topics = { -+ 'assert': r'''The "assert" statement -+********************** -+ -+Assert statements are a convenient way to insert debugging assertions -+into a program: -+ -+ **assert_stmt**: "assert" "expression" ["," "expression"] -+ -+The simple form, "assert expression", is equivalent to -+ -+ if __debug__: -+ if not expression: raise AssertionError -+ -+The extended form, "assert expression1, expression2", is equivalent to -+ -+ if __debug__: -+ if not expression1: raise AssertionError(expression2) -+ -+These equivalences assume that "__debug__" and "AssertionError" refer -+to the built-in variables with those names. In the current -+implementation, the built-in variable "__debug__" is "True" under -+normal circumstances, "False" when optimization is requested (command -+line option "-O"). The current code generator emits no code for an -+"assert" statement when optimization is requested at compile time. -+Note that it is unnecessary to include the source code for the -+expression that failed in the error message; it will be displayed as -+part of the stack trace. -+ -+Assignments to "__debug__" are illegal. The value for the built-in -+variable is determined when the interpreter starts. -+''', -+ 'assignment': r'''Assignment statements -+********************* -+ -+Assignment statements are used to (re)bind names to values and to -+modify attributes or items of mutable objects: -+ -+ **assignment_stmt**: ("target_list" "=")+ ("starred_expression" | "yield_expression") -+ **target_list**: "target" ("," "target")* [","] -+ **target**: "identifier" -+ | "(" ["target_list"] ")" -+ | "[" ["target_list"] "]" -+ | "attributeref" -+ | "subscription" -+ | "slicing" -+ | "*" "target" -+ -+(See section Primaries for the syntax definitions for *attributeref*, -+*subscription*, and *slicing*.) -+ -+An assignment statement evaluates the expression list (remember that -+this can be a single expression or a comma-separated list, the latter -+yielding a tuple) and assigns the single resulting object to each of -+the target lists, from left to right. -+ -+Assignment is defined recursively depending on the form of the target -+(list). When a target is part of a mutable object (an attribute -+reference, subscription or slicing), the mutable object must -+ultimately perform the assignment and decide about its validity, and -+may raise an exception if the assignment is unacceptable. The rules -+observed by various types and the exceptions raised are given with the -+definition of the object types (see section The standard type -+hierarchy). -+ -+Assignment of an object to a target list, optionally enclosed in -+parentheses or square brackets, is recursively defined as follows. -+ -+* If the target list is a single target with no trailing comma, -+ optionally in parentheses, the object is assigned to that target. -+ -+* Else: -+ -+ * If the target list contains one target prefixed with an asterisk, -+ called a “starred†target: The object must be an iterable with at -+ least as many items as there are targets in the target list, minus -+ one. The first items of the iterable are assigned, from left to -+ right, to the targets before the starred target. The final items -+ of the iterable are assigned to the targets after the starred -+ target. A list of the remaining items in the iterable is then -+ assigned to the starred target (the list can be empty). -+ -+ * Else: The object must be an iterable with the same number of items -+ as there are targets in the target list, and the items are -+ assigned, from left to right, to the corresponding targets. -+ -+Assignment of an object to a single target is recursively defined as -+follows. -+ -+* If the target is an identifier (name): -+ -+ * If the name does not occur in a "global" or "nonlocal" statement -+ in the current code block: the name is bound to the object in the -+ current local namespace. -+ -+ * Otherwise: the name is bound to the object in the global namespace -+ or the outer namespace determined by "nonlocal", respectively. -+ -+ The name is rebound if it was already bound. This may cause the -+ reference count for the object previously bound to the name to reach -+ zero, causing the object to be deallocated and its destructor (if it -+ has one) to be called. -+ -+* If the target is an attribute reference: The primary expression in -+ the reference is evaluated. It should yield an object with -+ assignable attributes; if this is not the case, "TypeError" is -+ raised. That object is then asked to assign the assigned object to -+ the given attribute; if it cannot perform the assignment, it raises -+ an exception (usually but not necessarily "AttributeError"). -+ -+ Note: If the object is a class instance and the attribute reference -+ occurs on both sides of the assignment operator, the right-hand side -+ expression, "a.x" can access either an instance attribute or (if no -+ instance attribute exists) a class attribute. The left-hand side -+ target "a.x" is always set as an instance attribute, creating it if -+ necessary. Thus, the two occurrences of "a.x" do not necessarily -+ refer to the same attribute: if the right-hand side expression -+ refers to a class attribute, the left-hand side creates a new -+ instance attribute as the target of the assignment: -+ -+ class Cls: -+ x = 3 # class variable -+ inst = Cls() -+ inst.x = inst.x + 1 # writes inst.x as 4 leaving Cls.x as 3 -+ -+ This description does not necessarily apply to descriptor -+ attributes, such as properties created with "property()". -+ -+* If the target is a subscription: The primary expression in the -+ reference is evaluated. It should yield either a mutable sequence -+ object (such as a list) or a mapping object (such as a dictionary). -+ Next, the subscript expression is evaluated. -+ -+ If the primary is a mutable sequence object (such as a list), the -+ subscript must yield an integer. If it is negative, the sequence’s -+ length is added to it. The resulting value must be a nonnegative -+ integer less than the sequence’s length, and the sequence is asked -+ to assign the assigned object to its item with that index. If the -+ index is out of range, "IndexError" is raised (assignment to a -+ subscripted sequence cannot add new items to a list). -+ -+ If the primary is a mapping object (such as a dictionary), the -+ subscript must have a type compatible with the mapping’s key type, -+ and the mapping is then asked to create a key/value pair which maps -+ the subscript to the assigned object. This can either replace an -+ existing key/value pair with the same key value, or insert a new -+ key/value pair (if no key with the same value existed). -+ -+ For user-defined objects, the "__setitem__()" method is called with -+ appropriate arguments. -+ -+* If the target is a slicing: The primary expression in the reference -+ is evaluated. It should yield a mutable sequence object (such as a -+ list). The assigned object should be a sequence object of the same -+ type. Next, the lower and upper bound expressions are evaluated, -+ insofar they are present; defaults are zero and the sequence’s -+ length. The bounds should evaluate to integers. If either bound is -+ negative, the sequence’s length is added to it. The resulting -+ bounds are clipped to lie between zero and the sequence’s length, -+ inclusive. Finally, the sequence object is asked to replace the -+ slice with the items of the assigned sequence. The length of the -+ slice may be different from the length of the assigned sequence, -+ thus changing the length of the target sequence, if the target -+ sequence allows it. -+ -+**CPython implementation detail:** In the current implementation, the -+syntax for targets is taken to be the same as for expressions, and -+invalid syntax is rejected during the code generation phase, causing -+less detailed error messages. -+ -+Although the definition of assignment implies that overlaps between -+the left-hand side and the right-hand side are ‘simultaneous’ (for -+example "a, b = b, a" swaps two variables), overlaps *within* the -+collection of assigned-to variables occur left-to-right, sometimes -+resulting in confusion. For instance, the following program prints -+"[0, 2]": -+ -+ x = [0, 1] -+ i = 0 -+ i, x[i] = 1, 2 # i is updated, then x[i] is updated -+ print(x) -+ -+See also: -+ -+ **PEP 3132** - Extended Iterable Unpacking -+ The specification for the "*target" feature. -+ -+ -+Augmented assignment statements -+=============================== -+ -+Augmented assignment is the combination, in a single statement, of a -+binary operation and an assignment statement: -+ -+ **augmented_assignment_stmt**: "augtarget" "augop" ("expression_list" | "yield_expression") -+ **augtarget**: "identifier" | "attributeref" | "subscription" | "slicing" -+ **augop**: "+=" | "-=" | "*=" | "@=" | "/=" | "//=" | "%=" | "**=" -+ | ">>=" | "<<=" | "&=" | "^=" | "|=" -+ -+(See section Primaries for the syntax definitions of the last three -+symbols.) -+ -+An augmented assignment evaluates the target (which, unlike normal -+assignment statements, cannot be an unpacking) and the expression -+list, performs the binary operation specific to the type of assignment -+on the two operands, and assigns the result to the original target. -+The target is only evaluated once. -+ -+An augmented assignment statement like "x += 1" can be rewritten as "x -+= x + 1" to achieve a similar, but not exactly equal effect. In the -+augmented version, "x" is only evaluated once. Also, when possible, -+the actual operation is performed *in-place*, meaning that rather than -+creating a new object and assigning that to the target, the old object -+is modified instead. -+ -+Unlike normal assignments, augmented assignments evaluate the left- -+hand side *before* evaluating the right-hand side. For example, "a[i] -++= f(x)" first looks-up "a[i]", then it evaluates "f(x)" and performs -+the addition, and lastly, it writes the result back to "a[i]". -+ -+With the exception of assigning to tuples and multiple targets in a -+single statement, the assignment done by augmented assignment -+statements is handled the same way as normal assignments. Similarly, -+with the exception of the possible *in-place* behavior, the binary -+operation performed by augmented assignment is the same as the normal -+binary operations. -+ -+For targets which are attribute references, the same caveat about -+class and instance attributes applies as for regular assignments. -+ -+ -+Annotated assignment statements -+=============================== -+ -+*Annotation* assignment is the combination, in a single statement, of -+a variable or attribute annotation and an optional assignment -+statement: -+ -+ **annotated_assignment_stmt**: "augtarget" ":" "expression" -+ ["=" ("starred_expression" | "yield_expression")] -+ -+The difference from normal Assignment statements is that only a single -+target is allowed. -+ -+The assignment target is considered “simple†if it consists of a -+single name that is not enclosed in parentheses. For simple assignment -+targets, if in class or module scope, the annotations are gathered in -+a lazily evaluated annotation scope. The annotations can be evaluated -+using the "__annotations__" attribute of a class or module, or using -+the facilities in the "annotationlib" module. -+ -+If the assignment target is not simple (an attribute, subscript node, -+or parenthesized name), the annotation is never evaluated. -+ -+If a name is annotated in a function scope, then this name is local -+for that scope. Annotations are never evaluated and stored in function -+scopes. -+ -+If the right hand side is present, an annotated assignment performs -+the actual assignment as if there was no annotation present. If the -+right hand side is not present for an expression target, then the -+interpreter evaluates the target except for the last "__setitem__()" -+or "__setattr__()" call. -+ -+See also: -+ -+ **PEP 526** - Syntax for Variable Annotations -+ The proposal that added syntax for annotating the types of -+ variables (including class variables and instance variables), -+ instead of expressing them through comments. -+ -+ **PEP 484** - Type hints -+ The proposal that added the "typing" module to provide a standard -+ syntax for type annotations that can be used in static analysis -+ tools and IDEs. -+ -+Changed in version 3.8: Now annotated assignments allow the same -+expressions in the right hand side as regular assignments. Previously, -+some expressions (like un-parenthesized tuple expressions) caused a -+syntax error. -+ -+Changed in version 3.14: Annotations are now lazily evaluated in a -+separate annotation scope. If the assignment target is not simple, -+annotations are never evaluated. -+''', -+ 'assignment-expressions': r'''Assignment expressions -+********************** -+ -+ **assignment_expression**: ["identifier" ":="] "expression" -+ -+An assignment expression (sometimes also called a “named expression†-+or “walrusâ€) assigns an "expression" to an "identifier", while also -+returning the value of the "expression". -+ -+One common use case is when handling matched regular expressions: -+ -+ if matching := pattern.search(data): -+ do_something(matching) -+ -+Or, when processing a file stream in chunks: -+ -+ while chunk := file.read(9000): -+ process(chunk) -+ -+Assignment expressions must be surrounded by parentheses when used as -+expression statements and when used as sub-expressions in slicing, -+conditional, lambda, keyword-argument, and comprehension-if -+expressions and in "assert", "with", and "assignment" statements. In -+all other places where they can be used, parentheses are not required, -+including in "if" and "while" statements. -+ -+Added in version 3.8: See **PEP 572** for more details about -+assignment expressions. -+''', -+ 'async': r'''Coroutines -+********** -+ -+Added in version 3.5. -+ -+ -+Coroutine function definition -+============================= -+ -+ **async_funcdef**: ["decorators"] "async" "def" "funcname" "(" ["parameter_list"] ")" -+ ["->" "expression"] ":" "suite" -+ -+Execution of Python coroutines can be suspended and resumed at many -+points (see *coroutine*). "await" expressions, "async for" and "async -+with" can only be used in the body of a coroutine function. -+ -+Functions defined with "async def" syntax are always coroutine -+functions, even if they do not contain "await" or "async" keywords. -+ -+It is a "SyntaxError" to use a "yield from" expression inside the body -+of a coroutine function. -+ -+An example of a coroutine function: -+ -+ async def func(param1, param2): -+ do_stuff() -+ await some_coroutine() -+ -+Changed in version 3.7: "await" and "async" are now keywords; -+previously they were only treated as such inside the body of a -+coroutine function. -+ -+ -+The "async for" statement -+========================= -+ -+ **async_for_stmt**: "async" "for_stmt" -+ -+An *asynchronous iterable* provides an "__aiter__" method that -+directly returns an *asynchronous iterator*, which can call -+asynchronous code in its "__anext__" method. -+ -+The "async for" statement allows convenient iteration over -+asynchronous iterables. -+ -+The following code: -+ -+ async for TARGET in ITER: -+ SUITE -+ else: -+ SUITE2 -+ -+Is semantically equivalent to: -+ -+ iter = (ITER) -+ iter = type(iter).__aiter__(iter) -+ running = True -+ -+ while running: -+ try: -+ TARGET = await type(iter).__anext__(iter) -+ except StopAsyncIteration: -+ running = False -+ else: -+ SUITE -+ else: -+ SUITE2 -+ -+See also "__aiter__()" and "__anext__()" for details. -+ -+It is a "SyntaxError" to use an "async for" statement outside the body -+of a coroutine function. -+ -+ -+The "async with" statement -+========================== -+ -+ **async_with_stmt**: "async" "with_stmt" -+ -+An *asynchronous context manager* is a *context manager* that is able -+to suspend execution in its *enter* and *exit* methods. -+ -+The following code: -+ -+ async with EXPRESSION as TARGET: -+ SUITE -+ -+is semantically equivalent to: -+ -+ manager = (EXPRESSION) -+ aenter = type(manager).__aenter__ -+ aexit = type(manager).__aexit__ -+ value = await aenter(manager) -+ hit_except = False -+ -+ try: -+ TARGET = value -+ SUITE -+ except: -+ hit_except = True -+ if not await aexit(manager, *sys.exc_info()): -+ raise -+ finally: -+ if not hit_except: -+ await aexit(manager, None, None, None) -+ -+See also "__aenter__()" and "__aexit__()" for details. -+ -+It is a "SyntaxError" to use an "async with" statement outside the -+body of a coroutine function. -+ -+See also: -+ -+ **PEP 492** - Coroutines with async and await syntax -+ The proposal that made coroutines a proper standalone concept in -+ Python, and added supporting syntax. -+''', -+ 'atom-identifiers': r'''Identifiers (Names) -+******************* -+ -+An identifier occurring as an atom is a name. See section Identifiers -+and keywords for lexical definition and section Naming and binding for -+documentation of naming and binding. -+ -+When the name is bound to an object, evaluation of the atom yields -+that object. When a name is not bound, an attempt to evaluate it -+raises a "NameError" exception. -+ -+ -+Private name mangling -+===================== -+ -+When an identifier that textually occurs in a class definition begins -+with two or more underscore characters and does not end in two or more -+underscores, it is considered a *private name* of that class. -+ -+See also: The class specifications. -+ -+More precisely, private names are transformed to a longer form before -+code is generated for them. If the transformed name is longer than -+255 characters, implementation-defined truncation may happen. -+ -+The transformation is independent of the syntactical context in which -+the identifier is used but only the following private identifiers are -+mangled: -+ -+* Any name used as the name of a variable that is assigned or read or -+ any name of an attribute being accessed. -+ -+ The "__name__" attribute of nested functions, classes, and type -+ aliases is however not mangled. -+ -+* The name of imported modules, e.g., "__spam" in "import __spam". If -+ the module is part of a package (i.e., its name contains a dot), the -+ name is *not* mangled, e.g., the "__foo" in "import __foo.bar" is -+ not mangled. -+ -+* The name of an imported member, e.g., "__f" in "from spam import -+ __f". -+ -+The transformation rule is defined as follows: -+ -+* The class name, with leading underscores removed and a single -+ leading underscore inserted, is inserted in front of the identifier, -+ e.g., the identifier "__spam" occurring in a class named "Foo", -+ "_Foo" or "__Foo" is transformed to "_Foo__spam". -+ -+* If the class name consists only of underscores, the transformation -+ is the identity, e.g., the identifier "__spam" occurring in a class -+ named "_" or "__" is left as is. -+''', -+ 'atom-literals': r'''Literals -+******** -+ -+Python supports string and bytes literals and various numeric -+literals: -+ -+ **literal**: "stringliteral" | "bytesliteral" -+ | "integer" | "floatnumber" | "imagnumber" -+ -+Evaluation of a literal yields an object of the given type (string, -+bytes, integer, floating-point number, complex number) with the given -+value. The value may be approximated in the case of floating-point -+and imaginary (complex) literals. See section Literals for details. -+ -+All literals correspond to immutable data types, and hence the -+object’s identity is less important than its value. Multiple -+evaluations of literals with the same value (either the same -+occurrence in the program text or a different occurrence) may obtain -+the same object or a different object with the same value. -+''', -+ 'attribute-access': r'''Customizing attribute access -+**************************** -+ -+The following methods can be defined to customize the meaning of -+attribute access (use of, assignment to, or deletion of "x.name") for -+class instances. -+ -+object.__getattr__(self, name) -+ -+ Called when the default attribute access fails with an -+ "AttributeError" (either "__getattribute__()" raises an -+ "AttributeError" because *name* is not an instance attribute or an -+ attribute in the class tree for "self"; or "__get__()" of a *name* -+ property raises "AttributeError"). This method should either -+ return the (computed) attribute value or raise an "AttributeError" -+ exception. The "object" class itself does not provide this method. -+ -+ Note that if the attribute is found through the normal mechanism, -+ "__getattr__()" is not called. (This is an intentional asymmetry -+ between "__getattr__()" and "__setattr__()".) This is done both for -+ efficiency reasons and because otherwise "__getattr__()" would have -+ no way to access other attributes of the instance. Note that at -+ least for instance variables, you can take total control by not -+ inserting any values in the instance attribute dictionary (but -+ instead inserting them in another object). See the -+ "__getattribute__()" method below for a way to actually get total -+ control over attribute access. -+ -+object.__getattribute__(self, name) -+ -+ Called unconditionally to implement attribute accesses for -+ instances of the class. If the class also defines "__getattr__()", -+ the latter will not be called unless "__getattribute__()" either -+ calls it explicitly or raises an "AttributeError". This method -+ should return the (computed) attribute value or raise an -+ "AttributeError" exception. In order to avoid infinite recursion in -+ this method, its implementation should always call the base class -+ method with the same name to access any attributes it needs, for -+ example, "object.__getattribute__(self, name)". -+ -+ Note: -+ -+ This method may still be bypassed when looking up special methods -+ as the result of implicit invocation via language syntax or -+ built-in functions. See Special method lookup. -+ -+ For certain sensitive attribute accesses, raises an auditing event -+ "object.__getattr__" with arguments "obj" and "name". -+ -+object.__setattr__(self, name, value) -+ -+ Called when an attribute assignment is attempted. This is called -+ instead of the normal mechanism (i.e. store the value in the -+ instance dictionary). *name* is the attribute name, *value* is the -+ value to be assigned to it. -+ -+ If "__setattr__()" wants to assign to an instance attribute, it -+ should call the base class method with the same name, for example, -+ "object.__setattr__(self, name, value)". -+ -+ For certain sensitive attribute assignments, raises an auditing -+ event "object.__setattr__" with arguments "obj", "name", "value". -+ -+object.__delattr__(self, name) -+ -+ Like "__setattr__()" but for attribute deletion instead of -+ assignment. This should only be implemented if "del obj.name" is -+ meaningful for the object. -+ -+ For certain sensitive attribute deletions, raises an auditing event -+ "object.__delattr__" with arguments "obj" and "name". -+ -+object.__dir__(self) -+ -+ Called when "dir()" is called on the object. An iterable must be -+ returned. "dir()" converts the returned iterable to a list and -+ sorts it. -+ -+ -+Customizing module attribute access -+=================================== -+ -+Special names "__getattr__" and "__dir__" can be also used to -+customize access to module attributes. The "__getattr__" function at -+the module level should accept one argument which is the name of an -+attribute and return the computed value or raise an "AttributeError". -+If an attribute is not found on a module object through the normal -+lookup, i.e. "object.__getattribute__()", then "__getattr__" is -+searched in the module "__dict__" before raising an "AttributeError". -+If found, it is called with the attribute name and the result is -+returned. -+ -+The "__dir__" function should accept no arguments, and return an -+iterable of strings that represents the names accessible on module. If -+present, this function overrides the standard "dir()" search on a -+module. -+ -+For a more fine grained customization of the module behavior (setting -+attributes, properties, etc.), one can set the "__class__" attribute -+of a module object to a subclass of "types.ModuleType". For example: -+ -+ import sys -+ from types import ModuleType -+ -+ class VerboseModule(ModuleType): -+ def __repr__(self): -+ return f'Verbose {self.__name__}' -+ -+ def __setattr__(self, attr, value): -+ print(f'Setting {attr}...') -+ super().__setattr__(attr, value) -+ -+ sys.modules[__name__].__class__ = VerboseModule -+ -+Note: -+ -+ Defining module "__getattr__" and setting module "__class__" only -+ affect lookups made using the attribute access syntax – directly -+ accessing the module globals (whether by code within the module, or -+ via a reference to the module’s globals dictionary) is unaffected. -+ -+Changed in version 3.5: "__class__" module attribute is now writable. -+ -+Added in version 3.7: "__getattr__" and "__dir__" module attributes. -+ -+See also: -+ -+ **PEP 562** - Module __getattr__ and __dir__ -+ Describes the "__getattr__" and "__dir__" functions on modules. -+ -+ -+Implementing Descriptors -+======================== -+ -+The following methods only apply when an instance of the class -+containing the method (a so-called *descriptor* class) appears in an -+*owner* class (the descriptor must be in either the owner’s class -+dictionary or in the class dictionary for one of its parents). In the -+examples below, “the attribute†refers to the attribute whose name is -+the key of the property in the owner class’ "__dict__". The "object" -+class itself does not implement any of these protocols. -+ -+object.__get__(self, instance, owner=None) -+ -+ Called to get the attribute of the owner class (class attribute -+ access) or of an instance of that class (instance attribute -+ access). The optional *owner* argument is the owner class, while -+ *instance* is the instance that the attribute was accessed through, -+ or "None" when the attribute is accessed through the *owner*. -+ -+ This method should return the computed attribute value or raise an -+ "AttributeError" exception. -+ -+ **PEP 252** specifies that "__get__()" is callable with one or two -+ arguments. Python’s own built-in descriptors support this -+ specification; however, it is likely that some third-party tools -+ have descriptors that require both arguments. Python’s own -+ "__getattribute__()" implementation always passes in both arguments -+ whether they are required or not. -+ -+object.__set__(self, instance, value) -+ -+ Called to set the attribute on an instance *instance* of the owner -+ class to a new value, *value*. -+ -+ Note, adding "__set__()" or "__delete__()" changes the kind of -+ descriptor to a “data descriptorâ€. See Invoking Descriptors for -+ more details. -+ -+object.__delete__(self, instance) -+ -+ Called to delete the attribute on an instance *instance* of the -+ owner class. -+ -+Instances of descriptors may also have the "__objclass__" attribute -+present: -+ -+object.__objclass__ -+ -+ The attribute "__objclass__" is interpreted by the "inspect" module -+ as specifying the class where this object was defined (setting this -+ appropriately can assist in runtime introspection of dynamic class -+ attributes). For callables, it may indicate that an instance of the -+ given type (or a subclass) is expected or required as the first -+ positional argument (for example, CPython sets this attribute for -+ unbound methods that are implemented in C). -+ -+ -+Invoking Descriptors -+==================== -+ -+In general, a descriptor is an object attribute with “binding -+behaviorâ€, one whose attribute access has been overridden by methods -+in the descriptor protocol: "__get__()", "__set__()", and -+"__delete__()". If any of those methods are defined for an object, it -+is said to be a descriptor. -+ -+The default behavior for attribute access is to get, set, or delete -+the attribute from an object’s dictionary. For instance, "a.x" has a -+lookup chain starting with "a.__dict__['x']", then -+"type(a).__dict__['x']", and continuing through the base classes of -+"type(a)" excluding metaclasses. -+ -+However, if the looked-up value is an object defining one of the -+descriptor methods, then Python may override the default behavior and -+invoke the descriptor method instead. Where this occurs in the -+precedence chain depends on which descriptor methods were defined and -+how they were called. -+ -+The starting point for descriptor invocation is a binding, "a.x". How -+the arguments are assembled depends on "a": -+ -+Direct Call -+ The simplest and least common call is when user code directly -+ invokes a descriptor method: "x.__get__(a)". -+ -+Instance Binding -+ If binding to an object instance, "a.x" is transformed into the -+ call: "type(a).__dict__['x'].__get__(a, type(a))". -+ -+Class Binding -+ If binding to a class, "A.x" is transformed into the call: -+ "A.__dict__['x'].__get__(None, A)". -+ -+Super Binding -+ A dotted lookup such as "super(A, a).x" searches -+ "a.__class__.__mro__" for a base class "B" following "A" and then -+ returns "B.__dict__['x'].__get__(a, A)". If not a descriptor, "x" -+ is returned unchanged. -+ -+For instance bindings, the precedence of descriptor invocation depends -+on which descriptor methods are defined. A descriptor can define any -+combination of "__get__()", "__set__()" and "__delete__()". If it -+does not define "__get__()", then accessing the attribute will return -+the descriptor object itself unless there is a value in the object’s -+instance dictionary. If the descriptor defines "__set__()" and/or -+"__delete__()", it is a data descriptor; if it defines neither, it is -+a non-data descriptor. Normally, data descriptors define both -+"__get__()" and "__set__()", while non-data descriptors have just the -+"__get__()" method. Data descriptors with "__get__()" and "__set__()" -+(and/or "__delete__()") defined always override a redefinition in an -+instance dictionary. In contrast, non-data descriptors can be -+overridden by instances. -+ -+Python methods (including those decorated with "@staticmethod" and -+"@classmethod") are implemented as non-data descriptors. Accordingly, -+instances can redefine and override methods. This allows individual -+instances to acquire behaviors that differ from other instances of the -+same class. -+ -+The "property()" function is implemented as a data descriptor. -+Accordingly, instances cannot override the behavior of a property. -+ -+ -+__slots__ -+========= -+ -+*__slots__* allow us to explicitly declare data members (like -+properties) and deny the creation of "__dict__" and *__weakref__* -+(unless explicitly declared in *__slots__* or available in a parent.) -+ -+The space saved over using "__dict__" can be significant. Attribute -+lookup speed can be significantly improved as well. -+ -+object.__slots__ -+ -+ This class variable can be assigned a string, iterable, or sequence -+ of strings with variable names used by instances. *__slots__* -+ reserves space for the declared variables and prevents the -+ automatic creation of "__dict__" and *__weakref__* for each -+ instance. -+ -+Notes on using *__slots__*: -+ -+* When inheriting from a class without *__slots__*, the "__dict__" and -+ *__weakref__* attribute of the instances will always be accessible. -+ -+* Without a "__dict__" variable, instances cannot be assigned new -+ variables not listed in the *__slots__* definition. Attempts to -+ assign to an unlisted variable name raises "AttributeError". If -+ dynamic assignment of new variables is desired, then add -+ "'__dict__'" to the sequence of strings in the *__slots__* -+ declaration. -+ -+* Without a *__weakref__* variable for each instance, classes defining -+ *__slots__* do not support "weak references" to its instances. If -+ weak reference support is needed, then add "'__weakref__'" to the -+ sequence of strings in the *__slots__* declaration. -+ -+* *__slots__* are implemented at the class level by creating -+ descriptors for each variable name. As a result, class attributes -+ cannot be used to set default values for instance variables defined -+ by *__slots__*; otherwise, the class attribute would overwrite the -+ descriptor assignment. -+ -+* The action of a *__slots__* declaration is not limited to the class -+ where it is defined. *__slots__* declared in parents are available -+ in child classes. However, instances of a child subclass will get a -+ "__dict__" and *__weakref__* unless the subclass also defines -+ *__slots__* (which should only contain names of any *additional* -+ slots). -+ -+* If a class defines a slot also defined in a base class, the instance -+ variable defined by the base class slot is inaccessible (except by -+ retrieving its descriptor directly from the base class). This -+ renders the meaning of the program undefined. In the future, a -+ check may be added to prevent this. -+ -+* "TypeError" will be raised if nonempty *__slots__* are defined for a -+ class derived from a ""variable-length" built-in type" such as -+ "int", "bytes", and "tuple". -+ -+* Any non-string *iterable* may be assigned to *__slots__*. -+ -+* If a "dictionary" is used to assign *__slots__*, the dictionary keys -+ will be used as the slot names. The values of the dictionary can be -+ used to provide per-attribute docstrings that will be recognised by -+ "inspect.getdoc()" and displayed in the output of "help()". -+ -+* "__class__" assignment works only if both classes have the same -+ *__slots__*. -+ -+* Multiple inheritance with multiple slotted parent classes can be -+ used, but only one parent is allowed to have attributes created by -+ slots (the other bases must have empty slot layouts) - violations -+ raise "TypeError". -+ -+* If an *iterator* is used for *__slots__* then a *descriptor* is -+ created for each of the iterator’s values. However, the *__slots__* -+ attribute will be an empty iterator. -+''', -+ 'attribute-references': r'''Attribute references -+******************** -+ -+An attribute reference is a primary followed by a period and a name: -+ -+ **attributeref**: "primary" "." "identifier" -+ -+The primary must evaluate to an object of a type that supports -+attribute references, which most objects do. This object is then -+asked to produce the attribute whose name is the identifier. The type -+and value produced is determined by the object. Multiple evaluations -+of the same attribute reference may yield different objects. -+ -+This production can be customized by overriding the -+"__getattribute__()" method or the "__getattr__()" method. The -+"__getattribute__()" method is called first and either returns a value -+or raises "AttributeError" if the attribute is not available. -+ -+If an "AttributeError" is raised and the object has a "__getattr__()" -+method, that method is called as a fallback. -+''', -+ 'augassign': r'''Augmented assignment statements -+******************************* -+ -+Augmented assignment is the combination, in a single statement, of a -+binary operation and an assignment statement: -+ -+ **augmented_assignment_stmt**: "augtarget" "augop" ("expression_list" | "yield_expression") -+ **augtarget**: "identifier" | "attributeref" | "subscription" | "slicing" -+ **augop**: "+=" | "-=" | "*=" | "@=" | "/=" | "//=" | "%=" | "**=" -+ | ">>=" | "<<=" | "&=" | "^=" | "|=" -+ -+(See section Primaries for the syntax definitions of the last three -+symbols.) -+ -+An augmented assignment evaluates the target (which, unlike normal -+assignment statements, cannot be an unpacking) and the expression -+list, performs the binary operation specific to the type of assignment -+on the two operands, and assigns the result to the original target. -+The target is only evaluated once. -+ -+An augmented assignment statement like "x += 1" can be rewritten as "x -+= x + 1" to achieve a similar, but not exactly equal effect. In the -+augmented version, "x" is only evaluated once. Also, when possible, -+the actual operation is performed *in-place*, meaning that rather than -+creating a new object and assigning that to the target, the old object -+is modified instead. -+ -+Unlike normal assignments, augmented assignments evaluate the left- -+hand side *before* evaluating the right-hand side. For example, "a[i] -++= f(x)" first looks-up "a[i]", then it evaluates "f(x)" and performs -+the addition, and lastly, it writes the result back to "a[i]". -+ -+With the exception of assigning to tuples and multiple targets in a -+single statement, the assignment done by augmented assignment -+statements is handled the same way as normal assignments. Similarly, -+with the exception of the possible *in-place* behavior, the binary -+operation performed by augmented assignment is the same as the normal -+binary operations. -+ -+For targets which are attribute references, the same caveat about -+class and instance attributes applies as for regular assignments. -+''', -+ 'await': r'''Await expression -+**************** -+ -+Suspend the execution of *coroutine* on an *awaitable* object. Can -+only be used inside a *coroutine function*. -+ -+ **await_expr**: "await" "primary" -+ -+Added in version 3.5. -+''', -+ 'binary': r'''Binary arithmetic operations -+**************************** -+ -+The binary arithmetic operations have the conventional priority -+levels. Note that some of these operations also apply to certain non- -+numeric types. Apart from the power operator, there are only two -+levels, one for multiplicative operators and one for additive -+operators: -+ -+ **m_expr**: "u_expr" | "m_expr" "*" "u_expr" | "m_expr" "@" "m_expr" | -+ "m_expr" "//" "u_expr" | "m_expr" "/" "u_expr" | -+ "m_expr" "%" "u_expr" -+ **a_expr**: "m_expr" | "a_expr" "+" "m_expr" | "a_expr" "-" "m_expr" -+ -+The "*" (multiplication) operator yields the product of its arguments. -+The arguments must either both be numbers, or one argument must be an -+integer and the other must be a sequence. In the former case, the -+numbers are converted to a common real type and then multiplied -+together. In the latter case, sequence repetition is performed; a -+negative repetition factor yields an empty sequence. -+ -+This operation can be customized using the special "__mul__()" and -+"__rmul__()" methods. -+ -+Changed in version 3.14: If only one operand is a complex number, the -+other operand is converted to a floating-point number. -+ -+The "@" (at) operator is intended to be used for matrix -+multiplication. No builtin Python types implement this operator. -+ -+This operation can be customized using the special "__matmul__()" and -+"__rmatmul__()" methods. -+ -+Added in version 3.5. -+ -+The "/" (division) and "//" (floor division) operators yield the -+quotient of their arguments. The numeric arguments are first -+converted to a common type. Division of integers yields a float, while -+floor division of integers results in an integer; the result is that -+of mathematical division with the ‘floor’ function applied to the -+result. Division by zero raises the "ZeroDivisionError" exception. -+ -+The division operation can be customized using the special -+"__truediv__()" and "__rtruediv__()" methods. The floor division -+operation can be customized using the special "__floordiv__()" and -+"__rfloordiv__()" methods. -+ -+The "%" (modulo) operator yields the remainder from the division of -+the first argument by the second. The numeric arguments are first -+converted to a common type. A zero right argument raises the -+"ZeroDivisionError" exception. The arguments may be floating-point -+numbers, e.g., "3.14%0.7" equals "0.34" (since "3.14" equals "4*0.7 + -+0.34".) The modulo operator always yields a result with the same sign -+as its second operand (or zero); the absolute value of the result is -+strictly smaller than the absolute value of the second operand [1]. -+ -+The floor division and modulo operators are connected by the following -+identity: "x == (x//y)*y + (x%y)". Floor division and modulo are also -+connected with the built-in function "divmod()": "divmod(x, y) == -+(x//y, x%y)". [2]. -+ -+In addition to performing the modulo operation on numbers, the "%" -+operator is also overloaded by string objects to perform old-style -+string formatting (also known as interpolation). The syntax for -+string formatting is described in the Python Library Reference, -+section printf-style String Formatting. -+ -+The *modulo* operation can be customized using the special "__mod__()" -+and "__rmod__()" methods. -+ -+The floor division operator, the modulo operator, and the "divmod()" -+function are not defined for complex numbers. Instead, convert to a -+floating-point number using the "abs()" function if appropriate. -+ -+The "+" (addition) operator yields the sum of its arguments. The -+arguments must either both be numbers or both be sequences of the same -+type. In the former case, the numbers are converted to a common real -+type and then added together. In the latter case, the sequences are -+concatenated. -+ -+This operation can be customized using the special "__add__()" and -+"__radd__()" methods. -+ -+Changed in version 3.14: If only one operand is a complex number, the -+other operand is converted to a floating-point number. -+ -+The "-" (subtraction) operator yields the difference of its arguments. -+The numeric arguments are first converted to a common real type. -+ -+This operation can be customized using the special "__sub__()" and -+"__rsub__()" methods. -+ -+Changed in version 3.14: If only one operand is a complex number, the -+other operand is converted to a floating-point number. -+''', -+ 'bitwise': r'''Binary bitwise operations -+************************* -+ -+Each of the three bitwise operations has a different priority level: -+ -+ **and_expr**: "shift_expr" | "and_expr" "&" "shift_expr" -+ **xor_expr**: "and_expr" | "xor_expr" "^" "and_expr" -+ **or_expr**: "xor_expr" | "or_expr" "|" "xor_expr" -+ -+The "&" operator yields the bitwise AND of its arguments, which must -+be integers or one of them must be a custom object overriding -+"__and__()" or "__rand__()" special methods. -+ -+The "^" operator yields the bitwise XOR (exclusive OR) of its -+arguments, which must be integers or one of them must be a custom -+object overriding "__xor__()" or "__rxor__()" special methods. -+ -+The "|" operator yields the bitwise (inclusive) OR of its arguments, -+which must be integers or one of them must be a custom object -+overriding "__or__()" or "__ror__()" special methods. -+''', -+ 'bltin-code-objects': r'''Code Objects -+************ -+ -+Code objects are used by the implementation to represent “pseudo- -+compiled†executable Python code such as a function body. They differ -+from function objects because they don’t contain a reference to their -+global execution environment. Code objects are returned by the built- -+in "compile()" function and can be extracted from function objects -+through their "__code__" attribute. See also the "code" module. -+ -+Accessing "__code__" raises an auditing event "object.__getattr__" -+with arguments "obj" and ""__code__"". -+ -+A code object can be executed or evaluated by passing it (instead of a -+source string) to the "exec()" or "eval()" built-in functions. -+ -+See The standard type hierarchy for more information. -+''', -+ 'bltin-ellipsis-object': r'''The Ellipsis Object -+******************* -+ -+This object is commonly used by slicing (see Slicings). It supports -+no special operations. There is exactly one ellipsis object, named -+"Ellipsis" (a built-in name). "type(Ellipsis)()" produces the -+"Ellipsis" singleton. -+ -+It is written as "Ellipsis" or "...". -+''', -+ 'bltin-null-object': r'''The Null Object -+*************** -+ -+This object is returned by functions that don’t explicitly return a -+value. It supports no special operations. There is exactly one null -+object, named "None" (a built-in name). "type(None)()" produces the -+same singleton. -+ -+It is written as "None". -+''', -+ 'bltin-type-objects': r'''Type Objects -+************ -+ -+Type objects represent the various object types. An object’s type is -+accessed by the built-in function "type()". There are no special -+operations on types. The standard module "types" defines names for -+all standard built-in types. -+ -+Types are written like this: "". -+''', -+ 'booleans': r'''Boolean operations -+****************** -+ -+ **or_test**: "and_test" | "or_test" "or" "and_test" -+ **and_test**: "not_test" | "and_test" "and" "not_test" -+ **not_test**: "comparison" | "not" "not_test" -+ -+In the context of Boolean operations, and also when expressions are -+used by control flow statements, the following values are interpreted -+as false: "False", "None", numeric zero of all types, and empty -+strings and containers (including strings, tuples, lists, -+dictionaries, sets and frozensets). All other values are interpreted -+as true. User-defined objects can customize their truth value by -+providing a "__bool__()" method. -+ -+The operator "not" yields "True" if its argument is false, "False" -+otherwise. -+ -+The expression "x and y" first evaluates *x*; if *x* is false, its -+value is returned; otherwise, *y* is evaluated and the resulting value -+is returned. -+ -+The expression "x or y" first evaluates *x*; if *x* is true, its value -+is returned; otherwise, *y* is evaluated and the resulting value is -+returned. -+ -+Note that neither "and" nor "or" restrict the value and type they -+return to "False" and "True", but rather return the last evaluated -+argument. This is sometimes useful, e.g., if "s" is a string that -+should be replaced by a default value if it is empty, the expression -+"s or 'foo'" yields the desired value. Because "not" has to create a -+new value, it returns a boolean value regardless of the type of its -+argument (for example, "not 'foo'" produces "False" rather than "''".) -+''', -+ 'break': r'''The "break" statement -+********************* -+ -+ **break_stmt**: "break" -+ -+"break" may only occur syntactically nested in a "for" or "while" -+loop, but not nested in a function or class definition within that -+loop. -+ -+It terminates the nearest enclosing loop, skipping the optional "else" -+clause if the loop has one. -+ -+If a "for" loop is terminated by "break", the loop control target -+keeps its current value. -+ -+When "break" passes control out of a "try" statement with a "finally" -+clause, that "finally" clause is executed before really leaving the -+loop. -+''', -+ 'callable-types': r'''Emulating callable objects -+************************** -+ -+object.__call__(self[, args...]) -+ -+ Called when the instance is “called†as a function; if this method -+ is defined, "x(arg1, arg2, ...)" roughly translates to -+ "type(x).__call__(x, arg1, ...)". The "object" class itself does -+ not provide this method. -+''', -+ 'calls': r'''Calls -+***** -+ -+A call calls a callable object (e.g., a *function*) with a possibly -+empty series of *arguments*: -+ -+ **call**: "primary" "(" ["argument_list" [","] | "comprehension"] ")" -+ **argument_list**: "positional_arguments" ["," "starred_and_keywords"] -+ ["," "keywords_arguments"] -+ | "starred_and_keywords" ["," "keywords_arguments"] -+ | "keywords_arguments" -+ **positional_arguments**: positional_item ("," positional_item)* -+ **positional_item**: "assignment_expression" | "*" "expression" -+ **starred_and_keywords**: ("*" "expression" | "keyword_item") -+ ("," "*" "expression" | "," "keyword_item")* -+ **keywords_arguments**: ("keyword_item" | "**" "expression") -+ ("," "keyword_item" | "," "**" "expression")* -+ **keyword_item**: "identifier" "=" "expression" -+ -+An optional trailing comma may be present after the positional and -+keyword arguments but does not affect the semantics. -+ -+The primary must evaluate to a callable object (user-defined -+functions, built-in functions, methods of built-in objects, class -+objects, methods of class instances, and all objects having a -+"__call__()" method are callable). All argument expressions are -+evaluated before the call is attempted. Please refer to section -+Function definitions for the syntax of formal *parameter* lists. -+ -+If keyword arguments are present, they are first converted to -+positional arguments, as follows. First, a list of unfilled slots is -+created for the formal parameters. If there are N positional -+arguments, they are placed in the first N slots. Next, for each -+keyword argument, the identifier is used to determine the -+corresponding slot (if the identifier is the same as the first formal -+parameter name, the first slot is used, and so on). If the slot is -+already filled, a "TypeError" exception is raised. Otherwise, the -+argument is placed in the slot, filling it (even if the expression is -+"None", it fills the slot). When all arguments have been processed, -+the slots that are still unfilled are filled with the corresponding -+default value from the function definition. (Default values are -+calculated, once, when the function is defined; thus, a mutable object -+such as a list or dictionary used as default value will be shared by -+all calls that don’t specify an argument value for the corresponding -+slot; this should usually be avoided.) If there are any unfilled -+slots for which no default value is specified, a "TypeError" exception -+is raised. Otherwise, the list of filled slots is used as the -+argument list for the call. -+ -+**CPython implementation detail:** An implementation may provide -+built-in functions whose positional parameters do not have names, even -+if they are ‘named’ for the purpose of documentation, and which -+therefore cannot be supplied by keyword. In CPython, this is the case -+for functions implemented in C that use "PyArg_ParseTuple()" to parse -+their arguments. -+ -+If there are more positional arguments than there are formal parameter -+slots, a "TypeError" exception is raised, unless a formal parameter -+using the syntax "*identifier" is present; in this case, that formal -+parameter receives a tuple containing the excess positional arguments -+(or an empty tuple if there were no excess positional arguments). -+ -+If any keyword argument does not correspond to a formal parameter -+name, a "TypeError" exception is raised, unless a formal parameter -+using the syntax "**identifier" is present; in this case, that formal -+parameter receives a dictionary containing the excess keyword -+arguments (using the keywords as keys and the argument values as -+corresponding values), or a (new) empty dictionary if there were no -+excess keyword arguments. -+ -+If the syntax "*expression" appears in the function call, "expression" -+must evaluate to an *iterable*. Elements from these iterables are -+treated as if they were additional positional arguments. For the call -+"f(x1, x2, *y, x3, x4)", if *y* evaluates to a sequence *y1*, …, *yM*, -+this is equivalent to a call with M+4 positional arguments *x1*, *x2*, -+*y1*, …, *yM*, *x3*, *x4*. -+ -+A consequence of this is that although the "*expression" syntax may -+appear *after* explicit keyword arguments, it is processed *before* -+the keyword arguments (and any "**expression" arguments – see below). -+So: -+ -+ >>> def f(a, b): -+ ... print(a, b) -+ ... -+ >>> f(b=1, *(2,)) -+ 2 1 -+ >>> f(a=1, *(2,)) -+ Traceback (most recent call last): -+ File "", line 1, in -+ TypeError: f() got multiple values for keyword argument 'a' -+ >>> f(1, *(2,)) -+ 1 2 -+ -+It is unusual for both keyword arguments and the "*expression" syntax -+to be used in the same call, so in practice this confusion does not -+often arise. -+ -+If the syntax "**expression" appears in the function call, -+"expression" must evaluate to a *mapping*, the contents of which are -+treated as additional keyword arguments. If a parameter matching a key -+has already been given a value (by an explicit keyword argument, or -+from another unpacking), a "TypeError" exception is raised. -+ -+When "**expression" is used, each key in this mapping must be a -+string. Each value from the mapping is assigned to the first formal -+parameter eligible for keyword assignment whose name is equal to the -+key. A key need not be a Python identifier (e.g. ""max-temp °F"" is -+acceptable, although it will not match any formal parameter that could -+be declared). If there is no match to a formal parameter the key-value -+pair is collected by the "**" parameter, if there is one, or if there -+is not, a "TypeError" exception is raised. -+ -+Formal parameters using the syntax "*identifier" or "**identifier" -+cannot be used as positional argument slots or as keyword argument -+names. -+ -+Changed in version 3.5: Function calls accept any number of "*" and -+"**" unpackings, positional arguments may follow iterable unpackings -+("*"), and keyword arguments may follow dictionary unpackings ("**"). -+Originally proposed by **PEP 448**. -+ -+A call always returns some value, possibly "None", unless it raises an -+exception. How this value is computed depends on the type of the -+callable object. -+ -+If it is— -+ -+a user-defined function: -+ The code block for the function is executed, passing it the -+ argument list. The first thing the code block will do is bind the -+ formal parameters to the arguments; this is described in section -+ Function definitions. When the code block executes a "return" -+ statement, this specifies the return value of the function call. -+ If execution reaches the end of the code block without executing a -+ "return" statement, the return value is "None". -+ -+a built-in function or method: -+ The result is up to the interpreter; see Built-in Functions for the -+ descriptions of built-in functions and methods. -+ -+a class object: -+ A new instance of that class is returned. -+ -+a class instance method: -+ The corresponding user-defined function is called, with an argument -+ list that is one longer than the argument list of the call: the -+ instance becomes the first argument. -+ -+a class instance: -+ The class must define a "__call__()" method; the effect is then the -+ same as if that method was called. -+''', -+ 'class': r'''Class definitions -+***************** -+ -+A class definition defines a class object (see section The standard -+type hierarchy): -+ -+ **classdef**: ["decorators"] "class" "classname" ["type_params"] ["inheritance"] ":" "suite" -+ **inheritance**: "(" ["argument_list"] ")" -+ **classname**: "identifier" -+ -+A class definition is an executable statement. The inheritance list -+usually gives a list of base classes (see Metaclasses for more -+advanced uses), so each item in the list should evaluate to a class -+object which allows subclassing. Classes without an inheritance list -+inherit, by default, from the base class "object"; hence, -+ -+ class Foo: -+ pass -+ -+is equivalent to -+ -+ class Foo(object): -+ pass -+ -+The class’s suite is then executed in a new execution frame (see -+Naming and binding), using a newly created local namespace and the -+original global namespace. (Usually, the suite contains mostly -+function definitions.) When the class’s suite finishes execution, its -+execution frame is discarded but its local namespace is saved. [5] A -+class object is then created using the inheritance list for the base -+classes and the saved local namespace for the attribute dictionary. -+The class name is bound to this class object in the original local -+namespace. -+ -+The order in which attributes are defined in the class body is -+preserved in the new class’s "__dict__". Note that this is reliable -+only right after the class is created and only for classes that were -+defined using the definition syntax. -+ -+Class creation can be customized heavily using metaclasses. -+ -+Classes can also be decorated: just like when decorating functions, -+ -+ @f1(arg) -+ @f2 -+ class Foo: pass -+ -+is roughly equivalent to -+ -+ class Foo: pass -+ Foo = f1(arg)(f2(Foo)) -+ -+The evaluation rules for the decorator expressions are the same as for -+function decorators. The result is then bound to the class name. -+ -+Changed in version 3.9: Classes may be decorated with any valid -+"assignment_expression". Previously, the grammar was much more -+restrictive; see **PEP 614** for details. -+ -+A list of type parameters may be given in square brackets immediately -+after the class’s name. This indicates to static type checkers that -+the class is generic. At runtime, the type parameters can be retrieved -+from the class’s "__type_params__" attribute. See Generic classes for -+more. -+ -+Changed in version 3.12: Type parameter lists are new in Python 3.12. -+ -+**Programmer’s note:** Variables defined in the class definition are -+class attributes; they are shared by instances. Instance attributes -+can be set in a method with "self.name = value". Both class and -+instance attributes are accessible through the notation “"self.name"â€, -+and an instance attribute hides a class attribute with the same name -+when accessed in this way. Class attributes can be used as defaults -+for instance attributes, but using mutable values there can lead to -+unexpected results. Descriptors can be used to create instance -+variables with different implementation details. -+ -+See also: -+ -+ **PEP 3115** - Metaclasses in Python 3000 -+ The proposal that changed the declaration of metaclasses to the -+ current syntax, and the semantics for how classes with -+ metaclasses are constructed. -+ -+ **PEP 3129** - Class Decorators -+ The proposal that added class decorators. Function and method -+ decorators were introduced in **PEP 318**. -+''', -+ 'comparisons': r'''Comparisons -+*********** -+ -+Unlike C, all comparison operations in Python have the same priority, -+which is lower than that of any arithmetic, shifting or bitwise -+operation. Also unlike C, expressions like "a < b < c" have the -+interpretation that is conventional in mathematics: -+ -+ **comparison**: "or_expr" ("comp_operator" "or_expr")* -+ **comp_operator**: "<" | ">" | "==" | ">=" | "<=" | "!=" -+ | "is" ["not"] | ["not"] "in" -+ -+Comparisons yield boolean values: "True" or "False". Custom *rich -+comparison methods* may return non-boolean values. In this case Python -+will call "bool()" on such value in boolean contexts. -+ -+Comparisons can be chained arbitrarily, e.g., "x < y <= z" is -+equivalent to "x < y and y <= z", except that "y" is evaluated only -+once (but in both cases "z" is not evaluated at all when "x < y" is -+found to be false). -+ -+Formally, if *a*, *b*, *c*, …, *y*, *z* are expressions and *op1*, -+*op2*, …, *opN* are comparison operators, then "a op1 b op2 c ... y -+opN z" is equivalent to "a op1 b and b op2 c and ... y opN z", except -+that each expression is evaluated at most once. -+ -+Note that "a op1 b op2 c" doesn’t imply any kind of comparison between -+*a* and *c*, so that, e.g., "x < y > z" is perfectly legal (though -+perhaps not pretty). -+ -+ -+Value comparisons -+================= -+ -+The operators "<", ">", "==", ">=", "<=", and "!=" compare the values -+of two objects. The objects do not need to have the same type. -+ -+Chapter Objects, values and types states that objects have a value (in -+addition to type and identity). The value of an object is a rather -+abstract notion in Python: For example, there is no canonical access -+method for an object’s value. Also, there is no requirement that the -+value of an object should be constructed in a particular way, e.g. -+comprised of all its data attributes. Comparison operators implement a -+particular notion of what the value of an object is. One can think of -+them as defining the value of an object indirectly, by means of their -+comparison implementation. -+ -+Because all types are (direct or indirect) subtypes of "object", they -+inherit the default comparison behavior from "object". Types can -+customize their comparison behavior by implementing *rich comparison -+methods* like "__lt__()", described in Basic customization. -+ -+The default behavior for equality comparison ("==" and "!=") is based -+on the identity of the objects. Hence, equality comparison of -+instances with the same identity results in equality, and equality -+comparison of instances with different identities results in -+inequality. A motivation for this default behavior is the desire that -+all objects should be reflexive (i.e. "x is y" implies "x == y"). -+ -+A default order comparison ("<", ">", "<=", and ">=") is not provided; -+an attempt raises "TypeError". A motivation for this default behavior -+is the lack of a similar invariant as for equality. -+ -+The behavior of the default equality comparison, that instances with -+different identities are always unequal, may be in contrast to what -+types will need that have a sensible definition of object value and -+value-based equality. Such types will need to customize their -+comparison behavior, and in fact, a number of built-in types have done -+that. -+ -+The following list describes the comparison behavior of the most -+important built-in types. -+ -+* Numbers of built-in numeric types (Numeric Types — int, float, -+ complex) and of the standard library types "fractions.Fraction" and -+ "decimal.Decimal" can be compared within and across their types, -+ with the restriction that complex numbers do not support order -+ comparison. Within the limits of the types involved, they compare -+ mathematically (algorithmically) correct without loss of precision. -+ -+ The not-a-number values "float('NaN')" and "decimal.Decimal('NaN')" -+ are special. Any ordered comparison of a number to a not-a-number -+ value is false. A counter-intuitive implication is that not-a-number -+ values are not equal to themselves. For example, if "x = -+ float('NaN')", "3 < x", "x < 3" and "x == x" are all false, while "x -+ != x" is true. This behavior is compliant with IEEE 754. -+ -+* "None" and "NotImplemented" are singletons. **PEP 8** advises that -+ comparisons for singletons should always be done with "is" or "is -+ not", never the equality operators. -+ -+* Binary sequences (instances of "bytes" or "bytearray") can be -+ compared within and across their types. They compare -+ lexicographically using the numeric values of their elements. -+ -+* Strings (instances of "str") compare lexicographically using the -+ numerical Unicode code points (the result of the built-in function -+ "ord()") of their characters. [3] -+ -+ Strings and binary sequences cannot be directly compared. -+ -+* Sequences (instances of "tuple", "list", or "range") can be compared -+ only within each of their types, with the restriction that ranges do -+ not support order comparison. Equality comparison across these -+ types results in inequality, and ordering comparison across these -+ types raises "TypeError". -+ -+ Sequences compare lexicographically using comparison of -+ corresponding elements. The built-in containers typically assume -+ identical objects are equal to themselves. That lets them bypass -+ equality tests for identical objects to improve performance and to -+ maintain their internal invariants. -+ -+ Lexicographical comparison between built-in collections works as -+ follows: -+ -+ * For two collections to compare equal, they must be of the same -+ type, have the same length, and each pair of corresponding -+ elements must compare equal (for example, "[1,2] == (1,2)" is -+ false because the type is not the same). -+ -+ * Collections that support order comparison are ordered the same as -+ their first unequal elements (for example, "[1,2,x] <= [1,2,y]" -+ has the same value as "x <= y"). If a corresponding element does -+ not exist, the shorter collection is ordered first (for example, -+ "[1,2] < [1,2,3]" is true). -+ -+* Mappings (instances of "dict") compare equal if and only if they -+ have equal "(key, value)" pairs. Equality comparison of the keys and -+ values enforces reflexivity. -+ -+ Order comparisons ("<", ">", "<=", and ">=") raise "TypeError". -+ -+* Sets (instances of "set" or "frozenset") can be compared within and -+ across their types. -+ -+ They define order comparison operators to mean subset and superset -+ tests. Those relations do not define total orderings (for example, -+ the two sets "{1,2}" and "{2,3}" are not equal, nor subsets of one -+ another, nor supersets of one another). Accordingly, sets are not -+ appropriate arguments for functions which depend on total ordering -+ (for example, "min()", "max()", and "sorted()" produce undefined -+ results given a list of sets as inputs). -+ -+ Comparison of sets enforces reflexivity of its elements. -+ -+* Most other built-in types have no comparison methods implemented, so -+ they inherit the default comparison behavior. -+ -+User-defined classes that customize their comparison behavior should -+follow some consistency rules, if possible: -+ -+* Equality comparison should be reflexive. In other words, identical -+ objects should compare equal: -+ -+ "x is y" implies "x == y" -+ -+* Comparison should be symmetric. In other words, the following -+ expressions should have the same result: -+ -+ "x == y" and "y == x" -+ -+ "x != y" and "y != x" -+ -+ "x < y" and "y > x" -+ -+ "x <= y" and "y >= x" -+ -+* Comparison should be transitive. The following (non-exhaustive) -+ examples illustrate that: -+ -+ "x > y and y > z" implies "x > z" -+ -+ "x < y and y <= z" implies "x < z" -+ -+* Inverse comparison should result in the boolean negation. In other -+ words, the following expressions should have the same result: -+ -+ "x == y" and "not x != y" -+ -+ "x < y" and "not x >= y" (for total ordering) -+ -+ "x > y" and "not x <= y" (for total ordering) -+ -+ The last two expressions apply to totally ordered collections (e.g. -+ to sequences, but not to sets or mappings). See also the -+ "total_ordering()" decorator. -+ -+* The "hash()" result should be consistent with equality. Objects that -+ are equal should either have the same hash value, or be marked as -+ unhashable. -+ -+Python does not enforce these consistency rules. In fact, the -+not-a-number values are an example for not following these rules. -+ -+ -+Membership test operations -+========================== -+ -+The operators "in" and "not in" test for membership. "x in s" -+evaluates to "True" if *x* is a member of *s*, and "False" otherwise. -+"x not in s" returns the negation of "x in s". All built-in sequences -+and set types support this as well as dictionary, for which "in" tests -+whether the dictionary has a given key. For container types such as -+list, tuple, set, frozenset, dict, or collections.deque, the -+expression "x in y" is equivalent to "any(x is e or x == e for e in -+y)". -+ -+For the string and bytes types, "x in y" is "True" if and only if *x* -+is a substring of *y*. An equivalent test is "y.find(x) != -1". -+Empty strings are always considered to be a substring of any other -+string, so """ in "abc"" will return "True". -+ -+For user-defined classes which define the "__contains__()" method, "x -+in y" returns "True" if "y.__contains__(x)" returns a true value, and -+"False" otherwise. -+ -+For user-defined classes which do not define "__contains__()" but do -+define "__iter__()", "x in y" is "True" if some value "z", for which -+the expression "x is z or x == z" is true, is produced while iterating -+over "y". If an exception is raised during the iteration, it is as if -+"in" raised that exception. -+ -+Lastly, the old-style iteration protocol is tried: if a class defines -+"__getitem__()", "x in y" is "True" if and only if there is a non- -+negative integer index *i* such that "x is y[i] or x == y[i]", and no -+lower integer index raises the "IndexError" exception. (If any other -+exception is raised, it is as if "in" raised that exception). -+ -+The operator "not in" is defined to have the inverse truth value of -+"in". -+ -+ -+Identity comparisons -+==================== -+ -+The operators "is" and "is not" test for an object’s identity: "x is -+y" is true if and only if *x* and *y* are the same object. An -+Object’s identity is determined using the "id()" function. "x is not -+y" yields the inverse truth value. [4] -+''', -+ 'compound': r'''Compound statements -+******************* -+ -+Compound statements contain (groups of) other statements; they affect -+or control the execution of those other statements in some way. In -+general, compound statements span multiple lines, although in simple -+incarnations a whole compound statement may be contained in one line. -+ -+The "if", "while" and "for" statements implement traditional control -+flow constructs. "try" specifies exception handlers and/or cleanup -+code for a group of statements, while the "with" statement allows the -+execution of initialization and finalization code around a block of -+code. Function and class definitions are also syntactically compound -+statements. -+ -+A compound statement consists of one or more ‘clauses.’ A clause -+consists of a header and a ‘suite.’ The clause headers of a -+particular compound statement are all at the same indentation level. -+Each clause header begins with a uniquely identifying keyword and ends -+with a colon. A suite is a group of statements controlled by a -+clause. A suite can be one or more semicolon-separated simple -+statements on the same line as the header, following the header’s -+colon, or it can be one or more indented statements on subsequent -+lines. Only the latter form of a suite can contain nested compound -+statements; the following is illegal, mostly because it wouldn’t be -+clear to which "if" clause a following "else" clause would belong: -+ -+ if test1: if test2: print(x) -+ -+Also note that the semicolon binds tighter than the colon in this -+context, so that in the following example, either all or none of the -+"print()" calls are executed: -+ -+ if x < y < z: print(x); print(y); print(z) -+ -+Summarizing: -+ -+ **compound_stmt**: "if_stmt" -+ | "while_stmt" -+ | "for_stmt" -+ | "try_stmt" -+ | "with_stmt" -+ | "match_stmt" -+ | "funcdef" -+ | "classdef" -+ | "async_with_stmt" -+ | "async_for_stmt" -+ | "async_funcdef" -+ **suite**: "stmt_list" NEWLINE | NEWLINE INDENT "statement"+ DEDENT -+ **statement**: "stmt_list" NEWLINE | "compound_stmt" -+ **stmt_list**: "simple_stmt" (";" "simple_stmt")* [";"] -+ -+Note that statements always end in a "NEWLINE" possibly followed by a -+"DEDENT". Also note that optional continuation clauses always begin -+with a keyword that cannot start a statement, thus there are no -+ambiguities (the ‘dangling "else"’ problem is solved in Python by -+requiring nested "if" statements to be indented). -+ -+The formatting of the grammar rules in the following sections places -+each clause on a separate line for clarity. -+ -+ -+The "if" statement -+================== -+ -+The "if" statement is used for conditional execution: -+ -+ **if_stmt**: "if" "assignment_expression" ":" "suite" -+ ("elif" "assignment_expression" ":" "suite")* -+ ["else" ":" "suite"] -+ -+It selects exactly one of the suites by evaluating the expressions one -+by one until one is found to be true (see section Boolean operations -+for the definition of true and false); then that suite is executed -+(and no other part of the "if" statement is executed or evaluated). -+If all expressions are false, the suite of the "else" clause, if -+present, is executed. -+ -+ -+The "while" statement -+===================== -+ -+The "while" statement is used for repeated execution as long as an -+expression is true: -+ -+ **while_stmt**: "while" "assignment_expression" ":" "suite" -+ ["else" ":" "suite"] -+ -+This repeatedly tests the expression and, if it is true, executes the -+first suite; if the expression is false (which may be the first time -+it is tested) the suite of the "else" clause, if present, is executed -+and the loop terminates. -+ -+A "break" statement executed in the first suite terminates the loop -+without executing the "else" clause’s suite. A "continue" statement -+executed in the first suite skips the rest of the suite and goes back -+to testing the expression. -+ -+ -+The "for" statement -+=================== -+ -+The "for" statement is used to iterate over the elements of a sequence -+(such as a string, tuple or list) or other iterable object: -+ -+ **for_stmt**: "for" "target_list" "in" "starred_list" ":" "suite" -+ ["else" ":" "suite"] -+ -+The "starred_list" expression is evaluated once; it should yield an -+*iterable* object. An *iterator* is created for that iterable. The -+first item provided by the iterator is then assigned to the target -+list using the standard rules for assignments (see Assignment -+statements), and the suite is executed. This repeats for each item -+provided by the iterator. When the iterator is exhausted, the suite -+in the "else" clause, if present, is executed, and the loop -+terminates. -+ -+A "break" statement executed in the first suite terminates the loop -+without executing the "else" clause’s suite. A "continue" statement -+executed in the first suite skips the rest of the suite and continues -+with the next item, or with the "else" clause if there is no next -+item. -+ -+The for-loop makes assignments to the variables in the target list. -+This overwrites all previous assignments to those variables including -+those made in the suite of the for-loop: -+ -+ for i in range(10): -+ print(i) -+ i = 5 # this will not affect the for-loop -+ # because i will be overwritten with the next -+ # index in the range -+ -+Names in the target list are not deleted when the loop is finished, -+but if the sequence is empty, they will not have been assigned to at -+all by the loop. Hint: the built-in type "range()" represents -+immutable arithmetic sequences of integers. For instance, iterating -+"range(3)" successively yields 0, 1, and then 2. -+ -+Changed in version 3.11: Starred elements are now allowed in the -+expression list. -+ -+ -+The "try" statement -+=================== -+ -+The "try" statement specifies exception handlers and/or cleanup code -+for a group of statements: -+ -+ **try_stmt**: "try1_stmt" | "try2_stmt" | "try3_stmt" -+ **try1_stmt**: "try" ":" "suite" -+ ("except" ["expression" ["as" "identifier"]] ":" "suite")+ -+ ["else" ":" "suite"] -+ ["finally" ":" "suite"] -+ **try2_stmt**: "try" ":" "suite" -+ ("except" "*" "expression" ["as" "identifier"] ":" "suite")+ -+ ["else" ":" "suite"] -+ ["finally" ":" "suite"] -+ **try3_stmt**: "try" ":" "suite" -+ "finally" ":" "suite" -+ -+Additional information on exceptions can be found in section -+Exceptions, and information on using the "raise" statement to generate -+exceptions may be found in section The raise statement. -+ -+ -+"except" clause -+--------------- -+ -+The "except" clause(s) specify one or more exception handlers. When no -+exception occurs in the "try" clause, no exception handler is -+executed. When an exception occurs in the "try" suite, a search for an -+exception handler is started. This search inspects the "except" -+clauses in turn until one is found that matches the exception. An -+expression-less "except" clause, if present, must be last; it matches -+any exception. -+ -+For an "except" clause with an expression, the expression must -+evaluate to an exception type or a tuple of exception types. The -+raised exception matches an "except" clause whose expression evaluates -+to the class or a *non-virtual base class* of the exception object, or -+to a tuple that contains such a class. -+ -+If no "except" clause matches the exception, the search for an -+exception handler continues in the surrounding code and on the -+invocation stack. [1] -+ -+If the evaluation of an expression in the header of an "except" clause -+raises an exception, the original search for a handler is canceled and -+a search starts for the new exception in the surrounding code and on -+the call stack (it is treated as if the entire "try" statement raised -+the exception). -+ -+When a matching "except" clause is found, the exception is assigned to -+the target specified after the "as" keyword in that "except" clause, -+if present, and the "except" clause’s suite is executed. All "except" -+clauses must have an executable block. When the end of this block is -+reached, execution continues normally after the entire "try" -+statement. (This means that if two nested handlers exist for the same -+exception, and the exception occurs in the "try" clause of the inner -+handler, the outer handler will not handle the exception.) -+ -+When an exception has been assigned using "as target", it is cleared -+at the end of the "except" clause. This is as if -+ -+ except E as N: -+ foo -+ -+was translated to -+ -+ except E as N: -+ try: -+ foo -+ finally: -+ del N -+ -+This means the exception must be assigned to a different name to be -+able to refer to it after the "except" clause. Exceptions are cleared -+because with the traceback attached to them, they form a reference -+cycle with the stack frame, keeping all locals in that frame alive -+until the next garbage collection occurs. -+ -+Before an "except" clause’s suite is executed, the exception is stored -+in the "sys" module, where it can be accessed from within the body of -+the "except" clause by calling "sys.exception()". When leaving an -+exception handler, the exception stored in the "sys" module is reset -+to its previous value: -+ -+ >>> print(sys.exception()) -+ None -+ >>> try: -+ ... raise TypeError -+ ... except: -+ ... print(repr(sys.exception())) -+ ... try: -+ ... raise ValueError -+ ... except: -+ ... print(repr(sys.exception())) -+ ... print(repr(sys.exception())) -+ ... -+ TypeError() -+ ValueError() -+ TypeError() -+ >>> print(sys.exception()) -+ None -+ -+ -+"except*" clause -+---------------- -+ -+The "except*" clause(s) are used for handling "ExceptionGroup"s. The -+exception type for matching is interpreted as in the case of "except", -+but in the case of exception groups we can have partial matches when -+the type matches some of the exceptions in the group. This means that -+multiple "except*" clauses can execute, each handling part of the -+exception group. Each clause executes at most once and handles an -+exception group of all matching exceptions. Each exception in the -+group is handled by at most one "except*" clause, the first that -+matches it. -+ -+ >>> try: -+ ... raise ExceptionGroup("eg", -+ ... [ValueError(1), TypeError(2), OSError(3), OSError(4)]) -+ ... except* TypeError as e: -+ ... print(f'caught {type(e)} with nested {e.exceptions}') -+ ... except* OSError as e: -+ ... print(f'caught {type(e)} with nested {e.exceptions}') -+ ... -+ caught with nested (TypeError(2),) -+ caught with nested (OSError(3), OSError(4)) -+ + Exception Group Traceback (most recent call last): -+ | File "", line 2, in -+ | ExceptionGroup: eg -+ +-+---------------- 1 ---------------- -+ | ValueError: 1 -+ +------------------------------------ -+ -+Any remaining exceptions that were not handled by any "except*" clause -+are re-raised at the end, along with all exceptions that were raised -+from within the "except*" clauses. If this list contains more than one -+exception to reraise, they are combined into an exception group. -+ -+If the raised exception is not an exception group and its type matches -+one of the "except*" clauses, it is caught and wrapped by an exception -+group with an empty message string. -+ -+ >>> try: -+ ... raise BlockingIOError -+ ... except* BlockingIOError as e: -+ ... print(repr(e)) -+ ... -+ ExceptionGroup('', (BlockingIOError())) -+ -+An "except*" clause must have a matching expression; it cannot be -+"except*:". Furthermore, this expression cannot contain exception -+group types, because that would have ambiguous semantics. -+ -+It is not possible to mix "except" and "except*" in the same "try". -+"break", "continue" and "return" cannot appear in an "except*" clause. -+ -+ -+"else" clause -+------------- -+ -+The optional "else" clause is executed if the control flow leaves the -+"try" suite, no exception was raised, and no "return", "continue", or -+"break" statement was executed. Exceptions in the "else" clause are -+not handled by the preceding "except" clauses. -+ -+ -+"finally" clause -+---------------- -+ -+If "finally" is present, it specifies a ‘cleanup’ handler. The "try" -+clause is executed, including any "except" and "else" clauses. If an -+exception occurs in any of the clauses and is not handled, the -+exception is temporarily saved. The "finally" clause is executed. If -+there is a saved exception it is re-raised at the end of the "finally" -+clause. If the "finally" clause raises another exception, the saved -+exception is set as the context of the new exception. If the "finally" -+clause executes a "return", "break" or "continue" statement, the saved -+exception is discarded: -+ -+ >>> def f(): -+ ... try: -+ ... 1/0 -+ ... finally: -+ ... return 42 -+ ... -+ >>> f() -+ 42 -+ -+The exception information is not available to the program during -+execution of the "finally" clause. -+ -+When a "return", "break" or "continue" statement is executed in the -+"try" suite of a "try"…"finally" statement, the "finally" clause is -+also executed ‘on the way out.’ -+ -+The return value of a function is determined by the last "return" -+statement executed. Since the "finally" clause always executes, a -+"return" statement executed in the "finally" clause will always be the -+last one executed: -+ -+ >>> def foo(): -+ ... try: -+ ... return 'try' -+ ... finally: -+ ... return 'finally' -+ ... -+ >>> foo() -+ 'finally' -+ -+Changed in version 3.8: Prior to Python 3.8, a "continue" statement -+was illegal in the "finally" clause due to a problem with the -+implementation. -+ -+ -+The "with" statement -+==================== -+ -+The "with" statement is used to wrap the execution of a block with -+methods defined by a context manager (see section With Statement -+Context Managers). This allows common "try"…"except"…"finally" usage -+patterns to be encapsulated for convenient reuse. -+ -+ **with_stmt**: "with" ( "(" "with_stmt_contents" ","? ")" | "with_stmt_contents" ) ":" "suite" -+ **with_stmt_contents**: "with_item" ("," "with_item")* -+ **with_item**: "expression" ["as" "target"] -+ -+The execution of the "with" statement with one “item†proceeds as -+follows: -+ -+1. The context expression (the expression given in the "with_item") is -+ evaluated to obtain a context manager. -+ -+2. The context manager’s "__enter__()" is loaded for later use. -+ -+3. The context manager’s "__exit__()" is loaded for later use. -+ -+4. The context manager’s "__enter__()" method is invoked. -+ -+5. If a target was included in the "with" statement, the return value -+ from "__enter__()" is assigned to it. -+ -+ Note: -+ -+ The "with" statement guarantees that if the "__enter__()" method -+ returns without an error, then "__exit__()" will always be -+ called. Thus, if an error occurs during the assignment to the -+ target list, it will be treated the same as an error occurring -+ within the suite would be. See step 7 below. -+ -+6. The suite is executed. -+ -+7. The context manager’s "__exit__()" method is invoked. If an -+ exception caused the suite to be exited, its type, value, and -+ traceback are passed as arguments to "__exit__()". Otherwise, three -+ "None" arguments are supplied. -+ -+ If the suite was exited due to an exception, and the return value -+ from the "__exit__()" method was false, the exception is reraised. -+ If the return value was true, the exception is suppressed, and -+ execution continues with the statement following the "with" -+ statement. -+ -+ If the suite was exited for any reason other than an exception, the -+ return value from "__exit__()" is ignored, and execution proceeds -+ at the normal location for the kind of exit that was taken. -+ -+The following code: -+ -+ with EXPRESSION as TARGET: -+ SUITE -+ -+is semantically equivalent to: -+ -+ manager = (EXPRESSION) -+ enter = type(manager).__enter__ -+ exit = type(manager).__exit__ -+ value = enter(manager) -+ hit_except = False -+ -+ try: -+ TARGET = value -+ SUITE -+ except: -+ hit_except = True -+ if not exit(manager, *sys.exc_info()): -+ raise -+ finally: -+ if not hit_except: -+ exit(manager, None, None, None) -+ -+With more than one item, the context managers are processed as if -+multiple "with" statements were nested: -+ -+ with A() as a, B() as b: -+ SUITE -+ -+is semantically equivalent to: -+ -+ with A() as a: -+ with B() as b: -+ SUITE -+ -+You can also write multi-item context managers in multiple lines if -+the items are surrounded by parentheses. For example: -+ -+ with ( -+ A() as a, -+ B() as b, -+ ): -+ SUITE -+ -+Changed in version 3.1: Support for multiple context expressions. -+ -+Changed in version 3.10: Support for using grouping parentheses to -+break the statement in multiple lines. -+ -+See also: -+ -+ **PEP 343** - The “with†statement -+ The specification, background, and examples for the Python "with" -+ statement. -+ -+ -+The "match" statement -+===================== -+ -+Added in version 3.10. -+ -+The match statement is used for pattern matching. Syntax: -+ -+ **match_stmt**: 'match' "subject_expr" ":" NEWLINE INDENT "case_block"+ DEDENT -+ **subject_expr**: "star_named_expression" "," "star_named_expressions"? -+ | "named_expression" -+ **case_block**: 'case' "patterns" ["guard"] ":" "block" -+ -+Note: -+ -+ This section uses single quotes to denote soft keywords. -+ -+Pattern matching takes a pattern as input (following "case") and a -+subject value (following "match"). The pattern (which may contain -+subpatterns) is matched against the subject value. The outcomes are: -+ -+* A match success or failure (also termed a pattern success or -+ failure). -+ -+* Possible binding of matched values to a name. The prerequisites for -+ this are further discussed below. -+ -+The "match" and "case" keywords are soft keywords. -+ -+See also: -+ -+ * **PEP 634** – Structural Pattern Matching: Specification -+ -+ * **PEP 636** – Structural Pattern Matching: Tutorial -+ -+ -+Overview -+-------- -+ -+Here’s an overview of the logical flow of a match statement: -+ -+1. The subject expression "subject_expr" is evaluated and a resulting -+ subject value obtained. If the subject expression contains a comma, -+ a tuple is constructed using the standard rules. -+ -+2. Each pattern in a "case_block" is attempted to match with the -+ subject value. The specific rules for success or failure are -+ described below. The match attempt can also bind some or all of the -+ standalone names within the pattern. The precise pattern binding -+ rules vary per pattern type and are specified below. **Name -+ bindings made during a successful pattern match outlive the -+ executed block and can be used after the match statement**. -+ -+ Note: -+ -+ During failed pattern matches, some subpatterns may succeed. Do -+ not rely on bindings being made for a failed match. Conversely, -+ do not rely on variables remaining unchanged after a failed -+ match. The exact behavior is dependent on implementation and may -+ vary. This is an intentional decision made to allow different -+ implementations to add optimizations. -+ -+3. If the pattern succeeds, the corresponding guard (if present) is -+ evaluated. In this case all name bindings are guaranteed to have -+ happened. -+ -+ * If the guard evaluates as true or is missing, the "block" inside -+ "case_block" is executed. -+ -+ * Otherwise, the next "case_block" is attempted as described above. -+ -+ * If there are no further case blocks, the match statement is -+ completed. -+ -+Note: -+ -+ Users should generally never rely on a pattern being evaluated. -+ Depending on implementation, the interpreter may cache values or use -+ other optimizations which skip repeated evaluations. -+ -+A sample match statement: -+ -+ >>> flag = False -+ >>> match (100, 200): -+ ... case (100, 300): # Mismatch: 200 != 300 -+ ... print('Case 1') -+ ... case (100, 200) if flag: # Successful match, but guard fails -+ ... print('Case 2') -+ ... case (100, y): # Matches and binds y to 200 -+ ... print(f'Case 3, y: {y}') -+ ... case _: # Pattern not attempted -+ ... print('Case 4, I match anything!') -+ ... -+ Case 3, y: 200 -+ -+In this case, "if flag" is a guard. Read more about that in the next -+section. -+ -+ -+Guards -+------ -+ -+ **guard**: "if" "named_expression" -+ -+A "guard" (which is part of the "case") must succeed for code inside -+the "case" block to execute. It takes the form: "if" followed by an -+expression. -+ -+The logical flow of a "case" block with a "guard" follows: -+ -+1. Check that the pattern in the "case" block succeeded. If the -+ pattern failed, the "guard" is not evaluated and the next "case" -+ block is checked. -+ -+2. If the pattern succeeded, evaluate the "guard". -+ -+ * If the "guard" condition evaluates as true, the case block is -+ selected. -+ -+ * If the "guard" condition evaluates as false, the case block is -+ not selected. -+ -+ * If the "guard" raises an exception during evaluation, the -+ exception bubbles up. -+ -+Guards are allowed to have side effects as they are expressions. -+Guard evaluation must proceed from the first to the last case block, -+one at a time, skipping case blocks whose pattern(s) don’t all -+succeed. (I.e., guard evaluation must happen in order.) Guard -+evaluation must stop once a case block is selected. -+ -+ -+Irrefutable Case Blocks -+----------------------- -+ -+An irrefutable case block is a match-all case block. A match -+statement may have at most one irrefutable case block, and it must be -+last. -+ -+A case block is considered irrefutable if it has no guard and its -+pattern is irrefutable. A pattern is considered irrefutable if we can -+prove from its syntax alone that it will always succeed. Only the -+following patterns are irrefutable: -+ -+* AS Patterns whose left-hand side is irrefutable -+ -+* OR Patterns containing at least one irrefutable pattern -+ -+* Capture Patterns -+ -+* Wildcard Patterns -+ -+* parenthesized irrefutable patterns -+ -+ -+Patterns -+-------- -+ -+Note: -+ -+ This section uses grammar notations beyond standard EBNF: -+ -+ * the notation "SEP.RULE+" is shorthand for "RULE (SEP RULE)*" -+ -+ * the notation "!RULE" is shorthand for a negative lookahead -+ assertion -+ -+The top-level syntax for "patterns" is: -+ -+ **patterns**: "open_sequence_pattern" | "pattern" -+ **pattern**: "as_pattern" | "or_pattern" -+ **closed_pattern**: | "literal_pattern" -+ | "capture_pattern" -+ | "wildcard_pattern" -+ | "value_pattern" -+ | "group_pattern" -+ | "sequence_pattern" -+ | "mapping_pattern" -+ | "class_pattern" -+ -+The descriptions below will include a description “in simple terms†of -+what a pattern does for illustration purposes (credits to Raymond -+Hettinger for a document that inspired most of the descriptions). Note -+that these descriptions are purely for illustration purposes and **may -+not** reflect the underlying implementation. Furthermore, they do not -+cover all valid forms. -+ -+ -+OR Patterns -+~~~~~~~~~~~ -+ -+An OR pattern is two or more patterns separated by vertical bars "|". -+Syntax: -+ -+ **or_pattern**: "|"."closed_pattern"+ -+ -+Only the final subpattern may be irrefutable, and each subpattern must -+bind the same set of names to avoid ambiguity. -+ -+An OR pattern matches each of its subpatterns in turn to the subject -+value, until one succeeds. The OR pattern is then considered -+successful. Otherwise, if none of the subpatterns succeed, the OR -+pattern fails. -+ -+In simple terms, "P1 | P2 | ..." will try to match "P1", if it fails -+it will try to match "P2", succeeding immediately if any succeeds, -+failing otherwise. -+ -+ -+AS Patterns -+~~~~~~~~~~~ -+ -+An AS pattern matches an OR pattern on the left of the "as" keyword -+against a subject. Syntax: -+ -+ **as_pattern**: "or_pattern" "as" "capture_pattern" -+ -+If the OR pattern fails, the AS pattern fails. Otherwise, the AS -+pattern binds the subject to the name on the right of the as keyword -+and succeeds. "capture_pattern" cannot be a "_". -+ -+In simple terms "P as NAME" will match with "P", and on success it -+will set "NAME = ". -+ -+ -+Literal Patterns -+~~~~~~~~~~~~~~~~ -+ -+A literal pattern corresponds to most literals in Python. Syntax: -+ -+ **literal_pattern**: "signed_number" -+ | "signed_number" "+" NUMBER -+ | "signed_number" "-" NUMBER -+ | "strings" -+ | "None" -+ | "True" -+ | "False" -+ **signed_number**: ["-"] NUMBER -+ -+The rule "strings" and the token "NUMBER" are defined in the standard -+Python grammar. Triple-quoted strings are supported. Raw strings and -+byte strings are supported. f-strings are not supported. -+ -+The forms "signed_number '+' NUMBER" and "signed_number '-' NUMBER" -+are for expressing complex numbers; they require a real number on the -+left and an imaginary number on the right. E.g. "3 + 4j". -+ -+In simple terms, "LITERAL" will succeed only if " == -+LITERAL". For the singletons "None", "True" and "False", the "is" -+operator is used. -+ -+ -+Capture Patterns -+~~~~~~~~~~~~~~~~ -+ -+A capture pattern binds the subject value to a name. Syntax: -+ -+ **capture_pattern**: !'_' NAME -+ -+A single underscore "_" is not a capture pattern (this is what "!'_'" -+expresses). It is instead treated as a "wildcard_pattern". -+ -+In a given pattern, a given name can only be bound once. E.g. "case -+x, x: ..." is invalid while "case [x] | x: ..." is allowed. -+ -+Capture patterns always succeed. The binding follows scoping rules -+established by the assignment expression operator in **PEP 572**; the -+name becomes a local variable in the closest containing function scope -+unless there’s an applicable "global" or "nonlocal" statement. -+ -+In simple terms "NAME" will always succeed and it will set "NAME = -+". -+ -+ -+Wildcard Patterns -+~~~~~~~~~~~~~~~~~ -+ -+A wildcard pattern always succeeds (matches anything) and binds no -+name. Syntax: -+ -+ **wildcard_pattern**: '_' -+ -+"_" is a soft keyword within any pattern, but only within patterns. -+It is an identifier, as usual, even within "match" subject -+expressions, "guard"s, and "case" blocks. -+ -+In simple terms, "_" will always succeed. -+ -+ -+Value Patterns -+~~~~~~~~~~~~~~ -+ -+A value pattern represents a named value in Python. Syntax: -+ -+ **value_pattern**: "attr" -+ **attr**: "name_or_attr" "." NAME -+ **name_or_attr**: "attr" | NAME -+ -+The dotted name in the pattern is looked up using standard Python name -+resolution rules. The pattern succeeds if the value found compares -+equal to the subject value (using the "==" equality operator). -+ -+In simple terms "NAME1.NAME2" will succeed only if " == -+NAME1.NAME2" -+ -+Note: -+ -+ If the same value occurs multiple times in the same match statement, -+ the interpreter may cache the first value found and reuse it rather -+ than repeat the same lookup. This cache is strictly tied to a given -+ execution of a given match statement. -+ -+ -+Group Patterns -+~~~~~~~~~~~~~~ -+ -+A group pattern allows users to add parentheses around patterns to -+emphasize the intended grouping. Otherwise, it has no additional -+syntax. Syntax: -+ -+ **group_pattern**: "(" "pattern" ")" -+ -+In simple terms "(P)" has the same effect as "P". -+ -+ -+Sequence Patterns -+~~~~~~~~~~~~~~~~~ -+ -+A sequence pattern contains several subpatterns to be matched against -+sequence elements. The syntax is similar to the unpacking of a list or -+tuple. -+ -+ **sequence_pattern**: "[" ["maybe_sequence_pattern"] "]" -+ | "(" ["open_sequence_pattern"] ")" -+ **open_sequence_pattern**: "maybe_star_pattern" "," ["maybe_sequence_pattern"] -+ **maybe_sequence_pattern**: ","."maybe_star_pattern"+ ","? -+ **maybe_star_pattern**: "star_pattern" | "pattern" -+ **star_pattern**: "*" ("capture_pattern" | "wildcard_pattern") -+ -+There is no difference if parentheses or square brackets are used for -+sequence patterns (i.e. "(...)" vs "[...]" ). -+ -+Note: -+ -+ A single pattern enclosed in parentheses without a trailing comma -+ (e.g. "(3 | 4)") is a group pattern. While a single pattern enclosed -+ in square brackets (e.g. "[3 | 4]") is still a sequence pattern. -+ -+At most one star subpattern may be in a sequence pattern. The star -+subpattern may occur in any position. If no star subpattern is -+present, the sequence pattern is a fixed-length sequence pattern; -+otherwise it is a variable-length sequence pattern. -+ -+The following is the logical flow for matching a sequence pattern -+against a subject value: -+ -+1. If the subject value is not a sequence [2], the sequence pattern -+ fails. -+ -+2. If the subject value is an instance of "str", "bytes" or -+ "bytearray" the sequence pattern fails. -+ -+3. The subsequent steps depend on whether the sequence pattern is -+ fixed or variable-length. -+ -+ If the sequence pattern is fixed-length: -+ -+ 1. If the length of the subject sequence is not equal to the number -+ of subpatterns, the sequence pattern fails -+ -+ 2. Subpatterns in the sequence pattern are matched to their -+ corresponding items in the subject sequence from left to right. -+ Matching stops as soon as a subpattern fails. If all -+ subpatterns succeed in matching their corresponding item, the -+ sequence pattern succeeds. -+ -+ Otherwise, if the sequence pattern is variable-length: -+ -+ 1. If the length of the subject sequence is less than the number of -+ non-star subpatterns, the sequence pattern fails. -+ -+ 2. The leading non-star subpatterns are matched to their -+ corresponding items as for fixed-length sequences. -+ -+ 3. If the previous step succeeds, the star subpattern matches a -+ list formed of the remaining subject items, excluding the -+ remaining items corresponding to non-star subpatterns following -+ the star subpattern. -+ -+ 4. Remaining non-star subpatterns are matched to their -+ corresponding subject items, as for a fixed-length sequence. -+ -+ Note: -+ -+ The length of the subject sequence is obtained via "len()" (i.e. -+ via the "__len__()" protocol). This length may be cached by the -+ interpreter in a similar manner as value patterns. -+ -+In simple terms "[P1, P2, P3," … ", P]" matches only if all the -+following happens: -+ -+* check "" is a sequence -+ -+* "len(subject) == " -+ -+* "P1" matches "[0]" (note that this match can also bind -+ names) -+ -+* "P2" matches "[1]" (note that this match can also bind -+ names) -+ -+* … and so on for the corresponding pattern/element. -+ -+ -+Mapping Patterns -+~~~~~~~~~~~~~~~~ -+ -+A mapping pattern contains one or more key-value patterns. The syntax -+is similar to the construction of a dictionary. Syntax: -+ -+ **mapping_pattern**: "{" ["items_pattern"] "}" -+ **items_pattern**: ","."key_value_pattern"+ ","? -+ **key_value_pattern**: ("literal_pattern" | "value_pattern") ":" "pattern" -+ | "double_star_pattern" -+ **double_star_pattern**: "**" "capture_pattern" -+ -+At most one double star pattern may be in a mapping pattern. The -+double star pattern must be the last subpattern in the mapping -+pattern. -+ -+Duplicate keys in mapping patterns are disallowed. Duplicate literal -+keys will raise a "SyntaxError". Two keys that otherwise have the same -+value will raise a "ValueError" at runtime. -+ -+The following is the logical flow for matching a mapping pattern -+against a subject value: -+ -+1. If the subject value is not a mapping [3],the mapping pattern -+ fails. -+ -+2. If every key given in the mapping pattern is present in the subject -+ mapping, and the pattern for each key matches the corresponding -+ item of the subject mapping, the mapping pattern succeeds. -+ -+3. If duplicate keys are detected in the mapping pattern, the pattern -+ is considered invalid. A "SyntaxError" is raised for duplicate -+ literal values; or a "ValueError" for named keys of the same value. -+ -+Note: -+ -+ Key-value pairs are matched using the two-argument form of the -+ mapping subject’s "get()" method. Matched key-value pairs must -+ already be present in the mapping, and not created on-the-fly via -+ "__missing__()" or "__getitem__()". -+ -+In simple terms "{KEY1: P1, KEY2: P2, ... }" matches only if all the -+following happens: -+ -+* check "" is a mapping -+ -+* "KEY1 in " -+ -+* "P1" matches "[KEY1]" -+ -+* … and so on for the corresponding KEY/pattern pair. -+ -+ -+Class Patterns -+~~~~~~~~~~~~~~ -+ -+A class pattern represents a class and its positional and keyword -+arguments (if any). Syntax: -+ -+ **class_pattern**: "name_or_attr" "(" ["pattern_arguments" ","?] ")" -+ **pattern_arguments**: "positional_patterns" ["," "keyword_patterns"] -+ | "keyword_patterns" -+ **positional_patterns**: ","."pattern"+ -+ **keyword_patterns**: ","."keyword_pattern"+ -+ **keyword_pattern**: NAME "=" "pattern" -+ -+The same keyword should not be repeated in class patterns. -+ -+The following is the logical flow for matching a class pattern against -+a subject value: -+ -+1. If "name_or_attr" is not an instance of the builtin "type" , raise -+ "TypeError". -+ -+2. If the subject value is not an instance of "name_or_attr" (tested -+ via "isinstance()"), the class pattern fails. -+ -+3. If no pattern arguments are present, the pattern succeeds. -+ Otherwise, the subsequent steps depend on whether keyword or -+ positional argument patterns are present. -+ -+ For a number of built-in types (specified below), a single -+ positional subpattern is accepted which will match the entire -+ subject; for these types keyword patterns also work as for other -+ types. -+ -+ If only keyword patterns are present, they are processed as -+ follows, one by one: -+ -+ I. The keyword is looked up as an attribute on the subject. -+ -+ * If this raises an exception other than "AttributeError", the -+ exception bubbles up. -+ -+ * If this raises "AttributeError", the class pattern has failed. -+ -+ * Else, the subpattern associated with the keyword pattern is -+ matched against the subject’s attribute value. If this fails, -+ the class pattern fails; if this succeeds, the match proceeds -+ to the next keyword. -+ -+ II. If all keyword patterns succeed, the class pattern succeeds. -+ -+ If any positional patterns are present, they are converted to -+ keyword patterns using the "__match_args__" attribute on the class -+ "name_or_attr" before matching: -+ -+ I. The equivalent of "getattr(cls, "__match_args__", ())" is -+ called. -+ -+ * If this raises an exception, the exception bubbles up. -+ -+ * If the returned value is not a tuple, the conversion fails and -+ "TypeError" is raised. -+ -+ * If there are more positional patterns than -+ "len(cls.__match_args__)", "TypeError" is raised. -+ -+ * Otherwise, positional pattern "i" is converted to a keyword -+ pattern using "__match_args__[i]" as the keyword. -+ "__match_args__[i]" must be a string; if not "TypeError" is -+ raised. -+ -+ * If there are duplicate keywords, "TypeError" is raised. -+ -+ See also: -+ -+ Customizing positional arguments in class pattern matching -+ -+ II. Once all positional patterns have been converted to keyword -+ patterns, -+ the match proceeds as if there were only keyword patterns. -+ -+ For the following built-in types the handling of positional -+ subpatterns is different: -+ -+ * "bool" -+ -+ * "bytearray" -+ -+ * "bytes" -+ -+ * "dict" -+ -+ * "float" -+ -+ * "frozenset" -+ -+ * "int" -+ -+ * "list" -+ -+ * "set" -+ -+ * "str" -+ -+ * "tuple" -+ -+ These classes accept a single positional argument, and the pattern -+ there is matched against the whole object rather than an attribute. -+ For example "int(0|1)" matches the value "0", but not the value -+ "0.0". -+ -+In simple terms "CLS(P1, attr=P2)" matches only if the following -+happens: -+ -+* "isinstance(, CLS)" -+ -+* convert "P1" to a keyword pattern using "CLS.__match_args__" -+ -+* For each keyword argument "attr=P2": -+ -+ * "hasattr(, "attr")" -+ -+ * "P2" matches ".attr" -+ -+* … and so on for the corresponding keyword argument/pattern pair. -+ -+See also: -+ -+ * **PEP 634** – Structural Pattern Matching: Specification -+ -+ * **PEP 636** – Structural Pattern Matching: Tutorial -+ -+ -+Function definitions -+==================== -+ -+A function definition defines a user-defined function object (see -+section The standard type hierarchy): -+ -+ **funcdef**: ["decorators"] "def" "funcname" ["type_params"] "(" ["parameter_list"] ")" -+ ["->" "expression"] ":" "suite" -+ **decorators**: "decorator"+ -+ **decorator**: "@" "assignment_expression" NEWLINE -+ **parameter_list**: "defparameter" ("," "defparameter")* "," "/" ["," ["parameter_list_no_posonly"]] -+ | "parameter_list_no_posonly" -+ **parameter_list_no_posonly**: "defparameter" ("," "defparameter")* ["," ["parameter_list_starargs"]] -+ | "parameter_list_starargs" -+ **parameter_list_starargs**: "*" ["star_parameter"] ("," "defparameter")* ["," ["parameter_star_kwargs"]] -+ "*" ("," "defparameter")+ ["," ["parameter_star_kwargs"]] -+ | "parameter_star_kwargs" -+ **parameter_star_kwargs**: "**" "parameter" [","] -+ **parameter**: "identifier" [":" "expression"] -+ **star_parameter**: "identifier" [":" ["*"] "expression"] -+ **defparameter**: "parameter" ["=" "expression"] -+ **funcname**: "identifier" -+ -+A function definition is an executable statement. Its execution binds -+the function name in the current local namespace to a function object -+(a wrapper around the executable code for the function). This -+function object contains a reference to the current global namespace -+as the global namespace to be used when the function is called. -+ -+The function definition does not execute the function body; this gets -+executed only when the function is called. [4] -+ -+A function definition may be wrapped by one or more *decorator* -+expressions. Decorator expressions are evaluated when the function is -+defined, in the scope that contains the function definition. The -+result must be a callable, which is invoked with the function object -+as the only argument. The returned value is bound to the function name -+instead of the function object. Multiple decorators are applied in -+nested fashion. For example, the following code -+ -+ @f1(arg) -+ @f2 -+ def func(): pass -+ -+is roughly equivalent to -+ -+ def func(): pass -+ func = f1(arg)(f2(func)) -+ -+except that the original function is not temporarily bound to the name -+"func". -+ -+Changed in version 3.9: Functions may be decorated with any valid -+"assignment_expression". Previously, the grammar was much more -+restrictive; see **PEP 614** for details. -+ -+A list of type parameters may be given in square brackets between the -+function’s name and the opening parenthesis for its parameter list. -+This indicates to static type checkers that the function is generic. -+At runtime, the type parameters can be retrieved from the function’s -+"__type_params__" attribute. See Generic functions for more. -+ -+Changed in version 3.12: Type parameter lists are new in Python 3.12. -+ -+When one or more *parameters* have the form *parameter* "=" -+*expression*, the function is said to have “default parameter values.†-+For a parameter with a default value, the corresponding *argument* may -+be omitted from a call, in which case the parameter’s default value is -+substituted. If a parameter has a default value, all following -+parameters up until the “"*"†must also have a default value — this is -+a syntactic restriction that is not expressed by the grammar. -+ -+**Default parameter values are evaluated from left to right when the -+function definition is executed.** This means that the expression is -+evaluated once, when the function is defined, and that the same “pre- -+computed†value is used for each call. This is especially important -+to understand when a default parameter value is a mutable object, such -+as a list or a dictionary: if the function modifies the object (e.g. -+by appending an item to a list), the default parameter value is in -+effect modified. This is generally not what was intended. A way -+around this is to use "None" as the default, and explicitly test for -+it in the body of the function, e.g.: -+ -+ def whats_on_the_telly(penguin=None): -+ if penguin is None: -+ penguin = [] -+ penguin.append("property of the zoo") -+ return penguin -+ -+Function call semantics are described in more detail in section Calls. -+A function call always assigns values to all parameters mentioned in -+the parameter list, either from positional arguments, from keyword -+arguments, or from default values. If the form “"*identifier"†is -+present, it is initialized to a tuple receiving any excess positional -+parameters, defaulting to the empty tuple. If the form -+“"**identifier"†is present, it is initialized to a new ordered -+mapping receiving any excess keyword arguments, defaulting to a new -+empty mapping of the same type. Parameters after “"*"†or -+“"*identifier"†are keyword-only parameters and may only be passed by -+keyword arguments. Parameters before “"/"†are positional-only -+parameters and may only be passed by positional arguments. -+ -+Changed in version 3.8: The "/" function parameter syntax may be used -+to indicate positional-only parameters. See **PEP 570** for details. -+ -+Parameters may have an *annotation* of the form “": expression"†-+following the parameter name. Any parameter may have an annotation, -+even those of the form "*identifier" or "**identifier". (As a special -+case, parameters of the form "*identifier" may have an annotation “": -+*expression"â€.) Functions may have “return†annotation of the form -+“"-> expression"†after the parameter list. These annotations can be -+any valid Python expression. The presence of annotations does not -+change the semantics of a function. See Annotations for more -+information on annotations. -+ -+Changed in version 3.11: Parameters of the form “"*identifier"†may -+have an annotation “": *expression"â€. See **PEP 646**. -+ -+It is also possible to create anonymous functions (functions not bound -+to a name), for immediate use in expressions. This uses lambda -+expressions, described in section Lambdas. Note that the lambda -+expression is merely a shorthand for a simplified function definition; -+a function defined in a “"def"†statement can be passed around or -+assigned to another name just like a function defined by a lambda -+expression. The “"def"†form is actually more powerful since it -+allows the execution of multiple statements and annotations. -+ -+**Programmer’s note:** Functions are first-class objects. A “"def"†-+statement executed inside a function definition defines a local -+function that can be returned or passed around. Free variables used -+in the nested function can access the local variables of the function -+containing the def. See section Naming and binding for details. -+ -+See also: -+ -+ **PEP 3107** - Function Annotations -+ The original specification for function annotations. -+ -+ **PEP 484** - Type Hints -+ Definition of a standard meaning for annotations: type hints. -+ -+ **PEP 526** - Syntax for Variable Annotations -+ Ability to type hint variable declarations, including class -+ variables and instance variables. -+ -+ **PEP 563** - Postponed Evaluation of Annotations -+ Support for forward references within annotations by preserving -+ annotations in a string form at runtime instead of eager -+ evaluation. -+ -+ **PEP 318** - Decorators for Functions and Methods -+ Function and method decorators were introduced. Class decorators -+ were introduced in **PEP 3129**. -+ -+ -+Class definitions -+================= -+ -+A class definition defines a class object (see section The standard -+type hierarchy): -+ -+ **classdef**: ["decorators"] "class" "classname" ["type_params"] ["inheritance"] ":" "suite" -+ **inheritance**: "(" ["argument_list"] ")" -+ **classname**: "identifier" -+ -+A class definition is an executable statement. The inheritance list -+usually gives a list of base classes (see Metaclasses for more -+advanced uses), so each item in the list should evaluate to a class -+object which allows subclassing. Classes without an inheritance list -+inherit, by default, from the base class "object"; hence, -+ -+ class Foo: -+ pass -+ -+is equivalent to -+ -+ class Foo(object): -+ pass -+ -+The class’s suite is then executed in a new execution frame (see -+Naming and binding), using a newly created local namespace and the -+original global namespace. (Usually, the suite contains mostly -+function definitions.) When the class’s suite finishes execution, its -+execution frame is discarded but its local namespace is saved. [5] A -+class object is then created using the inheritance list for the base -+classes and the saved local namespace for the attribute dictionary. -+The class name is bound to this class object in the original local -+namespace. -+ -+The order in which attributes are defined in the class body is -+preserved in the new class’s "__dict__". Note that this is reliable -+only right after the class is created and only for classes that were -+defined using the definition syntax. -+ -+Class creation can be customized heavily using metaclasses. -+ -+Classes can also be decorated: just like when decorating functions, -+ -+ @f1(arg) -+ @f2 -+ class Foo: pass -+ -+is roughly equivalent to -+ -+ class Foo: pass -+ Foo = f1(arg)(f2(Foo)) -+ -+The evaluation rules for the decorator expressions are the same as for -+function decorators. The result is then bound to the class name. -+ -+Changed in version 3.9: Classes may be decorated with any valid -+"assignment_expression". Previously, the grammar was much more -+restrictive; see **PEP 614** for details. -+ -+A list of type parameters may be given in square brackets immediately -+after the class’s name. This indicates to static type checkers that -+the class is generic. At runtime, the type parameters can be retrieved -+from the class’s "__type_params__" attribute. See Generic classes for -+more. -+ -+Changed in version 3.12: Type parameter lists are new in Python 3.12. -+ -+**Programmer’s note:** Variables defined in the class definition are -+class attributes; they are shared by instances. Instance attributes -+can be set in a method with "self.name = value". Both class and -+instance attributes are accessible through the notation “"self.name"â€, -+and an instance attribute hides a class attribute with the same name -+when accessed in this way. Class attributes can be used as defaults -+for instance attributes, but using mutable values there can lead to -+unexpected results. Descriptors can be used to create instance -+variables with different implementation details. -+ -+See also: -+ -+ **PEP 3115** - Metaclasses in Python 3000 -+ The proposal that changed the declaration of metaclasses to the -+ current syntax, and the semantics for how classes with -+ metaclasses are constructed. -+ -+ **PEP 3129** - Class Decorators -+ The proposal that added class decorators. Function and method -+ decorators were introduced in **PEP 318**. -+ -+ -+Coroutines -+========== -+ -+Added in version 3.5. -+ -+ -+Coroutine function definition -+----------------------------- -+ -+ **async_funcdef**: ["decorators"] "async" "def" "funcname" "(" ["parameter_list"] ")" -+ ["->" "expression"] ":" "suite" -+ -+Execution of Python coroutines can be suspended and resumed at many -+points (see *coroutine*). "await" expressions, "async for" and "async -+with" can only be used in the body of a coroutine function. -+ -+Functions defined with "async def" syntax are always coroutine -+functions, even if they do not contain "await" or "async" keywords. -+ -+It is a "SyntaxError" to use a "yield from" expression inside the body -+of a coroutine function. -+ -+An example of a coroutine function: -+ -+ async def func(param1, param2): -+ do_stuff() -+ await some_coroutine() -+ -+Changed in version 3.7: "await" and "async" are now keywords; -+previously they were only treated as such inside the body of a -+coroutine function. -+ -+ -+The "async for" statement -+------------------------- -+ -+ **async_for_stmt**: "async" "for_stmt" -+ -+An *asynchronous iterable* provides an "__aiter__" method that -+directly returns an *asynchronous iterator*, which can call -+asynchronous code in its "__anext__" method. -+ -+The "async for" statement allows convenient iteration over -+asynchronous iterables. -+ -+The following code: -+ -+ async for TARGET in ITER: -+ SUITE -+ else: -+ SUITE2 -+ -+Is semantically equivalent to: -+ -+ iter = (ITER) -+ iter = type(iter).__aiter__(iter) -+ running = True -+ -+ while running: -+ try: -+ TARGET = await type(iter).__anext__(iter) -+ except StopAsyncIteration: -+ running = False -+ else: -+ SUITE -+ else: -+ SUITE2 -+ -+See also "__aiter__()" and "__anext__()" for details. -+ -+It is a "SyntaxError" to use an "async for" statement outside the body -+of a coroutine function. -+ -+ -+The "async with" statement -+-------------------------- -+ -+ **async_with_stmt**: "async" "with_stmt" -+ -+An *asynchronous context manager* is a *context manager* that is able -+to suspend execution in its *enter* and *exit* methods. -+ -+The following code: -+ -+ async with EXPRESSION as TARGET: -+ SUITE -+ -+is semantically equivalent to: -+ -+ manager = (EXPRESSION) -+ aenter = type(manager).__aenter__ -+ aexit = type(manager).__aexit__ -+ value = await aenter(manager) -+ hit_except = False -+ -+ try: -+ TARGET = value -+ SUITE -+ except: -+ hit_except = True -+ if not await aexit(manager, *sys.exc_info()): -+ raise -+ finally: -+ if not hit_except: -+ await aexit(manager, None, None, None) -+ -+See also "__aenter__()" and "__aexit__()" for details. -+ -+It is a "SyntaxError" to use an "async with" statement outside the -+body of a coroutine function. -+ -+See also: -+ -+ **PEP 492** - Coroutines with async and await syntax -+ The proposal that made coroutines a proper standalone concept in -+ Python, and added supporting syntax. -+ -+ -+Type parameter lists -+==================== -+ -+Added in version 3.12. -+ -+Changed in version 3.13: Support for default values was added (see -+**PEP 696**). -+ -+ **type_params**: "[" "type_param" ("," "type_param")* "]" -+ **type_param**: "typevar" | "typevartuple" | "paramspec" -+ **typevar**: "identifier" (":" "expression")? ("=" "expression")? -+ **typevartuple**: "*" "identifier" ("=" "expression")? -+ **paramspec**: "**" "identifier" ("=" "expression")? -+ -+Functions (including coroutines), classes and type aliases may contain -+a type parameter list: -+ -+ def max[T](args: list[T]) -> T: -+ ... -+ -+ async def amax[T](args: list[T]) -> T: -+ ... -+ -+ class Bag[T]: -+ def __iter__(self) -> Iterator[T]: -+ ... -+ -+ def add(self, arg: T) -> None: -+ ... -+ -+ type ListOrSet[T] = list[T] | set[T] -+ -+Semantically, this indicates that the function, class, or type alias -+is generic over a type variable. This information is primarily used by -+static type checkers, and at runtime, generic objects behave much like -+their non-generic counterparts. -+ -+Type parameters are declared in square brackets ("[]") immediately -+after the name of the function, class, or type alias. The type -+parameters are accessible within the scope of the generic object, but -+not elsewhere. Thus, after a declaration "def func[T](): pass", the -+name "T" is not available in the module scope. Below, the semantics of -+generic objects are described with more precision. The scope of type -+parameters is modeled with a special function (technically, an -+annotation scope) that wraps the creation of the generic object. -+ -+Generic functions, classes, and type aliases have a "__type_params__" -+attribute listing their type parameters. -+ -+Type parameters come in three kinds: -+ -+* "typing.TypeVar", introduced by a plain name (e.g., "T"). -+ Semantically, this represents a single type to a type checker. -+ -+* "typing.TypeVarTuple", introduced by a name prefixed with a single -+ asterisk (e.g., "*Ts"). Semantically, this stands for a tuple of any -+ number of types. -+ -+* "typing.ParamSpec", introduced by a name prefixed with two asterisks -+ (e.g., "**P"). Semantically, this stands for the parameters of a -+ callable. -+ -+"typing.TypeVar" declarations can define *bounds* and *constraints* -+with a colon (":") followed by an expression. A single expression -+after the colon indicates a bound (e.g. "T: int"). Semantically, this -+means that the "typing.TypeVar" can only represent types that are a -+subtype of this bound. A parenthesized tuple of expressions after the -+colon indicates a set of constraints (e.g. "T: (str, bytes)"). Each -+member of the tuple should be a type (again, this is not enforced at -+runtime). Constrained type variables can only take on one of the types -+in the list of constraints. -+ -+For "typing.TypeVar"s declared using the type parameter list syntax, -+the bound and constraints are not evaluated when the generic object is -+created, but only when the value is explicitly accessed through the -+attributes "__bound__" and "__constraints__". To accomplish this, the -+bounds or constraints are evaluated in a separate annotation scope. -+ -+"typing.TypeVarTuple"s and "typing.ParamSpec"s cannot have bounds or -+constraints. -+ -+All three flavors of type parameters can also have a *default value*, -+which is used when the type parameter is not explicitly provided. This -+is added by appending a single equals sign ("=") followed by an -+expression. Like the bounds and constraints of type variables, the -+default value is not evaluated when the object is created, but only -+when the type parameter’s "__default__" attribute is accessed. To this -+end, the default value is evaluated in a separate annotation scope. If -+no default value is specified for a type parameter, the "__default__" -+attribute is set to the special sentinel object "typing.NoDefault". -+ -+The following example indicates the full set of allowed type parameter -+declarations: -+ -+ def overly_generic[ -+ SimpleTypeVar, -+ TypeVarWithDefault = int, -+ TypeVarWithBound: int, -+ TypeVarWithConstraints: (str, bytes), -+ *SimpleTypeVarTuple = (int, float), -+ **SimpleParamSpec = (str, bytearray), -+ ]( -+ a: SimpleTypeVar, -+ b: TypeVarWithDefault, -+ c: TypeVarWithBound, -+ d: Callable[SimpleParamSpec, TypeVarWithConstraints], -+ *e: SimpleTypeVarTuple, -+ ): ... -+ -+ -+Generic functions -+----------------- -+ -+Generic functions are declared as follows: -+ -+ def func[T](arg: T): ... -+ -+This syntax is equivalent to: -+ -+ annotation-def TYPE_PARAMS_OF_func(): -+ T = typing.TypeVar("T") -+ def func(arg: T): ... -+ func.__type_params__ = (T,) -+ return func -+ func = TYPE_PARAMS_OF_func() -+ -+Here "annotation-def" indicates an annotation scope, which is not -+actually bound to any name at runtime. (One other liberty is taken in -+the translation: the syntax does not go through attribute access on -+the "typing" module, but creates an instance of "typing.TypeVar" -+directly.) -+ -+The annotations of generic functions are evaluated within the -+annotation scope used for declaring the type parameters, but the -+function’s defaults and decorators are not. -+ -+The following example illustrates the scoping rules for these cases, -+as well as for additional flavors of type parameters: -+ -+ @decorator -+ def func[T: int, *Ts, **P](*args: *Ts, arg: Callable[P, T] = some_default): -+ ... -+ -+Except for the lazy evaluation of the "TypeVar" bound, this is -+equivalent to: -+ -+ DEFAULT_OF_arg = some_default -+ -+ annotation-def TYPE_PARAMS_OF_func(): -+ -+ annotation-def BOUND_OF_T(): -+ return int -+ # In reality, BOUND_OF_T() is evaluated only on demand. -+ T = typing.TypeVar("T", bound=BOUND_OF_T()) -+ -+ Ts = typing.TypeVarTuple("Ts") -+ P = typing.ParamSpec("P") -+ -+ def func(*args: *Ts, arg: Callable[P, T] = DEFAULT_OF_arg): -+ ... -+ -+ func.__type_params__ = (T, Ts, P) -+ return func -+ func = decorator(TYPE_PARAMS_OF_func()) -+ -+The capitalized names like "DEFAULT_OF_arg" are not actually bound at -+runtime. -+ -+ -+Generic classes -+--------------- -+ -+Generic classes are declared as follows: -+ -+ class Bag[T]: ... -+ -+This syntax is equivalent to: -+ -+ annotation-def TYPE_PARAMS_OF_Bag(): -+ T = typing.TypeVar("T") -+ class Bag(typing.Generic[T]): -+ __type_params__ = (T,) -+ ... -+ return Bag -+ Bag = TYPE_PARAMS_OF_Bag() -+ -+Here again "annotation-def" (not a real keyword) indicates an -+annotation scope, and the name "TYPE_PARAMS_OF_Bag" is not actually -+bound at runtime. -+ -+Generic classes implicitly inherit from "typing.Generic". The base -+classes and keyword arguments of generic classes are evaluated within -+the type scope for the type parameters, and decorators are evaluated -+outside that scope. This is illustrated by this example: -+ -+ @decorator -+ class Bag(Base[T], arg=T): ... -+ -+This is equivalent to: -+ -+ annotation-def TYPE_PARAMS_OF_Bag(): -+ T = typing.TypeVar("T") -+ class Bag(Base[T], typing.Generic[T], arg=T): -+ __type_params__ = (T,) -+ ... -+ return Bag -+ Bag = decorator(TYPE_PARAMS_OF_Bag()) -+ -+ -+Generic type aliases -+-------------------- -+ -+The "type" statement can also be used to create a generic type alias: -+ -+ type ListOrSet[T] = list[T] | set[T] -+ -+Except for the lazy evaluation of the value, this is equivalent to: -+ -+ annotation-def TYPE_PARAMS_OF_ListOrSet(): -+ T = typing.TypeVar("T") -+ -+ annotation-def VALUE_OF_ListOrSet(): -+ return list[T] | set[T] -+ # In reality, the value is lazily evaluated -+ return typing.TypeAliasType("ListOrSet", VALUE_OF_ListOrSet(), type_params=(T,)) -+ ListOrSet = TYPE_PARAMS_OF_ListOrSet() -+ -+Here, "annotation-def" (not a real keyword) indicates an annotation -+scope. The capitalized names like "TYPE_PARAMS_OF_ListOrSet" are not -+actually bound at runtime. -+ -+ -+Annotations -+=========== -+ -+Changed in version 3.14: Annotations are now lazily evaluated by -+default. -+ -+Variables and function parameters may carry *annotations*, created by -+adding a colon after the name, followed by an expression: -+ -+ x: annotation = 1 -+ def f(param: annotation): ... -+ -+Functions may also carry a return annotation following an arrow: -+ -+ def f() -> annotation: ... -+ -+Annotations are conventionally used for *type hints*, but this is not -+enforced by the language, and in general annotations may contain -+arbitrary expressions. The presence of annotations does not change the -+runtime semantics of the code, except if some mechanism is used that -+introspects and uses the annotations (such as "dataclasses" or -+"functools.singledispatch()"). -+ -+By default, annotations are lazily evaluated in a annotation scope. -+This means that they are not evaluated when the code containing the -+annotation is evaluated. Instead, the interpreter saves information -+that can be used to evaluate the annotation later if requested. The -+"annotationlib" module provides tools for evaluating annotations. -+ -+If the future statement "from __future__ import annotations" is -+present, all annotations are instead stored as strings: -+ -+ >>> from __future__ import annotations -+ >>> def f(param: annotation): ... -+ >>> f.__annotations__ -+ {'param': 'annotation'} -+ -+-[ Footnotes ]- -+ -+[1] The exception is propagated to the invocation stack unless there -+ is a "finally" clause which happens to raise another exception. -+ That new exception causes the old one to be lost. -+ -+[2] In pattern matching, a sequence is defined as one of the -+ following: -+ -+ * a class that inherits from "collections.abc.Sequence" -+ -+ * a Python class that has been registered as -+ "collections.abc.Sequence" -+ -+ * a builtin class that has its (CPython) "Py_TPFLAGS_SEQUENCE" bit -+ set -+ -+ * a class that inherits from any of the above -+ -+ The following standard library classes are sequences: -+ -+ * "array.array" -+ -+ * "collections.deque" -+ -+ * "list" -+ -+ * "memoryview" -+ -+ * "range" -+ -+ * "tuple" -+ -+ Note: -+ -+ Subject values of type "str", "bytes", and "bytearray" do not -+ match sequence patterns. -+ -+[3] In pattern matching, a mapping is defined as one of the following: -+ -+ * a class that inherits from "collections.abc.Mapping" -+ -+ * a Python class that has been registered as -+ "collections.abc.Mapping" -+ -+ * a builtin class that has its (CPython) "Py_TPFLAGS_MAPPING" bit -+ set -+ -+ * a class that inherits from any of the above -+ -+ The standard library classes "dict" and "types.MappingProxyType" -+ are mappings. -+ -+[4] A string literal appearing as the first statement in the function -+ body is transformed into the function’s "__doc__" attribute and -+ therefore the function’s *docstring*. -+ -+[5] A string literal appearing as the first statement in the class -+ body is transformed into the namespace’s "__doc__" item and -+ therefore the class’s *docstring*. -+''', -+ 'context-managers': r'''With Statement Context Managers -+******************************* -+ -+A *context manager* is an object that defines the runtime context to -+be established when executing a "with" statement. The context manager -+handles the entry into, and the exit from, the desired runtime context -+for the execution of the block of code. Context managers are normally -+invoked using the "with" statement (described in section The with -+statement), but can also be used by directly invoking their methods. -+ -+Typical uses of context managers include saving and restoring various -+kinds of global state, locking and unlocking resources, closing opened -+files, etc. -+ -+For more information on context managers, see Context Manager Types. -+The "object" class itself does not provide the context manager -+methods. -+ -+object.__enter__(self) -+ -+ Enter the runtime context related to this object. The "with" -+ statement will bind this method’s return value to the target(s) -+ specified in the "as" clause of the statement, if any. -+ -+object.__exit__(self, exc_type, exc_value, traceback) -+ -+ Exit the runtime context related to this object. The parameters -+ describe the exception that caused the context to be exited. If the -+ context was exited without an exception, all three arguments will -+ be "None". -+ -+ If an exception is supplied, and the method wishes to suppress the -+ exception (i.e., prevent it from being propagated), it should -+ return a true value. Otherwise, the exception will be processed -+ normally upon exit from this method. -+ -+ Note that "__exit__()" methods should not reraise the passed-in -+ exception; this is the caller’s responsibility. -+ -+See also: -+ -+ **PEP 343** - The “with†statement -+ The specification, background, and examples for the Python "with" -+ statement. -+''', -+ 'continue': r'''The "continue" statement -+************************ -+ -+ **continue_stmt**: "continue" -+ -+"continue" may only occur syntactically nested in a "for" or "while" -+loop, but not nested in a function or class definition within that -+loop. It continues with the next cycle of the nearest enclosing loop. -+ -+When "continue" passes control out of a "try" statement with a -+"finally" clause, that "finally" clause is executed before really -+starting the next loop cycle. -+''', -+ 'conversions': r'''Arithmetic conversions -+********************** -+ -+When a description of an arithmetic operator below uses the phrase -+“the numeric arguments are converted to a common real typeâ€, this -+means that the operator implementation for built-in types works as -+follows: -+ -+* If both arguments are complex numbers, no conversion is performed; -+ -+* if either argument is a complex or a floating-point number, the -+ other is converted to a floating-point number; -+ -+* otherwise, both must be integers and no conversion is necessary. -+ -+Some additional rules apply for certain operators (e.g., a string as a -+left argument to the ‘%’ operator). Extensions must define their own -+conversion behavior. -+''', -+ 'customization': r'''Basic customization -+******************* -+ -+object.__new__(cls[, ...]) -+ -+ Called to create a new instance of class *cls*. "__new__()" is a -+ static method (special-cased so you need not declare it as such) -+ that takes the class of which an instance was requested as its -+ first argument. The remaining arguments are those passed to the -+ object constructor expression (the call to the class). The return -+ value of "__new__()" should be the new object instance (usually an -+ instance of *cls*). -+ -+ Typical implementations create a new instance of the class by -+ invoking the superclass’s "__new__()" method using -+ "super().__new__(cls[, ...])" with appropriate arguments and then -+ modifying the newly created instance as necessary before returning -+ it. -+ -+ If "__new__()" is invoked during object construction and it returns -+ an instance of *cls*, then the new instance’s "__init__()" method -+ will be invoked like "__init__(self[, ...])", where *self* is the -+ new instance and the remaining arguments are the same as were -+ passed to the object constructor. -+ -+ If "__new__()" does not return an instance of *cls*, then the new -+ instance’s "__init__()" method will not be invoked. -+ -+ "__new__()" is intended mainly to allow subclasses of immutable -+ types (like int, str, or tuple) to customize instance creation. It -+ is also commonly overridden in custom metaclasses in order to -+ customize class creation. -+ -+object.__init__(self[, ...]) -+ -+ Called after the instance has been created (by "__new__()"), but -+ before it is returned to the caller. The arguments are those -+ passed to the class constructor expression. If a base class has an -+ "__init__()" method, the derived class’s "__init__()" method, if -+ any, must explicitly call it to ensure proper initialization of the -+ base class part of the instance; for example: -+ "super().__init__([args...])". -+ -+ Because "__new__()" and "__init__()" work together in constructing -+ objects ("__new__()" to create it, and "__init__()" to customize -+ it), no non-"None" value may be returned by "__init__()"; doing so -+ will cause a "TypeError" to be raised at runtime. -+ -+object.__del__(self) -+ -+ Called when the instance is about to be destroyed. This is also -+ called a finalizer or (improperly) a destructor. If a base class -+ has a "__del__()" method, the derived class’s "__del__()" method, -+ if any, must explicitly call it to ensure proper deletion of the -+ base class part of the instance. -+ -+ It is possible (though not recommended!) for the "__del__()" method -+ to postpone destruction of the instance by creating a new reference -+ to it. This is called object *resurrection*. It is -+ implementation-dependent whether "__del__()" is called a second -+ time when a resurrected object is about to be destroyed; the -+ current *CPython* implementation only calls it once. -+ -+ It is not guaranteed that "__del__()" methods are called for -+ objects that still exist when the interpreter exits. -+ "weakref.finalize" provides a straightforward way to register a -+ cleanup function to be called when an object is garbage collected. -+ -+ Note: -+ -+ "del x" doesn’t directly call "x.__del__()" — the former -+ decrements the reference count for "x" by one, and the latter is -+ only called when "x"’s reference count reaches zero. -+ -+ **CPython implementation detail:** It is possible for a reference -+ cycle to prevent the reference count of an object from going to -+ zero. In this case, the cycle will be later detected and deleted -+ by the *cyclic garbage collector*. A common cause of reference -+ cycles is when an exception has been caught in a local variable. -+ The frame’s locals then reference the exception, which references -+ its own traceback, which references the locals of all frames caught -+ in the traceback. -+ -+ See also: Documentation for the "gc" module. -+ -+ Warning: -+ -+ Due to the precarious circumstances under which "__del__()" -+ methods are invoked, exceptions that occur during their execution -+ are ignored, and a warning is printed to "sys.stderr" instead. -+ In particular: -+ -+ * "__del__()" can be invoked when arbitrary code is being -+ executed, including from any arbitrary thread. If "__del__()" -+ needs to take a lock or invoke any other blocking resource, it -+ may deadlock as the resource may already be taken by the code -+ that gets interrupted to execute "__del__()". -+ -+ * "__del__()" can be executed during interpreter shutdown. As a -+ consequence, the global variables it needs to access (including -+ other modules) may already have been deleted or set to "None". -+ Python guarantees that globals whose name begins with a single -+ underscore are deleted from their module before other globals -+ are deleted; if no other references to such globals exist, this -+ may help in assuring that imported modules are still available -+ at the time when the "__del__()" method is called. -+ -+object.__repr__(self) -+ -+ Called by the "repr()" built-in function to compute the “official†-+ string representation of an object. If at all possible, this -+ should look like a valid Python expression that could be used to -+ recreate an object with the same value (given an appropriate -+ environment). If this is not possible, a string of the form -+ "<...some useful description...>" should be returned. The return -+ value must be a string object. If a class defines "__repr__()" but -+ not "__str__()", then "__repr__()" is also used when an “informal†-+ string representation of instances of that class is required. -+ -+ This is typically used for debugging, so it is important that the -+ representation is information-rich and unambiguous. A default -+ implementation is provided by the "object" class itself. -+ -+object.__str__(self) -+ -+ Called by "str(object)", the default "__format__()" implementation, -+ and the built-in function "print()", to compute the “informal†or -+ nicely printable string representation of an object. The return -+ value must be a str object. -+ -+ This method differs from "object.__repr__()" in that there is no -+ expectation that "__str__()" return a valid Python expression: a -+ more convenient or concise representation can be used. -+ -+ The default implementation defined by the built-in type "object" -+ calls "object.__repr__()". -+ -+object.__bytes__(self) -+ -+ Called by bytes to compute a byte-string representation of an -+ object. This should return a "bytes" object. The "object" class -+ itself does not provide this method. -+ -+object.__format__(self, format_spec) -+ -+ Called by the "format()" built-in function, and by extension, -+ evaluation of formatted string literals and the "str.format()" -+ method, to produce a “formatted†string representation of an -+ object. The *format_spec* argument is a string that contains a -+ description of the formatting options desired. The interpretation -+ of the *format_spec* argument is up to the type implementing -+ "__format__()", however most classes will either delegate -+ formatting to one of the built-in types, or use a similar -+ formatting option syntax. -+ -+ See Format Specification Mini-Language for a description of the -+ standard formatting syntax. -+ -+ The return value must be a string object. -+ -+ The default implementation by the "object" class should be given an -+ empty *format_spec* string. It delegates to "__str__()". -+ -+ Changed in version 3.4: The __format__ method of "object" itself -+ raises a "TypeError" if passed any non-empty string. -+ -+ Changed in version 3.7: "object.__format__(x, '')" is now -+ equivalent to "str(x)" rather than "format(str(x), '')". -+ -+object.__lt__(self, other) -+object.__le__(self, other) -+object.__eq__(self, other) -+object.__ne__(self, other) -+object.__gt__(self, other) -+object.__ge__(self, other) -+ -+ These are the so-called “rich comparison†methods. The -+ correspondence between operator symbols and method names is as -+ follows: "xy" calls -+ "x.__gt__(y)", and "x>=y" calls "x.__ge__(y)". -+ -+ A rich comparison method may return the singleton "NotImplemented" -+ if it does not implement the operation for a given pair of -+ arguments. By convention, "False" and "True" are returned for a -+ successful comparison. However, these methods can return any value, -+ so if the comparison operator is used in a Boolean context (e.g., -+ in the condition of an "if" statement), Python will call "bool()" -+ on the value to determine if the result is true or false. -+ -+ By default, "object" implements "__eq__()" by using "is", returning -+ "NotImplemented" in the case of a false comparison: "True if x is y -+ else NotImplemented". For "__ne__()", by default it delegates to -+ "__eq__()" and inverts the result unless it is "NotImplemented". -+ There are no other implied relationships among the comparison -+ operators or default implementations; for example, the truth of -+ "(x.__hash__". -+ -+ If a class that does not override "__eq__()" wishes to suppress -+ hash support, it should include "__hash__ = None" in the class -+ definition. A class which defines its own "__hash__()" that -+ explicitly raises a "TypeError" would be incorrectly identified as -+ hashable by an "isinstance(obj, collections.abc.Hashable)" call. -+ -+ Note: -+ -+ By default, the "__hash__()" values of str and bytes objects are -+ “salted†with an unpredictable random value. Although they -+ remain constant within an individual Python process, they are not -+ predictable between repeated invocations of Python.This is -+ intended to provide protection against a denial-of-service caused -+ by carefully chosen inputs that exploit the worst case -+ performance of a dict insertion, *O*(*n*^2) complexity. See -+ http://ocert.org/advisories/ocert-2011-003.html for -+ details.Changing hash values affects the iteration order of sets. -+ Python has never made guarantees about this ordering (and it -+ typically varies between 32-bit and 64-bit builds).See also -+ "PYTHONHASHSEED". -+ -+ Changed in version 3.3: Hash randomization is enabled by default. -+ -+object.__bool__(self) -+ -+ Called to implement truth value testing and the built-in operation -+ "bool()"; should return "False" or "True". When this method is not -+ defined, "__len__()" is called, if it is defined, and the object is -+ considered true if its result is nonzero. If a class defines -+ neither "__len__()" nor "__bool__()" (which is true of the "object" -+ class itself), all its instances are considered true. -+''', -+ 'debugger': r'''"pdb" — The Python Debugger -+*************************** -+ -+**Source code:** Lib/pdb.py -+ -+====================================================================== -+ -+The module "pdb" defines an interactive source code debugger for -+Python programs. It supports setting (conditional) breakpoints and -+single stepping at the source line level, inspection of stack frames, -+source code listing, and evaluation of arbitrary Python code in the -+context of any stack frame. It also supports post-mortem debugging -+and can be called under program control. -+ -+The debugger is extensible – it is actually defined as the class -+"Pdb". This is currently undocumented but easily understood by reading -+the source. The extension interface uses the modules "bdb" and "cmd". -+ -+See also: -+ -+ Module "faulthandler" -+ Used to dump Python tracebacks explicitly, on a fault, after a -+ timeout, or on a user signal. -+ -+ Module "traceback" -+ Standard interface to extract, format and print stack traces of -+ Python programs. -+ -+The typical usage to break into the debugger is to insert: -+ -+ import pdb; pdb.set_trace() -+ -+Or: -+ -+ breakpoint() -+ -+at the location you want to break into the debugger, and then run the -+program. You can then step through the code following this statement, -+and continue running without the debugger using the "continue" -+command. -+ -+Changed in version 3.7: The built-in "breakpoint()", when called with -+defaults, can be used instead of "import pdb; pdb.set_trace()". -+ -+ def double(x): -+ breakpoint() -+ return x * 2 -+ val = 3 -+ print(f"{val} * 2 is {double(val)}") -+ -+The debugger’s prompt is "(Pdb)", which is the indicator that you are -+in debug mode: -+ -+ > ...(2)double() -+ -> breakpoint() -+ (Pdb) p x -+ 3 -+ (Pdb) continue -+ 3 * 2 is 6 -+ -+Changed in version 3.3: Tab-completion via the "readline" module is -+available for commands and command arguments, e.g. the current global -+and local names are offered as arguments of the "p" command. -+ -+You can also invoke "pdb" from the command line to debug other -+scripts. For example: -+ -+ python -m pdb myscript.py -+ -+When invoked as a module, pdb will automatically enter post-mortem -+debugging if the program being debugged exits abnormally. After post- -+mortem debugging (or after normal exit of the program), pdb will -+restart the program. Automatic restarting preserves pdb’s state (such -+as breakpoints) and in most cases is more useful than quitting the -+debugger upon program’s exit. -+ -+Changed in version 3.2: Added the "-c" option to execute commands as -+if given in a ".pdbrc" file; see Debugger Commands. -+ -+Changed in version 3.7: Added the "-m" option to execute modules -+similar to the way "python -m" does. As with a script, the debugger -+will pause execution just before the first line of the module. -+ -+Typical usage to execute a statement under control of the debugger is: -+ -+ >>> import pdb -+ >>> def f(x): -+ ... print(1 / x) -+ >>> pdb.run("f(2)") -+ > (1)() -+ (Pdb) continue -+ 0.5 -+ >>> -+ -+The typical usage to inspect a crashed program is: -+ -+ >>> import pdb -+ >>> def f(x): -+ ... print(1 / x) -+ ... -+ >>> f(0) -+ Traceback (most recent call last): -+ File "", line 1, in -+ File "", line 2, in f -+ ZeroDivisionError: division by zero -+ >>> pdb.pm() -+ > (2)f() -+ (Pdb) p x -+ 0 -+ (Pdb) -+ -+Changed in version 3.13: The implementation of **PEP 667** means that -+name assignments made via "pdb" will immediately affect the active -+scope, even when running inside an *optimized scope*. -+ -+The module defines the following functions; each enters the debugger -+in a slightly different way: -+ -+pdb.run(statement, globals=None, locals=None) -+ -+ Execute the *statement* (given as a string or a code object) under -+ debugger control. The debugger prompt appears before any code is -+ executed; you can set breakpoints and type "continue", or you can -+ step through the statement using "step" or "next" (all these -+ commands are explained below). The optional *globals* and *locals* -+ arguments specify the environment in which the code is executed; by -+ default the dictionary of the module "__main__" is used. (See the -+ explanation of the built-in "exec()" or "eval()" functions.) -+ -+pdb.runeval(expression, globals=None, locals=None) -+ -+ Evaluate the *expression* (given as a string or a code object) -+ under debugger control. When "runeval()" returns, it returns the -+ value of the *expression*. Otherwise this function is similar to -+ "run()". -+ -+pdb.runcall(function, *args, **kwds) -+ -+ Call the *function* (a function or method object, not a string) -+ with the given arguments. When "runcall()" returns, it returns -+ whatever the function call returned. The debugger prompt appears -+ as soon as the function is entered. -+ -+pdb.set_trace(*, header=None, commands=None) -+ -+ Enter the debugger at the calling stack frame. This is useful to -+ hard-code a breakpoint at a given point in a program, even if the -+ code is not otherwise being debugged (e.g. when an assertion -+ fails). If given, *header* is printed to the console just before -+ debugging begins. The *commands* argument, if given, is a list of -+ commands to execute when the debugger starts. -+ -+ Changed in version 3.7: The keyword-only argument *header*. -+ -+ Changed in version 3.13: "set_trace()" will enter the debugger -+ immediately, rather than on the next line of code to be executed. -+ -+ Added in version 3.14: The *commands* argument. -+ -+pdb.post_mortem(t=None) -+ -+ Enter post-mortem debugging of the given exception or traceback -+ object. If no value is given, it uses the exception that is -+ currently being handled, or raises "ValueError" if there isn’t one. -+ -+ Changed in version 3.13: Support for exception objects was added. -+ -+pdb.pm() -+ -+ Enter post-mortem debugging of the exception found in -+ "sys.last_exc". -+ -+The "run*" functions and "set_trace()" are aliases for instantiating -+the "Pdb" class and calling the method of the same name. If you want -+to access further features, you have to do this yourself: -+ -+class pdb.Pdb(completekey='tab', stdin=None, stdout=None, skip=None, nosigint=False, readrc=True, mode=None) -+ -+ "Pdb" is the debugger class. -+ -+ The *completekey*, *stdin* and *stdout* arguments are passed to the -+ underlying "cmd.Cmd" class; see the description there. -+ -+ The *skip* argument, if given, must be an iterable of glob-style -+ module name patterns. The debugger will not step into frames that -+ originate in a module that matches one of these patterns. [1] -+ -+ By default, Pdb sets a handler for the SIGINT signal (which is sent -+ when the user presses "Ctrl-C" on the console) when you give a -+ "continue" command. This allows you to break into the debugger -+ again by pressing "Ctrl-C". If you want Pdb not to touch the -+ SIGINT handler, set *nosigint* to true. -+ -+ The *readrc* argument defaults to true and controls whether Pdb -+ will load .pdbrc files from the filesystem. -+ -+ The *mode* argument specifies how the debugger was invoked. It -+ impacts the workings of some debugger commands. Valid values are -+ "'inline'" (used by the breakpoint() builtin), "'cli'" (used by the -+ command line invocation) or "None" (for backwards compatible -+ behaviour, as before the *mode* argument was added). -+ -+ Example call to enable tracing with *skip*: -+ -+ import pdb; pdb.Pdb(skip=['django.*']).set_trace() -+ -+ Raises an auditing event "pdb.Pdb" with no arguments. -+ -+ Changed in version 3.1: Added the *skip* parameter. -+ -+ Changed in version 3.2: Added the *nosigint* parameter. Previously, -+ a SIGINT handler was never set by Pdb. -+ -+ Changed in version 3.6: The *readrc* argument. -+ -+ Added in version 3.14: Added the *mode* argument. -+ -+ run(statement, globals=None, locals=None) -+ runeval(expression, globals=None, locals=None) -+ runcall(function, *args, **kwds) -+ set_trace() -+ -+ See the documentation for the functions explained above. -+ -+ -+Debugger Commands -+================= -+ -+The commands recognized by the debugger are listed below. Most -+commands can be abbreviated to one or two letters as indicated; e.g. -+"h(elp)" means that either "h" or "help" can be used to enter the help -+command (but not "he" or "hel", nor "H" or "Help" or "HELP"). -+Arguments to commands must be separated by whitespace (spaces or -+tabs). Optional arguments are enclosed in square brackets ("[]") in -+the command syntax; the square brackets must not be typed. -+Alternatives in the command syntax are separated by a vertical bar -+("|"). -+ -+Entering a blank line repeats the last command entered. Exception: if -+the last command was a "list" command, the next 11 lines are listed. -+ -+Commands that the debugger doesn’t recognize are assumed to be Python -+statements and are executed in the context of the program being -+debugged. Python statements can also be prefixed with an exclamation -+point ("!"). This is a powerful way to inspect the program being -+debugged; it is even possible to change a variable or call a function. -+When an exception occurs in such a statement, the exception name is -+printed but the debugger’s state is not changed. -+ -+Changed in version 3.13: Expressions/Statements whose prefix is a pdb -+command are now correctly identified and executed. -+ -+The debugger supports aliases. Aliases can have parameters which -+allows one a certain level of adaptability to the context under -+examination. -+ -+Multiple commands may be entered on a single line, separated by ";;". -+(A single ";" is not used as it is the separator for multiple commands -+in a line that is passed to the Python parser.) No intelligence is -+applied to separating the commands; the input is split at the first -+";;" pair, even if it is in the middle of a quoted string. A -+workaround for strings with double semicolons is to use implicit -+string concatenation "';'';'" or "";"";"". -+ -+To set a temporary global variable, use a *convenience variable*. A -+*convenience variable* is a variable whose name starts with "$". For -+example, "$foo = 1" sets a global variable "$foo" which you can use in -+the debugger session. The *convenience variables* are cleared when -+the program resumes execution so it’s less likely to interfere with -+your program compared to using normal variables like "foo = 1". -+ -+There are three preset *convenience variables*: -+ -+* "$_frame": the current frame you are debugging -+ -+* "$_retval": the return value if the frame is returning -+ -+* "$_exception": the exception if the frame is raising an exception -+ -+Added in version 3.12: Added the *convenience variable* feature. -+ -+If a file ".pdbrc" exists in the user’s home directory or in the -+current directory, it is read with "'utf-8'" encoding and executed as -+if it had been typed at the debugger prompt, with the exception that -+empty lines and lines starting with "#" are ignored. This is -+particularly useful for aliases. If both files exist, the one in the -+home directory is read first and aliases defined there can be -+overridden by the local file. -+ -+Changed in version 3.2: ".pdbrc" can now contain commands that -+continue debugging, such as "continue" or "next". Previously, these -+commands had no effect. -+ -+Changed in version 3.11: ".pdbrc" is now read with "'utf-8'" encoding. -+Previously, it was read with the system locale encoding. -+ -+h(elp) [command] -+ -+ Without argument, print the list of available commands. With a -+ *command* as argument, print help about that command. "help pdb" -+ displays the full documentation (the docstring of the "pdb" -+ module). Since the *command* argument must be an identifier, "help -+ exec" must be entered to get help on the "!" command. -+ -+w(here) [count] -+ -+ Print a stack trace, with the most recent frame at the bottom. if -+ *count* is 0, print the current frame entry. If *count* is -+ negative, print the least recent - *count* frames. If *count* is -+ positive, print the most recent *count* frames. An arrow (">") -+ indicates the current frame, which determines the context of most -+ commands. -+ -+ Changed in version 3.14: *count* argument is added. -+ -+d(own) [count] -+ -+ Move the current frame *count* (default one) levels down in the -+ stack trace (to a newer frame). -+ -+u(p) [count] -+ -+ Move the current frame *count* (default one) levels up in the stack -+ trace (to an older frame). -+ -+b(reak) [([filename:]lineno | function) [, condition]] -+ -+ With a *lineno* argument, set a break at line *lineno* in the -+ current file. The line number may be prefixed with a *filename* and -+ a colon, to specify a breakpoint in another file (possibly one that -+ hasn’t been loaded yet). The file is searched on "sys.path". -+ Acceptable forms of *filename* are "/abspath/to/file.py", -+ "relpath/file.py", "module" and "package.module". -+ -+ With a *function* argument, set a break at the first executable -+ statement within that function. *function* can be any expression -+ that evaluates to a function in the current namespace. -+ -+ If a second argument is present, it is an expression which must -+ evaluate to true before the breakpoint is honored. -+ -+ Without argument, list all breaks, including for each breakpoint, -+ the number of times that breakpoint has been hit, the current -+ ignore count, and the associated condition if any. -+ -+ Each breakpoint is assigned a number to which all the other -+ breakpoint commands refer. -+ -+tbreak [([filename:]lineno | function) [, condition]] -+ -+ Temporary breakpoint, which is removed automatically when it is -+ first hit. The arguments are the same as for "break". -+ -+cl(ear) [filename:lineno | bpnumber ...] -+ -+ With a *filename:lineno* argument, clear all the breakpoints at -+ this line. With a space separated list of breakpoint numbers, clear -+ those breakpoints. Without argument, clear all breaks (but first -+ ask confirmation). -+ -+disable bpnumber [bpnumber ...] -+ -+ Disable the breakpoints given as a space separated list of -+ breakpoint numbers. Disabling a breakpoint means it cannot cause -+ the program to stop execution, but unlike clearing a breakpoint, it -+ remains in the list of breakpoints and can be (re-)enabled. -+ -+enable bpnumber [bpnumber ...] -+ -+ Enable the breakpoints specified. -+ -+ignore bpnumber [count] -+ -+ Set the ignore count for the given breakpoint number. If *count* -+ is omitted, the ignore count is set to 0. A breakpoint becomes -+ active when the ignore count is zero. When non-zero, the *count* -+ is decremented each time the breakpoint is reached and the -+ breakpoint is not disabled and any associated condition evaluates -+ to true. -+ -+condition bpnumber [condition] -+ -+ Set a new *condition* for the breakpoint, an expression which must -+ evaluate to true before the breakpoint is honored. If *condition* -+ is absent, any existing condition is removed; i.e., the breakpoint -+ is made unconditional. -+ -+commands [bpnumber] -+ -+ Specify a list of commands for breakpoint number *bpnumber*. The -+ commands themselves appear on the following lines. Type a line -+ containing just "end" to terminate the commands. An example: -+ -+ (Pdb) commands 1 -+ (com) p some_variable -+ (com) end -+ (Pdb) -+ -+ To remove all commands from a breakpoint, type "commands" and -+ follow it immediately with "end"; that is, give no commands. -+ -+ With no *bpnumber* argument, "commands" refers to the last -+ breakpoint set. -+ -+ You can use breakpoint commands to start your program up again. -+ Simply use the "continue" command, or "step", or any other command -+ that resumes execution. -+ -+ Specifying any command resuming execution (currently "continue", -+ "step", "next", "return", "until", "jump", "quit" and their -+ abbreviations) terminates the command list (as if that command was -+ immediately followed by end). This is because any time you resume -+ execution (even with a simple next or step), you may encounter -+ another breakpoint—which could have its own command list, leading -+ to ambiguities about which list to execute. -+ -+ If the list of commands contains the "silent" command, or a command -+ that resumes execution, then the breakpoint message containing -+ information about the frame is not displayed. -+ -+ Changed in version 3.14: Frame information will not be displayed if -+ a command that resumes execution is present in the command list. -+ -+s(tep) -+ -+ Execute the current line, stop at the first possible occasion -+ (either in a function that is called or on the next line in the -+ current function). -+ -+n(ext) -+ -+ Continue execution until the next line in the current function is -+ reached or it returns. (The difference between "next" and "step" -+ is that "step" stops inside a called function, while "next" -+ executes called functions at (nearly) full speed, only stopping at -+ the next line in the current function.) -+ -+unt(il) [lineno] -+ -+ Without argument, continue execution until the line with a number -+ greater than the current one is reached. -+ -+ With *lineno*, continue execution until a line with a number -+ greater or equal to *lineno* is reached. In both cases, also stop -+ when the current frame returns. -+ -+ Changed in version 3.2: Allow giving an explicit line number. -+ -+r(eturn) -+ -+ Continue execution until the current function returns. -+ -+c(ont(inue)) -+ -+ Continue execution, only stop when a breakpoint is encountered. -+ -+j(ump) lineno -+ -+ Set the next line that will be executed. Only available in the -+ bottom-most frame. This lets you jump back and execute code again, -+ or jump forward to skip code that you don’t want to run. -+ -+ It should be noted that not all jumps are allowed – for instance it -+ is not possible to jump into the middle of a "for" loop or out of a -+ "finally" clause. -+ -+l(ist) [first[, last]] -+ -+ List source code for the current file. Without arguments, list 11 -+ lines around the current line or continue the previous listing. -+ With "." as argument, list 11 lines around the current line. With -+ one argument, list 11 lines around at that line. With two -+ arguments, list the given range; if the second argument is less -+ than the first, it is interpreted as a count. -+ -+ The current line in the current frame is indicated by "->". If an -+ exception is being debugged, the line where the exception was -+ originally raised or propagated is indicated by ">>", if it differs -+ from the current line. -+ -+ Changed in version 3.2: Added the ">>" marker. -+ -+ll | longlist -+ -+ List all source code for the current function or frame. -+ Interesting lines are marked as for "list". -+ -+ Added in version 3.2. -+ -+a(rgs) -+ -+ Print the arguments of the current function and their current -+ values. -+ -+p expression -+ -+ Evaluate *expression* in the current context and print its value. -+ -+ Note: -+ -+ "print()" can also be used, but is not a debugger command — this -+ executes the Python "print()" function. -+ -+pp expression -+ -+ Like the "p" command, except the value of *expression* is pretty- -+ printed using the "pprint" module. -+ -+whatis expression -+ -+ Print the type of *expression*. -+ -+source expression -+ -+ Try to get source code of *expression* and display it. -+ -+ Added in version 3.2. -+ -+display [expression] -+ -+ Display the value of *expression* if it changed, each time -+ execution stops in the current frame. -+ -+ Without *expression*, list all display expressions for the current -+ frame. -+ -+ Note: -+ -+ Display evaluates *expression* and compares to the result of the -+ previous evaluation of *expression*, so when the result is -+ mutable, display may not be able to pick up the changes. -+ -+ Example: -+ -+ lst = [] -+ breakpoint() -+ pass -+ lst.append(1) -+ print(lst) -+ -+ Display won’t realize "lst" has been changed because the result of -+ evaluation is modified in place by "lst.append(1)" before being -+ compared: -+ -+ > example.py(3)() -+ -> pass -+ (Pdb) display lst -+ display lst: [] -+ (Pdb) n -+ > example.py(4)() -+ -> lst.append(1) -+ (Pdb) n -+ > example.py(5)() -+ -> print(lst) -+ (Pdb) -+ -+ You can do some tricks with copy mechanism to make it work: -+ -+ > example.py(3)() -+ -> pass -+ (Pdb) display lst[:] -+ display lst[:]: [] -+ (Pdb) n -+ > example.py(4)() -+ -> lst.append(1) -+ (Pdb) n -+ > example.py(5)() -+ -> print(lst) -+ display lst[:]: [1] [old: []] -+ (Pdb) -+ -+ Added in version 3.2. -+ -+undisplay [expression] -+ -+ Do not display *expression* anymore in the current frame. Without -+ *expression*, clear all display expressions for the current frame. -+ -+ Added in version 3.2. -+ -+interact -+ -+ Start an interactive interpreter (using the "code" module) in a new -+ global namespace initialised from the local and global namespaces -+ for the current scope. Use "exit()" or "quit()" to exit the -+ interpreter and return to the debugger. -+ -+ Note: -+ -+ As "interact" creates a new dedicated namespace for code -+ execution, assignments to variables will not affect the original -+ namespaces. However, modifications to any referenced mutable -+ objects will be reflected in the original namespaces as usual. -+ -+ Added in version 3.2. -+ -+ Changed in version 3.13: "exit()" and "quit()" can be used to exit -+ the "interact" command. -+ -+ Changed in version 3.13: "interact" directs its output to the -+ debugger’s output channel rather than "sys.stderr". -+ -+alias [name [command]] -+ -+ Create an alias called *name* that executes *command*. The -+ *command* must *not* be enclosed in quotes. Replaceable parameters -+ can be indicated by "%1", "%2", … and "%9", while "%*" is replaced -+ by all the parameters. If *command* is omitted, the current alias -+ for *name* is shown. If no arguments are given, all aliases are -+ listed. -+ -+ Aliases may be nested and can contain anything that can be legally -+ typed at the pdb prompt. Note that internal pdb commands *can* be -+ overridden by aliases. Such a command is then hidden until the -+ alias is removed. Aliasing is recursively applied to the first -+ word of the command line; all other words in the line are left -+ alone. -+ -+ As an example, here are two useful aliases (especially when placed -+ in the ".pdbrc" file): -+ -+ # Print instance variables (usage "pi classInst") -+ alias pi for k in %1.__dict__.keys(): print(f"%1.{k} = {%1.__dict__[k]}") -+ # Print instance variables in self -+ alias ps pi self -+ -+unalias name -+ -+ Delete the specified alias *name*. -+ -+! statement -+ -+ Execute the (one-line) *statement* in the context of the current -+ stack frame. The exclamation point can be omitted unless the first -+ word of the statement resembles a debugger command, e.g.: -+ -+ (Pdb) ! n=42 -+ (Pdb) -+ -+ To set a global variable, you can prefix the assignment command -+ with a "global" statement on the same line, e.g.: -+ -+ (Pdb) global list_options; list_options = ['-l'] -+ (Pdb) -+ -+run [args ...] -+restart [args ...] -+ -+ Restart the debugged Python program. If *args* is supplied, it is -+ split with "shlex" and the result is used as the new "sys.argv". -+ History, breakpoints, actions and debugger options are preserved. -+ "restart" is an alias for "run". -+ -+ Changed in version 3.14: "run" and "restart" commands are disabled -+ when the debugger is invoked in "'inline'" mode. -+ -+q(uit) -+ -+ Quit from the debugger. The program being executed is aborted. An -+ end-of-file input is equivalent to "quit". -+ -+ A confirmation prompt will be shown if the debugger is invoked in -+ "'inline'" mode. Either "y", "Y", "" or "EOF" will confirm -+ the quit. -+ -+ Changed in version 3.14: A confirmation prompt will be shown if the -+ debugger is invoked in "'inline'" mode. After the confirmation, the -+ debugger will call "sys.exit()" immediately, instead of raising -+ "bdb.BdbQuit" in the next trace event. -+ -+debug code -+ -+ Enter a recursive debugger that steps through *code* (which is an -+ arbitrary expression or statement to be executed in the current -+ environment). -+ -+retval -+ -+ Print the return value for the last return of the current function. -+ -+exceptions [excnumber] -+ -+ List or jump between chained exceptions. -+ -+ When using "pdb.pm()" or "Pdb.post_mortem(...)" with a chained -+ exception instead of a traceback, it allows the user to move -+ between the chained exceptions using "exceptions" command to list -+ exceptions, and "exception " to switch to that exception. -+ -+ Example: -+ -+ def out(): -+ try: -+ middle() -+ except Exception as e: -+ raise ValueError("reraise middle() error") from e -+ -+ def middle(): -+ try: -+ return inner(0) -+ except Exception as e: -+ raise ValueError("Middle fail") -+ -+ def inner(x): -+ 1 / x -+ -+ out() -+ -+ calling "pdb.pm()" will allow to move between exceptions: -+ -+ > example.py(5)out() -+ -> raise ValueError("reraise middle() error") from e -+ -+ (Pdb) exceptions -+ 0 ZeroDivisionError('division by zero') -+ 1 ValueError('Middle fail') -+ > 2 ValueError('reraise middle() error') -+ -+ (Pdb) exceptions 0 -+ > example.py(16)inner() -+ -> 1 / x -+ -+ (Pdb) up -+ > example.py(10)middle() -+ -> return inner(0) -+ -+ Added in version 3.13. -+ -+-[ Footnotes ]- -+ -+[1] Whether a frame is considered to originate in a certain module is -+ determined by the "__name__" in the frame globals. -+''', -+ 'del': r'''The "del" statement -+******************* -+ -+ **del_stmt**: "del" "target_list" -+ -+Deletion is recursively defined very similar to the way assignment is -+defined. Rather than spelling it out in full details, here are some -+hints. -+ -+Deletion of a target list recursively deletes each target, from left -+to right. -+ -+Deletion of a name removes the binding of that name from the local or -+global namespace, depending on whether the name occurs in a "global" -+statement in the same code block. If the name is unbound, a -+"NameError" exception will be raised. -+ -+Deletion of attribute references, subscriptions and slicings is passed -+to the primary object involved; deletion of a slicing is in general -+equivalent to assignment of an empty slice of the right type (but even -+this is determined by the sliced object). -+ -+Changed in version 3.2: Previously it was illegal to delete a name -+from the local namespace if it occurs as a free variable in a nested -+block. -+''', -+ 'dict': r'''Dictionary displays -+******************* -+ -+A dictionary display is a possibly empty series of dict items -+(key/value pairs) enclosed in curly braces: -+ -+ **dict_display**: "{" ["dict_item_list" | "dict_comprehension"] "}" -+ **dict_item_list**: "dict_item" ("," "dict_item")* [","] -+ **dict_item**: "expression" ":" "expression" | "**" "or_expr" -+ **dict_comprehension**: "expression" ":" "expression" "comp_for" -+ -+A dictionary display yields a new dictionary object. -+ -+If a comma-separated sequence of dict items is given, they are -+evaluated from left to right to define the entries of the dictionary: -+each key object is used as a key into the dictionary to store the -+corresponding value. This means that you can specify the same key -+multiple times in the dict item list, and the final dictionary’s value -+for that key will be the last one given. -+ -+A double asterisk "**" denotes *dictionary unpacking*. Its operand -+must be a *mapping*. Each mapping item is added to the new -+dictionary. Later values replace values already set by earlier dict -+items and earlier dictionary unpackings. -+ -+Added in version 3.5: Unpacking into dictionary displays, originally -+proposed by **PEP 448**. -+ -+A dict comprehension, in contrast to list and set comprehensions, -+needs two expressions separated with a colon followed by the usual -+“for†and “if†clauses. When the comprehension is run, the resulting -+key and value elements are inserted in the new dictionary in the order -+they are produced. -+ -+Restrictions on the types of the key values are listed earlier in -+section The standard type hierarchy. (To summarize, the key type -+should be *hashable*, which excludes all mutable objects.) Clashes -+between duplicate keys are not detected; the last value (textually -+rightmost in the display) stored for a given key value prevails. -+ -+Changed in version 3.8: Prior to Python 3.8, in dict comprehensions, -+the evaluation order of key and value was not well-defined. In -+CPython, the value was evaluated before the key. Starting with 3.8, -+the key is evaluated before the value, as proposed by **PEP 572**. -+''', -+ 'dynamic-features': r'''Interaction with dynamic features -+********************************* -+ -+Name resolution of free variables occurs at runtime, not at compile -+time. This means that the following code will print 42: -+ -+ i = 10 -+ def f(): -+ print(i) -+ i = 42 -+ f() -+ -+The "eval()" and "exec()" functions do not have access to the full -+environment for resolving names. Names may be resolved in the local -+and global namespaces of the caller. Free variables are not resolved -+in the nearest enclosing namespace, but in the global namespace. [1] -+The "exec()" and "eval()" functions have optional arguments to -+override the global and local namespace. If only one namespace is -+specified, it is used for both. -+''', -+ 'else': r'''The "if" statement -+****************** -+ -+The "if" statement is used for conditional execution: -+ -+ **if_stmt**: "if" "assignment_expression" ":" "suite" -+ ("elif" "assignment_expression" ":" "suite")* -+ ["else" ":" "suite"] -+ -+It selects exactly one of the suites by evaluating the expressions one -+by one until one is found to be true (see section Boolean operations -+for the definition of true and false); then that suite is executed -+(and no other part of the "if" statement is executed or evaluated). -+If all expressions are false, the suite of the "else" clause, if -+present, is executed. -+''', -+ 'exceptions': r'''Exceptions -+********** -+ -+Exceptions are a means of breaking out of the normal flow of control -+of a code block in order to handle errors or other exceptional -+conditions. An exception is *raised* at the point where the error is -+detected; it may be *handled* by the surrounding code block or by any -+code block that directly or indirectly invoked the code block where -+the error occurred. -+ -+The Python interpreter raises an exception when it detects a run-time -+error (such as division by zero). A Python program can also -+explicitly raise an exception with the "raise" statement. Exception -+handlers are specified with the "try" … "except" statement. The -+"finally" clause of such a statement can be used to specify cleanup -+code which does not handle the exception, but is executed whether an -+exception occurred or not in the preceding code. -+ -+Python uses the “termination†model of error handling: an exception -+handler can find out what happened and continue execution at an outer -+level, but it cannot repair the cause of the error and retry the -+failing operation (except by re-entering the offending piece of code -+from the top). -+ -+When an exception is not handled at all, the interpreter terminates -+execution of the program, or returns to its interactive main loop. In -+either case, it prints a stack traceback, except when the exception is -+"SystemExit". -+ -+Exceptions are identified by class instances. The "except" clause is -+selected depending on the class of the instance: it must reference the -+class of the instance or a *non-virtual base class* thereof. The -+instance can be received by the handler and can carry additional -+information about the exceptional condition. -+ -+Note: -+ -+ Exception messages are not part of the Python API. Their contents -+ may change from one version of Python to the next without warning -+ and should not be relied on by code which will run under multiple -+ versions of the interpreter. -+ -+See also the description of the "try" statement in section The try -+statement and "raise" statement in section The raise statement. -+ -+-[ Footnotes ]- -+ -+[1] This limitation occurs because the code that is executed by these -+ operations is not available at the time the module is compiled. -+''', -+ 'execmodel': r'''Execution model -+*************** -+ -+ -+Structure of a program -+====================== -+ -+A Python program is constructed from code blocks. A *block* is a piece -+of Python program text that is executed as a unit. The following are -+blocks: a module, a function body, and a class definition. Each -+command typed interactively is a block. A script file (a file given -+as standard input to the interpreter or specified as a command line -+argument to the interpreter) is a code block. A script command (a -+command specified on the interpreter command line with the "-c" -+option) is a code block. A module run as a top level script (as module -+"__main__") from the command line using a "-m" argument is also a code -+block. The string argument passed to the built-in functions "eval()" -+and "exec()" is a code block. -+ -+A code block is executed in an *execution frame*. A frame contains -+some administrative information (used for debugging) and determines -+where and how execution continues after the code block’s execution has -+completed. -+ -+ -+Naming and binding -+================== -+ -+ -+Binding of names -+---------------- -+ -+*Names* refer to objects. Names are introduced by name binding -+operations. -+ -+The following constructs bind names: -+ -+* formal parameters to functions, -+ -+* class definitions, -+ -+* function definitions, -+ -+* assignment expressions, -+ -+* targets that are identifiers if occurring in an assignment: -+ -+ * "for" loop header, -+ -+ * after "as" in a "with" statement, "except" clause, "except*" -+ clause, or in the as-pattern in structural pattern matching, -+ -+ * in a capture pattern in structural pattern matching -+ -+* "import" statements. -+ -+* "type" statements. -+ -+* type parameter lists. -+ -+The "import" statement of the form "from ... import *" binds all names -+defined in the imported module, except those beginning with an -+underscore. This form may only be used at the module level. -+ -+A target occurring in a "del" statement is also considered bound for -+this purpose (though the actual semantics are to unbind the name). -+ -+Each assignment or import statement occurs within a block defined by a -+class or function definition or at the module level (the top-level -+code block). -+ -+If a name is bound in a block, it is a local variable of that block, -+unless declared as "nonlocal" or "global". If a name is bound at the -+module level, it is a global variable. (The variables of the module -+code block are local and global.) If a variable is used in a code -+block but not defined there, it is a *free variable*. -+ -+Each occurrence of a name in the program text refers to the *binding* -+of that name established by the following name resolution rules. -+ -+ -+Resolution of names -+------------------- -+ -+A *scope* defines the visibility of a name within a block. If a local -+variable is defined in a block, its scope includes that block. If the -+definition occurs in a function block, the scope extends to any blocks -+contained within the defining one, unless a contained block introduces -+a different binding for the name. -+ -+When a name is used in a code block, it is resolved using the nearest -+enclosing scope. The set of all such scopes visible to a code block -+is called the block’s *environment*. -+ -+When a name is not found at all, a "NameError" exception is raised. If -+the current scope is a function scope, and the name refers to a local -+variable that has not yet been bound to a value at the point where the -+name is used, an "UnboundLocalError" exception is raised. -+"UnboundLocalError" is a subclass of "NameError". -+ -+If a name binding operation occurs anywhere within a code block, all -+uses of the name within the block are treated as references to the -+current block. This can lead to errors when a name is used within a -+block before it is bound. This rule is subtle. Python lacks -+declarations and allows name binding operations to occur anywhere -+within a code block. The local variables of a code block can be -+determined by scanning the entire text of the block for name binding -+operations. See the FAQ entry on UnboundLocalError for examples. -+ -+If the "global" statement occurs within a block, all uses of the names -+specified in the statement refer to the bindings of those names in the -+top-level namespace. Names are resolved in the top-level namespace by -+searching the global namespace, i.e. the namespace of the module -+containing the code block, and the builtins namespace, the namespace -+of the module "builtins". The global namespace is searched first. If -+the names are not found there, the builtins namespace is searched -+next. If the names are also not found in the builtins namespace, new -+variables are created in the global namespace. The global statement -+must precede all uses of the listed names. -+ -+The "global" statement has the same scope as a name binding operation -+in the same block. If the nearest enclosing scope for a free variable -+contains a global statement, the free variable is treated as a global. -+ -+The "nonlocal" statement causes corresponding names to refer to -+previously bound variables in the nearest enclosing function scope. -+"SyntaxError" is raised at compile time if the given name does not -+exist in any enclosing function scope. Type parameters cannot be -+rebound with the "nonlocal" statement. -+ -+The namespace for a module is automatically created the first time a -+module is imported. The main module for a script is always called -+"__main__". -+ -+Class definition blocks and arguments to "exec()" and "eval()" are -+special in the context of name resolution. A class definition is an -+executable statement that may use and define names. These references -+follow the normal rules for name resolution with an exception that -+unbound local variables are looked up in the global namespace. The -+namespace of the class definition becomes the attribute dictionary of -+the class. The scope of names defined in a class block is limited to -+the class block; it does not extend to the code blocks of methods. -+This includes comprehensions and generator expressions, but it does -+not include annotation scopes, which have access to their enclosing -+class scopes. This means that the following will fail: -+ -+ class A: -+ a = 42 -+ b = list(a + i for i in range(10)) -+ -+However, the following will succeed: -+ -+ class A: -+ type Alias = Nested -+ class Nested: pass -+ -+ print(A.Alias.__value__) # -+ -+ -+Annotation scopes -+----------------- -+ -+*Annotations*, type parameter lists and "type" statements introduce -+*annotation scopes*, which behave mostly like function scopes, but -+with some exceptions discussed below. -+ -+Annotation scopes are used in the following contexts: -+ -+* *Function annotations*. -+ -+* *Variable annotations*. -+ -+* Type parameter lists for generic type aliases. -+ -+* Type parameter lists for generic functions. A generic function’s -+ annotations are executed within the annotation scope, but its -+ defaults and decorators are not. -+ -+* Type parameter lists for generic classes. A generic class’s base -+ classes and keyword arguments are executed within the annotation -+ scope, but its decorators are not. -+ -+* The bounds, constraints, and default values for type parameters -+ (lazily evaluated). -+ -+* The value of type aliases (lazily evaluated). -+ -+Annotation scopes differ from function scopes in the following ways: -+ -+* Annotation scopes have access to their enclosing class namespace. If -+ an annotation scope is immediately within a class scope, or within -+ another annotation scope that is immediately within a class scope, -+ the code in the annotation scope can use names defined in the class -+ scope as if it were executed directly within the class body. This -+ contrasts with regular functions defined within classes, which -+ cannot access names defined in the class scope. -+ -+* Expressions in annotation scopes cannot contain "yield", "yield -+ from", "await", or ":=" expressions. (These expressions are allowed -+ in other scopes contained within the annotation scope.) -+ -+* Names defined in annotation scopes cannot be rebound with "nonlocal" -+ statements in inner scopes. This includes only type parameters, as -+ no other syntactic elements that can appear within annotation scopes -+ can introduce new names. -+ -+* While annotation scopes have an internal name, that name is not -+ reflected in the *qualified name* of objects defined within the -+ scope. Instead, the "__qualname__" of such objects is as if the -+ object were defined in the enclosing scope. -+ -+Added in version 3.12: Annotation scopes were introduced in Python -+3.12 as part of **PEP 695**. -+ -+Changed in version 3.13: Annotation scopes are also used for type -+parameter defaults, as introduced by **PEP 696**. -+ -+Changed in version 3.14: Annotation scopes are now also used for -+annotations, as specified in **PEP 649** and **PEP 749**. -+ -+ -+Lazy evaluation -+--------------- -+ -+Most annotation scopes are *lazily evaluated*. This includes -+annotations, the values of type aliases created through the "type" -+statement, and the bounds, constraints, and default values of type -+variables created through the type parameter syntax. This means that -+they are not evaluated when the type alias or type variable is -+created, or when the object carrying annotations is created. Instead, -+they are only evaluated when necessary, for example when the -+"__value__" attribute on a type alias is accessed. -+ -+Example: -+ -+ >>> type Alias = 1/0 -+ >>> Alias.__value__ -+ Traceback (most recent call last): -+ ... -+ ZeroDivisionError: division by zero -+ >>> def func[T: 1/0](): pass -+ >>> T = func.__type_params__[0] -+ >>> T.__bound__ -+ Traceback (most recent call last): -+ ... -+ ZeroDivisionError: division by zero -+ -+Here the exception is raised only when the "__value__" attribute of -+the type alias or the "__bound__" attribute of the type variable is -+accessed. -+ -+This behavior is primarily useful for references to types that have -+not yet been defined when the type alias or type variable is created. -+For example, lazy evaluation enables creation of mutually recursive -+type aliases: -+ -+ from typing import Literal -+ -+ type SimpleExpr = int | Parenthesized -+ type Parenthesized = tuple[Literal["("], Expr, Literal[")"]] -+ type Expr = SimpleExpr | tuple[SimpleExpr, Literal["+", "-"], Expr] -+ -+Lazily evaluated values are evaluated in annotation scope, which means -+that names that appear inside the lazily evaluated value are looked up -+as if they were used in the immediately enclosing scope. -+ -+Added in version 3.12. -+ -+ -+Builtins and restricted execution -+--------------------------------- -+ -+**CPython implementation detail:** Users should not touch -+"__builtins__"; it is strictly an implementation detail. Users -+wanting to override values in the builtins namespace should "import" -+the "builtins" module and modify its attributes appropriately. -+ -+The builtins namespace associated with the execution of a code block -+is actually found by looking up the name "__builtins__" in its global -+namespace; this should be a dictionary or a module (in the latter case -+the module’s dictionary is used). By default, when in the "__main__" -+module, "__builtins__" is the built-in module "builtins"; when in any -+other module, "__builtins__" is an alias for the dictionary of the -+"builtins" module itself. -+ -+ -+Interaction with dynamic features -+--------------------------------- -+ -+Name resolution of free variables occurs at runtime, not at compile -+time. This means that the following code will print 42: -+ -+ i = 10 -+ def f(): -+ print(i) -+ i = 42 -+ f() -+ -+The "eval()" and "exec()" functions do not have access to the full -+environment for resolving names. Names may be resolved in the local -+and global namespaces of the caller. Free variables are not resolved -+in the nearest enclosing namespace, but in the global namespace. [1] -+The "exec()" and "eval()" functions have optional arguments to -+override the global and local namespace. If only one namespace is -+specified, it is used for both. -+ -+ -+Exceptions -+========== -+ -+Exceptions are a means of breaking out of the normal flow of control -+of a code block in order to handle errors or other exceptional -+conditions. An exception is *raised* at the point where the error is -+detected; it may be *handled* by the surrounding code block or by any -+code block that directly or indirectly invoked the code block where -+the error occurred. -+ -+The Python interpreter raises an exception when it detects a run-time -+error (such as division by zero). A Python program can also -+explicitly raise an exception with the "raise" statement. Exception -+handlers are specified with the "try" … "except" statement. The -+"finally" clause of such a statement can be used to specify cleanup -+code which does not handle the exception, but is executed whether an -+exception occurred or not in the preceding code. -+ -+Python uses the “termination†model of error handling: an exception -+handler can find out what happened and continue execution at an outer -+level, but it cannot repair the cause of the error and retry the -+failing operation (except by re-entering the offending piece of code -+from the top). -+ -+When an exception is not handled at all, the interpreter terminates -+execution of the program, or returns to its interactive main loop. In -+either case, it prints a stack traceback, except when the exception is -+"SystemExit". -+ -+Exceptions are identified by class instances. The "except" clause is -+selected depending on the class of the instance: it must reference the -+class of the instance or a *non-virtual base class* thereof. The -+instance can be received by the handler and can carry additional -+information about the exceptional condition. -+ -+Note: -+ -+ Exception messages are not part of the Python API. Their contents -+ may change from one version of Python to the next without warning -+ and should not be relied on by code which will run under multiple -+ versions of the interpreter. -+ -+See also the description of the "try" statement in section The try -+statement and "raise" statement in section The raise statement. -+ -+-[ Footnotes ]- -+ -+[1] This limitation occurs because the code that is executed by these -+ operations is not available at the time the module is compiled. -+''', -+ 'exprlists': r'''Expression lists -+**************** -+ -+ **starred_expression**: ["*"] "or_expr" -+ **flexible_expression**: "assignment_expression" | "starred_expression" -+ **flexible_expression_list**: "flexible_expression" ("," "flexible_expression")* [","] -+ **starred_expression_list**: "starred_expression" ("," "starred_expression")* [","] -+ **expression_list**: "expression" ("," "expression")* [","] -+ **yield_list**: "expression_list" | "starred_expression" "," ["starred_expression_list"] -+ -+Except when part of a list or set display, an expression list -+containing at least one comma yields a tuple. The length of the tuple -+is the number of expressions in the list. The expressions are -+evaluated from left to right. -+ -+An asterisk "*" denotes *iterable unpacking*. Its operand must be an -+*iterable*. The iterable is expanded into a sequence of items, which -+are included in the new tuple, list, or set, at the site of the -+unpacking. -+ -+Added in version 3.5: Iterable unpacking in expression lists, -+originally proposed by **PEP 448**. -+ -+Added in version 3.11: Any item in an expression list may be starred. -+See **PEP 646**. -+ -+A trailing comma is required only to create a one-item tuple, such as -+"1,"; it is optional in all other cases. A single expression without a -+trailing comma doesn’t create a tuple, but rather yields the value of -+that expression. (To create an empty tuple, use an empty pair of -+parentheses: "()".) -+''', -+ 'floating': r'''Floating-point literals -+*********************** -+ -+Floating-point literals are described by the following lexical -+definitions: -+ -+ **floatnumber**: "pointfloat" | "exponentfloat" -+ **pointfloat**: ["digitpart"] "fraction" | "digitpart" "." -+ **exponentfloat**: ("digitpart" | "pointfloat") "exponent" -+ **digitpart**: "digit" (["_"] "digit")* -+ **fraction**: "." "digitpart" -+ **exponent**: ("e" | "E") ["+" | "-"] "digitpart" -+ -+Note that the integer and exponent parts are always interpreted using -+radix 10. For example, "077e010" is legal, and denotes the same number -+as "77e10". The allowed range of floating-point literals is -+implementation-dependent. As in integer literals, underscores are -+supported for digit grouping. -+ -+Some examples of floating-point literals: -+ -+ 3.14 10. .001 1e100 3.14e-10 0e0 3.14_15_93 -+ -+Changed in version 3.6: Underscores are now allowed for grouping -+purposes in literals. -+''', -+ 'for': r'''The "for" statement -+******************* -+ -+The "for" statement is used to iterate over the elements of a sequence -+(such as a string, tuple or list) or other iterable object: -+ -+ **for_stmt**: "for" "target_list" "in" "starred_list" ":" "suite" -+ ["else" ":" "suite"] -+ -+The "starred_list" expression is evaluated once; it should yield an -+*iterable* object. An *iterator* is created for that iterable. The -+first item provided by the iterator is then assigned to the target -+list using the standard rules for assignments (see Assignment -+statements), and the suite is executed. This repeats for each item -+provided by the iterator. When the iterator is exhausted, the suite -+in the "else" clause, if present, is executed, and the loop -+terminates. -+ -+A "break" statement executed in the first suite terminates the loop -+without executing the "else" clause’s suite. A "continue" statement -+executed in the first suite skips the rest of the suite and continues -+with the next item, or with the "else" clause if there is no next -+item. -+ -+The for-loop makes assignments to the variables in the target list. -+This overwrites all previous assignments to those variables including -+those made in the suite of the for-loop: -+ -+ for i in range(10): -+ print(i) -+ i = 5 # this will not affect the for-loop -+ # because i will be overwritten with the next -+ # index in the range -+ -+Names in the target list are not deleted when the loop is finished, -+but if the sequence is empty, they will not have been assigned to at -+all by the loop. Hint: the built-in type "range()" represents -+immutable arithmetic sequences of integers. For instance, iterating -+"range(3)" successively yields 0, 1, and then 2. -+ -+Changed in version 3.11: Starred elements are now allowed in the -+expression list. -+''', -+ 'formatstrings': r'''Format String Syntax -+******************** -+ -+The "str.format()" method and the "Formatter" class share the same -+syntax for format strings (although in the case of "Formatter", -+subclasses can define their own format string syntax). The syntax is -+related to that of formatted string literals, but it is less -+sophisticated and, in particular, does not support arbitrary -+expressions. -+ -+Format strings contain “replacement fields†surrounded by curly braces -+"{}". Anything that is not contained in braces is considered literal -+text, which is copied unchanged to the output. If you need to include -+a brace character in the literal text, it can be escaped by doubling: -+"{{" and "}}". -+ -+The grammar for a replacement field is as follows: -+ -+ **replacement_field**: "{" ["field_name"] ["!" "conversion"] [":" "format_spec"] "}" -+ **field_name**: "arg_name" ("." "attribute_name" | "[" "element_index" "]")* -+ **arg_name**: ["identifier" | "digit"+] -+ **attribute_name**: "identifier" -+ **element_index**: "digit"+ | "index_string" -+ **index_string**: + -+ **conversion**: "r" | "s" | "a" -+ **format_spec**: "format-spec:format_spec" -+ -+In less formal terms, the replacement field can start with a -+*field_name* that specifies the object whose value is to be formatted -+and inserted into the output instead of the replacement field. The -+*field_name* is optionally followed by a *conversion* field, which is -+preceded by an exclamation point "'!'", and a *format_spec*, which is -+preceded by a colon "':'". These specify a non-default format for the -+replacement value. -+ -+See also the Format Specification Mini-Language section. -+ -+The *field_name* itself begins with an *arg_name* that is either a -+number or a keyword. If it’s a number, it refers to a positional -+argument, and if it’s a keyword, it refers to a named keyword -+argument. An *arg_name* is treated as a number if a call to -+"str.isdecimal()" on the string would return true. If the numerical -+arg_names in a format string are 0, 1, 2, … in sequence, they can all -+be omitted (not just some) and the numbers 0, 1, 2, … will be -+automatically inserted in that order. Because *arg_name* is not quote- -+delimited, it is not possible to specify arbitrary dictionary keys -+(e.g., the strings "'10'" or "':-]'") within a format string. The -+*arg_name* can be followed by any number of index or attribute -+expressions. An expression of the form "'.name'" selects the named -+attribute using "getattr()", while an expression of the form -+"'[index]'" does an index lookup using "__getitem__()". -+ -+Changed in version 3.1: The positional argument specifiers can be -+omitted for "str.format()", so "'{} {}'.format(a, b)" is equivalent to -+"'{0} {1}'.format(a, b)". -+ -+Changed in version 3.4: The positional argument specifiers can be -+omitted for "Formatter". -+ -+Some simple format string examples: -+ -+ "First, thou shalt count to {0}" # References first positional argument -+ "Bring me a {}" # Implicitly references the first positional argument -+ "From {} to {}" # Same as "From {0} to {1}" -+ "My quest is {name}" # References keyword argument 'name' -+ "Weight in tons {0.weight}" # 'weight' attribute of first positional arg -+ "Units destroyed: {players[0]}" # First element of keyword argument 'players'. -+ -+The *conversion* field causes a type coercion before formatting. -+Normally, the job of formatting a value is done by the "__format__()" -+method of the value itself. However, in some cases it is desirable to -+force a type to be formatted as a string, overriding its own -+definition of formatting. By converting the value to a string before -+calling "__format__()", the normal formatting logic is bypassed. -+ -+Three conversion flags are currently supported: "'!s'" which calls -+"str()" on the value, "'!r'" which calls "repr()" and "'!a'" which -+calls "ascii()". -+ -+Some examples: -+ -+ "Harold's a clever {0!s}" # Calls str() on the argument first -+ "Bring out the holy {name!r}" # Calls repr() on the argument first -+ "More {!a}" # Calls ascii() on the argument first -+ -+The *format_spec* field contains a specification of how the value -+should be presented, including such details as field width, alignment, -+padding, decimal precision and so on. Each value type can define its -+own “formatting mini-language†or interpretation of the *format_spec*. -+ -+Most built-in types support a common formatting mini-language, which -+is described in the next section. -+ -+A *format_spec* field can also include nested replacement fields -+within it. These nested replacement fields may contain a field name, -+conversion flag and format specification, but deeper nesting is not -+allowed. The replacement fields within the format_spec are -+substituted before the *format_spec* string is interpreted. This -+allows the formatting of a value to be dynamically specified. -+ -+See the Format examples section for some examples. -+ -+ -+Format Specification Mini-Language -+================================== -+ -+“Format specifications†are used within replacement fields contained -+within a format string to define how individual values are presented -+(see Format String Syntax and f-strings). They can also be passed -+directly to the built-in "format()" function. Each formattable type -+may define how the format specification is to be interpreted. -+ -+Most built-in types implement the following options for format -+specifications, although some of the formatting options are only -+supported by the numeric types. -+ -+A general convention is that an empty format specification produces -+the same result as if you had called "str()" on the value. A non-empty -+format specification typically modifies the result. -+ -+The general form of a *standard format specifier* is: -+ -+ **format_spec**: [["fill"]"align"]["sign"]["z"]["#"]["0"]["width"]["grouping_option"]["." "precision"]["type"] -+ **fill**: -+ **align**: "<" | ">" | "=" | "^" -+ **sign**: "+" | "-" | " " -+ **width**: "digit"+ -+ **grouping_option**: "_" | "," -+ **precision**: "digit"+ -+ **type**: "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%" -+ -+If a valid *align* value is specified, it can be preceded by a *fill* -+character that can be any character and defaults to a space if -+omitted. It is not possible to use a literal curly brace (â€"{"†or -+“"}"â€) as the *fill* character in a formatted string literal or when -+using the "str.format()" method. However, it is possible to insert a -+curly brace with a nested replacement field. This limitation doesn’t -+affect the "format()" function. -+ -+The meaning of the various alignment options is as follows: -+ -++-----------+------------------------------------------------------------+ -+| Option | Meaning | -+|===========|============================================================| -+| "'<'" | Forces the field to be left-aligned within the available | -+| | space (this is the default for most objects). | -++-----------+------------------------------------------------------------+ -+| "'>'" | Forces the field to be right-aligned within the available | -+| | space (this is the default for numbers). | -++-----------+------------------------------------------------------------+ -+| "'='" | Forces the padding to be placed after the sign (if any) | -+| | but before the digits. This is used for printing fields | -+| | in the form ‘+000000120’. This alignment option is only | -+| | valid for numeric types, excluding "complex". It becomes | -+| | the default for numbers when ‘0’ immediately precedes the | -+| | field width. | -++-----------+------------------------------------------------------------+ -+| "'^'" | Forces the field to be centered within the available | -+| | space. | -++-----------+------------------------------------------------------------+ -+ -+Note that unless a minimum field width is defined, the field width -+will always be the same size as the data to fill it, so that the -+alignment option has no meaning in this case. -+ -+The *sign* option is only valid for number types, and can be one of -+the following: -+ -++-----------+------------------------------------------------------------+ -+| Option | Meaning | -+|===========|============================================================| -+| "'+'" | indicates that a sign should be used for both positive as | -+| | well as negative numbers. | -++-----------+------------------------------------------------------------+ -+| "'-'" | indicates that a sign should be used only for negative | -+| | numbers (this is the default behavior). | -++-----------+------------------------------------------------------------+ -+| space | indicates that a leading space should be used on positive | -+| | numbers, and a minus sign on negative numbers. | -++-----------+------------------------------------------------------------+ -+ -+The "'z'" option coerces negative zero floating-point values to -+positive zero after rounding to the format precision. This option is -+only valid for floating-point presentation types. -+ -+Changed in version 3.11: Added the "'z'" option (see also **PEP -+682**). -+ -+The "'#'" option causes the “alternate form†to be used for the -+conversion. The alternate form is defined differently for different -+types. This option is only valid for integer, float and complex -+types. For integers, when binary, octal, or hexadecimal output is -+used, this option adds the respective prefix "'0b'", "'0o'", "'0x'", -+or "'0X'" to the output value. For float and complex the alternate -+form causes the result of the conversion to always contain a decimal- -+point character, even if no digits follow it. Normally, a decimal- -+point character appears in the result of these conversions only if a -+digit follows it. In addition, for "'g'" and "'G'" conversions, -+trailing zeros are not removed from the result. -+ -+The "','" option signals the use of a comma for a thousands separator -+for floating-point presentation types and for integer presentation -+type "'d'". For other presentation types, this option is an error. For -+a locale aware separator, use the "'n'" integer presentation type -+instead. -+ -+Changed in version 3.1: Added the "','" option (see also **PEP 378**). -+ -+The "'_'" option signals the use of an underscore for a thousands -+separator for floating-point presentation types and for integer -+presentation type "'d'". For integer presentation types "'b'", "'o'", -+"'x'", and "'X'", underscores will be inserted every 4 digits. For -+other presentation types, specifying this option is an error. -+ -+Changed in version 3.6: Added the "'_'" option (see also **PEP 515**). -+ -+*width* is a decimal integer defining the minimum total field width, -+including any prefixes, separators, and other formatting characters. -+If not specified, then the field width will be determined by the -+content. -+ -+When no explicit alignment is given, preceding the *width* field by a -+zero ("'0'") character enables sign-aware zero-padding for numeric -+types, excluding "complex". This is equivalent to a *fill* character -+of "'0'" with an *alignment* type of "'='". -+ -+Changed in version 3.10: Preceding the *width* field by "'0'" no -+longer affects the default alignment for strings. -+ -+The *precision* is a decimal integer indicating how many digits should -+be displayed after the decimal point for presentation types "'f'" and -+"'F'", or before and after the decimal point for presentation types -+"'g'" or "'G'". For string presentation types the field indicates the -+maximum field size - in other words, how many characters will be used -+from the field content. The *precision* is not allowed for integer -+presentation types. -+ -+Finally, the *type* determines how the data should be presented. -+ -+The available string presentation types are: -+ -+ +-----------+------------------------------------------------------------+ -+ | Type | Meaning | -+ |===========|============================================================| -+ | "'s'" | String format. This is the default type for strings and | -+ | | may be omitted. | -+ +-----------+------------------------------------------------------------+ -+ | None | The same as "'s'". | -+ +-----------+------------------------------------------------------------+ -+ -+The available integer presentation types are: -+ -+ +-----------+------------------------------------------------------------+ -+ | Type | Meaning | -+ |===========|============================================================| -+ | "'b'" | Binary format. Outputs the number in base 2. | -+ +-----------+------------------------------------------------------------+ -+ | "'c'" | Character. Converts the integer to the corresponding | -+ | | unicode character before printing. | -+ +-----------+------------------------------------------------------------+ -+ | "'d'" | Decimal Integer. Outputs the number in base 10. | -+ +-----------+------------------------------------------------------------+ -+ | "'o'" | Octal format. Outputs the number in base 8. | -+ +-----------+------------------------------------------------------------+ -+ | "'x'" | Hex format. Outputs the number in base 16, using lower- | -+ | | case letters for the digits above 9. | -+ +-----------+------------------------------------------------------------+ -+ | "'X'" | Hex format. Outputs the number in base 16, using upper- | -+ | | case letters for the digits above 9. In case "'#'" is | -+ | | specified, the prefix "'0x'" will be upper-cased to "'0X'" | -+ | | as well. | -+ +-----------+------------------------------------------------------------+ -+ | "'n'" | Number. This is the same as "'d'", except that it uses the | -+ | | current locale setting to insert the appropriate number | -+ | | separator characters. | -+ +-----------+------------------------------------------------------------+ -+ | None | The same as "'d'". | -+ +-----------+------------------------------------------------------------+ -+ -+In addition to the above presentation types, integers can be formatted -+with the floating-point presentation types listed below (except "'n'" -+and "None"). When doing so, "float()" is used to convert the integer -+to a floating-point number before formatting. -+ -+The available presentation types for "float" and "Decimal" values are: -+ -+ +-----------+------------------------------------------------------------+ -+ | Type | Meaning | -+ |===========|============================================================| -+ | "'e'" | Scientific notation. For a given precision "p", formats | -+ | | the number in scientific notation with the letter ‘e’ | -+ | | separating the coefficient from the exponent. The | -+ | | coefficient has one digit before and "p" digits after the | -+ | | decimal point, for a total of "p + 1" significant digits. | -+ | | With no precision given, uses a precision of "6" digits | -+ | | after the decimal point for "float", and shows all | -+ | | coefficient digits for "Decimal". If "p=0", the decimal | -+ | | point is omitted unless the "#" option is used. | -+ +-----------+------------------------------------------------------------+ -+ | "'E'" | Scientific notation. Same as "'e'" except it uses an upper | -+ | | case ‘E’ as the separator character. | -+ +-----------+------------------------------------------------------------+ -+ | "'f'" | Fixed-point notation. For a given precision "p", formats | -+ | | the number as a decimal number with exactly "p" digits | -+ | | following the decimal point. With no precision given, uses | -+ | | a precision of "6" digits after the decimal point for | -+ | | "float", and uses a precision large enough to show all | -+ | | coefficient digits for "Decimal". If "p=0", the decimal | -+ | | point is omitted unless the "#" option is used. | -+ +-----------+------------------------------------------------------------+ -+ | "'F'" | Fixed-point notation. Same as "'f'", but converts "nan" to | -+ | | "NAN" and "inf" to "INF". | -+ +-----------+------------------------------------------------------------+ -+ | "'g'" | General format. For a given precision "p >= 1", this | -+ | | rounds the number to "p" significant digits and then | -+ | | formats the result in either fixed-point format or in | -+ | | scientific notation, depending on its magnitude. A | -+ | | precision of "0" is treated as equivalent to a precision | -+ | | of "1". The precise rules are as follows: suppose that | -+ | | the result formatted with presentation type "'e'" and | -+ | | precision "p-1" would have exponent "exp". Then, if "m <= | -+ | | exp < p", where "m" is -4 for floats and -6 for | -+ | | "Decimals", the number is formatted with presentation type | -+ | | "'f'" and precision "p-1-exp". Otherwise, the number is | -+ | | formatted with presentation type "'e'" and precision | -+ | | "p-1". In both cases insignificant trailing zeros are | -+ | | removed from the significand, and the decimal point is | -+ | | also removed if there are no remaining digits following | -+ | | it, unless the "'#'" option is used. With no precision | -+ | | given, uses a precision of "6" significant digits for | -+ | | "float". For "Decimal", the coefficient of the result is | -+ | | formed from the coefficient digits of the value; | -+ | | scientific notation is used for values smaller than "1e-6" | -+ | | in absolute value and values where the place value of the | -+ | | least significant digit is larger than 1, and fixed-point | -+ | | notation is used otherwise. Positive and negative | -+ | | infinity, positive and negative zero, and nans, are | -+ | | formatted as "inf", "-inf", "0", "-0" and "nan" | -+ | | respectively, regardless of the precision. | -+ +-----------+------------------------------------------------------------+ -+ | "'G'" | General format. Same as "'g'" except switches to "'E'" if | -+ | | the number gets too large. The representations of infinity | -+ | | and NaN are uppercased, too. | -+ +-----------+------------------------------------------------------------+ -+ | "'n'" | Number. This is the same as "'g'", except that it uses the | -+ | | current locale setting to insert the appropriate number | -+ | | separator characters. | -+ +-----------+------------------------------------------------------------+ -+ | "'%'" | Percentage. Multiplies the number by 100 and displays in | -+ | | fixed ("'f'") format, followed by a percent sign. | -+ +-----------+------------------------------------------------------------+ -+ | None | For "float" this is like the "'g'" type, except that when | -+ | | fixed- point notation is used to format the result, it | -+ | | always includes at least one digit past the decimal point, | -+ | | and switches to the scientific notation when "exp >= p - | -+ | | 1". When the precision is not specified, the latter will | -+ | | be as large as needed to represent the given value | -+ | | faithfully. For "Decimal", this is the same as either | -+ | | "'g'" or "'G'" depending on the value of | -+ | | "context.capitals" for the current decimal context. The | -+ | | overall effect is to match the output of "str()" as | -+ | | altered by the other format modifiers. | -+ +-----------+------------------------------------------------------------+ -+ -+The result should be correctly rounded to a given precision "p" of -+digits after the decimal point. The rounding mode for "float" matches -+that of the "round()" builtin. For "Decimal", the rounding mode of -+the current context will be used. -+ -+The available presentation types for "complex" are the same as those -+for "float" ("'%'" is not allowed). Both the real and imaginary -+components of a complex number are formatted as floating-point -+numbers, according to the specified presentation type. They are -+separated by the mandatory sign of the imaginary part, the latter -+being terminated by a "j" suffix. If the presentation type is -+missing, the result will match the output of "str()" (complex numbers -+with a non-zero real part are also surrounded by parentheses), -+possibly altered by other format modifiers. -+ -+ -+Format examples -+=============== -+ -+This section contains examples of the "str.format()" syntax and -+comparison with the old "%"-formatting. -+ -+In most of the cases the syntax is similar to the old "%"-formatting, -+with the addition of the "{}" and with ":" used instead of "%". For -+example, "'%03.2f'" can be translated to "'{:03.2f}'". -+ -+The new format syntax also supports new and different options, shown -+in the following examples. -+ -+Accessing arguments by position: -+ -+ >>> '{0}, {1}, {2}'.format('a', 'b', 'c') -+ 'a, b, c' -+ >>> '{}, {}, {}'.format('a', 'b', 'c') # 3.1+ only -+ 'a, b, c' -+ >>> '{2}, {1}, {0}'.format('a', 'b', 'c') -+ 'c, b, a' -+ >>> '{2}, {1}, {0}'.format(*'abc') # unpacking argument sequence -+ 'c, b, a' -+ >>> '{0}{1}{0}'.format('abra', 'cad') # arguments' indices can be repeated -+ 'abracadabra' -+ -+Accessing arguments by name: -+ -+ >>> 'Coordinates: {latitude}, {longitude}'.format(latitude='37.24N', longitude='-115.81W') -+ 'Coordinates: 37.24N, -115.81W' -+ >>> coord = {'latitude': '37.24N', 'longitude': '-115.81W'} -+ >>> 'Coordinates: {latitude}, {longitude}'.format(**coord) -+ 'Coordinates: 37.24N, -115.81W' -+ -+Accessing arguments’ attributes: -+ -+ >>> c = 3-5j -+ >>> ('The complex number {0} is formed from the real part {0.real} ' -+ ... 'and the imaginary part {0.imag}.').format(c) -+ 'The complex number (3-5j) is formed from the real part 3.0 and the imaginary part -5.0.' -+ >>> class Point: -+ ... def __init__(self, x, y): -+ ... self.x, self.y = x, y -+ ... def __str__(self): -+ ... return 'Point({self.x}, {self.y})'.format(self=self) -+ ... -+ >>> str(Point(4, 2)) -+ 'Point(4, 2)' -+ -+Accessing arguments’ items: -+ -+ >>> coord = (3, 5) -+ >>> 'X: {0[0]}; Y: {0[1]}'.format(coord) -+ 'X: 3; Y: 5' -+ -+Replacing "%s" and "%r": -+ -+ >>> "repr() shows quotes: {!r}; str() doesn't: {!s}".format('test1', 'test2') -+ "repr() shows quotes: 'test1'; str() doesn't: test2" -+ -+Aligning the text and specifying a width: -+ -+ >>> '{:<30}'.format('left aligned') -+ 'left aligned ' -+ >>> '{:>30}'.format('right aligned') -+ ' right aligned' -+ >>> '{:^30}'.format('centered') -+ ' centered ' -+ >>> '{:*^30}'.format('centered') # use '*' as a fill char -+ '***********centered***********' -+ -+Replacing "%+f", "%-f", and "% f" and specifying a sign: -+ -+ >>> '{:+f}; {:+f}'.format(3.14, -3.14) # show it always -+ '+3.140000; -3.140000' -+ >>> '{: f}; {: f}'.format(3.14, -3.14) # show a space for positive numbers -+ ' 3.140000; -3.140000' -+ >>> '{:-f}; {:-f}'.format(3.14, -3.14) # show only the minus -- same as '{:f}; {:f}' -+ '3.140000; -3.140000' -+ -+Replacing "%x" and "%o" and converting the value to different bases: -+ -+ >>> # format also supports binary numbers -+ >>> "int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}".format(42) -+ 'int: 42; hex: 2a; oct: 52; bin: 101010' -+ >>> # with 0x, 0o, or 0b as prefix: -+ >>> "int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}".format(42) -+ 'int: 42; hex: 0x2a; oct: 0o52; bin: 0b101010' -+ -+Using the comma as a thousands separator: -+ -+ >>> '{:,}'.format(1234567890) -+ '1,234,567,890' -+ -+Expressing a percentage: -+ -+ >>> points = 19 -+ >>> total = 22 -+ >>> 'Correct answers: {:.2%}'.format(points/total) -+ 'Correct answers: 86.36%' -+ -+Using type-specific formatting: -+ -+ >>> import datetime -+ >>> d = datetime.datetime(2010, 7, 4, 12, 15, 58) -+ >>> '{:%Y-%m-%d %H:%M:%S}'.format(d) -+ '2010-07-04 12:15:58' -+ -+Nesting arguments and more complex examples: -+ -+ >>> for align, text in zip('<^>', ['left', 'center', 'right']): -+ ... '{0:{fill}{align}16}'.format(text, fill=align, align=align) -+ ... -+ 'left<<<<<<<<<<<<' -+ '^^^^^center^^^^^' -+ '>>>>>>>>>>>right' -+ >>> -+ >>> octets = [192, 168, 0, 1] -+ >>> '{:02X}{:02X}{:02X}{:02X}'.format(*octets) -+ 'C0A80001' -+ >>> int(_, 16) -+ 3232235521 -+ >>> -+ >>> width = 5 -+ >>> for num in range(5,12): -+ ... for base in 'dXob': -+ ... print('{0:{width}{base}}'.format(num, base=base, width=width), end=' ') -+ ... print() -+ ... -+ 5 5 5 101 -+ 6 6 6 110 -+ 7 7 7 111 -+ 8 8 10 1000 -+ 9 9 11 1001 -+ 10 A 12 1010 -+ 11 B 13 1011 -+''', -+ 'function': r'''Function definitions -+******************** -+ -+A function definition defines a user-defined function object (see -+section The standard type hierarchy): -+ -+ **funcdef**: ["decorators"] "def" "funcname" ["type_params"] "(" ["parameter_list"] ")" -+ ["->" "expression"] ":" "suite" -+ **decorators**: "decorator"+ -+ **decorator**: "@" "assignment_expression" NEWLINE -+ **parameter_list**: "defparameter" ("," "defparameter")* "," "/" ["," ["parameter_list_no_posonly"]] -+ | "parameter_list_no_posonly" -+ **parameter_list_no_posonly**: "defparameter" ("," "defparameter")* ["," ["parameter_list_starargs"]] -+ | "parameter_list_starargs" -+ **parameter_list_starargs**: "*" ["star_parameter"] ("," "defparameter")* ["," ["parameter_star_kwargs"]] -+ "*" ("," "defparameter")+ ["," ["parameter_star_kwargs"]] -+ | "parameter_star_kwargs" -+ **parameter_star_kwargs**: "**" "parameter" [","] -+ **parameter**: "identifier" [":" "expression"] -+ **star_parameter**: "identifier" [":" ["*"] "expression"] -+ **defparameter**: "parameter" ["=" "expression"] -+ **funcname**: "identifier" -+ -+A function definition is an executable statement. Its execution binds -+the function name in the current local namespace to a function object -+(a wrapper around the executable code for the function). This -+function object contains a reference to the current global namespace -+as the global namespace to be used when the function is called. -+ -+The function definition does not execute the function body; this gets -+executed only when the function is called. [4] -+ -+A function definition may be wrapped by one or more *decorator* -+expressions. Decorator expressions are evaluated when the function is -+defined, in the scope that contains the function definition. The -+result must be a callable, which is invoked with the function object -+as the only argument. The returned value is bound to the function name -+instead of the function object. Multiple decorators are applied in -+nested fashion. For example, the following code -+ -+ @f1(arg) -+ @f2 -+ def func(): pass -+ -+is roughly equivalent to -+ -+ def func(): pass -+ func = f1(arg)(f2(func)) -+ -+except that the original function is not temporarily bound to the name -+"func". -+ -+Changed in version 3.9: Functions may be decorated with any valid -+"assignment_expression". Previously, the grammar was much more -+restrictive; see **PEP 614** for details. -+ -+A list of type parameters may be given in square brackets between the -+function’s name and the opening parenthesis for its parameter list. -+This indicates to static type checkers that the function is generic. -+At runtime, the type parameters can be retrieved from the function’s -+"__type_params__" attribute. See Generic functions for more. -+ -+Changed in version 3.12: Type parameter lists are new in Python 3.12. -+ -+When one or more *parameters* have the form *parameter* "=" -+*expression*, the function is said to have “default parameter values.†-+For a parameter with a default value, the corresponding *argument* may -+be omitted from a call, in which case the parameter’s default value is -+substituted. If a parameter has a default value, all following -+parameters up until the “"*"†must also have a default value — this is -+a syntactic restriction that is not expressed by the grammar. -+ -+**Default parameter values are evaluated from left to right when the -+function definition is executed.** This means that the expression is -+evaluated once, when the function is defined, and that the same “pre- -+computed†value is used for each call. This is especially important -+to understand when a default parameter value is a mutable object, such -+as a list or a dictionary: if the function modifies the object (e.g. -+by appending an item to a list), the default parameter value is in -+effect modified. This is generally not what was intended. A way -+around this is to use "None" as the default, and explicitly test for -+it in the body of the function, e.g.: -+ -+ def whats_on_the_telly(penguin=None): -+ if penguin is None: -+ penguin = [] -+ penguin.append("property of the zoo") -+ return penguin -+ -+Function call semantics are described in more detail in section Calls. -+A function call always assigns values to all parameters mentioned in -+the parameter list, either from positional arguments, from keyword -+arguments, or from default values. If the form “"*identifier"†is -+present, it is initialized to a tuple receiving any excess positional -+parameters, defaulting to the empty tuple. If the form -+“"**identifier"†is present, it is initialized to a new ordered -+mapping receiving any excess keyword arguments, defaulting to a new -+empty mapping of the same type. Parameters after “"*"†or -+“"*identifier"†are keyword-only parameters and may only be passed by -+keyword arguments. Parameters before “"/"†are positional-only -+parameters and may only be passed by positional arguments. -+ -+Changed in version 3.8: The "/" function parameter syntax may be used -+to indicate positional-only parameters. See **PEP 570** for details. -+ -+Parameters may have an *annotation* of the form “": expression"†-+following the parameter name. Any parameter may have an annotation, -+even those of the form "*identifier" or "**identifier". (As a special -+case, parameters of the form "*identifier" may have an annotation “": -+*expression"â€.) Functions may have “return†annotation of the form -+“"-> expression"†after the parameter list. These annotations can be -+any valid Python expression. The presence of annotations does not -+change the semantics of a function. See Annotations for more -+information on annotations. -+ -+Changed in version 3.11: Parameters of the form “"*identifier"†may -+have an annotation “": *expression"â€. See **PEP 646**. -+ -+It is also possible to create anonymous functions (functions not bound -+to a name), for immediate use in expressions. This uses lambda -+expressions, described in section Lambdas. Note that the lambda -+expression is merely a shorthand for a simplified function definition; -+a function defined in a “"def"†statement can be passed around or -+assigned to another name just like a function defined by a lambda -+expression. The “"def"†form is actually more powerful since it -+allows the execution of multiple statements and annotations. -+ -+**Programmer’s note:** Functions are first-class objects. A “"def"†-+statement executed inside a function definition defines a local -+function that can be returned or passed around. Free variables used -+in the nested function can access the local variables of the function -+containing the def. See section Naming and binding for details. -+ -+See also: -+ -+ **PEP 3107** - Function Annotations -+ The original specification for function annotations. -+ -+ **PEP 484** - Type Hints -+ Definition of a standard meaning for annotations: type hints. -+ -+ **PEP 526** - Syntax for Variable Annotations -+ Ability to type hint variable declarations, including class -+ variables and instance variables. -+ -+ **PEP 563** - Postponed Evaluation of Annotations -+ Support for forward references within annotations by preserving -+ annotations in a string form at runtime instead of eager -+ evaluation. -+ -+ **PEP 318** - Decorators for Functions and Methods -+ Function and method decorators were introduced. Class decorators -+ were introduced in **PEP 3129**. -+''', -+ 'global': r'''The "global" statement -+********************** -+ -+ **global_stmt**: "global" "identifier" ("," "identifier")* -+ -+The "global" statement causes the listed identifiers to be interpreted -+as globals. It would be impossible to assign to a global variable -+without "global", although free variables may refer to globals without -+being declared global. -+ -+The "global" statement applies to the entire scope of a function or -+class body. A "SyntaxError" is raised if a variable is used or -+assigned to prior to its global declaration in the scope. -+ -+**Programmer’s note:** "global" is a directive to the parser. It -+applies only to code parsed at the same time as the "global" -+statement. In particular, a "global" statement contained in a string -+or code object supplied to the built-in "exec()" function does not -+affect the code block *containing* the function call, and code -+contained in such a string is unaffected by "global" statements in the -+code containing the function call. The same applies to the "eval()" -+and "compile()" functions. -+''', -+ 'id-classes': r'''Reserved classes of identifiers -+******************************* -+ -+Certain classes of identifiers (besides keywords) have special -+meanings. These classes are identified by the patterns of leading and -+trailing underscore characters: -+ -+"_*" -+ Not imported by "from module import *". -+ -+"_" -+ In a "case" pattern within a "match" statement, "_" is a soft -+ keyword that denotes a wildcard. -+ -+ Separately, the interactive interpreter makes the result of the -+ last evaluation available in the variable "_". (It is stored in the -+ "builtins" module, alongside built-in functions like "print".) -+ -+ Elsewhere, "_" is a regular identifier. It is often used to name -+ “special†items, but it is not special to Python itself. -+ -+ Note: -+ -+ The name "_" is often used in conjunction with -+ internationalization; refer to the documentation for the -+ "gettext" module for more information on this convention.It is -+ also commonly used for unused variables. -+ -+"__*__" -+ System-defined names, informally known as “dunder†names. These -+ names are defined by the interpreter and its implementation -+ (including the standard library). Current system names are -+ discussed in the Special method names section and elsewhere. More -+ will likely be defined in future versions of Python. *Any* use of -+ "__*__" names, in any context, that does not follow explicitly -+ documented use, is subject to breakage without warning. -+ -+"__*" -+ Class-private names. Names in this category, when used within the -+ context of a class definition, are re-written to use a mangled form -+ to help avoid name clashes between “private†attributes of base and -+ derived classes. See section Identifiers (Names). -+''', -+ 'identifiers': r'''Identifiers and keywords -+************************ -+ -+Identifiers (also referred to as *names*) are described by the -+following lexical definitions. -+ -+The syntax of identifiers in Python is based on the Unicode standard -+annex UAX-31, with elaboration and changes as defined below; see also -+**PEP 3131** for further details. -+ -+Within the ASCII range (U+0001..U+007F), the valid characters for -+identifiers include the uppercase and lowercase letters "A" through -+"Z", the underscore "_" and, except for the first character, the -+digits "0" through "9". Python 3.0 introduced additional characters -+from outside the ASCII range (see **PEP 3131**). For these -+characters, the classification uses the version of the Unicode -+Character Database as included in the "unicodedata" module. -+ -+Identifiers are unlimited in length. Case is significant. -+ -+ **identifier**: "xid_start" "xid_continue"* -+ **id_start**: -+ **id_continue**: -+ **xid_start**: -+ **xid_continue**: -+ -+The Unicode category codes mentioned above stand for: -+ -+* *Lu* - uppercase letters -+ -+* *Ll* - lowercase letters -+ -+* *Lt* - titlecase letters -+ -+* *Lm* - modifier letters -+ -+* *Lo* - other letters -+ -+* *Nl* - letter numbers -+ -+* *Mn* - nonspacing marks -+ -+* *Mc* - spacing combining marks -+ -+* *Nd* - decimal numbers -+ -+* *Pc* - connector punctuations -+ -+* *Other_ID_Start* - explicit list of characters in PropList.txt to -+ support backwards compatibility -+ -+* *Other_ID_Continue* - likewise -+ -+All identifiers are converted into the normal form NFKC while parsing; -+comparison of identifiers is based on NFKC. -+ -+A non-normative HTML file listing all valid identifier characters for -+Unicode 16.0.0 can be found at -+https://www.unicode.org/Public/16.0.0/ucd/DerivedCoreProperties.txt -+ -+ -+Keywords -+======== -+ -+The following identifiers are used as reserved words, or *keywords* of -+the language, and cannot be used as ordinary identifiers. They must -+be spelled exactly as written here: -+ -+ False await else import pass -+ None break except in raise -+ True class finally is return -+ and continue for lambda try -+ as def from nonlocal while -+ assert del global not with -+ async elif if or yield -+ -+ -+Soft Keywords -+============= -+ -+Added in version 3.10. -+ -+Some identifiers are only reserved under specific contexts. These are -+known as *soft keywords*. The identifiers "match", "case", "type" and -+"_" can syntactically act as keywords in certain contexts, but this -+distinction is done at the parser level, not when tokenizing. -+ -+As soft keywords, their use in the grammar is possible while still -+preserving compatibility with existing code that uses these names as -+identifier names. -+ -+"match", "case", and "_" are used in the "match" statement. "type" is -+used in the "type" statement. -+ -+Changed in version 3.12: "type" is now a soft keyword. -+ -+ -+Reserved classes of identifiers -+=============================== -+ -+Certain classes of identifiers (besides keywords) have special -+meanings. These classes are identified by the patterns of leading and -+trailing underscore characters: -+ -+"_*" -+ Not imported by "from module import *". -+ -+"_" -+ In a "case" pattern within a "match" statement, "_" is a soft -+ keyword that denotes a wildcard. -+ -+ Separately, the interactive interpreter makes the result of the -+ last evaluation available in the variable "_". (It is stored in the -+ "builtins" module, alongside built-in functions like "print".) -+ -+ Elsewhere, "_" is a regular identifier. It is often used to name -+ “special†items, but it is not special to Python itself. -+ -+ Note: -+ -+ The name "_" is often used in conjunction with -+ internationalization; refer to the documentation for the -+ "gettext" module for more information on this convention.It is -+ also commonly used for unused variables. -+ -+"__*__" -+ System-defined names, informally known as “dunder†names. These -+ names are defined by the interpreter and its implementation -+ (including the standard library). Current system names are -+ discussed in the Special method names section and elsewhere. More -+ will likely be defined in future versions of Python. *Any* use of -+ "__*__" names, in any context, that does not follow explicitly -+ documented use, is subject to breakage without warning. -+ -+"__*" -+ Class-private names. Names in this category, when used within the -+ context of a class definition, are re-written to use a mangled form -+ to help avoid name clashes between “private†attributes of base and -+ derived classes. See section Identifiers (Names). -+''', -+ 'if': r'''The "if" statement -+****************** -+ -+The "if" statement is used for conditional execution: -+ -+ **if_stmt**: "if" "assignment_expression" ":" "suite" -+ ("elif" "assignment_expression" ":" "suite")* -+ ["else" ":" "suite"] -+ -+It selects exactly one of the suites by evaluating the expressions one -+by one until one is found to be true (see section Boolean operations -+for the definition of true and false); then that suite is executed -+(and no other part of the "if" statement is executed or evaluated). -+If all expressions are false, the suite of the "else" clause, if -+present, is executed. -+''', -+ 'imaginary': r'''Imaginary literals -+****************** -+ -+Imaginary literals are described by the following lexical definitions: -+ -+ **imagnumber**: ("floatnumber" | "digitpart") ("j" | "J") -+ -+An imaginary literal yields a complex number with a real part of 0.0. -+Complex numbers are represented as a pair of floating-point numbers -+and have the same restrictions on their range. To create a complex -+number with a nonzero real part, add a floating-point number to it, -+e.g., "(3+4j)". Some examples of imaginary literals: -+ -+ 3.14j 10.j 10j .001j 1e100j 3.14e-10j 3.14_15_93j -+''', -+ 'import': r'''The "import" statement -+********************** -+ -+ **import_stmt**: "import" "module" ["as" "identifier"] ("," "module" ["as" "identifier"])* -+ | "from" "relative_module" "import" "identifier" ["as" "identifier"] -+ ("," "identifier" ["as" "identifier"])* -+ | "from" "relative_module" "import" "(" "identifier" ["as" "identifier"] -+ ("," "identifier" ["as" "identifier"])* [","] ")" -+ | "from" "relative_module" "import" "*" -+ **module**: ("identifier" ".")* "identifier" -+ **relative_module**: "."* "module" | "."+ -+ -+The basic import statement (no "from" clause) is executed in two -+steps: -+ -+1. find a module, loading and initializing it if necessary -+ -+2. define a name or names in the local namespace for the scope where -+ the "import" statement occurs. -+ -+When the statement contains multiple clauses (separated by commas) the -+two steps are carried out separately for each clause, just as though -+the clauses had been separated out into individual import statements. -+ -+The details of the first step, finding and loading modules, are -+described in greater detail in the section on the import system, which -+also describes the various types of packages and modules that can be -+imported, as well as all the hooks that can be used to customize the -+import system. Note that failures in this step may indicate either -+that the module could not be located, *or* that an error occurred -+while initializing the module, which includes execution of the -+module’s code. -+ -+If the requested module is retrieved successfully, it will be made -+available in the local namespace in one of three ways: -+ -+* If the module name is followed by "as", then the name following "as" -+ is bound directly to the imported module. -+ -+* If no other name is specified, and the module being imported is a -+ top level module, the module’s name is bound in the local namespace -+ as a reference to the imported module -+ -+* If the module being imported is *not* a top level module, then the -+ name of the top level package that contains the module is bound in -+ the local namespace as a reference to the top level package. The -+ imported module must be accessed using its full qualified name -+ rather than directly -+ -+The "from" form uses a slightly more complex process: -+ -+1. find the module specified in the "from" clause, loading and -+ initializing it if necessary; -+ -+2. for each of the identifiers specified in the "import" clauses: -+ -+ 1. check if the imported module has an attribute by that name -+ -+ 2. if not, attempt to import a submodule with that name and then -+ check the imported module again for that attribute -+ -+ 3. if the attribute is not found, "ImportError" is raised. -+ -+ 4. otherwise, a reference to that value is stored in the local -+ namespace, using the name in the "as" clause if it is present, -+ otherwise using the attribute name -+ -+Examples: -+ -+ import foo # foo imported and bound locally -+ import foo.bar.baz # foo, foo.bar, and foo.bar.baz imported, foo bound locally -+ import foo.bar.baz as fbb # foo, foo.bar, and foo.bar.baz imported, foo.bar.baz bound as fbb -+ from foo.bar import baz # foo, foo.bar, and foo.bar.baz imported, foo.bar.baz bound as baz -+ from foo import attr # foo imported and foo.attr bound as attr -+ -+If the list of identifiers is replaced by a star ("'*'"), all public -+names defined in the module are bound in the local namespace for the -+scope where the "import" statement occurs. -+ -+The *public names* defined by a module are determined by checking the -+module’s namespace for a variable named "__all__"; if defined, it must -+be a sequence of strings which are names defined or imported by that -+module. The names given in "__all__" are all considered public and -+are required to exist. If "__all__" is not defined, the set of public -+names includes all names found in the module’s namespace which do not -+begin with an underscore character ("'_'"). "__all__" should contain -+the entire public API. It is intended to avoid accidentally exporting -+items that are not part of the API (such as library modules which were -+imported and used within the module). -+ -+The wild card form of import — "from module import *" — is only -+allowed at the module level. Attempting to use it in class or -+function definitions will raise a "SyntaxError". -+ -+When specifying what module to import you do not have to specify the -+absolute name of the module. When a module or package is contained -+within another package it is possible to make a relative import within -+the same top package without having to mention the package name. By -+using leading dots in the specified module or package after "from" you -+can specify how high to traverse up the current package hierarchy -+without specifying exact names. One leading dot means the current -+package where the module making the import exists. Two dots means up -+one package level. Three dots is up two levels, etc. So if you execute -+"from . import mod" from a module in the "pkg" package then you will -+end up importing "pkg.mod". If you execute "from ..subpkg2 import mod" -+from within "pkg.subpkg1" you will import "pkg.subpkg2.mod". The -+specification for relative imports is contained in the Package -+Relative Imports section. -+ -+"importlib.import_module()" is provided to support applications that -+determine dynamically the modules to be loaded. -+ -+Raises an auditing event "import" with arguments "module", "filename", -+"sys.path", "sys.meta_path", "sys.path_hooks". -+ -+ -+Future statements -+================= -+ -+A *future statement* is a directive to the compiler that a particular -+module should be compiled using syntax or semantics that will be -+available in a specified future release of Python where the feature -+becomes standard. -+ -+The future statement is intended to ease migration to future versions -+of Python that introduce incompatible changes to the language. It -+allows use of the new features on a per-module basis before the -+release in which the feature becomes standard. -+ -+ **future_stmt**: "from" "__future__" "import" "feature" ["as" "identifier"] -+ ("," "feature" ["as" "identifier"])* -+ | "from" "__future__" "import" "(" "feature" ["as" "identifier"] -+ ("," "feature" ["as" "identifier"])* [","] ")" -+ **feature**: "identifier" -+ -+A future statement must appear near the top of the module. The only -+lines that can appear before a future statement are: -+ -+* the module docstring (if any), -+ -+* comments, -+ -+* blank lines, and -+ -+* other future statements. -+ -+The only feature that requires using the future statement is -+"annotations" (see **PEP 563**). -+ -+All historical features enabled by the future statement are still -+recognized by Python 3. The list includes "absolute_import", -+"division", "generators", "generator_stop", "unicode_literals", -+"print_function", "nested_scopes" and "with_statement". They are all -+redundant because they are always enabled, and only kept for backwards -+compatibility. -+ -+A future statement is recognized and treated specially at compile -+time: Changes to the semantics of core constructs are often -+implemented by generating different code. It may even be the case -+that a new feature introduces new incompatible syntax (such as a new -+reserved word), in which case the compiler may need to parse the -+module differently. Such decisions cannot be pushed off until -+runtime. -+ -+For any given release, the compiler knows which feature names have -+been defined, and raises a compile-time error if a future statement -+contains a feature not known to it. -+ -+The direct runtime semantics are the same as for any import statement: -+there is a standard module "__future__", described later, and it will -+be imported in the usual way at the time the future statement is -+executed. -+ -+The interesting runtime semantics depend on the specific feature -+enabled by the future statement. -+ -+Note that there is nothing special about the statement: -+ -+ import __future__ [as name] -+ -+That is not a future statement; it’s an ordinary import statement with -+no special semantics or syntax restrictions. -+ -+Code compiled by calls to the built-in functions "exec()" and -+"compile()" that occur in a module "M" containing a future statement -+will, by default, use the new syntax or semantics associated with the -+future statement. This can be controlled by optional arguments to -+"compile()" — see the documentation of that function for details. -+ -+A future statement typed at an interactive interpreter prompt will -+take effect for the rest of the interpreter session. If an -+interpreter is started with the "-i" option, is passed a script name -+to execute, and the script includes a future statement, it will be in -+effect in the interactive session started after the script is -+executed. -+ -+See also: -+ -+ **PEP 236** - Back to the __future__ -+ The original proposal for the __future__ mechanism. -+''', -+ 'in': r'''Membership test operations -+************************** -+ -+The operators "in" and "not in" test for membership. "x in s" -+evaluates to "True" if *x* is a member of *s*, and "False" otherwise. -+"x not in s" returns the negation of "x in s". All built-in sequences -+and set types support this as well as dictionary, for which "in" tests -+whether the dictionary has a given key. For container types such as -+list, tuple, set, frozenset, dict, or collections.deque, the -+expression "x in y" is equivalent to "any(x is e or x == e for e in -+y)". -+ -+For the string and bytes types, "x in y" is "True" if and only if *x* -+is a substring of *y*. An equivalent test is "y.find(x) != -1". -+Empty strings are always considered to be a substring of any other -+string, so """ in "abc"" will return "True". -+ -+For user-defined classes which define the "__contains__()" method, "x -+in y" returns "True" if "y.__contains__(x)" returns a true value, and -+"False" otherwise. -+ -+For user-defined classes which do not define "__contains__()" but do -+define "__iter__()", "x in y" is "True" if some value "z", for which -+the expression "x is z or x == z" is true, is produced while iterating -+over "y". If an exception is raised during the iteration, it is as if -+"in" raised that exception. -+ -+Lastly, the old-style iteration protocol is tried: if a class defines -+"__getitem__()", "x in y" is "True" if and only if there is a non- -+negative integer index *i* such that "x is y[i] or x == y[i]", and no -+lower integer index raises the "IndexError" exception. (If any other -+exception is raised, it is as if "in" raised that exception). -+ -+The operator "not in" is defined to have the inverse truth value of -+"in". -+''', -+ 'integers': r'''Integer literals -+**************** -+ -+Integer literals are described by the following lexical definitions: -+ -+ **integer**: "decinteger" | "bininteger" | "octinteger" | "hexinteger" -+ **decinteger**: "nonzerodigit" (["_"] "digit")* | "0"+ (["_"] "0")* -+ **bininteger**: "0" ("b" | "B") (["_"] "bindigit")+ -+ **octinteger**: "0" ("o" | "O") (["_"] "octdigit")+ -+ **hexinteger**: "0" ("x" | "X") (["_"] "hexdigit")+ -+ **nonzerodigit**: "1"..."9" -+ **digit**: "0"..."9" -+ **bindigit**: "0" | "1" -+ **octdigit**: "0"..."7" -+ **hexdigit**: "digit" | "a"..."f" | "A"..."F" -+ -+There is no limit for the length of integer literals apart from what -+can be stored in available memory. -+ -+Underscores are ignored for determining the numeric value of the -+literal. They can be used to group digits for enhanced readability. -+One underscore can occur between digits, and after base specifiers -+like "0x". -+ -+Note that leading zeros in a non-zero decimal number are not allowed. -+This is for disambiguation with C-style octal literals, which Python -+used before version 3.0. -+ -+Some examples of integer literals: -+ -+ 7 2147483647 0o177 0b100110111 -+ 3 79228162514264337593543950336 0o377 0xdeadbeef -+ 100_000_000_000 0b_1110_0101 -+ -+Changed in version 3.6: Underscores are now allowed for grouping -+purposes in literals. -+''', -+ 'lambda': r'''Lambdas -+******* -+ -+ **lambda_expr**: "lambda" ["parameter_list"] ":" "expression" -+ -+Lambda expressions (sometimes called lambda forms) are used to create -+anonymous functions. The expression "lambda parameters: expression" -+yields a function object. The unnamed object behaves like a function -+object defined with: -+ -+ def (parameters): -+ return expression -+ -+See section Function definitions for the syntax of parameter lists. -+Note that functions created with lambda expressions cannot contain -+statements or annotations. -+''', -+ 'lists': r'''List displays -+************* -+ -+A list display is a possibly empty series of expressions enclosed in -+square brackets: -+ -+ **list_display**: "[" ["flexible_expression_list" | "comprehension"] "]" -+ -+A list display yields a new list object, the contents being specified -+by either a list of expressions or a comprehension. When a comma- -+separated list of expressions is supplied, its elements are evaluated -+from left to right and placed into the list object in that order. -+When a comprehension is supplied, the list is constructed from the -+elements resulting from the comprehension. -+''', -+ 'naming': r'''Naming and binding -+****************** -+ -+ -+Binding of names -+================ -+ -+*Names* refer to objects. Names are introduced by name binding -+operations. -+ -+The following constructs bind names: -+ -+* formal parameters to functions, -+ -+* class definitions, -+ -+* function definitions, -+ -+* assignment expressions, -+ -+* targets that are identifiers if occurring in an assignment: -+ -+ * "for" loop header, -+ -+ * after "as" in a "with" statement, "except" clause, "except*" -+ clause, or in the as-pattern in structural pattern matching, -+ -+ * in a capture pattern in structural pattern matching -+ -+* "import" statements. -+ -+* "type" statements. -+ -+* type parameter lists. -+ -+The "import" statement of the form "from ... import *" binds all names -+defined in the imported module, except those beginning with an -+underscore. This form may only be used at the module level. -+ -+A target occurring in a "del" statement is also considered bound for -+this purpose (though the actual semantics are to unbind the name). -+ -+Each assignment or import statement occurs within a block defined by a -+class or function definition or at the module level (the top-level -+code block). -+ -+If a name is bound in a block, it is a local variable of that block, -+unless declared as "nonlocal" or "global". If a name is bound at the -+module level, it is a global variable. (The variables of the module -+code block are local and global.) If a variable is used in a code -+block but not defined there, it is a *free variable*. -+ -+Each occurrence of a name in the program text refers to the *binding* -+of that name established by the following name resolution rules. -+ -+ -+Resolution of names -+=================== -+ -+A *scope* defines the visibility of a name within a block. If a local -+variable is defined in a block, its scope includes that block. If the -+definition occurs in a function block, the scope extends to any blocks -+contained within the defining one, unless a contained block introduces -+a different binding for the name. -+ -+When a name is used in a code block, it is resolved using the nearest -+enclosing scope. The set of all such scopes visible to a code block -+is called the block’s *environment*. -+ -+When a name is not found at all, a "NameError" exception is raised. If -+the current scope is a function scope, and the name refers to a local -+variable that has not yet been bound to a value at the point where the -+name is used, an "UnboundLocalError" exception is raised. -+"UnboundLocalError" is a subclass of "NameError". -+ -+If a name binding operation occurs anywhere within a code block, all -+uses of the name within the block are treated as references to the -+current block. This can lead to errors when a name is used within a -+block before it is bound. This rule is subtle. Python lacks -+declarations and allows name binding operations to occur anywhere -+within a code block. The local variables of a code block can be -+determined by scanning the entire text of the block for name binding -+operations. See the FAQ entry on UnboundLocalError for examples. -+ -+If the "global" statement occurs within a block, all uses of the names -+specified in the statement refer to the bindings of those names in the -+top-level namespace. Names are resolved in the top-level namespace by -+searching the global namespace, i.e. the namespace of the module -+containing the code block, and the builtins namespace, the namespace -+of the module "builtins". The global namespace is searched first. If -+the names are not found there, the builtins namespace is searched -+next. If the names are also not found in the builtins namespace, new -+variables are created in the global namespace. The global statement -+must precede all uses of the listed names. -+ -+The "global" statement has the same scope as a name binding operation -+in the same block. If the nearest enclosing scope for a free variable -+contains a global statement, the free variable is treated as a global. -+ -+The "nonlocal" statement causes corresponding names to refer to -+previously bound variables in the nearest enclosing function scope. -+"SyntaxError" is raised at compile time if the given name does not -+exist in any enclosing function scope. Type parameters cannot be -+rebound with the "nonlocal" statement. -+ -+The namespace for a module is automatically created the first time a -+module is imported. The main module for a script is always called -+"__main__". -+ -+Class definition blocks and arguments to "exec()" and "eval()" are -+special in the context of name resolution. A class definition is an -+executable statement that may use and define names. These references -+follow the normal rules for name resolution with an exception that -+unbound local variables are looked up in the global namespace. The -+namespace of the class definition becomes the attribute dictionary of -+the class. The scope of names defined in a class block is limited to -+the class block; it does not extend to the code blocks of methods. -+This includes comprehensions and generator expressions, but it does -+not include annotation scopes, which have access to their enclosing -+class scopes. This means that the following will fail: -+ -+ class A: -+ a = 42 -+ b = list(a + i for i in range(10)) -+ -+However, the following will succeed: -+ -+ class A: -+ type Alias = Nested -+ class Nested: pass -+ -+ print(A.Alias.__value__) # -+ -+ -+Annotation scopes -+================= -+ -+*Annotations*, type parameter lists and "type" statements introduce -+*annotation scopes*, which behave mostly like function scopes, but -+with some exceptions discussed below. -+ -+Annotation scopes are used in the following contexts: -+ -+* *Function annotations*. -+ -+* *Variable annotations*. -+ -+* Type parameter lists for generic type aliases. -+ -+* Type parameter lists for generic functions. A generic function’s -+ annotations are executed within the annotation scope, but its -+ defaults and decorators are not. -+ -+* Type parameter lists for generic classes. A generic class’s base -+ classes and keyword arguments are executed within the annotation -+ scope, but its decorators are not. -+ -+* The bounds, constraints, and default values for type parameters -+ (lazily evaluated). -+ -+* The value of type aliases (lazily evaluated). -+ -+Annotation scopes differ from function scopes in the following ways: -+ -+* Annotation scopes have access to their enclosing class namespace. If -+ an annotation scope is immediately within a class scope, or within -+ another annotation scope that is immediately within a class scope, -+ the code in the annotation scope can use names defined in the class -+ scope as if it were executed directly within the class body. This -+ contrasts with regular functions defined within classes, which -+ cannot access names defined in the class scope. -+ -+* Expressions in annotation scopes cannot contain "yield", "yield -+ from", "await", or ":=" expressions. (These expressions are allowed -+ in other scopes contained within the annotation scope.) -+ -+* Names defined in annotation scopes cannot be rebound with "nonlocal" -+ statements in inner scopes. This includes only type parameters, as -+ no other syntactic elements that can appear within annotation scopes -+ can introduce new names. -+ -+* While annotation scopes have an internal name, that name is not -+ reflected in the *qualified name* of objects defined within the -+ scope. Instead, the "__qualname__" of such objects is as if the -+ object were defined in the enclosing scope. -+ -+Added in version 3.12: Annotation scopes were introduced in Python -+3.12 as part of **PEP 695**. -+ -+Changed in version 3.13: Annotation scopes are also used for type -+parameter defaults, as introduced by **PEP 696**. -+ -+Changed in version 3.14: Annotation scopes are now also used for -+annotations, as specified in **PEP 649** and **PEP 749**. -+ -+ -+Lazy evaluation -+=============== -+ -+Most annotation scopes are *lazily evaluated*. This includes -+annotations, the values of type aliases created through the "type" -+statement, and the bounds, constraints, and default values of type -+variables created through the type parameter syntax. This means that -+they are not evaluated when the type alias or type variable is -+created, or when the object carrying annotations is created. Instead, -+they are only evaluated when necessary, for example when the -+"__value__" attribute on a type alias is accessed. -+ -+Example: -+ -+ >>> type Alias = 1/0 -+ >>> Alias.__value__ -+ Traceback (most recent call last): -+ ... -+ ZeroDivisionError: division by zero -+ >>> def func[T: 1/0](): pass -+ >>> T = func.__type_params__[0] -+ >>> T.__bound__ -+ Traceback (most recent call last): -+ ... -+ ZeroDivisionError: division by zero -+ -+Here the exception is raised only when the "__value__" attribute of -+the type alias or the "__bound__" attribute of the type variable is -+accessed. -+ -+This behavior is primarily useful for references to types that have -+not yet been defined when the type alias or type variable is created. -+For example, lazy evaluation enables creation of mutually recursive -+type aliases: -+ -+ from typing import Literal -+ -+ type SimpleExpr = int | Parenthesized -+ type Parenthesized = tuple[Literal["("], Expr, Literal[")"]] -+ type Expr = SimpleExpr | tuple[SimpleExpr, Literal["+", "-"], Expr] -+ -+Lazily evaluated values are evaluated in annotation scope, which means -+that names that appear inside the lazily evaluated value are looked up -+as if they were used in the immediately enclosing scope. -+ -+Added in version 3.12. -+ -+ -+Builtins and restricted execution -+================================= -+ -+**CPython implementation detail:** Users should not touch -+"__builtins__"; it is strictly an implementation detail. Users -+wanting to override values in the builtins namespace should "import" -+the "builtins" module and modify its attributes appropriately. -+ -+The builtins namespace associated with the execution of a code block -+is actually found by looking up the name "__builtins__" in its global -+namespace; this should be a dictionary or a module (in the latter case -+the module’s dictionary is used). By default, when in the "__main__" -+module, "__builtins__" is the built-in module "builtins"; when in any -+other module, "__builtins__" is an alias for the dictionary of the -+"builtins" module itself. -+ -+ -+Interaction with dynamic features -+================================= -+ -+Name resolution of free variables occurs at runtime, not at compile -+time. This means that the following code will print 42: -+ -+ i = 10 -+ def f(): -+ print(i) -+ i = 42 -+ f() -+ -+The "eval()" and "exec()" functions do not have access to the full -+environment for resolving names. Names may be resolved in the local -+and global namespaces of the caller. Free variables are not resolved -+in the nearest enclosing namespace, but in the global namespace. [1] -+The "exec()" and "eval()" functions have optional arguments to -+override the global and local namespace. If only one namespace is -+specified, it is used for both. -+''', -+ 'nonlocal': r'''The "nonlocal" statement -+************************ -+ -+ **nonlocal_stmt**: "nonlocal" "identifier" ("," "identifier")* -+ -+When the definition of a function or class is nested (enclosed) within -+the definitions of other functions, its nonlocal scopes are the local -+scopes of the enclosing functions. The "nonlocal" statement causes the -+listed identifiers to refer to names previously bound in nonlocal -+scopes. It allows encapsulated code to rebind such nonlocal -+identifiers. If a name is bound in more than one nonlocal scope, the -+nearest binding is used. If a name is not bound in any nonlocal scope, -+or if there is no nonlocal scope, a "SyntaxError" is raised. -+ -+The "nonlocal" statement applies to the entire scope of a function or -+class body. A "SyntaxError" is raised if a variable is used or -+assigned to prior to its nonlocal declaration in the scope. -+ -+See also: -+ -+ **PEP 3104** - Access to Names in Outer Scopes -+ The specification for the "nonlocal" statement. -+ -+**Programmer’s note:** "nonlocal" is a directive to the parser and -+applies only to code parsed along with it. See the note for the -+"global" statement. -+''', -+ 'numbers': r'''Numeric literals -+**************** -+ -+There are three types of numeric literals: integers, floating-point -+numbers, and imaginary numbers. There are no complex literals -+(complex numbers can be formed by adding a real number and an -+imaginary number). -+ -+Note that numeric literals do not include a sign; a phrase like "-1" -+is actually an expression composed of the unary operator ‘"-"’ and the -+literal "1". -+''', -+ 'numeric-types': r'''Emulating numeric types -+*********************** -+ -+The following methods can be defined to emulate numeric objects. -+Methods corresponding to operations that are not supported by the -+particular kind of number implemented (e.g., bitwise operations for -+non-integral numbers) should be left undefined. -+ -+object.__add__(self, other) -+object.__sub__(self, other) -+object.__mul__(self, other) -+object.__matmul__(self, other) -+object.__truediv__(self, other) -+object.__floordiv__(self, other) -+object.__mod__(self, other) -+object.__divmod__(self, other) -+object.__pow__(self, other[, modulo]) -+object.__lshift__(self, other) -+object.__rshift__(self, other) -+object.__and__(self, other) -+object.__xor__(self, other) -+object.__or__(self, other) -+ -+ These methods are called to implement the binary arithmetic -+ operations ("+", "-", "*", "@", "/", "//", "%", "divmod()", -+ "pow()", "**", "<<", ">>", "&", "^", "|"). For instance, to -+ evaluate the expression "x + y", where *x* is an instance of a -+ class that has an "__add__()" method, "type(x).__add__(x, y)" is -+ called. The "__divmod__()" method should be the equivalent to -+ using "__floordiv__()" and "__mod__()"; it should not be related to -+ "__truediv__()". Note that "__pow__()" should be defined to accept -+ an optional third argument if the ternary version of the built-in -+ "pow()" function is to be supported. -+ -+ If one of those methods does not support the operation with the -+ supplied arguments, it should return "NotImplemented". -+ -+object.__radd__(self, other) -+object.__rsub__(self, other) -+object.__rmul__(self, other) -+object.__rmatmul__(self, other) -+object.__rtruediv__(self, other) -+object.__rfloordiv__(self, other) -+object.__rmod__(self, other) -+object.__rdivmod__(self, other) -+object.__rpow__(self, other[, modulo]) -+object.__rlshift__(self, other) -+object.__rrshift__(self, other) -+object.__rand__(self, other) -+object.__rxor__(self, other) -+object.__ror__(self, other) -+ -+ These methods are called to implement the binary arithmetic -+ operations ("+", "-", "*", "@", "/", "//", "%", "divmod()", -+ "pow()", "**", "<<", ">>", "&", "^", "|") with reflected (swapped) -+ operands. These functions are only called if the operands are of -+ different types, when the left operand does not support the -+ corresponding operation [3], or the right operand’s class is -+ derived from the left operand’s class. [4] For instance, to -+ evaluate the expression "x - y", where *y* is an instance of a -+ class that has an "__rsub__()" method, "type(y).__rsub__(y, x)" is -+ called if "type(x).__sub__(x, y)" returns "NotImplemented" or -+ "type(y)" is a subclass of "type(x)". [5] -+ -+ Note that ternary "pow()" will not try calling "__rpow__()" (the -+ coercion rules would become too complicated). -+ -+ Note: -+ -+ If the right operand’s type is a subclass of the left operand’s -+ type and that subclass provides a different implementation of the -+ reflected method for the operation, this method will be called -+ before the left operand’s non-reflected method. This behavior -+ allows subclasses to override their ancestors’ operations. -+ -+object.__iadd__(self, other) -+object.__isub__(self, other) -+object.__imul__(self, other) -+object.__imatmul__(self, other) -+object.__itruediv__(self, other) -+object.__ifloordiv__(self, other) -+object.__imod__(self, other) -+object.__ipow__(self, other[, modulo]) -+object.__ilshift__(self, other) -+object.__irshift__(self, other) -+object.__iand__(self, other) -+object.__ixor__(self, other) -+object.__ior__(self, other) -+ -+ These methods are called to implement the augmented arithmetic -+ assignments ("+=", "-=", "*=", "@=", "/=", "//=", "%=", "**=", -+ "<<=", ">>=", "&=", "^=", "|="). These methods should attempt to -+ do the operation in-place (modifying *self*) and return the result -+ (which could be, but does not have to be, *self*). If a specific -+ method is not defined, or if that method returns "NotImplemented", -+ the augmented assignment falls back to the normal methods. For -+ instance, if *x* is an instance of a class with an "__iadd__()" -+ method, "x += y" is equivalent to "x = x.__iadd__(y)" . If -+ "__iadd__()" does not exist, or if "x.__iadd__(y)" returns -+ "NotImplemented", "x.__add__(y)" and "y.__radd__(x)" are -+ considered, as with the evaluation of "x + y". In certain -+ situations, augmented assignment can result in unexpected errors -+ (see Why does a_tuple[i] += [‘item’] raise an exception when the -+ addition works?), but this behavior is in fact part of the data -+ model. -+ -+object.__neg__(self) -+object.__pos__(self) -+object.__abs__(self) -+object.__invert__(self) -+ -+ Called to implement the unary arithmetic operations ("-", "+", -+ "abs()" and "~"). -+ -+object.__complex__(self) -+object.__int__(self) -+object.__float__(self) -+ -+ Called to implement the built-in functions "complex()", "int()" and -+ "float()". Should return a value of the appropriate type. -+ -+object.__index__(self) -+ -+ Called to implement "operator.index()", and whenever Python needs -+ to losslessly convert the numeric object to an integer object (such -+ as in slicing, or in the built-in "bin()", "hex()" and "oct()" -+ functions). Presence of this method indicates that the numeric -+ object is an integer type. Must return an integer. -+ -+ If "__int__()", "__float__()" and "__complex__()" are not defined -+ then corresponding built-in functions "int()", "float()" and -+ "complex()" fall back to "__index__()". -+ -+object.__round__(self[, ndigits]) -+object.__trunc__(self) -+object.__floor__(self) -+object.__ceil__(self) -+ -+ Called to implement the built-in function "round()" and "math" -+ functions "trunc()", "floor()" and "ceil()". Unless *ndigits* is -+ passed to "__round__()" all these methods should return the value -+ of the object truncated to an "Integral" (typically an "int"). -+ -+ Changed in version 3.14: "int()" no longer delegates to the -+ "__trunc__()" method. -+''', -+ 'objects': r'''Objects, values and types -+************************* -+ -+*Objects* are Python’s abstraction for data. All data in a Python -+program is represented by objects or by relations between objects. (In -+a sense, and in conformance to Von Neumann’s model of a “stored -+program computerâ€, code is also represented by objects.) -+ -+Every object has an identity, a type and a value. An object’s -+*identity* never changes once it has been created; you may think of it -+as the object’s address in memory. The "is" operator compares the -+identity of two objects; the "id()" function returns an integer -+representing its identity. -+ -+**CPython implementation detail:** For CPython, "id(x)" is the memory -+address where "x" is stored. -+ -+An object’s type determines the operations that the object supports -+(e.g., “does it have a length?â€) and also defines the possible values -+for objects of that type. The "type()" function returns an object’s -+type (which is an object itself). Like its identity, an object’s -+*type* is also unchangeable. [1] -+ -+The *value* of some objects can change. Objects whose value can -+change are said to be *mutable*; objects whose value is unchangeable -+once they are created are called *immutable*. (The value of an -+immutable container object that contains a reference to a mutable -+object can change when the latter’s value is changed; however the -+container is still considered immutable, because the collection of -+objects it contains cannot be changed. So, immutability is not -+strictly the same as having an unchangeable value, it is more subtle.) -+An object’s mutability is determined by its type; for instance, -+numbers, strings and tuples are immutable, while dictionaries and -+lists are mutable. -+ -+Objects are never explicitly destroyed; however, when they become -+unreachable they may be garbage-collected. An implementation is -+allowed to postpone garbage collection or omit it altogether — it is a -+matter of implementation quality how garbage collection is -+implemented, as long as no objects are collected that are still -+reachable. -+ -+**CPython implementation detail:** CPython currently uses a reference- -+counting scheme with (optional) delayed detection of cyclically linked -+garbage, which collects most objects as soon as they become -+unreachable, but is not guaranteed to collect garbage containing -+circular references. See the documentation of the "gc" module for -+information on controlling the collection of cyclic garbage. Other -+implementations act differently and CPython may change. Do not depend -+on immediate finalization of objects when they become unreachable (so -+you should always close files explicitly). -+ -+Note that the use of the implementation’s tracing or debugging -+facilities may keep objects alive that would normally be collectable. -+Also note that catching an exception with a "try"…"except" statement -+may keep objects alive. -+ -+Some objects contain references to “external†resources such as open -+files or windows. It is understood that these resources are freed -+when the object is garbage-collected, but since garbage collection is -+not guaranteed to happen, such objects also provide an explicit way to -+release the external resource, usually a "close()" method. Programs -+are strongly recommended to explicitly close such objects. The -+"try"…"finally" statement and the "with" statement provide convenient -+ways to do this. -+ -+Some objects contain references to other objects; these are called -+*containers*. Examples of containers are tuples, lists and -+dictionaries. The references are part of a container’s value. In -+most cases, when we talk about the value of a container, we imply the -+values, not the identities of the contained objects; however, when we -+talk about the mutability of a container, only the identities of the -+immediately contained objects are implied. So, if an immutable -+container (like a tuple) contains a reference to a mutable object, its -+value changes if that mutable object is changed. -+ -+Types affect almost all aspects of object behavior. Even the -+importance of object identity is affected in some sense: for immutable -+types, operations that compute new values may actually return a -+reference to any existing object with the same type and value, while -+for mutable objects this is not allowed. For example, after "a = 1; b -+= 1", *a* and *b* may or may not refer to the same object with the -+value one, depending on the implementation. This is because "int" is -+an immutable type, so the reference to "1" can be reused. This -+behaviour depends on the implementation used, so should not be relied -+upon, but is something to be aware of when making use of object -+identity tests. However, after "c = []; d = []", *c* and *d* are -+guaranteed to refer to two different, unique, newly created empty -+lists. (Note that "e = f = []" assigns the *same* object to both *e* -+and *f*.) -+''', -+ 'operator-summary': r'''Operator precedence -+******************* -+ -+The following table summarizes the operator precedence in Python, from -+highest precedence (most binding) to lowest precedence (least -+binding). Operators in the same box have the same precedence. Unless -+the syntax is explicitly given, operators are binary. Operators in -+the same box group left to right (except for exponentiation and -+conditional expressions, which group from right to left). -+ -+Note that comparisons, membership tests, and identity tests, all have -+the same precedence and have a left-to-right chaining feature as -+described in the Comparisons section. -+ -++-------------------------------------------------+---------------------------------------+ -+| Operator | Description | -+|=================================================|=======================================| -+| "(expressions...)", "[expressions...]", "{key: | Binding or parenthesized expression, | -+| value...}", "{expressions...}" | list display, dictionary display, set | -+| | display | -++-------------------------------------------------+---------------------------------------+ -+| "x[index]", "x[index:index]", | Subscription, slicing, call, | -+| "x(arguments...)", "x.attribute" | attribute reference | -++-------------------------------------------------+---------------------------------------+ -+| "await x" | Await expression | -++-------------------------------------------------+---------------------------------------+ -+| "**" | Exponentiation [5] | -++-------------------------------------------------+---------------------------------------+ -+| "+x", "-x", "~x" | Positive, negative, bitwise NOT | -++-------------------------------------------------+---------------------------------------+ -+| "*", "@", "/", "//", "%" | Multiplication, matrix | -+| | multiplication, division, floor | -+| | division, remainder [6] | -++-------------------------------------------------+---------------------------------------+ -+| "+", "-" | Addition and subtraction | -++-------------------------------------------------+---------------------------------------+ -+| "<<", ">>" | Shifts | -++-------------------------------------------------+---------------------------------------+ -+| "&" | Bitwise AND | -++-------------------------------------------------+---------------------------------------+ -+| "^" | Bitwise XOR | -++-------------------------------------------------+---------------------------------------+ -+| "|" | Bitwise OR | -++-------------------------------------------------+---------------------------------------+ -+| "in", "not in", "is", "is not", "<", "<=", ">", | Comparisons, including membership | -+| ">=", "!=", "==" | tests and identity tests | -++-------------------------------------------------+---------------------------------------+ -+| "not x" | Boolean NOT | -++-------------------------------------------------+---------------------------------------+ -+| "and" | Boolean AND | -++-------------------------------------------------+---------------------------------------+ -+| "or" | Boolean OR | -++-------------------------------------------------+---------------------------------------+ -+| "if" – "else" | Conditional expression | -++-------------------------------------------------+---------------------------------------+ -+| "lambda" | Lambda expression | -++-------------------------------------------------+---------------------------------------+ -+| ":=" | Assignment expression | -++-------------------------------------------------+---------------------------------------+ -+ -+-[ Footnotes ]- -+ -+[1] While "abs(x%y) < abs(y)" is true mathematically, for floats it -+ may not be true numerically due to roundoff. For example, and -+ assuming a platform on which a Python float is an IEEE 754 double- -+ precision number, in order that "-1e-100 % 1e100" have the same -+ sign as "1e100", the computed result is "-1e-100 + 1e100", which -+ is numerically exactly equal to "1e100". The function -+ "math.fmod()" returns a result whose sign matches the sign of the -+ first argument instead, and so returns "-1e-100" in this case. -+ Which approach is more appropriate depends on the application. -+ -+[2] If x is very close to an exact integer multiple of y, it’s -+ possible for "x//y" to be one larger than "(x-x%y)//y" due to -+ rounding. In such cases, Python returns the latter result, in -+ order to preserve that "divmod(x,y)[0] * y + x % y" be very close -+ to "x". -+ -+[3] The Unicode standard distinguishes between *code points* (e.g. -+ U+0041) and *abstract characters* (e.g. “LATIN CAPITAL LETTER Aâ€). -+ While most abstract characters in Unicode are only represented -+ using one code point, there is a number of abstract characters -+ that can in addition be represented using a sequence of more than -+ one code point. For example, the abstract character “LATIN -+ CAPITAL LETTER C WITH CEDILLA†can be represented as a single -+ *precomposed character* at code position U+00C7, or as a sequence -+ of a *base character* at code position U+0043 (LATIN CAPITAL -+ LETTER C), followed by a *combining character* at code position -+ U+0327 (COMBINING CEDILLA). -+ -+ The comparison operators on strings compare at the level of -+ Unicode code points. This may be counter-intuitive to humans. For -+ example, ""\u00C7" == "\u0043\u0327"" is "False", even though both -+ strings represent the same abstract character “LATIN CAPITAL -+ LETTER C WITH CEDILLAâ€. -+ -+ To compare strings at the level of abstract characters (that is, -+ in a way intuitive to humans), use "unicodedata.normalize()". -+ -+[4] Due to automatic garbage-collection, free lists, and the dynamic -+ nature of descriptors, you may notice seemingly unusual behaviour -+ in certain uses of the "is" operator, like those involving -+ comparisons between instance methods, or constants. Check their -+ documentation for more info. -+ -+[5] The power operator "**" binds less tightly than an arithmetic or -+ bitwise unary operator on its right, that is, "2**-1" is "0.5". -+ -+[6] The "%" operator is also used for string formatting; the same -+ precedence applies. -+''', -+ 'pass': r'''The "pass" statement -+******************** -+ -+ **pass_stmt**: "pass" -+ -+"pass" is a null operation — when it is executed, nothing happens. It -+is useful as a placeholder when a statement is required syntactically, -+but no code needs to be executed, for example: -+ -+ def f(arg): pass # a function that does nothing (yet) -+ -+ class C: pass # a class with no methods (yet) -+''', -+ 'power': r'''The power operator -+****************** -+ -+The power operator binds more tightly than unary operators on its -+left; it binds less tightly than unary operators on its right. The -+syntax is: -+ -+ **power**: ("await_expr" | "primary") ["**" "u_expr"] -+ -+Thus, in an unparenthesized sequence of power and unary operators, the -+operators are evaluated from right to left (this does not constrain -+the evaluation order for the operands): "-1**2" results in "-1". -+ -+The power operator has the same semantics as the built-in "pow()" -+function, when called with two arguments: it yields its left argument -+raised to the power of its right argument. The numeric arguments are -+first converted to a common type, and the result is of that type. -+ -+For int operands, the result has the same type as the operands unless -+the second argument is negative; in that case, all arguments are -+converted to float and a float result is delivered. For example, -+"10**2" returns "100", but "10**-2" returns "0.01". -+ -+Raising "0.0" to a negative power results in a "ZeroDivisionError". -+Raising a negative number to a fractional power results in a "complex" -+number. (In earlier versions it raised a "ValueError".) -+ -+This operation can be customized using the special "__pow__()" and -+"__rpow__()" methods. -+''', -+ 'raise': r'''The "raise" statement -+********************* -+ -+ **raise_stmt**: "raise" ["expression" ["from" "expression"]] -+ -+If no expressions are present, "raise" re-raises the exception that is -+currently being handled, which is also known as the *active -+exception*. If there isn’t currently an active exception, a -+"RuntimeError" exception is raised indicating that this is an error. -+ -+Otherwise, "raise" evaluates the first expression as the exception -+object. It must be either a subclass or an instance of -+"BaseException". If it is a class, the exception instance will be -+obtained when needed by instantiating the class with no arguments. -+ -+The *type* of the exception is the exception instance’s class, the -+*value* is the instance itself. -+ -+A traceback object is normally created automatically when an exception -+is raised and attached to it as the "__traceback__" attribute. You can -+create an exception and set your own traceback in one step using the -+"with_traceback()" exception method (which returns the same exception -+instance, with its traceback set to its argument), like so: -+ -+ raise Exception("foo occurred").with_traceback(tracebackobj) -+ -+The "from" clause is used for exception chaining: if given, the second -+*expression* must be another exception class or instance. If the -+second expression is an exception instance, it will be attached to the -+raised exception as the "__cause__" attribute (which is writable). If -+the expression is an exception class, the class will be instantiated -+and the resulting exception instance will be attached to the raised -+exception as the "__cause__" attribute. If the raised exception is not -+handled, both exceptions will be printed: -+ -+ >>> try: -+ ... print(1 / 0) -+ ... except Exception as exc: -+ ... raise RuntimeError("Something bad happened") from exc -+ ... -+ Traceback (most recent call last): -+ File "", line 2, in -+ print(1 / 0) -+ ~~^~~ -+ ZeroDivisionError: division by zero -+ -+ The above exception was the direct cause of the following exception: -+ -+ Traceback (most recent call last): -+ File "", line 4, in -+ raise RuntimeError("Something bad happened") from exc -+ RuntimeError: Something bad happened -+ -+A similar mechanism works implicitly if a new exception is raised when -+an exception is already being handled. An exception may be handled -+when an "except" or "finally" clause, or a "with" statement, is used. -+The previous exception is then attached as the new exception’s -+"__context__" attribute: -+ -+ >>> try: -+ ... print(1 / 0) -+ ... except: -+ ... raise RuntimeError("Something bad happened") -+ ... -+ Traceback (most recent call last): -+ File "", line 2, in -+ print(1 / 0) -+ ~~^~~ -+ ZeroDivisionError: division by zero -+ -+ During handling of the above exception, another exception occurred: -+ -+ Traceback (most recent call last): -+ File "", line 4, in -+ raise RuntimeError("Something bad happened") -+ RuntimeError: Something bad happened -+ -+Exception chaining can be explicitly suppressed by specifying "None" -+in the "from" clause: -+ -+ >>> try: -+ ... print(1 / 0) -+ ... except: -+ ... raise RuntimeError("Something bad happened") from None -+ ... -+ Traceback (most recent call last): -+ File "", line 4, in -+ RuntimeError: Something bad happened -+ -+Additional information on exceptions can be found in section -+Exceptions, and information about handling exceptions is in section -+The try statement. -+ -+Changed in version 3.3: "None" is now permitted as "Y" in "raise X -+from Y".Added the "__suppress_context__" attribute to suppress -+automatic display of the exception context. -+ -+Changed in version 3.11: If the traceback of the active exception is -+modified in an "except" clause, a subsequent "raise" statement re- -+raises the exception with the modified traceback. Previously, the -+exception was re-raised with the traceback it had when it was caught. -+''', -+ 'return': r'''The "return" statement -+********************** -+ -+ **return_stmt**: "return" ["expression_list"] -+ -+"return" may only occur syntactically nested in a function definition, -+not within a nested class definition. -+ -+If an expression list is present, it is evaluated, else "None" is -+substituted. -+ -+"return" leaves the current function call with the expression list (or -+"None") as return value. -+ -+When "return" passes control out of a "try" statement with a "finally" -+clause, that "finally" clause is executed before really leaving the -+function. -+ -+In a generator function, the "return" statement indicates that the -+generator is done and will cause "StopIteration" to be raised. The -+returned value (if any) is used as an argument to construct -+"StopIteration" and becomes the "StopIteration.value" attribute. -+ -+In an asynchronous generator function, an empty "return" statement -+indicates that the asynchronous generator is done and will cause -+"StopAsyncIteration" to be raised. A non-empty "return" statement is -+a syntax error in an asynchronous generator function. -+''', -+ 'sequence-types': r'''Emulating container types -+************************* -+ -+The following methods can be defined to implement container objects. -+None of them are provided by the "object" class itself. Containers -+usually are *sequences* (such as "lists" or "tuples") or *mappings* -+(like *dictionaries*), but can represent other containers as well. -+The first set of methods is used either to emulate a sequence or to -+emulate a mapping; the difference is that for a sequence, the -+allowable keys should be the integers *k* for which "0 <= k < N" where -+*N* is the length of the sequence, or "slice" objects, which define a -+range of items. It is also recommended that mappings provide the -+methods "keys()", "values()", "items()", "get()", "clear()", -+"setdefault()", "pop()", "popitem()", "copy()", and "update()" -+behaving similar to those for Python’s standard "dictionary" objects. -+The "collections.abc" module provides a "MutableMapping" *abstract -+base class* to help create those methods from a base set of -+"__getitem__()", "__setitem__()", "__delitem__()", and "keys()". -+Mutable sequences should provide methods "append()", "count()", -+"index()", "extend()", "insert()", "pop()", "remove()", "reverse()" -+and "sort()", like Python standard "list" objects. Finally, sequence -+types should implement addition (meaning concatenation) and -+multiplication (meaning repetition) by defining the methods -+"__add__()", "__radd__()", "__iadd__()", "__mul__()", "__rmul__()" and -+"__imul__()" described below; they should not define other numerical -+operators. It is recommended that both mappings and sequences -+implement the "__contains__()" method to allow efficient use of the -+"in" operator; for mappings, "in" should search the mapping’s keys; -+for sequences, it should search through the values. It is further -+recommended that both mappings and sequences implement the -+"__iter__()" method to allow efficient iteration through the -+container; for mappings, "__iter__()" should iterate through the -+object’s keys; for sequences, it should iterate through the values. -+ -+object.__len__(self) -+ -+ Called to implement the built-in function "len()". Should return -+ the length of the object, an integer ">=" 0. Also, an object that -+ doesn’t define a "__bool__()" method and whose "__len__()" method -+ returns zero is considered to be false in a Boolean context. -+ -+ **CPython implementation detail:** In CPython, the length is -+ required to be at most "sys.maxsize". If the length is larger than -+ "sys.maxsize" some features (such as "len()") may raise -+ "OverflowError". To prevent raising "OverflowError" by truth value -+ testing, an object must define a "__bool__()" method. -+ -+object.__length_hint__(self) -+ -+ Called to implement "operator.length_hint()". Should return an -+ estimated length for the object (which may be greater or less than -+ the actual length). The length must be an integer ">=" 0. The -+ return value may also be "NotImplemented", which is treated the -+ same as if the "__length_hint__" method didn’t exist at all. This -+ method is purely an optimization and is never required for -+ correctness. -+ -+ Added in version 3.4. -+ -+Note: -+ -+ Slicing is done exclusively with the following three methods. A -+ call like -+ -+ a[1:2] = b -+ -+ is translated to -+ -+ a[slice(1, 2, None)] = b -+ -+ and so forth. Missing slice items are always filled in with "None". -+ -+object.__getitem__(self, key) -+ -+ Called to implement evaluation of "self[key]". For *sequence* -+ types, the accepted keys should be integers. Optionally, they may -+ support "slice" objects as well. Negative index support is also -+ optional. If *key* is of an inappropriate type, "TypeError" may be -+ raised; if *key* is a value outside the set of indexes for the -+ sequence (after any special interpretation of negative values), -+ "IndexError" should be raised. For *mapping* types, if *key* is -+ missing (not in the container), "KeyError" should be raised. -+ -+ Note: -+ -+ "for" loops expect that an "IndexError" will be raised for -+ illegal indexes to allow proper detection of the end of the -+ sequence. -+ -+ Note: -+ -+ When subscripting a *class*, the special class method -+ "__class_getitem__()" may be called instead of "__getitem__()". -+ See __class_getitem__ versus __getitem__ for more details. -+ -+object.__setitem__(self, key, value) -+ -+ Called to implement assignment to "self[key]". Same note as for -+ "__getitem__()". This should only be implemented for mappings if -+ the objects support changes to the values for keys, or if new keys -+ can be added, or for sequences if elements can be replaced. The -+ same exceptions should be raised for improper *key* values as for -+ the "__getitem__()" method. -+ -+object.__delitem__(self, key) -+ -+ Called to implement deletion of "self[key]". Same note as for -+ "__getitem__()". This should only be implemented for mappings if -+ the objects support removal of keys, or for sequences if elements -+ can be removed from the sequence. The same exceptions should be -+ raised for improper *key* values as for the "__getitem__()" method. -+ -+object.__missing__(self, key) -+ -+ Called by "dict"."__getitem__()" to implement "self[key]" for dict -+ subclasses when key is not in the dictionary. -+ -+object.__iter__(self) -+ -+ This method is called when an *iterator* is required for a -+ container. This method should return a new iterator object that can -+ iterate over all the objects in the container. For mappings, it -+ should iterate over the keys of the container. -+ -+object.__reversed__(self) -+ -+ Called (if present) by the "reversed()" built-in to implement -+ reverse iteration. It should return a new iterator object that -+ iterates over all the objects in the container in reverse order. -+ -+ If the "__reversed__()" method is not provided, the "reversed()" -+ built-in will fall back to using the sequence protocol ("__len__()" -+ and "__getitem__()"). Objects that support the sequence protocol -+ should only provide "__reversed__()" if they can provide an -+ implementation that is more efficient than the one provided by -+ "reversed()". -+ -+The membership test operators ("in" and "not in") are normally -+implemented as an iteration through a container. However, container -+objects can supply the following special method with a more efficient -+implementation, which also does not require the object be iterable. -+ -+object.__contains__(self, item) -+ -+ Called to implement membership test operators. Should return true -+ if *item* is in *self*, false otherwise. For mapping objects, this -+ should consider the keys of the mapping rather than the values or -+ the key-item pairs. -+ -+ For objects that don’t define "__contains__()", the membership test -+ first tries iteration via "__iter__()", then the old sequence -+ iteration protocol via "__getitem__()", see this section in the -+ language reference. -+''', -+ 'shifting': r'''Shifting operations -+******************* -+ -+The shifting operations have lower priority than the arithmetic -+operations: -+ -+ **shift_expr**: "a_expr" | "shift_expr" ("<<" | ">>") "a_expr" -+ -+These operators accept integers as arguments. They shift the first -+argument to the left or right by the number of bits given by the -+second argument. -+ -+The left shift operation can be customized using the special -+"__lshift__()" and "__rlshift__()" methods. The right shift operation -+can be customized using the special "__rshift__()" and "__rrshift__()" -+methods. -+ -+A right shift by *n* bits is defined as floor division by "pow(2,n)". -+A left shift by *n* bits is defined as multiplication with "pow(2,n)". -+''', -+ 'slicings': r'''Slicings -+******** -+ -+A slicing selects a range of items in a sequence object (e.g., a -+string, tuple or list). Slicings may be used as expressions or as -+targets in assignment or "del" statements. The syntax for a slicing: -+ -+ **slicing**: "primary" "[" "slice_list" "]" -+ **slice_list**: "slice_item" ("," "slice_item")* [","] -+ **slice_item**: "expression" | "proper_slice" -+ **proper_slice**: ["lower_bound"] ":" ["upper_bound"] [ ":" ["stride"] ] -+ **lower_bound**: "expression" -+ **upper_bound**: "expression" -+ **stride**: "expression" -+ -+There is ambiguity in the formal syntax here: anything that looks like -+an expression list also looks like a slice list, so any subscription -+can be interpreted as a slicing. Rather than further complicating the -+syntax, this is disambiguated by defining that in this case the -+interpretation as a subscription takes priority over the -+interpretation as a slicing (this is the case if the slice list -+contains no proper slice). -+ -+The semantics for a slicing are as follows. The primary is indexed -+(using the same "__getitem__()" method as normal subscription) with a -+key that is constructed from the slice list, as follows. If the slice -+list contains at least one comma, the key is a tuple containing the -+conversion of the slice items; otherwise, the conversion of the lone -+slice item is the key. The conversion of a slice item that is an -+expression is that expression. The conversion of a proper slice is a -+slice object (see section The standard type hierarchy) whose "start", -+"stop" and "step" attributes are the values of the expressions given -+as lower bound, upper bound and stride, respectively, substituting -+"None" for missing expressions. -+''', -+ 'specialattrs': r'''Special Attributes -+****************** -+ -+The implementation adds a few special read-only attributes to several -+object types, where they are relevant. Some of these are not reported -+by the "dir()" built-in function. -+ -+definition.__name__ -+ -+ The name of the class, function, method, descriptor, or generator -+ instance. -+ -+definition.__qualname__ -+ -+ The *qualified name* of the class, function, method, descriptor, or -+ generator instance. -+ -+ Added in version 3.3. -+ -+definition.__module__ -+ -+ The name of the module in which a class or function was defined. -+ -+definition.__doc__ -+ -+ The documentation string of a class or function, or "None" if -+ undefined. -+ -+definition.__type_params__ -+ -+ The type parameters of generic classes, functions, and type -+ aliases. For classes and functions that are not generic, this will -+ be an empty tuple. -+ -+ Added in version 3.12. -+''', -+ 'specialnames': r'''Special method names -+******************** -+ -+A class can implement certain operations that are invoked by special -+syntax (such as arithmetic operations or subscripting and slicing) by -+defining methods with special names. This is Python’s approach to -+*operator overloading*, allowing classes to define their own behavior -+with respect to language operators. For instance, if a class defines -+a method named "__getitem__()", and "x" is an instance of this class, -+then "x[i]" is roughly equivalent to "type(x).__getitem__(x, i)". -+Except where mentioned, attempts to execute an operation raise an -+exception when no appropriate method is defined (typically -+"AttributeError" or "TypeError"). -+ -+Setting a special method to "None" indicates that the corresponding -+operation is not available. For example, if a class sets "__iter__()" -+to "None", the class is not iterable, so calling "iter()" on its -+instances will raise a "TypeError" (without falling back to -+"__getitem__()"). [2] -+ -+When implementing a class that emulates any built-in type, it is -+important that the emulation only be implemented to the degree that it -+makes sense for the object being modelled. For example, some -+sequences may work well with retrieval of individual elements, but -+extracting a slice may not make sense. (One example of this is the -+"NodeList" interface in the W3C’s Document Object Model.) -+ -+ -+Basic customization -+=================== -+ -+object.__new__(cls[, ...]) -+ -+ Called to create a new instance of class *cls*. "__new__()" is a -+ static method (special-cased so you need not declare it as such) -+ that takes the class of which an instance was requested as its -+ first argument. The remaining arguments are those passed to the -+ object constructor expression (the call to the class). The return -+ value of "__new__()" should be the new object instance (usually an -+ instance of *cls*). -+ -+ Typical implementations create a new instance of the class by -+ invoking the superclass’s "__new__()" method using -+ "super().__new__(cls[, ...])" with appropriate arguments and then -+ modifying the newly created instance as necessary before returning -+ it. -+ -+ If "__new__()" is invoked during object construction and it returns -+ an instance of *cls*, then the new instance’s "__init__()" method -+ will be invoked like "__init__(self[, ...])", where *self* is the -+ new instance and the remaining arguments are the same as were -+ passed to the object constructor. -+ -+ If "__new__()" does not return an instance of *cls*, then the new -+ instance’s "__init__()" method will not be invoked. -+ -+ "__new__()" is intended mainly to allow subclasses of immutable -+ types (like int, str, or tuple) to customize instance creation. It -+ is also commonly overridden in custom metaclasses in order to -+ customize class creation. -+ -+object.__init__(self[, ...]) -+ -+ Called after the instance has been created (by "__new__()"), but -+ before it is returned to the caller. The arguments are those -+ passed to the class constructor expression. If a base class has an -+ "__init__()" method, the derived class’s "__init__()" method, if -+ any, must explicitly call it to ensure proper initialization of the -+ base class part of the instance; for example: -+ "super().__init__([args...])". -+ -+ Because "__new__()" and "__init__()" work together in constructing -+ objects ("__new__()" to create it, and "__init__()" to customize -+ it), no non-"None" value may be returned by "__init__()"; doing so -+ will cause a "TypeError" to be raised at runtime. -+ -+object.__del__(self) -+ -+ Called when the instance is about to be destroyed. This is also -+ called a finalizer or (improperly) a destructor. If a base class -+ has a "__del__()" method, the derived class’s "__del__()" method, -+ if any, must explicitly call it to ensure proper deletion of the -+ base class part of the instance. -+ -+ It is possible (though not recommended!) for the "__del__()" method -+ to postpone destruction of the instance by creating a new reference -+ to it. This is called object *resurrection*. It is -+ implementation-dependent whether "__del__()" is called a second -+ time when a resurrected object is about to be destroyed; the -+ current *CPython* implementation only calls it once. -+ -+ It is not guaranteed that "__del__()" methods are called for -+ objects that still exist when the interpreter exits. -+ "weakref.finalize" provides a straightforward way to register a -+ cleanup function to be called when an object is garbage collected. -+ -+ Note: -+ -+ "del x" doesn’t directly call "x.__del__()" — the former -+ decrements the reference count for "x" by one, and the latter is -+ only called when "x"’s reference count reaches zero. -+ -+ **CPython implementation detail:** It is possible for a reference -+ cycle to prevent the reference count of an object from going to -+ zero. In this case, the cycle will be later detected and deleted -+ by the *cyclic garbage collector*. A common cause of reference -+ cycles is when an exception has been caught in a local variable. -+ The frame’s locals then reference the exception, which references -+ its own traceback, which references the locals of all frames caught -+ in the traceback. -+ -+ See also: Documentation for the "gc" module. -+ -+ Warning: -+ -+ Due to the precarious circumstances under which "__del__()" -+ methods are invoked, exceptions that occur during their execution -+ are ignored, and a warning is printed to "sys.stderr" instead. -+ In particular: -+ -+ * "__del__()" can be invoked when arbitrary code is being -+ executed, including from any arbitrary thread. If "__del__()" -+ needs to take a lock or invoke any other blocking resource, it -+ may deadlock as the resource may already be taken by the code -+ that gets interrupted to execute "__del__()". -+ -+ * "__del__()" can be executed during interpreter shutdown. As a -+ consequence, the global variables it needs to access (including -+ other modules) may already have been deleted or set to "None". -+ Python guarantees that globals whose name begins with a single -+ underscore are deleted from their module before other globals -+ are deleted; if no other references to such globals exist, this -+ may help in assuring that imported modules are still available -+ at the time when the "__del__()" method is called. -+ -+object.__repr__(self) -+ -+ Called by the "repr()" built-in function to compute the “official†-+ string representation of an object. If at all possible, this -+ should look like a valid Python expression that could be used to -+ recreate an object with the same value (given an appropriate -+ environment). If this is not possible, a string of the form -+ "<...some useful description...>" should be returned. The return -+ value must be a string object. If a class defines "__repr__()" but -+ not "__str__()", then "__repr__()" is also used when an “informal†-+ string representation of instances of that class is required. -+ -+ This is typically used for debugging, so it is important that the -+ representation is information-rich and unambiguous. A default -+ implementation is provided by the "object" class itself. -+ -+object.__str__(self) -+ -+ Called by "str(object)", the default "__format__()" implementation, -+ and the built-in function "print()", to compute the “informal†or -+ nicely printable string representation of an object. The return -+ value must be a str object. -+ -+ This method differs from "object.__repr__()" in that there is no -+ expectation that "__str__()" return a valid Python expression: a -+ more convenient or concise representation can be used. -+ -+ The default implementation defined by the built-in type "object" -+ calls "object.__repr__()". -+ -+object.__bytes__(self) -+ -+ Called by bytes to compute a byte-string representation of an -+ object. This should return a "bytes" object. The "object" class -+ itself does not provide this method. -+ -+object.__format__(self, format_spec) -+ -+ Called by the "format()" built-in function, and by extension, -+ evaluation of formatted string literals and the "str.format()" -+ method, to produce a “formatted†string representation of an -+ object. The *format_spec* argument is a string that contains a -+ description of the formatting options desired. The interpretation -+ of the *format_spec* argument is up to the type implementing -+ "__format__()", however most classes will either delegate -+ formatting to one of the built-in types, or use a similar -+ formatting option syntax. -+ -+ See Format Specification Mini-Language for a description of the -+ standard formatting syntax. -+ -+ The return value must be a string object. -+ -+ The default implementation by the "object" class should be given an -+ empty *format_spec* string. It delegates to "__str__()". -+ -+ Changed in version 3.4: The __format__ method of "object" itself -+ raises a "TypeError" if passed any non-empty string. -+ -+ Changed in version 3.7: "object.__format__(x, '')" is now -+ equivalent to "str(x)" rather than "format(str(x), '')". -+ -+object.__lt__(self, other) -+object.__le__(self, other) -+object.__eq__(self, other) -+object.__ne__(self, other) -+object.__gt__(self, other) -+object.__ge__(self, other) -+ -+ These are the so-called “rich comparison†methods. The -+ correspondence between operator symbols and method names is as -+ follows: "xy" calls -+ "x.__gt__(y)", and "x>=y" calls "x.__ge__(y)". -+ -+ A rich comparison method may return the singleton "NotImplemented" -+ if it does not implement the operation for a given pair of -+ arguments. By convention, "False" and "True" are returned for a -+ successful comparison. However, these methods can return any value, -+ so if the comparison operator is used in a Boolean context (e.g., -+ in the condition of an "if" statement), Python will call "bool()" -+ on the value to determine if the result is true or false. -+ -+ By default, "object" implements "__eq__()" by using "is", returning -+ "NotImplemented" in the case of a false comparison: "True if x is y -+ else NotImplemented". For "__ne__()", by default it delegates to -+ "__eq__()" and inverts the result unless it is "NotImplemented". -+ There are no other implied relationships among the comparison -+ operators or default implementations; for example, the truth of -+ "(x.__hash__". -+ -+ If a class that does not override "__eq__()" wishes to suppress -+ hash support, it should include "__hash__ = None" in the class -+ definition. A class which defines its own "__hash__()" that -+ explicitly raises a "TypeError" would be incorrectly identified as -+ hashable by an "isinstance(obj, collections.abc.Hashable)" call. -+ -+ Note: -+ -+ By default, the "__hash__()" values of str and bytes objects are -+ “salted†with an unpredictable random value. Although they -+ remain constant within an individual Python process, they are not -+ predictable between repeated invocations of Python.This is -+ intended to provide protection against a denial-of-service caused -+ by carefully chosen inputs that exploit the worst case -+ performance of a dict insertion, *O*(*n*^2) complexity. See -+ http://ocert.org/advisories/ocert-2011-003.html for -+ details.Changing hash values affects the iteration order of sets. -+ Python has never made guarantees about this ordering (and it -+ typically varies between 32-bit and 64-bit builds).See also -+ "PYTHONHASHSEED". -+ -+ Changed in version 3.3: Hash randomization is enabled by default. -+ -+object.__bool__(self) -+ -+ Called to implement truth value testing and the built-in operation -+ "bool()"; should return "False" or "True". When this method is not -+ defined, "__len__()" is called, if it is defined, and the object is -+ considered true if its result is nonzero. If a class defines -+ neither "__len__()" nor "__bool__()" (which is true of the "object" -+ class itself), all its instances are considered true. -+ -+ -+Customizing attribute access -+============================ -+ -+The following methods can be defined to customize the meaning of -+attribute access (use of, assignment to, or deletion of "x.name") for -+class instances. -+ -+object.__getattr__(self, name) -+ -+ Called when the default attribute access fails with an -+ "AttributeError" (either "__getattribute__()" raises an -+ "AttributeError" because *name* is not an instance attribute or an -+ attribute in the class tree for "self"; or "__get__()" of a *name* -+ property raises "AttributeError"). This method should either -+ return the (computed) attribute value or raise an "AttributeError" -+ exception. The "object" class itself does not provide this method. -+ -+ Note that if the attribute is found through the normal mechanism, -+ "__getattr__()" is not called. (This is an intentional asymmetry -+ between "__getattr__()" and "__setattr__()".) This is done both for -+ efficiency reasons and because otherwise "__getattr__()" would have -+ no way to access other attributes of the instance. Note that at -+ least for instance variables, you can take total control by not -+ inserting any values in the instance attribute dictionary (but -+ instead inserting them in another object). See the -+ "__getattribute__()" method below for a way to actually get total -+ control over attribute access. -+ -+object.__getattribute__(self, name) -+ -+ Called unconditionally to implement attribute accesses for -+ instances of the class. If the class also defines "__getattr__()", -+ the latter will not be called unless "__getattribute__()" either -+ calls it explicitly or raises an "AttributeError". This method -+ should return the (computed) attribute value or raise an -+ "AttributeError" exception. In order to avoid infinite recursion in -+ this method, its implementation should always call the base class -+ method with the same name to access any attributes it needs, for -+ example, "object.__getattribute__(self, name)". -+ -+ Note: -+ -+ This method may still be bypassed when looking up special methods -+ as the result of implicit invocation via language syntax or -+ built-in functions. See Special method lookup. -+ -+ For certain sensitive attribute accesses, raises an auditing event -+ "object.__getattr__" with arguments "obj" and "name". -+ -+object.__setattr__(self, name, value) -+ -+ Called when an attribute assignment is attempted. This is called -+ instead of the normal mechanism (i.e. store the value in the -+ instance dictionary). *name* is the attribute name, *value* is the -+ value to be assigned to it. -+ -+ If "__setattr__()" wants to assign to an instance attribute, it -+ should call the base class method with the same name, for example, -+ "object.__setattr__(self, name, value)". -+ -+ For certain sensitive attribute assignments, raises an auditing -+ event "object.__setattr__" with arguments "obj", "name", "value". -+ -+object.__delattr__(self, name) -+ -+ Like "__setattr__()" but for attribute deletion instead of -+ assignment. This should only be implemented if "del obj.name" is -+ meaningful for the object. -+ -+ For certain sensitive attribute deletions, raises an auditing event -+ "object.__delattr__" with arguments "obj" and "name". -+ -+object.__dir__(self) -+ -+ Called when "dir()" is called on the object. An iterable must be -+ returned. "dir()" converts the returned iterable to a list and -+ sorts it. -+ -+ -+Customizing module attribute access -+----------------------------------- -+ -+Special names "__getattr__" and "__dir__" can be also used to -+customize access to module attributes. The "__getattr__" function at -+the module level should accept one argument which is the name of an -+attribute and return the computed value or raise an "AttributeError". -+If an attribute is not found on a module object through the normal -+lookup, i.e. "object.__getattribute__()", then "__getattr__" is -+searched in the module "__dict__" before raising an "AttributeError". -+If found, it is called with the attribute name and the result is -+returned. -+ -+The "__dir__" function should accept no arguments, and return an -+iterable of strings that represents the names accessible on module. If -+present, this function overrides the standard "dir()" search on a -+module. -+ -+For a more fine grained customization of the module behavior (setting -+attributes, properties, etc.), one can set the "__class__" attribute -+of a module object to a subclass of "types.ModuleType". For example: -+ -+ import sys -+ from types import ModuleType -+ -+ class VerboseModule(ModuleType): -+ def __repr__(self): -+ return f'Verbose {self.__name__}' -+ -+ def __setattr__(self, attr, value): -+ print(f'Setting {attr}...') -+ super().__setattr__(attr, value) -+ -+ sys.modules[__name__].__class__ = VerboseModule -+ -+Note: -+ -+ Defining module "__getattr__" and setting module "__class__" only -+ affect lookups made using the attribute access syntax – directly -+ accessing the module globals (whether by code within the module, or -+ via a reference to the module’s globals dictionary) is unaffected. -+ -+Changed in version 3.5: "__class__" module attribute is now writable. -+ -+Added in version 3.7: "__getattr__" and "__dir__" module attributes. -+ -+See also: -+ -+ **PEP 562** - Module __getattr__ and __dir__ -+ Describes the "__getattr__" and "__dir__" functions on modules. -+ -+ -+Implementing Descriptors -+------------------------ -+ -+The following methods only apply when an instance of the class -+containing the method (a so-called *descriptor* class) appears in an -+*owner* class (the descriptor must be in either the owner’s class -+dictionary or in the class dictionary for one of its parents). In the -+examples below, “the attribute†refers to the attribute whose name is -+the key of the property in the owner class’ "__dict__". The "object" -+class itself does not implement any of these protocols. -+ -+object.__get__(self, instance, owner=None) -+ -+ Called to get the attribute of the owner class (class attribute -+ access) or of an instance of that class (instance attribute -+ access). The optional *owner* argument is the owner class, while -+ *instance* is the instance that the attribute was accessed through, -+ or "None" when the attribute is accessed through the *owner*. -+ -+ This method should return the computed attribute value or raise an -+ "AttributeError" exception. -+ -+ **PEP 252** specifies that "__get__()" is callable with one or two -+ arguments. Python’s own built-in descriptors support this -+ specification; however, it is likely that some third-party tools -+ have descriptors that require both arguments. Python’s own -+ "__getattribute__()" implementation always passes in both arguments -+ whether they are required or not. -+ -+object.__set__(self, instance, value) -+ -+ Called to set the attribute on an instance *instance* of the owner -+ class to a new value, *value*. -+ -+ Note, adding "__set__()" or "__delete__()" changes the kind of -+ descriptor to a “data descriptorâ€. See Invoking Descriptors for -+ more details. -+ -+object.__delete__(self, instance) -+ -+ Called to delete the attribute on an instance *instance* of the -+ owner class. -+ -+Instances of descriptors may also have the "__objclass__" attribute -+present: -+ -+object.__objclass__ -+ -+ The attribute "__objclass__" is interpreted by the "inspect" module -+ as specifying the class where this object was defined (setting this -+ appropriately can assist in runtime introspection of dynamic class -+ attributes). For callables, it may indicate that an instance of the -+ given type (or a subclass) is expected or required as the first -+ positional argument (for example, CPython sets this attribute for -+ unbound methods that are implemented in C). -+ -+ -+Invoking Descriptors -+-------------------- -+ -+In general, a descriptor is an object attribute with “binding -+behaviorâ€, one whose attribute access has been overridden by methods -+in the descriptor protocol: "__get__()", "__set__()", and -+"__delete__()". If any of those methods are defined for an object, it -+is said to be a descriptor. -+ -+The default behavior for attribute access is to get, set, or delete -+the attribute from an object’s dictionary. For instance, "a.x" has a -+lookup chain starting with "a.__dict__['x']", then -+"type(a).__dict__['x']", and continuing through the base classes of -+"type(a)" excluding metaclasses. -+ -+However, if the looked-up value is an object defining one of the -+descriptor methods, then Python may override the default behavior and -+invoke the descriptor method instead. Where this occurs in the -+precedence chain depends on which descriptor methods were defined and -+how they were called. -+ -+The starting point for descriptor invocation is a binding, "a.x". How -+the arguments are assembled depends on "a": -+ -+Direct Call -+ The simplest and least common call is when user code directly -+ invokes a descriptor method: "x.__get__(a)". -+ -+Instance Binding -+ If binding to an object instance, "a.x" is transformed into the -+ call: "type(a).__dict__['x'].__get__(a, type(a))". -+ -+Class Binding -+ If binding to a class, "A.x" is transformed into the call: -+ "A.__dict__['x'].__get__(None, A)". -+ -+Super Binding -+ A dotted lookup such as "super(A, a).x" searches -+ "a.__class__.__mro__" for a base class "B" following "A" and then -+ returns "B.__dict__['x'].__get__(a, A)". If not a descriptor, "x" -+ is returned unchanged. -+ -+For instance bindings, the precedence of descriptor invocation depends -+on which descriptor methods are defined. A descriptor can define any -+combination of "__get__()", "__set__()" and "__delete__()". If it -+does not define "__get__()", then accessing the attribute will return -+the descriptor object itself unless there is a value in the object’s -+instance dictionary. If the descriptor defines "__set__()" and/or -+"__delete__()", it is a data descriptor; if it defines neither, it is -+a non-data descriptor. Normally, data descriptors define both -+"__get__()" and "__set__()", while non-data descriptors have just the -+"__get__()" method. Data descriptors with "__get__()" and "__set__()" -+(and/or "__delete__()") defined always override a redefinition in an -+instance dictionary. In contrast, non-data descriptors can be -+overridden by instances. -+ -+Python methods (including those decorated with "@staticmethod" and -+"@classmethod") are implemented as non-data descriptors. Accordingly, -+instances can redefine and override methods. This allows individual -+instances to acquire behaviors that differ from other instances of the -+same class. -+ -+The "property()" function is implemented as a data descriptor. -+Accordingly, instances cannot override the behavior of a property. -+ -+ -+__slots__ -+--------- -+ -+*__slots__* allow us to explicitly declare data members (like -+properties) and deny the creation of "__dict__" and *__weakref__* -+(unless explicitly declared in *__slots__* or available in a parent.) -+ -+The space saved over using "__dict__" can be significant. Attribute -+lookup speed can be significantly improved as well. -+ -+object.__slots__ -+ -+ This class variable can be assigned a string, iterable, or sequence -+ of strings with variable names used by instances. *__slots__* -+ reserves space for the declared variables and prevents the -+ automatic creation of "__dict__" and *__weakref__* for each -+ instance. -+ -+Notes on using *__slots__*: -+ -+* When inheriting from a class without *__slots__*, the "__dict__" and -+ *__weakref__* attribute of the instances will always be accessible. -+ -+* Without a "__dict__" variable, instances cannot be assigned new -+ variables not listed in the *__slots__* definition. Attempts to -+ assign to an unlisted variable name raises "AttributeError". If -+ dynamic assignment of new variables is desired, then add -+ "'__dict__'" to the sequence of strings in the *__slots__* -+ declaration. -+ -+* Without a *__weakref__* variable for each instance, classes defining -+ *__slots__* do not support "weak references" to its instances. If -+ weak reference support is needed, then add "'__weakref__'" to the -+ sequence of strings in the *__slots__* declaration. -+ -+* *__slots__* are implemented at the class level by creating -+ descriptors for each variable name. As a result, class attributes -+ cannot be used to set default values for instance variables defined -+ by *__slots__*; otherwise, the class attribute would overwrite the -+ descriptor assignment. -+ -+* The action of a *__slots__* declaration is not limited to the class -+ where it is defined. *__slots__* declared in parents are available -+ in child classes. However, instances of a child subclass will get a -+ "__dict__" and *__weakref__* unless the subclass also defines -+ *__slots__* (which should only contain names of any *additional* -+ slots). -+ -+* If a class defines a slot also defined in a base class, the instance -+ variable defined by the base class slot is inaccessible (except by -+ retrieving its descriptor directly from the base class). This -+ renders the meaning of the program undefined. In the future, a -+ check may be added to prevent this. -+ -+* "TypeError" will be raised if nonempty *__slots__* are defined for a -+ class derived from a ""variable-length" built-in type" such as -+ "int", "bytes", and "tuple". -+ -+* Any non-string *iterable* may be assigned to *__slots__*. -+ -+* If a "dictionary" is used to assign *__slots__*, the dictionary keys -+ will be used as the slot names. The values of the dictionary can be -+ used to provide per-attribute docstrings that will be recognised by -+ "inspect.getdoc()" and displayed in the output of "help()". -+ -+* "__class__" assignment works only if both classes have the same -+ *__slots__*. -+ -+* Multiple inheritance with multiple slotted parent classes can be -+ used, but only one parent is allowed to have attributes created by -+ slots (the other bases must have empty slot layouts) - violations -+ raise "TypeError". -+ -+* If an *iterator* is used for *__slots__* then a *descriptor* is -+ created for each of the iterator’s values. However, the *__slots__* -+ attribute will be an empty iterator. -+ -+ -+Customizing class creation -+========================== -+ -+Whenever a class inherits from another class, "__init_subclass__()" is -+called on the parent class. This way, it is possible to write classes -+which change the behavior of subclasses. This is closely related to -+class decorators, but where class decorators only affect the specific -+class they’re applied to, "__init_subclass__" solely applies to future -+subclasses of the class defining the method. -+ -+classmethod object.__init_subclass__(cls) -+ -+ This method is called whenever the containing class is subclassed. -+ *cls* is then the new subclass. If defined as a normal instance -+ method, this method is implicitly converted to a class method. -+ -+ Keyword arguments which are given to a new class are passed to the -+ parent class’s "__init_subclass__". For compatibility with other -+ classes using "__init_subclass__", one should take out the needed -+ keyword arguments and pass the others over to the base class, as -+ in: -+ -+ class Philosopher: -+ def __init_subclass__(cls, /, default_name, **kwargs): -+ super().__init_subclass__(**kwargs) -+ cls.default_name = default_name -+ -+ class AustralianPhilosopher(Philosopher, default_name="Bruce"): -+ pass -+ -+ The default implementation "object.__init_subclass__" does nothing, -+ but raises an error if it is called with any arguments. -+ -+ Note: -+ -+ The metaclass hint "metaclass" is consumed by the rest of the -+ type machinery, and is never passed to "__init_subclass__" -+ implementations. The actual metaclass (rather than the explicit -+ hint) can be accessed as "type(cls)". -+ -+ Added in version 3.6. -+ -+When a class is created, "type.__new__()" scans the class variables -+and makes callbacks to those with a "__set_name__()" hook. -+ -+object.__set_name__(self, owner, name) -+ -+ Automatically called at the time the owning class *owner* is -+ created. The object has been assigned to *name* in that class: -+ -+ class A: -+ x = C() # Automatically calls: x.__set_name__(A, 'x') -+ -+ If the class variable is assigned after the class is created, -+ "__set_name__()" will not be called automatically. If needed, -+ "__set_name__()" can be called directly: -+ -+ class A: -+ pass -+ -+ c = C() -+ A.x = c # The hook is not called -+ c.__set_name__(A, 'x') # Manually invoke the hook -+ -+ See Creating the class object for more details. -+ -+ Added in version 3.6. -+ -+ -+Metaclasses -+----------- -+ -+By default, classes are constructed using "type()". The class body is -+executed in a new namespace and the class name is bound locally to the -+result of "type(name, bases, namespace)". -+ -+The class creation process can be customized by passing the -+"metaclass" keyword argument in the class definition line, or by -+inheriting from an existing class that included such an argument. In -+the following example, both "MyClass" and "MySubclass" are instances -+of "Meta": -+ -+ class Meta(type): -+ pass -+ -+ class MyClass(metaclass=Meta): -+ pass -+ -+ class MySubclass(MyClass): -+ pass -+ -+Any other keyword arguments that are specified in the class definition -+are passed through to all metaclass operations described below. -+ -+When a class definition is executed, the following steps occur: -+ -+* MRO entries are resolved; -+ -+* the appropriate metaclass is determined; -+ -+* the class namespace is prepared; -+ -+* the class body is executed; -+ -+* the class object is created. -+ -+ -+Resolving MRO entries -+--------------------- -+ -+object.__mro_entries__(self, bases) -+ -+ If a base that appears in a class definition is not an instance of -+ "type", then an "__mro_entries__()" method is searched on the base. -+ If an "__mro_entries__()" method is found, the base is substituted -+ with the result of a call to "__mro_entries__()" when creating the -+ class. The method is called with the original bases tuple passed to -+ the *bases* parameter, and must return a tuple of classes that will -+ be used instead of the base. The returned tuple may be empty: in -+ these cases, the original base is ignored. -+ -+See also: -+ -+ "types.resolve_bases()" -+ Dynamically resolve bases that are not instances of "type". -+ -+ "types.get_original_bases()" -+ Retrieve a class’s “original bases†prior to modifications by -+ "__mro_entries__()". -+ -+ **PEP 560** -+ Core support for typing module and generic types. -+ -+ -+Determining the appropriate metaclass -+------------------------------------- -+ -+The appropriate metaclass for a class definition is determined as -+follows: -+ -+* if no bases and no explicit metaclass are given, then "type()" is -+ used; -+ -+* if an explicit metaclass is given and it is *not* an instance of -+ "type()", then it is used directly as the metaclass; -+ -+* if an instance of "type()" is given as the explicit metaclass, or -+ bases are defined, then the most derived metaclass is used. -+ -+The most derived metaclass is selected from the explicitly specified -+metaclass (if any) and the metaclasses (i.e. "type(cls)") of all -+specified base classes. The most derived metaclass is one which is a -+subtype of *all* of these candidate metaclasses. If none of the -+candidate metaclasses meets that criterion, then the class definition -+will fail with "TypeError". -+ -+ -+Preparing the class namespace -+----------------------------- -+ -+Once the appropriate metaclass has been identified, then the class -+namespace is prepared. If the metaclass has a "__prepare__" attribute, -+it is called as "namespace = metaclass.__prepare__(name, bases, -+**kwds)" (where the additional keyword arguments, if any, come from -+the class definition). The "__prepare__" method should be implemented -+as a "classmethod". The namespace returned by "__prepare__" is passed -+in to "__new__", but when the final class object is created the -+namespace is copied into a new "dict". -+ -+If the metaclass has no "__prepare__" attribute, then the class -+namespace is initialised as an empty ordered mapping. -+ -+See also: -+ -+ **PEP 3115** - Metaclasses in Python 3000 -+ Introduced the "__prepare__" namespace hook -+ -+ -+Executing the class body -+------------------------ -+ -+The class body is executed (approximately) as "exec(body, globals(), -+namespace)". The key difference from a normal call to "exec()" is that -+lexical scoping allows the class body (including any methods) to -+reference names from the current and outer scopes when the class -+definition occurs inside a function. -+ -+However, even when the class definition occurs inside the function, -+methods defined inside the class still cannot see names defined at the -+class scope. Class variables must be accessed through the first -+parameter of instance or class methods, or through the implicit -+lexically scoped "__class__" reference described in the next section. -+ -+ -+Creating the class object -+------------------------- -+ -+Once the class namespace has been populated by executing the class -+body, the class object is created by calling "metaclass(name, bases, -+namespace, **kwds)" (the additional keywords passed here are the same -+as those passed to "__prepare__"). -+ -+This class object is the one that will be referenced by the zero- -+argument form of "super()". "__class__" is an implicit closure -+reference created by the compiler if any methods in a class body refer -+to either "__class__" or "super". This allows the zero argument form -+of "super()" to correctly identify the class being defined based on -+lexical scoping, while the class or instance that was used to make the -+current call is identified based on the first argument passed to the -+method. -+ -+**CPython implementation detail:** In CPython 3.6 and later, the -+"__class__" cell is passed to the metaclass as a "__classcell__" entry -+in the class namespace. If present, this must be propagated up to the -+"type.__new__" call in order for the class to be initialised -+correctly. Failing to do so will result in a "RuntimeError" in Python -+3.8. -+ -+When using the default metaclass "type", or any metaclass that -+ultimately calls "type.__new__", the following additional -+customization steps are invoked after creating the class object: -+ -+1. The "type.__new__" method collects all of the attributes in the -+ class namespace that define a "__set_name__()" method; -+ -+2. Those "__set_name__" methods are called with the class being -+ defined and the assigned name of that particular attribute; -+ -+3. The "__init_subclass__()" hook is called on the immediate parent of -+ the new class in its method resolution order. -+ -+After the class object is created, it is passed to the class -+decorators included in the class definition (if any) and the resulting -+object is bound in the local namespace as the defined class. -+ -+When a new class is created by "type.__new__", the object provided as -+the namespace parameter is copied to a new ordered mapping and the -+original object is discarded. The new copy is wrapped in a read-only -+proxy, which becomes the "__dict__" attribute of the class object. -+ -+See also: -+ -+ **PEP 3135** - New super -+ Describes the implicit "__class__" closure reference -+ -+ -+Uses for metaclasses -+-------------------- -+ -+The potential uses for metaclasses are boundless. Some ideas that have -+been explored include enum, logging, interface checking, automatic -+delegation, automatic property creation, proxies, frameworks, and -+automatic resource locking/synchronization. -+ -+ -+Customizing instance and subclass checks -+======================================== -+ -+The following methods are used to override the default behavior of the -+"isinstance()" and "issubclass()" built-in functions. -+ -+In particular, the metaclass "abc.ABCMeta" implements these methods in -+order to allow the addition of Abstract Base Classes (ABCs) as -+“virtual base classes†to any class or type (including built-in -+types), including other ABCs. -+ -+type.__instancecheck__(self, instance) -+ -+ Return true if *instance* should be considered a (direct or -+ indirect) instance of *class*. If defined, called to implement -+ "isinstance(instance, class)". -+ -+type.__subclasscheck__(self, subclass) -+ -+ Return true if *subclass* should be considered a (direct or -+ indirect) subclass of *class*. If defined, called to implement -+ "issubclass(subclass, class)". -+ -+Note that these methods are looked up on the type (metaclass) of a -+class. They cannot be defined as class methods in the actual class. -+This is consistent with the lookup of special methods that are called -+on instances, only in this case the instance is itself a class. -+ -+See also: -+ -+ **PEP 3119** - Introducing Abstract Base Classes -+ Includes the specification for customizing "isinstance()" and -+ "issubclass()" behavior through "__instancecheck__()" and -+ "__subclasscheck__()", with motivation for this functionality in -+ the context of adding Abstract Base Classes (see the "abc" -+ module) to the language. -+ -+ -+Emulating generic types -+======================= -+ -+When using *type annotations*, it is often useful to *parameterize* a -+*generic type* using Python’s square-brackets notation. For example, -+the annotation "list[int]" might be used to signify a "list" in which -+all the elements are of type "int". -+ -+See also: -+ -+ **PEP 484** - Type Hints -+ Introducing Python’s framework for type annotations -+ -+ Generic Alias Types -+ Documentation for objects representing parameterized generic -+ classes -+ -+ Generics, user-defined generics and "typing.Generic" -+ Documentation on how to implement generic classes that can be -+ parameterized at runtime and understood by static type-checkers. -+ -+A class can *generally* only be parameterized if it defines the -+special class method "__class_getitem__()". -+ -+classmethod object.__class_getitem__(cls, key) -+ -+ Return an object representing the specialization of a generic class -+ by type arguments found in *key*. -+ -+ When defined on a class, "__class_getitem__()" is automatically a -+ class method. As such, there is no need for it to be decorated with -+ "@classmethod" when it is defined. -+ -+ -+The purpose of *__class_getitem__* -+---------------------------------- -+ -+The purpose of "__class_getitem__()" is to allow runtime -+parameterization of standard-library generic classes in order to more -+easily apply *type hints* to these classes. -+ -+To implement custom generic classes that can be parameterized at -+runtime and understood by static type-checkers, users should either -+inherit from a standard library class that already implements -+"__class_getitem__()", or inherit from "typing.Generic", which has its -+own implementation of "__class_getitem__()". -+ -+Custom implementations of "__class_getitem__()" on classes defined -+outside of the standard library may not be understood by third-party -+type-checkers such as mypy. Using "__class_getitem__()" on any class -+for purposes other than type hinting is discouraged. -+ -+ -+*__class_getitem__* versus *__getitem__* -+---------------------------------------- -+ -+Usually, the subscription of an object using square brackets will call -+the "__getitem__()" instance method defined on the object’s class. -+However, if the object being subscribed is itself a class, the class -+method "__class_getitem__()" may be called instead. -+"__class_getitem__()" should return a GenericAlias object if it is -+properly defined. -+ -+Presented with the *expression* "obj[x]", the Python interpreter -+follows something like the following process to decide whether -+"__getitem__()" or "__class_getitem__()" should be called: -+ -+ from inspect import isclass -+ -+ def subscribe(obj, x): -+ """Return the result of the expression 'obj[x]'""" -+ -+ class_of_obj = type(obj) -+ -+ # If the class of obj defines __getitem__, -+ # call class_of_obj.__getitem__(obj, x) -+ if hasattr(class_of_obj, '__getitem__'): -+ return class_of_obj.__getitem__(obj, x) -+ -+ # Else, if obj is a class and defines __class_getitem__, -+ # call obj.__class_getitem__(x) -+ elif isclass(obj) and hasattr(obj, '__class_getitem__'): -+ return obj.__class_getitem__(x) -+ -+ # Else, raise an exception -+ else: -+ raise TypeError( -+ f"'{class_of_obj.__name__}' object is not subscriptable" -+ ) -+ -+In Python, all classes are themselves instances of other classes. The -+class of a class is known as that class’s *metaclass*, and most -+classes have the "type" class as their metaclass. "type" does not -+define "__getitem__()", meaning that expressions such as "list[int]", -+"dict[str, float]" and "tuple[str, bytes]" all result in -+"__class_getitem__()" being called: -+ -+ >>> # list has class "type" as its metaclass, like most classes: -+ >>> type(list) -+ -+ >>> type(dict) == type(list) == type(tuple) == type(str) == type(bytes) -+ True -+ >>> # "list[int]" calls "list.__class_getitem__(int)" -+ >>> list[int] -+ list[int] -+ >>> # list.__class_getitem__ returns a GenericAlias object: -+ >>> type(list[int]) -+ -+ -+However, if a class has a custom metaclass that defines -+"__getitem__()", subscribing the class may result in different -+behaviour. An example of this can be found in the "enum" module: -+ -+ >>> from enum import Enum -+ >>> class Menu(Enum): -+ ... """A breakfast menu""" -+ ... SPAM = 'spam' -+ ... BACON = 'bacon' -+ ... -+ >>> # Enum classes have a custom metaclass: -+ >>> type(Menu) -+ -+ >>> # EnumMeta defines __getitem__, -+ >>> # so __class_getitem__ is not called, -+ >>> # and the result is not a GenericAlias object: -+ >>> Menu['SPAM'] -+ -+ >>> type(Menu['SPAM']) -+ -+ -+See also: -+ -+ **PEP 560** - Core Support for typing module and generic types -+ Introducing "__class_getitem__()", and outlining when a -+ subscription results in "__class_getitem__()" being called -+ instead of "__getitem__()" -+ -+ -+Emulating callable objects -+========================== -+ -+object.__call__(self[, args...]) -+ -+ Called when the instance is “called†as a function; if this method -+ is defined, "x(arg1, arg2, ...)" roughly translates to -+ "type(x).__call__(x, arg1, ...)". The "object" class itself does -+ not provide this method. -+ -+ -+Emulating container types -+========================= -+ -+The following methods can be defined to implement container objects. -+None of them are provided by the "object" class itself. Containers -+usually are *sequences* (such as "lists" or "tuples") or *mappings* -+(like *dictionaries*), but can represent other containers as well. -+The first set of methods is used either to emulate a sequence or to -+emulate a mapping; the difference is that for a sequence, the -+allowable keys should be the integers *k* for which "0 <= k < N" where -+*N* is the length of the sequence, or "slice" objects, which define a -+range of items. It is also recommended that mappings provide the -+methods "keys()", "values()", "items()", "get()", "clear()", -+"setdefault()", "pop()", "popitem()", "copy()", and "update()" -+behaving similar to those for Python’s standard "dictionary" objects. -+The "collections.abc" module provides a "MutableMapping" *abstract -+base class* to help create those methods from a base set of -+"__getitem__()", "__setitem__()", "__delitem__()", and "keys()". -+Mutable sequences should provide methods "append()", "count()", -+"index()", "extend()", "insert()", "pop()", "remove()", "reverse()" -+and "sort()", like Python standard "list" objects. Finally, sequence -+types should implement addition (meaning concatenation) and -+multiplication (meaning repetition) by defining the methods -+"__add__()", "__radd__()", "__iadd__()", "__mul__()", "__rmul__()" and -+"__imul__()" described below; they should not define other numerical -+operators. It is recommended that both mappings and sequences -+implement the "__contains__()" method to allow efficient use of the -+"in" operator; for mappings, "in" should search the mapping’s keys; -+for sequences, it should search through the values. It is further -+recommended that both mappings and sequences implement the -+"__iter__()" method to allow efficient iteration through the -+container; for mappings, "__iter__()" should iterate through the -+object’s keys; for sequences, it should iterate through the values. -+ -+object.__len__(self) -+ -+ Called to implement the built-in function "len()". Should return -+ the length of the object, an integer ">=" 0. Also, an object that -+ doesn’t define a "__bool__()" method and whose "__len__()" method -+ returns zero is considered to be false in a Boolean context. -+ -+ **CPython implementation detail:** In CPython, the length is -+ required to be at most "sys.maxsize". If the length is larger than -+ "sys.maxsize" some features (such as "len()") may raise -+ "OverflowError". To prevent raising "OverflowError" by truth value -+ testing, an object must define a "__bool__()" method. -+ -+object.__length_hint__(self) -+ -+ Called to implement "operator.length_hint()". Should return an -+ estimated length for the object (which may be greater or less than -+ the actual length). The length must be an integer ">=" 0. The -+ return value may also be "NotImplemented", which is treated the -+ same as if the "__length_hint__" method didn’t exist at all. This -+ method is purely an optimization and is never required for -+ correctness. -+ -+ Added in version 3.4. -+ -+Note: -+ -+ Slicing is done exclusively with the following three methods. A -+ call like -+ -+ a[1:2] = b -+ -+ is translated to -+ -+ a[slice(1, 2, None)] = b -+ -+ and so forth. Missing slice items are always filled in with "None". -+ -+object.__getitem__(self, key) -+ -+ Called to implement evaluation of "self[key]". For *sequence* -+ types, the accepted keys should be integers. Optionally, they may -+ support "slice" objects as well. Negative index support is also -+ optional. If *key* is of an inappropriate type, "TypeError" may be -+ raised; if *key* is a value outside the set of indexes for the -+ sequence (after any special interpretation of negative values), -+ "IndexError" should be raised. For *mapping* types, if *key* is -+ missing (not in the container), "KeyError" should be raised. -+ -+ Note: -+ -+ "for" loops expect that an "IndexError" will be raised for -+ illegal indexes to allow proper detection of the end of the -+ sequence. -+ -+ Note: -+ -+ When subscripting a *class*, the special class method -+ "__class_getitem__()" may be called instead of "__getitem__()". -+ See __class_getitem__ versus __getitem__ for more details. -+ -+object.__setitem__(self, key, value) -+ -+ Called to implement assignment to "self[key]". Same note as for -+ "__getitem__()". This should only be implemented for mappings if -+ the objects support changes to the values for keys, or if new keys -+ can be added, or for sequences if elements can be replaced. The -+ same exceptions should be raised for improper *key* values as for -+ the "__getitem__()" method. -+ -+object.__delitem__(self, key) -+ -+ Called to implement deletion of "self[key]". Same note as for -+ "__getitem__()". This should only be implemented for mappings if -+ the objects support removal of keys, or for sequences if elements -+ can be removed from the sequence. The same exceptions should be -+ raised for improper *key* values as for the "__getitem__()" method. -+ -+object.__missing__(self, key) -+ -+ Called by "dict"."__getitem__()" to implement "self[key]" for dict -+ subclasses when key is not in the dictionary. -+ -+object.__iter__(self) -+ -+ This method is called when an *iterator* is required for a -+ container. This method should return a new iterator object that can -+ iterate over all the objects in the container. For mappings, it -+ should iterate over the keys of the container. -+ -+object.__reversed__(self) -+ -+ Called (if present) by the "reversed()" built-in to implement -+ reverse iteration. It should return a new iterator object that -+ iterates over all the objects in the container in reverse order. -+ -+ If the "__reversed__()" method is not provided, the "reversed()" -+ built-in will fall back to using the sequence protocol ("__len__()" -+ and "__getitem__()"). Objects that support the sequence protocol -+ should only provide "__reversed__()" if they can provide an -+ implementation that is more efficient than the one provided by -+ "reversed()". -+ -+The membership test operators ("in" and "not in") are normally -+implemented as an iteration through a container. However, container -+objects can supply the following special method with a more efficient -+implementation, which also does not require the object be iterable. -+ -+object.__contains__(self, item) -+ -+ Called to implement membership test operators. Should return true -+ if *item* is in *self*, false otherwise. For mapping objects, this -+ should consider the keys of the mapping rather than the values or -+ the key-item pairs. -+ -+ For objects that don’t define "__contains__()", the membership test -+ first tries iteration via "__iter__()", then the old sequence -+ iteration protocol via "__getitem__()", see this section in the -+ language reference. -+ -+ -+Emulating numeric types -+======================= -+ -+The following methods can be defined to emulate numeric objects. -+Methods corresponding to operations that are not supported by the -+particular kind of number implemented (e.g., bitwise operations for -+non-integral numbers) should be left undefined. -+ -+object.__add__(self, other) -+object.__sub__(self, other) -+object.__mul__(self, other) -+object.__matmul__(self, other) -+object.__truediv__(self, other) -+object.__floordiv__(self, other) -+object.__mod__(self, other) -+object.__divmod__(self, other) -+object.__pow__(self, other[, modulo]) -+object.__lshift__(self, other) -+object.__rshift__(self, other) -+object.__and__(self, other) -+object.__xor__(self, other) -+object.__or__(self, other) -+ -+ These methods are called to implement the binary arithmetic -+ operations ("+", "-", "*", "@", "/", "//", "%", "divmod()", -+ "pow()", "**", "<<", ">>", "&", "^", "|"). For instance, to -+ evaluate the expression "x + y", where *x* is an instance of a -+ class that has an "__add__()" method, "type(x).__add__(x, y)" is -+ called. The "__divmod__()" method should be the equivalent to -+ using "__floordiv__()" and "__mod__()"; it should not be related to -+ "__truediv__()". Note that "__pow__()" should be defined to accept -+ an optional third argument if the ternary version of the built-in -+ "pow()" function is to be supported. -+ -+ If one of those methods does not support the operation with the -+ supplied arguments, it should return "NotImplemented". -+ -+object.__radd__(self, other) -+object.__rsub__(self, other) -+object.__rmul__(self, other) -+object.__rmatmul__(self, other) -+object.__rtruediv__(self, other) -+object.__rfloordiv__(self, other) -+object.__rmod__(self, other) -+object.__rdivmod__(self, other) -+object.__rpow__(self, other[, modulo]) -+object.__rlshift__(self, other) -+object.__rrshift__(self, other) -+object.__rand__(self, other) -+object.__rxor__(self, other) -+object.__ror__(self, other) -+ -+ These methods are called to implement the binary arithmetic -+ operations ("+", "-", "*", "@", "/", "//", "%", "divmod()", -+ "pow()", "**", "<<", ">>", "&", "^", "|") with reflected (swapped) -+ operands. These functions are only called if the operands are of -+ different types, when the left operand does not support the -+ corresponding operation [3], or the right operand’s class is -+ derived from the left operand’s class. [4] For instance, to -+ evaluate the expression "x - y", where *y* is an instance of a -+ class that has an "__rsub__()" method, "type(y).__rsub__(y, x)" is -+ called if "type(x).__sub__(x, y)" returns "NotImplemented" or -+ "type(y)" is a subclass of "type(x)". [5] -+ -+ Note that ternary "pow()" will not try calling "__rpow__()" (the -+ coercion rules would become too complicated). -+ -+ Note: -+ -+ If the right operand’s type is a subclass of the left operand’s -+ type and that subclass provides a different implementation of the -+ reflected method for the operation, this method will be called -+ before the left operand’s non-reflected method. This behavior -+ allows subclasses to override their ancestors’ operations. -+ -+object.__iadd__(self, other) -+object.__isub__(self, other) -+object.__imul__(self, other) -+object.__imatmul__(self, other) -+object.__itruediv__(self, other) -+object.__ifloordiv__(self, other) -+object.__imod__(self, other) -+object.__ipow__(self, other[, modulo]) -+object.__ilshift__(self, other) -+object.__irshift__(self, other) -+object.__iand__(self, other) -+object.__ixor__(self, other) -+object.__ior__(self, other) -+ -+ These methods are called to implement the augmented arithmetic -+ assignments ("+=", "-=", "*=", "@=", "/=", "//=", "%=", "**=", -+ "<<=", ">>=", "&=", "^=", "|="). These methods should attempt to -+ do the operation in-place (modifying *self*) and return the result -+ (which could be, but does not have to be, *self*). If a specific -+ method is not defined, or if that method returns "NotImplemented", -+ the augmented assignment falls back to the normal methods. For -+ instance, if *x* is an instance of a class with an "__iadd__()" -+ method, "x += y" is equivalent to "x = x.__iadd__(y)" . If -+ "__iadd__()" does not exist, or if "x.__iadd__(y)" returns -+ "NotImplemented", "x.__add__(y)" and "y.__radd__(x)" are -+ considered, as with the evaluation of "x + y". In certain -+ situations, augmented assignment can result in unexpected errors -+ (see Why does a_tuple[i] += [‘item’] raise an exception when the -+ addition works?), but this behavior is in fact part of the data -+ model. -+ -+object.__neg__(self) -+object.__pos__(self) -+object.__abs__(self) -+object.__invert__(self) -+ -+ Called to implement the unary arithmetic operations ("-", "+", -+ "abs()" and "~"). -+ -+object.__complex__(self) -+object.__int__(self) -+object.__float__(self) -+ -+ Called to implement the built-in functions "complex()", "int()" and -+ "float()". Should return a value of the appropriate type. -+ -+object.__index__(self) -+ -+ Called to implement "operator.index()", and whenever Python needs -+ to losslessly convert the numeric object to an integer object (such -+ as in slicing, or in the built-in "bin()", "hex()" and "oct()" -+ functions). Presence of this method indicates that the numeric -+ object is an integer type. Must return an integer. -+ -+ If "__int__()", "__float__()" and "__complex__()" are not defined -+ then corresponding built-in functions "int()", "float()" and -+ "complex()" fall back to "__index__()". -+ -+object.__round__(self[, ndigits]) -+object.__trunc__(self) -+object.__floor__(self) -+object.__ceil__(self) -+ -+ Called to implement the built-in function "round()" and "math" -+ functions "trunc()", "floor()" and "ceil()". Unless *ndigits* is -+ passed to "__round__()" all these methods should return the value -+ of the object truncated to an "Integral" (typically an "int"). -+ -+ Changed in version 3.14: "int()" no longer delegates to the -+ "__trunc__()" method. -+ -+ -+With Statement Context Managers -+=============================== -+ -+A *context manager* is an object that defines the runtime context to -+be established when executing a "with" statement. The context manager -+handles the entry into, and the exit from, the desired runtime context -+for the execution of the block of code. Context managers are normally -+invoked using the "with" statement (described in section The with -+statement), but can also be used by directly invoking their methods. -+ -+Typical uses of context managers include saving and restoring various -+kinds of global state, locking and unlocking resources, closing opened -+files, etc. -+ -+For more information on context managers, see Context Manager Types. -+The "object" class itself does not provide the context manager -+methods. -+ -+object.__enter__(self) -+ -+ Enter the runtime context related to this object. The "with" -+ statement will bind this method’s return value to the target(s) -+ specified in the "as" clause of the statement, if any. -+ -+object.__exit__(self, exc_type, exc_value, traceback) -+ -+ Exit the runtime context related to this object. The parameters -+ describe the exception that caused the context to be exited. If the -+ context was exited without an exception, all three arguments will -+ be "None". -+ -+ If an exception is supplied, and the method wishes to suppress the -+ exception (i.e., prevent it from being propagated), it should -+ return a true value. Otherwise, the exception will be processed -+ normally upon exit from this method. -+ -+ Note that "__exit__()" methods should not reraise the passed-in -+ exception; this is the caller’s responsibility. -+ -+See also: -+ -+ **PEP 343** - The “with†statement -+ The specification, background, and examples for the Python "with" -+ statement. -+ -+ -+Customizing positional arguments in class pattern matching -+========================================================== -+ -+When using a class name in a pattern, positional arguments in the -+pattern are not allowed by default, i.e. "case MyClass(x, y)" is -+typically invalid without special support in "MyClass". To be able to -+use that kind of pattern, the class needs to define a *__match_args__* -+attribute. -+ -+object.__match_args__ -+ -+ This class variable can be assigned a tuple of strings. When this -+ class is used in a class pattern with positional arguments, each -+ positional argument will be converted into a keyword argument, -+ using the corresponding value in *__match_args__* as the keyword. -+ The absence of this attribute is equivalent to setting it to "()". -+ -+For example, if "MyClass.__match_args__" is "("left", "center", -+"right")" that means that "case MyClass(x, y)" is equivalent to "case -+MyClass(left=x, center=y)". Note that the number of arguments in the -+pattern must be smaller than or equal to the number of elements in -+*__match_args__*; if it is larger, the pattern match attempt will -+raise a "TypeError". -+ -+Added in version 3.10. -+ -+See also: -+ -+ **PEP 634** - Structural Pattern Matching -+ The specification for the Python "match" statement. -+ -+ -+Emulating buffer types -+====================== -+ -+The buffer protocol provides a way for Python objects to expose -+efficient access to a low-level memory array. This protocol is -+implemented by builtin types such as "bytes" and "memoryview", and -+third-party libraries may define additional buffer types. -+ -+While buffer types are usually implemented in C, it is also possible -+to implement the protocol in Python. -+ -+object.__buffer__(self, flags) -+ -+ Called when a buffer is requested from *self* (for example, by the -+ "memoryview" constructor). The *flags* argument is an integer -+ representing the kind of buffer requested, affecting for example -+ whether the returned buffer is read-only or writable. -+ "inspect.BufferFlags" provides a convenient way to interpret the -+ flags. The method must return a "memoryview" object. -+ -+object.__release_buffer__(self, buffer) -+ -+ Called when a buffer is no longer needed. The *buffer* argument is -+ a "memoryview" object that was previously returned by -+ "__buffer__()". The method must release any resources associated -+ with the buffer. This method should return "None". Buffer objects -+ that do not need to perform any cleanup are not required to -+ implement this method. -+ -+Added in version 3.12. -+ -+See also: -+ -+ **PEP 688** - Making the buffer protocol accessible in Python -+ Introduces the Python "__buffer__" and "__release_buffer__" -+ methods. -+ -+ "collections.abc.Buffer" -+ ABC for buffer types. -+ -+ -+Annotations -+=========== -+ -+Functions, classes, and modules may contain *annotations*, which are a -+way to associate information (usually *type hints*) with a symbol. -+ -+object.__annotations__ -+ -+ This attribute contains the annotations for an object. It is lazily -+ evaluated, so accessing the attribute may execute arbitrary code -+ and raise exceptions. If evaluation is successful, the attribute is -+ set to a dictionary mapping from variable names to annotations. -+ -+ Changed in version 3.14: Annotations are now lazily evaluated. -+ -+object.__annotate__(format) -+ -+ An *annotate function*. Returns a new dictionary object mapping -+ attribute/parameter names to their annotation values. -+ -+ Takes a format parameter specifying the format in which annotations -+ values should be provided. It must be a member of the -+ "annotationlib.Format" enum, or an integer with a value -+ corresponding to a member of the enum. -+ -+ If an annotate function doesn’t support the requested format, it -+ must raise "NotImplementedError". Annotate functions must always -+ support "VALUE" format; they must not raise "NotImplementedError()" -+ when called with this format. -+ -+ When called with "VALUE" format, an annotate function may raise -+ "NameError"; it must not raise "NameError" when called requesting -+ any other format. -+ -+ If an object does not have any annotations, "__annotate__" should -+ preferably be set to "None" (it can’t be deleted), rather than set -+ to a function that returns an empty dict. -+ -+ Added in version 3.14. -+ -+See also: -+ -+ **PEP 649** — Deferred evaluation of annotation using descriptors -+ Introduces lazy evaluation of annotations and the "__annotate__" -+ function. -+ -+ -+Special method lookup -+===================== -+ -+For custom classes, implicit invocations of special methods are only -+guaranteed to work correctly if defined on an object’s type, not in -+the object’s instance dictionary. That behaviour is the reason why -+the following code raises an exception: -+ -+ >>> class C: -+ ... pass -+ ... -+ >>> c = C() -+ >>> c.__len__ = lambda: 5 -+ >>> len(c) -+ Traceback (most recent call last): -+ File "", line 1, in -+ TypeError: object of type 'C' has no len() -+ -+The rationale behind this behaviour lies with a number of special -+methods such as "__hash__()" and "__repr__()" that are implemented by -+all objects, including type objects. If the implicit lookup of these -+methods used the conventional lookup process, they would fail when -+invoked on the type object itself: -+ -+ >>> 1 .__hash__() == hash(1) -+ True -+ >>> int.__hash__() == hash(int) -+ Traceback (most recent call last): -+ File "", line 1, in -+ TypeError: descriptor '__hash__' of 'int' object needs an argument -+ -+Incorrectly attempting to invoke an unbound method of a class in this -+way is sometimes referred to as ‘metaclass confusion’, and is avoided -+by bypassing the instance when looking up special methods: -+ -+ >>> type(1).__hash__(1) == hash(1) -+ True -+ >>> type(int).__hash__(int) == hash(int) -+ True -+ -+In addition to bypassing any instance attributes in the interest of -+correctness, implicit special method lookup generally also bypasses -+the "__getattribute__()" method even of the object’s metaclass: -+ -+ >>> class Meta(type): -+ ... def __getattribute__(*args): -+ ... print("Metaclass getattribute invoked") -+ ... return type.__getattribute__(*args) -+ ... -+ >>> class C(object, metaclass=Meta): -+ ... def __len__(self): -+ ... return 10 -+ ... def __getattribute__(*args): -+ ... print("Class getattribute invoked") -+ ... return object.__getattribute__(*args) -+ ... -+ >>> c = C() -+ >>> c.__len__() # Explicit lookup via instance -+ Class getattribute invoked -+ 10 -+ >>> type(c).__len__(c) # Explicit lookup via type -+ Metaclass getattribute invoked -+ 10 -+ >>> len(c) # Implicit lookup -+ 10 -+ -+Bypassing the "__getattribute__()" machinery in this fashion provides -+significant scope for speed optimisations within the interpreter, at -+the cost of some flexibility in the handling of special methods (the -+special method *must* be set on the class object itself in order to be -+consistently invoked by the interpreter). -+''', -+ 'string-methods': r'''String Methods -+************** -+ -+Strings implement all of the common sequence operations, along with -+the additional methods described below. -+ -+Strings also support two styles of string formatting, one providing a -+large degree of flexibility and customization (see "str.format()", -+Format String Syntax and Custom String Formatting) and the other based -+on C "printf" style formatting that handles a narrower range of types -+and is slightly harder to use correctly, but is often faster for the -+cases it can handle (printf-style String Formatting). -+ -+The Text Processing Services section of the standard library covers a -+number of other modules that provide various text related utilities -+(including regular expression support in the "re" module). -+ -+str.capitalize() -+ -+ Return a copy of the string with its first character capitalized -+ and the rest lowercased. -+ -+ Changed in version 3.8: The first character is now put into -+ titlecase rather than uppercase. This means that characters like -+ digraphs will only have their first letter capitalized, instead of -+ the full character. -+ -+str.casefold() -+ -+ Return a casefolded copy of the string. Casefolded strings may be -+ used for caseless matching. -+ -+ Casefolding is similar to lowercasing but more aggressive because -+ it is intended to remove all case distinctions in a string. For -+ example, the German lowercase letter "'ß'" is equivalent to ""ss"". -+ Since it is already lowercase, "lower()" would do nothing to "'ß'"; -+ "casefold()" converts it to ""ss"". -+ -+ The casefolding algorithm is described in section 3.13 ‘Default -+ Case Folding’ of the Unicode Standard. -+ -+ Added in version 3.3. -+ -+str.center(width[, fillchar]) -+ -+ Return centered in a string of length *width*. Padding is done -+ using the specified *fillchar* (default is an ASCII space). The -+ original string is returned if *width* is less than or equal to -+ "len(s)". -+ -+str.count(sub[, start[, end]]) -+ -+ Return the number of non-overlapping occurrences of substring *sub* -+ in the range [*start*, *end*]. Optional arguments *start* and -+ *end* are interpreted as in slice notation. -+ -+ If *sub* is empty, returns the number of empty strings between -+ characters which is the length of the string plus one. -+ -+str.encode(encoding='utf-8', errors='strict') -+ -+ Return the string encoded to "bytes". -+ -+ *encoding* defaults to "'utf-8'"; see Standard Encodings for -+ possible values. -+ -+ *errors* controls how encoding errors are handled. If "'strict'" -+ (the default), a "UnicodeError" exception is raised. Other possible -+ values are "'ignore'", "'replace'", "'xmlcharrefreplace'", -+ "'backslashreplace'" and any other name registered via -+ "codecs.register_error()". See Error Handlers for details. -+ -+ For performance reasons, the value of *errors* is not checked for -+ validity unless an encoding error actually occurs, Python -+ Development Mode is enabled or a debug build is used. -+ -+ Changed in version 3.1: Added support for keyword arguments. -+ -+ Changed in version 3.9: The value of the *errors* argument is now -+ checked in Python Development Mode and in debug mode. -+ -+str.endswith(suffix[, start[, end]]) -+ -+ Return "True" if the string ends with the specified *suffix*, -+ otherwise return "False". *suffix* can also be a tuple of suffixes -+ to look for. With optional *start*, test beginning at that -+ position. With optional *end*, stop comparing at that position. -+ -+str.expandtabs(tabsize=8) -+ -+ Return a copy of the string where all tab characters are replaced -+ by one or more spaces, depending on the current column and the -+ given tab size. Tab positions occur every *tabsize* characters -+ (default is 8, giving tab positions at columns 0, 8, 16 and so on). -+ To expand the string, the current column is set to zero and the -+ string is examined character by character. If the character is a -+ tab ("\t"), one or more space characters are inserted in the result -+ until the current column is equal to the next tab position. (The -+ tab character itself is not copied.) If the character is a newline -+ ("\n") or return ("\r"), it is copied and the current column is -+ reset to zero. Any other character is copied unchanged and the -+ current column is incremented by one regardless of how the -+ character is represented when printed. -+ -+ >>> '01\t012\t0123\t01234'.expandtabs() -+ '01 012 0123 01234' -+ >>> '01\t012\t0123\t01234'.expandtabs(4) -+ '01 012 0123 01234' -+ -+str.find(sub[, start[, end]]) -+ -+ Return the lowest index in the string where substring *sub* is -+ found within the slice "s[start:end]". Optional arguments *start* -+ and *end* are interpreted as in slice notation. Return "-1" if -+ *sub* is not found. -+ -+ Note: -+ -+ The "find()" method should be used only if you need to know the -+ position of *sub*. To check if *sub* is a substring or not, use -+ the "in" operator: -+ -+ >>> 'Py' in 'Python' -+ True -+ -+str.format(*args, **kwargs) -+ -+ Perform a string formatting operation. The string on which this -+ method is called can contain literal text or replacement fields -+ delimited by braces "{}". Each replacement field contains either -+ the numeric index of a positional argument, or the name of a -+ keyword argument. Returns a copy of the string where each -+ replacement field is replaced with the string value of the -+ corresponding argument. -+ -+ >>> "The sum of 1 + 2 is {0}".format(1+2) -+ 'The sum of 1 + 2 is 3' -+ -+ See Format String Syntax for a description of the various -+ formatting options that can be specified in format strings. -+ -+ Note: -+ -+ When formatting a number ("int", "float", "complex", -+ "decimal.Decimal" and subclasses) with the "n" type (ex: -+ "'{:n}'.format(1234)"), the function temporarily sets the -+ "LC_CTYPE" locale to the "LC_NUMERIC" locale to decode -+ "decimal_point" and "thousands_sep" fields of "localeconv()" if -+ they are non-ASCII or longer than 1 byte, and the "LC_NUMERIC" -+ locale is different than the "LC_CTYPE" locale. This temporary -+ change affects other threads. -+ -+ Changed in version 3.7: When formatting a number with the "n" type, -+ the function sets temporarily the "LC_CTYPE" locale to the -+ "LC_NUMERIC" locale in some cases. -+ -+str.format_map(mapping, /) -+ -+ Similar to "str.format(**mapping)", except that "mapping" is used -+ directly and not copied to a "dict". This is useful if for example -+ "mapping" is a dict subclass: -+ -+ >>> class Default(dict): -+ ... def __missing__(self, key): -+ ... return key -+ ... -+ >>> '{name} was born in {country}'.format_map(Default(name='Guido')) -+ 'Guido was born in country' -+ -+ Added in version 3.2. -+ -+str.index(sub[, start[, end]]) -+ -+ Like "find()", but raise "ValueError" when the substring is not -+ found. -+ -+str.isalnum() -+ -+ Return "True" if all characters in the string are alphanumeric and -+ there is at least one character, "False" otherwise. A character -+ "c" is alphanumeric if one of the following returns "True": -+ "c.isalpha()", "c.isdecimal()", "c.isdigit()", or "c.isnumeric()". -+ -+str.isalpha() -+ -+ Return "True" if all characters in the string are alphabetic and -+ there is at least one character, "False" otherwise. Alphabetic -+ characters are those characters defined in the Unicode character -+ database as “Letterâ€, i.e., those with general category property -+ being one of “Lmâ€, “Ltâ€, “Luâ€, “Llâ€, or “Loâ€. Note that this is -+ different from the Alphabetic property defined in the section 4.10 -+ ‘Letters, Alphabetic, and Ideographic’ of the Unicode Standard. -+ -+str.isascii() -+ -+ Return "True" if the string is empty or all characters in the -+ string are ASCII, "False" otherwise. ASCII characters have code -+ points in the range U+0000-U+007F. -+ -+ Added in version 3.7. -+ -+str.isdecimal() -+ -+ Return "True" if all characters in the string are decimal -+ characters and there is at least one character, "False" otherwise. -+ Decimal characters are those that can be used to form numbers in -+ base 10, e.g. U+0660, ARABIC-INDIC DIGIT ZERO. Formally a decimal -+ character is a character in the Unicode General Category “Ndâ€. -+ -+str.isdigit() -+ -+ Return "True" if all characters in the string are digits and there -+ is at least one character, "False" otherwise. Digits include -+ decimal characters and digits that need special handling, such as -+ the compatibility superscript digits. This covers digits which -+ cannot be used to form numbers in base 10, like the Kharosthi -+ numbers. Formally, a digit is a character that has the property -+ value Numeric_Type=Digit or Numeric_Type=Decimal. -+ -+str.isidentifier() -+ -+ Return "True" if the string is a valid identifier according to the -+ language definition, section Identifiers and keywords. -+ -+ "keyword.iskeyword()" can be used to test whether string "s" is a -+ reserved identifier, such as "def" and "class". -+ -+ Example: -+ -+ >>> from keyword import iskeyword -+ -+ >>> 'hello'.isidentifier(), iskeyword('hello') -+ (True, False) -+ >>> 'def'.isidentifier(), iskeyword('def') -+ (True, True) -+ -+str.islower() -+ -+ Return "True" if all cased characters [4] in the string are -+ lowercase and there is at least one cased character, "False" -+ otherwise. -+ -+str.isnumeric() -+ -+ Return "True" if all characters in the string are numeric -+ characters, and there is at least one character, "False" otherwise. -+ Numeric characters include digit characters, and all characters -+ that have the Unicode numeric value property, e.g. U+2155, VULGAR -+ FRACTION ONE FIFTH. Formally, numeric characters are those with -+ the property value Numeric_Type=Digit, Numeric_Type=Decimal or -+ Numeric_Type=Numeric. -+ -+str.isprintable() -+ -+ Return "True" if all characters in the string are printable or the -+ string is empty, "False" otherwise. Nonprintable characters are -+ those characters defined in the Unicode character database as -+ “Other†or “Separatorâ€, excepting the ASCII space (0x20) which is -+ considered printable. (Note that printable characters in this -+ context are those which should not be escaped when "repr()" is -+ invoked on a string. It has no bearing on the handling of strings -+ written to "sys.stdout" or "sys.stderr".) -+ -+str.isspace() -+ -+ Return "True" if there are only whitespace characters in the string -+ and there is at least one character, "False" otherwise. -+ -+ A character is *whitespace* if in the Unicode character database -+ (see "unicodedata"), either its general category is "Zs" -+ (“Separator, spaceâ€), or its bidirectional class is one of "WS", -+ "B", or "S". -+ -+str.istitle() -+ -+ Return "True" if the string is a titlecased string and there is at -+ least one character, for example uppercase characters may only -+ follow uncased characters and lowercase characters only cased ones. -+ Return "False" otherwise. -+ -+str.isupper() -+ -+ Return "True" if all cased characters [4] in the string are -+ uppercase and there is at least one cased character, "False" -+ otherwise. -+ -+ >>> 'BANANA'.isupper() -+ True -+ >>> 'banana'.isupper() -+ False -+ >>> 'baNana'.isupper() -+ False -+ >>> ' '.isupper() -+ False -+ -+str.join(iterable) -+ -+ Return a string which is the concatenation of the strings in -+ *iterable*. A "TypeError" will be raised if there are any non- -+ string values in *iterable*, including "bytes" objects. The -+ separator between elements is the string providing this method. -+ -+str.ljust(width[, fillchar]) -+ -+ Return the string left justified in a string of length *width*. -+ Padding is done using the specified *fillchar* (default is an ASCII -+ space). The original string is returned if *width* is less than or -+ equal to "len(s)". -+ -+str.lower() -+ -+ Return a copy of the string with all the cased characters [4] -+ converted to lowercase. -+ -+ The lowercasing algorithm used is described in section 3.13 -+ ‘Default Case Folding’ of the Unicode Standard. -+ -+str.lstrip([chars]) -+ -+ Return a copy of the string with leading characters removed. The -+ *chars* argument is a string specifying the set of characters to be -+ removed. If omitted or "None", the *chars* argument defaults to -+ removing whitespace. The *chars* argument is not a prefix; rather, -+ all combinations of its values are stripped: -+ -+ >>> ' spacious '.lstrip() -+ 'spacious ' -+ >>> 'www.example.com'.lstrip('cmowz.') -+ 'example.com' -+ -+ See "str.removeprefix()" for a method that will remove a single -+ prefix string rather than all of a set of characters. For example: -+ -+ >>> 'Arthur: three!'.lstrip('Arthur: ') -+ 'ee!' -+ >>> 'Arthur: three!'.removeprefix('Arthur: ') -+ 'three!' -+ -+static str.maketrans(x[, y[, z]]) -+ -+ This static method returns a translation table usable for -+ "str.translate()". -+ -+ If there is only one argument, it must be a dictionary mapping -+ Unicode ordinals (integers) or characters (strings of length 1) to -+ Unicode ordinals, strings (of arbitrary lengths) or "None". -+ Character keys will then be converted to ordinals. -+ -+ If there are two arguments, they must be strings of equal length, -+ and in the resulting dictionary, each character in x will be mapped -+ to the character at the same position in y. If there is a third -+ argument, it must be a string, whose characters will be mapped to -+ "None" in the result. -+ -+str.partition(sep) -+ -+ Split the string at the first occurrence of *sep*, and return a -+ 3-tuple containing the part before the separator, the separator -+ itself, and the part after the separator. If the separator is not -+ found, return a 3-tuple containing the string itself, followed by -+ two empty strings. -+ -+str.removeprefix(prefix, /) -+ -+ If the string starts with the *prefix* string, return -+ "string[len(prefix):]". Otherwise, return a copy of the original -+ string: -+ -+ >>> 'TestHook'.removeprefix('Test') -+ 'Hook' -+ >>> 'BaseTestCase'.removeprefix('Test') -+ 'BaseTestCase' -+ -+ Added in version 3.9. -+ -+str.removesuffix(suffix, /) -+ -+ If the string ends with the *suffix* string and that *suffix* is -+ not empty, return "string[:-len(suffix)]". Otherwise, return a copy -+ of the original string: -+ -+ >>> 'MiscTests'.removesuffix('Tests') -+ 'Misc' -+ >>> 'TmpDirMixin'.removesuffix('Tests') -+ 'TmpDirMixin' -+ -+ Added in version 3.9. -+ -+str.replace(old, new, count=-1) -+ -+ Return a copy of the string with all occurrences of substring *old* -+ replaced by *new*. If *count* is given, only the first *count* -+ occurrences are replaced. If *count* is not specified or "-1", then -+ all occurrences are replaced. -+ -+ Changed in version 3.13: *count* is now supported as a keyword -+ argument. -+ -+str.rfind(sub[, start[, end]]) -+ -+ Return the highest index in the string where substring *sub* is -+ found, such that *sub* is contained within "s[start:end]". -+ Optional arguments *start* and *end* are interpreted as in slice -+ notation. Return "-1" on failure. -+ -+str.rindex(sub[, start[, end]]) -+ -+ Like "rfind()" but raises "ValueError" when the substring *sub* is -+ not found. -+ -+str.rjust(width[, fillchar]) -+ -+ Return the string right justified in a string of length *width*. -+ Padding is done using the specified *fillchar* (default is an ASCII -+ space). The original string is returned if *width* is less than or -+ equal to "len(s)". -+ -+str.rpartition(sep) -+ -+ Split the string at the last occurrence of *sep*, and return a -+ 3-tuple containing the part before the separator, the separator -+ itself, and the part after the separator. If the separator is not -+ found, return a 3-tuple containing two empty strings, followed by -+ the string itself. -+ -+str.rsplit(sep=None, maxsplit=-1) -+ -+ Return a list of the words in the string, using *sep* as the -+ delimiter string. If *maxsplit* is given, at most *maxsplit* splits -+ are done, the *rightmost* ones. If *sep* is not specified or -+ "None", any whitespace string is a separator. Except for splitting -+ from the right, "rsplit()" behaves like "split()" which is -+ described in detail below. -+ -+str.rstrip([chars]) -+ -+ Return a copy of the string with trailing characters removed. The -+ *chars* argument is a string specifying the set of characters to be -+ removed. If omitted or "None", the *chars* argument defaults to -+ removing whitespace. The *chars* argument is not a suffix; rather, -+ all combinations of its values are stripped: -+ -+ >>> ' spacious '.rstrip() -+ ' spacious' -+ >>> 'mississippi'.rstrip('ipz') -+ 'mississ' -+ -+ See "str.removesuffix()" for a method that will remove a single -+ suffix string rather than all of a set of characters. For example: -+ -+ >>> 'Monty Python'.rstrip(' Python') -+ 'M' -+ >>> 'Monty Python'.removesuffix(' Python') -+ 'Monty' -+ -+str.split(sep=None, maxsplit=-1) -+ -+ Return a list of the words in the string, using *sep* as the -+ delimiter string. If *maxsplit* is given, at most *maxsplit* -+ splits are done (thus, the list will have at most "maxsplit+1" -+ elements). If *maxsplit* is not specified or "-1", then there is -+ no limit on the number of splits (all possible splits are made). -+ -+ If *sep* is given, consecutive delimiters are not grouped together -+ and are deemed to delimit empty strings (for example, -+ "'1,,2'.split(',')" returns "['1', '', '2']"). The *sep* argument -+ may consist of multiple characters as a single delimiter (to split -+ with multiple delimiters, use "re.split()"). Splitting an empty -+ string with a specified separator returns "['']". -+ -+ For example: -+ -+ >>> '1,2,3'.split(',') -+ ['1', '2', '3'] -+ >>> '1,2,3'.split(',', maxsplit=1) -+ ['1', '2,3'] -+ >>> '1,2,,3,'.split(',') -+ ['1', '2', '', '3', ''] -+ >>> '1<>2<>3<4'.split('<>') -+ ['1', '2', '3<4'] -+ -+ If *sep* is not specified or is "None", a different splitting -+ algorithm is applied: runs of consecutive whitespace are regarded -+ as a single separator, and the result will contain no empty strings -+ at the start or end if the string has leading or trailing -+ whitespace. Consequently, splitting an empty string or a string -+ consisting of just whitespace with a "None" separator returns "[]". -+ -+ For example: -+ -+ >>> '1 2 3'.split() -+ ['1', '2', '3'] -+ >>> '1 2 3'.split(maxsplit=1) -+ ['1', '2 3'] -+ >>> ' 1 2 3 '.split() -+ ['1', '2', '3'] -+ -+str.splitlines(keepends=False) -+ -+ Return a list of the lines in the string, breaking at line -+ boundaries. Line breaks are not included in the resulting list -+ unless *keepends* is given and true. -+ -+ This method splits on the following line boundaries. In -+ particular, the boundaries are a superset of *universal newlines*. -+ -+ +-------------------------+-------------------------------+ -+ | Representation | Description | -+ |=========================|===============================| -+ | "\n" | Line Feed | -+ +-------------------------+-------------------------------+ -+ | "\r" | Carriage Return | -+ +-------------------------+-------------------------------+ -+ | "\r\n" | Carriage Return + Line Feed | -+ +-------------------------+-------------------------------+ -+ | "\v" or "\x0b" | Line Tabulation | -+ +-------------------------+-------------------------------+ -+ | "\f" or "\x0c" | Form Feed | -+ +-------------------------+-------------------------------+ -+ | "\x1c" | File Separator | -+ +-------------------------+-------------------------------+ -+ | "\x1d" | Group Separator | -+ +-------------------------+-------------------------------+ -+ | "\x1e" | Record Separator | -+ +-------------------------+-------------------------------+ -+ | "\x85" | Next Line (C1 Control Code) | -+ +-------------------------+-------------------------------+ -+ | "\u2028" | Line Separator | -+ +-------------------------+-------------------------------+ -+ | "\u2029" | Paragraph Separator | -+ +-------------------------+-------------------------------+ -+ -+ Changed in version 3.2: "\v" and "\f" added to list of line -+ boundaries. -+ -+ For example: -+ -+ >>> 'ab c\n\nde fg\rkl\r\n'.splitlines() -+ ['ab c', '', 'de fg', 'kl'] -+ >>> 'ab c\n\nde fg\rkl\r\n'.splitlines(keepends=True) -+ ['ab c\n', '\n', 'de fg\r', 'kl\r\n'] -+ -+ Unlike "split()" when a delimiter string *sep* is given, this -+ method returns an empty list for the empty string, and a terminal -+ line break does not result in an extra line: -+ -+ >>> "".splitlines() -+ [] -+ >>> "One line\n".splitlines() -+ ['One line'] -+ -+ For comparison, "split('\n')" gives: -+ -+ >>> ''.split('\n') -+ [''] -+ >>> 'Two lines\n'.split('\n') -+ ['Two lines', ''] -+ -+str.startswith(prefix[, start[, end]]) -+ -+ Return "True" if string starts with the *prefix*, otherwise return -+ "False". *prefix* can also be a tuple of prefixes to look for. -+ With optional *start*, test string beginning at that position. -+ With optional *end*, stop comparing string at that position. -+ -+str.strip([chars]) -+ -+ Return a copy of the string with the leading and trailing -+ characters removed. The *chars* argument is a string specifying the -+ set of characters to be removed. If omitted or "None", the *chars* -+ argument defaults to removing whitespace. The *chars* argument is -+ not a prefix or suffix; rather, all combinations of its values are -+ stripped: -+ -+ >>> ' spacious '.strip() -+ 'spacious' -+ >>> 'www.example.com'.strip('cmowz.') -+ 'example' -+ -+ The outermost leading and trailing *chars* argument values are -+ stripped from the string. Characters are removed from the leading -+ end until reaching a string character that is not contained in the -+ set of characters in *chars*. A similar action takes place on the -+ trailing end. For example: -+ -+ >>> comment_string = '#....... Section 3.2.1 Issue #32 .......' -+ >>> comment_string.strip('.#! ') -+ 'Section 3.2.1 Issue #32' -+ -+str.swapcase() -+ -+ Return a copy of the string with uppercase characters converted to -+ lowercase and vice versa. Note that it is not necessarily true that -+ "s.swapcase().swapcase() == s". -+ -+str.title() -+ -+ Return a titlecased version of the string where words start with an -+ uppercase character and the remaining characters are lowercase. -+ -+ For example: -+ -+ >>> 'Hello world'.title() -+ 'Hello World' -+ -+ The algorithm uses a simple language-independent definition of a -+ word as groups of consecutive letters. The definition works in -+ many contexts but it means that apostrophes in contractions and -+ possessives form word boundaries, which may not be the desired -+ result: -+ -+ >>> "they're bill's friends from the UK".title() -+ "They'Re Bill'S Friends From The Uk" -+ -+ The "string.capwords()" function does not have this problem, as it -+ splits words on spaces only. -+ -+ Alternatively, a workaround for apostrophes can be constructed -+ using regular expressions: -+ -+ >>> import re -+ >>> def titlecase(s): -+ ... return re.sub(r"[A-Za-z]+('[A-Za-z]+)?", -+ ... lambda mo: mo.group(0).capitalize(), -+ ... s) -+ ... -+ >>> titlecase("they're bill's friends.") -+ "They're Bill's Friends." -+ -+str.translate(table) -+ -+ Return a copy of the string in which each character has been mapped -+ through the given translation table. The table must be an object -+ that implements indexing via "__getitem__()", typically a *mapping* -+ or *sequence*. When indexed by a Unicode ordinal (an integer), the -+ table object can do any of the following: return a Unicode ordinal -+ or a string, to map the character to one or more other characters; -+ return "None", to delete the character from the return string; or -+ raise a "LookupError" exception, to map the character to itself. -+ -+ You can use "str.maketrans()" to create a translation map from -+ character-to-character mappings in different formats. -+ -+ See also the "codecs" module for a more flexible approach to custom -+ character mappings. -+ -+str.upper() -+ -+ Return a copy of the string with all the cased characters [4] -+ converted to uppercase. Note that "s.upper().isupper()" might be -+ "False" if "s" contains uncased characters or if the Unicode -+ category of the resulting character(s) is not “Lu†(Letter, -+ uppercase), but e.g. “Lt†(Letter, titlecase). -+ -+ The uppercasing algorithm used is described in section 3.13 -+ ‘Default Case Folding’ of the Unicode Standard. -+ -+str.zfill(width) -+ -+ Return a copy of the string left filled with ASCII "'0'" digits to -+ make a string of length *width*. A leading sign prefix -+ ("'+'"/"'-'") is handled by inserting the padding *after* the sign -+ character rather than before. The original string is returned if -+ *width* is less than or equal to "len(s)". -+ -+ For example: -+ -+ >>> "42".zfill(5) -+ '00042' -+ >>> "-42".zfill(5) -+ '-0042' -+''', -+ 'strings': '''String and Bytes literals -+************************* -+ -+String literals are described by the following lexical definitions: -+ -+ **stringliteral**: ["stringprefix"]("shortstring" | "longstring") -+ **stringprefix**: "r" | "u" | "R" | "U" | "f" | "F" -+ | "fr" | "Fr" | "fR" | "FR" | "rf" | "rF" | "Rf" | "RF" -+ **shortstring**: "'" "shortstringitem"* "'" | '"' "shortstringitem"* '"' -+ **longstring**: "\'\'\'" "longstringitem"* "\'\'\'" | '"""' "longstringitem"* '"""' -+ **shortstringitem**: "shortstringchar" | "stringescapeseq" -+ **longstringitem**: "longstringchar" | "stringescapeseq" -+ **shortstringchar**: -+ **longstringchar**: -+ **stringescapeseq**: "\\" -+ -+ **bytesliteral**: "bytesprefix"("shortbytes" | "longbytes") -+ **bytesprefix**: "b" | "B" | "br" | "Br" | "bR" | "BR" | "rb" | "rB" | "Rb" | "RB" -+ **shortbytes**: "'" "shortbytesitem"* "'" | '"' "shortbytesitem"* '"' -+ **longbytes**: "\'\'\'" "longbytesitem"* "\'\'\'" | '"""' "longbytesitem"* '"""' -+ **shortbytesitem**: "shortbyteschar" | "bytesescapeseq" -+ **longbytesitem**: "longbyteschar" | "bytesescapeseq" -+ **shortbyteschar**: -+ **longbyteschar**: -+ **bytesescapeseq**: "\\" -+ -+One syntactic restriction not indicated by these productions is that -+whitespace is not allowed between the "stringprefix" or "bytesprefix" -+and the rest of the literal. The source character set is defined by -+the encoding declaration; it is UTF-8 if no encoding declaration is -+given in the source file; see section Encoding declarations. -+ -+In plain English: Both types of literals can be enclosed in matching -+single quotes ("'") or double quotes ("""). They can also be enclosed -+in matching groups of three single or double quotes (these are -+generally referred to as *triple-quoted strings*). The backslash ("\\") -+character is used to give special meaning to otherwise ordinary -+characters like "n", which means ‘newline’ when escaped ("\\n"). It can -+also be used to escape characters that otherwise have a special -+meaning, such as newline, backslash itself, or the quote character. -+See escape sequences below for examples. -+ -+Bytes literals are always prefixed with "'b'" or "'B'"; they produce -+an instance of the "bytes" type instead of the "str" type. They may -+only contain ASCII characters; bytes with a numeric value of 128 or -+greater must be expressed with escapes. -+ -+Both string and bytes literals may optionally be prefixed with a -+letter "'r'" or "'R'"; such constructs are called *raw string -+literals* and *raw bytes literals* respectively and treat backslashes -+as literal characters. As a result, in raw string literals, "'\\U'" -+and "'\\u'" escapes are not treated specially. -+ -+Added in version 3.3: The "'rb'" prefix of raw bytes literals has been -+added as a synonym of "'br'".Support for the unicode legacy literal -+("u'value'") was reintroduced to simplify the maintenance of dual -+Python 2.x and 3.x codebases. See **PEP 414** for more information. -+ -+A string literal with "'f'" or "'F'" in its prefix is a *formatted -+string literal*; see f-strings. The "'f'" may be combined with "'r'", -+but not with "'b'" or "'u'", therefore raw formatted strings are -+possible, but formatted bytes literals are not. -+ -+In triple-quoted literals, unescaped newlines and quotes are allowed -+(and are retained), except that three unescaped quotes in a row -+terminate the literal. (A “quote†is the character used to open the -+literal, i.e. either "'" or """.) -+ -+ -+Escape sequences -+================ -+ -+Unless an "'r'" or "'R'" prefix is present, escape sequences in string -+and bytes literals are interpreted according to rules similar to those -+used by Standard C. The recognized escape sequences are: -+ -++---------------------------+-----------------------------------+---------+ -+| Escape Sequence | Meaning | Notes | -+|===========================|===================================|=========| -+| "\\" | Backslash and newline ignored | (1) | -++---------------------------+-----------------------------------+---------+ -+| "\\\\" | Backslash ("\\") | | -++---------------------------+-----------------------------------+---------+ -+| "\\'" | Single quote ("'") | | -++---------------------------+-----------------------------------+---------+ -+| "\\"" | Double quote (""") | | -++---------------------------+-----------------------------------+---------+ -+| "\\a" | ASCII Bell (BEL) | | -++---------------------------+-----------------------------------+---------+ -+| "\\b" | ASCII Backspace (BS) | | -++---------------------------+-----------------------------------+---------+ -+| "\\f" | ASCII Formfeed (FF) | | -++---------------------------+-----------------------------------+---------+ -+| "\\n" | ASCII Linefeed (LF) | | -++---------------------------+-----------------------------------+---------+ -+| "\\r" | ASCII Carriage Return (CR) | | -++---------------------------+-----------------------------------+---------+ -+| "\\t" | ASCII Horizontal Tab (TAB) | | -++---------------------------+-----------------------------------+---------+ -+| "\\v" | ASCII Vertical Tab (VT) | | -++---------------------------+-----------------------------------+---------+ -+| "\\*ooo*" | Character with octal value *ooo* | (2,4) | -++---------------------------+-----------------------------------+---------+ -+| "\\x*hh*" | Character with hex value *hh* | (3,4) | -++---------------------------+-----------------------------------+---------+ -+ -+Escape sequences only recognized in string literals are: -+ -++---------------------------+-----------------------------------+---------+ -+| Escape Sequence | Meaning | Notes | -+|===========================|===================================|=========| -+| "\\N{*name*}" | Character named *name* in the | (5) | -+| | Unicode database | | -++---------------------------+-----------------------------------+---------+ -+| "\\u*xxxx*" | Character with 16-bit hex value | (6) | -+| | *xxxx* | | -++---------------------------+-----------------------------------+---------+ -+| "\\U*xxxxxxxx*" | Character with 32-bit hex value | (7) | -+| | *xxxxxxxx* | | -++---------------------------+-----------------------------------+---------+ -+ -+Notes: -+ -+1. A backslash can be added at the end of a line to ignore the -+ newline: -+ -+ >>> 'This string will not include \\ -+ ... backslashes or newline characters.' -+ 'This string will not include backslashes or newline characters.' -+ -+ The same result can be achieved using triple-quoted strings, or -+ parentheses and string literal concatenation. -+ -+2. As in Standard C, up to three octal digits are accepted. -+ -+ Changed in version 3.11: Octal escapes with value larger than -+ "0o377" produce a "DeprecationWarning". -+ -+ Changed in version 3.12: Octal escapes with value larger than -+ "0o377" produce a "SyntaxWarning". In a future Python version they -+ will be eventually a "SyntaxError". -+ -+3. Unlike in Standard C, exactly two hex digits are required. -+ -+4. In a bytes literal, hexadecimal and octal escapes denote the byte -+ with the given value. In a string literal, these escapes denote a -+ Unicode character with the given value. -+ -+5. Changed in version 3.3: Support for name aliases [1] has been -+ added. -+ -+6. Exactly four hex digits are required. -+ -+7. Any Unicode character can be encoded this way. Exactly eight hex -+ digits are required. -+ -+Unlike Standard C, all unrecognized escape sequences are left in the -+string unchanged, i.e., *the backslash is left in the result*. (This -+behavior is useful when debugging: if an escape sequence is mistyped, -+the resulting output is more easily recognized as broken.) It is also -+important to note that the escape sequences only recognized in string -+literals fall into the category of unrecognized escapes for bytes -+literals. -+ -+Changed in version 3.6: Unrecognized escape sequences produce a -+"DeprecationWarning". -+ -+Changed in version 3.12: Unrecognized escape sequences produce a -+"SyntaxWarning". In a future Python version they will be eventually a -+"SyntaxError". -+ -+Even in a raw literal, quotes can be escaped with a backslash, but the -+backslash remains in the result; for example, "r"\\""" is a valid -+string literal consisting of two characters: a backslash and a double -+quote; "r"\\"" is not a valid string literal (even a raw string cannot -+end in an odd number of backslashes). Specifically, *a raw literal -+cannot end in a single backslash* (since the backslash would escape -+the following quote character). Note also that a single backslash -+followed by a newline is interpreted as those two characters as part -+of the literal, *not* as a line continuation. -+''', -+ 'subscriptions': r'''Subscriptions -+************* -+ -+The subscription of an instance of a container class will generally -+select an element from the container. The subscription of a *generic -+class* will generally return a GenericAlias object. -+ -+ **subscription**: "primary" "[" "flexible_expression_list" "]" -+ -+When an object is subscripted, the interpreter will evaluate the -+primary and the expression list. -+ -+The primary must evaluate to an object that supports subscription. An -+object may support subscription through defining one or both of -+"__getitem__()" and "__class_getitem__()". When the primary is -+subscripted, the evaluated result of the expression list will be -+passed to one of these methods. For more details on when -+"__class_getitem__" is called instead of "__getitem__", see -+__class_getitem__ versus __getitem__. -+ -+If the expression list contains at least one comma, or if any of the -+expressions are starred, the expression list will evaluate to a -+"tuple" containing the items of the expression list. Otherwise, the -+expression list will evaluate to the value of the list’s sole member. -+ -+Changed in version 3.11: Expressions in an expression list may be -+starred. See **PEP 646**. -+ -+For built-in objects, there are two types of objects that support -+subscription via "__getitem__()": -+ -+1. Mappings. If the primary is a *mapping*, the expression list must -+ evaluate to an object whose value is one of the keys of the -+ mapping, and the subscription selects the value in the mapping that -+ corresponds to that key. An example of a builtin mapping class is -+ the "dict" class. -+ -+2. Sequences. If the primary is a *sequence*, the expression list must -+ evaluate to an "int" or a "slice" (as discussed in the following -+ section). Examples of builtin sequence classes include the "str", -+ "list" and "tuple" classes. -+ -+The formal syntax makes no special provision for negative indices in -+*sequences*. However, built-in sequences all provide a "__getitem__()" -+method that interprets negative indices by adding the length of the -+sequence to the index so that, for example, "x[-1]" selects the last -+item of "x". The resulting value must be a nonnegative integer less -+than the number of items in the sequence, and the subscription selects -+the item whose index is that value (counting from zero). Since the -+support for negative indices and slicing occurs in the object’s -+"__getitem__()" method, subclasses overriding this method will need to -+explicitly add that support. -+ -+A "string" is a special kind of sequence whose items are *characters*. -+A character is not a separate data type but a string of exactly one -+character. -+''', -+ 'truth': r'''Truth Value Testing -+******************* -+ -+Any object can be tested for truth value, for use in an "if" or -+"while" condition or as operand of the Boolean operations below. -+ -+By default, an object is considered true unless its class defines -+either a "__bool__()" method that returns "False" or a "__len__()" -+method that returns zero, when called with the object. [1] Here are -+most of the built-in objects considered false: -+ -+* constants defined to be false: "None" and "False" -+ -+* zero of any numeric type: "0", "0.0", "0j", "Decimal(0)", -+ "Fraction(0, 1)" -+ -+* empty sequences and collections: "''", "()", "[]", "{}", "set()", -+ "range(0)" -+ -+Operations and built-in functions that have a Boolean result always -+return "0" or "False" for false and "1" or "True" for true, unless -+otherwise stated. (Important exception: the Boolean operations "or" -+and "and" always return one of their operands.) -+''', -+ 'try': r'''The "try" statement -+******************* -+ -+The "try" statement specifies exception handlers and/or cleanup code -+for a group of statements: -+ -+ **try_stmt**: "try1_stmt" | "try2_stmt" | "try3_stmt" -+ **try1_stmt**: "try" ":" "suite" -+ ("except" ["expression" ["as" "identifier"]] ":" "suite")+ -+ ["else" ":" "suite"] -+ ["finally" ":" "suite"] -+ **try2_stmt**: "try" ":" "suite" -+ ("except" "*" "expression" ["as" "identifier"] ":" "suite")+ -+ ["else" ":" "suite"] -+ ["finally" ":" "suite"] -+ **try3_stmt**: "try" ":" "suite" -+ "finally" ":" "suite" -+ -+Additional information on exceptions can be found in section -+Exceptions, and information on using the "raise" statement to generate -+exceptions may be found in section The raise statement. -+ -+ -+"except" clause -+=============== -+ -+The "except" clause(s) specify one or more exception handlers. When no -+exception occurs in the "try" clause, no exception handler is -+executed. When an exception occurs in the "try" suite, a search for an -+exception handler is started. This search inspects the "except" -+clauses in turn until one is found that matches the exception. An -+expression-less "except" clause, if present, must be last; it matches -+any exception. -+ -+For an "except" clause with an expression, the expression must -+evaluate to an exception type or a tuple of exception types. The -+raised exception matches an "except" clause whose expression evaluates -+to the class or a *non-virtual base class* of the exception object, or -+to a tuple that contains such a class. -+ -+If no "except" clause matches the exception, the search for an -+exception handler continues in the surrounding code and on the -+invocation stack. [1] -+ -+If the evaluation of an expression in the header of an "except" clause -+raises an exception, the original search for a handler is canceled and -+a search starts for the new exception in the surrounding code and on -+the call stack (it is treated as if the entire "try" statement raised -+the exception). -+ -+When a matching "except" clause is found, the exception is assigned to -+the target specified after the "as" keyword in that "except" clause, -+if present, and the "except" clause’s suite is executed. All "except" -+clauses must have an executable block. When the end of this block is -+reached, execution continues normally after the entire "try" -+statement. (This means that if two nested handlers exist for the same -+exception, and the exception occurs in the "try" clause of the inner -+handler, the outer handler will not handle the exception.) -+ -+When an exception has been assigned using "as target", it is cleared -+at the end of the "except" clause. This is as if -+ -+ except E as N: -+ foo -+ -+was translated to -+ -+ except E as N: -+ try: -+ foo -+ finally: -+ del N -+ -+This means the exception must be assigned to a different name to be -+able to refer to it after the "except" clause. Exceptions are cleared -+because with the traceback attached to them, they form a reference -+cycle with the stack frame, keeping all locals in that frame alive -+until the next garbage collection occurs. -+ -+Before an "except" clause’s suite is executed, the exception is stored -+in the "sys" module, where it can be accessed from within the body of -+the "except" clause by calling "sys.exception()". When leaving an -+exception handler, the exception stored in the "sys" module is reset -+to its previous value: -+ -+ >>> print(sys.exception()) -+ None -+ >>> try: -+ ... raise TypeError -+ ... except: -+ ... print(repr(sys.exception())) -+ ... try: -+ ... raise ValueError -+ ... except: -+ ... print(repr(sys.exception())) -+ ... print(repr(sys.exception())) -+ ... -+ TypeError() -+ ValueError() -+ TypeError() -+ >>> print(sys.exception()) -+ None -+ -+ -+"except*" clause -+================ -+ -+The "except*" clause(s) are used for handling "ExceptionGroup"s. The -+exception type for matching is interpreted as in the case of "except", -+but in the case of exception groups we can have partial matches when -+the type matches some of the exceptions in the group. This means that -+multiple "except*" clauses can execute, each handling part of the -+exception group. Each clause executes at most once and handles an -+exception group of all matching exceptions. Each exception in the -+group is handled by at most one "except*" clause, the first that -+matches it. -+ -+ >>> try: -+ ... raise ExceptionGroup("eg", -+ ... [ValueError(1), TypeError(2), OSError(3), OSError(4)]) -+ ... except* TypeError as e: -+ ... print(f'caught {type(e)} with nested {e.exceptions}') -+ ... except* OSError as e: -+ ... print(f'caught {type(e)} with nested {e.exceptions}') -+ ... -+ caught with nested (TypeError(2),) -+ caught with nested (OSError(3), OSError(4)) -+ + Exception Group Traceback (most recent call last): -+ | File "", line 2, in -+ | ExceptionGroup: eg -+ +-+---------------- 1 ---------------- -+ | ValueError: 1 -+ +------------------------------------ -+ -+Any remaining exceptions that were not handled by any "except*" clause -+are re-raised at the end, along with all exceptions that were raised -+from within the "except*" clauses. If this list contains more than one -+exception to reraise, they are combined into an exception group. -+ -+If the raised exception is not an exception group and its type matches -+one of the "except*" clauses, it is caught and wrapped by an exception -+group with an empty message string. -+ -+ >>> try: -+ ... raise BlockingIOError -+ ... except* BlockingIOError as e: -+ ... print(repr(e)) -+ ... -+ ExceptionGroup('', (BlockingIOError())) -+ -+An "except*" clause must have a matching expression; it cannot be -+"except*:". Furthermore, this expression cannot contain exception -+group types, because that would have ambiguous semantics. -+ -+It is not possible to mix "except" and "except*" in the same "try". -+"break", "continue" and "return" cannot appear in an "except*" clause. -+ -+ -+"else" clause -+============= -+ -+The optional "else" clause is executed if the control flow leaves the -+"try" suite, no exception was raised, and no "return", "continue", or -+"break" statement was executed. Exceptions in the "else" clause are -+not handled by the preceding "except" clauses. -+ -+ -+"finally" clause -+================ -+ -+If "finally" is present, it specifies a ‘cleanup’ handler. The "try" -+clause is executed, including any "except" and "else" clauses. If an -+exception occurs in any of the clauses and is not handled, the -+exception is temporarily saved. The "finally" clause is executed. If -+there is a saved exception it is re-raised at the end of the "finally" -+clause. If the "finally" clause raises another exception, the saved -+exception is set as the context of the new exception. If the "finally" -+clause executes a "return", "break" or "continue" statement, the saved -+exception is discarded: -+ -+ >>> def f(): -+ ... try: -+ ... 1/0 -+ ... finally: -+ ... return 42 -+ ... -+ >>> f() -+ 42 -+ -+The exception information is not available to the program during -+execution of the "finally" clause. -+ -+When a "return", "break" or "continue" statement is executed in the -+"try" suite of a "try"…"finally" statement, the "finally" clause is -+also executed ‘on the way out.’ -+ -+The return value of a function is determined by the last "return" -+statement executed. Since the "finally" clause always executes, a -+"return" statement executed in the "finally" clause will always be the -+last one executed: -+ -+ >>> def foo(): -+ ... try: -+ ... return 'try' -+ ... finally: -+ ... return 'finally' -+ ... -+ >>> foo() -+ 'finally' -+ -+Changed in version 3.8: Prior to Python 3.8, a "continue" statement -+was illegal in the "finally" clause due to a problem with the -+implementation. -+''', -+ 'types': r'''The standard type hierarchy -+*************************** -+ -+Below is a list of the types that are built into Python. Extension -+modules (written in C, Java, or other languages, depending on the -+implementation) can define additional types. Future versions of -+Python may add types to the type hierarchy (e.g., rational numbers, -+efficiently stored arrays of integers, etc.), although such additions -+will often be provided via the standard library instead. -+ -+Some of the type descriptions below contain a paragraph listing -+‘special attributes.’ These are attributes that provide access to the -+implementation and are not intended for general use. Their definition -+may change in the future. -+ -+ -+None -+==== -+ -+This type has a single value. There is a single object with this -+value. This object is accessed through the built-in name "None". It is -+used to signify the absence of a value in many situations, e.g., it is -+returned from functions that don’t explicitly return anything. Its -+truth value is false. -+ -+ -+NotImplemented -+============== -+ -+This type has a single value. There is a single object with this -+value. This object is accessed through the built-in name -+"NotImplemented". Numeric methods and rich comparison methods should -+return this value if they do not implement the operation for the -+operands provided. (The interpreter will then try the reflected -+operation, or some other fallback, depending on the operator.) It -+should not be evaluated in a boolean context. -+ -+See Implementing the arithmetic operations for more details. -+ -+Changed in version 3.9: Evaluating "NotImplemented" in a boolean -+context was deprecated. -+ -+Changed in version 3.14: Evaluating "NotImplemented" in a boolean -+context now raises a "TypeError". It previously evaluated to "True" -+and emitted a "DeprecationWarning" since Python 3.9. -+ -+ -+Ellipsis -+======== -+ -+This type has a single value. There is a single object with this -+value. This object is accessed through the literal "..." or the built- -+in name "Ellipsis". Its truth value is true. -+ -+ -+"numbers.Number" -+================ -+ -+These are created by numeric literals and returned as results by -+arithmetic operators and arithmetic built-in functions. Numeric -+objects are immutable; once created their value never changes. Python -+numbers are of course strongly related to mathematical numbers, but -+subject to the limitations of numerical representation in computers. -+ -+The string representations of the numeric classes, computed by -+"__repr__()" and "__str__()", have the following properties: -+ -+* They are valid numeric literals which, when passed to their class -+ constructor, produce an object having the value of the original -+ numeric. -+ -+* The representation is in base 10, when possible. -+ -+* Leading zeros, possibly excepting a single zero before a decimal -+ point, are not shown. -+ -+* Trailing zeros, possibly excepting a single zero after a decimal -+ point, are not shown. -+ -+* A sign is shown only when the number is negative. -+ -+Python distinguishes between integers, floating-point numbers, and -+complex numbers: -+ -+ -+"numbers.Integral" -+------------------ -+ -+These represent elements from the mathematical set of integers -+(positive and negative). -+ -+Note: -+ -+ The rules for integer representation are intended to give the most -+ meaningful interpretation of shift and mask operations involving -+ negative integers. -+ -+There are two types of integers: -+ -+Integers ("int") -+ These represent numbers in an unlimited range, subject to available -+ (virtual) memory only. For the purpose of shift and mask -+ operations, a binary representation is assumed, and negative -+ numbers are represented in a variant of 2’s complement which gives -+ the illusion of an infinite string of sign bits extending to the -+ left. -+ -+Booleans ("bool") -+ These represent the truth values False and True. The two objects -+ representing the values "False" and "True" are the only Boolean -+ objects. The Boolean type is a subtype of the integer type, and -+ Boolean values behave like the values 0 and 1, respectively, in -+ almost all contexts, the exception being that when converted to a -+ string, the strings ""False"" or ""True"" are returned, -+ respectively. -+ -+ -+"numbers.Real" ("float") -+------------------------ -+ -+These represent machine-level double precision floating-point numbers. -+You are at the mercy of the underlying machine architecture (and C or -+Java implementation) for the accepted range and handling of overflow. -+Python does not support single-precision floating-point numbers; the -+savings in processor and memory usage that are usually the reason for -+using these are dwarfed by the overhead of using objects in Python, so -+there is no reason to complicate the language with two kinds of -+floating-point numbers. -+ -+ -+"numbers.Complex" ("complex") -+----------------------------- -+ -+These represent complex numbers as a pair of machine-level double -+precision floating-point numbers. The same caveats apply as for -+floating-point numbers. The real and imaginary parts of a complex -+number "z" can be retrieved through the read-only attributes "z.real" -+and "z.imag". -+ -+ -+Sequences -+========= -+ -+These represent finite ordered sets indexed by non-negative numbers. -+The built-in function "len()" returns the number of items of a -+sequence. When the length of a sequence is *n*, the index set contains -+the numbers 0, 1, …, *n*-1. Item *i* of sequence *a* is selected by -+"a[i]". Some sequences, including built-in sequences, interpret -+negative subscripts by adding the sequence length. For example, -+"a[-2]" equals "a[n-2]", the second to last item of sequence a with -+length "n". -+ -+Sequences also support slicing: "a[i:j]" selects all items with index -+*k* such that *i* "<=" *k* "<" *j*. When used as an expression, a -+slice is a sequence of the same type. The comment above about negative -+indexes also applies to negative slice positions. -+ -+Some sequences also support “extended slicing†with a third “step†-+parameter: "a[i:j:k]" selects all items of *a* with index *x* where "x -+= i + n*k", *n* ">=" "0" and *i* "<=" *x* "<" *j*. -+ -+Sequences are distinguished according to their mutability: -+ -+ -+Immutable sequences -+------------------- -+ -+An object of an immutable sequence type cannot change once it is -+created. (If the object contains references to other objects, these -+other objects may be mutable and may be changed; however, the -+collection of objects directly referenced by an immutable object -+cannot change.) -+ -+The following types are immutable sequences: -+ -+Strings -+ A string is a sequence of values that represent Unicode code -+ points. All the code points in the range "U+0000 - U+10FFFF" can be -+ represented in a string. Python doesn’t have a char type; instead, -+ every code point in the string is represented as a string object -+ with length "1". The built-in function "ord()" converts a code -+ point from its string form to an integer in the range "0 - 10FFFF"; -+ "chr()" converts an integer in the range "0 - 10FFFF" to the -+ corresponding length "1" string object. "str.encode()" can be used -+ to convert a "str" to "bytes" using the given text encoding, and -+ "bytes.decode()" can be used to achieve the opposite. -+ -+Tuples -+ The items of a tuple are arbitrary Python objects. Tuples of two or -+ more items are formed by comma-separated lists of expressions. A -+ tuple of one item (a ‘singleton’) can be formed by affixing a comma -+ to an expression (an expression by itself does not create a tuple, -+ since parentheses must be usable for grouping of expressions). An -+ empty tuple can be formed by an empty pair of parentheses. -+ -+Bytes -+ A bytes object is an immutable array. The items are 8-bit bytes, -+ represented by integers in the range 0 <= x < 256. Bytes literals -+ (like "b'abc'") and the built-in "bytes()" constructor can be used -+ to create bytes objects. Also, bytes objects can be decoded to -+ strings via the "decode()" method. -+ -+ -+Mutable sequences -+----------------- -+ -+Mutable sequences can be changed after they are created. The -+subscription and slicing notations can be used as the target of -+assignment and "del" (delete) statements. -+ -+Note: -+ -+ The "collections" and "array" module provide additional examples of -+ mutable sequence types. -+ -+There are currently two intrinsic mutable sequence types: -+ -+Lists -+ The items of a list are arbitrary Python objects. Lists are formed -+ by placing a comma-separated list of expressions in square -+ brackets. (Note that there are no special cases needed to form -+ lists of length 0 or 1.) -+ -+Byte Arrays -+ A bytearray object is a mutable array. They are created by the -+ built-in "bytearray()" constructor. Aside from being mutable (and -+ hence unhashable), byte arrays otherwise provide the same interface -+ and functionality as immutable "bytes" objects. -+ -+ -+Set types -+========= -+ -+These represent unordered, finite sets of unique, immutable objects. -+As such, they cannot be indexed by any subscript. However, they can be -+iterated over, and the built-in function "len()" returns the number of -+items in a set. Common uses for sets are fast membership testing, -+removing duplicates from a sequence, and computing mathematical -+operations such as intersection, union, difference, and symmetric -+difference. -+ -+For set elements, the same immutability rules apply as for dictionary -+keys. Note that numeric types obey the normal rules for numeric -+comparison: if two numbers compare equal (e.g., "1" and "1.0"), only -+one of them can be contained in a set. -+ -+There are currently two intrinsic set types: -+ -+Sets -+ These represent a mutable set. They are created by the built-in -+ "set()" constructor and can be modified afterwards by several -+ methods, such as "add()". -+ -+Frozen sets -+ These represent an immutable set. They are created by the built-in -+ "frozenset()" constructor. As a frozenset is immutable and -+ *hashable*, it can be used again as an element of another set, or -+ as a dictionary key. -+ -+ -+Mappings -+======== -+ -+These represent finite sets of objects indexed by arbitrary index -+sets. The subscript notation "a[k]" selects the item indexed by "k" -+from the mapping "a"; this can be used in expressions and as the -+target of assignments or "del" statements. The built-in function -+"len()" returns the number of items in a mapping. -+ -+There is currently a single intrinsic mapping type: -+ -+ -+Dictionaries -+------------ -+ -+These represent finite sets of objects indexed by nearly arbitrary -+values. The only types of values not acceptable as keys are values -+containing lists or dictionaries or other mutable types that are -+compared by value rather than by object identity, the reason being -+that the efficient implementation of dictionaries requires a key’s -+hash value to remain constant. Numeric types used for keys obey the -+normal rules for numeric comparison: if two numbers compare equal -+(e.g., "1" and "1.0") then they can be used interchangeably to index -+the same dictionary entry. -+ -+Dictionaries preserve insertion order, meaning that keys will be -+produced in the same order they were added sequentially over the -+dictionary. Replacing an existing key does not change the order, -+however removing a key and re-inserting it will add it to the end -+instead of keeping its old place. -+ -+Dictionaries are mutable; they can be created by the "{}" notation -+(see section Dictionary displays). -+ -+The extension modules "dbm.ndbm" and "dbm.gnu" provide additional -+examples of mapping types, as does the "collections" module. -+ -+Changed in version 3.7: Dictionaries did not preserve insertion order -+in versions of Python before 3.6. In CPython 3.6, insertion order was -+preserved, but it was considered an implementation detail at that time -+rather than a language guarantee. -+ -+ -+Callable types -+============== -+ -+These are the types to which the function call operation (see section -+Calls) can be applied: -+ -+ -+User-defined functions -+---------------------- -+ -+A user-defined function object is created by a function definition -+(see section Function definitions). It should be called with an -+argument list containing the same number of items as the function’s -+formal parameter list. -+ -+ -+Special read-only attributes -+~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ -++----------------------------------------------------+----------------------------------------------------+ -+| Attribute | Meaning | -+|====================================================|====================================================| -+| function.__globals__ | A reference to the "dictionary" that holds the | -+| | function’s global variables – the global namespace | -+| | of the module in which the function was defined. | -++----------------------------------------------------+----------------------------------------------------+ -+| function.__closure__ | "None" or a "tuple" of cells that contain bindings | -+| | for the names specified in the "co_freevars" | -+| | attribute of the function’s "code object". A cell | -+| | object has the attribute "cell_contents". This can | -+| | be used to get the value of the cell, as well as | -+| | set the value. | -++----------------------------------------------------+----------------------------------------------------+ -+ -+ -+Special writable attributes -+~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ -+Most of these attributes check the type of the assigned value: -+ -++----------------------------------------------------+----------------------------------------------------+ -+| Attribute | Meaning | -+|====================================================|====================================================| -+| function.__doc__ | The function’s documentation string, or "None" if | -+| | unavailable. | -++----------------------------------------------------+----------------------------------------------------+ -+| function.__name__ | The function’s name. See also: "__name__ | -+| | attributes". | -++----------------------------------------------------+----------------------------------------------------+ -+| function.__qualname__ | The function’s *qualified name*. See also: | -+| | "__qualname__ attributes". Added in version 3.3. | -++----------------------------------------------------+----------------------------------------------------+ -+| function.__module__ | The name of the module the function was defined | -+| | in, or "None" if unavailable. | -++----------------------------------------------------+----------------------------------------------------+ -+| function.__defaults__ | A "tuple" containing default *parameter* values | -+| | for those parameters that have defaults, or "None" | -+| | if no parameters have a default value. | -++----------------------------------------------------+----------------------------------------------------+ -+| function.__code__ | The code object representing the compiled function | -+| | body. | -++----------------------------------------------------+----------------------------------------------------+ -+| function.__dict__ | The namespace supporting arbitrary function | -+| | attributes. See also: "__dict__ attributes". | -++----------------------------------------------------+----------------------------------------------------+ -+| function.__annotations__ | A "dictionary" containing annotations of | -+| | *parameters*. The keys of the dictionary are the | -+| | parameter names, and "'return'" for the return | -+| | annotation, if provided. See also: | -+| | "object.__annotations__". Changed in version | -+| | 3.14: Annotations are now lazily evaluated. See | -+| | **PEP 649**. | -++----------------------------------------------------+----------------------------------------------------+ -+| function.__annotate__ | The *annotate function* for this function, or | -+| | "None" if the function has no annotations. See | -+| | "object.__annotate__". Added in version 3.14. | -++----------------------------------------------------+----------------------------------------------------+ -+| function.__kwdefaults__ | A "dictionary" containing defaults for keyword- | -+| | only *parameters*. | -++----------------------------------------------------+----------------------------------------------------+ -+| function.__type_params__ | A "tuple" containing the type parameters of a | -+| | generic function. Added in version 3.12. | -++----------------------------------------------------+----------------------------------------------------+ -+ -+Function objects also support getting and setting arbitrary -+attributes, which can be used, for example, to attach metadata to -+functions. Regular attribute dot-notation is used to get and set such -+attributes. -+ -+**CPython implementation detail:** CPython’s current implementation -+only supports function attributes on user-defined functions. Function -+attributes on built-in functions may be supported in the future. -+ -+Additional information about a function’s definition can be retrieved -+from its code object (accessible via the "__code__" attribute). -+ -+ -+Instance methods -+---------------- -+ -+An instance method object combines a class, a class instance and any -+callable object (normally a user-defined function). -+ -+Special read-only attributes: -+ -++----------------------------------------------------+----------------------------------------------------+ -+| method.__self__ | Refers to the class instance object to which the | -+| | method is bound | -++----------------------------------------------------+----------------------------------------------------+ -+| method.__func__ | Refers to the original function object | -++----------------------------------------------------+----------------------------------------------------+ -+| method.__doc__ | The method’s documentation (same as | -+| | "method.__func__.__doc__"). A "string" if the | -+| | original function had a docstring, else "None". | -++----------------------------------------------------+----------------------------------------------------+ -+| method.__name__ | The name of the method (same as | -+| | "method.__func__.__name__") | -++----------------------------------------------------+----------------------------------------------------+ -+| method.__module__ | The name of the module the method was defined in, | -+| | or "None" if unavailable. | -++----------------------------------------------------+----------------------------------------------------+ -+ -+Methods also support accessing (but not setting) the arbitrary -+function attributes on the underlying function object. -+ -+User-defined method objects may be created when getting an attribute -+of a class (perhaps via an instance of that class), if that attribute -+is a user-defined function object or a "classmethod" object. -+ -+When an instance method object is created by retrieving a user-defined -+function object from a class via one of its instances, its "__self__" -+attribute is the instance, and the method object is said to be -+*bound*. The new method’s "__func__" attribute is the original -+function object. -+ -+When an instance method object is created by retrieving a -+"classmethod" object from a class or instance, its "__self__" -+attribute is the class itself, and its "__func__" attribute is the -+function object underlying the class method. -+ -+When an instance method object is called, the underlying function -+("__func__") is called, inserting the class instance ("__self__") in -+front of the argument list. For instance, when "C" is a class which -+contains a definition for a function "f()", and "x" is an instance of -+"C", calling "x.f(1)" is equivalent to calling "C.f(x, 1)". -+ -+When an instance method object is derived from a "classmethod" object, -+the “class instance†stored in "__self__" will actually be the class -+itself, so that calling either "x.f(1)" or "C.f(1)" is equivalent to -+calling "f(C,1)" where "f" is the underlying function. -+ -+It is important to note that user-defined functions which are -+attributes of a class instance are not converted to bound methods; -+this *only* happens when the function is an attribute of the class. -+ -+ -+Generator functions -+------------------- -+ -+A function or method which uses the "yield" statement (see section The -+yield statement) is called a *generator function*. Such a function, -+when called, always returns an *iterator* object which can be used to -+execute the body of the function: calling the iterator’s -+"iterator.__next__()" method will cause the function to execute until -+it provides a value using the "yield" statement. When the function -+executes a "return" statement or falls off the end, a "StopIteration" -+exception is raised and the iterator will have reached the end of the -+set of values to be returned. -+ -+ -+Coroutine functions -+------------------- -+ -+A function or method which is defined using "async def" is called a -+*coroutine function*. Such a function, when called, returns a -+*coroutine* object. It may contain "await" expressions, as well as -+"async with" and "async for" statements. See also the Coroutine -+Objects section. -+ -+ -+Asynchronous generator functions -+-------------------------------- -+ -+A function or method which is defined using "async def" and which uses -+the "yield" statement is called a *asynchronous generator function*. -+Such a function, when called, returns an *asynchronous iterator* -+object which can be used in an "async for" statement to execute the -+body of the function. -+ -+Calling the asynchronous iterator’s "aiterator.__anext__" method will -+return an *awaitable* which when awaited will execute until it -+provides a value using the "yield" expression. When the function -+executes an empty "return" statement or falls off the end, a -+"StopAsyncIteration" exception is raised and the asynchronous iterator -+will have reached the end of the set of values to be yielded. -+ -+ -+Built-in functions -+------------------ -+ -+A built-in function object is a wrapper around a C function. Examples -+of built-in functions are "len()" and "math.sin()" ("math" is a -+standard built-in module). The number and type of the arguments are -+determined by the C function. Special read-only attributes: -+ -+* "__doc__" is the function’s documentation string, or "None" if -+ unavailable. See "function.__doc__". -+ -+* "__name__" is the function’s name. See "function.__name__". -+ -+* "__self__" is set to "None" (but see the next item). -+ -+* "__module__" is the name of the module the function was defined in -+ or "None" if unavailable. See "function.__module__". -+ -+ -+Built-in methods -+---------------- -+ -+This is really a different disguise of a built-in function, this time -+containing an object passed to the C function as an implicit extra -+argument. An example of a built-in method is "alist.append()", -+assuming *alist* is a list object. In this case, the special read-only -+attribute "__self__" is set to the object denoted by *alist*. (The -+attribute has the same semantics as it does with "other instance -+methods".) -+ -+ -+Classes -+------- -+ -+Classes are callable. These objects normally act as factories for new -+instances of themselves, but variations are possible for class types -+that override "__new__()". The arguments of the call are passed to -+"__new__()" and, in the typical case, to "__init__()" to initialize -+the new instance. -+ -+ -+Class Instances -+--------------- -+ -+Instances of arbitrary classes can be made callable by defining a -+"__call__()" method in their class. -+ -+ -+Modules -+======= -+ -+Modules are a basic organizational unit of Python code, and are -+created by the import system as invoked either by the "import" -+statement, or by calling functions such as "importlib.import_module()" -+and built-in "__import__()". A module object has a namespace -+implemented by a "dictionary" object (this is the dictionary -+referenced by the "__globals__" attribute of functions defined in the -+module). Attribute references are translated to lookups in this -+dictionary, e.g., "m.x" is equivalent to "m.__dict__["x"]". A module -+object does not contain the code object used to initialize the module -+(since it isn’t needed once the initialization is done). -+ -+Attribute assignment updates the module’s namespace dictionary, e.g., -+"m.x = 1" is equivalent to "m.__dict__["x"] = 1". -+ -+ -+Import-related attributes on module objects -+------------------------------------------- -+ -+Module objects have the following attributes that relate to the import -+system. When a module is created using the machinery associated with -+the import system, these attributes are filled in based on the -+module’s *spec*, before the *loader* executes and loads the module. -+ -+To create a module dynamically rather than using the import system, -+it’s recommended to use "importlib.util.module_from_spec()", which -+will set the various import-controlled attributes to appropriate -+values. It’s also possible to use the "types.ModuleType" constructor -+to create modules directly, but this technique is more error-prone, as -+most attributes must be manually set on the module object after it has -+been created when using this approach. -+ -+Caution: -+ -+ With the exception of "__name__", it is **strongly** recommended -+ that you rely on "__spec__" and its attributes instead of any of the -+ other individual attributes listed in this subsection. Note that -+ updating an attribute on "__spec__" will not update the -+ corresponding attribute on the module itself: -+ -+ >>> import typing -+ >>> typing.__name__, typing.__spec__.name -+ ('typing', 'typing') -+ >>> typing.__spec__.name = 'spelling' -+ >>> typing.__name__, typing.__spec__.name -+ ('typing', 'spelling') -+ >>> typing.__name__ = 'keyboard_smashing' -+ >>> typing.__name__, typing.__spec__.name -+ ('keyboard_smashing', 'spelling') -+ -+module.__name__ -+ -+ The name used to uniquely identify the module in the import system. -+ For a directly executed module, this will be set to ""__main__"". -+ -+ This attribute must be set to the fully qualified name of the -+ module. It is expected to match the value of -+ "module.__spec__.name". -+ -+module.__spec__ -+ -+ A record of the module’s import-system-related state. -+ -+ Set to the "module spec" that was used when importing the module. -+ See Module specs for more details. -+ -+ Added in version 3.4. -+ -+module.__package__ -+ -+ The *package* a module belongs to. -+ -+ If the module is top-level (that is, not a part of any specific -+ package) then the attribute should be set to "''" (the empty -+ string). Otherwise, it should be set to the name of the module’s -+ package (which can be equal to "module.__name__" if the module -+ itself is a package). See **PEP 366** for further details. -+ -+ This attribute is used instead of "__name__" to calculate explicit -+ relative imports for main modules. It defaults to "None" for -+ modules created dynamically using the "types.ModuleType" -+ constructor; use "importlib.util.module_from_spec()" instead to -+ ensure the attribute is set to a "str". -+ -+ It is **strongly** recommended that you use -+ "module.__spec__.parent" instead of "module.__package__". -+ "__package__" is now only used as a fallback if "__spec__.parent" -+ is not set, and this fallback path is deprecated. -+ -+ Changed in version 3.4: This attribute now defaults to "None" for -+ modules created dynamically using the "types.ModuleType" -+ constructor. Previously the attribute was optional. -+ -+ Changed in version 3.6: The value of "__package__" is expected to -+ be the same as "__spec__.parent". "__package__" is now only used as -+ a fallback during import resolution if "__spec__.parent" is not -+ defined. -+ -+ Changed in version 3.10: "ImportWarning" is raised if an import -+ resolution falls back to "__package__" instead of -+ "__spec__.parent". -+ -+ Changed in version 3.12: Raise "DeprecationWarning" instead of -+ "ImportWarning" when falling back to "__package__" during import -+ resolution. -+ -+ Deprecated since version 3.13, will be removed in version 3.15: -+ "__package__" will cease to be set or taken into consideration by -+ the import system or standard library. -+ -+module.__loader__ -+ -+ The *loader* object that the import machinery used to load the -+ module. -+ -+ This attribute is mostly useful for introspection, but can be used -+ for additional loader-specific functionality, for example getting -+ data associated with a loader. -+ -+ "__loader__" defaults to "None" for modules created dynamically -+ using the "types.ModuleType" constructor; use -+ "importlib.util.module_from_spec()" instead to ensure the attribute -+ is set to a *loader* object. -+ -+ It is **strongly** recommended that you use -+ "module.__spec__.loader" instead of "module.__loader__". -+ -+ Changed in version 3.4: This attribute now defaults to "None" for -+ modules created dynamically using the "types.ModuleType" -+ constructor. Previously the attribute was optional. -+ -+ Deprecated since version 3.12, will be removed in version 3.16: -+ Setting "__loader__" on a module while failing to set -+ "__spec__.loader" is deprecated. In Python 3.16, "__loader__" will -+ cease to be set or taken into consideration by the import system or -+ the standard library. -+ -+module.__path__ -+ -+ A (possibly empty) *sequence* of strings enumerating the locations -+ where the package’s submodules will be found. Non-package modules -+ should not have a "__path__" attribute. See __path__ attributes on -+ modules for more details. -+ -+ It is **strongly** recommended that you use -+ "module.__spec__.submodule_search_locations" instead of -+ "module.__path__". -+ -+module.__file__ -+ -+module.__cached__ -+ -+ "__file__" and "__cached__" are both optional attributes that may -+ or may not be set. Both attributes should be a "str" when they are -+ available. -+ -+ "__file__" indicates the pathname of the file from which the module -+ was loaded (if loaded from a file), or the pathname of the shared -+ library file for extension modules loaded dynamically from a shared -+ library. It might be missing for certain types of modules, such as -+ C modules that are statically linked into the interpreter, and the -+ import system may opt to leave it unset if it has no semantic -+ meaning (for example, a module loaded from a database). -+ -+ If "__file__" is set then the "__cached__" attribute might also be -+ set, which is the path to any compiled version of the code (for -+ example, a byte-compiled file). The file does not need to exist to -+ set this attribute; the path can simply point to where the compiled -+ file *would* exist (see **PEP 3147**). -+ -+ Note that "__cached__" may be set even if "__file__" is not set. -+ However, that scenario is quite atypical. Ultimately, the *loader* -+ is what makes use of the module spec provided by the *finder* (from -+ which "__file__" and "__cached__" are derived). So if a loader can -+ load from a cached module but otherwise does not load from a file, -+ that atypical scenario may be appropriate. -+ -+ It is **strongly** recommended that you use -+ "module.__spec__.cached" instead of "module.__cached__". -+ -+ Deprecated since version 3.13, will be removed in version 3.15: -+ Setting "__cached__" on a module while failing to set -+ "__spec__.cached" is deprecated. In Python 3.15, "__cached__" will -+ cease to be set or taken into consideration by the import system or -+ standard library. -+ -+ -+Other writable attributes on module objects -+------------------------------------------- -+ -+As well as the import-related attributes listed above, module objects -+also have the following writable attributes: -+ -+module.__doc__ -+ -+ The module’s documentation string, or "None" if unavailable. See -+ also: "__doc__ attributes". -+ -+module.__annotations__ -+ -+ A dictionary containing *variable annotations* collected during -+ module body execution. For best practices on working with -+ "__annotations__", see "annotationlib". -+ -+ Changed in version 3.14: Annotations are now lazily evaluated. See -+ **PEP 649**. -+ -+module.__annotate__ -+ -+ The *annotate function* for this module, or "None" if the module -+ has no annotations. See also: "__annotate__" attributes. -+ -+ Added in version 3.14. -+ -+ -+Module dictionaries -+------------------- -+ -+Module objects also have the following special read-only attribute: -+ -+module.__dict__ -+ -+ The module’s namespace as a dictionary object. Uniquely among the -+ attributes listed here, "__dict__" cannot be accessed as a global -+ variable from within a module; it can only be accessed as an -+ attribute on module objects. -+ -+ **CPython implementation detail:** Because of the way CPython -+ clears module dictionaries, the module dictionary will be cleared -+ when the module falls out of scope even if the dictionary still has -+ live references. To avoid this, copy the dictionary or keep the -+ module around while using its dictionary directly. -+ -+ -+Custom classes -+============== -+ -+Custom class types are typically created by class definitions (see -+section Class definitions). A class has a namespace implemented by a -+dictionary object. Class attribute references are translated to -+lookups in this dictionary, e.g., "C.x" is translated to -+"C.__dict__["x"]" (although there are a number of hooks which allow -+for other means of locating attributes). When the attribute name is -+not found there, the attribute search continues in the base classes. -+This search of the base classes uses the C3 method resolution order -+which behaves correctly even in the presence of ‘diamond’ inheritance -+structures where there are multiple inheritance paths leading back to -+a common ancestor. Additional details on the C3 MRO used by Python can -+be found at The Python 2.3 Method Resolution Order. -+ -+When a class attribute reference (for class "C", say) would yield a -+class method object, it is transformed into an instance method object -+whose "__self__" attribute is "C". When it would yield a -+"staticmethod" object, it is transformed into the object wrapped by -+the static method object. See section Implementing Descriptors for -+another way in which attributes retrieved from a class may differ from -+those actually contained in its "__dict__". -+ -+Class attribute assignments update the class’s dictionary, never the -+dictionary of a base class. -+ -+A class object can be called (see above) to yield a class instance -+(see below). -+ -+ -+Special attributes -+------------------ -+ -++----------------------------------------------------+----------------------------------------------------+ -+| Attribute | Meaning | -+|====================================================|====================================================| -+| type.__name__ | The class’s name. See also: "__name__ attributes". | -++----------------------------------------------------+----------------------------------------------------+ -+| type.__qualname__ | The class’s *qualified name*. See also: | -+| | "__qualname__ attributes". | -++----------------------------------------------------+----------------------------------------------------+ -+| type.__module__ | The name of the module in which the class was | -+| | defined. | -++----------------------------------------------------+----------------------------------------------------+ -+| type.__dict__ | A "mapping proxy" providing a read-only view of | -+| | the class’s namespace. See also: "__dict__ | -+| | attributes". | -++----------------------------------------------------+----------------------------------------------------+ -+| type.__bases__ | A "tuple" containing the class’s bases. In most | -+| | cases, for a class defined as "class X(A, B, C)", | -+| | "X.__bases__" will be exactly equal to "(A, B, | -+| | C)". | -++----------------------------------------------------+----------------------------------------------------+ -+| type.__doc__ | The class’s documentation string, or "None" if | -+| | undefined. Not inherited by subclasses. | -++----------------------------------------------------+----------------------------------------------------+ -+| type.__annotations__ | A dictionary containing *variable annotations* | -+| | collected during class body execution. See also: | -+| | "__annotations__ attributes". For best practices | -+| | on working with "__annotations__", please see | -+| | "annotationlib". Caution: Accessing the | -+| | "__annotations__" attribute of a class object | -+| | directly may yield incorrect results in the | -+| | presence of metaclasses. In addition, the | -+| | attribute may not exist for some classes. Use | -+| | "annotationlib.get_annotations()" to retrieve | -+| | class annotations safely. Changed in version | -+| | 3.14: Annotations are now lazily evaluated. See | -+| | **PEP 649**. | -++----------------------------------------------------+----------------------------------------------------+ -+| type.__annotate__() | The *annotate function* for this class, or "None" | -+| | if the class has no annotations. See also: | -+| | "__annotate__ attributes". Caution: Accessing | -+| | the "__annotate__" attribute of a class object | -+| | directly may yield incorrect results in the | -+| | presence of metaclasses. Use | -+| | "annotationlib.get_annotate_function()" to | -+| | retrieve the annotate function safely. Added in | -+| | version 3.14. | -++----------------------------------------------------+----------------------------------------------------+ -+| type.__type_params__ | A "tuple" containing the type parameters of a | -+| | generic class. Added in version 3.12. | -++----------------------------------------------------+----------------------------------------------------+ -+| type.__static_attributes__ | A "tuple" containing names of attributes of this | -+| | class which are assigned through "self.X" from any | -+| | function in its body. Added in version 3.13. | -++----------------------------------------------------+----------------------------------------------------+ -+| type.__firstlineno__ | The line number of the first line of the class | -+| | definition, including decorators. Setting the | -+| | "__module__" attribute removes the | -+| | "__firstlineno__" item from the type’s dictionary. | -+| | Added in version 3.13. | -++----------------------------------------------------+----------------------------------------------------+ -+| type.__mro__ | The "tuple" of classes that are considered when | -+| | looking for base classes during method resolution. | -++----------------------------------------------------+----------------------------------------------------+ -+ -+ -+Special methods -+--------------- -+ -+In addition to the special attributes described above, all Python -+classes also have the following two methods available: -+ -+type.mro() -+ -+ This method can be overridden by a metaclass to customize the -+ method resolution order for its instances. It is called at class -+ instantiation, and its result is stored in "__mro__". -+ -+type.__subclasses__() -+ -+ Each class keeps a list of weak references to its immediate -+ subclasses. This method returns a list of all those references -+ still alive. The list is in definition order. Example: -+ -+ >>> class A: pass -+ >>> class B(A): pass -+ >>> A.__subclasses__() -+ [] -+ -+ -+Class instances -+=============== -+ -+A class instance is created by calling a class object (see above). A -+class instance has a namespace implemented as a dictionary which is -+the first place in which attribute references are searched. When an -+attribute is not found there, and the instance’s class has an -+attribute by that name, the search continues with the class -+attributes. If a class attribute is found that is a user-defined -+function object, it is transformed into an instance method object -+whose "__self__" attribute is the instance. Static method and class -+method objects are also transformed; see above under “Classesâ€. See -+section Implementing Descriptors for another way in which attributes -+of a class retrieved via its instances may differ from the objects -+actually stored in the class’s "__dict__". If no class attribute is -+found, and the object’s class has a "__getattr__()" method, that is -+called to satisfy the lookup. -+ -+Attribute assignments and deletions update the instance’s dictionary, -+never a class’s dictionary. If the class has a "__setattr__()" or -+"__delattr__()" method, this is called instead of updating the -+instance dictionary directly. -+ -+Class instances can pretend to be numbers, sequences, or mappings if -+they have methods with certain special names. See section Special -+method names. -+ -+ -+Special attributes -+------------------ -+ -+object.__class__ -+ -+ The class to which a class instance belongs. -+ -+object.__dict__ -+ -+ A dictionary or other mapping object used to store an object’s -+ (writable) attributes. Not all instances have a "__dict__" -+ attribute; see the section on __slots__ for more details. -+ -+ -+I/O objects (also known as file objects) -+======================================== -+ -+A *file object* represents an open file. Various shortcuts are -+available to create file objects: the "open()" built-in function, and -+also "os.popen()", "os.fdopen()", and the "makefile()" method of -+socket objects (and perhaps by other functions or methods provided by -+extension modules). -+ -+The objects "sys.stdin", "sys.stdout" and "sys.stderr" are initialized -+to file objects corresponding to the interpreter’s standard input, -+output and error streams; they are all open in text mode and therefore -+follow the interface defined by the "io.TextIOBase" abstract class. -+ -+ -+Internal types -+============== -+ -+A few types used internally by the interpreter are exposed to the -+user. Their definitions may change with future versions of the -+interpreter, but they are mentioned here for completeness. -+ -+ -+Code objects -+------------ -+ -+Code objects represent *byte-compiled* executable Python code, or -+*bytecode*. The difference between a code object and a function object -+is that the function object contains an explicit reference to the -+function’s globals (the module in which it was defined), while a code -+object contains no context; also the default argument values are -+stored in the function object, not in the code object (because they -+represent values calculated at run-time). Unlike function objects, -+code objects are immutable and contain no references (directly or -+indirectly) to mutable objects. -+ -+ -+Special read-only attributes -+~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ -++----------------------------------------------------+----------------------------------------------------+ -+| codeobject.co_name | The function name | -++----------------------------------------------------+----------------------------------------------------+ -+| codeobject.co_qualname | The fully qualified function name Added in | -+| | version 3.11. | -++----------------------------------------------------+----------------------------------------------------+ -+| codeobject.co_argcount | The total number of positional *parameters* | -+| | (including positional-only parameters and | -+| | parameters with default values) that the function | -+| | has | -++----------------------------------------------------+----------------------------------------------------+ -+| codeobject.co_posonlyargcount | The number of positional-only *parameters* | -+| | (including arguments with default values) that the | -+| | function has | -++----------------------------------------------------+----------------------------------------------------+ -+| codeobject.co_kwonlyargcount | The number of keyword-only *parameters* (including | -+| | arguments with default values) that the function | -+| | has | -++----------------------------------------------------+----------------------------------------------------+ -+| codeobject.co_nlocals | The number of local variables used by the function | -+| | (including parameters) | -++----------------------------------------------------+----------------------------------------------------+ -+| codeobject.co_varnames | A "tuple" containing the names of the local | -+| | variables in the function (starting with the | -+| | parameter names) | -++----------------------------------------------------+----------------------------------------------------+ -+| codeobject.co_cellvars | A "tuple" containing the names of local variables | -+| | that are referenced from at least one *nested | -+| | scope* inside the function | -++----------------------------------------------------+----------------------------------------------------+ -+| codeobject.co_freevars | A "tuple" containing the names of *free (closure) | -+| | variables* that a *nested scope* references in an | -+| | outer scope. See also "function.__closure__". | -+| | Note: references to global and builtin names are | -+| | *not* included. | -++----------------------------------------------------+----------------------------------------------------+ -+| codeobject.co_code | A string representing the sequence of *bytecode* | -+| | instructions in the function | -++----------------------------------------------------+----------------------------------------------------+ -+| codeobject.co_consts | A "tuple" containing the literals used by the | -+| | *bytecode* in the function | -++----------------------------------------------------+----------------------------------------------------+ -+| codeobject.co_names | A "tuple" containing the names used by the | -+| | *bytecode* in the function | -++----------------------------------------------------+----------------------------------------------------+ -+| codeobject.co_filename | The name of the file from which the code was | -+| | compiled | -++----------------------------------------------------+----------------------------------------------------+ -+| codeobject.co_firstlineno | The line number of the first line of the function | -++----------------------------------------------------+----------------------------------------------------+ -+| codeobject.co_lnotab | A string encoding the mapping from *bytecode* | -+| | offsets to line numbers. For details, see the | -+| | source code of the interpreter. Deprecated since | -+| | version 3.12: This attribute of code objects is | -+| | deprecated, and may be removed in Python 3.15. | -++----------------------------------------------------+----------------------------------------------------+ -+| codeobject.co_stacksize | The required stack size of the code object | -++----------------------------------------------------+----------------------------------------------------+ -+| codeobject.co_flags | An "integer" encoding a number of flags for the | -+| | interpreter. | -++----------------------------------------------------+----------------------------------------------------+ -+ -+The following flag bits are defined for "co_flags": bit "0x04" is set -+if the function uses the "*arguments" syntax to accept an arbitrary -+number of positional arguments; bit "0x08" is set if the function uses -+the "**keywords" syntax to accept arbitrary keyword arguments; bit -+"0x20" is set if the function is a generator. See Code Objects Bit -+Flags for details on the semantics of each flags that might be -+present. -+ -+Future feature declarations ("from __future__ import division") also -+use bits in "co_flags" to indicate whether a code object was compiled -+with a particular feature enabled: bit "0x2000" is set if the function -+was compiled with future division enabled; bits "0x10" and "0x1000" -+were used in earlier versions of Python. -+ -+Other bits in "co_flags" are reserved for internal use. -+ -+If a code object represents a function and has a docstring, the first -+item in "co_consts" is the docstring of the function. -+ -+ -+Methods on code objects -+~~~~~~~~~~~~~~~~~~~~~~~ -+ -+codeobject.co_positions() -+ -+ Returns an iterable over the source code positions of each -+ *bytecode* instruction in the code object. -+ -+ The iterator returns "tuple"s containing the "(start_line, -+ end_line, start_column, end_column)". The *i-th* tuple corresponds -+ to the position of the source code that compiled to the *i-th* code -+ unit. Column information is 0-indexed utf-8 byte offsets on the -+ given source line. -+ -+ This positional information can be missing. A non-exhaustive lists -+ of cases where this may happen: -+ -+ * Running the interpreter with "-X" "no_debug_ranges". -+ -+ * Loading a pyc file compiled while using "-X" "no_debug_ranges". -+ -+ * Position tuples corresponding to artificial instructions. -+ -+ * Line and column numbers that can’t be represented due to -+ implementation specific limitations. -+ -+ When this occurs, some or all of the tuple elements can be "None". -+ -+ Added in version 3.11. -+ -+ Note: -+ -+ This feature requires storing column positions in code objects -+ which may result in a small increase of disk usage of compiled -+ Python files or interpreter memory usage. To avoid storing the -+ extra information and/or deactivate printing the extra traceback -+ information, the "-X" "no_debug_ranges" command line flag or the -+ "PYTHONNODEBUGRANGES" environment variable can be used. -+ -+codeobject.co_lines() -+ -+ Returns an iterator that yields information about successive ranges -+ of *bytecode*s. Each item yielded is a "(start, end, lineno)" -+ "tuple": -+ -+ * "start" (an "int") represents the offset (inclusive) of the start -+ of the *bytecode* range -+ -+ * "end" (an "int") represents the offset (exclusive) of the end of -+ the *bytecode* range -+ -+ * "lineno" is an "int" representing the line number of the -+ *bytecode* range, or "None" if the bytecodes in the given range -+ have no line number -+ -+ The items yielded will have the following properties: -+ -+ * The first range yielded will have a "start" of 0. -+ -+ * The "(start, end)" ranges will be non-decreasing and consecutive. -+ That is, for any pair of "tuple"s, the "start" of the second will -+ be equal to the "end" of the first. -+ -+ * No range will be backwards: "end >= start" for all triples. -+ -+ * The last "tuple" yielded will have "end" equal to the size of the -+ *bytecode*. -+ -+ Zero-width ranges, where "start == end", are allowed. Zero-width -+ ranges are used for lines that are present in the source code, but -+ have been eliminated by the *bytecode* compiler. -+ -+ Added in version 3.10. -+ -+ See also: -+ -+ **PEP 626** - Precise line numbers for debugging and other tools. -+ The PEP that introduced the "co_lines()" method. -+ -+codeobject.replace(**kwargs) -+ -+ Return a copy of the code object with new values for the specified -+ fields. -+ -+ Code objects are also supported by the generic function -+ "copy.replace()". -+ -+ Added in version 3.8. -+ -+ -+Frame objects -+------------- -+ -+Frame objects represent execution frames. They may occur in traceback -+objects, and are also passed to registered trace functions. -+ -+ -+Special read-only attributes -+~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ -++----------------------------------------------------+----------------------------------------------------+ -+| frame.f_back | Points to the previous stack frame (towards the | -+| | caller), or "None" if this is the bottom stack | -+| | frame | -++----------------------------------------------------+----------------------------------------------------+ -+| frame.f_code | The code object being executed in this frame. | -+| | Accessing this attribute raises an auditing event | -+| | "object.__getattr__" with arguments "obj" and | -+| | ""f_code"". | -++----------------------------------------------------+----------------------------------------------------+ -+| frame.f_locals | The mapping used by the frame to look up local | -+| | variables. If the frame refers to an *optimized | -+| | scope*, this may return a write-through proxy | -+| | object. Changed in version 3.13: Return a proxy | -+| | for optimized scopes. | -++----------------------------------------------------+----------------------------------------------------+ -+| frame.f_globals | The dictionary used by the frame to look up global | -+| | variables | -++----------------------------------------------------+----------------------------------------------------+ -+| frame.f_builtins | The dictionary used by the frame to look up built- | -+| | in (intrinsic) names | -++----------------------------------------------------+----------------------------------------------------+ -+| frame.f_lasti | The “precise instruction†of the frame object | -+| | (this is an index into the *bytecode* string of | -+| | the code object) | -++----------------------------------------------------+----------------------------------------------------+ -+ -+ -+Special writable attributes -+~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ -++----------------------------------------------------+----------------------------------------------------+ -+| frame.f_trace | If not "None", this is a function called for | -+| | various events during code execution (this is used | -+| | by debuggers). Normally an event is triggered for | -+| | each new source line (see "f_trace_lines"). | -++----------------------------------------------------+----------------------------------------------------+ -+| frame.f_trace_lines | Set this attribute to "False" to disable | -+| | triggering a tracing event for each source line. | -++----------------------------------------------------+----------------------------------------------------+ -+| frame.f_trace_opcodes | Set this attribute to "True" to allow per-opcode | -+| | events to be requested. Note that this may lead to | -+| | undefined interpreter behaviour if exceptions | -+| | raised by the trace function escape to the | -+| | function being traced. | -++----------------------------------------------------+----------------------------------------------------+ -+| frame.f_lineno | The current line number of the frame – writing to | -+| | this from within a trace function jumps to the | -+| | given line (only for the bottom-most frame). A | -+| | debugger can implement a Jump command (aka Set | -+| | Next Statement) by writing to this attribute. | -++----------------------------------------------------+----------------------------------------------------+ -+ -+ -+Frame object methods -+~~~~~~~~~~~~~~~~~~~~ -+ -+Frame objects support one method: -+ -+frame.clear() -+ -+ This method clears all references to local variables held by the -+ frame. Also, if the frame belonged to a *generator*, the generator -+ is finalized. This helps break reference cycles involving frame -+ objects (for example when catching an exception and storing its -+ traceback for later use). -+ -+ "RuntimeError" is raised if the frame is currently executing or -+ suspended. -+ -+ Added in version 3.4. -+ -+ Changed in version 3.13: Attempting to clear a suspended frame -+ raises "RuntimeError" (as has always been the case for executing -+ frames). -+ -+ -+Traceback objects -+----------------- -+ -+Traceback objects represent the stack trace of an exception. A -+traceback object is implicitly created when an exception occurs, and -+may also be explicitly created by calling "types.TracebackType". -+ -+Changed in version 3.7: Traceback objects can now be explicitly -+instantiated from Python code. -+ -+For implicitly created tracebacks, when the search for an exception -+handler unwinds the execution stack, at each unwound level a traceback -+object is inserted in front of the current traceback. When an -+exception handler is entered, the stack trace is made available to the -+program. (See section The try statement.) It is accessible as the -+third item of the tuple returned by "sys.exc_info()", and as the -+"__traceback__" attribute of the caught exception. -+ -+When the program contains no suitable handler, the stack trace is -+written (nicely formatted) to the standard error stream; if the -+interpreter is interactive, it is also made available to the user as -+"sys.last_traceback". -+ -+For explicitly created tracebacks, it is up to the creator of the -+traceback to determine how the "tb_next" attributes should be linked -+to form a full stack trace. -+ -+Special read-only attributes: -+ -++----------------------------------------------------+----------------------------------------------------+ -+| traceback.tb_frame | Points to the execution frame of the current | -+| | level. Accessing this attribute raises an | -+| | auditing event "object.__getattr__" with arguments | -+| | "obj" and ""tb_frame"". | -++----------------------------------------------------+----------------------------------------------------+ -+| traceback.tb_lineno | Gives the line number where the exception occurred | -++----------------------------------------------------+----------------------------------------------------+ -+| traceback.tb_lasti | Indicates the “precise instructionâ€. | -++----------------------------------------------------+----------------------------------------------------+ -+ -+The line number and last instruction in the traceback may differ from -+the line number of its frame object if the exception occurred in a -+"try" statement with no matching except clause or with a "finally" -+clause. -+ -+traceback.tb_next -+ -+ The special writable attribute "tb_next" is the next level in the -+ stack trace (towards the frame where the exception occurred), or -+ "None" if there is no next level. -+ -+ Changed in version 3.7: This attribute is now writable -+ -+ -+Slice objects -+------------- -+ -+Slice objects are used to represent slices for "__getitem__()" -+methods. They are also created by the built-in "slice()" function. -+ -+Special read-only attributes: "start" is the lower bound; "stop" is -+the upper bound; "step" is the step value; each is "None" if omitted. -+These attributes can have any type. -+ -+Slice objects support one method: -+ -+slice.indices(self, length) -+ -+ This method takes a single integer argument *length* and computes -+ information about the slice that the slice object would describe if -+ applied to a sequence of *length* items. It returns a tuple of -+ three integers; respectively these are the *start* and *stop* -+ indices and the *step* or stride length of the slice. Missing or -+ out-of-bounds indices are handled in a manner consistent with -+ regular slices. -+ -+ -+Static method objects -+--------------------- -+ -+Static method objects provide a way of defeating the transformation of -+function objects to method objects described above. A static method -+object is a wrapper around any other object, usually a user-defined -+method object. When a static method object is retrieved from a class -+or a class instance, the object actually returned is the wrapped -+object, which is not subject to any further transformation. Static -+method objects are also callable. Static method objects are created by -+the built-in "staticmethod()" constructor. -+ -+ -+Class method objects -+-------------------- -+ -+A class method object, like a static method object, is a wrapper -+around another object that alters the way in which that object is -+retrieved from classes and class instances. The behaviour of class -+method objects upon such retrieval is described above, under “instance -+methodsâ€. Class method objects are created by the built-in -+"classmethod()" constructor. -+''', -+ 'typesfunctions': r'''Functions -+********* -+ -+Function objects are created by function definitions. The only -+operation on a function object is to call it: "func(argument-list)". -+ -+There are really two flavors of function objects: built-in functions -+and user-defined functions. Both support the same operation (to call -+the function), but the implementation is different, hence the -+different object types. -+ -+See Function definitions for more information. -+''', -+ 'typesmapping': r'''Mapping Types — "dict" -+********************** -+ -+A *mapping* object maps *hashable* values to arbitrary objects. -+Mappings are mutable objects. There is currently only one standard -+mapping type, the *dictionary*. (For other containers see the built- -+in "list", "set", and "tuple" classes, and the "collections" module.) -+ -+A dictionary’s keys are *almost* arbitrary values. Values that are -+not *hashable*, that is, values containing lists, dictionaries or -+other mutable types (that are compared by value rather than by object -+identity) may not be used as keys. Values that compare equal (such as -+"1", "1.0", and "True") can be used interchangeably to index the same -+dictionary entry. -+ -+class dict(**kwargs) -+class dict(mapping, **kwargs) -+class dict(iterable, **kwargs) -+ -+ Return a new dictionary initialized from an optional positional -+ argument and a possibly empty set of keyword arguments. -+ -+ Dictionaries can be created by several means: -+ -+ * Use a comma-separated list of "key: value" pairs within braces: -+ "{'jack': 4098, 'sjoerd': 4127}" or "{4098: 'jack', 4127: -+ 'sjoerd'}" -+ -+ * Use a dict comprehension: "{}", "{x: x ** 2 for x in range(10)}" -+ -+ * Use the type constructor: "dict()", "dict([('foo', 100), ('bar', -+ 200)])", "dict(foo=100, bar=200)" -+ -+ If no positional argument is given, an empty dictionary is created. -+ If a positional argument is given and it defines a "keys()" method, -+ a dictionary is created by calling "__getitem__()" on the argument -+ with each returned key from the method. Otherwise, the positional -+ argument must be an *iterable* object. Each item in the iterable -+ must itself be an iterable with exactly two elements. The first -+ element of each item becomes a key in the new dictionary, and the -+ second element the corresponding value. If a key occurs more than -+ once, the last value for that key becomes the corresponding value -+ in the new dictionary. -+ -+ If keyword arguments are given, the keyword arguments and their -+ values are added to the dictionary created from the positional -+ argument. If a key being added is already present, the value from -+ the keyword argument replaces the value from the positional -+ argument. -+ -+ To illustrate, the following examples all return a dictionary equal -+ to "{"one": 1, "two": 2, "three": 3}": -+ -+ >>> a = dict(one=1, two=2, three=3) -+ >>> b = {'one': 1, 'two': 2, 'three': 3} -+ >>> c = dict(zip(['one', 'two', 'three'], [1, 2, 3])) -+ >>> d = dict([('two', 2), ('one', 1), ('three', 3)]) -+ >>> e = dict({'three': 3, 'one': 1, 'two': 2}) -+ >>> f = dict({'one': 1, 'three': 3}, two=2) -+ >>> a == b == c == d == e == f -+ True -+ -+ Providing keyword arguments as in the first example only works for -+ keys that are valid Python identifiers. Otherwise, any valid keys -+ can be used. -+ -+ These are the operations that dictionaries support (and therefore, -+ custom mapping types should support too): -+ -+ list(d) -+ -+ Return a list of all the keys used in the dictionary *d*. -+ -+ len(d) -+ -+ Return the number of items in the dictionary *d*. -+ -+ d[key] -+ -+ Return the item of *d* with key *key*. Raises a "KeyError" if -+ *key* is not in the map. -+ -+ If a subclass of dict defines a method "__missing__()" and *key* -+ is not present, the "d[key]" operation calls that method with -+ the key *key* as argument. The "d[key]" operation then returns -+ or raises whatever is returned or raised by the -+ "__missing__(key)" call. No other operations or methods invoke -+ "__missing__()". If "__missing__()" is not defined, "KeyError" -+ is raised. "__missing__()" must be a method; it cannot be an -+ instance variable: -+ -+ >>> class Counter(dict): -+ ... def __missing__(self, key): -+ ... return 0 -+ ... -+ >>> c = Counter() -+ >>> c['red'] -+ 0 -+ >>> c['red'] += 1 -+ >>> c['red'] -+ 1 -+ -+ The example above shows part of the implementation of -+ "collections.Counter". A different "__missing__" method is used -+ by "collections.defaultdict". -+ -+ d[key] = value -+ -+ Set "d[key]" to *value*. -+ -+ del d[key] -+ -+ Remove "d[key]" from *d*. Raises a "KeyError" if *key* is not -+ in the map. -+ -+ key in d -+ -+ Return "True" if *d* has a key *key*, else "False". -+ -+ key not in d -+ -+ Equivalent to "not key in d". -+ -+ iter(d) -+ -+ Return an iterator over the keys of the dictionary. This is a -+ shortcut for "iter(d.keys())". -+ -+ clear() -+ -+ Remove all items from the dictionary. -+ -+ copy() -+ -+ Return a shallow copy of the dictionary. -+ -+ classmethod fromkeys(iterable, value=None, /) -+ -+ Create a new dictionary with keys from *iterable* and values set -+ to *value*. -+ -+ "fromkeys()" is a class method that returns a new dictionary. -+ *value* defaults to "None". All of the values refer to just a -+ single instance, so it generally doesn’t make sense for *value* -+ to be a mutable object such as an empty list. To get distinct -+ values, use a dict comprehension instead. -+ -+ get(key, default=None) -+ -+ Return the value for *key* if *key* is in the dictionary, else -+ *default*. If *default* is not given, it defaults to "None", so -+ that this method never raises a "KeyError". -+ -+ items() -+ -+ Return a new view of the dictionary’s items ("(key, value)" -+ pairs). See the documentation of view objects. -+ -+ keys() -+ -+ Return a new view of the dictionary’s keys. See the -+ documentation of view objects. -+ -+ pop(key[, default]) -+ -+ If *key* is in the dictionary, remove it and return its value, -+ else return *default*. If *default* is not given and *key* is -+ not in the dictionary, a "KeyError" is raised. -+ -+ popitem() -+ -+ Remove and return a "(key, value)" pair from the dictionary. -+ Pairs are returned in LIFO (last-in, first-out) order. -+ -+ "popitem()" is useful to destructively iterate over a -+ dictionary, as often used in set algorithms. If the dictionary -+ is empty, calling "popitem()" raises a "KeyError". -+ -+ Changed in version 3.7: LIFO order is now guaranteed. In prior -+ versions, "popitem()" would return an arbitrary key/value pair. -+ -+ reversed(d) -+ -+ Return a reverse iterator over the keys of the dictionary. This -+ is a shortcut for "reversed(d.keys())". -+ -+ Added in version 3.8. -+ -+ setdefault(key, default=None) -+ -+ If *key* is in the dictionary, return its value. If not, insert -+ *key* with a value of *default* and return *default*. *default* -+ defaults to "None". -+ -+ update([other]) -+ -+ Update the dictionary with the key/value pairs from *other*, -+ overwriting existing keys. Return "None". -+ -+ "update()" accepts either another object with a "keys()" method -+ (in which case "__getitem__()" is called with every key returned -+ from the method) or an iterable of key/value pairs (as tuples or -+ other iterables of length two). If keyword arguments are -+ specified, the dictionary is then updated with those key/value -+ pairs: "d.update(red=1, blue=2)". -+ -+ values() -+ -+ Return a new view of the dictionary’s values. See the -+ documentation of view objects. -+ -+ An equality comparison between one "dict.values()" view and -+ another will always return "False". This also applies when -+ comparing "dict.values()" to itself: -+ -+ >>> d = {'a': 1} -+ >>> d.values() == d.values() -+ False -+ -+ d | other -+ -+ Create a new dictionary with the merged keys and values of *d* -+ and *other*, which must both be dictionaries. The values of -+ *other* take priority when *d* and *other* share keys. -+ -+ Added in version 3.9. -+ -+ d |= other -+ -+ Update the dictionary *d* with keys and values from *other*, -+ which may be either a *mapping* or an *iterable* of key/value -+ pairs. The values of *other* take priority when *d* and *other* -+ share keys. -+ -+ Added in version 3.9. -+ -+ Dictionaries compare equal if and only if they have the same "(key, -+ value)" pairs (regardless of ordering). Order comparisons (‘<’, -+ ‘<=’, ‘>=’, ‘>’) raise "TypeError". -+ -+ Dictionaries preserve insertion order. Note that updating a key -+ does not affect the order. Keys added after deletion are inserted -+ at the end. -+ -+ >>> d = {"one": 1, "two": 2, "three": 3, "four": 4} -+ >>> d -+ {'one': 1, 'two': 2, 'three': 3, 'four': 4} -+ >>> list(d) -+ ['one', 'two', 'three', 'four'] -+ >>> list(d.values()) -+ [1, 2, 3, 4] -+ >>> d["one"] = 42 -+ >>> d -+ {'one': 42, 'two': 2, 'three': 3, 'four': 4} -+ >>> del d["two"] -+ >>> d["two"] = None -+ >>> d -+ {'one': 42, 'three': 3, 'four': 4, 'two': None} -+ -+ Changed in version 3.7: Dictionary order is guaranteed to be -+ insertion order. This behavior was an implementation detail of -+ CPython from 3.6. -+ -+ Dictionaries and dictionary views are reversible. -+ -+ >>> d = {"one": 1, "two": 2, "three": 3, "four": 4} -+ >>> d -+ {'one': 1, 'two': 2, 'three': 3, 'four': 4} -+ >>> list(reversed(d)) -+ ['four', 'three', 'two', 'one'] -+ >>> list(reversed(d.values())) -+ [4, 3, 2, 1] -+ >>> list(reversed(d.items())) -+ [('four', 4), ('three', 3), ('two', 2), ('one', 1)] -+ -+ Changed in version 3.8: Dictionaries are now reversible. -+ -+See also: -+ -+ "types.MappingProxyType" can be used to create a read-only view of a -+ "dict". -+ -+ -+Dictionary view objects -+======================= -+ -+The objects returned by "dict.keys()", "dict.values()" and -+"dict.items()" are *view objects*. They provide a dynamic view on the -+dictionary’s entries, which means that when the dictionary changes, -+the view reflects these changes. -+ -+Dictionary views can be iterated over to yield their respective data, -+and support membership tests: -+ -+len(dictview) -+ -+ Return the number of entries in the dictionary. -+ -+iter(dictview) -+ -+ Return an iterator over the keys, values or items (represented as -+ tuples of "(key, value)") in the dictionary. -+ -+ Keys and values are iterated over in insertion order. This allows -+ the creation of "(value, key)" pairs using "zip()": "pairs = -+ zip(d.values(), d.keys())". Another way to create the same list is -+ "pairs = [(v, k) for (k, v) in d.items()]". -+ -+ Iterating views while adding or deleting entries in the dictionary -+ may raise a "RuntimeError" or fail to iterate over all entries. -+ -+ Changed in version 3.7: Dictionary order is guaranteed to be -+ insertion order. -+ -+x in dictview -+ -+ Return "True" if *x* is in the underlying dictionary’s keys, values -+ or items (in the latter case, *x* should be a "(key, value)" -+ tuple). -+ -+reversed(dictview) -+ -+ Return a reverse iterator over the keys, values or items of the -+ dictionary. The view will be iterated in reverse order of the -+ insertion. -+ -+ Changed in version 3.8: Dictionary views are now reversible. -+ -+dictview.mapping -+ -+ Return a "types.MappingProxyType" that wraps the original -+ dictionary to which the view refers. -+ -+ Added in version 3.10. -+ -+Keys views are set-like since their entries are unique and *hashable*. -+Items views also have set-like operations since the (key, value) pairs -+are unique and the keys are hashable. If all values in an items view -+are hashable as well, then the items view can interoperate with other -+sets. (Values views are not treated as set-like since the entries are -+generally not unique.) For set-like views, all of the operations -+defined for the abstract base class "collections.abc.Set" are -+available (for example, "==", "<", or "^"). While using set -+operators, set-like views accept any iterable as the other operand, -+unlike sets which only accept sets as the input. -+ -+An example of dictionary view usage: -+ -+ >>> dishes = {'eggs': 2, 'sausage': 1, 'bacon': 1, 'spam': 500} -+ >>> keys = dishes.keys() -+ >>> values = dishes.values() -+ -+ >>> # iteration -+ >>> n = 0 -+ >>> for val in values: -+ ... n += val -+ ... -+ >>> print(n) -+ 504 -+ -+ >>> # keys and values are iterated over in the same order (insertion order) -+ >>> list(keys) -+ ['eggs', 'sausage', 'bacon', 'spam'] -+ >>> list(values) -+ [2, 1, 1, 500] -+ -+ >>> # view objects are dynamic and reflect dict changes -+ >>> del dishes['eggs'] -+ >>> del dishes['sausage'] -+ >>> list(keys) -+ ['bacon', 'spam'] -+ -+ >>> # set operations -+ >>> keys & {'eggs', 'bacon', 'salad'} -+ {'bacon'} -+ >>> keys ^ {'sausage', 'juice'} == {'juice', 'sausage', 'bacon', 'spam'} -+ True -+ >>> keys | ['juice', 'juice', 'juice'] == {'bacon', 'spam', 'juice'} -+ True -+ -+ >>> # get back a read-only proxy for the original dictionary -+ >>> values.mapping -+ mappingproxy({'bacon': 1, 'spam': 500}) -+ >>> values.mapping['spam'] -+ 500 -+''', -+ 'typesmethods': r'''Methods -+******* -+ -+Methods are functions that are called using the attribute notation. -+There are two flavors: built-in methods (such as "append()" on lists) -+and class instance method. Built-in methods are described with the -+types that support them. -+ -+If you access a method (a function defined in a class namespace) -+through an instance, you get a special object: a *bound method* (also -+called instance method) object. When called, it will add the "self" -+argument to the argument list. Bound methods have two special read- -+only attributes: "m.__self__" is the object on which the method -+operates, and "m.__func__" is the function implementing the method. -+Calling "m(arg-1, arg-2, ..., arg-n)" is completely equivalent to -+calling "m.__func__(m.__self__, arg-1, arg-2, ..., arg-n)". -+ -+Like function objects, bound method objects support getting arbitrary -+attributes. However, since method attributes are actually stored on -+the underlying function object ("method.__func__"), setting method -+attributes on bound methods is disallowed. Attempting to set an -+attribute on a method results in an "AttributeError" being raised. In -+order to set a method attribute, you need to explicitly set it on the -+underlying function object: -+ -+ >>> class C: -+ ... def method(self): -+ ... pass -+ ... -+ >>> c = C() -+ >>> c.method.whoami = 'my name is method' # can't set on the method -+ Traceback (most recent call last): -+ File "", line 1, in -+ AttributeError: 'method' object has no attribute 'whoami' -+ >>> c.method.__func__.whoami = 'my name is method' -+ >>> c.method.whoami -+ 'my name is method' -+ -+See Instance methods for more information. -+''', -+ 'typesmodules': r'''Modules -+******* -+ -+The only special operation on a module is attribute access: "m.name", -+where *m* is a module and *name* accesses a name defined in *m*’s -+symbol table. Module attributes can be assigned to. (Note that the -+"import" statement is not, strictly speaking, an operation on a module -+object; "import foo" does not require a module object named *foo* to -+exist, rather it requires an (external) *definition* for a module -+named *foo* somewhere.) -+ -+A special attribute of every module is "__dict__". This is the -+dictionary containing the module’s symbol table. Modifying this -+dictionary will actually change the module’s symbol table, but direct -+assignment to the "__dict__" attribute is not possible (you can write -+"m.__dict__['a'] = 1", which defines "m.a" to be "1", but you can’t -+write "m.__dict__ = {}"). Modifying "__dict__" directly is not -+recommended. -+ -+Modules built into the interpreter are written like this: "". If loaded from a file, they are written as -+"". -+''', -+ 'typesseq': r'''Sequence Types — "list", "tuple", "range" -+***************************************** -+ -+There are three basic sequence types: lists, tuples, and range -+objects. Additional sequence types tailored for processing of binary -+data and text strings are described in dedicated sections. -+ -+ -+Common Sequence Operations -+========================== -+ -+The operations in the following table are supported by most sequence -+types, both mutable and immutable. The "collections.abc.Sequence" ABC -+is provided to make it easier to correctly implement these operations -+on custom sequence types. -+ -+This table lists the sequence operations sorted in ascending priority. -+In the table, *s* and *t* are sequences of the same type, *n*, *i*, -+*j* and *k* are integers and *x* is an arbitrary object that meets any -+type and value restrictions imposed by *s*. -+ -+The "in" and "not in" operations have the same priorities as the -+comparison operations. The "+" (concatenation) and "*" (repetition) -+operations have the same priority as the corresponding numeric -+operations. [3] -+ -++----------------------------+----------------------------------+------------+ -+| Operation | Result | Notes | -+|============================|==================================|============| -+| "x in s" | "True" if an item of *s* is | (1) | -+| | equal to *x*, else "False" | | -++----------------------------+----------------------------------+------------+ -+| "x not in s" | "False" if an item of *s* is | (1) | -+| | equal to *x*, else "True" | | -++----------------------------+----------------------------------+------------+ -+| "s + t" | the concatenation of *s* and *t* | (6)(7) | -++----------------------------+----------------------------------+------------+ -+| "s * n" or "n * s" | equivalent to adding *s* to | (2)(7) | -+| | itself *n* times | | -++----------------------------+----------------------------------+------------+ -+| "s[i]" | *i*th item of *s*, origin 0 | (3) | -++----------------------------+----------------------------------+------------+ -+| "s[i:j]" | slice of *s* from *i* to *j* | (3)(4) | -++----------------------------+----------------------------------+------------+ -+| "s[i:j:k]" | slice of *s* from *i* to *j* | (3)(5) | -+| | with step *k* | | -++----------------------------+----------------------------------+------------+ -+| "len(s)" | length of *s* | | -++----------------------------+----------------------------------+------------+ -+| "min(s)" | smallest item of *s* | | -++----------------------------+----------------------------------+------------+ -+| "max(s)" | largest item of *s* | | -++----------------------------+----------------------------------+------------+ -+| "s.index(x[, i[, j]])" | index of the first occurrence of | (8) | -+| | *x* in *s* (at or after index | | -+| | *i* and before index *j*) | | -++----------------------------+----------------------------------+------------+ -+| "s.count(x)" | total number of occurrences of | | -+| | *x* in *s* | | -++----------------------------+----------------------------------+------------+ -+ -+Sequences of the same type also support comparisons. In particular, -+tuples and lists are compared lexicographically by comparing -+corresponding elements. This means that to compare equal, every -+element must compare equal and the two sequences must be of the same -+type and have the same length. (For full details see Comparisons in -+the language reference.) -+ -+Forward and reversed iterators over mutable sequences access values -+using an index. That index will continue to march forward (or -+backward) even if the underlying sequence is mutated. The iterator -+terminates only when an "IndexError" or a "StopIteration" is -+encountered (or when the index drops below zero). -+ -+Notes: -+ -+1. While the "in" and "not in" operations are used only for simple -+ containment testing in the general case, some specialised sequences -+ (such as "str", "bytes" and "bytearray") also use them for -+ subsequence testing: -+ -+ >>> "gg" in "eggs" -+ True -+ -+2. Values of *n* less than "0" are treated as "0" (which yields an -+ empty sequence of the same type as *s*). Note that items in the -+ sequence *s* are not copied; they are referenced multiple times. -+ This often haunts new Python programmers; consider: -+ -+ >>> lists = [[]] * 3 -+ >>> lists -+ [[], [], []] -+ >>> lists[0].append(3) -+ >>> lists -+ [[3], [3], [3]] -+ -+ What has happened is that "[[]]" is a one-element list containing -+ an empty list, so all three elements of "[[]] * 3" are references -+ to this single empty list. Modifying any of the elements of -+ "lists" modifies this single list. You can create a list of -+ different lists this way: -+ -+ >>> lists = [[] for i in range(3)] -+ >>> lists[0].append(3) -+ >>> lists[1].append(5) -+ >>> lists[2].append(7) -+ >>> lists -+ [[3], [5], [7]] -+ -+ Further explanation is available in the FAQ entry How do I create a -+ multidimensional list?. -+ -+3. If *i* or *j* is negative, the index is relative to the end of -+ sequence *s*: "len(s) + i" or "len(s) + j" is substituted. But -+ note that "-0" is still "0". -+ -+4. The slice of *s* from *i* to *j* is defined as the sequence of -+ items with index *k* such that "i <= k < j". If *i* or *j* is -+ greater than "len(s)", use "len(s)". If *i* is omitted or "None", -+ use "0". If *j* is omitted or "None", use "len(s)". If *i* is -+ greater than or equal to *j*, the slice is empty. -+ -+5. The slice of *s* from *i* to *j* with step *k* is defined as the -+ sequence of items with index "x = i + n*k" such that "0 <= n < -+ (j-i)/k". In other words, the indices are "i", "i+k", "i+2*k", -+ "i+3*k" and so on, stopping when *j* is reached (but never -+ including *j*). When *k* is positive, *i* and *j* are reduced to -+ "len(s)" if they are greater. When *k* is negative, *i* and *j* are -+ reduced to "len(s) - 1" if they are greater. If *i* or *j* are -+ omitted or "None", they become “end†values (which end depends on -+ the sign of *k*). Note, *k* cannot be zero. If *k* is "None", it -+ is treated like "1". -+ -+6. Concatenating immutable sequences always results in a new object. -+ This means that building up a sequence by repeated concatenation -+ will have a quadratic runtime cost in the total sequence length. -+ To get a linear runtime cost, you must switch to one of the -+ alternatives below: -+ -+ * if concatenating "str" objects, you can build a list and use -+ "str.join()" at the end or else write to an "io.StringIO" -+ instance and retrieve its value when complete -+ -+ * if concatenating "bytes" objects, you can similarly use -+ "bytes.join()" or "io.BytesIO", or you can do in-place -+ concatenation with a "bytearray" object. "bytearray" objects are -+ mutable and have an efficient overallocation mechanism -+ -+ * if concatenating "tuple" objects, extend a "list" instead -+ -+ * for other types, investigate the relevant class documentation -+ -+7. Some sequence types (such as "range") only support item sequences -+ that follow specific patterns, and hence don’t support sequence -+ concatenation or repetition. -+ -+8. "index" raises "ValueError" when *x* is not found in *s*. Not all -+ implementations support passing the additional arguments *i* and -+ *j*. These arguments allow efficient searching of subsections of -+ the sequence. Passing the extra arguments is roughly equivalent to -+ using "s[i:j].index(x)", only without copying any data and with the -+ returned index being relative to the start of the sequence rather -+ than the start of the slice. -+ -+ -+Immutable Sequence Types -+======================== -+ -+The only operation that immutable sequence types generally implement -+that is not also implemented by mutable sequence types is support for -+the "hash()" built-in. -+ -+This support allows immutable sequences, such as "tuple" instances, to -+be used as "dict" keys and stored in "set" and "frozenset" instances. -+ -+Attempting to hash an immutable sequence that contains unhashable -+values will result in "TypeError". -+ -+ -+Mutable Sequence Types -+====================== -+ -+The operations in the following table are defined on mutable sequence -+types. The "collections.abc.MutableSequence" ABC is provided to make -+it easier to correctly implement these operations on custom sequence -+types. -+ -+In the table *s* is an instance of a mutable sequence type, *t* is any -+iterable object and *x* is an arbitrary object that meets any type and -+value restrictions imposed by *s* (for example, "bytearray" only -+accepts integers that meet the value restriction "0 <= x <= 255"). -+ -++--------------------------------+----------------------------------+-----------------------+ -+| Operation | Result | Notes | -+|================================|==================================|=======================| -+| "s[i] = x" | item *i* of *s* is replaced by | | -+| | *x* | | -++--------------------------------+----------------------------------+-----------------------+ -+| "s[i:j] = t" | slice of *s* from *i* to *j* is | | -+| | replaced by the contents of the | | -+| | iterable *t* | | -++--------------------------------+----------------------------------+-----------------------+ -+| "del s[i:j]" | same as "s[i:j] = []" | | -++--------------------------------+----------------------------------+-----------------------+ -+| "s[i:j:k] = t" | the elements of "s[i:j:k]" are | (1) | -+| | replaced by those of *t* | | -++--------------------------------+----------------------------------+-----------------------+ -+| "del s[i:j:k]" | removes the elements of | | -+| | "s[i:j:k]" from the list | | -++--------------------------------+----------------------------------+-----------------------+ -+| "s.append(x)" | appends *x* to the end of the | | -+| | sequence (same as | | -+| | "s[len(s):len(s)] = [x]") | | -++--------------------------------+----------------------------------+-----------------------+ -+| "s.clear()" | removes all items from *s* (same | (5) | -+| | as "del s[:]") | | -++--------------------------------+----------------------------------+-----------------------+ -+| "s.copy()" | creates a shallow copy of *s* | (5) | -+| | (same as "s[:]") | | -++--------------------------------+----------------------------------+-----------------------+ -+| "s.extend(t)" or "s += t" | extends *s* with the contents of | | -+| | *t* (for the most part the same | | -+| | as "s[len(s):len(s)] = t") | | -++--------------------------------+----------------------------------+-----------------------+ -+| "s *= n" | updates *s* with its contents | (6) | -+| | repeated *n* times | | -++--------------------------------+----------------------------------+-----------------------+ -+| "s.insert(i, x)" | inserts *x* into *s* at the | | -+| | index given by *i* (same as | | -+| | "s[i:i] = [x]") | | -++--------------------------------+----------------------------------+-----------------------+ -+| "s.pop()" or "s.pop(i)" | retrieves the item at *i* and | (2) | -+| | also removes it from *s* | | -++--------------------------------+----------------------------------+-----------------------+ -+| "s.remove(x)" | removes the first item from *s* | (3) | -+| | where "s[i]" is equal to *x* | | -++--------------------------------+----------------------------------+-----------------------+ -+| "s.reverse()" | reverses the items of *s* in | (4) | -+| | place | | -++--------------------------------+----------------------------------+-----------------------+ -+ -+Notes: -+ -+1. If *k* is not equal to "1", *t* must have the same length as the -+ slice it is replacing. -+ -+2. The optional argument *i* defaults to "-1", so that by default the -+ last item is removed and returned. -+ -+3. "remove()" raises "ValueError" when *x* is not found in *s*. -+ -+4. The "reverse()" method modifies the sequence in place for economy -+ of space when reversing a large sequence. To remind users that it -+ operates by side effect, it does not return the reversed sequence. -+ -+5. "clear()" and "copy()" are included for consistency with the -+ interfaces of mutable containers that don’t support slicing -+ operations (such as "dict" and "set"). "copy()" is not part of the -+ "collections.abc.MutableSequence" ABC, but most concrete mutable -+ sequence classes provide it. -+ -+ Added in version 3.3: "clear()" and "copy()" methods. -+ -+6. The value *n* is an integer, or an object implementing -+ "__index__()". Zero and negative values of *n* clear the sequence. -+ Items in the sequence are not copied; they are referenced multiple -+ times, as explained for "s * n" under Common Sequence Operations. -+ -+ -+Lists -+===== -+ -+Lists are mutable sequences, typically used to store collections of -+homogeneous items (where the precise degree of similarity will vary by -+application). -+ -+class list([iterable]) -+ -+ Lists may be constructed in several ways: -+ -+ * Using a pair of square brackets to denote the empty list: "[]" -+ -+ * Using square brackets, separating items with commas: "[a]", "[a, -+ b, c]" -+ -+ * Using a list comprehension: "[x for x in iterable]" -+ -+ * Using the type constructor: "list()" or "list(iterable)" -+ -+ The constructor builds a list whose items are the same and in the -+ same order as *iterable*’s items. *iterable* may be either a -+ sequence, a container that supports iteration, or an iterator -+ object. If *iterable* is already a list, a copy is made and -+ returned, similar to "iterable[:]". For example, "list('abc')" -+ returns "['a', 'b', 'c']" and "list( (1, 2, 3) )" returns "[1, 2, -+ 3]". If no argument is given, the constructor creates a new empty -+ list, "[]". -+ -+ Many other operations also produce lists, including the "sorted()" -+ built-in. -+ -+ Lists implement all of the common and mutable sequence operations. -+ Lists also provide the following additional method: -+ -+ sort(*, key=None, reverse=False) -+ -+ This method sorts the list in place, using only "<" comparisons -+ between items. Exceptions are not suppressed - if any comparison -+ operations fail, the entire sort operation will fail (and the -+ list will likely be left in a partially modified state). -+ -+ "sort()" accepts two arguments that can only be passed by -+ keyword (keyword-only arguments): -+ -+ *key* specifies a function of one argument that is used to -+ extract a comparison key from each list element (for example, -+ "key=str.lower"). The key corresponding to each item in the list -+ is calculated once and then used for the entire sorting process. -+ The default value of "None" means that list items are sorted -+ directly without calculating a separate key value. -+ -+ The "functools.cmp_to_key()" utility is available to convert a -+ 2.x style *cmp* function to a *key* function. -+ -+ *reverse* is a boolean value. If set to "True", then the list -+ elements are sorted as if each comparison were reversed. -+ -+ This method modifies the sequence in place for economy of space -+ when sorting a large sequence. To remind users that it operates -+ by side effect, it does not return the sorted sequence (use -+ "sorted()" to explicitly request a new sorted list instance). -+ -+ The "sort()" method is guaranteed to be stable. A sort is -+ stable if it guarantees not to change the relative order of -+ elements that compare equal — this is helpful for sorting in -+ multiple passes (for example, sort by department, then by salary -+ grade). -+ -+ For sorting examples and a brief sorting tutorial, see Sorting -+ Techniques. -+ -+ **CPython implementation detail:** While a list is being sorted, -+ the effect of attempting to mutate, or even inspect, the list is -+ undefined. The C implementation of Python makes the list appear -+ empty for the duration, and raises "ValueError" if it can detect -+ that the list has been mutated during a sort. -+ -+ -+Tuples -+====== -+ -+Tuples are immutable sequences, typically used to store collections of -+heterogeneous data (such as the 2-tuples produced by the "enumerate()" -+built-in). Tuples are also used for cases where an immutable sequence -+of homogeneous data is needed (such as allowing storage in a "set" or -+"dict" instance). -+ -+class tuple([iterable]) -+ -+ Tuples may be constructed in a number of ways: -+ -+ * Using a pair of parentheses to denote the empty tuple: "()" -+ -+ * Using a trailing comma for a singleton tuple: "a," or "(a,)" -+ -+ * Separating items with commas: "a, b, c" or "(a, b, c)" -+ -+ * Using the "tuple()" built-in: "tuple()" or "tuple(iterable)" -+ -+ The constructor builds a tuple whose items are the same and in the -+ same order as *iterable*’s items. *iterable* may be either a -+ sequence, a container that supports iteration, or an iterator -+ object. If *iterable* is already a tuple, it is returned -+ unchanged. For example, "tuple('abc')" returns "('a', 'b', 'c')" -+ and "tuple( [1, 2, 3] )" returns "(1, 2, 3)". If no argument is -+ given, the constructor creates a new empty tuple, "()". -+ -+ Note that it is actually the comma which makes a tuple, not the -+ parentheses. The parentheses are optional, except in the empty -+ tuple case, or when they are needed to avoid syntactic ambiguity. -+ For example, "f(a, b, c)" is a function call with three arguments, -+ while "f((a, b, c))" is a function call with a 3-tuple as the sole -+ argument. -+ -+ Tuples implement all of the common sequence operations. -+ -+For heterogeneous collections of data where access by name is clearer -+than access by index, "collections.namedtuple()" may be a more -+appropriate choice than a simple tuple object. -+ -+ -+Ranges -+====== -+ -+The "range" type represents an immutable sequence of numbers and is -+commonly used for looping a specific number of times in "for" loops. -+ -+class range(stop) -+class range(start, stop[, step]) -+ -+ The arguments to the range constructor must be integers (either -+ built-in "int" or any object that implements the "__index__()" -+ special method). If the *step* argument is omitted, it defaults to -+ "1". If the *start* argument is omitted, it defaults to "0". If -+ *step* is zero, "ValueError" is raised. -+ -+ For a positive *step*, the contents of a range "r" are determined -+ by the formula "r[i] = start + step*i" where "i >= 0" and "r[i] < -+ stop". -+ -+ For a negative *step*, the contents of the range are still -+ determined by the formula "r[i] = start + step*i", but the -+ constraints are "i >= 0" and "r[i] > stop". -+ -+ A range object will be empty if "r[0]" does not meet the value -+ constraint. Ranges do support negative indices, but these are -+ interpreted as indexing from the end of the sequence determined by -+ the positive indices. -+ -+ Ranges containing absolute values larger than "sys.maxsize" are -+ permitted but some features (such as "len()") may raise -+ "OverflowError". -+ -+ Range examples: -+ -+ >>> list(range(10)) -+ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] -+ >>> list(range(1, 11)) -+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] -+ >>> list(range(0, 30, 5)) -+ [0, 5, 10, 15, 20, 25] -+ >>> list(range(0, 10, 3)) -+ [0, 3, 6, 9] -+ >>> list(range(0, -10, -1)) -+ [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] -+ >>> list(range(0)) -+ [] -+ >>> list(range(1, 0)) -+ [] -+ -+ Ranges implement all of the common sequence operations except -+ concatenation and repetition (due to the fact that range objects -+ can only represent sequences that follow a strict pattern and -+ repetition and concatenation will usually violate that pattern). -+ -+ start -+ -+ The value of the *start* parameter (or "0" if the parameter was -+ not supplied) -+ -+ stop -+ -+ The value of the *stop* parameter -+ -+ step -+ -+ The value of the *step* parameter (or "1" if the parameter was -+ not supplied) -+ -+The advantage of the "range" type over a regular "list" or "tuple" is -+that a "range" object will always take the same (small) amount of -+memory, no matter the size of the range it represents (as it only -+stores the "start", "stop" and "step" values, calculating individual -+items and subranges as needed). -+ -+Range objects implement the "collections.abc.Sequence" ABC, and -+provide features such as containment tests, element index lookup, -+slicing and support for negative indices (see Sequence Types — list, -+tuple, range): -+ -+>>> r = range(0, 20, 2) -+>>> r -+range(0, 20, 2) -+>>> 11 in r -+False -+>>> 10 in r -+True -+>>> r.index(10) -+5 -+>>> r[5] -+10 -+>>> r[:5] -+range(0, 10, 2) -+>>> r[-1] -+18 -+ -+Testing range objects for equality with "==" and "!=" compares them as -+sequences. That is, two range objects are considered equal if they -+represent the same sequence of values. (Note that two range objects -+that compare equal might have different "start", "stop" and "step" -+attributes, for example "range(0) == range(2, 1, 3)" or "range(0, 3, -+2) == range(0, 4, 2)".) -+ -+Changed in version 3.2: Implement the Sequence ABC. Support slicing -+and negative indices. Test "int" objects for membership in constant -+time instead of iterating through all items. -+ -+Changed in version 3.3: Define ‘==’ and ‘!=’ to compare range objects -+based on the sequence of values they define (instead of comparing -+based on object identity).Added the "start", "stop" and "step" -+attributes. -+ -+See also: -+ -+ * The linspace recipe shows how to implement a lazy version of range -+ suitable for floating-point applications. -+''', -+ 'typesseq-mutable': r'''Mutable Sequence Types -+********************** -+ -+The operations in the following table are defined on mutable sequence -+types. The "collections.abc.MutableSequence" ABC is provided to make -+it easier to correctly implement these operations on custom sequence -+types. -+ -+In the table *s* is an instance of a mutable sequence type, *t* is any -+iterable object and *x* is an arbitrary object that meets any type and -+value restrictions imposed by *s* (for example, "bytearray" only -+accepts integers that meet the value restriction "0 <= x <= 255"). -+ -++--------------------------------+----------------------------------+-----------------------+ -+| Operation | Result | Notes | -+|================================|==================================|=======================| -+| "s[i] = x" | item *i* of *s* is replaced by | | -+| | *x* | | -++--------------------------------+----------------------------------+-----------------------+ -+| "s[i:j] = t" | slice of *s* from *i* to *j* is | | -+| | replaced by the contents of the | | -+| | iterable *t* | | -++--------------------------------+----------------------------------+-----------------------+ -+| "del s[i:j]" | same as "s[i:j] = []" | | -++--------------------------------+----------------------------------+-----------------------+ -+| "s[i:j:k] = t" | the elements of "s[i:j:k]" are | (1) | -+| | replaced by those of *t* | | -++--------------------------------+----------------------------------+-----------------------+ -+| "del s[i:j:k]" | removes the elements of | | -+| | "s[i:j:k]" from the list | | -++--------------------------------+----------------------------------+-----------------------+ -+| "s.append(x)" | appends *x* to the end of the | | -+| | sequence (same as | | -+| | "s[len(s):len(s)] = [x]") | | -++--------------------------------+----------------------------------+-----------------------+ -+| "s.clear()" | removes all items from *s* (same | (5) | -+| | as "del s[:]") | | -++--------------------------------+----------------------------------+-----------------------+ -+| "s.copy()" | creates a shallow copy of *s* | (5) | -+| | (same as "s[:]") | | -++--------------------------------+----------------------------------+-----------------------+ -+| "s.extend(t)" or "s += t" | extends *s* with the contents of | | -+| | *t* (for the most part the same | | -+| | as "s[len(s):len(s)] = t") | | -++--------------------------------+----------------------------------+-----------------------+ -+| "s *= n" | updates *s* with its contents | (6) | -+| | repeated *n* times | | -++--------------------------------+----------------------------------+-----------------------+ -+| "s.insert(i, x)" | inserts *x* into *s* at the | | -+| | index given by *i* (same as | | -+| | "s[i:i] = [x]") | | -++--------------------------------+----------------------------------+-----------------------+ -+| "s.pop()" or "s.pop(i)" | retrieves the item at *i* and | (2) | -+| | also removes it from *s* | | -++--------------------------------+----------------------------------+-----------------------+ -+| "s.remove(x)" | removes the first item from *s* | (3) | -+| | where "s[i]" is equal to *x* | | -++--------------------------------+----------------------------------+-----------------------+ -+| "s.reverse()" | reverses the items of *s* in | (4) | -+| | place | | -++--------------------------------+----------------------------------+-----------------------+ -+ -+Notes: -+ -+1. If *k* is not equal to "1", *t* must have the same length as the -+ slice it is replacing. -+ -+2. The optional argument *i* defaults to "-1", so that by default the -+ last item is removed and returned. -+ -+3. "remove()" raises "ValueError" when *x* is not found in *s*. -+ -+4. The "reverse()" method modifies the sequence in place for economy -+ of space when reversing a large sequence. To remind users that it -+ operates by side effect, it does not return the reversed sequence. -+ -+5. "clear()" and "copy()" are included for consistency with the -+ interfaces of mutable containers that don’t support slicing -+ operations (such as "dict" and "set"). "copy()" is not part of the -+ "collections.abc.MutableSequence" ABC, but most concrete mutable -+ sequence classes provide it. -+ -+ Added in version 3.3: "clear()" and "copy()" methods. -+ -+6. The value *n* is an integer, or an object implementing -+ "__index__()". Zero and negative values of *n* clear the sequence. -+ Items in the sequence are not copied; they are referenced multiple -+ times, as explained for "s * n" under Common Sequence Operations. -+''', -+ 'unary': r'''Unary arithmetic and bitwise operations -+*************************************** -+ -+All unary arithmetic and bitwise operations have the same priority: -+ -+ **u_expr**: "power" | "-" "u_expr" | "+" "u_expr" | "~" "u_expr" -+ -+The unary "-" (minus) operator yields the negation of its numeric -+argument; the operation can be overridden with the "__neg__()" special -+method. -+ -+The unary "+" (plus) operator yields its numeric argument unchanged; -+the operation can be overridden with the "__pos__()" special method. -+ -+The unary "~" (invert) operator yields the bitwise inversion of its -+integer argument. The bitwise inversion of "x" is defined as -+"-(x+1)". It only applies to integral numbers or to custom objects -+that override the "__invert__()" special method. -+ -+In all three cases, if the argument does not have the proper type, a -+"TypeError" exception is raised. -+''', -+ 'while': r'''The "while" statement -+********************* -+ -+The "while" statement is used for repeated execution as long as an -+expression is true: -+ -+ **while_stmt**: "while" "assignment_expression" ":" "suite" -+ ["else" ":" "suite"] -+ -+This repeatedly tests the expression and, if it is true, executes the -+first suite; if the expression is false (which may be the first time -+it is tested) the suite of the "else" clause, if present, is executed -+and the loop terminates. -+ -+A "break" statement executed in the first suite terminates the loop -+without executing the "else" clause’s suite. A "continue" statement -+executed in the first suite skips the rest of the suite and goes back -+to testing the expression. -+''', -+ 'with': r'''The "with" statement -+******************** -+ -+The "with" statement is used to wrap the execution of a block with -+methods defined by a context manager (see section With Statement -+Context Managers). This allows common "try"…"except"…"finally" usage -+patterns to be encapsulated for convenient reuse. -+ -+ **with_stmt**: "with" ( "(" "with_stmt_contents" ","? ")" | "with_stmt_contents" ) ":" "suite" -+ **with_stmt_contents**: "with_item" ("," "with_item")* -+ **with_item**: "expression" ["as" "target"] -+ -+The execution of the "with" statement with one “item†proceeds as -+follows: -+ -+1. The context expression (the expression given in the "with_item") is -+ evaluated to obtain a context manager. -+ -+2. The context manager’s "__enter__()" is loaded for later use. -+ -+3. The context manager’s "__exit__()" is loaded for later use. -+ -+4. The context manager’s "__enter__()" method is invoked. -+ -+5. If a target was included in the "with" statement, the return value -+ from "__enter__()" is assigned to it. -+ -+ Note: -+ -+ The "with" statement guarantees that if the "__enter__()" method -+ returns without an error, then "__exit__()" will always be -+ called. Thus, if an error occurs during the assignment to the -+ target list, it will be treated the same as an error occurring -+ within the suite would be. See step 7 below. -+ -+6. The suite is executed. -+ -+7. The context manager’s "__exit__()" method is invoked. If an -+ exception caused the suite to be exited, its type, value, and -+ traceback are passed as arguments to "__exit__()". Otherwise, three -+ "None" arguments are supplied. -+ -+ If the suite was exited due to an exception, and the return value -+ from the "__exit__()" method was false, the exception is reraised. -+ If the return value was true, the exception is suppressed, and -+ execution continues with the statement following the "with" -+ statement. -+ -+ If the suite was exited for any reason other than an exception, the -+ return value from "__exit__()" is ignored, and execution proceeds -+ at the normal location for the kind of exit that was taken. -+ -+The following code: -+ -+ with EXPRESSION as TARGET: -+ SUITE -+ -+is semantically equivalent to: -+ -+ manager = (EXPRESSION) -+ enter = type(manager).__enter__ -+ exit = type(manager).__exit__ -+ value = enter(manager) -+ hit_except = False -+ -+ try: -+ TARGET = value -+ SUITE -+ except: -+ hit_except = True -+ if not exit(manager, *sys.exc_info()): -+ raise -+ finally: -+ if not hit_except: -+ exit(manager, None, None, None) -+ -+With more than one item, the context managers are processed as if -+multiple "with" statements were nested: -+ -+ with A() as a, B() as b: -+ SUITE -+ -+is semantically equivalent to: -+ -+ with A() as a: -+ with B() as b: -+ SUITE -+ -+You can also write multi-item context managers in multiple lines if -+the items are surrounded by parentheses. For example: -+ -+ with ( -+ A() as a, -+ B() as b, -+ ): -+ SUITE -+ -+Changed in version 3.1: Support for multiple context expressions. -+ -+Changed in version 3.10: Support for using grouping parentheses to -+break the statement in multiple lines. -+ -+See also: -+ -+ **PEP 343** - The “with†statement -+ The specification, background, and examples for the Python "with" -+ statement. -+''', -+ 'yield': r'''The "yield" statement -+********************* -+ -+ **yield_stmt**: "yield_expression" -+ -+A "yield" statement is semantically equivalent to a yield expression. -+The "yield" statement can be used to omit the parentheses that would -+otherwise be required in the equivalent yield expression statement. -+For example, the yield statements -+ -+ yield -+ yield from -+ -+are equivalent to the yield expression statements -+ -+ (yield ) -+ (yield from ) -+ -+Yield expressions and statements are only used when defining a -+*generator* function, and are only used in the body of the generator -+function. Using "yield" in a function definition is sufficient to -+cause that definition to create a generator function instead of a -+normal function. -+ -+For full details of "yield" semantics, refer to the Yield expressions -+section. -+''', -+} -diff --git a/Lib/shutil.py b/Lib/shutil.py -index 171489ca41f..510ae8c6f22 100644 ---- a/Lib/shutil.py -+++ b/Lib/shutil.py -@@ -49,6 +49,7 @@ - # https://bugs.python.org/issue43743#msg393429 - _USE_CP_SENDFILE = (hasattr(os, "sendfile") - and sys.platform.startswith(("linux", "android", "sunos"))) -+_USE_CP_COPY_FILE_RANGE = hasattr(os, "copy_file_range") - _HAS_FCOPYFILE = posix and hasattr(posix, "_fcopyfile") # macOS - - # CMD defaults in Windows 10 -@@ -107,6 +108,66 @@ - else: - raise err from None - -+def _determine_linux_fastcopy_blocksize(infd): -+ """Determine blocksize for fastcopying on Linux. -+ -+ Hopefully the whole file will be copied in a single call. -+ The copying itself should be performed in a loop 'till EOF is -+ reached (0 return) so a blocksize smaller or bigger than the actual -+ file size should not make any difference, also in case the file -+ content changes while being copied. -+ """ -+ try: -+ blocksize = max(os.fstat(infd).st_size, 2 ** 23) # min 8 MiB -+ except OSError: -+ blocksize = 2 ** 27 # 128 MiB -+ # On 32-bit architectures truncate to 1 GiB to avoid OverflowError, -+ # see gh-82500. -+ if sys.maxsize < 2 ** 32: -+ blocksize = min(blocksize, 2 ** 30) -+ return blocksize -+ -+def _fastcopy_copy_file_range(fsrc, fdst): -+ """Copy data from one regular mmap-like fd to another by using -+ a high-performance copy_file_range(2) syscall that gives filesystems -+ an opportunity to implement the use of reflinks or server-side copy. -+ -+ This should work on Linux >= 4.5 only. -+ """ -+ try: -+ infd = fsrc.fileno() -+ outfd = fdst.fileno() -+ except Exception as err: -+ raise _GiveupOnFastCopy(err) # not a regular file -+ -+ blocksize = _determine_linux_fastcopy_blocksize(infd) -+ offset = 0 -+ while True: -+ try: -+ n_copied = os.copy_file_range(infd, outfd, blocksize, offset_dst=offset) -+ except OSError as err: -+ # ...in oder to have a more informative exception. -+ err.filename = fsrc.name -+ err.filename2 = fdst.name -+ -+ if err.errno == errno.ENOSPC: # filesystem is full -+ raise err from None -+ -+ # Give up on first call and if no data was copied. -+ if offset == 0 and os.lseek(outfd, 0, os.SEEK_CUR) == 0: -+ raise _GiveupOnFastCopy(err) -+ -+ raise err -+ else: -+ if n_copied == 0: -+ # If no bytes have been copied yet, copy_file_range -+ # might silently fail. -+ # https://lore.kernel.org/linux-fsdevel/20210126233840.GG4626@dread.disaster.area/T/#m05753578c7f7882f6e9ffe01f981bc223edef2b0 -+ if offset == 0: -+ raise _GiveupOnFastCopy() -+ break -+ offset += n_copied -+ - def _fastcopy_sendfile(fsrc, fdst): - """Copy data from one regular mmap-like fd to another by using - high-performance sendfile(2) syscall. -@@ -128,20 +189,7 @@ - except Exception as err: - raise _GiveupOnFastCopy(err) # not a regular file - -- # Hopefully the whole file will be copied in a single call. -- # sendfile() is called in a loop 'till EOF is reached (0 return) -- # so a bufsize smaller or bigger than the actual file size -- # should not make any difference, also in case the file content -- # changes while being copied. -- try: -- blocksize = max(os.fstat(infd).st_size, 2 ** 23) # min 8MiB -- except OSError: -- blocksize = 2 ** 27 # 128MiB -- # On 32-bit architectures truncate to 1GiB to avoid OverflowError, -- # see bpo-38319. -- if sys.maxsize < 2 ** 32: -- blocksize = min(blocksize, 2 ** 30) -- -+ blocksize = _determine_linux_fastcopy_blocksize(infd) - offset = 0 - while True: - try: -@@ -266,12 +314,20 @@ - except _GiveupOnFastCopy: - pass - # Linux / Android / Solaris -- elif _USE_CP_SENDFILE: -- try: -- _fastcopy_sendfile(fsrc, fdst) -- return dst -- except _GiveupOnFastCopy: -- pass -+ elif _USE_CP_SENDFILE or _USE_CP_COPY_FILE_RANGE: -+ # reflink may be implicit in copy_file_range. -+ if _USE_CP_COPY_FILE_RANGE: -+ try: -+ _fastcopy_copy_file_range(fsrc, fdst) -+ return dst -+ except _GiveupOnFastCopy: -+ pass -+ if _USE_CP_SENDFILE: -+ try: -+ _fastcopy_sendfile(fsrc, fdst) -+ return dst -+ except _GiveupOnFastCopy: -+ pass - # Windows, see: - # https://github.com/python/cpython/pull/7160#discussion_r195405230 - elif _WINDOWS and file_size > 0: -diff --git a/Lib/site.py b/Lib/site.py -index 92bd1ccdadd..9da8b6724e1 100644 ---- a/Lib/site.py -+++ b/Lib/site.py -@@ -633,12 +633,9 @@ - # Doing this here ensures venv takes precedence over user-site - addsitepackages(known_paths, [sys.prefix]) - -- # addsitepackages will process site_prefix again if its in PREFIXES, -- # but that's ok; known_paths will prevent anything being added twice - if system_site == "true": -- PREFIXES.insert(0, sys.prefix) -+ PREFIXES += [sys.base_prefix, sys.base_exec_prefix] - else: -- PREFIXES = [sys.prefix] - ENABLE_USER_SITE = False - - return known_paths -diff --git a/Lib/socket.py b/Lib/socket.py -index be37c24d617..727b0e75f03 100644 ---- a/Lib/socket.py -+++ b/Lib/socket.py -@@ -937,7 +937,9 @@ - # Fail later on bind(), for platforms which may not - # support this option. - pass -- if reuse_port: -+ # Since Linux 6.12.9, SO_REUSEPORT is not allowed -+ # on other address families than AF_INET/AF_INET6. -+ if reuse_port and family in (AF_INET, AF_INET6): - sock.setsockopt(SOL_SOCKET, SO_REUSEPORT, 1) - if has_ipv6 and family == AF_INET6: - if dualstack_ipv6: -diff --git a/Lib/socketserver.py b/Lib/socketserver.py -index cd028ef1c63..35b2723de3b 100644 ---- a/Lib/socketserver.py -+++ b/Lib/socketserver.py -@@ -468,7 +468,12 @@ - """ - if self.allow_reuse_address and hasattr(socket, "SO_REUSEADDR"): - self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) -- if self.allow_reuse_port and hasattr(socket, "SO_REUSEPORT"): -+ # Since Linux 6.12.9, SO_REUSEPORT is not allowed -+ # on other address families than AF_INET/AF_INET6. -+ if ( -+ self.allow_reuse_port and hasattr(socket, "SO_REUSEPORT") -+ and self.address_family in (socket.AF_INET, socket.AF_INET6) -+ ): - self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) - self.socket.bind(self.server_address) - self.server_address = self.socket.getsockname() -diff --git a/Lib/sqlite3/__init__.py b/Lib/sqlite3/__init__.py -index 34a9c047dd6..ed727fae609 100644 ---- a/Lib/sqlite3/__init__.py -+++ b/Lib/sqlite3/__init__.py -@@ -22,7 +22,7 @@ - - """ - The sqlite3 extension module provides a DB-API 2.0 (PEP 249) compliant --interface to the SQLite library, and requires SQLite 3.7.15 or newer. -+interface to the SQLite library, and requires SQLite 3.15.2 or newer. - - To use the module, start by creating a database Connection object: - -diff --git a/Lib/ssl.py b/Lib/ssl.py -index c8703b046cf..05df4ad7f0f 100644 ---- a/Lib/ssl.py -+++ b/Lib/ssl.py -@@ -116,7 +116,7 @@ - - from _ssl import ( - HAS_SNI, HAS_ECDH, HAS_NPN, HAS_ALPN, HAS_SSLv2, HAS_SSLv3, HAS_TLSv1, -- HAS_TLSv1_1, HAS_TLSv1_2, HAS_TLSv1_3, HAS_PSK -+ HAS_TLSv1_1, HAS_TLSv1_2, HAS_TLSv1_3, HAS_PSK, HAS_PHA - ) - from _ssl import _DEFAULT_CIPHERS, _OPENSSL_API_VERSION - -diff --git a/Lib/string.py b/Lib/string.py -index 2eab6d4f595..c4f05c7223c 100644 ---- a/Lib/string.py -+++ b/Lib/string.py -@@ -212,19 +212,20 @@ - # this is some markup, find the object and do - # the formatting - -- # handle arg indexing when empty field_names are given. -- if field_name == '': -+ # handle arg indexing when empty field first parts are given. -+ field_first, _ = _string.formatter_field_name_split(field_name) -+ if field_first == '': - if auto_arg_index is False: - raise ValueError('cannot switch from manual field ' - 'specification to automatic field ' - 'numbering') -- field_name = str(auto_arg_index) -+ field_name = str(auto_arg_index) + field_name - auto_arg_index += 1 -- elif field_name.isdigit(): -+ elif isinstance(field_first, int): - if auto_arg_index: -- raise ValueError('cannot switch from manual field ' -- 'specification to automatic field ' -- 'numbering') -+ raise ValueError('cannot switch from automatic field ' -+ 'numbering to manual field ' -+ 'specification') - # disable auto arg incrementing, if it gets - # used later on, then an exception will be raised - auto_arg_index = False -diff --git a/Lib/subprocess.py b/Lib/subprocess.py -index 88f0230b05f..2044d2a4289 100644 ---- a/Lib/subprocess.py -+++ b/Lib/subprocess.py -@@ -43,10 +43,8 @@ - import builtins - import errno - import io --import locale - import os - import time --import signal - import sys - import threading - import warnings -@@ -144,6 +142,8 @@ - - def __str__(self): - if self.returncode and self.returncode < 0: -+ # Lazy import to improve module import time -+ import signal - try: - return "Command '%s' died with %r." % ( - self.cmd, signal.Signals(-self.returncode)) -@@ -381,12 +381,14 @@ - if sys.flags.utf8_mode: - return "utf-8" - else: -+ # Lazy import to improve module import time -+ import locale - return locale.getencoding() - - - def call(*popenargs, timeout=None, **kwargs): - """Run command with arguments. Wait for command to complete or -- timeout, then return the returncode attribute. -+ for timeout seconds, then return the returncode attribute. - - The arguments are the same as for the Popen constructor. Example: - -@@ -523,8 +525,8 @@ - in the returncode attribute, and output & stderr attributes if those streams - were captured. - -- If timeout is given, and the process takes too long, a TimeoutExpired -- exception will be raised. -+ If timeout (seconds) is given and the process takes too long, -+ a TimeoutExpired exception will be raised. - - There is an optional argument "input", allowing you to - pass bytes or a string to the subprocess's stdin. If you use this argument -@@ -1664,6 +1666,9 @@ - # Don't signal a process that we know has already died. - if self.returncode is not None: - return -+ -+ # Lazy import to improve module import time -+ import signal - if sig == signal.SIGTERM: - self.terminate() - elif sig == signal.CTRL_C_EVENT: -@@ -1765,6 +1770,9 @@ - """Execute program using os.posix_spawn().""" - kwargs = {} - if restore_signals: -+ # Lazy import to improve module import time -+ import signal -+ - # See _Py_RestoreSignals() in Python/pylifecycle.c - sigset = [] - for signame in ('SIGPIPE', 'SIGXFZ', 'SIGXFSZ'): -@@ -2214,9 +2222,13 @@ - def terminate(self): - """Terminate the process with SIGTERM - """ -+ # Lazy import to improve module import time -+ import signal - self.send_signal(signal.SIGTERM) - - def kill(self): - """Kill the process with SIGKILL - """ -+ # Lazy import to improve module import time -+ import signal - self.send_signal(signal.SIGKILL) -diff --git a/Lib/sysconfig/__init__.py b/Lib/sysconfig/__init__.py -index ed7b6a335d0..34ce643340b 100644 ---- a/Lib/sysconfig/__init__.py -+++ b/Lib/sysconfig/__init__.py -@@ -116,8 +116,10 @@ - if env_base: - return env_base - -- # Emscripten, iOS, tvOS, VxWorks, WASI, and watchOS have no home directories -- if sys.platform in {"emscripten", "ios", "tvos", "vxworks", "wasi", "watchos"}: -+ # Emscripten, iOS, tvOS, VxWorks, WASI, and watchOS have no home directories. -+ # Use _PYTHON_HOST_PLATFORM to get the correct platform when cross-compiling. -+ system_name = os.environ.get('_PYTHON_HOST_PLATFORM', sys.platform).split('-')[0] -+ if system_name in {"emscripten", "ios", "tvos", "vxworks", "wasi", "watchos"}: - return None - - def joinuser(*args): -@@ -220,8 +222,15 @@ - def is_python_build(check_home=None): - if check_home is not None: - import warnings -- warnings.warn("check_home argument is deprecated and ignored.", -- DeprecationWarning, stacklevel=2) -+ warnings.warn( -+ ( -+ 'The check_home argument of sysconfig.is_python_build is ' -+ 'deprecated and its value is ignored. ' -+ 'It will be removed in Python 3.15.' -+ ), -+ DeprecationWarning, -+ stacklevel=2, -+ ) - for fn in ("Setup", "Setup.local"): - if os.path.isfile(os.path.join(_PROJECT_BASE, "Modules", fn)): - return True -@@ -335,6 +344,18 @@ - return os.path.join(get_path('stdlib'), config_dir_name, 'Makefile') - - -+def _import_from_directory(path, name): -+ if name not in sys.modules: -+ import importlib.machinery -+ import importlib.util -+ -+ spec = importlib.machinery.PathFinder.find_spec(name, [path]) -+ module = importlib.util.module_from_spec(spec) -+ spec.loader.exec_module(module) -+ sys.modules[name] = module -+ return sys.modules[name] -+ -+ - def _get_sysconfigdata_name(): - multiarch = getattr(sys.implementation, '_multiarch', '') - return os.environ.get( -@@ -342,27 +363,34 @@ - f'_sysconfigdata_{sys.abiflags}_{sys.platform}_{multiarch}', - ) - --def _init_posix(vars): -- """Initialize the module as appropriate for POSIX systems.""" -- # _sysconfigdata is generated at build time, see _generate_posix_vars() -+ -+def _get_sysconfigdata(): -+ import importlib -+ - name = _get_sysconfigdata_name() -+ path = os.environ.get('_PYTHON_SYSCONFIGDATA_PATH') -+ module = _import_from_directory(path, name) if path else importlib.import_module(name) - -- # For cross builds, the path to the target's sysconfigdata must be specified -- # so it can be imported. It cannot be in PYTHONPATH, as foreign modules in -- # sys.path can cause crashes when loaded by the host interpreter. -- # Rely on truthiness as a valueless env variable is still an empty string. -- # See OS X note in _generate_posix_vars re _sysconfigdata. -- if (path := os.environ.get('_PYTHON_SYSCONFIGDATA_PATH')): -- from importlib.machinery import FileFinder, SourceFileLoader, SOURCE_SUFFIXES -- from importlib.util import module_from_spec -- spec = FileFinder(path, (SourceFileLoader, SOURCE_SUFFIXES)).find_spec(name) -- _temp = module_from_spec(spec) -- spec.loader.exec_module(_temp) -- else: -- _temp = __import__(name, globals(), locals(), ['build_time_vars'], 0) -- build_time_vars = _temp.build_time_vars -+ return module.build_time_vars -+ -+ -+def _installation_is_relocated(): -+ """Is the Python installation running from a different prefix than what was targetted when building?""" -+ if os.name != 'posix': -+ raise NotImplementedError('sysconfig._installation_is_relocated() is currently only supported on POSIX') -+ -+ data = _get_sysconfigdata() -+ return ( -+ data['prefix'] != getattr(sys, 'base_prefix', '') -+ or data['exec_prefix'] != getattr(sys, 'base_exec_prefix', '') -+ ) -+ -+ -+def _init_posix(vars): -+ """Initialize the module as appropriate for POSIX systems.""" - # GH-126920: Make sure we don't overwrite any of the keys already set -- vars.update(build_time_vars | vars) -+ vars.update(_get_sysconfigdata() | vars) -+ - - def _init_non_posix(vars): - """Initialize the module as appropriate for NT""" -@@ -485,10 +513,10 @@ - _init_posix(_CONFIG_VARS) - # If we are cross-compiling, load the prefixes from the Makefile instead. - if '_PYTHON_PROJECT_BASE' in os.environ: -- prefix = _CONFIG_VARS['prefix'] -- exec_prefix = _CONFIG_VARS['exec_prefix'] -- base_prefix = _CONFIG_VARS['prefix'] -- base_exec_prefix = _CONFIG_VARS['exec_prefix'] -+ prefix = _CONFIG_VARS['host_prefix'] -+ exec_prefix = _CONFIG_VARS['host_exec_prefix'] -+ base_prefix = _CONFIG_VARS['host_prefix'] -+ base_exec_prefix = _CONFIG_VARS['host_exec_prefix'] - abiflags = _CONFIG_VARS['ABIFLAGS'] - - # Normalized versions of prefix and exec_prefix are handy to have; -@@ -616,7 +644,8 @@ - solaris-2.6-sun4u - - Windows will return one of: -- win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc) -+ win-amd64 (64-bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc) -+ win-arm64 (64-bit Windows on ARM64 (aka AArch64) - win32 (all others - specifically, sys.platform is returned) - - For other non-POSIX platforms, currently just returns 'sys.platform'. -@@ -690,6 +719,14 @@ - release = get_config_vars().get("IPHONEOS_DEPLOYMENT_TARGET", "13.0") - osname = sys.platform - machine = sys.implementation._multiarch -+ elif sys.platform == "tvos": -+ release = get_config_vars().get("TVOS_DEPLOYMENT_TARGET", "9.0") -+ osname = sys.platform -+ machine = sys.implementation._multiarch -+ elif sys.platform == "watchos": -+ release = get_config_vars().get("WATCHOS_DEPLOYMENT_TARGET", "4.0") -+ osname = sys.platform -+ machine = sys.implementation._multiarch - else: - import _osx_support - osname, release, machine = _osx_support.get_platform_osx( -@@ -715,8 +752,20 @@ - variable expansions; if 'vars' is the output of 'parse_makefile()', - you're fine. Returns a variable-expanded version of 's'. - """ -+ -+ import warnings -+ warnings.warn( -+ 'sysconfig.expand_makefile_vars is deprecated and will be removed in ' -+ 'Python 3.16. Use sysconfig.get_paths(vars=...) instead.', -+ DeprecationWarning, -+ stacklevel=2, -+ ) -+ - import re - -+ _findvar1_rx = r"\$\(([A-Za-z][A-Za-z0-9_]*)\)" -+ _findvar2_rx = r"\${([A-Za-z][A-Za-z0-9_]*)}" -+ - # This algorithm does multiple expansion, so if vars['foo'] contains - # "${bar}", it will expand ${foo} to ${bar}, and then expand - # ${bar}... and so forth. This is fine as long as 'vars' comes from -diff --git a/Lib/sysconfig/__main__.py b/Lib/sysconfig/__main__.py -index 10728c709e1..bc2197cfe79 100644 ---- a/Lib/sysconfig/__main__.py -+++ b/Lib/sysconfig/__main__.py -@@ -232,10 +232,14 @@ - - print(f'Written {destfile}') - -+ install_vars = get_config_vars() -+ # Fix config vars to match the values after install (of the default environment) -+ install_vars['projectbase'] = install_vars['BINDIR'] -+ install_vars['srcdir'] = install_vars['LIBPL'] - # Write a JSON file with the output of sysconfig.get_config_vars - jsonfile = os.path.join(pybuilddir, _get_json_data_name()) - with open(jsonfile, 'w') as f: -- json.dump(get_config_vars(), f, indent=2) -+ json.dump(install_vars, f, indent=2) - - print(f'Written {jsonfile}') - -diff --git a/Lib/tempfile.py b/Lib/tempfile.py -index b5a15f7b72c..0eb9ddeb6ac 100644 ---- a/Lib/tempfile.py -+++ b/Lib/tempfile.py -@@ -437,11 +437,19 @@ - cleanup_called = False - close_called = False - -- def __init__(self, file, name, delete=True, delete_on_close=True): -+ def __init__( -+ self, -+ file, -+ name, -+ delete=True, -+ delete_on_close=True, -+ warn_message="Implicitly cleaning up unknown file", -+ ): - self.file = file - self.name = name - self.delete = delete - self.delete_on_close = delete_on_close -+ self.warn_message = warn_message - - def cleanup(self, windows=(_os.name == 'nt'), unlink=_os.unlink): - if not self.cleanup_called: -@@ -469,7 +477,10 @@ - self.cleanup() - - def __del__(self): -+ close_called = self.close_called - self.cleanup() -+ if not close_called: -+ _warnings.warn(self.warn_message, ResourceWarning) - - - class _TemporaryFileWrapper: -@@ -483,8 +494,17 @@ - def __init__(self, file, name, delete=True, delete_on_close=True): - self.file = file - self.name = name -- self._closer = _TemporaryFileCloser(file, name, delete, -- delete_on_close) -+ self._closer = _TemporaryFileCloser( -+ file, -+ name, -+ delete, -+ delete_on_close, -+ warn_message=f"Implicitly cleaning up {self!r}", -+ ) -+ -+ def __repr__(self): -+ file = self.__dict__['file'] -+ return f"<{type(self).__name__} {file=}>" - - def __getattr__(self, name): - # Attribute lookups are delegated to the underlying file -diff --git a/Lib/test/_test_eintr.py b/Lib/test/_test_eintr.py -index 493932d6c6d..0ce42276bfe 100644 ---- a/Lib/test/_test_eintr.py -+++ b/Lib/test/_test_eintr.py -@@ -91,7 +91,7 @@ - """ EINTR tests for the os module. """ - - def new_sleep_process(self): -- code = 'import time; time.sleep(%r)' % self.sleep_time -+ code = f'import time; time.sleep({self.sleep_time!r})' - return self.subprocess(code) - - def _test_wait_multiple(self, wait_func): -@@ -123,35 +123,46 @@ - def test_wait4(self): - self._test_wait_single(lambda pid: os.wait4(pid, 0)) - -- def test_read(self): -+ def _interrupted_reads(self): -+ """Make a fd which will force block on read of expected bytes.""" - rd, wr = os.pipe() - self.addCleanup(os.close, rd) - # wr closed explicitly by parent - - # the payload below are smaller than PIPE_BUF, hence the writes will be - # atomic -- datas = [b"hello", b"world", b"spam"] -+ data = [b"hello", b"world", b"spam"] - - code = '\n'.join(( - 'import os, sys, time', - '', - 'wr = int(sys.argv[1])', -- 'datas = %r' % datas, -- 'sleep_time = %r' % self.sleep_time, -+ f'data = {data!r}', -+ f'sleep_time = {self.sleep_time!r}', - '', -- 'for data in datas:', -+ 'for item in data:', - ' # let the parent block on read()', - ' time.sleep(sleep_time)', -- ' os.write(wr, data)', -+ ' os.write(wr, item)', - )) - - proc = self.subprocess(code, str(wr), pass_fds=[wr]) - with kill_on_error(proc): - os.close(wr) -- for data in datas: -- self.assertEqual(data, os.read(rd, len(data))) -+ for datum in data: -+ yield rd, datum - self.assertEqual(proc.wait(), 0) - -+ def test_read(self): -+ for fd, expected in self._interrupted_reads(): -+ self.assertEqual(expected, os.read(fd, len(expected))) -+ -+ def test_readinto(self): -+ for fd, expected in self._interrupted_reads(): -+ buffer = bytearray(len(expected)) -+ self.assertEqual(os.readinto(fd, buffer), len(expected)) -+ self.assertEqual(buffer, expected) -+ - def test_write(self): - rd, wr = os.pipe() - self.addCleanup(os.close, wr) -@@ -164,8 +175,8 @@ - 'import io, os, sys, time', - '', - 'rd = int(sys.argv[1])', -- 'sleep_time = %r' % self.sleep_time, -- 'data = b"x" * %s' % support.PIPE_MAX_SIZE, -+ f'sleep_time = {self.sleep_time!r}', -+ f'data = b"x" * {support.PIPE_MAX_SIZE}', - 'data_len = len(data)', - '', - '# let the parent block on write()', -@@ -178,8 +189,8 @@ - '', - 'value = read_data.getvalue()', - 'if value != data:', -- ' raise Exception("read error: %s vs %s bytes"', -- ' % (len(value), data_len))', -+ ' raise Exception(f"read error: {len(value)}' -+ ' vs {data_len} bytes")', - )) - - proc = self.subprocess(code, str(rd), pass_fds=[rd]) -@@ -202,33 +213,33 @@ - # wr closed explicitly by parent - - # single-byte payload guard us against partial recv -- datas = [b"x", b"y", b"z"] -+ data = [b"x", b"y", b"z"] - - code = '\n'.join(( - 'import os, socket, sys, time', - '', - 'fd = int(sys.argv[1])', -- 'family = %s' % int(wr.family), -- 'sock_type = %s' % int(wr.type), -- 'datas = %r' % datas, -- 'sleep_time = %r' % self.sleep_time, -+ f'family = {int(wr.family)}', -+ f'sock_type = {int(wr.type)}', -+ f'data = {data!r}', -+ f'sleep_time = {self.sleep_time!r}', - '', - 'wr = socket.fromfd(fd, family, sock_type)', - 'os.close(fd)', - '', - 'with wr:', -- ' for data in datas:', -+ ' for item in data:', - ' # let the parent block on recv()', - ' time.sleep(sleep_time)', -- ' wr.sendall(data)', -+ ' wr.sendall(item)', - )) - - fd = wr.fileno() - proc = self.subprocess(code, str(fd), pass_fds=[fd]) - with kill_on_error(proc): - wr.close() -- for data in datas: -- self.assertEqual(data, recv_func(rd, len(data))) -+ for item in data: -+ self.assertEqual(item, recv_func(rd, len(item))) - self.assertEqual(proc.wait(), 0) - - def test_recv(self): -@@ -250,10 +261,10 @@ - 'import os, socket, sys, time', - '', - 'fd = int(sys.argv[1])', -- 'family = %s' % int(rd.family), -- 'sock_type = %s' % int(rd.type), -- 'sleep_time = %r' % self.sleep_time, -- 'data = b"xyz" * %s' % (support.SOCK_MAX_SIZE // 3), -+ f'family = {int(rd.family)}', -+ f'sock_type = {int(rd.type)}', -+ f'sleep_time = {self.sleep_time!r}', -+ f'data = b"xyz" * {support.SOCK_MAX_SIZE // 3}', - 'data_len = len(data)', - '', - 'rd = socket.fromfd(fd, family, sock_type)', -@@ -269,8 +280,8 @@ - ' n += rd.recv_into(memoryview(received_data)[n:])', - '', - 'if received_data != data:', -- ' raise Exception("recv error: %s vs %s bytes"', -- ' % (len(received_data), data_len))', -+ ' raise Exception(f"recv error: {len(received_data)}' -+ ' vs {data_len} bytes")', - )) - - fd = rd.fileno() -@@ -302,9 +313,9 @@ - code = '\n'.join(( - 'import socket, time', - '', -- 'host = %r' % socket_helper.HOST, -- 'port = %s' % port, -- 'sleep_time = %r' % self.sleep_time, -+ f'host = {socket_helper.HOST!r}', -+ f'port = {port}', -+ f'sleep_time = {self.sleep_time!r}', - '', - '# let parent block on accept()', - 'time.sleep(sleep_time)', -@@ -332,15 +343,15 @@ - os_helper.unlink(filename) - try: - os.mkfifo(filename) -- except PermissionError as e: -- self.skipTest('os.mkfifo(): %s' % e) -+ except PermissionError as exc: -+ self.skipTest(f'os.mkfifo(): {exc!r}') - self.addCleanup(os_helper.unlink, filename) - - code = '\n'.join(( - 'import os, time', - '', -- 'path = %a' % filename, -- 'sleep_time = %r' % self.sleep_time, -+ f'path = {filename!a}', -+ f'sleep_time = {self.sleep_time!r}', - '', - '# let the parent block', - 'time.sleep(sleep_time)', -@@ -396,21 +407,20 @@ - - def check_sigwait(self, wait_func): - signum = signal.SIGUSR1 -- pid = os.getpid() - - old_handler = signal.signal(signum, lambda *args: None) - self.addCleanup(signal.signal, signum, old_handler) - - code = '\n'.join(( - 'import os, time', -- 'pid = %s' % os.getpid(), -- 'signum = %s' % int(signum), -- 'sleep_time = %r' % self.sleep_time, -+ f'pid = {os.getpid()}', -+ f'signum = {int(signum)}', -+ f'sleep_time = {self.sleep_time!r}', - 'time.sleep(sleep_time)', - 'os.kill(pid, signum)', - )) - -- old_mask = signal.pthread_sigmask(signal.SIG_BLOCK, [signum]) -+ signal.pthread_sigmask(signal.SIG_BLOCK, [signum]) - self.addCleanup(signal.pthread_sigmask, signal.SIG_UNBLOCK, [signum]) - - proc = self.subprocess(code) -diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py -index 80b08b8ac66..4b7c3e7fa8b 100644 ---- a/Lib/test/_test_multiprocessing.py -+++ b/Lib/test/_test_multiprocessing.py -@@ -319,7 +319,7 @@ - authkey = current.authkey - - self.assertTrue(current.is_alive()) -- self.assertTrue(not current.daemon) -+ self.assertFalse(current.daemon) - self.assertIsInstance(authkey, bytes) - self.assertTrue(len(authkey) > 0) - self.assertEqual(current.ident, os.getpid()) -@@ -463,7 +463,7 @@ - self.assertEqual(p.is_alive(), False) - self.assertEqual(p.daemon, True) - self.assertNotIn(p, self.active_children()) -- self.assertTrue(type(self.active_children()) is list) -+ self.assertIs(type(self.active_children()), list) - self.assertEqual(p.exitcode, None) - - p.start() -@@ -583,8 +583,8 @@ - cpus = multiprocessing.cpu_count() - except NotImplementedError: - cpus = 1 -- self.assertTrue(type(cpus) is int) -- self.assertTrue(cpus >= 1) -+ self.assertIsInstance(cpus, int) -+ self.assertGreaterEqual(cpus, 1) - - def test_active_children(self): - self.assertEqual(type(self.active_children()), list) -@@ -2382,14 +2382,14 @@ - self.assertEqual(lock, lock3) - - arr4 = self.Value('i', 5, lock=False) -- self.assertFalse(hasattr(arr4, 'get_lock')) -- self.assertFalse(hasattr(arr4, 'get_obj')) -+ self.assertNotHasAttr(arr4, 'get_lock') -+ self.assertNotHasAttr(arr4, 'get_obj') - - self.assertRaises(AttributeError, self.Value, 'i', 5, lock='navalue') - - arr5 = self.RawValue('i', 5) -- self.assertFalse(hasattr(arr5, 'get_lock')) -- self.assertFalse(hasattr(arr5, 'get_obj')) -+ self.assertNotHasAttr(arr5, 'get_lock') -+ self.assertNotHasAttr(arr5, 'get_obj') - - - class _TestArray(BaseTestCase): -@@ -2462,14 +2462,14 @@ - self.assertEqual(lock, lock3) - - arr4 = self.Array('i', range(10), lock=False) -- self.assertFalse(hasattr(arr4, 'get_lock')) -- self.assertFalse(hasattr(arr4, 'get_obj')) -+ self.assertNotHasAttr(arr4, 'get_lock') -+ self.assertNotHasAttr(arr4, 'get_obj') - self.assertRaises(AttributeError, - self.Array, 'i', range(10), lock='notalock') - - arr5 = self.RawArray('i', range(10)) -- self.assertFalse(hasattr(arr5, 'get_lock')) -- self.assertFalse(hasattr(arr5, 'get_obj')) -+ self.assertNotHasAttr(arr5, 'get_lock') -+ self.assertNotHasAttr(arr5, 'get_obj') - - # - # -@@ -2657,8 +2657,8 @@ - self.assertEqual((n.name, n.job), ('Bob', 'Builder')) - del n.job - self.assertEqual(str(n), "Namespace(name='Bob')") -- self.assertTrue(hasattr(n, 'name')) -- self.assertTrue(not hasattr(n, 'job')) -+ self.assertHasAttr(n, 'name') -+ self.assertNotHasAttr(n, 'job') - - # - # -@@ -4938,13 +4938,9 @@ - for name in modules: - __import__(name) - mod = sys.modules[name] -- self.assertTrue(hasattr(mod, '__all__'), name) -- -+ self.assertHasAttr(mod, '__all__', name) - for attr in mod.__all__: -- self.assertTrue( -- hasattr(mod, attr), -- '%r does not have attribute %r' % (mod, attr) -- ) -+ self.assertHasAttr(mod, attr) - - # - # Quick test that logging works -- does not test logging output -@@ -4957,7 +4953,7 @@ - def test_enable_logging(self): - logger = multiprocessing.get_logger() - logger.setLevel(util.SUBWARNING) -- self.assertTrue(logger is not None) -+ self.assertIsNotNone(logger) - logger.debug('this will not be printed') - logger.info('nor will this') - logger.setLevel(LOG_LEVEL) -@@ -5753,9 +5749,8 @@ - self.assertEqual(multiprocessing.get_start_method(), method) - ctx = multiprocessing.get_context() - self.assertEqual(ctx.get_start_method(), method) -- self.assertTrue(type(ctx).__name__.lower().startswith(method)) -- self.assertTrue( -- ctx.Process.__name__.lower().startswith(method)) -+ self.assertStartsWith(type(ctx).__name__.lower(), method) -+ self.assertStartsWith(ctx.Process.__name__.lower(), method) - self.check_context(multiprocessing) - count += 1 - finally: -@@ -5956,9 +5951,9 @@ - if should_die: - self.assertEqual(len(all_warn), 1) - the_warn = all_warn[0] -- self.assertTrue(issubclass(the_warn.category, UserWarning)) -- self.assertTrue("resource_tracker: process died" -- in str(the_warn.message)) -+ self.assertIsSubclass(the_warn.category, UserWarning) -+ self.assertIn("resource_tracker: process died", -+ str(the_warn.message)) - else: - self.assertEqual(len(all_warn), 0) - -@@ -6045,6 +6040,27 @@ - cleanup=cleanup, - ) - -+ @unittest.skipUnless(hasattr(signal, "pthread_sigmask"), "pthread_sigmask is not available") -+ def test_resource_tracker_blocked_signals(self): -+ # -+ # gh-127586: Check that resource_tracker does not override blocked signals of caller. -+ # -+ from multiprocessing.resource_tracker import ResourceTracker -+ orig_sigmask = signal.pthread_sigmask(signal.SIG_BLOCK, set()) -+ signals = {signal.SIGTERM, signal.SIGINT, signal.SIGUSR1} -+ -+ try: -+ for sig in signals: -+ signal.pthread_sigmask(signal.SIG_SETMASK, {sig}) -+ self.assertEqual(signal.pthread_sigmask(signal.SIG_BLOCK, set()), {sig}) -+ tracker = ResourceTracker() -+ tracker.ensure_running() -+ self.assertEqual(signal.pthread_sigmask(signal.SIG_BLOCK, set()), {sig}) -+ tracker._stop() -+ finally: -+ # restore sigmask to what it was before executing test -+ signal.pthread_sigmask(signal.SIG_SETMASK, orig_sigmask) -+ - class TestSimpleQueue(unittest.TestCase): - - @classmethod -@@ -6142,8 +6158,8 @@ - Process=FailingForkProcess)) - p.close() - p.join() -- self.assertFalse( -- any(process.is_alive() for process in forked_processes)) -+ for process in forked_processes: -+ self.assertFalse(process.is_alive(), process) - - - @hashlib_helper.requires_hashdigest('sha256') -diff --git a/Lib/test/audit-tests.py b/Lib/test/audit-tests.py -index 6df09d89143..6b9b21cf7f6 100644 ---- a/Lib/test/audit-tests.py -+++ b/Lib/test/audit-tests.py -@@ -187,7 +187,7 @@ - - - def test_open(testfn): -- # SSLContext.load_dh_params uses _Py_fopen_obj rather than normal open() -+ # SSLContext.load_dh_params uses Py_fopen() rather than normal open() - try: - import ssl - -diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c -index b6ae04ecf2f..0dfcc281985 100644 ---- a/Lib/test/clinic.test.c -+++ b/Lib/test/clinic.test.c -@@ -4758,7 +4758,7 @@ - Test_cls_with_param_impl(TestObj *self, PyTypeObject *cls, int a); - - static PyObject * --Test_cls_with_param(TestObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+Test_cls_with_param(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -4798,7 +4798,7 @@ - if (a == -1 && PyErr_Occurred()) { - goto exit; - } -- return_value = Test_cls_with_param_impl(self, cls, a); -+ return_value = Test_cls_with_param_impl((TestObj *)self, cls, a); - - exit: - return return_value; -@@ -4806,7 +4806,7 @@ - - static PyObject * - Test_cls_with_param_impl(TestObj *self, PyTypeObject *cls, int a) --/*[clinic end generated code: output=83a391eea66d08f8 input=af158077bd237ef9]*/ -+/*[clinic end generated code: output=7e893134a81fef92 input=af158077bd237ef9]*/ - - - /*[clinic input] -@@ -4908,18 +4908,18 @@ - Test_cls_no_params_impl(TestObj *self, PyTypeObject *cls); - - static PyObject * --Test_cls_no_params(TestObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+Test_cls_no_params(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "cls_no_params() takes no arguments"); - return NULL; - } -- return Test_cls_no_params_impl(self, cls); -+ return Test_cls_no_params_impl((TestObj *)self, cls); - } - - static PyObject * - Test_cls_no_params_impl(TestObj *self, PyTypeObject *cls) --/*[clinic end generated code: output=4d68b4652c144af3 input=e7e2e4e344e96a11]*/ -+/*[clinic end generated code: output=8845de054449f40a input=e7e2e4e344e96a11]*/ - - - /*[clinic input] -@@ -4945,7 +4945,7 @@ - PyObject *return_value = NULL; - int _return_value; - -- _return_value = Test_metho_not_default_return_converter_impl(self, a); -+ _return_value = Test_metho_not_default_return_converter_impl((TestObj *)self, a); - if ((_return_value == -1) && PyErr_Occurred()) { - goto exit; - } -@@ -4957,7 +4957,7 @@ - - static int - Test_metho_not_default_return_converter_impl(TestObj *self, PyObject *a) --/*[clinic end generated code: output=3350de11bd538007 input=428657129b521177]*/ -+/*[clinic end generated code: output=b2cce75a7af2e6ce input=428657129b521177]*/ - - - /*[clinic input] -@@ -4983,7 +4983,7 @@ - Test_an_metho_arg_named_arg_impl(TestObj *self, int arg); - - static PyObject * --Test_an_metho_arg_named_arg(TestObj *self, PyObject *arg_) -+Test_an_metho_arg_named_arg(PyObject *self, PyObject *arg_) - { - PyObject *return_value = NULL; - int arg; -@@ -4992,7 +4992,7 @@ - if (arg == -1 && PyErr_Occurred()) { - goto exit; - } -- return_value = Test_an_metho_arg_named_arg_impl(self, arg); -+ return_value = Test_an_metho_arg_named_arg_impl((TestObj *)self, arg); - - exit: - return return_value; -@@ -5000,7 +5000,7 @@ - - static PyObject * - Test_an_metho_arg_named_arg_impl(TestObj *self, int arg) --/*[clinic end generated code: output=9f04de4a62287e28 input=2a53a57cf5624f95]*/ -+/*[clinic end generated code: output=38554f09950d07e7 input=2a53a57cf5624f95]*/ - - - /*[clinic input] -@@ -5289,14 +5289,14 @@ - Test_meth_coexist_impl(TestObj *self); - - static PyObject * --Test_meth_coexist(TestObj *self, PyObject *Py_UNUSED(ignored)) -+Test_meth_coexist(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return Test_meth_coexist_impl(self); -+ return Test_meth_coexist_impl((TestObj *)self); - } - - static PyObject * - Test_meth_coexist_impl(TestObj *self) --/*[clinic end generated code: output=808a293d0cd27439 input=2a1d75b5e6fec6dd]*/ -+/*[clinic end generated code: output=7edf4e95b29f06fa input=2a1d75b5e6fec6dd]*/ - - /*[clinic input] - @getter -@@ -5317,14 +5317,14 @@ - Test_property_get_impl(TestObj *self); - - static PyObject * --Test_property_get(TestObj *self, void *Py_UNUSED(context)) -+Test_property_get(PyObject *self, void *Py_UNUSED(context)) - { -- return Test_property_get_impl(self); -+ return Test_property_get_impl((TestObj *)self); - } - - static PyObject * - Test_property_get_impl(TestObj *self) --/*[clinic end generated code: output=7cadd0f539805266 input=2d92b3449fbc7d2b]*/ -+/*[clinic end generated code: output=b38d68abd3466a6e input=2d92b3449fbc7d2b]*/ - - /*[clinic input] - @setter -@@ -5345,18 +5345,87 @@ - Test_property_set_impl(TestObj *self, PyObject *value); - - static int --Test_property_set(TestObj *self, PyObject *value, void *Py_UNUSED(context)) -+Test_property_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) - { - int return_value; - -- return_value = Test_property_set_impl(self, value); -+ return_value = Test_property_set_impl((TestObj *)self, value); - - return return_value; - } - - static int - Test_property_set_impl(TestObj *self, PyObject *value) --/*[clinic end generated code: output=e4342fe9bb1d7817 input=3bc3f46a23c83a88]*/ -+/*[clinic end generated code: output=49f925ab2a33b637 input=3bc3f46a23c83a88]*/ -+ -+/*[clinic input] -+@setter -+Test.setter_first_with_docstr -+[clinic start generated code]*/ -+ -+#if !defined(Test_setter_first_with_docstr_DOCSTR) -+# define Test_setter_first_with_docstr_DOCSTR NULL -+#endif -+#if defined(TEST_SETTER_FIRST_WITH_DOCSTR_GETSETDEF) -+# undef TEST_SETTER_FIRST_WITH_DOCSTR_GETSETDEF -+# define TEST_SETTER_FIRST_WITH_DOCSTR_GETSETDEF {"setter_first_with_docstr", (getter)Test_setter_first_with_docstr_get, (setter)Test_setter_first_with_docstr_set, Test_setter_first_with_docstr_DOCSTR}, -+#else -+# define TEST_SETTER_FIRST_WITH_DOCSTR_GETSETDEF {"setter_first_with_docstr", NULL, (setter)Test_setter_first_with_docstr_set, NULL}, -+#endif -+ -+static int -+Test_setter_first_with_docstr_set_impl(TestObj *self, PyObject *value); -+ -+static int -+Test_setter_first_with_docstr_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) -+{ -+ int return_value; -+ -+ return_value = Test_setter_first_with_docstr_set_impl((TestObj *)self, value); -+ -+ return return_value; -+} -+ -+static int -+Test_setter_first_with_docstr_set_impl(TestObj *self, PyObject *value) -+/*[clinic end generated code: output=5aaf44373c0af545 input=31a045ce11bbe961]*/ -+ -+/*[clinic input] -+@getter -+Test.setter_first_with_docstr -+ -+my silly docstring -+[clinic start generated code]*/ -+ -+PyDoc_STRVAR(Test_setter_first_with_docstr__doc__, -+"my silly docstring"); -+#if defined(Test_setter_first_with_docstr_DOCSTR) -+# undef Test_setter_first_with_docstr_DOCSTR -+#endif -+#define Test_setter_first_with_docstr_DOCSTR Test_setter_first_with_docstr__doc__ -+ -+#if !defined(Test_setter_first_with_docstr_DOCSTR) -+# define Test_setter_first_with_docstr_DOCSTR NULL -+#endif -+#if defined(TEST_SETTER_FIRST_WITH_DOCSTR_GETSETDEF) -+# undef TEST_SETTER_FIRST_WITH_DOCSTR_GETSETDEF -+# define TEST_SETTER_FIRST_WITH_DOCSTR_GETSETDEF {"setter_first_with_docstr", (getter)Test_setter_first_with_docstr_get, (setter)Test_setter_first_with_docstr_set, Test_setter_first_with_docstr_DOCSTR}, -+#else -+# define TEST_SETTER_FIRST_WITH_DOCSTR_GETSETDEF {"setter_first_with_docstr", (getter)Test_setter_first_with_docstr_get, NULL, Test_setter_first_with_docstr_DOCSTR}, -+#endif -+ -+static PyObject * -+Test_setter_first_with_docstr_get_impl(TestObj *self); -+ -+static PyObject * -+Test_setter_first_with_docstr_get(PyObject *self, void *Py_UNUSED(context)) -+{ -+ return Test_setter_first_with_docstr_get_impl((TestObj *)self); -+} -+ -+static PyObject * -+Test_setter_first_with_docstr_get_impl(TestObj *self) -+/*[clinic end generated code: output=fe6e3aa844a24920 input=10af4e43b3cb34dc]*/ - - /*[clinic input] - output push -@@ -5639,7 +5708,7 @@ - Py_ssize_t key_length); - - static PyObject * --Test__pyarg_parsestackandkeywords(TestObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+Test__pyarg_parsestackandkeywords(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -5662,7 +5731,7 @@ - &key, &key_length)) { - goto exit; - } -- return_value = Test__pyarg_parsestackandkeywords_impl(self, cls, key, key_length); -+ return_value = Test__pyarg_parsestackandkeywords_impl((TestObj *)self, cls, key, key_length); - - exit: - return return_value; -@@ -5672,7 +5741,7 @@ - Test__pyarg_parsestackandkeywords_impl(TestObj *self, PyTypeObject *cls, - const char *key, - Py_ssize_t key_length) --/*[clinic end generated code: output=4fda8a7f2547137c input=fc72ef4b4cfafabc]*/ -+/*[clinic end generated code: output=7060c213d7b8200e input=fc72ef4b4cfafabc]*/ - - - /*[clinic input] -diff --git a/Lib/test/libregrtest/cmdline.py b/Lib/test/libregrtest/cmdline.py -index bf9a71efbdb..81c7106ac0c 100644 ---- a/Lib/test/libregrtest/cmdline.py -+++ b/Lib/test/libregrtest/cmdline.py -@@ -160,6 +160,7 @@ - self.print_slow = False - self.random_seed = None - self.use_mp = None -+ self.parallel_threads = None - self.forever = False - self.header = False - self.failfast = False -@@ -167,6 +168,7 @@ - self.pgo = False - self.pgo_extended = False - self.tsan = False -+ self.tsan_parallel = False - self.worker_json = None - self.start = None - self.timeout = None -@@ -316,6 +318,10 @@ - 'a single process, ignore -jN option, ' - 'and failed tests are also rerun sequentially ' - 'in the same process') -+ group.add_argument('--parallel-threads', metavar='PARALLEL_THREADS', -+ type=int, -+ help='run copies of each test in PARALLEL_THREADS at ' -+ 'once') - group.add_argument('-T', '--coverage', action='store_true', - dest='trace', - help='turn on code coverage tracing using the trace ' -@@ -346,6 +352,9 @@ - help='enable extended PGO training (slower training)') - group.add_argument('--tsan', dest='tsan', action='store_true', - help='run a subset of test cases that are proper for the TSAN test') -+ group.add_argument('--tsan-parallel', action='store_true', -+ help='run a subset of test cases that are appropriate ' -+ 'for TSAN with `--parallel-threads=N`') - group.add_argument('--fail-env-changed', action='store_true', - help='if a test file alters the environment, mark ' - 'the test as failed') -diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py -index dcbcc6790c6..2f8fd4c92c1 100644 ---- a/Lib/test/libregrtest/main.py -+++ b/Lib/test/libregrtest/main.py -@@ -20,7 +20,7 @@ - from .runtests import RunTests, HuntRefleak - from .setup import setup_process, setup_test_dir - from .single import run_single_test, PROGRESS_MIN_TIME --from .tsan import setup_tsan_tests -+from .tsan import setup_tsan_tests, setup_tsan_parallel_tests - from .utils import ( - StrPath, StrJSON, TestName, TestList, TestTuple, TestFilter, - strip_py_suffix, count, format_duration, -@@ -60,6 +60,7 @@ - self.pgo: bool = ns.pgo - self.pgo_extended: bool = ns.pgo_extended - self.tsan: bool = ns.tsan -+ self.tsan_parallel: bool = ns.tsan_parallel - - # Test results - self.results: TestResults = TestResults() -@@ -142,6 +143,8 @@ - else: - self.random_seed = ns.random_seed - -+ self.parallel_threads = ns.parallel_threads -+ - # tests - self.first_runtests: RunTests | None = None - -@@ -193,6 +196,9 @@ - if self.tsan: - setup_tsan_tests(self.cmdline_args) - -+ if self.tsan_parallel: -+ setup_tsan_parallel_tests(self.cmdline_args) -+ - exclude_tests = set() - if self.exclude: - for arg in self.cmdline_args: -@@ -506,6 +512,7 @@ - python_cmd=self.python_cmd, - randomize=self.randomize, - random_seed=self.random_seed, -+ parallel_threads=self.parallel_threads, - ) - - def _run_tests(self, selected: TestTuple, tests: TestList | None) -> int: ---- /dev/null -+++ b/Lib/test/libregrtest/parallel_case.py -@@ -0,0 +1,79 @@ -+"""Run a test case multiple times in parallel threads.""" -+ -+import copy -+import functools -+import threading -+import unittest -+ -+from unittest import TestCase -+ -+ -+class ParallelTestCase(TestCase): -+ def __init__(self, test_case: TestCase, num_threads: int): -+ self.test_case = test_case -+ self.num_threads = num_threads -+ self._testMethodName = test_case._testMethodName -+ self._testMethodDoc = test_case._testMethodDoc -+ -+ def __str__(self): -+ return f"{str(self.test_case)} [threads={self.num_threads}]" -+ -+ def run_worker(self, test_case: TestCase, result: unittest.TestResult, -+ barrier: threading.Barrier): -+ barrier.wait() -+ test_case.run(result) -+ -+ def run(self, result=None): -+ if result is None: -+ result = test_case.defaultTestResult() -+ startTestRun = getattr(result, 'startTestRun', None) -+ stopTestRun = getattr(result, 'stopTestRun', None) -+ if startTestRun is not None: -+ startTestRun() -+ else: -+ stopTestRun = None -+ -+ # Called at the beginning of each test. See TestCase.run. -+ result.startTest(self) -+ -+ cases = [copy.copy(self.test_case) for _ in range(self.num_threads)] -+ results = [unittest.TestResult() for _ in range(self.num_threads)] -+ -+ barrier = threading.Barrier(self.num_threads) -+ threads = [] -+ for i, (case, r) in enumerate(zip(cases, results)): -+ thread = threading.Thread(target=self.run_worker, -+ args=(case, r, barrier), -+ name=f"{str(self.test_case)}-{i}", -+ daemon=True) -+ threads.append(thread) -+ -+ for thread in threads: -+ thread.start() -+ -+ for threads in threads: -+ threads.join() -+ -+ # Aggregate test results -+ if all(r.wasSuccessful() for r in results): -+ result.addSuccess(self) -+ -+ # Note: We can't call result.addError, result.addFailure, etc. because -+ # we no longer have the original exception, just the string format. -+ for r in results: -+ if len(r.errors) > 0 or len(r.failures) > 0: -+ result._mirrorOutput = True -+ result.errors.extend(r.errors) -+ result.failures.extend(r.failures) -+ result.skipped.extend(r.skipped) -+ result.expectedFailures.extend(r.expectedFailures) -+ result.unexpectedSuccesses.extend(r.unexpectedSuccesses) -+ result.collectedDurations.extend(r.collectedDurations) -+ -+ if any(r.shouldStop for r in results): -+ result.stop() -+ -+ # Test has finished running -+ result.stopTest(self) -+ if stopTestRun is not None: -+ stopTestRun() -diff --git a/Lib/test/libregrtest/pgo.py b/Lib/test/libregrtest/pgo.py -index f762345c88c..04803ddf644 100644 ---- a/Lib/test/libregrtest/pgo.py -+++ b/Lib/test/libregrtest/pgo.py -@@ -19,7 +19,6 @@ - 'test_datetime', - 'test_decimal', - 'test_difflib', -- 'test_embed', - 'test_float', - 'test_fstring', - 'test_functools', -diff --git a/Lib/test/libregrtest/runtests.py b/Lib/test/libregrtest/runtests.py -index 130c036a62e..759f24fc25e 100644 ---- a/Lib/test/libregrtest/runtests.py -+++ b/Lib/test/libregrtest/runtests.py -@@ -100,6 +100,7 @@ - python_cmd: tuple[str, ...] | None - randomize: bool - random_seed: int | str -+ parallel_threads: int | None - - def copy(self, **override) -> 'RunTests': - state = dataclasses.asdict(self) -@@ -184,6 +185,8 @@ - args.extend(("--python", cmd)) - if self.randomize: - args.append(f"--randomize") -+ if self.parallel_threads: -+ args.append(f"--parallel-threads={self.parallel_threads}") - args.append(f"--randseed={self.random_seed}") - return args - -diff --git a/Lib/test/libregrtest/save_env.py b/Lib/test/libregrtest/save_env.py -index b2cc381344b..ffc29fa8dc6 100644 ---- a/Lib/test/libregrtest/save_env.py -+++ b/Lib/test/libregrtest/save_env.py -@@ -97,7 +97,7 @@ - return support.maybe_get_event_loop_policy() - def restore_asyncio_events__event_loop_policy(self, policy): - asyncio = self.get_module('asyncio') -- asyncio.set_event_loop_policy(policy) -+ asyncio._set_event_loop_policy(policy) - - def get_sys_argv(self): - return id(sys.argv), sys.argv, sys.argv[:] -diff --git a/Lib/test/libregrtest/single.py b/Lib/test/libregrtest/single.py -index 0e174f82abe..57d7b649d2e 100644 ---- a/Lib/test/libregrtest/single.py -+++ b/Lib/test/libregrtest/single.py -@@ -17,6 +17,7 @@ - from .save_env import saved_test_environment - from .setup import setup_tests - from .testresult import get_test_runner -+from .parallel_case import ParallelTestCase - from .utils import ( - TestName, - clear_caches, remove_testfn, abs_module_name, print_warning) -@@ -27,14 +28,17 @@ - PROGRESS_MIN_TIME = 30.0 # seconds - - --def run_unittest(test_mod): -+def run_unittest(test_mod, runtests: RunTests): - loader = unittest.TestLoader() - tests = loader.loadTestsFromModule(test_mod) -+ - for error in loader.errors: - print(error, file=sys.stderr) - if loader.errors: - raise Exception("errors while loading tests") - _filter_suite(tests, match_test) -+ if runtests.parallel_threads: -+ _parallelize_tests(tests, runtests.parallel_threads) - return _run_suite(tests) - - def _filter_suite(suite, pred): -@@ -49,6 +53,28 @@ - newtests.append(test) - suite._tests = newtests - -+def _parallelize_tests(suite, parallel_threads: int): -+ def is_thread_unsafe(test): -+ test_method = getattr(test, test._testMethodName) -+ instance = test_method.__self__ -+ return (getattr(test_method, "__unittest_thread_unsafe__", False) or -+ getattr(instance, "__unittest_thread_unsafe__", False)) -+ -+ newtests: list[object] = [] -+ for test in suite._tests: -+ if isinstance(test, unittest.TestSuite): -+ _parallelize_tests(test, parallel_threads) -+ newtests.append(test) -+ continue -+ -+ if is_thread_unsafe(test): -+ # Don't parallelize thread-unsafe tests -+ newtests.append(test) -+ continue -+ -+ newtests.append(ParallelTestCase(test, parallel_threads)) -+ suite._tests = newtests -+ - def _run_suite(suite): - """Run tests from a unittest.TestSuite-derived class.""" - runner = get_test_runner(sys.stdout, -@@ -133,7 +159,7 @@ - raise Exception(f"Module {test_name} defines test_main() which " - f"is no longer supported by regrtest") - def test_func(): -- return run_unittest(test_mod) -+ return run_unittest(test_mod, runtests) - - try: - regrtest_runner(result, test_func, runtests) -@@ -162,8 +188,8 @@ - def _runtest_env_changed_exc(result: TestResult, runtests: RunTests, - display_failure: bool = True) -> None: - # Handle exceptions, detect environment changes. -- ansi = get_colors() -- red, reset, yellow = ansi.RED, ansi.RESET, ansi.YELLOW -+ stdout = get_colors(file=sys.stdout) -+ stderr = get_colors(file=sys.stderr) - - # Reset the environment_altered flag to detect if a test altered - # the environment -@@ -184,18 +210,24 @@ - _load_run_test(result, runtests) - except support.ResourceDenied as exc: - if not quiet and not pgo: -- print(f"{yellow}{test_name} skipped -- {exc}{reset}", flush=True) -+ print( -+ f"{stdout.YELLOW}{test_name} skipped -- {exc}{stdout.RESET}", -+ flush=True, -+ ) - result.state = State.RESOURCE_DENIED - return - except unittest.SkipTest as exc: - if not quiet and not pgo: -- print(f"{yellow}{test_name} skipped -- {exc}{reset}", flush=True) -+ print( -+ f"{stdout.YELLOW}{test_name} skipped -- {exc}{stdout.RESET}", -+ flush=True, -+ ) - result.state = State.SKIPPED - return - except support.TestFailedWithDetails as exc: -- msg = f"{red}test {test_name} failed{reset}" -+ msg = f"{stderr.RED}test {test_name} failed{stderr.RESET}" - if display_failure: -- msg = f"{red}{msg} -- {exc}{reset}" -+ msg = f"{stderr.RED}{msg} -- {exc}{stderr.RESET}" - print(msg, file=sys.stderr, flush=True) - result.state = State.FAILED - result.errors = exc.errors -@@ -203,9 +235,9 @@ - result.stats = exc.stats - return - except support.TestFailed as exc: -- msg = f"{red}test {test_name} failed{reset}" -+ msg = f"{stderr.RED}test {test_name} failed{stderr.RESET}" - if display_failure: -- msg = f"{red}{msg} -- {exc}{reset}" -+ msg = f"{stderr.RED}{msg} -- {exc}{stderr.RESET}" - print(msg, file=sys.stderr, flush=True) - result.state = State.FAILED - result.stats = exc.stats -@@ -220,8 +252,11 @@ - except: - if not pgo: - msg = traceback.format_exc() -- print(f"{red}test {test_name} crashed -- {msg}{reset}", -- file=sys.stderr, flush=True) -+ print( -+ f"{stderr.RED}test {test_name} crashed -- {msg}{stderr.RESET}", -+ file=sys.stderr, -+ flush=True, -+ ) - result.state = State.UNCAUGHT_EXC - return - -@@ -303,7 +338,7 @@ - If runtests.use_junit, xml_data is a list containing each generated - testsuite element. - """ -- ansi = get_colors() -+ ansi = get_colors(file=sys.stderr) - red, reset, yellow = ansi.BOLD_RED, ansi.RESET, ansi.YELLOW - - start_time = time.perf_counter() -diff --git a/Lib/test/libregrtest/tsan.py b/Lib/test/libregrtest/tsan.py -index 00d5779d950..10b12cce165 100644 ---- a/Lib/test/libregrtest/tsan.py -+++ b/Lib/test/libregrtest/tsan.py -@@ -25,10 +25,22 @@ - 'test_threading_local', - 'test_threadsignals', - 'test_weakref', -- 'test_free_threading.test_slots', -+ 'test_free_threading', -+] -+ -+# Tests that should be run with `--parallel-threads=N` under TSAN. These tests -+# typically do not use threads, but are run multiple times in parallel by -+# the regression test runner with the `--parallel-threads` option enabled. -+TSAN_PARALLEL_TESTS = [ -+ 'test_abc', -+ 'test_hashlib', - ] - - - def setup_tsan_tests(cmdline_args) -> None: - if not cmdline_args: - cmdline_args[:] = TSAN_TESTS[:] -+ -+def setup_tsan_parallel_tests(cmdline_args) -> None: -+ if not cmdline_args: -+ cmdline_args[:] = TSAN_PARALLEL_TESTS[:] -diff --git a/Lib/test/libregrtest/worker.py b/Lib/test/libregrtest/worker.py -index 0c9f5bd6e42..5d75bf7ae78 100644 ---- a/Lib/test/libregrtest/worker.py -+++ b/Lib/test/libregrtest/worker.py -@@ -56,6 +56,15 @@ - if USE_PROCESS_GROUP and test_name not in NEED_TTY: - kwargs['start_new_session'] = True - -+ # Include the test name in the TSAN log file name -+ if 'TSAN_OPTIONS' in env: -+ parts = env['TSAN_OPTIONS'].split(' ') -+ for i, part in enumerate(parts): -+ if part.startswith('log_path='): -+ parts[i] = f'{part}.{test_name}' -+ break -+ env['TSAN_OPTIONS'] = ' '.join(parts) -+ - # Pass json_file to the worker process - json_file = runtests.json_file - json_file.configure_subprocess(kwargs) -diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py -index 5c738ffaa27..f31d98bf731 100644 ---- a/Lib/test/support/__init__.py -+++ b/Lib/test/support/__init__.py -@@ -40,7 +40,7 @@ - "anticipate_failure", "load_package_tests", "detect_api_mismatch", - "check__all__", "skip_if_buggy_ucrt_strfptime", - "check_disallow_instantiation", "check_sanitizer", "skip_if_sanitizer", -- "requires_limited_api", "requires_specialization", -+ "requires_limited_api", "requires_specialization", "thread_unsafe", - # sys - "MS_WINDOWS", "is_jython", "is_android", "is_emscripten", "is_wasi", - "is_apple_mobile", "check_impl_detail", "unix_shell", "setswitchinterval", -@@ -58,10 +58,15 @@ - "LOOPBACK_TIMEOUT", "INTERNET_TIMEOUT", "SHORT_TIMEOUT", "LONG_TIMEOUT", - "Py_DEBUG", "exceeds_recursion_limit", "get_c_recursion_limit", - "skip_on_s390x", -- "without_optimizer", -+ "requires_jit_enabled", -+ "requires_jit_disabled", - "force_not_colorized", -+ "force_not_colorized_test_class", -+ "make_clean_env", - "BrokenIter", - "in_systemd_nspawn_sync_suppressed", -+ "run_no_yield_async_fn", "run_yielding_async_fn", "async_yield", -+ "reset_code", - ] - - -@@ -377,6 +382,21 @@ - return decorator - - -+def thread_unsafe(reason): -+ """Mark a test as not thread safe. When the test runner is run with -+ --parallel-threads=N, the test will be run in a single thread.""" -+ def decorator(test_item): -+ test_item.__unittest_thread_unsafe__ = True -+ # the reason is not currently used -+ test_item.__unittest_thread_unsafe__why__ = reason -+ return test_item -+ if isinstance(reason, types.FunctionType): -+ test_item = reason -+ reason = '' -+ return decorator(test_item) -+ return decorator -+ -+ - def skip_if_buildbot(reason=None): - """Decorator raising SkipTest if running on a buildbot.""" - import getpass -@@ -503,10 +523,10 @@ - - def has_no_debug_ranges(): - try: -- import _testinternalcapi -+ import _testcapi - except ImportError: - raise unittest.SkipTest("_testinternalcapi required") -- config = _testinternalcapi.get_config() -+ return not _testcapi.config_get('code_debug_ranges') - return not bool(config['code_debug_ranges']) - - def requires_debug_ranges(reason='requires co_positions / debug_ranges'): -@@ -1282,6 +1302,12 @@ - _opcode.ENABLE_SPECIALIZATION_FT, "requires specialization")(test) - - -+def reset_code(f: types.FunctionType) -> types.FunctionType: -+ """Clear all specializations, local instrumentation, and JIT code for the given function.""" -+ f.__code__ = f.__code__.replace() -+ return f -+ -+ - #======================================================================= - # Check for the presence of docstrings. - -@@ -2617,21 +2643,13 @@ - - Py_TRACE_REFS = hasattr(sys, 'getobjects') - --# Decorator to disable optimizer while a function run --def without_optimizer(func): -- try: -- from _testinternalcapi import get_optimizer, set_optimizer -- except ImportError: -- return func -- @functools.wraps(func) -- def wrapper(*args, **kwargs): -- save_opt = get_optimizer() -- try: -- set_optimizer(None) -- return func(*args, **kwargs) -- finally: -- set_optimizer(save_opt) -- return wrapper -+try: -+ from _testinternalcapi import jit_enabled -+except ImportError: -+ requires_jit_enabled = requires_jit_disabled = unittest.skip("requires _testinternalcapi") -+else: -+ requires_jit_enabled = unittest.skipUnless(jit_enabled(), "requires JIT enabled") -+ requires_jit_disabled = unittest.skipIf(jit_enabled(), "requires JIT disabled") - - - _BASE_COPY_SRC_DIR_IGNORED_NAMES = frozenset({ -@@ -2831,30 +2849,54 @@ - yield name, True - - -+@contextlib.contextmanager -+def no_color(): -+ import _colorize -+ from .os_helper import EnvironmentVarGuard -+ -+ with ( -+ swap_attr(_colorize, "can_colorize", lambda file=None: False), -+ EnvironmentVarGuard() as env, -+ ): -+ for var in {"FORCE_COLOR", "NO_COLOR", "PYTHON_COLORS"}: -+ env.unset(var) -+ env.set("NO_COLOR", "1") -+ yield -+ -+ - def force_not_colorized(func): - """Force the terminal not to be colorized.""" - @functools.wraps(func) - def wrapper(*args, **kwargs): -- import _colorize -- original_fn = _colorize.can_colorize -- variables: dict[str, str | None] = { -- "PYTHON_COLORS": None, "FORCE_COLOR": None, "NO_COLOR": None -- } -- try: -- for key in variables: -- variables[key] = os.environ.pop(key, None) -- os.environ["NO_COLOR"] = "1" -- _colorize.can_colorize = lambda: False -+ with no_color(): - return func(*args, **kwargs) -- finally: -- _colorize.can_colorize = original_fn -- del os.environ["NO_COLOR"] -- for key, value in variables.items(): -- if value is not None: -- os.environ[key] = value - return wrapper - - -+def force_not_colorized_test_class(cls): -+ """Force the terminal not to be colorized for the entire test class.""" -+ original_setUpClass = cls.setUpClass -+ -+ @classmethod -+ @functools.wraps(cls.setUpClass) -+ def new_setUpClass(cls): -+ cls.enterClassContext(no_color()) -+ original_setUpClass() -+ -+ cls.setUpClass = new_setUpClass -+ return cls -+ -+ -+def make_clean_env() -> dict[str, str]: -+ clean_env = os.environ.copy() -+ for k in clean_env.copy(): -+ if k.startswith("PYTHON"): -+ clean_env.pop(k) -+ clean_env.pop("FORCE_COLOR", None) -+ clean_env.pop("NO_COLOR", None) -+ return clean_env -+ -+ - def initialized_with_pyrepl(): - """Detect whether PyREPL was used during Python initialization.""" - # If the main module has a __file__ attribute it's a Python module, which means PyREPL. -@@ -2940,3 +2982,39 @@ - os.close(fd) - - return False -+ -+def run_no_yield_async_fn(async_fn, /, *args, **kwargs): -+ coro = async_fn(*args, **kwargs) -+ try: -+ coro.send(None) -+ except StopIteration as e: -+ return e.value -+ else: -+ raise AssertionError("coroutine did not complete") -+ finally: -+ coro.close() -+ -+ -+@types.coroutine -+def async_yield(v): -+ return (yield v) -+ -+ -+def run_yielding_async_fn(async_fn, /, *args, **kwargs): -+ coro = async_fn(*args, **kwargs) -+ try: -+ while True: -+ try: -+ coro.send(None) -+ except StopIteration as e: -+ return e.value -+ finally: -+ coro.close() -+ -+ -+def is_libssl_fips_mode(): -+ try: -+ from _hashlib import get_fips_mode # ask _hashopenssl.c -+ except ImportError: -+ return False # more of a maybe, unless we add this to the _ssl module. -+ return get_fips_mode() != 0 -diff --git a/Lib/test/support/os_helper.py b/Lib/test/support/os_helper.py -index 8071c248b9b..15dcdc9b1fd 100644 ---- a/Lib/test/support/os_helper.py -+++ b/Lib/test/support/os_helper.py -@@ -294,6 +294,33 @@ - return test if ok else unittest.skip(msg)(test) - - -+@contextlib.contextmanager -+def save_mode(path, *, quiet=False): -+ """Context manager that restores the mode (permissions) of *path* on exit. -+ -+ Arguments: -+ -+ path: Path of the file to restore the mode of. -+ -+ quiet: if False (the default), the context manager raises an exception -+ on error. Otherwise, it issues only a warning and keeps the current -+ working directory the same. -+ -+ """ -+ saved_mode = os.stat(path) -+ try: -+ yield -+ finally: -+ try: -+ os.chmod(path, saved_mode.st_mode) -+ except OSError as exc: -+ if not quiet: -+ raise -+ warnings.warn(f'tests may fail, unable to restore the mode of ' -+ f'{path!r} to {saved_mode.st_mode}: {exc}', -+ RuntimeWarning, stacklevel=3) -+ -+ - # Check whether the current effective user has the capability to override - # DAC (discretionary access control). Typically user root is able to - # bypass file read, write, and execute permission checks. The capability -diff --git a/Lib/test/support/venv.py b/Lib/test/support/venv.py -index 78e6a51ec18..7bfb9e4f3c4 100644 ---- a/Lib/test/support/venv.py -+++ b/Lib/test/support/venv.py -@@ -6,6 +6,7 @@ - import sys - import sysconfig - import tempfile -+import unittest - import venv - - -@@ -68,3 +69,14 @@ - raise - else: - return result -+ -+ -+class VirtualEnvironmentMixin: -+ def venv(self, name=None, **venv_create_args): -+ venv_name = self.id() -+ if name: -+ venv_name += f'-{name}' -+ return VirtualEnvironment.from_tmpdir( -+ prefix=f'{venv_name}-venv-', -+ **venv_create_args, -+ ) -diff --git a/Lib/test/test__colorize.py b/Lib/test/test__colorize.py -index 1871775fa20..056a5306ced 100644 ---- a/Lib/test/test__colorize.py -+++ b/Lib/test/test__colorize.py -@@ -1,68 +1,134 @@ - import contextlib -+import io - import sys - import unittest - import unittest.mock - import _colorize --from test.support import force_not_colorized -+from test.support.os_helper import EnvironmentVarGuard - --ORIGINAL_CAN_COLORIZE = _colorize.can_colorize - -+@contextlib.contextmanager -+def clear_env(): -+ with EnvironmentVarGuard() as mock_env: -+ for var in "FORCE_COLOR", "NO_COLOR", "PYTHON_COLORS": -+ mock_env.unset(var) -+ yield mock_env - --def setUpModule(): -- _colorize.can_colorize = lambda: False - -- --def tearDownModule(): -- _colorize.can_colorize = ORIGINAL_CAN_COLORIZE -+def supports_virtual_terminal(): -+ if sys.platform == "win32": -+ return unittest.mock.patch("nt._supports_virtual_terminal", return_value=True) -+ else: -+ return contextlib.nullcontext() - - - class TestColorizeFunction(unittest.TestCase): -- @force_not_colorized - def test_colorized_detection_checks_for_environment_variables(self): -- flags = unittest.mock.MagicMock(ignore_environment=False) -+ def check(env, fallback, expected): -+ with (self.subTest(env=env, fallback=fallback), -+ clear_env() as mock_env): -+ mock_env.update(env) -+ isatty_mock.return_value = fallback -+ stdout_mock.isatty.return_value = fallback -+ self.assertEqual(_colorize.can_colorize(), expected) -+ - with (unittest.mock.patch("os.isatty") as isatty_mock, -+ unittest.mock.patch("sys.stdout") as stdout_mock, -+ supports_virtual_terminal()): -+ stdout_mock.fileno.return_value = 1 -+ -+ for fallback in False, True: -+ check({}, fallback, fallback) -+ check({'TERM': 'dumb'}, fallback, False) -+ check({'TERM': 'xterm'}, fallback, fallback) -+ check({'TERM': ''}, fallback, fallback) -+ check({'FORCE_COLOR': '1'}, fallback, True) -+ check({'FORCE_COLOR': '0'}, fallback, True) -+ check({'FORCE_COLOR': ''}, fallback, fallback) -+ check({'NO_COLOR': '1'}, fallback, False) -+ check({'NO_COLOR': '0'}, fallback, False) -+ check({'NO_COLOR': ''}, fallback, fallback) -+ -+ check({'TERM': 'dumb', 'FORCE_COLOR': '1'}, False, True) -+ check({'FORCE_COLOR': '1', 'NO_COLOR': '1'}, True, False) -+ -+ for ignore_environment in False, True: -+ # Simulate running with or without `-E`. -+ flags = unittest.mock.MagicMock(ignore_environment=ignore_environment) -+ with unittest.mock.patch("sys.flags", flags): -+ check({'PYTHON_COLORS': '1'}, True, True) -+ check({'PYTHON_COLORS': '1'}, False, not ignore_environment) -+ check({'PYTHON_COLORS': '0'}, True, ignore_environment) -+ check({'PYTHON_COLORS': '0'}, False, False) -+ for fallback in False, True: -+ check({'PYTHON_COLORS': 'x'}, fallback, fallback) -+ check({'PYTHON_COLORS': ''}, fallback, fallback) -+ -+ check({'TERM': 'dumb', 'PYTHON_COLORS': '1'}, False, not ignore_environment) -+ check({'NO_COLOR': '1', 'PYTHON_COLORS': '1'}, False, not ignore_environment) -+ check({'FORCE_COLOR': '1', 'PYTHON_COLORS': '0'}, True, ignore_environment) -+ -+ @unittest.skipUnless(sys.platform == "win32", "requires Windows") -+ def test_colorized_detection_checks_on_windows(self): -+ with (clear_env(), -+ unittest.mock.patch("os.isatty") as isatty_mock, -+ unittest.mock.patch("sys.stdout") as stdout_mock, -+ supports_virtual_terminal() as vt_mock): -+ stdout_mock.fileno.return_value = 1 -+ isatty_mock.return_value = True -+ stdout_mock.isatty.return_value = True -+ -+ vt_mock.return_value = True -+ self.assertEqual(_colorize.can_colorize(), True) -+ vt_mock.return_value = False -+ self.assertEqual(_colorize.can_colorize(), False) -+ import nt -+ del nt._supports_virtual_terminal -+ self.assertEqual(_colorize.can_colorize(), False) -+ -+ def test_colorized_detection_checks_for_std_streams(self): -+ with (clear_env(), -+ unittest.mock.patch("os.isatty") as isatty_mock, -+ unittest.mock.patch("sys.stdout") as stdout_mock, - unittest.mock.patch("sys.stderr") as stderr_mock, -- unittest.mock.patch("sys.flags", flags), -- unittest.mock.patch("_colorize.can_colorize", ORIGINAL_CAN_COLORIZE), -- (unittest.mock.patch("nt._supports_virtual_terminal", return_value=False) -- if sys.platform == "win32" else -- contextlib.nullcontext()) as vt_mock): -+ supports_virtual_terminal()): -+ stdout_mock.fileno.return_value = 1 -+ stderr_mock.fileno.side_effect = ZeroDivisionError -+ stderr_mock.isatty.side_effect = ZeroDivisionError - - isatty_mock.return_value = True -- stderr_mock.fileno.return_value = 2 -- stderr_mock.isatty.return_value = True -- with unittest.mock.patch("os.environ", {'TERM': 'dumb'}): -- self.assertEqual(_colorize.can_colorize(), False) -- with unittest.mock.patch("os.environ", {'PYTHON_COLORS': '1'}): -- self.assertEqual(_colorize.can_colorize(), True) -- with unittest.mock.patch("os.environ", {'PYTHON_COLORS': '0'}): -- self.assertEqual(_colorize.can_colorize(), False) -- with unittest.mock.patch("os.environ", {'NO_COLOR': '1'}): -- self.assertEqual(_colorize.can_colorize(), False) -- with unittest.mock.patch("os.environ", -- {'NO_COLOR': '1', "PYTHON_COLORS": '1'}): -- self.assertEqual(_colorize.can_colorize(), True) -- with unittest.mock.patch("os.environ", {'FORCE_COLOR': '1'}): -- self.assertEqual(_colorize.can_colorize(), True) -- with unittest.mock.patch("os.environ", -- {'FORCE_COLOR': '1', 'NO_COLOR': '1'}): -- self.assertEqual(_colorize.can_colorize(), False) -- with unittest.mock.patch("os.environ", -- {'FORCE_COLOR': '1', "PYTHON_COLORS": '0'}): -- self.assertEqual(_colorize.can_colorize(), False) -- -- with unittest.mock.patch("os.environ", {}): -- if sys.platform == "win32": -- self.assertEqual(_colorize.can_colorize(), False) -- -- vt_mock.return_value = True -- self.assertEqual(_colorize.can_colorize(), True) -- else: -- self.assertEqual(_colorize.can_colorize(), True) -+ stdout_mock.isatty.return_value = True -+ self.assertEqual(_colorize.can_colorize(), True) -+ -+ isatty_mock.return_value = False -+ stdout_mock.isatty.return_value = False -+ self.assertEqual(_colorize.can_colorize(), False) - -+ def test_colorized_detection_checks_for_file(self): -+ with clear_env(), supports_virtual_terminal(): -+ -+ with unittest.mock.patch("os.isatty") as isatty_mock: -+ file = unittest.mock.MagicMock() -+ file.fileno.return_value = 1 -+ isatty_mock.return_value = True -+ self.assertEqual(_colorize.can_colorize(file=file), True) - isatty_mock.return_value = False -- stderr_mock.isatty.return_value = False -- self.assertEqual(_colorize.can_colorize(), False) -+ self.assertEqual(_colorize.can_colorize(file=file), False) -+ -+ # No file.fileno. -+ with unittest.mock.patch("os.isatty", side_effect=ZeroDivisionError): -+ file = unittest.mock.MagicMock(spec=['isatty']) -+ file.isatty.return_value = True -+ self.assertEqual(_colorize.can_colorize(file=file), False) -+ -+ # file.fileno() raises io.UnsupportedOperation. -+ with unittest.mock.patch("os.isatty", side_effect=ZeroDivisionError): -+ file = unittest.mock.MagicMock() -+ file.fileno.side_effect = io.UnsupportedOperation -+ file.isatty.return_value = True -+ self.assertEqual(_colorize.can_colorize(file=file), True) -+ file.isatty.return_value = False -+ self.assertEqual(_colorize.can_colorize(file=file), False) - - - if __name__ == "__main__": -diff --git a/Lib/test/test__interpreters.py b/Lib/test/test__interpreters.py -index bf3165e2341..fd444f1f06c 100644 ---- a/Lib/test/test__interpreters.py -+++ b/Lib/test/test__interpreters.py -@@ -557,7 +557,7 @@ - self.id = _interpreters.create() - - def test_signatures(self): -- # for method in ['exec', 'run_string', 'run_func']: -+ # See https://github.com/python/cpython/issues/126654 - msg = "expected 'shared' to be a dict" - with self.assertRaisesRegex(TypeError, msg): - _interpreters.exec(self.id, 'a', 1) -@@ -568,6 +568,17 @@ - with self.assertRaisesRegex(TypeError, msg): - _interpreters.run_func(self.id, lambda: None, shared=1) - -+ def test_invalid_shared_encoding(self): -+ # See https://github.com/python/cpython/issues/127196 -+ bad_shared = {"\uD82A": 0} -+ msg = 'surrogates not allowed' -+ with self.assertRaisesRegex(UnicodeEncodeError, msg): -+ _interpreters.exec(self.id, 'a', shared=bad_shared) -+ with self.assertRaisesRegex(UnicodeEncodeError, msg): -+ _interpreters.run_string(self.id, 'a', shared=bad_shared) -+ with self.assertRaisesRegex(UnicodeEncodeError, msg): -+ _interpreters.run_func(self.id, lambda: None, shared=bad_shared) -+ - - class RunStringTests(TestBase): - -diff --git a/Lib/test/test__opcode.py b/Lib/test/test__opcode.py -index d5cf014d40d..c253bc2be02 100644 ---- a/Lib/test/test__opcode.py -+++ b/Lib/test/test__opcode.py -@@ -38,6 +38,13 @@ - opcodes = [dis.opmap[opname] for opname in names] - self.check_bool_function_result(_opcode.is_valid, opcodes, True) - -+ def test_opmaps(self): -+ def check_roundtrip(name, map): -+ return self.assertEqual(opcode.opname[map[name]], name) -+ -+ check_roundtrip('BINARY_OP', opcode.opmap) -+ check_roundtrip('BINARY_OP_ADD_INT', opcode._specialized_opmap) -+ - def test_oplists(self): - def check_function(self, func, expected): - for op in [-10, 520]: -@@ -58,8 +65,7 @@ - class StackEffectTests(unittest.TestCase): - def test_stack_effect(self): - self.assertEqual(stack_effect(dis.opmap['POP_TOP']), -1) -- self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 0), -1) -- self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 1), -1) -+ self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 2), -1) - self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 3), -2) - self.assertRaises(ValueError, stack_effect, 30000) - # All defined opcodes -@@ -117,7 +123,7 @@ - if opcode._inline_cache_entries.get(op, 0) - ] - self.assertIn('load_attr', specialized_opcodes) -- self.assertIn('binary_subscr', specialized_opcodes) -+ self.assertIn('binary_op', specialized_opcodes) - - stats = _opcode.get_specialization_stats() - if stats is not None: -diff --git a/Lib/test/test_abc.py b/Lib/test/test_abc.py -index 5ce57cc209e..e90a8dc617c 100644 ---- a/Lib/test/test_abc.py -+++ b/Lib/test/test_abc.py -@@ -20,7 +20,7 @@ - def foo(self): pass - self.assertTrue(foo.__isabstractmethod__) - def bar(self): pass -- self.assertFalse(hasattr(bar, "__isabstractmethod__")) -+ self.assertNotHasAttr(bar, "__isabstractmethod__") - - class C(metaclass=abc_ABCMeta): - @abc.abstractproperty -@@ -89,7 +89,7 @@ - def foo(self): pass - self.assertTrue(foo.__isabstractmethod__) - def bar(self): pass -- self.assertFalse(hasattr(bar, "__isabstractmethod__")) -+ self.assertNotHasAttr(bar, "__isabstractmethod__") - - def test_abstractproperty_basics(self): - @property -@@ -276,21 +276,21 @@ - class B(object): - pass - b = B() -- self.assertFalse(issubclass(B, A)) -- self.assertFalse(issubclass(B, (A,))) -+ self.assertNotIsSubclass(B, A) -+ self.assertNotIsSubclass(B, (A,)) - self.assertNotIsInstance(b, A) - self.assertNotIsInstance(b, (A,)) - B1 = A.register(B) -- self.assertTrue(issubclass(B, A)) -- self.assertTrue(issubclass(B, (A,))) -+ self.assertIsSubclass(B, A) -+ self.assertIsSubclass(B, (A,)) - self.assertIsInstance(b, A) - self.assertIsInstance(b, (A,)) - self.assertIs(B1, B) - class C(B): - pass - c = C() -- self.assertTrue(issubclass(C, A)) -- self.assertTrue(issubclass(C, (A,))) -+ self.assertIsSubclass(C, A) -+ self.assertIsSubclass(C, (A,)) - self.assertIsInstance(c, A) - self.assertIsInstance(c, (A,)) - -@@ -301,16 +301,16 @@ - class B(object): - pass - b = B() -- self.assertTrue(issubclass(B, A)) -- self.assertTrue(issubclass(B, (A,))) -+ self.assertIsSubclass(B, A) -+ self.assertIsSubclass(B, (A,)) - self.assertIsInstance(b, A) - self.assertIsInstance(b, (A,)) - @A.register - class C(B): - pass - c = C() -- self.assertTrue(issubclass(C, A)) -- self.assertTrue(issubclass(C, (A,))) -+ self.assertIsSubclass(C, A) -+ self.assertIsSubclass(C, (A,)) - self.assertIsInstance(c, A) - self.assertIsInstance(c, (A,)) - self.assertIs(C, A.register(C)) -@@ -321,14 +321,14 @@ - class B: - pass - b = B() -- self.assertFalse(isinstance(b, A)) -- self.assertFalse(isinstance(b, (A,))) -+ self.assertNotIsInstance(b, A) -+ self.assertNotIsInstance(b, (A,)) - token_old = abc_get_cache_token() - A.register(B) - token_new = abc_get_cache_token() - self.assertGreater(token_new, token_old) -- self.assertTrue(isinstance(b, A)) -- self.assertTrue(isinstance(b, (A,))) -+ self.assertIsInstance(b, A) -+ self.assertIsInstance(b, (A,)) - - def test_registration_builtins(self): - class A(metaclass=abc_ABCMeta): -@@ -336,18 +336,18 @@ - A.register(int) - self.assertIsInstance(42, A) - self.assertIsInstance(42, (A,)) -- self.assertTrue(issubclass(int, A)) -- self.assertTrue(issubclass(int, (A,))) -+ self.assertIsSubclass(int, A) -+ self.assertIsSubclass(int, (A,)) - class B(A): - pass - B.register(str) - class C(str): pass - self.assertIsInstance("", A) - self.assertIsInstance("", (A,)) -- self.assertTrue(issubclass(str, A)) -- self.assertTrue(issubclass(str, (A,))) -- self.assertTrue(issubclass(C, A)) -- self.assertTrue(issubclass(C, (A,))) -+ self.assertIsSubclass(str, A) -+ self.assertIsSubclass(str, (A,)) -+ self.assertIsSubclass(C, A) -+ self.assertIsSubclass(C, (A,)) - - def test_registration_edge_cases(self): - class A(metaclass=abc_ABCMeta): -@@ -375,39 +375,39 @@ - def test_registration_transitiveness(self): - class A(metaclass=abc_ABCMeta): - pass -- self.assertTrue(issubclass(A, A)) -- self.assertTrue(issubclass(A, (A,))) -+ self.assertIsSubclass(A, A) -+ self.assertIsSubclass(A, (A,)) - class B(metaclass=abc_ABCMeta): - pass -- self.assertFalse(issubclass(A, B)) -- self.assertFalse(issubclass(A, (B,))) -- self.assertFalse(issubclass(B, A)) -- self.assertFalse(issubclass(B, (A,))) -+ self.assertNotIsSubclass(A, B) -+ self.assertNotIsSubclass(A, (B,)) -+ self.assertNotIsSubclass(B, A) -+ self.assertNotIsSubclass(B, (A,)) - class C(metaclass=abc_ABCMeta): - pass - A.register(B) - class B1(B): - pass -- self.assertTrue(issubclass(B1, A)) -- self.assertTrue(issubclass(B1, (A,))) -+ self.assertIsSubclass(B1, A) -+ self.assertIsSubclass(B1, (A,)) - class C1(C): - pass - B1.register(C1) -- self.assertFalse(issubclass(C, B)) -- self.assertFalse(issubclass(C, (B,))) -- self.assertFalse(issubclass(C, B1)) -- self.assertFalse(issubclass(C, (B1,))) -- self.assertTrue(issubclass(C1, A)) -- self.assertTrue(issubclass(C1, (A,))) -- self.assertTrue(issubclass(C1, B)) -- self.assertTrue(issubclass(C1, (B,))) -- self.assertTrue(issubclass(C1, B1)) -- self.assertTrue(issubclass(C1, (B1,))) -+ self.assertNotIsSubclass(C, B) -+ self.assertNotIsSubclass(C, (B,)) -+ self.assertNotIsSubclass(C, B1) -+ self.assertNotIsSubclass(C, (B1,)) -+ self.assertIsSubclass(C1, A) -+ self.assertIsSubclass(C1, (A,)) -+ self.assertIsSubclass(C1, B) -+ self.assertIsSubclass(C1, (B,)) -+ self.assertIsSubclass(C1, B1) -+ self.assertIsSubclass(C1, (B1,)) - C1.register(int) - class MyInt(int): - pass -- self.assertTrue(issubclass(MyInt, A)) -- self.assertTrue(issubclass(MyInt, (A,))) -+ self.assertIsSubclass(MyInt, A) -+ self.assertIsSubclass(MyInt, (A,)) - self.assertIsInstance(42, A) - self.assertIsInstance(42, (A,)) - -@@ -467,16 +467,16 @@ - if cls is A: - return 'foo' in C.__dict__ - return NotImplemented -- self.assertFalse(issubclass(A, A)) -- self.assertFalse(issubclass(A, (A,))) -+ self.assertNotIsSubclass(A, A) -+ self.assertNotIsSubclass(A, (A,)) - class B: - foo = 42 -- self.assertTrue(issubclass(B, A)) -- self.assertTrue(issubclass(B, (A,))) -+ self.assertIsSubclass(B, A) -+ self.assertIsSubclass(B, (A,)) - class C: - spam = 42 -- self.assertFalse(issubclass(C, A)) -- self.assertFalse(issubclass(C, (A,))) -+ self.assertNotIsSubclass(C, A) -+ self.assertNotIsSubclass(C, (A,)) - - def test_all_new_methods_are_called(self): - class A(metaclass=abc_ABCMeta): -@@ -493,7 +493,7 @@ - self.assertEqual(B.counter, 1) - - def test_ABC_has___slots__(self): -- self.assertTrue(hasattr(abc.ABC, '__slots__')) -+ self.assertHasAttr(abc.ABC, '__slots__') - - def test_tricky_new_works(self): - def with_metaclass(meta, *bases): -@@ -515,7 +515,7 @@ - - del A.foo - self.assertEqual(A.__abstractmethods__, {'foo'}) -- self.assertFalse(hasattr(A, 'foo')) -+ self.assertNotHasAttr(A, 'foo') - - abc.update_abstractmethods(A) - -@@ -588,7 +588,7 @@ - A.foo = updated_foo - abc.update_abstractmethods(A) - A() -- self.assertFalse(hasattr(A, '__abstractmethods__')) -+ self.assertNotHasAttr(A, '__abstractmethods__') - - def test_update_del_implementation(self): - class A(metaclass=abc_ABCMeta): -diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py -index f621f343eb0..58ea89c4fac 100755 ---- a/Lib/test/test_array.py -+++ b/Lib/test/test_array.py -@@ -1665,5 +1665,13 @@ - self.assertEqual(ls[:8], list(example[:8])) - self.assertEqual(ls[-8:], list(example[-8:])) - -+ def test_gh_128961(self): -+ a = array.array('i') -+ it = iter(a) -+ list(it) -+ it.__setstate__(0) -+ self.assertRaises(StopIteration, next, it) -+ -+ - if __name__ == "__main__": - unittest.main() -diff --git a/Lib/test/test_ast/test_ast.py b/Lib/test/test_ast/test_ast.py -index c268a1f00f9..a438c8e81e4 100644 ---- a/Lib/test/test_ast/test_ast.py -+++ b/Lib/test/test_ast/test_ast.py -@@ -3279,16 +3279,6 @@ - - self.assert_ast(code % (left, right), non_optimized_target, optimized_target) - -- def test_folding_subscript(self): -- code = "(1,)[0]" -- -- non_optimized_target = self.wrap_expr( -- ast.Subscript(value=ast.Tuple(elts=[ast.Constant(value=1)]), slice=ast.Constant(value=0)) -- ) -- optimized_target = self.wrap_expr(ast.Constant(value=1)) -- -- self.assert_ast(code, non_optimized_target, optimized_target) -- - def test_folding_type_param_in_function_def(self): - code = "def foo[%s = 1 + 1](): pass" - -diff --git a/Lib/test/test_asyncgen.py b/Lib/test/test_asyncgen.py -index 4f2278bb263..b8118787175 100644 ---- a/Lib/test/test_asyncgen.py -+++ b/Lib/test/test_asyncgen.py -@@ -624,12 +624,12 @@ - - def setUp(self): - self.loop = asyncio.new_event_loop() -- asyncio.set_event_loop(None) -+ asyncio._set_event_loop(None) - - def tearDown(self): - self.loop.close() - self.loop = None -- asyncio.set_event_loop_policy(None) -+ asyncio._set_event_loop_policy(None) - - def check_async_iterator_anext(self, ait_class): - with self.subTest(anext="pure-Python"): -@@ -1152,6 +1152,23 @@ - - self.loop.run_until_complete(run()) - -+ def test_async_gen_asyncio_anext_tuple_no_exceptions(self): -+ # StopAsyncIteration exceptions should be cleared. -+ # See: https://github.com/python/cpython/issues/128078. -+ -+ async def foo(): -+ if False: -+ yield (1, 2) -+ -+ async def run(): -+ it = foo().__aiter__() -+ with self.assertRaises(StopAsyncIteration): -+ await it.__anext__() -+ res = await anext(it, ('a', 'b')) -+ self.assertTupleEqual(res, ('a', 'b')) -+ -+ self.loop.run_until_complete(run()) -+ - def test_async_gen_asyncio_anext_stopiteration(self): - async def foo(): - try: -diff --git a/Lib/test/test_asyncio/functional.py b/Lib/test/test_asyncio/functional.py -index d19c7a612cc..2934325b6df 100644 ---- a/Lib/test/test_asyncio/functional.py -+++ b/Lib/test/test_asyncio/functional.py -@@ -24,7 +24,7 @@ - - def setUp(self): - self.loop = self.new_loop() -- asyncio.set_event_loop(None) -+ asyncio._set_event_loop(None) - - self.loop.set_exception_handler(self.loop_exception_handler) - self.__unhandled_exceptions = [] -@@ -39,7 +39,7 @@ - self.fail('unexpected calls to loop.call_exception_handler()') - - finally: -- asyncio.set_event_loop(None) -+ asyncio._set_event_loop(None) - self.loop = None - - def tcp_server(self, server_prog, *, -diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py -index c14a0bb180d..8cf1f6891fa 100644 ---- a/Lib/test/test_asyncio/test_base_events.py -+++ b/Lib/test/test_asyncio/test_base_events.py -@@ -25,7 +25,7 @@ - - - def tearDownModule(): -- asyncio.set_event_loop_policy(None) -+ asyncio._set_event_loop_policy(None) - - - def mock_socket_module(): -@@ -331,10 +331,10 @@ - if create_loop: - loop2 = base_events.BaseEventLoop() - try: -- asyncio.set_event_loop(loop2) -+ asyncio._set_event_loop(loop2) - self.check_thread(loop, debug) - finally: -- asyncio.set_event_loop(None) -+ asyncio._set_event_loop(None) - loop2.close() - else: - self.check_thread(loop, debug) -@@ -690,7 +690,7 @@ - - loop = Loop() - self.addCleanup(loop.close) -- asyncio.set_event_loop(loop) -+ asyncio._set_event_loop(loop) - - def run_loop(): - def zero_error(): -@@ -833,8 +833,8 @@ - loop.close() - - def test_create_named_task_with_custom_factory(self): -- def task_factory(loop, coro): -- return asyncio.Task(coro, loop=loop) -+ def task_factory(loop, coro, **kwargs): -+ return asyncio.Task(coro, loop=loop, **kwargs) - - async def test(): - pass -@@ -1345,7 +1345,7 @@ - with self.assertRaises(OSError) as cm: - self.loop.run_until_complete(coro) - -- self.assertTrue(str(cm.exception).startswith('Multiple exceptions: ')) -+ self.assertStartsWith(str(cm.exception), 'Multiple exceptions: ') - self.assertTrue(m_socket.socket.return_value.close.called) - - coro = self.loop.create_connection( -@@ -1983,7 +1983,7 @@ - async def stop_loop_coro(loop): - loop.stop() - -- asyncio.set_event_loop(self.loop) -+ asyncio._set_event_loop(self.loop) - self.loop.set_debug(True) - self.loop.slow_callback_duration = 0.0 - -diff --git a/Lib/test/test_asyncio/test_buffered_proto.py b/Lib/test/test_asyncio/test_buffered_proto.py -index f24e363ebfc..9c386dd2e63 100644 ---- a/Lib/test/test_asyncio/test_buffered_proto.py -+++ b/Lib/test/test_asyncio/test_buffered_proto.py -@@ -5,7 +5,7 @@ - - - def tearDownModule(): -- asyncio.set_event_loop_policy(None) -+ asyncio._set_event_loop_policy(None) - - - class ReceiveStuffProto(asyncio.BufferedProtocol): -diff --git a/Lib/test/test_asyncio/test_context.py b/Lib/test/test_asyncio/test_context.py -index 6b80721873d..ad394f44e7e 100644 ---- a/Lib/test/test_asyncio/test_context.py -+++ b/Lib/test/test_asyncio/test_context.py -@@ -4,7 +4,7 @@ - - - def tearDownModule(): -- asyncio.set_event_loop_policy(None) -+ asyncio._set_event_loop_policy(None) - - - @unittest.skipUnless(decimal.HAVE_CONTEXTVAR, "decimal is built with a thread-local context") -diff --git a/Lib/test/test_asyncio/test_eager_task_factory.py b/Lib/test/test_asyncio/test_eager_task_factory.py -index 0e2b189f761..bb0760a6967 100644 ---- a/Lib/test/test_asyncio/test_eager_task_factory.py -+++ b/Lib/test/test_asyncio/test_eager_task_factory.py -@@ -13,7 +13,7 @@ - - - def tearDownModule(): -- asyncio.set_event_loop_policy(None) -+ asyncio._set_event_loop_policy(None) - - - class EagerTaskFactoryLoopTests: -@@ -267,12 +267,33 @@ - class PyEagerTaskFactoryLoopTests(EagerTaskFactoryLoopTests, test_utils.TestCase): - Task = tasks._PyTask - -+ def setUp(self): -+ self._current_task = asyncio.current_task -+ asyncio.current_task = asyncio.tasks.current_task = asyncio.tasks._py_current_task -+ return super().setUp() -+ -+ def tearDown(self): -+ asyncio.current_task = asyncio.tasks.current_task = self._current_task -+ return super().tearDown() -+ -+ - - @unittest.skipUnless(hasattr(tasks, '_CTask'), - 'requires the C _asyncio module') - class CEagerTaskFactoryLoopTests(EagerTaskFactoryLoopTests, test_utils.TestCase): - Task = getattr(tasks, '_CTask', None) - -+ def setUp(self): -+ self._current_task = asyncio.current_task -+ asyncio.current_task = asyncio.tasks.current_task = asyncio.tasks._c_current_task -+ return super().setUp() -+ -+ def tearDown(self): -+ asyncio.current_task = asyncio.tasks.current_task = self._current_task -+ return super().tearDown() -+ -+ -+ @unittest.skip("skip") - def test_issue105987(self): - code = """if 1: - from _asyncio import _swap_current_task -@@ -302,6 +323,18 @@ - - self.run_coro(run()) - -+ def test_name(self): -+ name = None -+ async def coro(): -+ nonlocal name -+ name = asyncio.current_task().get_name() -+ -+ async def main(): -+ task = self.loop.create_task(coro(), name="test name") -+ self.assertEqual(name, "test name") -+ await task -+ -+ self.run_coro(coro()) - - class AsyncTaskCounter: - def __init__(self, loop, *, task_class, eager): -@@ -388,31 +421,83 @@ - - - class NonEagerTests(BaseNonEagerTaskFactoryTests, test_utils.TestCase): -- Task = asyncio.Task -+ Task = asyncio.tasks._CTask - -+ def setUp(self): -+ self._current_task = asyncio.current_task -+ asyncio.current_task = asyncio.tasks.current_task = asyncio.tasks._c_current_task -+ return super().setUp() -+ -+ def tearDown(self): -+ asyncio.current_task = asyncio.tasks.current_task = self._current_task -+ return super().tearDown() - - class EagerTests(BaseEagerTaskFactoryTests, test_utils.TestCase): -- Task = asyncio.Task -+ Task = asyncio.tasks._CTask -+ -+ def setUp(self): -+ self._current_task = asyncio.current_task -+ asyncio.current_task = asyncio.tasks.current_task = asyncio.tasks._c_current_task -+ return super().setUp() -+ -+ def tearDown(self): -+ asyncio.current_task = asyncio.tasks.current_task = self._current_task -+ return super().tearDown() - - - class NonEagerPyTaskTests(BaseNonEagerTaskFactoryTests, test_utils.TestCase): - Task = tasks._PyTask - -+ def setUp(self): -+ self._current_task = asyncio.current_task -+ asyncio.current_task = asyncio.tasks.current_task = asyncio.tasks._py_current_task -+ return super().setUp() -+ -+ def tearDown(self): -+ asyncio.current_task = asyncio.tasks.current_task = self._current_task -+ return super().tearDown() -+ - - class EagerPyTaskTests(BaseEagerTaskFactoryTests, test_utils.TestCase): - Task = tasks._PyTask - -+ def setUp(self): -+ self._current_task = asyncio.current_task -+ asyncio.current_task = asyncio.tasks.current_task = asyncio.tasks._py_current_task -+ return super().setUp() -+ -+ def tearDown(self): -+ asyncio.current_task = asyncio.tasks.current_task = self._current_task -+ return super().tearDown() - - @unittest.skipUnless(hasattr(tasks, '_CTask'), - 'requires the C _asyncio module') - class NonEagerCTaskTests(BaseNonEagerTaskFactoryTests, test_utils.TestCase): - Task = getattr(tasks, '_CTask', None) - -+ def setUp(self): -+ self._current_task = asyncio.current_task -+ asyncio.current_task = asyncio.tasks.current_task = asyncio.tasks._c_current_task -+ return super().setUp() -+ -+ def tearDown(self): -+ asyncio.current_task = asyncio.tasks.current_task = self._current_task -+ return super().tearDown() -+ - - @unittest.skipUnless(hasattr(tasks, '_CTask'), - 'requires the C _asyncio module') - class EagerCTaskTests(BaseEagerTaskFactoryTests, test_utils.TestCase): - Task = getattr(tasks, '_CTask', None) - -+ def setUp(self): -+ self._current_task = asyncio.current_task -+ asyncio.current_task = asyncio.tasks.current_task = asyncio.tasks._c_current_task -+ return super().setUp() -+ -+ def tearDown(self): -+ asyncio.current_task = asyncio.tasks.current_task = self._current_task -+ return super().tearDown() -+ - if __name__ == '__main__': - unittest.main() -diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py -index 2ab638dc527..3838993fa8c 100644 ---- a/Lib/test/test_asyncio/test_events.py -+++ b/Lib/test/test_asyncio/test_events.py -@@ -36,10 +36,10 @@ - from test.support import socket_helper - from test.support import threading_helper - from test.support import ALWAYS_EQ, LARGEST, SMALLEST -- -+from test.support import warnings_helper - - def tearDownModule(): -- asyncio.set_event_loop_policy(None) -+ asyncio._set_event_loop_policy(None) - - - def broken_unix_getsockname(): -@@ -58,7 +58,7 @@ - return 'hello' - - loop = asyncio.new_event_loop() -- asyncio.set_event_loop(loop) -+ asyncio._set_event_loop(loop) - return loop.run_until_complete(doit()) - - -@@ -353,6 +353,124 @@ - t.join() - self.assertEqual(results, ['hello', 'world']) - -+ def test_call_soon_threadsafe_handle_block_check_cancelled(self): -+ results = [] -+ -+ callback_started = threading.Event() -+ callback_finished = threading.Event() -+ def callback(arg): -+ callback_started.set() -+ results.append(arg) -+ time.sleep(1) -+ callback_finished.set() -+ -+ def run_in_thread(): -+ handle = self.loop.call_soon_threadsafe(callback, 'hello') -+ self.assertIsInstance(handle, events._ThreadSafeHandle) -+ callback_started.wait() -+ # callback started so it should block checking for cancellation -+ # until it finishes -+ self.assertFalse(handle.cancelled()) -+ self.assertTrue(callback_finished.is_set()) -+ self.loop.call_soon_threadsafe(self.loop.stop) -+ -+ t = threading.Thread(target=run_in_thread) -+ t.start() -+ -+ self.loop.run_forever() -+ t.join() -+ self.assertEqual(results, ['hello']) -+ -+ def test_call_soon_threadsafe_handle_block_cancellation(self): -+ results = [] -+ -+ callback_started = threading.Event() -+ callback_finished = threading.Event() -+ def callback(arg): -+ callback_started.set() -+ results.append(arg) -+ time.sleep(1) -+ callback_finished.set() -+ -+ def run_in_thread(): -+ handle = self.loop.call_soon_threadsafe(callback, 'hello') -+ self.assertIsInstance(handle, events._ThreadSafeHandle) -+ callback_started.wait() -+ # callback started so it cannot be cancelled from other thread until -+ # it finishes -+ handle.cancel() -+ self.assertTrue(callback_finished.is_set()) -+ self.loop.call_soon_threadsafe(self.loop.stop) -+ -+ t = threading.Thread(target=run_in_thread) -+ t.start() -+ -+ self.loop.run_forever() -+ t.join() -+ self.assertEqual(results, ['hello']) -+ -+ def test_call_soon_threadsafe_handle_cancel_same_thread(self): -+ results = [] -+ callback_started = threading.Event() -+ callback_finished = threading.Event() -+ -+ fut = concurrent.futures.Future() -+ def callback(arg): -+ callback_started.set() -+ handle = fut.result() -+ handle.cancel() -+ results.append(arg) -+ callback_finished.set() -+ self.loop.stop() -+ -+ def run_in_thread(): -+ handle = self.loop.call_soon_threadsafe(callback, 'hello') -+ fut.set_result(handle) -+ self.assertIsInstance(handle, events._ThreadSafeHandle) -+ callback_started.wait() -+ # callback cancels itself from same thread so it has no effect -+ # it runs to completion -+ self.assertTrue(handle.cancelled()) -+ self.assertTrue(callback_finished.is_set()) -+ self.loop.call_soon_threadsafe(self.loop.stop) -+ -+ t = threading.Thread(target=run_in_thread) -+ t.start() -+ -+ self.loop.run_forever() -+ t.join() -+ self.assertEqual(results, ['hello']) -+ -+ def test_call_soon_threadsafe_handle_cancel_other_thread(self): -+ results = [] -+ ev = threading.Event() -+ -+ callback_finished = threading.Event() -+ def callback(arg): -+ results.append(arg) -+ callback_finished.set() -+ self.loop.stop() -+ -+ def run_in_thread(): -+ handle = self.loop.call_soon_threadsafe(callback, 'hello') -+ # handle can be cancelled from other thread if not started yet -+ self.assertIsInstance(handle, events._ThreadSafeHandle) -+ handle.cancel() -+ self.assertTrue(handle.cancelled()) -+ self.assertFalse(callback_finished.is_set()) -+ ev.set() -+ self.loop.call_soon_threadsafe(self.loop.stop) -+ -+ # block the main loop until the callback is added and cancelled in the -+ # other thread -+ self.loop.call_soon(ev.wait) -+ t = threading.Thread(target=run_in_thread) -+ t.start() -+ self.loop.run_forever() -+ t.join() -+ self.assertEqual(results, []) -+ self.assertFalse(callback_finished.is_set()) -+ - def test_call_soon_threadsafe_same_thread(self): - results = [] - -@@ -2066,7 +2184,7 @@ - - transp.close() - self.assertEqual(b'OUT:test', proto.data[1]) -- self.assertTrue(proto.data[2].startswith(b'ERR:test'), proto.data[2]) -+ self.assertStartsWith(proto.data[2], b'ERR:test') - self.assertEqual(0, proto.returncode) - - @support.requires_subprocess() -@@ -2088,8 +2206,7 @@ - - stdin.write(b'test') - self.loop.run_until_complete(proto.completed) -- self.assertTrue(proto.data[1].startswith(b'OUT:testERR:test'), -- proto.data[1]) -+ self.assertStartsWith(proto.data[1], b'OUT:testERR:test') - self.assertEqual(b'', proto.data[2]) - - transp.close() -@@ -2397,7 +2514,7 @@ - self.assertRegex(repr(h), regex) - - def test_handle_source_traceback(self): -- loop = asyncio.get_event_loop_policy().new_event_loop() -+ loop = asyncio.new_event_loop() - loop.set_debug(True) - self.set_event_loop(loop) - -@@ -2695,14 +2812,34 @@ - - class PolicyTests(unittest.TestCase): - -+ def test_asyncio_set_event_loop_deprecation(self): -+ with self.assertWarnsRegex( -+ DeprecationWarning, "'asyncio.set_event_loop' is deprecated"): -+ loop = asyncio.new_event_loop() -+ asyncio.set_event_loop(loop) -+ self.assertIs(loop, asyncio.get_event_loop()) -+ loop.close() -+ -+ def test_abstract_event_loop_policy_deprecation(self): -+ with self.assertWarnsRegex( -+ DeprecationWarning, "'asyncio.AbstractEventLoopPolicy' is deprecated"): -+ policy = asyncio.AbstractEventLoopPolicy() -+ self.assertIsInstance(policy, asyncio.AbstractEventLoopPolicy) -+ -+ def test_default_event_loop_policy_deprecation(self): -+ with self.assertWarnsRegex( -+ DeprecationWarning, "'asyncio.DefaultEventLoopPolicy' is deprecated"): -+ policy = asyncio.DefaultEventLoopPolicy() -+ self.assertIsInstance(policy, asyncio.DefaultEventLoopPolicy) -+ - def test_event_loop_policy(self): -- policy = asyncio.AbstractEventLoopPolicy() -+ policy = asyncio._AbstractEventLoopPolicy() - self.assertRaises(NotImplementedError, policy.get_event_loop) - self.assertRaises(NotImplementedError, policy.set_event_loop, object()) - self.assertRaises(NotImplementedError, policy.new_event_loop) - - def test_get_event_loop(self): -- policy = asyncio.DefaultEventLoopPolicy() -+ policy = asyncio._DefaultEventLoopPolicy() - self.assertIsNone(policy._local._loop) - - with self.assertRaises(RuntimeError): -@@ -2710,7 +2847,7 @@ - self.assertIsNone(policy._local._loop) - - def test_get_event_loop_does_not_call_set_event_loop(self): -- policy = asyncio.DefaultEventLoopPolicy() -+ policy = asyncio._DefaultEventLoopPolicy() - - with mock.patch.object( - policy, "set_event_loop", -@@ -2722,7 +2859,7 @@ - m_set_event_loop.assert_not_called() - - def test_get_event_loop_after_set_none(self): -- policy = asyncio.DefaultEventLoopPolicy() -+ policy = asyncio._DefaultEventLoopPolicy() - policy.set_event_loop(None) - self.assertRaises(RuntimeError, policy.get_event_loop) - -@@ -2730,7 +2867,7 @@ - def test_get_event_loop_thread(self, m_current_thread): - - def f(): -- policy = asyncio.DefaultEventLoopPolicy() -+ policy = asyncio._DefaultEventLoopPolicy() - self.assertRaises(RuntimeError, policy.get_event_loop) - - th = threading.Thread(target=f) -@@ -2738,14 +2875,14 @@ - th.join() - - def test_new_event_loop(self): -- policy = asyncio.DefaultEventLoopPolicy() -+ policy = asyncio._DefaultEventLoopPolicy() - - loop = policy.new_event_loop() - self.assertIsInstance(loop, asyncio.AbstractEventLoop) - loop.close() - - def test_set_event_loop(self): -- policy = asyncio.DefaultEventLoopPolicy() -+ policy = asyncio._DefaultEventLoopPolicy() - old_loop = policy.new_event_loop() - policy.set_event_loop(old_loop) - -@@ -2759,20 +2896,31 @@ - old_loop.close() - - def test_get_event_loop_policy(self): -- policy = asyncio.get_event_loop_policy() -- self.assertIsInstance(policy, asyncio.AbstractEventLoopPolicy) -- self.assertIs(policy, asyncio.get_event_loop_policy()) -+ with self.assertWarnsRegex( -+ DeprecationWarning, "'asyncio.get_event_loop_policy' is deprecated"): -+ policy = asyncio.get_event_loop_policy() -+ self.assertIsInstance(policy, asyncio._AbstractEventLoopPolicy) -+ self.assertIs(policy, asyncio.get_event_loop_policy()) - - def test_set_event_loop_policy(self): -- self.assertRaises( -- TypeError, asyncio.set_event_loop_policy, object()) -+ with self.assertWarnsRegex( -+ DeprecationWarning, "'asyncio.set_event_loop_policy' is deprecated"): -+ self.assertRaises( -+ TypeError, asyncio.set_event_loop_policy, object()) - -- old_policy = asyncio.get_event_loop_policy() -+ with self.assertWarnsRegex( -+ DeprecationWarning, "'asyncio.get_event_loop_policy' is deprecated"): -+ old_policy = asyncio.get_event_loop_policy() - -- policy = asyncio.DefaultEventLoopPolicy() -- asyncio.set_event_loop_policy(policy) -- self.assertIs(policy, asyncio.get_event_loop_policy()) -- self.assertIsNot(policy, old_policy) -+ policy = asyncio._DefaultEventLoopPolicy() -+ with self.assertWarnsRegex( -+ DeprecationWarning, "'asyncio.set_event_loop_policy' is deprecated"): -+ asyncio.set_event_loop_policy(policy) -+ -+ with self.assertWarnsRegex( -+ DeprecationWarning, "'asyncio.get_event_loop_policy' is deprecated"): -+ self.assertIs(policy, asyncio.get_event_loop_policy()) -+ self.assertIsNot(policy, old_policy) - - - class GetEventLoopTestsMixin: -@@ -2782,11 +2930,16 @@ - get_running_loop_impl = None - get_event_loop_impl = None - -+ Task = None -+ Future = None -+ - def setUp(self): - self._get_running_loop_saved = events._get_running_loop - self._set_running_loop_saved = events._set_running_loop - self.get_running_loop_saved = events.get_running_loop - self.get_event_loop_saved = events.get_event_loop -+ self._Task_saved = asyncio.Task -+ self._Future_saved = asyncio.Future - - events._get_running_loop = type(self)._get_running_loop_impl - events._set_running_loop = type(self)._set_running_loop_impl -@@ -2798,17 +2951,19 @@ - asyncio.get_running_loop = type(self).get_running_loop_impl - asyncio.get_event_loop = type(self).get_event_loop_impl - -+ asyncio.Task = asyncio.tasks.Task = type(self).Task -+ asyncio.Future = asyncio.futures.Future = type(self).Future - super().setUp() - - self.loop = asyncio.new_event_loop() -- asyncio.set_event_loop(self.loop) -+ asyncio._set_event_loop(self.loop) - - def tearDown(self): - try: - super().tearDown() - finally: - self.loop.close() -- asyncio.set_event_loop(None) -+ asyncio._set_event_loop(None) - - events._get_running_loop = self._get_running_loop_saved - events._set_running_loop = self._set_running_loop_saved -@@ -2820,8 +2975,10 @@ - asyncio.get_running_loop = self.get_running_loop_saved - asyncio.get_event_loop = self.get_event_loop_saved - -- if sys.platform != 'win32': -+ asyncio.Task = asyncio.tasks.Task = self._Task_saved -+ asyncio.Future = asyncio.futures.Future = self._Future_saved - -+ if sys.platform != 'win32': - def test_get_event_loop_new_process(self): - # bpo-32126: The multiprocessing module used by - # ProcessPoolExecutor is not functional when the -@@ -2851,18 +3008,18 @@ - class TestError(Exception): - pass - -- class Policy(asyncio.DefaultEventLoopPolicy): -+ class Policy(asyncio._DefaultEventLoopPolicy): - def get_event_loop(self): - raise TestError - -- old_policy = asyncio.get_event_loop_policy() -+ old_policy = asyncio._get_event_loop_policy() - try: -- asyncio.set_event_loop_policy(Policy()) -+ asyncio._set_event_loop_policy(Policy()) - loop = asyncio.new_event_loop() - - with self.assertRaises(TestError): - asyncio.get_event_loop() -- asyncio.set_event_loop(None) -+ asyncio._set_event_loop(None) - with self.assertRaises(TestError): - asyncio.get_event_loop() - -@@ -2877,15 +3034,15 @@ - - loop.run_until_complete(func()) - -- asyncio.set_event_loop(loop) -+ asyncio._set_event_loop(loop) - with self.assertRaises(TestError): - asyncio.get_event_loop() -- asyncio.set_event_loop(None) -+ asyncio._set_event_loop(None) - with self.assertRaises(TestError): - asyncio.get_event_loop() - - finally: -- asyncio.set_event_loop_policy(old_policy) -+ asyncio._set_event_loop_policy(old_policy) - if loop is not None: - loop.close() - -@@ -2895,16 +3052,16 @@ - self.assertIs(asyncio._get_running_loop(), None) - - def test_get_event_loop_returns_running_loop2(self): -- old_policy = asyncio.get_event_loop_policy() -+ old_policy = asyncio._get_event_loop_policy() - try: -- asyncio.set_event_loop_policy(asyncio.DefaultEventLoopPolicy()) -+ asyncio._set_event_loop_policy(asyncio._DefaultEventLoopPolicy()) - loop = asyncio.new_event_loop() - self.addCleanup(loop.close) - - with self.assertRaisesRegex(RuntimeError, 'no current'): - asyncio.get_event_loop() - -- asyncio.set_event_loop(None) -+ asyncio._set_event_loop(None) - with self.assertRaisesRegex(RuntimeError, 'no current'): - asyncio.get_event_loop() - -@@ -2915,15 +3072,15 @@ - - loop.run_until_complete(func()) - -- asyncio.set_event_loop(loop) -+ asyncio._set_event_loop(loop) - self.assertIs(asyncio.get_event_loop(), loop) - -- asyncio.set_event_loop(None) -+ asyncio._set_event_loop(None) - with self.assertRaisesRegex(RuntimeError, 'no current'): - asyncio.get_event_loop() - - finally: -- asyncio.set_event_loop_policy(old_policy) -+ asyncio._set_event_loop_policy(old_policy) - if loop is not None: - loop.close() - -@@ -2940,6 +3097,8 @@ - get_running_loop_impl = events._py_get_running_loop - get_event_loop_impl = events._py_get_event_loop - -+ Task = asyncio.tasks._PyTask -+ Future = asyncio.futures._PyFuture - - try: - import _asyncio # NoQA -@@ -2954,6 +3113,8 @@ - get_running_loop_impl = events._c_get_running_loop - get_event_loop_impl = events._c_get_event_loop - -+ Task = asyncio.tasks._CTask -+ Future = asyncio.futures._CFuture - - class TestServer(unittest.TestCase): - ---- /dev/null -+++ b/Lib/test/test_asyncio/test_free_threading.py -@@ -0,0 +1,211 @@ -+import asyncio -+import threading -+import unittest -+from threading import Thread -+from unittest import TestCase -+import weakref -+from test import support -+from test.support import threading_helper -+ -+threading_helper.requires_working_threading(module=True) -+ -+ -+class MyException(Exception): -+ pass -+ -+ -+def tearDownModule(): -+ asyncio._set_event_loop_policy(None) -+ -+ -+class TestFreeThreading: -+ def test_all_tasks_race(self) -> None: -+ async def main(): -+ loop = asyncio.get_running_loop() -+ future = loop.create_future() -+ -+ async def coro(): -+ await future -+ -+ tasks = set() -+ -+ async with asyncio.TaskGroup() as tg: -+ for _ in range(100): -+ tasks.add(tg.create_task(coro())) -+ -+ all_tasks = self.all_tasks(loop) -+ self.assertEqual(len(all_tasks), 101) -+ -+ for task in all_tasks: -+ self.assertEqual(task.get_loop(), loop) -+ self.assertFalse(task.done()) -+ -+ current = asyncio.current_task() -+ self.assertEqual(current.get_loop(), loop) -+ self.assertSetEqual(all_tasks, tasks | {current}) -+ future.set_result(None) -+ -+ def runner(): -+ with asyncio.Runner() as runner: -+ loop = runner.get_loop() -+ loop.set_task_factory(self.factory) -+ runner.run(main()) -+ -+ threads = [] -+ -+ for _ in range(10): -+ thread = Thread(target=runner) -+ threads.append(thread) -+ -+ with threading_helper.start_threads(threads): -+ pass -+ -+ def test_all_tasks_different_thread(self) -> None: -+ loop = None -+ started = threading.Event() -+ done = threading.Event() # used for main task not finishing early -+ async def coro(): -+ await asyncio.Future() -+ -+ lock = threading.Lock() -+ tasks = set() -+ -+ async def main(): -+ nonlocal tasks, loop -+ loop = asyncio.get_running_loop() -+ started.set() -+ for i in range(1000): -+ with lock: -+ asyncio.create_task(coro()) -+ tasks = self.all_tasks(loop) -+ done.wait() -+ -+ runner = threading.Thread(target=lambda: asyncio.run(main())) -+ -+ def check(): -+ started.wait() -+ with lock: -+ self.assertSetEqual(tasks & self.all_tasks(loop), tasks) -+ -+ threads = [threading.Thread(target=check) for _ in range(10)] -+ runner.start() -+ -+ with threading_helper.start_threads(threads): -+ pass -+ -+ done.set() -+ runner.join() -+ -+ def test_task_different_thread_finalized(self) -> None: -+ task = None -+ async def func(): -+ nonlocal task -+ task = asyncio.current_task() -+ def runner(): -+ with asyncio.Runner() as runner: -+ loop = runner.get_loop() -+ loop.set_task_factory(self.factory) -+ runner.run(func()) -+ thread = Thread(target=runner) -+ thread.start() -+ thread.join() -+ wr = weakref.ref(task) -+ del thread -+ del task -+ # task finalization in different thread shouldn't crash -+ support.gc_collect() -+ self.assertIsNone(wr()) -+ -+ def test_run_coroutine_threadsafe(self) -> None: -+ results = [] -+ -+ def in_thread(loop: asyncio.AbstractEventLoop): -+ coro = asyncio.sleep(0.1, result=42) -+ fut = asyncio.run_coroutine_threadsafe(coro, loop) -+ result = fut.result() -+ self.assertEqual(result, 42) -+ results.append(result) -+ -+ async def main(): -+ loop = asyncio.get_running_loop() -+ async with asyncio.TaskGroup() as tg: -+ for _ in range(10): -+ tg.create_task(asyncio.to_thread(in_thread, loop)) -+ self.assertEqual(results, [42] * 10) -+ -+ with asyncio.Runner() as r: -+ loop = r.get_loop() -+ loop.set_task_factory(self.factory) -+ r.run(main()) -+ -+ def test_run_coroutine_threadsafe_exception(self) -> None: -+ async def coro(): -+ await asyncio.sleep(0) -+ raise MyException("test") -+ -+ def in_thread(loop: asyncio.AbstractEventLoop): -+ fut = asyncio.run_coroutine_threadsafe(coro(), loop) -+ return fut.result() -+ -+ async def main(): -+ loop = asyncio.get_running_loop() -+ tasks = [] -+ for _ in range(10): -+ task = loop.create_task(asyncio.to_thread(in_thread, loop)) -+ tasks.append(task) -+ results = await asyncio.gather(*tasks, return_exceptions=True) -+ -+ self.assertEqual(len(results), 10) -+ for result in results: -+ self.assertIsInstance(result, MyException) -+ self.assertEqual(str(result), "test") -+ -+ with asyncio.Runner() as r: -+ loop = r.get_loop() -+ loop.set_task_factory(self.factory) -+ r.run(main()) -+ -+ -+class TestPyFreeThreading(TestFreeThreading, TestCase): -+ all_tasks = staticmethod(asyncio.tasks._py_all_tasks) -+ -+ def setUp(self): -+ self._old_current_task = asyncio.current_task -+ asyncio.current_task = asyncio.tasks.current_task = asyncio.tasks._py_current_task -+ return super().setUp() -+ -+ def tearDown(self): -+ asyncio.current_task = asyncio.tasks.current_task = self._old_current_task -+ return super().tearDown() -+ -+ def factory(self, loop, coro, **kwargs): -+ return asyncio.tasks._PyTask(coro, loop=loop, **kwargs) -+ -+ -+@unittest.skipUnless(hasattr(asyncio.tasks, "_c_all_tasks"), "requires _asyncio") -+class TestCFreeThreading(TestFreeThreading, TestCase): -+ all_tasks = staticmethod(getattr(asyncio.tasks, "_c_all_tasks", None)) -+ -+ def setUp(self): -+ self._old_current_task = asyncio.current_task -+ asyncio.current_task = asyncio.tasks.current_task = asyncio.tasks._c_current_task -+ return super().setUp() -+ -+ def tearDown(self): -+ asyncio.current_task = asyncio.tasks.current_task = self._old_current_task -+ return super().tearDown() -+ -+ -+ def factory(self, loop, coro, **kwargs): -+ return asyncio.tasks._CTask(coro, loop=loop, **kwargs) -+ -+ -+class TestEagerPyFreeThreading(TestPyFreeThreading): -+ def factory(self, loop, coro, eager_start=True, **kwargs): -+ return asyncio.tasks._PyTask(coro, loop=loop, **kwargs, eager_start=eager_start) -+ -+ -+@unittest.skipUnless(hasattr(asyncio.tasks, "_c_all_tasks"), "requires _asyncio") -+class TestEagerCFreeThreading(TestCFreeThreading, TestCase): -+ def factory(self, loop, coro, eager_start=True, **kwargs): -+ return asyncio.tasks._CTask(coro, loop=loop, **kwargs, eager_start=eager_start) -diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py -index 3a4291e3a68..01d6230e6dd 100644 ---- a/Lib/test/test_asyncio/test_futures.py -+++ b/Lib/test/test_asyncio/test_futures.py -@@ -17,7 +17,7 @@ - - - def tearDownModule(): -- asyncio.set_event_loop_policy(None) -+ asyncio._set_event_loop_policy(None) - - - def _fakefunc(f): -@@ -178,8 +178,8 @@ - - def test_constructor_use_global_loop(self): - # Deprecated in 3.10, undeprecated in 3.12 -- asyncio.set_event_loop(self.loop) -- self.addCleanup(asyncio.set_event_loop, None) -+ asyncio._set_event_loop(self.loop) -+ self.addCleanup(asyncio._set_event_loop, None) - f = self._new_future() - self.assertIs(f._loop, self.loop) - self.assertIs(f.get_loop(), self.loop) -@@ -242,7 +242,7 @@ - - def test_future_cancel_message_getter(self): - f = self._new_future(loop=self.loop) -- self.assertTrue(hasattr(f, '_cancel_message')) -+ self.assertHasAttr(f, '_cancel_message') - self.assertEqual(f._cancel_message, None) - - f.cancel('my message') -@@ -566,8 +566,8 @@ - - def test_wrap_future_use_global_loop(self): - # Deprecated in 3.10, undeprecated in 3.12 -- asyncio.set_event_loop(self.loop) -- self.addCleanup(asyncio.set_event_loop, None) -+ asyncio._set_event_loop(self.loop) -+ self.addCleanup(asyncio._set_event_loop, None) - def run(arg): - return (arg, threading.get_ident()) - ex = concurrent.futures.ThreadPoolExecutor(1) -diff --git a/Lib/test/test_asyncio/test_futures2.py b/Lib/test/test_asyncio/test_futures2.py -index b7cfffb76bd..e2cddea01ec 100644 ---- a/Lib/test/test_asyncio/test_futures2.py -+++ b/Lib/test/test_asyncio/test_futures2.py -@@ -7,7 +7,7 @@ - - - def tearDownModule(): -- asyncio.set_event_loop_policy(None) -+ asyncio._set_event_loop_policy(None) - - - class FutureTests: ---- /dev/null -+++ b/Lib/test/test_asyncio/test_graph.py -@@ -0,0 +1,445 @@ -+import asyncio -+import io -+import unittest -+ -+ -+# To prevent a warning "test altered the execution environment" -+def tearDownModule(): -+ asyncio._set_event_loop_policy(None) -+ -+ -+def capture_test_stack(*, fut=None, depth=1): -+ -+ def walk(s): -+ ret = [ -+ (f"T<{n}>" if '-' not in (n := s.future.get_name()) else 'T') -+ if isinstance(s.future, asyncio.Task) else 'F' -+ ] -+ -+ ret.append( -+ [ -+ ( -+ f"s {entry.frame.f_code.co_name}" -+ if entry.frame.f_generator is None else -+ ( -+ f"a {entry.frame.f_generator.cr_code.co_name}" -+ if hasattr(entry.frame.f_generator, 'cr_code') else -+ f"ag {entry.frame.f_generator.ag_code.co_name}" -+ ) -+ ) for entry in s.call_stack -+ ] -+ ) -+ -+ ret.append( -+ sorted([ -+ walk(ab) for ab in s.awaited_by -+ ], key=lambda entry: entry[0]) -+ ) -+ -+ return ret -+ -+ buf = io.StringIO() -+ asyncio.print_call_graph(fut, file=buf, depth=depth+1) -+ -+ stack = asyncio.capture_call_graph(fut, depth=depth) -+ return walk(stack), buf.getvalue() -+ -+ -+class CallStackTestBase: -+ -+ async def test_stack_tgroup(self): -+ -+ stack_for_c5 = None -+ -+ def c5(): -+ nonlocal stack_for_c5 -+ stack_for_c5 = capture_test_stack(depth=2) -+ -+ async def c4(): -+ await asyncio.sleep(0) -+ c5() -+ -+ async def c3(): -+ await c4() -+ -+ async def c2(): -+ await c3() -+ -+ async def c1(task): -+ await task -+ -+ async def main(): -+ async with asyncio.TaskGroup() as tg: -+ task = tg.create_task(c2(), name="c2_root") -+ tg.create_task(c1(task), name="sub_main_1") -+ tg.create_task(c1(task), name="sub_main_2") -+ -+ await main() -+ -+ self.assertEqual(stack_for_c5[0], [ -+ # task name -+ 'T', -+ # call stack -+ ['s c5', 'a c4', 'a c3', 'a c2'], -+ # awaited by -+ [ -+ ['T', -+ ['a _aexit', 'a __aexit__', 'a main', 'a test_stack_tgroup'], [] -+ ], -+ ['T', -+ ['a c1'], -+ [ -+ ['T', -+ ['a _aexit', 'a __aexit__', 'a main', 'a test_stack_tgroup'], [] -+ ] -+ ] -+ ], -+ ['T', -+ ['a c1'], -+ [ -+ ['T', -+ ['a _aexit', 'a __aexit__', 'a main', 'a test_stack_tgroup'], [] -+ ] -+ ] -+ ] -+ ] -+ ]) -+ -+ self.assertIn( -+ ' async CallStackTestBase.test_stack_tgroup()', -+ stack_for_c5[1]) -+ -+ -+ async def test_stack_async_gen(self): -+ -+ stack_for_gen_nested_call = None -+ -+ async def gen_nested_call(): -+ nonlocal stack_for_gen_nested_call -+ stack_for_gen_nested_call = capture_test_stack() -+ -+ async def gen(): -+ for num in range(2): -+ yield num -+ if num == 1: -+ await gen_nested_call() -+ -+ async def main(): -+ async for el in gen(): -+ pass -+ -+ await main() -+ -+ self.assertEqual(stack_for_gen_nested_call[0], [ -+ 'T', -+ [ -+ 's capture_test_stack', -+ 'a gen_nested_call', -+ 'ag gen', -+ 'a main', -+ 'a test_stack_async_gen' -+ ], -+ [] -+ ]) -+ -+ self.assertIn( -+ 'async generator CallStackTestBase.test_stack_async_gen..gen()', -+ stack_for_gen_nested_call[1]) -+ -+ async def test_stack_gather(self): -+ -+ stack_for_deep = None -+ -+ async def deep(): -+ await asyncio.sleep(0) -+ nonlocal stack_for_deep -+ stack_for_deep = capture_test_stack() -+ -+ async def c1(): -+ await asyncio.sleep(0) -+ await deep() -+ -+ async def c2(): -+ await asyncio.sleep(0) -+ -+ async def main(): -+ await asyncio.gather(c1(), c2()) -+ -+ await main() -+ -+ self.assertEqual(stack_for_deep[0], [ -+ 'T', -+ ['s capture_test_stack', 'a deep', 'a c1'], -+ [ -+ ['T', ['a main', 'a test_stack_gather'], []] -+ ] -+ ]) -+ -+ async def test_stack_shield(self): -+ -+ stack_for_shield = None -+ -+ async def deep(): -+ await asyncio.sleep(0) -+ nonlocal stack_for_shield -+ stack_for_shield = capture_test_stack() -+ -+ async def c1(): -+ await asyncio.sleep(0) -+ await deep() -+ -+ async def main(): -+ await asyncio.shield(c1()) -+ -+ await main() -+ -+ self.assertEqual(stack_for_shield[0], [ -+ 'T', -+ ['s capture_test_stack', 'a deep', 'a c1'], -+ [ -+ ['T', ['a main', 'a test_stack_shield'], []] -+ ] -+ ]) -+ -+ async def test_stack_timeout(self): -+ -+ stack_for_inner = None -+ -+ async def inner(): -+ await asyncio.sleep(0) -+ nonlocal stack_for_inner -+ stack_for_inner = capture_test_stack() -+ -+ async def c1(): -+ async with asyncio.timeout(1): -+ await asyncio.sleep(0) -+ await inner() -+ -+ async def main(): -+ await asyncio.shield(c1()) -+ -+ await main() -+ -+ self.assertEqual(stack_for_inner[0], [ -+ 'T', -+ ['s capture_test_stack', 'a inner', 'a c1'], -+ [ -+ ['T', ['a main', 'a test_stack_timeout'], []] -+ ] -+ ]) -+ -+ async def test_stack_wait(self): -+ -+ stack_for_inner = None -+ -+ async def inner(): -+ await asyncio.sleep(0) -+ nonlocal stack_for_inner -+ stack_for_inner = capture_test_stack() -+ -+ async def c1(): -+ async with asyncio.timeout(1): -+ await asyncio.sleep(0) -+ await inner() -+ -+ async def c2(): -+ for i in range(3): -+ await asyncio.sleep(0) -+ -+ async def main(t1, t2): -+ while True: -+ _, pending = await asyncio.wait([t1, t2]) -+ if not pending: -+ break -+ -+ t1 = asyncio.create_task(c1()) -+ t2 = asyncio.create_task(c2()) -+ try: -+ await main(t1, t2) -+ finally: -+ await t1 -+ await t2 -+ -+ self.assertEqual(stack_for_inner[0], [ -+ 'T', -+ ['s capture_test_stack', 'a inner', 'a c1'], -+ [ -+ ['T', -+ ['a _wait', 'a wait', 'a main', 'a test_stack_wait'], -+ [] -+ ] -+ ] -+ ]) -+ -+ async def test_stack_task(self): -+ -+ stack_for_inner = None -+ -+ async def inner(): -+ await asyncio.sleep(0) -+ nonlocal stack_for_inner -+ stack_for_inner = capture_test_stack() -+ -+ async def c1(): -+ await inner() -+ -+ async def c2(): -+ await asyncio.create_task(c1(), name='there there') -+ -+ async def main(): -+ await c2() -+ -+ await main() -+ -+ self.assertEqual(stack_for_inner[0], [ -+ 'T', -+ ['s capture_test_stack', 'a inner', 'a c1'], -+ [['T', ['a c2', 'a main', 'a test_stack_task'], []]] -+ ]) -+ -+ async def test_stack_future(self): -+ -+ stack_for_fut = None -+ -+ async def a2(fut): -+ await fut -+ -+ async def a1(fut): -+ await a2(fut) -+ -+ async def b1(fut): -+ await fut -+ -+ async def main(): -+ nonlocal stack_for_fut -+ -+ fut = asyncio.Future() -+ async with asyncio.TaskGroup() as g: -+ g.create_task(a1(fut), name="task A") -+ g.create_task(b1(fut), name='task B') -+ -+ for _ in range(5): -+ # Do a few iterations to ensure that both a1 and b1 -+ # await on the future -+ await asyncio.sleep(0) -+ -+ stack_for_fut = capture_test_stack(fut=fut) -+ fut.set_result(None) -+ -+ await main() -+ -+ self.assertEqual(stack_for_fut[0], -+ ['F', -+ [], -+ [ -+ ['T', -+ ['a a2', 'a a1'], -+ [['T', ['a test_stack_future'], []]] -+ ], -+ ['T', -+ ['a b1'], -+ [['T', ['a test_stack_future'], []]] -+ ], -+ ]] -+ ) -+ -+ self.assertTrue(stack_for_fut[1].startswith('* Future(id=')) -+ -+ -+@unittest.skipIf( -+ not hasattr(asyncio.futures, "_c_future_add_to_awaited_by"), -+ "C-accelerated asyncio call graph backend missing", -+) -+class TestCallStackC(CallStackTestBase, unittest.IsolatedAsyncioTestCase): -+ def setUp(self): -+ futures = asyncio.futures -+ tasks = asyncio.tasks -+ -+ self._Future = asyncio.Future -+ asyncio.Future = futures.Future = futures._CFuture -+ -+ self._Task = asyncio.Task -+ asyncio.Task = tasks.Task = tasks._CTask -+ -+ self._future_add_to_awaited_by = asyncio.future_add_to_awaited_by -+ futures.future_add_to_awaited_by = futures._c_future_add_to_awaited_by -+ asyncio.future_add_to_awaited_by = futures.future_add_to_awaited_by -+ -+ self._future_discard_from_awaited_by = asyncio.future_discard_from_awaited_by -+ futures.future_discard_from_awaited_by = futures._c_future_discard_from_awaited_by -+ asyncio.future_discard_from_awaited_by = futures.future_discard_from_awaited_by -+ -+ self._current_task = asyncio.current_task -+ asyncio.current_task = asyncio.tasks.current_task = tasks._c_current_task -+ -+ def tearDown(self): -+ futures = asyncio.futures -+ tasks = asyncio.tasks -+ -+ futures.future_discard_from_awaited_by = self._future_discard_from_awaited_by -+ asyncio.future_discard_from_awaited_by = self._future_discard_from_awaited_by -+ del self._future_discard_from_awaited_by -+ -+ futures.future_add_to_awaited_by = self._future_add_to_awaited_by -+ asyncio.future_add_to_awaited_by = self._future_add_to_awaited_by -+ del self._future_add_to_awaited_by -+ -+ asyncio.Task = self._Task -+ tasks.Task = self._Task -+ del self._Task -+ -+ asyncio.Future = self._Future -+ futures.Future = self._Future -+ del self._Future -+ -+ asyncio.current_task = asyncio.tasks.current_task = self._current_task -+ -+ -+@unittest.skipIf( -+ not hasattr(asyncio.futures, "_py_future_add_to_awaited_by"), -+ "Pure Python asyncio call graph backend missing", -+) -+class TestCallStackPy(CallStackTestBase, unittest.IsolatedAsyncioTestCase): -+ def setUp(self): -+ futures = asyncio.futures -+ tasks = asyncio.tasks -+ -+ self._Future = asyncio.Future -+ asyncio.Future = futures.Future = futures._PyFuture -+ -+ self._Task = asyncio.Task -+ asyncio.Task = tasks.Task = tasks._PyTask -+ -+ self._future_add_to_awaited_by = asyncio.future_add_to_awaited_by -+ futures.future_add_to_awaited_by = futures._py_future_add_to_awaited_by -+ asyncio.future_add_to_awaited_by = futures.future_add_to_awaited_by -+ -+ self._future_discard_from_awaited_by = asyncio.future_discard_from_awaited_by -+ futures.future_discard_from_awaited_by = futures._py_future_discard_from_awaited_by -+ asyncio.future_discard_from_awaited_by = futures.future_discard_from_awaited_by -+ -+ self._current_task = asyncio.current_task -+ asyncio.current_task = asyncio.tasks.current_task = tasks._py_current_task -+ -+ -+ def tearDown(self): -+ futures = asyncio.futures -+ tasks = asyncio.tasks -+ -+ futures.future_discard_from_awaited_by = self._future_discard_from_awaited_by -+ asyncio.future_discard_from_awaited_by = self._future_discard_from_awaited_by -+ del self._future_discard_from_awaited_by -+ -+ futures.future_add_to_awaited_by = self._future_add_to_awaited_by -+ asyncio.future_add_to_awaited_by = self._future_add_to_awaited_by -+ del self._future_add_to_awaited_by -+ -+ asyncio.Task = self._Task -+ tasks.Task = self._Task -+ del self._Task -+ -+ asyncio.Future = self._Future -+ futures.Future = self._Future -+ del self._Future -+ -+ asyncio.current_task = asyncio.tasks.current_task = self._current_task -diff --git a/Lib/test/test_asyncio/test_locks.py b/Lib/test/test_asyncio/test_locks.py -index c3bff760f73..3bb3e5c4ca0 100644 ---- a/Lib/test/test_asyncio/test_locks.py -+++ b/Lib/test/test_asyncio/test_locks.py -@@ -20,18 +20,18 @@ - - - def tearDownModule(): -- asyncio.set_event_loop_policy(None) -+ asyncio._set_event_loop_policy(None) - - - class LockTests(unittest.IsolatedAsyncioTestCase): - - async def test_repr(self): - lock = asyncio.Lock() -- self.assertTrue(repr(lock).endswith('[unlocked]>')) -+ self.assertEndsWith(repr(lock), '[unlocked]>') - self.assertTrue(RGX_REPR.match(repr(lock))) - - await lock.acquire() -- self.assertTrue(repr(lock).endswith('[locked]>')) -+ self.assertEndsWith(repr(lock), '[locked]>') - self.assertTrue(RGX_REPR.match(repr(lock))) - - async def test_lock(self): -@@ -286,12 +286,12 @@ - - def test_repr(self): - ev = asyncio.Event() -- self.assertTrue(repr(ev).endswith('[unset]>')) -+ self.assertEndsWith(repr(ev), '[unset]>') - match = RGX_REPR.match(repr(ev)) - self.assertEqual(match.group('extras'), 'unset') - - ev.set() -- self.assertTrue(repr(ev).endswith('[set]>')) -+ self.assertEndsWith(repr(ev), '[set]>') - self.assertTrue(RGX_REPR.match(repr(ev))) - - ev._waiters.append(mock.Mock()) -@@ -916,11 +916,11 @@ - - async def test_repr(self): - sem = asyncio.Semaphore() -- self.assertTrue(repr(sem).endswith('[unlocked, value:1]>')) -+ self.assertEndsWith(repr(sem), '[unlocked, value:1]>') - self.assertTrue(RGX_REPR.match(repr(sem))) - - await sem.acquire() -- self.assertTrue(repr(sem).endswith('[locked]>')) -+ self.assertEndsWith(repr(sem), '[locked]>') - self.assertTrue('waiters' not in repr(sem)) - self.assertTrue(RGX_REPR.match(repr(sem))) - -diff --git a/Lib/test/test_asyncio/test_pep492.py b/Lib/test/test_asyncio/test_pep492.py -index 84c5f991295..48f4a75e0fd 100644 ---- a/Lib/test/test_asyncio/test_pep492.py -+++ b/Lib/test/test_asyncio/test_pep492.py -@@ -11,7 +11,7 @@ - - - def tearDownModule(): -- asyncio.set_event_loop_policy(None) -+ asyncio._set_event_loop_policy(None) - - - # Test that asyncio.iscoroutine() uses collections.abc.Coroutine -diff --git a/Lib/test/test_asyncio/test_proactor_events.py b/Lib/test/test_asyncio/test_proactor_events.py -index 4b3d551dd7b..24c4e8546b1 100644 ---- a/Lib/test/test_asyncio/test_proactor_events.py -+++ b/Lib/test/test_asyncio/test_proactor_events.py -@@ -18,7 +18,7 @@ - - - def tearDownModule(): -- asyncio.set_event_loop_policy(None) -+ asyncio._set_event_loop_policy(None) - - - def close_transport(transport): -diff --git a/Lib/test/test_asyncio/test_protocols.py b/Lib/test/test_asyncio/test_protocols.py -index 0f232631867..4484a031988 100644 ---- a/Lib/test/test_asyncio/test_protocols.py -+++ b/Lib/test/test_asyncio/test_protocols.py -@@ -7,7 +7,7 @@ - def tearDownModule(): - # not needed for the test file but added for uniformness with all other - # asyncio test files for the sake of unified cleanup -- asyncio.set_event_loop_policy(None) -+ asyncio._set_event_loop_policy(None) - - - class ProtocolsAbsTests(unittest.TestCase): -@@ -19,7 +19,7 @@ - self.assertIsNone(p.connection_lost(f)) - self.assertIsNone(p.pause_writing()) - self.assertIsNone(p.resume_writing()) -- self.assertFalse(hasattr(p, '__dict__')) -+ self.assertNotHasAttr(p, '__dict__') - - def test_protocol(self): - f = mock.Mock() -@@ -30,7 +30,7 @@ - self.assertIsNone(p.eof_received()) - self.assertIsNone(p.pause_writing()) - self.assertIsNone(p.resume_writing()) -- self.assertFalse(hasattr(p, '__dict__')) -+ self.assertNotHasAttr(p, '__dict__') - - def test_buffered_protocol(self): - f = mock.Mock() -@@ -41,7 +41,7 @@ - self.assertIsNone(p.buffer_updated(150)) - self.assertIsNone(p.pause_writing()) - self.assertIsNone(p.resume_writing()) -- self.assertFalse(hasattr(p, '__dict__')) -+ self.assertNotHasAttr(p, '__dict__') - - def test_datagram_protocol(self): - f = mock.Mock() -@@ -50,7 +50,7 @@ - self.assertIsNone(dp.connection_lost(f)) - self.assertIsNone(dp.error_received(f)) - self.assertIsNone(dp.datagram_received(f, f)) -- self.assertFalse(hasattr(dp, '__dict__')) -+ self.assertNotHasAttr(dp, '__dict__') - - def test_subprocess_protocol(self): - f = mock.Mock() -@@ -60,7 +60,7 @@ - self.assertIsNone(sp.pipe_data_received(1, f)) - self.assertIsNone(sp.pipe_connection_lost(1, f)) - self.assertIsNone(sp.process_exited()) -- self.assertFalse(hasattr(sp, '__dict__')) -+ self.assertNotHasAttr(sp, '__dict__') - - - if __name__ == '__main__': -diff --git a/Lib/test/test_asyncio/test_queues.py b/Lib/test/test_asyncio/test_queues.py -index 5019e9a2935..090b9774c22 100644 ---- a/Lib/test/test_asyncio/test_queues.py -+++ b/Lib/test/test_asyncio/test_queues.py -@@ -6,7 +6,7 @@ - - - def tearDownModule(): -- asyncio.set_event_loop_policy(None) -+ asyncio._set_event_loop_policy(None) - - - class QueueBasicTests(unittest.IsolatedAsyncioTestCase): -@@ -18,7 +18,7 @@ - appear in fn(Queue()). - """ - q = asyncio.Queue() -- self.assertTrue(fn(q).startswith(' None: -+ self.sock = sock -+ -+ def __getattr__(self, name): -+ return getattr(self.sock, name) -+ -+ def send(self, data): -+ # Fake that our write buffer is full, send only half -+ to_send = len(data)//2 -+ return self.sock.send(data[:to_send]) -+ -+ def _fake_full_write_buffer(data): -+ if socket_transport._read_ready_cb is None and not isinstance(socket_transport._sock, SocketWrapper): -+ socket_transport._sock = SocketWrapper(socket_transport._sock) -+ return unittest.mock.DEFAULT -+ -+ with unittest.mock.patch.object( -+ socket_transport, "write", -+ wraps=socket_transport.write, -+ side_effect=_fake_full_write_buffer -+ ): -+ await future -+ -+ writer.close() -+ await self.wait_closed(writer) -+ -+ def run(meth): -+ def wrapper(sock): -+ try: -+ meth(sock) -+ except Exception as ex: -+ self.loop.call_soon_threadsafe(future.set_exception, ex) -+ else: -+ self.loop.call_soon_threadsafe(future.set_result, None) -+ return wrapper -+ -+ with self.tcp_server(run(server)) as srv: -+ self.loop.run_until_complete(client(srv.addr)) -+ -+ with self.tcp_server(run(eof_server)) as srv: -+ self.loop.run_until_complete(client(srv.addr)) -+ - def test_connect_timeout_warning(self): - s = socket.socket(socket.AF_INET) - s.bind(('127.0.0.1', 0)) -diff --git a/Lib/test/test_asyncio/test_sslproto.py b/Lib/test/test_asyncio/test_sslproto.py -index 761904c5146..aa248c5786f 100644 ---- a/Lib/test/test_asyncio/test_sslproto.py -+++ b/Lib/test/test_asyncio/test_sslproto.py -@@ -21,7 +21,7 @@ - - - def tearDownModule(): -- asyncio.set_event_loop_policy(None) -+ asyncio._set_event_loop_policy(None) - - - @unittest.skipIf(ssl is None, 'No ssl module') -diff --git a/Lib/test/test_asyncio/test_staggered.py b/Lib/test/test_asyncio/test_staggered.py -index 74941f704c4..ad34aa6da01 100644 ---- a/Lib/test/test_asyncio/test_staggered.py -+++ b/Lib/test/test_asyncio/test_staggered.py -@@ -8,7 +8,7 @@ - - - def tearDownModule(): -- asyncio.set_event_loop_policy(None) -+ asyncio._set_event_loop_policy(None) - - - class StaggeredTests(unittest.IsolatedAsyncioTestCase): -@@ -122,3 +122,30 @@ - self.assertIsNone(excs[0], None) - self.assertIsInstance(excs[1], asyncio.CancelledError) - self.assertIsInstance(excs[2], asyncio.CancelledError) -+ -+ -+ async def test_cancelled(self): -+ log = [] -+ with self.assertRaises(TimeoutError): -+ async with asyncio.timeout(None) as cs_outer, asyncio.timeout(None) as cs_inner: -+ async def coro_fn(): -+ cs_inner.reschedule(-1) -+ await asyncio.sleep(0) -+ try: -+ await asyncio.sleep(0) -+ except asyncio.CancelledError: -+ log.append("cancelled 1") -+ -+ cs_outer.reschedule(-1) -+ await asyncio.sleep(0) -+ try: -+ await asyncio.sleep(0) -+ except asyncio.CancelledError: -+ log.append("cancelled 2") -+ try: -+ await staggered_race([coro_fn], delay=None) -+ except asyncio.CancelledError: -+ log.append("cancelled 3") -+ raise -+ -+ self.assertListEqual(log, ["cancelled 1", "cancelled 2", "cancelled 3"]) -diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py -index dbe5646c2b7..673c6b46c64 100644 ---- a/Lib/test/test_asyncio/test_streams.py -+++ b/Lib/test/test_asyncio/test_streams.py -@@ -21,7 +21,7 @@ - - - def tearDownModule(): -- asyncio.set_event_loop_policy(None) -+ asyncio._set_event_loop_policy(None) - - - class StreamTests(test_utils.TestCase): -@@ -50,7 +50,7 @@ - self.assertEqual(data, b'HTTP/1.0 200 OK\r\n') - f = reader.read() - data = self.loop.run_until_complete(f) -- self.assertTrue(data.endswith(b'\r\n\r\nTest message')) -+ self.assertEndsWith(data, b'\r\n\r\nTest message') - writer.close() - self.assertEqual(messages, []) - -@@ -71,11 +71,11 @@ - try: - reader, writer = self.loop.run_until_complete(open_connection_fut) - finally: -- asyncio.set_event_loop(None) -+ asyncio._set_event_loop(None) - writer.write(b'GET / HTTP/1.0\r\n\r\n') - f = reader.read() - data = self.loop.run_until_complete(f) -- self.assertTrue(data.endswith(b'\r\n\r\nTest message')) -+ self.assertEndsWith(data, b'\r\n\r\nTest message') - - writer.close() - self.assertEqual(messages, []) -@@ -839,8 +839,8 @@ - # asyncio issue #184: Ensure that StreamReaderProtocol constructor - # retrieves the current loop if the loop parameter is not set - # Deprecated in 3.10, undeprecated in 3.12 -- self.addCleanup(asyncio.set_event_loop, None) -- asyncio.set_event_loop(self.loop) -+ self.addCleanup(asyncio._set_event_loop, None) -+ asyncio._set_event_loop(self.loop) - reader = asyncio.StreamReader() - self.assertIs(reader._loop, self.loop) - -@@ -863,8 +863,8 @@ - # asyncio issue #184: Ensure that StreamReaderProtocol constructor - # retrieves the current loop if the loop parameter is not set - # Deprecated in 3.10, undeprecated in 3.12 -- self.addCleanup(asyncio.set_event_loop, None) -- asyncio.set_event_loop(self.loop) -+ self.addCleanup(asyncio._set_event_loop, None) -+ asyncio._set_event_loop(self.loop) - reader = mock.Mock() - protocol = asyncio.StreamReaderProtocol(reader) - self.assertIs(protocol._loop, self.loop) -@@ -1002,7 +1002,7 @@ - self.assertEqual(data, b'HTTP/1.0 200 OK\r\n') - f = rd.read() - data = self.loop.run_until_complete(f) -- self.assertTrue(data.endswith(b'\r\n\r\nTest message')) -+ self.assertEndsWith(data, b'\r\n\r\nTest message') - self.assertFalse(wr.is_closing()) - wr.close() - self.assertTrue(wr.is_closing()) -@@ -1028,7 +1028,7 @@ - data = await rd.readline() - self.assertEqual(data, b'HTTP/1.0 200 OK\r\n') - data = await rd.read() -- self.assertTrue(data.endswith(b'\r\n\r\nTest message')) -+ self.assertEndsWith(data, b'\r\n\r\nTest message') - wr.close() - await wr.wait_closed() - -@@ -1048,7 +1048,7 @@ - data = await rd.readline() - self.assertEqual(data, b'HTTP/1.0 200 OK\r\n') - data = await rd.read() -- self.assertTrue(data.endswith(b'\r\n\r\nTest message')) -+ self.assertEndsWith(data, b'\r\n\r\nTest message') - wr.close() - with self.assertRaises(ConnectionResetError): - wr.write(b'data') -@@ -1089,12 +1089,12 @@ - data = await rd.readline() - self.assertEqual(data, b'HTTP/1.0 200 OK\r\n') - data = await rd.read() -- self.assertTrue(data.endswith(b'\r\n\r\nTest message')) -+ self.assertEndsWith(data, b'\r\n\r\nTest message') - with self.assertWarns(ResourceWarning) as cm: - del wr - gc.collect() - self.assertEqual(len(cm.warnings), 1) -- self.assertTrue(str(cm.warnings[0].message).startswith("unclosed 50 times -- for _ in range(10 * ADAPTIVE_WARMUP_DELAY): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - assert_equal("overridden", f(num)) - - def test_setvectorcall_load_attr_specialization_skip(self): - from _testcapi import function_setvectorcall -+ _testinternalcapi = import_helper.import_module("_testinternalcapi") - - class X: - def __getattribute__(self, attr): -@@ -824,11 +823,12 @@ - function_setvectorcall(X.__getattribute__) - # make sure specialization doesn't trigger - # when vectorcall is overridden -- for _ in range(ADAPTIVE_WARMUP_DELAY): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - assert_equal("overridden", x.a) - - def test_setvectorcall_load_attr_specialization_deopt(self): - from _testcapi import function_setvectorcall -+ _testinternalcapi = import_helper.import_module("_testinternalcapi") - - class X: - def __getattribute__(self, attr): -@@ -840,12 +840,12 @@ - assert_equal = self.assertEqual - x = X() - # trigger LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN specialization -- for _ in range(ADAPTIVE_WARMUP_DELAY): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - assert_equal("a", get_a(x)) - function_setvectorcall(X.__getattribute__) - # make sure specialized LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN - # gets deopted due to overridden vectorcall -- for _ in range(ADAPTIVE_WARMUP_DELAY): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - assert_equal("overridden", get_a(x)) - - @requires_limited_api -@@ -1037,6 +1037,7 @@ - - @skip_on_s390x - @unittest.skipIf(is_wasi and Py_DEBUG, "requires deep stack") -+ @skip_if_sanitizer("requires deep stack", thread=True) - @unittest.skipIf(_testcapi is None, "requires _testcapi") - @skip_emscripten_stack_overflow() - def test_super_deep(self): -diff --git a/Lib/test/test_capi/test_abstract.py b/Lib/test/test_capi/test_abstract.py -index 6a626813f23..3de251bc5c2 100644 ---- a/Lib/test/test_capi/test_abstract.py -+++ b/Lib/test/test_capi/test_abstract.py -@@ -274,7 +274,7 @@ - - # PyObject_SetAttr(obj, attr_name, NULL) removes the attribute - xsetattr(obj, 'a', NULL) -- self.assertFalse(hasattr(obj, 'a')) -+ self.assertNotHasAttr(obj, 'a') - self.assertRaises(AttributeError, xsetattr, obj, 'b', NULL) - self.assertRaises(RuntimeError, xsetattr, obj, 'evil', NULL) - -@@ -294,7 +294,7 @@ - - # PyObject_SetAttrString(obj, attr_name, NULL) removes the attribute - setattrstring(obj, b'a', NULL) -- self.assertFalse(hasattr(obj, 'a')) -+ self.assertNotHasAttr(obj, 'a') - self.assertRaises(AttributeError, setattrstring, obj, b'b', NULL) - self.assertRaises(RuntimeError, setattrstring, obj, b'evil', NULL) - -@@ -311,10 +311,10 @@ - obj.a = 1 - setattr(obj, '\U0001f40d', 2) - xdelattr(obj, 'a') -- self.assertFalse(hasattr(obj, 'a')) -+ self.assertNotHasAttr(obj, 'a') - self.assertRaises(AttributeError, xdelattr, obj, 'b') - xdelattr(obj, '\U0001f40d') -- self.assertFalse(hasattr(obj, '\U0001f40d')) -+ self.assertNotHasAttr(obj, '\U0001f40d') - - self.assertRaises(AttributeError, xdelattr, 42, 'numerator') - self.assertRaises(RuntimeError, xdelattr, obj, 'evil') -@@ -328,10 +328,10 @@ - obj.a = 1 - setattr(obj, '\U0001f40d', 2) - delattrstring(obj, b'a') -- self.assertFalse(hasattr(obj, 'a')) -+ self.assertNotHasAttr(obj, 'a') - self.assertRaises(AttributeError, delattrstring, obj, b'b') - delattrstring(obj, '\U0001f40d'.encode()) -- self.assertFalse(hasattr(obj, '\U0001f40d')) -+ self.assertNotHasAttr(obj, '\U0001f40d') - - self.assertRaises(AttributeError, delattrstring, 42, b'numerator') - self.assertRaises(RuntimeError, delattrstring, obj, b'evil') -diff --git a/Lib/test/test_capi/test_bytearray.py b/Lib/test/test_capi/test_bytearray.py -index 39099f6b822..323e0d2a5ac 100644 ---- a/Lib/test/test_capi/test_bytearray.py -+++ b/Lib/test/test_capi/test_bytearray.py -@@ -151,10 +151,11 @@ - self.assertEqual(resize(ba, 3), 0) - self.assertEqual(ba, bytearray(b'abc')) - -+ self.assertRaises(ValueError, resize, bytearray(), -1) -+ self.assertRaises(ValueError, resize, bytearray(), -200) - self.assertRaises(MemoryError, resize, bytearray(), PY_SSIZE_T_MAX) - self.assertRaises(MemoryError, resize, bytearray(1000), PY_SSIZE_T_MAX) - -- # CRASHES resize(bytearray(b'abc'), -1) - # CRASHES resize(b'abc', 0) - # CRASHES resize(object(), 0) - # CRASHES resize(NULL, 0) -diff --git a/Lib/test/test_capi/test_codecs.py b/Lib/test/test_capi/test_codecs.py -index a557e35e689..a0355c7a388 100644 ---- a/Lib/test/test_capi/test_codecs.py -+++ b/Lib/test/test_capi/test_codecs.py -@@ -854,20 +854,18 @@ - self.do_test_codec_errors_handler(handler, self.unicode_encode_errors) - - def do_test_codec_errors_handler(self, handler, exceptions): -- at_least_one = False -+ self.assertNotEqual(len(exceptions), 0) - for exc in exceptions: -- # See https://github.com/python/cpython/issues/123378 and related -- # discussion and issues for details. -- if self._exception_may_crash(exc): -- continue -- -- at_least_one = True - with self.subTest(handler=handler, exc=exc): - # test that the handler does not crash -- self.assertIsInstance(handler(exc), tuple) -- -- if exceptions: -- self.assertTrue(at_least_one, "all exceptions are crashing") -+ res = handler(exc) -+ self.assertIsInstance(res, tuple) -+ self.assertEqual(len(res), 2) -+ replacement, continue_from = res -+ self.assertIsInstance(replacement, str) -+ self.assertIsInstance(continue_from, int) -+ self.assertGreaterEqual(continue_from, 0) -+ self.assertLessEqual(continue_from, len(exc.object)) - - for bad_exc in ( - self.bad_unicode_errors -@@ -876,30 +874,6 @@ - with self.subTest('bad type', handler=handler, exc=bad_exc): - self.assertRaises(TypeError, handler, bad_exc) - -- @classmethod -- def _exception_may_crash(cls, exc): -- """Indicate whether a Unicode exception might currently crash -- the interpreter when used by a built-in codecs error handler. -- -- Until gh-123378 is fixed, we skip the tests for these exceptions. -- -- This should only be used by "do_test_codec_errors_handler". -- """ -- message, start, end = exc.object, exc.start, exc.end -- match exc: -- case UnicodeEncodeError(): -- return end < start or (end - start) >= len(message) -- case UnicodeDecodeError(): -- # The case "end - start >= len(message)" does not crash. -- return end < start -- case UnicodeTranslateError(): -- # Test "end <= start" because PyCodec_ReplaceErrors checks -- # the Unicode kind of a 0-length string which by convention -- # is PyUnicode_1BYTE_KIND and not PyUnicode_2BYTE_KIND as -- # the handler currently expects. -- return end <= start or (end - start) >= len(message) -- return False -- - - if __name__ == "__main__": - unittest.main() ---- /dev/null -+++ b/Lib/test/test_capi/test_file.py -@@ -0,0 +1,305 @@ -+import io -+import os -+import unittest -+import warnings -+from test import support -+from test.support import import_helper, os_helper, warnings_helper -+ -+ -+_testcapi = import_helper.import_module('_testcapi') -+_testlimitedcapi = import_helper.import_module('_testlimitedcapi') -+_io = import_helper.import_module('_io') -+NULL = None -+STDOUT_FD = 1 -+ -+with open(__file__, 'rb') as fp: -+ FIRST_LINE = next(fp).decode() -+FIRST_LINE_NORM = FIRST_LINE.rstrip() + '\n' -+ -+ -+class CAPIFileTest(unittest.TestCase): -+ def test_pyfile_fromfd(self): -+ # Test PyFile_FromFd() which is a thin wrapper to _io.open() -+ pyfile_fromfd = _testlimitedcapi.pyfile_fromfd -+ filename = __file__ -+ with open(filename, "rb") as fp: -+ fd = fp.fileno() -+ -+ # FileIO -+ fp.seek(0) -+ obj = pyfile_fromfd(fd, filename, "rb", 0, NULL, NULL, NULL, 0) -+ try: -+ self.assertIsInstance(obj, _io.FileIO) -+ self.assertEqual(obj.readline(), FIRST_LINE.encode()) -+ finally: -+ obj.close() -+ -+ # BufferedReader -+ fp.seek(0) -+ obj = pyfile_fromfd(fd, filename, "rb", 1024, NULL, NULL, NULL, 0) -+ try: -+ self.assertIsInstance(obj, _io.BufferedReader) -+ self.assertEqual(obj.readline(), FIRST_LINE.encode()) -+ finally: -+ obj.close() -+ -+ # TextIOWrapper -+ fp.seek(0) -+ obj = pyfile_fromfd(fd, filename, "r", 1, -+ "utf-8", "replace", NULL, 0) -+ try: -+ self.assertIsInstance(obj, _io.TextIOWrapper) -+ self.assertEqual(obj.encoding, "utf-8") -+ self.assertEqual(obj.errors, "replace") -+ self.assertEqual(obj.readline(), FIRST_LINE_NORM) -+ finally: -+ obj.close() -+ -+ def test_pyfile_getline(self): -+ # Test PyFile_GetLine(file, n): call file.readline() -+ # and strip "\n" suffix if n < 0. -+ pyfile_getline = _testlimitedcapi.pyfile_getline -+ -+ # Test Unicode -+ with open(__file__, "r") as fp: -+ fp.seek(0) -+ self.assertEqual(pyfile_getline(fp, -1), -+ FIRST_LINE_NORM.rstrip('\n')) -+ fp.seek(0) -+ self.assertEqual(pyfile_getline(fp, 0), -+ FIRST_LINE_NORM) -+ fp.seek(0) -+ self.assertEqual(pyfile_getline(fp, 6), -+ FIRST_LINE_NORM[:6]) -+ -+ # Test bytes -+ with open(__file__, "rb") as fp: -+ fp.seek(0) -+ self.assertEqual(pyfile_getline(fp, -1), -+ FIRST_LINE.rstrip('\n').encode()) -+ fp.seek(0) -+ self.assertEqual(pyfile_getline(fp, 0), -+ FIRST_LINE.encode()) -+ fp.seek(0) -+ self.assertEqual(pyfile_getline(fp, 6), -+ FIRST_LINE.encode()[:6]) -+ -+ def test_pyfile_writestring(self): -+ # Test PyFile_WriteString(str, file): call file.write(str) -+ writestr = _testlimitedcapi.pyfile_writestring -+ -+ with io.StringIO() as fp: -+ self.assertEqual(writestr("a\xe9\u20ac\U0010FFFF".encode(), fp), 0) -+ with self.assertRaises(UnicodeDecodeError): -+ writestr(b"\xff", fp) -+ with self.assertRaises(UnicodeDecodeError): -+ writestr("\udc80".encode("utf-8", "surrogatepass"), fp) -+ -+ text = fp.getvalue() -+ self.assertEqual(text, "a\xe9\u20ac\U0010FFFF") -+ -+ with self.assertRaises(SystemError): -+ writestr(b"abc", NULL) -+ -+ def test_pyfile_writeobject(self): -+ # Test PyFile_WriteObject(obj, file, flags): -+ # - Call file.write(str(obj)) if flags equals Py_PRINT_RAW. -+ # - Call file.write(repr(obj)) otherwise. -+ writeobject = _testlimitedcapi.pyfile_writeobject -+ Py_PRINT_RAW = 1 -+ -+ with io.StringIO() as fp: -+ # Test flags=Py_PRINT_RAW -+ self.assertEqual(writeobject("raw", fp, Py_PRINT_RAW), 0) -+ writeobject(NULL, fp, Py_PRINT_RAW) -+ -+ # Test flags=0 -+ self.assertEqual(writeobject("repr", fp, 0), 0) -+ writeobject(NULL, fp, 0) -+ -+ text = fp.getvalue() -+ self.assertEqual(text, "raw'repr'") -+ -+ # invalid file type -+ for invalid_file in (123, "abc", object()): -+ with self.subTest(file=invalid_file): -+ with self.assertRaises(AttributeError): -+ writeobject("abc", invalid_file, Py_PRINT_RAW) -+ -+ with self.assertRaises(TypeError): -+ writeobject("abc", NULL, 0) -+ -+ def test_pyobject_asfiledescriptor(self): -+ # Test PyObject_AsFileDescriptor(obj): -+ # - Return obj if obj is an integer. -+ # - Return obj.fileno() otherwise. -+ # File descriptor must be >= 0. -+ asfd = _testlimitedcapi.pyobject_asfiledescriptor -+ -+ self.assertEqual(asfd(123), 123) -+ self.assertEqual(asfd(0), 0) -+ -+ with open(__file__, "rb") as fp: -+ self.assertEqual(asfd(fp), fp.fileno()) -+ -+ # bool emits RuntimeWarning -+ msg = r"bool is used as a file descriptor" -+ with warnings_helper.check_warnings((msg, RuntimeWarning)): -+ self.assertEqual(asfd(True), 1) -+ -+ class FakeFile: -+ def __init__(self, fd): -+ self.fd = fd -+ def fileno(self): -+ return self.fd -+ -+ # file descriptor must be positive -+ with self.assertRaises(ValueError): -+ asfd(-1) -+ with self.assertRaises(ValueError): -+ asfd(FakeFile(-1)) -+ -+ # fileno() result must be an integer -+ with self.assertRaises(TypeError): -+ asfd(FakeFile("text")) -+ -+ # unsupported types -+ for obj in ("string", ["list"], object()): -+ with self.subTest(obj=obj): -+ with self.assertRaises(TypeError): -+ asfd(obj) -+ -+ # CRASHES asfd(NULL) -+ -+ def test_pyfile_newstdprinter(self): -+ # Test PyFile_NewStdPrinter() -+ pyfile_newstdprinter = _testcapi.pyfile_newstdprinter -+ -+ file = pyfile_newstdprinter(STDOUT_FD) -+ self.assertEqual(file.closed, False) -+ self.assertIsNone(file.encoding) -+ self.assertEqual(file.mode, "w") -+ -+ self.assertEqual(file.fileno(), STDOUT_FD) -+ self.assertEqual(file.isatty(), os.isatty(STDOUT_FD)) -+ -+ # flush() is a no-op -+ self.assertIsNone(file.flush()) -+ -+ # close() is a no-op -+ self.assertIsNone(file.close()) -+ self.assertEqual(file.closed, False) -+ -+ support.check_disallow_instantiation(self, type(file)) -+ -+ def test_pyfile_newstdprinter_write(self): -+ # Test the write() method of PyFile_NewStdPrinter() -+ pyfile_newstdprinter = _testcapi.pyfile_newstdprinter -+ -+ filename = os_helper.TESTFN -+ self.addCleanup(os_helper.unlink, filename) -+ -+ try: -+ old_stdout = os.dup(STDOUT_FD) -+ except OSError as exc: -+ # os.dup(STDOUT_FD) is not supported on WASI -+ self.skipTest(f"os.dup() failed with {exc!r}") -+ -+ try: -+ with open(filename, "wb") as fp: -+ # PyFile_NewStdPrinter() only accepts fileno(stdout) -+ # or fileno(stderr) file descriptor. -+ fd = fp.fileno() -+ os.dup2(fd, STDOUT_FD) -+ -+ file = pyfile_newstdprinter(STDOUT_FD) -+ self.assertEqual(file.write("text"), 4) -+ # The surrogate character is encoded with -+ # the "surrogateescape" error handler -+ self.assertEqual(file.write("[\udc80]"), 8) -+ finally: -+ os.dup2(old_stdout, STDOUT_FD) -+ os.close(old_stdout) -+ -+ with open(filename, "r") as fp: -+ self.assertEqual(fp.read(), "text[\\udc80]") -+ -+ def test_py_fopen(self): -+ # Test Py_fopen() and Py_fclose() -+ py_fopen = _testcapi.py_fopen -+ -+ with open(__file__, "rb") as fp: -+ source = fp.read() -+ -+ for filename in (__file__, os.fsencode(__file__)): -+ with self.subTest(filename=filename): -+ data = py_fopen(filename, "rb") -+ self.assertEqual(data, source[:256]) -+ -+ data = py_fopen(os_helper.FakePath(filename), "rb") -+ self.assertEqual(data, source[:256]) -+ -+ filenames = [ -+ os_helper.TESTFN, -+ os.fsencode(os_helper.TESTFN), -+ ] -+ if os_helper.TESTFN_UNDECODABLE is not None: -+ filenames.append(os_helper.TESTFN_UNDECODABLE) -+ filenames.append(os.fsdecode(os_helper.TESTFN_UNDECODABLE)) -+ if os_helper.TESTFN_UNENCODABLE is not None: -+ filenames.append(os_helper.TESTFN_UNENCODABLE) -+ for filename in filenames: -+ with self.subTest(filename=filename): -+ try: -+ with open(filename, "wb") as fp: -+ fp.write(source) -+ except OSError: -+ # TESTFN_UNDECODABLE cannot be used to create a file -+ # on macOS/WASI. -+ filename = None -+ continue -+ try: -+ data = py_fopen(filename, "rb") -+ self.assertEqual(data, source[:256]) -+ finally: -+ os_helper.unlink(filename) -+ -+ # embedded null character/byte in the filename -+ with self.assertRaises(ValueError): -+ py_fopen("a\x00b", "rb") -+ with self.assertRaises(ValueError): -+ py_fopen(b"a\x00b", "rb") -+ -+ # non-ASCII mode failing with "Invalid argument" -+ with self.assertRaises(OSError): -+ py_fopen(__file__, b"\xc2\x80") -+ with self.assertRaises(OSError): -+ # \x98 is invalid in cp1250, cp1251, cp1257 -+ # \x9d is invalid in cp1252-cp1255, cp1258 -+ py_fopen(__file__, b"\xc2\x98\xc2\x9d") -+ # UnicodeDecodeError can come from the audit hook code -+ with self.assertRaises((UnicodeDecodeError, OSError)): -+ py_fopen(__file__, b"\x98\x9d") -+ -+ # invalid filename type -+ for invalid_type in (123, object()): -+ with self.subTest(filename=invalid_type): -+ with self.assertRaises(TypeError): -+ py_fopen(invalid_type, "rb") -+ -+ if support.MS_WINDOWS: -+ with self.assertRaises(OSError): -+ # On Windows, the file mode is limited to 10 characters -+ py_fopen(__file__, "rt+, ccs=UTF-8") -+ -+ # CRASHES py_fopen(NULL, 'rb') -+ # CRASHES py_fopen(__file__, NULL) -+ -+ # TODO: Test Py_UniversalNewlineFgets() -+ -+ # PyFile_SetOpenCodeHook() and PyFile_OpenCode() are tested by -+ # test_embed.test_open_code_hook() -+ -+ -+if __name__ == "__main__": -+ unittest.main() ---- /dev/null -+++ b/Lib/test/test_capi/test_frame.py -@@ -0,0 +1,56 @@ -+import sys -+import unittest -+from test.support import import_helper -+ -+ -+_testcapi = import_helper.import_module('_testcapi') -+ -+ -+class FrameTest(unittest.TestCase): -+ def getframe(self): -+ return sys._getframe() -+ -+ def test_frame_getters(self): -+ frame = self.getframe() -+ self.assertEqual(frame.f_locals, _testcapi.frame_getlocals(frame)) -+ self.assertIs(frame.f_globals, _testcapi.frame_getglobals(frame)) -+ self.assertIs(frame.f_builtins, _testcapi.frame_getbuiltins(frame)) -+ self.assertEqual(frame.f_lasti, _testcapi.frame_getlasti(frame)) -+ -+ def test_getvar(self): -+ current_frame = sys._getframe() -+ x = 1 -+ self.assertEqual(_testcapi.frame_getvar(current_frame, "x"), 1) -+ self.assertEqual(_testcapi.frame_getvarstring(current_frame, b"x"), 1) -+ with self.assertRaises(NameError): -+ _testcapi.frame_getvar(current_frame, "y") -+ with self.assertRaises(NameError): -+ _testcapi.frame_getvarstring(current_frame, b"y") -+ -+ # wrong name type -+ with self.assertRaises(TypeError): -+ _testcapi.frame_getvar(current_frame, b'x') -+ with self.assertRaises(TypeError): -+ _testcapi.frame_getvar(current_frame, 123) -+ -+ def getgenframe(self): -+ yield sys._getframe() -+ -+ def test_frame_get_generator(self): -+ gen = self.getgenframe() -+ frame = next(gen) -+ self.assertIs(gen, _testcapi.frame_getgenerator(frame)) -+ -+ def test_frame_fback_api(self): -+ """Test that accessing `f_back` does not cause a segmentation fault on -+ a frame created with `PyFrame_New` (GH-99110).""" -+ def dummy(): -+ pass -+ -+ frame = _testcapi.frame_new(dummy.__code__, globals(), locals()) -+ # The following line should not cause a segmentation fault. -+ self.assertIsNone(frame.f_back) -+ -+ -+if __name__ == "__main__": -+ unittest.main() ---- /dev/null -+++ b/Lib/test/test_capi/test_function.py -@@ -0,0 +1,323 @@ -+import unittest -+from test.support import import_helper -+ -+ -+_testcapi = import_helper.import_module('_testcapi') -+ -+ -+class FunctionTest(unittest.TestCase): -+ def test_function_get_code(self): -+ # Test PyFunction_GetCode() -+ import types -+ -+ def some(): -+ pass -+ -+ code = _testcapi.function_get_code(some) -+ self.assertIsInstance(code, types.CodeType) -+ self.assertEqual(code, some.__code__) -+ -+ with self.assertRaises(SystemError): -+ _testcapi.function_get_code(None) # not a function -+ -+ def test_function_get_globals(self): -+ # Test PyFunction_GetGlobals() -+ def some(): -+ pass -+ -+ globals_ = _testcapi.function_get_globals(some) -+ self.assertIsInstance(globals_, dict) -+ self.assertEqual(globals_, some.__globals__) -+ -+ with self.assertRaises(SystemError): -+ _testcapi.function_get_globals(None) # not a function -+ -+ def test_function_get_module(self): -+ # Test PyFunction_GetModule() -+ def some(): -+ pass -+ -+ module = _testcapi.function_get_module(some) -+ self.assertIsInstance(module, str) -+ self.assertEqual(module, some.__module__) -+ -+ with self.assertRaises(SystemError): -+ _testcapi.function_get_module(None) # not a function -+ -+ def test_function_get_defaults(self): -+ # Test PyFunction_GetDefaults() -+ def some( -+ pos_only1, pos_only2='p', -+ /, -+ zero=0, optional=None, -+ *, -+ kw1, -+ kw2=True, -+ ): -+ pass -+ -+ defaults = _testcapi.function_get_defaults(some) -+ self.assertEqual(defaults, ('p', 0, None)) -+ self.assertEqual(defaults, some.__defaults__) -+ -+ with self.assertRaises(SystemError): -+ _testcapi.function_get_defaults(None) # not a function -+ -+ def test_function_set_defaults(self): -+ # Test PyFunction_SetDefaults() -+ def some( -+ pos_only1, pos_only2='p', -+ /, -+ zero=0, optional=None, -+ *, -+ kw1, -+ kw2=True, -+ ): -+ pass -+ -+ old_defaults = ('p', 0, None) -+ self.assertEqual(_testcapi.function_get_defaults(some), old_defaults) -+ self.assertEqual(some.__defaults__, old_defaults) -+ -+ with self.assertRaises(SystemError): -+ _testcapi.function_set_defaults(some, 1) # not tuple or None -+ self.assertEqual(_testcapi.function_get_defaults(some), old_defaults) -+ self.assertEqual(some.__defaults__, old_defaults) -+ -+ with self.assertRaises(SystemError): -+ _testcapi.function_set_defaults(1, ()) # not a function -+ self.assertEqual(_testcapi.function_get_defaults(some), old_defaults) -+ self.assertEqual(some.__defaults__, old_defaults) -+ -+ new_defaults = ('q', 1, None) -+ _testcapi.function_set_defaults(some, new_defaults) -+ self.assertEqual(_testcapi.function_get_defaults(some), new_defaults) -+ self.assertEqual(some.__defaults__, new_defaults) -+ -+ # Empty tuple is fine: -+ new_defaults = () -+ _testcapi.function_set_defaults(some, new_defaults) -+ self.assertEqual(_testcapi.function_get_defaults(some), new_defaults) -+ self.assertEqual(some.__defaults__, new_defaults) -+ -+ class tuplesub(tuple): ... # tuple subclasses must work -+ -+ new_defaults = tuplesub(((1, 2), ['a', 'b'], None)) -+ _testcapi.function_set_defaults(some, new_defaults) -+ self.assertEqual(_testcapi.function_get_defaults(some), new_defaults) -+ self.assertEqual(some.__defaults__, new_defaults) -+ -+ # `None` is special, it sets `defaults` to `NULL`, -+ # it needs special handling in `_testcapi`: -+ _testcapi.function_set_defaults(some, None) -+ self.assertEqual(_testcapi.function_get_defaults(some), None) -+ self.assertEqual(some.__defaults__, None) -+ -+ def test_function_get_kw_defaults(self): -+ # Test PyFunction_GetKwDefaults() -+ def some( -+ pos_only1, pos_only2='p', -+ /, -+ zero=0, optional=None, -+ *, -+ kw1, -+ kw2=True, -+ ): -+ pass -+ -+ defaults = _testcapi.function_get_kw_defaults(some) -+ self.assertEqual(defaults, {'kw2': True}) -+ self.assertEqual(defaults, some.__kwdefaults__) -+ -+ with self.assertRaises(SystemError): -+ _testcapi.function_get_kw_defaults(None) # not a function -+ -+ def test_function_set_kw_defaults(self): -+ # Test PyFunction_SetKwDefaults() -+ def some( -+ pos_only1, pos_only2='p', -+ /, -+ zero=0, optional=None, -+ *, -+ kw1, -+ kw2=True, -+ ): -+ pass -+ -+ old_defaults = {'kw2': True} -+ self.assertEqual(_testcapi.function_get_kw_defaults(some), old_defaults) -+ self.assertEqual(some.__kwdefaults__, old_defaults) -+ -+ with self.assertRaises(SystemError): -+ _testcapi.function_set_kw_defaults(some, 1) # not dict or None -+ self.assertEqual(_testcapi.function_get_kw_defaults(some), old_defaults) -+ self.assertEqual(some.__kwdefaults__, old_defaults) -+ -+ with self.assertRaises(SystemError): -+ _testcapi.function_set_kw_defaults(1, {}) # not a function -+ self.assertEqual(_testcapi.function_get_kw_defaults(some), old_defaults) -+ self.assertEqual(some.__kwdefaults__, old_defaults) -+ -+ new_defaults = {'kw2': (1, 2, 3)} -+ _testcapi.function_set_kw_defaults(some, new_defaults) -+ self.assertEqual(_testcapi.function_get_kw_defaults(some), new_defaults) -+ self.assertEqual(some.__kwdefaults__, new_defaults) -+ -+ # Empty dict is fine: -+ new_defaults = {} -+ _testcapi.function_set_kw_defaults(some, new_defaults) -+ self.assertEqual(_testcapi.function_get_kw_defaults(some), new_defaults) -+ self.assertEqual(some.__kwdefaults__, new_defaults) -+ -+ class dictsub(dict): ... # dict subclasses must work -+ -+ new_defaults = dictsub({'kw2': None}) -+ _testcapi.function_set_kw_defaults(some, new_defaults) -+ self.assertEqual(_testcapi.function_get_kw_defaults(some), new_defaults) -+ self.assertEqual(some.__kwdefaults__, new_defaults) -+ -+ # `None` is special, it sets `kwdefaults` to `NULL`, -+ # it needs special handling in `_testcapi`: -+ _testcapi.function_set_kw_defaults(some, None) -+ self.assertEqual(_testcapi.function_get_kw_defaults(some), None) -+ self.assertEqual(some.__kwdefaults__, None) -+ -+ def test_function_get_closure(self): -+ # Test PyFunction_GetClosure() -+ from types import CellType -+ -+ def regular_function(): ... -+ def unused_one_level(arg1): -+ def inner(arg2, arg3): ... -+ return inner -+ def unused_two_levels(arg1, arg2): -+ def decorator(arg3, arg4): -+ def inner(arg5, arg6): ... -+ return inner -+ return decorator -+ def with_one_level(arg1): -+ def inner(arg2, arg3): -+ return arg1 + arg2 + arg3 -+ return inner -+ def with_two_levels(arg1, arg2): -+ def decorator(arg3, arg4): -+ def inner(arg5, arg6): -+ return arg1 + arg2 + arg3 + arg4 + arg5 + arg6 -+ return inner -+ return decorator -+ -+ # Functions without closures: -+ self.assertIsNone(_testcapi.function_get_closure(regular_function)) -+ self.assertIsNone(regular_function.__closure__) -+ -+ func = unused_one_level(1) -+ closure = _testcapi.function_get_closure(func) -+ self.assertIsNone(closure) -+ self.assertIsNone(func.__closure__) -+ -+ func = unused_two_levels(1, 2)(3, 4) -+ closure = _testcapi.function_get_closure(func) -+ self.assertIsNone(closure) -+ self.assertIsNone(func.__closure__) -+ -+ # Functions with closures: -+ func = with_one_level(5) -+ closure = _testcapi.function_get_closure(func) -+ self.assertEqual(closure, func.__closure__) -+ self.assertIsInstance(closure, tuple) -+ self.assertEqual(len(closure), 1) -+ self.assertEqual(len(closure), len(func.__code__.co_freevars)) -+ for cell in closure: -+ self.assertIsInstance(cell, CellType) -+ self.assertTrue(closure[0].cell_contents, 5) -+ -+ func = with_two_levels(1, 2)(3, 4) -+ closure = _testcapi.function_get_closure(func) -+ self.assertEqual(closure, func.__closure__) -+ self.assertIsInstance(closure, tuple) -+ self.assertEqual(len(closure), 4) -+ self.assertEqual(len(closure), len(func.__code__.co_freevars)) -+ for cell in closure: -+ self.assertIsInstance(cell, CellType) -+ self.assertEqual([cell.cell_contents for cell in closure], -+ [1, 2, 3, 4]) -+ -+ def test_function_get_closure_error(self): -+ # Test PyFunction_GetClosure() -+ with self.assertRaises(SystemError): -+ _testcapi.function_get_closure(1) -+ with self.assertRaises(SystemError): -+ _testcapi.function_get_closure(None) -+ -+ def test_function_set_closure(self): -+ # Test PyFunction_SetClosure() -+ from types import CellType -+ -+ def function_without_closure(): ... -+ def function_with_closure(arg): -+ def inner(): -+ return arg -+ return inner -+ -+ func = function_without_closure -+ _testcapi.function_set_closure(func, (CellType(1), CellType(1))) -+ closure = _testcapi.function_get_closure(func) -+ self.assertEqual([c.cell_contents for c in closure], [1, 1]) -+ self.assertEqual([c.cell_contents for c in func.__closure__], [1, 1]) -+ -+ func = function_with_closure(1) -+ _testcapi.function_set_closure(func, -+ (CellType(1), CellType(2), CellType(3))) -+ closure = _testcapi.function_get_closure(func) -+ self.assertEqual([c.cell_contents for c in closure], [1, 2, 3]) -+ self.assertEqual([c.cell_contents for c in func.__closure__], [1, 2, 3]) -+ -+ def test_function_set_closure_none(self): -+ # Test PyFunction_SetClosure() -+ def function_without_closure(): ... -+ def function_with_closure(arg): -+ def inner(): -+ return arg -+ return inner -+ -+ _testcapi.function_set_closure(function_without_closure, None) -+ self.assertIsNone( -+ _testcapi.function_get_closure(function_without_closure)) -+ self.assertIsNone(function_without_closure.__closure__) -+ -+ _testcapi.function_set_closure(function_with_closure, None) -+ self.assertIsNone( -+ _testcapi.function_get_closure(function_with_closure)) -+ self.assertIsNone(function_with_closure.__closure__) -+ -+ def test_function_set_closure_errors(self): -+ # Test PyFunction_SetClosure() -+ def function_without_closure(): ... -+ -+ with self.assertRaises(SystemError): -+ _testcapi.function_set_closure(None, ()) # not a function -+ -+ with self.assertRaises(SystemError): -+ _testcapi.function_set_closure(function_without_closure, 1) -+ self.assertIsNone(function_without_closure.__closure__) # no change -+ -+ # NOTE: this works, but goes against the docs: -+ _testcapi.function_set_closure(function_without_closure, (1, 2)) -+ self.assertEqual( -+ _testcapi.function_get_closure(function_without_closure), (1, 2)) -+ self.assertEqual(function_without_closure.__closure__, (1, 2)) -+ -+ # TODO: test PyFunction_New() -+ # TODO: test PyFunction_NewWithQualName() -+ # TODO: test PyFunction_SetVectorcall() -+ # TODO: test PyFunction_GetAnnotations() -+ # TODO: test PyFunction_SetAnnotations() -+ # TODO: test PyClassMethod_New() -+ # TODO: test PyStaticMethod_New() -+ # -+ # PyFunction_AddWatcher() and PyFunction_ClearWatcher() are tested by -+ # test_capi.test_watchers. -+ -+ -+if __name__ == "__main__": -+ unittest.main() -diff --git a/Lib/test/test_capi/test_immortal.py b/Lib/test/test_capi/test_immortal.py -index 3e36913ac30..660e8a0e789 100644 ---- a/Lib/test/test_capi/test_immortal.py -+++ b/Lib/test/test_capi/test_immortal.py -@@ -5,12 +5,22 @@ - _testinternalcapi = import_helper.import_module('_testinternalcapi') - - --class TestCAPI(unittest.TestCase): -- def test_immortal_builtins(self): -- _testcapi.test_immortal_builtins() -+class TestUnstableCAPI(unittest.TestCase): -+ def test_immortal(self): -+ # Not extensive -+ known_immortals = (True, False, None, 0, ()) -+ for immortal in known_immortals: -+ with self.subTest(immortal=immortal): -+ self.assertTrue(_testcapi.is_immortal(immortal)) -+ -+ # Some arbitrary mutable objects -+ non_immortals = (object(), self, [object()]) -+ for non_immortal in non_immortals: -+ with self.subTest(non_immortal=non_immortal): -+ self.assertFalse(_testcapi.is_immortal(non_immortal)) -+ -+ # CRASHES _testcapi.is_immortal(NULL) - -- def test_immortal_small_ints(self): -- _testcapi.test_immortal_small_ints() - - class TestInternalCAPI(unittest.TestCase): - ---- /dev/null -+++ b/Lib/test/test_capi/test_import.py -@@ -0,0 +1,381 @@ -+import importlib.util -+import os.path -+import sys -+import types -+import unittest -+from test.support import os_helper -+from test.support import import_helper -+from test.support.warnings_helper import check_warnings -+ -+_testcapi = import_helper.import_module('_testcapi') -+_testlimitedcapi = import_helper.import_module('_testlimitedcapi') -+NULL = None -+ -+ -+class ImportTests(unittest.TestCase): -+ def test_getmagicnumber(self): -+ # Test PyImport_GetMagicNumber() -+ magic = _testlimitedcapi.PyImport_GetMagicNumber() -+ self.assertEqual(magic, -+ int.from_bytes(importlib.util.MAGIC_NUMBER, 'little')) -+ -+ def test_getmagictag(self): -+ # Test PyImport_GetMagicTag() -+ tag = _testlimitedcapi.PyImport_GetMagicTag() -+ self.assertEqual(tag, sys.implementation.cache_tag) -+ -+ def test_getmoduledict(self): -+ # Test PyImport_GetModuleDict() -+ modules = _testlimitedcapi.PyImport_GetModuleDict() -+ self.assertIs(modules, sys.modules) -+ -+ def check_import_loaded_module(self, import_module): -+ for name in ('os', 'sys', 'test', 'unittest'): -+ with self.subTest(name=name): -+ self.assertIn(name, sys.modules) -+ old_module = sys.modules[name] -+ module = import_module(name) -+ self.assertIsInstance(module, types.ModuleType) -+ self.assertIs(module, old_module) -+ -+ def check_import_fresh_module(self, import_module): -+ old_modules = dict(sys.modules) -+ try: -+ for name in ('colorsys', 'math'): -+ with self.subTest(name=name): -+ sys.modules.pop(name, None) -+ module = import_module(name) -+ self.assertIsInstance(module, types.ModuleType) -+ self.assertIs(module, sys.modules[name]) -+ self.assertEqual(module.__name__, name) -+ finally: -+ sys.modules.clear() -+ sys.modules.update(old_modules) -+ -+ def test_getmodule(self): -+ # Test PyImport_GetModule() -+ getmodule = _testlimitedcapi.PyImport_GetModule -+ self.check_import_loaded_module(getmodule) -+ -+ nonexistent = 'nonexistent' -+ self.assertNotIn(nonexistent, sys.modules) -+ self.assertIs(getmodule(nonexistent), KeyError) -+ self.assertIs(getmodule(''), KeyError) -+ self.assertIs(getmodule(object()), KeyError) -+ -+ self.assertRaises(TypeError, getmodule, []) # unhashable -+ # CRASHES getmodule(NULL) -+ -+ def check_addmodule(self, add_module, accept_nonstr=False): -+ # create a new module -+ names = ['nonexistent'] -+ if accept_nonstr: -+ names.append(b'\xff') # non-UTF-8 -+ # PyImport_AddModuleObject() accepts non-string names -+ names.append(tuple(['hashable non-string'])) -+ for name in names: -+ with self.subTest(name=name): -+ self.assertNotIn(name, sys.modules) -+ try: -+ module = add_module(name) -+ self.assertIsInstance(module, types.ModuleType) -+ self.assertEqual(module.__name__, name) -+ self.assertIs(module, sys.modules[name]) -+ finally: -+ sys.modules.pop(name, None) -+ -+ # get an existing module -+ self.check_import_loaded_module(add_module) -+ -+ def test_addmoduleobject(self): -+ # Test PyImport_AddModuleObject() -+ addmoduleobject = _testlimitedcapi.PyImport_AddModuleObject -+ self.check_addmodule(addmoduleobject, accept_nonstr=True) -+ -+ self.assertRaises(TypeError, addmoduleobject, []) # unhashable -+ # CRASHES addmoduleobject(NULL) -+ -+ def test_addmodule(self): -+ # Test PyImport_AddModule() -+ addmodule = _testlimitedcapi.PyImport_AddModule -+ self.check_addmodule(addmodule) -+ -+ self.assertRaises(UnicodeDecodeError, addmodule, b'\xff') -+ # CRASHES addmodule(NULL) -+ -+ def test_addmoduleref(self): -+ # Test PyImport_AddModuleRef() -+ addmoduleref = _testlimitedcapi.PyImport_AddModuleRef -+ self.check_addmodule(addmoduleref) -+ -+ self.assertRaises(UnicodeDecodeError, addmoduleref, b'\xff') -+ # CRASHES addmoduleref(NULL) -+ -+ def check_import_func(self, import_module): -+ self.check_import_loaded_module(import_module) -+ self.check_import_fresh_module(import_module) -+ self.assertRaises(ModuleNotFoundError, import_module, 'nonexistent') -+ self.assertRaises(ValueError, import_module, '') -+ -+ def test_import(self): -+ # Test PyImport_Import() -+ import_ = _testlimitedcapi.PyImport_Import -+ self.check_import_func(import_) -+ -+ self.assertRaises(TypeError, import_, b'os') -+ self.assertRaises(SystemError, import_, NULL) -+ -+ def test_importmodule(self): -+ # Test PyImport_ImportModule() -+ importmodule = _testlimitedcapi.PyImport_ImportModule -+ self.check_import_func(importmodule) -+ -+ self.assertRaises(UnicodeDecodeError, importmodule, b'\xff') -+ # CRASHES importmodule(NULL) -+ -+ def test_importmodulenoblock(self): -+ # Test deprecated PyImport_ImportModuleNoBlock() -+ importmodulenoblock = _testlimitedcapi.PyImport_ImportModuleNoBlock -+ with check_warnings(('', DeprecationWarning)): -+ self.check_import_func(importmodulenoblock) -+ self.assertRaises(UnicodeDecodeError, importmodulenoblock, b'\xff') -+ -+ # CRASHES importmodulenoblock(NULL) -+ -+ def check_frozen_import(self, import_frozen_module): -+ # Importing a frozen module executes its code, so start by unloading -+ # the module to execute the code in a new (temporary) module. -+ old_zipimport = sys.modules.pop('zipimport') -+ try: -+ self.assertEqual(import_frozen_module('zipimport'), 1) -+ -+ # import zipimport again -+ self.assertEqual(import_frozen_module('zipimport'), 1) -+ finally: -+ sys.modules['zipimport'] = old_zipimport -+ -+ # not a frozen module -+ self.assertEqual(import_frozen_module('sys'), 0) -+ self.assertEqual(import_frozen_module('nonexistent'), 0) -+ self.assertEqual(import_frozen_module(''), 0) -+ -+ def test_importfrozenmodule(self): -+ # Test PyImport_ImportFrozenModule() -+ importfrozenmodule = _testlimitedcapi.PyImport_ImportFrozenModule -+ self.check_frozen_import(importfrozenmodule) -+ -+ self.assertRaises(UnicodeDecodeError, importfrozenmodule, b'\xff') -+ # CRASHES importfrozenmodule(NULL) -+ -+ def test_importfrozenmoduleobject(self): -+ # Test PyImport_ImportFrozenModuleObject() -+ importfrozenmoduleobject = _testlimitedcapi.PyImport_ImportFrozenModuleObject -+ self.check_frozen_import(importfrozenmoduleobject) -+ self.assertEqual(importfrozenmoduleobject(b'zipimport'), 0) -+ self.assertEqual(importfrozenmoduleobject(NULL), 0) -+ -+ def test_importmoduleex(self): -+ # Test PyImport_ImportModuleEx() -+ importmoduleex = _testlimitedcapi.PyImport_ImportModuleEx -+ self.check_import_func(lambda name: importmoduleex(name, NULL, NULL, NULL)) -+ -+ self.assertRaises(ModuleNotFoundError, importmoduleex, 'nonexistent', NULL, NULL, NULL) -+ self.assertRaises(ValueError, importmoduleex, '', NULL, NULL, NULL) -+ self.assertRaises(UnicodeDecodeError, importmoduleex, b'\xff', NULL, NULL, NULL) -+ # CRASHES importmoduleex(NULL, NULL, NULL, NULL) -+ -+ def check_importmodulelevel(self, importmodulelevel): -+ self.check_import_func(lambda name: importmodulelevel(name, NULL, NULL, NULL, 0)) -+ -+ self.assertRaises(ModuleNotFoundError, importmodulelevel, 'nonexistent', NULL, NULL, NULL, 0) -+ self.assertRaises(ValueError, importmodulelevel, '', NULL, NULL, NULL, 0) -+ -+ if __package__: -+ self.assertIs(importmodulelevel('test_import', globals(), NULL, NULL, 1), -+ sys.modules['test.test_capi.test_import']) -+ self.assertIs(importmodulelevel('test_capi', globals(), NULL, NULL, 2), -+ sys.modules['test.test_capi']) -+ self.assertRaises(ValueError, importmodulelevel, 'os', NULL, NULL, NULL, -1) -+ with self.assertWarns(ImportWarning): -+ self.assertRaises(KeyError, importmodulelevel, 'test_import', {}, NULL, NULL, 1) -+ self.assertRaises(TypeError, importmodulelevel, 'test_import', [], NULL, NULL, 1) -+ -+ def test_importmodulelevel(self): -+ # Test PyImport_ImportModuleLevel() -+ importmodulelevel = _testlimitedcapi.PyImport_ImportModuleLevel -+ self.check_importmodulelevel(importmodulelevel) -+ -+ self.assertRaises(UnicodeDecodeError, importmodulelevel, b'\xff', NULL, NULL, NULL, 0) -+ # CRASHES importmodulelevel(NULL, NULL, NULL, NULL, 0) -+ -+ def test_importmodulelevelobject(self): -+ # Test PyImport_ImportModuleLevelObject() -+ importmodulelevel = _testlimitedcapi.PyImport_ImportModuleLevelObject -+ self.check_importmodulelevel(importmodulelevel) -+ -+ self.assertRaises(TypeError, importmodulelevel, b'os', NULL, NULL, NULL, 0) -+ self.assertRaises(ValueError, importmodulelevel, NULL, NULL, NULL, NULL, 0) -+ -+ def check_executecodemodule(self, execute_code, *args): -+ name = 'test_import_executecode' -+ try: -+ # Create a temporary module where the code will be executed -+ self.assertNotIn(name, sys.modules) -+ module = _testlimitedcapi.PyImport_AddModuleRef(name) -+ self.assertNotHasAttr(module, 'attr') -+ -+ # Execute the code -+ code = compile('attr = 1', '', 'exec') -+ module2 = execute_code(name, code, *args) -+ self.assertIs(module2, module) -+ -+ # Check the function side effects -+ self.assertEqual(module.attr, 1) -+ finally: -+ sys.modules.pop(name, None) -+ return module.__spec__.origin -+ -+ def test_executecodemodule(self): -+ # Test PyImport_ExecCodeModule() -+ execcodemodule = _testlimitedcapi.PyImport_ExecCodeModule -+ self.check_executecodemodule(execcodemodule) -+ -+ code = compile('attr = 1', '', 'exec') -+ self.assertRaises(UnicodeDecodeError, execcodemodule, b'\xff', code) -+ # CRASHES execcodemodule(NULL, code) -+ # CRASHES execcodemodule(name, NULL) -+ -+ def test_executecodemoduleex(self): -+ # Test PyImport_ExecCodeModuleEx() -+ execcodemoduleex = _testlimitedcapi.PyImport_ExecCodeModuleEx -+ -+ # Test NULL path (it should not crash) -+ self.check_executecodemodule(execcodemoduleex, NULL) -+ -+ # Test non-NULL path -+ pathname = b'pathname' -+ origin = self.check_executecodemodule(execcodemoduleex, pathname) -+ self.assertEqual(origin, os.path.abspath(os.fsdecode(pathname))) -+ -+ pathname = os_helper.TESTFN_UNDECODABLE -+ if pathname: -+ origin = self.check_executecodemodule(execcodemoduleex, pathname) -+ self.assertEqual(origin, os.path.abspath(os.fsdecode(pathname))) -+ -+ code = compile('attr = 1', '', 'exec') -+ self.assertRaises(UnicodeDecodeError, execcodemoduleex, b'\xff', code, NULL) -+ # CRASHES execcodemoduleex(NULL, code, NULL) -+ # CRASHES execcodemoduleex(name, NULL, NULL) -+ -+ def check_executecode_pathnames(self, execute_code_func, object=False): -+ # Test non-NULL pathname and NULL cpathname -+ -+ # Test NULL paths (it should not crash) -+ self.check_executecodemodule(execute_code_func, NULL, NULL) -+ -+ pathname = 'pathname' -+ origin = self.check_executecodemodule(execute_code_func, pathname, NULL) -+ self.assertEqual(origin, os.path.abspath(os.fsdecode(pathname))) -+ origin = self.check_executecodemodule(execute_code_func, NULL, pathname) -+ if not object: -+ self.assertEqual(origin, os.path.abspath(os.fsdecode(pathname))) -+ -+ pathname = os_helper.TESTFN_UNDECODABLE -+ if pathname: -+ if object: -+ pathname = os.fsdecode(pathname) -+ origin = self.check_executecodemodule(execute_code_func, pathname, NULL) -+ self.assertEqual(origin, os.path.abspath(os.fsdecode(pathname))) -+ self.check_executecodemodule(execute_code_func, NULL, pathname) -+ -+ # Test NULL pathname and non-NULL cpathname -+ pyc_filename = importlib.util.cache_from_source(__file__) -+ py_filename = importlib.util.source_from_cache(pyc_filename) -+ origin = self.check_executecodemodule(execute_code_func, NULL, pyc_filename) -+ if not object: -+ self.assertEqual(origin, py_filename) -+ -+ def test_executecodemodulewithpathnames(self): -+ # Test PyImport_ExecCodeModuleWithPathnames() -+ execute_code_func = _testlimitedcapi.PyImport_ExecCodeModuleWithPathnames -+ self.check_executecode_pathnames(execute_code_func) -+ -+ code = compile('attr = 1', '', 'exec') -+ self.assertRaises(UnicodeDecodeError, execute_code_func, b'\xff', code, NULL, NULL) -+ # CRASHES execute_code_func(NULL, code, NULL, NULL) -+ # CRASHES execute_code_func(name, NULL, NULL, NULL) -+ -+ def test_executecodemoduleobject(self): -+ # Test PyImport_ExecCodeModuleObject() -+ execute_code_func = _testlimitedcapi.PyImport_ExecCodeModuleObject -+ self.check_executecode_pathnames(execute_code_func, object=True) -+ -+ code = compile('attr = 1', '', 'exec') -+ self.assertRaises(TypeError, execute_code_func, [], code, NULL, NULL) -+ nonstring = tuple(['hashable non-string']) -+ self.assertRaises(AttributeError, execute_code_func, nonstring, code, NULL, NULL) -+ sys.modules.pop(nonstring, None) -+ # CRASHES execute_code_func(NULL, code, NULL, NULL) -+ # CRASHES execute_code_func(name, NULL, NULL, NULL) -+ -+ def check_importmoduleattr(self, importmoduleattr): -+ self.assertIs(importmoduleattr('sys', 'argv'), sys.argv) -+ self.assertIs(importmoduleattr('types', 'ModuleType'), types.ModuleType) -+ -+ # module name containing a dot -+ attr = importmoduleattr('email.message', 'Message') -+ from email.message import Message -+ self.assertIs(attr, Message) -+ -+ with self.assertRaises(ImportError): -+ # nonexistent module -+ importmoduleattr('nonexistentmodule', 'attr') -+ with self.assertRaises(AttributeError): -+ # nonexistent attribute -+ importmoduleattr('sys', 'nonexistentattr') -+ with self.assertRaises(AttributeError): -+ # attribute name containing a dot -+ importmoduleattr('sys', 'implementation.name') -+ -+ def test_importmoduleattr(self): -+ # Test PyImport_ImportModuleAttr() -+ importmoduleattr = _testcapi.PyImport_ImportModuleAttr -+ self.check_importmoduleattr(importmoduleattr) -+ -+ # Invalid module name type -+ for mod_name in (object(), 123, b'bytes'): -+ with self.subTest(mod_name=mod_name): -+ with self.assertRaises(TypeError): -+ importmoduleattr(mod_name, "attr") -+ -+ # Invalid attribute name type -+ for attr_name in (object(), 123, b'bytes'): -+ with self.subTest(attr_name=attr_name): -+ with self.assertRaises(TypeError): -+ importmoduleattr("sys", attr_name) -+ -+ with self.assertRaises(SystemError): -+ importmoduleattr(NULL, "argv") -+ # CRASHES importmoduleattr("sys", NULL) -+ -+ def test_importmoduleattrstring(self): -+ # Test PyImport_ImportModuleAttrString() -+ importmoduleattr = _testcapi.PyImport_ImportModuleAttrString -+ self.check_importmoduleattr(importmoduleattr) -+ -+ with self.assertRaises(UnicodeDecodeError): -+ importmoduleattr(b"sys\xff", "argv") -+ with self.assertRaises(UnicodeDecodeError): -+ importmoduleattr("sys", b"argv\xff") -+ -+ # CRASHES importmoduleattr(NULL, "argv") -+ # CRASHES importmoduleattr("sys", NULL) -+ -+ # TODO: test PyImport_GetImporter() -+ # TODO: test PyImport_ReloadModule() -+ # TODO: test PyImport_ExtendInittab() -+ # PyImport_AppendInittab() is tested by test_embed -+ -+ -+if __name__ == "__main__": -+ unittest.main() -diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py -index ada30181aee..b218f72f1bb 100644 ---- a/Lib/test/test_capi/test_misc.py -+++ b/Lib/test/test_capi/test_misc.py -@@ -75,6 +75,11 @@ - id = _testcapi.instancemethod(id) - testfunction = _testcapi.instancemethod(testfunction) - -+ -+CURRENT_THREAD_REGEX = r'Current thread.*:\n' if not support.Py_GIL_DISABLED else r'Stack .*:\n' -+ -+ -+@support.force_not_colorized_test_class - class CAPITest(unittest.TestCase): - - def test_instancemethod(self): -@@ -114,8 +119,7 @@ - "after Python initialization and before Python finalization, " - "but it was called without an active thread state. " - "Are you trying to call the C API inside of a Py_BEGIN_ALLOW_THREADS block?").encode() -- self.assertTrue(err.rstrip().startswith(msg), -- err) -+ self.assertStartsWith(err.rstrip(), msg) - - def test_memoryview_from_NULL_pointer(self): - self.assertRaises(ValueError, _testcapi.make_memoryview_from_NULL_pointer) -@@ -234,8 +238,8 @@ - r'Python runtime state: initialized\n' - r'SystemError: ' - r'returned NULL without setting an exception\n' -- r'\n' -- r'Current thread.*:\n' -+ r'\n' + -+ CURRENT_THREAD_REGEX + - r' File .*", line 6 in \n') - else: - with self.assertRaises(SystemError) as cm: -@@ -268,8 +272,8 @@ - r'SystemError: ' - r'returned a result with an exception set\n' -- r'\n' -- r'Current thread.*:\n' -+ r'\n' + -+ CURRENT_THREAD_REGEX + - r' File .*, line 6 in \n') - else: - with self.assertRaises(SystemError) as cm: -@@ -298,11 +302,11 @@ - r'with an exception set\n' - r'Python runtime state: initialized\n' - r'ValueError: bug\n' -- r'\n' -- r'Current thread .* \(most recent call first\):\n' -+ r'\n' + -+ CURRENT_THREAD_REGEX + - r' File .*, line 6 in \n' - r'\n' -- r'Extension modules: _testcapi \(total: 1\)\n') -+ r'Extension modules: _testcapi, _testinternalcapi \(total: 2\)\n') - else: - # Python built with NDEBUG macro defined: - # test _Py_CheckFunctionResult() instead. -@@ -399,42 +403,6 @@ - def test_buildvalue_N(self): - _testcapi.test_buildvalue_N() - -- def check_negative_refcount(self, code): -- # bpo-35059: Check that Py_DECREF() reports the correct filename -- # when calling _Py_NegativeRefcount() to abort Python. -- code = textwrap.dedent(code) -- rc, out, err = assert_python_failure('-c', code) -- self.assertRegex(err, -- br'_testcapimodule\.c:[0-9]+: ' -- br'_Py_NegativeRefcount: Assertion failed: ' -- br'object has negative ref count') -- -- @unittest.skipUnless(hasattr(_testcapi, 'negative_refcount'), -- 'need _testcapi.negative_refcount()') -- def test_negative_refcount(self): -- code = """ -- import _testcapi -- from test import support -- -- with support.SuppressCrashReport(): -- _testcapi.negative_refcount() -- """ -- self.check_negative_refcount(code) -- -- @unittest.skipUnless(hasattr(_testcapi, 'decref_freed_object'), -- 'need _testcapi.decref_freed_object()') -- @support.skip_if_sanitizer("use after free on purpose", -- address=True, memory=True, ub=True) -- def test_decref_freed_object(self): -- code = """ -- import _testcapi -- from test import support -- -- with support.SuppressCrashReport(): -- _testcapi.decref_freed_object() -- """ -- self.check_negative_refcount(code) -- - def test_trashcan_subclass(self): - # bpo-35983: Check that the trashcan mechanism for "list" is NOT - # activated when its tp_dealloc is being called by a subclass -@@ -718,7 +686,7 @@ - - def test_heaptype_with_custom_metaclass(self): - metaclass = _testcapi.HeapCTypeMetaclass -- self.assertTrue(issubclass(metaclass, type)) -+ self.assertIsSubclass(metaclass, type) - - # Class creation from C - t = _testcapi.pytype_fromspec_meta(metaclass) -@@ -734,7 +702,7 @@ - def test_heaptype_with_custom_metaclass_null_new(self): - metaclass = _testcapi.HeapCTypeMetaclassNullNew - -- self.assertTrue(issubclass(metaclass, type)) -+ self.assertIsSubclass(metaclass, type) - - # Class creation from C - t = _testcapi.pytype_fromspec_meta(metaclass) -@@ -749,7 +717,7 @@ - def test_heaptype_with_custom_metaclass_custom_new(self): - metaclass = _testcapi.HeapCTypeMetaclassCustomNew - -- self.assertTrue(issubclass(_testcapi.HeapCTypeMetaclassCustomNew, type)) -+ self.assertIsSubclass(_testcapi.HeapCTypeMetaclassCustomNew, type) - - msg = "Metaclasses with custom tp_new are not supported." - with self.assertRaisesRegex(TypeError, msg): -@@ -908,8 +876,7 @@ - names.append('Py_FrozenMain') - - for name in names: -- with self.subTest(name=name): -- self.assertTrue(hasattr(ctypes.pythonapi, name)) -+ self.assertHasAttr(ctypes.pythonapi, name) - - def test_clear_managed_dict(self): - -@@ -925,175 +892,6 @@ - _testcapi.clear_managed_dict(c) - self.assertEqual(c.__dict__, {}) - -- def test_function_get_code(self): -- import types -- -- def some(): -- pass -- -- code = _testcapi.function_get_code(some) -- self.assertIsInstance(code, types.CodeType) -- self.assertEqual(code, some.__code__) -- -- with self.assertRaises(SystemError): -- _testcapi.function_get_code(None) # not a function -- -- def test_function_get_globals(self): -- def some(): -- pass -- -- globals_ = _testcapi.function_get_globals(some) -- self.assertIsInstance(globals_, dict) -- self.assertEqual(globals_, some.__globals__) -- -- with self.assertRaises(SystemError): -- _testcapi.function_get_globals(None) # not a function -- -- def test_function_get_module(self): -- def some(): -- pass -- -- module = _testcapi.function_get_module(some) -- self.assertIsInstance(module, str) -- self.assertEqual(module, some.__module__) -- -- with self.assertRaises(SystemError): -- _testcapi.function_get_module(None) # not a function -- -- def test_function_get_defaults(self): -- def some( -- pos_only1, pos_only2='p', -- /, -- zero=0, optional=None, -- *, -- kw1, -- kw2=True, -- ): -- pass -- -- defaults = _testcapi.function_get_defaults(some) -- self.assertEqual(defaults, ('p', 0, None)) -- self.assertEqual(defaults, some.__defaults__) -- -- with self.assertRaises(SystemError): -- _testcapi.function_get_defaults(None) # not a function -- -- def test_function_set_defaults(self): -- def some( -- pos_only1, pos_only2='p', -- /, -- zero=0, optional=None, -- *, -- kw1, -- kw2=True, -- ): -- pass -- -- old_defaults = ('p', 0, None) -- self.assertEqual(_testcapi.function_get_defaults(some), old_defaults) -- self.assertEqual(some.__defaults__, old_defaults) -- -- with self.assertRaises(SystemError): -- _testcapi.function_set_defaults(some, 1) # not tuple or None -- self.assertEqual(_testcapi.function_get_defaults(some), old_defaults) -- self.assertEqual(some.__defaults__, old_defaults) -- -- with self.assertRaises(SystemError): -- _testcapi.function_set_defaults(1, ()) # not a function -- self.assertEqual(_testcapi.function_get_defaults(some), old_defaults) -- self.assertEqual(some.__defaults__, old_defaults) -- -- new_defaults = ('q', 1, None) -- _testcapi.function_set_defaults(some, new_defaults) -- self.assertEqual(_testcapi.function_get_defaults(some), new_defaults) -- self.assertEqual(some.__defaults__, new_defaults) -- -- # Empty tuple is fine: -- new_defaults = () -- _testcapi.function_set_defaults(some, new_defaults) -- self.assertEqual(_testcapi.function_get_defaults(some), new_defaults) -- self.assertEqual(some.__defaults__, new_defaults) -- -- class tuplesub(tuple): ... # tuple subclasses must work -- -- new_defaults = tuplesub(((1, 2), ['a', 'b'], None)) -- _testcapi.function_set_defaults(some, new_defaults) -- self.assertEqual(_testcapi.function_get_defaults(some), new_defaults) -- self.assertEqual(some.__defaults__, new_defaults) -- -- # `None` is special, it sets `defaults` to `NULL`, -- # it needs special handling in `_testcapi`: -- _testcapi.function_set_defaults(some, None) -- self.assertEqual(_testcapi.function_get_defaults(some), None) -- self.assertEqual(some.__defaults__, None) -- -- def test_function_get_kw_defaults(self): -- def some( -- pos_only1, pos_only2='p', -- /, -- zero=0, optional=None, -- *, -- kw1, -- kw2=True, -- ): -- pass -- -- defaults = _testcapi.function_get_kw_defaults(some) -- self.assertEqual(defaults, {'kw2': True}) -- self.assertEqual(defaults, some.__kwdefaults__) -- -- with self.assertRaises(SystemError): -- _testcapi.function_get_kw_defaults(None) # not a function -- -- def test_function_set_kw_defaults(self): -- def some( -- pos_only1, pos_only2='p', -- /, -- zero=0, optional=None, -- *, -- kw1, -- kw2=True, -- ): -- pass -- -- old_defaults = {'kw2': True} -- self.assertEqual(_testcapi.function_get_kw_defaults(some), old_defaults) -- self.assertEqual(some.__kwdefaults__, old_defaults) -- -- with self.assertRaises(SystemError): -- _testcapi.function_set_kw_defaults(some, 1) # not dict or None -- self.assertEqual(_testcapi.function_get_kw_defaults(some), old_defaults) -- self.assertEqual(some.__kwdefaults__, old_defaults) -- -- with self.assertRaises(SystemError): -- _testcapi.function_set_kw_defaults(1, {}) # not a function -- self.assertEqual(_testcapi.function_get_kw_defaults(some), old_defaults) -- self.assertEqual(some.__kwdefaults__, old_defaults) -- -- new_defaults = {'kw2': (1, 2, 3)} -- _testcapi.function_set_kw_defaults(some, new_defaults) -- self.assertEqual(_testcapi.function_get_kw_defaults(some), new_defaults) -- self.assertEqual(some.__kwdefaults__, new_defaults) -- -- # Empty dict is fine: -- new_defaults = {} -- _testcapi.function_set_kw_defaults(some, new_defaults) -- self.assertEqual(_testcapi.function_get_kw_defaults(some), new_defaults) -- self.assertEqual(some.__kwdefaults__, new_defaults) -- -- class dictsub(dict): ... # dict subclasses must work -- -- new_defaults = dictsub({'kw2': None}) -- _testcapi.function_set_kw_defaults(some, new_defaults) -- self.assertEqual(_testcapi.function_get_kw_defaults(some), new_defaults) -- self.assertEqual(some.__kwdefaults__, new_defaults) -- -- # `None` is special, it sets `kwdefaults` to `NULL`, -- # it needs special handling in `_testcapi`: -- _testcapi.function_set_kw_defaults(some, None) -- self.assertEqual(_testcapi.function_get_kw_defaults(some), None) -- self.assertEqual(some.__kwdefaults__, None) -- - def test_unstable_gc_new_with_extra_data(self): - class Data(_testcapi.ObjExtraData): - __slots__ = ('x', 'y') -@@ -1108,147 +906,6 @@ - del d.extra - self.assertIsNone(d.extra) - -- def test_get_type_name(self): -- class MyType: -- pass -- -- from _testcapi import ( -- get_type_name, get_type_qualname, -- get_type_fullyqualname, get_type_module_name) -- -- from collections import OrderedDict -- ht = _testcapi.get_heaptype_for_name() -- for cls, fullname, modname, qualname, name in ( -- (int, -- 'int', -- 'builtins', -- 'int', -- 'int'), -- (OrderedDict, -- 'collections.OrderedDict', -- 'collections', -- 'OrderedDict', -- 'OrderedDict'), -- (ht, -- '_testcapi.HeapTypeNameType', -- '_testcapi', -- 'HeapTypeNameType', -- 'HeapTypeNameType'), -- (MyType, -- f'{__name__}.CAPITest.test_get_type_name..MyType', -- __name__, -- 'CAPITest.test_get_type_name..MyType', -- 'MyType'), -- ): -- with self.subTest(cls=repr(cls)): -- self.assertEqual(get_type_fullyqualname(cls), fullname) -- self.assertEqual(get_type_module_name(cls), modname) -- self.assertEqual(get_type_qualname(cls), qualname) -- self.assertEqual(get_type_name(cls), name) -- -- # override __module__ -- ht.__module__ = 'test_module' -- self.assertEqual(get_type_fullyqualname(ht), 'test_module.HeapTypeNameType') -- self.assertEqual(get_type_module_name(ht), 'test_module') -- self.assertEqual(get_type_qualname(ht), 'HeapTypeNameType') -- self.assertEqual(get_type_name(ht), 'HeapTypeNameType') -- -- # override __name__ and __qualname__ -- MyType.__name__ = 'my_name' -- MyType.__qualname__ = 'my_qualname' -- self.assertEqual(get_type_fullyqualname(MyType), f'{__name__}.my_qualname') -- self.assertEqual(get_type_module_name(MyType), __name__) -- self.assertEqual(get_type_qualname(MyType), 'my_qualname') -- self.assertEqual(get_type_name(MyType), 'my_name') -- -- # override also __module__ -- MyType.__module__ = 'my_module' -- self.assertEqual(get_type_fullyqualname(MyType), 'my_module.my_qualname') -- self.assertEqual(get_type_module_name(MyType), 'my_module') -- self.assertEqual(get_type_qualname(MyType), 'my_qualname') -- self.assertEqual(get_type_name(MyType), 'my_name') -- -- # PyType_GetFullyQualifiedName() ignores the module if it's "builtins" -- # or "__main__" of it is not a string -- MyType.__module__ = 'builtins' -- self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname') -- MyType.__module__ = '__main__' -- self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname') -- MyType.__module__ = 123 -- self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname') -- -- def test_get_base_by_token(self): -- def get_base_by_token(src, key, comparable=True): -- def run(use_mro): -- find_first = _testcapi.pytype_getbasebytoken -- ret1, result = find_first(src, key, use_mro, True) -- ret2, no_result = find_first(src, key, use_mro, False) -- self.assertIn(ret1, (0, 1)) -- self.assertEqual(ret1, result is not None) -- self.assertEqual(ret1, ret2) -- self.assertIsNone(no_result) -- return result -- -- found_in_mro = run(True) -- found_in_bases = run(False) -- if comparable: -- self.assertIs(found_in_mro, found_in_bases) -- return found_in_mro -- return found_in_mro, found_in_bases -- -- create_type = _testcapi.create_type_with_token -- get_token = _testcapi.get_tp_token -- -- Py_TP_USE_SPEC = _testcapi.Py_TP_USE_SPEC -- self.assertEqual(Py_TP_USE_SPEC, 0) -- -- A1 = create_type('_testcapi.A1', Py_TP_USE_SPEC) -- self.assertTrue(get_token(A1) != Py_TP_USE_SPEC) -- -- B1 = create_type('_testcapi.B1', id(self)) -- self.assertTrue(get_token(B1) == id(self)) -- -- tokenA1 = get_token(A1) -- # find A1 from A1 -- found = get_base_by_token(A1, tokenA1) -- self.assertIs(found, A1) -- -- # no token in static types -- STATIC = type(1) -- self.assertEqual(get_token(STATIC), 0) -- found = get_base_by_token(STATIC, tokenA1) -- self.assertIs(found, None) -- -- # no token in pure subtypes -- class A2(A1): pass -- self.assertEqual(get_token(A2), 0) -- # find A1 -- class Z(STATIC, B1, A2): pass -- found = get_base_by_token(Z, tokenA1) -- self.assertIs(found, A1) -- -- # searching for NULL token is an error -- with self.assertRaises(SystemError): -- get_base_by_token(Z, 0) -- with self.assertRaises(SystemError): -- get_base_by_token(STATIC, 0) -- -- # share the token with A1 -- C1 = create_type('_testcapi.C1', tokenA1) -- self.assertTrue(get_token(C1) == tokenA1) -- -- # find C1 first by shared token -- class Z(C1, A2): pass -- found = get_base_by_token(Z, tokenA1) -- self.assertIs(found, C1) -- # B1 not found -- found = get_base_by_token(Z, get_token(B1)) -- self.assertIs(found, None) -- -- with self.assertRaises(TypeError): -- _testcapi.pytype_getbasebytoken( -- 'not a type', id(self), True, False) -- - def test_gen_get_code(self): - def genf(): yield - gen = genf() -@@ -1457,125 +1114,6 @@ - _testcapi.pyobject_getitemdata(0) - - -- def test_function_get_closure(self): -- from types import CellType -- -- def regular_function(): ... -- def unused_one_level(arg1): -- def inner(arg2, arg3): ... -- return inner -- def unused_two_levels(arg1, arg2): -- def decorator(arg3, arg4): -- def inner(arg5, arg6): ... -- return inner -- return decorator -- def with_one_level(arg1): -- def inner(arg2, arg3): -- return arg1 + arg2 + arg3 -- return inner -- def with_two_levels(arg1, arg2): -- def decorator(arg3, arg4): -- def inner(arg5, arg6): -- return arg1 + arg2 + arg3 + arg4 + arg5 + arg6 -- return inner -- return decorator -- -- # Functions without closures: -- self.assertIsNone(_testcapi.function_get_closure(regular_function)) -- self.assertIsNone(regular_function.__closure__) -- -- func = unused_one_level(1) -- closure = _testcapi.function_get_closure(func) -- self.assertIsNone(closure) -- self.assertIsNone(func.__closure__) -- -- func = unused_two_levels(1, 2)(3, 4) -- closure = _testcapi.function_get_closure(func) -- self.assertIsNone(closure) -- self.assertIsNone(func.__closure__) -- -- # Functions with closures: -- func = with_one_level(5) -- closure = _testcapi.function_get_closure(func) -- self.assertEqual(closure, func.__closure__) -- self.assertIsInstance(closure, tuple) -- self.assertEqual(len(closure), 1) -- self.assertEqual(len(closure), len(func.__code__.co_freevars)) -- self.assertTrue(all(isinstance(cell, CellType) for cell in closure)) -- self.assertTrue(closure[0].cell_contents, 5) -- -- func = with_two_levels(1, 2)(3, 4) -- closure = _testcapi.function_get_closure(func) -- self.assertEqual(closure, func.__closure__) -- self.assertIsInstance(closure, tuple) -- self.assertEqual(len(closure), 4) -- self.assertEqual(len(closure), len(func.__code__.co_freevars)) -- self.assertTrue(all(isinstance(cell, CellType) for cell in closure)) -- self.assertEqual([cell.cell_contents for cell in closure], -- [1, 2, 3, 4]) -- -- def test_function_get_closure_error(self): -- with self.assertRaises(SystemError): -- _testcapi.function_get_closure(1) -- with self.assertRaises(SystemError): -- _testcapi.function_get_closure(None) -- -- def test_function_set_closure(self): -- from types import CellType -- -- def function_without_closure(): ... -- def function_with_closure(arg): -- def inner(): -- return arg -- return inner -- -- func = function_without_closure -- _testcapi.function_set_closure(func, (CellType(1), CellType(1))) -- closure = _testcapi.function_get_closure(func) -- self.assertEqual([c.cell_contents for c in closure], [1, 1]) -- self.assertEqual([c.cell_contents for c in func.__closure__], [1, 1]) -- -- func = function_with_closure(1) -- _testcapi.function_set_closure(func, -- (CellType(1), CellType(2), CellType(3))) -- closure = _testcapi.function_get_closure(func) -- self.assertEqual([c.cell_contents for c in closure], [1, 2, 3]) -- self.assertEqual([c.cell_contents for c in func.__closure__], [1, 2, 3]) -- -- def test_function_set_closure_none(self): -- def function_without_closure(): ... -- def function_with_closure(arg): -- def inner(): -- return arg -- return inner -- -- _testcapi.function_set_closure(function_without_closure, None) -- self.assertIsNone( -- _testcapi.function_get_closure(function_without_closure)) -- self.assertIsNone(function_without_closure.__closure__) -- -- _testcapi.function_set_closure(function_with_closure, None) -- self.assertIsNone( -- _testcapi.function_get_closure(function_with_closure)) -- self.assertIsNone(function_with_closure.__closure__) -- -- def test_function_set_closure_errors(self): -- def function_without_closure(): ... -- -- with self.assertRaises(SystemError): -- _testcapi.function_set_closure(None, ()) # not a function -- -- with self.assertRaises(SystemError): -- _testcapi.function_set_closure(function_without_closure, 1) -- self.assertIsNone(function_without_closure.__closure__) # no change -- -- # NOTE: this works, but goes against the docs: -- _testcapi.function_set_closure(function_without_closure, (1, 2)) -- self.assertEqual( -- _testcapi.function_get_closure(function_without_closure), (1, 2)) -- self.assertEqual(function_without_closure.__closure__, (1, 2)) -- -- - class TestPendingCalls(unittest.TestCase): - - # See the comment in ceval.c (at the "handle_eval_breaker" label) -@@ -2139,28 +1677,27 @@ - self.assertEqual(ret, 0) - self.assertEqual(pickle.load(f), {'a': '123x', 'b': '123'}) - -+ # _testcapi cannot be imported in a subinterpreter on a Free Threaded build -+ @support.requires_gil_enabled() - def test_py_config_isoloated_per_interpreter(self): - # A config change in one interpreter must not leak to out to others. - # - # This test could verify ANY config value, it just happens to have been - # written around the time of int_max_str_digits. Refactoring is okay. - code = """if 1: -- import sys, _testinternalcapi -+ import sys, _testcapi - - # Any config value would do, this happens to be the one being - # double checked at the time this test was written. -- config = _testinternalcapi.get_config() -- config['int_max_str_digits'] = 55555 -- config['parse_argv'] = 0 -- _testinternalcapi.set_config(config) -- sub_value = _testinternalcapi.get_config()['int_max_str_digits'] -+ _testcapi.config_set('int_max_str_digits', 55555) -+ sub_value = _testcapi.config_get('int_max_str_digits') - assert sub_value == 55555, sub_value - """ -- before_config = _testinternalcapi.get_config() -- assert before_config['int_max_str_digits'] != 55555 -+ before_config = _testcapi.config_get('int_max_str_digits') -+ assert before_config != 55555 - self.assertEqual(support.run_in_subinterp(code), 0, - 'subinterp code failure, check stderr.') -- after_config = _testinternalcapi.get_config() -+ after_config = _testcapi.config_get('int_max_str_digits') - self.assertIsNot( - before_config, after_config, - "Expected get_config() to return a new dict on each call") -@@ -2363,7 +1900,7 @@ - - support.run_in_subinterp("import binascii; binascii.Error.foobar = 'foobar'") - -- self.assertFalse(hasattr(binascii.Error, "foobar")) -+ self.assertNotHasAttr(binascii.Error, "foobar") - - @unittest.skipIf(_testmultiphase is None, "test requires _testmultiphase module") - # gh-117649: The free-threaded build does not currently support sharing -@@ -2918,39 +2455,6 @@ - 0, get_refcount(interpid)) - - --class BuiltinStaticTypesTests(unittest.TestCase): -- -- TYPES = [ -- object, -- type, -- int, -- str, -- dict, -- type(None), -- bool, -- BaseException, -- Exception, -- Warning, -- DeprecationWarning, # Warning subclass -- ] -- -- def test_tp_bases_is_set(self): -- # PyTypeObject.tp_bases is documented as public API. -- # See https://github.com/python/cpython/issues/105020. -- for typeobj in self.TYPES: -- with self.subTest(typeobj): -- bases = _testcapi.type_get_tp_bases(typeobj) -- self.assertIsNot(bases, None) -- -- def test_tp_mro_is_set(self): -- # PyTypeObject.tp_bases is documented as public API. -- # See https://github.com/python/cpython/issues/105020. -- for typeobj in self.TYPES: -- with self.subTest(typeobj): -- mro = _testcapi.type_get_tp_mro(typeobj) -- self.assertIsNot(mro, None) -- -- - class TestStaticTypes(unittest.TestCase): - - _has_run = False -@@ -3335,6 +2839,50 @@ - self.assertEqual(len(set(py_thread_ids)), len(py_thread_ids), - py_thread_ids) - -+class TestVersions(unittest.TestCase): -+ full_cases = ( -+ (3, 4, 1, 0xA, 2, 0x030401a2), -+ (3, 10, 0, 0xF, 0, 0x030a00f0), -+ (0x103, 0x10B, 0xFF00, -1, 0xF0, 0x030b00f0), # test masking -+ ) -+ xy_cases = ( -+ (3, 4, 0x03040000), -+ (3, 10, 0x030a0000), -+ (0x103, 0x10B, 0x030b0000), # test masking -+ ) -+ -+ def test_pack_full_version(self): -+ for *args, expected in self.full_cases: -+ with self.subTest(hexversion=hex(expected)): -+ result = _testlimitedcapi.pack_full_version(*args) -+ self.assertEqual(result, expected) -+ -+ def test_pack_version(self): -+ for *args, expected in self.xy_cases: -+ with self.subTest(hexversion=hex(expected)): -+ result = _testlimitedcapi.pack_version(*args) -+ self.assertEqual(result, expected) -+ -+ def test_pack_full_version_ctypes(self): -+ ctypes = import_helper.import_module('ctypes') -+ ctypes_func = ctypes.pythonapi.Py_PACK_FULL_VERSION -+ ctypes_func.restype = ctypes.c_uint32 -+ ctypes_func.argtypes = [ctypes.c_int] * 5 -+ for *args, expected in self.full_cases: -+ with self.subTest(hexversion=hex(expected)): -+ result = ctypes_func(*args) -+ self.assertEqual(result, expected) -+ -+ def test_pack_version_ctypes(self): -+ ctypes = import_helper.import_module('ctypes') -+ ctypes_func = ctypes.pythonapi.Py_PACK_VERSION -+ ctypes_func.restype = ctypes.c_uint32 -+ ctypes_func.argtypes = [ctypes.c_int] * 2 -+ for *args, expected in self.xy_cases: -+ with self.subTest(hexversion=hex(expected)): -+ result = ctypes_func(*args) -+ self.assertEqual(result, expected) -+ - - if __name__ == "__main__": - unittest.main() -diff --git a/Lib/test/test_capi/test_object.py b/Lib/test/test_capi/test_object.py -index b0d39937fd8..5d0a383de64 100644 ---- a/Lib/test/test_capi/test_object.py -+++ b/Lib/test/test_capi/test_object.py -@@ -1,9 +1,12 @@ - import enum -+import textwrap - import unittest - from test import support - from test.support import import_helper - from test.support import os_helper - from test.support import threading_helper -+from test.support.script_helper import assert_python_failure -+ - - _testlimitedcapi = import_helper.import_module('_testlimitedcapi') - _testcapi = import_helper.import_module('_testcapi') -@@ -170,5 +173,42 @@ - self.assertTrue(_testinternalcapi.has_deferred_refcount(silly_list)) - - -+class CAPITest(unittest.TestCase): -+ def check_negative_refcount(self, code): -+ # bpo-35059: Check that Py_DECREF() reports the correct filename -+ # when calling _Py_NegativeRefcount() to abort Python. -+ code = textwrap.dedent(code) -+ rc, out, err = assert_python_failure('-c', code) -+ self.assertRegex(err, -+ br'object\.c:[0-9]+: ' -+ br'_Py_NegativeRefcount: Assertion failed: ' -+ br'object has negative ref count') -+ -+ @unittest.skipUnless(hasattr(_testcapi, 'negative_refcount'), -+ 'need _testcapi.negative_refcount()') -+ def test_negative_refcount(self): -+ code = """ -+ import _testcapi -+ from test import support -+ -+ with support.SuppressCrashReport(): -+ _testcapi.negative_refcount() -+ """ -+ self.check_negative_refcount(code) -+ -+ @unittest.skipUnless(hasattr(_testcapi, 'decref_freed_object'), -+ 'need _testcapi.decref_freed_object()') -+ @support.skip_if_sanitizer("use after free on purpose", -+ address=True, memory=True, ub=True) -+ def test_decref_freed_object(self): -+ code = """ -+ import _testcapi -+ from test import support -+ -+ with support.SuppressCrashReport(): -+ _testcapi.decref_freed_object() -+ """ -+ self.check_negative_refcount(code) -+ - if __name__ == "__main__": - unittest.main() -diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py -index 4cf9b66170c..2a9b777862c 100644 ---- a/Lib/test/test_capi/test_opt.py -+++ b/Lib/test/test_capi/test_opt.py -@@ -1,4 +1,5 @@ - import contextlib -+import itertools - import sys - import textwrap - import unittest -@@ -8,114 +9,22 @@ - import _opcode - - from test.support import (script_helper, requires_specialization, -- import_helper, Py_GIL_DISABLED) -+ import_helper, Py_GIL_DISABLED, requires_jit_enabled, -+ reset_code) - - _testinternalcapi = import_helper.import_module("_testinternalcapi") - - from _testinternalcapi import TIER2_THRESHOLD - --@contextlib.contextmanager --def temporary_optimizer(opt): -- old_opt = _testinternalcapi.get_optimizer() -- _testinternalcapi.set_optimizer(opt) -- try: -- yield -- finally: -- _testinternalcapi.set_optimizer(old_opt) -- - - @contextlib.contextmanager - def clear_executors(func): - # Clear executors in func before and after running a block -- func.__code__ = func.__code__.replace() -+ reset_code(func) - try: - yield - finally: -- func.__code__ = func.__code__.replace() -- -- --@requires_specialization --@unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds") --@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"), -- "Requires optimizer infrastructure") --class TestOptimizerAPI(unittest.TestCase): -- -- def test_new_counter_optimizer_dealloc(self): -- # See gh-108727 -- def f(): -- _testinternalcapi.new_counter_optimizer() -- -- f() -- -- def test_get_set_optimizer(self): -- old = _testinternalcapi.get_optimizer() -- opt = _testinternalcapi.new_counter_optimizer() -- try: -- _testinternalcapi.set_optimizer(opt) -- self.assertEqual(_testinternalcapi.get_optimizer(), opt) -- _testinternalcapi.set_optimizer(None) -- self.assertEqual(_testinternalcapi.get_optimizer(), None) -- finally: -- _testinternalcapi.set_optimizer(old) -- -- -- def test_counter_optimizer(self): -- # Generate a new function at each call -- ns = {} -- exec(textwrap.dedent(f""" -- def loop(): -- for _ in range({TIER2_THRESHOLD + 1000}): -- pass -- """), ns, ns) -- loop = ns['loop'] -- -- for repeat in range(5): -- opt = _testinternalcapi.new_counter_optimizer() -- with temporary_optimizer(opt): -- self.assertEqual(opt.get_count(), 0) -- with clear_executors(loop): -- loop() -- self.assertEqual(opt.get_count(), 1001) -- -- def test_long_loop(self): -- "Check that we aren't confused by EXTENDED_ARG" -- -- # Generate a new function at each call -- ns = {} -- exec(textwrap.dedent(f""" -- def nop(): -- pass -- -- def long_loop(): -- for _ in range({TIER2_THRESHOLD + 20}): -- nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); -- nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); -- nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); -- nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); -- nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); -- nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); -- nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); -- """), ns, ns) -- long_loop = ns['long_loop'] -- -- opt = _testinternalcapi.new_counter_optimizer() -- with temporary_optimizer(opt): -- self.assertEqual(opt.get_count(), 0) -- long_loop() -- self.assertEqual(opt.get_count(), 21) # Need iterations to warm up -- -- def test_code_restore_for_ENTER_EXECUTOR(self): -- def testfunc(x): -- i = 0 -- while i < x: -- i += 1 -- -- opt = _testinternalcapi.new_counter_optimizer() -- with temporary_optimizer(opt): -- testfunc(1000) -- code, replace_code = testfunc.__code__, testfunc.__code__.replace() -- self.assertEqual(code, replace_code) -- self.assertEqual(hash(code), hash(replace_code)) -+ reset_code(func) - - - def get_first_executor(func): -@@ -140,18 +49,9 @@ - - @requires_specialization - @unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds") --@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"), -- "Requires optimizer infrastructure") -+@requires_jit_enabled - class TestExecutorInvalidation(unittest.TestCase): - -- def setUp(self): -- self.old = _testinternalcapi.get_optimizer() -- self.opt = _testinternalcapi.new_counter_optimizer() -- _testinternalcapi.set_optimizer(self.opt) -- -- def tearDown(self): -- _testinternalcapi.set_optimizer(self.old) -- - def test_invalidate_object(self): - # Generate a new set of functions at each call - ns = {} -@@ -195,9 +95,7 @@ - pass - """), ns, ns) - f = ns['f'] -- opt = _testinternalcapi.new_uop_optimizer() -- with temporary_optimizer(opt): -- f() -+ f() - exe = get_first_executor(f) - self.assertIsNotNone(exe) - self.assertTrue(exe.is_valid()) -@@ -208,9 +106,7 @@ - def f(): - for _ in range(TIER2_THRESHOLD): - pass -- opt = _testinternalcapi.new_uop_optimizer() -- with temporary_optimizer(opt): -- f() -+ f() - exe = get_first_executor(f) - self.assertIsNotNone(exe) - self.assertTrue(exe.is_valid()) -@@ -222,8 +118,7 @@ - - @requires_specialization - @unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds") --@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"), -- "Requires optimizer infrastructure") -+@requires_jit_enabled - @unittest.skipIf(os.getenv("PYTHON_UOPS_OPTIMIZE") == "0", "Needs uop optimizer to run.") - class TestUops(unittest.TestCase): - -@@ -233,9 +128,7 @@ - while i < x: - i += 1 - -- opt = _testinternalcapi.new_uop_optimizer() -- with temporary_optimizer(opt): -- testfunc(TIER2_THRESHOLD) -+ testfunc(TIER2_THRESHOLD) - - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) -@@ -281,11 +174,9 @@ - """), ns, ns) - many_vars = ns["many_vars"] - -- opt = _testinternalcapi.new_uop_optimizer() -- with temporary_optimizer(opt): -- ex = get_first_executor(many_vars) -- self.assertIsNone(ex) -- many_vars() -+ ex = get_first_executor(many_vars) -+ self.assertIsNone(ex) -+ many_vars() - - ex = get_first_executor(many_vars) - self.assertIsNotNone(ex) -@@ -304,10 +195,7 @@ - while i < x: - i += 1 - -- opt = _testinternalcapi.new_uop_optimizer() -- -- with temporary_optimizer(opt): -- testfunc(TIER2_THRESHOLD) -+ testfunc(TIER2_THRESHOLD) - - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) -@@ -320,9 +208,7 @@ - while i < n: - i += 1 - -- opt = _testinternalcapi.new_uop_optimizer() -- with temporary_optimizer(opt): -- testfunc(TIER2_THRESHOLD) -+ testfunc(TIER2_THRESHOLD) - - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) -@@ -335,9 +221,7 @@ - if x is None: - x = 0 - -- opt = _testinternalcapi.new_uop_optimizer() -- with temporary_optimizer(opt): -- testfunc(range(TIER2_THRESHOLD)) -+ testfunc(range(TIER2_THRESHOLD)) - - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) -@@ -352,9 +236,7 @@ - if x is not None: - x = 0 - -- opt = _testinternalcapi.new_uop_optimizer() -- with temporary_optimizer(opt): -- testfunc(range(TIER2_THRESHOLD)) -+ testfunc(range(TIER2_THRESHOLD)) - - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) -@@ -368,9 +250,7 @@ - while not i >= n: - i += 1 - -- opt = _testinternalcapi.new_uop_optimizer() -- with temporary_optimizer(opt): -- testfunc(TIER2_THRESHOLD) -+ testfunc(TIER2_THRESHOLD) - - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) -@@ -383,9 +263,7 @@ - while i < n: - i += 1 - -- opt = _testinternalcapi.new_uop_optimizer() -- with temporary_optimizer(opt): -- testfunc(TIER2_THRESHOLD) -+ testfunc(TIER2_THRESHOLD) - - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) -@@ -403,9 +281,7 @@ - a += 1 - return a - -- opt = _testinternalcapi.new_uop_optimizer() -- with temporary_optimizer(opt): -- testfunc(TIER2_THRESHOLD) -+ testfunc(TIER2_THRESHOLD) - - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) -@@ -421,10 +297,8 @@ - total += i - return total - -- opt = _testinternalcapi.new_uop_optimizer() -- with temporary_optimizer(opt): -- total = testfunc(TIER2_THRESHOLD) -- self.assertEqual(total, sum(range(TIER2_THRESHOLD))) -+ total = testfunc(TIER2_THRESHOLD) -+ self.assertEqual(total, sum(range(TIER2_THRESHOLD))) - - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) -@@ -442,11 +316,9 @@ - total += i - return total - -- opt = _testinternalcapi.new_uop_optimizer() -- with temporary_optimizer(opt): -- a = list(range(TIER2_THRESHOLD)) -- total = testfunc(a) -- self.assertEqual(total, sum(a)) -+ a = list(range(TIER2_THRESHOLD)) -+ total = testfunc(a) -+ self.assertEqual(total, sum(a)) - - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) -@@ -464,11 +336,9 @@ - total += i - return total - -- opt = _testinternalcapi.new_uop_optimizer() -- with temporary_optimizer(opt): -- a = tuple(range(TIER2_THRESHOLD)) -- total = testfunc(a) -- self.assertEqual(total, sum(a)) -+ a = tuple(range(TIER2_THRESHOLD)) -+ total = testfunc(a) -+ self.assertEqual(total, sum(a)) - - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) -@@ -484,14 +354,12 @@ - for x in it: - pass - -- opt = _testinternalcapi.new_uop_optimizer() -- with temporary_optimizer(opt): -- a = [1, 2, 3] -- it = iter(a) -- testfunc(it) -- a.append(4) -- with self.assertRaises(StopIteration): -- next(it) -+ a = [1, 2, 3] -+ it = iter(a) -+ testfunc(it) -+ a.append(4) -+ with self.assertRaises(StopIteration): -+ next(it) - - def test_call_py_exact_args(self): - def testfunc(n): -@@ -500,9 +368,7 @@ - for i in range(n): - dummy(i) - -- opt = _testinternalcapi.new_uop_optimizer() -- with temporary_optimizer(opt): -- testfunc(TIER2_THRESHOLD) -+ testfunc(TIER2_THRESHOLD) - - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) -@@ -518,9 +384,7 @@ - else: - i = 1 - -- opt = _testinternalcapi.new_uop_optimizer() -- with temporary_optimizer(opt): -- testfunc(TIER2_THRESHOLD) -+ testfunc(TIER2_THRESHOLD) - - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) -@@ -546,9 +410,7 @@ - x += 1000*i + j - return x - -- opt = _testinternalcapi.new_uop_optimizer() -- with temporary_optimizer(opt): -- x = testfunc(TIER2_THRESHOLD, TIER2_THRESHOLD) -+ x = testfunc(TIER2_THRESHOLD, TIER2_THRESHOLD) - - self.assertEqual(x, sum(range(TIER2_THRESHOLD)) * TIER2_THRESHOLD * 1001) - -@@ -573,9 +435,7 @@ - bits += 1 - return bits - -- opt = _testinternalcapi.new_uop_optimizer() -- with temporary_optimizer(opt): -- x = testfunc(TIER2_THRESHOLD * 2) -+ x = testfunc(TIER2_THRESHOLD * 2) - - self.assertEqual(x, TIER2_THRESHOLD * 5) - ex = get_first_executor(testfunc) -@@ -588,16 +448,12 @@ - - @requires_specialization - @unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds") --@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"), -- "Requires optimizer infrastructure") -+@requires_jit_enabled - @unittest.skipIf(os.getenv("PYTHON_UOPS_OPTIMIZE") == "0", "Needs uop optimizer to run.") - class TestUopsOptimization(unittest.TestCase): - - def _run_with_optimizer(self, testfunc, arg): -- res = None -- opt = _testinternalcapi.new_uop_optimizer() -- with temporary_optimizer(opt): -- res = testfunc(arg) -+ res = testfunc(arg) - - ex = get_first_executor(testfunc) - return res, ex -@@ -631,10 +487,7 @@ - num += 1 - return a - -- opt = _testinternalcapi.new_uop_optimizer() -- res = None -- with temporary_optimizer(opt): -- res = testfunc(TIER2_THRESHOLD) -+ res = testfunc(TIER2_THRESHOLD) - - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) -@@ -655,10 +508,7 @@ - num += 1 - return x - -- opt = _testinternalcapi.new_uop_optimizer() -- res = None -- with temporary_optimizer(opt): -- res = testfunc(TIER2_THRESHOLD) -+ res = testfunc(TIER2_THRESHOLD) - - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) -@@ -750,16 +600,14 @@ - for i in range(n): - dummy(i) - -- opt = _testinternalcapi.new_uop_optimizer() - # Trigger specialization - testfunc(8) -- with temporary_optimizer(opt): -- del dummy -- gc.collect() -+ del dummy -+ gc.collect() - -- def dummy(x): -- return x + 2 -- testfunc(32) -+ def dummy(x): -+ return x + 2 -+ testfunc(32) - - ex = get_first_executor(testfunc) - # Honestly as long as it doesn't crash it's fine. -@@ -792,16 +640,14 @@ - x = range(i) - return x - -- opt = _testinternalcapi.new_uop_optimizer() -- _testinternalcapi.set_optimizer(opt) - testfunc(_testinternalcapi.TIER2_THRESHOLD) - - ex = get_first_executor(testfunc) - assert ex is not None - uops = get_opnames(ex) - assert "_LOAD_GLOBAL_BUILTINS" not in uops -- assert "_LOAD_CONST_INLINE_BORROW_WITH_NULL" in uops -- """)) -+ assert "_LOAD_CONST_INLINE_BORROW" in uops -+ """), PYTHON_JIT="1") - self.assertEqual(result[0].rc, 0, result) - - def test_float_add_constant_propagation(self): -@@ -1314,6 +1160,7 @@ - self.assertIsNotNone(ex) - self.assertIn("_RETURN_GENERATOR", get_opnames(ex)) - -+ @unittest.skip("Tracing into generators currently isn't supported.") - def test_for_iter_gen(self): - def gen(n): - for i in range(n): -@@ -1488,9 +1335,7 @@ - # Only works on functions promoted to constants - global_identity(i) - -- opt = _testinternalcapi.new_uop_optimizer() -- with temporary_optimizer(opt): -- testfunc(TIER2_THRESHOLD) -+ testfunc(TIER2_THRESHOLD) - - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) -@@ -1511,6 +1356,87 @@ - with self.assertRaises(TypeError): - {item for item in items} - -+ def test_power_type_depends_on_input_values(self): -+ template = textwrap.dedent(""" -+ import _testinternalcapi -+ -+ L, R, X, Y = {l}, {r}, {x}, {y} -+ -+ def check(actual: complex, expected: complex) -> None: -+ assert actual == expected, (actual, expected) -+ assert type(actual) is type(expected), (actual, expected) -+ -+ def f(l: complex, r: complex) -> None: -+ expected_local_local = pow(l, r) + pow(l, r) -+ expected_const_local = pow(L, r) + pow(L, r) -+ expected_local_const = pow(l, R) + pow(l, R) -+ expected_const_const = pow(L, R) + pow(L, R) -+ for _ in range(_testinternalcapi.TIER2_THRESHOLD): -+ # Narrow types: -+ l + l, r + r -+ # The powers produce results, and the addition is unguarded: -+ check(l ** r + l ** r, expected_local_local) -+ check(L ** r + L ** r, expected_const_local) -+ check(l ** R + l ** R, expected_local_const) -+ check(L ** R + L ** R, expected_const_const) -+ -+ # JIT for one pair of values... -+ f(L, R) -+ # ...then run with another: -+ f(X, Y) -+ """) -+ interesting = [ -+ (1, 1), # int ** int -> int -+ (1, -1), # int ** int -> float -+ (1.0, 1), # float ** int -> float -+ (1, 1.0), # int ** float -> float -+ (-1, 0.5), # int ** float -> complex -+ (1.0, 1.0), # float ** float -> float -+ (-1.0, 0.5), # float ** float -> complex -+ ] -+ for (l, r), (x, y) in itertools.product(interesting, repeat=2): -+ s = template.format(l=l, r=r, x=x, y=y) -+ with self.subTest(l=l, r=r, x=x, y=y): -+ script_helper.assert_python_ok("-c", s) -+ -+ def test_symbols_flow_through_tuples(self): -+ def testfunc(n): -+ for _ in range(n): -+ a = 1 -+ b = 2 -+ t = a, b -+ x, y = t -+ r = x + y -+ return r -+ -+ res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) -+ self.assertEqual(res, 3) -+ self.assertIsNotNone(ex) -+ uops = get_opnames(ex) -+ self.assertIn("_BINARY_OP_ADD_INT", uops) -+ self.assertNotIn("_GUARD_BOTH_INT", uops) -+ self.assertNotIn("_GUARD_NOS_INT", uops) -+ self.assertNotIn("_GUARD_TOS_INT", uops) -+ -+ def test_decref_escapes(self): -+ class Convert9999ToNone: -+ def __del__(self): -+ ns = sys._getframe(1).f_locals -+ if ns["i"] == _testinternalcapi.TIER2_THRESHOLD: -+ ns["i"] = None -+ -+ def crash_addition(): -+ try: -+ for i in range(_testinternalcapi.TIER2_THRESHOLD + 1): -+ n = Convert9999ToNone() -+ i + i # Remove guards for i. -+ n = None # Change i. -+ i + i # This crashed when we didn't treat DECREF as escaping (gh-124483) -+ except TypeError: -+ pass -+ -+ crash_addition() -+ - - def global_identity(x): - return x -diff --git a/Lib/test/test_capi/test_sys.py b/Lib/test/test_capi/test_sys.py -index 54a8e026d88..d3a9b378e77 100644 ---- a/Lib/test/test_capi/test_sys.py -+++ b/Lib/test/test_capi/test_sys.py -@@ -51,7 +51,7 @@ - self.assertEqual(setobject(b'newattr', value2), 0) - self.assertIs(sys.newattr, value2) - self.assertEqual(setobject(b'newattr', NULL), 0) -- self.assertFalse(hasattr(sys, 'newattr')) -+ self.assertNotHasAttr(sys, 'newattr') - self.assertEqual(setobject(b'newattr', NULL), 0) - finally: - with contextlib.suppress(AttributeError): -@@ -60,7 +60,7 @@ - self.assertEqual(setobject('\U0001f40d'.encode(), value), 0) - self.assertIs(getattr(sys, '\U0001f40d'), value) - self.assertEqual(setobject('\U0001f40d'.encode(), NULL), 0) -- self.assertFalse(hasattr(sys, '\U0001f40d')) -+ self.assertNotHasAttr(sys, '\U0001f40d') - finally: - with contextlib.suppress(AttributeError): - delattr(sys, '\U0001f40d') -diff --git a/Lib/test/test_capi/test_type.py b/Lib/test/test_capi/test_type.py -index 54c83e09f89..7e5d013d737 100644 ---- a/Lib/test/test_capi/test_type.py -+++ b/Lib/test/test_capi/test_type.py -@@ -1,10 +1,184 @@ --from test.support import import_helper -+from test.support import import_helper, Py_GIL_DISABLED, refleak_helper - import unittest - - _testcapi = import_helper.import_module('_testcapi') - - -+class BuiltinStaticTypesTests(unittest.TestCase): -+ -+ TYPES = [ -+ object, -+ type, -+ int, -+ str, -+ dict, -+ type(None), -+ bool, -+ BaseException, -+ Exception, -+ Warning, -+ DeprecationWarning, # Warning subclass -+ ] -+ -+ def test_tp_bases_is_set(self): -+ # PyTypeObject.tp_bases is documented as public API. -+ # See https://github.com/python/cpython/issues/105020. -+ for typeobj in self.TYPES: -+ with self.subTest(typeobj): -+ bases = _testcapi.type_get_tp_bases(typeobj) -+ self.assertIsNot(bases, None) -+ -+ def test_tp_mro_is_set(self): -+ # PyTypeObject.tp_bases is documented as public API. -+ # See https://github.com/python/cpython/issues/105020. -+ for typeobj in self.TYPES: -+ with self.subTest(typeobj): -+ mro = _testcapi.type_get_tp_mro(typeobj) -+ self.assertIsNot(mro, None) -+ -+ - class TypeTests(unittest.TestCase): -+ def test_get_type_name(self): -+ class MyType: -+ pass -+ -+ from _testcapi import ( -+ get_type_name, get_type_qualname, -+ get_type_fullyqualname, get_type_module_name) -+ -+ from collections import OrderedDict -+ ht = _testcapi.get_heaptype_for_name() -+ for cls, fullname, modname, qualname, name in ( -+ (int, -+ 'int', -+ 'builtins', -+ 'int', -+ 'int'), -+ (OrderedDict, -+ 'collections.OrderedDict', -+ 'collections', -+ 'OrderedDict', -+ 'OrderedDict'), -+ (ht, -+ '_testcapi.HeapTypeNameType', -+ '_testcapi', -+ 'HeapTypeNameType', -+ 'HeapTypeNameType'), -+ (MyType, -+ f'{__name__}.TypeTests.test_get_type_name..MyType', -+ __name__, -+ 'TypeTests.test_get_type_name..MyType', -+ 'MyType'), -+ ): -+ with self.subTest(cls=repr(cls)): -+ self.assertEqual(get_type_fullyqualname(cls), fullname) -+ self.assertEqual(get_type_module_name(cls), modname) -+ self.assertEqual(get_type_qualname(cls), qualname) -+ self.assertEqual(get_type_name(cls), name) -+ -+ # override __module__ -+ ht.__module__ = 'test_module' -+ self.assertEqual(get_type_fullyqualname(ht), 'test_module.HeapTypeNameType') -+ self.assertEqual(get_type_module_name(ht), 'test_module') -+ self.assertEqual(get_type_qualname(ht), 'HeapTypeNameType') -+ self.assertEqual(get_type_name(ht), 'HeapTypeNameType') -+ -+ # override __name__ and __qualname__ -+ MyType.__name__ = 'my_name' -+ MyType.__qualname__ = 'my_qualname' -+ self.assertEqual(get_type_fullyqualname(MyType), f'{__name__}.my_qualname') -+ self.assertEqual(get_type_module_name(MyType), __name__) -+ self.assertEqual(get_type_qualname(MyType), 'my_qualname') -+ self.assertEqual(get_type_name(MyType), 'my_name') -+ -+ # override also __module__ -+ MyType.__module__ = 'my_module' -+ self.assertEqual(get_type_fullyqualname(MyType), 'my_module.my_qualname') -+ self.assertEqual(get_type_module_name(MyType), 'my_module') -+ self.assertEqual(get_type_qualname(MyType), 'my_qualname') -+ self.assertEqual(get_type_name(MyType), 'my_name') -+ -+ # PyType_GetFullyQualifiedName() ignores the module if it's "builtins" -+ # or "__main__" of it is not a string -+ MyType.__module__ = 'builtins' -+ self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname') -+ MyType.__module__ = '__main__' -+ self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname') -+ MyType.__module__ = 123 -+ self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname') -+ -+ def test_get_base_by_token(self): -+ def get_base_by_token(src, key, comparable=True): -+ def run(use_mro): -+ find_first = _testcapi.pytype_getbasebytoken -+ ret1, result = find_first(src, key, use_mro, True) -+ ret2, no_result = find_first(src, key, use_mro, False) -+ self.assertIn(ret1, (0, 1)) -+ self.assertEqual(ret1, result is not None) -+ self.assertEqual(ret1, ret2) -+ self.assertIsNone(no_result) -+ return result -+ -+ found_in_mro = run(True) -+ found_in_bases = run(False) -+ if comparable: -+ self.assertIs(found_in_mro, found_in_bases) -+ return found_in_mro -+ return found_in_mro, found_in_bases -+ -+ create_type = _testcapi.create_type_with_token -+ get_token = _testcapi.get_tp_token -+ -+ Py_TP_USE_SPEC = _testcapi.Py_TP_USE_SPEC -+ self.assertEqual(Py_TP_USE_SPEC, 0) -+ -+ A1 = create_type('_testcapi.A1', Py_TP_USE_SPEC) -+ self.assertTrue(get_token(A1) != Py_TP_USE_SPEC) -+ -+ B1 = create_type('_testcapi.B1', id(self)) -+ self.assertTrue(get_token(B1) == id(self)) -+ -+ tokenA1 = get_token(A1) -+ # find A1 from A1 -+ found = get_base_by_token(A1, tokenA1) -+ self.assertIs(found, A1) -+ -+ # no token in static types -+ STATIC = type(1) -+ self.assertEqual(get_token(STATIC), 0) -+ found = get_base_by_token(STATIC, tokenA1) -+ self.assertIs(found, None) -+ -+ # no token in pure subtypes -+ class A2(A1): pass -+ self.assertEqual(get_token(A2), 0) -+ # find A1 -+ class Z(STATIC, B1, A2): pass -+ found = get_base_by_token(Z, tokenA1) -+ self.assertIs(found, A1) -+ -+ # searching for NULL token is an error -+ with self.assertRaises(SystemError): -+ get_base_by_token(Z, 0) -+ with self.assertRaises(SystemError): -+ get_base_by_token(STATIC, 0) -+ -+ # share the token with A1 -+ C1 = create_type('_testcapi.C1', tokenA1) -+ self.assertTrue(get_token(C1) == tokenA1) -+ -+ # find C1 first by shared token -+ class Z(C1, A2): pass -+ found = get_base_by_token(Z, tokenA1) -+ self.assertIs(found, C1) -+ # B1 not found -+ found = get_base_by_token(Z, get_token(B1)) -+ self.assertIs(found, None) -+ -+ with self.assertRaises(TypeError): -+ _testcapi.pytype_getbasebytoken( -+ 'not a type', id(self), True, False) -+ - def test_freeze(self): - # test PyType_Freeze() - type_freeze = _testcapi.type_freeze -@@ -37,6 +211,9 @@ - # as well - type_freeze(D) - -+ @unittest.skipIf( -+ Py_GIL_DISABLED and refleak_helper.hunting_for_refleaks(), -+ "Specialization failure triggers gh-127773") - def test_freeze_meta(self): - """test PyType_Freeze() with overridden MRO""" - type_freeze = _testcapi.type_freeze -@@ -64,3 +241,10 @@ - Base.value = 3 - type_freeze(FreezeThis) - self.assertEqual(FreezeThis.value, 2) -+ -+ def test_manual_heap_type(self): -+ # gh-128923: test that a manually allocated and initailized heap type -+ # works correctly -+ ManualHeapType = _testcapi.ManualHeapType -+ for i in range(100): -+ self.assertIsInstance(ManualHeapType(), ManualHeapType) -diff --git a/Lib/test/test_capi/test_unicode.py b/Lib/test/test_capi/test_unicode.py -index 65d8242ad3f..3408c10f426 100644 ---- a/Lib/test/test_capi/test_unicode.py -+++ b/Lib/test/test_capi/test_unicode.py -@@ -1,7 +1,7 @@ - import unittest - import sys - from test import support --from test.support import import_helper -+from test.support import threading_helper - - try: - import _testcapi -@@ -1005,6 +1005,24 @@ - self.assertRaises(TypeError, unicode_asutf8, [], 0) - # CRASHES unicode_asutf8(NULL, 0) - -+ @unittest.skipIf(_testcapi is None, 'need _testcapi module') -+ @threading_helper.requires_working_threading() -+ def test_asutf8_race(self): -+ """Test that there's no race condition in PyUnicode_AsUTF8()""" -+ unicode_asutf8 = _testcapi.unicode_asutf8 -+ from threading import Thread -+ -+ data = "😊" -+ -+ def worker(): -+ for _ in range(1000): -+ self.assertEqual(unicode_asutf8(data, 5), b'\xf0\x9f\x98\x8a\0') -+ -+ threads = [Thread(target=worker) for _ in range(10)] -+ with threading_helper.start_threads(threads): -+ pass -+ -+ - @support.cpython_only - @unittest.skipIf(_testlimitedcapi is None, 'need _testlimitedcapi module') - def test_asutf8andsize(self): -diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py -index e20e59944e9..017aca3c828 100644 ---- a/Lib/test/test_class.py -+++ b/Lib/test/test_class.py -@@ -1,6 +1,7 @@ - "Test the functionality of Python classes implementing operators." - - import unittest -+from test import support - from test.support import cpython_only, import_helper, script_helper, skip_emscripten_stack_overflow - - testmeths = [ -@@ -134,6 +135,7 @@ - AllTests = type("AllTests", (object,), d) - del d, statictests, method, method_template - -+@support.thread_unsafe("callLst is shared between threads") - class ClassTests(unittest.TestCase): - def setUp(self): - callLst[:] = [] -diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py -index 11054963b6f..b45b9ee89ee 100644 ---- a/Lib/test/test_clinic.py -+++ b/Lib/test/test_clinic.py -@@ -740,6 +740,16 @@ - err = "Cannot use @text_signature when cloning a function" - self.expect_failure(block, err, lineno=11) - -+ def test_ignore_preprocessor_in_comments(self): -+ for dsl in "clinic", "python": -+ raw = dedent(f"""\ -+ /*[{dsl} input] -+ # CPP directives, valid or not, should be ignored in C comments. -+ # -+ [{dsl} start generated code]*/ -+ """) -+ self.clinic.parse(raw) -+ - - class ParseFileUnitTest(TestCase): - def expect_parsing_failure( -diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py -index 634efda3544..b949b310ac0 100644 ---- a/Lib/test/test_cmd_line.py -+++ b/Lib/test/test_cmd_line.py -@@ -336,6 +336,8 @@ - self.assertEqual(stdout, expected) - self.assertEqual(p.returncode, 0) - -+ @unittest.skipIf(os.environ.get("PYTHONUNBUFFERED", "0") != "0", -+ "Python stdio buffering is disabled.") - def test_non_interactive_output_buffering(self): - code = textwrap.dedent(""" - import sys -@@ -489,7 +491,7 @@ - rc, out, err = assert_python_failure('-c', code) - self.assertEqual(b'', out) - self.assertEqual(120, rc) -- self.assertIn(b'Exception ignored on flushing sys.stdout:\n' -+ self.assertIn(b'Exception ignored while flushing sys.stdout:\n' - b'OSError: '.replace(b'\n', os.linesep.encode()), - err) - -@@ -1012,7 +1014,7 @@ - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True) -- err_msg = "unknown option --unknown-option\nusage: " -+ err_msg = "Unknown option: --unknown-option\nusage: " - self.assertTrue(proc.stderr.startswith(err_msg), proc.stderr) - self.assertNotEqual(proc.returncode, 0) - -diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py -index f30107225ff..e7f3e46c186 100644 ---- a/Lib/test/test_cmd_line_script.py -+++ b/Lib/test/test_cmd_line_script.py -@@ -88,6 +88,8 @@ - importlib.invalidate_caches() - return to_return - -+ -+@support.force_not_colorized_test_class - class CmdLineTest(unittest.TestCase): - def _check_output(self, script_name, exit_code, data, - expected_file, expected_argv0, -@@ -659,7 +661,8 @@ - stderr.splitlines()[-3:], - [ b' foo = """\\q"""', - b' ^^^^^^^^', -- b'SyntaxError: invalid escape sequence \'\\q\'' -+ b'SyntaxError: "\\q" is an invalid escape sequence. ' -+ b'Did you mean "\\\\q"? A raw string is also an option.' - ], - ) - -diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py -index 2a1b26e8a1f..69c1ee0690d 100644 ---- a/Lib/test/test_code.py -+++ b/Lib/test/test_code.py -@@ -215,6 +215,8 @@ - from test.support import threading_helper, import_helper - from test.support.bytecode_helper import instructions_with_positions - from opcode import opmap, opname -+from _testcapi import code_offset_to_line -+ - COPY_FREE_VARS = opmap['COPY_FREE_VARS'] - - -@@ -427,14 +429,14 @@ - def foo(): - pass - -- # assert that opcode 229 is invalid -- self.assertEqual(opname[229], '<229>') -+ # assert that opcode 135 is invalid -+ self.assertEqual(opname[135], '<135>') - -- # change first opcode to 0xeb (=229) -+ # change first opcode to 0x87 (=135) - foo.__code__ = foo.__code__.replace( -- co_code=b'\xe5' + foo.__code__.co_code[1:]) -+ co_code=b'\x87' + foo.__code__.co_code[1:]) - -- msg = "unknown opcode 229" -+ msg = "unknown opcode 135" - with self.assertRaisesRegex(SystemError, msg): - foo() - -@@ -896,6 +898,44 @@ - - rc, out, err = assert_python_ok('-OO', '-c', code) - -+ def test_co_branches(self): -+ -+ def get_line_branches(func): -+ code = func.__code__ -+ base = code.co_firstlineno -+ return [ -+ ( -+ code_offset_to_line(code, src) - base, -+ code_offset_to_line(code, left) - base, -+ code_offset_to_line(code, right) - base -+ ) for (src, left, right) in -+ code.co_branches() -+ ] -+ -+ def simple(x): -+ if x: -+ A -+ else: -+ B -+ -+ self.assertEqual( -+ get_line_branches(simple), -+ [(1,2,4)]) -+ -+ def with_extended_args(x): -+ if x: -+ A.x; A.x; A.x; A.x; A.x; A.x; -+ A.x; A.x; A.x; A.x; A.x; A.x; -+ A.x; A.x; A.x; A.x; A.x; A.x; -+ A.x; A.x; A.x; A.x; A.x; A.x; -+ A.x; A.x; A.x; A.x; A.x; A.x; -+ else: -+ B -+ -+ self.assertEqual( -+ get_line_branches(with_extended_args), -+ [(1,2,8)]) -+ - if check_impl_detail(cpython=True) and ctypes is not None: - py = ctypes.pythonapi - freefunc = ctypes.CFUNCTYPE(None,ctypes.c_voidp) -diff --git a/Lib/test/test_code_module.py b/Lib/test/test_code_module.py -index 37c7bc772ed..20b960ce8d1 100644 ---- a/Lib/test/test_code_module.py -+++ b/Lib/test/test_code_module.py -@@ -5,9 +5,9 @@ - from textwrap import dedent - from contextlib import ExitStack - from unittest import mock -+from test.support import force_not_colorized_test_class - from test.support import import_helper - -- - code = import_helper.import_module('code') - - -@@ -30,6 +30,7 @@ - del self.sysmod.ps2 - - -+@force_not_colorized_test_class - class TestInteractiveConsole(unittest.TestCase, MockSys): - maxDiff = None - -diff --git a/Lib/test/test_codeop.py b/Lib/test/test_codeop.py -index 787bd1b6a79..0eefc22d11b 100644 ---- a/Lib/test/test_codeop.py -+++ b/Lib/test/test_codeop.py -@@ -282,7 +282,7 @@ - # Test that the warning is only returned once. - with warnings_helper.check_warnings( - ('"is" with \'str\' literal', SyntaxWarning), -- ("invalid escape sequence", SyntaxWarning), -+ ('"\\\\e" is an invalid escape sequence', SyntaxWarning), - ) as w: - compile_command(r"'\e' is 0") - self.assertEqual(len(w.warnings), 2) -diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py -index a24d3e3ea14..1e93530398b 100644 ---- a/Lib/test/test_collections.py -+++ b/Lib/test/test_collections.py -@@ -742,11 +742,11 @@ - C = type('C', (object,), {'__hash__': None}) - setattr(C, name, stub) - self.assertIsInstance(C(), abc) -- self.assertTrue(issubclass(C, abc)) -+ self.assertIsSubclass(C, abc) - - C = type('C', (object,), {'__hash__': None}) - self.assertNotIsInstance(C(), abc) -- self.assertFalse(issubclass(C, abc)) -+ self.assertNotIsSubclass(C, abc) - - def validate_comparison(self, instance): - ops = ['lt', 'gt', 'le', 'ge', 'ne', 'or', 'and', 'xor', 'sub'] -@@ -812,12 +812,12 @@ - non_samples = [None, int(), gen(), object()] - for x in non_samples: - self.assertNotIsInstance(x, Awaitable) -- self.assertFalse(issubclass(type(x), Awaitable), repr(type(x))) -+ self.assertNotIsSubclass(type(x), Awaitable) - - samples = [Bar(), MinimalCoro()] - for x in samples: - self.assertIsInstance(x, Awaitable) -- self.assertTrue(issubclass(type(x), Awaitable)) -+ self.assertIsSubclass(type(x), Awaitable) - - c = coro() - # Iterable coroutines (generators with CO_ITERABLE_COROUTINE -@@ -831,8 +831,8 @@ - - class CoroLike: pass - Coroutine.register(CoroLike) -- self.assertTrue(isinstance(CoroLike(), Awaitable)) -- self.assertTrue(issubclass(CoroLike, Awaitable)) -+ self.assertIsInstance(CoroLike(), Awaitable) -+ self.assertIsSubclass(CoroLike, Awaitable) - CoroLike = None - support.gc_collect() # Kill CoroLike to clean-up ABCMeta cache - -@@ -864,12 +864,12 @@ - non_samples = [None, int(), gen(), object(), Bar()] - for x in non_samples: - self.assertNotIsInstance(x, Coroutine) -- self.assertFalse(issubclass(type(x), Coroutine), repr(type(x))) -+ self.assertNotIsSubclass(type(x), Coroutine) - - samples = [MinimalCoro()] - for x in samples: - self.assertIsInstance(x, Awaitable) -- self.assertTrue(issubclass(type(x), Awaitable)) -+ self.assertIsSubclass(type(x), Awaitable) - - c = coro() - # Iterable coroutines (generators with CO_ITERABLE_COROUTINE -@@ -890,8 +890,8 @@ - pass - def __await__(self): - pass -- self.assertTrue(isinstance(CoroLike(), Coroutine)) -- self.assertTrue(issubclass(CoroLike, Coroutine)) -+ self.assertIsInstance(CoroLike(), Coroutine) -+ self.assertIsSubclass(CoroLike, Coroutine) - - class CoroLike: - def send(self, value): -@@ -900,15 +900,15 @@ - pass - def __await__(self): - pass -- self.assertFalse(isinstance(CoroLike(), Coroutine)) -- self.assertFalse(issubclass(CoroLike, Coroutine)) -+ self.assertNotIsInstance(CoroLike(), Coroutine) -+ self.assertNotIsSubclass(CoroLike, Coroutine) - - def test_Hashable(self): - # Check some non-hashables - non_samples = [bytearray(), list(), set(), dict()] - for x in non_samples: - self.assertNotIsInstance(x, Hashable) -- self.assertFalse(issubclass(type(x), Hashable), repr(type(x))) -+ self.assertNotIsSubclass(type(x), Hashable) - # Check some hashables - samples = [None, - int(), float(), complex(), -@@ -918,14 +918,14 @@ - ] - for x in samples: - self.assertIsInstance(x, Hashable) -- self.assertTrue(issubclass(type(x), Hashable), repr(type(x))) -+ self.assertIsSubclass(type(x), Hashable) - self.assertRaises(TypeError, Hashable) - # Check direct subclassing - class H(Hashable): - def __hash__(self): - return super().__hash__() - self.assertEqual(hash(H()), 0) -- self.assertFalse(issubclass(int, H)) -+ self.assertNotIsSubclass(int, H) - self.validate_abstract_methods(Hashable, '__hash__') - self.validate_isinstance(Hashable, '__hash__') - -@@ -933,13 +933,13 @@ - class AI: - def __aiter__(self): - return self -- self.assertTrue(isinstance(AI(), AsyncIterable)) -- self.assertTrue(issubclass(AI, AsyncIterable)) -+ self.assertIsInstance(AI(), AsyncIterable) -+ self.assertIsSubclass(AI, AsyncIterable) - # Check some non-iterables - non_samples = [None, object, []] - for x in non_samples: - self.assertNotIsInstance(x, AsyncIterable) -- self.assertFalse(issubclass(type(x), AsyncIterable), repr(type(x))) -+ self.assertNotIsSubclass(type(x), AsyncIterable) - self.validate_abstract_methods(AsyncIterable, '__aiter__') - self.validate_isinstance(AsyncIterable, '__aiter__') - -@@ -949,13 +949,13 @@ - return self - async def __anext__(self): - raise StopAsyncIteration -- self.assertTrue(isinstance(AI(), AsyncIterator)) -- self.assertTrue(issubclass(AI, AsyncIterator)) -+ self.assertIsInstance(AI(), AsyncIterator) -+ self.assertIsSubclass(AI, AsyncIterator) - non_samples = [None, object, []] - # Check some non-iterables - for x in non_samples: - self.assertNotIsInstance(x, AsyncIterator) -- self.assertFalse(issubclass(type(x), AsyncIterator), repr(type(x))) -+ self.assertNotIsSubclass(type(x), AsyncIterator) - # Similarly to regular iterators (see issue 10565) - class AnextOnly: - async def __anext__(self): -@@ -968,7 +968,7 @@ - non_samples = [None, 42, 3.14, 1j] - for x in non_samples: - self.assertNotIsInstance(x, Iterable) -- self.assertFalse(issubclass(type(x), Iterable), repr(type(x))) -+ self.assertNotIsSubclass(type(x), Iterable) - # Check some iterables - samples = [bytes(), str(), - tuple(), list(), set(), frozenset(), dict(), -@@ -978,13 +978,13 @@ - ] - for x in samples: - self.assertIsInstance(x, Iterable) -- self.assertTrue(issubclass(type(x), Iterable), repr(type(x))) -+ self.assertIsSubclass(type(x), Iterable) - # Check direct subclassing - class I(Iterable): - def __iter__(self): - return super().__iter__() - self.assertEqual(list(I()), []) -- self.assertFalse(issubclass(str, I)) -+ self.assertNotIsSubclass(str, I) - self.validate_abstract_methods(Iterable, '__iter__') - self.validate_isinstance(Iterable, '__iter__') - # Check None blocking -@@ -992,22 +992,22 @@ - def __iter__(self): return iter([]) - class ItBlocked(It): - __iter__ = None -- self.assertTrue(issubclass(It, Iterable)) -- self.assertTrue(isinstance(It(), Iterable)) -- self.assertFalse(issubclass(ItBlocked, Iterable)) -- self.assertFalse(isinstance(ItBlocked(), Iterable)) -+ self.assertIsSubclass(It, Iterable) -+ self.assertIsInstance(It(), Iterable) -+ self.assertNotIsSubclass(ItBlocked, Iterable) -+ self.assertNotIsInstance(ItBlocked(), Iterable) - - def test_Reversible(self): - # Check some non-reversibles - non_samples = [None, 42, 3.14, 1j, set(), frozenset()] - for x in non_samples: - self.assertNotIsInstance(x, Reversible) -- self.assertFalse(issubclass(type(x), Reversible), repr(type(x))) -+ self.assertNotIsSubclass(type(x), Reversible) - # Check some non-reversible iterables - non_reversibles = [_test_gen(), (x for x in []), iter([]), reversed([])] - for x in non_reversibles: - self.assertNotIsInstance(x, Reversible) -- self.assertFalse(issubclass(type(x), Reversible), repr(type(x))) -+ self.assertNotIsSubclass(type(x), Reversible) - # Check some reversible iterables - samples = [bytes(), str(), tuple(), list(), OrderedDict(), - OrderedDict().keys(), OrderedDict().items(), -@@ -1016,11 +1016,11 @@ - dict().keys(), dict().items(), dict().values()] - for x in samples: - self.assertIsInstance(x, Reversible) -- self.assertTrue(issubclass(type(x), Reversible), repr(type(x))) -+ self.assertIsSubclass(type(x), Reversible) - # Check also Mapping, MutableMapping, and Sequence -- self.assertTrue(issubclass(Sequence, Reversible), repr(Sequence)) -- self.assertFalse(issubclass(Mapping, Reversible), repr(Mapping)) -- self.assertFalse(issubclass(MutableMapping, Reversible), repr(MutableMapping)) -+ self.assertIsSubclass(Sequence, Reversible) -+ self.assertNotIsSubclass(Mapping, Reversible) -+ self.assertNotIsSubclass(MutableMapping, Reversible) - # Check direct subclassing - class R(Reversible): - def __iter__(self): -@@ -1028,17 +1028,17 @@ - def __reversed__(self): - return iter(list()) - self.assertEqual(list(reversed(R())), []) -- self.assertFalse(issubclass(float, R)) -+ self.assertNotIsSubclass(float, R) - self.validate_abstract_methods(Reversible, '__reversed__', '__iter__') - # Check reversible non-iterable (which is not Reversible) - class RevNoIter: - def __reversed__(self): return reversed([]) - class RevPlusIter(RevNoIter): - def __iter__(self): return iter([]) -- self.assertFalse(issubclass(RevNoIter, Reversible)) -- self.assertFalse(isinstance(RevNoIter(), Reversible)) -- self.assertTrue(issubclass(RevPlusIter, Reversible)) -- self.assertTrue(isinstance(RevPlusIter(), Reversible)) -+ self.assertNotIsSubclass(RevNoIter, Reversible) -+ self.assertNotIsInstance(RevNoIter(), Reversible) -+ self.assertIsSubclass(RevPlusIter, Reversible) -+ self.assertIsInstance(RevPlusIter(), Reversible) - # Check None blocking - class Rev: - def __iter__(self): return iter([]) -@@ -1047,39 +1047,38 @@ - __iter__ = None - class RevRevBlocked(Rev): - __reversed__ = None -- self.assertTrue(issubclass(Rev, Reversible)) -- self.assertTrue(isinstance(Rev(), Reversible)) -- self.assertFalse(issubclass(RevItBlocked, Reversible)) -- self.assertFalse(isinstance(RevItBlocked(), Reversible)) -- self.assertFalse(issubclass(RevRevBlocked, Reversible)) -- self.assertFalse(isinstance(RevRevBlocked(), Reversible)) -+ self.assertIsSubclass(Rev, Reversible) -+ self.assertIsInstance(Rev(), Reversible) -+ self.assertNotIsSubclass(RevItBlocked, Reversible) -+ self.assertNotIsInstance(RevItBlocked(), Reversible) -+ self.assertNotIsSubclass(RevRevBlocked, Reversible) -+ self.assertNotIsInstance(RevRevBlocked(), Reversible) - - def test_Collection(self): - # Check some non-collections - non_collections = [None, 42, 3.14, 1j, lambda x: 2*x] - for x in non_collections: - self.assertNotIsInstance(x, Collection) -- self.assertFalse(issubclass(type(x), Collection), repr(type(x))) -+ self.assertNotIsSubclass(type(x), Collection) - # Check some non-collection iterables - non_col_iterables = [_test_gen(), iter(b''), iter(bytearray()), - (x for x in [])] - for x in non_col_iterables: - self.assertNotIsInstance(x, Collection) -- self.assertFalse(issubclass(type(x), Collection), repr(type(x))) -+ self.assertNotIsSubclass(type(x), Collection) - # Check some collections - samples = [set(), frozenset(), dict(), bytes(), str(), tuple(), - list(), dict().keys(), dict().items(), dict().values()] - for x in samples: - self.assertIsInstance(x, Collection) -- self.assertTrue(issubclass(type(x), Collection), repr(type(x))) -+ self.assertIsSubclass(type(x), Collection) - # Check also Mapping, MutableMapping, etc. -- self.assertTrue(issubclass(Sequence, Collection), repr(Sequence)) -- self.assertTrue(issubclass(Mapping, Collection), repr(Mapping)) -- self.assertTrue(issubclass(MutableMapping, Collection), -- repr(MutableMapping)) -- self.assertTrue(issubclass(Set, Collection), repr(Set)) -- self.assertTrue(issubclass(MutableSet, Collection), repr(MutableSet)) -- self.assertTrue(issubclass(Sequence, Collection), repr(MutableSet)) -+ self.assertIsSubclass(Sequence, Collection) -+ self.assertIsSubclass(Mapping, Collection) -+ self.assertIsSubclass(MutableMapping, Collection) -+ self.assertIsSubclass(Set, Collection) -+ self.assertIsSubclass(MutableSet, Collection) -+ self.assertIsSubclass(Sequence, Collection) - # Check direct subclassing - class Col(Collection): - def __iter__(self): -@@ -1090,13 +1089,13 @@ - return False - class DerCol(Col): pass - self.assertEqual(list(iter(Col())), []) -- self.assertFalse(issubclass(list, Col)) -- self.assertFalse(issubclass(set, Col)) -- self.assertFalse(issubclass(float, Col)) -+ self.assertNotIsSubclass(list, Col) -+ self.assertNotIsSubclass(set, Col) -+ self.assertNotIsSubclass(float, Col) - self.assertEqual(list(iter(DerCol())), []) -- self.assertFalse(issubclass(list, DerCol)) -- self.assertFalse(issubclass(set, DerCol)) -- self.assertFalse(issubclass(float, DerCol)) -+ self.assertNotIsSubclass(list, DerCol) -+ self.assertNotIsSubclass(set, DerCol) -+ self.assertNotIsSubclass(float, DerCol) - self.validate_abstract_methods(Collection, '__len__', '__iter__', - '__contains__') - # Check sized container non-iterable (which is not Collection) etc. -@@ -1109,12 +1108,12 @@ - class ColNoCont: - def __iter__(self): return iter([]) - def __len__(self): return 0 -- self.assertFalse(issubclass(ColNoIter, Collection)) -- self.assertFalse(isinstance(ColNoIter(), Collection)) -- self.assertFalse(issubclass(ColNoSize, Collection)) -- self.assertFalse(isinstance(ColNoSize(), Collection)) -- self.assertFalse(issubclass(ColNoCont, Collection)) -- self.assertFalse(isinstance(ColNoCont(), Collection)) -+ self.assertNotIsSubclass(ColNoIter, Collection) -+ self.assertNotIsInstance(ColNoIter(), Collection) -+ self.assertNotIsSubclass(ColNoSize, Collection) -+ self.assertNotIsInstance(ColNoSize(), Collection) -+ self.assertNotIsSubclass(ColNoCont, Collection) -+ self.assertNotIsInstance(ColNoCont(), Collection) - # Check None blocking - class SizeBlock: - def __iter__(self): return iter([]) -@@ -1124,10 +1123,10 @@ - def __len__(self): return 0 - def __contains__(self): return True - __iter__ = None -- self.assertFalse(issubclass(SizeBlock, Collection)) -- self.assertFalse(isinstance(SizeBlock(), Collection)) -- self.assertFalse(issubclass(IterBlock, Collection)) -- self.assertFalse(isinstance(IterBlock(), Collection)) -+ self.assertNotIsSubclass(SizeBlock, Collection) -+ self.assertNotIsInstance(SizeBlock(), Collection) -+ self.assertNotIsSubclass(IterBlock, Collection) -+ self.assertNotIsInstance(IterBlock(), Collection) - # Check None blocking in subclass - class ColImpl: - def __iter__(self): -@@ -1138,15 +1137,15 @@ - return False - class NonCol(ColImpl): - __contains__ = None -- self.assertFalse(issubclass(NonCol, Collection)) -- self.assertFalse(isinstance(NonCol(), Collection)) -+ self.assertNotIsSubclass(NonCol, Collection) -+ self.assertNotIsInstance(NonCol(), Collection) - - - def test_Iterator(self): - non_samples = [None, 42, 3.14, 1j, b"", "", (), [], {}, set()] - for x in non_samples: - self.assertNotIsInstance(x, Iterator) -- self.assertFalse(issubclass(type(x), Iterator), repr(type(x))) -+ self.assertNotIsSubclass(type(x), Iterator) - samples = [iter(bytes()), iter(str()), - iter(tuple()), iter(list()), iter(dict()), - iter(set()), iter(frozenset()), -@@ -1157,7 +1156,7 @@ - ] - for x in samples: - self.assertIsInstance(x, Iterator) -- self.assertTrue(issubclass(type(x), Iterator), repr(type(x))) -+ self.assertIsSubclass(type(x), Iterator) - self.validate_abstract_methods(Iterator, '__next__', '__iter__') - - # Issue 10565 -@@ -1190,7 +1189,7 @@ - iter(()), iter([]), NonGen1(), NonGen2(), NonGen3()] - for x in non_samples: - self.assertNotIsInstance(x, Generator) -- self.assertFalse(issubclass(type(x), Generator), repr(type(x))) -+ self.assertNotIsSubclass(type(x), Generator) - - class Gen: - def __iter__(self): return self -@@ -1212,7 +1211,7 @@ - for x in samples: - self.assertIsInstance(x, Iterator) - self.assertIsInstance(x, Generator) -- self.assertTrue(issubclass(type(x), Generator), repr(type(x))) -+ self.assertIsSubclass(type(x), Generator) - self.validate_abstract_methods(Generator, 'send', 'throw') - - # mixin tests -@@ -1261,7 +1260,7 @@ - iter(()), iter([]), NonAGen1(), NonAGen2(), NonAGen3()] - for x in non_samples: - self.assertNotIsInstance(x, AsyncGenerator) -- self.assertFalse(issubclass(type(x), AsyncGenerator), repr(type(x))) -+ self.assertNotIsSubclass(type(x), AsyncGenerator) - - class Gen: - def __aiter__(self): return self -@@ -1283,7 +1282,7 @@ - for x in samples: - self.assertIsInstance(x, AsyncIterator) - self.assertIsInstance(x, AsyncGenerator) -- self.assertTrue(issubclass(type(x), AsyncGenerator), repr(type(x))) -+ self.assertIsSubclass(type(x), AsyncGenerator) - self.validate_abstract_methods(AsyncGenerator, 'asend', 'athrow') - - def run_async(coro): -@@ -1326,14 +1325,14 @@ - ] - for x in non_samples: - self.assertNotIsInstance(x, Sized) -- self.assertFalse(issubclass(type(x), Sized), repr(type(x))) -+ self.assertNotIsSubclass(type(x), Sized) - samples = [bytes(), str(), - tuple(), list(), set(), frozenset(), dict(), - dict().keys(), dict().items(), dict().values(), - ] - for x in samples: - self.assertIsInstance(x, Sized) -- self.assertTrue(issubclass(type(x), Sized), repr(type(x))) -+ self.assertIsSubclass(type(x), Sized) - self.validate_abstract_methods(Sized, '__len__') - self.validate_isinstance(Sized, '__len__') - -@@ -1344,14 +1343,14 @@ - ] - for x in non_samples: - self.assertNotIsInstance(x, Container) -- self.assertFalse(issubclass(type(x), Container), repr(type(x))) -+ self.assertNotIsSubclass(type(x), Container) - samples = [bytes(), str(), - tuple(), list(), set(), frozenset(), dict(), - dict().keys(), dict().items(), - ] - for x in samples: - self.assertIsInstance(x, Container) -- self.assertTrue(issubclass(type(x), Container), repr(type(x))) -+ self.assertIsSubclass(type(x), Container) - self.validate_abstract_methods(Container, '__contains__') - self.validate_isinstance(Container, '__contains__') - -@@ -1363,7 +1362,7 @@ - ] - for x in non_samples: - self.assertNotIsInstance(x, Callable) -- self.assertFalse(issubclass(type(x), Callable), repr(type(x))) -+ self.assertNotIsSubclass(type(x), Callable) - samples = [lambda: None, - type, int, object, - len, -@@ -1371,7 +1370,7 @@ - ] - for x in samples: - self.assertIsInstance(x, Callable) -- self.assertTrue(issubclass(type(x), Callable), repr(type(x))) -+ self.assertIsSubclass(type(x), Callable) - self.validate_abstract_methods(Callable, '__call__') - self.validate_isinstance(Callable, '__call__') - -@@ -1379,16 +1378,16 @@ - for B in Hashable, Iterable, Iterator, Reversible, Sized, Container, Callable: - class C(B): - pass -- self.assertTrue(issubclass(C, B)) -- self.assertFalse(issubclass(int, C)) -+ self.assertIsSubclass(C, B) -+ self.assertNotIsSubclass(int, C) - - def test_registration(self): - for B in Hashable, Iterable, Iterator, Reversible, Sized, Container, Callable: - class C: - __hash__ = None # Make sure it isn't hashable by default -- self.assertFalse(issubclass(C, B), B.__name__) -+ self.assertNotIsSubclass(C, B) - B.register(C) -- self.assertTrue(issubclass(C, B)) -+ self.assertIsSubclass(C, B) - - class WithSet(MutableSet): - -@@ -1419,7 +1418,7 @@ - def test_Set(self): - for sample in [set, frozenset]: - self.assertIsInstance(sample(), Set) -- self.assertTrue(issubclass(sample, Set)) -+ self.assertIsSubclass(sample, Set) - self.validate_abstract_methods(Set, '__contains__', '__iter__', '__len__') - class MySet(Set): - def __contains__(self, x): -@@ -1500,9 +1499,9 @@ - - def test_MutableSet(self): - self.assertIsInstance(set(), MutableSet) -- self.assertTrue(issubclass(set, MutableSet)) -+ self.assertIsSubclass(set, MutableSet) - self.assertNotIsInstance(frozenset(), MutableSet) -- self.assertFalse(issubclass(frozenset, MutableSet)) -+ self.assertNotIsSubclass(frozenset, MutableSet) - self.validate_abstract_methods(MutableSet, '__contains__', '__iter__', '__len__', - 'add', 'discard') - -@@ -1841,7 +1840,7 @@ - def test_Mapping(self): - for sample in [dict]: - self.assertIsInstance(sample(), Mapping) -- self.assertTrue(issubclass(sample, Mapping)) -+ self.assertIsSubclass(sample, Mapping) - self.validate_abstract_methods(Mapping, '__contains__', '__iter__', '__len__', - '__getitem__') - class MyMapping(Mapping): -@@ -1857,7 +1856,7 @@ - def test_MutableMapping(self): - for sample in [dict]: - self.assertIsInstance(sample(), MutableMapping) -- self.assertTrue(issubclass(sample, MutableMapping)) -+ self.assertIsSubclass(sample, MutableMapping) - self.validate_abstract_methods(MutableMapping, '__contains__', '__iter__', '__len__', - '__getitem__', '__setitem__', '__delitem__') - -@@ -1891,12 +1890,12 @@ - def test_Sequence(self): - for sample in [tuple, list, bytes, str]: - self.assertIsInstance(sample(), Sequence) -- self.assertTrue(issubclass(sample, Sequence)) -+ self.assertIsSubclass(sample, Sequence) - self.assertIsInstance(range(10), Sequence) -- self.assertTrue(issubclass(range, Sequence)) -+ self.assertIsSubclass(range, Sequence) - self.assertIsInstance(memoryview(b""), Sequence) -- self.assertTrue(issubclass(memoryview, Sequence)) -- self.assertTrue(issubclass(str, Sequence)) -+ self.assertIsSubclass(memoryview, Sequence) -+ self.assertIsSubclass(str, Sequence) - self.validate_abstract_methods(Sequence, '__contains__', '__iter__', '__len__', - '__getitem__') - -@@ -1938,21 +1937,21 @@ - def test_Buffer(self): - for sample in [bytes, bytearray, memoryview]: - self.assertIsInstance(sample(b"x"), Buffer) -- self.assertTrue(issubclass(sample, Buffer)) -+ self.assertIsSubclass(sample, Buffer) - for sample in [str, list, tuple]: - self.assertNotIsInstance(sample(), Buffer) -- self.assertFalse(issubclass(sample, Buffer)) -+ self.assertNotIsSubclass(sample, Buffer) - self.validate_abstract_methods(Buffer, '__buffer__') - - def test_MutableSequence(self): - for sample in [tuple, str, bytes]: - self.assertNotIsInstance(sample(), MutableSequence) -- self.assertFalse(issubclass(sample, MutableSequence)) -+ self.assertNotIsSubclass(sample, MutableSequence) - for sample in [list, bytearray, deque]: - self.assertIsInstance(sample(), MutableSequence) -- self.assertTrue(issubclass(sample, MutableSequence)) -- self.assertTrue(issubclass(array.array, MutableSequence)) -- self.assertFalse(issubclass(str, MutableSequence)) -+ self.assertIsSubclass(sample, MutableSequence) -+ self.assertIsSubclass(array.array, MutableSequence) -+ self.assertNotIsSubclass(str, MutableSequence) - self.validate_abstract_methods(MutableSequence, '__contains__', '__iter__', - '__len__', '__getitem__', '__setitem__', '__delitem__', 'insert') - -@@ -2043,8 +2042,8 @@ - self.assertEqual(c, Counter(a=3, b=2, c=1)) - self.assertIsInstance(c, dict) - self.assertIsInstance(c, Mapping) -- self.assertTrue(issubclass(Counter, dict)) -- self.assertTrue(issubclass(Counter, Mapping)) -+ self.assertIsSubclass(Counter, dict) -+ self.assertIsSubclass(Counter, Mapping) - self.assertEqual(len(c), 3) - self.assertEqual(sum(c.values()), 6) - self.assertEqual(list(c.values()), [3, 2, 1]) -diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py -index b5cf2ad18fe..6c3de2091c4 100644 ---- a/Lib/test/test_compile.py -+++ b/Lib/test/test_compile.py -@@ -1410,7 +1410,7 @@ - check_op_count(load, "BINARY_SLICE", 3) - check_op_count(load, "BUILD_SLICE", 0) - check_consts(load, slice, [slice(None, None, None)]) -- check_op_count(load, "BINARY_SUBSCR", 1) -+ check_op_count(load, "BINARY_OP", 4) - - def store(): - x[a:b] = y -@@ -1429,7 +1429,7 @@ - check_op_count(long_slice, "BUILD_SLICE", 1) - check_op_count(long_slice, "BINARY_SLICE", 0) - check_consts(long_slice, slice, []) -- check_op_count(long_slice, "BINARY_SUBSCR", 1) -+ check_op_count(long_slice, "BINARY_OP", 1) - - def aug(): - x[a:b] += y -@@ -1437,7 +1437,7 @@ - check_op_count(aug, "BINARY_SLICE", 1) - check_op_count(aug, "STORE_SLICE", 1) - check_op_count(aug, "BUILD_SLICE", 0) -- check_op_count(aug, "BINARY_SUBSCR", 0) -+ check_op_count(aug, "BINARY_OP", 1) - check_op_count(aug, "STORE_SUBSCR", 0) - check_consts(aug, slice, []) - -@@ -1446,7 +1446,7 @@ - - check_op_count(aug_const, "BINARY_SLICE", 0) - check_op_count(aug_const, "STORE_SLICE", 0) -- check_op_count(aug_const, "BINARY_SUBSCR", 1) -+ check_op_count(aug_const, "BINARY_OP", 2) - check_op_count(aug_const, "STORE_SUBSCR", 1) - check_consts(aug_const, slice, [slice(1, 2)]) - -@@ -2050,16 +2050,16 @@ - snippet = "a - b @ (c * x['key'] + 23)" - - compiled_code, _ = self.check_positions_against_ast(snippet) -- self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_SUBSCR', -+ self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP', - line=1, end_line=1, column=13, end_column=21) - self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP', -- line=1, end_line=1, column=9, end_column=21, occurrence=1) -+ line=1, end_line=1, column=9, end_column=21, occurrence=2) - self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP', -- line=1, end_line=1, column=9, end_column=26, occurrence=2) -+ line=1, end_line=1, column=9, end_column=26, occurrence=3) - self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP', -- line=1, end_line=1, column=4, end_column=27, occurrence=3) -+ line=1, end_line=1, column=4, end_column=27, occurrence=4) - self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP', -- line=1, end_line=1, column=0, end_column=27, occurrence=4) -+ line=1, end_line=1, column=0, end_column=27, occurrence=5) - - def test_multiline_assert_rewritten_as_method_call(self): - # GH-94694: Don't crash if pytest rewrites a multiline assert as a -diff --git a/Lib/test/test_compileall.py b/Lib/test/test_compileall.py -index 3a34c6822bc..a580a240d9f 100644 ---- a/Lib/test/test_compileall.py -+++ b/Lib/test/test_compileall.py -@@ -766,6 +766,7 @@ - rc, out, err = self.assertRunNotOK('-q', '-d', 'dinsdale', self.pkgdir) - self.assertRegex(out, b'File "dinsdale') - -+ @support.force_not_colorized - def test_d_runtime_error(self): - bazfn = script_helper.make_script(self.pkgdir, 'baz', 'raise Exception') - self.assertRunOK('-q', '-d', 'dinsdale', self.pkgdir) -diff --git a/Lib/test/test_compiler_codegen.py b/Lib/test/test_compiler_codegen.py -index 2dd7cf65ee3..cf5e2d901db 100644 ---- a/Lib/test/test_compiler_codegen.py -+++ b/Lib/test/test_compiler_codegen.py -@@ -59,7 +59,7 @@ - ('JUMP', loop_lbl), - exit_lbl, - ('END_FOR', None), -- ('POP_TOP', None), -+ ('POP_ITER', None), - ('LOAD_CONST', 0), - ('RETURN_VALUE', None), - ] -diff --git a/Lib/test/test_concurrent_futures/test_interpreter_pool.py b/Lib/test/test_concurrent_futures/test_interpreter_pool.py -index ea1512fc830..93eec08bfe1 100644 ---- a/Lib/test/test_concurrent_futures/test_interpreter_pool.py -+++ b/Lib/test/test_concurrent_futures/test_interpreter_pool.py -@@ -311,7 +311,7 @@ - # tests left a policy in place, just in case. - policy = support.maybe_get_event_loop_policy() - assert policy is None, policy -- cls.addClassCleanup(lambda: asyncio.set_event_loop_policy(None)) -+ cls.addClassCleanup(lambda: asyncio._set_event_loop_policy(None)) - - def setUp(self): - super().setUp() -diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py -index e3c5d08dd1e..bde805eb741 100644 ---- a/Lib/test/test_configparser.py -+++ b/Lib/test/test_configparser.py -@@ -2174,6 +2174,15 @@ - with self.assertRaises(configparser.UnnamedSectionDisabledError): - configparser.ConfigParser().add_section(configparser.UNNAMED_SECTION) - -+ def test_multiple_configs(self): -+ cfg = configparser.ConfigParser(allow_unnamed_section=True) -+ cfg.read_string('a = 1') -+ cfg.read_string('b = 2') -+ -+ self.assertEqual([configparser.UNNAMED_SECTION], cfg.sections()) -+ self.assertEqual('1', cfg[configparser.UNNAMED_SECTION]['a']) -+ self.assertEqual('2', cfg[configparser.UNNAMED_SECTION]['b']) -+ - - class MiscTestCase(unittest.TestCase): - def test__all__(self): -diff --git a/Lib/test/test_contextlib_async.py b/Lib/test/test_contextlib_async.py -index ca7315783b9..7750186e56a 100644 ---- a/Lib/test/test_contextlib_async.py -+++ b/Lib/test/test_contextlib_async.py -@@ -1,21 +1,27 @@ --import asyncio -+import functools - from contextlib import ( - asynccontextmanager, AbstractAsyncContextManager, - AsyncExitStack, nullcontext, aclosing, contextmanager) - from test import support -+from test.support import run_no_yield_async_fn as _run_async_fn - import unittest - import traceback - - from test.test_contextlib import TestBaseExitStack - --support.requires_working_socket(module=True) - --def tearDownModule(): -- asyncio.set_event_loop_policy(None) -+def _async_test(async_fn): -+ """Decorator to turn an async function into a synchronous function""" -+ @functools.wraps(async_fn) -+ def wrapper(*args, **kwargs): -+ return _run_async_fn(async_fn, *args, **kwargs) - -+ return wrapper - --class TestAbstractAsyncContextManager(unittest.IsolatedAsyncioTestCase): - -+class TestAbstractAsyncContextManager(unittest.TestCase): -+ -+ @_async_test - async def test_enter(self): - class DefaultEnter(AbstractAsyncContextManager): - async def __aexit__(self, *args): -@@ -27,6 +33,7 @@ - async with manager as context: - self.assertIs(manager, context) - -+ @_async_test - async def test_slots(self): - class DefaultAsyncContextManager(AbstractAsyncContextManager): - __slots__ = () -@@ -38,6 +45,7 @@ - manager = DefaultAsyncContextManager() - manager.var = 42 - -+ @_async_test - async def test_async_gen_propagates_generator_exit(self): - # A regression test for https://bugs.python.org/issue33786. - -@@ -88,8 +96,9 @@ - self.assertFalse(issubclass(NoneAexit, AbstractAsyncContextManager)) - - --class AsyncContextManagerTestCase(unittest.IsolatedAsyncioTestCase): -+class AsyncContextManagerTestCase(unittest.TestCase): - -+ @_async_test - async def test_contextmanager_plain(self): - state = [] - @asynccontextmanager -@@ -103,6 +112,7 @@ - state.append(x) - self.assertEqual(state, [1, 42, 999]) - -+ @_async_test - async def test_contextmanager_finally(self): - state = [] - @asynccontextmanager -@@ -120,6 +130,7 @@ - raise ZeroDivisionError() - self.assertEqual(state, [1, 42, 999]) - -+ @_async_test - async def test_contextmanager_traceback(self): - @asynccontextmanager - async def f(): -@@ -175,6 +186,7 @@ - self.assertEqual(frames[0].name, 'test_contextmanager_traceback') - self.assertEqual(frames[0].line, 'raise stop_exc') - -+ @_async_test - async def test_contextmanager_no_reraise(self): - @asynccontextmanager - async def whee(): -@@ -184,6 +196,7 @@ - # Calling __aexit__ should not result in an exception - self.assertFalse(await ctx.__aexit__(TypeError, TypeError("foo"), None)) - -+ @_async_test - async def test_contextmanager_trap_yield_after_throw(self): - @asynccontextmanager - async def whoo(): -@@ -199,6 +212,7 @@ - # The "gen" attribute is an implementation detail. - self.assertFalse(ctx.gen.ag_suspended) - -+ @_async_test - async def test_contextmanager_trap_no_yield(self): - @asynccontextmanager - async def whoo(): -@@ -208,6 +222,7 @@ - with self.assertRaises(RuntimeError): - await ctx.__aenter__() - -+ @_async_test - async def test_contextmanager_trap_second_yield(self): - @asynccontextmanager - async def whoo(): -@@ -221,6 +236,7 @@ - # The "gen" attribute is an implementation detail. - self.assertFalse(ctx.gen.ag_suspended) - -+ @_async_test - async def test_contextmanager_non_normalised(self): - @asynccontextmanager - async def whoo(): -@@ -234,6 +250,7 @@ - with self.assertRaises(SyntaxError): - await ctx.__aexit__(RuntimeError, None, None) - -+ @_async_test - async def test_contextmanager_except(self): - state = [] - @asynccontextmanager -@@ -251,6 +268,7 @@ - raise ZeroDivisionError(999) - self.assertEqual(state, [1, 42, 999]) - -+ @_async_test - async def test_contextmanager_except_stopiter(self): - @asynccontextmanager - async def woohoo(): -@@ -277,6 +295,7 @@ - else: - self.fail(f'{stop_exc} was suppressed') - -+ @_async_test - async def test_contextmanager_wrap_runtimeerror(self): - @asynccontextmanager - async def woohoo(): -@@ -321,12 +340,14 @@ - self.assertEqual(baz.__doc__, "Whee!") - - @support.requires_docstrings -+ @_async_test - async def test_instance_docstring_given_cm_docstring(self): - baz = self._create_contextmanager_attribs()(None) - self.assertEqual(baz.__doc__, "Whee!") - async with baz: - pass # suppress warning - -+ @_async_test - async def test_keywords(self): - # Ensure no keyword arguments are inhibited - @asynccontextmanager -@@ -335,6 +356,7 @@ - async with woohoo(self=11, func=22, args=33, kwds=44) as target: - self.assertEqual(target, (11, 22, 33, 44)) - -+ @_async_test - async def test_recursive(self): - depth = 0 - ncols = 0 -@@ -361,6 +383,7 @@ - self.assertEqual(ncols, 10) - self.assertEqual(depth, 0) - -+ @_async_test - async def test_decorator(self): - entered = False - -@@ -379,6 +402,7 @@ - await test() - self.assertFalse(entered) - -+ @_async_test - async def test_decorator_with_exception(self): - entered = False - -@@ -401,6 +425,7 @@ - await test() - self.assertFalse(entered) - -+ @_async_test - async def test_decorating_method(self): - - @asynccontextmanager -@@ -435,7 +460,7 @@ - self.assertEqual(test.b, 2) - - --class AclosingTestCase(unittest.IsolatedAsyncioTestCase): -+class AclosingTestCase(unittest.TestCase): - - @support.requires_docstrings - def test_instance_docs(self): -@@ -443,6 +468,7 @@ - obj = aclosing(None) - self.assertEqual(obj.__doc__, cm_docstring) - -+ @_async_test - async def test_aclosing(self): - state = [] - class C: -@@ -454,6 +480,7 @@ - self.assertEqual(x, y) - self.assertEqual(state, [1]) - -+ @_async_test - async def test_aclosing_error(self): - state = [] - class C: -@@ -467,6 +494,7 @@ - 1 / 0 - self.assertEqual(state, [1]) - -+ @_async_test - async def test_aclosing_bpo41229(self): - state = [] - -@@ -492,45 +520,27 @@ - self.assertEqual(state, [1]) - - --class TestAsyncExitStack(TestBaseExitStack, unittest.IsolatedAsyncioTestCase): -+class TestAsyncExitStack(TestBaseExitStack, unittest.TestCase): - class SyncAsyncExitStack(AsyncExitStack): -- @staticmethod -- def run_coroutine(coro): -- loop = asyncio.get_event_loop_policy().get_event_loop() -- t = loop.create_task(coro) -- t.add_done_callback(lambda f: loop.stop()) -- loop.run_forever() -- -- exc = t.exception() -- if not exc: -- return t.result() -- else: -- context = exc.__context__ -- -- try: -- raise exc -- except: -- exc.__context__ = context -- raise exc - - def close(self): -- return self.run_coroutine(self.aclose()) -+ return _run_async_fn(self.aclose) - - def __enter__(self): -- return self.run_coroutine(self.__aenter__()) -+ return _run_async_fn(self.__aenter__) - - def __exit__(self, *exc_details): -- return self.run_coroutine(self.__aexit__(*exc_details)) -+ return _run_async_fn(self.__aexit__, *exc_details) - - exit_stack = SyncAsyncExitStack - callback_error_internal_frames = [ -- ('__exit__', 'return self.run_coroutine(self.__aexit__(*exc_details))'), -- ('run_coroutine', 'raise exc'), -- ('run_coroutine', 'raise exc'), -+ ('__exit__', 'return _run_async_fn(self.__aexit__, *exc_details)'), -+ ('run_no_yield_async_fn', 'coro.send(None)'), - ('__aexit__', 'raise exc'), - ('__aexit__', 'cb_suppress = cb(*exc_details)'), - ] - -+ @_async_test - async def test_async_callback(self): - expected = [ - ((), {}), -@@ -573,6 +583,7 @@ - stack.push_async_callback(callback=_exit, arg=3) - self.assertEqual(result, []) - -+ @_async_test - async def test_async_push(self): - exc_raised = ZeroDivisionError - async def _expect_exc(exc_type, exc, exc_tb): -@@ -608,6 +619,7 @@ - self.assertIs(stack._exit_callbacks[-1][1], _expect_exc) - 1/0 - -+ @_async_test - async def test_enter_async_context(self): - class TestCM(object): - async def __aenter__(self): -@@ -629,6 +641,7 @@ - - self.assertEqual(result, [1, 2, 3, 4]) - -+ @_async_test - async def test_enter_async_context_errors(self): - class LacksEnterAndExit: - pass -@@ -648,6 +661,7 @@ - await stack.enter_async_context(LacksExit()) - self.assertFalse(stack._exit_callbacks) - -+ @_async_test - async def test_async_exit_exception_chaining(self): - # Ensure exception chaining matches the reference behaviour - async def raise_exc(exc): -@@ -679,6 +693,7 @@ - self.assertIsInstance(inner_exc, ValueError) - self.assertIsInstance(inner_exc.__context__, ZeroDivisionError) - -+ @_async_test - async def test_async_exit_exception_explicit_none_context(self): - # Ensure AsyncExitStack chaining matches actual nested `with` statements - # regarding explicit __context__ = None. -@@ -713,6 +728,7 @@ - else: - self.fail("Expected IndexError, but no exception was raised") - -+ @_async_test - async def test_instance_bypass_async(self): - class Example(object): pass - cm = Example() -@@ -725,7 +741,8 @@ - self.assertIs(stack._exit_callbacks[-1][1], cm) - - --class TestAsyncNullcontext(unittest.IsolatedAsyncioTestCase): -+class TestAsyncNullcontext(unittest.TestCase): -+ @_async_test - async def test_async_nullcontext(self): - class C: - pass -diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py -index e6d65e7d90a..ae3cd355500 100644 ---- a/Lib/test/test_coroutines.py -+++ b/Lib/test/test_coroutines.py -@@ -735,7 +735,7 @@ - - def test_func_12(self): - async def g(): -- i = me.send(None) -+ me.send(None) - await foo - me = g() - with self.assertRaisesRegex(ValueError, -@@ -2136,8 +2136,10 @@ - coro = None - support.gc_collect() - -+ self.assertEqual(cm.unraisable.err_msg, -+ f"Exception ignored while finalizing " -+ f"coroutine {coro_repr}") - self.assertIn("was never awaited", str(cm.unraisable.exc_value)) -- self.assertEqual(repr(cm.unraisable.object), coro_repr) - - def test_for_assign_raising_stop_async_iteration(self): - class BadTarget: -@@ -2281,20 +2283,20 @@ - buffer.append(exc_type.__name__) - - async def f(): -- async with CM() as c: -+ async with CM(): - await asyncio.sleep(0.01) - raise MyException - buffer.append('unreachable') - - loop = asyncio.new_event_loop() -- asyncio.set_event_loop(loop) -+ asyncio._set_event_loop(loop) - try: - loop.run_until_complete(f()) - except MyException: - pass - finally: - loop.close() -- asyncio.set_event_loop_policy(None) -+ asyncio._set_event_loop_policy(None) - - self.assertEqual(buffer, [1, 2, 'MyException']) - -@@ -2373,7 +2375,7 @@ - - orig_depth = sys.get_coroutine_origin_tracking_depth() - try: -- msg = check(0, f"coroutine '{corofn.__qualname__}' was never awaited") -+ check(0, f"coroutine '{corofn.__qualname__}' was never awaited") - check(1, "".join([ - f"coroutine '{corofn.__qualname__}' was never awaited\n", - "Coroutine created at (most recent call last)\n", -@@ -2414,7 +2416,9 @@ - del coro - support.gc_collect() - -- self.assertEqual(repr(cm.unraisable.object), coro_repr) -+ self.assertEqual(cm.unraisable.err_msg, -+ f"Exception ignored while finalizing " -+ f"coroutine {coro_repr}") - self.assertEqual(cm.unraisable.exc_type, ZeroDivisionError) - - del warnings._warn_unawaited_coroutine -diff --git a/Lib/test/test_ctypes/test_arrays.py b/Lib/test/test_ctypes/test_arrays.py -index c80fdff5de6..7f1f6cf5840 100644 ---- a/Lib/test/test_ctypes/test_arrays.py -+++ b/Lib/test/test_ctypes/test_arrays.py -@@ -5,7 +5,7 @@ - create_string_buffer, create_unicode_buffer, - c_char, c_wchar, c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint, - c_long, c_ulonglong, c_float, c_double, c_longdouble) --from test.support import bigmemtest, _2G -+from test.support import bigmemtest, _2G, threading_helper, Py_GIL_DISABLED - from ._support import (_CData, PyCArrayType, Py_TPFLAGS_DISALLOW_INSTANTIATION, - Py_TPFLAGS_IMMUTABLETYPE) - -@@ -267,6 +267,26 @@ - def test_large_array(self, size): - c_char * size - -+ @threading_helper.requires_working_threading() -+ @unittest.skipUnless(Py_GIL_DISABLED, "only meaningful if the GIL is disabled") -+ def test_thread_safety(self): -+ from threading import Thread -+ -+ buffer = (ctypes.c_char_p * 10)() -+ -+ def run(): -+ for i in range(100): -+ buffer.value = b"hello" -+ buffer[0] = b"j" -+ -+ with threading_helper.catch_threading_exception() as cm: -+ threads = (Thread(target=run) for _ in range(25)) -+ with threading_helper.start_threads(threads): -+ pass -+ -+ if cm.exc_value: -+ raise cm.exc_value -+ - - if __name__ == '__main__': - unittest.main() -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 eb77d6d7782..b446fd5c77d 100644 ---- a/Lib/test/test_ctypes/test_c_simple_type_meta.py -+++ b/Lib/test/test_ctypes/test_c_simple_type_meta.py -@@ -1,4 +1,5 @@ - import unittest -+from test.support import MS_WINDOWS - import ctypes - from ctypes import POINTER, c_void_p - -@@ -54,9 +55,9 @@ - pass - - self.assertIsInstance(POINTER(Sub2), p_meta) -- self.assertTrue(issubclass(POINTER(Sub2), Sub2)) -- self.assertTrue(issubclass(POINTER(Sub2), POINTER(Sub))) -- self.assertTrue(issubclass(POINTER(Sub), POINTER(CtBase))) -+ self.assertIsSubclass(POINTER(Sub2), Sub2) -+ self.assertIsSubclass(POINTER(Sub2), POINTER(Sub)) -+ self.assertIsSubclass(POINTER(Sub), POINTER(CtBase)) - - def test_creating_pointer_in_dunder_new_2(self): - # A simpler variant of the above, used in `CoClass` of the `comtypes` -@@ -84,7 +85,7 @@ - pass - - self.assertIsInstance(POINTER(Sub), p_meta) -- self.assertTrue(issubclass(POINTER(Sub), Sub)) -+ self.assertIsSubclass(POINTER(Sub), Sub) - - def test_creating_pointer_in_dunder_init_1(self): - class ct_meta(type): -@@ -120,9 +121,9 @@ - pass - - self.assertIsInstance(POINTER(Sub2), p_meta) -- self.assertTrue(issubclass(POINTER(Sub2), Sub2)) -- self.assertTrue(issubclass(POINTER(Sub2), POINTER(Sub))) -- self.assertTrue(issubclass(POINTER(Sub), POINTER(CtBase))) -+ self.assertIsSubclass(POINTER(Sub2), Sub2) -+ self.assertIsSubclass(POINTER(Sub2), POINTER(Sub)) -+ self.assertIsSubclass(POINTER(Sub), POINTER(CtBase)) - - def test_creating_pointer_in_dunder_init_2(self): - class ct_meta(type): -@@ -149,4 +150,21 @@ - pass - - self.assertIsInstance(POINTER(Sub), p_meta) -- self.assertTrue(issubclass(POINTER(Sub), Sub)) -+ self.assertIsSubclass(POINTER(Sub), Sub) -+ -+ def test_bad_type_message(self): -+ """Verify the error message that lists all available type codes""" -+ # (The string is generated at runtime, so this checks the underlying -+ # set of types as well as correct construction of the string.) -+ with self.assertRaises(AttributeError) as cm: -+ class F(metaclass=PyCSimpleType): -+ _type_ = "\0" -+ message = str(cm.exception) -+ expected_type_chars = list('cbBhHiIlLdCEFfuzZqQPXOv?g') -+ if not hasattr(ctypes, 'c_float_complex'): -+ expected_type_chars.remove('C') -+ expected_type_chars.remove('E') -+ expected_type_chars.remove('F') -+ if not MS_WINDOWS: -+ expected_type_chars.remove('X') -+ self.assertIn("'" + ''.join(expected_type_chars) + "'", message) -diff --git a/Lib/test/test_ctypes/test_callbacks.py b/Lib/test/test_ctypes/test_callbacks.py -index 8f483dfe1db..6c7c2e52707 100644 ---- a/Lib/test/test_ctypes/test_callbacks.py -+++ b/Lib/test/test_ctypes/test_callbacks.py -@@ -324,7 +324,7 @@ - - self.assertIsInstance(cm.unraisable.exc_value, TypeError) - self.assertEqual(cm.unraisable.err_msg, -- f"Exception ignored on converting result " -+ f"Exception ignored while converting result " - f"of ctypes callback function {func!r}") - self.assertIsNone(cm.unraisable.object) - -diff --git a/Lib/test/test_ctypes/test_cfuncs.py b/Lib/test/test_ctypes/test_cfuncs.py -index 48330c4b0a7..e0c124607cb 100644 ---- a/Lib/test/test_ctypes/test_cfuncs.py -+++ b/Lib/test/test_ctypes/test_cfuncs.py -@@ -5,7 +5,8 @@ - c_short, c_ushort, c_int, c_uint, - c_long, c_ulong, c_longlong, c_ulonglong, - c_float, c_double, c_longdouble) --from test.support import import_helper -+from test import support -+from test.support import import_helper, threading_helper - _ctypes_test = import_helper.import_module("_ctypes_test") - - -@@ -191,6 +192,23 @@ - self.assertEqual(self._dll.tv_i(-42), None) - self.assertEqual(self.S(), -42) - -+ @threading_helper.requires_working_threading() -+ @support.requires_resource("cpu") -+ @unittest.skipUnless(support.Py_GIL_DISABLED, "only meaningful on free-threading") -+ def test_thread_safety(self): -+ from threading import Thread -+ -+ def concurrent(): -+ for _ in range(100): -+ self._dll.tf_b.restype = c_byte -+ self._dll.tf_b.argtypes = (c_byte,) -+ -+ with threading_helper.catch_threading_exception() as exc: -+ with threading_helper.start_threads((Thread(target=concurrent) for _ in range(10))): -+ pass -+ -+ self.assertIsNone(exc.exc_value) -+ - - # The following repeats the above tests with stdcall functions (where - # they are available) -diff --git a/Lib/test/test_ctypes/test_dlerror.py b/Lib/test/test_ctypes/test_dlerror.py -index 4441e30cd7a..1c1b2aab3d5 100644 ---- a/Lib/test/test_ctypes/test_dlerror.py -+++ b/Lib/test/test_ctypes/test_dlerror.py -@@ -1,7 +1,12 @@ -+import _ctypes - import os -+import platform - import sys -+import test.support - import unittest --import platform -+from ctypes import CDLL, c_int -+from ctypes.util import find_library -+ - - FOO_C = r""" - #include -@@ -26,7 +31,7 @@ - - - @unittest.skipUnless(sys.platform.startswith('linux'), -- 'Test only valid for Linux') -+ 'test requires GNU IFUNC support') - class TestNullDlsym(unittest.TestCase): - """GH-126554: Ensure that we catch NULL dlsym return values - -@@ -53,19 +58,14 @@ - import subprocess - import tempfile - -- # To avoid ImportErrors on Windows, where _ctypes does not have -- # dlopen and dlsym, -- # import here, i.e., inside the test function. -- # The skipUnless('linux') decorator ensures that we're on linux -- # if we're executing these statements. -- from ctypes import CDLL, c_int -- from _ctypes import dlopen, dlsym -- -- retcode = subprocess.call(["gcc", "--version"], -- stdout=subprocess.DEVNULL, -- stderr=subprocess.DEVNULL) -- if retcode != 0: -+ try: -+ retcode = subprocess.call(["gcc", "--version"], -+ stdout=subprocess.DEVNULL, -+ stderr=subprocess.DEVNULL) -+ except OSError: - self.skipTest("gcc is missing") -+ if retcode != 0: -+ self.skipTest("gcc --version failed") - - pipe_r, pipe_w = os.pipe() - self.addCleanup(os.close, pipe_r) -@@ -111,6 +111,8 @@ - self.assertEqual(os.read(pipe_r, 2), b'OK') - - # Case #3: Test 'py_dl_sym' from Modules/_ctypes/callproc.c -+ dlopen = test.support.get_attribute(_ctypes, 'dlopen') -+ dlsym = test.support.get_attribute(_ctypes, 'dlsym') - L = dlopen(dstname) - with self.assertRaisesRegex(OSError, "symbol 'foo' not found"): - dlsym(L, "foo") -@@ -119,5 +121,59 @@ - self.assertEqual(os.read(pipe_r, 2), b'OK') - - -+@unittest.skipUnless(os.name != 'nt', 'test requires dlerror() calls') -+class TestLocalization(unittest.TestCase): -+ -+ @staticmethod -+ def configure_locales(func): -+ return test.support.run_with_locale( -+ 'LC_ALL', -+ 'fr_FR.iso88591', 'ja_JP.sjis', 'zh_CN.gbk', -+ 'fr_FR.utf8', 'en_US.utf8', -+ '', -+ )(func) -+ -+ @classmethod -+ def setUpClass(cls): -+ cls.libc_filename = find_library("c") -+ if cls.libc_filename is None: -+ raise unittest.SkipTest('cannot find libc') -+ -+ @configure_locales -+ def test_localized_error_from_dll(self): -+ dll = CDLL(self.libc_filename) -+ with self.assertRaises(AttributeError): -+ dll.this_name_does_not_exist -+ -+ @configure_locales -+ def test_localized_error_in_dll(self): -+ dll = CDLL(self.libc_filename) -+ with self.assertRaises(ValueError): -+ c_int.in_dll(dll, 'this_name_does_not_exist') -+ -+ @unittest.skipUnless(hasattr(_ctypes, 'dlopen'), -+ 'test requires _ctypes.dlopen()') -+ @configure_locales -+ def test_localized_error_dlopen(self): -+ missing_filename = b'missing\xff.so' -+ # Depending whether the locale, we may encode '\xff' differently -+ # but we are only interested in avoiding a UnicodeDecodeError -+ # when reporting the dlerror() error message which contains -+ # the localized filename. -+ filename_pattern = r'missing.*?\.so' -+ with self.assertRaisesRegex(OSError, filename_pattern): -+ _ctypes.dlopen(missing_filename, 2) -+ -+ @unittest.skipUnless(hasattr(_ctypes, 'dlopen'), -+ 'test requires _ctypes.dlopen()') -+ @unittest.skipUnless(hasattr(_ctypes, 'dlsym'), -+ 'test requires _ctypes.dlsym()') -+ @configure_locales -+ def test_localized_error_dlsym(self): -+ dll = _ctypes.dlopen(self.libc_filename) -+ with self.assertRaises(OSError): -+ _ctypes.dlsym(dll, 'this_name_does_not_exist') -+ -+ - if __name__ == "__main__": - unittest.main() ---- /dev/null -+++ b/Lib/test/test_ctypes/test_dllist.py -@@ -0,0 +1,59 @@ -+import os -+import sys -+import unittest -+from ctypes import CDLL -+import ctypes.util -+from test.support import import_helper -+ -+ -+WINDOWS = os.name == "nt" -+APPLE = sys.platform in {"darwin", "ios", "tvos", "watchos"} -+ -+if WINDOWS: -+ KNOWN_LIBRARIES = ["KERNEL32.DLL"] -+elif APPLE: -+ KNOWN_LIBRARIES = ["libSystem.B.dylib"] -+else: -+ # trickier than it seems, because libc may not be present -+ # on musl systems, and sometimes goes by different names. -+ # However, ctypes itself loads libffi -+ KNOWN_LIBRARIES = ["libc.so", "libffi.so"] -+ -+ -+@unittest.skipUnless( -+ hasattr(ctypes.util, "dllist"), -+ "ctypes.util.dllist is not available on this platform", -+) -+class ListSharedLibraries(unittest.TestCase): -+ -+ def test_lists_system(self): -+ dlls = ctypes.util.dllist() -+ -+ self.assertGreater(len(dlls), 0, f"loaded={dlls}") -+ self.assertTrue( -+ any(lib in dll for dll in dlls for lib in KNOWN_LIBRARIES), f"loaded={dlls}" -+ ) -+ -+ def test_lists_updates(self): -+ dlls = ctypes.util.dllist() -+ -+ # this test relies on being able to import a library which is -+ # not already loaded. -+ # If it is (e.g. by a previous test in the same process), we skip -+ if any("_ctypes_test" in dll for dll in dlls): -+ self.skipTest("Test library is already loaded") -+ -+ _ctypes_test = import_helper.import_module("_ctypes_test") -+ test_module = CDLL(_ctypes_test.__file__) -+ dlls2 = ctypes.util.dllist() -+ self.assertIsNotNone(dlls2) -+ -+ dlls1 = set(dlls) -+ dlls2 = set(dlls2) -+ -+ self.assertGreater(dlls2, dlls1, f"newly loaded libraries: {dlls2 - dlls1}") -+ self.assertTrue(any("_ctypes_test" in dll for dll in dlls2), f"loaded={dlls2}") -+ -+ -+if __name__ == "__main__": -+ unittest.main() -diff --git a/Lib/test/test_ctypes/test_generated_structs.py b/Lib/test/test_ctypes/test_generated_structs.py -index d61754d6d49..1df9f0dc163 100644 ---- a/Lib/test/test_ctypes/test_generated_structs.py -+++ b/Lib/test/test_ctypes/test_generated_structs.py -@@ -443,7 +443,7 @@ - - None - - reason to skip the test (str) - -- This does depend on the C compiler keeping padding bits zero. -+ This does depend on the C compiler keeping padding bits unchanged. - Common compilers seem to do so. - """ - for name, cls in TESTCASES.items(): -@@ -696,7 +696,8 @@ - output(' ' + line) - typename = f'{struct_or_union(cls)} {name}' - output(f""" -- {typename} value = {{0}}; -+ {typename} value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString({c_str_repr(name)})); - APPEND(PyLong_FromLong(sizeof({typename}))); - APPEND(PyLong_FromLong(_Alignof({typename}))); -diff --git a/Lib/test/test_ctypes/test_loading.py b/Lib/test/test_ctypes/test_loading.py -index fc1eecb77e1..13ed813ad98 100644 ---- a/Lib/test/test_ctypes/test_loading.py -+++ b/Lib/test/test_ctypes/test_loading.py -@@ -135,7 +135,7 @@ - 'test specific to Windows') - def test_load_hasattr(self): - # bpo-34816: shouldn't raise OSError -- self.assertFalse(hasattr(ctypes.windll, 'test')) -+ self.assertNotHasAttr(ctypes.windll, 'test') - - @unittest.skipUnless(os.name == "nt", - 'test specific to Windows') -diff --git a/Lib/test/test_ctypes/test_memfunctions.py b/Lib/test/test_ctypes/test_memfunctions.py -index 112b27ba48e..32548761813 100644 ---- a/Lib/test/test_ctypes/test_memfunctions.py -+++ b/Lib/test/test_ctypes/test_memfunctions.py -@@ -5,7 +5,9 @@ - create_string_buffer, string_at, - create_unicode_buffer, wstring_at, - memmove, memset, -- c_char_p, c_byte, c_ubyte, c_wchar) -+ memoryview_at, c_void_p, -+ c_char_p, c_byte, c_ubyte, c_wchar, -+ addressof, byref) - - - class MemFunctionsTest(unittest.TestCase): -@@ -77,6 +79,62 @@ - self.assertEqual(wstring_at(a, 16), "Hello, World\0\0\0\0") - self.assertEqual(wstring_at(a, 0), "") - -+ def test_memoryview_at(self): -+ b = (c_byte * 10)() -+ -+ size = len(b) -+ for foreign_ptr in ( -+ b, -+ cast(b, c_void_p), -+ byref(b), -+ addressof(b), -+ ): -+ with self.subTest(foreign_ptr=type(foreign_ptr).__name__): -+ b[:] = b"initialval" -+ v = memoryview_at(foreign_ptr, size) -+ self.assertIsInstance(v, memoryview) -+ self.assertEqual(bytes(v), b"initialval") -+ -+ # test that writes to source buffer get reflected in memoryview -+ b[:] = b"0123456789" -+ self.assertEqual(bytes(v), b"0123456789") -+ -+ # test that writes to memoryview get reflected in source buffer -+ v[:] = b"9876543210" -+ self.assertEqual(bytes(b), b"9876543210") -+ -+ with self.assertRaises(ValueError): -+ memoryview_at(foreign_ptr, -1) -+ -+ with self.assertRaises(ValueError): -+ memoryview_at(foreign_ptr, sys.maxsize + 1) -+ -+ v0 = memoryview_at(foreign_ptr, 0) -+ self.assertEqual(bytes(v0), b'') -+ -+ def test_memoryview_at_readonly(self): -+ b = (c_byte * 10)() -+ -+ size = len(b) -+ for foreign_ptr in ( -+ b, -+ cast(b, c_void_p), -+ byref(b), -+ addressof(b), -+ ): -+ with self.subTest(foreign_ptr=type(foreign_ptr).__name__): -+ b[:] = b"initialval" -+ v = memoryview_at(foreign_ptr, size, readonly=True) -+ self.assertIsInstance(v, memoryview) -+ self.assertEqual(bytes(v), b"initialval") -+ -+ # test that writes to source buffer get reflected in memoryview -+ b[:] = b"0123456789" -+ self.assertEqual(bytes(v), b"0123456789") -+ -+ # test that writes to the memoryview are blocked -+ with self.assertRaises(TypeError): -+ v[:] = b"9876543210" - - if __name__ == "__main__": - unittest.main() -diff --git a/Lib/test/test_ctypes/test_random_things.py b/Lib/test/test_ctypes/test_random_things.py -index 630f6ed9489..73ff57d925e 100644 ---- a/Lib/test/test_ctypes/test_random_things.py -+++ b/Lib/test/test_ctypes/test_random_things.py -@@ -51,7 +51,7 @@ - if exc_msg is not None: - self.assertEqual(str(cm.unraisable.exc_value), exc_msg) - self.assertEqual(cm.unraisable.err_msg, -- f"Exception ignored on calling ctypes " -+ f"Exception ignored while calling ctypes " - f"callback function {callback_func!r}") - self.assertIsNone(cm.unraisable.object) - -diff --git a/Lib/test/test_ctypes/test_repr.py b/Lib/test/test_ctypes/test_repr.py -index e7587984a92..8c85e6cbe70 100644 ---- a/Lib/test/test_ctypes/test_repr.py -+++ b/Lib/test/test_ctypes/test_repr.py -@@ -22,12 +22,12 @@ - def test_numbers(self): - for typ in subclasses: - base = typ.__bases__[0] -- self.assertTrue(repr(base(42)).startswith(base.__name__)) -- self.assertEqual(" - - - - -diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py -index c719f571152..27350120d66 100644 ---- a/Lib/test/test_dis.py -+++ b/Lib/test/test_dis.py -@@ -15,7 +15,7 @@ - import unittest - from test.support import (captured_stdout, requires_debug_ranges, - requires_specialization, cpython_only, -- os_helper) -+ os_helper, import_helper, reset_code) - from test.support.bytecode_helper import BytecodeTestCase - - -@@ -181,7 +181,7 @@ - %3d JUMP_BACKWARD 5 (to L1) - - %3d L2: END_FOR -- POP_TOP -+ POP_ITER - LOAD_CONST 0 (None) - RETURN_VALUE - """ % (bug708901.__code__.co_firstlineno, -@@ -438,7 +438,7 @@ - LOAD_SMALL_INT 1 - BINARY_OP 13 (+=) - STORE_NAME 0 (x) -- JUMP_BACKWARD 8 (to L1) -+ JUMP_BACKWARD 12 (to L1) - """ - - dis_traceback = """\ -@@ -458,7 +458,8 @@ - - %4d LOAD_GLOBAL 0 (Exception) - CHECK_EXC_MATCH -- POP_JUMP_IF_FALSE 23 (to L7) -+ POP_JUMP_IF_FALSE 24 (to L7) -+ NOT_TAKEN - STORE_FAST 0 (e) - - %4d L4: LOAD_FAST 0 (e) -@@ -555,7 +556,8 @@ - %4d L3: PUSH_EXC_INFO - WITH_EXCEPT_START - TO_BOOL -- POP_JUMP_IF_TRUE 1 (to L4) -+ POP_JUMP_IF_TRUE 2 (to L4) -+ NOT_TAKEN - RERAISE 2 - L4: POP_TOP - L5: POP_EXCEPT -@@ -645,10 +647,11 @@ - L20: CLEANUP_THROW - L21: END_SEND - TO_BOOL -- POP_JUMP_IF_TRUE 1 (to L22) -- RERAISE 2 -- L22: POP_TOP -- L23: POP_EXCEPT -+ POP_JUMP_IF_TRUE 2 (to L24) -+ L22: NOT_TAKEN -+ L23: RERAISE 2 -+ L24: POP_TOP -+ L25: POP_EXCEPT - POP_TOP - POP_TOP - POP_TOP -@@ -658,24 +661,25 @@ - LOAD_CONST 0 (None) - RETURN_VALUE - -- -- L24: COPY 3 -+ -- L26: COPY 3 - POP_EXCEPT - RERAISE 1 -- L25: CALL_INTRINSIC_1 3 (INTRINSIC_STOPITERATION_ERROR) -+ L27: CALL_INTRINSIC_1 3 (INTRINSIC_STOPITERATION_ERROR) - RERAISE 1 - ExceptionTable: -- L1 to L3 -> L25 [0] lasti -+ L1 to L3 -> L27 [0] lasti - L3 to L4 -> L12 [4] -- L4 to L6 -> L25 [0] lasti -+ L4 to L6 -> L27 [0] lasti - L6 to L7 -> L16 [2] lasti -- L7 to L9 -> L25 [0] lasti -+ L7 to L9 -> L27 [0] lasti - L9 to L10 -> L14 [2] -- L10 to L13 -> L25 [0] lasti -- L14 to L15 -> L25 [0] lasti -- L16 to L18 -> L24 [4] lasti -+ L10 to L13 -> L27 [0] lasti -+ L14 to L15 -> L27 [0] lasti -+ L16 to L18 -> L26 [4] lasti - L18 to L19 -> L20 [7] -- L19 to L23 -> L24 [4] lasti -- L23 to L25 -> L25 [0] lasti -+ L19 to L22 -> L26 [4] lasti -+ L23 to L25 -> L26 [4] lasti -+ L25 to L27 -> L27 [0] lasti - """ % (_asyncwith.__code__.co_firstlineno, - _asyncwith.__code__.co_firstlineno + 1, - _asyncwith.__code__.co_firstlineno + 2, -@@ -839,7 +843,7 @@ - L1: RESUME 0 - LOAD_FAST 0 (.0) - GET_ITER -- L2: FOR_ITER 10 (to L3) -+ L2: FOR_ITER 14 (to L3) - STORE_FAST 1 (z) - LOAD_DEREF 2 (x) - LOAD_FAST 1 (z) -@@ -847,9 +851,9 @@ - YIELD_VALUE 0 - RESUME 5 - POP_TOP -- JUMP_BACKWARD 12 (to L2) -+ JUMP_BACKWARD 16 (to L2) - L3: END_FOR -- POP_TOP -+ POP_ITER - LOAD_CONST 0 (None) - RETURN_VALUE - -@@ -888,7 +892,7 @@ - %3d RESUME_CHECK 0 - - %3d BUILD_LIST 0 -- LOAD_CONST 0 ((1, 2, 3)) -+ LOAD_CONST_MORTAL 1 ((1, 2, 3)) - LIST_EXTEND 1 - LOAD_SMALL_INT 3 - BINARY_OP 5 (*) -@@ -900,11 +904,11 @@ - LOAD_FAST 0 (i) - CALL_PY_GENERAL 1 - POP_TOP -- JUMP_BACKWARD 16 (to L1) -+ JUMP_BACKWARD_{: <6} 16 (to L1) - - %3d L2: END_FOR -- POP_TOP -- LOAD_CONST_IMMORTAL 1 (None) -+ POP_ITER -+ LOAD_CONST_IMMORTAL 0 (None) - RETURN_VALUE - """ % (loop_test.__code__.co_firstlineno, - loop_test.__code__.co_firstlineno + 1, -@@ -927,8 +931,6 @@ - """% (extended_arg_quick.__code__.co_firstlineno, - extended_arg_quick.__code__.co_firstlineno + 1,) - --ADAPTIVE_WARMUP_DELAY = 2 -- - class DisTestBase(unittest.TestCase): - "Common utilities for DisTests and TestDisTraceback" - -@@ -995,12 +997,14 @@ - def test_widths(self): - long_opcodes = set(['JUMP_BACKWARD_NO_INTERRUPT', - 'INSTRUMENTED_CALL_FUNCTION_EX']) -- for opcode, opname in enumerate(dis.opname): -+ for op, opname in enumerate(dis.opname): - if opname in long_opcodes or opname.startswith("INSTRUMENTED"): - continue -+ if opname in opcode._specialized_opmap: -+ continue - with self.subTest(opname=opname): - width = dis._OPNAME_WIDTH -- if opcode in dis.hasarg: -+ if op in dis.hasarg: - width += 1 + dis._OPARG_WIDTH - self.assertLessEqual(len(opname), width) - -@@ -1253,8 +1257,9 @@ - self.assertIsNone(e.__context__) - - @staticmethod -- def code_quicken(f, times=ADAPTIVE_WARMUP_DELAY): -- for _ in range(times): -+ def code_quicken(f): -+ _testinternalcapi = import_helper.import_module("_testinternalcapi") -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - f() - - @cpython_only -@@ -1300,16 +1305,18 @@ - @requires_specialization - def test_loop_quicken(self): - # Loop can trigger a quicken where the loop is located -- self.code_quicken(loop_test, 4) -+ self.code_quicken(loop_test) - got = self.get_disassembly(loop_test, adaptive=True) -- expected = dis_loop_test_quickened_code -+ jit = import_helper.import_module("_testinternalcapi").jit_enabled() -+ expected = dis_loop_test_quickened_code.format("JIT" if jit else "NO_JIT") - self.do_disassembly_compare(got, expected) - - @cpython_only - @requires_specialization - def test_loop_with_conditional_at_end_is_quickened(self): -+ _testinternalcapi = import_helper.import_module("_testinternalcapi") - def for_loop_true(x): -- for i in range(10): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - if x: - pass - -@@ -1318,7 +1325,7 @@ - self.get_disassembly(for_loop_true, adaptive=True)) - - def for_loop_false(x): -- for i in range(10): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - if x: - pass - -@@ -1328,7 +1335,7 @@ - - def while_loop(): - i = 0 -- while i < 10: -+ while i < _testinternalcapi.SPECIALIZATION_THRESHOLD: - i += 1 - - while_loop() -@@ -1349,7 +1356,7 @@ - self.code_quicken(f) - else: - # "copy" the code to un-quicken it: -- f.__code__ = f.__code__.replace() -+ reset_code(f) - for instruction in _unroll_caches_as_Instructions(dis.get_instructions( - f, show_caches=True, adaptive=adaptive - ), show_caches=True): -@@ -1699,204 +1706,211 @@ - Instruction = dis.Instruction - - expected_opinfo_outer = [ -- Instruction(opname='MAKE_CELL', opcode=92, arg=0, argval='a', argrepr='a', offset=0, start_offset=0, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), -- Instruction(opname='MAKE_CELL', opcode=92, arg=1, argval='b', argrepr='b', offset=2, start_offset=2, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), -+ Instruction(opname='MAKE_CELL', opcode=93, arg=0, argval='a', argrepr='a', offset=0, start_offset=0, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), -+ Instruction(opname='MAKE_CELL', opcode=93, arg=1, argval='b', argrepr='b', offset=2, start_offset=2, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), - Instruction(opname='RESUME', opcode=149, arg=0, argval=0, argrepr='', offset=4, start_offset=4, starts_line=True, line_number=1, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_CONST', opcode=79, arg=3, argval=(3, 4), argrepr='(3, 4)', offset=6, start_offset=6, starts_line=True, line_number=2, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_FAST', opcode=81, arg=0, argval='a', argrepr='a', offset=8, start_offset=8, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_FAST', opcode=81, arg=1, argval='b', argrepr='b', offset=10, start_offset=10, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), -- Instruction(opname='BUILD_TUPLE', opcode=48, arg=2, argval=2, argrepr='', offset=12, start_offset=12, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_CONST', opcode=79, arg=0, argval=code_object_f, argrepr=repr(code_object_f), offset=14, start_offset=14, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_CONST', opcode=80, arg=3, argval=(3, 4), argrepr='(3, 4)', offset=6, start_offset=6, starts_line=True, line_number=2, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_FAST', opcode=82, arg=0, argval='a', argrepr='a', offset=8, start_offset=8, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_FAST', opcode=82, arg=1, argval='b', argrepr='b', offset=10, start_offset=10, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), -+ Instruction(opname='BUILD_TUPLE', opcode=50, arg=2, argval=2, argrepr='', offset=12, start_offset=12, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_CONST', opcode=80, arg=0, argval=code_object_f, argrepr=repr(code_object_f), offset=14, start_offset=14, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), - Instruction(opname='MAKE_FUNCTION', opcode=23, arg=None, argval=None, argrepr='', offset=16, start_offset=16, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), -- Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=103, arg=8, argval=8, argrepr='closure', offset=18, start_offset=18, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), -- Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=103, arg=1, argval=1, argrepr='defaults', offset=20, start_offset=20, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), -- Instruction(opname='STORE_FAST', opcode=107, arg=2, argval='f', argrepr='f', offset=22, start_offset=22, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_GLOBAL', opcode=87, arg=1, argval='print', argrepr='print + NULL', offset=24, start_offset=24, starts_line=True, line_number=7, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), -- Instruction(opname='LOAD_DEREF', opcode=80, arg=0, argval='a', argrepr='a', offset=34, start_offset=34, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_DEREF', opcode=80, arg=1, argval='b', argrepr='b', offset=36, start_offset=36, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_CONST', opcode=79, arg=1, argval='', argrepr="''", offset=38, start_offset=38, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_SMALL_INT', opcode=89, arg=1, argval=1, argrepr='', offset=40, start_offset=40, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), -- Instruction(opname='BUILD_LIST', opcode=43, arg=0, argval=0, argrepr='', offset=42, start_offset=42, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), -- Instruction(opname='BUILD_MAP', opcode=44, arg=0, argval=0, argrepr='', offset=44, start_offset=44, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_CONST', opcode=79, arg=2, argval='Hello world!', argrepr="'Hello world!'", offset=46, start_offset=46, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), -- Instruction(opname='CALL', opcode=49, arg=7, argval=7, argrepr='', offset=48, start_offset=48, starts_line=False, line_number=7, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=56, start_offset=56, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_FAST', opcode=81, arg=2, argval='f', argrepr='f', offset=58, start_offset=58, starts_line=True, line_number=8, label=None, positions=None, cache_info=None), -- Instruction(opname='RETURN_VALUE', opcode=33, arg=None, argval=None, argrepr='', offset=60, start_offset=60, starts_line=False, line_number=8, label=None, positions=None, cache_info=None), -+ Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=104, arg=8, argval=8, argrepr='closure', offset=18, start_offset=18, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), -+ Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=104, arg=1, argval=1, argrepr='defaults', offset=20, start_offset=20, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), -+ Instruction(opname='STORE_FAST', opcode=108, arg=2, argval='f', argrepr='f', offset=22, start_offset=22, starts_line=False, line_number=2, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_GLOBAL', opcode=88, arg=1, argval='print', argrepr='print + NULL', offset=24, start_offset=24, starts_line=True, line_number=7, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), -+ Instruction(opname='LOAD_DEREF', opcode=81, arg=0, argval='a', argrepr='a', offset=34, start_offset=34, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_DEREF', opcode=81, arg=1, argval='b', argrepr='b', offset=36, start_offset=36, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_CONST', opcode=80, arg=1, argval='', argrepr="''", offset=38, start_offset=38, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_SMALL_INT', opcode=90, arg=1, argval=1, argrepr='', offset=40, start_offset=40, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), -+ Instruction(opname='BUILD_LIST', opcode=45, arg=0, argval=0, argrepr='', offset=42, start_offset=42, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), -+ Instruction(opname='BUILD_MAP', opcode=46, arg=0, argval=0, argrepr='', offset=44, start_offset=44, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_CONST', opcode=80, arg=2, argval='Hello world!', argrepr="'Hello world!'", offset=46, start_offset=46, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), -+ Instruction(opname='CALL', opcode=51, arg=7, argval=7, argrepr='', offset=48, start_offset=48, starts_line=False, line_number=7, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -+ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=56, start_offset=56, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_FAST', opcode=82, arg=2, argval='f', argrepr='f', offset=58, start_offset=58, starts_line=True, line_number=8, label=None, positions=None, cache_info=None), -+ Instruction(opname='RETURN_VALUE', opcode=35, arg=None, argval=None, argrepr='', offset=60, start_offset=60, starts_line=False, line_number=8, label=None, positions=None, cache_info=None), - ] - - expected_opinfo_f = [ -- Instruction(opname='COPY_FREE_VARS', opcode=58, arg=2, argval=2, argrepr='', offset=0, start_offset=0, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), -- Instruction(opname='MAKE_CELL', opcode=92, arg=0, argval='c', argrepr='c', offset=2, start_offset=2, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), -- Instruction(opname='MAKE_CELL', opcode=92, arg=1, argval='d', argrepr='d', offset=4, start_offset=4, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), -+ Instruction(opname='COPY_FREE_VARS', opcode=59, arg=2, argval=2, argrepr='', offset=0, start_offset=0, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), -+ Instruction(opname='MAKE_CELL', opcode=93, arg=0, argval='c', argrepr='c', offset=2, start_offset=2, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), -+ Instruction(opname='MAKE_CELL', opcode=93, arg=1, argval='d', argrepr='d', offset=4, start_offset=4, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), - Instruction(opname='RESUME', opcode=149, arg=0, argval=0, argrepr='', offset=6, start_offset=6, starts_line=True, line_number=2, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_CONST', opcode=79, arg=1, argval=(5, 6), argrepr='(5, 6)', offset=8, start_offset=8, starts_line=True, line_number=3, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_FAST', opcode=81, arg=3, argval='a', argrepr='a', offset=10, start_offset=10, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_FAST', opcode=81, arg=4, argval='b', argrepr='b', offset=12, start_offset=12, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_FAST', opcode=81, arg=0, argval='c', argrepr='c', offset=14, start_offset=14, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_FAST', opcode=81, arg=1, argval='d', argrepr='d', offset=16, start_offset=16, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), -- Instruction(opname='BUILD_TUPLE', opcode=48, arg=4, argval=4, argrepr='', offset=18, start_offset=18, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_CONST', opcode=79, arg=0, argval=code_object_inner, argrepr=repr(code_object_inner), offset=20, start_offset=20, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_CONST', opcode=80, arg=1, argval=(5, 6), argrepr='(5, 6)', offset=8, start_offset=8, starts_line=True, line_number=3, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_FAST', opcode=82, arg=3, argval='a', argrepr='a', offset=10, start_offset=10, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_FAST', opcode=82, arg=4, argval='b', argrepr='b', offset=12, start_offset=12, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_FAST', opcode=82, arg=0, argval='c', argrepr='c', offset=14, start_offset=14, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_FAST', opcode=82, arg=1, argval='d', argrepr='d', offset=16, start_offset=16, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), -+ Instruction(opname='BUILD_TUPLE', opcode=50, arg=4, argval=4, argrepr='', offset=18, start_offset=18, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_CONST', opcode=80, arg=0, argval=code_object_inner, argrepr=repr(code_object_inner), offset=20, start_offset=20, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), - Instruction(opname='MAKE_FUNCTION', opcode=23, arg=None, argval=None, argrepr='', offset=22, start_offset=22, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), -- Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=103, arg=8, argval=8, argrepr='closure', offset=24, start_offset=24, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), -- Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=103, arg=1, argval=1, argrepr='defaults', offset=26, start_offset=26, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), -- Instruction(opname='STORE_FAST', opcode=107, arg=2, argval='inner', argrepr='inner', offset=28, start_offset=28, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_GLOBAL', opcode=87, arg=1, argval='print', argrepr='print + NULL', offset=30, start_offset=30, starts_line=True, line_number=5, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), -- Instruction(opname='LOAD_DEREF', opcode=80, arg=3, argval='a', argrepr='a', offset=40, start_offset=40, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_DEREF', opcode=80, arg=4, argval='b', argrepr='b', offset=42, start_offset=42, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_DEREF', opcode=80, arg=0, argval='c', argrepr='c', offset=44, start_offset=44, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_DEREF', opcode=80, arg=1, argval='d', argrepr='d', offset=46, start_offset=46, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), -- Instruction(opname='CALL', opcode=49, arg=4, argval=4, argrepr='', offset=48, start_offset=48, starts_line=False, line_number=5, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=56, start_offset=56, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_FAST', opcode=81, arg=2, argval='inner', argrepr='inner', offset=58, start_offset=58, starts_line=True, line_number=6, label=None, positions=None, cache_info=None), -- Instruction(opname='RETURN_VALUE', opcode=33, arg=None, argval=None, argrepr='', offset=60, start_offset=60, starts_line=False, line_number=6, label=None, positions=None, cache_info=None), -+ Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=104, arg=8, argval=8, argrepr='closure', offset=24, start_offset=24, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), -+ Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=104, arg=1, argval=1, argrepr='defaults', offset=26, start_offset=26, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), -+ Instruction(opname='STORE_FAST', opcode=108, arg=2, argval='inner', argrepr='inner', offset=28, start_offset=28, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_GLOBAL', opcode=88, arg=1, argval='print', argrepr='print + NULL', offset=30, start_offset=30, starts_line=True, line_number=5, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), -+ Instruction(opname='LOAD_DEREF', opcode=81, arg=3, argval='a', argrepr='a', offset=40, start_offset=40, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_DEREF', opcode=81, arg=4, argval='b', argrepr='b', offset=42, start_offset=42, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_DEREF', opcode=81, arg=0, argval='c', argrepr='c', offset=44, start_offset=44, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_DEREF', opcode=81, arg=1, argval='d', argrepr='d', offset=46, start_offset=46, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), -+ Instruction(opname='CALL', opcode=51, arg=4, argval=4, argrepr='', offset=48, start_offset=48, starts_line=False, line_number=5, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -+ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=56, start_offset=56, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_FAST', opcode=82, arg=2, argval='inner', argrepr='inner', offset=58, start_offset=58, starts_line=True, line_number=6, label=None, positions=None, cache_info=None), -+ Instruction(opname='RETURN_VALUE', opcode=35, arg=None, argval=None, argrepr='', offset=60, start_offset=60, starts_line=False, line_number=6, label=None, positions=None, cache_info=None), - ] - - expected_opinfo_inner = [ -- Instruction(opname='COPY_FREE_VARS', opcode=58, arg=4, argval=4, argrepr='', offset=0, start_offset=0, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), -+ Instruction(opname='COPY_FREE_VARS', opcode=59, arg=4, argval=4, argrepr='', offset=0, start_offset=0, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), - Instruction(opname='RESUME', opcode=149, arg=0, argval=0, argrepr='', offset=2, start_offset=2, starts_line=True, line_number=3, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_GLOBAL', opcode=87, arg=1, argval='print', argrepr='print + NULL', offset=4, start_offset=4, starts_line=True, line_number=4, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), -- Instruction(opname='LOAD_DEREF', opcode=80, arg=2, argval='a', argrepr='a', offset=14, start_offset=14, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_DEREF', opcode=80, arg=3, argval='b', argrepr='b', offset=16, start_offset=16, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_DEREF', opcode=80, arg=4, argval='c', argrepr='c', offset=18, start_offset=18, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_DEREF', opcode=80, arg=5, argval='d', argrepr='d', offset=20, start_offset=20, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_FAST_LOAD_FAST', opcode=84, arg=1, argval=('e', 'f'), argrepr='e, f', offset=22, start_offset=22, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), -- Instruction(opname='CALL', opcode=49, arg=6, argval=6, argrepr='', offset=24, start_offset=24, starts_line=False, line_number=4, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=32, start_offset=32, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_CONST', opcode=79, arg=0, argval=None, argrepr='None', offset=34, start_offset=34, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), -- Instruction(opname='RETURN_VALUE', opcode=33, arg=None, argval=None, argrepr='', offset=36, start_offset=36, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_GLOBAL', opcode=88, arg=1, argval='print', argrepr='print + NULL', offset=4, start_offset=4, starts_line=True, line_number=4, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), -+ Instruction(opname='LOAD_DEREF', opcode=81, arg=2, argval='a', argrepr='a', offset=14, start_offset=14, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_DEREF', opcode=81, arg=3, argval='b', argrepr='b', offset=16, start_offset=16, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_DEREF', opcode=81, arg=4, argval='c', argrepr='c', offset=18, start_offset=18, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_DEREF', opcode=81, arg=5, argval='d', argrepr='d', offset=20, start_offset=20, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_FAST_LOAD_FAST', opcode=85, arg=1, argval=('e', 'f'), argrepr='e, f', offset=22, start_offset=22, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), -+ Instruction(opname='CALL', opcode=51, arg=6, argval=6, argrepr='', offset=24, start_offset=24, starts_line=False, line_number=4, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -+ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=32, start_offset=32, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_CONST', opcode=80, arg=0, argval=None, argrepr='None', offset=34, start_offset=34, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), -+ Instruction(opname='RETURN_VALUE', opcode=35, arg=None, argval=None, argrepr='', offset=36, start_offset=36, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), - ] - - expected_opinfo_jumpy = [ - Instruction(opname='RESUME', opcode=149, arg=0, argval=0, argrepr='', offset=0, start_offset=0, starts_line=True, line_number=1, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_GLOBAL', opcode=87, arg=1, argval='range', argrepr='range + NULL', offset=2, start_offset=2, starts_line=True, line_number=3, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), -- Instruction(opname='LOAD_SMALL_INT', opcode=89, arg=10, argval=10, argrepr='', offset=12, start_offset=12, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), -- Instruction(opname='CALL', opcode=49, arg=1, argval=1, argrepr='', offset=14, start_offset=14, starts_line=False, line_number=3, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -+ Instruction(opname='LOAD_GLOBAL', opcode=88, arg=1, argval='range', argrepr='range + NULL', offset=2, start_offset=2, starts_line=True, line_number=3, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), -+ Instruction(opname='LOAD_SMALL_INT', opcode=90, arg=10, argval=10, argrepr='', offset=12, start_offset=12, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), -+ Instruction(opname='CALL', opcode=51, arg=1, argval=1, argrepr='', offset=14, start_offset=14, starts_line=False, line_number=3, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), - Instruction(opname='GET_ITER', opcode=16, arg=None, argval=None, argrepr='', offset=22, start_offset=22, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), -- Instruction(opname='FOR_ITER', opcode=67, arg=30, argval=88, argrepr='to L4', offset=24, start_offset=24, starts_line=False, line_number=3, label=1, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -- Instruction(opname='STORE_FAST', opcode=107, arg=0, argval='i', argrepr='i', offset=28, start_offset=28, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_GLOBAL', opcode=87, arg=3, argval='print', argrepr='print + NULL', offset=30, start_offset=30, starts_line=True, line_number=4, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), -- Instruction(opname='LOAD_FAST', opcode=81, arg=0, argval='i', argrepr='i', offset=40, start_offset=40, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), -- Instruction(opname='CALL', opcode=49, arg=1, argval=1, argrepr='', offset=42, start_offset=42, starts_line=False, line_number=4, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=50, start_offset=50, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_FAST', opcode=81, arg=0, argval='i', argrepr='i', offset=52, start_offset=52, starts_line=True, line_number=5, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_SMALL_INT', opcode=89, arg=4, argval=4, argrepr='', offset=54, start_offset=54, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), -- Instruction(opname='COMPARE_OP', opcode=54, arg=18, argval='<', argrepr='bool(<)', offset=56, start_offset=56, starts_line=False, line_number=5, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -- Instruction(opname='POP_JUMP_IF_FALSE', opcode=95, arg=2, argval=68, argrepr='to L2', offset=60, start_offset=60, starts_line=False, line_number=5, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -- Instruction(opname='JUMP_BACKWARD', opcode=72, arg=22, argval=24, argrepr='to L1', offset=64, start_offset=64, starts_line=True, line_number=6, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -- Instruction(opname='LOAD_FAST', opcode=81, arg=0, argval='i', argrepr='i', offset=68, start_offset=68, starts_line=True, line_number=7, label=2, positions=None, cache_info=None), -- Instruction(opname='LOAD_SMALL_INT', opcode=89, arg=6, argval=6, argrepr='', offset=70, start_offset=70, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), -- Instruction(opname='COMPARE_OP', opcode=54, arg=148, argval='>', argrepr='bool(>)', offset=72, start_offset=72, starts_line=False, line_number=7, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -- Instruction(opname='POP_JUMP_IF_TRUE', opcode=98, arg=2, argval=84, argrepr='to L3', offset=76, start_offset=76, starts_line=False, line_number=7, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -- Instruction(opname='JUMP_BACKWARD', opcode=72, arg=30, argval=24, argrepr='to L1', offset=80, start_offset=80, starts_line=False, line_number=7, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=84, start_offset=84, starts_line=True, line_number=8, label=3, positions=None, cache_info=None), -- Instruction(opname='JUMP_FORWARD', opcode=74, arg=13, argval=114, argrepr='to L5', offset=86, start_offset=86, starts_line=False, line_number=8, label=None, positions=None, cache_info=None), -- Instruction(opname='END_FOR', opcode=9, arg=None, argval=None, argrepr='', offset=88, start_offset=88, starts_line=True, line_number=3, label=4, positions=None, cache_info=None), -- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=90, start_offset=90, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_GLOBAL', opcode=87, arg=3, argval='print', argrepr='print + NULL', offset=92, start_offset=92, starts_line=True, line_number=10, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), -- Instruction(opname='LOAD_CONST', opcode=79, arg=0, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=102, start_offset=102, starts_line=False, line_number=10, label=None, positions=None, cache_info=None), -- Instruction(opname='CALL', opcode=49, arg=1, argval=1, argrepr='', offset=104, start_offset=104, starts_line=False, line_number=10, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=112, start_offset=112, starts_line=False, line_number=10, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_FAST_CHECK', opcode=83, arg=0, argval='i', argrepr='i', offset=114, start_offset=114, starts_line=True, line_number=11, label=5, positions=None, cache_info=None), -- Instruction(opname='TO_BOOL', opcode=37, arg=None, argval=None, argrepr='', offset=116, start_offset=116, starts_line=False, line_number=11, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('version', 2, b'\x00\x00\x00\x00')]), -- Instruction(opname='POP_JUMP_IF_FALSE', opcode=95, arg=33, argval=194, argrepr='to L8', offset=124, start_offset=124, starts_line=False, line_number=11, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -- Instruction(opname='LOAD_GLOBAL', opcode=87, arg=3, argval='print', argrepr='print + NULL', offset=128, start_offset=128, starts_line=True, line_number=12, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), -- Instruction(opname='LOAD_FAST', opcode=81, arg=0, argval='i', argrepr='i', offset=138, start_offset=138, starts_line=False, line_number=12, label=None, positions=None, cache_info=None), -- Instruction(opname='CALL', opcode=49, arg=1, argval=1, argrepr='', offset=140, start_offset=140, starts_line=False, line_number=12, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=148, start_offset=148, starts_line=False, line_number=12, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_FAST', opcode=81, arg=0, argval='i', argrepr='i', offset=150, start_offset=150, starts_line=True, line_number=13, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_SMALL_INT', opcode=89, arg=1, argval=1, argrepr='', offset=152, start_offset=152, starts_line=False, line_number=13, label=None, positions=None, cache_info=None), -- Instruction(opname='BINARY_OP', opcode=42, arg=23, argval=23, argrepr='-=', offset=154, start_offset=154, starts_line=False, line_number=13, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -- Instruction(opname='STORE_FAST', opcode=107, arg=0, argval='i', argrepr='i', offset=158, start_offset=158, starts_line=False, line_number=13, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_FAST', opcode=81, arg=0, argval='i', argrepr='i', offset=160, start_offset=160, starts_line=True, line_number=14, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_SMALL_INT', opcode=89, arg=6, argval=6, argrepr='', offset=162, start_offset=162, starts_line=False, line_number=14, label=None, positions=None, cache_info=None), -- Instruction(opname='COMPARE_OP', opcode=54, arg=148, argval='>', argrepr='bool(>)', offset=164, start_offset=164, starts_line=False, line_number=14, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -- Instruction(opname='POP_JUMP_IF_FALSE', opcode=95, arg=2, argval=176, argrepr='to L6', offset=168, start_offset=168, starts_line=False, line_number=14, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -- Instruction(opname='JUMP_BACKWARD', opcode=72, arg=31, argval=114, argrepr='to L5', offset=172, start_offset=172, starts_line=True, line_number=15, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -- Instruction(opname='LOAD_FAST', opcode=81, arg=0, argval='i', argrepr='i', offset=176, start_offset=176, starts_line=True, line_number=16, label=6, positions=None, cache_info=None), -- Instruction(opname='LOAD_SMALL_INT', opcode=89, arg=4, argval=4, argrepr='', offset=178, start_offset=178, starts_line=False, line_number=16, label=None, positions=None, cache_info=None), -- Instruction(opname='COMPARE_OP', opcode=54, arg=18, argval='<', argrepr='bool(<)', offset=180, start_offset=180, starts_line=False, line_number=16, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -- Instruction(opname='POP_JUMP_IF_TRUE', opcode=98, arg=2, argval=192, argrepr='to L7', offset=184, start_offset=184, starts_line=False, line_number=16, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -- Instruction(opname='JUMP_BACKWARD', opcode=72, arg=39, argval=114, argrepr='to L5', offset=188, start_offset=188, starts_line=False, line_number=16, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -- Instruction(opname='JUMP_FORWARD', opcode=74, arg=11, argval=216, argrepr='to L9', offset=192, start_offset=192, starts_line=True, line_number=17, label=7, positions=None, cache_info=None), -- Instruction(opname='LOAD_GLOBAL', opcode=87, arg=3, argval='print', argrepr='print + NULL', offset=194, start_offset=194, starts_line=True, line_number=19, label=8, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), -- Instruction(opname='LOAD_CONST', opcode=79, arg=1, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=204, start_offset=204, starts_line=False, line_number=19, label=None, positions=None, cache_info=None), -- Instruction(opname='CALL', opcode=49, arg=1, argval=1, argrepr='', offset=206, start_offset=206, starts_line=False, line_number=19, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=214, start_offset=214, starts_line=False, line_number=19, label=None, positions=None, cache_info=None), -- Instruction(opname='NOP', opcode=27, arg=None, argval=None, argrepr='', offset=216, start_offset=216, starts_line=True, line_number=20, label=9, positions=None, cache_info=None), -- Instruction(opname='LOAD_SMALL_INT', opcode=89, arg=1, argval=1, argrepr='', offset=218, start_offset=218, starts_line=True, line_number=21, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_SMALL_INT', opcode=89, arg=0, argval=0, argrepr='', offset=220, start_offset=220, starts_line=False, line_number=21, label=None, positions=None, cache_info=None), -- Instruction(opname='BINARY_OP', opcode=42, arg=11, argval=11, argrepr='/', offset=222, start_offset=222, starts_line=False, line_number=21, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=226, start_offset=226, starts_line=False, line_number=21, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_FAST', opcode=81, arg=0, argval='i', argrepr='i', offset=228, start_offset=228, starts_line=True, line_number=25, label=None, positions=None, cache_info=None), -- Instruction(opname='COPY', opcode=57, arg=1, argval=1, argrepr='', offset=230, start_offset=230, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_SPECIAL', opcode=90, arg=1, argval=1, argrepr='__exit__', offset=232, start_offset=232, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -- Instruction(opname='SWAP', opcode=112, arg=2, argval=2, argrepr='', offset=234, start_offset=234, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -- Instruction(opname='SWAP', opcode=112, arg=3, argval=3, argrepr='', offset=236, start_offset=236, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_SPECIAL', opcode=90, arg=0, argval=0, argrepr='__enter__', offset=238, start_offset=238, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -- Instruction(opname='CALL', opcode=49, arg=0, argval=0, argrepr='', offset=240, start_offset=240, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -- Instruction(opname='STORE_FAST', opcode=107, arg=1, argval='dodgy', argrepr='dodgy', offset=248, start_offset=248, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_GLOBAL', opcode=87, arg=3, argval='print', argrepr='print + NULL', offset=250, start_offset=250, starts_line=True, line_number=26, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), -- Instruction(opname='LOAD_CONST', opcode=79, arg=2, argval='Never reach this', argrepr="'Never reach this'", offset=260, start_offset=260, starts_line=False, line_number=26, label=None, positions=None, cache_info=None), -- Instruction(opname='CALL', opcode=49, arg=1, argval=1, argrepr='', offset=262, start_offset=262, starts_line=False, line_number=26, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=270, start_offset=270, starts_line=False, line_number=26, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_CONST', opcode=79, arg=3, argval=None, argrepr='None', offset=272, start_offset=272, starts_line=True, line_number=25, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_CONST', opcode=79, arg=3, argval=None, argrepr='None', offset=274, start_offset=274, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_CONST', opcode=79, arg=3, argval=None, argrepr='None', offset=276, start_offset=276, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -- Instruction(opname='CALL', opcode=49, arg=3, argval=3, argrepr='', offset=278, start_offset=278, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=286, start_offset=286, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_GLOBAL', opcode=87, arg=3, argval='print', argrepr='print + NULL', offset=288, start_offset=288, starts_line=True, line_number=28, label=10, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), -- Instruction(opname='LOAD_CONST', opcode=79, arg=5, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=298, start_offset=298, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), -- Instruction(opname='CALL', opcode=49, arg=1, argval=1, argrepr='', offset=300, start_offset=300, starts_line=False, line_number=28, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=308, start_offset=308, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_CONST', opcode=79, arg=3, argval=None, argrepr='None', offset=310, start_offset=310, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), -- Instruction(opname='RETURN_VALUE', opcode=33, arg=None, argval=None, argrepr='', offset=312, start_offset=312, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), -- Instruction(opname='PUSH_EXC_INFO', opcode=30, arg=None, argval=None, argrepr='', offset=314, start_offset=314, starts_line=True, line_number=25, label=None, positions=None, cache_info=None), -- Instruction(opname='WITH_EXCEPT_START', opcode=41, arg=None, argval=None, argrepr='', offset=316, start_offset=316, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -- Instruction(opname='TO_BOOL', opcode=37, arg=None, argval=None, argrepr='', offset=318, start_offset=318, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('version', 2, b'\x00\x00\x00\x00')]), -- Instruction(opname='POP_JUMP_IF_TRUE', opcode=98, arg=1, argval=332, argrepr='to L11', offset=326, start_offset=326, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -- Instruction(opname='RERAISE', opcode=100, arg=2, argval=2, argrepr='', offset=330, start_offset=330, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=332, start_offset=332, starts_line=False, line_number=25, label=11, positions=None, cache_info=None), -- Instruction(opname='POP_EXCEPT', opcode=28, arg=None, argval=None, argrepr='', offset=334, start_offset=334, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=336, start_offset=336, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=338, start_offset=338, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=340, start_offset=340, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -- Instruction(opname='JUMP_BACKWARD_NO_INTERRUPT', opcode=73, arg=28, argval=288, argrepr='to L10', offset=342, start_offset=342, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -- Instruction(opname='COPY', opcode=57, arg=3, argval=3, argrepr='', offset=344, start_offset=344, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), -- Instruction(opname='POP_EXCEPT', opcode=28, arg=None, argval=None, argrepr='', offset=346, start_offset=346, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), -- Instruction(opname='RERAISE', opcode=100, arg=1, argval=1, argrepr='', offset=348, start_offset=348, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), -- Instruction(opname='PUSH_EXC_INFO', opcode=30, arg=None, argval=None, argrepr='', offset=350, start_offset=350, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_GLOBAL', opcode=87, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=352, start_offset=352, starts_line=True, line_number=22, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), -- Instruction(opname='CHECK_EXC_MATCH', opcode=5, arg=None, argval=None, argrepr='', offset=362, start_offset=362, starts_line=False, line_number=22, label=None, positions=None, cache_info=None), -- Instruction(opname='POP_JUMP_IF_FALSE', opcode=95, arg=14, argval=396, argrepr='to L12', offset=364, start_offset=364, starts_line=False, line_number=22, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=368, start_offset=368, starts_line=False, line_number=22, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_GLOBAL', opcode=87, arg=3, argval='print', argrepr='print + NULL', offset=370, start_offset=370, starts_line=True, line_number=23, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), -- Instruction(opname='LOAD_CONST', opcode=79, arg=4, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=380, start_offset=380, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), -- Instruction(opname='CALL', opcode=49, arg=1, argval=1, argrepr='', offset=382, start_offset=382, starts_line=False, line_number=23, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=390, start_offset=390, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), -- Instruction(opname='POP_EXCEPT', opcode=28, arg=None, argval=None, argrepr='', offset=392, start_offset=392, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), -- Instruction(opname='JUMP_BACKWARD_NO_INTERRUPT', opcode=73, arg=54, argval=288, argrepr='to L10', offset=394, start_offset=394, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), -- Instruction(opname='RERAISE', opcode=100, arg=0, argval=0, argrepr='', offset=396, start_offset=396, starts_line=True, line_number=22, label=12, positions=None, cache_info=None), -- Instruction(opname='COPY', opcode=57, arg=3, argval=3, argrepr='', offset=398, start_offset=398, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), -- Instruction(opname='POP_EXCEPT', opcode=28, arg=None, argval=None, argrepr='', offset=400, start_offset=400, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), -- Instruction(opname='RERAISE', opcode=100, arg=1, argval=1, argrepr='', offset=402, start_offset=402, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), -- Instruction(opname='PUSH_EXC_INFO', opcode=30, arg=None, argval=None, argrepr='', offset=404, start_offset=404, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), -- Instruction(opname='LOAD_GLOBAL', opcode=87, arg=3, argval='print', argrepr='print + NULL', offset=406, start_offset=406, starts_line=True, line_number=28, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), -- Instruction(opname='LOAD_CONST', opcode=79, arg=5, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=416, start_offset=416, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), -- Instruction(opname='CALL', opcode=49, arg=1, argval=1, argrepr='', offset=418, start_offset=418, starts_line=False, line_number=28, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -- Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=426, start_offset=426, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), -- Instruction(opname='RERAISE', opcode=100, arg=0, argval=0, argrepr='', offset=428, start_offset=428, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), -- Instruction(opname='COPY', opcode=57, arg=3, argval=3, argrepr='', offset=430, start_offset=430, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), -- Instruction(opname='POP_EXCEPT', opcode=28, arg=None, argval=None, argrepr='', offset=432, start_offset=432, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), -- Instruction(opname='RERAISE', opcode=100, arg=1, argval=1, argrepr='', offset=434, start_offset=434, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), -+ Instruction(opname='FOR_ITER', opcode=68, arg=32, argval=92, argrepr='to L4', offset=24, start_offset=24, starts_line=False, line_number=3, label=1, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -+ Instruction(opname='STORE_FAST', opcode=108, arg=0, argval='i', argrepr='i', offset=28, start_offset=28, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_GLOBAL', opcode=88, arg=3, argval='print', argrepr='print + NULL', offset=30, start_offset=30, starts_line=True, line_number=4, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), -+ Instruction(opname='LOAD_FAST', opcode=82, arg=0, argval='i', argrepr='i', offset=40, start_offset=40, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), -+ Instruction(opname='CALL', opcode=51, arg=1, argval=1, argrepr='', offset=42, start_offset=42, starts_line=False, line_number=4, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -+ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=50, start_offset=50, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_FAST', opcode=82, arg=0, argval='i', argrepr='i', offset=52, start_offset=52, starts_line=True, line_number=5, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_SMALL_INT', opcode=90, arg=4, argval=4, argrepr='', offset=54, start_offset=54, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), -+ Instruction(opname='COMPARE_OP', opcode=55, arg=18, argval='<', argrepr='bool(<)', offset=56, start_offset=56, starts_line=False, line_number=5, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -+ Instruction(opname='POP_JUMP_IF_FALSE', opcode=96, arg=3, argval=70, argrepr='to L2', offset=60, start_offset=60, starts_line=False, line_number=5, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -+ Instruction(opname='NOT_TAKEN', opcode=28, arg=None, argval=None, argrepr='', offset=64, start_offset=64, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), -+ Instruction(opname='JUMP_BACKWARD', opcode=73, arg=23, argval=24, argrepr='to L1', offset=66, start_offset=66, starts_line=True, line_number=6, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -+ Instruction(opname='LOAD_FAST', opcode=82, arg=0, argval='i', argrepr='i', offset=70, start_offset=70, starts_line=True, line_number=7, label=2, positions=None, cache_info=None), -+ Instruction(opname='LOAD_SMALL_INT', opcode=90, arg=6, argval=6, argrepr='', offset=72, start_offset=72, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), -+ Instruction(opname='COMPARE_OP', opcode=55, arg=148, argval='>', argrepr='bool(>)', offset=74, start_offset=74, starts_line=False, line_number=7, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -+ Instruction(opname='POP_JUMP_IF_TRUE', opcode=99, arg=3, argval=88, argrepr='to L3', offset=78, start_offset=78, starts_line=False, line_number=7, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -+ Instruction(opname='NOT_TAKEN', opcode=28, arg=None, argval=None, argrepr='', offset=82, start_offset=82, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), -+ Instruction(opname='JUMP_BACKWARD', opcode=73, arg=32, argval=24, argrepr='to L1', offset=84, start_offset=84, starts_line=False, line_number=7, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -+ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=88, start_offset=88, starts_line=True, line_number=8, label=3, positions=None, cache_info=None), -+ Instruction(opname='JUMP_FORWARD', opcode=75, arg=13, argval=118, argrepr='to L5', offset=90, start_offset=90, starts_line=False, line_number=8, label=None, positions=None, cache_info=None), -+ Instruction(opname='END_FOR', opcode=9, arg=None, argval=None, argrepr='', offset=92, start_offset=92, starts_line=True, line_number=3, label=4, positions=None, cache_info=None), -+ Instruction(opname='POP_ITER', opcode=30, arg=None, argval=None, argrepr='', offset=94, start_offset=94, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_GLOBAL', opcode=88, arg=3, argval='print', argrepr='print + NULL', offset=96, start_offset=96, starts_line=True, line_number=10, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), -+ Instruction(opname='LOAD_CONST', opcode=80, arg=0, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=106, start_offset=106, starts_line=False, line_number=10, label=None, positions=None, cache_info=None), -+ Instruction(opname='CALL', opcode=51, arg=1, argval=1, argrepr='', offset=108, start_offset=108, starts_line=False, line_number=10, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -+ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=116, start_offset=116, starts_line=False, line_number=10, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_FAST_CHECK', opcode=84, arg=0, argval='i', argrepr='i', offset=118, start_offset=118, starts_line=True, line_number=11, label=5, positions=None, cache_info=None), -+ Instruction(opname='TO_BOOL', opcode=39, arg=None, argval=None, argrepr='', offset=120, start_offset=120, starts_line=False, line_number=11, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('version', 2, b'\x00\x00\x00\x00')]), -+ Instruction(opname='POP_JUMP_IF_FALSE', opcode=96, arg=40, argval=212, argrepr='to L8', offset=128, start_offset=128, starts_line=False, line_number=11, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -+ Instruction(opname='NOT_TAKEN', opcode=28, arg=None, argval=None, argrepr='', offset=132, start_offset=132, starts_line=False, line_number=11, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_GLOBAL', opcode=88, arg=3, argval='print', argrepr='print + NULL', offset=134, start_offset=134, starts_line=True, line_number=12, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), -+ Instruction(opname='LOAD_FAST', opcode=82, arg=0, argval='i', argrepr='i', offset=144, start_offset=144, starts_line=False, line_number=12, label=None, positions=None, cache_info=None), -+ Instruction(opname='CALL', opcode=51, arg=1, argval=1, argrepr='', offset=146, start_offset=146, starts_line=False, line_number=12, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -+ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=154, start_offset=154, starts_line=False, line_number=12, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_FAST', opcode=82, arg=0, argval='i', argrepr='i', offset=156, start_offset=156, starts_line=True, line_number=13, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_SMALL_INT', opcode=90, arg=1, argval=1, argrepr='', offset=158, start_offset=158, starts_line=False, line_number=13, label=None, positions=None, cache_info=None), -+ Instruction(opname='BINARY_OP', opcode=44, arg=23, argval=23, argrepr='-=', offset=160, start_offset=160, starts_line=False, line_number=13, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('descr', 4, b'\x00\x00\x00\x00\x00\x00\x00\x00')]), -+ Instruction(opname='STORE_FAST', opcode=108, arg=0, argval='i', argrepr='i', offset=172, start_offset=172, starts_line=False, line_number=13, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_FAST', opcode=82, arg=0, argval='i', argrepr='i', offset=174, start_offset=174, starts_line=True, line_number=14, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_SMALL_INT', opcode=90, arg=6, argval=6, argrepr='', offset=176, start_offset=176, starts_line=False, line_number=14, label=None, positions=None, cache_info=None), -+ Instruction(opname='COMPARE_OP', opcode=55, arg=148, argval='>', argrepr='bool(>)', offset=178, start_offset=178, starts_line=False, line_number=14, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -+ Instruction(opname='POP_JUMP_IF_FALSE', opcode=96, arg=3, argval=192, argrepr='to L6', offset=182, start_offset=182, starts_line=False, line_number=14, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -+ Instruction(opname='NOT_TAKEN', opcode=28, arg=None, argval=None, argrepr='', offset=186, start_offset=186, starts_line=False, line_number=14, label=None, positions=None, cache_info=None), -+ Instruction(opname='JUMP_BACKWARD', opcode=73, arg=37, argval=118, argrepr='to L5', offset=188, start_offset=188, starts_line=True, line_number=15, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -+ Instruction(opname='LOAD_FAST', opcode=82, arg=0, argval='i', argrepr='i', offset=192, start_offset=192, starts_line=True, line_number=16, label=6, positions=None, cache_info=None), -+ Instruction(opname='LOAD_SMALL_INT', opcode=90, arg=4, argval=4, argrepr='', offset=194, start_offset=194, starts_line=False, line_number=16, label=None, positions=None, cache_info=None), -+ Instruction(opname='COMPARE_OP', opcode=55, arg=18, argval='<', argrepr='bool(<)', offset=196, start_offset=196, starts_line=False, line_number=16, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -+ Instruction(opname='POP_JUMP_IF_TRUE', opcode=99, arg=3, argval=210, argrepr='to L7', offset=200, start_offset=200, starts_line=False, line_number=16, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -+ Instruction(opname='NOT_TAKEN', opcode=28, arg=None, argval=None, argrepr='', offset=204, start_offset=204, starts_line=False, line_number=16, label=None, positions=None, cache_info=None), -+ Instruction(opname='JUMP_BACKWARD', opcode=73, arg=46, argval=118, argrepr='to L5', offset=206, start_offset=206, starts_line=False, line_number=16, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -+ Instruction(opname='JUMP_FORWARD', opcode=75, arg=11, argval=234, argrepr='to L9', offset=210, start_offset=210, starts_line=True, line_number=17, label=7, positions=None, cache_info=None), -+ Instruction(opname='LOAD_GLOBAL', opcode=88, arg=3, argval='print', argrepr='print + NULL', offset=212, start_offset=212, starts_line=True, line_number=19, label=8, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), -+ Instruction(opname='LOAD_CONST', opcode=80, arg=1, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=222, start_offset=222, starts_line=False, line_number=19, label=None, positions=None, cache_info=None), -+ Instruction(opname='CALL', opcode=51, arg=1, argval=1, argrepr='', offset=224, start_offset=224, starts_line=False, line_number=19, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -+ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=232, start_offset=232, starts_line=False, line_number=19, label=None, positions=None, cache_info=None), -+ Instruction(opname='NOP', opcode=27, arg=None, argval=None, argrepr='', offset=234, start_offset=234, starts_line=True, line_number=20, label=9, positions=None, cache_info=None), -+ Instruction(opname='LOAD_SMALL_INT', opcode=90, arg=1, argval=1, argrepr='', offset=236, start_offset=236, starts_line=True, line_number=21, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_SMALL_INT', opcode=90, arg=0, argval=0, argrepr='', offset=238, start_offset=238, starts_line=False, line_number=21, label=None, positions=None, cache_info=None), -+ Instruction(opname='BINARY_OP', opcode=44, arg=11, argval=11, argrepr='/', offset=240, start_offset=240, starts_line=False, line_number=21, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('descr', 4, b'\x00\x00\x00\x00\x00\x00\x00\x00')]), -+ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=252, start_offset=252, starts_line=False, line_number=21, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_FAST', opcode=82, arg=0, argval='i', argrepr='i', offset=254, start_offset=254, starts_line=True, line_number=25, label=None, positions=None, cache_info=None), -+ Instruction(opname='COPY', opcode=58, arg=1, argval=1, argrepr='', offset=256, start_offset=256, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_SPECIAL', opcode=91, arg=1, argval=1, argrepr='__exit__', offset=258, start_offset=258, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -+ Instruction(opname='SWAP', opcode=113, arg=2, argval=2, argrepr='', offset=260, start_offset=260, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -+ Instruction(opname='SWAP', opcode=113, arg=3, argval=3, argrepr='', offset=262, start_offset=262, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_SPECIAL', opcode=91, arg=0, argval=0, argrepr='__enter__', offset=264, start_offset=264, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -+ Instruction(opname='CALL', opcode=51, arg=0, argval=0, argrepr='', offset=266, start_offset=266, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -+ Instruction(opname='STORE_FAST', opcode=108, arg=1, argval='dodgy', argrepr='dodgy', offset=274, start_offset=274, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_GLOBAL', opcode=88, arg=3, argval='print', argrepr='print + NULL', offset=276, start_offset=276, starts_line=True, line_number=26, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), -+ Instruction(opname='LOAD_CONST', opcode=80, arg=2, argval='Never reach this', argrepr="'Never reach this'", offset=286, start_offset=286, starts_line=False, line_number=26, label=None, positions=None, cache_info=None), -+ Instruction(opname='CALL', opcode=51, arg=1, argval=1, argrepr='', offset=288, start_offset=288, starts_line=False, line_number=26, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -+ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=296, start_offset=296, starts_line=False, line_number=26, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_CONST', opcode=80, arg=3, argval=None, argrepr='None', offset=298, start_offset=298, starts_line=True, line_number=25, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_CONST', opcode=80, arg=3, argval=None, argrepr='None', offset=300, start_offset=300, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_CONST', opcode=80, arg=3, argval=None, argrepr='None', offset=302, start_offset=302, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -+ Instruction(opname='CALL', opcode=51, arg=3, argval=3, argrepr='', offset=304, start_offset=304, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -+ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=312, start_offset=312, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_GLOBAL', opcode=88, arg=3, argval='print', argrepr='print + NULL', offset=314, start_offset=314, starts_line=True, line_number=28, label=10, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), -+ Instruction(opname='LOAD_CONST', opcode=80, arg=5, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=324, start_offset=324, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), -+ Instruction(opname='CALL', opcode=51, arg=1, argval=1, argrepr='', offset=326, start_offset=326, starts_line=False, line_number=28, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -+ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=334, start_offset=334, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_CONST', opcode=80, arg=3, argval=None, argrepr='None', offset=336, start_offset=336, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), -+ Instruction(opname='RETURN_VALUE', opcode=35, arg=None, argval=None, argrepr='', offset=338, start_offset=338, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), -+ Instruction(opname='PUSH_EXC_INFO', opcode=32, arg=None, argval=None, argrepr='', offset=340, start_offset=340, starts_line=True, line_number=25, label=None, positions=None, cache_info=None), -+ Instruction(opname='WITH_EXCEPT_START', opcode=43, arg=None, argval=None, argrepr='', offset=342, start_offset=342, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -+ Instruction(opname='TO_BOOL', opcode=39, arg=None, argval=None, argrepr='', offset=344, start_offset=344, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('version', 2, b'\x00\x00\x00\x00')]), -+ Instruction(opname='POP_JUMP_IF_TRUE', opcode=99, arg=2, argval=360, argrepr='to L11', offset=352, start_offset=352, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -+ Instruction(opname='NOT_TAKEN', opcode=28, arg=None, argval=None, argrepr='', offset=356, start_offset=356, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -+ Instruction(opname='RERAISE', opcode=101, arg=2, argval=2, argrepr='', offset=358, start_offset=358, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -+ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=360, start_offset=360, starts_line=False, line_number=25, label=11, positions=None, cache_info=None), -+ Instruction(opname='POP_EXCEPT', opcode=29, arg=None, argval=None, argrepr='', offset=362, start_offset=362, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -+ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=364, start_offset=364, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -+ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=366, start_offset=366, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -+ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=368, start_offset=368, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -+ Instruction(opname='JUMP_BACKWARD_NO_INTERRUPT', opcode=74, arg=29, argval=314, argrepr='to L10', offset=370, start_offset=370, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), -+ Instruction(opname='COPY', opcode=58, arg=3, argval=3, argrepr='', offset=372, start_offset=372, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), -+ Instruction(opname='POP_EXCEPT', opcode=29, arg=None, argval=None, argrepr='', offset=374, start_offset=374, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), -+ Instruction(opname='RERAISE', opcode=101, arg=1, argval=1, argrepr='', offset=376, start_offset=376, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), -+ Instruction(opname='PUSH_EXC_INFO', opcode=32, arg=None, argval=None, argrepr='', offset=378, start_offset=378, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_GLOBAL', opcode=88, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=380, start_offset=380, starts_line=True, line_number=22, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), -+ Instruction(opname='CHECK_EXC_MATCH', opcode=5, arg=None, argval=None, argrepr='', offset=390, start_offset=390, starts_line=False, line_number=22, label=None, positions=None, cache_info=None), -+ Instruction(opname='POP_JUMP_IF_FALSE', opcode=96, arg=15, argval=426, argrepr='to L12', offset=392, start_offset=392, starts_line=False, line_number=22, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), -+ Instruction(opname='NOT_TAKEN', opcode=28, arg=None, argval=None, argrepr='', offset=396, start_offset=396, starts_line=False, line_number=22, label=None, positions=None, cache_info=None), -+ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=398, start_offset=398, starts_line=False, line_number=22, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_GLOBAL', opcode=88, arg=3, argval='print', argrepr='print + NULL', offset=400, start_offset=400, starts_line=True, line_number=23, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), -+ Instruction(opname='LOAD_CONST', opcode=80, arg=4, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=410, start_offset=410, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), -+ Instruction(opname='CALL', opcode=51, arg=1, argval=1, argrepr='', offset=412, start_offset=412, starts_line=False, line_number=23, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -+ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=420, start_offset=420, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), -+ Instruction(opname='POP_EXCEPT', opcode=29, arg=None, argval=None, argrepr='', offset=422, start_offset=422, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), -+ Instruction(opname='JUMP_BACKWARD_NO_INTERRUPT', opcode=74, arg=56, argval=314, argrepr='to L10', offset=424, start_offset=424, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), -+ Instruction(opname='RERAISE', opcode=101, arg=0, argval=0, argrepr='', offset=426, start_offset=426, starts_line=True, line_number=22, label=12, positions=None, cache_info=None), -+ Instruction(opname='COPY', opcode=58, arg=3, argval=3, argrepr='', offset=428, start_offset=428, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), -+ Instruction(opname='POP_EXCEPT', opcode=29, arg=None, argval=None, argrepr='', offset=430, start_offset=430, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), -+ Instruction(opname='RERAISE', opcode=101, arg=1, argval=1, argrepr='', offset=432, start_offset=432, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), -+ Instruction(opname='PUSH_EXC_INFO', opcode=32, arg=None, argval=None, argrepr='', offset=434, start_offset=434, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), -+ Instruction(opname='LOAD_GLOBAL', opcode=88, arg=3, argval='print', argrepr='print + NULL', offset=436, start_offset=436, starts_line=True, line_number=28, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), -+ Instruction(opname='LOAD_CONST', opcode=80, arg=5, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=446, start_offset=446, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), -+ Instruction(opname='CALL', opcode=51, arg=1, argval=1, argrepr='', offset=448, start_offset=448, starts_line=False, line_number=28, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), -+ Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=456, start_offset=456, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), -+ Instruction(opname='RERAISE', opcode=101, arg=0, argval=0, argrepr='', offset=458, start_offset=458, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), -+ Instruction(opname='COPY', opcode=58, arg=3, argval=3, argrepr='', offset=460, start_offset=460, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), -+ Instruction(opname='POP_EXCEPT', opcode=29, arg=None, argval=None, argrepr='', offset=462, start_offset=462, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), -+ Instruction(opname='RERAISE', opcode=101, arg=1, argval=1, argrepr='', offset=464, start_offset=464, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), - ] - - # One last piece of inspect fodder to check the default line number handling - def simple(): pass - expected_opinfo_simple = [ - Instruction(opname='RESUME', opcode=149, arg=0, argval=0, argrepr='', offset=0, start_offset=0, starts_line=True, line_number=simple.__code__.co_firstlineno, label=None, positions=None), -- Instruction(opname='LOAD_CONST', opcode=79, arg=0, argval=None, argrepr='None', offset=2, start_offset=2, starts_line=False, line_number=simple.__code__.co_firstlineno, label=None), -- Instruction(opname='RETURN_VALUE', opcode=33, arg=None, argval=None, argrepr='', offset=4, start_offset=4, starts_line=False, line_number=simple.__code__.co_firstlineno, label=None), -+ Instruction(opname='LOAD_CONST', opcode=80, arg=0, argval=None, argrepr='None', offset=2, start_offset=2, starts_line=False, line_number=simple.__code__.co_firstlineno, label=None), -+ Instruction(opname='RETURN_VALUE', opcode=35, arg=None, argval=None, argrepr='', offset=4, start_offset=4, starts_line=False, line_number=simple.__code__.co_firstlineno, label=None), - ] - - -@@ -2537,7 +2551,7 @@ - expect = ''' - 0 RESUME 0 - -- 1 LOAD_CONST_IMMORTAL 0 (None) -+ 1 LOAD_CONST 0 (None) - RETURN_VALUE - ''' - for flag in ['-S', '--specialized']: -diff --git a/Lib/test/test_doctest/test_doctest.py b/Lib/test/test_doctest/test_doctest.py -index b1e165fe16b..a4a49298bab 100644 ---- a/Lib/test/test_doctest/test_doctest.py -+++ b/Lib/test/test_doctest/test_doctest.py -@@ -2860,7 +2860,7 @@ - >>> _colorize.COLORIZE = save_colorize - """ - --class TestImporter(importlib.abc.MetaPathFinder, importlib.abc.ResourceLoader): -+class TestImporter(importlib.abc.MetaPathFinder): - - def find_spec(self, fullname, path, target=None): - return importlib.util.spec_from_file_location(fullname, path, loader=self) -@@ -2869,6 +2869,12 @@ - with open(path, mode='rb') as f: - return f.read() - -+ def exec_module(self, module): -+ raise ImportError -+ -+ def create_module(self, spec): -+ return None -+ - class TestHook: - - def __init__(self, pathdir): -diff --git a/Lib/test/test_email/test__header_value_parser.py b/Lib/test/test_email/test__header_value_parser.py -index 95224e19f67..d60a7039f9d 100644 ---- a/Lib/test/test_email/test__header_value_parser.py -+++ b/Lib/test/test_email/test__header_value_parser.py -@@ -3082,13 +3082,40 @@ - self._test(parser.get_address_list(to)[0], - f'{a},\n =?utf-8?q?H=C3=BCbsch?= Kaktus \n') - -- a = '.' * 79 -+ a = '.' * 79 # ('.' is a special, so must be in quoted-string.) - to = f'"{a}" , "Hübsch Kaktus" ' - self._test(parser.get_address_list(to)[0], -- f'{a}\n' -+ f'"{a}"\n' - ' , =?utf-8?q?H=C3=BCbsch?= Kaktus ' - '\n') - -+ def test_address_list_with_specials_in_long_quoted_string(self): -+ # Regression for gh-80222. -+ policy = self.policy.clone(max_line_length=40) -+ cases = [ -+ # (to, folded) -+ ('"Exfiltrator (unclosed comment?" ', -+ '"Exfiltrator (unclosed\n' -+ ' comment?" \n'), -+ ('"Escaped \\" chars \\\\ in quoted-string stay escaped" ', -+ '"Escaped \\" chars \\\\ in quoted-string\n' -+ ' stay escaped" \n'), -+ ('This long display name does not need quotes ', -+ 'This long display name does not need\n' -+ ' quotes \n'), -+ ('"Quotes are not required but are retained here" ', -+ '"Quotes are not required but are\n' -+ ' retained here" \n'), -+ ('"A quoted-string, it can be a valid local-part"@example.com', -+ '"A quoted-string, it can be a valid\n' -+ ' local-part"@example.com\n'), -+ ('"local-part-with-specials@but-no-fws.cannot-fold"@example.com', -+ '"local-part-with-specials@but-no-fws.cannot-fold"@example.com\n'), -+ ] -+ for (to, folded) in cases: -+ with self.subTest(to=to): -+ self._test(parser.get_address_list(to)[0], folded, policy=policy) -+ - # XXX Need tests with comments on various sides of a unicode token, - # and with unicode tokens in the comments. Spaces inside the quotes - # currently don't do the right thing. -diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py -index abe9ef2e944..2deb3572157 100644 ---- a/Lib/test/test_email/test_email.py -+++ b/Lib/test/test_email/test_email.py -@@ -810,6 +810,16 @@ - w4kgdGVzdGFiYwo= - """)) - -+ def test_string_payload_with_base64_cte(self): -+ msg = email.message_from_string(textwrap.dedent("""\ -+ Content-Transfer-Encoding: base64 -+ -+ SGVsbG8uIFRlc3Rpbmc= -+ """), policy=email.policy.default) -+ self.assertEqual(msg.get_payload(decode=True), b"Hello. Testing") -+ self.assertDefectsEqual(msg['content-transfer-encoding'].defects, []) -+ -+ - - # Test the email.encoders module - class TestEncoders(unittest.TestCase): -@@ -2352,6 +2362,40 @@ - self.assertDefectsEqual(msg.defects, - [errors.MissingHeaderBodySeparatorDefect]) - -+ def test_string_payload_with_extra_space_after_cte(self): -+ # https://github.com/python/cpython/issues/98188 -+ cte = "base64 " -+ msg = email.message_from_string(textwrap.dedent(f"""\ -+ Content-Transfer-Encoding: {cte} -+ -+ SGVsbG8uIFRlc3Rpbmc= -+ """), policy=email.policy.default) -+ self.assertEqual(msg.get_payload(decode=True), b"Hello. Testing") -+ self.assertDefectsEqual(msg['content-transfer-encoding'].defects, []) -+ -+ def test_string_payload_with_extra_text_after_cte(self): -+ msg = email.message_from_string(textwrap.dedent("""\ -+ Content-Transfer-Encoding: base64 some text -+ -+ SGVsbG8uIFRlc3Rpbmc= -+ """), policy=email.policy.default) -+ self.assertEqual(msg.get_payload(decode=True), b"Hello. Testing") -+ cte = msg['content-transfer-encoding'] -+ self.assertDefectsEqual(cte.defects, [email.errors.InvalidHeaderDefect]) -+ -+ def test_string_payload_with_extra_space_after_cte_compat32(self): -+ cte = "base64 " -+ msg = email.message_from_string(textwrap.dedent(f"""\ -+ Content-Transfer-Encoding: {cte} -+ -+ SGVsbG8uIFRlc3Rpbmc= -+ """), policy=email.policy.compat32) -+ pasted_cte = msg['content-transfer-encoding'] -+ self.assertEqual(pasted_cte, cte) -+ self.assertEqual(msg.get_payload(decode=True), b"Hello. Testing") -+ self.assertDefectsEqual(msg.defects, []) -+ -+ - - # Test RFC 2047 header encoding and decoding - class TestRFC2047(TestEmailBase): -diff --git a/Lib/test/test_email/test_headerregistry.py b/Lib/test/test_email/test_headerregistry.py -index 4c0523f4103..ff7a6da644d 100644 ---- a/Lib/test/test_email/test_headerregistry.py -+++ b/Lib/test/test_email/test_headerregistry.py -@@ -837,6 +837,11 @@ - '7bit', - [errors.InvalidHeaderDefect]), - -+ 'extra_space_after_cte': ( -+ 'base64 ', -+ 'base64', -+ []), -+ - } - - -diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py -index 7110fb889f3..cd65496cafb 100644 ---- a/Lib/test/test_embed.py -+++ b/Lib/test/test_embed.py -@@ -51,6 +51,14 @@ - MAX_HASH_SEED = 4294967295 - - ABI_THREAD = 't' if sysconfig.get_config_var('Py_GIL_DISABLED') else '' -+# PLATSTDLIB_LANDMARK copied from Modules/getpath.py -+if os.name == 'nt': -+ PLATSTDLIB_LANDMARK = f'{sys.platlibdir}' -+else: -+ VERSION_MAJOR = sys.version_info.major -+ VERSION_MINOR = sys.version_info.minor -+ PLATSTDLIB_LANDMARK = (f'{sys.platlibdir}/python{VERSION_MAJOR}.' -+ f'{VERSION_MINOR}{ABI_THREAD}/lib-dynload') - - - # If we are running from a build dir, but the stdlib has been installed, -@@ -376,11 +384,14 @@ - def test_specialized_static_code_gets_unspecialized_at_Py_FINALIZE(self): - # https://github.com/python/cpython/issues/92031 - -- code = textwrap.dedent("""\ -+ _testinternalcapi = import_helper.import_module("_testinternalcapi") -+ -+ code = textwrap.dedent(f"""\ - import dis - import importlib._bootstrap - import opcode - import test.test_dis -+ import test.support - - def is_specialized(f): - for instruction in dis.get_instructions(f, adaptive=True): -@@ -399,11 +410,11 @@ - func = importlib._bootstrap._handle_fromlist - - # "copy" the code to un-specialize it: -- func.__code__ = func.__code__.replace() -+ test.support.reset_code(func) - - assert not is_specialized(func), "specialized instructions found" - -- for i in range(test.test_dis.ADAPTIVE_WARMUP_DELAY): -+ for _ in range({_testinternalcapi.SPECIALIZATION_THRESHOLD}): - func(importlib._bootstrap, ["x"], lambda *args: None) - - assert is_specialized(func), "no specialized instructions found" -@@ -940,6 +951,7 @@ - self.check_global_config(configs) - return configs - -+ @unittest.skipIf(support.check_bolt_optimized, "segfaults on BOLT instrumented binaries") - def test_init_default_config(self): - self.check_all_configs("test_init_initialize_config", api=API_COMPAT) - -@@ -1039,6 +1051,7 @@ - self.check_all_configs("test_init_from_config", config, preconfig, - api=API_COMPAT) - -+ @unittest.skipIf(support.check_bolt_optimized, "segfaults on BOLT instrumented binaries") - def test_init_compat_env(self): - preconfig = { - 'allocator': ALLOCATOR_FOR_CONFIG, -@@ -1047,7 +1060,6 @@ - 'use_hash_seed': True, - 'hash_seed': 42, - 'tracemalloc': 2, -- 'perf_profiling': 0, - 'import_time': True, - 'code_debug_ranges': False, - 'malloc_stats': True, -@@ -1074,6 +1086,7 @@ - self.check_all_configs("test_init_compat_env", config, preconfig, - api=API_COMPAT) - -+ @unittest.skipIf(support.check_bolt_optimized, "segfaults on BOLT instrumented binaries") - def test_init_python_env(self): - preconfig = { - 'allocator': ALLOCATOR_FOR_CONFIG, -@@ -1083,7 +1096,6 @@ - 'use_hash_seed': True, - 'hash_seed': 42, - 'tracemalloc': 2, -- 'perf_profiling': 0, - 'import_time': True, - 'code_debug_ranges': False, - 'malloc_stats': True, -@@ -1271,24 +1283,6 @@ - } - self.check_all_configs("test_init_run_main", config, api=API_PYTHON) - -- def test_init_main(self): -- code = ('import _testinternalcapi, json; ' -- 'print(json.dumps(_testinternalcapi.get_configs()))') -- config = { -- 'argv': ['-c', 'arg2'], -- 'orig_argv': ['python3', -- '-c', code, -- 'arg2'], -- 'program_name': './python3', -- 'run_command': code + '\n', -- 'parse_argv': True, -- '_init_main': False, -- 'sys_path_0': '', -- } -- self.check_all_configs("test_init_main", config, -- api=API_PYTHON, -- stderr="Run Python code before _Py_InitializeMain") -- - def test_init_parse_argv(self): - config = { - 'parse_argv': True, -@@ -1613,7 +1607,13 @@ - - with self.tmpdir_with_python() as tmpdir, \ - tempfile.TemporaryDirectory() as pyvenv_home: -+ - ver = sys.version_info -+ base_prefix = sysconfig.get_config_var("prefix") -+ -+ # gh-128690: base_exec_prefix depends if PLATSTDLIB_LANDMARK exists -+ platstdlib = os.path.join(base_prefix, PLATSTDLIB_LANDMARK) -+ change_exec_prefix = not os.path.isdir(platstdlib) - - if not MS_WINDOWS: - lib_dynload = os.path.join(pyvenv_home, -@@ -1637,7 +1637,8 @@ - - paths = self.module_search_paths() - if not MS_WINDOWS: -- paths[-1] = lib_dynload -+ if change_exec_prefix: -+ paths[-1] = lib_dynload - else: - paths = [ - os.path.join(tmpdir, os.path.basename(paths[0])), -@@ -1647,16 +1648,16 @@ - - executable = self.test_exe - base_executable = os.path.join(pyvenv_home, os.path.basename(executable)) -- exec_prefix = pyvenv_home - config = { -- 'base_prefix': sysconfig.get_config_var("prefix"), -- 'base_exec_prefix': exec_prefix, -+ 'base_prefix': base_prefix, - 'exec_prefix': tmpdir, - 'prefix': tmpdir, - 'base_executable': base_executable, - 'executable': executable, - 'module_search_paths': paths, - } -+ if change_exec_prefix: -+ config['base_exec_prefix'] = pyvenv_home - if MS_WINDOWS: - config['base_prefix'] = pyvenv_home - config['stdlib_dir'] = os.path.join(pyvenv_home, 'Lib') -@@ -1763,15 +1764,7 @@ - self.check_all_configs("test_init_warnoptions", config, preconfig, - api=API_PYTHON) - -- def test_init_set_config(self): -- config = { -- '_init_main': 0, -- 'bytes_warning': 2, -- 'warnoptions': ['error::BytesWarning'], -- } -- self.check_all_configs("test_init_set_config", config, -- api=API_ISOLATED) -- -+ @unittest.skipIf(support.check_bolt_optimized, "segfaults on BOLT instrumented binaries") - def test_initconfig_api(self): - preconfig = { - 'configure_locale': True, -@@ -1862,22 +1855,6 @@ - self.assertEqual(err, "") - - --class SetConfigTests(unittest.TestCase): -- def test_set_config(self): -- # bpo-42260: Test _PyInterpreterState_SetConfig() -- import_helper.import_module('_testcapi') -- cmd = [sys.executable, '-X', 'utf8', '-I', '-m', 'test._test_embed_set_config'] -- proc = subprocess.run(cmd, -- stdout=subprocess.PIPE, -- stderr=subprocess.PIPE, -- encoding='utf-8', errors='backslashreplace') -- if proc.returncode and support.verbose: -- print(proc.stdout) -- print(proc.stderr) -- self.assertEqual(proc.returncode, 0, -- (proc.returncode, proc.stdout, proc.stderr)) -- -- - class AuditingTests(EmbeddingTestsMixin, unittest.TestCase): - def test_open_code_hook(self): - self.run_embedded_interpreter("test_open_code_hook") -@@ -2009,56 +1986,5 @@ - self.assertIn("unique-python-message", out) - - --class StdPrinterTests(EmbeddingTestsMixin, unittest.TestCase): -- # Test PyStdPrinter_Type which is used by _PySys_SetPreliminaryStderr(): -- # "Set up a preliminary stderr printer until we have enough -- # infrastructure for the io module in place." -- -- STDOUT_FD = 1 -- -- def create_printer(self, fd): -- ctypes = import_helper.import_module('ctypes') -- PyFile_NewStdPrinter = ctypes.pythonapi.PyFile_NewStdPrinter -- PyFile_NewStdPrinter.argtypes = (ctypes.c_int,) -- PyFile_NewStdPrinter.restype = ctypes.py_object -- return PyFile_NewStdPrinter(fd) -- -- def test_write(self): -- message = "unicode:\xe9-\u20ac-\udc80!\n" -- -- stdout_fd = self.STDOUT_FD -- stdout_fd_copy = os.dup(stdout_fd) -- self.addCleanup(os.close, stdout_fd_copy) -- -- rfd, wfd = os.pipe() -- self.addCleanup(os.close, rfd) -- self.addCleanup(os.close, wfd) -- try: -- # PyFile_NewStdPrinter() only accepts fileno(stdout) -- # or fileno(stderr) file descriptor. -- os.dup2(wfd, stdout_fd) -- -- printer = self.create_printer(stdout_fd) -- printer.write(message) -- finally: -- os.dup2(stdout_fd_copy, stdout_fd) -- -- data = os.read(rfd, 100) -- self.assertEqual(data, message.encode('utf8', 'backslashreplace')) -- -- def test_methods(self): -- fd = self.STDOUT_FD -- printer = self.create_printer(fd) -- self.assertEqual(printer.fileno(), fd) -- self.assertEqual(printer.isatty(), os.isatty(fd)) -- printer.flush() # noop -- printer.close() # noop -- -- def test_disallow_instantiation(self): -- fd = self.STDOUT_FD -- printer = self.create_printer(fd) -- support.check_disallow_instantiation(self, type(printer)) -- -- - if __name__ == "__main__": - unittest.main() -diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py -index b9e13fb8c35..8884295b1ab 100644 ---- a/Lib/test/test_enum.py -+++ b/Lib/test/test_enum.py -@@ -14,7 +14,7 @@ - from enum import Enum, EnumMeta, IntEnum, StrEnum, EnumType, Flag, IntFlag, unique, auto - from enum import STRICT, CONFORM, EJECT, KEEP, _simple_enum, _test_simple_enum - from enum import verify, UNIQUE, CONTINUOUS, NAMED_FLAGS, ReprEnum --from enum import member, nonmember, _iter_bits_lsb -+from enum import member, nonmember, _iter_bits_lsb, EnumDict - from io import StringIO - from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL - from test import support -@@ -5440,6 +5440,37 @@ - self.assertEqual(format(test_type.CONVERT_STRING_TEST_NAME_A), '5') - - -+class TestEnumDict(unittest.TestCase): -+ def test_enum_dict_in_metaclass(self): -+ """Test that EnumDict is usable as a class namespace""" -+ class Meta(type): -+ @classmethod -+ def __prepare__(metacls, cls, bases, **kwds): -+ return EnumDict(cls) -+ -+ class MyClass(metaclass=Meta): -+ a = 1 -+ -+ with self.assertRaises(TypeError): -+ a = 2 # duplicate -+ -+ with self.assertRaises(ValueError): -+ _a_sunder_ = 3 -+ -+ def test_enum_dict_standalone(self): -+ """Test that EnumDict is usable on its own""" -+ enumdict = EnumDict() -+ enumdict['a'] = 1 -+ -+ with self.assertRaises(TypeError): -+ enumdict['a'] = 'other value' -+ -+ # Only MutableMapping interface is overridden for now. -+ # If this stops passing, update the documentation. -+ enumdict |= {'a': 'other value'} -+ self.assertEqual(enumdict['a'], 'other value') -+ -+ - # helpers - - def enum_dir(cls): -diff --git a/Lib/test/test_eof.py b/Lib/test/test_eof.py -index e377383450e..582e5b6de6e 100644 ---- a/Lib/test/test_eof.py -+++ b/Lib/test/test_eof.py -@@ -2,7 +2,7 @@ - - import sys - from codecs import BOM_UTF8 --from test import support -+from test.support import force_not_colorized - from test.support import os_helper - from test.support import script_helper - from test.support import warnings_helper -@@ -44,6 +44,7 @@ - self.assertEqual(cm.exception.text, "ä = '''thîs is ") - self.assertEqual(cm.exception.offset, 5) - -+ @force_not_colorized - def test_EOFS_with_file(self): - expect = ("(, line 1)") - with os_helper.temp_dir() as temp_dir: -@@ -123,6 +124,7 @@ - self.assertEqual(str(cm.exception), expect) - - @unittest.skipIf(not sys.executable, "sys.executable required") -+ @force_not_colorized - def test_line_continuation_EOF_from_file_bpo2180(self): - """Ensure tok_nextc() does not add too many ending newlines.""" - with os_helper.temp_dir() as temp_dir: -diff --git a/Lib/test/test_except_star.py b/Lib/test/test_except_star.py -index c49c6008e08..284907f6121 100644 ---- a/Lib/test/test_except_star.py -+++ b/Lib/test/test_except_star.py -@@ -952,6 +952,49 @@ - self.assertExceptionIsLike(tes, FalsyEG("eg", [TypeError(1)])) - self.assertExceptionIsLike(ves, FalsyEG("eg", [ValueError(2)])) - -+ def test_exception_group_subclass_with_bad_split_func(self): -+ # see gh-128049. -+ class BadEG1(ExceptionGroup): -+ def split(self, *args): -+ return "NOT A 2-TUPLE!" -+ -+ class BadEG2(ExceptionGroup): -+ def split(self, *args): -+ return ("NOT A 2-TUPLE!",) -+ -+ eg_list = [ -+ (BadEG1("eg", [OSError(123), ValueError(456)]), -+ r"split must return a tuple, not str"), -+ (BadEG2("eg", [OSError(123), ValueError(456)]), -+ r"split must return a 2-tuple, got tuple of size 1") -+ ] -+ -+ for eg_class, msg in eg_list: -+ with self.assertRaisesRegex(TypeError, msg) as m: -+ try: -+ raise eg_class -+ except* ValueError: -+ pass -+ except* OSError: -+ pass -+ -+ self.assertExceptionIsLike(m.exception.__context__, eg_class) -+ -+ # we allow tuples of length > 2 for backwards compatibility -+ class WeirdEG(ExceptionGroup): -+ def split(self, *args): -+ return super().split(*args) + ("anything", 123456, None) -+ -+ try: -+ raise WeirdEG("eg", [OSError(123), ValueError(456)]) -+ except* OSError as e: -+ oeg = e -+ except* ValueError as e: -+ veg = e -+ -+ self.assertExceptionIsLike(oeg, WeirdEG("eg", [OSError(123)])) -+ self.assertExceptionIsLike(veg, WeirdEG("eg", [ValueError(456)])) -+ - - class TestExceptStarCleanup(ExceptStarTest): - def test_sys_exception_restored(self): -diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py -index 6ccfa9575f8..3838eb5b27c 100644 ---- a/Lib/test/test_exceptions.py -+++ b/Lib/test/test_exceptions.py -@@ -1465,6 +1465,7 @@ - - @cpython_only - @unittest.skipIf(_testcapi is None, "requires _testcapi") -+ @force_not_colorized - def test_recursion_normalizing_infinite_exception(self): - # Issue #30697. Test that a RecursionError is raised when - # maximum recursion depth has been exceeded when creating -@@ -1677,10 +1678,13 @@ - - obj = BrokenDel() - with support.catch_unraisable_exception() as cm: -+ obj_repr = repr(type(obj).__del__) - del obj - - gc_collect() # For PyPy or other GCs. -- self.assertEqual(cm.unraisable.object, BrokenDel.__del__) -+ self.assertEqual(cm.unraisable.err_msg, -+ f"Exception ignored while calling " -+ f"deallocator {obj_repr}") - self.assertIsNotNone(cm.unraisable.exc_traceback) - - def test_unhandled(self): -@@ -2180,6 +2184,7 @@ - self.assertEqual(result[-len(expected):], expected) - - -+@support.force_not_colorized_test_class - class SyntaxErrorTests(unittest.TestCase): - maxDiff = None - -@@ -2274,6 +2279,7 @@ - self.assertIn(expected, err.getvalue()) - the_exception = exc - -+ @force_not_colorized - def test_subclass(self): - class MySyntaxError(SyntaxError): - pass -diff --git a/Lib/test/test_external_inspection.py b/Lib/test/test_external_inspection.py -index d896fec73d1..2ab48a4778b 100644 ---- a/Lib/test/test_external_inspection.py -+++ b/Lib/test/test_external_inspection.py -@@ -13,8 +13,10 @@ - try: - from _testexternalinspection import PROCESS_VM_READV_SUPPORTED - from _testexternalinspection import get_stack_trace -+ from _testexternalinspection import get_async_stack_trace - except ImportError: -- raise unittest.SkipTest("Test only runs when _testexternalinspection is available") -+ raise unittest.SkipTest( -+ "Test only runs when _testexternalinspection is available") - - def _make_test_script(script_dir, script_basename, source): - to_return = make_script(script_dir, script_basename, source) -@@ -23,12 +25,14 @@ - - class TestGetStackTrace(unittest.TestCase): - -- @unittest.skipIf(sys.platform != "darwin" and sys.platform != "linux", "Test only runs on Linux and MacOS") -- @unittest.skipIf(sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, "Test only runs on Linux with process_vm_readv support") -+ @unittest.skipIf(sys.platform != "darwin" and sys.platform != "linux", -+ "Test only runs on Linux and MacOS") -+ @unittest.skipIf(sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, -+ "Test only runs on Linux with process_vm_readv support") - def test_remote_stack_trace(self): - # Spawn a process with some realistic Python code - script = textwrap.dedent("""\ -- import time, sys, os -+ import time, sys - def bar(): - for x in range(100): - if x == 50: -@@ -37,8 +41,8 @@ - foo() - - def foo(): -- fifo = sys.argv[1] -- with open(sys.argv[1], "w") as fifo: -+ fifo_path = sys.argv[1] -+ with open(fifo_path, "w") as fifo: - fifo.write("ready") - time.sleep(1000) - -@@ -74,8 +78,281 @@ - ] - self.assertEqual(stack_trace, expected_stack_trace) - -- @unittest.skipIf(sys.platform != "darwin" and sys.platform != "linux", "Test only runs on Linux and MacOS") -- @unittest.skipIf(sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, "Test only runs on Linux with process_vm_readv support") -+ @unittest.skipIf(sys.platform != "darwin" and sys.platform != "linux", -+ "Test only runs on Linux and MacOS") -+ @unittest.skipIf(sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, -+ "Test only runs on Linux with process_vm_readv support") -+ def test_async_remote_stack_trace(self): -+ # Spawn a process with some realistic Python code -+ script = textwrap.dedent("""\ -+ import asyncio -+ import time -+ import sys -+ -+ def c5(): -+ fifo_path = sys.argv[1] -+ with open(fifo_path, "w") as fifo: -+ fifo.write("ready") -+ time.sleep(10000) -+ -+ async def c4(): -+ await asyncio.sleep(0) -+ c5() -+ -+ async def c3(): -+ await c4() -+ -+ async def c2(): -+ await c3() -+ -+ async def c1(task): -+ await task -+ -+ async def main(): -+ async with asyncio.TaskGroup() as tg: -+ task = tg.create_task(c2(), name="c2_root") -+ tg.create_task(c1(task), name="sub_main_1") -+ tg.create_task(c1(task), name="sub_main_2") -+ -+ def new_eager_loop(): -+ loop = asyncio.new_event_loop() -+ eager_task_factory = asyncio.create_eager_task_factory( -+ asyncio.Task) -+ loop.set_task_factory(eager_task_factory) -+ return loop -+ -+ asyncio.run(main(), loop_factory={TASK_FACTORY}) -+ """) -+ stack_trace = None -+ for task_factory_variant in "asyncio.new_event_loop", "new_eager_loop": -+ with ( -+ self.subTest(task_factory_variant=task_factory_variant), -+ os_helper.temp_dir() as work_dir, -+ ): -+ script_dir = os.path.join(work_dir, "script_pkg") -+ os.mkdir(script_dir) -+ fifo = f"{work_dir}/the_fifo" -+ os.mkfifo(fifo) -+ script_name = _make_test_script( -+ script_dir, 'script', -+ script.format(TASK_FACTORY=task_factory_variant)) -+ try: -+ p = subprocess.Popen( -+ [sys.executable, script_name, str(fifo)] -+ ) -+ with open(fifo, "r") as fifo_file: -+ response = fifo_file.read() -+ self.assertEqual(response, "ready") -+ stack_trace = get_async_stack_trace(p.pid) -+ except PermissionError: -+ self.skipTest( -+ "Insufficient permissions to read the stack trace") -+ finally: -+ os.remove(fifo) -+ p.kill() -+ p.terminate() -+ p.wait(timeout=SHORT_TIMEOUT) -+ -+ # sets are unordered, so we want to sort "awaited_by"s -+ stack_trace[2].sort(key=lambda x: x[1]) -+ -+ root_task = "Task-1" -+ expected_stack_trace = [ -+ ["c5", "c4", "c3", "c2"], -+ "c2_root", -+ [ -+ [["main"], root_task, []], -+ [["c1"], "sub_main_1", [[["main"], root_task, []]]], -+ [["c1"], "sub_main_2", [[["main"], root_task, []]]], -+ ], -+ ] -+ self.assertEqual(stack_trace, expected_stack_trace) -+ -+ @unittest.skipIf(sys.platform != "darwin" and sys.platform != "linux", -+ "Test only runs on Linux and MacOS") -+ @unittest.skipIf(sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, -+ "Test only runs on Linux with process_vm_readv support") -+ def test_asyncgen_remote_stack_trace(self): -+ # Spawn a process with some realistic Python code -+ script = textwrap.dedent("""\ -+ import asyncio -+ import time -+ import sys -+ -+ async def gen_nested_call(): -+ fifo_path = sys.argv[1] -+ with open(fifo_path, "w") as fifo: -+ fifo.write("ready") -+ time.sleep(10000) -+ -+ async def gen(): -+ for num in range(2): -+ yield num -+ if num == 1: -+ await gen_nested_call() -+ -+ async def main(): -+ async for el in gen(): -+ pass -+ -+ asyncio.run(main()) -+ """) -+ stack_trace = None -+ with os_helper.temp_dir() as work_dir: -+ script_dir = os.path.join(work_dir, "script_pkg") -+ os.mkdir(script_dir) -+ fifo = f"{work_dir}/the_fifo" -+ os.mkfifo(fifo) -+ script_name = _make_test_script(script_dir, 'script', script) -+ try: -+ p = subprocess.Popen([sys.executable, script_name, str(fifo)]) -+ with open(fifo, "r") as fifo_file: -+ response = fifo_file.read() -+ self.assertEqual(response, "ready") -+ stack_trace = get_async_stack_trace(p.pid) -+ except PermissionError: -+ self.skipTest("Insufficient permissions to read the stack trace") -+ finally: -+ os.remove(fifo) -+ p.kill() -+ p.terminate() -+ p.wait(timeout=SHORT_TIMEOUT) -+ -+ # sets are unordered, so we want to sort "awaited_by"s -+ stack_trace[2].sort(key=lambda x: x[1]) -+ -+ expected_stack_trace = [ -+ ['gen_nested_call', 'gen', 'main'], 'Task-1', [] -+ ] -+ self.assertEqual(stack_trace, expected_stack_trace) -+ -+ @unittest.skipIf(sys.platform != "darwin" and sys.platform != "linux", -+ "Test only runs on Linux and MacOS") -+ @unittest.skipIf(sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, -+ "Test only runs on Linux with process_vm_readv support") -+ def test_async_gather_remote_stack_trace(self): -+ # Spawn a process with some realistic Python code -+ script = textwrap.dedent("""\ -+ import asyncio -+ import time -+ import sys -+ -+ async def deep(): -+ await asyncio.sleep(0) -+ fifo_path = sys.argv[1] -+ with open(fifo_path, "w") as fifo: -+ fifo.write("ready") -+ time.sleep(10000) -+ -+ async def c1(): -+ await asyncio.sleep(0) -+ await deep() -+ -+ async def c2(): -+ await asyncio.sleep(0) -+ -+ async def main(): -+ await asyncio.gather(c1(), c2()) -+ -+ asyncio.run(main()) -+ """) -+ stack_trace = None -+ with os_helper.temp_dir() as work_dir: -+ script_dir = os.path.join(work_dir, "script_pkg") -+ os.mkdir(script_dir) -+ fifo = f"{work_dir}/the_fifo" -+ os.mkfifo(fifo) -+ script_name = _make_test_script(script_dir, 'script', script) -+ try: -+ p = subprocess.Popen([sys.executable, script_name, str(fifo)]) -+ with open(fifo, "r") as fifo_file: -+ response = fifo_file.read() -+ self.assertEqual(response, "ready") -+ stack_trace = get_async_stack_trace(p.pid) -+ except PermissionError: -+ self.skipTest( -+ "Insufficient permissions to read the stack trace") -+ finally: -+ os.remove(fifo) -+ p.kill() -+ p.terminate() -+ p.wait(timeout=SHORT_TIMEOUT) -+ -+ # sets are unordered, so we want to sort "awaited_by"s -+ stack_trace[2].sort(key=lambda x: x[1]) -+ -+ expected_stack_trace = [ -+ ['deep', 'c1'], 'Task-2', [[['main'], 'Task-1', []]] -+ ] -+ self.assertEqual(stack_trace, expected_stack_trace) -+ -+ @unittest.skipIf(sys.platform != "darwin" and sys.platform != "linux", -+ "Test only runs on Linux and MacOS") -+ @unittest.skipIf(sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, -+ "Test only runs on Linux with process_vm_readv support") -+ def test_async_staggered_race_remote_stack_trace(self): -+ # Spawn a process with some realistic Python code -+ script = textwrap.dedent("""\ -+ import asyncio.staggered -+ import time -+ import sys -+ -+ async def deep(): -+ await asyncio.sleep(0) -+ fifo_path = sys.argv[1] -+ with open(fifo_path, "w") as fifo: -+ fifo.write("ready") -+ time.sleep(10000) -+ -+ async def c1(): -+ await asyncio.sleep(0) -+ await deep() -+ -+ async def c2(): -+ await asyncio.sleep(10000) -+ -+ async def main(): -+ await asyncio.staggered.staggered_race( -+ [c1, c2], -+ delay=None, -+ ) -+ -+ asyncio.run(main()) -+ """) -+ stack_trace = None -+ with os_helper.temp_dir() as work_dir: -+ script_dir = os.path.join(work_dir, "script_pkg") -+ os.mkdir(script_dir) -+ fifo = f"{work_dir}/the_fifo" -+ os.mkfifo(fifo) -+ script_name = _make_test_script(script_dir, 'script', script) -+ try: -+ p = subprocess.Popen([sys.executable, script_name, str(fifo)]) -+ with open(fifo, "r") as fifo_file: -+ response = fifo_file.read() -+ self.assertEqual(response, "ready") -+ stack_trace = get_async_stack_trace(p.pid) -+ except PermissionError: -+ self.skipTest( -+ "Insufficient permissions to read the stack trace") -+ finally: -+ os.remove(fifo) -+ p.kill() -+ p.terminate() -+ p.wait(timeout=SHORT_TIMEOUT) -+ -+ # sets are unordered, so we want to sort "awaited_by"s -+ stack_trace[2].sort(key=lambda x: x[1]) -+ -+ expected_stack_trace = [ -+ ['deep', 'c1', 'run_one_coro'], 'Task-2', [[['main'], 'Task-1', []]] -+ ] -+ self.assertEqual(stack_trace, expected_stack_trace) -+ -+ @unittest.skipIf(sys.platform != "darwin" and sys.platform != "linux", -+ "Test only runs on Linux and MacOS") -+ @unittest.skipIf(sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED, -+ "Test only runs on Linux with process_vm_readv support") - def test_self_trace(self): - stack_trace = get_stack_trace(os.getpid()) - self.assertEqual(stack_trace[0], "test_self_trace") -diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py -index 60815be96e1..bcebaef0a51 100644 ---- a/Lib/test/test_faulthandler.py -+++ b/Lib/test/test_faulthandler.py -@@ -7,7 +7,7 @@ - import subprocess - import sys - from test import support --from test.support import os_helper, script_helper, is_android, MS_WINDOWS -+from test.support import os_helper, script_helper, is_android, MS_WINDOWS, threading_helper - import tempfile - import unittest - from textwrap import dedent -@@ -100,7 +100,11 @@ - - Raise an error if the output doesn't match the expected format. - """ -- if all_threads: -+ all_threads_disabled = ( -+ all_threads -+ and (not sys._is_gil_enabled()) -+ ) -+ if all_threads and not all_threads_disabled: - if know_current_thread: - header = 'Current thread 0x[0-9a-f]+' - else: -@@ -111,10 +115,15 @@ - if py_fatal_error: - regex.append("Python runtime state: initialized") - regex.append('') -+ if all_threads_disabled and not py_fatal_error: -+ regex.append("") - regex.append(fr'{header} \(most recent call first\):') -- if garbage_collecting: -- regex.append(' Garbage-collecting') -- regex.append(fr' File "", line {lineno} in {function}') -+ if support.Py_GIL_DISABLED and py_fatal_error and not know_current_thread: -+ regex.append(" ") -+ else: -+ if garbage_collecting and not all_threads_disabled: -+ regex.append(' Garbage-collecting') -+ regex.append(fr' File "", line {lineno} in {function}') - regex = '\n'.join(regex) - - if other_regex: -@@ -786,6 +795,7 @@ - def test_register_threads(self): - self.check_register(all_threads=True) - -+ @support.skip_if_sanitizer("gh-129825: hangs under TSAN", thread=True) - def test_register_chain(self): - self.check_register(chain=True) - -@@ -896,6 +906,34 @@ - self.assertEqual(output, []) - self.assertEqual(exitcode, 0) - -+ @threading_helper.requires_working_threading() -+ @unittest.skipUnless(support.Py_GIL_DISABLED, "only meaningful if the GIL is disabled") -+ def test_free_threaded_dump_traceback(self): -+ # gh-128400: Other threads need to be paused to invoke faulthandler -+ code = dedent(""" -+ import faulthandler -+ from threading import Thread, Event -+ -+ class Waiter(Thread): -+ def __init__(self): -+ Thread.__init__(self) -+ self.running = Event() -+ self.stop = Event() -+ -+ def run(self): -+ self.running.set() -+ self.stop.wait() -+ -+ for _ in range(100): -+ waiter = Waiter() -+ waiter.start() -+ waiter.running.wait() -+ faulthandler.dump_traceback(all_threads=True) -+ waiter.stop.set() -+ waiter.join() -+ """) -+ _, exitcode = self.get_output(code) -+ self.assertEqual(exitcode, 0) - - if __name__ == "__main__": - unittest.main() -diff --git a/Lib/test/test_frame.py b/Lib/test/test_frame.py -index 11f191700cc..4d086064023 100644 ---- a/Lib/test/test_frame.py -+++ b/Lib/test/test_frame.py -@@ -222,6 +222,56 @@ - with self.assertRaises(AttributeError): - del f.f_lineno - -+ def test_f_generator(self): -+ # Test f_generator in different contexts. -+ -+ def t0(): -+ def nested(): -+ frame = sys._getframe() -+ return frame.f_generator -+ -+ def gen(): -+ yield nested() -+ -+ g = gen() -+ try: -+ return next(g) -+ finally: -+ g.close() -+ -+ def t1(): -+ frame = sys._getframe() -+ return frame.f_generator -+ -+ def t2(): -+ frame = sys._getframe() -+ yield frame.f_generator -+ -+ async def t3(): -+ frame = sys._getframe() -+ return frame.f_generator -+ -+ # For regular functions f_generator is None -+ self.assertIsNone(t0()) -+ self.assertIsNone(t1()) -+ -+ # For generators f_generator is equal to self -+ g = t2() -+ try: -+ frame_g = next(g) -+ self.assertIs(g, frame_g) -+ finally: -+ g.close() -+ -+ # Ditto for coroutines -+ c = t3() -+ try: -+ c.send(None) -+ except StopIteration as ex: -+ self.assertIs(ex.value, c) -+ else: -+ raise AssertionError('coroutine did not exit') -+ - - class ReprTest(unittest.TestCase): - """ -@@ -723,51 +773,6 @@ - self.assertIs(catcher.unraisable.exc_type, TypeError) - self.assertIsNone(weak()) - --@unittest.skipIf(_testcapi is None, 'need _testcapi') --class TestCAPI(unittest.TestCase): -- def getframe(self): -- return sys._getframe() -- -- def test_frame_getters(self): -- frame = self.getframe() -- self.assertEqual(frame.f_locals, _testcapi.frame_getlocals(frame)) -- self.assertIs(frame.f_globals, _testcapi.frame_getglobals(frame)) -- self.assertIs(frame.f_builtins, _testcapi.frame_getbuiltins(frame)) -- self.assertEqual(frame.f_lasti, _testcapi.frame_getlasti(frame)) -- -- def test_getvar(self): -- current_frame = sys._getframe() -- x = 1 -- self.assertEqual(_testcapi.frame_getvar(current_frame, "x"), 1) -- self.assertEqual(_testcapi.frame_getvarstring(current_frame, b"x"), 1) -- with self.assertRaises(NameError): -- _testcapi.frame_getvar(current_frame, "y") -- with self.assertRaises(NameError): -- _testcapi.frame_getvarstring(current_frame, b"y") -- -- # wrong name type -- with self.assertRaises(TypeError): -- _testcapi.frame_getvar(current_frame, b'x') -- with self.assertRaises(TypeError): -- _testcapi.frame_getvar(current_frame, 123) -- -- def getgenframe(self): -- yield sys._getframe() -- -- def test_frame_get_generator(self): -- gen = self.getgenframe() -- frame = next(gen) -- self.assertIs(gen, _testcapi.frame_getgenerator(frame)) -- -- def test_frame_fback_api(self): -- """Test that accessing `f_back` does not cause a segmentation fault on -- a frame created with `PyFrame_New` (GH-99110).""" -- def dummy(): -- pass -- -- frame = _testcapi.frame_new(dummy.__code__, globals(), locals()) -- # The following line should not cause a segmentation fault. -- self.assertIsNone(frame.f_back) - - if __name__ == "__main__": - unittest.main() -diff --git a/Lib/test/test_free_threading/test_dict.py b/Lib/test/test_free_threading/test_dict.py -index 13717cb39fa..4f605e0c51f 100644 ---- a/Lib/test/test_free_threading/test_dict.py -+++ b/Lib/test/test_free_threading/test_dict.py -@@ -5,7 +5,7 @@ - - from ast import Or - from functools import partial --from threading import Thread -+from threading import Barrier, Thread - from unittest import TestCase - - try: -@@ -142,6 +142,27 @@ - for ref in thread_list: - self.assertIsNone(ref()) - -+ def test_racing_get_set_dict(self): -+ """Races getting and setting a dict should be thread safe""" -+ THREAD_COUNT = 10 -+ barrier = Barrier(THREAD_COUNT) -+ def work(d): -+ barrier.wait() -+ for _ in range(1000): -+ d[10] = 0 -+ d.get(10, None) -+ _ = d[10] -+ -+ d = {} -+ worker_threads = [] -+ for ii in range(THREAD_COUNT): -+ worker_threads.append(Thread(target=work, args=[d])) -+ for t in worker_threads: -+ t.start() -+ for t in worker_threads: -+ t.join() -+ -+ - def test_racing_set_object_dict(self): - """Races assigning to __dict__ should be thread safe""" - class C: pass ---- /dev/null -+++ b/Lib/test/test_free_threading/test_func_annotations.py -@@ -0,0 +1,67 @@ -+import concurrent.futures -+import unittest -+import inspect -+from threading import Thread, Barrier -+from unittest import TestCase -+ -+from test.support import threading_helper, Py_GIL_DISABLED -+ -+threading_helper.requires_working_threading(module=True) -+ -+ -+def get_func_annotation(f, b): -+ b.wait() -+ return inspect.get_annotations(f) -+ -+ -+def get_func_annotation_dunder(f, b): -+ b.wait() -+ return f.__annotations__ -+ -+ -+def set_func_annotation(f, b): -+ b.wait() -+ f.__annotations__ = {'x': int, 'y': int, 'return': int} -+ return f.__annotations__ -+ -+ -+@unittest.skipUnless(Py_GIL_DISABLED, "Enable only in FT build") -+class TestFTFuncAnnotations(TestCase): -+ NUM_THREADS = 8 -+ -+ def test_concurrent_read(self): -+ def f(x: int) -> int: -+ return x + 1 -+ -+ for _ in range(100): -+ with concurrent.futures.ThreadPoolExecutor(max_workers=self.NUM_THREADS) as executor: -+ b = Barrier(self.NUM_THREADS) -+ futures = {executor.submit(get_func_annotation, f, b): i for i in range(self.NUM_THREADS)} -+ for fut in concurrent.futures.as_completed(futures): -+ annotate = fut.result() -+ self.assertIsNotNone(annotate) -+ self.assertEqual(annotate, {'x': int, 'return': int}) -+ -+ with concurrent.futures.ThreadPoolExecutor(max_workers=self.NUM_THREADS) as executor: -+ b = Barrier(self.NUM_THREADS) -+ futures = {executor.submit(get_func_annotation_dunder, f, b): i for i in range(self.NUM_THREADS)} -+ for fut in concurrent.futures.as_completed(futures): -+ annotate = fut.result() -+ self.assertIsNotNone(annotate) -+ self.assertEqual(annotate, {'x': int, 'return': int}) -+ -+ def test_concurrent_write(self): -+ def bar(x: int, y: float) -> float: -+ return y ** x -+ -+ for _ in range(100): -+ with concurrent.futures.ThreadPoolExecutor(max_workers=self.NUM_THREADS) as executor: -+ b = Barrier(self.NUM_THREADS) -+ futures = {executor.submit(set_func_annotation, bar, b): i for i in range(self.NUM_THREADS)} -+ for fut in concurrent.futures.as_completed(futures): -+ annotate = fut.result() -+ self.assertIsNotNone(annotate) -+ self.assertEqual(annotate, {'x': int, 'y': int, 'return': int}) -+ -+ # func_get_annotations returns in-place dict, so bar.__annotations__ should be modified as well -+ self.assertEqual(bar.__annotations__, {'x': int, 'y': int, 'return': int}) -diff --git a/Lib/test/test_free_threading/test_races.py b/Lib/test/test_free_threading/test_races.py -index 09e1d52e350..85aa69c8cd4 100644 ---- a/Lib/test/test_free_threading/test_races.py -+++ b/Lib/test/test_free_threading/test_races.py -@@ -4,6 +4,7 @@ - import threading - import time - import unittest -+import _testinternalcapi - - from test.support import threading_helper - -@@ -129,6 +130,161 @@ - # with the cell binding being changed). - do_race(access, mutate) - -+ def test_racing_to_bool(self): -+ -+ seq = [1] -+ -+ class C: -+ def __bool__(self): -+ return False -+ -+ def access(): -+ if seq: -+ return 1 -+ else: -+ return 2 -+ -+ def mutate(): -+ nonlocal seq -+ seq = [1] -+ time.sleep(0) -+ seq = C() -+ time.sleep(0) -+ -+ do_race(access, mutate) -+ -+ def test_racing_store_attr_slot(self): -+ class C: -+ __slots__ = ['x', '__dict__'] -+ -+ c = C() -+ -+ def set_slot(): -+ for i in range(10): -+ c.x = i -+ time.sleep(0) -+ -+ def change_type(): -+ def set_x(self, x): -+ pass -+ -+ def get_x(self): -+ pass -+ -+ C.x = property(get_x, set_x) -+ time.sleep(0) -+ del C.x -+ time.sleep(0) -+ -+ do_race(set_slot, change_type) -+ -+ def set_getattribute(): -+ C.__getattribute__ = lambda self, x: x -+ time.sleep(0) -+ del C.__getattribute__ -+ time.sleep(0) -+ -+ do_race(set_slot, set_getattribute) -+ -+ def test_racing_store_attr_instance_value(self): -+ class C: -+ pass -+ -+ c = C() -+ -+ def set_value(): -+ for i in range(100): -+ c.x = i -+ -+ set_value() -+ -+ def read(): -+ x = c.x -+ -+ def mutate(): -+ # Adding a property for 'x' should unspecialize it. -+ C.x = property(lambda self: None, lambda self, x: None) -+ time.sleep(0) -+ del C.x -+ time.sleep(0) -+ -+ do_race(read, mutate) -+ -+ def test_racing_store_attr_with_hint(self): -+ class C: -+ pass -+ -+ c = C() -+ for i in range(29): -+ setattr(c, f"_{i}", None) -+ -+ def set_value(): -+ for i in range(100): -+ c.x = i -+ -+ set_value() -+ -+ def read(): -+ x = c.x -+ -+ def mutate(): -+ # Adding a property for 'x' should unspecialize it. -+ C.x = property(lambda self: None, lambda self, x: None) -+ time.sleep(0) -+ del C.x -+ time.sleep(0) -+ -+ do_race(read, mutate) -+ -+ def make_shared_key_dict(self): -+ class C: -+ pass -+ -+ a = C() -+ a.x = 1 -+ return a.__dict__ -+ -+ def test_racing_store_attr_dict(self): -+ """Test STORE_ATTR with various dictionary types.""" -+ class C: -+ pass -+ -+ c = C() -+ -+ def set_value(): -+ for i in range(20): -+ c.x = i -+ -+ def mutate(): -+ nonlocal c -+ c.x = 1 -+ self.assertTrue(_testinternalcapi.has_inline_values(c)) -+ for i in range(30): -+ setattr(c, f"_{i}", None) -+ self.assertFalse(_testinternalcapi.has_inline_values(c.__dict__)) -+ c.__dict__ = self.make_shared_key_dict() -+ self.assertTrue(_testinternalcapi.has_split_table(c.__dict__)) -+ c.__dict__[1] = None -+ self.assertFalse(_testinternalcapi.has_split_table(c.__dict__)) -+ c = C() -+ -+ do_race(set_value, mutate) -+ -+ def test_racing_recursion_limit(self): -+ def something_recursive(): -+ def count(n): -+ if n > 0: -+ return count(n - 1) + 1 -+ return 0 -+ -+ count(50) -+ -+ def set_recursion_limit(): -+ for limit in range(100, 200): -+ sys.setrecursionlimit(limit) -+ -+ do_race(something_recursive, set_recursion_limit) -+ - - if __name__ == "__main__": - unittest.main() -diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py -index c359f2ecce0..1d96b7a2c24 100644 ---- a/Lib/test/test_fstring.py -+++ b/Lib/test/test_fstring.py -@@ -1649,6 +1649,14 @@ - #self.assertEqual(f'X{x =}Y', 'Xx\t='+repr(x)+'Y') - #self.assertEqual(f'X{x = }Y', 'Xx\t=\t'+repr(x)+'Y') - -+ def test_debug_expressions_are_raw_strings(self): -+ -+ self.assertEqual(f'{b"\N{OX}"=}', 'b"\\N{OX}"=b\'\\\\N{OX}\'') -+ self.assertEqual(f'{r"\xff"=}', 'r"\\xff"=\'\\\\xff\'') -+ self.assertEqual(f'{r"\n"=}', 'r"\\n"=\'\\\\n\'') -+ self.assertEqual(f"{'\''=}", "'\\''=\"'\"") -+ self.assertEqual(f'{'\xc5'=}', r"'\xc5'='Ã…'") -+ - def test_walrus(self): - x = 20 - # This isn't an assignment expression, it's 'x', with a format -@@ -1757,5 +1765,23 @@ - for s in ["", "some string"]: - self.assertEqual(get_code(f"'{s}'"), get_code(f"f'{s}'")) - -+ def test_gh129093(self): -+ self.assertEqual(f'{1==2=}', '1==2=False') -+ self.assertEqual(f'{1 == 2=}', '1 == 2=False') -+ self.assertEqual(f'{1!=2=}', '1!=2=True') -+ self.assertEqual(f'{1 != 2=}', '1 != 2=True') -+ -+ self.assertEqual(f'{(1) != 2=}', '(1) != 2=True') -+ self.assertEqual(f'{(1*2) != (3)=}', '(1*2) != (3)=True') -+ -+ self.assertEqual(f'{1 != 2 == 3 != 4=}', '1 != 2 == 3 != 4=False') -+ self.assertEqual(f'{1 == 2 != 3 == 4=}', '1 == 2 != 3 == 4=False') -+ -+ self.assertEqual(f'{f'{1==2=}'=}', "f'{1==2=}'='1==2=False'") -+ self.assertEqual(f'{f'{1 == 2=}'=}', "f'{1 == 2=}'='1 == 2=False'") -+ self.assertEqual(f'{f'{1!=2=}'=}', "f'{1!=2=}'='1!=2=True'") -+ self.assertEqual(f'{f'{1 != 2=}'=}', "f'{1 != 2=}'='1 != 2=True'") -+ -+ - if __name__ == '__main__': - unittest.main() -diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py -index ffd2adb8665..1b7a76bec83 100644 ---- a/Lib/test/test_functools.py -+++ b/Lib/test/test_functools.py -@@ -473,6 +473,12 @@ - self.assertEqual(a.cmeth(3, b=4), ((1, A, 3), {'a': 2, 'b': 4})) - self.assertEqual(a.smeth(3, b=4), ((1, 3), {'a': 2, 'b': 4})) - -+ def test_partial_genericalias(self): -+ alias = self.partial[int] -+ self.assertIs(alias.__origin__, self.partial) -+ self.assertEqual(alias.__args__, (int,)) -+ self.assertEqual(alias.__parameters__, ()) -+ - - @unittest.skipUnless(c_functools, 'requires the C _functools module') - class TestPartialC(TestPartial, unittest.TestCase): -@@ -639,11 +645,11 @@ - - def test_unbound_method_retrieval(self): - obj = self.A -- self.assertFalse(hasattr(obj.both, "__self__")) -- self.assertFalse(hasattr(obj.nested, "__self__")) -- self.assertFalse(hasattr(obj.over_partial, "__self__")) -- self.assertFalse(hasattr(obj.static, "__self__")) -- self.assertFalse(hasattr(self.a.static, "__self__")) -+ self.assertNotHasAttr(obj.both, "__self__") -+ self.assertNotHasAttr(obj.nested, "__self__") -+ self.assertNotHasAttr(obj.over_partial, "__self__") -+ self.assertNotHasAttr(obj.static, "__self__") -+ self.assertNotHasAttr(self.a.static, "__self__") - - def test_descriptors(self): - for obj in [self.A, self.a]: -@@ -785,7 +791,7 @@ - self.assertNotEqual(wrapper.__qualname__, f.__qualname__) - self.assertEqual(wrapper.__doc__, None) - self.assertEqual(wrapper.__annotations__, {}) -- self.assertFalse(hasattr(wrapper, 'attr')) -+ self.assertNotHasAttr(wrapper, 'attr') - - def test_selective_update(self): - def f(): -@@ -834,7 +840,7 @@ - pass - functools.update_wrapper(wrapper, max) - self.assertEqual(wrapper.__name__, 'max') -- self.assertTrue(wrapper.__doc__.startswith('max(')) -+ self.assertStartsWith(wrapper.__doc__, 'max(') - self.assertEqual(wrapper.__annotations__, {}) - - def test_update_type_wrapper(self): -@@ -904,7 +910,7 @@ - self.assertEqual(wrapper.__name__, 'wrapper') - self.assertNotEqual(wrapper.__qualname__, f.__qualname__) - self.assertEqual(wrapper.__doc__, None) -- self.assertFalse(hasattr(wrapper, 'attr')) -+ self.assertNotHasAttr(wrapper, 'attr') - - def test_selective_update(self): - def f(): -@@ -1039,6 +1045,12 @@ - class TestReducePy(TestReduce, unittest.TestCase): - reduce = staticmethod(py_functools.reduce) - -+ def test_reduce_with_kwargs(self): -+ with self.assertWarns(DeprecationWarning): -+ self.reduce(function=lambda x, y: x + y, sequence=[1, 2, 3, 4, 5], initial=1) -+ with self.assertWarns(DeprecationWarning): -+ self.reduce(lambda x, y: x + y, sequence=[1, 2, 3, 4, 5], initial=1) -+ - - class TestCmpToKey: - -@@ -2055,6 +2067,7 @@ - - @support.skip_on_s390x - @unittest.skipIf(support.is_wasi, "WASI has limited C stack") -+ @support.skip_if_sanitizer("requires deep stack", thread=True) - @support.skip_emscripten_stack_overflow() - def test_lru_recursion(self): - -@@ -2654,15 +2667,15 @@ - a.t(0) - self.assertEqual(a.arg, "int") - aa = A() -- self.assertFalse(hasattr(aa, 'arg')) -+ self.assertNotHasAttr(aa, 'arg') - a.t('') - self.assertEqual(a.arg, "str") - aa = A() -- self.assertFalse(hasattr(aa, 'arg')) -+ self.assertNotHasAttr(aa, 'arg') - a.t(0.0) - self.assertEqual(a.arg, "base") - aa = A() -- self.assertFalse(hasattr(aa, 'arg')) -+ self.assertNotHasAttr(aa, 'arg') - - def test_staticmethod_register(self): - class A: -@@ -3024,16 +3037,16 @@ - @i.register(42) - def _(arg): - return "I annotated with a non-type" -- self.assertTrue(str(exc.exception).startswith(msg_prefix + "42")) -- self.assertTrue(str(exc.exception).endswith(msg_suffix)) -+ self.assertStartsWith(str(exc.exception), msg_prefix + "42") -+ self.assertEndsWith(str(exc.exception), msg_suffix) - with self.assertRaises(TypeError) as exc: - @i.register - def _(arg): - return "I forgot to annotate" -- self.assertTrue(str(exc.exception).startswith(msg_prefix + -+ self.assertStartsWith(str(exc.exception), msg_prefix + - "._" -- )) -- self.assertTrue(str(exc.exception).endswith(msg_suffix)) -+ ) -+ self.assertEndsWith(str(exc.exception), msg_suffix) - - with self.assertRaises(TypeError) as exc: - @i.register -@@ -3043,23 +3056,23 @@ - # types from `typing`. Instead, annotate with regular types - # or ABCs. - return "I annotated with a generic collection" -- self.assertTrue(str(exc.exception).startswith( -+ self.assertStartsWith(str(exc.exception), - "Invalid annotation for 'arg'." -- )) -- self.assertTrue(str(exc.exception).endswith( -+ ) -+ self.assertEndsWith(str(exc.exception), - 'typing.Iterable[str] is not a class.' -- )) -+ ) - - with self.assertRaises(TypeError) as exc: - @i.register - def _(arg: typing.Union[int, typing.Iterable[str]]): - return "Invalid Union" -- self.assertTrue(str(exc.exception).startswith( -+ self.assertStartsWith(str(exc.exception), - "Invalid annotation for 'arg'." -- )) -- self.assertTrue(str(exc.exception).endswith( -+ ) -+ self.assertEndsWith(str(exc.exception), - 'typing.Union[int, typing.Iterable[str]] not all arguments are classes.' -- )) -+ ) - - def test_invalid_positional_argument(self): - @functools.singledispatch -diff --git a/Lib/test/test_gdb/util.py b/Lib/test/test_gdb/util.py -index 8fe9cfc5433..8097fd52aba 100644 ---- a/Lib/test/test_gdb/util.py -+++ b/Lib/test/test_gdb/util.py -@@ -280,11 +280,6 @@ - - return out - -- def assertEndsWith(self, actual, exp_end): -- '''Ensure that the given "actual" string ends with "exp_end"''' -- self.assertTrue(actual.endswith(exp_end), -- msg='%r did not end with %r' % (actual, exp_end)) -- - def assertMultilineMatches(self, actual, pattern): - m = re.match(pattern, actual, re.DOTALL) - if not m: -diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py -index 9c65e81dfe4..0e0f28be6b2 100644 ---- a/Lib/test/test_generated_cases.py -+++ b/Lib/test/test_generated_cases.py -@@ -281,12 +281,12 @@ - ) - - with open(self.temp_output_filename) as temp_output: -- lines = temp_output.readlines() -- while lines and lines[0].startswith(("// ", "#", " #", "\n")): -- lines.pop(0) -- while lines and lines[-1].startswith(("#", "\n")): -- lines.pop(-1) -- actual = "".join(lines) -+ lines = temp_output.read() -+ _, rest = lines.split(tier1_generator.INSTRUCTION_START_MARKER) -+ instructions, labels_with_prelude_and_postlude = rest.split(tier1_generator.INSTRUCTION_END_MARKER) -+ _, labels_with_postlude = labels_with_prelude_and_postlude.split(tier1_generator.LABEL_START_MARKER) -+ labels, _ = labels_with_postlude.split(tier1_generator.LABEL_END_MARKER) -+ actual = instructions.strip() + "\n\n " + labels.strip() - # if actual.strip() != expected.strip(): - # print("Actual:") - # print(actual) -@@ -304,6 +304,10 @@ - """ - output = """ - TARGET(OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP); -@@ -322,6 +326,10 @@ - """ - output = """ - TARGET(OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP); -@@ -343,6 +351,10 @@ - """ - output = """ - TARGET(OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP); -@@ -365,6 +377,10 @@ - """ - output = """ - TARGET(OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP); -@@ -388,6 +404,10 @@ - """ - output = """ - TARGET(OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP); -@@ -414,6 +434,10 @@ - """ - output = """ - TARGET(OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP); -@@ -442,10 +466,14 @@ - """ - output = """ - TARGET(OP1) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP1; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP1); -- PREDICTED(OP1); -+ PREDICTED_OP1:; - _PyStackRef res; - res = Py_None; - stack_pointer[-1] = res; -@@ -453,12 +481,22 @@ - } - - TARGET(OP3) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP3; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP3); - static_assert(INLINE_CACHE_ENTRIES_OP1 == 0, "incorrect cache size"); - _PyStackRef res; -- DEOPT_IF(xxx, OP1); -+ if (xxx) { -+ UPDATE_MISS_STATS(OP1); -+ assert(_PyOpcode_Deopt[opcode] == (OP1)); -+ JUMP_TO_PREDICTED(OP1); -+ } - res = Py_None; - stack_pointer[-1] = res; - DISPATCH(); -@@ -481,6 +519,10 @@ - """ - output = """ - TARGET(A) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = A; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(A); -@@ -498,6 +540,10 @@ - } - - TARGET(B) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = B; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(B); -@@ -535,10 +581,16 @@ - """ - output = """ - TARGET(OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP); -- if (cond) goto label; -+ if (cond) { -+ JUMP_TO_LABEL(label); -+ } - DISPATCH(); - } - """ -@@ -552,10 +604,16 @@ - """ - output = """ - TARGET(OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP); -- if (cond) goto label; -+ if (cond) { -+ JUMP_TO_LABEL(label); -+ } - // Comment is ok - DISPATCH(); - } -@@ -573,6 +631,10 @@ - """ - output = """ - TARGET(OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP); -@@ -582,7 +644,9 @@ - right = stack_pointer[-1]; - left = stack_pointer[-2]; - SPAM(left, right); -- if (cond) goto pop_2_label; -+ if (cond) { -+ JUMP_TO_LABEL(pop_2_label); -+ } - res = 0; - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -602,6 +666,10 @@ - """ - output = """ - TARGET(OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP); -@@ -611,7 +679,9 @@ - right = stack_pointer[-1]; - left = stack_pointer[-2]; - res = SPAM(left, right); -- if (cond) goto pop_2_label; -+ if (cond) { -+ JUMP_TO_LABEL(pop_2_label); -+ } - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); -@@ -627,8 +697,13 @@ - """ - output = """ - TARGET(OP) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(OP); - uint16_t counter = read_u16(&this_instr[1].cache); -@@ -644,16 +719,28 @@ - - def test_suppress_dispatch(self): - input = """ -+ label(somewhere) { -+ } -+ - inst(OP, (--)) { - goto somewhere; - } - """ - output = """ - TARGET(OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP); -- goto somewhere; -+ JUMP_TO_LABEL(somewhere); -+ } -+ -+ LABEL(somewhere) -+ { -+ - } - """ - self.run_cases_test(input, output) -@@ -676,10 +763,14 @@ - """ - output = """ - TARGET(OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 6; - INSTRUCTION_STATS(OP); -- PREDICTED(OP); -+ PREDICTED_OP:; - _Py_CODEUNIT* const this_instr = next_instr - 6; - (void)this_instr; - _PyStackRef left; -@@ -713,8 +804,13 @@ - } - - TARGET(OP1) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP1; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(OP1); - _PyStackRef left; -@@ -730,6 +826,10 @@ - } - - TARGET(OP3) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP3; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 6; - INSTRUCTION_STATS(OP3); -@@ -761,6 +861,10 @@ - """ - output = """ - TARGET(OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(OP); -@@ -783,6 +887,10 @@ - """ - output = """ - TARGET(OP1) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP1; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP1); -@@ -802,6 +910,10 @@ - """ - output = """ - TARGET(OP1) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP1; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP1); -@@ -824,6 +936,10 @@ - """ - output = """ - TARGET(OP1) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP1; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP1); -@@ -831,6 +947,10 @@ - } - - TARGET(OP2) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP2; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP2); -@@ -848,6 +968,10 @@ - """ - output = """ - TARGET(OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP); -@@ -871,6 +995,10 @@ - """ - output = """ - TARGET(OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP); -@@ -899,6 +1027,10 @@ - """ - output = """ - TARGET(OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP); -@@ -923,13 +1055,17 @@ - """ - output = """ - TARGET(OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP); - if (oparg == 0) { - stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); -- goto somewhere; -+ JUMP_TO_LABEL(somewhere); - } - stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); -@@ -949,6 +1085,10 @@ - """ - output = """ - TARGET(OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP); -@@ -990,6 +1130,10 @@ - """ - output = """ - TARGET(M) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = M; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(M); -@@ -1034,6 +1178,10 @@ - """ - output = """ - TARGET(M) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = M; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(M); -@@ -1067,6 +1215,10 @@ - """ - output = """ - TARGET(OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP); -@@ -1088,6 +1240,10 @@ - """ - output = """ - TARGET(M) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = M; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(M); -@@ -1105,6 +1261,10 @@ - """ - output = """ - TARGET(OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP); -@@ -1123,6 +1283,10 @@ - """ - output = """ - TARGET(M) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = M; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(M); -@@ -1159,6 +1323,10 @@ - """ - output = """ - TARGET(OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP); -@@ -1181,6 +1349,10 @@ - """ - output = """ - TARGET(OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP); -@@ -1219,6 +1391,10 @@ - """ - output = """ - TARGET(INST) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = INST; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(INST); -@@ -1245,6 +1421,10 @@ - """ - output = """ - TARGET(TEST) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = TEST; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(TEST); -@@ -1285,6 +1465,10 @@ - """ - output = """ - TARGET(TEST) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = TEST; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(TEST); -@@ -1324,6 +1508,10 @@ - """ - output = """ - TARGET(TEST) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = TEST; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(TEST); -@@ -1372,6 +1560,10 @@ - """ - output = """ - TARGET(TEST) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = TEST; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(TEST); -@@ -1392,7 +1584,9 @@ - // THIRD - { - // Mark j and k as used -- if (cond) goto pop_2_error; -+ if (cond) { -+ JUMP_TO_LABEL(pop_2_error); -+ } - } - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); -@@ -1418,6 +1612,10 @@ - - output = """ - TARGET(TEST) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = TEST; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(TEST); -@@ -1435,7 +1633,7 @@ - stack_pointer[1] = b; - stack_pointer += 2; - assert(WITHIN_STACK_BOUNDS()); -- goto error; -+ JUMP_TO_LABEL(error); - } - } - stack_pointer[0] = a; -@@ -1459,17 +1657,25 @@ - """ - output = """ - TARGET(OP1) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP1; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP1); -- goto here; -+ JUMP_TO_LABEL(here); - } - - TARGET(OP2) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP2; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP2); -- goto there; -+ JUMP_TO_LABEL(there); - } - """ - self.run_cases_test(input, output) -@@ -1523,6 +1729,10 @@ - - output = """ - TARGET(BALANCED) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = BALANCED; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(BALANCED); -@@ -1543,6 +1753,10 @@ - - output = """ - TARGET(BALANCED) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = BALANCED; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(BALANCED); -@@ -1564,6 +1778,12 @@ - - output = """ - TARGET(BALANCED) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = BALANCED; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(BALANCED); -@@ -1584,6 +1804,10 @@ - - output = """ - TARGET(OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP); -@@ -1619,6 +1843,10 @@ - """ - output = """ - TARGET(OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP); -@@ -1639,47 +1867,67 @@ - """ - self.run_cases_test(input, output) - -- def test_pop_dead_inputs_all_live(self): -+ def test_pystackref_frompyobject_new_next_to_cmacro(self): - input = """ -- inst(OP, (a, b --)) { -- POP_DEAD_INPUTS(); -- HAM(a, b); -- INPUTS_DEAD(); -+ inst(OP, (-- out1, out2)) { -+ PyObject *obj = SPAM(); -+ #ifdef Py_GIL_DISABLED -+ out1 = PyStackRef_FromPyObjectNew(obj); -+ #else -+ out1 = PyStackRef_FromPyObjectNew(obj); -+ #endif -+ out2 = PyStackRef_FromPyObjectNew(obj); - } - """ - output = """ - TARGET(OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP); -- _PyStackRef a; -- _PyStackRef b; -- b = stack_pointer[-1]; -- a = stack_pointer[-2]; -- HAM(a, b); -- stack_pointer += -2; -+ _PyStackRef out1; -+ _PyStackRef out2; -+ PyObject *obj = SPAM(); -+ #ifdef Py_GIL_DISABLED -+ out1 = PyStackRef_FromPyObjectNew(obj); -+ #else -+ out1 = PyStackRef_FromPyObjectNew(obj); -+ #endif -+ out2 = PyStackRef_FromPyObjectNew(obj); -+ stack_pointer[0] = out1; -+ stack_pointer[1] = out2; -+ stack_pointer += 2; - assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - """ - self.run_cases_test(input, output) - -- def test_pop_dead_inputs_some_live(self): -+ def test_pop_input(self): - input = """ -- inst(OP, (a, b, c --)) { -- POP_DEAD_INPUTS(); -+ inst(OP, (a, b --)) { -+ POP_INPUT(b); - HAM(a); - INPUTS_DEAD(); - } - """ - output = """ - TARGET(OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(OP); - _PyStackRef a; -- a = stack_pointer[-3]; -- stack_pointer += -2; -+ _PyStackRef b; -+ b = stack_pointer[-1]; -+ a = stack_pointer[-2]; -+ stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - HAM(a); - stack_pointer += -1; -@@ -1689,26 +1937,190 @@ - """ - self.run_cases_test(input, output) - -- def test_pop_dead_inputs_with_output(self): -+ def test_pop_input_with_empty_stack(self): -+ input = """ -+ inst(OP, (--)) { -+ POP_INPUT(foo); -+ } -+ """ -+ with self.assertRaises(SyntaxError): -+ self.run_cases_test(input, "") -+ -+ def test_pop_input_with_non_tos(self): -+ input = """ -+ inst(OP, (a, b --)) { -+ POP_INPUT(a); -+ } -+ """ -+ with self.assertRaises(SyntaxError): -+ self.run_cases_test(input, "") -+ -+ def test_no_escaping_calls_in_branching_macros(self): -+ -+ input = """ -+ inst(OP, ( -- )) { -+ DEOPT_IF(escaping_call()); -+ } -+ """ -+ with self.assertRaises(SyntaxError): -+ self.run_cases_test(input, "") -+ -+ input = """ -+ inst(OP, ( -- )) { -+ EXIT_IF(escaping_call()); -+ } -+ """ -+ with self.assertRaises(SyntaxError): -+ self.run_cases_test(input, "") -+ -+ input = """ -+ inst(OP, ( -- )) { -+ ERROR_IF(escaping_call(), error); -+ } -+ """ -+ with self.assertRaises(SyntaxError): -+ self.run_cases_test(input, "") -+ -+ def test_kill_in_wrong_order(self): - input = """ - inst(OP, (a, b -- c)) { -- POP_DEAD_INPUTS(); -- c = SPAM(); -+ c = b; -+ PyStackRef_CLOSE(a); -+ PyStackRef_CLOSE(b); -+ } -+ """ -+ with self.assertRaises(SyntaxError): -+ self.run_cases_test(input, "") -+ -+ def test_complex_label(self): -+ input = """ -+ label(other_label) { -+ } -+ -+ label(other_label2) { -+ } -+ -+ label(my_label) { -+ // Comment -+ do_thing(); -+ if (complex) { -+ goto other_label; -+ } -+ goto other_label2; - } - """ -+ - output = """ -- TARGET(OP) { -- frame->instr_ptr = next_instr; -- next_instr += 1; -- INSTRUCTION_STATS(OP); -- _PyStackRef c; -- stack_pointer += -2; -- assert(WITHIN_STACK_BOUNDS()); -- c = SPAM(); -- stack_pointer[0] = c; -- stack_pointer += 1; -- assert(WITHIN_STACK_BOUNDS()); -- DISPATCH(); -+ LABEL(other_label) -+ { -+ -+ } -+ -+ LABEL(other_label2) -+ { -+ -+ } -+ -+ LABEL(my_label) -+ { -+ // Comment -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ do_thing(); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (complex) { -+ JUMP_TO_LABEL(other_label); -+ } -+ JUMP_TO_LABEL(other_label2); -+ } -+ """ -+ self.run_cases_test(input, output) -+ -+ def test_spilled_label(self): -+ input = """ -+ spilled label(one) { -+ RELOAD_STACK(); -+ goto two; -+ } -+ -+ label(two) { -+ SAVE_STACK(); -+ goto one; -+ } -+ """ -+ -+ output = """ -+ LABEL(one) -+ { -+ /* STACK SPILLED */ -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ JUMP_TO_LABEL(two); -+ } -+ -+ LABEL(two) -+ { -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ JUMP_TO_LABEL(one); -+ } -+ """ -+ self.run_cases_test(input, output) -+ -+ -+ def test_incorrect_spills(self): -+ input1 = """ -+ spilled label(one) { -+ goto two; -+ } -+ -+ label(two) { -+ } -+ """ -+ -+ input2 = """ -+ spilled label(one) { -+ } -+ -+ label(two) { -+ goto one; -+ } -+ """ -+ with self.assertRaisesRegex(SyntaxError, ".*reload.*"): -+ self.run_cases_test(input1, "") -+ with self.assertRaisesRegex(SyntaxError, ".*spill.*"): -+ self.run_cases_test(input2, "") -+ -+ -+ def test_multiple_labels(self): -+ input = """ -+ label(my_label_1) { -+ // Comment -+ do_thing1(); -+ goto my_label_2; -+ } -+ -+ label(my_label_2) { -+ // Comment -+ do_thing2(); -+ goto my_label_1; -+ } -+ """ -+ -+ output = """ -+ LABEL(my_label_1) -+ { -+ // Comment -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ do_thing1(); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ JUMP_TO_LABEL(my_label_2); -+ } -+ -+ LABEL(my_label_2) -+ { -+ // Comment -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ do_thing2(); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ JUMP_TO_LABEL(my_label_1); - } - """ - self.run_cases_test(input, output) -@@ -1799,8 +2211,8 @@ - """ - output = """ - case OP: { -- _Py_UopsSymbol *arg1; -- _Py_UopsSymbol *out; -+ JitOptSymbol *arg1; -+ JitOptSymbol *out; - arg1 = stack_pointer[-1]; - out = EGGS(arg1); - stack_pointer[-1] = out; -@@ -1808,7 +2220,7 @@ - } - - case OP2: { -- _Py_UopsSymbol *out; -+ JitOptSymbol *out; - out = sym_new_not_null(ctx); - stack_pointer[-1] = out; - break; -@@ -1833,14 +2245,14 @@ - """ - output = """ - case OP: { -- _Py_UopsSymbol *out; -+ JitOptSymbol *out; - out = sym_new_not_null(ctx); - stack_pointer[-1] = out; - break; - } - - case OP2: { -- _Py_UopsSymbol *out; -+ JitOptSymbol *out; - out = NULL; - stack_pointer[-1] = out; - break; -diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py -index 2ea6dba12ef..bf4b88cd9c4 100644 ---- a/Lib/test/test_generators.py -+++ b/Lib/test/test_generators.py -@@ -652,6 +652,89 @@ - self.assertIsNone(f_wr()) - - -+# See https://github.com/python/cpython/issues/125723 -+class GeneratorDeallocTest(unittest.TestCase): -+ def test_frame_outlives_generator(self): -+ def g1(): -+ a = 42 -+ yield sys._getframe() -+ -+ def g2(): -+ a = 42 -+ yield -+ -+ def g3(obj): -+ a = 42 -+ obj.frame = sys._getframe() -+ yield -+ -+ class ObjectWithFrame(): -+ def __init__(self): -+ self.frame = None -+ -+ def get_frame(index): -+ if index == 1: -+ return next(g1()) -+ elif index == 2: -+ gen = g2() -+ next(gen) -+ return gen.gi_frame -+ elif index == 3: -+ obj = ObjectWithFrame() -+ next(g3(obj)) -+ return obj.frame -+ else: -+ return None -+ -+ for index in (1, 2, 3): -+ with self.subTest(index=index): -+ frame = get_frame(index) -+ frame_locals = frame.f_locals -+ self.assertIn('a', frame_locals) -+ self.assertEqual(frame_locals['a'], 42) -+ -+ def test_frame_locals_outlive_generator(self): -+ frame_locals1 = None -+ -+ def g1(): -+ nonlocal frame_locals1 -+ frame_locals1 = sys._getframe().f_locals -+ a = 42 -+ yield -+ -+ def g2(): -+ a = 42 -+ yield sys._getframe().f_locals -+ -+ def get_frame_locals(index): -+ if index == 1: -+ nonlocal frame_locals1 -+ next(g1()) -+ return frame_locals1 -+ if index == 2: -+ return next(g2()) -+ else: -+ return None -+ -+ for index in (1, 2): -+ with self.subTest(index=index): -+ frame_locals = get_frame_locals(index) -+ self.assertIn('a', frame_locals) -+ self.assertEqual(frame_locals['a'], 42) -+ -+ def test_frame_locals_outlive_generator_with_exec(self): -+ def g(): -+ a = 42 -+ yield locals(), sys._getframe().f_locals -+ -+ locals_ = {'g': g} -+ for i in range(10): -+ exec("snapshot, live_locals = next(g())", locals=locals_) -+ for l in (locals_['snapshot'], locals_['live_locals']): -+ self.assertIn('a', l) -+ self.assertEqual(l['a'], 42) -+ -+ - class GeneratorThrowTest(unittest.TestCase): - - def test_exception_context_with_yield(self): -@@ -2581,14 +2664,18 @@ - >>> with support.catch_unraisable_exception() as cm: - ... g = f() - ... next(g) -+... gen_repr = repr(g) - ... del g - ... -+... cm.unraisable.err_msg == (f'Exception ignored while closing ' -+... f'generator {gen_repr}') - ... cm.unraisable.exc_type == RuntimeError - ... "generator ignored GeneratorExit" in str(cm.unraisable.exc_value) - ... cm.unraisable.exc_traceback is not None - True - True - True -+True - - And errors thrown during closing should propagate: - -@@ -2693,10 +2780,12 @@ - ... invoke("del failed") - ... - >>> with support.catch_unraisable_exception() as cm: --... l = Leaker() --... del l -+... leaker = Leaker() -+... del_repr = repr(type(leaker).__del__) -+... del leaker - ... --... cm.unraisable.object == Leaker.__del__ -+... cm.unraisable.err_msg == (f'Exception ignored while ' -+... f'calling deallocator {del_repr}') - ... cm.unraisable.exc_type == RuntimeError - ... str(cm.unraisable.exc_value) == "del failed" - ... cm.unraisable.exc_traceback is not None -diff --git a/Lib/test/test_genericpath.py b/Lib/test/test_genericpath.py -index 6d2593cb4cf..391158b8556 100644 ---- a/Lib/test/test_genericpath.py -+++ b/Lib/test/test_genericpath.py -@@ -161,7 +161,7 @@ - self.assertIs(self.pathmodule.lexists(path=filename), True) - - @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") -- @unittest.skipIf(is_emscripten, "Emscripten pipe fds have no stat") -+ @unittest.skipIf(is_emscripten, "Fixed in next Emscripten release after 4.0.1") - def test_exists_fd(self): - r, w = os.pipe() - try: -diff --git a/Lib/test/test_glob.py b/Lib/test/test_glob.py -index b72640bd871..a45b30599d5 100644 ---- a/Lib/test/test_glob.py -+++ b/Lib/test/test_glob.py -@@ -6,6 +6,7 @@ - import unittest - import warnings - -+from test import support - from test.support import is_wasi, Py_DEBUG - from test.support.os_helper import (TESTFN, skip_unless_symlink, - can_symlink, create_empty_file, change_cwd) -@@ -170,37 +171,45 @@ - self.norm('aab', 'F')]) - - def test_glob_directory_with_trailing_slash(self): -- # Patterns ending with a slash shouldn't match non-dirs -- res = glob.glob(self.norm('Z*Z') + os.sep) -- self.assertEqual(res, []) -- res = glob.glob(self.norm('ZZZ') + os.sep) -- self.assertEqual(res, []) -- # When there is a wildcard pattern which ends with os.sep, glob() -- # doesn't blow up. -- res = glob.glob(self.norm('aa*') + os.sep) -- self.assertEqual(len(res), 2) -- # either of these results is reasonable -- self.assertIn(set(res), [ -- {self.norm('aaa'), self.norm('aab')}, -- {self.norm('aaa') + os.sep, self.norm('aab') + os.sep}, -- ]) -+ seps = (os.sep, os.altsep) if os.altsep else (os.sep,) -+ for sep in seps: -+ # Patterns ending with a slash shouldn't match non-dirs -+ self.assertEqual(glob.glob(self.norm('Z*Z') + sep), []) -+ self.assertEqual(glob.glob(self.norm('ZZZ') + sep), []) -+ self.assertEqual(glob.glob(self.norm('aaa') + sep), -+ [self.norm('aaa') + sep]) -+ # Preserving the redundant separators is an implementation detail. -+ self.assertEqual(glob.glob(self.norm('aaa') + sep*2), -+ [self.norm('aaa') + sep*2]) -+ # When there is a wildcard pattern which ends with a pathname -+ # separator, glob() doesn't blow. -+ # The result should end with the pathname separator. -+ # Normalizing the trailing separator is an implementation detail. -+ eq = self.assertSequencesEqual_noorder -+ eq(glob.glob(self.norm('aa*') + sep), -+ [self.norm('aaa') + os.sep, self.norm('aab') + os.sep]) -+ # Stripping the redundant separators is an implementation detail. -+ eq(glob.glob(self.norm('aa*') + sep*2), -+ [self.norm('aaa') + os.sep, self.norm('aab') + os.sep]) - - def test_glob_bytes_directory_with_trailing_slash(self): - # Same as test_glob_directory_with_trailing_slash, but with a - # bytes argument. -- res = glob.glob(os.fsencode(self.norm('Z*Z') + os.sep)) -- self.assertEqual(res, []) -- res = glob.glob(os.fsencode(self.norm('ZZZ') + os.sep)) -- self.assertEqual(res, []) -- res = glob.glob(os.fsencode(self.norm('aa*') + os.sep)) -- self.assertEqual(len(res), 2) -- # either of these results is reasonable -- self.assertIn(set(res), [ -- {os.fsencode(self.norm('aaa')), -- os.fsencode(self.norm('aab'))}, -- {os.fsencode(self.norm('aaa') + os.sep), -- os.fsencode(self.norm('aab') + os.sep)}, -- ]) -+ seps = (os.sep, os.altsep) if os.altsep else (os.sep,) -+ for sep in seps: -+ self.assertEqual(glob.glob(os.fsencode(self.norm('Z*Z') + sep)), []) -+ self.assertEqual(glob.glob(os.fsencode(self.norm('ZZZ') + sep)), []) -+ self.assertEqual(glob.glob(os.fsencode(self.norm('aaa') + sep)), -+ [os.fsencode(self.norm('aaa') + sep)]) -+ self.assertEqual(glob.glob(os.fsencode(self.norm('aaa') + sep*2)), -+ [os.fsencode(self.norm('aaa') + sep*2)]) -+ eq = self.assertSequencesEqual_noorder -+ eq(glob.glob(os.fsencode(self.norm('aa*') + sep)), -+ [os.fsencode(self.norm('aaa') + os.sep), -+ os.fsencode(self.norm('aab') + os.sep)]) -+ eq(glob.glob(os.fsencode(self.norm('aa*') + sep*2)), -+ [os.fsencode(self.norm('aaa') + os.sep), -+ os.fsencode(self.norm('aab') + os.sep)]) - - @skip_unless_symlink - def test_glob_symlinks(self): -@@ -208,8 +217,7 @@ - eq(self.glob('sym3'), [self.norm('sym3')]) - eq(self.glob('sym3', '*'), [self.norm('sym3', 'EF'), - self.norm('sym3', 'efg')]) -- self.assertIn(self.glob('sym3' + os.sep), -- [[self.norm('sym3')], [self.norm('sym3') + os.sep]]) -+ eq(self.glob('sym3' + os.sep), [self.norm('sym3') + os.sep]) - eq(self.glob('*', '*F'), - [self.norm('aaa', 'zzzF'), - self.norm('aab', 'F'), self.norm('sym3', 'EF')]) -@@ -510,11 +518,21 @@ - @skip_unless_symlink - class SymlinkLoopGlobTests(unittest.TestCase): - -+ # gh-109959: On Linux, glob._isdir() and glob._lexists() can return False -+ # randomly when checking the "link/" symbolic link. -+ # https://github.com/python/cpython/issues/109959#issuecomment-2577550700 -+ @unittest.skip("flaky test") - def test_selflink(self): - tempdir = TESTFN + "_dir" - os.makedirs(tempdir) - self.addCleanup(shutil.rmtree, tempdir) - with change_cwd(tempdir): -+ if support.verbose: -+ cwd = os.getcwd() -+ print(f"cwd: {cwd} ({len(cwd)} chars)") -+ cwdb = os.getcwdb() -+ print(f"cwdb: {cwdb!r} ({len(cwdb)} bytes)") -+ - os.makedirs('dir') - create_empty_file(os.path.join('dir', 'file')) - os.symlink(os.curdir, os.path.join('dir', 'link')) -diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py -index 575b2cd0da7..d1b04128bf6 100644 ---- a/Lib/test/test_hashlib.py -+++ b/Lib/test/test_hashlib.py -@@ -13,13 +13,13 @@ - import os - import sys - import sysconfig -+import tempfile - import threading - import unittest - import warnings - from test import support - from test.support import _4G, bigmemtest - from test.support.import_helper import import_fresh_module --from test.support import os_helper - from test.support import requires_resource - from test.support import threading_helper - from http.client import HTTPException -@@ -414,21 +414,18 @@ - digests = [name] - digests.extend(self.constructors_to_test[name]) - -- with open(os_helper.TESTFN, "wb") as f: -+ with tempfile.TemporaryFile() as f: - f.write(data) - -- try: - for digest in digests: - buf = io.BytesIO(data) - buf.seek(0) - self.assertEqual( - hashlib.file_digest(buf, digest).hexdigest(), hexdigest - ) -- with open(os_helper.TESTFN, "rb") as f: -- digestobj = hashlib.file_digest(f, digest) -+ f.seek(0) -+ digestobj = hashlib.file_digest(f, digest) - self.assertEqual(digestobj.hexdigest(), hexdigest) -- finally: -- os.unlink(os_helper.TESTFN) - - def check_no_unicode(self, algorithm_name): - # Unicode objects are not allowed as input. -@@ -1172,29 +1169,29 @@ - def test_file_digest(self): - data = b'a' * 65536 - d1 = hashlib.sha256() -- self.addCleanup(os.unlink, os_helper.TESTFN) -- with open(os_helper.TESTFN, "wb") as f: -+ with tempfile.NamedTemporaryFile(delete_on_close=False) as fp: - for _ in range(10): - d1.update(data) -- f.write(data) -+ fp.write(data) -+ fp.close() - -- with open(os_helper.TESTFN, "rb") as f: -- d2 = hashlib.file_digest(f, hashlib.sha256) -+ with open(fp.name, "rb") as f: -+ d2 = hashlib.file_digest(f, hashlib.sha256) - -- self.assertEqual(d1.hexdigest(), d2.hexdigest()) -- self.assertEqual(d1.name, d2.name) -- self.assertIs(type(d1), type(d2)) -+ self.assertEqual(d1.hexdigest(), d2.hexdigest()) -+ self.assertEqual(d1.name, d2.name) -+ self.assertIs(type(d1), type(d2)) - -- with self.assertRaises(ValueError): -- hashlib.file_digest(None, "sha256") -+ with self.assertRaises(ValueError): -+ with open(fp.name, "r") as f: -+ hashlib.file_digest(f, "sha256") - -- with self.assertRaises(ValueError): -- with open(os_helper.TESTFN, "r") as f: -- hashlib.file_digest(f, "sha256") -+ with self.assertRaises(ValueError): -+ with open(fp.name, "wb") as f: -+ hashlib.file_digest(f, "sha256") - - with self.assertRaises(ValueError): -- with open(os_helper.TESTFN, "wb") as f: -- hashlib.file_digest(f, "sha256") -+ hashlib.file_digest(None, "sha256") - - - if __name__ == "__main__": -diff --git a/Lib/test/test_http_cookies.py b/Lib/test/test_http_cookies.py -index 7b3dc0fdaed..d945de23493 100644 ---- a/Lib/test/test_http_cookies.py -+++ b/Lib/test/test_http_cookies.py -@@ -205,6 +205,14 @@ - self.assertEqual(C.output(), - 'Set-Cookie: Customer="WILE_E_COYOTE"; HttpOnly; Secure') - -+ def test_set_secure_httponly_partitioned_attrs(self): -+ C = cookies.SimpleCookie('Customer="WILE_E_COYOTE"') -+ C['Customer']['secure'] = True -+ C['Customer']['httponly'] = True -+ C['Customer']['partitioned'] = True -+ self.assertEqual(C.output(), -+ 'Set-Cookie: Customer="WILE_E_COYOTE"; HttpOnly; Partitioned; Secure') -+ - def test_samesite_attrs(self): - samesite_values = ['Strict', 'Lax', 'strict', 'lax'] - for val in samesite_values: -diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py -index 9d853d254db..75b748aee05 100644 ---- a/Lib/test/test_httplib.py -+++ b/Lib/test/test_httplib.py -@@ -594,8 +594,9 @@ - CONTINUE = 100, 'Continue', 'Request received, please continue' - SWITCHING_PROTOCOLS = (101, 'Switching Protocols', - 'Switching to new protocol; obey Upgrade header') -- PROCESSING = 102, 'Processing' -- EARLY_HINTS = 103, 'Early Hints' -+ PROCESSING = 102, 'Processing', 'Server is processing the request' -+ EARLY_HINTS = (103, 'Early Hints', -+ 'Headers sent to prepare for the response') - # success - OK = 200, 'OK', 'Request fulfilled, document follows' - CREATED = 201, 'Created', 'Document created, URL follows' -@@ -606,9 +607,11 @@ - NO_CONTENT = 204, 'No Content', 'Request fulfilled, nothing follows' - RESET_CONTENT = 205, 'Reset Content', 'Clear input form for further input' - PARTIAL_CONTENT = 206, 'Partial Content', 'Partial content follows' -- MULTI_STATUS = 207, 'Multi-Status' -- ALREADY_REPORTED = 208, 'Already Reported' -- IM_USED = 226, 'IM Used' -+ MULTI_STATUS = (207, 'Multi-Status', -+ 'Response contains multiple statuses in the body') -+ ALREADY_REPORTED = (208, 'Already Reported', -+ 'Operation has already been reported') -+ IM_USED = 226, 'IM Used', 'Request completed using instance manipulations' - # redirection - MULTIPLE_CHOICES = (300, 'Multiple Choices', - 'Object has several resources -- see URI list') -@@ -665,15 +668,19 @@ - EXPECTATION_FAILED = (417, 'Expectation Failed', - 'Expect condition could not be satisfied') - IM_A_TEAPOT = (418, 'I\'m a Teapot', -- 'Server refuses to brew coffee because it is a teapot.') -+ 'Server refuses to brew coffee because it is a teapot') - MISDIRECTED_REQUEST = (421, 'Misdirected Request', - 'Server is not able to produce a response') -- UNPROCESSABLE_CONTENT = 422, 'Unprocessable Content' -+ UNPROCESSABLE_CONTENT = (422, 'Unprocessable Content', -+ 'Server is not able to process the contained instructions') - UNPROCESSABLE_ENTITY = UNPROCESSABLE_CONTENT -- LOCKED = 423, 'Locked' -- FAILED_DEPENDENCY = 424, 'Failed Dependency' -- TOO_EARLY = 425, 'Too Early' -- UPGRADE_REQUIRED = 426, 'Upgrade Required' -+ LOCKED = 423, 'Locked', 'Resource of a method is locked' -+ FAILED_DEPENDENCY = (424, 'Failed Dependency', -+ 'Dependent action of the request failed') -+ TOO_EARLY = (425, 'Too Early', -+ 'Server refuses to process a request that might be replayed') -+ UPGRADE_REQUIRED = (426, 'Upgrade Required', -+ 'Server refuses to perform the request using the current protocol') - PRECONDITION_REQUIRED = (428, 'Precondition Required', - 'The origin server requires the request to be conditional') - TOO_MANY_REQUESTS = (429, 'Too Many Requests', -@@ -700,10 +707,14 @@ - 'The gateway server did not receive a timely response') - HTTP_VERSION_NOT_SUPPORTED = (505, 'HTTP Version Not Supported', - 'Cannot fulfill request') -- VARIANT_ALSO_NEGOTIATES = 506, 'Variant Also Negotiates' -- INSUFFICIENT_STORAGE = 507, 'Insufficient Storage' -- LOOP_DETECTED = 508, 'Loop Detected' -- NOT_EXTENDED = 510, 'Not Extended' -+ VARIANT_ALSO_NEGOTIATES = (506, 'Variant Also Negotiates', -+ 'Server has an internal configuration error') -+ INSUFFICIENT_STORAGE = (507, 'Insufficient Storage', -+ 'Server is not able to store the representation') -+ LOOP_DETECTED = (508, 'Loop Detected', -+ 'Server encountered an infinite loop while processing a request') -+ NOT_EXTENDED = (510, 'Not Extended', -+ 'Request does not meet the resource access policy') - NETWORK_AUTHENTICATION_REQUIRED = (511, - 'Network Authentication Required', - 'The client needs to authenticate to gain network access') -@@ -1081,6 +1092,25 @@ - self.assertEqual(resp.read(), expected) - resp.close() - -+ # Explicit full read -+ for n in (-123, -1, None): -+ with self.subTest('full read', n=n): -+ sock = FakeSocket(chunked_start + last_chunk + chunked_end) -+ resp = client.HTTPResponse(sock, method="GET") -+ resp.begin() -+ self.assertTrue(resp.chunked) -+ self.assertEqual(resp.read(n), expected) -+ resp.close() -+ -+ # Read first chunk -+ with self.subTest('read1(-1)'): -+ sock = FakeSocket(chunked_start + last_chunk + chunked_end) -+ resp = client.HTTPResponse(sock, method="GET") -+ resp.begin() -+ self.assertTrue(resp.chunked) -+ self.assertEqual(resp.read1(-1), b"hello worl") -+ resp.close() -+ - # Various read sizes - for n in range(1, 12): - sock = FakeSocket(chunked_start + last_chunk + chunked_end) -@@ -2073,8 +2103,8 @@ - - def test_tls13_pha(self): - import ssl -- if not ssl.HAS_TLSv1_3: -- self.skipTest('TLS 1.3 support required') -+ if not ssl.HAS_TLSv1_3 or not ssl.HAS_PHA: -+ self.skipTest('TLS 1.3 PHA support required') - # just check status of PHA flag - h = client.HTTPSConnection('localhost', 443) - self.assertTrue(h._context.post_handshake_auth) -diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py -index a6509fc3ba0..a13ee58d650 100644 ---- a/Lib/test/test_imaplib.py -+++ b/Lib/test/test_imaplib.py -@@ -208,6 +208,54 @@ - self._send_tagged(tag, 'BAD', 'No mailbox selected') - - -+class IdleCmdDenyHandler(SimpleIMAPHandler): -+ capabilities = 'IDLE' -+ def cmd_IDLE(self, tag, args): -+ self._send_tagged(tag, 'NO', 'IDLE is not allowed at this time') -+ -+ -+class IdleCmdHandler(SimpleIMAPHandler): -+ capabilities = 'IDLE' -+ def cmd_IDLE(self, tag, args): -+ # pre-idle-continuation response -+ self._send_line(b'* 0 EXISTS') -+ self._send_textline('+ idling') -+ # simple response -+ self._send_line(b'* 2 EXISTS') -+ # complex response: fragmented data due to literal string -+ self._send_line(b'* 1 FETCH (BODY[HEADER.FIELDS (DATE)] {41}') -+ self._send(b'Date: Fri, 06 Dec 2024 06:00:00 +0000\r\n\r\n') -+ self._send_line(b')') -+ # simple response following a fragmented one -+ self._send_line(b'* 3 EXISTS') -+ # response arriving later -+ time.sleep(1) -+ self._send_line(b'* 1 RECENT') -+ r = yield -+ if r == b'DONE\r\n': -+ self._send_line(b'* 9 RECENT') -+ self._send_tagged(tag, 'OK', 'Idle completed') -+ else: -+ self._send_tagged(tag, 'BAD', 'Expected DONE') -+ -+ -+class IdleCmdDelayedPacketHandler(SimpleIMAPHandler): -+ capabilities = 'IDLE' -+ def cmd_IDLE(self, tag, args): -+ self._send_textline('+ idling') -+ # response line spanning multiple packets, the last one delayed -+ self._send(b'* 1 EX') -+ time.sleep(0.2) -+ self._send(b'IS') -+ time.sleep(1) -+ self._send(b'TS\r\n') -+ r = yield -+ if r == b'DONE\r\n': -+ self._send_tagged(tag, 'OK', 'Idle completed') -+ else: -+ self._send_tagged(tag, 'BAD', 'Expected DONE') -+ -+ - class NewIMAPTestsMixin(): - client = None - -@@ -497,6 +545,73 @@ - - # command tests - -+ def test_idle_capability(self): -+ client, _ = self._setup(SimpleIMAPHandler) -+ with self.assertRaisesRegex(imaplib.IMAP4.error, -+ 'does not support IMAP4 IDLE'): -+ with client.idle(): -+ pass -+ -+ def test_idle_denied(self): -+ client, _ = self._setup(IdleCmdDenyHandler) -+ client.login('user', 'pass') -+ with self.assertRaises(imaplib.IMAP4.error): -+ with client.idle() as idler: -+ pass -+ -+ def test_idle_iter(self): -+ client, _ = self._setup(IdleCmdHandler) -+ client.login('user', 'pass') -+ with client.idle() as idler: -+ # iteration should include response between 'IDLE' & '+ idling' -+ response = next(idler) -+ self.assertEqual(response, ('EXISTS', [b'0'])) -+ # iteration should produce responses -+ response = next(idler) -+ self.assertEqual(response, ('EXISTS', [b'2'])) -+ # fragmented response (with literal string) should arrive whole -+ expected_fetch_data = [ -+ (b'1 (BODY[HEADER.FIELDS (DATE)] {41}', -+ b'Date: Fri, 06 Dec 2024 06:00:00 +0000\r\n\r\n'), -+ b')'] -+ typ, data = next(idler) -+ self.assertEqual(typ, 'FETCH') -+ self.assertEqual(data, expected_fetch_data) -+ # response after a fragmented one should arrive separately -+ response = next(idler) -+ self.assertEqual(response, ('EXISTS', [b'3'])) -+ # iteration should have consumed untagged responses -+ _, data = client.response('EXISTS') -+ self.assertEqual(data, [None]) -+ # responses not iterated should be available after idle -+ _, data = client.response('RECENT') -+ self.assertEqual(data[0], b'1') -+ # responses received after 'DONE' should be available after idle -+ self.assertEqual(data[1], b'9') -+ -+ def test_idle_burst(self): -+ client, _ = self._setup(IdleCmdHandler) -+ client.login('user', 'pass') -+ # burst() should yield immediately available responses -+ with client.idle() as idler: -+ batch = list(idler.burst()) -+ self.assertEqual(len(batch), 4) -+ # burst() should not have consumed later responses -+ _, data = client.response('RECENT') -+ self.assertEqual(data, [b'1', b'9']) -+ -+ def test_idle_delayed_packet(self): -+ client, _ = self._setup(IdleCmdDelayedPacketHandler) -+ client.login('user', 'pass') -+ # If our readline() implementation fails to preserve line fragments -+ # when idle timeouts trigger, a response spanning delayed packets -+ # can be corrupted, leaving the protocol stream in a bad state. -+ try: -+ with client.idle(0.5) as idler: -+ self.assertRaises(StopIteration, next, idler) -+ except client.abort as err: -+ self.fail('multi-packet response was corrupted by idle timeout') -+ - def test_login(self): - client, _ = self._setup(SimpleIMAPHandler) - typ, data = client.login('user', 'pass') -@@ -537,6 +652,14 @@ - self.assertEqual(data[0], b'Returned to authenticated state. (Success)') - self.assertEqual(client.state, 'AUTH') - -+ # property tests -+ -+ def test_file_property_should_not_be_accessed(self): -+ client, _ = self._setup(SimpleIMAPHandler) -+ # the 'file' property replaced a private attribute that is now unsafe -+ with self.assertWarns(RuntimeWarning): -+ client.file -+ - - class NewIMAPTests(NewIMAPTestsMixin, unittest.TestCase): - imap_class = imaplib.IMAP4 -@@ -901,6 +1024,20 @@ - self.assertRaises(imaplib.IMAP4.error, - self.imap_class, *server.server_address) - -+ def test_truncated_large_literal(self): -+ size = 0 -+ class BadHandler(SimpleIMAPHandler): -+ def handle(self): -+ self._send_textline('* OK {%d}' % size) -+ self._send_textline('IMAP4rev1') -+ -+ for exponent in range(15, 64): -+ size = 1 << exponent -+ with self.subTest(f"size=2e{size}"): -+ with self.reaped_server(BadHandler) as server: -+ with self.assertRaises(imaplib.IMAP4.abort): -+ self.imap_class(*server.server_address) -+ - @threading_helper.reap_threads - def test_simple_with_statement(self): - # simplest call -diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py -index 83efbc1e25e..207b7ae7517 100644 ---- a/Lib/test/test_import/__init__.py -+++ b/Lib/test/test_import/__init__.py -@@ -29,9 +29,21 @@ - - from test.support import os_helper - from test.support import ( -- STDLIB_DIR, swap_attr, swap_item, cpython_only, is_apple_mobile, is_emscripten, -- is_wasi, run_in_subinterp, run_in_subinterp_with_config, Py_TRACE_REFS, -- requires_gil_enabled, Py_GIL_DISABLED, no_rerun) -+ STDLIB_DIR, -+ swap_attr, -+ swap_item, -+ cpython_only, -+ is_apple_mobile, -+ is_emscripten, -+ is_wasi, -+ run_in_subinterp, -+ run_in_subinterp_with_config, -+ Py_TRACE_REFS, -+ requires_gil_enabled, -+ Py_GIL_DISABLED, -+ no_rerun, -+ force_not_colorized_test_class, -+) - from test.support.import_helper import ( - forget, make_legacy_pyc, unlink, unload, ready_to_import, - DirsOnSysPath, CleanImport, import_module) -@@ -333,6 +345,7 @@ - return cls.parse(text.decode()) - - -+@force_not_colorized_test_class - class ImportTests(unittest.TestCase): - - def setUp(self): -@@ -539,7 +552,7 @@ - import test as x - import test.support - self.assertIs(x, test, x.__name__) -- self.assertTrue(hasattr(test.support, "__file__")) -+ self.assertHasAttr(test.support, "__file__") - - # import x.y.z as w binds z as w - import test.support as y -@@ -610,7 +623,7 @@ - sys.path.insert(0, os.curdir) - try: - mod = __import__(TESTFN) -- self.assertTrue(mod.__file__.endswith('.py')) -+ self.assertEndsWith(mod.__file__, '.py') - os.remove(source) - del sys.modules[TESTFN] - make_legacy_pyc(source) -@@ -851,6 +864,29 @@ - stdout, stderr = popen.communicate() - self.assertIn(expected_error, stdout) - -+ def test_non_module_from_import_error(self): -+ prefix = """ -+import sys -+class NotAModule: ... -+nm = NotAModule() -+nm.symbol = 123 -+sys.modules["not_a_module"] = nm -+from not_a_module import symbol -+""" -+ scripts = [ -+ prefix + "from not_a_module import missing_symbol", -+ prefix + "nm.__spec__ = []\nfrom not_a_module import missing_symbol", -+ ] -+ for script in scripts: -+ with self.subTest(script=script): -+ expected_error = ( -+ b"ImportError: cannot import name 'missing_symbol' from " -+ b"'' (unknown location)" -+ ) -+ popen = script_helper.spawn_python("-c", script) -+ stdout, stderr = popen.communicate() -+ self.assertIn(expected_error, stdout) -+ - def test_script_shadowing_stdlib(self): - script_errors = [ - ( -@@ -1420,7 +1456,7 @@ - self.fail("could not import 'test_unc_path' from %r: %r" - % (unc, e)) - self.assertEqual(mod.testdata, 'test_unc_path') -- self.assertTrue(mod.__file__.startswith(unc), mod.__file__) -+ self.assertStartsWith(mod.__file__, unc) - unload("test_unc_path") - - -@@ -1433,7 +1469,7 @@ - def test_relimport_star(self): - # This will import * from .test_import. - from .. import relimport -- self.assertTrue(hasattr(relimport, "RelativeImportTests")) -+ self.assertHasAttr(relimport, "RelativeImportTests") - - def test_issue3221(self): - # Note for mergers: the 'absolute' tests from the 2.x branch -@@ -1763,7 +1799,7 @@ - self.assertIs(mod, _bootstrap) - self.assertEqual(mod.__name__, 'importlib._bootstrap') - self.assertEqual(mod.__package__, 'importlib') -- self.assertTrue(mod.__file__.endswith('_bootstrap.py'), mod.__file__) -+ self.assertEndsWith(mod.__file__, '_bootstrap.py') - - def test_frozen_importlib_external_is_bootstrap_external(self): - from importlib import _bootstrap_external -@@ -1771,7 +1807,7 @@ - self.assertIs(mod, _bootstrap_external) - self.assertEqual(mod.__name__, 'importlib._bootstrap_external') - self.assertEqual(mod.__package__, 'importlib') -- self.assertTrue(mod.__file__.endswith('_bootstrap_external.py'), mod.__file__) -+ self.assertEndsWith(mod.__file__, '_bootstrap_external.py') - - def test_there_can_be_only_one(self): - # Issue #15386 revealed a tricky loophole in the bootstrapping -@@ -2777,7 +2813,7 @@ - self.assertEqual(mod.__file__, self.FILE) - self.assertEqual(mod.__spec__.origin, self.ORIGIN) - if not isolated: -- self.assertTrue(issubclass(mod.error, Exception)) -+ self.assertIsSubclass(mod.error, Exception) - self.assertEqual(mod.int_const, 1969) - self.assertEqual(mod.str_const, 'something different') - self.assertIsInstance(mod._module_initialized, float) -@@ -3288,30 +3324,6 @@ - # * module's global state was initialized, not reset - - --@cpython_only --class CAPITests(unittest.TestCase): -- def test_pyimport_addmodule(self): -- # gh-105922: Test PyImport_AddModuleRef(), PyImport_AddModule() -- # and PyImport_AddModuleObject() -- _testcapi = import_module("_testcapi") -- for name in ( -- 'sys', # frozen module -- 'test', # package -- __name__, # package.module -- ): -- _testcapi.check_pyimport_addmodule(name) -- -- def test_pyimport_addmodule_create(self): -- # gh-105922: Test PyImport_AddModuleRef(), create a new module -- _testcapi = import_module("_testcapi") -- name = 'dontexist' -- self.assertNotIn(name, sys.modules) -- self.addCleanup(unload, name) -- -- mod = _testcapi.check_pyimport_addmodule(name) -- self.assertIs(mod, sys.modules[name]) -- -- - @cpython_only - class TestMagicNumber(unittest.TestCase): - def test_magic_number_endianness(self): -diff --git a/Lib/test/test_importlib/extension/test_path_hook.py b/Lib/test/test_importlib/extension/test_path_hook.py -index 314a635c77e..941dcd5432c 100644 ---- a/Lib/test/test_importlib/extension/test_path_hook.py -+++ b/Lib/test/test_importlib/extension/test_path_hook.py -@@ -21,7 +21,7 @@ - def test_success(self): - # Path hook should handle a directory where a known extension module - # exists. -- self.assertTrue(hasattr(self.hook(util.EXTENSIONS.path), 'find_spec')) -+ self.assertHasAttr(self.hook(util.EXTENSIONS.path), 'find_spec') - - - (Frozen_PathHooksTests, -diff --git a/Lib/test/test_importlib/frozen/test_loader.py b/Lib/test/test_importlib/frozen/test_loader.py -index 1112c0664ad..c808bb73291 100644 ---- a/Lib/test/test_importlib/frozen/test_loader.py -+++ b/Lib/test/test_importlib/frozen/test_loader.py -@@ -61,7 +61,7 @@ - module.main() - - self.assertTrue(module.initialized) -- self.assertTrue(hasattr(module, '__spec__')) -+ self.assertHasAttr(module, '__spec__') - self.assertEqual(module.__spec__.origin, 'frozen') - return module, stdout.getvalue() - -@@ -72,7 +72,7 @@ - for attr, value in check.items(): - self.assertEqual(getattr(module, attr), value) - self.assertEqual(output, 'Hello world!\n') -- self.assertTrue(hasattr(module, '__spec__')) -+ self.assertHasAttr(module, '__spec__') - self.assertEqual(module.__spec__.loader_state.origname, name) - - def test_package(self): -@@ -136,7 +136,7 @@ - exec(code, mod.__dict__) - with captured_stdout() as stdout: - mod.main() -- self.assertTrue(hasattr(mod, 'initialized')) -+ self.assertHasAttr(mod, 'initialized') - self.assertEqual(stdout.getvalue(), 'Hello world!\n') - - def test_get_source(self): -diff --git a/Lib/test/test_importlib/import_/test_caching.py b/Lib/test/test_importlib/import_/test_caching.py -index aedf0fd4f9d..718e7d041b0 100644 ---- a/Lib/test/test_importlib/import_/test_caching.py -+++ b/Lib/test/test_importlib/import_/test_caching.py -@@ -78,7 +78,7 @@ - with self.create_mock('pkg.__init__', 'pkg.module') as importer: - with util.import_state(meta_path=[importer]): - module = self.__import__('pkg.module') -- self.assertTrue(hasattr(module, 'module')) -+ self.assertHasAttr(module, 'module') - self.assertEqual(id(module.module), - id(sys.modules['pkg.module'])) - -@@ -88,7 +88,7 @@ - with self.create_mock('pkg.__init__', 'pkg.module') as importer: - with util.import_state(meta_path=[importer]): - module = self.__import__('pkg', fromlist=['module']) -- self.assertTrue(hasattr(module, 'module')) -+ self.assertHasAttr(module, 'module') - self.assertEqual(id(module.module), - id(sys.modules['pkg.module'])) - -diff --git a/Lib/test/test_importlib/import_/test_fromlist.py b/Lib/test/test_importlib/import_/test_fromlist.py -index 4b4b9bc3f5e..feccc7be09a 100644 ---- a/Lib/test/test_importlib/import_/test_fromlist.py -+++ b/Lib/test/test_importlib/import_/test_fromlist.py -@@ -63,7 +63,7 @@ - with util.import_state(meta_path=[importer]): - module = self.__import__('module', fromlist=['non_existent']) - self.assertEqual(module.__name__, 'module') -- self.assertFalse(hasattr(module, 'non_existent')) -+ self.assertNotHasAttr(module, 'non_existent') - - def test_module_from_package(self): - # [module] -@@ -71,7 +71,7 @@ - with util.import_state(meta_path=[importer]): - module = self.__import__('pkg', fromlist=['module']) - self.assertEqual(module.__name__, 'pkg') -- self.assertTrue(hasattr(module, 'module')) -+ self.assertHasAttr(module, 'module') - self.assertEqual(module.module.__name__, 'pkg.module') - - def test_nonexistent_from_package(self): -@@ -79,7 +79,7 @@ - with util.import_state(meta_path=[importer]): - module = self.__import__('pkg', fromlist=['non_existent']) - self.assertEqual(module.__name__, 'pkg') -- self.assertFalse(hasattr(module, 'non_existent')) -+ self.assertNotHasAttr(module, 'non_existent') - - def test_module_from_package_triggers_ModuleNotFoundError(self): - # If a submodule causes an ModuleNotFoundError because it tries -@@ -107,7 +107,7 @@ - mock['pkg'].__all__ = ['module'] - module = self.__import__('pkg', fromlist=fromlist) - self.assertEqual(module.__name__, 'pkg') -- self.assertTrue(hasattr(module, 'module')) -+ self.assertHasAttr(module, 'module') - self.assertEqual(module.module.__name__, 'pkg.module') - - def test_using_star(self): -@@ -125,8 +125,8 @@ - mock['pkg'].__all__ = ['module1'] - module = self.__import__('pkg', fromlist=['module2', '*']) - self.assertEqual(module.__name__, 'pkg') -- self.assertTrue(hasattr(module, 'module1')) -- self.assertTrue(hasattr(module, 'module2')) -+ self.assertHasAttr(module, 'module1') -+ self.assertHasAttr(module, 'module2') - self.assertEqual(module.module1.__name__, 'pkg.module1') - self.assertEqual(module.module2.__name__, 'pkg.module2') - -@@ -136,7 +136,7 @@ - importer['pkg'].__all__ = ['non_existent'] - module = self.__import__('pkg', fromlist=['*']) - self.assertEqual(module.__name__, 'pkg') -- self.assertFalse(hasattr(module, 'non_existent')) -+ self.assertNotHasAttr(module, 'non_existent') - - def test_star_in_all(self): - with util.mock_spec('pkg.__init__') as importer: -@@ -144,7 +144,7 @@ - importer['pkg'].__all__ = ['*'] - module = self.__import__('pkg', fromlist=['*']) - self.assertEqual(module.__name__, 'pkg') -- self.assertFalse(hasattr(module, '*')) -+ self.assertNotHasAttr(module, '*') - - def test_invalid_type(self): - with util.mock_spec('pkg.__init__') as importer: -diff --git a/Lib/test/test_importlib/import_/test_meta_path.py b/Lib/test/test_importlib/import_/test_meta_path.py -index 8689017ba43..4c00f60681a 100644 ---- a/Lib/test/test_importlib/import_/test_meta_path.py -+++ b/Lib/test/test_importlib/import_/test_meta_path.py -@@ -43,7 +43,7 @@ - self.assertIsNone(importlib._bootstrap._find_spec('nothing', - None)) - self.assertEqual(len(w), 1) -- self.assertTrue(issubclass(w[-1].category, ImportWarning)) -+ self.assertIsSubclass(w[-1].category, ImportWarning) - - - (Frozen_CallingOrder, -diff --git a/Lib/test/test_importlib/import_/test_path.py b/Lib/test/test_importlib/import_/test_path.py -index 89b52fbd1e1..51ff6115e12 100644 ---- a/Lib/test/test_importlib/import_/test_path.py -+++ b/Lib/test/test_importlib/import_/test_path.py -@@ -1,3 +1,4 @@ -+from test.support import os_helper - from test.test_importlib import util - - importlib = util.import_importlib('importlib') -@@ -80,7 +81,7 @@ - self.assertIsNone(self.find('os')) - self.assertIsNone(sys.path_importer_cache[path_entry]) - self.assertEqual(len(w), 1) -- self.assertTrue(issubclass(w[-1].category, ImportWarning)) -+ self.assertIsSubclass(w[-1].category, ImportWarning) - - def test_path_importer_cache_empty_string(self): - # The empty string should create a finder using the cwd. -@@ -153,6 +154,28 @@ - # Do not want FileNotFoundError raised. - self.assertIsNone(self.machinery.PathFinder.find_spec('whatever')) - -+ @os_helper.skip_unless_working_chmod -+ def test_permission_error_cwd(self): -+ # gh-115911: Test that an unreadable CWD does not break imports, in -+ # particular during early stages of interpreter startup. -+ with ( -+ os_helper.temp_dir() as new_dir, -+ os_helper.save_mode(new_dir), -+ os_helper.change_cwd(new_dir), -+ util.import_state(path=['']), -+ ): -+ # chmod() is done here (inside the 'with' block) because the order -+ # of teardown operations cannot be the reverse of setup order. See -+ # https://github.com/python/cpython/pull/116131#discussion_r1739649390 -+ try: -+ os.chmod(new_dir, 0o000) -+ except OSError: -+ self.skipTest("platform does not allow " -+ "changing mode of the cwd") -+ -+ # Do not want PermissionError raised. -+ self.assertIsNone(self.machinery.PathFinder.find_spec('whatever')) -+ - def test_invalidate_caches_finders(self): - # Finders with an invalidate_caches() method have it called. - class FakeFinder: -diff --git a/Lib/test/test_importlib/import_/test_relative_imports.py b/Lib/test/test_importlib/import_/test_relative_imports.py -index 99c24f1fd94..e535d119763 100644 ---- a/Lib/test/test_importlib/import_/test_relative_imports.py -+++ b/Lib/test/test_importlib/import_/test_relative_imports.py -@@ -81,7 +81,7 @@ - self.__import__('pkg') # For __import__(). - module = self.__import__('', global_, fromlist=['mod2'], level=1) - self.assertEqual(module.__name__, 'pkg') -- self.assertTrue(hasattr(module, 'mod2')) -+ self.assertHasAttr(module, 'mod2') - self.assertEqual(module.mod2.attr, 'pkg.mod2') - self.relative_import_test(create, globals_, callback) - -@@ -107,7 +107,7 @@ - module = self.__import__('', global_, fromlist=['module'], - level=1) - self.assertEqual(module.__name__, 'pkg') -- self.assertTrue(hasattr(module, 'module')) -+ self.assertHasAttr(module, 'module') - self.assertEqual(module.module.attr, 'pkg.module') - self.relative_import_test(create, globals_, callback) - -@@ -131,7 +131,7 @@ - module = self.__import__('', global_, fromlist=['subpkg2'], - level=2) - self.assertEqual(module.__name__, 'pkg') -- self.assertTrue(hasattr(module, 'subpkg2')) -+ self.assertHasAttr(module, 'subpkg2') - self.assertEqual(module.subpkg2.attr, 'pkg.subpkg2.__init__') - self.relative_import_test(create, globals_, callback) - -diff --git a/Lib/test/test_importlib/resources/_path.py b/Lib/test/test_importlib/resources/_path.py -index 1f97c961469..b144628cb73 100644 ---- a/Lib/test/test_importlib/resources/_path.py -+++ b/Lib/test/test_importlib/resources/_path.py -@@ -2,15 +2,44 @@ - import functools - - from typing import Dict, Union -+from typing import runtime_checkable -+from typing import Protocol - - - #### --# from jaraco.path 3.4.1 -+# from jaraco.path 3.7.1 - --FilesSpec = Dict[str, Union[str, bytes, 'FilesSpec']] # type: ignore - -+class Symlink(str): -+ """ -+ A string indicating the target of a symlink. -+ """ -+ -+ -+FilesSpec = Dict[str, Union[str, bytes, Symlink, 'FilesSpec']] -+ -+ -+@runtime_checkable -+class TreeMaker(Protocol): -+ def __truediv__(self, *args, **kwargs): ... # pragma: no cover -+ -+ def mkdir(self, **kwargs): ... # pragma: no cover -+ -+ def write_text(self, content, **kwargs): ... # pragma: no cover -+ -+ def write_bytes(self, content): ... # pragma: no cover - --def build(spec: FilesSpec, prefix=pathlib.Path()): -+ def symlink_to(self, target): ... # pragma: no cover -+ -+ -+def _ensure_tree_maker(obj: Union[str, TreeMaker]) -> TreeMaker: -+ return obj if isinstance(obj, TreeMaker) else pathlib.Path(obj) # type: ignore[return-value] -+ -+ -+def build( -+ spec: FilesSpec, -+ prefix: Union[str, TreeMaker] = pathlib.Path(), # type: ignore[assignment] -+): - """ - Build a set of files/directories, as described by the spec. - -@@ -25,21 +54,25 @@ - ... "__init__.py": "", - ... }, - ... "baz.py": "# Some code", -- ... } -+ ... "bar.py": Symlink("baz.py"), -+ ... }, -+ ... "bing": Symlink("foo"), - ... } - >>> target = getfixture('tmp_path') - >>> build(spec, target) - >>> target.joinpath('foo/baz.py').read_text(encoding='utf-8') - '# Some code' -+ >>> target.joinpath('bing/bar.py').read_text(encoding='utf-8') -+ '# Some code' - """ - for name, contents in spec.items(): -- create(contents, pathlib.Path(prefix) / name) -+ create(contents, _ensure_tree_maker(prefix) / name) - - - @functools.singledispatch - def create(content: Union[str, bytes, FilesSpec], path): - path.mkdir(exist_ok=True) -- build(content, prefix=path) # type: ignore -+ build(content, prefix=path) # type: ignore[arg-type] - - - @create.register -@@ -52,5 +85,10 @@ - path.write_text(content, encoding='utf-8') - - -+@create.register -+def _(content: Symlink, path): -+ path.symlink_to(content) -+ -+ - # end from jaraco.path - #### -diff --git a/Lib/test/test_importlib/resources/test_files.py b/Lib/test/test_importlib/resources/test_files.py -index 933894dce2c..db8a4e62a32 100644 ---- a/Lib/test/test_importlib/resources/test_files.py -+++ b/Lib/test/test_importlib/resources/test_files.py -@@ -60,6 +60,26 @@ - class OpenNamespaceTests(FilesTests, util.DiskSetup, unittest.TestCase): - MODULE = 'namespacedata01' - -+ def test_non_paths_in_dunder_path(self): -+ """ -+ Non-path items in a namespace package's ``__path__`` are ignored. -+ -+ As reported in python/importlib_resources#311, some tools -+ like Setuptools, when creating editable packages, will inject -+ non-paths into a namespace package's ``__path__``, a -+ sentinel like -+ ``__editable__.sample_namespace-1.0.finder.__path_hook__`` -+ to cause the ``PathEntryFinder`` to be called when searching -+ for packages. In that case, resources should still be loadable. -+ """ -+ import namespacedata01 -+ -+ namespacedata01.__path__.append( -+ '__editable__.sample_namespace-1.0.finder.__path_hook__' -+ ) -+ -+ resources.files(namespacedata01) -+ - - class OpenNamespaceZipTests(FilesTests, util.ZipSetup, unittest.TestCase): - ZIP_MODULE = 'namespacedata01' -@@ -86,7 +106,7 @@ - """ - A module can have resources found adjacent to the module. - """ -- import mod -+ import mod # type: ignore[import-not-found] - - actual = resources.files(mod).joinpath('res.txt').read_text(encoding='utf-8') - assert actual == self.spec['res.txt'] -diff --git a/Lib/test/test_importlib/resources/test_functional.py b/Lib/test/test_importlib/resources/test_functional.py -index 4317abf3162..e8d25fa4d9f 100644 ---- a/Lib/test/test_importlib/resources/test_functional.py -+++ b/Lib/test/test_importlib/resources/test_functional.py -@@ -43,12 +43,6 @@ - with self.subTest(path_parts=path_parts): - yield path_parts - -- def assertEndsWith(self, string, suffix): -- """Assert that `string` ends with `suffix`. -- -- Used to ignore an architecture-specific UTF-16 byte-order mark.""" -- self.assertEqual(string[-len(suffix) :], suffix) -- - def test_read_text(self): - self.assertEqual( - resources.read_text(self.anchor01, 'utf-8.file'), -diff --git a/Lib/test/test_importlib/resources/test_path.py b/Lib/test/test_importlib/resources/test_path.py -index 378dc7a2bae..903911f57b3 100644 ---- a/Lib/test/test_importlib/resources/test_path.py -+++ b/Lib/test/test_importlib/resources/test_path.py -@@ -20,7 +20,7 @@ - target = resources.files(self.data) / 'utf-8.file' - with resources.as_file(target) as path: - self.assertIsInstance(path, pathlib.Path) -- self.assertTrue(path.name.endswith("utf-8.file"), repr(path)) -+ self.assertEndsWith(path.name, "utf-8.file") - self.assertEqual('Hello, UTF-8 world!\n', path.read_text(encoding='utf-8')) - - -diff --git a/Lib/test/test_importlib/source/test_finder.py b/Lib/test/test_importlib/source/test_finder.py -index 8c06c4da1f5..4de736a6bf3 100644 ---- a/Lib/test/test_importlib/source/test_finder.py -+++ b/Lib/test/test_importlib/source/test_finder.py -@@ -73,7 +73,7 @@ - if error.errno != errno.ENOENT: - raise - loader = self.import_(mapping['.root'], test) -- self.assertTrue(hasattr(loader, 'load_module')) -+ self.assertHasAttr(loader, 'load_module') - return loader - - def test_module(self): -@@ -100,7 +100,7 @@ - with util.create_modules('pkg.__init__', 'pkg.sub') as mapping: - pkg_dir = os.path.dirname(mapping['pkg.__init__']) - loader = self.import_(pkg_dir, 'pkg.sub') -- self.assertTrue(hasattr(loader, 'load_module')) -+ self.assertHasAttr(loader, 'load_module') - - # [sub package] - def test_package_in_package(self): -@@ -108,7 +108,7 @@ - with context as mapping: - pkg_dir = os.path.dirname(mapping['pkg.__init__']) - loader = self.import_(pkg_dir, 'pkg.sub') -- self.assertTrue(hasattr(loader, 'load_module')) -+ self.assertHasAttr(loader, 'load_module') - - # [package over modules] - def test_package_over_module(self): -@@ -129,7 +129,7 @@ - file.write("# test file for importlib") - try: - loader = self._find(finder, 'mod', loader_only=True) -- self.assertTrue(hasattr(loader, 'load_module')) -+ self.assertHasAttr(loader, 'load_module') - finally: - os.unlink('mod.py') - -diff --git a/Lib/test/test_importlib/source/test_path_hook.py b/Lib/test/test_importlib/source/test_path_hook.py -index f274330e0b3..6e1c23e6a98 100644 ---- a/Lib/test/test_importlib/source/test_path_hook.py -+++ b/Lib/test/test_importlib/source/test_path_hook.py -@@ -15,12 +15,12 @@ - - def test_success(self): - with util.create_modules('dummy') as mapping: -- self.assertTrue(hasattr(self.path_hook()(mapping['.root']), -- 'find_spec')) -+ self.assertHasAttr(self.path_hook()(mapping['.root']), -+ 'find_spec') - - def test_empty_string(self): - # The empty string represents the cwd. -- self.assertTrue(hasattr(self.path_hook()(''), 'find_spec')) -+ self.assertHasAttr(self.path_hook()(''), 'find_spec') - - - (Frozen_PathHookTest, -diff --git a/Lib/test/test_importlib/test_abc.py b/Lib/test/test_importlib/test_abc.py -index 603125f6d92..b1ab52f966f 100644 ---- a/Lib/test/test_importlib/test_abc.py -+++ b/Lib/test/test_importlib/test_abc.py -@@ -43,14 +43,12 @@ - def test_subclasses(self): - # Test that the expected subclasses inherit. - for subclass in self.subclasses: -- self.assertTrue(issubclass(subclass, self.__test), -- "{0} is not a subclass of {1}".format(subclass, self.__test)) -+ self.assertIsSubclass(subclass, self.__test) - - def test_superclasses(self): - # Test that the class inherits from the expected superclasses. - for superclass in self.superclasses: -- self.assertTrue(issubclass(self.__test, superclass), -- "{0} is not a superclass of {1}".format(superclass, self.__test)) -+ self.assertIsSubclass(self.__test, superclass) - - - class MetaPathFinder(InheritanceTests): -@@ -226,7 +224,15 @@ - SPLIT = make_abc_subclasses(ResourceLoader) - - def test_get_data(self): -- with self.assertRaises(IOError): -+ with ( -+ self.assertRaises(IOError), -+ self.assertWarnsRegex( -+ DeprecationWarning, -+ r"importlib\.abc\.ResourceLoader is deprecated in favour of " -+ r"supporting resource loading through importlib\.resources" -+ r"\.abc\.TraversableResources.", -+ ), -+ ): - self.ins.get_data('/some/path') - - -@@ -416,14 +422,14 @@ - # Since compile() can handle strings, so should source_to_code(). - source = 'attr = 42' - module = self.source_to_module(source) -- self.assertTrue(hasattr(module, 'attr')) -+ self.assertHasAttr(module, 'attr') - self.assertEqual(module.attr, 42) - - def test_source_to_code_bytes(self): - # Since compile() can handle bytes, so should source_to_code(). - source = b'attr = 42' - module = self.source_to_module(source) -- self.assertTrue(hasattr(module, 'attr')) -+ self.assertHasAttr(module, 'attr') - self.assertEqual(module.attr, 42) - - def test_source_to_code_path(self): -@@ -757,7 +763,7 @@ - warnings.simplefilter('ignore', DeprecationWarning) - module = self.loader.load_module(self.name) - self.verify_module(module) -- self.assertFalse(hasattr(module, '__path__')) -+ self.assertNotHasAttr(module, '__path__') - - def test_get_source_encoding(self): - # Source is considered encoded in UTF-8 by default unless otherwise -@@ -913,5 +919,47 @@ - SourceOnlyLoaderMock=SPLIT_SOL) - - -+class SourceLoaderDeprecationWarningsTests(unittest.TestCase): -+ """Tests SourceLoader deprecation warnings.""" -+ -+ def test_deprecated_path_mtime(self): -+ from importlib.abc import SourceLoader -+ class DummySourceLoader(SourceLoader): -+ def get_data(self, path): -+ return b'' -+ -+ def get_filename(self, fullname): -+ return 'foo.py' -+ -+ def path_stats(self, path): -+ return {'mtime': 1} -+ with self.assertWarnsRegex( -+ DeprecationWarning, -+ r"importlib\.abc\.ResourceLoader is deprecated in favour of " -+ r"supporting resource loading through importlib\.resources" -+ r"\.abc\.TraversableResources.", -+ ): -+ loader = DummySourceLoader() -+ -+ with self.assertWarnsRegex( -+ DeprecationWarning, -+ r"SourceLoader\.path_mtime is deprecated in favour of " -+ r"SourceLoader\.path_stats\(\)\." -+ ): -+ loader.path_mtime('foo.py') -+ -+ -+class ResourceLoaderDeprecationWarningsTests(unittest.TestCase): -+ """Tests ResourceLoader deprecation warnings.""" -+ -+ def test_deprecated_resource_loader(self): -+ from importlib.abc import ResourceLoader -+ class DummyLoader(ResourceLoader): -+ def get_data(self, path): -+ return b'' -+ -+ with self.assertWarns(DeprecationWarning): -+ DummyLoader() -+ - if __name__ == '__main__': - unittest.main() -diff --git a/Lib/test/test_importlib/test_api.py b/Lib/test/test_importlib/test_api.py -index 51ea5270b1a..1bc531a2fe3 100644 ---- a/Lib/test/test_importlib/test_api.py -+++ b/Lib/test/test_importlib/test_api.py -@@ -430,8 +430,7 @@ - for name, module in sys.modules.items(): - if isinstance(module, types.ModuleType): - with self.subTest(name=name): -- self.assertTrue(hasattr(module, '__loader__'), -- '{!r} lacks a __loader__ attribute'.format(name)) -+ self.assertHasAttr(module, '__loader__') - if self.machinery.BuiltinImporter.find_spec(name): - self.assertIsNot(module.__loader__, None) - elif self.machinery.FrozenImporter.find_spec(name): -@@ -441,7 +440,7 @@ - for name, module in sys.modules.items(): - if isinstance(module, types.ModuleType): - with self.subTest(name=name): -- self.assertTrue(hasattr(module, '__spec__')) -+ self.assertHasAttr(module, '__spec__') - if self.machinery.BuiltinImporter.find_spec(name): - self.assertIsNot(module.__spec__, None) - elif self.machinery.FrozenImporter.find_spec(name): -@@ -492,5 +491,18 @@ - support.check__all__(self, util['Source'], extra=extra) - - -+class TestDeprecations(unittest.TestCase): -+ def test_machinery_deprecated_attributes(self): -+ from importlib import machinery -+ attributes = ( -+ 'DEBUG_BYTECODE_SUFFIXES', -+ 'OPTIMIZED_BYTECODE_SUFFIXES', -+ ) -+ for attr in attributes: -+ with self.subTest(attr=attr): -+ with self.assertWarns(DeprecationWarning): -+ getattr(machinery, attr) -+ -+ - if __name__ == '__main__': - unittest.main() -diff --git a/Lib/test/test_importlib/test_lazy.py b/Lib/test/test_importlib/test_lazy.py -index 5c6e0303528..e48fad8898f 100644 ---- a/Lib/test/test_importlib/test_lazy.py -+++ b/Lib/test/test_importlib/test_lazy.py -@@ -125,12 +125,12 @@ - # Deleting an attribute should stay deleted. - module = self.new_module() - del module.attr -- self.assertFalse(hasattr(module, 'attr')) -+ self.assertNotHasAttr(module, 'attr') - - def test_delete_preexisting_attr(self): - module = self.new_module() - del module.__name__ -- self.assertFalse(hasattr(module, '__name__')) -+ self.assertNotHasAttr(module, '__name__') - - def test_module_substitution_error(self): - with test_util.uncache(TestingImporter.module_name): -diff --git a/Lib/test/test_importlib/test_namespace_pkgs.py b/Lib/test/test_importlib/test_namespace_pkgs.py -index cbbdada3b01..6ca0978f9bc 100644 ---- a/Lib/test/test_importlib/test_namespace_pkgs.py -+++ b/Lib/test/test_importlib/test_namespace_pkgs.py -@@ -80,7 +80,7 @@ - - def test_simple_repr(self): - import foo.one -- self.assertTrue(repr(foo).startswith("sp\xc3\xa4m\x00') - -+ @patch('socket.socket') -+ def test_tcp_timeout(self, mock_socket): -+ instance_mock_sock = mock_socket.return_value -+ instance_mock_sock.connect.side_effect = socket.timeout -+ -+ with self.assertRaises(socket.timeout): -+ logging.handlers.SysLogHandler(address=('localhost', 514), -+ socktype=socket.SOCK_STREAM, -+ timeout=1) -+ -+ instance_mock_sock.close.assert_called() -+ - @unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required") - class UnixSysLogHandlerTest(SysLogHandlerTest): - -@@ -3524,7 +3537,7 @@ - self.assertEqual(h.foo, 'bar') - self.assertEqual(h.terminator, '!\n') - logging.warning('Exclamation') -- self.assertTrue(output.getvalue().endswith('Exclamation!\n')) -+ self.assertEndsWith(output.getvalue(), 'Exclamation!\n') - - def test_config15_ok(self): - -@@ -4281,7 +4294,7 @@ - msg = self.next_message() - self.que_logger.warning(msg) - data = self.queue.get_nowait() -- self.assertTrue(isinstance(data, logging.LogRecord)) -+ self.assertIsInstance(data, logging.LogRecord) - self.assertEqual(data.name, self.que_logger.name) - self.assertEqual((data.msg, data.args), (msg, None)) - -@@ -4879,14 +4892,14 @@ - r.removeHandler(h) - h.close() - r = h.records[0] -- self.assertTrue(r.exc_text.startswith('Traceback (most recent ' -- 'call last):\n')) -- self.assertTrue(r.exc_text.endswith('\nRuntimeError: ' -- 'deliberate mistake')) -- self.assertTrue(r.stack_info.startswith('Stack (most recent ' -- 'call last):\n')) -- self.assertTrue(r.stack_info.endswith('logging.exception(\'failed\', ' -- 'stack_info=True)')) -+ self.assertStartsWith(r.exc_text, -+ 'Traceback (most recent call last):\n') -+ self.assertEndsWith(r.exc_text, -+ '\nRuntimeError: deliberate mistake') -+ self.assertStartsWith(r.stack_info, -+ 'Stack (most recent call last):\n') -+ self.assertEndsWith(r.stack_info, -+ "logging.exception('failed', stack_info=True)") - - - class LastResortTest(BaseTest): -@@ -5229,8 +5242,8 @@ - def test_str_rep(self): - r = logging.makeLogRecord({}) - s = str(r) -- self.assertTrue(s.startswith('')) -+ self.assertStartsWith(s, '') - - def test_dict_arg(self): - h = RecordingHandler() -@@ -5352,7 +5365,7 @@ - logging.logAsyncioTasks = False - runner.run(make_record(self.assertIsNone)) - finally: -- asyncio.set_event_loop_policy(None) -+ asyncio._set_event_loop_policy(None) - - @support.requires_working_socket() - def test_taskName_without_asyncio_imported(self): -@@ -5364,7 +5377,7 @@ - logging.logAsyncioTasks = False - runner.run(make_record(self.assertIsNone)) - finally: -- asyncio.set_event_loop_policy(None) -+ asyncio._set_event_loop_policy(None) - - - class BasicConfigTest(unittest.TestCase): -@@ -5668,7 +5681,7 @@ - data = f.read().strip() - self.assertRegex(data, r'Task-\d+ - hello world') - finally: -- asyncio.set_event_loop_policy(None) -+ asyncio._set_event_loop_policy(None) - if handler: - handler.close() - -@@ -5880,14 +5893,14 @@ - self.adapter.critical('foo should be here') - self.assertEqual(len(self.recording.records), 1) - record = self.recording.records[0] -- self.assertTrue(hasattr(record, 'foo')) -+ self.assertHasAttr(record, 'foo') - self.assertEqual(record.foo, '1') - - def test_extra_not_merged_by_default(self): - self.adapter.critical('foo should NOT be here', extra={'foo': 'nope'}) - self.assertEqual(len(self.recording.records), 1) - record = self.recording.records[0] -- self.assertFalse(hasattr(record, 'foo')) -+ self.assertNotHasAttr(record, 'foo') - - def test_extra_merged(self): - self.adapter = logging.LoggerAdapter(logger=self.logger, -@@ -5897,8 +5910,8 @@ - self.adapter.critical('foo and bar should be here', extra={'bar': '2'}) - self.assertEqual(len(self.recording.records), 1) - record = self.recording.records[0] -- self.assertTrue(hasattr(record, 'foo')) -- self.assertTrue(hasattr(record, 'bar')) -+ self.assertHasAttr(record, 'foo') -+ self.assertHasAttr(record, 'bar') - self.assertEqual(record.foo, '1') - self.assertEqual(record.bar, '2') - -@@ -5910,7 +5923,7 @@ - self.adapter.critical('foo shall be min', extra={'foo': '2'}) - self.assertEqual(len(self.recording.records), 1) - record = self.recording.records[0] -- self.assertTrue(hasattr(record, 'foo')) -+ self.assertHasAttr(record, 'foo') - self.assertEqual(record.foo, '2') - - -@@ -6624,18 +6637,19 @@ - p = '%s.log.' % prefix - for c in candidates: - d, fn = os.path.split(c) -- self.assertTrue(fn.startswith(p)) -+ self.assertStartsWith(fn, p) - elif prefix.startswith('d.e'): - for c in candidates: - d, fn = os.path.split(c) -- self.assertTrue(fn.endswith('.log'), fn) -- self.assertTrue(fn.startswith(prefix + '.') and -- fn[len(prefix) + 2].isdigit()) -+ self.assertEndsWith(fn, '.log') -+ self.assertStartsWith(fn, prefix + '.') -+ self.assertTrue(fn[len(prefix) + 2].isdigit()) - elif prefix == 'g': - for c in candidates: - d, fn = os.path.split(c) -- self.assertTrue(fn.endswith('.oldlog')) -- self.assertTrue(fn.startswith('g') and fn[1].isdigit()) -+ self.assertEndsWith(fn, '.oldlog') -+ self.assertStartsWith(fn, 'g') -+ self.assertTrue(fn[1].isdigit()) - - def test_compute_files_to_delete_same_filename_different_extensions(self): - # See GH-93205 for background -@@ -6673,7 +6687,7 @@ - matcher = re.compile(r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}\Z") - for c in candidates: - d, fn = os.path.split(c) -- self.assertTrue(fn.startswith(prefix+'.')) -+ self.assertStartsWith(fn, prefix+'.') - suffix = fn[(len(prefix)+1):] - self.assertRegex(suffix, matcher) - -diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py -index 19978118c80..f336d49fa4f 100644 ---- a/Lib/test/test_long.py -+++ b/Lib/test/test_long.py -@@ -1470,7 +1470,6 @@ - b'\x00': 0, - b'\x00\x00': 0, - b'\x01': 1, -- b'\x00\x01': 256, - b'\xff': -1, - b'\xff\xff': -1, - b'\x81': -127, -diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py -index 6976a5d85da..2c57d288bc0 100644 ---- a/Lib/test/test_math.py -+++ b/Lib/test/test_math.py -@@ -2503,6 +2503,46 @@ - self.assertRaises(TypeError, math.atan2, 1.0) - self.assertRaises(TypeError, math.atan2, 1.0, 2.0, 3.0) - -+ def test_exception_messages(self): -+ x = -1.1 -+ with self.assertRaisesRegex(ValueError, -+ f"expected a nonnegative input, got {x}"): -+ math.sqrt(x) -+ with self.assertRaisesRegex(ValueError, -+ f"expected a positive input, got {x}"): -+ math.log(x) -+ with self.assertRaisesRegex(ValueError, -+ f"expected a positive input, got {x}"): -+ math.log(123, x) -+ with self.assertRaisesRegex(ValueError, -+ f"expected a positive input, got {x}"): -+ math.log(x, 123) -+ with self.assertRaisesRegex(ValueError, -+ f"expected a positive input, got {x}"): -+ math.log2(x) -+ with self.assertRaisesRegex(ValueError, -+ f"expected a positive input, got {x}"): -+ math.log10(x) -+ x = decimal.Decimal('-1.1') -+ with self.assertRaisesRegex(ValueError, -+ f"expected a positive input, got {x}"): -+ math.log(x) -+ x = fractions.Fraction(1, 10**400) -+ with self.assertRaisesRegex(ValueError, -+ f"expected a positive input, got {float(x)}"): -+ math.log(x) -+ x = -123 -+ with self.assertRaisesRegex(ValueError, -+ f"expected a positive input, got {x}"): -+ math.log(x) -+ with self.assertRaisesRegex(ValueError, -+ f"expected a float or nonnegative integer, got {x}"): -+ math.gamma(x) -+ x = 1.0 -+ with self.assertRaisesRegex(ValueError, -+ f"expected a number between -1 and 1, got {x}"): -+ math.atanh(x) -+ - # Custom assertions. - - def assertIsNaN(self, value): -diff --git a/Lib/test/test_metaclass.py b/Lib/test/test_metaclass.py -index b37b7defe84..07a333f98fa 100644 ---- a/Lib/test/test_metaclass.py -+++ b/Lib/test/test_metaclass.py -@@ -254,6 +254,33 @@ - [...] - test.test_metaclass.ObscureException - -+Test setting attributes with a non-base type in mro() (gh-127773). -+ -+ >>> class Base: -+ ... value = 1 -+ ... -+ >>> class Meta(type): -+ ... def mro(cls): -+ ... return (cls, Base, object) -+ ... -+ >>> class WeirdClass(metaclass=Meta): -+ ... pass -+ ... -+ >>> Base.value -+ 1 -+ >>> WeirdClass.value -+ 1 -+ >>> Base.value = 2 -+ >>> Base.value -+ 2 -+ >>> WeirdClass.value -+ 2 -+ >>> Base.value = 3 -+ >>> Base.value -+ 3 -+ >>> WeirdClass.value -+ 3 -+ - """ - - import sys -diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py -index 5a4bcebedf1..3125d190626 100644 ---- a/Lib/test/test_monitoring.py -+++ b/Lib/test/test_monitoring.py -@@ -12,9 +12,9 @@ - - import test.support - from test.support import requires_specialization_ft, script_helper --from test.support.import_helper import import_module - - _testcapi = test.support.import_helper.import_module("_testcapi") -+_testinternalcapi = test.support.import_helper.import_module("_testinternalcapi") - - PAIR = (0,1) - -@@ -850,12 +850,6 @@ - def __call__(self, code, offset, val): - self.events.append(("return", code.co_name, val)) - --# gh-127274: CALL_ALLOC_AND_ENTER_INIT will only cache __init__ methods that --# are deferred. We only defer functions defined at the top-level. --class ValueErrorRaiser: -- def __init__(self): -- raise ValueError() -- - - class ExceptionMonitoringTest(CheckEvents): - -@@ -904,13 +898,13 @@ - # re-specialize immediately, so that we can we can test the - # unspecialized version of the loop first. - # Note: this assumes that we don't specialize loops over sets. -- implicit_stop_iteration(set(range(100))) -+ implicit_stop_iteration(set(range(_testinternalcapi.SPECIALIZATION_THRESHOLD))) - - # This will record a RAISE event for the StopIteration. - self.check_events(implicit_stop_iteration, expected, recorders=recorders) - - # Now specialize, so that we see a STOP_ITERATION event. -- for _ in range(100): -+ for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN): - implicit_stop_iteration() - - # This will record a STOP_ITERATION event for the StopIteration. -@@ -1054,6 +1048,9 @@ - - @requires_specialization_ft - def test_no_unwind_for_shim_frame(self): -+ class ValueErrorRaiser: -+ def __init__(self): -+ raise ValueError() - - def f(): - try: -@@ -1061,7 +1058,7 @@ - except ValueError: - pass - -- for _ in range(100): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - f() - recorders = ( - ReturnRecorder, -@@ -1491,7 +1488,15 @@ - event_type = E.BRANCH - name = "branch" - -+class BranchRightRecorder(JumpRecorder): -+ -+ event_type = E.BRANCH_RIGHT -+ name = "branch right" -+ -+class BranchLeftRecorder(JumpRecorder): - -+ event_type = E.BRANCH_LEFT -+ name = "branch left" - - class JumpOffsetRecorder: - -@@ -1504,16 +1509,23 @@ - def __call__(self, code, from_, to): - self.events.append((self.name, code.co_name, from_, to)) - --class BranchOffsetRecorder(JumpOffsetRecorder): -+class BranchLeftOffsetRecorder(JumpOffsetRecorder): - -- event_type = E.BRANCH -- name = "branch" -+ event_type = E.BRANCH_LEFT -+ name = "branch left" -+ -+class BranchRightOffsetRecorder(JumpOffsetRecorder): -+ -+ event_type = E.BRANCH_RIGHT -+ name = "branch right" - - - JUMP_AND_BRANCH_RECORDERS = JumpRecorder, BranchRecorder - JUMP_BRANCH_AND_LINE_RECORDERS = JumpRecorder, BranchRecorder, LineRecorder - FLOW_AND_LINE_RECORDERS = JumpRecorder, BranchRecorder, LineRecorder, ExceptionRecorder, ReturnRecorder --BRANCH_OFFSET_RECORDERS = BranchOffsetRecorder, -+ -+BRANCHES_RECORDERS = BranchLeftRecorder, BranchRightRecorder -+BRANCH_OFFSET_RECORDERS = BranchLeftOffsetRecorder, BranchRightOffsetRecorder - - class TestBranchAndJumpEvents(CheckEvents): - maxDiff = None -@@ -1529,6 +1541,11 @@ - x = 6 - 7 - -+ def whilefunc(n=0): -+ while n < 3: -+ n += 1 # line 2 -+ 3 -+ - self.check_events(func, recorders = JUMP_AND_BRANCH_RECORDERS, expected = [ - ('branch', 'func', 2, 2), - ('branch', 'func', 3, 6), -@@ -1558,6 +1575,26 @@ - ('line', 'func', 7), - ('line', 'get_events', 11)]) - -+ self.check_events(func, recorders = BRANCHES_RECORDERS, expected = [ -+ ('branch left', 'func', 2, 2), -+ ('branch right', 'func', 3, 6), -+ ('branch left', 'func', 2, 2), -+ ('branch left', 'func', 3, 4), -+ ('branch right', 'func', 2, 7)]) -+ -+ self.check_events(whilefunc, recorders = BRANCHES_RECORDERS, expected = [ -+ ('branch left', 'whilefunc', 1, 2), -+ ('branch left', 'whilefunc', 1, 2), -+ ('branch left', 'whilefunc', 1, 2), -+ ('branch right', 'whilefunc', 1, 3)]) -+ -+ self.check_events(func, recorders = BRANCH_OFFSET_RECORDERS, expected = [ -+ ('branch left', 'func', 28, 32), -+ ('branch right', 'func', 44, 58), -+ ('branch left', 'func', 28, 32), -+ ('branch left', 'func', 44, 50), -+ ('branch right', 'func', 28, 70)]) -+ - def test_except_star(self): - - class Foo: -@@ -1583,8 +1620,8 @@ - ('branch', 'func', 4, 4), - ('line', 'func', 5), - ('line', 'meth', 1), -- ('jump', 'func', 5, '[offset=118]'), -- ('branch', 'func', '[offset=122]', '[offset=126]'), -+ ('jump', 'func', 5, '[offset=120]'), -+ ('branch', 'func', '[offset=124]', '[offset=130]'), - ('line', 'get_events', 11)]) - - self.check_events(func, recorders = FLOW_AND_LINE_RECORDERS, expected = [ -@@ -1598,8 +1635,8 @@ - ('line', 'func', 5), - ('line', 'meth', 1), - ('return', 'meth', None), -- ('jump', 'func', 5, '[offset=118]'), -- ('branch', 'func', '[offset=122]', '[offset=126]'), -+ ('jump', 'func', 5, '[offset=120]'), -+ ('branch', 'func', '[offset=124]', '[offset=130]'), - ('return', 'func', None), - ('line', 'get_events', 11)]) - -@@ -1611,8 +1648,8 @@ - n += 1 - return None - -- in_loop = ('branch', 'foo', 10, 14) -- exit_loop = ('branch', 'foo', 10, 30) -+ in_loop = ('branch left', 'foo', 10, 16) -+ exit_loop = ('branch right', 'foo', 10, 40) - self.check_events(foo, recorders = BRANCH_OFFSET_RECORDERS, expected = [ - in_loop, - in_loop, -@@ -1621,6 +1658,88 @@ - exit_loop]) - - -+class TestBranchConsistency(MonitoringTestBase, unittest.TestCase): -+ -+ def check_branches(self, func, tool=TEST_TOOL, recorders=BRANCH_OFFSET_RECORDERS): -+ try: -+ self.assertEqual(sys.monitoring._all_events(), {}) -+ event_list = [] -+ all_events = 0 -+ for recorder in recorders: -+ ev = recorder.event_type -+ sys.monitoring.register_callback(tool, ev, recorder(event_list)) -+ all_events |= ev -+ sys.monitoring.set_local_events(tool, func.__code__, all_events) -+ func() -+ sys.monitoring.set_local_events(tool, func.__code__, 0) -+ for recorder in recorders: -+ sys.monitoring.register_callback(tool, recorder.event_type, None) -+ lefts = set() -+ rights = set() -+ for (src, left, right) in func.__code__.co_branches(): -+ lefts.add((src, left)) -+ rights.add((src, right)) -+ for event in event_list: -+ way, _, src, dest = event -+ if "left" in way: -+ self.assertIn((src, dest), lefts) -+ else: -+ self.assertIn("right", way) -+ self.assertIn((src, dest), rights) -+ finally: -+ sys.monitoring.set_local_events(tool, func.__code__, 0) -+ for recorder in recorders: -+ sys.monitoring.register_callback(tool, recorder.event_type, None) -+ -+ def test_simple(self): -+ -+ def func(): -+ x = 1 -+ for a in range(2): -+ if a: -+ x = 4 -+ else: -+ x = 6 -+ 7 -+ -+ self.check_branches(func) -+ -+ def whilefunc(n=0): -+ while n < 3: -+ n += 1 # line 2 -+ 3 -+ -+ self.check_branches(whilefunc) -+ -+ def test_except_star(self): -+ -+ class Foo: -+ def meth(self): -+ pass -+ -+ def func(): -+ try: -+ try: -+ raise KeyError -+ except* Exception as e: -+ f = Foo(); f.meth() -+ except KeyError: -+ pass -+ -+ -+ self.check_branches(func) -+ -+ def test4(self): -+ -+ def foo(n=0): -+ while n<4: -+ pass -+ n += 1 -+ return None -+ -+ self.check_branches(foo) -+ -+ - class TestLoadSuperAttr(CheckEvents): - RECORDERS = CallRecorder, LineRecorder, CRaiseRecorder, CReturnRecorder - -@@ -1852,6 +1971,10 @@ - code = f1.__code__ - sys.monitoring.set_local_events(TEST_TOOL, code, E.PY_START) - self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL, code), E.PY_START) -+ sys.monitoring.set_local_events(TEST_TOOL, code, 0) -+ sys.monitoring.set_local_events(TEST_TOOL, code, E.BRANCH) -+ self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL, code), E.BRANCH_LEFT | E.BRANCH_RIGHT) -+ sys.monitoring.set_local_events(TEST_TOOL, code, 0) - sys.monitoring.set_local_events(TEST_TOOL2, code, E.PY_START) - self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL2, code), E.PY_START) - sys.monitoring.set_local_events(TEST_TOOL, code, 0) -@@ -1911,8 +2034,8 @@ - sys.monitoring.set_events(TEST_TOOL, E.PY_RESUME) - - def make_foo_optimized_then_set_event(): -- for i in range(100): -- Foo(i == 99) -+ for i in range(_testinternalcapi.SPECIALIZATION_THRESHOLD + 1): -+ Foo(i == _testinternalcapi.SPECIALIZATION_THRESHOLD) - - try: - make_foo_optimized_then_set_event() -@@ -1964,20 +2087,6 @@ - - class TestOptimizer(MonitoringTestBase, unittest.TestCase): - -- def setUp(self): -- _testinternalcapi = import_module("_testinternalcapi") -- if hasattr(_testinternalcapi, "get_optimizer"): -- self.old_opt = _testinternalcapi.get_optimizer() -- opt = _testinternalcapi.new_counter_optimizer() -- _testinternalcapi.set_optimizer(opt) -- super(TestOptimizer, self).setUp() -- -- def tearDown(self): -- super(TestOptimizer, self).tearDown() -- import _testinternalcapi -- if hasattr(_testinternalcapi, "get_optimizer"): -- _testinternalcapi.set_optimizer(self.old_opt) -- - def test_for_loop(self): - def test_func(x): - i = 0 -@@ -1998,9 +2107,9 @@ - set_events = sys.monitoring.set_events - line = E.LINE - i = 0 -- for i in range(551): -- # Turn on events without branching once i reaches 500. -- set_events(TEST_TOOL, line * int(i >= 500)) -+ for i in range(_testinternalcapi.SPECIALIZATION_THRESHOLD + 51): -+ # Turn on events without branching once i reaches _testinternalcapi.SPECIALIZATION_THRESHOLD. -+ set_events(TEST_TOOL, line * int(i >= _testinternalcapi.SPECIALIZATION_THRESHOLD)) - pass - pass - pass -@@ -2053,7 +2162,8 @@ - ( 1, E.PY_RETURN, capi.fire_event_py_return, 20), - ( 2, E.CALL, capi.fire_event_call, callable, 40), - ( 1, E.JUMP, capi.fire_event_jump, 60), -- ( 1, E.BRANCH, capi.fire_event_branch, 70), -+ ( 1, E.BRANCH_RIGHT, capi.fire_event_branch_right, 70), -+ ( 1, E.BRANCH_LEFT, capi.fire_event_branch_left, 80), - ( 1, E.PY_THROW, capi.fire_event_py_throw, ValueError(1)), - ( 1, E.RAISE, capi.fire_event_raise, ValueError(2)), - ( 1, E.EXCEPTION_HANDLED, capi.fire_event_exception_handled, ValueError(5)), -diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py -index 6715071af8c..da01c65a1c2 100644 ---- a/Lib/test/test_ntpath.py -+++ b/Lib/test/test_ntpath.py -@@ -940,7 +940,7 @@ - self.assertRaises(TypeError, ntpath.commonpath, ['C:\\Foo', b'Foo\\Baz']) - self.assertRaises(TypeError, ntpath.commonpath, ['Foo', b'C:\\Foo\\Baz']) - -- @unittest.skipIf(is_emscripten, "Emscripten cannot fstat unnamed files.") -+ @unittest.skipIf(is_emscripten, "Fixed in next Emscripten release after 4.0.1") - def test_sameopenfile(self): - with TemporaryFile() as tf1, TemporaryFile() as tf2: - # Make sure the same file is really the same -diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py -index 0a7557adc47..e4224b843b2 100644 ---- a/Lib/test/test_opcache.py -+++ b/Lib/test/test_opcache.py -@@ -6,7 +6,7 @@ - import unittest - from test.support import (threading_helper, check_impl_detail, - requires_specialization, requires_specialization_ft, -- cpython_only) -+ cpython_only, requires_jit_disabled, reset_code) - from test.support.import_helper import import_module - - # Skip this module on other interpreters, it is cpython specific: -@@ -16,20 +16,6 @@ - _testinternalcapi = import_module("_testinternalcapi") - - --def disabling_optimizer(func): -- def wrapper(*args, **kwargs): -- if not hasattr(_testinternalcapi, "get_optimizer"): -- return func(*args, **kwargs) -- old_opt = _testinternalcapi.get_optimizer() -- _testinternalcapi.set_optimizer(None) -- try: -- return func(*args, **kwargs) -- finally: -- _testinternalcapi.set_optimizer(old_opt) -- -- return wrapper -- -- - class TestBase(unittest.TestCase): - def assert_specialized(self, f, opname): - instructions = dis.get_instructions(f, adaptive=True) -@@ -59,7 +45,8 @@ - - d = D() - -- self.assertEqual(d.f(), 1) # warmup -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD - 1): -+ self.assertEqual(d.f(), 1) # warmup - calls.clear() - self.assertEqual(d.f(), 1) # try to specialize - self.assertEqual(calls, [(d, D)]) -@@ -79,7 +66,7 @@ - return o.x - - o = C() -- for i in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - assert f(o) == 1 - - Descriptor.__get__ = lambda self, instance, value: 2 -@@ -106,13 +93,13 @@ - def f(): - return Class.attribute - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - self.assertTrue(f()) - - Descriptor.__get__ = __get__ - Descriptor.__set__ = __set__ - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN): - self.assertFalse(f()) - - def test_metaclass_descriptor_shadows_class_attribute(self): -@@ -127,7 +114,7 @@ - def f(): - return Class.attribute - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - self.assertTrue(f()) - - def test_metaclass_set_descriptor_after_optimization(self): -@@ -144,12 +131,12 @@ - def f(): - return Class.attribute - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - self.assertTrue(f()) - - Metaclass.attribute = attribute - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN): - self.assertFalse(f()) - - def test_metaclass_del_descriptor_after_optimization(self): -@@ -164,12 +151,12 @@ - def f(): - return Class.attribute - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - self.assertTrue(f()) - - del Metaclass.attribute - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN): - self.assertFalse(f()) - - def test_type_descriptor_shadows_attribute_method(self): -@@ -179,7 +166,7 @@ - def f(): - return Class.mro - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - self.assertIsNone(f()) - - def test_type_descriptor_shadows_attribute_member(self): -@@ -189,7 +176,7 @@ - def f(): - return Class.__base__ - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - self.assertIs(f(), object) - - def test_type_descriptor_shadows_attribute_getset(self): -@@ -199,7 +186,7 @@ - def f(): - return Class.__name__ - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - self.assertEqual(f(), "Class") - - def test_metaclass_getattribute(self): -@@ -213,7 +200,7 @@ - def f(): - return Class.attribute - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - self.assertTrue(f()) - - def test_metaclass_swap(self): -@@ -233,12 +220,12 @@ - def f(): - return Class.attribute - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - self.assertTrue(f()) - - Class.__class__ = NewMetaclass - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN): - self.assertFalse(f()) - - def test_load_shadowing_slot_should_raise_type_error(self): -@@ -255,7 +242,7 @@ - o = Sneaky() - o.shadowed = 42 - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - with self.assertRaises(TypeError): - f(o) - -@@ -272,7 +259,7 @@ - - o = Sneaky() - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - with self.assertRaises(TypeError): - f(o) - -@@ -288,7 +275,7 @@ - - o = Sneaky() - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - with self.assertRaises(TypeError): - f(o) - -@@ -304,7 +291,7 @@ - - o = Sneaky() - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - with self.assertRaises(TypeError): - f(o) - -@@ -332,13 +319,13 @@ - def f(): - return instance.attribute() - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - self.assertTrue(f()) - - Descriptor.__get__ = __get__ - Descriptor.__set__ = __set__ - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN): - self.assertFalse(f()) - - def test_metaclass_descriptor_added_after_optimization(self): -@@ -361,13 +348,13 @@ - def f(): - return Class.attribute() - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - self.assertTrue(f()) - - Descriptor.__get__ = __get__ - Descriptor.__set__ = __set__ - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN): - self.assertFalse(f()) - - def test_metaclass_descriptor_shadows_class_attribute(self): -@@ -383,7 +370,7 @@ - def f(): - return Class.attribute() - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - self.assertTrue(f()) - - def test_metaclass_set_descriptor_after_optimization(self): -@@ -401,12 +388,12 @@ - def f(): - return Class.attribute() - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - self.assertTrue(f()) - - Metaclass.attribute = attribute - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN): - self.assertFalse(f()) - - def test_metaclass_del_descriptor_after_optimization(self): -@@ -422,12 +409,12 @@ - def f(): - return Class.attribute() - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - self.assertTrue(f()) - - del Metaclass.attribute - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN): - self.assertFalse(f()) - - def test_type_descriptor_shadows_attribute_method(self): -@@ -438,7 +425,7 @@ - def f(): - return Class.mro() - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - self.assertEqual(f(), ["Spam", "eggs"]) - - def test_type_descriptor_shadows_attribute_member(self): -@@ -449,7 +436,7 @@ - def f(): - return Class.__base__() - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - self.assertNotEqual(f(), "Spam") - - def test_metaclass_getattribute(self): -@@ -464,7 +451,7 @@ - def f(): - return Class.attribute() - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - self.assertTrue(f()) - - def test_metaclass_swap(self): -@@ -484,22 +471,15 @@ - def f(): - return Class.attribute() - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - self.assertTrue(f()) - - Class.__class__ = NewMetaclass - -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN): - self.assertFalse(f()) - - --# gh-127274: CALL_ALLOC_AND_ENTER_INIT will only cache __init__ methods that --# are deferred. We only defer functions defined at the top-level. --class MyClass: -- def __init__(self): -- pass -- -- - class InitTakesArg: - def __init__(self, arg): - self.arg = arg -@@ -511,7 +491,7 @@ - pass - - f.__defaults__ = (None,) -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - f() - - def test_too_many_defaults_1(self): -@@ -519,7 +499,7 @@ - pass - - f.__defaults__ = (None, None) -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - f(None) - f() - -@@ -528,19 +508,23 @@ - pass - - f.__defaults__ = (None, None, None) -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - f(None, None) - f(None) - f() - -- @disabling_optimizer -+ @requires_jit_disabled - @requires_specialization_ft - def test_assign_init_code(self): -+ class MyClass: -+ def __init__(self): -+ pass -+ - def instantiate(): - return MyClass() - - # Trigger specialization -- for _ in range(1025): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - instantiate() - self.assert_specialized(instantiate, "CALL_ALLOC_AND_ENTER_INIT") - -@@ -552,13 +536,13 @@ - MyClass.__init__.__code__ = count_args.__code__ - instantiate() - -- @disabling_optimizer -+ @requires_jit_disabled - @requires_specialization_ft - def test_push_init_frame_fails(self): - def instantiate(): - return InitTakesArg() - -- for _ in range(2): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - with self.assertRaises(TypeError): - instantiate() - self.assert_specialized(instantiate, "CALL_ALLOC_AND_ENTER_INIT") -@@ -567,16 +551,25 @@ - instantiate() - - -+def make_deferred_ref_count_obj(): -+ """Create an object that uses deferred reference counting. -+ -+ Only objects that use deferred refence counting may be stored in inline -+ caches in free-threaded builds. This constructs a new class named Foo, -+ which uses deferred reference counting. -+ """ -+ return type("Foo", (object,), {}) -+ -+ - @threading_helper.requires_working_threading() - class TestRacesDoNotCrash(TestBase): - # Careful with these. Bigger numbers have a higher chance of catching bugs, - # but you can also burn through a *ton* of type/dict/function versions: - ITEMS = 1000 - LOOPS = 4 -- WARMUPS = 2 - WRITERS = 2 - -- @disabling_optimizer -+ @requires_jit_disabled - def assert_races_do_not_crash( - self, opname, get_items, read, write, *, check_items=False - ): -@@ -586,11 +579,11 @@ - # Reset: - if check_items: - for item in items: -- item.__code__ = item.__code__.replace() -+ reset_code(item) - else: -- read.__code__ = read.__code__.replace() -+ reset_code(read) - # Specialize: -- for _ in range(self.WARMUPS): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - read(items) - if check_items: - for item in items: -@@ -609,7 +602,7 @@ - for writer in writers: - writer.join() - -- @requires_specialization -+ @requires_specialization_ft - def test_binary_subscr_getitem(self): - def get_items(): - class C: -@@ -636,7 +629,7 @@ - pass - type(item).__getitem__ = lambda self, item: None - -- opname = "BINARY_SUBSCR_GETITEM" -+ opname = "BINARY_OP_SUBSCR_GETITEM" - self.assert_races_do_not_crash(opname, get_items, read, write) - - @requires_specialization_ft -@@ -660,7 +653,7 @@ - item.clear() - item.append(None) - -- opname = "BINARY_SUBSCR_LIST_INT" -+ opname = "BINARY_OP_SUBSCR_LIST_INT" - self.assert_races_do_not_crash(opname, get_items, read, write) - - @requires_specialization -@@ -717,11 +710,11 @@ - opname = "FOR_ITER_LIST" - self.assert_races_do_not_crash(opname, get_items, read, write) - -- @requires_specialization -+ @requires_specialization_ft - def test_load_attr_class(self): - def get_items(): - class C: -- a = object() -+ a = make_deferred_ref_count_obj() - - items = [] - for _ in range(self.ITEMS): -@@ -742,12 +735,45 @@ - del item.a - except AttributeError: - pass -- item.a = object() -+ item.a = make_deferred_ref_count_obj() - - opname = "LOAD_ATTR_CLASS" - self.assert_races_do_not_crash(opname, get_items, read, write) - -- @requires_specialization -+ @requires_specialization_ft -+ def test_load_attr_class_with_metaclass_check(self): -+ def get_items(): -+ class Meta(type): -+ pass -+ -+ class C(metaclass=Meta): -+ a = make_deferred_ref_count_obj() -+ -+ items = [] -+ for _ in range(self.ITEMS): -+ item = C -+ items.append(item) -+ return items -+ -+ def read(items): -+ for item in items: -+ try: -+ item.a -+ except AttributeError: -+ pass -+ -+ def write(items): -+ for item in items: -+ try: -+ del item.a -+ except AttributeError: -+ pass -+ item.a = make_deferred_ref_count_obj() -+ -+ opname = "LOAD_ATTR_CLASS_WITH_METACLASS_CHECK" -+ self.assert_races_do_not_crash(opname, get_items, read, write) -+ -+ @requires_specialization_ft - def test_load_attr_getattribute_overridden(self): - def get_items(): - class C: -@@ -777,7 +803,7 @@ - opname = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN" - self.assert_races_do_not_crash(opname, get_items, read, write) - -- @requires_specialization -+ @requires_specialization_ft - def test_load_attr_instance_value(self): - def get_items(): - class C: -@@ -801,7 +827,7 @@ - opname = "LOAD_ATTR_INSTANCE_VALUE" - self.assert_races_do_not_crash(opname, get_items, read, write) - -- @requires_specialization -+ @requires_specialization_ft - def test_load_attr_method_lazy_dict(self): - def get_items(): - class C(Exception): -@@ -831,7 +857,7 @@ - opname = "LOAD_ATTR_METHOD_LAZY_DICT" - self.assert_races_do_not_crash(opname, get_items, read, write) - -- @requires_specialization -+ @requires_specialization_ft - def test_load_attr_method_no_dict(self): - def get_items(): - class C: -@@ -862,7 +888,7 @@ - opname = "LOAD_ATTR_METHOD_NO_DICT" - self.assert_races_do_not_crash(opname, get_items, read, write) - -- @requires_specialization -+ @requires_specialization_ft - def test_load_attr_method_with_values(self): - def get_items(): - class C: -@@ -917,7 +943,7 @@ - opname = "LOAD_ATTR_MODULE" - self.assert_races_do_not_crash(opname, get_items, read, write) - -- @requires_specialization -+ @requires_specialization_ft - def test_load_attr_property(self): - def get_items(): - class C: -@@ -947,7 +973,34 @@ - opname = "LOAD_ATTR_PROPERTY" - self.assert_races_do_not_crash(opname, get_items, read, write) - -- @requires_specialization -+ @requires_specialization_ft -+ def test_load_attr_slot(self): -+ def get_items(): -+ class C: -+ __slots__ = ["a", "b"] -+ -+ items = [] -+ for i in range(self.ITEMS): -+ item = C() -+ item.a = i -+ item.b = i + self.ITEMS -+ items.append(item) -+ return items -+ -+ def read(items): -+ for item in items: -+ item.a -+ item.b -+ -+ def write(items): -+ for item in items: -+ item.a = 100 -+ item.b = 200 -+ -+ opname = "LOAD_ATTR_SLOT" -+ self.assert_races_do_not_crash(opname, get_items, read, write) -+ -+ @requires_specialization_ft - def test_load_attr_with_hint(self): - def get_items(): - class C: -@@ -958,7 +1011,7 @@ - item = C() - item.a = None - # Resize into a combined unicode dict: -- for i in range(29): -+ for i in range(_testinternalcapi.SHARED_KEYS_MAX_SIZE - 1): - setattr(item, f"_{i}", None) - items.append(item) - return items -@@ -1029,7 +1082,7 @@ - for _ in range(self.ITEMS): - item = C() - # Resize into a combined unicode dict: -- for i in range(29): -+ for i in range(_testinternalcapi.SHARED_KEYS_MAX_SIZE - 1): - setattr(item, f"_{i}", None) - items.append(item) - return items -@@ -1069,7 +1122,7 @@ - opname = "STORE_SUBSCR_LIST_INT" - self.assert_races_do_not_crash(opname, get_items, read, write) - -- @requires_specialization -+ @requires_specialization_ft - def test_unpack_sequence_list(self): - def get_items(): - items = [] -@@ -1125,7 +1178,7 @@ - c.a = 1 - c.b = 2 - c.__dict__ -- for _ in range(100): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - c.a - self.assertEqual( - _testinternalcapi.get_object_dict_values(c), -@@ -1137,7 +1190,7 @@ - c.a = 1 - c.b = 2 - d = c.__dict__ -- for _ in range(100): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - c.a - self.assertIs(c.__dict__, d) - -@@ -1146,7 +1199,7 @@ - c.a = 1 - c.b = 2 - c2 = copy.copy(c) -- for _ in range(100): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - c.a - c2.a - self.assertEqual( -@@ -1158,7 +1211,7 @@ - (1, 2, '') - ) - c3 = copy.deepcopy(c) -- for _ in range(100): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - c.a - c3.a - self.assertEqual( -@@ -1172,7 +1225,7 @@ - c.a = 1 - c.b = 2 - c2 = pickle.loads(pickle.dumps(c)) -- for _ in range(100): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - c.a - c2.a - self.assertEqual( -@@ -1190,7 +1243,7 @@ - c.a = 1 - c.b = 2 - c.__dict__ = D(c.__dict__) -- for _ in range(100): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - c.a - self.assertIs( - _testinternalcapi.get_object_dict_values(c), -@@ -1235,7 +1288,7 @@ - for i in range(n): - o.b = i - # Prime f to store to dict slot 1 -- f(c, 100) -+ f(c, _testinternalcapi.SPECIALIZATION_THRESHOLD) - - test_obj = NoInlineAorB() - test_obj.__dict__ = make_special_dict() -@@ -1252,7 +1305,7 @@ - @requires_specialization_ft - def test_binary_op(self): - def binary_op_add_int(): -- for _ in range(100): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - a, b = 1, 2 - c = a + b - self.assertEqual(c, 3) -@@ -1262,7 +1315,7 @@ - self.assert_no_opcode(binary_op_add_int, "BINARY_OP") - - def binary_op_add_unicode(): -- for _ in range(100): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - a, b = "foo", "bar" - c = a + b - self.assertEqual(c, "foobar") -@@ -1271,6 +1324,103 @@ - self.assert_specialized(binary_op_add_unicode, "BINARY_OP_ADD_UNICODE") - self.assert_no_opcode(binary_op_add_unicode, "BINARY_OP") - -+ def binary_op_add_extend(): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): -+ a, b = 6, 3.0 -+ c = a + b -+ self.assertEqual(c, 9.0) -+ c = b + a -+ self.assertEqual(c, 9.0) -+ c = a - b -+ self.assertEqual(c, 3.0) -+ c = b - a -+ self.assertEqual(c, -3.0) -+ c = a * b -+ self.assertEqual(c, 18.0) -+ c = b * a -+ self.assertEqual(c, 18.0) -+ c = a / b -+ self.assertEqual(c, 2.0) -+ c = b / a -+ self.assertEqual(c, 0.5) -+ -+ binary_op_add_extend() -+ self.assert_specialized(binary_op_add_extend, "BINARY_OP_EXTEND") -+ self.assert_no_opcode(binary_op_add_extend, "BINARY_OP") -+ -+ def binary_op_zero_division(): -+ def compactlong_lhs(arg): -+ 42 / arg -+ def float_lhs(arg): -+ 42.0 / arg -+ -+ with self.assertRaises(ZeroDivisionError): -+ compactlong_lhs(0) -+ with self.assertRaises(ZeroDivisionError): -+ compactlong_lhs(0.0) -+ with self.assertRaises(ZeroDivisionError): -+ float_lhs(0.0) -+ with self.assertRaises(ZeroDivisionError): -+ float_lhs(0) -+ -+ self.assert_no_opcode(compactlong_lhs, "BINARY_OP_EXTEND") -+ self.assert_no_opcode(float_lhs, "BINARY_OP_EXTEND") -+ -+ binary_op_zero_division() -+ -+ def binary_op_nan(): -+ def compactlong_lhs(arg): -+ return ( -+ 42 + arg, -+ 42 - arg, -+ 42 * arg, -+ 42 / arg, -+ ) -+ def compactlong_rhs(arg): -+ return ( -+ arg + 42, -+ arg - 42, -+ arg * 2, -+ arg / 42, -+ ) -+ nan = float('nan') -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): -+ self.assertEqual(compactlong_lhs(1.0), (43.0, 41.0, 42.0, 42.0)) -+ for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN): -+ self.assertTrue(all(filter(lambda x: x is nan, compactlong_lhs(nan)))) -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): -+ self.assertEqual(compactlong_rhs(42.0), (84.0, 0.0, 84.0, 1.0)) -+ for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN): -+ self.assertTrue(all(filter(lambda x: x is nan, compactlong_rhs(nan)))) -+ -+ self.assert_no_opcode(compactlong_lhs, "BINARY_OP_EXTEND") -+ self.assert_no_opcode(compactlong_rhs, "BINARY_OP_EXTEND") -+ -+ binary_op_nan() -+ -+ def binary_op_bitwise_extend(): -+ for _ in range(100): -+ a, b = 2, 7 -+ x = a | b -+ self.assertEqual(x, 7) -+ y = a & b -+ self.assertEqual(y, 2) -+ z = a ^ b -+ self.assertEqual(z, 5) -+ a, b = 3, 9 -+ a |= b -+ self.assertEqual(a, 11) -+ a, b = 11, 9 -+ a &= b -+ self.assertEqual(a, 9) -+ a, b = 3, 9 -+ a ^= b -+ self.assertEqual(a, 10) -+ -+ binary_op_bitwise_extend() -+ self.assert_specialized(binary_op_bitwise_extend, "BINARY_OP_EXTEND") -+ self.assert_no_opcode(binary_op_bitwise_extend, "BINARY_OP") -+ - @cpython_only - @requires_specialization_ft - def test_load_super_attr(self): -@@ -1281,7 +1431,7 @@ - meth = super().__init__ - super().__init__() - -- for _ in range(100): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - A() - - self.assert_specialized(A.__init__, "LOAD_SUPER_ATTR_ATTR") -@@ -1301,7 +1451,7 @@ - globals()['super'] = fake_super - try: - # Should be unspecialized after enough calls. -- for _ in range(100): -+ for _ in range(_testinternalcapi.SPECIALIZATION_COOLDOWN): - A() - finally: - globals()['super'] = real_super -@@ -1314,7 +1464,7 @@ - @requires_specialization_ft - def test_contain_op(self): - def contains_op_dict(): -- for _ in range(100): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - a, b = 1, {1: 2, 2: 5} - self.assertTrue(a in b) - self.assertFalse(3 in b) -@@ -1324,7 +1474,7 @@ - self.assert_no_opcode(contains_op_dict, "CONTAINS_OP") - - def contains_op_set(): -- for _ in range(100): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - a, b = 1, {1, 2} - self.assertTrue(a in b) - self.assertFalse(3 in b) -@@ -1351,7 +1501,7 @@ - pass - - async def send_with(): -- for i in range(100): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - async with CM(): - x = 1 - -@@ -1369,25 +1519,94 @@ - def send_yield_from(): - yield from g() - -- for i in range(100): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - list(send_yield_from()) - - self.assert_specialized(send_yield_from, "SEND_GEN") - self.assert_no_opcode(send_yield_from, "SEND") - -+ @cpython_only -+ @requires_specialization_ft -+ def test_store_attr_slot(self): -+ class C: -+ __slots__ = ['x'] -+ -+ def set_slot(n): -+ c = C() -+ for i in range(n): -+ c.x = i -+ -+ set_slot(_testinternalcapi.SPECIALIZATION_THRESHOLD) -+ -+ self.assert_specialized(set_slot, "STORE_ATTR_SLOT") -+ self.assert_no_opcode(set_slot, "STORE_ATTR") -+ -+ # Adding a property for 'x' should unspecialize it. -+ C.x = property(lambda self: None, lambda self, x: None) -+ set_slot(_testinternalcapi.SPECIALIZATION_COOLDOWN) -+ self.assert_no_opcode(set_slot, "STORE_ATTR_SLOT") -+ -+ @cpython_only -+ @requires_specialization_ft -+ def test_store_attr_instance_value(self): -+ class C: -+ pass -+ -+ @reset_code -+ def set_value(n): -+ c = C() -+ for i in range(n): -+ c.x = i -+ -+ set_value(_testinternalcapi.SPECIALIZATION_THRESHOLD) -+ -+ self.assert_specialized(set_value, "STORE_ATTR_INSTANCE_VALUE") -+ self.assert_no_opcode(set_value, "STORE_ATTR") -+ -+ # Adding a property for 'x' should unspecialize it. -+ C.x = property(lambda self: None, lambda self, x: None) -+ set_value(_testinternalcapi.SPECIALIZATION_COOLDOWN) -+ self.assert_no_opcode(set_value, "STORE_ATTR_INSTANCE_VALUE") -+ -+ @cpython_only -+ @requires_specialization_ft -+ def test_store_attr_with_hint(self): -+ class C: -+ pass -+ -+ c = C() -+ for i in range(_testinternalcapi.SHARED_KEYS_MAX_SIZE - 1): -+ setattr(c, f"_{i}", None) -+ -+ @reset_code -+ def set_value(n): -+ for i in range(n): -+ c.x = i -+ -+ set_value(_testinternalcapi.SPECIALIZATION_THRESHOLD) -+ -+ self.assert_specialized(set_value, "STORE_ATTR_WITH_HINT") -+ self.assert_no_opcode(set_value, "STORE_ATTR") -+ -+ # Adding a property for 'x' should unspecialize it. -+ C.x = property(lambda self: None, lambda self, x: None) -+ set_value(_testinternalcapi.SPECIALIZATION_COOLDOWN) -+ self.assert_no_opcode(set_value, "STORE_ATTR_WITH_HINT") -+ - @cpython_only - @requires_specialization_ft - def test_to_bool(self): - def to_bool_bool(): - true_cnt, false_cnt = 0, 0 -- elems = [e % 2 == 0 for e in range(100)] -+ elems = [e % 2 == 0 for e in range(_testinternalcapi.SPECIALIZATION_THRESHOLD)] - for e in elems: - if e: - true_cnt += 1 - else: - false_cnt += 1 -- self.assertEqual(true_cnt, 50) -- self.assertEqual(false_cnt, 50) -+ d, m = divmod(_testinternalcapi.SPECIALIZATION_THRESHOLD, 2) -+ self.assertEqual(true_cnt, d + m) -+ self.assertEqual(false_cnt, d) - - to_bool_bool() - self.assert_specialized(to_bool_bool, "TO_BOOL_BOOL") -@@ -1395,12 +1614,12 @@ - - def to_bool_int(): - count = 0 -- for i in range(100): -+ for i in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - if i: - count += 1 - else: - count -= 1 -- self.assertEqual(count, 98) -+ self.assertEqual(count, _testinternalcapi.SPECIALIZATION_THRESHOLD - 2) - - to_bool_int() - self.assert_specialized(to_bool_int, "TO_BOOL_INT") -@@ -1408,11 +1627,11 @@ - - def to_bool_list(): - count = 0 -- elems = [1, 2, 3] -+ elems = list(range(_testinternalcapi.SPECIALIZATION_THRESHOLD)) - while elems: - count += elems.pop() - self.assertEqual(elems, []) -- self.assertEqual(count, 6) -+ self.assertEqual(count, sum(range(_testinternalcapi.SPECIALIZATION_THRESHOLD))) - - to_bool_list() - self.assert_specialized(to_bool_list, "TO_BOOL_LIST") -@@ -1420,11 +1639,11 @@ - - def to_bool_none(): - count = 0 -- elems = [None, None, None, None] -+ elems = [None] * _testinternalcapi.SPECIALIZATION_THRESHOLD - for e in elems: - if not e: - count += 1 -- self.assertEqual(count, len(elems)) -+ self.assertEqual(count, _testinternalcapi.SPECIALIZATION_THRESHOLD) - - to_bool_none() - self.assert_specialized(to_bool_none, "TO_BOOL_NONE") -@@ -1432,11 +1651,11 @@ - - def to_bool_str(): - count = 0 -- elems = ["", "foo", ""] -+ elems = [""] + ["foo"] * (_testinternalcapi.SPECIALIZATION_THRESHOLD - 1) - for e in elems: - if e: - count += 1 -- self.assertEqual(count, 1) -+ self.assertEqual(count, _testinternalcapi.SPECIALIZATION_THRESHOLD - 1) - - to_bool_str() - self.assert_specialized(to_bool_str, "TO_BOOL_STR") -@@ -1446,7 +1665,7 @@ - @requires_specialization_ft - def test_unpack_sequence(self): - def unpack_sequence_two_tuple(): -- for _ in range(100): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - a, b = 1, 2 - self.assertEqual(a, 1) - self.assertEqual(b, 2) -@@ -1457,7 +1676,7 @@ - self.assert_no_opcode(unpack_sequence_two_tuple, "UNPACK_SEQUENCE") - - def unpack_sequence_tuple(): -- for _ in range(100): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - a, = 1, - self.assertEqual(a, 1) - -@@ -1466,7 +1685,7 @@ - self.assert_no_opcode(unpack_sequence_tuple, "UNPACK_SEQUENCE") - - def unpack_sequence_list(): -- for _ in range(100): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - a, b = [1, 2] - self.assertEqual(a, 1) - self.assertEqual(b, 2) -@@ -1479,47 +1698,109 @@ - @requires_specialization_ft - def test_binary_subscr(self): - def binary_subscr_list_int(): -- for _ in range(100): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - a = [1, 2, 3] - for idx, expected in enumerate(a): - self.assertEqual(a[idx], expected) - - binary_subscr_list_int() - self.assert_specialized(binary_subscr_list_int, -- "BINARY_SUBSCR_LIST_INT") -+ "BINARY_OP_SUBSCR_LIST_INT") - self.assert_no_opcode(binary_subscr_list_int, "BINARY_SUBSCR") - - def binary_subscr_tuple_int(): -- for _ in range(100): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - a = (1, 2, 3) - for idx, expected in enumerate(a): - self.assertEqual(a[idx], expected) - - binary_subscr_tuple_int() - self.assert_specialized(binary_subscr_tuple_int, -- "BINARY_SUBSCR_TUPLE_INT") -+ "BINARY_OP_SUBSCR_TUPLE_INT") - self.assert_no_opcode(binary_subscr_tuple_int, "BINARY_SUBSCR") - - def binary_subscr_dict(): -- for _ in range(100): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - a = {1: 2, 2: 3} - self.assertEqual(a[1], 2) - self.assertEqual(a[2], 3) - - binary_subscr_dict() -- self.assert_specialized(binary_subscr_dict, "BINARY_SUBSCR_DICT") -- self.assert_no_opcode(binary_subscr_dict, "BINARY_SUBSCR") -+ self.assert_specialized(binary_subscr_dict, "BINARY_OP_SUBSCR_DICT") -+ self.assert_no_opcode(binary_subscr_dict, "BINARY_OP") - - def binary_subscr_str_int(): -- for _ in range(100): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - a = "foobar" - for idx, expected in enumerate(a): - self.assertEqual(a[idx], expected) - - binary_subscr_str_int() -- self.assert_specialized(binary_subscr_str_int, "BINARY_SUBSCR_STR_INT") -+ self.assert_specialized(binary_subscr_str_int, "BINARY_OP_SUBSCR_STR_INT") - self.assert_no_opcode(binary_subscr_str_int, "BINARY_SUBSCR") - -+ def binary_subscr_getitems(): -+ class C: -+ def __init__(self, val): -+ self.val = val -+ def __getitem__(self, item): -+ return self.val -+ -+ items = [C(i) for i in range(_testinternalcapi.SPECIALIZATION_THRESHOLD)] -+ for i in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): -+ self.assertEqual(items[i][i], i) -+ -+ binary_subscr_getitems() -+ self.assert_specialized(binary_subscr_getitems, "BINARY_OP_SUBSCR_GETITEM") -+ self.assert_no_opcode(binary_subscr_getitems, "BINARY_SUBSCR") -+ -+ @cpython_only -+ @requires_specialization_ft -+ def test_compare_op(self): -+ def compare_op_int(): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): -+ a, b = 1, 2 -+ c = a == b -+ self.assertFalse(c) -+ -+ compare_op_int() -+ self.assert_specialized(compare_op_int, "COMPARE_OP_INT") -+ self.assert_no_opcode(compare_op_int, "COMPARE_OP") -+ -+ def compare_op_float(): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): -+ a, b = 1.0, 2.0 -+ c = a == b -+ self.assertFalse(c) -+ -+ compare_op_float() -+ self.assert_specialized(compare_op_float, "COMPARE_OP_FLOAT") -+ self.assert_no_opcode(compare_op_float, "COMPARE_OP") -+ -+ def compare_op_str(): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): -+ a, b = "spam", "ham" -+ c = a == b -+ self.assertFalse(c) -+ -+ compare_op_str() -+ self.assert_specialized(compare_op_str, "COMPARE_OP_STR") -+ self.assert_no_opcode(compare_op_str, "COMPARE_OP") -+ -+ @cpython_only -+ @requires_specialization_ft -+ def test_load_const(self): -+ def load_const(): -+ def unused(): pass -+ # Currently, the empty tuple is immortal, and the otherwise -+ # unused nested function's code object is mortal. This test will -+ # have to use different values if either of that changes. -+ return () -+ -+ load_const() -+ self.assert_specialized(load_const, "LOAD_CONST_IMMORTAL") -+ self.assert_specialized(load_const, "LOAD_CONST_MORTAL") -+ self.assert_no_opcode(load_const, "LOAD_CONST") - - if __name__ == "__main__": - unittest.main() -diff --git a/Lib/test/test_operator.py b/Lib/test/test_operator.py -index 82578a0ef1e..1757824580e 100644 ---- a/Lib/test/test_operator.py -+++ b/Lib/test/test_operator.py -@@ -666,6 +666,7 @@ - module = c_operator - - -+@support.thread_unsafe("swaps global operator module") - class OperatorPickleTestCase: - def copy(self, obj, proto): - with support.swap_item(sys.modules, 'operator', self.module): -diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py -index b0e686cb754..6e40cb4f58b 100644 ---- a/Lib/test/test_os.py -+++ b/Lib/test/test_os.py -@@ -105,7 +105,7 @@ - - - def tearDownModule(): -- asyncio.set_event_loop_policy(None) -+ asyncio._set_event_loop_policy(None) - - - class MiscTests(unittest.TestCase): -@@ -230,6 +230,94 @@ - self.assertEqual(type(s), bytes) - self.assertEqual(s, b"spam") - -+ def test_readinto(self): -+ with open(os_helper.TESTFN, "w+b") as fobj: -+ fobj.write(b"spam") -+ fobj.flush() -+ fd = fobj.fileno() -+ os.lseek(fd, 0, 0) -+ # Oversized so readinto without hitting end. -+ buffer = bytearray(7) -+ s = os.readinto(fd, buffer) -+ self.assertEqual(type(s), int) -+ self.assertEqual(s, 4) -+ # Should overwrite the first 4 bytes of the buffer. -+ self.assertEqual(buffer[:4], b"spam") -+ -+ # Readinto at EOF should return 0 and not touch buffer. -+ buffer[:] = b"notspam" -+ s = os.readinto(fd, buffer) -+ self.assertEqual(type(s), int) -+ self.assertEqual(s, 0) -+ self.assertEqual(bytes(buffer), b"notspam") -+ s = os.readinto(fd, buffer) -+ self.assertEqual(s, 0) -+ self.assertEqual(bytes(buffer), b"notspam") -+ -+ # Readinto a 0 length bytearray when at EOF should return 0 -+ self.assertEqual(os.readinto(fd, bytearray()), 0) -+ -+ # Readinto a 0 length bytearray with data available should return 0. -+ os.lseek(fd, 0, 0) -+ self.assertEqual(os.readinto(fd, bytearray()), 0) -+ -+ @unittest.skipUnless(hasattr(os, 'get_blocking'), -+ 'needs os.get_blocking() and os.set_blocking()') -+ @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") -+ @unittest.skipIf(support.is_emscripten, "set_blocking does not work correctly") -+ def test_readinto_non_blocking(self): -+ # Verify behavior of a readinto which would block on a non-blocking fd. -+ r, w = os.pipe() -+ try: -+ os.set_blocking(r, False) -+ with self.assertRaises(BlockingIOError): -+ os.readinto(r, bytearray(5)) -+ -+ # Pass some data through -+ os.write(w, b"spam") -+ self.assertEqual(os.readinto(r, bytearray(4)), 4) -+ -+ # Still don't block or return 0. -+ with self.assertRaises(BlockingIOError): -+ os.readinto(r, bytearray(5)) -+ -+ # At EOF should return size 0 -+ os.close(w) -+ w = None -+ self.assertEqual(os.readinto(r, bytearray(5)), 0) -+ self.assertEqual(os.readinto(r, bytearray(5)), 0) # Still EOF -+ -+ finally: -+ os.close(r) -+ if w is not None: -+ os.close(w) -+ -+ def test_readinto_badarg(self): -+ with open(os_helper.TESTFN, "w+b") as fobj: -+ fobj.write(b"spam") -+ fobj.flush() -+ fd = fobj.fileno() -+ os.lseek(fd, 0, 0) -+ -+ for bad_arg in ("test", bytes(), 14): -+ with self.subTest(f"bad buffer {type(bad_arg)}"): -+ with self.assertRaises(TypeError): -+ os.readinto(fd, bad_arg) -+ -+ with self.subTest("doesn't work on file objects"): -+ with self.assertRaises(TypeError): -+ os.readinto(fobj, bytearray(5)) -+ -+ # takes two args -+ with self.assertRaises(TypeError): -+ os.readinto(fd) -+ -+ # No data should have been read with the bad arguments. -+ buffer = bytearray(4) -+ s = os.readinto(fd, buffer) -+ self.assertEqual(s, 4) -+ self.assertEqual(buffer, b"spam") -+ - @support.cpython_only - # Skip the test on 32-bit platforms: the number of bytes must fit in a - # Py_ssize_t type -@@ -249,6 +337,29 @@ - # operating system is free to return less bytes than requested. - self.assertEqual(data, b'test') - -+ -+ @support.cpython_only -+ # Skip the test on 32-bit platforms: the number of bytes must fit in a -+ # Py_ssize_t type -+ @unittest.skipUnless(INT_MAX < PY_SSIZE_T_MAX, -+ "needs INT_MAX < PY_SSIZE_T_MAX") -+ @support.bigmemtest(size=INT_MAX + 10, memuse=1, dry_run=False) -+ def test_large_readinto(self, size): -+ self.addCleanup(os_helper.unlink, os_helper.TESTFN) -+ create_file(os_helper.TESTFN, b'test') -+ -+ # Issue #21932: For readinto the buffer contains the length rather than -+ # a length being passed explicitly to read, should still get capped to a -+ # valid size / not raise an OverflowError for sizes larger than INT_MAX. -+ buffer = bytearray(INT_MAX + 10) -+ with open(os_helper.TESTFN, "rb") as fp: -+ length = os.readinto(fp.fileno(), buffer) -+ -+ # The test does not try to read more than 2 GiB at once because the -+ # operating system is free to return less bytes than requested. -+ self.assertEqual(length, 4) -+ self.assertEqual(buffer[:4], b'test') -+ - def test_write(self): - # os.write() accepts bytes- and buffer-like objects but not strings - fd = os.open(os_helper.TESTFN, os.O_CREAT | os.O_WRONLY) -@@ -2467,6 +2578,10 @@ - def test_read(self): - self.check(os.read, 1) - -+ @unittest.skipUnless(hasattr(os, 'readinto'), 'test needs os.readinto()') -+ def test_readinto(self): -+ self.check(os.readinto, bytearray(5)) -+ - @unittest.skipUnless(hasattr(os, 'readv'), 'test needs os.readv()') - def test_readv(self): - buf = bytearray(10) -diff --git a/Lib/test/test_pathlib/test_pathlib.py b/Lib/test/test_pathlib/test_pathlib.py -index ac3a3b4f15c..31e5306ae60 100644 ---- a/Lib/test/test_pathlib/test_pathlib.py -+++ b/Lib/test/test_pathlib/test_pathlib.py -@@ -75,7 +75,7 @@ - # Tests for the pure classes. - # - --class PurePathTest(test_pathlib_abc.DummyPurePathTest): -+class PurePathTest(test_pathlib_abc.DummyJoinablePathTest): - cls = pathlib.PurePath - - # Make sure any symbolic links in the base test path are resolved. -@@ -229,6 +229,31 @@ - self._check_str(p.__fspath__(), ('a/b',)) - self._check_str(os.fspath(p), ('a/b',)) - -+ def test_bytes(self): -+ P = self.cls -+ with self.assertRaises(TypeError): -+ P(b'a') -+ with self.assertRaises(TypeError): -+ P(b'a', 'b') -+ with self.assertRaises(TypeError): -+ P('a', b'b') -+ with self.assertRaises(TypeError): -+ P('a').joinpath(b'b') -+ with self.assertRaises(TypeError): -+ P('a') / b'b' -+ with self.assertRaises(TypeError): -+ b'a' / P('b') -+ with self.assertRaises(TypeError): -+ P('a').match(b'b') -+ with self.assertRaises(TypeError): -+ P('a').relative_to(b'b') -+ with self.assertRaises(TypeError): -+ P('a').with_name(b'b') -+ with self.assertRaises(TypeError): -+ P('a').with_stem(b'b') -+ with self.assertRaises(TypeError): -+ P('a').with_suffix(b'b') -+ - def test_bytes_exc_message(self): - P = self.cls - message = (r"argument should be a str or an os\.PathLike object " -@@ -245,6 +270,12 @@ - P = self.cls - self.assertEqual(bytes(P('a/b')), b'a' + sep + b'b') - -+ def test_as_posix_common(self): -+ P = self.cls -+ for pathstr in ('a', 'a/b', 'a/b/c', '/', '/a/b', '/a/b/c'): -+ self.assertEqual(P(pathstr).as_posix(), pathstr) -+ # Other tests for as_posix() are in test_equivalences(). -+ - def test_eq_common(self): - P = self.cls - self.assertEqual(P('a/b'), P('a/b')) -@@ -324,6 +355,51 @@ - self.assertEqual(q, p) - self.assertEqual(repr(q), r) - -+ def test_drive_common(self): -+ P = self.cls -+ self.assertEqual(P('a/b').drive, '') -+ self.assertEqual(P('/a/b').drive, '') -+ self.assertEqual(P('').drive, '') -+ -+ @needs_windows -+ def test_drive_windows(self): -+ P = self.cls -+ self.assertEqual(P('c:').drive, 'c:') -+ self.assertEqual(P('c:a/b').drive, 'c:') -+ self.assertEqual(P('c:/').drive, 'c:') -+ self.assertEqual(P('c:/a/b/').drive, 'c:') -+ self.assertEqual(P('//a/b').drive, '\\\\a\\b') -+ self.assertEqual(P('//a/b/').drive, '\\\\a\\b') -+ self.assertEqual(P('//a/b/c/d').drive, '\\\\a\\b') -+ self.assertEqual(P('./c:a').drive, '') -+ -+ -+ def test_root_common(self): -+ P = self.cls -+ sep = self.sep -+ self.assertEqual(P('').root, '') -+ self.assertEqual(P('a/b').root, '') -+ self.assertEqual(P('/').root, sep) -+ self.assertEqual(P('/a/b').root, sep) -+ -+ @needs_posix -+ def test_root_posix(self): -+ P = self.cls -+ self.assertEqual(P('/a/b').root, '/') -+ # POSIX special case for two leading slashes. -+ self.assertEqual(P('//a/b').root, '//') -+ -+ @needs_windows -+ def test_root_windows(self): -+ P = self.cls -+ self.assertEqual(P('c:').root, '') -+ self.assertEqual(P('c:a/b').root, '') -+ self.assertEqual(P('c:/').root, '\\') -+ self.assertEqual(P('c:/a/b/').root, '\\') -+ self.assertEqual(P('//a/b').root, '\\') -+ self.assertEqual(P('//a/b/').root, '\\') -+ self.assertEqual(P('//a/b/c/d').root, '\\') -+ - def test_name_empty(self): - P = self.cls - self.assertEqual(P('').name, '') -@@ -362,6 +438,84 @@ - self.assertRaises(ValueError, P('a').match, '') - self.assertRaises(ValueError, P('a').match, '.') - -+ def test_match_common(self): -+ P = self.cls -+ # Simple relative pattern. -+ self.assertTrue(P('b.py').match('b.py')) -+ self.assertTrue(P('a/b.py').match('b.py')) -+ self.assertTrue(P('/a/b.py').match('b.py')) -+ self.assertFalse(P('a.py').match('b.py')) -+ self.assertFalse(P('b/py').match('b.py')) -+ self.assertFalse(P('/a.py').match('b.py')) -+ self.assertFalse(P('b.py/c').match('b.py')) -+ # Wildcard relative pattern. -+ self.assertTrue(P('b.py').match('*.py')) -+ self.assertTrue(P('a/b.py').match('*.py')) -+ self.assertTrue(P('/a/b.py').match('*.py')) -+ self.assertFalse(P('b.pyc').match('*.py')) -+ self.assertFalse(P('b./py').match('*.py')) -+ self.assertFalse(P('b.py/c').match('*.py')) -+ # Multi-part relative pattern. -+ self.assertTrue(P('ab/c.py').match('a*/*.py')) -+ self.assertTrue(P('/d/ab/c.py').match('a*/*.py')) -+ self.assertFalse(P('a.py').match('a*/*.py')) -+ self.assertFalse(P('/dab/c.py').match('a*/*.py')) -+ self.assertFalse(P('ab/c.py/d').match('a*/*.py')) -+ # Absolute pattern. -+ self.assertTrue(P('/b.py').match('/*.py')) -+ self.assertFalse(P('b.py').match('/*.py')) -+ self.assertFalse(P('a/b.py').match('/*.py')) -+ self.assertFalse(P('/a/b.py').match('/*.py')) -+ # Multi-part absolute pattern. -+ self.assertTrue(P('/a/b.py').match('/a/*.py')) -+ self.assertFalse(P('/ab.py').match('/a/*.py')) -+ self.assertFalse(P('/a/b/c.py').match('/a/*.py')) -+ # Multi-part glob-style pattern. -+ self.assertFalse(P('/a/b/c.py').match('/**/*.py')) -+ self.assertTrue(P('/a/b/c.py').match('/a/**/*.py')) -+ # Case-sensitive flag -+ self.assertFalse(P('A.py').match('a.PY', case_sensitive=True)) -+ self.assertTrue(P('A.py').match('a.PY', case_sensitive=False)) -+ self.assertFalse(P('c:/a/B.Py').match('C:/A/*.pY', case_sensitive=True)) -+ self.assertTrue(P('/a/b/c.py').match('/A/*/*.Py', case_sensitive=False)) -+ # Matching against empty path -+ self.assertFalse(P('').match('*')) -+ self.assertFalse(P('').match('**')) -+ self.assertFalse(P('').match('**/*')) -+ -+ @needs_posix -+ def test_match_posix(self): -+ P = self.cls -+ self.assertFalse(P('A.py').match('a.PY')) -+ -+ @needs_windows -+ def test_match_windows(self): -+ P = self.cls -+ # Absolute patterns. -+ self.assertTrue(P('c:/b.py').match('*:/*.py')) -+ self.assertTrue(P('c:/b.py').match('c:/*.py')) -+ self.assertFalse(P('d:/b.py').match('c:/*.py')) # wrong drive -+ self.assertFalse(P('b.py').match('/*.py')) -+ self.assertFalse(P('b.py').match('c:*.py')) -+ self.assertFalse(P('b.py').match('c:/*.py')) -+ self.assertFalse(P('c:b.py').match('/*.py')) -+ self.assertFalse(P('c:b.py').match('c:/*.py')) -+ self.assertFalse(P('/b.py').match('c:*.py')) -+ self.assertFalse(P('/b.py').match('c:/*.py')) -+ # UNC patterns. -+ self.assertTrue(P('//some/share/a.py').match('//*/*/*.py')) -+ self.assertTrue(P('//some/share/a.py').match('//some/share/*.py')) -+ self.assertFalse(P('//other/share/a.py').match('//some/share/*.py')) -+ self.assertFalse(P('//some/share/a/b.py').match('//some/share/*.py')) -+ # Case-insensitivity. -+ self.assertTrue(P('B.py').match('b.PY')) -+ self.assertTrue(P('c:/a/B.Py').match('C:/A/*.pY')) -+ self.assertTrue(P('//Some/Share/B.Py').match('//somE/sharE/*.pY')) -+ # Path anchor doesn't match pattern anchor -+ self.assertFalse(P('c:/b.py').match('/*.py')) # 'c:/' vs '/' -+ self.assertFalse(P('c:/b.py').match('c:*.py')) # 'c:/' vs 'c:' -+ self.assertFalse(P('//some/share/a.py').match('/*.py')) # '//some/share/' vs '/' -+ - @needs_posix - def test_parse_path_posix(self): - check = self._check_parse_path -@@ -522,6 +676,311 @@ - self.assertFalse(p < q) - self.assertFalse(p > q) - -+ @needs_posix -+ def test_is_absolute_posix(self): -+ P = self.cls -+ self.assertFalse(P('').is_absolute()) -+ self.assertFalse(P('a').is_absolute()) -+ self.assertFalse(P('a/b/').is_absolute()) -+ self.assertTrue(P('/').is_absolute()) -+ self.assertTrue(P('/a').is_absolute()) -+ self.assertTrue(P('/a/b/').is_absolute()) -+ self.assertTrue(P('//a').is_absolute()) -+ self.assertTrue(P('//a/b').is_absolute()) -+ -+ @needs_windows -+ def test_is_absolute_windows(self): -+ P = self.cls -+ # Under NT, only paths with both a drive and a root are absolute. -+ self.assertFalse(P().is_absolute()) -+ self.assertFalse(P('a').is_absolute()) -+ self.assertFalse(P('a/b/').is_absolute()) -+ self.assertFalse(P('/').is_absolute()) -+ self.assertFalse(P('/a').is_absolute()) -+ self.assertFalse(P('/a/b/').is_absolute()) -+ self.assertFalse(P('c:').is_absolute()) -+ self.assertFalse(P('c:a').is_absolute()) -+ self.assertFalse(P('c:a/b/').is_absolute()) -+ self.assertTrue(P('c:/').is_absolute()) -+ self.assertTrue(P('c:/a').is_absolute()) -+ self.assertTrue(P('c:/a/b/').is_absolute()) -+ # UNC paths are absolute by definition. -+ self.assertTrue(P('//').is_absolute()) -+ self.assertTrue(P('//a').is_absolute()) -+ self.assertTrue(P('//a/b').is_absolute()) -+ self.assertTrue(P('//a/b/').is_absolute()) -+ self.assertTrue(P('//a/b/c').is_absolute()) -+ self.assertTrue(P('//a/b/c/d').is_absolute()) -+ self.assertTrue(P('//?/UNC/').is_absolute()) -+ self.assertTrue(P('//?/UNC/spam').is_absolute()) -+ -+ def test_relative_to_common(self): -+ P = self.cls -+ p = P('a/b') -+ self.assertRaises(TypeError, p.relative_to) -+ self.assertRaises(TypeError, p.relative_to, b'a') -+ self.assertEqual(p.relative_to(P('')), P('a/b')) -+ self.assertEqual(p.relative_to(''), P('a/b')) -+ self.assertEqual(p.relative_to(P('a')), P('b')) -+ self.assertEqual(p.relative_to('a'), P('b')) -+ self.assertEqual(p.relative_to('a/'), P('b')) -+ self.assertEqual(p.relative_to(P('a/b')), P('')) -+ self.assertEqual(p.relative_to('a/b'), P('')) -+ self.assertEqual(p.relative_to(P(''), walk_up=True), P('a/b')) -+ self.assertEqual(p.relative_to('', walk_up=True), P('a/b')) -+ self.assertEqual(p.relative_to(P('a'), walk_up=True), P('b')) -+ self.assertEqual(p.relative_to('a', walk_up=True), P('b')) -+ self.assertEqual(p.relative_to('a/', walk_up=True), P('b')) -+ self.assertEqual(p.relative_to(P('a/b'), walk_up=True), P('')) -+ self.assertEqual(p.relative_to('a/b', walk_up=True), P('')) -+ self.assertEqual(p.relative_to(P('a/c'), walk_up=True), P('../b')) -+ self.assertEqual(p.relative_to('a/c', walk_up=True), P('../b')) -+ self.assertEqual(p.relative_to(P('a/b/c'), walk_up=True), P('..')) -+ self.assertEqual(p.relative_to('a/b/c', walk_up=True), P('..')) -+ self.assertEqual(p.relative_to(P('c'), walk_up=True), P('../a/b')) -+ self.assertEqual(p.relative_to('c', walk_up=True), P('../a/b')) -+ # Unrelated paths. -+ self.assertRaises(ValueError, p.relative_to, P('c')) -+ self.assertRaises(ValueError, p.relative_to, P('a/b/c')) -+ self.assertRaises(ValueError, p.relative_to, P('a/c')) -+ self.assertRaises(ValueError, p.relative_to, P('/a')) -+ self.assertRaises(ValueError, p.relative_to, P("../a")) -+ self.assertRaises(ValueError, p.relative_to, P("a/..")) -+ self.assertRaises(ValueError, p.relative_to, P("/a/..")) -+ self.assertRaises(ValueError, p.relative_to, P('/'), walk_up=True) -+ self.assertRaises(ValueError, p.relative_to, P('/a'), walk_up=True) -+ self.assertRaises(ValueError, p.relative_to, P("../a"), walk_up=True) -+ self.assertRaises(ValueError, p.relative_to, P("a/.."), walk_up=True) -+ self.assertRaises(ValueError, p.relative_to, P("/a/.."), walk_up=True) -+ p = P('/a/b') -+ self.assertEqual(p.relative_to(P('/')), P('a/b')) -+ self.assertEqual(p.relative_to('/'), P('a/b')) -+ self.assertEqual(p.relative_to(P('/a')), P('b')) -+ self.assertEqual(p.relative_to('/a'), P('b')) -+ self.assertEqual(p.relative_to('/a/'), P('b')) -+ self.assertEqual(p.relative_to(P('/a/b')), P('')) -+ self.assertEqual(p.relative_to('/a/b'), P('')) -+ self.assertEqual(p.relative_to(P('/'), walk_up=True), P('a/b')) -+ self.assertEqual(p.relative_to('/', walk_up=True), P('a/b')) -+ self.assertEqual(p.relative_to(P('/a'), walk_up=True), P('b')) -+ self.assertEqual(p.relative_to('/a', walk_up=True), P('b')) -+ self.assertEqual(p.relative_to('/a/', walk_up=True), P('b')) -+ self.assertEqual(p.relative_to(P('/a/b'), walk_up=True), P('')) -+ self.assertEqual(p.relative_to('/a/b', walk_up=True), P('')) -+ self.assertEqual(p.relative_to(P('/a/c'), walk_up=True), P('../b')) -+ self.assertEqual(p.relative_to('/a/c', walk_up=True), P('../b')) -+ self.assertEqual(p.relative_to(P('/a/b/c'), walk_up=True), P('..')) -+ self.assertEqual(p.relative_to('/a/b/c', walk_up=True), P('..')) -+ self.assertEqual(p.relative_to(P('/c'), walk_up=True), P('../a/b')) -+ self.assertEqual(p.relative_to('/c', walk_up=True), P('../a/b')) -+ # Unrelated paths. -+ self.assertRaises(ValueError, p.relative_to, P('/c')) -+ self.assertRaises(ValueError, p.relative_to, P('/a/b/c')) -+ self.assertRaises(ValueError, p.relative_to, P('/a/c')) -+ self.assertRaises(ValueError, p.relative_to, P('')) -+ self.assertRaises(ValueError, p.relative_to, '') -+ self.assertRaises(ValueError, p.relative_to, P('a')) -+ self.assertRaises(ValueError, p.relative_to, P("../a")) -+ self.assertRaises(ValueError, p.relative_to, P("a/..")) -+ self.assertRaises(ValueError, p.relative_to, P("/a/..")) -+ self.assertRaises(ValueError, p.relative_to, P(''), walk_up=True) -+ self.assertRaises(ValueError, p.relative_to, P('a'), walk_up=True) -+ self.assertRaises(ValueError, p.relative_to, P("../a"), walk_up=True) -+ self.assertRaises(ValueError, p.relative_to, P("a/.."), walk_up=True) -+ self.assertRaises(ValueError, p.relative_to, P("/a/.."), walk_up=True) -+ -+ @needs_windows -+ def test_relative_to_windows(self): -+ P = self.cls -+ p = P('C:Foo/Bar') -+ self.assertEqual(p.relative_to(P('c:')), P('Foo/Bar')) -+ self.assertEqual(p.relative_to('c:'), P('Foo/Bar')) -+ self.assertEqual(p.relative_to(P('c:foO')), P('Bar')) -+ self.assertEqual(p.relative_to('c:foO'), P('Bar')) -+ self.assertEqual(p.relative_to('c:foO/'), P('Bar')) -+ self.assertEqual(p.relative_to(P('c:foO/baR')), P()) -+ self.assertEqual(p.relative_to('c:foO/baR'), P()) -+ self.assertEqual(p.relative_to(P('c:'), walk_up=True), P('Foo/Bar')) -+ self.assertEqual(p.relative_to('c:', walk_up=True), P('Foo/Bar')) -+ self.assertEqual(p.relative_to(P('c:foO'), walk_up=True), P('Bar')) -+ self.assertEqual(p.relative_to('c:foO', walk_up=True), P('Bar')) -+ self.assertEqual(p.relative_to('c:foO/', walk_up=True), P('Bar')) -+ self.assertEqual(p.relative_to(P('c:foO/baR'), walk_up=True), P()) -+ self.assertEqual(p.relative_to('c:foO/baR', walk_up=True), P()) -+ self.assertEqual(p.relative_to(P('C:Foo/Bar/Baz'), walk_up=True), P('..')) -+ self.assertEqual(p.relative_to(P('C:Foo/Baz'), walk_up=True), P('../Bar')) -+ self.assertEqual(p.relative_to(P('C:Baz/Bar'), walk_up=True), P('../../Foo/Bar')) -+ # Unrelated paths. -+ self.assertRaises(ValueError, p.relative_to, P()) -+ self.assertRaises(ValueError, p.relative_to, '') -+ self.assertRaises(ValueError, p.relative_to, P('d:')) -+ self.assertRaises(ValueError, p.relative_to, P('/')) -+ self.assertRaises(ValueError, p.relative_to, P('Foo')) -+ self.assertRaises(ValueError, p.relative_to, P('/Foo')) -+ self.assertRaises(ValueError, p.relative_to, P('C:/Foo')) -+ self.assertRaises(ValueError, p.relative_to, P('C:Foo/Bar/Baz')) -+ self.assertRaises(ValueError, p.relative_to, P('C:Foo/Baz')) -+ self.assertRaises(ValueError, p.relative_to, P(), walk_up=True) -+ self.assertRaises(ValueError, p.relative_to, '', walk_up=True) -+ self.assertRaises(ValueError, p.relative_to, P('d:'), walk_up=True) -+ self.assertRaises(ValueError, p.relative_to, P('/'), walk_up=True) -+ self.assertRaises(ValueError, p.relative_to, P('Foo'), walk_up=True) -+ self.assertRaises(ValueError, p.relative_to, P('/Foo'), walk_up=True) -+ self.assertRaises(ValueError, p.relative_to, P('C:/Foo'), walk_up=True) -+ p = P('C:/Foo/Bar') -+ self.assertEqual(p.relative_to(P('c:/')), P('Foo/Bar')) -+ self.assertEqual(p.relative_to('c:/'), P('Foo/Bar')) -+ self.assertEqual(p.relative_to(P('c:/foO')), P('Bar')) -+ self.assertEqual(p.relative_to('c:/foO'), P('Bar')) -+ self.assertEqual(p.relative_to('c:/foO/'), P('Bar')) -+ self.assertEqual(p.relative_to(P('c:/foO/baR')), P()) -+ self.assertEqual(p.relative_to('c:/foO/baR'), P()) -+ self.assertEqual(p.relative_to(P('c:/'), walk_up=True), P('Foo/Bar')) -+ self.assertEqual(p.relative_to('c:/', walk_up=True), P('Foo/Bar')) -+ self.assertEqual(p.relative_to(P('c:/foO'), walk_up=True), P('Bar')) -+ self.assertEqual(p.relative_to('c:/foO', walk_up=True), P('Bar')) -+ self.assertEqual(p.relative_to('c:/foO/', walk_up=True), P('Bar')) -+ self.assertEqual(p.relative_to(P('c:/foO/baR'), walk_up=True), P()) -+ self.assertEqual(p.relative_to('c:/foO/baR', walk_up=True), P()) -+ self.assertEqual(p.relative_to('C:/Baz', walk_up=True), P('../Foo/Bar')) -+ self.assertEqual(p.relative_to('C:/Foo/Bar/Baz', walk_up=True), P('..')) -+ self.assertEqual(p.relative_to('C:/Foo/Baz', walk_up=True), P('../Bar')) -+ # Unrelated paths. -+ self.assertRaises(ValueError, p.relative_to, 'c:') -+ self.assertRaises(ValueError, p.relative_to, P('c:')) -+ self.assertRaises(ValueError, p.relative_to, P('C:/Baz')) -+ self.assertRaises(ValueError, p.relative_to, P('C:/Foo/Bar/Baz')) -+ self.assertRaises(ValueError, p.relative_to, P('C:/Foo/Baz')) -+ self.assertRaises(ValueError, p.relative_to, P('C:Foo')) -+ self.assertRaises(ValueError, p.relative_to, P('d:')) -+ self.assertRaises(ValueError, p.relative_to, P('d:/')) -+ self.assertRaises(ValueError, p.relative_to, P('/')) -+ self.assertRaises(ValueError, p.relative_to, P('/Foo')) -+ self.assertRaises(ValueError, p.relative_to, P('//C/Foo')) -+ self.assertRaises(ValueError, p.relative_to, 'c:', walk_up=True) -+ self.assertRaises(ValueError, p.relative_to, P('c:'), walk_up=True) -+ self.assertRaises(ValueError, p.relative_to, P('C:Foo'), walk_up=True) -+ self.assertRaises(ValueError, p.relative_to, P('d:'), walk_up=True) -+ self.assertRaises(ValueError, p.relative_to, P('d:/'), walk_up=True) -+ self.assertRaises(ValueError, p.relative_to, P('/'), walk_up=True) -+ self.assertRaises(ValueError, p.relative_to, P('/Foo'), walk_up=True) -+ self.assertRaises(ValueError, p.relative_to, P('//C/Foo'), walk_up=True) -+ # UNC paths. -+ p = P('//Server/Share/Foo/Bar') -+ self.assertEqual(p.relative_to(P('//sErver/sHare')), P('Foo/Bar')) -+ self.assertEqual(p.relative_to('//sErver/sHare'), P('Foo/Bar')) -+ self.assertEqual(p.relative_to('//sErver/sHare/'), P('Foo/Bar')) -+ self.assertEqual(p.relative_to(P('//sErver/sHare/Foo')), P('Bar')) -+ self.assertEqual(p.relative_to('//sErver/sHare/Foo'), P('Bar')) -+ self.assertEqual(p.relative_to('//sErver/sHare/Foo/'), P('Bar')) -+ self.assertEqual(p.relative_to(P('//sErver/sHare/Foo/Bar')), P()) -+ self.assertEqual(p.relative_to('//sErver/sHare/Foo/Bar'), P()) -+ self.assertEqual(p.relative_to(P('//sErver/sHare'), walk_up=True), P('Foo/Bar')) -+ self.assertEqual(p.relative_to('//sErver/sHare', walk_up=True), P('Foo/Bar')) -+ self.assertEqual(p.relative_to('//sErver/sHare/', walk_up=True), P('Foo/Bar')) -+ self.assertEqual(p.relative_to(P('//sErver/sHare/Foo'), walk_up=True), P('Bar')) -+ self.assertEqual(p.relative_to('//sErver/sHare/Foo', walk_up=True), P('Bar')) -+ self.assertEqual(p.relative_to('//sErver/sHare/Foo/', walk_up=True), P('Bar')) -+ self.assertEqual(p.relative_to(P('//sErver/sHare/Foo/Bar'), walk_up=True), P()) -+ self.assertEqual(p.relative_to('//sErver/sHare/Foo/Bar', walk_up=True), P()) -+ self.assertEqual(p.relative_to(P('//sErver/sHare/bar'), walk_up=True), P('../Foo/Bar')) -+ self.assertEqual(p.relative_to('//sErver/sHare/bar', walk_up=True), P('../Foo/Bar')) -+ # Unrelated paths. -+ self.assertRaises(ValueError, p.relative_to, P('/Server/Share/Foo')) -+ self.assertRaises(ValueError, p.relative_to, P('c:/Server/Share/Foo')) -+ self.assertRaises(ValueError, p.relative_to, P('//z/Share/Foo')) -+ self.assertRaises(ValueError, p.relative_to, P('//Server/z/Foo')) -+ self.assertRaises(ValueError, p.relative_to, P('/Server/Share/Foo'), walk_up=True) -+ self.assertRaises(ValueError, p.relative_to, P('c:/Server/Share/Foo'), walk_up=True) -+ self.assertRaises(ValueError, p.relative_to, P('//z/Share/Foo'), walk_up=True) -+ self.assertRaises(ValueError, p.relative_to, P('//Server/z/Foo'), walk_up=True) -+ -+ def test_is_relative_to_common(self): -+ P = self.cls -+ p = P('a/b') -+ self.assertRaises(TypeError, p.is_relative_to) -+ self.assertRaises(TypeError, p.is_relative_to, b'a') -+ self.assertTrue(p.is_relative_to(P(''))) -+ self.assertTrue(p.is_relative_to('')) -+ self.assertTrue(p.is_relative_to(P('a'))) -+ self.assertTrue(p.is_relative_to('a/')) -+ self.assertTrue(p.is_relative_to(P('a/b'))) -+ self.assertTrue(p.is_relative_to('a/b')) -+ # Unrelated paths. -+ self.assertFalse(p.is_relative_to(P('c'))) -+ self.assertFalse(p.is_relative_to(P('a/b/c'))) -+ self.assertFalse(p.is_relative_to(P('a/c'))) -+ self.assertFalse(p.is_relative_to(P('/a'))) -+ p = P('/a/b') -+ self.assertTrue(p.is_relative_to(P('/'))) -+ self.assertTrue(p.is_relative_to('/')) -+ self.assertTrue(p.is_relative_to(P('/a'))) -+ self.assertTrue(p.is_relative_to('/a')) -+ self.assertTrue(p.is_relative_to('/a/')) -+ self.assertTrue(p.is_relative_to(P('/a/b'))) -+ self.assertTrue(p.is_relative_to('/a/b')) -+ # Unrelated paths. -+ self.assertFalse(p.is_relative_to(P('/c'))) -+ self.assertFalse(p.is_relative_to(P('/a/b/c'))) -+ self.assertFalse(p.is_relative_to(P('/a/c'))) -+ self.assertFalse(p.is_relative_to(P(''))) -+ self.assertFalse(p.is_relative_to('')) -+ self.assertFalse(p.is_relative_to(P('a'))) -+ -+ @needs_windows -+ def test_is_relative_to_windows(self): -+ P = self.cls -+ p = P('C:Foo/Bar') -+ self.assertTrue(p.is_relative_to(P('c:'))) -+ self.assertTrue(p.is_relative_to('c:')) -+ self.assertTrue(p.is_relative_to(P('c:foO'))) -+ self.assertTrue(p.is_relative_to('c:foO')) -+ self.assertTrue(p.is_relative_to('c:foO/')) -+ self.assertTrue(p.is_relative_to(P('c:foO/baR'))) -+ self.assertTrue(p.is_relative_to('c:foO/baR')) -+ # Unrelated paths. -+ self.assertFalse(p.is_relative_to(P())) -+ self.assertFalse(p.is_relative_to('')) -+ self.assertFalse(p.is_relative_to(P('d:'))) -+ self.assertFalse(p.is_relative_to(P('/'))) -+ self.assertFalse(p.is_relative_to(P('Foo'))) -+ self.assertFalse(p.is_relative_to(P('/Foo'))) -+ self.assertFalse(p.is_relative_to(P('C:/Foo'))) -+ self.assertFalse(p.is_relative_to(P('C:Foo/Bar/Baz'))) -+ self.assertFalse(p.is_relative_to(P('C:Foo/Baz'))) -+ p = P('C:/Foo/Bar') -+ self.assertTrue(p.is_relative_to(P('c:/'))) -+ self.assertTrue(p.is_relative_to(P('c:/foO'))) -+ self.assertTrue(p.is_relative_to('c:/foO/')) -+ self.assertTrue(p.is_relative_to(P('c:/foO/baR'))) -+ self.assertTrue(p.is_relative_to('c:/foO/baR')) -+ # Unrelated paths. -+ self.assertFalse(p.is_relative_to('c:')) -+ self.assertFalse(p.is_relative_to(P('C:/Baz'))) -+ self.assertFalse(p.is_relative_to(P('C:/Foo/Bar/Baz'))) -+ self.assertFalse(p.is_relative_to(P('C:/Foo/Baz'))) -+ self.assertFalse(p.is_relative_to(P('C:Foo'))) -+ self.assertFalse(p.is_relative_to(P('d:'))) -+ self.assertFalse(p.is_relative_to(P('d:/'))) -+ self.assertFalse(p.is_relative_to(P('/'))) -+ self.assertFalse(p.is_relative_to(P('/Foo'))) -+ self.assertFalse(p.is_relative_to(P('//C/Foo'))) -+ # UNC paths. -+ p = P('//Server/Share/Foo/Bar') -+ self.assertTrue(p.is_relative_to(P('//sErver/sHare'))) -+ self.assertTrue(p.is_relative_to('//sErver/sHare')) -+ self.assertTrue(p.is_relative_to('//sErver/sHare/')) -+ self.assertTrue(p.is_relative_to(P('//sErver/sHare/Foo'))) -+ self.assertTrue(p.is_relative_to('//sErver/sHare/Foo')) -+ self.assertTrue(p.is_relative_to('//sErver/sHare/Foo/')) -+ self.assertTrue(p.is_relative_to(P('//sErver/sHare/Foo/Bar'))) -+ self.assertTrue(p.is_relative_to('//sErver/sHare/Foo/Bar')) -+ # Unrelated paths. -+ self.assertFalse(p.is_relative_to(P('/Server/Share/Foo'))) -+ self.assertFalse(p.is_relative_to(P('c:/Server/Share/Foo'))) -+ self.assertFalse(p.is_relative_to(P('//z/Share/Foo'))) -+ self.assertFalse(p.is_relative_to(P('//Server/z/Foo'))) -+ - - class PurePosixPathTest(PurePathTest): - cls = pathlib.PurePosixPath -@@ -543,7 +1002,7 @@ - # Tests for the concrete classes. - # - --class PathTest(test_pathlib_abc.DummyPathTest, PurePathTest): -+class PathTest(test_pathlib_abc.DummyRWPathTest, PurePathTest): - """Tests for the FS-accessing functionalities of the Path classes.""" - cls = pathlib.Path - can_symlink = os_helper.can_symlink() -@@ -553,10 +1012,44 @@ - if name in _tests_needing_symlinks and not self.can_symlink: - self.skipTest('requires symlinks') - super().setUp() -- os.chmod(self.parser.join(self.base, 'dirE'), 0) -+ -+ def createTestHierarchy(self): -+ os.mkdir(self.base) -+ os.mkdir(os.path.join(self.base, 'dirA')) -+ os.mkdir(os.path.join(self.base, 'dirB')) -+ os.mkdir(os.path.join(self.base, 'dirC')) -+ os.mkdir(os.path.join(self.base, 'dirC', 'dirD')) -+ os.mkdir(os.path.join(self.base, 'dirE')) -+ with open(os.path.join(self.base, 'fileA'), 'wb') as f: -+ f.write(b"this is file A\n") -+ with open(os.path.join(self.base, 'dirB', 'fileB'), 'wb') as f: -+ f.write(b"this is file B\n") -+ with open(os.path.join(self.base, 'dirC', 'fileC'), 'wb') as f: -+ f.write(b"this is file C\n") -+ with open(os.path.join(self.base, 'dirC', 'novel.txt'), 'wb') as f: -+ f.write(b"this is a novel\n") -+ with open(os.path.join(self.base, 'dirC', 'dirD', 'fileD'), 'wb') as f: -+ f.write(b"this is file D\n") -+ os.chmod(os.path.join(self.base, 'dirE'), 0) -+ if self.can_symlink: -+ # Relative symlinks. -+ os.symlink('fileA', os.path.join(self.base, 'linkA')) -+ os.symlink('non-existing', os.path.join(self.base, 'brokenLink')) -+ os.symlink('dirB', -+ os.path.join(self.base, 'linkB'), -+ target_is_directory=True) -+ os.symlink(os.path.join('..', 'dirB'), -+ os.path.join(self.base, 'dirA', 'linkC'), -+ target_is_directory=True) -+ # This one goes upwards, creating a loop. -+ os.symlink(os.path.join('..', 'dirB'), -+ os.path.join(self.base, 'dirB', 'linkD'), -+ target_is_directory=True) -+ # Broken symlink (pointing to itself). -+ os.symlink('brokenLinkLoop', os.path.join(self.base, 'brokenLinkLoop')) - - def tearDown(self): -- os.chmod(self.parser.join(self.base, 'dirE'), 0o777) -+ os.chmod(os.path.join(self.base, 'dirE'), 0o777) - os_helper.rmtree(self.base) - - def tempdir(self): -@@ -565,15 +1058,15 @@ - self.addCleanup(os_helper.rmtree, d) - return d - -- def test_matches_pathbase_docstrings(self): -- path_names = {name for name in dir(pathlib._abc.PathBase) if name[0] != '_'} -+ def test_matches_writablepath_docstrings(self): -+ path_names = {name for name in dir(pathlib._abc.WritablePath) if name[0] != '_'} - for attr_name in path_names: - if attr_name == 'parser': -- # On Windows, Path.parser is ntpath, but PathBase.parser is -+ # On Windows, Path.parser is ntpath, but WritablePath.parser is - # posixpath, and so their docstrings differ. - continue - our_attr = getattr(self.cls, attr_name) -- path_attr = getattr(pathlib._abc.PathBase, attr_name) -+ path_attr = getattr(pathlib._abc.WritablePath, attr_name) - self.assertEqual(our_attr.__doc__, path_attr.__doc__) - - def test_concrete_class(self): -@@ -687,6 +1180,15 @@ - for dirpath, dirnames, filenames in p.walk(): - self.assertEqual(42, dirpath.session_id) - -+ def test_open_common(self): -+ p = self.cls(self.base) -+ with (p / 'fileA').open('r') as f: -+ self.assertIsInstance(f, io.TextIOBase) -+ self.assertEqual(f.read(), "this is file A\n") -+ with (p / 'fileA').open('rb') as f: -+ self.assertIsInstance(f, io.BufferedIOBase) -+ self.assertEqual(f.read().strip(), b"this is file A") -+ - def test_open_unbuffered(self): - p = self.cls(self.base) - with (p / 'fileA').open('rb', buffering=0) as f: -@@ -1008,26 +1510,97 @@ - self.assertTrue(target.is_symlink()) - self.assertEqual(source_readlink, target.readlink()) - -+ def test_move_file(self): -+ base = self.cls(self.base) -+ source = base / 'fileA' -+ source_text = source.read_text() -+ target = base / 'fileA_moved' -+ result = source.move(target) -+ self.assertEqual(result, target) -+ self.assertFalse(source.exists()) -+ self.assertTrue(target.exists()) -+ self.assertEqual(source_text, target.read_text()) -+ - @patch_replace - def test_move_file_other_fs(self): - self.test_move_file() - -+ def test_move_file_to_file(self): -+ base = self.cls(self.base) -+ source = base / 'fileA' -+ source_text = source.read_text() -+ target = base / 'dirB' / 'fileB' -+ result = source.move(target) -+ self.assertEqual(result, target) -+ self.assertFalse(source.exists()) -+ self.assertTrue(target.exists()) -+ self.assertEqual(source_text, target.read_text()) -+ - @patch_replace - def test_move_file_to_file_other_fs(self): - self.test_move_file_to_file() - -+ def test_move_file_to_dir(self): -+ base = self.cls(self.base) -+ source = base / 'fileA' -+ target = base / 'dirB' -+ self.assertRaises(OSError, source.move, target) -+ - @patch_replace - def test_move_file_to_dir_other_fs(self): - self.test_move_file_to_dir() - -+ def test_move_file_to_itself(self): -+ base = self.cls(self.base) -+ source = base / 'fileA' -+ self.assertRaises(OSError, source.move, source) -+ -+ def test_move_dir(self): -+ base = self.cls(self.base) -+ source = base / 'dirC' -+ target = base / 'dirC_moved' -+ result = source.move(target) -+ self.assertEqual(result, target) -+ self.assertFalse(source.exists()) -+ self.assertTrue(target.is_dir()) -+ self.assertTrue(target.joinpath('dirD').is_dir()) -+ self.assertTrue(target.joinpath('dirD', 'fileD').is_file()) -+ self.assertEqual(target.joinpath('dirD', 'fileD').read_text(), -+ "this is file D\n") -+ self.assertTrue(target.joinpath('fileC').is_file()) -+ self.assertTrue(target.joinpath('fileC').read_text(), -+ "this is file C\n") -+ - @patch_replace - def test_move_dir_other_fs(self): - self.test_move_dir() - -+ def test_move_dir_to_dir(self): -+ base = self.cls(self.base) -+ source = base / 'dirC' -+ target = base / 'dirB' -+ self.assertRaises(OSError, source.move, target) -+ self.assertTrue(source.exists()) -+ self.assertTrue(target.exists()) -+ - @patch_replace - def test_move_dir_to_dir_other_fs(self): - self.test_move_dir_to_dir() - -+ def test_move_dir_to_itself(self): -+ base = self.cls(self.base) -+ source = base / 'dirC' -+ self.assertRaises(OSError, source.move, source) -+ self.assertTrue(source.exists()) -+ -+ def test_move_dir_into_itself(self): -+ base = self.cls(self.base) -+ source = base / 'dirC' -+ target = base / 'dirC' / 'bar' -+ self.assertRaises(OSError, source.move, target) -+ self.assertTrue(source.exists()) -+ self.assertFalse(target.exists()) -+ - @patch_replace - def test_move_dir_into_itself_other_fs(self): - self.test_move_dir_into_itself() -@@ -1057,10 +1630,26 @@ - def test_move_dangling_symlink_other_fs(self): - self.test_move_dangling_symlink() - -+ def test_move_into(self): -+ base = self.cls(self.base) -+ source = base / 'fileA' -+ source_text = source.read_text() -+ target_dir = base / 'dirA' -+ result = source.move_into(target_dir) -+ self.assertEqual(result, target_dir / 'fileA') -+ self.assertFalse(source.exists()) -+ self.assertTrue(result.exists()) -+ self.assertEqual(source_text, result.read_text()) -+ - @patch_replace - def test_move_into_other_os(self): - self.test_move_into() - -+ def test_move_into_empty_name(self): -+ source = self.cls('') -+ target_dir = self.base -+ self.assertRaises(ValueError, source.move_into, target_dir) -+ - @patch_replace - def test_move_into_empty_name_other_os(self): - self.test_move_into_empty_name() -@@ -1379,6 +1968,37 @@ - self.assertFileNotFound(p.stat) - self.assertFileNotFound(p.unlink) - -+ def test_delete_file(self): -+ p = self.cls(self.base) / 'fileA' -+ p._delete() -+ self.assertFalse(p.exists()) -+ self.assertFileNotFound(p._delete) -+ -+ def test_delete_dir(self): -+ base = self.cls(self.base) -+ base.joinpath('dirA')._delete() -+ self.assertFalse(base.joinpath('dirA').exists()) -+ self.assertFalse(base.joinpath('dirA', 'linkC').exists( -+ follow_symlinks=False)) -+ base.joinpath('dirB')._delete() -+ self.assertFalse(base.joinpath('dirB').exists()) -+ self.assertFalse(base.joinpath('dirB', 'fileB').exists()) -+ self.assertFalse(base.joinpath('dirB', 'linkD').exists( -+ follow_symlinks=False)) -+ base.joinpath('dirC')._delete() -+ self.assertFalse(base.joinpath('dirC').exists()) -+ self.assertFalse(base.joinpath('dirC', 'dirD').exists()) -+ self.assertFalse(base.joinpath('dirC', 'dirD', 'fileD').exists()) -+ self.assertFalse(base.joinpath('dirC', 'fileC').exists()) -+ self.assertFalse(base.joinpath('dirC', 'novel.txt').exists()) -+ -+ def test_delete_missing(self): -+ tmp = self.cls(self.base, 'delete') -+ tmp.mkdir() -+ # filename is guaranteed not to exist -+ filename = tmp / 'foo' -+ self.assertRaises(FileNotFoundError, filename._delete) -+ - @needs_symlinks - def test_delete_symlink(self): - tmp = self.cls(self.base, 'delete') -@@ -1776,6 +2396,44 @@ - with self.assertRaises(pathlib.UnsupportedOperation): - q.symlink_to(p) - -+ @needs_symlinks -+ def test_info_is_symlink_caching(self): -+ p = self.cls(self.base) -+ q = p / 'mylink' -+ self.assertFalse(q.info.is_symlink()) -+ q.symlink_to('blah') -+ self.assertFalse(q.info.is_symlink()) -+ -+ q = p / 'mylink' # same path, new instance. -+ self.assertTrue(q.info.is_symlink()) -+ q.unlink() -+ self.assertTrue(q.info.is_symlink()) -+ -+ def test_stat(self): -+ statA = self.cls(self.base).joinpath('fileA').stat() -+ statB = self.cls(self.base).joinpath('dirB', 'fileB').stat() -+ statC = self.cls(self.base).joinpath('dirC').stat() -+ # st_mode: files are the same, directory differs. -+ self.assertIsInstance(statA.st_mode, int) -+ self.assertEqual(statA.st_mode, statB.st_mode) -+ self.assertNotEqual(statA.st_mode, statC.st_mode) -+ self.assertNotEqual(statB.st_mode, statC.st_mode) -+ # st_ino: all different, -+ self.assertIsInstance(statA.st_ino, int) -+ self.assertNotEqual(statA.st_ino, statB.st_ino) -+ self.assertNotEqual(statA.st_ino, statC.st_ino) -+ self.assertNotEqual(statB.st_ino, statC.st_ino) -+ # st_dev: all the same. -+ self.assertIsInstance(statA.st_dev, int) -+ self.assertEqual(statA.st_dev, statB.st_dev) -+ self.assertEqual(statA.st_dev, statC.st_dev) -+ # other attributes not used by pathlib. -+ -+ def test_stat_no_follow_symlinks_nosymlink(self): -+ p = self.cls(self.base) / 'fileA' -+ st = p.stat() -+ self.assertEqual(st, p.stat(follow_symlinks=False)) -+ - @needs_symlinks - def test_stat_no_follow_symlinks(self): - p = self.cls(self.base) / 'linkA' -@@ -2461,7 +3119,7 @@ - P('c:/').group() - - --class PathWalkTest(test_pathlib_abc.DummyPathWalkTest): -+class PathWalkTest(test_pathlib_abc.DummyReadablePathWalkTest): - cls = pathlib.Path - base = PathTest.base - can_symlink = PathTest.can_symlink -@@ -2471,6 +3129,42 @@ - if name in _tests_needing_symlinks and not self.can_symlink: - self.skipTest('requires symlinks') - super().setUp() -+ -+ def createTestHierarchy(self): -+ # Build: -+ # TESTFN/ -+ # TEST1/ a file kid and two directory kids -+ # tmp1 -+ # SUB1/ a file kid and a directory kid -+ # tmp2 -+ # SUB11/ no kids -+ # SUB2/ a file kid and a dirsymlink kid -+ # tmp3 -+ # link/ a symlink to TEST2 -+ # broken_link -+ # broken_link2 -+ # TEST2/ -+ # tmp4 a lone file -+ t2_path = self.cls(self.base, "TEST2") -+ os.makedirs(self.sub11_path) -+ os.makedirs(self.sub2_path) -+ os.makedirs(t2_path) -+ -+ tmp1_path = self.walk_path / "tmp1" -+ tmp2_path = self.sub1_path / "tmp2" -+ tmp3_path = self.sub2_path / "tmp3" -+ tmp4_path = self.cls(self.base, "TEST2", "tmp4") -+ for path in tmp1_path, tmp2_path, tmp3_path, tmp4_path: -+ with open(path, "w", encoding='utf-8') as f: -+ f.write(f"I'm {path} and proud of it. Blame test_pathlib.\n") -+ -+ if self.can_symlink: -+ broken_link_path = self.sub2_path / "broken_link" -+ broken_link2_path = self.sub2_path / "broken_link2" -+ os.symlink(t2_path, self.link_path, target_is_directory=True) -+ os.symlink('broken', broken_link_path) -+ os.symlink(os.path.join('tmp3', 'broken'), broken_link2_path) -+ self.sub2_tree = (self.sub2_path, [], ["broken_link", "broken_link2", "link", "tmp3"]) - sub21_path= self.sub2_path / "SUB21" - tmp5_path = sub21_path / "tmp3" - broken_link3_path = self.sub2_path / "broken_link3" -@@ -2494,7 +3188,7 @@ - def tearDown(self): - if 'SUB21' in self.sub2_tree[1]: - os.chmod(self.sub2_path / "SUB21", stat.S_IRWXU) -- super().tearDown() -+ os_helper.rmtree(self.base) - - def test_walk_bad_dir(self): - errors = [] -diff --git a/Lib/test/test_pathlib/test_pathlib_abc.py b/Lib/test/test_pathlib/test_pathlib_abc.py -index e230dd18879..836d8387bdc 100644 ---- a/Lib/test/test_pathlib/test_pathlib_abc.py -+++ b/Lib/test/test_pathlib/test_pathlib_abc.py -@@ -2,11 +2,10 @@ - import io - import os - import errno --import stat - import unittest - --from pathlib._abc import PurePathBase, PathBase --from pathlib._types import Parser -+from pathlib._abc import JoinablePath, ReadablePath, WritablePath, magic_open -+from pathlib.types import _PathParser, PathInfo - import posixpath - - from test.support.os_helper import TESTFN -@@ -32,8 +31,8 @@ - # - - --class PurePathBaseTest(unittest.TestCase): -- cls = PurePathBase -+class JoinablePathTest(unittest.TestCase): -+ cls = JoinablePath - - def test_magic_methods(self): - P = self.cls -@@ -52,11 +51,19 @@ - self.assertIs(self.cls.parser, posixpath) - - --class DummyPurePath(PurePathBase): -- __slots__ = () -+class DummyJoinablePath(JoinablePath): -+ __slots__ = ('_segments',) -+ -+ def __init__(self, *segments): -+ self._segments = segments -+ -+ def __str__(self): -+ if self._segments: -+ return self.parser.join(*self._segments) -+ return '' - - def __eq__(self, other): -- if not isinstance(other, DummyPurePath): -+ if not isinstance(other, DummyJoinablePath): - return NotImplemented - return str(self) == str(other) - -@@ -64,11 +71,14 @@ - return hash(str(self)) - - def __repr__(self): -- return "{}({!r})".format(self.__class__.__name__, self.as_posix()) -+ return "{}({!r})".format(self.__class__.__name__, str(self)) -+ -+ def with_segments(self, *pathsegments): -+ return type(self)(*pathsegments) - - --class DummyPurePathTest(unittest.TestCase): -- cls = DummyPurePath -+class DummyJoinablePathTest(unittest.TestCase): -+ cls = DummyJoinablePath - - # Use a base path that's unrelated to any real filesystem path. - base = f'/this/path/kills/fascists/{TESTFN}' -@@ -85,7 +95,7 @@ - self.altsep = self.parser.altsep - - def test_parser(self): -- self.assertIsInstance(self.cls.parser, Parser) -+ self.assertIsInstance(self.cls.parser, _PathParser) - - def test_constructor_common(self): - P = self.cls -@@ -97,31 +107,6 @@ - P('a/b/c') - P('/a/b/c') - -- def test_bytes(self): -- P = self.cls -- with self.assertRaises(TypeError): -- P(b'a') -- with self.assertRaises(TypeError): -- P(b'a', 'b') -- with self.assertRaises(TypeError): -- P('a', b'b') -- with self.assertRaises(TypeError): -- P('a').joinpath(b'b') -- with self.assertRaises(TypeError): -- P('a') / b'b' -- with self.assertRaises(TypeError): -- b'a' / P('b') -- with self.assertRaises(TypeError): -- P('a').match(b'b') -- with self.assertRaises(TypeError): -- P('a').relative_to(b'b') -- with self.assertRaises(TypeError): -- P('a').with_name(b'b') -- with self.assertRaises(TypeError): -- P('a').with_stem(b'b') -- with self.assertRaises(TypeError): -- P('a').with_suffix(b'b') -- - def _check_str_subclass(self, *args): - # Issue #21127: it should be possible to construct a PurePath object - # from a str subclass instance, and it then gets converted to -@@ -170,7 +155,6 @@ - self.assertEqual(42, p.with_stem('foo').session_id) - self.assertEqual(42, p.with_suffix('.foo').session_id) - self.assertEqual(42, p.with_segments('foo').session_id) -- self.assertEqual(42, p.relative_to('foo').session_id) - self.assertEqual(42, p.parent.session_id) - for parent in p.parents: - self.assertEqual(42, parent.session_id) -@@ -312,94 +296,6 @@ - p = self.cls('//a/b/c/d') - self.assertEqual(str(p), '\\\\a\\b\\c\\d') - -- def test_as_posix_common(self): -- P = self.cls -- for pathstr in ('a', 'a/b', 'a/b/c', '/', '/a/b', '/a/b/c'): -- self.assertEqual(P(pathstr).as_posix(), pathstr) -- # Other tests for as_posix() are in test_equivalences(). -- -- def test_match_empty(self): -- P = self.cls -- self.assertRaises(ValueError, P('a').match, '') -- -- def test_match_common(self): -- P = self.cls -- # Simple relative pattern. -- self.assertTrue(P('b.py').match('b.py')) -- self.assertTrue(P('a/b.py').match('b.py')) -- self.assertTrue(P('/a/b.py').match('b.py')) -- self.assertFalse(P('a.py').match('b.py')) -- self.assertFalse(P('b/py').match('b.py')) -- self.assertFalse(P('/a.py').match('b.py')) -- self.assertFalse(P('b.py/c').match('b.py')) -- # Wildcard relative pattern. -- self.assertTrue(P('b.py').match('*.py')) -- self.assertTrue(P('a/b.py').match('*.py')) -- self.assertTrue(P('/a/b.py').match('*.py')) -- self.assertFalse(P('b.pyc').match('*.py')) -- self.assertFalse(P('b./py').match('*.py')) -- self.assertFalse(P('b.py/c').match('*.py')) -- # Multi-part relative pattern. -- self.assertTrue(P('ab/c.py').match('a*/*.py')) -- self.assertTrue(P('/d/ab/c.py').match('a*/*.py')) -- self.assertFalse(P('a.py').match('a*/*.py')) -- self.assertFalse(P('/dab/c.py').match('a*/*.py')) -- self.assertFalse(P('ab/c.py/d').match('a*/*.py')) -- # Absolute pattern. -- self.assertTrue(P('/b.py').match('/*.py')) -- self.assertFalse(P('b.py').match('/*.py')) -- self.assertFalse(P('a/b.py').match('/*.py')) -- self.assertFalse(P('/a/b.py').match('/*.py')) -- # Multi-part absolute pattern. -- self.assertTrue(P('/a/b.py').match('/a/*.py')) -- self.assertFalse(P('/ab.py').match('/a/*.py')) -- self.assertFalse(P('/a/b/c.py').match('/a/*.py')) -- # Multi-part glob-style pattern. -- self.assertFalse(P('/a/b/c.py').match('/**/*.py')) -- self.assertTrue(P('/a/b/c.py').match('/a/**/*.py')) -- # Case-sensitive flag -- self.assertFalse(P('A.py').match('a.PY', case_sensitive=True)) -- self.assertTrue(P('A.py').match('a.PY', case_sensitive=False)) -- self.assertFalse(P('c:/a/B.Py').match('C:/A/*.pY', case_sensitive=True)) -- self.assertTrue(P('/a/b/c.py').match('/A/*/*.Py', case_sensitive=False)) -- # Matching against empty path -- self.assertFalse(P('').match('*')) -- self.assertFalse(P('').match('**')) -- self.assertFalse(P('').match('**/*')) -- -- @needs_posix -- def test_match_posix(self): -- P = self.cls -- self.assertFalse(P('A.py').match('a.PY')) -- -- @needs_windows -- def test_match_windows(self): -- P = self.cls -- # Absolute patterns. -- self.assertTrue(P('c:/b.py').match('*:/*.py')) -- self.assertTrue(P('c:/b.py').match('c:/*.py')) -- self.assertFalse(P('d:/b.py').match('c:/*.py')) # wrong drive -- self.assertFalse(P('b.py').match('/*.py')) -- self.assertFalse(P('b.py').match('c:*.py')) -- self.assertFalse(P('b.py').match('c:/*.py')) -- self.assertFalse(P('c:b.py').match('/*.py')) -- self.assertFalse(P('c:b.py').match('c:/*.py')) -- self.assertFalse(P('/b.py').match('c:*.py')) -- self.assertFalse(P('/b.py').match('c:/*.py')) -- # UNC patterns. -- self.assertTrue(P('//some/share/a.py').match('//*/*/*.py')) -- self.assertTrue(P('//some/share/a.py').match('//some/share/*.py')) -- self.assertFalse(P('//other/share/a.py').match('//some/share/*.py')) -- self.assertFalse(P('//some/share/a/b.py').match('//some/share/*.py')) -- # Case-insensitivity. -- self.assertTrue(P('B.py').match('b.PY')) -- self.assertTrue(P('c:/a/B.Py').match('C:/A/*.pY')) -- self.assertTrue(P('//Some/Share/B.Py').match('//somE/sharE/*.pY')) -- # Path anchor doesn't match pattern anchor -- self.assertFalse(P('c:/b.py').match('/*.py')) # 'c:/' vs '/' -- self.assertFalse(P('c:/b.py').match('c:*.py')) # 'c:/' vs 'c:' -- self.assertFalse(P('//some/share/a.py').match('/*.py')) # '//some/share/' vs '/' -- - def test_full_match_common(self): - P = self.cls - # Simple relative pattern. -@@ -624,50 +520,6 @@ - with self.assertRaises(IndexError): - par[2] - -- def test_drive_common(self): -- P = self.cls -- self.assertEqual(P('a/b').drive, '') -- self.assertEqual(P('/a/b').drive, '') -- self.assertEqual(P('').drive, '') -- -- @needs_windows -- def test_drive_windows(self): -- P = self.cls -- self.assertEqual(P('c:').drive, 'c:') -- self.assertEqual(P('c:a/b').drive, 'c:') -- self.assertEqual(P('c:/').drive, 'c:') -- self.assertEqual(P('c:/a/b/').drive, 'c:') -- self.assertEqual(P('//a/b').drive, '\\\\a\\b') -- self.assertEqual(P('//a/b/').drive, '\\\\a\\b') -- self.assertEqual(P('//a/b/c/d').drive, '\\\\a\\b') -- self.assertEqual(P('./c:a').drive, '') -- -- def test_root_common(self): -- P = self.cls -- sep = self.sep -- self.assertEqual(P('').root, '') -- self.assertEqual(P('a/b').root, '') -- self.assertEqual(P('/').root, sep) -- self.assertEqual(P('/a/b').root, sep) -- -- @needs_posix -- def test_root_posix(self): -- P = self.cls -- self.assertEqual(P('/a/b').root, '/') -- # POSIX special case for two leading slashes. -- self.assertEqual(P('//a/b').root, '//') -- -- @needs_windows -- def test_root_windows(self): -- P = self.cls -- self.assertEqual(P('c:').root, '') -- self.assertEqual(P('c:a/b').root, '') -- self.assertEqual(P('c:/').root, '\\') -- self.assertEqual(P('c:/a/b/').root, '\\') -- self.assertEqual(P('//a/b').root, '\\') -- self.assertEqual(P('//a/b/').root, '\\') -- self.assertEqual(P('//a/b/c/d').root, '\\') -- - def test_anchor_common(self): - P = self.cls - sep = self.sep -@@ -976,350 +828,15 @@ - self.assertRaises(ValueError, P('a/b').with_suffix, '.d/.') - self.assertRaises(TypeError, P('a/b').with_suffix, None) - -- def test_relative_to_common(self): -- P = self.cls -- p = P('a/b') -- self.assertRaises(TypeError, p.relative_to) -- self.assertRaises(TypeError, p.relative_to, b'a') -- self.assertEqual(p.relative_to(P('')), P('a/b')) -- self.assertEqual(p.relative_to(''), P('a/b')) -- self.assertEqual(p.relative_to(P('a')), P('b')) -- self.assertEqual(p.relative_to('a'), P('b')) -- self.assertEqual(p.relative_to('a/'), P('b')) -- self.assertEqual(p.relative_to(P('a/b')), P('')) -- self.assertEqual(p.relative_to('a/b'), P('')) -- self.assertEqual(p.relative_to(P(''), walk_up=True), P('a/b')) -- self.assertEqual(p.relative_to('', walk_up=True), P('a/b')) -- self.assertEqual(p.relative_to(P('a'), walk_up=True), P('b')) -- self.assertEqual(p.relative_to('a', walk_up=True), P('b')) -- self.assertEqual(p.relative_to('a/', walk_up=True), P('b')) -- self.assertEqual(p.relative_to(P('a/b'), walk_up=True), P('')) -- self.assertEqual(p.relative_to('a/b', walk_up=True), P('')) -- self.assertEqual(p.relative_to(P('a/c'), walk_up=True), P('../b')) -- self.assertEqual(p.relative_to('a/c', walk_up=True), P('../b')) -- self.assertEqual(p.relative_to(P('a/b/c'), walk_up=True), P('..')) -- self.assertEqual(p.relative_to('a/b/c', walk_up=True), P('..')) -- self.assertEqual(p.relative_to(P('c'), walk_up=True), P('../a/b')) -- self.assertEqual(p.relative_to('c', walk_up=True), P('../a/b')) -- # Unrelated paths. -- self.assertRaises(ValueError, p.relative_to, P('c')) -- self.assertRaises(ValueError, p.relative_to, P('a/b/c')) -- self.assertRaises(ValueError, p.relative_to, P('a/c')) -- self.assertRaises(ValueError, p.relative_to, P('/a')) -- self.assertRaises(ValueError, p.relative_to, P("../a")) -- self.assertRaises(ValueError, p.relative_to, P("a/..")) -- self.assertRaises(ValueError, p.relative_to, P("/a/..")) -- self.assertRaises(ValueError, p.relative_to, P('/'), walk_up=True) -- self.assertRaises(ValueError, p.relative_to, P('/a'), walk_up=True) -- self.assertRaises(ValueError, p.relative_to, P("../a"), walk_up=True) -- self.assertRaises(ValueError, p.relative_to, P("a/.."), walk_up=True) -- self.assertRaises(ValueError, p.relative_to, P("/a/.."), walk_up=True) -- p = P('/a/b') -- self.assertEqual(p.relative_to(P('/')), P('a/b')) -- self.assertEqual(p.relative_to('/'), P('a/b')) -- self.assertEqual(p.relative_to(P('/a')), P('b')) -- self.assertEqual(p.relative_to('/a'), P('b')) -- self.assertEqual(p.relative_to('/a/'), P('b')) -- self.assertEqual(p.relative_to(P('/a/b')), P('')) -- self.assertEqual(p.relative_to('/a/b'), P('')) -- self.assertEqual(p.relative_to(P('/'), walk_up=True), P('a/b')) -- self.assertEqual(p.relative_to('/', walk_up=True), P('a/b')) -- self.assertEqual(p.relative_to(P('/a'), walk_up=True), P('b')) -- self.assertEqual(p.relative_to('/a', walk_up=True), P('b')) -- self.assertEqual(p.relative_to('/a/', walk_up=True), P('b')) -- self.assertEqual(p.relative_to(P('/a/b'), walk_up=True), P('')) -- self.assertEqual(p.relative_to('/a/b', walk_up=True), P('')) -- self.assertEqual(p.relative_to(P('/a/c'), walk_up=True), P('../b')) -- self.assertEqual(p.relative_to('/a/c', walk_up=True), P('../b')) -- self.assertEqual(p.relative_to(P('/a/b/c'), walk_up=True), P('..')) -- self.assertEqual(p.relative_to('/a/b/c', walk_up=True), P('..')) -- self.assertEqual(p.relative_to(P('/c'), walk_up=True), P('../a/b')) -- self.assertEqual(p.relative_to('/c', walk_up=True), P('../a/b')) -- # Unrelated paths. -- self.assertRaises(ValueError, p.relative_to, P('/c')) -- self.assertRaises(ValueError, p.relative_to, P('/a/b/c')) -- self.assertRaises(ValueError, p.relative_to, P('/a/c')) -- self.assertRaises(ValueError, p.relative_to, P('')) -- self.assertRaises(ValueError, p.relative_to, '') -- self.assertRaises(ValueError, p.relative_to, P('a')) -- self.assertRaises(ValueError, p.relative_to, P("../a")) -- self.assertRaises(ValueError, p.relative_to, P("a/..")) -- self.assertRaises(ValueError, p.relative_to, P("/a/..")) -- self.assertRaises(ValueError, p.relative_to, P(''), walk_up=True) -- self.assertRaises(ValueError, p.relative_to, P('a'), walk_up=True) -- self.assertRaises(ValueError, p.relative_to, P("../a"), walk_up=True) -- self.assertRaises(ValueError, p.relative_to, P("a/.."), walk_up=True) -- self.assertRaises(ValueError, p.relative_to, P("/a/.."), walk_up=True) -- -- @needs_windows -- def test_relative_to_windows(self): -- P = self.cls -- p = P('C:Foo/Bar') -- self.assertEqual(p.relative_to(P('c:')), P('Foo/Bar')) -- self.assertEqual(p.relative_to('c:'), P('Foo/Bar')) -- self.assertEqual(p.relative_to(P('c:foO')), P('Bar')) -- self.assertEqual(p.relative_to('c:foO'), P('Bar')) -- self.assertEqual(p.relative_to('c:foO/'), P('Bar')) -- self.assertEqual(p.relative_to(P('c:foO/baR')), P()) -- self.assertEqual(p.relative_to('c:foO/baR'), P()) -- self.assertEqual(p.relative_to(P('c:'), walk_up=True), P('Foo/Bar')) -- self.assertEqual(p.relative_to('c:', walk_up=True), P('Foo/Bar')) -- self.assertEqual(p.relative_to(P('c:foO'), walk_up=True), P('Bar')) -- self.assertEqual(p.relative_to('c:foO', walk_up=True), P('Bar')) -- self.assertEqual(p.relative_to('c:foO/', walk_up=True), P('Bar')) -- self.assertEqual(p.relative_to(P('c:foO/baR'), walk_up=True), P()) -- self.assertEqual(p.relative_to('c:foO/baR', walk_up=True), P()) -- self.assertEqual(p.relative_to(P('C:Foo/Bar/Baz'), walk_up=True), P('..')) -- self.assertEqual(p.relative_to(P('C:Foo/Baz'), walk_up=True), P('../Bar')) -- self.assertEqual(p.relative_to(P('C:Baz/Bar'), walk_up=True), P('../../Foo/Bar')) -- # Unrelated paths. -- self.assertRaises(ValueError, p.relative_to, P()) -- self.assertRaises(ValueError, p.relative_to, '') -- self.assertRaises(ValueError, p.relative_to, P('d:')) -- self.assertRaises(ValueError, p.relative_to, P('/')) -- self.assertRaises(ValueError, p.relative_to, P('Foo')) -- self.assertRaises(ValueError, p.relative_to, P('/Foo')) -- self.assertRaises(ValueError, p.relative_to, P('C:/Foo')) -- self.assertRaises(ValueError, p.relative_to, P('C:Foo/Bar/Baz')) -- self.assertRaises(ValueError, p.relative_to, P('C:Foo/Baz')) -- self.assertRaises(ValueError, p.relative_to, P(), walk_up=True) -- self.assertRaises(ValueError, p.relative_to, '', walk_up=True) -- self.assertRaises(ValueError, p.relative_to, P('d:'), walk_up=True) -- self.assertRaises(ValueError, p.relative_to, P('/'), walk_up=True) -- self.assertRaises(ValueError, p.relative_to, P('Foo'), walk_up=True) -- self.assertRaises(ValueError, p.relative_to, P('/Foo'), walk_up=True) -- self.assertRaises(ValueError, p.relative_to, P('C:/Foo'), walk_up=True) -- p = P('C:/Foo/Bar') -- self.assertEqual(p.relative_to(P('c:/')), P('Foo/Bar')) -- self.assertEqual(p.relative_to('c:/'), P('Foo/Bar')) -- self.assertEqual(p.relative_to(P('c:/foO')), P('Bar')) -- self.assertEqual(p.relative_to('c:/foO'), P('Bar')) -- self.assertEqual(p.relative_to('c:/foO/'), P('Bar')) -- self.assertEqual(p.relative_to(P('c:/foO/baR')), P()) -- self.assertEqual(p.relative_to('c:/foO/baR'), P()) -- self.assertEqual(p.relative_to(P('c:/'), walk_up=True), P('Foo/Bar')) -- self.assertEqual(p.relative_to('c:/', walk_up=True), P('Foo/Bar')) -- self.assertEqual(p.relative_to(P('c:/foO'), walk_up=True), P('Bar')) -- self.assertEqual(p.relative_to('c:/foO', walk_up=True), P('Bar')) -- self.assertEqual(p.relative_to('c:/foO/', walk_up=True), P('Bar')) -- self.assertEqual(p.relative_to(P('c:/foO/baR'), walk_up=True), P()) -- self.assertEqual(p.relative_to('c:/foO/baR', walk_up=True), P()) -- self.assertEqual(p.relative_to('C:/Baz', walk_up=True), P('../Foo/Bar')) -- self.assertEqual(p.relative_to('C:/Foo/Bar/Baz', walk_up=True), P('..')) -- self.assertEqual(p.relative_to('C:/Foo/Baz', walk_up=True), P('../Bar')) -- # Unrelated paths. -- self.assertRaises(ValueError, p.relative_to, 'c:') -- self.assertRaises(ValueError, p.relative_to, P('c:')) -- self.assertRaises(ValueError, p.relative_to, P('C:/Baz')) -- self.assertRaises(ValueError, p.relative_to, P('C:/Foo/Bar/Baz')) -- self.assertRaises(ValueError, p.relative_to, P('C:/Foo/Baz')) -- self.assertRaises(ValueError, p.relative_to, P('C:Foo')) -- self.assertRaises(ValueError, p.relative_to, P('d:')) -- self.assertRaises(ValueError, p.relative_to, P('d:/')) -- self.assertRaises(ValueError, p.relative_to, P('/')) -- self.assertRaises(ValueError, p.relative_to, P('/Foo')) -- self.assertRaises(ValueError, p.relative_to, P('//C/Foo')) -- self.assertRaises(ValueError, p.relative_to, 'c:', walk_up=True) -- self.assertRaises(ValueError, p.relative_to, P('c:'), walk_up=True) -- self.assertRaises(ValueError, p.relative_to, P('C:Foo'), walk_up=True) -- self.assertRaises(ValueError, p.relative_to, P('d:'), walk_up=True) -- self.assertRaises(ValueError, p.relative_to, P('d:/'), walk_up=True) -- self.assertRaises(ValueError, p.relative_to, P('/'), walk_up=True) -- self.assertRaises(ValueError, p.relative_to, P('/Foo'), walk_up=True) -- self.assertRaises(ValueError, p.relative_to, P('//C/Foo'), walk_up=True) -- # UNC paths. -- p = P('//Server/Share/Foo/Bar') -- self.assertEqual(p.relative_to(P('//sErver/sHare')), P('Foo/Bar')) -- self.assertEqual(p.relative_to('//sErver/sHare'), P('Foo/Bar')) -- self.assertEqual(p.relative_to('//sErver/sHare/'), P('Foo/Bar')) -- self.assertEqual(p.relative_to(P('//sErver/sHare/Foo')), P('Bar')) -- self.assertEqual(p.relative_to('//sErver/sHare/Foo'), P('Bar')) -- self.assertEqual(p.relative_to('//sErver/sHare/Foo/'), P('Bar')) -- self.assertEqual(p.relative_to(P('//sErver/sHare/Foo/Bar')), P()) -- self.assertEqual(p.relative_to('//sErver/sHare/Foo/Bar'), P()) -- self.assertEqual(p.relative_to(P('//sErver/sHare'), walk_up=True), P('Foo/Bar')) -- self.assertEqual(p.relative_to('//sErver/sHare', walk_up=True), P('Foo/Bar')) -- self.assertEqual(p.relative_to('//sErver/sHare/', walk_up=True), P('Foo/Bar')) -- self.assertEqual(p.relative_to(P('//sErver/sHare/Foo'), walk_up=True), P('Bar')) -- self.assertEqual(p.relative_to('//sErver/sHare/Foo', walk_up=True), P('Bar')) -- self.assertEqual(p.relative_to('//sErver/sHare/Foo/', walk_up=True), P('Bar')) -- self.assertEqual(p.relative_to(P('//sErver/sHare/Foo/Bar'), walk_up=True), P()) -- self.assertEqual(p.relative_to('//sErver/sHare/Foo/Bar', walk_up=True), P()) -- self.assertEqual(p.relative_to(P('//sErver/sHare/bar'), walk_up=True), P('../Foo/Bar')) -- self.assertEqual(p.relative_to('//sErver/sHare/bar', walk_up=True), P('../Foo/Bar')) -- # Unrelated paths. -- self.assertRaises(ValueError, p.relative_to, P('/Server/Share/Foo')) -- self.assertRaises(ValueError, p.relative_to, P('c:/Server/Share/Foo')) -- self.assertRaises(ValueError, p.relative_to, P('//z/Share/Foo')) -- self.assertRaises(ValueError, p.relative_to, P('//Server/z/Foo')) -- self.assertRaises(ValueError, p.relative_to, P('/Server/Share/Foo'), walk_up=True) -- self.assertRaises(ValueError, p.relative_to, P('c:/Server/Share/Foo'), walk_up=True) -- self.assertRaises(ValueError, p.relative_to, P('//z/Share/Foo'), walk_up=True) -- self.assertRaises(ValueError, p.relative_to, P('//Server/z/Foo'), walk_up=True) -- -- def test_is_relative_to_common(self): -- P = self.cls -- p = P('a/b') -- self.assertRaises(TypeError, p.is_relative_to) -- self.assertRaises(TypeError, p.is_relative_to, b'a') -- self.assertTrue(p.is_relative_to(P(''))) -- self.assertTrue(p.is_relative_to('')) -- self.assertTrue(p.is_relative_to(P('a'))) -- self.assertTrue(p.is_relative_to('a/')) -- self.assertTrue(p.is_relative_to(P('a/b'))) -- self.assertTrue(p.is_relative_to('a/b')) -- # Unrelated paths. -- self.assertFalse(p.is_relative_to(P('c'))) -- self.assertFalse(p.is_relative_to(P('a/b/c'))) -- self.assertFalse(p.is_relative_to(P('a/c'))) -- self.assertFalse(p.is_relative_to(P('/a'))) -- p = P('/a/b') -- self.assertTrue(p.is_relative_to(P('/'))) -- self.assertTrue(p.is_relative_to('/')) -- self.assertTrue(p.is_relative_to(P('/a'))) -- self.assertTrue(p.is_relative_to('/a')) -- self.assertTrue(p.is_relative_to('/a/')) -- self.assertTrue(p.is_relative_to(P('/a/b'))) -- self.assertTrue(p.is_relative_to('/a/b')) -- # Unrelated paths. -- self.assertFalse(p.is_relative_to(P('/c'))) -- self.assertFalse(p.is_relative_to(P('/a/b/c'))) -- self.assertFalse(p.is_relative_to(P('/a/c'))) -- self.assertFalse(p.is_relative_to(P(''))) -- self.assertFalse(p.is_relative_to('')) -- self.assertFalse(p.is_relative_to(P('a'))) -- -- @needs_windows -- def test_is_relative_to_windows(self): -- P = self.cls -- p = P('C:Foo/Bar') -- self.assertTrue(p.is_relative_to(P('c:'))) -- self.assertTrue(p.is_relative_to('c:')) -- self.assertTrue(p.is_relative_to(P('c:foO'))) -- self.assertTrue(p.is_relative_to('c:foO')) -- self.assertTrue(p.is_relative_to('c:foO/')) -- self.assertTrue(p.is_relative_to(P('c:foO/baR'))) -- self.assertTrue(p.is_relative_to('c:foO/baR')) -- # Unrelated paths. -- self.assertFalse(p.is_relative_to(P())) -- self.assertFalse(p.is_relative_to('')) -- self.assertFalse(p.is_relative_to(P('d:'))) -- self.assertFalse(p.is_relative_to(P('/'))) -- self.assertFalse(p.is_relative_to(P('Foo'))) -- self.assertFalse(p.is_relative_to(P('/Foo'))) -- self.assertFalse(p.is_relative_to(P('C:/Foo'))) -- self.assertFalse(p.is_relative_to(P('C:Foo/Bar/Baz'))) -- self.assertFalse(p.is_relative_to(P('C:Foo/Baz'))) -- p = P('C:/Foo/Bar') -- self.assertTrue(p.is_relative_to(P('c:/'))) -- self.assertTrue(p.is_relative_to(P('c:/foO'))) -- self.assertTrue(p.is_relative_to('c:/foO/')) -- self.assertTrue(p.is_relative_to(P('c:/foO/baR'))) -- self.assertTrue(p.is_relative_to('c:/foO/baR')) -- # Unrelated paths. -- self.assertFalse(p.is_relative_to('c:')) -- self.assertFalse(p.is_relative_to(P('C:/Baz'))) -- self.assertFalse(p.is_relative_to(P('C:/Foo/Bar/Baz'))) -- self.assertFalse(p.is_relative_to(P('C:/Foo/Baz'))) -- self.assertFalse(p.is_relative_to(P('C:Foo'))) -- self.assertFalse(p.is_relative_to(P('d:'))) -- self.assertFalse(p.is_relative_to(P('d:/'))) -- self.assertFalse(p.is_relative_to(P('/'))) -- self.assertFalse(p.is_relative_to(P('/Foo'))) -- self.assertFalse(p.is_relative_to(P('//C/Foo'))) -- # UNC paths. -- p = P('//Server/Share/Foo/Bar') -- self.assertTrue(p.is_relative_to(P('//sErver/sHare'))) -- self.assertTrue(p.is_relative_to('//sErver/sHare')) -- self.assertTrue(p.is_relative_to('//sErver/sHare/')) -- self.assertTrue(p.is_relative_to(P('//sErver/sHare/Foo'))) -- self.assertTrue(p.is_relative_to('//sErver/sHare/Foo')) -- self.assertTrue(p.is_relative_to('//sErver/sHare/Foo/')) -- self.assertTrue(p.is_relative_to(P('//sErver/sHare/Foo/Bar'))) -- self.assertTrue(p.is_relative_to('//sErver/sHare/Foo/Bar')) -- # Unrelated paths. -- self.assertFalse(p.is_relative_to(P('/Server/Share/Foo'))) -- self.assertFalse(p.is_relative_to(P('c:/Server/Share/Foo'))) -- self.assertFalse(p.is_relative_to(P('//z/Share/Foo'))) -- self.assertFalse(p.is_relative_to(P('//Server/z/Foo'))) -- -- @needs_posix -- def test_is_absolute_posix(self): -- P = self.cls -- self.assertFalse(P('').is_absolute()) -- self.assertFalse(P('a').is_absolute()) -- self.assertFalse(P('a/b/').is_absolute()) -- self.assertTrue(P('/').is_absolute()) -- self.assertTrue(P('/a').is_absolute()) -- self.assertTrue(P('/a/b/').is_absolute()) -- self.assertTrue(P('//a').is_absolute()) -- self.assertTrue(P('//a/b').is_absolute()) -- -- @needs_windows -- def test_is_absolute_windows(self): -- P = self.cls -- # Under NT, only paths with both a drive and a root are absolute. -- self.assertFalse(P().is_absolute()) -- self.assertFalse(P('a').is_absolute()) -- self.assertFalse(P('a/b/').is_absolute()) -- self.assertFalse(P('/').is_absolute()) -- self.assertFalse(P('/a').is_absolute()) -- self.assertFalse(P('/a/b/').is_absolute()) -- self.assertFalse(P('c:').is_absolute()) -- self.assertFalse(P('c:a').is_absolute()) -- self.assertFalse(P('c:a/b/').is_absolute()) -- self.assertTrue(P('c:/').is_absolute()) -- self.assertTrue(P('c:/a').is_absolute()) -- self.assertTrue(P('c:/a/b/').is_absolute()) -- # UNC paths are absolute by definition. -- self.assertTrue(P('//').is_absolute()) -- self.assertTrue(P('//a').is_absolute()) -- self.assertTrue(P('//a/b').is_absolute()) -- self.assertTrue(P('//a/b/').is_absolute()) -- self.assertTrue(P('//a/b/c').is_absolute()) -- self.assertTrue(P('//a/b/c/d').is_absolute()) -- self.assertTrue(P('//?/UNC/').is_absolute()) -- self.assertTrue(P('//?/UNC/spam').is_absolute()) -- - - # - # Tests for the virtual classes. - # - --class PathBaseTest(PurePathBaseTest): -- cls = PathBase -- -- def test_not_implemented_error(self): -- p = self.cls('') -- e = NotImplementedError -- self.assertRaises(e, p.stat) -- self.assertRaises(e, p.exists) -- self.assertRaises(e, p.is_dir) -- self.assertRaises(e, p.is_file) -- self.assertRaises(e, p.is_symlink) -- self.assertRaises(e, p.open) -- self.assertRaises(e, p.read_bytes) -- self.assertRaises(e, p.read_text) -- self.assertRaises(e, p.write_bytes, b'foo') -- self.assertRaises(e, p.write_text, 'foo') -- self.assertRaises(e, p.iterdir) -- self.assertRaises(e, lambda: list(p.glob('*'))) -- self.assertRaises(e, lambda: list(p.rglob('*'))) -- self.assertRaises(e, lambda: list(p.walk())) -- self.assertRaises(e, p.readlink) -- self.assertRaises(e, p.symlink_to, 'foo') -- self.assertRaises(e, p.mkdir) -- -- def test_fspath_common(self): -- self.assertRaises(TypeError, os.fspath, self.cls('')) -- -- def test_as_bytes_common(self): -- self.assertRaises(TypeError, bytes, self.cls('')) -- -- --class DummyPathIO(io.BytesIO): -+ -+class DummyWritablePathIO(io.BytesIO): - """ -- Used by DummyPath to implement `open('w')` -+ Used by DummyWritablePath to implement `__open_wb__()` - """ - - def __init__(self, files, path): -@@ -1332,68 +849,56 @@ - super().close() - - --DummyPathStatResult = collections.namedtuple( -- 'DummyPathStatResult', -- 'st_mode st_ino st_dev st_nlink st_uid st_gid st_size st_atime st_mtime st_ctime') -+class DummyReadablePathInfo: -+ __slots__ = ('_is_dir', '_is_file') -+ -+ def __init__(self, is_dir, is_file): -+ self._is_dir = is_dir -+ self._is_file = is_file - -+ def exists(self, *, follow_symlinks=True): -+ return self._is_dir or self._is_file - --class DummyPath(PathBase): -+ def is_dir(self, *, follow_symlinks=True): -+ return self._is_dir -+ -+ def is_file(self, *, follow_symlinks=True): -+ return self._is_file -+ -+ def is_symlink(self): -+ return False -+ -+ -+class DummyReadablePath(ReadablePath, DummyJoinablePath): - """ -- Simple implementation of PathBase that keeps files and directories in -- memory. -+ Simple implementation of DummyReadablePath that keeps files and -+ directories in memory. - """ -- __slots__ = () -+ __slots__ = ('_info') - - _files = {} - _directories = {} - -- def __eq__(self, other): -- if not isinstance(other, DummyPath): -- return NotImplemented -- return str(self) == str(other) -- -- def __hash__(self): -- return hash(str(self)) -- -- def __repr__(self): -- return "{}({!r})".format(self.__class__.__name__, self.as_posix()) -+ def __init__(self, *segments): -+ super().__init__(*segments) -+ self._info = None - -- def stat(self, *, follow_symlinks=True): -- path = str(self).rstrip('/') -- if path in self._files: -- st_mode = stat.S_IFREG -- elif path in self._directories: -- st_mode = stat.S_IFDIR -- else: -- raise FileNotFoundError(errno.ENOENT, "Not found", str(self)) -- return DummyPathStatResult(st_mode, hash(str(self)), 0, 0, 0, 0, 0, 0, 0, 0) -+ @property -+ def info(self): -+ if self._info is None: -+ path_str = str(self) -+ self._info = DummyReadablePathInfo( -+ is_dir=path_str.rstrip('/') in self._directories, -+ is_file=path_str in self._files) -+ return self._info - -- def open(self, mode='r', buffering=-1, encoding=None, -- errors=None, newline=None): -- if buffering != -1 and not (buffering == 0 and 'b' in mode): -- raise NotImplementedError -+ def __open_rb__(self, buffering=-1): - path = str(self) - if path in self._directories: - raise IsADirectoryError(errno.EISDIR, "Is a directory", path) -- -- text = 'b' not in mode -- mode = ''.join(c for c in mode if c not in 'btU') -- if mode == 'r': -- if path not in self._files: -- raise FileNotFoundError(errno.ENOENT, "File not found", path) -- stream = io.BytesIO(self._files[path]) -- elif mode == 'w': -- parent, name = posixpath.split(path) -- if parent not in self._directories: -- raise FileNotFoundError(errno.ENOENT, "File not found", parent) -- stream = DummyPathIO(self._files, path) -- self._files[path] = b'' -- self._directories[parent].add(name) -- else: -- raise NotImplementedError -- if text: -- stream = io.TextIOWrapper(stream, encoding=encoding, errors=errors, newline=newline) -- return stream -+ elif path not in self._files: -+ raise FileNotFoundError(errno.ENOENT, "File not found", path) -+ return io.BytesIO(self._files[path]) - - def iterdir(self): - path = str(self).rstrip('/') -@@ -1404,6 +909,21 @@ - else: - raise FileNotFoundError(errno.ENOENT, "File not found", path) - -+ -+class DummyWritablePath(WritablePath, DummyJoinablePath): -+ __slots__ = () -+ -+ def __open_wb__(self, buffering=-1): -+ path = str(self) -+ if path in self._directories: -+ raise IsADirectoryError(errno.EISDIR, "Is a directory", path) -+ parent, name = posixpath.split(path) -+ if parent not in self._directories: -+ raise FileNotFoundError(errno.ENOENT, "File not found", parent) -+ self._files[path] = b'' -+ self._directories[parent].add(name) -+ return DummyWritablePathIO(self._files, path) -+ - def mkdir(self, mode=0o777, parents=False, exist_ok=False): - path = str(self) - parent = str(self.parent) -@@ -1422,24 +942,11 @@ - self.parent.mkdir(parents=True, exist_ok=True) - self.mkdir(mode, parents=False, exist_ok=exist_ok) - -- def _delete(self): -- path = str(self) -- if path in self._files: -- del self._files[path] -- elif path in self._directories: -- for name in list(self._directories[path]): -- self.joinpath(name)._delete() -- del self._directories[path] -- else: -- raise FileNotFoundError(errno.ENOENT, "File not found", path) -- parent = str(self.parent) -- self._directories[parent].remove(self.name) -- - --class DummyPathTest(DummyPurePathTest): -- """Tests for PathBase methods that use stat(), open() and iterdir().""" -+class DummyReadablePathTest(DummyJoinablePathTest): -+ """Tests for ReadablePathTest methods that use stat(), open() and iterdir().""" - -- cls = DummyPath -+ cls = DummyReadablePath - can_symlink = False - - # (self.base) -@@ -1464,33 +971,25 @@ - - def setUp(self): - super().setUp() -- parser = self.cls.parser -- p = self.cls(self.base) -- p.mkdir(parents=True) -- p.joinpath('dirA').mkdir() -- p.joinpath('dirB').mkdir() -- p.joinpath('dirC').mkdir() -- p.joinpath('dirC', 'dirD').mkdir() -- p.joinpath('dirE').mkdir() -- with p.joinpath('fileA').open('wb') as f: -- f.write(b"this is file A\n") -- with p.joinpath('dirB', 'fileB').open('wb') as f: -- f.write(b"this is file B\n") -- with p.joinpath('dirC', 'fileC').open('wb') as f: -- f.write(b"this is file C\n") -- with p.joinpath('dirC', 'novel.txt').open('wb') as f: -- f.write(b"this is a novel\n") -- with p.joinpath('dirC', 'dirD', 'fileD').open('wb') as f: -- f.write(b"this is file D\n") -- if self.can_symlink: -- p.joinpath('linkA').symlink_to('fileA') -- p.joinpath('brokenLink').symlink_to('non-existing') -- p.joinpath('linkB').symlink_to('dirB', target_is_directory=True) -- p.joinpath('dirA', 'linkC').symlink_to( -- parser.join('..', 'dirB'), target_is_directory=True) -- p.joinpath('dirB', 'linkD').symlink_to( -- parser.join('..', 'dirB'), target_is_directory=True) -- p.joinpath('brokenLinkLoop').symlink_to('brokenLinkLoop') -+ self.createTestHierarchy() -+ -+ def createTestHierarchy(self): -+ cls = self.cls -+ cls._files = { -+ f'{self.base}/fileA': b'this is file A\n', -+ f'{self.base}/dirB/fileB': b'this is file B\n', -+ f'{self.base}/dirC/fileC': b'this is file C\n', -+ f'{self.base}/dirC/dirD/fileD': b'this is file D\n', -+ f'{self.base}/dirC/novel.txt': b'this is a novel\n', -+ } -+ cls._directories = { -+ f'{self.base}': {'fileA', 'dirA', 'dirB', 'dirC', 'dirE'}, -+ f'{self.base}/dirA': set(), -+ f'{self.base}/dirB': {'fileB'}, -+ f'{self.base}/dirC': {'fileC', 'dirD', 'novel.txt'}, -+ f'{self.base}/dirC/dirD': {'fileD'}, -+ f'{self.base}/dirE': set(), -+ } - - def tearDown(self): - cls = self.cls -@@ -1530,398 +1029,103 @@ - self.assertIs(False, P(self.base + '\udfff').exists()) - self.assertIs(False, P(self.base + '\x00').exists()) - -- def test_open_common(self): -+ def test_magic_open(self): - p = self.cls(self.base) -- with (p / 'fileA').open('r') as f: -+ with magic_open(p / 'fileA', 'r') as f: - self.assertIsInstance(f, io.TextIOBase) - self.assertEqual(f.read(), "this is file A\n") -- with (p / 'fileA').open('rb') as f: -+ with magic_open(p / 'fileA', 'rb') as f: - self.assertIsInstance(f, io.BufferedIOBase) - self.assertEqual(f.read().strip(), b"this is file A") - -- def test_read_write_bytes(self): -- p = self.cls(self.base) -- (p / 'fileA').write_bytes(b'abcdefg') -- self.assertEqual((p / 'fileA').read_bytes(), b'abcdefg') -- # Check that trying to write str does not truncate the file. -- self.assertRaises(TypeError, (p / 'fileA').write_bytes, 'somestr') -- self.assertEqual((p / 'fileA').read_bytes(), b'abcdefg') -+ def test_iterdir(self): -+ P = self.cls -+ p = P(self.base) -+ it = p.iterdir() -+ paths = set(it) -+ expected = ['dirA', 'dirB', 'dirC', 'dirE', 'fileA'] -+ if self.can_symlink: -+ expected += ['linkA', 'linkB', 'brokenLink', 'brokenLinkLoop'] -+ self.assertEqual(paths, { P(self.base, q) for q in expected }) - -- def test_read_write_text(self): -- p = self.cls(self.base) -- (p / 'fileA').write_text('äbcdefg', encoding='latin-1') -- self.assertEqual((p / 'fileA').read_text( -- encoding='utf-8', errors='ignore'), 'bcdefg') -- # Check that trying to write bytes does not truncate the file. -- self.assertRaises(TypeError, (p / 'fileA').write_text, b'somebytes') -- self.assertEqual((p / 'fileA').read_text(encoding='latin-1'), 'äbcdefg') -+ def test_iterdir_nodir(self): -+ # __iter__ on something that is not a directory. -+ p = self.cls(self.base, 'fileA') -+ with self.assertRaises(OSError) as cm: -+ p.iterdir() -+ # ENOENT or EINVAL under Windows, ENOTDIR otherwise -+ # (see issue #12802). -+ self.assertIn(cm.exception.errno, (errno.ENOTDIR, -+ errno.ENOENT, errno.EINVAL)) - -- def test_read_text_with_newlines(self): -+ def test_iterdir_info(self): - p = self.cls(self.base) -- # Check that `\n` character change nothing -- (p / 'fileA').write_bytes(b'abcde\r\nfghlk\n\rmnopq') -- self.assertEqual((p / 'fileA').read_text(newline='\n'), -- 'abcde\r\nfghlk\n\rmnopq') -- # Check that `\r` character replaces `\n` -- (p / 'fileA').write_bytes(b'abcde\r\nfghlk\n\rmnopq') -- self.assertEqual((p / 'fileA').read_text(newline='\r'), -- 'abcde\r\nfghlk\n\rmnopq') -- # Check that `\r\n` character replaces `\n` -- (p / 'fileA').write_bytes(b'abcde\r\nfghlk\n\rmnopq') -- self.assertEqual((p / 'fileA').read_text(newline='\r\n'), -- 'abcde\r\nfghlk\n\rmnopq') -+ for child in p.iterdir(): -+ info = child.info -+ self.assertIsInstance(info, PathInfo) -+ self.assertEqual(info.exists(), child.exists()) -+ self.assertEqual(info.is_dir(), child.is_dir()) -+ self.assertEqual(info.is_file(), child.is_file()) -+ self.assertEqual(info.is_symlink(), child.is_symlink()) -+ self.assertTrue(info.exists(follow_symlinks=False)) -+ self.assertEqual(info.is_dir(follow_symlinks=False), -+ child.is_dir(follow_symlinks=False)) -+ self.assertEqual(info.is_file(follow_symlinks=False), -+ child.is_file(follow_symlinks=False)) - -- def test_write_text_with_newlines(self): -- p = self.cls(self.base) -- # Check that `\n` character change nothing -- (p / 'fileA').write_text('abcde\r\nfghlk\n\rmnopq', newline='\n') -- self.assertEqual((p / 'fileA').read_bytes(), -- b'abcde\r\nfghlk\n\rmnopq') -- # Check that `\r` character replaces `\n` -- (p / 'fileA').write_text('abcde\r\nfghlk\n\rmnopq', newline='\r') -- self.assertEqual((p / 'fileA').read_bytes(), -- b'abcde\r\rfghlk\r\rmnopq') -- # Check that `\r\n` character replaces `\n` -- (p / 'fileA').write_text('abcde\r\nfghlk\n\rmnopq', newline='\r\n') -- self.assertEqual((p / 'fileA').read_bytes(), -- b'abcde\r\r\nfghlk\r\n\rmnopq') -- # Check that no argument passed will change `\n` to `os.linesep` -- os_linesep_byte = bytes(os.linesep, encoding='ascii') -- (p / 'fileA').write_text('abcde\nfghlk\n\rmnopq') -- self.assertEqual((p / 'fileA').read_bytes(), -- b'abcde' + os_linesep_byte + b'fghlk' + os_linesep_byte + b'\rmnopq') -+ def test_glob_common(self): -+ def _check(glob, expected): -+ self.assertEqual(set(glob), { P(self.base, q) for q in expected }) -+ P = self.cls -+ p = P(self.base) -+ it = p.glob("fileA") -+ self.assertIsInstance(it, collections.abc.Iterator) -+ _check(it, ["fileA"]) -+ _check(p.glob("fileB"), []) -+ _check(p.glob("dir*/file*"), ["dirB/fileB", "dirC/fileC"]) -+ if not self.can_symlink: -+ _check(p.glob("*A"), ['dirA', 'fileA']) -+ else: -+ _check(p.glob("*A"), ['dirA', 'fileA', 'linkA']) -+ if not self.can_symlink: -+ _check(p.glob("*B/*"), ['dirB/fileB']) -+ else: -+ _check(p.glob("*B/*"), ['dirB/fileB', 'dirB/linkD', -+ 'linkB/fileB', 'linkB/linkD']) -+ if not self.can_symlink: -+ _check(p.glob("*/fileB"), ['dirB/fileB']) -+ else: -+ _check(p.glob("*/fileB"), ['dirB/fileB', 'linkB/fileB']) -+ if self.can_symlink: -+ _check(p.glob("brokenLink"), ['brokenLink']) - -- def test_copy_file(self): -- base = self.cls(self.base) -- source = base / 'fileA' -- target = base / 'copyA' -- result = source.copy(target) -- self.assertEqual(result, target) -- self.assertTrue(target.exists()) -- self.assertEqual(source.read_text(), target.read_text()) -+ if not self.can_symlink: -+ _check(p.glob("*/"), ["dirA/", "dirB/", "dirC/", "dirE/"]) -+ else: -+ _check(p.glob("*/"), ["dirA/", "dirB/", "dirC/", "dirE/", "linkB/"]) - -- def test_copy_file_to_existing_file(self): -- base = self.cls(self.base) -- source = base / 'fileA' -- target = base / 'dirB' / 'fileB' -- result = source.copy(target) -- self.assertEqual(result, target) -- self.assertTrue(target.exists()) -- self.assertEqual(source.read_text(), target.read_text()) -+ @needs_posix -+ def test_glob_posix(self): -+ P = self.cls -+ p = P(self.base) -+ q = p / "FILEa" -+ given = set(p.glob("FILEa")) -+ expect = {q} if q.exists() else set() -+ self.assertEqual(given, expect) -+ self.assertEqual(set(p.glob("FILEa*")), set()) - -- def test_copy_file_to_existing_directory(self): -- base = self.cls(self.base) -- source = base / 'fileA' -- target = base / 'dirA' -- self.assertRaises(OSError, source.copy, target) -+ @needs_windows -+ def test_glob_windows(self): -+ P = self.cls -+ p = P(self.base) -+ self.assertEqual(set(p.glob("FILEa")), { P(self.base, "fileA") }) -+ self.assertEqual(set(p.glob("*a\\")), { P(self.base, "dirA/") }) -+ self.assertEqual(set(p.glob("F*a")), { P(self.base, "fileA") }) - -- def test_copy_file_empty(self): -- base = self.cls(self.base) -- source = base / 'empty' -- target = base / 'copyA' -- source.write_bytes(b'') -- result = source.copy(target) -- self.assertEqual(result, target) -- self.assertTrue(target.exists()) -- self.assertEqual(target.read_bytes(), b'') -- -- def test_copy_file_to_itself(self): -- base = self.cls(self.base) -- source = base / 'empty' -- source.write_bytes(b'') -- self.assertRaises(OSError, source.copy, source) -- self.assertRaises(OSError, source.copy, source, follow_symlinks=False) -- -- def test_copy_dir_simple(self): -- base = self.cls(self.base) -- source = base / 'dirC' -- target = base / 'copyC' -- result = source.copy(target) -- self.assertEqual(result, target) -- self.assertTrue(target.is_dir()) -- self.assertTrue(target.joinpath('dirD').is_dir()) -- self.assertTrue(target.joinpath('dirD', 'fileD').is_file()) -- self.assertEqual(target.joinpath('dirD', 'fileD').read_text(), -- "this is file D\n") -- self.assertTrue(target.joinpath('fileC').is_file()) -- self.assertTrue(target.joinpath('fileC').read_text(), -- "this is file C\n") -- -- def test_copy_dir_complex(self, follow_symlinks=True): -- def ordered_walk(path): -- for dirpath, dirnames, filenames in path.walk(follow_symlinks=follow_symlinks): -- dirnames.sort() -- filenames.sort() -- yield dirpath, dirnames, filenames -- base = self.cls(self.base) -- source = base / 'dirC' -- -- if self.can_symlink: -- # Add some symlinks -- source.joinpath('linkC').symlink_to('fileC') -- source.joinpath('linkD').symlink_to('dirD', target_is_directory=True) -- -- # Perform the copy -- target = base / 'copyC' -- result = source.copy(target, follow_symlinks=follow_symlinks) -- self.assertEqual(result, target) -- -- # Compare the source and target trees -- source_walk = ordered_walk(source) -- target_walk = ordered_walk(target) -- for source_item, target_item in zip(source_walk, target_walk, strict=True): -- self.assertEqual(source_item[0].relative_to(source), -- target_item[0].relative_to(target)) # dirpath -- self.assertEqual(source_item[1], target_item[1]) # dirnames -- self.assertEqual(source_item[2], target_item[2]) # filenames -- # Compare files and symlinks -- for filename in source_item[2]: -- source_file = source_item[0].joinpath(filename) -- target_file = target_item[0].joinpath(filename) -- if follow_symlinks or not source_file.is_symlink(): -- # Regular file. -- self.assertEqual(source_file.read_bytes(), target_file.read_bytes()) -- elif source_file.is_dir(): -- # Symlink to directory. -- self.assertTrue(target_file.is_dir()) -- self.assertEqual(source_file.readlink(), target_file.readlink()) -- else: -- # Symlink to file. -- self.assertEqual(source_file.read_bytes(), target_file.read_bytes()) -- self.assertEqual(source_file.readlink(), target_file.readlink()) -- -- def test_copy_dir_complex_follow_symlinks_false(self): -- self.test_copy_dir_complex(follow_symlinks=False) -- -- def test_copy_dir_to_existing_directory(self): -- base = self.cls(self.base) -- source = base / 'dirC' -- target = base / 'copyC' -- target.mkdir() -- target.joinpath('dirD').mkdir() -- self.assertRaises(FileExistsError, source.copy, target) -- -- def test_copy_dir_to_existing_directory_dirs_exist_ok(self): -- base = self.cls(self.base) -- source = base / 'dirC' -- target = base / 'copyC' -- target.mkdir() -- target.joinpath('dirD').mkdir() -- result = source.copy(target, dirs_exist_ok=True) -- self.assertEqual(result, target) -- self.assertTrue(target.is_dir()) -- self.assertTrue(target.joinpath('dirD').is_dir()) -- self.assertTrue(target.joinpath('dirD', 'fileD').is_file()) -- self.assertEqual(target.joinpath('dirD', 'fileD').read_text(), -- "this is file D\n") -- self.assertTrue(target.joinpath('fileC').is_file()) -- self.assertTrue(target.joinpath('fileC').read_text(), -- "this is file C\n") -- -- def test_copy_dir_to_itself(self): -- base = self.cls(self.base) -- source = base / 'dirC' -- self.assertRaises(OSError, source.copy, source) -- self.assertRaises(OSError, source.copy, source, follow_symlinks=False) -- -- def test_copy_dir_into_itself(self): -- base = self.cls(self.base) -- source = base / 'dirC' -- target = base / 'dirC' / 'dirD' / 'copyC' -- self.assertRaises(OSError, source.copy, target) -- self.assertRaises(OSError, source.copy, target, follow_symlinks=False) -- self.assertFalse(target.exists()) -- -- def test_copy_into(self): -- base = self.cls(self.base) -- source = base / 'fileA' -- target_dir = base / 'dirA' -- result = source.copy_into(target_dir) -- self.assertEqual(result, target_dir / 'fileA') -- self.assertTrue(result.exists()) -- self.assertEqual(source.read_text(), result.read_text()) -- -- def test_copy_into_empty_name(self): -- source = self.cls('') -- target_dir = self.base -- self.assertRaises(ValueError, source.copy_into, target_dir) -- -- def test_move_file(self): -- base = self.cls(self.base) -- source = base / 'fileA' -- source_text = source.read_text() -- target = base / 'fileA_moved' -- result = source.move(target) -- self.assertEqual(result, target) -- self.assertFalse(source.exists()) -- self.assertTrue(target.exists()) -- self.assertEqual(source_text, target.read_text()) -- -- def test_move_file_to_file(self): -- base = self.cls(self.base) -- source = base / 'fileA' -- source_text = source.read_text() -- target = base / 'dirB' / 'fileB' -- result = source.move(target) -- self.assertEqual(result, target) -- self.assertFalse(source.exists()) -- self.assertTrue(target.exists()) -- self.assertEqual(source_text, target.read_text()) -- -- def test_move_file_to_dir(self): -- base = self.cls(self.base) -- source = base / 'fileA' -- target = base / 'dirB' -- self.assertRaises(OSError, source.move, target) -- -- def test_move_file_to_itself(self): -- base = self.cls(self.base) -- source = base / 'fileA' -- self.assertRaises(OSError, source.move, source) -- -- def test_move_dir(self): -- base = self.cls(self.base) -- source = base / 'dirC' -- target = base / 'dirC_moved' -- result = source.move(target) -- self.assertEqual(result, target) -- self.assertFalse(source.exists()) -- self.assertTrue(target.is_dir()) -- self.assertTrue(target.joinpath('dirD').is_dir()) -- self.assertTrue(target.joinpath('dirD', 'fileD').is_file()) -- self.assertEqual(target.joinpath('dirD', 'fileD').read_text(), -- "this is file D\n") -- self.assertTrue(target.joinpath('fileC').is_file()) -- self.assertTrue(target.joinpath('fileC').read_text(), -- "this is file C\n") -- -- def test_move_dir_to_dir(self): -- base = self.cls(self.base) -- source = base / 'dirC' -- target = base / 'dirB' -- self.assertRaises(OSError, source.move, target) -- self.assertTrue(source.exists()) -- self.assertTrue(target.exists()) -- -- def test_move_dir_to_itself(self): -- base = self.cls(self.base) -- source = base / 'dirC' -- self.assertRaises(OSError, source.move, source) -- self.assertTrue(source.exists()) -- -- def test_move_dir_into_itself(self): -- base = self.cls(self.base) -- source = base / 'dirC' -- target = base / 'dirC' / 'bar' -- self.assertRaises(OSError, source.move, target) -- self.assertTrue(source.exists()) -- self.assertFalse(target.exists()) -- -- def test_move_into(self): -- base = self.cls(self.base) -- source = base / 'fileA' -- source_text = source.read_text() -- target_dir = base / 'dirA' -- result = source.move_into(target_dir) -- self.assertEqual(result, target_dir / 'fileA') -- self.assertFalse(source.exists()) -- self.assertTrue(result.exists()) -- self.assertEqual(source_text, result.read_text()) -- -- def test_move_into_empty_name(self): -- source = self.cls('') -- target_dir = self.base -- self.assertRaises(ValueError, source.move_into, target_dir) -- -- def test_iterdir(self): -- P = self.cls -- p = P(self.base) -- it = p.iterdir() -- paths = set(it) -- expected = ['dirA', 'dirB', 'dirC', 'dirE', 'fileA'] -- if self.can_symlink: -- expected += ['linkA', 'linkB', 'brokenLink', 'brokenLinkLoop'] -- self.assertEqual(paths, { P(self.base, q) for q in expected }) -- -- def test_iterdir_nodir(self): -- # __iter__ on something that is not a directory. -- p = self.cls(self.base, 'fileA') -- with self.assertRaises(OSError) as cm: -- p.iterdir() -- # ENOENT or EINVAL under Windows, ENOTDIR otherwise -- # (see issue #12802). -- self.assertIn(cm.exception.errno, (errno.ENOTDIR, -- errno.ENOENT, errno.EINVAL)) -- -- def test_scandir(self): -- p = self.cls(self.base) -- with p._scandir() as entries: -- self.assertTrue(list(entries)) -- with p._scandir() as entries: -- for entry in entries: -- child = p / entry.name -- self.assertIsNotNone(entry) -- self.assertEqual(entry.name, child.name) -- self.assertEqual(entry.is_symlink(), -- child.is_symlink()) -- self.assertEqual(entry.is_dir(follow_symlinks=False), -- child.is_dir(follow_symlinks=False)) -- if entry.name != 'brokenLinkLoop': -- self.assertEqual(entry.is_dir(), child.is_dir()) -- -- def test_glob_common(self): -- def _check(glob, expected): -- self.assertEqual(set(glob), { P(self.base, q) for q in expected }) -- P = self.cls -- p = P(self.base) -- it = p.glob("fileA") -- self.assertIsInstance(it, collections.abc.Iterator) -- _check(it, ["fileA"]) -- _check(p.glob("fileB"), []) -- _check(p.glob("dir*/file*"), ["dirB/fileB", "dirC/fileC"]) -- if not self.can_symlink: -- _check(p.glob("*A"), ['dirA', 'fileA']) -- else: -- _check(p.glob("*A"), ['dirA', 'fileA', 'linkA']) -- if not self.can_symlink: -- _check(p.glob("*B/*"), ['dirB/fileB']) -- else: -- _check(p.glob("*B/*"), ['dirB/fileB', 'dirB/linkD', -- 'linkB/fileB', 'linkB/linkD']) -- if not self.can_symlink: -- _check(p.glob("*/fileB"), ['dirB/fileB']) -- else: -- _check(p.glob("*/fileB"), ['dirB/fileB', 'linkB/fileB']) -- if self.can_symlink: -- _check(p.glob("brokenLink"), ['brokenLink']) -- -- if not self.can_symlink: -- _check(p.glob("*/"), ["dirA/", "dirB/", "dirC/", "dirE/"]) -- else: -- _check(p.glob("*/"), ["dirA/", "dirB/", "dirC/", "dirE/", "linkB/"]) -- -- @needs_posix -- def test_glob_posix(self): -- P = self.cls -- p = P(self.base) -- q = p / "FILEa" -- given = set(p.glob("FILEa")) -- expect = {q} if q.exists() else set() -- self.assertEqual(given, expect) -- self.assertEqual(set(p.glob("FILEa*")), set()) -- -- @needs_windows -- def test_glob_windows(self): -- P = self.cls -- p = P(self.base) -- self.assertEqual(set(p.glob("FILEa")), { P(self.base, "fileA") }) -- self.assertEqual(set(p.glob("*a\\")), { P(self.base, "dirA/") }) -- self.assertEqual(set(p.glob("F*a")), { P(self.base, "fileA") }) -- -- def test_glob_empty_pattern(self): -- P = self.cls -- p = P(self.base) -- self.assertEqual(list(p.glob("")), [p]) -+ def test_glob_empty_pattern(self): -+ P = self.cls -+ p = P(self.base) -+ self.assertEqual(list(p.glob("")), [p.joinpath("")]) - - def test_glob_case_sensitive(self): - P = self.cls -@@ -1993,30 +1197,117 @@ - self.assertEqual(set(p.rglob("FILEd")), { P(self.base, "dirC/dirD/fileD") }) - self.assertEqual(set(p.rglob("*\\")), { P(self.base, "dirC/dirD/") }) - -- def test_stat(self): -- statA = self.cls(self.base).joinpath('fileA').stat() -- statB = self.cls(self.base).joinpath('dirB', 'fileB').stat() -- statC = self.cls(self.base).joinpath('dirC').stat() -- # st_mode: files are the same, directory differs. -- self.assertIsInstance(statA.st_mode, int) -- self.assertEqual(statA.st_mode, statB.st_mode) -- self.assertNotEqual(statA.st_mode, statC.st_mode) -- self.assertNotEqual(statB.st_mode, statC.st_mode) -- # st_ino: all different, -- self.assertIsInstance(statA.st_ino, int) -- self.assertNotEqual(statA.st_ino, statB.st_ino) -- self.assertNotEqual(statA.st_ino, statC.st_ino) -- self.assertNotEqual(statB.st_ino, statC.st_ino) -- # st_dev: all the same. -- self.assertIsInstance(statA.st_dev, int) -- self.assertEqual(statA.st_dev, statB.st_dev) -- self.assertEqual(statA.st_dev, statC.st_dev) -- # other attributes not used by pathlib. -- -- def test_stat_no_follow_symlinks_nosymlink(self): -- p = self.cls(self.base) / 'fileA' -- st = p.stat() -- self.assertEqual(st, p.stat(follow_symlinks=False)) -+ def test_info_exists(self): -+ p = self.cls(self.base) -+ self.assertTrue(p.info.exists()) -+ self.assertTrue((p / 'dirA').info.exists()) -+ self.assertTrue((p / 'dirA').info.exists(follow_symlinks=False)) -+ self.assertTrue((p / 'fileA').info.exists()) -+ self.assertTrue((p / 'fileA').info.exists(follow_symlinks=False)) -+ self.assertFalse((p / 'non-existing').info.exists()) -+ self.assertFalse((p / 'non-existing').info.exists(follow_symlinks=False)) -+ if self.can_symlink: -+ self.assertTrue((p / 'linkA').info.exists()) -+ self.assertTrue((p / 'linkA').info.exists(follow_symlinks=False)) -+ self.assertTrue((p / 'linkB').info.exists()) -+ self.assertTrue((p / 'linkB').info.exists(follow_symlinks=True)) -+ self.assertFalse((p / 'brokenLink').info.exists()) -+ self.assertTrue((p / 'brokenLink').info.exists(follow_symlinks=False)) -+ self.assertFalse((p / 'brokenLinkLoop').info.exists()) -+ self.assertTrue((p / 'brokenLinkLoop').info.exists(follow_symlinks=False)) -+ self.assertFalse((p / 'fileA\udfff').info.exists()) -+ self.assertFalse((p / 'fileA\udfff').info.exists(follow_symlinks=False)) -+ self.assertFalse((p / 'fileA\x00').info.exists()) -+ self.assertFalse((p / 'fileA\x00').info.exists(follow_symlinks=False)) -+ -+ def test_info_exists_caching(self): -+ p = self.cls(self.base) -+ q = p / 'myfile' -+ self.assertFalse(q.info.exists()) -+ self.assertFalse(q.info.exists(follow_symlinks=False)) -+ if isinstance(self.cls, WritablePath): -+ q.write_text('hullo') -+ self.assertFalse(q.info.exists()) -+ self.assertFalse(q.info.exists(follow_symlinks=False)) -+ -+ def test_info_is_dir(self): -+ p = self.cls(self.base) -+ self.assertTrue((p / 'dirA').info.is_dir()) -+ self.assertTrue((p / 'dirA').info.is_dir(follow_symlinks=False)) -+ self.assertFalse((p / 'fileA').info.is_dir()) -+ self.assertFalse((p / 'fileA').info.is_dir(follow_symlinks=False)) -+ self.assertFalse((p / 'non-existing').info.is_dir()) -+ self.assertFalse((p / 'non-existing').info.is_dir(follow_symlinks=False)) -+ if self.can_symlink: -+ self.assertFalse((p / 'linkA').info.is_dir()) -+ self.assertFalse((p / 'linkA').info.is_dir(follow_symlinks=False)) -+ self.assertTrue((p / 'linkB').info.is_dir()) -+ self.assertFalse((p / 'linkB').info.is_dir(follow_symlinks=False)) -+ self.assertFalse((p / 'brokenLink').info.is_dir()) -+ self.assertFalse((p / 'brokenLink').info.is_dir(follow_symlinks=False)) -+ self.assertFalse((p / 'brokenLinkLoop').info.is_dir()) -+ self.assertFalse((p / 'brokenLinkLoop').info.is_dir(follow_symlinks=False)) -+ self.assertFalse((p / 'dirA\udfff').info.is_dir()) -+ self.assertFalse((p / 'dirA\udfff').info.is_dir(follow_symlinks=False)) -+ self.assertFalse((p / 'dirA\x00').info.is_dir()) -+ self.assertFalse((p / 'dirA\x00').info.is_dir(follow_symlinks=False)) -+ -+ def test_info_is_dir_caching(self): -+ p = self.cls(self.base) -+ q = p / 'mydir' -+ self.assertFalse(q.info.is_dir()) -+ self.assertFalse(q.info.is_dir(follow_symlinks=False)) -+ if isinstance(self.cls, WritablePath): -+ q.mkdir() -+ self.assertFalse(q.info.is_dir()) -+ self.assertFalse(q.info.is_dir(follow_symlinks=False)) -+ -+ def test_info_is_file(self): -+ p = self.cls(self.base) -+ self.assertTrue((p / 'fileA').info.is_file()) -+ self.assertTrue((p / 'fileA').info.is_file(follow_symlinks=False)) -+ self.assertFalse((p / 'dirA').info.is_file()) -+ self.assertFalse((p / 'dirA').info.is_file(follow_symlinks=False)) -+ self.assertFalse((p / 'non-existing').info.is_file()) -+ self.assertFalse((p / 'non-existing').info.is_file(follow_symlinks=False)) -+ if self.can_symlink: -+ self.assertTrue((p / 'linkA').info.is_file()) -+ self.assertFalse((p / 'linkA').info.is_file(follow_symlinks=False)) -+ self.assertFalse((p / 'linkB').info.is_file()) -+ self.assertFalse((p / 'linkB').info.is_file(follow_symlinks=False)) -+ self.assertFalse((p / 'brokenLink').info.is_file()) -+ self.assertFalse((p / 'brokenLink').info.is_file(follow_symlinks=False)) -+ self.assertFalse((p / 'brokenLinkLoop').info.is_file()) -+ self.assertFalse((p / 'brokenLinkLoop').info.is_file(follow_symlinks=False)) -+ self.assertFalse((p / 'fileA\udfff').info.is_file()) -+ self.assertFalse((p / 'fileA\udfff').info.is_file(follow_symlinks=False)) -+ self.assertFalse((p / 'fileA\x00').info.is_file()) -+ self.assertFalse((p / 'fileA\x00').info.is_file(follow_symlinks=False)) -+ -+ def test_info_is_file_caching(self): -+ p = self.cls(self.base) -+ q = p / 'myfile' -+ self.assertFalse(q.info.is_file()) -+ self.assertFalse(q.info.is_file(follow_symlinks=False)) -+ if isinstance(self.cls, WritablePath): -+ q.write_text('hullo') -+ self.assertFalse(q.info.is_file()) -+ self.assertFalse(q.info.is_file(follow_symlinks=False)) -+ -+ def test_info_is_symlink(self): -+ p = self.cls(self.base) -+ self.assertFalse((p / 'fileA').info.is_symlink()) -+ self.assertFalse((p / 'dirA').info.is_symlink()) -+ self.assertFalse((p / 'non-existing').info.is_symlink()) -+ if self.can_symlink: -+ self.assertTrue((p / 'linkA').info.is_symlink()) -+ self.assertTrue((p / 'linkB').info.is_symlink()) -+ self.assertTrue((p / 'brokenLink').info.is_symlink()) -+ self.assertFalse((p / 'linkA\udfff').info.is_symlink()) -+ self.assertFalse((p / 'linkA\x00').info.is_symlink()) -+ self.assertTrue((p / 'brokenLinkLoop').info.is_symlink()) -+ self.assertFalse((p / 'fileA\udfff').info.is_symlink()) -+ self.assertFalse((p / 'fileA\x00').info.is_symlink()) - - def test_is_dir(self): - P = self.cls(self.base) -@@ -2086,90 +1377,262 @@ - self.assertIs((P / 'linkA\udfff').is_file(), False) - self.assertIs((P / 'linkA\x00').is_file(), False) - -- def test_delete_file(self): -- p = self.cls(self.base) / 'fileA' -- p._delete() -- self.assertFileNotFound(p.stat) -- self.assertFileNotFound(p._delete) - -- def test_delete_dir(self): -+class DummyWritablePathTest(DummyJoinablePathTest): -+ cls = DummyWritablePath -+ -+ -+class DummyRWPath(DummyWritablePath, DummyReadablePath): -+ __slots__ = () -+ -+ -+class DummyRWPathTest(DummyWritablePathTest, DummyReadablePathTest): -+ cls = DummyRWPath -+ can_symlink = False -+ -+ def test_read_write_bytes(self): -+ p = self.cls(self.base) -+ (p / 'fileA').write_bytes(b'abcdefg') -+ self.assertEqual((p / 'fileA').read_bytes(), b'abcdefg') -+ # Check that trying to write str does not truncate the file. -+ self.assertRaises(TypeError, (p / 'fileA').write_bytes, 'somestr') -+ self.assertEqual((p / 'fileA').read_bytes(), b'abcdefg') -+ -+ def test_read_write_text(self): -+ p = self.cls(self.base) -+ (p / 'fileA').write_text('äbcdefg', encoding='latin-1') -+ self.assertEqual((p / 'fileA').read_text( -+ encoding='utf-8', errors='ignore'), 'bcdefg') -+ # Check that trying to write bytes does not truncate the file. -+ self.assertRaises(TypeError, (p / 'fileA').write_text, b'somebytes') -+ self.assertEqual((p / 'fileA').read_text(encoding='latin-1'), 'äbcdefg') -+ -+ def test_read_text_with_newlines(self): -+ p = self.cls(self.base) -+ # Check that `\n` character change nothing -+ (p / 'fileA').write_bytes(b'abcde\r\nfghlk\n\rmnopq') -+ self.assertEqual((p / 'fileA').read_text(newline='\n'), -+ 'abcde\r\nfghlk\n\rmnopq') -+ # Check that `\r` character replaces `\n` -+ (p / 'fileA').write_bytes(b'abcde\r\nfghlk\n\rmnopq') -+ self.assertEqual((p / 'fileA').read_text(newline='\r'), -+ 'abcde\r\nfghlk\n\rmnopq') -+ # Check that `\r\n` character replaces `\n` -+ (p / 'fileA').write_bytes(b'abcde\r\nfghlk\n\rmnopq') -+ self.assertEqual((p / 'fileA').read_text(newline='\r\n'), -+ 'abcde\r\nfghlk\n\rmnopq') -+ -+ def test_write_text_with_newlines(self): -+ p = self.cls(self.base) -+ # Check that `\n` character change nothing -+ (p / 'fileA').write_text('abcde\r\nfghlk\n\rmnopq', newline='\n') -+ self.assertEqual((p / 'fileA').read_bytes(), -+ b'abcde\r\nfghlk\n\rmnopq') -+ # Check that `\r` character replaces `\n` -+ (p / 'fileA').write_text('abcde\r\nfghlk\n\rmnopq', newline='\r') -+ self.assertEqual((p / 'fileA').read_bytes(), -+ b'abcde\r\rfghlk\r\rmnopq') -+ # Check that `\r\n` character replaces `\n` -+ (p / 'fileA').write_text('abcde\r\nfghlk\n\rmnopq', newline='\r\n') -+ self.assertEqual((p / 'fileA').read_bytes(), -+ b'abcde\r\r\nfghlk\r\n\rmnopq') -+ # Check that no argument passed will change `\n` to `os.linesep` -+ os_linesep_byte = bytes(os.linesep, encoding='ascii') -+ (p / 'fileA').write_text('abcde\nfghlk\n\rmnopq') -+ self.assertEqual((p / 'fileA').read_bytes(), -+ b'abcde' + os_linesep_byte + b'fghlk' + os_linesep_byte + b'\rmnopq') -+ -+ def test_copy_file(self): -+ base = self.cls(self.base) -+ source = base / 'fileA' -+ target = base / 'copyA' -+ result = source.copy(target) -+ self.assertEqual(result, target) -+ self.assertTrue(target.exists()) -+ self.assertEqual(source.read_text(), target.read_text()) -+ -+ def test_copy_file_to_existing_file(self): -+ base = self.cls(self.base) -+ source = base / 'fileA' -+ target = base / 'dirB' / 'fileB' -+ result = source.copy(target) -+ self.assertEqual(result, target) -+ self.assertTrue(target.exists()) -+ self.assertEqual(source.read_text(), target.read_text()) -+ -+ def test_copy_file_to_existing_directory(self): -+ base = self.cls(self.base) -+ source = base / 'fileA' -+ target = base / 'dirA' -+ self.assertRaises(OSError, source.copy, target) -+ -+ def test_copy_file_empty(self): -+ base = self.cls(self.base) -+ source = base / 'empty' -+ target = base / 'copyA' -+ source.write_bytes(b'') -+ result = source.copy(target) -+ self.assertEqual(result, target) -+ self.assertTrue(target.exists()) -+ self.assertEqual(target.read_bytes(), b'') -+ -+ def test_copy_file_to_itself(self): -+ base = self.cls(self.base) -+ source = base / 'empty' -+ source.write_bytes(b'') -+ self.assertRaises(OSError, source.copy, source) -+ self.assertRaises(OSError, source.copy, source, follow_symlinks=False) -+ -+ def test_copy_dir_simple(self): -+ base = self.cls(self.base) -+ source = base / 'dirC' -+ target = base / 'copyC' -+ result = source.copy(target) -+ self.assertEqual(result, target) -+ self.assertTrue(target.is_dir()) -+ self.assertTrue(target.joinpath('dirD').is_dir()) -+ self.assertTrue(target.joinpath('dirD', 'fileD').is_file()) -+ self.assertEqual(target.joinpath('dirD', 'fileD').read_text(), -+ "this is file D\n") -+ self.assertTrue(target.joinpath('fileC').is_file()) -+ self.assertTrue(target.joinpath('fileC').read_text(), -+ "this is file C\n") -+ -+ def test_copy_dir_complex(self, follow_symlinks=True): -+ def ordered_walk(path): -+ for dirpath, dirnames, filenames in path.walk(follow_symlinks=follow_symlinks): -+ dirnames.sort() -+ filenames.sort() -+ yield dirpath, dirnames, filenames -+ base = self.cls(self.base) -+ source = base / 'dirC' -+ -+ if self.can_symlink: -+ # Add some symlinks -+ source.joinpath('linkC').symlink_to('fileC') -+ source.joinpath('linkD').symlink_to('dirD', target_is_directory=True) -+ -+ # Perform the copy -+ target = base / 'copyC' -+ result = source.copy(target, follow_symlinks=follow_symlinks) -+ self.assertEqual(result, target) -+ -+ # Compare the source and target trees -+ source_walk = ordered_walk(source) -+ target_walk = ordered_walk(target) -+ for source_item, target_item in zip(source_walk, target_walk, strict=True): -+ self.assertEqual(source_item[0].parts[len(source.parts):], -+ target_item[0].parts[len(target.parts):]) # dirpath -+ self.assertEqual(source_item[1], target_item[1]) # dirnames -+ self.assertEqual(source_item[2], target_item[2]) # filenames -+ # Compare files and symlinks -+ for filename in source_item[2]: -+ source_file = source_item[0].joinpath(filename) -+ target_file = target_item[0].joinpath(filename) -+ if follow_symlinks or not source_file.is_symlink(): -+ # Regular file. -+ self.assertEqual(source_file.read_bytes(), target_file.read_bytes()) -+ elif source_file.is_dir(): -+ # Symlink to directory. -+ self.assertTrue(target_file.is_dir()) -+ self.assertEqual(source_file.readlink(), target_file.readlink()) -+ else: -+ # Symlink to file. -+ self.assertEqual(source_file.read_bytes(), target_file.read_bytes()) -+ self.assertEqual(source_file.readlink(), target_file.readlink()) -+ -+ def test_copy_dir_complex_follow_symlinks_false(self): -+ self.test_copy_dir_complex(follow_symlinks=False) -+ -+ def test_copy_dir_to_existing_directory(self): -+ base = self.cls(self.base) -+ source = base / 'dirC' -+ target = base / 'copyC' -+ target.mkdir() -+ target.joinpath('dirD').mkdir() -+ self.assertRaises(FileExistsError, source.copy, target) -+ -+ def test_copy_dir_to_existing_directory_dirs_exist_ok(self): -+ base = self.cls(self.base) -+ source = base / 'dirC' -+ target = base / 'copyC' -+ target.mkdir() -+ target.joinpath('dirD').mkdir() -+ result = source.copy(target, dirs_exist_ok=True) -+ self.assertEqual(result, target) -+ self.assertTrue(target.is_dir()) -+ self.assertTrue(target.joinpath('dirD').is_dir()) -+ self.assertTrue(target.joinpath('dirD', 'fileD').is_file()) -+ self.assertEqual(target.joinpath('dirD', 'fileD').read_text(), -+ "this is file D\n") -+ self.assertTrue(target.joinpath('fileC').is_file()) -+ self.assertTrue(target.joinpath('fileC').read_text(), -+ "this is file C\n") -+ -+ def test_copy_dir_to_itself(self): -+ base = self.cls(self.base) -+ source = base / 'dirC' -+ self.assertRaises(OSError, source.copy, source) -+ self.assertRaises(OSError, source.copy, source, follow_symlinks=False) -+ -+ def test_copy_dir_into_itself(self): - base = self.cls(self.base) -- base.joinpath('dirA')._delete() -- self.assertRaises(FileNotFoundError, base.joinpath('dirA').stat) -- self.assertRaises(FileNotFoundError, base.joinpath('dirA', 'linkC').stat, -- follow_symlinks=False) -- base.joinpath('dirB')._delete() -- self.assertRaises(FileNotFoundError, base.joinpath('dirB').stat) -- self.assertRaises(FileNotFoundError, base.joinpath('dirB', 'fileB').stat) -- self.assertRaises(FileNotFoundError, base.joinpath('dirB', 'linkD').stat, -- follow_symlinks=False) -- base.joinpath('dirC')._delete() -- self.assertRaises(FileNotFoundError, base.joinpath('dirC').stat) -- self.assertRaises(FileNotFoundError, base.joinpath('dirC', 'dirD').stat) -- self.assertRaises(FileNotFoundError, base.joinpath('dirC', 'dirD', 'fileD').stat) -- self.assertRaises(FileNotFoundError, base.joinpath('dirC', 'fileC').stat) -- self.assertRaises(FileNotFoundError, base.joinpath('dirC', 'novel.txt').stat) -- -- def test_delete_missing(self): -- tmp = self.cls(self.base, 'delete') -- tmp.mkdir() -- # filename is guaranteed not to exist -- filename = tmp / 'foo' -- self.assertRaises(FileNotFoundError, filename._delete) -- -- --class DummyPathWalkTest(unittest.TestCase): -- cls = DummyPath -- base = DummyPathTest.base -+ source = base / 'dirC' -+ target = base / 'dirC' / 'dirD' / 'copyC' -+ self.assertRaises(OSError, source.copy, target) -+ self.assertRaises(OSError, source.copy, target, follow_symlinks=False) -+ self.assertFalse(target.exists()) -+ -+ def test_copy_into(self): -+ base = self.cls(self.base) -+ source = base / 'fileA' -+ target_dir = base / 'dirA' -+ result = source.copy_into(target_dir) -+ self.assertEqual(result, target_dir / 'fileA') -+ self.assertTrue(result.exists()) -+ self.assertEqual(source.read_text(), result.read_text()) -+ -+ def test_copy_into_empty_name(self): -+ source = self.cls('') -+ target_dir = self.base -+ self.assertRaises(ValueError, source.copy_into, target_dir) -+ -+ -+class DummyReadablePathWalkTest(unittest.TestCase): -+ cls = DummyReadablePath -+ base = DummyReadablePathTest.base - can_symlink = False - - def setUp(self): -- # Build: -- # TESTFN/ -- # TEST1/ a file kid and two directory kids -- # tmp1 -- # SUB1/ a file kid and a directory kid -- # tmp2 -- # SUB11/ no kids -- # SUB2/ a file kid and a dirsymlink kid -- # tmp3 -- # link/ a symlink to TEST2 -- # broken_link -- # broken_link2 -- # TEST2/ -- # tmp4 a lone file - self.walk_path = self.cls(self.base, "TEST1") - self.sub1_path = self.walk_path / "SUB1" - self.sub11_path = self.sub1_path / "SUB11" - self.sub2_path = self.walk_path / "SUB2" -- tmp1_path = self.walk_path / "tmp1" -- tmp2_path = self.sub1_path / "tmp2" -- tmp3_path = self.sub2_path / "tmp3" - self.link_path = self.sub2_path / "link" -- t2_path = self.cls(self.base, "TEST2") -- tmp4_path = self.cls(self.base, "TEST2", "tmp4") -- broken_link_path = self.sub2_path / "broken_link" -- broken_link2_path = self.sub2_path / "broken_link2" -- -- self.sub11_path.mkdir(parents=True) -- self.sub2_path.mkdir(parents=True) -- t2_path.mkdir(parents=True) -- -- for path in tmp1_path, tmp2_path, tmp3_path, tmp4_path: -- with path.open("w", encoding='utf-8') as f: -- f.write(f"I'm {path} and proud of it. Blame test_pathlib.\n") -+ self.sub2_tree = (self.sub2_path, [], ["tmp3"]) -+ self.createTestHierarchy() - -- if self.can_symlink: -- self.link_path.symlink_to(t2_path, target_is_directory=True) -- broken_link_path.symlink_to('broken') -- broken_link2_path.symlink_to(self.cls('tmp3', 'broken')) -- self.sub2_tree = (self.sub2_path, [], ["broken_link", "broken_link2", "link", "tmp3"]) -- else: -- self.sub2_tree = (self.sub2_path, [], ["tmp3"]) -+ def createTestHierarchy(self): -+ cls = self.cls -+ cls._files = { -+ f'{self.base}/TEST1/tmp1': b'this is tmp1\n', -+ f'{self.base}/TEST1/SUB1/tmp2': b'this is tmp2\n', -+ f'{self.base}/TEST1/SUB2/tmp3': b'this is tmp3\n', -+ f'{self.base}/TEST2/tmp4': b'this is tmp4\n', -+ } -+ cls._directories = { -+ f'{self.base}': {'TEST1', 'TEST2'}, -+ f'{self.base}/TEST1': {'SUB1', 'SUB2', 'tmp1'}, -+ f'{self.base}/TEST1/SUB1': {'SUB11', 'tmp2'}, -+ f'{self.base}/TEST1/SUB1/SUB11': set(), -+ f'{self.base}/TEST1/SUB2': {'tmp3'}, -+ f'{self.base}/TEST2': {'tmp4'}, -+ } - - def tearDown(self): -- base = self.cls(self.base) -- base._delete() -+ cls = self.cls -+ cls._files.clear() -+ cls._directories.clear() - - def test_walk_topdown(self): - walker = self.walk_path.walk() -diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py -index 48a4c568651..4d371a6e754 100644 ---- a/Lib/test/test_pdb.py -+++ b/Lib/test/test_pdb.py -@@ -20,8 +20,7 @@ - from test.support.pty_helper import run_pty, FakeInput - from unittest.mock import patch - --# gh-114275: WASI fails to run asyncio tests, similar skip than test_asyncio. --SKIP_ASYNCIO_TESTS = (not support.has_socket_support) -+SKIP_CORO_TESTS = False - - - class PdbTestInput(object): -@@ -1987,7 +1986,7 @@ - """ - - def test_pdb_next_command_for_generator(): -- """Testing skip unwindng stack on yield for generators for "next" command -+ """Testing skip unwinding stack on yield for generators for "next" command - - >>> def test_gen(): - ... yield 0 -@@ -2049,26 +2048,23 @@ - finished - """ - --if not SKIP_ASYNCIO_TESTS: -+if not SKIP_CORO_TESTS: - def test_pdb_next_command_for_coroutine(): -- """Testing skip unwindng stack on yield for coroutines for "next" command -+ """Testing skip unwinding stack on yield for coroutines for "next" command - -- >>> import asyncio -+ >>> from test.support import run_yielding_async_fn, async_yield - - >>> async def test_coro(): -- ... await asyncio.sleep(0) -- ... await asyncio.sleep(0) -- ... await asyncio.sleep(0) -+ ... await async_yield(0) -+ ... await async_yield(0) -+ ... await async_yield(0) - - >>> async def test_main(): - ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() - ... await test_coro() - - >>> def test_function(): -- ... loop = asyncio.new_event_loop() -- ... loop.run_until_complete(test_main()) -- ... loop.close() -- ... asyncio.set_event_loop_policy(None) -+ ... run_yielding_async_fn(test_main) - ... print("finished") - - >>> with PdbTestInput(['step', -@@ -2091,13 +2087,13 @@ - -> async def test_coro(): - (Pdb) step - > (2)test_coro() -- -> await asyncio.sleep(0) -+ -> await async_yield(0) - (Pdb) next - > (3)test_coro() -- -> await asyncio.sleep(0) -+ -> await async_yield(0) - (Pdb) next - > (4)test_coro() -- -> await asyncio.sleep(0) -+ -> await async_yield(0) - (Pdb) next - Internal StopIteration - > (3)test_main() -@@ -2111,13 +2107,13 @@ - """ - - def test_pdb_next_command_for_asyncgen(): -- """Testing skip unwindng stack on yield for coroutines for "next" command -+ """Testing skip unwinding stack on yield for coroutines for "next" command - -- >>> import asyncio -+ >>> from test.support import run_yielding_async_fn, async_yield - - >>> async def agen(): - ... yield 1 -- ... await asyncio.sleep(0) -+ ... await async_yield(0) - ... yield 2 - - >>> async def test_coro(): -@@ -2129,10 +2125,7 @@ - ... await test_coro() - - >>> def test_function(): -- ... loop = asyncio.new_event_loop() -- ... loop.run_until_complete(test_main()) -- ... loop.close() -- ... asyncio.set_event_loop_policy(None) -+ ... run_yielding_async_fn(test_main) - ... print("finished") - - >>> with PdbTestInput(['step', -@@ -2169,14 +2162,14 @@ - -> yield 1 - (Pdb) next - > (3)agen() -- -> await asyncio.sleep(0) -+ -> await async_yield(0) - (Pdb) continue - 2 - finished - """ - - def test_pdb_return_command_for_generator(): -- """Testing no unwindng stack on yield for generators -+ """Testing no unwinding stack on yield for generators - for "return" command - - >>> def test_gen(): -@@ -2234,26 +2227,23 @@ - finished - """ - --if not SKIP_ASYNCIO_TESTS: -+if not SKIP_CORO_TESTS: - def test_pdb_return_command_for_coroutine(): -- """Testing no unwindng stack on yield for coroutines for "return" command -+ """Testing no unwinding stack on yield for coroutines for "return" command - -- >>> import asyncio -+ >>> from test.support import run_yielding_async_fn, async_yield - - >>> async def test_coro(): -- ... await asyncio.sleep(0) -- ... await asyncio.sleep(0) -- ... await asyncio.sleep(0) -+ ... await async_yield(0) -+ ... await async_yield(0) -+ ... await async_yield(0) - - >>> async def test_main(): - ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() - ... await test_coro() - - >>> def test_function(): -- ... loop = asyncio.new_event_loop() -- ... loop.run_until_complete(test_main()) -- ... loop.close() -- ... asyncio.set_event_loop_policy(None) -+ ... run_yielding_async_fn(test_main) - ... print("finished") - - >>> with PdbTestInput(['step', -@@ -2273,16 +2263,16 @@ - -> async def test_coro(): - (Pdb) step - > (2)test_coro() -- -> await asyncio.sleep(0) -+ -> await async_yield(0) - (Pdb) next - > (3)test_coro() -- -> await asyncio.sleep(0) -+ -> await async_yield(0) - (Pdb) continue - finished - """ - - def test_pdb_until_command_for_generator(): -- """Testing no unwindng stack on yield for generators -+ """Testing no unwinding stack on yield for generators - for "until" command if target breakpoint is not reached - - >>> def test_gen(): -@@ -2329,20 +2319,20 @@ - finished - """ - --if not SKIP_ASYNCIO_TESTS: -+if not SKIP_CORO_TESTS: - def test_pdb_until_command_for_coroutine(): -- """Testing no unwindng stack for coroutines -+ """Testing no unwinding stack for coroutines - for "until" command if target breakpoint is not reached - -- >>> import asyncio -+ >>> from test.support import run_yielding_async_fn, async_yield - - >>> async def test_coro(): - ... print(0) -- ... await asyncio.sleep(0) -+ ... await async_yield(0) - ... print(1) -- ... await asyncio.sleep(0) -+ ... await async_yield(0) - ... print(2) -- ... await asyncio.sleep(0) -+ ... await async_yield(0) - ... print(3) - - >>> async def test_main(): -@@ -2350,10 +2340,7 @@ - ... await test_coro() - - >>> def test_function(): -- ... loop = asyncio.new_event_loop() -- ... loop.run_until_complete(test_main()) -- ... loop.close() -- ... asyncio.set_event_loop_policy(None) -+ ... run_yielding_async_fn(test_main) - ... print("finished") - - >>> with PdbTestInput(['step', -@@ -3022,6 +3009,57 @@ - (Pdb) continue - """ - -+def test_pdb_frame_refleak(): -+ """ -+ pdb should not leak reference to frames -+ -+ >>> def frame_leaker(container): -+ ... import sys -+ ... container.append(sys._getframe()) -+ ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() -+ ... pass -+ -+ >>> def test_function(): -+ ... import gc -+ ... container = [] -+ ... frame_leaker(container) # c -+ ... print(len(gc.get_referrers(container[0]))) -+ ... container = [] -+ ... frame_leaker(container) # n c -+ ... print(len(gc.get_referrers(container[0]))) -+ ... container = [] -+ ... frame_leaker(container) # r c -+ ... print(len(gc.get_referrers(container[0]))) -+ -+ >>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE -+ ... 'continue', -+ ... 'next', -+ ... 'continue', -+ ... 'return', -+ ... 'continue', -+ ... ]): -+ ... test_function() -+ > (4)frame_leaker() -+ -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() -+ (Pdb) continue -+ 1 -+ > (4)frame_leaker() -+ -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() -+ (Pdb) next -+ > (5)frame_leaker() -+ -> pass -+ (Pdb) continue -+ 1 -+ > (4)frame_leaker() -+ -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() -+ (Pdb) return -+ --Return-- -+ > (5)frame_leaker()->None -+ -> pass -+ (Pdb) continue -+ 1 -+ """ -+ - def test_pdb_function_break(): - """Testing the line number of break on function - -@@ -3165,16 +3203,12 @@ - self.addCleanup(os_helper.unlink, '.pdbrc') - self.addCleanup(os_helper.unlink, filename) - -- homesave = None -- if remove_home: -- homesave = os.environ.pop('HOME', None) -- try: -+ with os_helper.EnvironmentVarGuard() as env: -+ if remove_home: -+ env.unset('HOME') - if script_args is None: - script_args = [] - stdout, stderr = self._run_pdb([filename] + script_args, commands, expected_returncode, extra_env) -- finally: -- if homesave is not None: -- os.environ['HOME'] = homesave - return stdout, stderr - - def run_pdb_module(self, script, commands): -@@ -3598,17 +3632,14 @@ - self.assertIn("NameError: name 'invalid' is not defined", stdout) - - def test_readrc_homedir(self): -- save_home = os.environ.pop("HOME", None) -- with os_helper.temp_dir() as temp_dir, patch("os.path.expanduser"): -- rc_path = os.path.join(temp_dir, ".pdbrc") -- os.path.expanduser.return_value = rc_path -- try: -+ with os_helper.EnvironmentVarGuard() as env: -+ env.unset("HOME") -+ with os_helper.temp_dir() as temp_dir, patch("os.path.expanduser"): -+ rc_path = os.path.join(temp_dir, ".pdbrc") -+ os.path.expanduser.return_value = rc_path - with open(rc_path, "w") as f: - f.write("invalid") - self.assertEqual(pdb.Pdb().rcLines[0], "invalid") -- finally: -- if save_home is not None: -- os.environ["HOME"] = save_home - - def test_header(self): - stdout = StringIO() -@@ -4206,6 +4237,62 @@ - self.assertFalse(db.checkline(os_helper.TESTFN, lineno)) - - -+@support.requires_subprocess() -+class PdbTestInline(unittest.TestCase): -+ @unittest.skipIf(sys.flags.safe_path, -+ 'PYTHONSAFEPATH changes default sys.path') -+ def _run_script(self, script, commands, -+ expected_returncode=0, -+ extra_env=None): -+ self.addCleanup(os_helper.rmtree, '__pycache__') -+ filename = 'main.py' -+ with open(filename, 'w') as f: -+ f.write(textwrap.dedent(script)) -+ self.addCleanup(os_helper.unlink, filename) -+ -+ commands = textwrap.dedent(commands) -+ -+ cmd = [sys.executable, 'main.py'] -+ if extra_env is not None: -+ env = os.environ | extra_env -+ else: -+ env = os.environ -+ with subprocess.Popen( -+ cmd, -+ stdout=subprocess.PIPE, -+ stdin=subprocess.PIPE, -+ stderr=subprocess.PIPE, -+ env = {**env, 'PYTHONIOENCODING': 'utf-8'} -+ ) as proc: -+ stdout, stderr = proc.communicate(str.encode(commands)) -+ stdout = bytes.decode(stdout) if isinstance(stdout, bytes) else stdout -+ stderr = bytes.decode(stderr) if isinstance(stderr, bytes) else stderr -+ self.assertEqual( -+ proc.returncode, -+ expected_returncode, -+ f"Unexpected return code\nstdout: {stdout}\nstderr: {stderr}" -+ ) -+ return stdout, stderr -+ -+ def test_quit(self): -+ script = """ -+ x = 1 -+ breakpoint() -+ """ -+ -+ commands = """ -+ quit -+ n -+ p x + 1 -+ quit -+ y -+ """ -+ -+ stdout, stderr = self._run_script(script, commands) -+ self.assertIn("2", stdout) -+ self.assertIn("Quit anyway", stdout) -+ -+ - @support.requires_subprocess() - class PdbTestReadline(unittest.TestCase): - def setUpClass(): -diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py -index c7da151dce3..ed92e5257df 100644 ---- a/Lib/test/test_peepholer.py -+++ b/Lib/test/test_peepholer.py -@@ -1,5 +1,6 @@ - import dis - from itertools import combinations, product -+import opcode - import sys - import textwrap - import unittest -@@ -35,6 +36,13 @@ - return count - - -+def get_binop_argval(arg): -+ for i, nb_op in enumerate(opcode._nb_ops): -+ if arg == nb_op[0]: -+ return i -+ assert False, f"{arg} is not a valid BINARY_OP argument." -+ -+ - class TestTranforms(BytecodeTestCase): - - def check_jump_targets(self, code): -@@ -280,23 +288,23 @@ - # valid code get optimized - code = compile('"foo"[0]', '', 'single') - self.assertInBytecode(code, 'LOAD_CONST', 'f') -- self.assertNotInBytecode(code, 'BINARY_SUBSCR') -+ self.assertNotInBytecode(code, 'BINARY_OP') - self.check_lnotab(code) - code = compile('"\u0061\uffff"[1]', '', 'single') - self.assertInBytecode(code, 'LOAD_CONST', '\uffff') -- self.assertNotInBytecode(code,'BINARY_SUBSCR') -+ self.assertNotInBytecode(code,'BINARY_OP') - self.check_lnotab(code) - - # With PEP 393, non-BMP char get optimized - code = compile('"\U00012345"[0]', '', 'single') - self.assertInBytecode(code, 'LOAD_CONST', '\U00012345') -- self.assertNotInBytecode(code, 'BINARY_SUBSCR') -+ self.assertNotInBytecode(code, 'BINARY_OP') - self.check_lnotab(code) - - # invalid code doesn't get optimized - # out of range - code = compile('"fuu"[10]', '', 'single') -- self.assertInBytecode(code, 'BINARY_SUBSCR') -+ self.assertInBytecode(code, 'BINARY_OP') - self.check_lnotab(code) - - def test_folding_of_unaryops_on_constants(self): -@@ -473,6 +481,60 @@ - self.assertFalse(instr.opname.startswith('BUILD_')) - self.check_lnotab(code) - -+ def test_constant_folding_small_int(self): -+ tests = [ -+ # subscript -+ ('(0, )[0]', 0), -+ ('(1 + 2, )[0]', 3), -+ ('(2 + 2 * 2, )[0]', 6), -+ ('(1, (1 + 2 + 3, ))[1][0]', 6), -+ ('(255, )[0]', 255), -+ ('(256, )[0]', None), -+ ('(1000, )[0]', None), -+ ('(1 - 2, )[0]', None), -+ ] -+ for expr, oparg in tests: -+ with self.subTest(expr=expr, oparg=oparg): -+ code = compile(expr, '', 'single') -+ if oparg is not None: -+ self.assertInBytecode(code, 'LOAD_SMALL_INT', oparg) -+ else: -+ self.assertNotInBytecode(code, 'LOAD_SMALL_INT') -+ self.check_lnotab(code) -+ -+ def test_folding_subscript(self): -+ tests = [ -+ ('(1, )[0]', False), -+ ('(1, )[-1]', False), -+ ('(1 + 2, )[0]', False), -+ ('(1, (1, 2))[1][1]', False), -+ ('(1, 2)[2-1]', False), -+ ('(1, (1, 2))[1][2-1]', False), -+ ('(1, (1, 2))[1:6][0][2-1]', False), -+ ('"a"[0]', False), -+ ('("a" + "b")[1]', False), -+ ('("a" + "b", )[0][1]', False), -+ ('("a" * 10)[9]', False), -+ ('(1, )[1]', True), -+ ('(1, )[-2]', True), -+ ('"a"[1]', True), -+ ('"a"[-2]', True), -+ ('("a" + "b")[2]', True), -+ ('("a" + "b", )[0][2]', True), -+ ('("a" + "b", )[1][0]', True), -+ ('("a" * 10)[10]', True), -+ ('(1, (1, 2))[2:6][0][2-1]', True), -+ ] -+ subscr_argval = get_binop_argval('NB_SUBSCR') -+ for expr, has_error in tests: -+ with self.subTest(expr=expr, has_error=has_error): -+ code = compile(expr, '', 'single') -+ if not has_error: -+ self.assertNotInBytecode(code, 'BINARY_OP', argval=subscr_argval) -+ else: -+ self.assertInBytecode(code, 'BINARY_OP', argval=subscr_argval) -+ self.check_lnotab(code) -+ - def test_in_literal_list(self): - def containtest(): - return x in [a, b] -@@ -1006,6 +1068,200 @@ - consts=[0, 1, 2, 3, 4], - expected_consts=[0, 2, 3]) - -+ def test_list_exceeding_stack_use_guideline(self): -+ def f(): -+ return [ -+ 0, 1, 2, 3, 4, -+ 5, 6, 7, 8, 9, -+ 10, 11, 12, 13, 14, -+ 15, 16, 17, 18, 19, -+ 20, 21, 22, 23, 24, -+ 25, 26, 27, 28, 29, -+ 30, 31, 32, 33, 34, -+ 35, 36, 37, 38, 39 -+ ] -+ self.assertEqual(f(), list(range(40))) -+ -+ def test_set_exceeding_stack_use_guideline(self): -+ def f(): -+ return { -+ 0, 1, 2, 3, 4, -+ 5, 6, 7, 8, 9, -+ 10, 11, 12, 13, 14, -+ 15, 16, 17, 18, 19, -+ 20, 21, 22, 23, 24, -+ 25, 26, 27, 28, 29, -+ 30, 31, 32, 33, 34, -+ 35, 36, 37, 38, 39 -+ } -+ self.assertEqual(f(), frozenset(range(40))) -+ -+ def test_multiple_foldings(self): -+ before = [ -+ ('LOAD_SMALL_INT', 1, 0), -+ ('LOAD_SMALL_INT', 2, 0), -+ ('BUILD_TUPLE', 1, 0), -+ ('LOAD_SMALL_INT', 0, 0), -+ ('BINARY_OP', get_binop_argval('NB_SUBSCR'), 0), -+ ('BUILD_TUPLE', 2, 0), -+ ('RETURN_VALUE', None, 0) -+ ] -+ after = [ -+ ('LOAD_CONST', 1, 0), -+ ('RETURN_VALUE', None, 0) -+ ] -+ self.cfg_optimization_test(before, after, consts=[], expected_consts=[(2,), (1, 2)]) -+ -+ def test_build_empty_tuple(self): -+ before = [ -+ ('BUILD_TUPLE', 0, 0), -+ ('RETURN_VALUE', None, 0), -+ ] -+ after = [ -+ ('LOAD_CONST', 0, 0), -+ ('RETURN_VALUE', None, 0), -+ ] -+ self.cfg_optimization_test(before, after, consts=[], expected_consts=[()]) -+ -+ def test_fold_tuple_of_constants(self): -+ before = [ -+ ('NOP', None, 0), -+ ('LOAD_SMALL_INT', 1, 0), -+ ('NOP', None, 0), -+ ('LOAD_SMALL_INT', 2, 0), -+ ('NOP', None, 0), -+ ('NOP', None, 0), -+ ('LOAD_SMALL_INT', 3, 0), -+ ('NOP', None, 0), -+ ('BUILD_TUPLE', 3, 0), -+ ('RETURN_VALUE', None, 0), -+ ] -+ after = [ -+ ('LOAD_CONST', 0, 0), -+ ('RETURN_VALUE', None, 0), -+ ] -+ self.cfg_optimization_test(before, after, consts=[], expected_consts=[(1, 2, 3)]) -+ -+ # not enough consts -+ same = [ -+ ('LOAD_SMALL_INT', 1, 0), -+ ('LOAD_SMALL_INT', 2, 0), -+ ('BUILD_TUPLE', 3, 0), -+ ('RETURN_VALUE', None, 0) -+ ] -+ self.cfg_optimization_test(same, same, consts=[]) -+ -+ # not all consts -+ same = [ -+ ('LOAD_SMALL_INT', 1, 0), -+ ('LOAD_NAME', 0, 0), -+ ('LOAD_SMALL_INT', 2, 0), -+ ('BUILD_TUPLE', 3, 0), -+ ('RETURN_VALUE', None, 0) -+ ] -+ self.cfg_optimization_test(same, same, consts=[]) -+ -+ def test_optimize_if_const_list(self): -+ before = [ -+ ('NOP', None, 0), -+ ('LOAD_SMALL_INT', 1, 0), -+ ('NOP', None, 0), -+ ('LOAD_SMALL_INT', 2, 0), -+ ('NOP', None, 0), -+ ('NOP', None, 0), -+ ('LOAD_SMALL_INT', 3, 0), -+ ('NOP', None, 0), -+ ('BUILD_LIST', 3, 0), -+ ('RETURN_VALUE', None, 0), -+ ] -+ after = [ -+ ('BUILD_LIST', 0, 0), -+ ('LOAD_CONST', 0, 0), -+ ('LIST_EXTEND', 1, 0), -+ ('RETURN_VALUE', None, 0), -+ ] -+ self.cfg_optimization_test(before, after, consts=[], expected_consts=[(1, 2, 3)]) -+ -+ # need minimum 3 consts to optimize -+ same = [ -+ ('LOAD_SMALL_INT', 1, 0), -+ ('LOAD_SMALL_INT', 2, 0), -+ ('BUILD_LIST', 2, 0), -+ ('RETURN_VALUE', None, 0), -+ ] -+ self.cfg_optimization_test(same, same, consts=[]) -+ -+ # not enough consts -+ same = [ -+ ('LOAD_SMALL_INT', 1, 0), -+ ('LOAD_SMALL_INT', 2, 0), -+ ('LOAD_SMALL_INT', 3, 0), -+ ('BUILD_LIST', 4, 0), -+ ('RETURN_VALUE', None, 0), -+ ] -+ self.cfg_optimization_test(same, same, consts=[]) -+ -+ # not all consts -+ same = [ -+ ('LOAD_SMALL_INT', 1, 0), -+ ('LOAD_NAME', 0, 0), -+ ('LOAD_SMALL_INT', 3, 0), -+ ('BUILD_LIST', 3, 0), -+ ('RETURN_VALUE', None, 0), -+ ] -+ self.cfg_optimization_test(same, same, consts=[]) -+ -+ def test_optimize_if_const_set(self): -+ before = [ -+ ('NOP', None, 0), -+ ('LOAD_SMALL_INT', 1, 0), -+ ('NOP', None, 0), -+ ('LOAD_SMALL_INT', 2, 0), -+ ('NOP', None, 0), -+ ('NOP', None, 0), -+ ('LOAD_SMALL_INT', 3, 0), -+ ('NOP', None, 0), -+ ('BUILD_SET', 3, 0), -+ ('RETURN_VALUE', None, 0), -+ ] -+ after = [ -+ ('BUILD_SET', 0, 0), -+ ('LOAD_CONST', 0, 0), -+ ('SET_UPDATE', 1, 0), -+ ('RETURN_VALUE', None, 0), -+ ] -+ self.cfg_optimization_test(before, after, consts=[], expected_consts=[frozenset({1, 2, 3})]) -+ -+ # need minimum 3 consts to optimize -+ same = [ -+ ('LOAD_SMALL_INT', 1, 0), -+ ('LOAD_SMALL_INT', 2, 0), -+ ('BUILD_SET', 2, 0), -+ ('RETURN_VALUE', None, 0), -+ ] -+ self.cfg_optimization_test(same, same, consts=[]) -+ -+ # not enough consts -+ same = [ -+ ('LOAD_SMALL_INT', 1, 0), -+ ('LOAD_SMALL_INT', 2, 0), -+ ('LOAD_SMALL_INT', 3, 0), -+ ('BUILD_SET', 4, 0), -+ ('RETURN_VALUE', None, 0), -+ ] -+ self.cfg_optimization_test(same, same, consts=[]) -+ -+ # not all consts -+ same = [ -+ ('LOAD_SMALL_INT', 1, 0), -+ ('LOAD_NAME', 0, 0), -+ ('LOAD_SMALL_INT', 3, 0), -+ ('BUILD_SET', 3, 0), -+ ('RETURN_VALUE', None, 0), -+ ] -+ self.cfg_optimization_test(same, same, consts=[]) -+ -+ - def test_conditional_jump_forward_const_condition(self): - # The unreachable branch of the jump is removed, the jump - # becomes redundant and is replaced by a NOP (for the lineno) -@@ -1193,5 +1449,56 @@ - ] - self.cfg_optimization_test(insts, expected_insts, consts=list(range(5))) - -+ def test_list_to_tuple_get_iter(self): -+ # for _ in (*foo, *bar) -> for _ in [*foo, *bar] -+ INTRINSIC_LIST_TO_TUPLE = 6 -+ insts = [ -+ ("BUILD_LIST", 0, 1), -+ ("LOAD_FAST", 0, 2), -+ ("LIST_EXTEND", 1, 3), -+ ("LOAD_FAST", 1, 4), -+ ("LIST_EXTEND", 1, 5), -+ ("CALL_INTRINSIC_1", INTRINSIC_LIST_TO_TUPLE, 6), -+ ("GET_ITER", None, 7), -+ top := self.Label(), -+ ("FOR_ITER", end := self.Label(), 8), -+ ("STORE_FAST", 2, 9), -+ ("JUMP", top, 10), -+ end, -+ ("END_FOR", None, 11), -+ ("POP_TOP", None, 12), -+ ("LOAD_CONST", 0, 13), -+ ("RETURN_VALUE", None, 14), -+ ] -+ expected_insts = [ -+ ("BUILD_LIST", 0, 1), -+ ("LOAD_FAST", 0, 2), -+ ("LIST_EXTEND", 1, 3), -+ ("LOAD_FAST", 1, 4), -+ ("LIST_EXTEND", 1, 5), -+ ("NOP", None, 6), # ("CALL_INTRINSIC_1", INTRINSIC_LIST_TO_TUPLE, 6), -+ ("GET_ITER", None, 7), -+ top := self.Label(), -+ ("FOR_ITER", end := self.Label(), 8), -+ ("STORE_FAST", 2, 9), -+ ("JUMP", top, 10), -+ end, -+ ("END_FOR", None, 11), -+ ("POP_TOP", None, 12), -+ ("LOAD_CONST", 0, 13), -+ ("RETURN_VALUE", None, 14), -+ ] -+ self.cfg_optimization_test(insts, expected_insts, consts=[None]) -+ -+ def test_list_to_tuple_get_iter_is_safe(self): -+ a, b = [], [] -+ for item in (*(items := [0, 1, 2, 3]),): -+ a.append(item) -+ b.append(items.pop()) -+ self.assertEqual(a, [0, 1, 2, 3]) -+ self.assertEqual(b, [3, 2, 1, 0]) -+ self.assertEqual(items, []) -+ -+ - if __name__ == "__main__": - unittest.main() -diff --git a/Lib/test/test_perf_profiler.py b/Lib/test/test_perf_profiler.py -index 1e749908780..6f1fd8d38e4 100644 ---- a/Lib/test/test_perf_profiler.py -+++ b/Lib/test/test_perf_profiler.py -@@ -47,6 +47,7 @@ - for file in files_to_delete: - file.unlink() - -+ @unittest.skipIf(support.check_bolt_optimized, "fails on BOLT instrumented binaries") - def test_trampoline_works(self): - code = """if 1: - def foo(): -@@ -100,6 +101,7 @@ - "Address should contain only hex characters", - ) - -+ @unittest.skipIf(support.check_bolt_optimized, "fails on BOLT instrumented binaries") - def test_trampoline_works_with_forks(self): - code = """if 1: - import os, sys -@@ -160,6 +162,7 @@ - self.assertIn(f"py::bar_fork:{script}", child_perf_file_contents) - self.assertIn(f"py::baz_fork:{script}", child_perf_file_contents) - -+ @unittest.skipIf(support.check_bolt_optimized, "fails on BOLT instrumented binaries") - def test_sys_api(self): - code = """if 1: - import sys -diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py -index 4bf0576586c..74910980567 100644 ---- a/Lib/test/test_pyclbr.py -+++ b/Lib/test/test_pyclbr.py -@@ -31,14 +31,6 @@ - print("l1=%r\nl2=%r\nignore=%r" % (l1, l2, ignore), file=sys.stderr) - self.fail("%r missing" % missing.pop()) - -- def assertHasattr(self, obj, attr, ignore): -- ''' succeed iff hasattr(obj,attr) or attr in ignore. ''' -- if attr in ignore: return -- if not hasattr(obj, attr): print("???", attr) -- self.assertTrue(hasattr(obj, attr), -- 'expected hasattr(%r, %r)' % (obj, attr)) -- -- - def assertHaskey(self, obj, key, ignore): - ''' succeed iff key in obj or key in ignore. ''' - if key in ignore: return -@@ -86,7 +78,7 @@ - for name, value in dict.items(): - if name in ignore: - continue -- self.assertHasattr(module, name, ignore) -+ self.assertHasAttr(module, name, ignore) - py_item = getattr(module, name) - if isinstance(value, pyclbr.Function): - self.assertIsInstance(py_item, (FunctionType, BuiltinFunctionType)) -@@ -234,7 +226,7 @@ - cm( - 'pdb', - # pyclbr does not handle elegantly `typing` or properties -- ignore=('Union', '_ModuleTarget', '_ScriptTarget', '_ZipTarget'), -+ ignore=('Union', '_ModuleTarget', '_ScriptTarget', '_ZipTarget', 'curframe_locals'), - ) - cm('pydoc', ignore=('input', 'output',)) # properties - ---- /dev/null -+++ b/Lib/test/test_pydoc/module_none.py -@@ -0,0 +1,8 @@ -+def func(): -+ pass -+func.__module__ = None -+ -+class A: -+ def method(self): -+ pass -+ method.__module__ = None -diff --git a/Lib/test/test_pydoc/test_pydoc.py b/Lib/test/test_pydoc/test_pydoc.py -index 3283fde9e12..0abd36c5e07 100644 ---- a/Lib/test/test_pydoc/test_pydoc.py -+++ b/Lib/test/test_pydoc/test_pydoc.py -@@ -4,6 +4,7 @@ - import contextlib - import importlib.util - import inspect -+import io - import pydoc - import py_compile - import keyword -@@ -79,7 +80,7 @@ - class B(builtins.object) - | Methods defined here: - | -- | __annotate__(...) -+ | __annotate__(format, /) - | - | ---------------------------------------------------------------------- - | Data descriptors defined here: -@@ -180,7 +181,7 @@ - - class B(builtins.object) - Methods defined here: -- __annotate__(...) -+ __annotate__(format, /) - ---------------------------------------------------------------------- - Data descriptors defined here: - __dict__ -@@ -555,6 +556,14 @@ - | ... and 82 other subclasses - """ - doc = pydoc.TextDoc() -+ try: -+ # Make sure HeapType, which has no __module__ attribute, is one -+ # of the known subclasses of object. (doc.docclass() used to -+ # fail if HeapType was imported before running this test, like -+ # when running tests sequentially.) -+ from _testcapi import HeapType -+ except ImportError: -+ pass - text = doc.docclass(object) - snip = (" | Built-in subclasses:\n" - " | async_generator\n" -@@ -899,6 +908,82 @@ - synopsis = pydoc.synopsis(TESTFN, {}) - self.assertEqual(synopsis, 'line 1: h\xe9') - -+ def test_source_synopsis(self): -+ def check(source, expected, encoding=None): -+ if isinstance(source, str): -+ source_file = StringIO(source) -+ else: -+ source_file = io.TextIOWrapper(io.BytesIO(source), encoding=encoding) -+ with source_file: -+ result = pydoc.source_synopsis(source_file) -+ self.assertEqual(result, expected) -+ -+ check('"""Single line docstring."""', -+ 'Single line docstring.') -+ check('"""First line of docstring.\nSecond line.\nThird line."""', -+ 'First line of docstring.') -+ check('"""First line of docstring.\\nSecond line.\\nThird line."""', -+ 'First line of docstring.') -+ check('""" Whitespace around docstring. """', -+ 'Whitespace around docstring.') -+ check('import sys\n"""No docstring"""', -+ None) -+ check(' \n"""Docstring after empty line."""', -+ 'Docstring after empty line.') -+ check('# Comment\n"""Docstring after comment."""', -+ 'Docstring after comment.') -+ check(' # Indented comment\n"""Docstring after comment."""', -+ 'Docstring after comment.') -+ check('""""""', # Empty docstring -+ '') -+ check('', # Empty file -+ None) -+ check('"""Embedded\0null byte"""', -+ None) -+ check('"""Embedded null byte"""\0', -+ None) -+ check('"""Café and résumé."""', -+ 'Café and résumé.') -+ check("'''Triple single quotes'''", -+ 'Triple single quotes') -+ check('"Single double quotes"', -+ 'Single double quotes') -+ check("'Single single quotes'", -+ 'Single single quotes') -+ check('"""split\\\nline"""', -+ 'splitline') -+ check('"""Unrecognized escape \\sequence"""', -+ 'Unrecognized escape \\sequence') -+ check('"""Invalid escape seq\\uence"""', -+ None) -+ check('r"""Raw \\stri\\ng"""', -+ 'Raw \\stri\\ng') -+ check('b"""Bytes literal"""', -+ None) -+ check('f"""f-string"""', -+ None) -+ check('"""Concatenated""" \\\n"string" \'literals\'', -+ 'Concatenatedstringliterals') -+ check('"""String""" + """expression"""', -+ None) -+ check('("""In parentheses""")', -+ 'In parentheses') -+ check('("""Multiple lines """\n"""in parentheses""")', -+ 'Multiple lines in parentheses') -+ check('()', # tuple -+ None) -+ check(b'# coding: iso-8859-15\n"""\xa4uro sign"""', -+ '€uro sign', encoding='iso-8859-15') -+ check(b'"""\xa4"""', # Decoding error -+ None, encoding='utf-8') -+ -+ with tempfile.NamedTemporaryFile(mode='w+', encoding='utf-8') as temp_file: -+ temp_file.write('"""Real file test."""\n') -+ temp_file.flush() -+ temp_file.seek(0) -+ result = pydoc.source_synopsis(temp_file) -+ self.assertEqual(result, "Real file test.") -+ - @requires_docstrings - def test_synopsis_sourceless(self): - os = import_helper.import_fresh_module('os') -@@ -1818,6 +1903,11 @@ - html - ) - -+ def test_module_none(self): -+ # Issue #128772 -+ from test.test_pydoc import module_none -+ pydoc.render_doc(module_none) -+ - - class PydocFodderTest(unittest.TestCase): - def tearDown(self): -diff --git a/Lib/test/test_pyrepl/support.py b/Lib/test/test_pyrepl/support.py -index 672d4896c92..45e3bf758f1 100644 ---- a/Lib/test/test_pyrepl/support.py -+++ b/Lib/test/test_pyrepl/support.py -@@ -101,16 +101,6 @@ - ) - - --def make_clean_env() -> dict[str, str]: -- clean_env = os.environ.copy() -- for k in clean_env.copy(): -- if k.startswith("PYTHON"): -- clean_env.pop(k) -- clean_env.pop("FORCE_COLOR", None) -- clean_env.pop("NO_COLOR", None) -- return clean_env -- -- - class FakeConsole(Console): - def __init__(self, events, encoding="utf-8") -> None: - self.events = iter(events) -diff --git a/Lib/test/test_pyrepl/test_pyrepl.py b/Lib/test/test_pyrepl/test_pyrepl.py -index f29a7ffbd7c..3540d2a5a41 100644 ---- a/Lib/test/test_pyrepl/test_pyrepl.py -+++ b/Lib/test/test_pyrepl/test_pyrepl.py -@@ -10,7 +10,7 @@ - import tempfile - from unittest import TestCase, skipUnless, skipIf - from unittest.mock import patch --from test.support import force_not_colorized -+from test.support import force_not_colorized, make_clean_env - from test.support import SHORT_TIMEOUT - from test.support.import_helper import import_module - from test.support.os_helper import unlink -@@ -23,7 +23,6 @@ - multiline_input, - code_to_events, - clean_screen, -- make_clean_env, - ) - from _pyrepl.console import Event - from _pyrepl.readline import (ReadlineAlikeReader, ReadlineConfig, -@@ -851,7 +850,7 @@ - output = multiline_input(reader, namespace) - self.assertEqual(output, "python") - -- def test_updown_arrow_with_completion_menu(self): -+ def test_up_down_arrow_with_completion_menu(self): - """Up arrow in the middle of unfinished tab completion when the menu is displayed - should work and trigger going back in history. Down arrow should subsequently - get us back to the incomplete command.""" -@@ -861,6 +860,7 @@ - events = itertools.chain( - code_to_events(code), - [ -+ Event(evt="key", data="down", raw=bytearray(b"\x1bOB")), - Event(evt="key", data="up", raw=bytearray(b"\x1bOA")), - Event(evt="key", data="down", raw=bytearray(b"\x1bOB")), - ], -@@ -1324,23 +1324,35 @@ - if readline.backend != "editline": - self.skipTest("GNU readline is not affected by this issue") - -- hfile = tempfile.NamedTemporaryFile() -- self.addCleanup(unlink, hfile.name) -- env = os.environ.copy() -- env["PYTHON_HISTORY"] = hfile.name -+ with tempfile.NamedTemporaryFile() as hfile: -+ env = os.environ.copy() -+ env["PYTHON_HISTORY"] = hfile.name - -- env["PYTHON_BASIC_REPL"] = "1" -- output, exit_code = self.run_repl("spam \nexit()\n", env=env) -- self.assertEqual(exit_code, 0) -- self.assertIn("spam ", output) -- self.assertNotEqual(pathlib.Path(hfile.name).stat().st_size, 0) -- self.assertIn("spam\\040", pathlib.Path(hfile.name).read_text()) -+ env["PYTHON_BASIC_REPL"] = "1" -+ output, exit_code = self.run_repl("spam \nexit()\n", env=env) -+ self.assertEqual(exit_code, 0) -+ self.assertIn("spam ", output) -+ self.assertNotEqual(pathlib.Path(hfile.name).stat().st_size, 0) -+ self.assertIn("spam\\040", pathlib.Path(hfile.name).read_text()) - -- env.pop("PYTHON_BASIC_REPL", None) -- output, exit_code = self.run_repl("exit\n", env=env) -- self.assertEqual(exit_code, 0) -- self.assertNotIn("\\040", pathlib.Path(hfile.name).read_text()) -+ env.pop("PYTHON_BASIC_REPL", None) -+ output, exit_code = self.run_repl("exit\n", env=env) -+ self.assertEqual(exit_code, 0) -+ self.assertNotIn("\\040", pathlib.Path(hfile.name).read_text()) - - def test_keyboard_interrupt_after_isearch(self): - output, exit_code = self.run_repl(["\x12", "\x03", "exit"]) - self.assertEqual(exit_code, 0) -+ -+ def test_prompt_after_help(self): -+ output, exit_code = self.run_repl(["help", "q", "exit"]) -+ -+ # Regex pattern to remove ANSI escape sequences -+ ansi_escape = re.compile(r"(\x1B(=|>|(\[)[0-?]*[ -\/]*[@-~]))") -+ cleaned_output = ansi_escape.sub("", output) -+ self.assertEqual(exit_code, 0) -+ -+ # Ensure that we don't see multiple prompts after exiting `help` -+ # Extra stuff (newline and `exit` rewrites) are necessary -+ # because of how run_repl works. -+ self.assertNotIn(">>> \n>>> >>>", cleaned_output) -diff --git a/Lib/test/test_pyrepl/test_reader.py b/Lib/test/test_pyrepl/test_reader.py -index 6c72a1d39c5..27c6d6664ed 100644 ---- a/Lib/test/test_pyrepl/test_reader.py -+++ b/Lib/test/test_pyrepl/test_reader.py -@@ -4,7 +4,7 @@ - from unittest import TestCase - from unittest.mock import MagicMock - --from .support import handle_all_events, handle_events_narrow_console, code_to_events, prepare_reader -+from .support import handle_all_events, handle_events_narrow_console, code_to_events, prepare_reader, prepare_console - from _pyrepl.console import Event - from _pyrepl.reader import Reader - -@@ -295,8 +295,8 @@ - - actual = reader.screen - self.assertEqual(len(actual), 2) -- self.assertEqual(actual[0].rstrip(), "itertools.accumulate(") -- self.assertEqual(actual[1], f"{code}a") -+ self.assertEqual(actual[0], f"{code}a") -+ self.assertEqual(actual[1].rstrip(), "itertools.accumulate(") - - def test_key_press_on_tab_press_once(self): - namespace = {"itertools": itertools} -@@ -312,3 +312,10 @@ - reader, _ = handle_all_events(events, prepare_reader=completing_reader) - - self.assert_screen_equals(reader, f"{code}a") -+ -+ def test_pos2xy_with_no_columns(self): -+ console = prepare_console([]) -+ reader = prepare_reader(console) -+ # Simulate a resize to 0 columns -+ reader.screeninfo = [] -+ self.assertEqual(reader.pos2xy(), (0, 0)) -diff --git a/Lib/test/test_pyrepl/test_unix_console.py b/Lib/test/test_pyrepl/test_unix_console.py -index e3bbabcb008..15dbf48bcf0 100644 ---- a/Lib/test/test_pyrepl/test_unix_console.py -+++ b/Lib/test/test_pyrepl/test_unix_console.py -@@ -1,7 +1,9 @@ - import itertools -+import os - import sys - import unittest - from functools import partial -+from test.support import os_helper - from unittest import TestCase - from unittest.mock import MagicMock, call, patch, ANY - -@@ -312,3 +314,14 @@ - ) - console.restore() - con.restore() -+ -+ def test_getheightwidth_with_invalid_environ(self, _os_write): -+ # gh-128636 -+ console = UnixConsole() -+ with os_helper.EnvironmentVarGuard() as env: -+ env["LINES"] = "" -+ self.assertIsInstance(console.getheightwidth(), tuple) -+ env["COLUMNS"] = "" -+ self.assertIsInstance(console.getheightwidth(), tuple) -+ os.environ = [] -+ self.assertIsInstance(console.getheightwidth(), tuple) -diff --git a/Lib/test/test_pyrepl/test_windows_console.py b/Lib/test/test_pyrepl/test_windows_console.py -index 4a3b2baf64a..07eaccd1124 100644 ---- a/Lib/test/test_pyrepl/test_windows_console.py -+++ b/Lib/test/test_pyrepl/test_windows_console.py -@@ -329,6 +329,20 @@ - def erase_in_line(self): - return ERASE_IN_LINE.encode("utf8") - -+ def test_multiline_ctrl_z(self): -+ # see gh-126332 -+ code = "abcdefghi" -+ -+ events = itertools.chain( -+ code_to_events(code), -+ [ -+ Event(evt="key", data='\x1a', raw=bytearray(b'\x1a')), -+ Event(evt="key", data='\x1a', raw=bytearray(b'\x1a')), -+ ], -+ ) -+ reader, _ = self.handle_events_narrow(events) -+ self.assertEqual(reader.cxy, (2, 3)) -+ - - if __name__ == "__main__": - unittest.main() -diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py -index 0d3599be87f..5538de60b2a 100644 ---- a/Lib/test/test_re.py -+++ b/Lib/test/test_re.py -@@ -978,18 +978,15 @@ - self.assertIsNone(re.fullmatch(br".+\B", b"abc", re.LOCALE)) - self.assertIsNone(re.fullmatch(r".+\B", "ьюÑ")) - self.assertTrue(re.fullmatch(r".+\B", "ьюÑ", re.ASCII)) -- # However, an empty string contains no word boundaries, and also no -- # non-boundaries. -+ # However, an empty string contains no word boundaries. - self.assertIsNone(re.search(r"\b", "")) - self.assertIsNone(re.search(r"\b", "", re.ASCII)) - self.assertIsNone(re.search(br"\b", b"")) - self.assertIsNone(re.search(br"\b", b"", re.LOCALE)) -- # This one is questionable and different from the perlre behaviour, -- # but describes current behavior. -- self.assertIsNone(re.search(r"\B", "")) -- self.assertIsNone(re.search(r"\B", "", re.ASCII)) -- self.assertIsNone(re.search(br"\B", b"")) -- self.assertIsNone(re.search(br"\B", b"", re.LOCALE)) -+ self.assertTrue(re.search(r"\B", "")) -+ self.assertTrue(re.search(r"\B", "", re.ASCII)) -+ self.assertTrue(re.search(br"\B", b"")) -+ self.assertTrue(re.search(br"\B", b"", re.LOCALE)) - # A single word-character string has two boundaries, but no - # non-boundary gaps. - self.assertEqual(len(re.findall(r"\b", "a")), 2) -diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py -index ab46ccbf004..969f483814d 100644 ---- a/Lib/test/test_regrtest.py -+++ b/Lib/test/test_regrtest.py -@@ -792,6 +792,7 @@ - f'{", ".join(output.splitlines())}') - - -+@support.force_not_colorized_test_class - class ProgramsTestCase(BaseTestCase): - """ - Test various ways to run the Python test suite. Use options close -@@ -905,6 +906,7 @@ - self.run_batch(script, *rt_args, *self.regrtest_args, *self.tests) - - -+@support.force_not_colorized_test_class - class ArgsTestCase(BaseTestCase): - """ - Test arguments of the Python test suite. -@@ -1183,7 +1185,7 @@ - stats=TestStats(4, 1), - forever=True) - -- @support.without_optimizer -+ @support.requires_jit_disabled - def check_leak(self, code, what, *, run_workers=False): - test = self.create_test('huntrleaks', code=code) - -@@ -2145,25 +2147,25 @@ - import unittest - from test import support - try: -- from _testinternalcapi import get_config -+ from _testcapi import config_get - except ImportError: -- get_config = None -+ config_get = None - - # WASI/WASM buildbots don't use -E option - use_environment = (support.is_emscripten or support.is_wasi) - - class WorkerTests(unittest.TestCase): -- @unittest.skipUnless(get_config is None, 'need get_config()') -+ @unittest.skipUnless(config_get is None, 'need config_get()') - def test_config(self): -- config = get_config()['config'] -+ config = config_get() - # -u option -- self.assertEqual(config['buffered_stdio'], 0) -+ self.assertEqual(config_get('buffered_stdio'), 0) - # -W default option -- self.assertTrue(config['warnoptions'], ['default']) -+ self.assertTrue(config_get('warnoptions'), ['default']) - # -bb option -- self.assertTrue(config['bytes_warning'], 2) -+ self.assertTrue(config_get('bytes_warning'), 2) - # -E option -- self.assertTrue(config['use_environment'], use_environment) -+ self.assertTrue(config_get('use_environment'), use_environment) - - def test_python_opts(self): - # -u option -diff --git a/Lib/test/test_repl.py b/Lib/test/test_repl.py -index e764e60560d..356ff5b198d 100644 ---- a/Lib/test/test_repl.py -+++ b/Lib/test/test_repl.py -@@ -70,6 +70,7 @@ - return output - - -+@support.force_not_colorized_test_class - class TestInteractiveInterpreter(unittest.TestCase): - - @cpython_only -@@ -273,6 +274,8 @@ - - self.assertEqual(exit_code, 0, "".join(output)) - -+ -+@support.force_not_colorized_test_class - class TestInteractiveModeSyntaxErrors(unittest.TestCase): - - def test_interactive_syntax_error_correct_line(self): -diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py -index b64383f6546..ada78ec8e6b 100644 ---- a/Lib/test/test_runpy.py -+++ b/Lib/test/test_runpy.py -@@ -12,8 +12,14 @@ - import textwrap - import unittest - import warnings --from test.support import (infinite_recursion, no_tracing, verbose, -- requires_subprocess, requires_resource) -+from test.support import ( -+ force_not_colorized_test_class, -+ infinite_recursion, -+ no_tracing, -+ requires_resource, -+ requires_subprocess, -+ verbose, -+) - from test.support.import_helper import forget, make_legacy_pyc, unload - from test.support.os_helper import create_empty_file, temp_dir, FakePath - from test.support.script_helper import make_script, make_zip_script -@@ -758,6 +764,7 @@ - self.assertEqual(result['s'], "non-ASCII: h\xe9") - - -+@force_not_colorized_test_class - class TestExit(unittest.TestCase): - STATUS_CONTROL_C_EXIT = 0xC000013A - EXPECTED_CODE = ( -diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py -index 1f18b1f09b5..078ddd6c431 100644 ---- a/Lib/test/test_shutil.py -+++ b/Lib/test/test_shutil.py -@@ -3239,12 +3239,8 @@ - self.assertRaises(OSError, self.zerocopy_fun, src, dst) - - --@unittest.skipIf(not SUPPORTS_SENDFILE, 'os.sendfile() not supported') --class TestZeroCopySendfile(_ZeroCopyFileTest, unittest.TestCase): -- PATCHPOINT = "os.sendfile" -- -- def zerocopy_fun(self, fsrc, fdst): -- return shutil._fastcopy_sendfile(fsrc, fdst) -+class _ZeroCopyFileLinuxTest(_ZeroCopyFileTest): -+ BLOCKSIZE_INDEX = None - - def test_non_regular_file_src(self): - with io.BytesIO(self.FILEDATA) as src: -@@ -3265,65 +3261,65 @@ - self.assertEqual(dst.read(), self.FILEDATA) - - def test_exception_on_second_call(self): -- def sendfile(*args, **kwargs): -+ def syscall(*args, **kwargs): - if not flag: - flag.append(None) -- return orig_sendfile(*args, **kwargs) -+ return orig_syscall(*args, **kwargs) - else: - raise OSError(errno.EBADF, "yo") - - flag = [] -- orig_sendfile = os.sendfile -- with unittest.mock.patch('os.sendfile', create=True, -- side_effect=sendfile): -+ orig_syscall = eval(self.PATCHPOINT) -+ with unittest.mock.patch(self.PATCHPOINT, create=True, -+ side_effect=syscall): - with self.get_files() as (src, dst): - with self.assertRaises(OSError) as cm: -- shutil._fastcopy_sendfile(src, dst) -+ self.zerocopy_fun(src, dst) - assert flag - self.assertEqual(cm.exception.errno, errno.EBADF) - - def test_cant_get_size(self): - # Emulate a case where src file size cannot be determined. - # Internally bufsize will be set to a small value and -- # sendfile() will be called repeatedly. -+ # a system call will be called repeatedly. - with unittest.mock.patch('os.fstat', side_effect=OSError) as m: - with self.get_files() as (src, dst): -- shutil._fastcopy_sendfile(src, dst) -+ self.zerocopy_fun(src, dst) - assert m.called - self.assertEqual(read_file(TESTFN2, binary=True), self.FILEDATA) - - def test_small_chunks(self): - # Force internal file size detection to be smaller than the -- # actual file size. We want to force sendfile() to be called -+ # actual file size. We want to force a system call to be called - # multiple times, also in order to emulate a src fd which gets - # bigger while it is being copied. - mock = unittest.mock.Mock() - mock.st_size = 65536 + 1 - with unittest.mock.patch('os.fstat', return_value=mock) as m: - with self.get_files() as (src, dst): -- shutil._fastcopy_sendfile(src, dst) -+ self.zerocopy_fun(src, dst) - assert m.called - self.assertEqual(read_file(TESTFN2, binary=True), self.FILEDATA) - - def test_big_chunk(self): - # Force internal file size detection to be +100MB bigger than -- # the actual file size. Make sure sendfile() does not rely on -+ # the actual file size. Make sure a system call does not rely on - # file size value except for (maybe) a better throughput / - # performance. - mock = unittest.mock.Mock() - mock.st_size = self.FILESIZE + (100 * 1024 * 1024) - with unittest.mock.patch('os.fstat', return_value=mock) as m: - with self.get_files() as (src, dst): -- shutil._fastcopy_sendfile(src, dst) -+ self.zerocopy_fun(src, dst) - assert m.called - self.assertEqual(read_file(TESTFN2, binary=True), self.FILEDATA) - - def test_blocksize_arg(self): -- with unittest.mock.patch('os.sendfile', -+ with unittest.mock.patch(self.PATCHPOINT, - side_effect=ZeroDivisionError) as m: - self.assertRaises(ZeroDivisionError, - shutil.copyfile, TESTFN, TESTFN2) -- blocksize = m.call_args[0][3] -+ blocksize = m.call_args[0][self.BLOCKSIZE_INDEX] - # Make sure file size and the block size arg passed to - # sendfile() are the same. - self.assertEqual(blocksize, os.path.getsize(TESTFN)) -@@ -3333,9 +3329,19 @@ - self.addCleanup(os_helper.unlink, TESTFN2 + '3') - self.assertRaises(ZeroDivisionError, - shutil.copyfile, TESTFN2, TESTFN2 + '3') -- blocksize = m.call_args[0][3] -+ blocksize = m.call_args[0][self.BLOCKSIZE_INDEX] - self.assertEqual(blocksize, 2 ** 23) - -+ -+@unittest.skipIf(not SUPPORTS_SENDFILE, 'os.sendfile() not supported') -+@unittest.mock.patch.object(shutil, "_USE_CP_COPY_FILE_RANGE", False) -+class TestZeroCopySendfile(_ZeroCopyFileLinuxTest, unittest.TestCase): -+ PATCHPOINT = "os.sendfile" -+ BLOCKSIZE_INDEX = 3 -+ -+ def zerocopy_fun(self, fsrc, fdst): -+ return shutil._fastcopy_sendfile(fsrc, fdst) -+ - def test_file2file_not_supported(self): - # Emulate a case where sendfile() only support file->socket - # fds. In such a case copyfile() is supposed to skip the -@@ -3358,6 +3364,29 @@ - shutil._USE_CP_SENDFILE = True - - -+@unittest.skipUnless(shutil._USE_CP_COPY_FILE_RANGE, "os.copy_file_range() not supported") -+class TestZeroCopyCopyFileRange(_ZeroCopyFileLinuxTest, unittest.TestCase): -+ PATCHPOINT = "os.copy_file_range" -+ BLOCKSIZE_INDEX = 2 -+ -+ def zerocopy_fun(self, fsrc, fdst): -+ return shutil._fastcopy_copy_file_range(fsrc, fdst) -+ -+ def test_empty_file(self): -+ srcname = f"{TESTFN}src" -+ dstname = f"{TESTFN}dst" -+ self.addCleanup(lambda: os_helper.unlink(srcname)) -+ self.addCleanup(lambda: os_helper.unlink(dstname)) -+ with open(srcname, "wb"): -+ pass -+ -+ with open(srcname, "rb") as src, open(dstname, "wb") as dst: -+ # _fastcopy_copy_file_range gives up copying empty files due -+ # to a bug in older Linux. -+ with self.assertRaises(shutil._GiveupOnFastCopy): -+ self.zerocopy_fun(src, dst) -+ -+ - @unittest.skipIf(not MACOS, 'macOS only') - class TestZeroCopyMACOS(_ZeroCopyFileTest, unittest.TestCase): - PATCHPOINT = "posix._fcopyfile" -diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py -index 704a0090bdb..72a01cd1e45 100644 ---- a/Lib/test/test_signal.py -+++ b/Lib/test/test_signal.py -@@ -253,9 +253,7 @@ - self.assertRaises((ValueError, OSError), - signal.set_wakeup_fd, fd) - -- # Emscripten does not support fstat on pipes yet. -- # https://github.com/emscripten-core/emscripten/issues/16414 -- @unittest.skipIf(support.is_emscripten, "Emscripten cannot fstat pipes.") -+ @unittest.skipIf(support.is_emscripten, "Fixed in next Emscripten release after 4.0.1") - @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") - def test_set_wakeup_fd_result(self): - r1, w1 = os.pipe() -@@ -274,7 +272,7 @@ - self.assertEqual(signal.set_wakeup_fd(-1), w2) - self.assertEqual(signal.set_wakeup_fd(-1), -1) - -- @unittest.skipIf(support.is_emscripten, "Emscripten cannot fstat pipes.") -+ @unittest.skipIf(support.is_emscripten, "Fixed in next Emscripten release after 4.0.1") - @unittest.skipUnless(support.has_socket_support, "needs working sockets.") - def test_set_wakeup_fd_socket_result(self): - sock1 = socket.socket() -@@ -295,7 +293,7 @@ - # On Windows, files are always blocking and Windows does not provide a - # function to test if a socket is in non-blocking mode. - @unittest.skipIf(sys.platform == "win32", "tests specific to POSIX") -- @unittest.skipIf(support.is_emscripten, "Emscripten cannot fstat pipes.") -+ @unittest.skipIf(support.is_emscripten, "Fixed in next Emscripten release after 4.0.1") - @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") - def test_set_wakeup_fd_blocking(self): - rfd, wfd = os.pipe() -@@ -385,7 +383,7 @@ - except ZeroDivisionError: - # An ignored exception should have been printed out on stderr - err = err.getvalue() -- if ('Exception ignored when trying to write to the signal wakeup fd' -+ if ('Exception ignored while trying to write to the signal wakeup fd' - not in err): - raise AssertionError(err) - if ('OSError: [Errno %d]' % errno.EBADF) not in err: -@@ -574,7 +572,7 @@ - signal.raise_signal(signum) - - err = err.getvalue() -- if ('Exception ignored when trying to {action} to the signal wakeup fd' -+ if ('Exception ignored while trying to {action} to the signal wakeup fd' - not in err): - raise AssertionError(err) - """.format(action=action) -@@ -644,7 +642,7 @@ - "buffer" % written) - - # By default, we get a warning when a signal arrives -- msg = ('Exception ignored when trying to {action} ' -+ msg = ('Exception ignored while trying to {action} ' - 'to the signal wakeup fd') - signal.set_wakeup_fd(write.fileno()) - -diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py -index 307d6e886c6..b77fa3cb215 100644 ---- a/Lib/test/test_socket.py -+++ b/Lib/test/test_socket.py -@@ -520,6 +520,8 @@ - @unittest.skipIf(WSL, 'VSOCK does not work on Microsoft WSL') - @unittest.skipUnless(HAVE_SOCKET_VSOCK, - 'VSOCK sockets required for this test.') -+@unittest.skipUnless(get_cid() != 2, # VMADDR_CID_HOST -+ "This test can only be run on a virtual guest.") - class ThreadedVSOCKSocketStreamTest(unittest.TestCase, ThreadableTest): - - def __init__(self, methodName='runTest'): -@@ -547,7 +549,10 @@ - self.cli.connect((cid, VSOCKPORT)) - - def testStream(self): -- msg = self.conn.recv(1024) -+ try: -+ msg = self.conn.recv(1024) -+ except PermissionError as exc: -+ self.skipTest(repr(exc)) - self.assertEqual(msg, MSG) - - def _testStream(self): -@@ -7072,6 +7077,26 @@ - self.assertEqual(data, str(index).encode()) - - -+class FreeThreadingTests(unittest.TestCase): -+ -+ def test_close_detach_race(self): -+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -+ -+ def close(): -+ for _ in range(1000): -+ s.close() -+ -+ def detach(): -+ for _ in range(1000): -+ s.detach() -+ -+ t1 = threading.Thread(target=close) -+ t2 = threading.Thread(target=detach) -+ -+ with threading_helper.start_threads([t1, t2]): -+ pass -+ -+ - def setUpModule(): - thread_info = threading_helper.threading_setup() - unittest.addModuleCleanup(threading_helper.threading_cleanup, *thread_info) -diff --git a/Lib/test/test_sqlite3/test_cli.py b/Lib/test/test_sqlite3/test_cli.py -index d014a9ce841..dcd90d11d46 100644 ---- a/Lib/test/test_sqlite3/test_cli.py -+++ b/Lib/test/test_sqlite3/test_cli.py -@@ -90,14 +90,14 @@ - out, err = self.run_cli() - self.assertIn(self.MEMORY_DB_MSG, err) - self.assertIn(self.MEMORY_DB_MSG, err) -- self.assertTrue(out.endswith(self.PS1)) -+ self.assertEndsWith(out, self.PS1) - self.assertEqual(out.count(self.PS1), 1) - self.assertEqual(out.count(self.PS2), 0) - - def test_interact_quit(self): - out, err = self.run_cli(commands=(".quit",)) - self.assertIn(self.MEMORY_DB_MSG, err) -- self.assertTrue(out.endswith(self.PS1)) -+ self.assertEndsWith(out, self.PS1) - self.assertEqual(out.count(self.PS1), 1) - self.assertEqual(out.count(self.PS2), 0) - -@@ -105,7 +105,7 @@ - out, err = self.run_cli(commands=(".version",)) - self.assertIn(self.MEMORY_DB_MSG, err) - self.assertIn(sqlite3.sqlite_version + "\n", out) -- self.assertTrue(out.endswith(self.PS1)) -+ self.assertEndsWith(out, self.PS1) - self.assertEqual(out.count(self.PS1), 2) - self.assertEqual(out.count(self.PS2), 0) - self.assertIn(sqlite3.sqlite_version, out) -@@ -114,14 +114,14 @@ - out, err = self.run_cli(commands=("SELECT 1;",)) - self.assertIn(self.MEMORY_DB_MSG, err) - self.assertIn("(1,)\n", out) -- self.assertTrue(out.endswith(self.PS1)) -+ self.assertEndsWith(out, self.PS1) - self.assertEqual(out.count(self.PS1), 2) - self.assertEqual(out.count(self.PS2), 0) - - def test_interact_incomplete_multiline_sql(self): - out, err = self.run_cli(commands=("SELECT 1",)) - self.assertIn(self.MEMORY_DB_MSG, err) -- self.assertTrue(out.endswith(self.PS2)) -+ self.assertEndsWith(out, self.PS2) - self.assertEqual(out.count(self.PS1), 1) - self.assertEqual(out.count(self.PS2), 1) - -@@ -130,7 +130,7 @@ - self.assertIn(self.MEMORY_DB_MSG, err) - self.assertIn(self.PS2, out) - self.assertIn("(1,)\n", out) -- self.assertTrue(out.endswith(self.PS1)) -+ self.assertEndsWith(out, self.PS1) - self.assertEqual(out.count(self.PS1), 2) - self.assertEqual(out.count(self.PS2), 1) - -@@ -138,7 +138,7 @@ - out, err = self.run_cli(commands=("sel;",)) - self.assertIn(self.MEMORY_DB_MSG, err) - self.assertIn("OperationalError (SQLITE_ERROR)", err) -- self.assertTrue(out.endswith(self.PS1)) -+ self.assertEndsWith(out, self.PS1) - self.assertEqual(out.count(self.PS1), 2) - self.assertEqual(out.count(self.PS2), 0) - -@@ -147,7 +147,7 @@ - - out, err = self.run_cli(TESTFN, commands=("CREATE TABLE t(t);",)) - self.assertIn(TESTFN, err) -- self.assertTrue(out.endswith(self.PS1)) -+ self.assertEndsWith(out, self.PS1) - - out, _ = self.run_cli(TESTFN, commands=("SELECT count(t) FROM t;",)) - self.assertIn("(0,)\n", out) -diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py -index 488b401fb00..c3aa3bf2d7b 100644 ---- a/Lib/test/test_sqlite3/test_dbapi.py -+++ b/Lib/test/test_sqlite3/test_dbapi.py -@@ -59,45 +59,34 @@ - sqlite.paramstyle) - - def test_warning(self): -- self.assertTrue(issubclass(sqlite.Warning, Exception), -- "Warning is not a subclass of Exception") -+ self.assertIsSubclass(sqlite.Warning, Exception) - - def test_error(self): -- self.assertTrue(issubclass(sqlite.Error, Exception), -- "Error is not a subclass of Exception") -+ self.assertIsSubclass(sqlite.Error, Exception) - - def test_interface_error(self): -- self.assertTrue(issubclass(sqlite.InterfaceError, sqlite.Error), -- "InterfaceError is not a subclass of Error") -+ self.assertIsSubclass(sqlite.InterfaceError, sqlite.Error) - - def test_database_error(self): -- self.assertTrue(issubclass(sqlite.DatabaseError, sqlite.Error), -- "DatabaseError is not a subclass of Error") -+ self.assertIsSubclass(sqlite.DatabaseError, sqlite.Error) - - def test_data_error(self): -- self.assertTrue(issubclass(sqlite.DataError, sqlite.DatabaseError), -- "DataError is not a subclass of DatabaseError") -+ self.assertIsSubclass(sqlite.DataError, sqlite.DatabaseError) - - def test_operational_error(self): -- self.assertTrue(issubclass(sqlite.OperationalError, sqlite.DatabaseError), -- "OperationalError is not a subclass of DatabaseError") -+ self.assertIsSubclass(sqlite.OperationalError, sqlite.DatabaseError) - - def test_integrity_error(self): -- self.assertTrue(issubclass(sqlite.IntegrityError, sqlite.DatabaseError), -- "IntegrityError is not a subclass of DatabaseError") -+ self.assertIsSubclass(sqlite.IntegrityError, sqlite.DatabaseError) - - def test_internal_error(self): -- self.assertTrue(issubclass(sqlite.InternalError, sqlite.DatabaseError), -- "InternalError is not a subclass of DatabaseError") -+ self.assertIsSubclass(sqlite.InternalError, sqlite.DatabaseError) - - def test_programming_error(self): -- self.assertTrue(issubclass(sqlite.ProgrammingError, sqlite.DatabaseError), -- "ProgrammingError is not a subclass of DatabaseError") -+ self.assertIsSubclass(sqlite.ProgrammingError, sqlite.DatabaseError) - - def test_not_supported_error(self): -- self.assertTrue(issubclass(sqlite.NotSupportedError, -- sqlite.DatabaseError), -- "NotSupportedError is not a subclass of DatabaseError") -+ self.assertIsSubclass(sqlite.NotSupportedError, sqlite.DatabaseError) - - def test_module_constants(self): - consts = [ -@@ -274,7 +263,7 @@ - consts.append("SQLITE_IOERR_CORRUPTFS") - for const in consts: - with self.subTest(const=const): -- self.assertTrue(hasattr(sqlite, const)) -+ self.assertHasAttr(sqlite, const) - - def test_error_code_on_exception(self): - err_msg = "unable to open database file" -@@ -288,7 +277,7 @@ - sqlite.connect(db) - e = cm.exception - self.assertEqual(e.sqlite_errorcode, err_code) -- self.assertTrue(e.sqlite_errorname.startswith("SQLITE_CANTOPEN")) -+ self.assertStartsWith(e.sqlite_errorname, "SQLITE_CANTOPEN") - - def test_extended_error_code_on_exception(self): - with memory_database() as con: -@@ -425,7 +414,7 @@ - ] - for exc in exceptions: - with self.subTest(exc=exc): -- self.assertTrue(hasattr(self.cx, exc)) -+ self.assertHasAttr(self.cx, exc) - self.assertIs(getattr(sqlite, exc), getattr(self.cx, exc)) - - def test_interrupt_on_closed_db(self): -@@ -1935,5 +1924,70 @@ - self.assertEqual(proc.returncode, 0) - - -+class RowTests(unittest.TestCase): -+ -+ def setUp(self): -+ self.cx = sqlite.connect(":memory:") -+ self.cx.row_factory = sqlite.Row -+ -+ def tearDown(self): -+ self.cx.close() -+ -+ def test_row_keys(self): -+ cu = self.cx.execute("SELECT 1 as first, 2 as second") -+ row = cu.fetchone() -+ self.assertEqual(row.keys(), ["first", "second"]) -+ -+ def test_row_length(self): -+ cu = self.cx.execute("SELECT 1, 2, 3") -+ row = cu.fetchone() -+ self.assertEqual(len(row), 3) -+ -+ def test_row_getitem(self): -+ cu = self.cx.execute("SELECT 1 as a, 2 as b") -+ row = cu.fetchone() -+ self.assertEqual(row[0], 1) -+ self.assertEqual(row[1], 2) -+ self.assertEqual(row["a"], 1) -+ self.assertEqual(row["b"], 2) -+ for key in "nokey", 4, 1.2: -+ with self.subTest(key=key): -+ with self.assertRaises(IndexError): -+ row[key] -+ -+ def test_row_equality(self): -+ c1 = self.cx.execute("SELECT 1 as a") -+ r1 = c1.fetchone() -+ -+ c2 = self.cx.execute("SELECT 1 as a") -+ r2 = c2.fetchone() -+ -+ self.assertIsNot(r1, r2) -+ self.assertEqual(r1, r2) -+ -+ c3 = self.cx.execute("SELECT 1 as b") -+ r3 = c3.fetchone() -+ -+ self.assertNotEqual(r1, r3) -+ -+ def test_row_no_description(self): -+ cu = self.cx.cursor() -+ self.assertIsNone(cu.description) -+ -+ row = sqlite.Row(cu, ()) -+ self.assertEqual(row.keys(), []) -+ with self.assertRaisesRegex(IndexError, "nokey"): -+ row["nokey"] -+ -+ def test_row_is_a_sequence(self): -+ from collections.abc import Sequence -+ -+ cu = self.cx.execute("SELECT 1") -+ row = cu.fetchone() -+ -+ self.assertIsSubclass(sqlite.Row, Sequence) -+ self.assertIsInstance(row, Sequence) -+ -+ - if __name__ == "__main__": - unittest.main() -diff --git a/Lib/test/test_sqlite3/test_dump.py b/Lib/test/test_sqlite3/test_dump.py -index 550cea41976..e18a207e9f6 100644 ---- a/Lib/test/test_sqlite3/test_dump.py -+++ b/Lib/test/test_sqlite3/test_dump.py -@@ -4,6 +4,7 @@ - - from .util import memory_database - from .util import MemoryDatabaseMixin -+from .util import requires_virtual_table - - - class DumpTests(MemoryDatabaseMixin, unittest.TestCase): -@@ -206,6 +207,7 @@ - self.assertEqual(expected, actual) - self.assertEqual(self.cx.row_factory, dict_factory) - -+ @requires_virtual_table("fts4") - def test_dump_virtual_tables(self): - # gh-64662 - expected = [ -diff --git a/Lib/test/test_sqlite3/test_factory.py b/Lib/test/test_sqlite3/test_factory.py -index 48d35b54a2e..cc9f1ec5c4b 100644 ---- a/Lib/test/test_sqlite3/test_factory.py -+++ b/Lib/test/test_sqlite3/test_factory.py -@@ -280,7 +280,7 @@ - austria = "Österreich" - row = self.con.execute("select ?", (austria,)).fetchone() - self.assertEqual(type(row[0]), str, "type of row[0] must be unicode") -- self.assertTrue(row[0].endswith("reich"), "column must contain original data") -+ self.assertEndsWith(row[0], "reich", "column must contain original data") - - - class TextFactoryTestsWithEmbeddedZeroBytes(unittest.TestCase): -diff --git a/Lib/test/test_sqlite3/test_hooks.py b/Lib/test/test_sqlite3/test_hooks.py -index 49e72f8fcfb..53b8a39bf29 100644 ---- a/Lib/test/test_sqlite3/test_hooks.py -+++ b/Lib/test/test_sqlite3/test_hooks.py -@@ -196,7 +196,7 @@ - con.execute("select 1 union select 2 union select 3").fetchall() - self.assertEqual(action, 0, "progress handler was not cleared") - -- @with_tracebacks(ZeroDivisionError, name="bad_progress") -+ @with_tracebacks(ZeroDivisionError, msg_regex="bad_progress") - def test_error_in_progress_handler(self): - def bad_progress(): - 1 / 0 -@@ -206,7 +206,7 @@ - create table foo(a, b) - """) - -- @with_tracebacks(ZeroDivisionError, name="bad_progress") -+ @with_tracebacks(ZeroDivisionError, msg_regex="bad_progress") - def test_error_in_progress_handler_result(self): - class BadBool: - def __bool__(self): -diff --git a/Lib/test/test_sqlite3/test_userfunctions.py b/Lib/test/test_sqlite3/test_userfunctions.py -index c6c3db159ad..3abc43a3b1a 100644 ---- a/Lib/test/test_sqlite3/test_userfunctions.py -+++ b/Lib/test/test_sqlite3/test_userfunctions.py -@@ -171,7 +171,7 @@ - self.con.close() - - def test_func_error_on_create(self): -- with self.assertRaises(sqlite.OperationalError): -+ with self.assertRaisesRegex(sqlite.ProgrammingError, "not -100"): - self.con.create_function("bla", -100, lambda x: 2*x) - - def test_func_too_many_args(self): -@@ -254,7 +254,7 @@ - cur.execute("select returnnan()") - self.assertIsNone(cur.fetchone()[0]) - -- @with_tracebacks(ZeroDivisionError, name="func_raiseexception") -+ @with_tracebacks(ZeroDivisionError, msg_regex="func_raiseexception") - def test_func_exception(self): - cur = self.con.cursor() - with self.assertRaises(sqlite.OperationalError) as cm: -@@ -262,14 +262,14 @@ - cur.fetchone() - self.assertEqual(str(cm.exception), 'user-defined function raised exception') - -- @with_tracebacks(MemoryError, name="func_memoryerror") -+ @with_tracebacks(MemoryError, msg_regex="func_memoryerror") - def test_func_memory_error(self): - cur = self.con.cursor() - with self.assertRaises(MemoryError): - cur.execute("select memoryerror()") - cur.fetchone() - -- @with_tracebacks(OverflowError, name="func_overflowerror") -+ @with_tracebacks(OverflowError, msg_regex="func_overflowerror") - def test_func_overflow_error(self): - cur = self.con.cursor() - with self.assertRaises(sqlite.DataError): -@@ -389,7 +389,7 @@ - with self.assertRaisesRegex(sqlite.DataError, msg): - cur.execute("select largeint()") - -- @with_tracebacks(UnicodeEncodeError, "surrogates not allowed", "chr") -+ @with_tracebacks(UnicodeEncodeError, "surrogates not allowed") - def test_func_return_text_with_surrogates(self): - cur = self.con.cursor() - self.con.create_function("pychr", 1, chr) -@@ -507,9 +507,8 @@ - self.assertEqual(self.cur.fetchall(), self.expected) - - def test_win_error_on_create(self): -- self.assertRaises(sqlite.ProgrammingError, -- self.con.create_window_function, -- "shouldfail", -100, WindowSumInt) -+ with self.assertRaisesRegex(sqlite.ProgrammingError, "not -100"): -+ self.con.create_window_function("shouldfail", -100, WindowSumInt) - - @with_tracebacks(BadWindow) - def test_win_exception_in_method(self): -@@ -638,10 +637,10 @@ - self.con.close() - - def test_aggr_error_on_create(self): -- with self.assertRaises(sqlite.OperationalError): -+ with self.assertRaisesRegex(sqlite.ProgrammingError, "not -100"): - self.con.create_function("bla", -100, AggrSum) - -- @with_tracebacks(AttributeError, name="AggrNoStep") -+ @with_tracebacks(AttributeError, msg_regex="AggrNoStep") - def test_aggr_no_step(self): - cur = self.con.cursor() - with self.assertRaises(sqlite.OperationalError) as cm: -@@ -656,7 +655,7 @@ - cur.execute("select nofinalize(t) from test") - val = cur.fetchone()[0] - -- @with_tracebacks(ZeroDivisionError, name="AggrExceptionInInit") -+ @with_tracebacks(ZeroDivisionError, msg_regex="AggrExceptionInInit") - def test_aggr_exception_in_init(self): - cur = self.con.cursor() - with self.assertRaises(sqlite.OperationalError) as cm: -@@ -664,7 +663,7 @@ - val = cur.fetchone()[0] - self.assertEqual(str(cm.exception), "user-defined aggregate's '__init__' method raised error") - -- @with_tracebacks(ZeroDivisionError, name="AggrExceptionInStep") -+ @with_tracebacks(ZeroDivisionError, msg_regex="AggrExceptionInStep") - def test_aggr_exception_in_step(self): - cur = self.con.cursor() - with self.assertRaises(sqlite.OperationalError) as cm: -@@ -672,7 +671,7 @@ - val = cur.fetchone()[0] - self.assertEqual(str(cm.exception), "user-defined aggregate's 'step' method raised error") - -- @with_tracebacks(ZeroDivisionError, name="AggrExceptionInFinalize") -+ @with_tracebacks(ZeroDivisionError, msg_regex="AggrExceptionInFinalize") - def test_aggr_exception_in_finalize(self): - cur = self.con.cursor() - with self.assertRaises(sqlite.OperationalError) as cm: -@@ -822,11 +821,11 @@ - raise ValueError - return sqlite.SQLITE_OK - -- @with_tracebacks(ValueError, name="authorizer_cb") -+ @with_tracebacks(ValueError, msg_regex="authorizer_cb") - def test_table_access(self): - super().test_table_access() - -- @with_tracebacks(ValueError, name="authorizer_cb") -+ @with_tracebacks(ValueError, msg_regex="authorizer_cb") - def test_column_access(self): - super().test_table_access() - -diff --git a/Lib/test/test_sqlite3/util.py b/Lib/test/test_sqlite3/util.py -index 5599823838b..cccd062160f 100644 ---- a/Lib/test/test_sqlite3/util.py -+++ b/Lib/test/test_sqlite3/util.py -@@ -4,6 +4,7 @@ - import re - import sqlite3 - import test.support -+import unittest - - - # Helper for temporary memory databases -@@ -22,15 +23,16 @@ - cx.setlimit(category, _prev) - - --def with_tracebacks(exc, regex="", name=""): -+def with_tracebacks(exc, regex="", name="", msg_regex=""): - """Convenience decorator for testing callback tracebacks.""" - def decorator(func): -- _regex = re.compile(regex) if regex else None -+ exc_regex = re.compile(regex) if regex else None -+ _msg_regex = re.compile(msg_regex) if msg_regex else None - @functools.wraps(func) - def wrapper(self, *args, **kwargs): - with test.support.catch_unraisable_exception() as cm: - # First, run the test with traceback enabled. -- with check_tracebacks(self, cm, exc, _regex, name): -+ with check_tracebacks(self, cm, exc, exc_regex, _msg_regex, name): - func(self, *args, **kwargs) - - # Then run the test with traceback disabled. -@@ -40,7 +42,7 @@ - - - @contextlib.contextmanager --def check_tracebacks(self, cm, exc, regex, obj_name): -+def check_tracebacks(self, cm, exc, exc_regex, msg_regex, obj_name): - """Convenience context manager for testing callback tracebacks.""" - sqlite3.enable_callback_tracebacks(True) - try: -@@ -49,9 +51,12 @@ - yield - - self.assertEqual(cm.unraisable.exc_type, exc) -- if regex: -+ if exc_regex: - msg = str(cm.unraisable.exc_value) -- self.assertIsNotNone(regex.search(msg)) -+ self.assertIsNotNone(exc_regex.search(msg), (exc_regex, msg)) -+ if msg_regex: -+ msg = cm.unraisable.err_msg -+ self.assertIsNotNone(msg_regex.search(msg), (msg_regex, msg)) - if obj_name: - self.assertEqual(cm.unraisable.object.__name__, obj_name) - finally: -@@ -75,3 +80,10 @@ - @property - def cu(self): - return self.cur -+ -+ -+def requires_virtual_table(module): -+ with memory_database() as cx: -+ supported = (module,) in list(cx.execute("PRAGMA module_list")) -+ reason = f"Requires {module!r} virtual table support" -+ return unittest.skipUnless(supported, reason) -diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py -index 3f6f890bbdc..9863f3ffe97 100644 ---- a/Lib/test/test_ssl.py -+++ b/Lib/test/test_ssl.py -@@ -1325,8 +1325,7 @@ - def test_load_dh_params(self): - ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) - ctx.load_dh_params(DHFILE) -- if os.name != 'nt': -- ctx.load_dh_params(BYTES_DHFILE) -+ ctx.load_dh_params(BYTES_DHFILE) - self.assertRaises(TypeError, ctx.load_dh_params) - self.assertRaises(TypeError, ctx.load_dh_params, None) - with self.assertRaises(FileNotFoundError) as cm: -@@ -4494,7 +4493,8 @@ - s.connect((HOST, server.port)) - - --@unittest.skipUnless(has_tls_version('TLSv1_3'), "Test needs TLS 1.3") -+@unittest.skipUnless(has_tls_version('TLSv1_3') and ssl.HAS_PHA, -+ "Test needs TLS 1.3 PHA") - class TestPostHandshakeAuth(unittest.TestCase): - def test_pha_setter(self): - protocols = [ -diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py -index fa08dc6a25b..f3724ce6d4d 100644 ---- a/Lib/test/test_stable_abi_ctypes.py -+++ b/Lib/test/test_stable_abi_ctypes.py -@@ -901,6 +901,8 @@ - "Py_MakePendingCalls", - "Py_NewInterpreter", - "Py_NewRef", -+ "Py_PACK_FULL_VERSION", -+ "Py_PACK_VERSION", - "Py_REFCNT", - "Py_ReprEnter", - "Py_ReprLeave", -diff --git a/Lib/test/test_str.py b/Lib/test/test_str.py -index 4de6c1cba15..d1c9542c7d1 100644 ---- a/Lib/test/test_str.py -+++ b/Lib/test/test_str.py -@@ -7,6 +7,7 @@ - """ - import _string - import codecs -+import datetime - import itertools - import operator - import pickle -@@ -1908,6 +1909,12 @@ - self.assertRaises(UnicodeDecodeError, - (b'\xF4'+cb+b'\xBF\xBF').decode, 'utf-8') - -+ def test_issue127903(self): -+ # gh-127903: ``_copy_characters`` crashes on DEBUG builds when -+ # there is nothing to copy. -+ d = datetime.datetime(2013, 11, 10, 14, 20, 59) -+ self.assertEqual(d.strftime('%z'), '') -+ - def test_issue8271(self): - # Issue #8271: during the decoding of an invalid UTF-8 byte sequence, - # only the start byte and the continuation byte(s) are now considered -diff --git a/Lib/test/test_string.py b/Lib/test/test_string.py -index 824b89ad517..f6d112d8a93 100644 ---- a/Lib/test/test_string.py -+++ b/Lib/test/test_string.py -@@ -1,6 +1,7 @@ - import unittest - import string - from string import Template -+import types - - - class ModuleTest(unittest.TestCase): -@@ -101,6 +102,24 @@ - with self.assertRaises(KeyError): - fmt.format("{0[2]}{0[0]}", {}) - -+ def test_auto_numbering_lookup(self): -+ fmt = string.Formatter() -+ namespace = types.SimpleNamespace(foo=types.SimpleNamespace(bar='baz')) -+ widths = [None, types.SimpleNamespace(qux=4)] -+ self.assertEqual( -+ fmt.format("{.foo.bar:{[1].qux}}", namespace, widths), 'baz ') -+ -+ def test_auto_numbering_reenterability(self): -+ class ReenteringFormatter(string.Formatter): -+ def format_field(self, value, format_spec): -+ if format_spec.isdigit() and int(format_spec) > 0: -+ return self.format('{:{}}!', value, int(format_spec) - 1) -+ else: -+ return super().format_field(value, format_spec) -+ fmt = ReenteringFormatter() -+ x = types.SimpleNamespace(a='X') -+ self.assertEqual(fmt.format('{.a:{}}', x, 3), 'X!!!') -+ - def test_override_get_value(self): - class NamespaceFormatter(string.Formatter): - def __init__(self, namespace={}): -diff --git a/Lib/test/test_string_literals.py b/Lib/test/test_string_literals.py -index c7c6f684cd3..f56195ca276 100644 ---- a/Lib/test/test_string_literals.py -+++ b/Lib/test/test_string_literals.py -@@ -116,7 +116,9 @@ - warnings.simplefilter('always', category=SyntaxWarning) - eval("'''\n\\z'''") - self.assertEqual(len(w), 1) -- self.assertEqual(str(w[0].message), r"invalid escape sequence '\z'") -+ self.assertEqual(str(w[0].message), r'"\z" is an invalid escape sequence. ' -+ r'Such sequences will not work in the future. ' -+ r'Did you mean "\\z"? A raw string is also an option.') - self.assertEqual(w[0].filename, '') - self.assertEqual(w[0].lineno, 1) - -@@ -126,7 +128,8 @@ - eval("'''\n\\z'''") - exc = cm.exception - self.assertEqual(w, []) -- self.assertEqual(exc.msg, r"invalid escape sequence '\z'") -+ self.assertEqual(exc.msg, r'"\z" is an invalid escape sequence. ' -+ r'Did you mean "\\z"? A raw string is also an option.') - self.assertEqual(exc.filename, '') - self.assertEqual(exc.lineno, 1) - self.assertEqual(exc.offset, 1) -@@ -153,7 +156,9 @@ - eval("'''\n\\407'''") - self.assertEqual(len(w), 1) - self.assertEqual(str(w[0].message), -- r"invalid octal escape sequence '\407'") -+ r'"\407" is an invalid octal escape sequence. ' -+ r'Such sequences will not work in the future. ' -+ r'Did you mean "\\407"? A raw string is also an option.') - self.assertEqual(w[0].filename, '') - self.assertEqual(w[0].lineno, 1) - -@@ -163,7 +168,8 @@ - eval("'''\n\\407'''") - exc = cm.exception - self.assertEqual(w, []) -- self.assertEqual(exc.msg, r"invalid octal escape sequence '\407'") -+ self.assertEqual(exc.msg, r'"\407" is an invalid octal escape sequence. ' -+ r'Did you mean "\\407"? A raw string is also an option.') - self.assertEqual(exc.filename, '') - self.assertEqual(exc.lineno, 1) - self.assertEqual(exc.offset, 1) -@@ -205,7 +211,9 @@ - warnings.simplefilter('always', category=SyntaxWarning) - eval("b'''\n\\z'''") - self.assertEqual(len(w), 1) -- self.assertEqual(str(w[0].message), r"invalid escape sequence '\z'") -+ self.assertEqual(str(w[0].message), r'"\z" is an invalid escape sequence. ' -+ r'Such sequences will not work in the future. ' -+ r'Did you mean "\\z"? A raw string is also an option.') - self.assertEqual(w[0].filename, '') - self.assertEqual(w[0].lineno, 1) - -@@ -215,7 +223,8 @@ - eval("b'''\n\\z'''") - exc = cm.exception - self.assertEqual(w, []) -- self.assertEqual(exc.msg, r"invalid escape sequence '\z'") -+ self.assertEqual(exc.msg, r'"\z" is an invalid escape sequence. ' -+ r'Did you mean "\\z"? A raw string is also an option.') - self.assertEqual(exc.filename, '') - self.assertEqual(exc.lineno, 1) - -@@ -228,8 +237,9 @@ - warnings.simplefilter('always', category=SyntaxWarning) - eval("b'''\n\\407'''") - self.assertEqual(len(w), 1) -- self.assertEqual(str(w[0].message), -- r"invalid octal escape sequence '\407'") -+ self.assertEqual(str(w[0].message), r'"\407" is an invalid octal escape sequence. ' -+ r'Such sequences will not work in the future. ' -+ r'Did you mean "\\407"? A raw string is also an option.') - self.assertEqual(w[0].filename, '') - self.assertEqual(w[0].lineno, 1) - -@@ -239,7 +249,8 @@ - eval("b'''\n\\407'''") - exc = cm.exception - self.assertEqual(w, []) -- self.assertEqual(exc.msg, r"invalid octal escape sequence '\407'") -+ self.assertEqual(exc.msg, r'"\407" is an invalid octal escape sequence. ' -+ r'Did you mean "\\407"? A raw string is also an option.') - self.assertEqual(exc.filename, '') - self.assertEqual(exc.lineno, 1) - -diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py -index 5fee9fbb92a..b99391e482f 100644 ---- a/Lib/test/test_struct.py -+++ b/Lib/test/test_struct.py -@@ -694,7 +694,7 @@ - rc, stdout, stderr = assert_python_ok("-c", code) - self.assertEqual(rc, 0) - self.assertEqual(stdout.rstrip(), b"") -- self.assertIn(b"Exception ignored in:", stderr) -+ self.assertIn(b"Exception ignored while calling deallocator", stderr) - self.assertIn(b"C.__del__", stderr) - - def test__struct_reference_cycle_cleaned_up(self): -diff --git a/Lib/test/test_super.py b/Lib/test/test_super.py -index 14901663552..5cef612a340 100644 ---- a/Lib/test/test_super.py -+++ b/Lib/test/test_super.py -@@ -9,9 +9,6 @@ - from test.support import import_helper, threading_helper - - --ADAPTIVE_WARMUP_DELAY = 2 -- -- - class A: - def f(self): - return 'A' -@@ -466,7 +463,8 @@ - super(MyType, type(mytype)).__setattr__(mytype, "bar", 1) - self.assertEqual(mytype.bar, 1) - -- for _ in range(ADAPTIVE_WARMUP_DELAY): -+ _testinternalcapi = import_helper.import_module("_testinternalcapi") -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - test("foo1") - - def test_reassigned_new(self): -@@ -485,7 +483,8 @@ - def __new__(cls): - return super().__new__(cls) - -- for _ in range(ADAPTIVE_WARMUP_DELAY): -+ _testinternalcapi = import_helper.import_module("_testinternalcapi") -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - C() - - def test_mixed_staticmethod_hierarchy(self): -@@ -505,7 +504,8 @@ - def some(cls): - return super().some(cls) - -- for _ in range(ADAPTIVE_WARMUP_DELAY): -+ _testinternalcapi = import_helper.import_module("_testinternalcapi") -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - C.some(C) - - @threading_helper.requires_working_threading() -diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py -index d839893d2c6..39857445a02 100644 ---- a/Lib/test/test_sys.py -+++ b/Lib/test/test_sys.py -@@ -1621,7 +1621,7 @@ - return sys._getframe() - x = func() - if support.Py_GIL_DISABLED: -- INTERPRETER_FRAME = '10PhcP' -+ INTERPRETER_FRAME = '9PihcP' - else: - INTERPRETER_FRAME = '9PhcP' - check(x, size('3PiccPP' + INTERPRETER_FRAME + 'P')) -diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py -index 95cf0d1ec2d..28c2c681bab 100644 ---- a/Lib/test/test_sys_settrace.py -+++ b/Lib/test/test_sys_settrace.py -@@ -6,8 +6,7 @@ - import difflib - import gc - from functools import wraps --import asyncio --from test.support import import_helper, requires_subprocess -+from test.support import import_helper, requires_subprocess, run_no_yield_async_fn - import contextlib - import os - import tempfile -@@ -19,8 +18,6 @@ - except ImportError: - _testinternalcapi = None - --support.requires_working_socket(module=True) -- - class tracecontext: - """Context manager that traces its enter and exit.""" - def __init__(self, output, value): -@@ -2067,10 +2064,9 @@ - stack.enter_context(self.assertRaisesRegex(*error)) - if warning is not None: - stack.enter_context(self.assertWarnsRegex(*warning)) -- asyncio.run(func(output)) -+ run_no_yield_async_fn(func, output) - - sys.settrace(None) -- asyncio.set_event_loop_policy(None) - self.compare_jump_output(expected, output) - - def jump_test(jumpFrom, jumpTo, expected, error=None, event='line', warning=None): -diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py -index ce504dc21af..3738914cf17 100644 ---- a/Lib/test/test_sysconfig.py -+++ b/Lib/test/test_sysconfig.py -@@ -20,7 +20,7 @@ - from test.support.import_helper import import_module - from test.support.os_helper import (TESTFN, unlink, skip_unless_symlink, - change_cwd) --from test.support.venv import VirtualEnvironment -+from test.support.venv import VirtualEnvironmentMixin - - import sysconfig - from sysconfig import (get_paths, get_platform, get_config_vars, -@@ -37,7 +37,7 @@ - HAS_USER_BASE = sysconfig._HAS_USER_BASE - - --class TestSysConfig(unittest.TestCase): -+class TestSysConfig(unittest.TestCase, VirtualEnvironmentMixin): - - def setUp(self): - super(TestSysConfig, self).setUp() -@@ -111,13 +111,6 @@ - elif os.path.isdir(path): - shutil.rmtree(path) - -- def venv(self, **venv_create_args): -- return VirtualEnvironment.from_tmpdir( -- prefix=f'{self.id()}-venv-', -- **venv_create_args, -- ) -- -- - def test_get_path_names(self): - self.assertEqual(get_path_names(), sysconfig._SCHEME_KEYS) - -@@ -650,8 +643,21 @@ - - system_config_vars = get_config_vars() - -- # Ignore keys in the check -- for key in ('projectbase', 'srcdir'): -+ ignore_keys = set() -+ # Keys dependent on Python being run outside the build directrory -+ if sysconfig.is_python_build(): -+ ignore_keys |= {'srcdir'} -+ # Keys dependent on the executable location -+ if os.path.dirname(sys.executable) != system_config_vars['BINDIR']: -+ ignore_keys |= {'projectbase'} -+ # Keys dependent on the environment (different inside virtual environments) -+ if sys.prefix != sys.base_prefix: -+ ignore_keys |= {'prefix', 'exec_prefix', 'base', 'platbase'} -+ # Keys dependent on Python being run from the prefix targetted when building (different on relocatable installs) -+ if sysconfig._installation_is_relocated(): -+ ignore_keys |= {'prefix', 'exec_prefix', 'base', 'platbase', 'installed_base', 'installed_platbase'} -+ -+ for key in ignore_keys: - json_config_vars.pop(key) - system_config_vars.pop(key) - -@@ -711,5 +717,38 @@ - }) - - -+class DeprecationTests(unittest.TestCase): -+ def deprecated(self, removal_version, deprecation_msg=None, error=Exception, error_msg=None): -+ if sys.version_info >= removal_version: -+ return self.assertRaises(error, msg=error_msg) -+ else: -+ return self.assertWarns(DeprecationWarning, msg=deprecation_msg) -+ -+ def test_expand_makefile_vars(self): -+ with self.deprecated( -+ removal_version=(3, 16), -+ deprecation_msg=( -+ 'sysconfig.expand_makefile_vars is deprecated and will be removed in ' -+ 'Python 3.16. Use sysconfig.get_paths(vars=...) instead.', -+ ), -+ error=AttributeError, -+ error_msg="module 'sysconfig' has no attribute 'expand_makefile_vars'", -+ ): -+ sysconfig.expand_makefile_vars('', {}) -+ -+ def test_is_python_build_check_home(self): -+ with self.deprecated( -+ removal_version=(3, 15), -+ deprecation_msg=( -+ 'The check_home argument of sysconfig.is_python_build is ' -+ 'deprecated and its value is ignored. ' -+ 'It will be removed in Python 3.15.' -+ ), -+ error=TypeError, -+ error_msg="is_python_build() takes 0 positional arguments but 1 were given", -+ ): -+ sysconfig.is_python_build('foo') -+ -+ - if __name__ == "__main__": - unittest.main() -diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py -index 57e9bd20c77..7adc021d298 100644 ---- a/Lib/test/test_tempfile.py -+++ b/Lib/test/test_tempfile.py -@@ -1112,11 +1112,14 @@ - # Testing extreme case, where the file is not explicitly closed - # f.close() - return tmp_name -- # Make sure that the garbage collector has finalized the file object. -- gc.collect() - dir = tempfile.mkdtemp() - try: -- tmp_name = my_func(dir) -+ with self.assertWarnsRegex( -+ expected_warning=ResourceWarning, -+ expected_regex=r"Implicitly cleaning up <_TemporaryFileWrapper file=.*>", -+ ): -+ tmp_name = my_func(dir) -+ support.gc_collect() - self.assertFalse(os.path.exists(tmp_name), - f"NamedTemporaryFile {tmp_name!r} " - f"exists after finalizer ") -diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py -index 3e164a12581..214e1ba0b53 100644 ---- a/Lib/test/test_threading.py -+++ b/Lib/test/test_threading.py -@@ -2130,6 +2130,15 @@ - - # Test long non-ASCII name (truncated) - "x" * (limit - 1) + "é€", -+ -+ # Test long non-BMP names (truncated) creating surrogate pairs -+ # on Windows -+ "x" * (limit - 1) + "\U0010FFFF", -+ "x" * (limit - 2) + "\U0010FFFF" * 2, -+ "x" + "\U0001f40d" * limit, -+ "xx" + "\U0001f40d" * limit, -+ "xxx" + "\U0001f40d" * limit, -+ "xxxx" + "\U0001f40d" * limit, - ] - if os_helper.FS_NONASCII: - tests.append(f"nonascii:{os_helper.FS_NONASCII}") -@@ -2146,15 +2155,31 @@ - work_name = _thread._get_name() - - for name in tests: -- encoded = name.encode(encoding, "replace") -- if b'\0' in encoded: -- encoded = encoded.split(b'\0', 1)[0] -- if truncate is not None: -- encoded = encoded[:truncate] -- if sys.platform.startswith("solaris"): -- expected = encoded.decode("utf-8", "surrogateescape") -+ if not support.MS_WINDOWS: -+ encoded = name.encode(encoding, "replace") -+ if b'\0' in encoded: -+ encoded = encoded.split(b'\0', 1)[0] -+ if truncate is not None: -+ encoded = encoded[:truncate] -+ if sys.platform.startswith("solaris"): -+ expected = encoded.decode("utf-8", "surrogateescape") -+ else: -+ expected = os.fsdecode(encoded) - else: -- expected = os.fsdecode(encoded) -+ size = 0 -+ chars = [] -+ for ch in name: -+ if ord(ch) > 0xFFFF: -+ size += 2 -+ else: -+ size += 1 -+ if size > truncate: -+ break -+ chars.append(ch) -+ expected = ''.join(chars) -+ -+ if '\0' in expected: -+ expected = expected.split('\0', 1)[0] - - with self.subTest(name=name, expected=expected): - work_name = None -diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py -index 1c540bed33c..1147997d8d8 100644 ---- a/Lib/test/test_time.py -+++ b/Lib/test/test_time.py -@@ -158,10 +158,19 @@ - self.assertEqual(int(time.mktime(time.localtime(self.t))), - int(self.t)) - -- def test_sleep(self): -+ def test_sleep_exceptions(self): -+ self.assertRaises(TypeError, time.sleep, []) -+ self.assertRaises(TypeError, time.sleep, "a") -+ self.assertRaises(TypeError, time.sleep, complex(0, 0)) -+ - self.assertRaises(ValueError, time.sleep, -2) - self.assertRaises(ValueError, time.sleep, -1) -- time.sleep(1.2) -+ self.assertRaises(ValueError, time.sleep, -0.1) -+ -+ def test_sleep(self): -+ for value in [-0.0, 0, 0.0, 1e-100, 1e-9, 1e-6, 1, 1.2]: -+ with self.subTest(value=value): -+ time.sleep(value) - - def test_epoch(self): - # bpo-43869: Make sure that Python use the same Epoch on all platforms: -diff --git a/Lib/test/test_tkinter/test_misc.py b/Lib/test/test_tkinter/test_misc.py -index 475edcbd533..96ea3f0117c 100644 ---- a/Lib/test/test_tkinter/test_misc.py -+++ b/Lib/test/test_tkinter/test_misc.py -@@ -4,7 +4,8 @@ - from tkinter import TclError - import enum - from test import support --from test.test_tkinter.support import AbstractTkTest, AbstractDefaultRootTest, requires_tk -+from test.test_tkinter.support import (AbstractTkTest, AbstractDefaultRootTest, -+ requires_tk, get_tk_patchlevel) - - support.requires('gui') - -@@ -30,12 +31,20 @@ - self.assertEqual(repr(f), '') - - def test_generated_names(self): -+ class Button2(tkinter.Button): -+ pass -+ - t = tkinter.Toplevel(self.root) - f = tkinter.Frame(t) - f2 = tkinter.Frame(t) -+ self.assertNotEqual(str(f), str(f2)) - b = tkinter.Button(f2) -- for name in str(b).split('.'): -+ b2 = Button2(f2) -+ for name in str(b).split('.') + str(b2).split('.'): - self.assertFalse(name.isidentifier(), msg=repr(name)) -+ b3 = tkinter.Button(f2) -+ b4 = Button2(f2) -+ self.assertEqual(len({str(b), str(b2), str(b3), str(b4)}), 4) - - @requires_tk(8, 6, 6) - def test_tk_busy(self): -@@ -554,6 +563,31 @@ - self.assertEqual(w.wm_attributes('alpha'), - 1.0 if self.wantobjects else '1.0') - -+ def test_wm_iconbitmap(self): -+ t = tkinter.Toplevel(self.root) -+ self.assertEqual(t.wm_iconbitmap(), '') -+ t.wm_iconbitmap('hourglass') -+ bug = False -+ if t._windowingsystem == 'aqua': -+ # Tk bug 13ac26b35dc55f7c37f70b39d59d7ef3e63017c8. -+ patchlevel = get_tk_patchlevel(t) -+ if patchlevel < (8, 6, 17) or (9, 0) <= patchlevel < (9, 0, 2): -+ bug = True -+ if not bug: -+ self.assertEqual(t.wm_iconbitmap(), 'hourglass') -+ self.assertEqual(self.root.wm_iconbitmap(), '') -+ t.wm_iconbitmap('') -+ self.assertEqual(t.wm_iconbitmap(), '') -+ -+ if t._windowingsystem == 'win32': -+ t.wm_iconbitmap(default='hourglass') -+ self.assertEqual(t.wm_iconbitmap(), 'hourglass') -+ self.assertEqual(self.root.wm_iconbitmap(), '') -+ t.wm_iconbitmap(default='') -+ self.assertEqual(t.wm_iconbitmap(), '') -+ -+ t.destroy() -+ - - class EventTest(AbstractTkTest, unittest.TestCase): - -diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py -index 75710db7d05..52d33419750 100644 ---- a/Lib/test/test_tokenize.py -+++ b/Lib/test/test_tokenize.py -@@ -1,4 +1,5 @@ - import os -+import re - import token - import tokenize - import unittest -@@ -1537,6 +1538,7 @@ - self.assertEqual(encoding, 'utf-8') - self.assertEqual(consumed_lines, [b'print("#coding=fake")']) - -+ @support.thread_unsafe - def test_open(self): - filename = os_helper.TESTFN + '.py' - self.addCleanup(os_helper.unlink, filename) -@@ -1819,6 +1821,22 @@ - self.assertEqual(tokenize.untokenize(iter(tokens)), b'Hello ') - - -+def contains_ambiguous_backslash(source): -+ """Return `True` if the source contains a backslash on a -+ line by itself. For example: -+ -+ a = (1 -+ \\ -+ ) -+ -+ Code like this cannot be untokenized exactly. This is because -+ the tokenizer does not produce any tokens for the line containing -+ the backslash and so there is no way to know its indent. -+ """ -+ pattern = re.compile(br'\n\s*\\\r?\n') -+ return pattern.search(source) is not None -+ -+ - class TestRoundtrip(TestCase): - - def check_roundtrip(self, f): -@@ -1829,6 +1847,9 @@ - tokenize.untokenize(), and the latter tokenized again to 2-tuples. - The test fails if the 3 pair tokenizations do not match. - -+ If the source code can be untokenized unambiguously, the -+ untokenized code must match the original code exactly. -+ - When untokenize bugs are fixed, untokenize with 5-tuples should - reproduce code that does not contain a backslash continuation - following spaces. A proper test should test this. -@@ -1852,6 +1873,13 @@ - tokens2_from5 = [tok[:2] for tok in tokenize.tokenize(readline5)] - self.assertEqual(tokens2_from5, tokens2) - -+ if not contains_ambiguous_backslash(code): -+ # The BOM does not produce a token so there is no way to preserve it. -+ code_without_bom = code.removeprefix(b'\xef\xbb\xbf') -+ readline = iter(code_without_bom.splitlines(keepends=True)).__next__ -+ untokenized_code = tokenize.untokenize(tokenize.tokenize(readline)) -+ self.assertEqual(code_without_bom, untokenized_code) -+ - def check_line_extraction(self, f): - if isinstance(f, str): - code = f.encode('utf-8') -diff --git a/Lib/test/test_tomllib/test_misc.py b/Lib/test/test_tomllib/test_misc.py -index 9e677a337a2..59116afa1f3 100644 ---- a/Lib/test/test_tomllib/test_misc.py -+++ b/Lib/test/test_tomllib/test_misc.py -@@ -5,6 +5,7 @@ - import copy - import datetime - from decimal import Decimal as D -+import importlib - from pathlib import Path - import sys - import tempfile -@@ -113,3 +114,11 @@ - nest_count=nest_count): - recursive_table_toml = nest_count * "key = {" + nest_count * "}" - tomllib.loads(recursive_table_toml) -+ -+ def test_types_import(self): -+ """Test that `_types` module runs. -+ -+ The module is for type annotations only, so it is otherwise -+ never imported by tests. -+ """ -+ importlib.import_module(f"{tomllib.__name__}._types") -diff --git a/Lib/test/test_tools/i18n_data/docstrings.pot b/Lib/test/test_tools/i18n_data/docstrings.pot -index 5af1d41422f..387db2413a5 100644 ---- a/Lib/test/test_tools/i18n_data/docstrings.pot -+++ b/Lib/test/test_tools/i18n_data/docstrings.pot -@@ -15,26 +15,40 @@ - "Generated-By: pygettext.py 1.5\n" - - --#: docstrings.py:7 -+#: docstrings.py:1 -+#, docstring -+msgid "Module docstring" -+msgstr "" -+ -+#: docstrings.py:9 - #, docstring - msgid "" - msgstr "" - --#: docstrings.py:18 -+#: docstrings.py:15 -+#, docstring -+msgid "docstring" -+msgstr "" -+ -+#: docstrings.py:20 - #, docstring - msgid "" - "multiline\n" --" docstring\n" --" " -+"docstring" - msgstr "" - --#: docstrings.py:25 -+#: docstrings.py:27 - #, docstring - msgid "docstring1" - msgstr "" - --#: docstrings.py:30 -+#: docstrings.py:38 -+#, docstring -+msgid "nested docstring" -+msgstr "" -+ -+#: docstrings.py:43 - #, docstring --msgid "Hello, {}!" -+msgid "nested class docstring" - msgstr "" - -diff --git a/Lib/test/test_tools/i18n_data/docstrings.py b/Lib/test/test_tools/i18n_data/docstrings.py -index 85d7f159d37..151a55a4b56 100644 ---- a/Lib/test/test_tools/i18n_data/docstrings.py -+++ b/Lib/test/test_tools/i18n_data/docstrings.py -@@ -1,3 +1,5 @@ -+"""Module docstring""" -+ - # Test docstring extraction - from gettext import gettext as _ - -@@ -10,10 +12,10 @@ - # Leading empty line - def test2(x): - -- """docstring""" # XXX This should be extracted but isn't. -+ """docstring""" - - --# XXX Multiline docstrings should be cleaned with `inspect.cleandoc`. -+# Multiline docstrings are cleaned with `inspect.cleandoc`. - def test3(x): - """multiline - docstring -@@ -27,15 +29,15 @@ - - - def test5(x): -- """Hello, {}!""".format("world!") # XXX This should not be extracted. -+ """Hello, {}!""".format("world!") # This should not be extracted. - - - # Nested docstrings - def test6(x): - def inner(y): -- """nested docstring""" # XXX This should be extracted but isn't. -+ """nested docstring""" - - - class Outer: - class Inner: -- "nested class docstring" # XXX This should be extracted but isn't. -+ "nested class docstring" -diff --git a/Lib/test/test_tools/i18n_data/messages.pot b/Lib/test/test_tools/i18n_data/messages.pot -index 8d66fbc4f3a..e8167acfc07 100644 ---- a/Lib/test/test_tools/i18n_data/messages.pot -+++ b/Lib/test/test_tools/i18n_data/messages.pot -@@ -19,22 +19,22 @@ - msgid "" - msgstr "" - --#: messages.py:19 messages.py:20 -+#: messages.py:19 messages.py:20 messages.py:21 - msgid "parentheses" - msgstr "" - --#: messages.py:23 -+#: messages.py:24 - msgid "Hello, world!" - msgstr "" - --#: messages.py:26 -+#: messages.py:27 - msgid "" - "Hello,\n" - " multiline!\n" - msgstr "" - - #: messages.py:46 messages.py:89 messages.py:90 messages.py:93 messages.py:94 --#: messages.py:99 -+#: messages.py:99 messages.py:100 messages.py:101 - msgid "foo" - msgid_plural "foos" - msgstr[0] "" -@@ -68,7 +68,7 @@ - msgid "set" - msgstr "" - --#: messages.py:63 -+#: messages.py:62 messages.py:63 - msgid "nested string" - msgstr "" - -@@ -76,6 +76,10 @@ - msgid "baz" - msgstr "" - -+#: messages.py:71 messages.py:75 -+msgid "default value" -+msgstr "" -+ - #: messages.py:91 messages.py:92 messages.py:95 messages.py:96 - msgctxt "context" - msgid "foo" -@@ -83,7 +87,13 @@ - msgstr[0] "" - msgstr[1] "" - --#: messages.py:100 -+#: messages.py:102 - msgid "domain foo" - msgstr "" - -+#: messages.py:118 messages.py:119 -+msgid "world" -+msgid_plural "worlds" -+msgstr[0] "" -+msgstr[1] "" -+ -diff --git a/Lib/test/test_tools/i18n_data/messages.py b/Lib/test/test_tools/i18n_data/messages.py -index 1e03f4e5568..9457bcb8611 100644 ---- a/Lib/test/test_tools/i18n_data/messages.py -+++ b/Lib/test/test_tools/i18n_data/messages.py -@@ -18,6 +18,7 @@ - # Extra parentheses - (_("parentheses")) - ((_("parentheses"))) -+_(("parentheses")) - - # Multiline strings - _("Hello, " -@@ -32,7 +33,6 @@ - _(None) - _(1) - _(False) --_(("invalid")) - _(["invalid"]) - _({"invalid"}) - _("string"[3]) -@@ -40,7 +40,7 @@ - _({"string": "foo"}) - - # pygettext does not allow keyword arguments, but both xgettext and pybabel do --_(x="kwargs work!") -+_(x="kwargs are not allowed!") - - # Unusual, but valid arguments - _("foo", "bar") -@@ -48,7 +48,7 @@ - - # .format() - _("Hello, {}!").format("world") # valid --_("Hello, {}!".format("world")) # invalid, but xgettext and pybabel extract the first string -+_("Hello, {}!".format("world")) # invalid, but xgettext extracts the first string - - # Nested structures - _("1"), _("2") -@@ -59,7 +59,7 @@ - - # Nested functions and classes - def test(): -- _("nested string") # XXX This should be extracted but isn't. -+ _("nested string") - [_("nested string")] - - -@@ -68,11 +68,11 @@ - return _("baz") - - --def bar(x=_('default value')): # XXX This should be extracted but isn't. -+def bar(x=_('default value')): - pass - - --def baz(x=[_('default value')]): # XXX This should be extracted but isn't. -+def baz(x=[_('default value')]): - pass - - -@@ -97,6 +97,8 @@ - - # Complex arguments - ngettext("foo", "foos", 42 + (10 - 20)) -+ngettext("foo", "foos", *args) -+ngettext("foo", "foos", **kwargs) - dgettext(["some", {"complex"}, ("argument",)], "domain foo") - - # Invalid calls which are not extracted -@@ -108,3 +110,10 @@ - dngettext('domain', 'foo') - dpgettext('domain', 'context') - dnpgettext('domain', 'context', 'foo') -+dgettext(*args, 'foo') -+dpgettext(*args, 'context', 'foo') -+dnpgettext(*args, 'context', 'foo', 'foos') -+ -+# f-strings -+f"Hello, {_('world')}!" -+f"Hello, {ngettext('world', 'worlds', 3)}!" -diff --git a/Lib/test/test_tools/test_i18n.py b/Lib/test/test_tools/test_i18n.py -index 29c3423e234..d23479104d4 100644 ---- a/Lib/test/test_tools/test_i18n.py -+++ b/Lib/test/test_tools/test_i18n.py -@@ -87,7 +87,7 @@ - self.maxDiff = None - self.assertEqual(normalize_POT_file(expected), normalize_POT_file(actual)) - -- def extract_from_str(self, module_content, *, args=(), strict=True): -+ def extract_from_str(self, module_content, *, args=(), strict=True, with_stderr=False): - """Return all msgids extracted from module_content.""" - filename = 'test.py' - with temp_cwd(None): -@@ -98,12 +98,18 @@ - self.assertEqual(res.err, b'') - with open('messages.pot', encoding='utf-8') as fp: - data = fp.read() -- return self.get_msgids(data) -+ msgids = self.get_msgids(data) -+ if not with_stderr: -+ return msgids -+ return msgids, res.err - - def extract_docstrings_from_str(self, module_content): - """Return all docstrings extracted from module_content.""" - return self.extract_from_str(module_content, args=('--docstrings',), strict=False) - -+ def get_stderr(self, module_content): -+ return self.extract_from_str(module_content, strict=False, with_stderr=True)[1] -+ - def test_header(self): - """Make sure the required fields are in the header, according to: - http://www.gnu.org/software/gettext/manual/gettext.html#Header-Entry -@@ -407,6 +413,24 @@ - self.assertIn(f'msgid "{text2}"', data) - self.assertNotIn(text3, data) - -+ def test_error_messages(self): -+ """Test that pygettext outputs error messages to stderr.""" -+ stderr = self.get_stderr(dedent('''\ -+ _(1+2) -+ ngettext('foo') -+ dgettext(*args, 'foo') -+ ''')) -+ -+ # Normalize line endings on Windows -+ stderr = stderr.decode('utf-8').replace('\r', '') -+ -+ self.assertEqual( -+ stderr, -+ "*** test.py:1: Expected a string constant for argument 1, got 1 + 2\n" -+ "*** test.py:2: Expected at least 2 positional argument(s) in gettext call, got 1\n" -+ "*** test.py:3: Variable positional arguments are not allowed in gettext calls\n" -+ ) -+ - - def update_POT_snapshots(): - for input_file in DATA_DIR.glob('*.py'): -diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py -index 31f0a61d6a9..89980ae6f85 100644 ---- a/Lib/test/test_traceback.py -+++ b/Lib/test/test_traceback.py -@@ -21,7 +21,7 @@ - from test.support.os_helper import TESTFN, unlink - from test.support.script_helper import assert_python_ok, assert_python_failure - from test.support.import_helper import forget --from test.support import force_not_colorized -+from test.support import force_not_colorized, force_not_colorized_test_class - - import json - import textwrap -@@ -86,7 +86,7 @@ - err = self.get_exception_format(self.syntax_error_with_caret, - SyntaxError) - self.assertEqual(len(err), 4) -- self.assertTrue(err[1].strip() == "return x!") -+ self.assertEqual(err[1].strip(), "return x!") - self.assertIn("^", err[2]) # third line has caret - self.assertEqual(err[1].find("!"), err[2].find("^")) # in the right place - self.assertEqual(err[2].count("^"), 1) -@@ -376,6 +376,30 @@ - ' ValueError: 0\n', - ]) - -+ def test_format_exception_group_syntax_error_with_custom_values(self): -+ # See https://github.com/python/cpython/issues/128894 -+ for exc in [ -+ SyntaxError('error', 'abcd'), -+ SyntaxError('error', [None] * 4), -+ SyntaxError('error', (1, 2, 3, 4)), -+ SyntaxError('error', (1, 2, 3, 4)), -+ SyntaxError('error', (1, 'a', 'b', 2)), -+ # with end_lineno and end_offset: -+ SyntaxError('error', 'abcdef'), -+ SyntaxError('error', [None] * 6), -+ SyntaxError('error', (1, 2, 3, 4, 5, 6)), -+ SyntaxError('error', (1, 'a', 'b', 2, 'c', 'd')), -+ ]: -+ with self.subTest(exc=exc): -+ err = traceback.format_exception_only(exc, show_group=True) -+ # Should not raise an exception: -+ if exc.lineno is not None: -+ self.assertEqual(len(err), 2) -+ self.assertTrue(err[0].startswith(' File')) -+ else: -+ self.assertEqual(len(err), 1) -+ self.assertEqual(err[-1], 'SyntaxError: error\n') -+ - @requires_subprocess() - @force_not_colorized - def test_encoded_file(self): -@@ -419,16 +443,10 @@ - err_line = "raise RuntimeError('{0}')".format(message_ascii) - err_msg = "RuntimeError: {0}".format(message_ascii) - -- self.assertIn(("line %s" % lineno), stdout[1], -- "Invalid line number: {0!r} instead of {1}".format( -- stdout[1], lineno)) -- self.assertTrue(stdout[2].endswith(err_line), -- "Invalid traceback line: {0!r} instead of {1!r}".format( -- stdout[2], err_line)) -+ self.assertIn("line %s" % lineno, stdout[1]) -+ self.assertEndsWith(stdout[2], err_line) - actual_err_msg = stdout[3] -- self.assertTrue(actual_err_msg == err_msg, -- "Invalid error message: {0!r} instead of {1!r}".format( -- actual_err_msg, err_msg)) -+ self.assertEqual(actual_err_msg, err_msg) - - do_test("", "foo", "ascii", 3) - for charset in ("ascii", "iso-8859-1", "utf-8", "GBK"): -@@ -1712,6 +1730,7 @@ - - - @requires_debug_ranges() -+@force_not_colorized_test_class - class PurePythonTracebackErrorCaretTests( - PurePythonExceptionFormattingMixin, - TracebackErrorLocationCaretTestBase, -@@ -1725,6 +1744,7 @@ - - @cpython_only - @requires_debug_ranges() -+@force_not_colorized_test_class - class CPythonTracebackErrorCaretTests( - CAPIExceptionFormattingMixin, - TracebackErrorLocationCaretTestBase, -@@ -1736,6 +1756,7 @@ - - @cpython_only - @requires_debug_ranges() -+@force_not_colorized_test_class - class CPythonTracebackLegacyErrorCaretTests( - CAPIExceptionFormattingLegacyMixin, - TracebackErrorLocationCaretTestBase, -@@ -1806,9 +1827,9 @@ - banner = tb_lines[0] - self.assertEqual(len(tb_lines), 5) - location, source_line = tb_lines[-2], tb_lines[-1] -- self.assertTrue(banner.startswith('Traceback')) -- self.assertTrue(location.startswith(' File')) -- self.assertTrue(source_line.startswith(' raise')) -+ self.assertStartsWith(banner, 'Traceback') -+ self.assertStartsWith(location, ' File') -+ self.assertStartsWith(source_line, ' raise') - - def test_traceback_format(self): - self.check_traceback_format() -@@ -2149,10 +2170,12 @@ - boundaries = re.compile( - '(%s|%s)' % (re.escape(cause_message), re.escape(context_message))) - -+@force_not_colorized_test_class - class TestTracebackFormat(unittest.TestCase, TracebackFormatMixin): - pass - - @cpython_only -+@force_not_colorized_test_class - class TestFallbackTracebackFormat(unittest.TestCase, TracebackFormatMixin): - DEBUG_RANGES = False - def setUp(self) -> None: -@@ -2185,12 +2208,12 @@ - def check_zero_div(self, msg): - lines = msg.splitlines() - if has_no_debug_ranges(): -- self.assertTrue(lines[-3].startswith(' File')) -+ self.assertStartsWith(lines[-3], ' File') - self.assertIn('1/0 # In zero_div', lines[-2]) - else: -- self.assertTrue(lines[-4].startswith(' File')) -+ self.assertStartsWith(lines[-4], ' File') - self.assertIn('1/0 # In zero_div', lines[-3]) -- self.assertTrue(lines[-1].startswith('ZeroDivisionError'), lines[-1]) -+ self.assertStartsWith(lines[-1], 'ZeroDivisionError') - - def test_simple(self): - try: -@@ -2200,12 +2223,12 @@ - lines = self.get_report(e).splitlines() - if has_no_debug_ranges(): - self.assertEqual(len(lines), 4) -- self.assertTrue(lines[3].startswith('ZeroDivisionError')) -+ self.assertStartsWith(lines[3], 'ZeroDivisionError') - else: - self.assertEqual(len(lines), 5) -- self.assertTrue(lines[4].startswith('ZeroDivisionError')) -- self.assertTrue(lines[0].startswith('Traceback')) -- self.assertTrue(lines[1].startswith(' File')) -+ self.assertStartsWith(lines[4], 'ZeroDivisionError') -+ self.assertStartsWith(lines[0], 'Traceback') -+ self.assertStartsWith(lines[1], ' File') - self.assertIn('1/0 # Marker', lines[2]) - - def test_cause(self): -@@ -2246,9 +2269,9 @@ - e = _ - lines = self.get_report(e).splitlines() - self.assertEqual(len(lines), 4) -- self.assertTrue(lines[3].startswith('ZeroDivisionError')) -- self.assertTrue(lines[0].startswith('Traceback')) -- self.assertTrue(lines[1].startswith(' File')) -+ self.assertStartsWith(lines[3], 'ZeroDivisionError') -+ self.assertStartsWith(lines[0], 'Traceback') -+ self.assertStartsWith(lines[1], ' File') - self.assertIn('ZeroDivisionError from None', lines[2]) - - def test_cause_and_context(self): -@@ -2914,6 +2937,33 @@ - report = self.get_report(exc) - self.assertEqual(report, expected) - -+ def test_exception_group_wrapped_naked(self): -+ # See gh-128799 -+ -+ def exc(): -+ try: -+ raise Exception(42) -+ except* Exception as e: -+ raise -+ -+ expected = (f' + Exception Group Traceback (most recent call last):\n' -+ f' | File "{__file__}", line {self.callable_line}, in get_exception\n' -+ f' | exception_or_callable()\n' -+ f' | ~~~~~~~~~~~~~~~~~~~~~^^\n' -+ f' | File "{__file__}", line {exc.__code__.co_firstlineno + 3}, in exc\n' -+ f' | except* Exception as e:\n' -+ f' | raise\n' -+ f' | ExceptionGroup: (1 sub-exception)\n' -+ f' +-+---------------- 1 ----------------\n' -+ f' | Traceback (most recent call last):\n' -+ f' | File "{__file__}", line {exc.__code__.co_firstlineno + 2}, in exc\n' -+ f' | raise Exception(42)\n' -+ f' | Exception: 42\n' -+ f' +------------------------------------\n') -+ -+ report = self.get_report(exc) -+ self.assertEqual(report, expected) -+ - def test_KeyboardInterrupt_at_first_line_of_frame(self): - # see GH-93249 - def f(): -@@ -2940,6 +2990,7 @@ - self.assertEqual(report, expected) - - -+@force_not_colorized_test_class - class PyExcReportingTests(BaseExceptionReportingTests, unittest.TestCase): - # - # This checks reporting through the 'traceback' module, with both -@@ -2956,6 +3007,7 @@ - return s - - -+@force_not_colorized_test_class - class CExcReportingTests(BaseExceptionReportingTests, unittest.TestCase): - # - # This checks built-in reporting by the interpreter. -diff --git a/Lib/test/test_tracemalloc.py b/Lib/test/test_tracemalloc.py -index 5755f7697de..0220a83d24b 100644 ---- a/Lib/test/test_tracemalloc.py -+++ b/Lib/test/test_tracemalloc.py -@@ -1,14 +1,16 @@ - import contextlib - import os - import sys -+import textwrap - import tracemalloc - import unittest - from unittest.mock import patch - from test.support.script_helper import (assert_python_ok, assert_python_failure, - interpreter_requires_environment) - from test import support --from test.support import os_helper - from test.support import force_not_colorized -+from test.support import os_helper -+from test.support import threading_helper - - try: - import _testcapi -@@ -18,6 +20,7 @@ - _testinternalcapi = None - - -+DEFAULT_DOMAIN = 0 - EMPTY_STRING_SIZE = sys.getsizeof(b'') - INVALID_NFRAME = (-1, 2**30) - -@@ -952,7 +955,6 @@ - return - self.fail(f"unexpected output: {stderr!a}") - -- - def test_env_var_invalid(self): - for nframe in INVALID_NFRAME: - with self.subTest(nframe=nframe): -@@ -981,6 +983,7 @@ - return - self.fail(f"unexpected output: {stderr!a}") - -+ @force_not_colorized - def test_sys_xoptions_invalid(self): - for nframe in INVALID_NFRAME: - with self.subTest(nframe=nframe): -@@ -1026,8 +1029,8 @@ - release_gil) - return frames - -- def untrack(self): -- _testcapi.tracemalloc_untrack(self.domain, self.ptr) -+ def untrack(self, release_gil=False): -+ _testcapi.tracemalloc_untrack(self.domain, self.ptr, release_gil) - - def get_traced_memory(self): - # Get the traced size in the domain -@@ -1069,7 +1072,7 @@ - self.assertEqual(self.get_traceback(), - tracemalloc.Traceback(frames)) - -- def test_untrack(self): -+ def check_untrack(self, release_gil): - tracemalloc.start() - - self.track() -@@ -1077,13 +1080,19 @@ - self.assertEqual(self.get_traced_memory(), self.size) - - # untrack must remove the trace -- self.untrack() -+ self.untrack(release_gil) - self.assertIsNone(self.get_traceback()) - self.assertEqual(self.get_traced_memory(), 0) - - # calling _PyTraceMalloc_Untrack() multiple times must not crash -- self.untrack() -- self.untrack() -+ self.untrack(release_gil) -+ self.untrack(release_gil) -+ -+ def test_untrack(self): -+ self.check_untrack(False) -+ -+ def test_untrack_without_gil(self): -+ self.check_untrack(True) - - def test_stop_track(self): - tracemalloc.start() -@@ -1101,6 +1110,37 @@ - with self.assertRaises(RuntimeError): - self.untrack() - -+ @unittest.skipIf(_testcapi is None, 'need _testcapi') -+ @threading_helper.requires_working_threading() -+ # gh-128679: Test crash on a debug build (especially on FreeBSD). -+ @unittest.skipIf(support.Py_DEBUG, 'need release build') -+ def test_tracemalloc_track_race(self): -+ # gh-128679: Test fix for tracemalloc.stop() race condition -+ _testcapi.tracemalloc_track_race() -+ -+ def test_late_untrack(self): -+ code = textwrap.dedent(f""" -+ from test import support -+ import tracemalloc -+ import _testcapi -+ -+ class Tracked: -+ def __init__(self, domain, size): -+ self.domain = domain -+ self.ptr = id(self) -+ self.size = size -+ _testcapi.tracemalloc_track(self.domain, self.ptr, self.size) -+ -+ def __del__(self, untrack=_testcapi.tracemalloc_untrack): -+ untrack(self.domain, self.ptr, 1) -+ -+ domain = {DEFAULT_DOMAIN} -+ tracemalloc.start() -+ obj = Tracked(domain, 1024 * 1024) -+ support.late_deletion(obj) -+ """) -+ assert_python_ok("-c", code) -+ - - if __name__ == "__main__": - unittest.main() -diff --git a/Lib/test/test_turtle.py b/Lib/test/test_turtle.py -index c75a002a89b..d02cac284a9 100644 ---- a/Lib/test/test_turtle.py -+++ b/Lib/test/test_turtle.py -@@ -1,9 +1,9 @@ - import os - import pickle - import re -+import tempfile - import unittest - import unittest.mock --import tempfile - from test import support - from test.support import import_helper - from test.support import os_helper -@@ -54,6 +54,21 @@ - """ - - -+def patch_screen(): -+ """Patch turtle._Screen for testing without a display. -+ -+ We must patch the _Screen class itself instead of the _Screen -+ instance because instantiating it requires a display. -+ """ -+ return unittest.mock.patch( -+ "turtle._Screen.__new__", -+ **{ -+ "return_value.__class__": turtle._Screen, -+ "return_value.mode.return_value": "standard", -+ }, -+ ) -+ -+ - class TurtleConfigTest(unittest.TestCase): - - def get_cfg_file(self, cfg_str): -@@ -513,7 +528,7 @@ - - turtle.TurtleScreen.save(screen, file_path, overwrite=True) - with open(file_path) as f: -- assert f.read() == "postscript" -+ self.assertEqual(f.read(), "postscript") - - def test_save(self) -> None: - screen = unittest.mock.Mock() -@@ -524,7 +539,101 @@ - - turtle.TurtleScreen.save(screen, file_path) - with open(file_path) as f: -- assert f.read() == "postscript" -+ self.assertEqual(f.read(), "postscript") -+ -+ def test_no_animation_sets_tracer_0(self): -+ s = turtle.TurtleScreen(cv=unittest.mock.MagicMock()) -+ -+ with s.no_animation(): -+ self.assertEqual(s.tracer(), 0) -+ -+ def test_no_animation_resets_tracer_to_old_value(self): -+ s = turtle.TurtleScreen(cv=unittest.mock.MagicMock()) -+ -+ for tracer in [0, 1, 5]: -+ s.tracer(tracer) -+ with s.no_animation(): -+ pass -+ self.assertEqual(s.tracer(), tracer) -+ -+ def test_no_animation_calls_update_at_exit(self): -+ s = turtle.TurtleScreen(cv=unittest.mock.MagicMock()) -+ s.update = unittest.mock.MagicMock() -+ -+ with s.no_animation(): -+ s.update.assert_not_called() -+ s.update.assert_called_once() -+ -+ -+class TestTurtle(unittest.TestCase): -+ def setUp(self): -+ with patch_screen(): -+ self.turtle = turtle.Turtle() -+ -+ # Reset the Screen singleton to avoid reference leaks -+ self.addCleanup(setattr, turtle.Turtle, '_screen', None) -+ -+ def test_begin_end_fill(self): -+ self.assertFalse(self.turtle.filling()) -+ self.turtle.begin_fill() -+ self.assertTrue(self.turtle.filling()) -+ self.turtle.end_fill() -+ self.assertFalse(self.turtle.filling()) -+ -+ def test_fill(self): -+ # The context manager behaves like begin_fill and end_fill. -+ self.assertFalse(self.turtle.filling()) -+ with self.turtle.fill(): -+ self.assertTrue(self.turtle.filling()) -+ self.assertFalse(self.turtle.filling()) -+ -+ def test_fill_resets_after_exception(self): -+ # The context manager cleans up correctly after exceptions. -+ try: -+ with self.turtle.fill(): -+ self.assertTrue(self.turtle.filling()) -+ raise ValueError -+ except ValueError: -+ self.assertFalse(self.turtle.filling()) -+ -+ def test_fill_context_when_filling(self): -+ # The context manager works even when the turtle is already filling. -+ self.turtle.begin_fill() -+ self.assertTrue(self.turtle.filling()) -+ with self.turtle.fill(): -+ self.assertTrue(self.turtle.filling()) -+ self.assertFalse(self.turtle.filling()) -+ -+ def test_begin_end_poly(self): -+ self.assertFalse(self.turtle._creatingPoly) -+ self.turtle.begin_poly() -+ self.assertTrue(self.turtle._creatingPoly) -+ self.turtle.end_poly() -+ self.assertFalse(self.turtle._creatingPoly) -+ -+ def test_poly(self): -+ # The context manager behaves like begin_poly and end_poly. -+ self.assertFalse(self.turtle._creatingPoly) -+ with self.turtle.poly(): -+ self.assertTrue(self.turtle._creatingPoly) -+ self.assertFalse(self.turtle._creatingPoly) -+ -+ def test_poly_resets_after_exception(self): -+ # The context manager cleans up correctly after exceptions. -+ try: -+ with self.turtle.poly(): -+ self.assertTrue(self.turtle._creatingPoly) -+ raise ValueError -+ except ValueError: -+ self.assertFalse(self.turtle._creatingPoly) -+ -+ def test_poly_context_when_creating_poly(self): -+ # The context manager works when the turtle is already creating poly. -+ self.turtle.begin_poly() -+ self.assertTrue(self.turtle._creatingPoly) -+ with self.turtle.poly(): -+ self.assertTrue(self.turtle._creatingPoly) -+ self.assertFalse(self.turtle._creatingPoly) - - - class TestModuleLevel(unittest.TestCase): -diff --git a/Lib/test/test_type_annotations.py b/Lib/test/test_type_annotations.py -index 7d88f4cdfa3..0afcd76af15 100644 ---- a/Lib/test/test_type_annotations.py -+++ b/Lib/test/test_type_annotations.py -@@ -1,4 +1,5 @@ - import annotationlib -+import inspect - import textwrap - import types - import unittest -@@ -380,6 +381,11 @@ - annotate(None) - self.assertEqual(annotate(annotationlib.Format.VALUE), {"x": int}) - -+ sig = inspect.signature(annotate) -+ self.assertEqual(sig, inspect.Signature([ -+ inspect.Parameter("format", inspect.Parameter.POSITIONAL_ONLY) -+ ])) -+ - def test_comprehension_in_annotation(self): - # This crashed in an earlier version of the code - ns = run_code("x: [y for y in range(10)]") -@@ -400,6 +406,7 @@ - - def test_name_clash_with_format(self): - # this test would fail if __annotate__'s parameter was called "format" -+ # during symbol table construction - code = """ - class format: pass - -@@ -408,3 +415,45 @@ - ns = run_code(code) - f = ns["f"] - self.assertEqual(f.__annotations__, {"x": ns["format"]}) -+ -+ code = """ -+ class Outer: -+ class format: pass -+ -+ def meth(self, x: format): ... -+ """ -+ ns = run_code(code) -+ self.assertEqual(ns["Outer"].meth.__annotations__, {"x": ns["Outer"].format}) -+ -+ code = """ -+ def f(format): -+ def inner(x: format): pass -+ return inner -+ res = f("closure var") -+ """ -+ ns = run_code(code) -+ self.assertEqual(ns["res"].__annotations__, {"x": "closure var"}) -+ -+ code = """ -+ def f(x: format): -+ pass -+ """ -+ ns = run_code(code) -+ # picks up the format() builtin -+ self.assertEqual(ns["f"].__annotations__, {"x": format}) -+ -+ code = """ -+ def outer(): -+ def f(x: format): -+ pass -+ if False: -+ class format: pass -+ return f -+ f = outer() -+ """ -+ ns = run_code(code) -+ with self.assertRaisesRegex( -+ NameError, -+ "cannot access free variable 'format' where it is not associated with a value in enclosing scope", -+ ): -+ ns["f"].__annotations__ -diff --git a/Lib/test/test_type_cache.py b/Lib/test/test_type_cache.py -index e109a657413..ee64f89358e 100644 ---- a/Lib/test/test_type_cache.py -+++ b/Lib/test/test_type_cache.py -@@ -131,7 +131,7 @@ - return set(instr.opname for instr in dis.Bytecode(func, adaptive=True)) - - def _check_specialization(self, func, arg, opname, *, should_specialize): -- for _ in range(100): -+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): - func(arg) - - if should_specialize: -diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py -index 433b19593bd..0f393def827 100644 ---- a/Lib/test/test_type_params.py -+++ b/Lib/test/test_type_params.py -@@ -1,11 +1,10 @@ - import annotationlib --import asyncio - import textwrap - import types - import unittest - import pickle - import weakref --from test.support import requires_working_socket, check_syntax_error, run_code -+from test.support import check_syntax_error, run_code, run_no_yield_async_fn - - from typing import Generic, NoDefault, Sequence, TypeAliasType, TypeVar, TypeVarTuple, ParamSpec, get_args - -@@ -1051,7 +1050,6 @@ - self.assertIsInstance(c, TypeVar) - self.assertEqual(c.__name__, "C") - -- @requires_working_socket() - def test_typevar_coroutine(self): - def get_coroutine[A](): - async def coroutine[B](): -@@ -1060,8 +1058,7 @@ - - co = get_coroutine() - -- self.addCleanup(asyncio.set_event_loop_policy, None) -- a, b = asyncio.run(co()) -+ a, b = run_no_yield_async_fn(co) - - self.assertIsInstance(a, TypeVar) - self.assertEqual(a.__name__, "A") -diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py -index aa42beca5f9..f002d28df60 100644 ---- a/Lib/test/test_typing.py -+++ b/Lib/test/test_typing.py -@@ -45,6 +45,7 @@ - import textwrap - import typing - import weakref -+import warnings - import types - - from test.support import captured_stderr, cpython_only, infinite_recursion, requires_docstrings, import_helper, run_code -@@ -58,20 +59,6 @@ - - class BaseTestCase(TestCase): - -- def assertIsSubclass(self, cls, class_or_tuple, msg=None): -- if not issubclass(cls, class_or_tuple): -- message = '%r is not a subclass of %r' % (cls, class_or_tuple) -- if msg is not None: -- message += ' : %s' % msg -- raise self.failureException(message) -- -- def assertNotIsSubclass(self, cls, class_or_tuple, msg=None): -- if issubclass(cls, class_or_tuple): -- message = '%r is a subclass of %r' % (cls, class_or_tuple) -- if msg is not None: -- message += ' : %s' % msg -- raise self.failureException(message) -- - def clear_caches(self): - for f in typing._cleanups: - f() -@@ -122,21 +109,24 @@ - - def test_errors(self): - with self.assertRaises(TypeError): -- issubclass(42, Any) -+ isinstance(42, Any) - with self.assertRaises(TypeError): - Any[int] # Any is not a generic type. - - def test_can_subclass(self): - class Mock(Any): pass -- self.assertTrue(issubclass(Mock, Any)) -+ self.assertIsSubclass(Mock, Any) - self.assertIsInstance(Mock(), Mock) - - class Something: pass -- self.assertFalse(issubclass(Something, Any)) -+ self.assertNotIsSubclass(Something, Any) - self.assertNotIsInstance(Something(), Mock) - - class MockSomething(Something, Mock): pass -- self.assertTrue(issubclass(MockSomething, Any)) -+ self.assertIsSubclass(MockSomething, Any) -+ self.assertIsSubclass(MockSomething, MockSomething) -+ self.assertIsSubclass(MockSomething, Something) -+ self.assertIsSubclass(MockSomething, Mock) - ms = MockSomething() - self.assertIsInstance(ms, MockSomething) - self.assertIsInstance(ms, Something) -@@ -1248,10 +1238,6 @@ - - class TypeVarTupleTests(BaseTestCase): - -- def assertEndsWith(self, string, tail): -- if not string.endswith(tail): -- self.fail(f"String {string!r} does not end with {tail!r}") -- - def test_name(self): - Ts = TypeVarTuple('Ts') - self.assertEqual(Ts.__name__, 'Ts') -@@ -2010,13 +1996,81 @@ - u = Union[int, float] - self.assertNotEqual(u, Union) - -- def test_subclass_error(self): -+ def test_union_isinstance(self): -+ self.assertIsInstance(42, Union[int, str]) -+ self.assertIsInstance('abc', Union[int, str]) -+ self.assertNotIsInstance(3.14, Union[int, str]) -+ self.assertIsInstance(42, Union[int, list[int]]) -+ self.assertIsInstance(42, Union[int, Any]) -+ -+ def test_union_isinstance_type_error(self): -+ with self.assertRaises(TypeError): -+ isinstance(42, Union[str, list[int]]) -+ with self.assertRaises(TypeError): -+ isinstance(42, Union[list[int], int]) -+ with self.assertRaises(TypeError): -+ isinstance(42, Union[list[int], str]) -+ with self.assertRaises(TypeError): -+ isinstance(42, Union[str, Any]) -+ with self.assertRaises(TypeError): -+ isinstance(42, Union[Any, int]) -+ with self.assertRaises(TypeError): -+ isinstance(42, Union[Any, str]) -+ -+ def test_optional_isinstance(self): -+ self.assertIsInstance(42, Optional[int]) -+ self.assertIsInstance(None, Optional[int]) -+ self.assertNotIsInstance('abc', Optional[int]) -+ -+ def test_optional_isinstance_type_error(self): -+ with self.assertRaises(TypeError): -+ isinstance(42, Optional[list[int]]) -+ with self.assertRaises(TypeError): -+ isinstance(None, Optional[list[int]]) -+ with self.assertRaises(TypeError): -+ isinstance(42, Optional[Any]) -+ with self.assertRaises(TypeError): -+ isinstance(None, Optional[Any]) -+ -+ def test_union_issubclass(self): -+ self.assertIsSubclass(int, Union[int, str]) -+ self.assertIsSubclass(str, Union[int, str]) -+ self.assertNotIsSubclass(float, Union[int, str]) -+ self.assertIsSubclass(int, Union[int, list[int]]) -+ self.assertIsSubclass(int, Union[int, Any]) -+ self.assertNotIsSubclass(int, Union[str, Any]) -+ self.assertIsSubclass(int, Union[Any, int]) -+ self.assertNotIsSubclass(int, Union[Any, str]) -+ -+ def test_union_issubclass_type_error(self): - with self.assertRaises(TypeError): - issubclass(int, Union) - with self.assertRaises(TypeError): - issubclass(Union, int) - with self.assertRaises(TypeError): - issubclass(Union[int, str], int) -+ with self.assertRaises(TypeError): -+ issubclass(int, Union[str, list[int]]) -+ with self.assertRaises(TypeError): -+ issubclass(int, Union[list[int], int]) -+ with self.assertRaises(TypeError): -+ issubclass(int, Union[list[int], str]) -+ -+ def test_optional_issubclass(self): -+ self.assertIsSubclass(int, Optional[int]) -+ self.assertIsSubclass(type(None), Optional[int]) -+ self.assertNotIsSubclass(str, Optional[int]) -+ self.assertIsSubclass(Any, Optional[Any]) -+ self.assertIsSubclass(type(None), Optional[Any]) -+ self.assertNotIsSubclass(int, Optional[Any]) -+ -+ def test_optional_issubclass_type_error(self): -+ with self.assertRaises(TypeError): -+ issubclass(list[int], Optional[list[int]]) -+ with self.assertRaises(TypeError): -+ issubclass(type(None), Optional[list[int]]) -+ with self.assertRaises(TypeError): -+ issubclass(int, Optional[list[int]]) - - def test_union_any(self): - u = Union[Any] -@@ -3996,8 +4050,8 @@ - - class P(Protocol[T, S]): pass - -- self.assertTrue(repr(P[T, S]).endswith('P[~T, ~S]')) -- self.assertTrue(repr(P[int, str]).endswith('P[int, str]')) -+ self.assertEndsWith(repr(P[T, S]), 'P[~T, ~S]') -+ self.assertEndsWith(repr(P[int, str]), 'P[int, str]') - - def test_generic_protocols_eq(self): - T = TypeVar('T') -@@ -4587,8 +4641,7 @@ - self.assertNotEqual(Z, Y[int]) - self.assertNotEqual(Z, Y[T]) - -- self.assertTrue(str(Z).endswith( -- '.C[typing.Tuple[str, int]]')) -+ self.assertEndsWith(str(Z), '.C[typing.Tuple[str, int]]') - - def test_new_repr(self): - T = TypeVar('T') -@@ -4816,12 +4869,12 @@ - self.assertNotEqual(typing.FrozenSet[A[str]], - typing.FrozenSet[mod_generics_cache.B.A[str]]) - -- self.assertTrue(repr(Tuple[A[str]]).endswith('.A[str]]')) -- self.assertTrue(repr(Tuple[B.A[str]]).endswith('.B.A[str]]')) -- self.assertTrue(repr(Tuple[mod_generics_cache.A[str]]) -- .endswith('mod_generics_cache.A[str]]')) -- self.assertTrue(repr(Tuple[mod_generics_cache.B.A[str]]) -- .endswith('mod_generics_cache.B.A[str]]')) -+ self.assertEndsWith(repr(Tuple[A[str]]), '.A[str]]') -+ self.assertEndsWith(repr(Tuple[B.A[str]]), '.B.A[str]]') -+ self.assertEndsWith(repr(Tuple[mod_generics_cache.A[str]]), -+ 'mod_generics_cache.A[str]]') -+ self.assertEndsWith(repr(Tuple[mod_generics_cache.B.A[str]]), -+ 'mod_generics_cache.B.A[str]]') - - def test_extended_generic_rules_eq(self): - T = TypeVar('T') -@@ -5111,6 +5164,18 @@ - x = pickle.loads(z) - self.assertEqual(s, x) - -+ # Test ParamSpec args and kwargs -+ global PP -+ PP = ParamSpec('PP') -+ for thing in [PP.args, PP.kwargs]: -+ for proto in range(pickle.HIGHEST_PROTOCOL + 1): -+ with self.subTest(thing=thing, proto=proto): -+ self.assertEqual( -+ pickle.loads(pickle.dumps(thing, proto)), -+ thing, -+ ) -+ del PP -+ - def test_copy_and_deepcopy(self): - T = TypeVar('T') - class Node(Generic[T]): ... -@@ -5751,7 +5816,7 @@ - @Wrapper - def wrapped(): ... - self.assertIsInstance(wrapped, Wrapper) -- self.assertIs(False, hasattr(wrapped, "__final__")) -+ self.assertNotHasAttr(wrapped, "__final__") - - class Meta(type): - @property -@@ -5763,7 +5828,7 @@ - # Builtin classes throw TypeError if you try to set an - # attribute. - final(int) -- self.assertIs(False, hasattr(int, "__final__")) -+ self.assertNotHasAttr(int, "__final__") - - # Make sure it works with common builtin decorators - class Methods: -@@ -5844,19 +5909,19 @@ - self.assertEqual(Derived.class_method_good_order(), 42) - self.assertIs(True, Derived.class_method_good_order.__override__) - self.assertEqual(Derived.class_method_bad_order(), 42) -- self.assertIs(False, hasattr(Derived.class_method_bad_order, "__override__")) -+ self.assertNotHasAttr(Derived.class_method_bad_order, "__override__") - - self.assertEqual(Derived.static_method_good_order(), 42) - self.assertIs(True, Derived.static_method_good_order.__override__) - self.assertEqual(Derived.static_method_bad_order(), 42) -- self.assertIs(False, hasattr(Derived.static_method_bad_order, "__override__")) -+ self.assertNotHasAttr(Derived.static_method_bad_order, "__override__") - - # Base object is not changed: -- self.assertIs(False, hasattr(Base.normal_method, "__override__")) -- self.assertIs(False, hasattr(Base.class_method_good_order, "__override__")) -- self.assertIs(False, hasattr(Base.class_method_bad_order, "__override__")) -- self.assertIs(False, hasattr(Base.static_method_good_order, "__override__")) -- self.assertIs(False, hasattr(Base.static_method_bad_order, "__override__")) -+ self.assertNotHasAttr(Base.normal_method, "__override__") -+ self.assertNotHasAttr(Base.class_method_good_order, "__override__") -+ self.assertNotHasAttr(Base.class_method_bad_order, "__override__") -+ self.assertNotHasAttr(Base.static_method_good_order, "__override__") -+ self.assertNotHasAttr(Base.static_method_bad_order, "__override__") - - def test_property(self): - class Base: -@@ -5881,8 +5946,8 @@ - self.assertEqual(instance.correct, 2) - self.assertTrue(Child.correct.fget.__override__) - self.assertEqual(instance.wrong, 2) -- self.assertFalse(hasattr(Child.wrong, "__override__")) -- self.assertFalse(hasattr(Child.wrong.fset, "__override__")) -+ self.assertNotHasAttr(Child.wrong, "__override__") -+ self.assertNotHasAttr(Child.wrong.fset, "__override__") - - def test_silent_failure(self): - class CustomProp: -@@ -5899,7 +5964,7 @@ - return 1 - - self.assertEqual(WithOverride.some, 1) -- self.assertFalse(hasattr(WithOverride.some, "__override__")) -+ self.assertNotHasAttr(WithOverride.some, "__override__") - - def test_multiple_decorators(self): - def with_wraps(f): # similar to `lru_cache` definition -@@ -7069,6 +7134,25 @@ - self.assertEqual(get_type_hints(C, format=annotationlib.Format.STRING), - {'x': 'undefined'}) - -+ def test_get_type_hints_format_function(self): -+ def func(x: undefined) -> undefined: ... -+ -+ # VALUE -+ with self.assertRaises(NameError): -+ get_type_hints(func) -+ with self.assertRaises(NameError): -+ get_type_hints(func, format=annotationlib.Format.VALUE) -+ -+ # FORWARDREF -+ self.assertEqual( -+ get_type_hints(func, format=annotationlib.Format.FORWARDREF), -+ {'x': ForwardRef('undefined'), 'return': ForwardRef('undefined')}, -+ ) -+ -+ # STRING -+ self.assertEqual(get_type_hints(func, format=annotationlib.Format.STRING), -+ {'x': 'undefined', 'return': 'undefined'}) -+ - - class GetUtilitiesTestCase(TestCase): - def test_get_origin(self): -@@ -7171,6 +7255,51 @@ - self.assertEqual(get_args(Unpack[tuple[Unpack[Ts]]]), (tuple[Unpack[Ts]],)) - - -+class EvaluateForwardRefTests(BaseTestCase): -+ def test_evaluate_forward_ref(self): -+ int_ref = ForwardRef('int') -+ missing = ForwardRef('missing') -+ self.assertIs( -+ typing.evaluate_forward_ref(int_ref, type_params=()), -+ int, -+ ) -+ self.assertIs( -+ typing.evaluate_forward_ref( -+ int_ref, type_params=(), format=annotationlib.Format.FORWARDREF, -+ ), -+ int, -+ ) -+ self.assertIs( -+ typing.evaluate_forward_ref( -+ missing, type_params=(), format=annotationlib.Format.FORWARDREF, -+ ), -+ missing, -+ ) -+ self.assertEqual( -+ typing.evaluate_forward_ref( -+ int_ref, type_params=(), format=annotationlib.Format.STRING, -+ ), -+ 'int', -+ ) -+ -+ def test_evaluate_forward_ref_no_type_params(self): -+ ref = ForwardRef('int') -+ with self.assertWarnsRegex( -+ DeprecationWarning, -+ ( -+ "Failing to pass a value to the 'type_params' parameter " -+ "of 'typing.evaluate_forward_ref' is deprecated, " -+ "as it leads to incorrect behaviour" -+ ), -+ ): -+ typing.evaluate_forward_ref(ref) -+ -+ # No warnings when `type_params` is passed: -+ with warnings.catch_warnings(record=True) as w: -+ typing.evaluate_forward_ref(ref, type_params=()) -+ self.assertEqual(w, []) -+ -+ - class CollectionsAbcTests(BaseTestCase): - - def test_hashable(self): -@@ -8841,13 +8970,13 @@ - self.assertEqual(Child1.__mutable_keys__, frozenset({'b'})) - - class Base2(TypedDict): -- a: ReadOnly[int] -+ a: int - - class Child2(Base2): -- b: str -+ b: ReadOnly[str] - -- self.assertEqual(Child1.__readonly_keys__, frozenset({'a'})) -- self.assertEqual(Child1.__mutable_keys__, frozenset({'b'})) -+ self.assertEqual(Child2.__readonly_keys__, frozenset({'b'})) -+ self.assertEqual(Child2.__mutable_keys__, frozenset({'a'})) - - def test_cannot_make_mutable_key_readonly(self): - class Base(TypedDict): -@@ -10058,6 +10187,18 @@ - self.assertEqual(C4.__args__, (Concatenate[int, T, P], T)) - self.assertEqual(C4.__parameters__, (T, P)) - -+ def test_invalid_uses(self): -+ with self.assertRaisesRegex(TypeError, 'Concatenate of no types'): -+ Concatenate[()] -+ with self.assertRaisesRegex( -+ TypeError, -+ ( -+ 'The last parameter to Concatenate should be a ' -+ 'ParamSpec variable or ellipsis' -+ ), -+ ): -+ Concatenate[int] -+ - def test_var_substitution(self): - T = TypeVar('T') - P = ParamSpec('P') -@@ -10332,7 +10473,7 @@ - # to the variable name to which it is assigned". Thus, providing - # __qualname__ is unnecessary. - self.assertEqual(SpecialAttrsT.__name__, 'SpecialAttrsT') -- self.assertFalse(hasattr(SpecialAttrsT, '__qualname__')) -+ self.assertNotHasAttr(SpecialAttrsT, '__qualname__') - self.assertEqual(SpecialAttrsT.__module__, __name__) - # Module-level type variables are picklable. - for proto in range(pickle.HIGHEST_PROTOCOL + 1): -@@ -10341,7 +10482,7 @@ - self.assertIs(SpecialAttrsT, loaded) - - self.assertEqual(SpecialAttrsP.__name__, 'SpecialAttrsP') -- self.assertFalse(hasattr(SpecialAttrsP, '__qualname__')) -+ self.assertNotHasAttr(SpecialAttrsP, '__qualname__') - self.assertEqual(SpecialAttrsP.__module__, __name__) - # Module-level ParamSpecs are picklable. - for proto in range(pickle.HIGHEST_PROTOCOL + 1): -diff --git a/Lib/test/test_unicodedata.py b/Lib/test/test_unicodedata.py -index c7d09a6b460..0285f0d51f2 100644 ---- a/Lib/test/test_unicodedata.py -+++ b/Lib/test/test_unicodedata.py -@@ -11,8 +11,14 @@ - import sys - import unicodedata - import unittest --from test.support import (open_urlresource, requires_resource, script_helper, -- cpython_only, check_disallow_instantiation) -+from test.support import ( -+ open_urlresource, -+ requires_resource, -+ script_helper, -+ cpython_only, -+ check_disallow_instantiation, -+ force_not_colorized, -+) - - - class UnicodeMethodsTest(unittest.TestCase): -@@ -277,6 +283,7 @@ - # Ensure that the type disallows instantiation (bpo-43916) - check_disallow_instantiation(self, unicodedata.UCD) - -+ @force_not_colorized - def test_failed_import_during_compiling(self): - # Issue 4367 - # Decoding \N escapes requires the unicodedata module. If it can't be -diff --git a/Lib/test/test_unittest/test_async_case.py b/Lib/test/test_unittest/test_async_case.py -index 8ea244bff05..fc996b42149 100644 ---- a/Lib/test/test_unittest/test_async_case.py -+++ b/Lib/test/test_unittest/test_async_case.py -@@ -12,7 +12,7 @@ - - - def tearDownModule(): -- asyncio.set_event_loop_policy(None) -+ asyncio._set_event_loop_policy(None) - - - class TestCM: -@@ -476,11 +476,11 @@ - def test_setup_get_event_loop(self): - # See https://github.com/python/cpython/issues/95736 - # Make sure the default event loop is not used -- asyncio.set_event_loop(None) -+ asyncio._set_event_loop(None) - - class TestCase1(unittest.IsolatedAsyncioTestCase): - def setUp(self): -- asyncio.get_event_loop_policy().get_event_loop() -+ asyncio._get_event_loop_policy().get_event_loop() - - async def test_demo1(self): - pass -@@ -490,7 +490,7 @@ - self.assertTrue(result.wasSuccessful()) - - def test_loop_factory(self): -- asyncio.set_event_loop_policy(None) -+ asyncio._set_event_loop_policy(None) - - class TestCase1(unittest.IsolatedAsyncioTestCase): - loop_factory = asyncio.EventLoop -diff --git a/Lib/test/test_unittest/test_case.py b/Lib/test/test_unittest/test_case.py -index b4b2194a09c..a04af55f3fc 100644 ---- a/Lib/test/test_unittest/test_case.py -+++ b/Lib/test/test_unittest/test_case.py -@@ -10,6 +10,7 @@ - import inspect - import types - -+from collections import UserString - from copy import deepcopy - from test import support - -@@ -54,6 +55,10 @@ - self.events.append('tearDown') - - -+class List(list): -+ pass -+ -+ - class Test_TestCase(unittest.TestCase, TestEquality, TestHashing): - - ### Set up attributes used by inherited tests -@@ -85,7 +90,7 @@ - def runTest(self): raise MyException() - def test(self): pass - -- self.assertEqual(Test().id()[-13:], '.Test.runTest') -+ self.assertEndsWith(Test().id(), '.Test.runTest') - - # test that TestCase can be instantiated with no args - # primarily for use at the interactive interpreter -@@ -106,7 +111,7 @@ - def runTest(self): raise MyException() - def test(self): pass - -- self.assertEqual(Test('test').id()[-10:], '.Test.test') -+ self.assertEndsWith(Test('test').id(), '.Test.test') - - # "class TestCase([methodName])" - # ... -@@ -347,7 +352,10 @@ - return 1 - - with self.assertWarns(DeprecationWarning) as w: -+ warnings.filterwarnings('ignore', -+ 'coroutine .* was never awaited', RuntimeWarning) - Foo('test1').run() -+ support.gc_collect() - self.assertIn('It is deprecated to return a value that is not None', str(w.warning)) - self.assertIn('test1', str(w.warning)) - self.assertEqual(w.filename, __file__) -@@ -697,16 +705,136 @@ - self.assertRaises(self.failureException, self.assertIsNot, thing, thing) - - def testAssertIsInstance(self): -- thing = [] -+ thing = List() - self.assertIsInstance(thing, list) -- self.assertRaises(self.failureException, self.assertIsInstance, -- thing, dict) -+ self.assertIsInstance(thing, (int, list)) -+ with self.assertRaises(self.failureException) as cm: -+ self.assertIsInstance(thing, int) -+ self.assertEqual(str(cm.exception), -+ "[] is not an instance of ") -+ with self.assertRaises(self.failureException) as cm: -+ self.assertIsInstance(thing, (int, float)) -+ self.assertEqual(str(cm.exception), -+ "[] is not an instance of any of (, )") -+ -+ with self.assertRaises(self.failureException) as cm: -+ self.assertIsInstance(thing, int, 'ababahalamaha') -+ self.assertIn('ababahalamaha', str(cm.exception)) -+ with self.assertRaises(self.failureException) as cm: -+ self.assertIsInstance(thing, int, msg='ababahalamaha') -+ self.assertIn('ababahalamaha', str(cm.exception)) - - def testAssertNotIsInstance(self): -- thing = [] -- self.assertNotIsInstance(thing, dict) -- self.assertRaises(self.failureException, self.assertNotIsInstance, -- thing, list) -+ thing = List() -+ self.assertNotIsInstance(thing, int) -+ self.assertNotIsInstance(thing, (int, float)) -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotIsInstance(thing, list) -+ self.assertEqual(str(cm.exception), -+ "[] is an instance of ") -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotIsInstance(thing, (int, list)) -+ self.assertEqual(str(cm.exception), -+ "[] is an instance of ") -+ -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotIsInstance(thing, list, 'ababahalamaha') -+ self.assertIn('ababahalamaha', str(cm.exception)) -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotIsInstance(thing, list, msg='ababahalamaha') -+ self.assertIn('ababahalamaha', str(cm.exception)) -+ -+ def testAssertIsSubclass(self): -+ self.assertIsSubclass(List, list) -+ self.assertIsSubclass(List, (int, list)) -+ with self.assertRaises(self.failureException) as cm: -+ self.assertIsSubclass(List, int) -+ self.assertEqual(str(cm.exception), -+ f"{List!r} is not a subclass of ") -+ with self.assertRaises(self.failureException) as cm: -+ self.assertIsSubclass(List, (int, float)) -+ self.assertEqual(str(cm.exception), -+ f"{List!r} is not a subclass of any of (, )") -+ with self.assertRaises(self.failureException) as cm: -+ self.assertIsSubclass(1, int) -+ self.assertEqual(str(cm.exception), "1 is not a class") -+ -+ with self.assertRaises(self.failureException) as cm: -+ self.assertIsSubclass(List, int, 'ababahalamaha') -+ self.assertIn('ababahalamaha', str(cm.exception)) -+ with self.assertRaises(self.failureException) as cm: -+ self.assertIsSubclass(List, int, msg='ababahalamaha') -+ self.assertIn('ababahalamaha', str(cm.exception)) -+ -+ def testAssertNotIsSubclass(self): -+ self.assertNotIsSubclass(List, int) -+ self.assertNotIsSubclass(List, (int, float)) -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotIsSubclass(List, list) -+ self.assertEqual(str(cm.exception), -+ f"{List!r} is a subclass of ") -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotIsSubclass(List, (int, list)) -+ self.assertEqual(str(cm.exception), -+ f"{List!r} is a subclass of ") -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotIsSubclass(1, int) -+ self.assertEqual(str(cm.exception), "1 is not a class") -+ -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotIsSubclass(List, list, 'ababahalamaha') -+ self.assertIn('ababahalamaha', str(cm.exception)) -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotIsSubclass(List, list, msg='ababahalamaha') -+ self.assertIn('ababahalamaha', str(cm.exception)) -+ -+ def testAssertHasAttr(self): -+ a = List() -+ a.x = 1 -+ self.assertHasAttr(a, 'x') -+ with self.assertRaises(self.failureException) as cm: -+ self.assertHasAttr(a, 'y') -+ self.assertEqual(str(cm.exception), -+ "'List' object has no attribute 'y'") -+ with self.assertRaises(self.failureException) as cm: -+ self.assertHasAttr(List, 'spam') -+ self.assertEqual(str(cm.exception), -+ "type object 'List' has no attribute 'spam'") -+ with self.assertRaises(self.failureException) as cm: -+ self.assertHasAttr(sys, 'nonexistent') -+ self.assertEqual(str(cm.exception), -+ "module 'sys' has no attribute 'nonexistent'") -+ -+ with self.assertRaises(self.failureException) as cm: -+ self.assertHasAttr(a, 'y', 'ababahalamaha') -+ self.assertIn('ababahalamaha', str(cm.exception)) -+ with self.assertRaises(self.failureException) as cm: -+ self.assertHasAttr(a, 'y', msg='ababahalamaha') -+ self.assertIn('ababahalamaha', str(cm.exception)) -+ -+ def testAssertNotHasAttr(self): -+ a = List() -+ a.x = 1 -+ self.assertNotHasAttr(a, 'y') -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotHasAttr(a, 'x') -+ self.assertEqual(str(cm.exception), -+ "'List' object has unexpected attribute 'x'") -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotHasAttr(List, 'append') -+ self.assertEqual(str(cm.exception), -+ "type object 'List' has unexpected attribute 'append'") -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotHasAttr(sys, 'modules') -+ self.assertEqual(str(cm.exception), -+ "module 'sys' has unexpected attribute 'modules'") -+ -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotHasAttr(a, 'x', 'ababahalamaha') -+ self.assertIn('ababahalamaha', str(cm.exception)) -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotHasAttr(a, 'x', msg='ababahalamaha') -+ self.assertIn('ababahalamaha', str(cm.exception)) - - def testAssertIn(self): - animals = {'monkey': 'banana', 'cow': 'grass', 'seal': 'fish'} -@@ -1861,6 +1989,186 @@ - pass - self.assertIsNone(value) - -+ def testAssertStartswith(self): -+ self.assertStartsWith('ababahalamaha', 'ababa') -+ self.assertStartsWith('ababahalamaha', ('x', 'ababa', 'y')) -+ self.assertStartsWith(UserString('ababahalamaha'), 'ababa') -+ self.assertStartsWith(UserString('ababahalamaha'), ('x', 'ababa', 'y')) -+ self.assertStartsWith(bytearray(b'ababahalamaha'), b'ababa') -+ self.assertStartsWith(bytearray(b'ababahalamaha'), (b'x', b'ababa', b'y')) -+ self.assertStartsWith(b'ababahalamaha', bytearray(b'ababa')) -+ self.assertStartsWith(b'ababahalamaha', -+ (bytearray(b'x'), bytearray(b'ababa'), bytearray(b'y'))) -+ -+ with self.assertRaises(self.failureException) as cm: -+ self.assertStartsWith('ababahalamaha', 'amaha') -+ self.assertEqual(str(cm.exception), -+ "'ababahalamaha' doesn't start with 'amaha'") -+ with self.assertRaises(self.failureException) as cm: -+ self.assertStartsWith('ababahalamaha', ('x', 'y')) -+ self.assertEqual(str(cm.exception), -+ "'ababahalamaha' doesn't start with any of ('x', 'y')") -+ -+ with self.assertRaises(self.failureException) as cm: -+ self.assertStartsWith(b'ababahalamaha', 'ababa') -+ self.assertEqual(str(cm.exception), 'Expected str, not bytes') -+ with self.assertRaises(self.failureException) as cm: -+ self.assertStartsWith(b'ababahalamaha', ('amaha', 'ababa')) -+ self.assertEqual(str(cm.exception), 'Expected str, not bytes') -+ with self.assertRaises(self.failureException) as cm: -+ self.assertStartsWith([], 'ababa') -+ self.assertEqual(str(cm.exception), 'Expected str, not list') -+ with self.assertRaises(self.failureException) as cm: -+ self.assertStartsWith('ababahalamaha', b'ababa') -+ self.assertEqual(str(cm.exception), 'Expected bytes, not str') -+ with self.assertRaises(self.failureException) as cm: -+ self.assertStartsWith('ababahalamaha', (b'amaha', b'ababa')) -+ self.assertEqual(str(cm.exception), 'Expected bytes, not str') -+ with self.assertRaises(TypeError): -+ self.assertStartsWith('ababahalamaha', ord('a')) -+ -+ with self.assertRaises(self.failureException) as cm: -+ self.assertStartsWith('ababahalamaha', 'amaha', 'abracadabra') -+ self.assertIn('ababahalamaha', str(cm.exception)) -+ with self.assertRaises(self.failureException) as cm: -+ self.assertStartsWith('ababahalamaha', 'amaha', msg='abracadabra') -+ self.assertIn('ababahalamaha', str(cm.exception)) -+ -+ def testAssertNotStartswith(self): -+ self.assertNotStartsWith('ababahalamaha', 'amaha') -+ self.assertNotStartsWith('ababahalamaha', ('x', 'amaha', 'y')) -+ self.assertNotStartsWith(UserString('ababahalamaha'), 'amaha') -+ self.assertNotStartsWith(UserString('ababahalamaha'), ('x', 'amaha', 'y')) -+ self.assertNotStartsWith(bytearray(b'ababahalamaha'), b'amaha') -+ self.assertNotStartsWith(bytearray(b'ababahalamaha'), (b'x', b'amaha', b'y')) -+ self.assertNotStartsWith(b'ababahalamaha', bytearray(b'amaha')) -+ self.assertNotStartsWith(b'ababahalamaha', -+ (bytearray(b'x'), bytearray(b'amaha'), bytearray(b'y'))) -+ -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotStartsWith('ababahalamaha', 'ababa') -+ self.assertEqual(str(cm.exception), -+ "'ababahalamaha' starts with 'ababa'") -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotStartsWith('ababahalamaha', ('x', 'ababa', 'y')) -+ self.assertEqual(str(cm.exception), -+ "'ababahalamaha' starts with 'ababa'") -+ -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotStartsWith(b'ababahalamaha', 'ababa') -+ self.assertEqual(str(cm.exception), 'Expected str, not bytes') -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotStartsWith(b'ababahalamaha', ('amaha', 'ababa')) -+ self.assertEqual(str(cm.exception), 'Expected str, not bytes') -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotStartsWith([], 'ababa') -+ self.assertEqual(str(cm.exception), 'Expected str, not list') -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotStartsWith('ababahalamaha', b'ababa') -+ self.assertEqual(str(cm.exception), 'Expected bytes, not str') -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotStartsWith('ababahalamaha', (b'amaha', b'ababa')) -+ self.assertEqual(str(cm.exception), 'Expected bytes, not str') -+ with self.assertRaises(TypeError): -+ self.assertNotStartsWith('ababahalamaha', ord('a')) -+ -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotStartsWith('ababahalamaha', 'ababa', 'abracadabra') -+ self.assertIn('ababahalamaha', str(cm.exception)) -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotStartsWith('ababahalamaha', 'ababa', msg='abracadabra') -+ self.assertIn('ababahalamaha', str(cm.exception)) -+ -+ def testAssertEndswith(self): -+ self.assertEndsWith('ababahalamaha', 'amaha') -+ self.assertEndsWith('ababahalamaha', ('x', 'amaha', 'y')) -+ self.assertEndsWith(UserString('ababahalamaha'), 'amaha') -+ self.assertEndsWith(UserString('ababahalamaha'), ('x', 'amaha', 'y')) -+ self.assertEndsWith(bytearray(b'ababahalamaha'), b'amaha') -+ self.assertEndsWith(bytearray(b'ababahalamaha'), (b'x', b'amaha', b'y')) -+ self.assertEndsWith(b'ababahalamaha', bytearray(b'amaha')) -+ self.assertEndsWith(b'ababahalamaha', -+ (bytearray(b'x'), bytearray(b'amaha'), bytearray(b'y'))) -+ -+ with self.assertRaises(self.failureException) as cm: -+ self.assertEndsWith('ababahalamaha', 'ababa') -+ self.assertEqual(str(cm.exception), -+ "'ababahalamaha' doesn't end with 'ababa'") -+ with self.assertRaises(self.failureException) as cm: -+ self.assertEndsWith('ababahalamaha', ('x', 'y')) -+ self.assertEqual(str(cm.exception), -+ "'ababahalamaha' doesn't end with any of ('x', 'y')") -+ -+ with self.assertRaises(self.failureException) as cm: -+ self.assertEndsWith(b'ababahalamaha', 'amaha') -+ self.assertEqual(str(cm.exception), 'Expected str, not bytes') -+ with self.assertRaises(self.failureException) as cm: -+ self.assertEndsWith(b'ababahalamaha', ('ababa', 'amaha')) -+ self.assertEqual(str(cm.exception), 'Expected str, not bytes') -+ with self.assertRaises(self.failureException) as cm: -+ self.assertEndsWith([], 'amaha') -+ self.assertEqual(str(cm.exception), 'Expected str, not list') -+ with self.assertRaises(self.failureException) as cm: -+ self.assertEndsWith('ababahalamaha', b'amaha') -+ self.assertEqual(str(cm.exception), 'Expected bytes, not str') -+ with self.assertRaises(self.failureException) as cm: -+ self.assertEndsWith('ababahalamaha', (b'ababa', b'amaha')) -+ self.assertEqual(str(cm.exception), 'Expected bytes, not str') -+ with self.assertRaises(TypeError): -+ self.assertEndsWith('ababahalamaha', ord('a')) -+ -+ with self.assertRaises(self.failureException) as cm: -+ self.assertEndsWith('ababahalamaha', 'ababa', 'abracadabra') -+ self.assertIn('ababahalamaha', str(cm.exception)) -+ with self.assertRaises(self.failureException) as cm: -+ self.assertEndsWith('ababahalamaha', 'ababa', msg='abracadabra') -+ self.assertIn('ababahalamaha', str(cm.exception)) -+ -+ def testAssertNotEndswith(self): -+ self.assertNotEndsWith('ababahalamaha', 'ababa') -+ self.assertNotEndsWith('ababahalamaha', ('x', 'ababa', 'y')) -+ self.assertNotEndsWith(UserString('ababahalamaha'), 'ababa') -+ self.assertNotEndsWith(UserString('ababahalamaha'), ('x', 'ababa', 'y')) -+ self.assertNotEndsWith(bytearray(b'ababahalamaha'), b'ababa') -+ self.assertNotEndsWith(bytearray(b'ababahalamaha'), (b'x', b'ababa', b'y')) -+ self.assertNotEndsWith(b'ababahalamaha', bytearray(b'ababa')) -+ self.assertNotEndsWith(b'ababahalamaha', -+ (bytearray(b'x'), bytearray(b'ababa'), bytearray(b'y'))) -+ -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotEndsWith('ababahalamaha', 'amaha') -+ self.assertEqual(str(cm.exception), -+ "'ababahalamaha' ends with 'amaha'") -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotEndsWith('ababahalamaha', ('x', 'amaha', 'y')) -+ self.assertEqual(str(cm.exception), -+ "'ababahalamaha' ends with 'amaha'") -+ -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotEndsWith(b'ababahalamaha', 'amaha') -+ self.assertEqual(str(cm.exception), 'Expected str, not bytes') -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotEndsWith(b'ababahalamaha', ('ababa', 'amaha')) -+ self.assertEqual(str(cm.exception), 'Expected str, not bytes') -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotEndsWith([], 'amaha') -+ self.assertEqual(str(cm.exception), 'Expected str, not list') -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotEndsWith('ababahalamaha', b'amaha') -+ self.assertEqual(str(cm.exception), 'Expected bytes, not str') -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotEndsWith('ababahalamaha', (b'ababa', b'amaha')) -+ self.assertEqual(str(cm.exception), 'Expected bytes, not str') -+ with self.assertRaises(TypeError): -+ self.assertNotEndsWith('ababahalamaha', ord('a')) -+ -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotEndsWith('ababahalamaha', 'amaha', 'abracadabra') -+ self.assertIn('ababahalamaha', str(cm.exception)) -+ with self.assertRaises(self.failureException) as cm: -+ self.assertNotEndsWith('ababahalamaha', 'amaha', msg='abracadabra') -+ self.assertIn('ababahalamaha', str(cm.exception)) -+ - def testDeprecatedFailMethods(self): - """Test that the deprecated fail* methods get removed in 3.12""" - deprecated_names = [ -diff --git a/Lib/test/test_unittest/test_loader.py b/Lib/test/test_unittest/test_loader.py -index 83dd25ca546..cdff6d1a20c 100644 ---- a/Lib/test/test_unittest/test_loader.py -+++ b/Lib/test/test_unittest/test_loader.py -@@ -76,7 +76,7 @@ - - loader = unittest.TestLoader() - # This has to be false for the test to succeed -- self.assertFalse('runTest'.startswith(loader.testMethodPrefix)) -+ self.assertNotStartsWith('runTest', loader.testMethodPrefix) - - suite = loader.loadTestsFromTestCase(Foo) - self.assertIsInstance(suite, loader.suiteClass) -diff --git a/Lib/test/test_unittest/test_program.py b/Lib/test/test_unittest/test_program.py -index 0b46f338ac7..6092ed292d8 100644 ---- a/Lib/test/test_unittest/test_program.py -+++ b/Lib/test/test_unittest/test_program.py -@@ -4,10 +4,10 @@ - from test import support - import unittest - import test.test_unittest --from test.support import force_not_colorized - from test.test_unittest.test_result import BufferedWriter - - -+@support.force_not_colorized_test_class - class Test_TestProgram(unittest.TestCase): - - def test_discovery_from_dotted_path(self): -@@ -121,23 +121,21 @@ - self.assertEqual(['test.test_unittest', 'test.test_unittest2'], - program.testNames) - -- @force_not_colorized - def test_NonExit(self): - stream = BufferedWriter() - program = unittest.main(exit=False, - argv=["foobar"], - testRunner=unittest.TextTestRunner(stream=stream), - testLoader=self.TestLoader(self.FooBar)) -- self.assertTrue(hasattr(program, 'result')) -+ self.assertHasAttr(program, 'result') - out = stream.getvalue() - self.assertIn('\nFAIL: testFail ', out) - self.assertIn('\nERROR: testError ', out) - self.assertIn('\nUNEXPECTED SUCCESS: testUnexpectedSuccess ', out) - expected = ('\n\nFAILED (failures=1, errors=1, skipped=1, ' - 'expected failures=1, unexpected successes=1)\n') -- self.assertTrue(out.endswith(expected)) -+ self.assertEndsWith(out, expected) - -- @force_not_colorized - def test_Exit(self): - stream = BufferedWriter() - with self.assertRaises(SystemExit) as cm: -@@ -153,9 +151,8 @@ - self.assertIn('\nUNEXPECTED SUCCESS: testUnexpectedSuccess ', out) - expected = ('\n\nFAILED (failures=1, errors=1, skipped=1, ' - 'expected failures=1, unexpected successes=1)\n') -- self.assertTrue(out.endswith(expected)) -+ self.assertEndsWith(out, expected) - -- @force_not_colorized - def test_ExitAsDefault(self): - stream = BufferedWriter() - with self.assertRaises(SystemExit): -@@ -169,9 +166,8 @@ - self.assertIn('\nUNEXPECTED SUCCESS: testUnexpectedSuccess ', out) - expected = ('\n\nFAILED (failures=1, errors=1, skipped=1, ' - 'expected failures=1, unexpected successes=1)\n') -- self.assertTrue(out.endswith(expected)) -+ self.assertEndsWith(out, expected) - -- @force_not_colorized - def test_ExitSkippedSuite(self): - stream = BufferedWriter() - with self.assertRaises(SystemExit) as cm: -@@ -182,9 +178,8 @@ - self.assertEqual(cm.exception.code, 0) - out = stream.getvalue() - expected = '\n\nOK (skipped=1)\n' -- self.assertTrue(out.endswith(expected)) -+ self.assertEndsWith(out, expected) - -- @force_not_colorized - def test_ExitEmptySuite(self): - stream = BufferedWriter() - with self.assertRaises(SystemExit) as cm: -diff --git a/Lib/test/test_unittest/test_result.py b/Lib/test/test_unittest/test_result.py -index 746b9fa2677..9ac4c52449c 100644 ---- a/Lib/test/test_unittest/test_result.py -+++ b/Lib/test/test_unittest/test_result.py -@@ -1,13 +1,11 @@ - import io - import sys - import textwrap -- --from test.support import warnings_helper, captured_stdout -- - import traceback - import unittest - from unittest.util import strclass --from test.support import force_not_colorized -+from test.support import warnings_helper -+from test.support import captured_stdout, force_not_colorized_test_class - from test.test_unittest.support import BufferedWriter - - -@@ -35,6 +33,7 @@ - raise ValueError('bad cleanup2') - - -+@force_not_colorized_test_class - class Test_TestResult(unittest.TestCase): - # Note: there are not separate tests for TestResult.wasSuccessful(), - # TestResult.errors, TestResult.failures, TestResult.testsRun or -@@ -206,7 +205,6 @@ - self.assertIs(test_case, test) - self.assertIsInstance(formatted_exc, str) - -- @force_not_colorized - def test_addFailure_filter_traceback_frames(self): - class Foo(unittest.TestCase): - def test_1(self): -@@ -233,7 +231,6 @@ - self.assertEqual(len(dropped), 1) - self.assertIn("raise self.failureException(msg)", dropped[0]) - -- @force_not_colorized - def test_addFailure_filter_traceback_frames_context(self): - class Foo(unittest.TestCase): - def test_1(self): -@@ -263,7 +260,6 @@ - self.assertEqual(len(dropped), 1) - self.assertIn("raise self.failureException(msg)", dropped[0]) - -- @force_not_colorized - def test_addFailure_filter_traceback_frames_chained_exception_self_loop(self): - class Foo(unittest.TestCase): - def test_1(self): -@@ -289,7 +285,6 @@ - formatted_exc = result.failures[0][1] - self.assertEqual(formatted_exc.count("Exception: Loop\n"), 1) - -- @force_not_colorized - def test_addFailure_filter_traceback_frames_chained_exception_cycle(self): - class Foo(unittest.TestCase): - def test_1(self): -@@ -451,7 +446,6 @@ - result.addUnexpectedSuccess(None) - self.assertTrue(result.shouldStop) - -- @force_not_colorized - def testFailFastSetByRunner(self): - stream = BufferedWriter() - runner = unittest.TextTestRunner(stream=stream, failfast=True) -@@ -460,9 +454,10 @@ - self.assertTrue(result.failfast) - result = runner.run(test) - stream.flush() -- self.assertTrue(stream.getvalue().endswith('\n\nOK\n')) -+ self.assertEndsWith(stream.getvalue(), '\n\nOK\n') - - -+@force_not_colorized_test_class - class Test_TextTestResult(unittest.TestCase): - maxDiff = None - -@@ -625,7 +620,6 @@ - test.run(result) - return stream.getvalue() - -- @force_not_colorized - def testDotsOutput(self): - self.assertEqual(self._run_test('testSuccess', 1), '.') - self.assertEqual(self._run_test('testSkip', 1), 's') -@@ -634,7 +628,6 @@ - self.assertEqual(self._run_test('testExpectedFailure', 1), 'x') - self.assertEqual(self._run_test('testUnexpectedSuccess', 1), 'u') - -- @force_not_colorized - def testLongOutput(self): - classname = f'{__name__}.{self.Test.__qualname__}' - self.assertEqual(self._run_test('testSuccess', 2), -@@ -650,21 +643,17 @@ - self.assertEqual(self._run_test('testUnexpectedSuccess', 2), - f'testUnexpectedSuccess ({classname}.testUnexpectedSuccess) ... unexpected success\n') - -- @force_not_colorized - def testDotsOutputSubTestSuccess(self): - self.assertEqual(self._run_test('testSubTestSuccess', 1), '.') - -- @force_not_colorized - def testLongOutputSubTestSuccess(self): - classname = f'{__name__}.{self.Test.__qualname__}' - self.assertEqual(self._run_test('testSubTestSuccess', 2), - f'testSubTestSuccess ({classname}.testSubTestSuccess) ... ok\n') - -- @force_not_colorized - def testDotsOutputSubTestMixed(self): - self.assertEqual(self._run_test('testSubTestMixed', 1), 'sFE') - -- @force_not_colorized - def testLongOutputSubTestMixed(self): - classname = f'{__name__}.{self.Test.__qualname__}' - self.assertEqual(self._run_test('testSubTestMixed', 2), -@@ -673,7 +662,6 @@ - f' testSubTestMixed ({classname}.testSubTestMixed) [fail] (c=3) ... FAIL\n' - f' testSubTestMixed ({classname}.testSubTestMixed) [error] (d=4) ... ERROR\n') - -- @force_not_colorized - def testDotsOutputTearDownFail(self): - out = self._run_test('testSuccess', 1, AssertionError('fail')) - self.assertEqual(out, 'F') -@@ -684,7 +672,6 @@ - out = self._run_test('testSkip', 1, AssertionError('fail')) - self.assertEqual(out, 'sF') - -- @force_not_colorized - def testLongOutputTearDownFail(self): - classname = f'{__name__}.{self.Test.__qualname__}' - out = self._run_test('testSuccess', 2, AssertionError('fail')) -@@ -772,6 +759,7 @@ - runner.run(Test('testFoo')) - - -+@force_not_colorized_test_class - class TestOutputBuffering(unittest.TestCase): - - def setUp(self): -diff --git a/Lib/test/test_unittest/test_runner.py b/Lib/test/test_unittest/test_runner.py -index 1131cd73128..4d3cfd60b8d 100644 ---- a/Lib/test/test_unittest/test_runner.py -+++ b/Lib/test/test_unittest/test_runner.py -@@ -4,7 +4,6 @@ - import pickle - import subprocess - from test import support --from test.support import force_not_colorized - - import unittest - from unittest.case import _Outcome -@@ -107,7 +106,7 @@ - self.assertTrue(test.doCleanups()) - self.assertEqual(cleanups, [(2, (), {}), (1, (1, 2, 3), dict(four='hello', five='goodbye'))]) - -- @force_not_colorized -+ @support.force_not_colorized - def testCleanUpWithErrors(self): - class TestableTest(unittest.TestCase): - def testNothing(self): -@@ -251,6 +250,7 @@ - self.assertEqual(test._cleanups, []) - - -+@support.force_not_colorized_test_class - class TestClassCleanup(unittest.TestCase): - def test_addClassCleanUp(self): - class TestableTest(unittest.TestCase): -@@ -418,7 +418,6 @@ - self.assertIsInstance(e2[1], CustomError) - self.assertEqual(str(e2[1]), 'cleanup1') - -- @force_not_colorized - def test_with_errors_addCleanUp(self): - ordering = [] - class TestableTest(unittest.TestCase): -@@ -442,7 +441,6 @@ - ['setUpClass', 'setUp', 'cleanup_exc', - 'tearDownClass', 'cleanup_good']) - -- @force_not_colorized - def test_run_with_errors_addClassCleanUp(self): - ordering = [] - class TestableTest(unittest.TestCase): -@@ -466,7 +464,6 @@ - ['setUpClass', 'setUp', 'test', 'cleanup_good', - 'tearDownClass', 'cleanup_exc']) - -- @force_not_colorized - def test_with_errors_in_addClassCleanup_and_setUps(self): - ordering = [] - class_blow_up = False -@@ -519,7 +516,6 @@ - ['setUpClass', 'setUp', 'tearDownClass', - 'cleanup_exc']) - -- @force_not_colorized - def test_with_errors_in_tearDownClass(self): - ordering = [] - class TestableTest(unittest.TestCase): -@@ -596,7 +592,6 @@ - 'inner setup', 'inner test', 'inner cleanup', - 'end outer test', 'outer cleanup']) - -- @force_not_colorized - def test_run_empty_suite_error_message(self): - class EmptyTest(unittest.TestCase): - pass -@@ -608,6 +603,7 @@ - self.assertIn("\nNO TESTS RAN\n", runner.stream.getvalue()) - - -+@support.force_not_colorized_test_class - class TestModuleCleanUp(unittest.TestCase): - def test_add_and_do_ModuleCleanup(self): - module_cleanups = [] -@@ -670,7 +666,6 @@ - self.assertEqual(cleanups, - [((1, 2), {'function': 'hello'})]) - -- @force_not_colorized - def test_run_module_cleanUp(self): - blowUp = True - ordering = [] -@@ -810,7 +805,6 @@ - 'tearDownClass', 'cleanup_good']) - self.assertEqual(unittest.case._module_cleanups, []) - -- @force_not_colorized - def test_run_module_cleanUp_when_teardown_exception(self): - ordering = [] - class Module(object): -@@ -972,7 +966,6 @@ - self.assertEqual(cleanups, - [((1, 2), {'function': 3, 'self': 4})]) - -- @force_not_colorized - def test_with_errors_in_addClassCleanup(self): - ordering = [] - -@@ -1006,7 +999,6 @@ - ['setUpModule', 'setUpClass', 'test', 'tearDownClass', - 'cleanup_exc', 'tearDownModule', 'cleanup_good']) - -- @force_not_colorized - def test_with_errors_in_addCleanup(self): - ordering = [] - class Module(object): -@@ -1037,7 +1029,6 @@ - ['setUpModule', 'setUp', 'test', 'tearDown', - 'cleanup_exc', 'tearDownModule', 'cleanup_good']) - -- @force_not_colorized - def test_with_errors_in_addModuleCleanup_and_setUps(self): - ordering = [] - module_blow_up = False -@@ -1330,7 +1321,7 @@ - expectedresult = (runner.stream, DESCRIPTIONS, VERBOSITY) - self.assertEqual(runner._makeResult(), expectedresult) - -- @force_not_colorized -+ @support.force_not_colorized - @support.requires_subprocess() - def test_warnings(self): - """ -diff --git a/Lib/test/test_unittest/testmock/testasync.py b/Lib/test/test_unittest/testmock/testasync.py -index 73f04291373..0791675b540 100644 ---- a/Lib/test/test_unittest/testmock/testasync.py -+++ b/Lib/test/test_unittest/testmock/testasync.py -@@ -15,7 +15,7 @@ - - - def tearDownModule(): -- asyncio.set_event_loop_policy(None) -+ asyncio._set_event_loop_policy(None) - - - class AsyncClass: -@@ -586,16 +586,16 @@ - - def test_magicmock_has_async_magic_methods(self): - m_mock = MagicMock() -- self.assertTrue(hasattr(m_mock, "__aenter__")) -- self.assertTrue(hasattr(m_mock, "__aexit__")) -- self.assertTrue(hasattr(m_mock, "__anext__")) -+ self.assertHasAttr(m_mock, "__aenter__") -+ self.assertHasAttr(m_mock, "__aexit__") -+ self.assertHasAttr(m_mock, "__anext__") - - def test_asyncmock_has_sync_magic_methods(self): - a_mock = AsyncMock() -- self.assertTrue(hasattr(a_mock, "__enter__")) -- self.assertTrue(hasattr(a_mock, "__exit__")) -- self.assertTrue(hasattr(a_mock, "__next__")) -- self.assertTrue(hasattr(a_mock, "__len__")) -+ self.assertHasAttr(a_mock, "__enter__") -+ self.assertHasAttr(a_mock, "__exit__") -+ self.assertHasAttr(a_mock, "__next__") -+ self.assertHasAttr(a_mock, "__len__") - - def test_magic_methods_are_async_functions(self): - m_mock = MagicMock() -diff --git a/Lib/test/test_unittest/testmock/testcallable.py b/Lib/test/test_unittest/testmock/testcallable.py -index ca88511f639..03cb983e447 100644 ---- a/Lib/test/test_unittest/testmock/testcallable.py -+++ b/Lib/test/test_unittest/testmock/testcallable.py -@@ -23,21 +23,21 @@ - def test_non_callable(self): - for mock in NonCallableMagicMock(), NonCallableMock(): - self.assertRaises(TypeError, mock) -- self.assertFalse(hasattr(mock, '__call__')) -+ self.assertNotHasAttr(mock, '__call__') - self.assertIn(mock.__class__.__name__, repr(mock)) - - - def test_hierarchy(self): -- self.assertTrue(issubclass(MagicMock, Mock)) -- self.assertTrue(issubclass(NonCallableMagicMock, NonCallableMock)) -+ self.assertIsSubclass(MagicMock, Mock) -+ self.assertIsSubclass(NonCallableMagicMock, NonCallableMock) - - - def test_attributes(self): - one = NonCallableMock() -- self.assertTrue(issubclass(type(one.one), Mock)) -+ self.assertIsSubclass(type(one.one), Mock) - - two = NonCallableMagicMock() -- self.assertTrue(issubclass(type(two.two), MagicMock)) -+ self.assertIsSubclass(type(two.two), MagicMock) - - - def test_subclasses(self): -@@ -45,13 +45,13 @@ - pass - - one = MockSub() -- self.assertTrue(issubclass(type(one.one), MockSub)) -+ self.assertIsSubclass(type(one.one), MockSub) - - class MagicSub(MagicMock): - pass - - two = MagicSub() -- self.assertTrue(issubclass(type(two.two), MagicSub)) -+ self.assertIsSubclass(type(two.two), MagicSub) - - - def test_patch_spec(self): -diff --git a/Lib/test/test_unittest/testmock/testhelpers.py b/Lib/test/test_unittest/testmock/testhelpers.py -index f260769eb8c..8d0f3ebc5cb 100644 ---- a/Lib/test/test_unittest/testmock/testhelpers.py -+++ b/Lib/test/test_unittest/testmock/testhelpers.py -@@ -951,7 +951,7 @@ - - proxy = Foo() - autospec = create_autospec(proxy) -- self.assertFalse(hasattr(autospec, '__name__')) -+ self.assertNotHasAttr(autospec, '__name__') - - - def test_autospec_signature_staticmethod(self): -diff --git a/Lib/test/test_unittest/testmock/testmagicmethods.py b/Lib/test/test_unittest/testmock/testmagicmethods.py -index 2a8aa11b328..acdbd699d18 100644 ---- a/Lib/test/test_unittest/testmock/testmagicmethods.py -+++ b/Lib/test/test_unittest/testmock/testmagicmethods.py -@@ -10,13 +10,13 @@ - - def test_deleting_magic_methods(self): - mock = Mock() -- self.assertFalse(hasattr(mock, '__getitem__')) -+ self.assertNotHasAttr(mock, '__getitem__') - - mock.__getitem__ = Mock() -- self.assertTrue(hasattr(mock, '__getitem__')) -+ self.assertHasAttr(mock, '__getitem__') - - del mock.__getitem__ -- self.assertFalse(hasattr(mock, '__getitem__')) -+ self.assertNotHasAttr(mock, '__getitem__') - - - def test_magicmock_del(self): -@@ -252,12 +252,12 @@ - self.assertEqual(list(mock), [1, 2, 3]) - - getattr(mock, '__bool__').return_value = False -- self.assertFalse(hasattr(mock, '__nonzero__')) -+ self.assertNotHasAttr(mock, '__nonzero__') - self.assertFalse(bool(mock)) - - for entry in _magics: -- self.assertTrue(hasattr(mock, entry)) -- self.assertFalse(hasattr(mock, '__imaginary__')) -+ self.assertHasAttr(mock, entry) -+ self.assertNotHasAttr(mock, '__imaginary__') - - - def test_magic_mock_equality(self): -diff --git a/Lib/test/test_unittest/testmock/testmock.py b/Lib/test/test_unittest/testmock/testmock.py -index e1b108f81e5..5d1bf4258af 100644 ---- a/Lib/test/test_unittest/testmock/testmock.py -+++ b/Lib/test/test_unittest/testmock/testmock.py -@@ -2215,13 +2215,13 @@ - def test_attribute_deletion(self): - for mock in (Mock(), MagicMock(), NonCallableMagicMock(), - NonCallableMock()): -- self.assertTrue(hasattr(mock, 'm')) -+ self.assertHasAttr(mock, 'm') - - del mock.m -- self.assertFalse(hasattr(mock, 'm')) -+ self.assertNotHasAttr(mock, 'm') - - del mock.f -- self.assertFalse(hasattr(mock, 'f')) -+ self.assertNotHasAttr(mock, 'f') - self.assertRaises(AttributeError, getattr, mock, 'f') - - -@@ -2230,18 +2230,18 @@ - for mock in (Mock(), MagicMock(), NonCallableMagicMock(), - NonCallableMock()): - mock.foo = 3 -- self.assertTrue(hasattr(mock, 'foo')) -+ self.assertHasAttr(mock, 'foo') - self.assertEqual(mock.foo, 3) - - del mock.foo -- self.assertFalse(hasattr(mock, 'foo')) -+ self.assertNotHasAttr(mock, 'foo') - - mock.foo = 4 -- self.assertTrue(hasattr(mock, 'foo')) -+ self.assertHasAttr(mock, 'foo') - self.assertEqual(mock.foo, 4) - - del mock.foo -- self.assertFalse(hasattr(mock, 'foo')) -+ self.assertNotHasAttr(mock, 'foo') - - - def test_mock_raises_when_deleting_nonexistent_attribute(self): -@@ -2259,7 +2259,7 @@ - mock.child = True - del mock.child - mock.reset_mock() -- self.assertFalse(hasattr(mock, 'child')) -+ self.assertNotHasAttr(mock, 'child') - - - def test_class_assignable(self): -diff --git a/Lib/test/test_unittest/testmock/testpatch.py b/Lib/test/test_unittest/testmock/testpatch.py -index 037c021e6ea..7c5fc3deed2 100644 ---- a/Lib/test/test_unittest/testmock/testpatch.py -+++ b/Lib/test/test_unittest/testmock/testpatch.py -@@ -366,7 +366,7 @@ - self.assertEqual(SomeClass.frooble, sentinel.Frooble) - - test() -- self.assertFalse(hasattr(SomeClass, 'frooble')) -+ self.assertNotHasAttr(SomeClass, 'frooble') - - - def test_patch_wont_create_by_default(self): -@@ -383,7 +383,7 @@ - @patch.object(SomeClass, 'ord', sentinel.Frooble) - def test(): pass - test() -- self.assertFalse(hasattr(SomeClass, 'ord')) -+ self.assertNotHasAttr(SomeClass, 'ord') - - - def test_patch_builtins_without_create(self): -@@ -1477,7 +1477,7 @@ - finally: - patcher.stop() - -- self.assertFalse(hasattr(Foo, 'blam')) -+ self.assertNotHasAttr(Foo, 'blam') - - - def test_patch_multiple_spec_set(self): -diff --git a/Lib/test/test_unparse.py b/Lib/test/test_unparse.py -index 35394f29fbe..f6c4f1f3f64 100644 ---- a/Lib/test/test_unparse.py -+++ b/Lib/test/test_unparse.py -@@ -513,11 +513,13 @@ - self.check_src_roundtrip("class X(*args, **kwargs):\n pass") - - def test_fstrings(self): -- self.check_src_roundtrip("f'-{f'*{f'+{f'.{x}.'}+'}*'}-'") -- self.check_src_roundtrip("f'\\u2028{'x'}'") -+ self.check_src_roundtrip('''f\'\'\'-{f"""*{f"+{f'.{x}.'}+"}*"""}-\'\'\'''') -+ self.check_src_roundtrip('''f\'-{f\'\'\'*{f"""+{f".{f'{x}'}."}+"""}*\'\'\'}-\'''') -+ self.check_src_roundtrip('''f\'-{f\'*{f\'\'\'+{f""".{f"{f'{x}'}"}."""}+\'\'\'}*\'}-\'''') -+ self.check_src_roundtrip('''f"\\u2028{'x'}"''') - self.check_src_roundtrip(r"f'{x}\n'") -- self.check_src_roundtrip("f'{'\\n'}\\n'") -- self.check_src_roundtrip("f'{f'{x}\\n'}\\n'") -+ self.check_src_roundtrip('''f"{'\\n'}\\n"''') -+ self.check_src_roundtrip('''f"{f'{x}\\n'}\\n"''') - - def test_docstrings(self): - docstrings = ( -@@ -651,7 +653,9 @@ - - def test_backslash_in_format_spec(self): - import re -- msg = re.escape("invalid escape sequence '\\ '") -+ msg = re.escape('"\\ " is an invalid escape sequence. ' -+ 'Such sequences will not work in the future. ' -+ 'Did you mean "\\\\ "? A raw string is also an option.') - with self.assertWarnsRegex(SyntaxWarning, msg): - self.check_ast_roundtrip("""f"{x:\\ }" """) - self.check_ast_roundtrip("""f"{x:\\n}" """) -diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py -index 042d3b35b77..4842428d6fd 100644 ---- a/Lib/test/test_urllib.py -+++ b/Lib/test/test_urllib.py -@@ -419,7 +419,9 @@ - Content-Type: text/html; charset=iso-8859-1 - ''', mock_close=True) - try: -- self.assertRaises(OSError, urllib.request.urlopen, "http://python.org/") -+ with self.assertRaises(urllib.error.HTTPError) as cm: -+ urllib.request.urlopen("http://python.org/") -+ cm.exception.close() - finally: - self.unfakehttp() - -@@ -434,8 +436,9 @@ - ''', mock_close=True) - try: - msg = "Redirection to url 'file:" -- with self.assertRaisesRegex(urllib.error.HTTPError, msg): -+ with self.assertRaisesRegex(urllib.error.HTTPError, msg) as cm: - urllib.request.urlopen("http://python.org/") -+ cm.exception.close() - finally: - self.unfakehttp() - -@@ -448,8 +451,9 @@ - Connection: close - ''', mock_close=True) - try: -- self.assertRaises(urllib.error.HTTPError, urllib.request.urlopen, -- "http://something") -+ with self.assertRaises(urllib.error.HTTPError) as cm: -+ urllib.request.urlopen("http://something") -+ cm.exception.close() - finally: - self.unfakehttp() - -@@ -529,10 +533,11 @@ - "QOjdAAAAAXNSR0IArs4c6QAAAA9JREFUCNdj%0AYGBg%2BP//PwAGAQL%2BCm8 " - "vHgAAAABJRU5ErkJggg%3D%3D%0A%20") - -- self.text_url_resp = urllib.request.urlopen(self.text_url) -- self.text_url_base64_resp = urllib.request.urlopen( -- self.text_url_base64) -- self.image_url_resp = urllib.request.urlopen(self.image_url) -+ self.text_url_resp = self.enterContext( -+ urllib.request.urlopen(self.text_url)) -+ self.text_url_base64_resp = self.enterContext( -+ urllib.request.urlopen(self.text_url_base64)) -+ self.image_url_resp = self.enterContext(urllib.request.urlopen(self.image_url)) - - def test_interface(self): - # Make sure object returned by urlopen() has the specified methods -@@ -548,8 +553,10 @@ - [('text/plain', ''), ('charset', 'ISO-8859-1')]) - self.assertEqual(self.image_url_resp.info()['content-length'], - str(len(self.image))) -- self.assertEqual(urllib.request.urlopen("data:,").info().get_params(), -+ r = urllib.request.urlopen("data:,") -+ self.assertEqual(r.info().get_params(), - [('text/plain', ''), ('charset', 'US-ASCII')]) -+ r.close() - - def test_geturl(self): - self.assertEqual(self.text_url_resp.geturl(), self.text_url) -diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py -index 4a9e653515b..44e6af8c6b6 100644 ---- a/Lib/test/test_urllib2.py -+++ b/Lib/test/test_urllib2.py -@@ -27,6 +27,7 @@ - import urllib.error - import http.client - -+ - support.requires_working_socket(module=True) - - # XXX -@@ -781,6 +782,7 @@ - headers = r.info() - self.assertEqual(headers.get("Content-type"), mimetype) - self.assertEqual(int(headers["Content-length"]), len(data)) -+ r.close() - - @support.requires_resource("network") - def test_ftp_error(self): -@@ -1246,10 +1248,11 @@ - try: - method(req, MockFile(), code, "Blah", - MockHeaders({"location": to_url})) -- except urllib.error.HTTPError: -+ except urllib.error.HTTPError as err: - # 307 and 308 in response to POST require user OK - self.assertIn(code, (307, 308)) - self.assertIsNotNone(data) -+ err.close() - self.assertEqual(o.req.get_full_url(), to_url) - try: - self.assertEqual(o.req.get_method(), "GET") -@@ -1285,9 +1288,10 @@ - while 1: - redirect(h, req, "http://example.com/") - count = count + 1 -- except urllib.error.HTTPError: -+ except urllib.error.HTTPError as err: - # don't stop until max_repeats, because cookies may introduce state - self.assertEqual(count, urllib.request.HTTPRedirectHandler.max_repeats) -+ err.close() - - # detect endless non-repeating chain of redirects - req = Request(from_url, origin_req_host="example.com") -@@ -1297,9 +1301,10 @@ - while 1: - redirect(h, req, "http://example.com/%d" % count) - count = count + 1 -- except urllib.error.HTTPError: -+ except urllib.error.HTTPError as err: - self.assertEqual(count, - urllib.request.HTTPRedirectHandler.max_redirections) -+ err.close() - - def test_invalid_redirect(self): - from_url = "http://example.com/a.html" -@@ -1313,9 +1318,11 @@ - - for scheme in invalid_schemes: - invalid_url = scheme + '://' + schemeless_url -- self.assertRaises(urllib.error.HTTPError, h.http_error_302, -+ with self.assertRaises(urllib.error.HTTPError) as cm: -+ h.http_error_302( - req, MockFile(), 302, "Security Loophole", - MockHeaders({"location": invalid_url})) -+ cm.exception.close() - - for scheme in valid_schemes: - valid_url = scheme + '://' + schemeless_url -@@ -1911,11 +1918,13 @@ - self.assertEqual(str(err), expected_errmsg) - expected_errmsg = '' % (err.code, err.msg) - self.assertEqual(repr(err), expected_errmsg) -+ err.close() - - def test_gh_98778(self): - x = urllib.error.HTTPError("url", 405, "METHOD NOT ALLOWED", None, None) - self.assertEqual(getattr(x, "__notes__", ()), ()) - self.assertIsInstance(x.fp.read(), bytes) -+ x.close() - - def test_parse_proxy(self): - parse_proxy_test_cases = [ -@@ -1962,10 +1971,38 @@ - - self.assertRaises(ValueError, _parse_proxy, 'file:/ftp.example.com'), - -- def test_unsupported_algorithm(self): -- handler = AbstractDigestAuthHandler() -+ -+skip_libssl_fips_mode = unittest.skipIf( -+ support.is_libssl_fips_mode(), -+ "conservative skip due to OpenSSL FIPS mode possible algorithm nerfing", -+) -+ -+ -+class TestDigestAuthAlgorithms(unittest.TestCase): -+ def setUp(self): -+ self.handler = AbstractDigestAuthHandler() -+ -+ @skip_libssl_fips_mode -+ def test_md5_algorithm(self): -+ H, KD = self.handler.get_algorithm_impls('MD5') -+ self.assertEqual(H("foo"), "acbd18db4cc2f85cedef654fccc4a4d8") -+ self.assertEqual(KD("foo", "bar"), "4e99e8c12de7e01535248d2bac85e732") -+ -+ @skip_libssl_fips_mode -+ def test_sha_algorithm(self): -+ H, KD = self.handler.get_algorithm_impls('SHA') -+ self.assertEqual(H("foo"), "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33") -+ self.assertEqual(KD("foo", "bar"), "54dcbe67d21d5eb39493d46d89ae1f412d3bd6de") -+ -+ @skip_libssl_fips_mode -+ def test_sha256_algorithm(self): -+ H, KD = self.handler.get_algorithm_impls('SHA-256') -+ self.assertEqual(H("foo"), "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae") -+ self.assertEqual(KD("foo", "bar"), "a765a8beaa9d561d4c5cbed29d8f4e30870297fdfa9cb7d6e9848a95fec9f937") -+ -+ def test_invalid_algorithm(self): - with self.assertRaises(ValueError) as exc: -- handler.get_algorithm_impls('invalid') -+ self.handler.get_algorithm_impls('invalid') - self.assertEqual( - str(exc.exception), - "Unsupported digest authentication algorithm 'invalid'" -diff --git a/Lib/test/test_urllib2_localnet.py b/Lib/test/test_urllib2_localnet.py -index 50c491a3cfd..9cb15d61c2a 100644 ---- a/Lib/test/test_urllib2_localnet.py -+++ b/Lib/test/test_urllib2_localnet.py -@@ -316,7 +316,9 @@ - ah = urllib.request.HTTPBasicAuthHandler() - ah.add_password(self.REALM, self.server_url, self.USER, self.INCORRECT_PASSWD) - urllib.request.install_opener(urllib.request.build_opener(ah)) -- self.assertRaises(urllib.error.HTTPError, urllib.request.urlopen, self.server_url) -+ with self.assertRaises(urllib.error.HTTPError) as cm: -+ urllib.request.urlopen(self.server_url) -+ cm.exception.close() - - - @hashlib_helper.requires_hashdigest("md5", openssl=True) -@@ -362,15 +364,15 @@ - self.proxy_digest_handler.add_password(self.REALM, self.URL, - self.USER, self.PASSWD+"bad") - self.digest_auth_handler.set_qop("auth") -- self.assertRaises(urllib.error.HTTPError, -- self.opener.open, -- self.URL) -+ with self.assertRaises(urllib.error.HTTPError) as cm: -+ self.opener.open(self.URL) -+ cm.exception.close() - - def test_proxy_with_no_password_raises_httperror(self): - self.digest_auth_handler.set_qop("auth") -- self.assertRaises(urllib.error.HTTPError, -- self.opener.open, -- self.URL) -+ with self.assertRaises(urllib.error.HTTPError) as cm: -+ self.opener.open(self.URL) -+ cm.exception.close() - - def test_proxy_qop_auth_works(self): - self.proxy_digest_handler.add_password(self.REALM, self.URL, -diff --git a/Lib/test/test_urllib_response.py b/Lib/test/test_urllib_response.py -index b76763f4ed8..d949fa38bfc 100644 ---- a/Lib/test/test_urllib_response.py -+++ b/Lib/test/test_urllib_response.py -@@ -48,6 +48,7 @@ - info = urllib.response.addinfo(self.fp, self.test_headers) - self.assertEqual(info.info(), self.test_headers) - self.assertEqual(info.headers, self.test_headers) -+ info.close() - - def test_addinfourl(self): - url = "http://www.python.org" -@@ -60,6 +61,7 @@ - self.assertEqual(infourl.headers, self.test_headers) - self.assertEqual(infourl.url, url) - self.assertEqual(infourl.status, code) -+ infourl.close() - - def tearDown(self): - self.sock.close() -diff --git a/Lib/test/test_urllibnet.py b/Lib/test/test_urllibnet.py -index f824dddf711..ce4e60e3a80 100644 ---- a/Lib/test/test_urllibnet.py -+++ b/Lib/test/test_urllibnet.py -@@ -106,6 +106,7 @@ - with urllib.request.urlopen(URL): - pass - self.assertEqual(e.exception.code, 404) -+ e.exception.close() - - @support.requires_resource('walltime') - def test_bad_address(self): -diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py -index 4516bdea6ad..b51cc006b73 100644 ---- a/Lib/test/test_urlparse.py -+++ b/Lib/test/test_urlparse.py -@@ -1412,16 +1412,51 @@ - self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[0439:23af::2309::fae7:1234]/Path?Query') - self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[0439:23af:2309::fae7:1234:2342:438e:192.0.2.146]/Path?Query') - self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@]v6a.ip[/Path') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[v6a.ip]') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[v6a.ip].suffix') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[v6a.ip]/') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[v6a.ip].suffix/') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[v6a.ip]?') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[v6a.ip].suffix?') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]/') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix/') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]?') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix?') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]:a') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix:a') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]:a1') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix:a1') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]:1a') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix:1a') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]:') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix:/') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]:?') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://user@prefix.[v6a.ip]') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://user@[v6a.ip].suffix') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[v6a.ip') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://v6a.ip]') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://]v6a.ip[') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://]v6a.ip') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://v6a.ip[') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[v6a.ip') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://v6a.ip].suffix') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix]v6a.ip[suffix') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix]v6a.ip') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://v6a.ip[suffix') - - def test_splitting_bracketed_hosts(self): -- p1 = urllib.parse.urlsplit('scheme://user@[v6a.ip]/path?query') -+ p1 = urllib.parse.urlsplit('scheme://user@[v6a.ip]:1234/path?query') - self.assertEqual(p1.hostname, 'v6a.ip') - self.assertEqual(p1.username, 'user') - self.assertEqual(p1.path, '/path') -+ self.assertEqual(p1.port, 1234) - p2 = urllib.parse.urlsplit('scheme://user@[0439:23af:2309::fae7%test]/path?query') - self.assertEqual(p2.hostname, '0439:23af:2309::fae7%test') - self.assertEqual(p2.username, 'user') - self.assertEqual(p2.path, '/path') -+ self.assertIs(p2.port, None) - p3 = urllib.parse.urlsplit('scheme://user@[0439:23af:2309::fae7:1234:192.0.2.146%test]/path?query') - self.assertEqual(p3.hostname, '0439:23af:2309::fae7:1234:192.0.2.146%test') - self.assertEqual(p3.username, 'user') -diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py -index 7bd26a8ca34..8216c4dd00e 100755 ---- a/Lib/test/test_uuid.py -+++ b/Lib/test/test_uuid.py -@@ -21,7 +21,7 @@ - try: - __import__(name) - return True -- except: -+ except ModuleNotFoundError: - return False - - -@@ -34,6 +34,47 @@ - class BaseTestUUID: - uuid = None - -+ def test_nil_uuid(self): -+ nil_uuid = self.uuid.NIL -+ -+ s = '00000000-0000-0000-0000-000000000000' -+ i = 0 -+ self.assertEqual(nil_uuid, self.uuid.UUID(s)) -+ self.assertEqual(nil_uuid, self.uuid.UUID(int=i)) -+ self.assertEqual(nil_uuid.int, i) -+ self.assertEqual(str(nil_uuid), s) -+ # The Nil UUID falls within the range of the Apollo NCS variant as per -+ # RFC 9562. -+ # See https://www.rfc-editor.org/rfc/rfc9562.html#section-5.9-4 -+ self.assertEqual(nil_uuid.variant, self.uuid.RESERVED_NCS) -+ # A version field of all zeros is "Unused" in RFC 9562, but the version -+ # field also only applies to the 10xx variant, i.e. the variant -+ # specified in RFC 9562. As such, because the Nil UUID falls under a -+ # different variant, its version is considered undefined. -+ # See https://www.rfc-editor.org/rfc/rfc9562.html#table2 -+ self.assertIsNone(nil_uuid.version) -+ -+ def test_max_uuid(self): -+ max_uuid = self.uuid.MAX -+ -+ s = 'ffffffff-ffff-ffff-ffff-ffffffffffff' -+ i = (1 << 128) - 1 -+ self.assertEqual(max_uuid, self.uuid.UUID(s)) -+ self.assertEqual(max_uuid, self.uuid.UUID(int=i)) -+ self.assertEqual(max_uuid.int, i) -+ self.assertEqual(str(max_uuid), s) -+ # The Max UUID falls within the range of the "yet-to-be defined" future -+ # UUID variant as per RFC 9562. -+ # See https://www.rfc-editor.org/rfc/rfc9562.html#section-5.10-4 -+ self.assertEqual(max_uuid.variant, self.uuid.RESERVED_FUTURE) -+ # A version field of all ones is "Reserved for future definition" in -+ # RFC 9562, but the version field also only applies to the 10xx -+ # variant, i.e. the variant specified in RFC 9562. As such, because the -+ # Max UUID falls under a different variant, its version is considered -+ # undefined. -+ # See https://www.rfc-editor.org/rfc/rfc9562.html#table2 -+ self.assertIsNone(max_uuid.version) -+ - def test_safe_uuid_enum(self): - class CheckedSafeUUID(enum.Enum): - safe = 0 -@@ -707,12 +748,16 @@ - equal(u.int & 0x3fffffffffffffff, lo) - - def test_uuid8_uniqueness(self): -- # Test that UUIDv8-generated values are unique -- # (up to a negligible probability of failure). -- u1 = self.uuid.uuid8() -- u2 = self.uuid.uuid8() -- self.assertNotEqual(u1.int, u2.int) -- self.assertEqual(u1.version, u2.version) -+ # Test that UUIDv8-generated values are unique (up to a negligible -+ # probability of failure). There are 122 bits of entropy and assuming -+ # that the underlying mt-19937-based random generator is sufficiently -+ # good, it is unlikely to have a collision of two UUIDs. -+ N = 1000 -+ uuids = {self.uuid.uuid8() for _ in range(N)} -+ self.assertEqual(len(uuids), N) -+ -+ versions = {u.version for u in uuids} -+ self.assertSetEqual(versions, {8}) - - @support.requires_fork() - def testIssue8621(self): -diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py -index 0b09010c69d..6e23097deaf 100644 ---- a/Lib/test/test_venv.py -+++ b/Lib/test/test_venv.py -@@ -111,10 +111,6 @@ - result = f.read() - return result - -- def assertEndsWith(self, string, tail): -- if not string.endswith(tail): -- self.fail(f"String {string!r} does not end with {tail!r}") -- - class BasicTest(BaseTest): - """Test venv module functionality.""" - -diff --git a/Lib/test/test_warnings/__init__.py b/Lib/test/test_warnings/__init__.py -index 4e3c877896f..6f4c569d247 100644 ---- a/Lib/test/test_warnings/__init__.py -+++ b/Lib/test/test_warnings/__init__.py -@@ -1432,6 +1432,17 @@ - module = py_warnings - - -+class LocksTest(unittest.TestCase): -+ @support.cpython_only -+ @unittest.skipUnless(c_warnings, 'C module is required') -+ def test_release_lock_no_lock(self): -+ with self.assertRaisesRegex( -+ RuntimeError, -+ 'cannot release un-acquired lock', -+ ): -+ c_warnings._release_lock() -+ -+ - class _DeprecatedTest(BaseTest, unittest.TestCase): - - """Test _deprecated().""" -@@ -1521,7 +1532,7 @@ - self.assertTrue(err.startswith(expected), ascii(err)) - - --class DeprecatedTests(unittest.TestCase): -+class DeprecatedTests(PyPublicAPITests): - def test_dunder_deprecated(self): - @deprecated("A will go away soon") - class A: ---- /dev/null -+++ b/Lib/test/test_xml_dom_xmlbuilder.py -@@ -0,0 +1,88 @@ -+import io -+import unittest -+from http import client -+from test.test_httplib import FakeSocket -+from unittest import mock -+from xml.dom import getDOMImplementation, minidom, xmlbuilder -+ -+SMALL_SAMPLE = b""" -+ -+ -+Introduction to XSL -+
-+

A. Namespace

-+""" -+ -+ -+class XMLBuilderTest(unittest.TestCase): -+ def test_entity_resolver(self): -+ body = ( -+ b"HTTP/1.1 200 OK\r\nContent-Type: text/xml; charset=utf-8\r\n\r\n" -+ + SMALL_SAMPLE -+ ) -+ -+ sock = FakeSocket(body) -+ response = client.HTTPResponse(sock) -+ response.begin() -+ attrs = {"open.return_value": response} -+ opener = mock.Mock(**attrs) -+ -+ resolver = xmlbuilder.DOMEntityResolver() -+ -+ with mock.patch("urllib.request.build_opener") as mock_build: -+ mock_build.return_value = opener -+ source = resolver.resolveEntity(None, "http://example.com/2000/svg") -+ -+ self.assertIsInstance(source, xmlbuilder.DOMInputSource) -+ self.assertIsNone(source.publicId) -+ self.assertEqual(source.systemId, "http://example.com/2000/svg") -+ self.assertEqual(source.baseURI, "http://example.com/2000/") -+ self.assertEqual(source.encoding, "utf-8") -+ self.assertIs(source.byteStream, response) -+ -+ self.assertIsNone(source.characterStream) -+ self.assertIsNone(source.stringData) -+ -+ def test_builder(self): -+ imp = getDOMImplementation() -+ self.assertIsInstance(imp, xmlbuilder.DOMImplementationLS) -+ -+ builder = imp.createDOMBuilder(imp.MODE_SYNCHRONOUS, None) -+ self.assertIsInstance(builder, xmlbuilder.DOMBuilder) -+ -+ def test_parse_uri(self): -+ body = ( -+ b"HTTP/1.1 200 OK\r\nContent-Type: text/xml; charset=utf-8\r\n\r\n" -+ + SMALL_SAMPLE -+ ) -+ -+ sock = FakeSocket(body) -+ response = client.HTTPResponse(sock) -+ response.begin() -+ attrs = {"open.return_value": response} -+ opener = mock.Mock(**attrs) -+ -+ with mock.patch("urllib.request.build_opener") as mock_build: -+ mock_build.return_value = opener -+ -+ imp = getDOMImplementation() -+ builder = imp.createDOMBuilder(imp.MODE_SYNCHRONOUS, None) -+ document = builder.parseURI("http://example.com/2000/svg") -+ -+ self.assertIsInstance(document, minidom.Document) -+ self.assertEqual(len(document.childNodes), 1) -+ -+ def test_parse_with_systemId(self): -+ response = io.BytesIO(SMALL_SAMPLE) -+ -+ with mock.patch("urllib.request.urlopen") as mock_open: -+ mock_open.return_value = response -+ -+ imp = getDOMImplementation() -+ source = imp.createDOMInputSource() -+ builder = imp.createDOMBuilder(imp.MODE_SYNCHRONOUS, None) -+ source.systemId = "http://example.com/2000/svg" -+ document = builder.parse(source) -+ -+ self.assertIsInstance(document, minidom.Document) -+ self.assertEqual(len(document.childNodes), 1) -diff --git a/Lib/test/test_zipfile/_path/test_path.py b/Lib/test/test_zipfile/_path/test_path.py -index aba515536f0..1ee45f5fc57 100644 ---- a/Lib/test/test_zipfile/_path/test_path.py -+++ b/Lib/test/test_zipfile/_path/test_path.py -@@ -634,7 +634,7 @@ - """ - data = io.BytesIO() - zf = zipfile.ZipFile(data, "w") -- zf.writestr(DirtyZipInfo.for_name("foo\\bar", zf), b"content") -+ zf.writestr(DirtyZipInfo("foo\\bar")._for_archive(zf), b"content") - zf.filename = '' - root = zipfile.Path(zf) - (first,) = root.iterdir() -@@ -657,20 +657,3 @@ - def __init__(self, filename, *args, **kwargs): - super().__init__(filename, *args, **kwargs) - self.filename = filename -- -- @classmethod -- def for_name(cls, name, archive): -- """ -- Construct the same way that ZipFile.writestr does. -- -- TODO: extract this functionality and re-use -- """ -- self = cls(filename=name, date_time=time.localtime(time.time())[:6]) -- self.compress_type = archive.compression -- self.compress_level = archive.compresslevel -- if self.filename.endswith('/'): # pragma: no cover -- self.external_attr = 0o40775 << 16 # drwxrwxr-x -- self.external_attr |= 0x10 # MS-DOS directory flag -- else: -- self.external_attr = 0o600 << 16 # ?rw------- -- return self -diff --git a/Lib/test/test_zipfile/test_core.py b/Lib/test/test_zipfile/test_core.py -index c36228c033a..6b1fe56074d 100644 ---- a/Lib/test/test_zipfile/test_core.py -+++ b/Lib/test/test_zipfile/test_core.py -@@ -1,3 +1,4 @@ -+import _pyio - import array - import contextlib - import importlib.util -@@ -5,6 +6,7 @@ - import itertools - import os - import posixpath -+import stat - import struct - import subprocess - import sys -@@ -18,10 +20,11 @@ - from random import randint, random, randbytes - - from test import archiver_tests --from test.support import script_helper -+from test.support import script_helper, os_helper - from test.support import ( - findfile, requires_zlib, requires_bz2, requires_lzma, -- captured_stdout, captured_stderr, requires_subprocess -+ captured_stdout, captured_stderr, requires_subprocess, -+ is_emscripten - ) - from test.support.os_helper import ( - TESTFN, unlink, rmtree, temp_dir, temp_cwd, fd_count, FakePath -@@ -1780,6 +1783,35 @@ - zinfo.flag_bits |= zipfile._MASK_USE_DATA_DESCRIPTOR # Include an extended local header. - orig_zip.writestr(zinfo, data) - -+ def test_write_with_source_date_epoch(self): -+ with os_helper.EnvironmentVarGuard() as env: -+ # Set the SOURCE_DATE_EPOCH environment variable to a specific timestamp -+ env['SOURCE_DATE_EPOCH'] = "1735715999" -+ -+ with zipfile.ZipFile(TESTFN, "w") as zf: -+ zf.writestr("test_source_date_epoch.txt", "Testing SOURCE_DATE_EPOCH") -+ -+ with zipfile.ZipFile(TESTFN, "r") as zf: -+ zip_info = zf.getinfo("test_source_date_epoch.txt") -+ get_time = time.localtime(int(os.environ['SOURCE_DATE_EPOCH']))[:6] -+ # Compare each element of the date_time tuple -+ # Allow for a 1-second difference -+ for z_time, g_time in zip(zip_info.date_time, get_time): -+ self.assertAlmostEqual(z_time, g_time, delta=1) -+ -+ def test_write_without_source_date_epoch(self): -+ with os_helper.EnvironmentVarGuard() as env: -+ del env['SOURCE_DATE_EPOCH'] -+ -+ with zipfile.ZipFile(TESTFN, "w") as zf: -+ zf.writestr("test_no_source_date_epoch.txt", "Testing without SOURCE_DATE_EPOCH") -+ -+ with zipfile.ZipFile(TESTFN, "r") as zf: -+ zip_info = zf.getinfo("test_no_source_date_epoch.txt") -+ current_time = time.localtime()[:6] -+ for z_time, c_time in zip(zip_info.date_time, current_time): -+ self.assertAlmostEqual(z_time, c_time, delta=1) -+ - def test_close(self): - """Check that the zipfile is closed after the 'with' block.""" - with zipfile.ZipFile(TESTFN2, "w") as zipfp: -@@ -2211,6 +2243,34 @@ - zi = zipfile.ZipInfo(filename="empty") - self.assertEqual(repr(zi), "") - -+ def test_for_archive(self): -+ base_filename = TESTFN2.rstrip('/') -+ -+ with zipfile.ZipFile(TESTFN, mode="w", compresslevel=1, -+ compression=zipfile.ZIP_STORED) as zf: -+ # no trailing forward slash -+ zi = zipfile.ZipInfo(base_filename)._for_archive(zf) -+ self.assertEqual(zi.compress_level, 1) -+ self.assertEqual(zi.compress_type, zipfile.ZIP_STORED) -+ # ?rw- --- --- -+ filemode = stat.S_IRUSR | stat.S_IWUSR -+ # filemode is stored as the highest 16 bits of external_attr -+ self.assertEqual(zi.external_attr >> 16, filemode) -+ self.assertEqual(zi.external_attr & 0xFF, 0) # no MS-DOS flag -+ -+ with zipfile.ZipFile(TESTFN, mode="w", compresslevel=1, -+ compression=zipfile.ZIP_STORED) as zf: -+ # with a trailing slash -+ zi = zipfile.ZipInfo(f'{base_filename}/')._for_archive(zf) -+ self.assertEqual(zi.compress_level, 1) -+ self.assertEqual(zi.compress_type, zipfile.ZIP_STORED) -+ # d rwx rwx r-x -+ filemode = stat.S_IFDIR -+ filemode |= stat.S_IRWXU | stat.S_IRWXG -+ filemode |= stat.S_IROTH | stat.S_IXOTH -+ self.assertEqual(zi.external_attr >> 16, filemode) -+ self.assertEqual(zi.external_attr & 0xFF, 0x10) # MS-DOS flag -+ - def test_create_empty_zipinfo_default_attributes(self): - """Ensure all required attributes are set.""" - zi = zipfile.ZipInfo() -@@ -2333,6 +2393,18 @@ - fp.seek(1, os.SEEK_CUR) - self.assertEqual(fp.read(-1), b'men!') - -+ def test_uncompressed_interleaved_seek_read(self): -+ # gh-127847: Make sure the position in the archive is correct -+ # in the special case of seeking in a ZIP_STORED entry. -+ with zipfile.ZipFile(TESTFN, "w") as zipf: -+ zipf.writestr("a.txt", "123") -+ zipf.writestr("b.txt", "456") -+ with zipfile.ZipFile(TESTFN, "r") as zipf: -+ with zipf.open("a.txt", "r") as a, zipf.open("b.txt", "r") as b: -+ self.assertEqual(a.read(1), b"1") -+ self.assertEqual(b.seek(1), 1) -+ self.assertEqual(b.read(1), b"5") -+ - @requires_bz2() - def test_decompress_without_3rd_party_library(self): - data = b'PK\x05\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' -@@ -3448,5 +3520,87 @@ - b"zzz", zipfile._Extra.strip(b"zzz", (self.ZIP64_EXTRA,))) - - -+class StatIO(_pyio.BytesIO): -+ """Buffer which remembers the number of bytes that were read.""" -+ -+ def __init__(self): -+ super().__init__() -+ self.bytes_read = 0 -+ -+ def read(self, size=-1): -+ bs = super().read(size) -+ self.bytes_read += len(bs) -+ return bs -+ -+ -+class StoredZipExtFileRandomReadTest(unittest.TestCase): -+ """Tests whether an uncompressed, unencrypted zip entry can be randomly -+ seek and read without reading redundant bytes.""" -+ def test_stored_seek_and_read(self): -+ -+ sio = StatIO() -+ # 20000 bytes -+ txt = b'0123456789' * 2000 -+ -+ # The seek length must be greater than ZipExtFile.MIN_READ_SIZE -+ # as `ZipExtFile._read2()` reads in blocks of this size and we -+ # need to seek out of the buffered data -+ read_buffer_size = zipfile.ZipExtFile.MIN_READ_SIZE -+ self.assertGreaterEqual(10002, read_buffer_size) # for forward seek test -+ self.assertGreaterEqual(5003, read_buffer_size) # for backward seek test -+ # The read length must be less than MIN_READ_SIZE, since we assume that -+ # only 1 block is read in the test. -+ read_length = 100 -+ self.assertGreaterEqual(read_buffer_size, read_length) # for read() calls -+ -+ with zipfile.ZipFile(sio, "w", compression=zipfile.ZIP_STORED) as zipf: -+ zipf.writestr("foo.txt", txt) -+ -+ # check random seek and read on a file -+ with zipfile.ZipFile(sio, "r") as zipf: -+ with zipf.open("foo.txt", "r") as fp: -+ # Test this optimized read hasn't rewound and read from the -+ # start of the file (as in the case of the unoptimized path) -+ -+ # forward seek -+ old_count = sio.bytes_read -+ forward_seek_len = 10002 -+ current_pos = 0 -+ fp.seek(forward_seek_len, os.SEEK_CUR) -+ current_pos += forward_seek_len -+ self.assertEqual(fp.tell(), current_pos) -+ self.assertEqual(fp._left, fp._compress_left) -+ arr = fp.read(read_length) -+ current_pos += read_length -+ self.assertEqual(fp.tell(), current_pos) -+ self.assertEqual(arr, txt[current_pos - read_length:current_pos]) -+ self.assertEqual(fp._left, fp._compress_left) -+ read_count = sio.bytes_read - old_count -+ self.assertLessEqual(read_count, read_buffer_size) -+ -+ # backward seek -+ old_count = sio.bytes_read -+ backward_seek_len = 5003 -+ fp.seek(-backward_seek_len, os.SEEK_CUR) -+ current_pos -= backward_seek_len -+ self.assertEqual(fp.tell(), current_pos) -+ self.assertEqual(fp._left, fp._compress_left) -+ arr = fp.read(read_length) -+ current_pos += read_length -+ self.assertEqual(fp.tell(), current_pos) -+ self.assertEqual(arr, txt[current_pos - read_length:current_pos]) -+ self.assertEqual(fp._left, fp._compress_left) -+ read_count = sio.bytes_read - old_count -+ self.assertLessEqual(read_count, read_buffer_size) -+ -+ # eof flags test -+ fp.seek(0, os.SEEK_END) -+ fp.seek(12345, os.SEEK_SET) -+ current_pos = 12345 -+ arr = fp.read(read_length) -+ current_pos += read_length -+ self.assertEqual(arr, txt[current_pos - read_length:current_pos]) -+ -+ - if __name__ == "__main__": - unittest.main() -diff --git a/Lib/threading.py b/Lib/threading.py -index 78e59112427..da9cdf0b09d 100644 ---- a/Lib/threading.py -+++ b/Lib/threading.py -@@ -3,7 +3,6 @@ - import os as _os - import sys as _sys - import _thread --import warnings - - from time import monotonic as _time - from _weakrefset import WeakSet -@@ -133,6 +132,7 @@ - - """ - if args or kwargs: -+ import warnings - warnings.warn( - 'Passing arguments to RLock is deprecated and will be removed in 3.15', - DeprecationWarning, -@@ -694,7 +694,7 @@ - - """ - if parties < 1: -- raise ValueError("parties must be > 0") -+ raise ValueError("parties must be >= 1") - self._cond = Condition(Lock()) - self._action = action - self._timeout = timeout -diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py -index bfec04bb6c1..0baed8b569e 100644 ---- a/Lib/tkinter/__init__.py -+++ b/Lib/tkinter/__init__.py -@@ -2265,7 +2265,7 @@ - explicitly. DEFAULT can be the relative path to a .ico file - (example: root.iconbitmap(default='myicon.ico') ). See Tk - documentation for more information.""" -- if default: -+ if default is not None: - return self.tk.call('wm', 'iconbitmap', self._w, '-default', default) - else: - return self.tk.call('wm', 'iconbitmap', self._w, bitmap) -@@ -2741,6 +2741,8 @@ - del cnf['name'] - if not name: - name = self.__class__.__name__.lower() -+ if name[-1].isdigit(): -+ name += "!" # Avoid duplication when calculating names below - if master._last_child_ids is None: - master._last_child_ids = {} - count = master._last_child_ids.get(name, 0) + 1 -diff --git a/Lib/tokenize.py b/Lib/tokenize.py -index 7ece4e9b70d..9ce95a62d96 100644 ---- a/Lib/tokenize.py -+++ b/Lib/tokenize.py -@@ -169,6 +169,7 @@ - self.prev_row = 1 - self.prev_col = 0 - self.prev_type = None -+ self.prev_line = "" - self.encoding = None - - def add_whitespace(self, start): -@@ -176,14 +177,28 @@ - if row < self.prev_row or row == self.prev_row and col < self.prev_col: - raise ValueError("start ({},{}) precedes previous end ({},{})" - .format(row, col, self.prev_row, self.prev_col)) -- row_offset = row - self.prev_row -- if row_offset: -- self.tokens.append("\\\n" * row_offset) -- self.prev_col = 0 -+ self.add_backslash_continuation(start) - col_offset = col - self.prev_col - if col_offset: - self.tokens.append(" " * col_offset) - -+ def add_backslash_continuation(self, start): -+ """Add backslash continuation characters if the row has increased -+ without encountering a newline token. -+ -+ This also inserts the correct amount of whitespace before the backslash. -+ """ -+ row = start[0] -+ row_offset = row - self.prev_row -+ if row_offset == 0: -+ return -+ -+ newline = '\r\n' if self.prev_line.endswith('\r\n') else '\n' -+ line = self.prev_line.rstrip('\\\r\n') -+ ws = ''.join(_itertools.takewhile(str.isspace, reversed(line))) -+ self.tokens.append(ws + f"\\{newline}" * row_offset) -+ self.prev_col = 0 -+ - def escape_brackets(self, token): - characters = [] - consume_until_next_bracket = False -@@ -243,8 +258,6 @@ - end_line, end_col = end - extra_chars = last_line.count("{{") + last_line.count("}}") - end = (end_line, end_col + extra_chars) -- elif tok_type in (STRING, FSTRING_START) and self.prev_type in (STRING, FSTRING_END): -- self.tokens.append(" ") - - self.add_whitespace(start) - self.tokens.append(token) -@@ -253,6 +266,7 @@ - self.prev_row += 1 - self.prev_col = 0 - self.prev_type = tok_type -+ self.prev_line = line - return "".join(self.tokens) - - def compat(self, token, iterable): -@@ -318,16 +332,10 @@ - with at least two elements, a token number and token value. If - only two tokens are passed, the resulting output is poor. - -- Round-trip invariant for full input: -- Untokenized source will match input source exactly -- -- Round-trip invariant for limited input: -- # Output bytes will tokenize back to the input -- t1 = [tok[:2] for tok in tokenize(f.readline)] -- newcode = untokenize(t1) -- readline = BytesIO(newcode).readline -- t2 = [tok[:2] for tok in tokenize(readline)] -- assert t1 == t2 -+ The result is guaranteed to tokenize back to match the input so -+ that the conversion is lossless and round-trips are assured. -+ The guarantee applies only to the token type and token string as -+ the spacing between tokens (column positions) may change. - """ - ut = Untokenizer() - out = ut.untokenize(iterable) -diff --git a/Lib/tomllib/_parser.py b/Lib/tomllib/_parser.py -index 4d208bcfb4a..0e522c3a69e 100644 ---- a/Lib/tomllib/_parser.py -+++ b/Lib/tomllib/_parser.py -@@ -4,11 +4,7 @@ - - from __future__ import annotations - --from collections.abc import Iterable --import string - from types import MappingProxyType --from typing import Any, BinaryIO, NamedTuple --import warnings - - from ._re import ( - RE_DATETIME, -@@ -18,7 +14,13 @@ - match_to_localtime, - match_to_number, - ) --from ._types import Key, ParseFloat, Pos -+ -+TYPE_CHECKING = False -+if TYPE_CHECKING: -+ from collections.abc import Iterable -+ from typing import IO, Any -+ -+ from ._types import Key, ParseFloat, Pos - - ASCII_CTRL = frozenset(chr(i) for i in range(32)) | frozenset(chr(127)) - -@@ -34,9 +36,11 @@ - - TOML_WS = frozenset(" \t") - TOML_WS_AND_NEWLINE = TOML_WS | frozenset("\n") --BARE_KEY_CHARS = frozenset(string.ascii_letters + string.digits + "-_") -+BARE_KEY_CHARS = frozenset( -+ "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789" "-_" -+) - KEY_INITIAL_CHARS = BARE_KEY_CHARS | frozenset("\"'") --HEXDIGIT_CHARS = frozenset(string.hexdigits) -+HEXDIGIT_CHARS = frozenset("abcdef" "ABCDEF" "0123456789") - - BASIC_STR_ESCAPE_REPLACEMENTS = MappingProxyType( - { -@@ -80,6 +84,8 @@ - or not isinstance(doc, str) - or not isinstance(pos, int) - ): -+ import warnings -+ - warnings.warn( - "Free-form arguments for TOMLDecodeError are deprecated. " - "Please set 'msg' (str), 'doc' (str) and 'pos' (int) arguments only.", -@@ -115,7 +121,7 @@ - self.colno = colno - - --def load(fp: BinaryIO, /, *, parse_float: ParseFloat = float) -> dict[str, Any]: -+def load(fp: IO[bytes], /, *, parse_float: ParseFloat = float) -> dict[str, Any]: - """Parse TOML from a binary file object.""" - b = fp.read() - try: -@@ -139,7 +145,7 @@ - f"Expected str object, not '{type(s).__qualname__}'" - ) from None - pos = 0 -- out = Output(NestedDict(), Flags()) -+ out = Output() - header: Key = () - parse_float = make_safe_parse_float(parse_float) - -@@ -290,9 +296,10 @@ - cont[last_key] = [{}] - - --class Output(NamedTuple): -- data: NestedDict -- flags: Flags -+class Output: -+ def __init__(self) -> None: -+ self.data = NestedDict() -+ self.flags = Flags() - - - def skip_chars(src: str, pos: Pos, chars: Iterable[str]) -> Pos: -diff --git a/Lib/tomllib/_re.py b/Lib/tomllib/_re.py -index 9eacefc7295..1ca6bef77a0 100644 ---- a/Lib/tomllib/_re.py -+++ b/Lib/tomllib/_re.py -@@ -7,9 +7,12 @@ - from datetime import date, datetime, time, timedelta, timezone, tzinfo - from functools import lru_cache - import re --from typing import Any - --from ._types import ParseFloat -+TYPE_CHECKING = False -+if TYPE_CHECKING: -+ from typing import Any -+ -+ from ._types import ParseFloat - - # E.g. - # - 00:32:00.999999 -diff --git a/Lib/traceback.py b/Lib/traceback.py -index 6367c00e4d4..31c73efcef5 100644 ---- a/Lib/traceback.py -+++ b/Lib/traceback.py -@@ -135,7 +135,7 @@ - - def _print_exception_bltin(exc, /): - file = sys.stderr if sys.stderr is not None else sys.__stderr__ -- colorize = _colorize.can_colorize() -+ colorize = _colorize.can_colorize(file=file) - return print_exception(exc, limit=BUILTIN_EXCEPTION_LIMIT, file=file, colorize=colorize) - - -@@ -1283,7 +1283,7 @@ - filename_suffix = ' ({})'.format(self.filename) - - text = self.text -- if text is not None: -+ if isinstance(text, str): - # text = " foo\n" - # rtext = " foo" - # ltext = "foo" -@@ -1292,10 +1292,17 @@ - spaces = len(rtext) - len(ltext) - if self.offset is None: - yield ' {}\n'.format(ltext) -- else: -+ elif isinstance(self.offset, int): - offset = self.offset - if self.lineno == self.end_lineno: -- end_offset = self.end_offset if self.end_offset not in {None, 0} else offset -+ end_offset = ( -+ self.end_offset -+ if ( -+ isinstance(self.end_offset, int) -+ and self.end_offset != 0 -+ ) -+ else offset -+ ) - else: - end_offset = len(rtext) + 1 - -diff --git a/Lib/turtle.py b/Lib/turtle.py -index 8a5801f2efe..e88981d298a 100644 ---- a/Lib/turtle.py -+++ b/Lib/turtle.py -@@ -51,7 +51,7 @@ - turtle. So the turtles can more easily be used as a visual feedback - instrument by the (beginning) programmer. - --- Different turtle shapes, gif-images as turtle shapes, user defined -+- Different turtle shapes, image files as turtle shapes, user defined - and user controllable turtle shapes, among them compound - (multicolored) shapes. Turtle shapes can be stretched and tilted, which - makes turtles very versatile geometrical objects. -@@ -107,6 +107,7 @@ - - from os.path import isfile, split, join - from pathlib import Path -+from contextlib import contextmanager - from copy import deepcopy - from tkinter import simpledialog - -@@ -114,23 +115,24 @@ - 'RawTurtle', 'Turtle', 'RawPen', 'Pen', 'Shape', 'Vec2D'] - _tg_screen_functions = ['addshape', 'bgcolor', 'bgpic', 'bye', - 'clearscreen', 'colormode', 'delay', 'exitonclick', 'getcanvas', -- 'getshapes', 'listen', 'mainloop', 'mode', 'numinput', -+ 'getshapes', 'listen', 'mainloop', 'mode', 'no_animation', 'numinput', - 'onkey', 'onkeypress', 'onkeyrelease', 'onscreenclick', 'ontimer', - 'register_shape', 'resetscreen', 'screensize', 'save', 'setup', -- 'setworldcoordinates', 'textinput', 'title', 'tracer', 'turtles', 'update', -- 'window_height', 'window_width'] -+ 'setworldcoordinates', 'textinput', 'title', 'tracer', 'turtles', -+ 'update', 'window_height', 'window_width'] - _tg_turtle_functions = ['back', 'backward', 'begin_fill', 'begin_poly', 'bk', - 'circle', 'clear', 'clearstamp', 'clearstamps', 'clone', 'color', - 'degrees', 'distance', 'dot', 'down', 'end_fill', 'end_poly', 'fd', -- 'fillcolor', 'filling', 'forward', 'get_poly', 'getpen', 'getscreen', 'get_shapepoly', -- 'getturtle', 'goto', 'heading', 'hideturtle', 'home', 'ht', 'isdown', -- 'isvisible', 'left', 'lt', 'onclick', 'ondrag', 'onrelease', 'pd', -- 'pen', 'pencolor', 'pendown', 'pensize', 'penup', 'pos', 'position', -- 'pu', 'radians', 'right', 'reset', 'resizemode', 'rt', -- 'seth', 'setheading', 'setpos', 'setposition', -- 'setundobuffer', 'setx', 'sety', 'shape', 'shapesize', 'shapetransform', 'shearfactor', 'showturtle', -- 'speed', 'st', 'stamp', 'teleport', 'tilt', 'tiltangle', 'towards', -- 'turtlesize', 'undo', 'undobufferentries', 'up', 'width', -+ 'fillcolor', 'fill', 'filling', 'forward', 'get_poly', 'getpen', -+ 'getscreen', 'get_shapepoly', 'getturtle', 'goto', 'heading', -+ 'hideturtle', 'home', 'ht', 'isdown', 'isvisible', 'left', 'lt', -+ 'onclick', 'ondrag', 'onrelease', 'pd', 'pen', 'pencolor', 'pendown', -+ 'pensize', 'penup', 'poly', 'pos', 'position', 'pu', 'radians', 'right', -+ 'reset', 'resizemode', 'rt', 'seth', 'setheading', 'setpos', -+ 'setposition', 'setundobuffer', 'setx', 'sety', 'shape', 'shapesize', -+ 'shapetransform', 'shearfactor', 'showturtle', 'speed', 'st', 'stamp', -+ 'teleport', 'tilt', 'tiltangle', 'towards', 'turtlesize', 'undo', -+ 'undobufferentries', 'up', 'width', - 'write', 'xcor', 'ycor'] - _tg_utilities = ['write_docstringdict', 'done'] - -@@ -468,7 +470,7 @@ - - def _image(self, filename): - """return an image object containing the -- imagedata from a gif-file named filename. -+ imagedata from an image file named filename. - """ - return TK.PhotoImage(file=filename, master=self.cv) - -@@ -872,10 +874,7 @@ - if isinstance(data, list): - data = tuple(data) - elif type_ == "image": -- if isinstance(data, str): -- if data.lower().endswith(".gif") and isfile(data): -- data = TurtleScreen._image(data) -- # else data assumed to be PhotoImage -+ assert(isinstance(data, TK.PhotoImage)) - elif type_ == "compound": - data = [] - else: -@@ -1100,14 +1099,18 @@ - """Adds a turtle shape to TurtleScreen's shapelist. - - Arguments: -- (1) name is the name of a gif-file and shape is None. -+ (1) name is the name of an image file (PNG, GIF, PGM, and PPM) and shape is None. - Installs the corresponding image shape. - !! Image-shapes DO NOT rotate when turning the turtle, - !! so they do not display the heading of the turtle! -- (2) name is an arbitrary string and shape is a tuple -+ (2) name is an arbitrary string and shape is the name of an image file (PNG, GIF, PGM, and PPM). -+ Installs the corresponding image shape. -+ !! Image-shapes DO NOT rotate when turning the turtle, -+ !! so they do not display the heading of the turtle! -+ (3) name is an arbitrary string and shape is a tuple - of pairs of coordinates. Installs the corresponding - polygon shape -- (3) name is an arbitrary string and shape is a -+ (4) name is an arbitrary string and shape is a - (compound) Shape object. Installs the corresponding - compound shape. - To use a shape, you have to issue the command shape(shapename). -@@ -1120,12 +1123,9 @@ - - """ - if shape is None: -- # image -- if name.lower().endswith(".gif"): -- shape = Shape("image", self._image(name)) -- else: -- raise TurtleGraphicsError("Bad arguments for register_shape.\n" -- + "Use help(register_shape)" ) -+ shape = Shape("image", self._image(name)) -+ elif isinstance(shape, str): -+ shape = Shape("image", self._image(shape)) - elif isinstance(shape, tuple): - shape = Shape("polygon", shape) - ## else shape assumed to be Shape-instance -@@ -1277,6 +1277,26 @@ - return self._delayvalue - self._delayvalue = int(delay) - -+ @contextmanager -+ def no_animation(self): -+ """Temporarily turn off auto-updating the screen. -+ -+ This is useful for drawing complex shapes where even the fastest setting -+ is too slow. Once this context manager is exited, the drawing will -+ be displayed. -+ -+ Example (for a TurtleScreen instance named screen -+ and a Turtle instance named turtle): -+ >>> with screen.no_animation(): -+ ... turtle.circle(50) -+ """ -+ tracer = self.tracer() -+ try: -+ self.tracer(0) -+ yield -+ finally: -+ self.tracer(tracer) -+ - def _incrementudc(self): - """Increment update counter.""" - if not TurtleScreen._RUNNING: -@@ -1454,7 +1474,7 @@ - """Set background image or return name of current backgroundimage. - - Optional argument: -- picname -- a string, name of a gif-file or "nopic". -+ picname -- a string, name of an image file (PNG, GIF, PGM, and PPM) or "nopic". - - If picname is a filename, set the corresponding image as background. - If picname is "nopic", delete backgroundimage, if present. -@@ -3382,6 +3402,24 @@ - """ - return isinstance(self._fillpath, list) - -+ @contextmanager -+ def fill(self): -+ """A context manager for filling a shape. -+ -+ Implicitly ensures the code block is wrapped with -+ begin_fill() and end_fill(). -+ -+ Example (for a Turtle instance named turtle): -+ >>> turtle.color("black", "red") -+ >>> with turtle.fill(): -+ ... turtle.circle(60) -+ """ -+ self.begin_fill() -+ try: -+ yield -+ finally: -+ self.end_fill() -+ - def begin_fill(self): - """Called just before drawing a shape to be filled. - -@@ -3402,7 +3440,6 @@ - self.undobuffer.push(("beginfill", self._fillitem)) - self._update() - -- - def end_fill(self): - """Fill the shape drawn after the call begin_fill(). - -@@ -3506,6 +3543,27 @@ - if self.undobuffer: - self.undobuffer.cumulate = False - -+ @contextmanager -+ def poly(self): -+ """A context manager for recording the vertices of a polygon. -+ -+ Implicitly ensures that the code block is wrapped with -+ begin_poly() and end_poly() -+ -+ Example (for a Turtle instance named turtle) where we create a -+ triangle as the polygon and move the turtle 100 steps forward: -+ >>> with turtle.poly(): -+ ... for side in range(3) -+ ... turtle.forward(50) -+ ... turtle.right(60) -+ >>> turtle.forward(100) -+ """ -+ self.begin_poly() -+ try: -+ yield -+ finally: -+ self.end_poly() -+ - def begin_poly(self): - """Start recording the vertices of a polygon. - -diff --git a/Lib/turtledemo/__main__.py b/Lib/turtledemo/__main__.py -index 9c15916fb66..b49c0beab3c 100644 ---- a/Lib/turtledemo/__main__.py -+++ b/Lib/turtledemo/__main__.py -@@ -105,7 +105,6 @@ - DONE = 4 - EVENTDRIVEN = 5 - --menufont = ("Arial", 12, NORMAL) - btnfont = ("Arial", 12, 'bold') - txtfont = ['Lucida Console', 10, 'normal'] - -@@ -297,23 +296,21 @@ - for entry in getExampleEntries(): - def load(entry=entry): - self.loadfile(entry) -- menu.add_command(label=entry, underline=0, -- font=menufont, command=load) -+ menu.add_command(label=entry, underline=0, command=load) - return menu - - def makeFontMenu(self, master): - menu = Menu(master, tearoff=0) -- menu.add_command(label="Decrease (C-'-')", command=self.decrease_size, -- font=menufont) -- menu.add_command(label="Increase (C-'+')", command=self.increase_size, -- font=menufont) -+ menu.add_command(label="Decrease", command=self.decrease_size, -+ accelerator=f"{'Command' if darwin else 'Ctrl'}+-") -+ menu.add_command(label="Increase", command=self.increase_size, -+ accelerator=f"{'Command' if darwin else 'Ctrl'}+=") - menu.add_separator() - - for size in font_sizes: - def resize(size=size): - self.set_txtsize(size) -- menu.add_command(label=str(size), underline=0, -- font=menufont, command=resize) -+ menu.add_command(label=str(size), underline=0, command=resize) - return menu - - def makeHelpMenu(self, master): -@@ -322,7 +319,7 @@ - for help_label, help_file in help_entries: - def show(help_label=help_label, help_file=help_file): - view_text(self.root, help_label, help_file) -- menu.add_command(label=help_label, font=menufont, command=show) -+ menu.add_command(label=help_label, command=show) - return menu - - def refreshCanvas(self): -diff --git a/Lib/typing.py b/Lib/typing.py -index 5f3aacd8772..66570db7a5b 100644 ---- a/Lib/typing.py -+++ b/Lib/typing.py -@@ -1024,7 +1024,7 @@ - owner=None, - globals=None, - locals=None, -- type_params=None, -+ type_params=_sentinel, - format=annotationlib.Format.VALUE, - _recursive_guard=frozenset(), - ): -@@ -1733,12 +1733,16 @@ - return super().__repr__() - - def __instancecheck__(self, obj): -- return self.__subclasscheck__(type(obj)) -+ for arg in self.__args__: -+ if isinstance(obj, arg): -+ return True -+ return False - - def __subclasscheck__(self, cls): - for arg in self.__args__: - if issubclass(cls, arg): - return True -+ return False - - def __reduce__(self): - func, (origin, args) = super().__reduce__() -diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py -index 55c79d35353..10c3b7e1223 100644 ---- a/Lib/unittest/case.py -+++ b/Lib/unittest/case.py -@@ -1321,13 +1321,71 @@ - """Same as self.assertTrue(isinstance(obj, cls)), with a nicer - default message.""" - if not isinstance(obj, cls): -- standardMsg = '%s is not an instance of %r' % (safe_repr(obj), cls) -+ if isinstance(cls, tuple): -+ standardMsg = f'{safe_repr(obj)} is not an instance of any of {cls!r}' -+ else: -+ standardMsg = f'{safe_repr(obj)} is not an instance of {cls!r}' - self.fail(self._formatMessage(msg, standardMsg)) - - def assertNotIsInstance(self, obj, cls, msg=None): - """Included for symmetry with assertIsInstance.""" - if isinstance(obj, cls): -- standardMsg = '%s is an instance of %r' % (safe_repr(obj), cls) -+ if isinstance(cls, tuple): -+ for x in cls: -+ if isinstance(obj, x): -+ cls = x -+ break -+ standardMsg = f'{safe_repr(obj)} is an instance of {cls!r}' -+ self.fail(self._formatMessage(msg, standardMsg)) -+ -+ def assertIsSubclass(self, cls, superclass, msg=None): -+ try: -+ if issubclass(cls, superclass): -+ return -+ except TypeError: -+ if not isinstance(cls, type): -+ self.fail(self._formatMessage(msg, f'{cls!r} is not a class')) -+ raise -+ if isinstance(superclass, tuple): -+ standardMsg = f'{cls!r} is not a subclass of any of {superclass!r}' -+ else: -+ standardMsg = f'{cls!r} is not a subclass of {superclass!r}' -+ self.fail(self._formatMessage(msg, standardMsg)) -+ -+ def assertNotIsSubclass(self, cls, superclass, msg=None): -+ try: -+ if not issubclass(cls, superclass): -+ return -+ except TypeError: -+ if not isinstance(cls, type): -+ self.fail(self._formatMessage(msg, f'{cls!r} is not a class')) -+ raise -+ if isinstance(superclass, tuple): -+ for x in superclass: -+ if issubclass(cls, x): -+ superclass = x -+ break -+ standardMsg = f'{cls!r} is a subclass of {superclass!r}' -+ self.fail(self._formatMessage(msg, standardMsg)) -+ -+ def assertHasAttr(self, obj, name, msg=None): -+ if not hasattr(obj, name): -+ if isinstance(obj, types.ModuleType): -+ standardMsg = f'module {obj.__name__!r} has no attribute {name!r}' -+ elif isinstance(obj, type): -+ standardMsg = f'type object {obj.__name__!r} has no attribute {name!r}' -+ else: -+ standardMsg = f'{type(obj).__name__!r} object has no attribute {name!r}' -+ self.fail(self._formatMessage(msg, standardMsg)) -+ -+ def assertNotHasAttr(self, obj, name, msg=None): -+ if hasattr(obj, name): -+ if isinstance(obj, types.ModuleType): -+ standardMsg = f'module {obj.__name__!r} has unexpected attribute {name!r}' -+ elif isinstance(obj, type): -+ standardMsg = f'type object {obj.__name__!r} has unexpected attribute {name!r}' -+ else: -+ standardMsg = f'{type(obj).__name__!r} object has unexpected attribute {name!r}' - self.fail(self._formatMessage(msg, standardMsg)) - - def assertRaisesRegex(self, expected_exception, expected_regex, -@@ -1391,6 +1449,80 @@ - msg = self._formatMessage(msg, standardMsg) - raise self.failureException(msg) - -+ def _tail_type_check(self, s, tails, msg): -+ if not isinstance(tails, tuple): -+ tails = (tails,) -+ for tail in tails: -+ if isinstance(tail, str): -+ if not isinstance(s, str): -+ self.fail(self._formatMessage(msg, -+ f'Expected str, not {type(s).__name__}')) -+ elif isinstance(tail, (bytes, bytearray)): -+ if not isinstance(s, (bytes, bytearray)): -+ self.fail(self._formatMessage(msg, -+ f'Expected bytes, not {type(s).__name__}')) -+ -+ def assertStartsWith(self, s, prefix, msg=None): -+ try: -+ if s.startswith(prefix): -+ return -+ except (AttributeError, TypeError): -+ self._tail_type_check(s, prefix, msg) -+ raise -+ a = safe_repr(s, short=True) -+ b = safe_repr(prefix) -+ if isinstance(prefix, tuple): -+ standardMsg = f"{a} doesn't start with any of {b}" -+ else: -+ standardMsg = f"{a} doesn't start with {b}" -+ self.fail(self._formatMessage(msg, standardMsg)) -+ -+ def assertNotStartsWith(self, s, prefix, msg=None): -+ try: -+ if not s.startswith(prefix): -+ return -+ except (AttributeError, TypeError): -+ self._tail_type_check(s, prefix, msg) -+ raise -+ if isinstance(prefix, tuple): -+ for x in prefix: -+ if s.startswith(x): -+ prefix = x -+ break -+ a = safe_repr(s, short=True) -+ b = safe_repr(prefix) -+ self.fail(self._formatMessage(msg, f"{a} starts with {b}")) -+ -+ def assertEndsWith(self, s, suffix, msg=None): -+ try: -+ if s.endswith(suffix): -+ return -+ except (AttributeError, TypeError): -+ self._tail_type_check(s, suffix, msg) -+ raise -+ a = safe_repr(s, short=True) -+ b = safe_repr(suffix) -+ if isinstance(suffix, tuple): -+ standardMsg = f"{a} doesn't end with any of {b}" -+ else: -+ standardMsg = f"{a} doesn't end with {b}" -+ self.fail(self._formatMessage(msg, standardMsg)) -+ -+ def assertNotEndsWith(self, s, suffix, msg=None): -+ try: -+ if not s.endswith(suffix): -+ return -+ except (AttributeError, TypeError): -+ self._tail_type_check(s, suffix, msg) -+ raise -+ if isinstance(suffix, tuple): -+ for x in suffix: -+ if s.endswith(x): -+ suffix = x -+ break -+ a = safe_repr(s, short=True) -+ b = safe_repr(suffix) -+ self.fail(self._formatMessage(msg, f"{a} ends with {b}")) - - - class FunctionTestCase(TestCase): -diff --git a/Lib/unittest/result.py b/Lib/unittest/result.py -index 97262735aa8..b8ea396db67 100644 ---- a/Lib/unittest/result.py -+++ b/Lib/unittest/result.py -@@ -191,7 +191,8 @@ - capture_locals=self.tb_locals, compact=True) - from _colorize import can_colorize - -- msgLines = list(tb_e.format(colorize=can_colorize())) -+ colorize = hasattr(self, "stream") and can_colorize(file=self.stream) -+ msgLines = list(tb_e.format(colorize=colorize)) - - if self.buffer: - output = sys.stdout.getvalue() -diff --git a/Lib/unittest/runner.py b/Lib/unittest/runner.py -index d60c295a1ed..eb0234a2617 100644 ---- a/Lib/unittest/runner.py -+++ b/Lib/unittest/runner.py -@@ -45,7 +45,7 @@ - self.showAll = verbosity > 1 - self.dots = verbosity == 1 - self.descriptions = descriptions -- self._ansi = get_colors() -+ self._ansi = get_colors(file=stream) - self._newline = True - self.durations = durations - -@@ -286,7 +286,7 @@ - expected_fails, unexpected_successes, skipped = results - - infos = [] -- ansi = get_colors() -+ ansi = get_colors(file=self.stream) - bold_red = ansi.BOLD_RED - green = ansi.GREEN - red = ansi.RED -diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py -index c412c729852..9d51f4c6812 100644 ---- a/Lib/urllib/parse.py -+++ b/Lib/urllib/parse.py -@@ -439,6 +439,23 @@ - raise ValueError("netloc '" + netloc + "' contains invalid " + - "characters under NFKC normalization") - -+def _check_bracketed_netloc(netloc): -+ # Note that this function must mirror the splitting -+ # done in NetlocResultMixins._hostinfo(). -+ hostname_and_port = netloc.rpartition('@')[2] -+ before_bracket, have_open_br, bracketed = hostname_and_port.partition('[') -+ if have_open_br: -+ # No data is allowed before a bracket. -+ if before_bracket: -+ raise ValueError("Invalid IPv6 URL") -+ hostname, _, port = bracketed.partition(']') -+ # No data is allowed after the bracket but before the port delimiter. -+ if port and not port.startswith(":"): -+ raise ValueError("Invalid IPv6 URL") -+ else: -+ hostname, _, port = hostname_and_port.partition(':') -+ _check_bracketed_host(hostname) -+ - # Valid bracketed hosts are defined in - # https://www.rfc-editor.org/rfc/rfc3986#page-49 and https://url.spec.whatwg.org/ - def _check_bracketed_host(hostname): -@@ -505,8 +522,7 @@ - (']' in netloc and '[' not in netloc)): - raise ValueError("Invalid IPv6 URL") - if '[' in netloc and ']' in netloc: -- bracketed_host = netloc.partition('[')[2].partition(']')[0] -- _check_bracketed_host(bracketed_host) -+ _check_bracketed_netloc(netloc) - if allow_fragments and '#' in url: - url, fragment = url.split('#', 1) - if '?' in url: -diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py -index c5a6a18a32b..0d1b594b8cf 100644 ---- a/Lib/urllib/request.py -+++ b/Lib/urllib/request.py -@@ -1048,7 +1048,7 @@ - - - class AbstractDigestAuthHandler: -- # Digest authentication is specified in RFC 2617. -+ # Digest authentication is specified in RFC 2617/7616. - - # XXX The client does not inspect the Authentication-Info header - # in a successful response. -@@ -1176,11 +1176,14 @@ - return base - - def get_algorithm_impls(self, algorithm): -+ # algorithm names taken from RFC 7616 Section 6.1 - # lambdas assume digest modules are imported at the top level - if algorithm == 'MD5': - H = lambda x: hashlib.md5(x.encode("ascii")).hexdigest() -- elif algorithm == 'SHA': -+ elif algorithm == 'SHA': # non-standard, retained for compatibility. - H = lambda x: hashlib.sha1(x.encode("ascii")).hexdigest() -+ elif algorithm == 'SHA-256': -+ H = lambda x: hashlib.sha256(x.encode("ascii")).hexdigest() - # XXX MD5-sess - else: - raise ValueError("Unsupported digest authentication " -diff --git a/Lib/urllib/robotparser.py b/Lib/urllib/robotparser.py -index c58565e3945..409f2b2e48d 100644 ---- a/Lib/urllib/robotparser.py -+++ b/Lib/urllib/robotparser.py -@@ -11,6 +11,7 @@ - """ - - import collections -+import urllib.error - import urllib.parse - import urllib.request - -@@ -65,6 +66,7 @@ - self.disallow_all = True - elif err.code >= 400 and err.code < 500: - self.allow_all = True -+ err.close() - else: - raw = f.read() - self.parse(raw.decode("utf-8").splitlines()) -diff --git a/Lib/uuid.py b/Lib/uuid.py -index 9c6ad9643cf..36809b85cb8 100644 ---- a/Lib/uuid.py -+++ b/Lib/uuid.py -@@ -42,6 +42,14 @@ - # make a UUID from a 16-byte string - >>> uuid.UUID(bytes=x.bytes) - UUID('00010203-0405-0607-0809-0a0b0c0d0e0f') -+ -+ # get the Nil UUID -+ >>> uuid.NIL -+ UUID('00000000-0000-0000-0000-000000000000') -+ -+ # get the Max UUID -+ >>> uuid.MAX -+ UUID('ffffffff-ffff-ffff-ffff-ffffffffffff') - """ - - import os -@@ -85,6 +93,17 @@ - unknown = None - - -+_UINT_128_MAX = (1 << 128) - 1 -+# 128-bit mask to clear the variant and version bits of a UUID integral value -+_RFC_4122_CLEARFLAGS_MASK = ~((0xf000 << 64) | (0xc000 << 48)) -+# RFC 4122 variant bits and version bits to activate on a UUID integral value. -+_RFC_4122_VERSION_1_FLAGS = ((1 << 76) | (0x8000 << 48)) -+_RFC_4122_VERSION_3_FLAGS = ((3 << 76) | (0x8000 << 48)) -+_RFC_4122_VERSION_4_FLAGS = ((4 << 76) | (0x8000 << 48)) -+_RFC_4122_VERSION_5_FLAGS = ((5 << 76) | (0x8000 << 48)) -+_RFC_4122_VERSION_8_FLAGS = ((8 << 76) | (0x8000 << 48)) -+ -+ - class UUID: - """Instances of the UUID class represent UUIDs as specified in RFC 4122. - UUID objects are immutable, hashable, and usable as dictionary keys. -@@ -174,57 +193,69 @@ - if [hex, bytes, bytes_le, fields, int].count(None) != 4: - raise TypeError('one of the hex, bytes, bytes_le, fields, ' - 'or int arguments must be given') -- if hex is not None: -+ if int is not None: -+ pass -+ elif hex is not None: - hex = hex.replace('urn:', '').replace('uuid:', '') - hex = hex.strip('{}').replace('-', '') - if len(hex) != 32: - raise ValueError('badly formed hexadecimal UUID string') - int = int_(hex, 16) -- if bytes_le is not None: -+ elif bytes_le is not None: - if len(bytes_le) != 16: - raise ValueError('bytes_le is not a 16-char string') -+ assert isinstance(bytes_le, bytes_), repr(bytes_le) - bytes = (bytes_le[4-1::-1] + bytes_le[6-1:4-1:-1] + - bytes_le[8-1:6-1:-1] + bytes_le[8:]) -- if bytes is not None: -+ int = int_.from_bytes(bytes) # big endian -+ elif bytes is not None: - if len(bytes) != 16: - raise ValueError('bytes is not a 16-char string') - assert isinstance(bytes, bytes_), repr(bytes) - int = int_.from_bytes(bytes) # big endian -- if fields is not None: -+ elif fields is not None: - if len(fields) != 6: - raise ValueError('fields is not a 6-tuple') - (time_low, time_mid, time_hi_version, - clock_seq_hi_variant, clock_seq_low, node) = fields -- if not 0 <= time_low < 1<<32: -+ if not 0 <= time_low < (1 << 32): - raise ValueError('field 1 out of range (need a 32-bit value)') -- if not 0 <= time_mid < 1<<16: -+ if not 0 <= time_mid < (1 << 16): - raise ValueError('field 2 out of range (need a 16-bit value)') -- if not 0 <= time_hi_version < 1<<16: -+ if not 0 <= time_hi_version < (1 << 16): - raise ValueError('field 3 out of range (need a 16-bit value)') -- if not 0 <= clock_seq_hi_variant < 1<<8: -+ if not 0 <= clock_seq_hi_variant < (1 << 8): - raise ValueError('field 4 out of range (need an 8-bit value)') -- if not 0 <= clock_seq_low < 1<<8: -+ if not 0 <= clock_seq_low < (1 << 8): - raise ValueError('field 5 out of range (need an 8-bit value)') -- if not 0 <= node < 1<<48: -+ if not 0 <= node < (1 << 48): - raise ValueError('field 6 out of range (need a 48-bit value)') - clock_seq = (clock_seq_hi_variant << 8) | clock_seq_low - int = ((time_low << 96) | (time_mid << 80) | - (time_hi_version << 64) | (clock_seq << 48) | node) -- if int is not None: -- if not 0 <= int < 1<<128: -- raise ValueError('int is out of range (need a 128-bit value)') -+ if not 0 <= int <= _UINT_128_MAX: -+ raise ValueError('int is out of range (need a 128-bit value)') - if version is not None: - if not 1 <= version <= 8: - raise ValueError('illegal version number') -+ # clear the variant and the version number bits -+ int &= _RFC_4122_CLEARFLAGS_MASK - # Set the variant to RFC 4122/9562. -- int &= ~(0xc000 << 48) -- int |= 0x8000 << 48 -+ int |= 0x8000_0000_0000_0000 # (0x8000 << 48) - # Set the version number. -- int &= ~(0xf000 << 64) - int |= version << 76 - object.__setattr__(self, 'int', int) - object.__setattr__(self, 'is_safe', is_safe) - -+ @classmethod -+ def _from_int(cls, value): -+ """Create a UUID from an integer *value*. Internal use only.""" -+ assert 0 <= value <= _UINT_128_MAX, repr(value) -+ self = object.__new__(cls) -+ object.__setattr__(self, 'int', value) -+ object.__setattr__(self, 'is_safe', SafeUUID.unknown) -+ return self -+ - def __getstate__(self): - d = {'int': self.int} - if self.is_safe != SafeUUID.unknown: -@@ -700,24 +731,30 @@ - """Generate a UUID from the MD5 hash of a namespace UUID and a name.""" - if isinstance(name, str): - name = bytes(name, "utf-8") -- from hashlib import md5 -- digest = md5( -- namespace.bytes + name, -- usedforsecurity=False -- ).digest() -- return UUID(bytes=digest[:16], version=3) -+ import hashlib -+ h = hashlib.md5(namespace.bytes + name, usedforsecurity=False) -+ int_uuid_3 = int.from_bytes(h.digest()) -+ int_uuid_3 &= _RFC_4122_CLEARFLAGS_MASK -+ int_uuid_3 |= _RFC_4122_VERSION_3_FLAGS -+ return UUID._from_int(int_uuid_3) - - def uuid4(): - """Generate a random UUID.""" -- return UUID(bytes=os.urandom(16), version=4) -+ int_uuid_4 = int.from_bytes(os.urandom(16)) -+ int_uuid_4 &= _RFC_4122_CLEARFLAGS_MASK -+ int_uuid_4 |= _RFC_4122_VERSION_4_FLAGS -+ return UUID._from_int(int_uuid_4) - - def uuid5(namespace, name): - """Generate a UUID from the SHA-1 hash of a namespace UUID and a name.""" - if isinstance(name, str): - name = bytes(name, "utf-8") -- from hashlib import sha1 -- hash = sha1(namespace.bytes + name).digest() -- return UUID(bytes=hash[:16], version=5) -+ import hashlib -+ h = hashlib.sha1(namespace.bytes + name, usedforsecurity=False) -+ int_uuid_5 = int.from_bytes(h.digest()[:16]) -+ int_uuid_5 &= _RFC_4122_CLEARFLAGS_MASK -+ int_uuid_5 |= _RFC_4122_VERSION_5_FLAGS -+ return UUID._from_int(int_uuid_5) - - def uuid8(a=None, b=None, c=None): - """Generate a UUID from three custom blocks. -@@ -740,7 +777,9 @@ - int_uuid_8 = (a & 0xffff_ffff_ffff) << 80 - int_uuid_8 |= (b & 0xfff) << 64 - int_uuid_8 |= c & 0x3fff_ffff_ffff_ffff -- return UUID(int=int_uuid_8, version=8) -+ # by construction, the variant and version bits are already cleared -+ int_uuid_8 |= _RFC_4122_VERSION_8_FLAGS -+ return UUID._from_int(int_uuid_8) - - def main(): - """Run the uuid command line interface.""" -@@ -799,5 +838,10 @@ - NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8') - NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8') - -+# RFC 9562 Sections 5.9 and 5.10 define the special Nil and Max UUID formats. -+ -+NIL = UUID('00000000-0000-0000-0000-000000000000') -+MAX = UUID('ffffffff-ffff-ffff-ffff-ffffffffffff') -+ - if __name__ == "__main__": - main() -diff --git a/Lib/warnings.py b/Lib/warnings.py -index e83cde37ab2..13ad6c8aacb 100644 ---- a/Lib/warnings.py -+++ b/Lib/warnings.py -@@ -185,24 +185,32 @@ - raise ValueError("lineno must be an int >= 0") - _add_filter(action, None, category, None, lineno, append=append) - -+def _filters_mutated(): -+ # Even though this function is not part of the public API, it's used by -+ # a fair amount of user code. -+ with _lock: -+ _filters_mutated_lock_held() -+ - def _add_filter(*item, append): -- # Remove possible duplicate filters, so new one will be placed -- # in correct place. If append=True and duplicate exists, do nothing. -- if not append: -- try: -- filters.remove(item) -- except ValueError: -- pass -- filters.insert(0, item) -- else: -- if item not in filters: -- filters.append(item) -- _filters_mutated() -+ with _lock: -+ if not append: -+ # Remove possible duplicate filters, so new one will be placed -+ # in correct place. If append=True and duplicate exists, do nothing. -+ try: -+ filters.remove(item) -+ except ValueError: -+ pass -+ filters.insert(0, item) -+ else: -+ if item not in filters: -+ filters.append(item) -+ _filters_mutated_lock_held() - - def resetwarnings(): - """Clear the list of warning filters, so that no filters are active.""" -- filters[:] = [] -- _filters_mutated() -+ with _lock: -+ filters[:] = [] -+ _filters_mutated_lock_held() - - class _OptionError(Exception): - """Exception used by option processing helpers.""" -@@ -353,11 +361,6 @@ - module = filename or "" - if module[-3:].lower() == ".py": - module = module[:-3] # XXX What about leading pathname? -- if registry is None: -- registry = {} -- if registry.get('version', 0) != _filters_version: -- registry.clear() -- registry['version'] = _filters_version - if isinstance(message, Warning): - text = str(message) - category = message.__class__ -@@ -365,52 +368,59 @@ - text = message - message = category(message) - key = (text, category, lineno) -- # Quick test for common case -- if registry.get(key): -- return -- # Search the filters -- for item in filters: -- action, msg, cat, mod, ln = item -- if ((msg is None or msg.match(text)) and -- issubclass(category, cat) and -- (mod is None or mod.match(module)) and -- (ln == 0 or lineno == ln)): -- break -- else: -- action = defaultaction -- # Early exit actions -- if action == "ignore": -- return -+ with _lock: -+ if registry is None: -+ registry = {} -+ if registry.get('version', 0) != _filters_version: -+ registry.clear() -+ registry['version'] = _filters_version -+ # Quick test for common case -+ if registry.get(key): -+ return -+ # Search the filters -+ for item in filters: -+ action, msg, cat, mod, ln = item -+ if ((msg is None or msg.match(text)) and -+ issubclass(category, cat) and -+ (mod is None or mod.match(module)) and -+ (ln == 0 or lineno == ln)): -+ break -+ else: -+ action = defaultaction -+ # Early exit actions -+ if action == "ignore": -+ return -+ -+ if action == "error": -+ raise message -+ # Other actions -+ if action == "once": -+ registry[key] = 1 -+ oncekey = (text, category) -+ if onceregistry.get(oncekey): -+ return -+ onceregistry[oncekey] = 1 -+ elif action in {"always", "all"}: -+ pass -+ elif action == "module": -+ registry[key] = 1 -+ altkey = (text, category, 0) -+ if registry.get(altkey): -+ return -+ registry[altkey] = 1 -+ elif action == "default": -+ registry[key] = 1 -+ else: -+ # Unrecognized actions are errors -+ raise RuntimeError( -+ "Unrecognized action (%r) in warnings.filters:\n %s" % -+ (action, item)) - - # Prime the linecache for formatting, in case the - # "file" is actually in a zipfile or something. - import linecache - linecache.getlines(filename, module_globals) - -- if action == "error": -- raise message -- # Other actions -- if action == "once": -- registry[key] = 1 -- oncekey = (text, category) -- if onceregistry.get(oncekey): -- return -- onceregistry[oncekey] = 1 -- elif action in {"always", "all"}: -- pass -- elif action == "module": -- registry[key] = 1 -- altkey = (text, category, 0) -- if registry.get(altkey): -- return -- registry[altkey] = 1 -- elif action == "default": -- registry[key] = 1 -- else: -- # Unrecognized actions are errors -- raise RuntimeError( -- "Unrecognized action (%r) in warnings.filters:\n %s" % -- (action, item)) - # Print message and context - msg = WarningMessage(message, category, filename, lineno, source) - _showwarnmsg(msg) -@@ -463,9 +473,6 @@ - """Specify whether to record warnings and if an alternative module - should be used other than sys.modules['warnings']. - -- For compatibility with Python 3.0, please consider all arguments to be -- keyword-only. -- - """ - self._record = record - self._module = sys.modules['warnings'] if module is None else module -@@ -488,30 +495,32 @@ - if self._entered: - raise RuntimeError("Cannot enter %r twice" % self) - self._entered = True -- self._filters = self._module.filters -- self._module.filters = self._filters[:] -- self._module._filters_mutated() -- self._showwarning = self._module.showwarning -- self._showwarnmsg_impl = self._module._showwarnmsg_impl -+ with _lock: -+ self._filters = self._module.filters -+ self._module.filters = self._filters[:] -+ self._module._filters_mutated_lock_held() -+ self._showwarning = self._module.showwarning -+ self._showwarnmsg_impl = self._module._showwarnmsg_impl -+ if self._record: -+ log = [] -+ self._module._showwarnmsg_impl = log.append -+ # Reset showwarning() to the default implementation to make sure -+ # that _showwarnmsg() calls _showwarnmsg_impl() -+ self._module.showwarning = self._module._showwarning_orig -+ else: -+ log = None - if self._filter is not None: - simplefilter(*self._filter) -- if self._record: -- log = [] -- self._module._showwarnmsg_impl = log.append -- # Reset showwarning() to the default implementation to make sure -- # that _showwarnmsg() calls _showwarnmsg_impl() -- self._module.showwarning = self._module._showwarning_orig -- return log -- else: -- return None -+ return log - - def __exit__(self, *exc_info): - if not self._entered: - raise RuntimeError("Cannot exit %r without entering first" % self) -- self._module.filters = self._filters -- self._module._filters_mutated() -- self._module.showwarning = self._showwarning -- self._module._showwarnmsg_impl = self._showwarnmsg_impl -+ with _lock: -+ self._module.filters = self._filters -+ self._module._filters_mutated_lock_held() -+ self._module.showwarning = self._showwarning -+ self._module._showwarnmsg_impl = self._showwarnmsg_impl - - - class deprecated: -@@ -701,18 +710,36 @@ - # If either if the compiled regexs are None, match anything. - try: - from _warnings import (filters, _defaultaction, _onceregistry, -- warn, warn_explicit, _filters_mutated) -+ warn, warn_explicit, -+ _filters_mutated_lock_held, -+ _acquire_lock, _release_lock, -+ ) - defaultaction = _defaultaction - onceregistry = _onceregistry - _warnings_defaults = True -+ -+ class _Lock: -+ def __enter__(self): -+ _acquire_lock() -+ return self -+ -+ def __exit__(self, *args): -+ _release_lock() -+ -+ _lock = _Lock() -+ - except ImportError: - filters = [] - defaultaction = "default" - onceregistry = {} - -+ import _thread -+ -+ _lock = _thread.RLock() -+ - _filters_version = 1 - -- def _filters_mutated(): -+ def _filters_mutated_lock_held(): - global _filters_version - _filters_version += 1 - -diff --git a/Lib/xml/dom/xmlbuilder.py b/Lib/xml/dom/xmlbuilder.py -index 8a200263497..a8852625a2f 100644 ---- a/Lib/xml/dom/xmlbuilder.py -+++ b/Lib/xml/dom/xmlbuilder.py -@@ -189,7 +189,7 @@ - options.filter = self.filter - options.errorHandler = self.errorHandler - fp = input.byteStream -- if fp is None and options.systemId: -+ if fp is None and input.systemId: - import urllib.request - fp = urllib.request.urlopen(input.systemId) - return self._parse_bytestream(fp, options) -@@ -247,10 +247,12 @@ - - def _guess_media_encoding(self, source): - info = source.byteStream.info() -- if "Content-Type" in info: -- for param in info.getplist(): -- if param.startswith("charset="): -- return param.split("=", 1)[1].lower() -+ # import email.message -+ # assert isinstance(info, email.message.Message) -+ charset = info.get_param('charset') -+ if charset is not None: -+ return charset.lower() -+ return None - - - class DOMInputSource(object): -diff --git a/Lib/zipfile/__init__.py b/Lib/zipfile/__init__.py -index 6907ae6d5b7..b8b496ad947 100644 ---- a/Lib/zipfile/__init__.py -+++ b/Lib/zipfile/__init__.py -@@ -605,6 +605,28 @@ - - return zinfo - -+ def _for_archive(self, archive): -+ """Resolve suitable defaults from the archive. -+ -+ Resolve the date_time, compression attributes, and external attributes -+ to suitable defaults as used by :method:`ZipFile.writestr`. -+ -+ Return self. -+ """ -+ # gh-91279: Set the SOURCE_DATE_EPOCH to a specific timestamp -+ epoch = os.environ.get('SOURCE_DATE_EPOCH') -+ get_time = int(epoch) if epoch else time.time() -+ self.date_time = time.localtime(get_time)[:6] -+ -+ self.compress_type = archive.compression -+ self.compress_level = archive.compresslevel -+ if self.filename.endswith('/'): # pragma: no cover -+ self.external_attr = 0o40775 << 16 # drwxrwxr-x -+ self.external_attr |= 0x10 # MS-DOS directory flag -+ else: -+ self.external_attr = 0o600 << 16 # ?rw------- -+ return self -+ - def is_dir(self): - """Return True if this archive member is a directory.""" - if self.filename.endswith('/'): -@@ -819,7 +841,10 @@ - raise ValueError("Can't reposition in the ZIP file while " - "there is an open writing handle on it. " - "Close the writing handle before trying to read.") -- self._file.seek(offset, whence) -+ if whence == os.SEEK_CUR: -+ self._file.seek(self._pos + offset) -+ else: -+ self._file.seek(offset, whence) - self._pos = self._file.tell() - return self._pos - -@@ -1162,13 +1187,15 @@ - self._offset = buff_offset - read_offset = 0 - # Fast seek uncompressed unencrypted file -- elif self._compress_type == ZIP_STORED and self._decrypter is None and read_offset > 0: -+ elif self._compress_type == ZIP_STORED and self._decrypter is None and read_offset != 0: - # disable CRC checking after first seeking - it would be invalid - self._expected_crc = None - # seek actual file taking already buffered data into account - read_offset -= len(self._readbuffer) - self._offset - self._fileobj.seek(read_offset, os.SEEK_CUR) - self._left -= read_offset -+ self._compress_left -= read_offset -+ self._eof = self._left <= 0 - read_offset = 0 - # flush read buffer - self._readbuffer = b'' -@@ -1905,18 +1932,10 @@ - the name of the file in the archive.""" - if isinstance(data, str): - data = data.encode("utf-8") -- if not isinstance(zinfo_or_arcname, ZipInfo): -- zinfo = ZipInfo(filename=zinfo_or_arcname, -- date_time=time.localtime(time.time())[:6]) -- zinfo.compress_type = self.compression -- zinfo.compress_level = self.compresslevel -- if zinfo.filename.endswith('/'): -- zinfo.external_attr = 0o40775 << 16 # drwxrwxr-x -- zinfo.external_attr |= 0x10 # MS-DOS directory flag -- else: -- zinfo.external_attr = 0o600 << 16 # ?rw------- -- else: -+ if isinstance(zinfo_or_arcname, ZipInfo): - zinfo = zinfo_or_arcname -+ else: -+ zinfo = ZipInfo(zinfo_or_arcname)._for_archive(self) - - if not self.fp: - raise ValueError( -diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py -index f5f0ed44884..cb2484767e6 100755 ---- a/Mac/BuildScript/build-installer.py -+++ b/Mac/BuildScript/build-installer.py -@@ -325,32 +325,32 @@ - - result.extend([ - dict( -- name="NCurses 5.9", -- url="http://ftp.gnu.org/pub/gnu/ncurses/ncurses-5.9.tar.gz", -- checksum='8cb9c412e5f2d96bc6f459aa8c6282a1', -+ name="NCurses 6.5", -+ url="https://ftp.gnu.org/gnu/ncurses/ncurses-6.5.tar.gz", -+ checksum="136d91bc269a9a5785e5f9e980bc76ab57428f604ce3e5a5a90cebc767971cc6", - configure_pre=[ -+ "--datadir=/usr/share", -+ "--disable-lib-suffixes", -+ "--disable-db-install", -+ "--disable-mixed-case", -+ "--enable-overwrite", - "--enable-widec", -+ f"--libdir=/Library/Frameworks/Python.framework/Versions/{getVersion()}/lib", -+ "--sharedstatedir=/usr/com", -+ "--sysconfdir=/etc", -+ "--with-default-terminfo-dir=/usr/share/terminfo", -+ "--with-shared", -+ "--with-terminfo-dirs=/usr/share/terminfo", -+ "--without-ada", - "--without-cxx", - "--without-cxx-binding", -- "--without-ada", -- "--without-curses-h", -- "--enable-shared", -- "--with-shared", -+ "--without-cxx-shared", - "--without-debug", -+ "--without-manpages", - "--without-normal", -+ "--without-progs", - "--without-tests", -- "--without-manpages", -- "--datadir=/usr/share", -- "--sysconfdir=/etc", -- "--sharedstatedir=/usr/com", -- "--with-terminfo-dirs=/usr/share/terminfo", -- "--with-default-terminfo-dir=/usr/share/terminfo", -- "--libdir=/Library/Frameworks/Python.framework/Versions/%s/lib"%(getVersion(),), - ], -- patchscripts=[ -- ("ftp://ftp.invisible-island.net/ncurses//5.9/ncurses-5.9-20120616-patch.sh.bz2", -- "f54bf02a349f96a7c4f0d00922f3a0d4"), -- ], - useLDFlags=False, - install='make && make install DESTDIR=%s && cd %s/usr/local/lib && ln -fs ../../../Library/Frameworks/Python.framework/Versions/%s/lib/lib* .'%( - shellQuote(os.path.join(WORKDIR, 'libraries')), -diff --git a/Makefile.pre.in b/Makefile.pre.in -index 3e880f7800f..67acf0fc520 100644 ---- a/Makefile.pre.in -+++ b/Makefile.pre.in -@@ -488,6 +488,7 @@ - Python/qsbr.o \ - Python/bootstrap_hash.o \ - Python/specialize.o \ -+ Python/stackrefs.o \ - Python/structmember.o \ - Python/symtable.o \ - Python/sysmodule.o \ -diff --git a/Misc/ACKS b/Misc/ACKS -index 08693066682..2a68b69f161 100644 ---- a/Misc/ACKS -+++ b/Misc/ACKS -@@ -189,6 +189,7 @@ - Eric Blossom - Sergey Bobrov - Finn Bock -+VojtÄ›ch BoÄek - Paul Boddie - Matthew Boedicker - Robin Boerdijk -@@ -258,6 +259,7 @@ - Erik de Bueger - Jan-Hein Bührman - Marc Bürg -+Calvin Bui - Lars Buitinck - Artem Bulgakov - Dick Bulterman -@@ -574,6 +576,7 @@ - Artem Fokin - Arnaud Fontaine - Michael Foord -+Forest - Amaury Forgeot d'Arc - Doug Fort - Daniel Fortunov -@@ -1037,6 +1040,7 @@ - Kabir Kwatra - Ross Lagerwall - Cameron Laird -+Filipe Laíns - Loïc Lajeanne - Alexander Lakeev - David Lam -@@ -1128,6 +1132,7 @@ - Everett Lipman - Mirko Liss - Alexander Liu -+Hui Liu - Yuan Liu - Nick Lockwood - Stephanie Lockwood -@@ -1472,6 +1477,7 @@ - Martin Pool - Iustin Pop - Claudiu Popa -+Nick Pope - John Popplewell - Matheus Vieira Portela - Davin Potts -@@ -1919,6 +1925,7 @@ - Fraser Tweedale - Doobee R. Tzeck - Eren Türkay -+Stan Ulbrych - Lionel Ulmer - Adnan Umer - Utkarsh Upadhyay -@@ -1966,6 +1973,7 @@ - Michael Vogt - Radu Voicilas - Alex Volkov -+Illia Volochii - Ruben Vorderman - Guido Vranken - Martijn Vries -@@ -1985,6 +1993,7 @@ - Jiahua Wang - Ke Wang - Liang-Bo Wang -+Brian Ward - Greg Ward - Tom Wardill - Zachary Ware -diff --git a/Misc/SpecialBuilds.txt b/Misc/SpecialBuilds.txt -index 78201bfbd67..23fa36af78c 100644 ---- a/Misc/SpecialBuilds.txt -+++ b/Misc/SpecialBuilds.txt -@@ -78,22 +78,16 @@ - - This is what is generally meant by "a debug build" of Python. - --Py_DEBUG implies LLTRACE and Py_REF_DEBUG. In addition, C assert()s are enabled -+Py_DEBUG implies Py_REF_DEBUG. In addition, C assert()s are enabled - (via the C way: by not defining NDEBUG), and some routines do additional sanity - checks inside "#ifdef Py_DEBUG" blocks. - -- --LLTRACE --------- -- --Compile in support for Low Level TRACE-ing of the main interpreter loop. -- --When this preprocessor symbol is defined, before PyEval_EvalFrame executes a --frame's code it checks the frame's global namespace for a variable --"__lltrace__". If such a variable is found, mounds of information about what --the interpreter is doing are sprayed to stdout, such as every opcode and opcode --argument and values pushed onto and popped off the value stack. -- --Not useful very often, but very useful when needed. -- --Py_DEBUG implies LLTRACE. -+Also, compile in support for "lltrace" (Low Level TRACE-ing) of the main -+interpreter loop. Before _PyEval_EvalFrameDefault executes a frame's code, it -+checks the frame's global namespace for a variable "__lltrace__" (as well as for -+the environment variable PYTHON_LLTRACE"). If such a variable is found, mounds -+of information about what the interpreter is doing are sprayed to stdout, such -+as every opcode and opcode argument and values pushed onto and popped off the -+value stack. Higher integer values for the environment variable result in more -+and more detail being printed (the global __lltrace__ always enables the maximum -+output). Not useful very often, but *very* useful when needed. -diff --git a/Misc/platform_triplet.c b/Misc/platform_triplet.c -index ec0857a4a99..190670f271d 100644 ---- a/Misc/platform_triplet.c -+++ b/Misc/platform_triplet.c -@@ -254,9 +254,55 @@ - # else - PLATFORM_TRIPLET=arm64-iphonesimulator - # endif -+# elif defined(TARGET_OS_MACCATALYST) && TARGET_OS_MACCATALYST -+# if __x86_64__ -+PLATFORM_TRIPLET=x86_64-iphoneos-macabi -+# else -+PLATFORM_TRIPLET=arm64-iphoneos-macabi -+# endif - # else - PLATFORM_TRIPLET=arm64-iphoneos - # endif -+# elif defined(TARGET_OS_TV) && TARGET_OS_TV -+# if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR -+# if __x86_64__ -+PLATFORM_TRIPLET=x86_64-appletvsimulator -+# else -+PLATFORM_TRIPLET=arm64-appletvsimulator -+# endif -+# else -+PLATFORM_TRIPLET=arm64-appletvos -+# endif -+# elif defined(TARGET_OS_WATCH) && TARGET_OS_WATCH -+# if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR -+# if __x86_64__ -+PLATFORM_TRIPLET=x86_64-watchsimulator -+# else -+PLATFORM_TRIPLET=arm64-watchsimulator -+# endif -+# else -+PLATFORM_TRIPLET=arm64_32-watchos -+# endif -+# elif defined(TARGET_OS_TV) && TARGET_OS_TV -+# if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR -+# if __x86_64__ -+PLATFORM_TRIPLET=x86_64-appletvsimulator -+# else -+PLATFORM_TRIPLET=arm64-appletvsimulator -+# endif -+# else -+PLATFORM_TRIPLET=arm64-appletvos -+# endif -+# elif defined(TARGET_OS_WATCH) && TARGET_OS_WATCH -+# if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR -+# if __x86_64__ -+PLATFORM_TRIPLET=x86_64-watchsimulator -+# else -+PLATFORM_TRIPLET=arm64-watchsimulator -+# endif -+# else -+PLATFORM_TRIPLET=arm64_32-watchos -+# endif - // Older macOS SDKs do not define TARGET_OS_OSX - # elif !defined(TARGET_OS_OSX) || TARGET_OS_OSX - PLATFORM_TRIPLET=darwin -diff --git a/Misc/sbom.spdx.json b/Misc/sbom.spdx.json -index 739e005646b..316c266b7e4 100644 ---- a/Misc/sbom.spdx.json -+++ b/Misc/sbom.spdx.json -@@ -566,11 +566,11 @@ - "checksums": [ - { - "algorithm": "SHA1", -- "checksumValue": "2e08072c0c57dac02b67f3f71d77068c537ac02e" -+ "checksumValue": "118dc712780ea680affa8d9794470440eb87ff10" - }, - { - "algorithm": "SHA256", -- "checksumValue": "e69fd3e84f77873ecb414f5300761b686321d01f5710ccf2517765236b08fc25" -+ "checksumValue": "b017e7d5662a308c938cf4e4b919680c8f3e27f42975ca152b62fe65c5f7fb0c" - } - ], - "fileName": "Modules/_hacl/Lib_Memzero0.c" -@@ -622,11 +622,11 @@ - "checksums": [ - { - "algorithm": "SHA1", -- "checksumValue": "9881567f43deb32bae77a84b2d349858a24b6685" -+ "checksumValue": "9c5cac1582dcd6e0d0a4142e6e8b285b4cb7d9e6" - }, - { - "algorithm": "SHA256", -- "checksumValue": "3382156e32fcb376009177d3d2dc9712ff7c8c02afb97b3e16d98b41a2114f84" -+ "checksumValue": "b1e32138ac8c262e872f7da43ec80c1e54c08bcbdec4b7be17117aa25807f87e" - } - ], - "fileName": "Modules/_hacl/include/krml/internal/target.h" -@@ -1280,11 +1280,11 @@ - "checksums": [ - { - "algorithm": "SHA1", -- "checksumValue": "9dcb50e3f9c3245972731be5da0b28e7583198d9" -+ "checksumValue": "5d6fdd98730584f74f7b731da6e488fe234504b3" - }, - { - "algorithm": "SHA256", -- "checksumValue": "7cac49fef5e9d952ec9390bf81c54d83f1b5da32fdf76091c2f0770ed943b7fe" -+ "checksumValue": "d74f365463166891f62e1326d22b2d39d865776b7ea5e0df2aea5eede4d85b0f" - } - ], - "fileName": "Modules/_decimal/libmpdec/io.c" -diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml -index f9e51f0683c..9317be605f0 100644 ---- a/Misc/stable_abi.toml -+++ b/Misc/stable_abi.toml -@@ -1253,6 +1253,7 @@ - added = '3.2' - [function.PySequence_Fast] - added = '3.2' -+ abi_only = true - [function.PySequence_GetItem] - added = '3.2' - [function.PySequence_GetSlice] -@@ -2540,3 +2541,7 @@ - added = '3.14' - [function.PyType_Freeze] - added = '3.14' -+[function.Py_PACK_FULL_VERSION] -+ added = '3.14' -+[function.Py_PACK_VERSION] -+ added = '3.14' -diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in -index 52c0f883d38..6bb05a06a34 100644 ---- a/Modules/Setup.stdlib.in -+++ b/Modules/Setup.stdlib.in -@@ -162,8 +162,8 @@ - @MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c - @MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c - @MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c _testinternalcapi/set.c _testinternalcapi/test_critical_sections.c --@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/monitoring.c _testcapi/config.c --@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/codec.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/sys.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c -+@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/monitoring.c _testcapi/config.c _testcapi/import.c _testcapi/frame.c _testcapi/type.c _testcapi/function.c -+@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/codec.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/import.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/sys.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c _testlimitedcapi/version.c _testlimitedcapi/file.c - @MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c - @MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c - -diff --git a/Modules/_abc.c b/Modules/_abc.c -index 4f4b24b035d..d6a953b3360 100644 ---- a/Modules/_abc.c -+++ b/Modules/_abc.c -@@ -67,6 +67,8 @@ - uint64_t _abc_negative_cache_version; - } _abc_data; - -+#define _abc_data_CAST(op) ((_abc_data *)(op)) -+ - static inline uint64_t - get_cache_version(_abc_data *impl) - { -@@ -88,8 +90,9 @@ - } - - static int --abc_data_traverse(_abc_data *self, visitproc visit, void *arg) -+abc_data_traverse(PyObject *op, visitproc visit, void *arg) - { -+ _abc_data *self = _abc_data_CAST(op); - Py_VISIT(Py_TYPE(self)); - Py_VISIT(self->_abc_registry); - Py_VISIT(self->_abc_cache); -@@ -98,8 +101,9 @@ - } - - static int --abc_data_clear(_abc_data *self) -+abc_data_clear(PyObject *op) - { -+ _abc_data *self = _abc_data_CAST(op); - Py_CLEAR(self->_abc_registry); - Py_CLEAR(self->_abc_cache); - Py_CLEAR(self->_abc_negative_cache); -@@ -107,7 +111,7 @@ - } - - static void --abc_data_dealloc(_abc_data *self) -+abc_data_dealloc(PyObject *self) - { - PyObject_GC_UnTrack(self); - PyTypeObject *tp = Py_TYPE(self); -@@ -212,7 +216,7 @@ - } - - static PyMethodDef _destroy_def = { -- "_destroy", (PyCFunction) _destroy, METH_O -+ "_destroy", _destroy, METH_O - }; - - static int -@@ -964,7 +968,7 @@ - static void - _abcmodule_free(void *module) - { -- _abcmodule_clear((PyObject *)module); -+ (void)_abcmodule_clear((PyObject *)module); - } - - static PyModuleDef_Slot _abcmodule_slots[] = { -diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c -index f883125a2c7..5a4e65636e4 100644 ---- a/Modules/_asynciomodule.c -+++ b/Modules/_asynciomodule.c -@@ -6,9 +6,10 @@ - #include "pycore_critical_section.h" // Py_BEGIN_CRITICAL_SECTION_MUT() - #include "pycore_dict.h" // _PyDict_GetItem_KnownHash() - #include "pycore_freelist.h" // _Py_FREELIST_POP() -+#include "pycore_llist.h" // struct llist_node - #include "pycore_modsupport.h" // _PyArg_CheckPositional() - #include "pycore_moduleobject.h" // _PyModule_GetState() --#include "pycore_object.h" // _Py_SetImmortalUntracked() -+#include "pycore_object.h" // _PyObject_SetMaybeWeakref - #include "pycore_pyerrors.h" // _PyErr_ClearExcState() - #include "pycore_pylifecycle.h" // _Py_IsInterpreterFinalizing() - #include "pycore_pystate.h" // _PyThreadState_GET() -@@ -40,12 +41,17 @@ - PyObject *prefix##_source_tb; \ - PyObject *prefix##_cancel_msg; \ - PyObject *prefix##_cancelled_exc; \ -+ PyObject *prefix##_awaited_by; \ - fut_state prefix##_state; \ -- /* These bitfields need to be at the end of the struct -- so that these and bitfields from TaskObj are contiguous. -+ /* Used by profilers to make traversing the stack from an external \ -+ process faster. */ \ -+ char prefix##_is_task; \ -+ char prefix##_awaited_by_is_set; \ -+ /* These bitfields need to be at the end of the struct \ -+ so that these and bitfields from TaskObj are contiguous. \ - */ \ - unsigned prefix##_log_tb: 1; \ -- unsigned prefix##_blocking: 1; -+ unsigned prefix##_blocking: 1; \ - - typedef struct { - FutureObj_HEAD(fut) -@@ -60,8 +66,11 @@ - PyObject *task_coro; - PyObject *task_name; - PyObject *task_context; -- struct TaskObj *next; -- struct TaskObj *prev; -+ struct llist_node task_node; -+#ifdef Py_GIL_DISABLED -+ // thread id of the thread where this task was created -+ uintptr_t task_tid; -+#endif - } TaskObj; - - typedef struct { -@@ -70,26 +79,58 @@ - PyObject *sw_arg; - } TaskStepMethWrapper; - -- - #define Future_CheckExact(state, obj) Py_IS_TYPE(obj, state->FutureType) - #define Task_CheckExact(state, obj) Py_IS_TYPE(obj, state->TaskType) - --#define Future_Check(state, obj) PyObject_TypeCheck(obj, state->FutureType) --#define Task_Check(state, obj) PyObject_TypeCheck(obj, state->TaskType) -- --#ifdef Py_GIL_DISABLED --# define ASYNCIO_STATE_LOCK(state) Py_BEGIN_CRITICAL_SECTION_MUT(&state->mutex) --# define ASYNCIO_STATE_UNLOCK(state) Py_END_CRITICAL_SECTION() --#else --# define ASYNCIO_STATE_LOCK(state) ((void)state) --# define ASYNCIO_STATE_UNLOCK(state) ((void)state) --#endif -+#define Future_Check(state, obj) \ -+ (Future_CheckExact(state, obj) \ -+ || PyObject_TypeCheck(obj, state->FutureType)) -+ -+#define Task_Check(state, obj) \ -+ (Task_CheckExact(state, obj) \ -+ || PyObject_TypeCheck(obj, state->TaskType)) -+ -+// This macro is optimized to quickly return for native Future *or* Task -+// objects by inlining fast "exact" checks to be called first. -+#define TaskOrFuture_Check(state, obj) \ -+ (Task_CheckExact(state, obj) \ -+ || Future_CheckExact(state, obj) \ -+ || PyObject_TypeCheck(obj, state->FutureType) \ -+ || PyObject_TypeCheck(obj, state->TaskType)) -+ -+typedef struct _Py_AsyncioModuleDebugOffsets { -+ struct _asyncio_task_object { -+ uint64_t size; -+ uint64_t task_name; -+ uint64_t task_awaited_by; -+ uint64_t task_is_task; -+ uint64_t task_awaited_by_is_set; -+ uint64_t task_coro; -+ } asyncio_task_object; -+ struct _asyncio_thread_state { -+ uint64_t size; -+ uint64_t asyncio_running_loop; -+ uint64_t asyncio_running_task; -+ } asyncio_thread_state; -+} Py_AsyncioModuleDebugOffsets; -+ -+GENERATE_DEBUG_SECTION(AsyncioDebug, Py_AsyncioModuleDebugOffsets AsyncioDebug) -+ = {.asyncio_task_object = { -+ .size = sizeof(TaskObj), -+ .task_name = offsetof(TaskObj, task_name), -+ .task_awaited_by = offsetof(TaskObj, task_awaited_by), -+ .task_is_task = offsetof(TaskObj, task_is_task), -+ .task_awaited_by_is_set = offsetof(TaskObj, task_awaited_by_is_set), -+ .task_coro = offsetof(TaskObj, task_coro), -+ }, -+ .asyncio_thread_state = { -+ .size = sizeof(_PyThreadStateImpl), -+ .asyncio_running_loop = offsetof(_PyThreadStateImpl, asyncio_running_loop), -+ .asyncio_running_task = offsetof(_PyThreadStateImpl, asyncio_running_task), -+ }}; - - /* State of the _asyncio module */ - typedef struct { --#ifdef Py_GIL_DISABLED -- PyMutex mutex; --#endif - PyTypeObject *FutureIterType; - PyTypeObject *TaskStepMethWrapper_Type; - PyTypeObject *FutureType; -@@ -136,21 +177,6 @@ - /* Counter for autogenerated Task names */ - uint64_t task_name_counter; - -- /* Circular linked-list of all tasks which are instances of asyncio.Task or subclasses -- of it. Third party tasks implementations which don't inherit from -- asyncio.Task are tracked separately using the 'non_asyncio_tasks' WeakSet. -- `first` is used as a sentinel to mark the end of the linked-list. It avoids one -- branch in checking for empty list when adding a new task, the list is -- initialized with `head`, `head->next` and `head->prev` pointing to `first` -- to mark an empty list. -- -- */ -- -- struct { -- TaskObj first; -- TaskObj *head; -- } asyncio_tasks; -- - } asyncio_state; - - static inline asyncio_state * -@@ -196,6 +222,22 @@ - task_step_handle_result_impl(asyncio_state *state, TaskObj *task, PyObject *result); - - -+static void -+clear_task_coro(TaskObj *task) -+{ -+ Py_CLEAR(task->task_coro); -+} -+ -+ -+static void -+set_task_coro(TaskObj *task, PyObject *coro) -+{ -+ assert(coro != NULL); -+ Py_INCREF(coro); -+ Py_XSETREF(task->task_coro, coro); -+} -+ -+ - static int - _is_coroutine(asyncio_state *state, PyObject *coro) - { -@@ -375,6 +417,8 @@ - static int - future_schedule_callbacks(asyncio_state *state, FutureObj *fut) - { -+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(fut); -+ - if (fut->fut_callback0 != NULL) { - /* There's a 1st callback */ - -@@ -446,10 +490,13 @@ - Py_CLEAR(fut->fut_source_tb); - Py_CLEAR(fut->fut_cancel_msg); - Py_CLEAR(fut->fut_cancelled_exc); -+ Py_CLEAR(fut->fut_awaited_by); - - fut->fut_state = STATE_PENDING; - fut->fut_log_tb = 0; - fut->fut_blocking = 0; -+ fut->fut_awaited_by_is_set = 0; -+ fut->fut_is_task = 0; - - if (loop == Py_None) { - asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut); -@@ -489,9 +536,86 @@ - return 0; - } - -+static int -+future_awaited_by_add(asyncio_state *state, FutureObj *fut, PyObject *thing) -+{ -+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(fut); -+ // We only want to support native asyncio Futures. -+ // For further insight see the comment in the Python -+ // implementation of "future_add_to_awaited_by()". -+ assert(TaskOrFuture_Check(state, fut)); -+ assert(TaskOrFuture_Check(state, thing)); -+ -+ /* Most futures/task are only awaited by one entity, so we want -+ to avoid always creating a set for `fut_awaited_by`. -+ */ -+ if (fut->fut_awaited_by == NULL) { -+ assert(!fut->fut_awaited_by_is_set); -+ Py_INCREF(thing); -+ fut->fut_awaited_by = thing; -+ return 0; -+ } -+ -+ if (fut->fut_awaited_by_is_set) { -+ assert(PySet_CheckExact(fut->fut_awaited_by)); -+ return PySet_Add(fut->fut_awaited_by, thing); -+ } -+ -+ PyObject *set = PySet_New(NULL); -+ if (set == NULL) { -+ return -1; -+ } -+ if (PySet_Add(set, thing)) { -+ Py_DECREF(set); -+ return -1; -+ } -+ if (PySet_Add(set, fut->fut_awaited_by)) { -+ Py_DECREF(set); -+ return -1; -+ } -+ Py_SETREF(fut->fut_awaited_by, set); -+ fut->fut_awaited_by_is_set = 1; -+ return 0; -+} -+ -+static int -+future_awaited_by_discard(asyncio_state *state, FutureObj *fut, PyObject *thing) -+{ -+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(fut); -+ // We only want to support native asyncio Futures. -+ // For further insight see the comment in the Python -+ // implementation of "future_add_to_awaited_by()". -+ assert(TaskOrFuture_Check(state, fut)); -+ assert(TaskOrFuture_Check(state, thing)); -+ -+ /* Following the semantics of 'set.discard()' here in not -+ raising an error if `thing` isn't in the `awaited_by` "set". -+ */ -+ if (fut->fut_awaited_by == NULL) { -+ return 0; -+ } -+ if (fut->fut_awaited_by == thing) { -+ Py_CLEAR(fut->fut_awaited_by); -+ return 0; -+ } -+ if (fut->fut_awaited_by_is_set) { -+ assert(PySet_CheckExact(fut->fut_awaited_by)); -+ int err = PySet_Discard(fut->fut_awaited_by, thing); -+ if (err < 0) { -+ return -1; -+ } else { -+ return 0; -+ } -+ } -+ return 0; -+} -+ -+ - static PyObject * - future_set_result(asyncio_state *state, FutureObj *fut, PyObject *res) - { -+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(fut); -+ - if (future_ensure_alive(fut)) { - return NULL; - } -@@ -514,6 +638,8 @@ - static PyObject * - future_set_exception(asyncio_state *state, FutureObj *fut, PyObject *exc) - { -+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(fut); -+ - PyObject *exc_val = NULL; - - if (fut->fut_state != STATE_PENDING) { -@@ -580,6 +706,8 @@ - static PyObject * - create_cancelled_error(asyncio_state *state, FutureObj *fut) - { -+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(fut); -+ - PyObject *exc; - if (fut->fut_cancelled_exc != NULL) { - /* transfer ownership */ -@@ -599,6 +727,8 @@ - static void - future_set_cancelled_error(asyncio_state *state, FutureObj *fut) - { -+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(fut); -+ - PyObject *exc = create_cancelled_error(state, fut); - if (exc == NULL) { - return; -@@ -610,6 +740,8 @@ - static int - future_get_result(asyncio_state *state, FutureObj *fut, PyObject **result) - { -+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(fut); -+ - if (fut->fut_state == STATE_CANCELLED) { - future_set_cancelled_error(state, fut); - return -1; -@@ -643,6 +775,8 @@ - future_add_done_callback(asyncio_state *state, FutureObj *fut, PyObject *arg, - PyObject *ctx) - { -+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(fut); -+ - if (!future_is_alive(fut)) { - PyErr_SetString(PyExc_RuntimeError, "uninitialized Future object"); - return NULL; -@@ -717,6 +851,8 @@ - static PyObject * - future_cancel(asyncio_state *state, FutureObj *fut, PyObject *msg) - { -+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(fut); -+ - fut->fut_log_tb = 0; - - if (fut->fut_state != STATE_PENDING) { -@@ -775,6 +911,8 @@ - Py_CLEAR(fut->fut_source_tb); - Py_CLEAR(fut->fut_cancel_msg); - Py_CLEAR(fut->fut_cancelled_exc); -+ Py_CLEAR(fut->fut_awaited_by); -+ fut->fut_awaited_by_is_set = 0; - PyObject_ClearManagedDict((PyObject *)fut); - return 0; - } -@@ -793,11 +931,13 @@ - Py_VISIT(fut->fut_source_tb); - Py_VISIT(fut->fut_cancel_msg); - Py_VISIT(fut->fut_cancelled_exc); -+ Py_VISIT(fut->fut_awaited_by); - PyObject_VisitManagedDict((PyObject *)fut, visit, arg); - return 0; - } - - /*[clinic input] -+@critical_section - _asyncio.Future.result - - Return the result this future represents. -@@ -809,7 +949,7 @@ - - static PyObject * - _asyncio_Future_result_impl(FutureObj *self) --/*[clinic end generated code: output=f35f940936a4b1e5 input=49ecf9cf5ec50dc5]*/ -+/*[clinic end generated code: output=f35f940936a4b1e5 input=61d89f48e4c8b670]*/ - { - asyncio_state *state = get_asyncio_state_by_def((PyObject *)self); - PyObject *result; -@@ -838,6 +978,7 @@ - } - - /*[clinic input] -+@critical_section - _asyncio.Future.exception - - cls: defining_class -@@ -853,7 +994,7 @@ - - static PyObject * - _asyncio_Future_exception_impl(FutureObj *self, PyTypeObject *cls) --/*[clinic end generated code: output=ce75576b187c905b input=3faf15c22acdb60d]*/ -+/*[clinic end generated code: output=ce75576b187c905b input=647d1fd1fc403301]*/ - { - if (!future_is_alive(self)) { - asyncio_state *state = get_asyncio_state_by_cls(cls); -@@ -884,6 +1025,7 @@ - } - - /*[clinic input] -+@critical_section - _asyncio.Future.set_result - - cls: defining_class -@@ -899,7 +1041,7 @@ - static PyObject * - _asyncio_Future_set_result_impl(FutureObj *self, PyTypeObject *cls, - PyObject *result) --/*[clinic end generated code: output=99afbbe78f99c32d input=d5a41c1e353acc2e]*/ -+/*[clinic end generated code: output=99afbbe78f99c32d input=4069306f03a3b6ee]*/ - { - asyncio_state *state = get_asyncio_state_by_cls(cls); - ENSURE_FUTURE_ALIVE(state, self) -@@ -907,6 +1049,7 @@ - } - - /*[clinic input] -+@critical_section - _asyncio.Future.set_exception - - cls: defining_class -@@ -922,7 +1065,7 @@ - static PyObject * - _asyncio_Future_set_exception_impl(FutureObj *self, PyTypeObject *cls, - PyObject *exception) --/*[clinic end generated code: output=0a5e8b5a52f058d6 input=a245cd49d3df939b]*/ -+/*[clinic end generated code: output=0a5e8b5a52f058d6 input=b6eab43a389bc966]*/ - { - asyncio_state *state = get_asyncio_state_by_cls(cls); - ENSURE_FUTURE_ALIVE(state, self) -@@ -930,6 +1073,7 @@ - } - - /*[clinic input] -+@critical_section - _asyncio.Future.add_done_callback - - cls: defining_class -@@ -948,7 +1092,7 @@ - static PyObject * - _asyncio_Future_add_done_callback_impl(FutureObj *self, PyTypeObject *cls, - PyObject *fn, PyObject *context) --/*[clinic end generated code: output=922e9a4cbd601167 input=599261c521458cc2]*/ -+/*[clinic end generated code: output=922e9a4cbd601167 input=37d97f941beb7b3e]*/ - { - asyncio_state *state = get_asyncio_state_by_cls(cls); - if (context == NULL) { -@@ -964,6 +1108,7 @@ - } - - /*[clinic input] -+@critical_section - _asyncio.Future.remove_done_callback - - cls: defining_class -@@ -978,7 +1123,7 @@ - static PyObject * - _asyncio_Future_remove_done_callback_impl(FutureObj *self, PyTypeObject *cls, - PyObject *fn) --/*[clinic end generated code: output=2da35ccabfe41b98 input=c7518709b86fc747]*/ -+/*[clinic end generated code: output=2da35ccabfe41b98 input=3afbc9f6a673091b]*/ - { - PyObject *newlist; - Py_ssize_t len, i, j=0; -@@ -1087,6 +1232,7 @@ - } - - /*[clinic input] -+@critical_section - _asyncio.Future.cancel - - cls: defining_class -@@ -1103,7 +1249,7 @@ - static PyObject * - _asyncio_Future_cancel_impl(FutureObj *self, PyTypeObject *cls, - PyObject *msg) --/*[clinic end generated code: output=074956f35904b034 input=bba8f8b786941a94]*/ -+/*[clinic end generated code: output=074956f35904b034 input=44ab4003da839970]*/ - { - asyncio_state *state = get_asyncio_state_by_cls(cls); - ENSURE_FUTURE_ALIVE(state, self) -@@ -1111,6 +1257,7 @@ - } - - /*[clinic input] -+@critical_section - _asyncio.Future.cancelled - - Return True if the future was cancelled. -@@ -1118,7 +1265,7 @@ - - static PyObject * - _asyncio_Future_cancelled_impl(FutureObj *self) --/*[clinic end generated code: output=145197ced586357d input=943ab8b7b7b17e45]*/ -+/*[clinic end generated code: output=145197ced586357d input=9b8644819a675416]*/ - { - if (future_is_alive(self) && self->fut_state == STATE_CANCELLED) { - Py_RETURN_TRUE; -@@ -1129,6 +1276,7 @@ - } - - /*[clinic input] -+@critical_section - _asyncio.Future.done - - Return True if the future is done. -@@ -1139,7 +1287,7 @@ - - static PyObject * - _asyncio_Future_done_impl(FutureObj *self) --/*[clinic end generated code: output=244c5ac351145096 input=28d7b23fdb65d2ac]*/ -+/*[clinic end generated code: output=244c5ac351145096 input=7204d3cc63bef7f3]*/ - { - if (!future_is_alive(self) || self->fut_state == STATE_PENDING) { - Py_RETURN_FALSE; -@@ -1150,6 +1298,7 @@ - } - - /*[clinic input] -+@critical_section - _asyncio.Future.get_loop - - cls: defining_class -@@ -1160,17 +1309,56 @@ - - static PyObject * - _asyncio_Future_get_loop_impl(FutureObj *self, PyTypeObject *cls) --/*[clinic end generated code: output=f50ea6c374d9ee97 input=163c2c498b45a1f0]*/ -+/*[clinic end generated code: output=f50ea6c374d9ee97 input=f3ce629bfd9f45c1]*/ - { - asyncio_state *state = get_asyncio_state_by_cls(cls); - ENSURE_FUTURE_ALIVE(state, self) - return Py_NewRef(self->fut_loop); - } - -+/*[clinic input] -+@critical_section -+@getter -+_asyncio.Future._asyncio_awaited_by -+[clinic start generated code]*/ -+ -+static PyObject * -+_asyncio_Future__asyncio_awaited_by_get_impl(FutureObj *self) -+/*[clinic end generated code: output=932af76d385d2e2a input=64c1783df2d44d2b]*/ -+{ -+ /* Implementation of a Python getter. */ -+ if (self->fut_awaited_by == NULL) { -+ Py_RETURN_NONE; -+ } -+ if (self->fut_awaited_by_is_set) { -+ /* Already a set, just wrap it into a frozen set and return. */ -+ assert(PySet_CheckExact(self->fut_awaited_by)); -+ return PyFrozenSet_New(self->fut_awaited_by); -+ } -+ -+ PyObject *set = PyFrozenSet_New(NULL); -+ if (set == NULL) { -+ return NULL; -+ } -+ if (PySet_Add(set, self->fut_awaited_by)) { -+ Py_DECREF(set); -+ return NULL; -+ } -+ return set; -+} -+ -+ -+/*[clinic input] -+@critical_section -+@getter -+_asyncio.Future._asyncio_future_blocking -+[clinic start generated code]*/ -+ - static PyObject * --FutureObj_get_blocking(FutureObj *fut, void *Py_UNUSED(ignored)) -+_asyncio_Future__asyncio_future_blocking_get_impl(FutureObj *self) -+/*[clinic end generated code: output=a558a2c51e38823b input=58da92efc03b617d]*/ - { -- if (future_is_alive(fut) && fut->fut_blocking) { -+ if (future_is_alive(self) && self->fut_blocking) { - Py_RETURN_TRUE; - } - else { -@@ -1178,31 +1366,47 @@ - } - } - -+/*[clinic input] -+@critical_section -+@setter -+_asyncio.Future._asyncio_future_blocking -+[clinic start generated code]*/ -+ - static int --FutureObj_set_blocking(FutureObj *fut, PyObject *val, void *Py_UNUSED(ignored)) -+_asyncio_Future__asyncio_future_blocking_set_impl(FutureObj *self, -+ PyObject *value) -+/*[clinic end generated code: output=0686d1cb024a7453 input=3fd4a5f95df788b7]*/ -+ - { -- if (future_ensure_alive(fut)) { -+ if (future_ensure_alive(self)) { - return -1; - } -- if (val == NULL) { -+ if (value == NULL) { - PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); - return -1; - } - -- int is_true = PyObject_IsTrue(val); -+ int is_true = PyObject_IsTrue(value); - if (is_true < 0) { - return -1; - } -- fut->fut_blocking = is_true; -+ self->fut_blocking = is_true; - return 0; - } - -+/*[clinic input] -+@critical_section -+@getter -+_asyncio.Future._log_traceback -+[clinic start generated code]*/ -+ - static PyObject * --FutureObj_get_log_traceback(FutureObj *fut, void *Py_UNUSED(ignored)) -+_asyncio_Future__log_traceback_get_impl(FutureObj *self) -+/*[clinic end generated code: output=2724433b238593c7 input=91e5144ea4117d8e]*/ - { -- asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut); -- ENSURE_FUTURE_ALIVE(state, fut) -- if (fut->fut_log_tb) { -+ asyncio_state *state = get_asyncio_state_by_def((PyObject *)self); -+ ENSURE_FUTURE_ALIVE(state, self) -+ if (self->fut_log_tb) { - Py_RETURN_TRUE; - } - else { -@@ -1210,14 +1414,21 @@ - } - } - -+/*[clinic input] -+@critical_section -+@setter -+_asyncio.Future._log_traceback -+[clinic start generated code]*/ -+ - static int --FutureObj_set_log_traceback(FutureObj *fut, PyObject *val, void *Py_UNUSED(ignored)) -+_asyncio_Future__log_traceback_set_impl(FutureObj *self, PyObject *value) -+/*[clinic end generated code: output=9ce8e19504f42f54 input=30ac8217754b08c2]*/ - { -- if (val == NULL) { -+ if (value == NULL) { - PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); - return -1; - } -- int is_true = PyObject_IsTrue(val); -+ int is_true = PyObject_IsTrue(value); - if (is_true < 0) { - return -1; - } -@@ -1226,31 +1437,44 @@ - "_log_traceback can only be set to False"); - return -1; - } -- fut->fut_log_tb = is_true; -+ self->fut_log_tb = is_true; - return 0; - } -+/*[clinic input] -+@critical_section -+@getter -+_asyncio.Future._loop -+[clinic start generated code]*/ - - static PyObject * --FutureObj_get_loop(FutureObj *fut, void *Py_UNUSED(ignored)) -+_asyncio_Future__loop_get_impl(FutureObj *self) -+/*[clinic end generated code: output=5ba31563eecfeedf input=0337130bc5781670]*/ - { -- if (!future_is_alive(fut)) { -+ if (!future_is_alive(self)) { - Py_RETURN_NONE; - } -- return Py_NewRef(fut->fut_loop); -+ return Py_NewRef(self->fut_loop); - } - -+/*[clinic input] -+@critical_section -+@getter -+_asyncio.Future._callbacks -+[clinic start generated code]*/ -+ - static PyObject * --FutureObj_get_callbacks(FutureObj *fut, void *Py_UNUSED(ignored)) -+_asyncio_Future__callbacks_get_impl(FutureObj *self) -+/*[clinic end generated code: output=b40d360505fcc583 input=7a466649530c01bb]*/ - { -- asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut); -- ENSURE_FUTURE_ALIVE(state, fut) -+ asyncio_state *state = get_asyncio_state_by_def((PyObject *)self); -+ ENSURE_FUTURE_ALIVE(state, self) - - Py_ssize_t len = 0; -- if (fut->fut_callback0 != NULL) { -+ if (self->fut_callback0 != NULL) { - len++; - } -- if (fut->fut_callbacks != NULL) { -- len += PyList_GET_SIZE(fut->fut_callbacks); -+ if (self->fut_callbacks != NULL) { -+ len += PyList_GET_SIZE(self->fut_callbacks); - } - - if (len == 0) { -@@ -1263,22 +1487,22 @@ - } - - Py_ssize_t i = 0; -- if (fut->fut_callback0 != NULL) { -+ if (self->fut_callback0 != NULL) { - PyObject *tup0 = PyTuple_New(2); - if (tup0 == NULL) { - Py_DECREF(callbacks); - return NULL; - } -- PyTuple_SET_ITEM(tup0, 0, Py_NewRef(fut->fut_callback0)); -- assert(fut->fut_context0 != NULL); -- PyTuple_SET_ITEM(tup0, 1, Py_NewRef(fut->fut_context0)); -+ PyTuple_SET_ITEM(tup0, 0, Py_NewRef(self->fut_callback0)); -+ assert(self->fut_context0 != NULL); -+ PyTuple_SET_ITEM(tup0, 1, Py_NewRef(self->fut_context0)); - PyList_SET_ITEM(callbacks, i, tup0); - i++; - } - -- if (fut->fut_callbacks != NULL) { -- for (Py_ssize_t j = 0; j < PyList_GET_SIZE(fut->fut_callbacks); j++) { -- PyObject *cb = PyList_GET_ITEM(fut->fut_callbacks, j); -+ if (self->fut_callbacks != NULL) { -+ for (Py_ssize_t j = 0; j < PyList_GET_SIZE(self->fut_callbacks); j++) { -+ PyObject *cb = PyList_GET_ITEM(self->fut_callbacks, j); - Py_INCREF(cb); - PyList_SET_ITEM(callbacks, i, cb); - i++; -@@ -1288,68 +1512,110 @@ - return callbacks; - } - -+/*[clinic input] -+@critical_section -+@getter -+_asyncio.Future._result -+[clinic start generated code]*/ -+ - static PyObject * --FutureObj_get_result(FutureObj *fut, void *Py_UNUSED(ignored)) -+_asyncio_Future__result_get_impl(FutureObj *self) -+/*[clinic end generated code: output=6877e8ce97333873 input=624f8e28e67f2636]*/ -+ - { -- asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut); -- ENSURE_FUTURE_ALIVE(state, fut) -- if (fut->fut_result == NULL) { -+ asyncio_state *state = get_asyncio_state_by_def((PyObject *)self); -+ ENSURE_FUTURE_ALIVE(state, self) -+ if (self->fut_result == NULL) { - Py_RETURN_NONE; - } -- return Py_NewRef(fut->fut_result); -+ return Py_NewRef(self->fut_result); - } - -+/*[clinic input] -+@critical_section -+@getter -+_asyncio.Future._exception -+[clinic start generated code]*/ -+ - static PyObject * --FutureObj_get_exception(FutureObj *fut, void *Py_UNUSED(ignored)) -+_asyncio_Future__exception_get_impl(FutureObj *self) -+/*[clinic end generated code: output=32f2c93b9e021a9b input=1828a1fcac929710]*/ - { -- asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut); -- ENSURE_FUTURE_ALIVE(state, fut) -- if (fut->fut_exception == NULL) { -+ asyncio_state *state = get_asyncio_state_by_def((PyObject *)self); -+ ENSURE_FUTURE_ALIVE(state, self) -+ if (self->fut_exception == NULL) { - Py_RETURN_NONE; - } -- return Py_NewRef(fut->fut_exception); -+ return Py_NewRef(self->fut_exception); - } - -+/*[clinic input] -+@critical_section -+@getter -+_asyncio.Future._source_traceback -+[clinic start generated code]*/ -+ - static PyObject * --FutureObj_get_source_traceback(FutureObj *fut, void *Py_UNUSED(ignored)) -+_asyncio_Future__source_traceback_get_impl(FutureObj *self) -+/*[clinic end generated code: output=d4f12b09af22f61b input=3c831fbde5da90d0]*/ - { -- if (!future_is_alive(fut) || fut->fut_source_tb == NULL) { -+ if (!future_is_alive(self) || self->fut_source_tb == NULL) { - Py_RETURN_NONE; - } -- return Py_NewRef(fut->fut_source_tb); -+ return Py_NewRef(self->fut_source_tb); - } - -+/*[clinic input] -+@critical_section -+@getter -+_asyncio.Future._cancel_message -+[clinic start generated code]*/ -+ - static PyObject * --FutureObj_get_cancel_message(FutureObj *fut, void *Py_UNUSED(ignored)) -+_asyncio_Future__cancel_message_get_impl(FutureObj *self) -+/*[clinic end generated code: output=52ef6444f92cedac input=54c12c67082e4eea]*/ - { -- if (fut->fut_cancel_msg == NULL) { -+ if (self->fut_cancel_msg == NULL) { - Py_RETURN_NONE; - } -- return Py_NewRef(fut->fut_cancel_msg); -+ return Py_NewRef(self->fut_cancel_msg); - } - -+/*[clinic input] -+@critical_section -+@setter -+_asyncio.Future._cancel_message -+[clinic start generated code]*/ -+ - static int --FutureObj_set_cancel_message(FutureObj *fut, PyObject *msg, -- void *Py_UNUSED(ignored)) -+_asyncio_Future__cancel_message_set_impl(FutureObj *self, PyObject *value) -+/*[clinic end generated code: output=0854b2f77bff2209 input=f461d17f2d891fad]*/ - { -- if (msg == NULL) { -+ if (value == NULL) { - PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); - return -1; - } -- Py_INCREF(msg); -- Py_XSETREF(fut->fut_cancel_msg, msg); -+ Py_INCREF(value); -+ Py_XSETREF(self->fut_cancel_msg, value); - return 0; - } - -+/*[clinic input] -+@critical_section -+@getter -+_asyncio.Future._state -+[clinic start generated code]*/ -+ - static PyObject * --FutureObj_get_state(FutureObj *fut, void *Py_UNUSED(ignored)) -+_asyncio_Future__state_get_impl(FutureObj *self) -+/*[clinic end generated code: output=622f560a3fa69c63 input=7c5ad023a93423ff]*/ - { -- asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut); -+ asyncio_state *state = get_asyncio_state_by_def((PyObject *)self); - PyObject *ret = NULL; - -- ENSURE_FUTURE_ALIVE(state, fut) -+ ENSURE_FUTURE_ALIVE(state, self) - -- switch (fut->fut_state) { -+ switch (self->fut_state) { - case STATE_PENDING: - ret = &_Py_ID(PENDING); - break; -@@ -1375,6 +1641,7 @@ - } - - /*[clinic input] -+@critical_section - _asyncio.Future._make_cancelled_error - - Create the CancelledError to raise if the Future is cancelled. -@@ -1385,7 +1652,7 @@ - - static PyObject * - _asyncio_Future__make_cancelled_error_impl(FutureObj *self) --/*[clinic end generated code: output=a5df276f6c1213de input=ac6effe4ba795ecc]*/ -+/*[clinic end generated code: output=a5df276f6c1213de input=ccb90df8c3c18bcd]*/ - { - asyncio_state *state = get_asyncio_state_by_def((PyObject *)self); - return create_cancelled_error(state, self); -@@ -1434,7 +1701,8 @@ - if (func != NULL) { - PyObject *res = PyObject_CallOneArg(func, context); - if (res == NULL) { -- PyErr_WriteUnraisable(func); -+ PyErr_FormatUnraisable("Exception ignored while calling asyncio " -+ "function %R", func); - } - else { - Py_DECREF(res); -@@ -1466,23 +1734,17 @@ - {NULL, NULL} /* Sentinel */ - }; - --#define FUTURE_COMMON_GETSETLIST \ -- {"_state", (getter)FutureObj_get_state, NULL, NULL}, \ -- {"_asyncio_future_blocking", (getter)FutureObj_get_blocking, \ -- (setter)FutureObj_set_blocking, NULL}, \ -- {"_loop", (getter)FutureObj_get_loop, NULL, NULL}, \ -- {"_callbacks", (getter)FutureObj_get_callbacks, NULL, NULL}, \ -- {"_result", (getter)FutureObj_get_result, NULL, NULL}, \ -- {"_exception", (getter)FutureObj_get_exception, NULL, NULL}, \ -- {"_log_traceback", (getter)FutureObj_get_log_traceback, \ -- (setter)FutureObj_set_log_traceback, NULL}, \ -- {"_source_traceback", (getter)FutureObj_get_source_traceback, \ -- NULL, NULL}, \ -- {"_cancel_message", (getter)FutureObj_get_cancel_message, \ -- (setter)FutureObj_set_cancel_message, NULL}, -- - static PyGetSetDef FutureType_getsetlist[] = { -- FUTURE_COMMON_GETSETLIST -+ _ASYNCIO_FUTURE__STATE_GETSETDEF -+ _ASYNCIO_FUTURE__ASYNCIO_FUTURE_BLOCKING_GETSETDEF -+ _ASYNCIO_FUTURE__LOOP_GETSETDEF -+ _ASYNCIO_FUTURE__CALLBACKS_GETSETDEF -+ _ASYNCIO_FUTURE__RESULT_GETSETDEF -+ _ASYNCIO_FUTURE__EXCEPTION_GETSETDEF -+ _ASYNCIO_FUTURE__LOG_TRACEBACK_GETSETDEF -+ _ASYNCIO_FUTURE__SOURCE_TRACEBACK_GETSETDEF -+ _ASYNCIO_FUTURE__CANCEL_MESSAGE_GETSETDEF -+ _ASYNCIO_FUTURE__ASYNCIO_AWAITED_BY_GETSETDEF - {NULL} /* Sentinel */ - }; - -@@ -1561,19 +1823,13 @@ - } - - static PySendResult --FutureIter_am_send(futureiterobject *it, -- PyObject *Py_UNUSED(arg), -- PyObject **result) -+FutureIter_am_send_lock_held(futureiterobject *it, PyObject **result) - { -- /* arg is unused, see the comment on FutureIter_send for clarification */ -- - PyObject *res; - FutureObj *fut = it->future; -+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(fut); - - *result = NULL; -- if (fut == NULL) { -- return PYGEN_ERROR; -- } - - if (fut->fut_state == STATE_PENDING) { - if (!fut->fut_blocking) { -@@ -1586,18 +1842,29 @@ - return PYGEN_ERROR; - } - -- it->future = NULL; - res = _asyncio_Future_result_impl(fut); - if (res != NULL) { -- Py_DECREF(fut); - *result = res; - return PYGEN_RETURN; - } - -- Py_DECREF(fut); - return PYGEN_ERROR; - } - -+static PySendResult -+FutureIter_am_send(futureiterobject *it, -+ PyObject *Py_UNUSED(arg), -+ PyObject **result) -+{ -+ /* arg is unused, see the comment on FutureIter_send for clarification */ -+ PySendResult res; -+ Py_BEGIN_CRITICAL_SECTION(it->future); -+ res = FutureIter_am_send_lock_held(it, result); -+ Py_END_CRITICAL_SECTION(); -+ return res; -+} -+ -+ - static PyObject * - FutureIter_iternext(futureiterobject *it) - { -@@ -1784,6 +2051,8 @@ - static PyObject * task_wakeup(TaskObj *, PyObject *); - static PyObject * task_step(asyncio_state *, TaskObj *, PyObject *); - static int task_eager_start(asyncio_state *state, TaskObj *task); -+static inline void clear_ts_asyncio_running_task(PyObject *loop); -+static inline void set_ts_asyncio_running_task(PyObject *loop, PyObject *task); - - /* ----- Task._step wrapper */ - -@@ -1818,7 +2087,11 @@ - return NULL; - } - asyncio_state *state = get_asyncio_state_by_def((PyObject *)o); -- return task_step(state, o->sw_task, o->sw_arg); -+ PyObject *res; -+ Py_BEGIN_CRITICAL_SECTION(o->sw_task); -+ res = task_step(state, o->sw_task, o->sw_arg); -+ Py_END_CRITICAL_SECTION(); -+ return res; - } - - static int -@@ -1894,23 +2167,15 @@ - static void - register_task(asyncio_state *state, TaskObj *task) - { -- ASYNCIO_STATE_LOCK(state); - assert(Task_Check(state, task)); -- assert(task != &state->asyncio_tasks.first); -- if (task->next != NULL) { -+ if (task->task_node.next != NULL) { - // already registered -- goto exit; -+ assert(task->task_node.prev != NULL); -+ return; - } -- assert(task->prev == NULL); -- assert(state->asyncio_tasks.head != NULL); -- -- task->next = state->asyncio_tasks.head; -- task->prev = state->asyncio_tasks.head->prev; -- state->asyncio_tasks.head->prev->next = task; -- state->asyncio_tasks.head->prev = task; -- --exit: -- ASYNCIO_STATE_UNLOCK(state); -+ _PyThreadStateImpl *tstate = (_PyThreadStateImpl *) _PyThreadState_GET(); -+ struct llist_node *head = &tstate->asyncio_tasks_head; -+ llist_insert_tail(head, &task->task_node); - } - - static int -@@ -1919,25 +2184,38 @@ - return PySet_Add(state->eager_tasks, task); - } - -+static inline void -+unregister_task_safe(TaskObj *task) -+{ -+ if (task->task_node.next == NULL) { -+ // not registered -+ assert(task->task_node.prev == NULL); -+ return; -+ } -+ llist_remove(&task->task_node); -+} -+ - static void - unregister_task(asyncio_state *state, TaskObj *task) - { -- ASYNCIO_STATE_LOCK(state); - assert(Task_Check(state, task)); -- assert(task != &state->asyncio_tasks.first); -- if (task->next == NULL) { -- // not registered -- assert(task->prev == NULL); -- assert(state->asyncio_tasks.head != task); -- goto exit; -- } -- task->next->prev = task->prev; -- task->prev->next = task->next; -- task->next = NULL; -- task->prev = NULL; -- assert(state->asyncio_tasks.head != task); --exit: -- ASYNCIO_STATE_UNLOCK(state); -+#ifdef Py_GIL_DISABLED -+ // check if we are in the same thread -+ // if so, we can avoid locking -+ if (task->task_tid == _Py_ThreadId()) { -+ unregister_task_safe(task); -+ } -+ else { -+ // we are in a different thread -+ // stop the world then check and remove the task -+ PyThreadState *tstate = _PyThreadState_GET(); -+ _PyEval_StopTheWorld(tstate->interp); -+ unregister_task_safe(task); -+ _PyEval_StartTheWorld(tstate->interp); -+ } -+#else -+ unregister_task_safe(task); -+#endif - } - - static int -@@ -1963,7 +2241,10 @@ - Py_DECREF(item); - return -1; - } -- Py_DECREF(item); -+ -+ assert(task == item); -+ Py_CLEAR(item); -+ set_ts_asyncio_running_task(loop, task); - return 0; - } - -@@ -1988,7 +2269,6 @@ - - static int - leave_task(asyncio_state *state, PyObject *loop, PyObject *task) --/*[clinic end generated code: output=0ebf6db4b858fb41 input=51296a46313d1ad8]*/ - { - int res = _PyDict_DelItemIf(state->current_tasks, loop, - leave_task_predicate, task); -@@ -1996,6 +2276,7 @@ - // task was not found - return err_leave_task(Py_None, task); - } -+ clear_ts_asyncio_running_task(loop); - return res; - } - -@@ -2022,6 +2303,7 @@ - { - PyObject *prev_task; - -+ clear_ts_asyncio_running_task(loop); - if (task == Py_None) { - if (PyDict_Pop(state->current_tasks, loop, &prev_task) < 0) { - return NULL; -@@ -2041,9 +2323,63 @@ - Py_BEGIN_CRITICAL_SECTION(current_tasks); - prev_task = swap_current_task_lock_held(current_tasks, loop, hash, task); - Py_END_CRITICAL_SECTION(); -+ set_ts_asyncio_running_task(loop, task); - return prev_task; - } - -+static inline void -+set_ts_asyncio_running_task(PyObject *loop, PyObject *task) -+{ -+ // We want to enable debuggers and profilers to be able to quickly -+ // introspect the asyncio running state from another process. -+ // When we do that, we need to essentially traverse the address space -+ // of a Python process and understand what every Python thread in it is -+ // currently doing, mainly: -+ // -+ // * current frame -+ // * current asyncio task -+ // -+ // A naive solution would be to require profilers and debuggers to -+ // find the current task in the "_asynciomodule" module state, but -+ // unfortunately that would require a lot of complicated remote -+ // memory reads and logic, as Python's dict is a notoriously complex -+ // and ever-changing data structure. -+ // -+ // So the easier solution is to put a strong reference to the currently -+ // running `asyncio.Task` on the current thread state (the current loop -+ // is also stored there.) -+ _PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET(); -+ if (ts->asyncio_running_loop == loop) { -+ // Protect from a situation when someone calls this method -+ // from another thread. This shouldn't ever happen though, -+ // as `enter_task` and `leave_task` can either be called by: -+ // -+ // - `asyncio.Task` itself, in `Task.__step()`. That method -+ // can only be called by the event loop itself. -+ // -+ // - third-party Task "from scratch" implementations, that -+ // our `capture_call_graph` API doesn't support anyway. -+ // -+ // That said, we still want to make sure we don't end up in -+ // a broken state, so we check that we're in the correct thread -+ // by comparing the *loop* argument to the event loop running -+ // in the current thread. If they match we know we're in the -+ // right thread, as asyncio event loops don't change threads. -+ assert(ts->asyncio_running_task == NULL); -+ ts->asyncio_running_task = Py_NewRef(task); -+ } -+} -+ -+static inline void -+clear_ts_asyncio_running_task(PyObject *loop) -+{ -+ // See comment in set_ts_asyncio_running_task() for details. -+ _PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET(); -+ if (ts->asyncio_running_loop == NULL || ts->asyncio_running_loop == loop) { -+ Py_CLEAR(ts->asyncio_running_task); -+ } -+} -+ - /* ----- Task */ - - /*[clinic input] -@@ -2068,6 +2404,7 @@ - if (future_init((FutureObj*)self, loop)) { - return -1; - } -+ self->task_is_task = 1; - - asyncio_state *state = get_asyncio_state_by_def((PyObject *)self); - int is_coro = is_coroutine(state, coro); -@@ -2092,11 +2429,13 @@ - } - - Py_CLEAR(self->task_fut_waiter); -+#ifdef Py_GIL_DISABLED -+ self->task_tid = _Py_ThreadId(); -+#endif - self->task_must_cancel = 0; - self->task_log_destroy_pending = 1; - self->task_num_cancels_requested = 0; -- Py_INCREF(coro); -- Py_XSETREF(self->task_coro, coro); -+ set_task_coro(self, coro); - - if (name == Py_None) { - // optimization: defer task name formatting -@@ -2136,6 +2475,11 @@ - if (task_call_step_soon(state, self, NULL)) { - return -1; - } -+#ifdef Py_GIL_DISABLED -+ // This is required so that _Py_TryIncref(self) -+ // works correctly in non-owning threads. -+ _PyObject_SetMaybeWeakref((PyObject *)self); -+#endif - register_task(state, self); - return 0; - } -@@ -2144,8 +2488,8 @@ - TaskObj_clear(TaskObj *task) - { - (void)FutureObj_clear((FutureObj*) task); -+ clear_task_coro(task); - Py_CLEAR(task->task_context); -- Py_CLEAR(task->task_coro); - Py_CLEAR(task->task_name); - Py_CLEAR(task->task_fut_waiter); - return 0; -@@ -2170,14 +2514,22 @@ - Py_VISIT(fut->fut_source_tb); - Py_VISIT(fut->fut_cancel_msg); - Py_VISIT(fut->fut_cancelled_exc); -+ Py_VISIT(fut->fut_awaited_by); - PyObject_VisitManagedDict((PyObject *)fut, visit, arg); - return 0; - } - -+/*[clinic input] -+@critical_section -+@getter -+_asyncio.Task._log_destroy_pending -+[clinic start generated code]*/ -+ - static PyObject * --TaskObj_get_log_destroy_pending(TaskObj *task, void *Py_UNUSED(ignored)) -+_asyncio_Task__log_destroy_pending_get_impl(TaskObj *self) -+/*[clinic end generated code: output=e6c2a47d029ac93b input=17127298cd4c720b]*/ - { -- if (task->task_log_destroy_pending) { -+ if (self->task_log_destroy_pending) { - Py_RETURN_TRUE; - } - else { -@@ -2185,25 +2537,40 @@ - } - } - -+/*[clinic input] -+@critical_section -+@setter -+_asyncio.Task._log_destroy_pending -+[clinic start generated code]*/ -+ - static int --TaskObj_set_log_destroy_pending(TaskObj *task, PyObject *val, void *Py_UNUSED(ignored)) -+_asyncio_Task__log_destroy_pending_set_impl(TaskObj *self, PyObject *value) -+/*[clinic end generated code: output=7ebc030bb92ec5ce input=49b759c97d1216a4]*/ - { -- if (val == NULL) { -+ if (value == NULL) { - PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); - return -1; - } -- int is_true = PyObject_IsTrue(val); -+ int is_true = PyObject_IsTrue(value); - if (is_true < 0) { - return -1; - } -- task->task_log_destroy_pending = is_true; -+ self->task_log_destroy_pending = is_true; - return 0; - } - -+ -+/*[clinic input] -+@critical_section -+@getter -+_asyncio.Task._must_cancel -+[clinic start generated code]*/ -+ - static PyObject * --TaskObj_get_must_cancel(TaskObj *task, void *Py_UNUSED(ignored)) -+_asyncio_Task__must_cancel_get_impl(TaskObj *self) -+/*[clinic end generated code: output=70e79b900996c363 input=2d04529fb23feedf]*/ - { -- if (task->task_must_cancel) { -+ if (self->task_must_cancel) { - Py_RETURN_TRUE; - } - else { -@@ -2211,21 +2578,36 @@ - } - } - -+/*[clinic input] -+@critical_section -+@getter -+_asyncio.Task._coro -+[clinic start generated code]*/ -+ - static PyObject * --TaskObj_get_coro(TaskObj *task, void *Py_UNUSED(ignored)) -+_asyncio_Task__coro_get_impl(TaskObj *self) -+/*[clinic end generated code: output=a2726012ab5fd531 input=323c31a272020624]*/ - { -- if (task->task_coro) { -- return Py_NewRef(task->task_coro); -+ if (self->task_coro) { -+ return Py_NewRef(self->task_coro); - } - - Py_RETURN_NONE; - } - -+ -+/*[clinic input] -+@critical_section -+@getter -+_asyncio.Task._fut_waiter -+[clinic start generated code]*/ -+ - static PyObject * --TaskObj_get_fut_waiter(TaskObj *task, void *Py_UNUSED(ignored)) -+_asyncio_Task__fut_waiter_get_impl(TaskObj *self) -+/*[clinic end generated code: output=c4f966b847fefcdf input=4d1005d725e72db7]*/ - { -- if (task->task_fut_waiter) { -- return Py_NewRef(task->task_fut_waiter); -+ if (self->task_fut_waiter) { -+ return Py_NewRef(self->task_fut_waiter); - } - - Py_RETURN_NONE; -@@ -2241,6 +2623,7 @@ - - - /*[clinic input] -+@critical_section - _asyncio.Task._make_cancelled_error - - Create the CancelledError to raise if the Task is cancelled. -@@ -2251,7 +2634,7 @@ - - static PyObject * - _asyncio_Task__make_cancelled_error_impl(TaskObj *self) --/*[clinic end generated code: output=55a819e8b4276fab input=52c0e32de8e2f840]*/ -+/*[clinic end generated code: output=55a819e8b4276fab input=2d3213be0cb02390]*/ - { - FutureObj *fut = (FutureObj*)self; - return _asyncio_Future__make_cancelled_error_impl(fut); -@@ -2259,6 +2642,7 @@ - - - /*[clinic input] -+@critical_section - _asyncio.Task.cancel - - msg: object = None -@@ -2287,7 +2671,7 @@ - - static PyObject * - _asyncio_Task_cancel_impl(TaskObj *self, PyObject *msg) --/*[clinic end generated code: output=c66b60d41c74f9f1 input=7bb51bf25974c783]*/ -+/*[clinic end generated code: output=c66b60d41c74f9f1 input=6125d45b9a6a5abd]*/ - { - self->task_log_tb = 0; - -@@ -2332,6 +2716,7 @@ - } - - /*[clinic input] -+@critical_section - _asyncio.Task.cancelling - - Return the count of the task's cancellation requests. -@@ -2342,13 +2727,14 @@ - - static PyObject * - _asyncio_Task_cancelling_impl(TaskObj *self) --/*[clinic end generated code: output=803b3af96f917d7e input=b625224d310cbb17]*/ -+/*[clinic end generated code: output=803b3af96f917d7e input=5ef89b1b38f080ee]*/ - /*[clinic end generated code]*/ - { - return PyLong_FromLong(self->task_num_cancels_requested); - } - - /*[clinic input] -+@critical_section - _asyncio.Task.uncancel - - Decrement the task's count of cancellation requests. -@@ -2361,7 +2747,7 @@ - - static PyObject * - _asyncio_Task_uncancel_impl(TaskObj *self) --/*[clinic end generated code: output=58184d236a817d3c input=68f81a4b90b46be2]*/ -+/*[clinic end generated code: output=58184d236a817d3c input=cb3220b0e5afd61d]*/ - /*[clinic end generated code]*/ - { - if (self->task_num_cancels_requested > 0) { -@@ -2475,12 +2861,13 @@ - } - - /*[clinic input] -+@critical_section - _asyncio.Task.get_coro - [clinic start generated code]*/ - - static PyObject * - _asyncio_Task_get_coro_impl(TaskObj *self) --/*[clinic end generated code: output=bcac27c8cc6c8073 input=d2e8606c42a7b403]*/ -+/*[clinic end generated code: output=bcac27c8cc6c8073 input=a47f81427e39fe0c]*/ - { - if (self->task_coro) { - return Py_NewRef(self->task_coro); -@@ -2501,12 +2888,13 @@ - } - - /*[clinic input] -+@critical_section - _asyncio.Task.get_name - [clinic start generated code]*/ - - static PyObject * - _asyncio_Task_get_name_impl(TaskObj *self) --/*[clinic end generated code: output=0ecf1570c3b37a8f input=a4a6595d12f4f0f8]*/ -+/*[clinic end generated code: output=0ecf1570c3b37a8f input=92a8f30c85034249]*/ - { - if (self->task_name) { - if (PyLong_CheckExact(self->task_name)) { -@@ -2523,6 +2911,7 @@ - } - - /*[clinic input] -+@critical_section - _asyncio.Task.set_name - - value: object -@@ -2530,8 +2919,8 @@ - [clinic start generated code]*/ - - static PyObject * --_asyncio_Task_set_name(TaskObj *self, PyObject *value) --/*[clinic end generated code: output=138a8d51e32057d6 input=a8359b6e65f8fd31]*/ -+_asyncio_Task_set_name_impl(TaskObj *self, PyObject *value) -+/*[clinic end generated code: output=f88ff4c0d64a9a6f input=e8d400ad64bad799]*/ - { - if (!PyUnicode_CheckExact(value)) { - value = PyObject_Str(value); -@@ -2549,15 +2938,6 @@ - static void - TaskObj_finalize(TaskObj *task) - { -- asyncio_state *state = get_asyncio_state_by_def((PyObject *)task); -- // Unregister the task from the linked list of tasks. -- // Since task is a native task, we directly call the -- // unregister_task function. Third party event loops -- // should use the asyncio._unregister_task function. -- // See https://docs.python.org/3/library/asyncio-extending.html#task-lifetime-support -- -- unregister_task(state, task); -- - PyObject *context; - PyObject *message = NULL; - PyObject *func; -@@ -2597,7 +2977,8 @@ - if (func != NULL) { - PyObject *res = PyObject_CallOneArg(func, context); - if (res == NULL) { -- PyErr_WriteUnraisable(func); -+ PyErr_FormatUnraisable("Exception ignored while calling asyncio " -+ "function %R", func); - } - else { - Py_DECREF(res); -@@ -2642,12 +3023,10 @@ - }; - - static PyGetSetDef TaskType_getsetlist[] = { -- FUTURE_COMMON_GETSETLIST -- {"_log_destroy_pending", (getter)TaskObj_get_log_destroy_pending, -- (setter)TaskObj_set_log_destroy_pending, NULL}, -- {"_must_cancel", (getter)TaskObj_get_must_cancel, NULL, NULL}, -- {"_coro", (getter)TaskObj_get_coro, NULL, NULL}, -- {"_fut_waiter", (getter)TaskObj_get_fut_waiter, NULL, NULL}, -+ _ASYNCIO_TASK__LOG_DESTROY_PENDING_GETSETDEF -+ _ASYNCIO_TASK__MUST_CANCEL_GETSETDEF -+ _ASYNCIO_TASK__CORO_GETSETDEF -+ _ASYNCIO_TASK__FUT_WAITER_GETSETDEF - {NULL} /* Sentinel */ - }; - -@@ -2683,8 +3062,15 @@ - { - TaskObj *task = (TaskObj *)self; - -- if (PyObject_CallFinalizerFromDealloc(self) < 0) { -- // resurrected. -+ _PyObject_ResurrectStart(self); -+ // Unregister the task here so that even if any subclass of Task -+ // which doesn't end up calling TaskObj_finalize not crashes. -+ asyncio_state *state = get_asyncio_state_by_def(self); -+ unregister_task(state, task); -+ -+ PyObject_CallFinalizer(self); -+ -+ if (_PyObject_ResurrectEnd(self)) { - return; - } - -@@ -2762,6 +3148,8 @@ - static PyObject * - task_step_impl(asyncio_state *state, TaskObj *task, PyObject *exc) - { -+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(task); -+ - int clear_exc = 0; - PyObject *result = NULL; - PyObject *coro; -@@ -2891,6 +3279,8 @@ - static PyObject * - task_step_handle_result_impl(asyncio_state *state, TaskObj *task, PyObject *result) - { -+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(task); -+ - int res; - PyObject *o; - -@@ -2913,6 +3303,13 @@ - if (!fut->fut_blocking) { - goto yield_insteadof_yf; - } -+ int res; -+ Py_BEGIN_CRITICAL_SECTION(result); -+ res = future_awaited_by_add(state, (FutureObj *)result, (PyObject *)task); -+ Py_END_CRITICAL_SECTION(); -+ if (res) { -+ goto fail; -+ } - - fut->fut_blocking = 0; - -@@ -2921,8 +3318,10 @@ - if (wrapper == NULL) { - goto fail; - } -+ Py_BEGIN_CRITICAL_SECTION(result); - tmp = future_add_done_callback(state, - (FutureObj*)result, wrapper, task->task_context); -+ Py_END_CRITICAL_SECTION(); - Py_DECREF(wrapper); - if (tmp == NULL) { - goto fail; -@@ -3001,6 +3400,16 @@ - goto yield_insteadof_yf; - } - -+ if (TaskOrFuture_Check(state, result)) { -+ int res; -+ Py_BEGIN_CRITICAL_SECTION(result); -+ res = future_awaited_by_add(state, (FutureObj *)result, (PyObject *)task); -+ Py_END_CRITICAL_SECTION(); -+ if (res) { -+ goto fail; -+ } -+ } -+ - /* result._asyncio_future_blocking = False */ - if (PyObject_SetAttr( - result, &_Py_ID(_asyncio_future_blocking), Py_False) == -1) { -@@ -3164,7 +3573,10 @@ - - int retval = 0; - -- PyObject *stepres = task_step_impl(state, task, NULL); -+ PyObject *stepres; -+ Py_BEGIN_CRITICAL_SECTION(task); -+ stepres = task_step_impl(state, task, NULL); -+ Py_END_CRITICAL_SECTION(); - if (stepres == NULL) { - PyObject *exc = PyErr_GetRaisedException(); - _PyErr_ChainExceptions1(exc); -@@ -3194,23 +3606,38 @@ - register_task(state, task); - } else { - // This seems to really help performance on pyperformance benchmarks -- Py_CLEAR(task->task_coro); -+ clear_task_coro(task); - } - - return retval; - } - - static PyObject * --task_wakeup(TaskObj *task, PyObject *o) -+task_wakeup_lock_held(TaskObj *task, PyObject *o) - { -+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(task); -+ - PyObject *result; - assert(o); - - asyncio_state *state = get_asyncio_state_by_def((PyObject *)task); -+ -+ if (TaskOrFuture_Check(state, o)) { -+ int res; -+ Py_BEGIN_CRITICAL_SECTION(o); -+ res = future_awaited_by_discard(state, (FutureObj *)o, (PyObject *)task); -+ Py_END_CRITICAL_SECTION(); -+ if (res) { -+ return NULL; -+ } -+ } -+ - if (Future_CheckExact(state, o) || Task_CheckExact(state, o)) { - PyObject *fut_result = NULL; -- int res = future_get_result(state, (FutureObj*)o, &fut_result); -- -+ int res; -+ Py_BEGIN_CRITICAL_SECTION(o); -+ res = future_get_result(state, (FutureObj*)o, &fut_result); -+ Py_END_CRITICAL_SECTION(); - switch(res) { - case -1: - assert(fut_result == NULL); -@@ -3244,6 +3671,16 @@ - return result; - } - -+static PyObject * -+task_wakeup(TaskObj *task, PyObject *o) -+{ -+ PyObject *res; -+ Py_BEGIN_CRITICAL_SECTION(task); -+ res = task_wakeup_lock_held(task, o); -+ Py_END_CRITICAL_SECTION(); -+ return res; -+} -+ - - /*********************** Functions **************************/ - -@@ -3551,6 +3988,20 @@ - static inline int - add_one_task(asyncio_state *state, PyObject *tasks, PyObject *task, PyObject *loop) - { -+ assert(PySet_CheckExact(tasks)); -+ if (Task_CheckExact(state, task)) { -+ int pending = 0; -+ Py_BEGIN_CRITICAL_SECTION(task); -+ pending = ((TaskObj *)task)->task_state == STATE_PENDING && ((TaskObj *)task)->task_loop == loop; -+ Py_END_CRITICAL_SECTION(); -+ if (pending) { -+ if (PySet_Add(tasks, task) < 0) { -+ return -1; -+ } -+ } -+ return 0; -+ } -+ - PyObject *done = PyObject_CallMethodNoArgs(task, &_Py_ID(done)); - if (done == NULL) { - return -1; -@@ -3573,6 +4024,57 @@ - return 0; - } - -+static inline int -+add_tasks_llist(struct llist_node *head, PyListObject *tasks) -+{ -+ struct llist_node *node; -+ llist_for_each_safe(node, head) { -+ TaskObj *task = llist_data(node, TaskObj, task_node); -+ // The linked list holds borrowed references to task -+ // as such it is possible that the task is concurrently -+ // deallocated while added to this list. -+ // To protect against concurrent deallocations, -+ // we first try to incref the task which would fail -+ // if it is concurrently getting deallocated in another thread, -+ // otherwise it gets added to the list. -+ if (_Py_TryIncref((PyObject *)task)) { -+ if (_PyList_AppendTakeRef(tasks, (PyObject *)task) < 0) { -+ // do not call any escaping calls here while the world is stopped. -+ return -1; -+ } -+ } -+ } -+ return 0; -+} -+ -+static inline int -+add_tasks_interp(PyInterpreterState *interp, PyListObject *tasks) -+{ -+#ifdef Py_GIL_DISABLED -+ assert(interp->stoptheworld.world_stopped); -+#endif -+ // Start traversing from interpreter's linked list -+ struct llist_node *head = &interp->asyncio_tasks_head; -+ -+ if (add_tasks_llist(head, tasks) < 0) { -+ return -1; -+ } -+ -+ int ret = 0; -+ // traverse the task lists of thread states -+ _Py_FOR_EACH_TSTATE_BEGIN(interp, p) { -+ _PyThreadStateImpl *ts = (_PyThreadStateImpl *)p; -+ head = &ts->asyncio_tasks_head; -+ if (add_tasks_llist(head, tasks) < 0) { -+ ret = -1; -+ goto exit; -+ } -+ } -+exit: -+ _Py_FOR_EACH_TSTATE_END(interp); -+ return ret; -+} -+ - /*********************** Module **************************/ - - /*[clinic input] -@@ -3588,81 +4090,138 @@ - _asyncio_all_tasks_impl(PyObject *module, PyObject *loop) - /*[clinic end generated code: output=0e107cbb7f72aa7b input=43a1b423c2d95bfa]*/ - { -- - asyncio_state *state = get_asyncio_state(module); -- PyObject *tasks = PySet_New(NULL); -- if (tasks == NULL) { -- return NULL; -- } - if (loop == Py_None) { - loop = _asyncio_get_running_loop_impl(module); - if (loop == NULL) { -- Py_DECREF(tasks); - return NULL; - } - } else { - Py_INCREF(loop); - } -- // First add eager tasks to the set so that we don't miss -+ // First add eager tasks to the list so that we don't miss - // any tasks which graduates from eager to non-eager -- PyObject *eager_iter = PyObject_GetIter(state->eager_tasks); -- if (eager_iter == NULL) { -- Py_DECREF(tasks); -+ // We first add all the tasks to `tasks` list and then filter -+ // out the tasks which are done and return it as a set. -+ PyObject *tasks = PyList_New(0); -+ if (tasks == NULL) { - Py_DECREF(loop); - return NULL; - } -- PyObject *item; -- while ((item = PyIter_Next(eager_iter)) != NULL) { -- if (add_one_task(state, tasks, item, loop) < 0) { -- Py_DECREF(tasks); -- Py_DECREF(loop); -- Py_DECREF(item); -- Py_DECREF(eager_iter); -- return NULL; -- } -- Py_DECREF(item); -+ if (PyList_Extend(tasks, state->eager_tasks) < 0) { -+ Py_DECREF(tasks); -+ Py_DECREF(loop); -+ return NULL; - } -- Py_DECREF(eager_iter); -- int err = 0; -- ASYNCIO_STATE_LOCK(state); -- TaskObj *first = &state->asyncio_tasks.first; -- TaskObj *head = state->asyncio_tasks.head->next; -- Py_INCREF(head); -- while (head != first) -- { -- if (add_one_task(state, tasks, (PyObject *)head, loop) < 0) { -- Py_DECREF(tasks); -- Py_DECREF(loop); -- Py_DECREF(head); -- err = 1; -- break; -- } -- Py_INCREF(head->next); -- Py_SETREF(head, head->next); -+ if (PyList_Extend(tasks, state->non_asyncio_tasks) < 0) { -+ Py_DECREF(tasks); -+ Py_DECREF(loop); -+ return NULL; - } -- ASYNCIO_STATE_UNLOCK(state); -- if (err) { -+ -+ PyInterpreterState *interp = PyInterpreterState_Get(); -+ // Stop the world and traverse the per-thread linked list -+ // of asyncio tasks for every thread, as well as the -+ // interpreter's linked list, and add them to `tasks`. -+ // The interpreter linked list is used for any lingering tasks -+ // whose thread state has been deallocated while the task was -+ // still alive. This can happen if a task is referenced by -+ // a different thread, in which case the task is moved to -+ // the interpreter's linked list from the thread's linked -+ // list before deallocation. See PyThreadState_Clear. -+ // -+ // The stop-the-world pause is required so that no thread -+ // modifies its linked list while being iterated here -+ // in parallel. This design allows for lock-free -+ // register_task/unregister_task for loops running in parallel -+ // in different threads (the general case). -+ _PyEval_StopTheWorld(interp); -+ int ret = add_tasks_interp(interp, (PyListObject *)tasks); -+ _PyEval_StartTheWorld(interp); -+ if (ret < 0) { -+ // call any escaping calls after starting the world to avoid any deadlocks. -+ Py_DECREF(tasks); -+ Py_DECREF(loop); - return NULL; - } -- PyObject *scheduled_iter = PyObject_GetIter(state->non_asyncio_tasks); -- if (scheduled_iter == NULL) { -+ -+ // All the tasks are now in the list, now filter the tasks which are done -+ PyObject *res = PySet_New(NULL); -+ if (res == NULL) { - Py_DECREF(tasks); - Py_DECREF(loop); - return NULL; - } -- while ((item = PyIter_Next(scheduled_iter)) != NULL) { -- if (add_one_task(state, tasks, item, loop) < 0) { -+ -+ for (Py_ssize_t i = 0; i < PyList_GET_SIZE(tasks); i++) { -+ PyObject *task = PyList_GET_ITEM(tasks, i); -+ if (add_one_task(state, res, task, loop) < 0) { -+ Py_DECREF(res); - Py_DECREF(tasks); - Py_DECREF(loop); -- Py_DECREF(item); -- Py_DECREF(scheduled_iter); - return NULL; - } -- Py_DECREF(item); - } -- Py_DECREF(scheduled_iter); -+ -+ Py_DECREF(tasks); - Py_DECREF(loop); -- return tasks; -+ return res; -+} -+ -+/*[clinic input] -+_asyncio.future_add_to_awaited_by -+ -+ fut: object -+ waiter: object -+ / -+ -+Record that `fut` is awaited on by `waiter`. -+ -+[clinic start generated code]*/ -+ -+static PyObject * -+_asyncio_future_add_to_awaited_by_impl(PyObject *module, PyObject *fut, -+ PyObject *waiter) -+/*[clinic end generated code: output=0ab9a1a63389e4df input=06e6eaac51f532b9]*/ -+{ -+ asyncio_state *state = get_asyncio_state(module); -+ if (TaskOrFuture_Check(state, fut) && TaskOrFuture_Check(state, waiter)) { -+ int res; -+ Py_BEGIN_CRITICAL_SECTION(fut); -+ res = future_awaited_by_add(state, (FutureObj *)fut, waiter); -+ Py_END_CRITICAL_SECTION(); -+ if (res) { -+ return NULL; -+ } -+ } -+ Py_RETURN_NONE; -+} -+ -+/*[clinic input] -+_asyncio.future_discard_from_awaited_by -+ -+ fut: object -+ waiter: object -+ / -+ -+[clinic start generated code]*/ -+ -+static PyObject * -+_asyncio_future_discard_from_awaited_by_impl(PyObject *module, PyObject *fut, -+ PyObject *waiter) -+/*[clinic end generated code: output=a03b0b4323b779de input=3833f7639e88e483]*/ -+{ -+ asyncio_state *state = get_asyncio_state(module); -+ if (TaskOrFuture_Check(state, fut) && TaskOrFuture_Check(state, waiter)) { -+ int res; -+ Py_BEGIN_CRITICAL_SECTION(fut); -+ res = future_awaited_by_discard(state, (FutureObj *)fut, waiter); -+ Py_END_CRITICAL_SECTION(); -+ if (res) { -+ return NULL; -+ } -+ } -+ Py_RETURN_NONE; - } - - static int -@@ -3723,6 +4282,12 @@ - Py_CLEAR(state->iscoroutine_typecache); - - Py_CLEAR(state->context_kwname); -+ // Clear the ref to running loop so that finalizers can run early. -+ // If there are other running loops in different threads, -+ // those get cleared in PyThreadState_Clear. -+ _PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET(); -+ Py_CLEAR(ts->asyncio_running_loop); -+ Py_CLEAR(ts->asyncio_running_task); - - return 0; - } -@@ -3753,7 +4318,6 @@ - goto fail; - } - -- - state->context_kwname = Py_BuildValue("(s)", "context"); - if (state->context_kwname == NULL) { - goto fail; -@@ -3773,7 +4337,7 @@ - } - - WITH_MOD("asyncio.events") -- GET_MOD_ATTR(state->asyncio_get_event_loop_policy, "get_event_loop_policy") -+ GET_MOD_ATTR(state->asyncio_get_event_loop_policy, "_get_event_loop_policy") - - WITH_MOD("asyncio.base_futures") - GET_MOD_ATTR(state->asyncio_future_repr_func, "_future_repr") -@@ -3834,6 +4398,8 @@ - _ASYNCIO__LEAVE_TASK_METHODDEF - _ASYNCIO__SWAP_CURRENT_TASK_METHODDEF - _ASYNCIO_ALL_TASKS_METHODDEF -+ _ASYNCIO_FUTURE_ADD_TO_AWAITED_BY_METHODDEF -+ _ASYNCIO_FUTURE_DISCARD_FROM_AWAITED_BY_METHODDEF - {NULL, NULL} - }; - -@@ -3842,11 +4408,6 @@ - { - asyncio_state *state = get_asyncio_state(mod); - -- Py_SET_TYPE(&state->asyncio_tasks.first, state->TaskType); -- _Py_SetImmortalUntracked((PyObject *)&state->asyncio_tasks.first); -- state->asyncio_tasks.head = &state->asyncio_tasks.first; -- state->asyncio_tasks.head->next = &state->asyncio_tasks.first; -- state->asyncio_tasks.head->prev = &state->asyncio_tasks.first; - - #define CREATE_TYPE(m, tp, spec, base) \ - do { \ -diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c -index 661847ad267..9e85e0de42c 100644 ---- a/Modules/_bz2module.c -+++ b/Modules/_bz2module.c -@@ -129,6 +129,9 @@ - PyThread_type_lock lock; - } BZ2Decompressor; - -+#define _BZ2Compressor_CAST(op) ((BZ2Compressor *)(op)) -+#define _BZ2Decompressor_CAST(op) ((BZ2Decompressor *)(op)) -+ - /* Helper functions. */ - - static int -@@ -376,8 +379,9 @@ - } - - static void --BZ2Compressor_dealloc(BZ2Compressor *self) -+BZ2Compressor_dealloc(PyObject *op) - { -+ BZ2Compressor *self = _BZ2Compressor_CAST(op); - BZ2_bzCompressEnd(&self->bzs); - if (self->lock != NULL) { - PyThread_free_lock(self->lock); -@@ -388,7 +392,7 @@ - } - - static int --BZ2Compressor_traverse(BZ2Compressor *self, visitproc visit, void *arg) -+BZ2Compressor_traverse(PyObject *self, visitproc visit, void *arg) - { - Py_VISIT(Py_TYPE(self)); - return 0; -@@ -680,8 +684,10 @@ - } - - static void --BZ2Decompressor_dealloc(BZ2Decompressor *self) -+BZ2Decompressor_dealloc(PyObject *op) - { -+ BZ2Decompressor *self = _BZ2Decompressor_CAST(op); -+ - if(self->input_buffer != NULL) { - PyMem_Free(self->input_buffer); - } -@@ -697,7 +703,7 @@ - } - - static int --BZ2Decompressor_traverse(BZ2Decompressor *self, visitproc visit, void *arg) -+BZ2Decompressor_traverse(PyObject *self, visitproc visit, void *arg) - { - Py_VISIT(Py_TYPE(self)); - return 0; -diff --git a/Modules/_csv.c b/Modules/_csv.c -index 1a4dc3f1f55..e5ae853590b 100644 ---- a/Modules/_csv.c -+++ b/Modules/_csv.c -@@ -77,7 +77,7 @@ - static void - _csv_free(void *module) - { -- _csv_clear((PyObject *)module); -+ (void)_csv_clear((PyObject *)module); - } - - typedef enum { -@@ -151,6 +151,10 @@ - PyObject *error_obj; /* cached error object */ - } WriterObj; - -+#define _DialectObj_CAST(op) ((DialectObj *)(op)) -+#define _ReaderObj_CAST(op) ((ReaderObj *)(op)) -+#define _WriterObj_CAST(op) ((WriterObj *)(op)) -+ - /* - * DIALECT class - */ -@@ -176,32 +180,37 @@ - } - - static PyObject * --Dialect_get_lineterminator(DialectObj *self, void *Py_UNUSED(ignored)) -+Dialect_get_lineterminator(PyObject *op, void *Py_UNUSED(ignored)) - { -+ DialectObj *self = _DialectObj_CAST(op); - return Py_XNewRef(self->lineterminator); - } - - static PyObject * --Dialect_get_delimiter(DialectObj *self, void *Py_UNUSED(ignored)) -+Dialect_get_delimiter(PyObject *op, void *Py_UNUSED(ignored)) - { -+ DialectObj *self = _DialectObj_CAST(op); - return get_char_or_None(self->delimiter); - } - - static PyObject * --Dialect_get_escapechar(DialectObj *self, void *Py_UNUSED(ignored)) -+Dialect_get_escapechar(PyObject *op, void *Py_UNUSED(ignored)) - { -+ DialectObj *self = _DialectObj_CAST(op); - return get_char_or_None(self->escapechar); - } - - static PyObject * --Dialect_get_quotechar(DialectObj *self, void *Py_UNUSED(ignored)) -+Dialect_get_quotechar(PyObject *op, void *Py_UNUSED(ignored)) - { -+ DialectObj *self = _DialectObj_CAST(op); - return get_char_or_None(self->quotechar); - } - - static PyObject * --Dialect_get_quoting(DialectObj *self, void *Py_UNUSED(ignored)) -+Dialect_get_quoting(PyObject *op, void *Py_UNUSED(ignored)) - { -+ DialectObj *self = _DialectObj_CAST(op); - return PyLong_FromLong(self->quoting); - } - -@@ -371,16 +380,16 @@ - #undef D_OFF - - static PyGetSetDef Dialect_getsetlist[] = { -- { "delimiter", (getter)Dialect_get_delimiter}, -- { "escapechar", (getter)Dialect_get_escapechar}, -- { "lineterminator", (getter)Dialect_get_lineterminator}, -- { "quotechar", (getter)Dialect_get_quotechar}, -- { "quoting", (getter)Dialect_get_quoting}, -+ {"delimiter", Dialect_get_delimiter}, -+ {"escapechar", Dialect_get_escapechar}, -+ {"lineterminator", Dialect_get_lineterminator}, -+ {"quotechar", Dialect_get_quotechar}, -+ {"quoting", Dialect_get_quoting}, - {NULL}, - }; - - static void --Dialect_dealloc(DialectObj *self) -+Dialect_dealloc(PyObject *self) - { - PyTypeObject *tp = Py_TYPE(self); - PyObject_GC_UnTrack(self); -@@ -594,15 +603,17 @@ - "The Dialect type records CSV parsing and generation options.\n"); - - static int --Dialect_clear(DialectObj *self) -+Dialect_clear(PyObject *op) - { -+ DialectObj *self = _DialectObj_CAST(op); - Py_CLEAR(self->lineterminator); - return 0; - } - - static int --Dialect_traverse(DialectObj *self, visitproc visit, void *arg) -+Dialect_traverse(PyObject *op, visitproc visit, void *arg) - { -+ DialectObj *self = _DialectObj_CAST(op); - Py_VISIT(self->lineterminator); - Py_VISIT(Py_TYPE(self)); - return 0; -@@ -916,8 +927,10 @@ - } - - static PyObject * --Reader_iternext(ReaderObj *self) -+Reader_iternext(PyObject *op) - { -+ ReaderObj *self = _ReaderObj_CAST(op); -+ - PyObject *fields = NULL; - Py_UCS4 c; - Py_ssize_t pos, linelen; -@@ -982,11 +995,12 @@ - } - - static void --Reader_dealloc(ReaderObj *self) -+Reader_dealloc(PyObject *op) - { -+ ReaderObj *self = _ReaderObj_CAST(op); - PyTypeObject *tp = Py_TYPE(self); - PyObject_GC_UnTrack(self); -- tp->tp_clear((PyObject *)self); -+ (void)tp->tp_clear(op); - if (self->field != NULL) { - PyMem_Free(self->field); - self->field = NULL; -@@ -996,8 +1010,9 @@ - } - - static int --Reader_traverse(ReaderObj *self, visitproc visit, void *arg) -+Reader_traverse(PyObject *op, visitproc visit, void *arg) - { -+ ReaderObj *self = _ReaderObj_CAST(op); - Py_VISIT(self->dialect); - Py_VISIT(self->input_iter); - Py_VISIT(self->fields); -@@ -1006,8 +1021,9 @@ - } - - static int --Reader_clear(ReaderObj *self) -+Reader_clear(PyObject *op) - { -+ ReaderObj *self = _ReaderObj_CAST(op); - Py_CLEAR(self->dialect); - Py_CLEAR(self->input_iter); - Py_CLEAR(self->fields); -@@ -1122,7 +1138,7 @@ - int copy_phase) - { - DialectObj *dialect = self->dialect; -- int i; -+ Py_ssize_t i; - Py_ssize_t rec_len; - - #define INCLEN \ -@@ -1303,8 +1319,9 @@ - "elements will be converted to string."); - - static PyObject * --csv_writerow(WriterObj *self, PyObject *seq) -+csv_writerow(PyObject *op, PyObject *seq) - { -+ WriterObj *self = _WriterObj_CAST(op); - DialectObj *dialect = self->dialect; - PyObject *iter, *field, *line, *result; - bool null_field = false; -@@ -1412,7 +1429,7 @@ - "elements will be converted to string."); - - static PyObject * --csv_writerows(WriterObj *self, PyObject *seqseq) -+csv_writerows(PyObject *self, PyObject *seqseq) - { - PyObject *row_iter, *row_obj, *result; - -@@ -1437,9 +1454,9 @@ - } - - static struct PyMethodDef Writer_methods[] = { -- { "writerow", (PyCFunction)csv_writerow, METH_O, csv_writerow_doc}, -- { "writerows", (PyCFunction)csv_writerows, METH_O, csv_writerows_doc}, -- { NULL, NULL } -+ {"writerow", csv_writerow, METH_O, csv_writerow_doc}, -+ {"writerows", csv_writerows, METH_O, csv_writerows_doc}, -+ {NULL, NULL, 0, NULL} /* sentinel */ - }; - - #define W_OFF(x) offsetof(WriterObj, x) -@@ -1452,8 +1469,9 @@ - #undef W_OFF - - static int --Writer_traverse(WriterObj *self, visitproc visit, void *arg) -+Writer_traverse(PyObject *op, visitproc visit, void *arg) - { -+ WriterObj *self = _WriterObj_CAST(op); - Py_VISIT(self->dialect); - Py_VISIT(self->write); - Py_VISIT(self->error_obj); -@@ -1462,8 +1480,9 @@ - } - - static int --Writer_clear(WriterObj *self) -+Writer_clear(PyObject *op) - { -+ WriterObj *self = _WriterObj_CAST(op); - Py_CLEAR(self->dialect); - Py_CLEAR(self->write); - Py_CLEAR(self->error_obj); -@@ -1471,11 +1490,12 @@ - } - - static void --Writer_dealloc(WriterObj *self) -+Writer_dealloc(PyObject *op) - { -+ WriterObj *self = _WriterObj_CAST(op); - PyTypeObject *tp = Py_TYPE(self); - PyObject_GC_UnTrack(self); -- tp->tp_clear((PyObject *)self); -+ tp->tp_clear(op); - if (self->rec != NULL) { - PyMem_Free(self->rec); - } -diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c -index bb469988405..7c0ac1a57f5 100644 ---- a/Modules/_ctypes/_ctypes.c -+++ b/Modules/_ctypes/_ctypes.c -@@ -128,8 +128,9 @@ - - /*[clinic input] - module _ctypes -+class _ctypes.CFuncPtr "PyCFuncPtrObject *" "&PyCFuncPtr_Type" - [clinic start generated code]*/ --/*[clinic end generated code: output=da39a3ee5e6b4b0d input=476a19c49b31a75c]*/ -+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=58e8c99474bc631e]*/ - - #define clinic_state() (get_module_state_by_class(cls)) - #define clinic_state_sub() (get_module_state_by_class(cls->tp_base)) -@@ -145,9 +146,12 @@ - PyObject *dict; - } DictRemoverObject; - -+#define _DictRemoverObject_CAST(op) ((DictRemoverObject *)(op)) -+ - static int --_DictRemover_traverse(DictRemoverObject *self, visitproc visit, void *arg) -+_DictRemover_traverse(PyObject *myself, visitproc visit, void *arg) - { -+ DictRemoverObject *self = _DictRemoverObject_CAST(myself); - Py_VISIT(Py_TYPE(self)); - Py_VISIT(self->key); - Py_VISIT(self->dict); -@@ -155,8 +159,9 @@ - } - - static int --_DictRemover_clear(DictRemoverObject *self) -+_DictRemover_clear(PyObject *myself) - { -+ DictRemoverObject *self = _DictRemoverObject_CAST(myself); - Py_CLEAR(self->key); - Py_CLEAR(self->dict); - return 0; -@@ -166,9 +171,8 @@ - _DictRemover_dealloc(PyObject *myself) - { - PyTypeObject *tp = Py_TYPE(myself); -- DictRemoverObject *self = (DictRemoverObject *)myself; - PyObject_GC_UnTrack(myself); -- (void)_DictRemover_clear(self); -+ (void)_DictRemover_clear(myself); - tp->tp_free(myself); - Py_DECREF(tp); - } -@@ -176,10 +180,11 @@ - static PyObject * - _DictRemover_call(PyObject *myself, PyObject *args, PyObject *kw) - { -- DictRemoverObject *self = (DictRemoverObject *)myself; -+ DictRemoverObject *self = _DictRemoverObject_CAST(myself); - if (self->key && self->dict) { - if (-1 == PyDict_DelItem(self->dict, self->key)) { -- PyErr_FormatUnraisable("Exception ignored on calling _ctypes.DictRemover"); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "calling _ctypes.DictRemover"); - } - Py_CLEAR(self->key); - Py_CLEAR(self->dict); -@@ -401,16 +406,19 @@ - PyObject *keep; // If set, a reference to the original CDataObject. - } StructParamObject; - -+#define _StructParamObject_CAST(op) ((StructParamObject *)(op)) -+ - static int --StructParam_traverse(StructParamObject *self, visitproc visit, void *arg) -+StructParam_traverse(PyObject *self, visitproc visit, void *arg) - { - Py_VISIT(Py_TYPE(self)); - return 0; - } - - static int --StructParam_clear(StructParamObject *self) -+StructParam_clear(PyObject *myself) - { -+ StructParamObject *self = _StructParamObject_CAST(myself); - Py_CLEAR(self->keep); - return 0; - } -@@ -418,10 +426,10 @@ - static void - StructParam_dealloc(PyObject *myself) - { -- StructParamObject *self = (StructParamObject *)myself; -+ StructParamObject *self = _StructParamObject_CAST(myself); - PyTypeObject *tp = Py_TYPE(self); - PyObject_GC_UnTrack(myself); -- (void)StructParam_clear(self); -+ (void)StructParam_clear(myself); - PyMem_Free(self->ptr); - tp->tp_free(myself); - Py_DECREF(tp); -@@ -456,7 +464,8 @@ - { - StgInfo *info = _PyStgInfo_FromType_NoState(self); - if (!info) { -- PyErr_WriteUnraisable(self); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "calling ctypes traverse function %R", self); - } - if (info) { - Py_VISIT(info->proto); -@@ -487,7 +496,8 @@ - { - StgInfo *info = _PyStgInfo_FromType_NoState(self); - if (!info) { -- PyErr_WriteUnraisable(self); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "clearing ctypes %R", self); - } - if (info) { - ctype_clear_stginfo(info); -@@ -500,7 +510,8 @@ - { - StgInfo *info = _PyStgInfo_FromType_NoState(self); - if (!info) { -- PyErr_WriteUnraisable(NULL); // NULL avoids segfault here -+ PyErr_FormatUnraisable("Exception ignored while " -+ "deallocating ctypes %R", self); - } - if (info) { - PyMem_Free(info->ffi_type_pointer.elements); -@@ -597,7 +608,7 @@ - if (ptr == NULL) { - return NULL; - } -- memcpy(ptr, self->b_ptr, self->b_size); -+ locked_memcpy_from(ptr, self, self->b_size); - - /* Create a Python object which calls PyMem_Free(ptr) in - its deallocator. The object will be destroyed -@@ -674,7 +685,7 @@ - - info->paramfunc = StructUnionType_paramfunc; - -- if (PyDict_GetItemRef((PyObject *)attrdict, &_Py_ID(_fields_), &fields) < 0) { -+ if (PyDict_GetItemRef(attrdict, &_Py_ID(_fields_), &fields) < 0) { - Py_DECREF(attrdict); - return -1; - } -@@ -906,8 +917,7 @@ - - result = generic_pycdata_new(st, (PyTypeObject *)type, NULL, NULL); - if (result != NULL) { -- memcpy(((CDataObject *)result)->b_ptr, -- (char *)buffer->buf + offset, info->size); -+ locked_memcpy_to((CDataObject *) result, (char *)buffer->buf + offset, info->size); - } - return result; - } -@@ -984,15 +994,8 @@ - #ifdef USE_DLERROR - const char *dlerr = dlerror(); - if (dlerr) { -- PyObject *message = PyUnicode_DecodeLocale(dlerr, "surrogateescape"); -- if (message) { -- PyErr_SetObject(PyExc_ValueError, message); -- Py_DECREF(message); -- return NULL; -- } -- // Ignore errors from PyUnicode_DecodeLocale, -- // fall back to the generic error below. -- PyErr_Clear(); -+ _PyErr_SetLocaleString(PyExc_ValueError, dlerr); -+ return NULL; - } - #endif - #undef USE_DLERROR -@@ -1201,7 +1204,7 @@ - parg->tag = 'P'; - parg->pffi_type = &ffi_type_pointer; - parg->obj = Py_NewRef(self); -- parg->value.p = *(void **)self->b_ptr; -+ parg->value.p = locked_deref(self); - return parg; - } - -@@ -1418,11 +1421,12 @@ - */ - - static int --CharArray_set_raw(CDataObject *self, PyObject *value, void *Py_UNUSED(ignored)) -+CharArray_set_raw(PyObject *op, PyObject *value, void *Py_UNUSED(ignored)) - { - char *ptr; - Py_ssize_t size; - Py_buffer view; -+ CDataObject *self = _CDataObject_CAST(op); - - if (value == NULL) { - PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); -@@ -1438,7 +1442,7 @@ - goto fail; - } - -- memcpy(self->b_ptr, ptr, size); -+ locked_memcpy_to(self, ptr, size); - - PyBuffer_Release(&view); - return 0; -@@ -1448,27 +1452,38 @@ - } - - static PyObject * --CharArray_get_raw(CDataObject *self, void *Py_UNUSED(ignored)) -+CharArray_get_raw(PyObject *op, void *Py_UNUSED(ignored)) - { -- return PyBytes_FromStringAndSize(self->b_ptr, self->b_size); -+ PyObject *res; -+ CDataObject *self = _CDataObject_CAST(op); -+ LOCK_PTR(self); -+ res = PyBytes_FromStringAndSize(self->b_ptr, self->b_size); -+ UNLOCK_PTR(self); -+ return res; - } - - static PyObject * --CharArray_get_value(CDataObject *self, void *Py_UNUSED(ignored)) -+CharArray_get_value(PyObject *op, void *Py_UNUSED(ignored)) - { - Py_ssize_t i; -+ PyObject *res; -+ CDataObject *self = _CDataObject_CAST(op); -+ LOCK_PTR(self); - char *ptr = self->b_ptr; - for (i = 0; i < self->b_size; ++i) - if (*ptr++ == '\0') - break; -- return PyBytes_FromStringAndSize(self->b_ptr, i); -+ res = PyBytes_FromStringAndSize(self->b_ptr, i); -+ UNLOCK_PTR(self); -+ return res; - } - - static int --CharArray_set_value(CDataObject *self, PyObject *value, void *Py_UNUSED(ignored)) -+CharArray_set_value(PyObject *op, PyObject *value, void *Py_UNUSED(ignored)) - { - const char *ptr; - Py_ssize_t size; -+ CDataObject *self = _CDataObject_CAST(op); - - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, -@@ -1492,36 +1507,43 @@ - } - - ptr = PyBytes_AS_STRING(value); -+ LOCK_PTR(self); - memcpy(self->b_ptr, ptr, size); - if (size < self->b_size) - self->b_ptr[size] = '\0'; -+ UNLOCK_PTR(self); - Py_DECREF(value); - - return 0; - } - - static PyGetSetDef CharArray_getsets[] = { -- { "raw", (getter)CharArray_get_raw, (setter)CharArray_set_raw, -- "value", NULL }, -- { "value", (getter)CharArray_get_value, (setter)CharArray_set_value, -- "string value"}, -+ { "raw", CharArray_get_raw, CharArray_set_raw, "value", NULL }, -+ { "value", CharArray_get_value, CharArray_set_value, "string value" }, - { NULL, NULL } - }; - - static PyObject * --WCharArray_get_value(CDataObject *self, void *Py_UNUSED(ignored)) -+WCharArray_get_value(PyObject *op, void *Py_UNUSED(ignored)) - { - Py_ssize_t i; -+ PyObject *res; -+ CDataObject *self = _CDataObject_CAST(op); - wchar_t *ptr = (wchar_t *)self->b_ptr; -+ LOCK_PTR(self); - for (i = 0; i < self->b_size/(Py_ssize_t)sizeof(wchar_t); ++i) - if (*ptr++ == (wchar_t)0) - break; -- return PyUnicode_FromWideChar((wchar_t *)self->b_ptr, i); -+ res = PyUnicode_FromWideChar((wchar_t *)self->b_ptr, i); -+ UNLOCK_PTR(self); -+ return res; - } - - static int --WCharArray_set_value(CDataObject *self, PyObject *value, void *Py_UNUSED(ignored)) -+WCharArray_set_value(PyObject *op, PyObject *value, void *Py_UNUSED(ignored)) - { -+ CDataObject *self = _CDataObject_CAST(op); -+ - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, - "can't delete attribute"); -@@ -1546,15 +1568,15 @@ - PyErr_SetString(PyExc_ValueError, "string too long"); - return -1; - } -- if (PyUnicode_AsWideChar(value, (wchar_t *)self->b_ptr, size) < 0) { -- return -1; -- } -- return 0; -+ Py_ssize_t rc; -+ LOCK_PTR(self); -+ rc = PyUnicode_AsWideChar(value, (wchar_t *)self->b_ptr, size); -+ UNLOCK_PTR(self); -+ return rc < 0 ? -1 : 0; - } - - static PyGetSetDef WCharArray_getsets[] = { -- { "value", (getter)WCharArray_get_value, (setter)WCharArray_set_value, -- "string value"}, -+ { "value", WCharArray_get_value, WCharArray_set_value, "string value" }, - { NULL, NULL } - }; - -@@ -1768,11 +1790,6 @@ - [clinic start generated code]*/ - /*[clinic end generated code: output=da39a3ee5e6b4b0d input=dd4d9646c56f43a9]*/ - --#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX) --static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdCEFfuzZqQPXOv?g"; --#else --static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdfuzZqQPXOv?g"; --#endif - - /*[clinic input] - _ctypes.c_wchar_p.from_param as c_wchar_p_from_param -@@ -1985,7 +2002,7 @@ - return NULL; - parg->pffi_type = &ffi_type_pointer; - parg->tag = 'P'; -- parg->obj = fd->setfunc(&parg->value, value, 0); -+ parg->obj = fd->setfunc(&parg->value, value, sizeof(void*)); - if (parg->obj == NULL) { - Py_DECREF(parg); - return NULL; -@@ -2059,6 +2076,7 @@ - parg->pffi_type = &ffi_type_pointer; - parg->tag = 'P'; - Py_INCREF(value); -+ // Function pointers don't change their contents, no need to lock - parg->value.p = *(void **)func->b_ptr; - parg->obj = value; - return (PyObject *)parg; -@@ -2085,7 +2103,7 @@ - parg->tag = 'Z'; - parg->obj = Py_NewRef(value); - /* Remember: b_ptr points to where the pointer is stored! */ -- parg->value.p = *(void **)(((CDataObject *)value)->b_ptr); -+ parg->value.p = locked_deref((CDataObject *)value); - return (PyObject *)parg; - } - } -@@ -2202,7 +2220,7 @@ - parg->tag = fmt[0]; - parg->pffi_type = fd->pffi_type; - parg->obj = Py_NewRef(self); -- memcpy(&parg->value, self->b_ptr, self->b_size); -+ locked_memcpy_from(&parg->value, self, self->b_size); - return parg; - } - -@@ -2243,17 +2261,13 @@ - "which must be a string of length 1"); - goto error; - } -- if (!strchr(SIMPLE_TYPE_CHARS, *proto_str)) { -+ 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 '%s'.", -- SIMPLE_TYPE_CHARS); -- goto error; -- } -- fmt = _ctypes_get_fielddesc(proto_str); -- if (fmt == NULL) { -- PyErr_Format(PyExc_ValueError, -- "_type_ '%s' not supported", proto_str); -+ "a single character string containing one of the\n" -+ "supported types: '%s'.", -+ _ctypes_get_simple_type_chars()); - goto error; - } - -@@ -2450,7 +2464,7 @@ - - parg->tag = fmt[0]; - parg->pffi_type = fd->pffi_type; -- parg->obj = fd->setfunc(&parg->value, value, 0); -+ parg->obj = fd->setfunc(&parg->value, value, info->size); - if (parg->obj) - return (PyObject *)parg; - PyObject *exc = PyErr_GetRaisedException(); -@@ -2627,7 +2641,7 @@ - stginfo->getfunc = NULL; - stginfo->ffi_type_pointer = ffi_type_pointer; - -- if (PyDict_GetItemRef((PyObject *)attrdict, &_Py_ID(_flags_), &ob) < 0) { -+ if (PyDict_GetItemRef(attrdict, &_Py_ID(_flags_), &ob) < 0) { - return -1; - } - if (!ob || !PyLong_Check(ob)) { -@@ -2640,7 +2654,7 @@ - Py_DECREF(ob); - - /* _argtypes_ is optional... */ -- if (PyDict_GetItemRef((PyObject *)attrdict, &_Py_ID(_argtypes_), &ob) < 0) { -+ if (PyDict_GetItemRef(attrdict, &_Py_ID(_argtypes_), &ob) < 0) { - return -1; - } - if (ob) { -@@ -2653,7 +2667,7 @@ - stginfo->converters = converters; - } - -- if (PyDict_GetItemRef((PyObject *)attrdict, &_Py_ID(_restype_), &ob) < 0) { -+ if (PyDict_GetItemRef(attrdict, &_Py_ID(_restype_), &ob) < 0) { - return -1; - } - if (ob) { -@@ -2675,7 +2689,7 @@ - } - } - /* XXX later, maybe. -- if (PyDict_GetItemRef((PyObject *)attrdict, &_Py _ID(_errcheck_), &ob) < 0) { -+ if (PyDict_GetItemRef(attrdict, &_Py _ID(_errcheck_), &ob) < 0) { - return -1; - } - if (ob) { -@@ -2703,7 +2717,7 @@ - parg->tag = 'P'; - parg->pffi_type = &ffi_type_pointer; - parg->obj = Py_NewRef(self); -- parg->value.p = *(void **)self->b_ptr; -+ parg->value.p = locked_deref(self); - return parg; - } - -@@ -2877,8 +2891,9 @@ - - - static int --PyCData_traverse(CDataObject *self, visitproc visit, void *arg) -+PyCData_traverse(PyObject *op, visitproc visit, void *arg) - { -+ CDataObject *self = _CDataObject_CAST(op); - Py_VISIT(self->b_objects); - Py_VISIT((PyObject *)self->b_base); - PyTypeObject *type = Py_TYPE(self); -@@ -2887,8 +2902,9 @@ - } - - static int --PyCData_clear(CDataObject *self) -+PyCData_clear(PyObject *op) - { -+ CDataObject *self = _CDataObject_CAST(op); - Py_CLEAR(self->b_objects); - if ((self->b_needsfree) - && _CDataObject_HasExternalBuffer(self)) -@@ -2903,7 +2919,7 @@ - { - PyTypeObject *type = Py_TYPE(self); - PyObject_GC_UnTrack(self); -- PyCData_clear((CDataObject *)self); -+ (void)PyCData_clear(self); - type->tp_free(self); - Py_DECREF(type); - } -@@ -2946,7 +2962,7 @@ - static int - PyCData_NewGetBuffer(PyObject *myself, Py_buffer *view, int flags) - { -- CDataObject *self = (CDataObject *)myself; -+ CDataObject *self = _CDataObject_CAST(myself); - - ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(myself))); - StgInfo *info; -@@ -3005,7 +3021,7 @@ - PyCData_reduce_impl(PyObject *myself, PyTypeObject *cls) - /*[clinic end generated code: output=1a025ccfdd8c935d input=34097a5226ea63c1]*/ - { -- CDataObject *self = (CDataObject *)myself; -+ CDataObject *self = _CDataObject_CAST(myself); - - ctypes_state *st = get_module_state_by_class(cls); - StgInfo *info; -@@ -3023,8 +3039,12 @@ - if (dict == NULL) { - return NULL; - } -+ PyObject *bytes; -+ LOCK_PTR(self); -+ bytes = PyBytes_FromStringAndSize(self->b_ptr, self->b_size); -+ UNLOCK_PTR(self); - return Py_BuildValue("O(O(NN))", st->_unpickle, Py_TYPE(myself), dict, -- PyBytes_FromStringAndSize(self->b_ptr, self->b_size)); -+ bytes); - } - - static PyObject * -@@ -3034,7 +3054,7 @@ - Py_ssize_t len; - int res; - PyObject *dict, *mydict; -- CDataObject *self = (CDataObject *)myself; -+ CDataObject *self = _CDataObject_CAST(myself); - if (!PyArg_ParseTuple(args, "O!s#", - &PyDict_Type, &dict, &data, &len)) - { -@@ -3042,7 +3062,10 @@ - } - if (len > self->b_size) - len = self->b_size; -+ // XXX Can we use locked_memcpy_to()? -+ LOCK_PTR(self); - memmove(self->b_ptr, data, len); -+ UNLOCK_PTR(self); - mydict = PyObject_GetAttrString(myself, "__dict__"); - if (mydict == NULL) { - return NULL; -@@ -3100,6 +3123,12 @@ - static int - PyCData_MallocBuffer(CDataObject *obj, StgInfo *info) - { -+ /* We don't have to lock in this function, because it's only -+ * used in constructors and therefore does not have concurrent -+ * access. -+ */ -+ assert (Py_REFCNT(obj) == 1); -+ - if ((size_t)info->size <= sizeof(obj->b_value)) { - /* No need to call malloc, can use the default buffer */ - obj->b_ptr = (char *)&obj->b_value; -@@ -3225,15 +3254,25 @@ - PyCData_get(ctypes_state *st, PyObject *type, GETFUNC getfunc, PyObject *src, - Py_ssize_t index, Py_ssize_t size, char *adr) - { -- if (getfunc) -- return getfunc(adr, size); -+ CDataObject *cdata = _CDataObject_CAST(src); -+ if (getfunc) { -+ PyObject *res; -+ LOCK_PTR(cdata); -+ res = getfunc(adr, size); -+ UNLOCK_PTR(cdata); -+ return res; -+ } - assert(type); - StgInfo *info; - if (PyStgInfo_FromType(st, type, &info) < 0) { - return NULL; - } - if (info && info->getfunc && !_ctypes_simple_instance(st, type)) { -- return info->getfunc(adr, size); -+ PyObject *res; -+ LOCK_PTR(cdata); -+ res = info->getfunc(adr, size); -+ UNLOCK_PTR(cdata); -+ return res; - } - return PyCData_FromBaseObj(st, type, src, index, adr); - } -@@ -3250,15 +3289,24 @@ - int err; - - if (setfunc) { -- return setfunc(ptr, value, size); -+ PyObject *res; -+ LOCK_PTR(dst); -+ res = setfunc(ptr, value, size); -+ UNLOCK_PTR(dst); -+ return res; - } - if (!CDataObject_Check(st, value)) { - StgInfo *info; - if (PyStgInfo_FromType(st, type, &info) < 0) { - return NULL; - } -- if (info && info->setfunc) -- return info->setfunc(ptr, value, size); -+ if (info && info->setfunc) { -+ PyObject *res; -+ LOCK_PTR(dst); -+ res = info->setfunc(ptr, value, size); -+ UNLOCK_PTR(dst); -+ return res; -+ } - /* - If value is a tuple, we try to call the type with the tuple - and use the result! -@@ -3278,7 +3326,9 @@ - Py_DECREF(ob); - return result; - } else if (value == Py_None && PyCPointerTypeObject_Check(st, type)) { -+ LOCK_PTR(dst); - *(void **)ptr = NULL; -+ UNLOCK_PTR(dst); - Py_RETURN_NONE; - } else { - PyErr_Format(PyExc_TypeError, -@@ -3294,9 +3344,7 @@ - if (err == -1) - return NULL; - if (err) { -- memcpy(ptr, -- src->b_ptr, -- size); -+ locked_memcpy_from(ptr, src, size); - - if (PyCPointerTypeObject_Check(st, type)) { - /* XXX */ -@@ -3330,7 +3378,9 @@ - ((PyTypeObject *)type)->tp_name); - return NULL; - } -+ LOCK_PTR(src); - *(void **)ptr = src->b_ptr; -+ UNLOCK_PTR(src); - - keep = GetKeepedObjects(src); - if (keep == NULL) -@@ -3429,21 +3479,37 @@ - PyCFuncPtr_Type - */ - -+/*[clinic input] -+@critical_section -+@setter -+_ctypes.CFuncPtr.errcheck -+[clinic start generated code]*/ -+ - static int --PyCFuncPtr_set_errcheck(PyCFuncPtrObject *self, PyObject *ob, void *Py_UNUSED(ignored)) -+_ctypes_CFuncPtr_errcheck_set_impl(PyCFuncPtrObject *self, PyObject *value) -+/*[clinic end generated code: output=6580cf1ffdf3b9fb input=84930bb16c490b33]*/ - { -- if (ob && !PyCallable_Check(ob)) { -+ if (value && !PyCallable_Check(value)) { - PyErr_SetString(PyExc_TypeError, - "the errcheck attribute must be callable"); - return -1; - } -- Py_XINCREF(ob); -- Py_XSETREF(self->errcheck, ob); -+ Py_XINCREF(value); -+ Py_XSETREF(self->errcheck, value); - return 0; - } - -+/*[clinic input] -+@critical_section -+@getter -+_ctypes.CFuncPtr.errcheck -+ -+a function to check for errors -+[clinic start generated code]*/ -+ - static PyObject * --PyCFuncPtr_get_errcheck(PyCFuncPtrObject *self, void *Py_UNUSED(ignored)) -+_ctypes_CFuncPtr_errcheck_get_impl(PyCFuncPtrObject *self) -+/*[clinic end generated code: output=dfa6fb5c6f90fd14 input=4672135fef37819f]*/ - { - if (self->errcheck) { - return Py_NewRef(self->errcheck); -@@ -3451,11 +3517,18 @@ - Py_RETURN_NONE; - } - -+/*[clinic input] -+@setter -+@critical_section -+_ctypes.CFuncPtr.restype -+[clinic start generated code]*/ -+ - static int --PyCFuncPtr_set_restype(PyCFuncPtrObject *self, PyObject *ob, void *Py_UNUSED(ignored)) -+_ctypes_CFuncPtr_restype_set_impl(PyCFuncPtrObject *self, PyObject *value) -+/*[clinic end generated code: output=0be0a086abbabf18 input=683c3bef4562ccc6]*/ - { - PyObject *checker, *oldchecker; -- if (ob == NULL) { -+ if (value == NULL) { - oldchecker = self->checker; - self->checker = NULL; - Py_CLEAR(self->restype); -@@ -3464,27 +3537,36 @@ - } - ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self))); - StgInfo *info; -- if (PyStgInfo_FromType(st, ob, &info) < 0) { -+ if (PyStgInfo_FromType(st, value, &info) < 0) { - return -1; - } -- if (ob != Py_None && !info && !PyCallable_Check(ob)) { -+ if (value != Py_None && !info && !PyCallable_Check(value)) { - PyErr_SetString(PyExc_TypeError, - "restype must be a type, a callable, or None"); - return -1; - } -- if (PyObject_GetOptionalAttr(ob, &_Py_ID(_check_retval_), &checker) < 0) { -+ if (PyObject_GetOptionalAttr(value, &_Py_ID(_check_retval_), &checker) < 0) { - return -1; - } - oldchecker = self->checker; - self->checker = checker; -- Py_INCREF(ob); -- Py_XSETREF(self->restype, ob); -+ Py_INCREF(value); -+ Py_XSETREF(self->restype, value); - Py_XDECREF(oldchecker); - return 0; - } - -+/*[clinic input] -+@getter -+@critical_section -+_ctypes.CFuncPtr.restype -+ -+specify the result type -+[clinic start generated code]*/ -+ - static PyObject * --PyCFuncPtr_get_restype(PyCFuncPtrObject *self, void *Py_UNUSED(ignored)) -+_ctypes_CFuncPtr_restype_get_impl(PyCFuncPtrObject *self) -+/*[clinic end generated code: output=c8f44cd16f1dee5e input=5e3ed95116204fd2]*/ - { - if (self->restype) { - return Py_NewRef(self->restype); -@@ -3502,28 +3584,44 @@ - } - } - -+/*[clinic input] -+@setter -+@critical_section -+_ctypes.CFuncPtr.argtypes -+[clinic start generated code]*/ -+ - static int --PyCFuncPtr_set_argtypes(PyCFuncPtrObject *self, PyObject *ob, void *Py_UNUSED(ignored)) -+_ctypes_CFuncPtr_argtypes_set_impl(PyCFuncPtrObject *self, PyObject *value) -+/*[clinic end generated code: output=596a36e2ae89d7d1 input=c4627573e980aa8b]*/ - { - PyObject *converters; - -- if (ob == NULL || ob == Py_None) { -+ if (value == NULL || value == Py_None) { - Py_CLEAR(self->converters); - Py_CLEAR(self->argtypes); - } else { - ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self))); -- converters = converters_from_argtypes(st, ob); -+ converters = converters_from_argtypes(st, value); - if (!converters) - return -1; - Py_XSETREF(self->converters, converters); -- Py_INCREF(ob); -- Py_XSETREF(self->argtypes, ob); -+ Py_INCREF(value); -+ Py_XSETREF(self->argtypes, value); - } - return 0; - } - -+/*[clinic input] -+@getter -+@critical_section -+_ctypes.CFuncPtr.argtypes -+ -+specify the argument types -+[clinic start generated code]*/ -+ - static PyObject * --PyCFuncPtr_get_argtypes(PyCFuncPtrObject *self, void *Py_UNUSED(ignored)) -+_ctypes_CFuncPtr_argtypes_get_impl(PyCFuncPtrObject *self) -+/*[clinic end generated code: output=c46b05a1b0f99172 input=37a8a545a56f8ae2]*/ - { - if (self->argtypes) { - return Py_NewRef(self->argtypes); -@@ -3542,13 +3640,9 @@ - } - - static PyGetSetDef PyCFuncPtr_getsets[] = { -- { "errcheck", (getter)PyCFuncPtr_get_errcheck, (setter)PyCFuncPtr_set_errcheck, -- "a function to check for errors", NULL }, -- { "restype", (getter)PyCFuncPtr_get_restype, (setter)PyCFuncPtr_set_restype, -- "specify the result type", NULL }, -- { "argtypes", (getter)PyCFuncPtr_get_argtypes, -- (setter)PyCFuncPtr_set_argtypes, -- "specify the argument types", NULL }, -+ _CTYPES_CFUNCPTR_ERRCHECK_GETSETDEF -+ _CTYPES_CFUNCPTR_RESTYPE_GETSETDEF -+ _CTYPES_CFUNCPTR_ARGTYPES_GETSETDEF - { NULL, NULL } - }; - -@@ -3825,21 +3919,14 @@ - address = (PPROC)dlsym(handle, name); - - if (!address) { -- #ifdef USE_DLERROR -+ #ifdef USE_DLERROR - const char *dlerr = dlerror(); - if (dlerr) { -- PyObject *message = PyUnicode_DecodeLocale(dlerr, "surrogateescape"); -- if (message) { -- PyErr_SetObject(PyExc_AttributeError, message); -- Py_DECREF(ftuple); -- Py_DECREF(message); -- return NULL; -- } -- // Ignore errors from PyUnicode_DecodeLocale, -- // fall back to the generic error below. -- PyErr_Clear(); -+ _PyErr_SetLocaleString(PyExc_AttributeError, dlerr); -+ Py_DECREF(ftuple); -+ return NULL; - } -- #endif -+ #endif - PyErr_Format(PyExc_AttributeError, "function '%s' not found", name); - Py_DECREF(ftuple); - return NULL; -@@ -3860,6 +3947,8 @@ - - self->paramflags = Py_XNewRef(paramflags); - -+ // No other threads can have this object, no need to -+ // lock it. - *(void **)self->b_ptr = address; - Py_INCREF(dll); - Py_DECREF(ftuple); -@@ -4318,7 +4407,7 @@ - } - - static PyObject * --PyCFuncPtr_call(PyCFuncPtrObject *self, PyObject *inargs, PyObject *kwds) -+PyCFuncPtr_call(PyObject *op, PyObject *inargs, PyObject *kwds) - { - PyObject *restype; - PyObject *converters; -@@ -4331,6 +4420,7 @@ - IUnknown *piunk = NULL; - #endif - void *pProc = NULL; -+ PyCFuncPtrObject *self = _PyCFuncPtrObject_CAST(op); - - int inoutmask; - int outmask; -@@ -4338,7 +4428,7 @@ - - ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self))); - StgInfo *info; -- if (PyStgInfo_FromObject(st, (PyObject *)self, &info) < 0) { -+ if (PyStgInfo_FromObject(st, op, &info) < 0) { - return NULL; - } - assert(info); /* Cannot be NULL for PyCFuncPtrObject instances */ -@@ -4456,8 +4546,9 @@ - } - - static int --PyCFuncPtr_traverse(PyCFuncPtrObject *self, visitproc visit, void *arg) -+PyCFuncPtr_traverse(PyObject *op, visitproc visit, void *arg) - { -+ PyCFuncPtrObject *self = _PyCFuncPtrObject_CAST(op); - Py_VISIT(self->callable); - Py_VISIT(self->restype); - Py_VISIT(self->checker); -@@ -4466,12 +4557,13 @@ - Py_VISIT(self->converters); - Py_VISIT(self->paramflags); - Py_VISIT(self->thunk); -- return PyCData_traverse((CDataObject *)self, visit, arg); -+ return PyCData_traverse(op, visit, arg); - } - - static int --PyCFuncPtr_clear(PyCFuncPtrObject *self) -+PyCFuncPtr_clear(PyObject *op) - { -+ PyCFuncPtrObject *self = _PyCFuncPtrObject_CAST(op); - Py_CLEAR(self->callable); - Py_CLEAR(self->restype); - Py_CLEAR(self->checker); -@@ -4480,22 +4572,23 @@ - Py_CLEAR(self->converters); - Py_CLEAR(self->paramflags); - Py_CLEAR(self->thunk); -- return PyCData_clear((CDataObject *)self); -+ return PyCData_clear(op); - } - - static void --PyCFuncPtr_dealloc(PyCFuncPtrObject *self) -+PyCFuncPtr_dealloc(PyObject *self) - { - PyObject_GC_UnTrack(self); -- PyCFuncPtr_clear(self); -+ (void)PyCFuncPtr_clear(self); - PyTypeObject *type = Py_TYPE(self); -- type->tp_free((PyObject *)self); -+ type->tp_free(self); - Py_DECREF(type); - } - - static PyObject * --PyCFuncPtr_repr(PyCFuncPtrObject *self) -+PyCFuncPtr_repr(PyObject *op) - { -+ PyCFuncPtrObject *self = _PyCFuncPtrObject_CAST(op); - #ifdef MS_WIN32 - if (self->index) - return PyUnicode_FromFormat("", -@@ -4509,8 +4602,9 @@ - } - - static int --PyCFuncPtr_bool(PyCFuncPtrObject *self) -+PyCFuncPtr_bool(PyObject *op) - { -+ PyCFuncPtrObject *self = _PyCFuncPtrObject_CAST(op); - return ((*(void **)self->b_ptr != NULL) - #ifdef MS_WIN32 - || (self->index != 0) -@@ -4698,7 +4792,7 @@ - PyCArray_Type - */ - static int --Array_init(CDataObject *self, PyObject *args, PyObject *kw) -+Array_init(PyObject *self, PyObject *args, PyObject *kw) - { - Py_ssize_t i; - Py_ssize_t n; -@@ -4712,7 +4806,7 @@ - for (i = 0; i < n; ++i) { - PyObject *v; - v = PyTuple_GET_ITEM(args, i); -- if (-1 == PySequence_SetItem((PyObject *)self, i, v)) -+ if (-1 == PySequence_SetItem(self, i, v)) - return -1; - } - return 0; -@@ -4721,7 +4815,7 @@ - static PyObject * - Array_item(PyObject *myself, Py_ssize_t index) - { -- CDataObject *self = (CDataObject *)myself; -+ CDataObject *self = _CDataObject_CAST(myself); - Py_ssize_t offset, size; - - if (index < 0 || index >= self->b_length) { -@@ -4732,7 +4826,7 @@ - - ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self))); - StgInfo *stginfo; -- if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) { -+ if (PyStgInfo_FromObject(st, myself, &stginfo) < 0) { - return NULL; - } - -@@ -4742,14 +4836,14 @@ - size = stginfo->size / stginfo->length; - offset = index * size; - -- return PyCData_get(st, stginfo->proto, stginfo->getfunc, (PyObject *)self, -- index, size, self->b_ptr + offset); -+ return PyCData_get(st, stginfo->proto, stginfo->getfunc, myself, -+ index, size, self->b_ptr + offset); - } - - static PyObject * - Array_subscript(PyObject *myself, PyObject *item) - { -- CDataObject *self = (CDataObject *)myself; -+ CDataObject *self = _CDataObject_CAST(myself); - - if (PyIndex_Check(item)) { - Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); -@@ -4773,7 +4867,7 @@ - - ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self))); - StgInfo *stginfo; -- if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) { -+ if (PyStgInfo_FromObject(st, myself, &stginfo) < 0) { - return NULL; - } - assert(stginfo); /* Cannot be NULL for array object instances */ -@@ -4792,18 +4886,24 @@ - if (slicelen <= 0) - return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); - if (step == 1) { -- return PyBytes_FromStringAndSize(ptr + start, -- slicelen); -+ PyObject *res; -+ LOCK_PTR(self); -+ res = PyBytes_FromStringAndSize(ptr + start, -+ slicelen); -+ UNLOCK_PTR(self); -+ return res; - } - dest = (char *)PyMem_Malloc(slicelen); - - if (dest == NULL) - return PyErr_NoMemory(); - -+ LOCK_PTR(self); - for (cur = start, i = 0; i < slicelen; - cur += step, i++) { - dest[i] = ptr[cur]; - } -+ UNLOCK_PTR(self); - - np = PyBytes_FromStringAndSize(dest, slicelen); - PyMem_Free(dest); -@@ -4816,8 +4916,12 @@ - if (slicelen <= 0) - return Py_GetConstant(Py_CONSTANT_EMPTY_STR); - if (step == 1) { -- return PyUnicode_FromWideChar(ptr + start, -- slicelen); -+ PyObject *res; -+ LOCK_PTR(self); -+ res = PyUnicode_FromWideChar(ptr + start, -+ slicelen); -+ UNLOCK_PTR(self); -+ return res; - } - - dest = PyMem_New(wchar_t, slicelen); -@@ -4826,10 +4930,12 @@ - return NULL; - } - -+ LOCK_PTR(self); - for (cur = start, i = 0; i < slicelen; - cur += step, i++) { - dest[i] = ptr[cur]; - } -+ UNLOCK_PTR(self); - - np = PyUnicode_FromWideChar(dest, slicelen); - PyMem_Free(dest); -@@ -4862,7 +4968,7 @@ - static int - Array_ass_item(PyObject *myself, Py_ssize_t index, PyObject *value) - { -- CDataObject *self = (CDataObject *)myself; -+ CDataObject *self = _CDataObject_CAST(myself); - Py_ssize_t size, offset; - char *ptr; - -@@ -4874,7 +4980,7 @@ - - ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self))); - StgInfo *stginfo; -- if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) { -+ if (PyStgInfo_FromObject(st, myself, &stginfo) < 0) { - return -1; - } - assert(stginfo); /* Cannot be NULL for array object instances */ -@@ -4888,14 +4994,14 @@ - offset = index * size; - ptr = self->b_ptr + offset; - -- return PyCData_set(st, (PyObject *)self, stginfo->proto, stginfo->setfunc, value, -- index, size, ptr); -+ return PyCData_set(st, myself, stginfo->proto, stginfo->setfunc, value, -+ index, size, ptr); - } - - static int - Array_ass_subscript(PyObject *myself, PyObject *item, PyObject *value) - { -- CDataObject *self = (CDataObject *)myself; -+ CDataObject *self = _CDataObject_CAST(myself); - - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, -@@ -4952,7 +5058,7 @@ - static Py_ssize_t - Array_length(PyObject *myself) - { -- CDataObject *self = (CDataObject *)myself; -+ CDataObject *self = _CDataObject_CAST(myself); - return self->b_length; - } - -@@ -5068,11 +5174,11 @@ - [clinic start generated code]*/ - /*[clinic end generated code: output=da39a3ee5e6b4b0d input=016c476c7aa8b8a8]*/ - -- - static int --Simple_set_value(CDataObject *self, PyObject *value, void *Py_UNUSED(ignored)) -+Simple_set_value(PyObject *op, PyObject *value, void *Py_UNUSED(ignored)) - { - PyObject *result; -+ CDataObject *self = _CDataObject_CAST(op); - - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, -@@ -5082,13 +5188,15 @@ - - ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self))); - StgInfo *info; -- if (PyStgInfo_FromObject(st, (PyObject *)self, &info) < 0) { -+ if (PyStgInfo_FromObject(st, op, &info) < 0) { - return -1; - } - assert(info); /* Cannot be NULL for CDataObject instances */ - assert(info->setfunc); - -+ LOCK_PTR(self); - result = info->setfunc(self->b_ptr, value, info->size); -+ UNLOCK_PTR(self); - if (!result) - return -1; - -@@ -5097,7 +5205,7 @@ - } - - static int --Simple_init(CDataObject *self, PyObject *args, PyObject *kw) -+Simple_init(PyObject *self, PyObject *args, PyObject *kw) - { - PyObject *value = NULL; - if (!PyArg_UnpackTuple(args, "__init__", 0, 1, &value)) -@@ -5108,20 +5216,25 @@ - } - - static PyObject * --Simple_get_value(CDataObject *self, void *Py_UNUSED(ignored)) -+Simple_get_value(PyObject *op, void *Py_UNUSED(ignored)) - { -+ CDataObject *self = _CDataObject_CAST(op); - ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self))); - StgInfo *info; -- if (PyStgInfo_FromObject(st, (PyObject *)self, &info) < 0) { -+ if (PyStgInfo_FromObject(st, op, &info) < 0) { - return NULL; - } - assert(info); /* Cannot be NULL for CDataObject instances */ - assert(info->getfunc); -- return info->getfunc(self->b_ptr, self->b_size); -+ PyObject *res; -+ LOCK_PTR(self); -+ res = info->getfunc(self->b_ptr, self->b_size); -+ UNLOCK_PTR(self); -+ return res; - } - - static PyGetSetDef Simple_getsets[] = { -- { "value", (getter)Simple_get_value, (setter)Simple_set_value, -+ { "value", Simple_get_value, Simple_set_value, - "current value", NULL }, - { NULL, NULL } - }; -@@ -5143,7 +5256,7 @@ - return Py_NewRef(self); - } - /* call stginfo->getfunc */ -- return Simple_get_value((CDataObject *)self, NULL); -+ return Simple_get_value(self, NULL); - } - - static PyMethodDef Simple_methods[] = { -@@ -5151,14 +5264,20 @@ - { NULL, NULL }, - }; - --static int Simple_bool(CDataObject *self) -+static int -+Simple_bool(PyObject *op) - { -- return memcmp(self->b_ptr, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", self->b_size); -+ int cmp; -+ CDataObject *self = _CDataObject_CAST(op); -+ LOCK_PTR(self); -+ cmp = memcmp(self->b_ptr, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", self->b_size); -+ UNLOCK_PTR(self); -+ return cmp; - } - - /* "%s(%s)" % (self.__class__.__name__, self.value) */ - static PyObject * --Simple_repr(CDataObject *self) -+Simple_repr(PyObject *self) - { - PyObject *val, *result; - ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self))); -@@ -5205,12 +5324,13 @@ - static PyObject * - Pointer_item(PyObject *myself, Py_ssize_t index) - { -- CDataObject *self = (CDataObject *)myself; -+ CDataObject *self = _CDataObject_CAST(myself); - Py_ssize_t size; - Py_ssize_t offset; - PyObject *proto; -+ void *deref = locked_deref(self); - -- if (*(void **)self->b_ptr == NULL) { -+ if (deref == NULL) { - PyErr_SetString(PyExc_ValueError, - "NULL pointer access"); - return NULL; -@@ -5218,7 +5338,7 @@ - - ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(myself))); - StgInfo *stginfo; -- if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) { -+ if (PyStgInfo_FromObject(st, myself, &stginfo) < 0) { - return NULL; - } - assert(stginfo); /* Cannot be NULL for pointer object instances */ -@@ -5236,14 +5356,14 @@ - size = iteminfo->size; - offset = index * iteminfo->size; - -- return PyCData_get(st, proto, stginfo->getfunc, (PyObject *)self, -- index, size, (*(char **)self->b_ptr) + offset); -+ return PyCData_get(st, proto, stginfo->getfunc, myself, -+ index, size, (char *)((char *)deref + offset)); - } - - static int - Pointer_ass_item(PyObject *myself, Py_ssize_t index, PyObject *value) - { -- CDataObject *self = (CDataObject *)myself; -+ CDataObject *self = _CDataObject_CAST(myself); - Py_ssize_t size; - Py_ssize_t offset; - PyObject *proto; -@@ -5254,7 +5374,8 @@ - return -1; - } - -- if (*(void **)self->b_ptr == NULL) { -+ void *deref = locked_deref(self); -+ if (deref == NULL) { - PyErr_SetString(PyExc_ValueError, - "NULL pointer access"); - return -1; -@@ -5262,7 +5383,7 @@ - - ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(myself))); - StgInfo *stginfo; -- if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) { -+ if (PyStgInfo_FromObject(st, myself, &stginfo) < 0) { - return -1; - } - assert(stginfo); /* Cannot be NULL for pointer instances */ -@@ -5280,14 +5401,15 @@ - size = iteminfo->size; - offset = index * iteminfo->size; - -- return PyCData_set(st, (PyObject *)self, proto, stginfo->setfunc, value, -- index, size, (*(char **)self->b_ptr) + offset); -+ return PyCData_set(st, myself, proto, stginfo->setfunc, value, -+ index, size, ((char *)deref + offset)); - } - - static PyObject * --Pointer_get_contents(CDataObject *self, void *closure) -+Pointer_get_contents(PyObject *self, void *closure) - { -- if (*(void **)self->b_ptr == NULL) { -+ void *deref = locked_deref(_CDataObject_CAST(self)); -+ if (deref == NULL) { - PyErr_SetString(PyExc_ValueError, - "NULL pointer access"); - return NULL; -@@ -5295,21 +5417,20 @@ - - ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self))); - StgInfo *stginfo; -- if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) { -+ if (PyStgInfo_FromObject(st, self, &stginfo) < 0) { - return NULL; - } - assert(stginfo); /* Cannot be NULL for pointer instances */ - -- return PyCData_FromBaseObj(st, stginfo->proto, -- (PyObject *)self, 0, -- *(void **)self->b_ptr); -+ return PyCData_FromBaseObj(st, stginfo->proto, self, 0, deref); - } - - static int --Pointer_set_contents(CDataObject *self, PyObject *value, void *closure) -+Pointer_set_contents(PyObject *op, PyObject *value, void *closure) - { - CDataObject *dst; - PyObject *keep; -+ CDataObject *self = _CDataObject_CAST(op); - - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, -@@ -5318,7 +5439,7 @@ - } - ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self))); - StgInfo *stginfo; -- if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) { -+ if (PyStgInfo_FromObject(st, op, &stginfo) < 0) { - return -1; - } - assert(stginfo); /* Cannot be NULL for pointer instances */ -@@ -5337,7 +5458,7 @@ - } - - dst = (CDataObject *)value; -- *(void **)self->b_ptr = dst->b_ptr; -+ locked_deref_assign(self, dst->b_ptr); - - /* - A Pointer instance must keep the value it points to alive. So, a -@@ -5357,17 +5478,15 @@ - } - - static PyGetSetDef Pointer_getsets[] = { -- { "contents", (getter)Pointer_get_contents, -- (setter)Pointer_set_contents, -+ { "contents", Pointer_get_contents, Pointer_set_contents, - "the object this pointer points to (read-write)", NULL }, - { NULL, NULL } - }; - - static int --Pointer_init(CDataObject *self, PyObject *args, PyObject *kw) -+Pointer_init(PyObject *self, PyObject *args, PyObject *kw) - { - PyObject *value = NULL; -- - if (!PyArg_UnpackTuple(args, "POINTER", 0, 1, &value)) - return -1; - if (value == NULL) -@@ -5394,7 +5513,7 @@ - static PyObject * - Pointer_subscript(PyObject *myself, PyObject *item) - { -- CDataObject *self = (CDataObject *)myself; -+ CDataObject *self = _CDataObject_CAST(myself); - if (PyIndex_Check(item)) { - Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); - if (i == -1 && PyErr_Occurred()) -@@ -5460,7 +5579,7 @@ - - ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(myself))); - StgInfo *stginfo; -- if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) { -+ if (PyStgInfo_FromObject(st, myself, &stginfo) < 0) { - return NULL; - } - assert(stginfo); /* Cannot be NULL for pointer instances */ -@@ -5472,41 +5591,53 @@ - } - assert(iteminfo); - if (iteminfo->getfunc == _ctypes_get_fielddesc("c")->getfunc) { -- char *ptr = *(char **)self->b_ptr; -+ char *ptr = locked_deref(self); - char *dest; - - if (len <= 0) - return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); - if (step == 1) { -- return PyBytes_FromStringAndSize(ptr + start, -- len); -+ PyObject *res; -+ LOCK_PTR(self); -+ res = PyBytes_FromStringAndSize(ptr + start, -+ len); -+ UNLOCK_PTR(self); -+ return res; - } - dest = (char *)PyMem_Malloc(len); - if (dest == NULL) - return PyErr_NoMemory(); -+ LOCK_PTR(self); - for (cur = start, i = 0; i < len; cur += step, i++) { - dest[i] = ptr[cur]; - } -+ UNLOCK_PTR(self); - np = PyBytes_FromStringAndSize(dest, len); - PyMem_Free(dest); - return np; - } - if (iteminfo->getfunc == _ctypes_get_fielddesc("u")->getfunc) { -- wchar_t *ptr = *(wchar_t **)self->b_ptr; -+ wchar_t *ptr = locked_deref(self); - wchar_t *dest; - - if (len <= 0) - return Py_GetConstant(Py_CONSTANT_EMPTY_STR); - if (step == 1) { -- return PyUnicode_FromWideChar(ptr + start, -- len); -+ PyObject *res; -+ LOCK_PTR(self); -+ res = PyUnicode_FromWideChar(ptr + start, -+ len); -+ UNLOCK_PTR(self); -+ return res; - } - dest = PyMem_New(wchar_t, len); - if (dest == NULL) - return PyErr_NoMemory(); -+ LOCK_PTR(self); - for (cur = start, i = 0; i < len; cur += step, i++) { - dest[i] = ptr[cur]; - } -+ UNLOCK_PTR(self); - np = PyUnicode_FromWideChar(dest, len); - PyMem_Free(dest); - return np; -@@ -5530,13 +5661,13 @@ - } - - static int --Pointer_bool(CDataObject *self) -+Pointer_bool(PyObject *self) - { -- return (*(void **)self->b_ptr != NULL); -+ return locked_deref(_CDataObject_CAST(self)) != NULL; - } - - static PyType_Slot pycpointer_slots[] = { -- {Py_tp_doc, PyDoc_STR("XXX to be provided")}, -+ {Py_tp_doc, (void *)PyDoc_STR("XXX to be provided")}, - {Py_tp_getset, Pointer_getsets}, - {Py_tp_init, Pointer_init}, - {Py_tp_new, Pointer_new}, -@@ -5740,7 +5871,7 @@ - } - } - /* Should we assert that result is a pointer type? */ -- memcpy(result->b_ptr, &ptr, sizeof(void *)); -+ locked_memcpy_to(result, &ptr, sizeof(void *)); - return (PyObject *)result; - - failed: -@@ -5761,6 +5892,22 @@ - return PyUnicode_FromWideChar(ptr, ssize); - } - -+static PyObject * -+memoryview_at(void *ptr, Py_ssize_t size, int readonly) -+{ -+ if (PySys_Audit("ctypes.memoryview_at", "nni", -+ (Py_ssize_t)ptr, size, readonly) < 0) { -+ return NULL; -+ } -+ if (size < 0) { -+ PyErr_Format(PyExc_ValueError, -+ "memoryview_at: size is negative (or overflowed): %zd", -+ size); -+ return NULL; -+ } -+ return PyMemoryView_FromMemory(ptr, size, -+ readonly ? PyBUF_READ : PyBUF_WRITE); -+} - - static int - _ctypes_add_types(PyObject *mod) -@@ -5889,6 +6036,7 @@ - MOD_ADD("_string_at_addr", PyLong_FromVoidPtr(string_at)); - MOD_ADD("_cast_addr", PyLong_FromVoidPtr(cast)); - MOD_ADD("_wstring_at_addr", PyLong_FromVoidPtr(wstring_at)); -+ MOD_ADD("_memoryview_at_addr", PyLong_FromVoidPtr(memoryview_at)); - - /* If RTLD_LOCAL is not defined (Windows!), set it to zero. */ - #if !HAVE_DECL_RTLD_LOCAL -diff --git a/Modules/_ctypes/_ctypes_test_generated.c.h b/Modules/_ctypes/_ctypes_test_generated.c.h -index 46a3e4b01e2..d70b33eaa8b 100644 ---- a/Modules/_ctypes/_ctypes_test_generated.c.h -+++ b/Modules/_ctypes/_ctypes_test_generated.c.h -@@ -56,7 +56,8 @@ - struct SingleInt { - int a; - }; -- struct SingleInt value = {0}; -+ struct SingleInt value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("SingleInt")); - APPEND(PyLong_FromLong(sizeof(struct SingleInt))); - APPEND(PyLong_FromLong(_Alignof(struct SingleInt))); -@@ -69,7 +70,8 @@ - union SingleInt_Union { - int a; - }; -- union SingleInt_Union value = {0}; -+ union SingleInt_Union value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("SingleInt_Union")); - APPEND(PyLong_FromLong(sizeof(union SingleInt_Union))); - APPEND(PyLong_FromLong(_Alignof(union SingleInt_Union))); -@@ -82,7 +84,8 @@ - struct SingleU32 { - uint32_t a; - }; -- struct SingleU32 value = {0}; -+ struct SingleU32 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("SingleU32")); - APPEND(PyLong_FromLong(sizeof(struct SingleU32))); - APPEND(PyLong_FromLong(_Alignof(struct SingleU32))); -@@ -97,7 +100,8 @@ - int8_t y; - uint16_t z; - }; -- struct SimpleStruct value = {0}; -+ struct SimpleStruct value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("SimpleStruct")); - APPEND(PyLong_FromLong(sizeof(struct SimpleStruct))); - APPEND(PyLong_FromLong(_Alignof(struct SimpleStruct))); -@@ -114,7 +118,8 @@ - int8_t y; - uint16_t z; - }; -- union SimpleUnion value = {0}; -+ union SimpleUnion value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("SimpleUnion")); - APPEND(PyLong_FromLong(sizeof(union SimpleUnion))); - APPEND(PyLong_FromLong(_Alignof(union SimpleUnion))); -@@ -136,7 +141,8 @@ - int64_t i64; - uint64_t u64; - }; -- struct ManyTypes value = {0}; -+ struct ManyTypes value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("ManyTypes")); - APPEND(PyLong_FromLong(sizeof(struct ManyTypes))); - APPEND(PyLong_FromLong(_Alignof(struct ManyTypes))); -@@ -163,7 +169,8 @@ - int64_t i64; - uint64_t u64; - }; -- union ManyTypesU value = {0}; -+ union ManyTypesU value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("ManyTypesU")); - APPEND(PyLong_FromLong(sizeof(union ManyTypesU))); - APPEND(PyLong_FromLong(_Alignof(union ManyTypesU))); -@@ -197,7 +204,8 @@ - uint16_t z; - }; - }; -- struct Nested value = {0}; -+ struct Nested value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Nested")); - APPEND(PyLong_FromLong(sizeof(struct Nested))); - APPEND(PyLong_FromLong(_Alignof(struct Nested))); -@@ -223,7 +231,8 @@ - int64_t b; - }; - #pragma pack(pop) -- struct Packed1 value = {0}; -+ struct Packed1 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Packed1")); - APPEND(PyLong_FromLong(sizeof(struct Packed1))); - APPEND(PyLong_FromLong(_Alignof(struct Packed1))); -@@ -247,7 +256,8 @@ - int64_t b; - }; - #pragma pack(pop) -- struct Packed2 value = {0}; -+ struct Packed2 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Packed2")); - APPEND(PyLong_FromLong(sizeof(struct Packed2))); - APPEND(PyLong_FromLong(_Alignof(struct Packed2))); -@@ -271,7 +281,8 @@ - int64_t b; - }; - #pragma pack(pop) -- struct Packed3 value = {0}; -+ struct Packed3 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Packed3")); - APPEND(PyLong_FromLong(sizeof(struct Packed3))); - APPEND(PyLong_FromLong(_Alignof(struct Packed3))); -@@ -295,7 +306,8 @@ - int64_t b; - }; - #pragma pack(pop) -- struct Packed4 value = {0}; -+ struct Packed4 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Packed4")); - APPEND(PyLong_FromLong(sizeof(struct Packed4))); - APPEND(PyLong_FromLong(_Alignof(struct Packed4))); -@@ -316,7 +328,8 @@ - int64_t b; - int32_t c; - }; -- struct X86_32EdgeCase value = {0}; -+ struct X86_32EdgeCase value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("X86_32EdgeCase")); - APPEND(PyLong_FromLong(sizeof(struct X86_32EdgeCase))); - APPEND(PyLong_FromLong(_Alignof(struct X86_32EdgeCase))); -@@ -333,7 +346,8 @@ - unsigned int b :5; - unsigned int c :7; - }; -- struct MSBitFieldExample value = {0}; -+ struct MSBitFieldExample value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("MSBitFieldExample")); - APPEND(PyLong_FromLong(sizeof(struct MSBitFieldExample))); - APPEND(PyLong_FromLong(_Alignof(struct MSBitFieldExample))); -@@ -351,7 +365,8 @@ - unsigned int may_straddle :30; - unsigned int last :18; - }; -- struct MSStraddlingExample value = {0}; -+ struct MSStraddlingExample value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("MSStraddlingExample")); - APPEND(PyLong_FromLong(sizeof(struct MSStraddlingExample))); - APPEND(PyLong_FromLong(_Alignof(struct MSStraddlingExample))); -@@ -375,7 +390,8 @@ - int H :8; - int I :9; - }; -- struct IntBits value = {0}; -+ struct IntBits value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("IntBits")); - APPEND(PyLong_FromLong(sizeof(struct IntBits))); - APPEND(PyLong_FromLong(_Alignof(struct IntBits))); -@@ -413,7 +429,8 @@ - short R :6; - short S :7; - }; -- struct Bits value = {0}; -+ struct Bits value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Bits")); - APPEND(PyLong_FromLong(sizeof(struct Bits))); - APPEND(PyLong_FromLong(_Alignof(struct Bits))); -@@ -456,7 +473,8 @@ - int H :8; - int I :9; - }; -- struct IntBits_MSVC value = {0}; -+ struct IntBits_MSVC value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("IntBits_MSVC")); - APPEND(PyLong_FromLong(sizeof(struct IntBits_MSVC))); - APPEND(PyLong_FromLong(_Alignof(struct IntBits_MSVC))); -@@ -499,7 +517,8 @@ - short R :6; - short S :7; - }; -- struct Bits_MSVC value = {0}; -+ struct Bits_MSVC value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Bits_MSVC")); - APPEND(PyLong_FromLong(sizeof(struct Bits_MSVC))); - APPEND(PyLong_FromLong(_Alignof(struct Bits_MSVC))); -@@ -536,7 +555,8 @@ - int64_t b :62; - int64_t c :1; - }; -- struct I64Bits value = {0}; -+ struct I64Bits value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("I64Bits")); - APPEND(PyLong_FromLong(sizeof(struct I64Bits))); - APPEND(PyLong_FromLong(_Alignof(struct I64Bits))); -@@ -560,7 +580,8 @@ - uint64_t b :62; - uint64_t c :1; - }; -- struct U64Bits value = {0}; -+ struct U64Bits value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("U64Bits")); - APPEND(PyLong_FromLong(sizeof(struct U64Bits))); - APPEND(PyLong_FromLong(_Alignof(struct U64Bits))); -@@ -584,7 +605,8 @@ - int8_t b :3; - int8_t c :1; - }; -- struct Struct331_8 value = {0}; -+ struct Struct331_8 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct331_8")); - APPEND(PyLong_FromLong(sizeof(struct Struct331_8))); - APPEND(PyLong_FromLong(_Alignof(struct Struct331_8))); -@@ -608,7 +630,8 @@ - int8_t b :6; - int8_t c :1; - }; -- struct Struct1x1_8 value = {0}; -+ struct Struct1x1_8 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct1x1_8")); - APPEND(PyLong_FromLong(sizeof(struct Struct1x1_8))); - APPEND(PyLong_FromLong(_Alignof(struct Struct1x1_8))); -@@ -633,7 +656,8 @@ - int8_t b :6; - int8_t c :1; - }; -- struct Struct1nx1_8 value = {0}; -+ struct Struct1nx1_8 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct1nx1_8")); - APPEND(PyLong_FromLong(sizeof(struct Struct1nx1_8))); - APPEND(PyLong_FromLong(_Alignof(struct Struct1nx1_8))); -@@ -658,7 +682,8 @@ - int8_t b :6; - int8_t c :6; - }; -- struct Struct3xx_8 value = {0}; -+ struct Struct3xx_8 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct3xx_8")); - APPEND(PyLong_FromLong(sizeof(struct Struct3xx_8))); - APPEND(PyLong_FromLong(_Alignof(struct Struct3xx_8))); -@@ -682,7 +707,8 @@ - uint8_t b :3; - uint8_t c :1; - }; -- struct Struct331_u8 value = {0}; -+ struct Struct331_u8 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct331_u8")); - APPEND(PyLong_FromLong(sizeof(struct Struct331_u8))); - APPEND(PyLong_FromLong(_Alignof(struct Struct331_u8))); -@@ -706,7 +732,8 @@ - uint8_t b :6; - uint8_t c :1; - }; -- struct Struct1x1_u8 value = {0}; -+ struct Struct1x1_u8 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct1x1_u8")); - APPEND(PyLong_FromLong(sizeof(struct Struct1x1_u8))); - APPEND(PyLong_FromLong(_Alignof(struct Struct1x1_u8))); -@@ -731,7 +758,8 @@ - uint8_t b :6; - uint8_t c :1; - }; -- struct Struct1nx1_u8 value = {0}; -+ struct Struct1nx1_u8 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct1nx1_u8")); - APPEND(PyLong_FromLong(sizeof(struct Struct1nx1_u8))); - APPEND(PyLong_FromLong(_Alignof(struct Struct1nx1_u8))); -@@ -756,7 +784,8 @@ - uint8_t b :6; - uint8_t c :6; - }; -- struct Struct3xx_u8 value = {0}; -+ struct Struct3xx_u8 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct3xx_u8")); - APPEND(PyLong_FromLong(sizeof(struct Struct3xx_u8))); - APPEND(PyLong_FromLong(_Alignof(struct Struct3xx_u8))); -@@ -780,7 +809,8 @@ - int16_t b :3; - int16_t c :1; - }; -- struct Struct331_16 value = {0}; -+ struct Struct331_16 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct331_16")); - APPEND(PyLong_FromLong(sizeof(struct Struct331_16))); - APPEND(PyLong_FromLong(_Alignof(struct Struct331_16))); -@@ -804,7 +834,8 @@ - int16_t b :14; - int16_t c :1; - }; -- struct Struct1x1_16 value = {0}; -+ struct Struct1x1_16 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct1x1_16")); - APPEND(PyLong_FromLong(sizeof(struct Struct1x1_16))); - APPEND(PyLong_FromLong(_Alignof(struct Struct1x1_16))); -@@ -829,7 +860,8 @@ - int16_t b :14; - int16_t c :1; - }; -- struct Struct1nx1_16 value = {0}; -+ struct Struct1nx1_16 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct1nx1_16")); - APPEND(PyLong_FromLong(sizeof(struct Struct1nx1_16))); - APPEND(PyLong_FromLong(_Alignof(struct Struct1nx1_16))); -@@ -854,7 +886,8 @@ - int16_t b :14; - int16_t c :14; - }; -- struct Struct3xx_16 value = {0}; -+ struct Struct3xx_16 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct3xx_16")); - APPEND(PyLong_FromLong(sizeof(struct Struct3xx_16))); - APPEND(PyLong_FromLong(_Alignof(struct Struct3xx_16))); -@@ -878,7 +911,8 @@ - uint16_t b :3; - uint16_t c :1; - }; -- struct Struct331_u16 value = {0}; -+ struct Struct331_u16 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct331_u16")); - APPEND(PyLong_FromLong(sizeof(struct Struct331_u16))); - APPEND(PyLong_FromLong(_Alignof(struct Struct331_u16))); -@@ -902,7 +936,8 @@ - uint16_t b :14; - uint16_t c :1; - }; -- struct Struct1x1_u16 value = {0}; -+ struct Struct1x1_u16 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct1x1_u16")); - APPEND(PyLong_FromLong(sizeof(struct Struct1x1_u16))); - APPEND(PyLong_FromLong(_Alignof(struct Struct1x1_u16))); -@@ -927,7 +962,8 @@ - uint16_t b :14; - uint16_t c :1; - }; -- struct Struct1nx1_u16 value = {0}; -+ struct Struct1nx1_u16 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct1nx1_u16")); - APPEND(PyLong_FromLong(sizeof(struct Struct1nx1_u16))); - APPEND(PyLong_FromLong(_Alignof(struct Struct1nx1_u16))); -@@ -952,7 +988,8 @@ - uint16_t b :14; - uint16_t c :14; - }; -- struct Struct3xx_u16 value = {0}; -+ struct Struct3xx_u16 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct3xx_u16")); - APPEND(PyLong_FromLong(sizeof(struct Struct3xx_u16))); - APPEND(PyLong_FromLong(_Alignof(struct Struct3xx_u16))); -@@ -976,7 +1013,8 @@ - int32_t b :3; - int32_t c :1; - }; -- struct Struct331_32 value = {0}; -+ struct Struct331_32 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct331_32")); - APPEND(PyLong_FromLong(sizeof(struct Struct331_32))); - APPEND(PyLong_FromLong(_Alignof(struct Struct331_32))); -@@ -1000,7 +1038,8 @@ - int32_t b :30; - int32_t c :1; - }; -- struct Struct1x1_32 value = {0}; -+ struct Struct1x1_32 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct1x1_32")); - APPEND(PyLong_FromLong(sizeof(struct Struct1x1_32))); - APPEND(PyLong_FromLong(_Alignof(struct Struct1x1_32))); -@@ -1025,7 +1064,8 @@ - int32_t b :30; - int32_t c :1; - }; -- struct Struct1nx1_32 value = {0}; -+ struct Struct1nx1_32 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct1nx1_32")); - APPEND(PyLong_FromLong(sizeof(struct Struct1nx1_32))); - APPEND(PyLong_FromLong(_Alignof(struct Struct1nx1_32))); -@@ -1050,7 +1090,8 @@ - int32_t b :30; - int32_t c :30; - }; -- struct Struct3xx_32 value = {0}; -+ struct Struct3xx_32 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct3xx_32")); - APPEND(PyLong_FromLong(sizeof(struct Struct3xx_32))); - APPEND(PyLong_FromLong(_Alignof(struct Struct3xx_32))); -@@ -1074,7 +1115,8 @@ - uint32_t b :3; - uint32_t c :1; - }; -- struct Struct331_u32 value = {0}; -+ struct Struct331_u32 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct331_u32")); - APPEND(PyLong_FromLong(sizeof(struct Struct331_u32))); - APPEND(PyLong_FromLong(_Alignof(struct Struct331_u32))); -@@ -1098,7 +1140,8 @@ - uint32_t b :30; - uint32_t c :1; - }; -- struct Struct1x1_u32 value = {0}; -+ struct Struct1x1_u32 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct1x1_u32")); - APPEND(PyLong_FromLong(sizeof(struct Struct1x1_u32))); - APPEND(PyLong_FromLong(_Alignof(struct Struct1x1_u32))); -@@ -1123,7 +1166,8 @@ - uint32_t b :30; - uint32_t c :1; - }; -- struct Struct1nx1_u32 value = {0}; -+ struct Struct1nx1_u32 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct1nx1_u32")); - APPEND(PyLong_FromLong(sizeof(struct Struct1nx1_u32))); - APPEND(PyLong_FromLong(_Alignof(struct Struct1nx1_u32))); -@@ -1148,7 +1192,8 @@ - uint32_t b :30; - uint32_t c :30; - }; -- struct Struct3xx_u32 value = {0}; -+ struct Struct3xx_u32 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct3xx_u32")); - APPEND(PyLong_FromLong(sizeof(struct Struct3xx_u32))); - APPEND(PyLong_FromLong(_Alignof(struct Struct3xx_u32))); -@@ -1172,7 +1217,8 @@ - int64_t b :3; - int64_t c :1; - }; -- struct Struct331_64 value = {0}; -+ struct Struct331_64 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct331_64")); - APPEND(PyLong_FromLong(sizeof(struct Struct331_64))); - APPEND(PyLong_FromLong(_Alignof(struct Struct331_64))); -@@ -1196,7 +1242,8 @@ - int64_t b :62; - int64_t c :1; - }; -- struct Struct1x1_64 value = {0}; -+ struct Struct1x1_64 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct1x1_64")); - APPEND(PyLong_FromLong(sizeof(struct Struct1x1_64))); - APPEND(PyLong_FromLong(_Alignof(struct Struct1x1_64))); -@@ -1221,7 +1268,8 @@ - int64_t b :62; - int64_t c :1; - }; -- struct Struct1nx1_64 value = {0}; -+ struct Struct1nx1_64 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct1nx1_64")); - APPEND(PyLong_FromLong(sizeof(struct Struct1nx1_64))); - APPEND(PyLong_FromLong(_Alignof(struct Struct1nx1_64))); -@@ -1246,7 +1294,8 @@ - int64_t b :62; - int64_t c :62; - }; -- struct Struct3xx_64 value = {0}; -+ struct Struct3xx_64 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct3xx_64")); - APPEND(PyLong_FromLong(sizeof(struct Struct3xx_64))); - APPEND(PyLong_FromLong(_Alignof(struct Struct3xx_64))); -@@ -1270,7 +1319,8 @@ - uint64_t b :3; - uint64_t c :1; - }; -- struct Struct331_u64 value = {0}; -+ struct Struct331_u64 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct331_u64")); - APPEND(PyLong_FromLong(sizeof(struct Struct331_u64))); - APPEND(PyLong_FromLong(_Alignof(struct Struct331_u64))); -@@ -1294,7 +1344,8 @@ - uint64_t b :62; - uint64_t c :1; - }; -- struct Struct1x1_u64 value = {0}; -+ struct Struct1x1_u64 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct1x1_u64")); - APPEND(PyLong_FromLong(sizeof(struct Struct1x1_u64))); - APPEND(PyLong_FromLong(_Alignof(struct Struct1x1_u64))); -@@ -1319,7 +1370,8 @@ - uint64_t b :62; - uint64_t c :1; - }; -- struct Struct1nx1_u64 value = {0}; -+ struct Struct1nx1_u64 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct1nx1_u64")); - APPEND(PyLong_FromLong(sizeof(struct Struct1nx1_u64))); - APPEND(PyLong_FromLong(_Alignof(struct Struct1nx1_u64))); -@@ -1344,7 +1396,8 @@ - uint64_t b :62; - uint64_t c :62; - }; -- struct Struct3xx_u64 value = {0}; -+ struct Struct3xx_u64 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Struct3xx_u64")); - APPEND(PyLong_FromLong(sizeof(struct Struct3xx_u64))); - APPEND(PyLong_FromLong(_Alignof(struct Struct3xx_u64))); -@@ -1367,7 +1420,8 @@ - signed char a :4; - int b :4; - }; -- struct Mixed1 value = {0}; -+ struct Mixed1 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Mixed1")); - APPEND(PyLong_FromLong(sizeof(struct Mixed1))); - APPEND(PyLong_FromLong(_Alignof(struct Mixed1))); -@@ -1389,7 +1443,8 @@ - signed char a :4; - int32_t b :32; - }; -- struct Mixed2 value = {0}; -+ struct Mixed2 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Mixed2")); - APPEND(PyLong_FromLong(sizeof(struct Mixed2))); - APPEND(PyLong_FromLong(_Alignof(struct Mixed2))); -@@ -1411,7 +1466,8 @@ - signed char a :4; - unsigned char b :4; - }; -- struct Mixed3 value = {0}; -+ struct Mixed3 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Mixed3")); - APPEND(PyLong_FromLong(sizeof(struct Mixed3))); - APPEND(PyLong_FromLong(_Alignof(struct Mixed3))); -@@ -1437,7 +1493,8 @@ - short e :4; - int f :24; - }; -- struct Mixed4 value = {0}; -+ struct Mixed4 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Mixed4")); - APPEND(PyLong_FromLong(sizeof(struct Mixed4))); - APPEND(PyLong_FromLong(_Alignof(struct Mixed4))); -@@ -1463,7 +1520,8 @@ - unsigned int A :1; - unsigned short B :16; - }; -- struct Mixed5 value = {0}; -+ struct Mixed5 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Mixed5")); - APPEND(PyLong_FromLong(sizeof(struct Mixed5))); - APPEND(PyLong_FromLong(_Alignof(struct Mixed5))); -@@ -1485,7 +1543,8 @@ - unsigned long long A :1; - unsigned int B :32; - }; -- struct Mixed6 value = {0}; -+ struct Mixed6 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Mixed6")); - APPEND(PyLong_FromLong(sizeof(struct Mixed6))); - APPEND(PyLong_FromLong(_Alignof(struct Mixed6))); -@@ -1508,7 +1567,8 @@ - uint32_t B :20; - uint64_t C :24; - }; -- struct Mixed7 value = {0}; -+ struct Mixed7 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Mixed7")); - APPEND(PyLong_FromLong(sizeof(struct Mixed7))); - APPEND(PyLong_FromLong(_Alignof(struct Mixed7))); -@@ -1532,7 +1592,8 @@ - uint32_t B :32; - unsigned long long C :1; - }; -- struct Mixed8_a value = {0}; -+ struct Mixed8_a value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Mixed8_a")); - APPEND(PyLong_FromLong(sizeof(struct Mixed8_a))); - APPEND(PyLong_FromLong(_Alignof(struct Mixed8_a))); -@@ -1556,7 +1617,8 @@ - uint32_t B; - unsigned long long C :1; - }; -- struct Mixed8_b value = {0}; -+ struct Mixed8_b value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Mixed8_b")); - APPEND(PyLong_FromLong(sizeof(struct Mixed8_b))); - APPEND(PyLong_FromLong(_Alignof(struct Mixed8_b))); -@@ -1579,7 +1641,8 @@ - uint8_t A; - uint32_t B :1; - }; -- struct Mixed9 value = {0}; -+ struct Mixed9 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Mixed9")); - APPEND(PyLong_FromLong(sizeof(struct Mixed9))); - APPEND(PyLong_FromLong(_Alignof(struct Mixed9))); -@@ -1601,7 +1664,8 @@ - uint32_t A :1; - uint64_t B :1; - }; -- struct Mixed10 value = {0}; -+ struct Mixed10 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Mixed10")); - APPEND(PyLong_FromLong(sizeof(struct Mixed10))); - APPEND(PyLong_FromLong(_Alignof(struct Mixed10))); -@@ -1623,7 +1687,8 @@ - uint32_t A :1; - uint64_t B :1; - }; -- struct Example_gh_95496 value = {0}; -+ struct Example_gh_95496 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Example_gh_95496")); - APPEND(PyLong_FromLong(sizeof(struct Example_gh_95496))); - APPEND(PyLong_FromLong(_Alignof(struct Example_gh_95496))); -@@ -1655,7 +1720,8 @@ - uint16_t b1 :12; - }; - #pragma pack(pop) -- struct Example_gh_84039_bad value = {0}; -+ struct Example_gh_84039_bad value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Example_gh_84039_bad")); - APPEND(PyLong_FromLong(sizeof(struct Example_gh_84039_bad))); - APPEND(PyLong_FromLong(_Alignof(struct Example_gh_84039_bad))); -@@ -1693,7 +1759,8 @@ - uint8_t a7 :1; - }; - #pragma pack(pop) -- struct Example_gh_84039_good_a value = {0}; -+ struct Example_gh_84039_good_a value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Example_gh_84039_good_a")); - APPEND(PyLong_FromLong(sizeof(struct Example_gh_84039_good_a))); - APPEND(PyLong_FromLong(_Alignof(struct Example_gh_84039_good_a))); -@@ -1735,7 +1802,8 @@ - uint16_t b1 :12; - }; - #pragma pack(pop) -- struct Example_gh_84039_good value = {0}; -+ struct Example_gh_84039_good value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Example_gh_84039_good")); - APPEND(PyLong_FromLong(sizeof(struct Example_gh_84039_good))); - APPEND(PyLong_FromLong(_Alignof(struct Example_gh_84039_good))); -@@ -1775,7 +1843,8 @@ - uint32_t R2 :2; - }; - #pragma pack(pop) -- struct Example_gh_73939 value = {0}; -+ struct Example_gh_73939 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Example_gh_73939")); - APPEND(PyLong_FromLong(sizeof(struct Example_gh_73939))); - APPEND(PyLong_FromLong(_Alignof(struct Example_gh_73939))); -@@ -1806,7 +1875,8 @@ - uint8_t b :8; - uint32_t c :16; - }; -- struct Example_gh_86098 value = {0}; -+ struct Example_gh_86098 value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Example_gh_86098")); - APPEND(PyLong_FromLong(sizeof(struct Example_gh_86098))); - APPEND(PyLong_FromLong(_Alignof(struct Example_gh_86098))); -@@ -1832,7 +1902,8 @@ - uint32_t c :16; - }; - #pragma pack(pop) -- struct Example_gh_86098_pack value = {0}; -+ struct Example_gh_86098_pack value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("Example_gh_86098_pack")); - APPEND(PyLong_FromLong(sizeof(struct Example_gh_86098_pack))); - APPEND(PyLong_FromLong(_Alignof(struct Example_gh_86098_pack))); -@@ -1858,7 +1929,8 @@ - }; - signed char y; - }; -- struct AnonBitfields value = {0}; -+ struct AnonBitfields value; -+ memset(&value, 0, sizeof(value)); - APPEND(PyUnicode_FromString("AnonBitfields")); - APPEND(PyLong_FromLong(sizeof(struct AnonBitfields))); - APPEND(PyLong_FromLong(_Alignof(struct AnonBitfields))); -diff --git a/Modules/_ctypes/callbacks.c b/Modules/_ctypes/callbacks.c -index 7b9f6437c7d..6dd6f6ec56d 100644 ---- a/Modules/_ctypes/callbacks.c -+++ b/Modules/_ctypes/callbacks.c -@@ -81,22 +81,6 @@ - - /**************************************************************/ - --static void --PrintError(const char *msg, ...) --{ -- char buf[512]; -- PyObject *f = PySys_GetObject("stderr"); -- va_list marker; -- -- va_start(marker, msg); -- PyOS_vsnprintf(buf, sizeof(buf), msg, marker); -- va_end(marker); -- if (f != NULL && f != Py_None) -- PyFile_WriteString(buf, f); -- PyErr_Print(); --} -- -- - #ifdef MS_WIN32 - /* - * We must call AddRef() on non-NULL COM pointers we receive as arguments -@@ -108,26 +92,23 @@ - * after checking for PyObject_IsTrue(), but this would probably be somewhat - * slower. - */ --static void -+static int - TryAddRef(PyObject *cnv, CDataObject *obj) - { - IUnknown *punk; - PyObject *attrdict = _PyType_GetDict((PyTypeObject *)cnv); - if (!attrdict) { -- return; -+ return 0; - } - int r = PyDict_Contains(attrdict, &_Py_ID(_needs_com_addref_)); - if (r <= 0) { -- if (r < 0) { -- PrintError("getting _needs_com_addref_"); -- } -- return; -+ return r; - } - - punk = *(IUnknown **)obj->b_ptr; - if (punk) - punk->lpVtbl->AddRef(punk); -- return; -+ return 0; - } - #endif - -@@ -162,14 +143,13 @@ - - StgInfo *info; - if (PyStgInfo_FromType(st, cnv, &info) < 0) { -- goto Done; -+ goto Error; - } - - if (info && info->getfunc && !_ctypes_simple_instance(st, cnv)) { - PyObject *v = info->getfunc(*pArgs, info->size); - if (!v) { -- PrintError("create argument %zd:\n", i); -- goto Done; -+ goto Error; - } - args[i] = v; - /* XXX XXX XX -@@ -182,24 +162,25 @@ - /* Hm, shouldn't we use PyCData_AtAddress() or something like that instead? */ - CDataObject *obj = (CDataObject *)_PyObject_CallNoArgs(cnv); - if (!obj) { -- PrintError("create argument %zd:\n", i); -- goto Done; -+ goto Error; - } - if (!CDataObject_Check(st, obj)) { -+ PyErr_Format(PyExc_TypeError, -+ "%R returned unexpected result of type %T", cnv, obj); - Py_DECREF(obj); -- PrintError("unexpected result of create argument %zd:\n", i); -- goto Done; -+ goto Error; - } - memcpy(obj->b_ptr, *pArgs, info->size); - args[i] = (PyObject *)obj; - #ifdef MS_WIN32 -- TryAddRef(cnv, obj); -+ if (TryAddRef(cnv, obj) < 0) { -+ goto Error; -+ } - #endif - } else { -- PyErr_SetString(PyExc_TypeError, -- "cannot build parameter"); -- PrintError("Parsing argument %zd\n", i); -- goto Done; -+ PyErr_Format(PyExc_TypeError, -+ "cannot build parameter of type %R", cnv); -+ goto Error; - } - /* XXX error handling! */ - pArgs++; -@@ -207,8 +188,13 @@ - - if (flags & (FUNCFLAG_USE_ERRNO | FUNCFLAG_USE_LASTERROR)) { - error_object = _ctypes_get_errobj(st, &space); -- if (error_object == NULL) -+ if (error_object == NULL) { -+ PyErr_FormatUnraisable( -+ "Exception ignored while setting error for " -+ "ctypes callback function %R", -+ callable); - goto Done; -+ } - if (flags & FUNCFLAG_USE_ERRNO) { - int temp = space[0]; - space[0] = errno; -@@ -225,9 +211,9 @@ - - result = PyObject_Vectorcall(callable, args, nargs, NULL); - if (result == NULL) { -- PyErr_FormatUnraisable( -- "Exception ignored on calling ctypes callback function %R", -- callable); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "calling ctypes callback function %R", -+ callable); - } - - #ifdef MS_WIN32 -@@ -264,12 +250,12 @@ - be the result. EXCEPT when restype is py_object - Python - itself knows how to manage the refcount of these objects. - */ -- PyObject *keep = setfunc(mem, result, 0); -+ PyObject *keep = setfunc(mem, result, restype->size); - - if (keep == NULL) { - /* Could not convert callback result. */ - PyErr_FormatUnraisable( -- "Exception ignored on converting result " -+ "Exception ignored while converting result " - "of ctypes callback function %R", - callable); - } -@@ -282,7 +268,7 @@ - "memory leak in callback function.", - 1) == -1) { - PyErr_FormatUnraisable( -- "Exception ignored on converting result " -+ "Exception ignored while converting result " - "of ctypes callback function %R", - callable); - } -@@ -295,6 +281,14 @@ - for (j = 0; j < i; j++) { - Py_DECREF(args[j]); - } -+ return; -+ -+ Error: -+ PyErr_FormatUnraisable( -+ "Exception ignored while creating argument %zd for " -+ "ctypes callback function %R", -+ i, callable); -+ goto Done; - } - - static void closure_fcn(ffi_cif *cif, -@@ -487,39 +481,31 @@ - { - PyObject *func, *result; - long retval; -- static PyObject *context; -- -- if (context == NULL) -- context = PyUnicode_InternFromString("_ctypes.DllGetClassObject"); - -- func = _PyImport_GetModuleAttrString("ctypes", "DllGetClassObject"); -+ func = PyImport_ImportModuleAttrString("ctypes", "DllGetClassObject"); - if (!func) { -- PyErr_WriteUnraisable(context ? context : Py_None); - /* There has been a warning before about this already */ -- return E_FAIL; -+ goto error; - } - - { - PyObject *py_rclsid = PyLong_FromVoidPtr((void *)rclsid); - if (py_rclsid == NULL) { - Py_DECREF(func); -- PyErr_WriteUnraisable(context ? context : Py_None); -- return E_FAIL; -+ goto error; - } - PyObject *py_riid = PyLong_FromVoidPtr((void *)riid); - if (py_riid == NULL) { - Py_DECREF(func); - Py_DECREF(py_rclsid); -- PyErr_WriteUnraisable(context ? context : Py_None); -- return E_FAIL; -+ goto error; - } - PyObject *py_ppv = PyLong_FromVoidPtr(ppv); - if (py_ppv == NULL) { - Py_DECREF(py_rclsid); - Py_DECREF(py_riid); - Py_DECREF(func); -- PyErr_WriteUnraisable(context ? context : Py_None); -- return E_FAIL; -+ goto error; - } - result = PyObject_CallFunctionObjArgs(func, - py_rclsid, -@@ -532,17 +518,21 @@ - } - Py_DECREF(func); - if (!result) { -- PyErr_WriteUnraisable(context ? context : Py_None); -- return E_FAIL; -+ goto error; - } - - retval = PyLong_AsLong(result); - if (PyErr_Occurred()) { -- PyErr_WriteUnraisable(context ? context : Py_None); -- retval = E_FAIL; -+ Py_DECREF(result); -+ goto error; - } - Py_DECREF(result); - return retval; -+ -+error: -+ PyErr_FormatUnraisable("Exception ignored while calling " -+ "ctypes.DllGetClassObject"); -+ return E_FAIL; - } - - STDAPI DllGetClassObject(REFCLSID rclsid, -@@ -561,43 +551,30 @@ - - long Call_CanUnloadNow(void) - { -- PyObject *mod, *func, *result; -- long retval; -- static PyObject *context; -- -- if (context == NULL) -- context = PyUnicode_InternFromString("_ctypes.DllCanUnloadNow"); -- -- mod = PyImport_ImportModule("ctypes"); -- if (!mod) { --/* OutputDebugString("Could not import ctypes"); */ -- /* We assume that this error can only occur when shutting -- down, so we silently ignore it */ -- PyErr_Clear(); -- return E_FAIL; -- } -- /* Other errors cannot be raised, but are printed to stderr */ -- func = PyObject_GetAttrString(mod, "DllCanUnloadNow"); -- Py_DECREF(mod); -+ PyObject *func = PyImport_ImportModuleAttrString("ctypes", -+ "DllCanUnloadNow"); - if (!func) { -- PyErr_WriteUnraisable(context ? context : Py_None); -- return E_FAIL; -+ goto error; - } - -- result = _PyObject_CallNoArgs(func); -+ PyObject *result = _PyObject_CallNoArgs(func); - Py_DECREF(func); - if (!result) { -- PyErr_WriteUnraisable(context ? context : Py_None); -- return E_FAIL; -+ goto error; - } - -- retval = PyLong_AsLong(result); -+ long retval = PyLong_AsLong(result); - if (PyErr_Occurred()) { -- PyErr_WriteUnraisable(context ? context : Py_None); -- retval = E_FAIL; -+ Py_DECREF(result); -+ goto error; - } - Py_DECREF(result); - return retval; -+ -+error: -+ PyErr_FormatUnraisable("Exception ignored while calling " -+ "ctypes.DllCanUnloadNow"); -+ return E_FAIL; - } - - /* -diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c -index 218c3a9c81e..c6b6460126c 100644 ---- a/Modules/_ctypes/callproc.c -+++ b/Modules/_ctypes/callproc.c -@@ -493,27 +493,29 @@ - } - - static int --PyCArg_traverse(PyCArgObject *self, visitproc visit, void *arg) -+PyCArg_traverse(PyObject *op, visitproc visit, void *arg) - { -+ PyCArgObject *self = _PyCArgObject_CAST(op); - Py_VISIT(Py_TYPE(self)); - Py_VISIT(self->obj); - return 0; - } - - static int --PyCArg_clear(PyCArgObject *self) -+PyCArg_clear(PyObject *op) - { -+ PyCArgObject *self = _PyCArgObject_CAST(op); - Py_CLEAR(self->obj); - return 0; - } - - static void --PyCArg_dealloc(PyCArgObject *self) -+PyCArg_dealloc(PyObject *self) - { - PyTypeObject *tp = Py_TYPE(self); - PyObject_GC_UnTrack(self); - (void)PyCArg_clear(self); -- tp->tp_free((PyObject *)self); -+ tp->tp_free(self); - Py_DECREF(tp); - } - -@@ -524,8 +526,9 @@ - } - - static PyObject * --PyCArg_repr(PyCArgObject *self) -+PyCArg_repr(PyObject *op) - { -+ PyCArgObject *self = _PyCArgObject_CAST(op); - switch(self->tag) { - case 'b': - case 'B': -@@ -1588,10 +1591,11 @@ - Py_XDECREF(name2); - if (!handle) { - const char *errmsg = dlerror(); -- if (!errmsg) -- errmsg = "dlopen() error"; -- PyErr_SetString(PyExc_OSError, -- errmsg); -+ if (errmsg) { -+ _PyErr_SetLocaleString(PyExc_OSError, errmsg); -+ return NULL; -+ } -+ PyErr_SetString(PyExc_OSError, "dlopen() error"); - return NULL; - } - return PyLong_FromVoidPtr(handle); -@@ -1604,8 +1608,12 @@ - if (!PyArg_ParseTuple(args, "O&:dlclose", &_parse_voidp, &handle)) - return NULL; - if (dlclose(handle)) { -- PyErr_SetString(PyExc_OSError, -- dlerror()); -+ const char *errmsg = dlerror(); -+ if (errmsg) { -+ _PyErr_SetLocaleString(PyExc_OSError, errmsg); -+ return NULL; -+ } -+ PyErr_SetString(PyExc_OSError, "dlclose() error"); - return NULL; - } - Py_RETURN_NONE; -@@ -1639,21 +1647,14 @@ - if (ptr) { - return PyLong_FromVoidPtr(ptr); - } -- #ifdef USE_DLERROR -- const char *dlerr = dlerror(); -- if (dlerr) { -- PyObject *message = PyUnicode_DecodeLocale(dlerr, "surrogateescape"); -- if (message) { -- PyErr_SetObject(PyExc_OSError, message); -- Py_DECREF(message); -- return NULL; -- } -- // Ignore errors from PyUnicode_DecodeLocale, -- // fall back to the generic error below. -- PyErr_Clear(); -+ #ifdef USE_DLERROR -+ const char *errmsg = dlerror(); -+ if (errmsg) { -+ _PyErr_SetLocaleString(PyExc_OSError, errmsg); -+ return NULL; - } -- #endif -- #undef USE_DLERROR -+ #endif -+ #undef USE_DLERROR - PyErr_Format(PyExc_OSError, "symbol '%s' not found", name); - return NULL; - } -diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c -index 2b9e8a1a10d..9924d62c088 100644 ---- a/Modules/_ctypes/cfield.c -+++ b/Modules/_ctypes/cfield.c -@@ -10,6 +10,7 @@ - - #include "pycore_bitutils.h" // _Py_bswap32() - #include "pycore_call.h" // _PyObject_CallNoArgs() -+#include // bool - - #include - #include "ctypes.h" -@@ -193,17 +194,18 @@ - - - static int --PyCField_set(CFieldObject *self, PyObject *inst, PyObject *value) -+PyCField_set(PyObject *op, PyObject *inst, PyObject *value) - { - CDataObject *dst; - char *ptr; -+ CFieldObject *self = _CFieldObject_CAST(op); - ctypes_state *st = get_module_state_by_class(Py_TYPE(self)); - if (!CDataObject_Check(st, inst)) { - PyErr_SetString(PyExc_TypeError, - "not a ctype instance"); - return -1; - } -- dst = (CDataObject *)inst; -+ dst = _CDataObject_CAST(inst); - ptr = dst->b_ptr + self->offset; - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, -@@ -211,13 +213,14 @@ - return -1; - } - return PyCData_set(st, inst, self->proto, self->setfunc, value, -- self->index, self->size, ptr); -+ self->index, self->size, ptr); - } - - static PyObject * --PyCField_get(CFieldObject *self, PyObject *inst, PyTypeObject *type) -+PyCField_get(PyObject *op, PyObject *inst, PyTypeObject *type) - { - CDataObject *src; -+ CFieldObject *self = _CFieldObject_CAST(op); - if (inst == NULL) { - return Py_NewRef(self); - } -@@ -227,21 +230,21 @@ - "not a ctype instance"); - return NULL; - } -- src = (CDataObject *)inst; -+ src = _CDataObject_CAST(inst); - return PyCData_get(st, self->proto, self->getfunc, inst, -- self->index, self->size, src->b_ptr + self->offset); -+ self->index, self->size, src->b_ptr + self->offset); - } - - static PyObject * - PyCField_get_offset(PyObject *self, void *data) - { -- return PyLong_FromSsize_t(((CFieldObject *)self)->offset); -+ return PyLong_FromSsize_t(_CFieldObject_CAST(self)->offset); - } - - static PyObject * - PyCField_get_size(PyObject *self, void *data) - { -- return PyLong_FromSsize_t(((CFieldObject *)self)->size); -+ return PyLong_FromSsize_t(_CFieldObject_CAST(self)->size); - } - - static PyGetSetDef PyCField_getset[] = { -@@ -251,17 +254,20 @@ - }; - - static int --PyCField_traverse(CFieldObject *self, visitproc visit, void *arg) -+PyCField_traverse(PyObject *op, visitproc visit, void *arg) - { -+ CFieldObject *self = _CFieldObject_CAST(op); - Py_VISIT(Py_TYPE(self)); - Py_VISIT(self->proto); - return 0; - } - - static int --PyCField_clear(CFieldObject *self) -+PyCField_clear(PyObject *op) - { -+ CFieldObject *self = _CFieldObject_CAST(op); - Py_CLEAR(self->proto); -+ Py_CLEAR(self->name); - return 0; - } - -@@ -270,17 +276,16 @@ - { - PyTypeObject *tp = Py_TYPE(self); - PyObject_GC_UnTrack(self); -- CFieldObject *self_cf = (CFieldObject *)self; -- (void)PyCField_clear(self_cf); -- Py_CLEAR(self_cf->name); -+ (void)PyCField_clear(self); - Py_TYPE(self)->tp_free(self); - Py_DECREF(tp); - } - - static PyObject * --PyCField_repr(CFieldObject *self) -+PyCField_repr(PyObject *op) - { - PyObject *result; -+ CFieldObject *self = _CFieldObject_CAST(op); - Py_ssize_t bits = NUM_BITS(self->size); - Py_ssize_t size = LOW_BIT(self->size); - const char *name; -@@ -320,61 +325,6 @@ - }; - - --/******************************************************************/ --/* -- Accessor functions --*/ -- --/* Derived from Modules/structmodule.c: -- Helper routine to get a Python integer and raise the appropriate error -- if it isn't one */ -- --static int --get_long(PyObject *v, long *p) --{ -- long x = PyLong_AsUnsignedLongMask(v); -- if (x == -1 && PyErr_Occurred()) -- return -1; -- *p = x; -- return 0; --} -- --/* Same, but handling unsigned long */ -- --static int --get_ulong(PyObject *v, unsigned long *p) --{ -- unsigned long x = PyLong_AsUnsignedLongMask(v); -- if (x == (unsigned long)-1 && PyErr_Occurred()) -- return -1; -- *p = x; -- return 0; --} -- --/* Same, but handling native long long. */ -- --static int --get_longlong(PyObject *v, long long *p) --{ -- long long x = PyLong_AsUnsignedLongLongMask(v); -- if (x == -1 && PyErr_Occurred()) -- return -1; -- *p = x; -- return 0; --} -- --/* Same, but handling native unsigned long long. */ -- --static int --get_ulonglong(PyObject *v, unsigned long long *p) --{ -- unsigned long long x = PyLong_AsUnsignedLongLongMask(v); -- if (x == (unsigned long long)-1 && PyErr_Occurred()) -- return -1; -- *p = x; -- return 0; --} -- - /***************************************************************** - * Integer fields, with bitfield support - */ -@@ -404,34 +354,8 @@ - /* This macro RETURNS the first parameter with the bit field CHANGED. */ - #define SET(type, x, v, size) \ - (NUM_BITS(size) ? \ -- ( ( (type)x & ~(BIT_MASK(type, size) << LOW_BIT(size)) ) | ( ((type)v & BIT_MASK(type, size)) << LOW_BIT(size) ) ) \ -- : (type)v) -- --#if SIZEOF_SHORT == 2 --# define SWAP_SHORT _Py_bswap16 --#else --# error "unsupported short size" --#endif -- --#if SIZEOF_INT == 4 --# define SWAP_INT _Py_bswap32 --#else --# error "unsupported int size" --#endif -- --#if SIZEOF_LONG == 4 --# define SWAP_LONG _Py_bswap32 --#elif SIZEOF_LONG == 8 --# define SWAP_LONG _Py_bswap64 --#else --# error "unsupported long size" --#endif -- --#if SIZEOF_LONG_LONG == 8 --# define SWAP_LONG_LONG _Py_bswap64 --#else --# error "unsupported long long size" --#endif -+ ( ( (type)(x) & ~(BIT_MASK(type, size) << LOW_BIT(size)) ) | ( ((type)(v) & BIT_MASK(type, size)) << LOW_BIT(size) ) ) \ -+ : (type)(v)) - - /***************************************************************** - * The setter methods return an object which must be kept alive, to keep the -@@ -454,203 +378,145 @@ - #endif - - /***************************************************************** -- * integer accessor methods, supporting bit fields -+ * accessor methods for fixed-width integers (e.g. int8_t, uint64_t), -+ * supporting bit fields. -+ * These are named e.g. `i8_set`/`i8_get` or `u64_set`/`u64_get`, -+ * and are all alike, so they're defined using a macro. - */ - --static PyObject * --b_set(void *ptr, PyObject *value, Py_ssize_t size) --{ -- long val; -- if (get_long(value, &val) < 0) -- return NULL; -- *(signed char *)ptr = SET(signed char, *(signed char *)ptr, val, size); -- _RET(value); --} -- -- --static PyObject * --b_get(void *ptr, Py_ssize_t size) --{ -- signed char val = *(signed char *)ptr; -- GET_BITFIELD(val, size); -- return PyLong_FromLong(val); --} -- --static PyObject * --B_set(void *ptr, PyObject *value, Py_ssize_t size) --{ -- unsigned long val; -- if (get_ulong(value, &val) < 0) -- return NULL; -- *(unsigned char *)ptr = SET(unsigned char, *(unsigned char*)ptr, val, size); -- _RET(value); --} -- -- --static PyObject * --B_get(void *ptr, Py_ssize_t size) --{ -- unsigned char val = *(unsigned char *)ptr; -- GET_BITFIELD(val, size); -- return PyLong_FromLong(val); --} -- --static PyObject * --h_set(void *ptr, PyObject *value, Py_ssize_t size) --{ -- long val; -- short x; -- if (get_long(value, &val) < 0) -- return NULL; -- memcpy(&x, ptr, sizeof(x)); -- x = SET(short, x, val, size); -- memcpy(ptr, &x, sizeof(x)); -- _RET(value); --} -- -- --static PyObject * --h_set_sw(void *ptr, PyObject *value, Py_ssize_t size) --{ -- long val; -- short field; -- if (get_long(value, &val) < 0) { -- return NULL; -- } -- memcpy(&field, ptr, sizeof(field)); -- field = SWAP_SHORT(field); -- field = SET(short, field, val, size); -- field = SWAP_SHORT(field); -- memcpy(ptr, &field, sizeof(field)); -- _RET(value); --} -- --static PyObject * --h_get(void *ptr, Py_ssize_t size) --{ -- short val; -- memcpy(&val, ptr, sizeof(val)); -- GET_BITFIELD(val, size); -- return PyLong_FromLong((long)val); --} -- --static PyObject * --h_get_sw(void *ptr, Py_ssize_t size) --{ -- short val; -- memcpy(&val, ptr, sizeof(val)); -- val = SWAP_SHORT(val); -- GET_BITFIELD(val, size); -- return PyLong_FromLong(val); --} -- --static PyObject * --H_set(void *ptr, PyObject *value, Py_ssize_t size) --{ -- unsigned long val; -- unsigned short x; -- if (get_ulong(value, &val) < 0) -- return NULL; -- memcpy(&x, ptr, sizeof(x)); -- x = SET(unsigned short, x, val, size); -- memcpy(ptr, &x, sizeof(x)); -- _RET(value); --} -- --static PyObject * --H_set_sw(void *ptr, PyObject *value, Py_ssize_t size) --{ -- unsigned long val; -- unsigned short field; -- if (get_ulong(value, &val) < 0) { -- return NULL; -- } -- memcpy(&field, ptr, sizeof(field)); -- field = SWAP_SHORT(field); -- field = SET(unsigned short, field, val, size); -- field = SWAP_SHORT(field); -- memcpy(ptr, &field, sizeof(field)); -- _RET(value); --} -- -- --static PyObject * --H_get(void *ptr, Py_ssize_t size) --{ -- unsigned short val; -- memcpy(&val, ptr, sizeof(val)); -- GET_BITFIELD(val, size); -- return PyLong_FromLong(val); --} -- --static PyObject * --H_get_sw(void *ptr, Py_ssize_t size) --{ -- unsigned short val; -- memcpy(&val, ptr, sizeof(val)); -- val = SWAP_SHORT(val); -- GET_BITFIELD(val, size); -- return PyLong_FromLong(val); --} -- --static PyObject * --i_set(void *ptr, PyObject *value, Py_ssize_t size) --{ -- long val; -- int x; -- if (get_long(value, &val) < 0) -- return NULL; -- memcpy(&x, ptr, sizeof(x)); -- x = SET(int, x, val, size); -- memcpy(ptr, &x, sizeof(x)); -- _RET(value); --} -- --static PyObject * --i_set_sw(void *ptr, PyObject *value, Py_ssize_t size) --{ -- long val; -- int field; -- if (get_long(value, &val) < 0) { -- return NULL; -- } -- memcpy(&field, ptr, sizeof(field)); -- field = SWAP_INT(field); -- field = SET(int, field, val, size); -- field = SWAP_INT(field); -- memcpy(ptr, &field, sizeof(field)); -- _RET(value); --} -- -+#define FIXINT_GETSET(TAG, CTYPE, NBITS, PYAPI_FROMFUNC) \ -+ static PyObject * \ -+ TAG ## _set(void *ptr, PyObject *value, Py_ssize_t size_arg) \ -+ { \ -+ assert(NUM_BITS(size_arg) || (size_arg == (NBITS) / 8)); \ -+ CTYPE val; \ -+ if (PyLong_Check(value) \ -+ && PyUnstable_Long_IsCompact((PyLongObject *)value)) \ -+ { \ -+ val = (CTYPE)PyUnstable_Long_CompactValue( \ -+ (PyLongObject *)value); \ -+ } \ -+ else { \ -+ Py_ssize_t res = PyLong_AsNativeBytes( \ -+ value, &val, (NBITS) / 8, \ -+ Py_ASNATIVEBYTES_NATIVE_ENDIAN \ -+ | Py_ASNATIVEBYTES_ALLOW_INDEX); \ -+ if (res < 0) { \ -+ return NULL; \ -+ } \ -+ } \ -+ CTYPE prev; \ -+ memcpy(&prev, ptr, (NBITS) / 8); \ -+ val = SET(CTYPE, prev, val, size_arg); \ -+ memcpy(ptr, &val, (NBITS) / 8); \ -+ _RET(value); \ -+ } \ -+ \ -+ static PyObject * \ -+ TAG ## _get(void *ptr, Py_ssize_t size_arg) \ -+ { \ -+ assert(NUM_BITS(size_arg) || (size_arg == (NBITS) / 8)); \ -+ CTYPE val; \ -+ memcpy(&val, ptr, sizeof(val)); \ -+ GET_BITFIELD(val, size_arg); \ -+ return PYAPI_FROMFUNC(val); \ -+ } \ -+ /////////////////////////////////////////////////////////////////////////// -+ -+/* Another macro for byte-swapped variants (e.g. `i8_set_sw`/`i8_get_sw`) */ -+ -+#define FIXINT_GETSET_SW(TAG, CTYPE, NBITS, PYAPI_FROMFUNC, PY_SWAPFUNC) \ -+ static PyObject * \ -+ TAG ## _set_sw(void *ptr, PyObject *value, Py_ssize_t size_arg) \ -+ { \ -+ CTYPE val; \ -+ PyObject *res = TAG ## _set(&val, value, (NBITS) / 8); \ -+ if (res == NULL) { \ -+ return NULL; \ -+ } \ -+ Py_DECREF(res); \ -+ CTYPE field; \ -+ memcpy(&field, ptr, sizeof(field)); \ -+ field = PY_SWAPFUNC(field); \ -+ field = SET(CTYPE, field, val, size_arg); \ -+ field = PY_SWAPFUNC(field); \ -+ memcpy(ptr, &field, sizeof(field)); \ -+ _RET(value); \ -+ } \ -+ \ -+ static PyObject * \ -+ TAG ## _get_sw(void *ptr, Py_ssize_t size_arg) \ -+ { \ -+ assert(NUM_BITS(size_arg) || (size_arg == (NBITS) / 8)); \ -+ CTYPE val; \ -+ memcpy(&val, ptr, sizeof(val)); \ -+ val = PY_SWAPFUNC(val); \ -+ GET_BITFIELD(val, size_arg); \ -+ return PYAPI_FROMFUNC(val); \ -+ } \ -+ /////////////////////////////////////////////////////////////////////////// -+ -+/* These macros are expanded for all supported combinations of byte sizes -+ * (1, 2, 4, 8), signed and unsigned, native and swapped byteorder. -+ * That's a lot, so generate the list with Argument Clinic (`make clinic`). -+ */ - --static PyObject * --i_get(void *ptr, Py_ssize_t size) --{ -- int val; -- memcpy(&val, ptr, sizeof(val)); -- GET_BITFIELD(val, size); -- return PyLong_FromLong(val); --} -+/*[python input] -+for nbits in 8, 16, 32, 64: -+ for sgn in 'i', 'u': -+ u = 'u' if sgn == 'u' else '' -+ U = u.upper() -+ apibits = max(nbits, 32) -+ parts = [ -+ f'{sgn}{nbits}', -+ f'{u}int{nbits}_t', -+ f'{nbits}', -+ f'PyLong_From{U}Int{apibits}', -+ ] -+ print(f'FIXINT_GETSET({", ".join(parts)})') -+ if nbits > 8: -+ parts.append(f'_Py_bswap{nbits}') -+ print(f'FIXINT_GETSET_SW({", ".join(parts)})') -+[python start generated code]*/ -+FIXINT_GETSET(i8, int8_t, 8, PyLong_FromInt32) -+FIXINT_GETSET(u8, uint8_t, 8, PyLong_FromUInt32) -+FIXINT_GETSET(i16, int16_t, 16, PyLong_FromInt32) -+FIXINT_GETSET_SW(i16, int16_t, 16, PyLong_FromInt32, _Py_bswap16) -+FIXINT_GETSET(u16, uint16_t, 16, PyLong_FromUInt32) -+FIXINT_GETSET_SW(u16, uint16_t, 16, PyLong_FromUInt32, _Py_bswap16) -+FIXINT_GETSET(i32, int32_t, 32, PyLong_FromInt32) -+FIXINT_GETSET_SW(i32, int32_t, 32, PyLong_FromInt32, _Py_bswap32) -+FIXINT_GETSET(u32, uint32_t, 32, PyLong_FromUInt32) -+FIXINT_GETSET_SW(u32, uint32_t, 32, PyLong_FromUInt32, _Py_bswap32) -+FIXINT_GETSET(i64, int64_t, 64, PyLong_FromInt64) -+FIXINT_GETSET_SW(i64, int64_t, 64, PyLong_FromInt64, _Py_bswap64) -+FIXINT_GETSET(u64, uint64_t, 64, PyLong_FromUInt64) -+FIXINT_GETSET_SW(u64, uint64_t, 64, PyLong_FromUInt64, _Py_bswap64) -+/*[python end generated code: output=3d60c96fa58e07d5 input=0b7e166f2ea18e70]*/ -+ -+// For one-byte types, swapped variants are the same as native -+#define i8_set_sw i8_set -+#define i8_get_sw i8_get -+#define u8_set_sw u8_set -+#define u8_get_sw u8_get -+ -+#undef FIXINT_GETSET -+#undef FIXINT_GETSET_SW - --static PyObject * --i_get_sw(void *ptr, Py_ssize_t size) --{ -- int val; -- memcpy(&val, ptr, sizeof(val)); -- val = SWAP_INT(val); -- GET_BITFIELD(val, size); -- return PyLong_FromLong(val); --} -+/***************************************************************** -+ * non-integer accessor methods, not supporting bit fields -+ */ - - #ifndef MS_WIN32 - /* http://msdn.microsoft.com/en-us/library/cc237864.aspx */ - #define VARIANT_FALSE 0x0000 - #define VARIANT_TRUE 0xFFFF - #endif --/* short BOOL - VARIANT_BOOL */ -+/* v: short BOOL - VARIANT_BOOL */ - static PyObject * --vBOOL_set(void *ptr, PyObject *value, Py_ssize_t size) -+v_set(void *ptr, PyObject *value, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(short int))); - switch (PyObject_IsTrue(value)) { - case -1: - return NULL; -@@ -664,22 +530,25 @@ - } - - static PyObject * --vBOOL_get(void *ptr, Py_ssize_t size) -+v_get(void *ptr, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(short int))); - return PyBool_FromLong((long)*(short int *)ptr); - } - -+/* bool ('?'): bool (i.e. _Bool) */ - static PyObject * - bool_set(void *ptr, PyObject *value, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(bool))); - switch (PyObject_IsTrue(value)) { - case -1: - return NULL; - case 0: -- *(_Bool *)ptr = 0; -+ *(bool *)ptr = 0; - _RET(value); - default: -- *(_Bool *)ptr = 1; -+ *(bool *)ptr = 1; - _RET(value); - } - } -@@ -687,260 +556,15 @@ - static PyObject * - bool_get(void *ptr, Py_ssize_t size) - { -- return PyBool_FromLong((long)*(_Bool *)ptr); --} -- --static PyObject * --I_set(void *ptr, PyObject *value, Py_ssize_t size) --{ -- unsigned long val; -- unsigned int x; -- if (get_ulong(value, &val) < 0) -- return NULL; -- memcpy(&x, ptr, sizeof(x)); -- x = SET(unsigned int, x, val, size); -- memcpy(ptr, &x, sizeof(x)); -- _RET(value); --} -- --static PyObject * --I_set_sw(void *ptr, PyObject *value, Py_ssize_t size) --{ -- unsigned long val; -- unsigned int field; -- if (get_ulong(value, &val) < 0) { -- return NULL; -- } -- memcpy(&field, ptr, sizeof(field)); -- field = SWAP_INT(field); -- field = SET(unsigned int, field, (unsigned int)val, size); -- field = SWAP_INT(field); -- memcpy(ptr, &field, sizeof(field)); -- _RET(value); -+ assert(NUM_BITS(size) || (size == sizeof(bool))); -+ return PyBool_FromLong((long)*(bool *)ptr); - } - -- --static PyObject * --I_get(void *ptr, Py_ssize_t size) --{ -- unsigned int val; -- memcpy(&val, ptr, sizeof(val)); -- GET_BITFIELD(val, size); -- return PyLong_FromUnsignedLong(val); --} -- --static PyObject * --I_get_sw(void *ptr, Py_ssize_t size) --{ -- unsigned int val; -- memcpy(&val, ptr, sizeof(val)); -- val = SWAP_INT(val); -- GET_BITFIELD(val, size); -- return PyLong_FromUnsignedLong(val); --} -- --static PyObject * --l_set(void *ptr, PyObject *value, Py_ssize_t size) --{ -- long val; -- long x; -- if (get_long(value, &val) < 0) -- return NULL; -- memcpy(&x, ptr, sizeof(x)); -- x = SET(long, x, val, size); -- memcpy(ptr, &x, sizeof(x)); -- _RET(value); --} -- --static PyObject * --l_set_sw(void *ptr, PyObject *value, Py_ssize_t size) --{ -- long val; -- long field; -- if (get_long(value, &val) < 0) { -- return NULL; -- } -- memcpy(&field, ptr, sizeof(field)); -- field = SWAP_LONG(field); -- field = SET(long, field, val, size); -- field = SWAP_LONG(field); -- memcpy(ptr, &field, sizeof(field)); -- _RET(value); --} -- -- --static PyObject * --l_get(void *ptr, Py_ssize_t size) --{ -- long val; -- memcpy(&val, ptr, sizeof(val)); -- GET_BITFIELD(val, size); -- return PyLong_FromLong(val); --} -- --static PyObject * --l_get_sw(void *ptr, Py_ssize_t size) --{ -- long val; -- memcpy(&val, ptr, sizeof(val)); -- val = SWAP_LONG(val); -- GET_BITFIELD(val, size); -- return PyLong_FromLong(val); --} -- --static PyObject * --L_set(void *ptr, PyObject *value, Py_ssize_t size) --{ -- unsigned long val; -- unsigned long x; -- if (get_ulong(value, &val) < 0) -- return NULL; -- memcpy(&x, ptr, sizeof(x)); -- x = SET(unsigned long, x, val, size); -- memcpy(ptr, &x, sizeof(x)); -- _RET(value); --} -- --static PyObject * --L_set_sw(void *ptr, PyObject *value, Py_ssize_t size) --{ -- unsigned long val; -- unsigned long field; -- if (get_ulong(value, &val) < 0) { -- return NULL; -- } -- memcpy(&field, ptr, sizeof(field)); -- field = SWAP_LONG(field); -- field = SET(unsigned long, field, val, size); -- field = SWAP_LONG(field); -- memcpy(ptr, &field, sizeof(field)); -- _RET(value); --} -- -- --static PyObject * --L_get(void *ptr, Py_ssize_t size) --{ -- unsigned long val; -- memcpy(&val, ptr, sizeof(val)); -- GET_BITFIELD(val, size); -- return PyLong_FromUnsignedLong(val); --} -- --static PyObject * --L_get_sw(void *ptr, Py_ssize_t size) --{ -- unsigned long val; -- memcpy(&val, ptr, sizeof(val)); -- val = SWAP_LONG(val); -- GET_BITFIELD(val, size); -- return PyLong_FromUnsignedLong(val); --} -- --static PyObject * --q_set(void *ptr, PyObject *value, Py_ssize_t size) --{ -- long long val; -- long long x; -- if (get_longlong(value, &val) < 0) -- return NULL; -- memcpy(&x, ptr, sizeof(x)); -- x = SET(long long, x, val, size); -- memcpy(ptr, &x, sizeof(x)); -- _RET(value); --} -- --static PyObject * --q_set_sw(void *ptr, PyObject *value, Py_ssize_t size) --{ -- long long val; -- long long field; -- if (get_longlong(value, &val) < 0) { -- return NULL; -- } -- memcpy(&field, ptr, sizeof(field)); -- field = SWAP_LONG_LONG(field); -- field = SET(long long, field, val, size); -- field = SWAP_LONG_LONG(field); -- memcpy(ptr, &field, sizeof(field)); -- _RET(value); --} -- --static PyObject * --q_get(void *ptr, Py_ssize_t size) --{ -- long long val; -- memcpy(&val, ptr, sizeof(val)); -- GET_BITFIELD(val, size); -- return PyLong_FromLongLong(val); --} -- --static PyObject * --q_get_sw(void *ptr, Py_ssize_t size) --{ -- long long val; -- memcpy(&val, ptr, sizeof(val)); -- val = SWAP_LONG_LONG(val); -- GET_BITFIELD(val, size); -- return PyLong_FromLongLong(val); --} -- --static PyObject * --Q_set(void *ptr, PyObject *value, Py_ssize_t size) --{ -- unsigned long long val; -- unsigned long long x; -- if (get_ulonglong(value, &val) < 0) -- return NULL; -- memcpy(&x, ptr, sizeof(x)); -- x = SET(long long, x, val, size); -- memcpy(ptr, &x, sizeof(x)); -- _RET(value); --} -- --static PyObject * --Q_set_sw(void *ptr, PyObject *value, Py_ssize_t size) --{ -- unsigned long long val; -- unsigned long long field; -- if (get_ulonglong(value, &val) < 0) { -- return NULL; -- } -- memcpy(&field, ptr, sizeof(field)); -- field = SWAP_LONG_LONG(field); -- field = SET(unsigned long long, field, val, size); -- field = SWAP_LONG_LONG(field); -- memcpy(ptr, &field, sizeof(field)); -- _RET(value); --} -- --static PyObject * --Q_get(void *ptr, Py_ssize_t size) --{ -- unsigned long long val; -- memcpy(&val, ptr, sizeof(val)); -- GET_BITFIELD(val, size); -- return PyLong_FromUnsignedLongLong(val); --} -- --static PyObject * --Q_get_sw(void *ptr, Py_ssize_t size) --{ -- unsigned long long val; -- memcpy(&val, ptr, sizeof(val)); -- val = SWAP_LONG_LONG(val); -- GET_BITFIELD(val, size); -- return PyLong_FromUnsignedLongLong(val); --} -- --/***************************************************************** -- * non-integer accessor methods, not supporting bit fields -- */ -- -- -+/* g: long double */ - static PyObject * - g_set(void *ptr, PyObject *value, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(long double))); - long double x; - - x = PyFloat_AsDouble(value); -@@ -953,14 +577,17 @@ - static PyObject * - g_get(void *ptr, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(long double))); - long double val; - memcpy(&val, ptr, sizeof(long double)); - return PyFloat_FromDouble(val); - } - -+/* d: double */ - static PyObject * - d_set(void *ptr, PyObject *value, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(double))); - double x; - - x = PyFloat_AsDouble(value); -@@ -973,15 +600,18 @@ - static PyObject * - d_get(void *ptr, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(double))); - double val; - memcpy(&val, ptr, sizeof(val)); - return PyFloat_FromDouble(val); - } - - #if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX) -+/* C: double complex */ - static PyObject * - C_set(void *ptr, PyObject *value, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(double complex))); - Py_complex c = PyComplex_AsCComplex(value); - - if (c.real == -1 && PyErr_Occurred()) { -@@ -995,15 +625,18 @@ - static PyObject * - C_get(void *ptr, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(double complex))); - double complex x; - - memcpy(&x, ptr, sizeof(x)); - return PyComplex_FromDoubles(creal(x), cimag(x)); - } - -+/* E: float complex */ - static PyObject * - E_set(void *ptr, PyObject *value, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(float complex))); - Py_complex c = PyComplex_AsCComplex(value); - - if (c.real == -1 && PyErr_Occurred()) { -@@ -1017,15 +650,18 @@ - static PyObject * - E_get(void *ptr, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(float complex))); - float complex x; - - memcpy(&x, ptr, sizeof(x)); - return PyComplex_FromDoubles(crealf(x), cimagf(x)); - } - -+/* F: long double complex */ - static PyObject * - F_set(void *ptr, PyObject *value, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(long double complex))); - Py_complex c = PyComplex_AsCComplex(value); - - if (c.real == -1 && PyErr_Occurred()) { -@@ -1039,6 +675,7 @@ - static PyObject * - F_get(void *ptr, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(long double complex))); - long double complex x; - - memcpy(&x, ptr, sizeof(x)); -@@ -1046,9 +683,11 @@ - } - #endif - -+/* d: double */ - static PyObject * - d_set_sw(void *ptr, PyObject *value, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(double))); - double x; - - x = PyFloat_AsDouble(value); -@@ -1067,6 +706,7 @@ - static PyObject * - d_get_sw(void *ptr, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(double))); - #ifdef WORDS_BIGENDIAN - return PyFloat_FromDouble(PyFloat_Unpack8(ptr, 1)); - #else -@@ -1074,9 +714,11 @@ - #endif - } - -+/* f: float */ - static PyObject * - f_set(void *ptr, PyObject *value, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(float))); - float x; - - x = (float)PyFloat_AsDouble(value); -@@ -1089,6 +731,7 @@ - static PyObject * - f_get(void *ptr, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(float))); - float val; - memcpy(&val, ptr, sizeof(val)); - return PyFloat_FromDouble(val); -@@ -1097,6 +740,7 @@ - static PyObject * - f_set_sw(void *ptr, PyObject *value, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(float))); - float x; - - x = (float)PyFloat_AsDouble(value); -@@ -1115,6 +759,7 @@ - static PyObject * - f_get_sw(void *ptr, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(float))); - #ifdef WORDS_BIGENDIAN - return PyFloat_FromDouble(PyFloat_Unpack4(ptr, 1)); - #else -@@ -1122,6 +767,7 @@ - #endif - } - -+/* O: Python object */ - /* - py_object refcounts: - -@@ -1135,6 +781,7 @@ - static PyObject * - O_get(void *ptr, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(PyObject *))); - PyObject *ob = *(PyObject **)ptr; - if (ob == NULL) { - if (!PyErr_Occurred()) -@@ -1149,15 +796,18 @@ - static PyObject * - O_set(void *ptr, PyObject *value, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(PyObject *))); - /* Hm, does the memory block need it's own refcount or not? */ - *(PyObject **)ptr = value; - return Py_NewRef(value); - } - - -+/* c: a single byte-character */ - static PyObject * - c_set(void *ptr, PyObject *value, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(char))); - if (PyBytes_Check(value)) { - if (PyBytes_GET_SIZE(value) != 1) { - PyErr_Format(PyExc_TypeError, -@@ -1204,13 +854,15 @@ - static PyObject * - c_get(void *ptr, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(char))); - return PyBytes_FromStringAndSize((char *)ptr, 1); - } - --/* u - a single wchar_t character */ -+/* u: a single wchar_t character */ - static PyObject * - u_set(void *ptr, PyObject *value, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(wchar_t))); - Py_ssize_t len; - wchar_t chars[2]; - if (!PyUnicode_Check(value)) { -@@ -1244,10 +896,11 @@ - static PyObject * - u_get(void *ptr, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(wchar_t))); - return PyUnicode_FromWideChar((wchar_t *)ptr, 1); - } - --/* U - a unicode string */ -+/* U: a wchar_t* unicode string */ - static PyObject * - U_get(void *ptr, Py_ssize_t size) - { -@@ -1306,6 +959,7 @@ - } - - -+/* s: a byte string */ - static PyObject * - s_get(void *ptr, Py_ssize_t size) - { -@@ -1355,6 +1009,7 @@ - _RET(value); - } - -+/* z: a byte string, can be set from integer pointer */ - static PyObject * - z_set(void *ptr, PyObject *value, Py_ssize_t size) - { -@@ -1391,6 +1046,7 @@ - } - } - -+/* Z: a wchar* string, can be set from integer pointer */ - static PyObject * - Z_set(void *ptr, PyObject *value, Py_ssize_t size) - { -@@ -1445,8 +1101,9 @@ - - - #ifdef MS_WIN32 -+/* X: COM BSTR (wide-char string to be handled handled using Windows API) */ - static PyObject * --BSTR_set(void *ptr, PyObject *value, Py_ssize_t size) -+X_set(void *ptr, PyObject *value, Py_ssize_t size) - { - BSTR bstr; - -@@ -1490,7 +1147,7 @@ - - - static PyObject * --BSTR_get(void *ptr, Py_ssize_t size) -+X_get(void *ptr, Py_ssize_t size) - { - BSTR p; - p = *(BSTR *)ptr; -@@ -1505,9 +1162,11 @@ - } - #endif - -+/* P: generic pointer */ - static PyObject * - P_set(void *ptr, PyObject *value, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(void *))); - void *v; - if (value == Py_None) { - *(void **)ptr = NULL; -@@ -1539,154 +1198,399 @@ - static PyObject * - P_get(void *ptr, Py_ssize_t size) - { -+ assert(NUM_BITS(size) || (size == sizeof(void *))); - if (*(void **)ptr == NULL) { - Py_RETURN_NONE; - } - return PyLong_FromVoidPtr(*(void **)ptr); - } - --static struct fielddesc formattable[] = { -- { 's', s_set, s_get, NULL}, -- { 'b', b_set, b_get, NULL}, -- { 'B', B_set, B_get, NULL}, -- { 'c', c_set, c_get, NULL}, -- { 'd', d_set, d_get, NULL, d_set_sw, d_get_sw}, --#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX) -- { 'C', C_set, C_get, NULL}, -- { 'E', E_set, E_get, NULL}, -- { 'F', F_set, F_get, NULL}, --#endif -- { 'g', g_set, g_get, NULL}, -- { 'f', f_set, f_get, NULL, f_set_sw, f_get_sw}, -- { 'h', h_set, h_get, NULL, h_set_sw, h_get_sw}, -- { 'H', H_set, H_get, NULL, H_set_sw, H_get_sw}, -- { 'i', i_set, i_get, NULL, i_set_sw, i_get_sw}, -- { 'I', I_set, I_get, NULL, I_set_sw, I_get_sw}, -- { 'l', l_set, l_get, NULL, l_set_sw, l_get_sw}, -- { 'L', L_set, L_get, NULL, L_set_sw, L_get_sw}, -- { 'q', q_set, q_get, NULL, q_set_sw, q_get_sw}, -- { 'Q', Q_set, Q_get, NULL, Q_set_sw, Q_get_sw}, -- { 'P', P_set, P_get, NULL}, -- { 'z', z_set, z_get, NULL}, -- { 'u', u_set, u_get, NULL}, -- { 'U', U_set, U_get, NULL}, -- { 'Z', Z_set, Z_get, NULL}, --#ifdef MS_WIN32 -- { 'X', BSTR_set, BSTR_get, NULL}, --#endif -- { 'v', vBOOL_set, vBOOL_get, NULL}, --#if SIZEOF__BOOL == SIZEOF_INT -- { '?', bool_set, bool_get, NULL, I_set_sw, I_get_sw}, --#elif SIZEOF__BOOL == SIZEOF_LONG -- { '?', bool_set, bool_get, NULL, L_set_sw, L_get_sw}, --#elif SIZEOF__BOOL == SIZEOF_LONG_LONG -- { '?', bool_set, bool_get, NULL, Q_set_sw, Q_get_sw}, --#else -- { '?', bool_set, bool_get, NULL}, --#endif /* SIZEOF__BOOL */ -- { 'O', O_set, O_get, NULL}, -- { 0, NULL, NULL, NULL}, -+/* Table with info about all formats. -+ * Must be accessed via _ctypes_get_fielddesc, which initializes it on -+ * first use. After initialization it's treated as constant & read-only. -+ */ -+ -+struct formattable { -+/*[python input] -+for nbytes in 8, 16, 32, 64: -+ for sgn in 'i', 'u': -+ print(f' struct fielddesc fmt_{sgn}{nbytes};') -+for code in 'sbBcdCEFgfhHiIlLqQPzuUZXvO': -+ print(f' struct fielddesc fmt_{code};') -+[python start generated code]*/ -+ struct fielddesc fmt_i8; -+ struct fielddesc fmt_u8; -+ struct fielddesc fmt_i16; -+ struct fielddesc fmt_u16; -+ struct fielddesc fmt_i32; -+ struct fielddesc fmt_u32; -+ struct fielddesc fmt_i64; -+ struct fielddesc fmt_u64; -+ struct fielddesc fmt_s; -+ struct fielddesc fmt_b; -+ struct fielddesc fmt_B; -+ struct fielddesc fmt_c; -+ struct fielddesc fmt_d; -+ struct fielddesc fmt_C; -+ struct fielddesc fmt_E; -+ struct fielddesc fmt_F; -+ struct fielddesc fmt_g; -+ struct fielddesc fmt_f; -+ struct fielddesc fmt_h; -+ struct fielddesc fmt_H; -+ struct fielddesc fmt_i; -+ struct fielddesc fmt_I; -+ struct fielddesc fmt_l; -+ struct fielddesc fmt_L; -+ struct fielddesc fmt_q; -+ struct fielddesc fmt_Q; -+ struct fielddesc fmt_P; -+ struct fielddesc fmt_z; -+ struct fielddesc fmt_u; -+ struct fielddesc fmt_U; -+ struct fielddesc fmt_Z; -+ struct fielddesc fmt_X; -+ struct fielddesc fmt_v; -+ struct fielddesc fmt_O; -+/*[python end generated code: output=fa648744ec7f919d input=087d58357d4bf2c5]*/ -+ -+ // bool has code '?': -+ struct fielddesc fmt_bool; -+ -+ // always contains NULLs: -+ struct fielddesc fmt_nil; -+ -+ // Result of _ctypes_get_simple_type_chars. Initialized just after -+ // the rest of formattable, so we stash it here. -+ char simple_type_chars[26]; - }; - --/* -- Ideas: Implement VARIANT in this table, using 'V' code. -- Use '?' as code for BOOL. --*/ -+static struct formattable formattable; -+ -+ -+/* Get fielddesc info for a fixed-width integer. -+ * N.B: - must be called after (or from) _ctypes_init_fielddesc! -+ * - nbytes must be one of the supported values -+ */ -+ -+static inline struct fielddesc * -+_ctypes_fixint_fielddesc(Py_ssize_t nbytes, bool is_signed) -+{ -+#define _PACK(NBYTES, SGN) ((NBYTES<<2) + (SGN ? 1 : 0)) -+ switch (_PACK(nbytes, is_signed)) { -+/*[python input] -+for nbytes in 8, 16, 32, 64: -+ for sgn in 'i', 'u': -+ is_signed = sgn == 'i' -+ print(f' case (_PACK({nbytes // 8}, {int(is_signed)})): ' -+ + f'return &formattable.fmt_{sgn}{nbytes};') -+[python start generated code]*/ -+ case (_PACK(1, 1)): return &formattable.fmt_i8; -+ case (_PACK(1, 0)): return &formattable.fmt_u8; -+ case (_PACK(2, 1)): return &formattable.fmt_i16; -+ case (_PACK(2, 0)): return &formattable.fmt_u16; -+ case (_PACK(4, 1)): return &formattable.fmt_i32; -+ case (_PACK(4, 0)): return &formattable.fmt_u32; -+ case (_PACK(8, 1)): return &formattable.fmt_i64; -+ case (_PACK(8, 0)): return &formattable.fmt_u64; -+/*[python end generated code: output=0194ba35c4d64ff3 input=ee9f6f5bb872d645]*/ -+#undef _PACK -+ } -+ /* ctypes currently only supports platforms where the basic integer types -+ * (`char`, `short`, `int`, `long`, `long long`) have 1, 2, 4, or 8 bytes -+ * (i.e. 8 to 64 bits). -+ */ -+ Py_UNREACHABLE(); -+} -+ -+ -+/* Macro to call _ctypes_fixint_fielddesc for a given C type. */ -+ -+_Py_COMP_DIAG_PUSH -+#if defined(__GNUC__) && (__GNUC__ < 14) -+/* The signedness check expands to an expression that's always true or false. -+ * Older GCC gives a '-Wtype-limits' warning for this, which is a GCC bug -+ * (docs say it should "not warn for constant expressions"): -+ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86647 -+ * Silence that warning. -+ */ -+#pragma GCC diagnostic ignored "-Wtype-limits" -+#endif -+ -+#define FIXINT_FIELDDESC_FOR(C_TYPE) \ -+ _ctypes_fixint_fielddesc(sizeof(C_TYPE), (C_TYPE)-1 < 0) -+ - - /* Delayed initialization. Windows cannot statically reference dynamically - loaded addresses from DLLs. */ --void --_ctypes_init_fielddesc(void) --{ -- struct fielddesc *fd = formattable; -- for (; fd->code; ++fd) { -- switch (fd->code) { -- case 's': fd->pffi_type = &ffi_type_pointer; break; -- case 'b': fd->pffi_type = &ffi_type_schar; break; -- case 'B': fd->pffi_type = &ffi_type_uchar; break; -- case 'c': fd->pffi_type = &ffi_type_schar; break; -- case 'd': fd->pffi_type = &ffi_type_double; break; -+static void -+_ctypes_init_fielddesc_locked(void) -+{ -+ /* Fixed-width integers */ -+ -+/*[python input] -+for nbytes in 8, 16, 32, 64: -+ for sgn in 'i', 'u': -+ is_signed = sgn == 'i' -+ u = 'u' if sgn == 'u' else 's' -+ parts = [ -+ f"0", -+ f'&ffi_type_{u}int{nbytes}', -+ f'{sgn}{nbytes}_set', -+ f'{sgn}{nbytes}_get', -+ f'{sgn}{nbytes}_set_sw', -+ f'{sgn}{nbytes}_get_sw', -+ ] -+ print(f' formattable.fmt_{sgn}{nbytes} = (struct fielddesc){{') -+ print(f' {', '.join(parts)} }};') -+[python start generated code]*/ -+ formattable.fmt_i8 = (struct fielddesc){ -+ 0, &ffi_type_sint8, i8_set, i8_get, i8_set_sw, i8_get_sw }; -+ formattable.fmt_u8 = (struct fielddesc){ -+ 0, &ffi_type_uint8, u8_set, u8_get, u8_set_sw, u8_get_sw }; -+ formattable.fmt_i16 = (struct fielddesc){ -+ 0, &ffi_type_sint16, i16_set, i16_get, i16_set_sw, i16_get_sw }; -+ formattable.fmt_u16 = (struct fielddesc){ -+ 0, &ffi_type_uint16, u16_set, u16_get, u16_set_sw, u16_get_sw }; -+ formattable.fmt_i32 = (struct fielddesc){ -+ 0, &ffi_type_sint32, i32_set, i32_get, i32_set_sw, i32_get_sw }; -+ formattable.fmt_u32 = (struct fielddesc){ -+ 0, &ffi_type_uint32, u32_set, u32_get, u32_set_sw, u32_get_sw }; -+ formattable.fmt_i64 = (struct fielddesc){ -+ 0, &ffi_type_sint64, i64_set, i64_get, i64_set_sw, i64_get_sw }; -+ formattable.fmt_u64 = (struct fielddesc){ -+ 0, &ffi_type_uint64, u64_set, u64_get, u64_set_sw, u64_get_sw }; -+/*[python end generated code: output=16806fe0ca3a9c4c input=850b8dd6388b1b10]*/ -+ -+ -+ /* Native C integers. -+ * These use getters/setters for fixed-width ints but have their own -+ * `code` and `pffi_type`. -+ */ -+ -+/*[python input] -+for base_code, base_c_type in [ -+ ('b', 'char'), -+ ('h', 'short'), -+ ('i', 'int'), -+ ('l', 'long'), -+ ('q', 'long long'), -+]: -+ for code, c_type, ffi_type in [ -+ (base_code, 'signed ' + base_c_type, 's' + base_c_type), -+ (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}';") -+ if base_code == 'q': -+ # ffi doesn't have `long long`; keep use the fixint type -+ pass -+ else: -+ 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.pffi_type = &ffi_type_schar; -+ formattable.fmt_B = *FIXINT_FIELDDESC_FOR(unsigned char); -+ 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.pffi_type = &ffi_type_sshort; -+ formattable.fmt_H = *FIXINT_FIELDDESC_FOR(unsigned short); -+ 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.pffi_type = &ffi_type_sint; -+ formattable.fmt_I = *FIXINT_FIELDDESC_FOR(unsigned int); -+ 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.pffi_type = &ffi_type_slong; -+ formattable.fmt_L = *FIXINT_FIELDDESC_FOR(unsigned long); -+ 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 = *FIXINT_FIELDDESC_FOR(unsigned long long); -+ formattable.fmt_Q.code = 'Q'; -+/*[python end generated code: output=873c87a2e6b5075a input=ee814ca263aac18e]*/ -+ -+ -+ /* Other types have bespoke setters and getters named `@_set` and `@_get`, -+ * where `@` is the type code. -+ * Some have swapped variants, `@_set_sw` and `@_get_sw` -+ */ -+ -+#define _TABLE_ENTRY(SYMBOL, FFI_TYPE, ...) \ -+ formattable.fmt_ ## SYMBOL = \ -+ (struct fielddesc){(#SYMBOL)[0], (FFI_TYPE), __VA_ARGS__}; \ -+ /////////////////////////////////////////////////////////////////////////// -+ -+#define TABLE_ENTRY(SYMBOL, FFI_TYPE) \ -+ _TABLE_ENTRY(SYMBOL, FFI_TYPE, SYMBOL ## _set, SYMBOL ## _get) \ -+ /////////////////////////////////////////////////////////////////////////// -+ -+#define TABLE_ENTRY_SW(SYMBOL, FFI_TYPE) \ -+ _TABLE_ENTRY(SYMBOL, FFI_TYPE, SYMBOL ## _set, \ -+ SYMBOL ## _get, SYMBOL ## _set_sw, SYMBOL ## _get_sw) \ -+ /////////////////////////////////////////////////////////////////////////// -+ -+ TABLE_ENTRY_SW(d, &ffi_type_double); - #if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX) -- case 'C': fd->pffi_type = &ffi_type_complex_double; break; -- case 'E': fd->pffi_type = &ffi_type_complex_float; break; -- case 'F': fd->pffi_type = &ffi_type_complex_longdouble; break; -+ if (Py_FFI_COMPLEX_AVAILABLE) { -+ TABLE_ENTRY(C, &ffi_type_complex_double); -+ TABLE_ENTRY(E, &ffi_type_complex_float); -+ TABLE_ENTRY(F, &ffi_type_complex_longdouble); -+ } - #endif -- case 'g': fd->pffi_type = &ffi_type_longdouble; break; -- case 'f': fd->pffi_type = &ffi_type_float; break; -- case 'h': fd->pffi_type = &ffi_type_sshort; break; -- case 'H': fd->pffi_type = &ffi_type_ushort; break; -- case 'i': fd->pffi_type = &ffi_type_sint; break; -- case 'I': fd->pffi_type = &ffi_type_uint; break; -- /* XXX Hm, sizeof(int) == sizeof(long) doesn't hold on every platform */ -- /* As soon as we can get rid of the type codes, this is no longer a problem */ -- #if SIZEOF_LONG == 4 -- case 'l': fd->pffi_type = &ffi_type_sint32; break; -- case 'L': fd->pffi_type = &ffi_type_uint32; break; -- #elif SIZEOF_LONG == 8 -- case 'l': fd->pffi_type = &ffi_type_sint64; break; -- case 'L': fd->pffi_type = &ffi_type_uint64; break; -- #else -- #error -- #endif -- #if SIZEOF_LONG_LONG == 8 -- case 'q': fd->pffi_type = &ffi_type_sint64; break; -- case 'Q': fd->pffi_type = &ffi_type_uint64; break; -- #else -- #error -- #endif -- case 'P': fd->pffi_type = &ffi_type_pointer; break; -- case 'z': fd->pffi_type = &ffi_type_pointer; break; -- case 'u': -- if (sizeof(wchar_t) == sizeof(short)) -- fd->pffi_type = &ffi_type_sshort; -- else if (sizeof(wchar_t) == sizeof(int)) -- fd->pffi_type = &ffi_type_sint; -- else if (sizeof(wchar_t) == sizeof(long)) -- fd->pffi_type = &ffi_type_slong; -- else -- Py_UNREACHABLE(); -- break; -- case 'U': fd->pffi_type = &ffi_type_pointer; break; -- case 'Z': fd->pffi_type = &ffi_type_pointer; break; -- #ifdef MS_WIN32 -- case 'X': fd->pffi_type = &ffi_type_pointer; break; -- #endif -- case 'v': fd->pffi_type = &ffi_type_sshort; break; -- #if SIZEOF__BOOL == 1 -- case '?': fd->pffi_type = &ffi_type_uchar; break; /* Also fallback for no native _Bool support */ -- #elif SIZEOF__BOOL == SIZEOF_SHORT -- case '?': fd->pffi_type = &ffi_type_ushort; break; -- #elif SIZEOF__BOOL == SIZEOF_INT -- case '?': fd->pffi_type = &ffi_type_uint; break; -- #elif SIZEOF__BOOL == SIZEOF_LONG -- case '?': fd->pffi_type = &ffi_type_ulong; break; -- #elif SIZEOF__BOOL == SIZEOF_LONG_LONG -- case '?': fd->pffi_type = &ffi_type_ulong; break; -- #endif /* SIZEOF__BOOL */ -- case 'O': fd->pffi_type = &ffi_type_pointer; break; -- default: -- Py_UNREACHABLE(); -- } -+ TABLE_ENTRY(g, &ffi_type_longdouble); -+ TABLE_ENTRY_SW(f, &ffi_type_float); -+ TABLE_ENTRY(v, &ffi_type_sshort); /* vBOOL */ -+ -+ // ctypes.c_char is signed for FFI, even where C wchar_t is unsigned. -+ TABLE_ENTRY(c, _ctypes_fixint_fielddesc(sizeof(char), true)->pffi_type); -+ // ctypes.c_wchar is signed for FFI, even where C wchar_t is unsigned. -+ TABLE_ENTRY(u, _ctypes_fixint_fielddesc(sizeof(wchar_t), true)->pffi_type); -+ -+ TABLE_ENTRY(s, &ffi_type_pointer); -+ TABLE_ENTRY(P, &ffi_type_pointer); -+ TABLE_ENTRY(z, &ffi_type_pointer); -+ TABLE_ENTRY(U, &ffi_type_pointer); -+ TABLE_ENTRY(Z, &ffi_type_pointer); -+#ifdef MS_WIN32 -+ TABLE_ENTRY(X, &ffi_type_pointer); -+#endif -+ TABLE_ENTRY(O, &ffi_type_pointer); -+ -+#undef TABLE_ENTRY_SW -+#undef TABLE_ENTRY -+#undef _TABLE_ENTRY -+ -+ /* bool has code '?', fill it in manually */ -+ -+ // 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.setfunc = bool_set; -+ formattable.fmt_bool.getfunc = bool_get; -+ -+/*[python input] -+all_chars = "cbBhHiIlLdCEFfuzZqQPXOv?g" -+print(f' assert(sizeof(formattable.simple_type_chars) == {len(all_chars)+1});') -+print(f' int i = 0;') -+for char in all_chars: -+ ident_char = {'?': 'bool'}.get(char, char) -+ print(f" if (formattable.fmt_{ident_char}.code) " -+ + 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); -+ 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'; -+ if (formattable.fmt_B.code) formattable.simple_type_chars[i++] = 'B'; -+ if (formattable.fmt_h.code) formattable.simple_type_chars[i++] = 'h'; -+ if (formattable.fmt_H.code) formattable.simple_type_chars[i++] = 'H'; -+ if (formattable.fmt_i.code) formattable.simple_type_chars[i++] = 'i'; -+ if (formattable.fmt_I.code) formattable.simple_type_chars[i++] = 'I'; -+ 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_C.code) formattable.simple_type_chars[i++] = 'C'; -+ if (formattable.fmt_E.code) formattable.simple_type_chars[i++] = 'E'; -+ if (formattable.fmt_F.code) formattable.simple_type_chars[i++] = 'F'; -+ 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'; -+ if (formattable.fmt_Z.code) formattable.simple_type_chars[i++] = 'Z'; -+ if (formattable.fmt_q.code) formattable.simple_type_chars[i++] = 'q'; -+ if (formattable.fmt_Q.code) formattable.simple_type_chars[i++] = 'Q'; -+ if (formattable.fmt_P.code) formattable.simple_type_chars[i++] = 'P'; -+ if (formattable.fmt_X.code) formattable.simple_type_chars[i++] = 'X'; -+ if (formattable.fmt_O.code) formattable.simple_type_chars[i++] = 'O'; -+ if (formattable.fmt_v.code) formattable.simple_type_chars[i++] = 'v'; -+ 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=e6e5098a02f4b606 input=72031a625eac00c1]*/ -+ -+} -+#undef FIXINT_FIELDDESC_FOR -+_Py_COMP_DIAG_POP -+ -+static void -+_ctypes_init_fielddesc(void) -+{ -+ static bool initialized = false; -+ static PyMutex mutex = {0}; -+ PyMutex_Lock(&mutex); -+ if (!initialized) { -+ _ctypes_init_fielddesc_locked(); -+ initialized = true; - } -+ PyMutex_Unlock(&mutex); -+} - -+char * -+_ctypes_get_simple_type_chars(void) { -+ _ctypes_init_fielddesc(); -+ return formattable.simple_type_chars; - } - - struct fielddesc * - _ctypes_get_fielddesc(const char *fmt) - { -- static int initialized = 0; -- struct fielddesc *table = formattable; -- -- if (!initialized) { -- initialized = 1; -- _ctypes_init_fielddesc(); -+ _ctypes_init_fielddesc(); -+ -+ struct fielddesc *result = NULL; -+ switch(fmt[0]) { -+/*[python input] -+for code in 'sbBcdCEFgfhHiIlLqQPzuUZXvO': -+ print(f" case '{code}': result = &formattable.fmt_{code}; break;") -+[python start generated code]*/ -+ case 's': result = &formattable.fmt_s; break; -+ case 'b': result = &formattable.fmt_b; break; -+ case 'B': result = &formattable.fmt_B; break; -+ case 'c': result = &formattable.fmt_c; break; -+ case 'd': result = &formattable.fmt_d; break; -+ case 'C': result = &formattable.fmt_C; break; -+ case 'E': result = &formattable.fmt_E; break; -+ case 'F': result = &formattable.fmt_F; break; -+ case 'g': result = &formattable.fmt_g; break; -+ case 'f': result = &formattable.fmt_f; break; -+ case 'h': result = &formattable.fmt_h; break; -+ case 'H': result = &formattable.fmt_H; break; -+ case 'i': result = &formattable.fmt_i; break; -+ case 'I': result = &formattable.fmt_I; break; -+ case 'l': result = &formattable.fmt_l; break; -+ case 'L': result = &formattable.fmt_L; break; -+ case 'q': result = &formattable.fmt_q; break; -+ case 'Q': result = &formattable.fmt_Q; break; -+ case 'P': result = &formattable.fmt_P; break; -+ 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=81a8223dda9f81f7 input=2f59666d3c024edf]*/ -+ case '?': result = &formattable.fmt_bool; break; - } -- -- for (; table->code; ++table) { -- if (table->code == fmt[0]) -- return table; -+ if (!result || !result->code) { -+ return NULL; - } -- return NULL; -+ assert(result->pffi_type); -+ assert(result->setfunc); -+ assert(result->getfunc); -+ return result; - } - -+/* -+ Ideas: Implement VARIANT in this table, using 'V' code. -+*/ -+ - /*---------------- EOF ----------------*/ -diff --git a/Modules/_ctypes/clinic/_ctypes.c.h b/Modules/_ctypes/clinic/_ctypes.c.h -index 1332ba04cdf..1f2e871137e 100644 ---- a/Modules/_ctypes/clinic/_ctypes.c.h -+++ b/Modules/_ctypes/clinic/_ctypes.c.h -@@ -6,6 +6,7 @@ - # include "pycore_runtime.h" // _Py_SINGLETON() - #endif - #include "pycore_abstract.h" // _PyNumber_Index() -+#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() - #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() - - PyDoc_STRVAR(_ctypes_CType_Type___sizeof____doc__, -@@ -330,7 +331,7 @@ - PyObject *type); - - static PyObject * --PyCPointerType_set_type(PyTypeObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+PyCPointerType_set_type(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -355,7 +356,7 @@ - goto exit; - } - type = args[0]; -- return_value = PyCPointerType_set_type_impl(self, cls, type); -+ return_value = PyCPointerType_set_type_impl((PyTypeObject *)self, cls, type); - - exit: - return return_value; -@@ -601,6 +602,177 @@ - return PyCData_reduce_impl(myself, cls); - } - -+#if !defined(_ctypes_CFuncPtr_errcheck_DOCSTR) -+# define _ctypes_CFuncPtr_errcheck_DOCSTR NULL -+#endif -+#if defined(_CTYPES_CFUNCPTR_ERRCHECK_GETSETDEF) -+# undef _CTYPES_CFUNCPTR_ERRCHECK_GETSETDEF -+# define _CTYPES_CFUNCPTR_ERRCHECK_GETSETDEF {"errcheck", (getter)_ctypes_CFuncPtr_errcheck_get, (setter)_ctypes_CFuncPtr_errcheck_set, _ctypes_CFuncPtr_errcheck_DOCSTR}, -+#else -+# define _CTYPES_CFUNCPTR_ERRCHECK_GETSETDEF {"errcheck", NULL, (setter)_ctypes_CFuncPtr_errcheck_set, NULL}, -+#endif -+ -+static int -+_ctypes_CFuncPtr_errcheck_set_impl(PyCFuncPtrObject *self, PyObject *value); -+ -+static int -+_ctypes_CFuncPtr_errcheck_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) -+{ -+ int return_value; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _ctypes_CFuncPtr_errcheck_set_impl((PyCFuncPtrObject *)self, value); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+PyDoc_STRVAR(_ctypes_CFuncPtr_errcheck__doc__, -+"a function to check for errors"); -+#if defined(_ctypes_CFuncPtr_errcheck_DOCSTR) -+# undef _ctypes_CFuncPtr_errcheck_DOCSTR -+#endif -+#define _ctypes_CFuncPtr_errcheck_DOCSTR _ctypes_CFuncPtr_errcheck__doc__ -+ -+#if !defined(_ctypes_CFuncPtr_errcheck_DOCSTR) -+# define _ctypes_CFuncPtr_errcheck_DOCSTR NULL -+#endif -+#if defined(_CTYPES_CFUNCPTR_ERRCHECK_GETSETDEF) -+# undef _CTYPES_CFUNCPTR_ERRCHECK_GETSETDEF -+# define _CTYPES_CFUNCPTR_ERRCHECK_GETSETDEF {"errcheck", (getter)_ctypes_CFuncPtr_errcheck_get, (setter)_ctypes_CFuncPtr_errcheck_set, _ctypes_CFuncPtr_errcheck_DOCSTR}, -+#else -+# define _CTYPES_CFUNCPTR_ERRCHECK_GETSETDEF {"errcheck", (getter)_ctypes_CFuncPtr_errcheck_get, NULL, _ctypes_CFuncPtr_errcheck_DOCSTR}, -+#endif -+ -+static PyObject * -+_ctypes_CFuncPtr_errcheck_get_impl(PyCFuncPtrObject *self); -+ -+static PyObject * -+_ctypes_CFuncPtr_errcheck_get(PyObject *self, void *Py_UNUSED(context)) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _ctypes_CFuncPtr_errcheck_get_impl((PyCFuncPtrObject *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(_ctypes_CFuncPtr_restype_DOCSTR) -+# define _ctypes_CFuncPtr_restype_DOCSTR NULL -+#endif -+#if defined(_CTYPES_CFUNCPTR_RESTYPE_GETSETDEF) -+# undef _CTYPES_CFUNCPTR_RESTYPE_GETSETDEF -+# define _CTYPES_CFUNCPTR_RESTYPE_GETSETDEF {"restype", (getter)_ctypes_CFuncPtr_restype_get, (setter)_ctypes_CFuncPtr_restype_set, _ctypes_CFuncPtr_restype_DOCSTR}, -+#else -+# define _CTYPES_CFUNCPTR_RESTYPE_GETSETDEF {"restype", NULL, (setter)_ctypes_CFuncPtr_restype_set, NULL}, -+#endif -+ -+static int -+_ctypes_CFuncPtr_restype_set_impl(PyCFuncPtrObject *self, PyObject *value); -+ -+static int -+_ctypes_CFuncPtr_restype_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) -+{ -+ int return_value; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _ctypes_CFuncPtr_restype_set_impl((PyCFuncPtrObject *)self, value); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+PyDoc_STRVAR(_ctypes_CFuncPtr_restype__doc__, -+"specify the result type"); -+#if defined(_ctypes_CFuncPtr_restype_DOCSTR) -+# undef _ctypes_CFuncPtr_restype_DOCSTR -+#endif -+#define _ctypes_CFuncPtr_restype_DOCSTR _ctypes_CFuncPtr_restype__doc__ -+ -+#if !defined(_ctypes_CFuncPtr_restype_DOCSTR) -+# define _ctypes_CFuncPtr_restype_DOCSTR NULL -+#endif -+#if defined(_CTYPES_CFUNCPTR_RESTYPE_GETSETDEF) -+# undef _CTYPES_CFUNCPTR_RESTYPE_GETSETDEF -+# define _CTYPES_CFUNCPTR_RESTYPE_GETSETDEF {"restype", (getter)_ctypes_CFuncPtr_restype_get, (setter)_ctypes_CFuncPtr_restype_set, _ctypes_CFuncPtr_restype_DOCSTR}, -+#else -+# define _CTYPES_CFUNCPTR_RESTYPE_GETSETDEF {"restype", (getter)_ctypes_CFuncPtr_restype_get, NULL, _ctypes_CFuncPtr_restype_DOCSTR}, -+#endif -+ -+static PyObject * -+_ctypes_CFuncPtr_restype_get_impl(PyCFuncPtrObject *self); -+ -+static PyObject * -+_ctypes_CFuncPtr_restype_get(PyObject *self, void *Py_UNUSED(context)) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _ctypes_CFuncPtr_restype_get_impl((PyCFuncPtrObject *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(_ctypes_CFuncPtr_argtypes_DOCSTR) -+# define _ctypes_CFuncPtr_argtypes_DOCSTR NULL -+#endif -+#if defined(_CTYPES_CFUNCPTR_ARGTYPES_GETSETDEF) -+# undef _CTYPES_CFUNCPTR_ARGTYPES_GETSETDEF -+# define _CTYPES_CFUNCPTR_ARGTYPES_GETSETDEF {"argtypes", (getter)_ctypes_CFuncPtr_argtypes_get, (setter)_ctypes_CFuncPtr_argtypes_set, _ctypes_CFuncPtr_argtypes_DOCSTR}, -+#else -+# define _CTYPES_CFUNCPTR_ARGTYPES_GETSETDEF {"argtypes", NULL, (setter)_ctypes_CFuncPtr_argtypes_set, NULL}, -+#endif -+ -+static int -+_ctypes_CFuncPtr_argtypes_set_impl(PyCFuncPtrObject *self, PyObject *value); -+ -+static int -+_ctypes_CFuncPtr_argtypes_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) -+{ -+ int return_value; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _ctypes_CFuncPtr_argtypes_set_impl((PyCFuncPtrObject *)self, value); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+PyDoc_STRVAR(_ctypes_CFuncPtr_argtypes__doc__, -+"specify the argument types"); -+#if defined(_ctypes_CFuncPtr_argtypes_DOCSTR) -+# undef _ctypes_CFuncPtr_argtypes_DOCSTR -+#endif -+#define _ctypes_CFuncPtr_argtypes_DOCSTR _ctypes_CFuncPtr_argtypes__doc__ -+ -+#if !defined(_ctypes_CFuncPtr_argtypes_DOCSTR) -+# define _ctypes_CFuncPtr_argtypes_DOCSTR NULL -+#endif -+#if defined(_CTYPES_CFUNCPTR_ARGTYPES_GETSETDEF) -+# undef _CTYPES_CFUNCPTR_ARGTYPES_GETSETDEF -+# define _CTYPES_CFUNCPTR_ARGTYPES_GETSETDEF {"argtypes", (getter)_ctypes_CFuncPtr_argtypes_get, (setter)_ctypes_CFuncPtr_argtypes_set, _ctypes_CFuncPtr_argtypes_DOCSTR}, -+#else -+# define _CTYPES_CFUNCPTR_ARGTYPES_GETSETDEF {"argtypes", (getter)_ctypes_CFuncPtr_argtypes_get, NULL, _ctypes_CFuncPtr_argtypes_DOCSTR}, -+#endif -+ -+static PyObject * -+_ctypes_CFuncPtr_argtypes_get_impl(PyCFuncPtrObject *self); -+ -+static PyObject * -+_ctypes_CFuncPtr_argtypes_get(PyObject *self, void *Py_UNUSED(context)) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _ctypes_CFuncPtr_argtypes_get_impl((PyCFuncPtrObject *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ - PyDoc_STRVAR(Simple_from_outparm__doc__, - "__ctypes_from_outparam__($self, /)\n" - "--\n" -@@ -621,4 +793,4 @@ - } - return Simple_from_outparm_impl(self, cls); - } --/*[clinic end generated code: output=52724c091e3a8b8d input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=a18d87239b6fb8ca input=a9049054013a1b77]*/ -diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h -index 7e0804054cd..07049d0968c 100644 ---- a/Modules/_ctypes/ctypes.h -+++ b/Modules/_ctypes/ctypes.h -@@ -5,8 +5,21 @@ - #include "pycore_moduleobject.h" // _PyModule_GetState() - #include "pycore_typeobject.h" // _PyType_GetModuleState() - -+// Do we support C99 complex types in ffi? -+// For Apple's libffi, this must be determined at runtime (see gh-128156). - #if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX) - # include "../_complex.h" // complex -+# if USING_APPLE_OS_LIBFFI && defined(__has_builtin) -+# if __has_builtin(__builtin_available) -+# define Py_FFI_COMPLEX_AVAILABLE __builtin_available(macOS 10.15, *) -+# else -+# define Py_FFI_COMPLEX_AVAILABLE 1 -+# endif -+# else -+# define Py_FFI_COMPLEX_AVAILABLE 1 -+# endif -+#else -+# define Py_FFI_COMPLEX_AVAILABLE 0 - #endif - - #ifndef MS_WIN32 -@@ -112,9 +125,21 @@ - extern PyType_Spec cthunk_spec; - - typedef struct tagPyCArgObject PyCArgObject; -+#define _PyCArgObject_CAST(op) ((PyCArgObject *)(op)) -+ - typedef struct tagCDataObject CDataObject; --typedef PyObject *(* GETFUNC)(void *, Py_ssize_t size); --typedef PyObject *(* SETFUNC)(void *, PyObject *value, Py_ssize_t size); -+#define _CDataObject_CAST(op) ((CDataObject *)(op)) -+ -+// GETFUNC: convert the C value at *ptr* to Python object, return the object -+// SETFUNC: write content of the PyObject *value* to the location at *ptr*; -+// return a new reference to either *value*, or None for simple types -+// (see _CTYPES_DEBUG_KEEP). -+// Note that the *size* arg can have different meanings depending on context: -+// for string-like arrays it's the size in bytes -+// for int-style fields it's either the type size, or bitfiled info -+// that can be unpacked using the LOW_BIT & NUM_BITS macros. -+typedef PyObject *(* GETFUNC)(void *ptr, Py_ssize_t size); -+typedef PyObject *(* SETFUNC)(void *ptr, PyObject *value, Py_ssize_t size); - typedef PyCArgObject *(* PARAMFUNC)(ctypes_state *st, CDataObject *obj); - - /* A default buffer in CDataObject, which can be used for small C types. If -@@ -167,6 +192,8 @@ - ffi_type *ffi_restype; - ffi_type *atypes[1]; - } CThunkObject; -+ -+#define _CThunkObject_CAST(op) ((CThunkObject *)(op)) - #define CThunk_CheckExact(st, v) Py_IS_TYPE(v, st->PyCThunk_Type) - - typedef struct { -@@ -200,6 +227,8 @@ - PyObject *paramflags; - } PyCFuncPtrObject; - -+#define _PyCFuncPtrObject_CAST(op) ((PyCFuncPtrObject *)(op)) -+ - extern int PyCStructUnionType_update_stginfo(PyObject *fields, PyObject *type, int isStruct); - extern int PyType_stginfo(PyTypeObject *self, Py_ssize_t *psize, Py_ssize_t *palign, Py_ssize_t *plength); - extern int PyObject_stginfo(PyObject *self, Py_ssize_t *psize, Py_ssize_t *palign, Py_ssize_t *plength); -@@ -239,13 +268,16 @@ - /* a table entry describing a predefined ctypes type */ - struct fielddesc { - char code; -+ ffi_type *pffi_type; /* always statically allocated */ - SETFUNC setfunc; - GETFUNC getfunc; -- ffi_type *pffi_type; /* always statically allocated */ - SETFUNC setfunc_swapped; - GETFUNC getfunc_swapped; - }; - -+// Get all single-character type codes (for use in error messages) -+extern char *_ctypes_get_simple_type_chars(void); -+ - typedef struct CFieldObject { - PyObject_HEAD - Py_ssize_t offset; -@@ -260,6 +292,8 @@ - PyObject *name; /* exact PyUnicode */ - } CFieldObject; - -+#define _CFieldObject_CAST(op) ((CFieldObject *)(op)) -+ - /**************************************************************** - StgInfo - -@@ -396,6 +430,8 @@ - Py_ssize_t size; /* for the 'V' tag */ - }; - -+#define _PyCArgObject_CAST(op) ((PyCArgObject *)(op)) -+ - #define PyCArg_CheckExact(st, v) Py_IS_TYPE(v, st->PyCArg_Type) - extern PyCArgObject *PyCArgObject_new(ctypes_state *st); - -@@ -534,3 +570,51 @@ - info->initialized = 1; - return info; - } -+ -+/* See discussion in gh-128490. The plan here is to eventually use a per-object -+ * lock rather than a critical section, but that work is for later. */ -+#ifdef Py_GIL_DISABLED -+# define LOCK_PTR(self) Py_BEGIN_CRITICAL_SECTION(self) -+# define UNLOCK_PTR(self) Py_END_CRITICAL_SECTION() -+#else -+/* -+ * Dummy functions instead of macros so that 'self' can be -+ * unused in the caller without triggering a compiler warning. -+ */ -+static inline void LOCK_PTR(CDataObject *Py_UNUSED(self)) {} -+static inline void UNLOCK_PTR(CDataObject *Py_UNUSED(self)) {} -+#endif -+ -+static inline void -+locked_memcpy_to(CDataObject *self, void *buf, Py_ssize_t size) -+{ -+ LOCK_PTR(self); -+ (void)memcpy(self->b_ptr, buf, size); -+ UNLOCK_PTR(self); -+} -+ -+static inline void -+locked_memcpy_from(void *buf, CDataObject *self, Py_ssize_t size) -+{ -+ LOCK_PTR(self); -+ (void)memcpy(buf, self->b_ptr, size); -+ UNLOCK_PTR(self); -+} -+ -+static inline void * -+locked_deref(CDataObject *self) -+{ -+ void *ptr; -+ LOCK_PTR(self); -+ ptr = *(void **)self->b_ptr; -+ UNLOCK_PTR(self); -+ return ptr; -+} -+ -+static inline void -+locked_deref_assign(CDataObject *self, void *new_ptr) -+{ -+ LOCK_PTR(self); -+ *(void **)self->b_ptr = new_ptr; -+ UNLOCK_PTR(self); -+} -diff --git a/Modules/_ctypes/stgdict.c b/Modules/_ctypes/stgdict.c -index 5ca5b624276..05239d85c44 100644 ---- a/Modules/_ctypes/stgdict.c -+++ b/Modules/_ctypes/stgdict.c -@@ -257,8 +257,8 @@ - goto error; - } - -- PyObject *layout_func = _PyImport_GetModuleAttrString("ctypes._layout", -- "get_layout"); -+ PyObject *layout_func = PyImport_ImportModuleAttrString("ctypes._layout", -+ "get_layout"); - if (!layout_func) { - goto error; - } -diff --git a/Modules/_curses_panel.c b/Modules/_curses_panel.c -index bbbb62c9066..eecf7a1c8a1 100644 ---- a/Modules/_curses_panel.c -+++ b/Modules/_curses_panel.c -@@ -62,7 +62,7 @@ - static void - _curses_panel_free(void *mod) - { -- _curses_panel_clear((PyObject *) mod); -+ (void)_curses_panel_clear((PyObject *)mod); - } - - /* Utility Functions */ -@@ -101,6 +101,8 @@ - PyCursesWindowObject *wo; /* for reference counts */ - } PyCursesPanelObject; - -+#define _PyCursesPanelObject_CAST(op) ((PyCursesPanelObject *)(op)) -+ - /* Some helper functions. The problem is that there's always a window - associated with a panel. To ensure that Python's GC doesn't pull - this window from under our feet we need to keep track of references -@@ -277,9 +279,10 @@ - } - - static void --PyCursesPanel_Dealloc(PyCursesPanelObject *po) -+PyCursesPanel_Dealloc(PyObject *self) - { - PyObject *tp, *obj; -+ PyCursesPanelObject *po = _PyCursesPanelObject_CAST(self); - - tp = (PyObject *) Py_TYPE(po); - obj = (PyObject *) panel_userptr(po->pan); -diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c -index 040ffa81153..7213a5be07d 100644 ---- a/Modules/_cursesmodule.c -+++ b/Modules/_cursesmodule.c -@@ -138,7 +138,7 @@ - #define STRICT_SYSV_CURSES - #endif - --#if NCURSES_EXT_FUNCS+0 >= 20170401 && NCURSES_EXT_COLORS+0 >= 20170401 -+#if defined(HAVE_NCURSESW) && NCURSES_EXT_FUNCS+0 >= 20170401 && NCURSES_EXT_COLORS+0 >= 20170401 - #define _NCURSES_EXTENDED_COLOR_FUNCS 1 - #else - #define _NCURSES_EXTENDED_COLOR_FUNCS 0 -@@ -187,6 +187,8 @@ - return get_cursesmodule_state_by_cls(Py_TYPE(win)); - } - -+#define _PyCursesWindowObject_CAST(op) ((PyCursesWindowObject *)(op)) -+ - /*[clinic input] - module _curses - class _curses.window "PyCursesWindowObject *" "clinic_state()->window_type" -@@ -224,7 +226,7 @@ - if (called == TRUE) { - return 1; - } -- PyObject *exc = _PyImport_GetModuleAttrString("_curses", "error"); -+ PyObject *exc = PyImport_ImportModuleAttrString("_curses", "error"); - if (exc != NULL) { - PyErr_Format(exc, "must call %s() first", funcname); - Py_DECREF(exc); -@@ -654,53 +656,80 @@ - PARSESTR - format string for argument parsing - */ - --#define Window_NoArgNoReturnFunction(X) \ -- static PyObject *PyCursesWindow_ ## X \ -- (PyCursesWindowObject *self, PyObject *Py_UNUSED(ignored)) \ -- { return PyCursesCheckERR_ForWin(self, X(self->win), # X); } -+#define Window_NoArgNoReturnFunction(X) \ -+ static PyObject *PyCursesWindow_ ## X \ -+ (PyObject *op, PyObject *Py_UNUSED(ignored)) \ -+ { \ -+ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); \ -+ int code = X(self->win); \ -+ return PyCursesCheckERR_ForWin(self, code, # X); \ -+ } - - #define Window_NoArgTrueFalseFunction(X) \ - static PyObject * PyCursesWindow_ ## X \ -- (PyCursesWindowObject *self, PyObject *Py_UNUSED(ignored)) \ -+ (PyObject *op, PyObject *Py_UNUSED(ignored)) \ - { \ -- return PyBool_FromLong(X(self->win)); } -+ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); \ -+ return PyBool_FromLong(X(self->win)); \ -+ } - --#define Window_NoArgNoReturnVoidFunction(X) \ -- static PyObject * PyCursesWindow_ ## X \ -- (PyCursesWindowObject *self, PyObject *Py_UNUSED(ignored)) \ -- { \ -- X(self->win); Py_RETURN_NONE; } -+#define Window_NoArgNoReturnVoidFunction(X) \ -+ static PyObject * PyCursesWindow_ ## X \ -+ (PyObject *op, PyObject *Py_UNUSED(ignored)) \ -+ { \ -+ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); \ -+ X(self->win); \ -+ Py_RETURN_NONE; \ -+ } - - #define Window_NoArg2TupleReturnFunction(X, TYPE, ERGSTR) \ - static PyObject * PyCursesWindow_ ## X \ -- (PyCursesWindowObject *self, PyObject *Py_UNUSED(ignored)) \ -+ (PyObject *op, PyObject *Py_UNUSED(ignored)) \ - { \ - TYPE arg1, arg2; \ -- X(self->win,arg1,arg2); return Py_BuildValue(ERGSTR, arg1, arg2); } -+ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); \ -+ X(self->win, arg1, arg2); \ -+ return Py_BuildValue(ERGSTR, arg1, arg2); \ -+ } - - #define Window_OneArgNoReturnVoidFunction(X, TYPE, PARSESTR) \ - static PyObject * PyCursesWindow_ ## X \ -- (PyCursesWindowObject *self, PyObject *args) \ -+ (PyObject *op, PyObject *args) \ - { \ - TYPE arg1; \ -- if (!PyArg_ParseTuple(args, PARSESTR, &arg1)) return NULL; \ -- X(self->win,arg1); Py_RETURN_NONE; } -+ if (!PyArg_ParseTuple(args, PARSESTR, &arg1)) { \ -+ return NULL; \ -+ } \ -+ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); \ -+ X(self->win, arg1); \ -+ Py_RETURN_NONE; \ -+ } - - #define Window_OneArgNoReturnFunction(X, TYPE, PARSESTR) \ - static PyObject * PyCursesWindow_ ## X \ -- (PyCursesWindowObject *self, PyObject *args) \ -+ (PyObject *op, PyObject *args) \ - { \ - TYPE arg1; \ -- if (!PyArg_ParseTuple(args,PARSESTR, &arg1)) return NULL; \ -- return PyCursesCheckERR_ForWin(self, X(self->win, arg1), # X); } -+ if (!PyArg_ParseTuple(args, PARSESTR, &arg1)) { \ -+ return NULL; \ -+ } \ -+ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); \ -+ int code = X(self->win, arg1); \ -+ return PyCursesCheckERR_ForWin(self, code, # X); \ -+ } - - #define Window_TwoArgNoReturnFunction(X, TYPE, PARSESTR) \ - static PyObject * PyCursesWindow_ ## X \ -- (PyCursesWindowObject *self, PyObject *args) \ -+ (PyObject *op, PyObject *args) \ - { \ - TYPE arg1, arg2; \ -- if (!PyArg_ParseTuple(args,PARSESTR, &arg1, &arg2)) return NULL; \ -- return PyCursesCheckERR_ForWin(self, X(self->win, arg1, arg2), # X); } -+ if (!PyArg_ParseTuple(args,PARSESTR, &arg1, &arg2)) { \ -+ return NULL; \ -+ } \ -+ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); \ -+ int code = X(self->win, arg1, arg2); \ -+ return PyCursesCheckERR_ForWin(self, code, # X); \ -+ } - - /* ------------- WINDOW routines --------------- */ - -@@ -1302,8 +1331,10 @@ - window refresh. - [-clinic start generated code]*/ - static PyObject * --PyCursesWindow_ChgAt(PyCursesWindowObject *self, PyObject *args) -+PyCursesWindow_ChgAt(PyObject *op, PyObject *args) - { -+ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); -+ - int rtn; - int x, y; - int num = -1; -@@ -1656,8 +1687,10 @@ - [-clinic start generated code]*/ - - static PyObject * --PyCursesWindow_GetStr(PyCursesWindowObject *self, PyObject *args) -+PyCursesWindow_GetStr(PyObject *op, PyObject *args) - { -+ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); -+ - int x, y, n; - char rtn[1024]; /* This should be big enough.. I hope */ - int rtn2; -@@ -1860,8 +1893,10 @@ - n characters long (exclusive of the trailing NUL). - [-clinic start generated code]*/ - static PyObject * --PyCursesWindow_InStr(PyCursesWindowObject *self, PyObject *args) -+PyCursesWindow_InStr(PyObject *op, PyObject *args) - { -+ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); -+ - int x, y, n; - char rtn[1024]; /* This should be big enough.. I hope */ - int rtn2; -@@ -2557,14 +2592,17 @@ - } - - static PyObject * --PyCursesWindow_get_encoding(PyCursesWindowObject *self, void *closure) -+PyCursesWindow_get_encoding(PyObject *op, void *closure) - { -+ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); - return PyUnicode_FromString(self->encoding); - } - - static int --PyCursesWindow_set_encoding(PyCursesWindowObject *self, PyObject *value, void *Py_UNUSED(ignored)) -+PyCursesWindow_set_encoding(PyObject *op, PyObject *value, void *Py_UNUSED(ignored)) - { -+ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); -+ - PyObject *ascii; - char *encoding; - -@@ -2607,88 +2645,90 @@ - _CURSES_WINDOW_ATTRSET_METHODDEF - _CURSES_WINDOW_BKGD_METHODDEF - #ifdef HAVE_CURSES_WCHGAT -- {"chgat", (PyCFunction)PyCursesWindow_ChgAt, METH_VARARGS}, -+ {"chgat", PyCursesWindow_ChgAt, METH_VARARGS}, - #endif - _CURSES_WINDOW_BKGDSET_METHODDEF - _CURSES_WINDOW_BORDER_METHODDEF - _CURSES_WINDOW_BOX_METHODDEF -- {"clear", (PyCFunction)PyCursesWindow_wclear, METH_NOARGS}, -- {"clearok", (PyCFunction)PyCursesWindow_clearok, METH_VARARGS}, -- {"clrtobot", (PyCFunction)PyCursesWindow_wclrtobot, METH_NOARGS}, -- {"clrtoeol", (PyCFunction)PyCursesWindow_wclrtoeol, METH_NOARGS}, -- {"cursyncup", (PyCFunction)PyCursesWindow_wcursyncup, METH_NOARGS}, -+ {"clear", PyCursesWindow_wclear, METH_NOARGS}, -+ {"clearok", PyCursesWindow_clearok, METH_VARARGS}, -+ {"clrtobot", PyCursesWindow_wclrtobot, METH_NOARGS}, -+ {"clrtoeol", PyCursesWindow_wclrtoeol, METH_NOARGS}, -+ {"cursyncup", PyCursesWindow_wcursyncup, METH_NOARGS}, - _CURSES_WINDOW_DELCH_METHODDEF -- {"deleteln", (PyCFunction)PyCursesWindow_wdeleteln, METH_NOARGS}, -+ {"deleteln", PyCursesWindow_wdeleteln, METH_NOARGS}, - _CURSES_WINDOW_DERWIN_METHODDEF - _CURSES_WINDOW_ECHOCHAR_METHODDEF - _CURSES_WINDOW_ENCLOSE_METHODDEF -- {"erase", (PyCFunction)PyCursesWindow_werase, METH_NOARGS}, -- {"getbegyx", (PyCFunction)PyCursesWindow_getbegyx, METH_NOARGS}, -+ {"erase", PyCursesWindow_werase, METH_NOARGS}, -+ {"getbegyx", PyCursesWindow_getbegyx, METH_NOARGS}, - _CURSES_WINDOW_GETBKGD_METHODDEF - _CURSES_WINDOW_GETCH_METHODDEF - _CURSES_WINDOW_GETKEY_METHODDEF - _CURSES_WINDOW_GET_WCH_METHODDEF -- {"getmaxyx", (PyCFunction)PyCursesWindow_getmaxyx, METH_NOARGS}, -- {"getparyx", (PyCFunction)PyCursesWindow_getparyx, METH_NOARGS}, -- {"getstr", (PyCFunction)PyCursesWindow_GetStr, METH_VARARGS}, -- {"getyx", (PyCFunction)PyCursesWindow_getyx, METH_NOARGS}, -+ {"getmaxyx", PyCursesWindow_getmaxyx, METH_NOARGS}, -+ {"getparyx", PyCursesWindow_getparyx, METH_NOARGS}, -+ {"getstr", PyCursesWindow_GetStr, METH_VARARGS}, -+ {"getyx", PyCursesWindow_getyx, METH_NOARGS}, - _CURSES_WINDOW_HLINE_METHODDEF -- {"idcok", (PyCFunction)PyCursesWindow_idcok, METH_VARARGS}, -- {"idlok", (PyCFunction)PyCursesWindow_idlok, METH_VARARGS}, -+ {"idcok", PyCursesWindow_idcok, METH_VARARGS}, -+ {"idlok", PyCursesWindow_idlok, METH_VARARGS}, - #ifdef HAVE_CURSES_IMMEDOK -- {"immedok", (PyCFunction)PyCursesWindow_immedok, METH_VARARGS}, -+ {"immedok", PyCursesWindow_immedok, METH_VARARGS}, - #endif - _CURSES_WINDOW_INCH_METHODDEF - _CURSES_WINDOW_INSCH_METHODDEF -- {"insdelln", (PyCFunction)PyCursesWindow_winsdelln, METH_VARARGS}, -- {"insertln", (PyCFunction)PyCursesWindow_winsertln, METH_NOARGS}, -+ {"insdelln", PyCursesWindow_winsdelln, METH_VARARGS}, -+ {"insertln", PyCursesWindow_winsertln, METH_NOARGS}, - _CURSES_WINDOW_INSNSTR_METHODDEF - _CURSES_WINDOW_INSSTR_METHODDEF -- {"instr", (PyCFunction)PyCursesWindow_InStr, METH_VARARGS}, -+ {"instr", PyCursesWindow_InStr, METH_VARARGS}, - _CURSES_WINDOW_IS_LINETOUCHED_METHODDEF -- {"is_wintouched", (PyCFunction)PyCursesWindow_is_wintouched, METH_NOARGS}, -- {"keypad", (PyCFunction)PyCursesWindow_keypad, METH_VARARGS}, -- {"leaveok", (PyCFunction)PyCursesWindow_leaveok, METH_VARARGS}, -- {"move", (PyCFunction)PyCursesWindow_wmove, METH_VARARGS}, -- {"mvderwin", (PyCFunction)PyCursesWindow_mvderwin, METH_VARARGS}, -- {"mvwin", (PyCFunction)PyCursesWindow_mvwin, METH_VARARGS}, -- {"nodelay", (PyCFunction)PyCursesWindow_nodelay, METH_VARARGS}, -- {"notimeout", (PyCFunction)PyCursesWindow_notimeout, METH_VARARGS}, -+ {"is_wintouched", PyCursesWindow_is_wintouched, METH_NOARGS}, -+ {"keypad", PyCursesWindow_keypad, METH_VARARGS}, -+ {"leaveok", PyCursesWindow_leaveok, METH_VARARGS}, -+ {"move", PyCursesWindow_wmove, METH_VARARGS}, -+ {"mvderwin", PyCursesWindow_mvderwin, METH_VARARGS}, -+ {"mvwin", PyCursesWindow_mvwin, METH_VARARGS}, -+ {"nodelay", PyCursesWindow_nodelay, METH_VARARGS}, -+ {"notimeout", PyCursesWindow_notimeout, METH_VARARGS}, - _CURSES_WINDOW_NOUTREFRESH_METHODDEF - _CURSES_WINDOW_OVERLAY_METHODDEF - _CURSES_WINDOW_OVERWRITE_METHODDEF - _CURSES_WINDOW_PUTWIN_METHODDEF - _CURSES_WINDOW_REDRAWLN_METHODDEF -- {"redrawwin", (PyCFunction)PyCursesWindow_redrawwin, METH_NOARGS}, -+ {"redrawwin", PyCursesWindow_redrawwin, METH_NOARGS}, - _CURSES_WINDOW_REFRESH_METHODDEF - #ifndef STRICT_SYSV_CURSES -- {"resize", (PyCFunction)PyCursesWindow_wresize, METH_VARARGS}, -+ {"resize", PyCursesWindow_wresize, METH_VARARGS}, - #endif - _CURSES_WINDOW_SCROLL_METHODDEF -- {"scrollok", (PyCFunction)PyCursesWindow_scrollok, METH_VARARGS}, -+ {"scrollok", PyCursesWindow_scrollok, METH_VARARGS}, - _CURSES_WINDOW_SETSCRREG_METHODDEF -- {"standend", (PyCFunction)PyCursesWindow_wstandend, METH_NOARGS}, -- {"standout", (PyCFunction)PyCursesWindow_wstandout, METH_NOARGS}, -+ {"standend", PyCursesWindow_wstandend, METH_NOARGS}, -+ {"standout", PyCursesWindow_wstandout, METH_NOARGS}, - {"subpad", (PyCFunction)_curses_window_subwin, METH_VARARGS, _curses_window_subwin__doc__}, - _CURSES_WINDOW_SUBWIN_METHODDEF -- {"syncdown", (PyCFunction)PyCursesWindow_wsyncdown, METH_NOARGS}, -+ {"syncdown", PyCursesWindow_wsyncdown, METH_NOARGS}, - #ifdef HAVE_CURSES_SYNCOK -- {"syncok", (PyCFunction)PyCursesWindow_syncok, METH_VARARGS}, -+ {"syncok", PyCursesWindow_syncok, METH_VARARGS}, - #endif -- {"syncup", (PyCFunction)PyCursesWindow_wsyncup, METH_NOARGS}, -- {"timeout", (PyCFunction)PyCursesWindow_wtimeout, METH_VARARGS}, -+ {"syncup", PyCursesWindow_wsyncup, METH_NOARGS}, -+ {"timeout", PyCursesWindow_wtimeout, METH_VARARGS}, - _CURSES_WINDOW_TOUCHLINE_METHODDEF -- {"touchwin", (PyCFunction)PyCursesWindow_touchwin, METH_NOARGS}, -- {"untouchwin", (PyCFunction)PyCursesWindow_untouchwin, METH_NOARGS}, -+ {"touchwin", PyCursesWindow_touchwin, METH_NOARGS}, -+ {"untouchwin", PyCursesWindow_untouchwin, METH_NOARGS}, - _CURSES_WINDOW_VLINE_METHODDEF - {NULL, NULL} /* sentinel */ - }; - - static PyGetSetDef PyCursesWindow_getsets[] = { -- {"encoding", -- (getter)PyCursesWindow_get_encoding, -- (setter)PyCursesWindow_set_encoding, -- "the typecode character used to create the array"}, -+ { -+ "encoding", -+ PyCursesWindow_get_encoding, -+ PyCursesWindow_set_encoding, -+ "the typecode character used to create the array" -+ }, - {NULL, NULL, NULL, NULL } /* sentinel */ - }; - -diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c -index b1102984cb5..bcbf4217d41 100644 ---- a/Modules/_datetimemodule.c -+++ b/Modules/_datetimemodule.c -@@ -226,7 +226,7 @@ - goto finally; - - error: -- PyErr_WriteUnraisable(NULL); -+ PyErr_FormatUnraisable("Exception ignored while clearing _datetime module"); - - finally: - PyErr_SetRaisedException(exc); -@@ -1839,7 +1839,7 @@ - assert(object && format && timetuple); - assert(PyUnicode_Check(format)); - -- PyObject *strftime = _PyImport_GetModuleAttrString("time", "strftime"); -+ PyObject *strftime = PyImport_ImportModuleAttrString("time", "strftime"); - if (strftime == NULL) { - return NULL; - } -@@ -1849,9 +1849,10 @@ - * is expensive, don't unless they're actually used. - */ - -- _PyUnicodeWriter writer; -- _PyUnicodeWriter_Init(&writer); -- writer.overallocate = 1; -+ PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); -+ if (writer == NULL) { -+ goto Error; -+ } - - Py_ssize_t flen = PyUnicode_GET_LENGTH(format); - Py_ssize_t i = 0; -@@ -1912,9 +1913,7 @@ - } - #ifdef Py_NORMALIZE_CENTURY - else if (ch == 'Y' || ch == 'G' --#ifdef Py_STRFTIME_C99_SUPPORT - || ch == 'F' || ch == 'C' --#endif - ) { - /* 0-pad year with century as necessary */ - PyObject *item = PySequence_GetItem(timetuple, 0); -@@ -1952,20 +1951,16 @@ - * +6 to accommodate dashes, 2-digit month and day for %F. */ - char buf[SIZEOF_LONG * 5 / 2 + 2 + 6]; - Py_ssize_t n = PyOS_snprintf(buf, sizeof(buf), --#ifdef Py_STRFTIME_C99_SUPPORT - ch == 'F' ? "%04ld-%%m-%%d" : --#endif - "%04ld", year_long); --#ifdef Py_STRFTIME_C99_SUPPORT - if (ch == 'C') { - n -= 2; - } --#endif -- if (_PyUnicodeWriter_WriteSubstring(&writer, format, start, end) < 0) { -+ if (PyUnicodeWriter_WriteSubstring(writer, format, start, end) < 0) { - goto Error; - } - start = i; -- if (_PyUnicodeWriter_WriteASCIIString(&writer, buf, n) < 0) { -+ if (PyUnicodeWriter_WriteUTF8(writer, buf, n) < 0) { - goto Error; - } - continue; -@@ -1977,25 +1972,25 @@ - } - assert(replacement != NULL); - assert(PyUnicode_Check(replacement)); -- if (_PyUnicodeWriter_WriteSubstring(&writer, format, start, end) < 0) { -+ if (PyUnicodeWriter_WriteSubstring(writer, format, start, end) < 0) { - goto Error; - } - start = i; -- if (_PyUnicodeWriter_WriteStr(&writer, replacement) < 0) { -+ if (PyUnicodeWriter_WriteStr(writer, replacement) < 0) { - goto Error; - } - } /* end while() */ - - PyObject *newformat; - if (start == 0) { -- _PyUnicodeWriter_Dealloc(&writer); -+ PyUnicodeWriter_Discard(writer); - newformat = Py_NewRef(format); - } - else { -- if (_PyUnicodeWriter_WriteSubstring(&writer, format, start, flen) < 0) { -+ if (PyUnicodeWriter_WriteSubstring(writer, format, start, flen) < 0) { - goto Error; - } -- newformat = _PyUnicodeWriter_Finish(&writer); -+ newformat = PyUnicodeWriter_Finish(writer); - if (newformat == NULL) { - goto Done; - } -@@ -2013,7 +2008,7 @@ - return result; - - Error: -- _PyUnicodeWriter_Dealloc(&writer); -+ PyUnicodeWriter_Discard(writer); - goto Done; - } - -@@ -2027,7 +2022,7 @@ - time_time(void) - { - PyObject *result = NULL; -- PyObject *time = _PyImport_GetModuleAttrString("time", "time"); -+ PyObject *time = PyImport_ImportModuleAttrString("time", "time"); - - if (time != NULL) { - result = PyObject_CallNoArgs(time); -@@ -2045,7 +2040,7 @@ - PyObject *struct_time; - PyObject *result; - -- struct_time = _PyImport_GetModuleAttrString("time", "struct_time"); -+ struct_time = PyImport_ImportModuleAttrString("time", "struct_time"); - if (struct_time == NULL) { - return NULL; - } -@@ -4953,7 +4948,7 @@ - minute: int(c_default="TIME_GET_MINUTE(self)") = unchanged - second: int(c_default="TIME_GET_SECOND(self)") = unchanged - microsecond: int(c_default="TIME_GET_MICROSECOND(self)") = unchanged -- tzinfo: object(c_default="HASTZINFO(self) ? self->tzinfo : Py_None") = unchanged -+ tzinfo: object(c_default="HASTZINFO(self) ? ((PyDateTime_Time *)self)->tzinfo : Py_None") = unchanged - * - fold: int(c_default="TIME_GET_FOLD(self)") = unchanged - -@@ -4964,7 +4959,7 @@ - datetime_time_replace_impl(PyDateTime_Time *self, int hour, int minute, - int second, int microsecond, PyObject *tzinfo, - int fold) --/*[clinic end generated code: output=0b89a44c299e4f80 input=9b6a35b1e704b0ca]*/ -+/*[clinic end generated code: output=0b89a44c299e4f80 input=abf23656e8df4e97]*/ - { - return new_time_subclass_fold_ex(hour, minute, second, microsecond, tzinfo, - fold, (PyObject *)Py_TYPE(self)); -@@ -6455,7 +6450,7 @@ - minute: int(c_default="DATE_GET_MINUTE(self)") = unchanged - second: int(c_default="DATE_GET_SECOND(self)") = unchanged - microsecond: int(c_default="DATE_GET_MICROSECOND(self)") = unchanged -- tzinfo: object(c_default="HASTZINFO(self) ? self->tzinfo : Py_None") = unchanged -+ tzinfo: object(c_default="HASTZINFO(self) ? ((PyDateTime_DateTime *)self)->tzinfo : Py_None") = unchanged - * - fold: int(c_default="DATE_GET_FOLD(self)") = unchanged - -@@ -6467,7 +6462,7 @@ - int month, int day, int hour, int minute, - int second, int microsecond, PyObject *tzinfo, - int fold) --/*[clinic end generated code: output=00bc96536833fddb input=9b38253d56d9bcad]*/ -+/*[clinic end generated code: output=00bc96536833fddb input=fd972762d604d3e7]*/ - { - return new_datetime_subclass_fold_ex(year, month, day, hour, minute, - second, microsecond, tzinfo, fold, -diff --git a/Modules/_dbmmodule.c b/Modules/_dbmmodule.c -index 1be4234aad3..cc65cbd98d7 100644 ---- a/Modules/_dbmmodule.c -+++ b/Modules/_dbmmodule.c -@@ -64,6 +64,8 @@ - DBM *di_dbm; - } dbmobject; - -+#define dbmobject_CAST(op) ((dbmobject *)(op)) -+ - #include "clinic/_dbmmodule.c.h" - - #define check_dbmobject_open(v, err) \ -@@ -94,15 +96,16 @@ - - /* Methods */ - static int --dbm_traverse(dbmobject *dp, visitproc visit, void *arg) -+dbm_traverse(PyObject *dp, visitproc visit, void *arg) - { - Py_VISIT(Py_TYPE(dp)); - return 0; - } - - static void --dbm_dealloc(dbmobject *dp) -+dbm_dealloc(PyObject *self) - { -+ dbmobject *dp = dbmobject_CAST(self); - PyObject_GC_UnTrack(dp); - if (dp->di_dbm) { - dbm_close(dp->di_dbm); -@@ -113,8 +116,9 @@ - } - - static Py_ssize_t --dbm_length(dbmobject *dp) -+dbm_length(PyObject *self) - { -+ dbmobject *dp = dbmobject_CAST(self); - _dbm_state *state = PyType_GetModuleState(Py_TYPE(dp)); - assert(state != NULL); - if (dp->di_dbm == NULL) { -@@ -135,8 +139,9 @@ - } - - static int --dbm_bool(dbmobject *dp) -+dbm_bool(PyObject *self) - { -+ dbmobject *dp = dbmobject_CAST(self); - _dbm_state *state = PyType_GetModuleState(Py_TYPE(dp)); - assert(state != NULL); - -@@ -166,10 +171,11 @@ - } - - static PyObject * --dbm_subscript(dbmobject *dp, PyObject *key) -+dbm_subscript(PyObject *self, PyObject *key) - { - datum drec, krec; - Py_ssize_t tmp_size; -+ dbmobject *dp = dbmobject_CAST(self); - _dbm_state *state = PyType_GetModuleState(Py_TYPE(dp)); - assert(state != NULL); - if (!PyArg_Parse(key, "s#", &krec.dptr, &tmp_size)) { -@@ -192,10 +198,11 @@ - } - - static int --dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w) -+dbm_ass_sub(PyObject *self, PyObject *v, PyObject *w) - { - datum krec, drec; - Py_ssize_t tmp_size; -+ dbmobject *dp = dbmobject_CAST(self); - - if ( !PyArg_Parse(v, "s#", &krec.dptr, &tmp_size) ) { - PyErr_SetString(PyExc_TypeError, -@@ -305,7 +312,7 @@ - static int - dbm_contains(PyObject *self, PyObject *arg) - { -- dbmobject *dp = (dbmobject *)self; -+ dbmobject *dp = dbmobject_CAST(self); - datum key, val; - Py_ssize_t size; - -@@ -452,15 +459,16 @@ - } - - static PyObject * --dbm__enter__(PyObject *self, PyObject *args) -+dbm__enter__(PyObject *self, PyObject *Py_UNUSED(dummy)) - { - return Py_NewRef(self); - } - - static PyObject * --dbm__exit__(PyObject *self, PyObject *args) -+dbm__exit__(PyObject *self, PyObject *Py_UNUSED(args)) - { -- return _dbm_dbm_close_impl((dbmobject *)self); -+ dbmobject *dp = dbmobject_CAST(self); -+ return _dbm_dbm_close_impl(dp); - } - - static PyMethodDef dbm_methods[] = { -@@ -610,7 +618,7 @@ - static void - _dbm_module_free(void *module) - { -- _dbm_module_clear((PyObject *)module); -+ (void)_dbm_module_clear((PyObject *)module); - } - - static PyModuleDef_Slot _dbmmodule_slots[] = { -diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c -index c564813036e..3dcb3e9870c 100644 ---- a/Modules/_decimal/_decimal.c -+++ b/Modules/_decimal/_decimal.c -@@ -30,7 +30,6 @@ - #endif - - #include --#include "pycore_long.h" // _PyLong_IsZero() - #include "pycore_pystate.h" // _PyThreadState_GET() - #include "pycore_typeobject.h" - #include "complexobject.h" -@@ -179,11 +178,15 @@ - mpd_uint_t data[_Py_DEC_MINALLOC]; - } PyDecObject; - -+#define _PyDecObject_CAST(op) ((PyDecObject *)(op)) -+ - typedef struct { - PyObject_HEAD - uint32_t *flags; - } PyDecSignalDictObject; - -+#define _PyDecSignalDictObject_CAST(op) ((PyDecSignalDictObject *)(op)) -+ - typedef struct PyDecContextObject { - PyObject_HEAD - mpd_context_t ctx; -@@ -194,23 +197,27 @@ - decimal_state *modstate; - } PyDecContextObject; - -+#define _PyDecContextObject_CAST(op) ((PyDecContextObject *)(op)) -+ - typedef struct { - PyObject_HEAD - PyObject *local; - PyObject *global; - } PyDecContextManagerObject; - -+#define _PyDecContextManagerObject_CAST(op) ((PyDecContextManagerObject *)(op)) -+ - #undef MPD - #undef CTX - #define PyDec_CheckExact(st, v) Py_IS_TYPE(v, (st)->PyDec_Type) - #define PyDec_Check(st, v) PyObject_TypeCheck(v, (st)->PyDec_Type) - #define PyDecSignalDict_Check(st, v) Py_IS_TYPE(v, (st)->PyDecSignalDict_Type) - #define PyDecContext_Check(st, v) PyObject_TypeCheck(v, (st)->PyDecContext_Type) --#define MPD(v) (&((PyDecObject *)v)->dec) --#define SdFlagAddr(v) (((PyDecSignalDictObject *)v)->flags) --#define SdFlags(v) (*((PyDecSignalDictObject *)v)->flags) --#define CTX(v) (&((PyDecContextObject *)v)->ctx) --#define CtxCaps(v) (((PyDecContextObject *)v)->capitals) -+#define MPD(v) (&_PyDecObject_CAST(v)->dec) -+#define SdFlagAddr(v) (_PyDecSignalDictObject_CAST(v)->flags) -+#define SdFlags(v) (*_PyDecSignalDictObject_CAST(v)->flags) -+#define CTX(v) (&_PyDecContextObject_CAST(v)->ctx) -+#define CtxCaps(v) (_PyDecContextObject_CAST(v)->capitals) - - static inline decimal_state * - get_module_state_from_ctx(PyObject *v) -@@ -1414,8 +1421,9 @@ - } - - static int --context_traverse(PyDecContextObject *self, visitproc visit, void *arg) -+context_traverse(PyObject *op, visitproc visit, void *arg) - { -+ PyDecContextObject *self = _PyDecContextObject_CAST(op); - Py_VISIT(Py_TYPE(self)); - Py_VISIT(self->traps); - Py_VISIT(self->flags); -@@ -1423,15 +1431,16 @@ - } - - static int --context_clear(PyDecContextObject *self) -+context_clear(PyObject *op) - { -+ PyDecContextObject *self = _PyDecContextObject_CAST(op); - Py_CLEAR(self->traps); - Py_CLEAR(self->flags); - return 0; - } - - static void --context_dealloc(PyDecContextObject *self) -+context_dealloc(PyObject *self) - { - PyTypeObject *tp = Py_TYPE(self); - PyObject_GC_UnTrack(self); -@@ -1474,7 +1483,7 @@ - } - - static PyObject * --context_repr(PyDecContextObject *self) -+context_repr(PyObject *self) - { - mpd_context_t *ctx; - char flags[MPD_MAX_SIGNAL_LIST]; -@@ -1482,7 +1491,7 @@ - int n, mem; - - #ifdef Py_DEBUG -- decimal_state *state = get_module_state_from_ctx((PyObject *)self); -+ decimal_state *state = get_module_state_from_ctx(self); - assert(PyDecContext_Check(state, self)); - #endif - ctx = CTX(self); -@@ -1502,7 +1511,7 @@ - "Context(prec=%zd, rounding=%s, Emin=%zd, Emax=%zd, " - "capitals=%d, clamp=%d, flags=%s, traps=%s)", - ctx->prec, mpd_round_string[ctx->round], ctx->emin, ctx->emax, -- self->capitals, ctx->clamp, flags, traps); -+ CtxCaps(self), ctx->clamp, flags, traps); - } - - static void -@@ -1622,16 +1631,16 @@ - - static PyGetSetDef context_getsets [] = - { -- { "prec", (getter)context_getprec, (setter)context_setprec, NULL, NULL}, -- { "Emax", (getter)context_getemax, (setter)context_setemax, NULL, NULL}, -- { "Emin", (getter)context_getemin, (setter)context_setemin, NULL, NULL}, -- { "rounding", (getter)context_getround, (setter)context_setround, NULL, NULL}, -- { "capitals", (getter)context_getcapitals, (setter)context_setcapitals, NULL, NULL}, -- { "clamp", (getter)context_getclamp, (setter)context_setclamp, NULL, NULL}, -+ { "prec", context_getprec, context_setprec, NULL, NULL}, -+ { "Emax", context_getemax, context_setemax, NULL, NULL}, -+ { "Emin", context_getemin, context_setemin, NULL, NULL}, -+ { "rounding", context_getround, context_setround, NULL, NULL}, -+ { "capitals", context_getcapitals, context_setcapitals, NULL, NULL}, -+ { "clamp", context_getclamp, context_setclamp, NULL, NULL}, - #ifdef EXTRA_FUNCTIONALITY -- { "_allcr", (getter)context_getallcr, (setter)context_setallcr, NULL, NULL}, -- { "_traps", (getter)context_gettraps, (setter)context_settraps, NULL, NULL}, -- { "_flags", (getter)context_getstatus, (setter)context_setstatus, NULL, NULL}, -+ { "_allcr", context_getallcr, context_setallcr, NULL, NULL}, -+ { "_traps", context_gettraps, context_settraps, NULL, NULL}, -+ { "_flags", context_getstatus, context_setstatus, NULL, NULL}, - #endif - {NULL} - }; -@@ -1947,9 +1956,9 @@ - } - - static int --ctxmanager_traverse(PyDecContextManagerObject *self, visitproc visit, -- void *arg) -+ctxmanager_traverse(PyObject *op, visitproc visit, void *arg) - { -+ PyDecContextManagerObject *self = _PyDecContextManagerObject_CAST(op); - Py_VISIT(Py_TYPE(self)); - Py_VISIT(self->local); - Py_VISIT(self->global); -@@ -1957,29 +1966,29 @@ - } - - static int --ctxmanager_clear(PyDecContextManagerObject *self) -+ctxmanager_clear(PyObject *op) - { -+ PyDecContextManagerObject *self = _PyDecContextManagerObject_CAST(op); - Py_CLEAR(self->local); - Py_CLEAR(self->global); - return 0; - } - - static void --ctxmanager_dealloc(PyDecContextManagerObject *self) -+ctxmanager_dealloc(PyObject *self) - { - PyTypeObject *tp = Py_TYPE(self); - PyObject_GC_UnTrack(self); - (void)ctxmanager_clear(self); -- tp->tp_free((PyObject *)self); -+ tp->tp_free(self); - Py_DECREF(tp); - } - - static PyObject * --ctxmanager_set_local(PyDecContextManagerObject *self, -- PyObject *Py_UNUSED(dummy)) -+ctxmanager_set_local(PyObject *op, PyObject *Py_UNUSED(dummy)) - { - PyObject *ret; -- -+ PyDecContextManagerObject *self = _PyDecContextManagerObject_CAST(op); - ret = PyDec_SetCurrentContext(PyType_GetModule(Py_TYPE(self)), self->local); - if (ret == NULL) { - return NULL; -@@ -1990,11 +1999,10 @@ - } - - static PyObject * --ctxmanager_restore_global(PyDecContextManagerObject *self, -- PyObject *Py_UNUSED(args)) -+ctxmanager_restore_global(PyObject *op, PyObject *Py_UNUSED(args)) - { - PyObject *ret; -- -+ PyDecContextManagerObject *self = _PyDecContextManagerObject_CAST(op); - ret = PyDec_SetCurrentContext(PyType_GetModule(Py_TYPE(self)), self->global); - if (ret == NULL) { - return NULL; -@@ -2006,8 +2014,8 @@ - - - static PyMethodDef ctxmanager_methods[] = { -- {"__enter__", (PyCFunction)ctxmanager_set_local, METH_NOARGS, NULL}, -- {"__exit__", (PyCFunction)ctxmanager_restore_global, METH_VARARGS, NULL}, -+ {"__enter__", ctxmanager_set_local, METH_NOARGS, NULL}, -+ {"__exit__", ctxmanager_restore_global, METH_VARARGS, NULL}, - {NULL, NULL} - }; - -@@ -2323,38 +2331,43 @@ - dec_from_long(decimal_state *state, PyTypeObject *type, PyObject *v, - const mpd_context_t *ctx, uint32_t *status) - { -- PyObject *dec; -- PyLongObject *l = (PyLongObject *)v; -+ PyObject *dec = PyDecType_New(state, type); - -- dec = PyDecType_New(state, type); - if (dec == NULL) { - return NULL; - } - -- if (_PyLong_IsZero(l)) { -- _dec_settriple(dec, MPD_POS, 0, 0); -- return dec; -- } -- -- uint8_t sign = _PyLong_IsNegative(l) ? MPD_NEG : MPD_POS; -+ PyLongExport export_long; - -- if (_PyLong_IsCompact(l)) { -- _dec_settriple(dec, sign, l->long_value.ob_digit[0], 0); -- mpd_qfinalize(MPD(dec), ctx, status); -- return dec; -+ if (PyLong_Export(v, &export_long) == -1) { -+ Py_DECREF(dec); -+ return NULL; - } -- size_t len = _PyLong_DigitCount(l); -+ if (export_long.digits) { -+ const PyLongLayout *layout = PyLong_GetNativeLayout(); - --#if PYLONG_BITS_IN_DIGIT == 30 -- mpd_qimport_u32(MPD(dec), l->long_value.ob_digit, len, sign, PyLong_BASE, -- ctx, status); --#elif PYLONG_BITS_IN_DIGIT == 15 -- mpd_qimport_u16(MPD(dec), l->long_value.ob_digit, len, sign, PyLong_BASE, -- ctx, status); --#else -- #error "PYLONG_BITS_IN_DIGIT should be 15 or 30" --#endif -+ assert(layout->bits_per_digit < 32); -+ assert(layout->digits_order == -1); -+ assert(layout->digit_endianness == (PY_LITTLE_ENDIAN ? -1 : 1)); -+ assert(layout->digit_size == 2 || layout->digit_size == 4); - -+ uint32_t base = (uint32_t)1 << layout->bits_per_digit; -+ uint8_t sign = export_long.negative ? MPD_NEG : MPD_POS; -+ Py_ssize_t len = export_long.ndigits; -+ -+ if (layout->digit_size == 4) { -+ mpd_qimport_u32(MPD(dec), export_long.digits, len, sign, -+ base, ctx, status); -+ } -+ else { -+ mpd_qimport_u16(MPD(dec), export_long.digits, len, sign, -+ base, ctx, status); -+ } -+ PyLong_FreeExport(&export_long); -+ } -+ else { -+ mpd_qset_i64(MPD(dec), export_long.value, ctx, status); -+ } - return dec; - } - -@@ -3461,7 +3474,7 @@ - PyObject *u; - - if (state->PyDecimal == NULL) { -- state->PyDecimal = _PyImport_GetModuleAttrString("_pydecimal", "Decimal"); -+ state->PyDecimal = PyImport_ImportModuleAttrString("_pydecimal", "Decimal"); - if (state->PyDecimal == NULL) { - return NULL; - } -@@ -3639,13 +3652,6 @@ - static PyObject * - dec_as_long(PyObject *dec, PyObject *context, int round) - { -- PyLongObject *pylong; -- digit *ob_digit; -- size_t n; -- mpd_t *x; -- mpd_context_t workctx; -- uint32_t status = 0; -- - if (mpd_isspecial(MPD(dec))) { - if (mpd_isnan(MPD(dec))) { - PyErr_SetString(PyExc_ValueError, -@@ -3658,12 +3664,16 @@ - return NULL; - } - -- x = mpd_qnew(); -+ mpd_t *x = mpd_qnew(); -+ - if (x == NULL) { - PyErr_NoMemory(); - return NULL; - } -- workctx = *CTX(context); -+ -+ mpd_context_t workctx = *CTX(context); -+ uint32_t status = 0; -+ - workctx.round = round; - mpd_qround_to_int(x, MPD(dec), &workctx, &status); - if (dec_addstatus(context, status)) { -@@ -3672,34 +3682,56 @@ - } - - status = 0; -- ob_digit = NULL; --#if PYLONG_BITS_IN_DIGIT == 30 -- n = mpd_qexport_u32(&ob_digit, 0, PyLong_BASE, x, &status); --#elif PYLONG_BITS_IN_DIGIT == 15 -- n = mpd_qexport_u16(&ob_digit, 0, PyLong_BASE, x, &status); --#else -- #error "PYLONG_BITS_IN_DIGIT should be 15 or 30" --#endif -+ int64_t val = mpd_qget_i64(x, &status); -+ -+ if (!status) { -+ mpd_del(x); -+ return PyLong_FromInt64(val); -+ } -+ assert(!mpd_iszero(x)); -+ -+ const PyLongLayout *layout = PyLong_GetNativeLayout(); -+ -+ assert(layout->bits_per_digit < 32); -+ assert(layout->digits_order == -1); -+ assert(layout->digit_endianness == (PY_LITTLE_ENDIAN ? -1 : 1)); -+ assert(layout->digit_size == 2 || layout->digit_size == 4); -+ -+ uint32_t base = (uint32_t)1 << layout->bits_per_digit; -+ /* We use a temporary buffer for digits for now, as for nonzero rdata -+ mpd_qexport_u32/u16() require either space "allocated by one of -+ libmpdec’s allocation functions" or "rlen MUST be correct" (to avoid -+ reallocation). This can be further optimized by using rlen from -+ mpd_sizeinbase(). See gh-127925. */ -+ void *tmp_digits = NULL; -+ size_t n; -+ -+ status = 0; -+ if (layout->digit_size == 4) { -+ n = mpd_qexport_u32((uint32_t **)&tmp_digits, 0, base, x, &status); -+ } -+ else { -+ n = mpd_qexport_u16((uint16_t **)&tmp_digits, 0, base, x, &status); -+ } - - if (n == SIZE_MAX) { - PyErr_NoMemory(); - mpd_del(x); -+ mpd_free(tmp_digits); - return NULL; - } - -- if (n == 1) { -- sdigit val = mpd_arith_sign(x) * ob_digit[0]; -- mpd_free(ob_digit); -- mpd_del(x); -- return PyLong_FromLong(val); -- } -+ void *digits; -+ PyLongWriter *writer = PyLongWriter_Create(mpd_isnegative(x), n, &digits); - -- assert(n > 0); -- assert(!mpd_iszero(x)); -- pylong = _PyLong_FromDigits(mpd_isnegative(x), n, ob_digit); -- mpd_free(ob_digit); - mpd_del(x); -- return (PyObject *) pylong; -+ if (writer == NULL) { -+ mpd_free(tmp_digits); -+ return NULL; -+ } -+ memcpy(digits, tmp_digits, layout->digit_size*n); -+ mpd_free(tmp_digits); -+ return PyLongWriter_Finish(writer); - } - - /* Convert a Decimal to its exact integer ratio representation. */ -@@ -5018,8 +5050,8 @@ - - static PyGetSetDef dec_getsets [] = - { -- { "real", (getter)dec_real, NULL, NULL, NULL}, -- { "imag", (getter)dec_imag, NULL, NULL, NULL}, -+ { "real", dec_real, NULL, NULL, NULL}, -+ { "imag", dec_imag, NULL, NULL, NULL}, - {NULL} - }; - -diff --git a/Modules/_decimal/libmpdec/io.c b/Modules/_decimal/libmpdec/io.c -index 4e95b8964c8..bdcca001659 100644 ---- a/Modules/_decimal/libmpdec/io.c -+++ b/Modules/_decimal/libmpdec/io.c -@@ -347,6 +347,10 @@ - or the location of a decimal point. */ - #define EXTRACT_DIGIT(s, x, d, dot) \ - if (s == dot) *s++ = '.'; *s++ = '0' + (char)(x / d); x %= d -+#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && __GNUC__ >= 12 -+ #pragma GCC diagnostic push -+ #pragma GCC diagnostic ignored "-Wstringop-overflow" -+#endif - static inline char * - word_to_string(char *s, mpd_uint_t x, int n, char *dot) - { -@@ -378,6 +382,9 @@ - *s = '\0'; - return s; - } -+#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && __GNUC__ >= 12 -+ #pragma GCC diagnostic pop -+#endif - - /* Print exponent x to string s. Undefined for MPD_SSIZE_MIN. */ - static inline char * -diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c -index 355f322d304..b5b0b82571f 100644 ---- a/Modules/_elementtree.c -+++ b/Modules/_elementtree.c -@@ -16,7 +16,6 @@ - #endif - - #include "Python.h" --#include "pycore_import.h" // _PyImport_GetModuleAttrString() - #include "pycore_pyhash.h" // _Py_HashSecret - - #include // offsetof() -@@ -4393,7 +4392,7 @@ - CREATE_TYPE(m, st->Element_Type, &element_spec); - CREATE_TYPE(m, st->XMLParser_Type, &xmlparser_spec); - -- st->deepcopy_obj = _PyImport_GetModuleAttrString("copy", "deepcopy"); -+ st->deepcopy_obj = PyImport_ImportModuleAttrString("copy", "deepcopy"); - if (st->deepcopy_obj == NULL) { - goto error; - } -@@ -4403,7 +4402,7 @@ - goto error; - - /* link against pyexpat */ -- if (!(st->expat_capsule = _PyImport_GetModuleAttrString("pyexpat", "expat_CAPI"))) -+ if (!(st->expat_capsule = PyImport_ImportModuleAttrString("pyexpat", "expat_CAPI"))) - goto error; - if (!(st->expat_capi = PyCapsule_GetPointer(st->expat_capsule, PyExpat_CAPSULE_NAME))) - goto error; -diff --git a/Modules/_gdbmmodule.c b/Modules/_gdbmmodule.c -index df7fba67810..ab2ebdba924 100644 ---- a/Modules/_gdbmmodule.c -+++ b/Modules/_gdbmmodule.c -@@ -8,10 +8,11 @@ - #endif - - #include "Python.h" -+#include "pycore_pyerrors.h" // _PyErr_SetLocaleString() - #include "gdbm.h" - - #include --#include // free() -+#include // free() - #include - #include - -@@ -33,6 +34,24 @@ - return (_gdbm_state *)state; - } - -+/* -+ * Set the gdbm error obtained by gdbm_strerror(gdbm_errno). -+ * -+ * If no error message exists, a generic (UTF-8) error message -+ * is used instead. -+ */ -+static void -+set_gdbm_error(_gdbm_state *state, const char *generic_error) -+{ -+ const char *gdbm_errmsg = gdbm_strerror(gdbm_errno); -+ if (gdbm_errmsg) { -+ _PyErr_SetLocaleString(state->gdbm_error, gdbm_errmsg); -+ } -+ else { -+ PyErr_SetString(state->gdbm_error, generic_error); -+ } -+} -+ - /*[clinic input] - module _gdbm - class _gdbm.gdbm "gdbmobject *" "&Gdbmtype" -@@ -57,6 +76,8 @@ - GDBM_FILE di_dbm; - } gdbmobject; - -+#define _gdbmobject_CAST(op) ((gdbmobject *)(op)) -+ - #include "clinic/_gdbmmodule.c.h" - - #define check_gdbmobject_open(v, err) \ -@@ -91,7 +112,7 @@ - PyErr_SetFromErrnoWithFilename(state->gdbm_error, file); - } - else { -- PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno)); -+ set_gdbm_error(state, "gdbm_open() error"); - } - Py_DECREF(dp); - return NULL; -@@ -101,27 +122,29 @@ - - /* Methods */ - static int --gdbm_traverse(gdbmobject *dp, visitproc visit, void *arg) -+gdbm_traverse(PyObject *op, visitproc visit, void *arg) - { -- Py_VISIT(Py_TYPE(dp)); -+ Py_VISIT(Py_TYPE(op)); - return 0; - } - - static void --gdbm_dealloc(gdbmobject *dp) -+gdbm_dealloc(PyObject *op) - { -+ gdbmobject *dp = _gdbmobject_CAST(op); -+ PyTypeObject *tp = Py_TYPE(dp); - PyObject_GC_UnTrack(dp); - if (dp->di_dbm) { - gdbm_close(dp->di_dbm); - } -- PyTypeObject *tp = Py_TYPE(dp); - tp->tp_free(dp); - Py_DECREF(tp); - } - - static Py_ssize_t --gdbm_length(gdbmobject *dp) -+gdbm_length(PyObject *op) - { -+ gdbmobject *dp = _gdbmobject_CAST(op); - _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp)); - if (dp->di_dbm == NULL) { - PyErr_SetString(state->gdbm_error, "GDBM object has already been closed"); -@@ -136,7 +159,7 @@ - PyErr_SetFromErrno(state->gdbm_error); - } - else { -- PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno)); -+ set_gdbm_error(state, "gdbm_count() error"); - } - return -1; - } -@@ -166,8 +189,9 @@ - } - - static int --gdbm_bool(gdbmobject *dp) -+gdbm_bool(PyObject *op) - { -+ gdbmobject *dp = _gdbmobject_CAST(op); - _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp)); - if (dp->di_dbm == NULL) { - PyErr_SetString(state->gdbm_error, "GDBM object has already been closed"); -@@ -216,10 +240,11 @@ - } - - static PyObject * --gdbm_subscript(gdbmobject *dp, PyObject *key) -+gdbm_subscript(PyObject *op, PyObject *key) - { - PyObject *v; - datum drec, krec; -+ gdbmobject *dp = _gdbmobject_CAST(op); - _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp)); - - if (!parse_datum(key, &krec, NULL)) { -@@ -256,7 +281,7 @@ - { - PyObject *res; - -- res = gdbm_subscript(self, key); -+ res = gdbm_subscript((PyObject *)self, key); - if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) { - PyErr_Clear(); - return Py_NewRef(default_value); -@@ -265,10 +290,11 @@ - } - - static int --gdbm_ass_sub(gdbmobject *dp, PyObject *v, PyObject *w) -+gdbm_ass_sub(PyObject *op, PyObject *v, PyObject *w) - { - datum krec, drec; - const char *failmsg = "gdbm mappings have bytes or string indices only"; -+ gdbmobject *dp = _gdbmobject_CAST(op); - _gdbm_state *state = PyType_GetModuleState(Py_TYPE(dp)); - - if (!parse_datum(v, &krec, failmsg)) { -@@ -286,7 +312,7 @@ - PyErr_SetObject(PyExc_KeyError, v); - } - else { -- PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno)); -+ set_gdbm_error(state, "gdbm_delete() error"); - } - return -1; - } -@@ -297,11 +323,12 @@ - } - errno = 0; - if (gdbm_store(dp->di_dbm, krec, drec, GDBM_REPLACE) < 0) { -- if (errno != 0) -+ if (errno != 0) { - PyErr_SetFromErrno(state->gdbm_error); -- else -- PyErr_SetString(state->gdbm_error, -- gdbm_strerror(gdbm_errno)); -+ } -+ else { -+ set_gdbm_error(state, "gdbm_store() error"); -+ } - return -1; - } - } -@@ -325,12 +352,12 @@ - { - PyObject *res; - -- res = gdbm_subscript(self, key); -+ res = gdbm_subscript((PyObject *)self, key); - if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) { - PyErr_Clear(); -- if (gdbm_ass_sub(self, key, default_value) < 0) -+ if (gdbm_ass_sub((PyObject *)self, key, default_value) < 0) - return NULL; -- return gdbm_subscript(self, key); -+ return gdbm_subscript((PyObject *)self, key); - } - return res; - } -@@ -534,10 +561,12 @@ - check_gdbmobject_open(self, state->gdbm_error); - errno = 0; - if (gdbm_reorganize(self->di_dbm) < 0) { -- if (errno != 0) -+ if (errno != 0) { - PyErr_SetFromErrno(state->gdbm_error); -- else -- PyErr_SetString(state->gdbm_error, gdbm_strerror(gdbm_errno)); -+ } -+ else { -+ set_gdbm_error(state, "gdbm_reorganize() error"); -+ } - return NULL; - } - Py_RETURN_NONE; -@@ -819,7 +848,7 @@ - static void - _gdbm_module_free(void *module) - { -- _gdbm_module_clear((PyObject *)module); -+ (void)_gdbm_module_clear((PyObject *)module); - } - - static PyModuleDef_Slot _gdbm_module_slots[] = { -diff --git a/Modules/_hacl/Lib_Memzero0.c b/Modules/_hacl/Lib_Memzero0.c -index 5c269d231de..f01568a1386 100644 ---- a/Modules/_hacl/Lib_Memzero0.c -+++ b/Modules/_hacl/Lib_Memzero0.c -@@ -8,6 +8,10 @@ - #include - #endif - -+#if defined(__APPLE__) && defined(__MACH__) -+#include -+#endif -+ - #if (defined(__APPLE__) && defined(__MACH__)) || defined(__linux__) - #define __STDC_WANT_LIB_EXT1__ 1 - #include -@@ -37,7 +41,7 @@ - - #ifdef _WIN32 - SecureZeroMemory(dst, len_); -- #elif defined(__APPLE__) && defined(__MACH__) -+ #elif defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_MIN_REQUIRED) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1090) - memset_s(dst, len_, 0, len_); - #elif (defined(__linux__) && !defined(LINUX_NO_EXPLICIT_BZERO)) || defined(__FreeBSD__) - explicit_bzero(dst, len_); -diff --git a/Modules/_hacl/include/krml/internal/target.h b/Modules/_hacl/include/krml/internal/target.h -index fd74d3da684..9b403c36cec 100644 ---- a/Modules/_hacl/include/krml/internal/target.h -+++ b/Modules/_hacl/include/krml/internal/target.h -@@ -19,6 +19,20 @@ - # define inline __inline__ - #endif - -+/* There is no support for aligned_alloc() in macOS before Catalina, so -+ * let's make a macro to use _mm_malloc() and _mm_free() functions -+ * from mm_malloc.h. */ -+#if defined(__APPLE__) && defined(__MACH__) -+# include -+# if defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \ -+ (MAC_OS_X_VERSION_MIN_REQUIRED < 101500) -+# include -+# define LEGACY_MACOS -+# else -+# undef LEGACY_MACOS -+#endif -+#endif -+ - /******************************************************************************/ - /* Macros that KaRaMeL will generate. */ - /******************************************************************************/ -@@ -133,6 +147,8 @@ - defined(_MSC_VER) || \ - (defined(__MINGW32__) && defined(__MINGW64_VERSION_MAJOR))) - # define KRML_ALIGNED_MALLOC(X, Y) _aligned_malloc(Y, X) -+# elif defined(LEGACY_MACOS) -+# define KRML_ALIGNED_MALLOC(X, Y) _mm_malloc(Y, X) - # else - # define KRML_ALIGNED_MALLOC(X, Y) aligned_alloc(X, Y) - # endif -@@ -150,6 +166,8 @@ - defined(_MSC_VER) || \ - (defined(__MINGW32__) && defined(__MINGW64_VERSION_MAJOR))) - # define KRML_ALIGNED_FREE(X) _aligned_free(X) -+# elif defined(LEGACY_MACOS) -+# define KRML_ALIGNED_FREE(X) _mm_free(X) - # else - # define KRML_ALIGNED_FREE(X) free(X) - # endif -diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c -index 2c9a9feecc7..d7586feea3e 100644 ---- a/Modules/_hashopenssl.c -+++ b/Modules/_hashopenssl.c -@@ -25,13 +25,14 @@ - #include - #include "Python.h" - #include "pycore_hashtable.h" --#include "pycore_strhex.h" // _Py_strhex() -+#include "pycore_strhex.h" // _Py_strhex() -+#include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_LOAD_PTR_RELAXED - #include "hashlib.h" - - /* EVP is the preferred interface to hashing in OpenSSL */ - #include - #include --#include // FIPS_mode() -+#include // FIPS_mode() - /* We use the object interface to discover what hashes OpenSSL supports. */ - #include - #include -@@ -319,6 +320,7 @@ - va_end(vargs); - ERR_clear_error(); - -+ /* ERR_ERROR_STRING(3) ensures that the messages below are ASCII */ - lib = ERR_lib_error_string(errcode); - func = ERR_func_error_string(errcode); - reason = ERR_reason_error_string(errcode); -@@ -368,6 +370,7 @@ - py_digest_by_name(PyObject *module, const char *name, enum Py_hash_type py_ht) - { - PY_EVP_MD *digest = NULL; -+ PY_EVP_MD *other_digest = NULL; - _hashlibstate *state = get_hashlib_state(module); - py_hashentry_t *entry = (py_hashentry_t *)_Py_hashtable_get( - state->hashtable, (const void*)name -@@ -378,20 +381,36 @@ - case Py_ht_evp: - case Py_ht_mac: - case Py_ht_pbkdf2: -- if (entry->evp == NULL) { -- entry->evp = PY_EVP_MD_fetch(entry->ossl_name, NULL); -+ digest = FT_ATOMIC_LOAD_PTR_RELAXED(entry->evp); -+ if (digest == NULL) { -+ digest = PY_EVP_MD_fetch(entry->ossl_name, NULL); -+#ifdef Py_GIL_DISABLED -+ // exchange just in case another thread did same thing at same time -+ other_digest = _Py_atomic_exchange_ptr(&entry->evp, digest); -+#else -+ entry->evp = digest; -+#endif - } -- digest = entry->evp; - break; - case Py_ht_evp_nosecurity: -- if (entry->evp_nosecurity == NULL) { -- entry->evp_nosecurity = PY_EVP_MD_fetch(entry->ossl_name, "-fips"); -+ digest = FT_ATOMIC_LOAD_PTR_RELAXED(entry->evp_nosecurity); -+ if (digest == NULL) { -+ digest = PY_EVP_MD_fetch(entry->ossl_name, "-fips"); -+#ifdef Py_GIL_DISABLED -+ // exchange just in case another thread did same thing at same time -+ other_digest = _Py_atomic_exchange_ptr(&entry->evp_nosecurity, digest); -+#else -+ entry->evp_nosecurity = digest; -+#endif - } -- digest = entry->evp_nosecurity; - break; - } -+ // if another thread same thing at same time make sure we got same ptr -+ assert(other_digest == NULL || other_digest == digest); - if (digest != NULL) { -- PY_EVP_MD_up_ref(digest); -+ if (other_digest == NULL) { -+ PY_EVP_MD_up_ref(digest); -+ } - } - } else { - // Fall back for looking up an unindexed OpenSSL specific name. -diff --git a/Modules/_interpretersmodule.c b/Modules/_interpretersmodule.c -index a36823c4bb9..fcd0baf696f 100644 ---- a/Modules/_interpretersmodule.c -+++ b/Modules/_interpretersmodule.c -@@ -459,7 +459,12 @@ - - // Prep and switch interpreters. - if (_PyXI_Enter(&session, interp, shareables) < 0) { -- assert(!PyErr_Occurred()); -+ if (PyErr_Occurred()) { -+ // If an error occured at this step, it means that interp -+ // was not prepared and switched. -+ return -1; -+ } -+ // Now, apply the error from another interpreter: - PyObject *excinfo = _PyXI_ApplyError(session.error); - if (excinfo != NULL) { - *p_excinfo = excinfo; -diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c -index bc5fff54a62..53c4702f673 100644 ---- a/Modules/_io/bufferedio.c -+++ b/Modules/_io/bufferedio.c -@@ -261,6 +261,8 @@ - PyObject *weakreflist; - } buffered; - -+#define buffered_CAST(op) ((buffered *)(op)) -+ - /* - Implementation notes: - -@@ -399,8 +401,9 @@ - - - static int --buffered_clear(buffered *self) -+buffered_clear(PyObject *op) - { -+ buffered *self = buffered_CAST(op); - self->ok = 0; - Py_CLEAR(self->raw); - Py_CLEAR(self->dict); -@@ -408,16 +411,17 @@ - } - - static void --buffered_dealloc(buffered *self) -+buffered_dealloc(PyObject *op) - { -+ buffered *self = buffered_CAST(op); - PyTypeObject *tp = Py_TYPE(self); - self->finalizing = 1; -- if (_PyIOBase_finalize((PyObject *) self) < 0) -+ if (_PyIOBase_finalize(op) < 0) - return; - _PyObject_GC_UNTRACK(self); - self->ok = 0; - if (self->weakreflist != NULL) -- PyObject_ClearWeakRefs((PyObject *)self); -+ PyObject_ClearWeakRefs(op); - if (self->buffer) { - PyMem_Free(self->buffer); - self->buffer = NULL; -@@ -426,8 +430,8 @@ - PyThread_free_lock(self->lock); - self->lock = NULL; - } -- (void)buffered_clear(self); -- tp->tp_free((PyObject *)self); -+ (void)buffered_clear(op); -+ tp->tp_free(self); - Py_DECREF(tp); - } - -@@ -2227,6 +2231,8 @@ - PyObject *weakreflist; - } rwpair; - -+#define rwpair_CAST(op) ((rwpair *)(op)) -+ - /*[clinic input] - _io.BufferedRWPair.__init__ - reader: object -@@ -2276,8 +2282,9 @@ - } - - static int --bufferedrwpair_traverse(rwpair *self, visitproc visit, void *arg) -+bufferedrwpair_traverse(PyObject *op, visitproc visit, void *arg) - { -+ rwpair *self = rwpair_CAST(op); - Py_VISIT(Py_TYPE(self)); - Py_VISIT(self->dict); - Py_VISIT(self->reader); -@@ -2286,8 +2293,9 @@ - } - - static int --bufferedrwpair_clear(rwpair *self) -+bufferedrwpair_clear(PyObject *op) - { -+ rwpair *self = rwpair_CAST(op); - Py_CLEAR(self->reader); - Py_CLEAR(self->writer); - Py_CLEAR(self->dict); -@@ -2295,14 +2303,15 @@ - } - - static void --bufferedrwpair_dealloc(rwpair *self) -+bufferedrwpair_dealloc(PyObject *op) - { -+ rwpair *self = rwpair_CAST(op); - PyTypeObject *tp = Py_TYPE(self); - _PyObject_GC_UNTRACK(self); - if (self->weakreflist != NULL) -- PyObject_ClearWeakRefs((PyObject *)self); -- (void)bufferedrwpair_clear(self); -- tp->tp_free((PyObject *) self); -+ PyObject_ClearWeakRefs(op); -+ (void)bufferedrwpair_clear(op); -+ tp->tp_free(self); - Py_DECREF(tp); - } - -@@ -2328,62 +2337,72 @@ - } - - static PyObject * --bufferedrwpair_read(rwpair *self, PyObject *args) -+bufferedrwpair_read(PyObject *op, PyObject *args) - { -+ rwpair *self = rwpair_CAST(op); - return _forward_call(self->reader, &_Py_ID(read), args); - } - - static PyObject * --bufferedrwpair_peek(rwpair *self, PyObject *args) -+bufferedrwpair_peek(PyObject *op, PyObject *args) - { -+ rwpair *self = rwpair_CAST(op); - return _forward_call(self->reader, &_Py_ID(peek), args); - } - - static PyObject * --bufferedrwpair_read1(rwpair *self, PyObject *args) -+bufferedrwpair_read1(PyObject *op, PyObject *args) - { -+ rwpair *self = rwpair_CAST(op); - return _forward_call(self->reader, &_Py_ID(read1), args); - } - - static PyObject * --bufferedrwpair_readinto(rwpair *self, PyObject *args) -+bufferedrwpair_readinto(PyObject *op, PyObject *args) - { -+ rwpair *self = rwpair_CAST(op); - return _forward_call(self->reader, &_Py_ID(readinto), args); - } - - static PyObject * --bufferedrwpair_readinto1(rwpair *self, PyObject *args) -+bufferedrwpair_readinto1(PyObject *op, PyObject *args) - { -+ rwpair *self = rwpair_CAST(op); - return _forward_call(self->reader, &_Py_ID(readinto1), args); - } - - static PyObject * --bufferedrwpair_write(rwpair *self, PyObject *args) -+bufferedrwpair_write(PyObject *op, PyObject *args) - { -+ rwpair *self = rwpair_CAST(op); - return _forward_call(self->writer, &_Py_ID(write), args); - } - - static PyObject * --bufferedrwpair_flush(rwpair *self, PyObject *Py_UNUSED(ignored)) -+bufferedrwpair_flush(PyObject *op, PyObject *Py_UNUSED(dummy)) - { -+ rwpair *self = rwpair_CAST(op); - return _forward_call(self->writer, &_Py_ID(flush), NULL); - } - - static PyObject * --bufferedrwpair_readable(rwpair *self, PyObject *Py_UNUSED(ignored)) -+bufferedrwpair_readable(PyObject *op, PyObject *Py_UNUSED(dummy)) - { -+ rwpair *self = rwpair_CAST(op); - return _forward_call(self->reader, &_Py_ID(readable), NULL); - } - - static PyObject * --bufferedrwpair_writable(rwpair *self, PyObject *Py_UNUSED(ignored)) -+bufferedrwpair_writable(PyObject *op, PyObject *Py_UNUSED(dummy)) - { -+ rwpair *self = rwpair_CAST(op); - return _forward_call(self->writer, &_Py_ID(writable), NULL); - } - - static PyObject * --bufferedrwpair_close(rwpair *self, PyObject *Py_UNUSED(ignored)) -+bufferedrwpair_close(PyObject *op, PyObject *Py_UNUSED(dummy)) - { -+ rwpair *self = rwpair_CAST(op); - PyObject *exc = NULL; - PyObject *ret = _forward_call(self->writer, &_Py_ID(close), NULL); - if (ret == NULL) { -@@ -2401,8 +2420,9 @@ - } - - static PyObject * --bufferedrwpair_isatty(rwpair *self, PyObject *Py_UNUSED(ignored)) -+bufferedrwpair_isatty(PyObject *op, PyObject *Py_UNUSED(dummy)) - { -+ rwpair *self = rwpair_CAST(op); - PyObject *ret = _forward_call(self->writer, &_Py_ID(isatty), NULL); - - if (ret != Py_False) { -@@ -2415,8 +2435,9 @@ - } - - static PyObject * --bufferedrwpair_closed_get(rwpair *self, void *context) -+bufferedrwpair_closed_get(PyObject *op, void *Py_UNUSED(dummy)) - { -+ rwpair *self = rwpair_CAST(op); - if (self->writer == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "the BufferedRWPair object is being garbage-collected"); -@@ -2633,20 +2654,20 @@ - }; - - static PyMethodDef bufferedrwpair_methods[] = { -- {"read", (PyCFunction)bufferedrwpair_read, METH_VARARGS}, -- {"peek", (PyCFunction)bufferedrwpair_peek, METH_VARARGS}, -- {"read1", (PyCFunction)bufferedrwpair_read1, METH_VARARGS}, -- {"readinto", (PyCFunction)bufferedrwpair_readinto, METH_VARARGS}, -- {"readinto1", (PyCFunction)bufferedrwpair_readinto1, METH_VARARGS}, -+ {"read", bufferedrwpair_read, METH_VARARGS}, -+ {"peek", bufferedrwpair_peek, METH_VARARGS}, -+ {"read1", bufferedrwpair_read1, METH_VARARGS}, -+ {"readinto", bufferedrwpair_readinto, METH_VARARGS}, -+ {"readinto1", bufferedrwpair_readinto1, METH_VARARGS}, - -- {"write", (PyCFunction)bufferedrwpair_write, METH_VARARGS}, -- {"flush", (PyCFunction)bufferedrwpair_flush, METH_NOARGS}, -+ {"write", bufferedrwpair_write, METH_VARARGS}, -+ {"flush", bufferedrwpair_flush, METH_NOARGS}, - -- {"readable", (PyCFunction)bufferedrwpair_readable, METH_NOARGS}, -- {"writable", (PyCFunction)bufferedrwpair_writable, METH_NOARGS}, -+ {"readable", bufferedrwpair_readable, METH_NOARGS}, -+ {"writable", bufferedrwpair_writable, METH_NOARGS}, - -- {"close", (PyCFunction)bufferedrwpair_close, METH_NOARGS}, -- {"isatty", (PyCFunction)bufferedrwpair_isatty, METH_NOARGS}, -+ {"close", bufferedrwpair_close, METH_NOARGS}, -+ {"isatty", bufferedrwpair_isatty, METH_NOARGS}, - - {NULL, NULL} - }; -@@ -2658,7 +2679,7 @@ - }; - - static PyGetSetDef bufferedrwpair_getset[] = { -- {"closed", (getter)bufferedrwpair_closed_get, NULL, NULL}, -+ {"closed", bufferedrwpair_closed_get, NULL, NULL}, - {NULL} - }; - -diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c -index fb66d3db0f7..dc4e40b9f09 100644 ---- a/Modules/_io/bytesio.c -+++ b/Modules/_io/bytesio.c -@@ -21,11 +21,15 @@ - Py_ssize_t exports; - } bytesio; - -+#define bytesio_CAST(op) ((bytesio *)(op)) -+ - typedef struct { - PyObject_HEAD - bytesio *source; - } bytesiobuf; - -+#define bytesiobuf_CAST(op) ((bytesiobuf *)(op)) -+ - /* The bytesio object can be in three states: - * Py_REFCNT(buf) == 1, exports == 0. - * Py_REFCNT(buf) > 1. exports == 0, -@@ -239,8 +243,9 @@ - } - - static PyObject * --bytesio_get_closed(bytesio *self, void *Py_UNUSED(ignored)) -+bytesio_get_closed(PyObject *op, void *Py_UNUSED(closure)) - { -+ bytesio *self = bytesio_CAST(op); - if (self->buf == NULL) { - Py_RETURN_TRUE; - } -@@ -588,7 +593,7 @@ - - /*[clinic input] - _io.BytesIO.truncate -- size: Py_ssize_t(accept={int, NoneType}, c_default="self->pos") = None -+ size: Py_ssize_t(accept={int, NoneType}, c_default="((bytesio *)self)->pos") = None - / - - Truncate the file to at most size bytes. -@@ -599,7 +604,7 @@ - - static PyObject * - _io_BytesIO_truncate_impl(bytesio *self, Py_ssize_t size) --/*[clinic end generated code: output=9ad17650c15fa09b input=423759dd42d2f7c1]*/ -+/*[clinic end generated code: output=9ad17650c15fa09b input=dae4295e11c1bbb4]*/ - { - CHECK_CLOSED(self); - CHECK_EXPORTS(self); -@@ -620,9 +625,10 @@ - } - - static PyObject * --bytesio_iternext(bytesio *self) -+bytesio_iternext(PyObject *op) - { - Py_ssize_t n; -+ bytesio *self = bytesio_CAST(op); - - CHECK_CLOSED(self); - -@@ -783,8 +789,9 @@ - */ - - static PyObject * --bytesio_getstate(bytesio *self, PyObject *Py_UNUSED(ignored)) -+bytesio_getstate(PyObject *op, PyObject *Py_UNUSED(dummy)) - { -+ bytesio *self = bytesio_CAST(op); - PyObject *initvalue = _io_BytesIO_getvalue_impl(self); - PyObject *dict; - PyObject *state; -@@ -808,12 +815,13 @@ - } - - static PyObject * --bytesio_setstate(bytesio *self, PyObject *state) -+bytesio_setstate(PyObject *op, PyObject *state) - { - PyObject *result; - PyObject *position_obj; - PyObject *dict; - Py_ssize_t pos; -+ bytesio *self = bytesio_CAST(op); - - assert(state != NULL); - -@@ -883,8 +891,9 @@ - } - - static void --bytesio_dealloc(bytesio *self) -+bytesio_dealloc(PyObject *op) - { -+ bytesio *self = bytesio_CAST(op); - PyTypeObject *tp = Py_TYPE(self); - _PyObject_GC_UNTRACK(self); - if (self->exports > 0) { -@@ -895,7 +904,7 @@ - Py_CLEAR(self->buf); - Py_CLEAR(self->dict); - if (self->weakreflist != NULL) -- PyObject_ClearWeakRefs((PyObject *) self); -+ PyObject_ClearWeakRefs(op); - tp->tp_free(self); - Py_DECREF(tp); - } -@@ -961,8 +970,9 @@ - } - - static PyObject * --bytesio_sizeof(bytesio *self, void *unused) -+bytesio_sizeof(PyObject *op, PyObject *Py_UNUSED(dummy)) - { -+ bytesio *self = bytesio_CAST(op); - size_t res = _PyObject_SIZE(Py_TYPE(self)); - if (self->buf && !SHARED_BUF(self)) { - size_t s = _PySys_GetSizeOf(self->buf); -@@ -975,8 +985,9 @@ - } - - static int --bytesio_traverse(bytesio *self, visitproc visit, void *arg) -+bytesio_traverse(PyObject *op, visitproc visit, void *arg) - { -+ bytesio *self = bytesio_CAST(op); - Py_VISIT(Py_TYPE(self)); - Py_VISIT(self->dict); - Py_VISIT(self->buf); -@@ -984,8 +995,9 @@ - } - - static int --bytesio_clear(bytesio *self) -+bytesio_clear(PyObject *op) - { -+ bytesio *self = bytesio_CAST(op); - Py_CLEAR(self->dict); - if (self->exports == 0) { - Py_CLEAR(self->buf); -@@ -999,7 +1011,7 @@ - #undef clinic_state - - static PyGetSetDef bytesio_getsetlist[] = { -- {"closed", (getter)bytesio_get_closed, NULL, -+ {"closed", bytesio_get_closed, NULL, - "True if the file is closed."}, - {NULL}, /* sentinel */ - }; -@@ -1023,9 +1035,9 @@ - _IO_BYTESIO_GETVALUE_METHODDEF - _IO_BYTESIO_SEEK_METHODDEF - _IO_BYTESIO_TRUNCATE_METHODDEF -- {"__getstate__", (PyCFunction)bytesio_getstate, METH_NOARGS, NULL}, -- {"__setstate__", (PyCFunction)bytesio_setstate, METH_O, NULL}, -- {"__sizeof__", (PyCFunction)bytesio_sizeof, METH_NOARGS, NULL}, -+ {"__getstate__", bytesio_getstate, METH_NOARGS, NULL}, -+ {"__setstate__", bytesio_setstate, METH_O, NULL}, -+ {"__sizeof__", bytesio_sizeof, METH_NOARGS, NULL}, - {NULL, NULL} /* sentinel */ - }; - -@@ -1065,9 +1077,10 @@ - */ - - static int --bytesiobuf_getbuffer(bytesiobuf *obj, Py_buffer *view, int flags) -+bytesiobuf_getbuffer(PyObject *op, Py_buffer *view, int flags) - { -- bytesio *b = (bytesio *) obj->source; -+ bytesiobuf *obj = bytesiobuf_CAST(op); -+ bytesio *b = bytesio_CAST(obj->source); - - if (view == NULL) { - PyErr_SetString(PyExc_BufferError, -@@ -1080,7 +1093,7 @@ - } - - /* cannot fail if view != NULL and readonly == 0 */ -- (void)PyBuffer_FillInfo(view, (PyObject*)obj, -+ (void)PyBuffer_FillInfo(view, op, - PyBytes_AS_STRING(b->buf), b->string_size, - 0, flags); - b->exports++; -@@ -1088,26 +1101,29 @@ - } - - static void --bytesiobuf_releasebuffer(bytesiobuf *obj, Py_buffer *view) -+bytesiobuf_releasebuffer(PyObject *op, Py_buffer *Py_UNUSED(view)) - { -- bytesio *b = (bytesio *) obj->source; -+ bytesiobuf *obj = bytesiobuf_CAST(op); -+ bytesio *b = bytesio_CAST(obj->source); - b->exports--; - } - - static int --bytesiobuf_traverse(bytesiobuf *self, visitproc visit, void *arg) -+bytesiobuf_traverse(PyObject *op, visitproc visit, void *arg) - { -+ bytesiobuf *self = bytesiobuf_CAST(op); - Py_VISIT(Py_TYPE(self)); - Py_VISIT(self->source); - return 0; - } - - static void --bytesiobuf_dealloc(bytesiobuf *self) -+bytesiobuf_dealloc(PyObject *op) - { -+ bytesiobuf *self = bytesiobuf_CAST(op); - PyTypeObject *tp = Py_TYPE(self); - /* bpo-31095: UnTrack is needed before calling any callbacks */ -- PyObject_GC_UnTrack(self); -+ PyObject_GC_UnTrack(op); - Py_CLEAR(self->source); - tp->tp_free(self); - Py_DECREF(tp); -diff --git a/Modules/_io/clinic/bufferedio.c.h b/Modules/_io/clinic/bufferedio.c.h -index e035bd99bac..8ab8000fafe 100644 ---- a/Modules/_io/clinic/bufferedio.c.h -+++ b/Modules/_io/clinic/bufferedio.c.h -@@ -288,12 +288,12 @@ - _io__Buffered___sizeof___impl(buffered *self); - - static PyObject * --_io__Buffered___sizeof__(buffered *self, PyObject *Py_UNUSED(ignored)) -+_io__Buffered___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io__Buffered___sizeof___impl(self); -+ return_value = _io__Buffered___sizeof___impl((buffered *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -319,12 +319,12 @@ - _io__Buffered_simple_flush_impl(buffered *self); - - static PyObject * --_io__Buffered_simple_flush(buffered *self, PyObject *Py_UNUSED(ignored)) -+_io__Buffered_simple_flush(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io__Buffered_simple_flush_impl(self); -+ return_value = _io__Buffered_simple_flush_impl((buffered *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -344,12 +344,12 @@ - _io__Buffered_closed_get_impl(buffered *self); - - static PyObject * --_io__Buffered_closed_get(buffered *self, void *Py_UNUSED(context)) -+_io__Buffered_closed_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io__Buffered_closed_get_impl(self); -+ return_value = _io__Buffered_closed_get_impl((buffered *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -367,12 +367,12 @@ - _io__Buffered_close_impl(buffered *self); - - static PyObject * --_io__Buffered_close(buffered *self, PyObject *Py_UNUSED(ignored)) -+_io__Buffered_close(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io__Buffered_close_impl(self); -+ return_value = _io__Buffered_close_impl((buffered *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -390,12 +390,12 @@ - _io__Buffered_detach_impl(buffered *self); - - static PyObject * --_io__Buffered_detach(buffered *self, PyObject *Py_UNUSED(ignored)) -+_io__Buffered_detach(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io__Buffered_detach_impl(self); -+ return_value = _io__Buffered_detach_impl((buffered *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -413,12 +413,12 @@ - _io__Buffered_seekable_impl(buffered *self); - - static PyObject * --_io__Buffered_seekable(buffered *self, PyObject *Py_UNUSED(ignored)) -+_io__Buffered_seekable(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io__Buffered_seekable_impl(self); -+ return_value = _io__Buffered_seekable_impl((buffered *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -436,12 +436,12 @@ - _io__Buffered_readable_impl(buffered *self); - - static PyObject * --_io__Buffered_readable(buffered *self, PyObject *Py_UNUSED(ignored)) -+_io__Buffered_readable(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io__Buffered_readable_impl(self); -+ return_value = _io__Buffered_readable_impl((buffered *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -459,12 +459,12 @@ - _io__Buffered_writable_impl(buffered *self); - - static PyObject * --_io__Buffered_writable(buffered *self, PyObject *Py_UNUSED(ignored)) -+_io__Buffered_writable(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io__Buffered_writable_impl(self); -+ return_value = _io__Buffered_writable_impl((buffered *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -484,12 +484,12 @@ - _io__Buffered_name_get_impl(buffered *self); - - static PyObject * --_io__Buffered_name_get(buffered *self, void *Py_UNUSED(context)) -+_io__Buffered_name_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io__Buffered_name_get_impl(self); -+ return_value = _io__Buffered_name_get_impl((buffered *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -509,12 +509,12 @@ - _io__Buffered_mode_get_impl(buffered *self); - - static PyObject * --_io__Buffered_mode_get(buffered *self, void *Py_UNUSED(context)) -+_io__Buffered_mode_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io__Buffered_mode_get_impl(self); -+ return_value = _io__Buffered_mode_get_impl((buffered *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -532,12 +532,12 @@ - _io__Buffered_fileno_impl(buffered *self); - - static PyObject * --_io__Buffered_fileno(buffered *self, PyObject *Py_UNUSED(ignored)) -+_io__Buffered_fileno(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io__Buffered_fileno_impl(self); -+ return_value = _io__Buffered_fileno_impl((buffered *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -555,12 +555,12 @@ - _io__Buffered_isatty_impl(buffered *self); - - static PyObject * --_io__Buffered_isatty(buffered *self, PyObject *Py_UNUSED(ignored)) -+_io__Buffered_isatty(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io__Buffered_isatty_impl(self); -+ return_value = _io__Buffered_isatty_impl((buffered *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -578,12 +578,12 @@ - _io__Buffered_flush_impl(buffered *self); - - static PyObject * --_io__Buffered_flush(buffered *self, PyObject *Py_UNUSED(ignored)) -+_io__Buffered_flush(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io__Buffered_flush_impl(self); -+ return_value = _io__Buffered_flush_impl((buffered *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -601,7 +601,7 @@ - _io__Buffered_peek_impl(buffered *self, Py_ssize_t size); - - static PyObject * --_io__Buffered_peek(buffered *self, PyObject *const *args, Py_ssize_t nargs) -+_io__Buffered_peek(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - Py_ssize_t size = 0; -@@ -626,7 +626,7 @@ - } - skip_optional: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io__Buffered_peek_impl(self, size); -+ return_value = _io__Buffered_peek_impl((buffered *)self, size); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -645,7 +645,7 @@ - _io__Buffered_read_impl(buffered *self, Py_ssize_t n); - - static PyObject * --_io__Buffered_read(buffered *self, PyObject *const *args, Py_ssize_t nargs) -+_io__Buffered_read(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - Py_ssize_t n = -1; -@@ -661,7 +661,7 @@ - } - skip_optional: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io__Buffered_read_impl(self, n); -+ return_value = _io__Buffered_read_impl((buffered *)self, n); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -680,7 +680,7 @@ - _io__Buffered_read1_impl(buffered *self, Py_ssize_t n); - - static PyObject * --_io__Buffered_read1(buffered *self, PyObject *const *args, Py_ssize_t nargs) -+_io__Buffered_read1(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - Py_ssize_t n = -1; -@@ -705,7 +705,7 @@ - } - skip_optional: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io__Buffered_read1_impl(self, n); -+ return_value = _io__Buffered_read1_impl((buffered *)self, n); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -724,7 +724,7 @@ - _io__Buffered_readinto_impl(buffered *self, Py_buffer *buffer); - - static PyObject * --_io__Buffered_readinto(buffered *self, PyObject *arg) -+_io__Buffered_readinto(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - Py_buffer buffer = {NULL, NULL}; -@@ -734,7 +734,7 @@ - goto exit; - } - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io__Buffered_readinto_impl(self, &buffer); -+ return_value = _io__Buffered_readinto_impl((buffered *)self, &buffer); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -758,7 +758,7 @@ - _io__Buffered_readinto1_impl(buffered *self, Py_buffer *buffer); - - static PyObject * --_io__Buffered_readinto1(buffered *self, PyObject *arg) -+_io__Buffered_readinto1(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - Py_buffer buffer = {NULL, NULL}; -@@ -768,7 +768,7 @@ - goto exit; - } - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io__Buffered_readinto1_impl(self, &buffer); -+ return_value = _io__Buffered_readinto1_impl((buffered *)self, &buffer); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -792,7 +792,7 @@ - _io__Buffered_readline_impl(buffered *self, Py_ssize_t size); - - static PyObject * --_io__Buffered_readline(buffered *self, PyObject *const *args, Py_ssize_t nargs) -+_io__Buffered_readline(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - Py_ssize_t size = -1; -@@ -808,7 +808,7 @@ - } - skip_optional: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io__Buffered_readline_impl(self, size); -+ return_value = _io__Buffered_readline_impl((buffered *)self, size); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -827,12 +827,12 @@ - _io__Buffered_tell_impl(buffered *self); - - static PyObject * --_io__Buffered_tell(buffered *self, PyObject *Py_UNUSED(ignored)) -+_io__Buffered_tell(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io__Buffered_tell_impl(self); -+ return_value = _io__Buffered_tell_impl((buffered *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -850,7 +850,7 @@ - _io__Buffered_seek_impl(buffered *self, PyObject *targetobj, int whence); - - static PyObject * --_io__Buffered_seek(buffered *self, PyObject *const *args, Py_ssize_t nargs) -+_io__Buffered_seek(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *targetobj; -@@ -869,7 +869,7 @@ - } - skip_optional: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io__Buffered_seek_impl(self, targetobj, whence); -+ return_value = _io__Buffered_seek_impl((buffered *)self, targetobj, whence); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -888,7 +888,7 @@ - _io__Buffered_truncate_impl(buffered *self, PyTypeObject *cls, PyObject *pos); - - static PyObject * --_io__Buffered_truncate(buffered *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_io__Buffered_truncate(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -918,7 +918,7 @@ - pos = args[0]; - skip_optional_posonly: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io__Buffered_truncate_impl(self, cls, pos); -+ return_value = _io__Buffered_truncate_impl((buffered *)self, cls, pos); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -1089,7 +1089,7 @@ - _io_BufferedWriter_write_impl(buffered *self, Py_buffer *buffer); - - static PyObject * --_io_BufferedWriter_write(buffered *self, PyObject *arg) -+_io_BufferedWriter_write(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - Py_buffer buffer = {NULL, NULL}; -@@ -1098,7 +1098,7 @@ - goto exit; - } - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_BufferedWriter_write_impl(self, &buffer); -+ return_value = _io_BufferedWriter_write_impl((buffered *)self, &buffer); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -1246,4 +1246,4 @@ - exit: - return return_value; - } --/*[clinic end generated code: output=8f28a97987a9fbe1 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=f019d29701ba2556 input=a9049054013a1b77]*/ -diff --git a/Modules/_io/clinic/bytesio.c.h b/Modules/_io/clinic/bytesio.c.h -index 98d88698c5e..5528df952c3 100644 ---- a/Modules/_io/clinic/bytesio.c.h -+++ b/Modules/_io/clinic/bytesio.c.h -@@ -22,9 +22,9 @@ - _io_BytesIO_readable_impl(bytesio *self); - - static PyObject * --_io_BytesIO_readable(bytesio *self, PyObject *Py_UNUSED(ignored)) -+_io_BytesIO_readable(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _io_BytesIO_readable_impl(self); -+ return _io_BytesIO_readable_impl((bytesio *)self); - } - - PyDoc_STRVAR(_io_BytesIO_writable__doc__, -@@ -40,9 +40,9 @@ - _io_BytesIO_writable_impl(bytesio *self); - - static PyObject * --_io_BytesIO_writable(bytesio *self, PyObject *Py_UNUSED(ignored)) -+_io_BytesIO_writable(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _io_BytesIO_writable_impl(self); -+ return _io_BytesIO_writable_impl((bytesio *)self); - } - - PyDoc_STRVAR(_io_BytesIO_seekable__doc__, -@@ -58,9 +58,9 @@ - _io_BytesIO_seekable_impl(bytesio *self); - - static PyObject * --_io_BytesIO_seekable(bytesio *self, PyObject *Py_UNUSED(ignored)) -+_io_BytesIO_seekable(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _io_BytesIO_seekable_impl(self); -+ return _io_BytesIO_seekable_impl((bytesio *)self); - } - - PyDoc_STRVAR(_io_BytesIO_flush__doc__, -@@ -76,9 +76,9 @@ - _io_BytesIO_flush_impl(bytesio *self); - - static PyObject * --_io_BytesIO_flush(bytesio *self, PyObject *Py_UNUSED(ignored)) -+_io_BytesIO_flush(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _io_BytesIO_flush_impl(self); -+ return _io_BytesIO_flush_impl((bytesio *)self); - } - - PyDoc_STRVAR(_io_BytesIO_getbuffer__doc__, -@@ -94,13 +94,13 @@ - _io_BytesIO_getbuffer_impl(bytesio *self, PyTypeObject *cls); - - static PyObject * --_io_BytesIO_getbuffer(bytesio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_io_BytesIO_getbuffer(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "getbuffer() takes no arguments"); - return NULL; - } -- return _io_BytesIO_getbuffer_impl(self, cls); -+ return _io_BytesIO_getbuffer_impl((bytesio *)self, cls); - } - - PyDoc_STRVAR(_io_BytesIO_getvalue__doc__, -@@ -116,9 +116,9 @@ - _io_BytesIO_getvalue_impl(bytesio *self); - - static PyObject * --_io_BytesIO_getvalue(bytesio *self, PyObject *Py_UNUSED(ignored)) -+_io_BytesIO_getvalue(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _io_BytesIO_getvalue_impl(self); -+ return _io_BytesIO_getvalue_impl((bytesio *)self); - } - - PyDoc_STRVAR(_io_BytesIO_isatty__doc__, -@@ -136,9 +136,9 @@ - _io_BytesIO_isatty_impl(bytesio *self); - - static PyObject * --_io_BytesIO_isatty(bytesio *self, PyObject *Py_UNUSED(ignored)) -+_io_BytesIO_isatty(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _io_BytesIO_isatty_impl(self); -+ return _io_BytesIO_isatty_impl((bytesio *)self); - } - - PyDoc_STRVAR(_io_BytesIO_tell__doc__, -@@ -154,9 +154,9 @@ - _io_BytesIO_tell_impl(bytesio *self); - - static PyObject * --_io_BytesIO_tell(bytesio *self, PyObject *Py_UNUSED(ignored)) -+_io_BytesIO_tell(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _io_BytesIO_tell_impl(self); -+ return _io_BytesIO_tell_impl((bytesio *)self); - } - - PyDoc_STRVAR(_io_BytesIO_read__doc__, -@@ -175,7 +175,7 @@ - _io_BytesIO_read_impl(bytesio *self, Py_ssize_t size); - - static PyObject * --_io_BytesIO_read(bytesio *self, PyObject *const *args, Py_ssize_t nargs) -+_io_BytesIO_read(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - Py_ssize_t size = -1; -@@ -190,7 +190,7 @@ - goto exit; - } - skip_optional: -- return_value = _io_BytesIO_read_impl(self, size); -+ return_value = _io_BytesIO_read_impl((bytesio *)self, size); - - exit: - return return_value; -@@ -212,7 +212,7 @@ - _io_BytesIO_read1_impl(bytesio *self, Py_ssize_t size); - - static PyObject * --_io_BytesIO_read1(bytesio *self, PyObject *const *args, Py_ssize_t nargs) -+_io_BytesIO_read1(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - Py_ssize_t size = -1; -@@ -227,7 +227,7 @@ - goto exit; - } - skip_optional: -- return_value = _io_BytesIO_read1_impl(self, size); -+ return_value = _io_BytesIO_read1_impl((bytesio *)self, size); - - exit: - return return_value; -@@ -250,7 +250,7 @@ - _io_BytesIO_readline_impl(bytesio *self, Py_ssize_t size); - - static PyObject * --_io_BytesIO_readline(bytesio *self, PyObject *const *args, Py_ssize_t nargs) -+_io_BytesIO_readline(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - Py_ssize_t size = -1; -@@ -265,7 +265,7 @@ - goto exit; - } - skip_optional: -- return_value = _io_BytesIO_readline_impl(self, size); -+ return_value = _io_BytesIO_readline_impl((bytesio *)self, size); - - exit: - return return_value; -@@ -288,7 +288,7 @@ - _io_BytesIO_readlines_impl(bytesio *self, PyObject *arg); - - static PyObject * --_io_BytesIO_readlines(bytesio *self, PyObject *const *args, Py_ssize_t nargs) -+_io_BytesIO_readlines(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *arg = Py_None; -@@ -301,7 +301,7 @@ - } - arg = args[0]; - skip_optional: -- return_value = _io_BytesIO_readlines_impl(self, arg); -+ return_value = _io_BytesIO_readlines_impl((bytesio *)self, arg); - - exit: - return return_value; -@@ -323,7 +323,7 @@ - _io_BytesIO_readinto_impl(bytesio *self, Py_buffer *buffer); - - static PyObject * --_io_BytesIO_readinto(bytesio *self, PyObject *arg) -+_io_BytesIO_readinto(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - Py_buffer buffer = {NULL, NULL}; -@@ -332,7 +332,7 @@ - _PyArg_BadArgument("readinto", "argument", "read-write bytes-like object", arg); - goto exit; - } -- return_value = _io_BytesIO_readinto_impl(self, &buffer); -+ return_value = _io_BytesIO_readinto_impl((bytesio *)self, &buffer); - - exit: - /* Cleanup for buffer */ -@@ -359,10 +359,10 @@ - _io_BytesIO_truncate_impl(bytesio *self, Py_ssize_t size); - - static PyObject * --_io_BytesIO_truncate(bytesio *self, PyObject *const *args, Py_ssize_t nargs) -+_io_BytesIO_truncate(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; -- Py_ssize_t size = self->pos; -+ Py_ssize_t size = ((bytesio *)self)->pos; - - if (!_PyArg_CheckPositional("truncate", nargs, 0, 1)) { - goto exit; -@@ -374,7 +374,7 @@ - goto exit; - } - skip_optional: -- return_value = _io_BytesIO_truncate_impl(self, size); -+ return_value = _io_BytesIO_truncate_impl((bytesio *)self, size); - - exit: - return return_value; -@@ -399,7 +399,7 @@ - _io_BytesIO_seek_impl(bytesio *self, Py_ssize_t pos, int whence); - - static PyObject * --_io_BytesIO_seek(bytesio *self, PyObject *const *args, Py_ssize_t nargs) -+_io_BytesIO_seek(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - Py_ssize_t pos; -@@ -428,7 +428,7 @@ - goto exit; - } - skip_optional: -- return_value = _io_BytesIO_seek_impl(self, pos, whence); -+ return_value = _io_BytesIO_seek_impl((bytesio *)self, pos, whence); - - exit: - return return_value; -@@ -471,9 +471,9 @@ - _io_BytesIO_close_impl(bytesio *self); - - static PyObject * --_io_BytesIO_close(bytesio *self, PyObject *Py_UNUSED(ignored)) -+_io_BytesIO_close(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _io_BytesIO_close_impl(self); -+ return _io_BytesIO_close_impl((bytesio *)self); - } - - PyDoc_STRVAR(_io_BytesIO___init____doc__, -@@ -535,4 +535,4 @@ - exit: - return return_value; - } --/*[clinic end generated code: output=985ff54e89f6036e input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=8a5e153bc7584b55 input=a9049054013a1b77]*/ -diff --git a/Modules/_io/clinic/fileio.c.h b/Modules/_io/clinic/fileio.c.h -index 0b8b4a49ac2..22d27bce677 100644 ---- a/Modules/_io/clinic/fileio.c.h -+++ b/Modules/_io/clinic/fileio.c.h -@@ -25,13 +25,13 @@ - _io_FileIO_close_impl(fileio *self, PyTypeObject *cls); - - static PyObject * --_io_FileIO_close(fileio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_io_FileIO_close(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "close() takes no arguments"); - return NULL; - } -- return _io_FileIO_close_impl(self, cls); -+ return _io_FileIO_close_impl((fileio *)self, cls); - } - - PyDoc_STRVAR(_io_FileIO___init____doc__, -@@ -151,9 +151,9 @@ - _io_FileIO_fileno_impl(fileio *self); - - static PyObject * --_io_FileIO_fileno(fileio *self, PyObject *Py_UNUSED(ignored)) -+_io_FileIO_fileno(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _io_FileIO_fileno_impl(self); -+ return _io_FileIO_fileno_impl((fileio *)self); - } - - PyDoc_STRVAR(_io_FileIO_readable__doc__, -@@ -169,9 +169,9 @@ - _io_FileIO_readable_impl(fileio *self); - - static PyObject * --_io_FileIO_readable(fileio *self, PyObject *Py_UNUSED(ignored)) -+_io_FileIO_readable(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _io_FileIO_readable_impl(self); -+ return _io_FileIO_readable_impl((fileio *)self); - } - - PyDoc_STRVAR(_io_FileIO_writable__doc__, -@@ -187,9 +187,9 @@ - _io_FileIO_writable_impl(fileio *self); - - static PyObject * --_io_FileIO_writable(fileio *self, PyObject *Py_UNUSED(ignored)) -+_io_FileIO_writable(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _io_FileIO_writable_impl(self); -+ return _io_FileIO_writable_impl((fileio *)self); - } - - PyDoc_STRVAR(_io_FileIO_seekable__doc__, -@@ -205,9 +205,9 @@ - _io_FileIO_seekable_impl(fileio *self); - - static PyObject * --_io_FileIO_seekable(fileio *self, PyObject *Py_UNUSED(ignored)) -+_io_FileIO_seekable(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _io_FileIO_seekable_impl(self); -+ return _io_FileIO_seekable_impl((fileio *)self); - } - - PyDoc_STRVAR(_io_FileIO_readinto__doc__, -@@ -223,7 +223,7 @@ - _io_FileIO_readinto_impl(fileio *self, PyTypeObject *cls, Py_buffer *buffer); - - static PyObject * --_io_FileIO_readinto(fileio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_io_FileIO_readinto(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -251,7 +251,7 @@ - _PyArg_BadArgument("readinto", "argument 1", "read-write bytes-like object", args[0]); - goto exit; - } -- return_value = _io_FileIO_readinto_impl(self, cls, &buffer); -+ return_value = _io_FileIO_readinto_impl((fileio *)self, cls, &buffer); - - exit: - /* Cleanup for buffer */ -@@ -278,9 +278,9 @@ - _io_FileIO_readall_impl(fileio *self); - - static PyObject * --_io_FileIO_readall(fileio *self, PyObject *Py_UNUSED(ignored)) -+_io_FileIO_readall(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _io_FileIO_readall_impl(self); -+ return _io_FileIO_readall_impl((fileio *)self); - } - - PyDoc_STRVAR(_io_FileIO_read__doc__, -@@ -300,7 +300,7 @@ - _io_FileIO_read_impl(fileio *self, PyTypeObject *cls, Py_ssize_t size); - - static PyObject * --_io_FileIO_read(fileio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_io_FileIO_read(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -331,7 +331,7 @@ - goto exit; - } - skip_optional_posonly: -- return_value = _io_FileIO_read_impl(self, cls, size); -+ return_value = _io_FileIO_read_impl((fileio *)self, cls, size); - - exit: - return return_value; -@@ -354,7 +354,7 @@ - _io_FileIO_write_impl(fileio *self, PyTypeObject *cls, Py_buffer *b); - - static PyObject * --_io_FileIO_write(fileio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_io_FileIO_write(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -381,7 +381,7 @@ - if (PyObject_GetBuffer(args[0], &b, PyBUF_SIMPLE) != 0) { - goto exit; - } -- return_value = _io_FileIO_write_impl(self, cls, &b); -+ return_value = _io_FileIO_write_impl((fileio *)self, cls, &b); - - exit: - /* Cleanup for b */ -@@ -413,7 +413,7 @@ - _io_FileIO_seek_impl(fileio *self, PyObject *pos, int whence); - - static PyObject * --_io_FileIO_seek(fileio *self, PyObject *const *args, Py_ssize_t nargs) -+_io_FileIO_seek(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *pos; -@@ -431,7 +431,7 @@ - goto exit; - } - skip_optional: -- return_value = _io_FileIO_seek_impl(self, pos, whence); -+ return_value = _io_FileIO_seek_impl((fileio *)self, pos, whence); - - exit: - return return_value; -@@ -452,9 +452,9 @@ - _io_FileIO_tell_impl(fileio *self); - - static PyObject * --_io_FileIO_tell(fileio *self, PyObject *Py_UNUSED(ignored)) -+_io_FileIO_tell(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _io_FileIO_tell_impl(self); -+ return _io_FileIO_tell_impl((fileio *)self); - } - - #if defined(HAVE_FTRUNCATE) -@@ -475,7 +475,7 @@ - _io_FileIO_truncate_impl(fileio *self, PyTypeObject *cls, PyObject *posobj); - - static PyObject * --_io_FileIO_truncate(fileio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_io_FileIO_truncate(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -504,7 +504,7 @@ - } - posobj = args[0]; - skip_optional_posonly: -- return_value = _io_FileIO_truncate_impl(self, cls, posobj); -+ return_value = _io_FileIO_truncate_impl((fileio *)self, cls, posobj); - - exit: - return return_value; -@@ -525,12 +525,12 @@ - _io_FileIO_isatty_impl(fileio *self); - - static PyObject * --_io_FileIO_isatty(fileio *self, PyObject *Py_UNUSED(ignored)) -+_io_FileIO_isatty(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _io_FileIO_isatty_impl(self); -+ return _io_FileIO_isatty_impl((fileio *)self); - } - - #ifndef _IO_FILEIO_TRUNCATE_METHODDEF - #define _IO_FILEIO_TRUNCATE_METHODDEF - #endif /* !defined(_IO_FILEIO_TRUNCATE_METHODDEF) */ --/*[clinic end generated code: output=1c262ae135da4dcb input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=dcbeb6a0b13e4b1f input=a9049054013a1b77]*/ -diff --git a/Modules/_io/clinic/stringio.c.h b/Modules/_io/clinic/stringio.c.h -index 6f9205af32f..bc571698806 100644 ---- a/Modules/_io/clinic/stringio.c.h -+++ b/Modules/_io/clinic/stringio.c.h -@@ -23,12 +23,12 @@ - _io_StringIO_getvalue_impl(stringio *self); - - static PyObject * --_io_StringIO_getvalue(stringio *self, PyObject *Py_UNUSED(ignored)) -+_io_StringIO_getvalue(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_StringIO_getvalue_impl(self); -+ return_value = _io_StringIO_getvalue_impl((stringio *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -47,12 +47,12 @@ - _io_StringIO_tell_impl(stringio *self); - - static PyObject * --_io_StringIO_tell(stringio *self, PyObject *Py_UNUSED(ignored)) -+_io_StringIO_tell(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_StringIO_tell_impl(self); -+ return_value = _io_StringIO_tell_impl((stringio *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -74,7 +74,7 @@ - _io_StringIO_read_impl(stringio *self, Py_ssize_t size); - - static PyObject * --_io_StringIO_read(stringio *self, PyObject *const *args, Py_ssize_t nargs) -+_io_StringIO_read(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - Py_ssize_t size = -1; -@@ -90,7 +90,7 @@ - } - skip_optional: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_StringIO_read_impl(self, size); -+ return_value = _io_StringIO_read_impl((stringio *)self, size); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -112,7 +112,7 @@ - _io_StringIO_readline_impl(stringio *self, Py_ssize_t size); - - static PyObject * --_io_StringIO_readline(stringio *self, PyObject *const *args, Py_ssize_t nargs) -+_io_StringIO_readline(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - Py_ssize_t size = -1; -@@ -128,7 +128,7 @@ - } - skip_optional: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_StringIO_readline_impl(self, size); -+ return_value = _io_StringIO_readline_impl((stringio *)self, size); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -152,10 +152,10 @@ - _io_StringIO_truncate_impl(stringio *self, Py_ssize_t size); - - static PyObject * --_io_StringIO_truncate(stringio *self, PyObject *const *args, Py_ssize_t nargs) -+_io_StringIO_truncate(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; -- Py_ssize_t size = self->pos; -+ Py_ssize_t size = ((stringio *)self)->pos; - - if (!_PyArg_CheckPositional("truncate", nargs, 0, 1)) { - goto exit; -@@ -168,7 +168,7 @@ - } - skip_optional: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_StringIO_truncate_impl(self, size); -+ return_value = _io_StringIO_truncate_impl((stringio *)self, size); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -194,7 +194,7 @@ - _io_StringIO_seek_impl(stringio *self, Py_ssize_t pos, int whence); - - static PyObject * --_io_StringIO_seek(stringio *self, PyObject *const *args, Py_ssize_t nargs) -+_io_StringIO_seek(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - Py_ssize_t pos; -@@ -224,7 +224,7 @@ - } - skip_optional: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_StringIO_seek_impl(self, pos, whence); -+ return_value = _io_StringIO_seek_impl((stringio *)self, pos, whence); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -252,7 +252,7 @@ - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_StringIO_write_impl(self, obj); -+ return_value = _io_StringIO_write_impl((stringio *)self, obj); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -276,12 +276,12 @@ - _io_StringIO_close_impl(stringio *self); - - static PyObject * --_io_StringIO_close(stringio *self, PyObject *Py_UNUSED(ignored)) -+_io_StringIO_close(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_StringIO_close_impl(self); -+ return_value = _io_StringIO_close_impl((stringio *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -371,12 +371,12 @@ - _io_StringIO_readable_impl(stringio *self); - - static PyObject * --_io_StringIO_readable(stringio *self, PyObject *Py_UNUSED(ignored)) -+_io_StringIO_readable(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_StringIO_readable_impl(self); -+ return_value = _io_StringIO_readable_impl((stringio *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -395,12 +395,12 @@ - _io_StringIO_writable_impl(stringio *self); - - static PyObject * --_io_StringIO_writable(stringio *self, PyObject *Py_UNUSED(ignored)) -+_io_StringIO_writable(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_StringIO_writable_impl(self); -+ return_value = _io_StringIO_writable_impl((stringio *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -419,12 +419,12 @@ - _io_StringIO_seekable_impl(stringio *self); - - static PyObject * --_io_StringIO_seekable(stringio *self, PyObject *Py_UNUSED(ignored)) -+_io_StringIO_seekable(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_StringIO_seekable_impl(self); -+ return_value = _io_StringIO_seekable_impl((stringio *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -442,12 +442,12 @@ - _io_StringIO___getstate___impl(stringio *self); - - static PyObject * --_io_StringIO___getstate__(stringio *self, PyObject *Py_UNUSED(ignored)) -+_io_StringIO___getstate__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_StringIO___getstate___impl(self); -+ return_value = _io_StringIO___getstate___impl((stringio *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -470,7 +470,7 @@ - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_StringIO___setstate___impl(self, state); -+ return_value = _io_StringIO___setstate___impl((stringio *)self, state); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -490,12 +490,12 @@ - _io_StringIO_closed_get_impl(stringio *self); - - static PyObject * --_io_StringIO_closed_get(stringio *self, void *Py_UNUSED(context)) -+_io_StringIO_closed_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_StringIO_closed_get_impl(self); -+ return_value = _io_StringIO_closed_get_impl((stringio *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -515,12 +515,12 @@ - _io_StringIO_line_buffering_get_impl(stringio *self); - - static PyObject * --_io_StringIO_line_buffering_get(stringio *self, void *Py_UNUSED(context)) -+_io_StringIO_line_buffering_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_StringIO_line_buffering_get_impl(self); -+ return_value = _io_StringIO_line_buffering_get_impl((stringio *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -540,14 +540,14 @@ - _io_StringIO_newlines_get_impl(stringio *self); - - static PyObject * --_io_StringIO_newlines_get(stringio *self, void *Py_UNUSED(context)) -+_io_StringIO_newlines_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_StringIO_newlines_get_impl(self); -+ return_value = _io_StringIO_newlines_get_impl((stringio *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; - } --/*[clinic end generated code: output=9d2b092274469d42 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=7796e223e778a214 input=a9049054013a1b77]*/ -diff --git a/Modules/_io/clinic/textio.c.h b/Modules/_io/clinic/textio.c.h -index 160f80ada43..9ce1d70ad71 100644 ---- a/Modules/_io/clinic/textio.c.h -+++ b/Modules/_io/clinic/textio.c.h -@@ -208,6 +208,9 @@ - "Encoding of the text stream.\n" - "\n" - "Subclasses should override."); -+#if defined(_io__TextIOBase_encoding_DOCSTR) -+# undef _io__TextIOBase_encoding_DOCSTR -+#endif - #define _io__TextIOBase_encoding_DOCSTR _io__TextIOBase_encoding__doc__ - - #if !defined(_io__TextIOBase_encoding_DOCSTR) -@@ -235,6 +238,9 @@ - "Only line endings translated during reading are considered.\n" - "\n" - "Subclasses should override."); -+#if defined(_io__TextIOBase_newlines_DOCSTR) -+# undef _io__TextIOBase_newlines_DOCSTR -+#endif - #define _io__TextIOBase_newlines_DOCSTR _io__TextIOBase_newlines__doc__ - - #if !defined(_io__TextIOBase_newlines_DOCSTR) -@@ -260,6 +266,9 @@ - "The error setting of the decoder or encoder.\n" - "\n" - "Subclasses should override."); -+#if defined(_io__TextIOBase_errors_DOCSTR) -+# undef _io__TextIOBase_errors_DOCSTR -+#endif - #define _io__TextIOBase_errors_DOCSTR _io__TextIOBase_errors__doc__ - - #if !defined(_io__TextIOBase_errors_DOCSTR) -@@ -370,7 +379,7 @@ - PyObject *input, int final); - - static PyObject * --_io_IncrementalNewlineDecoder_decode(nldecoder_object *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_io_IncrementalNewlineDecoder_decode(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -417,7 +426,7 @@ - goto exit; - } - skip_optional_pos: -- return_value = _io_IncrementalNewlineDecoder_decode_impl(self, input, final); -+ return_value = _io_IncrementalNewlineDecoder_decode_impl((nldecoder_object *)self, input, final); - - exit: - return return_value; -@@ -435,9 +444,9 @@ - _io_IncrementalNewlineDecoder_getstate_impl(nldecoder_object *self); - - static PyObject * --_io_IncrementalNewlineDecoder_getstate(nldecoder_object *self, PyObject *Py_UNUSED(ignored)) -+_io_IncrementalNewlineDecoder_getstate(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _io_IncrementalNewlineDecoder_getstate_impl(self); -+ return _io_IncrementalNewlineDecoder_getstate_impl((nldecoder_object *)self); - } - - PyDoc_STRVAR(_io_IncrementalNewlineDecoder_setstate__doc__, -@@ -460,9 +469,9 @@ - _io_IncrementalNewlineDecoder_reset_impl(nldecoder_object *self); - - static PyObject * --_io_IncrementalNewlineDecoder_reset(nldecoder_object *self, PyObject *Py_UNUSED(ignored)) -+_io_IncrementalNewlineDecoder_reset(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _io_IncrementalNewlineDecoder_reset_impl(self); -+ return _io_IncrementalNewlineDecoder_reset_impl((nldecoder_object *)self); - } - - PyDoc_STRVAR(_io_TextIOWrapper___init____doc__, -@@ -645,7 +654,7 @@ - PyObject *write_through_obj); - - static PyObject * --_io_TextIOWrapper_reconfigure(textio *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_io_TextIOWrapper_reconfigure(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -716,7 +725,7 @@ - write_through_obj = args[4]; - skip_optional_kwonly: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_TextIOWrapper_reconfigure_impl(self, encoding, errors, newline_obj, line_buffering_obj, write_through_obj); -+ return_value = _io_TextIOWrapper_reconfigure_impl((textio *)self, encoding, errors, newline_obj, line_buffering_obj, write_through_obj); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -735,12 +744,12 @@ - _io_TextIOWrapper_detach_impl(textio *self); - - static PyObject * --_io_TextIOWrapper_detach(textio *self, PyObject *Py_UNUSED(ignored)) -+_io_TextIOWrapper_detach(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_TextIOWrapper_detach_impl(self); -+ return_value = _io_TextIOWrapper_detach_impl((textio *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -758,7 +767,7 @@ - _io_TextIOWrapper_write_impl(textio *self, PyObject *text); - - static PyObject * --_io_TextIOWrapper_write(textio *self, PyObject *arg) -+_io_TextIOWrapper_write(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - PyObject *text; -@@ -769,7 +778,7 @@ - } - text = arg; - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_TextIOWrapper_write_impl(self, text); -+ return_value = _io_TextIOWrapper_write_impl((textio *)self, text); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -788,7 +797,7 @@ - _io_TextIOWrapper_read_impl(textio *self, Py_ssize_t n); - - static PyObject * --_io_TextIOWrapper_read(textio *self, PyObject *const *args, Py_ssize_t nargs) -+_io_TextIOWrapper_read(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - Py_ssize_t n = -1; -@@ -804,7 +813,7 @@ - } - skip_optional: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_TextIOWrapper_read_impl(self, n); -+ return_value = _io_TextIOWrapper_read_impl((textio *)self, n); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -823,7 +832,7 @@ - _io_TextIOWrapper_readline_impl(textio *self, Py_ssize_t size); - - static PyObject * --_io_TextIOWrapper_readline(textio *self, PyObject *const *args, Py_ssize_t nargs) -+_io_TextIOWrapper_readline(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - Py_ssize_t size = -1; -@@ -848,7 +857,7 @@ - } - skip_optional: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_TextIOWrapper_readline_impl(self, size); -+ return_value = _io_TextIOWrapper_readline_impl((textio *)self, size); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -885,7 +894,7 @@ - _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence); - - static PyObject * --_io_TextIOWrapper_seek(textio *self, PyObject *const *args, Py_ssize_t nargs) -+_io_TextIOWrapper_seek(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *cookieObj; -@@ -904,7 +913,7 @@ - } - skip_optional: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_TextIOWrapper_seek_impl(self, cookieObj, whence); -+ return_value = _io_TextIOWrapper_seek_impl((textio *)self, cookieObj, whence); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -927,12 +936,12 @@ - _io_TextIOWrapper_tell_impl(textio *self); - - static PyObject * --_io_TextIOWrapper_tell(textio *self, PyObject *Py_UNUSED(ignored)) -+_io_TextIOWrapper_tell(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_TextIOWrapper_tell_impl(self); -+ return_value = _io_TextIOWrapper_tell_impl((textio *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -950,7 +959,7 @@ - _io_TextIOWrapper_truncate_impl(textio *self, PyObject *pos); - - static PyObject * --_io_TextIOWrapper_truncate(textio *self, PyObject *const *args, Py_ssize_t nargs) -+_io_TextIOWrapper_truncate(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *pos = Py_None; -@@ -964,7 +973,7 @@ - pos = args[0]; - skip_optional: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_TextIOWrapper_truncate_impl(self, pos); -+ return_value = _io_TextIOWrapper_truncate_impl((textio *)self, pos); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -983,12 +992,12 @@ - _io_TextIOWrapper_fileno_impl(textio *self); - - static PyObject * --_io_TextIOWrapper_fileno(textio *self, PyObject *Py_UNUSED(ignored)) -+_io_TextIOWrapper_fileno(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_TextIOWrapper_fileno_impl(self); -+ return_value = _io_TextIOWrapper_fileno_impl((textio *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1006,12 +1015,12 @@ - _io_TextIOWrapper_seekable_impl(textio *self); - - static PyObject * --_io_TextIOWrapper_seekable(textio *self, PyObject *Py_UNUSED(ignored)) -+_io_TextIOWrapper_seekable(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_TextIOWrapper_seekable_impl(self); -+ return_value = _io_TextIOWrapper_seekable_impl((textio *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1029,12 +1038,12 @@ - _io_TextIOWrapper_readable_impl(textio *self); - - static PyObject * --_io_TextIOWrapper_readable(textio *self, PyObject *Py_UNUSED(ignored)) -+_io_TextIOWrapper_readable(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_TextIOWrapper_readable_impl(self); -+ return_value = _io_TextIOWrapper_readable_impl((textio *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1052,12 +1061,12 @@ - _io_TextIOWrapper_writable_impl(textio *self); - - static PyObject * --_io_TextIOWrapper_writable(textio *self, PyObject *Py_UNUSED(ignored)) -+_io_TextIOWrapper_writable(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_TextIOWrapper_writable_impl(self); -+ return_value = _io_TextIOWrapper_writable_impl((textio *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1075,12 +1084,12 @@ - _io_TextIOWrapper_isatty_impl(textio *self); - - static PyObject * --_io_TextIOWrapper_isatty(textio *self, PyObject *Py_UNUSED(ignored)) -+_io_TextIOWrapper_isatty(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_TextIOWrapper_isatty_impl(self); -+ return_value = _io_TextIOWrapper_isatty_impl((textio *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1098,12 +1107,12 @@ - _io_TextIOWrapper_flush_impl(textio *self); - - static PyObject * --_io_TextIOWrapper_flush(textio *self, PyObject *Py_UNUSED(ignored)) -+_io_TextIOWrapper_flush(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_TextIOWrapper_flush_impl(self); -+ return_value = _io_TextIOWrapper_flush_impl((textio *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1121,12 +1130,12 @@ - _io_TextIOWrapper_close_impl(textio *self); - - static PyObject * --_io_TextIOWrapper_close(textio *self, PyObject *Py_UNUSED(ignored)) -+_io_TextIOWrapper_close(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_TextIOWrapper_close_impl(self); -+ return_value = _io_TextIOWrapper_close_impl((textio *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1146,12 +1155,12 @@ - _io_TextIOWrapper_name_get_impl(textio *self); - - static PyObject * --_io_TextIOWrapper_name_get(textio *self, void *Py_UNUSED(context)) -+_io_TextIOWrapper_name_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_TextIOWrapper_name_get_impl(self); -+ return_value = _io_TextIOWrapper_name_get_impl((textio *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1171,12 +1180,12 @@ - _io_TextIOWrapper_closed_get_impl(textio *self); - - static PyObject * --_io_TextIOWrapper_closed_get(textio *self, void *Py_UNUSED(context)) -+_io_TextIOWrapper_closed_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_TextIOWrapper_closed_get_impl(self); -+ return_value = _io_TextIOWrapper_closed_get_impl((textio *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1196,12 +1205,12 @@ - _io_TextIOWrapper_newlines_get_impl(textio *self); - - static PyObject * --_io_TextIOWrapper_newlines_get(textio *self, void *Py_UNUSED(context)) -+_io_TextIOWrapper_newlines_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_TextIOWrapper_newlines_get_impl(self); -+ return_value = _io_TextIOWrapper_newlines_get_impl((textio *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1221,12 +1230,12 @@ - _io_TextIOWrapper_errors_get_impl(textio *self); - - static PyObject * --_io_TextIOWrapper_errors_get(textio *self, void *Py_UNUSED(context)) -+_io_TextIOWrapper_errors_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_TextIOWrapper_errors_get_impl(self); -+ return_value = _io_TextIOWrapper_errors_get_impl((textio *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1246,12 +1255,12 @@ - _io_TextIOWrapper__CHUNK_SIZE_get_impl(textio *self); - - static PyObject * --_io_TextIOWrapper__CHUNK_SIZE_get(textio *self, void *Py_UNUSED(context)) -+_io_TextIOWrapper__CHUNK_SIZE_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_TextIOWrapper__CHUNK_SIZE_get_impl(self); -+ return_value = _io_TextIOWrapper__CHUNK_SIZE_get_impl((textio *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1271,14 +1280,14 @@ - _io_TextIOWrapper__CHUNK_SIZE_set_impl(textio *self, PyObject *value); - - static int --_io_TextIOWrapper__CHUNK_SIZE_set(textio *self, PyObject *value, void *Py_UNUSED(context)) -+_io_TextIOWrapper__CHUNK_SIZE_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) - { - int return_value; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _io_TextIOWrapper__CHUNK_SIZE_set_impl(self, value); -+ return_value = _io_TextIOWrapper__CHUNK_SIZE_set_impl((textio *)self, value); - Py_END_CRITICAL_SECTION(); - - return return_value; - } --/*[clinic end generated code: output=1172c500a022c65d input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=6e64e43113a97340 input=a9049054013a1b77]*/ -diff --git a/Modules/_io/clinic/winconsoleio.c.h b/Modules/_io/clinic/winconsoleio.c.h -index df281dfeb13..ba6dcde6e01 100644 ---- a/Modules/_io/clinic/winconsoleio.c.h -+++ b/Modules/_io/clinic/winconsoleio.c.h -@@ -27,13 +27,13 @@ - _io__WindowsConsoleIO_close_impl(winconsoleio *self, PyTypeObject *cls); - - static PyObject * --_io__WindowsConsoleIO_close(winconsoleio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_io__WindowsConsoleIO_close(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "close() takes no arguments"); - return NULL; - } -- return _io__WindowsConsoleIO_close_impl(self, cls); -+ return _io__WindowsConsoleIO_close_impl((winconsoleio *)self, cls); - } - - #endif /* defined(HAVE_WINDOWS_CONSOLE_IO) */ -@@ -154,9 +154,9 @@ - _io__WindowsConsoleIO_fileno_impl(winconsoleio *self); - - static PyObject * --_io__WindowsConsoleIO_fileno(winconsoleio *self, PyObject *Py_UNUSED(ignored)) -+_io__WindowsConsoleIO_fileno(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _io__WindowsConsoleIO_fileno_impl(self); -+ return _io__WindowsConsoleIO_fileno_impl((winconsoleio *)self); - } - - #endif /* defined(HAVE_WINDOWS_CONSOLE_IO) */ -@@ -176,9 +176,9 @@ - _io__WindowsConsoleIO_readable_impl(winconsoleio *self); - - static PyObject * --_io__WindowsConsoleIO_readable(winconsoleio *self, PyObject *Py_UNUSED(ignored)) -+_io__WindowsConsoleIO_readable(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _io__WindowsConsoleIO_readable_impl(self); -+ return _io__WindowsConsoleIO_readable_impl((winconsoleio *)self); - } - - #endif /* defined(HAVE_WINDOWS_CONSOLE_IO) */ -@@ -198,9 +198,9 @@ - _io__WindowsConsoleIO_writable_impl(winconsoleio *self); - - static PyObject * --_io__WindowsConsoleIO_writable(winconsoleio *self, PyObject *Py_UNUSED(ignored)) -+_io__WindowsConsoleIO_writable(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _io__WindowsConsoleIO_writable_impl(self); -+ return _io__WindowsConsoleIO_writable_impl((winconsoleio *)self); - } - - #endif /* defined(HAVE_WINDOWS_CONSOLE_IO) */ -@@ -221,7 +221,7 @@ - Py_buffer *buffer); - - static PyObject * --_io__WindowsConsoleIO_readinto(winconsoleio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_io__WindowsConsoleIO_readinto(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -249,7 +249,7 @@ - _PyArg_BadArgument("readinto", "argument 1", "read-write bytes-like object", args[0]); - goto exit; - } -- return_value = _io__WindowsConsoleIO_readinto_impl(self, cls, &buffer); -+ return_value = _io__WindowsConsoleIO_readinto_impl((winconsoleio *)self, cls, &buffer); - - exit: - /* Cleanup for buffer */ -@@ -279,9 +279,9 @@ - _io__WindowsConsoleIO_readall_impl(winconsoleio *self); - - static PyObject * --_io__WindowsConsoleIO_readall(winconsoleio *self, PyObject *Py_UNUSED(ignored)) -+_io__WindowsConsoleIO_readall(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _io__WindowsConsoleIO_readall_impl(self); -+ return _io__WindowsConsoleIO_readall_impl((winconsoleio *)self); - } - - #endif /* defined(HAVE_WINDOWS_CONSOLE_IO) */ -@@ -306,7 +306,7 @@ - Py_ssize_t size); - - static PyObject * --_io__WindowsConsoleIO_read(winconsoleio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_io__WindowsConsoleIO_read(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -337,7 +337,7 @@ - goto exit; - } - skip_optional_posonly: -- return_value = _io__WindowsConsoleIO_read_impl(self, cls, size); -+ return_value = _io__WindowsConsoleIO_read_impl((winconsoleio *)self, cls, size); - - exit: - return return_value; -@@ -364,7 +364,7 @@ - Py_buffer *b); - - static PyObject * --_io__WindowsConsoleIO_write(winconsoleio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_io__WindowsConsoleIO_write(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -391,7 +391,7 @@ - if (PyObject_GetBuffer(args[0], &b, PyBUF_SIMPLE) != 0) { - goto exit; - } -- return_value = _io__WindowsConsoleIO_write_impl(self, cls, &b); -+ return_value = _io__WindowsConsoleIO_write_impl((winconsoleio *)self, cls, &b); - - exit: - /* Cleanup for b */ -@@ -419,9 +419,9 @@ - _io__WindowsConsoleIO_isatty_impl(winconsoleio *self); - - static PyObject * --_io__WindowsConsoleIO_isatty(winconsoleio *self, PyObject *Py_UNUSED(ignored)) -+_io__WindowsConsoleIO_isatty(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _io__WindowsConsoleIO_isatty_impl(self); -+ return _io__WindowsConsoleIO_isatty_impl((winconsoleio *)self); - } - - #endif /* defined(HAVE_WINDOWS_CONSOLE_IO) */ -@@ -461,4 +461,4 @@ - #ifndef _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF - #define _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF - #endif /* !defined(_IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF) */ --/*[clinic end generated code: output=78e0f6abf4de2d6d input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=edc47f5c49589045 input=a9049054013a1b77]*/ -diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c -index cf0f1d671b5..89f1cfe6b20 100644 ---- a/Modules/_io/fileio.c -+++ b/Modules/_io/fileio.c -@@ -83,7 +83,7 @@ - } fileio; - - #define PyFileIO_Check(state, op) (PyObject_TypeCheck((op), state->PyFileIO_Type)) --#define _PyFileIO_CAST(op) _Py_CAST(fileio*, (op)) -+#define PyFileIO_CAST(op) ((fileio *)(op)) - - /* Forward declarations */ - static PyObject* portable_lseek(fileio *self, PyObject *posobj, int whence, bool suppress_pipe_error); -@@ -91,7 +91,7 @@ - int - _PyFileIO_closed(PyObject *self) - { -- return (_PyFileIO_CAST(self)->fd < 0); -+ return (PyFileIO_CAST(self)->fd < 0); - } - - /* Because this can call arbitrary code, it shouldn't be called when -@@ -100,13 +100,15 @@ - static PyObject * - fileio_dealloc_warn(PyObject *op, PyObject *source) - { -- fileio *self = _PyFileIO_CAST(op); -+ fileio *self = PyFileIO_CAST(op); - if (self->fd >= 0 && self->closefd) { - PyObject *exc = PyErr_GetRaisedException(); - if (PyErr_ResourceWarning(source, 1, "unclosed file %R", source)) { - /* Spurious errors can appear at shutdown */ -- if (PyErr_ExceptionMatches(PyExc_Warning)) -- PyErr_WriteUnraisable((PyObject *) self); -+ if (PyErr_ExceptionMatches(PyExc_Warning)) { -+ PyErr_FormatUnraisable("Exception ignored " -+ "while finalizing file %R", self); -+ } - } - PyErr_SetRaisedException(exc); - } -@@ -540,7 +542,7 @@ - static int - fileio_traverse(PyObject *op, visitproc visit, void *arg) - { -- fileio *self = _PyFileIO_CAST(op); -+ fileio *self = PyFileIO_CAST(op); - Py_VISIT(Py_TYPE(self)); - Py_VISIT(self->dict); - return 0; -@@ -549,7 +551,7 @@ - static int - fileio_clear(PyObject *op) - { -- fileio *self = _PyFileIO_CAST(op); -+ fileio *self = PyFileIO_CAST(op); - Py_CLEAR(self->dict); - return 0; - } -@@ -557,7 +559,7 @@ - static void - fileio_dealloc(PyObject *op) - { -- fileio *self = _PyFileIO_CAST(op); -+ fileio *self = PyFileIO_CAST(op); - self->finalizing = 1; - if (_PyIOBase_finalize(op) < 0) { - return; -@@ -1159,7 +1161,7 @@ - static PyObject * - fileio_repr(PyObject *op) - { -- fileio *self = _PyFileIO_CAST(op); -+ fileio *self = PyFileIO_CAST(op); - const char *type_name = Py_TYPE(self)->tp_name; - - if (self->fd < 0) { -@@ -1225,9 +1227,9 @@ - context TOCTOU issues (the fd could be arbitrarily modified by - surrounding code). */ - static PyObject * --_io_FileIO_isatty_open_only(PyObject *op, PyObject *Py_UNUSED(ignored)) -+_io_FileIO_isatty_open_only(PyObject *op, PyObject *Py_UNUSED(dummy)) - { -- fileio *self = _PyFileIO_CAST(op); -+ fileio *self = PyFileIO_CAST(op); - if (self->stat_atopen != NULL && !S_ISCHR(self->stat_atopen->st_mode)) { - Py_RETURN_FALSE; - } -@@ -1262,28 +1264,28 @@ - static PyObject * - fileio_get_closed(PyObject *op, void *closure) - { -- fileio *self = _PyFileIO_CAST(op); -+ fileio *self = PyFileIO_CAST(op); - return PyBool_FromLong((long)(self->fd < 0)); - } - - static PyObject * - fileio_get_closefd(PyObject *op, void *closure) - { -- fileio *self = _PyFileIO_CAST(op); -+ fileio *self = PyFileIO_CAST(op); - return PyBool_FromLong((long)(self->closefd)); - } - - static PyObject * - fileio_get_mode(PyObject *op, void *closure) - { -- fileio *self = _PyFileIO_CAST(op); -+ fileio *self = PyFileIO_CAST(op); - return PyUnicode_FromString(mode_string(self)); - } - - static PyObject * - fileio_get_blksize(PyObject *op, void *closure) - { -- fileio *self = _PyFileIO_CAST(op); -+ fileio *self = PyFileIO_CAST(op); - #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE - if (self->stat_atopen != NULL && self->stat_atopen->st_blksize > 1) { - return PyLong_FromLong(self->stat_atopen->st_blksize); -diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c -index 419e5516b5c..7e0822e3350 100644 ---- a/Modules/_io/iobase.c -+++ b/Modules/_io/iobase.c -@@ -35,6 +35,8 @@ - PyObject *weakreflist; - } iobase; - -+#define iobase_CAST(op) ((iobase *)(op)) -+ - PyDoc_STRVAR(iobase_doc, - "The abstract base class for all I/O classes.\n" - "\n" -@@ -314,7 +316,8 @@ - PyErr_Clear(); - res = PyObject_CallMethodNoArgs((PyObject *)self, &_Py_ID(close)); - if (res == NULL) { -- PyErr_WriteUnraisable(self); -+ PyErr_FormatUnraisable("Exception ignored " -+ "while finalizing file %R", self); - } - else { - Py_DECREF(res); -@@ -342,16 +345,18 @@ - } - - static int --iobase_traverse(iobase *self, visitproc visit, void *arg) -+iobase_traverse(PyObject *op, visitproc visit, void *arg) - { -+ iobase *self = iobase_CAST(op); - Py_VISIT(Py_TYPE(self)); - Py_VISIT(self->dict); - return 0; - } - - static int --iobase_clear(iobase *self) -+iobase_clear(PyObject *op) - { -+ iobase *self = iobase_CAST(op); - Py_CLEAR(self->dict); - return 0; - } -@@ -359,14 +364,15 @@ - /* Destructor */ - - static void --iobase_dealloc(iobase *self) -+iobase_dealloc(PyObject *op) - { - /* NOTE: since IOBaseObject has its own dict, Python-defined attributes - are still available here for close() to use. - However, if the derived class declares a __slots__, those slots are - already gone. - */ -- if (_PyIOBase_finalize((PyObject *) self) < 0) { -+ iobase *self = iobase_CAST(op); -+ if (_PyIOBase_finalize(op) < 0) { - /* When called from a heap type's dealloc, the type will be - decref'ed on return (see e.g. subtype_dealloc in typeobject.c). */ - if (_PyType_HasFeature(Py_TYPE(self), Py_TPFLAGS_HEAPTYPE)) { -@@ -377,9 +383,9 @@ - PyTypeObject *tp = Py_TYPE(self); - _PyObject_GC_UNTRACK(self); - if (self->weakreflist != NULL) -- PyObject_ClearWeakRefs((PyObject *) self); -+ PyObject_ClearWeakRefs(op); - Py_CLEAR(self->dict); -- tp->tp_free((PyObject *)self); -+ tp->tp_free(self); - Py_DECREF(tp); - } - -@@ -852,7 +858,7 @@ - - static PyGetSetDef iobase_getset[] = { - {"__dict__", PyObject_GenericGetDict, NULL, NULL}, -- {"closed", (getter)iobase_closed_get, NULL, NULL}, -+ {"closed", iobase_closed_get, NULL, NULL}, - {NULL} - }; - -diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c -index 65e8d97aa8a..9d1bfa3ea05 100644 ---- a/Modules/_io/stringio.c -+++ b/Modules/_io/stringio.c -@@ -30,7 +30,7 @@ - _PyUnicodeWriter is destroyed. - */ - int state; -- _PyUnicodeWriter writer; -+ PyUnicodeWriter *writer; - - char ok; /* initialized? */ - char closed; -@@ -45,6 +45,8 @@ - _PyIO_State *module_state; - } stringio; - -+#define stringio_CAST(op) ((stringio *)(op)) -+ - #define clinic_state() (find_io_state_by_def(Py_TYPE(self))) - #include "clinic/stringio.c.h" - #undef clinic_state -@@ -129,14 +131,18 @@ - static PyObject * - make_intermediate(stringio *self) - { -- PyObject *intermediate = _PyUnicodeWriter_Finish(&self->writer); -+ PyObject *intermediate = PyUnicodeWriter_Finish(self->writer); -+ self->writer = NULL; - self->state = STATE_REALIZED; - if (intermediate == NULL) - return NULL; - -- _PyUnicodeWriter_Init(&self->writer); -- self->writer.overallocate = 1; -- if (_PyUnicodeWriter_WriteStr(&self->writer, intermediate)) { -+ self->writer = PyUnicodeWriter_Create(0); -+ if (self->writer == NULL) { -+ Py_DECREF(intermediate); -+ return NULL; -+ } -+ if (PyUnicodeWriter_WriteStr(self->writer, intermediate)) { - Py_DECREF(intermediate); - return NULL; - } -@@ -155,7 +161,8 @@ - assert(self->state == STATE_ACCUMULATING); - self->state = STATE_REALIZED; - -- intermediate = _PyUnicodeWriter_Finish(&self->writer); -+ intermediate = PyUnicodeWriter_Finish(self->writer); -+ self->writer = NULL; - if (intermediate == NULL) - return -1; - -@@ -217,7 +224,7 @@ - - if (self->state == STATE_ACCUMULATING) { - if (self->string_size == self->pos) { -- if (_PyUnicodeWriter_WriteStr(&self->writer, decoded)) -+ if (PyUnicodeWriter_WriteStr(self->writer, decoded)) - goto fail; - goto success; - } -@@ -397,9 +404,10 @@ - } - - static PyObject * --stringio_iternext(stringio *self) -+stringio_iternext(PyObject *op) - { - PyObject *line; -+ stringio *self = stringio_CAST(op); - - CHECK_INITIALIZED(self); - CHECK_CLOSED(self); -@@ -411,8 +419,7 @@ - } - else { - /* XXX is subclassing StringIO really supported? */ -- line = PyObject_CallMethodNoArgs((PyObject *)self, -- &_Py_ID(readline)); -+ line = PyObject_CallMethodNoArgs(op, &_Py_ID(readline)); - if (line && !PyUnicode_Check(line)) { - PyErr_Format(PyExc_OSError, - "readline() should have returned a str object, " -@@ -437,7 +444,7 @@ - /*[clinic input] - @critical_section - _io.StringIO.truncate -- pos as size: Py_ssize_t(accept={int, NoneType}, c_default="self->pos") = None -+ pos as size: Py_ssize_t(accept={int, NoneType}, c_default="((stringio *)self)->pos") = None - / - - Truncate size to pos. -@@ -449,7 +456,7 @@ - - static PyObject * - _io_StringIO_truncate_impl(stringio *self, Py_ssize_t size) --/*[clinic end generated code: output=eb3aef8e06701365 input=461b872dce238452]*/ -+/*[clinic end generated code: output=eb3aef8e06701365 input=fa8a6c98bb2ba780]*/ - { - CHECK_INITIALIZED(self); - CHECK_CLOSED(self); -@@ -577,7 +584,8 @@ - /* Free up some memory */ - if (resize_buffer(self, 0) < 0) - return NULL; -- _PyUnicodeWriter_Dealloc(&self->writer); -+ PyUnicodeWriter_Discard(self->writer); -+ self->writer = NULL; - Py_CLEAR(self->readnl); - Py_CLEAR(self->writenl); - Py_CLEAR(self->decoder); -@@ -585,8 +593,9 @@ - } - - static int --stringio_traverse(stringio *self, visitproc visit, void *arg) -+stringio_traverse(PyObject *op, visitproc visit, void *arg) - { -+ stringio *self = stringio_CAST(op); - Py_VISIT(Py_TYPE(self)); - Py_VISIT(self->readnl); - Py_VISIT(self->writenl); -@@ -596,8 +605,9 @@ - } - - static int --stringio_clear(stringio *self) -+stringio_clear(PyObject *op) - { -+ stringio *self = stringio_CAST(op); - Py_CLEAR(self->readnl); - Py_CLEAR(self->writenl); - Py_CLEAR(self->decoder); -@@ -606,8 +616,9 @@ - } - - static void --stringio_dealloc(stringio *self) -+stringio_dealloc(PyObject *op) - { -+ stringio *self = stringio_CAST(op); - PyTypeObject *tp = Py_TYPE(self); - _PyObject_GC_UNTRACK(self); - self->ok = 0; -@@ -615,10 +626,10 @@ - PyMem_Free(self->buf); - self->buf = NULL; - } -- _PyUnicodeWriter_Dealloc(&self->writer); -- (void)stringio_clear(self); -+ PyUnicodeWriter_Discard(self->writer); -+ (void)stringio_clear(op); - if (self->weakreflist != NULL) { -- PyObject_ClearWeakRefs((PyObject *) self); -+ PyObject_ClearWeakRefs(op); - } - tp->tp_free(self); - Py_DECREF(tp); -@@ -699,7 +710,8 @@ - - self->ok = 0; - -- _PyUnicodeWriter_Dealloc(&self->writer); -+ PyUnicodeWriter_Discard(self->writer); -+ self->writer = NULL; - Py_CLEAR(self->readnl); - Py_CLEAR(self->writenl); - Py_CLEAR(self->decoder); -@@ -754,8 +766,10 @@ - /* Empty stringio object, we can start by accumulating */ - if (resize_buffer(self, 0) < 0) - return -1; -- _PyUnicodeWriter_Init(&self->writer); -- self->writer.overallocate = 1; -+ self->writer = PyUnicodeWriter_Create(0); -+ if (self->writer == NULL) { -+ return -1; -+ } - self->state = STATE_ACCUMULATING; - } - self->pos = 0; -diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c -index 791ee070401..935aaab20a0 100644 ---- a/Modules/_io/textio.c -+++ b/Modules/_io/textio.c -@@ -223,6 +223,8 @@ - unsigned int seennl: 3; - }; - -+#define nldecoder_object_CAST(op) ((nldecoder_object *)(op)) -+ - /*[clinic input] - _io.IncrementalNewlineDecoder.__init__ - decoder: object -@@ -263,9 +265,9 @@ - } - - static int --incrementalnewlinedecoder_traverse(nldecoder_object *self, visitproc visit, -- void *arg) -+incrementalnewlinedecoder_traverse(PyObject *op, visitproc visit, void *arg) - { -+ nldecoder_object *self = nldecoder_object_CAST(op); - Py_VISIT(Py_TYPE(self)); - Py_VISIT(self->decoder); - Py_VISIT(self->errors); -@@ -273,20 +275,22 @@ - } - - static int --incrementalnewlinedecoder_clear(nldecoder_object *self) -+incrementalnewlinedecoder_clear(PyObject *op) - { -+ nldecoder_object *self = nldecoder_object_CAST(op); - Py_CLEAR(self->decoder); - Py_CLEAR(self->errors); - return 0; - } - - static void --incrementalnewlinedecoder_dealloc(nldecoder_object *self) -+incrementalnewlinedecoder_dealloc(PyObject *op) - { -+ nldecoder_object *self = nldecoder_object_CAST(op); - PyTypeObject *tp = Py_TYPE(self); - _PyObject_GC_UNTRACK(self); -- (void)incrementalnewlinedecoder_clear(self); -- tp->tp_free((PyObject *)self); -+ (void)incrementalnewlinedecoder_clear(op); -+ tp->tp_free(self); - Py_DECREF(tp); - } - -@@ -323,7 +327,7 @@ - { - PyObject *output; - Py_ssize_t output_len; -- nldecoder_object *self = (nldecoder_object *) myself; -+ nldecoder_object *self = nldecoder_object_CAST(myself); - - CHECK_INITIALIZED_DECODER(self); - -@@ -625,8 +629,9 @@ - } - - static PyObject * --incrementalnewlinedecoder_newlines_get(nldecoder_object *self, void *context) -+incrementalnewlinedecoder_newlines_get(PyObject *op, void *Py_UNUSED(context)) - { -+ nldecoder_object *self = nldecoder_object_CAST(op); - CHECK_INITIALIZED_DECODER(self); - - switch (self->seennl) { -@@ -652,8 +657,7 @@ - - /* TextIOWrapper */ - --typedef PyObject * -- (*encodefunc_t)(PyObject *, PyObject *); -+typedef PyObject *(*encodefunc_t)(PyObject *, PyObject *); - - struct textio - { -@@ -716,6 +720,8 @@ - _PyIO_State *state; - }; - -+#define textio_CAST(op) ((textio *)(op)) -+ - static void - textiowrapper_set_decoded_chars(textio *self, PyObject *chars); - -@@ -723,78 +729,81 @@ - encoding methods for the most popular encodings. */ - - static PyObject * --ascii_encode(textio *self, PyObject *text) -+ascii_encode(PyObject *op, PyObject *text) - { -+ textio *self = textio_CAST(op); - return _PyUnicode_AsASCIIString(text, PyUnicode_AsUTF8(self->errors)); - } - - static PyObject * --utf16be_encode(textio *self, PyObject *text) -+utf16be_encode(PyObject *op, PyObject *text) - { -- return _PyUnicode_EncodeUTF16(text, -- PyUnicode_AsUTF8(self->errors), 1); -+ textio *self = textio_CAST(op); -+ return _PyUnicode_EncodeUTF16(text, PyUnicode_AsUTF8(self->errors), 1); - } - - static PyObject * --utf16le_encode(textio *self, PyObject *text) -+utf16le_encode(PyObject *op, PyObject *text) - { -- return _PyUnicode_EncodeUTF16(text, -- PyUnicode_AsUTF8(self->errors), -1); -+ textio *self = textio_CAST(op); -+ return _PyUnicode_EncodeUTF16(text, PyUnicode_AsUTF8(self->errors), -1); - } - - static PyObject * --utf16_encode(textio *self, PyObject *text) -+utf16_encode(PyObject *op, PyObject *text) - { -+ textio *self = textio_CAST(op); - if (!self->encoding_start_of_stream) { - /* Skip the BOM and use native byte ordering */ - #if PY_BIG_ENDIAN -- return utf16be_encode(self, text); -+ return utf16be_encode(op, text); - #else -- return utf16le_encode(self, text); -+ return utf16le_encode(op, text); - #endif - } -- return _PyUnicode_EncodeUTF16(text, -- PyUnicode_AsUTF8(self->errors), 0); -+ return _PyUnicode_EncodeUTF16(text, PyUnicode_AsUTF8(self->errors), 0); - } - - static PyObject * --utf32be_encode(textio *self, PyObject *text) -+utf32be_encode(PyObject *op, PyObject *text) - { -- return _PyUnicode_EncodeUTF32(text, -- PyUnicode_AsUTF8(self->errors), 1); -+ textio *self = textio_CAST(op); -+ return _PyUnicode_EncodeUTF32(text, PyUnicode_AsUTF8(self->errors), 1); - } - - static PyObject * --utf32le_encode(textio *self, PyObject *text) -+utf32le_encode(PyObject *op, PyObject *text) - { -- return _PyUnicode_EncodeUTF32(text, -- PyUnicode_AsUTF8(self->errors), -1); -+ textio *self = textio_CAST(op); -+ return _PyUnicode_EncodeUTF32(text, PyUnicode_AsUTF8(self->errors), -1); - } - - static PyObject * --utf32_encode(textio *self, PyObject *text) -+utf32_encode(PyObject *op, PyObject *text) - { -+ textio *self = textio_CAST(op); - if (!self->encoding_start_of_stream) { - /* Skip the BOM and use native byte ordering */ - #if PY_BIG_ENDIAN -- return utf32be_encode(self, text); -+ return utf32be_encode(op, text); - #else -- return utf32le_encode(self, text); -+ return utf32le_encode(op, text); - #endif - } -- return _PyUnicode_EncodeUTF32(text, -- PyUnicode_AsUTF8(self->errors), 0); -+ return _PyUnicode_EncodeUTF32(text, PyUnicode_AsUTF8(self->errors), 0); - } - - static PyObject * --utf8_encode(textio *self, PyObject *text) -+utf8_encode(PyObject *op, PyObject *text) - { -+ textio *self = textio_CAST(op); - return _PyUnicode_AsUTF8String(text, PyUnicode_AsUTF8(self->errors)); - } - - static PyObject * --latin1_encode(textio *self, PyObject *text) -+latin1_encode(PyObject *op, PyObject *text) - { -+ textio *self = textio_CAST(op); - return _PyUnicode_AsLatin1String(text, PyUnicode_AsUTF8(self->errors)); - } - -@@ -802,9 +811,7 @@ - static inline int - is_asciicompat_encoding(encodefunc_t f) - { -- return f == (encodefunc_t) ascii_encode -- || f == (encodefunc_t) latin1_encode -- || f == (encodefunc_t) utf8_encode; -+ return f == ascii_encode || f == latin1_encode || f == utf8_encode; - } - - /* Map normalized encoding names onto the specialized encoding funcs */ -@@ -815,15 +822,15 @@ - } encodefuncentry; - - static const encodefuncentry encodefuncs[] = { -- {"ascii", (encodefunc_t) ascii_encode}, -- {"iso8859-1", (encodefunc_t) latin1_encode}, -- {"utf-8", (encodefunc_t) utf8_encode}, -- {"utf-16-be", (encodefunc_t) utf16be_encode}, -- {"utf-16-le", (encodefunc_t) utf16le_encode}, -- {"utf-16", (encodefunc_t) utf16_encode}, -- {"utf-32-be", (encodefunc_t) utf32be_encode}, -- {"utf-32-le", (encodefunc_t) utf32le_encode}, -- {"utf-32", (encodefunc_t) utf32_encode}, -+ {"ascii", ascii_encode}, -+ {"iso8859-1", latin1_encode}, -+ {"utf-8", utf8_encode}, -+ {"utf-16-be", utf16be_encode}, -+ {"utf-16-le", utf16le_encode}, -+ {"utf-16", utf16_encode}, -+ {"utf-32-be", utf32be_encode}, -+ {"utf-32-le", utf32le_encode}, -+ {"utf-32", utf32_encode}, - {NULL, NULL} - }; - -@@ -1433,8 +1440,9 @@ - } - - static int --textiowrapper_clear(textio *self) -+textiowrapper_clear(PyObject *op) - { -+ textio *self = textio_CAST(op); - self->ok = 0; - Py_CLEAR(self->buffer); - Py_CLEAR(self->encoding); -@@ -1452,24 +1460,26 @@ - } - - static void --textiowrapper_dealloc(textio *self) -+textiowrapper_dealloc(PyObject *op) - { -+ textio *self = textio_CAST(op); - PyTypeObject *tp = Py_TYPE(self); - self->finalizing = 1; -- if (_PyIOBase_finalize((PyObject *) self) < 0) -+ if (_PyIOBase_finalize(op) < 0) - return; - self->ok = 0; - _PyObject_GC_UNTRACK(self); - if (self->weakreflist != NULL) -- PyObject_ClearWeakRefs((PyObject *)self); -- (void)textiowrapper_clear(self); -- tp->tp_free((PyObject *)self); -+ PyObject_ClearWeakRefs(op); -+ (void)textiowrapper_clear(op); -+ tp->tp_free(self); - Py_DECREF(tp); - } - - static int --textiowrapper_traverse(textio *self, visitproc visit, void *arg) -+textiowrapper_traverse(PyObject *op, visitproc visit, void *arg) - { -+ textio *self = textio_CAST(op); - Py_VISIT(Py_TYPE(self)); - Py_VISIT(self->buffer); - Py_VISIT(self->encoding); -@@ -2963,10 +2973,11 @@ - } - - static PyObject * --textiowrapper_repr(textio *self) -+textiowrapper_repr(PyObject *op) - { - PyObject *nameobj, *modeobj, *res, *s; - int status; -+ textio *self = textio_CAST(op); - const char *type_name = Py_TYPE(self)->tp_name; - - CHECK_INITIALIZED(self); -@@ -2975,7 +2986,7 @@ - if (res == NULL) - return NULL; - -- status = Py_ReprEnter((PyObject *)self); -+ status = Py_ReprEnter(op); - if (status != 0) { - if (status > 0) { - PyErr_Format(PyExc_RuntimeError, -@@ -2984,7 +2995,7 @@ - } - goto error; - } -- if (PyObject_GetOptionalAttr((PyObject *) self, &_Py_ID(name), &nameobj) < 0) { -+ if (PyObject_GetOptionalAttr(op, &_Py_ID(name), &nameobj) < 0) { - if (!PyErr_ExceptionMatches(PyExc_ValueError)) { - goto error; - } -@@ -3000,7 +3011,7 @@ - if (res == NULL) - goto error; - } -- if (PyObject_GetOptionalAttr((PyObject *) self, &_Py_ID(mode), &modeobj) < 0) { -+ if (PyObject_GetOptionalAttr(op, &_Py_ID(mode), &modeobj) < 0) { - goto error; - } - if (modeobj != NULL) { -@@ -3016,14 +3027,14 @@ - res, self->encoding); - Py_DECREF(res); - if (status == 0) { -- Py_ReprLeave((PyObject *)self); -+ Py_ReprLeave(op); - } - return s; - - error: - Py_XDECREF(res); - if (status == 0) { -- Py_ReprLeave((PyObject *)self); -+ Py_ReprLeave(op); - } - return NULL; - } -@@ -3163,9 +3174,10 @@ - } - - static PyObject * --textiowrapper_iternext(textio *self) -+textiowrapper_iternext(PyObject *op) - { - PyObject *line; -+ textio *self = textio_CAST(op); - - CHECK_ATTACHED(self); - -@@ -3175,8 +3187,7 @@ - line = _textiowrapper_readline(self, -1); - } - else { -- line = PyObject_CallMethodNoArgs((PyObject *)self, -- &_Py_ID(readline)); -+ line = PyObject_CallMethodNoArgs(op, &_Py_ID(readline)); - if (line && !PyUnicode_Check(line)) { - PyErr_Format(PyExc_OSError, - "readline() should have returned a str object, " -@@ -3313,7 +3324,7 @@ - }; - - static PyGetSetDef incrementalnewlinedecoder_getset[] = { -- {"newlines", (getter)incrementalnewlinedecoder_newlines_get, NULL, NULL}, -+ {"newlines", incrementalnewlinedecoder_newlines_get, NULL, NULL}, - {NULL} - }; - -diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c -index 3fa0301e337..27c320ed073 100644 ---- a/Modules/_io/winconsoleio.c -+++ b/Modules/_io/winconsoleio.c -@@ -221,6 +221,8 @@ - wchar_t wbuf; - } winconsoleio; - -+#define winconsoleio_CAST(op) ((winconsoleio *)(op)) -+ - int - _PyWindowsConsoleIO_closed(PyObject *self) - { -@@ -492,32 +494,35 @@ - } - - static int --winconsoleio_traverse(winconsoleio *self, visitproc visit, void *arg) -+winconsoleio_traverse(PyObject *op, visitproc visit, void *arg) - { -+ winconsoleio *self = winconsoleio_CAST(op); - Py_VISIT(Py_TYPE(self)); - Py_VISIT(self->dict); - return 0; - } - - static int --winconsoleio_clear(winconsoleio *self) -+winconsoleio_clear(PyObject *op) - { -+ winconsoleio *self = winconsoleio_CAST(op); - Py_CLEAR(self->dict); - return 0; - } - - static void --winconsoleio_dealloc(winconsoleio *self) -+winconsoleio_dealloc(PyObject *op) - { -+ winconsoleio *self = winconsoleio_CAST(op); - PyTypeObject *tp = Py_TYPE(self); - self->finalizing = 1; -- if (_PyIOBase_finalize((PyObject *) self) < 0) -+ if (_PyIOBase_finalize(op) < 0) - return; - _PyObject_GC_UNTRACK(self); - if (self->weakreflist != NULL) -- PyObject_ClearWeakRefs((PyObject *) self); -+ PyObject_ClearWeakRefs(op); - Py_CLEAR(self->dict); -- tp->tp_free((PyObject *)self); -+ tp->tp_free(self); - Py_DECREF(tp); - } - -@@ -1137,9 +1142,10 @@ - } - - static PyObject * --winconsoleio_repr(winconsoleio *self) -+winconsoleio_repr(PyObject *op) - { -- const char *type_name = (Py_TYPE((PyObject *)self)->tp_name); -+ winconsoleio *self = winconsoleio_CAST(op); -+ const char *type_name = Py_TYPE(self)->tp_name; - - if (self->fd == -1) { - return PyUnicode_FromFormat("<%.100s [closed]>", type_name); -@@ -1197,28 +1203,31 @@ - /* 'closed' and 'mode' are attributes for compatibility with FileIO. */ - - static PyObject * --get_closed(winconsoleio *self, void *closure) -+get_closed(PyObject *op, void *Py_UNUSED(closure)) - { -+ winconsoleio *self = winconsoleio_CAST(op); - return PyBool_FromLong((long)(self->fd == -1)); - } - - static PyObject * --get_closefd(winconsoleio *self, void *closure) -+get_closefd(PyObject *op, void *Py_UNUSED(closure)) - { -+ winconsoleio *self = winconsoleio_CAST(op); - return PyBool_FromLong((long)(self->closefd)); - } - - static PyObject * --get_mode(winconsoleio *self, void *closure) -+get_mode(PyObject *op, void *Py_UNUSED(closure)) - { -+ winconsoleio *self = winconsoleio_CAST(op); - return PyUnicode_FromString(self->readable ? "rb" : "wb"); - } - - static PyGetSetDef winconsoleio_getsetlist[] = { -- {"closed", (getter)get_closed, NULL, "True if the file is closed"}, -- {"closefd", (getter)get_closefd, NULL, -+ {"closed", get_closed, NULL, "True if the file is closed"}, -+ {"closefd", get_closefd, NULL, - "True if the file descriptor will be closed by close()."}, -- {"mode", (getter)get_mode, NULL, "String giving the file mode"}, -+ {"mode", get_mode, NULL, "String giving the file mode"}, - {NULL}, - }; - -diff --git a/Modules/_json.c b/Modules/_json.c -index a99abbe72bf..5532e252819 100644 ---- a/Modules/_json.c -+++ b/Modules/_json.c -@@ -302,7 +302,7 @@ - /* Use JSONDecodeError exception to raise a nice looking ValueError subclass */ - _Py_DECLARE_STR(json_decoder, "json.decoder"); - PyObject *JSONDecodeError = -- _PyImport_GetModuleAttr(&_Py_STR(json_decoder), &_Py_ID(JSONDecodeError)); -+ PyImport_ImportModuleAttr(&_Py_STR(json_decoder), &_Py_ID(JSONDecodeError)); - if (JSONDecodeError == NULL) { - return; - } -@@ -353,6 +353,13 @@ - return tpl; - } - -+static inline int -+_PyUnicodeWriter_IsEmpty(PyUnicodeWriter *writer_pub) -+{ -+ _PyUnicodeWriter *writer = (_PyUnicodeWriter*)writer_pub; -+ return (writer->pos == 0); -+} -+ - static PyObject * - scanstring_unicode(PyObject *pystr, Py_ssize_t end, int strict, Py_ssize_t *next_end_ptr) - { -@@ -371,9 +378,10 @@ - const void *buf; - int kind; - -- _PyUnicodeWriter writer; -- _PyUnicodeWriter_Init(&writer); -- writer.overallocate = 1; -+ PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); -+ if (writer == NULL) { -+ goto bail; -+ } - - len = PyUnicode_GET_LENGTH(pystr); - buf = PyUnicode_DATA(pystr); -@@ -404,11 +412,12 @@ - - if (c == '"') { - // Fast path for simple case. -- if (writer.buffer == NULL) { -+ if (_PyUnicodeWriter_IsEmpty(writer)) { - PyObject *ret = PyUnicode_Substring(pystr, end, next); - if (ret == NULL) { - goto bail; - } -+ PyUnicodeWriter_Discard(writer); - *next_end_ptr = next + 1;; - return ret; - } -@@ -420,7 +429,7 @@ - - /* Pick up this chunk if it's not zero length */ - if (next != end) { -- if (_PyUnicodeWriter_WriteSubstring(&writer, pystr, end, next) < 0) { -+ if (PyUnicodeWriter_WriteSubstring(writer, pystr, end, next) < 0) { - goto bail; - } - } -@@ -511,18 +520,18 @@ - end -= 6; - } - } -- if (_PyUnicodeWriter_WriteChar(&writer, c) < 0) { -+ if (PyUnicodeWriter_WriteChar(writer, c) < 0) { - goto bail; - } - } - -- rval = _PyUnicodeWriter_Finish(&writer); -+ rval = PyUnicodeWriter_Finish(writer); - *next_end_ptr = end; - return rval; - - bail: - *next_end_ptr = -1; -- _PyUnicodeWriter_Dealloc(&writer); -+ PyUnicodeWriter_Discard(writer); - return NULL; - } - -diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c -index 51ad9fc7da8..eab26b39be1 100644 ---- a/Modules/_lsprof.c -+++ b/Modules/_lsprof.c -@@ -97,7 +97,8 @@ - pObj->flags &= ~POF_EXT_TIMER; - - if (o == NULL) { -- PyErr_WriteUnraisable(pObj->externalTimer); -+ PyErr_FormatUnraisable("Exception ignored while calling " -+ "_lsprof timer %R", pObj->externalTimer); - return 0; - } - -@@ -116,7 +117,8 @@ - } - Py_DECREF(o); - if (err < 0) { -- PyErr_WriteUnraisable(pObj->externalTimer); -+ PyErr_FormatUnraisable("Exception ignored while calling " -+ "_lsprof timer %R", pObj->externalTimer); - return 0; - } - return result; -@@ -775,7 +777,7 @@ - return NULL; - } - -- PyObject* monitoring = _PyImport_GetModuleAttrString("sys", "monitoring"); -+ PyObject* monitoring = PyImport_ImportModuleAttrString("sys", "monitoring"); - if (!monitoring) { - return NULL; - } -@@ -857,7 +859,7 @@ - } - if (self->flags & POF_ENABLED) { - PyObject* result = NULL; -- PyObject* monitoring = _PyImport_GetModuleAttrString("sys", "monitoring"); -+ PyObject* monitoring = PyImport_ImportModuleAttrString("sys", "monitoring"); - - if (!monitoring) { - return NULL; -@@ -933,7 +935,8 @@ - if (op->flags & POF_ENABLED) { - PyThreadState *tstate = _PyThreadState_GET(); - if (_PyEval_SetProfile(tstate, NULL, NULL) < 0) { -- PyErr_FormatUnraisable("Exception ignored when destroying _lsprof profiler"); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "destroying _lsprof profiler"); - } - } - -@@ -973,7 +976,7 @@ - Py_XSETREF(self->externalTimer, Py_XNewRef(timer)); - self->tool_id = PY_MONITORING_PROFILER_ID; - -- PyObject* monitoring = _PyImport_GetModuleAttrString("sys", "monitoring"); -+ PyObject* monitoring = PyImport_ImportModuleAttrString("sys", "monitoring"); - if (!monitoring) { - return -1; - } -diff --git a/Modules/_multiprocessing/clinic/semaphore.c.h b/Modules/_multiprocessing/clinic/semaphore.c.h -index 2702c3369c7..e789137ec1e 100644 ---- a/Modules/_multiprocessing/clinic/semaphore.c.h -+++ b/Modules/_multiprocessing/clinic/semaphore.c.h -@@ -25,7 +25,7 @@ - PyObject *timeout_obj); - - static PyObject * --_multiprocessing_SemLock_acquire(SemLockObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_multiprocessing_SemLock_acquire(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -78,7 +78,7 @@ - timeout_obj = args[1]; - skip_optional_pos: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _multiprocessing_SemLock_acquire_impl(self, blocking, timeout_obj); -+ return_value = _multiprocessing_SemLock_acquire_impl((SemLockObject *)self, blocking, timeout_obj); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -102,12 +102,12 @@ - _multiprocessing_SemLock_release_impl(SemLockObject *self); - - static PyObject * --_multiprocessing_SemLock_release(SemLockObject *self, PyObject *Py_UNUSED(ignored)) -+_multiprocessing_SemLock_release(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _multiprocessing_SemLock_release_impl(self); -+ return_value = _multiprocessing_SemLock_release_impl((SemLockObject *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -131,7 +131,7 @@ - PyObject *timeout_obj); - - static PyObject * --_multiprocessing_SemLock_acquire(SemLockObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_multiprocessing_SemLock_acquire(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -184,7 +184,7 @@ - timeout_obj = args[1]; - skip_optional_pos: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _multiprocessing_SemLock_acquire_impl(self, blocking, timeout_obj); -+ return_value = _multiprocessing_SemLock_acquire_impl((SemLockObject *)self, blocking, timeout_obj); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -208,12 +208,12 @@ - _multiprocessing_SemLock_release_impl(SemLockObject *self); - - static PyObject * --_multiprocessing_SemLock_release(SemLockObject *self, PyObject *Py_UNUSED(ignored)) -+_multiprocessing_SemLock_release(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _multiprocessing_SemLock_release_impl(self); -+ return_value = _multiprocessing_SemLock_release_impl((SemLockObject *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -358,12 +358,12 @@ - _multiprocessing_SemLock__count_impl(SemLockObject *self); - - static PyObject * --_multiprocessing_SemLock__count(SemLockObject *self, PyObject *Py_UNUSED(ignored)) -+_multiprocessing_SemLock__count(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _multiprocessing_SemLock__count_impl(self); -+ return_value = _multiprocessing_SemLock__count_impl((SemLockObject *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -386,9 +386,9 @@ - _multiprocessing_SemLock__is_mine_impl(SemLockObject *self); - - static PyObject * --_multiprocessing_SemLock__is_mine(SemLockObject *self, PyObject *Py_UNUSED(ignored)) -+_multiprocessing_SemLock__is_mine(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _multiprocessing_SemLock__is_mine_impl(self); -+ return _multiprocessing_SemLock__is_mine_impl((SemLockObject *)self); - } - - #endif /* defined(HAVE_MP_SEMAPHORE) */ -@@ -408,9 +408,9 @@ - _multiprocessing_SemLock__get_value_impl(SemLockObject *self); - - static PyObject * --_multiprocessing_SemLock__get_value(SemLockObject *self, PyObject *Py_UNUSED(ignored)) -+_multiprocessing_SemLock__get_value(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _multiprocessing_SemLock__get_value_impl(self); -+ return _multiprocessing_SemLock__get_value_impl((SemLockObject *)self); - } - - #endif /* defined(HAVE_MP_SEMAPHORE) */ -@@ -430,9 +430,9 @@ - _multiprocessing_SemLock__is_zero_impl(SemLockObject *self); - - static PyObject * --_multiprocessing_SemLock__is_zero(SemLockObject *self, PyObject *Py_UNUSED(ignored)) -+_multiprocessing_SemLock__is_zero(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _multiprocessing_SemLock__is_zero_impl(self); -+ return _multiprocessing_SemLock__is_zero_impl((SemLockObject *)self); - } - - #endif /* defined(HAVE_MP_SEMAPHORE) */ -@@ -452,9 +452,9 @@ - _multiprocessing_SemLock__after_fork_impl(SemLockObject *self); - - static PyObject * --_multiprocessing_SemLock__after_fork(SemLockObject *self, PyObject *Py_UNUSED(ignored)) -+_multiprocessing_SemLock__after_fork(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _multiprocessing_SemLock__after_fork_impl(self); -+ return _multiprocessing_SemLock__after_fork_impl((SemLockObject *)self); - } - - #endif /* defined(HAVE_MP_SEMAPHORE) */ -@@ -474,12 +474,12 @@ - _multiprocessing_SemLock___enter___impl(SemLockObject *self); - - static PyObject * --_multiprocessing_SemLock___enter__(SemLockObject *self, PyObject *Py_UNUSED(ignored)) -+_multiprocessing_SemLock___enter__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _multiprocessing_SemLock___enter___impl(self); -+ return_value = _multiprocessing_SemLock___enter___impl((SemLockObject *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -504,7 +504,7 @@ - PyObject *exc_value, PyObject *exc_tb); - - static PyObject * --_multiprocessing_SemLock___exit__(SemLockObject *self, PyObject *const *args, Py_ssize_t nargs) -+_multiprocessing_SemLock___exit__(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *exc_type = Py_None; -@@ -528,7 +528,7 @@ - exc_tb = args[2]; - skip_optional: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _multiprocessing_SemLock___exit___impl(self, exc_type, exc_value, exc_tb); -+ return_value = _multiprocessing_SemLock___exit___impl((SemLockObject *)self, exc_type, exc_value, exc_tb); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -576,4 +576,4 @@ - #ifndef _MULTIPROCESSING_SEMLOCK___EXIT___METHODDEF - #define _MULTIPROCESSING_SEMLOCK___EXIT___METHODDEF - #endif /* !defined(_MULTIPROCESSING_SEMLOCK___EXIT___METHODDEF) */ --/*[clinic end generated code: output=9023d3e48a24afd2 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=e28d0fdbfefd1235 input=a9049054013a1b77]*/ -diff --git a/Modules/_multiprocessing/semaphore.c b/Modules/_multiprocessing/semaphore.c -index 9eef7c25636..036db2cd4c6 100644 ---- a/Modules/_multiprocessing/semaphore.c -+++ b/Modules/_multiprocessing/semaphore.c -@@ -28,6 +28,8 @@ - char *name; - } SemLockObject; - -+#define _SemLockObject_CAST(op) ((SemLockObject *)(op)) -+ - /*[python input] - class SEM_HANDLE_converter(CConverter): - type = "SEM_HANDLE" -@@ -576,8 +578,9 @@ - } - - static void --semlock_dealloc(SemLockObject* self) -+semlock_dealloc(PyObject *op) - { -+ SemLockObject *self = _SemLockObject_CAST(op); - PyTypeObject *tp = Py_TYPE(self); - PyObject_GC_UnTrack(self); - if (self->handle != SEM_FAILED) -@@ -718,7 +721,7 @@ - } - - static int --semlock_traverse(SemLockObject *s, visitproc visit, void *arg) -+semlock_traverse(PyObject *s, visitproc visit, void *arg) - { - Py_VISIT(Py_TYPE(s)); - return 0; -diff --git a/Modules/_opcode.c b/Modules/_opcode.c -index 7ccf7af6bf9..c295f7b3152 100644 ---- a/Modules/_opcode.c -+++ b/Modules/_opcode.c -@@ -274,6 +274,7 @@ - ADD_NB_OP(NB_INPLACE_SUBTRACT, "-="); - ADD_NB_OP(NB_INPLACE_TRUE_DIVIDE, "/="); - ADD_NB_OP(NB_INPLACE_XOR, "^="); -+ ADD_NB_OP(NB_SUBSCR, "[]"); - - #undef ADD_NB_OP - -diff --git a/Modules/_operator.c b/Modules/_operator.c -index ce3ef015710..59987b8f143 100644 ---- a/Modules/_operator.c -+++ b/Modules/_operator.c -@@ -1868,7 +1868,7 @@ - PyObject *constructor; - PyObject *newargs[2]; - -- partial = _PyImport_GetModuleAttrString("functools", "partial"); -+ partial = PyImport_ImportModuleAttrString("functools", "partial"); - if (!partial) - return NULL; - -diff --git a/Modules/_pickle.c b/Modules/_pickle.c -index 599b5f92c2a..5641f93391c 100644 ---- a/Modules/_pickle.c -+++ b/Modules/_pickle.c -@@ -362,7 +362,7 @@ - } - Py_CLEAR(compat_pickle); - -- st->codecs_encode = _PyImport_GetModuleAttrString("codecs", "encode"); -+ st->codecs_encode = PyImport_ImportModuleAttrString("codecs", "encode"); - if (st->codecs_encode == NULL) { - goto error; - } -@@ -373,7 +373,7 @@ - goto error; - } - -- st->partial = _PyImport_GetModuleAttrString("functools", "partial"); -+ st->partial = PyImport_ImportModuleAttrString("functools", "partial"); - if (!st->partial) - goto error; - -@@ -2159,8 +2159,10 @@ - unsigned char *pdata; - char header[5]; - int i; -- int sign = _PyLong_Sign(obj); - -+ int sign; -+ assert(PyLong_Check(obj)); -+ (void)PyLong_GetSign(obj, &sign); - if (sign == 0) { - header[0] = LONG1; - header[1] = 0; /* It's 0 -- an empty bytestring. */ -diff --git a/Modules/_sqlite/blob.c b/Modules/_sqlite/blob.c -index d1a549a971c..35d090e3ca2 100644 ---- a/Modules/_sqlite/blob.c -+++ b/Modules/_sqlite/blob.c -@@ -9,6 +9,8 @@ - #include "clinic/blob.c.h" - #undef clinic_state - -+#define _pysqlite_Blob_CAST(op) ((pysqlite_Blob *)(op)) -+ - /*[clinic input] - module _sqlite3 - class _sqlite3.Blob "pysqlite_Blob *" "clinic_state()->BlobType" -@@ -29,32 +31,35 @@ - } - - static int --blob_traverse(pysqlite_Blob *self, visitproc visit, void *arg) -+blob_traverse(PyObject *op, visitproc visit, void *arg) - { -+ pysqlite_Blob *self = _pysqlite_Blob_CAST(op); - Py_VISIT(Py_TYPE(self)); - Py_VISIT(self->connection); - return 0; - } - - static int --blob_clear(pysqlite_Blob *self) -+blob_clear(PyObject *op) - { -+ pysqlite_Blob *self = _pysqlite_Blob_CAST(op); - Py_CLEAR(self->connection); - return 0; - } - - static void --blob_dealloc(pysqlite_Blob *self) -+blob_dealloc(PyObject *op) - { -+ pysqlite_Blob *self = _pysqlite_Blob_CAST(op); - PyTypeObject *tp = Py_TYPE(self); - PyObject_GC_UnTrack(self); - - close_blob(self); - - if (self->in_weakreflist != NULL) { -- PyObject_ClearWeakRefs((PyObject*)self); -+ PyObject_ClearWeakRefs(op); - } -- tp->tp_clear((PyObject *)self); -+ (void)tp->tp_clear(op); - tp->tp_free(self); - Py_DECREF(tp); - } -@@ -114,7 +119,7 @@ - blob_seterror(pysqlite_Blob *self, int rc) - { - assert(self->connection != NULL); -- _pysqlite_seterror(self->connection->state, self->connection->db); -+ set_error_from_db(self->connection->state, self->connection->db); - } - - static PyObject * -@@ -373,8 +378,9 @@ - } - - static Py_ssize_t --blob_length(pysqlite_Blob *self) -+blob_length(PyObject *op) - { -+ pysqlite_Blob *self = _pysqlite_Blob_CAST(op); - if (!check_blob(self)) { - return -1; - } -@@ -449,8 +455,9 @@ - } - - static PyObject * --blob_subscript(pysqlite_Blob *self, PyObject *item) -+blob_subscript(PyObject *op, PyObject *item) - { -+ pysqlite_Blob *self = _pysqlite_Blob_CAST(op); - if (!check_blob(self)) { - return NULL; - } -@@ -546,8 +553,9 @@ - } - - static int --blob_ass_subscript(pysqlite_Blob *self, PyObject *item, PyObject *value) -+blob_ass_subscript(PyObject *op, PyObject *item, PyObject *value) - { -+ pysqlite_Blob *self = _pysqlite_Blob_CAST(op); - if (!check_blob(self)) { - return -1; - } -diff --git a/Modules/_sqlite/clinic/blob.c.h b/Modules/_sqlite/clinic/blob.c.h -index b95ba948aaf..921e7cbd7ff 100644 ---- a/Modules/_sqlite/clinic/blob.c.h -+++ b/Modules/_sqlite/clinic/blob.c.h -@@ -17,9 +17,9 @@ - blob_close_impl(pysqlite_Blob *self); - - static PyObject * --blob_close(pysqlite_Blob *self, PyObject *Py_UNUSED(ignored)) -+blob_close(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return blob_close_impl(self); -+ return blob_close_impl((pysqlite_Blob *)self); - } - - PyDoc_STRVAR(blob_read__doc__, -@@ -42,7 +42,7 @@ - blob_read_impl(pysqlite_Blob *self, int length); - - static PyObject * --blob_read(pysqlite_Blob *self, PyObject *const *args, Py_ssize_t nargs) -+blob_read(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - int length = -1; -@@ -58,7 +58,7 @@ - goto exit; - } - skip_optional: -- return_value = blob_read_impl(self, length); -+ return_value = blob_read_impl((pysqlite_Blob *)self, length); - - exit: - return return_value; -@@ -80,7 +80,7 @@ - blob_write_impl(pysqlite_Blob *self, Py_buffer *data); - - static PyObject * --blob_write(pysqlite_Blob *self, PyObject *arg) -+blob_write(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - Py_buffer data = {NULL, NULL}; -@@ -88,7 +88,7 @@ - if (PyObject_GetBuffer(arg, &data, PyBUF_SIMPLE) != 0) { - goto exit; - } -- return_value = blob_write_impl(self, &data); -+ return_value = blob_write_impl((pysqlite_Blob *)self, &data); - - exit: - /* Cleanup for data */ -@@ -116,7 +116,7 @@ - blob_seek_impl(pysqlite_Blob *self, int offset, int origin); - - static PyObject * --blob_seek(pysqlite_Blob *self, PyObject *const *args, Py_ssize_t nargs) -+blob_seek(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - int offset; -@@ -137,7 +137,7 @@ - goto exit; - } - skip_optional: -- return_value = blob_seek_impl(self, offset, origin); -+ return_value = blob_seek_impl((pysqlite_Blob *)self, offset, origin); - - exit: - return return_value; -@@ -156,9 +156,9 @@ - blob_tell_impl(pysqlite_Blob *self); - - static PyObject * --blob_tell(pysqlite_Blob *self, PyObject *Py_UNUSED(ignored)) -+blob_tell(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return blob_tell_impl(self); -+ return blob_tell_impl((pysqlite_Blob *)self); - } - - PyDoc_STRVAR(blob_enter__doc__, -@@ -174,9 +174,9 @@ - blob_enter_impl(pysqlite_Blob *self); - - static PyObject * --blob_enter(pysqlite_Blob *self, PyObject *Py_UNUSED(ignored)) -+blob_enter(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return blob_enter_impl(self); -+ return blob_enter_impl((pysqlite_Blob *)self); - } - - PyDoc_STRVAR(blob_exit__doc__, -@@ -193,7 +193,7 @@ - PyObject *tb); - - static PyObject * --blob_exit(pysqlite_Blob *self, PyObject *const *args, Py_ssize_t nargs) -+blob_exit(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *type; -@@ -206,9 +206,9 @@ - type = args[0]; - val = args[1]; - tb = args[2]; -- return_value = blob_exit_impl(self, type, val, tb); -+ return_value = blob_exit_impl((pysqlite_Blob *)self, type, val, tb); - - exit: - return return_value; - } --/*[clinic end generated code: output=31abd55660e0c5af input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=f03f4ba622b67ae0 input=a9049054013a1b77]*/ -diff --git a/Modules/_sqlite/clinic/connection.c.h b/Modules/_sqlite/clinic/connection.c.h -index 42eb6eb2f12..82fba44eb1b 100644 ---- a/Modules/_sqlite/clinic/connection.c.h -+++ b/Modules/_sqlite/clinic/connection.c.h -@@ -182,7 +182,7 @@ - pysqlite_connection_cursor_impl(pysqlite_Connection *self, PyObject *factory); - - static PyObject * --pysqlite_connection_cursor(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+pysqlite_connection_cursor(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -224,7 +224,7 @@ - } - factory = args[0]; - skip_optional_pos: -- return_value = pysqlite_connection_cursor_impl(self, factory); -+ return_value = pysqlite_connection_cursor_impl((pysqlite_Connection *)self, factory); - - exit: - return return_value; -@@ -255,7 +255,7 @@ - sqlite3_int64 row, int readonly, const char *name); - - static PyObject * --blobopen(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+blobopen(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -351,7 +351,7 @@ - goto exit; - } - skip_optional_kwonly: -- return_value = blobopen_impl(self, table, col, row, readonly, name); -+ return_value = blobopen_impl((pysqlite_Connection *)self, table, col, row, readonly, name); - - exit: - return return_value; -@@ -372,9 +372,9 @@ - pysqlite_connection_close_impl(pysqlite_Connection *self); - - static PyObject * --pysqlite_connection_close(pysqlite_Connection *self, PyObject *Py_UNUSED(ignored)) -+pysqlite_connection_close(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return pysqlite_connection_close_impl(self); -+ return pysqlite_connection_close_impl((pysqlite_Connection *)self); - } - - PyDoc_STRVAR(pysqlite_connection_commit__doc__, -@@ -392,9 +392,9 @@ - pysqlite_connection_commit_impl(pysqlite_Connection *self); - - static PyObject * --pysqlite_connection_commit(pysqlite_Connection *self, PyObject *Py_UNUSED(ignored)) -+pysqlite_connection_commit(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return pysqlite_connection_commit_impl(self); -+ return pysqlite_connection_commit_impl((pysqlite_Connection *)self); - } - - PyDoc_STRVAR(pysqlite_connection_rollback__doc__, -@@ -412,9 +412,9 @@ - pysqlite_connection_rollback_impl(pysqlite_Connection *self); - - static PyObject * --pysqlite_connection_rollback(pysqlite_Connection *self, PyObject *Py_UNUSED(ignored)) -+pysqlite_connection_rollback(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return pysqlite_connection_rollback_impl(self); -+ return pysqlite_connection_rollback_impl((pysqlite_Connection *)self); - } - - PyDoc_STRVAR(pysqlite_connection_create_function__doc__, -@@ -449,7 +449,7 @@ - #endif - - static PyObject * --pysqlite_connection_create_function(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+pysqlite_connection_create_function(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -525,7 +525,7 @@ - goto exit; - } - skip_optional_kwonly: -- return_value = pysqlite_connection_create_function_impl(self, cls, name, narg, func, deterministic); -+ return_value = pysqlite_connection_create_function_impl((pysqlite_Connection *)self, cls, name, narg, func, deterministic); - - exit: - return return_value; -@@ -557,7 +557,7 @@ - PyObject *aggregate_class); - - static PyObject * --create_window_function(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+create_window_function(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -601,7 +601,7 @@ - goto exit; - } - aggregate_class = args[2]; -- return_value = create_window_function_impl(self, cls, name, num_params, aggregate_class); -+ return_value = create_window_function_impl((pysqlite_Connection *)self, cls, name, num_params, aggregate_class); - - exit: - return return_value; -@@ -642,7 +642,7 @@ - #endif - - static PyObject * --pysqlite_connection_create_aggregate(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+pysqlite_connection_create_aggregate(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -708,7 +708,7 @@ - goto exit; - } - aggregate_class = args[2]; -- return_value = pysqlite_connection_create_aggregate_impl(self, cls, name, n_arg, aggregate_class); -+ return_value = pysqlite_connection_create_aggregate_impl((pysqlite_Connection *)self, cls, name, n_arg, aggregate_class); - - exit: - return return_value; -@@ -745,7 +745,7 @@ - #endif - - static PyObject * --pysqlite_connection_set_authorizer(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+pysqlite_connection_set_authorizer(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -792,7 +792,7 @@ - } - } - callable = args[0]; -- return_value = pysqlite_connection_set_authorizer_impl(self, cls, callable); -+ return_value = pysqlite_connection_set_authorizer_impl((pysqlite_Connection *)self, cls, callable); - - exit: - return return_value; -@@ -839,7 +839,7 @@ - #endif - - static PyObject * --pysqlite_connection_set_progress_handler(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+pysqlite_connection_set_progress_handler(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -891,7 +891,7 @@ - if (n == -1 && PyErr_Occurred()) { - goto exit; - } -- return_value = pysqlite_connection_set_progress_handler_impl(self, cls, callable, n); -+ return_value = pysqlite_connection_set_progress_handler_impl((pysqlite_Connection *)self, cls, callable, n); - - exit: - return return_value; -@@ -928,7 +928,7 @@ - #endif - - static PyObject * --pysqlite_connection_set_trace_callback(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+pysqlite_connection_set_trace_callback(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -975,7 +975,7 @@ - } - } - callable = args[0]; -- return_value = pysqlite_connection_set_trace_callback_impl(self, cls, callable); -+ return_value = pysqlite_connection_set_trace_callback_impl((pysqlite_Connection *)self, cls, callable); - - exit: - return return_value; -@@ -997,7 +997,7 @@ - int onoff); - - static PyObject * --pysqlite_connection_enable_load_extension(pysqlite_Connection *self, PyObject *arg) -+pysqlite_connection_enable_load_extension(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - int onoff; -@@ -1006,7 +1006,7 @@ - if (onoff < 0) { - goto exit; - } -- return_value = pysqlite_connection_enable_load_extension_impl(self, onoff); -+ return_value = pysqlite_connection_enable_load_extension_impl((pysqlite_Connection *)self, onoff); - - exit: - return return_value; -@@ -1031,7 +1031,7 @@ - const char *entrypoint); - - static PyObject * --pysqlite_connection_load_extension(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+pysqlite_connection_load_extension(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -1104,7 +1104,7 @@ - goto exit; - } - skip_optional_kwonly: -- return_value = pysqlite_connection_load_extension_impl(self, extension_name, entrypoint); -+ return_value = pysqlite_connection_load_extension_impl((pysqlite_Connection *)self, extension_name, entrypoint); - - exit: - return return_value; -@@ -1126,7 +1126,7 @@ - PyObject *parameters); - - static PyObject * --pysqlite_connection_execute(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs) -+pysqlite_connection_execute(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *sql; -@@ -1145,7 +1145,7 @@ - } - parameters = args[1]; - skip_optional: -- return_value = pysqlite_connection_execute_impl(self, sql, parameters); -+ return_value = pysqlite_connection_execute_impl((pysqlite_Connection *)self, sql, parameters); - - exit: - return return_value; -@@ -1165,7 +1165,7 @@ - PyObject *sql, PyObject *parameters); - - static PyObject * --pysqlite_connection_executemany(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs) -+pysqlite_connection_executemany(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *sql; -@@ -1180,7 +1180,7 @@ - } - sql = args[0]; - parameters = args[1]; -- return_value = pysqlite_connection_executemany_impl(self, sql, parameters); -+ return_value = pysqlite_connection_executemany_impl((pysqlite_Connection *)self, sql, parameters); - - exit: - return return_value; -@@ -1208,9 +1208,9 @@ - pysqlite_connection_interrupt_impl(pysqlite_Connection *self); - - static PyObject * --pysqlite_connection_interrupt(pysqlite_Connection *self, PyObject *Py_UNUSED(ignored)) -+pysqlite_connection_interrupt(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return pysqlite_connection_interrupt_impl(self); -+ return pysqlite_connection_interrupt_impl((pysqlite_Connection *)self); - } - - PyDoc_STRVAR(pysqlite_connection_iterdump__doc__, -@@ -1230,7 +1230,7 @@ - PyObject *filter); - - static PyObject * --pysqlite_connection_iterdump(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+pysqlite_connection_iterdump(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -1272,7 +1272,7 @@ - } - filter = args[0]; - skip_optional_kwonly: -- return_value = pysqlite_connection_iterdump_impl(self, filter); -+ return_value = pysqlite_connection_iterdump_impl((pysqlite_Connection *)self, filter); - - exit: - return return_value; -@@ -1295,7 +1295,7 @@ - double sleep); - - static PyObject * --pysqlite_connection_backup(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+pysqlite_connection_backup(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -1388,7 +1388,7 @@ - } - } - skip_optional_kwonly: -- return_value = pysqlite_connection_backup_impl(self, target, pages, progress, name, sleep); -+ return_value = pysqlite_connection_backup_impl((pysqlite_Connection *)self, target, pages, progress, name, sleep); - - exit: - return return_value; -@@ -1410,7 +1410,7 @@ - PyObject *callable); - - static PyObject * --pysqlite_connection_create_collation(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+pysqlite_connection_create_collation(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -1449,7 +1449,7 @@ - goto exit; - } - callable = args[1]; -- return_value = pysqlite_connection_create_collation_impl(self, cls, name, callable); -+ return_value = pysqlite_connection_create_collation_impl((pysqlite_Connection *)self, cls, name, callable); - - exit: - return return_value; -@@ -1478,7 +1478,7 @@ - serialize_impl(pysqlite_Connection *self, const char *name); - - static PyObject * --serialize(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+serialize(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -1532,7 +1532,7 @@ - goto exit; - } - skip_optional_kwonly: -- return_value = serialize_impl(self, name); -+ return_value = serialize_impl((pysqlite_Connection *)self, name); - - exit: - return return_value; -@@ -1568,7 +1568,7 @@ - const char *name); - - static PyObject * --deserialize(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+deserialize(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -1638,7 +1638,7 @@ - goto exit; - } - skip_optional_kwonly: -- return_value = deserialize_impl(self, &data, name); -+ return_value = deserialize_impl((pysqlite_Connection *)self, &data, name); - - exit: - /* Cleanup for data */ -@@ -1666,9 +1666,9 @@ - pysqlite_connection_enter_impl(pysqlite_Connection *self); - - static PyObject * --pysqlite_connection_enter(pysqlite_Connection *self, PyObject *Py_UNUSED(ignored)) -+pysqlite_connection_enter(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return pysqlite_connection_enter_impl(self); -+ return pysqlite_connection_enter_impl((pysqlite_Connection *)self); - } - - PyDoc_STRVAR(pysqlite_connection_exit__doc__, -@@ -1687,7 +1687,7 @@ - PyObject *exc_value, PyObject *exc_tb); - - static PyObject * --pysqlite_connection_exit(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs) -+pysqlite_connection_exit(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *exc_type; -@@ -1700,7 +1700,7 @@ - exc_type = args[0]; - exc_value = args[1]; - exc_tb = args[2]; -- return_value = pysqlite_connection_exit_impl(self, exc_type, exc_value, exc_tb); -+ return_value = pysqlite_connection_exit_impl((pysqlite_Connection *)self, exc_type, exc_value, exc_tb); - - exit: - return return_value; -@@ -1729,7 +1729,7 @@ - setlimit_impl(pysqlite_Connection *self, int category, int limit); - - static PyObject * --setlimit(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs) -+setlimit(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - int category; -@@ -1746,7 +1746,7 @@ - if (limit == -1 && PyErr_Occurred()) { - goto exit; - } -- return_value = setlimit_impl(self, category, limit); -+ return_value = setlimit_impl((pysqlite_Connection *)self, category, limit); - - exit: - return return_value; -@@ -1768,7 +1768,7 @@ - getlimit_impl(pysqlite_Connection *self, int category); - - static PyObject * --getlimit(pysqlite_Connection *self, PyObject *arg) -+getlimit(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - int category; -@@ -1777,7 +1777,7 @@ - if (category == -1 && PyErr_Occurred()) { - goto exit; - } -- return_value = getlimit_impl(self, category); -+ return_value = getlimit_impl((pysqlite_Connection *)self, category); - - exit: - return return_value; -@@ -1799,7 +1799,7 @@ - setconfig_impl(pysqlite_Connection *self, int op, int enable); - - static PyObject * --setconfig(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs) -+setconfig(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - int op; -@@ -1820,7 +1820,7 @@ - goto exit; - } - skip_optional: -- return_value = setconfig_impl(self, op, enable); -+ return_value = setconfig_impl((pysqlite_Connection *)self, op, enable); - - exit: - return return_value; -@@ -1842,7 +1842,7 @@ - getconfig_impl(pysqlite_Connection *self, int op); - - static PyObject * --getconfig(pysqlite_Connection *self, PyObject *arg) -+getconfig(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - int op; -@@ -1852,7 +1852,7 @@ - if (op == -1 && PyErr_Occurred()) { - goto exit; - } -- _return_value = getconfig_impl(self, op); -+ _return_value = getconfig_impl((pysqlite_Connection *)self, op); - if ((_return_value == -1) && PyErr_Occurred()) { - goto exit; - } -@@ -1881,4 +1881,4 @@ - #ifndef DESERIALIZE_METHODDEF - #define DESERIALIZE_METHODDEF - #endif /* !defined(DESERIALIZE_METHODDEF) */ --/*[clinic end generated code: output=a8fd19301c7390cc input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=c59effb407b8ea4d input=a9049054013a1b77]*/ -diff --git a/Modules/_sqlite/clinic/cursor.c.h b/Modules/_sqlite/clinic/cursor.c.h -index ca7823cf5ae..590e429e913 100644 ---- a/Modules/_sqlite/clinic/cursor.c.h -+++ b/Modules/_sqlite/clinic/cursor.c.h -@@ -52,7 +52,7 @@ - PyObject *parameters); - - static PyObject * --pysqlite_cursor_execute(pysqlite_Cursor *self, PyObject *const *args, Py_ssize_t nargs) -+pysqlite_cursor_execute(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *sql; -@@ -71,7 +71,7 @@ - } - parameters = args[1]; - skip_optional: -- return_value = pysqlite_cursor_execute_impl(self, sql, parameters); -+ return_value = pysqlite_cursor_execute_impl((pysqlite_Cursor *)self, sql, parameters); - - exit: - return return_value; -@@ -91,7 +91,7 @@ - PyObject *seq_of_parameters); - - static PyObject * --pysqlite_cursor_executemany(pysqlite_Cursor *self, PyObject *const *args, Py_ssize_t nargs) -+pysqlite_cursor_executemany(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *sql; -@@ -106,7 +106,7 @@ - } - sql = args[0]; - seq_of_parameters = args[1]; -- return_value = pysqlite_cursor_executemany_impl(self, sql, seq_of_parameters); -+ return_value = pysqlite_cursor_executemany_impl((pysqlite_Cursor *)self, sql, seq_of_parameters); - - exit: - return return_value; -@@ -126,7 +126,7 @@ - const char *sql_script); - - static PyObject * --pysqlite_cursor_executescript(pysqlite_Cursor *self, PyObject *arg) -+pysqlite_cursor_executescript(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - const char *sql_script; -@@ -144,7 +144,7 @@ - PyErr_SetString(PyExc_ValueError, "embedded null character"); - goto exit; - } -- return_value = pysqlite_cursor_executescript_impl(self, sql_script); -+ return_value = pysqlite_cursor_executescript_impl((pysqlite_Cursor *)self, sql_script); - - exit: - return return_value; -@@ -163,9 +163,9 @@ - pysqlite_cursor_fetchone_impl(pysqlite_Cursor *self); - - static PyObject * --pysqlite_cursor_fetchone(pysqlite_Cursor *self, PyObject *Py_UNUSED(ignored)) -+pysqlite_cursor_fetchone(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return pysqlite_cursor_fetchone_impl(self); -+ return pysqlite_cursor_fetchone_impl((pysqlite_Cursor *)self); - } - - PyDoc_STRVAR(pysqlite_cursor_fetchmany__doc__, -@@ -184,7 +184,7 @@ - pysqlite_cursor_fetchmany_impl(pysqlite_Cursor *self, int maxrows); - - static PyObject * --pysqlite_cursor_fetchmany(pysqlite_Cursor *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+pysqlite_cursor_fetchmany(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -214,7 +214,7 @@ - #undef KWTUPLE - PyObject *argsbuf[1]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; -- int maxrows = self->arraysize; -+ int maxrows = ((pysqlite_Cursor *)self)->arraysize; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); -@@ -229,7 +229,7 @@ - goto exit; - } - skip_optional_pos: -- return_value = pysqlite_cursor_fetchmany_impl(self, maxrows); -+ return_value = pysqlite_cursor_fetchmany_impl((pysqlite_Cursor *)self, maxrows); - - exit: - return return_value; -@@ -248,9 +248,9 @@ - pysqlite_cursor_fetchall_impl(pysqlite_Cursor *self); - - static PyObject * --pysqlite_cursor_fetchall(pysqlite_Cursor *self, PyObject *Py_UNUSED(ignored)) -+pysqlite_cursor_fetchall(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return pysqlite_cursor_fetchall_impl(self); -+ return pysqlite_cursor_fetchall_impl((pysqlite_Cursor *)self); - } - - PyDoc_STRVAR(pysqlite_cursor_setinputsizes__doc__, -@@ -276,7 +276,7 @@ - PyObject *column); - - static PyObject * --pysqlite_cursor_setoutputsize(pysqlite_Cursor *self, PyObject *const *args, Py_ssize_t nargs) -+pysqlite_cursor_setoutputsize(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *size; -@@ -291,7 +291,7 @@ - } - column = args[1]; - skip_optional: -- return_value = pysqlite_cursor_setoutputsize_impl(self, size, column); -+ return_value = pysqlite_cursor_setoutputsize_impl((pysqlite_Cursor *)self, size, column); - - exit: - return return_value; -@@ -310,8 +310,8 @@ - pysqlite_cursor_close_impl(pysqlite_Cursor *self); - - static PyObject * --pysqlite_cursor_close(pysqlite_Cursor *self, PyObject *Py_UNUSED(ignored)) -+pysqlite_cursor_close(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return pysqlite_cursor_close_impl(self); -+ return pysqlite_cursor_close_impl((pysqlite_Cursor *)self); - } --/*[clinic end generated code: output=f0804afc5f8646c1 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=82620ca7622b547c input=a9049054013a1b77]*/ -diff --git a/Modules/_sqlite/clinic/row.c.h b/Modules/_sqlite/clinic/row.c.h -index e8d1dbf2ba8..068906744e4 100644 ---- a/Modules/_sqlite/clinic/row.c.h -+++ b/Modules/_sqlite/clinic/row.c.h -@@ -52,8 +52,8 @@ - pysqlite_row_keys_impl(pysqlite_Row *self); - - static PyObject * --pysqlite_row_keys(pysqlite_Row *self, PyObject *Py_UNUSED(ignored)) -+pysqlite_row_keys(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return pysqlite_row_keys_impl(self); -+ return pysqlite_row_keys_impl((pysqlite_Row *)self); - } --/*[clinic end generated code: output=788bf817acc02b8e input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=6c1acbb48f386468 input=a9049054013a1b77]*/ -diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c -index fc03e4a085c..7997e5f4d98 100644 ---- a/Modules/_sqlite/connection.c -+++ b/Modules/_sqlite/connection.c -@@ -34,7 +34,6 @@ - #include "prepare_protocol.h" - #include "util.h" - --#include "pycore_import.h" // _PyImport_GetModuleAttrString() - #include "pycore_modsupport.h" // _PyArg_NoKeywords() - #include "pycore_pyerrors.h" // _PyErr_ChainExceptions1() - #include "pycore_pylifecycle.h" // _Py_IsInterpreterFinalizing() -@@ -136,6 +135,8 @@ - #include "clinic/connection.c.h" - #undef clinic_state - -+#define _pysqlite_Connection_CAST(op) ((pysqlite_Connection *)(op)) -+ - /*[clinic input] - module _sqlite3 - class _sqlite3.Connection "pysqlite_Connection *" "clinic_state()->ConnectionType" -@@ -187,7 +188,7 @@ - Py_END_ALLOW_THREADS - - if (rc != SQLITE_OK) { -- (void)_pysqlite_seterror(self->state, self->db); -+ set_error_from_db(self->state, self->db); - return -1; - } - return 0; -@@ -273,7 +274,7 @@ - - pysqlite_state *state = pysqlite_get_state_by_type(Py_TYPE(self)); - if (rc != SQLITE_OK) { -- _pysqlite_seterror(state, db); -+ set_error_from_db(state, db); - goto error; - } - -@@ -385,8 +386,9 @@ - } while (0) - - static int --connection_traverse(pysqlite_Connection *self, visitproc visit, void *arg) -+connection_traverse(PyObject *op, visitproc visit, void *arg) - { -+ pysqlite_Connection *self = _pysqlite_Connection_CAST(op); - Py_VISIT(Py_TYPE(self)); - Py_VISIT(self->statement_cache); - Py_VISIT(self->cursors); -@@ -410,8 +412,9 @@ - } - - static int --connection_clear(pysqlite_Connection *self) -+connection_clear(PyObject *op) - { -+ pysqlite_Connection *self = _pysqlite_Connection_CAST(op); - Py_CLEAR(self->statement_cache); - Py_CLEAR(self->cursors); - Py_CLEAR(self->blobs); -@@ -494,7 +497,8 @@ - if (PyErr_ResourceWarning(self, 1, "unclosed database in %R", self)) { - /* Spurious errors can appear at shutdown */ - if (PyErr_ExceptionMatches(PyExc_Warning)) { -- PyErr_WriteUnraisable(self); -+ PyErr_FormatUnraisable("Exception ignored while finalizing " -+ "database connection %R", self); - } - } - } -@@ -503,7 +507,8 @@ - PyErr_Clear(); - } - else { -- PyErr_WriteUnraisable((PyObject *)self); -+ PyErr_FormatUnraisable("Exception ignored while closing database %R", -+ self); - } - } - -@@ -518,7 +523,7 @@ - } - PyTypeObject *tp = Py_TYPE(self); - PyObject_GC_UnTrack(self); -- tp->tp_clear(self); -+ (void)tp->tp_clear(self); - tp->tp_free(self); - Py_DECREF(tp); - } -@@ -602,11 +607,11 @@ - Py_END_ALLOW_THREADS - - if (rc == SQLITE_MISUSE) { -- PyErr_Format(self->state->InterfaceError, sqlite3_errstr(rc)); -+ set_error_from_code(self->state, rc); - return NULL; - } - else if (rc != SQLITE_OK) { -- _pysqlite_seterror(self->state, self->db); -+ set_error_from_db(self->state, self->db); - return NULL; - } - -@@ -890,7 +895,8 @@ - assert(ctx != NULL); - assert(ctx->state != NULL); - if (ctx->state->enable_callback_tracebacks) { -- PyErr_WriteUnraisable(ctx->callable); -+ PyErr_FormatUnraisable("Exception ignored on sqlite3 callback %R", -+ ctx->callable); - } - else { - PyErr_Clear(); -@@ -958,6 +964,11 @@ - assert(ctx != NULL); - - aggregate_instance = (PyObject**)sqlite3_aggregate_context(context, sizeof(PyObject*)); -+ if (aggregate_instance == NULL) { -+ (void)PyErr_NoMemory(); -+ set_sqlite_error(context, "unable to allocate SQLite aggregate context"); -+ goto error; -+ } - if (*aggregate_instance == NULL) { - *aggregate_instance = PyObject_CallNoArgs(ctx->callable); - if (!*aggregate_instance) { -@@ -1128,6 +1139,20 @@ - } - } - -+static int -+check_num_params(pysqlite_Connection *self, const int n, const char *name) -+{ -+ int limit = sqlite3_limit(self->db, SQLITE_LIMIT_FUNCTION_ARG, -1); -+ assert(limit >= 0); -+ if (n < -1 || n > limit) { -+ PyErr_Format(self->ProgrammingError, -+ "'%s' must be between -1 and %d, not %d", -+ name, limit, n); -+ return -1; -+ } -+ return 0; -+} -+ - /*[clinic input] - _sqlite3.Connection.create_function as pysqlite_connection_create_function - -@@ -1156,6 +1181,9 @@ - if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { - return NULL; - } -+ if (check_num_params(self, narg, "narg") < 0) { -+ return NULL; -+ } - - if (deterministic) { - flags |= SQLITE_DETERMINISTIC; -@@ -1296,10 +1324,12 @@ - "SQLite 3.25.0 or higher"); - return NULL; - } -- - if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { - return NULL; - } -+ if (check_num_params(self, num_params, "num_params") < 0) { -+ return NULL; -+ } - - int flags = SQLITE_UTF8; - int rc; -@@ -1322,9 +1352,9 @@ - } - - if (rc != SQLITE_OK) { -- // Errors are not set on the database connection, so we cannot -- // use _pysqlite_seterror(). -- PyErr_SetString(self->ProgrammingError, sqlite3_errstr(rc)); -+ /* Errors are not set on the database connection; use result code -+ * instead. */ -+ set_error_from_code(self->state, rc); - return NULL; - } - Py_RETURN_NONE; -@@ -1356,6 +1386,9 @@ - if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { - return NULL; - } -+ if (check_num_params(self, n_arg, "n_arg") < 0) { -+ return NULL; -+ } - - callback_context *ctx = create_callback_context(cls, aggregate_class); - if (ctx == NULL) { -@@ -1711,8 +1744,10 @@ - return 1; - } - --static PyObject* pysqlite_connection_get_isolation_level(pysqlite_Connection* self, void* unused) -+static PyObject * -+pysqlite_connection_get_isolation_level(PyObject *op, void *Py_UNUSED(closure)) - { -+ pysqlite_Connection *self = _pysqlite_Connection_CAST(op); - if (!pysqlite_check_connection(self)) { - return NULL; - } -@@ -1722,16 +1757,20 @@ - Py_RETURN_NONE; - } - --static PyObject* pysqlite_connection_get_total_changes(pysqlite_Connection* self, void* unused) -+static PyObject * -+pysqlite_connection_get_total_changes(PyObject *op, void *Py_UNUSED(closure)) - { -+ pysqlite_Connection *self = _pysqlite_Connection_CAST(op); - if (!pysqlite_check_connection(self)) { - return NULL; - } - return PyLong_FromLong(sqlite3_total_changes(self->db)); - } - --static PyObject* pysqlite_connection_get_in_transaction(pysqlite_Connection* self, void* unused) -+static PyObject * -+pysqlite_connection_get_in_transaction(PyObject *op, void *Py_UNUSED(closure)) - { -+ pysqlite_Connection *self = _pysqlite_Connection_CAST(op); - if (!pysqlite_check_connection(self)) { - return NULL; - } -@@ -1742,8 +1781,11 @@ - } - - static int --pysqlite_connection_set_isolation_level(pysqlite_Connection* self, PyObject* isolation_level, void *Py_UNUSED(ignored)) -+pysqlite_connection_set_isolation_level(PyObject *op, -+ PyObject *isolation_level, -+ void *Py_UNUSED(ignored)) - { -+ pysqlite_Connection *self = _pysqlite_Connection_CAST(op); - if (isolation_level == NULL) { - PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); - return -1; -@@ -1766,11 +1808,11 @@ - } - - static PyObject * --pysqlite_connection_call(pysqlite_Connection *self, PyObject *args, -- PyObject *kwargs) -+pysqlite_connection_call(PyObject *op, PyObject *args, PyObject *kwargs) - { - PyObject* sql; - pysqlite_Statement* statement; -+ pysqlite_Connection *self = _pysqlite_Connection_CAST(op); - - if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { - return NULL; -@@ -1995,7 +2037,7 @@ - return NULL; - } - -- PyObject *iterdump = _PyImport_GetModuleAttrString(MODULE_NAME ".dump", "_iterdump"); -+ PyObject *iterdump = PyImport_ImportModuleAttrString(MODULE_NAME ".dump", "_iterdump"); - if (!iterdump) { - if (!PyErr_Occurred()) { - PyErr_SetString(self->OperationalError, -@@ -2070,7 +2112,7 @@ - Py_END_ALLOW_THREADS - - if (bck_handle == NULL) { -- _pysqlite_seterror(self->state, bck_conn); -+ set_error_from_db(self->state, bck_conn); - return NULL; - } - -@@ -2108,7 +2150,7 @@ - Py_END_ALLOW_THREADS - - if (rc != SQLITE_OK) { -- _pysqlite_seterror(self->state, bck_conn); -+ set_error_from_db(self->state, bck_conn); - return NULL; - } - -@@ -2166,7 +2208,7 @@ - if (callable != Py_None) { - free_callback_context(ctx); - } -- _pysqlite_seterror(self->state, self->db); -+ set_error_from_db(self->state, self->db); - return NULL; - } - -@@ -2284,7 +2326,7 @@ - Py_END_ALLOW_THREADS - - if (rc != SQLITE_OK) { -- (void)_pysqlite_seterror(self->state, self->db); -+ set_error_from_db(self->state, self->db); - return NULL; - } - Py_RETURN_NONE; -@@ -2479,7 +2521,7 @@ - int actual; - int rc = sqlite3_db_config(self->db, op, enable, &actual); - if (rc != SQLITE_OK) { -- (void)_pysqlite_seterror(self->state, self->db); -+ set_error_from_db(self->state, self->db); - return NULL; - } - if (enable != actual) { -@@ -2514,15 +2556,16 @@ - int current; - int rc = sqlite3_db_config(self->db, op, -1, ¤t); - if (rc != SQLITE_OK) { -- (void)_pysqlite_seterror(self->state, self->db); -+ set_error_from_db(self->state, self->db); - return -1; - } - return current; - } - - static PyObject * --get_autocommit(pysqlite_Connection *self, void *Py_UNUSED(ctx)) -+get_autocommit(PyObject *op, void *Py_UNUSED(closure)) - { -+ pysqlite_Connection *self = _pysqlite_Connection_CAST(op); - if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { - return NULL; - } -@@ -2536,8 +2579,9 @@ - } - - static int --set_autocommit(pysqlite_Connection *self, PyObject *val, void *Py_UNUSED(ctx)) -+set_autocommit(PyObject *op, PyObject *val, void *Py_UNUSED(closure)) - { -+ pysqlite_Connection *self = _pysqlite_Connection_CAST(op); - if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { - return -1; - } -@@ -2562,7 +2606,7 @@ - } - - static PyObject * --get_sig(PyObject *self, void *Py_UNUSED(ctx)) -+get_sig(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) - { - return PyUnicode_FromString("(sql, /)"); - } -@@ -2572,11 +2616,12 @@ - PyDoc_STR("SQLite database connection object."); - - static PyGetSetDef connection_getset[] = { -- {"isolation_level", (getter)pysqlite_connection_get_isolation_level, (setter)pysqlite_connection_set_isolation_level}, -- {"total_changes", (getter)pysqlite_connection_get_total_changes, (setter)0}, -- {"in_transaction", (getter)pysqlite_connection_get_in_transaction, (setter)0}, -- {"autocommit", (getter)get_autocommit, (setter)set_autocommit}, -- {"__text_signature__", get_sig, (setter)0}, -+ {"isolation_level", pysqlite_connection_get_isolation_level, -+ pysqlite_connection_set_isolation_level}, -+ {"total_changes", pysqlite_connection_get_total_changes, NULL}, -+ {"in_transaction", pysqlite_connection_get_in_transaction, NULL}, -+ {"autocommit", get_autocommit, set_autocommit}, -+ {"__text_signature__", get_sig, NULL}, - {NULL} - }; - -diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c -index 0fbd408f18c..ad3587d88dd 100644 ---- a/Modules/_sqlite/cursor.c -+++ b/Modules/_sqlite/cursor.c -@@ -44,6 +44,8 @@ - #include "clinic/cursor.c.h" - #undef clinic_state - -+#define _pysqlite_Cursor_CAST(op) ((pysqlite_Cursor *)(op)) -+ - static inline int - check_cursor_locked(pysqlite_Cursor *cur) - { -@@ -146,8 +148,9 @@ - } - - static int --cursor_traverse(pysqlite_Cursor *self, visitproc visit, void *arg) -+cursor_traverse(PyObject *op, visitproc visit, void *arg) - { -+ pysqlite_Cursor *self = _pysqlite_Cursor_CAST(op); - Py_VISIT(Py_TYPE(self)); - Py_VISIT(self->connection); - Py_VISIT(self->description); -@@ -159,8 +162,9 @@ - } - - static int --cursor_clear(pysqlite_Cursor *self) -+cursor_clear(PyObject *op) - { -+ pysqlite_Cursor *self = _pysqlite_Cursor_CAST(op); - Py_CLEAR(self->connection); - Py_CLEAR(self->description); - Py_CLEAR(self->row_cast_map); -@@ -176,14 +180,15 @@ - } - - static void --cursor_dealloc(pysqlite_Cursor *self) -+cursor_dealloc(PyObject *op) - { -+ pysqlite_Cursor *self = _pysqlite_Cursor_CAST(op); - PyTypeObject *tp = Py_TYPE(self); - PyObject_GC_UnTrack(self); - if (self->in_weakreflist != NULL) { -- PyObject_ClearWeakRefs((PyObject*)self); -+ PyObject_ClearWeakRefs(op); - } -- tp->tp_clear((PyObject *)self); -+ (void)tp->tp_clear(op); - tp->tp_free(self); - Py_DECREF(tp); - } -@@ -500,7 +505,7 @@ - Py_END_ALLOW_THREADS - - if (rc != SQLITE_OK) { -- (void)_pysqlite_seterror(self->state, self->db); -+ set_error_from_db(self->state, self->db); - return -1; - } - -@@ -710,7 +715,7 @@ - if (rc != SQLITE_OK) { - PyObject *exc = PyErr_GetRaisedException(); - sqlite3 *db = sqlite3_db_handle(self->st); -- _pysqlite_seterror(state, db); -+ set_error_from_db(state, db); - _PyErr_ChainExceptions1(exc); - return; - } -@@ -759,7 +764,7 @@ - if (rc != SQLITE_OK) { - PyObject *exc = PyErr_GetRaisedException(); - sqlite3 *db = sqlite3_db_handle(self->st); -- _pysqlite_seterror(state, db); -+ set_error_from_db(state, db); - _PyErr_ChainExceptions1(exc); - return; - } -@@ -891,7 +896,7 @@ - PyErr_Clear(); - } - } -- _pysqlite_seterror(state, self->connection->db); -+ set_error_from_db(state, self->connection->db); - goto error; - } - -@@ -1082,13 +1087,14 @@ - return Py_NewRef((PyObject *)self); - - error: -- _pysqlite_seterror(self->connection->state, db); -+ set_error_from_db(self->connection->state, db); - return NULL; - } - - static PyObject * --pysqlite_cursor_iternext(pysqlite_Cursor *self) -+pysqlite_cursor_iternext(PyObject *op) - { -+ pysqlite_Cursor *self = _pysqlite_Cursor_CAST(op); - if (!check_cursor(self)) { - return NULL; - } -@@ -1116,8 +1122,7 @@ - Py_CLEAR(self->statement); - } - else if (rc != SQLITE_ROW) { -- (void)_pysqlite_seterror(self->connection->state, -- self->connection->db); -+ set_error_from_db(self->connection->state, self->connection->db); - (void)stmt_reset(self->statement); - Py_CLEAR(self->statement); - Py_DECREF(row); -@@ -1125,7 +1130,7 @@ - } - if (!Py_IsNone(self->row_factory)) { - PyObject *factory = self->row_factory; -- PyObject *args[] = { (PyObject *)self, row, }; -+ PyObject *args[] = { op, row, }; - PyObject *new_row = PyObject_Vectorcall(factory, args, 2, NULL); - Py_SETREF(row, new_row); - } -@@ -1144,7 +1149,7 @@ - { - PyObject* row; - -- row = pysqlite_cursor_iternext(self); -+ row = pysqlite_cursor_iternext((PyObject *)self); - if (!row && !PyErr_Occurred()) { - Py_RETURN_NONE; - } -@@ -1155,7 +1160,7 @@ - /*[clinic input] - _sqlite3.Cursor.fetchmany as pysqlite_cursor_fetchmany - -- size as maxrows: int(c_default='self->arraysize') = 1 -+ size as maxrows: int(c_default='((pysqlite_Cursor *)self)->arraysize') = 1 - The default value is set by the Cursor.arraysize attribute. - - Fetches several rows from the resultset. -@@ -1163,7 +1168,7 @@ - - static PyObject * - pysqlite_cursor_fetchmany_impl(pysqlite_Cursor *self, int maxrows) --/*[clinic end generated code: output=a8ef31fea64d0906 input=c26e6ca3f34debd0]*/ -+/*[clinic end generated code: output=a8ef31fea64d0906 input=035dbe44a1005bf2]*/ - { - PyObject* row; - PyObject* list; -@@ -1174,7 +1179,7 @@ - return NULL; - } - -- while ((row = pysqlite_cursor_iternext(self))) { -+ while ((row = pysqlite_cursor_iternext((PyObject *)self))) { - if (PyList_Append(list, row) < 0) { - Py_DECREF(row); - break; -@@ -1212,7 +1217,7 @@ - return NULL; - } - -- while ((row = pysqlite_cursor_iternext(self))) { -+ while ((row = pysqlite_cursor_iternext((PyObject *)self))) { - if (PyList_Append(list, row) < 0) { - Py_DECREF(row); - break; -diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c -index 698e81d9b89..27e8dab92e0 100644 ---- a/Modules/_sqlite/module.c -+++ b/Modules/_sqlite/module.c -@@ -33,8 +33,6 @@ - #include "row.h" - #include "blob.h" - --#include "pycore_import.h" // _PyImport_GetModuleAttrString() -- - #if SQLITE_VERSION_NUMBER < 3015002 - #error "SQLite 3.15.2 or higher required" - #endif -@@ -234,7 +232,7 @@ - load_functools_lru_cache(PyObject *module) - { - pysqlite_state *state = pysqlite_get_state(module); -- state->lru_cache = _PyImport_GetModuleAttrString("functools", "lru_cache"); -+ state->lru_cache = PyImport_ImportModuleAttrString("functools", "lru_cache"); - if (state->lru_cache == NULL) { - return -1; - } -@@ -619,7 +617,7 @@ - static void - module_free(void *module) - { -- module_clear((PyObject *)module); -+ (void)module_clear((PyObject *)module); - } - - #define ADD_TYPE(module, type) \ -diff --git a/Modules/_sqlite/prepare_protocol.c b/Modules/_sqlite/prepare_protocol.c -index 44533225665..31092417cb4 100644 ---- a/Modules/_sqlite/prepare_protocol.c -+++ b/Modules/_sqlite/prepare_protocol.c -@@ -24,8 +24,7 @@ - #include "prepare_protocol.h" - - static int --pysqlite_prepare_protocol_init(pysqlite_PrepareProtocol *self, PyObject *args, -- PyObject *kwargs) -+pysqlite_prepare_protocol_init(PyObject *self, PyObject *args, PyObject *kwargs) - { - return 0; - } -@@ -38,7 +37,7 @@ - } - - static void --pysqlite_prepare_protocol_dealloc(pysqlite_PrepareProtocol *self) -+pysqlite_prepare_protocol_dealloc(PyObject *self) - { - PyTypeObject *tp = Py_TYPE(self); - PyObject_GC_UnTrack(self); -diff --git a/Modules/_sqlite/row.c b/Modules/_sqlite/row.c -index 14555076a7e..94565a01d18 100644 ---- a/Modules/_sqlite/row.c -+++ b/Modules/_sqlite/row.c -@@ -32,6 +32,8 @@ - #include "clinic/row.c.h" - #undef clinic_state - -+#define _pysqlite_Row_CAST(op) ((pysqlite_Row *)(op)) -+ - /*[clinic input] - module _sqlite3 - class _sqlite3.Row "pysqlite_Row *" "clinic_state()->RowType" -@@ -39,16 +41,18 @@ - /*[clinic end generated code: output=da39a3ee5e6b4b0d input=966c53403d7f3a40]*/ - - static int --row_clear(pysqlite_Row *self) -+row_clear(PyObject *op) - { -+ pysqlite_Row *self = _pysqlite_Row_CAST(op); - Py_CLEAR(self->data); - Py_CLEAR(self->description); - return 0; - } - - static int --row_traverse(pysqlite_Row *self, visitproc visit, void *arg) -+row_traverse(PyObject *op, visitproc visit, void *arg) - { -+ pysqlite_Row *self = _pysqlite_Row_CAST(op); - Py_VISIT(Py_TYPE(self)); - Py_VISIT(self->data); - Py_VISIT(self->description); -@@ -60,7 +64,7 @@ - { - PyTypeObject *tp = Py_TYPE(self); - PyObject_GC_UnTrack(self); -- tp->tp_clear(self); -+ (void)tp->tp_clear(self); - tp->tp_free(self); - Py_DECREF(tp); - } -@@ -94,10 +98,12 @@ - return (PyObject *) self; - } - --PyObject* pysqlite_row_item(pysqlite_Row* self, Py_ssize_t idx) -+static PyObject * -+pysqlite_row_item(PyObject *op, Py_ssize_t idx) - { -- PyObject *item = PyTuple_GetItem(self->data, idx); -- return Py_XNewRef(item); -+ pysqlite_Row *self = _pysqlite_Row_CAST(op); -+ PyObject *item = PyTuple_GetItem(self->data, idx); -+ return Py_XNewRef(item); - } - - static int -@@ -129,10 +135,10 @@ - } - - static PyObject * --pysqlite_row_subscript(pysqlite_Row *self, PyObject *idx) -+pysqlite_row_subscript(PyObject *op, PyObject *idx) - { - Py_ssize_t _idx; -- Py_ssize_t nitems, i; -+ pysqlite_Row *self = _pysqlite_Row_CAST(op); - - if (PyLong_Check(idx)) { - _idx = PyNumber_AsSsize_t(idx, PyExc_IndexError); -@@ -144,9 +150,13 @@ - PyObject *item = PyTuple_GetItem(self->data, _idx); - return Py_XNewRef(item); - } else if (PyUnicode_Check(idx)) { -- nitems = PyTuple_Size(self->description); -+ if (Py_IsNone(self->description)) { -+ PyErr_Format(PyExc_IndexError, "No item with key %R", idx); -+ return NULL; -+ } -+ Py_ssize_t nitems = PyTuple_GET_SIZE(self->description); - -- for (i = 0; i < nitems; i++) { -+ for (Py_ssize_t i = 0; i < nitems; i++) { - PyObject *obj; - obj = PyTuple_GET_ITEM(self->description, i); - obj = PyTuple_GET_ITEM(obj, 0); -@@ -174,8 +184,9 @@ - } - - static Py_ssize_t --pysqlite_row_length(pysqlite_Row* self) -+pysqlite_row_length(PyObject *op) - { -+ pysqlite_Row *self = _pysqlite_Row_CAST(op); - return PyTuple_GET_SIZE(self->data); - } - -@@ -189,17 +200,19 @@ - pysqlite_row_keys_impl(pysqlite_Row *self) - /*[clinic end generated code: output=efe3dfb3af6edc07 input=7549a122827c5563]*/ - { -- PyObject* list; -- Py_ssize_t nitems, i; -- -- list = PyList_New(0); -+ PyObject *list = PyList_New(0); - if (!list) { - return NULL; - } -- nitems = PyTuple_Size(self->description); -+ if (Py_IsNone(self->description)) { -+ return list; -+ } - -- for (i = 0; i < nitems; i++) { -- if (PyList_Append(list, PyTuple_GET_ITEM(PyTuple_GET_ITEM(self->description, i), 0)) != 0) { -+ Py_ssize_t nitems = PyTuple_GET_SIZE(self->description); -+ for (Py_ssize_t i = 0; i < nitems; i++) { -+ PyObject *descr = PyTuple_GET_ITEM(self->description, i); -+ PyObject *name = PyTuple_GET_ITEM(descr, 0); -+ if (PyList_Append(list, name) < 0) { - Py_DECREF(list); - return NULL; - } -@@ -208,24 +221,30 @@ - return list; - } - --static PyObject* pysqlite_iter(pysqlite_Row* self) -+static PyObject * -+pysqlite_iter(PyObject *op) - { -+ pysqlite_Row *self = _pysqlite_Row_CAST(op); - return PyObject_GetIter(self->data); - } - --static Py_hash_t pysqlite_row_hash(pysqlite_Row *self) -+static Py_hash_t -+pysqlite_row_hash(PyObject *op) - { -+ pysqlite_Row *self = _pysqlite_Row_CAST(op); - return PyObject_Hash(self->description) ^ PyObject_Hash(self->data); - } - --static PyObject* pysqlite_row_richcompare(pysqlite_Row *self, PyObject *_other, int opid) -+static PyObject * -+pysqlite_row_richcompare(PyObject *op, PyObject *opother, int opid) - { - if (opid != Py_EQ && opid != Py_NE) - Py_RETURN_NOTIMPLEMENTED; - -+ pysqlite_Row *self = _pysqlite_Row_CAST(op); - pysqlite_state *state = pysqlite_get_state_by_type(Py_TYPE(self)); -- if (PyObject_TypeCheck(_other, state->RowType)) { -- pysqlite_Row *other = (pysqlite_Row *)_other; -+ if (PyObject_TypeCheck(opother, state->RowType)) { -+ pysqlite_Row *other = (pysqlite_Row *)opother; - int eq = PyObject_RichCompareBool(self->description, other->description, Py_EQ); - if (eq < 0) { - return NULL; -diff --git a/Modules/_sqlite/statement.c b/Modules/_sqlite/statement.c -index 229bfc3b504..736e60fd778 100644 ---- a/Modules/_sqlite/statement.c -+++ b/Modules/_sqlite/statement.c -@@ -25,6 +25,8 @@ - #include "statement.h" - #include "util.h" - -+#define _pysqlite_Statement_CAST(op) ((pysqlite_Statement *)(op)) -+ - /* prototypes */ - static const char *lstrip_sql(const char *sql); - -@@ -60,7 +62,7 @@ - Py_END_ALLOW_THREADS - - if (rc != SQLITE_OK) { -- _pysqlite_seterror(state, db); -+ set_error_from_db(state, db); - return NULL; - } - -@@ -99,10 +101,11 @@ - } - - static void --stmt_dealloc(pysqlite_Statement *self) -+stmt_dealloc(PyObject *op) - { -+ pysqlite_Statement *self = _pysqlite_Statement_CAST(op); - PyTypeObject *tp = Py_TYPE(self); -- PyObject_GC_UnTrack(self); -+ PyObject_GC_UnTrack(op); - if (self->st) { - Py_BEGIN_ALLOW_THREADS - sqlite3_finalize(self->st); -@@ -114,7 +117,7 @@ - } - - static int --stmt_traverse(pysqlite_Statement *self, visitproc visit, void *arg) -+stmt_traverse(PyObject *self, visitproc visit, void *arg) - { - Py_VISIT(Py_TYPE(self)); - return 0; -diff --git a/Modules/_sqlite/util.c b/Modules/_sqlite/util.c -index 9e8613ef679..103248ff55a 100644 ---- a/Modules/_sqlite/util.c -+++ b/Modules/_sqlite/util.c -@@ -118,25 +118,38 @@ - Py_XDECREF(exc); - } - -+void -+set_error_from_code(pysqlite_state *state, int code) -+{ -+ PyObject *exc_class = get_exception_class(state, code); -+ if (exc_class == NULL) { -+ // No new exception need be raised. -+ return; -+ } -+ -+ const char *errmsg = sqlite3_errstr(code); -+ assert(errmsg != NULL); -+ raise_exception(exc_class, code, errmsg); -+} -+ - /** - * Checks the SQLite error code and sets the appropriate DB-API exception. -- * Returns the error code (0 means no error occurred). - */ --int --_pysqlite_seterror(pysqlite_state *state, sqlite3 *db) -+void -+set_error_from_db(pysqlite_state *state, sqlite3 *db) - { - int errorcode = sqlite3_errcode(db); - PyObject *exc_class = get_exception_class(state, errorcode); - if (exc_class == NULL) { -- // No new exception need be raised; just pass the error code -- return errorcode; -+ // No new exception need be raised. -+ return; - } - - /* Create and set the exception. */ - int extended_errcode = sqlite3_extended_errcode(db); -+ // sqlite3_errmsg() always returns an UTF-8 encoded message - const char *errmsg = sqlite3_errmsg(db); - raise_exception(exc_class, extended_errcode, errmsg); -- return extended_errcode; - } - - #ifdef WORDS_BIGENDIAN -diff --git a/Modules/_sqlite/util.h b/Modules/_sqlite/util.h -index 68b1a8cb67a..f8e45baffae 100644 ---- a/Modules/_sqlite/util.h -+++ b/Modules/_sqlite/util.h -@@ -30,9 +30,9 @@ - - /** - * Checks the SQLite error code and sets the appropriate DB-API exception. -- * Returns the error code (0 means no error occurred). - */ --int _pysqlite_seterror(pysqlite_state *state, sqlite3 *db); -+void set_error_from_db(pysqlite_state *state, sqlite3 *db); -+void set_error_from_code(pysqlite_state *state, int code); - - sqlite_int64 _pysqlite_long_as_int64(PyObject * value); - -diff --git a/Modules/_sre/clinic/sre.c.h b/Modules/_sre/clinic/sre.c.h -index 87e4785a428..cfc6813f37f 100644 ---- a/Modules/_sre/clinic/sre.c.h -+++ b/Modules/_sre/clinic/sre.c.h -@@ -179,7 +179,7 @@ - Py_ssize_t endpos); - - static PyObject * --_sre_SRE_Pattern_match(PatternObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_sre_SRE_Pattern_match(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -252,7 +252,7 @@ - endpos = ival; - } - skip_optional_pos: -- return_value = _sre_SRE_Pattern_match_impl(self, cls, string, pos, endpos); -+ return_value = _sre_SRE_Pattern_match_impl((PatternObject *)self, cls, string, pos, endpos); - - exit: - return return_value; -@@ -273,7 +273,7 @@ - Py_ssize_t endpos); - - static PyObject * --_sre_SRE_Pattern_fullmatch(PatternObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_sre_SRE_Pattern_fullmatch(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -346,7 +346,7 @@ - endpos = ival; - } - skip_optional_pos: -- return_value = _sre_SRE_Pattern_fullmatch_impl(self, cls, string, pos, endpos); -+ return_value = _sre_SRE_Pattern_fullmatch_impl((PatternObject *)self, cls, string, pos, endpos); - - exit: - return return_value; -@@ -369,7 +369,7 @@ - Py_ssize_t endpos); - - static PyObject * --_sre_SRE_Pattern_search(PatternObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_sre_SRE_Pattern_search(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -442,7 +442,7 @@ - endpos = ival; - } - skip_optional_pos: -- return_value = _sre_SRE_Pattern_search_impl(self, cls, string, pos, endpos); -+ return_value = _sre_SRE_Pattern_search_impl((PatternObject *)self, cls, string, pos, endpos); - - exit: - return return_value; -@@ -462,7 +462,7 @@ - Py_ssize_t pos, Py_ssize_t endpos); - - static PyObject * --_sre_SRE_Pattern_findall(PatternObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_sre_SRE_Pattern_findall(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -535,7 +535,7 @@ - endpos = ival; - } - skip_optional_pos: -- return_value = _sre_SRE_Pattern_findall_impl(self, string, pos, endpos); -+ return_value = _sre_SRE_Pattern_findall_impl((PatternObject *)self, string, pos, endpos); - - exit: - return return_value; -@@ -558,7 +558,7 @@ - Py_ssize_t endpos); - - static PyObject * --_sre_SRE_Pattern_finditer(PatternObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_sre_SRE_Pattern_finditer(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -631,7 +631,7 @@ - endpos = ival; - } - skip_optional_pos: -- return_value = _sre_SRE_Pattern_finditer_impl(self, cls, string, pos, endpos); -+ return_value = _sre_SRE_Pattern_finditer_impl((PatternObject *)self, cls, string, pos, endpos); - - exit: - return return_value; -@@ -651,7 +651,7 @@ - Py_ssize_t endpos); - - static PyObject * --_sre_SRE_Pattern_scanner(PatternObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_sre_SRE_Pattern_scanner(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -724,7 +724,7 @@ - endpos = ival; - } - skip_optional_pos: -- return_value = _sre_SRE_Pattern_scanner_impl(self, cls, string, pos, endpos); -+ return_value = _sre_SRE_Pattern_scanner_impl((PatternObject *)self, cls, string, pos, endpos); - - exit: - return return_value; -@@ -744,7 +744,7 @@ - Py_ssize_t maxsplit); - - static PyObject * --_sre_SRE_Pattern_split(PatternObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_sre_SRE_Pattern_split(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -799,7 +799,7 @@ - maxsplit = ival; - } - skip_optional_pos: -- return_value = _sre_SRE_Pattern_split_impl(self, string, maxsplit); -+ return_value = _sre_SRE_Pattern_split_impl((PatternObject *)self, string, maxsplit); - - exit: - return return_value; -@@ -819,7 +819,7 @@ - PyObject *repl, PyObject *string, Py_ssize_t count); - - static PyObject * --_sre_SRE_Pattern_sub(PatternObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_sre_SRE_Pattern_sub(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -876,7 +876,7 @@ - count = ival; - } - skip_optional_pos: -- return_value = _sre_SRE_Pattern_sub_impl(self, cls, repl, string, count); -+ return_value = _sre_SRE_Pattern_sub_impl((PatternObject *)self, cls, repl, string, count); - - exit: - return return_value; -@@ -897,7 +897,7 @@ - Py_ssize_t count); - - static PyObject * --_sre_SRE_Pattern_subn(PatternObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_sre_SRE_Pattern_subn(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -954,7 +954,7 @@ - count = ival; - } - skip_optional_pos: -- return_value = _sre_SRE_Pattern_subn_impl(self, cls, repl, string, count); -+ return_value = _sre_SRE_Pattern_subn_impl((PatternObject *)self, cls, repl, string, count); - - exit: - return return_value; -@@ -972,9 +972,9 @@ - _sre_SRE_Pattern___copy___impl(PatternObject *self); - - static PyObject * --_sre_SRE_Pattern___copy__(PatternObject *self, PyObject *Py_UNUSED(ignored)) -+_sre_SRE_Pattern___copy__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _sre_SRE_Pattern___copy___impl(self); -+ return _sre_SRE_Pattern___copy___impl((PatternObject *)self); - } - - PyDoc_STRVAR(_sre_SRE_Pattern___deepcopy____doc__, -@@ -1001,7 +1001,7 @@ - PyObject *exception); - - static PyObject * --_sre_SRE_Pattern__fail_after(PatternObject *self, PyObject *const *args, Py_ssize_t nargs) -+_sre_SRE_Pattern__fail_after(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - int count; -@@ -1015,7 +1015,7 @@ - goto exit; - } - exception = args[1]; -- return_value = _sre_SRE_Pattern__fail_after_impl(self, count, exception); -+ return_value = _sre_SRE_Pattern__fail_after_impl((PatternObject *)self, count, exception); - - exit: - return return_value; -@@ -1169,7 +1169,7 @@ - _sre_SRE_Match_expand_impl(MatchObject *self, PyObject *template); - - static PyObject * --_sre_SRE_Match_expand(MatchObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_sre_SRE_Match_expand(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -1206,7 +1206,7 @@ - goto exit; - } - template = args[0]; -- return_value = _sre_SRE_Match_expand_impl(self, template); -+ return_value = _sre_SRE_Match_expand_impl((MatchObject *)self, template); - - exit: - return return_value; -@@ -1228,7 +1228,7 @@ - _sre_SRE_Match_groups_impl(MatchObject *self, PyObject *default_value); - - static PyObject * --_sre_SRE_Match_groups(MatchObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_sre_SRE_Match_groups(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -1270,7 +1270,7 @@ - } - default_value = args[0]; - skip_optional_pos: -- return_value = _sre_SRE_Match_groups_impl(self, default_value); -+ return_value = _sre_SRE_Match_groups_impl((MatchObject *)self, default_value); - - exit: - return return_value; -@@ -1292,7 +1292,7 @@ - _sre_SRE_Match_groupdict_impl(MatchObject *self, PyObject *default_value); - - static PyObject * --_sre_SRE_Match_groupdict(MatchObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_sre_SRE_Match_groupdict(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -1334,7 +1334,7 @@ - } - default_value = args[0]; - skip_optional_pos: -- return_value = _sre_SRE_Match_groupdict_impl(self, default_value); -+ return_value = _sre_SRE_Match_groupdict_impl((MatchObject *)self, default_value); - - exit: - return return_value; -@@ -1353,7 +1353,7 @@ - _sre_SRE_Match_start_impl(MatchObject *self, PyObject *group); - - static PyObject * --_sre_SRE_Match_start(MatchObject *self, PyObject *const *args, Py_ssize_t nargs) -+_sre_SRE_Match_start(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *group = NULL; -@@ -1367,7 +1367,7 @@ - } - group = args[0]; - skip_optional: -- _return_value = _sre_SRE_Match_start_impl(self, group); -+ _return_value = _sre_SRE_Match_start_impl((MatchObject *)self, group); - if ((_return_value == -1) && PyErr_Occurred()) { - goto exit; - } -@@ -1390,7 +1390,7 @@ - _sre_SRE_Match_end_impl(MatchObject *self, PyObject *group); - - static PyObject * --_sre_SRE_Match_end(MatchObject *self, PyObject *const *args, Py_ssize_t nargs) -+_sre_SRE_Match_end(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *group = NULL; -@@ -1404,7 +1404,7 @@ - } - group = args[0]; - skip_optional: -- _return_value = _sre_SRE_Match_end_impl(self, group); -+ _return_value = _sre_SRE_Match_end_impl((MatchObject *)self, group); - if ((_return_value == -1) && PyErr_Occurred()) { - goto exit; - } -@@ -1427,7 +1427,7 @@ - _sre_SRE_Match_span_impl(MatchObject *self, PyObject *group); - - static PyObject * --_sre_SRE_Match_span(MatchObject *self, PyObject *const *args, Py_ssize_t nargs) -+_sre_SRE_Match_span(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *group = NULL; -@@ -1440,7 +1440,7 @@ - } - group = args[0]; - skip_optional: -- return_value = _sre_SRE_Match_span_impl(self, group); -+ return_value = _sre_SRE_Match_span_impl((MatchObject *)self, group); - - exit: - return return_value; -@@ -1458,9 +1458,9 @@ - _sre_SRE_Match___copy___impl(MatchObject *self); - - static PyObject * --_sre_SRE_Match___copy__(MatchObject *self, PyObject *Py_UNUSED(ignored)) -+_sre_SRE_Match___copy__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _sre_SRE_Match___copy___impl(self); -+ return _sre_SRE_Match___copy___impl((MatchObject *)self); - } - - PyDoc_STRVAR(_sre_SRE_Match___deepcopy____doc__, -@@ -1483,13 +1483,13 @@ - _sre_SRE_Scanner_match_impl(ScannerObject *self, PyTypeObject *cls); - - static PyObject * --_sre_SRE_Scanner_match(ScannerObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_sre_SRE_Scanner_match(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "match() takes no arguments"); - return NULL; - } -- return _sre_SRE_Scanner_match_impl(self, cls); -+ return _sre_SRE_Scanner_match_impl((ScannerObject *)self, cls); - } - - PyDoc_STRVAR(_sre_SRE_Scanner_search__doc__, -@@ -1504,16 +1504,16 @@ - _sre_SRE_Scanner_search_impl(ScannerObject *self, PyTypeObject *cls); - - static PyObject * --_sre_SRE_Scanner_search(ScannerObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_sre_SRE_Scanner_search(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "search() takes no arguments"); - return NULL; - } -- return _sre_SRE_Scanner_search_impl(self, cls); -+ return _sre_SRE_Scanner_search_impl((ScannerObject *)self, cls); - } - - #ifndef _SRE_SRE_PATTERN__FAIL_AFTER_METHODDEF - #define _SRE_SRE_PATTERN__FAIL_AFTER_METHODDEF - #endif /* !defined(_SRE_SRE_PATTERN__FAIL_AFTER_METHODDEF) */ --/*[clinic end generated code: output=f8cb77f2261f0b2e input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=3654103c87eb4830 input=a9049054013a1b77]*/ -diff --git a/Modules/_sre/sre.c b/Modules/_sre/sre.c -index 36f542ddb4d..0d8d4843d33 100644 ---- a/Modules/_sre/sre.c -+++ b/Modules/_sre/sre.c -@@ -395,6 +395,11 @@ - static PyObject*pattern_new_match(_sremodulestate *, PatternObject*, SRE_STATE*, Py_ssize_t); - static PyObject *pattern_scanner(_sremodulestate *, PatternObject *, PyObject *, Py_ssize_t, Py_ssize_t); - -+#define _PatternObject_CAST(op) ((PatternObject *)(op)) -+#define _MatchObject_CAST(op) ((MatchObject *)(op)) -+#define _TemplateObject_CAST(op) ((TemplateObject *)(op)) -+#define _ScannerObject_CAST(op) ((ScannerObject *)(op)) -+ - /*[clinic input] - module _sre - class _sre.SRE_Pattern "PatternObject *" "get_sre_module_state_by_class(tp)->Pattern_Type" -@@ -699,8 +704,9 @@ - } - - static int --pattern_traverse(PatternObject *self, visitproc visit, void *arg) -+pattern_traverse(PyObject *op, visitproc visit, void *arg) - { -+ PatternObject *self = _PatternObject_CAST(op); - Py_VISIT(Py_TYPE(self)); - Py_VISIT(self->groupindex); - Py_VISIT(self->indexgroup); -@@ -712,8 +718,9 @@ - } - - static int --pattern_clear(PatternObject *self) -+pattern_clear(PyObject *op) - { -+ PatternObject *self = _PatternObject_CAST(op); - Py_CLEAR(self->groupindex); - Py_CLEAR(self->indexgroup); - Py_CLEAR(self->pattern); -@@ -724,13 +731,13 @@ - } - - static void --pattern_dealloc(PatternObject* self) -+pattern_dealloc(PyObject *self) - { - PyTypeObject *tp = Py_TYPE(self); -- - PyObject_GC_UnTrack(self); -- if (self->weakreflist != NULL) { -- PyObject_ClearWeakRefs((PyObject *) self); -+ PatternObject *obj = _PatternObject_CAST(self); -+ if (obj->weakreflist != NULL) { -+ PyObject_ClearWeakRefs(self); - } - (void)pattern_clear(self); - tp->tp_free(self); -@@ -1162,7 +1169,7 @@ - /* delegate to Python code */ - PyObject *func = module_state->compile_template; - if (func == NULL) { -- func = _PyImport_GetModuleAttrString("re", "_compile_template"); -+ func = PyImport_ImportModuleAttrString("re", "_compile_template"); - if (func == NULL) { - return NULL; - } -@@ -1497,7 +1504,7 @@ - #endif /* Py_DEBUG */ - - static PyObject * --pattern_repr(PatternObject *obj) -+pattern_repr(PyObject *self) - { - static const struct { - const char *name; -@@ -1512,6 +1519,8 @@ - {"re.DEBUG", SRE_FLAG_DEBUG}, - {"re.ASCII", SRE_FLAG_ASCII}, - }; -+ -+ PatternObject *obj = _PatternObject_CAST(self); - PyObject *result = NULL; - PyObject *flag_items; - size_t i; -@@ -1579,8 +1588,9 @@ - - /* PatternObject's 'groupindex' method. */ - static PyObject * --pattern_groupindex(PatternObject *self, void *Py_UNUSED(ignored)) -+pattern_groupindex(PyObject *op, void *Py_UNUSED(ignored)) - { -+ PatternObject *self = _PatternObject_CAST(op); - if (self->groupindex == NULL) - return PyDict_New(); - return PyDictProxy_New(self->groupindex); -@@ -2245,8 +2255,9 @@ - /* match methods */ - - static int --match_traverse(MatchObject *self, visitproc visit, void *arg) -+match_traverse(PyObject *op, visitproc visit, void *arg) - { -+ MatchObject *self = _MatchObject_CAST(op); - Py_VISIT(Py_TYPE(self)); - Py_VISIT(self->string); - Py_VISIT(self->regs); -@@ -2255,8 +2266,9 @@ - } - - static int --match_clear(MatchObject *self) -+match_clear(PyObject *op) - { -+ MatchObject *self = _MatchObject_CAST(op); - Py_CLEAR(self->string); - Py_CLEAR(self->regs); - Py_CLEAR(self->pattern); -@@ -2264,10 +2276,9 @@ - } - - static void --match_dealloc(MatchObject* self) -+match_dealloc(PyObject *self) - { - PyTypeObject *tp = Py_TYPE(self); -- - PyObject_GC_UnTrack(self); - (void)match_clear(self); - tp->tp_free(self); -@@ -2376,8 +2387,9 @@ - } - - static PyObject* --match_group(MatchObject* self, PyObject* args) -+match_group(PyObject *op, PyObject* args) - { -+ MatchObject *self = _MatchObject_CAST(op); - PyObject* result; - Py_ssize_t i, size; - -@@ -2411,8 +2423,9 @@ - } - - static PyObject* --match_getitem(MatchObject* self, PyObject* name) -+match_getitem(PyObject *op, PyObject* name) - { -+ MatchObject *self = _MatchObject_CAST(op); - return match_getslice(self, name, Py_None); - } - -@@ -2654,16 +2667,18 @@ - For 0 returns the entire match."); - - static PyObject * --match_lastindex_get(MatchObject *self, void *Py_UNUSED(ignored)) -+match_lastindex_get(PyObject *op, void *Py_UNUSED(ignored)) - { -+ MatchObject *self = _MatchObject_CAST(op); - if (self->lastindex >= 0) - return PyLong_FromSsize_t(self->lastindex); - Py_RETURN_NONE; - } - - static PyObject * --match_lastgroup_get(MatchObject *self, void *Py_UNUSED(ignored)) -+match_lastgroup_get(PyObject *op, void *Py_UNUSED(ignored)) - { -+ MatchObject *self = _MatchObject_CAST(op); - if (self->pattern->indexgroup && - self->lastindex >= 0 && - self->lastindex < PyTuple_GET_SIZE(self->pattern->indexgroup)) -@@ -2676,8 +2691,9 @@ - } - - static PyObject * --match_regs_get(MatchObject *self, void *Py_UNUSED(ignored)) -+match_regs_get(PyObject *op, void *Py_UNUSED(ignored)) - { -+ MatchObject *self = _MatchObject_CAST(op); - if (self->regs) { - return Py_NewRef(self->regs); - } else -@@ -2780,27 +2796,29 @@ - /* scanner methods (experimental) */ - - static int --scanner_traverse(ScannerObject *self, visitproc visit, void *arg) -+scanner_traverse(PyObject *op, visitproc visit, void *arg) - { -+ ScannerObject *self = _ScannerObject_CAST(op); - Py_VISIT(Py_TYPE(self)); - Py_VISIT(self->pattern); - return 0; - } - - static int --scanner_clear(ScannerObject *self) -+scanner_clear(PyObject *op) - { -+ ScannerObject *self = _ScannerObject_CAST(op); - Py_CLEAR(self->pattern); - return 0; - } - - static void --scanner_dealloc(ScannerObject* self) -+scanner_dealloc(PyObject *self) - { - PyTypeObject *tp = Py_TYPE(self); -- - PyObject_GC_UnTrack(self); -- state_fini(&self->state); -+ ScannerObject *scanner = _ScannerObject_CAST(self); -+ state_fini(&scanner->state); - (void)scanner_clear(self); - tp->tp_free(self); - Py_DECREF(tp); -@@ -2957,8 +2975,9 @@ - /* template methods */ - - static int --template_traverse(TemplateObject *self, visitproc visit, void *arg) -+template_traverse(PyObject *op, visitproc visit, void *arg) - { -+ TemplateObject *self = _TemplateObject_CAST(op); - Py_VISIT(Py_TYPE(self)); - Py_VISIT(self->literal); - for (Py_ssize_t i = 0, n = Py_SIZE(self); i < n; i++) { -@@ -2968,8 +2987,9 @@ - } - - static int --template_clear(TemplateObject *self) -+template_clear(PyObject *op) - { -+ TemplateObject *self = _TemplateObject_CAST(op); - Py_CLEAR(self->literal); - for (Py_ssize_t i = 0, n = Py_SIZE(self); i < n; i++) { - Py_CLEAR(self->items[i].literal); -@@ -2978,10 +2998,9 @@ - } - - static void --template_dealloc(TemplateObject *self) -+template_dealloc(PyObject *self) - { - PyTypeObject *tp = Py_TYPE(self); -- - PyObject_GC_UnTrack(self); - (void)template_clear(self); - tp->tp_free(self); -@@ -3056,8 +3075,10 @@ - - - static Py_hash_t --pattern_hash(PatternObject *self) -+pattern_hash(PyObject *op) - { -+ PatternObject *self = _PatternObject_CAST(op); -+ - Py_hash_t hash, hash2; - - hash = PyObject_Hash(self->pattern); -@@ -3148,7 +3169,7 @@ - }; - - static PyGetSetDef pattern_getset[] = { -- {"groupindex", (getter)pattern_groupindex, (setter)NULL, -+ {"groupindex", pattern_groupindex, NULL, - "A dictionary mapping group names to group numbers."}, - {NULL} /* Sentinel */ - }; -@@ -3166,9 +3187,9 @@ - }; - - static PyType_Slot pattern_slots[] = { -- {Py_tp_dealloc, (destructor)pattern_dealloc}, -- {Py_tp_repr, (reprfunc)pattern_repr}, -- {Py_tp_hash, (hashfunc)pattern_hash}, -+ {Py_tp_dealloc, pattern_dealloc}, -+ {Py_tp_repr, pattern_repr}, -+ {Py_tp_hash, pattern_hash}, - {Py_tp_doc, (void *)pattern_doc}, - {Py_tp_richcompare, pattern_richcompare}, - {Py_tp_methods, pattern_methods}, -@@ -3189,7 +3210,7 @@ - }; - - static PyMethodDef match_methods[] = { -- {"group", (PyCFunction) match_group, METH_VARARGS, match_group_doc}, -+ {"group", match_group, METH_VARARGS, match_group_doc}, - _SRE_SRE_MATCH_START_METHODDEF - _SRE_SRE_MATCH_END_METHODDEF - _SRE_SRE_MATCH_SPAN_METHODDEF -@@ -3204,11 +3225,11 @@ - }; - - static PyGetSetDef match_getset[] = { -- {"lastindex", (getter)match_lastindex_get, (setter)NULL, -+ {"lastindex", match_lastindex_get, NULL, - "The integer index of the last matched capturing group."}, -- {"lastgroup", (getter)match_lastgroup_get, (setter)NULL, -+ {"lastgroup", match_lastgroup_get, NULL, - "The name of the last matched capturing group."}, -- {"regs", (getter)match_regs_get, (setter)NULL}, -+ {"regs", match_regs_get, NULL, NULL}, - {NULL} - }; - -diff --git a/Modules/_sre/sre_lib.h b/Modules/_sre/sre_lib.h -index af4bfc56083..df377905bfa 100644 ---- a/Modules/_sre/sre_lib.h -+++ b/Modules/_sre/sre_lib.h -@@ -42,8 +42,6 @@ - return ((void*) ptr == state->end); - - case SRE_AT_BOUNDARY: -- if (state->beginning == state->end) -- return 0; - thatp = ((void*) ptr > state->beginning) ? - SRE_IS_WORD((int) ptr[-1]) : 0; - thisp = ((void*) ptr < state->end) ? -@@ -51,8 +49,6 @@ - return thisp != thatp; - - case SRE_AT_NON_BOUNDARY: -- if (state->beginning == state->end) -- return 0; - thatp = ((void*) ptr > state->beginning) ? - SRE_IS_WORD((int) ptr[-1]) : 0; - thisp = ((void*) ptr < state->end) ? -@@ -60,8 +56,6 @@ - return thisp == thatp; - - case SRE_AT_LOC_BOUNDARY: -- if (state->beginning == state->end) -- return 0; - thatp = ((void*) ptr > state->beginning) ? - SRE_LOC_IS_WORD((int) ptr[-1]) : 0; - thisp = ((void*) ptr < state->end) ? -@@ -69,8 +63,6 @@ - return thisp != thatp; - - case SRE_AT_LOC_NON_BOUNDARY: -- if (state->beginning == state->end) -- return 0; - thatp = ((void*) ptr > state->beginning) ? - SRE_LOC_IS_WORD((int) ptr[-1]) : 0; - thisp = ((void*) ptr < state->end) ? -@@ -78,8 +70,6 @@ - return thisp == thatp; - - case SRE_AT_UNI_BOUNDARY: -- if (state->beginning == state->end) -- return 0; - thatp = ((void*) ptr > state->beginning) ? - SRE_UNI_IS_WORD((int) ptr[-1]) : 0; - thisp = ((void*) ptr < state->end) ? -@@ -87,8 +77,6 @@ - return thisp != thatp; - - case SRE_AT_UNI_NON_BOUNDARY: -- if (state->beginning == state->end) -- return 0; - thatp = ((void*) ptr > state->beginning) ? - SRE_UNI_IS_WORD((int) ptr[-1]) : 0; - thisp = ((void*) ptr < state->end) ? -diff --git a/Modules/_ssl.c b/Modules/_ssl.c -index e7df132869f..85e917fbbb7 100644 ---- a/Modules/_ssl.c -+++ b/Modules/_ssl.c -@@ -473,6 +473,7 @@ - PyObject *err_value = NULL, *reason_obj = NULL, *lib_obj = NULL; - PyObject *verify_obj = NULL, *verify_code_obj = NULL; - PyObject *init_value, *msg, *key; -+ PyUnicodeWriter *writer = NULL; - - if (errcode != 0) { - int lib, reason; -@@ -495,11 +496,10 @@ - if (lib_obj == NULL && PyErr_Occurred()) { - goto fail; - } -- if (errstr == NULL) -+ if (errstr == NULL) { - errstr = ERR_reason_error_string(errcode); -+ } - } -- if (errstr == NULL) -- errstr = "unknown error"; - - /* verify code for cert validation error */ - if ((sslsock != NULL) && (type == state->PySSLCertVerificationErrorObject)) { -@@ -539,20 +539,50 @@ - } - } - -- if (verify_obj && reason_obj && lib_obj) -- msg = PyUnicode_FromFormat("[%S: %S] %s: %S (_ssl.c:%d)", -- lib_obj, reason_obj, errstr, verify_obj, -- lineno); -- else if (reason_obj && lib_obj) -- msg = PyUnicode_FromFormat("[%S: %S] %s (_ssl.c:%d)", -- lib_obj, reason_obj, errstr, lineno); -- else if (lib_obj) -- msg = PyUnicode_FromFormat("[%S] %s (_ssl.c:%d)", -- lib_obj, errstr, lineno); -- else -- msg = PyUnicode_FromFormat("%s (_ssl.c:%d)", errstr, lineno); -- if (msg == NULL) -+ // Format message roughly as: -+ // [lib_obj: reason_obj] errstr: verify_obj (_ssl.c:lineno) -+ // with parts missing/replaced if unavailable -+ writer = PyUnicodeWriter_Create(64); -+ if (!writer) { - goto fail; -+ } -+ if (lib_obj) { -+ if (PyUnicodeWriter_Format(writer, "[%S", lib_obj) < 0) { -+ goto fail; -+ } -+ if (reason_obj) { -+ if (PyUnicodeWriter_Format(writer, ": %S", reason_obj) < 0) { -+ goto fail; -+ } -+ } -+ if (PyUnicodeWriter_WriteUTF8(writer, "] ", 2) < 0) { -+ goto fail; -+ } -+ } -+ if (errstr) { -+ if (PyUnicodeWriter_Format(writer, "%s", errstr) < 0) { -+ goto fail; -+ } -+ } -+ else { -+ if (PyUnicodeWriter_Format( -+ writer, "unknown error (0x%x)", errcode) < 0) { -+ goto fail; -+ } -+ } -+ if (verify_obj) { -+ if (PyUnicodeWriter_Format(writer, ": %S", verify_obj) < 0) { -+ goto fail; -+ } -+ } -+ if (PyUnicodeWriter_Format(writer, " (_ssl.c:%d)", lineno) < 0) { -+ goto fail; -+ } -+ msg = PyUnicodeWriter_Finish(writer); -+ writer = NULL; -+ if (!msg) { -+ goto fail; -+ } - - init_value = Py_BuildValue("iN", ERR_GET_REASON(ssl_errno), msg); - if (init_value == NULL) -@@ -587,6 +617,7 @@ - Py_XDECREF(err_value); - Py_XDECREF(verify_code_obj); - Py_XDECREF(verify_obj); -+ PyUnicodeWriter_Discard(writer); - } - - static int -@@ -934,13 +965,13 @@ - } - } - if (owner && owner != Py_None) { -- if (_ssl__SSLSocket_owner_set(self, owner, NULL) == -1) { -+ if (_ssl__SSLSocket_owner_set((PyObject *)self, owner, NULL) < 0) { - Py_DECREF(self); - return NULL; - } - } - if (session && session != Py_None) { -- if (_ssl__SSLSocket_session_set(self, session, NULL) == -1) { -+ if (_ssl__SSLSocket_session_set((PyObject *)self, session, NULL) < 0) { - Py_DECREF(self); - return NULL; - } -@@ -4377,7 +4408,7 @@ - FILE *f; - DH *dh; - -- f = _Py_fopen_obj(filepath, "rb"); -+ f = Py_fopen(filepath, "rb"); - if (f == NULL) - return NULL; - -@@ -4635,7 +4666,8 @@ - - servername_bytes = PyBytes_FromString(servername); - if (servername_bytes == NULL) { -- PyErr_WriteUnraisable((PyObject *) sslctx); -+ PyErr_FormatUnraisable("Exception ignored " -+ "in ssl servername callback"); - goto error; - } - /* server_hostname was encoded to an A-label by our caller; put it -@@ -4643,7 +4675,10 @@ - */ - servername_str = PyUnicode_FromEncodedObject(servername_bytes, "ascii", NULL); - if (servername_str == NULL) { -- PyErr_WriteUnraisable(servername_bytes); -+ PyErr_FormatUnraisable("Exception ignored " -+ "in ssl servername callback " -+ "while decoding name %R", -+ servername_bytes); - Py_DECREF(servername_bytes); - goto error; - } -@@ -4656,7 +4691,10 @@ - Py_DECREF(ssl_socket); - - if (result == NULL) { -- PyErr_WriteUnraisable(sslctx->set_sni_cb); -+ PyErr_FormatUnraisable("Exception ignored " -+ "in ssl servername callback " -+ "while calling set SNI callback %R", -+ sslctx->set_sni_cb); - *al = SSL_AD_HANDSHAKE_FAILURE; - ret = SSL_TLSEXT_ERR_ALERT_FATAL; - } -@@ -4669,7 +4707,11 @@ - } else { - *al = (int) PyLong_AsLong(result); - if (PyErr_Occurred()) { -- PyErr_WriteUnraisable(result); -+ PyErr_FormatUnraisable("Exception ignored " -+ "in ssl servername callback " -+ "while calling set SNI callback " -+ "(result=%R)", -+ result); - *al = SSL_AD_INTERNAL_ERROR; - } - ret = SSL_TLSEXT_ERR_ALERT_FATAL; -@@ -4976,7 +5018,8 @@ - - error: - if (PyErr_Occurred()) { -- PyErr_WriteUnraisable(callback); -+ PyErr_FormatUnraisable("Exception ignored in ssl PSK client callback " -+ "while calling callback %R", callback); - } - PyGILState_Release(gstate); - return 0; -@@ -5085,7 +5128,8 @@ - - error: - if (PyErr_Occurred()) { -- PyErr_WriteUnraisable(callback); -+ PyErr_FormatUnraisable("Exception ignored in ssl PSK server callback " -+ "while calling callback %R", callback); - } - PyGILState_Release(gstate); - return 0; -@@ -6553,6 +6597,12 @@ - addbool(m, "HAS_PSK", 1); - #endif - -+#ifdef SSL_VERIFY_POST_HANDSHAKE -+ addbool(m, "HAS_PHA", 1); -+#else -+ addbool(m, "HAS_PHA", 0); -+#endif -+ - #undef addbool - #undef ADD_INT_CONST - -diff --git a/Modules/_ssl/cert.c b/Modules/_ssl/cert.c -index bda66dc4d94..c11ed8e3a28 100644 ---- a/Modules/_ssl/cert.c -+++ b/Modules/_ssl/cert.c -@@ -153,10 +153,13 @@ - * PySSLCertificate_Type - */ - -+#define _PySSLCertificate_CAST(op) ((PySSLCertificate *)(op)) -+ - static PyObject * --certificate_repr(PySSLCertificate *self) -+certificate_repr(PyObject *op) - { - PyObject *osubject, *result; -+ PySSLCertificate *self = _PySSLCertificate_CAST(op); - - /* subject string is ASCII encoded, UTF-8 chars are quoted */ - osubject = _x509name_print( -@@ -176,8 +179,9 @@ - } - - static Py_hash_t --certificate_hash(PySSLCertificate *self) -+certificate_hash(PyObject *op) - { -+ PySSLCertificate *self = _PySSLCertificate_CAST(op); - if (self->hash == (Py_hash_t)-1) { - unsigned long hash; - hash = X509_subject_name_hash(self->cert); -@@ -191,19 +195,20 @@ - } - - static PyObject * --certificate_richcompare(PySSLCertificate *self, PyObject *other, int op) -+certificate_richcompare(PyObject *lhs, PyObject *rhs, int op) - { - int cmp; -+ PySSLCertificate *self = _PySSLCertificate_CAST(lhs); - _sslmodulestate *state = get_state_cert(self); - -- if (Py_TYPE(other) != state->PySSLCertificate_Type) { -+ if (Py_TYPE(rhs) != state->PySSLCertificate_Type) { - Py_RETURN_NOTIMPLEMENTED; - } - /* only support == and != */ - if ((op != Py_EQ) && (op != Py_NE)) { - Py_RETURN_NOTIMPLEMENTED; - } -- cmp = X509_cmp(self->cert, ((PySSLCertificate*)other)->cert); -+ cmp = X509_cmp(self->cert, ((PySSLCertificate*)rhs)->cert); - if (((op == Py_EQ) && (cmp == 0)) || ((op == Py_NE) && (cmp != 0))) { - Py_RETURN_TRUE; - } else { -@@ -212,11 +217,12 @@ - } - - static void --certificate_dealloc(PySSLCertificate *self) -+certificate_dealloc(PyObject *op) - { -+ PySSLCertificate *self = _PySSLCertificate_CAST(op); - PyTypeObject *tp = Py_TYPE(self); - X509_free(self->cert); -- Py_TYPE(self)->tp_free(self); -+ (void)Py_TYPE(self)->tp_free(self); - Py_DECREF(tp); - } - -diff --git a/Modules/_ssl/clinic/cert.c.h b/Modules/_ssl/clinic/cert.c.h -index 19559442cd9..3e0c5b40509 100644 ---- a/Modules/_ssl/clinic/cert.c.h -+++ b/Modules/_ssl/clinic/cert.c.h -@@ -20,7 +20,7 @@ - _ssl_Certificate_public_bytes_impl(PySSLCertificate *self, int format); - - static PyObject * --_ssl_Certificate_public_bytes(PySSLCertificate *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_ssl_Certificate_public_bytes(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -65,7 +65,7 @@ - goto exit; - } - skip_optional_pos: -- return_value = _ssl_Certificate_public_bytes_impl(self, format); -+ return_value = _ssl_Certificate_public_bytes_impl((PySSLCertificate *)self, format); - - exit: - return return_value; -@@ -83,8 +83,8 @@ - _ssl_Certificate_get_info_impl(PySSLCertificate *self); - - static PyObject * --_ssl_Certificate_get_info(PySSLCertificate *self, PyObject *Py_UNUSED(ignored)) -+_ssl_Certificate_get_info(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _ssl_Certificate_get_info_impl(self); -+ return _ssl_Certificate_get_info_impl((PySSLCertificate *)self); - } --/*[clinic end generated code: output=e5fa354db5fc56b4 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=51365b498b975ee0 input=a9049054013a1b77]*/ -diff --git a/Modules/_ssl/debughelpers.c b/Modules/_ssl/debughelpers.c -index 9c87f8b4d21..318c045a0ee 100644 ---- a/Modules/_ssl/debughelpers.c -+++ b/Modules/_ssl/debughelpers.c -@@ -180,8 +180,8 @@ - return 0; - } - -- /* _Py_fopen_obj() also checks that arg is of proper type. */ -- fp = _Py_fopen_obj(arg, "a" PY_STDIOTEXTMODE); -+ /* Py_fopen() also checks that arg is of proper type. */ -+ fp = Py_fopen(arg, "a" PY_STDIOTEXTMODE); - if (fp == NULL) - return -1; - ---- /dev/null -+++ b/Modules/_testcapi/clinic/file.c.h -@@ -0,0 +1,64 @@ -+/*[clinic input] -+preserve -+[clinic start generated code]*/ -+ -+#include "pycore_modsupport.h" // _PyArg_CheckPositional() -+ -+PyDoc_STRVAR(_testcapi_pyfile_newstdprinter__doc__, -+"pyfile_newstdprinter($module, fd, /)\n" -+"--\n" -+"\n"); -+ -+#define _TESTCAPI_PYFILE_NEWSTDPRINTER_METHODDEF \ -+ {"pyfile_newstdprinter", (PyCFunction)_testcapi_pyfile_newstdprinter, METH_O, _testcapi_pyfile_newstdprinter__doc__}, -+ -+static PyObject * -+_testcapi_pyfile_newstdprinter_impl(PyObject *module, int fd); -+ -+static PyObject * -+_testcapi_pyfile_newstdprinter(PyObject *module, PyObject *arg) -+{ -+ PyObject *return_value = NULL; -+ int fd; -+ -+ fd = PyLong_AsInt(arg); -+ if (fd == -1 && PyErr_Occurred()) { -+ goto exit; -+ } -+ return_value = _testcapi_pyfile_newstdprinter_impl(module, fd); -+ -+exit: -+ return return_value; -+} -+ -+PyDoc_STRVAR(_testcapi_py_fopen__doc__, -+"py_fopen($module, path, mode, /)\n" -+"--\n" -+"\n" -+"Call Py_fopen(), fread(256) and Py_fclose(). Return read bytes."); -+ -+#define _TESTCAPI_PY_FOPEN_METHODDEF \ -+ {"py_fopen", _PyCFunction_CAST(_testcapi_py_fopen), METH_FASTCALL, _testcapi_py_fopen__doc__}, -+ -+static PyObject * -+_testcapi_py_fopen_impl(PyObject *module, PyObject *path, const char *mode, -+ Py_ssize_t mode_length); -+ -+static PyObject * -+_testcapi_py_fopen(PyObject *module, PyObject *const *args, Py_ssize_t nargs) -+{ -+ PyObject *return_value = NULL; -+ PyObject *path; -+ const char *mode; -+ Py_ssize_t mode_length; -+ -+ if (!_PyArg_ParseStack(args, nargs, "Oz#:py_fopen", -+ &path, &mode, &mode_length)) { -+ goto exit; -+ } -+ return_value = _testcapi_py_fopen_impl(module, path, mode, mode_length); -+ -+exit: -+ return return_value; -+} -+/*[clinic end generated code: output=e943bbd7f181d079 input=a9049054013a1b77]*/ -diff --git a/Modules/_testcapi/code.c b/Modules/_testcapi/code.c -index c0193489b6f..94f752c9726 100644 ---- a/Modules/_testcapi/code.c -+++ b/Modules/_testcapi/code.c -@@ -47,7 +47,6 @@ - test_code_extra(PyObject* self, PyObject *Py_UNUSED(callable)) - { - PyObject *result = NULL; -- PyObject *test_module = NULL; - PyObject *test_func = NULL; - - // Get or initialize interpreter-specific code object storage index -@@ -62,11 +61,8 @@ - - // Get a function to test with - // This can be any Python function. Use `test.test_misc.testfunction`. -- test_module = PyImport_ImportModule("test.test_capi.test_misc"); -- if (!test_module) { -- goto finally; -- } -- test_func = PyObject_GetAttrString(test_module, "testfunction"); -+ test_func = PyImport_ImportModuleAttrString("test.test_capi.test_misc", -+ "testfunction"); - if (!test_func) { - goto finally; - } -@@ -102,7 +98,6 @@ - } - result = Py_NewRef(Py_None); - finally: -- Py_XDECREF(test_module); - Py_XDECREF(test_func); - return result; - } -diff --git a/Modules/_testcapi/dict.c b/Modules/_testcapi/dict.c -index 307797f98f1..b7c73d7332b 100644 ---- a/Modules/_testcapi/dict.c -+++ b/Modules/_testcapi/dict.c -@@ -181,6 +181,83 @@ - RETURN_INT(PyDict_PopString(dict, key, NULL)); - } - -+ -+static int -+test_dict_inner(PyObject *self, int count) -+{ -+ Py_ssize_t pos = 0, iterations = 0; -+ int i; -+ PyObject *dict = PyDict_New(); -+ PyObject *v, *k; -+ -+ if (dict == NULL) -+ return -1; -+ -+ for (i = 0; i < count; i++) { -+ v = PyLong_FromLong(i); -+ if (v == NULL) { -+ goto error; -+ } -+ if (PyDict_SetItem(dict, v, v) < 0) { -+ Py_DECREF(v); -+ goto error; -+ } -+ Py_DECREF(v); -+ } -+ -+ k = v = UNINITIALIZED_PTR; -+ while (PyDict_Next(dict, &pos, &k, &v)) { -+ PyObject *o; -+ iterations++; -+ -+ assert(k != UNINITIALIZED_PTR); -+ assert(v != UNINITIALIZED_PTR); -+ i = PyLong_AS_LONG(v) + 1; -+ o = PyLong_FromLong(i); -+ if (o == NULL) { -+ goto error; -+ } -+ if (PyDict_SetItem(dict, k, o) < 0) { -+ Py_DECREF(o); -+ goto error; -+ } -+ Py_DECREF(o); -+ k = v = UNINITIALIZED_PTR; -+ } -+ assert(k == UNINITIALIZED_PTR); -+ assert(v == UNINITIALIZED_PTR); -+ -+ Py_DECREF(dict); -+ -+ if (iterations != count) { -+ PyErr_SetString( -+ PyExc_AssertionError, -+ "test_dict_iteration: dict iteration went wrong "); -+ return -1; -+ } else { -+ return 0; -+ } -+error: -+ Py_DECREF(dict); -+ return -1; -+} -+ -+ -+static PyObject* -+test_dict_iteration(PyObject* self, PyObject *Py_UNUSED(ignored)) -+{ -+ int i; -+ -+ for (i = 0; i < 200; i++) { -+ if (test_dict_inner(self, i) < 0) { -+ return NULL; -+ } -+ } -+ -+ Py_RETURN_NONE; -+} -+ -+ - static PyMethodDef test_methods[] = { - {"dict_containsstring", dict_containsstring, METH_VARARGS}, - {"dict_getitemref", dict_getitemref, METH_VARARGS}, -@@ -191,6 +268,7 @@ - {"dict_pop_null", dict_pop_null, METH_VARARGS}, - {"dict_popstring", dict_popstring, METH_VARARGS}, - {"dict_popstring_null", dict_popstring_null, METH_VARARGS}, -+ {"test_dict_iteration", test_dict_iteration, METH_NOARGS}, - {NULL}, - }; - -diff --git a/Modules/_testcapi/exceptions.c b/Modules/_testcapi/exceptions.c -index e92d9670e7c..b647bfc71ea 100644 ---- a/Modules/_testcapi/exceptions.c -+++ b/Modules/_testcapi/exceptions.c -@@ -3,6 +3,7 @@ - - #include "parts.h" - #include "util.h" -+ - #include "clinic/exceptions.c.h" - - -diff --git a/Modules/_testcapi/file.c b/Modules/_testcapi/file.c -index 634563f6ea1..060e0f50598 100644 ---- a/Modules/_testcapi/file.c -+++ b/Modules/_testcapi/file.c -@@ -1,17 +1,70 @@ -+// clinic/file.c.h uses internal pycore_modsupport.h API -+#define PYTESTCAPI_NEED_INTERNAL_API -+ - #include "parts.h" - #include "util.h" -+#include "clinic/file.c.h" -+ -+ -+/*[clinic input] -+module _testcapi -+[clinic start generated code]*/ -+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=6361033e795369fc]*/ -+ -+ -+/*[clinic input] -+_testcapi.pyfile_newstdprinter -+ -+ fd: int -+ / -+ -+[clinic start generated code]*/ -+ -+static PyObject * -+_testcapi_pyfile_newstdprinter_impl(PyObject *module, int fd) -+/*[clinic end generated code: output=8a2d1c57b6892db3 input=442f1824142262ea]*/ -+{ -+ return PyFile_NewStdPrinter(fd); -+} -+ -+ -+/*[clinic input] -+_testcapi.py_fopen -+ -+ path: object -+ mode: str(zeroes=True, accept={robuffer, str, NoneType}) -+ / -+ -+Call Py_fopen(), fread(256) and Py_fclose(). Return read bytes. -+[clinic start generated code]*/ -+ -+static PyObject * -+_testcapi_py_fopen_impl(PyObject *module, PyObject *path, const char *mode, -+ Py_ssize_t mode_length) -+/*[clinic end generated code: output=69840d0cfd8b7fbb input=f3a579dd7eb60926]*/ -+{ -+ NULLABLE(path); -+ FILE *fp = Py_fopen(path, mode); -+ if (fp == NULL) { -+ return NULL; -+ } -+ -+ char buffer[256]; -+ size_t size = fread(buffer, 1, Py_ARRAY_LENGTH(buffer), fp); -+ Py_fclose(fp); -+ -+ return PyBytes_FromStringAndSize(buffer, size); -+} - - - static PyMethodDef test_methods[] = { -+ _TESTCAPI_PYFILE_NEWSTDPRINTER_METHODDEF -+ _TESTCAPI_PY_FOPEN_METHODDEF - {NULL}, - }; - - int - _PyTestCapi_Init_File(PyObject *m) - { -- if (PyModule_AddFunctions(m, test_methods) < 0){ -- return -1; -- } -- -- return 0; -+ return PyModule_AddFunctions(m, test_methods); - } -diff --git a/Modules/_testcapi/float.c b/Modules/_testcapi/float.c -index 15ea97ec452..e3869134c84 100644 ---- a/Modules/_testcapi/float.c -+++ b/Modules/_testcapi/float.c -@@ -99,9 +99,68 @@ - return PyFloat_FromDouble(d); - } - -+ -+/* Test PyOS_string_to_double. */ -+static PyObject * -+test_string_to_double(PyObject *self, PyObject *Py_UNUSED(ignored)) -+{ -+ double result; -+ const char *msg; -+ -+#define CHECK_STRING(STR, expected) \ -+ do { \ -+ result = PyOS_string_to_double(STR, NULL, NULL); \ -+ if (result == -1.0 && PyErr_Occurred()) { \ -+ return NULL; \ -+ } \ -+ if (result != (double)expected) { \ -+ msg = "conversion of " STR " to float failed"; \ -+ goto fail; \ -+ } \ -+ } while (0) -+ -+#define CHECK_INVALID(STR) \ -+ do { \ -+ result = PyOS_string_to_double(STR, NULL, NULL); \ -+ if (result == -1.0 && PyErr_Occurred()) { \ -+ if (PyErr_ExceptionMatches(PyExc_ValueError)) { \ -+ PyErr_Clear(); \ -+ } \ -+ else { \ -+ return NULL; \ -+ } \ -+ } \ -+ else { \ -+ msg = "conversion of " STR " didn't raise ValueError"; \ -+ goto fail; \ -+ } \ -+ } while (0) -+ -+ CHECK_STRING("0.1", 0.1); -+ CHECK_STRING("1.234", 1.234); -+ CHECK_STRING("-1.35", -1.35); -+ CHECK_STRING(".1e01", 1.0); -+ CHECK_STRING("2.e-2", 0.02); -+ -+ CHECK_INVALID(" 0.1"); -+ CHECK_INVALID("\t\n-3"); -+ CHECK_INVALID(".123 "); -+ CHECK_INVALID("3\n"); -+ CHECK_INVALID("123abc"); -+ -+ Py_RETURN_NONE; -+ fail: -+ PyErr_Format(PyExc_AssertionError, "test_string_to_double: %s", msg); -+ return NULL; -+#undef CHECK_STRING -+#undef CHECK_INVALID -+} -+ -+ - static PyMethodDef test_methods[] = { - _TESTCAPI_FLOAT_PACK_METHODDEF - _TESTCAPI_FLOAT_UNPACK_METHODDEF -+ {"test_string_to_double", test_string_to_double, METH_NOARGS}, - {NULL}, - }; - ---- /dev/null -+++ b/Modules/_testcapi/frame.c -@@ -0,0 +1,134 @@ -+#include "parts.h" -+#include "util.h" -+ -+#include "frameobject.h" // PyFrame_New() -+ -+ -+static PyObject * -+frame_getlocals(PyObject *self, PyObject *frame) -+{ -+ if (!PyFrame_Check(frame)) { -+ PyErr_SetString(PyExc_TypeError, "argument must be a frame"); -+ return NULL; -+ } -+ return PyFrame_GetLocals((PyFrameObject *)frame); -+} -+ -+ -+static PyObject * -+frame_getglobals(PyObject *self, PyObject *frame) -+{ -+ if (!PyFrame_Check(frame)) { -+ PyErr_SetString(PyExc_TypeError, "argument must be a frame"); -+ return NULL; -+ } -+ return PyFrame_GetGlobals((PyFrameObject *)frame); -+} -+ -+ -+static PyObject * -+frame_getgenerator(PyObject *self, PyObject *frame) -+{ -+ if (!PyFrame_Check(frame)) { -+ PyErr_SetString(PyExc_TypeError, "argument must be a frame"); -+ return NULL; -+ } -+ return PyFrame_GetGenerator((PyFrameObject *)frame); -+} -+ -+ -+static PyObject * -+frame_getbuiltins(PyObject *self, PyObject *frame) -+{ -+ if (!PyFrame_Check(frame)) { -+ PyErr_SetString(PyExc_TypeError, "argument must be a frame"); -+ return NULL; -+ } -+ return PyFrame_GetBuiltins((PyFrameObject *)frame); -+} -+ -+ -+static PyObject * -+frame_getlasti(PyObject *self, PyObject *frame) -+{ -+ if (!PyFrame_Check(frame)) { -+ PyErr_SetString(PyExc_TypeError, "argument must be a frame"); -+ return NULL; -+ } -+ int lasti = PyFrame_GetLasti((PyFrameObject *)frame); -+ if (lasti < 0) { -+ assert(lasti == -1); -+ Py_RETURN_NONE; -+ } -+ return PyLong_FromLong(lasti); -+} -+ -+ -+static PyObject * -+frame_new(PyObject *self, PyObject *args) -+{ -+ PyObject *code, *globals, *locals; -+ if (!PyArg_ParseTuple(args, "OOO", &code, &globals, &locals)) { -+ return NULL; -+ } -+ if (!PyCode_Check(code)) { -+ PyErr_SetString(PyExc_TypeError, "argument must be a code object"); -+ return NULL; -+ } -+ PyThreadState *tstate = PyThreadState_Get(); -+ -+ return (PyObject *)PyFrame_New(tstate, (PyCodeObject *)code, globals, locals); -+} -+ -+ -+static PyObject * -+frame_getvar(PyObject *self, PyObject *args) -+{ -+ PyObject *frame, *name; -+ if (!PyArg_ParseTuple(args, "OO", &frame, &name)) { -+ return NULL; -+ } -+ if (!PyFrame_Check(frame)) { -+ PyErr_SetString(PyExc_TypeError, "argument must be a frame"); -+ return NULL; -+ } -+ -+ return PyFrame_GetVar((PyFrameObject *)frame, name); -+} -+ -+ -+static PyObject * -+frame_getvarstring(PyObject *self, PyObject *args) -+{ -+ PyObject *frame; -+ const char *name; -+ if (!PyArg_ParseTuple(args, "Oy", &frame, &name)) { -+ return NULL; -+ } -+ if (!PyFrame_Check(frame)) { -+ PyErr_SetString(PyExc_TypeError, "argument must be a frame"); -+ return NULL; -+ } -+ -+ return PyFrame_GetVarString((PyFrameObject *)frame, name); -+} -+ -+ -+static PyMethodDef test_methods[] = { -+ {"frame_getlocals", frame_getlocals, METH_O, NULL}, -+ {"frame_getglobals", frame_getglobals, METH_O, NULL}, -+ {"frame_getgenerator", frame_getgenerator, METH_O, NULL}, -+ {"frame_getbuiltins", frame_getbuiltins, METH_O, NULL}, -+ {"frame_getlasti", frame_getlasti, METH_O, NULL}, -+ {"frame_new", frame_new, METH_VARARGS, NULL}, -+ {"frame_getvar", frame_getvar, METH_VARARGS, NULL}, -+ {"frame_getvarstring", frame_getvarstring, METH_VARARGS, NULL}, -+ {NULL}, -+}; -+ -+int -+_PyTestCapi_Init_Frame(PyObject *m) -+{ -+ return PyModule_AddFunctions(m, test_methods); -+} -+ ---- /dev/null -+++ b/Modules/_testcapi/function.c -@@ -0,0 +1,143 @@ -+#include "parts.h" -+#include "util.h" -+ -+ -+static PyObject * -+function_get_code(PyObject *self, PyObject *func) -+{ -+ PyObject *code = PyFunction_GetCode(func); -+ if (code != NULL) { -+ return Py_NewRef(code); -+ } else { -+ return NULL; -+ } -+} -+ -+ -+static PyObject * -+function_get_globals(PyObject *self, PyObject *func) -+{ -+ PyObject *globals = PyFunction_GetGlobals(func); -+ if (globals != NULL) { -+ return Py_NewRef(globals); -+ } else { -+ return NULL; -+ } -+} -+ -+ -+static PyObject * -+function_get_module(PyObject *self, PyObject *func) -+{ -+ PyObject *module = PyFunction_GetModule(func); -+ if (module != NULL) { -+ return Py_NewRef(module); -+ } else { -+ return NULL; -+ } -+} -+ -+ -+static PyObject * -+function_get_defaults(PyObject *self, PyObject *func) -+{ -+ PyObject *defaults = PyFunction_GetDefaults(func); -+ if (defaults != NULL) { -+ return Py_NewRef(defaults); -+ } else if (PyErr_Occurred()) { -+ return NULL; -+ } else { -+ Py_RETURN_NONE; // This can happen when `defaults` are set to `None` -+ } -+} -+ -+ -+static PyObject * -+function_set_defaults(PyObject *self, PyObject *args) -+{ -+ PyObject *func = NULL, *defaults = NULL; -+ if (!PyArg_ParseTuple(args, "OO", &func, &defaults)) { -+ return NULL; -+ } -+ int result = PyFunction_SetDefaults(func, defaults); -+ if (result == -1) -+ return NULL; -+ Py_RETURN_NONE; -+} -+ -+ -+static PyObject * -+function_get_kw_defaults(PyObject *self, PyObject *func) -+{ -+ PyObject *defaults = PyFunction_GetKwDefaults(func); -+ if (defaults != NULL) { -+ return Py_NewRef(defaults); -+ } else if (PyErr_Occurred()) { -+ return NULL; -+ } else { -+ Py_RETURN_NONE; // This can happen when `kwdefaults` are set to `None` -+ } -+} -+ -+ -+static PyObject * -+function_set_kw_defaults(PyObject *self, PyObject *args) -+{ -+ PyObject *func = NULL, *defaults = NULL; -+ if (!PyArg_ParseTuple(args, "OO", &func, &defaults)) { -+ return NULL; -+ } -+ int result = PyFunction_SetKwDefaults(func, defaults); -+ if (result == -1) -+ return NULL; -+ Py_RETURN_NONE; -+} -+ -+ -+static PyObject * -+function_get_closure(PyObject *self, PyObject *func) -+{ -+ PyObject *closure = PyFunction_GetClosure(func); -+ if (closure != NULL) { -+ return Py_NewRef(closure); -+ } else if (PyErr_Occurred()) { -+ return NULL; -+ } else { -+ Py_RETURN_NONE; // This can happen when `closure` is set to `None` -+ } -+} -+ -+ -+static PyObject * -+function_set_closure(PyObject *self, PyObject *args) -+{ -+ PyObject *func = NULL, *closure = NULL; -+ if (!PyArg_ParseTuple(args, "OO", &func, &closure)) { -+ return NULL; -+ } -+ int result = PyFunction_SetClosure(func, closure); -+ if (result == -1) { -+ return NULL; -+ } -+ Py_RETURN_NONE; -+} -+ -+ -+static PyMethodDef test_methods[] = { -+ {"function_get_code", function_get_code, METH_O, NULL}, -+ {"function_get_globals", function_get_globals, METH_O, NULL}, -+ {"function_get_module", function_get_module, METH_O, NULL}, -+ {"function_get_defaults", function_get_defaults, METH_O, NULL}, -+ {"function_set_defaults", function_set_defaults, METH_VARARGS, NULL}, -+ {"function_get_kw_defaults", function_get_kw_defaults, METH_O, NULL}, -+ {"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL}, -+ {"function_get_closure", function_get_closure, METH_O, NULL}, -+ {"function_set_closure", function_set_closure, METH_VARARGS, NULL}, -+ {NULL}, -+}; -+ -+int -+_PyTestCapi_Init_Function(PyObject *m) -+{ -+ return PyModule_AddFunctions(m, test_methods); -+} -diff --git a/Modules/_testcapi/gc.c b/Modules/_testcapi/gc.c -index 7e33e0d4861..3691796302e 100644 ---- a/Modules/_testcapi/gc.c -+++ b/Modules/_testcapi/gc.c -@@ -94,7 +94,7 @@ - - PyObject *tp_del = PyUnicode_InternFromString("__tp_del__"); - if (tp_del == NULL) { -- PyErr_WriteUnraisable(NULL); -+ PyErr_FormatUnraisable("Exception ignored while deallocating"); - PyErr_SetRaisedException(exc); - return; - } -@@ -104,10 +104,13 @@ - if (del != NULL) { - res = PyObject_CallOneArg(del, self); - Py_DECREF(del); -- if (res == NULL) -- PyErr_WriteUnraisable(del); -- else -+ if (res == NULL) { -+ PyErr_FormatUnraisable("Exception ignored while calling " -+ "deallocator %R", del); -+ } -+ else { - Py_DECREF(res); -+ } - } - - /* Restore the saved exception. */ -diff --git a/Modules/_testcapi/immortal.c b/Modules/_testcapi/immortal.c -index 9f81389811c..0663c3781d4 100644 ---- a/Modules/_testcapi/immortal.c -+++ b/Modules/_testcapi/immortal.c -@@ -1,5 +1,8 @@ - #include "parts.h" - -+#define Py_BUILD_CORE -+#include "internal/pycore_long.h" // IMMORTALITY_BIT_MASK -+ - int verify_immortality(PyObject *object) - { - assert(_Py_IsImmortal(object)); -@@ -26,14 +29,31 @@ - test_immortal_small_ints(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - for (int i = -5; i <= 256; i++) { -- assert(verify_immortality(PyLong_FromLong(i))); -+ PyObject *obj = PyLong_FromLong(i); -+ assert(verify_immortality(obj)); -+ int has_int_immortal_bit = ((PyLongObject *)obj)->long_value.lv_tag & IMMORTALITY_BIT_MASK; -+ assert(has_int_immortal_bit); -+ } -+ for (int i = 257; i <= 260; i++) { -+ PyObject *obj = PyLong_FromLong(i); -+ assert(obj); -+ int has_int_immortal_bit = ((PyLongObject *)obj)->long_value.lv_tag & IMMORTALITY_BIT_MASK; -+ assert(!has_int_immortal_bit); -+ Py_DECREF(obj); - } - Py_RETURN_NONE; - } - -+static PyObject * -+is_immortal(PyObject *self, PyObject *op) -+{ -+ return PyBool_FromLong(PyUnstable_IsImmortal(op)); -+} -+ - static PyMethodDef test_methods[] = { - {"test_immortal_builtins", test_immortal_builtins, METH_NOARGS}, - {"test_immortal_small_ints", test_immortal_small_ints, METH_NOARGS}, -+ {"is_immortal", is_immortal, METH_O}, - {NULL}, - }; - ---- /dev/null -+++ b/Modules/_testcapi/import.c -@@ -0,0 +1,44 @@ -+#include "parts.h" -+#include "util.h" -+ -+// Test PyImport_ImportModuleAttr() -+static PyObject * -+pyimport_importmoduleattr(PyObject *self, PyObject *args) -+{ -+ PyObject *mod_name, *attr_name; -+ if (!PyArg_ParseTuple(args, "OO", &mod_name, &attr_name)) { -+ return NULL; -+ } -+ NULLABLE(mod_name); -+ NULLABLE(attr_name); -+ -+ return PyImport_ImportModuleAttr(mod_name, attr_name); -+} -+ -+ -+// Test PyImport_ImportModuleAttrString() -+static PyObject * -+pyimport_importmoduleattrstring(PyObject *self, PyObject *args) -+{ -+ const char *mod_name, *attr_name; -+ Py_ssize_t len; -+ if (!PyArg_ParseTuple(args, "z#z#", &mod_name, &len, &attr_name, &len)) { -+ return NULL; -+ } -+ -+ return PyImport_ImportModuleAttrString(mod_name, attr_name); -+} -+ -+ -+static PyMethodDef test_methods[] = { -+ {"PyImport_ImportModuleAttr", pyimport_importmoduleattr, METH_VARARGS}, -+ {"PyImport_ImportModuleAttrString", pyimport_importmoduleattrstring, METH_VARARGS}, -+ {NULL}, -+}; -+ -+int -+_PyTestCapi_Init_Import(PyObject *m) -+{ -+ return PyModule_AddFunctions(m, test_methods); -+} -+ -diff --git a/Modules/_testcapi/list.c b/Modules/_testcapi/list.c -index 09cec4c30c8..530b47780ac 100644 ---- a/Modules/_testcapi/list.c -+++ b/Modules/_testcapi/list.c -@@ -60,22 +60,61 @@ - } - - -+static PyObject* -+test_list_api(PyObject *self, PyObject *Py_UNUSED(ignored)) -+{ -+ PyObject* list; -+ int i; -+ -+ /* SF bug 132008: PyList_Reverse segfaults */ -+#define NLIST 30 -+ list = PyList_New(NLIST); -+ if (list == (PyObject*)NULL) -+ return (PyObject*)NULL; -+ /* list = range(NLIST) */ -+ for (i = 0; i < NLIST; ++i) { -+ PyObject* anint = PyLong_FromLong(i); -+ if (anint == (PyObject*)NULL) { -+ Py_DECREF(list); -+ return (PyObject*)NULL; -+ } -+ PyList_SET_ITEM(list, i, anint); -+ } -+ /* list.reverse(), via PyList_Reverse() */ -+ i = PyList_Reverse(list); /* should not blow up! */ -+ if (i != 0) { -+ Py_DECREF(list); -+ return (PyObject*)NULL; -+ } -+ /* Check that list == range(29, -1, -1) now */ -+ for (i = 0; i < NLIST; ++i) { -+ PyObject* anint = PyList_GET_ITEM(list, i); -+ if (PyLong_AS_LONG(anint) != NLIST-1-i) { -+ PyErr_SetString(PyExc_AssertionError, -+ "test_list_api: reverse screwed up"); -+ Py_DECREF(list); -+ return (PyObject*)NULL; -+ } -+ } -+ Py_DECREF(list); -+#undef NLIST -+ -+ Py_RETURN_NONE; -+} -+ -+ - static PyMethodDef test_methods[] = { - {"list_get_size", list_get_size, METH_O}, - {"list_get_item", list_get_item, METH_VARARGS}, - {"list_set_item", list_set_item, METH_VARARGS}, - {"list_clear", list_clear, METH_O}, - {"list_extend", list_extend, METH_VARARGS}, -- -+ {"test_list_api", test_list_api, METH_NOARGS}, - {NULL}, - }; - - int - _PyTestCapi_Init_List(PyObject *m) - { -- if (PyModule_AddFunctions(m, test_methods) < 0) { -- return -1; -- } -- -- return 0; -+ return PyModule_AddFunctions(m, test_methods); - } -diff --git a/Modules/_testcapi/mem.c b/Modules/_testcapi/mem.c -index ab4ad934644..7237fb94c3f 100644 ---- a/Modules/_testcapi/mem.c -+++ b/Modules/_testcapi/mem.c -@@ -557,8 +557,9 @@ - { - unsigned int domain; - PyObject *ptr_obj; -+ int release_gil = 0; - -- if (!PyArg_ParseTuple(args, "IO", &domain, &ptr_obj)) { -+ if (!PyArg_ParseTuple(args, "IO|i", &domain, &ptr_obj, &release_gil)) { - return NULL; - } - void *ptr = PyLong_AsVoidPtr(ptr_obj); -@@ -566,7 +567,15 @@ - return NULL; - } - -- int res = PyTraceMalloc_Untrack(domain, (uintptr_t)ptr); -+ int res; -+ if (release_gil) { -+ Py_BEGIN_ALLOW_THREADS -+ res = PyTraceMalloc_Untrack(domain, (uintptr_t)ptr); -+ Py_END_ALLOW_THREADS -+ } -+ else { -+ res = PyTraceMalloc_Untrack(domain, (uintptr_t)ptr); -+ } - if (res < 0) { - PyErr_SetString(PyExc_RuntimeError, "PyTraceMalloc_Untrack error"); - return NULL; -@@ -575,6 +584,106 @@ - Py_RETURN_NONE; - } - -+ -+static void -+tracemalloc_track_race_thread(void *data) -+{ -+ PyTraceMalloc_Track(123, 10, 1); -+ PyTraceMalloc_Untrack(123, 10); -+ -+ PyThread_type_lock lock = (PyThread_type_lock)data; -+ PyThread_release_lock(lock); -+} -+ -+// gh-128679: Test fix for tracemalloc.stop() race condition -+static PyObject * -+tracemalloc_track_race(PyObject *self, PyObject *args) -+{ -+#define NTHREAD 50 -+ PyObject *tracemalloc = NULL; -+ PyObject *stop = NULL; -+ PyThread_type_lock locks[NTHREAD]; -+ memset(locks, 0, sizeof(locks)); -+ -+ // Call tracemalloc.start() -+ tracemalloc = PyImport_ImportModule("tracemalloc"); -+ if (tracemalloc == NULL) { -+ goto error; -+ } -+ PyObject *start = PyObject_GetAttrString(tracemalloc, "start"); -+ if (start == NULL) { -+ goto error; -+ } -+ PyObject *res = PyObject_CallNoArgs(start); -+ Py_DECREF(start); -+ if (res == NULL) { -+ goto error; -+ } -+ Py_DECREF(res); -+ -+ stop = PyObject_GetAttrString(tracemalloc, "stop"); -+ Py_CLEAR(tracemalloc); -+ if (stop == NULL) { -+ goto error; -+ } -+ -+ // Start threads -+ for (size_t i = 0; i < NTHREAD; i++) { -+ PyThread_type_lock lock = PyThread_allocate_lock(); -+ if (!lock) { -+ PyErr_NoMemory(); -+ goto error; -+ } -+ locks[i] = lock; -+ PyThread_acquire_lock(lock, 1); -+ -+ unsigned long thread; -+ thread = PyThread_start_new_thread(tracemalloc_track_race_thread, -+ (void*)lock); -+ if (thread == (unsigned long)-1) { -+ PyErr_SetString(PyExc_RuntimeError, "can't start new thread"); -+ goto error; -+ } -+ } -+ -+ // Call tracemalloc.stop() while threads are running -+ res = PyObject_CallNoArgs(stop); -+ Py_CLEAR(stop); -+ if (res == NULL) { -+ goto error; -+ } -+ Py_DECREF(res); -+ -+ // Wait until threads complete with the GIL released -+ Py_BEGIN_ALLOW_THREADS -+ for (size_t i = 0; i < NTHREAD; i++) { -+ PyThread_type_lock lock = locks[i]; -+ PyThread_acquire_lock(lock, 1); -+ PyThread_release_lock(lock); -+ } -+ Py_END_ALLOW_THREADS -+ -+ // Free threads locks -+ for (size_t i=0; i < NTHREAD; i++) { -+ PyThread_type_lock lock = locks[i]; -+ PyThread_free_lock(lock); -+ } -+ Py_RETURN_NONE; -+ -+error: -+ Py_CLEAR(tracemalloc); -+ Py_CLEAR(stop); -+ for (size_t i=0; i < NTHREAD; i++) { -+ PyThread_type_lock lock = locks[i]; -+ if (lock) { -+ PyThread_free_lock(lock); -+ } -+ } -+ return NULL; -+#undef NTHREAD -+} -+ -+ - static PyMethodDef test_methods[] = { - {"pymem_api_misuse", pymem_api_misuse, METH_NOARGS}, - {"pymem_buffer_overflow", pymem_buffer_overflow, METH_NOARGS}, -@@ -593,6 +702,7 @@ - // Tracemalloc tests - {"tracemalloc_track", tracemalloc_track, METH_VARARGS}, - {"tracemalloc_untrack", tracemalloc_untrack, METH_VARARGS}, -+ {"tracemalloc_track_race", tracemalloc_track_race, METH_NOARGS}, - {NULL}, - }; - -diff --git a/Modules/_testcapi/monitoring.c b/Modules/_testcapi/monitoring.c -index 6fd4a405688..e475e3b5937 100644 ---- a/Modules/_testcapi/monitoring.c -+++ b/Modules/_testcapi/monitoring.c -@@ -286,7 +286,7 @@ - } - - static PyObject * --fire_event_branch(PyObject *self, PyObject *args) -+fire_event_branch_right(PyObject *self, PyObject *args) - { - PyObject *codelike; - int offset; -@@ -299,7 +299,25 @@ - if (state == NULL) { - return NULL; - } -- int res = PyMonitoring_FireBranchEvent(state, codelike, offset, target_offset); -+ int res = PyMonitoring_FireBranchRightEvent(state, codelike, offset, target_offset); -+ RETURN_INT(teardown_fire(res, state, exception)); -+} -+ -+static PyObject * -+fire_event_branch_left(PyObject *self, PyObject *args) -+{ -+ PyObject *codelike; -+ int offset; -+ PyObject *target_offset; -+ if (!PyArg_ParseTuple(args, "OiO", &codelike, &offset, &target_offset)) { -+ return NULL; -+ } -+ PyObject *exception = NULL; -+ PyMonitoringState *state = setup_fire(codelike, offset, exception); -+ if (state == NULL) { -+ return NULL; -+ } -+ int res = PyMonitoring_FireBranchLeftEvent(state, codelike, offset, target_offset); - RETURN_INT(teardown_fire(res, state, exception)); - } - -@@ -478,7 +496,8 @@ - {"fire_event_call", fire_event_call, METH_VARARGS}, - {"fire_event_line", fire_event_line, METH_VARARGS}, - {"fire_event_jump", fire_event_jump, METH_VARARGS}, -- {"fire_event_branch", fire_event_branch, METH_VARARGS}, -+ {"fire_event_branch_left", fire_event_branch_left, METH_VARARGS}, -+ {"fire_event_branch_right", fire_event_branch_right, METH_VARARGS}, - {"fire_event_py_throw", fire_event_py_throw, METH_VARARGS}, - {"fire_event_raise", fire_event_raise, METH_VARARGS}, - {"fire_event_c_raise", fire_event_c_raise, METH_VARARGS}, -diff --git a/Modules/_testcapi/object.c b/Modules/_testcapi/object.c -index 3af5429ef00..2d538627d21 100644 ---- a/Modules/_testcapi/object.c -+++ b/Modules/_testcapi/object.c -@@ -15,7 +15,7 @@ - return NULL; - } - -- fp = _Py_fopen_obj(filename, "w+"); -+ fp = Py_fopen(filename, "w+"); - - if (Py_IsTrue(print_raw)) { - flags = Py_PRINT_RAW; -@@ -41,7 +41,7 @@ - return NULL; - } - -- fp = _Py_fopen_obj(filename, "w+"); -+ fp = Py_fopen(filename, "w+"); - - if (PyObject_Print(NULL, fp, 0) < 0) { - fclose(fp); -@@ -72,7 +72,7 @@ - return NULL; - } - -- fp = _Py_fopen_obj(filename, "w+"); -+ fp = Py_fopen(filename, "w+"); - - if (PyObject_Print(test_string, fp, 0) < 0){ - fclose(fp); -@@ -103,7 +103,7 @@ - } - - // open file in read mode to induce OSError -- fp = _Py_fopen_obj(filename, "r"); -+ fp = Py_fopen(filename, "r"); - - if (PyObject_Print(test_string, fp, 0) < 0) { - fclose(fp); -@@ -131,6 +131,346 @@ - return PyLong_FromLong(result); - } - -+static int MyObject_dealloc_called = 0; -+ -+static void -+MyObject_dealloc(PyObject *op) -+{ -+ // PyUnstable_TryIncRef should return 0 if object is being deallocated -+ assert(Py_REFCNT(op) == 0); -+ assert(!PyUnstable_TryIncRef(op)); -+ assert(Py_REFCNT(op) == 0); -+ -+ MyObject_dealloc_called++; -+ Py_TYPE(op)->tp_free(op); -+} -+ -+static PyTypeObject MyType = { -+ PyVarObject_HEAD_INIT(NULL, 0) -+ .tp_name = "MyType", -+ .tp_basicsize = sizeof(PyObject), -+ .tp_dealloc = MyObject_dealloc, -+}; -+ -+static PyObject * -+test_py_try_inc_ref(PyObject *self, PyObject *unused) -+{ -+ if (PyType_Ready(&MyType) < 0) { -+ return NULL; -+ } -+ -+ MyObject_dealloc_called = 0; -+ -+ PyObject *op = PyObject_New(PyObject, &MyType); -+ if (op == NULL) { -+ return NULL; -+ } -+ -+ PyUnstable_EnableTryIncRef(op); -+#ifdef Py_GIL_DISABLED -+ // PyUnstable_EnableTryIncRef sets the shared flags to -+ // `_Py_REF_MAYBE_WEAKREF` if the flags are currently zero to ensure that -+ // the shared reference count is merged on deallocation. -+ assert((op->ob_ref_shared & _Py_REF_SHARED_FLAG_MASK) >= _Py_REF_MAYBE_WEAKREF); -+#endif -+ -+ if (!PyUnstable_TryIncRef(op)) { -+ PyErr_SetString(PyExc_AssertionError, "PyUnstable_TryIncRef failed"); -+ Py_DECREF(op); -+ return NULL; -+ } -+ Py_DECREF(op); // undo try-incref -+ Py_DECREF(op); // dealloc -+ assert(MyObject_dealloc_called == 1); -+ Py_RETURN_NONE; -+} -+ -+ -+static PyObject * -+_test_incref(PyObject *ob) -+{ -+ return Py_NewRef(ob); -+} -+ -+static PyObject * -+test_xincref_doesnt_leak(PyObject *ob, PyObject *Py_UNUSED(ignored)) -+{ -+ PyObject *obj = PyLong_FromLong(0); -+ Py_XINCREF(_test_incref(obj)); -+ Py_DECREF(obj); -+ Py_DECREF(obj); -+ Py_DECREF(obj); -+ Py_RETURN_NONE; -+} -+ -+ -+static PyObject * -+test_incref_doesnt_leak(PyObject *ob, PyObject *Py_UNUSED(ignored)) -+{ -+ PyObject *obj = PyLong_FromLong(0); -+ Py_INCREF(_test_incref(obj)); -+ Py_DECREF(obj); -+ Py_DECREF(obj); -+ Py_DECREF(obj); -+ Py_RETURN_NONE; -+} -+ -+ -+static PyObject * -+test_xdecref_doesnt_leak(PyObject *ob, PyObject *Py_UNUSED(ignored)) -+{ -+ Py_XDECREF(PyLong_FromLong(0)); -+ Py_RETURN_NONE; -+} -+ -+ -+static PyObject * -+test_decref_doesnt_leak(PyObject *ob, PyObject *Py_UNUSED(ignored)) -+{ -+ Py_DECREF(PyLong_FromLong(0)); -+ Py_RETURN_NONE; -+} -+ -+ -+static PyObject * -+test_incref_decref_API(PyObject *ob, PyObject *Py_UNUSED(ignored)) -+{ -+ PyObject *obj = PyLong_FromLong(0); -+ Py_IncRef(obj); -+ Py_DecRef(obj); -+ Py_DecRef(obj); -+ Py_RETURN_NONE; -+} -+ -+ -+#ifdef Py_REF_DEBUG -+static PyObject * -+negative_refcount(PyObject *self, PyObject *Py_UNUSED(args)) -+{ -+ PyObject *obj = PyUnicode_FromString("negative_refcount"); -+ if (obj == NULL) { -+ return NULL; -+ } -+ assert(Py_REFCNT(obj) == 1); -+ -+ Py_SET_REFCNT(obj, 0); -+ /* Py_DECREF() must call _Py_NegativeRefcount() and abort Python */ -+ Py_DECREF(obj); -+ -+ Py_RETURN_NONE; -+} -+ -+ -+static PyObject * -+decref_freed_object(PyObject *self, PyObject *Py_UNUSED(args)) -+{ -+ PyObject *obj = PyUnicode_FromString("decref_freed_object"); -+ if (obj == NULL) { -+ return NULL; -+ } -+ assert(Py_REFCNT(obj) == 1); -+ -+ // Deallocate the memory -+ Py_DECREF(obj); -+ // obj is a now a dangling pointer -+ -+ // gh-109496: If Python is built in debug mode, Py_DECREF() must call -+ // _Py_NegativeRefcount() and abort Python. -+ Py_DECREF(obj); -+ -+ Py_RETURN_NONE; -+} -+#endif -+ -+ -+// Test Py_CLEAR() macro -+static PyObject* -+test_py_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) -+{ -+ // simple case with a variable -+ PyObject *obj = PyList_New(0); -+ if (obj == NULL) { -+ return NULL; -+ } -+ Py_CLEAR(obj); -+ assert(obj == NULL); -+ -+ // gh-98724: complex case, Py_CLEAR() argument has a side effect -+ PyObject* array[1]; -+ array[0] = PyList_New(0); -+ if (array[0] == NULL) { -+ return NULL; -+ } -+ -+ PyObject **p = array; -+ Py_CLEAR(*p++); -+ assert(array[0] == NULL); -+ assert(p == array + 1); -+ -+ Py_RETURN_NONE; -+} -+ -+ -+// Test Py_SETREF() and Py_XSETREF() macros, similar to test_py_clear() -+static PyObject* -+test_py_setref(PyObject *self, PyObject *Py_UNUSED(ignored)) -+{ -+ // Py_SETREF() simple case with a variable -+ PyObject *obj = PyList_New(0); -+ if (obj == NULL) { -+ return NULL; -+ } -+ Py_SETREF(obj, NULL); -+ assert(obj == NULL); -+ -+ // Py_XSETREF() simple case with a variable -+ PyObject *obj2 = PyList_New(0); -+ if (obj2 == NULL) { -+ return NULL; -+ } -+ Py_XSETREF(obj2, NULL); -+ assert(obj2 == NULL); -+ // test Py_XSETREF() when the argument is NULL -+ Py_XSETREF(obj2, NULL); -+ assert(obj2 == NULL); -+ -+ // gh-98724: complex case, Py_SETREF() argument has a side effect -+ PyObject* array[1]; -+ array[0] = PyList_New(0); -+ if (array[0] == NULL) { -+ return NULL; -+ } -+ -+ PyObject **p = array; -+ Py_SETREF(*p++, NULL); -+ assert(array[0] == NULL); -+ assert(p == array + 1); -+ -+ // gh-98724: complex case, Py_XSETREF() argument has a side effect -+ PyObject* array2[1]; -+ array2[0] = PyList_New(0); -+ if (array2[0] == NULL) { -+ return NULL; -+ } -+ -+ PyObject **p2 = array2; -+ Py_XSETREF(*p2++, NULL); -+ assert(array2[0] == NULL); -+ assert(p2 == array2 + 1); -+ -+ // test Py_XSETREF() when the argument is NULL -+ p2 = array2; -+ Py_XSETREF(*p2++, NULL); -+ assert(array2[0] == NULL); -+ assert(p2 == array2 + 1); -+ -+ Py_RETURN_NONE; -+} -+ -+ -+#define TEST_REFCOUNT() \ -+ do { \ -+ PyObject *obj = PyList_New(0); \ -+ if (obj == NULL) { \ -+ return NULL; \ -+ } \ -+ assert(Py_REFCNT(obj) == 1); \ -+ \ -+ /* test Py_NewRef() */ \ -+ PyObject *ref = Py_NewRef(obj); \ -+ assert(ref == obj); \ -+ assert(Py_REFCNT(obj) == 2); \ -+ Py_DECREF(ref); \ -+ \ -+ /* test Py_XNewRef() */ \ -+ PyObject *xref = Py_XNewRef(obj); \ -+ assert(xref == obj); \ -+ assert(Py_REFCNT(obj) == 2); \ -+ Py_DECREF(xref); \ -+ \ -+ assert(Py_XNewRef(NULL) == NULL); \ -+ \ -+ Py_DECREF(obj); \ -+ Py_RETURN_NONE; \ -+ } while (0) -+ -+ -+// Test Py_NewRef() and Py_XNewRef() macros -+static PyObject* -+test_refcount_macros(PyObject *self, PyObject *Py_UNUSED(ignored)) -+{ -+ TEST_REFCOUNT(); -+} -+ -+#undef Py_NewRef -+#undef Py_XNewRef -+ -+// Test Py_NewRef() and Py_XNewRef() functions, after undefining macros. -+static PyObject* -+test_refcount_funcs(PyObject *self, PyObject *Py_UNUSED(ignored)) -+{ -+ TEST_REFCOUNT(); -+} -+ -+ -+// Test Py_Is() function -+#define TEST_PY_IS() \ -+ do { \ -+ PyObject *o_none = Py_None; \ -+ PyObject *o_true = Py_True; \ -+ PyObject *o_false = Py_False; \ -+ PyObject *obj = PyList_New(0); \ -+ if (obj == NULL) { \ -+ return NULL; \ -+ } \ -+ \ -+ /* test Py_Is() */ \ -+ assert(Py_Is(obj, obj)); \ -+ assert(!Py_Is(obj, o_none)); \ -+ \ -+ /* test Py_None */ \ -+ assert(Py_Is(o_none, o_none)); \ -+ assert(!Py_Is(obj, o_none)); \ -+ \ -+ /* test Py_True */ \ -+ assert(Py_Is(o_true, o_true)); \ -+ assert(!Py_Is(o_false, o_true)); \ -+ assert(!Py_Is(obj, o_true)); \ -+ \ -+ /* test Py_False */ \ -+ assert(Py_Is(o_false, o_false)); \ -+ assert(!Py_Is(o_true, o_false)); \ -+ assert(!Py_Is(obj, o_false)); \ -+ \ -+ Py_DECREF(obj); \ -+ Py_RETURN_NONE; \ -+ } while (0) -+ -+// Test Py_Is() macro -+static PyObject* -+test_py_is_macros(PyObject *self, PyObject *Py_UNUSED(ignored)) -+{ -+ TEST_PY_IS(); -+} -+ -+#undef Py_Is -+ -+// Test Py_Is() function, after undefining its macro. -+static PyObject* -+test_py_is_funcs(PyObject *self, PyObject *Py_UNUSED(ignored)) -+{ -+ TEST_PY_IS(); -+} -+ -+ -+static PyObject * -+clear_managed_dict(PyObject *self, PyObject *obj) -+{ -+ PyObject_ClearManagedDict(obj); -+ Py_RETURN_NONE; -+} -+ -+ - static PyMethodDef test_methods[] = { - {"call_pyobject_print", call_pyobject_print, METH_VARARGS}, - {"pyobject_print_null", pyobject_print_null, METH_VARARGS}, -@@ -138,15 +478,28 @@ - {"pyobject_print_os_error", pyobject_print_os_error, METH_VARARGS}, - {"pyobject_clear_weakrefs_no_callbacks", pyobject_clear_weakrefs_no_callbacks, METH_O}, - {"pyobject_enable_deferred_refcount", pyobject_enable_deferred_refcount, METH_O}, -+ {"test_py_try_inc_ref", test_py_try_inc_ref, METH_NOARGS}, -+ {"test_xincref_doesnt_leak",test_xincref_doesnt_leak, METH_NOARGS}, -+ {"test_incref_doesnt_leak", test_incref_doesnt_leak, METH_NOARGS}, -+ {"test_xdecref_doesnt_leak",test_xdecref_doesnt_leak, METH_NOARGS}, -+ {"test_decref_doesnt_leak", test_decref_doesnt_leak, METH_NOARGS}, -+ {"test_incref_decref_API", test_incref_decref_API, METH_NOARGS}, -+#ifdef Py_REF_DEBUG -+ {"negative_refcount", negative_refcount, METH_NOARGS}, -+ {"decref_freed_object", decref_freed_object, METH_NOARGS}, -+#endif -+ {"test_py_clear", test_py_clear, METH_NOARGS}, -+ {"test_py_setref", test_py_setref, METH_NOARGS}, -+ {"test_refcount_macros", test_refcount_macros, METH_NOARGS}, -+ {"test_refcount_funcs", test_refcount_funcs, METH_NOARGS}, -+ {"test_py_is_macros", test_py_is_macros, METH_NOARGS}, -+ {"test_py_is_funcs", test_py_is_funcs, METH_NOARGS}, -+ {"clear_managed_dict", clear_managed_dict, METH_O, NULL}, - {NULL}, - }; - - int - _PyTestCapi_Init_Object(PyObject *m) - { -- if (PyModule_AddFunctions(m, test_methods) < 0) { -- return -1; -- } -- -- return 0; -+ return PyModule_AddFunctions(m, test_methods); - } -diff --git a/Modules/_testcapi/parts.h b/Modules/_testcapi/parts.h -index 65ba77596c7..af6400162da 100644 ---- a/Modules/_testcapi/parts.h -+++ b/Modules/_testcapi/parts.h -@@ -61,5 +61,9 @@ - int _PyTestCapi_Init_Monitoring(PyObject *module); - int _PyTestCapi_Init_Object(PyObject *module); - int _PyTestCapi_Init_Config(PyObject *mod); -+int _PyTestCapi_Init_Import(PyObject *mod); -+int _PyTestCapi_Init_Frame(PyObject *mod); -+int _PyTestCapi_Init_Type(PyObject *mod); -+int _PyTestCapi_Init_Function(PyObject *mod); - - #endif // Py_TESTCAPI_PARTS_H -diff --git a/Modules/_testcapi/set.c b/Modules/_testcapi/set.c -index 31b52cee5e9..092715ab7d0 100644 ---- a/Modules/_testcapi/set.c -+++ b/Modules/_testcapi/set.c -@@ -8,18 +8,37 @@ - RETURN_SIZE(PySet_GET_SIZE(obj)); - } - -+ -+static PyObject* -+test_set_type_size(PyObject *self, PyObject *Py_UNUSED(ignored)) -+{ -+ PyObject *obj = PyList_New(0); -+ if (obj == NULL) { -+ return NULL; -+ } -+ -+ // Ensure that following tests don't modify the object, -+ // to ensure that Py_DECREF() will not crash. -+ assert(Py_TYPE(obj) == &PyList_Type); -+ assert(Py_SIZE(obj) == 0); -+ -+ // bpo-39573: Test Py_SET_TYPE() and Py_SET_SIZE() functions. -+ Py_SET_TYPE(obj, &PyList_Type); -+ Py_SET_SIZE(obj, 0); -+ -+ Py_DECREF(obj); -+ Py_RETURN_NONE; -+} -+ -+ - static PyMethodDef test_methods[] = { - {"set_get_size", set_get_size, METH_O}, -- -+ {"test_set_type_size", test_set_type_size, METH_NOARGS}, - {NULL}, - }; - - int - _PyTestCapi_Init_Set(PyObject *m) - { -- if (PyModule_AddFunctions(m, test_methods) < 0) { -- return -1; -- } -- -- return 0; -+ return PyModule_AddFunctions(m, test_methods); - } ---- /dev/null -+++ b/Modules/_testcapi/type.c -@@ -0,0 +1,251 @@ -+#include "parts.h" -+#include "util.h" -+ -+ -+static PyType_Slot HeapTypeNameType_slots[] = { -+ {0}, -+}; -+ -+static PyType_Spec HeapTypeNameType_Spec = { -+ .name = "_testcapi.HeapTypeNameType", -+ .basicsize = sizeof(PyObject), -+ .flags = Py_TPFLAGS_DEFAULT, -+ .slots = HeapTypeNameType_slots, -+}; -+ -+static PyObject * -+get_heaptype_for_name(PyObject *self, PyObject *Py_UNUSED(ignored)) -+{ -+ return PyType_FromSpec(&HeapTypeNameType_Spec); -+} -+ -+ -+static PyObject * -+get_type_name(PyObject *self, PyObject *type) -+{ -+ assert(PyType_Check(type)); -+ return PyType_GetName((PyTypeObject *)type); -+} -+ -+ -+static PyObject * -+get_type_qualname(PyObject *self, PyObject *type) -+{ -+ assert(PyType_Check(type)); -+ return PyType_GetQualName((PyTypeObject *)type); -+} -+ -+ -+static PyObject * -+get_type_fullyqualname(PyObject *self, PyObject *type) -+{ -+ assert(PyType_Check(type)); -+ return PyType_GetFullyQualifiedName((PyTypeObject *)type); -+} -+ -+ -+static PyObject * -+get_type_module_name(PyObject *self, PyObject *type) -+{ -+ assert(PyType_Check(type)); -+ return PyType_GetModuleName((PyTypeObject *)type); -+} -+ -+ -+static PyObject * -+test_get_type_dict(PyObject *self, PyObject *Py_UNUSED(ignored)) -+{ -+ /* Test for PyType_GetDict */ -+ -+ // Assert ints have a `to_bytes` method -+ PyObject *long_dict = PyType_GetDict(&PyLong_Type); -+ assert(long_dict); -+ assert(PyDict_GetItemString(long_dict, "to_bytes")); // borrowed ref -+ Py_DECREF(long_dict); -+ -+ // Make a new type, add an attribute to it and assert it's there -+ PyObject *HeapTypeNameType = PyType_FromSpec(&HeapTypeNameType_Spec); -+ assert(HeapTypeNameType); -+ assert(PyObject_SetAttrString( -+ HeapTypeNameType, "new_attr", Py_NewRef(Py_None)) >= 0); -+ PyObject *type_dict = PyType_GetDict((PyTypeObject*)HeapTypeNameType); -+ assert(type_dict); -+ assert(PyDict_GetItemString(type_dict, "new_attr")); // borrowed ref -+ Py_DECREF(HeapTypeNameType); -+ Py_DECREF(type_dict); -+ Py_RETURN_NONE; -+} -+ -+ -+static PyObject * -+test_get_statictype_slots(PyObject *self, PyObject *Py_UNUSED(ignored)) -+{ -+ newfunc tp_new = PyType_GetSlot(&PyLong_Type, Py_tp_new); -+ if (PyLong_Type.tp_new != tp_new) { -+ PyErr_SetString(PyExc_AssertionError, "mismatch: tp_new of long"); -+ return NULL; -+ } -+ -+ reprfunc tp_repr = PyType_GetSlot(&PyLong_Type, Py_tp_repr); -+ if (PyLong_Type.tp_repr != tp_repr) { -+ PyErr_SetString(PyExc_AssertionError, "mismatch: tp_repr of long"); -+ return NULL; -+ } -+ -+ ternaryfunc tp_call = PyType_GetSlot(&PyLong_Type, Py_tp_call); -+ if (tp_call != NULL) { -+ PyErr_SetString(PyExc_AssertionError, "mismatch: tp_call of long"); -+ return NULL; -+ } -+ -+ binaryfunc nb_add = PyType_GetSlot(&PyLong_Type, Py_nb_add); -+ if (PyLong_Type.tp_as_number->nb_add != nb_add) { -+ PyErr_SetString(PyExc_AssertionError, "mismatch: nb_add of long"); -+ return NULL; -+ } -+ -+ lenfunc mp_length = PyType_GetSlot(&PyLong_Type, Py_mp_length); -+ if (mp_length != NULL) { -+ PyErr_SetString(PyExc_AssertionError, "mismatch: mp_length of long"); -+ return NULL; -+ } -+ -+ void *over_value = PyType_GetSlot(&PyLong_Type, Py_bf_releasebuffer + 1); -+ if (over_value != NULL) { -+ PyErr_SetString(PyExc_AssertionError, "mismatch: max+1 of long"); -+ return NULL; -+ } -+ -+ tp_new = PyType_GetSlot(&PyLong_Type, 0); -+ if (tp_new != NULL) { -+ PyErr_SetString(PyExc_AssertionError, "mismatch: slot 0 of long"); -+ return NULL; -+ } -+ if (PyErr_ExceptionMatches(PyExc_SystemError)) { -+ // This is the right exception -+ PyErr_Clear(); -+ } -+ else { -+ return NULL; -+ } -+ -+ Py_RETURN_NONE; -+} -+ -+ -+// Get type->tp_version_tag -+static PyObject * -+type_get_version(PyObject *self, PyObject *type) -+{ -+ if (!PyType_Check(type)) { -+ PyErr_SetString(PyExc_TypeError, "argument must be a type"); -+ return NULL; -+ } -+ PyObject *res = PyLong_FromUnsignedLong( -+ ((PyTypeObject *)type)->tp_version_tag); -+ if (res == NULL) { -+ assert(PyErr_Occurred()); -+ return NULL; -+ } -+ return res; -+} -+ -+static PyObject * -+type_modified(PyObject *self, PyObject *arg) -+{ -+ if (!PyType_Check(arg)) { -+ PyErr_SetString(PyExc_TypeError, "argument must be a type"); -+ return NULL; -+ } -+ PyTypeObject *type = (PyTypeObject*)arg; -+ -+ PyType_Modified(type); -+ Py_RETURN_NONE; -+} -+ -+ -+static PyObject * -+type_assign_version(PyObject *self, PyObject *arg) -+{ -+ if (!PyType_Check(arg)) { -+ PyErr_SetString(PyExc_TypeError, "argument must be a type"); -+ return NULL; -+ } -+ PyTypeObject *type = (PyTypeObject*)arg; -+ -+ int res = PyUnstable_Type_AssignVersionTag(type); -+ return PyLong_FromLong(res); -+} -+ -+ -+static PyObject * -+type_get_tp_bases(PyObject *self, PyObject *arg) -+{ -+ if (!PyType_Check(arg)) { -+ PyErr_SetString(PyExc_TypeError, "argument must be a type"); -+ return NULL; -+ } -+ PyTypeObject *type = (PyTypeObject*)arg; -+ -+ PyObject *bases = type->tp_bases; -+ if (bases == NULL) { -+ Py_RETURN_NONE; -+ } -+ return Py_NewRef(bases); -+} -+ -+static PyObject * -+type_get_tp_mro(PyObject *self, PyObject *arg) -+{ -+ if (!PyType_Check(arg)) { -+ PyErr_SetString(PyExc_TypeError, "argument must be a type"); -+ return NULL; -+ } -+ PyTypeObject *type = (PyTypeObject*)arg; -+ -+ PyObject *mro = ((PyTypeObject *)type)->tp_mro; -+ if (mro == NULL) { -+ Py_RETURN_NONE; -+ } -+ return Py_NewRef(mro); -+} -+ -+ -+static PyObject * -+type_freeze(PyObject *module, PyObject *arg) -+{ -+ if (!PyType_Check(arg)) { -+ PyErr_SetString(PyExc_TypeError, "argument must be a type"); -+ return NULL; -+ } -+ PyTypeObject *type = (PyTypeObject*)arg; -+ -+ if (PyType_Freeze(type) < 0) { -+ return NULL; -+ } -+ Py_RETURN_NONE; -+} -+ -+ -+static PyMethodDef test_methods[] = { -+ {"get_heaptype_for_name", get_heaptype_for_name, METH_NOARGS}, -+ {"get_type_name", get_type_name, METH_O}, -+ {"get_type_qualname", get_type_qualname, METH_O}, -+ {"get_type_fullyqualname", get_type_fullyqualname, METH_O}, -+ {"get_type_module_name", get_type_module_name, METH_O}, -+ {"test_get_type_dict", test_get_type_dict, METH_NOARGS}, -+ {"test_get_statictype_slots", test_get_statictype_slots, METH_NOARGS}, -+ {"type_get_version", type_get_version, METH_O, PyDoc_STR("type->tp_version_tag")}, -+ {"type_modified", type_modified, METH_O, PyDoc_STR("PyType_Modified")}, -+ {"type_assign_version", type_assign_version, METH_O, PyDoc_STR("PyUnstable_Type_AssignVersionTag")}, -+ {"type_get_tp_bases", type_get_tp_bases, METH_O}, -+ {"type_get_tp_mro", type_get_tp_mro, METH_O}, -+ {"type_freeze", type_freeze, METH_O}, -+ {NULL}, -+}; -+ -+int -+_PyTestCapi_Init_Type(PyObject *m) -+{ -+ return PyModule_AddFunctions(m, test_methods); -+} -diff --git a/Modules/_testcapi/watchers.c b/Modules/_testcapi/watchers.c -index 321d3aeffb6..f7440769b95 100644 ---- a/Modules/_testcapi/watchers.c -+++ b/Modules/_testcapi/watchers.c -@@ -428,7 +428,8 @@ - PyObject *exc = PyErr_GetRaisedException(); - for (int i = 0; i < num_watchers; i++) { - if (PyCode_ClearWatcher(watcher_ids[i]) < 0) { -- PyErr_WriteUnraisable(Py_None); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "clearing code watcher"); - break; - } - } -@@ -609,7 +610,8 @@ - PyObject *exc = PyErr_GetRaisedException(); - for (int i = 0; i < num_watchers; i++) { - if (PyFunction_ClearWatcher(watcher_ids[i]) < 0) { -- PyErr_WriteUnraisable(Py_None); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "clearing function watcher"); - break; - } - } -@@ -755,7 +757,8 @@ - PyObject *exc = PyErr_GetRaisedException(); - for (int i = 0; i < num_watchers; i++) { - if (PyContext_ClearWatcher(watcher_ids[i]) < 0) { -- PyErr_WriteUnraisable(Py_None); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "clearing context watcher"); - break; - } - } -diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c -index 8d86b535eff..c84646ccf03 100644 ---- a/Modules/_testcapimodule.c -+++ b/Modules/_testcapimodule.c -@@ -163,124 +163,6 @@ - #endif - } - --static PyObject* --test_list_api(PyObject *self, PyObject *Py_UNUSED(ignored)) --{ -- PyObject* list; -- int i; -- -- /* SF bug 132008: PyList_Reverse segfaults */ --#define NLIST 30 -- list = PyList_New(NLIST); -- if (list == (PyObject*)NULL) -- return (PyObject*)NULL; -- /* list = range(NLIST) */ -- for (i = 0; i < NLIST; ++i) { -- PyObject* anint = PyLong_FromLong(i); -- if (anint == (PyObject*)NULL) { -- Py_DECREF(list); -- return (PyObject*)NULL; -- } -- PyList_SET_ITEM(list, i, anint); -- } -- /* list.reverse(), via PyList_Reverse() */ -- i = PyList_Reverse(list); /* should not blow up! */ -- if (i != 0) { -- Py_DECREF(list); -- return (PyObject*)NULL; -- } -- /* Check that list == range(29, -1, -1) now */ -- for (i = 0; i < NLIST; ++i) { -- PyObject* anint = PyList_GET_ITEM(list, i); -- if (PyLong_AS_LONG(anint) != NLIST-1-i) { -- PyErr_SetString(get_testerror(self), -- "test_list_api: reverse screwed up"); -- Py_DECREF(list); -- return (PyObject*)NULL; -- } -- } -- Py_DECREF(list); --#undef NLIST -- -- Py_RETURN_NONE; --} -- --static int --test_dict_inner(PyObject *self, int count) --{ -- Py_ssize_t pos = 0, iterations = 0; -- int i; -- PyObject *dict = PyDict_New(); -- PyObject *v, *k; -- -- if (dict == NULL) -- return -1; -- -- for (i = 0; i < count; i++) { -- v = PyLong_FromLong(i); -- if (v == NULL) { -- goto error; -- } -- if (PyDict_SetItem(dict, v, v) < 0) { -- Py_DECREF(v); -- goto error; -- } -- Py_DECREF(v); -- } -- -- k = v = UNINITIALIZED_PTR; -- while (PyDict_Next(dict, &pos, &k, &v)) { -- PyObject *o; -- iterations++; -- -- assert(k != UNINITIALIZED_PTR); -- assert(v != UNINITIALIZED_PTR); -- i = PyLong_AS_LONG(v) + 1; -- o = PyLong_FromLong(i); -- if (o == NULL) { -- goto error; -- } -- if (PyDict_SetItem(dict, k, o) < 0) { -- Py_DECREF(o); -- goto error; -- } -- Py_DECREF(o); -- k = v = UNINITIALIZED_PTR; -- } -- assert(k == UNINITIALIZED_PTR); -- assert(v == UNINITIALIZED_PTR); -- -- Py_DECREF(dict); -- -- if (iterations != count) { -- PyErr_SetString( -- get_testerror(self), -- "test_dict_iteration: dict iteration went wrong "); -- return -1; -- } else { -- return 0; -- } --error: -- Py_DECREF(dict); -- return -1; --} -- -- -- --static PyObject* --test_dict_iteration(PyObject* self, PyObject *Py_UNUSED(ignored)) --{ -- int i; -- -- for (i = 0; i < 200; i++) { -- if (test_dict_inner(self, i) < 0) { -- return NULL; -- } -- } -- -- Py_RETURN_NONE; --} -- - /* Issue #4701: Check that PyObject_Hash implicitly calls - * PyType_Ready if it hasn't already been called - */ -@@ -530,136 +412,6 @@ - } - - --static PyObject * --test_get_statictype_slots(PyObject *self, PyObject *Py_UNUSED(ignored)) --{ -- newfunc tp_new = PyType_GetSlot(&PyLong_Type, Py_tp_new); -- if (PyLong_Type.tp_new != tp_new) { -- PyErr_SetString(PyExc_AssertionError, "mismatch: tp_new of long"); -- return NULL; -- } -- -- reprfunc tp_repr = PyType_GetSlot(&PyLong_Type, Py_tp_repr); -- if (PyLong_Type.tp_repr != tp_repr) { -- PyErr_SetString(PyExc_AssertionError, "mismatch: tp_repr of long"); -- return NULL; -- } -- -- ternaryfunc tp_call = PyType_GetSlot(&PyLong_Type, Py_tp_call); -- if (tp_call != NULL) { -- PyErr_SetString(PyExc_AssertionError, "mismatch: tp_call of long"); -- return NULL; -- } -- -- binaryfunc nb_add = PyType_GetSlot(&PyLong_Type, Py_nb_add); -- if (PyLong_Type.tp_as_number->nb_add != nb_add) { -- PyErr_SetString(PyExc_AssertionError, "mismatch: nb_add of long"); -- return NULL; -- } -- -- lenfunc mp_length = PyType_GetSlot(&PyLong_Type, Py_mp_length); -- if (mp_length != NULL) { -- PyErr_SetString(PyExc_AssertionError, "mismatch: mp_length of long"); -- return NULL; -- } -- -- void *over_value = PyType_GetSlot(&PyLong_Type, Py_bf_releasebuffer + 1); -- if (over_value != NULL) { -- PyErr_SetString(PyExc_AssertionError, "mismatch: max+1 of long"); -- return NULL; -- } -- -- tp_new = PyType_GetSlot(&PyLong_Type, 0); -- if (tp_new != NULL) { -- PyErr_SetString(PyExc_AssertionError, "mismatch: slot 0 of long"); -- return NULL; -- } -- if (PyErr_ExceptionMatches(PyExc_SystemError)) { -- // This is the right exception -- PyErr_Clear(); -- } -- else { -- return NULL; -- } -- -- Py_RETURN_NONE; --} -- -- --static PyType_Slot HeapTypeNameType_slots[] = { -- {0}, --}; -- --static PyType_Spec HeapTypeNameType_Spec = { -- .name = "_testcapi.HeapTypeNameType", -- .basicsize = sizeof(PyObject), -- .flags = Py_TPFLAGS_DEFAULT, -- .slots = HeapTypeNameType_slots, --}; -- --static PyObject * --get_heaptype_for_name(PyObject *self, PyObject *Py_UNUSED(ignored)) --{ -- return PyType_FromSpec(&HeapTypeNameType_Spec); --} -- -- --static PyObject * --get_type_name(PyObject *self, PyObject *type) --{ -- assert(PyType_Check(type)); -- return PyType_GetName((PyTypeObject *)type); --} -- -- --static PyObject * --get_type_qualname(PyObject *self, PyObject *type) --{ -- assert(PyType_Check(type)); -- return PyType_GetQualName((PyTypeObject *)type); --} -- -- --static PyObject * --get_type_fullyqualname(PyObject *self, PyObject *type) --{ -- assert(PyType_Check(type)); -- return PyType_GetFullyQualifiedName((PyTypeObject *)type); --} -- -- --static PyObject * --get_type_module_name(PyObject *self, PyObject *type) --{ -- assert(PyType_Check(type)); -- return PyType_GetModuleName((PyTypeObject *)type); --} -- -- --static PyObject * --test_get_type_dict(PyObject *self, PyObject *Py_UNUSED(ignored)) --{ -- /* Test for PyType_GetDict */ -- -- // Assert ints have a `to_bytes` method -- PyObject *long_dict = PyType_GetDict(&PyLong_Type); -- assert(long_dict); -- assert(PyDict_GetItemString(long_dict, "to_bytes")); // borrowed ref -- Py_DECREF(long_dict); -- -- // Make a new type, add an attribute to it and assert it's there -- PyObject *HeapTypeNameType = PyType_FromSpec(&HeapTypeNameType_Spec); -- assert(HeapTypeNameType); -- assert(PyObject_SetAttrString( -- HeapTypeNameType, "new_attr", Py_NewRef(Py_None)) >= 0); -- PyObject *type_dict = PyType_GetDict((PyTypeObject*)HeapTypeNameType); -- assert(type_dict); -- assert(PyDict_GetItemString(type_dict, "new_attr")); // borrowed ref -- Py_DECREF(HeapTypeNameType); -- Py_DECREF(type_dict); -- Py_RETURN_NONE; --} -- - static PyObject * - pyobject_repr_from_null(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -@@ -885,61 +637,6 @@ - return PyLong_FromUnsignedLong((unsigned long)num_added); - } - --/* Test PyOS_string_to_double. */ --static PyObject * --test_string_to_double(PyObject *self, PyObject *Py_UNUSED(ignored)) { -- double result; -- const char *msg; -- --#define CHECK_STRING(STR, expected) \ -- do { \ -- result = PyOS_string_to_double(STR, NULL, NULL); \ -- if (result == -1.0 && PyErr_Occurred()) { \ -- return NULL; \ -- } \ -- if (result != (double)expected) { \ -- msg = "conversion of " STR " to float failed"; \ -- goto fail; \ -- } \ -- } while (0) -- --#define CHECK_INVALID(STR) \ -- do { \ -- result = PyOS_string_to_double(STR, NULL, NULL); \ -- if (result == -1.0 && PyErr_Occurred()) { \ -- if (PyErr_ExceptionMatches(PyExc_ValueError)) { \ -- PyErr_Clear(); \ -- } \ -- else { \ -- return NULL; \ -- } \ -- } \ -- else { \ -- msg = "conversion of " STR " didn't raise ValueError"; \ -- goto fail; \ -- } \ -- } while (0) -- -- CHECK_STRING("0.1", 0.1); -- CHECK_STRING("1.234", 1.234); -- CHECK_STRING("-1.35", -1.35); -- CHECK_STRING(".1e01", 1.0); -- CHECK_STRING("2.e-2", 0.02); -- -- CHECK_INVALID(" 0.1"); -- CHECK_INVALID("\t\n-3"); -- CHECK_INVALID(".123 "); -- CHECK_INVALID("3\n"); -- CHECK_INVALID("123abc"); -- -- Py_RETURN_NONE; -- fail: -- return raiseTestError(self, "test_string_to_double", msg); --#undef CHECK_STRING --#undef CHECK_INVALID --} -- -- - /* Coverage testing of capsule objects. */ - - static const char *capsule_name = "capsule name"; -@@ -1360,15 +1057,10 @@ - if (ret != -1 || match == 0) - goto error; - -- PyObject *mod_io = PyImport_ImportModule("_io"); -- if (mod_io == NULL) { -- return NULL; -- } -- - /* bytesiobuf_getbuffer() */ -- PyTypeObject *type = (PyTypeObject *)PyObject_GetAttrString( -- mod_io, "_BytesIOBuffer"); -- Py_DECREF(mod_io); -+ PyTypeObject *type = (PyTypeObject *)PyImport_ImportModuleAttrString( -+ "_io", -+ "_BytesIOBuffer"); - if (type == NULL) { - return NULL; - } -@@ -1521,48 +1213,6 @@ - NULL - }; - --static PyObject * --_test_incref(PyObject *ob) --{ -- return Py_NewRef(ob); --} -- --static PyObject * --test_xincref_doesnt_leak(PyObject *ob, PyObject *Py_UNUSED(ignored)) --{ -- PyObject *obj = PyLong_FromLong(0); -- Py_XINCREF(_test_incref(obj)); -- Py_DECREF(obj); -- Py_DECREF(obj); -- Py_DECREF(obj); -- Py_RETURN_NONE; --} -- --static PyObject * --test_incref_doesnt_leak(PyObject *ob, PyObject *Py_UNUSED(ignored)) --{ -- PyObject *obj = PyLong_FromLong(0); -- Py_INCREF(_test_incref(obj)); -- Py_DECREF(obj); -- Py_DECREF(obj); -- Py_DECREF(obj); -- Py_RETURN_NONE; --} -- --static PyObject * --test_xdecref_doesnt_leak(PyObject *ob, PyObject *Py_UNUSED(ignored)) --{ -- Py_XDECREF(PyLong_FromLong(0)); -- Py_RETURN_NONE; --} -- --static PyObject * --test_decref_doesnt_leak(PyObject *ob, PyObject *Py_UNUSED(ignored)) --{ -- Py_DECREF(PyLong_FromLong(0)); -- Py_RETURN_NONE; --} -- - static PyObject * - test_structseq_newtype_doesnt_leak(PyObject *Py_UNUSED(self), - PyObject *Py_UNUSED(args)) -@@ -1609,16 +1259,6 @@ - Py_RETURN_NONE; - } - --static PyObject * --test_incref_decref_API(PyObject *ob, PyObject *Py_UNUSED(ignored)) --{ -- PyObject *obj = PyLong_FromLong(0); -- Py_IncRef(obj); -- Py_DecRef(obj); -- Py_DecRef(obj); -- Py_RETURN_NONE; --} -- - typedef struct { - PyThread_type_lock start_event; - PyThread_type_lock exit_event; -@@ -1744,7 +1384,7 @@ - &value, &filename, &version)) - return NULL; - -- fp = _Py_fopen_obj(filename, "wb"); -+ fp = Py_fopen(filename, "wb"); - if (fp == NULL) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; -@@ -1769,7 +1409,7 @@ - &obj, &filename, &version)) - return NULL; - -- fp = _Py_fopen_obj(filename, "wb"); -+ fp = Py_fopen(filename, "wb"); - if (fp == NULL) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; -@@ -1793,7 +1433,7 @@ - if (!PyArg_ParseTuple(args, "O:pymarshal_read_short_from_file", &filename)) - return NULL; - -- fp = _Py_fopen_obj(filename, "rb"); -+ fp = Py_fopen(filename, "rb"); - if (fp == NULL) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; -@@ -1818,7 +1458,7 @@ - if (!PyArg_ParseTuple(args, "O:pymarshal_read_long_from_file", &filename)) - return NULL; - -- fp = _Py_fopen_obj(filename, "rb"); -+ fp = Py_fopen(filename, "rb"); - if (fp == NULL) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; -@@ -1840,7 +1480,7 @@ - if (!PyArg_ParseTuple(args, "O:pymarshal_read_last_object_from_file", &filename)) - return NULL; - -- FILE *fp = _Py_fopen_obj(filename, "rb"); -+ FILE *fp = Py_fopen(filename, "rb"); - if (fp == NULL) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; -@@ -1863,7 +1503,7 @@ - if (!PyArg_ParseTuple(args, "O:pymarshal_read_object_from_file", &filename)) - return NULL; - -- FILE *fp = _Py_fopen_obj(filename, "rb"); -+ FILE *fp = Py_fopen(filename, "rb"); - if (fp == NULL) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; -@@ -2036,45 +1676,6 @@ - } - - --#ifdef Py_REF_DEBUG --static PyObject * --negative_refcount(PyObject *self, PyObject *Py_UNUSED(args)) --{ -- PyObject *obj = PyUnicode_FromString("negative_refcount"); -- if (obj == NULL) { -- return NULL; -- } -- assert(Py_REFCNT(obj) == 1); -- -- Py_SET_REFCNT(obj, 0); -- /* Py_DECREF() must call _Py_NegativeRefcount() and abort Python */ -- Py_DECREF(obj); -- -- Py_RETURN_NONE; --} -- --static PyObject * --decref_freed_object(PyObject *self, PyObject *Py_UNUSED(args)) --{ -- PyObject *obj = PyUnicode_FromString("decref_freed_object"); -- if (obj == NULL) { -- return NULL; -- } -- assert(Py_REFCNT(obj) == 1); -- -- // Deallocate the memory -- Py_DECREF(obj); -- // obj is a now a dangling pointer -- -- // gh-109496: If Python is built in debug mode, Py_DECREF() must call -- // _Py_NegativeRefcount() and abort Python. -- Py_DECREF(obj); -- -- Py_RETURN_NONE; --} --#endif -- -- - /* Functions for testing C calling conventions (METH_*) are named meth_*, - * e.g. "meth_varargs" for METH_VARARGS. - * -@@ -2178,319 +1779,55 @@ - return PyNumber_ToBase(obj, base); - } - --static PyObject* --test_set_type_size(PyObject *self, PyObject *Py_UNUSED(ignored)) --{ -- PyObject *obj = PyList_New(0); -- if (obj == NULL) { -- return NULL; -+/* We only use 2 in test_capi/test_misc.py. */ -+#define NUM_BASIC_STATIC_TYPES 2 -+static PyTypeObject BasicStaticTypes[NUM_BASIC_STATIC_TYPES] = { -+#define INIT_BASIC_STATIC_TYPE \ -+ { \ -+ PyVarObject_HEAD_INIT(NULL, 0) \ -+ .tp_name = "BasicStaticType", \ -+ .tp_basicsize = sizeof(PyObject), \ - } -+ INIT_BASIC_STATIC_TYPE, -+ INIT_BASIC_STATIC_TYPE, -+#undef INIT_BASIC_STATIC_TYPE -+}; -+static int num_basic_static_types_used = 0; - -- // Ensure that following tests don't modify the object, -- // to ensure that Py_DECREF() will not crash. -- assert(Py_TYPE(obj) == &PyList_Type); -- assert(Py_SIZE(obj) == 0); -- -- // bpo-39573: Test Py_SET_TYPE() and Py_SET_SIZE() functions. -- Py_SET_TYPE(obj, &PyList_Type); -- Py_SET_SIZE(obj, 0); -- -- Py_DECREF(obj); -- Py_RETURN_NONE; --} -- -- --// Test Py_CLEAR() macro --static PyObject* --test_py_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) -+static PyObject * -+get_basic_static_type(PyObject *self, PyObject *args) - { -- // simple case with a variable -- PyObject *obj = PyList_New(0); -- if (obj == NULL) { -+ PyObject *base = NULL; -+ if (!PyArg_ParseTuple(args, "|O", &base)) { - return NULL; - } -- Py_CLEAR(obj); -- assert(obj == NULL); -+ assert(base == NULL || PyType_Check(base)); - -- // gh-98724: complex case, Py_CLEAR() argument has a side effect -- PyObject* array[1]; -- array[0] = PyList_New(0); -- if (array[0] == NULL) { -+ if(num_basic_static_types_used >= NUM_BASIC_STATIC_TYPES) { -+ PyErr_SetString(PyExc_RuntimeError, "no more available basic static types"); - return NULL; - } -+ PyTypeObject *cls = &BasicStaticTypes[num_basic_static_types_used++]; - -- PyObject **p = array; -- Py_CLEAR(*p++); -- assert(array[0] == NULL); -- assert(p == array + 1); -- -- Py_RETURN_NONE; -+ if (base != NULL) { -+ cls->tp_bases = PyTuple_Pack(1, base); -+ if (cls->tp_bases == NULL) { -+ return NULL; -+ } -+ cls->tp_base = (PyTypeObject *)Py_NewRef(base); -+ } -+ if (PyType_Ready(cls) < 0) { -+ Py_DECREF(cls->tp_bases); -+ Py_DECREF(cls->tp_base); -+ return NULL; -+ } -+ return (PyObject *)cls; - } - - --// Test Py_SETREF() and Py_XSETREF() macros, similar to test_py_clear() --static PyObject* --test_py_setref(PyObject *self, PyObject *Py_UNUSED(ignored)) --{ -- // Py_SETREF() simple case with a variable -- PyObject *obj = PyList_New(0); -- if (obj == NULL) { -- return NULL; -- } -- Py_SETREF(obj, NULL); -- assert(obj == NULL); -- -- // Py_XSETREF() simple case with a variable -- PyObject *obj2 = PyList_New(0); -- if (obj2 == NULL) { -- return NULL; -- } -- Py_XSETREF(obj2, NULL); -- assert(obj2 == NULL); -- // test Py_XSETREF() when the argument is NULL -- Py_XSETREF(obj2, NULL); -- assert(obj2 == NULL); -- -- // gh-98724: complex case, Py_SETREF() argument has a side effect -- PyObject* array[1]; -- array[0] = PyList_New(0); -- if (array[0] == NULL) { -- return NULL; -- } -- -- PyObject **p = array; -- Py_SETREF(*p++, NULL); -- assert(array[0] == NULL); -- assert(p == array + 1); -- -- // gh-98724: complex case, Py_XSETREF() argument has a side effect -- PyObject* array2[1]; -- array2[0] = PyList_New(0); -- if (array2[0] == NULL) { -- return NULL; -- } -- -- PyObject **p2 = array2; -- Py_XSETREF(*p2++, NULL); -- assert(array2[0] == NULL); -- assert(p2 == array2 + 1); -- -- // test Py_XSETREF() when the argument is NULL -- p2 = array2; -- Py_XSETREF(*p2++, NULL); -- assert(array2[0] == NULL); -- assert(p2 == array2 + 1); -- -- Py_RETURN_NONE; --} -- -- --#define TEST_REFCOUNT() \ -- do { \ -- PyObject *obj = PyList_New(0); \ -- if (obj == NULL) { \ -- return NULL; \ -- } \ -- assert(Py_REFCNT(obj) == 1); \ -- \ -- /* test Py_NewRef() */ \ -- PyObject *ref = Py_NewRef(obj); \ -- assert(ref == obj); \ -- assert(Py_REFCNT(obj) == 2); \ -- Py_DECREF(ref); \ -- \ -- /* test Py_XNewRef() */ \ -- PyObject *xref = Py_XNewRef(obj); \ -- assert(xref == obj); \ -- assert(Py_REFCNT(obj) == 2); \ -- Py_DECREF(xref); \ -- \ -- assert(Py_XNewRef(NULL) == NULL); \ -- \ -- Py_DECREF(obj); \ -- Py_RETURN_NONE; \ -- } while (0) -- -- --// Test Py_NewRef() and Py_XNewRef() macros --static PyObject* --test_refcount_macros(PyObject *self, PyObject *Py_UNUSED(ignored)) --{ -- TEST_REFCOUNT(); --} -- --#undef Py_NewRef --#undef Py_XNewRef -- --// Test Py_NewRef() and Py_XNewRef() functions, after undefining macros. --static PyObject* --test_refcount_funcs(PyObject *self, PyObject *Py_UNUSED(ignored)) --{ -- TEST_REFCOUNT(); --} -- -- --// Test Py_Is() function --#define TEST_PY_IS() \ -- do { \ -- PyObject *o_none = Py_None; \ -- PyObject *o_true = Py_True; \ -- PyObject *o_false = Py_False; \ -- PyObject *obj = PyList_New(0); \ -- if (obj == NULL) { \ -- return NULL; \ -- } \ -- \ -- /* test Py_Is() */ \ -- assert(Py_Is(obj, obj)); \ -- assert(!Py_Is(obj, o_none)); \ -- \ -- /* test Py_None */ \ -- assert(Py_Is(o_none, o_none)); \ -- assert(!Py_Is(obj, o_none)); \ -- \ -- /* test Py_True */ \ -- assert(Py_Is(o_true, o_true)); \ -- assert(!Py_Is(o_false, o_true)); \ -- assert(!Py_Is(obj, o_true)); \ -- \ -- /* test Py_False */ \ -- assert(Py_Is(o_false, o_false)); \ -- assert(!Py_Is(o_true, o_false)); \ -- assert(!Py_Is(obj, o_false)); \ -- \ -- Py_DECREF(obj); \ -- Py_RETURN_NONE; \ -- } while (0) -- --// Test Py_Is() macro --static PyObject* --test_py_is_macros(PyObject *self, PyObject *Py_UNUSED(ignored)) --{ -- TEST_PY_IS(); --} -- --#undef Py_Is -- --// Test Py_Is() function, after undefining its macro. --static PyObject* --test_py_is_funcs(PyObject *self, PyObject *Py_UNUSED(ignored)) --{ -- TEST_PY_IS(); --} -- -- --// type->tp_version_tag --static PyObject * --type_get_version(PyObject *self, PyObject *type) --{ -- if (!PyType_Check(type)) { -- PyErr_SetString(PyExc_TypeError, "argument must be a type"); -- return NULL; -- } -- PyObject *res = PyLong_FromUnsignedLong( -- ((PyTypeObject *)type)->tp_version_tag); -- if (res == NULL) { -- assert(PyErr_Occurred()); -- return NULL; -- } -- return res; --} -- --static PyObject * --type_modified(PyObject *self, PyObject *type) --{ -- if (!PyType_Check(type)) { -- PyErr_SetString(PyExc_TypeError, "argument must be a type"); -- return NULL; -- } -- PyType_Modified((PyTypeObject *)type); -- Py_RETURN_NONE; --} -- -- --static PyObject * --type_assign_version(PyObject *self, PyObject *type) --{ -- if (!PyType_Check(type)) { -- PyErr_SetString(PyExc_TypeError, "argument must be a type"); -- return NULL; -- } -- int res = PyUnstable_Type_AssignVersionTag((PyTypeObject *)type); -- return PyLong_FromLong(res); --} -- -- --static PyObject * --type_get_tp_bases(PyObject *self, PyObject *type) --{ -- PyObject *bases = ((PyTypeObject *)type)->tp_bases; -- if (bases == NULL) { -- Py_RETURN_NONE; -- } -- return Py_NewRef(bases); --} -- --static PyObject * --type_get_tp_mro(PyObject *self, PyObject *type) --{ -- PyObject *mro = ((PyTypeObject *)type)->tp_mro; -- if (mro == NULL) { -- Py_RETURN_NONE; -- } -- return Py_NewRef(mro); --} -- -- --/* We only use 2 in test_capi/test_misc.py. */ --#define NUM_BASIC_STATIC_TYPES 2 --static PyTypeObject BasicStaticTypes[NUM_BASIC_STATIC_TYPES] = { --#define INIT_BASIC_STATIC_TYPE \ -- { \ -- PyVarObject_HEAD_INIT(NULL, 0) \ -- .tp_name = "BasicStaticType", \ -- .tp_basicsize = sizeof(PyObject), \ -- } -- INIT_BASIC_STATIC_TYPE, -- INIT_BASIC_STATIC_TYPE, --#undef INIT_BASIC_STATIC_TYPE --}; --static int num_basic_static_types_used = 0; -- --static PyObject * --get_basic_static_type(PyObject *self, PyObject *args) --{ -- PyObject *base = NULL; -- if (!PyArg_ParseTuple(args, "|O", &base)) { -- return NULL; -- } -- assert(base == NULL || PyType_Check(base)); -- -- if(num_basic_static_types_used >= NUM_BASIC_STATIC_TYPES) { -- PyErr_SetString(PyExc_RuntimeError, "no more available basic static types"); -- return NULL; -- } -- PyTypeObject *cls = &BasicStaticTypes[num_basic_static_types_used++]; -- -- if (base != NULL) { -- cls->tp_bases = PyTuple_Pack(1, base); -- if (cls->tp_bases == NULL) { -- return NULL; -- } -- cls->tp_base = (PyTypeObject *)Py_NewRef(base); -- } -- if (PyType_Ready(cls) < 0) { -- Py_DECREF(cls->tp_bases); -- Py_DECREF(cls->tp_base); -- return NULL; -- } -- return (PyObject *)cls; --} -- -- --// Test PyThreadState C API --static PyObject * --test_tstate_capi(PyObject *self, PyObject *Py_UNUSED(args)) -+// Test PyThreadState C API -+static PyObject * -+test_tstate_capi(PyObject *self, PyObject *Py_UNUSED(args)) - { - // PyThreadState_Get() - PyThreadState *tstate = PyThreadState_Get(); -@@ -2533,109 +1870,6 @@ - Py_RETURN_NONE; - } - --static PyObject * --frame_getlocals(PyObject *self, PyObject *frame) --{ -- if (!PyFrame_Check(frame)) { -- PyErr_SetString(PyExc_TypeError, "argument must be a frame"); -- return NULL; -- } -- return PyFrame_GetLocals((PyFrameObject *)frame); --} -- --static PyObject * --frame_getglobals(PyObject *self, PyObject *frame) --{ -- if (!PyFrame_Check(frame)) { -- PyErr_SetString(PyExc_TypeError, "argument must be a frame"); -- return NULL; -- } -- return PyFrame_GetGlobals((PyFrameObject *)frame); --} -- --static PyObject * --frame_getgenerator(PyObject *self, PyObject *frame) --{ -- if (!PyFrame_Check(frame)) { -- PyErr_SetString(PyExc_TypeError, "argument must be a frame"); -- return NULL; -- } -- return PyFrame_GetGenerator((PyFrameObject *)frame); --} -- --static PyObject * --frame_getbuiltins(PyObject *self, PyObject *frame) --{ -- if (!PyFrame_Check(frame)) { -- PyErr_SetString(PyExc_TypeError, "argument must be a frame"); -- return NULL; -- } -- return PyFrame_GetBuiltins((PyFrameObject *)frame); --} -- --static PyObject * --frame_getlasti(PyObject *self, PyObject *frame) --{ -- if (!PyFrame_Check(frame)) { -- PyErr_SetString(PyExc_TypeError, "argument must be a frame"); -- return NULL; -- } -- int lasti = PyFrame_GetLasti((PyFrameObject *)frame); -- if (lasti < 0) { -- assert(lasti == -1); -- Py_RETURN_NONE; -- } -- return PyLong_FromLong(lasti); --} -- --static PyObject * --frame_new(PyObject *self, PyObject *args) --{ -- PyObject *code, *globals, *locals; -- if (!PyArg_ParseTuple(args, "OOO", &code, &globals, &locals)) { -- return NULL; -- } -- if (!PyCode_Check(code)) { -- PyErr_SetString(PyExc_TypeError, "argument must be a code object"); -- return NULL; -- } -- PyThreadState *tstate = PyThreadState_Get(); -- -- return (PyObject *)PyFrame_New(tstate, (PyCodeObject *)code, globals, locals); --} -- --static PyObject * --test_frame_getvar(PyObject *self, PyObject *args) --{ -- PyObject *frame, *name; -- if (!PyArg_ParseTuple(args, "OO", &frame, &name)) { -- return NULL; -- } -- if (!PyFrame_Check(frame)) { -- PyErr_SetString(PyExc_TypeError, "argument must be a frame"); -- return NULL; -- } -- -- return PyFrame_GetVar((PyFrameObject *)frame, name); --} -- --static PyObject * --test_frame_getvarstring(PyObject *self, PyObject *args) --{ -- PyObject *frame; -- const char *name; -- if (!PyArg_ParseTuple(args, "Oy", &frame, &name)) { -- return NULL; -- } -- if (!PyFrame_Check(frame)) { -- PyErr_SetString(PyExc_TypeError, "argument must be a frame"); -- return NULL; -- } -- -- return PyFrame_GetVarString((PyFrameObject *)frame, name); --} -- -- - static PyObject * - gen_get_code(PyObject *self, PyObject *gen) - { -@@ -2903,14 +2137,6 @@ - Py_RETURN_NONE; - } - --static PyObject * --clear_managed_dict(PyObject *self, PyObject *obj) --{ -- PyObject_ClearManagedDict(obj); -- Py_RETURN_NONE; --} -- -- - static PyObject * - test_macros(PyObject *self, PyObject *Py_UNUSED(args)) - { -@@ -2947,165 +2173,6 @@ - Py_RETURN_NONE; - } - --static PyObject * --function_get_code(PyObject *self, PyObject *func) --{ -- PyObject *code = PyFunction_GetCode(func); -- if (code != NULL) { -- return Py_NewRef(code); -- } else { -- return NULL; -- } --} -- --static PyObject * --function_get_globals(PyObject *self, PyObject *func) --{ -- PyObject *globals = PyFunction_GetGlobals(func); -- if (globals != NULL) { -- return Py_NewRef(globals); -- } else { -- return NULL; -- } --} -- --static PyObject * --function_get_module(PyObject *self, PyObject *func) --{ -- PyObject *module = PyFunction_GetModule(func); -- if (module != NULL) { -- return Py_NewRef(module); -- } else { -- return NULL; -- } --} -- --static PyObject * --function_get_defaults(PyObject *self, PyObject *func) --{ -- PyObject *defaults = PyFunction_GetDefaults(func); -- if (defaults != NULL) { -- return Py_NewRef(defaults); -- } else if (PyErr_Occurred()) { -- return NULL; -- } else { -- Py_RETURN_NONE; // This can happen when `defaults` are set to `None` -- } --} -- --static PyObject * --function_set_defaults(PyObject *self, PyObject *args) --{ -- PyObject *func = NULL, *defaults = NULL; -- if (!PyArg_ParseTuple(args, "OO", &func, &defaults)) { -- return NULL; -- } -- int result = PyFunction_SetDefaults(func, defaults); -- if (result == -1) -- return NULL; -- Py_RETURN_NONE; --} -- --static PyObject * --function_get_kw_defaults(PyObject *self, PyObject *func) --{ -- PyObject *defaults = PyFunction_GetKwDefaults(func); -- if (defaults != NULL) { -- return Py_NewRef(defaults); -- } else if (PyErr_Occurred()) { -- return NULL; -- } else { -- Py_RETURN_NONE; // This can happen when `kwdefaults` are set to `None` -- } --} -- --static PyObject * --function_set_kw_defaults(PyObject *self, PyObject *args) --{ -- PyObject *func = NULL, *defaults = NULL; -- if (!PyArg_ParseTuple(args, "OO", &func, &defaults)) { -- return NULL; -- } -- int result = PyFunction_SetKwDefaults(func, defaults); -- if (result == -1) -- return NULL; -- Py_RETURN_NONE; --} -- --static PyObject * --function_get_closure(PyObject *self, PyObject *func) --{ -- PyObject *closure = PyFunction_GetClosure(func); -- if (closure != NULL) { -- return Py_NewRef(closure); -- } else if (PyErr_Occurred()) { -- return NULL; -- } else { -- Py_RETURN_NONE; // This can happen when `closure` is set to `None` -- } --} -- --static PyObject * --function_set_closure(PyObject *self, PyObject *args) --{ -- PyObject *func = NULL, *closure = NULL; -- if (!PyArg_ParseTuple(args, "OO", &func, &closure)) { -- return NULL; -- } -- int result = PyFunction_SetClosure(func, closure); -- if (result == -1) { -- return NULL; -- } -- Py_RETURN_NONE; --} -- --static PyObject * --check_pyimport_addmodule(PyObject *self, PyObject *args) --{ -- const char *name; -- if (!PyArg_ParseTuple(args, "s", &name)) { -- return NULL; -- } -- -- // test PyImport_AddModuleRef() -- PyObject *module = PyImport_AddModuleRef(name); -- if (module == NULL) { -- return NULL; -- } -- assert(PyModule_Check(module)); -- // module is a strong reference -- -- // test PyImport_AddModule() -- PyObject *module2 = PyImport_AddModule(name); -- if (module2 == NULL) { -- goto error; -- } -- assert(PyModule_Check(module2)); -- assert(module2 == module); -- // module2 is a borrowed ref -- -- // test PyImport_AddModuleObject() -- PyObject *name_obj = PyUnicode_FromString(name); -- if (name_obj == NULL) { -- goto error; -- } -- PyObject *module3 = PyImport_AddModuleObject(name_obj); -- Py_DECREF(name_obj); -- if (module3 == NULL) { -- goto error; -- } -- assert(PyModule_Check(module3)); -- assert(module3 == module); -- // module3 is a borrowed ref -- -- return module; -- --error: -- Py_DECREF(module); -- return NULL; --} -- -- - static PyObject * - test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) - { -@@ -3144,6 +2211,7 @@ - PyObject *ref = UNINITIALIZED_PTR; - assert(PyWeakref_GetRef(weakref, &ref) == 1); - assert(ref == obj); -+ assert(!PyWeakref_IsDead(weakref)); - assert(Py_REFCNT(obj) == (refcnt + 1)); - Py_DECREF(ref); - -@@ -3159,6 +2227,8 @@ - assert(Py_REFCNT(obj) == 1); - Py_DECREF(obj); - -+ assert(PyWeakref_IsDead(weakref)); -+ - // test PyWeakref_GET_OBJECT(), reference is dead - assert(PyWeakref_GET_OBJECT(weakref) == Py_None); - -@@ -3181,6 +2251,12 @@ - PyErr_Clear(); - assert(ref == NULL); - -+ // test PyWeakRef_IsDead(), invalid type -+ assert(!PyErr_Occurred()); -+ assert(PyWeakref_IsDead(invalid_weakref) == -1); -+ assert(PyErr_ExceptionMatches(PyExc_TypeError)); -+ PyErr_Clear(); -+ - // test PyWeakref_GetObject(), invalid type - assert(PyWeakref_GetObject(invalid_weakref) == NULL); - assert(PyErr_ExceptionMatches(PyExc_SystemError)); -@@ -3193,6 +2269,11 @@ - assert(ref == NULL); - PyErr_Clear(); - -+ // test PyWeakref_IsDead(NULL) -+ assert(PyWeakref_IsDead(NULL) == -1); -+ assert(PyErr_ExceptionMatches(PyExc_SystemError)); -+ PyErr_Clear(); -+ - // test PyWeakref_GetObject(NULL) - assert(PyWeakref_GetObject(NULL) == NULL); - assert(PyErr_ExceptionMatches(PyExc_SystemError)); -@@ -3340,19 +2421,6 @@ - } - - --static PyObject * --type_freeze(PyObject *module, PyObject *args) --{ -- PyTypeObject *type; -- if (!PyArg_ParseTuple(args, "O!", &PyType_Type, &type)) { -- return NULL; -- } -- if (PyType_Freeze(type) < 0) { -- return NULL; -- } -- Py_RETURN_NONE; --} -- - struct atexit_data { - int called; - PyThreadState *tstate; -@@ -3401,26 +2469,39 @@ - Py_RETURN_NONE; - } - -+static PyObject* -+code_offset_to_line(PyObject* self, PyObject* const* args, Py_ssize_t nargsf) -+{ -+ Py_ssize_t nargs = _PyVectorcall_NARGS(nargsf); -+ if (nargs != 2) { -+ PyErr_SetString(PyExc_TypeError, "code_offset_to_line takes 2 arguments"); -+ return NULL; -+ } -+ int offset; -+ if (PyLong_AsInt32(args[1], &offset) < 0) { -+ return NULL; -+ } -+ PyCodeObject *code = (PyCodeObject *)args[0]; -+ if (!PyCode_Check(code)) { -+ PyErr_SetString(PyExc_TypeError, "first arg must be a code object"); -+ return NULL; -+ } -+ return PyLong_FromInt32(PyCode_Addr2Line(code, offset)); -+} -+ -+ - static PyMethodDef TestMethods[] = { - {"set_errno", set_errno, METH_VARARGS}, - {"test_config", test_config, METH_NOARGS}, - {"test_sizeof_c_types", test_sizeof_c_types, METH_NOARGS}, -- {"test_list_api", test_list_api, METH_NOARGS}, -- {"test_dict_iteration", test_dict_iteration, METH_NOARGS}, - {"test_lazy_hash_inheritance", test_lazy_hash_inheritance,METH_NOARGS}, -- {"test_xincref_doesnt_leak",test_xincref_doesnt_leak, METH_NOARGS}, -- {"test_incref_doesnt_leak", test_incref_doesnt_leak, METH_NOARGS}, -- {"test_xdecref_doesnt_leak",test_xdecref_doesnt_leak, METH_NOARGS}, -- {"test_decref_doesnt_leak", test_decref_doesnt_leak, METH_NOARGS}, - {"test_structseq_newtype_doesnt_leak", - test_structseq_newtype_doesnt_leak, METH_NOARGS}, - {"test_structseq_newtype_null_descr_doc", - test_structseq_newtype_null_descr_doc, METH_NOARGS}, -- {"test_incref_decref_API", test_incref_decref_API, METH_NOARGS}, - {"pyobject_repr_from_null", pyobject_repr_from_null, METH_NOARGS}, - {"pyobject_str_from_null", pyobject_str_from_null, METH_NOARGS}, - {"pyobject_bytes_from_null", pyobject_bytes_from_null, METH_NOARGS}, -- {"test_string_to_double", test_string_to_double, METH_NOARGS}, - {"test_capsule", (PyCFunction)test_capsule, METH_NOARGS}, - {"test_from_contiguous", (PyCFunction)test_from_contiguous, METH_NOARGS}, - #if (defined(__linux__) || defined(__FreeBSD__)) && defined(__GNUC__) -@@ -3431,13 +2512,6 @@ - {"py_buildvalue", py_buildvalue, METH_VARARGS}, - {"py_buildvalue_ints", py_buildvalue_ints, METH_VARARGS}, - {"test_buildvalue_N", test_buildvalue_N, METH_NOARGS}, -- {"test_get_statictype_slots", test_get_statictype_slots, METH_NOARGS}, -- {"get_heaptype_for_name", get_heaptype_for_name, METH_NOARGS}, -- {"get_type_name", get_type_name, METH_O}, -- {"get_type_qualname", get_type_qualname, METH_O}, -- {"get_type_fullyqualname", get_type_fullyqualname, METH_O}, -- {"get_type_module_name", get_type_module_name, METH_O}, -- {"test_get_type_dict", test_get_type_dict, METH_NOARGS}, - {"test_reftracer", test_reftracer, METH_NOARGS}, - {"_test_thread_state", test_thread_state, METH_VARARGS}, - {"gilstate_ensure_release", gilstate_ensure_release, METH_NOARGS}, -@@ -3486,10 +2560,6 @@ - #endif - {"test_pythread_tss_key_state", test_pythread_tss_key_state, METH_VARARGS}, - {"bad_get", bad_get, METH_VARARGS}, --#ifdef Py_REF_DEBUG -- {"negative_refcount", negative_refcount, METH_NOARGS}, -- {"decref_freed_object", decref_freed_object, METH_NOARGS}, --#endif - {"meth_varargs", meth_varargs, METH_VARARGS}, - {"meth_varargs_keywords", _PyCFunction_CAST(meth_varargs_keywords), METH_VARARGS|METH_KEYWORDS}, - {"meth_o", meth_o, METH_O}, -@@ -3498,51 +2568,20 @@ - {"meth_fastcall_keywords", _PyCFunction_CAST(meth_fastcall_keywords), METH_FASTCALL|METH_KEYWORDS}, - {"pycfunction_call", test_pycfunction_call, METH_VARARGS}, - {"pynumber_tobase", pynumber_tobase, METH_VARARGS}, -- {"test_set_type_size", test_set_type_size, METH_NOARGS}, -- {"test_py_clear", test_py_clear, METH_NOARGS}, -- {"test_py_setref", test_py_setref, METH_NOARGS}, -- {"test_refcount_macros", test_refcount_macros, METH_NOARGS}, -- {"test_refcount_funcs", test_refcount_funcs, METH_NOARGS}, -- {"test_py_is_macros", test_py_is_macros, METH_NOARGS}, -- {"test_py_is_funcs", test_py_is_funcs, METH_NOARGS}, -- {"type_get_version", type_get_version, METH_O, PyDoc_STR("type->tp_version_tag")}, -- {"type_modified", type_modified, METH_O, PyDoc_STR("PyType_Modified")}, -- {"type_assign_version", type_assign_version, METH_O, PyDoc_STR("PyUnstable_Type_AssignVersionTag")}, -- {"type_get_tp_bases", type_get_tp_bases, METH_O}, -- {"type_get_tp_mro", type_get_tp_mro, METH_O}, - {"get_basic_static_type", get_basic_static_type, METH_VARARGS, NULL}, - {"test_tstate_capi", test_tstate_capi, METH_NOARGS, NULL}, -- {"frame_getlocals", frame_getlocals, METH_O, NULL}, -- {"frame_getglobals", frame_getglobals, METH_O, NULL}, -- {"frame_getgenerator", frame_getgenerator, METH_O, NULL}, -- {"frame_getbuiltins", frame_getbuiltins, METH_O, NULL}, -- {"frame_getlasti", frame_getlasti, METH_O, NULL}, -- {"frame_new", frame_new, METH_VARARGS, NULL}, -- {"frame_getvar", test_frame_getvar, METH_VARARGS, NULL}, -- {"frame_getvarstring", test_frame_getvarstring, METH_VARARGS, NULL}, - {"gen_get_code", gen_get_code, METH_O, NULL}, - {"get_feature_macros", get_feature_macros, METH_NOARGS, NULL}, - {"test_code_api", test_code_api, METH_NOARGS, NULL}, - {"settrace_to_error", settrace_to_error, METH_O, NULL}, - {"settrace_to_record", settrace_to_record, METH_O, NULL}, - {"test_macros", test_macros, METH_NOARGS, NULL}, -- {"clear_managed_dict", clear_managed_dict, METH_O, NULL}, -- {"function_get_code", function_get_code, METH_O, NULL}, -- {"function_get_globals", function_get_globals, METH_O, NULL}, -- {"function_get_module", function_get_module, METH_O, NULL}, -- {"function_get_defaults", function_get_defaults, METH_O, NULL}, -- {"function_set_defaults", function_set_defaults, METH_VARARGS, NULL}, -- {"function_get_kw_defaults", function_get_kw_defaults, METH_O, NULL}, -- {"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL}, -- {"function_get_closure", function_get_closure, METH_O, NULL}, -- {"function_set_closure", function_set_closure, METH_VARARGS, NULL}, -- {"check_pyimport_addmodule", check_pyimport_addmodule, METH_VARARGS}, - {"test_weakref_capi", test_weakref_capi, METH_NOARGS}, - {"function_set_warning", function_set_warning, METH_NOARGS}, - {"test_critical_sections", test_critical_sections, METH_NOARGS}, - {"finalize_thread_hang", finalize_thread_hang, METH_O, NULL}, -- {"type_freeze", type_freeze, METH_VARARGS}, - {"test_atexit", test_atexit, METH_NOARGS}, -+ {"code_offset_to_line", _PyCFunction_CAST(code_offset_to_line), METH_FASTCALL}, - {NULL, NULL} /* sentinel */ - }; - -@@ -4015,6 +3054,61 @@ - .tp_new = ContainerNoGC_new, - }; - -+/* Manually allocated heap type */ -+ -+typedef struct { -+ PyObject_HEAD -+ PyObject *dict; -+} ManualHeapType; -+ -+static int -+ManualHeapType_traverse(PyObject *self, visitproc visit, void *arg) -+{ -+ ManualHeapType *mht = (ManualHeapType *)self; -+ Py_VISIT(mht->dict); -+ return 0; -+} -+ -+static void -+ManualHeapType_dealloc(PyObject *self) -+{ -+ ManualHeapType *mht = (ManualHeapType *)self; -+ PyObject_GC_UnTrack(self); -+ Py_XDECREF(mht->dict); -+ PyTypeObject *type = Py_TYPE(self); -+ Py_TYPE(self)->tp_free(self); -+ Py_DECREF(type); -+} -+ -+static PyObject * -+create_manual_heap_type(void) -+{ -+ // gh-128923: Ensure that a heap type allocated through PyType_Type.tp_alloc -+ // with minimal initialization works correctly. -+ PyHeapTypeObject *heap_type = (PyHeapTypeObject *)PyType_Type.tp_alloc(&PyType_Type, 0); -+ if (heap_type == NULL) { -+ return NULL; -+ } -+ PyTypeObject* type = &heap_type->ht_type; -+ type->tp_basicsize = sizeof(ManualHeapType); -+ type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE | Py_TPFLAGS_HAVE_GC; -+ type->tp_new = PyType_GenericNew; -+ type->tp_name = "ManualHeapType"; -+ type->tp_dictoffset = offsetof(ManualHeapType, dict); -+ type->tp_traverse = ManualHeapType_traverse; -+ type->tp_dealloc = ManualHeapType_dealloc; -+ heap_type->ht_name = PyUnicode_FromString(type->tp_name); -+ if (!heap_type->ht_name) { -+ Py_DECREF(type); -+ return NULL; -+ } -+ heap_type->ht_qualname = Py_NewRef(heap_type->ht_name); -+ if (PyType_Ready(type) < 0) { -+ Py_DECREF(type); -+ return NULL; -+ } -+ return (PyObject *)type; -+} - - static struct PyModuleDef _testcapimodule = { - PyModuleDef_HEAD_INIT, -@@ -4149,6 +3243,15 @@ - (PyObject *) &ContainerNoGC_type) < 0) - return NULL; - -+ PyObject *manual_heap_type = create_manual_heap_type(); -+ if (manual_heap_type == NULL) { -+ return NULL; -+ } -+ if (PyModule_Add(m, "ManualHeapType", manual_heap_type) < 0) { -+ return NULL; -+ } -+ -+ - /* Include tests from the _testcapi/ directory */ - if (_PyTestCapi_Init_Vectorcall(m) < 0) { - return NULL; -@@ -4249,6 +3352,18 @@ - if (_PyTestCapi_Init_Config(m) < 0) { - return NULL; - } -+ if (_PyTestCapi_Init_Import(m) < 0) { -+ return NULL; -+ } -+ if (_PyTestCapi_Init_Frame(m) < 0) { -+ return NULL; -+ } -+ if (_PyTestCapi_Init_Type(m) < 0) { -+ return NULL; -+ } -+ if (_PyTestCapi_Init_Function(m) < 0) { -+ return NULL; -+ } - - PyState_AddModule(m, &_testcapimodule); - return m; -diff --git a/Modules/_testexternalinspection.c b/Modules/_testexternalinspection.c -index 0807d1e47b6..22074c81b74 100644 ---- a/Modules/_testexternalinspection.c -+++ b/Modules/_testexternalinspection.c -@@ -59,10 +59,30 @@ - # define HAVE_PROCESS_VM_READV 0 - #endif - -+struct _Py_AsyncioModuleDebugOffsets { -+ struct _asyncio_task_object { -+ uint64_t size; -+ uint64_t task_name; -+ uint64_t task_awaited_by; -+ uint64_t task_is_task; -+ uint64_t task_awaited_by_is_set; -+ uint64_t task_coro; -+ } asyncio_task_object; -+ struct _asyncio_thread_state { -+ uint64_t size; -+ uint64_t asyncio_running_loop; -+ uint64_t asyncio_running_task; -+ } asyncio_thread_state; -+}; -+ - #if defined(__APPLE__) && TARGET_OS_OSX --static void* --analyze_macho64(mach_port_t proc_ref, void* base, void* map) --{ -+static uintptr_t -+return_section_address( -+ const char* section, -+ mach_port_t proc_ref, -+ uintptr_t base, -+ void* map -+) { - struct mach_header_64* hdr = (struct mach_header_64*)map; - int ncmds = hdr->ncmds; - -@@ -72,35 +92,40 @@ - mach_vm_size_t size = 0; - mach_msg_type_number_t count = sizeof(vm_region_basic_info_data_64_t); - mach_vm_address_t address = (mach_vm_address_t)base; -- vm_region_basic_info_data_64_t region_info; -+ vm_region_basic_info_data_64_t r_info; - mach_port_t object_name; -+ uintptr_t vmaddr = 0; - - for (int i = 0; cmd_cnt < 2 && i < ncmds; i++) { -+ if (cmd->cmd == LC_SEGMENT_64 && strcmp(cmd->segname, "__TEXT") == 0) { -+ vmaddr = cmd->vmaddr; -+ } - if (cmd->cmd == LC_SEGMENT_64 && strcmp(cmd->segname, "__DATA") == 0) { - while (cmd->filesize != size) { - address += size; -- if (mach_vm_region( -- proc_ref, -- &address, -- &size, -- VM_REGION_BASIC_INFO_64, -- (vm_region_info_t)®ion_info, // cppcheck-suppress [uninitvar] -- &count, -- &object_name) -- != KERN_SUCCESS) -- { -- PyErr_SetString(PyExc_RuntimeError, "Cannot get any more VM maps.\n"); -- return NULL; -+ kern_return_t ret = mach_vm_region( -+ proc_ref, -+ &address, -+ &size, -+ VM_REGION_BASIC_INFO_64, -+ (vm_region_info_t)&r_info, // cppcheck-suppress [uninitvar] -+ &count, -+ &object_name -+ ); -+ if (ret != KERN_SUCCESS) { -+ PyErr_SetString( -+ PyExc_RuntimeError, "Cannot get any more VM maps.\n"); -+ return 0; - } - } -- base = (void*)address - cmd->vmaddr; - - int nsects = cmd->nsects; -- struct section_64* sec = -- (struct section_64*)((void*)cmd + sizeof(struct segment_command_64)); -+ struct section_64* sec = (struct section_64*)( -+ (void*)cmd + sizeof(struct segment_command_64) -+ ); - for (int j = 0; j < nsects; j++) { -- if (strcmp(sec[j].sectname, "PyRuntime") == 0) { -- return base + sec[j].addr; -+ if (strcmp(sec[j].sectname, section) == 0) { -+ return base + sec[j].addr - vmaddr; - } - } - cmd_cnt++; -@@ -108,33 +133,39 @@ - - cmd = (struct segment_command_64*)((void*)cmd + cmd->cmdsize); - } -- return NULL; -+ return 0; - } - --static void* --analyze_macho(char* path, void* base, mach_vm_size_t size, mach_port_t proc_ref) --{ -+static uintptr_t -+search_section_in_file( -+ const char* secname, -+ char* path, -+ uintptr_t base, -+ mach_vm_size_t size, -+ mach_port_t proc_ref -+) { - int fd = open(path, O_RDONLY); - if (fd == -1) { - PyErr_Format(PyExc_RuntimeError, "Cannot open binary %s\n", path); -- return NULL; -+ return 0; - } - - struct stat fs; - if (fstat(fd, &fs) == -1) { -- PyErr_Format(PyExc_RuntimeError, "Cannot get size of binary %s\n", path); -+ PyErr_Format( -+ PyExc_RuntimeError, "Cannot get size of binary %s\n", path); - close(fd); -- return NULL; -+ return 0; - } - - void* map = mmap(0, fs.st_size, PROT_READ, MAP_SHARED, fd, 0); - if (map == MAP_FAILED) { - PyErr_Format(PyExc_RuntimeError, "Cannot map binary %s\n", path); - close(fd); -- return NULL; -+ return 0; - } - -- void* result = NULL; -+ uintptr_t result = 0; - - struct mach_header_64* hdr = (struct mach_header_64*)map; - switch (hdr->magic) { -@@ -142,11 +173,13 @@ - case MH_CIGAM: - case FAT_MAGIC: - case FAT_CIGAM: -- PyErr_SetString(PyExc_RuntimeError, "32-bit Mach-O binaries are not supported"); -+ PyErr_SetString( -+ PyExc_RuntimeError, -+ "32-bit Mach-O binaries are not supported"); - break; - case MH_MAGIC_64: - case MH_CIGAM_64: -- result = analyze_macho64(proc_ref, base, map); -+ result = return_section_address(secname, proc_ref, base, map); - break; - default: - PyErr_SetString(PyExc_RuntimeError, "Unknown Mach-O magic"); -@@ -174,9 +207,8 @@ - return task; - } - --static void* --get_py_runtime_macos(pid_t pid) --{ -+static uintptr_t -+search_map_for_section(pid_t pid, const char* secname, const char* substr) { - mach_vm_address_t address = 0; - mach_vm_size_t size = 0; - mach_msg_type_number_t count = sizeof(vm_region_basic_info_data_64_t); -@@ -186,12 +218,11 @@ - mach_port_t proc_ref = pid_to_task(pid); - if (proc_ref == 0) { - PyErr_SetString(PyExc_PermissionError, "Cannot get task for PID"); -- return NULL; -+ return 0; - } - - int match_found = 0; - char map_filename[MAXPATHLEN + 1]; -- void* result_address = NULL; - while (mach_vm_region( - proc_ref, - &address, -@@ -199,10 +230,16 @@ - VM_REGION_BASIC_INFO_64, - (vm_region_info_t)®ion_info, - &count, -- &object_name) -- == KERN_SUCCESS) -+ &object_name) == KERN_SUCCESS) - { -- int path_len = proc_regionfilename(pid, address, map_filename, MAXPATHLEN); -+ if ((region_info.protection & VM_PROT_READ) == 0 -+ || (region_info.protection & VM_PROT_EXECUTE) == 0) { -+ address += size; -+ continue; -+ } -+ -+ int path_len = proc_regionfilename( -+ pid, address, map_filename, MAXPATHLEN); - if (path_len == 0) { - address += size; - continue; -@@ -215,26 +252,20 @@ - filename = map_filename; // No path, use the whole string - } - -- // Check if the filename starts with "python" or "libpython" -- if (!match_found && strncmp(filename, "python", 6) == 0) { -- match_found = 1; -- result_address = analyze_macho(map_filename, (void*)address, size, proc_ref); -- } -- if (strncmp(filename, "libpython", 9) == 0) { -+ if (!match_found && strncmp(filename, substr, strlen(substr)) == 0) { - match_found = 1; -- result_address = analyze_macho(map_filename, (void*)address, size, proc_ref); -- break; -+ return search_section_in_file( -+ secname, map_filename, address, size, proc_ref); - } - - address += size; - } -- return result_address; -+ return 0; - } --#endif - --#ifdef __linux__ --void* --find_python_map_start_address(pid_t pid, char* result_filename) -+#elif defined(__linux__) -+static uintptr_t -+find_map_start_address(pid_t pid, char* result_filename, const char* map) - { - char maps_file_path[64]; - sprintf(maps_file_path, "/proc/%d/maps", pid); -@@ -242,17 +273,20 @@ - FILE* maps_file = fopen(maps_file_path, "r"); - if (maps_file == NULL) { - PyErr_SetFromErrno(PyExc_OSError); -- return NULL; -+ return 0; - } - - int match_found = 0; - - char line[256]; - char map_filename[PATH_MAX]; -- void* result_address = 0; -+ uintptr_t result_address = 0; - while (fgets(line, sizeof(line), maps_file) != NULL) { - unsigned long start_address = 0; -- sscanf(line, "%lx-%*x %*s %*s %*s %*s %s", &start_address, map_filename); -+ sscanf( -+ line, "%lx-%*x %*s %*s %*s %*s %s", -+ &start_address, map_filename -+ ); - char* filename = strrchr(map_filename, '/'); - if (filename != NULL) { - filename++; // Move past the '/' -@@ -260,15 +294,9 @@ - filename = map_filename; // No path, use the whole string - } - -- // Check if the filename starts with "python" or "libpython" -- if (!match_found && strncmp(filename, "python", 6) == 0) { -- match_found = 1; -- result_address = (void*)start_address; -- strcpy(result_filename, map_filename); -- } -- if (strncmp(filename, "libpython", 9) == 0) { -+ if (!match_found && strncmp(filename, map, strlen(map)) == 0) { - match_found = 1; -- result_address = (void*)start_address; -+ result_address = start_address; - strcpy(result_filename, map_filename); - break; - } -@@ -283,18 +311,17 @@ - return result_address; - } - --void* --get_py_runtime_linux(pid_t pid) -+static uintptr_t -+search_map_for_section(pid_t pid, const char* secname, const char* map) - { - char elf_file[256]; -- void* start_address = (void*)find_python_map_start_address(pid, elf_file); -+ uintptr_t start_address = find_map_start_address(pid, elf_file, map); - - if (start_address == 0) { -- PyErr_SetString(PyExc_RuntimeError, "No memory map associated with python or libpython found"); -- return NULL; -+ return 0; - } - -- void* result = NULL; -+ uintptr_t result = 0; - void* file_memory = NULL; - - int fd = open(elf_file, O_RDONLY); -@@ -317,20 +344,29 @@ - - Elf_Ehdr* elf_header = (Elf_Ehdr*)file_memory; - -- Elf_Shdr* section_header_table = (Elf_Shdr*)(file_memory + elf_header->e_shoff); -+ Elf_Shdr* section_header_table = -+ (Elf_Shdr*)(file_memory + elf_header->e_shoff); - - Elf_Shdr* shstrtab_section = §ion_header_table[elf_header->e_shstrndx]; - char* shstrtab = (char*)(file_memory + shstrtab_section->sh_offset); - -- Elf_Shdr* py_runtime_section = NULL; -+ Elf_Shdr* section = NULL; - for (int i = 0; i < elf_header->e_shnum; i++) { -- if (strcmp(".PyRuntime", shstrtab + section_header_table[i].sh_name) == 0) { -- py_runtime_section = §ion_header_table[i]; -+ const char* this_sec_name = ( -+ shstrtab + -+ section_header_table[i].sh_name + -+ 1 // "+1" accounts for the leading "." -+ ); -+ -+ if (strcmp(secname, this_sec_name) == 0) { -+ section = §ion_header_table[i]; - break; - } - } - -- Elf_Phdr* program_header_table = (Elf_Phdr*)(file_memory + elf_header->e_phoff); -+ Elf_Phdr* program_header_table = -+ (Elf_Phdr*)(file_memory + elf_header->e_phoff); -+ - // Find the first PT_LOAD segment - Elf_Phdr* first_load_segment = NULL; - for (int i = 0; i < elf_header->e_phnum; i++) { -@@ -340,10 +376,16 @@ - } - } - -- if (py_runtime_section != NULL && first_load_segment != NULL) { -- uintptr_t elf_load_addr = first_load_segment->p_vaddr -- - (first_load_segment->p_vaddr % first_load_segment->p_align); -- result = start_address + py_runtime_section->sh_addr - elf_load_addr; -+ if (section != NULL && first_load_segment != NULL) { -+ uintptr_t elf_load_addr = -+ first_load_segment->p_vaddr - ( -+ first_load_segment->p_vaddr % first_load_segment->p_align -+ ); -+ result = start_address + (uintptr_t)section->sh_addr - elf_load_addr; -+ } -+ else { -+ PyErr_Format(PyExc_KeyError, -+ "cannot find map for section %s", secname); - } - - exit: -@@ -355,10 +397,37 @@ - } - return result; - } -+#else -+static uintptr_t -+search_map_for_section(pid_t pid, const char* secname, const char* map) -+{ -+ return 0; -+} - #endif - --ssize_t --read_memory(pid_t pid, void* remote_address, size_t len, void* dst) -+static uintptr_t -+get_py_runtime(pid_t pid) -+{ -+ uintptr_t address = search_map_for_section(pid, "PyRuntime", "libpython"); -+ if (address == 0) { -+ address = search_map_for_section(pid, "PyRuntime", "python"); -+ } -+ return address; -+} -+ -+static uintptr_t -+get_async_debug(pid_t pid) -+{ -+ uintptr_t result = search_map_for_section(pid, "AsyncioDebug", "_asyncio.cpython"); -+ if (result == 0 && !PyErr_Occurred()) { -+ PyErr_SetString(PyExc_RuntimeError, "Cannot find AsyncioDebug section"); -+ } -+ return result; -+} -+ -+ -+static ssize_t -+read_memory(pid_t pid, uintptr_t remote_address, size_t len, void* dst) - { - ssize_t total_bytes_read = 0; - #if defined(__linux__) && HAVE_PROCESS_VM_READV -@@ -394,13 +463,19 @@ - if (kr != KERN_SUCCESS) { - switch (kr) { - case KERN_PROTECTION_FAILURE: -- PyErr_SetString(PyExc_PermissionError, "Not enough permissions to read memory"); -+ PyErr_SetString( -+ PyExc_PermissionError, -+ "Not enough permissions to read memory"); - break; - case KERN_INVALID_ARGUMENT: -- PyErr_SetString(PyExc_PermissionError, "Invalid argument to mach_vm_read_overwrite"); -+ PyErr_SetString( -+ PyExc_PermissionError, -+ "Invalid argument to mach_vm_read_overwrite"); - break; - default: -- PyErr_SetString(PyExc_RuntimeError, "Unknown error reading memory"); -+ PyErr_SetString( -+ PyExc_RuntimeError, -+ "Unknown error reading memory"); - } - return -1; - } -@@ -411,13 +486,22 @@ - return total_bytes_read; - } - --int --read_string(pid_t pid, _Py_DebugOffsets* debug_offsets, void* address, char* buffer, Py_ssize_t size) --{ -+static int -+read_string( -+ pid_t pid, -+ _Py_DebugOffsets* debug_offsets, -+ uintptr_t address, -+ char* buffer, -+ Py_ssize_t size -+) { - Py_ssize_t len; -- ssize_t bytes_read = -- read_memory(pid, address + debug_offsets->unicode_object.length, sizeof(Py_ssize_t), &len); -- if (bytes_read == -1) { -+ ssize_t bytes_read = read_memory( -+ pid, -+ address + debug_offsets->unicode_object.length, -+ sizeof(Py_ssize_t), -+ &len -+ ); -+ if (bytes_read < 0) { - return -1; - } - if (len >= size) { -@@ -426,51 +510,652 @@ - } - size_t offset = debug_offsets->unicode_object.asciiobject_size; - bytes_read = read_memory(pid, address + offset, len, buffer); -- if (bytes_read == -1) { -+ if (bytes_read < 0) { - return -1; - } - buffer[len] = '\0'; - return 0; - } - --void* --get_py_runtime(pid_t pid) -+ -+static inline int -+read_ptr(pid_t pid, uintptr_t address, uintptr_t *ptr_addr) - { --#if defined(__linux__) -- return get_py_runtime_linux(pid); --#elif defined(__APPLE__) && TARGET_OS_OSX -- return get_py_runtime_macos(pid); --#else -- return NULL; --#endif -+ int bytes_read = read_memory(pid, address, sizeof(void*), ptr_addr); -+ if (bytes_read < 0) { -+ return -1; -+ } -+ return 0; -+} -+ -+static inline int -+read_ssize_t(pid_t pid, uintptr_t address, Py_ssize_t *size) -+{ -+ int bytes_read = read_memory(pid, address, sizeof(Py_ssize_t), size); -+ if (bytes_read < 0) { -+ return -1; -+ } -+ return 0; - } - - static int --parse_code_object( -- int pid, -- PyObject* result, -- struct _Py_DebugOffsets* offsets, -- void* address, -- void** previous_frame) -+read_py_ptr(pid_t pid, uintptr_t address, uintptr_t *ptr_addr) -+{ -+ if (read_ptr(pid, address, ptr_addr)) { -+ return -1; -+ } -+ *ptr_addr &= ~Py_TAG_BITS; -+ return 0; -+} -+ -+static int -+read_char(pid_t pid, uintptr_t address, char *result) -+{ -+ int bytes_read = read_memory(pid, address, sizeof(char), result); -+ if (bytes_read < 0) { -+ return -1; -+ } -+ return 0; -+} -+ -+static int -+read_int(pid_t pid, uintptr_t address, int *result) -+{ -+ int bytes_read = read_memory(pid, address, sizeof(int), result); -+ if (bytes_read < 0) { -+ return -1; -+ } -+ return 0; -+} -+ -+static int -+read_unsigned_long(pid_t pid, uintptr_t address, unsigned long *result) -+{ -+ int bytes_read = read_memory(pid, address, sizeof(unsigned long), result); -+ if (bytes_read < 0) { -+ return -1; -+ } -+ return 0; -+} -+ -+static int -+read_pyobj(pid_t pid, uintptr_t address, PyObject *ptr_addr) - { -- void* address_of_function_name; -- read_memory( -+ int bytes_read = read_memory(pid, address, sizeof(PyObject), ptr_addr); -+ if (bytes_read < 0) { -+ return -1; -+ } -+ return 0; -+} -+ -+static PyObject * -+read_py_str( -+ pid_t pid, -+ _Py_DebugOffsets* debug_offsets, -+ uintptr_t address, -+ ssize_t max_len -+) { -+ assert(max_len > 0); -+ -+ PyObject *result = NULL; -+ -+ char *buf = (char *)PyMem_RawMalloc(max_len); -+ if (buf == NULL) { -+ PyErr_NoMemory(); -+ return NULL; -+ } -+ if (read_string(pid, debug_offsets, address, buf, max_len)) { -+ goto err; -+ } -+ -+ result = PyUnicode_FromString(buf); -+ if (result == NULL) { -+ goto err; -+ } -+ -+ PyMem_RawFree(buf); -+ assert(result != NULL); -+ return result; -+ -+err: -+ PyMem_RawFree(buf); -+ return NULL; -+} -+ -+static long -+read_py_long(pid_t pid, _Py_DebugOffsets* offsets, uintptr_t address) -+{ -+ unsigned int shift = PYLONG_BITS_IN_DIGIT; -+ -+ ssize_t size; -+ uintptr_t lv_tag; -+ -+ int bytes_read = read_memory( -+ pid, address + offsets->long_object.lv_tag, -+ sizeof(uintptr_t), -+ &lv_tag); -+ if (bytes_read < 0) { -+ return -1; -+ } -+ -+ int negative = (lv_tag & 3) == 2; -+ size = lv_tag >> 3; -+ -+ if (size == 0) { -+ return 0; -+ } -+ -+ digit *digits = (digit *)PyMem_RawMalloc(size * sizeof(digit)); -+ if (!digits) { -+ PyErr_NoMemory(); -+ return -1; -+ } -+ -+ bytes_read = read_memory( -+ pid, -+ address + offsets->long_object.ob_digit, -+ sizeof(digit) * size, -+ digits -+ ); -+ if (bytes_read < 0) { -+ goto error; -+ } -+ -+ long value = 0; -+ -+ // In theory this can overflow, but because of llvm/llvm-project#16778 -+ // we can't use __builtin_mul_overflow because it fails to link with -+ // __muloti4 on aarch64. In practice this is fine because all we're -+ // testing here are task numbers that would fit in a single byte. -+ for (ssize_t i = 0; i < size; ++i) { -+ long long factor = digits[i] * (1UL << (ssize_t)(shift * i)); -+ value += factor; -+ } -+ PyMem_RawFree(digits); -+ if (negative) { -+ value *= -1; -+ } -+ return value; -+error: -+ PyMem_RawFree(digits); -+ return -1; -+} -+ -+static PyObject * -+parse_task_name( -+ int pid, -+ _Py_DebugOffsets* offsets, -+ struct _Py_AsyncioModuleDebugOffsets* async_offsets, -+ uintptr_t task_address -+) { -+ uintptr_t task_name_addr; -+ int err = read_py_ptr( -+ pid, -+ task_address + async_offsets->asyncio_task_object.task_name, -+ &task_name_addr); -+ if (err) { -+ return NULL; -+ } -+ -+ // The task name can be a long or a string so we need to check the type -+ -+ PyObject task_name_obj; -+ err = read_pyobj( -+ pid, -+ task_name_addr, -+ &task_name_obj); -+ if (err) { -+ return NULL; -+ } -+ -+ unsigned long flags; -+ err = read_unsigned_long( -+ pid, -+ (uintptr_t)task_name_obj.ob_type + offsets->type_object.tp_flags, -+ &flags); -+ if (err) { -+ return NULL; -+ } -+ -+ if ((flags & Py_TPFLAGS_LONG_SUBCLASS)) { -+ long res = read_py_long(pid, offsets, task_name_addr); -+ if (res == -1) { -+ PyErr_SetString(PyExc_RuntimeError, "Failed to get task name"); -+ return NULL; -+ } -+ return PyUnicode_FromFormat("Task-%d", res); -+ } -+ -+ if(!(flags & Py_TPFLAGS_UNICODE_SUBCLASS)) { -+ PyErr_SetString(PyExc_RuntimeError, "Invalid task name object"); -+ return NULL; -+ } -+ -+ return read_py_str( -+ pid, -+ offsets, -+ task_name_addr, -+ 255 -+ ); -+} -+ -+static int -+parse_coro_chain( -+ int pid, -+ struct _Py_DebugOffsets* offsets, -+ struct _Py_AsyncioModuleDebugOffsets* async_offsets, -+ uintptr_t coro_address, -+ PyObject *render_to -+) { -+ assert((void*)coro_address != NULL); -+ -+ uintptr_t gen_type_addr; -+ int err = read_ptr( -+ pid, -+ coro_address + sizeof(void*), -+ &gen_type_addr); -+ if (err) { -+ return -1; -+ } -+ -+ uintptr_t gen_name_addr; -+ err = read_py_ptr( -+ pid, -+ coro_address + offsets->gen_object.gi_name, -+ &gen_name_addr); -+ if (err) { -+ return -1; -+ } -+ -+ PyObject *name = read_py_str( -+ pid, -+ offsets, -+ gen_name_addr, -+ 255 -+ ); -+ if (name == NULL) { -+ return -1; -+ } -+ -+ if (PyList_Append(render_to, name)) { -+ return -1; -+ } -+ Py_DECREF(name); -+ -+ int gi_frame_state; -+ err = read_int( -+ pid, -+ coro_address + offsets->gen_object.gi_frame_state, -+ &gi_frame_state); -+ -+ if (gi_frame_state == FRAME_SUSPENDED_YIELD_FROM) { -+ char owner; -+ err = read_char( - pid, -- (void*)(address + offsets->code_object.name), -- sizeof(void*), -- &address_of_function_name); -+ coro_address + offsets->gen_object.gi_iframe + -+ offsets->interpreter_frame.owner, -+ &owner -+ ); -+ if (err) { -+ return -1; -+ } -+ if (owner != FRAME_OWNED_BY_GENERATOR) { -+ PyErr_SetString( -+ PyExc_RuntimeError, -+ "generator doesn't own its frame \\_o_/"); -+ return -1; -+ } - -- if (address_of_function_name == NULL) { -- PyErr_SetString(PyExc_RuntimeError, "No function name found"); -+ uintptr_t stackpointer_addr; -+ err = read_py_ptr( -+ pid, -+ coro_address + offsets->gen_object.gi_iframe + -+ offsets->interpreter_frame.stackpointer, -+ &stackpointer_addr); -+ if (err) { -+ return -1; -+ } -+ -+ if ((void*)stackpointer_addr != NULL) { -+ uintptr_t gi_await_addr; -+ err = read_py_ptr( -+ pid, -+ stackpointer_addr - sizeof(void*), -+ &gi_await_addr); -+ if (err) { -+ return -1; -+ } -+ -+ if ((void*)gi_await_addr != NULL) { -+ uintptr_t gi_await_addr_type_addr; -+ int err = read_ptr( -+ pid, -+ gi_await_addr + sizeof(void*), -+ &gi_await_addr_type_addr); -+ if (err) { -+ return -1; -+ } -+ -+ if (gen_type_addr == gi_await_addr_type_addr) { -+ /* This needs an explanation. We always start with parsing -+ native coroutine / generator frames. Ultimately they -+ are awaiting on something. That something can be -+ a native coroutine frame or... an iterator. -+ If it's the latter -- we can't continue building -+ our chain. So the condition to bail out of this is -+ to do that when the type of the current coroutine -+ doesn't match the type of whatever it points to -+ in its cr_await. -+ */ -+ err = parse_coro_chain( -+ pid, -+ offsets, -+ async_offsets, -+ gi_await_addr, -+ render_to -+ ); -+ if (err) { -+ return -1; -+ } -+ } -+ } -+ } -+ -+ } -+ -+ return 0; -+} -+ -+ -+static int -+parse_task_awaited_by( -+ int pid, -+ struct _Py_DebugOffsets* offsets, -+ struct _Py_AsyncioModuleDebugOffsets* async_offsets, -+ uintptr_t task_address, -+ PyObject *awaited_by -+); -+ -+ -+static int -+parse_task( -+ int pid, -+ struct _Py_DebugOffsets* offsets, -+ struct _Py_AsyncioModuleDebugOffsets* async_offsets, -+ uintptr_t task_address, -+ PyObject *render_to -+) { -+ char is_task; -+ int err = read_char( -+ pid, -+ task_address + async_offsets->asyncio_task_object.task_is_task, -+ &is_task); -+ if (err) { -+ return -1; -+ } -+ -+ uintptr_t refcnt; -+ read_ptr(pid, task_address + sizeof(Py_ssize_t), &refcnt); -+ -+ PyObject* result = PyList_New(0); -+ if (result == NULL) { -+ return -1; -+ } -+ -+ PyObject *call_stack = PyList_New(0); -+ if (call_stack == NULL) { -+ goto err; -+ } -+ if (PyList_Append(result, call_stack)) { -+ Py_DECREF(call_stack); -+ goto err; -+ } -+ /* we can operate on a borrowed one to simplify cleanup */ -+ Py_DECREF(call_stack); -+ -+ if (is_task) { -+ PyObject *tn = parse_task_name( -+ pid, offsets, async_offsets, task_address); -+ if (tn == NULL) { -+ goto err; -+ } -+ if (PyList_Append(result, tn)) { -+ Py_DECREF(tn); -+ goto err; -+ } -+ Py_DECREF(tn); -+ -+ uintptr_t coro_addr; -+ err = read_py_ptr( -+ pid, -+ task_address + async_offsets->asyncio_task_object.task_coro, -+ &coro_addr); -+ if (err) { -+ goto err; -+ } -+ -+ if ((void*)coro_addr != NULL) { -+ err = parse_coro_chain( -+ pid, -+ offsets, -+ async_offsets, -+ coro_addr, -+ call_stack -+ ); -+ if (err) { -+ goto err; -+ } -+ -+ if (PyList_Reverse(call_stack)) { -+ goto err; -+ } -+ } -+ } -+ -+ if (PyList_Append(render_to, result)) { -+ goto err; -+ } -+ Py_DECREF(result); -+ -+ PyObject *awaited_by = PyList_New(0); -+ if (awaited_by == NULL) { -+ goto err; -+ } -+ if (PyList_Append(result, awaited_by)) { -+ Py_DECREF(awaited_by); -+ goto err; -+ } -+ /* we can operate on a borrowed one to simplify cleanup */ -+ Py_DECREF(awaited_by); -+ -+ if (parse_task_awaited_by(pid, offsets, async_offsets, -+ task_address, awaited_by) -+ ) { -+ goto err; -+ } -+ -+ return 0; -+ -+err: -+ Py_DECREF(result); -+ return -1; -+} -+ -+static int -+parse_tasks_in_set( -+ int pid, -+ struct _Py_DebugOffsets* offsets, -+ struct _Py_AsyncioModuleDebugOffsets* async_offsets, -+ uintptr_t set_addr, -+ PyObject *awaited_by -+) { -+ uintptr_t set_obj; -+ if (read_py_ptr( -+ pid, -+ set_addr, -+ &set_obj) -+ ) { -+ return -1; -+ } -+ -+ Py_ssize_t num_els; -+ if (read_ssize_t( -+ pid, -+ set_obj + offsets->set_object.used, -+ &num_els) -+ ) { -+ return -1; -+ } -+ -+ Py_ssize_t set_len; -+ if (read_ssize_t( -+ pid, -+ set_obj + offsets->set_object.mask, -+ &set_len) -+ ) { -+ return -1; -+ } -+ set_len++; // The set contains the `mask+1` element slots. -+ -+ uintptr_t table_ptr; -+ if (read_ptr( -+ pid, -+ set_obj + offsets->set_object.table, -+ &table_ptr) -+ ) { -+ return -1; -+ } -+ -+ Py_ssize_t i = 0; -+ Py_ssize_t els = 0; -+ while (i < set_len) { -+ uintptr_t key_addr; -+ if (read_py_ptr(pid, table_ptr, &key_addr)) { -+ return -1; -+ } -+ -+ if ((void*)key_addr != NULL) { -+ Py_ssize_t ref_cnt; -+ if (read_ssize_t(pid, table_ptr, &ref_cnt)) { -+ return -1; -+ } -+ -+ if (ref_cnt) { -+ // if 'ref_cnt=0' it's a set dummy marker -+ -+ if (parse_task( -+ pid, -+ offsets, -+ async_offsets, -+ key_addr, -+ awaited_by) -+ ) { -+ return -1; -+ } -+ -+ if (++els == num_els) { -+ break; -+ } -+ } -+ } -+ -+ table_ptr += sizeof(void*) * 2; -+ i++; -+ } -+ return 0; -+} -+ -+ -+static int -+parse_task_awaited_by( -+ int pid, -+ struct _Py_DebugOffsets* offsets, -+ struct _Py_AsyncioModuleDebugOffsets* async_offsets, -+ uintptr_t task_address, -+ PyObject *awaited_by -+) { -+ uintptr_t task_ab_addr; -+ int err = read_py_ptr( -+ pid, -+ task_address + async_offsets->asyncio_task_object.task_awaited_by, -+ &task_ab_addr); -+ if (err) { -+ return -1; -+ } -+ -+ if ((void*)task_ab_addr == NULL) { -+ return 0; -+ } -+ -+ char awaited_by_is_a_set; -+ err = read_char( -+ pid, -+ task_address + async_offsets->asyncio_task_object.task_awaited_by_is_set, -+ &awaited_by_is_a_set); -+ if (err) { -+ return -1; -+ } -+ -+ if (awaited_by_is_a_set) { -+ if (parse_tasks_in_set( -+ pid, -+ offsets, -+ async_offsets, -+ task_address + async_offsets->asyncio_task_object.task_awaited_by, -+ awaited_by) -+ ) { -+ return -1; -+ } -+ } else { -+ uintptr_t sub_task; -+ if (read_py_ptr( -+ pid, -+ task_address + async_offsets->asyncio_task_object.task_awaited_by, -+ &sub_task) -+ ) { -+ return -1; -+ } -+ -+ if (parse_task( -+ pid, -+ offsets, -+ async_offsets, -+ sub_task, -+ awaited_by) -+ ) { -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+static int -+parse_code_object( -+ int pid, -+ PyObject* result, -+ struct _Py_DebugOffsets* offsets, -+ uintptr_t address, -+ uintptr_t* previous_frame -+) { -+ uintptr_t address_of_function_name; -+ int bytes_read = read_memory( -+ pid, -+ address + offsets->code_object.name, -+ sizeof(void*), -+ &address_of_function_name -+ ); -+ if (bytes_read < 0) { - return -1; - } - -- char function_name[256]; -- if (read_string(pid, offsets, address_of_function_name, function_name, sizeof(function_name)) != 0) { -+ if ((void*)address_of_function_name == NULL) { -+ PyErr_SetString(PyExc_RuntimeError, "No function name found"); - return -1; - } - -- PyObject* py_function_name = PyUnicode_FromString(function_name); -+ PyObject* py_function_name = read_py_str( -+ pid, offsets, address_of_function_name, 256); - if (py_function_name == NULL) { - return -1; - } -@@ -486,54 +1171,283 @@ - - static int - parse_frame_object( -- int pid, -- PyObject* result, -- struct _Py_DebugOffsets* offsets, -- void* address, -- void** previous_frame) --{ -+ int pid, -+ PyObject* result, -+ struct _Py_DebugOffsets* offsets, -+ uintptr_t address, -+ uintptr_t* previous_frame -+) { -+ int err; -+ -+ ssize_t bytes_read = read_memory( -+ pid, -+ address + offsets->interpreter_frame.previous, -+ sizeof(void*), -+ previous_frame -+ ); -+ if (bytes_read < 0) { -+ return -1; -+ } -+ -+ char owner; -+ if (read_char(pid, address + offsets->interpreter_frame.owner, &owner)) { -+ return -1; -+ } -+ -+ if (owner >= FRAME_OWNED_BY_INTERPRETER) { -+ return 0; -+ } -+ -+ uintptr_t address_of_code_object; -+ err = read_py_ptr( -+ pid, -+ address + offsets->interpreter_frame.executable, -+ &address_of_code_object -+ ); -+ if (err) { -+ return -1; -+ } -+ -+ if ((void*)address_of_code_object == NULL) { -+ return 0; -+ } -+ -+ return parse_code_object( -+ pid, result, offsets, address_of_code_object, previous_frame); -+} -+ -+static int -+parse_async_frame_object( -+ int pid, -+ PyObject* result, -+ struct _Py_DebugOffsets* offsets, -+ uintptr_t address, -+ uintptr_t* previous_frame, -+ uintptr_t* code_object -+) { -+ int err; -+ -+ ssize_t bytes_read = read_memory( -+ pid, -+ address + offsets->interpreter_frame.previous, -+ sizeof(void*), -+ previous_frame -+ ); -+ if (bytes_read < 0) { -+ return -1; -+ } -+ -+ char owner; -+ bytes_read = read_memory( -+ pid, address + offsets->interpreter_frame.owner, sizeof(char), &owner); -+ if (bytes_read < 0) { -+ return -1; -+ } -+ -+ if (owner == FRAME_OWNED_BY_CSTACK || owner == FRAME_OWNED_BY_INTERPRETER) { -+ return 0; // C frame -+ } -+ -+ if (owner != FRAME_OWNED_BY_GENERATOR -+ && owner != FRAME_OWNED_BY_THREAD) { -+ PyErr_Format(PyExc_RuntimeError, "Unhandled frame owner %d.\n", owner); -+ return -1; -+ } -+ -+ err = read_py_ptr( -+ pid, -+ address + offsets->interpreter_frame.executable, -+ code_object -+ ); -+ if (err) { -+ return -1; -+ } -+ -+ assert(code_object != NULL); -+ if ((void*)*code_object == NULL) { -+ return 0; -+ } -+ -+ if (parse_code_object( -+ pid, result, offsets, *code_object, previous_frame)) { -+ return -1; -+ } -+ -+ return 1; -+} -+ -+static int -+read_offsets( -+ int pid, -+ uintptr_t *runtime_start_address, -+ _Py_DebugOffsets* debug_offsets -+) { -+ *runtime_start_address = get_py_runtime(pid); -+ if ((void*)*runtime_start_address == NULL) { -+ if (!PyErr_Occurred()) { -+ PyErr_SetString( -+ PyExc_RuntimeError, "Failed to get .PyRuntime address"); -+ } -+ return -1; -+ } -+ size_t size = sizeof(struct _Py_DebugOffsets); -+ ssize_t bytes_read = read_memory( -+ pid, *runtime_start_address, size, debug_offsets); -+ if (bytes_read < 0) { -+ return -1; -+ } -+ return 0; -+} -+ -+static int -+read_async_debug( -+ int pid, -+ struct _Py_AsyncioModuleDebugOffsets* async_debug -+) { -+ uintptr_t async_debug_addr = get_async_debug(pid); -+ if (!async_debug_addr) { -+ return -1; -+ } -+ size_t size = sizeof(struct _Py_AsyncioModuleDebugOffsets); - ssize_t bytes_read = read_memory( -+ pid, async_debug_addr, size, async_debug); -+ if (bytes_read < 0) { -+ return -1; -+ } -+ return 0; -+} -+ -+static int -+find_running_frame( -+ int pid, -+ uintptr_t runtime_start_address, -+ _Py_DebugOffsets* local_debug_offsets, -+ uintptr_t *frame -+) { -+ off_t interpreter_state_list_head = -+ local_debug_offsets->runtime_state.interpreters_head; -+ -+ uintptr_t address_of_interpreter_state; -+ int bytes_read = read_memory( - pid, -- (void*)(address + offsets->interpreter_frame.previous), -+ runtime_start_address + interpreter_state_list_head, - sizeof(void*), -- previous_frame); -- if (bytes_read == -1) { -+ &address_of_interpreter_state); -+ if (bytes_read < 0) { - return -1; - } - -- char owner; -- bytes_read = -- read_memory(pid, (void*)(address + offsets->interpreter_frame.owner), sizeof(char), &owner); -+ if (address_of_interpreter_state == 0) { -+ PyErr_SetString(PyExc_RuntimeError, "No interpreter state found"); -+ return -1; -+ } -+ -+ uintptr_t address_of_thread; -+ bytes_read = read_memory( -+ pid, -+ address_of_interpreter_state + -+ local_debug_offsets->interpreter_state.threads_head, -+ sizeof(void*), -+ &address_of_thread); - if (bytes_read < 0) { - return -1; - } - -- if (owner == FRAME_OWNED_BY_CSTACK) { -+ // No Python frames are available for us (can happen at tear-down). -+ if ((void*)address_of_thread != NULL) { -+ int err = read_ptr( -+ pid, -+ address_of_thread + local_debug_offsets->thread_state.current_frame, -+ frame); -+ if (err) { -+ return -1; -+ } - return 0; - } - -- uintptr_t address_of_code_object; -+ *frame = (uintptr_t)NULL; -+ return 0; -+} -+ -+static int -+find_running_task( -+ int pid, -+ uintptr_t runtime_start_address, -+ _Py_DebugOffsets *local_debug_offsets, -+ struct _Py_AsyncioModuleDebugOffsets *async_offsets, -+ uintptr_t *running_task_addr -+) { -+ *running_task_addr = (uintptr_t)NULL; -+ -+ off_t interpreter_state_list_head = -+ local_debug_offsets->runtime_state.interpreters_head; -+ -+ uintptr_t address_of_interpreter_state; -+ int bytes_read = read_memory( -+ pid, -+ runtime_start_address + interpreter_state_list_head, -+ sizeof(void*), -+ &address_of_interpreter_state); -+ if (bytes_read < 0) { -+ return -1; -+ } -+ -+ if (address_of_interpreter_state == 0) { -+ PyErr_SetString(PyExc_RuntimeError, "No interpreter state found"); -+ return -1; -+ } -+ -+ uintptr_t address_of_thread; - bytes_read = read_memory( - pid, -- (void*)(address + offsets->interpreter_frame.executable), -+ address_of_interpreter_state + -+ local_debug_offsets->interpreter_state.threads_head, - sizeof(void*), -- &address_of_code_object); -+ &address_of_thread); -+ if (bytes_read < 0) { -+ return -1; -+ } -+ -+ uintptr_t address_of_running_loop; -+ // No Python frames are available for us (can happen at tear-down). -+ if ((void*)address_of_thread == NULL) { -+ return 0; -+ } -+ -+ bytes_read = read_py_ptr( -+ pid, -+ address_of_thread -+ + async_offsets->asyncio_thread_state.asyncio_running_loop, -+ &address_of_running_loop); - if (bytes_read == -1) { - return -1; - } - -- if (address_of_code_object == 0) { -+ // no asyncio loop is now running -+ if ((void*)address_of_running_loop == NULL) { - return 0; - } -- address_of_code_object &= ~Py_TAG_BITS; -- return parse_code_object(pid, result, offsets, (void *)address_of_code_object, previous_frame); -+ -+ int err = read_ptr( -+ pid, -+ address_of_thread -+ + async_offsets->asyncio_thread_state.asyncio_running_task, -+ running_task_addr); -+ if (err) { -+ return -1; -+ } -+ -+ return 0; - } - - static PyObject* - get_stack_trace(PyObject* self, PyObject* args) - { --#if (!defined(__linux__) && !defined(__APPLE__)) || (defined(__linux__) && !HAVE_PROCESS_VM_READV) -- PyErr_SetString(PyExc_RuntimeError, "get_stack_trace is not supported on this platform"); -+#if (!defined(__linux__) && !defined(__APPLE__)) || \ -+ (defined(__linux__) && !HAVE_PROCESS_VM_READV) -+ PyErr_SetString( -+ PyExc_RuntimeError, -+ "get_stack_trace is not supported on this platform"); - return NULL; - #endif - int pid; -@@ -542,88 +1456,205 @@ - return NULL; - } - -- void* runtime_start_address = get_py_runtime(pid); -- if (runtime_start_address == NULL) { -- if (!PyErr_Occurred()) { -- PyErr_SetString(PyExc_RuntimeError, "Failed to get .PyRuntime address"); -- } -+ uintptr_t runtime_start_address = get_py_runtime(pid); -+ struct _Py_DebugOffsets local_debug_offsets; -+ -+ if (read_offsets(pid, &runtime_start_address, &local_debug_offsets)) { - return NULL; - } -- size_t size = sizeof(struct _Py_DebugOffsets); -- struct _Py_DebugOffsets local_debug_offsets; - -- ssize_t bytes_read = read_memory(pid, runtime_start_address, size, &local_debug_offsets); -- if (bytes_read == -1) { -+ uintptr_t address_of_current_frame; -+ if (find_running_frame( -+ pid, runtime_start_address, &local_debug_offsets, -+ &address_of_current_frame) -+ ) { - return NULL; - } -- off_t interpreter_state_list_head = local_debug_offsets.runtime_state.interpreters_head; - -- void* address_of_interpreter_state; -- bytes_read = read_memory( -- pid, -- (void*)(runtime_start_address + interpreter_state_list_head), -- sizeof(void*), -- &address_of_interpreter_state); -- if (bytes_read == -1) { -+ PyObject* result = PyList_New(0); -+ if (result == NULL) { - return NULL; - } - -- if (address_of_interpreter_state == NULL) { -- PyErr_SetString(PyExc_RuntimeError, "No interpreter state found"); -+ while ((void*)address_of_current_frame != NULL) { -+ if (parse_frame_object( -+ pid, -+ result, -+ &local_debug_offsets, -+ address_of_current_frame, -+ &address_of_current_frame) -+ < 0) -+ { -+ Py_DECREF(result); -+ return NULL; -+ } -+ } -+ -+ return result; -+} -+ -+static PyObject* -+get_async_stack_trace(PyObject* self, PyObject* args) -+{ -+#if (!defined(__linux__) && !defined(__APPLE__)) || \ -+ (defined(__linux__) && !HAVE_PROCESS_VM_READV) -+ PyErr_SetString( -+ PyExc_RuntimeError, -+ "get_stack_trace is not supported on this platform"); -+ return NULL; -+#endif -+ int pid; -+ -+ if (!PyArg_ParseTuple(args, "i", &pid)) { - return NULL; - } - -- void* address_of_thread; -- bytes_read = read_memory( -- pid, -- (void*)(address_of_interpreter_state + local_debug_offsets.interpreter_state.threads_head), -- sizeof(void*), -- &address_of_thread); -- if (bytes_read == -1) { -+ uintptr_t runtime_start_address = get_py_runtime(pid); -+ struct _Py_DebugOffsets local_debug_offsets; -+ -+ if (read_offsets(pid, &runtime_start_address, &local_debug_offsets)) { - return NULL; - } - -- PyObject* result = PyList_New(0); -+ struct _Py_AsyncioModuleDebugOffsets local_async_debug; -+ if (read_async_debug(pid, &local_async_debug)) { -+ return NULL; -+ } -+ -+ PyObject* result = PyList_New(1); - if (result == NULL) { - return NULL; - } -+ PyObject* calls = PyList_New(0); -+ if (calls == NULL) { -+ return NULL; -+ } -+ if (PyList_SetItem(result, 0, calls)) { /* steals ref to 'calls' */ -+ Py_DECREF(result); -+ Py_DECREF(calls); -+ return NULL; -+ } - -- // No Python frames are available for us (can happen at tear-down). -- if (address_of_thread != NULL) { -- void* address_of_current_frame; -- (void)read_memory( -- pid, -- (void*)(address_of_thread + local_debug_offsets.thread_state.current_frame), -- sizeof(void*), -- &address_of_current_frame); -- while (address_of_current_frame != NULL) { -- if (parse_frame_object( -- pid, -- result, -- &local_debug_offsets, -- address_of_current_frame, -- &address_of_current_frame) -- < 0) -- { -- Py_DECREF(result); -- return NULL; -- } -+ uintptr_t running_task_addr = (uintptr_t)NULL; -+ if (find_running_task( -+ pid, runtime_start_address, &local_debug_offsets, &local_async_debug, -+ &running_task_addr) -+ ) { -+ goto result_err; -+ } -+ -+ if ((void*)running_task_addr == NULL) { -+ PyErr_SetString(PyExc_RuntimeError, "No running task found"); -+ goto result_err; -+ } -+ -+ uintptr_t running_coro_addr; -+ if (read_py_ptr( -+ pid, -+ running_task_addr + local_async_debug.asyncio_task_object.task_coro, -+ &running_coro_addr -+ )) { -+ goto result_err; -+ } -+ -+ if ((void*)running_coro_addr == NULL) { -+ PyErr_SetString(PyExc_RuntimeError, "Running task coro is NULL"); -+ goto result_err; -+ } -+ -+ // note: genobject's gi_iframe is an embedded struct so the address to -+ // the offset leads directly to its first field: f_executable -+ uintptr_t address_of_running_task_code_obj; -+ if (read_py_ptr( -+ pid, -+ running_coro_addr + local_debug_offsets.gen_object.gi_iframe, -+ &address_of_running_task_code_obj -+ )) { -+ goto result_err; -+ } -+ -+ if ((void*)address_of_running_task_code_obj == NULL) { -+ PyErr_SetString(PyExc_RuntimeError, "Running task code object is NULL"); -+ goto result_err; -+ } -+ -+ uintptr_t address_of_current_frame; -+ if (find_running_frame( -+ pid, runtime_start_address, &local_debug_offsets, -+ &address_of_current_frame) -+ ) { -+ goto result_err; -+ } -+ -+ uintptr_t address_of_code_object; -+ while ((void*)address_of_current_frame != NULL) { -+ int res = parse_async_frame_object( -+ pid, -+ calls, -+ &local_debug_offsets, -+ address_of_current_frame, -+ &address_of_current_frame, -+ &address_of_code_object -+ ); -+ -+ if (res < 0) { -+ goto result_err; -+ } -+ -+ if (address_of_code_object == address_of_running_task_code_obj) { -+ break; - } - } - -+ PyObject *tn = parse_task_name( -+ pid, &local_debug_offsets, &local_async_debug, running_task_addr); -+ if (tn == NULL) { -+ goto result_err; -+ } -+ if (PyList_Append(result, tn)) { -+ Py_DECREF(tn); -+ goto result_err; -+ } -+ Py_DECREF(tn); -+ -+ PyObject* awaited_by = PyList_New(0); -+ if (awaited_by == NULL) { -+ goto result_err; -+ } -+ if (PyList_Append(result, awaited_by)) { -+ Py_DECREF(awaited_by); -+ goto result_err; -+ } -+ Py_DECREF(awaited_by); -+ -+ if (parse_task_awaited_by( -+ pid, &local_debug_offsets, &local_async_debug, -+ running_task_addr, awaited_by) -+ ) { -+ goto result_err; -+ } -+ - return result; -+ -+result_err: -+ Py_DECREF(result); -+ return NULL; - } - -+ - static PyMethodDef methods[] = { -- {"get_stack_trace", get_stack_trace, METH_VARARGS, "Get the Python stack from a given PID"}, -- {NULL, NULL, 0, NULL}, -+ {"get_stack_trace", get_stack_trace, METH_VARARGS, -+ "Get the Python stack from a given PID"}, -+ {"get_async_stack_trace", get_async_stack_trace, METH_VARARGS, -+ "Get the asyncio stack from a given PID"}, -+ {NULL, NULL, 0, NULL}, - }; - - static struct PyModuleDef module = { -- .m_base = PyModuleDef_HEAD_INIT, -- .m_name = "_testexternalinspection", -- .m_size = -1, -- .m_methods = methods, -+ .m_base = PyModuleDef_HEAD_INIT, -+ .m_name = "_testexternalinspection", -+ .m_size = -1, -+ .m_methods = methods, - }; - - PyMODINIT_FUNC -@@ -636,7 +1667,8 @@ - #ifdef Py_GIL_DISABLED - PyUnstable_Module_SetGIL(mod, Py_MOD_GIL_NOT_USED); - #endif -- int rc = PyModule_AddIntConstant(mod, "PROCESS_VM_READV_SUPPORTED", HAVE_PROCESS_VM_READV); -+ int rc = PyModule_AddIntConstant( -+ mod, "PROCESS_VM_READV_SUPPORTED", HAVE_PROCESS_VM_READV); - if (rc < 0) { - Py_DECREF(mod); - return NULL; -diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c -index 014f89997f7..e44b629897c 100644 ---- a/Modules/_testinternalcapi.c -+++ b/Modules/_testinternalcapi.c -@@ -25,10 +25,8 @@ - #include "pycore_hashtable.h" // _Py_hashtable_new() - #include "pycore_initconfig.h" // _Py_GetConfigsAsDict() - #include "pycore_instruction_sequence.h" // _PyInstructionSequence_New() --#include "pycore_interp.h" // _PyInterpreterState_GetConfigCopy() --#include "pycore_long.h" // _PyLong_Sign() - #include "pycore_object.h" // _PyObject_IsFreed() --#include "pycore_optimizer.h" // _Py_UopsSymbol, etc. -+#include "pycore_optimizer.h" // JitOptSymbol, etc. - #include "pycore_pathconfig.h" // _PyPathConfig_ClearGlobal() - #include "pycore_pyerrors.h" // _PyErr_ChainExceptions1() - #include "pycore_pylifecycle.h" // _PyInterpreterConfig_AsDict() -@@ -318,41 +316,6 @@ - } - - --static PyObject * --test_get_config(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) --{ -- PyConfig config; -- PyConfig_InitIsolatedConfig(&config); -- if (_PyInterpreterState_GetConfigCopy(&config) < 0) { -- PyConfig_Clear(&config); -- return NULL; -- } -- PyObject *dict = _PyConfig_AsDict(&config); -- PyConfig_Clear(&config); -- return dict; --} -- -- --static PyObject * --test_set_config(PyObject *Py_UNUSED(self), PyObject *dict) --{ -- PyConfig config; -- PyConfig_InitIsolatedConfig(&config); -- if (_PyConfig_FromDict(&config, dict) < 0) { -- goto error; -- } -- if (_PyInterpreterState_SetConfig(&config) < 0) { -- goto error; -- } -- PyConfig_Clear(&config); -- Py_RETURN_NONE; -- --error: -- PyConfig_Clear(&config); -- return NULL; --} -- -- - static PyObject * - test_reset_path_config(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(arg)) - { -@@ -987,44 +950,13 @@ - return PyLong_FromLong(code->co_framesize); - } - --#ifdef _Py_TIER2 -- --static PyObject * --new_counter_optimizer(PyObject *self, PyObject *arg) --{ -- return _PyOptimizer_NewCounter(); --} -- - static PyObject * --new_uop_optimizer(PyObject *self, PyObject *arg) -+jit_enabled(PyObject *self, PyObject *arg) - { -- return _PyOptimizer_NewUOpOptimizer(); -+ return PyBool_FromLong(_PyInterpreterState_GET()->jit); - } - --static PyObject * --set_optimizer(PyObject *self, PyObject *opt) --{ -- if (opt == Py_None) { -- opt = NULL; -- } -- if (_Py_SetTier2Optimizer((_PyOptimizerObject*)opt) < 0) { -- return NULL; -- } -- Py_RETURN_NONE; --} -- --static PyObject * --get_optimizer(PyObject *self, PyObject *Py_UNUSED(ignored)) --{ -- PyObject *opt = NULL; - #ifdef _Py_TIER2 -- opt = (PyObject *)_Py_GetOptimizer(); --#endif -- if (opt == NULL) { -- Py_RETURN_NONE; -- } -- return opt; --} - - static PyObject * - add_executor_dependency(PyObject *self, PyObject *args) -@@ -1034,12 +966,6 @@ - if (!PyArg_ParseTuple(args, "OO", &exec, &obj)) { - return NULL; - } -- /* No way to tell in general if exec is an executor, so we only accept -- * counting_executor */ -- if (strcmp(Py_TYPE(exec)->tp_name, "counting_executor")) { -- PyErr_SetString(PyExc_TypeError, "argument must be a counting_executor"); -- return NULL; -- } - _Py_Executor_DependsOn((_PyExecutorObject *)exec, obj); - Py_RETURN_NONE; - } -@@ -1846,14 +1772,14 @@ - - for (i = 0; i < Py_ARRAY_LENGTH(testcases); ++i) { - uint64_t nbits; -- int sign; -+ int sign = -7; - PyObject *plong; - - plong = PyLong_FromLong(testcases[i].input); - if (plong == NULL) - return NULL; - nbits = _PyLong_NumBits(plong); -- sign = _PyLong_Sign(plong); -+ (void)PyLong_GetSign(plong, &sign); - - Py_DECREF(plong); - if (nbits != testcases[i].nbits) -@@ -1861,7 +1787,7 @@ - "wrong result for _PyLong_NumBits"); - if (sign != testcases[i].sign) - return raiseTestError("test_long_numbits", -- "wrong result for _PyLong_Sign"); -+ "wrong result for PyLong_GetSign()"); - } - Py_RETURN_NONE; - } -@@ -1989,6 +1915,14 @@ - Py_RETURN_FALSE; - } - -+static PyObject * -+has_split_table(PyObject *self, PyObject *obj) -+{ -+ if (PyDict_Check(obj) && _PyDict_HasSplitTable((PyDictObject *)obj)) { -+ Py_RETURN_TRUE; -+ } -+ Py_RETURN_FALSE; -+} - - // Circumvents standard version assignment machinery - use with caution and only on - // short-lived heap types -@@ -2066,8 +2000,6 @@ - {"test_popcount", test_popcount, METH_NOARGS}, - {"test_bit_length", test_bit_length, METH_NOARGS}, - {"test_hashtable", test_hashtable, METH_NOARGS}, -- {"get_config", test_get_config, METH_NOARGS}, -- {"set_config", test_set_config, METH_O}, - {"reset_path_config", test_reset_path_config, METH_NOARGS}, - {"test_edit_cost", test_edit_cost, METH_NOARGS}, - {"test_bytes_find", test_bytes_find, METH_NOARGS}, -@@ -2090,11 +2022,8 @@ - {"iframe_getline", iframe_getline, METH_O, NULL}, - {"iframe_getlasti", iframe_getlasti, METH_O, NULL}, - {"get_co_framesize", get_co_framesize, METH_O, NULL}, -+ {"jit_enabled", jit_enabled, METH_NOARGS, NULL}, - #ifdef _Py_TIER2 -- {"get_optimizer", get_optimizer, METH_NOARGS, NULL}, -- {"set_optimizer", set_optimizer, METH_O, NULL}, -- {"new_counter_optimizer", new_counter_optimizer, METH_NOARGS, NULL}, -- {"new_uop_optimizer", new_uop_optimizer, METH_NOARGS, NULL}, - {"add_executor_dependency", add_executor_dependency, METH_VARARGS, NULL}, - {"invalidate_executors", invalidate_executors, METH_O, NULL}, - #endif -@@ -2139,6 +2068,7 @@ - {"get_rare_event_counters", get_rare_event_counters, METH_NOARGS}, - {"reset_rare_event_counters", reset_rare_event_counters, METH_NOARGS}, - {"has_inline_values", has_inline_values, METH_O}, -+ {"has_split_table", has_split_table, METH_O}, - {"type_assign_specific_version_unsafe", type_assign_specific_version_unsafe, METH_VARARGS, - PyDoc_STR("forcefully assign type->tp_version_tag")}, - -@@ -2208,6 +2138,21 @@ - return 1; - } - -+ if (PyModule_Add(module, "SPECIALIZATION_THRESHOLD", -+ PyLong_FromLong(ADAPTIVE_WARMUP_VALUE + 1)) < 0) { -+ return 1; -+ } -+ -+ if (PyModule_Add(module, "SPECIALIZATION_COOLDOWN", -+ PyLong_FromLong(ADAPTIVE_COOLDOWN_VALUE + 1)) < 0) { -+ return 1; -+ } -+ -+ if (PyModule_Add(module, "SHARED_KEYS_MAX_SIZE", -+ PyLong_FromLong(SHARED_KEYS_MAX_SIZE)) < 0) { -+ return 1; -+ } -+ - return 0; - } - -diff --git a/Modules/_testlimitedcapi.c b/Modules/_testlimitedcapi.c -index ba83a23117b..4dae99ec92a 100644 ---- a/Modules/_testlimitedcapi.c -+++ b/Modules/_testlimitedcapi.c -@@ -56,6 +56,9 @@ - if (_PyTestLimitedCAPI_Init_HeaptypeRelative(mod) < 0) { - return NULL; - } -+ if (_PyTestLimitedCAPI_Init_Import(mod) < 0) { -+ return NULL; -+ } - if (_PyTestLimitedCAPI_Init_List(mod) < 0) { - return NULL; - } -@@ -83,5 +86,11 @@ - if (_PyTestLimitedCAPI_Init_VectorcallLimited(mod) < 0) { - return NULL; - } -+ if (_PyTestLimitedCAPI_Init_Version(mod) < 0) { -+ return NULL; -+ } -+ if (_PyTestLimitedCAPI_Init_File(mod) < 0) { -+ return NULL; -+ } - return mod; - } ---- /dev/null -+++ b/Modules/_testlimitedcapi/clinic/file.c.h -@@ -0,0 +1,81 @@ -+/*[clinic input] -+preserve -+[clinic start generated code]*/ -+ -+PyDoc_STRVAR(_testcapi_pyfile_getline__doc__, -+"pyfile_getline($module, file, n, /)\n" -+"--\n" -+"\n"); -+ -+#define _TESTCAPI_PYFILE_GETLINE_METHODDEF \ -+ {"pyfile_getline", (PyCFunction)(void(*)(void))_testcapi_pyfile_getline, METH_FASTCALL, _testcapi_pyfile_getline__doc__}, -+ -+static PyObject * -+_testcapi_pyfile_getline_impl(PyObject *module, PyObject *file, int n); -+ -+static PyObject * -+_testcapi_pyfile_getline(PyObject *module, PyObject *const *args, Py_ssize_t nargs) -+{ -+ PyObject *return_value = NULL; -+ PyObject *file; -+ int n; -+ -+ if (nargs != 2) { -+ PyErr_Format(PyExc_TypeError, "pyfile_getline expected 2 arguments, got %zd", nargs); -+ goto exit; -+ } -+ file = args[0]; -+ n = PyLong_AsInt(args[1]); -+ if (n == -1 && PyErr_Occurred()) { -+ goto exit; -+ } -+ return_value = _testcapi_pyfile_getline_impl(module, file, n); -+ -+exit: -+ return return_value; -+} -+ -+PyDoc_STRVAR(_testcapi_pyfile_writeobject__doc__, -+"pyfile_writeobject($module, obj, file, flags, /)\n" -+"--\n" -+"\n"); -+ -+#define _TESTCAPI_PYFILE_WRITEOBJECT_METHODDEF \ -+ {"pyfile_writeobject", (PyCFunction)(void(*)(void))_testcapi_pyfile_writeobject, METH_FASTCALL, _testcapi_pyfile_writeobject__doc__}, -+ -+static PyObject * -+_testcapi_pyfile_writeobject_impl(PyObject *module, PyObject *obj, -+ PyObject *file, int flags); -+ -+static PyObject * -+_testcapi_pyfile_writeobject(PyObject *module, PyObject *const *args, Py_ssize_t nargs) -+{ -+ PyObject *return_value = NULL; -+ PyObject *obj; -+ PyObject *file; -+ int flags; -+ -+ if (nargs != 3) { -+ PyErr_Format(PyExc_TypeError, "pyfile_writeobject expected 3 arguments, got %zd", nargs); -+ goto exit; -+ } -+ obj = args[0]; -+ file = args[1]; -+ flags = PyLong_AsInt(args[2]); -+ if (flags == -1 && PyErr_Occurred()) { -+ goto exit; -+ } -+ return_value = _testcapi_pyfile_writeobject_impl(module, obj, file, flags); -+ -+exit: -+ return return_value; -+} -+ -+PyDoc_STRVAR(_testcapi_pyobject_asfiledescriptor__doc__, -+"pyobject_asfiledescriptor($module, obj, /)\n" -+"--\n" -+"\n"); -+ -+#define _TESTCAPI_PYOBJECT_ASFILEDESCRIPTOR_METHODDEF \ -+ {"pyobject_asfiledescriptor", (PyCFunction)_testcapi_pyobject_asfiledescriptor, METH_O, _testcapi_pyobject_asfiledescriptor__doc__}, -+/*[clinic end generated code: output=ea572aaaa01aec7b input=a9049054013a1b77]*/ ---- /dev/null -+++ b/Modules/_testlimitedcapi/clinic/version.c.h -@@ -0,0 +1,93 @@ -+/*[clinic input] -+preserve -+[clinic start generated code]*/ -+ -+PyDoc_STRVAR(_testlimitedcapi_pack_full_version__doc__, -+"pack_full_version($module, major, minor, micro, level, serial, /)\n" -+"--\n" -+"\n"); -+ -+#define _TESTLIMITEDCAPI_PACK_FULL_VERSION_METHODDEF \ -+ {"pack_full_version", (PyCFunction)(void(*)(void))_testlimitedcapi_pack_full_version, METH_FASTCALL, _testlimitedcapi_pack_full_version__doc__}, -+ -+static PyObject * -+_testlimitedcapi_pack_full_version_impl(PyObject *module, int major, -+ int minor, int micro, int level, -+ int serial); -+ -+static PyObject * -+_testlimitedcapi_pack_full_version(PyObject *module, PyObject *const *args, Py_ssize_t nargs) -+{ -+ PyObject *return_value = NULL; -+ int major; -+ int minor; -+ int micro; -+ int level; -+ int serial; -+ -+ if (nargs != 5) { -+ PyErr_Format(PyExc_TypeError, "pack_full_version expected 5 arguments, got %zd", nargs); -+ goto exit; -+ } -+ major = PyLong_AsInt(args[0]); -+ if (major == -1 && PyErr_Occurred()) { -+ goto exit; -+ } -+ minor = PyLong_AsInt(args[1]); -+ if (minor == -1 && PyErr_Occurred()) { -+ goto exit; -+ } -+ micro = PyLong_AsInt(args[2]); -+ if (micro == -1 && PyErr_Occurred()) { -+ goto exit; -+ } -+ level = PyLong_AsInt(args[3]); -+ if (level == -1 && PyErr_Occurred()) { -+ goto exit; -+ } -+ serial = PyLong_AsInt(args[4]); -+ if (serial == -1 && PyErr_Occurred()) { -+ goto exit; -+ } -+ return_value = _testlimitedcapi_pack_full_version_impl(module, major, minor, micro, level, serial); -+ -+exit: -+ return return_value; -+} -+ -+PyDoc_STRVAR(_testlimitedcapi_pack_version__doc__, -+"pack_version($module, major, minor, /)\n" -+"--\n" -+"\n"); -+ -+#define _TESTLIMITEDCAPI_PACK_VERSION_METHODDEF \ -+ {"pack_version", (PyCFunction)(void(*)(void))_testlimitedcapi_pack_version, METH_FASTCALL, _testlimitedcapi_pack_version__doc__}, -+ -+static PyObject * -+_testlimitedcapi_pack_version_impl(PyObject *module, int major, int minor); -+ -+static PyObject * -+_testlimitedcapi_pack_version(PyObject *module, PyObject *const *args, Py_ssize_t nargs) -+{ -+ PyObject *return_value = NULL; -+ int major; -+ int minor; -+ -+ if (nargs != 2) { -+ PyErr_Format(PyExc_TypeError, "pack_version expected 2 arguments, got %zd", nargs); -+ goto exit; -+ } -+ major = PyLong_AsInt(args[0]); -+ if (major == -1 && PyErr_Occurred()) { -+ goto exit; -+ } -+ minor = PyLong_AsInt(args[1]); -+ if (minor == -1 && PyErr_Occurred()) { -+ goto exit; -+ } -+ return_value = _testlimitedcapi_pack_version_impl(module, major, minor); -+ -+exit: -+ return return_value; -+} -+/*[clinic end generated code: output=aed3e226da77f2d2 input=a9049054013a1b77]*/ ---- /dev/null -+++ b/Modules/_testlimitedcapi/file.c -@@ -0,0 +1,128 @@ -+#include "pyconfig.h" // Py_GIL_DISABLED -+#ifndef Py_GIL_DISABLED -+ // Need limited C API 3.13 for PyLong_AsInt() -+# define Py_LIMITED_API 0x030d0000 -+#endif -+ -+#include "parts.h" -+#include "util.h" -+#include "clinic/file.c.h" -+ -+ -+/*[clinic input] -+module _testcapi -+[clinic start generated code]*/ -+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=6361033e795369fc]*/ -+ -+ -+static PyObject * -+pyfile_fromfd(PyObject *module, PyObject *args) -+{ -+ int fd; -+ const char *name; -+ Py_ssize_t size; -+ const char *mode; -+ int buffering; -+ const char *encoding; -+ const char *errors; -+ const char *newline; -+ int closefd; -+ if (!PyArg_ParseTuple(args, -+ "iz#z#" -+ "iz#z#" -+ "z#i", -+ &fd, &name, &size, &mode, &size, -+ &buffering, &encoding, &size, &errors, &size, -+ &newline, &size, &closefd)) { -+ return NULL; -+ } -+ -+ return PyFile_FromFd(fd, name, mode, buffering, -+ encoding, errors, newline, closefd); -+} -+ -+ -+/*[clinic input] -+_testcapi.pyfile_getline -+ -+ file: object -+ n: int -+ / -+ -+[clinic start generated code]*/ -+ -+static PyObject * -+_testcapi_pyfile_getline_impl(PyObject *module, PyObject *file, int n) -+/*[clinic end generated code: output=137fde2774563266 input=df26686148b3657e]*/ -+{ -+ return PyFile_GetLine(file, n); -+} -+ -+ -+/*[clinic input] -+_testcapi.pyfile_writeobject -+ -+ obj: object -+ file: object -+ flags: int -+ / -+ -+[clinic start generated code]*/ -+ -+static PyObject * -+_testcapi_pyfile_writeobject_impl(PyObject *module, PyObject *obj, -+ PyObject *file, int flags) -+/*[clinic end generated code: output=ebb4d802e3db489c input=64a34a3e75b9935a]*/ -+{ -+ NULLABLE(obj); -+ NULLABLE(file); -+ RETURN_INT(PyFile_WriteObject(obj, file, flags)); -+} -+ -+ -+static PyObject * -+pyfile_writestring(PyObject *module, PyObject *args) -+{ -+ const char *str; -+ Py_ssize_t size; -+ PyObject *file; -+ if (!PyArg_ParseTuple(args, "z#O", &str, &size, &file)) { -+ return NULL; -+ } -+ NULLABLE(file); -+ -+ RETURN_INT(PyFile_WriteString(str, file)); -+} -+ -+ -+/*[clinic input] -+_testcapi.pyobject_asfiledescriptor -+ -+ obj: object -+ / -+ -+[clinic start generated code]*/ -+ -+static PyObject * -+_testcapi_pyobject_asfiledescriptor(PyObject *module, PyObject *obj) -+/*[clinic end generated code: output=2d640c6a1970c721 input=45fa1171d62b18d7]*/ -+{ -+ NULLABLE(obj); -+ RETURN_INT(PyObject_AsFileDescriptor(obj)); -+} -+ -+ -+static PyMethodDef test_methods[] = { -+ {"pyfile_fromfd", pyfile_fromfd, METH_VARARGS}, -+ _TESTCAPI_PYFILE_GETLINE_METHODDEF -+ _TESTCAPI_PYFILE_WRITEOBJECT_METHODDEF -+ {"pyfile_writestring", pyfile_writestring, METH_VARARGS}, -+ _TESTCAPI_PYOBJECT_ASFILEDESCRIPTOR_METHODDEF -+ {NULL}, -+}; -+ -+int -+_PyTestLimitedCAPI_Init_File(PyObject *m) -+{ -+ return PyModule_AddFunctions(m, test_methods); -+} ---- /dev/null -+++ b/Modules/_testlimitedcapi/import.c -@@ -0,0 +1,306 @@ -+// Need limited C API version 3.13 for PyImport_AddModuleRef() -+#include "pyconfig.h" // Py_GIL_DISABLED -+#if !defined(Py_GIL_DISABLED) && !defined(Py_LIMITED_API) -+# define Py_LIMITED_API 0x030d0000 -+#endif -+ -+#include "parts.h" -+#include "util.h" -+ -+ -+/* Test PyImport_GetMagicNumber() */ -+static PyObject * -+pyimport_getmagicnumber(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) -+{ -+ long magic = PyImport_GetMagicNumber(); -+ return PyLong_FromLong(magic); -+} -+ -+ -+/* Test PyImport_GetMagicTag() */ -+static PyObject * -+pyimport_getmagictag(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) -+{ -+ const char *tag = PyImport_GetMagicTag(); -+ return PyUnicode_FromString(tag); -+} -+ -+ -+/* Test PyImport_GetModuleDict() */ -+static PyObject * -+pyimport_getmoduledict(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) -+{ -+ return Py_XNewRef(PyImport_GetModuleDict()); -+} -+ -+ -+/* Test PyImport_GetModule() */ -+static PyObject * -+pyimport_getmodule(PyObject *Py_UNUSED(module), PyObject *name) -+{ -+ assert(!PyErr_Occurred()); -+ NULLABLE(name); -+ PyObject *module = PyImport_GetModule(name); -+ if (module == NULL && !PyErr_Occurred()) { -+ return Py_NewRef(PyExc_KeyError); -+ } -+ return module; -+} -+ -+ -+/* Test PyImport_AddModuleObject() */ -+static PyObject * -+pyimport_addmoduleobject(PyObject *Py_UNUSED(module), PyObject *name) -+{ -+ NULLABLE(name); -+ return Py_XNewRef(PyImport_AddModuleObject(name)); -+} -+ -+ -+/* Test PyImport_AddModule() */ -+static PyObject * -+pyimport_addmodule(PyObject *Py_UNUSED(module), PyObject *args) -+{ -+ const char *name; -+ Py_ssize_t size; -+ if (!PyArg_ParseTuple(args, "z#", &name, &size)) { -+ return NULL; -+ } -+ -+ return Py_XNewRef(PyImport_AddModule(name)); -+} -+ -+ -+/* Test PyImport_AddModuleRef() */ -+static PyObject * -+pyimport_addmoduleref(PyObject *Py_UNUSED(module), PyObject *args) -+{ -+ const char *name; -+ Py_ssize_t size; -+ if (!PyArg_ParseTuple(args, "z#", &name, &size)) { -+ return NULL; -+ } -+ -+ return PyImport_AddModuleRef(name); -+} -+ -+ -+/* Test PyImport_Import() */ -+static PyObject * -+pyimport_import(PyObject *Py_UNUSED(module), PyObject *name) -+{ -+ NULLABLE(name); -+ return PyImport_Import(name); -+} -+ -+ -+/* Test PyImport_ImportModule() */ -+static PyObject * -+pyimport_importmodule(PyObject *Py_UNUSED(module), PyObject *args) -+{ -+ const char *name; -+ Py_ssize_t size; -+ if (!PyArg_ParseTuple(args, "z#", &name, &size)) { -+ return NULL; -+ } -+ -+ return PyImport_ImportModule(name); -+} -+ -+ -+/* Test PyImport_ImportModuleNoBlock() */ -+static PyObject * -+pyimport_importmodulenoblock(PyObject *Py_UNUSED(module), PyObject *args) -+{ -+ const char *name; -+ Py_ssize_t size; -+ if (!PyArg_ParseTuple(args, "z#", &name, &size)) { -+ return NULL; -+ } -+ -+ _Py_COMP_DIAG_PUSH -+ _Py_COMP_DIAG_IGNORE_DEPR_DECLS -+ return PyImport_ImportModuleNoBlock(name); -+ _Py_COMP_DIAG_POP -+} -+ -+ -+/* Test PyImport_ImportModuleEx() */ -+static PyObject * -+pyimport_importmoduleex(PyObject *Py_UNUSED(module), PyObject *args) -+{ -+ const char *name; -+ Py_ssize_t size; -+ PyObject *globals, *locals, *fromlist; -+ if (!PyArg_ParseTuple(args, "z#OOO", -+ &name, &size, &globals, &locals, &fromlist)) { -+ return NULL; -+ } -+ NULLABLE(globals); -+ NULLABLE(locals); -+ NULLABLE(fromlist); -+ -+ return PyImport_ImportModuleEx(name, globals, locals, fromlist); -+} -+ -+ -+/* Test PyImport_ImportModuleLevel() */ -+static PyObject * -+pyimport_importmodulelevel(PyObject *Py_UNUSED(module), PyObject *args) -+{ -+ const char *name; -+ Py_ssize_t size; -+ PyObject *globals, *locals, *fromlist; -+ int level; -+ if (!PyArg_ParseTuple(args, "z#OOOi", -+ &name, &size, &globals, &locals, &fromlist, &level)) { -+ return NULL; -+ } -+ NULLABLE(globals); -+ NULLABLE(locals); -+ NULLABLE(fromlist); -+ -+ return PyImport_ImportModuleLevel(name, globals, locals, fromlist, level); -+} -+ -+ -+/* Test PyImport_ImportModuleLevelObject() */ -+static PyObject * -+pyimport_importmodulelevelobject(PyObject *Py_UNUSED(module), PyObject *args) -+{ -+ PyObject *name, *globals, *locals, *fromlist; -+ int level; -+ if (!PyArg_ParseTuple(args, "OOOOi", -+ &name, &globals, &locals, &fromlist, &level)) { -+ return NULL; -+ } -+ NULLABLE(name); -+ NULLABLE(globals); -+ NULLABLE(locals); -+ NULLABLE(fromlist); -+ -+ return PyImport_ImportModuleLevelObject(name, globals, locals, fromlist, level); -+} -+ -+ -+/* Test PyImport_ImportFrozenModule() */ -+static PyObject * -+pyimport_importfrozenmodule(PyObject *Py_UNUSED(module), PyObject *args) -+{ -+ const char *name; -+ Py_ssize_t size; -+ if (!PyArg_ParseTuple(args, "z#", &name, &size)) { -+ return NULL; -+ } -+ -+ RETURN_INT(PyImport_ImportFrozenModule(name)); -+} -+ -+ -+/* Test PyImport_ImportFrozenModuleObject() */ -+static PyObject * -+pyimport_importfrozenmoduleobject(PyObject *Py_UNUSED(module), PyObject *name) -+{ -+ NULLABLE(name); -+ RETURN_INT(PyImport_ImportFrozenModuleObject(name)); -+} -+ -+ -+/* Test PyImport_ExecCodeModule() */ -+static PyObject * -+pyimport_executecodemodule(PyObject *Py_UNUSED(module), PyObject *args) -+{ -+ const char *name; -+ Py_ssize_t size; -+ PyObject *code; -+ if (!PyArg_ParseTuple(args, "z#O", &name, &size, &code)) { -+ return NULL; -+ } -+ NULLABLE(code); -+ -+ return PyImport_ExecCodeModule(name, code); -+} -+ -+ -+/* Test PyImport_ExecCodeModuleEx() */ -+static PyObject * -+pyimport_executecodemoduleex(PyObject *Py_UNUSED(module), PyObject *args) -+{ -+ const char *name; -+ Py_ssize_t size; -+ PyObject *code; -+ const char *pathname; -+ if (!PyArg_ParseTuple(args, "z#Oz#", &name, &size, &code, &pathname, &size)) { -+ return NULL; -+ } -+ NULLABLE(code); -+ -+ return PyImport_ExecCodeModuleEx(name, code, pathname); -+} -+ -+ -+/* Test PyImport_ExecCodeModuleWithPathnames() */ -+static PyObject * -+pyimport_executecodemodulewithpathnames(PyObject *Py_UNUSED(module), PyObject *args) -+{ -+ const char *name; -+ Py_ssize_t size; -+ PyObject *code; -+ const char *pathname; -+ const char *cpathname; -+ if (!PyArg_ParseTuple(args, "z#Oz#z#", &name, &size, &code, &pathname, &size, &cpathname, &size)) { -+ return NULL; -+ } -+ NULLABLE(code); -+ -+ return PyImport_ExecCodeModuleWithPathnames(name, code, -+ pathname, cpathname); -+} -+ -+ -+/* Test PyImport_ExecCodeModuleObject() */ -+static PyObject * -+pyimport_executecodemoduleobject(PyObject *Py_UNUSED(module), PyObject *args) -+{ -+ PyObject *name, *code, *pathname, *cpathname; -+ if (!PyArg_ParseTuple(args, "OOOO", &name, &code, &pathname, &cpathname)) { -+ return NULL; -+ } -+ NULLABLE(name); -+ NULLABLE(code); -+ NULLABLE(pathname); -+ NULLABLE(cpathname); -+ -+ return PyImport_ExecCodeModuleObject(name, code, pathname, cpathname); -+} -+ -+ -+static PyMethodDef test_methods[] = { -+ {"PyImport_GetMagicNumber", pyimport_getmagicnumber, METH_NOARGS}, -+ {"PyImport_GetMagicTag", pyimport_getmagictag, METH_NOARGS}, -+ {"PyImport_GetModuleDict", pyimport_getmoduledict, METH_NOARGS}, -+ {"PyImport_GetModule", pyimport_getmodule, METH_O}, -+ {"PyImport_AddModuleObject", pyimport_addmoduleobject, METH_O}, -+ {"PyImport_AddModule", pyimport_addmodule, METH_VARARGS}, -+ {"PyImport_AddModuleRef", pyimport_addmoduleref, METH_VARARGS}, -+ {"PyImport_Import", pyimport_import, METH_O}, -+ {"PyImport_ImportModule", pyimport_importmodule, METH_VARARGS}, -+ {"PyImport_ImportModuleNoBlock", pyimport_importmodulenoblock, METH_VARARGS}, -+ {"PyImport_ImportModuleEx", pyimport_importmoduleex, METH_VARARGS}, -+ {"PyImport_ImportModuleLevel", pyimport_importmodulelevel, METH_VARARGS}, -+ {"PyImport_ImportModuleLevelObject", pyimport_importmodulelevelobject, METH_VARARGS}, -+ {"PyImport_ImportFrozenModule", pyimport_importfrozenmodule, METH_VARARGS}, -+ {"PyImport_ImportFrozenModuleObject", pyimport_importfrozenmoduleobject, METH_O}, -+ {"PyImport_ExecCodeModule", pyimport_executecodemodule, METH_VARARGS}, -+ {"PyImport_ExecCodeModuleEx", pyimport_executecodemoduleex, METH_VARARGS}, -+ {"PyImport_ExecCodeModuleWithPathnames", pyimport_executecodemodulewithpathnames, METH_VARARGS}, -+ {"PyImport_ExecCodeModuleObject", pyimport_executecodemoduleobject, METH_VARARGS}, -+ {NULL}, -+}; -+ -+ -+int -+_PyTestLimitedCAPI_Init_Import(PyObject *module) -+{ -+ return PyModule_AddFunctions(module, test_methods); -+} -diff --git a/Modules/_testlimitedcapi/parts.h b/Modules/_testlimitedcapi/parts.h -index 4107b150c5b..60f6f03011a 100644 ---- a/Modules/_testlimitedcapi/parts.h -+++ b/Modules/_testlimitedcapi/parts.h -@@ -31,6 +31,7 @@ - int _PyTestLimitedCAPI_Init_Eval(PyObject *module); - int _PyTestLimitedCAPI_Init_Float(PyObject *module); - int _PyTestLimitedCAPI_Init_HeaptypeRelative(PyObject *module); -+int _PyTestLimitedCAPI_Init_Import(PyObject *module); - int _PyTestLimitedCAPI_Init_Object(PyObject *module); - int _PyTestLimitedCAPI_Init_List(PyObject *module); - int _PyTestLimitedCAPI_Init_Long(PyObject *module); -@@ -40,5 +41,7 @@ - int _PyTestLimitedCAPI_Init_Tuple(PyObject *module); - int _PyTestLimitedCAPI_Init_Unicode(PyObject *module); - int _PyTestLimitedCAPI_Init_VectorcallLimited(PyObject *module); -+int _PyTestLimitedCAPI_Init_Version(PyObject *module); -+int _PyTestLimitedCAPI_Init_File(PyObject *module); - - #endif // Py_TESTLIMITEDCAPI_PARTS_H ---- /dev/null -+++ b/Modules/_testlimitedcapi/version.c -@@ -0,0 +1,77 @@ -+/* Test version macros in the limited API */ -+ -+#include "pyconfig.h" // Py_GIL_DISABLED -+#ifndef Py_GIL_DISABLED -+# define Py_LIMITED_API 0x030e0000 // Added in 3.14 -+#endif -+ -+#include "parts.h" -+#include "clinic/version.c.h" -+#include -+ -+/*[clinic input] -+module _testlimitedcapi -+[clinic start generated code]*/ -+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=2700057f9c1135ba]*/ -+ -+/*[clinic input] -+_testlimitedcapi.pack_full_version -+ -+ major: int -+ minor: int -+ micro: int -+ level: int -+ serial: int -+ / -+[clinic start generated code]*/ -+ -+static PyObject * -+_testlimitedcapi_pack_full_version_impl(PyObject *module, int major, -+ int minor, int micro, int level, -+ int serial) -+/*[clinic end generated code: output=b87a1e9805648861 input=2a304423be61d2ac]*/ -+{ -+ uint32_t macro_result = Py_PACK_FULL_VERSION( -+ major, minor, micro, level, serial); -+#undef Py_PACK_FULL_VERSION -+ uint32_t func_result = Py_PACK_FULL_VERSION( -+ major, minor, micro, level, serial); -+ -+ assert(macro_result == func_result); -+ return PyLong_FromUnsignedLong((unsigned long)func_result); -+} -+ -+/*[clinic input] -+_testlimitedcapi.pack_version -+ -+ major: int -+ minor: int -+ / -+[clinic start generated code]*/ -+ -+static PyObject * -+_testlimitedcapi_pack_version_impl(PyObject *module, int major, int minor) -+/*[clinic end generated code: output=771247bbd06e7883 input=3e39e9dcbc09e86a]*/ -+{ -+ uint32_t macro_result = Py_PACK_VERSION(major, minor); -+#undef Py_PACK_VERSION -+ uint32_t func_result = Py_PACK_VERSION(major, minor); -+ -+ assert(macro_result == func_result); -+ return PyLong_FromUnsignedLong((unsigned long)func_result); -+} -+ -+static PyMethodDef TestMethods[] = { -+ _TESTLIMITEDCAPI_PACK_FULL_VERSION_METHODDEF -+ _TESTLIMITEDCAPI_PACK_VERSION_METHODDEF -+ {NULL}, -+}; -+ -+int -+_PyTestLimitedCAPI_Init_Version(PyObject *m) -+{ -+ if (PyModule_AddFunctions(m, TestMethods) < 0) { -+ return -1; -+ } -+ return 0; -+} -diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c -index 75b34a8df76..e251736fb36 100644 ---- a/Modules/_threadmodule.c -+++ b/Modules/_threadmodule.c -@@ -47,6 +47,14 @@ - } - - -+#ifdef MS_WINDOWS -+typedef HRESULT (WINAPI *PF_GET_THREAD_DESCRIPTION)(HANDLE, PCWSTR*); -+typedef HRESULT (WINAPI *PF_SET_THREAD_DESCRIPTION)(HANDLE, PCWSTR); -+static PF_GET_THREAD_DESCRIPTION pGetThreadDescription = NULL; -+static PF_SET_THREAD_DESCRIPTION pSetThreadDescription = NULL; -+#endif -+ -+ - /*[clinic input] - module _thread - [clinic start generated code]*/ -@@ -1414,6 +1422,10 @@ - return NULL; - } - -+ // gh-128691: Use deferred reference counting for thread-locals to avoid -+ // contention on the shared object. -+ _PyObject_SetDeferredRefcount((PyObject *)self); -+ - self->args = Py_XNewRef(args); - self->kw = Py_XNewRef(kw); - -@@ -1527,17 +1539,20 @@ - goto err; - } - -- if (PyDict_SetItem(self->localdicts, tstate->threading_local_key, ldict) < -- 0) { -+ if (PyDict_SetItem(self->localdicts, tstate->threading_local_key, -+ ldict) < 0) -+ { - goto err; - } - - wr = create_sentinel_wr(self); - if (wr == NULL) { - PyObject *exc = PyErr_GetRaisedException(); -- if (PyDict_DelItem(self->localdicts, tstate->threading_local_key) < -- 0) { -- PyErr_WriteUnraisable((PyObject *)self); -+ if (PyDict_DelItem(self->localdicts, -+ tstate->threading_local_key) < 0) -+ { -+ PyErr_FormatUnraisable("Exception ignored while deleting " -+ "thread local of %R", self); - } - PyErr_SetRaisedException(exc); - goto err; -@@ -1545,9 +1560,11 @@ - - if (PySet_Add(self->thread_watchdogs, wr) < 0) { - PyObject *exc = PyErr_GetRaisedException(); -- if (PyDict_DelItem(self->localdicts, tstate->threading_local_key) < -- 0) { -- PyErr_WriteUnraisable((PyObject *)self); -+ if (PyDict_DelItem(self->localdicts, -+ tstate->threading_local_key) < 0) -+ { -+ PyErr_FormatUnraisable("Exception ignored while deleting " -+ "thread local of %R", self); - } - PyErr_SetRaisedException(exc); - goto err; -@@ -1597,13 +1614,16 @@ - we create a new one the next time we do an attr - access */ - PyObject *exc = PyErr_GetRaisedException(); -- if (PyDict_DelItem(self->localdicts, tstate->threading_local_key) < -- 0) { -- PyErr_WriteUnraisable((PyObject *)self); -- PyErr_Clear(); -+ if (PyDict_DelItem(self->localdicts, -+ tstate->threading_local_key) < 0) -+ { -+ PyErr_FormatUnraisable("Exception ignored while deleting " -+ "thread local of %R", self); -+ assert(!PyErr_Occurred()); - } - if (PySet_Discard(self->thread_watchdogs, wr) < 0) { -- PyErr_WriteUnraisable((PyObject *)self); -+ PyErr_FormatUnraisable("Exception ignored while discarding " -+ "thread watchdog of %R", self); - } - PyErr_SetRaisedException(exc); - Py_DECREF(ldict); -@@ -1734,12 +1754,14 @@ - if (self->localdicts != NULL) { - PyObject *key = PyTuple_GetItem(locals_and_key, 1); - if (PyDict_Pop(self->localdicts, key, NULL) < 0) { -- PyErr_WriteUnraisable((PyObject*)self); -+ PyErr_FormatUnraisable("Exception ignored while clearing " -+ "thread local %R", (PyObject *)self); - } - } - if (self->thread_watchdogs != NULL) { - if (PySet_Discard(self->thread_watchdogs, dummyweakref) < 0) { -- PyErr_WriteUnraisable((PyObject *)self); -+ PyErr_FormatUnraisable("Exception ignored while clearing " -+ "thread local %R", (PyObject *)self); - } - } - -@@ -2302,7 +2324,8 @@ - // Wait for the thread to finish. If we're interrupted, such - // as by a ctrl-c we print the error and exit early. - if (ThreadHandle_join(handle, -1) < 0) { -- PyErr_WriteUnraisable(NULL); -+ PyErr_FormatUnraisable("Exception ignored while joining a thread " -+ "in _thread._shutdown()"); - ThreadHandle_decref(handle); - Py_RETURN_NONE; - } -@@ -2364,7 +2387,7 @@ - of the main interpreter."); - - --#ifdef HAVE_PTHREAD_GETNAME_NP -+#if defined(HAVE_PTHREAD_GETNAME_NP) || defined(MS_WINDOWS) - /*[clinic input] - _thread._get_name - -@@ -2375,6 +2398,7 @@ - _thread__get_name_impl(PyObject *module) - /*[clinic end generated code: output=20026e7ee3da3dd7 input=35cec676833d04c8]*/ - { -+#ifndef MS_WINDOWS - // Linux and macOS are limited to respectively 16 and 64 bytes - char name[100]; - pthread_t thread = pthread_self(); -@@ -2389,11 +2413,26 @@ - #else - return PyUnicode_DecodeFSDefault(name); - #endif -+#else -+ // Windows implementation -+ assert(pGetThreadDescription != NULL); -+ -+ wchar_t *name; -+ HRESULT hr = pGetThreadDescription(GetCurrentThread(), &name); -+ if (FAILED(hr)) { -+ PyErr_SetFromWindowsErr(0); -+ return NULL; -+ } -+ -+ PyObject *name_obj = PyUnicode_FromWideChar(name, -1); -+ LocalFree(name); -+ return name_obj; -+#endif - } - #endif // HAVE_PTHREAD_GETNAME_NP - - --#ifdef HAVE_PTHREAD_SETNAME_NP -+#if defined(HAVE_PTHREAD_SETNAME_NP) || defined(MS_WINDOWS) - /*[clinic input] - _thread.set_name - -@@ -2406,6 +2445,7 @@ - _thread_set_name_impl(PyObject *module, PyObject *name_obj) - /*[clinic end generated code: output=402b0c68e0c0daed input=7e7acd98261be82f]*/ - { -+#ifndef MS_WINDOWS - #ifdef __sun - // Solaris always uses UTF-8 - const char *encoding = "utf-8"; -@@ -2421,12 +2461,12 @@ - return NULL; - } - --#ifdef PYTHREAD_NAME_MAXLEN -- // Truncate to PYTHREAD_NAME_MAXLEN bytes + the NUL byte if needed -- if (PyBytes_GET_SIZE(name_encoded) > PYTHREAD_NAME_MAXLEN) { -+#ifdef _PYTHREAD_NAME_MAXLEN -+ // Truncate to _PYTHREAD_NAME_MAXLEN bytes + the NUL byte if needed -+ if (PyBytes_GET_SIZE(name_encoded) > _PYTHREAD_NAME_MAXLEN) { - PyObject *truncated; - truncated = PyBytes_FromStringAndSize(PyBytes_AS_STRING(name_encoded), -- PYTHREAD_NAME_MAXLEN); -+ _PYTHREAD_NAME_MAXLEN); - if (truncated == NULL) { - Py_DECREF(name_encoded); - return NULL; -@@ -2438,6 +2478,9 @@ - const char *name = PyBytes_AS_STRING(name_encoded); - #ifdef __APPLE__ - int rc = pthread_setname_np(name); -+#elif defined(__NetBSD__) -+ pthread_t thread = pthread_self(); -+ int rc = pthread_setname_np(thread, "%s", (void *)name); - #else - pthread_t thread = pthread_self(); - int rc = pthread_setname_np(thread, name); -@@ -2448,6 +2491,35 @@ - return PyErr_SetFromErrno(PyExc_OSError); - } - Py_RETURN_NONE; -+#else -+ // Windows implementation -+ assert(pSetThreadDescription != NULL); -+ -+ Py_ssize_t len; -+ wchar_t *name = PyUnicode_AsWideCharString(name_obj, &len); -+ if (name == NULL) { -+ return NULL; -+ } -+ -+ if (len > _PYTHREAD_NAME_MAXLEN) { -+ // Truncate the name -+ Py_UCS4 ch = name[_PYTHREAD_NAME_MAXLEN-1]; -+ if (Py_UNICODE_IS_HIGH_SURROGATE(ch)) { -+ name[_PYTHREAD_NAME_MAXLEN-1] = 0; -+ } -+ else { -+ name[_PYTHREAD_NAME_MAXLEN] = 0; -+ } -+ } -+ -+ HRESULT hr = pSetThreadDescription(GetCurrentThread(), name); -+ PyMem_Free(name); -+ if (FAILED(hr)) { -+ PyErr_SetFromWindowsErr((int)hr); -+ return NULL; -+ } -+ Py_RETURN_NONE; -+#endif - } - #endif // HAVE_PTHREAD_SETNAME_NP - -@@ -2584,13 +2656,38 @@ - - llist_init(&state->shutdown_handles); - --#ifdef PYTHREAD_NAME_MAXLEN -+#ifdef _PYTHREAD_NAME_MAXLEN - if (PyModule_AddIntConstant(module, "_NAME_MAXLEN", -- PYTHREAD_NAME_MAXLEN) < 0) { -+ _PYTHREAD_NAME_MAXLEN) < 0) { - return -1; - } - #endif - -+#ifdef MS_WINDOWS -+ HMODULE kernelbase = GetModuleHandleW(L"kernelbase.dll"); -+ if (kernelbase != NULL) { -+ if (pGetThreadDescription == NULL) { -+ pGetThreadDescription = (PF_GET_THREAD_DESCRIPTION)GetProcAddress( -+ kernelbase, "GetThreadDescription"); -+ } -+ if (pSetThreadDescription == NULL) { -+ pSetThreadDescription = (PF_SET_THREAD_DESCRIPTION)GetProcAddress( -+ kernelbase, "SetThreadDescription"); -+ } -+ } -+ -+ if (pGetThreadDescription == NULL) { -+ if (PyObject_DelAttrString(module, "_get_name") < 0) { -+ return -1; -+ } -+ } -+ if (pSetThreadDescription == NULL) { -+ if (PyObject_DelAttrString(module, "set_name") < 0) { -+ return -1; -+ } -+ } -+#endif -+ - return 0; - } - -diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c -index 887a1e820e2..be71fc9fc9c 100644 ---- a/Modules/_tracemalloc.c -+++ b/Modules/_tracemalloc.c -@@ -215,18 +215,14 @@ - PyMODINIT_FUNC - PyInit__tracemalloc(void) - { -- PyObject *m; -- m = PyModule_Create(&module_def); -- if (m == NULL) -+ PyObject *mod = PyModule_Create(&module_def); -+ if (mod == NULL) { - return NULL; -+ } -+ - #ifdef Py_GIL_DISABLED -- PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED); -+ PyUnstable_Module_SetGIL(mod, Py_MOD_GIL_NOT_USED); - #endif - -- if (_PyTraceMalloc_Init() < 0) { -- Py_DECREF(m); -- return NULL; -- } -- -- return m; -+ return mod; - } -diff --git a/Modules/_winapi.c b/Modules/_winapi.c -index 4ce689fe30e..786a828f009 100644 ---- a/Modules/_winapi.c -+++ b/Modules/_winapi.c -@@ -171,17 +171,16 @@ - { - /* The operation is no longer pending -- nothing to do. */ - } -- else if (_Py_IsInterpreterFinalizing(_PyInterpreterState_GET())) -- { -+ else if (_Py_IsInterpreterFinalizing(_PyInterpreterState_GET())) { - /* The operation is still pending -- give a warning. This - will probably only happen on Windows XP. */ - PyErr_SetString(PyExc_PythonFinalizationError, - "I/O operations still in flight while destroying " - "Overlapped object, the process may crash"); -- PyErr_WriteUnraisable(NULL); -+ PyErr_FormatUnraisable("Exception ignored while deallocating " -+ "overlapped operation %R", self); - } -- else -- { -+ else { - /* The operation is still pending, but the process is - probably about to exit, so we need not worry too much - about memory leaks. Leaking self prevents a potential -@@ -1048,7 +1047,7 @@ - } - - normalized_environment = normalize_environment(environment); -- if (normalize_environment == NULL) { -+ if (normalized_environment == NULL) { - return NULL; - } - -diff --git a/Modules/_zoneinfo.c b/Modules/_zoneinfo.c -index c5292575c22..1fcea9ce8b1 100644 ---- a/Modules/_zoneinfo.c -+++ b/Modules/_zoneinfo.c -@@ -782,7 +782,7 @@ - if (self->source == SOURCE_FILE) { - // Objects constructed from files cannot be pickled. - PyObject *pickle_error = -- _PyImport_GetModuleAttrString("pickle", "PicklingError"); -+ PyImport_ImportModuleAttrString("pickle", "PicklingError"); - if (pickle_error == NULL) { - return NULL; - } -@@ -2554,7 +2554,7 @@ - new_weak_cache(void) - { - PyObject *WeakValueDictionary = -- _PyImport_GetModuleAttrString("weakref", "WeakValueDictionary"); -+ PyImport_ImportModuleAttrString("weakref", "WeakValueDictionary"); - if (WeakValueDictionary == NULL) { - return NULL; - } -@@ -2732,12 +2732,12 @@ - - /* Populate imports */ - state->_tzpath_find_tzfile = -- _PyImport_GetModuleAttrString("zoneinfo._tzpath", "find_tzfile"); -+ PyImport_ImportModuleAttrString("zoneinfo._tzpath", "find_tzfile"); - if (state->_tzpath_find_tzfile == NULL) { - goto error; - } - -- state->io_open = _PyImport_GetModuleAttrString("io", "open"); -+ state->io_open = PyImport_ImportModuleAttrString("io", "open"); - if (state->io_open == NULL) { - goto error; - } -diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c -index b80c964f20d..5b86ec98393 100644 ---- a/Modules/arraymodule.c -+++ b/Modules/arraymodule.c -@@ -79,6 +79,9 @@ - #define get_array_state_by_class(cls) \ - (get_array_state(PyType_GetModule(cls))) - -+#define arrayobject_CAST(op) ((arrayobject *)(op)) -+#define arrayiterobject_CAST(op) ((arrayiterobject *)(op)) -+ - enum machine_format_code { - UNKNOWN_FORMAT = -1, - /* UNKNOWN_FORMAT is used to indicate that the machine format for an -@@ -712,22 +715,25 @@ - /* Methods */ - - static int --array_tp_traverse(arrayobject *op, visitproc visit, void *arg) -+array_tp_traverse(PyObject *op, visitproc visit, void *arg) - { - Py_VISIT(Py_TYPE(op)); - return 0; - } - - static void --array_dealloc(arrayobject *op) -+array_dealloc(PyObject *op) - { - PyTypeObject *tp = Py_TYPE(op); - PyObject_GC_UnTrack(op); - -- if (op->weakreflist != NULL) -- PyObject_ClearWeakRefs((PyObject *) op); -- if (op->ob_item != NULL) -- PyMem_Free(op->ob_item); -+ arrayobject *self = arrayobject_CAST(op); -+ if (self->weakreflist != NULL) { -+ PyObject_ClearWeakRefs(op); -+ } -+ if (self->ob_item != NULL) { -+ PyMem_Free(self->ob_item); -+ } - tp->tp_free(op); - Py_DECREF(tp); - } -@@ -843,19 +849,19 @@ - } - - static Py_ssize_t --array_length(arrayobject *a) -+array_length(PyObject *op) - { -- return Py_SIZE(a); -+ return Py_SIZE(op); - } - - static PyObject * --array_item(arrayobject *a, Py_ssize_t i) -+array_item(PyObject *op, Py_ssize_t i) - { -- if (i < 0 || i >= Py_SIZE(a)) { -+ if (i < 0 || i >= Py_SIZE(op)) { - PyErr_SetString(PyExc_IndexError, "array index out of range"); - return NULL; - } -- return getarrayitem((PyObject *)a, i); -+ return getarrayitem(op, i); - } - - static PyObject * -@@ -930,8 +936,9 @@ - } - - static PyObject * --array_concat(arrayobject *a, PyObject *bb) -+array_concat(PyObject *op, PyObject *bb) - { -+ arrayobject *a = arrayobject_CAST(op); - array_state *state = find_array_state_by_type(Py_TYPE(a)); - Py_ssize_t size; - arrayobject *np; -@@ -966,8 +973,9 @@ - } - - static PyObject * --array_repeat(arrayobject *a, Py_ssize_t n) -+array_repeat(PyObject *op, Py_ssize_t n) - { -+ arrayobject *a = arrayobject_CAST(op); - array_state *state = find_array_state_by_type(Py_TYPE(a)); - - if (n < 0) -@@ -1026,8 +1034,9 @@ - } - - static int --array_ass_item(arrayobject *a, Py_ssize_t i, PyObject *v) -+array_ass_item(PyObject *op, Py_ssize_t i, PyObject *v) - { -+ arrayobject *a = arrayobject_CAST(op); - if (i < 0 || i >= Py_SIZE(a)) { - PyErr_SetString(PyExc_IndexError, - "array assignment index out of range"); -@@ -1045,7 +1054,7 @@ - array_state *state = find_array_state_by_type(Py_TYPE(a)); - assert(array_Check(a, state)); - #endif -- return array_ass_item((arrayobject *)a, i, v); -+ return array_ass_item(a, i, v); - } - - static int -@@ -1105,8 +1114,9 @@ - } - - static PyObject * --array_inplace_concat(arrayobject *self, PyObject *bb) -+array_inplace_concat(PyObject *op, PyObject *bb) - { -+ arrayobject *self = arrayobject_CAST(op); - array_state *state = find_array_state_by_type(Py_TYPE(self)); - - if (!array_Check(bb, state)) { -@@ -1121,8 +1131,9 @@ - } - - static PyObject * --array_inplace_repeat(arrayobject *self, Py_ssize_t n) -+array_inplace_repeat(PyObject *op, Py_ssize_t n) - { -+ arrayobject *self = arrayobject_CAST(op); - const Py_ssize_t array_size = Py_SIZE(self); - - if (array_size > 0 && n != 1 ) { -@@ -1236,13 +1247,13 @@ - } - - static int --array_contains(arrayobject *self, PyObject *v) -+array_contains(PyObject *self, PyObject *v) - { - Py_ssize_t i; - int cmp; - - for (i = 0, cmp = 0 ; cmp == 0 && i < Py_SIZE(self); i++) { -- PyObject *selfi = getarrayitem((PyObject *)self, i); -+ PyObject *selfi = getarrayitem(self, i); - if (selfi == NULL) - return -1; - cmp = PyObject_RichCompareBool(selfi, v, Py_EQ); -@@ -1557,7 +1568,7 @@ - - not_enough_bytes = (PyBytes_GET_SIZE(b) != nbytes); - -- res = array_array_frombytes(self, b); -+ res = array_array_frombytes((PyObject *)self, b); - Py_DECREF(b); - if (res == NULL) - return NULL; -@@ -2285,7 +2296,7 @@ - assert(state != NULL); - - if (state->array_reconstructor == NULL) { -- state->array_reconstructor = _PyImport_GetModuleAttrString( -+ state->array_reconstructor = PyImport_ImportModuleAttrString( - "array", "_array_reconstructor"); - if (state->array_reconstructor == NULL) { - return NULL; -@@ -2349,22 +2360,24 @@ - } - - static PyObject * --array_get_typecode(arrayobject *a, void *closure) -+array_get_typecode(PyObject *op, void *Py_UNUSED(closure)) - { -+ arrayobject *a = arrayobject_CAST(op); - char typecode = a->ob_descr->typecode; - return PyUnicode_FromOrdinal(typecode); - } - - static PyObject * --array_get_itemsize(arrayobject *a, void *closure) -+array_get_itemsize(PyObject *op, void *Py_UNUSED(closure)) - { -+ arrayobject *a = arrayobject_CAST(op); - return PyLong_FromLong((long)a->ob_descr->itemsize); - } - - static PyGetSetDef array_getsets [] = { -- {"typecode", (getter) array_get_typecode, NULL, -+ {"typecode", array_get_typecode, NULL, - "the typecode character used to create the array"}, -- {"itemsize", (getter) array_get_itemsize, NULL, -+ {"itemsize", array_get_itemsize, NULL, - "the size, in bytes, of one array item"}, - {NULL} - }; -@@ -2398,11 +2411,12 @@ - }; - - static PyObject * --array_repr(arrayobject *a) -+array_repr(PyObject *op) - { - char typecode; - PyObject *s, *v = NULL; - Py_ssize_t len; -+ arrayobject *a = arrayobject_CAST(op); - - len = Py_SIZE(a); - typecode = a->ob_descr->typecode; -@@ -2425,8 +2439,9 @@ - } - - static PyObject* --array_subscr(arrayobject* self, PyObject* item) -+array_subscr(PyObject *op, PyObject *item) - { -+ arrayobject *self = arrayobject_CAST(op); - array_state *state = find_array_state_by_type(Py_TYPE(self)); - - if (PyIndex_Check(item)) { -@@ -2436,7 +2451,7 @@ - } - if (i < 0) - i += Py_SIZE(self); -- return array_item(self, i); -+ return array_item(op, i); - } - else if (PySlice_Check(item)) { - Py_ssize_t start, stop, step, slicelength, i; -@@ -2488,9 +2503,10 @@ - } - - static int --array_ass_subscr(arrayobject* self, PyObject* item, PyObject* value) -+array_ass_subscr(PyObject *op, PyObject *item, PyObject *value) - { - Py_ssize_t start, stop, step, slicelength, needed; -+ arrayobject *self = arrayobject_CAST(op); - array_state* state = find_array_state_by_type(Py_TYPE(self)); - arrayobject* other; - int itemsize; -@@ -2542,7 +2558,7 @@ - value = array_slice(other, 0, needed); - if (value == NULL) - return -1; -- ret = array_ass_subscr(self, item, value); -+ ret = array_ass_subscr(op, item, value); - Py_DECREF(value); - return ret; - } -@@ -2649,7 +2665,7 @@ - - - static int --array_buffer_getbuf(arrayobject *self, Py_buffer *view, int flags) -+array_buffer_getbuf(PyObject *op, Py_buffer *view, int flags) - { - if (view == NULL) { - PyErr_SetString(PyExc_BufferError, -@@ -2657,6 +2673,7 @@ - return -1; - } - -+ arrayobject *self = arrayobject_CAST(op); - view->buf = (void *)self->ob_item; - view->obj = Py_NewRef(self); - if (view->buf == NULL) -@@ -2689,8 +2706,9 @@ - } - - static void --array_buffer_relbuf(arrayobject *self, Py_buffer *view) -+array_buffer_relbuf(PyObject *op, Py_buffer *Py_UNUSED(view)) - { -+ arrayobject *self = arrayobject_CAST(op); - self->ob_exports--; - } - -@@ -2797,8 +2815,7 @@ - else if (initial != NULL && (PyByteArray_Check(initial) || - PyBytes_Check(initial))) { - PyObject *v; -- v = array_array_frombytes((arrayobject *)a, -- initial); -+ v = array_array_frombytes((PyObject *)a, initial); - if (v == NULL) { - Py_DECREF(a); - return NULL; -@@ -2926,7 +2943,7 @@ - itemsize -- the length in bytes of one array item\n\ - "); - --static PyObject *array_iter(arrayobject *ao); -+static PyObject *array_iter(PyObject *op); - - static struct PyMemberDef array_members[] = { - {"__weaklistoffset__", Py_T_PYSSIZET, offsetof(arrayobject, weakreflist), Py_READONLY}, -@@ -2986,8 +3003,9 @@ - /*[clinic end generated code: output=da39a3ee5e6b4b0d input=fb46d5ef98dd95ff]*/ - - static PyObject * --array_iter(arrayobject *ao) -+array_iter(PyObject *op) - { -+ arrayobject *ao = arrayobject_CAST(op); - array_state *state = find_array_state_by_type(Py_TYPE(ao)); - arrayiterobject *it; - -@@ -3008,16 +3026,15 @@ - } - - static PyObject * --arrayiter_next(arrayiterobject *it) -+arrayiter_next(PyObject *op) - { -- arrayobject *ao; -- -+ arrayiterobject *it = arrayiterobject_CAST(op); - assert(it != NULL); - #ifndef NDEBUG - array_state *state = find_array_state_by_type(Py_TYPE(it)); - assert(PyObject_TypeCheck(it, state->ArrayIterType)); - #endif -- ao = it->ao; -+ arrayobject *ao = it->ao; - if (ao == NULL) { - return NULL; - } -@@ -3033,10 +3050,10 @@ - } - - static void --arrayiter_dealloc(arrayiterobject *it) -+arrayiter_dealloc(PyObject *op) - { -+ arrayiterobject *it = arrayiterobject_CAST(op); - PyTypeObject *tp = Py_TYPE(it); -- - PyObject_GC_UnTrack(it); - Py_XDECREF(it->ao); - PyObject_GC_Del(it); -@@ -3044,8 +3061,9 @@ - } - - static int --arrayiter_traverse(arrayiterobject *it, visitproc visit, void *arg) -+arrayiter_traverse(PyObject *op, visitproc visit, void *arg) - { -+ arrayiterobject *it = arrayiterobject_CAST(op); - Py_VISIT(Py_TYPE(it)); - Py_VISIT(it->ao); - return 0; -@@ -3090,11 +3108,16 @@ - Py_ssize_t index = PyLong_AsSsize_t(state); - if (index == -1 && PyErr_Occurred()) - return NULL; -- if (index < 0) -- index = 0; -- else if (index > Py_SIZE(self->ao)) -- index = Py_SIZE(self->ao); /* iterator exhausted */ -- self->index = index; -+ arrayobject *ao = self->ao; -+ if (ao != NULL) { -+ if (index < 0) { -+ index = 0; -+ } -+ else if (index > Py_SIZE(ao)) { -+ index = Py_SIZE(ao); /* iterator exhausted */ -+ } -+ self->index = index; -+ } - Py_RETURN_NONE; - } - -@@ -3152,7 +3175,7 @@ - static void - array_free(void *module) - { -- array_clear((PyObject *)module); -+ (void)array_clear((PyObject *)module); - } - - /* No functions in array module. */ -@@ -3202,7 +3225,7 @@ - return -1; - } - -- PyObject *mutablesequence = _PyImport_GetModuleAttrString( -+ PyObject *mutablesequence = PyImport_ImportModuleAttrString( - "collections.abc", "MutableSequence"); - if (!mutablesequence) { - Py_DECREF((PyObject *)state->ArrayType); -diff --git a/Modules/atexitmodule.c b/Modules/atexitmodule.c -index 1b89b32ba90..2bfdda53af8 100644 ---- a/Modules/atexitmodule.c -+++ b/Modules/atexitmodule.c -@@ -110,7 +110,8 @@ - PyObject *copy = PyList_GetSlice(state->callbacks, 0, PyList_GET_SIZE(state->callbacks)); - if (copy == NULL) - { -- PyErr_WriteUnraisable(NULL); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "copying atexit callbacks"); - return; - } - -diff --git a/Modules/blake2module.c b/Modules/blake2module.c -index 94cdfe7fd2e..016c834c01b 100644 ---- a/Modules/blake2module.c -+++ b/Modules/blake2module.c -@@ -366,6 +366,8 @@ - PyMutex mutex; - } Blake2Object; - -+#define _Blake2Object_CAST(op) ((Blake2Object *)(op)) -+ - #include "clinic/blake2module.c.h" - - /*[clinic input] -@@ -379,13 +381,13 @@ - static Blake2Object * - new_Blake2Object(PyTypeObject *type) - { -- Blake2Object *self; -- self = (Blake2Object *)type->tp_alloc(type, 0); -+ Blake2Object *self = PyObject_GC_New(Blake2Object, type); - if (self == NULL) { - return NULL; - } - HASHLIB_INIT_MUTEX(self); - -+ PyObject_GC_Track(self); - return self; - } - -@@ -454,7 +456,28 @@ - } - - self->impl = type_to_impl(type); -- -+ // Ensure that the states are NULL-initialized in case of an error. -+ // See: py_blake2_clear() for more details. -+ switch (self->impl) { -+#if HACL_CAN_COMPILE_SIMD256 -+ case Blake2b_256: -+ self->blake2b_256_state = NULL; -+ break; -+#endif -+#if HACL_CAN_COMPILE_SIMD128 -+ case Blake2s_128: -+ self->blake2s_128_state = NULL; -+ break; -+#endif -+ case Blake2b: -+ self->blake2b_state = NULL; -+ break; -+ case Blake2s: -+ self->blake2s_state = NULL; -+ break; -+ default: -+ Py_UNREACHABLE(); -+ } - // Using Blake2b because we statically know that these are greater than the - // Blake2s sizes -- this avoids a VLA. - uint8_t salt_[HACL_HASH_BLAKE2B_SALT_BYTES] = { 0 }; -@@ -595,7 +618,7 @@ - - return (PyObject *)self; - error: -- Py_XDECREF(self); -+ Py_XDECREF(self); - return NULL; - } - -@@ -828,24 +851,27 @@ - - - static PyObject * --py_blake2b_get_name(Blake2Object *self, void *closure) -+py_blake2b_get_name(PyObject *op, void *Py_UNUSED(closure)) - { -+ Blake2Object *self = _Blake2Object_CAST(op); - return PyUnicode_FromString(is_blake2b(self->impl) ? "blake2b" : "blake2s"); - } - - - - static PyObject * --py_blake2b_get_block_size(Blake2Object *self, void *closure) -+py_blake2b_get_block_size(PyObject *op, void *Py_UNUSED(closure)) - { -+ Blake2Object *self = _Blake2Object_CAST(op); - return PyLong_FromLong(is_blake2b(self->impl) ? HACL_HASH_BLAKE2B_BLOCK_BYTES : HACL_HASH_BLAKE2S_BLOCK_BYTES); - } - - - - static PyObject * --py_blake2b_get_digest_size(Blake2Object *self, void *closure) -+py_blake2b_get_digest_size(PyObject *op, void *Py_UNUSED(closure)) - { -+ Blake2Object *self = _Blake2Object_CAST(op); - switch (self->impl) { - #if HACL_CAN_COMPILE_SIMD256 - case Blake2b_256: -@@ -866,55 +892,77 @@ - - - static PyGetSetDef py_blake2b_getsetters[] = { -- {"name", (getter)py_blake2b_get_name, -- NULL, NULL, NULL}, -- {"block_size", (getter)py_blake2b_get_block_size, -- NULL, NULL, NULL}, -- {"digest_size", (getter)py_blake2b_get_digest_size, -- NULL, NULL, NULL}, -- {NULL} -+ {"name", py_blake2b_get_name, NULL, NULL, NULL}, -+ {"block_size", py_blake2b_get_block_size, NULL, NULL, NULL}, -+ {"digest_size", py_blake2b_get_digest_size, NULL, NULL, NULL}, -+ {NULL} /* Sentinel */ - }; - - --static void --py_blake2b_dealloc(Blake2Object *self) -+static int -+py_blake2_clear(PyObject *op) - { -+ Blake2Object *self = (Blake2Object *)op; -+ // The initialization function uses PyObject_GC_New() but explicitly -+ // initializes the HACL* internal state to NULL before allocating -+ // it. If an error occurs in the constructor, we should only free -+ // states that were allocated (i.e. that are not NULL). - switch (self->impl) { - #if HACL_CAN_COMPILE_SIMD256 - case Blake2b_256: -- if (self->blake2b_256_state != NULL) -+ if (self->blake2b_256_state != NULL) { - Hacl_Hash_Blake2b_Simd256_free(self->blake2b_256_state); -+ self->blake2b_256_state = NULL; -+ } - break; - #endif - #if HACL_CAN_COMPILE_SIMD128 - case Blake2s_128: -- if (self->blake2s_128_state != NULL) -+ if (self->blake2s_128_state != NULL) { - Hacl_Hash_Blake2s_Simd128_free(self->blake2s_128_state); -+ self->blake2s_128_state = NULL; -+ } - break; - #endif - case Blake2b: -- // This happens if we hit "goto error" in the middle of the -- // initialization function. We leverage the fact that tp_alloc -- // guarantees that the contents of the object are NULL-initialized -- // (see documentation for PyType_GenericAlloc) to detect this case. -- if (self->blake2b_state != NULL) -+ if (self->blake2b_state != NULL) { - Hacl_Hash_Blake2b_free(self->blake2b_state); -+ self->blake2b_state = NULL; -+ } - break; - case Blake2s: -- if (self->blake2s_state != NULL) -+ if (self->blake2s_state != NULL) { - Hacl_Hash_Blake2s_free(self->blake2s_state); -+ self->blake2s_state = NULL; -+ } - break; - default: - Py_UNREACHABLE(); - } -+ return 0; -+} - -+static void -+py_blake2_dealloc(PyObject *self) -+{ - PyTypeObject *type = Py_TYPE(self); -- PyObject_Free(self); -+ PyObject_GC_UnTrack(self); -+ (void)py_blake2_clear(self); -+ type->tp_free(self); - Py_DECREF(type); - } - -+static int -+py_blake2_traverse(PyObject *self, visitproc visit, void *arg) -+{ -+ Py_VISIT(Py_TYPE(self)); -+ return 0; -+} -+ - static PyType_Slot blake2b_type_slots[] = { -- {Py_tp_dealloc, py_blake2b_dealloc}, -+ {Py_tp_clear, py_blake2_clear}, -+ {Py_tp_dealloc, py_blake2_dealloc}, -+ {Py_tp_traverse, py_blake2_traverse}, - {Py_tp_doc, (char *)py_blake2b_new__doc__}, - {Py_tp_methods, py_blake2b_methods}, - {Py_tp_getset, py_blake2b_getsetters}, -@@ -923,7 +971,9 @@ - }; - - static PyType_Slot blake2s_type_slots[] = { -- {Py_tp_dealloc, py_blake2b_dealloc}, -+ {Py_tp_clear, py_blake2_clear}, -+ {Py_tp_dealloc, py_blake2_dealloc}, -+ {Py_tp_traverse, py_blake2_traverse}, - {Py_tp_doc, (char *)py_blake2s_new__doc__}, - {Py_tp_methods, py_blake2b_methods}, - {Py_tp_getset, py_blake2b_getsetters}, -@@ -936,13 +986,15 @@ - static PyType_Spec blake2b_type_spec = { - .name = "_blake2.blake2b", - .basicsize = sizeof(Blake2Object), -- .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE, -+ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE -+ | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HEAPTYPE, - .slots = blake2b_type_slots - }; - - static PyType_Spec blake2s_type_spec = { - .name = "_blake2.blake2s", - .basicsize = sizeof(Blake2Object), -- .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE, -+ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE -+ | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HEAPTYPE, - .slots = blake2s_type_slots - }; -diff --git a/Modules/cjkcodecs/cjkcodecs.h b/Modules/cjkcodecs/cjkcodecs.h -index 2b446ba5226..737a7a04275 100644 ---- a/Modules/cjkcodecs/cjkcodecs.h -+++ b/Modules/cjkcodecs/cjkcodecs.h -@@ -13,7 +13,6 @@ - - #include "Python.h" - #include "multibytecodec.h" --#include "pycore_import.h" // _PyImport_GetModuleAttrString() - - - /* a unicode "undefined" code point */ -@@ -299,7 +298,7 @@ - static PyObject * - getmultibytecodec(void) - { -- return _PyImport_GetModuleAttrString("_multibytecodec", "__create_codec"); -+ return PyImport_ImportModuleAttrString("_multibytecodec", "__create_codec"); - } - - static void -diff --git a/Modules/cjkcodecs/clinic/multibytecodec.c.h b/Modules/cjkcodecs/clinic/multibytecodec.c.h -index 7e7ea9e0fdf..d77bbd48066 100644 ---- a/Modules/cjkcodecs/clinic/multibytecodec.c.h -+++ b/Modules/cjkcodecs/clinic/multibytecodec.c.h -@@ -28,7 +28,7 @@ - const char *errors); - - static PyObject * --_multibytecodec_MultibyteCodec_encode(MultibyteCodecObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_multibytecodec_MultibyteCodec_encode(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -89,7 +89,7 @@ - goto exit; - } - skip_optional_pos: -- return_value = _multibytecodec_MultibyteCodec_encode_impl(self, input, errors); -+ return_value = _multibytecodec_MultibyteCodec_encode_impl((MultibyteCodecObject *)self, input, errors); - - exit: - return return_value; -@@ -115,7 +115,7 @@ - const char *errors); - - static PyObject * --_multibytecodec_MultibyteCodec_decode(MultibyteCodecObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_multibytecodec_MultibyteCodec_decode(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -178,7 +178,7 @@ - goto exit; - } - skip_optional_pos: -- return_value = _multibytecodec_MultibyteCodec_decode_impl(self, &input, errors); -+ return_value = _multibytecodec_MultibyteCodec_decode_impl((MultibyteCodecObject *)self, &input, errors); - - exit: - /* Cleanup for input */ -@@ -203,7 +203,7 @@ - int final); - - static PyObject * --_multibytecodec_MultibyteIncrementalEncoder_encode(MultibyteIncrementalEncoderObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_multibytecodec_MultibyteIncrementalEncoder_encode(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -250,7 +250,7 @@ - goto exit; - } - skip_optional_pos: -- return_value = _multibytecodec_MultibyteIncrementalEncoder_encode_impl(self, input, final); -+ return_value = _multibytecodec_MultibyteIncrementalEncoder_encode_impl((MultibyteIncrementalEncoderObject *)self, input, final); - - exit: - return return_value; -@@ -268,9 +268,9 @@ - _multibytecodec_MultibyteIncrementalEncoder_getstate_impl(MultibyteIncrementalEncoderObject *self); - - static PyObject * --_multibytecodec_MultibyteIncrementalEncoder_getstate(MultibyteIncrementalEncoderObject *self, PyObject *Py_UNUSED(ignored)) -+_multibytecodec_MultibyteIncrementalEncoder_getstate(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _multibytecodec_MultibyteIncrementalEncoder_getstate_impl(self); -+ return _multibytecodec_MultibyteIncrementalEncoder_getstate_impl((MultibyteIncrementalEncoderObject *)self); - } - - PyDoc_STRVAR(_multibytecodec_MultibyteIncrementalEncoder_setstate__doc__, -@@ -286,7 +286,7 @@ - PyLongObject *statelong); - - static PyObject * --_multibytecodec_MultibyteIncrementalEncoder_setstate(MultibyteIncrementalEncoderObject *self, PyObject *arg) -+_multibytecodec_MultibyteIncrementalEncoder_setstate(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - PyLongObject *statelong; -@@ -296,7 +296,7 @@ - goto exit; - } - statelong = (PyLongObject *)arg; -- return_value = _multibytecodec_MultibyteIncrementalEncoder_setstate_impl(self, statelong); -+ return_value = _multibytecodec_MultibyteIncrementalEncoder_setstate_impl((MultibyteIncrementalEncoderObject *)self, statelong); - - exit: - return return_value; -@@ -314,9 +314,9 @@ - _multibytecodec_MultibyteIncrementalEncoder_reset_impl(MultibyteIncrementalEncoderObject *self); - - static PyObject * --_multibytecodec_MultibyteIncrementalEncoder_reset(MultibyteIncrementalEncoderObject *self, PyObject *Py_UNUSED(ignored)) -+_multibytecodec_MultibyteIncrementalEncoder_reset(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _multibytecodec_MultibyteIncrementalEncoder_reset_impl(self); -+ return _multibytecodec_MultibyteIncrementalEncoder_reset_impl((MultibyteIncrementalEncoderObject *)self); - } - - PyDoc_STRVAR(_multibytecodec_MultibyteIncrementalDecoder_decode__doc__, -@@ -333,7 +333,7 @@ - int final); - - static PyObject * --_multibytecodec_MultibyteIncrementalDecoder_decode(MultibyteIncrementalDecoderObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_multibytecodec_MultibyteIncrementalDecoder_decode(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -382,7 +382,7 @@ - goto exit; - } - skip_optional_pos: -- return_value = _multibytecodec_MultibyteIncrementalDecoder_decode_impl(self, &input, final); -+ return_value = _multibytecodec_MultibyteIncrementalDecoder_decode_impl((MultibyteIncrementalDecoderObject *)self, &input, final); - - exit: - /* Cleanup for input */ -@@ -405,9 +405,9 @@ - _multibytecodec_MultibyteIncrementalDecoder_getstate_impl(MultibyteIncrementalDecoderObject *self); - - static PyObject * --_multibytecodec_MultibyteIncrementalDecoder_getstate(MultibyteIncrementalDecoderObject *self, PyObject *Py_UNUSED(ignored)) -+_multibytecodec_MultibyteIncrementalDecoder_getstate(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _multibytecodec_MultibyteIncrementalDecoder_getstate_impl(self); -+ return _multibytecodec_MultibyteIncrementalDecoder_getstate_impl((MultibyteIncrementalDecoderObject *)self); - } - - PyDoc_STRVAR(_multibytecodec_MultibyteIncrementalDecoder_setstate__doc__, -@@ -423,7 +423,7 @@ - PyObject *state); - - static PyObject * --_multibytecodec_MultibyteIncrementalDecoder_setstate(MultibyteIncrementalDecoderObject *self, PyObject *arg) -+_multibytecodec_MultibyteIncrementalDecoder_setstate(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - PyObject *state; -@@ -433,7 +433,7 @@ - goto exit; - } - state = arg; -- return_value = _multibytecodec_MultibyteIncrementalDecoder_setstate_impl(self, state); -+ return_value = _multibytecodec_MultibyteIncrementalDecoder_setstate_impl((MultibyteIncrementalDecoderObject *)self, state); - - exit: - return return_value; -@@ -451,9 +451,9 @@ - _multibytecodec_MultibyteIncrementalDecoder_reset_impl(MultibyteIncrementalDecoderObject *self); - - static PyObject * --_multibytecodec_MultibyteIncrementalDecoder_reset(MultibyteIncrementalDecoderObject *self, PyObject *Py_UNUSED(ignored)) -+_multibytecodec_MultibyteIncrementalDecoder_reset(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _multibytecodec_MultibyteIncrementalDecoder_reset_impl(self); -+ return _multibytecodec_MultibyteIncrementalDecoder_reset_impl((MultibyteIncrementalDecoderObject *)self); - } - - PyDoc_STRVAR(_multibytecodec_MultibyteStreamReader_read__doc__, -@@ -469,7 +469,7 @@ - PyObject *sizeobj); - - static PyObject * --_multibytecodec_MultibyteStreamReader_read(MultibyteStreamReaderObject *self, PyObject *const *args, Py_ssize_t nargs) -+_multibytecodec_MultibyteStreamReader_read(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *sizeobj = Py_None; -@@ -482,7 +482,7 @@ - } - sizeobj = args[0]; - skip_optional: -- return_value = _multibytecodec_MultibyteStreamReader_read_impl(self, sizeobj); -+ return_value = _multibytecodec_MultibyteStreamReader_read_impl((MultibyteStreamReaderObject *)self, sizeobj); - - exit: - return return_value; -@@ -501,7 +501,7 @@ - PyObject *sizeobj); - - static PyObject * --_multibytecodec_MultibyteStreamReader_readline(MultibyteStreamReaderObject *self, PyObject *const *args, Py_ssize_t nargs) -+_multibytecodec_MultibyteStreamReader_readline(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *sizeobj = Py_None; -@@ -514,7 +514,7 @@ - } - sizeobj = args[0]; - skip_optional: -- return_value = _multibytecodec_MultibyteStreamReader_readline_impl(self, sizeobj); -+ return_value = _multibytecodec_MultibyteStreamReader_readline_impl((MultibyteStreamReaderObject *)self, sizeobj); - - exit: - return return_value; -@@ -533,7 +533,7 @@ - PyObject *sizehintobj); - - static PyObject * --_multibytecodec_MultibyteStreamReader_readlines(MultibyteStreamReaderObject *self, PyObject *const *args, Py_ssize_t nargs) -+_multibytecodec_MultibyteStreamReader_readlines(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *sizehintobj = Py_None; -@@ -546,7 +546,7 @@ - } - sizehintobj = args[0]; - skip_optional: -- return_value = _multibytecodec_MultibyteStreamReader_readlines_impl(self, sizehintobj); -+ return_value = _multibytecodec_MultibyteStreamReader_readlines_impl((MultibyteStreamReaderObject *)self, sizehintobj); - - exit: - return return_value; -@@ -564,9 +564,9 @@ - _multibytecodec_MultibyteStreamReader_reset_impl(MultibyteStreamReaderObject *self); - - static PyObject * --_multibytecodec_MultibyteStreamReader_reset(MultibyteStreamReaderObject *self, PyObject *Py_UNUSED(ignored)) -+_multibytecodec_MultibyteStreamReader_reset(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _multibytecodec_MultibyteStreamReader_reset_impl(self); -+ return _multibytecodec_MultibyteStreamReader_reset_impl((MultibyteStreamReaderObject *)self); - } - - PyDoc_STRVAR(_multibytecodec_MultibyteStreamWriter_write__doc__, -@@ -583,7 +583,7 @@ - PyObject *strobj); - - static PyObject * --_multibytecodec_MultibyteStreamWriter_write(MultibyteStreamWriterObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_multibytecodec_MultibyteStreamWriter_write(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -608,7 +608,7 @@ - goto exit; - } - strobj = args[0]; -- return_value = _multibytecodec_MultibyteStreamWriter_write_impl(self, cls, strobj); -+ return_value = _multibytecodec_MultibyteStreamWriter_write_impl((MultibyteStreamWriterObject *)self, cls, strobj); - - exit: - return return_value; -@@ -628,7 +628,7 @@ - PyObject *lines); - - static PyObject * --_multibytecodec_MultibyteStreamWriter_writelines(MultibyteStreamWriterObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_multibytecodec_MultibyteStreamWriter_writelines(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -653,7 +653,7 @@ - goto exit; - } - lines = args[0]; -- return_value = _multibytecodec_MultibyteStreamWriter_writelines_impl(self, cls, lines); -+ return_value = _multibytecodec_MultibyteStreamWriter_writelines_impl((MultibyteStreamWriterObject *)self, cls, lines); - - exit: - return return_value; -@@ -672,13 +672,13 @@ - PyTypeObject *cls); - - static PyObject * --_multibytecodec_MultibyteStreamWriter_reset(MultibyteStreamWriterObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_multibytecodec_MultibyteStreamWriter_reset(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "reset() takes no arguments"); - return NULL; - } -- return _multibytecodec_MultibyteStreamWriter_reset_impl(self, cls); -+ return _multibytecodec_MultibyteStreamWriter_reset_impl((MultibyteStreamWriterObject *)self, cls); - } - - PyDoc_STRVAR(_multibytecodec___create_codec__doc__, -@@ -688,4 +688,4 @@ - - #define _MULTIBYTECODEC___CREATE_CODEC_METHODDEF \ - {"__create_codec", (PyCFunction)_multibytecodec___create_codec, METH_O, _multibytecodec___create_codec__doc__}, --/*[clinic end generated code: output=60e1fa3a7615c148 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=6571941b8e45b013 input=a9049054013a1b77]*/ -diff --git a/Modules/cjkcodecs/multibytecodec.c b/Modules/cjkcodecs/multibytecodec.c -index 53135ae4aa7..08b74740bda 100644 ---- a/Modules/cjkcodecs/multibytecodec.c -+++ b/Modules/cjkcodecs/multibytecodec.c -@@ -56,6 +56,27 @@ - /*[clinic end generated code: output=da39a3ee5e6b4b0d input=305a76dfdd24b99c]*/ - #undef clinic_get_state - -+#define _MultibyteCodec_CAST(op) ((MultibyteCodec *)(op)) -+#define _MultibyteCodecObject_CAST(op) ((MultibyteCodecObject *)(op)) -+ -+#define _MultibyteStatefulCodecContext_CAST(op) \ -+ ((MultibyteStatefulCodecContext *)(op)) -+ -+#define _MultibyteStatefulEncoderContext_CAST(op) \ -+ ((MultibyteStatefulEncoderContext *)(op)) -+#define _MultibyteStatefulDecoderContext_CAST(op) \ -+ ((MultibyteStatefulDecoderContext *)(op)) -+ -+#define _MultibyteIncrementalEncoderObject_CAST(op) \ -+ ((MultibyteIncrementalEncoderObject *)(op)) -+#define _MultibyteIncrementalDecoderObject_CAST(op) \ -+ ((MultibyteIncrementalDecoderObject *)(op)) -+ -+#define _MultibyteStreamReaderObject_CAST(op) \ -+ ((MultibyteStreamReaderObject *)(op)) -+#define _MultibyteStreamWriterObject_CAST(op) \ -+ ((MultibyteStreamWriterObject *)(op)) -+ - typedef struct { - PyObject *inobj; - Py_ssize_t inpos, inlen; -@@ -136,9 +157,10 @@ - } - - static PyObject * --codecctx_errors_get(MultibyteStatefulCodecContext *self, void *Py_UNUSED(ignored)) -+codecctx_errors_get(PyObject *op, void *Py_UNUSED(closure)) - { - const char *errors; -+ MultibyteStatefulCodecContext *self = _MultibyteStatefulCodecContext_CAST(op); - - if (self->errors == ERROR_STRICT) - errors = "strict"; -@@ -154,11 +176,11 @@ - } - - static int --codecctx_errors_set(MultibyteStatefulCodecContext *self, PyObject *value, -- void *closure) -+codecctx_errors_set(PyObject *op, PyObject *value, void *Py_UNUSED(closure)) - { - PyObject *cb; - const char *str; -+ MultibyteStatefulCodecContext *self = _MultibyteStatefulCodecContext_CAST(op); - - if (value == NULL) { - PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); -@@ -184,9 +206,8 @@ - - /* This getset handlers list is used by all the stateful codec objects */ - static PyGetSetDef codecctx_getsets[] = { -- {"errors", (getter)codecctx_errors_get, -- (setter)codecctx_errors_set, -- PyDoc_STR("how to treat errors")}, -+ {"errors", codecctx_errors_get, codecctx_errors_set, -+ PyDoc_STR("how to treat errors")}, - {NULL,} - }; - -@@ -719,22 +740,24 @@ - }; - - static int --multibytecodec_clear(MultibyteCodecObject *self) -+multibytecodec_clear(PyObject *op) - { -+ MultibyteCodecObject *self = _MultibyteCodecObject_CAST(op); - Py_CLEAR(self->cjk_module); - return 0; - } - - static int --multibytecodec_traverse(MultibyteCodecObject *self, visitproc visit, void *arg) -+multibytecodec_traverse(PyObject *op, visitproc visit, void *arg) - { -+ MultibyteCodecObject *self = _MultibyteCodecObject_CAST(op); - Py_VISIT(Py_TYPE(self)); - Py_VISIT(self->cjk_module); - return 0; - } - - static void --multibytecodec_dealloc(MultibyteCodecObject *self) -+multibytecodec_dealloc(PyObject *self) - { - PyObject_GC_UnTrack(self); - PyTypeObject *tp = Py_TYPE(self); -@@ -1106,17 +1129,18 @@ - } - - static int --mbiencoder_traverse(MultibyteIncrementalEncoderObject *self, -- visitproc visit, void *arg) -+mbiencoder_traverse(PyObject *op, visitproc visit, void *arg) - { -+ MultibyteIncrementalEncoderObject *self = _MultibyteIncrementalEncoderObject_CAST(op); - if (ERROR_ISCUSTOM(self->errors)) - Py_VISIT(self->errors); - return 0; - } - - static void --mbiencoder_dealloc(MultibyteIncrementalEncoderObject *self) -+mbiencoder_dealloc(PyObject *op) - { -+ MultibyteIncrementalEncoderObject *self = _MultibyteIncrementalEncoderObject_CAST(op); - PyTypeObject *tp = Py_TYPE(self); - PyObject_GC_UnTrack(self); - ERROR_DECREF(self->errors); -@@ -1388,17 +1412,18 @@ - } - - static int --mbidecoder_traverse(MultibyteIncrementalDecoderObject *self, -- visitproc visit, void *arg) -+mbidecoder_traverse(PyObject *op, visitproc visit, void *arg) - { -+ MultibyteIncrementalDecoderObject *self = _MultibyteIncrementalDecoderObject_CAST(op); - if (ERROR_ISCUSTOM(self->errors)) - Py_VISIT(self->errors); - return 0; - } - - static void --mbidecoder_dealloc(MultibyteIncrementalDecoderObject *self) -+mbidecoder_dealloc(PyObject *op) - { -+ MultibyteIncrementalDecoderObject *self = _MultibyteIncrementalDecoderObject_CAST(op); - PyTypeObject *tp = Py_TYPE(self); - PyObject_GC_UnTrack(self); - ERROR_DECREF(self->errors); -@@ -1704,9 +1729,9 @@ - } - - static int --mbstreamreader_traverse(MultibyteStreamReaderObject *self, -- visitproc visit, void *arg) -+mbstreamreader_traverse(PyObject *op, visitproc visit, void *arg) - { -+ MultibyteStreamReaderObject *self = _MultibyteStreamReaderObject_CAST(op); - if (ERROR_ISCUSTOM(self->errors)) - Py_VISIT(self->errors); - Py_VISIT(self->stream); -@@ -1714,8 +1739,9 @@ - } - - static void --mbstreamreader_dealloc(MultibyteStreamReaderObject *self) -+mbstreamreader_dealloc(PyObject *op) - { -+ MultibyteStreamReaderObject *self = _MultibyteStreamReaderObject_CAST(op); - PyTypeObject *tp = Py_TYPE(self); - PyObject_GC_UnTrack(self); - ERROR_DECREF(self->errors); -@@ -1927,9 +1953,9 @@ - } - - static int --mbstreamwriter_traverse(MultibyteStreamWriterObject *self, -- visitproc visit, void *arg) -+mbstreamwriter_traverse(PyObject *op, visitproc visit, void *arg) - { -+ MultibyteStreamWriterObject *self = _MultibyteStreamWriterObject_CAST(op); - if (ERROR_ISCUSTOM(self->errors)) - Py_VISIT(self->errors); - Py_VISIT(self->stream); -@@ -1937,8 +1963,9 @@ - } - - static void --mbstreamwriter_dealloc(MultibyteStreamWriterObject *self) -+mbstreamwriter_dealloc(PyObject *op) - { -+ MultibyteStreamWriterObject *self = _MultibyteStreamWriterObject_CAST(op); - PyTypeObject *tp = Py_TYPE(self); - PyObject_GC_UnTrack(self); - ERROR_DECREF(self->errors); -@@ -2044,7 +2071,7 @@ - static void - _multibytecodec_free(void *mod) - { -- _multibytecodec_clear((PyObject *)mod); -+ (void)_multibytecodec_clear((PyObject *)mod); - } - - #define CREATE_TYPE(module, type, spec) \ -diff --git a/Modules/clinic/_asynciomodule.c.h b/Modules/clinic/_asynciomodule.c.h -index 32045804c35..d25411ee995 100644 ---- a/Modules/clinic/_asynciomodule.c.h -+++ b/Modules/clinic/_asynciomodule.c.h -@@ -6,6 +6,7 @@ - # include "pycore_gc.h" // PyGC_Head - # include "pycore_runtime.h" // _Py_ID() - #endif -+#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() - #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() - - PyDoc_STRVAR(_asyncio_Future___init____doc__, -@@ -96,9 +97,15 @@ - _asyncio_Future_result_impl(FutureObj *self); - - static PyObject * --_asyncio_Future_result(FutureObj *self, PyObject *Py_UNUSED(ignored)) -+_asyncio_Future_result(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _asyncio_Future_result_impl(self); -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Future_result_impl((FutureObj *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; - } - - PyDoc_STRVAR(_asyncio_Future_exception__doc__, -@@ -119,13 +126,20 @@ - _asyncio_Future_exception_impl(FutureObj *self, PyTypeObject *cls); - - static PyObject * --_asyncio_Future_exception(FutureObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_asyncio_Future_exception(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { -+ PyObject *return_value = NULL; -+ - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "exception() takes no arguments"); -- return NULL; -+ goto exit; - } -- return _asyncio_Future_exception_impl(self, cls); -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Future_exception_impl((FutureObj *)self, cls); -+ Py_END_CRITICAL_SECTION(); -+ -+exit: -+ return return_value; - } - - PyDoc_STRVAR(_asyncio_Future_set_result__doc__, -@@ -145,7 +159,7 @@ - PyObject *result); - - static PyObject * --_asyncio_Future_set_result(FutureObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_asyncio_Future_set_result(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -170,7 +184,9 @@ - goto exit; - } - result = args[0]; -- return_value = _asyncio_Future_set_result_impl(self, cls, result); -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Future_set_result_impl((FutureObj *)self, cls, result); -+ Py_END_CRITICAL_SECTION(); - - exit: - return return_value; -@@ -193,7 +209,7 @@ - PyObject *exception); - - static PyObject * --_asyncio_Future_set_exception(FutureObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_asyncio_Future_set_exception(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -218,7 +234,9 @@ - goto exit; - } - exception = args[0]; -- return_value = _asyncio_Future_set_exception_impl(self, cls, exception); -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Future_set_exception_impl((FutureObj *)self, cls, exception); -+ Py_END_CRITICAL_SECTION(); - - exit: - return return_value; -@@ -242,7 +260,7 @@ - PyObject *fn, PyObject *context); - - static PyObject * --_asyncio_Future_add_done_callback(FutureObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_asyncio_Future_add_done_callback(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -286,7 +304,9 @@ - } - context = args[1]; - skip_optional_kwonly: -- return_value = _asyncio_Future_add_done_callback_impl(self, cls, fn, context); -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Future_add_done_callback_impl((FutureObj *)self, cls, fn, context); -+ Py_END_CRITICAL_SECTION(); - - exit: - return return_value; -@@ -308,7 +328,7 @@ - PyObject *fn); - - static PyObject * --_asyncio_Future_remove_done_callback(FutureObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_asyncio_Future_remove_done_callback(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -333,7 +353,9 @@ - goto exit; - } - fn = args[0]; -- return_value = _asyncio_Future_remove_done_callback_impl(self, cls, fn); -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Future_remove_done_callback_impl((FutureObj *)self, cls, fn); -+ Py_END_CRITICAL_SECTION(); - - exit: - return return_value; -@@ -357,7 +379,7 @@ - PyObject *msg); - - static PyObject * --_asyncio_Future_cancel(FutureObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_asyncio_Future_cancel(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -399,7 +421,9 @@ - } - msg = args[0]; - skip_optional_pos: -- return_value = _asyncio_Future_cancel_impl(self, cls, msg); -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Future_cancel_impl((FutureObj *)self, cls, msg); -+ Py_END_CRITICAL_SECTION(); - - exit: - return return_value; -@@ -418,9 +442,15 @@ - _asyncio_Future_cancelled_impl(FutureObj *self); - - static PyObject * --_asyncio_Future_cancelled(FutureObj *self, PyObject *Py_UNUSED(ignored)) -+_asyncio_Future_cancelled(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _asyncio_Future_cancelled_impl(self); -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Future_cancelled_impl((FutureObj *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; - } - - PyDoc_STRVAR(_asyncio_Future_done__doc__, -@@ -439,9 +469,15 @@ - _asyncio_Future_done_impl(FutureObj *self); - - static PyObject * --_asyncio_Future_done(FutureObj *self, PyObject *Py_UNUSED(ignored)) -+_asyncio_Future_done(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _asyncio_Future_done_impl(self); -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Future_done_impl((FutureObj *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; - } - - PyDoc_STRVAR(_asyncio_Future_get_loop__doc__, -@@ -457,13 +493,346 @@ - _asyncio_Future_get_loop_impl(FutureObj *self, PyTypeObject *cls); - - static PyObject * --_asyncio_Future_get_loop(FutureObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_asyncio_Future_get_loop(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { -+ PyObject *return_value = NULL; -+ - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "get_loop() takes no arguments"); -- return NULL; -+ goto exit; - } -- return _asyncio_Future_get_loop_impl(self, cls); -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Future_get_loop_impl((FutureObj *)self, cls); -+ Py_END_CRITICAL_SECTION(); -+ -+exit: -+ return return_value; -+} -+ -+#if !defined(_asyncio_Future__asyncio_awaited_by_DOCSTR) -+# define _asyncio_Future__asyncio_awaited_by_DOCSTR NULL -+#endif -+#if defined(_ASYNCIO_FUTURE__ASYNCIO_AWAITED_BY_GETSETDEF) -+# undef _ASYNCIO_FUTURE__ASYNCIO_AWAITED_BY_GETSETDEF -+# define _ASYNCIO_FUTURE__ASYNCIO_AWAITED_BY_GETSETDEF {"_asyncio_awaited_by", (getter)_asyncio_Future__asyncio_awaited_by_get, (setter)_asyncio_Future__asyncio_awaited_by_set, _asyncio_Future__asyncio_awaited_by_DOCSTR}, -+#else -+# define _ASYNCIO_FUTURE__ASYNCIO_AWAITED_BY_GETSETDEF {"_asyncio_awaited_by", (getter)_asyncio_Future__asyncio_awaited_by_get, NULL, _asyncio_Future__asyncio_awaited_by_DOCSTR}, -+#endif -+ -+static PyObject * -+_asyncio_Future__asyncio_awaited_by_get_impl(FutureObj *self); -+ -+static PyObject * -+_asyncio_Future__asyncio_awaited_by_get(PyObject *self, void *Py_UNUSED(context)) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Future__asyncio_awaited_by_get_impl((FutureObj *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(_asyncio_Future__asyncio_future_blocking_DOCSTR) -+# define _asyncio_Future__asyncio_future_blocking_DOCSTR NULL -+#endif -+#if defined(_ASYNCIO_FUTURE__ASYNCIO_FUTURE_BLOCKING_GETSETDEF) -+# undef _ASYNCIO_FUTURE__ASYNCIO_FUTURE_BLOCKING_GETSETDEF -+# define _ASYNCIO_FUTURE__ASYNCIO_FUTURE_BLOCKING_GETSETDEF {"_asyncio_future_blocking", (getter)_asyncio_Future__asyncio_future_blocking_get, (setter)_asyncio_Future__asyncio_future_blocking_set, _asyncio_Future__asyncio_future_blocking_DOCSTR}, -+#else -+# define _ASYNCIO_FUTURE__ASYNCIO_FUTURE_BLOCKING_GETSETDEF {"_asyncio_future_blocking", (getter)_asyncio_Future__asyncio_future_blocking_get, NULL, _asyncio_Future__asyncio_future_blocking_DOCSTR}, -+#endif -+ -+static PyObject * -+_asyncio_Future__asyncio_future_blocking_get_impl(FutureObj *self); -+ -+static PyObject * -+_asyncio_Future__asyncio_future_blocking_get(PyObject *self, void *Py_UNUSED(context)) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Future__asyncio_future_blocking_get_impl((FutureObj *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(_asyncio_Future__asyncio_future_blocking_DOCSTR) -+# define _asyncio_Future__asyncio_future_blocking_DOCSTR NULL -+#endif -+#if defined(_ASYNCIO_FUTURE__ASYNCIO_FUTURE_BLOCKING_GETSETDEF) -+# undef _ASYNCIO_FUTURE__ASYNCIO_FUTURE_BLOCKING_GETSETDEF -+# define _ASYNCIO_FUTURE__ASYNCIO_FUTURE_BLOCKING_GETSETDEF {"_asyncio_future_blocking", (getter)_asyncio_Future__asyncio_future_blocking_get, (setter)_asyncio_Future__asyncio_future_blocking_set, _asyncio_Future__asyncio_future_blocking_DOCSTR}, -+#else -+# define _ASYNCIO_FUTURE__ASYNCIO_FUTURE_BLOCKING_GETSETDEF {"_asyncio_future_blocking", NULL, (setter)_asyncio_Future__asyncio_future_blocking_set, NULL}, -+#endif -+ -+static int -+_asyncio_Future__asyncio_future_blocking_set_impl(FutureObj *self, -+ PyObject *value); -+ -+static int -+_asyncio_Future__asyncio_future_blocking_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) -+{ -+ int return_value; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Future__asyncio_future_blocking_set_impl((FutureObj *)self, value); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(_asyncio_Future__log_traceback_DOCSTR) -+# define _asyncio_Future__log_traceback_DOCSTR NULL -+#endif -+#if defined(_ASYNCIO_FUTURE__LOG_TRACEBACK_GETSETDEF) -+# undef _ASYNCIO_FUTURE__LOG_TRACEBACK_GETSETDEF -+# define _ASYNCIO_FUTURE__LOG_TRACEBACK_GETSETDEF {"_log_traceback", (getter)_asyncio_Future__log_traceback_get, (setter)_asyncio_Future__log_traceback_set, _asyncio_Future__log_traceback_DOCSTR}, -+#else -+# define _ASYNCIO_FUTURE__LOG_TRACEBACK_GETSETDEF {"_log_traceback", (getter)_asyncio_Future__log_traceback_get, NULL, _asyncio_Future__log_traceback_DOCSTR}, -+#endif -+ -+static PyObject * -+_asyncio_Future__log_traceback_get_impl(FutureObj *self); -+ -+static PyObject * -+_asyncio_Future__log_traceback_get(PyObject *self, void *Py_UNUSED(context)) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Future__log_traceback_get_impl((FutureObj *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(_asyncio_Future__log_traceback_DOCSTR) -+# define _asyncio_Future__log_traceback_DOCSTR NULL -+#endif -+#if defined(_ASYNCIO_FUTURE__LOG_TRACEBACK_GETSETDEF) -+# undef _ASYNCIO_FUTURE__LOG_TRACEBACK_GETSETDEF -+# define _ASYNCIO_FUTURE__LOG_TRACEBACK_GETSETDEF {"_log_traceback", (getter)_asyncio_Future__log_traceback_get, (setter)_asyncio_Future__log_traceback_set, _asyncio_Future__log_traceback_DOCSTR}, -+#else -+# define _ASYNCIO_FUTURE__LOG_TRACEBACK_GETSETDEF {"_log_traceback", NULL, (setter)_asyncio_Future__log_traceback_set, NULL}, -+#endif -+ -+static int -+_asyncio_Future__log_traceback_set_impl(FutureObj *self, PyObject *value); -+ -+static int -+_asyncio_Future__log_traceback_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) -+{ -+ int return_value; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Future__log_traceback_set_impl((FutureObj *)self, value); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(_asyncio_Future__loop_DOCSTR) -+# define _asyncio_Future__loop_DOCSTR NULL -+#endif -+#if defined(_ASYNCIO_FUTURE__LOOP_GETSETDEF) -+# undef _ASYNCIO_FUTURE__LOOP_GETSETDEF -+# define _ASYNCIO_FUTURE__LOOP_GETSETDEF {"_loop", (getter)_asyncio_Future__loop_get, (setter)_asyncio_Future__loop_set, _asyncio_Future__loop_DOCSTR}, -+#else -+# define _ASYNCIO_FUTURE__LOOP_GETSETDEF {"_loop", (getter)_asyncio_Future__loop_get, NULL, _asyncio_Future__loop_DOCSTR}, -+#endif -+ -+static PyObject * -+_asyncio_Future__loop_get_impl(FutureObj *self); -+ -+static PyObject * -+_asyncio_Future__loop_get(PyObject *self, void *Py_UNUSED(context)) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Future__loop_get_impl((FutureObj *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(_asyncio_Future__callbacks_DOCSTR) -+# define _asyncio_Future__callbacks_DOCSTR NULL -+#endif -+#if defined(_ASYNCIO_FUTURE__CALLBACKS_GETSETDEF) -+# undef _ASYNCIO_FUTURE__CALLBACKS_GETSETDEF -+# define _ASYNCIO_FUTURE__CALLBACKS_GETSETDEF {"_callbacks", (getter)_asyncio_Future__callbacks_get, (setter)_asyncio_Future__callbacks_set, _asyncio_Future__callbacks_DOCSTR}, -+#else -+# define _ASYNCIO_FUTURE__CALLBACKS_GETSETDEF {"_callbacks", (getter)_asyncio_Future__callbacks_get, NULL, _asyncio_Future__callbacks_DOCSTR}, -+#endif -+ -+static PyObject * -+_asyncio_Future__callbacks_get_impl(FutureObj *self); -+ -+static PyObject * -+_asyncio_Future__callbacks_get(PyObject *self, void *Py_UNUSED(context)) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Future__callbacks_get_impl((FutureObj *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(_asyncio_Future__result_DOCSTR) -+# define _asyncio_Future__result_DOCSTR NULL -+#endif -+#if defined(_ASYNCIO_FUTURE__RESULT_GETSETDEF) -+# undef _ASYNCIO_FUTURE__RESULT_GETSETDEF -+# define _ASYNCIO_FUTURE__RESULT_GETSETDEF {"_result", (getter)_asyncio_Future__result_get, (setter)_asyncio_Future__result_set, _asyncio_Future__result_DOCSTR}, -+#else -+# define _ASYNCIO_FUTURE__RESULT_GETSETDEF {"_result", (getter)_asyncio_Future__result_get, NULL, _asyncio_Future__result_DOCSTR}, -+#endif -+ -+static PyObject * -+_asyncio_Future__result_get_impl(FutureObj *self); -+ -+static PyObject * -+_asyncio_Future__result_get(PyObject *self, void *Py_UNUSED(context)) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Future__result_get_impl((FutureObj *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(_asyncio_Future__exception_DOCSTR) -+# define _asyncio_Future__exception_DOCSTR NULL -+#endif -+#if defined(_ASYNCIO_FUTURE__EXCEPTION_GETSETDEF) -+# undef _ASYNCIO_FUTURE__EXCEPTION_GETSETDEF -+# define _ASYNCIO_FUTURE__EXCEPTION_GETSETDEF {"_exception", (getter)_asyncio_Future__exception_get, (setter)_asyncio_Future__exception_set, _asyncio_Future__exception_DOCSTR}, -+#else -+# define _ASYNCIO_FUTURE__EXCEPTION_GETSETDEF {"_exception", (getter)_asyncio_Future__exception_get, NULL, _asyncio_Future__exception_DOCSTR}, -+#endif -+ -+static PyObject * -+_asyncio_Future__exception_get_impl(FutureObj *self); -+ -+static PyObject * -+_asyncio_Future__exception_get(PyObject *self, void *Py_UNUSED(context)) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Future__exception_get_impl((FutureObj *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(_asyncio_Future__source_traceback_DOCSTR) -+# define _asyncio_Future__source_traceback_DOCSTR NULL -+#endif -+#if defined(_ASYNCIO_FUTURE__SOURCE_TRACEBACK_GETSETDEF) -+# undef _ASYNCIO_FUTURE__SOURCE_TRACEBACK_GETSETDEF -+# define _ASYNCIO_FUTURE__SOURCE_TRACEBACK_GETSETDEF {"_source_traceback", (getter)_asyncio_Future__source_traceback_get, (setter)_asyncio_Future__source_traceback_set, _asyncio_Future__source_traceback_DOCSTR}, -+#else -+# define _ASYNCIO_FUTURE__SOURCE_TRACEBACK_GETSETDEF {"_source_traceback", (getter)_asyncio_Future__source_traceback_get, NULL, _asyncio_Future__source_traceback_DOCSTR}, -+#endif -+ -+static PyObject * -+_asyncio_Future__source_traceback_get_impl(FutureObj *self); -+ -+static PyObject * -+_asyncio_Future__source_traceback_get(PyObject *self, void *Py_UNUSED(context)) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Future__source_traceback_get_impl((FutureObj *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(_asyncio_Future__cancel_message_DOCSTR) -+# define _asyncio_Future__cancel_message_DOCSTR NULL -+#endif -+#if defined(_ASYNCIO_FUTURE__CANCEL_MESSAGE_GETSETDEF) -+# undef _ASYNCIO_FUTURE__CANCEL_MESSAGE_GETSETDEF -+# define _ASYNCIO_FUTURE__CANCEL_MESSAGE_GETSETDEF {"_cancel_message", (getter)_asyncio_Future__cancel_message_get, (setter)_asyncio_Future__cancel_message_set, _asyncio_Future__cancel_message_DOCSTR}, -+#else -+# define _ASYNCIO_FUTURE__CANCEL_MESSAGE_GETSETDEF {"_cancel_message", (getter)_asyncio_Future__cancel_message_get, NULL, _asyncio_Future__cancel_message_DOCSTR}, -+#endif -+ -+static PyObject * -+_asyncio_Future__cancel_message_get_impl(FutureObj *self); -+ -+static PyObject * -+_asyncio_Future__cancel_message_get(PyObject *self, void *Py_UNUSED(context)) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Future__cancel_message_get_impl((FutureObj *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(_asyncio_Future__cancel_message_DOCSTR) -+# define _asyncio_Future__cancel_message_DOCSTR NULL -+#endif -+#if defined(_ASYNCIO_FUTURE__CANCEL_MESSAGE_GETSETDEF) -+# undef _ASYNCIO_FUTURE__CANCEL_MESSAGE_GETSETDEF -+# define _ASYNCIO_FUTURE__CANCEL_MESSAGE_GETSETDEF {"_cancel_message", (getter)_asyncio_Future__cancel_message_get, (setter)_asyncio_Future__cancel_message_set, _asyncio_Future__cancel_message_DOCSTR}, -+#else -+# define _ASYNCIO_FUTURE__CANCEL_MESSAGE_GETSETDEF {"_cancel_message", NULL, (setter)_asyncio_Future__cancel_message_set, NULL}, -+#endif -+ -+static int -+_asyncio_Future__cancel_message_set_impl(FutureObj *self, PyObject *value); -+ -+static int -+_asyncio_Future__cancel_message_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) -+{ -+ int return_value; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Future__cancel_message_set_impl((FutureObj *)self, value); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(_asyncio_Future__state_DOCSTR) -+# define _asyncio_Future__state_DOCSTR NULL -+#endif -+#if defined(_ASYNCIO_FUTURE__STATE_GETSETDEF) -+# undef _ASYNCIO_FUTURE__STATE_GETSETDEF -+# define _ASYNCIO_FUTURE__STATE_GETSETDEF {"_state", (getter)_asyncio_Future__state_get, (setter)_asyncio_Future__state_set, _asyncio_Future__state_DOCSTR}, -+#else -+# define _ASYNCIO_FUTURE__STATE_GETSETDEF {"_state", (getter)_asyncio_Future__state_get, NULL, _asyncio_Future__state_DOCSTR}, -+#endif -+ -+static PyObject * -+_asyncio_Future__state_get_impl(FutureObj *self); -+ -+static PyObject * -+_asyncio_Future__state_get(PyObject *self, void *Py_UNUSED(context)) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Future__state_get_impl((FutureObj *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; - } - - PyDoc_STRVAR(_asyncio_Future__make_cancelled_error__doc__, -@@ -482,9 +851,15 @@ - _asyncio_Future__make_cancelled_error_impl(FutureObj *self); - - static PyObject * --_asyncio_Future__make_cancelled_error(FutureObj *self, PyObject *Py_UNUSED(ignored)) -+_asyncio_Future__make_cancelled_error(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _asyncio_Future__make_cancelled_error_impl(self); -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Future__make_cancelled_error_impl((FutureObj *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; - } - - PyDoc_STRVAR(_asyncio_Task___init____doc__, -@@ -575,6 +950,131 @@ - return return_value; - } - -+#if !defined(_asyncio_Task__log_destroy_pending_DOCSTR) -+# define _asyncio_Task__log_destroy_pending_DOCSTR NULL -+#endif -+#if defined(_ASYNCIO_TASK__LOG_DESTROY_PENDING_GETSETDEF) -+# undef _ASYNCIO_TASK__LOG_DESTROY_PENDING_GETSETDEF -+# define _ASYNCIO_TASK__LOG_DESTROY_PENDING_GETSETDEF {"_log_destroy_pending", (getter)_asyncio_Task__log_destroy_pending_get, (setter)_asyncio_Task__log_destroy_pending_set, _asyncio_Task__log_destroy_pending_DOCSTR}, -+#else -+# define _ASYNCIO_TASK__LOG_DESTROY_PENDING_GETSETDEF {"_log_destroy_pending", (getter)_asyncio_Task__log_destroy_pending_get, NULL, _asyncio_Task__log_destroy_pending_DOCSTR}, -+#endif -+ -+static PyObject * -+_asyncio_Task__log_destroy_pending_get_impl(TaskObj *self); -+ -+static PyObject * -+_asyncio_Task__log_destroy_pending_get(PyObject *self, void *Py_UNUSED(context)) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Task__log_destroy_pending_get_impl((TaskObj *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(_asyncio_Task__log_destroy_pending_DOCSTR) -+# define _asyncio_Task__log_destroy_pending_DOCSTR NULL -+#endif -+#if defined(_ASYNCIO_TASK__LOG_DESTROY_PENDING_GETSETDEF) -+# undef _ASYNCIO_TASK__LOG_DESTROY_PENDING_GETSETDEF -+# define _ASYNCIO_TASK__LOG_DESTROY_PENDING_GETSETDEF {"_log_destroy_pending", (getter)_asyncio_Task__log_destroy_pending_get, (setter)_asyncio_Task__log_destroy_pending_set, _asyncio_Task__log_destroy_pending_DOCSTR}, -+#else -+# define _ASYNCIO_TASK__LOG_DESTROY_PENDING_GETSETDEF {"_log_destroy_pending", NULL, (setter)_asyncio_Task__log_destroy_pending_set, NULL}, -+#endif -+ -+static int -+_asyncio_Task__log_destroy_pending_set_impl(TaskObj *self, PyObject *value); -+ -+static int -+_asyncio_Task__log_destroy_pending_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) -+{ -+ int return_value; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Task__log_destroy_pending_set_impl((TaskObj *)self, value); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(_asyncio_Task__must_cancel_DOCSTR) -+# define _asyncio_Task__must_cancel_DOCSTR NULL -+#endif -+#if defined(_ASYNCIO_TASK__MUST_CANCEL_GETSETDEF) -+# undef _ASYNCIO_TASK__MUST_CANCEL_GETSETDEF -+# define _ASYNCIO_TASK__MUST_CANCEL_GETSETDEF {"_must_cancel", (getter)_asyncio_Task__must_cancel_get, (setter)_asyncio_Task__must_cancel_set, _asyncio_Task__must_cancel_DOCSTR}, -+#else -+# define _ASYNCIO_TASK__MUST_CANCEL_GETSETDEF {"_must_cancel", (getter)_asyncio_Task__must_cancel_get, NULL, _asyncio_Task__must_cancel_DOCSTR}, -+#endif -+ -+static PyObject * -+_asyncio_Task__must_cancel_get_impl(TaskObj *self); -+ -+static PyObject * -+_asyncio_Task__must_cancel_get(PyObject *self, void *Py_UNUSED(context)) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Task__must_cancel_get_impl((TaskObj *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(_asyncio_Task__coro_DOCSTR) -+# define _asyncio_Task__coro_DOCSTR NULL -+#endif -+#if defined(_ASYNCIO_TASK__CORO_GETSETDEF) -+# undef _ASYNCIO_TASK__CORO_GETSETDEF -+# define _ASYNCIO_TASK__CORO_GETSETDEF {"_coro", (getter)_asyncio_Task__coro_get, (setter)_asyncio_Task__coro_set, _asyncio_Task__coro_DOCSTR}, -+#else -+# define _ASYNCIO_TASK__CORO_GETSETDEF {"_coro", (getter)_asyncio_Task__coro_get, NULL, _asyncio_Task__coro_DOCSTR}, -+#endif -+ -+static PyObject * -+_asyncio_Task__coro_get_impl(TaskObj *self); -+ -+static PyObject * -+_asyncio_Task__coro_get(PyObject *self, void *Py_UNUSED(context)) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Task__coro_get_impl((TaskObj *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(_asyncio_Task__fut_waiter_DOCSTR) -+# define _asyncio_Task__fut_waiter_DOCSTR NULL -+#endif -+#if defined(_ASYNCIO_TASK__FUT_WAITER_GETSETDEF) -+# undef _ASYNCIO_TASK__FUT_WAITER_GETSETDEF -+# define _ASYNCIO_TASK__FUT_WAITER_GETSETDEF {"_fut_waiter", (getter)_asyncio_Task__fut_waiter_get, (setter)_asyncio_Task__fut_waiter_set, _asyncio_Task__fut_waiter_DOCSTR}, -+#else -+# define _ASYNCIO_TASK__FUT_WAITER_GETSETDEF {"_fut_waiter", (getter)_asyncio_Task__fut_waiter_get, NULL, _asyncio_Task__fut_waiter_DOCSTR}, -+#endif -+ -+static PyObject * -+_asyncio_Task__fut_waiter_get_impl(TaskObj *self); -+ -+static PyObject * -+_asyncio_Task__fut_waiter_get(PyObject *self, void *Py_UNUSED(context)) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Task__fut_waiter_get_impl((TaskObj *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ - PyDoc_STRVAR(_asyncio_Task__make_cancelled_error__doc__, - "_make_cancelled_error($self, /)\n" - "--\n" -@@ -591,9 +1091,15 @@ - _asyncio_Task__make_cancelled_error_impl(TaskObj *self); - - static PyObject * --_asyncio_Task__make_cancelled_error(TaskObj *self, PyObject *Py_UNUSED(ignored)) -+_asyncio_Task__make_cancelled_error(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _asyncio_Task__make_cancelled_error_impl(self); -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Task__make_cancelled_error_impl((TaskObj *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; - } - - PyDoc_STRVAR(_asyncio_Task_cancel__doc__, -@@ -628,7 +1134,7 @@ - _asyncio_Task_cancel_impl(TaskObj *self, PyObject *msg); - - static PyObject * --_asyncio_Task_cancel(TaskObj *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_asyncio_Task_cancel(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -670,7 +1176,9 @@ - } - msg = args[0]; - skip_optional_pos: -- return_value = _asyncio_Task_cancel_impl(self, msg); -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Task_cancel_impl((TaskObj *)self, msg); -+ Py_END_CRITICAL_SECTION(); - - exit: - return return_value; -@@ -692,9 +1200,15 @@ - _asyncio_Task_cancelling_impl(TaskObj *self); - - static PyObject * --_asyncio_Task_cancelling(TaskObj *self, PyObject *Py_UNUSED(ignored)) -+_asyncio_Task_cancelling(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _asyncio_Task_cancelling_impl(self); -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Task_cancelling_impl((TaskObj *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; - } - - PyDoc_STRVAR(_asyncio_Task_uncancel__doc__, -@@ -715,9 +1229,15 @@ - _asyncio_Task_uncancel_impl(TaskObj *self); - - static PyObject * --_asyncio_Task_uncancel(TaskObj *self, PyObject *Py_UNUSED(ignored)) -+_asyncio_Task_uncancel(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _asyncio_Task_uncancel_impl(self); -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Task_uncancel_impl((TaskObj *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; - } - - PyDoc_STRVAR(_asyncio_Task_get_stack__doc__, -@@ -752,7 +1272,7 @@ - PyObject *limit); - - static PyObject * --_asyncio_Task_get_stack(TaskObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_asyncio_Task_get_stack(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -794,7 +1314,7 @@ - } - limit = args[0]; - skip_optional_kwonly: -- return_value = _asyncio_Task_get_stack_impl(self, cls, limit); -+ return_value = _asyncio_Task_get_stack_impl((TaskObj *)self, cls, limit); - - exit: - return return_value; -@@ -820,7 +1340,7 @@ - PyObject *limit, PyObject *file); - - static PyObject * --_asyncio_Task_print_stack(TaskObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_asyncio_Task_print_stack(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -869,7 +1389,7 @@ - } - file = args[1]; - skip_optional_kwonly: -- return_value = _asyncio_Task_print_stack_impl(self, cls, limit, file); -+ return_value = _asyncio_Task_print_stack_impl((TaskObj *)self, cls, limit, file); - - exit: - return return_value; -@@ -903,9 +1423,15 @@ - _asyncio_Task_get_coro_impl(TaskObj *self); - - static PyObject * --_asyncio_Task_get_coro(TaskObj *self, PyObject *Py_UNUSED(ignored)) -+_asyncio_Task_get_coro(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _asyncio_Task_get_coro_impl(self); -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Task_get_coro_impl((TaskObj *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; - } - - PyDoc_STRVAR(_asyncio_Task_get_context__doc__, -@@ -920,9 +1446,9 @@ - _asyncio_Task_get_context_impl(TaskObj *self); - - static PyObject * --_asyncio_Task_get_context(TaskObj *self, PyObject *Py_UNUSED(ignored)) -+_asyncio_Task_get_context(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _asyncio_Task_get_context_impl(self); -+ return _asyncio_Task_get_context_impl((TaskObj *)self); - } - - PyDoc_STRVAR(_asyncio_Task_get_name__doc__, -@@ -937,9 +1463,15 @@ - _asyncio_Task_get_name_impl(TaskObj *self); - - static PyObject * --_asyncio_Task_get_name(TaskObj *self, PyObject *Py_UNUSED(ignored)) -+_asyncio_Task_get_name(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _asyncio_Task_get_name_impl(self); -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Task_get_name_impl((TaskObj *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; - } - - PyDoc_STRVAR(_asyncio_Task_set_name__doc__, -@@ -950,6 +1482,21 @@ - #define _ASYNCIO_TASK_SET_NAME_METHODDEF \ - {"set_name", (PyCFunction)_asyncio_Task_set_name, METH_O, _asyncio_Task_set_name__doc__}, - -+static PyObject * -+_asyncio_Task_set_name_impl(TaskObj *self, PyObject *value); -+ -+static PyObject * -+_asyncio_Task_set_name(TaskObj *self, PyObject *value) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = _asyncio_Task_set_name_impl((TaskObj *)self, value); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ - PyDoc_STRVAR(_asyncio__get_running_loop__doc__, - "_get_running_loop($module, /)\n" - "--\n" -@@ -1566,4 +2113,65 @@ - exit: - return return_value; - } --/*[clinic end generated code: output=e5d95a0ec229ffcd input=a9049054013a1b77]*/ -+ -+PyDoc_STRVAR(_asyncio_future_add_to_awaited_by__doc__, -+"future_add_to_awaited_by($module, fut, waiter, /)\n" -+"--\n" -+"\n" -+"Record that `fut` is awaited on by `waiter`."); -+ -+#define _ASYNCIO_FUTURE_ADD_TO_AWAITED_BY_METHODDEF \ -+ {"future_add_to_awaited_by", _PyCFunction_CAST(_asyncio_future_add_to_awaited_by), METH_FASTCALL, _asyncio_future_add_to_awaited_by__doc__}, -+ -+static PyObject * -+_asyncio_future_add_to_awaited_by_impl(PyObject *module, PyObject *fut, -+ PyObject *waiter); -+ -+static PyObject * -+_asyncio_future_add_to_awaited_by(PyObject *module, PyObject *const *args, Py_ssize_t nargs) -+{ -+ PyObject *return_value = NULL; -+ PyObject *fut; -+ PyObject *waiter; -+ -+ if (!_PyArg_CheckPositional("future_add_to_awaited_by", nargs, 2, 2)) { -+ goto exit; -+ } -+ fut = args[0]; -+ waiter = args[1]; -+ return_value = _asyncio_future_add_to_awaited_by_impl(module, fut, waiter); -+ -+exit: -+ return return_value; -+} -+ -+PyDoc_STRVAR(_asyncio_future_discard_from_awaited_by__doc__, -+"future_discard_from_awaited_by($module, fut, waiter, /)\n" -+"--\n" -+"\n"); -+ -+#define _ASYNCIO_FUTURE_DISCARD_FROM_AWAITED_BY_METHODDEF \ -+ {"future_discard_from_awaited_by", _PyCFunction_CAST(_asyncio_future_discard_from_awaited_by), METH_FASTCALL, _asyncio_future_discard_from_awaited_by__doc__}, -+ -+static PyObject * -+_asyncio_future_discard_from_awaited_by_impl(PyObject *module, PyObject *fut, -+ PyObject *waiter); -+ -+static PyObject * -+_asyncio_future_discard_from_awaited_by(PyObject *module, PyObject *const *args, Py_ssize_t nargs) -+{ -+ PyObject *return_value = NULL; -+ PyObject *fut; -+ PyObject *waiter; -+ -+ if (!_PyArg_CheckPositional("future_discard_from_awaited_by", nargs, 2, 2)) { -+ goto exit; -+ } -+ fut = args[0]; -+ waiter = args[1]; -+ return_value = _asyncio_future_discard_from_awaited_by_impl(module, fut, waiter); -+ -+exit: -+ return return_value; -+} -+/*[clinic end generated code: output=f14ff14c29c691ec input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/_bz2module.c.h b/Modules/clinic/_bz2module.c.h -index 93988bf48a1..a599bd1a8be 100644 ---- a/Modules/clinic/_bz2module.c.h -+++ b/Modules/clinic/_bz2module.c.h -@@ -27,7 +27,7 @@ - _bz2_BZ2Compressor_compress_impl(BZ2Compressor *self, Py_buffer *data); - - static PyObject * --_bz2_BZ2Compressor_compress(BZ2Compressor *self, PyObject *arg) -+_bz2_BZ2Compressor_compress(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - Py_buffer data = {NULL, NULL}; -@@ -35,7 +35,7 @@ - if (PyObject_GetBuffer(arg, &data, PyBUF_SIMPLE) != 0) { - goto exit; - } -- return_value = _bz2_BZ2Compressor_compress_impl(self, &data); -+ return_value = _bz2_BZ2Compressor_compress_impl((BZ2Compressor *)self, &data); - - exit: - /* Cleanup for data */ -@@ -63,9 +63,9 @@ - _bz2_BZ2Compressor_flush_impl(BZ2Compressor *self); - - static PyObject * --_bz2_BZ2Compressor_flush(BZ2Compressor *self, PyObject *Py_UNUSED(ignored)) -+_bz2_BZ2Compressor_flush(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _bz2_BZ2Compressor_flush_impl(self); -+ return _bz2_BZ2Compressor_flush_impl((BZ2Compressor *)self); - } - - PyDoc_STRVAR(_bz2_BZ2Compressor__doc__, -@@ -137,7 +137,7 @@ - Py_ssize_t max_length); - - static PyObject * --_bz2_BZ2Decompressor_decompress(BZ2Decompressor *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_bz2_BZ2Decompressor_decompress(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -194,7 +194,7 @@ - max_length = ival; - } - skip_optional_pos: -- return_value = _bz2_BZ2Decompressor_decompress_impl(self, &data, max_length); -+ return_value = _bz2_BZ2Decompressor_decompress_impl((BZ2Decompressor *)self, &data, max_length); - - exit: - /* Cleanup for data */ -@@ -235,4 +235,4 @@ - exit: - return return_value; - } --/*[clinic end generated code: output=701a383434374c36 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=0fc5a6292c5fd2c5 input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/_collectionsmodule.c.h b/Modules/clinic/_collectionsmodule.c.h -index b4e3325e895..ddf18c2c77a 100644 ---- a/Modules/clinic/_collectionsmodule.c.h -+++ b/Modules/clinic/_collectionsmodule.c.h -@@ -23,12 +23,12 @@ - deque_pop_impl(dequeobject *deque); - - static PyObject * --deque_pop(dequeobject *deque, PyObject *Py_UNUSED(ignored)) -+deque_pop(PyObject *deque, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(deque); -- return_value = deque_pop_impl(deque); -+ return_value = deque_pop_impl((dequeobject *)deque); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -47,12 +47,12 @@ - deque_popleft_impl(dequeobject *deque); - - static PyObject * --deque_popleft(dequeobject *deque, PyObject *Py_UNUSED(ignored)) -+deque_popleft(PyObject *deque, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(deque); -- return_value = deque_popleft_impl(deque); -+ return_value = deque_popleft_impl((dequeobject *)deque); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -76,7 +76,7 @@ - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(deque); -- return_value = deque_append_impl(deque, item); -+ return_value = deque_append_impl((dequeobject *)deque, item); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -100,7 +100,7 @@ - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(deque); -- return_value = deque_appendleft_impl(deque, item); -+ return_value = deque_appendleft_impl((dequeobject *)deque, item); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -124,7 +124,7 @@ - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(deque); -- return_value = deque_extend_impl(deque, iterable); -+ return_value = deque_extend_impl((dequeobject *)deque, iterable); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -148,7 +148,7 @@ - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(deque); -- return_value = deque_extendleft_impl(deque, iterable); -+ return_value = deque_extendleft_impl((dequeobject *)deque, iterable); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -167,12 +167,12 @@ - deque_copy_impl(dequeobject *deque); - - static PyObject * --deque_copy(dequeobject *deque, PyObject *Py_UNUSED(ignored)) -+deque_copy(PyObject *deque, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(deque); -- return_value = deque_copy_impl(deque); -+ return_value = deque_copy_impl((dequeobject *)deque); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -191,12 +191,12 @@ - deque___copy___impl(dequeobject *deque); - - static PyObject * --deque___copy__(dequeobject *deque, PyObject *Py_UNUSED(ignored)) -+deque___copy__(PyObject *deque, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(deque); -- return_value = deque___copy___impl(deque); -+ return_value = deque___copy___impl((dequeobject *)deque); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -215,12 +215,12 @@ - deque_clearmethod_impl(dequeobject *deque); - - static PyObject * --deque_clearmethod(dequeobject *deque, PyObject *Py_UNUSED(ignored)) -+deque_clearmethod(PyObject *deque, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(deque); -- return_value = deque_clearmethod_impl(deque); -+ return_value = deque_clearmethod_impl((dequeobject *)deque); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -239,7 +239,7 @@ - deque_rotate_impl(dequeobject *deque, Py_ssize_t n); - - static PyObject * --deque_rotate(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) -+deque_rotate(PyObject *deque, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - Py_ssize_t n = 1; -@@ -264,7 +264,7 @@ - } - skip_optional: - Py_BEGIN_CRITICAL_SECTION(deque); -- return_value = deque_rotate_impl(deque, n); -+ return_value = deque_rotate_impl((dequeobject *)deque, n); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -284,12 +284,12 @@ - deque_reverse_impl(dequeobject *deque); - - static PyObject * --deque_reverse(dequeobject *deque, PyObject *Py_UNUSED(ignored)) -+deque_reverse(PyObject *deque, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(deque); -- return_value = deque_reverse_impl(deque); -+ return_value = deque_reverse_impl((dequeobject *)deque); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -313,7 +313,7 @@ - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(deque); -- return_value = deque_count_impl(deque, v); -+ return_value = deque_count_impl((dequeobject *)deque, v); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -335,7 +335,7 @@ - Py_ssize_t stop); - - static PyObject * --deque_index(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) -+deque_index(PyObject *deque, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *v; -@@ -360,7 +360,7 @@ - } - skip_optional: - Py_BEGIN_CRITICAL_SECTION(deque); -- return_value = deque_index_impl(deque, v, start, stop); -+ return_value = deque_index_impl((dequeobject *)deque, v, start, stop); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -380,7 +380,7 @@ - deque_insert_impl(dequeobject *deque, Py_ssize_t index, PyObject *value); - - static PyObject * --deque_insert(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) -+deque_insert(PyObject *deque, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - Py_ssize_t index; -@@ -403,7 +403,7 @@ - } - value = args[1]; - Py_BEGIN_CRITICAL_SECTION(deque); -- return_value = deque_insert_impl(deque, index, value); -+ return_value = deque_insert_impl((dequeobject *)deque, index, value); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -428,7 +428,7 @@ - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(deque); -- return_value = deque_remove_impl(deque, value); -+ return_value = deque_remove_impl((dequeobject *)deque, value); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -447,9 +447,9 @@ - deque___reduce___impl(dequeobject *deque); - - static PyObject * --deque___reduce__(dequeobject *deque, PyObject *Py_UNUSED(ignored)) -+deque___reduce__(PyObject *deque, PyObject *Py_UNUSED(ignored)) - { -- return deque___reduce___impl(deque); -+ return deque___reduce___impl((dequeobject *)deque); - } - - PyDoc_STRVAR(deque_init__doc__, -@@ -534,12 +534,12 @@ - deque___sizeof___impl(dequeobject *deque); - - static PyObject * --deque___sizeof__(dequeobject *deque, PyObject *Py_UNUSED(ignored)) -+deque___sizeof__(PyObject *deque, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(deque); -- return_value = deque___sizeof___impl(deque); -+ return_value = deque___sizeof___impl((dequeobject *)deque); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -558,9 +558,9 @@ - deque___reversed___impl(dequeobject *deque); - - static PyObject * --deque___reversed__(dequeobject *deque, PyObject *Py_UNUSED(ignored)) -+deque___reversed__(PyObject *deque, PyObject *Py_UNUSED(ignored)) - { -- return deque___reversed___impl(deque); -+ return deque___reversed___impl((dequeobject *)deque); - } - - PyDoc_STRVAR(_collections__count_elements__doc__, -@@ -630,4 +630,4 @@ - exit: - return return_value; - } --/*[clinic end generated code: output=65f896fb13902f6d input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=2d89c39288fc7389 input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/_curses_panel.c.h b/Modules/clinic/_curses_panel.c.h -index b6bff5274a3..6f4966825ec 100644 ---- a/Modules/clinic/_curses_panel.c.h -+++ b/Modules/clinic/_curses_panel.c.h -@@ -20,13 +20,13 @@ - _curses_panel_panel_bottom_impl(PyCursesPanelObject *self, PyTypeObject *cls); - - static PyObject * --_curses_panel_panel_bottom(PyCursesPanelObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_curses_panel_panel_bottom(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "bottom() takes no arguments"); - return NULL; - } -- return _curses_panel_panel_bottom_impl(self, cls); -+ return _curses_panel_panel_bottom_impl((PyCursesPanelObject *)self, cls); - } - - PyDoc_STRVAR(_curses_panel_panel_hide__doc__, -@@ -44,13 +44,13 @@ - _curses_panel_panel_hide_impl(PyCursesPanelObject *self, PyTypeObject *cls); - - static PyObject * --_curses_panel_panel_hide(PyCursesPanelObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_curses_panel_panel_hide(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "hide() takes no arguments"); - return NULL; - } -- return _curses_panel_panel_hide_impl(self, cls); -+ return _curses_panel_panel_hide_impl((PyCursesPanelObject *)self, cls); - } - - PyDoc_STRVAR(_curses_panel_panel_show__doc__, -@@ -66,13 +66,13 @@ - _curses_panel_panel_show_impl(PyCursesPanelObject *self, PyTypeObject *cls); - - static PyObject * --_curses_panel_panel_show(PyCursesPanelObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_curses_panel_panel_show(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "show() takes no arguments"); - return NULL; - } -- return _curses_panel_panel_show_impl(self, cls); -+ return _curses_panel_panel_show_impl((PyCursesPanelObject *)self, cls); - } - - PyDoc_STRVAR(_curses_panel_panel_top__doc__, -@@ -88,13 +88,13 @@ - _curses_panel_panel_top_impl(PyCursesPanelObject *self, PyTypeObject *cls); - - static PyObject * --_curses_panel_panel_top(PyCursesPanelObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_curses_panel_panel_top(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "top() takes no arguments"); - return NULL; - } -- return _curses_panel_panel_top_impl(self, cls); -+ return _curses_panel_panel_top_impl((PyCursesPanelObject *)self, cls); - } - - PyDoc_STRVAR(_curses_panel_panel_above__doc__, -@@ -110,9 +110,9 @@ - _curses_panel_panel_above_impl(PyCursesPanelObject *self); - - static PyObject * --_curses_panel_panel_above(PyCursesPanelObject *self, PyObject *Py_UNUSED(ignored)) -+_curses_panel_panel_above(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _curses_panel_panel_above_impl(self); -+ return _curses_panel_panel_above_impl((PyCursesPanelObject *)self); - } - - PyDoc_STRVAR(_curses_panel_panel_below__doc__, -@@ -128,9 +128,9 @@ - _curses_panel_panel_below_impl(PyCursesPanelObject *self); - - static PyObject * --_curses_panel_panel_below(PyCursesPanelObject *self, PyObject *Py_UNUSED(ignored)) -+_curses_panel_panel_below(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _curses_panel_panel_below_impl(self); -+ return _curses_panel_panel_below_impl((PyCursesPanelObject *)self); - } - - PyDoc_STRVAR(_curses_panel_panel_hidden__doc__, -@@ -146,9 +146,9 @@ - _curses_panel_panel_hidden_impl(PyCursesPanelObject *self); - - static PyObject * --_curses_panel_panel_hidden(PyCursesPanelObject *self, PyObject *Py_UNUSED(ignored)) -+_curses_panel_panel_hidden(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _curses_panel_panel_hidden_impl(self); -+ return _curses_panel_panel_hidden_impl((PyCursesPanelObject *)self); - } - - PyDoc_STRVAR(_curses_panel_panel_move__doc__, -@@ -165,7 +165,7 @@ - int y, int x); - - static PyObject * --_curses_panel_panel_move(PyCursesPanelObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_curses_panel_panel_move(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -198,7 +198,7 @@ - if (x == -1 && PyErr_Occurred()) { - goto exit; - } -- return_value = _curses_panel_panel_move_impl(self, cls, y, x); -+ return_value = _curses_panel_panel_move_impl((PyCursesPanelObject *)self, cls, y, x); - - exit: - return return_value; -@@ -217,9 +217,9 @@ - _curses_panel_panel_window_impl(PyCursesPanelObject *self); - - static PyObject * --_curses_panel_panel_window(PyCursesPanelObject *self, PyObject *Py_UNUSED(ignored)) -+_curses_panel_panel_window(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _curses_panel_panel_window_impl(self); -+ return _curses_panel_panel_window_impl((PyCursesPanelObject *)self); - } - - PyDoc_STRVAR(_curses_panel_panel_replace__doc__, -@@ -237,7 +237,7 @@ - PyCursesWindowObject *win); - - static PyObject * --_curses_panel_panel_replace(PyCursesPanelObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_curses_panel_panel_replace(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -266,7 +266,7 @@ - goto exit; - } - win = (PyCursesWindowObject *)args[0]; -- return_value = _curses_panel_panel_replace_impl(self, cls, win); -+ return_value = _curses_panel_panel_replace_impl((PyCursesPanelObject *)self, cls, win); - - exit: - return return_value; -@@ -286,7 +286,7 @@ - PyTypeObject *cls, PyObject *obj); - - static PyObject * --_curses_panel_panel_set_userptr(PyCursesPanelObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_curses_panel_panel_set_userptr(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -311,7 +311,7 @@ - goto exit; - } - obj = args[0]; -- return_value = _curses_panel_panel_set_userptr_impl(self, cls, obj); -+ return_value = _curses_panel_panel_set_userptr_impl((PyCursesPanelObject *)self, cls, obj); - - exit: - return return_value; -@@ -331,13 +331,13 @@ - PyTypeObject *cls); - - static PyObject * --_curses_panel_panel_userptr(PyCursesPanelObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_curses_panel_panel_userptr(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "userptr() takes no arguments"); - return NULL; - } -- return _curses_panel_panel_userptr_impl(self, cls); -+ return _curses_panel_panel_userptr_impl((PyCursesPanelObject *)self, cls); - } - - PyDoc_STRVAR(_curses_panel_bottom_panel__doc__, -@@ -424,4 +424,4 @@ - { - return _curses_panel_update_panels_impl(module); - } --/*[clinic end generated code: output=298e49d54c0b14a0 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=36853ecb4a979814 input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h -index 524a114aba9..8291d5d635c 100644 ---- a/Modules/clinic/_cursesmodule.c.h -+++ b/Modules/clinic/_cursesmodule.c.h -@@ -35,7 +35,7 @@ - long attr); - - static PyObject * --_curses_window_addch(PyCursesWindowObject *self, PyObject *args) -+_curses_window_addch(PyObject *self, PyObject *args) - { - PyObject *return_value = NULL; - int group_left_1 = 0; -@@ -74,7 +74,7 @@ - PyErr_SetString(PyExc_TypeError, "_curses.window.addch requires 1 to 4 arguments"); - goto exit; - } -- return_value = _curses_window_addch_impl(self, group_left_1, y, x, ch, group_right_1, attr); -+ return_value = _curses_window_addch_impl((PyCursesWindowObject *)self, group_left_1, y, x, ch, group_right_1, attr); - - exit: - return return_value; -@@ -107,7 +107,7 @@ - long attr); - - static PyObject * --_curses_window_addstr(PyCursesWindowObject *self, PyObject *args) -+_curses_window_addstr(PyObject *self, PyObject *args) - { - PyObject *return_value = NULL; - int group_left_1 = 0; -@@ -146,7 +146,7 @@ - PyErr_SetString(PyExc_TypeError, "_curses.window.addstr requires 1 to 4 arguments"); - goto exit; - } -- return_value = _curses_window_addstr_impl(self, group_left_1, y, x, str, group_right_1, attr); -+ return_value = _curses_window_addstr_impl((PyCursesWindowObject *)self, group_left_1, y, x, str, group_right_1, attr); - - exit: - return return_value; -@@ -181,7 +181,7 @@ - int group_right_1, long attr); - - static PyObject * --_curses_window_addnstr(PyCursesWindowObject *self, PyObject *args) -+_curses_window_addnstr(PyObject *self, PyObject *args) - { - PyObject *return_value = NULL; - int group_left_1 = 0; -@@ -221,7 +221,7 @@ - PyErr_SetString(PyExc_TypeError, "_curses.window.addnstr requires 2 to 5 arguments"); - goto exit; - } -- return_value = _curses_window_addnstr_impl(self, group_left_1, y, x, str, n, group_right_1, attr); -+ return_value = _curses_window_addnstr_impl((PyCursesWindowObject *)self, group_left_1, y, x, str, n, group_right_1, attr); - - exit: - return return_value; -@@ -245,7 +245,7 @@ - _curses_window_bkgd_impl(PyCursesWindowObject *self, PyObject *ch, long attr); - - static PyObject * --_curses_window_bkgd(PyCursesWindowObject *self, PyObject *const *args, Py_ssize_t nargs) -+_curses_window_bkgd(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *ch; -@@ -263,7 +263,7 @@ - goto exit; - } - skip_optional: -- return_value = _curses_window_bkgd_impl(self, ch, attr); -+ return_value = _curses_window_bkgd_impl((PyCursesWindowObject *)self, ch, attr); - - exit: - return return_value; -@@ -282,7 +282,7 @@ - _curses_window_attroff_impl(PyCursesWindowObject *self, long attr); - - static PyObject * --_curses_window_attroff(PyCursesWindowObject *self, PyObject *arg) -+_curses_window_attroff(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - long attr; -@@ -291,7 +291,7 @@ - if (attr == -1 && PyErr_Occurred()) { - goto exit; - } -- return_value = _curses_window_attroff_impl(self, attr); -+ return_value = _curses_window_attroff_impl((PyCursesWindowObject *)self, attr); - - exit: - return return_value; -@@ -310,7 +310,7 @@ - _curses_window_attron_impl(PyCursesWindowObject *self, long attr); - - static PyObject * --_curses_window_attron(PyCursesWindowObject *self, PyObject *arg) -+_curses_window_attron(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - long attr; -@@ -319,7 +319,7 @@ - if (attr == -1 && PyErr_Occurred()) { - goto exit; - } -- return_value = _curses_window_attron_impl(self, attr); -+ return_value = _curses_window_attron_impl((PyCursesWindowObject *)self, attr); - - exit: - return return_value; -@@ -338,7 +338,7 @@ - _curses_window_attrset_impl(PyCursesWindowObject *self, long attr); - - static PyObject * --_curses_window_attrset(PyCursesWindowObject *self, PyObject *arg) -+_curses_window_attrset(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - long attr; -@@ -347,7 +347,7 @@ - if (attr == -1 && PyErr_Occurred()) { - goto exit; - } -- return_value = _curses_window_attrset_impl(self, attr); -+ return_value = _curses_window_attrset_impl((PyCursesWindowObject *)self, attr); - - exit: - return return_value; -@@ -372,7 +372,7 @@ - long attr); - - static PyObject * --_curses_window_bkgdset(PyCursesWindowObject *self, PyObject *const *args, Py_ssize_t nargs) -+_curses_window_bkgdset(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *ch; -@@ -390,7 +390,7 @@ - goto exit; - } - skip_optional: -- return_value = _curses_window_bkgdset_impl(self, ch, attr); -+ return_value = _curses_window_bkgdset_impl((PyCursesWindowObject *)self, ch, attr); - - exit: - return return_value; -@@ -437,7 +437,7 @@ - PyObject *br); - - static PyObject * --_curses_window_border(PyCursesWindowObject *self, PyObject *const *args, Py_ssize_t nargs) -+_curses_window_border(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *ls = NULL; -@@ -485,7 +485,7 @@ - } - br = args[7]; - skip_optional: -- return_value = _curses_window_border_impl(self, ls, rs, ts, bs, tl, tr, bl, br); -+ return_value = _curses_window_border_impl((PyCursesWindowObject *)self, ls, rs, ts, bs, tl, tr, bl, br); - - exit: - return return_value; -@@ -511,7 +511,7 @@ - PyObject *verch, PyObject *horch); - - static PyObject * --_curses_window_box(PyCursesWindowObject *self, PyObject *args) -+_curses_window_box(PyObject *self, PyObject *args) - { - PyObject *return_value = NULL; - int group_right_1 = 0; -@@ -531,7 +531,7 @@ - PyErr_SetString(PyExc_TypeError, "_curses.window.box requires 0 to 2 arguments"); - goto exit; - } -- return_value = _curses_window_box_impl(self, group_right_1, verch, horch); -+ return_value = _curses_window_box_impl((PyCursesWindowObject *)self, group_right_1, verch, horch); - - exit: - return return_value; -@@ -554,7 +554,7 @@ - int y, int x); - - static PyObject * --_curses_window_delch(PyCursesWindowObject *self, PyObject *args) -+_curses_window_delch(PyObject *self, PyObject *args) - { - PyObject *return_value = NULL; - int group_right_1 = 0; -@@ -574,7 +574,7 @@ - PyErr_SetString(PyExc_TypeError, "_curses.window.delch requires 0 to 2 arguments"); - goto exit; - } -- return_value = _curses_window_delch_impl(self, group_right_1, y, x); -+ return_value = _curses_window_delch_impl((PyCursesWindowObject *)self, group_right_1, y, x); - - exit: - return return_value; -@@ -605,7 +605,7 @@ - int nlines, int ncols, int begin_y, int begin_x); - - static PyObject * --_curses_window_derwin(PyCursesWindowObject *self, PyObject *args) -+_curses_window_derwin(PyObject *self, PyObject *args) - { - PyObject *return_value = NULL; - int group_left_1 = 0; -@@ -630,7 +630,7 @@ - PyErr_SetString(PyExc_TypeError, "_curses.window.derwin requires 2 to 4 arguments"); - goto exit; - } -- return_value = _curses_window_derwin_impl(self, group_left_1, nlines, ncols, begin_y, begin_x); -+ return_value = _curses_window_derwin_impl((PyCursesWindowObject *)self, group_left_1, nlines, ncols, begin_y, begin_x); - - exit: - return return_value; -@@ -655,7 +655,7 @@ - long attr); - - static PyObject * --_curses_window_echochar(PyCursesWindowObject *self, PyObject *const *args, Py_ssize_t nargs) -+_curses_window_echochar(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *ch; -@@ -673,7 +673,7 @@ - goto exit; - } - skip_optional: -- return_value = _curses_window_echochar_impl(self, ch, attr); -+ return_value = _curses_window_echochar_impl((PyCursesWindowObject *)self, ch, attr); - - exit: - return return_value; -@@ -699,7 +699,7 @@ - _curses_window_enclose_impl(PyCursesWindowObject *self, int y, int x); - - static PyObject * --_curses_window_enclose(PyCursesWindowObject *self, PyObject *const *args, Py_ssize_t nargs) -+_curses_window_enclose(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - int y; -@@ -716,7 +716,7 @@ - if (x == -1 && PyErr_Occurred()) { - goto exit; - } -- return_value = _curses_window_enclose_impl(self, y, x); -+ return_value = _curses_window_enclose_impl((PyCursesWindowObject *)self, y, x); - - exit: - return return_value; -@@ -737,12 +737,12 @@ - _curses_window_getbkgd_impl(PyCursesWindowObject *self); - - static PyObject * --_curses_window_getbkgd(PyCursesWindowObject *self, PyObject *Py_UNUSED(ignored)) -+_curses_window_getbkgd(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - long _return_value; - -- _return_value = _curses_window_getbkgd_impl(self); -+ _return_value = _curses_window_getbkgd_impl((PyCursesWindowObject *)self); - if ((_return_value == -1) && PyErr_Occurred()) { - goto exit; - } -@@ -773,7 +773,7 @@ - int y, int x); - - static PyObject * --_curses_window_getch(PyCursesWindowObject *self, PyObject *args) -+_curses_window_getch(PyObject *self, PyObject *args) - { - PyObject *return_value = NULL; - int group_right_1 = 0; -@@ -794,7 +794,7 @@ - PyErr_SetString(PyExc_TypeError, "_curses.window.getch requires 0 to 2 arguments"); - goto exit; - } -- _return_value = _curses_window_getch_impl(self, group_right_1, y, x); -+ _return_value = _curses_window_getch_impl((PyCursesWindowObject *)self, group_right_1, y, x); - if ((_return_value == -1) && PyErr_Occurred()) { - goto exit; - } -@@ -825,7 +825,7 @@ - int y, int x); - - static PyObject * --_curses_window_getkey(PyCursesWindowObject *self, PyObject *args) -+_curses_window_getkey(PyObject *self, PyObject *args) - { - PyObject *return_value = NULL; - int group_right_1 = 0; -@@ -845,7 +845,7 @@ - PyErr_SetString(PyExc_TypeError, "_curses.window.getkey requires 0 to 2 arguments"); - goto exit; - } -- return_value = _curses_window_getkey_impl(self, group_right_1, y, x); -+ return_value = _curses_window_getkey_impl((PyCursesWindowObject *)self, group_right_1, y, x); - - exit: - return return_value; -@@ -873,7 +873,7 @@ - int y, int x); - - static PyObject * --_curses_window_get_wch(PyCursesWindowObject *self, PyObject *args) -+_curses_window_get_wch(PyObject *self, PyObject *args) - { - PyObject *return_value = NULL; - int group_right_1 = 0; -@@ -893,7 +893,7 @@ - PyErr_SetString(PyExc_TypeError, "_curses.window.get_wch requires 0 to 2 arguments"); - goto exit; - } -- return_value = _curses_window_get_wch_impl(self, group_right_1, y, x); -+ return_value = _curses_window_get_wch_impl((PyCursesWindowObject *)self, group_right_1, y, x); - - exit: - return return_value; -@@ -925,7 +925,7 @@ - int group_right_1, long attr); - - static PyObject * --_curses_window_hline(PyCursesWindowObject *self, PyObject *args) -+_curses_window_hline(PyObject *self, PyObject *args) - { - PyObject *return_value = NULL; - int group_left_1 = 0; -@@ -965,7 +965,7 @@ - PyErr_SetString(PyExc_TypeError, "_curses.window.hline requires 2 to 5 arguments"); - goto exit; - } -- return_value = _curses_window_hline_impl(self, group_left_1, y, x, ch, n, group_right_1, attr); -+ return_value = _curses_window_hline_impl((PyCursesWindowObject *)self, group_left_1, y, x, ch, n, group_right_1, attr); - - exit: - return return_value; -@@ -996,7 +996,7 @@ - long attr); - - static PyObject * --_curses_window_insch(PyCursesWindowObject *self, PyObject *args) -+_curses_window_insch(PyObject *self, PyObject *args) - { - PyObject *return_value = NULL; - int group_left_1 = 0; -@@ -1035,7 +1035,7 @@ - PyErr_SetString(PyExc_TypeError, "_curses.window.insch requires 1 to 4 arguments"); - goto exit; - } -- return_value = _curses_window_insch_impl(self, group_left_1, y, x, ch, group_right_1, attr); -+ return_value = _curses_window_insch_impl((PyCursesWindowObject *)self, group_left_1, y, x, ch, group_right_1, attr); - - exit: - return return_value; -@@ -1060,7 +1060,7 @@ - int y, int x); - - static PyObject * --_curses_window_inch(PyCursesWindowObject *self, PyObject *args) -+_curses_window_inch(PyObject *self, PyObject *args) - { - PyObject *return_value = NULL; - int group_right_1 = 0; -@@ -1081,7 +1081,7 @@ - PyErr_SetString(PyExc_TypeError, "_curses.window.inch requires 0 to 2 arguments"); - goto exit; - } -- _return_value = _curses_window_inch_impl(self, group_right_1, y, x); -+ _return_value = _curses_window_inch_impl((PyCursesWindowObject *)self, group_right_1, y, x); - if ((_return_value == (unsigned long)-1) && PyErr_Occurred()) { - goto exit; - } -@@ -1119,7 +1119,7 @@ - long attr); - - static PyObject * --_curses_window_insstr(PyCursesWindowObject *self, PyObject *args) -+_curses_window_insstr(PyObject *self, PyObject *args) - { - PyObject *return_value = NULL; - int group_left_1 = 0; -@@ -1158,7 +1158,7 @@ - PyErr_SetString(PyExc_TypeError, "_curses.window.insstr requires 1 to 4 arguments"); - goto exit; - } -- return_value = _curses_window_insstr_impl(self, group_left_1, y, x, str, group_right_1, attr); -+ return_value = _curses_window_insstr_impl((PyCursesWindowObject *)self, group_left_1, y, x, str, group_right_1, attr); - - exit: - return return_value; -@@ -1195,7 +1195,7 @@ - int group_right_1, long attr); - - static PyObject * --_curses_window_insnstr(PyCursesWindowObject *self, PyObject *args) -+_curses_window_insnstr(PyObject *self, PyObject *args) - { - PyObject *return_value = NULL; - int group_left_1 = 0; -@@ -1235,7 +1235,7 @@ - PyErr_SetString(PyExc_TypeError, "_curses.window.insnstr requires 2 to 5 arguments"); - goto exit; - } -- return_value = _curses_window_insnstr_impl(self, group_left_1, y, x, str, n, group_right_1, attr); -+ return_value = _curses_window_insnstr_impl((PyCursesWindowObject *)self, group_left_1, y, x, str, n, group_right_1, attr); - - exit: - return return_value; -@@ -1259,7 +1259,7 @@ - _curses_window_is_linetouched_impl(PyCursesWindowObject *self, int line); - - static PyObject * --_curses_window_is_linetouched(PyCursesWindowObject *self, PyObject *arg) -+_curses_window_is_linetouched(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - int line; -@@ -1268,7 +1268,7 @@ - if (line == -1 && PyErr_Occurred()) { - goto exit; - } -- return_value = _curses_window_is_linetouched_impl(self, line); -+ return_value = _curses_window_is_linetouched_impl((PyCursesWindowObject *)self, line); - - exit: - return return_value; -@@ -1294,7 +1294,7 @@ - int smaxcol); - - static PyObject * --_curses_window_noutrefresh(PyCursesWindowObject *self, PyObject *args) -+_curses_window_noutrefresh(PyObject *self, PyObject *args) - { - PyObject *return_value = NULL; - int group_right_1 = 0; -@@ -1318,7 +1318,7 @@ - PyErr_SetString(PyExc_TypeError, "_curses.window.noutrefresh requires 0 to 6 arguments"); - goto exit; - } -- return_value = _curses_window_noutrefresh_impl(self, group_right_1, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol); -+ return_value = _curses_window_noutrefresh_impl((PyCursesWindowObject *)self, group_right_1, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol); - - exit: - return return_value; -@@ -1345,9 +1345,9 @@ - _curses_window_noutrefresh_impl(PyCursesWindowObject *self); - - static PyObject * --_curses_window_noutrefresh(PyCursesWindowObject *self, PyObject *Py_UNUSED(ignored)) -+_curses_window_noutrefresh(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _curses_window_noutrefresh_impl(self); -+ return _curses_window_noutrefresh_impl((PyCursesWindowObject *)self); - } - - #endif /* !defined(py_is_pad) */ -@@ -1375,7 +1375,7 @@ - int dmincol, int dmaxrow, int dmaxcol); - - static PyObject * --_curses_window_overlay(PyCursesWindowObject *self, PyObject *args) -+_curses_window_overlay(PyObject *self, PyObject *args) - { - PyObject *return_value = NULL; - PyCursesWindowObject *destwin; -@@ -1403,7 +1403,7 @@ - PyErr_SetString(PyExc_TypeError, "_curses.window.overlay requires 1 to 7 arguments"); - goto exit; - } -- return_value = _curses_window_overlay_impl(self, destwin, group_right_1, sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol); -+ return_value = _curses_window_overlay_impl((PyCursesWindowObject *)self, destwin, group_right_1, sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol); - - exit: - return return_value; -@@ -1434,7 +1434,7 @@ - int dmaxcol); - - static PyObject * --_curses_window_overwrite(PyCursesWindowObject *self, PyObject *args) -+_curses_window_overwrite(PyObject *self, PyObject *args) - { - PyObject *return_value = NULL; - PyCursesWindowObject *destwin; -@@ -1462,7 +1462,7 @@ - PyErr_SetString(PyExc_TypeError, "_curses.window.overwrite requires 1 to 7 arguments"); - goto exit; - } -- return_value = _curses_window_overwrite_impl(self, destwin, group_right_1, sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol); -+ return_value = _curses_window_overwrite_impl((PyCursesWindowObject *)self, destwin, group_right_1, sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol); - - exit: - return return_value; -@@ -1499,7 +1499,7 @@ - _curses_window_redrawln_impl(PyCursesWindowObject *self, int beg, int num); - - static PyObject * --_curses_window_redrawln(PyCursesWindowObject *self, PyObject *const *args, Py_ssize_t nargs) -+_curses_window_redrawln(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - int beg; -@@ -1516,7 +1516,7 @@ - if (num == -1 && PyErr_Occurred()) { - goto exit; - } -- return_value = _curses_window_redrawln_impl(self, beg, num); -+ return_value = _curses_window_redrawln_impl((PyCursesWindowObject *)self, beg, num); - - exit: - return return_value; -@@ -1547,7 +1547,7 @@ - int smincol, int smaxrow, int smaxcol); - - static PyObject * --_curses_window_refresh(PyCursesWindowObject *self, PyObject *args) -+_curses_window_refresh(PyObject *self, PyObject *args) - { - PyObject *return_value = NULL; - int group_right_1 = 0; -@@ -1571,7 +1571,7 @@ - PyErr_SetString(PyExc_TypeError, "_curses.window.refresh requires 0 to 6 arguments"); - goto exit; - } -- return_value = _curses_window_refresh_impl(self, group_right_1, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol); -+ return_value = _curses_window_refresh_impl((PyCursesWindowObject *)self, group_right_1, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol); - - exit: - return return_value; -@@ -1598,7 +1598,7 @@ - int bottom); - - static PyObject * --_curses_window_setscrreg(PyCursesWindowObject *self, PyObject *const *args, Py_ssize_t nargs) -+_curses_window_setscrreg(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - int top; -@@ -1615,7 +1615,7 @@ - if (bottom == -1 && PyErr_Occurred()) { - goto exit; - } -- return_value = _curses_window_setscrreg_impl(self, top, bottom); -+ return_value = _curses_window_setscrreg_impl((PyCursesWindowObject *)self, top, bottom); - - exit: - return return_value; -@@ -1645,7 +1645,7 @@ - int nlines, int ncols, int begin_y, int begin_x); - - static PyObject * --_curses_window_subwin(PyCursesWindowObject *self, PyObject *args) -+_curses_window_subwin(PyObject *self, PyObject *args) - { - PyObject *return_value = NULL; - int group_left_1 = 0; -@@ -1670,7 +1670,7 @@ - PyErr_SetString(PyExc_TypeError, "_curses.window.subwin requires 2 to 4 arguments"); - goto exit; - } -- return_value = _curses_window_subwin_impl(self, group_left_1, nlines, ncols, begin_y, begin_x); -+ return_value = _curses_window_subwin_impl((PyCursesWindowObject *)self, group_left_1, nlines, ncols, begin_y, begin_x); - - exit: - return return_value; -@@ -1693,7 +1693,7 @@ - int lines); - - static PyObject * --_curses_window_scroll(PyCursesWindowObject *self, PyObject *args) -+_curses_window_scroll(PyObject *self, PyObject *args) - { - PyObject *return_value = NULL; - int group_right_1 = 0; -@@ -1712,7 +1712,7 @@ - PyErr_SetString(PyExc_TypeError, "_curses.window.scroll requires 0 to 1 arguments"); - goto exit; - } -- return_value = _curses_window_scroll_impl(self, group_right_1, lines); -+ return_value = _curses_window_scroll_impl((PyCursesWindowObject *)self, group_right_1, lines); - - exit: - return return_value; -@@ -1733,7 +1733,7 @@ - int count, int group_right_1, int changed); - - static PyObject * --_curses_window_touchline(PyCursesWindowObject *self, PyObject *args) -+_curses_window_touchline(PyObject *self, PyObject *args) - { - PyObject *return_value = NULL; - int start; -@@ -1757,7 +1757,7 @@ - PyErr_SetString(PyExc_TypeError, "_curses.window.touchline requires 2 to 3 arguments"); - goto exit; - } -- return_value = _curses_window_touchline_impl(self, start, count, group_right_1, changed); -+ return_value = _curses_window_touchline_impl((PyCursesWindowObject *)self, start, count, group_right_1, changed); - - exit: - return return_value; -@@ -1787,7 +1787,7 @@ - int group_right_1, long attr); - - static PyObject * --_curses_window_vline(PyCursesWindowObject *self, PyObject *args) -+_curses_window_vline(PyObject *self, PyObject *args) - { - PyObject *return_value = NULL; - int group_left_1 = 0; -@@ -1827,7 +1827,7 @@ - PyErr_SetString(PyExc_TypeError, "_curses.window.vline requires 2 to 5 arguments"); - goto exit; - } -- return_value = _curses_window_vline_impl(self, group_left_1, y, x, ch, n, group_right_1, attr); -+ return_value = _curses_window_vline_impl((PyCursesWindowObject *)self, group_left_1, y, x, ch, n, group_right_1, attr); - - exit: - return return_value; -@@ -4379,4 +4379,4 @@ - #ifndef _CURSES_USE_DEFAULT_COLORS_METHODDEF - #define _CURSES_USE_DEFAULT_COLORS_METHODDEF - #endif /* !defined(_CURSES_USE_DEFAULT_COLORS_METHODDEF) */ --/*[clinic end generated code: output=26fe38c09ff8ca44 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=c4211865ed96c2af input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/_datetimemodule.c.h b/Modules/clinic/_datetimemodule.c.h -index 72c230fc8ae..8f33c9e7d4e 100644 ---- a/Modules/clinic/_datetimemodule.c.h -+++ b/Modules/clinic/_datetimemodule.c.h -@@ -97,7 +97,7 @@ - int day); - - static PyObject * --datetime_date_replace(PyDateTime_Date *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+datetime_date_replace(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -162,7 +162,7 @@ - goto exit; - } - skip_optional_pos: -- return_value = datetime_date_replace_impl(self, year, month, day); -+ return_value = datetime_date_replace_impl((PyDateTime_Date *)self, year, month, day); - - exit: - return return_value; -@@ -184,7 +184,7 @@ - int fold); - - static PyObject * --datetime_time_replace(PyDateTime_Time *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+datetime_time_replace(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -218,7 +218,7 @@ - int minute = TIME_GET_MINUTE(self); - int second = TIME_GET_SECOND(self); - int microsecond = TIME_GET_MICROSECOND(self); -- PyObject *tzinfo = HASTZINFO(self) ? self->tzinfo : Py_None; -+ PyObject *tzinfo = HASTZINFO(self) ? ((PyDateTime_Time *)self)->tzinfo : Py_None; - int fold = TIME_GET_FOLD(self); - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, -@@ -280,7 +280,7 @@ - goto exit; - } - skip_optional_kwonly: -- return_value = datetime_time_replace_impl(self, hour, minute, second, microsecond, tzinfo, fold); -+ return_value = datetime_time_replace_impl((PyDateTime_Time *)self, hour, minute, second, microsecond, tzinfo, fold); - - exit: - return return_value; -@@ -370,7 +370,7 @@ - int fold); - - static PyObject * --datetime_datetime_replace(PyDateTime_DateTime *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+datetime_datetime_replace(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -407,7 +407,7 @@ - int minute = DATE_GET_MINUTE(self); - int second = DATE_GET_SECOND(self); - int microsecond = DATE_GET_MICROSECOND(self); -- PyObject *tzinfo = HASTZINFO(self) ? self->tzinfo : Py_None; -+ PyObject *tzinfo = HASTZINFO(self) ? ((PyDateTime_DateTime *)self)->tzinfo : Py_None; - int fold = DATE_GET_FOLD(self); - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, -@@ -496,9 +496,9 @@ - goto exit; - } - skip_optional_kwonly: -- return_value = datetime_datetime_replace_impl(self, year, month, day, hour, minute, second, microsecond, tzinfo, fold); -+ return_value = datetime_datetime_replace_impl((PyDateTime_DateTime *)self, year, month, day, hour, minute, second, microsecond, tzinfo, fold); - - exit: - return return_value; - } --/*[clinic end generated code: output=203217a61ea14171 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=8acf62fbc7328f79 input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/_dbmmodule.c.h b/Modules/clinic/_dbmmodule.c.h -index 4379b433db3..5e503194408 100644 ---- a/Modules/clinic/_dbmmodule.c.h -+++ b/Modules/clinic/_dbmmodule.c.h -@@ -20,9 +20,9 @@ - _dbm_dbm_close_impl(dbmobject *self); - - static PyObject * --_dbm_dbm_close(dbmobject *self, PyObject *Py_UNUSED(ignored)) -+_dbm_dbm_close(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _dbm_dbm_close_impl(self); -+ return _dbm_dbm_close_impl((dbmobject *)self); - } - - PyDoc_STRVAR(_dbm_dbm_keys__doc__, -@@ -38,13 +38,13 @@ - _dbm_dbm_keys_impl(dbmobject *self, PyTypeObject *cls); - - static PyObject * --_dbm_dbm_keys(dbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_dbm_dbm_keys(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "keys() takes no arguments"); - return NULL; - } -- return _dbm_dbm_keys_impl(self, cls); -+ return _dbm_dbm_keys_impl((dbmobject *)self, cls); - } - - PyDoc_STRVAR(_dbm_dbm_get__doc__, -@@ -61,7 +61,7 @@ - Py_ssize_t key_length, PyObject *default_value); - - static PyObject * --_dbm_dbm_get(dbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_dbm_dbm_get(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -85,7 +85,7 @@ - &key, &key_length, &default_value)) { - goto exit; - } -- return_value = _dbm_dbm_get_impl(self, cls, key, key_length, default_value); -+ return_value = _dbm_dbm_get_impl((dbmobject *)self, cls, key, key_length, default_value); - - exit: - return return_value; -@@ -107,7 +107,7 @@ - Py_ssize_t key_length, PyObject *default_value); - - static PyObject * --_dbm_dbm_setdefault(dbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_dbm_dbm_setdefault(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -131,7 +131,7 @@ - &key, &key_length, &default_value)) { - goto exit; - } -- return_value = _dbm_dbm_setdefault_impl(self, cls, key, key_length, default_value); -+ return_value = _dbm_dbm_setdefault_impl((dbmobject *)self, cls, key, key_length, default_value); - - exit: - return return_value; -@@ -150,13 +150,13 @@ - _dbm_dbm_clear_impl(dbmobject *self, PyTypeObject *cls); - - static PyObject * --_dbm_dbm_clear(dbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_dbm_dbm_clear(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "clear() takes no arguments"); - return NULL; - } -- return _dbm_dbm_clear_impl(self, cls); -+ return _dbm_dbm_clear_impl((dbmobject *)self, cls); - } - - PyDoc_STRVAR(dbmopen__doc__, -@@ -221,4 +221,4 @@ - exit: - return return_value; - } --/*[clinic end generated code: output=f7d9a87d80a64278 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=3b456118f231b160 input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/_elementtree.c.h b/Modules/clinic/_elementtree.c.h -index 07045e72040..78391887b61 100644 ---- a/Modules/clinic/_elementtree.c.h -+++ b/Modules/clinic/_elementtree.c.h -@@ -22,7 +22,7 @@ - PyObject *subelement); - - static PyObject * --_elementtree_Element_append(ElementObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_elementtree_Element_append(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -51,7 +51,7 @@ - goto exit; - } - subelement = args[0]; -- return_value = _elementtree_Element_append_impl(self, cls, subelement); -+ return_value = _elementtree_Element_append_impl((ElementObject *)self, cls, subelement); - - exit: - return return_value; -@@ -69,9 +69,9 @@ - _elementtree_Element_clear_impl(ElementObject *self); - - static PyObject * --_elementtree_Element_clear(ElementObject *self, PyObject *Py_UNUSED(ignored)) -+_elementtree_Element_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _elementtree_Element_clear_impl(self); -+ return _elementtree_Element_clear_impl((ElementObject *)self); - } - - PyDoc_STRVAR(_elementtree_Element___copy____doc__, -@@ -86,13 +86,13 @@ - _elementtree_Element___copy___impl(ElementObject *self, PyTypeObject *cls); - - static PyObject * --_elementtree_Element___copy__(ElementObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_elementtree_Element___copy__(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "__copy__() takes no arguments"); - return NULL; - } -- return _elementtree_Element___copy___impl(self, cls); -+ return _elementtree_Element___copy___impl((ElementObject *)self, cls); - } - - PyDoc_STRVAR(_elementtree_Element___deepcopy____doc__, -@@ -107,7 +107,7 @@ - _elementtree_Element___deepcopy___impl(ElementObject *self, PyObject *memo); - - static PyObject * --_elementtree_Element___deepcopy__(ElementObject *self, PyObject *arg) -+_elementtree_Element___deepcopy__(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - PyObject *memo; -@@ -117,7 +117,7 @@ - goto exit; - } - memo = arg; -- return_value = _elementtree_Element___deepcopy___impl(self, memo); -+ return_value = _elementtree_Element___deepcopy___impl((ElementObject *)self, memo); - - exit: - return return_value; -@@ -135,12 +135,12 @@ - _elementtree_Element___sizeof___impl(ElementObject *self); - - static PyObject * --_elementtree_Element___sizeof__(ElementObject *self, PyObject *Py_UNUSED(ignored)) -+_elementtree_Element___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - size_t _return_value; - -- _return_value = _elementtree_Element___sizeof___impl(self); -+ _return_value = _elementtree_Element___sizeof___impl((ElementObject *)self); - if ((_return_value == (size_t)-1) && PyErr_Occurred()) { - goto exit; - } -@@ -162,9 +162,9 @@ - _elementtree_Element___getstate___impl(ElementObject *self); - - static PyObject * --_elementtree_Element___getstate__(ElementObject *self, PyObject *Py_UNUSED(ignored)) -+_elementtree_Element___getstate__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _elementtree_Element___getstate___impl(self); -+ return _elementtree_Element___getstate___impl((ElementObject *)self); - } - - PyDoc_STRVAR(_elementtree_Element___setstate____doc__, -@@ -180,7 +180,7 @@ - PyTypeObject *cls, PyObject *state); - - static PyObject * --_elementtree_Element___setstate__(ElementObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_elementtree_Element___setstate__(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -205,7 +205,7 @@ - goto exit; - } - state = args[0]; -- return_value = _elementtree_Element___setstate___impl(self, cls, state); -+ return_value = _elementtree_Element___setstate___impl((ElementObject *)self, cls, state); - - exit: - return return_value; -@@ -224,7 +224,7 @@ - PyObject *elements); - - static PyObject * --_elementtree_Element_extend(ElementObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_elementtree_Element_extend(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -249,7 +249,7 @@ - goto exit; - } - elements = args[0]; -- return_value = _elementtree_Element_extend_impl(self, cls, elements); -+ return_value = _elementtree_Element_extend_impl((ElementObject *)self, cls, elements); - - exit: - return return_value; -@@ -268,7 +268,7 @@ - PyObject *path, PyObject *namespaces); - - static PyObject * --_elementtree_Element_find(ElementObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_elementtree_Element_find(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -312,7 +312,7 @@ - } - namespaces = args[1]; - skip_optional_pos: -- return_value = _elementtree_Element_find_impl(self, cls, path, namespaces); -+ return_value = _elementtree_Element_find_impl((ElementObject *)self, cls, path, namespaces); - - exit: - return return_value; -@@ -332,7 +332,7 @@ - PyObject *namespaces); - - static PyObject * --_elementtree_Element_findtext(ElementObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_elementtree_Element_findtext(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -383,7 +383,7 @@ - } - namespaces = args[2]; - skip_optional_pos: -- return_value = _elementtree_Element_findtext_impl(self, cls, path, default_value, namespaces); -+ return_value = _elementtree_Element_findtext_impl((ElementObject *)self, cls, path, default_value, namespaces); - - exit: - return return_value; -@@ -402,7 +402,7 @@ - PyObject *path, PyObject *namespaces); - - static PyObject * --_elementtree_Element_findall(ElementObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_elementtree_Element_findall(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -446,7 +446,7 @@ - } - namespaces = args[1]; - skip_optional_pos: -- return_value = _elementtree_Element_findall_impl(self, cls, path, namespaces); -+ return_value = _elementtree_Element_findall_impl((ElementObject *)self, cls, path, namespaces); - - exit: - return return_value; -@@ -465,7 +465,7 @@ - PyObject *path, PyObject *namespaces); - - static PyObject * --_elementtree_Element_iterfind(ElementObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_elementtree_Element_iterfind(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -509,7 +509,7 @@ - } - namespaces = args[1]; - skip_optional_pos: -- return_value = _elementtree_Element_iterfind_impl(self, cls, path, namespaces); -+ return_value = _elementtree_Element_iterfind_impl((ElementObject *)self, cls, path, namespaces); - - exit: - return return_value; -@@ -528,7 +528,7 @@ - PyObject *default_value); - - static PyObject * --_elementtree_Element_get(ElementObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_elementtree_Element_get(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -572,7 +572,7 @@ - } - default_value = args[1]; - skip_optional_pos: -- return_value = _elementtree_Element_get_impl(self, key, default_value); -+ return_value = _elementtree_Element_get_impl((ElementObject *)self, key, default_value); - - exit: - return return_value; -@@ -591,7 +591,7 @@ - PyObject *tag); - - static PyObject * --_elementtree_Element_iter(ElementObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_elementtree_Element_iter(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -633,7 +633,7 @@ - } - tag = args[0]; - skip_optional_pos: -- return_value = _elementtree_Element_iter_impl(self, cls, tag); -+ return_value = _elementtree_Element_iter_impl((ElementObject *)self, cls, tag); - - exit: - return return_value; -@@ -651,13 +651,13 @@ - _elementtree_Element_itertext_impl(ElementObject *self, PyTypeObject *cls); - - static PyObject * --_elementtree_Element_itertext(ElementObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_elementtree_Element_itertext(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "itertext() takes no arguments"); - return NULL; - } -- return _elementtree_Element_itertext_impl(self, cls); -+ return _elementtree_Element_itertext_impl((ElementObject *)self, cls); - } - - PyDoc_STRVAR(_elementtree_Element_insert__doc__, -@@ -673,7 +673,7 @@ - PyObject *subelement); - - static PyObject * --_elementtree_Element_insert(ElementObject *self, PyObject *const *args, Py_ssize_t nargs) -+_elementtree_Element_insert(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - Py_ssize_t index; -@@ -699,7 +699,7 @@ - goto exit; - } - subelement = args[1]; -- return_value = _elementtree_Element_insert_impl(self, index, subelement); -+ return_value = _elementtree_Element_insert_impl((ElementObject *)self, index, subelement); - - exit: - return return_value; -@@ -717,9 +717,9 @@ - _elementtree_Element_items_impl(ElementObject *self); - - static PyObject * --_elementtree_Element_items(ElementObject *self, PyObject *Py_UNUSED(ignored)) -+_elementtree_Element_items(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _elementtree_Element_items_impl(self); -+ return _elementtree_Element_items_impl((ElementObject *)self); - } - - PyDoc_STRVAR(_elementtree_Element_keys__doc__, -@@ -734,9 +734,9 @@ - _elementtree_Element_keys_impl(ElementObject *self); - - static PyObject * --_elementtree_Element_keys(ElementObject *self, PyObject *Py_UNUSED(ignored)) -+_elementtree_Element_keys(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _elementtree_Element_keys_impl(self); -+ return _elementtree_Element_keys_impl((ElementObject *)self); - } - - PyDoc_STRVAR(_elementtree_Element_makeelement__doc__, -@@ -752,7 +752,7 @@ - PyObject *tag, PyObject *attrib); - - static PyObject * --_elementtree_Element_makeelement(ElementObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_elementtree_Element_makeelement(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -783,7 +783,7 @@ - goto exit; - } - attrib = args[1]; -- return_value = _elementtree_Element_makeelement_impl(self, cls, tag, attrib); -+ return_value = _elementtree_Element_makeelement_impl((ElementObject *)self, cls, tag, attrib); - - exit: - return return_value; -@@ -801,7 +801,7 @@ - _elementtree_Element_remove_impl(ElementObject *self, PyObject *subelement); - - static PyObject * --_elementtree_Element_remove(ElementObject *self, PyObject *arg) -+_elementtree_Element_remove(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - PyObject *subelement; -@@ -811,7 +811,7 @@ - goto exit; - } - subelement = arg; -- return_value = _elementtree_Element_remove_impl(self, subelement); -+ return_value = _elementtree_Element_remove_impl((ElementObject *)self, subelement); - - exit: - return return_value; -@@ -830,7 +830,7 @@ - PyObject *value); - - static PyObject * --_elementtree_Element_set(ElementObject *self, PyObject *const *args, Py_ssize_t nargs) -+_elementtree_Element_set(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *key; -@@ -841,7 +841,7 @@ - } - key = args[0]; - value = args[1]; -- return_value = _elementtree_Element_set_impl(self, key, value); -+ return_value = _elementtree_Element_set_impl((ElementObject *)self, key, value); - - exit: - return return_value; -@@ -1013,7 +1013,7 @@ - PyObject *text); - - static PyObject * --_elementtree_TreeBuilder_pi(TreeBuilderObject *self, PyObject *const *args, Py_ssize_t nargs) -+_elementtree_TreeBuilder_pi(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *target; -@@ -1028,7 +1028,7 @@ - } - text = args[1]; - skip_optional: -- return_value = _elementtree_TreeBuilder_pi_impl(self, target, text); -+ return_value = _elementtree_TreeBuilder_pi_impl((TreeBuilderObject *)self, target, text); - - exit: - return return_value; -@@ -1046,9 +1046,9 @@ - _elementtree_TreeBuilder_close_impl(TreeBuilderObject *self); - - static PyObject * --_elementtree_TreeBuilder_close(TreeBuilderObject *self, PyObject *Py_UNUSED(ignored)) -+_elementtree_TreeBuilder_close(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _elementtree_TreeBuilder_close_impl(self); -+ return _elementtree_TreeBuilder_close_impl((TreeBuilderObject *)self); - } - - PyDoc_STRVAR(_elementtree_TreeBuilder_start__doc__, -@@ -1064,7 +1064,7 @@ - PyObject *attrs); - - static PyObject * --_elementtree_TreeBuilder_start(TreeBuilderObject *self, PyObject *const *args, Py_ssize_t nargs) -+_elementtree_TreeBuilder_start(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *tag; -@@ -1079,7 +1079,7 @@ - goto exit; - } - attrs = args[1]; -- return_value = _elementtree_TreeBuilder_start_impl(self, tag, attrs); -+ return_value = _elementtree_TreeBuilder_start_impl((TreeBuilderObject *)self, tag, attrs); - - exit: - return return_value; -@@ -1176,9 +1176,9 @@ - _elementtree_XMLParser_close_impl(XMLParserObject *self); - - static PyObject * --_elementtree_XMLParser_close(XMLParserObject *self, PyObject *Py_UNUSED(ignored)) -+_elementtree_XMLParser_close(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _elementtree_XMLParser_close_impl(self); -+ return _elementtree_XMLParser_close_impl((XMLParserObject *)self); - } - - PyDoc_STRVAR(_elementtree_XMLParser_flush__doc__, -@@ -1193,9 +1193,9 @@ - _elementtree_XMLParser_flush_impl(XMLParserObject *self); - - static PyObject * --_elementtree_XMLParser_flush(XMLParserObject *self, PyObject *Py_UNUSED(ignored)) -+_elementtree_XMLParser_flush(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _elementtree_XMLParser_flush_impl(self); -+ return _elementtree_XMLParser_flush_impl((XMLParserObject *)self); - } - - PyDoc_STRVAR(_elementtree_XMLParser_feed__doc__, -@@ -1228,7 +1228,7 @@ - PyObject *events_to_report); - - static PyObject * --_elementtree_XMLParser__setevents(XMLParserObject *self, PyObject *const *args, Py_ssize_t nargs) -+_elementtree_XMLParser__setevents(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *events_queue; -@@ -1243,9 +1243,9 @@ - } - events_to_report = args[1]; - skip_optional: -- return_value = _elementtree_XMLParser__setevents_impl(self, events_queue, events_to_report); -+ return_value = _elementtree_XMLParser__setevents_impl((XMLParserObject *)self, events_queue, events_to_report); - - exit: - return return_value; - } --/*[clinic end generated code: output=b713bf59fd0fef9b input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=e5c758958f14f102 input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/_gdbmmodule.c.h b/Modules/clinic/_gdbmmodule.c.h -index bbf4365114c..00950f18e53 100644 ---- a/Modules/clinic/_gdbmmodule.c.h -+++ b/Modules/clinic/_gdbmmodule.c.h -@@ -20,7 +20,7 @@ - _gdbm_gdbm_get_impl(gdbmobject *self, PyObject *key, PyObject *default_value); - - static PyObject * --_gdbm_gdbm_get(gdbmobject *self, PyObject *const *args, Py_ssize_t nargs) -+_gdbm_gdbm_get(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *key; -@@ -35,7 +35,7 @@ - } - default_value = args[1]; - skip_optional: -- return_value = _gdbm_gdbm_get_impl(self, key, default_value); -+ return_value = _gdbm_gdbm_get_impl((gdbmobject *)self, key, default_value); - - exit: - return return_value; -@@ -55,7 +55,7 @@ - PyObject *default_value); - - static PyObject * --_gdbm_gdbm_setdefault(gdbmobject *self, PyObject *const *args, Py_ssize_t nargs) -+_gdbm_gdbm_setdefault(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *key; -@@ -70,7 +70,7 @@ - } - default_value = args[1]; - skip_optional: -- return_value = _gdbm_gdbm_setdefault_impl(self, key, default_value); -+ return_value = _gdbm_gdbm_setdefault_impl((gdbmobject *)self, key, default_value); - - exit: - return return_value; -@@ -89,9 +89,9 @@ - _gdbm_gdbm_close_impl(gdbmobject *self); - - static PyObject * --_gdbm_gdbm_close(gdbmobject *self, PyObject *Py_UNUSED(ignored)) -+_gdbm_gdbm_close(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _gdbm_gdbm_close_impl(self); -+ return _gdbm_gdbm_close_impl((gdbmobject *)self); - } - - PyDoc_STRVAR(_gdbm_gdbm_keys__doc__, -@@ -107,13 +107,13 @@ - _gdbm_gdbm_keys_impl(gdbmobject *self, PyTypeObject *cls); - - static PyObject * --_gdbm_gdbm_keys(gdbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_gdbm_gdbm_keys(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "keys() takes no arguments"); - return NULL; - } -- return _gdbm_gdbm_keys_impl(self, cls); -+ return _gdbm_gdbm_keys_impl((gdbmobject *)self, cls); - } - - PyDoc_STRVAR(_gdbm_gdbm_firstkey__doc__, -@@ -133,13 +133,13 @@ - _gdbm_gdbm_firstkey_impl(gdbmobject *self, PyTypeObject *cls); - - static PyObject * --_gdbm_gdbm_firstkey(gdbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_gdbm_gdbm_firstkey(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "firstkey() takes no arguments"); - return NULL; - } -- return _gdbm_gdbm_firstkey_impl(self, cls); -+ return _gdbm_gdbm_firstkey_impl((gdbmobject *)self, cls); - } - - PyDoc_STRVAR(_gdbm_gdbm_nextkey__doc__, -@@ -164,7 +164,7 @@ - Py_ssize_t key_length); - - static PyObject * --_gdbm_gdbm_nextkey(gdbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_gdbm_gdbm_nextkey(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -187,7 +187,7 @@ - &key, &key_length)) { - goto exit; - } -- return_value = _gdbm_gdbm_nextkey_impl(self, cls, key, key_length); -+ return_value = _gdbm_gdbm_nextkey_impl((gdbmobject *)self, cls, key, key_length); - - exit: - return return_value; -@@ -212,13 +212,13 @@ - _gdbm_gdbm_reorganize_impl(gdbmobject *self, PyTypeObject *cls); - - static PyObject * --_gdbm_gdbm_reorganize(gdbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_gdbm_gdbm_reorganize(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "reorganize() takes no arguments"); - return NULL; - } -- return _gdbm_gdbm_reorganize_impl(self, cls); -+ return _gdbm_gdbm_reorganize_impl((gdbmobject *)self, cls); - } - - PyDoc_STRVAR(_gdbm_gdbm_sync__doc__, -@@ -237,13 +237,13 @@ - _gdbm_gdbm_sync_impl(gdbmobject *self, PyTypeObject *cls); - - static PyObject * --_gdbm_gdbm_sync(gdbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_gdbm_gdbm_sync(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "sync() takes no arguments"); - return NULL; - } -- return _gdbm_gdbm_sync_impl(self, cls); -+ return _gdbm_gdbm_sync_impl((gdbmobject *)self, cls); - } - - PyDoc_STRVAR(_gdbm_gdbm_clear__doc__, -@@ -259,13 +259,13 @@ - _gdbm_gdbm_clear_impl(gdbmobject *self, PyTypeObject *cls); - - static PyObject * --_gdbm_gdbm_clear(gdbmobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_gdbm_gdbm_clear(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "clear() takes no arguments"); - return NULL; - } -- return _gdbm_gdbm_clear_impl(self, cls); -+ return _gdbm_gdbm_clear_impl((gdbmobject *)self, cls); - } - - PyDoc_STRVAR(dbmopen__doc__, -@@ -343,4 +343,4 @@ - exit: - return return_value; - } --/*[clinic end generated code: output=07bdeb4a8ecb328e input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=d974cb39e4ee5d67 input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/_hashopenssl.c.h b/Modules/clinic/_hashopenssl.c.h -index f54f065f7d2..d219b80b791 100644 ---- a/Modules/clinic/_hashopenssl.c.h -+++ b/Modules/clinic/_hashopenssl.c.h -@@ -22,9 +22,9 @@ - EVP_copy_impl(EVPobject *self); - - static PyObject * --EVP_copy(EVPobject *self, PyObject *Py_UNUSED(ignored)) -+EVP_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return EVP_copy_impl(self); -+ return EVP_copy_impl((EVPobject *)self); - } - - PyDoc_STRVAR(EVP_digest__doc__, -@@ -40,9 +40,9 @@ - EVP_digest_impl(EVPobject *self); - - static PyObject * --EVP_digest(EVPobject *self, PyObject *Py_UNUSED(ignored)) -+EVP_digest(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return EVP_digest_impl(self); -+ return EVP_digest_impl((EVPobject *)self); - } - - PyDoc_STRVAR(EVP_hexdigest__doc__, -@@ -58,9 +58,9 @@ - EVP_hexdigest_impl(EVPobject *self); - - static PyObject * --EVP_hexdigest(EVPobject *self, PyObject *Py_UNUSED(ignored)) -+EVP_hexdigest(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return EVP_hexdigest_impl(self); -+ return EVP_hexdigest_impl((EVPobject *)self); - } - - PyDoc_STRVAR(EVP_update__doc__, -@@ -87,7 +87,7 @@ - EVPXOF_digest_impl(EVPobject *self, Py_ssize_t length); - - static PyObject * --EVPXOF_digest(EVPobject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+EVPXOF_digest(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -135,7 +135,7 @@ - } - length = ival; - } -- return_value = EVPXOF_digest_impl(self, length); -+ return_value = EVPXOF_digest_impl((EVPobject *)self, length); - - exit: - return return_value; -@@ -158,7 +158,7 @@ - EVPXOF_hexdigest_impl(EVPobject *self, Py_ssize_t length); - - static PyObject * --EVPXOF_hexdigest(EVPobject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+EVPXOF_hexdigest(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -206,7 +206,7 @@ - } - length = ival; - } -- return_value = EVPXOF_hexdigest_impl(self, length); -+ return_value = EVPXOF_hexdigest_impl((EVPobject *)self, length); - - exit: - return return_value; -@@ -1634,9 +1634,9 @@ - _hashlib_HMAC_copy_impl(HMACobject *self); - - static PyObject * --_hashlib_HMAC_copy(HMACobject *self, PyObject *Py_UNUSED(ignored)) -+_hashlib_HMAC_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _hashlib_HMAC_copy_impl(self); -+ return _hashlib_HMAC_copy_impl((HMACobject *)self); - } - - PyDoc_STRVAR(_hashlib_HMAC_update__doc__, -@@ -1652,7 +1652,7 @@ - _hashlib_HMAC_update_impl(HMACobject *self, PyObject *msg); - - static PyObject * --_hashlib_HMAC_update(HMACobject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_hashlib_HMAC_update(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -1689,7 +1689,7 @@ - goto exit; - } - msg = args[0]; -- return_value = _hashlib_HMAC_update_impl(self, msg); -+ return_value = _hashlib_HMAC_update_impl((HMACobject *)self, msg); - - exit: - return return_value; -@@ -1708,9 +1708,9 @@ - _hashlib_HMAC_digest_impl(HMACobject *self); - - static PyObject * --_hashlib_HMAC_digest(HMACobject *self, PyObject *Py_UNUSED(ignored)) -+_hashlib_HMAC_digest(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _hashlib_HMAC_digest_impl(self); -+ return _hashlib_HMAC_digest_impl((HMACobject *)self); - } - - PyDoc_STRVAR(_hashlib_HMAC_hexdigest__doc__, -@@ -1729,9 +1729,9 @@ - _hashlib_HMAC_hexdigest_impl(HMACobject *self); - - static PyObject * --_hashlib_HMAC_hexdigest(HMACobject *self, PyObject *Py_UNUSED(ignored)) -+_hashlib_HMAC_hexdigest(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _hashlib_HMAC_hexdigest_impl(self); -+ return _hashlib_HMAC_hexdigest_impl((HMACobject *)self); - } - - PyDoc_STRVAR(_hashlib_get_fips_mode__doc__, -@@ -1844,4 +1844,4 @@ - #ifndef _HASHLIB_SCRYPT_METHODDEF - #define _HASHLIB_SCRYPT_METHODDEF - #endif /* !defined(_HASHLIB_SCRYPT_METHODDEF) */ --/*[clinic end generated code: output=c3ef67e4a573cc7a input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=811a8b50beae1018 input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/_lsprof.c.h b/Modules/clinic/_lsprof.c.h -index e19840f97e5..6a75a8f9833 100644 ---- a/Modules/clinic/_lsprof.c.h -+++ b/Modules/clinic/_lsprof.c.h -@@ -43,13 +43,13 @@ - _lsprof_Profiler_getstats_impl(ProfilerObject *self, PyTypeObject *cls); - - static PyObject * --_lsprof_Profiler_getstats(ProfilerObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_lsprof_Profiler_getstats(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "getstats() takes no arguments"); - return NULL; - } -- return _lsprof_Profiler_getstats_impl(self, cls); -+ return _lsprof_Profiler_getstats_impl((ProfilerObject *)self, cls); - } - - PyDoc_STRVAR(_lsprof_Profiler__pystart_callback__doc__, -@@ -65,7 +65,7 @@ - PyObject *instruction_offset); - - static PyObject * --_lsprof_Profiler__pystart_callback(ProfilerObject *self, PyObject *const *args, Py_ssize_t nargs) -+_lsprof_Profiler__pystart_callback(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *code; -@@ -76,7 +76,7 @@ - } - code = args[0]; - instruction_offset = args[1]; -- return_value = _lsprof_Profiler__pystart_callback_impl(self, code, instruction_offset); -+ return_value = _lsprof_Profiler__pystart_callback_impl((ProfilerObject *)self, code, instruction_offset); - - exit: - return return_value; -@@ -97,7 +97,7 @@ - PyObject *retval); - - static PyObject * --_lsprof_Profiler__pyreturn_callback(ProfilerObject *self, PyObject *const *args, Py_ssize_t nargs) -+_lsprof_Profiler__pyreturn_callback(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *code; -@@ -110,7 +110,7 @@ - code = args[0]; - instruction_offset = args[1]; - retval = args[2]; -- return_value = _lsprof_Profiler__pyreturn_callback_impl(self, code, instruction_offset, retval); -+ return_value = _lsprof_Profiler__pyreturn_callback_impl((ProfilerObject *)self, code, instruction_offset, retval); - - exit: - return return_value; -@@ -130,7 +130,7 @@ - PyObject *callable, PyObject *self_arg); - - static PyObject * --_lsprof_Profiler__ccall_callback(ProfilerObject *self, PyObject *const *args, Py_ssize_t nargs) -+_lsprof_Profiler__ccall_callback(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *code; -@@ -145,7 +145,7 @@ - instruction_offset = args[1]; - callable = args[2]; - self_arg = args[3]; -- return_value = _lsprof_Profiler__ccall_callback_impl(self, code, instruction_offset, callable, self_arg); -+ return_value = _lsprof_Profiler__ccall_callback_impl((ProfilerObject *)self, code, instruction_offset, callable, self_arg); - - exit: - return return_value; -@@ -167,7 +167,7 @@ - PyObject *self_arg); - - static PyObject * --_lsprof_Profiler__creturn_callback(ProfilerObject *self, PyObject *const *args, Py_ssize_t nargs) -+_lsprof_Profiler__creturn_callback(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *code; -@@ -182,7 +182,7 @@ - instruction_offset = args[1]; - callable = args[2]; - self_arg = args[3]; -- return_value = _lsprof_Profiler__creturn_callback_impl(self, code, instruction_offset, callable, self_arg); -+ return_value = _lsprof_Profiler__creturn_callback_impl((ProfilerObject *)self, code, instruction_offset, callable, self_arg); - - exit: - return return_value; -@@ -209,7 +209,7 @@ - int builtins); - - static PyObject * --_lsprof_Profiler_enable(ProfilerObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_lsprof_Profiler_enable(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -264,7 +264,7 @@ - goto exit; - } - skip_optional_pos: -- return_value = _lsprof_Profiler_enable_impl(self, subcalls, builtins); -+ return_value = _lsprof_Profiler_enable_impl((ProfilerObject *)self, subcalls, builtins); - - exit: - return return_value; -@@ -283,9 +283,9 @@ - _lsprof_Profiler_disable_impl(ProfilerObject *self); - - static PyObject * --_lsprof_Profiler_disable(ProfilerObject *self, PyObject *Py_UNUSED(ignored)) -+_lsprof_Profiler_disable(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _lsprof_Profiler_disable_impl(self); -+ return _lsprof_Profiler_disable_impl((ProfilerObject *)self); - } - - PyDoc_STRVAR(_lsprof_Profiler_clear__doc__, -@@ -301,9 +301,9 @@ - _lsprof_Profiler_clear_impl(ProfilerObject *self); - - static PyObject * --_lsprof_Profiler_clear(ProfilerObject *self, PyObject *Py_UNUSED(ignored)) -+_lsprof_Profiler_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _lsprof_Profiler_clear_impl(self); -+ return _lsprof_Profiler_clear_impl((ProfilerObject *)self); - } - - PyDoc_STRVAR(profiler_init__doc__, -@@ -407,4 +407,4 @@ - exit: - return return_value; - } --/*[clinic end generated code: output=e56d849e35d005a5 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=d983dbf23fd8ac3b input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/_lzmamodule.c.h b/Modules/clinic/_lzmamodule.c.h -index 187f7b183dc..c7c81d8d1f1 100644 ---- a/Modules/clinic/_lzmamodule.c.h -+++ b/Modules/clinic/_lzmamodule.c.h -@@ -27,7 +27,7 @@ - _lzma_LZMACompressor_compress_impl(Compressor *self, Py_buffer *data); - - static PyObject * --_lzma_LZMACompressor_compress(Compressor *self, PyObject *arg) -+_lzma_LZMACompressor_compress(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - Py_buffer data = {NULL, NULL}; -@@ -35,7 +35,7 @@ - if (PyObject_GetBuffer(arg, &data, PyBUF_SIMPLE) != 0) { - goto exit; - } -- return_value = _lzma_LZMACompressor_compress_impl(self, &data); -+ return_value = _lzma_LZMACompressor_compress_impl((Compressor *)self, &data); - - exit: - /* Cleanup for data */ -@@ -63,9 +63,9 @@ - _lzma_LZMACompressor_flush_impl(Compressor *self); - - static PyObject * --_lzma_LZMACompressor_flush(Compressor *self, PyObject *Py_UNUSED(ignored)) -+_lzma_LZMACompressor_flush(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _lzma_LZMACompressor_flush_impl(self); -+ return _lzma_LZMACompressor_flush_impl((Compressor *)self); - } - - PyDoc_STRVAR(_lzma_LZMADecompressor_decompress__doc__, -@@ -95,7 +95,7 @@ - Py_ssize_t max_length); - - static PyObject * --_lzma_LZMADecompressor_decompress(Decompressor *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_lzma_LZMADecompressor_decompress(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -152,7 +152,7 @@ - max_length = ival; - } - skip_optional_pos: -- return_value = _lzma_LZMADecompressor_decompress_impl(self, &data, max_length); -+ return_value = _lzma_LZMADecompressor_decompress_impl((Decompressor *)self, &data, max_length); - - exit: - /* Cleanup for data */ -@@ -329,4 +329,4 @@ - - return return_value; - } --/*[clinic end generated code: output=52e1b68d0886cebb input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=19ed9b1182f5ddf9 input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/_pickle.c.h b/Modules/clinic/_pickle.c.h -index 2e84bb83e21..91d355c5afb 100644 ---- a/Modules/clinic/_pickle.c.h -+++ b/Modules/clinic/_pickle.c.h -@@ -26,9 +26,9 @@ - _pickle_Pickler_clear_memo_impl(PicklerObject *self); - - static PyObject * --_pickle_Pickler_clear_memo(PicklerObject *self, PyObject *Py_UNUSED(ignored)) -+_pickle_Pickler_clear_memo(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _pickle_Pickler_clear_memo_impl(self); -+ return _pickle_Pickler_clear_memo_impl((PicklerObject *)self); - } - - PyDoc_STRVAR(_pickle_Pickler_dump__doc__, -@@ -45,7 +45,7 @@ - PyObject *obj); - - static PyObject * --_pickle_Pickler_dump(PicklerObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_pickle_Pickler_dump(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -70,7 +70,7 @@ - goto exit; - } - obj = args[0]; -- return_value = _pickle_Pickler_dump_impl(self, cls, obj); -+ return_value = _pickle_Pickler_dump_impl((PicklerObject *)self, cls, obj); - - exit: - return return_value; -@@ -89,12 +89,12 @@ - _pickle_Pickler___sizeof___impl(PicklerObject *self); - - static PyObject * --_pickle_Pickler___sizeof__(PicklerObject *self, PyObject *Py_UNUSED(ignored)) -+_pickle_Pickler___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - size_t _return_value; - -- _return_value = _pickle_Pickler___sizeof___impl(self); -+ _return_value = _pickle_Pickler___sizeof___impl((PicklerObject *)self); - if ((_return_value == (size_t)-1) && PyErr_Occurred()) { - goto exit; - } -@@ -227,9 +227,9 @@ - _pickle_PicklerMemoProxy_clear_impl(PicklerMemoProxyObject *self); - - static PyObject * --_pickle_PicklerMemoProxy_clear(PicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) -+_pickle_PicklerMemoProxy_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _pickle_PicklerMemoProxy_clear_impl(self); -+ return _pickle_PicklerMemoProxy_clear_impl((PicklerMemoProxyObject *)self); - } - - PyDoc_STRVAR(_pickle_PicklerMemoProxy_copy__doc__, -@@ -245,9 +245,9 @@ - _pickle_PicklerMemoProxy_copy_impl(PicklerMemoProxyObject *self); - - static PyObject * --_pickle_PicklerMemoProxy_copy(PicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) -+_pickle_PicklerMemoProxy_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _pickle_PicklerMemoProxy_copy_impl(self); -+ return _pickle_PicklerMemoProxy_copy_impl((PicklerMemoProxyObject *)self); - } - - PyDoc_STRVAR(_pickle_PicklerMemoProxy___reduce____doc__, -@@ -263,9 +263,9 @@ - _pickle_PicklerMemoProxy___reduce___impl(PicklerMemoProxyObject *self); - - static PyObject * --_pickle_PicklerMemoProxy___reduce__(PicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) -+_pickle_PicklerMemoProxy___reduce__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _pickle_PicklerMemoProxy___reduce___impl(self); -+ return _pickle_PicklerMemoProxy___reduce___impl((PicklerMemoProxyObject *)self); - } - - PyDoc_STRVAR(_pickle_Unpickler_persistent_load__doc__, -@@ -281,7 +281,7 @@ - PyTypeObject *cls, PyObject *pid); - - static PyObject * --_pickle_Unpickler_persistent_load(UnpicklerObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_pickle_Unpickler_persistent_load(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -306,7 +306,7 @@ - goto exit; - } - pid = args[0]; -- return_value = _pickle_Unpickler_persistent_load_impl(self, cls, pid); -+ return_value = _pickle_Unpickler_persistent_load_impl((UnpicklerObject *)self, cls, pid); - - exit: - return return_value; -@@ -329,13 +329,13 @@ - _pickle_Unpickler_load_impl(UnpicklerObject *self, PyTypeObject *cls); - - static PyObject * --_pickle_Unpickler_load(UnpicklerObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_pickle_Unpickler_load(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "load() takes no arguments"); - return NULL; - } -- return _pickle_Unpickler_load_impl(self, cls); -+ return _pickle_Unpickler_load_impl((UnpicklerObject *)self, cls); - } - - PyDoc_STRVAR(_pickle_Unpickler_find_class__doc__, -@@ -360,7 +360,7 @@ - PyObject *global_name); - - static PyObject * --_pickle_Unpickler_find_class(UnpicklerObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_pickle_Unpickler_find_class(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -387,7 +387,7 @@ - } - module_name = args[0]; - global_name = args[1]; -- return_value = _pickle_Unpickler_find_class_impl(self, cls, module_name, global_name); -+ return_value = _pickle_Unpickler_find_class_impl((UnpicklerObject *)self, cls, module_name, global_name); - - exit: - return return_value; -@@ -406,12 +406,12 @@ - _pickle_Unpickler___sizeof___impl(UnpicklerObject *self); - - static PyObject * --_pickle_Unpickler___sizeof__(UnpicklerObject *self, PyObject *Py_UNUSED(ignored)) -+_pickle_Unpickler___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - size_t _return_value; - -- _return_value = _pickle_Unpickler___sizeof___impl(self); -+ _return_value = _pickle_Unpickler___sizeof___impl((UnpicklerObject *)self); - if ((_return_value == (size_t)-1) && PyErr_Occurred()) { - goto exit; - } -@@ -566,9 +566,9 @@ - _pickle_UnpicklerMemoProxy_clear_impl(UnpicklerMemoProxyObject *self); - - static PyObject * --_pickle_UnpicklerMemoProxy_clear(UnpicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) -+_pickle_UnpicklerMemoProxy_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _pickle_UnpicklerMemoProxy_clear_impl(self); -+ return _pickle_UnpicklerMemoProxy_clear_impl((UnpicklerMemoProxyObject *)self); - } - - PyDoc_STRVAR(_pickle_UnpicklerMemoProxy_copy__doc__, -@@ -584,9 +584,9 @@ - _pickle_UnpicklerMemoProxy_copy_impl(UnpicklerMemoProxyObject *self); - - static PyObject * --_pickle_UnpicklerMemoProxy_copy(UnpicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) -+_pickle_UnpicklerMemoProxy_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _pickle_UnpicklerMemoProxy_copy_impl(self); -+ return _pickle_UnpicklerMemoProxy_copy_impl((UnpicklerMemoProxyObject *)self); - } - - PyDoc_STRVAR(_pickle_UnpicklerMemoProxy___reduce____doc__, -@@ -602,9 +602,9 @@ - _pickle_UnpicklerMemoProxy___reduce___impl(UnpicklerMemoProxyObject *self); - - static PyObject * --_pickle_UnpicklerMemoProxy___reduce__(UnpicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) -+_pickle_UnpicklerMemoProxy___reduce__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _pickle_UnpicklerMemoProxy___reduce___impl(self); -+ return _pickle_UnpicklerMemoProxy___reduce___impl((UnpicklerMemoProxyObject *)self); - } - - PyDoc_STRVAR(_pickle_dump__doc__, -@@ -1086,4 +1086,4 @@ - exit: - return return_value; - } --/*[clinic end generated code: output=48ceb6687a8e716c input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=d71dc73af298ebe8 input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/_queuemodule.c.h b/Modules/clinic/_queuemodule.c.h -index f0d4a3a164c..2dfc3e6be19 100644 ---- a/Modules/clinic/_queuemodule.c.h -+++ b/Modules/clinic/_queuemodule.c.h -@@ -55,7 +55,7 @@ - int block, PyObject *timeout); - - static PyObject * --_queue_SimpleQueue_put(simplequeueobject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_queue_SimpleQueue_put(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -110,7 +110,7 @@ - timeout = args[2]; - skip_optional_pos: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _queue_SimpleQueue_put_impl(self, item, block, timeout); -+ return_value = _queue_SimpleQueue_put_impl((simplequeueobject *)self, item, block, timeout); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -133,7 +133,7 @@ - _queue_SimpleQueue_put_nowait_impl(simplequeueobject *self, PyObject *item); - - static PyObject * --_queue_SimpleQueue_put_nowait(simplequeueobject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_queue_SimpleQueue_put_nowait(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -171,7 +171,7 @@ - } - item = args[0]; - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _queue_SimpleQueue_put_nowait_impl(self, item); -+ return_value = _queue_SimpleQueue_put_nowait_impl((simplequeueobject *)self, item); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -200,7 +200,7 @@ - int block, PyObject *timeout_obj); - - static PyObject * --_queue_SimpleQueue_get(simplequeueobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_queue_SimpleQueue_get(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -253,7 +253,7 @@ - timeout_obj = args[1]; - skip_optional_pos: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _queue_SimpleQueue_get_impl(self, cls, block, timeout_obj); -+ return_value = _queue_SimpleQueue_get_impl((simplequeueobject *)self, cls, block, timeout_obj); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -277,7 +277,7 @@ - PyTypeObject *cls); - - static PyObject * --_queue_SimpleQueue_get_nowait(simplequeueobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_queue_SimpleQueue_get_nowait(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - -@@ -286,7 +286,7 @@ - goto exit; - } - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _queue_SimpleQueue_get_nowait_impl(self, cls); -+ return_value = _queue_SimpleQueue_get_nowait_impl((simplequeueobject *)self, cls); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -306,13 +306,13 @@ - _queue_SimpleQueue_empty_impl(simplequeueobject *self); - - static PyObject * --_queue_SimpleQueue_empty(simplequeueobject *self, PyObject *Py_UNUSED(ignored)) -+_queue_SimpleQueue_empty(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - int _return_value; - - Py_BEGIN_CRITICAL_SECTION(self); -- _return_value = _queue_SimpleQueue_empty_impl(self); -+ _return_value = _queue_SimpleQueue_empty_impl((simplequeueobject *)self); - Py_END_CRITICAL_SECTION(); - if ((_return_value == -1) && PyErr_Occurred()) { - goto exit; -@@ -336,13 +336,13 @@ - _queue_SimpleQueue_qsize_impl(simplequeueobject *self); - - static PyObject * --_queue_SimpleQueue_qsize(simplequeueobject *self, PyObject *Py_UNUSED(ignored)) -+_queue_SimpleQueue_qsize(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - Py_ssize_t _return_value; - - Py_BEGIN_CRITICAL_SECTION(self); -- _return_value = _queue_SimpleQueue_qsize_impl(self); -+ _return_value = _queue_SimpleQueue_qsize_impl((simplequeueobject *)self); - Py_END_CRITICAL_SECTION(); - if ((_return_value == -1) && PyErr_Occurred()) { - goto exit; -@@ -352,4 +352,4 @@ - exit: - return return_value; - } --/*[clinic end generated code: output=07b5742dca7692d9 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=e04e15a1b959c700 input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/_randommodule.c.h b/Modules/clinic/_randommodule.c.h -index 6193acac67e..b2d67e11c63 100644 ---- a/Modules/clinic/_randommodule.c.h -+++ b/Modules/clinic/_randommodule.c.h -@@ -18,12 +18,12 @@ - _random_Random_random_impl(RandomObject *self); - - static PyObject * --_random_Random_random(RandomObject *self, PyObject *Py_UNUSED(ignored)) -+_random_Random_random(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _random_Random_random_impl(self); -+ return_value = _random_Random_random_impl((RandomObject *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -45,7 +45,7 @@ - _random_Random_seed_impl(RandomObject *self, PyObject *n); - - static PyObject * --_random_Random_seed(RandomObject *self, PyObject *const *args, Py_ssize_t nargs) -+_random_Random_seed(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *n = Py_None; -@@ -59,7 +59,7 @@ - n = args[0]; - skip_optional: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _random_Random_seed_impl(self, n); -+ return_value = _random_Random_seed_impl((RandomObject *)self, n); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -79,12 +79,12 @@ - _random_Random_getstate_impl(RandomObject *self); - - static PyObject * --_random_Random_getstate(RandomObject *self, PyObject *Py_UNUSED(ignored)) -+_random_Random_getstate(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _random_Random_getstate_impl(self); -+ return_value = _random_Random_getstate_impl((RandomObject *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -108,7 +108,7 @@ - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _random_Random_setstate_impl(self, state); -+ return_value = _random_Random_setstate_impl((RandomObject *)self, state); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -127,7 +127,7 @@ - _random_Random_getrandbits_impl(RandomObject *self, int k); - - static PyObject * --_random_Random_getrandbits(RandomObject *self, PyObject *arg) -+_random_Random_getrandbits(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - int k; -@@ -137,10 +137,10 @@ - goto exit; - } - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _random_Random_getrandbits_impl(self, k); -+ return_value = _random_Random_getrandbits_impl((RandomObject *)self, k); - Py_END_CRITICAL_SECTION(); - - exit: - return return_value; - } --/*[clinic end generated code: output=bf49ece1d341b1b6 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=859cfbf59c133a4e input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/_ssl.c.h b/Modules/clinic/_ssl.c.h -index 1ff85e32ffe..73c5d304f1a 100644 ---- a/Modules/clinic/_ssl.c.h -+++ b/Modules/clinic/_ssl.c.h -@@ -21,12 +21,12 @@ - _ssl__SSLSocket_do_handshake_impl(PySSLSocket *self); - - static PyObject * --_ssl__SSLSocket_do_handshake(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) -+_ssl__SSLSocket_do_handshake(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLSocket_do_handshake_impl(self); -+ return_value = _ssl__SSLSocket_do_handshake_impl((PySSLSocket *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -79,7 +79,7 @@ - _ssl__SSLSocket_getpeercert_impl(PySSLSocket *self, int binary_mode); - - static PyObject * --_ssl__SSLSocket_getpeercert(PySSLSocket *self, PyObject *const *args, Py_ssize_t nargs) -+_ssl__SSLSocket_getpeercert(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - int binary_mode = 0; -@@ -96,7 +96,7 @@ - } - skip_optional: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLSocket_getpeercert_impl(self, binary_mode); -+ return_value = _ssl__SSLSocket_getpeercert_impl((PySSLSocket *)self, binary_mode); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -115,12 +115,12 @@ - _ssl__SSLSocket_get_verified_chain_impl(PySSLSocket *self); - - static PyObject * --_ssl__SSLSocket_get_verified_chain(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) -+_ssl__SSLSocket_get_verified_chain(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLSocket_get_verified_chain_impl(self); -+ return_value = _ssl__SSLSocket_get_verified_chain_impl((PySSLSocket *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -138,12 +138,12 @@ - _ssl__SSLSocket_get_unverified_chain_impl(PySSLSocket *self); - - static PyObject * --_ssl__SSLSocket_get_unverified_chain(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) -+_ssl__SSLSocket_get_unverified_chain(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLSocket_get_unverified_chain_impl(self); -+ return_value = _ssl__SSLSocket_get_unverified_chain_impl((PySSLSocket *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -161,12 +161,12 @@ - _ssl__SSLSocket_shared_ciphers_impl(PySSLSocket *self); - - static PyObject * --_ssl__SSLSocket_shared_ciphers(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) -+_ssl__SSLSocket_shared_ciphers(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLSocket_shared_ciphers_impl(self); -+ return_value = _ssl__SSLSocket_shared_ciphers_impl((PySSLSocket *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -184,12 +184,12 @@ - _ssl__SSLSocket_cipher_impl(PySSLSocket *self); - - static PyObject * --_ssl__SSLSocket_cipher(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) -+_ssl__SSLSocket_cipher(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLSocket_cipher_impl(self); -+ return_value = _ssl__SSLSocket_cipher_impl((PySSLSocket *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -207,12 +207,12 @@ - _ssl__SSLSocket_version_impl(PySSLSocket *self); - - static PyObject * --_ssl__SSLSocket_version(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) -+_ssl__SSLSocket_version(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLSocket_version_impl(self); -+ return_value = _ssl__SSLSocket_version_impl((PySSLSocket *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -230,12 +230,12 @@ - _ssl__SSLSocket_selected_alpn_protocol_impl(PySSLSocket *self); - - static PyObject * --_ssl__SSLSocket_selected_alpn_protocol(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) -+_ssl__SSLSocket_selected_alpn_protocol(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLSocket_selected_alpn_protocol_impl(self); -+ return_value = _ssl__SSLSocket_selected_alpn_protocol_impl((PySSLSocket *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -253,9 +253,9 @@ - _ssl__SSLSocket_compression_impl(PySSLSocket *self); - - static PyObject * --_ssl__SSLSocket_compression(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) -+_ssl__SSLSocket_compression(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _ssl__SSLSocket_compression_impl(self); -+ return _ssl__SSLSocket_compression_impl((PySSLSocket *)self); - } - - PyDoc_STRVAR(_ssl__SSLSocket_context__doc__, -@@ -264,6 +264,9 @@ - "This is typically used from within a callback function set by the sni_callback\n" - "on the SSLContext to change the certificate information associated with the\n" - "SSLSocket before the cryptographic exchange handshake messages."); -+#if defined(_ssl__SSLSocket_context_DOCSTR) -+# undef _ssl__SSLSocket_context_DOCSTR -+#endif - #define _ssl__SSLSocket_context_DOCSTR _ssl__SSLSocket_context__doc__ - - #if !defined(_ssl__SSLSocket_context_DOCSTR) -@@ -280,12 +283,12 @@ - _ssl__SSLSocket_context_get_impl(PySSLSocket *self); - - static PyObject * --_ssl__SSLSocket_context_get(PySSLSocket *self, void *Py_UNUSED(context)) -+_ssl__SSLSocket_context_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLSocket_context_get_impl(self); -+ return_value = _ssl__SSLSocket_context_get_impl((PySSLSocket *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -305,12 +308,12 @@ - _ssl__SSLSocket_context_set_impl(PySSLSocket *self, PyObject *value); - - static int --_ssl__SSLSocket_context_set(PySSLSocket *self, PyObject *value, void *Py_UNUSED(context)) -+_ssl__SSLSocket_context_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) - { - int return_value; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLSocket_context_set_impl(self, value); -+ return_value = _ssl__SSLSocket_context_set_impl((PySSLSocket *)self, value); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -318,6 +321,9 @@ - - PyDoc_STRVAR(_ssl__SSLSocket_server_side__doc__, - "Whether this is a server-side socket."); -+#if defined(_ssl__SSLSocket_server_side_DOCSTR) -+# undef _ssl__SSLSocket_server_side_DOCSTR -+#endif - #define _ssl__SSLSocket_server_side_DOCSTR _ssl__SSLSocket_server_side__doc__ - - #if !defined(_ssl__SSLSocket_server_side_DOCSTR) -@@ -334,12 +340,12 @@ - _ssl__SSLSocket_server_side_get_impl(PySSLSocket *self); - - static PyObject * --_ssl__SSLSocket_server_side_get(PySSLSocket *self, void *Py_UNUSED(context)) -+_ssl__SSLSocket_server_side_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLSocket_server_side_get_impl(self); -+ return_value = _ssl__SSLSocket_server_side_get_impl((PySSLSocket *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -347,6 +353,9 @@ - - PyDoc_STRVAR(_ssl__SSLSocket_server_hostname__doc__, - "The currently set server hostname (for SNI)."); -+#if defined(_ssl__SSLSocket_server_hostname_DOCSTR) -+# undef _ssl__SSLSocket_server_hostname_DOCSTR -+#endif - #define _ssl__SSLSocket_server_hostname_DOCSTR _ssl__SSLSocket_server_hostname__doc__ - - #if !defined(_ssl__SSLSocket_server_hostname_DOCSTR) -@@ -363,12 +372,12 @@ - _ssl__SSLSocket_server_hostname_get_impl(PySSLSocket *self); - - static PyObject * --_ssl__SSLSocket_server_hostname_get(PySSLSocket *self, void *Py_UNUSED(context)) -+_ssl__SSLSocket_server_hostname_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLSocket_server_hostname_get_impl(self); -+ return_value = _ssl__SSLSocket_server_hostname_get_impl((PySSLSocket *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -378,6 +387,9 @@ - "The Python-level owner of this object.\n" - "\n" - "Passed as \"self\" in servername callback."); -+#if defined(_ssl__SSLSocket_owner_DOCSTR) -+# undef _ssl__SSLSocket_owner_DOCSTR -+#endif - #define _ssl__SSLSocket_owner_DOCSTR _ssl__SSLSocket_owner__doc__ - - #if !defined(_ssl__SSLSocket_owner_DOCSTR) -@@ -394,12 +406,12 @@ - _ssl__SSLSocket_owner_get_impl(PySSLSocket *self); - - static PyObject * --_ssl__SSLSocket_owner_get(PySSLSocket *self, void *Py_UNUSED(context)) -+_ssl__SSLSocket_owner_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLSocket_owner_get_impl(self); -+ return_value = _ssl__SSLSocket_owner_get_impl((PySSLSocket *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -419,12 +431,12 @@ - _ssl__SSLSocket_owner_set_impl(PySSLSocket *self, PyObject *value); - - static int --_ssl__SSLSocket_owner_set(PySSLSocket *self, PyObject *value, void *Py_UNUSED(context)) -+_ssl__SSLSocket_owner_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) - { - int return_value; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLSocket_owner_set_impl(self, value); -+ return_value = _ssl__SSLSocket_owner_set_impl((PySSLSocket *)self, value); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -445,7 +457,7 @@ - _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b); - - static PyObject * --_ssl__SSLSocket_write(PySSLSocket *self, PyObject *arg) -+_ssl__SSLSocket_write(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - Py_buffer b = {NULL, NULL}; -@@ -454,7 +466,7 @@ - goto exit; - } - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLSocket_write_impl(self, &b); -+ return_value = _ssl__SSLSocket_write_impl((PySSLSocket *)self, &b); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -479,12 +491,12 @@ - _ssl__SSLSocket_pending_impl(PySSLSocket *self); - - static PyObject * --_ssl__SSLSocket_pending(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) -+_ssl__SSLSocket_pending(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLSocket_pending_impl(self); -+ return_value = _ssl__SSLSocket_pending_impl((PySSLSocket *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -502,7 +514,7 @@ - int group_right_1, Py_buffer *buffer); - - static PyObject * --_ssl__SSLSocket_read(PySSLSocket *self, PyObject *args) -+_ssl__SSLSocket_read(PyObject *self, PyObject *args) - { - PyObject *return_value = NULL; - Py_ssize_t len; -@@ -526,7 +538,7 @@ - goto exit; - } - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLSocket_read_impl(self, len, group_right_1, &buffer); -+ return_value = _ssl__SSLSocket_read_impl((PySSLSocket *)self, len, group_right_1, &buffer); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -551,12 +563,12 @@ - _ssl__SSLSocket_shutdown_impl(PySSLSocket *self); - - static PyObject * --_ssl__SSLSocket_shutdown(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) -+_ssl__SSLSocket_shutdown(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLSocket_shutdown_impl(self); -+ return_value = _ssl__SSLSocket_shutdown_impl((PySSLSocket *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -580,7 +592,7 @@ - const char *cb_type); - - static PyObject * --_ssl__SSLSocket_get_channel_binding(PySSLSocket *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_ssl__SSLSocket_get_channel_binding(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -635,7 +647,7 @@ - } - skip_optional_pos: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLSocket_get_channel_binding_impl(self, cb_type); -+ return_value = _ssl__SSLSocket_get_channel_binding_impl((PySSLSocket *)self, cb_type); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -655,12 +667,12 @@ - _ssl__SSLSocket_verify_client_post_handshake_impl(PySSLSocket *self); - - static PyObject * --_ssl__SSLSocket_verify_client_post_handshake(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) -+_ssl__SSLSocket_verify_client_post_handshake(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLSocket_verify_client_post_handshake_impl(self); -+ return_value = _ssl__SSLSocket_verify_client_post_handshake_impl((PySSLSocket *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -668,6 +680,9 @@ - - PyDoc_STRVAR(_ssl__SSLSocket_session__doc__, - "The underlying SSLSession object."); -+#if defined(_ssl__SSLSocket_session_DOCSTR) -+# undef _ssl__SSLSocket_session_DOCSTR -+#endif - #define _ssl__SSLSocket_session_DOCSTR _ssl__SSLSocket_session__doc__ - - #if !defined(_ssl__SSLSocket_session_DOCSTR) -@@ -684,12 +699,12 @@ - _ssl__SSLSocket_session_get_impl(PySSLSocket *self); - - static PyObject * --_ssl__SSLSocket_session_get(PySSLSocket *self, void *Py_UNUSED(context)) -+_ssl__SSLSocket_session_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLSocket_session_get_impl(self); -+ return_value = _ssl__SSLSocket_session_get_impl((PySSLSocket *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -709,12 +724,12 @@ - _ssl__SSLSocket_session_set_impl(PySSLSocket *self, PyObject *value); - - static int --_ssl__SSLSocket_session_set(PySSLSocket *self, PyObject *value, void *Py_UNUSED(context)) -+_ssl__SSLSocket_session_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) - { - int return_value; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLSocket_session_set_impl(self, value); -+ return_value = _ssl__SSLSocket_session_set_impl((PySSLSocket *)self, value); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -722,6 +737,9 @@ - - PyDoc_STRVAR(_ssl__SSLSocket_session_reused__doc__, - "Was the client session reused during handshake?"); -+#if defined(_ssl__SSLSocket_session_reused_DOCSTR) -+# undef _ssl__SSLSocket_session_reused_DOCSTR -+#endif - #define _ssl__SSLSocket_session_reused_DOCSTR _ssl__SSLSocket_session_reused__doc__ - - #if !defined(_ssl__SSLSocket_session_reused_DOCSTR) -@@ -738,12 +756,12 @@ - _ssl__SSLSocket_session_reused_get_impl(PySSLSocket *self); - - static PyObject * --_ssl__SSLSocket_session_reused_get(PySSLSocket *self, void *Py_UNUSED(context)) -+_ssl__SSLSocket_session_reused_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLSocket_session_reused_get_impl(self); -+ return_value = _ssl__SSLSocket_session_reused_get_impl((PySSLSocket *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -790,7 +808,7 @@ - _ssl__SSLContext_set_ciphers_impl(PySSLContext *self, const char *cipherlist); - - static PyObject * --_ssl__SSLContext_set_ciphers(PySSLContext *self, PyObject *arg) -+_ssl__SSLContext_set_ciphers(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - const char *cipherlist; -@@ -809,7 +827,7 @@ - goto exit; - } - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_set_ciphers_impl(self, cipherlist); -+ return_value = _ssl__SSLContext_set_ciphers_impl((PySSLContext *)self, cipherlist); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -828,12 +846,12 @@ - _ssl__SSLContext_get_ciphers_impl(PySSLContext *self); - - static PyObject * --_ssl__SSLContext_get_ciphers(PySSLContext *self, PyObject *Py_UNUSED(ignored)) -+_ssl__SSLContext_get_ciphers(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_get_ciphers_impl(self); -+ return_value = _ssl__SSLContext_get_ciphers_impl((PySSLContext *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -852,7 +870,7 @@ - Py_buffer *protos); - - static PyObject * --_ssl__SSLContext__set_alpn_protocols(PySSLContext *self, PyObject *arg) -+_ssl__SSLContext__set_alpn_protocols(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - Py_buffer protos = {NULL, NULL}; -@@ -861,7 +879,7 @@ - goto exit; - } - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext__set_alpn_protocols_impl(self, &protos); -+ return_value = _ssl__SSLContext__set_alpn_protocols_impl((PySSLContext *)self, &protos); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -887,12 +905,12 @@ - _ssl__SSLContext_verify_mode_get_impl(PySSLContext *self); - - static PyObject * --_ssl__SSLContext_verify_mode_get(PySSLContext *self, void *Py_UNUSED(context)) -+_ssl__SSLContext_verify_mode_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_verify_mode_get_impl(self); -+ return_value = _ssl__SSLContext_verify_mode_get_impl((PySSLContext *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -912,12 +930,12 @@ - _ssl__SSLContext_verify_mode_set_impl(PySSLContext *self, PyObject *value); - - static int --_ssl__SSLContext_verify_mode_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) -+_ssl__SSLContext_verify_mode_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) - { - int return_value; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_verify_mode_set_impl(self, value); -+ return_value = _ssl__SSLContext_verify_mode_set_impl((PySSLContext *)self, value); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -937,12 +955,12 @@ - _ssl__SSLContext_verify_flags_get_impl(PySSLContext *self); - - static PyObject * --_ssl__SSLContext_verify_flags_get(PySSLContext *self, void *Py_UNUSED(context)) -+_ssl__SSLContext_verify_flags_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_verify_flags_get_impl(self); -+ return_value = _ssl__SSLContext_verify_flags_get_impl((PySSLContext *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -962,12 +980,12 @@ - _ssl__SSLContext_verify_flags_set_impl(PySSLContext *self, PyObject *value); - - static int --_ssl__SSLContext_verify_flags_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) -+_ssl__SSLContext_verify_flags_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) - { - int return_value; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_verify_flags_set_impl(self, value); -+ return_value = _ssl__SSLContext_verify_flags_set_impl((PySSLContext *)self, value); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -987,12 +1005,12 @@ - _ssl__SSLContext_minimum_version_get_impl(PySSLContext *self); - - static PyObject * --_ssl__SSLContext_minimum_version_get(PySSLContext *self, void *Py_UNUSED(context)) -+_ssl__SSLContext_minimum_version_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_minimum_version_get_impl(self); -+ return_value = _ssl__SSLContext_minimum_version_get_impl((PySSLContext *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1013,12 +1031,12 @@ - PyObject *value); - - static int --_ssl__SSLContext_minimum_version_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) -+_ssl__SSLContext_minimum_version_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) - { - int return_value; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_minimum_version_set_impl(self, value); -+ return_value = _ssl__SSLContext_minimum_version_set_impl((PySSLContext *)self, value); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1038,12 +1056,12 @@ - _ssl__SSLContext_maximum_version_get_impl(PySSLContext *self); - - static PyObject * --_ssl__SSLContext_maximum_version_get(PySSLContext *self, void *Py_UNUSED(context)) -+_ssl__SSLContext_maximum_version_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_maximum_version_get_impl(self); -+ return_value = _ssl__SSLContext_maximum_version_get_impl((PySSLContext *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1064,12 +1082,12 @@ - PyObject *value); - - static int --_ssl__SSLContext_maximum_version_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) -+_ssl__SSLContext_maximum_version_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) - { - int return_value; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_maximum_version_set_impl(self, value); -+ return_value = _ssl__SSLContext_maximum_version_set_impl((PySSLContext *)self, value); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1077,6 +1095,9 @@ - - PyDoc_STRVAR(_ssl__SSLContext_num_tickets__doc__, - "Control the number of TLSv1.3 session tickets."); -+#if defined(_ssl__SSLContext_num_tickets_DOCSTR) -+# undef _ssl__SSLContext_num_tickets_DOCSTR -+#endif - #define _ssl__SSLContext_num_tickets_DOCSTR _ssl__SSLContext_num_tickets__doc__ - - #if !defined(_ssl__SSLContext_num_tickets_DOCSTR) -@@ -1093,12 +1114,12 @@ - _ssl__SSLContext_num_tickets_get_impl(PySSLContext *self); - - static PyObject * --_ssl__SSLContext_num_tickets_get(PySSLContext *self, void *Py_UNUSED(context)) -+_ssl__SSLContext_num_tickets_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_num_tickets_get_impl(self); -+ return_value = _ssl__SSLContext_num_tickets_get_impl((PySSLContext *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1118,12 +1139,12 @@ - _ssl__SSLContext_num_tickets_set_impl(PySSLContext *self, PyObject *value); - - static int --_ssl__SSLContext_num_tickets_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) -+_ssl__SSLContext_num_tickets_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) - { - int return_value; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_num_tickets_set_impl(self, value); -+ return_value = _ssl__SSLContext_num_tickets_set_impl((PySSLContext *)self, value); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1131,6 +1152,9 @@ - - PyDoc_STRVAR(_ssl__SSLContext_security_level__doc__, - "The current security level."); -+#if defined(_ssl__SSLContext_security_level_DOCSTR) -+# undef _ssl__SSLContext_security_level_DOCSTR -+#endif - #define _ssl__SSLContext_security_level_DOCSTR _ssl__SSLContext_security_level__doc__ - - #if !defined(_ssl__SSLContext_security_level_DOCSTR) -@@ -1147,12 +1171,12 @@ - _ssl__SSLContext_security_level_get_impl(PySSLContext *self); - - static PyObject * --_ssl__SSLContext_security_level_get(PySSLContext *self, void *Py_UNUSED(context)) -+_ssl__SSLContext_security_level_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_security_level_get_impl(self); -+ return_value = _ssl__SSLContext_security_level_get_impl((PySSLContext *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1172,12 +1196,12 @@ - _ssl__SSLContext_options_get_impl(PySSLContext *self); - - static PyObject * --_ssl__SSLContext_options_get(PySSLContext *self, void *Py_UNUSED(context)) -+_ssl__SSLContext_options_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_options_get_impl(self); -+ return_value = _ssl__SSLContext_options_get_impl((PySSLContext *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1197,12 +1221,12 @@ - _ssl__SSLContext_options_set_impl(PySSLContext *self, PyObject *value); - - static int --_ssl__SSLContext_options_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) -+_ssl__SSLContext_options_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) - { - int return_value; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_options_set_impl(self, value); -+ return_value = _ssl__SSLContext_options_set_impl((PySSLContext *)self, value); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1222,12 +1246,12 @@ - _ssl__SSLContext__host_flags_get_impl(PySSLContext *self); - - static PyObject * --_ssl__SSLContext__host_flags_get(PySSLContext *self, void *Py_UNUSED(context)) -+_ssl__SSLContext__host_flags_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext__host_flags_get_impl(self); -+ return_value = _ssl__SSLContext__host_flags_get_impl((PySSLContext *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1247,12 +1271,12 @@ - _ssl__SSLContext__host_flags_set_impl(PySSLContext *self, PyObject *value); - - static int --_ssl__SSLContext__host_flags_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) -+_ssl__SSLContext__host_flags_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) - { - int return_value; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext__host_flags_set_impl(self, value); -+ return_value = _ssl__SSLContext__host_flags_set_impl((PySSLContext *)self, value); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1272,12 +1296,12 @@ - _ssl__SSLContext_check_hostname_get_impl(PySSLContext *self); - - static PyObject * --_ssl__SSLContext_check_hostname_get(PySSLContext *self, void *Py_UNUSED(context)) -+_ssl__SSLContext_check_hostname_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_check_hostname_get_impl(self); -+ return_value = _ssl__SSLContext_check_hostname_get_impl((PySSLContext *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1297,12 +1321,12 @@ - _ssl__SSLContext_check_hostname_set_impl(PySSLContext *self, PyObject *value); - - static int --_ssl__SSLContext_check_hostname_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) -+_ssl__SSLContext_check_hostname_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) - { - int return_value; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_check_hostname_set_impl(self, value); -+ return_value = _ssl__SSLContext_check_hostname_set_impl((PySSLContext *)self, value); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1322,12 +1346,12 @@ - _ssl__SSLContext_protocol_get_impl(PySSLContext *self); - - static PyObject * --_ssl__SSLContext_protocol_get(PySSLContext *self, void *Py_UNUSED(context)) -+_ssl__SSLContext_protocol_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_protocol_get_impl(self); -+ return_value = _ssl__SSLContext_protocol_get_impl((PySSLContext *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1346,7 +1370,7 @@ - PyObject *keyfile, PyObject *password); - - static PyObject * --_ssl__SSLContext_load_cert_chain(PySSLContext *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_ssl__SSLContext_load_cert_chain(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -1398,7 +1422,7 @@ - password = args[2]; - skip_optional_pos: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_load_cert_chain_impl(self, certfile, keyfile, password); -+ return_value = _ssl__SSLContext_load_cert_chain_impl((PySSLContext *)self, certfile, keyfile, password); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -1420,7 +1444,7 @@ - PyObject *cadata); - - static PyObject * --_ssl__SSLContext_load_verify_locations(PySSLContext *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_ssl__SSLContext_load_verify_locations(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -1477,7 +1501,7 @@ - cadata = args[2]; - skip_optional_pos: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_load_verify_locations_impl(self, cafile, capath, cadata); -+ return_value = _ssl__SSLContext_load_verify_locations_impl((PySSLContext *)self, cafile, capath, cadata); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -1501,7 +1525,7 @@ - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_load_dh_params_impl(self, filepath); -+ return_value = _ssl__SSLContext_load_dh_params_impl((PySSLContext *)self, filepath); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1522,7 +1546,7 @@ - PyObject *owner, PyObject *session); - - static PyObject * --_ssl__SSLContext__wrap_socket(PySSLContext *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_ssl__SSLContext__wrap_socket(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -1594,7 +1618,7 @@ - session = args[4]; - skip_optional_kwonly: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext__wrap_socket_impl(self, sock, server_side, hostname_obj, owner, session); -+ return_value = _ssl__SSLContext__wrap_socket_impl((PySSLContext *)self, sock, server_side, hostname_obj, owner, session); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -1617,7 +1641,7 @@ - PyObject *session); - - static PyObject * --_ssl__SSLContext__wrap_bio(PySSLContext *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_ssl__SSLContext__wrap_bio(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -1695,7 +1719,7 @@ - session = args[5]; - skip_optional_kwonly: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext__wrap_bio_impl(self, incoming, outgoing, server_side, hostname_obj, owner, session); -+ return_value = _ssl__SSLContext__wrap_bio_impl((PySSLContext *)self, incoming, outgoing, server_side, hostname_obj, owner, session); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -1714,12 +1738,12 @@ - _ssl__SSLContext_session_stats_impl(PySSLContext *self); - - static PyObject * --_ssl__SSLContext_session_stats(PySSLContext *self, PyObject *Py_UNUSED(ignored)) -+_ssl__SSLContext_session_stats(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_session_stats_impl(self); -+ return_value = _ssl__SSLContext_session_stats_impl((PySSLContext *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1737,12 +1761,12 @@ - _ssl__SSLContext_set_default_verify_paths_impl(PySSLContext *self); - - static PyObject * --_ssl__SSLContext_set_default_verify_paths(PySSLContext *self, PyObject *Py_UNUSED(ignored)) -+_ssl__SSLContext_set_default_verify_paths(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_set_default_verify_paths_impl(self); -+ return_value = _ssl__SSLContext_set_default_verify_paths_impl((PySSLContext *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1765,7 +1789,7 @@ - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_set_ecdh_curve_impl(self, name); -+ return_value = _ssl__SSLContext_set_ecdh_curve_impl((PySSLContext *)self, name); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1778,6 +1802,9 @@ - "with the SSLSocket, the server name as a string, and the SSLContext object.\n" - "\n" - "See RFC 6066 for details of the SNI extension."); -+#if defined(_ssl__SSLContext_sni_callback_DOCSTR) -+# undef _ssl__SSLContext_sni_callback_DOCSTR -+#endif - #define _ssl__SSLContext_sni_callback_DOCSTR _ssl__SSLContext_sni_callback__doc__ - - #if !defined(_ssl__SSLContext_sni_callback_DOCSTR) -@@ -1794,12 +1821,12 @@ - _ssl__SSLContext_sni_callback_get_impl(PySSLContext *self); - - static PyObject * --_ssl__SSLContext_sni_callback_get(PySSLContext *self, void *Py_UNUSED(context)) -+_ssl__SSLContext_sni_callback_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_sni_callback_get_impl(self); -+ return_value = _ssl__SSLContext_sni_callback_get_impl((PySSLContext *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1819,12 +1846,12 @@ - _ssl__SSLContext_sni_callback_set_impl(PySSLContext *self, PyObject *value); - - static int --_ssl__SSLContext_sni_callback_set(PySSLContext *self, PyObject *value, void *Py_UNUSED(context)) -+_ssl__SSLContext_sni_callback_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) - { - int return_value; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_sni_callback_set_impl(self, value); -+ return_value = _ssl__SSLContext_sni_callback_set_impl((PySSLContext *)self, value); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1849,12 +1876,12 @@ - _ssl__SSLContext_cert_store_stats_impl(PySSLContext *self); - - static PyObject * --_ssl__SSLContext_cert_store_stats(PySSLContext *self, PyObject *Py_UNUSED(ignored)) -+_ssl__SSLContext_cert_store_stats(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_cert_store_stats_impl(self); -+ return_value = _ssl__SSLContext_cert_store_stats_impl((PySSLContext *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1879,7 +1906,7 @@ - _ssl__SSLContext_get_ca_certs_impl(PySSLContext *self, int binary_form); - - static PyObject * --_ssl__SSLContext_get_ca_certs(PySSLContext *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_ssl__SSLContext_get_ca_certs(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -1925,7 +1952,7 @@ - } - skip_optional_pos: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_get_ca_certs_impl(self, binary_form); -+ return_value = _ssl__SSLContext_get_ca_certs_impl((PySSLContext *)self, binary_form); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -1945,7 +1972,7 @@ - PyObject *callback); - - static PyObject * --_ssl__SSLContext_set_psk_client_callback(PySSLContext *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_ssl__SSLContext_set_psk_client_callback(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -1983,7 +2010,7 @@ - } - callback = args[0]; - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_set_psk_client_callback_impl(self, callback); -+ return_value = _ssl__SSLContext_set_psk_client_callback_impl((PySSLContext *)self, callback); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -2004,7 +2031,7 @@ - const char *identity_hint); - - static PyObject * --_ssl__SSLContext_set_psk_server_callback(PySSLContext *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_ssl__SSLContext_set_psk_server_callback(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -2066,7 +2093,7 @@ - } - skip_optional_pos: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl__SSLContext_set_psk_server_callback_impl(self, callback, identity_hint); -+ return_value = _ssl__SSLContext_set_psk_server_callback_impl((PySSLContext *)self, callback, identity_hint); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -2100,6 +2127,9 @@ - - PyDoc_STRVAR(_ssl_MemoryBIO_pending__doc__, - "The number of bytes pending in the memory BIO."); -+#if defined(_ssl_MemoryBIO_pending_DOCSTR) -+# undef _ssl_MemoryBIO_pending_DOCSTR -+#endif - #define _ssl_MemoryBIO_pending_DOCSTR _ssl_MemoryBIO_pending__doc__ - - #if !defined(_ssl_MemoryBIO_pending_DOCSTR) -@@ -2116,12 +2146,12 @@ - _ssl_MemoryBIO_pending_get_impl(PySSLMemoryBIO *self); - - static PyObject * --_ssl_MemoryBIO_pending_get(PySSLMemoryBIO *self, void *Py_UNUSED(context)) -+_ssl_MemoryBIO_pending_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl_MemoryBIO_pending_get_impl(self); -+ return_value = _ssl_MemoryBIO_pending_get_impl((PySSLMemoryBIO *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -2129,6 +2159,9 @@ - - PyDoc_STRVAR(_ssl_MemoryBIO_eof__doc__, - "Whether the memory BIO is at EOF."); -+#if defined(_ssl_MemoryBIO_eof_DOCSTR) -+# undef _ssl_MemoryBIO_eof_DOCSTR -+#endif - #define _ssl_MemoryBIO_eof_DOCSTR _ssl_MemoryBIO_eof__doc__ - - #if !defined(_ssl_MemoryBIO_eof_DOCSTR) -@@ -2145,12 +2178,12 @@ - _ssl_MemoryBIO_eof_get_impl(PySSLMemoryBIO *self); - - static PyObject * --_ssl_MemoryBIO_eof_get(PySSLMemoryBIO *self, void *Py_UNUSED(context)) -+_ssl_MemoryBIO_eof_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl_MemoryBIO_eof_get_impl(self); -+ return_value = _ssl_MemoryBIO_eof_get_impl((PySSLMemoryBIO *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -2174,7 +2207,7 @@ - _ssl_MemoryBIO_read_impl(PySSLMemoryBIO *self, int len); - - static PyObject * --_ssl_MemoryBIO_read(PySSLMemoryBIO *self, PyObject *const *args, Py_ssize_t nargs) -+_ssl_MemoryBIO_read(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - int len = -1; -@@ -2191,7 +2224,7 @@ - } - skip_optional: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl_MemoryBIO_read_impl(self, len); -+ return_value = _ssl_MemoryBIO_read_impl((PySSLMemoryBIO *)self, len); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -2213,7 +2246,7 @@ - _ssl_MemoryBIO_write_impl(PySSLMemoryBIO *self, Py_buffer *b); - - static PyObject * --_ssl_MemoryBIO_write(PySSLMemoryBIO *self, PyObject *arg) -+_ssl_MemoryBIO_write(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - Py_buffer b = {NULL, NULL}; -@@ -2222,7 +2255,7 @@ - goto exit; - } - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl_MemoryBIO_write_impl(self, &b); -+ return_value = _ssl_MemoryBIO_write_impl((PySSLMemoryBIO *)self, &b); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -2249,12 +2282,12 @@ - _ssl_MemoryBIO_write_eof_impl(PySSLMemoryBIO *self); - - static PyObject * --_ssl_MemoryBIO_write_eof(PySSLMemoryBIO *self, PyObject *Py_UNUSED(ignored)) -+_ssl_MemoryBIO_write_eof(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl_MemoryBIO_write_eof_impl(self); -+ return_value = _ssl_MemoryBIO_write_eof_impl((PySSLMemoryBIO *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -2262,6 +2295,9 @@ - - PyDoc_STRVAR(_ssl_SSLSession_time__doc__, - "Session creation time (seconds since epoch)."); -+#if defined(_ssl_SSLSession_time_DOCSTR) -+# undef _ssl_SSLSession_time_DOCSTR -+#endif - #define _ssl_SSLSession_time_DOCSTR _ssl_SSLSession_time__doc__ - - #if !defined(_ssl_SSLSession_time_DOCSTR) -@@ -2278,12 +2314,12 @@ - _ssl_SSLSession_time_get_impl(PySSLSession *self); - - static PyObject * --_ssl_SSLSession_time_get(PySSLSession *self, void *Py_UNUSED(context)) -+_ssl_SSLSession_time_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl_SSLSession_time_get_impl(self); -+ return_value = _ssl_SSLSession_time_get_impl((PySSLSession *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -2291,6 +2327,9 @@ - - PyDoc_STRVAR(_ssl_SSLSession_timeout__doc__, - "Session timeout (delta in seconds)."); -+#if defined(_ssl_SSLSession_timeout_DOCSTR) -+# undef _ssl_SSLSession_timeout_DOCSTR -+#endif - #define _ssl_SSLSession_timeout_DOCSTR _ssl_SSLSession_timeout__doc__ - - #if !defined(_ssl_SSLSession_timeout_DOCSTR) -@@ -2307,12 +2346,12 @@ - _ssl_SSLSession_timeout_get_impl(PySSLSession *self); - - static PyObject * --_ssl_SSLSession_timeout_get(PySSLSession *self, void *Py_UNUSED(context)) -+_ssl_SSLSession_timeout_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl_SSLSession_timeout_get_impl(self); -+ return_value = _ssl_SSLSession_timeout_get_impl((PySSLSession *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -2320,6 +2359,9 @@ - - PyDoc_STRVAR(_ssl_SSLSession_ticket_lifetime_hint__doc__, - "Ticket life time hint."); -+#if defined(_ssl_SSLSession_ticket_lifetime_hint_DOCSTR) -+# undef _ssl_SSLSession_ticket_lifetime_hint_DOCSTR -+#endif - #define _ssl_SSLSession_ticket_lifetime_hint_DOCSTR _ssl_SSLSession_ticket_lifetime_hint__doc__ - - #if !defined(_ssl_SSLSession_ticket_lifetime_hint_DOCSTR) -@@ -2336,12 +2378,12 @@ - _ssl_SSLSession_ticket_lifetime_hint_get_impl(PySSLSession *self); - - static PyObject * --_ssl_SSLSession_ticket_lifetime_hint_get(PySSLSession *self, void *Py_UNUSED(context)) -+_ssl_SSLSession_ticket_lifetime_hint_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl_SSLSession_ticket_lifetime_hint_get_impl(self); -+ return_value = _ssl_SSLSession_ticket_lifetime_hint_get_impl((PySSLSession *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -2349,6 +2391,9 @@ - - PyDoc_STRVAR(_ssl_SSLSession_id__doc__, - "Session ID."); -+#if defined(_ssl_SSLSession_id_DOCSTR) -+# undef _ssl_SSLSession_id_DOCSTR -+#endif - #define _ssl_SSLSession_id_DOCSTR _ssl_SSLSession_id__doc__ - - #if !defined(_ssl_SSLSession_id_DOCSTR) -@@ -2365,12 +2410,12 @@ - _ssl_SSLSession_id_get_impl(PySSLSession *self); - - static PyObject * --_ssl_SSLSession_id_get(PySSLSession *self, void *Py_UNUSED(context)) -+_ssl_SSLSession_id_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl_SSLSession_id_get_impl(self); -+ return_value = _ssl_SSLSession_id_get_impl((PySSLSession *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -2378,6 +2423,9 @@ - - PyDoc_STRVAR(_ssl_SSLSession_has_ticket__doc__, - "Does the session contain a ticket?"); -+#if defined(_ssl_SSLSession_has_ticket_DOCSTR) -+# undef _ssl_SSLSession_has_ticket_DOCSTR -+#endif - #define _ssl_SSLSession_has_ticket_DOCSTR _ssl_SSLSession_has_ticket__doc__ - - #if !defined(_ssl_SSLSession_has_ticket_DOCSTR) -@@ -2394,12 +2442,12 @@ - _ssl_SSLSession_has_ticket_get_impl(PySSLSession *self); - - static PyObject * --_ssl_SSLSession_has_ticket_get(PySSLSession *self, void *Py_UNUSED(context)) -+_ssl_SSLSession_has_ticket_get(PyObject *self, void *Py_UNUSED(context)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = _ssl_SSLSession_has_ticket_get_impl(self); -+ return_value = _ssl_SSLSession_has_ticket_get_impl((PySSLSession *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -2830,4 +2878,4 @@ - #ifndef _SSL_ENUM_CRLS_METHODDEF - #define _SSL_ENUM_CRLS_METHODDEF - #endif /* !defined(_SSL_ENUM_CRLS_METHODDEF) */ --/*[clinic end generated code: output=654d6d7af659f6cd input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=bededfb2b927bd41 input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/_struct.c.h b/Modules/clinic/_struct.c.h -index cfc2fe7fc1d..7cf179f7a69 100644 ---- a/Modules/clinic/_struct.c.h -+++ b/Modules/clinic/_struct.c.h -@@ -87,7 +87,7 @@ - Struct_unpack_impl(PyStructObject *self, Py_buffer *buffer); - - static PyObject * --Struct_unpack(PyStructObject *self, PyObject *arg) -+Struct_unpack(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - Py_buffer buffer = {NULL, NULL}; -@@ -95,7 +95,7 @@ - if (PyObject_GetBuffer(arg, &buffer, PyBUF_SIMPLE) != 0) { - goto exit; - } -- return_value = Struct_unpack_impl(self, &buffer); -+ return_value = Struct_unpack_impl((PyStructObject *)self, &buffer); - - exit: - /* Cleanup for buffer */ -@@ -127,7 +127,7 @@ - Py_ssize_t offset); - - static PyObject * --Struct_unpack_from(PyStructObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+Struct_unpack_from(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -184,7 +184,7 @@ - offset = ival; - } - skip_optional_pos: -- return_value = Struct_unpack_from_impl(self, &buffer, offset); -+ return_value = Struct_unpack_from_impl((PyStructObject *)self, &buffer, offset); - - exit: - /* Cleanup for buffer */ -@@ -439,4 +439,4 @@ - - return return_value; - } --/*[clinic end generated code: output=faff90f99c6bd09f input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=ec540c21be08e1d0 input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/_testmultiphase.c.h b/Modules/clinic/_testmultiphase.c.h -index 5a432a6f703..01c29c0753a 100644 ---- a/Modules/clinic/_testmultiphase.c.h -+++ b/Modules/clinic/_testmultiphase.c.h -@@ -25,13 +25,13 @@ - PyTypeObject *cls); - - static PyObject * --_testmultiphase_StateAccessType_get_defining_module(StateAccessTypeObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_testmultiphase_StateAccessType_get_defining_module(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "get_defining_module() takes no arguments"); - return NULL; - } -- return _testmultiphase_StateAccessType_get_defining_module_impl(self, cls); -+ return _testmultiphase_StateAccessType_get_defining_module_impl((StateAccessTypeObject *)self, cls); - } - - PyDoc_STRVAR(_testmultiphase_StateAccessType_getmodulebydef_bad_def__doc__, -@@ -48,13 +48,13 @@ - PyTypeObject *cls); - - static PyObject * --_testmultiphase_StateAccessType_getmodulebydef_bad_def(StateAccessTypeObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_testmultiphase_StateAccessType_getmodulebydef_bad_def(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "getmodulebydef_bad_def() takes no arguments"); - return NULL; - } -- return _testmultiphase_StateAccessType_getmodulebydef_bad_def_impl(self, cls); -+ return _testmultiphase_StateAccessType_getmodulebydef_bad_def_impl((StateAccessTypeObject *)self, cls); - } - - PyDoc_STRVAR(_testmultiphase_StateAccessType_increment_count_clinic__doc__, -@@ -76,7 +76,7 @@ - int n, int twice); - - static PyObject * --_testmultiphase_StateAccessType_increment_count_clinic(StateAccessTypeObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_testmultiphase_StateAccessType_increment_count_clinic(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -135,7 +135,7 @@ - goto exit; - } - skip_optional_kwonly: -- return_value = _testmultiphase_StateAccessType_increment_count_clinic_impl(self, cls, n, twice); -+ return_value = _testmultiphase_StateAccessType_increment_count_clinic_impl((StateAccessTypeObject *)self, cls, n, twice); - - exit: - return return_value; -@@ -155,12 +155,12 @@ - PyTypeObject *cls); - - static PyObject * --_testmultiphase_StateAccessType_get_count(StateAccessTypeObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+_testmultiphase_StateAccessType_get_count(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "get_count() takes no arguments"); - return NULL; - } -- return _testmultiphase_StateAccessType_get_count_impl(self, cls); -+ return _testmultiphase_StateAccessType_get_count_impl((StateAccessTypeObject *)self, cls); - } --/*[clinic end generated code: output=c1aa0af3572bf059 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=ea0ca98e467e53c2 input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/_threadmodule.c.h b/Modules/clinic/_threadmodule.c.h -index 8f0507d4028..09b7afebd6d 100644 ---- a/Modules/clinic/_threadmodule.c.h -+++ b/Modules/clinic/_threadmodule.c.h -@@ -8,7 +8,7 @@ - #endif - #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() - --#if defined(HAVE_PTHREAD_GETNAME_NP) -+#if (defined(HAVE_PTHREAD_GETNAME_NP) || defined(MS_WINDOWS)) - - PyDoc_STRVAR(_thread__get_name__doc__, - "_get_name($module, /)\n" -@@ -28,9 +28,9 @@ - return _thread__get_name_impl(module); - } - --#endif /* defined(HAVE_PTHREAD_GETNAME_NP) */ -+#endif /* (defined(HAVE_PTHREAD_GETNAME_NP) || defined(MS_WINDOWS)) */ - --#if defined(HAVE_PTHREAD_SETNAME_NP) -+#if (defined(HAVE_PTHREAD_SETNAME_NP) || defined(MS_WINDOWS)) - - PyDoc_STRVAR(_thread_set_name__doc__, - "set_name($module, /, name)\n" -@@ -92,7 +92,7 @@ - return return_value; - } - --#endif /* defined(HAVE_PTHREAD_SETNAME_NP) */ -+#endif /* (defined(HAVE_PTHREAD_SETNAME_NP) || defined(MS_WINDOWS)) */ - - #ifndef _THREAD__GET_NAME_METHODDEF - #define _THREAD__GET_NAME_METHODDEF -@@ -101,4 +101,4 @@ - #ifndef _THREAD_SET_NAME_METHODDEF - #define _THREAD_SET_NAME_METHODDEF - #endif /* !defined(_THREAD_SET_NAME_METHODDEF) */ --/*[clinic end generated code: output=b5cb85aaccc45bf6 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=6e88ef6b126cece8 input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/_tkinter.c.h b/Modules/clinic/_tkinter.c.h -index 2b1ac954b4d..d6e783b04fe 100644 ---- a/Modules/clinic/_tkinter.c.h -+++ b/Modules/clinic/_tkinter.c.h -@@ -16,7 +16,7 @@ - _tkinter_tkapp_eval_impl(TkappObject *self, const char *script); - - static PyObject * --_tkinter_tkapp_eval(TkappObject *self, PyObject *arg) -+_tkinter_tkapp_eval(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - const char *script; -@@ -34,7 +34,7 @@ - PyErr_SetString(PyExc_ValueError, "embedded null character"); - goto exit; - } -- return_value = _tkinter_tkapp_eval_impl(self, script); -+ return_value = _tkinter_tkapp_eval_impl((TkappObject *)self, script); - - exit: - return return_value; -@@ -52,7 +52,7 @@ - _tkinter_tkapp_evalfile_impl(TkappObject *self, const char *fileName); - - static PyObject * --_tkinter_tkapp_evalfile(TkappObject *self, PyObject *arg) -+_tkinter_tkapp_evalfile(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - const char *fileName; -@@ -70,7 +70,7 @@ - PyErr_SetString(PyExc_ValueError, "embedded null character"); - goto exit; - } -- return_value = _tkinter_tkapp_evalfile_impl(self, fileName); -+ return_value = _tkinter_tkapp_evalfile_impl((TkappObject *)self, fileName); - - exit: - return return_value; -@@ -88,7 +88,7 @@ - _tkinter_tkapp_record_impl(TkappObject *self, const char *script); - - static PyObject * --_tkinter_tkapp_record(TkappObject *self, PyObject *arg) -+_tkinter_tkapp_record(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - const char *script; -@@ -106,7 +106,7 @@ - PyErr_SetString(PyExc_ValueError, "embedded null character"); - goto exit; - } -- return_value = _tkinter_tkapp_record_impl(self, script); -+ return_value = _tkinter_tkapp_record_impl((TkappObject *)self, script); - - exit: - return return_value; -@@ -124,7 +124,7 @@ - _tkinter_tkapp_adderrorinfo_impl(TkappObject *self, const char *msg); - - static PyObject * --_tkinter_tkapp_adderrorinfo(TkappObject *self, PyObject *arg) -+_tkinter_tkapp_adderrorinfo(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - const char *msg; -@@ -142,7 +142,7 @@ - PyErr_SetString(PyExc_ValueError, "embedded null character"); - goto exit; - } -- return_value = _tkinter_tkapp_adderrorinfo_impl(self, msg); -+ return_value = _tkinter_tkapp_adderrorinfo_impl((TkappObject *)self, msg); - - exit: - return return_value; -@@ -184,7 +184,7 @@ - _tkinter_tkapp_exprstring_impl(TkappObject *self, const char *s); - - static PyObject * --_tkinter_tkapp_exprstring(TkappObject *self, PyObject *arg) -+_tkinter_tkapp_exprstring(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - const char *s; -@@ -202,7 +202,7 @@ - PyErr_SetString(PyExc_ValueError, "embedded null character"); - goto exit; - } -- return_value = _tkinter_tkapp_exprstring_impl(self, s); -+ return_value = _tkinter_tkapp_exprstring_impl((TkappObject *)self, s); - - exit: - return return_value; -@@ -220,7 +220,7 @@ - _tkinter_tkapp_exprlong_impl(TkappObject *self, const char *s); - - static PyObject * --_tkinter_tkapp_exprlong(TkappObject *self, PyObject *arg) -+_tkinter_tkapp_exprlong(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - const char *s; -@@ -238,7 +238,7 @@ - PyErr_SetString(PyExc_ValueError, "embedded null character"); - goto exit; - } -- return_value = _tkinter_tkapp_exprlong_impl(self, s); -+ return_value = _tkinter_tkapp_exprlong_impl((TkappObject *)self, s); - - exit: - return return_value; -@@ -256,7 +256,7 @@ - _tkinter_tkapp_exprdouble_impl(TkappObject *self, const char *s); - - static PyObject * --_tkinter_tkapp_exprdouble(TkappObject *self, PyObject *arg) -+_tkinter_tkapp_exprdouble(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - const char *s; -@@ -274,7 +274,7 @@ - PyErr_SetString(PyExc_ValueError, "embedded null character"); - goto exit; - } -- return_value = _tkinter_tkapp_exprdouble_impl(self, s); -+ return_value = _tkinter_tkapp_exprdouble_impl((TkappObject *)self, s); - - exit: - return return_value; -@@ -292,7 +292,7 @@ - _tkinter_tkapp_exprboolean_impl(TkappObject *self, const char *s); - - static PyObject * --_tkinter_tkapp_exprboolean(TkappObject *self, PyObject *arg) -+_tkinter_tkapp_exprboolean(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - const char *s; -@@ -310,7 +310,7 @@ - PyErr_SetString(PyExc_ValueError, "embedded null character"); - goto exit; - } -- return_value = _tkinter_tkapp_exprboolean_impl(self, s); -+ return_value = _tkinter_tkapp_exprboolean_impl((TkappObject *)self, s); - - exit: - return return_value; -@@ -337,7 +337,7 @@ - PyObject *func); - - static PyObject * --_tkinter_tkapp_createcommand(TkappObject *self, PyObject *const *args, Py_ssize_t nargs) -+_tkinter_tkapp_createcommand(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - const char *name; -@@ -360,7 +360,7 @@ - goto exit; - } - func = args[1]; -- return_value = _tkinter_tkapp_createcommand_impl(self, name, func); -+ return_value = _tkinter_tkapp_createcommand_impl((TkappObject *)self, name, func); - - exit: - return return_value; -@@ -378,7 +378,7 @@ - _tkinter_tkapp_deletecommand_impl(TkappObject *self, const char *name); - - static PyObject * --_tkinter_tkapp_deletecommand(TkappObject *self, PyObject *arg) -+_tkinter_tkapp_deletecommand(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - const char *name; -@@ -396,7 +396,7 @@ - PyErr_SetString(PyExc_ValueError, "embedded null character"); - goto exit; - } -- return_value = _tkinter_tkapp_deletecommand_impl(self, name); -+ return_value = _tkinter_tkapp_deletecommand_impl((TkappObject *)self, name); - - exit: - return return_value; -@@ -417,7 +417,7 @@ - int mask, PyObject *func); - - static PyObject * --_tkinter_tkapp_createfilehandler(TkappObject *self, PyObject *const *args, Py_ssize_t nargs) -+_tkinter_tkapp_createfilehandler(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *file; -@@ -433,7 +433,7 @@ - goto exit; - } - func = args[2]; -- return_value = _tkinter_tkapp_createfilehandler_impl(self, file, mask, func); -+ return_value = _tkinter_tkapp_createfilehandler_impl((TkappObject *)self, file, mask, func); - - exit: - return return_value; -@@ -465,9 +465,9 @@ - _tkinter_tktimertoken_deletetimerhandler_impl(TkttObject *self); - - static PyObject * --_tkinter_tktimertoken_deletetimerhandler(TkttObject *self, PyObject *Py_UNUSED(ignored)) -+_tkinter_tktimertoken_deletetimerhandler(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _tkinter_tktimertoken_deletetimerhandler_impl(self); -+ return _tkinter_tktimertoken_deletetimerhandler_impl((TkttObject *)self); - } - - PyDoc_STRVAR(_tkinter_tkapp_createtimerhandler__doc__, -@@ -483,7 +483,7 @@ - PyObject *func); - - static PyObject * --_tkinter_tkapp_createtimerhandler(TkappObject *self, PyObject *const *args, Py_ssize_t nargs) -+_tkinter_tkapp_createtimerhandler(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - int milliseconds; -@@ -497,7 +497,7 @@ - goto exit; - } - func = args[1]; -- return_value = _tkinter_tkapp_createtimerhandler_impl(self, milliseconds, func); -+ return_value = _tkinter_tkapp_createtimerhandler_impl((TkappObject *)self, milliseconds, func); - - exit: - return return_value; -@@ -515,7 +515,7 @@ - _tkinter_tkapp_mainloop_impl(TkappObject *self, int threshold); - - static PyObject * --_tkinter_tkapp_mainloop(TkappObject *self, PyObject *const *args, Py_ssize_t nargs) -+_tkinter_tkapp_mainloop(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - int threshold = 0; -@@ -531,7 +531,7 @@ - goto exit; - } - skip_optional: -- return_value = _tkinter_tkapp_mainloop_impl(self, threshold); -+ return_value = _tkinter_tkapp_mainloop_impl((TkappObject *)self, threshold); - - exit: - return return_value; -@@ -549,7 +549,7 @@ - _tkinter_tkapp_dooneevent_impl(TkappObject *self, int flags); - - static PyObject * --_tkinter_tkapp_dooneevent(TkappObject *self, PyObject *const *args, Py_ssize_t nargs) -+_tkinter_tkapp_dooneevent(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - int flags = 0; -@@ -565,7 +565,7 @@ - goto exit; - } - skip_optional: -- return_value = _tkinter_tkapp_dooneevent_impl(self, flags); -+ return_value = _tkinter_tkapp_dooneevent_impl((TkappObject *)self, flags); - - exit: - return return_value; -@@ -583,9 +583,9 @@ - _tkinter_tkapp_quit_impl(TkappObject *self); - - static PyObject * --_tkinter_tkapp_quit(TkappObject *self, PyObject *Py_UNUSED(ignored)) -+_tkinter_tkapp_quit(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _tkinter_tkapp_quit_impl(self); -+ return _tkinter_tkapp_quit_impl((TkappObject *)self); - } - - PyDoc_STRVAR(_tkinter_tkapp_interpaddr__doc__, -@@ -600,9 +600,9 @@ - _tkinter_tkapp_interpaddr_impl(TkappObject *self); - - static PyObject * --_tkinter_tkapp_interpaddr(TkappObject *self, PyObject *Py_UNUSED(ignored)) -+_tkinter_tkapp_interpaddr(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _tkinter_tkapp_interpaddr_impl(self); -+ return _tkinter_tkapp_interpaddr_impl((TkappObject *)self); - } - - PyDoc_STRVAR(_tkinter_tkapp_loadtk__doc__, -@@ -617,9 +617,9 @@ - _tkinter_tkapp_loadtk_impl(TkappObject *self); - - static PyObject * --_tkinter_tkapp_loadtk(TkappObject *self, PyObject *Py_UNUSED(ignored)) -+_tkinter_tkapp_loadtk(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _tkinter_tkapp_loadtk_impl(self); -+ return _tkinter_tkapp_loadtk_impl((TkappObject *)self); - } - - PyDoc_STRVAR(_tkinter_tkapp_settrace__doc__, -@@ -644,9 +644,9 @@ - _tkinter_tkapp_gettrace_impl(TkappObject *self); - - static PyObject * --_tkinter_tkapp_gettrace(TkappObject *self, PyObject *Py_UNUSED(ignored)) -+_tkinter_tkapp_gettrace(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _tkinter_tkapp_gettrace_impl(self); -+ return _tkinter_tkapp_gettrace_impl((TkappObject *)self); - } - - PyDoc_STRVAR(_tkinter_tkapp_willdispatch__doc__, -@@ -661,9 +661,9 @@ - _tkinter_tkapp_willdispatch_impl(TkappObject *self); - - static PyObject * --_tkinter_tkapp_willdispatch(TkappObject *self, PyObject *Py_UNUSED(ignored)) -+_tkinter_tkapp_willdispatch(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _tkinter_tkapp_willdispatch_impl(self); -+ return _tkinter_tkapp_willdispatch_impl((TkappObject *)self); - } - - PyDoc_STRVAR(_tkinter__flatten__doc__, -@@ -888,4 +888,4 @@ - #ifndef _TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF - #define _TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF - #endif /* !defined(_TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF) */ --/*[clinic end generated code: output=d90c1a9850c63249 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=172a98df5f209a84 input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/_winapi.c.h b/Modules/clinic/_winapi.c.h -index 8bbecc44dc9..6a2f8d45cd4 100644 ---- a/Modules/clinic/_winapi.c.h -+++ b/Modules/clinic/_winapi.c.h -@@ -21,7 +21,7 @@ - _winapi_Overlapped_GetOverlappedResult_impl(OverlappedObject *self, int wait); - - static PyObject * --_winapi_Overlapped_GetOverlappedResult(OverlappedObject *self, PyObject *arg) -+_winapi_Overlapped_GetOverlappedResult(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - int wait; -@@ -30,7 +30,7 @@ - if (wait < 0) { - goto exit; - } -- return_value = _winapi_Overlapped_GetOverlappedResult_impl(self, wait); -+ return_value = _winapi_Overlapped_GetOverlappedResult_impl((OverlappedObject *)self, wait); - - exit: - return return_value; -@@ -48,9 +48,9 @@ - _winapi_Overlapped_getbuffer_impl(OverlappedObject *self); - - static PyObject * --_winapi_Overlapped_getbuffer(OverlappedObject *self, PyObject *Py_UNUSED(ignored)) -+_winapi_Overlapped_getbuffer(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _winapi_Overlapped_getbuffer_impl(self); -+ return _winapi_Overlapped_getbuffer_impl((OverlappedObject *)self); - } - - PyDoc_STRVAR(_winapi_Overlapped_cancel__doc__, -@@ -65,9 +65,9 @@ - _winapi_Overlapped_cancel_impl(OverlappedObject *self); - - static PyObject * --_winapi_Overlapped_cancel(OverlappedObject *self, PyObject *Py_UNUSED(ignored)) -+_winapi_Overlapped_cancel(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _winapi_Overlapped_cancel_impl(self); -+ return _winapi_Overlapped_cancel_impl((OverlappedObject *)self); - } - - PyDoc_STRVAR(_winapi_CloseHandle__doc__, -@@ -2127,4 +2127,4 @@ - - return return_value; - } --/*[clinic end generated code: output=b2a178bde6868e88 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=06b56212b2186250 input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/arraymodule.c.h b/Modules/clinic/arraymodule.c.h -index 4a7266ecb8b..c5b62b16699 100644 ---- a/Modules/clinic/arraymodule.c.h -+++ b/Modules/clinic/arraymodule.c.h -@@ -21,9 +21,9 @@ - array_array_clear_impl(arrayobject *self); - - static PyObject * --array_array_clear(arrayobject *self, PyObject *Py_UNUSED(ignored)) -+array_array_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return array_array_clear_impl(self); -+ return array_array_clear_impl((arrayobject *)self); - } - - PyDoc_STRVAR(array_array___copy____doc__, -@@ -39,9 +39,9 @@ - array_array___copy___impl(arrayobject *self); - - static PyObject * --array_array___copy__(arrayobject *self, PyObject *Py_UNUSED(ignored)) -+array_array___copy__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return array_array___copy___impl(self); -+ return array_array___copy___impl((arrayobject *)self); - } - - PyDoc_STRVAR(array_array___deepcopy____doc__, -@@ -78,7 +78,7 @@ - Py_ssize_t stop); - - static PyObject * --array_array_index(arrayobject *self, PyObject *const *args, Py_ssize_t nargs) -+array_array_index(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *v; -@@ -102,7 +102,7 @@ - goto exit; - } - skip_optional: -- return_value = array_array_index_impl(self, v, start, stop); -+ return_value = array_array_index_impl((arrayobject *)self, v, start, stop); - - exit: - return return_value; -@@ -132,7 +132,7 @@ - array_array_pop_impl(arrayobject *self, Py_ssize_t i); - - static PyObject * --array_array_pop(arrayobject *self, PyObject *const *args, Py_ssize_t nargs) -+array_array_pop(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - Py_ssize_t i = -1; -@@ -156,7 +156,7 @@ - i = ival; - } - skip_optional: -- return_value = array_array_pop_impl(self, i); -+ return_value = array_array_pop_impl((arrayobject *)self, i); - - exit: - return return_value; -@@ -175,7 +175,7 @@ - array_array_extend_impl(arrayobject *self, PyTypeObject *cls, PyObject *bb); - - static PyObject * --array_array_extend(arrayobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+array_array_extend(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -200,7 +200,7 @@ - goto exit; - } - bb = args[0]; -- return_value = array_array_extend_impl(self, cls, bb); -+ return_value = array_array_extend_impl((arrayobject *)self, cls, bb); - - exit: - return return_value; -@@ -219,7 +219,7 @@ - array_array_insert_impl(arrayobject *self, Py_ssize_t i, PyObject *v); - - static PyObject * --array_array_insert(arrayobject *self, PyObject *const *args, Py_ssize_t nargs) -+array_array_insert(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - Py_ssize_t i; -@@ -241,7 +241,7 @@ - i = ival; - } - v = args[1]; -- return_value = array_array_insert_impl(self, i, v); -+ return_value = array_array_insert_impl((arrayobject *)self, i, v); - - exit: - return return_value; -@@ -263,9 +263,9 @@ - array_array_buffer_info_impl(arrayobject *self); - - static PyObject * --array_array_buffer_info(arrayobject *self, PyObject *Py_UNUSED(ignored)) -+array_array_buffer_info(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return array_array_buffer_info_impl(self); -+ return array_array_buffer_info_impl((arrayobject *)self); - } - - PyDoc_STRVAR(array_array_append__doc__, -@@ -293,9 +293,9 @@ - array_array_byteswap_impl(arrayobject *self); - - static PyObject * --array_array_byteswap(arrayobject *self, PyObject *Py_UNUSED(ignored)) -+array_array_byteswap(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return array_array_byteswap_impl(self); -+ return array_array_byteswap_impl((arrayobject *)self); - } - - PyDoc_STRVAR(array_array_reverse__doc__, -@@ -311,9 +311,9 @@ - array_array_reverse_impl(arrayobject *self); - - static PyObject * --array_array_reverse(arrayobject *self, PyObject *Py_UNUSED(ignored)) -+array_array_reverse(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return array_array_reverse_impl(self); -+ return array_array_reverse_impl((arrayobject *)self); - } - - PyDoc_STRVAR(array_array_fromfile__doc__, -@@ -330,7 +330,7 @@ - Py_ssize_t n); - - static PyObject * --array_array_fromfile(arrayobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+array_array_fromfile(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -368,7 +368,7 @@ - } - n = ival; - } -- return_value = array_array_fromfile_impl(self, cls, f, n); -+ return_value = array_array_fromfile_impl((arrayobject *)self, cls, f, n); - - exit: - return return_value; -@@ -387,7 +387,7 @@ - array_array_tofile_impl(arrayobject *self, PyTypeObject *cls, PyObject *f); - - static PyObject * --array_array_tofile(arrayobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+array_array_tofile(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -412,7 +412,7 @@ - goto exit; - } - f = args[0]; -- return_value = array_array_tofile_impl(self, cls, f); -+ return_value = array_array_tofile_impl((arrayobject *)self, cls, f); - - exit: - return return_value; -@@ -440,9 +440,9 @@ - array_array_tolist_impl(arrayobject *self); - - static PyObject * --array_array_tolist(arrayobject *self, PyObject *Py_UNUSED(ignored)) -+array_array_tolist(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return array_array_tolist_impl(self); -+ return array_array_tolist_impl((arrayobject *)self); - } - - PyDoc_STRVAR(array_array_frombytes__doc__, -@@ -458,7 +458,7 @@ - array_array_frombytes_impl(arrayobject *self, Py_buffer *buffer); - - static PyObject * --array_array_frombytes(arrayobject *self, PyObject *arg) -+array_array_frombytes(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - Py_buffer buffer = {NULL, NULL}; -@@ -466,7 +466,7 @@ - if (PyObject_GetBuffer(arg, &buffer, PyBUF_SIMPLE) != 0) { - goto exit; - } -- return_value = array_array_frombytes_impl(self, &buffer); -+ return_value = array_array_frombytes_impl((arrayobject *)self, &buffer); - - exit: - /* Cleanup for buffer */ -@@ -490,9 +490,9 @@ - array_array_tobytes_impl(arrayobject *self); - - static PyObject * --array_array_tobytes(arrayobject *self, PyObject *Py_UNUSED(ignored)) -+array_array_tobytes(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return array_array_tobytes_impl(self); -+ return array_array_tobytes_impl((arrayobject *)self); - } - - PyDoc_STRVAR(array_array_fromunicode__doc__, -@@ -512,7 +512,7 @@ - array_array_fromunicode_impl(arrayobject *self, PyObject *ustr); - - static PyObject * --array_array_fromunicode(arrayobject *self, PyObject *arg) -+array_array_fromunicode(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - PyObject *ustr; -@@ -522,7 +522,7 @@ - goto exit; - } - ustr = arg; -- return_value = array_array_fromunicode_impl(self, ustr); -+ return_value = array_array_fromunicode_impl((arrayobject *)self, ustr); - - exit: - return return_value; -@@ -545,9 +545,9 @@ - array_array_tounicode_impl(arrayobject *self); - - static PyObject * --array_array_tounicode(arrayobject *self, PyObject *Py_UNUSED(ignored)) -+array_array_tounicode(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return array_array_tounicode_impl(self); -+ return array_array_tounicode_impl((arrayobject *)self); - } - - PyDoc_STRVAR(array_array___sizeof____doc__, -@@ -563,9 +563,9 @@ - array_array___sizeof___impl(arrayobject *self); - - static PyObject * --array_array___sizeof__(arrayobject *self, PyObject *Py_UNUSED(ignored)) -+array_array___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return array_array___sizeof___impl(self); -+ return array_array___sizeof___impl((arrayobject *)self); - } - - PyDoc_STRVAR(array__array_reconstructor__doc__, -@@ -634,7 +634,7 @@ - PyObject *value); - - static PyObject * --array_array___reduce_ex__(arrayobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+array_array___reduce_ex__(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -659,7 +659,7 @@ - goto exit; - } - value = args[0]; -- return_value = array_array___reduce_ex___impl(self, cls, value); -+ return_value = array_array___reduce_ex___impl((arrayobject *)self, cls, value); - - exit: - return return_value; -@@ -678,13 +678,13 @@ - array_arrayiterator___reduce___impl(arrayiterobject *self, PyTypeObject *cls); - - static PyObject * --array_arrayiterator___reduce__(arrayiterobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+array_arrayiterator___reduce__(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "__reduce__() takes no arguments"); - return NULL; - } -- return array_arrayiterator___reduce___impl(self, cls); -+ return array_arrayiterator___reduce___impl((arrayiterobject *)self, cls); - } - - PyDoc_STRVAR(array_arrayiterator___setstate____doc__, -@@ -695,4 +695,4 @@ - - #define ARRAY_ARRAYITERATOR___SETSTATE___METHODDEF \ - {"__setstate__", (PyCFunction)array_arrayiterator___setstate__, METH_O, array_arrayiterator___setstate____doc__}, --/*[clinic end generated code: output=22dbe12826bfa86f input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=8120dc5c4fa414b9 input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/blake2module.c.h b/Modules/clinic/blake2module.c.h -index f695f27e9e6..b5ac90143a1 100644 ---- a/Modules/clinic/blake2module.c.h -+++ b/Modules/clinic/blake2module.c.h -@@ -412,9 +412,9 @@ - _blake2_blake2b_copy_impl(Blake2Object *self); - - static PyObject * --_blake2_blake2b_copy(Blake2Object *self, PyObject *Py_UNUSED(ignored)) -+_blake2_blake2b_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _blake2_blake2b_copy_impl(self); -+ return _blake2_blake2b_copy_impl((Blake2Object *)self); - } - - PyDoc_STRVAR(_blake2_blake2b_update__doc__, -@@ -439,9 +439,9 @@ - _blake2_blake2b_digest_impl(Blake2Object *self); - - static PyObject * --_blake2_blake2b_digest(Blake2Object *self, PyObject *Py_UNUSED(ignored)) -+_blake2_blake2b_digest(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _blake2_blake2b_digest_impl(self); -+ return _blake2_blake2b_digest_impl((Blake2Object *)self); - } - - PyDoc_STRVAR(_blake2_blake2b_hexdigest__doc__, -@@ -457,8 +457,8 @@ - _blake2_blake2b_hexdigest_impl(Blake2Object *self); - - static PyObject * --_blake2_blake2b_hexdigest(Blake2Object *self, PyObject *Py_UNUSED(ignored)) -+_blake2_blake2b_hexdigest(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _blake2_blake2b_hexdigest_impl(self); -+ return _blake2_blake2b_hexdigest_impl((Blake2Object *)self); - } --/*[clinic end generated code: output=e0aaaf112d023b79 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=6e03c947b7e0d973 input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/md5module.c.h b/Modules/clinic/md5module.c.h -index 7721616862e..1f0acebf47b 100644 ---- a/Modules/clinic/md5module.c.h -+++ b/Modules/clinic/md5module.c.h -@@ -21,13 +21,13 @@ - MD5Type_copy_impl(MD5object *self, PyTypeObject *cls); - - static PyObject * --MD5Type_copy(MD5object *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+MD5Type_copy(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "copy() takes no arguments"); - return NULL; - } -- return MD5Type_copy_impl(self, cls); -+ return MD5Type_copy_impl((MD5object *)self, cls); - } - - PyDoc_STRVAR(MD5Type_digest__doc__, -@@ -43,9 +43,9 @@ - MD5Type_digest_impl(MD5object *self); - - static PyObject * --MD5Type_digest(MD5object *self, PyObject *Py_UNUSED(ignored)) -+MD5Type_digest(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return MD5Type_digest_impl(self); -+ return MD5Type_digest_impl((MD5object *)self); - } - - PyDoc_STRVAR(MD5Type_hexdigest__doc__, -@@ -61,9 +61,9 @@ - MD5Type_hexdigest_impl(MD5object *self); - - static PyObject * --MD5Type_hexdigest(MD5object *self, PyObject *Py_UNUSED(ignored)) -+MD5Type_hexdigest(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return MD5Type_hexdigest_impl(self); -+ return MD5Type_hexdigest_impl((MD5object *)self); - } - - PyDoc_STRVAR(MD5Type_update__doc__, -@@ -149,4 +149,4 @@ - exit: - return return_value; - } --/*[clinic end generated code: output=62ebf28802ae8b5f input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=a4292eab710dcb60 input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/overlapped.c.h b/Modules/clinic/overlapped.c.h -index 9d5adb5193f..7e571566002 100644 ---- a/Modules/clinic/overlapped.c.h -+++ b/Modules/clinic/overlapped.c.h -@@ -516,9 +516,9 @@ - _overlapped_Overlapped_cancel_impl(OverlappedObject *self); - - static PyObject * --_overlapped_Overlapped_cancel(OverlappedObject *self, PyObject *Py_UNUSED(ignored)) -+_overlapped_Overlapped_cancel(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _overlapped_Overlapped_cancel_impl(self); -+ return _overlapped_Overlapped_cancel_impl((OverlappedObject *)self); - } - - PyDoc_STRVAR(_overlapped_Overlapped_getresult__doc__, -@@ -537,7 +537,7 @@ - _overlapped_Overlapped_getresult_impl(OverlappedObject *self, BOOL wait); - - static PyObject * --_overlapped_Overlapped_getresult(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) -+_overlapped_Overlapped_getresult(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - BOOL wait = FALSE; -@@ -553,7 +553,7 @@ - goto exit; - } - skip_optional: -- return_value = _overlapped_Overlapped_getresult_impl(self, wait); -+ return_value = _overlapped_Overlapped_getresult_impl((OverlappedObject *)self, wait); - - exit: - return return_value; -@@ -573,7 +573,7 @@ - DWORD size); - - static PyObject * --_overlapped_Overlapped_ReadFile(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) -+_overlapped_Overlapped_ReadFile(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - HANDLE handle; -@@ -589,7 +589,7 @@ - if (!_PyLong_UnsignedLong_Converter(args[1], &size)) { - goto exit; - } -- return_value = _overlapped_Overlapped_ReadFile_impl(self, handle, size); -+ return_value = _overlapped_Overlapped_ReadFile_impl((OverlappedObject *)self, handle, size); - - exit: - return return_value; -@@ -609,7 +609,7 @@ - HANDLE handle, Py_buffer *bufobj); - - static PyObject * --_overlapped_Overlapped_ReadFileInto(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) -+_overlapped_Overlapped_ReadFileInto(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - HANDLE handle; -@@ -625,7 +625,7 @@ - if (PyObject_GetBuffer(args[1], &bufobj, PyBUF_SIMPLE) != 0) { - goto exit; - } -- return_value = _overlapped_Overlapped_ReadFileInto_impl(self, handle, &bufobj); -+ return_value = _overlapped_Overlapped_ReadFileInto_impl((OverlappedObject *)self, handle, &bufobj); - - exit: - /* Cleanup for bufobj */ -@@ -650,7 +650,7 @@ - DWORD size, DWORD flags); - - static PyObject * --_overlapped_Overlapped_WSARecv(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) -+_overlapped_Overlapped_WSARecv(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - HANDLE handle; -@@ -674,7 +674,7 @@ - goto exit; - } - skip_optional: -- return_value = _overlapped_Overlapped_WSARecv_impl(self, handle, size, flags); -+ return_value = _overlapped_Overlapped_WSARecv_impl((OverlappedObject *)self, handle, size, flags); - - exit: - return return_value; -@@ -695,7 +695,7 @@ - DWORD flags); - - static PyObject * --_overlapped_Overlapped_WSARecvInto(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) -+_overlapped_Overlapped_WSARecvInto(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - HANDLE handle; -@@ -715,7 +715,7 @@ - if (!_PyLong_UnsignedLong_Converter(args[2], &flags)) { - goto exit; - } -- return_value = _overlapped_Overlapped_WSARecvInto_impl(self, handle, &bufobj, flags); -+ return_value = _overlapped_Overlapped_WSARecvInto_impl((OverlappedObject *)self, handle, &bufobj, flags); - - exit: - /* Cleanup for bufobj */ -@@ -740,7 +740,7 @@ - Py_buffer *bufobj); - - static PyObject * --_overlapped_Overlapped_WriteFile(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) -+_overlapped_Overlapped_WriteFile(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - HANDLE handle; -@@ -756,7 +756,7 @@ - if (PyObject_GetBuffer(args[1], &bufobj, PyBUF_SIMPLE) != 0) { - goto exit; - } -- return_value = _overlapped_Overlapped_WriteFile_impl(self, handle, &bufobj); -+ return_value = _overlapped_Overlapped_WriteFile_impl((OverlappedObject *)self, handle, &bufobj); - - exit: - /* Cleanup for bufobj */ -@@ -781,7 +781,7 @@ - Py_buffer *bufobj, DWORD flags); - - static PyObject * --_overlapped_Overlapped_WSASend(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) -+_overlapped_Overlapped_WSASend(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - HANDLE handle; -@@ -801,7 +801,7 @@ - if (!_PyLong_UnsignedLong_Converter(args[2], &flags)) { - goto exit; - } -- return_value = _overlapped_Overlapped_WSASend_impl(self, handle, &bufobj, flags); -+ return_value = _overlapped_Overlapped_WSASend_impl((OverlappedObject *)self, handle, &bufobj, flags); - - exit: - /* Cleanup for bufobj */ -@@ -827,7 +827,7 @@ - HANDLE AcceptSocket); - - static PyObject * --_overlapped_Overlapped_AcceptEx(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) -+_overlapped_Overlapped_AcceptEx(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - HANDLE ListenSocket; -@@ -844,7 +844,7 @@ - if (!AcceptSocket && PyErr_Occurred()) { - goto exit; - } -- return_value = _overlapped_Overlapped_AcceptEx_impl(self, ListenSocket, AcceptSocket); -+ return_value = _overlapped_Overlapped_AcceptEx_impl((OverlappedObject *)self, ListenSocket, AcceptSocket); - - exit: - return return_value; -@@ -867,7 +867,7 @@ - PyObject *AddressObj); - - static PyObject * --_overlapped_Overlapped_ConnectEx(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) -+_overlapped_Overlapped_ConnectEx(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - HANDLE ConnectSocket; -@@ -885,7 +885,7 @@ - goto exit; - } - AddressObj = args[1]; -- return_value = _overlapped_Overlapped_ConnectEx_impl(self, ConnectSocket, AddressObj); -+ return_value = _overlapped_Overlapped_ConnectEx_impl((OverlappedObject *)self, ConnectSocket, AddressObj); - - exit: - return return_value; -@@ -904,7 +904,7 @@ - HANDLE Socket, DWORD flags); - - static PyObject * --_overlapped_Overlapped_DisconnectEx(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) -+_overlapped_Overlapped_DisconnectEx(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - HANDLE Socket; -@@ -920,7 +920,7 @@ - if (!_PyLong_UnsignedLong_Converter(args[1], &flags)) { - goto exit; - } -- return_value = _overlapped_Overlapped_DisconnectEx_impl(self, Socket, flags); -+ return_value = _overlapped_Overlapped_DisconnectEx_impl((OverlappedObject *)self, Socket, flags); - - exit: - return return_value; -@@ -944,7 +944,7 @@ - DWORD count_per_send, DWORD flags); - - static PyObject * --_overlapped_Overlapped_TransmitFile(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) -+_overlapped_Overlapped_TransmitFile(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - HANDLE Socket; -@@ -981,7 +981,7 @@ - if (!_PyLong_UnsignedLong_Converter(args[6], &flags)) { - goto exit; - } -- return_value = _overlapped_Overlapped_TransmitFile_impl(self, Socket, File, offset, offset_high, count_to_write, count_per_send, flags); -+ return_value = _overlapped_Overlapped_TransmitFile_impl((OverlappedObject *)self, Socket, File, offset, offset_high, count_to_write, count_per_send, flags); - - exit: - return return_value; -@@ -1001,7 +1001,7 @@ - HANDLE Pipe); - - static PyObject * --_overlapped_Overlapped_ConnectNamedPipe(OverlappedObject *self, PyObject *arg) -+_overlapped_Overlapped_ConnectNamedPipe(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - HANDLE Pipe; -@@ -1010,7 +1010,7 @@ - if (!Pipe && PyErr_Occurred()) { - goto exit; - } -- return_value = _overlapped_Overlapped_ConnectNamedPipe_impl(self, Pipe); -+ return_value = _overlapped_Overlapped_ConnectNamedPipe_impl((OverlappedObject *)self, Pipe); - - exit: - return return_value; -@@ -1030,7 +1030,7 @@ - const wchar_t *Address); - - static PyObject * --_overlapped_Overlapped_ConnectPipe(OverlappedObject *self, PyObject *arg) -+_overlapped_Overlapped_ConnectPipe(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - const wchar_t *Address = NULL; -@@ -1043,7 +1043,7 @@ - if (Address == NULL) { - goto exit; - } -- return_value = _overlapped_Overlapped_ConnectPipe_impl(self, Address); -+ return_value = _overlapped_Overlapped_ConnectPipe_impl((OverlappedObject *)self, Address); - - exit: - /* Cleanup for Address */ -@@ -1105,7 +1105,7 @@ - PyObject *AddressObj); - - static PyObject * --_overlapped_Overlapped_WSASendTo(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) -+_overlapped_Overlapped_WSASendTo(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - HANDLE handle; -@@ -1131,7 +1131,7 @@ - goto exit; - } - AddressObj = args[3]; -- return_value = _overlapped_Overlapped_WSASendTo_impl(self, handle, &bufobj, flags, AddressObj); -+ return_value = _overlapped_Overlapped_WSASendTo_impl((OverlappedObject *)self, handle, &bufobj, flags, AddressObj); - - exit: - /* Cleanup for bufobj */ -@@ -1157,7 +1157,7 @@ - DWORD flags); - - static PyObject * --_overlapped_Overlapped_WSARecvFrom(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) -+_overlapped_Overlapped_WSARecvFrom(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - HANDLE handle; -@@ -1181,7 +1181,7 @@ - goto exit; - } - skip_optional: -- return_value = _overlapped_Overlapped_WSARecvFrom_impl(self, handle, size, flags); -+ return_value = _overlapped_Overlapped_WSARecvFrom_impl((OverlappedObject *)self, handle, size, flags); - - exit: - return return_value; -@@ -1202,7 +1202,7 @@ - DWORD size, DWORD flags); - - static PyObject * --_overlapped_Overlapped_WSARecvFromInto(OverlappedObject *self, PyObject *const *args, Py_ssize_t nargs) -+_overlapped_Overlapped_WSARecvFromInto(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - HANDLE handle; -@@ -1230,7 +1230,7 @@ - goto exit; - } - skip_optional: -- return_value = _overlapped_Overlapped_WSARecvFromInto_impl(self, handle, &bufobj, size, flags); -+ return_value = _overlapped_Overlapped_WSARecvFromInto_impl((OverlappedObject *)self, handle, &bufobj, size, flags); - - exit: - /* Cleanup for bufobj */ -@@ -1240,4 +1240,4 @@ - - return return_value; - } --/*[clinic end generated code: output=14c4f87906f28dc5 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=d009cc9e53d9732a input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h -index 554299b8598..abeb9c3e3e1 100644 ---- a/Modules/clinic/posixmodule.c.h -+++ b/Modules/clinic/posixmodule.c.h -@@ -309,7 +309,7 @@ - return return_value; - } - --#if defined(HAVE_TTYNAME) -+#if defined(HAVE_TTYNAME_R) - - PyDoc_STRVAR(os_ttyname__doc__, - "ttyname($module, fd, /)\n" -@@ -342,7 +342,7 @@ - return return_value; - } - --#endif /* defined(HAVE_TTYNAME) */ -+#endif /* defined(HAVE_TTYNAME_R) */ - - #if defined(HAVE_CTERMID) - -@@ -7577,6 +7577,62 @@ - return return_value; - } - -+PyDoc_STRVAR(os_readinto__doc__, -+"readinto($module, fd, buffer, /)\n" -+"--\n" -+"\n" -+"Read into a buffer object from a file descriptor.\n" -+"\n" -+"The buffer should be mutable and bytes-like. On success, returns the number of\n" -+"bytes read. Less bytes may be read than the size of the buffer. The underlying\n" -+"system call will be retried when interrupted by a signal, unless the signal\n" -+"handler raises an exception. Other errors will not be retried and an error will\n" -+"be raised.\n" -+"\n" -+"Returns 0 if *fd* is at end of file or if the provided *buffer* has length 0\n" -+"(which can be used to check for errors without reading data). Never returns\n" -+"negative."); -+ -+#define OS_READINTO_METHODDEF \ -+ {"readinto", _PyCFunction_CAST(os_readinto), METH_FASTCALL, os_readinto__doc__}, -+ -+static Py_ssize_t -+os_readinto_impl(PyObject *module, int fd, Py_buffer *buffer); -+ -+static PyObject * -+os_readinto(PyObject *module, PyObject *const *args, Py_ssize_t nargs) -+{ -+ PyObject *return_value = NULL; -+ int fd; -+ Py_buffer buffer = {NULL, NULL}; -+ Py_ssize_t _return_value; -+ -+ if (!_PyArg_CheckPositional("readinto", nargs, 2, 2)) { -+ goto exit; -+ } -+ fd = PyLong_AsInt(args[0]); -+ if (fd == -1 && PyErr_Occurred()) { -+ goto exit; -+ } -+ if (PyObject_GetBuffer(args[1], &buffer, PyBUF_WRITABLE) < 0) { -+ _PyArg_BadArgument("readinto", "argument 2", "read-write bytes-like object", args[1]); -+ goto exit; -+ } -+ _return_value = os_readinto_impl(module, fd, &buffer); -+ if ((_return_value == -1) && PyErr_Occurred()) { -+ goto exit; -+ } -+ return_value = PyLong_FromSsize_t(_return_value); -+ -+exit: -+ /* Cleanup for buffer */ -+ if (buffer.obj) { -+ PyBuffer_Release(&buffer); -+ } -+ -+ return return_value; -+} -+ - #if defined(HAVE_READV) - - PyDoc_STRVAR(os_readv__doc__, -@@ -11662,7 +11718,7 @@ - os_DirEntry_is_symlink_impl(DirEntry *self, PyTypeObject *defining_class); - - static PyObject * --os_DirEntry_is_symlink(DirEntry *self, PyTypeObject *defining_class, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+os_DirEntry_is_symlink(PyObject *self, PyTypeObject *defining_class, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - int _return_value; -@@ -11671,7 +11727,7 @@ - PyErr_SetString(PyExc_TypeError, "is_symlink() takes no arguments"); - goto exit; - } -- _return_value = os_DirEntry_is_symlink_impl(self, defining_class); -+ _return_value = os_DirEntry_is_symlink_impl((DirEntry *)self, defining_class); - if ((_return_value == -1) && PyErr_Occurred()) { - goto exit; - } -@@ -11694,12 +11750,12 @@ - os_DirEntry_is_junction_impl(DirEntry *self); - - static PyObject * --os_DirEntry_is_junction(DirEntry *self, PyObject *Py_UNUSED(ignored)) -+os_DirEntry_is_junction(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - int _return_value; - -- _return_value = os_DirEntry_is_junction_impl(self); -+ _return_value = os_DirEntry_is_junction_impl((DirEntry *)self); - if ((_return_value == -1) && PyErr_Occurred()) { - goto exit; - } -@@ -11723,7 +11779,7 @@ - int follow_symlinks); - - static PyObject * --os_DirEntry_stat(DirEntry *self, PyTypeObject *defining_class, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+os_DirEntry_stat(PyObject *self, PyTypeObject *defining_class, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -11768,7 +11824,7 @@ - goto exit; - } - skip_optional_kwonly: -- return_value = os_DirEntry_stat_impl(self, defining_class, follow_symlinks); -+ return_value = os_DirEntry_stat_impl((DirEntry *)self, defining_class, follow_symlinks); - - exit: - return return_value; -@@ -11788,7 +11844,7 @@ - int follow_symlinks); - - static PyObject * --os_DirEntry_is_dir(DirEntry *self, PyTypeObject *defining_class, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+os_DirEntry_is_dir(PyObject *self, PyTypeObject *defining_class, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -11834,7 +11890,7 @@ - goto exit; - } - skip_optional_kwonly: -- _return_value = os_DirEntry_is_dir_impl(self, defining_class, follow_symlinks); -+ _return_value = os_DirEntry_is_dir_impl((DirEntry *)self, defining_class, follow_symlinks); - if ((_return_value == -1) && PyErr_Occurred()) { - goto exit; - } -@@ -11858,7 +11914,7 @@ - int follow_symlinks); - - static PyObject * --os_DirEntry_is_file(DirEntry *self, PyTypeObject *defining_class, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+os_DirEntry_is_file(PyObject *self, PyTypeObject *defining_class, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -11904,7 +11960,7 @@ - goto exit; - } - skip_optional_kwonly: -- _return_value = os_DirEntry_is_file_impl(self, defining_class, follow_symlinks); -+ _return_value = os_DirEntry_is_file_impl((DirEntry *)self, defining_class, follow_symlinks); - if ((_return_value == -1) && PyErr_Occurred()) { - goto exit; - } -@@ -11927,9 +11983,9 @@ - os_DirEntry_inode_impl(DirEntry *self); - - static PyObject * --os_DirEntry_inode(DirEntry *self, PyObject *Py_UNUSED(ignored)) -+os_DirEntry_inode(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return os_DirEntry_inode_impl(self); -+ return os_DirEntry_inode_impl((DirEntry *)self); - } - - PyDoc_STRVAR(os_DirEntry___fspath____doc__, -@@ -11945,9 +12001,9 @@ - os_DirEntry___fspath___impl(DirEntry *self); - - static PyObject * --os_DirEntry___fspath__(DirEntry *self, PyObject *Py_UNUSED(ignored)) -+os_DirEntry___fspath__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return os_DirEntry___fspath___impl(self); -+ return os_DirEntry___fspath___impl((DirEntry *)self); - } - - PyDoc_STRVAR(os_scandir__doc__, -@@ -13140,4 +13196,4 @@ - #ifndef OS__EMSCRIPTEN_DEBUGGER_METHODDEF - #define OS__EMSCRIPTEN_DEBUGGER_METHODDEF - #endif /* !defined(OS__EMSCRIPTEN_DEBUGGER_METHODDEF) */ --/*[clinic end generated code: output=9c2ca1dbf986c62c input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=8318c26fc2cd236c input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/pyexpat.c.h b/Modules/clinic/pyexpat.c.h -index e57aa8a07d7..9eba59731c3 100644 ---- a/Modules/clinic/pyexpat.c.h -+++ b/Modules/clinic/pyexpat.c.h -@@ -22,7 +22,7 @@ - int enabled); - - static PyObject * --pyexpat_xmlparser_SetReparseDeferralEnabled(xmlparseobject *self, PyObject *arg) -+pyexpat_xmlparser_SetReparseDeferralEnabled(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - int enabled; -@@ -31,7 +31,7 @@ - if (enabled < 0) { - goto exit; - } -- return_value = pyexpat_xmlparser_SetReparseDeferralEnabled_impl(self, enabled); -+ return_value = pyexpat_xmlparser_SetReparseDeferralEnabled_impl((xmlparseobject *)self, enabled); - - exit: - return return_value; -@@ -50,9 +50,9 @@ - pyexpat_xmlparser_GetReparseDeferralEnabled_impl(xmlparseobject *self); - - static PyObject * --pyexpat_xmlparser_GetReparseDeferralEnabled(xmlparseobject *self, PyObject *Py_UNUSED(ignored)) -+pyexpat_xmlparser_GetReparseDeferralEnabled(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return pyexpat_xmlparser_GetReparseDeferralEnabled_impl(self); -+ return pyexpat_xmlparser_GetReparseDeferralEnabled_impl((xmlparseobject *)self); - } - - PyDoc_STRVAR(pyexpat_xmlparser_Parse__doc__, -@@ -71,7 +71,7 @@ - PyObject *data, int isfinal); - - static PyObject * --pyexpat_xmlparser_Parse(xmlparseobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+pyexpat_xmlparser_Parse(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -105,7 +105,7 @@ - goto exit; - } - skip_optional_posonly: -- return_value = pyexpat_xmlparser_Parse_impl(self, cls, data, isfinal); -+ return_value = pyexpat_xmlparser_Parse_impl((xmlparseobject *)self, cls, data, isfinal); - - exit: - return return_value; -@@ -125,7 +125,7 @@ - PyObject *file); - - static PyObject * --pyexpat_xmlparser_ParseFile(xmlparseobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+pyexpat_xmlparser_ParseFile(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -150,7 +150,7 @@ - goto exit; - } - file = args[0]; -- return_value = pyexpat_xmlparser_ParseFile_impl(self, cls, file); -+ return_value = pyexpat_xmlparser_ParseFile_impl((xmlparseobject *)self, cls, file); - - exit: - return return_value; -@@ -169,7 +169,7 @@ - pyexpat_xmlparser_SetBase_impl(xmlparseobject *self, const char *base); - - static PyObject * --pyexpat_xmlparser_SetBase(xmlparseobject *self, PyObject *arg) -+pyexpat_xmlparser_SetBase(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - const char *base; -@@ -187,7 +187,7 @@ - PyErr_SetString(PyExc_ValueError, "embedded null character"); - goto exit; - } -- return_value = pyexpat_xmlparser_SetBase_impl(self, base); -+ return_value = pyexpat_xmlparser_SetBase_impl((xmlparseobject *)self, base); - - exit: - return return_value; -@@ -206,9 +206,9 @@ - pyexpat_xmlparser_GetBase_impl(xmlparseobject *self); - - static PyObject * --pyexpat_xmlparser_GetBase(xmlparseobject *self, PyObject *Py_UNUSED(ignored)) -+pyexpat_xmlparser_GetBase(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return pyexpat_xmlparser_GetBase_impl(self); -+ return pyexpat_xmlparser_GetBase_impl((xmlparseobject *)self); - } - - PyDoc_STRVAR(pyexpat_xmlparser_GetInputContext__doc__, -@@ -227,9 +227,9 @@ - pyexpat_xmlparser_GetInputContext_impl(xmlparseobject *self); - - static PyObject * --pyexpat_xmlparser_GetInputContext(xmlparseobject *self, PyObject *Py_UNUSED(ignored)) -+pyexpat_xmlparser_GetInputContext(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return pyexpat_xmlparser_GetInputContext_impl(self); -+ return pyexpat_xmlparser_GetInputContext_impl((xmlparseobject *)self); - } - - PyDoc_STRVAR(pyexpat_xmlparser_ExternalEntityParserCreate__doc__, -@@ -249,7 +249,7 @@ - const char *encoding); - - static PyObject * --pyexpat_xmlparser_ExternalEntityParserCreate(xmlparseobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+pyexpat_xmlparser_ExternalEntityParserCreate(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -309,7 +309,7 @@ - goto exit; - } - skip_optional_posonly: -- return_value = pyexpat_xmlparser_ExternalEntityParserCreate_impl(self, cls, context, encoding); -+ return_value = pyexpat_xmlparser_ExternalEntityParserCreate_impl((xmlparseobject *)self, cls, context, encoding); - - exit: - return return_value; -@@ -333,7 +333,7 @@ - pyexpat_xmlparser_SetParamEntityParsing_impl(xmlparseobject *self, int flag); - - static PyObject * --pyexpat_xmlparser_SetParamEntityParsing(xmlparseobject *self, PyObject *arg) -+pyexpat_xmlparser_SetParamEntityParsing(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - int flag; -@@ -342,7 +342,7 @@ - if (flag == -1 && PyErr_Occurred()) { - goto exit; - } -- return_value = pyexpat_xmlparser_SetParamEntityParsing_impl(self, flag); -+ return_value = pyexpat_xmlparser_SetParamEntityParsing_impl((xmlparseobject *)self, flag); - - exit: - return return_value; -@@ -368,7 +368,7 @@ - int flag); - - static PyObject * --pyexpat_xmlparser_UseForeignDTD(xmlparseobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+pyexpat_xmlparser_UseForeignDTD(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -400,7 +400,7 @@ - goto exit; - } - skip_optional_posonly: -- return_value = pyexpat_xmlparser_UseForeignDTD_impl(self, cls, flag); -+ return_value = pyexpat_xmlparser_UseForeignDTD_impl((xmlparseobject *)self, cls, flag); - - exit: - return return_value; -@@ -550,4 +550,4 @@ - #ifndef PYEXPAT_XMLPARSER_USEFOREIGNDTD_METHODDEF - #define PYEXPAT_XMLPARSER_USEFOREIGNDTD_METHODDEF - #endif /* !defined(PYEXPAT_XMLPARSER_USEFOREIGNDTD_METHODDEF) */ --/*[clinic end generated code: output=63be65cb1823b5f8 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=7ee30ae5b666d0a8 input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/selectmodule.c.h b/Modules/clinic/selectmodule.c.h -index 806a888d6b8..d8bdd6f95f3 100644 ---- a/Modules/clinic/selectmodule.c.h -+++ b/Modules/clinic/selectmodule.c.h -@@ -91,7 +91,7 @@ - select_poll_register_impl(pollObject *self, int fd, unsigned short eventmask); - - static PyObject * --select_poll_register(pollObject *self, PyObject *const *args, Py_ssize_t nargs) -+select_poll_register(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - int fd; -@@ -112,7 +112,7 @@ - } - skip_optional: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = select_poll_register_impl(self, fd, eventmask); -+ return_value = select_poll_register_impl((pollObject *)self, fd, eventmask); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -142,7 +142,7 @@ - select_poll_modify_impl(pollObject *self, int fd, unsigned short eventmask); - - static PyObject * --select_poll_modify(pollObject *self, PyObject *const *args, Py_ssize_t nargs) -+select_poll_modify(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - int fd; -@@ -159,7 +159,7 @@ - goto exit; - } - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = select_poll_modify_impl(self, fd, eventmask); -+ return_value = select_poll_modify_impl((pollObject *)self, fd, eventmask); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -183,7 +183,7 @@ - select_poll_unregister_impl(pollObject *self, int fd); - - static PyObject * --select_poll_unregister(pollObject *self, PyObject *arg) -+select_poll_unregister(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - int fd; -@@ -193,7 +193,7 @@ - goto exit; - } - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = select_poll_unregister_impl(self, fd); -+ return_value = select_poll_unregister_impl((pollObject *)self, fd); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -224,7 +224,7 @@ - select_poll_poll_impl(pollObject *self, PyObject *timeout_obj); - - static PyObject * --select_poll_poll(pollObject *self, PyObject *const *args, Py_ssize_t nargs) -+select_poll_poll(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *timeout_obj = Py_None; -@@ -238,7 +238,7 @@ - timeout_obj = args[0]; - skip_optional: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = select_poll_poll_impl(self, timeout_obj); -+ return_value = select_poll_poll_impl((pollObject *)self, timeout_obj); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -270,7 +270,7 @@ - unsigned short eventmask); - - static PyObject * --select_devpoll_register(devpollObject *self, PyObject *const *args, Py_ssize_t nargs) -+select_devpoll_register(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - int fd; -@@ -291,7 +291,7 @@ - } - skip_optional: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = select_devpoll_register_impl(self, fd, eventmask); -+ return_value = select_devpoll_register_impl((devpollObject *)self, fd, eventmask); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -323,7 +323,7 @@ - unsigned short eventmask); - - static PyObject * --select_devpoll_modify(devpollObject *self, PyObject *const *args, Py_ssize_t nargs) -+select_devpoll_modify(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - int fd; -@@ -344,7 +344,7 @@ - } - skip_optional: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = select_devpoll_modify_impl(self, fd, eventmask); -+ return_value = select_devpoll_modify_impl((devpollObject *)self, fd, eventmask); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -368,7 +368,7 @@ - select_devpoll_unregister_impl(devpollObject *self, int fd); - - static PyObject * --select_devpoll_unregister(devpollObject *self, PyObject *arg) -+select_devpoll_unregister(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - int fd; -@@ -378,7 +378,7 @@ - goto exit; - } - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = select_devpoll_unregister_impl(self, fd); -+ return_value = select_devpoll_unregister_impl((devpollObject *)self, fd); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -409,7 +409,7 @@ - select_devpoll_poll_impl(devpollObject *self, PyObject *timeout_obj); - - static PyObject * --select_devpoll_poll(devpollObject *self, PyObject *const *args, Py_ssize_t nargs) -+select_devpoll_poll(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *timeout_obj = Py_None; -@@ -423,7 +423,7 @@ - timeout_obj = args[0]; - skip_optional: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = select_devpoll_poll_impl(self, timeout_obj); -+ return_value = select_devpoll_poll_impl((devpollObject *)self, timeout_obj); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -449,12 +449,12 @@ - select_devpoll_close_impl(devpollObject *self); - - static PyObject * --select_devpoll_close(devpollObject *self, PyObject *Py_UNUSED(ignored)) -+select_devpoll_close(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = select_devpoll_close_impl(self); -+ return_value = select_devpoll_close_impl((devpollObject *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -477,12 +477,12 @@ - select_devpoll_fileno_impl(devpollObject *self); - - static PyObject * --select_devpoll_fileno(devpollObject *self, PyObject *Py_UNUSED(ignored)) -+select_devpoll_fileno(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = select_devpoll_fileno_impl(self); -+ return_value = select_devpoll_fileno_impl((devpollObject *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -643,12 +643,12 @@ - select_epoll_close_impl(pyEpoll_Object *self); - - static PyObject * --select_epoll_close(pyEpoll_Object *self, PyObject *Py_UNUSED(ignored)) -+select_epoll_close(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = select_epoll_close_impl(self); -+ return_value = select_epoll_close_impl((pyEpoll_Object *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -671,9 +671,9 @@ - select_epoll_fileno_impl(pyEpoll_Object *self); - - static PyObject * --select_epoll_fileno(pyEpoll_Object *self, PyObject *Py_UNUSED(ignored)) -+select_epoll_fileno(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return select_epoll_fileno_impl(self); -+ return select_epoll_fileno_impl((pyEpoll_Object *)self); - } - - #endif /* defined(HAVE_EPOLL) */ -@@ -734,7 +734,7 @@ - unsigned int eventmask); - - static PyObject * --select_epoll_register(pyEpoll_Object *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+select_epoll_register(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -784,7 +784,7 @@ - goto exit; - } - skip_optional_pos: -- return_value = select_epoll_register_impl(self, fd, eventmask); -+ return_value = select_epoll_register_impl((pyEpoll_Object *)self, fd, eventmask); - - exit: - return return_value; -@@ -813,7 +813,7 @@ - unsigned int eventmask); - - static PyObject * --select_epoll_modify(pyEpoll_Object *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+select_epoll_modify(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -858,7 +858,7 @@ - if (eventmask == (unsigned int)-1 && PyErr_Occurred()) { - goto exit; - } -- return_value = select_epoll_modify_impl(self, fd, eventmask); -+ return_value = select_epoll_modify_impl((pyEpoll_Object *)self, fd, eventmask); - - exit: - return return_value; -@@ -884,7 +884,7 @@ - select_epoll_unregister_impl(pyEpoll_Object *self, int fd); - - static PyObject * --select_epoll_unregister(pyEpoll_Object *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+select_epoll_unregister(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -924,7 +924,7 @@ - if (fd < 0) { - goto exit; - } -- return_value = select_epoll_unregister_impl(self, fd); -+ return_value = select_epoll_unregister_impl((pyEpoll_Object *)self, fd); - - exit: - return return_value; -@@ -957,7 +957,7 @@ - int maxevents); - - static PyObject * --select_epoll_poll(pyEpoll_Object *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+select_epoll_poll(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -1009,7 +1009,7 @@ - goto exit; - } - skip_optional_pos: -- return_value = select_epoll_poll_impl(self, timeout_obj, maxevents); -+ return_value = select_epoll_poll_impl((pyEpoll_Object *)self, timeout_obj, maxevents); - - exit: - return return_value; -@@ -1031,9 +1031,9 @@ - select_epoll___enter___impl(pyEpoll_Object *self); - - static PyObject * --select_epoll___enter__(pyEpoll_Object *self, PyObject *Py_UNUSED(ignored)) -+select_epoll___enter__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return select_epoll___enter___impl(self); -+ return select_epoll___enter___impl((pyEpoll_Object *)self); - } - - #endif /* defined(HAVE_EPOLL) */ -@@ -1053,7 +1053,7 @@ - PyObject *exc_value, PyObject *exc_tb); - - static PyObject * --select_epoll___exit__(pyEpoll_Object *self, PyObject *const *args, Py_ssize_t nargs) -+select_epoll___exit__(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *exc_type = Py_None; -@@ -1076,7 +1076,7 @@ - } - exc_tb = args[2]; - skip_optional: -- return_value = select_epoll___exit___impl(self, exc_type, exc_value, exc_tb); -+ return_value = select_epoll___exit___impl((pyEpoll_Object *)self, exc_type, exc_value, exc_tb); - - exit: - return return_value; -@@ -1146,12 +1146,12 @@ - select_kqueue_close_impl(kqueue_queue_Object *self); - - static PyObject * --select_kqueue_close(kqueue_queue_Object *self, PyObject *Py_UNUSED(ignored)) -+select_kqueue_close(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = select_kqueue_close_impl(self); -+ return_value = select_kqueue_close_impl((kqueue_queue_Object *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -1174,9 +1174,9 @@ - select_kqueue_fileno_impl(kqueue_queue_Object *self); - - static PyObject * --select_kqueue_fileno(kqueue_queue_Object *self, PyObject *Py_UNUSED(ignored)) -+select_kqueue_fileno(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return select_kqueue_fileno_impl(self); -+ return select_kqueue_fileno_impl((kqueue_queue_Object *)self); - } - - #endif /* defined(HAVE_KQUEUE) */ -@@ -1238,7 +1238,7 @@ - int maxevents, PyObject *otimeout); - - static PyObject * --select_kqueue_control(kqueue_queue_Object *self, PyObject *const *args, Py_ssize_t nargs) -+select_kqueue_control(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *changelist; -@@ -1258,7 +1258,7 @@ - } - otimeout = args[2]; - skip_optional: -- return_value = select_kqueue_control_impl(self, changelist, maxevents, otimeout); -+ return_value = select_kqueue_control_impl((kqueue_queue_Object *)self, changelist, maxevents, otimeout); - - exit: - return return_value; -@@ -1365,4 +1365,4 @@ - #ifndef SELECT_KQUEUE_CONTROL_METHODDEF - #define SELECT_KQUEUE_CONTROL_METHODDEF - #endif /* !defined(SELECT_KQUEUE_CONTROL_METHODDEF) */ --/*[clinic end generated code: output=78b4e67f7d401b5e input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=c18fd93efc5f4dce input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/sha1module.c.h b/Modules/clinic/sha1module.c.h -index 6af77ba64ec..ddd8e66a41d 100644 ---- a/Modules/clinic/sha1module.c.h -+++ b/Modules/clinic/sha1module.c.h -@@ -21,13 +21,13 @@ - SHA1Type_copy_impl(SHA1object *self, PyTypeObject *cls); - - static PyObject * --SHA1Type_copy(SHA1object *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+SHA1Type_copy(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "copy() takes no arguments"); - return NULL; - } -- return SHA1Type_copy_impl(self, cls); -+ return SHA1Type_copy_impl((SHA1object *)self, cls); - } - - PyDoc_STRVAR(SHA1Type_digest__doc__, -@@ -43,9 +43,9 @@ - SHA1Type_digest_impl(SHA1object *self); - - static PyObject * --SHA1Type_digest(SHA1object *self, PyObject *Py_UNUSED(ignored)) -+SHA1Type_digest(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return SHA1Type_digest_impl(self); -+ return SHA1Type_digest_impl((SHA1object *)self); - } - - PyDoc_STRVAR(SHA1Type_hexdigest__doc__, -@@ -61,9 +61,9 @@ - SHA1Type_hexdigest_impl(SHA1object *self); - - static PyObject * --SHA1Type_hexdigest(SHA1object *self, PyObject *Py_UNUSED(ignored)) -+SHA1Type_hexdigest(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return SHA1Type_hexdigest_impl(self); -+ return SHA1Type_hexdigest_impl((SHA1object *)self); - } - - PyDoc_STRVAR(SHA1Type_update__doc__, -@@ -149,4 +149,4 @@ - exit: - return return_value; - } --/*[clinic end generated code: output=917e2789f1f5ebf9 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=ad6f3788a6e7ff6f input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/sha2module.c.h b/Modules/clinic/sha2module.c.h -index fec655a0dfa..d86f5510d75 100644 ---- a/Modules/clinic/sha2module.c.h -+++ b/Modules/clinic/sha2module.c.h -@@ -21,13 +21,13 @@ - SHA256Type_copy_impl(SHA256object *self, PyTypeObject *cls); - - static PyObject * --SHA256Type_copy(SHA256object *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+SHA256Type_copy(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "copy() takes no arguments"); - return NULL; - } -- return SHA256Type_copy_impl(self, cls); -+ return SHA256Type_copy_impl((SHA256object *)self, cls); - } - - PyDoc_STRVAR(SHA512Type_copy__doc__, -@@ -43,13 +43,13 @@ - SHA512Type_copy_impl(SHA512object *self, PyTypeObject *cls); - - static PyObject * --SHA512Type_copy(SHA512object *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+SHA512Type_copy(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "copy() takes no arguments"); - return NULL; - } -- return SHA512Type_copy_impl(self, cls); -+ return SHA512Type_copy_impl((SHA512object *)self, cls); - } - - PyDoc_STRVAR(SHA256Type_digest__doc__, -@@ -65,9 +65,9 @@ - SHA256Type_digest_impl(SHA256object *self); - - static PyObject * --SHA256Type_digest(SHA256object *self, PyObject *Py_UNUSED(ignored)) -+SHA256Type_digest(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return SHA256Type_digest_impl(self); -+ return SHA256Type_digest_impl((SHA256object *)self); - } - - PyDoc_STRVAR(SHA512Type_digest__doc__, -@@ -83,9 +83,9 @@ - SHA512Type_digest_impl(SHA512object *self); - - static PyObject * --SHA512Type_digest(SHA512object *self, PyObject *Py_UNUSED(ignored)) -+SHA512Type_digest(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return SHA512Type_digest_impl(self); -+ return SHA512Type_digest_impl((SHA512object *)self); - } - - PyDoc_STRVAR(SHA256Type_hexdigest__doc__, -@@ -101,9 +101,9 @@ - SHA256Type_hexdigest_impl(SHA256object *self); - - static PyObject * --SHA256Type_hexdigest(SHA256object *self, PyObject *Py_UNUSED(ignored)) -+SHA256Type_hexdigest(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return SHA256Type_hexdigest_impl(self); -+ return SHA256Type_hexdigest_impl((SHA256object *)self); - } - - PyDoc_STRVAR(SHA512Type_hexdigest__doc__, -@@ -119,9 +119,9 @@ - SHA512Type_hexdigest_impl(SHA512object *self); - - static PyObject * --SHA512Type_hexdigest(SHA512object *self, PyObject *Py_UNUSED(ignored)) -+SHA512Type_hexdigest(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return SHA512Type_hexdigest_impl(self); -+ return SHA512Type_hexdigest_impl((SHA512object *)self); - } - - PyDoc_STRVAR(SHA256Type_update__doc__, -@@ -441,4 +441,4 @@ - exit: - return return_value; - } --/*[clinic end generated code: output=602a6939b8ec0927 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=1d7fec114eb6b6e3 input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/sha3module.c.h b/Modules/clinic/sha3module.c.h -index d9f4b66f81a..729e216ce02 100644 ---- a/Modules/clinic/sha3module.c.h -+++ b/Modules/clinic/sha3module.c.h -@@ -92,9 +92,9 @@ - _sha3_sha3_224_copy_impl(SHA3object *self); - - static PyObject * --_sha3_sha3_224_copy(SHA3object *self, PyObject *Py_UNUSED(ignored)) -+_sha3_sha3_224_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _sha3_sha3_224_copy_impl(self); -+ return _sha3_sha3_224_copy_impl((SHA3object *)self); - } - - PyDoc_STRVAR(_sha3_sha3_224_digest__doc__, -@@ -110,9 +110,9 @@ - _sha3_sha3_224_digest_impl(SHA3object *self); - - static PyObject * --_sha3_sha3_224_digest(SHA3object *self, PyObject *Py_UNUSED(ignored)) -+_sha3_sha3_224_digest(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _sha3_sha3_224_digest_impl(self); -+ return _sha3_sha3_224_digest_impl((SHA3object *)self); - } - - PyDoc_STRVAR(_sha3_sha3_224_hexdigest__doc__, -@@ -128,9 +128,9 @@ - _sha3_sha3_224_hexdigest_impl(SHA3object *self); - - static PyObject * --_sha3_sha3_224_hexdigest(SHA3object *self, PyObject *Py_UNUSED(ignored)) -+_sha3_sha3_224_hexdigest(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _sha3_sha3_224_hexdigest_impl(self); -+ return _sha3_sha3_224_hexdigest_impl((SHA3object *)self); - } - - PyDoc_STRVAR(_sha3_sha3_224_update__doc__, -@@ -155,7 +155,7 @@ - _sha3_shake_128_digest_impl(SHA3object *self, unsigned long length); - - static PyObject * --_sha3_shake_128_digest(SHA3object *self, PyObject *arg) -+_sha3_shake_128_digest(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - unsigned long length; -@@ -163,7 +163,7 @@ - if (!_PyLong_UnsignedLong_Converter(arg, &length)) { - goto exit; - } -- return_value = _sha3_shake_128_digest_impl(self, length); -+ return_value = _sha3_shake_128_digest_impl((SHA3object *)self, length); - - exit: - return return_value; -@@ -182,7 +182,7 @@ - _sha3_shake_128_hexdigest_impl(SHA3object *self, unsigned long length); - - static PyObject * --_sha3_shake_128_hexdigest(SHA3object *self, PyObject *arg) -+_sha3_shake_128_hexdigest(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - unsigned long length; -@@ -190,9 +190,9 @@ - if (!_PyLong_UnsignedLong_Converter(arg, &length)) { - goto exit; - } -- return_value = _sha3_shake_128_hexdigest_impl(self, length); -+ return_value = _sha3_shake_128_hexdigest_impl((SHA3object *)self, length); - - exit: - return return_value; - } --/*[clinic end generated code: output=5c644eb0ed42b993 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=21da06d9570969d8 input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/socketmodule.c.h b/Modules/clinic/socketmodule.c.h -index db1a28b86c8..dc62c4290d3 100644 ---- a/Modules/clinic/socketmodule.c.h -+++ b/Modules/clinic/socketmodule.c.h -@@ -6,7 +6,6 @@ - # include "pycore_gc.h" // PyGC_Head - # include "pycore_runtime.h" // _Py_ID() - #endif --#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() - #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() - - PyDoc_STRVAR(_socket_socket_close__doc__, -@@ -24,15 +23,9 @@ - _socket_socket_close_impl(PySocketSockObject *s); - - static PyObject * --_socket_socket_close(PySocketSockObject *s, PyObject *Py_UNUSED(ignored)) -+_socket_socket_close(PyObject *s, PyObject *Py_UNUSED(ignored)) - { -- PyObject *return_value = NULL; -- -- Py_BEGIN_CRITICAL_SECTION(s); -- return_value = _socket_socket_close_impl(s); -- Py_END_CRITICAL_SECTION(); -- -- return return_value; -+ return _socket_socket_close_impl((PySocketSockObject *)s); - } - - static int -@@ -133,7 +126,7 @@ - _socket_socket_ntohs_impl(PySocketSockObject *self, int x); - - static PyObject * --_socket_socket_ntohs(PySocketSockObject *self, PyObject *arg) -+_socket_socket_ntohs(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - int x; -@@ -142,7 +135,7 @@ - if (x == -1 && PyErr_Occurred()) { - goto exit; - } -- return_value = _socket_socket_ntohs_impl(self, x); -+ return_value = _socket_socket_ntohs_impl((PySocketSockObject *)self, x); - - exit: - return return_value; -@@ -161,7 +154,7 @@ - _socket_socket_htons_impl(PySocketSockObject *self, int x); - - static PyObject * --_socket_socket_htons(PySocketSockObject *self, PyObject *arg) -+_socket_socket_htons(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - int x; -@@ -170,7 +163,7 @@ - if (x == -1 && PyErr_Occurred()) { - goto exit; - } -- return_value = _socket_socket_htons_impl(self, x); -+ return_value = _socket_socket_htons_impl((PySocketSockObject *)self, x); - - exit: - return return_value; -@@ -189,7 +182,7 @@ - _socket_socket_inet_aton_impl(PySocketSockObject *self, const char *ip_addr); - - static PyObject * --_socket_socket_inet_aton(PySocketSockObject *self, PyObject *arg) -+_socket_socket_inet_aton(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - const char *ip_addr; -@@ -207,7 +200,7 @@ - PyErr_SetString(PyExc_ValueError, "embedded null character"); - goto exit; - } -- return_value = _socket_socket_inet_aton_impl(self, ip_addr); -+ return_value = _socket_socket_inet_aton_impl((PySocketSockObject *)self, ip_addr); - - exit: - return return_value; -@@ -228,7 +221,7 @@ - _socket_socket_inet_ntoa_impl(PySocketSockObject *self, Py_buffer *packed_ip); - - static PyObject * --_socket_socket_inet_ntoa(PySocketSockObject *self, PyObject *arg) -+_socket_socket_inet_ntoa(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - Py_buffer packed_ip = {NULL, NULL}; -@@ -236,7 +229,7 @@ - if (PyObject_GetBuffer(arg, &packed_ip, PyBUF_SIMPLE) != 0) { - goto exit; - } -- return_value = _socket_socket_inet_ntoa_impl(self, &packed_ip); -+ return_value = _socket_socket_inet_ntoa_impl((PySocketSockObject *)self, &packed_ip); - - exit: - /* Cleanup for packed_ip */ -@@ -264,7 +257,7 @@ - _socket_socket_if_nametoindex_impl(PySocketSockObject *self, PyObject *oname); - - static PyObject * --_socket_socket_if_nametoindex(PySocketSockObject *self, PyObject *arg) -+_socket_socket_if_nametoindex(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - PyObject *oname; -@@ -272,7 +265,7 @@ - if (!PyUnicode_FSConverter(arg, &oname)) { - goto exit; - } -- return_value = _socket_socket_if_nametoindex_impl(self, oname); -+ return_value = _socket_socket_if_nametoindex_impl((PySocketSockObject *)self, oname); - - exit: - return return_value; -@@ -287,4 +280,4 @@ - #ifndef _SOCKET_SOCKET_IF_NAMETOINDEX_METHODDEF - #define _SOCKET_SOCKET_IF_NAMETOINDEX_METHODDEF - #endif /* !defined(_SOCKET_SOCKET_IF_NAMETOINDEX_METHODDEF) */ --/*[clinic end generated code: output=59c36bb31b05de68 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=d39efc30d811e74b input=a9049054013a1b77]*/ -diff --git a/Modules/clinic/zlibmodule.c.h b/Modules/clinic/zlibmodule.c.h -index 19906dc328d..91a3ac76bcf 100644 ---- a/Modules/clinic/zlibmodule.c.h -+++ b/Modules/clinic/zlibmodule.c.h -@@ -439,7 +439,7 @@ - Py_buffer *data); - - static PyObject * --zlib_Compress_compress(compobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+zlib_Compress_compress(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -466,7 +466,7 @@ - if (PyObject_GetBuffer(args[0], &data, PyBUF_SIMPLE) != 0) { - goto exit; - } -- return_value = zlib_Compress_compress_impl(self, cls, &data); -+ return_value = zlib_Compress_compress_impl((compobject *)self, cls, &data); - - exit: - /* Cleanup for data */ -@@ -502,7 +502,7 @@ - Py_buffer *data, Py_ssize_t max_length); - - static PyObject * --zlib_Decompress_decompress(compobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+zlib_Decompress_decompress(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -559,7 +559,7 @@ - max_length = ival; - } - skip_optional_pos: -- return_value = zlib_Decompress_decompress_impl(self, cls, &data, max_length); -+ return_value = zlib_Decompress_decompress_impl((compobject *)self, cls, &data, max_length); - - exit: - /* Cleanup for data */ -@@ -589,7 +589,7 @@ - zlib_Compress_flush_impl(compobject *self, PyTypeObject *cls, int mode); - - static PyObject * --zlib_Compress_flush(compobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+zlib_Compress_flush(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -621,7 +621,7 @@ - goto exit; - } - skip_optional_posonly: -- return_value = zlib_Compress_flush_impl(self, cls, mode); -+ return_value = zlib_Compress_flush_impl((compobject *)self, cls, mode); - - exit: - return return_value; -@@ -642,13 +642,13 @@ - zlib_Compress_copy_impl(compobject *self, PyTypeObject *cls); - - static PyObject * --zlib_Compress_copy(compobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+zlib_Compress_copy(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "copy() takes no arguments"); - return NULL; - } -- return zlib_Compress_copy_impl(self, cls); -+ return zlib_Compress_copy_impl((compobject *)self, cls); - } - - #endif /* defined(HAVE_ZLIB_COPY) */ -@@ -667,13 +667,13 @@ - zlib_Compress___copy___impl(compobject *self, PyTypeObject *cls); - - static PyObject * --zlib_Compress___copy__(compobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+zlib_Compress___copy__(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "__copy__() takes no arguments"); - return NULL; - } -- return zlib_Compress___copy___impl(self, cls); -+ return zlib_Compress___copy___impl((compobject *)self, cls); - } - - #endif /* defined(HAVE_ZLIB_COPY) */ -@@ -693,7 +693,7 @@ - PyObject *memo); - - static PyObject * --zlib_Compress___deepcopy__(compobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+zlib_Compress___deepcopy__(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -718,7 +718,7 @@ - goto exit; - } - memo = args[0]; -- return_value = zlib_Compress___deepcopy___impl(self, cls, memo); -+ return_value = zlib_Compress___deepcopy___impl((compobject *)self, cls, memo); - - exit: - return return_value; -@@ -741,13 +741,13 @@ - zlib_Decompress_copy_impl(compobject *self, PyTypeObject *cls); - - static PyObject * --zlib_Decompress_copy(compobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+zlib_Decompress_copy(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "copy() takes no arguments"); - return NULL; - } -- return zlib_Decompress_copy_impl(self, cls); -+ return zlib_Decompress_copy_impl((compobject *)self, cls); - } - - #endif /* defined(HAVE_ZLIB_COPY) */ -@@ -766,13 +766,13 @@ - zlib_Decompress___copy___impl(compobject *self, PyTypeObject *cls); - - static PyObject * --zlib_Decompress___copy__(compobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+zlib_Decompress___copy__(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { - PyErr_SetString(PyExc_TypeError, "__copy__() takes no arguments"); - return NULL; - } -- return zlib_Decompress___copy___impl(self, cls); -+ return zlib_Decompress___copy___impl((compobject *)self, cls); - } - - #endif /* defined(HAVE_ZLIB_COPY) */ -@@ -792,7 +792,7 @@ - PyObject *memo); - - static PyObject * --zlib_Decompress___deepcopy__(compobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+zlib_Decompress___deepcopy__(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -817,7 +817,7 @@ - goto exit; - } - memo = args[0]; -- return_value = zlib_Decompress___deepcopy___impl(self, cls, memo); -+ return_value = zlib_Decompress___deepcopy___impl((compobject *)self, cls, memo); - - exit: - return return_value; -@@ -842,7 +842,7 @@ - Py_ssize_t length); - - static PyObject * --zlib_Decompress_flush(compobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+zlib_Decompress_flush(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -882,7 +882,7 @@ - length = ival; - } - skip_optional_posonly: -- return_value = zlib_Decompress_flush_impl(self, cls, length); -+ return_value = zlib_Decompress_flush_impl((compobject *)self, cls, length); - - exit: - return return_value; -@@ -915,7 +915,7 @@ - Py_buffer *data, Py_ssize_t max_length); - - static PyObject * --zlib_ZlibDecompressor_decompress(ZlibDecompressor *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+zlib_ZlibDecompressor_decompress(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -972,7 +972,7 @@ - max_length = ival; - } - skip_optional_pos: -- return_value = zlib_ZlibDecompressor_decompress_impl(self, &data, max_length); -+ return_value = zlib_ZlibDecompressor_decompress_impl((ZlibDecompressor *)self, &data, max_length); - - exit: - /* Cleanup for data */ -@@ -1109,4 +1109,4 @@ - #ifndef ZLIB_DECOMPRESS___DEEPCOPY___METHODDEF - #define ZLIB_DECOMPRESS___DEEPCOPY___METHODDEF - #endif /* !defined(ZLIB_DECOMPRESS___DEEPCOPY___METHODDEF) */ --/*[clinic end generated code: output=2fef49f168842b17 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=969872868c303e8a input=a9049054013a1b77]*/ -diff --git a/Modules/config.c.in b/Modules/config.c.in -index 53b4fb28549..c578cd103dc 100644 ---- a/Modules/config.c.in -+++ b/Modules/config.c.in -@@ -1,13 +1,3 @@ --/* -*- C -*- *********************************************** --Copyright (c) 2000, BeOpen.com. --Copyright (c) 1995-2000, Corporation for National Research Initiatives. --Copyright (c) 1990-1995, Stichting Mathematisch Centrum. --All rights reserved. -- --See the file "Misc/COPYRIGHT" for information on usage and --redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. --******************************************************************/ -- - /* Module configuration */ - - /* !!! !!! !!! This file is edited by the makesetup script !!! !!! !!! */ -diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c -index b62362f2777..a15ced22677 100644 ---- a/Modules/faulthandler.c -+++ b/Modules/faulthandler.c -@@ -1,4 +1,5 @@ - #include "Python.h" -+#include "pycore_ceval.h" // _PyEval_IsGILEnabled - #include "pycore_initconfig.h" // _PyStatus_ERR - #include "pycore_pyerrors.h" // _Py_DumpExtensionModules - #include "pycore_pystate.h" // _PyThreadState_GET() -@@ -27,6 +28,8 @@ - # include // getauxval() - #endif - -+/* Sentinel to ignore all_threads on free-threading */ -+#define FT_IGNORE_ALL_THREADS 2 - - /* Allocate at maximum 100 MiB of the stack to raise the stack overflow */ - #define STACK_OVERFLOW_MAX_SIZE (100 * 1024 * 1024) -@@ -201,10 +204,13 @@ - PyGILState_GetThisThreadState(). */ - PyThreadState *tstate = PyGILState_GetThisThreadState(); - -- if (all_threads) { -+ if (all_threads == 1) { - (void)_Py_DumpTracebackThreads(fd, NULL, tstate); - } - else { -+ if (all_threads == FT_IGNORE_ALL_THREADS) { -+ PUTS(fd, "\n"); -+ } - if (tstate != NULL) - _Py_DumpTraceback(fd, tstate); - } -@@ -237,7 +243,12 @@ - return NULL; - - if (all_threads) { -+ PyInterpreterState *interp = _PyInterpreterState_GET(); -+ /* gh-128400: Accessing other thread states while they're running -+ * isn't safe if those threads are running. */ -+ _PyEval_StopTheWorld(interp); - errmsg = _Py_DumpTracebackThreads(fd, NULL, tstate); -+ _PyEval_StartTheWorld(interp); - if (errmsg != NULL) { - PyErr_SetString(PyExc_RuntimeError, errmsg); - return NULL; -@@ -266,6 +277,27 @@ - #endif - } - -+static int -+deduce_all_threads(void) -+{ -+#ifndef Py_GIL_DISABLED -+ return fatal_error.all_threads; -+#else -+ if (fatal_error.all_threads == 0) { -+ return 0; -+ } -+ // We can't use _PyThreadState_GET, so use the stored GILstate one -+ PyThreadState *tstate = PyGILState_GetThisThreadState(); -+ if (tstate == NULL) { -+ return 0; -+ } -+ -+ /* In theory, it's safe to dump all threads if the GIL is enabled */ -+ return _PyEval_IsGILEnabled(tstate) -+ ? fatal_error.all_threads -+ : FT_IGNORE_ALL_THREADS; -+#endif -+} - - /* Handler for SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL signals. - -@@ -320,7 +352,7 @@ - PUTS(fd, "\n\n"); - } - -- faulthandler_dump_traceback(fd, fatal_error.all_threads, -+ faulthandler_dump_traceback(fd, deduce_all_threads(), - fatal_error.interp); - - _Py_DumpExtensionModules(fd, fatal_error.interp); -@@ -396,7 +428,7 @@ - } - } - -- faulthandler_dump_traceback(fd, fatal_error.all_threads, -+ faulthandler_dump_traceback(fd, deduce_all_threads(), - fatal_error.interp); - - /* call the next exception handler */ -@@ -1314,7 +1346,7 @@ - static int - faulthandler_init_enable(void) - { -- PyObject *enable = _PyImport_GetModuleAttrString("faulthandler", "enable"); -+ PyObject *enable = PyImport_ImportModuleAttrString("faulthandler", "enable"); - if (enable == NULL) { - return -1; - } -diff --git a/Modules/getpath.c b/Modules/getpath.c -index 18ddfaf8dbc..e2478da021f 100644 ---- a/Modules/getpath.c -+++ b/Modules/getpath.c -@@ -17,10 +17,13 @@ - #endif - - #ifdef __APPLE__ --# include - # include - #endif - -+#ifdef HAVE_DLFCN_H -+# include -+#endif -+ - /* Reference the precompiled getpath.py */ - #include "Python/frozen_modules/getpath.h" - -@@ -803,36 +806,25 @@ - static int - library_to_dict(PyObject *dict, const char *key) - { -+/* macOS framework builds do not link against a libpython dynamic library, but -+ instead link against a macOS Framework. */ -+#if defined(Py_ENABLE_SHARED) || defined(WITH_NEXT_FRAMEWORK) -+ - #ifdef MS_WINDOWS --#ifdef Py_ENABLE_SHARED - extern HMODULE PyWin_DLLhModule; - if (PyWin_DLLhModule) { - return winmodule_to_dict(dict, key, PyWin_DLLhModule); - } - #endif --#elif defined(WITH_NEXT_FRAMEWORK) -- static char modPath[MAXPATHLEN + 1]; -- static int modPathInitialized = -1; -- if (modPathInitialized < 0) { -- modPathInitialized = 0; -- -- /* On Mac OS X we have a special case if we're running from a framework. -- This is because the python home should be set relative to the library, -- which is in the framework, not relative to the executable, which may -- be outside of the framework. Except when we're in the build -- directory... */ -- Dl_info pythonInfo; -- if (dladdr(&Py_Initialize, &pythonInfo)) { -- if (pythonInfo.dli_fname) { -- strncpy(modPath, pythonInfo.dli_fname, MAXPATHLEN); -- modPathInitialized = 1; -- } -- } -- } -- if (modPathInitialized > 0) { -- return decode_to_dict(dict, key, modPath); -+ -+#if HAVE_DLADDR -+ Dl_info libpython_info; -+ if (dladdr(&Py_Initialize, &libpython_info) && libpython_info.dli_fname) { -+ return decode_to_dict(dict, key, libpython_info.dli_fname); - } - #endif -+#endif -+ - return PyDict_SetItemString(dict, key, Py_None) == 0; - } - -@@ -963,7 +955,7 @@ - ) { - Py_DECREF(co); - Py_DECREF(dict); -- PyErr_FormatUnraisable("Exception ignored in preparing getpath"); -+ PyErr_FormatUnraisable("Exception ignored while preparing getpath"); - return PyStatus_Error("error evaluating initial values"); - } - -@@ -972,13 +964,13 @@ - - if (!r) { - Py_DECREF(dict); -- PyErr_FormatUnraisable("Exception ignored in running getpath"); -+ PyErr_FormatUnraisable("Exception ignored while running getpath"); - return PyStatus_Error("error evaluating path"); - } - Py_DECREF(r); - - if (_PyConfig_FromDict(config, configDict) < 0) { -- PyErr_FormatUnraisable("Exception ignored in reading getpath results"); -+ PyErr_FormatUnraisable("Exception ignored while reading getpath results"); - Py_DECREF(dict); - return PyStatus_Error("error getting getpath results"); - } -diff --git a/Modules/getpath.py b/Modules/getpath.py -index c34101e7208..be2210345af 100644 ---- a/Modules/getpath.py -+++ b/Modules/getpath.py -@@ -625,6 +625,8 @@ - # gh-100320: Our PYDs are assumed to be relative to the Lib directory - # (that is, prefix) rather than the executable (that is, executable_dir) - exec_prefix = prefix -+ if not exec_prefix and prefix and isdir(joinpath(prefix, PLATSTDLIB_LANDMARK)): -+ exec_prefix = prefix - if not exec_prefix and executable_dir: - exec_prefix = search_up(executable_dir, PLATSTDLIB_LANDMARK, test=isdir) - if not exec_prefix and EXEC_PREFIX: -diff --git a/Modules/main.c b/Modules/main.c -index 15ea49a1bad..f8a2438cdd0 100644 ---- a/Modules/main.c -+++ b/Modules/main.c -@@ -314,25 +314,19 @@ - static int - pymain_run_module(const wchar_t *modname, int set_argv0) - { -- PyObject *module, *runpy, *runmodule, *runargs, *result; -+ PyObject *module, *runmodule, *runargs, *result; - if (PySys_Audit("cpython.run_module", "u", modname) < 0) { - return pymain_exit_err_print(); - } -- runpy = PyImport_ImportModule("runpy"); -- if (runpy == NULL) { -- fprintf(stderr, "Could not import runpy module\n"); -- return pymain_exit_err_print(); -- } -- runmodule = PyObject_GetAttrString(runpy, "_run_module_as_main"); -+ runmodule = PyImport_ImportModuleAttrString("runpy", -+ "_run_module_as_main"); - if (runmodule == NULL) { -- fprintf(stderr, "Could not access runpy._run_module_as_main\n"); -- Py_DECREF(runpy); -+ fprintf(stderr, "Could not import runpy._run_module_as_main\n"); - return pymain_exit_err_print(); - } - module = PyUnicode_FromWideChar(modname, wcslen(modname)); - if (module == NULL) { - fprintf(stderr, "Could not convert module name to unicode\n"); -- Py_DECREF(runpy); - Py_DECREF(runmodule); - return pymain_exit_err_print(); - } -@@ -340,7 +334,6 @@ - if (runargs == NULL) { - fprintf(stderr, - "Could not create arguments for runpy._run_module_as_main\n"); -- Py_DECREF(runpy); - Py_DECREF(runmodule); - Py_DECREF(module); - return pymain_exit_err_print(); -@@ -350,7 +343,6 @@ - if (!result && PyErr_Occurred() == PyExc_KeyboardInterrupt) { - _PyRuntime.signals.unhandled_keyboard_interrupt = 1; - } -- Py_DECREF(runpy); - Py_DECREF(runmodule); - Py_DECREF(module); - Py_DECREF(runargs); -@@ -370,10 +362,11 @@ - return pymain_exit_err_print(); - } - -- FILE *fp = _Py_fopen_obj(filename, "rb"); -+ FILE *fp = Py_fopen(filename, "rb"); - if (fp == NULL) { - // Ignore the OSError - PyErr_Clear(); -+ // TODO(picnixz): strerror() is locale dependent but not PySys_FormatStderr(). - PySys_FormatStderr("%S: can't open file %R: [Errno %d] %s\n", - program_name, filename, errno, strerror(errno)); - return 2; -@@ -464,7 +457,7 @@ - goto error; - } - -- FILE *fp = _Py_fopen_obj(startup, "r"); -+ FILE *fp = Py_fopen(startup, "r"); - if (fp == NULL) { - int save_errno = errno; - PyErr_Clear(); -@@ -496,24 +489,22 @@ - static int - pymain_run_interactive_hook(int *exitcode) - { -- PyObject *sys, *hook, *result; -- sys = PyImport_ImportModule("sys"); -- if (sys == NULL) { -- goto error; -- } -- -- hook = PyObject_GetAttrString(sys, "__interactivehook__"); -- Py_DECREF(sys); -+ PyObject *hook = PyImport_ImportModuleAttrString("sys", -+ "__interactivehook__"); - if (hook == NULL) { -- PyErr_Clear(); -- return 0; -+ if (PyErr_ExceptionMatches(PyExc_AttributeError)) { -+ // no sys.__interactivehook__ attribute -+ PyErr_Clear(); -+ return 0; -+ } -+ goto error; - } - - if (PySys_Audit("cpython.run_interactivehook", "O", hook) < 0) { - goto error; - } - -- result = _PyObject_CallNoArgs(hook); -+ PyObject *result = _PyObject_CallNoArgs(hook); - Py_DECREF(hook); - if (result == NULL) { - goto error; -diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c -index 29638114dd9..b4c15a143f9 100644 ---- a/Modules/mathmodule.c -+++ b/Modules/mathmodule.c -@@ -858,12 +858,15 @@ - * true (1), but may return false (0) without setting up an exception. - */ - static int --is_error(double x) -+is_error(double x, int raise_edom) - { - int result = 1; /* presumption of guilt */ - assert(errno); /* non-zero errno is a precondition for calling */ -- if (errno == EDOM) -- PyErr_SetString(PyExc_ValueError, "math domain error"); -+ if (errno == EDOM) { -+ if (raise_edom) { -+ PyErr_SetString(PyExc_ValueError, "math domain error"); -+ } -+ } - - else if (errno == ERANGE) { - /* ANSI C generally requires libm functions to set ERANGE -@@ -928,7 +931,8 @@ - */ - - static PyObject * --math_1(PyObject *arg, double (*func) (double), int can_overflow) -+math_1(PyObject *arg, double (*func) (double), int can_overflow, -+ const char *err_msg) - { - double x, r; - x = PyFloat_AsDouble(arg); -@@ -936,25 +940,34 @@ - return NULL; - errno = 0; - r = (*func)(x); -- if (isnan(r) && !isnan(x)) { -- PyErr_SetString(PyExc_ValueError, -- "math domain error"); /* invalid arg */ -- return NULL; -- } -+ if (isnan(r) && !isnan(x)) -+ goto domain_err; /* domain error */ - if (isinf(r) && isfinite(x)) { - if (can_overflow) - PyErr_SetString(PyExc_OverflowError, - "math range error"); /* overflow */ - else -- PyErr_SetString(PyExc_ValueError, -- "math domain error"); /* singularity */ -+ goto domain_err; /* singularity */ - return NULL; - } -- if (isfinite(r) && errno && is_error(r)) -+ if (isfinite(r) && errno && is_error(r, 1)) - /* this branch unnecessary on most platforms */ - return NULL; - - return PyFloat_FromDouble(r); -+ -+domain_err: -+ if (err_msg) { -+ char *buf = PyOS_double_to_string(x, 'r', 0, Py_DTSF_ADD_DOT_0, NULL); -+ if (buf) { -+ PyErr_Format(PyExc_ValueError, err_msg, buf); -+ PyMem_Free(buf); -+ } -+ } -+ else { -+ PyErr_SetString(PyExc_ValueError, "math domain error"); -+ } -+ return NULL; - } - - /* variant of math_1, to be used when the function being wrapped is known to -@@ -962,7 +975,7 @@ - errno = ERANGE for overflow). */ - - static PyObject * --math_1a(PyObject *arg, double (*func) (double)) -+math_1a(PyObject *arg, double (*func) (double), const char *err_msg) - { - double x, r; - x = PyFloat_AsDouble(arg); -@@ -970,8 +983,17 @@ - return NULL; - errno = 0; - r = (*func)(x); -- if (errno && is_error(r)) -+ if (errno && is_error(r, err_msg ? 0 : 1)) { -+ if (err_msg && errno == EDOM) { -+ assert(!PyErr_Occurred()); /* exception is not set by is_error() */ -+ char *buf = PyOS_double_to_string(x, 'r', 0, Py_DTSF_ADD_DOT_0, NULL); -+ if (buf) { -+ PyErr_Format(PyExc_ValueError, err_msg, buf); -+ PyMem_Free(buf); -+ } -+ } - return NULL; -+ } - return PyFloat_FromDouble(r); - } - -@@ -1031,7 +1053,7 @@ - else - errno = 0; - } -- if (errno && is_error(r)) -+ if (errno && is_error(r, 1)) - return NULL; - else - return PyFloat_FromDouble(r); -@@ -1039,13 +1061,25 @@ - - #define FUNC1(funcname, func, can_overflow, docstring) \ - static PyObject * math_##funcname(PyObject *self, PyObject *args) { \ -- return math_1(args, func, can_overflow); \ -+ return math_1(args, func, can_overflow, NULL); \ -+ }\ -+ PyDoc_STRVAR(math_##funcname##_doc, docstring); -+ -+#define FUNC1D(funcname, func, can_overflow, docstring, err_msg) \ -+ static PyObject * math_##funcname(PyObject *self, PyObject *args) { \ -+ return math_1(args, func, can_overflow, err_msg); \ - }\ - PyDoc_STRVAR(math_##funcname##_doc, docstring); - - #define FUNC1A(funcname, func, docstring) \ - static PyObject * math_##funcname(PyObject *self, PyObject *args) { \ -- return math_1a(args, func); \ -+ return math_1a(args, func, NULL); \ -+ }\ -+ PyDoc_STRVAR(math_##funcname##_doc, docstring); -+ -+#define FUNC1AD(funcname, func, docstring, err_msg) \ -+ static PyObject * math_##funcname(PyObject *self, PyObject *args) { \ -+ return math_1a(args, func, err_msg); \ - }\ - PyDoc_STRVAR(math_##funcname##_doc, docstring); - -@@ -1077,9 +1111,10 @@ - "atan2($module, y, x, /)\n--\n\n" - "Return the arc tangent (measured in radians) of y/x.\n\n" - "Unlike atan(y/x), the signs of both x and y are considered.") --FUNC1(atanh, atanh, 0, -+FUNC1D(atanh, atanh, 0, - "atanh($module, x, /)\n--\n\n" -- "Return the inverse hyperbolic tangent of x.") -+ "Return the inverse hyperbolic tangent of x.", -+ "expected a number between -1 and 1, got %s") - FUNC1(cbrt, cbrt, 0, - "cbrt($module, x, /)\n--\n\n" - "Return the cube root of x.") -@@ -1190,9 +1225,10 @@ - return PyLong_FromDouble(floor(x)); - } - --FUNC1A(gamma, m_tgamma, -+FUNC1AD(gamma, m_tgamma, - "gamma($module, x, /)\n--\n\n" -- "Gamma function at x.") -+ "Gamma function at x.", -+ "expected a float or nonnegative integer, got %s") - FUNC1A(lgamma, m_lgamma, - "lgamma($module, x, /)\n--\n\n" - "Natural logarithm of absolute value of Gamma function at x.") -@@ -1212,9 +1248,10 @@ - FUNC1(sinh, sinh, 1, - "sinh($module, x, /)\n--\n\n" - "Return the hyperbolic sine of x.") --FUNC1(sqrt, sqrt, 0, -+FUNC1D(sqrt, sqrt, 0, - "sqrt($module, x, /)\n--\n\n" -- "Return the square root of x.") -+ "Return the square root of x.", -+ "expected a nonnegative input, got %s") - FUNC1(tan, tan, 0, - "tan($module, x, /)\n--\n\n" - "Return the tangent of x (measured in radians).") -@@ -2141,7 +2178,7 @@ - errno = ERANGE; - } - -- if (errno && is_error(r)) -+ if (errno && is_error(r, 1)) - return NULL; - return PyFloat_FromDouble(r); - } -@@ -2195,8 +2232,8 @@ - - /* Negative or zero inputs give a ValueError. */ - if (!_PyLong_IsPositive((PyLongObject *)arg)) { -- PyErr_SetString(PyExc_ValueError, -- "math domain error"); -+ PyErr_Format(PyExc_ValueError, -+ "expected a positive input, got %S", arg); - return NULL; - } - -@@ -2220,7 +2257,7 @@ - } - - /* Else let libm handle it by itself. */ -- return math_1(arg, func, 0); -+ return math_1(arg, func, 0, "expected a positive input, got %s"); - } - - -@@ -2369,7 +2406,7 @@ - else - errno = 0; - } -- if (errno && is_error(r)) -+ if (errno && is_error(r, 1)) - return NULL; - else - return PyFloat_FromDouble(r); -@@ -3010,7 +3047,7 @@ - } - } - -- if (errno && is_error(r)) -+ if (errno && is_error(r, 1)) - return NULL; - else - return PyFloat_FromDouble(r); -diff --git a/Modules/md5module.c b/Modules/md5module.c -index ef9163e8be5..d86c8e55501 100644 ---- a/Modules/md5module.c -+++ b/Modules/md5module.c -@@ -54,6 +54,8 @@ - Hacl_Hash_MD5_state_t *hash_state; - } MD5object; - -+#define _MD5object_CAST(op) ((MD5object *)(op)) -+ - #include "clinic/md5module.c.h" - - -@@ -72,7 +74,7 @@ - static MD5object * - newMD5object(MD5State * st) - { -- MD5object *md5 = (MD5object *)PyObject_GC_New(MD5object, st->md5_type); -+ MD5object *md5 = PyObject_GC_New(MD5object, st->md5_type); - if (!md5) { - return NULL; - } -@@ -91,10 +93,11 @@ - } - - static void --MD5_dealloc(MD5object *ptr) -+MD5_dealloc(PyObject *op) - { -+ MD5object *ptr = _MD5object_CAST(op); - Hacl_Hash_MD5_free(ptr->hash_state); -- PyTypeObject *tp = Py_TYPE((PyObject*)ptr); -+ PyTypeObject *tp = Py_TYPE(op); - PyObject_GC_UnTrack(ptr); - PyObject_GC_Del(ptr); - Py_DECREF(tp); -@@ -224,36 +227,27 @@ - }; - - static PyObject * --MD5_get_block_size(PyObject *self, void *closure) -+MD5_get_block_size(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) - { - return PyLong_FromLong(MD5_BLOCKSIZE); - } - - static PyObject * --MD5_get_name(PyObject *self, void *closure) -+MD5_get_name(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) - { - return PyUnicode_FromStringAndSize("md5", 3); - } - - static PyObject * --md5_get_digest_size(PyObject *self, void *closure) -+md5_get_digest_size(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) - { - return PyLong_FromLong(MD5_DIGESTSIZE); - } - - static PyGetSetDef MD5_getseters[] = { -- {"block_size", -- (getter)MD5_get_block_size, NULL, -- NULL, -- NULL}, -- {"name", -- (getter)MD5_get_name, NULL, -- NULL, -- NULL}, -- {"digest_size", -- (getter)md5_get_digest_size, NULL, -- NULL, -- NULL}, -+ {"block_size", MD5_get_block_size, NULL, NULL, NULL}, -+ {"name", MD5_get_name, NULL, NULL, NULL}, -+ {"digest_size", md5_get_digest_size, NULL, NULL, NULL}, - {NULL} /* Sentinel */ - }; - -diff --git a/Modules/overlapped.c b/Modules/overlapped.c -index 308a0dab7fa..806ebee7a70 100644 ---- a/Modules/overlapped.c -+++ b/Modules/overlapped.c -@@ -759,7 +759,8 @@ - PyExc_RuntimeError, - "%R still has pending operation at " - "deallocation, the process may crash", self); -- PyErr_WriteUnraisable(NULL); -+ PyErr_FormatUnraisable("Exception ignored while deallocating " -+ "overlapped operation %R", self); - } - } - -diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c -index 2045c6065b8..6dfe73017ab 100644 ---- a/Modules/posixmodule.c -+++ b/Modules/posixmodule.c -@@ -7,6 +7,8 @@ - of the compiler used. Different compilers define their own feature - test macro, e.g. '_MSC_VER'. */ - -+// --- Python includes ------------------------------------------------------ -+ - #include "Python.h" - - #ifdef __VXWORKS__ -@@ -26,255 +28,63 @@ - #include "pycore_time.h" // _PyLong_FromTime_t() - #include "pycore_typeobject.h" // _PyType_AddMethod() - --#ifdef HAVE_UNISTD_H --# include // symlink() --#endif -- --#ifdef MS_WINDOWS --# include --# if !defined(MS_WINDOWS_GAMES) || defined(MS_WINDOWS_DESKTOP) --# include --# endif --# include --# include // UNLEN --# include "osdefs.h" // SEP --# include // SetEntriesInAcl --# include // SDDL_REVISION_1 --# if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) --# define HAVE_SYMLINK --# endif /* MS_WINDOWS_DESKTOP | MS_WINDOWS_SYSTEM */ --#endif -- - #ifndef MS_WINDOWS --# include "posixmodule.h" -+# include "posixmodule.h" // _PyLong_FromUid() - #else --# include "pycore_fileutils_windows.h" --# include "winreparse.h" -+# include "pycore_fileutils_windows.h" // _Py_GetFileInformationByName() -+# include "osdefs.h" // SEP -+# include "winreparse.h" // _Py_REPARSE_DATA_BUFFER - #endif - --#if !defined(EX_OK) && defined(EXIT_SUCCESS) --# define EX_OK EXIT_SUCCESS -+ -+// --- System includes ------------------------------------------------------ -+ -+#include // ctermid() -+#include // system() -+ -+#ifdef HAVE_UNISTD_H -+# include // symlink() - #endif - - #ifdef __APPLE__ -- /* Needed for the implementation of os.statvfs */ -+ /* Needed for the implementation of os.statvfs */ - # include - # include - #endif - --/* On android API level 21, 'AT_EACCESS' is not declared although -- * HAVE_FACCESSAT is defined. */ --#ifdef __ANDROID__ --# undef HAVE_FACCESSAT --#endif -- --#include // ctermid() --#include // system() - #ifdef HAVE_SYS_TIME_H - # include // futimes() - #endif -+ - #ifdef HAVE_SYS_PIDFD_H - # include // PIDFD_NONBLOCK - #endif - -- --// SGI apparently needs this forward declaration --#ifdef HAVE__GETPTY --# include // mode_t -- extern char * _getpty(int *, int, mode_t, int); --#endif -- - #ifdef __EMSCRIPTEN__ --#include "emscripten.h" // emscripten_debugger() --#endif -- --/* -- * A number of APIs are available on macOS from a certain macOS version. -- * To support building with a new SDK while deploying to older versions -- * the availability test is split into two: -- * - HAVE_: The configure check for compile time availability -- * - HAVE__RUNTIME: Runtime check for availability -- * -- * The latter is always true when not on macOS, or when using a compiler -- * that does not support __has_builtin (older versions of Xcode). -- * -- * Due to compiler restrictions there is one valid use of HAVE__RUNTIME: -- * if (HAVE__RUNTIME) { ... } -- * -- * In mixing the test with other tests or using negations will result in compile -- * errors. -- */ --#if defined(__APPLE__) -- --#include -- --#if defined(__has_builtin) --#if __has_builtin(__builtin_available) --#define HAVE_BUILTIN_AVAILABLE 1 --#endif --#endif -- --#ifdef HAVE_BUILTIN_AVAILABLE --# define HAVE_FSTATAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) --# define HAVE_FACCESSAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) --# define HAVE_FCHMODAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) --# define HAVE_FCHOWNAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) --# define HAVE_LINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) --# define HAVE_FDOPENDIR_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) --# define HAVE_MKDIRAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) --# define HAVE_RENAMEAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) --# define HAVE_UNLINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) --# define HAVE_OPENAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) --# define HAVE_READLINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) --# define HAVE_SYMLINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) --# define HAVE_FUTIMENS_RUNTIME __builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *) --# define HAVE_UTIMENSAT_RUNTIME __builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *) --# define HAVE_PWRITEV_RUNTIME __builtin_available(macOS 11.0, iOS 14.0, tvOS 14.0, watchOS 7.0, *) --# define HAVE_MKFIFOAT_RUNTIME __builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) --# define HAVE_MKNODAT_RUNTIME __builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) --# define HAVE_PTSNAME_R_RUNTIME __builtin_available(macOS 10.13.4, iOS 11.3, tvOS 11.3, watchOS 4.3, *) -- --# define HAVE_POSIX_SPAWN_SETSID_RUNTIME __builtin_available(macOS 10.15, *) -- --#else /* Xcode 8 or earlier */ -- -- /* __builtin_available is not present in these compilers, but -- * some of the symbols might be weak linked (10.10 SDK or later -- * deploying on 10.9. -- * -- * Fall back to the older style of availability checking for -- * symbols introduced in macOS 10.10. -- */ -- --# ifdef HAVE_FSTATAT --# define HAVE_FSTATAT_RUNTIME (fstatat != NULL) --# endif -- --# ifdef HAVE_FACCESSAT --# define HAVE_FACCESSAT_RUNTIME (faccessat != NULL) --# endif -- --# ifdef HAVE_FCHMODAT --# define HAVE_FCHMODAT_RUNTIME (fchmodat != NULL) --# endif -- --# ifdef HAVE_FCHOWNAT --# define HAVE_FCHOWNAT_RUNTIME (fchownat != NULL) --# endif -- --# ifdef HAVE_LINKAT --# define HAVE_LINKAT_RUNTIME (linkat != NULL) --# endif -- --# ifdef HAVE_FDOPENDIR --# define HAVE_FDOPENDIR_RUNTIME (fdopendir != NULL) --# endif -- --# ifdef HAVE_MKDIRAT --# define HAVE_MKDIRAT_RUNTIME (mkdirat != NULL) --# endif -- --# ifdef HAVE_RENAMEAT --# define HAVE_RENAMEAT_RUNTIME (renameat != NULL) --# endif -- --# ifdef HAVE_UNLINKAT --# define HAVE_UNLINKAT_RUNTIME (unlinkat != NULL) --# endif -- --# ifdef HAVE_OPENAT --# define HAVE_OPENAT_RUNTIME (openat != NULL) --# endif -- --# ifdef HAVE_READLINKAT --# define HAVE_READLINKAT_RUNTIME (readlinkat != NULL) --# endif -- --# ifdef HAVE_SYMLINKAT --# define HAVE_SYMLINKAT_RUNTIME (symlinkat != NULL) --# endif -- --# ifdef HAVE_UTIMENSAT --# define HAVE_UTIMENSAT_RUNTIME (utimensat != NULL) --# endif -- --# ifdef HAVE_FUTIMENS --# define HAVE_FUTIMENS_RUNTIME (futimens != NULL) --# endif -- --# ifdef HAVE_PWRITEV --# define HAVE_PWRITEV_RUNTIME (pwritev != NULL) --# endif -- --# ifdef HAVE_MKFIFOAT --# define HAVE_MKFIFOAT_RUNTIME (mkfifoat != NULL) --# endif -- --# ifdef HAVE_MKNODAT --# define HAVE_MKNODAT_RUNTIME (mknodat != NULL) --# endif -- --# ifdef HAVE_PTSNAME_R --# define HAVE_PTSNAME_R_RUNTIME (ptsname_r != NULL) --# endif -- --#endif -- --#ifdef HAVE_FUTIMESAT --/* Some of the logic for weak linking depends on this assertion */ --# error "HAVE_FUTIMESAT unexpectedly defined" -+# include "emscripten.h" // emscripten_debugger() - #endif - --#else --# define HAVE_FSTATAT_RUNTIME 1 --# define HAVE_FACCESSAT_RUNTIME 1 --# define HAVE_FCHMODAT_RUNTIME 1 --# define HAVE_FCHOWNAT_RUNTIME 1 --# define HAVE_LINKAT_RUNTIME 1 --# define HAVE_FDOPENDIR_RUNTIME 1 --# define HAVE_MKDIRAT_RUNTIME 1 --# define HAVE_RENAMEAT_RUNTIME 1 --# define HAVE_UNLINKAT_RUNTIME 1 --# define HAVE_OPENAT_RUNTIME 1 --# define HAVE_READLINKAT_RUNTIME 1 --# define HAVE_SYMLINKAT_RUNTIME 1 --# define HAVE_FUTIMENS_RUNTIME 1 --# define HAVE_UTIMENSAT_RUNTIME 1 --# define HAVE_PWRITEV_RUNTIME 1 --# define HAVE_MKFIFOAT_RUNTIME 1 --# define HAVE_MKNODAT_RUNTIME 1 --# define HAVE_PTSNAME_R_RUNTIME 1 --#endif -- -- --PyDoc_STRVAR(posix__doc__, --"This module provides access to operating system functionality that is\n\ --standardized by the C Standard and the POSIX standard (a thinly\n\ --disguised Unix interface). Refer to the library manual and\n\ --corresponding Unix manual entries for more information on calls."); -- -- - #ifdef HAVE_SYS_UIO_H - # include - #endif - - #ifdef HAVE_SYS_TYPES_H --/* Should be included before on HP-UX v3 */ -+ /* Should be included before on HP-UX v3 */ - # include --#endif /* HAVE_SYS_TYPES_H */ -- -+#endif - #ifdef HAVE_SYS_SYSMACROS_H --/* GNU C Library: major(), minor(), makedev() */ -+ /* GNU C Library: major(), minor(), makedev() */ - # include - #endif - - #ifdef HAVE_SYS_STAT_H - # include --#endif /* HAVE_SYS_STAT_H */ -+#endif - - #ifdef HAVE_SYS_WAIT_H - # include // WNOHANG - #endif -+ - #ifdef HAVE_LINUX_WAIT_H - # include // P_PIDFD - #endif -@@ -284,50 +94,34 @@ - #endif - - #ifdef HAVE_FCNTL_H --# include -+# include // fcntl() - #endif - - #ifdef HAVE_GRP_H --# include -+# include // setgroups() - #endif - - #ifdef HAVE_SYSEXITS_H --# include -+# include // EX_OK - #endif - - #ifdef HAVE_SYS_LOADAVG_H --# include -+# include // getloadavg() - #endif - - #ifdef HAVE_SYS_SENDFILE_H --# include -+# include // sendfile() - #endif - - #if defined(__APPLE__) --# include -+# include // fcopyfile() - #endif - - #ifdef HAVE_SCHED_H --# include --#endif -- --#if !defined(CPU_ALLOC) && defined(HAVE_SCHED_SETAFFINITY) --# undef HAVE_SCHED_SETAFFINITY --#endif -- --#if defined(HAVE_SYS_XATTR_H) --# if defined(HAVE_LINUX_LIMITS_H) && !defined(__FreeBSD_kernel__) && !defined(__GNU__) --# define USE_XATTRS --# include // Needed for XATTR_SIZE_MAX on musl libc. --# endif --# if defined(__CYGWIN__) --# define USE_XATTRS --# include // Needed for XATTR_SIZE_MAX and XATTR_LIST_MAX. --# endif -+# include // sched_setscheduler() - #endif -- --#ifdef USE_XATTRS --# include -+#ifdef HAVE_LINUX_SCHED_H -+# include // SCHED_IDLE, SCHED_RR - #endif - - #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__APPLE__) -@@ -353,23 +147,128 @@ - #endif - - #ifdef HAVE_LINUX_RANDOM_H --# include -+# include // GRND_RANDOM - #endif - #ifdef HAVE_GETRANDOM_SYSCALL --# include -+# include // syscall() -+#endif -+ -+#ifdef HAVE_POSIX_SPAWN -+# include // posix_spawn() -+#endif -+ -+#ifdef HAVE_UTIME_H -+# include // utime() - #endif - -+#ifdef HAVE_SYS_UTIME_H -+# include -+# define HAVE_UTIME_H /* pretend we do for the rest of this file */ -+#endif -+ -+#ifdef HAVE_SYS_TIMES_H -+# include // times() -+#endif -+ -+#ifdef HAVE_SYS_PARAM_H -+# include -+#endif -+ -+#ifdef HAVE_SYS_UTSNAME_H -+# include // uname() -+#endif -+ -+/* memfd_create is either defined in sys/mman.h or sys/memfd.h -+ * linux/memfd.h defines additional flags -+ */ -+#ifdef HAVE_SYS_MMAN_H -+# include // memfd_create() -+#endif -+#ifdef HAVE_SYS_MEMFD_H -+# include // memfd_create() -+#endif -+#ifdef HAVE_LINUX_MEMFD_H -+# include // memfd_create(), MFD_CLOEXEC -+#endif -+ -+#ifdef HAVE_SYS_EVENTFD_H -+# include // eventfd() -+#endif -+ -+#ifdef HAVE_SYS_TIMERFD_H -+# include // timerfd_create() -+#endif -+ -+#ifdef _Py_MEMORY_SANITIZER -+# include // __msan_unpoison() -+#endif -+ -+ -+// --- More complex system includes ----------------------------------------- -+ -+#ifdef MS_WINDOWS -+# include -+# if !defined(MS_WINDOWS_GAMES) || defined(MS_WINDOWS_DESKTOP) -+# include // PathCchSkipRoot() -+# endif -+# include // SetEntriesInAcl -+# include // UNLEN -+# include // SDDL_REVISION_1 -+# include // FSCTL_GET_REPARSE_POINT -+# if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) -+# define HAVE_SYMLINK -+# endif /* MS_WINDOWS_DESKTOP | MS_WINDOWS_SYSTEM */ -+#endif -+ -+ -+#ifdef _MSC_VER -+# ifdef HAVE_DIRECT_H -+# include -+# endif -+# ifdef HAVE_IO_H -+# include -+# endif -+# ifdef HAVE_PROCESS_H -+# include // getpid(), _cwait() -+# endif -+# include -+#endif /* _MSC_VER */ -+ -+ -+#ifdef HAVE__GETPTY -+# include // mode_t -+ // SGI apparently needs this forward declaration -+ extern char * _getpty(int *, int, mode_t, int); -+#endif -+ -+ -+#if defined(HAVE_SYS_XATTR_H) -+# if defined(HAVE_LINUX_LIMITS_H) && !defined(__FreeBSD_kernel__) && !defined(__GNU__) -+# define USE_XATTRS -+# include // Needed for XATTR_SIZE_MAX on musl libc. -+# endif -+# if defined(__CYGWIN__) -+# define USE_XATTRS -+# include // Needed for XATTR_SIZE_MAX and XATTR_LIST_MAX. -+# endif -+#endif -+#ifdef USE_XATTRS -+# include // fgetxattr() -+#endif -+ -+ - #ifdef HAVE_WINDOWS_CONSOLE_IO - # define TERMSIZE_USE_CONIO - #elif defined(HAVE_SYS_IOCTL_H) --# include -+# include // ioctl(), TIOCGWINSZ - # if defined(HAVE_TERMIOS_H) - # include - # endif - # if defined(TIOCGWINSZ) - # define TERMSIZE_USE_IOCTL - # endif --#endif /* HAVE_WINDOWS_CONSOLE_IO */ -+#endif -+ - - /* Various compilers have only certain posix functions */ - /* XXX Gosh I wish these were all moved into pyconfig.h */ -@@ -396,23 +295,15 @@ - # define HAVE_PIPE 1 - # define HAVE_FSYNC 1 - # define fsync _commit --#endif /* ! __WATCOMC__ || __QNX__ */ -- --/*[clinic input] --# one of the few times we lie about this name! --module os --[clinic start generated code]*/ --/*[clinic end generated code: output=da39a3ee5e6b4b0d input=94a0f0f978acae17]*/ -+#endif - --#ifndef _MSC_VER - --#if defined(__sgi)&&_COMPILER_VERSION>=700 -+#if !defined(_MSC_VER) && defined(__sgi) && _COMPILER_VERSION>=700 - /* declare ctermid_r if compiling with MIPSPro 7.x in ANSI C mode - (default) */ --extern char *ctermid_r(char *); -+extern char *ctermid_r(char *); - #endif - --#endif /* !_MSC_VER */ - - #if defined(__VXWORKS__) - # include -@@ -426,33 +317,9 @@ - # endif - #endif /* __VXWORKS__ */ - --#ifdef HAVE_POSIX_SPAWN --# include --#endif -- --#ifdef HAVE_UTIME_H --# include --#endif /* HAVE_UTIME_H */ -- --#ifdef HAVE_SYS_UTIME_H --# include --# define HAVE_UTIME_H /* pretend we do for the rest of this file */ --#endif /* HAVE_SYS_UTIME_H */ -- --#ifdef HAVE_SYS_TIMES_H --# include --#endif /* HAVE_SYS_TIMES_H */ -- --#ifdef HAVE_SYS_PARAM_H --# include --#endif /* HAVE_SYS_PARAM_H */ -- --#ifdef HAVE_SYS_UTSNAME_H --# include --#endif /* HAVE_SYS_UTSNAME_H */ - - #ifdef HAVE_DIRENT_H --# include -+# include // opendir() - # define NAMLEN(dirent) strlen((dirent)->d_name) - #else - # if defined(__WATCOMC__) && !defined(__QNX__) -@@ -473,18 +340,20 @@ - # endif - #endif - --#ifdef _MSC_VER --# ifdef HAVE_DIRECT_H --# include --# endif --# ifdef HAVE_IO_H --# include -+ -+#if defined(MAJOR_IN_MKDEV) -+# include -+#else -+# if defined(MAJOR_IN_SYSMACROS) -+# include - # endif --# ifdef HAVE_PROCESS_H --# include -+# if defined(HAVE_MKNOD) && defined(HAVE_SYS_MKDEV_H) -+# include - # endif --# include --#endif /* _MSC_VER */ -+#endif -+ -+ -+// --- Macros --------------------------------------------------------------- - - #ifndef MAXPATHLEN - # if defined(PATH_MAX) && PATH_MAX > 1024 -@@ -494,6 +363,7 @@ - # endif - #endif /* MAXPATHLEN */ - -+ - #ifdef UNION_WAIT - /* Emulate some macros on systems that have a union instead of macros */ - # ifndef WIFEXITED -@@ -513,12 +383,14 @@ - # define WAIT_STATUS_INT(s) (s) - #endif /* UNION_WAIT */ - -+ - /* Don't use the "_r" form if we don't need it (also, won't have a - prototype for it, at least on Solaris -- maybe others as well?). */ - #if defined(HAVE_CTERMID_R) - # define USE_CTERMID_R - #endif - -+ - /* choose the appropriate stat and fstat functions and return structs */ - #undef STAT - #undef FSTAT -@@ -535,25 +407,19 @@ - # define STRUCT_STAT struct stat - #endif - --#if defined(MAJOR_IN_MKDEV) --# include --#else --# if defined(MAJOR_IN_SYSMACROS) --# include --# endif --# if defined(HAVE_MKNOD) && defined(HAVE_SYS_MKDEV_H) --# include --# endif -+ -+#if !defined(EX_OK) && defined(EXIT_SUCCESS) -+# define EX_OK EXIT_SUCCESS - #endif - --#ifdef MS_WINDOWS --# define INITFUNC PyInit_nt --# define MODNAME "nt" --# define MODNAME_OBJ &_Py_ID(nt) --#else --# define INITFUNC PyInit_posix --# define MODNAME "posix" --# define MODNAME_OBJ &_Py_ID(posix) -+#if !defined(CPU_ALLOC) && defined(HAVE_SCHED_SETAFFINITY) -+# undef HAVE_SCHED_SETAFFINITY -+#endif -+ -+/* On android API level 21, 'AT_EACCESS' is not declared although -+ * HAVE_FACCESSAT is defined. */ -+#ifdef __ANDROID__ -+# undef HAVE_FACCESSAT - #endif - - #if defined(__sun) -@@ -561,33 +427,195 @@ - # define HAVE_STRUCT_STAT_ST_FSTYPE 1 - #endif - --/* memfd_create is either defined in sys/mman.h or sys/memfd.h -- * linux/memfd.h defines additional flags -+ -+// --- Apple __builtin_available() macros ----------------------------------- -+ -+/* -+ * A number of APIs are available on macOS from a certain macOS version. -+ * To support building with a new SDK while deploying to older versions -+ * the availability test is split into two: -+ * - HAVE_: The configure check for compile time availability -+ * - HAVE__RUNTIME: Runtime check for availability -+ * -+ * The latter is always true when not on macOS, or when using a compiler -+ * that does not support __has_builtin (older versions of Xcode). -+ * -+ * Due to compiler restrictions there is one valid use of HAVE__RUNTIME: -+ * if (HAVE__RUNTIME) { ... } -+ * -+ * In mixing the test with other tests or using negations will result in compile -+ * errors. - */ --#ifdef HAVE_SYS_MMAN_H --# include -+#if defined(__APPLE__) -+ -+#include -+ -+#if defined(__has_builtin) -+#if __has_builtin(__builtin_available) -+#define HAVE_BUILTIN_AVAILABLE 1 - #endif --#ifdef HAVE_SYS_MEMFD_H --# include - #endif --#ifdef HAVE_LINUX_MEMFD_H --# include -+ -+#ifdef HAVE_BUILTIN_AVAILABLE -+# define HAVE_FSTATAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) -+# define HAVE_FACCESSAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) -+# define HAVE_FCHMODAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) -+# define HAVE_FCHOWNAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) -+# define HAVE_LINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) -+# define HAVE_FDOPENDIR_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) -+# define HAVE_MKDIRAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) -+# define HAVE_RENAMEAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) -+# define HAVE_UNLINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) -+# define HAVE_OPENAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) -+# define HAVE_READLINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) -+# define HAVE_SYMLINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *) -+# define HAVE_FUTIMENS_RUNTIME __builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *) -+# define HAVE_UTIMENSAT_RUNTIME __builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *) -+# define HAVE_PWRITEV_RUNTIME __builtin_available(macOS 11.0, iOS 14.0, tvOS 14.0, watchOS 7.0, *) -+# define HAVE_MKFIFOAT_RUNTIME __builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) -+# define HAVE_MKNODAT_RUNTIME __builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) -+# define HAVE_PTSNAME_R_RUNTIME __builtin_available(macOS 10.13.4, iOS 11.3, tvOS 11.3, watchOS 4.3, *) -+ -+# define HAVE_POSIX_SPAWN_SETSID_RUNTIME __builtin_available(macOS 10.15, *) -+ -+#else /* Xcode 8 or earlier */ -+ -+ /* __builtin_available is not present in these compilers, but -+ * some of the symbols might be weak linked (10.10 SDK or later -+ * deploying on 10.9. -+ * -+ * Fall back to the older style of availability checking for -+ * symbols introduced in macOS 10.10. -+ */ -+ -+# ifdef HAVE_FSTATAT -+# define HAVE_FSTATAT_RUNTIME (fstatat != NULL) -+# endif -+ -+# ifdef HAVE_FACCESSAT -+# define HAVE_FACCESSAT_RUNTIME (faccessat != NULL) -+# endif -+ -+# ifdef HAVE_FCHMODAT -+# define HAVE_FCHMODAT_RUNTIME (fchmodat != NULL) -+# endif -+ -+# ifdef HAVE_FCHOWNAT -+# define HAVE_FCHOWNAT_RUNTIME (fchownat != NULL) -+# endif -+ -+# ifdef HAVE_LINKAT -+# define HAVE_LINKAT_RUNTIME (linkat != NULL) -+# endif -+ -+# ifdef HAVE_FDOPENDIR -+# define HAVE_FDOPENDIR_RUNTIME (fdopendir != NULL) -+# endif -+ -+# ifdef HAVE_MKDIRAT -+# define HAVE_MKDIRAT_RUNTIME (mkdirat != NULL) -+# endif -+ -+# ifdef HAVE_RENAMEAT -+# define HAVE_RENAMEAT_RUNTIME (renameat != NULL) -+# endif -+ -+# ifdef HAVE_UNLINKAT -+# define HAVE_UNLINKAT_RUNTIME (unlinkat != NULL) -+# endif -+ -+# ifdef HAVE_OPENAT -+# define HAVE_OPENAT_RUNTIME (openat != NULL) -+# endif -+ -+# ifdef HAVE_READLINKAT -+# define HAVE_READLINKAT_RUNTIME (readlinkat != NULL) -+# endif -+ -+# ifdef HAVE_SYMLINKAT -+# define HAVE_SYMLINKAT_RUNTIME (symlinkat != NULL) -+# endif -+ -+# ifdef HAVE_UTIMENSAT -+# define HAVE_UTIMENSAT_RUNTIME (utimensat != NULL) -+# endif -+ -+# ifdef HAVE_FUTIMENS -+# define HAVE_FUTIMENS_RUNTIME (futimens != NULL) -+# endif -+ -+# ifdef HAVE_PWRITEV -+# define HAVE_PWRITEV_RUNTIME (pwritev != NULL) -+# endif -+ -+# ifdef HAVE_MKFIFOAT -+# define HAVE_MKFIFOAT_RUNTIME (mkfifoat != NULL) -+# endif -+ -+# ifdef HAVE_MKNODAT -+# define HAVE_MKNODAT_RUNTIME (mknodat != NULL) -+# endif -+ -+# ifdef HAVE_PTSNAME_R -+# define HAVE_PTSNAME_R_RUNTIME (ptsname_r != NULL) -+# endif -+ - #endif - --/* eventfd() */ --#ifdef HAVE_SYS_EVENTFD_H --# include -+#ifdef HAVE_FUTIMESAT -+/* Some of the logic for weak linking depends on this assertion */ -+# error "HAVE_FUTIMESAT unexpectedly defined" - #endif - --/* timerfd_create() */ --#ifdef HAVE_SYS_TIMERFD_H --# include -+#else -+# define HAVE_FSTATAT_RUNTIME 1 -+# define HAVE_FACCESSAT_RUNTIME 1 -+# define HAVE_FCHMODAT_RUNTIME 1 -+# define HAVE_FCHOWNAT_RUNTIME 1 -+# define HAVE_LINKAT_RUNTIME 1 -+# define HAVE_FDOPENDIR_RUNTIME 1 -+# define HAVE_MKDIRAT_RUNTIME 1 -+# define HAVE_RENAMEAT_RUNTIME 1 -+# define HAVE_UNLINKAT_RUNTIME 1 -+# define HAVE_OPENAT_RUNTIME 1 -+# define HAVE_READLINKAT_RUNTIME 1 -+# define HAVE_SYMLINKAT_RUNTIME 1 -+# define HAVE_FUTIMENS_RUNTIME 1 -+# define HAVE_UTIMENSAT_RUNTIME 1 -+# define HAVE_PWRITEV_RUNTIME 1 -+# define HAVE_MKFIFOAT_RUNTIME 1 -+# define HAVE_MKNODAT_RUNTIME 1 -+# define HAVE_PTSNAME_R_RUNTIME 1 - #endif - --#ifdef _Py_MEMORY_SANITIZER --# include -+ -+// --- os module ------------------------------------------------------------ -+ -+#ifdef MS_WINDOWS -+# define INITFUNC PyInit_nt -+# define MODNAME "nt" -+# define MODNAME_OBJ &_Py_ID(nt) -+#else -+# define INITFUNC PyInit_posix -+# define MODNAME "posix" -+# define MODNAME_OBJ &_Py_ID(posix) - #endif - -+/*[clinic input] -+# one of the few times we lie about this name! -+module os -+[clinic start generated code]*/ -+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=94a0f0f978acae17]*/ -+ -+PyDoc_STRVAR(posix__doc__, -+"This module provides access to operating system functionality that is\n\ -+standardized by the C Standard and the POSIX standard (a thinly\n\ -+disguised Unix interface). Refer to the library manual and\n\ -+corresponding Unix manual entries for more information on calls."); -+ -+ -+// --- Functions ------------------------------------------------------------ -+ - #ifdef HAVE_FORK - static void - run_at_forkers(PyObject *lst, int reverse) -@@ -602,8 +630,10 @@ - * one of the callbacks. - */ - cpy = PyList_GetSlice(lst, 0, PyList_GET_SIZE(lst)); -- if (cpy == NULL) -- PyErr_WriteUnraisable(lst); -+ if (cpy == NULL) { -+ PyErr_FormatUnraisable("Exception ignored in atfork callback " -+ "while copying list %R", lst); -+ } - else { - if (reverse) - PyList_Reverse(cpy); -@@ -611,10 +641,13 @@ - PyObject *func, *res; - func = PyList_GET_ITEM(cpy, i); - res = _PyObject_CallNoArgs(func); -- if (res == NULL) -- PyErr_WriteUnraisable(func); -- else -+ if (res == NULL) { -+ PyErr_FormatUnraisable("Exception ignored " -+ "in atfork callback %R", func); -+ } -+ else { - Py_DECREF(res); -+ } - } - Py_DECREF(cpy); - } -@@ -3343,7 +3376,7 @@ - #endif - - --#ifdef HAVE_TTYNAME -+#ifdef HAVE_TTYNAME_R - /*[clinic input] - os.ttyname - -@@ -9578,42 +9611,33 @@ - - Py_RETURN_NONE; - #else /* !MS_WINDOWS */ -- PyObject *result; - DWORD sig = (DWORD)signal; -- DWORD err; -- HANDLE handle; - - #ifdef HAVE_WINDOWS_CONSOLE_IO - /* Console processes which share a common console can be sent CTRL+C or - CTRL+BREAK events, provided they handle said events. */ - if (sig == CTRL_C_EVENT || sig == CTRL_BREAK_EVENT) { - if (GenerateConsoleCtrlEvent(sig, (DWORD)pid) == 0) { -- err = GetLastError(); -- PyErr_SetFromWindowsErr(err); -- } -- else { -- Py_RETURN_NONE; -+ return PyErr_SetFromWindowsErr(0); - } -+ Py_RETURN_NONE; - } - #endif /* HAVE_WINDOWS_CONSOLE_IO */ - - /* If the signal is outside of what GenerateConsoleCtrlEvent can use, - attempt to open and terminate the process. */ -- handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)pid); -+ HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)pid); - if (handle == NULL) { -- err = GetLastError(); -- return PyErr_SetFromWindowsErr(err); -+ return PyErr_SetFromWindowsErr(0); - } - -- if (TerminateProcess(handle, sig) == 0) { -- err = GetLastError(); -- result = PyErr_SetFromWindowsErr(err); -- } else { -- result = Py_NewRef(Py_None); -+ BOOL res = TerminateProcess(handle, sig); -+ CloseHandle(handle); -+ if (res == 0) { -+ return PyErr_SetFromWindowsErr(0); - } - -- CloseHandle(handle); -- return result; -+ Py_RETURN_NONE; - #endif /* !MS_WINDOWS */ - } - #endif /* HAVE_KILL */ -@@ -9882,7 +9906,7 @@ - memset(ru, 0, sizeof(*ru)); - } - -- struct_rusage = _PyImport_GetModuleAttrString("resource", "struct_rusage"); -+ struct_rusage = PyImport_ImportModuleAttrString("resource", "struct_rusage"); - if (struct_rusage == NULL) - return NULL; - -@@ -11438,6 +11462,38 @@ - return buffer; - } - -+/*[clinic input] -+os.readinto -> Py_ssize_t -+ fd: int -+ buffer: Py_buffer(accept={rwbuffer}) -+ / -+ -+Read into a buffer object from a file descriptor. -+ -+The buffer should be mutable and bytes-like. On success, returns the number of -+bytes read. Less bytes may be read than the size of the buffer. The underlying -+system call will be retried when interrupted by a signal, unless the signal -+handler raises an exception. Other errors will not be retried and an error will -+be raised. -+ -+Returns 0 if *fd* is at end of file or if the provided *buffer* has length 0 -+(which can be used to check for errors without reading data). Never returns -+negative. -+[clinic start generated code]*/ -+ -+static Py_ssize_t -+os_readinto_impl(PyObject *module, int fd, Py_buffer *buffer) -+/*[clinic end generated code: output=8091a3513c683a80 input=d40074d0a68de575]*/ -+{ -+ assert(buffer->len >= 0); -+ Py_ssize_t result = _Py_read(fd, buffer->buf, buffer->len); -+ /* Ensure negative is never returned without an error. Simplifies calling -+ code. _Py_read should succeed, possibly reading 0 bytes, _or_ set an -+ error. */ -+ assert(result >= 0 || (result == -1 && PyErr_Occurred())); -+ return result; -+} -+ - #if (defined(HAVE_SENDFILE) && (defined(__FreeBSD__) || defined(__DragonFly__) \ - || defined(__APPLE__))) \ - || defined(HAVE_READV) || defined(HAVE_PREADV) || defined (HAVE_PREADV2) \ -@@ -16303,7 +16359,8 @@ - "unclosed scandir iterator %R", iterator)) { - /* Spurious errors can appear at shutdown */ - if (PyErr_ExceptionMatches(PyExc_Warning)) { -- PyErr_WriteUnraisable((PyObject *) iterator); -+ PyErr_FormatUnraisable("Exception ignored while finalizing " -+ "scandir iterator %R", iterator); - } - } - } -@@ -16978,6 +17035,7 @@ - OS_LOCKF_METHODDEF - OS_LSEEK_METHODDEF - OS_READ_METHODDEF -+ OS_READINTO_METHODDEF - OS_READV_METHODDEF - OS_PREAD_METHODDEF - OS_PREADV_METHODDEF -@@ -17523,9 +17581,15 @@ - #ifdef SCHED_OTHER - if (PyModule_AddIntMacro(m, SCHED_OTHER)) return -1; - #endif -+#ifdef SCHED_DEADLINE -+ if (PyModule_AddIntMacro(m, SCHED_DEADLINE)) return -1; -+#endif - #ifdef SCHED_FIFO - if (PyModule_AddIntMacro(m, SCHED_FIFO)) return -1; - #endif -+#ifdef SCHED_NORMAL -+ if (PyModule_AddIntMacro(m, SCHED_NORMAL)) return -1; -+#endif - #ifdef SCHED_RR - if (PyModule_AddIntMacro(m, SCHED_RR)) return -1; - #endif -diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c -index 9733bc34f7c..3290706f143 100644 ---- a/Modules/pyexpat.c -+++ b/Modules/pyexpat.c -@@ -1767,7 +1767,10 @@ - {"XML_ERROR_NO_BUFFER", "a successful prior call to function XML_GetBuffer is required"}, - - /* Added in 2.4.0. */ -- {"XML_ERROR_AMPLIFICATION_LIMIT_BREACH", "limit on input amplification factor (from DTD and entities) breached"} -+ {"XML_ERROR_AMPLIFICATION_LIMIT_BREACH", "limit on input amplification factor (from DTD and entities) breached"}, -+ -+ /* Added in 2.6.4. */ -+ {"XML_ERROR_NOT_STARTED", "parser not started"}, - }; - - static int -@@ -1782,7 +1785,12 @@ - * with the other uses of the XML_ErrorString function - * elsewhere within this file. pyexpat's copy of the messages - * only acts as a fallback in case of outdated runtime libexpat, -- * where it returns NULL. */ -+ * where it returns NULL. -+ * -+ * In addition, XML_ErrorString is assumed to return UTF-8 encoded -+ * strings (in conv_string_to_unicode, we decode them using 'strict' -+ * error handling). -+ */ - const char *error_string = XML_ErrorString(error_code); - if (error_string == NULL) { - error_string = error_info_of[error_index].description; -@@ -1940,7 +1948,8 @@ - { - void *p = PyCapsule_GetPointer(capsule, PyExpat_CAPSULE_NAME); - if (p == NULL) { -- PyErr_WriteUnraisable(capsule); -+ PyErr_FormatUnraisable("Exception ignored while destroying " -+ "pyexact capsule"); - return; - } - PyMem_Free(p); -diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c -index e14e114a6da..c75e2ba28c5 100644 ---- a/Modules/selectmodule.c -+++ b/Modules/selectmodule.c -@@ -14,7 +14,6 @@ - - #include "Python.h" - #include "pycore_fileutils.h" // _Py_set_inheritable() --#include "pycore_import.h" // _PyImport_GetModuleAttrString() - #include "pycore_time.h" // _PyTime_FromSecondsObject() - - #include -@@ -1996,7 +1995,7 @@ - // Register a callback to invalidate kqueues with open fds after fork. - PyObject *register_at_fork = NULL, *cb = NULL, *args = NULL, - *kwargs = NULL, *result = NULL; -- register_at_fork = _PyImport_GetModuleAttrString("posix", -+ register_at_fork = PyImport_ImportModuleAttrString("posix", - "register_at_fork"); - if (register_at_fork == NULL) { - goto finally; -diff --git a/Modules/sha1module.c b/Modules/sha1module.c -index 34a427a39b5..d0b1e825077 100644 ---- a/Modules/sha1module.c -+++ b/Modules/sha1module.c -@@ -55,6 +55,8 @@ - Hacl_Hash_SHA1_state_t *hash_state; - } SHA1object; - -+#define _SHA1object_CAST(op) ((SHA1object *)(op)) -+ - #include "clinic/sha1module.c.h" - - -@@ -73,7 +75,7 @@ - static SHA1object * - newSHA1object(SHA1State *st) - { -- SHA1object *sha = (SHA1object *)PyObject_GC_New(SHA1object, st->sha1_type); -+ SHA1object *sha = PyObject_GC_New(SHA1object, st->sha1_type); - if (sha == NULL) { - return NULL; - } -@@ -93,8 +95,9 @@ - } - - static void --SHA1_dealloc(SHA1object *ptr) -+SHA1_dealloc(PyObject *op) - { -+ SHA1object *ptr = _SHA1object_CAST(op); - Hacl_Hash_SHA1_free(ptr->hash_state); - PyTypeObject *tp = Py_TYPE(ptr); - PyObject_GC_UnTrack(ptr); -@@ -217,36 +220,27 @@ - }; - - static PyObject * --SHA1_get_block_size(PyObject *self, void *closure) -+SHA1_get_block_size(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) - { - return PyLong_FromLong(SHA1_BLOCKSIZE); - } - - static PyObject * --SHA1_get_name(PyObject *self, void *closure) -+SHA1_get_name(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) - { - return PyUnicode_FromStringAndSize("sha1", 4); - } - - static PyObject * --sha1_get_digest_size(PyObject *self, void *closure) -+sha1_get_digest_size(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) - { - return PyLong_FromLong(SHA1_DIGESTSIZE); - } - - static PyGetSetDef SHA1_getseters[] = { -- {"block_size", -- (getter)SHA1_get_block_size, NULL, -- NULL, -- NULL}, -- {"name", -- (getter)SHA1_get_name, NULL, -- NULL, -- NULL}, -- {"digest_size", -- (getter)sha1_get_digest_size, NULL, -- NULL, -- NULL}, -+ {"block_size", SHA1_get_block_size, NULL, NULL, NULL}, -+ {"name", SHA1_get_name, NULL, NULL, NULL}, -+ {"digest_size", sha1_get_digest_size, NULL, NULL, NULL}, - {NULL} /* Sentinel */ - }; - -@@ -346,7 +340,7 @@ - static void - _sha1_free(void *module) - { -- _sha1_clear((PyObject *)module); -+ (void)_sha1_clear((PyObject *)module); - } - - static int -diff --git a/Modules/sha2module.c b/Modules/sha2module.c -index 7d6a1e40243..45fa120cf76 100644 ---- a/Modules/sha2module.c -+++ b/Modules/sha2module.c -@@ -67,6 +67,9 @@ - Hacl_Hash_SHA2_state_t_512 *state; - } SHA512object; - -+#define _SHA256object_CAST(op) ((SHA256object *)(op)) -+#define _SHA512object_CAST(op) ((SHA512object *)(op)) -+ - #include "clinic/sha2module.c.h" - - /* We shall use run-time type information in the remainder of this module to -@@ -101,8 +104,7 @@ - static SHA256object * - newSHA224object(sha2_state *state) - { -- SHA256object *sha = (SHA256object *)PyObject_GC_New( -- SHA256object, state->sha224_type); -+ SHA256object *sha = PyObject_GC_New(SHA256object, state->sha224_type); - if (!sha) { - return NULL; - } -@@ -115,8 +117,7 @@ - static SHA256object * - newSHA256object(sha2_state *state) - { -- SHA256object *sha = (SHA256object *)PyObject_GC_New( -- SHA256object, state->sha256_type); -+ SHA256object *sha = PyObject_GC_New(SHA256object, state->sha256_type); - if (!sha) { - return NULL; - } -@@ -129,8 +130,7 @@ - static SHA512object * - newSHA384object(sha2_state *state) - { -- SHA512object *sha = (SHA512object *)PyObject_GC_New( -- SHA512object, state->sha384_type); -+ SHA512object *sha = PyObject_GC_New(SHA512object, state->sha384_type); - if (!sha) { - return NULL; - } -@@ -143,8 +143,7 @@ - static SHA512object * - newSHA512object(sha2_state *state) - { -- SHA512object *sha = (SHA512object *)PyObject_GC_New( -- SHA512object, state->sha512_type); -+ SHA512object *sha = PyObject_GC_New(SHA512object, state->sha512_type); - if (!sha) { - return NULL; - } -@@ -164,8 +163,9 @@ - } - - static void --SHA256_dealloc(SHA256object *ptr) -+SHA256_dealloc(PyObject *op) - { -+ SHA256object *ptr = _SHA256object_CAST(op); - Hacl_Hash_SHA2_free_256(ptr->state); - PyTypeObject *tp = Py_TYPE(ptr); - PyObject_GC_UnTrack(ptr); -@@ -174,8 +174,9 @@ - } - - static void --SHA512_dealloc(SHA512object *ptr) -+SHA512_dealloc(PyObject *op) - { -+ SHA512object *ptr = _SHA512object_CAST(op); - Hacl_Hash_SHA2_free_512(ptr->state); - PyTypeObject *tp = Py_TYPE(ptr); - PyObject_GC_UnTrack(ptr); -@@ -442,32 +443,35 @@ - }; - - static PyObject * --SHA256_get_block_size(PyObject *self, void *closure) -+SHA256_get_block_size(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) - { - return PyLong_FromLong(SHA256_BLOCKSIZE); - } - - static PyObject * --SHA512_get_block_size(PyObject *self, void *closure) -+SHA512_get_block_size(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) - { - return PyLong_FromLong(SHA512_BLOCKSIZE); - } - - static PyObject * --SHA256_get_digest_size(SHA256object *self, void *closure) -+SHA256_get_digest_size(PyObject *op, void *Py_UNUSED(closure)) - { -+ SHA256object *self = _SHA256object_CAST(op); - return PyLong_FromLong(self->digestsize); - } - - static PyObject * --SHA512_get_digest_size(SHA512object *self, void *closure) -+SHA512_get_digest_size(PyObject *op, void *Py_UNUSED(closure)) - { -+ SHA512object *self = _SHA512object_CAST(op); - return PyLong_FromLong(self->digestsize); - } - - static PyObject * --SHA256_get_name(SHA256object *self, void *closure) -+SHA256_get_name(PyObject *op, void *Py_UNUSED(closure)) - { -+ SHA256object *self = _SHA256object_CAST(op); - if (self->digestsize == 28) { - return PyUnicode_FromStringAndSize("sha224", 6); - } -@@ -475,8 +479,9 @@ - } - - static PyObject * --SHA512_get_name(SHA512object *self, void *closure) -+SHA512_get_name(PyObject *op, void *Py_UNUSED(closure)) - { -+ SHA512object *self = _SHA512object_CAST(op); - if (self->digestsize == 64) { - return PyUnicode_FromStringAndSize("sha512", 6); - } -@@ -484,34 +489,16 @@ - } - - static PyGetSetDef SHA256_getseters[] = { -- {"block_size", -- (getter)SHA256_get_block_size, NULL, -- NULL, -- NULL}, -- {"name", -- (getter)SHA256_get_name, NULL, -- NULL, -- NULL}, -- {"digest_size", -- (getter)SHA256_get_digest_size, NULL, -- NULL, -- NULL}, -+ {"block_size", SHA256_get_block_size, NULL, NULL, NULL}, -+ {"name", SHA256_get_name, NULL, NULL, NULL}, -+ {"digest_size", SHA256_get_digest_size, NULL, NULL, NULL}, - {NULL} /* Sentinel */ - }; - - static PyGetSetDef SHA512_getseters[] = { -- {"block_size", -- (getter)SHA512_get_block_size, NULL, -- NULL, -- NULL}, -- {"name", -- (getter)SHA512_get_name, NULL, -- NULL, -- NULL}, -- {"digest_size", -- (getter)SHA512_get_digest_size, NULL, -- NULL, -- NULL}, -+ {"block_size", SHA512_get_block_size, NULL, NULL, NULL}, -+ {"name", SHA512_get_name, NULL, NULL, NULL}, -+ {"digest_size", SHA512_get_digest_size, NULL, NULL, NULL}, - {NULL} /* Sentinel */ - }; - -@@ -818,7 +805,7 @@ - static void - _sha2_free(void *module) - { -- _sha2_clear((PyObject *)module); -+ (void)_sha2_clear((PyObject *)module); - } - - /* Initialize this module. */ -diff --git a/Modules/sha3module.c b/Modules/sha3module.c -index b13e6a9de10..72a11602b0e 100644 ---- a/Modules/sha3module.c -+++ b/Modules/sha3module.c -@@ -66,6 +66,8 @@ - Hacl_Hash_SHA3_state_t *hash_state; - } SHA3object; - -+#define _SHA3object_CAST(op) ((SHA3object *)(op)) -+ - #include "clinic/sha3module.c.h" - - static SHA3object * -@@ -167,8 +169,9 @@ - /* Internal methods for a hash object */ - - static int --SHA3_clear(SHA3object *self) -+SHA3_clear(PyObject *op) - { -+ SHA3object *self = _SHA3object_CAST(op); - if (self->hash_state != NULL) { - Hacl_Hash_SHA3_free(self->hash_state); - self->hash_state = NULL; -@@ -177,7 +180,7 @@ - } - - static void --SHA3_dealloc(SHA3object *self) -+SHA3_dealloc(PyObject *self) - { - PyTypeObject *tp = Py_TYPE(self); - PyObject_GC_UnTrack(self); -@@ -303,15 +306,16 @@ - - - static PyObject * --SHA3_get_block_size(SHA3object *self, void *closure) -+SHA3_get_block_size(PyObject *op, void *Py_UNUSED(closure)) - { -+ SHA3object *self = _SHA3object_CAST(op); - uint32_t rate = Hacl_Hash_SHA3_block_len(self->hash_state); - return PyLong_FromLong(rate); - } - - - static PyObject * --SHA3_get_name(SHA3object *self, void *closure) -+SHA3_get_name(PyObject *self, void *Py_UNUSED(closure)) - { - PyTypeObject *type = Py_TYPE(self); - -@@ -338,9 +342,10 @@ - - - static PyObject * --SHA3_get_digest_size(SHA3object *self, void *closure) -+SHA3_get_digest_size(PyObject *op, void *Py_UNUSED(closure)) - { - // Preserving previous behavior: variable-length algorithms return 0 -+ SHA3object *self = _SHA3object_CAST(op); - if (Hacl_Hash_SHA3_is_shake(self->hash_state)) - return PyLong_FromLong(0); - else -@@ -349,8 +354,9 @@ - - - static PyObject * --SHA3_get_capacity_bits(SHA3object *self, void *closure) -+SHA3_get_capacity_bits(PyObject *op, void *Py_UNUSED(closure)) - { -+ SHA3object *self = _SHA3object_CAST(op); - uint32_t rate = Hacl_Hash_SHA3_block_len(self->hash_state) * 8; - assert(rate <= 1600); - int capacity = 1600 - rate; -@@ -359,26 +365,27 @@ - - - static PyObject * --SHA3_get_rate_bits(SHA3object *self, void *closure) -+SHA3_get_rate_bits(PyObject *op, void *Py_UNUSED(closure)) - { -+ SHA3object *self = _SHA3object_CAST(op); - uint32_t rate = Hacl_Hash_SHA3_block_len(self->hash_state) * 8; - return PyLong_FromLong(rate); - } - - static PyObject * --SHA3_get_suffix(SHA3object *self, void *closure) -+SHA3_get_suffix(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) - { - unsigned char suffix[2] = {0x06, 0}; - return PyBytes_FromStringAndSize((const char *)suffix, 1); - } - - static PyGetSetDef SHA3_getseters[] = { -- {"block_size", (getter)SHA3_get_block_size, NULL, NULL, NULL}, -- {"name", (getter)SHA3_get_name, NULL, NULL, NULL}, -- {"digest_size", (getter)SHA3_get_digest_size, NULL, NULL, NULL}, -- {"_capacity_bits", (getter)SHA3_get_capacity_bits, NULL, NULL, NULL}, -- {"_rate_bits", (getter)SHA3_get_rate_bits, NULL, NULL, NULL}, -- {"_suffix", (getter)SHA3_get_suffix, NULL, NULL, NULL}, -+ {"block_size", SHA3_get_block_size, NULL, NULL, NULL}, -+ {"name", SHA3_get_name, NULL, NULL, NULL}, -+ {"digest_size", SHA3_get_digest_size, NULL, NULL, NULL}, -+ {"_capacity_bits", SHA3_get_capacity_bits, NULL, NULL, NULL}, -+ {"_rate_bits", SHA3_get_rate_bits, NULL, NULL, NULL}, -+ {"_suffix", SHA3_get_suffix, NULL, NULL, NULL}, - {NULL} /* Sentinel */ - }; - -@@ -438,10 +445,11 @@ - SHA3_TYPE_SPEC(sha3_512_spec, "sha3_512", sha3_512_slots); - - static PyObject * --_SHAKE_digest(SHA3object *self, unsigned long digestlen, int hex) -+_SHAKE_digest(PyObject *op, unsigned long digestlen, int hex) - { - unsigned char *digest = NULL; - PyObject *result = NULL; -+ SHA3object *self = _SHA3object_CAST(op); - - if (digestlen >= (1 << 29)) { - PyErr_SetString(PyExc_ValueError, "length is too large"); -@@ -483,7 +491,7 @@ - _sha3_shake_128_digest_impl(SHA3object *self, unsigned long length) - /*[clinic end generated code: output=2313605e2f87bb8f input=418ef6a36d2e6082]*/ - { -- return _SHAKE_digest(self, length, 0); -+ return _SHAKE_digest((PyObject *)self, length, 0); - } - - -@@ -500,17 +508,17 @@ - _sha3_shake_128_hexdigest_impl(SHA3object *self, unsigned long length) - /*[clinic end generated code: output=bf8e2f1e490944a8 input=69fb29b0926ae321]*/ - { -- return _SHAKE_digest(self, length, 1); -+ return _SHAKE_digest((PyObject *)self, length, 1); - } - - static PyObject * --SHAKE_get_digest_size(SHA3object *self, void *closure) -+SHAKE_get_digest_size(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) - { - return PyLong_FromLong(0); - } - - static PyObject * --SHAKE_get_suffix(SHA3object *self, void *closure) -+SHAKE_get_suffix(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) - { - unsigned char suffix[2] = {0x1f, 0}; - return PyBytes_FromStringAndSize((const char *)suffix, 1); -@@ -518,12 +526,12 @@ - - - static PyGetSetDef SHAKE_getseters[] = { -- {"block_size", (getter)SHA3_get_block_size, NULL, NULL, NULL}, -- {"name", (getter)SHA3_get_name, NULL, NULL, NULL}, -- {"digest_size", (getter)SHAKE_get_digest_size, NULL, NULL, NULL}, -- {"_capacity_bits", (getter)SHA3_get_capacity_bits, NULL, NULL, NULL}, -- {"_rate_bits", (getter)SHA3_get_rate_bits, NULL, NULL, NULL}, -- {"_suffix", (getter)SHAKE_get_suffix, NULL, NULL, NULL}, -+ {"block_size", SHA3_get_block_size, NULL, NULL, NULL}, -+ {"name", SHA3_get_name, NULL, NULL, NULL}, -+ {"digest_size", SHAKE_get_digest_size, NULL, NULL, NULL}, -+ {"_capacity_bits", SHA3_get_capacity_bits, NULL, NULL, NULL}, -+ {"_rate_bits", SHA3_get_rate_bits, NULL, NULL, NULL}, -+ {"_suffix", SHAKE_get_suffix, NULL, NULL, NULL}, - {NULL} /* Sentinel */ - }; - -diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c -index 0e53a36bca5..b679b83bed5 100644 ---- a/Modules/signalmodule.c -+++ b/Modules/signalmodule.c -@@ -245,7 +245,8 @@ - errno = (int) (intptr_t) data; - PyObject *exc = PyErr_GetRaisedException(); - PyErr_SetFromErrno(PyExc_OSError); -- PyErr_FormatUnraisable("Exception ignored when trying to write to the signal wakeup fd"); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "trying to write to the signal wakeup fd"); - PyErr_SetRaisedException(exc); - errno = save_errno; - return 0; -@@ -262,7 +263,8 @@ - recognizes the error codes used by both GetLastError() and - WSAGetLastError */ - PyErr_SetExcFromWindowsErr(PyExc_OSError, send_errno); -- PyErr_FormatUnraisable("Exception ignored when trying to send to the signal wakeup fd"); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "trying to send to the signal wakeup fd"); - PyErr_SetRaisedException(exc); - return 0; - } -@@ -1837,7 +1839,8 @@ - PyErr_Format(PyExc_OSError, - "Signal %i ignored due to race condition", - i); -- PyErr_WriteUnraisable(Py_None); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "calling signal handler"); - continue; - } - PyObject *arglist = NULL; -diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c -index 9394f1c940b..4b6d2dd1c5f 100644 ---- a/Modules/socketmodule.c -+++ b/Modules/socketmodule.c -@@ -110,6 +110,8 @@ - #include "pycore_fileutils.h" // _Py_set_inheritable() - #include "pycore_moduleobject.h" // _PyModule_GetState - #include "pycore_time.h" // _PyTime_AsMilliseconds() -+#include "pycore_pystate.h" // _Py_AssertHoldsTstate() -+#include "pycore_pyatomic_ft_wrappers.h" - - #ifdef _Py_MEMORY_SANITIZER - # include -@@ -549,20 +551,58 @@ - - /* Default timeout for new sockets */ - PyTime_t defaulttimeout; -+} socket_state; - - #if defined(HAVE_ACCEPT) || defined(HAVE_ACCEPT4) - #if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) -- /* accept4() is available on Linux 2.6.28+ and glibc 2.10 */ -- int accept4_works; -+/* accept4() is available on Linux 2.6.28+ and glibc 2.10 */ -+static int accept4_works = -1; - #endif - #endif - - #ifdef SOCK_CLOEXEC -- /* socket() and socketpair() fail with EINVAL on Linux kernel older -- * than 2.6.27 if SOCK_CLOEXEC flag is set in the socket type. */ -- int sock_cloexec_works; -+/* socket() and socketpair() fail with EINVAL on Linux kernel older -+ * than 2.6.27 if SOCK_CLOEXEC flag is set in the socket type. */ -+static int sock_cloexec_works = -1; - #endif --} socket_state; -+ -+static inline void -+set_sock_fd(PySocketSockObject *s, SOCKET_T fd) -+{ -+#ifdef Py_GIL_DISABLED -+#if SIZEOF_SOCKET_T == SIZEOF_INT -+ _Py_atomic_store_int_relaxed((int *)&s->sock_fd, (int)fd); -+#elif SIZEOF_SOCKET_T == SIZEOF_LONG -+ _Py_atomic_store_long_relaxed((long *)&s->sock_fd, (long)fd); -+#elif SIZEOF_SOCKET_T == SIZEOF_LONG_LONG -+ _Py_atomic_store_llong_relaxed((long long *)&s->sock_fd, (long long)fd); -+#else -+ #error "Unsupported SIZEOF_SOCKET_T" -+#endif -+#else -+ s->sock_fd = fd; -+#endif -+} -+ -+static inline SOCKET_T -+get_sock_fd(PySocketSockObject *s) -+{ -+#ifdef Py_GIL_DISABLED -+#if SIZEOF_SOCKET_T == SIZEOF_INT -+ return (SOCKET_T)_Py_atomic_load_int_relaxed((int *)&s->sock_fd); -+#elif SIZEOF_SOCKET_T == SIZEOF_LONG -+ return (SOCKET_T)_Py_atomic_load_long_relaxed((long *)&s->sock_fd); -+#elif SIZEOF_SOCKET_T == SIZEOF_LONG_LONG -+ return (SOCKET_T)_Py_atomic_load_llong_relaxed((long long *)&s->sock_fd); -+#else -+ #error "Unsupported SIZEOF_SOCKET_T" -+#endif -+#else -+ return s->sock_fd; -+#endif -+} -+ -+#define _PySocketSockObject_CAST(op) ((PySocketSockObject *)(op)) - - static inline socket_state * - get_module_state(PyObject *mod) -@@ -736,10 +776,10 @@ - #ifndef MS_WINDOWS - #if (defined(HAVE_SYS_IOCTL_H) && defined(FIONBIO)) - block = !block; -- if (ioctl(s->sock_fd, FIONBIO, (unsigned int *)&block) == -1) -+ if (ioctl(get_sock_fd(s), FIONBIO, (unsigned int *)&block) == -1) - goto done; - #else -- delay_flag = fcntl(s->sock_fd, F_GETFL, 0); -+ delay_flag = fcntl(get_sock_fd(s), F_GETFL, 0); - if (delay_flag == -1) - goto done; - if (block) -@@ -747,12 +787,12 @@ - else - new_delay_flag = delay_flag | O_NONBLOCK; - if (new_delay_flag != delay_flag) -- if (fcntl(s->sock_fd, F_SETFL, new_delay_flag) == -1) -+ if (fcntl(get_sock_fd(s), F_SETFL, new_delay_flag) == -1) - goto done; - #endif - #else /* MS_WINDOWS */ - arg = !block; -- if (ioctlsocket(s->sock_fd, FIONBIO, &arg) != 0) -+ if (ioctlsocket(get_sock_fd(s), FIONBIO, &arg) != 0) - goto done; - #endif /* MS_WINDOWS */ - -@@ -785,20 +825,20 @@ - struct timeval tv, *tvp; - #endif - -- /* must be called with the GIL held */ -- assert(PyGILState_Check()); -+ /* must be called with a thread state */ -+ _Py_AssertHoldsTstate(); - - /* Error condition is for output only */ - assert(!(connect && !writing)); - - /* Guard against closed socket */ -- if (s->sock_fd == INVALID_SOCKET) -+ if (get_sock_fd(s) == INVALID_SOCKET) - return 0; - - /* Prefer poll, if available, since you can poll() any fd - * which can't be done with select(). */ - #ifdef HAVE_POLL -- pollfd.fd = s->sock_fd; -+ pollfd.fd = get_sock_fd(s); - pollfd.events = writing ? POLLOUT : POLLIN; - if (connect) { - /* On Windows, the socket becomes writable on connection success, -@@ -838,23 +878,23 @@ - tvp = NULL; - - FD_ZERO(&fds); -- FD_SET(s->sock_fd, &fds); -+ FD_SET(get_sock_fd(s), &fds); - FD_ZERO(&efds); - if (connect) { - /* On Windows, the socket becomes writable on connection success, - but a connection failure is notified as an error. On POSIX, the - socket becomes writable on connection success or on connection - failure. */ -- FD_SET(s->sock_fd, &efds); -+ FD_SET(get_sock_fd(s), &efds); - } - - /* See if the socket is ready */ - Py_BEGIN_ALLOW_THREADS; - if (writing) -- n = select(Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int), -+ n = select(Py_SAFE_DOWNCAST(get_sock_fd(s)+1, SOCKET_T, int), - NULL, &fds, &efds, tvp); - else -- n = select(Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int), -+ n = select(Py_SAFE_DOWNCAST(get_sock_fd(s)+1, SOCKET_T, int), - &fds, NULL, &efds, tvp); - Py_END_ALLOW_THREADS; - #endif -@@ -899,8 +939,8 @@ - int deadline_initialized = 0; - int res; - -- /* sock_call() must be called with the GIL held. */ -- assert(PyGILState_Check()); -+ /* sock_call() must be called with a thread state. */ -+ _Py_AssertHoldsTstate(); - - /* outer loop to retry select() when select() is interrupted by a signal - or to retry select()+sock_func() on false positive (see above) */ -@@ -1030,7 +1070,7 @@ - init_sockobject(socket_state *state, PySocketSockObject *s, - SOCKET_T fd, int family, int type, int proto) - { -- s->sock_fd = fd; -+ set_sock_fd(s, fd); - s->sock_family = family; - - s->sock_type = type; -@@ -2127,7 +2167,7 @@ - } - strncpy(ifr.ifr_name, interfaceName, sizeof(ifr.ifr_name)); - ifr.ifr_name[(sizeof(ifr.ifr_name))-1] = '\0'; -- if (ioctl(s->sock_fd, SIOCGIFINDEX, &ifr) < 0) { -+ if (ioctl(get_sock_fd(s), SIOCGIFINDEX, &ifr) < 0) { - s->errorhandler(); - PyBuffer_Release(&haddr); - return 0; -@@ -2252,7 +2292,7 @@ - } else if ((size_t)len < sizeof(ifr.ifr_name)) { - strncpy(ifr.ifr_name, PyBytes_AS_STRING(interfaceName), sizeof(ifr.ifr_name)); - ifr.ifr_name[(sizeof(ifr.ifr_name))-1] = '\0'; -- if (ioctl(s->sock_fd, SIOCGIFINDEX, &ifr) < 0) { -+ if (ioctl(get_sock_fd(s), SIOCGIFINDEX, &ifr) < 0) { - s->errorhandler(); - Py_DECREF(interfaceName); - return 0; -@@ -2296,7 +2336,7 @@ - } else if ((size_t)len < sizeof(ifr.ifr_name)) { - strncpy(ifr.ifr_name, PyBytes_AS_STRING(interfaceName), sizeof(ifr.ifr_name)); - ifr.ifr_name[(sizeof(ifr.ifr_name))-1] = '\0'; -- if (ioctl(s->sock_fd, SIOCGIFINDEX, &ifr) < 0) { -+ if (ioctl(get_sock_fd(s), SIOCGIFINDEX, &ifr) < 0) { - s->errorhandler(); - Py_DECREF(interfaceName); - return 0; -@@ -2344,7 +2384,7 @@ - } else if ((size_t)len < sizeof(ifr.ifr_name)) { - strncpy(ifr.ifr_name, PyBytes_AS_STRING(interfaceName), sizeof(ifr.ifr_name)); - ifr.ifr_name[(sizeof(ifr.ifr_name))-1] = '\0'; -- if (ioctl(s->sock_fd, SIOCGIFINDEX, &ifr) < 0) { -+ if (ioctl(get_sock_fd(s), SIOCGIFINDEX, &ifr) < 0) { - s->errorhandler(); - Py_DECREF(interfaceName); - return 0; -@@ -2403,7 +2443,7 @@ - sizeof(info.ctl_name)); - Py_DECREF(ctl_name); - -- if (ioctl(s->sock_fd, CTLIOCGINFO, &info)) { -+ if (ioctl(get_sock_fd(s), CTLIOCGINFO, &info)) { - PyErr_SetString(PyExc_OSError, - "cannot find kernel control with provided name"); - return 0; -@@ -2867,19 +2907,18 @@ - #endif - - #if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) -- socket_state *state = s->state; -- if (state->accept4_works != 0) { -- ctx->result = accept4(s->sock_fd, addr, paddrlen, -+ if (_Py_atomic_load_int_relaxed(&accept4_works) != 0) { -+ ctx->result = accept4(get_sock_fd(s), addr, paddrlen, - SOCK_CLOEXEC); -- if (ctx->result == INVALID_SOCKET && state->accept4_works == -1) { -+ if (ctx->result == INVALID_SOCKET && _Py_atomic_load_int_relaxed(&accept4_works) == -1) { - /* On Linux older than 2.6.28, accept4() fails with ENOSYS */ -- state->accept4_works = (errno != ENOSYS); -+ _Py_atomic_store_int_relaxed(&accept4_works, errno != ENOSYS); - } - } -- if (state->accept4_works == 0) -- ctx->result = accept(s->sock_fd, addr, paddrlen); -+ if (_Py_atomic_load_int_relaxed(&accept4_works) == 0) -+ ctx->result = accept(get_sock_fd(s), addr, paddrlen); - #else -- ctx->result = accept(s->sock_fd, addr, paddrlen); -+ ctx->result = accept(get_sock_fd(s), addr, paddrlen); - #endif - - #ifdef MS_WINDOWS -@@ -2892,8 +2931,10 @@ - /* s._accept() -> (fd, address) */ - - static PyObject * --sock_accept(PySocketSockObject *s, PyObject *Py_UNUSED(ignored)) -+sock_accept(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); -+ - sock_addr_t addrbuf; - SOCKET_T newfd; - socklen_t addrlen; -@@ -2911,6 +2952,8 @@ - - ctx.addrlen = &addrlen; - ctx.addrbuf = &addrbuf; -+ ctx.result = INVALID_SOCKET; -+ - if (sock_call(s, 0, sock_accept_impl, &ctx) < 0) - return NULL; - newfd = ctx.result; -@@ -2929,8 +2972,7 @@ - #else - - #if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) -- socket_state *state = s->state; -- if (!state->accept4_works) -+ if (!_Py_atomic_load_int_relaxed(&accept4_works)) - #endif - { - if (_Py_set_inheritable(newfd, 0, NULL) < 0) { -@@ -2946,7 +2988,7 @@ - goto finally; - } - -- addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf), -+ addr = makesockaddr(get_sock_fd(s), SAS2SA(&addrbuf), - addrlen, s->sock_proto); - if (addr == NULL) - goto finally; -@@ -2974,7 +3016,7 @@ - */ - - static PyObject * --sock_setblocking(PySocketSockObject *s, PyObject *arg) -+sock_setblocking(PyObject *self, PyObject *arg) - { - long block; - -@@ -2982,6 +3024,7 @@ - if (block < 0) - return NULL; - -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); - s->sock_timeout = _PyTime_FromSeconds(block ? -1 : 0); - if (internal_setblocking(s, block) == -1) { - return NULL; -@@ -3001,8 +3044,9 @@ - False if it is in non-blocking mode. - */ - static PyObject * --sock_getblocking(PySocketSockObject *s, PyObject *Py_UNUSED(ignored)) -+sock_getblocking(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); - if (s->sock_timeout) { - Py_RETURN_TRUE; - } -@@ -3065,13 +3109,14 @@ - < 0 -- illegal; raises an exception - */ - static PyObject * --sock_settimeout(PySocketSockObject *s, PyObject *arg) -+sock_settimeout(PyObject *self, PyObject *arg) - { - PyTime_t timeout; - - if (socket_parse_timeout(&timeout, arg) < 0) - return NULL; - -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); - s->sock_timeout = timeout; - - int block = timeout < 0; -@@ -3113,8 +3158,9 @@ - /* s.gettimeout() method. - Returns the timeout associated with a socket. */ - static PyObject * --sock_gettimeout(PySocketSockObject *s, PyObject *Py_UNUSED(ignored)) -+sock_gettimeout_impl(PyObject *self, void *Py_UNUSED(ignored)) - { -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); - if (s->sock_timeout < 0) { - Py_RETURN_NONE; - } -@@ -3124,6 +3170,18 @@ - } - } - -+static inline PyObject * -+sock_gettimeout_method(PyObject *self, PyObject *Py_UNUSED(ignored)) -+{ -+ return sock_gettimeout_impl(self, NULL); -+} -+ -+static inline PyObject * -+sock_gettimeout_getter(PyObject *self, void *Py_UNUSED(closure)) -+{ -+ return sock_gettimeout_impl(self, NULL); -+} -+ - PyDoc_STRVAR(gettimeout_doc, - "gettimeout() -> timeout\n\ - \n\ -@@ -3141,8 +3199,10 @@ - */ - - static PyObject * --sock_setsockopt(PySocketSockObject *s, PyObject *args) -+sock_setsockopt(PyObject *self, PyObject *args) - { -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); -+ - int level; - int optname; - int res; -@@ -3158,7 +3218,7 @@ - if (PyArg_ParseTuple(args, "iiK:setsockopt", - &level, &optname, &vflag)) { - // level should always be set to AF_VSOCK -- res = setsockopt(s->sock_fd, level, optname, -+ res = setsockopt(get_sock_fd(s), level, optname, - (void*)&vflag, sizeof vflag); - goto done; - } -@@ -3172,7 +3232,7 @@ - #ifdef MS_WINDOWS - if (optname == SIO_TCP_SET_ACK_FREQUENCY) { - int dummy; -- res = WSAIoctl(s->sock_fd, SIO_TCP_SET_ACK_FREQUENCY, &flag, -+ res = WSAIoctl(get_sock_fd(s), SIO_TCP_SET_ACK_FREQUENCY, &flag, - sizeof(flag), NULL, 0, &dummy, NULL, NULL); - if (res >= 0) { - s->quickack = flag; -@@ -3180,7 +3240,7 @@ - goto done; - } - #endif -- res = setsockopt(s->sock_fd, level, optname, -+ res = setsockopt(get_sock_fd(s), level, optname, - (char*)&flag, sizeof flag); - goto done; - } -@@ -3190,7 +3250,7 @@ - if (PyArg_ParseTuple(args, "iiO!I:setsockopt", - &level, &optname, Py_TYPE(Py_None), &none, &optlen)) { - assert(sizeof(socklen_t) >= sizeof(unsigned int)); -- res = setsockopt(s->sock_fd, level, optname, -+ res = setsockopt(get_sock_fd(s), level, optname, - NULL, (socklen_t)optlen); - goto done; - } -@@ -3209,10 +3269,10 @@ - INT_MAX); - return NULL; - } -- res = setsockopt(s->sock_fd, level, optname, -+ res = setsockopt(get_sock_fd(s), level, optname, - optval.buf, (int)optval.len); - #else -- res = setsockopt(s->sock_fd, level, optname, optval.buf, optval.len); -+ res = setsockopt(get_sock_fd(s), level, optname, optval.buf, optval.len); - #endif - PyBuffer_Release(&optval); - -@@ -3240,8 +3300,10 @@ - use optional built-in module 'struct' to decode the string. */ - - static PyObject * --sock_getsockopt(PySocketSockObject *s, PyObject *args) -+sock_getsockopt(PyObject *self, PyObject *args) - { -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); -+ - int level; - int optname; - int res; -@@ -3259,7 +3321,7 @@ - if (s->sock_family == AF_VSOCK) { - uint64_t vflag = 0; // Must be set width of 64 bits - flagsize = sizeof vflag; -- res = getsockopt(s->sock_fd, level, optname, -+ res = getsockopt(get_sock_fd(s), level, optname, - (void *)&vflag, &flagsize); - if (res < 0) - return s->errorhandler(); -@@ -3272,7 +3334,7 @@ - } - #endif - flagsize = sizeof flag; -- res = getsockopt(s->sock_fd, level, optname, -+ res = getsockopt(get_sock_fd(s), level, optname, - (void *)&flag, &flagsize); - if (res < 0) - return s->errorhandler(); -@@ -3293,7 +3355,7 @@ - buf = PyBytes_FromStringAndSize((char *)NULL, buflen); - if (buf == NULL) - return NULL; -- res = getsockopt(s->sock_fd, level, optname, -+ res = getsockopt(get_sock_fd(s), level, optname, - (void *)PyBytes_AS_STRING(buf), &buflen); - if (res < 0) { - Py_DECREF(buf); -@@ -3315,8 +3377,10 @@ - /* s.bind(sockaddr) method */ - - static PyObject * --sock_bind(PySocketSockObject *s, PyObject *addro) -+sock_bind(PyObject *self, PyObject *addro) - { -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); -+ - sock_addr_t addrbuf; - int addrlen; - int res; -@@ -3330,7 +3394,7 @@ - } - - Py_BEGIN_ALLOW_THREADS -- res = bind(s->sock_fd, SAS2SA(&addrbuf), addrlen); -+ res = bind(get_sock_fd(s), SAS2SA(&addrbuf), addrlen); - Py_END_ALLOW_THREADS - if (res < 0) - return s->errorhandler(); -@@ -3351,7 +3415,6 @@ - will surely fail. */ - - /*[clinic input] --@critical_section - _socket.socket.close - self as s: self(type="PySocketSockObject *") - -@@ -3362,14 +3425,14 @@ - - static PyObject * - _socket_socket_close_impl(PySocketSockObject *s) --/*[clinic end generated code: output=038b2418e07f6f6c input=9839a261e05bcb97]*/ -+/*[clinic end generated code: output=038b2418e07f6f6c input=dc487e470e55a83c]*/ - { - SOCKET_T fd; - int res; - -- fd = s->sock_fd; -+ fd = get_sock_fd(s); - if (fd != INVALID_SOCKET) { -- s->sock_fd = INVALID_SOCKET; -+ set_sock_fd(s, INVALID_SOCKET); - - /* We do not want to retry upon EINTR: see - http://lwn.net/Articles/576478/ and -@@ -3388,10 +3451,11 @@ - } - - static PyObject * --sock_detach(PySocketSockObject *s, PyObject *Py_UNUSED(ignored)) -+sock_detach(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- SOCKET_T fd = s->sock_fd; -- s->sock_fd = INVALID_SOCKET; -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); -+ SOCKET_T fd = get_sock_fd(s); -+ set_sock_fd(s, INVALID_SOCKET); - return PyLong_FromSocket_t(fd); - } - -@@ -3409,7 +3473,7 @@ - int err; - socklen_t size = sizeof err; - -- if (getsockopt(s->sock_fd, SOL_SOCKET, SO_ERROR, (void *)&err, &size)) { -+ if (getsockopt(get_sock_fd(s), SOL_SOCKET, SO_ERROR, (void *)&err, &size)) { - /* getsockopt() failed */ - return 0; - } -@@ -3443,7 +3507,7 @@ - int res, err, wait_connect; - - Py_BEGIN_ALLOW_THREADS -- res = connect(s->sock_fd, addr, addrlen); -+ res = connect(get_sock_fd(s), addr, addrlen); - Py_END_ALLOW_THREADS - - if (!res) { -@@ -3505,8 +3569,10 @@ - /* s.connect(sockaddr) method */ - - static PyObject * --sock_connect(PySocketSockObject *s, PyObject *addro) -+sock_connect(PyObject *self, PyObject *addro) - { -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); -+ - sock_addr_t addrbuf; - int addrlen; - int res; -@@ -3538,8 +3604,10 @@ - /* s.connect_ex(sockaddr) method */ - - static PyObject * --sock_connect_ex(PySocketSockObject *s, PyObject *addro) -+sock_connect_ex(PyObject *self, PyObject *addro) - { -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); -+ - sock_addr_t addrbuf; - int addrlen; - int res; -@@ -3571,9 +3639,10 @@ - /* s.fileno() method */ - - static PyObject * --sock_fileno(PySocketSockObject *s, PyObject *Py_UNUSED(ignored)) -+sock_fileno(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return PyLong_FromSocket_t(s->sock_fd); -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); -+ return PyLong_FromSocket_t(get_sock_fd(s)); - } - - PyDoc_STRVAR(fileno_doc, -@@ -3586,8 +3655,10 @@ - /* s.getsockname() method */ - - static PyObject * --sock_getsockname(PySocketSockObject *s, PyObject *Py_UNUSED(ignored)) -+sock_getsockname(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); -+ - sock_addr_t addrbuf; - int res; - socklen_t addrlen; -@@ -3596,11 +3667,11 @@ - return NULL; - memset(&addrbuf, 0, addrlen); - Py_BEGIN_ALLOW_THREADS -- res = getsockname(s->sock_fd, SAS2SA(&addrbuf), &addrlen); -+ res = getsockname(get_sock_fd(s), SAS2SA(&addrbuf), &addrlen); - Py_END_ALLOW_THREADS - if (res < 0) - return s->errorhandler(); -- return makesockaddr(s->sock_fd, SAS2SA(&addrbuf), addrlen, -+ return makesockaddr(get_sock_fd(s), SAS2SA(&addrbuf), addrlen, - s->sock_proto); - } - -@@ -3618,8 +3689,10 @@ - /* s.getpeername() method */ - - static PyObject * --sock_getpeername(PySocketSockObject *s, PyObject *Py_UNUSED(ignored)) -+sock_getpeername(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); -+ - sock_addr_t addrbuf; - int res; - socklen_t addrlen; -@@ -3628,11 +3701,11 @@ - return NULL; - memset(&addrbuf, 0, addrlen); - Py_BEGIN_ALLOW_THREADS -- res = getpeername(s->sock_fd, SAS2SA(&addrbuf), &addrlen); -+ res = getpeername(get_sock_fd(s), SAS2SA(&addrbuf), &addrlen); - Py_END_ALLOW_THREADS - if (res < 0) - return s->errorhandler(); -- return makesockaddr(s->sock_fd, SAS2SA(&addrbuf), addrlen, -+ return makesockaddr(get_sock_fd(s), SAS2SA(&addrbuf), addrlen, - s->sock_proto); - } - -@@ -3649,8 +3722,9 @@ - /* s.listen(n) method */ - - static PyObject * --sock_listen(PySocketSockObject *s, PyObject *args) -+sock_listen(PyObject *self, PyObject *args) - { -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); - /* We try to choose a default backlog high enough to avoid connection drops - * for common workloads, yet not too high to limit resource usage. */ - int backlog = Py_MIN(SOMAXCONN, 128); -@@ -3664,7 +3738,7 @@ - * (which doesn't make sense anyway) we force a minimum value of 0. */ - if (backlog < 0) - backlog = 0; -- res = listen(s->sock_fd, backlog); -+ res = listen(get_sock_fd(s), backlog); - Py_END_ALLOW_THREADS - if (res < 0) - return s->errorhandler(); -@@ -3695,9 +3769,9 @@ - #ifdef MS_WINDOWS - if (ctx->len > INT_MAX) - ctx->len = INT_MAX; -- ctx->result = recv(s->sock_fd, ctx->cbuf, (int)ctx->len, ctx->flags); -+ ctx->result = recv(get_sock_fd(s), ctx->cbuf, (int)ctx->len, ctx->flags); - #else -- ctx->result = recv(s->sock_fd, ctx->cbuf, ctx->len, ctx->flags); -+ ctx->result = recv(get_sock_fd(s), ctx->cbuf, ctx->len, ctx->flags); - #endif - return (ctx->result >= 0); - } -@@ -3739,8 +3813,10 @@ - /* s.recv(nbytes [,flags]) method */ - - static PyObject * --sock_recv(PySocketSockObject *s, PyObject *args) -+sock_recv(PyObject *self, PyObject *args) - { -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); -+ - Py_ssize_t recvlen, outlen; - int flags = 0; - PyObject *buf; -@@ -3788,9 +3864,10 @@ - /* s.recv_into(buffer, [nbytes [,flags]]) method */ - - static PyObject* --sock_recv_into(PySocketSockObject *s, PyObject *args, PyObject *kwds) -+sock_recv_into(PyObject *self, PyObject *args, PyObject *kwds) - { - static char *kwlist[] = {"buffer", "nbytes", "flags", 0}; -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); - - int flags = 0; - Py_buffer pbuf; -@@ -3866,10 +3943,10 @@ - #ifdef MS_WINDOWS - if (ctx->len > INT_MAX) - ctx->len = INT_MAX; -- ctx->result = recvfrom(s->sock_fd, ctx->cbuf, (int)ctx->len, ctx->flags, -+ ctx->result = recvfrom(get_sock_fd(s), ctx->cbuf, (int)ctx->len, ctx->flags, - SAS2SA(ctx->addrbuf), ctx->addrlen); - #else -- ctx->result = recvfrom(s->sock_fd, ctx->cbuf, ctx->len, ctx->flags, -+ ctx->result = recvfrom(get_sock_fd(s), ctx->cbuf, ctx->len, ctx->flags, - SAS2SA(ctx->addrbuf), ctx->addrlen); - #endif - return (ctx->result >= 0); -@@ -3913,7 +3990,7 @@ - if (sock_call(s, 0, sock_recvfrom_impl, &ctx) < 0) - return -1; - -- *addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf), addrlen, -+ *addr = makesockaddr(get_sock_fd(s), SAS2SA(&addrbuf), addrlen, - s->sock_proto); - if (*addr == NULL) - return -1; -@@ -3924,8 +4001,10 @@ - /* s.recvfrom(nbytes [,flags]) method */ - - static PyObject * --sock_recvfrom(PySocketSockObject *s, PyObject *args) -+sock_recvfrom(PyObject *self, PyObject *args) - { -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); -+ - PyObject *buf = NULL; - PyObject *addr = NULL; - PyObject *ret = NULL; -@@ -3976,9 +4055,10 @@ - /* s.recvfrom_into(buffer[, nbytes [,flags]]) method */ - - static PyObject * --sock_recvfrom_into(PySocketSockObject *s, PyObject *args, PyObject* kwds) -+sock_recvfrom_into(PyObject *self, PyObject *args, PyObject* kwds) - { - static char *kwlist[] = {"buffer", "nbytes", "flags", 0}; -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); - - int flags = 0; - Py_buffer pbuf; -@@ -4044,7 +4124,7 @@ - { - struct sock_recvmsg *ctx = data; - -- ctx->result = recvmsg(s->sock_fd, ctx->msg, ctx->flags); -+ ctx->result = recvmsg(get_sock_fd(s), ctx->msg, ctx->flags); - return (ctx->result >= 0); - } - -@@ -4153,7 +4233,7 @@ - (*makeval)(ctx.result, makeval_data), - cmsg_list, - (int)msg.msg_flags, -- makesockaddr(s->sock_fd, SAS2SA(&addrbuf), -+ makesockaddr(get_sock_fd(s), SAS2SA(&addrbuf), - ((msg.msg_namelen > addrbuflen) ? - addrbuflen : msg.msg_namelen), - s->sock_proto)); -@@ -4204,8 +4284,10 @@ - /* s.recvmsg(bufsize[, ancbufsize[, flags]]) method */ - - static PyObject * --sock_recvmsg(PySocketSockObject *s, PyObject *args) -+sock_recvmsg(PyObject *self, PyObject *args) - { -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); -+ - Py_ssize_t bufsize, ancbufsize = 0; - int flags = 0; - struct iovec iov; -@@ -4271,8 +4353,10 @@ - /* s.recvmsg_into(buffers[, ancbufsize[, flags]]) method */ - - static PyObject * --sock_recvmsg_into(PySocketSockObject *s, PyObject *args) -+sock_recvmsg_into(PyObject *self, PyObject *args) - { -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); -+ - Py_ssize_t ancbufsize = 0; - int flags = 0; - struct iovec *iovs = NULL; -@@ -4372,9 +4456,9 @@ - #ifdef MS_WINDOWS - if (ctx->len > INT_MAX) - ctx->len = INT_MAX; -- ctx->result = send(s->sock_fd, ctx->buf, (int)ctx->len, ctx->flags); -+ ctx->result = send(get_sock_fd(s), ctx->buf, (int)ctx->len, ctx->flags); - #else -- ctx->result = send(s->sock_fd, ctx->buf, ctx->len, ctx->flags); -+ ctx->result = send(get_sock_fd(s), ctx->buf, ctx->len, ctx->flags); - #endif - return (ctx->result >= 0); - } -@@ -4382,8 +4466,10 @@ - /* s.send(data [,flags]) method */ - - static PyObject * --sock_send(PySocketSockObject *s, PyObject *args) -+sock_send(PyObject *self, PyObject *args) - { -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); -+ - int flags = 0; - Py_buffer pbuf; - struct sock_send ctx; -@@ -4418,8 +4504,10 @@ - /* s.sendall(data [,flags]) method */ - - static PyObject * --sock_sendall(PySocketSockObject *s, PyObject *args) -+sock_sendall(PyObject *self, PyObject *args) - { -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); -+ - char *buf; - Py_ssize_t len, n; - int flags = 0; -@@ -4511,10 +4599,10 @@ - #ifdef MS_WINDOWS - if (ctx->len > INT_MAX) - ctx->len = INT_MAX; -- ctx->result = sendto(s->sock_fd, ctx->buf, (int)ctx->len, ctx->flags, -+ ctx->result = sendto(get_sock_fd(s), ctx->buf, (int)ctx->len, ctx->flags, - SAS2SA(ctx->addrbuf), ctx->addrlen); - #else -- ctx->result = sendto(s->sock_fd, ctx->buf, ctx->len, ctx->flags, -+ ctx->result = sendto(get_sock_fd(s), ctx->buf, ctx->len, ctx->flags, - SAS2SA(ctx->addrbuf), ctx->addrlen); - #endif - return (ctx->result >= 0); -@@ -4523,8 +4611,10 @@ - /* s.sendto(data, [flags,] sockaddr) method */ - - static PyObject * --sock_sendto(PySocketSockObject *s, PyObject *args) -+sock_sendto(PyObject *self, PyObject *args) - { -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); -+ - Py_buffer pbuf; - PyObject *addro; - Py_ssize_t arglen; -@@ -4660,15 +4750,17 @@ - { - struct sock_sendmsg *ctx = data; - -- ctx->result = sendmsg(s->sock_fd, ctx->msg, ctx->flags); -+ ctx->result = sendmsg(get_sock_fd(s), ctx->msg, ctx->flags); - return (ctx->result >= 0); - } - - /* s.sendmsg(buffers[, ancdata[, flags[, address]]]) method */ - - static PyObject * --sock_sendmsg(PySocketSockObject *s, PyObject *args) -+sock_sendmsg(PyObject *self, PyObject *args) - { -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); -+ - Py_ssize_t i, ndatabufs = 0, ncmsgs, ncmsgbufs = 0; - Py_buffer *databufs = NULL; - sock_addr_t addrbuf; -@@ -4871,8 +4963,10 @@ - - #ifdef HAVE_SOCKADDR_ALG - static PyObject* --sock_sendmsg_afalg(PySocketSockObject *self, PyObject *args, PyObject *kwds) -+sock_sendmsg_afalg(PyObject *s, PyObject *args, PyObject *kwds) - { -+ PySocketSockObject *self = _PySocketSockObject_CAST(s); -+ - PyObject *retval = NULL; - - Py_ssize_t i, ndatabufs = 0; -@@ -5039,8 +5133,10 @@ - /* s.shutdown(how) method */ - - static PyObject * --sock_shutdown(PySocketSockObject *s, PyObject *arg) -+sock_shutdown(PyObject *self, PyObject *arg) - { -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); -+ - int how; - int res; - -@@ -5048,7 +5144,7 @@ - if (how == -1 && PyErr_Occurred()) - return NULL; - Py_BEGIN_ALLOW_THREADS -- res = shutdown(s->sock_fd, how); -+ res = shutdown(get_sock_fd(s), how); - Py_END_ALLOW_THREADS - if (res < 0) - return s->errorhandler(); -@@ -5064,8 +5160,10 @@ - - #if defined(MS_WINDOWS) && defined(SIO_RCVALL) - static PyObject* --sock_ioctl(PySocketSockObject *s, PyObject *arg) -+sock_ioctl(PyObject *self, PyObject *arg) - { -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); -+ - unsigned long cmd = SIO_RCVALL; - PyObject *argO; - DWORD recv; -@@ -5078,7 +5176,7 @@ - unsigned int option = RCVALL_ON; - if (!PyArg_ParseTuple(arg, "kI:ioctl", &cmd, &option)) - return NULL; -- if (WSAIoctl(s->sock_fd, cmd, &option, sizeof(option), -+ if (WSAIoctl(get_sock_fd(s), cmd, &option, sizeof(option), - NULL, 0, &recv, NULL, NULL) == SOCKET_ERROR) { - return set_error(); - } -@@ -5088,7 +5186,7 @@ - if (!PyArg_ParseTuple(arg, "k(kkk):ioctl", &cmd, - &ka.onoff, &ka.keepalivetime, &ka.keepaliveinterval)) - return NULL; -- if (WSAIoctl(s->sock_fd, cmd, &ka, sizeof(ka), -+ if (WSAIoctl(get_sock_fd(s), cmd, &ka, sizeof(ka), - NULL, 0, &recv, NULL, NULL) == SOCKET_ERROR) { - return set_error(); - } -@@ -5098,7 +5196,7 @@ - unsigned int option; - if (!PyArg_ParseTuple(arg, "kI:ioctl", &cmd, &option)) - return NULL; -- if (WSAIoctl(s->sock_fd, cmd, &option, sizeof(option), -+ if (WSAIoctl(get_sock_fd(s), cmd, &option, sizeof(option), - NULL, 0, &recv, NULL, NULL) == SOCKET_ERROR) { - return set_error(); - } -@@ -5120,8 +5218,10 @@ - - #if defined(MS_WINDOWS) - static PyObject* --sock_share(PySocketSockObject *s, PyObject *arg) -+sock_share(PyObject *self, PyObject *arg) - { -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); -+ - WSAPROTOCOL_INFOW info; - DWORD processId; - int result; -@@ -5130,7 +5230,7 @@ - return NULL; - - Py_BEGIN_ALLOW_THREADS -- result = WSADuplicateSocketW(s->sock_fd, processId, &info); -+ result = WSADuplicateSocketW(get_sock_fd(s), processId, &info); - Py_END_ALLOW_THREADS - if (result == SOCKET_ERROR) - return set_error(); -@@ -5151,93 +5251,82 @@ - - static PyMethodDef sock_methods[] = { - #if defined(HAVE_ACCEPT) || defined(HAVE_ACCEPT4) -- {"_accept", (PyCFunction)sock_accept, METH_NOARGS, -- accept_doc}, -+ {"_accept", sock_accept, METH_NOARGS, accept_doc}, - #endif - #ifdef HAVE_BIND -- {"bind", (PyCFunction)sock_bind, METH_O, -- bind_doc}, -+ {"bind", sock_bind, METH_O, bind_doc}, - #endif - _SOCKET_SOCKET_CLOSE_METHODDEF - #ifdef HAVE_CONNECT -- {"connect", (PyCFunction)sock_connect, METH_O, -- connect_doc}, -- {"connect_ex", (PyCFunction)sock_connect_ex, METH_O, -- connect_ex_doc}, --#endif -- {"detach", (PyCFunction)sock_detach, METH_NOARGS, -- detach_doc}, -- {"fileno", (PyCFunction)sock_fileno, METH_NOARGS, -- fileno_doc}, -+ {"connect", sock_connect, METH_O, connect_doc}, -+ {"connect_ex", sock_connect_ex, METH_O, connect_ex_doc}, -+#endif -+ {"detach", sock_detach, METH_NOARGS, detach_doc}, -+ {"fileno", sock_fileno, METH_NOARGS, fileno_doc}, - #ifdef HAVE_GETPEERNAME -- {"getpeername", (PyCFunction)sock_getpeername, -- METH_NOARGS, getpeername_doc}, -+ {"getpeername", sock_getpeername, METH_NOARGS, getpeername_doc}, - #endif - #ifdef HAVE_GETSOCKNAME -- {"getsockname", (PyCFunction)sock_getsockname, -- METH_NOARGS, getsockname_doc}, -+ {"getsockname", sock_getsockname, METH_NOARGS, getsockname_doc}, - #endif -- {"getsockopt", (PyCFunction)sock_getsockopt, METH_VARARGS, -- getsockopt_doc}, -+ {"getsockopt", sock_getsockopt, METH_VARARGS, getsockopt_doc}, - #if defined(MS_WINDOWS) && defined(SIO_RCVALL) -- {"ioctl", (PyCFunction)sock_ioctl, METH_VARARGS, -- sock_ioctl_doc}, -+ {"ioctl", sock_ioctl, METH_VARARGS, sock_ioctl_doc}, - #endif - #if defined(MS_WINDOWS) -- {"share", (PyCFunction)sock_share, METH_VARARGS, -- sock_share_doc}, -+ {"share", sock_share, METH_VARARGS, sock_share_doc}, - #endif - #ifdef HAVE_LISTEN -- {"listen", (PyCFunction)sock_listen, METH_VARARGS, -- listen_doc}, -+ {"listen", sock_listen, METH_VARARGS, listen_doc}, - #endif -- {"recv", (PyCFunction)sock_recv, METH_VARARGS, -- recv_doc}, -- {"recv_into", _PyCFunction_CAST(sock_recv_into), METH_VARARGS | METH_KEYWORDS, -- recv_into_doc}, -+ {"recv", sock_recv, METH_VARARGS, recv_doc}, -+ { -+ "recv_into", -+ _PyCFunction_CAST(sock_recv_into), -+ METH_VARARGS | METH_KEYWORDS, -+ recv_into_doc -+ }, - #ifdef HAVE_RECVFROM -- {"recvfrom", (PyCFunction)sock_recvfrom, METH_VARARGS, -- recvfrom_doc}, -- {"recvfrom_into", _PyCFunction_CAST(sock_recvfrom_into), METH_VARARGS | METH_KEYWORDS, -- recvfrom_into_doc}, --#endif -- {"send", (PyCFunction)sock_send, METH_VARARGS, -- send_doc}, -- {"sendall", (PyCFunction)sock_sendall, METH_VARARGS, -- sendall_doc}, -+ {"recvfrom", sock_recvfrom, METH_VARARGS, recvfrom_doc}, -+ { -+ "recvfrom_into", -+ _PyCFunction_CAST(sock_recvfrom_into), -+ METH_VARARGS | METH_KEYWORDS, -+ recvfrom_into_doc -+ }, -+#endif -+ {"send", sock_send, METH_VARARGS, send_doc}, -+ {"sendall", sock_sendall, METH_VARARGS, sendall_doc}, - #ifdef HAVE_SENDTO -- {"sendto", (PyCFunction)sock_sendto, METH_VARARGS, -- sendto_doc}, --#endif -- {"setblocking", (PyCFunction)sock_setblocking, METH_O, -- setblocking_doc}, -- {"getblocking", (PyCFunction)sock_getblocking, METH_NOARGS, -- getblocking_doc}, -- {"settimeout", (PyCFunction)sock_settimeout, METH_O, -- settimeout_doc}, -- {"gettimeout", (PyCFunction)sock_gettimeout, METH_NOARGS, -- gettimeout_doc}, -+ {"sendto", sock_sendto, METH_VARARGS, sendto_doc}, -+#endif -+ {"setblocking", sock_setblocking, METH_O, setblocking_doc}, -+ {"getblocking", sock_getblocking, METH_NOARGS, getblocking_doc}, -+ {"settimeout", sock_settimeout, METH_O, settimeout_doc}, -+ { -+ "gettimeout", sock_gettimeout_method, METH_NOARGS, -+ gettimeout_doc -+ }, - #ifdef HAVE_SETSOCKOPT -- {"setsockopt", (PyCFunction)sock_setsockopt, METH_VARARGS, -- setsockopt_doc}, -+ {"setsockopt", sock_setsockopt, METH_VARARGS, setsockopt_doc}, - #endif - #ifdef HAVE_SHUTDOWN -- {"shutdown", (PyCFunction)sock_shutdown, METH_O, -- shutdown_doc}, -+ {"shutdown", sock_shutdown, METH_O, shutdown_doc}, - #endif - #ifdef CMSG_LEN -- {"recvmsg", (PyCFunction)sock_recvmsg, METH_VARARGS, -- recvmsg_doc}, -- {"recvmsg_into", (PyCFunction)sock_recvmsg_into, METH_VARARGS, -- recvmsg_into_doc,}, -- {"sendmsg", (PyCFunction)sock_sendmsg, METH_VARARGS, -- sendmsg_doc}, -+ {"recvmsg", sock_recvmsg, METH_VARARGS, recvmsg_doc}, -+ {"recvmsg_into", sock_recvmsg_into, METH_VARARGS, recvmsg_into_doc}, -+ {"sendmsg", sock_sendmsg, METH_VARARGS, sendmsg_doc}, - #endif - #ifdef HAVE_SOCKADDR_ALG -- {"sendmsg_afalg", _PyCFunction_CAST(sock_sendmsg_afalg), METH_VARARGS | METH_KEYWORDS, -- sendmsg_afalg_doc}, -+ { -+ "sendmsg_afalg", -+ _PyCFunction_CAST(sock_sendmsg_afalg), -+ METH_VARARGS | METH_KEYWORDS, -+ sendmsg_afalg_doc -+ }, - #endif -- {NULL, NULL} /* sentinel */ -+ {NULL, NULL, 0, NULL} /* sentinel */ - }; - - /* SockObject members */ -@@ -5249,7 +5338,7 @@ - }; - - static PyGetSetDef sock_getsetlist[] = { -- {"timeout", (getter)sock_gettimeout, NULL, PyDoc_STR("the socket timeout")}, -+ {"timeout", sock_gettimeout_getter, NULL, PyDoc_STR("the socket timeout")}, - {NULL} /* sentinel */ - }; - -@@ -5257,18 +5346,21 @@ - First close the file description. */ - - static void --sock_finalize(PySocketSockObject *s) -+sock_finalize(PyObject *self) - { -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); -+ - SOCKET_T fd; - - /* Save the current exception, if any. */ - PyObject *exc = PyErr_GetRaisedException(); - -- if (s->sock_fd != INVALID_SOCKET) { -+ if (get_sock_fd(s) != INVALID_SOCKET) { - if (PyErr_ResourceWarning((PyObject *)s, 1, "unclosed %R", s)) { - /* Spurious errors can appear at shutdown */ - if (PyErr_ExceptionMatches(PyExc_Warning)) { -- PyErr_WriteUnraisable((PyObject *)s); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "finalizing socket %R", s); - } - } - -@@ -5276,8 +5368,8 @@ - to allow the logger to call socket methods like - socket.getsockname(). If the socket is closed before, socket - methods fails with the EBADF error. */ -- fd = s->sock_fd; -- s->sock_fd = INVALID_SOCKET; -+ fd = get_sock_fd(s); -+ set_sock_fd(s, INVALID_SOCKET); - - /* We do not want to retry upon EINTR: see sock_close() */ - Py_BEGIN_ALLOW_THREADS -@@ -5290,35 +5382,37 @@ - } - - static int --sock_traverse(PySocketSockObject *s, visitproc visit, void *arg) -+sock_traverse(PyObject *s, visitproc visit, void *arg) - { - Py_VISIT(Py_TYPE(s)); - return 0; - } - - static void --sock_dealloc(PySocketSockObject *s) -+sock_dealloc(PyObject *s) - { -- if (PyObject_CallFinalizerFromDealloc((PyObject *)s) < 0) { -+ if (PyObject_CallFinalizerFromDealloc(s) < 0) { - return; - } - PyTypeObject *tp = Py_TYPE(s); - PyObject_GC_UnTrack(s); -- tp->tp_free((PyObject *)s); -+ tp->tp_free(s); - Py_DECREF(tp); - } - - - static PyObject * --sock_repr(PySocketSockObject *s) -+sock_repr(PyObject *self) - { -+ PySocketSockObject *s = _PySocketSockObject_CAST(self); -+ - long sock_fd; - /* On Windows, this test is needed because SOCKET_T is unsigned */ -- if (s->sock_fd == INVALID_SOCKET) { -+ if (get_sock_fd(s) == INVALID_SOCKET) { - sock_fd = -1; - } - #if SIZEOF_SOCKET_T > SIZEOF_LONG -- else if (s->sock_fd > LONG_MAX) { -+ else if (get_sock_fd(s) > LONG_MAX) { - /* this can occur on Win64, and actually there is a special - ugly printf formatter for decimal pointer length integer - printing, only bother if necessary*/ -@@ -5329,7 +5423,7 @@ - } - #endif - else -- sock_fd = (long)s->sock_fd; -+ sock_fd = (long)get_sock_fd(s); - return PyUnicode_FromFormat( - "", - sock_fd, s->sock_family, -@@ -5391,7 +5485,7 @@ - - #ifndef MS_WINDOWS - #ifdef SOCK_CLOEXEC -- int *atomic_flag_works = &state->sock_cloexec_works; -+ int *atomic_flag_works = &sock_cloexec_works; - #else - int *atomic_flag_works = NULL; - #endif -@@ -5546,15 +5640,16 @@ - /* UNIX */ - Py_BEGIN_ALLOW_THREADS - #ifdef SOCK_CLOEXEC -- if (state->sock_cloexec_works != 0) { -+ if (_Py_atomic_load_int_relaxed(&sock_cloexec_works) != 0) { - fd = socket(family, type | SOCK_CLOEXEC, proto); -- if (state->sock_cloexec_works == -1) { -+ if (_Py_atomic_load_int_relaxed(&sock_cloexec_works) == -1) { - if (fd >= 0) { -- state->sock_cloexec_works = 1; -+ _Py_atomic_store_int_relaxed(&sock_cloexec_works, 1); - } -+ - else if (errno == EINVAL) { - /* Linux older than 2.6.27 does not support SOCK_CLOEXEC */ -- state->sock_cloexec_works = 0; -+ _Py_atomic_store_int_relaxed(&sock_cloexec_works, 0); - fd = socket(family, type, proto); - } - } -@@ -6295,7 +6390,7 @@ - PyObject *res = NULL; - socket_state *state = get_module_state(self); - #ifdef SOCK_CLOEXEC -- int *atomic_flag_works = &state->sock_cloexec_works; -+ int *atomic_flag_works = &sock_cloexec_works; - #else - int *atomic_flag_works = NULL; - #endif -@@ -6313,15 +6408,15 @@ - /* Create a pair of socket fds */ - Py_BEGIN_ALLOW_THREADS - #ifdef SOCK_CLOEXEC -- if (state->sock_cloexec_works != 0) { -+ if (_Py_atomic_load_int_relaxed(&sock_cloexec_works) != 0) { - ret = socketpair(family, type | SOCK_CLOEXEC, proto, sv); -- if (state->sock_cloexec_works == -1) { -+ if (_Py_atomic_load_int_relaxed(&sock_cloexec_works) == -1) { - if (ret >= 0) { -- state->sock_cloexec_works = 1; -+ _Py_atomic_store_int_relaxed(&sock_cloexec_works, 1); - } - else if (errno == EINVAL) { - /* Linux older than 2.6.27 does not support SOCK_CLOEXEC */ -- state->sock_cloexec_works = 0; -+ _Py_atomic_store_int_relaxed(&sock_cloexec_works, 0); - ret = socketpair(family, type, proto, sv); - } - } -@@ -7429,17 +7524,8 @@ - } - - socket_state *state = get_module_state(m); -- state->defaulttimeout = _PYTIME_FROMSECONDS(-1); - --#if defined(HAVE_ACCEPT) || defined(HAVE_ACCEPT4) --#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) -- state->accept4_works = -1; --#endif --#endif -- --#ifdef SOCK_CLOEXEC -- state->sock_cloexec_works = -1; --#endif -+ _Py_atomic_store_int64_relaxed(&state->defaulttimeout, _PYTIME_FROMSECONDS(-1)); - - #define ADD_EXC(MOD, NAME, VAR, BASE) do { \ - VAR = PyErr_NewException("socket." NAME, BASE, NULL); \ -@@ -7916,6 +8002,9 @@ - ADD_INT_MACRO(m, SO_REUSEPORT); - #endif - #endif -+#ifdef SO_REUSEPORT_LB -+ ADD_INT_MACRO(m, SO_REUSEPORT_LB); -+#endif - #ifdef SO_SNDBUF - ADD_INT_MACRO(m, SO_SNDBUF); - #endif -diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c -index 14e7ca591a0..aa1bc9da91d 100644 ---- a/Modules/syslogmodule.c -+++ b/Modules/syslogmodule.c -@@ -176,7 +176,7 @@ - } - } - if (PySys_Audit("syslog.openlog", "Oll", ident ? ident : Py_None, logopt, facility) < 0) { -- Py_DECREF(ident); -+ Py_XDECREF(ident); - return NULL; - } - -@@ -258,7 +258,7 @@ - // Since the sys.closelog changes the process level state of syslog library, - // this operation is only allowed for the main interpreter. - if (!is_main_interpreter()) { -- PyErr_SetString(PyExc_RuntimeError, "sunbinterpreter can't use syslog.closelog()"); -+ PyErr_SetString(PyExc_RuntimeError, "subinterpreter can't use syslog.closelog()"); - return NULL; - } - -diff --git a/Modules/timemodule.c b/Modules/timemodule.c -index 340011fc08b..8d2cbff662b 100644 ---- a/Modules/timemodule.c -+++ b/Modules/timemodule.c -@@ -913,9 +913,10 @@ - PyErr_NoMemory(); - return NULL; - } -- _PyUnicodeWriter writer; -- _PyUnicodeWriter_Init(&writer); -- writer.overallocate = 1; -+ PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); -+ if (writer == NULL) { -+ goto error; -+ } - Py_ssize_t i = 0; - while (i < format_size) { - fmtlen = 0; -@@ -933,7 +934,7 @@ - if (unicode == NULL) { - goto error; - } -- if (_PyUnicodeWriter_WriteStr(&writer, unicode) < 0) { -+ if (PyUnicodeWriter_WriteStr(writer, unicode) < 0) { - Py_DECREF(unicode); - goto error; - } -@@ -947,18 +948,18 @@ - break; - } - } -- if (_PyUnicodeWriter_WriteSubstring(&writer, format_arg, start, i) < 0) { -+ if (PyUnicodeWriter_WriteSubstring(writer, format_arg, start, i) < 0) { - goto error; - } - } - - PyMem_Free(outbuf); - PyMem_Free(format); -- return _PyUnicodeWriter_Finish(&writer); -+ return PyUnicodeWriter_Finish(writer); - error: - PyMem_Free(outbuf); - PyMem_Free(format); -- _PyUnicodeWriter_Dealloc(&writer); -+ PyUnicodeWriter_Discard(writer); - return NULL; - } - -@@ -978,7 +979,7 @@ - { - PyObject *func, *result; - -- func = _PyImport_GetModuleAttrString("_strptime", "_strptime_time"); -+ func = PyImport_ImportModuleAttrString("_strptime", "_strptime_time"); - if (!func) { - return NULL; - } -diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c -index 78dcce73cda..b90665ae7ef 100644 ---- a/Modules/zlibmodule.c -+++ b/Modules/zlibmodule.c -@@ -221,6 +221,8 @@ - PyThread_type_lock lock; - } compobject; - -+#define _compobject_CAST(op) ((compobject *)op) -+ - static void - zlib_error(zlibstate *state, z_stream zst, int err, const char *msg) - { -@@ -706,7 +708,7 @@ - static void - Dealloc(compobject *self) - { -- PyObject *type = (PyObject *)Py_TYPE(self); -+ PyTypeObject *type = Py_TYPE(self); - PyThread_free_lock(self->lock); - Py_XDECREF(self->unused_data); - Py_XDECREF(self->unconsumed_tail); -@@ -716,18 +718,20 @@ - } - - static void --Comp_dealloc(compobject *self) -+Comp_dealloc(PyObject *op) - { -+ compobject *self = _compobject_CAST(op); - if (self->is_initialised) -- deflateEnd(&self->zst); -+ (void)deflateEnd(&self->zst); - Dealloc(self); - } - - static void --Decomp_dealloc(compobject *self) -+Decomp_dealloc(PyObject *op) - { -+ compobject *self = _compobject_CAST(op); - if (self->is_initialised) -- inflateEnd(&self->zst); -+ (void)inflateEnd(&self->zst); - Dealloc(self); - } - -diff --git a/Objects/abstract.c b/Objects/abstract.c -index c92ef10aa79..db7b9263711 100644 ---- a/Objects/abstract.c -+++ b/Objects/abstract.c -@@ -583,7 +583,7 @@ - PyObject *fmt = NULL; - Py_ssize_t itemsize = -1; - -- calcsize = _PyImport_GetModuleAttrString("struct", "calcsize"); -+ calcsize = PyImport_ImportModuleAttrString("struct", "calcsize"); - if (calcsize == NULL) { - goto done; - } -diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c -index 871f99b6f88..6133d30f499 100644 ---- a/Objects/bytearrayobject.c -+++ b/Objects/bytearrayobject.c -@@ -184,7 +184,12 @@ - assert(self != NULL); - assert(PyByteArray_Check(self)); - assert(logical_offset <= alloc); -- assert(requested_size >= 0); -+ -+ if (requested_size < 0) { -+ PyErr_Format(PyExc_ValueError, -+ "Can only resize to positive sizes, got %zd", requested_size); -+ return -1; -+ } - - if (requested_size == Py_SIZE(self)) { - return 0; -@@ -1388,6 +1393,31 @@ - } - - -+/*[clinic input] -+bytearray.resize -+ size: Py_ssize_t -+ New size to resize to.. -+ / -+Resize the internal buffer of bytearray to len. -+[clinic start generated code]*/ -+ -+static PyObject * -+bytearray_resize_impl(PyByteArrayObject *self, Py_ssize_t size) -+/*[clinic end generated code: output=f73524922990b2d9 input=75fd4d17c4aa47d3]*/ -+{ -+ Py_ssize_t start_size = PyByteArray_GET_SIZE(self); -+ int result = PyByteArray_Resize((PyObject *)self, size); -+ if (result < 0) { -+ return NULL; -+ } -+ // Set new bytes to null bytes -+ if (size > start_size) { -+ memset(PyByteArray_AS_STRING(self) + start_size, 0, size - start_size); -+ } -+ Py_RETURN_NONE; -+} -+ -+ - /*[clinic input] - bytearray.translate - -@@ -2113,8 +2143,9 @@ - Return the number of bytes actually allocated."); - - static PyObject * --bytearray_alloc(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored)) -+bytearray_alloc(PyObject *op, PyObject *Py_UNUSED(ignored)) - { -+ PyByteArrayObject *self = _PyByteArray_CAST(op); - return PyLong_FromSsize_t(self->ob_alloc); - } - -@@ -2313,7 +2344,7 @@ - }; - - static PyMethodDef bytearray_methods[] = { -- {"__alloc__", (PyCFunction)bytearray_alloc, METH_NOARGS, alloc_doc}, -+ {"__alloc__", bytearray_alloc, METH_NOARGS, alloc_doc}, - BYTEARRAY_REDUCE_METHODDEF - BYTEARRAY_REDUCE_EX_METHODDEF - BYTEARRAY_SIZEOF_METHODDEF -@@ -2360,6 +2391,7 @@ - BYTEARRAY_REPLACE_METHODDEF - BYTEARRAY_REMOVEPREFIX_METHODDEF - BYTEARRAY_REMOVESUFFIX_METHODDEF -+ BYTEARRAY_RESIZE_METHODDEF - BYTEARRAY_REVERSE_METHODDEF - BYTEARRAY_RFIND_METHODDEF - BYTEARRAY_RINDEX_METHODDEF -@@ -2464,24 +2496,29 @@ - PyByteArrayObject *it_seq; /* Set to NULL when iterator is exhausted */ - } bytesiterobject; - -+#define _bytesiterobject_CAST(op) ((bytesiterobject *)(op)) -+ - static void --bytearrayiter_dealloc(bytesiterobject *it) -+bytearrayiter_dealloc(PyObject *self) - { -+ bytesiterobject *it = _bytesiterobject_CAST(self); - _PyObject_GC_UNTRACK(it); - Py_XDECREF(it->it_seq); - PyObject_GC_Del(it); - } - - static int --bytearrayiter_traverse(bytesiterobject *it, visitproc visit, void *arg) -+bytearrayiter_traverse(PyObject *self, visitproc visit, void *arg) - { -+ bytesiterobject *it = _bytesiterobject_CAST(self); - Py_VISIT(it->it_seq); - return 0; - } - - static PyObject * --bytearrayiter_next(bytesiterobject *it) -+bytearrayiter_next(PyObject *self) - { -+ bytesiterobject *it = _bytesiterobject_CAST(self); - PyByteArrayObject *seq; - - assert(it != NULL); -@@ -2501,8 +2538,9 @@ - } - - static PyObject * --bytearrayiter_length_hint(bytesiterobject *it, PyObject *Py_UNUSED(ignored)) -+bytearrayiter_length_hint(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -+ bytesiterobject *it = _bytesiterobject_CAST(self); - Py_ssize_t len = 0; - if (it->it_seq) { - len = PyByteArray_GET_SIZE(it->it_seq) - it->it_index; -@@ -2517,14 +2555,14 @@ - "Private method returning an estimate of len(list(it))."); - - static PyObject * --bytearrayiter_reduce(bytesiterobject *it, PyObject *Py_UNUSED(ignored)) -+bytearrayiter_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *iter = _PyEval_GetBuiltin(&_Py_ID(iter)); - - /* _PyEval_GetBuiltin can invoke arbitrary code, - * call must be before access of iterator pointers. - * see issue #101765 */ -- -+ bytesiterobject *it = _bytesiterobject_CAST(self); - if (it->it_seq != NULL) { - return Py_BuildValue("N(O)n", iter, it->it_seq, it->it_index); - } else { -@@ -2533,11 +2571,13 @@ - } - - static PyObject * --bytearrayiter_setstate(bytesiterobject *it, PyObject *state) -+bytearrayiter_setstate(PyObject *self, PyObject *state) - { - Py_ssize_t index = PyLong_AsSsize_t(state); - if (index == -1 && PyErr_Occurred()) - return NULL; -+ -+ bytesiterobject *it = _bytesiterobject_CAST(self); - if (it->it_seq != NULL) { - if (index < 0) - index = 0; -@@ -2551,11 +2591,11 @@ - PyDoc_STRVAR(setstate_doc, "Set state information for unpickling."); - - static PyMethodDef bytearrayiter_methods[] = { -- {"__length_hint__", (PyCFunction)bytearrayiter_length_hint, METH_NOARGS, -+ {"__length_hint__", bytearrayiter_length_hint, METH_NOARGS, - length_hint_doc}, -- {"__reduce__", (PyCFunction)bytearrayiter_reduce, METH_NOARGS, -+ {"__reduce__", bytearrayiter_reduce, METH_NOARGS, - bytearray_reduce__doc__}, -- {"__setstate__", (PyCFunction)bytearrayiter_setstate, METH_O, -+ {"__setstate__", bytearrayiter_setstate, METH_O, - setstate_doc}, - {NULL, NULL} /* sentinel */ - }; -@@ -2566,7 +2606,7 @@ - sizeof(bytesiterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ -- (destructor)bytearrayiter_dealloc, /* tp_dealloc */ -+ bytearrayiter_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ -@@ -2583,12 +2623,12 @@ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ -- (traverseproc)bytearrayiter_traverse, /* tp_traverse */ -+ bytearrayiter_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ -- (iternextfunc)bytearrayiter_next, /* tp_iternext */ -+ bytearrayiter_next, /* tp_iternext */ - bytearrayiter_methods, /* tp_methods */ - 0, - }; -diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c -index 533089d25cd..b3d1c425ad1 100644 ---- a/Objects/bytesobject.c -+++ b/Objects/bytesobject.c -@@ -51,6 +51,33 @@ - } - - -+static inline void -+set_ob_shash(PyBytesObject *a, Py_hash_t hash) -+{ -+_Py_COMP_DIAG_PUSH -+_Py_COMP_DIAG_IGNORE_DEPR_DECLS -+#ifdef Py_GIL_DISABLED -+ _Py_atomic_store_ssize_relaxed(&a->ob_shash, hash); -+#else -+ a->ob_shash = hash; -+#endif -+_Py_COMP_DIAG_POP -+} -+ -+static inline Py_hash_t -+get_ob_shash(PyBytesObject *a) -+{ -+_Py_COMP_DIAG_PUSH -+_Py_COMP_DIAG_IGNORE_DEPR_DECLS -+#ifdef Py_GIL_DISABLED -+ return _Py_atomic_load_ssize_relaxed(&a->ob_shash); -+#else -+ return a->ob_shash; -+#endif -+_Py_COMP_DIAG_POP -+} -+ -+ - /* - For PyBytes_FromString(), the parameter 'str' points to a null-terminated - string containing exactly 'size' bytes. -@@ -98,10 +125,7 @@ - return PyErr_NoMemory(); - } - _PyObject_InitVar((PyVarObject*)op, &PyBytes_Type, size); --_Py_COMP_DIAG_PUSH --_Py_COMP_DIAG_IGNORE_DEPR_DECLS -- op->ob_shash = -1; --_Py_COMP_DIAG_POP -+ set_ob_shash(op, -1); - if (!use_calloc) { - op->ob_sval[size] = '\0'; - } -@@ -165,10 +189,7 @@ - return PyErr_NoMemory(); - } - _PyObject_InitVar((PyVarObject*)op, &PyBytes_Type, size); --_Py_COMP_DIAG_PUSH --_Py_COMP_DIAG_IGNORE_DEPR_DECLS -- op->ob_shash = -1; --_Py_COMP_DIAG_POP -+ set_ob_shash(op, -1); - memcpy(op->ob_sval, str, size+1); - return (PyObject *) op; - } -@@ -1184,7 +1205,8 @@ - unsigned char c = *first_invalid_escape; - if ('4' <= c && c <= '7') { - if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, -- "invalid octal escape sequence '\\%.3s'", -+ "b\"\\%.3s\" is an invalid octal escape sequence. " -+ "Such sequences will not work in the future. ", - first_invalid_escape) < 0) - { - Py_DECREF(result); -@@ -1193,7 +1215,8 @@ - } - else { - if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, -- "invalid escape sequence '\\%c'", -+ "b\"\\%c\" is an invalid escape sequence. " -+ "Such sequences will not work in the future. ", - c) < 0) - { - Py_DECREF(result); -@@ -1202,7 +1225,6 @@ - } - } - return result; -- - } - /* -------------------------------------------------------------------- */ - /* object api */ -@@ -1485,10 +1507,7 @@ - return PyErr_NoMemory(); - } - _PyObject_InitVar((PyVarObject*)op, &PyBytes_Type, size); --_Py_COMP_DIAG_PUSH --_Py_COMP_DIAG_IGNORE_DEPR_DECLS -- op->ob_shash = -1; --_Py_COMP_DIAG_POP -+ set_ob_shash(op, -1); - op->ob_sval[size] = '\0'; - - _PyBytes_Repeat(op->ob_sval, size, a->ob_sval, Py_SIZE(a)); -@@ -1597,14 +1616,13 @@ - bytes_hash(PyObject *self) - { - PyBytesObject *a = _PyBytes_CAST(self); --_Py_COMP_DIAG_PUSH --_Py_COMP_DIAG_IGNORE_DEPR_DECLS -- if (a->ob_shash == -1) { -+ Py_hash_t hash = get_ob_shash(a); -+ if (hash == -1) { - /* Can't fail */ -- a->ob_shash = Py_HashBuffer(a->ob_sval, Py_SIZE(a)); -+ hash = Py_HashBuffer(a->ob_sval, Py_SIZE(a)); -+ set_ob_shash(a, hash); - } -- return a->ob_shash; --_Py_COMP_DIAG_POP -+ return hash; - } - - static PyObject* -@@ -3004,10 +3022,7 @@ - if (obj == NULL) { - return NULL; - } --_Py_COMP_DIAG_PUSH --_Py_COMP_DIAG_IGNORE_DEPR_DECLS -- obj->ob_shash = -1; --_Py_COMP_DIAG_POP -+ set_ob_shash(obj, -1); - return (PyObject*)obj; - } - -@@ -3024,11 +3039,8 @@ - if (pnew != NULL) { - memcpy(PyBytes_AS_STRING(pnew), - PyBytes_AS_STRING(tmp), n+1); --_Py_COMP_DIAG_PUSH --_Py_COMP_DIAG_IGNORE_DEPR_DECLS -- ((PyBytesObject *)pnew)->ob_shash = -- ((PyBytesObject *)tmp)->ob_shash; --_Py_COMP_DIAG_POP -+ set_ob_shash((PyBytesObject *)pnew, -+ get_ob_shash((PyBytesObject *)tmp)); - } - return pnew; - } -@@ -3074,7 +3086,7 @@ - bytes_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ -- (richcmpfunc)bytes_richcompare, /* tp_richcompare */ -+ bytes_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - bytes_iter, /* tp_iter */ - 0, /* tp_iternext */ -@@ -3221,10 +3233,7 @@ - sv = (PyBytesObject *) *pv; - Py_SET_SIZE(sv, newsize); - sv->ob_sval[newsize] = '\0'; --_Py_COMP_DIAG_PUSH --_Py_COMP_DIAG_IGNORE_DEPR_DECLS -- sv->ob_shash = -1; /* invalidate cached hash value */ --_Py_COMP_DIAG_POP -+ set_ob_shash(sv, -1); /* invalidate cached hash value */ - return 0; - } - -@@ -3237,24 +3246,29 @@ - PyBytesObject *it_seq; /* Set to NULL when iterator is exhausted */ - } striterobject; - -+#define _striterobject_CAST(op) ((striterobject *)(op)) -+ - static void --striter_dealloc(striterobject *it) -+striter_dealloc(PyObject *op) - { -+ striterobject *it = _striterobject_CAST(op); - _PyObject_GC_UNTRACK(it); - Py_XDECREF(it->it_seq); - PyObject_GC_Del(it); - } - - static int --striter_traverse(striterobject *it, visitproc visit, void *arg) -+striter_traverse(PyObject *op, visitproc visit, void *arg) - { -+ striterobject *it = _striterobject_CAST(op); - Py_VISIT(it->it_seq); - return 0; - } - - static PyObject * --striter_next(striterobject *it) -+striter_next(PyObject *op) - { -+ striterobject *it = _striterobject_CAST(op); - PyBytesObject *seq; - - assert(it != NULL); -@@ -3274,8 +3288,9 @@ - } - - static PyObject * --striter_len(striterobject *it, PyObject *Py_UNUSED(ignored)) -+striter_len(PyObject *op, PyObject *Py_UNUSED(ignored)) - { -+ striterobject *it = _striterobject_CAST(op); - Py_ssize_t len = 0; - if (it->it_seq) - len = PyBytes_GET_SIZE(it->it_seq) - it->it_index; -@@ -3286,14 +3301,14 @@ - "Private method returning an estimate of len(list(it))."); - - static PyObject * --striter_reduce(striterobject *it, PyObject *Py_UNUSED(ignored)) -+striter_reduce(PyObject *op, PyObject *Py_UNUSED(ignored)) - { - PyObject *iter = _PyEval_GetBuiltin(&_Py_ID(iter)); - - /* _PyEval_GetBuiltin can invoke arbitrary code, - * call must be before access of iterator pointers. - * see issue #101765 */ -- -+ striterobject *it = _striterobject_CAST(op); - if (it->it_seq != NULL) { - return Py_BuildValue("N(O)n", iter, it->it_seq, it->it_index); - } else { -@@ -3304,11 +3319,12 @@ - PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); - - static PyObject * --striter_setstate(striterobject *it, PyObject *state) -+striter_setstate(PyObject *op, PyObject *state) - { - Py_ssize_t index = PyLong_AsSsize_t(state); - if (index == -1 && PyErr_Occurred()) - return NULL; -+ striterobject *it = _striterobject_CAST(op); - if (it->it_seq != NULL) { - if (index < 0) - index = 0; -@@ -3322,12 +3338,9 @@ - PyDoc_STRVAR(setstate_doc, "Set state information for unpickling."); - - static PyMethodDef striter_methods[] = { -- {"__length_hint__", (PyCFunction)striter_len, METH_NOARGS, -- length_hint_doc}, -- {"__reduce__", (PyCFunction)striter_reduce, METH_NOARGS, -- reduce_doc}, -- {"__setstate__", (PyCFunction)striter_setstate, METH_O, -- setstate_doc}, -+ {"__length_hint__", striter_len, METH_NOARGS, length_hint_doc}, -+ {"__reduce__", striter_reduce, METH_NOARGS, reduce_doc}, -+ {"__setstate__", striter_setstate, METH_O, setstate_doc}, - {NULL, NULL} /* sentinel */ - }; - -@@ -3337,7 +3350,7 @@ - sizeof(striterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ -- (destructor)striter_dealloc, /* tp_dealloc */ -+ striter_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ -@@ -3354,12 +3367,12 @@ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ - 0, /* tp_doc */ -- (traverseproc)striter_traverse, /* tp_traverse */ -+ striter_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ -- (iternextfunc)striter_next, /* tp_iternext */ -+ striter_next, /* tp_iternext */ - striter_methods, /* tp_methods */ - 0, - }; -diff --git a/Objects/capsule.c b/Objects/capsule.c -index 28965e0f21b..16ae65905ef 100644 ---- a/Objects/capsule.c -+++ b/Objects/capsule.c -@@ -18,6 +18,8 @@ - } PyCapsule; - - -+#define _PyCapsule_CAST(op) ((PyCapsule *)(op)) -+ - - static int - _is_legal_capsule(PyObject *op, const char *invalid_capsule) -@@ -284,7 +286,7 @@ - static void - capsule_dealloc(PyObject *op) - { -- PyCapsule *capsule = (PyCapsule *)op; -+ PyCapsule *capsule = _PyCapsule_CAST(op); - PyObject_GC_UnTrack(op); - if (capsule->destructor) { - capsule->destructor(op); -@@ -296,7 +298,7 @@ - static PyObject * - capsule_repr(PyObject *o) - { -- PyCapsule *capsule = (PyCapsule *)o; -+ PyCapsule *capsule = _PyCapsule_CAST(o); - const char *name; - const char *quote; - -@@ -314,28 +316,27 @@ - - - static int --capsule_traverse(PyCapsule *capsule, visitproc visit, void *arg) -+capsule_traverse(PyObject *self, visitproc visit, void *arg) - { - // Capsule object is only tracked by the GC - // if _PyCapsule_SetTraverse() is called, but - // this can still be manually triggered by gc.get_referents() -- -+ PyCapsule *capsule = _PyCapsule_CAST(self); - if (capsule->traverse_func != NULL) { -- return capsule->traverse_func((PyObject*)capsule, visit, arg); -+ return capsule->traverse_func(self, visit, arg); - } -- - return 0; - } - - - static int --capsule_clear(PyCapsule *capsule) -+capsule_clear(PyObject *self) - { - // Capsule object is only tracked by the GC - // if _PyCapsule_SetTraverse() is called -+ PyCapsule *capsule = _PyCapsule_CAST(self); - assert(capsule->clear_func != NULL); -- -- return capsule->clear_func((PyObject*)capsule); -+ return capsule->clear_func(self); - } - - -@@ -358,8 +359,8 @@ - .tp_dealloc = capsule_dealloc, - .tp_repr = capsule_repr, - .tp_doc = PyCapsule_Type__doc__, -- .tp_traverse = (traverseproc)capsule_traverse, -- .tp_clear = (inquiry)capsule_clear, -+ .tp_traverse = capsule_traverse, -+ .tp_clear = capsule_clear, - }; - - -diff --git a/Objects/classobject.c b/Objects/classobject.c -index 775894ad5a7..58e1d179773 100644 ---- a/Objects/classobject.c -+++ b/Objects/classobject.c -@@ -3,6 +3,7 @@ - #include "Python.h" - #include "pycore_call.h" // _PyObject_VectorcallTstate() - #include "pycore_ceval.h" // _PyEval_GetBuiltin() -+#include "pycore_freelist.h" - #include "pycore_object.h" - #include "pycore_pyerrors.h" - #include "pycore_pystate.h" // _PyThreadState_GET() -@@ -112,9 +113,12 @@ - PyErr_BadInternalCall(); - return NULL; - } -- PyMethodObject *im = PyObject_GC_New(PyMethodObject, &PyMethod_Type); -+ PyMethodObject *im = _Py_FREELIST_POP(PyMethodObject, pymethodobjects); - if (im == NULL) { -- return NULL; -+ im = PyObject_GC_New(PyMethodObject, &PyMethod_Type); -+ if (im == NULL) { -+ return NULL; -+ } - } - im->im_weakreflist = NULL; - im->im_func = Py_NewRef(func); -@@ -245,7 +249,8 @@ - PyObject_ClearWeakRefs((PyObject *)im); - Py_DECREF(im->im_func); - Py_XDECREF(im->im_self); -- PyObject_GC_Del(im); -+ assert(Py_IS_TYPE(self, &PyMethod_Type)); -+ _Py_FREELIST_FREE(pymethodobjects, (PyObject *)im, PyObject_GC_Del); - } - - static PyObject * -diff --git a/Objects/clinic/bytearrayobject.c.h b/Objects/clinic/bytearrayobject.c.h -index dee7c1e8bff..03b5a8a516c 100644 ---- a/Objects/clinic/bytearrayobject.c.h -+++ b/Objects/clinic/bytearrayobject.c.h -@@ -123,7 +123,7 @@ - Py_ssize_t end); - - static PyObject * --bytearray_find(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) -+bytearray_find(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *sub; -@@ -147,7 +147,7 @@ - goto exit; - } - skip_optional: -- return_value = bytearray_find_impl(self, sub, start, end); -+ return_value = bytearray_find_impl((PyByteArrayObject *)self, sub, start, end); - - exit: - return return_value; -@@ -172,7 +172,7 @@ - Py_ssize_t start, Py_ssize_t end); - - static PyObject * --bytearray_count(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) -+bytearray_count(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *sub; -@@ -196,7 +196,7 @@ - goto exit; - } - skip_optional: -- return_value = bytearray_count_impl(self, sub, start, end); -+ return_value = bytearray_count_impl((PyByteArrayObject *)self, sub, start, end); - - exit: - return return_value; -@@ -215,9 +215,9 @@ - bytearray_clear_impl(PyByteArrayObject *self); - - static PyObject * --bytearray_clear(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored)) -+bytearray_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return bytearray_clear_impl(self); -+ return bytearray_clear_impl((PyByteArrayObject *)self); - } - - PyDoc_STRVAR(bytearray_copy__doc__, -@@ -233,9 +233,9 @@ - bytearray_copy_impl(PyByteArrayObject *self); - - static PyObject * --bytearray_copy(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored)) -+bytearray_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return bytearray_copy_impl(self); -+ return bytearray_copy_impl((PyByteArrayObject *)self); - } - - PyDoc_STRVAR(bytearray_index__doc__, -@@ -259,7 +259,7 @@ - Py_ssize_t start, Py_ssize_t end); - - static PyObject * --bytearray_index(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) -+bytearray_index(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *sub; -@@ -283,7 +283,7 @@ - goto exit; - } - skip_optional: -- return_value = bytearray_index_impl(self, sub, start, end); -+ return_value = bytearray_index_impl((PyByteArrayObject *)self, sub, start, end); - - exit: - return return_value; -@@ -310,7 +310,7 @@ - Py_ssize_t start, Py_ssize_t end); - - static PyObject * --bytearray_rfind(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) -+bytearray_rfind(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *sub; -@@ -334,7 +334,7 @@ - goto exit; - } - skip_optional: -- return_value = bytearray_rfind_impl(self, sub, start, end); -+ return_value = bytearray_rfind_impl((PyByteArrayObject *)self, sub, start, end); - - exit: - return return_value; -@@ -361,7 +361,7 @@ - Py_ssize_t start, Py_ssize_t end); - - static PyObject * --bytearray_rindex(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) -+bytearray_rindex(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *sub; -@@ -385,7 +385,7 @@ - goto exit; - } - skip_optional: -- return_value = bytearray_rindex_impl(self, sub, start, end); -+ return_value = bytearray_rindex_impl((PyByteArrayObject *)self, sub, start, end); - - exit: - return return_value; -@@ -412,7 +412,7 @@ - Py_ssize_t start, Py_ssize_t end); - - static PyObject * --bytearray_startswith(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) -+bytearray_startswith(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *subobj; -@@ -436,7 +436,7 @@ - goto exit; - } - skip_optional: -- return_value = bytearray_startswith_impl(self, subobj, start, end); -+ return_value = bytearray_startswith_impl((PyByteArrayObject *)self, subobj, start, end); - - exit: - return return_value; -@@ -463,7 +463,7 @@ - Py_ssize_t start, Py_ssize_t end); - - static PyObject * --bytearray_endswith(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) -+bytearray_endswith(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *subobj; -@@ -487,7 +487,7 @@ - goto exit; - } - skip_optional: -- return_value = bytearray_endswith_impl(self, subobj, start, end); -+ return_value = bytearray_endswith_impl((PyByteArrayObject *)self, subobj, start, end); - - exit: - return return_value; -@@ -510,7 +510,7 @@ - bytearray_removeprefix_impl(PyByteArrayObject *self, Py_buffer *prefix); - - static PyObject * --bytearray_removeprefix(PyByteArrayObject *self, PyObject *arg) -+bytearray_removeprefix(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - Py_buffer prefix = {NULL, NULL}; -@@ -518,7 +518,7 @@ - if (PyObject_GetBuffer(arg, &prefix, PyBUF_SIMPLE) != 0) { - goto exit; - } -- return_value = bytearray_removeprefix_impl(self, &prefix); -+ return_value = bytearray_removeprefix_impl((PyByteArrayObject *)self, &prefix); - - exit: - /* Cleanup for prefix */ -@@ -546,7 +546,7 @@ - bytearray_removesuffix_impl(PyByteArrayObject *self, Py_buffer *suffix); - - static PyObject * --bytearray_removesuffix(PyByteArrayObject *self, PyObject *arg) -+bytearray_removesuffix(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - Py_buffer suffix = {NULL, NULL}; -@@ -554,7 +554,7 @@ - if (PyObject_GetBuffer(arg, &suffix, PyBUF_SIMPLE) != 0) { - goto exit; - } -- return_value = bytearray_removesuffix_impl(self, &suffix); -+ return_value = bytearray_removesuffix_impl((PyByteArrayObject *)self, &suffix); - - exit: - /* Cleanup for suffix */ -@@ -565,6 +565,45 @@ - return return_value; - } - -+PyDoc_STRVAR(bytearray_resize__doc__, -+"resize($self, size, /)\n" -+"--\n" -+"\n" -+"Resize the internal buffer of bytearray to len.\n" -+"\n" -+" size\n" -+" New size to resize to.."); -+ -+#define BYTEARRAY_RESIZE_METHODDEF \ -+ {"resize", (PyCFunction)bytearray_resize, METH_O, bytearray_resize__doc__}, -+ -+static PyObject * -+bytearray_resize_impl(PyByteArrayObject *self, Py_ssize_t size); -+ -+static PyObject * -+bytearray_resize(PyObject *self, PyObject *arg) -+{ -+ PyObject *return_value = NULL; -+ Py_ssize_t size; -+ -+ { -+ Py_ssize_t ival = -1; -+ PyObject *iobj = _PyNumber_Index(arg); -+ if (iobj != NULL) { -+ ival = PyLong_AsSsize_t(iobj); -+ Py_DECREF(iobj); -+ } -+ if (ival == -1 && PyErr_Occurred()) { -+ goto exit; -+ } -+ size = ival; -+ } -+ return_value = bytearray_resize_impl((PyByteArrayObject *)self, size); -+ -+exit: -+ return return_value; -+} -+ - PyDoc_STRVAR(bytearray_translate__doc__, - "translate($self, table, /, delete=b\'\')\n" - "--\n" -@@ -585,7 +624,7 @@ - PyObject *deletechars); - - static PyObject * --bytearray_translate(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+bytearray_translate(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -629,7 +668,7 @@ - } - deletechars = args[1]; - skip_optional_pos: -- return_value = bytearray_translate_impl(self, table, deletechars); -+ return_value = bytearray_translate_impl((PyByteArrayObject *)self, table, deletechars); - - exit: - return return_value; -@@ -704,7 +743,7 @@ - Py_buffer *new, Py_ssize_t count); - - static PyObject * --bytearray_replace(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) -+bytearray_replace(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - Py_buffer old = {NULL, NULL}; -@@ -736,7 +775,7 @@ - count = ival; - } - skip_optional: -- return_value = bytearray_replace_impl(self, &old, &new, count); -+ return_value = bytearray_replace_impl((PyByteArrayObject *)self, &old, &new, count); - - exit: - /* Cleanup for old */ -@@ -773,7 +812,7 @@ - Py_ssize_t maxsplit); - - static PyObject * --bytearray_split(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+bytearray_split(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -833,7 +872,7 @@ - maxsplit = ival; - } - skip_optional_pos: -- return_value = bytearray_split_impl(self, sep, maxsplit); -+ return_value = bytearray_split_impl((PyByteArrayObject *)self, sep, maxsplit); - - exit: - return return_value; -@@ -896,7 +935,7 @@ - Py_ssize_t maxsplit); - - static PyObject * --bytearray_rsplit(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+bytearray_rsplit(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -956,7 +995,7 @@ - maxsplit = ival; - } - skip_optional_pos: -- return_value = bytearray_rsplit_impl(self, sep, maxsplit); -+ return_value = bytearray_rsplit_impl((PyByteArrayObject *)self, sep, maxsplit); - - exit: - return return_value; -@@ -975,9 +1014,9 @@ - bytearray_reverse_impl(PyByteArrayObject *self); - - static PyObject * --bytearray_reverse(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored)) -+bytearray_reverse(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return bytearray_reverse_impl(self); -+ return bytearray_reverse_impl((PyByteArrayObject *)self); - } - - PyDoc_STRVAR(bytearray_insert__doc__, -@@ -998,7 +1037,7 @@ - bytearray_insert_impl(PyByteArrayObject *self, Py_ssize_t index, int item); - - static PyObject * --bytearray_insert(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) -+bytearray_insert(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - Py_ssize_t index; -@@ -1022,7 +1061,7 @@ - if (!_getbytevalue(args[1], &item)) { - goto exit; - } -- return_value = bytearray_insert_impl(self, index, item); -+ return_value = bytearray_insert_impl((PyByteArrayObject *)self, index, item); - - exit: - return return_value; -@@ -1044,7 +1083,7 @@ - bytearray_append_impl(PyByteArrayObject *self, int item); - - static PyObject * --bytearray_append(PyByteArrayObject *self, PyObject *arg) -+bytearray_append(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - int item; -@@ -1052,7 +1091,7 @@ - if (!_getbytevalue(arg, &item)) { - goto exit; - } -- return_value = bytearray_append_impl(self, item); -+ return_value = bytearray_append_impl((PyByteArrayObject *)self, item); - - exit: - return return_value; -@@ -1089,7 +1128,7 @@ - bytearray_pop_impl(PyByteArrayObject *self, Py_ssize_t index); - - static PyObject * --bytearray_pop(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) -+bytearray_pop(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - Py_ssize_t index = -1; -@@ -1113,7 +1152,7 @@ - index = ival; - } - skip_optional: -- return_value = bytearray_pop_impl(self, index); -+ return_value = bytearray_pop_impl((PyByteArrayObject *)self, index); - - exit: - return return_value; -@@ -1135,7 +1174,7 @@ - bytearray_remove_impl(PyByteArrayObject *self, int value); - - static PyObject * --bytearray_remove(PyByteArrayObject *self, PyObject *arg) -+bytearray_remove(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - int value; -@@ -1143,7 +1182,7 @@ - if (!_getbytevalue(arg, &value)) { - goto exit; - } -- return_value = bytearray_remove_impl(self, value); -+ return_value = bytearray_remove_impl((PyByteArrayObject *)self, value); - - exit: - return return_value; -@@ -1164,7 +1203,7 @@ - bytearray_strip_impl(PyByteArrayObject *self, PyObject *bytes); - - static PyObject * --bytearray_strip(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) -+bytearray_strip(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *bytes = Py_None; -@@ -1177,7 +1216,7 @@ - } - bytes = args[0]; - skip_optional: -- return_value = bytearray_strip_impl(self, bytes); -+ return_value = bytearray_strip_impl((PyByteArrayObject *)self, bytes); - - exit: - return return_value; -@@ -1198,7 +1237,7 @@ - bytearray_lstrip_impl(PyByteArrayObject *self, PyObject *bytes); - - static PyObject * --bytearray_lstrip(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) -+bytearray_lstrip(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *bytes = Py_None; -@@ -1211,7 +1250,7 @@ - } - bytes = args[0]; - skip_optional: -- return_value = bytearray_lstrip_impl(self, bytes); -+ return_value = bytearray_lstrip_impl((PyByteArrayObject *)self, bytes); - - exit: - return return_value; -@@ -1232,7 +1271,7 @@ - bytearray_rstrip_impl(PyByteArrayObject *self, PyObject *bytes); - - static PyObject * --bytearray_rstrip(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) -+bytearray_rstrip(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *bytes = Py_None; -@@ -1245,7 +1284,7 @@ - } - bytes = args[0]; - skip_optional: -- return_value = bytearray_rstrip_impl(self, bytes); -+ return_value = bytearray_rstrip_impl((PyByteArrayObject *)self, bytes); - - exit: - return return_value; -@@ -1274,7 +1313,7 @@ - const char *errors); - - static PyObject * --bytearray_decode(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+bytearray_decode(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -1347,7 +1386,7 @@ - goto exit; - } - skip_optional_pos: -- return_value = bytearray_decode_impl(self, encoding, errors); -+ return_value = bytearray_decode_impl((PyByteArrayObject *)self, encoding, errors); - - exit: - return return_value; -@@ -1382,7 +1421,7 @@ - bytearray_splitlines_impl(PyByteArrayObject *self, int keepends); - - static PyObject * --bytearray_splitlines(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+bytearray_splitlines(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -1427,7 +1466,7 @@ - goto exit; - } - skip_optional_pos: -- return_value = bytearray_splitlines_impl(self, keepends); -+ return_value = bytearray_splitlines_impl((PyByteArrayObject *)self, keepends); - - exit: - return return_value; -@@ -1495,7 +1534,7 @@ - bytearray_hex_impl(PyByteArrayObject *self, PyObject *sep, int bytes_per_sep); - - static PyObject * --bytearray_hex(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+bytearray_hex(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -1547,7 +1586,7 @@ - goto exit; - } - skip_optional_pos: -- return_value = bytearray_hex_impl(self, sep, bytes_per_sep); -+ return_value = bytearray_hex_impl((PyByteArrayObject *)self, sep, bytes_per_sep); - - exit: - return return_value; -@@ -1566,9 +1605,9 @@ - bytearray_reduce_impl(PyByteArrayObject *self); - - static PyObject * --bytearray_reduce(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored)) -+bytearray_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return bytearray_reduce_impl(self); -+ return bytearray_reduce_impl((PyByteArrayObject *)self); - } - - PyDoc_STRVAR(bytearray_reduce_ex__doc__, -@@ -1584,7 +1623,7 @@ - bytearray_reduce_ex_impl(PyByteArrayObject *self, int proto); - - static PyObject * --bytearray_reduce_ex(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) -+bytearray_reduce_ex(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - int proto = 0; -@@ -1600,7 +1639,7 @@ - goto exit; - } - skip_optional: -- return_value = bytearray_reduce_ex_impl(self, proto); -+ return_value = bytearray_reduce_ex_impl((PyByteArrayObject *)self, proto); - - exit: - return return_value; -@@ -1619,8 +1658,8 @@ - bytearray_sizeof_impl(PyByteArrayObject *self); - - static PyObject * --bytearray_sizeof(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored)) -+bytearray_sizeof(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return bytearray_sizeof_impl(self); -+ return bytearray_sizeof_impl((PyByteArrayObject *)self); - } --/*[clinic end generated code: output=4488e38e7ffcc6ec input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=41bb67a8a181e733 input=a9049054013a1b77]*/ -diff --git a/Objects/clinic/bytesobject.c.h b/Objects/clinic/bytesobject.c.h -index d2c6cc88770..9aef736428a 100644 ---- a/Objects/clinic/bytesobject.c.h -+++ b/Objects/clinic/bytesobject.c.h -@@ -22,9 +22,9 @@ - bytes___bytes___impl(PyBytesObject *self); - - static PyObject * --bytes___bytes__(PyBytesObject *self, PyObject *Py_UNUSED(ignored)) -+bytes___bytes__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return bytes___bytes___impl(self); -+ return bytes___bytes___impl((PyBytesObject *)self); - } - - PyDoc_STRVAR(bytes_split__doc__, -@@ -48,7 +48,7 @@ - bytes_split_impl(PyBytesObject *self, PyObject *sep, Py_ssize_t maxsplit); - - static PyObject * --bytes_split(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+bytes_split(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -108,7 +108,7 @@ - maxsplit = ival; - } - skip_optional_pos: -- return_value = bytes_split_impl(self, sep, maxsplit); -+ return_value = bytes_split_impl((PyBytesObject *)self, sep, maxsplit); - - exit: - return return_value; -@@ -134,7 +134,7 @@ - bytes_partition_impl(PyBytesObject *self, Py_buffer *sep); - - static PyObject * --bytes_partition(PyBytesObject *self, PyObject *arg) -+bytes_partition(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - Py_buffer sep = {NULL, NULL}; -@@ -142,7 +142,7 @@ - if (PyObject_GetBuffer(arg, &sep, PyBUF_SIMPLE) != 0) { - goto exit; - } -- return_value = bytes_partition_impl(self, &sep); -+ return_value = bytes_partition_impl((PyBytesObject *)self, &sep); - - exit: - /* Cleanup for sep */ -@@ -173,7 +173,7 @@ - bytes_rpartition_impl(PyBytesObject *self, Py_buffer *sep); - - static PyObject * --bytes_rpartition(PyBytesObject *self, PyObject *arg) -+bytes_rpartition(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - Py_buffer sep = {NULL, NULL}; -@@ -181,7 +181,7 @@ - if (PyObject_GetBuffer(arg, &sep, PyBUF_SIMPLE) != 0) { - goto exit; - } -- return_value = bytes_rpartition_impl(self, &sep); -+ return_value = bytes_rpartition_impl((PyBytesObject *)self, &sep); - - exit: - /* Cleanup for sep */ -@@ -215,7 +215,7 @@ - bytes_rsplit_impl(PyBytesObject *self, PyObject *sep, Py_ssize_t maxsplit); - - static PyObject * --bytes_rsplit(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+bytes_rsplit(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -275,7 +275,7 @@ - maxsplit = ival; - } - skip_optional_pos: -- return_value = bytes_rsplit_impl(self, sep, maxsplit); -+ return_value = bytes_rsplit_impl((PyBytesObject *)self, sep, maxsplit); - - exit: - return return_value; -@@ -317,7 +317,7 @@ - Py_ssize_t end); - - static PyObject * --bytes_find(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs) -+bytes_find(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *sub; -@@ -341,7 +341,7 @@ - goto exit; - } - skip_optional: -- return_value = bytes_find_impl(self, sub, start, end); -+ return_value = bytes_find_impl((PyBytesObject *)self, sub, start, end); - - exit: - return return_value; -@@ -368,7 +368,7 @@ - Py_ssize_t end); - - static PyObject * --bytes_index(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs) -+bytes_index(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *sub; -@@ -392,7 +392,7 @@ - goto exit; - } - skip_optional: -- return_value = bytes_index_impl(self, sub, start, end); -+ return_value = bytes_index_impl((PyBytesObject *)self, sub, start, end); - - exit: - return return_value; -@@ -419,7 +419,7 @@ - Py_ssize_t end); - - static PyObject * --bytes_rfind(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs) -+bytes_rfind(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *sub; -@@ -443,7 +443,7 @@ - goto exit; - } - skip_optional: -- return_value = bytes_rfind_impl(self, sub, start, end); -+ return_value = bytes_rfind_impl((PyBytesObject *)self, sub, start, end); - - exit: - return return_value; -@@ -470,7 +470,7 @@ - Py_ssize_t end); - - static PyObject * --bytes_rindex(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs) -+bytes_rindex(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *sub; -@@ -494,7 +494,7 @@ - goto exit; - } - skip_optional: -- return_value = bytes_rindex_impl(self, sub, start, end); -+ return_value = bytes_rindex_impl((PyBytesObject *)self, sub, start, end); - - exit: - return return_value; -@@ -515,7 +515,7 @@ - bytes_strip_impl(PyBytesObject *self, PyObject *bytes); - - static PyObject * --bytes_strip(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs) -+bytes_strip(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *bytes = Py_None; -@@ -528,7 +528,7 @@ - } - bytes = args[0]; - skip_optional: -- return_value = bytes_strip_impl(self, bytes); -+ return_value = bytes_strip_impl((PyBytesObject *)self, bytes); - - exit: - return return_value; -@@ -549,7 +549,7 @@ - bytes_lstrip_impl(PyBytesObject *self, PyObject *bytes); - - static PyObject * --bytes_lstrip(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs) -+bytes_lstrip(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *bytes = Py_None; -@@ -562,7 +562,7 @@ - } - bytes = args[0]; - skip_optional: -- return_value = bytes_lstrip_impl(self, bytes); -+ return_value = bytes_lstrip_impl((PyBytesObject *)self, bytes); - - exit: - return return_value; -@@ -583,7 +583,7 @@ - bytes_rstrip_impl(PyBytesObject *self, PyObject *bytes); - - static PyObject * --bytes_rstrip(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs) -+bytes_rstrip(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *bytes = Py_None; -@@ -596,7 +596,7 @@ - } - bytes = args[0]; - skip_optional: -- return_value = bytes_rstrip_impl(self, bytes); -+ return_value = bytes_rstrip_impl((PyBytesObject *)self, bytes); - - exit: - return return_value; -@@ -621,7 +621,7 @@ - Py_ssize_t end); - - static PyObject * --bytes_count(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs) -+bytes_count(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *sub; -@@ -645,7 +645,7 @@ - goto exit; - } - skip_optional: -- return_value = bytes_count_impl(self, sub, start, end); -+ return_value = bytes_count_impl((PyBytesObject *)self, sub, start, end); - - exit: - return return_value; -@@ -671,7 +671,7 @@ - PyObject *deletechars); - - static PyObject * --bytes_translate(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+bytes_translate(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -715,7 +715,7 @@ - } - deletechars = args[1]; - skip_optional_pos: -- return_value = bytes_translate_impl(self, table, deletechars); -+ return_value = bytes_translate_impl((PyBytesObject *)self, table, deletechars); - - exit: - return return_value; -@@ -790,7 +790,7 @@ - Py_ssize_t count); - - static PyObject * --bytes_replace(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs) -+bytes_replace(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - Py_buffer old = {NULL, NULL}; -@@ -822,7 +822,7 @@ - count = ival; - } - skip_optional: -- return_value = bytes_replace_impl(self, &old, &new, count); -+ return_value = bytes_replace_impl((PyBytesObject *)self, &old, &new, count); - - exit: - /* Cleanup for old */ -@@ -853,7 +853,7 @@ - bytes_removeprefix_impl(PyBytesObject *self, Py_buffer *prefix); - - static PyObject * --bytes_removeprefix(PyBytesObject *self, PyObject *arg) -+bytes_removeprefix(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - Py_buffer prefix = {NULL, NULL}; -@@ -861,7 +861,7 @@ - if (PyObject_GetBuffer(arg, &prefix, PyBUF_SIMPLE) != 0) { - goto exit; - } -- return_value = bytes_removeprefix_impl(self, &prefix); -+ return_value = bytes_removeprefix_impl((PyBytesObject *)self, &prefix); - - exit: - /* Cleanup for prefix */ -@@ -889,7 +889,7 @@ - bytes_removesuffix_impl(PyBytesObject *self, Py_buffer *suffix); - - static PyObject * --bytes_removesuffix(PyBytesObject *self, PyObject *arg) -+bytes_removesuffix(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - Py_buffer suffix = {NULL, NULL}; -@@ -897,7 +897,7 @@ - if (PyObject_GetBuffer(arg, &suffix, PyBUF_SIMPLE) != 0) { - goto exit; - } -- return_value = bytes_removesuffix_impl(self, &suffix); -+ return_value = bytes_removesuffix_impl((PyBytesObject *)self, &suffix); - - exit: - /* Cleanup for suffix */ -@@ -929,7 +929,7 @@ - Py_ssize_t start, Py_ssize_t end); - - static PyObject * --bytes_startswith(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs) -+bytes_startswith(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *subobj; -@@ -953,7 +953,7 @@ - goto exit; - } - skip_optional: -- return_value = bytes_startswith_impl(self, subobj, start, end); -+ return_value = bytes_startswith_impl((PyBytesObject *)self, subobj, start, end); - - exit: - return return_value; -@@ -980,7 +980,7 @@ - Py_ssize_t end); - - static PyObject * --bytes_endswith(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs) -+bytes_endswith(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *subobj; -@@ -1004,7 +1004,7 @@ - goto exit; - } - skip_optional: -- return_value = bytes_endswith_impl(self, subobj, start, end); -+ return_value = bytes_endswith_impl((PyBytesObject *)self, subobj, start, end); - - exit: - return return_value; -@@ -1033,7 +1033,7 @@ - const char *errors); - - static PyObject * --bytes_decode(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+bytes_decode(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -1106,7 +1106,7 @@ - goto exit; - } - skip_optional_pos: -- return_value = bytes_decode_impl(self, encoding, errors); -+ return_value = bytes_decode_impl((PyBytesObject *)self, encoding, errors); - - exit: - return return_value; -@@ -1128,7 +1128,7 @@ - bytes_splitlines_impl(PyBytesObject *self, int keepends); - - static PyObject * --bytes_splitlines(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+bytes_splitlines(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -1173,7 +1173,7 @@ - goto exit; - } - skip_optional_pos: -- return_value = bytes_splitlines_impl(self, keepends); -+ return_value = bytes_splitlines_impl((PyBytesObject *)self, keepends); - - exit: - return return_value; -@@ -1241,7 +1241,7 @@ - bytes_hex_impl(PyBytesObject *self, PyObject *sep, int bytes_per_sep); - - static PyObject * --bytes_hex(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+bytes_hex(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -1293,7 +1293,7 @@ - goto exit; - } - skip_optional_pos: -- return_value = bytes_hex_impl(self, sep, bytes_per_sep); -+ return_value = bytes_hex_impl((PyBytesObject *)self, sep, bytes_per_sep); - - exit: - return return_value; -@@ -1391,4 +1391,4 @@ - exit: - return return_value; - } --/*[clinic end generated code: output=fb7939a1983e463a input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=96fe2d6ef9ac8f6a input=a9049054013a1b77]*/ -diff --git a/Objects/clinic/classobject.c.h b/Objects/clinic/classobject.c.h -index 3e149c97324..5934f1c2a41 100644 ---- a/Objects/clinic/classobject.c.h -+++ b/Objects/clinic/classobject.c.h -@@ -16,9 +16,9 @@ - method___reduce___impl(PyMethodObject *self); - - static PyObject * --method___reduce__(PyMethodObject *self, PyObject *Py_UNUSED(ignored)) -+method___reduce__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return method___reduce___impl(self); -+ return method___reduce___impl((PyMethodObject *)self); - } - - PyDoc_STRVAR(method_new__doc__, -@@ -82,4 +82,4 @@ - exit: - return return_value; - } --/*[clinic end generated code: output=5a5e3f2d0726f189 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=ab546abf90aac94e input=a9049054013a1b77]*/ -diff --git a/Objects/clinic/codeobject.c.h b/Objects/clinic/codeobject.c.h -index 45738f767df..2184742cc0d 100644 ---- a/Objects/clinic/codeobject.c.h -+++ b/Objects/clinic/codeobject.c.h -@@ -174,7 +174,7 @@ - PyObject *co_exceptiontable); - - static PyObject * --code_replace(PyCodeObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+code_replace(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -204,24 +204,24 @@ - #undef KWTUPLE - PyObject *argsbuf[18]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; -- int co_argcount = self->co_argcount; -- int co_posonlyargcount = self->co_posonlyargcount; -- int co_kwonlyargcount = self->co_kwonlyargcount; -- int co_nlocals = self->co_nlocals; -- int co_stacksize = self->co_stacksize; -- int co_flags = self->co_flags; -- int co_firstlineno = self->co_firstlineno; -+ int co_argcount = ((PyCodeObject *)self)->co_argcount; -+ int co_posonlyargcount = ((PyCodeObject *)self)->co_posonlyargcount; -+ int co_kwonlyargcount = ((PyCodeObject *)self)->co_kwonlyargcount; -+ int co_nlocals = ((PyCodeObject *)self)->co_nlocals; -+ int co_stacksize = ((PyCodeObject *)self)->co_stacksize; -+ int co_flags = ((PyCodeObject *)self)->co_flags; -+ int co_firstlineno = ((PyCodeObject *)self)->co_firstlineno; - PyObject *co_code = NULL; -- PyObject *co_consts = self->co_consts; -- PyObject *co_names = self->co_names; -+ PyObject *co_consts = ((PyCodeObject *)self)->co_consts; -+ PyObject *co_names = ((PyCodeObject *)self)->co_names; - PyObject *co_varnames = NULL; - PyObject *co_freevars = NULL; - PyObject *co_cellvars = NULL; -- PyObject *co_filename = self->co_filename; -- PyObject *co_name = self->co_name; -- PyObject *co_qualname = self->co_qualname; -- PyObject *co_linetable = self->co_linetable; -- PyObject *co_exceptiontable = self->co_exceptiontable; -+ PyObject *co_filename = ((PyCodeObject *)self)->co_filename; -+ PyObject *co_name = ((PyCodeObject *)self)->co_name; -+ PyObject *co_qualname = ((PyCodeObject *)self)->co_qualname; -+ PyObject *co_linetable = ((PyCodeObject *)self)->co_linetable; -+ PyObject *co_exceptiontable = ((PyCodeObject *)self)->co_exceptiontable; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 0, /*maxpos*/ 0, /*minkw*/ 0, /*varpos*/ 0, argsbuf); -@@ -400,7 +400,7 @@ - } - co_exceptiontable = args[17]; - skip_optional_kwonly: -- return_value = code_replace_impl(self, co_argcount, co_posonlyargcount, co_kwonlyargcount, co_nlocals, co_stacksize, co_flags, co_firstlineno, co_code, co_consts, co_names, co_varnames, co_freevars, co_cellvars, co_filename, co_name, co_qualname, co_linetable, co_exceptiontable); -+ return_value = code_replace_impl((PyCodeObject *)self, co_argcount, co_posonlyargcount, co_kwonlyargcount, co_nlocals, co_stacksize, co_flags, co_firstlineno, co_code, co_consts, co_names, co_varnames, co_freevars, co_cellvars, co_filename, co_name, co_qualname, co_linetable, co_exceptiontable); - - exit: - return return_value; -@@ -421,7 +421,7 @@ - code__varname_from_oparg_impl(PyCodeObject *self, int oparg); - - static PyObject * --code__varname_from_oparg(PyCodeObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+code__varname_from_oparg(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -461,9 +461,9 @@ - if (oparg == -1 && PyErr_Occurred()) { - goto exit; - } -- return_value = code__varname_from_oparg_impl(self, oparg); -+ return_value = code__varname_from_oparg_impl((PyCodeObject *)self, oparg); - - exit: - return return_value; - } --/*[clinic end generated code: output=e919ea67a1bcf524 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=73861c79e93aaee5 input=a9049054013a1b77]*/ -diff --git a/Objects/clinic/complexobject.c.h b/Objects/clinic/complexobject.c.h -index 3c3d1071b6e..e00da1d960c 100644 ---- a/Objects/clinic/complexobject.c.h -+++ b/Objects/clinic/complexobject.c.h -@@ -21,9 +21,9 @@ - complex_conjugate_impl(PyComplexObject *self); - - static PyObject * --complex_conjugate(PyComplexObject *self, PyObject *Py_UNUSED(ignored)) -+complex_conjugate(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return complex_conjugate_impl(self); -+ return complex_conjugate_impl((PyComplexObject *)self); - } - - PyDoc_STRVAR(complex___getnewargs____doc__, -@@ -38,9 +38,9 @@ - complex___getnewargs___impl(PyComplexObject *self); - - static PyObject * --complex___getnewargs__(PyComplexObject *self, PyObject *Py_UNUSED(ignored)) -+complex___getnewargs__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return complex___getnewargs___impl(self); -+ return complex___getnewargs___impl((PyComplexObject *)self); - } - - PyDoc_STRVAR(complex___format____doc__, -@@ -56,7 +56,7 @@ - complex___format___impl(PyComplexObject *self, PyObject *format_spec); - - static PyObject * --complex___format__(PyComplexObject *self, PyObject *arg) -+complex___format__(PyObject *self, PyObject *arg) - { - PyObject *return_value = NULL; - PyObject *format_spec; -@@ -66,7 +66,7 @@ - goto exit; - } - format_spec = arg; -- return_value = complex___format___impl(self, format_spec); -+ return_value = complex___format___impl((PyComplexObject *)self, format_spec); - - exit: - return return_value; -@@ -85,9 +85,9 @@ - complex___complex___impl(PyComplexObject *self); - - static PyObject * --complex___complex__(PyComplexObject *self, PyObject *Py_UNUSED(ignored)) -+complex___complex__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return complex___complex___impl(self); -+ return complex___complex___impl((PyComplexObject *)self); - } - - PyDoc_STRVAR(complex_new__doc__, -@@ -170,4 +170,4 @@ - - #define COMPLEX_FROM_NUMBER_METHODDEF \ - {"from_number", (PyCFunction)complex_from_number, METH_O|METH_CLASS, complex_from_number__doc__}, --/*[clinic end generated code: output=8c49a41c5a7f0aee input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=252cddef7f9169a0 input=a9049054013a1b77]*/ -diff --git a/Objects/clinic/dictobject.c.h b/Objects/clinic/dictobject.c.h -index fb46c4c6433..c66916bb33a 100644 ---- a/Objects/clinic/dictobject.c.h -+++ b/Objects/clinic/dictobject.c.h -@@ -52,9 +52,9 @@ - dict_copy_impl(PyDictObject *self); - - static PyObject * --dict_copy(PyDictObject *self, PyObject *Py_UNUSED(ignored)) -+dict_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return dict_copy_impl(self); -+ return dict_copy_impl((PyDictObject *)self); - } - - PyDoc_STRVAR(dict___contains____doc__, -@@ -79,7 +79,7 @@ - dict_get_impl(PyDictObject *self, PyObject *key, PyObject *default_value); - - static PyObject * --dict_get(PyDictObject *self, PyObject *const *args, Py_ssize_t nargs) -+dict_get(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *key; -@@ -94,9 +94,7 @@ - } - default_value = args[1]; - skip_optional: -- Py_BEGIN_CRITICAL_SECTION(self); -- return_value = dict_get_impl(self, key, default_value); -- Py_END_CRITICAL_SECTION(); -+ return_value = dict_get_impl((PyDictObject *)self, key, default_value); - - exit: - return return_value; -@@ -118,7 +116,7 @@ - PyObject *default_value); - - static PyObject * --dict_setdefault(PyDictObject *self, PyObject *const *args, Py_ssize_t nargs) -+dict_setdefault(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *key; -@@ -134,7 +132,7 @@ - default_value = args[1]; - skip_optional: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = dict_setdefault_impl(self, key, default_value); -+ return_value = dict_setdefault_impl((PyDictObject *)self, key, default_value); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -154,9 +152,9 @@ - dict_clear_impl(PyDictObject *self); - - static PyObject * --dict_clear(PyDictObject *self, PyObject *Py_UNUSED(ignored)) -+dict_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return dict_clear_impl(self); -+ return dict_clear_impl((PyDictObject *)self); - } - - PyDoc_STRVAR(dict_pop__doc__, -@@ -175,7 +173,7 @@ - dict_pop_impl(PyDictObject *self, PyObject *key, PyObject *default_value); - - static PyObject * --dict_pop(PyDictObject *self, PyObject *const *args, Py_ssize_t nargs) -+dict_pop(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *key; -@@ -190,7 +188,7 @@ - } - default_value = args[1]; - skip_optional: -- return_value = dict_pop_impl(self, key, default_value); -+ return_value = dict_pop_impl((PyDictObject *)self, key, default_value); - - exit: - return return_value; -@@ -212,12 +210,12 @@ - dict_popitem_impl(PyDictObject *self); - - static PyObject * --dict_popitem(PyDictObject *self, PyObject *Py_UNUSED(ignored)) -+dict_popitem(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = dict_popitem_impl(self); -+ return_value = dict_popitem_impl((PyDictObject *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -236,9 +234,9 @@ - dict___sizeof___impl(PyDictObject *self); - - static PyObject * --dict___sizeof__(PyDictObject *self, PyObject *Py_UNUSED(ignored)) -+dict___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return dict___sizeof___impl(self); -+ return dict___sizeof___impl((PyDictObject *)self); - } - - PyDoc_STRVAR(dict___reversed____doc__, -@@ -254,9 +252,9 @@ - dict___reversed___impl(PyDictObject *self); - - static PyObject * --dict___reversed__(PyDictObject *self, PyObject *Py_UNUSED(ignored)) -+dict___reversed__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return dict___reversed___impl(self); -+ return dict___reversed___impl((PyDictObject *)self); - } - - PyDoc_STRVAR(dict_keys__doc__, -@@ -272,9 +270,9 @@ - dict_keys_impl(PyDictObject *self); - - static PyObject * --dict_keys(PyDictObject *self, PyObject *Py_UNUSED(ignored)) -+dict_keys(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return dict_keys_impl(self); -+ return dict_keys_impl((PyDictObject *)self); - } - - PyDoc_STRVAR(dict_items__doc__, -@@ -290,9 +288,9 @@ - dict_items_impl(PyDictObject *self); - - static PyObject * --dict_items(PyDictObject *self, PyObject *Py_UNUSED(ignored)) -+dict_items(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return dict_items_impl(self); -+ return dict_items_impl((PyDictObject *)self); - } - - PyDoc_STRVAR(dict_values__doc__, -@@ -308,8 +306,8 @@ - dict_values_impl(PyDictObject *self); - - static PyObject * --dict_values(PyDictObject *self, PyObject *Py_UNUSED(ignored)) -+dict_values(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return dict_values_impl(self); -+ return dict_values_impl((PyDictObject *)self); - } --/*[clinic end generated code: output=f3dd5f3fb8122aef input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=0f04bf0e7e6b130f input=a9049054013a1b77]*/ ---- /dev/null -+++ b/Objects/clinic/exceptions.c.h -@@ -0,0 +1,383 @@ -+/*[clinic input] -+preserve -+[clinic start generated code]*/ -+ -+#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() -+#include "pycore_modsupport.h" // _PyArg_BadArgument() -+ -+PyDoc_STRVAR(BaseException___reduce____doc__, -+"__reduce__($self, /)\n" -+"--\n" -+"\n"); -+ -+#define BASEEXCEPTION___REDUCE___METHODDEF \ -+ {"__reduce__", (PyCFunction)BaseException___reduce__, METH_NOARGS, BaseException___reduce____doc__}, -+ -+static PyObject * -+BaseException___reduce___impl(PyBaseExceptionObject *self); -+ -+static PyObject * -+BaseException___reduce__(PyObject *self, PyObject *Py_UNUSED(ignored)) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = BaseException___reduce___impl((PyBaseExceptionObject *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+PyDoc_STRVAR(BaseException___setstate____doc__, -+"__setstate__($self, state, /)\n" -+"--\n" -+"\n"); -+ -+#define BASEEXCEPTION___SETSTATE___METHODDEF \ -+ {"__setstate__", (PyCFunction)BaseException___setstate__, METH_O, BaseException___setstate____doc__}, -+ -+static PyObject * -+BaseException___setstate___impl(PyBaseExceptionObject *self, PyObject *state); -+ -+static PyObject * -+BaseException___setstate__(PyBaseExceptionObject *self, PyObject *state) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = BaseException___setstate___impl((PyBaseExceptionObject *)self, state); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+PyDoc_STRVAR(BaseException_with_traceback__doc__, -+"with_traceback($self, tb, /)\n" -+"--\n" -+"\n" -+"Set self.__traceback__ to tb and return self."); -+ -+#define BASEEXCEPTION_WITH_TRACEBACK_METHODDEF \ -+ {"with_traceback", (PyCFunction)BaseException_with_traceback, METH_O, BaseException_with_traceback__doc__}, -+ -+static PyObject * -+BaseException_with_traceback_impl(PyBaseExceptionObject *self, PyObject *tb); -+ -+static PyObject * -+BaseException_with_traceback(PyBaseExceptionObject *self, PyObject *tb) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = BaseException_with_traceback_impl((PyBaseExceptionObject *)self, tb); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+PyDoc_STRVAR(BaseException_add_note__doc__, -+"add_note($self, note, /)\n" -+"--\n" -+"\n" -+"Add a note to the exception"); -+ -+#define BASEEXCEPTION_ADD_NOTE_METHODDEF \ -+ {"add_note", (PyCFunction)BaseException_add_note, METH_O, BaseException_add_note__doc__}, -+ -+static PyObject * -+BaseException_add_note_impl(PyBaseExceptionObject *self, PyObject *note); -+ -+static PyObject * -+BaseException_add_note(PyObject *self, PyObject *arg) -+{ -+ PyObject *return_value = NULL; -+ PyObject *note; -+ -+ if (!PyUnicode_Check(arg)) { -+ _PyArg_BadArgument("add_note", "argument", "str", arg); -+ goto exit; -+ } -+ note = arg; -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = BaseException_add_note_impl((PyBaseExceptionObject *)self, note); -+ Py_END_CRITICAL_SECTION(); -+ -+exit: -+ return return_value; -+} -+ -+#if !defined(BaseException_args_DOCSTR) -+# define BaseException_args_DOCSTR NULL -+#endif -+#if defined(BASEEXCEPTION_ARGS_GETSETDEF) -+# undef BASEEXCEPTION_ARGS_GETSETDEF -+# define BASEEXCEPTION_ARGS_GETSETDEF {"args", (getter)BaseException_args_get, (setter)BaseException_args_set, BaseException_args_DOCSTR}, -+#else -+# define BASEEXCEPTION_ARGS_GETSETDEF {"args", (getter)BaseException_args_get, NULL, BaseException_args_DOCSTR}, -+#endif -+ -+static PyObject * -+BaseException_args_get_impl(PyBaseExceptionObject *self); -+ -+static PyObject * -+BaseException_args_get(PyObject *self, void *Py_UNUSED(context)) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = BaseException_args_get_impl((PyBaseExceptionObject *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(BaseException_args_DOCSTR) -+# define BaseException_args_DOCSTR NULL -+#endif -+#if defined(BASEEXCEPTION_ARGS_GETSETDEF) -+# undef BASEEXCEPTION_ARGS_GETSETDEF -+# define BASEEXCEPTION_ARGS_GETSETDEF {"args", (getter)BaseException_args_get, (setter)BaseException_args_set, BaseException_args_DOCSTR}, -+#else -+# define BASEEXCEPTION_ARGS_GETSETDEF {"args", NULL, (setter)BaseException_args_set, NULL}, -+#endif -+ -+static int -+BaseException_args_set_impl(PyBaseExceptionObject *self, PyObject *value); -+ -+static int -+BaseException_args_set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) -+{ -+ int return_value; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = BaseException_args_set_impl((PyBaseExceptionObject *)self, value); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(BaseException___traceback___DOCSTR) -+# define BaseException___traceback___DOCSTR NULL -+#endif -+#if defined(BASEEXCEPTION___TRACEBACK___GETSETDEF) -+# undef BASEEXCEPTION___TRACEBACK___GETSETDEF -+# define BASEEXCEPTION___TRACEBACK___GETSETDEF {"__traceback__", (getter)BaseException___traceback___get, (setter)BaseException___traceback___set, BaseException___traceback___DOCSTR}, -+#else -+# define BASEEXCEPTION___TRACEBACK___GETSETDEF {"__traceback__", (getter)BaseException___traceback___get, NULL, BaseException___traceback___DOCSTR}, -+#endif -+ -+static PyObject * -+BaseException___traceback___get_impl(PyBaseExceptionObject *self); -+ -+static PyObject * -+BaseException___traceback___get(PyObject *self, void *Py_UNUSED(context)) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = BaseException___traceback___get_impl((PyBaseExceptionObject *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(BaseException___traceback___DOCSTR) -+# define BaseException___traceback___DOCSTR NULL -+#endif -+#if defined(BASEEXCEPTION___TRACEBACK___GETSETDEF) -+# undef BASEEXCEPTION___TRACEBACK___GETSETDEF -+# define BASEEXCEPTION___TRACEBACK___GETSETDEF {"__traceback__", (getter)BaseException___traceback___get, (setter)BaseException___traceback___set, BaseException___traceback___DOCSTR}, -+#else -+# define BASEEXCEPTION___TRACEBACK___GETSETDEF {"__traceback__", NULL, (setter)BaseException___traceback___set, NULL}, -+#endif -+ -+static int -+BaseException___traceback___set_impl(PyBaseExceptionObject *self, -+ PyObject *value); -+ -+static int -+BaseException___traceback___set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) -+{ -+ int return_value; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = BaseException___traceback___set_impl((PyBaseExceptionObject *)self, value); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(BaseException___context___DOCSTR) -+# define BaseException___context___DOCSTR NULL -+#endif -+#if defined(BASEEXCEPTION___CONTEXT___GETSETDEF) -+# undef BASEEXCEPTION___CONTEXT___GETSETDEF -+# define BASEEXCEPTION___CONTEXT___GETSETDEF {"__context__", (getter)BaseException___context___get, (setter)BaseException___context___set, BaseException___context___DOCSTR}, -+#else -+# define BASEEXCEPTION___CONTEXT___GETSETDEF {"__context__", (getter)BaseException___context___get, NULL, BaseException___context___DOCSTR}, -+#endif -+ -+static PyObject * -+BaseException___context___get_impl(PyBaseExceptionObject *self); -+ -+static PyObject * -+BaseException___context___get(PyObject *self, void *Py_UNUSED(context)) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = BaseException___context___get_impl((PyBaseExceptionObject *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(BaseException___context___DOCSTR) -+# define BaseException___context___DOCSTR NULL -+#endif -+#if defined(BASEEXCEPTION___CONTEXT___GETSETDEF) -+# undef BASEEXCEPTION___CONTEXT___GETSETDEF -+# define BASEEXCEPTION___CONTEXT___GETSETDEF {"__context__", (getter)BaseException___context___get, (setter)BaseException___context___set, BaseException___context___DOCSTR}, -+#else -+# define BASEEXCEPTION___CONTEXT___GETSETDEF {"__context__", NULL, (setter)BaseException___context___set, NULL}, -+#endif -+ -+static int -+BaseException___context___set_impl(PyBaseExceptionObject *self, -+ PyObject *value); -+ -+static int -+BaseException___context___set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) -+{ -+ int return_value; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = BaseException___context___set_impl((PyBaseExceptionObject *)self, value); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(BaseException___cause___DOCSTR) -+# define BaseException___cause___DOCSTR NULL -+#endif -+#if defined(BASEEXCEPTION___CAUSE___GETSETDEF) -+# undef BASEEXCEPTION___CAUSE___GETSETDEF -+# define BASEEXCEPTION___CAUSE___GETSETDEF {"__cause__", (getter)BaseException___cause___get, (setter)BaseException___cause___set, BaseException___cause___DOCSTR}, -+#else -+# define BASEEXCEPTION___CAUSE___GETSETDEF {"__cause__", (getter)BaseException___cause___get, NULL, BaseException___cause___DOCSTR}, -+#endif -+ -+static PyObject * -+BaseException___cause___get_impl(PyBaseExceptionObject *self); -+ -+static PyObject * -+BaseException___cause___get(PyObject *self, void *Py_UNUSED(context)) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = BaseException___cause___get_impl((PyBaseExceptionObject *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(BaseException___cause___DOCSTR) -+# define BaseException___cause___DOCSTR NULL -+#endif -+#if defined(BASEEXCEPTION___CAUSE___GETSETDEF) -+# undef BASEEXCEPTION___CAUSE___GETSETDEF -+# define BASEEXCEPTION___CAUSE___GETSETDEF {"__cause__", (getter)BaseException___cause___get, (setter)BaseException___cause___set, BaseException___cause___DOCSTR}, -+#else -+# define BASEEXCEPTION___CAUSE___GETSETDEF {"__cause__", NULL, (setter)BaseException___cause___set, NULL}, -+#endif -+ -+static int -+BaseException___cause___set_impl(PyBaseExceptionObject *self, -+ PyObject *value); -+ -+static int -+BaseException___cause___set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) -+{ -+ int return_value; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = BaseException___cause___set_impl((PyBaseExceptionObject *)self, value); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+PyDoc_STRVAR(BaseExceptionGroup_derive__doc__, -+"derive($self, excs, /)\n" -+"--\n" -+"\n"); -+ -+#define BASEEXCEPTIONGROUP_DERIVE_METHODDEF \ -+ {"derive", (PyCFunction)BaseExceptionGroup_derive, METH_O, BaseExceptionGroup_derive__doc__}, -+ -+static PyObject * -+BaseExceptionGroup_derive_impl(PyBaseExceptionGroupObject *self, -+ PyObject *excs); -+ -+static PyObject * -+BaseExceptionGroup_derive(PyBaseExceptionGroupObject *self, PyObject *excs) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = BaseExceptionGroup_derive_impl((PyBaseExceptionGroupObject *)self, excs); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+PyDoc_STRVAR(BaseExceptionGroup_split__doc__, -+"split($self, matcher_value, /)\n" -+"--\n" -+"\n"); -+ -+#define BASEEXCEPTIONGROUP_SPLIT_METHODDEF \ -+ {"split", (PyCFunction)BaseExceptionGroup_split, METH_O, BaseExceptionGroup_split__doc__}, -+ -+static PyObject * -+BaseExceptionGroup_split_impl(PyBaseExceptionGroupObject *self, -+ PyObject *matcher_value); -+ -+static PyObject * -+BaseExceptionGroup_split(PyBaseExceptionGroupObject *self, PyObject *matcher_value) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = BaseExceptionGroup_split_impl((PyBaseExceptionGroupObject *)self, matcher_value); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+PyDoc_STRVAR(BaseExceptionGroup_subgroup__doc__, -+"subgroup($self, matcher_value, /)\n" -+"--\n" -+"\n"); -+ -+#define BASEEXCEPTIONGROUP_SUBGROUP_METHODDEF \ -+ {"subgroup", (PyCFunction)BaseExceptionGroup_subgroup, METH_O, BaseExceptionGroup_subgroup__doc__}, -+ -+static PyObject * -+BaseExceptionGroup_subgroup_impl(PyBaseExceptionGroupObject *self, -+ PyObject *matcher_value); -+ -+static PyObject * -+BaseExceptionGroup_subgroup(PyBaseExceptionGroupObject *self, PyObject *matcher_value) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = BaseExceptionGroup_subgroup_impl((PyBaseExceptionGroupObject *)self, matcher_value); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+/*[clinic end generated code: output=19aed708dcaf7184 input=a9049054013a1b77]*/ -diff --git a/Objects/clinic/funcobject.c.h b/Objects/clinic/funcobject.c.h -index 3f95a1db7b2..efc579dc259 100644 ---- a/Objects/clinic/funcobject.c.h -+++ b/Objects/clinic/funcobject.c.h -@@ -6,8 +6,180 @@ - # include "pycore_gc.h" // PyGC_Head - # include "pycore_runtime.h" // _Py_ID() - #endif -+#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() - #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() - -+PyDoc_STRVAR(function___annotate____doc__, -+"Get the code object for a function."); -+#if defined(function___annotate___DOCSTR) -+# undef function___annotate___DOCSTR -+#endif -+#define function___annotate___DOCSTR function___annotate____doc__ -+ -+#if !defined(function___annotate___DOCSTR) -+# define function___annotate___DOCSTR NULL -+#endif -+#if defined(FUNCTION___ANNOTATE___GETSETDEF) -+# undef FUNCTION___ANNOTATE___GETSETDEF -+# define FUNCTION___ANNOTATE___GETSETDEF {"__annotate__", (getter)function___annotate___get, (setter)function___annotate___set, function___annotate___DOCSTR}, -+#else -+# define FUNCTION___ANNOTATE___GETSETDEF {"__annotate__", (getter)function___annotate___get, NULL, function___annotate___DOCSTR}, -+#endif -+ -+static PyObject * -+function___annotate___get_impl(PyFunctionObject *self); -+ -+static PyObject * -+function___annotate___get(PyObject *self, void *Py_UNUSED(context)) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = function___annotate___get_impl((PyFunctionObject *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(function___annotate___DOCSTR) -+# define function___annotate___DOCSTR NULL -+#endif -+#if defined(FUNCTION___ANNOTATE___GETSETDEF) -+# undef FUNCTION___ANNOTATE___GETSETDEF -+# define FUNCTION___ANNOTATE___GETSETDEF {"__annotate__", (getter)function___annotate___get, (setter)function___annotate___set, function___annotate___DOCSTR}, -+#else -+# define FUNCTION___ANNOTATE___GETSETDEF {"__annotate__", NULL, (setter)function___annotate___set, NULL}, -+#endif -+ -+static int -+function___annotate___set_impl(PyFunctionObject *self, PyObject *value); -+ -+static int -+function___annotate___set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) -+{ -+ int return_value; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = function___annotate___set_impl((PyFunctionObject *)self, value); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+PyDoc_STRVAR(function___annotations____doc__, -+"Dict of annotations in a function object."); -+#if defined(function___annotations___DOCSTR) -+# undef function___annotations___DOCSTR -+#endif -+#define function___annotations___DOCSTR function___annotations____doc__ -+ -+#if !defined(function___annotations___DOCSTR) -+# define function___annotations___DOCSTR NULL -+#endif -+#if defined(FUNCTION___ANNOTATIONS___GETSETDEF) -+# undef FUNCTION___ANNOTATIONS___GETSETDEF -+# define FUNCTION___ANNOTATIONS___GETSETDEF {"__annotations__", (getter)function___annotations___get, (setter)function___annotations___set, function___annotations___DOCSTR}, -+#else -+# define FUNCTION___ANNOTATIONS___GETSETDEF {"__annotations__", (getter)function___annotations___get, NULL, function___annotations___DOCSTR}, -+#endif -+ -+static PyObject * -+function___annotations___get_impl(PyFunctionObject *self); -+ -+static PyObject * -+function___annotations___get(PyObject *self, void *Py_UNUSED(context)) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = function___annotations___get_impl((PyFunctionObject *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(function___annotations___DOCSTR) -+# define function___annotations___DOCSTR NULL -+#endif -+#if defined(FUNCTION___ANNOTATIONS___GETSETDEF) -+# undef FUNCTION___ANNOTATIONS___GETSETDEF -+# define FUNCTION___ANNOTATIONS___GETSETDEF {"__annotations__", (getter)function___annotations___get, (setter)function___annotations___set, function___annotations___DOCSTR}, -+#else -+# define FUNCTION___ANNOTATIONS___GETSETDEF {"__annotations__", NULL, (setter)function___annotations___set, NULL}, -+#endif -+ -+static int -+function___annotations___set_impl(PyFunctionObject *self, PyObject *value); -+ -+static int -+function___annotations___set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) -+{ -+ int return_value; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = function___annotations___set_impl((PyFunctionObject *)self, value); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+PyDoc_STRVAR(function___type_params____doc__, -+"Get the declared type parameters for a function."); -+#if defined(function___type_params___DOCSTR) -+# undef function___type_params___DOCSTR -+#endif -+#define function___type_params___DOCSTR function___type_params____doc__ -+ -+#if !defined(function___type_params___DOCSTR) -+# define function___type_params___DOCSTR NULL -+#endif -+#if defined(FUNCTION___TYPE_PARAMS___GETSETDEF) -+# undef FUNCTION___TYPE_PARAMS___GETSETDEF -+# define FUNCTION___TYPE_PARAMS___GETSETDEF {"__type_params__", (getter)function___type_params___get, (setter)function___type_params___set, function___type_params___DOCSTR}, -+#else -+# define FUNCTION___TYPE_PARAMS___GETSETDEF {"__type_params__", (getter)function___type_params___get, NULL, function___type_params___DOCSTR}, -+#endif -+ -+static PyObject * -+function___type_params___get_impl(PyFunctionObject *self); -+ -+static PyObject * -+function___type_params___get(PyObject *self, void *Py_UNUSED(context)) -+{ -+ PyObject *return_value = NULL; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = function___type_params___get_impl((PyFunctionObject *)self); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ -+#if !defined(function___type_params___DOCSTR) -+# define function___type_params___DOCSTR NULL -+#endif -+#if defined(FUNCTION___TYPE_PARAMS___GETSETDEF) -+# undef FUNCTION___TYPE_PARAMS___GETSETDEF -+# define FUNCTION___TYPE_PARAMS___GETSETDEF {"__type_params__", (getter)function___type_params___get, (setter)function___type_params___set, function___type_params___DOCSTR}, -+#else -+# define FUNCTION___TYPE_PARAMS___GETSETDEF {"__type_params__", NULL, (setter)function___type_params___set, NULL}, -+#endif -+ -+static int -+function___type_params___set_impl(PyFunctionObject *self, PyObject *value); -+ -+static int -+function___type_params___set(PyObject *self, PyObject *value, void *Py_UNUSED(context)) -+{ -+ int return_value; -+ -+ Py_BEGIN_CRITICAL_SECTION(self); -+ return_value = function___type_params___set_impl((PyFunctionObject *)self, value); -+ Py_END_CRITICAL_SECTION(); -+ -+ return return_value; -+} -+ - PyDoc_STRVAR(func_new__doc__, - "function(code, globals, name=None, argdefs=None, closure=None,\n" - " kwdefaults=None)\n" -@@ -116,4 +288,4 @@ - exit: - return return_value; - } --/*[clinic end generated code: output=bad4e19757dd26c3 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=3cdce22867efe617 input=a9049054013a1b77]*/ -diff --git a/Objects/clinic/listobject.c.h b/Objects/clinic/listobject.c.h -index 975f253c096..a29ed9f7088 100644 ---- a/Objects/clinic/listobject.c.h -+++ b/Objects/clinic/listobject.c.h -@@ -23,7 +23,7 @@ - list_insert_impl(PyListObject *self, Py_ssize_t index, PyObject *object); - - static PyObject * --list_insert(PyListObject *self, PyObject *const *args, Py_ssize_t nargs) -+list_insert(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - Py_ssize_t index; -@@ -46,7 +46,7 @@ - } - object = args[1]; - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = list_insert_impl(self, index, object); -+ return_value = list_insert_impl((PyListObject *)self, index, object); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -66,12 +66,12 @@ - py_list_clear_impl(PyListObject *self); - - static PyObject * --py_list_clear(PyListObject *self, PyObject *Py_UNUSED(ignored)) -+py_list_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = py_list_clear_impl(self); -+ return_value = py_list_clear_impl((PyListObject *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -90,12 +90,12 @@ - list_copy_impl(PyListObject *self); - - static PyObject * --list_copy(PyListObject *self, PyObject *Py_UNUSED(ignored)) -+list_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = list_copy_impl(self); -+ return_value = list_copy_impl((PyListObject *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -119,7 +119,7 @@ - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = list_append_impl(self, object); -+ return_value = list_append_impl((PyListObject *)self, object); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -149,7 +149,7 @@ - list_pop_impl(PyListObject *self, Py_ssize_t index); - - static PyObject * --list_pop(PyListObject *self, PyObject *const *args, Py_ssize_t nargs) -+list_pop(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - Py_ssize_t index = -1; -@@ -174,7 +174,7 @@ - } - skip_optional: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = list_pop_impl(self, index); -+ return_value = list_pop_impl((PyListObject *)self, index); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -202,7 +202,7 @@ - list_sort_impl(PyListObject *self, PyObject *keyfunc, int reverse); - - static PyObject * --list_sort(PyListObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+list_sort(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -255,7 +255,7 @@ - } - skip_optional_kwonly: - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = list_sort_impl(self, keyfunc, reverse); -+ return_value = list_sort_impl((PyListObject *)self, keyfunc, reverse); - Py_END_CRITICAL_SECTION(); - - exit: -@@ -275,12 +275,12 @@ - list_reverse_impl(PyListObject *self); - - static PyObject * --list_reverse(PyListObject *self, PyObject *Py_UNUSED(ignored)) -+list_reverse(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = list_reverse_impl(self); -+ return_value = list_reverse_impl((PyListObject *)self); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -302,7 +302,7 @@ - Py_ssize_t stop); - - static PyObject * --list_index(PyListObject *self, PyObject *const *args, Py_ssize_t nargs) -+list_index(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *value; -@@ -326,7 +326,7 @@ - goto exit; - } - skip_optional: -- return_value = list_index_impl(self, value, start, stop); -+ return_value = list_index_impl((PyListObject *)self, value, start, stop); - - exit: - return return_value; -@@ -361,7 +361,7 @@ - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(self); -- return_value = list_remove_impl(self, value); -+ return_value = list_remove_impl((PyListObject *)self, value); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -418,9 +418,9 @@ - list___sizeof___impl(PyListObject *self); - - static PyObject * --list___sizeof__(PyListObject *self, PyObject *Py_UNUSED(ignored)) -+list___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return list___sizeof___impl(self); -+ return list___sizeof___impl((PyListObject *)self); - } - - PyDoc_STRVAR(list___reversed____doc__, -@@ -436,8 +436,8 @@ - list___reversed___impl(PyListObject *self); - - static PyObject * --list___reversed__(PyListObject *self, PyObject *Py_UNUSED(ignored)) -+list___reversed__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return list___reversed___impl(self); -+ return list___reversed___impl((PyListObject *)self); - } --/*[clinic end generated code: output=9357151278d77ea1 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=35c43dc33f9ba521 input=a9049054013a1b77]*/ -diff --git a/Objects/clinic/memoryobject.c.h b/Objects/clinic/memoryobject.c.h -index a6cf1f431a1..4706c920519 100644 ---- a/Objects/clinic/memoryobject.c.h -+++ b/Objects/clinic/memoryobject.c.h -@@ -137,9 +137,9 @@ - memoryview_release_impl(PyMemoryViewObject *self); - - static PyObject * --memoryview_release(PyMemoryViewObject *self, PyObject *Py_UNUSED(ignored)) -+memoryview_release(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return memoryview_release_impl(self); -+ return memoryview_release_impl((PyMemoryViewObject *)self); - } - - PyDoc_STRVAR(memoryview_cast__doc__, -@@ -156,7 +156,7 @@ - PyObject *shape); - - static PyObject * --memoryview_cast(PyMemoryViewObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+memoryview_cast(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -204,7 +204,7 @@ - } - shape = args[1]; - skip_optional_pos: -- return_value = memoryview_cast_impl(self, format, shape); -+ return_value = memoryview_cast_impl((PyMemoryViewObject *)self, format, shape); - - exit: - return return_value; -@@ -223,9 +223,9 @@ - memoryview_toreadonly_impl(PyMemoryViewObject *self); - - static PyObject * --memoryview_toreadonly(PyMemoryViewObject *self, PyObject *Py_UNUSED(ignored)) -+memoryview_toreadonly(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return memoryview_toreadonly_impl(self); -+ return memoryview_toreadonly_impl((PyMemoryViewObject *)self); - } - - PyDoc_STRVAR(memoryview_tolist__doc__, -@@ -241,9 +241,9 @@ - memoryview_tolist_impl(PyMemoryViewObject *self); - - static PyObject * --memoryview_tolist(PyMemoryViewObject *self, PyObject *Py_UNUSED(ignored)) -+memoryview_tolist(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return memoryview_tolist_impl(self); -+ return memoryview_tolist_impl((PyMemoryViewObject *)self); - } - - PyDoc_STRVAR(memoryview_tobytes__doc__, -@@ -265,7 +265,7 @@ - memoryview_tobytes_impl(PyMemoryViewObject *self, const char *order); - - static PyObject * --memoryview_tobytes(PyMemoryViewObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+memoryview_tobytes(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -324,7 +324,7 @@ - goto exit; - } - skip_optional_pos: -- return_value = memoryview_tobytes_impl(self, order); -+ return_value = memoryview_tobytes_impl((PyMemoryViewObject *)self, order); - - exit: - return return_value; -@@ -361,7 +361,7 @@ - int bytes_per_sep); - - static PyObject * --memoryview_hex(PyMemoryViewObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+memoryview_hex(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -413,7 +413,7 @@ - goto exit; - } - skip_optional_pos: -- return_value = memoryview_hex_impl(self, sep, bytes_per_sep); -+ return_value = memoryview_hex_impl((PyMemoryViewObject *)self, sep, bytes_per_sep); - - exit: - return return_value; -@@ -444,7 +444,7 @@ - Py_ssize_t start, Py_ssize_t stop); - - static PyObject * --memoryview_index(PyMemoryViewObject *self, PyObject *const *args, Py_ssize_t nargs) -+memoryview_index(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *value; -@@ -468,9 +468,9 @@ - goto exit; - } - skip_optional: -- return_value = memoryview_index_impl(self, value, start, stop); -+ return_value = memoryview_index_impl((PyMemoryViewObject *)self, value, start, stop); - - exit: - return return_value; - } --/*[clinic end generated code: output=132893ef5f67ad73 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=2ef6c061d9c4e3dc input=a9049054013a1b77]*/ -diff --git a/Objects/clinic/odictobject.c.h b/Objects/clinic/odictobject.c.h -index 4b97596e5db..44d89c4e0ef 100644 ---- a/Objects/clinic/odictobject.c.h -+++ b/Objects/clinic/odictobject.c.h -@@ -87,7 +87,7 @@ - PyObject *default_value); - - static PyObject * --OrderedDict_setdefault(PyODictObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+OrderedDict_setdefault(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -131,7 +131,7 @@ - } - default_value = args[1]; - skip_optional_pos: -- return_value = OrderedDict_setdefault_impl(self, key, default_value); -+ return_value = OrderedDict_setdefault_impl((PyODictObject *)self, key, default_value); - - exit: - return return_value; -@@ -154,7 +154,7 @@ - PyObject *default_value); - - static PyObject * --OrderedDict_pop(PyODictObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+OrderedDict_pop(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -198,7 +198,7 @@ - } - default_value = args[1]; - skip_optional_pos: -- return_value = OrderedDict_pop_impl(self, key, default_value); -+ return_value = OrderedDict_pop_impl((PyODictObject *)self, key, default_value); - - exit: - return return_value; -@@ -219,7 +219,7 @@ - OrderedDict_popitem_impl(PyODictObject *self, int last); - - static PyObject * --OrderedDict_popitem(PyODictObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+OrderedDict_popitem(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -264,7 +264,7 @@ - goto exit; - } - skip_optional_pos: -- return_value = OrderedDict_popitem_impl(self, last); -+ return_value = OrderedDict_popitem_impl((PyODictObject *)self, last); - - exit: - return return_value; -@@ -285,7 +285,7 @@ - OrderedDict_move_to_end_impl(PyODictObject *self, PyObject *key, int last); - - static PyObject * --OrderedDict_move_to_end(PyODictObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+OrderedDict_move_to_end(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -332,9 +332,9 @@ - goto exit; - } - skip_optional_pos: -- return_value = OrderedDict_move_to_end_impl(self, key, last); -+ return_value = OrderedDict_move_to_end_impl((PyODictObject *)self, key, last); - - exit: - return return_value; - } --/*[clinic end generated code: output=2aa6fc0567c9252c input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=55bd390bb516e997 input=a9049054013a1b77]*/ -diff --git a/Objects/clinic/setobject.c.h b/Objects/clinic/setobject.c.h -index 986993b4aa9..bf7e604e4b0 100644 ---- a/Objects/clinic/setobject.c.h -+++ b/Objects/clinic/setobject.c.h -@@ -19,12 +19,12 @@ - set_pop_impl(PySetObject *so); - - static PyObject * --set_pop(PySetObject *so, PyObject *Py_UNUSED(ignored)) -+set_pop(PyObject *so, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(so); -- return_value = set_pop_impl(so); -+ return_value = set_pop_impl((PySetObject *)so); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -44,7 +44,7 @@ - Py_ssize_t others_length); - - static PyObject * --set_update(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) -+set_update(PyObject *so, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject * const *others; -@@ -52,7 +52,7 @@ - - others = args; - others_length = nargs; -- return_value = set_update_impl(so, others, others_length); -+ return_value = set_update_impl((PySetObject *)so, others, others_length); - - return return_value; - } -@@ -70,12 +70,12 @@ - set_copy_impl(PySetObject *so); - - static PyObject * --set_copy(PySetObject *so, PyObject *Py_UNUSED(ignored)) -+set_copy(PyObject *so, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(so); -- return_value = set_copy_impl(so); -+ return_value = set_copy_impl((PySetObject *)so); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -94,12 +94,12 @@ - frozenset_copy_impl(PySetObject *so); - - static PyObject * --frozenset_copy(PySetObject *so, PyObject *Py_UNUSED(ignored)) -+frozenset_copy(PyObject *so, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(so); -- return_value = frozenset_copy_impl(so); -+ return_value = frozenset_copy_impl((PySetObject *)so); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -118,12 +118,12 @@ - set_clear_impl(PySetObject *so); - - static PyObject * --set_clear(PySetObject *so, PyObject *Py_UNUSED(ignored)) -+set_clear(PyObject *so, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(so); -- return_value = set_clear_impl(so); -+ return_value = set_clear_impl((PySetObject *)so); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -143,7 +143,7 @@ - Py_ssize_t others_length); - - static PyObject * --set_union(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) -+set_union(PyObject *so, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject * const *others; -@@ -151,7 +151,7 @@ - - others = args; - others_length = nargs; -- return_value = set_union_impl(so, others, others_length); -+ return_value = set_union_impl((PySetObject *)so, others, others_length); - - return return_value; - } -@@ -170,7 +170,7 @@ - Py_ssize_t others_length); - - static PyObject * --set_intersection_multi(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) -+set_intersection_multi(PyObject *so, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject * const *others; -@@ -178,7 +178,7 @@ - - others = args; - others_length = nargs; -- return_value = set_intersection_multi_impl(so, others, others_length); -+ return_value = set_intersection_multi_impl((PySetObject *)so, others, others_length); - - return return_value; - } -@@ -197,7 +197,7 @@ - Py_ssize_t others_length); - - static PyObject * --set_intersection_update_multi(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) -+set_intersection_update_multi(PyObject *so, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject * const *others; -@@ -205,7 +205,7 @@ - - others = args; - others_length = nargs; -- return_value = set_intersection_update_multi_impl(so, others, others_length); -+ return_value = set_intersection_update_multi_impl((PySetObject *)so, others, others_length); - - return return_value; - } -@@ -228,7 +228,7 @@ - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION2(so, other); -- return_value = set_isdisjoint_impl(so, other); -+ return_value = set_isdisjoint_impl((PySetObject *)so, other); - Py_END_CRITICAL_SECTION2(); - - return return_value; -@@ -248,7 +248,7 @@ - Py_ssize_t others_length); - - static PyObject * --set_difference_update(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) -+set_difference_update(PyObject *so, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject * const *others; -@@ -256,7 +256,7 @@ - - others = args; - others_length = nargs; -- return_value = set_difference_update_impl(so, others, others_length); -+ return_value = set_difference_update_impl((PySetObject *)so, others, others_length); - - return return_value; - } -@@ -275,7 +275,7 @@ - Py_ssize_t others_length); - - static PyObject * --set_difference_multi(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) -+set_difference_multi(PyObject *so, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject * const *others; -@@ -283,7 +283,7 @@ - - others = args; - others_length = nargs; -- return_value = set_difference_multi_impl(so, others, others_length); -+ return_value = set_difference_multi_impl((PySetObject *)so, others, others_length); - - return return_value; - } -@@ -315,7 +315,7 @@ - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION2(so, other); -- return_value = set_symmetric_difference_impl(so, other); -+ return_value = set_symmetric_difference_impl((PySetObject *)so, other); - Py_END_CRITICAL_SECTION2(); - - return return_value; -@@ -339,7 +339,7 @@ - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION2(so, other); -- return_value = set_issubset_impl(so, other); -+ return_value = set_issubset_impl((PySetObject *)so, other); - Py_END_CRITICAL_SECTION2(); - - return return_value; -@@ -363,7 +363,7 @@ - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION2(so, other); -- return_value = set_issuperset_impl(so, other); -+ return_value = set_issuperset_impl((PySetObject *)so, other); - Py_END_CRITICAL_SECTION2(); - - return return_value; -@@ -389,7 +389,7 @@ - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(so); -- return_value = set_add_impl(so, key); -+ return_value = set_add_impl((PySetObject *)so, key); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -413,7 +413,7 @@ - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(so); -- return_value = set___contains___impl(so, key); -+ return_value = set___contains___impl((PySetObject *)so, key); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -439,7 +439,7 @@ - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(so); -- return_value = set_remove_impl(so, key); -+ return_value = set_remove_impl((PySetObject *)so, key); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -466,7 +466,7 @@ - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(so); -- return_value = set_discard_impl(so, key); -+ return_value = set_discard_impl((PySetObject *)so, key); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -485,12 +485,12 @@ - set___reduce___impl(PySetObject *so); - - static PyObject * --set___reduce__(PySetObject *so, PyObject *Py_UNUSED(ignored)) -+set___reduce__(PyObject *so, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(so); -- return_value = set___reduce___impl(so); -+ return_value = set___reduce___impl((PySetObject *)so); - Py_END_CRITICAL_SECTION(); - - return return_value; -@@ -509,14 +509,14 @@ - set___sizeof___impl(PySetObject *so); - - static PyObject * --set___sizeof__(PySetObject *so, PyObject *Py_UNUSED(ignored)) -+set___sizeof__(PyObject *so, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - - Py_BEGIN_CRITICAL_SECTION(so); -- return_value = set___sizeof___impl(so); -+ return_value = set___sizeof___impl((PySetObject *)so); - Py_END_CRITICAL_SECTION(); - - return return_value; - } --/*[clinic end generated code: output=4b65e7709927f31f input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=83b7742a762ce465 input=a9049054013a1b77]*/ -diff --git a/Objects/clinic/tupleobject.c.h b/Objects/clinic/tupleobject.c.h -index 5d6a2c481a5..40ffd4c1755 100644 ---- a/Objects/clinic/tupleobject.c.h -+++ b/Objects/clinic/tupleobject.c.h -@@ -20,7 +20,7 @@ - Py_ssize_t stop); - - static PyObject * --tuple_index(PyTupleObject *self, PyObject *const *args, Py_ssize_t nargs) -+tuple_index(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *value; -@@ -44,7 +44,7 @@ - goto exit; - } - skip_optional: -- return_value = tuple_index_impl(self, value, start, stop); -+ return_value = tuple_index_impl((PyTupleObject *)self, value, start, stop); - - exit: - return return_value; -@@ -110,8 +110,8 @@ - tuple___getnewargs___impl(PyTupleObject *self); - - static PyObject * --tuple___getnewargs__(PyTupleObject *self, PyObject *Py_UNUSED(ignored)) -+tuple___getnewargs__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return tuple___getnewargs___impl(self); -+ return tuple___getnewargs___impl((PyTupleObject *)self); - } --/*[clinic end generated code: output=a6a9abba5d121f4c input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=779cb4a13db67397 input=a9049054013a1b77]*/ -diff --git a/Objects/clinic/typeobject.c.h b/Objects/clinic/typeobject.c.h -index 1fa153598db..5e8187b3f5b 100644 ---- a/Objects/clinic/typeobject.c.h -+++ b/Objects/clinic/typeobject.c.h -@@ -22,7 +22,7 @@ - PyObject *return_value = NULL; - int _return_value; - -- _return_value = type___instancecheck___impl(self, instance); -+ _return_value = type___instancecheck___impl((PyTypeObject *)self, instance); - if ((_return_value == -1) && PyErr_Occurred()) { - goto exit; - } -@@ -50,7 +50,7 @@ - PyObject *return_value = NULL; - int _return_value; - -- _return_value = type___subclasscheck___impl(self, subclass); -+ _return_value = type___subclasscheck___impl((PyTypeObject *)self, subclass); - if ((_return_value == -1) && PyErr_Occurred()) { - goto exit; - } -@@ -73,9 +73,9 @@ - type_mro_impl(PyTypeObject *self); - - static PyObject * --type_mro(PyTypeObject *self, PyObject *Py_UNUSED(ignored)) -+type_mro(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return type_mro_impl(self); -+ return type_mro_impl((PyTypeObject *)self); - } - - PyDoc_STRVAR(type___subclasses____doc__, -@@ -91,9 +91,9 @@ - type___subclasses___impl(PyTypeObject *self); - - static PyObject * --type___subclasses__(PyTypeObject *self, PyObject *Py_UNUSED(ignored)) -+type___subclasses__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return type___subclasses___impl(self); -+ return type___subclasses___impl((PyTypeObject *)self); - } - - PyDoc_STRVAR(type___dir____doc__, -@@ -109,9 +109,9 @@ - type___dir___impl(PyTypeObject *self); - - static PyObject * --type___dir__(PyTypeObject *self, PyObject *Py_UNUSED(ignored)) -+type___dir__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return type___dir___impl(self); -+ return type___dir___impl((PyTypeObject *)self); - } - - PyDoc_STRVAR(type___sizeof____doc__, -@@ -127,9 +127,9 @@ - type___sizeof___impl(PyTypeObject *self); - - static PyObject * --type___sizeof__(PyTypeObject *self, PyObject *Py_UNUSED(ignored)) -+type___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return type___sizeof___impl(self); -+ return type___sizeof___impl((PyTypeObject *)self); - } - - PyDoc_STRVAR(object___getstate____doc__, -@@ -262,4 +262,4 @@ - { - return object___dir___impl(self); - } --/*[clinic end generated code: output=b56c87f9cace1921 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=f7db85fd11818c63 input=a9049054013a1b77]*/ -diff --git a/Objects/clinic/typevarobject.c.h b/Objects/clinic/typevarobject.c.h -index c17998830b0..e50ed7d95b9 100644 ---- a/Objects/clinic/typevarobject.c.h -+++ b/Objects/clinic/typevarobject.c.h -@@ -143,7 +143,7 @@ - PyObject *args); - - static PyObject * --typevar_typing_prepare_subst(typevarobject *self, PyObject *const *args, Py_ssize_t nargs) -+typevar_typing_prepare_subst(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *alias; -@@ -154,7 +154,7 @@ - } - alias = args[0]; - __clinic_args = args[1]; -- return_value = typevar_typing_prepare_subst_impl(self, alias, __clinic_args); -+ return_value = typevar_typing_prepare_subst_impl((typevarobject *)self, alias, __clinic_args); - - exit: - return return_value; -@@ -172,9 +172,9 @@ - typevar_reduce_impl(typevarobject *self); - - static PyObject * --typevar_reduce(typevarobject *self, PyObject *Py_UNUSED(ignored)) -+typevar_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return typevar_reduce_impl(self); -+ return typevar_reduce_impl((typevarobject *)self); - } - - PyDoc_STRVAR(typevar_has_default__doc__, -@@ -189,9 +189,9 @@ - typevar_has_default_impl(typevarobject *self); - - static PyObject * --typevar_has_default(typevarobject *self, PyObject *Py_UNUSED(ignored)) -+typevar_has_default(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return typevar_has_default_impl(self); -+ return typevar_has_default_impl((typevarobject *)self); - } - - PyDoc_STRVAR(paramspecargs_new__doc__, -@@ -431,7 +431,7 @@ - PyObject *args); - - static PyObject * --paramspec_typing_prepare_subst(paramspecobject *self, PyObject *const *args, Py_ssize_t nargs) -+paramspec_typing_prepare_subst(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *alias; -@@ -442,7 +442,7 @@ - } - alias = args[0]; - __clinic_args = args[1]; -- return_value = paramspec_typing_prepare_subst_impl(self, alias, __clinic_args); -+ return_value = paramspec_typing_prepare_subst_impl((paramspecobject *)self, alias, __clinic_args); - - exit: - return return_value; -@@ -460,9 +460,9 @@ - paramspec_reduce_impl(paramspecobject *self); - - static PyObject * --paramspec_reduce(paramspecobject *self, PyObject *Py_UNUSED(ignored)) -+paramspec_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return paramspec_reduce_impl(self); -+ return paramspec_reduce_impl((paramspecobject *)self); - } - - PyDoc_STRVAR(paramspec_has_default__doc__, -@@ -477,9 +477,9 @@ - paramspec_has_default_impl(paramspecobject *self); - - static PyObject * --paramspec_has_default(paramspecobject *self, PyObject *Py_UNUSED(ignored)) -+paramspec_has_default(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return paramspec_has_default_impl(self); -+ return paramspec_has_default_impl((paramspecobject *)self); - } - - PyDoc_STRVAR(typevartuple__doc__, -@@ -570,7 +570,7 @@ - PyObject *alias, PyObject *args); - - static PyObject * --typevartuple_typing_prepare_subst(typevartupleobject *self, PyObject *const *args, Py_ssize_t nargs) -+typevartuple_typing_prepare_subst(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *alias; -@@ -581,7 +581,7 @@ - } - alias = args[0]; - __clinic_args = args[1]; -- return_value = typevartuple_typing_prepare_subst_impl(self, alias, __clinic_args); -+ return_value = typevartuple_typing_prepare_subst_impl((typevartupleobject *)self, alias, __clinic_args); - - exit: - return return_value; -@@ -599,9 +599,9 @@ - typevartuple_reduce_impl(typevartupleobject *self); - - static PyObject * --typevartuple_reduce(typevartupleobject *self, PyObject *Py_UNUSED(ignored)) -+typevartuple_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return typevartuple_reduce_impl(self); -+ return typevartuple_reduce_impl((typevartupleobject *)self); - } - - PyDoc_STRVAR(typevartuple_has_default__doc__, -@@ -616,9 +616,9 @@ - typevartuple_has_default_impl(typevartupleobject *self); - - static PyObject * --typevartuple_has_default(typevartupleobject *self, PyObject *Py_UNUSED(ignored)) -+typevartuple_has_default(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return typevartuple_has_default_impl(self); -+ return typevartuple_has_default_impl((typevartupleobject *)self); - } - - PyDoc_STRVAR(typealias_reduce__doc__, -@@ -633,9 +633,9 @@ - typealias_reduce_impl(typealiasobject *self); - - static PyObject * --typealias_reduce(typealiasobject *self, PyObject *Py_UNUSED(ignored)) -+typealias_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return typealias_reduce_impl(self); -+ return typealias_reduce_impl((typealiasobject *)self); - } - - PyDoc_STRVAR(typealias_new__doc__, -@@ -706,4 +706,4 @@ - exit: - return return_value; - } --/*[clinic end generated code: output=26351c3549f5ad83 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=f499d959a942c599 input=a9049054013a1b77]*/ -diff --git a/Objects/clinic/unicodeobject.c.h b/Objects/clinic/unicodeobject.c.h -index 361f20c0fa4..5c6a425b0f8 100644 ---- a/Objects/clinic/unicodeobject.c.h -+++ b/Objects/clinic/unicodeobject.c.h -@@ -22,9 +22,9 @@ - EncodingMap_size_impl(struct encoding_map *self); - - static PyObject * --EncodingMap_size(struct encoding_map *self, PyObject *Py_UNUSED(ignored)) -+EncodingMap_size(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return EncodingMap_size_impl(self); -+ return EncodingMap_size_impl((struct encoding_map *)self); - } - - PyDoc_STRVAR(unicode_title__doc__, -@@ -1895,4 +1895,4 @@ - exit: - return return_value; - } --/*[clinic end generated code: output=30efbf79c5a07dd2 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=4d1cecd6d08498a4 input=a9049054013a1b77]*/ -diff --git a/Objects/codeobject.c b/Objects/codeobject.c -index eb8de136ee6..a7b46aa2dfb 100644 ---- a/Objects/codeobject.c -+++ b/Objects/codeobject.c -@@ -108,6 +108,8 @@ - * generic helpers - ******************/ - -+#define _PyCodeObject_CAST(op) (assert(PyCode_Check(op)), (PyCodeObject *)(op)) -+ - static int - should_intern_string(PyObject *o) - { -@@ -457,8 +459,7 @@ - } - - extern void --_PyCode_Quicken(_Py_CODEUNIT *instructions, Py_ssize_t size, PyObject *consts, -- int enable_counters); -+_PyCode_Quicken(_Py_CODEUNIT *instructions, Py_ssize_t size, int enable_counters); - - #ifdef Py_GIL_DISABLED - static _PyCodeArray * _PyCodeArray_New(Py_ssize_t size); -@@ -541,10 +542,9 @@ - } - co->_co_firsttraceable = entry_point; - #ifdef Py_GIL_DISABLED -- _PyCode_Quicken(_PyCode_CODE(co), Py_SIZE(co), co->co_consts, -- interp->config.tlbc_enabled); -+ _PyCode_Quicken(_PyCode_CODE(co), Py_SIZE(co), interp->config.tlbc_enabled); - #else -- _PyCode_Quicken(_PyCode_CODE(co), Py_SIZE(co), co->co_consts, 1); -+ _PyCode_Quicken(_PyCode_CODE(co), Py_SIZE(co), 1); - #endif - notify_code_watchers(PY_CODE_EVENT_CREATE, co); - return 0; -@@ -977,6 +977,9 @@ - if (addrq < 0) { - return co->co_firstlineno; - } -+ if (co->_co_monitoring && co->_co_monitoring->lines) { -+ return _Py_Instrumentation_GetLine(co, addrq/sizeof(_Py_CODEUNIT)); -+ } - assert(addrq >= 0 && addrq < _PyCode_NBYTES(co)); - PyCodeAddressRange bounds; - _PyCode_InitAddressRange(co, &bounds); -@@ -1865,11 +1868,12 @@ - } - - static void --code_dealloc(PyCodeObject *co) -+code_dealloc(PyObject *self) - { -- _PyObject_ResurrectStart((PyObject *)co); -+ PyCodeObject *co = _PyCodeObject_CAST(self); -+ _PyObject_ResurrectStart(self); - notify_code_watchers(PY_CODE_EVENT_DESTROY, co); -- if (_PyObject_ResurrectEnd((PyObject *)co)) { -+ if (_PyObject_ResurrectEnd(self)) { - return; - } - -@@ -1908,7 +1912,7 @@ - Py_XDECREF(co->co_linetable); - Py_XDECREF(co->co_exceptiontable); - #ifdef Py_GIL_DISABLED -- assert(co->_co_unique_id == -1); -+ assert(co->_co_unique_id == _Py_INVALID_UNIQUE_ID); - #endif - if (co->_co_cached != NULL) { - Py_XDECREF(co->_co_cached->_co_code); -@@ -1918,7 +1922,7 @@ - PyMem_Free(co->_co_cached); - } - if (co->co_weakreflist != NULL) { -- PyObject_ClearWeakRefs((PyObject*)co); -+ PyObject_ClearWeakRefs(self); - } - free_monitoring_data(co->_co_monitoring); - #ifdef Py_GIL_DISABLED -@@ -1939,7 +1943,7 @@ - static int - code_traverse(PyObject *self, visitproc visit, void *arg) - { -- PyCodeObject *co = (PyCodeObject*)self; -+ PyCodeObject *co = _PyCodeObject_CAST(self); - Py_VISIT(co->co_consts); - return 0; - } -@@ -1948,7 +1952,7 @@ - static PyObject * - code_repr(PyObject *self) - { -- PyCodeObject *co = (PyCodeObject*)self; -+ PyCodeObject *co = _PyCodeObject_CAST(self); - int lineno; - if (co->co_firstlineno != 0) - lineno = co->co_firstlineno; -@@ -2057,7 +2061,7 @@ - static Py_hash_t - code_hash(PyObject *self) - { -- PyCodeObject *co = (PyCodeObject*)self; -+ PyCodeObject *co = _PyCodeObject_CAST(self); - Py_uhash_t uhash = 20221211; - #define SCRAMBLE_IN(H) do { \ - uhash ^= (Py_uhash_t)(H); \ -@@ -2120,7 +2124,7 @@ - static PyObject * - code_getlnotab(PyObject *self, void *closure) - { -- PyCodeObject *code = (PyCodeObject*)self; -+ PyCodeObject *code = _PyCodeObject_CAST(self); - if (PyErr_WarnEx(PyExc_DeprecationWarning, - "co_lnotab is deprecated, use co_lines instead.", - 1) < 0) { -@@ -2132,28 +2136,28 @@ - static PyObject * - code_getvarnames(PyObject *self, void *closure) - { -- PyCodeObject *code = (PyCodeObject*)self; -+ PyCodeObject *code = _PyCodeObject_CAST(self); - return _PyCode_GetVarnames(code); - } - - static PyObject * - code_getcellvars(PyObject *self, void *closure) - { -- PyCodeObject *code = (PyCodeObject*)self; -+ PyCodeObject *code = _PyCodeObject_CAST(self); - return _PyCode_GetCellvars(code); - } - - static PyObject * - code_getfreevars(PyObject *self, void *closure) - { -- PyCodeObject *code = (PyCodeObject*)self; -+ PyCodeObject *code = _PyCodeObject_CAST(self); - return _PyCode_GetFreevars(code); - } - - static PyObject * - code_getcodeadaptive(PyObject *self, void *closure) - { -- PyCodeObject *code = (PyCodeObject*)self; -+ PyCodeObject *code = _PyCodeObject_CAST(self); - return PyBytes_FromStringAndSize(code->co_code_adaptive, - _PyCode_NBYTES(code)); - } -@@ -2161,7 +2165,7 @@ - static PyObject * - code_getcode(PyObject *self, void *closure) - { -- PyCodeObject *code = (PyCodeObject*)self; -+ PyCodeObject *code = _PyCodeObject_CAST(self); - return _PyCode_GetCode(code); - } - -@@ -2180,7 +2184,7 @@ - static PyObject * - code_sizeof(PyObject *self, PyObject *Py_UNUSED(args)) - { -- PyCodeObject *co = (PyCodeObject*)self; -+ PyCodeObject *co = _PyCodeObject_CAST(self); - size_t res = _PyObject_VAR_SIZE(Py_TYPE(co), Py_SIZE(co)); - _PyCodeObjectExtra *co_extra = (_PyCodeObjectExtra*) co->co_extra; - if (co_extra != NULL) { -@@ -2193,33 +2197,40 @@ - static PyObject * - code_linesiterator(PyObject *self, PyObject *Py_UNUSED(args)) - { -- PyCodeObject *code = (PyCodeObject*)self; -+ PyCodeObject *code = _PyCodeObject_CAST(self); - return (PyObject *)new_linesiterator(code); - } - -+static PyObject * -+code_branchesiterator(PyObject *self, PyObject *Py_UNUSED(args)) -+{ -+ PyCodeObject *code = _PyCodeObject_CAST(self); -+ return _PyInstrumentation_BranchesIterator(code); -+} -+ - /*[clinic input] - @text_signature "($self, /, **changes)" - code.replace - - * -- co_argcount: int(c_default="self->co_argcount") = unchanged -- co_posonlyargcount: int(c_default="self->co_posonlyargcount") = unchanged -- co_kwonlyargcount: int(c_default="self->co_kwonlyargcount") = unchanged -- co_nlocals: int(c_default="self->co_nlocals") = unchanged -- co_stacksize: int(c_default="self->co_stacksize") = unchanged -- co_flags: int(c_default="self->co_flags") = unchanged -- co_firstlineno: int(c_default="self->co_firstlineno") = unchanged -+ co_argcount: int(c_default="((PyCodeObject *)self)->co_argcount") = unchanged -+ co_posonlyargcount: int(c_default="((PyCodeObject *)self)->co_posonlyargcount") = unchanged -+ co_kwonlyargcount: int(c_default="((PyCodeObject *)self)->co_kwonlyargcount") = unchanged -+ co_nlocals: int(c_default="((PyCodeObject *)self)->co_nlocals") = unchanged -+ co_stacksize: int(c_default="((PyCodeObject *)self)->co_stacksize") = unchanged -+ co_flags: int(c_default="((PyCodeObject *)self)->co_flags") = unchanged -+ co_firstlineno: int(c_default="((PyCodeObject *)self)->co_firstlineno") = unchanged - co_code: object(subclass_of="&PyBytes_Type", c_default="NULL") = unchanged -- co_consts: object(subclass_of="&PyTuple_Type", c_default="self->co_consts") = unchanged -- co_names: object(subclass_of="&PyTuple_Type", c_default="self->co_names") = unchanged -+ co_consts: object(subclass_of="&PyTuple_Type", c_default="((PyCodeObject *)self)->co_consts") = unchanged -+ co_names: object(subclass_of="&PyTuple_Type", c_default="((PyCodeObject *)self)->co_names") = unchanged - co_varnames: object(subclass_of="&PyTuple_Type", c_default="NULL") = unchanged - co_freevars: object(subclass_of="&PyTuple_Type", c_default="NULL") = unchanged - co_cellvars: object(subclass_of="&PyTuple_Type", c_default="NULL") = unchanged -- co_filename: unicode(c_default="self->co_filename") = unchanged -- co_name: unicode(c_default="self->co_name") = unchanged -- co_qualname: unicode(c_default="self->co_qualname") = unchanged -- co_linetable: object(subclass_of="&PyBytes_Type", c_default="self->co_linetable") = unchanged -- co_exceptiontable: object(subclass_of="&PyBytes_Type", c_default="self->co_exceptiontable") = unchanged -+ co_filename: unicode(c_default="((PyCodeObject *)self)->co_filename") = unchanged -+ co_name: unicode(c_default="((PyCodeObject *)self)->co_name") = unchanged -+ co_qualname: unicode(c_default="((PyCodeObject *)self)->co_qualname") = unchanged -+ co_linetable: object(subclass_of="&PyBytes_Type", c_default="((PyCodeObject *)self)->co_linetable") = unchanged -+ co_exceptiontable: object(subclass_of="&PyBytes_Type", c_default="((PyCodeObject *)self)->co_exceptiontable") = unchanged - - Return a copy of the code object with new values for the specified fields. - [clinic start generated code]*/ -@@ -2234,7 +2245,7 @@ - PyObject *co_filename, PyObject *co_name, - PyObject *co_qualname, PyObject *co_linetable, - PyObject *co_exceptiontable) --/*[clinic end generated code: output=e75c48a15def18b9 input=18e280e07846c122]*/ -+/*[clinic end generated code: output=e75c48a15def18b9 input=a455a89c57ac9d42]*/ - { - #define CHECK_INT_ARG(ARG) \ - if (ARG < 0) { \ -@@ -2337,6 +2348,7 @@ - static struct PyMethodDef code_methods[] = { - {"__sizeof__", code_sizeof, METH_NOARGS}, - {"co_lines", code_linesiterator, METH_NOARGS}, -+ {"co_branches", code_branchesiterator, METH_NOARGS}, - {"co_positions", code_positionsiterator, METH_NOARGS}, - CODE_REPLACE_METHODDEF - CODE__VARNAME_FROM_OPARG_METHODDEF -@@ -2351,7 +2363,7 @@ - "code", - offsetof(PyCodeObject, co_code_adaptive), - sizeof(_Py_CODEUNIT), -- (destructor)code_dealloc, /* tp_dealloc */ -+ code_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ -@@ -2805,7 +2817,7 @@ - for (int i = 0; i < code_len; i += _PyInstruction_GetLength(co, i)) { - dst[i] = _Py_GetBaseCodeUnit(co, i); - } -- _PyCode_Quicken(dst, code_len, co->co_consts, 1); -+ _PyCode_Quicken(dst, code_len, 1); - } - - static Py_ssize_t -diff --git a/Objects/complexobject.c b/Objects/complexobject.c -index bf6187efac9..5d9b3c9f0e3 100644 ---- a/Objects/complexobject.c -+++ b/Objects/complexobject.c -@@ -14,6 +14,8 @@ - #include "pycore_pymath.h" // _Py_ADJUST_ERANGE2() - - -+#define _PyComplexObject_CAST(op) ((PyComplexObject *)(op)) -+ - - /*[clinic input] - class complex "PyComplexObject *" "&PyComplex_Type" -@@ -553,11 +555,12 @@ - } - - static PyObject * --complex_repr(PyComplexObject *v) -+complex_repr(PyObject *op) - { - int precision = 0; - char format_code = 'r'; - PyObject *result = NULL; -+ PyComplexObject *v = _PyComplexObject_CAST(op); - - /* If these are non-NULL, they'll need to be freed. */ - char *pre = NULL; -@@ -609,13 +612,14 @@ - } - - static Py_hash_t --complex_hash(PyComplexObject *v) -+complex_hash(PyObject *op) - { - Py_uhash_t hashreal, hashimag, combined; -- hashreal = (Py_uhash_t)_Py_HashDouble((PyObject *) v, v->cval.real); -+ PyComplexObject *v = _PyComplexObject_CAST(op); -+ hashreal = (Py_uhash_t)_Py_HashDouble(op, v->cval.real); - if (hashreal == (Py_uhash_t)-1) - return -1; -- hashimag = (Py_uhash_t)_Py_HashDouble((PyObject *)v, v->cval.imag); -+ hashimag = (Py_uhash_t)_Py_HashDouble(op, v->cval.imag); - if (hashimag == (Py_uhash_t)-1) - return -1; - /* Note: if the imaginary part is 0, hashimag is 0 now, -@@ -753,8 +757,9 @@ - } - - static PyObject * --complex_neg(PyComplexObject *v) -+complex_neg(PyObject *op) - { -+ PyComplexObject *v = _PyComplexObject_CAST(op); - Py_complex neg; - neg.real = -v->cval.real; - neg.imag = -v->cval.imag; -@@ -762,22 +767,20 @@ - } - - static PyObject * --complex_pos(PyComplexObject *v) -+complex_pos(PyObject *op) - { -+ PyComplexObject *v = _PyComplexObject_CAST(op); - if (PyComplex_CheckExact(v)) { - return Py_NewRef(v); - } -- else -- return PyComplex_FromCComplex(v->cval); -+ return PyComplex_FromCComplex(v->cval); - } - - static PyObject * --complex_abs(PyComplexObject *v) -+complex_abs(PyObject *op) - { -- double result; -- -- result = _Py_c_abs(v->cval); -- -+ PyComplexObject *v = _PyComplexObject_CAST(op); -+ double result = _Py_c_abs(v->cval); - if (errno == ERANGE) { - PyErr_SetString(PyExc_OverflowError, - "absolute value too large"); -@@ -787,8 +790,9 @@ - } - - static int --complex_bool(PyComplexObject *v) -+complex_bool(PyObject *op) - { -+ PyComplexObject *v = _PyComplexObject_CAST(op); - return v->cval.real != 0.0 || v->cval.imag != 0.0; - } - -@@ -1339,16 +1343,16 @@ - }; - - static PyNumberMethods complex_as_number = { -- (binaryfunc)complex_add, /* nb_add */ -- (binaryfunc)complex_sub, /* nb_subtract */ -- (binaryfunc)complex_mul, /* nb_multiply */ -+ complex_add, /* nb_add */ -+ complex_sub, /* nb_subtract */ -+ complex_mul, /* nb_multiply */ - 0, /* nb_remainder */ - 0, /* nb_divmod */ -- (ternaryfunc)complex_pow, /* nb_power */ -- (unaryfunc)complex_neg, /* nb_negative */ -- (unaryfunc)complex_pos, /* nb_positive */ -- (unaryfunc)complex_abs, /* nb_absolute */ -- (inquiry)complex_bool, /* nb_bool */ -+ complex_pow, /* nb_power */ -+ complex_neg, /* nb_negative */ -+ complex_pos, /* nb_positive */ -+ complex_abs, /* nb_absolute */ -+ complex_bool, /* nb_bool */ - 0, /* nb_invert */ - 0, /* nb_lshift */ - 0, /* nb_rshift */ -@@ -1369,7 +1373,7 @@ - 0, /* nb_inplace_xor */ - 0, /* nb_inplace_or */ - 0, /* nb_floor_divide */ -- (binaryfunc)complex_div, /* nb_true_divide */ -+ complex_div, /* nb_true_divide */ - 0, /* nb_inplace_floor_divide */ - 0, /* nb_inplace_true_divide */ - }; -@@ -1384,11 +1388,11 @@ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ -- (reprfunc)complex_repr, /* tp_repr */ -+ complex_repr, /* tp_repr */ - &complex_as_number, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ -- (hashfunc)complex_hash, /* tp_hash */ -+ complex_hash, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ -diff --git a/Objects/descrobject.c b/Objects/descrobject.c -index 4eccd1704eb..238becee241 100644 ---- a/Objects/descrobject.c -+++ b/Objects/descrobject.c -@@ -1349,7 +1349,7 @@ - wrapperobject *wp = (wrapperobject *)self; - Py_hash_t x, y; - x = PyObject_GenericHash(wp->self); -- y = _Py_HashPointer(wp->descr); -+ y = Py_HashPointer(wp->descr); - x = x ^ y; - if (x == -1) - x = -2; -@@ -1508,6 +1508,8 @@ - - /* A built-in 'property' type */ - -+#define _propertyobject_CAST(op) ((propertyobject *)(op)) -+ - /* - class property(object): - -@@ -1911,8 +1913,9 @@ - } - - static PyObject * --property_get__name__(propertyobject *prop, void *Py_UNUSED(ignored)) -+property_get__name__(PyObject *op, void *Py_UNUSED(ignored)) - { -+ propertyobject *prop = _propertyobject_CAST(op); - PyObject *name; - if (property_name(prop, &name) < 0) { - return NULL; -@@ -1925,16 +1928,17 @@ - } - - static int --property_set__name__(propertyobject *prop, PyObject *value, -- void *Py_UNUSED(ignored)) -+property_set__name__(PyObject *op, PyObject *value, void *Py_UNUSED(ignored)) - { -+ propertyobject *prop = _propertyobject_CAST(op); - Py_XSETREF(prop->prop_name, Py_XNewRef(value)); - return 0; - } - - static PyObject * --property_get___isabstractmethod__(propertyobject *prop, void *closure) -+property_get___isabstractmethod__(PyObject *op, void *closure) - { -+ propertyobject *prop = _propertyobject_CAST(op); - int res = _PyObject_IsAbstract(prop->prop_get); - if (res == -1) { - return NULL; -@@ -1962,9 +1966,8 @@ - } - - static PyGetSetDef property_getsetlist[] = { -- {"__name__", (getter)property_get__name__, (setter)property_set__name__}, -- {"__isabstractmethod__", -- (getter)property_get___isabstractmethod__, NULL, -+ {"__name__", property_get__name__, property_set__name__, NULL, NULL}, -+ {"__isabstractmethod__", property_get___isabstractmethod__, NULL, - NULL, - NULL}, - {NULL} /* Sentinel */ -diff --git a/Objects/dictobject.c b/Objects/dictobject.c -index 05c93a3e448..d979cd72b48 100644 ---- a/Objects/dictobject.c -+++ b/Objects/dictobject.c -@@ -1129,6 +1129,53 @@ - return do_lookup(mp, dk, key, hash, compare_generic); - } - -+static bool -+check_keys_unicode(PyDictKeysObject *dk, PyObject *key) -+{ -+ return PyUnicode_CheckExact(key) && (dk->dk_kind != DICT_KEYS_GENERAL); -+} -+ -+static Py_ssize_t -+hash_unicode_key(PyObject *key) -+{ -+ assert(PyUnicode_CheckExact(key)); -+ Py_hash_t hash = unicode_get_hash(key); -+ if (hash == -1) { -+ hash = PyUnicode_Type.tp_hash(key); -+ assert(hash != -1); -+ } -+ return hash; -+} -+ -+#ifdef Py_GIL_DISABLED -+static Py_ssize_t -+unicodekeys_lookup_unicode_threadsafe(PyDictKeysObject* dk, PyObject *key, -+ Py_hash_t hash); -+#endif -+ -+static Py_ssize_t -+unicodekeys_lookup_split(PyDictKeysObject* dk, PyObject *key, Py_hash_t hash) -+{ -+ Py_ssize_t ix; -+ assert(dk->dk_kind == DICT_KEYS_SPLIT); -+ assert(PyUnicode_CheckExact(key)); -+ -+#ifdef Py_GIL_DISABLED -+ // A split dictionaries keys can be mutated by other dictionaries -+ // but if we have a unicode key we can avoid locking the shared -+ // keys. -+ ix = unicodekeys_lookup_unicode_threadsafe(dk, key, hash); -+ if (ix == DKIX_KEY_CHANGED) { -+ LOCK_KEYS(dk); -+ ix = unicodekeys_lookup_unicode(dk, key, hash); -+ UNLOCK_KEYS(dk); -+ } -+#else -+ ix = unicodekeys_lookup_unicode(dk, key, hash); -+#endif -+ return ix; -+} -+ - /* Lookup a string in a (all unicode) dict keys. - * Returns DKIX_ERROR if key is not a string, - * or if the dict keys is not all strings. -@@ -1138,10 +1185,36 @@ - Py_ssize_t - _PyDictKeys_StringLookup(PyDictKeysObject* dk, PyObject *key) - { -- DictKeysKind kind = dk->dk_kind; -- if (!PyUnicode_CheckExact(key) || kind == DICT_KEYS_GENERAL) { -+ if (!check_keys_unicode(dk, key)) { -+ return DKIX_ERROR; -+ } -+ Py_hash_t hash = hash_unicode_key(key); -+ return unicodekeys_lookup_unicode(dk, key, hash); -+} -+ -+Py_ssize_t -+_PyDictKeys_StringLookupAndVersion(PyDictKeysObject *dk, PyObject *key, uint32_t *version) -+{ -+ if (!check_keys_unicode(dk, key)) { - return DKIX_ERROR; - } -+ Py_ssize_t ix; -+ Py_hash_t hash = hash_unicode_key(key); -+ LOCK_KEYS(dk); -+ ix = unicodekeys_lookup_unicode(dk, key, hash); -+ *version = _PyDictKeys_GetVersionForCurrentState(_PyInterpreterState_GET(), dk); -+ UNLOCK_KEYS(dk); -+ return ix; -+} -+ -+/* Like _PyDictKeys_StringLookup() but only works on split keys. Note -+ * that in free-threaded builds this locks the keys object as required. -+ */ -+Py_ssize_t -+_PyDictKeys_StringLookupSplit(PyDictKeysObject* dk, PyObject *key) -+{ -+ assert(dk->dk_kind == DICT_KEYS_SPLIT); -+ assert(PyUnicode_CheckExact(key)); - Py_hash_t hash = unicode_get_hash(key); - if (hash == -1) { - hash = PyUnicode_Type.tp_hash(key); -@@ -1150,17 +1223,9 @@ - return DKIX_ERROR; - } - } -- return unicodekeys_lookup_unicode(dk, key, hash); -+ return unicodekeys_lookup_split(dk, key, hash); - } - --#ifdef Py_GIL_DISABLED -- --static Py_ssize_t --unicodekeys_lookup_unicode_threadsafe(PyDictKeysObject* dk, PyObject *key, -- Py_hash_t hash); -- --#endif -- - /* - The basic lookup function used by all operations. - This is based on Algorithm D from Knuth Vol. 3, Sec. 6.4. -@@ -1192,15 +1257,7 @@ - if (PyUnicode_CheckExact(key)) { - #ifdef Py_GIL_DISABLED - if (kind == DICT_KEYS_SPLIT) { -- // A split dictionaries keys can be mutated by other -- // dictionaries but if we have a unicode key we can avoid -- // locking the shared keys. -- ix = unicodekeys_lookup_unicode_threadsafe(dk, key, hash); -- if (ix == DKIX_KEY_CHANGED) { -- LOCK_KEYS(dk); -- ix = unicodekeys_lookup_unicode(dk, key, hash); -- UNLOCK_KEYS(dk); -- } -+ ix = unicodekeys_lookup_split(dk, key, hash); - } - else { - ix = unicodekeys_lookup_unicode(dk, key, hash); -@@ -1602,6 +1659,9 @@ - assert(PyDict_Check(op)); - #ifdef Py_GIL_DISABLED - Py_ssize_t id = _PyObject_AssignUniqueId(op); -+ if (id == _Py_INVALID_UNIQUE_ID) { -+ return; -+ } - if ((uint64_t)id >= (uint64_t)DICT_UNIQUE_ID_MAX) { - _PyObject_ReleaseUniqueId(id); - return; -@@ -1609,8 +1669,7 @@ - - PyDictObject *mp = (PyDictObject *)op; - assert((mp->_ma_watcher_tag >> DICT_UNIQUE_ID_SHIFT) == 0); -- // Plus 1 so that _ma_watcher_tag=0 represents an unassigned id -- mp->_ma_watcher_tag += ((uint64_t)id + 1) << DICT_UNIQUE_ID_SHIFT; -+ mp->_ma_watcher_tag += (uint64_t)id << DICT_UNIQUE_ID_SHIFT; - #endif - } - -@@ -1894,6 +1953,16 @@ - } - } - -+static void -+invalidate_and_clear_inline_values(PyDictValues *values) -+{ -+ assert(values->embedded); -+ FT_ATOMIC_STORE_UINT8(values->valid, 0); -+ for (int i = 0; i < values->capacity; i++) { -+ FT_ATOMIC_STORE_PTR_RELEASE(values->values[i], NULL); -+ } -+} -+ - /* - Restructure the table by allocating a new table and reinserting all - items again. When entries have been deleted, the new table may -@@ -1985,7 +2054,7 @@ - if (oldvalues->embedded) { - assert(oldvalues->embedded == 1); - assert(oldvalues->valid == 1); -- FT_ATOMIC_STORE_UINT8(oldvalues->valid, 0); -+ invalidate_and_clear_inline_values(oldvalues); - } - else { - free_values(oldvalues, IS_DICT_SHARED(mp)); -@@ -3021,8 +3090,8 @@ - } - - --PyObject * --_PyDict_Pop(PyObject *dict, PyObject *key, PyObject *default_value) -+static PyObject * -+dict_pop_default(PyObject *dict, PyObject *key, PyObject *default_value) - { - PyObject *result; - if (PyDict_Pop(dict, key, &result) == 0) { -@@ -3035,6 +3104,12 @@ - return result; - } - -+PyObject * -+_PyDict_Pop(PyObject *dict, PyObject *key, PyObject *default_value) -+{ -+ return dict_pop_default(dict, key, default_value); -+} -+ - static PyDictObject * - dict_dict_fromkeys(PyInterpreterState *interp, PyDictObject *mp, - PyObject *iterable, PyObject *value) -@@ -3718,7 +3793,7 @@ - - ensure_shared_on_resize(mp); - dictkeys_decref(interp, mp->ma_keys, IS_DICT_SHARED(mp)); -- mp->ma_keys = keys; -+ set_keys(mp, keys); - STORE_USED(mp, other->ma_used); - ASSERT_CONSISTENT(mp); - -@@ -4173,7 +4248,6 @@ - } - - /*[clinic input] --@critical_section - dict.get - - key: object -@@ -4185,7 +4259,7 @@ - - static PyObject * - dict_get_impl(PyDictObject *self, PyObject *key, PyObject *default_value) --/*[clinic end generated code: output=bba707729dee05bf input=a631d3f18f584c60]*/ -+/*[clinic end generated code: output=bba707729dee05bf input=279ddb5790b6b107]*/ - { - PyObject *val = NULL; - Py_hash_t hash; -@@ -4396,7 +4470,7 @@ - dict_pop_impl(PyDictObject *self, PyObject *key, PyObject *default_value) - /*[clinic end generated code: output=3abb47b89f24c21c input=e221baa01044c44c]*/ - { -- return _PyDict_Pop((PyObject*)self, key, default_value); -+ return dict_pop_default((PyObject*)self, key, default_value); - } - - /*[clinic input] -@@ -6967,7 +7041,7 @@ - - PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj)); - assert(keys != NULL); -- Py_ssize_t ix = _PyDictKeys_StringLookup(keys, name); -+ Py_ssize_t ix = _PyDictKeys_StringLookupSplit(keys, name); - if (ix == DKIX_EMPTY) { - *attr = NULL; - return true; -@@ -6975,7 +7049,13 @@ - - #ifdef Py_GIL_DISABLED - PyObject *value = _Py_atomic_load_ptr_acquire(&values->values[ix]); -- if (value == NULL || _Py_TryIncrefCompare(&values->values[ix], value)) { -+ if (value == NULL) { -+ if (FT_ATOMIC_LOAD_UINT8(values->valid)) { -+ *attr = NULL; -+ return true; -+ } -+ } -+ else if (_Py_TryIncrefCompare(&values->values[ix], value)) { - *attr = value; - return true; - } -@@ -7271,7 +7351,8 @@ - if (set_or_clear_managed_dict(obj, NULL, true) < 0) { - /* Must be out of memory */ - assert(PyErr_Occurred() == PyExc_MemoryError); -- PyErr_WriteUnraisable(NULL); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "clearing an object managed dict"); - /* Clear the dict */ - PyDictObject *dict = _PyObject_GetManagedDict(obj); - Py_BEGIN_CRITICAL_SECTION2(dict, obj); -@@ -7313,7 +7394,7 @@ - } - mp->ma_values = values; - -- FT_ATOMIC_STORE_UINT8(_PyObject_InlineValues(obj)->valid, 0); -+ invalidate_and_clear_inline_values(_PyObject_InlineValues(obj)); - - assert(_PyObject_InlineValuesConsistencyCheck(obj)); - ASSERT_CONSISTENT(mp); -diff --git a/Objects/enumobject.c b/Objects/enumobject.c -index 556666779d8..eb895267526 100644 ---- a/Objects/enumobject.c -+++ b/Objects/enumobject.c -@@ -23,6 +23,7 @@ - PyObject* one; /* borrowed reference */ - } enumobject; - -+#define _enumobject_CAST(op) ((enumobject *)(op)) - - /*[clinic input] - @classmethod -@@ -150,8 +151,9 @@ - } - - static void --enum_dealloc(enumobject *en) -+enum_dealloc(PyObject *op) - { -+ enumobject *en = _enumobject_CAST(op); - PyObject_GC_UnTrack(en); - Py_XDECREF(en->en_sit); - Py_XDECREF(en->en_result); -@@ -160,8 +162,9 @@ - } - - static int --enum_traverse(enumobject *en, visitproc visit, void *arg) -+enum_traverse(PyObject *op, visitproc visit, void *arg) - { -+ enumobject *en = _enumobject_CAST(op); - Py_VISIT(en->en_sit); - Py_VISIT(en->en_result); - Py_VISIT(en->en_longindex); -@@ -220,8 +223,9 @@ - } - - static PyObject * --enum_next(enumobject *en) -+enum_next(PyObject *op) - { -+ enumobject *en = _enumobject_CAST(op); - PyObject *next_index; - PyObject *next_item; - PyObject *result = en->en_result; -@@ -270,8 +274,9 @@ - } - - static PyObject * --enum_reduce(enumobject *en, PyObject *Py_UNUSED(ignored)) -+enum_reduce(PyObject *op, PyObject *Py_UNUSED(ignored)) - { -+ enumobject *en = _enumobject_CAST(op); - if (en->en_longindex != NULL) - return Py_BuildValue("O(OO)", Py_TYPE(en), en->en_sit, en->en_longindex); - else -@@ -281,7 +286,7 @@ - PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); - - static PyMethodDef enum_methods[] = { -- {"__reduce__", (PyCFunction)enum_reduce, METH_NOARGS, reduce_doc}, -+ {"__reduce__", enum_reduce, METH_NOARGS, reduce_doc}, - {"__class_getitem__", Py_GenericAlias, - METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, - {NULL, NULL} /* sentinel */ -@@ -293,7 +298,7 @@ - sizeof(enumobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ -- (destructor)enum_dealloc, /* tp_dealloc */ -+ enum_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ -@@ -311,12 +316,12 @@ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - enum_new__doc__, /* tp_doc */ -- (traverseproc)enum_traverse, /* tp_traverse */ -+ enum_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ -- (iternextfunc)enum_next, /* tp_iternext */ -+ enum_next, /* tp_iternext */ - enum_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ -@@ -329,7 +334,7 @@ - PyType_GenericAlloc, /* tp_alloc */ - enum_new, /* tp_new */ - PyObject_GC_Del, /* tp_free */ -- .tp_vectorcall = (vectorcallfunc)enumerate_vectorcall -+ .tp_vectorcall = enumerate_vectorcall - }; - - /* Reversed Object ***************************************************************/ -@@ -340,6 +345,8 @@ - PyObject* seq; - } reversedobject; - -+#define _reversedobject_CAST(op) ((reversedobject *)(op)) -+ - /*[clinic input] - @classmethod - reversed.__new__ as reversed_new -@@ -411,23 +418,26 @@ - } - - static void --reversed_dealloc(reversedobject *ro) -+reversed_dealloc(PyObject *op) - { -+ reversedobject *ro = _reversedobject_CAST(op); - PyObject_GC_UnTrack(ro); - Py_XDECREF(ro->seq); - Py_TYPE(ro)->tp_free(ro); - } - - static int --reversed_traverse(reversedobject *ro, visitproc visit, void *arg) -+reversed_traverse(PyObject *op, visitproc visit, void *arg) - { -+ reversedobject *ro = _reversedobject_CAST(op); - Py_VISIT(ro->seq); - return 0; - } - - static PyObject * --reversed_next(reversedobject *ro) -+reversed_next(PyObject *op) - { -+ reversedobject *ro = _reversedobject_CAST(op); - PyObject *item; - Py_ssize_t index = ro->index; - -@@ -447,8 +457,9 @@ - } - - static PyObject * --reversed_len(reversedobject *ro, PyObject *Py_UNUSED(ignored)) -+reversed_len(PyObject *op, PyObject *Py_UNUSED(ignored)) - { -+ reversedobject *ro = _reversedobject_CAST(op); - Py_ssize_t position, seqsize; - - if (ro->seq == NULL) -@@ -463,8 +474,9 @@ - PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it))."); - - static PyObject * --reversed_reduce(reversedobject *ro, PyObject *Py_UNUSED(ignored)) -+reversed_reduce(PyObject *op, PyObject *Py_UNUSED(ignored)) - { -+ reversedobject *ro = _reversedobject_CAST(op); - if (ro->seq) - return Py_BuildValue("O(O)n", Py_TYPE(ro), ro->seq, ro->index); - else -@@ -472,8 +484,9 @@ - } - - static PyObject * --reversed_setstate(reversedobject *ro, PyObject *state) -+reversed_setstate(PyObject *op, PyObject *state) - { -+ reversedobject *ro = _reversedobject_CAST(op); - Py_ssize_t index = PyLong_AsSsize_t(state); - if (index == -1 && PyErr_Occurred()) - return NULL; -@@ -493,9 +506,9 @@ - PyDoc_STRVAR(setstate_doc, "Set state information for unpickling."); - - static PyMethodDef reversediter_methods[] = { -- {"__length_hint__", (PyCFunction)reversed_len, METH_NOARGS, length_hint_doc}, -- {"__reduce__", (PyCFunction)reversed_reduce, METH_NOARGS, reduce_doc}, -- {"__setstate__", (PyCFunction)reversed_setstate, METH_O, setstate_doc}, -+ {"__length_hint__", reversed_len, METH_NOARGS, length_hint_doc}, -+ {"__reduce__", reversed_reduce, METH_NOARGS, reduce_doc}, -+ {"__setstate__", reversed_setstate, METH_O, setstate_doc}, - {NULL, NULL} /* sentinel */ - }; - -@@ -505,7 +518,7 @@ - sizeof(reversedobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ -- (destructor)reversed_dealloc, /* tp_dealloc */ -+ reversed_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ -@@ -523,12 +536,12 @@ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - reversed_new__doc__, /* tp_doc */ -- (traverseproc)reversed_traverse,/* tp_traverse */ -+ reversed_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ -- (iternextfunc)reversed_next, /* tp_iternext */ -+ reversed_next, /* tp_iternext */ - reversediter_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ -@@ -541,5 +554,5 @@ - PyType_GenericAlloc, /* tp_alloc */ - reversed_new, /* tp_new */ - PyObject_GC_Del, /* tp_free */ -- .tp_vectorcall = (vectorcallfunc)reversed_vectorcall, -+ .tp_vectorcall = reversed_vectorcall, - }; -diff --git a/Objects/exceptions.c b/Objects/exceptions.c -index 6880c24196c..154cde93168 100644 ---- a/Objects/exceptions.c -+++ b/Objects/exceptions.c -@@ -16,6 +16,14 @@ - - #include "osdefs.h" // SEP - -+#include "clinic/exceptions.c.h" -+ -+/*[clinic input] -+class BaseException "PyBaseExceptionObject *" "&PyExc_BaseException" -+class BaseExceptionGroup "PyBaseExceptionGroupObject *" "&PyExc_BaseExceptionGroup" -+[clinic start generated code]*/ -+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=b7c45e78cff8edc3]*/ -+ - - /* Compatibility aliases */ - PyObject *PyExc_EnvironmentError = NULL; // borrowed ref -@@ -152,30 +160,50 @@ - static PyObject * - BaseException_str(PyBaseExceptionObject *self) - { -+ PyObject *res; -+ Py_BEGIN_CRITICAL_SECTION(self); - switch (PyTuple_GET_SIZE(self->args)) { - case 0: -- return Py_GetConstant(Py_CONSTANT_EMPTY_STR); -+ res = Py_GetConstant(Py_CONSTANT_EMPTY_STR); -+ break; - case 1: -- return PyObject_Str(PyTuple_GET_ITEM(self->args, 0)); -+ res = PyObject_Str(PyTuple_GET_ITEM(self->args, 0)); -+ break; - default: -- return PyObject_Str(self->args); -+ res = PyObject_Str(self->args); -+ break; - } -+ Py_END_CRITICAL_SECTION(); -+ return res; - } - - static PyObject * - BaseException_repr(PyBaseExceptionObject *self) - { -+ PyObject *res; -+ Py_BEGIN_CRITICAL_SECTION(self); - const char *name = _PyType_Name(Py_TYPE(self)); -- if (PyTuple_GET_SIZE(self->args) == 1) -- return PyUnicode_FromFormat("%s(%R)", name, -+ if (PyTuple_GET_SIZE(self->args) == 1) { -+ res = PyUnicode_FromFormat("%s(%R)", name, - PyTuple_GET_ITEM(self->args, 0)); -- else -- return PyUnicode_FromFormat("%s%R", name, self->args); -+ } -+ else { -+ res = PyUnicode_FromFormat("%s%R", name, self->args); -+ } -+ Py_END_CRITICAL_SECTION(); -+ return res; - } - - /* Pickling support */ -+ -+/*[clinic input] -+@critical_section -+BaseException.__reduce__ -+[clinic start generated code]*/ -+ - static PyObject * --BaseException_reduce(PyBaseExceptionObject *self, PyObject *Py_UNUSED(ignored)) -+BaseException___reduce___impl(PyBaseExceptionObject *self) -+/*[clinic end generated code: output=af87c1247ef98748 input=283be5a10d9c964f]*/ - { - if (self->args && self->dict) - return PyTuple_Pack(3, Py_TYPE(self), self->args, self->dict); -@@ -188,8 +216,17 @@ - * all their attributes in the __dict__. Code is taken from cPickle's - * load_build function. - */ -+ -+/*[clinic input] -+@critical_section -+BaseException.__setstate__ -+ state: object -+ / -+[clinic start generated code]*/ -+ - static PyObject * --BaseException_setstate(PyObject *self, PyObject *state) -+BaseException___setstate___impl(PyBaseExceptionObject *self, PyObject *state) -+/*[clinic end generated code: output=f3834889950453ab input=5524b61cfe9b9856]*/ - { - PyObject *d_key, *d_value; - Py_ssize_t i = 0; -@@ -202,7 +239,7 @@ - while (PyDict_Next(state, &i, &d_key, &d_value)) { - Py_INCREF(d_key); - Py_INCREF(d_value); -- int res = PyObject_SetAttr(self, d_key, d_value); -+ int res = PyObject_SetAttr((PyObject *)self, d_key, d_value); - Py_DECREF(d_value); - Py_DECREF(d_key); - if (res < 0) { -@@ -213,18 +250,26 @@ - Py_RETURN_NONE; - } - -+ -+/*[clinic input] -+@critical_section -+BaseException.with_traceback -+ tb: object -+ / -+ -+Set self.__traceback__ to tb and return self. -+[clinic start generated code]*/ -+ - static PyObject * --BaseException_with_traceback(PyObject *self, PyObject *tb) { -- if (PyException_SetTraceback(self, tb)) -+BaseException_with_traceback_impl(PyBaseExceptionObject *self, PyObject *tb) -+/*[clinic end generated code: output=81e92f2387927f10 input=b5fb64d834717e36]*/ -+{ -+ if (BaseException___traceback___set_impl(self, tb) < 0){ - return NULL; -- -+ } - return Py_NewRef(self); - } - --PyDoc_STRVAR(with_traceback_doc, --"Exception.with_traceback(tb) --\n\ -- set self.__traceback__ to tb and return self."); -- - static inline PyBaseExceptionObject* - _PyBaseExceptionObject_cast(PyObject *exc) - { -@@ -232,18 +277,21 @@ - return (PyBaseExceptionObject *)exc; - } - -+/*[clinic input] -+@critical_section -+BaseException.add_note -+ note: object(subclass_of="&PyUnicode_Type") -+ / -+ -+Add a note to the exception -+[clinic start generated code]*/ -+ - static PyObject * --BaseException_add_note(PyObject *self, PyObject *note) -+BaseException_add_note_impl(PyBaseExceptionObject *self, PyObject *note) -+/*[clinic end generated code: output=fb7cbcba611c187b input=e60a6b6e9596acaf]*/ - { -- if (!PyUnicode_Check(note)) { -- PyErr_Format(PyExc_TypeError, -- "note must be a str, not '%s'", -- Py_TYPE(note)->tp_name); -- return NULL; -- } -- - PyObject *notes; -- if (PyObject_GetOptionalAttr(self, &_Py_ID(__notes__), ¬es) < 0) { -+ if (PyObject_GetOptionalAttr((PyObject *)self, &_Py_ID(__notes__), ¬es) < 0) { - return NULL; - } - if (notes == NULL) { -@@ -251,7 +299,7 @@ - if (notes == NULL) { - return NULL; - } -- if (PyObject_SetAttr(self, &_Py_ID(__notes__), notes) < 0) { -+ if (PyObject_SetAttr((PyObject *)self, &_Py_ID(__notes__), notes) < 0) { - Py_DECREF(notes); - return NULL; - } -@@ -269,22 +317,23 @@ - Py_RETURN_NONE; - } - --PyDoc_STRVAR(add_note_doc, --"Exception.add_note(note) --\n\ -- add a note to the exception"); -- - static PyMethodDef BaseException_methods[] = { -- {"__reduce__", (PyCFunction)BaseException_reduce, METH_NOARGS }, -- {"__setstate__", (PyCFunction)BaseException_setstate, METH_O }, -- {"with_traceback", (PyCFunction)BaseException_with_traceback, METH_O, -- with_traceback_doc}, -- {"add_note", (PyCFunction)BaseException_add_note, METH_O, -- add_note_doc}, -- {NULL, NULL, 0, NULL}, -+ BASEEXCEPTION___REDUCE___METHODDEF -+ BASEEXCEPTION___SETSTATE___METHODDEF -+ BASEEXCEPTION_WITH_TRACEBACK_METHODDEF -+ BASEEXCEPTION_ADD_NOTE_METHODDEF -+ {NULL, NULL, 0, NULL}, - }; - -+/*[clinic input] -+@critical_section -+@getter -+BaseException.args -+[clinic start generated code]*/ -+ - static PyObject * --BaseException_get_args(PyBaseExceptionObject *self, void *Py_UNUSED(ignored)) -+BaseException_args_get_impl(PyBaseExceptionObject *self) -+/*[clinic end generated code: output=e02e34e35cf4d677 input=64282386e4d7822d]*/ - { - if (self->args == NULL) { - Py_RETURN_NONE; -@@ -292,23 +341,37 @@ - return Py_NewRef(self->args); - } - -+/*[clinic input] -+@critical_section -+@setter -+BaseException.args -+[clinic start generated code]*/ -+ - static int --BaseException_set_args(PyBaseExceptionObject *self, PyObject *val, void *Py_UNUSED(ignored)) -+BaseException_args_set_impl(PyBaseExceptionObject *self, PyObject *value) -+/*[clinic end generated code: output=331137e11d8f9e80 input=2400047ea5970a84]*/ - { - PyObject *seq; -- if (val == NULL) { -+ if (value == NULL) { - PyErr_SetString(PyExc_TypeError, "args may not be deleted"); - return -1; - } -- seq = PySequence_Tuple(val); -+ seq = PySequence_Tuple(value); - if (!seq) - return -1; - Py_XSETREF(self->args, seq); - return 0; - } - -+/*[clinic input] -+@critical_section -+@getter -+BaseException.__traceback__ -+[clinic start generated code]*/ -+ - static PyObject * --BaseException_get_tb(PyBaseExceptionObject *self, void *Py_UNUSED(ignored)) -+BaseException___traceback___get_impl(PyBaseExceptionObject *self) -+/*[clinic end generated code: output=17cf874a52339398 input=a2277f0de62170cf]*/ - { - if (self->traceback == NULL) { - Py_RETURN_NONE; -@@ -316,17 +379,26 @@ - return Py_NewRef(self->traceback); - } - -+ -+/*[clinic input] -+@critical_section -+@setter -+BaseException.__traceback__ -+[clinic start generated code]*/ -+ - static int --BaseException_set_tb(PyBaseExceptionObject *self, PyObject *tb, void *Py_UNUSED(ignored)) -+BaseException___traceback___set_impl(PyBaseExceptionObject *self, -+ PyObject *value) -+/*[clinic end generated code: output=a82c86d9f29f48f0 input=12676035676badad]*/ - { -- if (tb == NULL) { -+ if (value == NULL) { - PyErr_SetString(PyExc_TypeError, "__traceback__ may not be deleted"); - return -1; - } -- if (PyTraceBack_Check(tb)) { -- Py_XSETREF(self->traceback, Py_NewRef(tb)); -+ if (PyTraceBack_Check(value)) { -+ Py_XSETREF(self->traceback, Py_NewRef(value)); - } -- else if (tb == Py_None) { -+ else if (value == Py_None) { - Py_CLEAR(self->traceback); - } - else { -@@ -337,73 +409,100 @@ - return 0; - } - -+/*[clinic input] -+@critical_section -+@getter -+BaseException.__context__ -+[clinic start generated code]*/ -+ - static PyObject * --BaseException_get_context(PyObject *self, void *Py_UNUSED(ignored)) -+BaseException___context___get_impl(PyBaseExceptionObject *self) -+/*[clinic end generated code: output=6ec5d296ce8d1c93 input=b2d22687937e66ab]*/ - { -- PyObject *res = PyException_GetContext(self); -- if (res) -- return res; /* new reference already returned above */ -- Py_RETURN_NONE; -+ if (self->context == NULL) { -+ Py_RETURN_NONE; -+ } -+ return Py_NewRef(self->context); - } - -+/*[clinic input] -+@critical_section -+@setter -+BaseException.__context__ -+[clinic start generated code]*/ -+ - static int --BaseException_set_context(PyObject *self, PyObject *arg, void *Py_UNUSED(ignored)) -+BaseException___context___set_impl(PyBaseExceptionObject *self, -+ PyObject *value) -+/*[clinic end generated code: output=b4cb52dcca1da3bd input=c0971adf47fa1858]*/ - { -- if (arg == NULL) { -+ if (value == NULL) { - PyErr_SetString(PyExc_TypeError, "__context__ may not be deleted"); - return -1; -- } else if (arg == Py_None) { -- arg = NULL; -- } else if (!PyExceptionInstance_Check(arg)) { -+ } else if (value == Py_None) { -+ value = NULL; -+ } else if (!PyExceptionInstance_Check(value)) { - PyErr_SetString(PyExc_TypeError, "exception context must be None " - "or derive from BaseException"); - return -1; - } else { -- /* PyException_SetContext steals this reference */ -- Py_INCREF(arg); -+ Py_INCREF(value); - } -- PyException_SetContext(self, arg); -+ Py_XSETREF(self->context, value); - return 0; - } - -+/*[clinic input] -+@critical_section -+@getter -+BaseException.__cause__ -+[clinic start generated code]*/ -+ - static PyObject * --BaseException_get_cause(PyObject *self, void *Py_UNUSED(ignored)) -+BaseException___cause___get_impl(PyBaseExceptionObject *self) -+/*[clinic end generated code: output=987f6c4d8a0bdbab input=40e0eac427b6e602]*/ - { -- PyObject *res = PyException_GetCause(self); -- if (res) -- return res; /* new reference already returned above */ -- Py_RETURN_NONE; -+ if (self->cause == NULL) { -+ Py_RETURN_NONE; -+ } -+ return Py_NewRef(self->cause); - } - -+/*[clinic input] -+@critical_section -+@setter -+BaseException.__cause__ -+[clinic start generated code]*/ -+ - static int --BaseException_set_cause(PyObject *self, PyObject *arg, void *Py_UNUSED(ignored)) -+BaseException___cause___set_impl(PyBaseExceptionObject *self, -+ PyObject *value) -+/*[clinic end generated code: output=6161315398aaf541 input=e1b403c0bde3f62a]*/ - { -- if (arg == NULL) { -+ if (value == NULL) { - PyErr_SetString(PyExc_TypeError, "__cause__ may not be deleted"); - return -1; -- } else if (arg == Py_None) { -- arg = NULL; -- } else if (!PyExceptionInstance_Check(arg)) { -+ } else if (value == Py_None) { -+ value = NULL; -+ } else if (!PyExceptionInstance_Check(value)) { - PyErr_SetString(PyExc_TypeError, "exception cause must be None " - "or derive from BaseException"); - return -1; - } else { - /* PyException_SetCause steals this reference */ -- Py_INCREF(arg); -+ Py_INCREF(value); - } -- PyException_SetCause(self, arg); -+ PyException_SetCause((PyObject *)self, value); - return 0; - } - - - static PyGetSetDef BaseException_getset[] = { - {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict}, -- {"args", (getter)BaseException_get_args, (setter)BaseException_set_args}, -- {"__traceback__", (getter)BaseException_get_tb, (setter)BaseException_set_tb}, -- {"__context__", BaseException_get_context, -- BaseException_set_context, PyDoc_STR("exception context")}, -- {"__cause__", BaseException_get_cause, -- BaseException_set_cause, PyDoc_STR("exception cause")}, -+ BASEEXCEPTION_ARGS_GETSETDEF -+ BASEEXCEPTION___TRACEBACK___GETSETDEF -+ BASEEXCEPTION___CONTEXT___GETSETDEF -+ BASEEXCEPTION___CAUSE___GETSETDEF - {NULL}, - }; - -@@ -411,59 +510,81 @@ - PyObject * - PyException_GetTraceback(PyObject *self) - { -- PyBaseExceptionObject *base_self = _PyBaseExceptionObject_cast(self); -- return Py_XNewRef(base_self->traceback); -+ PyObject *traceback; -+ Py_BEGIN_CRITICAL_SECTION(self); -+ traceback = Py_XNewRef(_PyBaseExceptionObject_cast(self)->traceback); -+ Py_END_CRITICAL_SECTION(); -+ return traceback; - } - - - int - PyException_SetTraceback(PyObject *self, PyObject *tb) - { -- return BaseException_set_tb(_PyBaseExceptionObject_cast(self), tb, NULL); -+ int res; -+ Py_BEGIN_CRITICAL_SECTION(self); -+ res = BaseException___traceback___set_impl(_PyBaseExceptionObject_cast(self), tb); -+ Py_END_CRITICAL_SECTION(); -+ return res; - } - - PyObject * - PyException_GetCause(PyObject *self) - { -- PyObject *cause = _PyBaseExceptionObject_cast(self)->cause; -- return Py_XNewRef(cause); -+ PyObject *cause; -+ Py_BEGIN_CRITICAL_SECTION(self); -+ cause = Py_XNewRef(_PyBaseExceptionObject_cast(self)->cause); -+ Py_END_CRITICAL_SECTION(); -+ return cause; - } - - /* Steals a reference to cause */ - void - PyException_SetCause(PyObject *self, PyObject *cause) - { -+ Py_BEGIN_CRITICAL_SECTION(self); - PyBaseExceptionObject *base_self = _PyBaseExceptionObject_cast(self); - base_self->suppress_context = 1; - Py_XSETREF(base_self->cause, cause); -+ Py_END_CRITICAL_SECTION(); - } - - PyObject * - PyException_GetContext(PyObject *self) - { -- PyObject *context = _PyBaseExceptionObject_cast(self)->context; -- return Py_XNewRef(context); -+ PyObject *context; -+ Py_BEGIN_CRITICAL_SECTION(self); -+ context = Py_XNewRef(_PyBaseExceptionObject_cast(self)->context); -+ Py_END_CRITICAL_SECTION(); -+ return context; - } - - /* Steals a reference to context */ - void - PyException_SetContext(PyObject *self, PyObject *context) - { -+ Py_BEGIN_CRITICAL_SECTION(self); - Py_XSETREF(_PyBaseExceptionObject_cast(self)->context, context); -+ Py_END_CRITICAL_SECTION(); - } - - PyObject * - PyException_GetArgs(PyObject *self) - { -- PyObject *args = _PyBaseExceptionObject_cast(self)->args; -- return Py_NewRef(args); -+ PyObject *args; -+ Py_BEGIN_CRITICAL_SECTION(self); -+ args = Py_NewRef(_PyBaseExceptionObject_cast(self)->args); -+ Py_END_CRITICAL_SECTION(); -+ return args; - } - - void - PyException_SetArgs(PyObject *self, PyObject *args) - { -+ Py_BEGIN_CRITICAL_SECTION(self); - Py_INCREF(args); - Py_XSETREF(_PyBaseExceptionObject_cast(self)->args, args); -+ Py_END_CRITICAL_SECTION(); - } - - const char * -@@ -914,10 +1035,18 @@ - self->msg, num_excs, num_excs > 1 ? "s" : ""); - } - -+/*[clinic input] -+@critical_section -+BaseExceptionGroup.derive -+ excs: object -+ / -+[clinic start generated code]*/ -+ - static PyObject * --BaseExceptionGroup_derive(PyObject *self_, PyObject *excs) -+BaseExceptionGroup_derive_impl(PyBaseExceptionGroupObject *self, -+ PyObject *excs) -+/*[clinic end generated code: output=4307564218dfbf06 input=f72009d38e98cec1]*/ - { -- PyBaseExceptionGroupObject *self = _PyBaseExceptionGroupObject_cast(self_); - PyObject *init_args = PyTuple_Pack(2, self->msg, excs); - if (!init_args) { - return NULL; -@@ -1210,8 +1339,17 @@ - return retval; - } - -+/*[clinic input] -+@critical_section -+BaseExceptionGroup.split -+ matcher_value: object -+ / -+[clinic start generated code]*/ -+ - static PyObject * --BaseExceptionGroup_split(PyObject *self, PyObject *matcher_value) -+BaseExceptionGroup_split_impl(PyBaseExceptionGroupObject *self, -+ PyObject *matcher_value) -+/*[clinic end generated code: output=d74db579da4df6e2 input=0c5cfbfed57e0052]*/ - { - _exceptiongroup_split_matcher_type matcher_type; - if (get_matcher_type(matcher_value, &matcher_type) < 0) { -@@ -1221,7 +1359,7 @@ - _exceptiongroup_split_result split_result; - bool construct_rest = true; - if (exceptiongroup_split_recursive( -- self, matcher_type, matcher_value, -+ (PyObject *)self, matcher_type, matcher_value, - construct_rest, &split_result) < 0) { - return NULL; - } -@@ -1236,8 +1374,17 @@ - return result; - } - -+/*[clinic input] -+@critical_section -+BaseExceptionGroup.subgroup -+ matcher_value: object -+ / -+[clinic start generated code]*/ -+ - static PyObject * --BaseExceptionGroup_subgroup(PyObject *self, PyObject *matcher_value) -+BaseExceptionGroup_subgroup_impl(PyBaseExceptionGroupObject *self, -+ PyObject *matcher_value) -+/*[clinic end generated code: output=07dbec8f77d4dd8e input=988ffdd755a151ce]*/ - { - _exceptiongroup_split_matcher_type matcher_type; - if (get_matcher_type(matcher_value, &matcher_type) < 0) { -@@ -1247,7 +1394,7 @@ - _exceptiongroup_split_result split_result; - bool construct_rest = false; - if (exceptiongroup_split_recursive( -- self, matcher_type, matcher_value, -+ (PyObject *)self, matcher_type, matcher_value, - construct_rest, &split_result) < 0) { - return NULL; - } -@@ -1513,9 +1660,9 @@ - static PyMethodDef BaseExceptionGroup_methods[] = { - {"__class_getitem__", (PyCFunction)Py_GenericAlias, - METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, -- {"derive", (PyCFunction)BaseExceptionGroup_derive, METH_O}, -- {"split", (PyCFunction)BaseExceptionGroup_split, METH_O}, -- {"subgroup", (PyCFunction)BaseExceptionGroup_subgroup, METH_O}, -+ BASEEXCEPTIONGROUP_DERIVE_METHODDEF -+ BASEEXCEPTIONGROUP_SPLIT_METHODDEF -+ BASEEXCEPTIONGROUP_SUBGROUP_METHODDEF - {NULL} - }; - -@@ -2667,55 +2814,177 @@ - SimpleExtendsException(PyExc_ValueError, UnicodeError, - "Unicode related error."); - -+ -+/* -+ * Check the validity of 'attr' as a unicode or bytes object depending -+ * on 'as_bytes' and return a new reference on it if it is the case. -+ * -+ * The 'name' is the attribute name and is only used for error reporting. -+ * -+ * On success, this returns a strong reference on 'attr'. -+ * On failure, this sets a TypeError and returns NULL. -+ */ - static PyObject * --get_bytes(PyObject *attr, const char *name) -+as_unicode_error_attribute(PyObject *attr, const char *name, int as_bytes) - { -- if (!attr) { -- PyErr_Format(PyExc_TypeError, "%.200s attribute not set", name); -+ assert(as_bytes == 0 || as_bytes == 1); -+ if (attr == NULL) { -+ PyErr_Format(PyExc_TypeError, "%s attribute not set", name); - return NULL; - } -- -- if (!PyBytes_Check(attr)) { -- PyErr_Format(PyExc_TypeError, "%.200s attribute must be bytes", name); -+ if (!(as_bytes ? PyBytes_Check(attr) : PyUnicode_Check(attr))) { -+ PyErr_Format(PyExc_TypeError, -+ "%s attribute must be %s", -+ name, -+ as_bytes ? "bytes" : "unicode"); - return NULL; - } - return Py_NewRef(attr); - } - --static PyObject * --get_unicode(PyObject *attr, const char *name) --{ -- if (!attr) { -- PyErr_Format(PyExc_TypeError, "%.200s attribute not set", name); -- return NULL; -- } - -- if (!PyUnicode_Check(attr)) { -+#define PyUnicodeError_Check(PTR) \ -+ PyObject_TypeCheck((PTR), (PyTypeObject *)PyExc_UnicodeError) -+#define PyUnicodeError_CAST(PTR) \ -+ (assert(PyUnicodeError_Check(PTR)), ((PyUnicodeErrorObject *)(PTR))) -+ -+ -+/* class names to use when reporting errors */ -+#define Py_UNICODE_ENCODE_ERROR_NAME "UnicodeEncodeError" -+#define Py_UNICODE_DECODE_ERROR_NAME "UnicodeDecodeError" -+#define Py_UNICODE_TRANSLATE_ERROR_NAME "UnicodeTranslateError" -+ -+ -+/* -+ * Check that 'self' is a UnicodeError object. -+ * -+ * On success, this returns 0. -+ * On failure, this sets a TypeError exception and returns -1. -+ * -+ * The 'expect_type' is the name of the expected type, which is -+ * only used for error reporting. -+ * -+ * As an implementation detail, the `PyUnicode*Error_*` functions -+ * currently allow *any* subclass of UnicodeError as 'self'. -+ * -+ * Use one of the `Py_UNICODE_*_ERROR_NAME` macros to avoid typos. -+ */ -+static inline int -+check_unicode_error_type(PyObject *self, const char *expect_type) -+{ -+ assert(self != NULL); -+ if (!PyUnicodeError_Check(self)) { - PyErr_Format(PyExc_TypeError, -- "%.200s attribute must be unicode", name); -- return NULL; -+ "expecting a %s object, got %T", expect_type, self); -+ return -1; - } -- return Py_NewRef(attr); -+ return 0; - } - --static int --set_unicodefromstring(PyObject **attr, const char *value) -+ -+// --- PyUnicodeEncodeObject: internal helpers -------------------------------- -+// -+// In the helpers below, the caller is responsible to ensure that 'self' -+// is a PyUnicodeErrorObject, although this is verified on DEBUG builds -+// through PyUnicodeError_CAST(). -+ -+/* -+ * Return the underlying (str) 'encoding' attribute of a UnicodeError object. -+ */ -+static inline PyObject * -+unicode_error_get_encoding_impl(PyObject *self) -+{ -+ assert(self != NULL); -+ PyUnicodeErrorObject *exc = PyUnicodeError_CAST(self); -+ return as_unicode_error_attribute(exc->encoding, "encoding", false); -+} -+ -+ -+/* -+ * Return the underlying 'object' attribute of a UnicodeError object -+ * as a bytes or a string instance, depending on the 'as_bytes' flag. -+ */ -+static inline PyObject * -+unicode_error_get_object_impl(PyObject *self, int as_bytes) -+{ -+ assert(self != NULL); -+ PyUnicodeErrorObject *exc = PyUnicodeError_CAST(self); -+ return as_unicode_error_attribute(exc->object, "object", as_bytes); -+} -+ -+ -+/* -+ * Return the underlying (str) 'reason' attribute of a UnicodeError object. -+ */ -+static inline PyObject * -+unicode_error_get_reason_impl(PyObject *self) -+{ -+ assert(self != NULL); -+ PyUnicodeErrorObject *exc = PyUnicodeError_CAST(self); -+ return as_unicode_error_attribute(exc->reason, "reason", false); -+} -+ -+ -+/* -+ * Set the underlying (str) 'reason' attribute of a UnicodeError object. -+ * -+ * Return 0 on success and -1 on failure. -+ */ -+static inline int -+unicode_error_set_reason_impl(PyObject *self, const char *reason) - { -- PyObject *obj = PyUnicode_FromString(value); -- if (!obj) -+ assert(self != NULL); -+ PyObject *value = PyUnicode_FromString(reason); -+ if (value == NULL) { - return -1; -- Py_XSETREF(*attr, obj); -+ } -+ PyUnicodeErrorObject *exc = PyUnicodeError_CAST(self); -+ Py_XSETREF(exc->reason, value); - return 0; - } - -+ -+/* -+ * Set the 'start' attribute of a UnicodeError object. -+ * -+ * Return 0 on success and -1 on failure. -+ */ -+static inline int -+unicode_error_set_start_impl(PyObject *self, Py_ssize_t start) -+{ -+ assert(self != NULL); -+ PyUnicodeErrorObject *exc = PyUnicodeError_CAST(self); -+ exc->start = start; -+ return 0; -+} -+ -+ -+/* -+ * Set the 'end' attribute of a UnicodeError object. -+ * -+ * Return 0 on success and -1 on failure. -+ */ -+static inline int -+unicode_error_set_end_impl(PyObject *self, Py_ssize_t end) -+{ -+ assert(self != NULL); -+ PyUnicodeErrorObject *exc = PyUnicodeError_CAST(self); -+ exc->end = end; -+ return 0; -+} -+ -+// --- PyUnicodeEncodeObject: internal getters -------------------------------- -+ - /* - * Adjust the (inclusive) 'start' value of a UnicodeError object. - * - * The 'start' can be negative or not, but when adjusting the value, - * we clip it in [0, max(0, objlen - 1)] and do not interpret it as - * a relative offset. -+ * -+ * This function always succeeds. - */ --static inline Py_ssize_t -+static Py_ssize_t - unicode_error_adjust_start(Py_ssize_t start, Py_ssize_t objlen) - { - assert(objlen >= 0); -@@ -2728,14 +2997,35 @@ - return start; - } - -+ -+/* Assert some properties of the adjusted 'start' value. */ -+#ifndef NDEBUG -+static void -+assert_adjusted_unicode_error_start(Py_ssize_t start, Py_ssize_t objlen) -+{ -+ assert(objlen >= 0); -+ /* in the future, `min_start` may be something else */ -+ Py_ssize_t min_start = 0; -+ assert(start >= min_start); -+ /* in the future, `max_start` may be something else */ -+ Py_ssize_t max_start = Py_MAX(min_start, objlen - 1); -+ assert(start <= max_start); -+} -+#else -+#define assert_adjusted_unicode_error_start(...) -+#endif -+ -+ - /* - * Adjust the (exclusive) 'end' value of a UnicodeError object. - * - * The 'end' can be negative or not, but when adjusting the value, - * we clip it in [min(1, objlen), max(min(1, objlen), objlen)] and - * do not interpret it as a relative offset. -+ * -+ * This function always succeeds. - */ --static inline Py_ssize_t -+static Py_ssize_t - unicode_error_adjust_end(Py_ssize_t end, Py_ssize_t objlen) - { - assert(objlen >= 0); -@@ -2748,134 +3038,233 @@ - return end; - } - --#define _PyUnicodeError_CAST(PTR) ((PyUnicodeErrorObject *)(PTR)) --#define PyUnicodeError_Check(PTR) \ -- PyObject_TypeCheck((PTR), (PyTypeObject *)PyExc_UnicodeError) --#define PyUnicodeError_CAST(PTR) \ -- (assert(PyUnicodeError_Check(PTR)), _PyUnicodeError_CAST(PTR)) - -+/* Assert some properties of the adjusted 'end' value. */ -+#ifndef NDEBUG -+static void -+assert_adjusted_unicode_error_end(Py_ssize_t end, Py_ssize_t objlen) -+{ -+ assert(objlen >= 0); -+ /* in the future, `min_end` may be something else */ -+ Py_ssize_t min_end = Py_MIN(1, objlen); -+ assert(end >= min_end); -+ /* in the future, `max_end` may be something else */ -+ Py_ssize_t max_end = Py_MAX(min_end, objlen); -+ assert(end <= max_end); -+} -+#else -+#define assert_adjusted_unicode_error_end(...) -+#endif - --static inline int --check_unicode_error_type(PyObject *self, const char *expect_type) -+ -+/* -+ * Adjust the length of the range described by a UnicodeError object. -+ * -+ * The 'start' and 'end' arguments must have been obtained by -+ * unicode_error_adjust_start() and unicode_error_adjust_end(). -+ * -+ * The result is clipped in [0, objlen]. By construction, it -+ * will always be smaller than 'objlen' as 'start' and 'end' -+ * are smaller than 'objlen'. -+ */ -+static Py_ssize_t -+unicode_error_adjust_len(Py_ssize_t start, Py_ssize_t end, Py_ssize_t objlen) - { -- if (!PyUnicodeError_Check(self)) { -- PyErr_Format(PyExc_TypeError, -- "expecting a %s object, got %T", expect_type, self); -+ assert_adjusted_unicode_error_start(start, objlen); -+ assert_adjusted_unicode_error_end(end, objlen); -+ Py_ssize_t ranlen = end - start; -+ assert(ranlen <= objlen); -+ return ranlen < 0 ? 0 : ranlen; -+} -+ -+ -+/* Assert some properties of the adjusted range 'len' value. */ -+#ifndef NDEBUG -+static void -+assert_adjusted_unicode_error_len(Py_ssize_t ranlen, Py_ssize_t objlen) -+{ -+ assert(objlen >= 0); -+ assert(ranlen >= 0); -+ assert(ranlen <= objlen); -+} -+#else -+#define assert_adjusted_unicode_error_len(...) -+#endif -+ -+ -+/* -+ * Get various common parameters of a UnicodeError object. -+ * -+ * The caller is responsible to ensure that 'self' is a PyUnicodeErrorObject, -+ * although this condition is verified by this function on DEBUG builds. -+ * -+ * Return 0 on success and -1 on failure. -+ * -+ * Output parameters: -+ * -+ * obj A strong reference to the 'object' attribute. -+ * objlen The 'object' length. -+ * start The clipped 'start' attribute. -+ * end The clipped 'end' attribute. -+ * slen The length of the slice described by the clipped 'start' -+ * and 'end' values. It always lies in [0, objlen]. -+ * -+ * An output parameter can be NULL to indicate that -+ * the corresponding value does not need to be stored. -+ * -+ * Input parameter: -+ * -+ * as_bytes If true, the error's 'object' attribute must be a `bytes`, -+ * i.e. 'self' is a `UnicodeDecodeError` instance. Otherwise, -+ * the 'object' attribute must be a string. -+ * -+ * A TypeError is raised if the 'object' type is incompatible. -+ */ -+int -+_PyUnicodeError_GetParams(PyObject *self, -+ PyObject **obj, Py_ssize_t *objlen, -+ Py_ssize_t *start, Py_ssize_t *end, Py_ssize_t *slen, -+ int as_bytes) -+{ -+ assert(self != NULL); -+ assert(as_bytes == 0 || as_bytes == 1); -+ PyUnicodeErrorObject *exc = PyUnicodeError_CAST(self); -+ PyObject *r = as_unicode_error_attribute(exc->object, "object", as_bytes); -+ if (r == NULL) { - return -1; - } -+ -+ Py_ssize_t n = as_bytes ? PyBytes_GET_SIZE(r) : PyUnicode_GET_LENGTH(r); -+ if (objlen != NULL) { -+ *objlen = n; -+ } -+ -+ Py_ssize_t start_value = -1; -+ if (start != NULL || slen != NULL) { -+ start_value = unicode_error_adjust_start(exc->start, n); -+ } -+ if (start != NULL) { -+ assert_adjusted_unicode_error_start(start_value, n); -+ *start = start_value; -+ } -+ -+ Py_ssize_t end_value = -1; -+ if (end != NULL || slen != NULL) { -+ end_value = unicode_error_adjust_end(exc->end, n); -+ } -+ if (end != NULL) { -+ assert_adjusted_unicode_error_end(end_value, n); -+ *end = end_value; -+ } -+ -+ if (slen != NULL) { -+ *slen = unicode_error_adjust_len(start_value, end_value, n); -+ assert_adjusted_unicode_error_len(*slen, n); -+ } -+ -+ if (obj != NULL) { -+ *obj = r; -+ } -+ else { -+ Py_DECREF(r); -+ } - return 0; - } - - --static inline PyUnicodeErrorObject * --as_unicode_error(PyObject *self, const char *expect_type) --{ -- int rc = check_unicode_error_type(self, expect_type); -- return rc < 0 ? NULL : _PyUnicodeError_CAST(self); --} -+// --- PyUnicodeEncodeObject: 'encoding' getters ------------------------------ -+// Note: PyUnicodeTranslateError does not have an 'encoding' attribute. - - PyObject * - PyUnicodeEncodeError_GetEncoding(PyObject *self) - { -- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeEncodeError"); -- return exc == NULL ? NULL : get_unicode(exc->encoding, "encoding"); -+ int rc = check_unicode_error_type(self, Py_UNICODE_ENCODE_ERROR_NAME); -+ return rc < 0 ? NULL : unicode_error_get_encoding_impl(self); - } - -+ - PyObject * - PyUnicodeDecodeError_GetEncoding(PyObject *self) - { -- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeDecodeError"); -- return exc == NULL ? NULL : get_unicode(exc->encoding, "encoding"); -+ int rc = check_unicode_error_type(self, Py_UNICODE_DECODE_ERROR_NAME); -+ return rc < 0 ? NULL : unicode_error_get_encoding_impl(self); - } - -+ -+// --- PyUnicodeEncodeObject: 'object' getters -------------------------------- -+ - PyObject * - PyUnicodeEncodeError_GetObject(PyObject *self) - { -- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeEncodeError"); -- return exc == NULL ? NULL : get_unicode(exc->object, "object"); -+ int rc = check_unicode_error_type(self, Py_UNICODE_ENCODE_ERROR_NAME); -+ return rc < 0 ? NULL : unicode_error_get_object_impl(self, false); - } - -+ - PyObject * - PyUnicodeDecodeError_GetObject(PyObject *self) - { -- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeDecodeError"); -- return exc == NULL ? NULL : get_bytes(exc->object, "object"); -+ int rc = check_unicode_error_type(self, Py_UNICODE_DECODE_ERROR_NAME); -+ return rc < 0 ? NULL : unicode_error_get_object_impl(self, true); - } - -+ - PyObject * - PyUnicodeTranslateError_GetObject(PyObject *self) - { -- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeTranslateError"); -- return exc == NULL ? NULL : get_unicode(exc->object, "object"); -+ int rc = check_unicode_error_type(self, Py_UNICODE_TRANSLATE_ERROR_NAME); -+ return rc < 0 ? NULL : unicode_error_get_object_impl(self, false); -+} -+ -+ -+// --- PyUnicodeEncodeObject: 'start' getters --------------------------------- -+ -+/* -+ * Specialization of _PyUnicodeError_GetParams() for the 'start' attribute. -+ * -+ * The caller is responsible to ensure that 'self' is a PyUnicodeErrorObject, -+ * although this condition is verified by this function on DEBUG builds. -+ */ -+static inline int -+unicode_error_get_start_impl(PyObject *self, Py_ssize_t *start, int as_bytes) -+{ -+ assert(self != NULL); -+ return _PyUnicodeError_GetParams(self, NULL, NULL, -+ start, NULL, NULL, -+ as_bytes); - } - -+ - int - PyUnicodeEncodeError_GetStart(PyObject *self, Py_ssize_t *start) - { -- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeEncodeError"); -- if (exc == NULL) { -- return -1; -- } -- PyObject *obj = get_unicode(exc->object, "object"); -- if (obj == NULL) { -- return -1; -- } -- Py_ssize_t size = PyUnicode_GET_LENGTH(obj); -- Py_DECREF(obj); -- *start = unicode_error_adjust_start(exc->start, size); -- return 0; -+ int rc = check_unicode_error_type(self, Py_UNICODE_ENCODE_ERROR_NAME); -+ return rc < 0 ? -1 : unicode_error_get_start_impl(self, start, false); - } - - - int - PyUnicodeDecodeError_GetStart(PyObject *self, Py_ssize_t *start) - { -- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeDecodeError"); -- if (exc == NULL) { -- return -1; -- } -- PyObject *obj = get_bytes(exc->object, "object"); -- if (obj == NULL) { -- return -1; -- } -- Py_ssize_t size = PyBytes_GET_SIZE(obj); -- Py_DECREF(obj); -- *start = unicode_error_adjust_start(exc->start, size); -- return 0; -+ int rc = check_unicode_error_type(self, Py_UNICODE_DECODE_ERROR_NAME); -+ return rc < 0 ? -1 : unicode_error_get_start_impl(self, start, true); - } - - - int - PyUnicodeTranslateError_GetStart(PyObject *self, Py_ssize_t *start) - { -- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeTranslateError"); -- if (exc == NULL) { -- return -1; -- } -- PyObject *obj = get_unicode(exc->object, "object"); -- if (obj == NULL) { -- return -1; -- } -- Py_ssize_t size = PyUnicode_GET_LENGTH(obj); -- Py_DECREF(obj); -- *start = unicode_error_adjust_start(exc->start, size); -- return 0; -+ int rc = check_unicode_error_type(self, Py_UNICODE_TRANSLATE_ERROR_NAME); -+ return rc < 0 ? -1 : unicode_error_get_start_impl(self, start, false); - } - - --static inline int --unicode_error_set_start_impl(PyObject *self, Py_ssize_t start) --{ -- PyUnicodeErrorObject *exc = _PyUnicodeError_CAST(self); -- exc->start = start; -- return 0; --} -- -+// --- PyUnicodeEncodeObject: 'start' setters --------------------------------- - - int - PyUnicodeEncodeError_SetStart(PyObject *self, Py_ssize_t start) - { -- int rc = check_unicode_error_type(self, "UnicodeEncodeError"); -+ int rc = check_unicode_error_type(self, Py_UNICODE_ENCODE_ERROR_NAME); - return rc < 0 ? -1 : unicode_error_set_start_impl(self, start); - } - -@@ -2883,7 +3272,7 @@ - int - PyUnicodeDecodeError_SetStart(PyObject *self, Py_ssize_t start) - { -- int rc = check_unicode_error_type(self, "UnicodeDecodeError"); -+ int rc = check_unicode_error_type(self, Py_UNICODE_DECODE_ERROR_NAME); - return rc < 0 ? -1 : unicode_error_set_start_impl(self, start); - } - -@@ -2891,78 +3280,59 @@ - int - PyUnicodeTranslateError_SetStart(PyObject *self, Py_ssize_t start) - { -- int rc = check_unicode_error_type(self, "UnicodeTranslateError"); -+ int rc = check_unicode_error_type(self, Py_UNICODE_TRANSLATE_ERROR_NAME); - return rc < 0 ? -1 : unicode_error_set_start_impl(self, start); - } - - -+// --- PyUnicodeEncodeObject: 'end' getters ----------------------------------- -+ -+/* -+ * Specialization of _PyUnicodeError_GetParams() for the 'end' attribute. -+ * -+ * The caller is responsible to ensure that 'self' is a PyUnicodeErrorObject, -+ * although this condition is verified by this function on DEBUG builds. -+ */ -+static inline int -+unicode_error_get_end_impl(PyObject *self, Py_ssize_t *end, int as_bytes) -+{ -+ assert(self != NULL); -+ return _PyUnicodeError_GetParams(self, NULL, NULL, -+ NULL, end, NULL, -+ as_bytes); -+} -+ -+ - int - PyUnicodeEncodeError_GetEnd(PyObject *self, Py_ssize_t *end) - { -- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeEncodeError"); -- if (exc == NULL) { -- return -1; -- } -- PyObject *obj = get_unicode(exc->object, "object"); -- if (obj == NULL) { -- return -1; -- } -- Py_ssize_t size = PyUnicode_GET_LENGTH(obj); -- Py_DECREF(obj); -- *end = unicode_error_adjust_end(exc->end, size); -- return 0; -+ int rc = check_unicode_error_type(self, Py_UNICODE_ENCODE_ERROR_NAME); -+ return rc < 0 ? -1 : unicode_error_get_end_impl(self, end, false); - } - - - int - PyUnicodeDecodeError_GetEnd(PyObject *self, Py_ssize_t *end) - { -- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeDecodeError"); -- if (exc == NULL) { -- return -1; -- } -- PyObject *obj = get_bytes(exc->object, "object"); -- if (obj == NULL) { -- return -1; -- } -- Py_ssize_t size = PyBytes_GET_SIZE(obj); -- Py_DECREF(obj); -- *end = unicode_error_adjust_end(exc->end, size); -- return 0; -+ int rc = check_unicode_error_type(self, Py_UNICODE_DECODE_ERROR_NAME); -+ return rc < 0 ? -1 : unicode_error_get_end_impl(self, end, true); - } - - - int - PyUnicodeTranslateError_GetEnd(PyObject *self, Py_ssize_t *end) - { -- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeTranslateError"); -- if (exc == NULL) { -- return -1; -- } -- PyObject *obj = get_unicode(exc->object, "object"); -- if (obj == NULL) { -- return -1; -- } -- Py_ssize_t size = PyUnicode_GET_LENGTH(obj); -- Py_DECREF(obj); -- *end = unicode_error_adjust_end(exc->end, size); -- return 0; -+ int rc = check_unicode_error_type(self, Py_UNICODE_TRANSLATE_ERROR_NAME); -+ return rc < 0 ? -1 : unicode_error_get_end_impl(self, end, false); - } - - --static inline int --unicode_error_set_end_impl(PyObject *self, Py_ssize_t end) --{ -- PyUnicodeErrorObject *exc = _PyUnicodeError_CAST(self); -- exc->end = end; -- return 0; --} -- -+// --- PyUnicodeEncodeObject: 'end' setters ----------------------------------- - - int - PyUnicodeEncodeError_SetEnd(PyObject *self, Py_ssize_t end) - { -- int rc = check_unicode_error_type(self, "UnicodeEncodeError"); -+ int rc = check_unicode_error_type(self, Py_UNICODE_ENCODE_ERROR_NAME); - return rc < 0 ? -1 : unicode_error_set_end_impl(self, end); - } - -@@ -2970,7 +3340,7 @@ - int - PyUnicodeDecodeError_SetEnd(PyObject *self, Py_ssize_t end) - { -- int rc = check_unicode_error_type(self, "UnicodeDecodeError"); -+ int rc = check_unicode_error_type(self, Py_UNICODE_DECODE_ERROR_NAME); - return rc < 0 ? -1 : unicode_error_set_end_impl(self, end); - } - -@@ -2978,56 +3348,60 @@ - int - PyUnicodeTranslateError_SetEnd(PyObject *self, Py_ssize_t end) - { -- int rc = check_unicode_error_type(self, "UnicodeTranslateError"); -+ int rc = check_unicode_error_type(self, Py_UNICODE_TRANSLATE_ERROR_NAME); - return rc < 0 ? -1 : unicode_error_set_end_impl(self, end); - } - - -+// --- PyUnicodeEncodeObject: 'reason' getters -------------------------------- -+ - PyObject * - PyUnicodeEncodeError_GetReason(PyObject *self) - { -- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeEncodeError"); -- return exc == NULL ? NULL : get_unicode(exc->reason, "reason"); -+ int rc = check_unicode_error_type(self, Py_UNICODE_ENCODE_ERROR_NAME); -+ return rc < 0 ? NULL : unicode_error_get_reason_impl(self); - } - - - PyObject * - PyUnicodeDecodeError_GetReason(PyObject *self) - { -- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeDecodeError"); -- return exc == NULL ? NULL : get_unicode(exc->reason, "reason"); -+ int rc = check_unicode_error_type(self, Py_UNICODE_DECODE_ERROR_NAME); -+ return rc < 0 ? NULL : unicode_error_get_reason_impl(self); - } - - - PyObject * - PyUnicodeTranslateError_GetReason(PyObject *self) - { -- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeTranslateError"); -- return exc == NULL ? NULL : get_unicode(exc->reason, "reason"); -+ int rc = check_unicode_error_type(self, Py_UNICODE_TRANSLATE_ERROR_NAME); -+ return rc < 0 ? NULL : unicode_error_get_reason_impl(self); - } - - -+// --- PyUnicodeEncodeObject: 'reason' setters -------------------------------- -+ - int - PyUnicodeEncodeError_SetReason(PyObject *self, const char *reason) - { -- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeEncodeError"); -- return exc == NULL ? -1 : set_unicodefromstring(&exc->reason, reason); -+ int rc = check_unicode_error_type(self, Py_UNICODE_ENCODE_ERROR_NAME); -+ return rc < 0 ? -1 : unicode_error_set_reason_impl(self, reason); - } - - - int - PyUnicodeDecodeError_SetReason(PyObject *self, const char *reason) - { -- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeDecodeError"); -- return exc == NULL ? -1 : set_unicodefromstring(&exc->reason, reason); -+ int rc = check_unicode_error_type(self, Py_UNICODE_DECODE_ERROR_NAME); -+ return rc < 0 ? -1 : unicode_error_set_reason_impl(self, reason); - } - - - int - PyUnicodeTranslateError_SetReason(PyObject *self, const char *reason) - { -- PyUnicodeErrorObject *exc = as_unicode_error(self, "UnicodeTranslateError"); -- return exc == NULL ? -1 : set_unicodefromstring(&exc->reason, reason); -+ int rc = check_unicode_error_type(self, Py_UNICODE_TRANSLATE_ERROR_NAME); -+ return rc < 0 ? -1 : unicode_error_set_reason_impl(self, reason); - } - - -@@ -3458,36 +3832,43 @@ - - #define MEMERRORS_SAVE 16 - -+#ifdef Py_GIL_DISABLED -+# define MEMERRORS_LOCK(state) PyMutex_LockFlags(&state->memerrors_lock, _Py_LOCK_DONT_DETACH) -+# define MEMERRORS_UNLOCK(state) PyMutex_Unlock(&state->memerrors_lock) -+#else -+# define MEMERRORS_LOCK(state) ((void)0) -+# define MEMERRORS_UNLOCK(state) ((void)0) -+#endif -+ - static PyObject * - get_memory_error(int allow_allocation, PyObject *args, PyObject *kwds) - { -- PyBaseExceptionObject *self; -+ PyBaseExceptionObject *self = NULL; - struct _Py_exc_state *state = get_exc_state(); -- if (state->memerrors_freelist == NULL) { -- if (!allow_allocation) { -- PyInterpreterState *interp = _PyInterpreterState_GET(); -- return Py_NewRef( -- &_Py_INTERP_SINGLETON(interp, last_resort_memory_error)); -- } -- PyObject *result = BaseException_new((PyTypeObject *)PyExc_MemoryError, args, kwds); -- return result; -- } - -- /* Fetch object from freelist and revive it */ -- self = state->memerrors_freelist; -- self->args = PyTuple_New(0); -- /* This shouldn't happen since the empty tuple is persistent */ -+ MEMERRORS_LOCK(state); -+ if (state->memerrors_freelist != NULL) { -+ /* Fetch MemoryError from freelist and initialize it */ -+ self = state->memerrors_freelist; -+ state->memerrors_freelist = (PyBaseExceptionObject *) self->dict; -+ state->memerrors_numfree--; -+ self->dict = NULL; -+ self->args = (PyObject *)&_Py_SINGLETON(tuple_empty); -+ _Py_NewReference((PyObject *)self); -+ _PyObject_GC_TRACK(self); -+ } -+ MEMERRORS_UNLOCK(state); - -- if (self->args == NULL) { -- return NULL; -+ if (self != NULL) { -+ return (PyObject *)self; - } - -- state->memerrors_freelist = (PyBaseExceptionObject *) self->dict; -- state->memerrors_numfree--; -- self->dict = NULL; -- _Py_NewReference((PyObject *)self); -- _PyObject_GC_TRACK(self); -- return (PyObject *)self; -+ if (!allow_allocation) { -+ PyInterpreterState *interp = _PyInterpreterState_GET(); -+ return Py_NewRef( -+ &_Py_INTERP_SINGLETON(interp, last_resort_memory_error)); -+ } -+ return BaseException_new((PyTypeObject *)PyExc_MemoryError, args, kwds); - } - - static PyObject * -@@ -3533,14 +3914,17 @@ - } - - struct _Py_exc_state *state = get_exc_state(); -- if (state->memerrors_numfree >= MEMERRORS_SAVE) { -- Py_TYPE(self)->tp_free((PyObject *)self); -- } -- else { -+ MEMERRORS_LOCK(state); -+ if (state->memerrors_numfree < MEMERRORS_SAVE) { - self->dict = (PyObject *) state->memerrors_freelist; - state->memerrors_freelist = self; - state->memerrors_numfree++; -+ MEMERRORS_UNLOCK(state); -+ return; - } -+ MEMERRORS_UNLOCK(state); -+ -+ Py_TYPE(self)->tp_free((PyObject *)self); - } - - static int -diff --git a/Objects/fileobject.c b/Objects/fileobject.c -index c377d1bb28b..7025b5bcffc 100644 ---- a/Objects/fileobject.c -+++ b/Objects/fileobject.c -@@ -34,7 +34,7 @@ - PyObject *open, *stream; - - /* import _io in case we are being used to open io.py */ -- open = _PyImport_GetModuleAttrString("_io", "open"); -+ open = PyImport_ImportModuleAttrString("_io", "open"); - if (open == NULL) - return NULL; - stream = PyObject_CallFunction(open, "isisssO", fd, mode, -@@ -506,7 +506,7 @@ - if (hook) { - f = hook(path, _PyRuntime.open_code_userdata); - } else { -- PyObject *open = _PyImport_GetModuleAttrString("_io", "open"); -+ PyObject *open = PyImport_ImportModuleAttrString("_io", "open"); - if (open) { - f = PyObject_CallFunction(open, "Os", path, "rb"); - Py_DECREF(open); -diff --git a/Objects/floatobject.c b/Objects/floatobject.c -index bcc77287454..3b72a1e7c37 100644 ---- a/Objects/floatobject.c -+++ b/Objects/floatobject.c -@@ -369,8 +369,9 @@ - } - - static PyObject * --float_repr(PyFloatObject *v) -+float_repr(PyObject *op) - { -+ PyFloatObject *v = _PyFloat_CAST(op); - PyObject *result; - char *buf; - -@@ -428,9 +429,10 @@ - - else if (PyLong_Check(w)) { - int vsign = i == 0.0 ? 0 : i < 0.0 ? -1 : 1; -- int wsign = _PyLong_Sign(w); -+ int wsign; - int exponent; - -+ (void)PyLong_GetSign(w, &wsign); - if (vsign != wsign) { - /* Magnitudes are irrelevant -- the signs alone - * determine the outcome. -@@ -578,9 +580,10 @@ - } - - static Py_hash_t --float_hash(PyFloatObject *v) -+float_hash(PyObject *op) - { -- return _Py_HashDouble((PyObject *)v, v->ob_fval); -+ PyFloatObject *v = _PyFloat_CAST(op); -+ return _Py_HashDouble(op, v->ob_fval); - } - - static PyObject * -@@ -850,20 +853,23 @@ - #undef DOUBLE_IS_ODD_INTEGER - - static PyObject * --float_neg(PyFloatObject *v) -+float_neg(PyObject *op) - { -+ PyFloatObject *v = _PyFloat_CAST(op); - return PyFloat_FromDouble(-v->ob_fval); - } - - static PyObject * --float_abs(PyFloatObject *v) -+float_abs(PyObject *op) - { -+ PyFloatObject *v = _PyFloat_CAST(op); - return PyFloat_FromDouble(fabs(v->ob_fval)); - } - - static int --float_bool(PyFloatObject *v) -+float_bool(PyObject *op) - { -+ PyFloatObject *v = _PyFloat_CAST(op); - return v->ob_fval != 0.0; - } - -@@ -1205,7 +1211,7 @@ - CONVERT_TO_DOUBLE(self, x); - - if (isnan(x) || isinf(x)) -- return float_repr((PyFloatObject *)self); -+ return float_repr(self); - - if (x == 0.0) { - if (copysign(1.0, x) == -1.0) -@@ -1650,7 +1656,7 @@ - } - - static PyObject * --float_vectorcall(PyObject *type, PyObject * const*args, -+float_vectorcall(PyObject *type, PyObject *const *args, - size_t nargsf, PyObject *kwnames) - { - if (!_PyArg_NoKwnames("float", kwnames)) { -@@ -1770,13 +1776,13 @@ - - - static PyObject * --float_getreal(PyObject *v, void *closure) -+float_getreal(PyObject *v, void *Py_UNUSED(closure)) - { - return float_float(v); - } - - static PyObject * --float_getimag(PyObject *v, void *closure) -+float_getimag(PyObject *Py_UNUSED(v), void *Py_UNUSED(closure)) - { - return PyFloat_FromDouble(0.0); - } -@@ -1828,11 +1834,11 @@ - - static PyGetSetDef float_getset[] = { - {"real", -- float_getreal, (setter)NULL, -+ float_getreal, NULL, - "the real part of a complex number", - NULL}, - {"imag", -- float_getimag, (setter)NULL, -+ float_getimag, NULL, - "the imaginary part of a complex number", - NULL}, - {NULL} /* Sentinel */ -@@ -1846,10 +1852,10 @@ - float_rem, /* nb_remainder */ - float_divmod, /* nb_divmod */ - float_pow, /* nb_power */ -- (unaryfunc)float_neg, /* nb_negative */ -+ float_neg, /* nb_negative */ - float_float, /* nb_positive */ -- (unaryfunc)float_abs, /* nb_absolute */ -- (inquiry)float_bool, /* nb_bool */ -+ float_abs, /* nb_absolute */ -+ float_bool, /* nb_bool */ - 0, /* nb_invert */ - 0, /* nb_lshift */ - 0, /* nb_rshift */ -@@ -1880,16 +1886,16 @@ - "float", - sizeof(PyFloatObject), - 0, -- (destructor)float_dealloc, /* tp_dealloc */ -+ float_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ -- (reprfunc)float_repr, /* tp_repr */ -+ float_repr, /* tp_repr */ - &float_as_number, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ -- (hashfunc)float_hash, /* tp_hash */ -+ float_hash, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ -@@ -1915,7 +1921,7 @@ - 0, /* tp_init */ - 0, /* tp_alloc */ - float_new, /* tp_new */ -- .tp_vectorcall = (vectorcallfunc)float_vectorcall, -+ .tp_vectorcall = float_vectorcall, - .tp_version_tag = _Py_TYPE_VERSION_FLOAT, - }; - -diff --git a/Objects/frameobject.c b/Objects/frameobject.c -index 03ed2b9480f..8ebcc1a4b5e 100644 ---- a/Objects/frameobject.c -+++ b/Objects/frameobject.c -@@ -16,6 +16,14 @@ - #include "pycore_frame.h" - #include "opcode.h" // EXTENDED_ARG - -+#define PyFrameObject_CAST(op) \ -+ (assert(PyObject_TypeCheck((op), &PyFrame_Type)), (PyFrameObject *)(op)) -+ -+#define PyFrameLocalsProxyObject_CAST(op) \ -+ ( \ -+ assert(PyObject_TypeCheck((op), &PyFrameLocalsProxy_Type)), \ -+ (PyFrameLocalsProxyObject *)(op) \ -+ ) - - #define OFF(x) offsetof(PyFrameObject, x) - -@@ -126,8 +134,8 @@ - static PyObject * - framelocalsproxy_getitem(PyObject *self, PyObject *key) - { -- PyFrameObject* frame = ((PyFrameLocalsProxyObject*)self)->frame; -- PyCodeObject* co = _PyFrame_GetCode(frame->f_frame); -+ PyFrameObject *frame = PyFrameLocalsProxyObject_CAST(self)->frame; -+ PyCodeObject *co = _PyFrame_GetCode(frame->f_frame); - - int i = framelocalsproxy_getkeyindex(frame, key, true); - if (i == -2) { -@@ -157,7 +165,7 @@ - framelocalsproxy_setitem(PyObject *self, PyObject *key, PyObject *value) - { - /* Merge locals into fast locals */ -- PyFrameObject *frame = ((PyFrameLocalsProxyObject*)self)->frame; -+ PyFrameObject *frame = PyFrameLocalsProxyObject_CAST(self)->frame; - _PyStackRef *fast = _PyFrame_GetLocalsArray(frame->f_frame); - PyCodeObject *co = _PyFrame_GetCode(frame->f_frame); - -@@ -179,9 +187,9 @@ - if (kind == CO_FAST_FREE) { - // The cell was set when the frame was created from - // the function's closure. -- assert(oldvalue.bits != 0 && PyCell_Check(PyStackRef_AsPyObjectBorrow(oldvalue))); -+ assert(!PyStackRef_IsNull(oldvalue) && PyCell_Check(PyStackRef_AsPyObjectBorrow(oldvalue))); - cell = PyStackRef_AsPyObjectBorrow(oldvalue); -- } else if (kind & CO_FAST_CELL && oldvalue.bits != 0) { -+ } else if (kind & CO_FAST_CELL && !PyStackRef_IsNull(oldvalue)) { - PyObject *as_obj = PyStackRef_AsPyObjectBorrow(oldvalue); - if (PyCell_Check(as_obj)) { - cell = as_obj; -@@ -264,13 +272,17 @@ - - Py_DECREF(iter); - -+ if (PyErr_Occurred()) { -+ return -1; -+ } -+ - return 0; - } - - static PyObject * --framelocalsproxy_keys(PyObject *self, void *Py_UNUSED(ignored)) -+framelocalsproxy_keys(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- PyFrameObject *frame = ((PyFrameLocalsProxyObject*)self)->frame; -+ PyFrameObject *frame = PyFrameLocalsProxyObject_CAST(self)->frame; - PyCodeObject *co = _PyFrame_GetCode(frame->f_frame); - PyObject *names = PyList_New(0); - if (names == NULL) { -@@ -310,8 +322,9 @@ - static void - framelocalsproxy_dealloc(PyObject *self) - { -+ PyFrameLocalsProxyObject *proxy = PyFrameLocalsProxyObject_CAST(self); - PyObject_GC_UnTrack(self); -- Py_CLEAR(((PyFrameLocalsProxyObject*)self)->frame); -+ Py_CLEAR(proxy->frame); - Py_TYPE(self)->tp_free(self); - } - -@@ -351,14 +364,16 @@ - static int - framelocalsproxy_tp_clear(PyObject *self) - { -- Py_CLEAR(((PyFrameLocalsProxyObject*)self)->frame); -+ PyFrameLocalsProxyObject *proxy = PyFrameLocalsProxyObject_CAST(self); -+ Py_CLEAR(proxy->frame); - return 0; - } - - static int - framelocalsproxy_visit(PyObject *self, visitproc visit, void *arg) - { -- Py_VISIT(((PyFrameLocalsProxyObject*)self)->frame); -+ PyFrameLocalsProxyObject *proxy = PyFrameLocalsProxyObject_CAST(self); -+ Py_VISIT(proxy->frame); - return 0; - } - -@@ -377,27 +392,29 @@ - } - - static PyObject * --framelocalsproxy_richcompare(PyObject *self, PyObject *other, int op) -+framelocalsproxy_richcompare(PyObject *lhs, PyObject *rhs, int op) - { -- if (PyFrameLocalsProxy_Check(other)) { -- bool result = ((PyFrameLocalsProxyObject*)self)->frame == ((PyFrameLocalsProxyObject*)other)->frame; -+ PyFrameLocalsProxyObject *self = PyFrameLocalsProxyObject_CAST(lhs); -+ if (PyFrameLocalsProxy_Check(rhs)) { -+ PyFrameLocalsProxyObject *other = (PyFrameLocalsProxyObject *)rhs; -+ bool result = self->frame == other->frame; - if (op == Py_EQ) { - return PyBool_FromLong(result); - } else if (op == Py_NE) { - return PyBool_FromLong(!result); - } -- } else if (PyDict_Check(other)) { -+ } else if (PyDict_Check(rhs)) { - PyObject *dct = PyDict_New(); - if (dct == NULL) { - return NULL; - } - -- if (PyDict_Update(dct, self) < 0) { -+ if (PyDict_Update(dct, lhs) < 0) { - Py_DECREF(dct); - return NULL; - } - -- PyObject *result = PyObject_RichCompare(dct, other, op); -+ PyObject *result = PyObject_RichCompare(dct, rhs, op); - Py_DECREF(dct); - return result; - } -@@ -472,10 +489,10 @@ - return Py_NewRef(self); - } - --static PyObject* --framelocalsproxy_values(PyObject *self, void *Py_UNUSED(ignored)) -+static PyObject * -+framelocalsproxy_values(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- PyFrameObject *frame = ((PyFrameLocalsProxyObject*)self)->frame; -+ PyFrameObject *frame = PyFrameLocalsProxyObject_CAST(self)->frame; - PyCodeObject *co = _PyFrame_GetCode(frame->f_frame); - PyObject *values = PyList_New(0); - if (values == NULL) { -@@ -509,9 +526,9 @@ - } - - static PyObject * --framelocalsproxy_items(PyObject *self, void *Py_UNUSED(ignored)) -+framelocalsproxy_items(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- PyFrameObject *frame = ((PyFrameLocalsProxyObject*)self)->frame; -+ PyFrameObject *frame = PyFrameLocalsProxyObject_CAST(self)->frame; - PyCodeObject *co = _PyFrame_GetCode(frame->f_frame); - PyObject *items = PyList_New(0); - if (items == NULL) { -@@ -567,7 +584,7 @@ - static Py_ssize_t - framelocalsproxy_length(PyObject *self) - { -- PyFrameObject *frame = ((PyFrameLocalsProxyObject*)self)->frame; -+ PyFrameObject *frame = PyFrameLocalsProxyObject_CAST(self)->frame; - PyCodeObject *co = _PyFrame_GetCode(frame->f_frame); - Py_ssize_t size = 0; - -@@ -587,7 +604,7 @@ - static int - framelocalsproxy_contains(PyObject *self, PyObject *key) - { -- PyFrameObject *frame = ((PyFrameLocalsProxyObject*)self)->frame; -+ PyFrameObject *frame = PyFrameLocalsProxyObject_CAST(self)->frame; - - int i = framelocalsproxy_getkeyindex(frame, key, true); - if (i == -2) { -@@ -597,7 +614,7 @@ - return 1; - } - -- PyObject *extra = ((PyFrameObject*)frame)->f_extra_locals; -+ PyObject *extra = frame->f_extra_locals; - if (extra != NULL) { - return PyDict_Contains(extra, key); - } -@@ -698,7 +715,7 @@ - default_value = args[1]; - } - -- PyFrameObject *frame = ((PyFrameLocalsProxyObject*)self)->frame; -+ PyFrameObject *frame = PyFrameLocalsProxyObject_CAST(self)->frame; - - int i = framelocalsproxy_getkeyindex(frame, key, false); - if (i == -2) { -@@ -755,7 +772,7 @@ - } - - static PyObject* --framelocalsproxy_reversed(PyObject *self, void *Py_UNUSED(ignored)) -+framelocalsproxy_reversed(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *result = framelocalsproxy_keys(self, NULL); - -@@ -780,42 +797,36 @@ - }; - - static PyMappingMethods framelocalsproxy_as_mapping = { -- framelocalsproxy_length, // mp_length -- framelocalsproxy_getitem, // mp_subscript -- framelocalsproxy_setitem, // mp_ass_subscript -+ .mp_length = framelocalsproxy_length, -+ .mp_subscript = framelocalsproxy_getitem, -+ .mp_ass_subscript = framelocalsproxy_setitem, - }; - - static PyMethodDef framelocalsproxy_methods[] = { -- {"__contains__", framelocalsproxy___contains__, METH_O | METH_COEXIST, -- NULL}, -- {"__getitem__", framelocalsproxy_getitem, METH_O | METH_COEXIST, -- NULL}, -- {"update", framelocalsproxy_update, METH_O, -- NULL}, -- {"__reversed__", _PyCFunction_CAST(framelocalsproxy_reversed), METH_NOARGS, -- NULL}, -- {"copy", _PyCFunction_CAST(framelocalsproxy_copy), METH_NOARGS, -- NULL}, -- {"keys", _PyCFunction_CAST(framelocalsproxy_keys), METH_NOARGS, -- NULL}, -- {"values", _PyCFunction_CAST(framelocalsproxy_values), METH_NOARGS, -- NULL}, -- {"items", _PyCFunction_CAST(framelocalsproxy_items), METH_NOARGS, -- NULL}, -- {"get", _PyCFunction_CAST(framelocalsproxy_get), METH_FASTCALL, -- NULL}, -- {"pop", _PyCFunction_CAST(framelocalsproxy_pop), METH_FASTCALL, -- NULL}, -- {"setdefault", _PyCFunction_CAST(framelocalsproxy_setdefault), METH_FASTCALL, -- NULL}, -- {NULL, NULL} /* sentinel */ -+ {"__contains__", framelocalsproxy___contains__, METH_O | METH_COEXIST, NULL}, -+ {"__getitem__", framelocalsproxy_getitem, METH_O | METH_COEXIST, NULL}, -+ {"update", framelocalsproxy_update, METH_O, NULL}, -+ {"__reversed__", framelocalsproxy_reversed, METH_NOARGS, NULL}, -+ {"copy", framelocalsproxy_copy, METH_NOARGS, NULL}, -+ {"keys", framelocalsproxy_keys, METH_NOARGS, NULL}, -+ {"values", framelocalsproxy_values, METH_NOARGS, NULL}, -+ {"items", _PyCFunction_CAST(framelocalsproxy_items), METH_NOARGS, NULL}, -+ {"get", _PyCFunction_CAST(framelocalsproxy_get), METH_FASTCALL, NULL}, -+ {"pop", _PyCFunction_CAST(framelocalsproxy_pop), METH_FASTCALL, NULL}, -+ { -+ "setdefault", -+ _PyCFunction_CAST(framelocalsproxy_setdefault), -+ METH_FASTCALL, -+ NULL -+ }, -+ {NULL, NULL} /* sentinel */ - }; - - PyTypeObject PyFrameLocalsProxy_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - .tp_name = "FrameLocalsProxy", - .tp_basicsize = sizeof(PyFrameLocalsProxyObject), -- .tp_dealloc = (destructor)framelocalsproxy_dealloc, -+ .tp_dealloc = framelocalsproxy_dealloc, - .tp_repr = &framelocalsproxy_repr, - .tp_as_number = &framelocalsproxy_as_number, - .tp_as_sequence = &framelocalsproxy_as_sequence, -@@ -841,7 +852,7 @@ - return NULL; - } - -- PyObject* proxy = (PyObject*)framelocalsproxy_new(&PyFrameLocalsProxy_Type, args, NULL); -+ PyObject* proxy = framelocalsproxy_new(&PyFrameLocalsProxy_Type, args, NULL); - Py_DECREF(args); - return proxy; - } -@@ -852,8 +863,9 @@ - }; - - static PyObject * --frame_getlocals(PyFrameObject *f, void *closure) -+frame_getlocals(PyObject *op, void *Py_UNUSED(closure)) - { -+ PyFrameObject *f = PyFrameObject_CAST(op); - if (f == NULL) { - PyErr_BadInternalCall(); - return NULL; -@@ -899,8 +911,9 @@ - } - - static PyObject * --frame_getlineno(PyFrameObject *f, void *closure) -+frame_getlineno(PyObject *op, void *Py_UNUSED(closure)) - { -+ PyFrameObject *f = PyFrameObject_CAST(op); - int lineno = PyFrame_GetLineNumber(f); - if (lineno < 0) { - Py_RETURN_NONE; -@@ -911,8 +924,9 @@ - } - - static PyObject * --frame_getlasti(PyFrameObject *f, void *closure) -+frame_getlasti(PyObject *op, void *Py_UNUSED(closure)) - { -+ PyFrameObject *f = PyFrameObject_CAST(op); - int lasti = _PyInterpreterFrame_LASTI(f->f_frame); - if (lasti < 0) { - return PyLong_FromLong(-1); -@@ -921,8 +935,9 @@ - } - - static PyObject * --frame_getglobals(PyFrameObject *f, void *closure) -+frame_getglobals(PyObject *op, void *Py_UNUSED(closure)) - { -+ PyFrameObject *f = PyFrameObject_CAST(op); - PyObject *globals = f->f_frame->f_globals; - if (globals == NULL) { - globals = Py_None; -@@ -931,8 +946,9 @@ - } - - static PyObject * --frame_getbuiltins(PyFrameObject *f, void *closure) -+frame_getbuiltins(PyObject *op, void *Py_UNUSED(closure)) - { -+ PyFrameObject *f = PyFrameObject_CAST(op); - PyObject *builtins = f->f_frame->f_builtins; - if (builtins == NULL) { - builtins = Py_None; -@@ -941,8 +957,9 @@ - } - - static PyObject * --frame_getcode(PyFrameObject *f, void *closure) -+frame_getcode(PyObject *op, void *Py_UNUSED(closure)) - { -+ PyFrameObject *f = PyFrameObject_CAST(op); - if (PySys_Audit("object.__getattr__", "Os", f, "f_code") < 0) { - return NULL; - } -@@ -950,8 +967,9 @@ - } - - static PyObject * --frame_getback(PyFrameObject *f, void *closure) -+frame_getback(PyObject *op, void *Py_UNUSED(closure)) - { -+ PyFrameObject *f = PyFrameObject_CAST(op); - PyObject *res = (PyObject *)PyFrame_GetBack(f); - if (res == NULL) { - Py_RETURN_NONE; -@@ -960,15 +978,17 @@ - } - - static PyObject * --frame_gettrace_opcodes(PyFrameObject *f, void *closure) -+frame_gettrace_opcodes(PyObject *op, void *Py_UNUSED(closure)) - { -+ PyFrameObject *f = PyFrameObject_CAST(op); - PyObject *result = f->f_trace_opcodes ? Py_True : Py_False; - return Py_NewRef(result); - } - - static int --frame_settrace_opcodes(PyFrameObject *f, PyObject* value, void *Py_UNUSED(ignored)) -+frame_settrace_opcodes(PyObject *op, PyObject* value, void *Py_UNUSED(closure)) - { -+ PyFrameObject *f = PyFrameObject_CAST(op); - if (!PyBool_Check(value)) { - PyErr_SetString(PyExc_TypeError, - "attribute value type must be bool"); -@@ -1460,8 +1480,9 @@ - * that time. - */ - static int --frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignored)) -+frame_setlineno(PyObject *op, PyObject* p_new_lineno, void *Py_UNUSED(closure)) - { -+ PyFrameObject *f = PyFrameObject_CAST(op); - PyCodeObject *code = _PyFrame_GetCode(f->f_frame); - if (p_new_lineno == NULL) { - PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); -@@ -1654,8 +1675,9 @@ - } - - static PyObject * --frame_gettrace(PyFrameObject *f, void *closure) -+frame_gettrace(PyObject *op, void *Py_UNUSED(closure)) - { -+ PyFrameObject *f = PyFrameObject_CAST(op); - PyObject* trace = f->f_trace; - if (trace == NULL) - trace = Py_None; -@@ -1663,8 +1685,9 @@ - } - - static int --frame_settrace(PyFrameObject *f, PyObject* v, void *closure) -+frame_settrace(PyObject *op, PyObject* v, void *Py_UNUSED(closure)) - { -+ PyFrameObject *f = PyFrameObject_CAST(op); - if (v == Py_None) { - v = NULL; - } -@@ -1677,27 +1700,37 @@ - return 0; - } - -+static PyObject * -+frame_getgenerator(PyObject *op, void *Py_UNUSED(closure)) { -+ PyFrameObject *f = PyFrameObject_CAST(op); -+ if (f->f_frame->owner == FRAME_OWNED_BY_GENERATOR) { -+ PyObject *gen = (PyObject *)_PyGen_GetGeneratorFromFrame(f->f_frame); -+ return Py_NewRef(gen); -+ } -+ Py_RETURN_NONE; -+} -+ - - static PyGetSetDef frame_getsetlist[] = { -- {"f_back", (getter)frame_getback, NULL, NULL}, -- {"f_locals", (getter)frame_getlocals, NULL, NULL}, -- {"f_lineno", (getter)frame_getlineno, -- (setter)frame_setlineno, NULL}, -- {"f_trace", (getter)frame_gettrace, (setter)frame_settrace, NULL}, -- {"f_lasti", (getter)frame_getlasti, NULL, NULL}, -- {"f_globals", (getter)frame_getglobals, NULL, NULL}, -- {"f_builtins", (getter)frame_getbuiltins, NULL, NULL}, -- {"f_code", (getter)frame_getcode, NULL, NULL}, -- {"f_trace_opcodes", (getter)frame_gettrace_opcodes, (setter)frame_settrace_opcodes, NULL}, -+ {"f_back", frame_getback, NULL, NULL}, -+ {"f_locals", frame_getlocals, NULL, NULL}, -+ {"f_lineno", frame_getlineno, frame_setlineno, NULL}, -+ {"f_trace", frame_gettrace, frame_settrace, NULL}, -+ {"f_lasti", frame_getlasti, NULL, NULL}, -+ {"f_globals", frame_getglobals, NULL, NULL}, -+ {"f_builtins", frame_getbuiltins, NULL, NULL}, -+ {"f_code", frame_getcode, NULL, NULL}, -+ {"f_trace_opcodes", frame_gettrace_opcodes, frame_settrace_opcodes, NULL}, -+ {"f_generator", frame_getgenerator, NULL, NULL}, - {0} - }; - - static void --frame_dealloc(PyFrameObject *f) -+frame_dealloc(PyObject *op) - { - /* It is the responsibility of the owning generator/coroutine - * to have cleared the generator pointer */ -- -+ PyFrameObject *f = PyFrameObject_CAST(op); - if (_PyObject_GC_IS_TRACKED(f)) { - _PyObject_GC_UNTRACK(f); - } -@@ -1730,8 +1763,9 @@ - } - - static int --frame_traverse(PyFrameObject *f, visitproc visit, void *arg) -+frame_traverse(PyObject *op, visitproc visit, void *arg) - { -+ PyFrameObject *f = PyFrameObject_CAST(op); - Py_VISIT(f->f_back); - Py_VISIT(f->f_trace); - Py_VISIT(f->f_extra_locals); -@@ -1744,8 +1778,9 @@ - } - - static int --frame_tp_clear(PyFrameObject *f) -+frame_tp_clear(PyObject *op) - { -+ PyFrameObject *f = PyFrameObject_CAST(op); - Py_CLEAR(f->f_trace); - Py_CLEAR(f->f_extra_locals); - Py_CLEAR(f->f_locals_cache); -@@ -1764,8 +1799,9 @@ - } - - static PyObject * --frame_clear(PyFrameObject *f, PyObject *Py_UNUSED(ignored)) -+frame_clear(PyObject *op, PyObject *Py_UNUSED(ignored)) - { -+ PyFrameObject *f = PyFrameObject_CAST(op); - if (f->f_frame->owner == FRAME_OWNED_BY_GENERATOR) { - PyGenObject *gen = _PyGen_GetGeneratorFromFrame(f->f_frame); - if (gen->gi_frame_state == FRAME_EXECUTING) { -@@ -1781,7 +1817,7 @@ - } - else { - assert(f->f_frame->owner == FRAME_OWNED_BY_FRAME_OBJECT); -- (void)frame_tp_clear(f); -+ (void)frame_tp_clear(op); - } - Py_RETURN_NONE; - running: -@@ -1798,8 +1834,9 @@ - "F.clear(): clear all references held by the frame"); - - static PyObject * --frame_sizeof(PyFrameObject *f, PyObject *Py_UNUSED(ignored)) -+frame_sizeof(PyObject *op, PyObject *Py_UNUSED(ignored)) - { -+ PyFrameObject *f = PyFrameObject_CAST(op); - Py_ssize_t res; - res = offsetof(PyFrameObject, _f_frame_data) + offsetof(_PyInterpreterFrame, localsplus); - PyCodeObject *code = _PyFrame_GetCode(f->f_frame); -@@ -1811,8 +1848,9 @@ - "F.__sizeof__() -> size of F in memory, in bytes"); - - static PyObject * --frame_repr(PyFrameObject *f) -+frame_repr(PyObject *op) - { -+ PyFrameObject *f = PyFrameObject_CAST(op); - int lineno = PyFrame_GetLineNumber(f); - PyCodeObject *code = _PyFrame_GetCode(f->f_frame); - return PyUnicode_FromFormat( -@@ -1821,11 +1859,9 @@ - } - - static PyMethodDef frame_methods[] = { -- {"clear", (PyCFunction)frame_clear, METH_NOARGS, -- clear__doc__}, -- {"__sizeof__", (PyCFunction)frame_sizeof, METH_NOARGS, -- sizeof__doc__}, -- {NULL, NULL} /* sentinel */ -+ {"clear", frame_clear, METH_NOARGS, clear__doc__}, -+ {"__sizeof__", frame_sizeof, METH_NOARGS, sizeof__doc__}, -+ {NULL, NULL} /* sentinel */ - }; - - PyTypeObject PyFrame_Type = { -@@ -1834,12 +1870,12 @@ - offsetof(PyFrameObject, _f_frame_data) + - offsetof(_PyInterpreterFrame, localsplus), - sizeof(PyObject *), -- (destructor)frame_dealloc, /* tp_dealloc */ -+ frame_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ -- (reprfunc)frame_repr, /* tp_repr */ -+ frame_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ -@@ -1851,8 +1887,8 @@ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ - 0, /* tp_doc */ -- (traverseproc)frame_traverse, /* tp_traverse */ -- (inquiry)frame_tp_clear, /* tp_clear */ -+ frame_traverse, /* tp_traverse */ -+ frame_tp_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ -@@ -2138,7 +2174,7 @@ - assert(frame != NULL); - _PyInterpreterFrame *f = frame->f_frame; - assert(!_PyFrame_IsIncomplete(f)); -- return f->previous && f->previous->owner == FRAME_OWNED_BY_CSTACK; -+ return f->previous && f->previous->owner == FRAME_OWNED_BY_INTERPRETER; - } - - PyCodeObject * -@@ -2172,21 +2208,21 @@ - PyFrame_GetLocals(PyFrameObject *frame) - { - assert(!_PyFrame_IsIncomplete(frame->f_frame)); -- return frame_getlocals(frame, NULL); -+ return frame_getlocals((PyObject *)frame, NULL); - } - - PyObject* - PyFrame_GetGlobals(PyFrameObject *frame) - { - assert(!_PyFrame_IsIncomplete(frame->f_frame)); -- return frame_getglobals(frame, NULL); -+ return frame_getglobals((PyObject *)frame, NULL); - } - - PyObject* - PyFrame_GetBuiltins(PyFrameObject *frame) - { - assert(!_PyFrame_IsIncomplete(frame->f_frame)); -- return frame_getbuiltins(frame, NULL); -+ return frame_getbuiltins((PyObject *)frame, NULL); - } - - int -diff --git a/Objects/funcobject.c b/Objects/funcobject.c -index cca7f014980..169db2048c6 100644 ---- a/Objects/funcobject.c -+++ b/Objects/funcobject.c -@@ -2,11 +2,11 @@ - /* Function object implementation */ - - #include "Python.h" --#include "pycore_dict.h" // _Py_INCREF_DICT() --#include "pycore_long.h" // _PyLong_GetOne() --#include "pycore_modsupport.h" // _PyArg_NoKeywords() --#include "pycore_object.h" // _PyObject_GC_UNTRACK() --#include "pycore_pyerrors.h" // _PyErr_Occurred() -+#include "pycore_dict.h" // _Py_INCREF_DICT() -+#include "pycore_long.h" // _PyLong_GetOne() -+#include "pycore_modsupport.h" // _PyArg_NoKeywords() -+#include "pycore_object.h" // _PyObject_GC_UNTRACK() -+#include "pycore_pyerrors.h" // _PyErr_Occurred() - - - static const char * -@@ -210,10 +210,14 @@ - op->func_typeparams = NULL; - op->vectorcall = _PyFunction_Vectorcall; - op->func_version = FUNC_VERSION_UNSET; -- if ((code_obj->co_flags & CO_NESTED) == 0) { -+ if (((code_obj->co_flags & CO_NESTED) == 0) || -+ (code_obj->co_flags & CO_METHOD)) { - // Use deferred reference counting for top-level functions, but not - // nested functions because they are more likely to capture variables, - // which makes prompt deallocation more important. -+ // -+ // Nested methods (functions defined in class scope) are also deferred, -+ // since they will likely be cleaned up by GC anyway. - _PyObject_SetDeferredRefcount((PyObject *)op); - } - _PyObject_GC_TRACK(op); -@@ -631,6 +635,13 @@ - {NULL} /* Sentinel */ - }; - -+/*[clinic input] -+class function "PyFunctionObject *" "&PyFunction_Type" -+[clinic start generated code]*/ -+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=70af9c90aa2e71b0]*/ -+ -+#include "clinic/funcobject.c.h" -+ - static PyObject * - func_get_code(PyObject *self, void *Py_UNUSED(ignored)) - { -@@ -820,32 +831,46 @@ - return 0; - } - -+/*[clinic input] -+@critical_section -+@getter -+function.__annotate__ -+ -+Get the code object for a function. -+[clinic start generated code]*/ -+ - static PyObject * --func_get_annotate(PyObject *self, void *Py_UNUSED(ignored)) -+function___annotate___get_impl(PyFunctionObject *self) -+/*[clinic end generated code: output=5ec7219ff2bda9e6 input=7f3db11e3c3329f3]*/ - { -- PyFunctionObject *op = _PyFunction_CAST(self); -- if (op->func_annotate == NULL) { -+ if (self->func_annotate == NULL) { - Py_RETURN_NONE; - } -- return Py_NewRef(op->func_annotate); -+ return Py_NewRef(self->func_annotate); - } - -+/*[clinic input] -+@critical_section -+@setter -+function.__annotate__ -+[clinic start generated code]*/ -+ - static int --func_set_annotate(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) -+function___annotate___set_impl(PyFunctionObject *self, PyObject *value) -+/*[clinic end generated code: output=05b7dfc07ada66cd input=eb6225e358d97448]*/ - { -- PyFunctionObject *op = _PyFunction_CAST(self); - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, - "__annotate__ cannot be deleted"); - return -1; - } - if (Py_IsNone(value)) { -- Py_XSETREF(op->func_annotate, value); -+ Py_XSETREF(self->func_annotate, value); - return 0; - } - else if (PyCallable_Check(value)) { -- Py_XSETREF(op->func_annotate, Py_XNewRef(value)); -- Py_CLEAR(op->func_annotations); -+ Py_XSETREF(self->func_annotate, Py_XNewRef(value)); -+ Py_CLEAR(self->func_annotations); - return 0; - } - else { -@@ -855,24 +880,39 @@ - } - } - -+/*[clinic input] -+@critical_section -+@getter -+function.__annotations__ -+ -+Dict of annotations in a function object. -+[clinic start generated code]*/ -+ - static PyObject * --func_get_annotations(PyObject *self, void *Py_UNUSED(ignored)) --{ -- PyFunctionObject *op = _PyFunction_CAST(self); -- if (op->func_annotations == NULL && -- (op->func_annotate == NULL || !PyCallable_Check(op->func_annotate))) { -- op->func_annotations = PyDict_New(); -- if (op->func_annotations == NULL) -+function___annotations___get_impl(PyFunctionObject *self) -+/*[clinic end generated code: output=a4cf4c884c934cbb input=92643d7186c1ad0c]*/ -+{ -+ PyObject *d = NULL; -+ if (self->func_annotations == NULL && -+ (self->func_annotate == NULL || !PyCallable_Check(self->func_annotate))) { -+ self->func_annotations = PyDict_New(); -+ if (self->func_annotations == NULL) - return NULL; - } -- PyObject *d = func_get_annotation_dict(op); -+ d = func_get_annotation_dict(self); - return Py_XNewRef(d); - } - -+/*[clinic input] -+@critical_section -+@setter -+function.__annotations__ -+[clinic start generated code]*/ -+ - static int --func_set_annotations(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) -+function___annotations___set_impl(PyFunctionObject *self, PyObject *value) -+/*[clinic end generated code: output=a61795d4a95eede4 input=5302641f686f0463]*/ - { -- PyFunctionObject *op = _PyFunction_CAST(self); - if (value == Py_None) - value = NULL; - /* Legal to del f.func_annotations. -@@ -883,35 +923,49 @@ - "__annotations__ must be set to a dict object"); - return -1; - } -- Py_XSETREF(op->func_annotations, Py_XNewRef(value)); -- Py_CLEAR(op->func_annotate); -+ Py_XSETREF(self->func_annotations, Py_XNewRef(value)); -+ Py_CLEAR(self->func_annotate); - return 0; - } - -+/*[clinic input] -+@critical_section -+@getter -+function.__type_params__ -+ -+Get the declared type parameters for a function. -+[clinic start generated code]*/ -+ - static PyObject * --func_get_type_params(PyObject *self, void *Py_UNUSED(ignored)) -+function___type_params___get_impl(PyFunctionObject *self) -+/*[clinic end generated code: output=eb844d7ffca517a8 input=0864721484293724]*/ - { -- PyFunctionObject *op = _PyFunction_CAST(self); -- if (op->func_typeparams == NULL) { -+ if (self->func_typeparams == NULL) { - return PyTuple_New(0); - } - -- assert(PyTuple_Check(op->func_typeparams)); -- return Py_NewRef(op->func_typeparams); -+ assert(PyTuple_Check(self->func_typeparams)); -+ return Py_NewRef(self->func_typeparams); - } - -+/*[clinic input] -+@critical_section -+@setter -+function.__type_params__ -+[clinic start generated code]*/ -+ - static int --func_set_type_params(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) -+function___type_params___set_impl(PyFunctionObject *self, PyObject *value) -+/*[clinic end generated code: output=038b4cda220e56fb input=3862fbd4db2b70e8]*/ - { - /* Not legal to del f.__type_params__ or to set it to anything - * other than a tuple object. */ -- PyFunctionObject *op = _PyFunction_CAST(self); - if (value == NULL || !PyTuple_Check(value)) { - PyErr_SetString(PyExc_TypeError, - "__type_params__ must be set to a tuple"); - return -1; - } -- Py_XSETREF(op->func_typeparams, Py_NewRef(value)); -+ Py_XSETREF(self->func_typeparams, Py_NewRef(value)); - return 0; - } - -@@ -930,22 +984,15 @@ - {"__code__", func_get_code, func_set_code}, - {"__defaults__", func_get_defaults, func_set_defaults}, - {"__kwdefaults__", func_get_kwdefaults, func_set_kwdefaults}, -- {"__annotations__", func_get_annotations, func_set_annotations}, -- {"__annotate__", func_get_annotate, func_set_annotate}, -+ FUNCTION___ANNOTATIONS___GETSETDEF -+ FUNCTION___ANNOTATE___GETSETDEF - {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict}, - {"__name__", func_get_name, func_set_name}, - {"__qualname__", func_get_qualname, func_set_qualname}, -- {"__type_params__", func_get_type_params, func_set_type_params}, -+ FUNCTION___TYPE_PARAMS___GETSETDEF - {NULL} /* Sentinel */ - }; - --/*[clinic input] --class function "PyFunctionObject *" "&PyFunction_Type" --[clinic start generated code]*/ --/*[clinic end generated code: output=da39a3ee5e6b4b0d input=70af9c90aa2e71b0]*/ -- --#include "clinic/funcobject.c.h" -- - /* function.__new__() maintains the following invariants for closures. - The closure must correspond to the free variables of the code object. - -diff --git a/Objects/genobject.c b/Objects/genobject.c -index e87f199c250..79aed8571c3 100644 ---- a/Objects/genobject.c -+++ b/Objects/genobject.c -@@ -97,8 +97,10 @@ - - PyObject *res = PyObject_CallOneArg(finalizer, self); - if (res == NULL) { -- PyErr_WriteUnraisable(self); -- } else { -+ PyErr_FormatUnraisable("Exception ignored while " -+ "finalizing generator %R", self); -+ } -+ else { - Py_DECREF(res); - } - /* Restore the saved exception. */ -@@ -122,7 +124,8 @@ - PyObject *res = gen_close((PyObject*)gen, NULL); - if (res == NULL) { - if (PyErr_Occurred()) { -- PyErr_WriteUnraisable(self); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "closing generator %R", self); - } - } - else { -@@ -134,6 +137,19 @@ - PyErr_SetRaisedException(exc); - } - -+static void -+gen_clear_frame(PyGenObject *gen) -+{ -+ if (gen->gi_frame_state == FRAME_CLEARED) -+ return; -+ -+ gen->gi_frame_state = FRAME_CLEARED; -+ _PyInterpreterFrame *frame = &gen->gi_iframe; -+ frame->previous = NULL; -+ _PyFrame_ClearExceptCode(frame); -+ _PyErr_ClearExcState(&gen->gi_exc_state); -+} -+ - static void - gen_dealloc(PyObject *self) - { -@@ -159,13 +175,7 @@ - if (PyCoro_CheckExact(gen)) { - Py_CLEAR(((PyCoroObject *)gen)->cr_origin_or_finalizer); - } -- if (gen->gi_frame_state != FRAME_CLEARED) { -- _PyInterpreterFrame *frame = &gen->gi_iframe; -- gen->gi_frame_state = FRAME_CLEARED; -- frame->previous = NULL; -- _PyFrame_ClearExceptCode(frame); -- _PyErr_ClearExcState(&gen->gi_exc_state); -- } -+ gen_clear_frame(gen); - assert(gen->gi_exc_state.exc_value == NULL); - PyStackRef_CLEAR(gen->gi_iframe.f_executable); - Py_CLEAR(gen->gi_name); -@@ -331,7 +341,8 @@ - else { - PyObject *meth; - if (PyObject_GetOptionalAttr(yf, &_Py_ID(close), &meth) < 0) { -- PyErr_WriteUnraisable(yf); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "closing generator %R", yf); - } - if (meth) { - retval = _PyObject_CallNoArgs(meth); -@@ -400,7 +411,7 @@ - // RESUME after YIELD_VALUE and exception depth is 1 - assert((oparg & RESUME_OPARG_LOCATION_MASK) != RESUME_AT_FUNC_START); - gen->gi_frame_state = FRAME_COMPLETED; -- _PyFrame_ClearLocals(&gen->gi_iframe); -+ gen_clear_frame(gen); - Py_RETURN_NONE; - } - } -@@ -633,30 +644,19 @@ - int - _PyGen_SetStopIterationValue(PyObject *value) - { -- PyObject *e; -- -- if (value == NULL || -- (!PyTuple_Check(value) && !PyExceptionInstance_Check(value))) -- { -- /* Delay exception instantiation if we can */ -- PyErr_SetObject(PyExc_StopIteration, value); -- return 0; -- } -- /* Construct an exception instance manually with -- * PyObject_CallOneArg and pass it to PyErr_SetObject. -- * -- * We do this to handle a situation when "value" is a tuple, in which -- * case PyErr_SetObject would set the value of StopIteration to -- * the first element of the tuple. -- * -- * (See PyErr_SetObject/_PyErr_CreateException code for details.) -- */ -- e = PyObject_CallOneArg(PyExc_StopIteration, value); -- if (e == NULL) { -+ assert(!PyErr_Occurred()); -+ // Construct an exception instance manually with PyObject_CallOneArg() -+ // but use PyErr_SetRaisedException() instead of PyErr_SetObject() as -+ // PyErr_SetObject(exc_type, value) has a fast path when 'value' -+ // is a tuple, where the value of the StopIteration exception would be -+ // set to 'value[0]' instead of 'value'. -+ PyObject *exc = value == NULL -+ ? PyObject_CallNoArgs(PyExc_StopIteration) -+ : PyObject_CallOneArg(PyExc_StopIteration, value); -+ if (exc == NULL) { - return -1; - } -- PyErr_SetObject(PyExc_StopIteration, e); -- Py_DECREF(e); -+ PyErr_SetRaisedException(exc /* stolen */); - return 0; - } - -@@ -1157,7 +1157,6 @@ - return _gen_getcode(_PyGen_CAST(coro), "cr_code"); - } - -- - static PyGetSetDef coro_getsetlist[] = { - {"__name__", gen_get_name, gen_set_name, - PyDoc_STR("name of the coroutine")}, -diff --git a/Objects/iterobject.c b/Objects/iterobject.c -index 135ced9ea1f..ebb342ff109 100644 ---- a/Objects/iterobject.c -+++ b/Objects/iterobject.c -@@ -384,6 +384,7 @@ - return result; - } - if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration)) { -+ PyErr_Clear(); - _PyGen_SetStopIterationValue(obj->default_value); - } - return NULL; -@@ -407,6 +408,7 @@ - * exception we replace it with a `StopIteration(default)`, as if - * it was the return value of `__anext__()` coroutine. - */ -+ PyErr_Clear(); - _PyGen_SetStopIterationValue(obj->default_value); - } - return NULL; -diff --git a/Objects/listobject.c b/Objects/listobject.c -index a877bad66be..120e353b709 100644 ---- a/Objects/listobject.c -+++ b/Objects/listobject.c -@@ -335,11 +335,7 @@ - if (!valid_index(idx, size)) { - goto exit; - } --#ifdef Py_GIL_DISABLED - item = _Py_NewRefWithLock(self->ob_item[idx]); --#else -- item = Py_NewRef(self->ob_item[idx]); --#endif - exit: - Py_END_CRITICAL_SECTION(); - return item; -@@ -423,7 +419,6 @@ - PyList_SetItem(PyObject *op, Py_ssize_t i, - PyObject *newitem) - { -- PyObject **p; - if (!PyList_Check(op)) { - Py_XDECREF(newitem); - PyErr_BadInternalCall(); -@@ -439,8 +434,9 @@ - ret = -1; - goto end; - } -- p = self->ob_item + i; -- Py_XSETREF(*p, newitem); -+ PyObject *tmp = self->ob_item[i]; -+ FT_ATOMIC_STORE_PTR_RELEASE(self->ob_item[i], newitem); -+ Py_XDECREF(tmp); - ret = 0; - end:; - Py_END_CRITICAL_SECTION(); -@@ -470,8 +466,8 @@ - where = n; - items = self->ob_item; - for (i = n; --i >= where; ) -- items[i+1] = items[i]; -- items[where] = Py_NewRef(v); -+ FT_ATOMIC_STORE_PTR_RELAXED(items[i+1], items[i]); -+ FT_ATOMIC_STORE_PTR_RELEASE(items[where], Py_NewRef(v)); - return 0; - } - -@@ -3194,7 +3190,7 @@ - } - - PyObject * --_PyList_FromStackRefSteal(const _PyStackRef *src, Py_ssize_t n) -+_PyList_FromStackRefStealOnSuccess(const _PyStackRef *src, Py_ssize_t n) - { - if (n == 0) { - return PyList_New(0); -@@ -3202,9 +3198,6 @@ - - PyListObject *list = (PyListObject *)PyList_New(n); - if (list == NULL) { -- for (Py_ssize_t i = 0; i < n; i++) { -- PyStackRef_CLOSE(src[i]); -- } - return NULL; - } - -@@ -3910,15 +3903,17 @@ - static PyObject * - list_iter(PyObject *seq) - { -- _PyListIterObject *it; -- - if (!PyList_Check(seq)) { - PyErr_BadInternalCall(); - return NULL; - } -- it = PyObject_GC_New(_PyListIterObject, &PyListIter_Type); -- if (it == NULL) -- return NULL; -+ _PyListIterObject *it = _Py_FREELIST_POP(_PyListIterObject, list_iters); -+ if (it == NULL) { -+ it = PyObject_GC_New(_PyListIterObject, &PyListIter_Type); -+ if (it == NULL) { -+ return NULL; -+ } -+ } - it->it_index = 0; - it->it_seq = (PyListObject *)Py_NewRef(seq); - _PyObject_GC_TRACK(it); -@@ -3931,7 +3926,8 @@ - _PyListIterObject *it = (_PyListIterObject *)self; - _PyObject_GC_UNTRACK(it); - Py_XDECREF(it->it_seq); -- PyObject_GC_Del(it); -+ assert(Py_IS_TYPE(self, &PyListIter_Type)); -+ _Py_FREELIST_FREE(list_iters, it, PyObject_GC_Del); - } - - static int -diff --git a/Objects/longobject.c b/Objects/longobject.c -index bd7ff68d089..370328dcfe8 100644 ---- a/Objects/longobject.c -+++ b/Objects/longobject.c -@@ -152,11 +152,11 @@ - # define MAX_LONG_DIGITS ((INT64_MAX-1) / PyLong_SHIFT) - #endif - --PyLongObject * --_PyLong_New(Py_ssize_t size) -+static PyLongObject * -+long_alloc(Py_ssize_t size) - { - assert(size >= 0); -- PyLongObject *result; -+ PyLongObject *result = NULL; - if (size > (Py_ssize_t)MAX_LONG_DIGITS) { - PyErr_SetString(PyExc_OverflowError, - "too many digits in integer"); -@@ -165,25 +165,37 @@ - /* Fast operations for single digit integers (including zero) - * assume that there is always at least one digit present. */ - Py_ssize_t ndigits = size ? size : 1; -- /* Number of bytes needed is: offsetof(PyLongObject, ob_digit) + -- sizeof(digit)*size. Previous incarnations of this code used -- sizeof() instead of the offsetof, but this risks being -- incorrect in the presence of padding between the header -- and the digits. */ -- result = PyObject_Malloc(offsetof(PyLongObject, long_value.ob_digit) + -- ndigits*sizeof(digit)); -- if (!result) { -- PyErr_NoMemory(); -- return NULL; -+ -+ if (ndigits == 1) { -+ result = (PyLongObject *)_Py_FREELIST_POP(PyLongObject, ints); -+ } -+ if (result == NULL) { -+ /* Number of bytes needed is: offsetof(PyLongObject, ob_digit) + -+ sizeof(digit)*size. Previous incarnations of this code used -+ sizeof() instead of the offsetof, but this risks being -+ incorrect in the presence of padding between the header -+ and the digits. */ -+ result = PyObject_Malloc(offsetof(PyLongObject, long_value.ob_digit) + -+ ndigits*sizeof(digit)); -+ if (!result) { -+ PyErr_NoMemory(); -+ return NULL; -+ } -+ _PyObject_Init((PyObject*)result, &PyLong_Type); - } - _PyLong_SetSignAndDigitCount(result, size != 0, size); -- _PyObject_Init((PyObject*)result, &PyLong_Type); - /* The digit has to be initialized explicitly to avoid - * use-of-uninitialized-value. */ - result->long_value.ob_digit[0] = 0; - return result; - } - -+PyLongObject * -+_PyLong_New(Py_ssize_t size) -+{ -+ return long_alloc(size); -+} -+ - PyLongObject * - _PyLong_FromDigits(int negative, Py_ssize_t digit_count, digit *digits) - { -@@ -191,9 +203,8 @@ - if (digit_count == 0) { - return (PyLongObject *)_PyLong_GetZero(); - } -- PyLongObject *result = _PyLong_New(digit_count); -+ PyLongObject *result = long_alloc(digit_count); - if (result == NULL) { -- PyErr_NoMemory(); - return NULL; - } - _PyLong_SetSignAndDigitCount(result, negative?-1:1, digit_count); -@@ -205,15 +216,29 @@ - _PyLong_Copy(PyLongObject *src) - { - assert(src != NULL); -+ int sign; - - if (_PyLong_IsCompact(src)) { - stwodigits ival = medium_value(src); - if (IS_SMALL_INT(ival)) { - return get_small_int((sdigit)ival); - } -+ sign = _PyLong_CompactSign(src); -+ } -+ else { -+ sign = _PyLong_NonCompactSign(src); - } -+ - Py_ssize_t size = _PyLong_DigitCount(src); -- return (PyObject *)_PyLong_FromDigits(_PyLong_IsNegative(src), size, src->long_value.ob_digit); -+ PyLongObject *result = long_alloc(size); -+ -+ if (result == NULL) { -+ return NULL; -+ } -+ _PyLong_SetSignAndDigitCount(result, sign, size); -+ memcpy(result->long_value.ob_digit, src->long_value.ob_digit, -+ size * sizeof(digit)); -+ return (PyObject *)result; - } - - static PyObject * -@@ -262,7 +287,7 @@ - ++ndigits; - t >>= PyLong_SHIFT; - } -- PyLongObject *v = _PyLong_New(ndigits); -+ PyLongObject *v = long_alloc(ndigits); - if (v != NULL) { - digit *p = v->long_value.ob_digit; - _PyLong_SetSignAndDigitCount(v, sign, ndigits); -@@ -335,7 +360,7 @@ - } - - /* Construct output value. */ -- v = _PyLong_New(ndigits); -+ v = long_alloc(ndigits); - if (v != NULL) { - digit *p = v->long_value.ob_digit; - _PyLong_SetSignAndDigitCount(v, ival < 0 ? -1 : 1, ndigits); -@@ -353,14 +378,18 @@ - if (IS_SMALL_UINT(ival)) { \ - return get_small_int((sdigit)(ival)); \ - } \ -+ if ((ival) <= PyLong_MASK) { \ -+ return _PyLong_FromMedium((sdigit)(ival)); \ -+ } \ -+ /* Do shift in two steps to avoid possible undefined behavior. */ \ -+ INT_TYPE t = (ival) >> PyLong_SHIFT >> PyLong_SHIFT; \ - /* Count the number of Python digits. */ \ -- Py_ssize_t ndigits = 0; \ -- INT_TYPE t = (ival); \ -+ Py_ssize_t ndigits = 2; \ - while (t) { \ - ++ndigits; \ - t >>= PyLong_SHIFT; \ - } \ -- PyLongObject *v = _PyLong_New(ndigits); \ -+ PyLongObject *v = long_alloc(ndigits); \ - if (v == NULL) { \ - return NULL; \ - } \ -@@ -437,7 +466,7 @@ - frac = frexp(dval, &expo); /* dval = frac*2**expo; 0.0 <= frac < 1.0 */ - assert(expo > 0); - ndig = (expo-1) / PyLong_SHIFT + 1; /* Number of 'digits' in result */ -- v = _PyLong_New(ndig); -+ v = long_alloc(ndig); - if (v == NULL) - return NULL; - frac = ldexp(frac, (expo-1) % PyLong_SHIFT + 1); -@@ -821,19 +850,25 @@ - return _PyLong_IsZero((PyLongObject *)obj); - } - --int --_PyLong_Sign(PyObject *vv) -+static int -+long_sign(PyObject *vv) - { -+ assert(vv != NULL); -+ assert(PyLong_Check(vv)); - PyLongObject *v = (PyLongObject *)vv; - -- assert(v != NULL); -- assert(PyLong_Check(v)); - if (_PyLong_IsCompact(v)) { - return _PyLong_CompactSign(v); - } - return _PyLong_NonCompactSign(v); - } - -+int -+_PyLong_Sign(PyObject *vv) -+{ -+ return long_sign(vv); -+} -+ - int - PyLong_GetSign(PyObject *vv, int *sign) - { -@@ -842,7 +877,7 @@ - return -1; - } - -- *sign = _PyLong_Sign(vv); -+ *sign = long_sign(vv); - return 0; - } - -@@ -940,7 +975,7 @@ - return NULL; - } - ndigits = (numsignificantbytes * 8 + PyLong_SHIFT - 1) / PyLong_SHIFT; -- v = _PyLong_New(ndigits); -+ v = long_alloc(ndigits); - if (v == NULL) - return NULL; - -@@ -1470,7 +1505,7 @@ - } - - /* Construct output value. */ -- v = _PyLong_New(ndigits); -+ v = long_alloc(ndigits); - if (v != NULL) { - digit *p = v->long_value.ob_digit; - _PyLong_SetSignAndDigitCount(v, ival < 0 ? -1 : 1, ndigits); -@@ -1513,7 +1548,7 @@ - ++ndigits; - t >>= PyLong_SHIFT; - } -- v = _PyLong_New(ndigits); -+ v = long_alloc(ndigits); - if (v != NULL) { - digit *p = v->long_value.ob_digit; - _PyLong_SetSignAndDigitCount(v, negative ? -1 : 1, ndigits); -@@ -2003,7 +2038,7 @@ - PyLongObject *z; - - assert(n > 0 && n <= PyLong_MASK); -- z = _PyLong_New(size); -+ z = long_alloc(size); - if (z == NULL) - return NULL; - *prem = inplace_divrem1(z->long_value.ob_digit, a->long_value.ob_digit, size, n); -@@ -2180,7 +2215,7 @@ - (10 * PyLong_SHIFT - 33 * _PyLong_DECIMAL_SHIFT); - assert(size_a < PY_SSIZE_T_MAX/2); - size = 1 + size_a + size_a / d; -- scratch = _PyLong_New(size); -+ scratch = long_alloc(size); - if (scratch == NULL) - return -1; - -@@ -2623,7 +2658,7 @@ - return 0; - } - n = (digits * bits_per_char + PyLong_SHIFT - 1) / PyLong_SHIFT; -- z = _PyLong_New(n); -+ z = long_alloc(n); - if (z == NULL) { - *res = NULL; - return 0; -@@ -2827,7 +2862,7 @@ - */ - double fsize_z = (double)digits * log_base_BASE[base] + 1.0; - if (fsize_z > (double)MAX_LONG_DIGITS) { -- /* The same exception as in _PyLong_New(). */ -+ /* The same exception as in long_alloc(). */ - PyErr_SetString(PyExc_OverflowError, - "too many digits in integer"); - *res = NULL; -@@ -2837,7 +2872,7 @@ - /* Uncomment next line to test exceedingly rare copy code */ - /* size_z = 1; */ - assert(size_z > 0); -- z = _PyLong_New(size_z); -+ z = long_alloc(size_z); - if (z == NULL) { - *res = NULL; - return 0; -@@ -2900,7 +2935,7 @@ - PyLongObject *tmp; - /* Extremely rare. Get more space. */ - assert(_PyLong_DigitCount(z) == size_z); -- tmp = _PyLong_New(size_z + 1); -+ tmp = long_alloc(size_z + 1); - if (tmp == NULL) { - Py_DECREF(z); - *res = NULL; -@@ -3321,12 +3356,12 @@ - size_v = _PyLong_DigitCount(v1); - size_w = _PyLong_DigitCount(w1); - assert(size_v >= size_w && size_w >= 2); /* Assert checks by div() */ -- v = _PyLong_New(size_v+1); -+ v = long_alloc(size_v+1); - if (v == NULL) { - *prem = NULL; - return NULL; - } -- w = _PyLong_New(size_w); -+ w = long_alloc(size_w); - if (w == NULL) { - Py_DECREF(v); - *prem = NULL; -@@ -3348,7 +3383,7 @@ - at most (and usually exactly) k = size_v - size_w digits. */ - k = size_v - size_w; - assert(k >= 0); -- a = _PyLong_New(k); -+ a = long_alloc(k); - if (a == NULL) { - Py_DECREF(w); - Py_DECREF(v); -@@ -3616,32 +3651,25 @@ - } - - static inline int --compact_int_is_small(PyObject *self) -+/// Return 1 if the object is one of the immortal small ints -+_long_is_small_int(PyObject *op) - { -- PyLongObject *pylong = (PyLongObject *)self; -- assert(_PyLong_IsCompact(pylong)); -- stwodigits ival = medium_value(pylong); -- if (IS_SMALL_INT(ival)) { -- PyLongObject *small_pylong = (PyLongObject *)get_small_int((sdigit)ival); -- if (pylong == small_pylong) { -- return 1; -- } -- } -- return 0; -+ PyLongObject *long_object = (PyLongObject *)op; -+ int is_small_int = (long_object->long_value.lv_tag & IMMORTALITY_BIT_MASK) != 0; -+ assert((!is_small_int) || PyLong_CheckExact(op)); -+ return is_small_int; - } - - void - _PyLong_ExactDealloc(PyObject *self) - { - assert(PyLong_CheckExact(self)); -+ if (_long_is_small_int(self)) { -+ // See PEP 683, section Accidental De-Immortalizing for details -+ _Py_SetImmortal(self); -+ return; -+ } - if (_PyLong_IsCompact((PyLongObject *)self)) { -- #ifndef Py_GIL_DISABLED -- if (compact_int_is_small(self)) { -- // See PEP 683, section Accidental De-Immortalizing for details -- _Py_SetImmortal(self); -- return; -- } -- #endif - _Py_FREELIST_FREE(ints, self, PyObject_Free); - return; - } -@@ -3651,24 +3679,20 @@ - static void - long_dealloc(PyObject *self) - { -- assert(self); -- if (_PyLong_IsCompact((PyLongObject *)self)) { -- if (compact_int_is_small(self)) { -- /* This should never get called, but we also don't want to SEGV if -- * we accidentally decref small Ints out of existence. Instead, -- * since small Ints are immortal, re-set the reference count. -- * -- * See PEP 683, section Accidental De-Immortalizing for details -- */ -- _Py_SetImmortal(self); -- return; -- } -- if (PyLong_CheckExact(self)) { -- _Py_FREELIST_FREE(ints, self, PyObject_Free); -- return; -- } -+ if (_long_is_small_int(self)) { -+ /* This should never get called, but we also don't want to SEGV if -+ * we accidentally decref small Ints out of existence. Instead, -+ * since small Ints are immortal, re-set the reference count. -+ * -+ * See PEP 683, section Accidental De-Immortalizing for details -+ */ -+ _Py_SetImmortal(self); -+ return; -+ } -+ if (PyLong_CheckExact(self) && _PyLong_IsCompact((PyLongObject *)self)) { -+ _Py_FREELIST_FREE(ints, self, PyObject_Free); -+ return; - } -- - Py_TYPE(self)->tp_free(self); - } - -@@ -3746,7 +3770,7 @@ - size_a = size_b; - size_b = size_temp; } - } -- z = _PyLong_New(size_a+1); -+ z = long_alloc(size_a+1); - if (z == NULL) - return NULL; - for (i = 0; i < size_b; ++i) { -@@ -3795,7 +3819,7 @@ - } - size_a = size_b = i+1; - } -- z = _PyLong_New(size_a); -+ z = long_alloc(size_a); - if (z == NULL) - return NULL; - for (i = 0; i < size_b; ++i) { -@@ -3920,7 +3944,7 @@ - Py_ssize_t size_b = _PyLong_DigitCount(b); - Py_ssize_t i; - -- z = _PyLong_New(size_a + size_b); -+ z = long_alloc(size_a + size_b); - if (z == NULL) - return NULL; - -@@ -4030,9 +4054,9 @@ - size_lo = Py_MIN(size_n, size); - size_hi = size_n - size_lo; - -- if ((hi = _PyLong_New(size_hi)) == NULL) -+ if ((hi = long_alloc(size_hi)) == NULL) - return -1; -- if ((lo = _PyLong_New(size_lo)) == NULL) { -+ if ((lo = long_alloc(size_lo)) == NULL) { - Py_DECREF(hi); - return -1; - } -@@ -4132,7 +4156,7 @@ - */ - - /* 1. Allocate result space. */ -- ret = _PyLong_New(asize + bsize); -+ ret = long_alloc(asize + bsize); - if (ret == NULL) goto fail; - #ifdef Py_DEBUG - /* Fill with trash, to catch reference to uninitialized digits. */ -@@ -4282,13 +4306,13 @@ - assert(2 * asize <= bsize); - - /* Allocate result space, and zero it out. */ -- ret = _PyLong_New(asize + bsize); -+ ret = long_alloc(asize + bsize); - if (ret == NULL) - return NULL; - memset(ret->long_value.ob_digit, 0, _PyLong_DigitCount(ret) * sizeof(digit)); - - /* Successive slices of b are copied into bslice. */ -- bslice = _PyLong_New(asize); -+ bslice = long_alloc(asize); - if (bslice == NULL) - goto fail; - -@@ -4754,7 +4778,7 @@ - "intermediate overflow during division"); - goto error; - } -- x = _PyLong_New(a_size + shift_digits + 1); -+ x = long_alloc(a_size + shift_digits + 1); - if (x == NULL) - goto error; - for (i = 0; i < shift_digits; i++) -@@ -4768,7 +4792,7 @@ - digit rem; - /* x = a >> shift */ - assert(a_size >= shift_digits); -- x = _PyLong_New(a_size - shift_digits); -+ x = long_alloc(a_size - shift_digits); - if (x == NULL) - goto error; - rem = v_rshift(x->long_value.ob_digit, a->long_value.ob_digit + shift_digits, -@@ -5348,7 +5372,7 @@ - /* Shifting all the bits of 'a' out gives either -1 or 0. */ - return PyLong_FromLong(-a_negative); - } -- z = _PyLong_New(newsize); -+ z = long_alloc(newsize); - if (z == NULL) { - return NULL; - } -@@ -5463,7 +5487,7 @@ - newsize = oldsize + wordshift; - if (remshift) - ++newsize; -- z = _PyLong_New(newsize); -+ z = long_alloc(newsize); - if (z == NULL) - return NULL; - if (_PyLong_IsNegative(a)) { -@@ -5578,7 +5602,7 @@ - size_a = _PyLong_DigitCount(a); - nega = _PyLong_IsNegative(a); - if (nega) { -- z = _PyLong_New(size_a); -+ z = long_alloc(size_a); - if (z == NULL) - return NULL; - v_complement(z->long_value.ob_digit, a->long_value.ob_digit, size_a); -@@ -5592,7 +5616,7 @@ - size_b = _PyLong_DigitCount(b); - negb = _PyLong_IsNegative(b); - if (negb) { -- z = _PyLong_New(size_b); -+ z = long_alloc(size_b); - if (z == NULL) { - Py_DECREF(a); - return NULL; -@@ -5636,7 +5660,7 @@ - - /* We allow an extra digit if z is negative, to make sure that - the final two's complement of z doesn't overflow. */ -- z = _PyLong_New(size_z + negz); -+ z = long_alloc(size_z + negz); - if (z == NULL) { - Py_DECREF(a); - Py_DECREF(b); -@@ -5834,7 +5858,7 @@ - } - else { - alloc_a = size_a; -- c = _PyLong_New(size_a); -+ c = long_alloc(size_a); - if (c == NULL) - goto error; - } -@@ -5850,7 +5874,7 @@ - } - else { - alloc_b = size_a; -- d = _PyLong_New(size_a); -+ d = long_alloc(size_a); - if (d == NULL) - goto error; - } -@@ -6030,7 +6054,7 @@ - return NULL; - } - assert(PyLong_Check(newobj)); -- newobj->long_value.lv_tag = tmp->long_value.lv_tag; -+ newobj->long_value.lv_tag = tmp->long_value.lv_tag & ~IMMORTALITY_BIT_MASK; - for (i = 0; i < n; i++) { - newobj->long_value.ob_digit[i] = tmp->long_value.ob_digit[i]; - } -@@ -6898,7 +6922,7 @@ - } - assert(digits != NULL); - -- PyLongObject *obj = _PyLong_New(ndigits); -+ PyLongObject *obj = long_alloc(ndigits); - if (obj == NULL) { - goto error; - } -@@ -6918,6 +6942,10 @@ - void - PyLongWriter_Discard(PyLongWriter *writer) - { -+ if (writer == NULL) { -+ return; -+ } -+ - PyLongObject *obj = (PyLongObject *)writer; - assert(Py_REFCNT(obj) == 1); - Py_DECREF(obj); -diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c -index ea4d24dc690..331363b2bab 100644 ---- a/Objects/memoryobject.c -+++ b/Objects/memoryobject.c -@@ -2083,7 +2083,7 @@ - PyObject *format = NULL; - struct unpacker *x = NULL; - -- Struct = _PyImport_GetModuleAttrString("struct", "Struct"); -+ Struct = PyImport_ImportModuleAttrString("struct", "Struct"); - if (Struct == NULL) - return NULL; - -diff --git a/Objects/methodobject.c b/Objects/methodobject.c -index 345da460742..ecec0f7205a 100644 ---- a/Objects/methodobject.c -+++ b/Objects/methodobject.c -@@ -331,7 +331,7 @@ - { - PyCFunctionObject *a = _PyCFunctionObject_CAST(self); - Py_hash_t x = PyObject_GenericHash(a->m_self); -- Py_hash_t y = _Py_HashPointer((void*)(a->m_ml->ml_meth)); -+ Py_hash_t y = Py_HashPointer((void*)(a->m_ml->ml_meth)); - x ^= y; - if (x == -1) { - x = -2; -diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c -index a8d64c9aefa..740392b061b 100644 ---- a/Objects/moduleobject.c -+++ b/Objects/moduleobject.c -@@ -703,7 +703,8 @@ - PyErr_Clear(); - } - if (PyDict_SetItem(d, key, Py_None) != 0) { -- PyErr_FormatUnraisable("Exception ignored on clearing module dict"); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "clearing module dict"); - } - } - } -@@ -724,7 +725,8 @@ - PyErr_Clear(); - } - if (PyDict_SetItem(d, key, Py_None) != 0) { -- PyErr_FormatUnraisable("Exception ignored on clearing module dict"); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "clearing module dict"); - } - } - } -diff --git a/Objects/namespaceobject.c b/Objects/namespaceobject.c -index 5b7547103a2..4ef3bd92f5a 100644 ---- a/Objects/namespaceobject.c -+++ b/Objects/namespaceobject.c -@@ -141,6 +141,10 @@ - goto error; - } - -+ if (PyErr_Occurred()) { -+ goto error; -+ } -+ - separator = PyUnicode_FromString(", "); - if (separator == NULL) - goto error; -diff --git a/Objects/object.c b/Objects/object.c -index d584414c559..f3c7fa6d906 100644 ---- a/Objects/object.c -+++ b/Objects/object.c -@@ -19,7 +19,7 @@ - #include "pycore_object.h" // PyAPI_DATA() _Py_SwappedOp definition - #include "pycore_object_state.h" // struct _reftracer_runtime_state - #include "pycore_long.h" // _PyLong_GetZero() --#include "pycore_optimizer.h" // _PyUOpExecutor_Type, _PyUOpOptimizer_Type, ... -+#include "pycore_optimizer.h" // _PyUOpExecutor_Type, ... - #include "pycore_pyerrors.h" // _PyErr_Occurred() - #include "pycore_pymem.h" // _PyMem_IsPtrFreed() - #include "pycore_pystate.h" // _PyThreadState_GET() -@@ -923,6 +923,8 @@ - clear_freelist(&freelists->tuples[i], is_finalization, free_object); - } - clear_freelist(&freelists->lists, is_finalization, free_object); -+ clear_freelist(&freelists->list_iters, is_finalization, free_object); -+ clear_freelist(&freelists->tuple_iters, is_finalization, free_object); - clear_freelist(&freelists->dicts, is_finalization, free_object); - clear_freelist(&freelists->dictkeys, is_finalization, PyMem_Free); - clear_freelist(&freelists->slices, is_finalization, free_object); -@@ -937,6 +939,7 @@ - } - clear_freelist(&freelists->unicode_writers, is_finalization, PyMem_Free); - clear_freelist(&freelists->ints, is_finalization, free_object); -+ clear_freelist(&freelists->pymethodobjects, is_finalization, free_object); - } - - /* -@@ -1717,7 +1720,11 @@ - else { - PyObject **dictptr = _PyObject_ComputedDictPointer(obj); - if (dictptr) { -+#ifdef Py_GIL_DISABLED -+ dict = _Py_atomic_load_ptr_acquire(dictptr); -+#else - dict = *dictptr; -+#endif - } - } - } -@@ -2374,11 +2381,6 @@ - &_PyBufferWrapper_Type, - &_PyContextTokenMissing_Type, - &_PyCoroWrapper_Type, --#ifdef _Py_TIER2 -- &_PyCounterExecutor_Type, -- &_PyCounterOptimizer_Type, -- &_PyDefaultOptimizer_Type, --#endif - &_Py_GenericAliasIterType, - &_PyHamtItems_Type, - &_PyHamtKeys_Type, -@@ -2401,7 +2403,6 @@ - &_PyUnion_Type, - #ifdef _Py_TIER2 - &_PyUOpExecutor_Type, -- &_PyUOpOptimizer_Type, - #endif - &_PyWeakref_CallableProxyType, - &_PyWeakref_ProxyType, -@@ -2484,13 +2485,20 @@ - op->ob_refcnt = 1; - #endif - #else -- op->ob_tid = _Py_ThreadId(); - op->ob_flags = 0; - op->ob_mutex = (PyMutex){ 0 }; -+#ifdef _Py_THREAD_SANITIZER -+ _Py_atomic_store_uintptr_relaxed(&op->ob_tid, _Py_ThreadId()); -+ _Py_atomic_store_uint8_relaxed(&op->ob_gc_bits, 0); -+ _Py_atomic_store_uint32_relaxed(&op->ob_ref_local, 1); -+ _Py_atomic_store_ssize_relaxed(&op->ob_ref_shared, 0); -+#else -+ op->ob_tid = _Py_ThreadId(); - op->ob_gc_bits = 0; - op->ob_ref_local = 1; - op->ob_ref_shared = 0; - #endif -+#endif - #ifdef Py_TRACE_REFS - _Py_AddToAllObjects(op); - #endif -@@ -2585,6 +2593,20 @@ - #endif - } - -+int -+PyUnstable_TryIncRef(PyObject *op) -+{ -+ return _Py_TryIncref(op); -+} -+ -+void -+PyUnstable_EnableTryIncRef(PyObject *op) -+{ -+#ifdef Py_GIL_DISABLED -+ _PyObject_SetMaybeWeakref(op); -+#endif -+} -+ - void - _Py_ResurrectReference(PyObject *op) - { -@@ -3070,14 +3092,14 @@ - } - - int PyRefTracer_SetTracer(PyRefTracer tracer, void *data) { -- assert(PyGILState_Check()); -+ _Py_AssertHoldsTstate(); - _PyRuntime.ref_tracer.tracer_func = tracer; - _PyRuntime.ref_tracer.tracer_data = data; - return 0; - } - - PyRefTracer PyRefTracer_GetTracer(void** data) { -- assert(PyGILState_Check()); -+ _Py_AssertHoldsTstate(); - if (data != NULL) { - *data = _PyRuntime.ref_tracer.tracer_data; - } -@@ -3152,3 +3174,12 @@ - { - return _Py_REFCNT(ob); - } -+ -+int -+PyUnstable_IsImmortal(PyObject *op) -+{ -+ /* Checking a reference count requires a thread state */ -+ _Py_AssertHoldsTstate(); -+ assert(op != NULL); -+ return _Py_IsImmortal(op); -+} -diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c -index b103deb01ca..5688049b024 100644 ---- a/Objects/obmalloc.c -+++ b/Objects/obmalloc.c -@@ -2909,7 +2909,8 @@ - static inline void - _PyMem_DebugCheckGIL(const char *func) - { -- if (!PyGILState_Check()) { -+ PyThreadState *tstate = _PyThreadState_GET(); -+ if (tstate == NULL) { - #ifndef Py_GIL_DISABLED - _Py_FatalErrorFunc(func, - "Python memory allocator called " -diff --git a/Objects/odictobject.c b/Objects/odictobject.c -index e151023dd76..f2d8da0c567 100644 ---- a/Objects/odictobject.c -+++ b/Objects/odictobject.c -@@ -260,7 +260,7 @@ - mp_subscript __getitem__ - dict_subscript - mp_ass_subscript __setitem__ - dict_ass_sub - __delitem__ --tp_hash __hash__ _Py_HashPointer ..._HashNotImpl -+tp_hash __hash__ Py_HashPointer ..._HashNotImpl - tp_str __str__ object_str - - tp_getattro __getattribute__ ..._GenericGetAttr (repeated) - __getattr__ -diff --git a/Objects/setobject.c b/Objects/setobject.c -index 955ccbebf74..26ab352ca6d 100644 ---- a/Objects/setobject.c -+++ b/Objects/setobject.c -@@ -1298,7 +1298,7 @@ - PyObject *other; - Py_ssize_t i; - -- result = (PySetObject *)set_copy(so, NULL); -+ result = (PySetObject *)set_copy((PyObject *)so, NULL); - if (result == NULL) - return NULL; - -@@ -1321,13 +1321,12 @@ - - if (!PyAnySet_Check(self) || !PyAnySet_Check(other)) - Py_RETURN_NOTIMPLEMENTED; -- PySetObject *so = _PySet_CAST(self); - -- result = (PySetObject *)set_copy(so, NULL); -+ result = (PySetObject *)set_copy(self, NULL); - if (result == NULL) { - return NULL; - } -- if (Py_Is((PyObject *)so, other)) { -+ if (Py_Is(self, other)) { - return (PyObject *)result; - } - if (set_update_local(result, other)) { -@@ -1449,7 +1448,7 @@ - Py_ssize_t i; - - if (others_length == 0) { -- return set_copy(so, NULL); -+ return set_copy((PyObject *)so, NULL); - } - - PyObject *result = Py_NewRef(so); -@@ -1806,7 +1805,7 @@ - PyObject *result, *other; - - if (others_length == 0) { -- return set_copy(so, NULL); -+ return set_copy((PyObject *)so, NULL); - } - - other = others[0]; -@@ -1929,7 +1928,7 @@ - /*[clinic end generated code: output=fbb049c0806028de input=a50acf0365e1f0a5]*/ - { - if (Py_Is((PyObject *)so, other)) { -- return set_clear(so, NULL); -+ return set_clear((PyObject *)so, NULL); - } - - int rv; -@@ -2646,7 +2645,7 @@ - PyErr_BadInternalCall(); - return -1; - } -- (void)set_clear((PySetObject *)set, NULL); -+ (void)set_clear(set, NULL); - return 0; - } - -@@ -2742,7 +2741,7 @@ - PyErr_BadInternalCall(); - return NULL; - } -- return set_pop((PySetObject *)set, NULL); -+ return set_pop(set, NULL); - } - - int -diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c -index 4fef0af93fe..1b07c2a2c49 100644 ---- a/Objects/sliceobject.c -+++ b/Objects/sliceobject.c -@@ -399,11 +399,14 @@ - step_is_negative = 0; - } - else { -- int step_sign; - step = evaluate_slice_index(self->step); -- if (step == NULL) -+ if (step == NULL) { - goto error; -- step_sign = _PyLong_Sign(step); -+ } -+ assert(PyLong_Check(step)); -+ -+ int step_sign; -+ (void)PyLong_GetSign(step, &step_sign); - if (step_sign == 0) { - PyErr_SetString(PyExc_ValueError, - "slice step cannot be zero"); -diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c -index 49977726ead..60af9e40e3f 100644 ---- a/Objects/tupleobject.c -+++ b/Objects/tupleobject.c -@@ -391,16 +391,13 @@ - } - - PyObject * --_PyTuple_FromStackRefSteal(const _PyStackRef *src, Py_ssize_t n) -+_PyTuple_FromStackRefStealOnSuccess(const _PyStackRef *src, Py_ssize_t n) - { - if (n == 0) { - return tuple_get_empty(); - } - PyTupleObject *tuple = tuple_alloc(n); - if (tuple == NULL) { -- for (Py_ssize_t i = 0; i < n; i++) { -- PyStackRef_CLOSE(src[i]); -- } - return NULL; - } - PyObject **dst = tuple->ob_item; -@@ -988,26 +985,30 @@ - - /*********************** Tuple Iterator **************************/ - -+#define _PyTupleIterObject_CAST(op) ((_PyTupleIterObject *)(op)) - - static void --tupleiter_dealloc(_PyTupleIterObject *it) -+tupleiter_dealloc(PyObject *self) - { -+ _PyTupleIterObject *it = _PyTupleIterObject_CAST(self); - _PyObject_GC_UNTRACK(it); - Py_XDECREF(it->it_seq); -- PyObject_GC_Del(it); -+ assert(Py_IS_TYPE(self, &PyTupleIter_Type)); -+ _Py_FREELIST_FREE(tuple_iters, it, PyObject_GC_Del); - } - - static int --tupleiter_traverse(_PyTupleIterObject *it, visitproc visit, void *arg) -+tupleiter_traverse(PyObject *self, visitproc visit, void *arg) - { -+ _PyTupleIterObject *it = _PyTupleIterObject_CAST(self); - Py_VISIT(it->it_seq); - return 0; - } - - static PyObject * --tupleiter_next(PyObject *obj) -+tupleiter_next(PyObject *self) - { -- _PyTupleIterObject *it = (_PyTupleIterObject *)obj; -+ _PyTupleIterObject *it = _PyTupleIterObject_CAST(self); - PyTupleObject *seq; - PyObject *item; - -@@ -1029,8 +1030,9 @@ - } - - static PyObject * --tupleiter_len(_PyTupleIterObject *it, PyObject *Py_UNUSED(ignored)) -+tupleiter_len(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -+ _PyTupleIterObject *it = _PyTupleIterObject_CAST(self); - Py_ssize_t len = 0; - if (it->it_seq) - len = PyTuple_GET_SIZE(it->it_seq) - it->it_index; -@@ -1040,13 +1042,14 @@ - PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it))."); - - static PyObject * --tupleiter_reduce(_PyTupleIterObject *it, PyObject *Py_UNUSED(ignored)) -+tupleiter_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *iter = _PyEval_GetBuiltin(&_Py_ID(iter)); - - /* _PyEval_GetBuiltin can invoke arbitrary code, - * call must be before access of iterator pointers. - * see issue #101765 */ -+ _PyTupleIterObject *it = _PyTupleIterObject_CAST(self); - - if (it->it_seq) - return Py_BuildValue("N(O)n", iter, it->it_seq, it->it_index); -@@ -1055,8 +1058,9 @@ - } - - static PyObject * --tupleiter_setstate(_PyTupleIterObject *it, PyObject *state) -+tupleiter_setstate(PyObject *self, PyObject *state) - { -+ _PyTupleIterObject *it = _PyTupleIterObject_CAST(self); - Py_ssize_t index = PyLong_AsSsize_t(state); - if (index == -1 && PyErr_Occurred()) - return NULL; -@@ -1074,19 +1078,19 @@ - PyDoc_STRVAR(setstate_doc, "Set state information for unpickling."); - - static PyMethodDef tupleiter_methods[] = { -- {"__length_hint__", (PyCFunction)tupleiter_len, METH_NOARGS, length_hint_doc}, -- {"__reduce__", (PyCFunction)tupleiter_reduce, METH_NOARGS, reduce_doc}, -- {"__setstate__", (PyCFunction)tupleiter_setstate, METH_O, setstate_doc}, -- {NULL, NULL} /* sentinel */ -+ {"__length_hint__", tupleiter_len, METH_NOARGS, length_hint_doc}, -+ {"__reduce__", tupleiter_reduce, METH_NOARGS, reduce_doc}, -+ {"__setstate__", tupleiter_setstate, METH_O, setstate_doc}, -+ {NULL, NULL, 0, NULL} /* sentinel */ - }; - - PyTypeObject PyTupleIter_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - "tuple_iterator", /* tp_name */ -- sizeof(_PyTupleIterObject), /* tp_basicsize */ -+ sizeof(_PyTupleIterObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ -- (destructor)tupleiter_dealloc, /* tp_dealloc */ -+ tupleiter_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ -@@ -1103,7 +1107,7 @@ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ - 0, /* tp_doc */ -- (traverseproc)tupleiter_traverse, /* tp_traverse */ -+ tupleiter_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ -@@ -1116,15 +1120,16 @@ - static PyObject * - tuple_iter(PyObject *seq) - { -- _PyTupleIterObject *it; -- - if (!PyTuple_Check(seq)) { - PyErr_BadInternalCall(); - return NULL; - } -- it = PyObject_GC_New(_PyTupleIterObject, &PyTupleIter_Type); -- if (it == NULL) -- return NULL; -+ _PyTupleIterObject *it = _Py_FREELIST_POP(_PyTupleIterObject, tuple_iters); -+ if (it == NULL) { -+ it = PyObject_GC_New(_PyTupleIterObject, &PyTupleIter_Type); -+ if (it == NULL) -+ return NULL; -+ } - it->it_index = 0; - it->it_seq = (PyTupleObject *)Py_NewRef(seq); - _PyObject_GC_TRACK(it); -diff --git a/Objects/typeobject.c b/Objects/typeobject.c -index 2068d6aa9be..f3238da8a64 100644 ---- a/Objects/typeobject.c -+++ b/Objects/typeobject.c -@@ -992,6 +992,7 @@ - set_version_unlocked(PyTypeObject *tp, unsigned int version) - { - ASSERT_TYPE_LOCK_HELD(); -+ assert(version == 0 || (tp->tp_versions_used != _Py_ATTR_CACHE_UNUSED)); - #ifndef Py_GIL_DISABLED - PyInterpreterState *interp = _PyInterpreterState_GET(); - // lookup the old version and set to null -@@ -1038,7 +1039,7 @@ - We don't assign new version tags eagerly, but only as - needed. - */ -- if (type->tp_version_tag == 0) { -+ if (FT_ATOMIC_LOAD_UINT_RELAXED(type->tp_version_tag) == 0) { - return; - } - // Cannot modify static builtin types. -@@ -1148,6 +1149,10 @@ - PyObject *b = PyTuple_GET_ITEM(bases, i); - PyTypeObject *cls = _PyType_CAST(b); - -+ if (cls->tp_versions_used >= _Py_ATTR_CACHE_UNUSED) { -+ goto clear; -+ } -+ - if (!is_subtype_with_mro(lookup_tp_mro(type), type, cls)) { - goto clear; - } -@@ -1156,7 +1161,8 @@ - - clear: - assert(!(type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN)); -- set_version_unlocked(type, 0); /* 0 is not a valid version tag */ -+ set_version_unlocked(type, 0); /* 0 is not a valid version tag */ -+ type->tp_versions_used = _Py_ATTR_CACHE_UNUSED; - if (PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) { - // This field *must* be invalidated if the type is modified (see the - // comment on struct _specialization_cache): -@@ -1208,6 +1214,9 @@ - - - #define MAX_VERSIONS_PER_CLASS 1000 -+#if _Py_ATTR_CACHE_UNUSED < MAX_VERSIONS_PER_CLASS -+#error "_Py_ATTR_CACHE_UNUSED must be bigger than max" -+#endif - - static int - assign_version_tag(PyInterpreterState *interp, PyTypeObject *type) -@@ -1225,6 +1234,7 @@ - return 0; - } - if (type->tp_versions_used >= MAX_VERSIONS_PER_CLASS) { -+ /* (this includes `tp_versions_used == _Py_ATTR_CACHE_UNUSED`) */ - return 0; - } - -@@ -2860,7 +2870,7 @@ - */ - - static int --tail_contains(PyObject *tuple, int whence, PyObject *o) -+tail_contains(PyObject *tuple, Py_ssize_t whence, PyObject *o) - { - Py_ssize_t j, size; - size = PyTuple_GET_SIZE(tuple); -@@ -2923,7 +2933,7 @@ - */ - - static void --set_mro_error(PyObject **to_merge, Py_ssize_t to_merge_size, int *remain) -+set_mro_error(PyObject **to_merge, Py_ssize_t to_merge_size, Py_ssize_t *remain) - { - Py_ssize_t i, n, off; - char buf[1000]; -@@ -2978,13 +2988,13 @@ - { - int res = 0; - Py_ssize_t i, j, empty_cnt; -- int *remain; -+ Py_ssize_t *remain; - - /* remain stores an index into each sublist of to_merge. - remain[i] is the index of the next base in to_merge[i] - that is not included in acc. - */ -- remain = PyMem_New(int, to_merge_size); -+ remain = PyMem_New(Py_ssize_t, to_merge_size); - if (remain == NULL) { - PyErr_NoMemory(); - return -1; -@@ -5679,6 +5689,31 @@ - return can_cache; - } - -+int -+_PyType_CacheGetItemForSpecialization(PyHeapTypeObject *ht, PyObject *descriptor, uint32_t tp_version) -+{ -+ if (!descriptor || !tp_version) { -+ return 0; -+ } -+ int can_cache; -+ BEGIN_TYPE_LOCK(); -+ can_cache = ((PyTypeObject*)ht)->tp_version_tag == tp_version; -+ // This pointer is invalidated by PyType_Modified (see the comment on -+ // struct _specialization_cache): -+ PyFunctionObject *func = (PyFunctionObject *)descriptor; -+ uint32_t version = _PyFunction_GetVersionForCurrentState(func); -+ can_cache = can_cache && _PyFunction_IsVersionValid(version); -+#ifdef Py_GIL_DISABLED -+ can_cache = can_cache && _PyObject_HasDeferredRefcount(descriptor); -+#endif -+ if (can_cache) { -+ FT_ATOMIC_STORE_PTR_RELEASE(ht->_spec_cache.getitem, descriptor); -+ FT_ATOMIC_STORE_UINT32_RELAXED(ht->_spec_cache.getitem_version, version); -+ } -+ END_TYPE_LOCK(); -+ return can_cache; -+} -+ - static void - set_flags(PyTypeObject *self, unsigned long mask, unsigned long flags) - { -@@ -6125,7 +6160,7 @@ - Py_XDECREF(et->ht_module); - PyMem_Free(et->_ht_tpname); - #ifdef Py_GIL_DISABLED -- assert(et->unique_id == -1); -+ assert(et->unique_id == _Py_INVALID_UNIQUE_ID); - #endif - et->ht_token = NULL; - Py_TYPE(type)->tp_free((PyObject *)type); -@@ -10253,10 +10288,13 @@ - del = lookup_maybe_method(self, &_Py_ID(__del__), &unbound); - if (del != NULL) { - res = call_unbound_noarg(unbound, del, self); -- if (res == NULL) -- PyErr_WriteUnraisable(del); -- else -+ if (res == NULL) { -+ PyErr_FormatUnraisable("Exception ignored while " -+ "calling deallocator %R", del); -+ } -+ else { - Py_DECREF(res); -+ } - Py_DECREF(del); - } - -diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c -index b7aeb06d32b..75967d69ed3 100644 ---- a/Objects/unicodeobject.c -+++ b/Objects/unicodeobject.c -@@ -112,20 +112,42 @@ - # define _PyUnicode_CHECK(op) PyUnicode_Check(op) - #endif - --#define _PyUnicode_UTF8(op) \ -- (_PyCompactUnicodeObject_CAST(op)->utf8) --#define PyUnicode_UTF8(op) \ -- (assert(_PyUnicode_CHECK(op)), \ -- PyUnicode_IS_COMPACT_ASCII(op) ? \ -- ((char*)(_PyASCIIObject_CAST(op) + 1)) : \ -- _PyUnicode_UTF8(op)) --#define _PyUnicode_UTF8_LENGTH(op) \ -- (_PyCompactUnicodeObject_CAST(op)->utf8_length) --#define PyUnicode_UTF8_LENGTH(op) \ -- (assert(_PyUnicode_CHECK(op)), \ -- PyUnicode_IS_COMPACT_ASCII(op) ? \ -- _PyASCIIObject_CAST(op)->length : \ -- _PyUnicode_UTF8_LENGTH(op)) -+static inline char* _PyUnicode_UTF8(PyObject *op) -+{ -+ return FT_ATOMIC_LOAD_PTR_ACQUIRE(_PyCompactUnicodeObject_CAST(op)->utf8); -+} -+ -+static inline char* PyUnicode_UTF8(PyObject *op) -+{ -+ assert(_PyUnicode_CHECK(op)); -+ if (PyUnicode_IS_COMPACT_ASCII(op)) { -+ return ((char*)(_PyASCIIObject_CAST(op) + 1)); -+ } -+ else { -+ return _PyUnicode_UTF8(op); -+ } -+} -+ -+static inline void PyUnicode_SET_UTF8(PyObject *op, char *utf8) -+{ -+ FT_ATOMIC_STORE_PTR_RELEASE(_PyCompactUnicodeObject_CAST(op)->utf8, utf8); -+} -+ -+static inline Py_ssize_t PyUnicode_UTF8_LENGTH(PyObject *op) -+{ -+ assert(_PyUnicode_CHECK(op)); -+ if (PyUnicode_IS_COMPACT_ASCII(op)) { -+ return _PyASCIIObject_CAST(op)->length; -+ } -+ else { -+ return _PyCompactUnicodeObject_CAST(op)->utf8_length; -+ } -+} -+ -+static inline void PyUnicode_SET_UTF8_LENGTH(PyObject *op, Py_ssize_t length) -+{ -+ _PyCompactUnicodeObject_CAST(op)->utf8_length = length; -+} - - #define _PyUnicode_LENGTH(op) \ - (_PyASCIIObject_CAST(op)->length) -@@ -133,26 +155,37 @@ - (_PyASCIIObject_CAST(op)->state) - #define _PyUnicode_HASH(op) \ - (_PyASCIIObject_CAST(op)->hash) --#define _PyUnicode_KIND(op) \ -- (assert(_PyUnicode_CHECK(op)), \ -- _PyASCIIObject_CAST(op)->state.kind) --#define _PyUnicode_GET_LENGTH(op) \ -- (assert(_PyUnicode_CHECK(op)), \ -- _PyASCIIObject_CAST(op)->length) -+ -+static inline Py_hash_t PyUnicode_HASH(PyObject *op) -+{ -+ assert(_PyUnicode_CHECK(op)); -+ return FT_ATOMIC_LOAD_SSIZE_RELAXED(_PyASCIIObject_CAST(op)->hash); -+} -+ -+static inline void PyUnicode_SET_HASH(PyObject *op, Py_hash_t hash) -+{ -+ FT_ATOMIC_STORE_SSIZE_RELAXED(_PyASCIIObject_CAST(op)->hash, hash); -+} -+ - #define _PyUnicode_DATA_ANY(op) \ - (_PyUnicodeObject_CAST(op)->data.any) - --#define _PyUnicode_SHARE_UTF8(op) \ -- (assert(_PyUnicode_CHECK(op)), \ -- assert(!PyUnicode_IS_COMPACT_ASCII(op)), \ -- (_PyUnicode_UTF8(op) == PyUnicode_DATA(op))) -+static inline int _PyUnicode_SHARE_UTF8(PyObject *op) -+{ -+ assert(_PyUnicode_CHECK(op)); -+ assert(!PyUnicode_IS_COMPACT_ASCII(op)); -+ return (_PyUnicode_UTF8(op) == PyUnicode_DATA(op)); -+} - - /* true if the Unicode object has an allocated UTF-8 memory block - (not shared with other data) */ --#define _PyUnicode_HAS_UTF8_MEMORY(op) \ -- ((!PyUnicode_IS_COMPACT_ASCII(op) \ -- && _PyUnicode_UTF8(op) \ -- && _PyUnicode_UTF8(op) != PyUnicode_DATA(op))) -+static inline int _PyUnicode_HAS_UTF8_MEMORY(PyObject *op) -+{ -+ return (!PyUnicode_IS_COMPACT_ASCII(op) -+ && _PyUnicode_UTF8(op) != NULL -+ && _PyUnicode_UTF8(op) != PyUnicode_DATA(op)); -+} -+ - - /* Generic helper macro to convert characters of different types. - from_type and to_type have to be valid type names, begin and end -@@ -655,7 +688,7 @@ - || kind == PyUnicode_2BYTE_KIND - || kind == PyUnicode_4BYTE_KIND); - CHECK(ascii->state.ascii == 0); -- CHECK(compact->utf8 != data); -+ CHECK(_PyUnicode_UTF8(op) != data); - } - else { - PyUnicodeObject *unicode = _PyUnicodeObject_CAST(op); -@@ -667,16 +700,17 @@ - CHECK(ascii->state.compact == 0); - CHECK(data != NULL); - if (ascii->state.ascii) { -- CHECK(compact->utf8 == data); -+ CHECK(_PyUnicode_UTF8(op) == data); - CHECK(compact->utf8_length == ascii->length); - } - else { -- CHECK(compact->utf8 != data); -+ CHECK(_PyUnicode_UTF8(op) != data); - } - } -- -- if (compact->utf8 == NULL) -+#ifndef Py_GIL_DISABLED -+ if (_PyUnicode_UTF8(op) == NULL) - CHECK(compact->utf8_length == 0); -+#endif - } - - /* check that the best kind is used: O(n) operation */ -@@ -1123,8 +1157,8 @@ - - if (_PyUnicode_HAS_UTF8_MEMORY(unicode)) { - PyMem_Free(_PyUnicode_UTF8(unicode)); -- _PyUnicode_UTF8(unicode) = NULL; -- _PyUnicode_UTF8_LENGTH(unicode) = 0; -+ PyUnicode_SET_UTF8_LENGTH(unicode, 0); -+ PyUnicode_SET_UTF8(unicode, NULL); - } - #ifdef Py_TRACE_REFS - _Py_ForgetReference(unicode); -@@ -1177,8 +1211,8 @@ - if (!share_utf8 && _PyUnicode_HAS_UTF8_MEMORY(unicode)) - { - PyMem_Free(_PyUnicode_UTF8(unicode)); -- _PyUnicode_UTF8(unicode) = NULL; -- _PyUnicode_UTF8_LENGTH(unicode) = 0; -+ PyUnicode_SET_UTF8_LENGTH(unicode, 0); -+ PyUnicode_SET_UTF8(unicode, NULL); - } - - data = (PyObject *)PyObject_Realloc(data, new_size); -@@ -1188,8 +1222,8 @@ - } - _PyUnicode_DATA_ANY(unicode) = data; - if (share_utf8) { -- _PyUnicode_UTF8(unicode) = data; -- _PyUnicode_UTF8_LENGTH(unicode) = length; -+ PyUnicode_SET_UTF8_LENGTH(unicode, length); -+ PyUnicode_SET_UTF8(unicode, data); - } - _PyUnicode_LENGTH(unicode) = length; - PyUnicode_WRITE(PyUnicode_KIND(unicode), data, length, 0); -@@ -1429,11 +1463,14 @@ - assert(PyUnicode_Check(from)); - assert(from_start + how_many <= PyUnicode_GET_LENGTH(from)); - -- assert(PyUnicode_Check(to)); -- assert(to_start + how_many <= PyUnicode_GET_LENGTH(to)); -+ assert(to == NULL || PyUnicode_Check(to)); - -- if (how_many == 0) -+ if (how_many == 0) { - return 0; -+ } -+ -+ assert(to != NULL); -+ assert(to_start + how_many <= PyUnicode_GET_LENGTH(to)); - - from_kind = PyUnicode_KIND(from); - from_data = PyUnicode_DATA(from); -@@ -1698,7 +1735,9 @@ - PyObject *popped; - int r = PyDict_Pop(interned, unicode, &popped); - if (r == -1) { -- PyErr_WriteUnraisable(unicode); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "removing an interned string %R", -+ unicode); - // We don't know what happened to the string. It's probably - // best to leak it: - // - if it was popped, there are no more references to it -@@ -1769,7 +1808,7 @@ - assert(_PyUnicode_CHECK(unicode)); - if (Py_REFCNT(unicode) != 1) - return 0; -- if (FT_ATOMIC_LOAD_SSIZE_RELAXED(_PyUnicode_HASH(unicode)) != -1) -+ if (PyUnicode_HASH(unicode) != -1) - return 0; - if (PyUnicode_CHECK_INTERNED(unicode)) - return 0; -@@ -4183,6 +4222,21 @@ - - static int unicode_fill_utf8(PyObject *unicode); - -+ -+static int -+unicode_ensure_utf8(PyObject *unicode) -+{ -+ int err = 0; -+ if (PyUnicode_UTF8(unicode) == NULL) { -+ Py_BEGIN_CRITICAL_SECTION(unicode); -+ if (PyUnicode_UTF8(unicode) == NULL) { -+ err = unicode_fill_utf8(unicode); -+ } -+ Py_END_CRITICAL_SECTION(); -+ } -+ return err; -+} -+ - const char * - PyUnicode_AsUTF8AndSize(PyObject *unicode, Py_ssize_t *psize) - { -@@ -4194,13 +4248,11 @@ - return NULL; - } - -- if (PyUnicode_UTF8(unicode) == NULL) { -- if (unicode_fill_utf8(unicode) == -1) { -- if (psize) { -- *psize = -1; -- } -- return NULL; -+ if (unicode_ensure_utf8(unicode) == -1) { -+ if (psize) { -+ *psize = -1; - } -+ return NULL; - } - - if (psize) { -@@ -5821,6 +5873,7 @@ - static int - unicode_fill_utf8(PyObject *unicode) - { -+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(unicode); - /* the string cannot be ASCII, or PyUnicode_UTF8() would be set */ - assert(!PyUnicode_IS_ASCII(unicode)); - -@@ -5862,10 +5915,10 @@ - PyErr_NoMemory(); - return -1; - } -- _PyUnicode_UTF8(unicode) = cache; -- _PyUnicode_UTF8_LENGTH(unicode) = len; - memcpy(cache, start, len); - cache[len] = '\0'; -+ PyUnicode_SET_UTF8_LENGTH(unicode, len); -+ PyUnicode_SET_UTF8(unicode, cache); - _PyBytesWriter_Dealloc(&writer); - return 0; - } -@@ -6802,7 +6855,8 @@ - unsigned char c = *first_invalid_escape; - if ('4' <= c && c <= '7') { - if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, -- "invalid octal escape sequence '\\%.3s'", -+ "\"\\%.3s\" is an invalid octal escape sequence. " -+ "Such sequences will not work in the future. ", - first_invalid_escape) < 0) - { - Py_DECREF(result); -@@ -6811,7 +6865,8 @@ - } - else { - if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, -- "invalid escape sequence '\\%c'", -+ "\"\\%c\" is an invalid escape sequence. " -+ "Such sequences will not work in the future. ", - c) < 0) - { - Py_DECREF(result); -@@ -11434,9 +11489,9 @@ - return 0; - } - -- Py_hash_t right_hash = FT_ATOMIC_LOAD_SSIZE_RELAXED(_PyUnicode_HASH(right_uni)); -+ Py_hash_t right_hash = PyUnicode_HASH(right_uni); - assert(right_hash != -1); -- Py_hash_t hash = FT_ATOMIC_LOAD_SSIZE_RELAXED(_PyUnicode_HASH(left)); -+ Py_hash_t hash = PyUnicode_HASH(left); - if (hash != -1 && hash != right_hash) { - return 0; - } -@@ -11916,14 +11971,14 @@ - #ifdef Py_DEBUG - assert(_Py_HashSecret_Initialized); - #endif -- Py_hash_t hash = FT_ATOMIC_LOAD_SSIZE_RELAXED(_PyUnicode_HASH(self)); -+ Py_hash_t hash = PyUnicode_HASH(self); - if (hash != -1) { - return hash; - } - x = Py_HashBuffer(PyUnicode_DATA(self), - PyUnicode_GET_LENGTH(self) * PyUnicode_KIND(self)); - -- FT_ATOMIC_STORE_SSIZE_RELAXED(_PyUnicode_HASH(self), x); -+ PyUnicode_SET_HASH(self, x); - return x; - } - -@@ -15427,8 +15482,8 @@ - _PyUnicode_STATE(self).compact = 0; - _PyUnicode_STATE(self).ascii = _PyUnicode_STATE(unicode).ascii; - _PyUnicode_STATE(self).statically_allocated = 0; -- _PyUnicode_UTF8_LENGTH(self) = 0; -- _PyUnicode_UTF8(self) = NULL; -+ PyUnicode_SET_UTF8_LENGTH(self, 0); -+ PyUnicode_SET_UTF8(self, NULL); - _PyUnicode_DATA_ANY(self) = NULL; - - share_utf8 = 0; -@@ -15458,8 +15513,8 @@ - - _PyUnicode_DATA_ANY(self) = data; - if (share_utf8) { -- _PyUnicode_UTF8_LENGTH(self) = length; -- _PyUnicode_UTF8(self) = data; -+ PyUnicode_SET_UTF8_LENGTH(self, length); -+ PyUnicode_SET_UTF8(self, data); - } - - memcpy(data, PyUnicode_DATA(unicode), kind * (length + 1)); -@@ -15678,7 +15733,7 @@ - _Py_DecRefTotal(_PyThreadState_GET()); - } - #endif -- _PyUnicode_STATE(s).interned = SSTATE_INTERNED_IMMORTAL; -+ FT_ATOMIC_STORE_UINT16_RELAXED(_PyUnicode_STATE(s).interned, SSTATE_INTERNED_IMMORTAL); - _Py_SetImmortal(s); - } - -@@ -15797,7 +15852,7 @@ - _Py_DecRefTotal(_PyThreadState_GET()); - #endif - } -- _PyUnicode_STATE(s).interned = SSTATE_INTERNED_MORTAL; -+ FT_ATOMIC_STORE_UINT16_RELAXED(_PyUnicode_STATE(s).interned, SSTATE_INTERNED_MORTAL); - - /* INTERNED_MORTAL -> INTERNED_IMMORTAL (if needed) */ - -@@ -15933,7 +15988,7 @@ - Py_UNREACHABLE(); - } - if (!shared) { -- _PyUnicode_STATE(s).interned = SSTATE_NOT_INTERNED; -+ FT_ATOMIC_STORE_UINT16_RELAXED(_PyUnicode_STATE(s).interned, SSTATE_NOT_INTERNED); - } - } - #ifdef INTERNED_STATS -@@ -16433,3 +16488,24 @@ - { - return PyModuleDef_Init(&_string_module); - } -+ -+ -+#undef PyUnicode_KIND -+int PyUnicode_KIND(PyObject *op) -+{ -+ if (!PyUnicode_Check(op)) { -+ PyErr_Format(PyExc_TypeError, "expect str, got %T", op); -+ return -1; -+ } -+ return _PyASCIIObject_CAST(op)->state.kind; -+} -+ -+#undef PyUnicode_DATA -+void* PyUnicode_DATA(PyObject *op) -+{ -+ if (!PyUnicode_Check(op)) { -+ PyErr_Format(PyExc_TypeError, "expect str, got %T", op); -+ return NULL; -+ } -+ return _PyUnicode_DATA(op); -+} -diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c -index 9e3da1c3394..bd4c4ac9b34 100644 ---- a/Objects/weakrefobject.c -+++ b/Objects/weakrefobject.c -@@ -932,6 +932,19 @@ - return (PyObject *)get_or_create_weakref(type, ob, callback); - } - -+int -+PyWeakref_IsDead(PyObject *ref) -+{ -+ if (ref == NULL) { -+ PyErr_BadInternalCall(); -+ return -1; -+ } -+ if (!PyWeakref_Check(ref)) { -+ PyErr_Format(PyExc_TypeError, "expected a weakref, got %T", ref); -+ return -1; -+ } -+ return _PyWeakref_IS_DEAD(ref); -+} - - int - PyWeakref_GetRef(PyObject *ref, PyObject **pobj) -@@ -974,10 +987,13 @@ - { - PyObject *cbresult = PyObject_CallOneArg(callback, (PyObject *)ref); - -- if (cbresult == NULL) -- PyErr_WriteUnraisable(callback); -- else -+ if (cbresult == NULL) { -+ PyErr_FormatUnraisable("Exception ignored while " -+ "calling weakref callback %R", callback); -+ } -+ else { - Py_DECREF(cbresult); -+ } - } - - /* This function is called by the tp_dealloc handler to clear weak references. -@@ -1029,7 +1045,8 @@ - PyObject *tuple = PyTuple_New(num_weakrefs * 2); - if (tuple == NULL) { - _PyWeakref_ClearWeakRefsNoCallbacks(object); -- PyErr_WriteUnraisable(NULL); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "clearing object weakrefs"); - PyErr_SetRaisedException(exc); - return; - } -diff --git a/PC/clinic/winreg.c.h b/PC/clinic/winreg.c.h -index b14913366b7..00fa6a75ec1 100644 ---- a/PC/clinic/winreg.c.h -+++ b/PC/clinic/winreg.c.h -@@ -26,9 +26,9 @@ - winreg_HKEYType_Close_impl(PyHKEYObject *self); - - static PyObject * --winreg_HKEYType_Close(PyHKEYObject *self, PyObject *Py_UNUSED(ignored)) -+winreg_HKEYType_Close(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return winreg_HKEYType_Close_impl(self); -+ return winreg_HKEYType_Close_impl((PyHKEYObject *)self); - } - - #endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) */ -@@ -56,9 +56,9 @@ - winreg_HKEYType_Detach_impl(PyHKEYObject *self); - - static PyObject * --winreg_HKEYType_Detach(PyHKEYObject *self, PyObject *Py_UNUSED(ignored)) -+winreg_HKEYType_Detach(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return winreg_HKEYType_Detach_impl(self); -+ return winreg_HKEYType_Detach_impl((PyHKEYObject *)self); - } - - #endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) */ -@@ -77,12 +77,12 @@ - winreg_HKEYType___enter___impl(PyHKEYObject *self); - - static PyObject * --winreg_HKEYType___enter__(PyHKEYObject *self, PyObject *Py_UNUSED(ignored)) -+winreg_HKEYType___enter__(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - PyHKEYObject *_return_value; - -- _return_value = winreg_HKEYType___enter___impl(self); -+ _return_value = winreg_HKEYType___enter___impl((PyHKEYObject *)self); - return_value = (PyObject *)_return_value; - - return return_value; -@@ -105,7 +105,7 @@ - PyObject *exc_value, PyObject *traceback); - - static PyObject * --winreg_HKEYType___exit__(PyHKEYObject *self, PyObject *const *args, Py_ssize_t nargs) -+winreg_HKEYType___exit__(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *exc_type; -@@ -118,7 +118,7 @@ - exc_type = args[0]; - exc_value = args[1]; - traceback = args[2]; -- return_value = winreg_HKEYType___exit___impl(self, exc_type, exc_value, traceback); -+ return_value = winreg_HKEYType___exit___impl((PyHKEYObject *)self, exc_type, exc_value, traceback); - - exit: - return return_value; -@@ -1766,4 +1766,4 @@ - #ifndef WINREG_QUERYREFLECTIONKEY_METHODDEF - #define WINREG_QUERYREFLECTIONKEY_METHODDEF - #endif /* !defined(WINREG_QUERYREFLECTIONKEY_METHODDEF) */ --/*[clinic end generated code: output=aef4aa8ab8ddf38f input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=fbe9b075cd2fa833 input=a9049054013a1b77]*/ -diff --git a/PC/pyconfig.h.in b/PC/pyconfig.h.in -index 010f5fe5646..f4f57c5d270 100644 ---- a/PC/pyconfig.h.in -+++ b/PC/pyconfig.h.in -@@ -753,4 +753,7 @@ - /* Define if libssl has X509_VERIFY_PARAM_set1_host and related function */ - #define HAVE_X509_VERIFY_PARAM_SET1_HOST 1 - -+// Truncate the thread name to 32766 characters. -+#define _PYTHREAD_NAME_MAXLEN 32766 -+ - #endif /* !Py_CONFIG_H */ -diff --git a/PC/python.manifest b/PC/python.manifest -index 8e1bc022adf..19c9fc1b80a 100644 ---- a/PC/python.manifest -+++ b/PC/python.manifest -@@ -9,10 +9,15 @@ - - - -+ - -+ - -+ - -+ - -+ - - - -diff --git a/PC/python3dll.c b/PC/python3dll.c -index 8657ddb9fa5..84b3c735240 100755 ---- a/PC/python3dll.c -+++ b/PC/python3dll.c -@@ -81,6 +81,8 @@ - EXPORT_FUNC(Py_MakePendingCalls) - EXPORT_FUNC(Py_NewInterpreter) - EXPORT_FUNC(Py_NewRef) -+EXPORT_FUNC(Py_PACK_FULL_VERSION) -+EXPORT_FUNC(Py_PACK_VERSION) - EXPORT_FUNC(Py_REFCNT) - EXPORT_FUNC(Py_ReprEnter) - EXPORT_FUNC(Py_ReprLeave) -diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c -index 5ac1dd78136..2fe8d11badc 100644 ---- a/Parser/action_helpers.c -+++ b/Parser/action_helpers.c -@@ -969,8 +969,6 @@ - return result_token_with_metadata(p, conv, conv_token->metadata); - } - --static asdl_expr_seq * --unpack_top_level_joined_strs(Parser *p, asdl_expr_seq *raw_expressions); - ResultTokenWithMetadata * - _PyPegen_setup_full_format_spec(Parser *p, Token *colon, asdl_expr_seq *spec, int lineno, int col_offset, - int end_lineno, int end_col_offset, PyArena *arena) -@@ -1279,9 +1277,9 @@ - p->arena); - } - --static asdl_expr_seq * --unpack_top_level_joined_strs(Parser *p, asdl_expr_seq *raw_expressions) --{ -+expr_ty -+_PyPegen_joined_str(Parser *p, Token* a, asdl_expr_seq* expr, Token*b) { -+ - /* The parser might put multiple f-string values into an individual - * JoinedStr node at the top level due to stuff like f-string debugging - * expressions. This function flattens those and promotes them to the -@@ -1289,44 +1287,14 @@ - * of the regular output, so this is not necessary if you are not going - * to expose the output AST to Python level. */ - -- Py_ssize_t i, req_size, raw_size; -- -- req_size = raw_size = asdl_seq_LEN(raw_expressions); -- expr_ty expr; -- for (i = 0; i < raw_size; i++) { -- expr = asdl_seq_GET(raw_expressions, i); -- if (expr->kind == JoinedStr_kind) { -- req_size += asdl_seq_LEN(expr->v.JoinedStr.values) - 1; -- } -- } -- -- asdl_expr_seq *expressions = _Py_asdl_expr_seq_new(req_size, p->arena); -- if (expressions == NULL) { -- return NULL; -- } -- -- Py_ssize_t raw_index, req_index = 0; -- for (raw_index = 0; raw_index < raw_size; raw_index++) { -- expr = asdl_seq_GET(raw_expressions, raw_index); -- if (expr->kind == JoinedStr_kind) { -- asdl_expr_seq *values = expr->v.JoinedStr.values; -- for (Py_ssize_t n = 0; n < asdl_seq_LEN(values); n++) { -- asdl_seq_SET(expressions, req_index, asdl_seq_GET(values, n)); -- req_index++; -- } -- } else { -- asdl_seq_SET(expressions, req_index, expr); -- req_index++; -+ Py_ssize_t n_items = asdl_seq_LEN(expr); -+ Py_ssize_t total_items = n_items; -+ for (Py_ssize_t i = 0; i < n_items; i++) { -+ expr_ty item = asdl_seq_GET(expr, i); -+ if (item->kind == JoinedStr_kind) { -+ total_items += asdl_seq_LEN(item->v.JoinedStr.values) - 1; - } - } -- return expressions; --} -- --expr_ty --_PyPegen_joined_str(Parser *p, Token* a, asdl_expr_seq* raw_expressions, Token*b) { -- -- asdl_expr_seq *expr = unpack_top_level_joined_strs(p, raw_expressions); -- Py_ssize_t n_items = asdl_seq_LEN(expr); - - const char* quote_str = PyBytes_AsString(a->bytes); - if (quote_str == NULL) { -@@ -1334,7 +1302,7 @@ - } - int is_raw = strpbrk(quote_str, "rR") != NULL; - -- asdl_expr_seq *seq = _Py_asdl_expr_seq_new(n_items, p->arena); -+ asdl_expr_seq *seq = _Py_asdl_expr_seq_new(total_items, p->arena); - if (seq == NULL) { - return NULL; - } -@@ -1342,6 +1310,31 @@ - Py_ssize_t index = 0; - for (Py_ssize_t i = 0; i < n_items; i++) { - expr_ty item = asdl_seq_GET(expr, i); -+ -+ // This should correspond to a JoinedStr node of two elements -+ // created _PyPegen_formatted_value. This situation can only be the result of -+ // a f-string debug expression where the first element is a constant with the text and the second -+ // a formatted value with the expression. -+ if (item->kind == JoinedStr_kind) { -+ asdl_expr_seq *values = item->v.JoinedStr.values; -+ if (asdl_seq_LEN(values) != 2) { -+ PyErr_Format(PyExc_SystemError, -+ "unexpected JoinedStr node without debug data in f-string at line %d", -+ item->lineno); -+ return NULL; -+ } -+ -+ expr_ty first = asdl_seq_GET(values, 0); -+ assert(first->kind == Constant_kind); -+ asdl_seq_SET(seq, index++, first); -+ -+ expr_ty second = asdl_seq_GET(values, 1); -+ assert(second->kind == FormattedValue_kind); -+ asdl_seq_SET(seq, index++, second); -+ -+ continue; -+ } -+ - if (item->kind == Constant_kind) { - item = _PyPegen_decode_fstring_part(p, is_raw, item, b); - if (item == NULL) { -@@ -1360,7 +1353,7 @@ - } - - asdl_expr_seq *resized_exprs; -- if (index != n_items) { -+ if (index != total_items) { - resized_exprs = _Py_asdl_expr_seq_new(index, p->arena); - if (resized_exprs == NULL) { - return NULL; -diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py -index 853a3e99807..7b2df738119 100755 ---- a/Parser/asdl_c.py -+++ b/Parser/asdl_c.py -@@ -1462,10 +1462,11 @@ - return PyObject_Repr(list); - } - -- _PyUnicodeWriter writer; -- _PyUnicodeWriter_Init(&writer); -- writer.overallocate = 1; - PyObject *items[2] = {NULL, NULL}; -+ PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); -+ if (writer == NULL) { -+ goto error; -+ } - - items[0] = PySequence_GetItem(list, 0); - if (!items[0]) { -@@ -1479,52 +1480,54 @@ - } - - bool is_list = PyList_Check(list); -- if (_PyUnicodeWriter_WriteChar(&writer, is_list ? '[' : '(') < 0) { -+ if (PyUnicodeWriter_WriteChar(writer, is_list ? '[' : '(') < 0) { - goto error; - } - - for (Py_ssize_t i = 0; i < Py_MIN(length, 2); i++) { -- PyObject *item = items[i]; -- PyObject *item_repr; -+ if (i > 0) { -+ if (PyUnicodeWriter_WriteUTF8(writer, ", ", 2) < 0) { -+ goto error; -+ } -+ } - -+ PyObject *item = items[i]; - if (PyType_IsSubtype(Py_TYPE(item), (PyTypeObject *)state->AST_type)) { -+ PyObject *item_repr; - item_repr = ast_repr_max_depth((AST_object*)item, depth - 1); -- } else { -- item_repr = PyObject_Repr(item); -- } -- if (!item_repr) { -- goto error; -- } -- if (i > 0) { -- if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) { -+ if (!item_repr) { -+ goto error; -+ } -+ if (PyUnicodeWriter_WriteStr(writer, item_repr) < 0) { -+ Py_DECREF(item_repr); - goto error; - } -- } -- if (_PyUnicodeWriter_WriteStr(&writer, item_repr) < 0) { - Py_DECREF(item_repr); -- goto error; -+ } else { -+ if (PyUnicodeWriter_WriteRepr(writer, item) < 0) { -+ goto error; -+ } - } -+ - if (i == 0 && length > 2) { -- if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ...", 5) < 0) { -- Py_DECREF(item_repr); -+ if (PyUnicodeWriter_WriteUTF8(writer, ", ...", 5) < 0) { - goto error; - } - } -- Py_DECREF(item_repr); - } - -- if (_PyUnicodeWriter_WriteChar(&writer, is_list ? ']' : ')') < 0) { -+ if (PyUnicodeWriter_WriteChar(writer, is_list ? ']' : ')') < 0) { - goto error; - } - - Py_XDECREF(items[0]); - Py_XDECREF(items[1]); -- return _PyUnicodeWriter_Finish(&writer); -+ return PyUnicodeWriter_Finish(writer); - - error: - Py_XDECREF(items[0]); - Py_XDECREF(items[1]); -- _PyUnicodeWriter_Dealloc(&writer); -+ PyUnicodeWriter_Discard(writer); - return NULL; - } - -@@ -1568,14 +1571,15 @@ - } - - const char* tp_name = Py_TYPE(self)->tp_name; -- _PyUnicodeWriter writer; -- _PyUnicodeWriter_Init(&writer); -- writer.overallocate = 1; -+ PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); -+ if (writer == NULL) { -+ goto error; -+ } - -- if (_PyUnicodeWriter_WriteASCIIString(&writer, tp_name, strlen(tp_name)) < 0) { -+ if (PyUnicodeWriter_WriteUTF8(writer, tp_name, -1) < 0) { - goto error; - } -- if (_PyUnicodeWriter_WriteChar(&writer, '(') < 0) { -+ if (PyUnicodeWriter_WriteChar(writer, '(') < 0) { - goto error; - } - -@@ -1610,13 +1614,13 @@ - } - - if (i > 0) { -- if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) { -+ if (PyUnicodeWriter_WriteUTF8(writer, ", ", 2) < 0) { - Py_DECREF(name); - Py_DECREF(value_repr); - goto error; - } - } -- if (_PyUnicodeWriter_WriteStr(&writer, name) < 0) { -+ if (PyUnicodeWriter_WriteStr(writer, name) < 0) { - Py_DECREF(name); - Py_DECREF(value_repr); - goto error; -@@ -1624,11 +1628,11 @@ - - Py_DECREF(name); - -- if (_PyUnicodeWriter_WriteChar(&writer, '=') < 0) { -+ if (PyUnicodeWriter_WriteChar(writer, '=') < 0) { - Py_DECREF(value_repr); - goto error; - } -- if (_PyUnicodeWriter_WriteStr(&writer, value_repr) < 0) { -+ if (PyUnicodeWriter_WriteStr(writer, value_repr) < 0) { - Py_DECREF(value_repr); - goto error; - } -@@ -1636,17 +1640,17 @@ - Py_DECREF(value_repr); - } - -- if (_PyUnicodeWriter_WriteChar(&writer, ')') < 0) { -+ if (PyUnicodeWriter_WriteChar(writer, ')') < 0) { - goto error; - } - Py_ReprLeave((PyObject *)self); - Py_DECREF(fields); -- return _PyUnicodeWriter_Finish(&writer); -+ return PyUnicodeWriter_Finish(writer); - - error: - Py_ReprLeave((PyObject *)self); - Py_DECREF(fields); -- _PyUnicodeWriter_Dealloc(&writer); -+ PyUnicodeWriter_Discard(writer); - return NULL; - } - -diff --git a/Parser/lexer/lexer.c b/Parser/lexer/lexer.c -index 8c868593f94..8c5ae37fa90 100644 ---- a/Parser/lexer/lexer.c -+++ b/Parser/lexer/lexer.c -@@ -212,9 +212,7 @@ - case '}': - case '!': - case ':': -- if (tok_mode->last_expr_end == -1) { -- tok_mode->last_expr_end = strlen(tok->start); -- } -+ tok_mode->last_expr_end = strlen(tok->start); - break; - default: - Py_UNREACHABLE(); -@@ -329,11 +327,7 @@ - return 0; - } - Py_ssize_t invalid = _PyUnicode_ScanIdentifier(s); -- if (invalid < 0) { -- Py_DECREF(s); -- tok->done = E_ERROR; -- return 0; -- } -+ assert(invalid >= 0); - assert(PyUnicode_GET_LENGTH(s) > 0); - if (invalid < PyUnicode_GET_LENGTH(s)) { - Py_UCS4 ch = PyUnicode_READ_CHAR(s, invalid); -diff --git a/Parser/pegen.c b/Parser/pegen.c -index bb98e7b184a..83b0022e47d 100644 ---- a/Parser/pegen.c -+++ b/Parser/pegen.c -@@ -111,7 +111,7 @@ - if (p->normalize) { - return 1; - } -- p->normalize = _PyImport_GetModuleAttrString("unicodedata", "normalize"); -+ p->normalize = PyImport_ImportModuleAttrString("unicodedata", "normalize"); - if (!p->normalize) - { - return 0; -diff --git a/Parser/string_parser.c b/Parser/string_parser.c -index 9537c543b0e..9dd8f9ef28b 100644 ---- a/Parser/string_parser.c -+++ b/Parser/string_parser.c -@@ -28,9 +28,16 @@ - int octal = ('4' <= c && c <= '7'); - PyObject *msg = - octal -- ? PyUnicode_FromFormat("invalid octal escape sequence '\\%.3s'", -- first_invalid_escape) -- : PyUnicode_FromFormat("invalid escape sequence '\\%c'", c); -+ ? PyUnicode_FromFormat( -+ "\"\\%.3s\" is an invalid octal escape sequence. " -+ "Such sequences will not work in the future. " -+ "Did you mean \"\\\\%.3s\"? A raw string is also an option.", -+ first_invalid_escape, first_invalid_escape) -+ : PyUnicode_FromFormat( -+ "\"\\%c\" is an invalid escape sequence. " -+ "Such sequences will not work in the future. " -+ "Did you mean \"\\\\%c\"? A raw string is also an option.", -+ c, c); - if (msg == NULL) { - return -1; - } -@@ -53,11 +60,16 @@ - error location, if p->known_err_token is not set. */ - p->known_err_token = t; - if (octal) { -- RAISE_SYNTAX_ERROR("invalid octal escape sequence '\\%.3s'", -- first_invalid_escape); -+ RAISE_SYNTAX_ERROR( -+ "\"\\%.3s\" is an invalid octal escape sequence. " -+ "Did you mean \"\\\\%.3s\"? A raw string is also an option.", -+ first_invalid_escape, first_invalid_escape); - } - else { -- RAISE_SYNTAX_ERROR("invalid escape sequence '\\%c'", c); -+ RAISE_SYNTAX_ERROR( -+ "\"\\%c\" is an invalid escape sequence. " -+ "Did you mean \"\\\\%c\"? A raw string is also an option.", -+ c, c); - } - } - Py_DECREF(msg); -diff --git a/Parser/tokenizer/file_tokenizer.c b/Parser/tokenizer/file_tokenizer.c -index 2750527da48..efe9fb9b56a 100644 ---- a/Parser/tokenizer/file_tokenizer.c -+++ b/Parser/tokenizer/file_tokenizer.c -@@ -158,7 +158,7 @@ - return 0; - } - -- open = _PyImport_GetModuleAttrString("io", "open"); -+ open = PyImport_ImportModuleAttrString("io", "open"); - if (open == NULL) { - return 0; - } -diff --git a/Parser/tokenizer/helpers.c b/Parser/tokenizer/helpers.c -index 9c9d05bbef0..5a416adb875 100644 ---- a/Parser/tokenizer/helpers.c -+++ b/Parser/tokenizer/helpers.c -@@ -113,7 +113,10 @@ - } - - PyObject *msg = PyUnicode_FromFormat( -- "invalid escape sequence '\\%c'", -+ "\"\\%c\" is an invalid escape sequence. " -+ "Such sequences will not work in the future. " -+ "Did you mean \"\\\\%c\"? A raw string is also an option.", -+ (char) first_invalid_escape_char, - (char) first_invalid_escape_char - ); - -@@ -129,7 +132,12 @@ - /* Replace the SyntaxWarning exception with a SyntaxError - to get a more accurate error report */ - PyErr_Clear(); -- return _PyTokenizer_syntaxerror(tok, "invalid escape sequence '\\%c'", (char) first_invalid_escape_char); -+ -+ return _PyTokenizer_syntaxerror(tok, -+ "\"\\%c\" is an invalid escape sequence. " -+ "Did you mean \"\\\\%c\"? A raw string is also an option.", -+ (char) first_invalid_escape_char, -+ (char) first_invalid_escape_char); - } - - return -1; -diff --git a/Programs/_testembed.c b/Programs/_testembed.c -index d15dd519dbf..6f6d0cae580 100644 ---- a/Programs/_testembed.c -+++ b/Programs/_testembed.c -@@ -1791,55 +1791,6 @@ - } - - --static int tune_config(void) --{ -- PyConfig config; -- PyConfig_InitPythonConfig(&config); -- if (_PyInterpreterState_GetConfigCopy(&config) < 0) { -- PyConfig_Clear(&config); -- PyErr_Print(); -- return -1; -- } -- -- config.bytes_warning = 2; -- -- if (_PyInterpreterState_SetConfig(&config) < 0) { -- PyConfig_Clear(&config); -- return -1; -- } -- PyConfig_Clear(&config); -- return 0; --} -- -- --static int test_init_set_config(void) --{ -- // Initialize core -- PyConfig config; -- PyConfig_InitIsolatedConfig(&config); -- config_set_string(&config, &config.program_name, PROGRAM_NAME); -- config._init_main = 0; -- config.bytes_warning = 0; -- init_from_config_clear(&config); -- -- // Tune the configuration using _PyInterpreterState_SetConfig() -- if (tune_config() < 0) { -- PyErr_Print(); -- return 1; -- } -- -- // Finish initialization: main part -- PyStatus status = _Py_InitializeMain(); -- if (PyStatus_Exception(status)) { -- Py_ExitStatusException(status); -- } -- -- dump_config(); -- Py_Finalize(); -- return 0; --} -- -- - static int initconfig_getint(PyInitConfig *config, const char *name) - { - int64_t value; -@@ -2089,33 +2040,6 @@ - } - - --static int test_init_main(void) --{ -- PyConfig config; -- PyConfig_InitPythonConfig(&config); -- -- configure_init_main(&config); -- config._init_main = 0; -- init_from_config_clear(&config); -- -- /* sys.stdout don't exist yet: it is created by _Py_InitializeMain() */ -- int res = PyRun_SimpleString( -- "import sys; " -- "print('Run Python code before _Py_InitializeMain', " -- "file=sys.stderr)"); -- if (res < 0) { -- exit(1); -- } -- -- PyStatus status = _Py_InitializeMain(); -- if (PyStatus_Exception(status)) { -- Py_ExitStatusException(status); -- } -- -- return Py_RunMain(); --} -- -- - static int test_run_main(void) - { - PyConfig config; -@@ -2473,14 +2397,12 @@ - {"test_preinit_dont_parse_argv", test_preinit_dont_parse_argv}, - {"test_init_read_set", test_init_read_set}, - {"test_init_run_main", test_init_run_main}, -- {"test_init_main", test_init_main}, - {"test_init_sys_add", test_init_sys_add}, - {"test_init_setpath", test_init_setpath}, - {"test_init_setpath_config", test_init_setpath_config}, - {"test_init_setpythonhome", test_init_setpythonhome}, - {"test_init_is_python_build", test_init_is_python_build}, - {"test_init_warnoptions", test_init_warnoptions}, -- {"test_init_set_config", test_init_set_config}, - {"test_initconfig_api", test_initconfig_api}, - {"test_initconfig_get_api", test_initconfig_get_api}, - {"test_initconfig_exit", test_initconfig_exit}, -diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h -index c936622c020..0fe8d3d3f7d 100644 ---- a/Programs/test_frozenmain.h -+++ b/Programs/test_frozenmain.h -@@ -1,18 +1,19 @@ - // Auto-generated by Programs/freeze_test_frozenmain.py - unsigned char M_test_frozenmain[] = { -- 227,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, -- 0,0,0,0,0,243,168,0,0,0,149,0,89,0,79,0, -- 70,0,111,0,89,0,79,0,70,1,111,1,88,2,31,0, -- 79,1,49,1,0,0,0,0,0,0,29,0,88,2,31,0, -- 79,2,88,0,77,6,0,0,0,0,0,0,0,0,0,0, -- 0,0,0,0,0,0,0,0,49,2,0,0,0,0,0,0, -- 29,0,88,1,77,8,0,0,0,0,0,0,0,0,0,0, -- 0,0,0,0,0,0,0,0,31,0,49,0,0,0,0,0, -- 0,0,79,3,2,0,0,0,111,5,79,4,16,0,67,20, -- 0,0,111,6,88,2,31,0,79,5,88,6,12,0,79,6, -- 88,5,88,6,2,0,0,0,12,0,47,4,49,1,0,0, -- 0,0,0,0,29,0,72,22,0,0,9,0,29,0,79,0, -- 33,0,41,7,78,122,18,70,114,111,122,101,110,32,72,101, -+ 227,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0, -+ 0,0,0,0,0,243,184,0,0,0,149,0,90,0,80,0, -+ 71,0,112,0,90,0,80,0,71,1,112,1,89,2,33,0, -+ 80,1,51,1,0,0,0,0,0,0,31,0,89,2,33,0, -+ 80,2,89,0,78,6,0,0,0,0,0,0,0,0,0,0, -+ 0,0,0,0,0,0,0,0,51,2,0,0,0,0,0,0, -+ 31,0,89,1,78,8,0,0,0,0,0,0,0,0,0,0, -+ 0,0,0,0,0,0,0,0,33,0,51,0,0,0,0,0, -+ 0,0,80,3,44,26,0,0,0,0,0,0,0,0,0,0, -+ 112,5,80,4,16,0,68,24,0,0,112,6,89,2,33,0, -+ 80,5,89,6,12,0,80,6,89,5,89,6,44,26,0,0, -+ 0,0,0,0,0,0,0,0,12,0,49,4,51,1,0,0, -+ 0,0,0,0,31,0,73,26,0,0,9,0,30,0,80,0, -+ 35,0,41,7,78,122,18,70,114,111,122,101,110,32,72,101, - 108,108,111,32,87,111,114,108,100,122,8,115,121,115,46,97, - 114,103,118,218,6,99,111,110,102,105,103,41,5,218,12,112, - 114,111,103,114,97,109,95,110,97,109,101,218,10,101,120,101, -@@ -30,8 +31,8 @@ - 1,0,0,0,115,94,0,0,0,240,3,1,1,1,243,8, - 0,1,11,219,0,24,225,0,5,208,6,26,212,0,27,217, - 0,5,128,106,144,35,151,40,145,40,212,0,27,216,9,26, -- 215,9,38,210,9,38,211,9,40,168,24,209,9,50,128,6, -+ 215,9,38,210,9,38,211,9,40,168,24,213,9,50,128,6, - 243,2,6,12,2,128,67,241,14,0,5,10,136,71,144,67, -- 144,53,152,2,152,54,160,35,153,59,152,45,208,10,40,214, -+ 144,53,152,2,152,54,160,35,157,59,152,45,208,10,40,214, - 4,41,243,15,6,12,2,114,15,0,0,0, - }; -diff --git a/Python/Python-ast.c b/Python/Python-ast.c -index 41299b29705..7038e3c92ab 100644 ---- a/Python/Python-ast.c -+++ b/Python/Python-ast.c -@@ -5661,10 +5661,11 @@ - return PyObject_Repr(list); - } - -- _PyUnicodeWriter writer; -- _PyUnicodeWriter_Init(&writer); -- writer.overallocate = 1; - PyObject *items[2] = {NULL, NULL}; -+ PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); -+ if (writer == NULL) { -+ goto error; -+ } - - items[0] = PySequence_GetItem(list, 0); - if (!items[0]) { -@@ -5678,52 +5679,54 @@ - } - - bool is_list = PyList_Check(list); -- if (_PyUnicodeWriter_WriteChar(&writer, is_list ? '[' : '(') < 0) { -+ if (PyUnicodeWriter_WriteChar(writer, is_list ? '[' : '(') < 0) { - goto error; - } - - for (Py_ssize_t i = 0; i < Py_MIN(length, 2); i++) { -- PyObject *item = items[i]; -- PyObject *item_repr; -+ if (i > 0) { -+ if (PyUnicodeWriter_WriteUTF8(writer, ", ", 2) < 0) { -+ goto error; -+ } -+ } - -+ PyObject *item = items[i]; - if (PyType_IsSubtype(Py_TYPE(item), (PyTypeObject *)state->AST_type)) { -+ PyObject *item_repr; - item_repr = ast_repr_max_depth((AST_object*)item, depth - 1); -- } else { -- item_repr = PyObject_Repr(item); -- } -- if (!item_repr) { -- goto error; -- } -- if (i > 0) { -- if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) { -+ if (!item_repr) { -+ goto error; -+ } -+ if (PyUnicodeWriter_WriteStr(writer, item_repr) < 0) { -+ Py_DECREF(item_repr); - goto error; - } -- } -- if (_PyUnicodeWriter_WriteStr(&writer, item_repr) < 0) { - Py_DECREF(item_repr); -- goto error; -+ } else { -+ if (PyUnicodeWriter_WriteRepr(writer, item) < 0) { -+ goto error; -+ } - } -+ - if (i == 0 && length > 2) { -- if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ...", 5) < 0) { -- Py_DECREF(item_repr); -+ if (PyUnicodeWriter_WriteUTF8(writer, ", ...", 5) < 0) { - goto error; - } - } -- Py_DECREF(item_repr); - } - -- if (_PyUnicodeWriter_WriteChar(&writer, is_list ? ']' : ')') < 0) { -+ if (PyUnicodeWriter_WriteChar(writer, is_list ? ']' : ')') < 0) { - goto error; - } - - Py_XDECREF(items[0]); - Py_XDECREF(items[1]); -- return _PyUnicodeWriter_Finish(&writer); -+ return PyUnicodeWriter_Finish(writer); - - error: - Py_XDECREF(items[0]); - Py_XDECREF(items[1]); -- _PyUnicodeWriter_Dealloc(&writer); -+ PyUnicodeWriter_Discard(writer); - return NULL; - } - -@@ -5767,14 +5770,15 @@ - } - - const char* tp_name = Py_TYPE(self)->tp_name; -- _PyUnicodeWriter writer; -- _PyUnicodeWriter_Init(&writer); -- writer.overallocate = 1; -+ PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); -+ if (writer == NULL) { -+ goto error; -+ } - -- if (_PyUnicodeWriter_WriteASCIIString(&writer, tp_name, strlen(tp_name)) < 0) { -+ if (PyUnicodeWriter_WriteUTF8(writer, tp_name, -1) < 0) { - goto error; - } -- if (_PyUnicodeWriter_WriteChar(&writer, '(') < 0) { -+ if (PyUnicodeWriter_WriteChar(writer, '(') < 0) { - goto error; - } - -@@ -5809,13 +5813,13 @@ - } - - if (i > 0) { -- if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) { -+ if (PyUnicodeWriter_WriteUTF8(writer, ", ", 2) < 0) { - Py_DECREF(name); - Py_DECREF(value_repr); - goto error; - } - } -- if (_PyUnicodeWriter_WriteStr(&writer, name) < 0) { -+ if (PyUnicodeWriter_WriteStr(writer, name) < 0) { - Py_DECREF(name); - Py_DECREF(value_repr); - goto error; -@@ -5823,11 +5827,11 @@ - - Py_DECREF(name); - -- if (_PyUnicodeWriter_WriteChar(&writer, '=') < 0) { -+ if (PyUnicodeWriter_WriteChar(writer, '=') < 0) { - Py_DECREF(value_repr); - goto error; - } -- if (_PyUnicodeWriter_WriteStr(&writer, value_repr) < 0) { -+ if (PyUnicodeWriter_WriteStr(writer, value_repr) < 0) { - Py_DECREF(value_repr); - goto error; - } -@@ -5835,17 +5839,17 @@ - Py_DECREF(value_repr); - } - -- if (_PyUnicodeWriter_WriteChar(&writer, ')') < 0) { -+ if (PyUnicodeWriter_WriteChar(writer, ')') < 0) { - goto error; - } - Py_ReprLeave((PyObject *)self); - Py_DECREF(fields); -- return _PyUnicodeWriter_Finish(&writer); -+ return PyUnicodeWriter_Finish(writer); - - error: - Py_ReprLeave((PyObject *)self); - Py_DECREF(fields); -- _PyUnicodeWriter_Dealloc(&writer); -+ PyUnicodeWriter_Discard(writer); - return NULL; - } - -diff --git a/Python/_warnings.c b/Python/_warnings.c -index e05ba99e8ea..891db2743a2 100644 ---- a/Python/_warnings.c -+++ b/Python/_warnings.c -@@ -232,6 +232,64 @@ - return obj; - } - -+static inline void -+warnings_lock(PyInterpreterState *interp) -+{ -+ WarningsState *st = warnings_get_state(interp); -+ assert(st != NULL); -+ _PyRecursiveMutex_Lock(&st->lock); -+} -+ -+static inline int -+warnings_unlock(PyInterpreterState *interp) -+{ -+ WarningsState *st = warnings_get_state(interp); -+ assert(st != NULL); -+ return _PyRecursiveMutex_TryUnlock(&st->lock); -+} -+ -+static inline bool -+warnings_lock_held(WarningsState *st) -+{ -+ return PyMutex_IsLocked(&st->lock.mutex); -+} -+ -+/*[clinic input] -+_acquire_lock as warnings_acquire_lock -+ -+[clinic start generated code]*/ -+ -+static PyObject * -+warnings_acquire_lock_impl(PyObject *module) -+/*[clinic end generated code: output=594313457d1bf8e1 input=46ec20e55acca52f]*/ -+{ -+ PyInterpreterState *interp = get_current_interp(); -+ if (interp == NULL) { -+ return NULL; -+ } -+ warnings_lock(interp); -+ Py_RETURN_NONE; -+} -+ -+/*[clinic input] -+_release_lock as warnings_release_lock -+ -+[clinic start generated code]*/ -+ -+static PyObject * -+warnings_release_lock_impl(PyObject *module) -+/*[clinic end generated code: output=d73d5a8789396750 input=ea01bb77870c5693]*/ -+{ -+ PyInterpreterState *interp = get_current_interp(); -+ if (interp == NULL) { -+ return NULL; -+ } -+ if (warnings_unlock(interp) < 0) { -+ PyErr_SetString(PyExc_RuntimeError, "cannot release un-acquired lock"); -+ return NULL; -+ } -+ Py_RETURN_NONE; -+} - - static PyObject * - get_once_registry(PyInterpreterState *interp) -@@ -239,7 +297,7 @@ - WarningsState *st = warnings_get_state(interp); - assert(st != NULL); - -- _Py_CRITICAL_SECTION_ASSERT_MUTEX_LOCKED(&st->mutex); -+ assert(warnings_lock_held(st)); - - PyObject *registry = GET_WARNINGS_ATTR(interp, onceregistry, 0); - if (registry == NULL) { -@@ -267,7 +325,7 @@ - WarningsState *st = warnings_get_state(interp); - assert(st != NULL); - -- _Py_CRITICAL_SECTION_ASSERT_MUTEX_LOCKED(&st->mutex); -+ assert(warnings_lock_held(st)); - - PyObject *default_action = GET_WARNINGS_ATTR(interp, defaultaction, 0); - if (default_action == NULL) { -@@ -299,7 +357,7 @@ - WarningsState *st = warnings_get_state(interp); - assert(st != NULL); - -- _Py_CRITICAL_SECTION_ASSERT_MUTEX_LOCKED(&st->mutex); -+ assert(warnings_lock_held(st)); - - PyObject *warnings_filters = GET_WARNINGS_ATTR(interp, filters, 0); - if (warnings_filters == NULL) { -@@ -399,7 +457,7 @@ - - WarningsState *st = warnings_get_state(interp); - assert(st != NULL); -- _Py_CRITICAL_SECTION_ASSERT_MUTEX_LOCKED(&st->mutex); -+ assert(warnings_lock_held(st)); - - PyObject *version_obj; - if (PyDict_GetItemRef(registry, &_Py_ID(version), &version_obj) < 0) { -@@ -994,15 +1052,10 @@ - &filename, &lineno, &module, ®istry)) - return NULL; - --#ifdef Py_GIL_DISABLED -- WarningsState *st = warnings_get_state(tstate->interp); -- assert(st != NULL); --#endif -- -- Py_BEGIN_CRITICAL_SECTION_MUT(&st->mutex); -+ warnings_lock(tstate->interp); - res = warn_explicit(tstate, category, message, filename, lineno, module, registry, - NULL, source); -- Py_END_CRITICAL_SECTION(); -+ warnings_unlock(tstate->interp); - Py_DECREF(filename); - Py_DECREF(registry); - Py_DECREF(module); -@@ -1151,27 +1204,22 @@ - } - } - --#ifdef Py_GIL_DISABLED -- WarningsState *st = warnings_get_state(tstate->interp); -- assert(st != NULL); --#endif -- -- Py_BEGIN_CRITICAL_SECTION_MUT(&st->mutex); -+ warnings_lock(tstate->interp); - returned = warn_explicit(tstate, category, message, filename, lineno, - mod, registry, source_line, sourceobj); -- Py_END_CRITICAL_SECTION(); -+ warnings_unlock(tstate->interp); - Py_XDECREF(source_line); - return returned; - } - - /*[clinic input] --_filters_mutated as warnings_filters_mutated -+_filters_mutated_lock_held as warnings_filters_mutated_lock_held - - [clinic start generated code]*/ - - static PyObject * --warnings_filters_mutated_impl(PyObject *module) --/*[clinic end generated code: output=8ce517abd12b88f4 input=35ecbf08ee2491b2]*/ -+warnings_filters_mutated_lock_held_impl(PyObject *module) -+/*[clinic end generated code: output=df5c84f044e856ec input=34208bf03d70e432]*/ - { - PyInterpreterState *interp = get_current_interp(); - if (interp == NULL) { -@@ -1181,14 +1229,17 @@ - WarningsState *st = warnings_get_state(interp); - assert(st != NULL); - -- Py_BEGIN_CRITICAL_SECTION_MUT(&st->mutex); -+ // Note that the lock must be held by the caller. -+ if (!warnings_lock_held(st)) { -+ PyErr_SetString(PyExc_RuntimeError, "warnings lock is not held"); -+ return NULL; -+ } -+ - st->filters_version++; -- Py_END_CRITICAL_SECTION(); - - Py_RETURN_NONE; - } - -- - /* Function to issue a warning message; may raise an exception. */ - - static int -@@ -1303,15 +1354,10 @@ - return -1; - } - --#ifdef Py_GIL_DISABLED -- WarningsState *st = warnings_get_state(tstate->interp); -- assert(st != NULL); --#endif -- -- Py_BEGIN_CRITICAL_SECTION_MUT(&st->mutex); -+ warnings_lock(tstate->interp); - res = warn_explicit(tstate, category, message, filename, lineno, - module, registry, NULL, NULL); -- Py_END_CRITICAL_SECTION(); -+ warnings_unlock(tstate->interp); - if (res == NULL) - return -1; - Py_DECREF(res); -@@ -1376,15 +1422,10 @@ - PyObject *res; - PyThreadState *tstate = get_current_tstate(); - if (tstate != NULL) { --#ifdef Py_GIL_DISABLED -- WarningsState *st = warnings_get_state(tstate->interp); -- assert(st != NULL); --#endif -- -- Py_BEGIN_CRITICAL_SECTION_MUT(&st->mutex); -+ warnings_lock(tstate->interp); - res = warn_explicit(tstate, category, message, filename, lineno, - module, registry, NULL, NULL); -- Py_END_CRITICAL_SECTION(); -+ warnings_unlock(tstate->interp); - Py_DECREF(message); - if (res != NULL) { - Py_DECREF(res); -@@ -1407,7 +1448,8 @@ - "coroutine method %R of %R was never awaited", - method, agen->ag_qualname) < 0) - { -- PyErr_WriteUnraisable((PyObject *)agen); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "finalizing async generator %R", agen); - } - PyErr_SetRaisedException(exc); - } -@@ -1449,14 +1491,17 @@ - } - - if (PyErr_Occurred()) { -- PyErr_WriteUnraisable(coro); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "finalizing coroutine %R", coro); - } -+ - if (!warned) { - if (_PyErr_WarnFormat(coro, PyExc_RuntimeWarning, 1, - "coroutine '%S' was never awaited", - ((PyCoroObject *)coro)->cr_qualname) < 0) - { -- PyErr_WriteUnraisable(coro); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "finalizing coroutine %R", coro); - } - } - } -@@ -1464,7 +1509,9 @@ - static PyMethodDef warnings_functions[] = { - WARNINGS_WARN_METHODDEF - WARNINGS_WARN_EXPLICIT_METHODDEF -- WARNINGS_FILTERS_MUTATED_METHODDEF -+ WARNINGS_FILTERS_MUTATED_LOCK_HELD_METHODDEF -+ WARNINGS_ACQUIRE_LOCK_METHODDEF -+ WARNINGS_RELEASE_LOCK_METHODDEF - /* XXX(brett.cannon): add showwarning? */ - /* XXX(brett.cannon): Reasonable to add formatwarning? */ - {NULL, NULL} /* sentinel */ -diff --git a/Python/ast_opt.c b/Python/ast_opt.c -index 01e208b88ec..78d84002d59 100644 ---- a/Python/ast_opt.c -+++ b/Python/ast_opt.c -@@ -567,25 +567,6 @@ - return make_const(node, newval, arena); - } - --static int --fold_subscr(expr_ty node, PyArena *arena, _PyASTOptimizeState *state) --{ -- PyObject *newval; -- expr_ty arg, idx; -- -- arg = node->v.Subscript.value; -- idx = node->v.Subscript.slice; -- if (node->v.Subscript.ctx != Load || -- arg->kind != Constant_kind || -- idx->kind != Constant_kind) -- { -- return 1; -- } -- -- newval = PyObject_GetItem(arg->v.Constant.value, idx->v.Constant.value); -- return make_const(node, newval, arena); --} -- - /* Change literal list or set of constants into constant - tuple or frozenset respectively. Change literal list of - non-constants into tuple. -@@ -822,7 +803,6 @@ - case Subscript_kind: - CALL(astfold_expr, expr_ty, node_->v.Subscript.value); - CALL(astfold_expr, expr_ty, node_->v.Subscript.slice); -- CALL(fold_subscr, expr_ty, node_); - break; - case Starred_kind: - CALL(astfold_expr, expr_ty, node_->v.Starred.value); -diff --git a/Python/ast_unparse.c b/Python/ast_unparse.c -index 8017cfc7fcf..f3c669c33eb 100644 ---- a/Python/ast_unparse.c -+++ b/Python/ast_unparse.c -@@ -16,24 +16,40 @@ - static PyObject * - expr_as_unicode(expr_ty e, int level); - static int --append_ast_expr(_PyUnicodeWriter *writer, expr_ty e, int level); -+append_ast_expr(PyUnicodeWriter *writer, expr_ty e, int level); - static int --append_joinedstr(_PyUnicodeWriter *writer, expr_ty e, bool is_format_spec); -+append_joinedstr(PyUnicodeWriter *writer, expr_ty e, bool is_format_spec); - static int --append_formattedvalue(_PyUnicodeWriter *writer, expr_ty e); -+append_formattedvalue(PyUnicodeWriter *writer, expr_ty e); - static int --append_ast_slice(_PyUnicodeWriter *writer, expr_ty e); -+append_ast_slice(PyUnicodeWriter *writer, expr_ty e); - - static int --append_charp(_PyUnicodeWriter *writer, const char *charp) -+append_char(PyUnicodeWriter *writer, Py_UCS4 ch) - { -- return _PyUnicodeWriter_WriteASCIIString(writer, charp, -1); -+ return PyUnicodeWriter_WriteChar(writer, ch); - } - -+static int -+append_charp(PyUnicodeWriter *writer, const char *charp) -+{ -+ return PyUnicodeWriter_WriteUTF8(writer, charp, -1); -+} -+ -+#define APPEND_CHAR_FINISH(ch) do { \ -+ return append_char(writer, (ch)); \ -+ } while (0) -+ - #define APPEND_STR_FINISH(str) do { \ - return append_charp(writer, (str)); \ - } while (0) - -+#define APPEND_CHAR(ch) do { \ -+ if (-1 == append_char(writer, (ch))) { \ -+ return -1; \ -+ } \ -+ } while (0) -+ - #define APPEND_STR(str) do { \ - if (-1 == append_charp(writer, (str))) { \ - return -1; \ -@@ -64,10 +80,9 @@ - } while (0) - - static int --append_repr(_PyUnicodeWriter *writer, PyObject *obj) -+append_repr(PyUnicodeWriter *writer, PyObject *obj) - { - PyObject *repr = PyObject_Repr(obj); -- - if (!repr) { - return -1; - } -@@ -88,7 +103,8 @@ - } - repr = new_repr; - } -- int ret = _PyUnicodeWriter_WriteStr(writer, repr); -+ -+ int ret = PyUnicodeWriter_WriteStr(writer, repr); - Py_DECREF(repr); - return ret; - } -@@ -117,7 +133,7 @@ - }; - - static int --append_ast_boolop(_PyUnicodeWriter *writer, expr_ty e, int level) -+append_ast_boolop(PyUnicodeWriter *writer, expr_ty e, int level) - { - Py_ssize_t i, value_count; - asdl_expr_seq *values; -@@ -139,7 +155,7 @@ - } - - static int --append_ast_binop(_PyUnicodeWriter *writer, expr_ty e, int level) -+append_ast_binop(PyUnicodeWriter *writer, expr_ty e, int level) - { - const char *op; - int pr; -@@ -174,7 +190,7 @@ - } - - static int --append_ast_unaryop(_PyUnicodeWriter *writer, expr_ty e, int level) -+append_ast_unaryop(PyUnicodeWriter *writer, expr_ty e, int level) - { - const char *op; - int pr; -@@ -198,9 +214,9 @@ - } - - static int --append_ast_arg(_PyUnicodeWriter *writer, arg_ty arg) -+append_ast_arg(PyUnicodeWriter *writer, arg_ty arg) - { -- if (-1 == _PyUnicodeWriter_WriteStr(writer, arg->arg)) { -+ if (PyUnicodeWriter_WriteStr(writer, arg->arg) < 0) { - return -1; - } - if (arg->annotation) { -@@ -211,7 +227,7 @@ - } - - static int --append_ast_args(_PyUnicodeWriter *writer, arguments_ty args) -+append_ast_args(PyUnicodeWriter *writer, arguments_ty args) - { - bool first; - Py_ssize_t i, di, arg_count, posonlyarg_count, default_count; -@@ -232,7 +248,7 @@ - - di = i - posonlyarg_count - arg_count + default_count; - if (di >= 0) { -- APPEND_STR("="); -+ APPEND_CHAR('='); - APPEND_EXPR((expr_ty)asdl_seq_GET(args->defaults, di), PR_TEST); - } - if (posonlyarg_count && i + 1 == posonlyarg_count) { -@@ -260,7 +276,7 @@ - if (di >= 0) { - expr_ty default_ = (expr_ty)asdl_seq_GET(args->kw_defaults, di); - if (default_) { -- APPEND_STR("="); -+ APPEND_CHAR('='); - APPEND_EXPR(default_, PR_TEST); - } - } -@@ -277,7 +293,7 @@ - } - - static int --append_ast_lambda(_PyUnicodeWriter *writer, expr_ty e, int level) -+append_ast_lambda(PyUnicodeWriter *writer, expr_ty e, int level) - { - APPEND_STR_IF(level > PR_TEST, "("); - Py_ssize_t n_positional = (asdl_seq_LEN(e->v.Lambda.args->args) + -@@ -291,7 +307,7 @@ - } - - static int --append_ast_ifexp(_PyUnicodeWriter *writer, expr_ty e, int level) -+append_ast_ifexp(PyUnicodeWriter *writer, expr_ty e, int level) - { - APPEND_STR_IF(level > PR_TEST, "("); - APPEND_EXPR(e->v.IfExp.body, PR_TEST + 1); -@@ -304,12 +320,12 @@ - } - - static int --append_ast_dict(_PyUnicodeWriter *writer, expr_ty e) -+append_ast_dict(PyUnicodeWriter *writer, expr_ty e) - { - Py_ssize_t i, value_count; - expr_ty key_node; - -- APPEND_STR("{"); -+ APPEND_CHAR('{'); - value_count = asdl_seq_LEN(e->v.Dict.values); - - for (i = 0; i < value_count; i++) { -@@ -326,41 +342,41 @@ - } - } - -- APPEND_STR_FINISH("}"); -+ APPEND_CHAR_FINISH('}'); - } - - static int --append_ast_set(_PyUnicodeWriter *writer, expr_ty e) -+append_ast_set(PyUnicodeWriter *writer, expr_ty e) - { - Py_ssize_t i, elem_count; - -- APPEND_STR("{"); -+ APPEND_CHAR('{'); - elem_count = asdl_seq_LEN(e->v.Set.elts); - for (i = 0; i < elem_count; i++) { - APPEND_STR_IF(i > 0, ", "); - APPEND_EXPR((expr_ty)asdl_seq_GET(e->v.Set.elts, i), PR_TEST); - } - -- APPEND_STR_FINISH("}"); -+ APPEND_CHAR_FINISH('}'); - } - - static int --append_ast_list(_PyUnicodeWriter *writer, expr_ty e) -+append_ast_list(PyUnicodeWriter *writer, expr_ty e) - { - Py_ssize_t i, elem_count; - -- APPEND_STR("["); -+ APPEND_CHAR('['); - elem_count = asdl_seq_LEN(e->v.List.elts); - for (i = 0; i < elem_count; i++) { - APPEND_STR_IF(i > 0, ", "); - APPEND_EXPR((expr_ty)asdl_seq_GET(e->v.List.elts, i), PR_TEST); - } - -- APPEND_STR_FINISH("]"); -+ APPEND_CHAR_FINISH(']'); - } - - static int --append_ast_tuple(_PyUnicodeWriter *writer, expr_ty e, int level) -+append_ast_tuple(PyUnicodeWriter *writer, expr_ty e, int level) - { - Py_ssize_t i, elem_count; - -@@ -383,7 +399,7 @@ - } - - static int --append_ast_comprehension(_PyUnicodeWriter *writer, comprehension_ty gen) -+append_ast_comprehension(PyUnicodeWriter *writer, comprehension_ty gen) - { - Py_ssize_t i, if_count; - -@@ -401,7 +417,7 @@ - } - - static int --append_ast_comprehensions(_PyUnicodeWriter *writer, asdl_comprehension_seq *comprehensions) -+append_ast_comprehensions(PyUnicodeWriter *writer, asdl_comprehension_seq *comprehensions) - { - Py_ssize_t i, gen_count; - gen_count = asdl_seq_LEN(comprehensions); -@@ -414,45 +430,45 @@ - } - - static int --append_ast_genexp(_PyUnicodeWriter *writer, expr_ty e) -+append_ast_genexp(PyUnicodeWriter *writer, expr_ty e) - { -- APPEND_STR("("); -+ APPEND_CHAR('('); - APPEND_EXPR(e->v.GeneratorExp.elt, PR_TEST); - APPEND(comprehensions, e->v.GeneratorExp.generators); -- APPEND_STR_FINISH(")"); -+ APPEND_CHAR_FINISH(')'); - } - - static int --append_ast_listcomp(_PyUnicodeWriter *writer, expr_ty e) -+append_ast_listcomp(PyUnicodeWriter *writer, expr_ty e) - { -- APPEND_STR("["); -+ APPEND_CHAR('['); - APPEND_EXPR(e->v.ListComp.elt, PR_TEST); - APPEND(comprehensions, e->v.ListComp.generators); -- APPEND_STR_FINISH("]"); -+ APPEND_CHAR_FINISH(']'); - } - - static int --append_ast_setcomp(_PyUnicodeWriter *writer, expr_ty e) -+append_ast_setcomp(PyUnicodeWriter *writer, expr_ty e) - { -- APPEND_STR("{"); -+ APPEND_CHAR('{'); - APPEND_EXPR(e->v.SetComp.elt, PR_TEST); - APPEND(comprehensions, e->v.SetComp.generators); -- APPEND_STR_FINISH("}"); -+ APPEND_CHAR_FINISH('}'); - } - - static int --append_ast_dictcomp(_PyUnicodeWriter *writer, expr_ty e) -+append_ast_dictcomp(PyUnicodeWriter *writer, expr_ty e) - { -- APPEND_STR("{"); -+ APPEND_CHAR('{'); - APPEND_EXPR(e->v.DictComp.key, PR_TEST); - APPEND_STR(": "); - APPEND_EXPR(e->v.DictComp.value, PR_TEST); - APPEND(comprehensions, e->v.DictComp.generators); -- APPEND_STR_FINISH("}"); -+ APPEND_CHAR_FINISH('}'); - } - - static int --append_ast_compare(_PyUnicodeWriter *writer, expr_ty e, int level) -+append_ast_compare(PyUnicodeWriter *writer, expr_ty e, int level) - { - const char *op; - Py_ssize_t i, comparator_count; -@@ -516,17 +532,17 @@ - } - - static int --append_ast_keyword(_PyUnicodeWriter *writer, keyword_ty kw) -+append_ast_keyword(PyUnicodeWriter *writer, keyword_ty kw) - { - if (kw->arg == NULL) { - APPEND_STR("**"); - } - else { -- if (-1 == _PyUnicodeWriter_WriteStr(writer, kw->arg)) { -+ if (-1 == PyUnicodeWriter_WriteStr(writer, kw->arg)) { - return -1; - } - -- APPEND_STR("="); -+ APPEND_CHAR('='); - } - - APPEND_EXPR(kw->value, PR_TEST); -@@ -534,7 +550,7 @@ - } - - static int --append_ast_call(_PyUnicodeWriter *writer, expr_ty e) -+append_ast_call(PyUnicodeWriter *writer, expr_ty e) - { - bool first; - Py_ssize_t i, arg_count, kw_count; -@@ -552,7 +568,7 @@ - } - } - -- APPEND_STR("("); -+ APPEND_CHAR('('); - - first = true; - for (i = 0; i < arg_count; i++) { -@@ -565,7 +581,7 @@ - APPEND(keyword, (keyword_ty)asdl_seq_GET(e->v.Call.keywords, i)); - } - -- APPEND_STR_FINISH(")"); -+ APPEND_CHAR_FINISH(')'); - } - - static PyObject * -@@ -585,20 +601,20 @@ - } - - static int --append_fstring_unicode(_PyUnicodeWriter *writer, PyObject *unicode) -+append_fstring_unicode(PyUnicodeWriter *writer, PyObject *unicode) - { - PyObject *escaped; - int result = -1; - escaped = escape_braces(unicode); - if (escaped) { -- result = _PyUnicodeWriter_WriteStr(writer, escaped); -+ result = PyUnicodeWriter_WriteStr(writer, escaped); - Py_DECREF(escaped); - } - return result; - } - - static int --append_fstring_element(_PyUnicodeWriter *writer, expr_ty e, bool is_format_spec) -+append_fstring_element(PyUnicodeWriter *writer, expr_ty e, bool is_format_spec) - { - switch (e->kind) { - case Constant_kind: -@@ -619,28 +635,27 @@ - static PyObject * - build_fstring_body(asdl_expr_seq *values, bool is_format_spec) - { -- Py_ssize_t i, value_count; -- _PyUnicodeWriter body_writer; -- _PyUnicodeWriter_Init(&body_writer); -- body_writer.min_length = 256; -- body_writer.overallocate = 1; -+ PyUnicodeWriter *body_writer = PyUnicodeWriter_Create(256); -+ if (body_writer == NULL) { -+ return NULL; -+ } - -- value_count = asdl_seq_LEN(values); -- for (i = 0; i < value_count; ++i) { -- if (-1 == append_fstring_element(&body_writer, -+ Py_ssize_t value_count = asdl_seq_LEN(values); -+ for (Py_ssize_t i = 0; i < value_count; ++i) { -+ if (-1 == append_fstring_element(body_writer, - (expr_ty)asdl_seq_GET(values, i), - is_format_spec - )) { -- _PyUnicodeWriter_Dealloc(&body_writer); -+ PyUnicodeWriter_Discard(body_writer); - return NULL; - } - } - -- return _PyUnicodeWriter_Finish(&body_writer); -+ return PyUnicodeWriter_Finish(body_writer); - } - - static int --append_joinedstr(_PyUnicodeWriter *writer, expr_ty e, bool is_format_spec) -+append_joinedstr(PyUnicodeWriter *writer, expr_ty e, bool is_format_spec) - { - int result = -1; - PyObject *body = build_fstring_body(e->v.JoinedStr.values, is_format_spec); -@@ -656,14 +671,14 @@ - } - } - else { -- result = _PyUnicodeWriter_WriteStr(writer, body); -+ result = PyUnicodeWriter_WriteStr(writer, body); - } - Py_DECREF(body); - return result; - } - - static int --append_formattedvalue(_PyUnicodeWriter *writer, expr_ty e) -+append_formattedvalue(PyUnicodeWriter *writer, expr_ty e) - { - const char *conversion; - const char *outer_brace = "{"; -@@ -682,7 +697,7 @@ - Py_DECREF(temp_fv_str); - return -1; - } -- if (-1 == _PyUnicodeWriter_WriteStr(writer, temp_fv_str)) { -+ if (-1 == PyUnicodeWriter_WriteStr(writer, temp_fv_str)) { - Py_DECREF(temp_fv_str); - return -1; - } -@@ -707,7 +722,7 @@ - APPEND_STR(conversion); - } - if (e->v.FormattedValue.format_spec) { -- if (-1 == _PyUnicodeWriter_WriteASCIIString(writer, ":", 1) || -+ if (-1 == PyUnicodeWriter_WriteChar(writer, ':') || - -1 == append_fstring_element(writer, - e->v.FormattedValue.format_spec, - true -@@ -717,17 +732,17 @@ - } - } - -- APPEND_STR_FINISH("}"); -+ APPEND_CHAR_FINISH('}'); - } - - static int --append_ast_constant(_PyUnicodeWriter *writer, PyObject *constant) -+append_ast_constant(PyUnicodeWriter *writer, PyObject *constant) - { - if (PyTuple_CheckExact(constant)) { - Py_ssize_t i, elem_count; - - elem_count = PyTuple_GET_SIZE(constant); -- APPEND_STR("("); -+ APPEND_CHAR('('); - for (i = 0; i < elem_count; i++) { - APPEND_STR_IF(i > 0, ", "); - if (append_ast_constant(writer, PyTuple_GET_ITEM(constant, i)) < 0) { -@@ -736,14 +751,13 @@ - } - - APPEND_STR_IF(elem_count == 1, ","); -- APPEND_STR(")"); -- return 0; -+ APPEND_CHAR_FINISH(')'); - } - return append_repr(writer, constant); - } - - static int --append_ast_attribute(_PyUnicodeWriter *writer, expr_ty e) -+append_ast_attribute(PyUnicodeWriter *writer, expr_ty e) - { - const char *period; - expr_ty v = e->v.Attribute.value; -@@ -759,48 +773,48 @@ - } - APPEND_STR(period); - -- return _PyUnicodeWriter_WriteStr(writer, e->v.Attribute.attr); -+ return PyUnicodeWriter_WriteStr(writer, e->v.Attribute.attr); - } - - static int --append_ast_slice(_PyUnicodeWriter *writer, expr_ty e) -+append_ast_slice(PyUnicodeWriter *writer, expr_ty e) - { - if (e->v.Slice.lower) { - APPEND_EXPR(e->v.Slice.lower, PR_TEST); - } - -- APPEND_STR(":"); -+ APPEND_CHAR(':'); - - if (e->v.Slice.upper) { - APPEND_EXPR(e->v.Slice.upper, PR_TEST); - } - - if (e->v.Slice.step) { -- APPEND_STR(":"); -+ APPEND_CHAR(':'); - APPEND_EXPR(e->v.Slice.step, PR_TEST); - } - return 0; - } - - static int --append_ast_subscript(_PyUnicodeWriter *writer, expr_ty e) -+append_ast_subscript(PyUnicodeWriter *writer, expr_ty e) - { - APPEND_EXPR(e->v.Subscript.value, PR_ATOM); -- APPEND_STR("["); -+ APPEND_CHAR('['); - APPEND_EXPR(e->v.Subscript.slice, PR_TUPLE); -- APPEND_STR_FINISH("]"); -+ APPEND_CHAR_FINISH(']'); - } - - static int --append_ast_starred(_PyUnicodeWriter *writer, expr_ty e) -+append_ast_starred(PyUnicodeWriter *writer, expr_ty e) - { -- APPEND_STR("*"); -+ APPEND_CHAR('*'); - APPEND_EXPR(e->v.Starred.value, PR_EXPR); - return 0; - } - - static int --append_ast_yield(_PyUnicodeWriter *writer, expr_ty e) -+append_ast_yield(PyUnicodeWriter *writer, expr_ty e) - { - if (!e->v.Yield.value) { - APPEND_STR_FINISH("(yield)"); -@@ -808,19 +822,19 @@ - - APPEND_STR("(yield "); - APPEND_EXPR(e->v.Yield.value, PR_TEST); -- APPEND_STR_FINISH(")"); -+ APPEND_CHAR_FINISH(')'); - } - - static int --append_ast_yield_from(_PyUnicodeWriter *writer, expr_ty e) -+append_ast_yield_from(PyUnicodeWriter *writer, expr_ty e) - { - APPEND_STR("(yield from "); - APPEND_EXPR(e->v.YieldFrom.value, PR_TEST); -- APPEND_STR_FINISH(")"); -+ APPEND_CHAR_FINISH(')'); - } - - static int --append_ast_await(_PyUnicodeWriter *writer, expr_ty e, int level) -+append_ast_await(PyUnicodeWriter *writer, expr_ty e, int level) - { - APPEND_STR_IF(level > PR_AWAIT, "("); - APPEND_STR("await "); -@@ -830,7 +844,7 @@ - } - - static int --append_named_expr(_PyUnicodeWriter *writer, expr_ty e, int level) -+append_named_expr(PyUnicodeWriter *writer, expr_ty e, int level) - { - APPEND_STR_IF(level > PR_TUPLE, "("); - APPEND_EXPR(e->v.NamedExpr.target, PR_ATOM); -@@ -841,7 +855,7 @@ - } - - static int --append_ast_expr(_PyUnicodeWriter *writer, expr_ty e, int level) -+append_ast_expr(PyUnicodeWriter *writer, expr_ty e, int level) - { - switch (e->kind) { - case BoolOp_kind: -@@ -881,7 +895,7 @@ - APPEND_STR_FINISH("..."); - } - if (e->v.Constant.kind != NULL -- && -1 == _PyUnicodeWriter_WriteStr(writer, e->v.Constant.kind)) { -+ && -1 == PyUnicodeWriter_WriteStr(writer, e->v.Constant.kind)) { - return -1; - } - return append_ast_constant(writer, e->v.Constant.value); -@@ -899,7 +913,7 @@ - case Slice_kind: - return append_ast_slice(writer, e); - case Name_kind: -- return _PyUnicodeWriter_WriteStr(writer, e->v.Name.id); -+ return PyUnicodeWriter_WriteStr(writer, e->v.Name.id); - case List_kind: - return append_ast_list(writer, e); - case Tuple_kind: -@@ -916,15 +930,16 @@ - static PyObject * - expr_as_unicode(expr_ty e, int level) - { -- _PyUnicodeWriter writer; -- _PyUnicodeWriter_Init(&writer); -- writer.min_length = 256; -- writer.overallocate = 1; -- if (-1 == append_ast_expr(&writer, e, level)) { -- _PyUnicodeWriter_Dealloc(&writer); -+ PyUnicodeWriter *writer = PyUnicodeWriter_Create(256); -+ if (writer == NULL) { -+ return NULL; -+ } -+ -+ if (-1 == append_ast_expr(writer, e, level)) { -+ PyUnicodeWriter_Discard(writer); - return NULL; - } -- return _PyUnicodeWriter_Finish(&writer); -+ return PyUnicodeWriter_Finish(writer); - } - - PyObject * -diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c -index fb9868b3740..46a6fd9a8ef 100644 ---- a/Python/bltinmodule.c -+++ b/Python/bltinmodule.c -@@ -494,6 +494,8 @@ - PyObject *it; - } filterobject; - -+#define _filterobject_CAST(op) ((filterobject *)(op)) -+ - static PyObject * - filter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) - { -@@ -559,8 +561,9 @@ - } - - static void --filter_dealloc(filterobject *lz) -+filter_dealloc(PyObject *self) - { -+ filterobject *lz = _filterobject_CAST(self); - PyObject_GC_UnTrack(lz); - Py_TRASHCAN_BEGIN(lz, filter_dealloc) - Py_XDECREF(lz->func); -@@ -570,16 +573,18 @@ - } - - static int --filter_traverse(filterobject *lz, visitproc visit, void *arg) -+filter_traverse(PyObject *self, visitproc visit, void *arg) - { -+ filterobject *lz = _filterobject_CAST(self); - Py_VISIT(lz->it); - Py_VISIT(lz->func); - return 0; - } - - static PyObject * --filter_next(filterobject *lz) -+filter_next(PyObject *self) - { -+ filterobject *lz = _filterobject_CAST(self); - PyObject *item; - PyObject *it = lz->it; - long ok; -@@ -613,15 +618,16 @@ - } - - static PyObject * --filter_reduce(filterobject *lz, PyObject *Py_UNUSED(ignored)) -+filter_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -+ filterobject *lz = _filterobject_CAST(self); - return Py_BuildValue("O(OO)", Py_TYPE(lz), lz->func, lz->it); - } - - PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); - - static PyMethodDef filter_methods[] = { -- {"__reduce__", _PyCFunction_CAST(filter_reduce), METH_NOARGS, reduce_doc}, -+ {"__reduce__", filter_reduce, METH_NOARGS, reduce_doc}, - {NULL, NULL} /* sentinel */ - }; - -@@ -638,7 +644,7 @@ - sizeof(filterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ -- (destructor)filter_dealloc, /* tp_dealloc */ -+ filter_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ -@@ -656,12 +662,12 @@ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - filter_doc, /* tp_doc */ -- (traverseproc)filter_traverse, /* tp_traverse */ -+ filter_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ -- (iternextfunc)filter_next, /* tp_iternext */ -+ filter_next, /* tp_iternext */ - filter_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ -@@ -674,7 +680,7 @@ - PyType_GenericAlloc, /* tp_alloc */ - filter_new, /* tp_new */ - PyObject_GC_Del, /* tp_free */ -- .tp_vectorcall = (vectorcallfunc)filter_vectorcall -+ .tp_vectorcall = filter_vectorcall - }; - - -@@ -1319,6 +1325,8 @@ - int strict; - } mapobject; - -+#define _mapobject_CAST(op) ((mapobject *)(op)) -+ - static PyObject * - map_new(PyTypeObject *type, PyObject *args, PyObject *kwds) - { -@@ -1422,8 +1430,9 @@ - } - - static void --map_dealloc(mapobject *lz) -+map_dealloc(PyObject *self) - { -+ mapobject *lz = _mapobject_CAST(self); - PyObject_GC_UnTrack(lz); - Py_XDECREF(lz->iters); - Py_XDECREF(lz->func); -@@ -1431,16 +1440,18 @@ - } - - static int --map_traverse(mapobject *lz, visitproc visit, void *arg) -+map_traverse(PyObject *self, visitproc visit, void *arg) - { -+ mapobject *lz = _mapobject_CAST(self); - Py_VISIT(lz->iters); - Py_VISIT(lz->func); - return 0; - } - - static PyObject * --map_next(mapobject *lz) -+map_next(PyObject *self) - { -+ mapobject *lz = _mapobject_CAST(self); - Py_ssize_t i; - PyObject *small_stack[_PY_FASTCALL_SMALL_STACK]; - PyObject **stack; -@@ -1523,8 +1534,9 @@ - } - - static PyObject * --map_reduce(mapobject *lz, PyObject *Py_UNUSED(ignored)) -+map_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -+ mapobject *lz = _mapobject_CAST(self); - Py_ssize_t numargs = PyTuple_GET_SIZE(lz->iters); - PyObject *args = PyTuple_New(numargs+1); - Py_ssize_t i; -@@ -1545,19 +1557,20 @@ - PyDoc_STRVAR(setstate_doc, "Set state information for unpickling."); - - static PyObject * --map_setstate(mapobject *lz, PyObject *state) -+map_setstate(PyObject *self, PyObject *state) - { - int strict = PyObject_IsTrue(state); - if (strict < 0) { - return NULL; - } -+ mapobject *lz = _mapobject_CAST(self); - lz->strict = strict; - Py_RETURN_NONE; - } - - static PyMethodDef map_methods[] = { -- {"__reduce__", _PyCFunction_CAST(map_reduce), METH_NOARGS, reduce_doc}, -- {"__setstate__", _PyCFunction_CAST(map_setstate), METH_O, setstate_doc}, -+ {"__reduce__", map_reduce, METH_NOARGS, reduce_doc}, -+ {"__setstate__", map_setstate, METH_O, setstate_doc}, - {NULL, NULL} /* sentinel */ - }; - -@@ -1578,7 +1591,7 @@ - sizeof(mapobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ -- (destructor)map_dealloc, /* tp_dealloc */ -+ map_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ -@@ -1596,12 +1609,12 @@ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - map_doc, /* tp_doc */ -- (traverseproc)map_traverse, /* tp_traverse */ -+ map_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ -- (iternextfunc)map_next, /* tp_iternext */ -+ map_next, /* tp_iternext */ - map_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ -@@ -1614,7 +1627,7 @@ - PyType_GenericAlloc, /* tp_alloc */ - map_new, /* tp_new */ - PyObject_GC_Del, /* tp_free */ -- .tp_vectorcall = (vectorcallfunc)map_vectorcall -+ .tp_vectorcall = map_vectorcall - }; - - -@@ -2965,6 +2978,8 @@ - int strict; - } zipobject; - -+#define _zipobject_CAST(op) ((zipobject *)(op)) -+ - static PyObject * - zip_new(PyTypeObject *type, PyObject *args, PyObject *kwds) - { -@@ -3033,8 +3048,9 @@ - } - - static void --zip_dealloc(zipobject *lz) -+zip_dealloc(PyObject *self) - { -+ zipobject *lz = _zipobject_CAST(self); - PyObject_GC_UnTrack(lz); - Py_XDECREF(lz->ittuple); - Py_XDECREF(lz->result); -@@ -3042,16 +3058,19 @@ - } - - static int --zip_traverse(zipobject *lz, visitproc visit, void *arg) -+zip_traverse(PyObject *self, visitproc visit, void *arg) - { -+ zipobject *lz = _zipobject_CAST(self); - Py_VISIT(lz->ittuple); - Py_VISIT(lz->result); - return 0; - } - - static PyObject * --zip_next(zipobject *lz) -+zip_next(PyObject *self) - { -+ zipobject *lz = _zipobject_CAST(self); -+ - Py_ssize_t i; - Py_ssize_t tuplesize = lz->tuplesize; - PyObject *result = lz->result; -@@ -3141,8 +3160,9 @@ - } - - static PyObject * --zip_reduce(zipobject *lz, PyObject *Py_UNUSED(ignored)) -+zip_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -+ zipobject *lz = _zipobject_CAST(self); - /* Just recreate the zip with the internal iterator tuple */ - if (lz->strict) { - return PyTuple_Pack(3, Py_TYPE(lz), lz->ittuple, Py_True); -@@ -3151,19 +3171,20 @@ - } - - static PyObject * --zip_setstate(zipobject *lz, PyObject *state) -+zip_setstate(PyObject *self, PyObject *state) - { - int strict = PyObject_IsTrue(state); - if (strict < 0) { - return NULL; - } -+ zipobject *lz = _zipobject_CAST(self); - lz->strict = strict; - Py_RETURN_NONE; - } - - static PyMethodDef zip_methods[] = { -- {"__reduce__", _PyCFunction_CAST(zip_reduce), METH_NOARGS, reduce_doc}, -- {"__setstate__", _PyCFunction_CAST(zip_setstate), METH_O, setstate_doc}, -+ {"__reduce__", zip_reduce, METH_NOARGS, reduce_doc}, -+ {"__setstate__", zip_setstate, METH_O, setstate_doc}, - {NULL} /* sentinel */ - }; - -@@ -3188,7 +3209,7 @@ - sizeof(zipobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ -- (destructor)zip_dealloc, /* tp_dealloc */ -+ zip_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ -@@ -3206,12 +3227,12 @@ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - zip_doc, /* tp_doc */ -- (traverseproc)zip_traverse, /* tp_traverse */ -+ zip_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ -- (iternextfunc)zip_next, /* tp_iternext */ -+ zip_next, /* tp_iternext */ - zip_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ -diff --git a/Python/bytecodes.c b/Python/bytecodes.c -index 772b46d17ec..703d7ec61eb 100644 ---- a/Python/bytecodes.c -+++ b/Python/bytecodes.c -@@ -45,7 +45,6 @@ - #include "ceval_macros.h" - - /* Flow control macros */ --#define GO_TO_INSTRUCTION(instname) ((void)0) - - #define inst(name, ...) case name: - #define op(name, ...) /* NAME is ignored */ -@@ -53,6 +52,7 @@ - #define super(name) static int SUPER_##name - #define family(name, ...) static int family_##name - #define pseudo(name) static int pseudo_##name -+#define label(name) name: - - /* Annotations */ - #define guard -@@ -60,6 +60,8 @@ - #define specializing - #define split - #define replicate(TIMES) -+#define tier1 -+#define no_save_ip - - // Dummy variables for stack effects. - static PyObject *value, *value1, *value2, *left, *right, *res, *sum, *prod, *sub; -@@ -101,7 +103,6 @@ - PyObject *codeobj; - PyObject *cond; - PyObject *descr; -- _PyInterpreterFrame entry_frame; - PyObject *exc; - PyObject *exit; - PyObject *fget; -@@ -148,6 +149,8 @@ - RESUME_CHECK, - }; - -+ macro(NOT_TAKEN) = NOP; -+ - op(_CHECK_PERIODIC, (--)) { - _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); -@@ -269,7 +272,6 @@ - - inst(LOAD_FAST_AND_CLEAR, (-- value)) { - value = GETLOCAL(oparg); -- // do not use SETLOCAL here, it decrefs the old value - GETLOCAL(oparg) = PyStackRef_NULL; - } - -@@ -281,11 +283,35 @@ - } - - family(LOAD_CONST, 0) = { -+ LOAD_CONST_MORTAL, - LOAD_CONST_IMMORTAL, - }; - -- pure inst(LOAD_CONST, (-- value)) { -- value = PyStackRef_FromPyObjectNew(GETITEM(FRAME_CO_CONSTS, oparg)); -+ inst(LOAD_CONST, (-- value)) { -+ /* We can't do this in the bytecode compiler as -+ * marshalling can intern strings and make them immortal. */ -+ PyObject *obj = GETITEM(FRAME_CO_CONSTS, oparg); -+ value = PyStackRef_FromPyObjectNew(obj); -+#if ENABLE_SPECIALIZATION_FT -+#ifdef Py_GIL_DISABLED -+ uint8_t expected = LOAD_CONST; -+ if (!_Py_atomic_compare_exchange_uint8( -+ &this_instr->op.code, &expected, -+ _Py_IsImmortal(obj) ? LOAD_CONST_IMMORTAL : LOAD_CONST_MORTAL)) { -+ // We might lose a race with instrumentation, which we don't care about. -+ assert(expected >= MIN_INSTRUMENTED_OPCODE); -+ } -+#else -+ if (this_instr->op.code == LOAD_CONST) { -+ this_instr->op.code = _Py_IsImmortal(obj) ? LOAD_CONST_IMMORTAL : LOAD_CONST_MORTAL; -+ } -+#endif -+#endif -+ } -+ -+ inst(LOAD_CONST_MORTAL, (-- value)) { -+ PyObject *obj = GETITEM(FRAME_CO_CONSTS, oparg); -+ value = PyStackRef_FromPyObjectNew(obj); - } - - inst(LOAD_CONST_IMMORTAL, (-- value)) { -@@ -301,8 +327,10 @@ - } - - replicate(8) inst(STORE_FAST, (value --)) { -- SETLOCAL(oparg, value); -+ _PyStackRef tmp = GETLOCAL(oparg); -+ GETLOCAL(oparg) = value; - DEAD(value); -+ PyStackRef_XCLOSE(tmp); - } - - pseudo(STORE_FAST_MAYBE_NULL, (unused --)) = { -@@ -312,18 +340,24 @@ - inst(STORE_FAST_LOAD_FAST, (value1 -- value2)) { - uint32_t oparg1 = oparg >> 4; - uint32_t oparg2 = oparg & 15; -- SETLOCAL(oparg1, value1); -+ _PyStackRef tmp = GETLOCAL(oparg1); -+ GETLOCAL(oparg1) = value1; - DEAD(value1); - value2 = PyStackRef_DUP(GETLOCAL(oparg2)); -+ PyStackRef_XCLOSE(tmp); - } - - inst(STORE_FAST_STORE_FAST, (value2, value1 --)) { - uint32_t oparg1 = oparg >> 4; - uint32_t oparg2 = oparg & 15; -- SETLOCAL(oparg1, value1); -+ _PyStackRef tmp = GETLOCAL(oparg1); -+ GETLOCAL(oparg1) = value1; - DEAD(value1); -- SETLOCAL(oparg2, value2); -+ PyStackRef_XCLOSE(tmp); -+ tmp = GETLOCAL(oparg2); -+ GETLOCAL(oparg2) = value2; - DEAD(value2); -+ PyStackRef_XCLOSE(tmp); - } - - pure inst(POP_TOP, (value --)) { -@@ -334,9 +368,18 @@ - res = PyStackRef_NULL; - } - -- macro(END_FOR) = POP_TOP; -+ no_save_ip inst(END_FOR, (value -- )) { -+ /* Don't update instr_ptr, so that POP_ITER sees -+ * the FOR_ITER as the previous instruction. -+ * This has the benign side effect that if value is -+ * finalized it will see the location as the FOR_ITER's. -+ */ -+ PyStackRef_CLOSE(value); -+ } -+ -+ macro(POP_ITER) = POP_TOP; - -- tier1 inst(INSTRUMENTED_END_FOR, (receiver, value -- receiver)) { -+ no_save_ip tier1 inst(INSTRUMENTED_END_FOR, (receiver, value -- receiver)) { - /* Need to create a fake StopIteration error here, - * to conform to PEP 380 */ - if (PyStackRef_GenCheck(receiver)) { -@@ -348,11 +391,16 @@ - DECREF_INPUTS(); - } - -+ tier1 inst(INSTRUMENTED_POP_ITER, (iter -- )) { -+ INSTRUMENTED_JUMP(prev_instr, this_instr+1, PY_MONITORING_EVENT_BRANCH_RIGHT); -+ PyStackRef_CLOSE(iter); -+ } -+ - pure inst(END_SEND, (receiver, value -- val)) { - (void)receiver; - val = value; - DEAD(value); -- PyStackRef_CLOSE(receiver); -+ DECREF_INPUTS(); - } - - tier1 inst(INSTRUMENTED_END_SEND, (receiver, value -- val)) { -@@ -489,7 +537,13 @@ - BINARY_OP_ADD_FLOAT, - BINARY_OP_SUBTRACT_FLOAT, - BINARY_OP_ADD_UNICODE, -+ BINARY_OP_SUBSCR_LIST_INT, -+ BINARY_OP_SUBSCR_TUPLE_INT, -+ BINARY_OP_SUBSCR_STR_INT, -+ BINARY_OP_SUBSCR_DICT, -+ BINARY_OP_SUBSCR_GETITEM, - // BINARY_OP_INPLACE_ADD_UNICODE, // See comments at that opcode. -+ BINARY_OP_EXTEND, - }; - - op(_GUARD_BOTH_INT, (left, right -- left, right)) { -@@ -512,6 +566,8 @@ - pure op(_BINARY_OP_MULTIPLY_INT, (left, right -- res)) { - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(PyLong_CheckExact(left_o)); -+ assert(PyLong_CheckExact(right_o)); - - STAT_INC(BINARY_OP, hit); - PyObject *res_o = _PyLong_Multiply((PyLongObject *)left_o, (PyLongObject *)right_o); -@@ -525,6 +581,8 @@ - pure op(_BINARY_OP_ADD_INT, (left, right -- res)) { - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(PyLong_CheckExact(left_o)); -+ assert(PyLong_CheckExact(right_o)); - - STAT_INC(BINARY_OP, hit); - PyObject *res_o = _PyLong_Add((PyLongObject *)left_o, (PyLongObject *)right_o); -@@ -538,6 +596,8 @@ - pure op(_BINARY_OP_SUBTRACT_INT, (left, right -- res)) { - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(PyLong_CheckExact(left_o)); -+ assert(PyLong_CheckExact(right_o)); - - STAT_INC(BINARY_OP, hit); - PyObject *res_o = _PyLong_Subtract((PyLongObject *)left_o, (PyLongObject *)right_o); -@@ -549,11 +609,11 @@ - } - - macro(BINARY_OP_MULTIPLY_INT) = -- _GUARD_BOTH_INT + unused/1 + _BINARY_OP_MULTIPLY_INT; -+ _GUARD_BOTH_INT + unused/5 + _BINARY_OP_MULTIPLY_INT; - macro(BINARY_OP_ADD_INT) = -- _GUARD_BOTH_INT + unused/1 + _BINARY_OP_ADD_INT; -+ _GUARD_BOTH_INT + unused/5 + _BINARY_OP_ADD_INT; - macro(BINARY_OP_SUBTRACT_INT) = -- _GUARD_BOTH_INT + unused/1 + _BINARY_OP_SUBTRACT_INT; -+ _GUARD_BOTH_INT + unused/5 + _BINARY_OP_SUBTRACT_INT; - - op(_GUARD_BOTH_FLOAT, (left, right -- left, right)) { - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); -@@ -575,6 +635,8 @@ - pure op(_BINARY_OP_MULTIPLY_FLOAT, (left, right -- res)) { - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(PyFloat_CheckExact(left_o)); -+ assert(PyFloat_CheckExact(right_o)); - - STAT_INC(BINARY_OP, hit); - double dres = -@@ -589,6 +651,8 @@ - pure op(_BINARY_OP_ADD_FLOAT, (left, right -- res)) { - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(PyFloat_CheckExact(left_o)); -+ assert(PyFloat_CheckExact(right_o)); - - STAT_INC(BINARY_OP, hit); - double dres = -@@ -603,6 +667,8 @@ - pure op(_BINARY_OP_SUBTRACT_FLOAT, (left, right -- res)) { - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(PyFloat_CheckExact(left_o)); -+ assert(PyFloat_CheckExact(right_o)); - - STAT_INC(BINARY_OP, hit); - double dres = -@@ -615,11 +681,11 @@ - } - - macro(BINARY_OP_MULTIPLY_FLOAT) = -- _GUARD_BOTH_FLOAT + unused/1 + _BINARY_OP_MULTIPLY_FLOAT; -+ _GUARD_BOTH_FLOAT + unused/5 + _BINARY_OP_MULTIPLY_FLOAT; - macro(BINARY_OP_ADD_FLOAT) = -- _GUARD_BOTH_FLOAT + unused/1 + _BINARY_OP_ADD_FLOAT; -+ _GUARD_BOTH_FLOAT + unused/5 + _BINARY_OP_ADD_FLOAT; - macro(BINARY_OP_SUBTRACT_FLOAT) = -- _GUARD_BOTH_FLOAT + unused/1 + _BINARY_OP_SUBTRACT_FLOAT; -+ _GUARD_BOTH_FLOAT + unused/5 + _BINARY_OP_SUBTRACT_FLOAT; - - op(_GUARD_BOTH_UNICODE, (left, right -- left, right)) { - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); -@@ -632,18 +698,20 @@ - pure op(_BINARY_OP_ADD_UNICODE, (left, right -- res)) { - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(PyUnicode_CheckExact(left_o)); -+ assert(PyUnicode_CheckExact(right_o)); - - STAT_INC(BINARY_OP, hit); - PyObject *res_o = PyUnicode_Concat(left_o, right_o); -- PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); -+ PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); - INPUTS_DEAD(); - ERROR_IF(res_o == NULL, error); - res = PyStackRef_FromPyObjectSteal(res_o); - } - - macro(BINARY_OP_ADD_UNICODE) = -- _GUARD_BOTH_UNICODE + unused/1 + _BINARY_OP_ADD_UNICODE; -+ _GUARD_BOTH_UNICODE + unused/5 + _BINARY_OP_ADD_UNICODE; - - // This is a subtle one. It's a super-instruction for - // BINARY_OP_ADD_UNICODE followed by STORE_FAST -@@ -654,6 +722,8 @@ - op(_BINARY_OP_INPLACE_ADD_UNICODE, (left, right --)) { - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(PyUnicode_CheckExact(left_o)); -+ assert(PyUnicode_CheckExact(right_o)); - - int next_oparg; - #if TIER_ONE -@@ -677,9 +747,9 @@ - * that the string is safe to mutate. - */ - assert(Py_REFCNT(left_o) >= 2); -- PyStackRef_CLOSE(left); -+ PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); - DEAD(left); -- PyObject *temp = PyStackRef_AsPyObjectBorrow(*target_local); -+ PyObject *temp = PyStackRef_AsPyObjectSteal(*target_local); - PyUnicode_Append(&temp, right_o); - *target_local = PyStackRef_FromPyObjectSteal(temp); - PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); -@@ -693,41 +763,34 @@ - #endif - } - -- macro(BINARY_OP_INPLACE_ADD_UNICODE) = -- _GUARD_BOTH_UNICODE + unused/1 + _BINARY_OP_INPLACE_ADD_UNICODE; -- -- family(BINARY_SUBSCR, INLINE_CACHE_ENTRIES_BINARY_SUBSCR) = { -- BINARY_SUBSCR_DICT, -- BINARY_SUBSCR_GETITEM, -- BINARY_SUBSCR_LIST_INT, -- BINARY_SUBSCR_STR_INT, -- BINARY_SUBSCR_TUPLE_INT, -- }; -- -- specializing op(_SPECIALIZE_BINARY_SUBSCR, (counter/1, container, sub -- container, sub)) { -- #if ENABLE_SPECIALIZATION_FT -- assert(frame->stackpointer == NULL); -- if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { -- next_instr = this_instr; -- _Py_Specialize_BinarySubscr(container, sub, next_instr); -- DISPATCH_SAME_OPARG(); -- } -- OPCODE_DEFERRED_INC(BINARY_SUBSCR); -- ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); -- #endif /* ENABLE_SPECIALIZATION_FT */ -+ op(_GUARD_BINARY_OP_EXTEND, (descr/4, left, right -- left, right)) { -+ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); -+ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ _PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr; -+ assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5); -+ assert(d && d->guard); -+ int res = d->guard(left_o, right_o); -+ DEOPT_IF(!res); - } - -- op(_BINARY_SUBSCR, (container, sub -- res)) { -- PyObject *container_o = PyStackRef_AsPyObjectBorrow(container); -- PyObject *sub_o = PyStackRef_AsPyObjectBorrow(sub); -+ pure op(_BINARY_OP_EXTEND, (descr/4, left, right -- res)) { -+ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); -+ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5); -+ _PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr; -+ -+ STAT_INC(BINARY_OP, hit); - -- PyObject *res_o = PyObject_GetItem(container_o, sub_o); -+ PyObject *res_o = d->action(left_o, right_o); - DECREF_INPUTS(); -- ERROR_IF(res_o == NULL, error); - res = PyStackRef_FromPyObjectSteal(res_o); - } - -- macro(BINARY_SUBSCR) = _SPECIALIZE_BINARY_SUBSCR + _BINARY_SUBSCR; -+ macro(BINARY_OP_EXTEND) = -+ unused/1 + _GUARD_BINARY_OP_EXTEND + rewind/-4 + _BINARY_OP_EXTEND; -+ -+ macro(BINARY_OP_INPLACE_ADD_UNICODE) = -+ _GUARD_BOTH_UNICODE + unused/5 + _BINARY_OP_INPLACE_ADD_UNICODE; - - specializing op(_SPECIALIZE_BINARY_SLICE, (container, start, stop -- container, start, stop)) { - // Placeholder until we implement BINARY_SLICE specialization -@@ -774,14 +837,13 @@ - err = PyObject_SetItem(PyStackRef_AsPyObjectBorrow(container), slice, PyStackRef_AsPyObjectBorrow(v)); - Py_DECREF(slice); - } -- PyStackRef_CLOSE(v); -- PyStackRef_CLOSE(container); -+ DECREF_INPUTS(); - ERROR_IF(err, error); - } - - macro(STORE_SLICE) = _SPECIALIZE_STORE_SLICE + _STORE_SLICE; - -- inst(BINARY_SUBSCR_LIST_INT, (unused/1, list_st, sub_st -- res)) { -+ inst(BINARY_OP_SUBSCR_LIST_INT, (unused/5, list_st, sub_st -- res)) { - PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); - PyObject *list = PyStackRef_AsPyObjectBorrow(list_st); - -@@ -794,10 +856,10 @@ - #ifdef Py_GIL_DISABLED - PyObject *res_o = _PyList_GetItemRef((PyListObject*)list, index); - DEOPT_IF(res_o == NULL); -- STAT_INC(BINARY_SUBSCR, hit); -+ STAT_INC(BINARY_OP, hit); - #else - DEOPT_IF(index >= PyList_GET_SIZE(list)); -- STAT_INC(BINARY_SUBSCR, hit); -+ STAT_INC(BINARY_OP, hit); - PyObject *res_o = PyList_GET_ITEM(list, index); - assert(res_o != NULL); - Py_INCREF(res_o); -@@ -808,7 +870,7 @@ - res = PyStackRef_FromPyObjectSteal(res_o); - } - -- inst(BINARY_SUBSCR_STR_INT, (unused/1, str_st, sub_st -- res)) { -+ inst(BINARY_OP_SUBSCR_STR_INT, (unused/5, str_st, sub_st -- res)) { - PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); - PyObject *str = PyStackRef_AsPyObjectBorrow(str_st); - -@@ -820,7 +882,7 @@ - // Specialize for reading an ASCII character from any string: - Py_UCS4 c = PyUnicode_READ_CHAR(str, index); - DEOPT_IF(Py_ARRAY_LENGTH(_Py_SINGLETON(strings).ascii) <= c); -- STAT_INC(BINARY_SUBSCR, hit); -+ STAT_INC(BINARY_OP, hit); - PyObject *res_o = (PyObject*)&_Py_SINGLETON(strings).ascii[c]; - PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); - DEAD(sub_st); -@@ -828,7 +890,7 @@ - res = PyStackRef_FromPyObjectSteal(res_o); - } - -- inst(BINARY_SUBSCR_TUPLE_INT, (unused/1, tuple_st, sub_st -- res)) { -+ inst(BINARY_OP_SUBSCR_TUPLE_INT, (unused/5, tuple_st, sub_st -- res)) { - PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); - PyObject *tuple = PyStackRef_AsPyObjectBorrow(tuple_st); - -@@ -839,7 +901,7 @@ - DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub)); - Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; - DEOPT_IF(index >= PyTuple_GET_SIZE(tuple)); -- STAT_INC(BINARY_SUBSCR, hit); -+ STAT_INC(BINARY_OP, hit); - PyObject *res_o = PyTuple_GET_ITEM(tuple, index); - assert(res_o != NULL); - Py_INCREF(res_o); -@@ -849,12 +911,12 @@ - res = PyStackRef_FromPyObjectSteal(res_o); - } - -- inst(BINARY_SUBSCR_DICT, (unused/1, dict_st, sub_st -- res)) { -+ inst(BINARY_OP_SUBSCR_DICT, (unused/5, dict_st, sub_st -- res)) { - PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); - PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st); - - DEOPT_IF(!PyDict_CheckExact(dict)); -- STAT_INC(BINARY_SUBSCR, hit); -+ STAT_INC(BINARY_OP, hit); - PyObject *res_o; - int rc = PyDict_GetItemRef(dict, sub, &res_o); - if (rc == 0) { -@@ -865,37 +927,35 @@ - res = PyStackRef_FromPyObjectSteal(res_o); - } - -- op(_BINARY_SUBSCR_CHECK_FUNC, (container, unused -- container, unused)) { -+ op(_BINARY_OP_SUBSCR_CHECK_FUNC, (container, unused -- container, unused, getitem)) { - PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(container)); - DEOPT_IF(!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)); - PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; -- PyObject *getitem = ht->_spec_cache.getitem; -- DEOPT_IF(getitem == NULL); -- assert(PyFunction_Check(getitem)); -- uint32_t cached_version = ht->_spec_cache.getitem_version; -- DEOPT_IF(((PyFunctionObject *)getitem)->func_version != cached_version); -- PyCodeObject *code = (PyCodeObject *)PyFunction_GET_CODE(getitem); -+ PyObject *getitem_o = FT_ATOMIC_LOAD_PTR_ACQUIRE(ht->_spec_cache.getitem); -+ DEOPT_IF(getitem_o == NULL); -+ assert(PyFunction_Check(getitem_o)); -+ uint32_t cached_version = FT_ATOMIC_LOAD_UINT32_RELAXED(ht->_spec_cache.getitem_version); -+ DEOPT_IF(((PyFunctionObject *)getitem_o)->func_version != cached_version); -+ PyCodeObject *code = (PyCodeObject *)PyFunction_GET_CODE(getitem_o); - assert(code->co_argcount == 2); - DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize)); -- STAT_INC(BINARY_SUBSCR, hit); -+ getitem = PyStackRef_FromPyObjectNew(getitem_o); -+ STAT_INC(BINARY_OP, hit); - } - -- op(_BINARY_SUBSCR_INIT_CALL, (container, sub -- new_frame: _PyInterpreterFrame* )) { -- PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(container)); -- PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; -- PyObject *getitem = ht->_spec_cache.getitem; -- new_frame = _PyFrame_PushUnchecked(tstate, PyStackRef_FromPyObjectNew(getitem), 2, frame); -+ op(_BINARY_OP_SUBSCR_INIT_CALL, (container, sub, getitem -- new_frame: _PyInterpreterFrame* )) { -+ new_frame = _PyFrame_PushUnchecked(tstate, getitem, 2, frame); - new_frame->localsplus[0] = container; - new_frame->localsplus[1] = sub; - INPUTS_DEAD(); - frame->return_offset = INSTRUCTION_SIZE; - } - -- macro(BINARY_SUBSCR_GETITEM) = -- unused/1 + // Skip over the counter -+ macro(BINARY_OP_SUBSCR_GETITEM) = -+ unused/5 + // Skip over the counter and cache - _CHECK_PEP_523 + -- _BINARY_SUBSCR_CHECK_FUNC + -- _BINARY_SUBSCR_INIT_CALL + -+ _BINARY_OP_SUBSCR_CHECK_FUNC + -+ _BINARY_OP_SUBSCR_INIT_CALL + - _PUSH_FRAME; - - inst(LIST_APPEND, (list, unused[oparg-1], v -- list, unused[oparg-1])) { -@@ -959,10 +1019,10 @@ - PyList_SET_ITEM(list, index, PyStackRef_AsPyObjectSteal(value)); - assert(old_value != NULL); - UNLOCK_OBJECT(list); // unlock before decrefs! -- Py_DECREF(old_value); - PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); - DEAD(sub_st); - PyStackRef_CLOSE(list_st); -+ Py_DECREF(old_value); - } - - inst(STORE_SUBSCR_DICT, (unused/1, value, dict_st, sub -- )) { -@@ -1018,7 +1078,7 @@ - } - - tier1 inst(INTERPRETER_EXIT, (retval --)) { -- assert(frame == &entry_frame); -+ assert(frame->owner == FRAME_OWNED_BY_INTERPRETER); - assert(_PyFrame_IsIncomplete(frame)); - /* Restore previous frame and return. */ - tstate->current_frame = frame->previous; -@@ -1033,9 +1093,7 @@ - // retval is popped from the stack, but res - // is pushed to a different frame, the callers' frame. - inst(RETURN_VALUE, (retval -- res)) { -- #if TIER_ONE -- assert(frame != &entry_frame); -- #endif -+ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); - _PyStackRef temp = retval; - DEAD(retval); - SAVE_STACK(); -@@ -1133,7 +1191,7 @@ - PyObject *receiver_o = PyStackRef_AsPyObjectBorrow(receiver); - - PyObject *retval_o; -- assert(frame != &entry_frame); -+ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); - if ((tstate->interp->eval_frame == NULL) && - (Py_TYPE(receiver_o) == &PyGen_Type || Py_TYPE(receiver_o) == &PyCoro_Type) && - ((PyGenObject *)receiver_o)->gi_frame_state < FRAME_EXECUTING) -@@ -1206,9 +1264,7 @@ - // NOTE: It's important that YIELD_VALUE never raises an exception! - // The compiler treats any exception raised here as a failed close() - // or throw() call. -- #if TIER_ONE -- assert(frame != &entry_frame); -- #endif -+ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); - frame->instr_ptr++; - PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); - assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); -@@ -1303,7 +1359,9 @@ - - tier1 inst(CLEANUP_THROW, (sub_iter_st, last_sent_val_st, exc_value_st -- none, value)) { - PyObject *exc_value = PyStackRef_AsPyObjectBorrow(exc_value_st); -+ #ifndef Py_TAIL_CALL_INTERP - assert(throwflag); -+ #endif - assert(exc_value && PyExceptionInstance_Check(exc_value)); - - int matches = PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration); -@@ -1467,7 +1525,7 @@ - }; - - specializing op(_SPECIALIZE_STORE_ATTR, (counter/1, owner -- owner)) { -- #if ENABLE_SPECIALIZATION -+ #if ENABLE_SPECIALIZATION_FT - if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); - next_instr = this_instr; -@@ -1476,7 +1534,7 @@ - } - OPCODE_DEFERRED_INC(STORE_ATTR); - ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); -- #endif /* ENABLE_SPECIALIZATION */ -+ #endif /* ENABLE_SPECIALIZATION_FT */ - } - - op(_STORE_ATTR, (v, owner --)) { -@@ -1597,10 +1655,13 @@ - } - - // res[1] because we need a pointer to res to pass it to _PyEval_LoadGlobalStackRef -- op(_LOAD_GLOBAL, ( -- res[1], null if (oparg & 1))) { -+ op(_LOAD_GLOBAL, ( -- res[1])) { - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); - _PyEval_LoadGlobalStackRef(GLOBALS(), BUILTINS(), name, res); - ERROR_IF(PyStackRef_IsNull(*res), error); -+ } -+ -+ op(_PUSH_NULL_CONDITIONAL, ( -- null if (oparg & 1))) { - null = PyStackRef_NULL; - } - -@@ -1609,7 +1670,8 @@ - counter/1 + - globals_version/1 + - builtins_version/1 + -- _LOAD_GLOBAL; -+ _LOAD_GLOBAL + -+ _PUSH_NULL_CONDITIONAL; - - op(_GUARD_GLOBALS_VERSION, (version/1 --)) { - PyDictObject *dict = (PyDictObject *)GLOBALS(); -@@ -1639,7 +1701,7 @@ - assert(DK_IS_UNICODE(builtins_keys)); - } - -- op(_LOAD_GLOBAL_MODULE_FROM_KEYS, (index/1, globals_keys: PyDictKeysObject* -- res, null if (oparg & 1))) { -+ op(_LOAD_GLOBAL_MODULE_FROM_KEYS, (index/1, globals_keys: PyDictKeysObject* -- res)) { - PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(globals_keys); - PyObject *res_o = FT_ATOMIC_LOAD_PTR_RELAXED(entries[index].me_value); - DEAD(globals_keys); -@@ -1653,10 +1715,9 @@ - res = PyStackRef_FromPyObjectSteal(res_o); - #endif - STAT_INC(LOAD_GLOBAL, hit); -- null = PyStackRef_NULL; - } - -- op(_LOAD_GLOBAL_BUILTINS_FROM_KEYS, (index/1, builtins_keys: PyDictKeysObject* -- res, null if (oparg & 1))) { -+ op(_LOAD_GLOBAL_BUILTINS_FROM_KEYS, (index/1, builtins_keys: PyDictKeysObject* -- res)) { - PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(builtins_keys); - PyObject *res_o = FT_ATOMIC_LOAD_PTR_RELAXED(entries[index].me_value); - DEAD(builtins_keys); -@@ -1670,20 +1731,21 @@ - res = PyStackRef_FromPyObjectSteal(res_o); - #endif - STAT_INC(LOAD_GLOBAL, hit); -- null = PyStackRef_NULL; - } - - macro(LOAD_GLOBAL_MODULE) = - unused/1 + // Skip over the counter - _GUARD_GLOBALS_VERSION_PUSH_KEYS + - unused/1 + // Skip over the builtins version -- _LOAD_GLOBAL_MODULE_FROM_KEYS; -+ _LOAD_GLOBAL_MODULE_FROM_KEYS + -+ _PUSH_NULL_CONDITIONAL; - - macro(LOAD_GLOBAL_BUILTIN) = - unused/1 + // Skip over the counter - _GUARD_GLOBALS_VERSION + - _GUARD_BUILTINS_VERSION_PUSH_KEYS + -- _LOAD_GLOBAL_BUILTINS_FROM_KEYS; -+ _LOAD_GLOBAL_BUILTINS_FROM_KEYS + -+ _PUSH_NULL_CONDITIONAL; - - inst(DELETE_FAST, (--)) { - _PyStackRef v = GETLOCAL(oparg); -@@ -1694,7 +1756,9 @@ - ); - ERROR_IF(1, error); - } -- SETLOCAL(oparg, PyStackRef_NULL); -+ _PyStackRef tmp = GETLOCAL(oparg); -+ GETLOCAL(oparg) = PyStackRef_NULL; -+ PyStackRef_XCLOSE(tmp); - } - - inst(MAKE_CELL, (--)) { -@@ -1705,7 +1769,9 @@ - if (cell == NULL) { - ERROR_NO_POP(); - } -- SETLOCAL(oparg, PyStackRef_FromPyObjectSteal(cell)); -+ _PyStackRef tmp = GETLOCAL(oparg); -+ GETLOCAL(oparg) = PyStackRef_FromPyObjectSteal(cell); -+ PyStackRef_XCLOSE(tmp); - } - - inst(DELETE_DEREF, (--)) { -@@ -1787,16 +1853,20 @@ - } - - inst(BUILD_TUPLE, (values[oparg] -- tup)) { -- PyObject *tup_o = _PyTuple_FromStackRefSteal(values, oparg); -+ PyObject *tup_o = _PyTuple_FromStackRefStealOnSuccess(values, oparg); -+ if (tup_o == NULL) { -+ ERROR_NO_POP(); -+ } - INPUTS_DEAD(); -- ERROR_IF(tup_o == NULL, error); - tup = PyStackRef_FromPyObjectSteal(tup_o); - } - - inst(BUILD_LIST, (values[oparg] -- list)) { -- PyObject *list_o = _PyList_FromStackRefSteal(values, oparg); -+ PyObject *list_o = _PyList_FromStackRefStealOnSuccess(values, oparg); -+ if (list_o == NULL) { -+ ERROR_NO_POP(); -+ } - INPUTS_DEAD(); -- ERROR_IF(list_o == NULL, error); - list = PyStackRef_FromPyObjectSteal(list_o); - } - -@@ -1840,9 +1910,8 @@ - if (err == 0) { - err = PySet_Add(set_o, PyStackRef_AsPyObjectBorrow(values[i])); - } -- PyStackRef_CLOSE(values[i]); - } -- DEAD(values); -+ DECREF_INPUTS(); - if (err != 0) { - Py_DECREF(set_o); - ERROR_IF(true, error); -@@ -1934,12 +2003,10 @@ - ERROR_IF(err != 0, error); - } - -- inst(INSTRUMENTED_LOAD_SUPER_ATTR, (unused/1 -- )) { -- // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we -- // don't want to specialize instrumented instructions -- PAUSE_ADAPTIVE_COUNTER(this_instr[1].counter); -- GO_TO_INSTRUCTION(LOAD_SUPER_ATTR); -- } -+ macro(INSTRUMENTED_LOAD_SUPER_ATTR) = -+ counter/1 + -+ _LOAD_SUPER_ATTR + -+ _PUSH_NULL_CONDITIONAL; - - family(LOAD_SUPER_ATTR, INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR) = { - LOAD_SUPER_ATTR_ATTR, -@@ -1959,7 +2026,7 @@ - #endif /* ENABLE_SPECIALIZATION_FT */ - } - -- tier1 op(_LOAD_SUPER_ATTR, (global_super_st, class_st, self_st -- attr, null if (oparg & 1))) { -+ tier1 op(_LOAD_SUPER_ATTR, (global_super_st, class_st, self_st -- attr)) { - PyObject *global_super = PyStackRef_AsPyObjectBorrow(global_super_st); - PyObject *class = PyStackRef_AsPyObjectBorrow(class_st); - PyObject *self = PyStackRef_AsPyObjectBorrow(self_st); -@@ -2001,12 +2068,14 @@ - Py_DECREF(super); - ERROR_IF(attr_o == NULL, error); - attr = PyStackRef_FromPyObjectSteal(attr_o); -- null = PyStackRef_NULL; - } - -- macro(LOAD_SUPER_ATTR) = _SPECIALIZE_LOAD_SUPER_ATTR + _LOAD_SUPER_ATTR; -+ macro(LOAD_SUPER_ATTR) = -+ _SPECIALIZE_LOAD_SUPER_ATTR + -+ _LOAD_SUPER_ATTR + -+ _PUSH_NULL_CONDITIONAL; - -- inst(LOAD_SUPER_ATTR_ATTR, (unused/1, global_super_st, class_st, self_st -- attr_st, unused if (0))) { -+ inst(LOAD_SUPER_ATTR_ATTR, (unused/1, global_super_st, class_st, self_st -- attr_st)) { - PyObject *global_super = PyStackRef_AsPyObjectBorrow(global_super_st); - PyObject *class = PyStackRef_AsPyObjectBorrow(class_st); - PyObject *self = PyStackRef_AsPyObjectBorrow(self_st); -@@ -2036,11 +2105,8 @@ - int method_found = 0; - PyObject *attr_o = _PySuper_Lookup(cls, self, name, - Py_TYPE(self)->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL); -- PyStackRef_CLOSE(global_super_st); -- PyStackRef_CLOSE(class_st); - if (attr_o == NULL) { -- PyStackRef_CLOSE(self_st); -- ERROR_IF(true, error); -+ ERROR_NO_POP(); - } - if (method_found) { - self_or_null = self_st; // transfer ownership -@@ -2049,6 +2115,7 @@ - PyStackRef_CLOSE(self_st); - self_or_null = PyStackRef_NULL; - } -+ DECREF_INPUTS(); - - attr = PyStackRef_FromPyObjectSteal(attr_o); - } -@@ -2082,7 +2149,7 @@ - #endif /* ENABLE_SPECIALIZATION_FT */ - } - -- op(_LOAD_ATTR, (owner -- attr, self_or_null if (oparg & 1))) { -+ op(_LOAD_ATTR, (owner -- attr, self_or_null[oparg&1])) { - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); - PyObject *attr_o; - if (oparg & 1) { -@@ -2095,7 +2162,7 @@ - meth | self | arg1 | ... | argN - */ - assert(attr_o != NULL); // No errors on this branch -- self_or_null = owner; // Transfer ownership -+ self_or_null[0] = owner; // Transfer ownership - DEAD(owner); - } - else { -@@ -2107,7 +2174,7 @@ - */ - DECREF_INPUTS(); - ERROR_IF(attr_o == NULL, error); -- self_or_null = PyStackRef_NULL; -+ self_or_null[0] = PyStackRef_NULL; - } - } - else { -@@ -2115,12 +2182,11 @@ - attr_o = PyObject_GetAttr(PyStackRef_AsPyObjectBorrow(owner), name); - DECREF_INPUTS(); - ERROR_IF(attr_o == NULL, error); -- /* We need to define self_or_null on all paths */ -- self_or_null = PyStackRef_NULL; - } - attr = PyStackRef_FromPyObjectSteal(attr_o); - } - -+ - macro(LOAD_ATTR) = - _SPECIALIZE_LOAD_ATTR + - unused/8 + -@@ -2129,26 +2195,41 @@ - op(_GUARD_TYPE_VERSION, (type_version/2, owner -- owner)) { - PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - assert(type_version != 0); -- EXIT_IF(tp->tp_version_tag != type_version); -+ EXIT_IF(FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version); -+ } -+ -+ op(_GUARD_TYPE_VERSION_AND_LOCK, (type_version/2, owner -- owner)) { -+ PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); -+ assert(type_version != 0); -+ EXIT_IF(!LOCK_OBJECT(owner_o)); -+ PyTypeObject *tp = Py_TYPE(owner_o); -+ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { -+ UNLOCK_OBJECT(owner_o); -+ EXIT_IF(true); -+ } - } - - op(_CHECK_MANAGED_OBJECT_HAS_VALUES, (owner -- owner)) { - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - assert(Py_TYPE(owner_o)->tp_dictoffset < 0); - assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); -- DEOPT_IF(!_PyObject_InlineValues(owner_o)->valid); -+ DEOPT_IF(!FT_ATOMIC_LOAD_UINT8(_PyObject_InlineValues(owner_o)->valid)); - } - -- split op(_LOAD_ATTR_INSTANCE_VALUE, (offset/1, owner -- attr, null if (oparg & 1))) { -+ op(_LOAD_ATTR_INSTANCE_VALUE, (offset/1, owner -- attr)) { - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); -- PyObject *attr_o = *value_ptr; -+ PyObject *attr_o = FT_ATOMIC_LOAD_PTR_ACQUIRE(*value_ptr); - DEOPT_IF(attr_o == NULL); -+ #ifdef Py_GIL_DISABLED -+ if (!_Py_TryIncrefCompareStackRef(value_ptr, attr_o, &attr)) { -+ DEOPT_IF(true); -+ } -+ #else -+ attr = PyStackRef_FromPyObjectNew(attr_o); -+ #endif - STAT_INC(LOAD_ATTR, hit); -- Py_INCREF(attr_o); -- null = PyStackRef_NULL; -- attr = PyStackRef_FromPyObjectSteal(attr_o); -- DECREF_INPUTS(); -+ PyStackRef_CLOSE(owner); - } - - macro(LOAD_ATTR_INSTANCE_VALUE) = -@@ -2156,7 +2237,8 @@ - _GUARD_TYPE_VERSION + - _CHECK_MANAGED_OBJECT_HAS_VALUES + - _LOAD_ATTR_INSTANCE_VALUE + -- unused/5; // Skip over rest of cache -+ unused/5 + -+ _PUSH_NULL_CONDITIONAL; - - op(_CHECK_ATTR_MODULE_PUSH_KEYS, (dict_version/2, owner -- owner, mod_keys: PyDictKeysObject *)) { - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); -@@ -2168,14 +2250,13 @@ - mod_keys = keys; - } - -- op(_LOAD_ATTR_MODULE_FROM_KEYS, (index/1, owner, mod_keys: PyDictKeysObject * -- attr, null if (oparg & 1))) { -+ op(_LOAD_ATTR_MODULE_FROM_KEYS, (index/1, owner, mod_keys: PyDictKeysObject * -- attr)) { - assert(mod_keys->dk_kind == DICT_KEYS_UNICODE); - assert(index < FT_ATOMIC_LOAD_SSIZE_RELAXED(mod_keys->dk_nentries)); - PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(mod_keys) + index; - PyObject *attr_o = FT_ATOMIC_LOAD_PTR_RELAXED(ep->me_value); -- DEAD(mod_keys); - // Clear mod_keys from stack in case we need to deopt -- POP_DEAD_INPUTS(); -+ POP_INPUT(mod_keys); - DEOPT_IF(attr_o == NULL); - #ifdef Py_GIL_DISABLED - int increfed = _Py_TryIncrefCompareStackRef(&ep->me_value, attr_o, &attr); -@@ -2187,7 +2268,6 @@ - attr = PyStackRef_FromPyObjectSteal(attr_o); - #endif - STAT_INC(LOAD_ATTR, hit); -- null = PyStackRef_NULL; - PyStackRef_CLOSE(owner); - } - -@@ -2195,33 +2275,53 @@ - unused/1 + - _CHECK_ATTR_MODULE_PUSH_KEYS + - _LOAD_ATTR_MODULE_FROM_KEYS + -- unused/5; -+ unused/5 + -+ _PUSH_NULL_CONDITIONAL; - -- op(_CHECK_ATTR_WITH_HINT, (owner -- owner)) { -+ op(_CHECK_ATTR_WITH_HINT, (owner -- owner, dict: PyDictObject *)) { - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - - assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_MANAGED_DICT); -- PyDictObject *dict = _PyObject_GetManagedDict(owner_o); -- EXIT_IF(dict == NULL); -- assert(PyDict_CheckExact((PyObject *)dict)); -+ PyDictObject *dict_o = _PyObject_GetManagedDict(owner_o); -+ EXIT_IF(dict_o == NULL); -+ assert(PyDict_CheckExact((PyObject *)dict_o)); -+ dict = dict_o; - } - -- op(_LOAD_ATTR_WITH_HINT, (hint/1, owner -- attr, null if (oparg & 1))) { -- PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); -+ op(_LOAD_ATTR_WITH_HINT, (hint/1, owner, dict: PyDictObject * -- attr)) { - PyObject *attr_o; -+ if (!LOCK_OBJECT(dict)) { -+ POP_INPUT(dict); -+ DEOPT_IF(true); -+ } - -- PyDictObject *dict = _PyObject_GetManagedDict(owner_o); -- DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries); -+ if (hint >= (size_t)dict->ma_keys->dk_nentries) { -+ UNLOCK_OBJECT(dict); -+ POP_INPUT(dict); -+ DEOPT_IF(true); -+ } - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); -- DEOPT_IF(!DK_IS_UNICODE(dict->ma_keys)); -+ if (dict->ma_keys->dk_kind != DICT_KEYS_UNICODE) { -+ UNLOCK_OBJECT(dict); -+ POP_INPUT(dict); -+ DEOPT_IF(true); -+ } - PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; -- DEOPT_IF(ep->me_key != name); -+ if (ep->me_key != name) { -+ UNLOCK_OBJECT(dict); -+ POP_INPUT(dict); -+ DEOPT_IF(true); -+ } - attr_o = ep->me_value; -- DEOPT_IF(attr_o == NULL); -+ if (attr_o == NULL) { -+ UNLOCK_OBJECT(dict); -+ POP_INPUT(dict); -+ DEOPT_IF(true); -+ } - STAT_INC(LOAD_ATTR, hit); -- Py_INCREF(attr_o); -- attr = PyStackRef_FromPyObjectSteal(attr_o); -- null = PyStackRef_NULL; -+ attr = PyStackRef_FromPyObjectNew(attr_o); -+ UNLOCK_OBJECT(dict); -+ DEAD(dict); - DECREF_INPUTS(); - } - -@@ -2230,17 +2330,22 @@ - _GUARD_TYPE_VERSION + - _CHECK_ATTR_WITH_HINT + - _LOAD_ATTR_WITH_HINT + -- unused/5; -+ unused/5 + -+ _PUSH_NULL_CONDITIONAL; - -- split op(_LOAD_ATTR_SLOT, (index/1, owner -- attr, null if (oparg & 1))) { -+ op(_LOAD_ATTR_SLOT, (index/1, owner -- attr)) { - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - -- char *addr = (char *)owner_o + index; -- PyObject *attr_o = *(PyObject **)addr; -+ PyObject **addr = (PyObject **)((char *)owner_o + index); -+ PyObject *attr_o = FT_ATOMIC_LOAD_PTR(*addr); - DEOPT_IF(attr_o == NULL); -- STAT_INC(LOAD_ATTR, hit); -- null = PyStackRef_NULL; -+ #ifdef Py_GIL_DISABLED -+ int increfed = _Py_TryIncrefCompareStackRef(addr, attr_o, &attr); -+ DEOPT_IF(!increfed); -+ #else - attr = PyStackRef_FromPyObjectNew(attr_o); -+ #endif -+ STAT_INC(LOAD_ATTR, hit); - DECREF_INPUTS(); - } - -@@ -2248,21 +2353,21 @@ - unused/1 + - _GUARD_TYPE_VERSION + - _LOAD_ATTR_SLOT + // NOTE: This action may also deopt -- unused/5; -+ unused/5 + -+ _PUSH_NULL_CONDITIONAL; - - op(_CHECK_ATTR_CLASS, (type_version/2, owner -- owner)) { - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - - EXIT_IF(!PyType_Check(owner_o)); - assert(type_version != 0); -- EXIT_IF(((PyTypeObject *)owner_o)->tp_version_tag != type_version); -+ EXIT_IF(FT_ATOMIC_LOAD_UINT_RELAXED(((PyTypeObject *)owner_o)->tp_version_tag) != type_version); - } - -- split op(_LOAD_ATTR_CLASS, (descr/4, owner -- attr, null if (oparg & 1))) { -+ op(_LOAD_ATTR_CLASS, (descr/4, owner -- attr)) { - STAT_INC(LOAD_ATTR, hit); - assert(descr != NULL); - attr = PyStackRef_FromPyObjectNew(descr); -- null = PyStackRef_NULL; - DECREF_INPUTS(); - } - -@@ -2270,13 +2375,15 @@ - unused/1 + - _CHECK_ATTR_CLASS + - unused/2 + -- _LOAD_ATTR_CLASS; -+ _LOAD_ATTR_CLASS + -+ _PUSH_NULL_CONDITIONAL; - - macro(LOAD_ATTR_CLASS_WITH_METACLASS_CHECK) = - unused/1 + - _CHECK_ATTR_CLASS + - _GUARD_TYPE_VERSION + -- _LOAD_ATTR_CLASS; -+ _LOAD_ATTR_CLASS + -+ _PUSH_NULL_CONDITIONAL; - - op(_LOAD_ATTR_PROPERTY_FRAME, (fget/4, owner -- new_frame: _PyInterpreterFrame *)) { - assert((oparg & 1) == 0); -@@ -2302,14 +2409,14 @@ - _SAVE_RETURN_OFFSET + - _PUSH_FRAME; - -- inst(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, (unused/1, type_version/2, func_version/2, getattribute/4, owner -- unused, unused if (0))) { -+ inst(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, (unused/1, type_version/2, func_version/2, getattribute/4, owner -- unused)) { - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - - assert((oparg & 1) == 0); - DEOPT_IF(tstate->interp->eval_frame); - PyTypeObject *cls = Py_TYPE(owner_o); - assert(type_version != 0); -- DEOPT_IF(cls->tp_version_tag != type_version); -+ DEOPT_IF(FT_ATOMIC_LOAD_UINT_RELAXED(cls->tp_version_tag) != type_version); - assert(Py_IS_TYPE(getattribute, &PyFunction_Type)); - PyFunctionObject *f = (PyFunctionObject *)getattribute; - assert(func_version != 0); -@@ -2336,8 +2443,11 @@ - - assert(Py_TYPE(owner_o)->tp_dictoffset < 0); - assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); -- EXIT_IF(_PyObject_GetManagedDict(owner_o)); -- EXIT_IF(_PyObject_InlineValues(owner_o)->valid == 0); -+ if (_PyObject_GetManagedDict(owner_o) || -+ !FT_ATOMIC_LOAD_UINT8(_PyObject_InlineValues(owner_o)->valid)) { -+ UNLOCK_OBJECT(owner_o); -+ EXIT_IF(true); -+ } - } - - op(_STORE_ATTR_INSTANCE_VALUE, (offset/1, value, owner --)) { -@@ -2347,21 +2457,20 @@ - assert(_PyObject_GetManagedDict(owner_o) == NULL); - PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); - PyObject *old_value = *value_ptr; -- *value_ptr = PyStackRef_AsPyObjectSteal(value); -+ FT_ATOMIC_STORE_PTR_RELEASE(*value_ptr, PyStackRef_AsPyObjectSteal(value)); - if (old_value == NULL) { - PyDictValues *values = _PyObject_InlineValues(owner_o); - Py_ssize_t index = value_ptr - values->values; - _PyDictValues_AddToInsertionOrder(values, index); - } -- else { -- Py_DECREF(old_value); -- } -+ UNLOCK_OBJECT(owner_o); - PyStackRef_CLOSE(owner); -+ Py_XDECREF(old_value); - } - - macro(STORE_ATTR_INSTANCE_VALUE) = - unused/1 + -- _GUARD_TYPE_VERSION + -+ _GUARD_TYPE_VERSION_AND_LOCK + - _GUARD_DORV_NO_DICT + - _STORE_ATTR_INSTANCE_VALUE; - -@@ -2370,21 +2479,39 @@ - assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_MANAGED_DICT); - PyDictObject *dict = _PyObject_GetManagedDict(owner_o); - DEOPT_IF(dict == NULL); -+ DEOPT_IF(!LOCK_OBJECT(dict)); -+ #ifdef Py_GIL_DISABLED -+ if (dict != _PyObject_GetManagedDict(owner_o)) { -+ UNLOCK_OBJECT(dict); -+ DEOPT_IF(true); -+ } -+ #endif - assert(PyDict_CheckExact((PyObject *)dict)); - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); -- DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries); -- DEOPT_IF(!DK_IS_UNICODE(dict->ma_keys)); -+ if (hint >= (size_t)dict->ma_keys->dk_nentries || -+ !DK_IS_UNICODE(dict->ma_keys)) { -+ UNLOCK_OBJECT(dict); -+ DEOPT_IF(true); -+ } - PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; -- DEOPT_IF(ep->me_key != name); -+ if (ep->me_key != name) { -+ UNLOCK_OBJECT(dict); -+ DEOPT_IF(true); -+ } - PyObject *old_value = ep->me_value; -- DEOPT_IF(old_value == NULL); -+ if (old_value == NULL) { -+ UNLOCK_OBJECT(dict); -+ DEOPT_IF(true); -+ } - _PyDict_NotifyEvent(tstate->interp, PyDict_EVENT_MODIFIED, dict, name, PyStackRef_AsPyObjectBorrow(value)); -- ep->me_value = PyStackRef_AsPyObjectSteal(value); -+ FT_ATOMIC_STORE_PTR_RELEASE(ep->me_value, PyStackRef_AsPyObjectSteal(value)); -+ UNLOCK_OBJECT(dict); -+ - // old_value should be DECREFed after GC track checking is done, if not, it could raise a segmentation fault, - // when dict only holds the strong reference to value in ep->me_value. -- Py_XDECREF(old_value); - STAT_INC(STORE_ATTR, hit); - PyStackRef_CLOSE(owner); -+ Py_XDECREF(old_value); - } - - macro(STORE_ATTR_WITH_HINT) = -@@ -2395,12 +2522,14 @@ - op(_STORE_ATTR_SLOT, (index/1, value, owner --)) { - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - -+ DEOPT_IF(!LOCK_OBJECT(owner_o)); - char *addr = (char *)owner_o + index; - STAT_INC(STORE_ATTR, hit); - PyObject *old_value = *(PyObject **)addr; -- *(PyObject **)addr = PyStackRef_AsPyObjectSteal(value); -- Py_XDECREF(old_value); -+ FT_ATOMIC_STORE_PTR_RELEASE(*(PyObject **)addr, PyStackRef_AsPyObjectSteal(value)); -+ UNLOCK_OBJECT(owner_o); - PyStackRef_CLOSE(owner); -+ Py_XDECREF(old_value); - } - - macro(STORE_ATTR_SLOT) = -@@ -2415,7 +2544,7 @@ - }; - - specializing op(_SPECIALIZE_COMPARE_OP, (counter/1, left, right -- left, right)) { -- #if ENABLE_SPECIALIZATION -+ #if ENABLE_SPECIALIZATION_FT - if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { - next_instr = this_instr; - _Py_Specialize_CompareOp(left, right, next_instr, oparg); -@@ -2423,7 +2552,7 @@ - } - OPCODE_DEFERRED_INC(COMPARE_OP); - ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); -- #endif /* ENABLE_SPECIALIZATION */ -+ #endif /* ENABLE_SPECIALIZATION_FT */ - } - - op(_COMPARE_OP, (left, right -- res)) { -@@ -2585,7 +2714,7 @@ - - PyObject *match_o = NULL; - PyObject *rest_o = NULL; -- int res = _PyEval_ExceptionGroupMatch(exc_value, match_type, -+ int res = _PyEval_ExceptionGroupMatch(frame, exc_value, match_type, - &match_o, &rest_o); - DECREF_INPUTS(); - ERROR_IF(res < 0, error); -@@ -2637,13 +2766,26 @@ - JUMPBY(oparg); - } - -- tier1 op(_JUMP_BACKWARD, (the_counter/1 --)) { -- assert(oparg <= INSTR_OFFSET()); -- JUMPBY(-oparg); -- #ifdef _Py_TIER2 -- #if ENABLE_SPECIALIZATION -+ family(JUMP_BACKWARD, 1) = { -+ JUMP_BACKWARD_NO_JIT, -+ JUMP_BACKWARD_JIT, -+ }; -+ -+ tier1 op(_SPECIALIZE_JUMP_BACKWARD, (--)) { -+ #if ENABLE_SPECIALIZATION -+ if (this_instr->op.code == JUMP_BACKWARD) { -+ this_instr->op.code = tstate->interp->jit ? JUMP_BACKWARD_JIT : JUMP_BACKWARD_NO_JIT; -+ // Need to re-dispatch so the warmup counter isn't off by one: -+ next_instr = this_instr; -+ DISPATCH_SAME_OPARG(); -+ } -+ #endif -+ } -+ -+ tier1 op(_JIT, (--)) { -+ #ifdef _Py_TIER2 - _Py_BackoffCounter counter = this_instr[1].counter; -- if (backoff_counter_triggers(counter) && this_instr->op.code == JUMP_BACKWARD) { -+ if (backoff_counter_triggers(counter) && this_instr->op.code == JUMP_BACKWARD_JIT) { - _Py_CODEUNIT *start = this_instr; - /* Back up over EXTENDED_ARGs so optimizer sees the whole instruction */ - while (oparg > 255) { -@@ -2651,7 +2793,7 @@ - start--; - } - _PyExecutorObject *executor; -- int optimized = _PyOptimizer_Optimize(frame, start, stack_pointer, &executor, 0); -+ int optimized = _PyOptimizer_Optimize(frame, start, &executor, 0); - if (optimized <= 0) { - this_instr[1].counter = restart_backoff_counter(counter); - ERROR_IF(optimized < 0, error); -@@ -2666,13 +2808,25 @@ - else { - ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - } -- #endif /* ENABLE_SPECIALIZATION */ -- #endif /* _Py_TIER2 */ -+ #endif - } - - macro(JUMP_BACKWARD) = -+ unused/1 + -+ _SPECIALIZE_JUMP_BACKWARD + -+ _CHECK_PERIODIC + -+ JUMP_BACKWARD_NO_INTERRUPT; -+ -+ macro(JUMP_BACKWARD_NO_JIT) = -+ unused/1 + - _CHECK_PERIODIC + -- _JUMP_BACKWARD; -+ JUMP_BACKWARD_NO_INTERRUPT; -+ -+ macro(JUMP_BACKWARD_JIT) = -+ unused/1 + -+ _CHECK_PERIODIC + -+ JUMP_BACKWARD_NO_INTERRUPT + -+ _JIT; - - pseudo(JUMP, (--)) = { - JUMP_FORWARD, -@@ -2725,7 +2879,7 @@ - int flag = PyStackRef_IsFalse(cond); - DEAD(cond); - RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); -- JUMPBY(oparg * flag); -+ JUMPBY(flag ? oparg : next_instr->op.code == NOT_TAKEN); - } - - replaced op(_POP_JUMP_IF_TRUE, (cond -- )) { -@@ -2733,7 +2887,7 @@ - int flag = PyStackRef_IsTrue(cond); - DEAD(cond); - RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); -- JUMPBY(oparg * flag); -+ JUMPBY(flag ? oparg : next_instr->op.code == NOT_TAKEN); - } - - op(_IS_NONE, (value -- b)) { -@@ -2761,6 +2915,7 @@ - * generator or coroutine, so we deliberately do not check it here. - * (see bpo-30039). - */ -+ assert(oparg <= INSTR_OFFSET()); - JUMPBY(-oparg); - } - -@@ -2841,7 +2996,6 @@ - else { - /* `iterable` is not a generator. */ - PyObject *iter_o = PyObject_GetIter(iterable_o); -- DEAD(iterable); - if (iter_o == NULL) { - ERROR_NO_POP(); - } -@@ -2891,10 +3045,8 @@ - /* iterator ended normally */ - assert(next_instr[oparg].op.code == END_FOR || - next_instr[oparg].op.code == INSTRUMENTED_END_FOR); -- PyStackRef_CLOSE(iter); -- STACK_SHRINK(1); -- /* Jump forward oparg, then skip following END_FOR and POP_TOP instruction */ -- JUMPBY(oparg + 2); -+ /* Jump forward oparg, then skip following END_FOR */ -+ JUMPBY(oparg + 1); - DISPATCH(); - } - next = PyStackRef_FromPyObjectSteal(next_o); -@@ -2924,14 +3076,14 @@ - - macro(FOR_ITER) = _SPECIALIZE_FOR_ITER + _FOR_ITER; - -+ - inst(INSTRUMENTED_FOR_ITER, (unused/1 -- )) { -- _Py_CODEUNIT *target; - _PyStackRef iter_stackref = TOP(); - PyObject *iter = PyStackRef_AsPyObjectBorrow(iter_stackref); - PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter); - if (next != NULL) { - PUSH(PyStackRef_FromPyObjectSteal(next)); -- target = next_instr; -+ INSTRUMENTED_JUMP(this_instr, next_instr, PY_MONITORING_EVENT_BRANCH_LEFT); - } - else { - if (_PyErr_Occurred(tstate)) { -@@ -2945,14 +3097,12 @@ - /* iterator ended normally */ - assert(next_instr[oparg].op.code == END_FOR || - next_instr[oparg].op.code == INSTRUMENTED_END_FOR); -- STACK_SHRINK(1); -- PyStackRef_CLOSE(iter_stackref); -- /* Skip END_FOR and POP_TOP */ -- target = next_instr + oparg + 2; -+ /* Skip END_FOR */ -+ JUMPBY(oparg + 1); - } -- INSTRUMENTED_JUMP(this_instr, target, PY_MONITORING_EVENT_BRANCH); - } - -+ - op(_ITER_CHECK_LIST, (iter -- iter)) { - EXIT_IF(Py_TYPE(PyStackRef_AsPyObjectBorrow(iter)) != &PyListIter_Type); - } -@@ -2971,10 +3121,8 @@ - Py_DECREF(seq); - } - #endif -- PyStackRef_CLOSE(iter); -- STACK_SHRINK(1); -- /* Jump forward oparg, then skip following END_FOR and POP_TOP instructions */ -- JUMPBY(oparg + 2); -+ /* Jump forward oparg, then skip following END_FOR instruction */ -+ JUMPBY(oparg + 1); - DISPATCH(); - } - } -@@ -3023,10 +3171,8 @@ - it->it_seq = NULL; - Py_DECREF(seq); - } -- PyStackRef_CLOSE(iter); -- STACK_SHRINK(1); -- /* Jump forward oparg, then skip following END_FOR and POP_TOP instructions */ -- JUMPBY(oparg + 2); -+ /* Jump forward oparg, then skip following END_FOR instruction */ -+ JUMPBY(oparg + 1); - DISPATCH(); - } - } -@@ -3067,10 +3213,8 @@ - assert(Py_TYPE(r) == &PyRangeIter_Type); - STAT_INC(FOR_ITER, hit); - if (r->len <= 0) { -- STACK_SHRINK(1); -- PyStackRef_CLOSE(iter); -- // Jump over END_FOR and POP_TOP instructions. -- JUMPBY(oparg + 2); -+ // Jump over END_FOR instruction. -+ JUMPBY(oparg + 1); - DISPATCH(); - } - } -@@ -3216,16 +3360,18 @@ - op(_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, (owner -- owner)) { - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); -- DEOPT_IF(!_PyObject_InlineValues(owner_o)->valid); -+ PyDictValues *ivs = _PyObject_InlineValues(owner_o); -+ DEOPT_IF(!FT_ATOMIC_LOAD_UINT8(ivs->valid)); - } - - op(_GUARD_KEYS_VERSION, (keys_version/2, owner -- owner)) { - PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; -- DEOPT_IF(owner_heap_type->ht_cached_keys->dk_version != keys_version); -+ PyDictKeysObject *keys = owner_heap_type->ht_cached_keys; -+ DEOPT_IF(FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version); - } - -- split op(_LOAD_ATTR_METHOD_WITH_VALUES, (descr/4, owner -- attr, self if (1))) { -+ op(_LOAD_ATTR_METHOD_WITH_VALUES, (descr/4, owner -- attr, self)) { - assert(oparg & 1); - /* Cached method object */ - STAT_INC(LOAD_ATTR, hit); -@@ -3243,7 +3389,7 @@ - _GUARD_KEYS_VERSION + - _LOAD_ATTR_METHOD_WITH_VALUES; - -- op(_LOAD_ATTR_METHOD_NO_DICT, (descr/4, owner -- attr, self if (1))) { -+ op(_LOAD_ATTR_METHOD_NO_DICT, (descr/4, owner -- attr, self)) { - assert(oparg & 1); - assert(Py_TYPE(PyStackRef_AsPyObjectBorrow(owner))->tp_dictoffset == 0); - STAT_INC(LOAD_ATTR, hit); -@@ -3260,7 +3406,7 @@ - unused/2 + - _LOAD_ATTR_METHOD_NO_DICT; - -- op(_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, (descr/4, owner -- attr, unused if (0))) { -+ op(_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, (descr/4, owner -- attr)) { - assert((oparg & 1) == 0); - STAT_INC(LOAD_ATTR, hit); - assert(descr != NULL); -@@ -3275,7 +3421,7 @@ - _GUARD_KEYS_VERSION + - _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES; - -- op(_LOAD_ATTR_NONDESCRIPTOR_NO_DICT, (descr/4, owner -- attr, unused if (0))) { -+ op(_LOAD_ATTR_NONDESCRIPTOR_NO_DICT, (descr/4, owner -- attr)) { - assert((oparg & 1) == 0); - assert(Py_TYPE(PyStackRef_AsPyObjectBorrow(owner))->tp_dictoffset == 0); - STAT_INC(LOAD_ATTR, hit); -@@ -3292,12 +3438,12 @@ - - op(_CHECK_ATTR_METHOD_LAZY_DICT, (dictoffset/1, owner -- owner)) { - char *ptr = ((char *)PyStackRef_AsPyObjectBorrow(owner)) + MANAGED_DICT_OFFSET + dictoffset; -- PyObject *dict = *(PyObject **)ptr; -+ PyObject *dict = FT_ATOMIC_LOAD_PTR_ACQUIRE(*(PyObject **)ptr); - /* This object has a __dict__, just not yet created */ - DEOPT_IF(dict != NULL); - } - -- op(_LOAD_ATTR_METHOD_LAZY_DICT, (descr/4, owner -- attr, self if (1))) { -+ op(_LOAD_ATTR_METHOD_LAZY_DICT, (descr/4, owner -- attr, self)) { - assert(oparg & 1); - STAT_INC(LOAD_ATTR, hit); - assert(descr != NULL); -@@ -3352,6 +3498,7 @@ - } - - op(_MAYBE_EXPAND_METHOD, (callable[1], self_or_null[1], args[oparg] -- func[1], maybe_self[1], args[oparg])) { -+ (void)args; - if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - PyObject *self = ((PyMethodObject *)callable_o)->im_self; -@@ -3369,8 +3516,9 @@ - - // oparg counts all of the args, but *not* self: - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - // Check if the call can be inlined or not -@@ -3382,7 +3530,7 @@ - PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); - _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( - tstate, callable[0], locals, -- args, total_args, NULL, frame -+ arguments, total_args, NULL, frame - ); - // Manipulate stack directly since we leave using DISPATCH_INLINED(). - SYNC_SP(); -@@ -3395,13 +3543,9 @@ - DISPATCH_INLINED(new_frame); - } - /* Callable is not a normal Python function */ -- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { -- PyStackRef_CLOSE(callable[0]); -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -- } -- DEAD(self_or_null); -+ DECREF_INPUTS(); - ERROR_IF(true, error); - } - PyObject *res_o = PyObject_Vectorcall( -@@ -3411,7 +3555,7 @@ - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - if (opcode == INSTRUMENTED_CALL) { - PyObject *arg = total_args == 0 ? -- &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(args[0]); -+ &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(arguments[0]); - if (res_o == NULL) { - _Py_call_instrumentation_exc2( - tstate, PY_MONITORING_EVENT_C_RAISE, -@@ -3427,11 +3571,7 @@ - } - } - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); -- PyStackRef_CLOSE(callable[0]); -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -- } -- DEAD(self_or_null); -+ DECREF_INPUTS(); - ERROR_IF(res_o == NULL, error); - res = PyStackRef_FromPyObjectSteal(res_o); - } -@@ -3516,15 +3656,14 @@ - EXIT_IF(!PyStackRef_IsNull(null[0])); - } - -- op(_EXPAND_METHOD, (callable[1], null[1], unused[oparg] -- method[1], self[1], unused[oparg])) { -+ op(_EXPAND_METHOD, (callable[1], self_or_null[1], unused[oparg] -- callable[1], self_or_null[1], unused[oparg])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); -- assert(PyStackRef_IsNull(null[0])); -- DEAD(null); -+ assert(PyStackRef_IsNull(self_or_null[0])); - assert(Py_TYPE(callable_o) == &PyMethod_Type); -- self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); -+ self_or_null[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); - _PyStackRef temp = callable[0]; -- method[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); -- assert(PyStackRef_FunctionCheck(method[0])); -+ callable[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); -+ assert(PyStackRef_FunctionCheck(callable[0])); - PyStackRef_CLOSE(temp); - } - -@@ -3551,12 +3690,13 @@ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - /* Callable is not a normal Python function */ -- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - DECREF_INPUTS(); - ERROR_IF(true, error); -@@ -3567,11 +3707,7 @@ - NULL); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); -- PyStackRef_CLOSE(callable[0]); -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -- } -- DEAD(self_or_null); -+ DECREF_INPUTS(); - ERROR_IF(res_o == NULL, error); - res = PyStackRef_FromPyObjectSteal(res_o); - } -@@ -3588,13 +3724,13 @@ - EXIT_IF(Py_TYPE(PyStackRef_AsPyObjectBorrow(callable[0])) != &PyMethod_Type); - } - -- op(_INIT_CALL_BOUND_METHOD_EXACT_ARGS, (callable[1], null[1], unused[oparg] -- func[1], self[1], unused[oparg])) { -- DEAD(null); -+ op(_INIT_CALL_BOUND_METHOD_EXACT_ARGS, (callable[1], self_or_null[1], unused[oparg] -- callable[1], self_or_null[1], unused[oparg])) { -+ assert(PyStackRef_IsNull(self_or_null[0])); - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - STAT_INC(CALL, hit); -- self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); -+ self_or_null[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); - _PyStackRef temp = callable[0]; -- func[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); -+ callable[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); - PyStackRef_CLOSE(temp); - } - -@@ -3729,18 +3865,21 @@ - _CHECK_PERIODIC; - - op(_CHECK_AND_ALLOCATE_OBJECT, (type_version/2, callable[1], null[1], args[oparg] -- init[1], self[1], args[oparg])) { -+ (void)args; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - DEOPT_IF(!PyStackRef_IsNull(null[0])); - DEOPT_IF(!PyType_Check(callable_o)); - PyTypeObject *tp = (PyTypeObject *)callable_o; - DEOPT_IF(FT_ATOMIC_LOAD_UINT32_RELAXED(tp->tp_version_tag) != type_version); -- assert(tp->tp_flags & Py_TPFLAGS_INLINE_VALUES); -+ assert(tp->tp_new == PyBaseObject_Type.tp_new); -+ assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE); -+ assert(tp->tp_alloc == PyType_GenericAlloc); - PyHeapTypeObject *cls = (PyHeapTypeObject *)callable_o; - PyFunctionObject *init_func = (PyFunctionObject *)FT_ATOMIC_LOAD_PTR_ACQUIRE(cls->_spec_cache.init); - PyCodeObject *code = (PyCodeObject *)init_func->func_code; - DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize + _Py_InitCleanup.co_framesize)); - STAT_INC(CALL, hit); -- PyObject *self_o = _PyType_NewManagedObject(tp); -+ PyObject *self_o = PyType_GenericAlloc(tp, 0); - if (self_o == NULL) { - ERROR_NO_POP(); - } -@@ -3794,29 +3933,24 @@ - - op(_CALL_BUILTIN_CLASS, (callable[1], self_or_null[1], args[oparg] -- res)) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); -- -+ DEOPT_IF(!PyType_Check(callable_o)); -+ PyTypeObject *tp = (PyTypeObject *)callable_o; - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } -- DEAD(self_or_null); -- DEOPT_IF(!PyType_Check(callable_o)); -- PyTypeObject *tp = (PyTypeObject *)callable_o; - DEOPT_IF(tp->tp_vectorcall == NULL); - STAT_INC(CALL, hit); -- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - DECREF_INPUTS(); - ERROR_IF(true, error); - } - PyObject *res_o = tp->tp_vectorcall((PyObject *)tp, args_o, total_args, NULL); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); -- /* Free the arguments. */ -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -- } -- PyStackRef_CLOSE(callable[0]); -+ DECREF_INPUTS(); - ERROR_IF(res_o == NULL, error); - res = PyStackRef_FromPyObjectSteal(res_o); - } -@@ -3868,17 +4002,17 @@ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } -- DEAD(self_or_null); - DEOPT_IF(!PyCFunction_CheckExact(callable_o)); - DEOPT_IF(PyCFunction_GET_FLAGS(callable_o) != METH_FASTCALL); - STAT_INC(CALL, hit); - PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable_o); - /* res = func(self, args, nargs) */ -- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - DECREF_INPUTS(); - ERROR_IF(true, error); -@@ -3889,12 +4023,7 @@ - total_args); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); -- -- /* Free the arguments. */ -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -- } -- PyStackRef_CLOSE(callable[0]); -+ DECREF_INPUTS(); - ERROR_IF(res_o == NULL, error); - res = PyStackRef_FromPyObjectSteal(res_o); - } -@@ -3910,34 +4039,28 @@ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - DEOPT_IF(!PyCFunction_CheckExact(callable_o)); - DEOPT_IF(PyCFunction_GET_FLAGS(callable_o) != (METH_FASTCALL | METH_KEYWORDS)); - STAT_INC(CALL, hit); -- /* res = func(self, args, nargs, kwnames) */ -+ /* res = func(self, arguments, nargs, kwnames) */ - PyCFunctionFastWithKeywords cfunc = - (PyCFunctionFastWithKeywords)(void(*)(void)) - PyCFunction_GET_FUNCTION(callable_o); - -- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - DECREF_INPUTS(); - ERROR_IF(true, error); - } - PyObject *res_o = cfunc(PyCFunction_GET_SELF(callable_o), args_o, total_args, NULL); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); -- - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); -- -- /* Free the arguments. */ -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -- } -- DEAD(self_or_null); -- PyStackRef_CLOSE(callable[0]); -+ DECREF_INPUTS(); - ERROR_IF(res_o == NULL, error); - res = PyStackRef_FromPyObjectSteal(res_o); - } -@@ -3970,10 +4093,12 @@ - PyObject *res_o = PyLong_FromSsize_t(len_i); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - if (res_o == NULL) { -- GOTO_ERROR(error); -+ ERROR_NO_POP(); - } -- PyStackRef_CLOSE(callable[0]); - PyStackRef_CLOSE(arg_stackref); -+ DEAD(args); -+ DEAD(self_or_null); -+ PyStackRef_CLOSE(callable[0]); - res = PyStackRef_FromPyObjectSteal(res_o); - } - -@@ -3982,25 +4107,24 @@ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - DEOPT_IF(total_args != 2); - PyInterpreterState *interp = tstate->interp; - DEOPT_IF(callable_o != interp->callable_cache.isinstance); - STAT_INC(CALL, hit); -- _PyStackRef cls_stackref = args[1]; -- _PyStackRef inst_stackref = args[0]; -+ _PyStackRef cls_stackref = arguments[1]; -+ _PyStackRef inst_stackref = arguments[0]; - int retval = PyObject_IsInstance(PyStackRef_AsPyObjectBorrow(inst_stackref), PyStackRef_AsPyObjectBorrow(cls_stackref)); - if (retval < 0) { - ERROR_NO_POP(); - } - res = retval ? PyStackRef_True : PyStackRef_False; - assert((!PyStackRef_IsNull(res)) ^ (_PyErr_Occurred(tstate) != NULL)); -- PyStackRef_CLOSE(inst_stackref); -- PyStackRef_CLOSE(cls_stackref); -- PyStackRef_CLOSE(callable[0]); -+ DECREF_INPUTS(); - } - - // This is secretly a super-instruction -@@ -4032,8 +4156,9 @@ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - -@@ -4044,8 +4169,8 @@ - EXIT_IF(meth->ml_flags != METH_O); - // CPython promises to check all non-vectorcall function calls. - EXIT_IF(tstate->c_recursion_remaining <= 0); -- _PyStackRef arg_stackref = args[1]; -- _PyStackRef self_stackref = args[0]; -+ _PyStackRef arg_stackref = arguments[1]; -+ _PyStackRef self_stackref = arguments[0]; - EXIT_IF(!Py_IS_TYPE(PyStackRef_AsPyObjectBorrow(self_stackref), - method->d_common.d_type)); - STAT_INC(CALL, hit); -@@ -4056,11 +4181,7 @@ - PyStackRef_AsPyObjectBorrow(arg_stackref)); - _Py_LeaveRecursiveCallTstate(tstate); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); -- PyStackRef_CLOSE(self_stackref); -- PyStackRef_CLOSE(arg_stackref); -- DEAD(args); -- DEAD(self_or_null); -- PyStackRef_CLOSE(callable[0]); -+ DECREF_INPUTS(); - ERROR_IF(res_o == NULL, error); - res = PyStackRef_FromPyObjectSteal(res_o); - } -@@ -4075,8 +4196,9 @@ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; -@@ -4084,12 +4206,12 @@ - PyMethodDef *meth = method->d_method; - EXIT_IF(meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS)); - PyTypeObject *d_type = method->d_common.d_type; -- PyObject *self = PyStackRef_AsPyObjectBorrow(args[0]); -+ PyObject *self = PyStackRef_AsPyObjectBorrow(arguments[0]); - EXIT_IF(!Py_IS_TYPE(self, d_type)); - STAT_INC(CALL, hit); - int nargs = total_args - 1; - -- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - DECREF_INPUTS(); - ERROR_IF(true, error); -@@ -4099,13 +4221,7 @@ - PyObject *res_o = cfunc(self, (args_o + 1), nargs, NULL); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); -- -- /* Free the arguments. */ -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -- } -- DEAD(self_or_null); -- PyStackRef_CLOSE(callable[0]); -+ DECREF_INPUTS(); - ERROR_IF(res_o == NULL, error); - res = PyStackRef_FromPyObjectSteal(res_o); - } -@@ -4159,8 +4275,9 @@ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; -@@ -4168,12 +4285,12 @@ - EXIT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type)); - PyMethodDef *meth = method->d_method; - EXIT_IF(meth->ml_flags != METH_FASTCALL); -- PyObject *self = PyStackRef_AsPyObjectBorrow(args[0]); -+ PyObject *self = PyStackRef_AsPyObjectBorrow(arguments[0]); - EXIT_IF(!Py_IS_TYPE(self, method->d_common.d_type)); - STAT_INC(CALL, hit); - int nargs = total_args - 1; - -- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - DECREF_INPUTS(); - ERROR_IF(true, error); -@@ -4183,13 +4300,7 @@ - PyObject *res_o = cfunc(self, (args_o + 1), nargs); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); -- -- /* Clear the stack of the arguments. */ -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -- } -- DEAD(self_or_null); -- PyStackRef_CLOSE(callable[0]); -+ DECREF_INPUTS(); - ERROR_IF(res_o == NULL, error); - res = PyStackRef_FromPyObjectSteal(res_o); - } -@@ -4207,21 +4318,27 @@ - CALL_KW_NON_PY, - }; - -- inst(INSTRUMENTED_CALL_KW, (counter/1, version/2 -- )) { -- int is_meth = !PyStackRef_IsNull(PEEK(oparg + 2)); -- int total_args = oparg + is_meth; -- PyObject *function = PyStackRef_AsPyObjectBorrow(PEEK(oparg + 3)); -- PyObject *arg = total_args == 0 ? &_PyInstrumentation_MISSING -- : PyStackRef_AsPyObjectBorrow(PEEK(total_args + 1)); -+ op(_MONITOR_CALL_KW, (callable[1], self_or_null[1], args[oparg], kwnames -- callable[1], self_or_null[1], args[oparg], kwnames)) { -+ int is_meth = !PyStackRef_IsNull(self_or_null[0]); -+ PyObject *arg; -+ if (is_meth) { -+ arg = PyStackRef_AsPyObjectBorrow(self_or_null[0]); -+ } -+ else if (args) { -+ arg = PyStackRef_AsPyObjectBorrow(args[0]); -+ } -+ else { -+ arg = &_PyInstrumentation_MISSING; -+ } -+ PyObject *function = PyStackRef_AsPyObjectBorrow(callable[0]); - int err = _Py_call_instrumentation_2args( - tstate, PY_MONITORING_EVENT_CALL, - frame, this_instr, function, arg); - ERROR_IF(err, error); -- PAUSE_ADAPTIVE_COUNTER(this_instr[1].counter); -- GO_TO_INSTRUCTION(CALL_KW); - } - - op(_MAYBE_EXPAND_METHOD_KW, (callable[1], self_or_null[1], args[oparg], kwnames_in -- func[1], maybe_self[1], args[oparg], kwnames_out)) { -+ (void)args; - if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - PyObject *self = ((PyMethodObject *)callable_o)->im_self; -@@ -4241,8 +4358,9 @@ - - // oparg counts all of the args, but *not* self: - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - int positional_args = total_args - (int)PyTuple_GET_SIZE(kwnames_o); -@@ -4255,7 +4373,7 @@ - PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); - _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( - tstate, callable[0], locals, -- args, positional_args, kwnames_o, frame -+ arguments, positional_args, kwnames_o, frame - ); - PyStackRef_CLOSE(kwnames); - // Sync stack explicitly since we leave using DISPATCH_INLINED(). -@@ -4270,7 +4388,7 @@ - DISPATCH_INLINED(new_frame); - } - /* Callable is not a normal Python function */ -- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - DECREF_INPUTS(); - ERROR_IF(true, error); -@@ -4282,7 +4400,7 @@ - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - if (opcode == INSTRUMENTED_CALL_KW) { - PyObject *arg = total_args == 0 ? -- &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(args[0]); -+ &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(arguments[0]); - if (res_o == NULL) { - _Py_call_instrumentation_exc2( - tstate, PY_MONITORING_EVENT_C_RAISE, -@@ -4297,13 +4415,7 @@ - } - } - } -- PyStackRef_CLOSE(kwnames); -- assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); -- PyStackRef_CLOSE(callable[0]); -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -- } -- DEAD(self_or_null); -+ DECREF_INPUTS(); - ERROR_IF(res_o == NULL, error); - res = PyStackRef_FromPyObjectSteal(res_o); - } -@@ -4313,8 +4425,9 @@ - - // oparg counts all of the args, but *not* self: - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); -@@ -4324,7 +4437,7 @@ - PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); - _PyInterpreterFrame *temp = _PyEvalFramePushAndInit( - tstate, callable[0], locals, -- args, positional_args, kwnames_o, frame -+ arguments, positional_args, kwnames_o, frame - ); - PyStackRef_CLOSE(kwnames); - // The frame has stolen all the arguments from the stack, -@@ -4361,15 +4474,14 @@ - EXIT_IF(!PyStackRef_IsNull(null[0])); - } - -- op(_EXPAND_METHOD_KW, (callable[1], null[1], unused[oparg], unused -- method[1], self[1], unused[oparg], unused)) { -+ op(_EXPAND_METHOD_KW, (callable[1], self_or_null[1], unused[oparg], unused -- callable[1], self_or_null[1], unused[oparg], unused)) { -+ assert(PyStackRef_IsNull(self_or_null[0])); - _PyStackRef callable_s = callable[0]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable_s); -- -- assert(PyStackRef_IsNull(null[0])); - assert(Py_TYPE(callable_o) == &PyMethod_Type); -- self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); -- method[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); -- assert(PyStackRef_FunctionCheck(method[0])); -+ self_or_null[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); -+ callable[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); -+ assert(PyStackRef_FunctionCheck(callable[0])); - PyStackRef_CLOSE(callable_s); - } - -@@ -4401,6 +4513,13 @@ - _MAYBE_EXPAND_METHOD_KW + - _DO_CALL_KW; - -+ macro(INSTRUMENTED_CALL_KW) = -+ counter/1 + -+ unused/2 + -+ _MONITOR_CALL_KW + -+ _MAYBE_EXPAND_METHOD_KW + -+ _DO_CALL_KW; -+ - op(_CHECK_IS_NOT_PY_CALLABLE_KW, (callable[1], unused[1], unused[oparg], kwnames -- callable[1], unused[1], unused[oparg], kwnames)) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - EXIT_IF(PyFunction_Check(callable_o)); -@@ -4415,12 +4534,13 @@ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - /* Callable is not a normal Python function */ -- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - DECREF_INPUTS(); - ERROR_IF(true, error); -@@ -4434,11 +4554,7 @@ - PyStackRef_CLOSE(kwnames); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -- } -- DEAD(self_or_null); -- PyStackRef_CLOSE(callable[0]); -+ DECREF_INPUTS(); - ERROR_IF(res_o == NULL, error); - res = PyStackRef_FromPyObjectSteal(res_o); - } -@@ -4450,14 +4566,12 @@ - _CALL_KW_NON_PY + - _CHECK_PERIODIC; - -- inst(INSTRUMENTED_CALL_FUNCTION_EX, ( -- )) { -- GO_TO_INSTRUCTION(CALL_FUNCTION_EX); -- } -- -- op(_MAKE_CALLARGS_A_TUPLE, (func, unused, callargs, kwargs_in if (oparg & 1) -- func, unused, tuple, kwargs_out if (oparg & 1))) { -+ op(_MAKE_CALLARGS_A_TUPLE, (func, unused, callargs, kwargs_in -- func, unused, tuple, kwargs_out)) { - PyObject *callargs_o = PyStackRef_AsPyObjectBorrow(callargs); - if (PyTuple_CheckExact(callargs_o)) { - tuple = callargs; -+ kwargs_out = kwargs_in; -+ DEAD(kwargs_in); - DEAD(callargs); - } - else { -@@ -4469,26 +4583,27 @@ - if (tuple_o == NULL) { - ERROR_NO_POP(); - } -+ kwargs_out = kwargs_in; -+ DEAD(kwargs_in); - PyStackRef_CLOSE(callargs); - tuple = PyStackRef_FromPyObjectSteal(tuple_o); - } -- kwargs_out = kwargs_in; -- DEAD(kwargs_in); - } - -- op(_DO_CALL_FUNCTION_EX, (func_st, unused, callargs_st, kwargs_st if (oparg & 1) -- result)) { -+ op(_DO_CALL_FUNCTION_EX, (func_st, null, callargs_st, kwargs_st -- result)) { -+ (void)null; - PyObject *func = PyStackRef_AsPyObjectBorrow(func_st); -- PyObject *callargs = PyStackRef_AsPyObjectBorrow(callargs_st); -- PyObject *kwargs = PyStackRef_AsPyObjectBorrow(kwargs_st); - - // DICT_MERGE is called before this opcode if there are kwargs. - // It converts all dict subtypes in kwargs into regular dicts. -- assert(kwargs == NULL || PyDict_CheckExact(kwargs)); -- assert(PyTuple_CheckExact(callargs)); - EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_FUNCTION_EX, func); - PyObject *result_o; - assert(!_PyErr_Occurred(tstate)); - if (opcode == INSTRUMENTED_CALL_FUNCTION_EX) { -+ PyObject *callargs = PyStackRef_AsPyObjectBorrow(callargs_st); -+ PyObject *kwargs = PyStackRef_AsPyObjectBorrow(kwargs_st); -+ assert(kwargs == NULL || PyDict_CheckExact(kwargs)); -+ assert(PyTuple_CheckExact(callargs)); - PyObject *arg = PyTuple_GET_SIZE(callargs) > 0 ? - PyTuple_GET_ITEM(callargs, 0) : &_PyInstrumentation_MISSING; - int err = _Py_call_instrumentation_2args( -@@ -4519,7 +4634,10 @@ - if (Py_TYPE(func) == &PyFunction_Type && - tstate->interp->eval_frame == NULL && - ((PyFunctionObject *)func)->vectorcall == _PyFunction_Vectorcall) { -+ PyObject *callargs = PyStackRef_AsPyObjectSteal(callargs_st); - assert(PyTuple_CheckExact(callargs)); -+ PyObject *kwargs = PyStackRef_IsNull(kwargs_st) ? NULL : PyStackRef_AsPyObjectSteal(kwargs_st); -+ assert(kwargs == NULL || PyDict_CheckExact(kwargs)); - Py_ssize_t nargs = PyTuple_GET_SIZE(callargs); - int code_flags = ((PyCodeObject *)PyFunction_GET_CODE(func))->co_flags; - PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(func)); -@@ -4537,11 +4655,15 @@ - frame->return_offset = 1; - DISPATCH_INLINED(new_frame); - } -+ PyObject *callargs = PyStackRef_AsPyObjectBorrow(callargs_st); -+ assert(PyTuple_CheckExact(callargs)); -+ PyObject *kwargs = PyStackRef_AsPyObjectBorrow(kwargs_st); -+ assert(kwargs == NULL || PyDict_CheckExact(kwargs)); - result_o = PyObject_Call(func, callargs, kwargs); - } - PyStackRef_XCLOSE(kwargs_st); -- DEAD(kwargs_st); - PyStackRef_CLOSE(callargs_st); -+ DEAD(null); - PyStackRef_CLOSE(func_st); - ERROR_IF(result_o == NULL, error); - result = PyStackRef_FromPyObjectSteal(result_o); -@@ -4552,6 +4674,10 @@ - _DO_CALL_FUNCTION_EX + - _CHECK_PERIODIC; - -+ macro(INSTRUMENTED_CALL_FUNCTION_EX) = -+ _MAKE_CALLARGS_A_TUPLE + -+ _DO_CALL_FUNCTION_EX + -+ _CHECK_PERIODIC; - - inst(MAKE_FUNCTION, (codeobj_st -- func)) { - PyObject *codeobj = PyStackRef_AsPyObjectBorrow(codeobj_st); -@@ -4603,11 +4729,10 @@ - LLTRACE_RESUME_FRAME(); - } - -- inst(BUILD_SLICE, (start, stop, step if (oparg == 3) -- slice)) { -- PyObject *start_o = PyStackRef_AsPyObjectBorrow(start); -- PyObject *stop_o = PyStackRef_AsPyObjectBorrow(stop); -- PyObject *step_o = PyStackRef_AsPyObjectBorrow(step); -- -+ inst(BUILD_SLICE, (args[oparg] -- slice)) { -+ PyObject *start_o = PyStackRef_AsPyObjectBorrow(args[0]); -+ PyObject *stop_o = PyStackRef_AsPyObjectBorrow(args[1]); -+ PyObject *step_o = oparg == 3 ? PyStackRef_AsPyObjectBorrow(args[2]) : NULL; - PyObject *slice_o = PySlice_New(start_o, stop_o, step_o); - DECREF_INPUTS(); - ERROR_IF(slice_o == NULL, error); -@@ -4642,8 +4767,7 @@ - - inst(FORMAT_WITH_SPEC, (value, fmt_spec -- res)) { - PyObject *res_o = PyObject_Format(PyStackRef_AsPyObjectBorrow(value), PyStackRef_AsPyObjectBorrow(fmt_spec)); -- PyStackRef_CLOSE(value); -- PyStackRef_CLOSE(fmt_spec); -+ DECREF_INPUTS(); - ERROR_IF(res_o == NULL, error); - res = PyStackRef_FromPyObjectSteal(res_o); - } -@@ -4664,7 +4788,7 @@ - ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ - assert(NB_ADD <= oparg); -- assert(oparg <= NB_INPLACE_XOR); -+ assert(oparg <= NB_OPARG_LAST); - } - - op(_BINARY_OP, (lhs, rhs -- res)) { -@@ -4678,14 +4802,13 @@ - res = PyStackRef_FromPyObjectSteal(res_o); - } - -- macro(BINARY_OP) = _SPECIALIZE_BINARY_OP + _BINARY_OP; -+ macro(BINARY_OP) = _SPECIALIZE_BINARY_OP + unused/4 + _BINARY_OP; - -- pure inst(SWAP, (bottom_in, unused[oparg-2], top_in -- -- top_out, unused[oparg-2], bottom_out)) { -- bottom_out = bottom_in; -- DEAD(bottom_in); -- top_out = top_in; -- DEAD(top_in); -+ pure inst(SWAP, (bottom[1], unused[oparg-2], top[1] -- -+ bottom[1], unused[oparg-2], top[1])) { -+ _PyStackRef temp = bottom[0]; -+ bottom[0] = top[0]; -+ top[0] = temp; - assert(oparg >= 2); - } - -@@ -4693,7 +4816,8 @@ - int original_opcode = 0; - if (tstate->tracing) { - PyCodeObject *code = _PyFrame_GetCode(frame); -- original_opcode = code->_co_monitoring->lines[(int)(this_instr - _PyFrame_GetBytecode(frame))].original_opcode; -+ int index = (int)(this_instr - _PyFrame_GetBytecode(frame)); -+ original_opcode = code->_co_monitoring->lines->data[index*code->_co_monitoring->lines->bytes_per_entry]; - next_instr = this_instr; - } else { - original_opcode = _Py_call_instrumentation_line( -@@ -4738,6 +4862,11 @@ - INSTRUMENTED_JUMP(this_instr, next_instr - oparg, PY_MONITORING_EVENT_JUMP); - } - -+ inst(INSTRUMENTED_NOT_TAKEN, ( -- )) { -+ (void)this_instr; // INSTRUMENTED_JUMP requires this_instr -+ INSTRUMENTED_JUMP(prev_instr, next_instr, PY_MONITORING_EVENT_BRANCH_LEFT); -+ } -+ - macro(INSTRUMENTED_JUMP_BACKWARD) = - unused/1 + - _CHECK_PERIODIC + -@@ -4746,51 +4875,43 @@ - inst(INSTRUMENTED_POP_JUMP_IF_TRUE, (unused/1 -- )) { - _PyStackRef cond = POP(); - assert(PyStackRef_BoolCheck(cond)); -- int flag = PyStackRef_IsTrue(cond); -- int offset = flag * oparg; -- RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); -- INSTRUMENTED_JUMP(this_instr, next_instr + offset, PY_MONITORING_EVENT_BRANCH); -+ int jump = PyStackRef_IsTrue(cond); -+ RECORD_BRANCH_TAKEN(this_instr[1].cache, jump); -+ if (jump) { -+ INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT); -+ } - } - - inst(INSTRUMENTED_POP_JUMP_IF_FALSE, (unused/1 -- )) { - _PyStackRef cond = POP(); - assert(PyStackRef_BoolCheck(cond)); -- int flag = PyStackRef_IsFalse(cond); -- int offset = flag * oparg; -- RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); -- INSTRUMENTED_JUMP(this_instr, next_instr + offset, PY_MONITORING_EVENT_BRANCH); -+ int jump = PyStackRef_IsFalse(cond); -+ RECORD_BRANCH_TAKEN(this_instr[1].cache, jump); -+ if (jump) { -+ INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT); -+ } - } - - inst(INSTRUMENTED_POP_JUMP_IF_NONE, (unused/1 -- )) { - _PyStackRef value_stackref = POP(); -- int flag = PyStackRef_IsNone(value_stackref); -- int offset; -- if (flag) { -- offset = oparg; -+ int jump = PyStackRef_IsNone(value_stackref); -+ RECORD_BRANCH_TAKEN(this_instr[1].cache, jump); -+ if (jump) { -+ INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT); - } - else { - PyStackRef_CLOSE(value_stackref); -- offset = 0; - } -- RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); -- INSTRUMENTED_JUMP(this_instr, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - } - - inst(INSTRUMENTED_POP_JUMP_IF_NOT_NONE, (unused/1 -- )) { - _PyStackRef value_stackref = POP(); -- int offset; -- int nflag = PyStackRef_IsNone(value_stackref); -- if (nflag) { -- offset = 0; -- } -- else { -+ int jump = !PyStackRef_IsNone(value_stackref); -+ RECORD_BRANCH_TAKEN(this_instr[1].cache, jump); -+ if (jump) { - PyStackRef_CLOSE(value_stackref); -- offset = oparg; -+ INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT); - } -- #if ENABLE_SPECIALIZATION -- this_instr[1].cache = (this_instr[1].cache << 1) | !nflag; -- #endif -- INSTRUMENTED_JUMP(this_instr, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - } - - tier1 inst(EXTENDED_ARG, ( -- )) { -@@ -4873,10 +4994,10 @@ - _Py_CODEUNIT *target = _PyFrame_GetBytecode(frame) + exit->target; - #if defined(Py_DEBUG) && !defined(_Py_JIT) - OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); -- if (lltrace >= 2) { -+ if (frame->lltrace >= 2) { - printf("SIDE EXIT: [UOp "); - _PyUOpPrint(&next_uop[-1]); -- printf(", exit %u, temp %d, target %d -> %s]\n", -+ printf(", exit %lu, temp %d, target %d -> %s]\n", - exit - current_executor->exits, exit->temperature.value_and_backoff, - (int)(target - _PyFrame_GetBytecode(frame)), - _PyOpcode_OpName[target->op.code]); -@@ -4886,11 +5007,11 @@ - exit->temperature = initial_temperature_backoff_counter(); - Py_CLEAR(exit->executor); - } -+ tstate->previous_executor = (PyObject *)current_executor; - if (exit->executor == NULL) { - _Py_BackoffCounter temperature = exit->temperature; - if (!backoff_counter_triggers(temperature)) { - exit->temperature = advance_backoff_counter(temperature); -- tstate->previous_executor = (PyObject *)current_executor; - GOTO_TIER_ONE(target); - } - _PyExecutorObject *executor; -@@ -4900,23 +5021,16 @@ - } - else { - int chain_depth = current_executor->vm_data.chain_depth + 1; -- int optimized = _PyOptimizer_Optimize(frame, target, stack_pointer, &executor, chain_depth); -+ int optimized = _PyOptimizer_Optimize(frame, target, &executor, chain_depth); - if (optimized <= 0) { - exit->temperature = restart_backoff_counter(temperature); -- if (optimized < 0) { -- GOTO_UNWIND(); -- } -- tstate->previous_executor = (PyObject *)current_executor; -- GOTO_TIER_ONE(target); -- } -- else { -- exit->temperature = initial_temperature_backoff_counter(); -+ GOTO_TIER_ONE(optimized < 0 ? NULL : target); - } -+ exit->temperature = initial_temperature_backoff_counter(); - } - exit->executor = executor; - } - Py_INCREF(exit->executor); -- tstate->previous_executor = (PyObject *)current_executor; - GOTO_TIER_TWO(exit->executor); - } - -@@ -4937,43 +5051,31 @@ - value = PyStackRef_FromPyObjectImmortal(ptr); - } - -- tier2 pure op(_LOAD_CONST_INLINE_WITH_NULL, (ptr/4 -- value, null)) { -- value = PyStackRef_FromPyObjectNew(ptr); -- null = PyStackRef_NULL; -- } -- -- tier2 pure op(_LOAD_CONST_INLINE_BORROW_WITH_NULL, (ptr/4 -- value, null)) { -- value = PyStackRef_FromPyObjectImmortal(ptr); -- null = PyStackRef_NULL; -- } -- - tier2 op(_CHECK_FUNCTION, (func_version/2 -- )) { - assert(PyStackRef_FunctionCheck(frame->f_funcobj)); - PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj); - DEOPT_IF(func->func_version != func_version); - } - -- tier2 op(_LOAD_GLOBAL_MODULE, (index/1 -- res, null if (oparg & 1))) { -+ tier2 op(_LOAD_GLOBAL_MODULE, (index/1 -- res)) { - PyDictObject *dict = (PyDictObject *)GLOBALS(); - PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); - PyObject *res_o = entries[index].me_value; - DEOPT_IF(res_o == NULL); - Py_INCREF(res_o); - res = PyStackRef_FromPyObjectSteal(res_o); -- null = PyStackRef_NULL; - } - -- tier2 op(_LOAD_GLOBAL_BUILTINS, (index/1 -- res, null if (oparg & 1))) { -+ tier2 op(_LOAD_GLOBAL_BUILTINS, (index/1 -- res)) { - PyDictObject *dict = (PyDictObject *)BUILTINS(); - PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); - PyObject *res_o = entries[index].me_value; - DEOPT_IF(res_o == NULL); - Py_INCREF(res_o); - res = PyStackRef_FromPyObjectSteal(res_o); -- null = PyStackRef_NULL; - } - -- tier2 op(_LOAD_ATTR_MODULE, (index/1, owner -- attr, null if (oparg & 1))) { -+ tier2 op(_LOAD_ATTR_MODULE, (index/1, owner -- attr)) { - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner_o)->md_dict; - assert(dict->ma_keys->dk_kind == DICT_KEYS_UNICODE); -@@ -4984,61 +5086,11 @@ - STAT_INC(LOAD_ATTR, hit); - Py_INCREF(attr_o); - attr = PyStackRef_FromPyObjectSteal(attr_o); -- null = PyStackRef_NULL; - DECREF_INPUTS(); - } - -- /* Internal -- for testing executors */ -- op(_INTERNAL_INCREMENT_OPT_COUNTER, (opt --)) { -- _PyCounterOptimizerObject *exe = (_PyCounterOptimizerObject *)PyStackRef_AsPyObjectBorrow(opt); -- exe->count++; -- DEAD(opt); -- } -- -- tier2 op(_DYNAMIC_EXIT, (exit_p/4 --)) { -- tstate->previous_executor = (PyObject *)current_executor; -- _PyExitData *exit = (_PyExitData *)exit_p; -- _Py_CODEUNIT *target = frame->instr_ptr; -- #if defined(Py_DEBUG) && !defined(_Py_JIT) -- OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); -- if (lltrace >= 2) { -- printf("DYNAMIC EXIT: [UOp "); -- _PyUOpPrint(&next_uop[-1]); -- printf(", exit %u, temp %d, target %d -> %s]\n", -- exit - current_executor->exits, exit->temperature.value_and_backoff, -- (int)(target - _PyFrame_GetBytecode(frame)), -- _PyOpcode_OpName[target->op.code]); -- } -- #endif -- _PyExecutorObject *executor; -- if (target->op.code == ENTER_EXECUTOR) { -- PyCodeObject *code = _PyFrame_GetCode(frame); -- executor = code->co_executors->executors[target->op.arg]; -- Py_INCREF(executor); -- } -- else { -- if (!backoff_counter_triggers(exit->temperature)) { -- exit->temperature = advance_backoff_counter(exit->temperature); -- GOTO_TIER_ONE(target); -- } -- int optimized = _PyOptimizer_Optimize(frame, target, stack_pointer, &executor, 0); -- if (optimized <= 0) { -- exit->temperature = restart_backoff_counter(exit->temperature); -- if (optimized < 0) { -- GOTO_UNWIND(); -- } -- GOTO_TIER_ONE(target); -- } -- else { -- exit->temperature = initial_temperature_backoff_counter(); -- } -- } -- GOTO_TIER_TWO(executor); -- } -- - tier2 op(_START_EXECUTOR, (executor/4 --)) { -- Py_DECREF(tstate->previous_executor); -- tstate->previous_executor = NULL; -+ Py_CLEAR(tstate->previous_executor); - #ifndef _Py_JIT - current_executor = (_PyExecutorObject*)executor; - #endif -@@ -5064,13 +5116,16 @@ - } - - tier2 op(_DEOPT, (--)) { -- EXIT_TO_TIER1(); -+ tstate->previous_executor = (PyObject *)current_executor; -+ GOTO_TIER_ONE(_PyFrame_GetBytecode(frame) + CURRENT_TARGET()); - } - -- tier2 op(_ERROR_POP_N, (target/2, unused[oparg] --)) { -+ tier2 op(_ERROR_POP_N, (target/2 --)) { -+ tstate->previous_executor = (PyObject *)current_executor; -+ assert(oparg == 0); - frame->instr_ptr = _PyFrame_GetBytecode(frame) + target; - SYNC_SP(); -- GOTO_UNWIND(); -+ GOTO_TIER_ONE(NULL); - } - - /* Progress is guaranteed if we DEOPT on the eval breaker, because -@@ -5085,6 +5140,151 @@ - assert(tstate->tracing || eval_breaker == FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version)); - } - -+ label(pop_4_error) { -+ STACK_SHRINK(4); -+ goto error; -+ } -+ -+ label(pop_3_error) { -+ STACK_SHRINK(3); -+ goto error; -+ } -+ -+ label(pop_2_error) { -+ STACK_SHRINK(2); -+ goto error; -+ } -+ -+ label(pop_1_error) { -+ STACK_SHRINK(1); -+ goto error; -+ } -+ -+ label(error) { -+ /* Double-check exception status. */ -+#ifdef NDEBUG -+ if (!_PyErr_Occurred(tstate)) { -+ _PyErr_SetString(tstate, PyExc_SystemError, -+ "error return without exception set"); -+ } -+#else -+ assert(_PyErr_Occurred(tstate)); -+#endif -+ -+ /* Log traceback info. */ -+ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); -+ if (!_PyFrame_IsIncomplete(frame)) { -+ PyFrameObject *f = _PyFrame_GetFrameObject(frame); -+ if (f != NULL) { -+ PyTraceBack_Here(f); -+ } -+ } -+ _PyEval_MonitorRaise(tstate, frame, next_instr-1); -+ goto exception_unwind; -+ } -+ -+ spilled label(exception_unwind) { -+ /* We can't use frame->instr_ptr here, as RERAISE may have set it */ -+ int offset = INSTR_OFFSET()-1; -+ int level, handler, lasti; -+ int handled = get_exception_handler(_PyFrame_GetCode(frame), offset, &level, &handler, &lasti); -+ if (handled == 0) { -+ // No handlers, so exit. -+ assert(_PyErr_Occurred(tstate)); -+ /* Pop remaining stack entries. */ -+ _PyStackRef *stackbase = _PyFrame_Stackbase(frame); -+ while (frame->stackpointer > stackbase) { -+ _PyStackRef ref = _PyFrame_StackPop(frame); -+ PyStackRef_XCLOSE(ref); -+ } -+ monitor_unwind(tstate, frame, next_instr-1); -+ goto exit_unwind; -+ } -+ assert(STACK_LEVEL() >= level); -+ _PyStackRef *new_top = _PyFrame_Stackbase(frame) + level; -+ assert(frame->stackpointer >= new_top); -+ while (frame->stackpointer > new_top) { -+ _PyStackRef ref = _PyFrame_StackPop(frame); -+ PyStackRef_XCLOSE(ref); -+ } -+ if (lasti) { -+ int frame_lasti = _PyInterpreterFrame_LASTI(frame); -+ PyObject *lasti = PyLong_FromLong(frame_lasti); -+ if (lasti == NULL) { -+ goto exception_unwind; -+ } -+ _PyFrame_StackPush(frame, PyStackRef_FromPyObjectSteal(lasti)); -+ } -+ -+ /* Make the raw exception data -+ available to the handler, -+ so a program can emulate the -+ Python main loop. */ -+ PyObject *exc = _PyErr_GetRaisedException(tstate); -+ _PyFrame_StackPush(frame, PyStackRef_FromPyObjectSteal(exc)); -+ next_instr = _PyFrame_GetBytecode(frame) + handler; -+ -+ int err = monitor_handled(tstate, frame, next_instr, exc); -+ if (err < 0) { -+ goto exception_unwind; -+ } -+ /* Resume normal execution */ -+#ifdef Py_DEBUG -+ if (frame->lltrace >= 5) { -+ lltrace_resume_frame(frame); -+ } -+#endif -+ RELOAD_STACK(); -+#ifdef Py_TAIL_CALL_INTERP -+ int opcode; -+#endif -+ DISPATCH(); -+ } -+ -+ spilled label(exit_unwind) { -+ assert(_PyErr_Occurred(tstate)); -+ _Py_LeaveRecursiveCallPy(tstate); -+ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); -+ // GH-99729: We need to unlink the frame *before* clearing it: -+ _PyInterpreterFrame *dying = frame; -+ frame = tstate->current_frame = dying->previous; -+ _PyEval_FrameClearAndPop(tstate, dying); -+ frame->return_offset = 0; -+ if (frame->owner == FRAME_OWNED_BY_INTERPRETER) { -+ /* Restore previous frame and exit */ -+ tstate->current_frame = frame->previous; -+ tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS; -+ return NULL; -+ } -+ next_instr = frame->instr_ptr; -+ RELOAD_STACK(); -+ goto error; -+ } -+ -+ spilled label(start_frame) { -+ int too_deep = _Py_EnterRecursivePy(tstate); -+ if (too_deep) { -+ goto exit_unwind; -+ } -+ next_instr = frame->instr_ptr; -+ -+ LLTRACE_RESUME_FRAME(); -+ -+ #ifdef Py_DEBUG -+ /* _PyEval_EvalFrameDefault() must not be called with an exception set, -+ because it can clear it (directly or indirectly) and so the -+ caller loses its exception */ -+ assert(!_PyErr_Occurred(tstate)); -+ #endif -+ RELOAD_STACK(); -+#ifdef Py_TAIL_CALL_INTERP -+ int opcode; -+#endif -+ DISPATCH(); -+ } -+ -+ -+ - // END BYTECODES // - - } -@@ -5094,7 +5294,6 @@ - exit_unwind: - handle_eval_breaker: - resume_frame: -- resume_with_error: - start_frame: - unbound_local_error: - ; -diff --git a/Python/ceval.c b/Python/ceval.c -index fd891d78391..5f8f0ae69ef 100644 ---- a/Python/ceval.c -+++ b/Python/ceval.c -@@ -27,6 +27,7 @@ - #include "pycore_range.h" // _PyRangeIterObject - #include "pycore_setobject.h" // _PySet_Update() - #include "pycore_sliceobject.h" // _PyBuildSlice_ConsumeRefs -+#include "pycore_traceback.h" // _PyTraceBack_FromFrame - #include "pycore_tuple.h" // _PyTuple_ITEMS() - #include "pycore_uop_ids.h" // Uops - #include "pycore_pyerrors.h" -@@ -42,11 +43,6 @@ - - #include // bool - --#ifdef Py_DEBUG -- /* For debugging the interpreter: */ --# define LLTRACE 1 /* Low-level trace feature */ --#endif -- - #if !defined(Py_BUILD_CORE) - # error "ceval.c must be build with Py_BUILD_CORE define for best performance" - #endif -@@ -135,7 +131,7 @@ - #endif - - --#ifdef LLTRACE -+#ifdef Py_DEBUG - static void - dump_stack(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer) - { -@@ -164,7 +160,7 @@ - PyErr_Clear(); - } - // Don't call __repr__(), it might recurse into the interpreter. -- printf("<%s at %p>", Py_TYPE(obj)->tp_name, (void *)(ptr->bits)); -+ printf("<%s at %p>", Py_TYPE(obj)->tp_name, PyStackRef_AsPyObjectBorrow(*ptr)); - } - printf("]\n"); - fflush(stdout); -@@ -178,7 +174,7 @@ - int opcode, - int oparg) - { -- if (frame->owner == FRAME_OWNED_BY_CSTACK) { -+ if (frame->owner >= FRAME_OWNED_BY_INTERPRETER) { - return; - } - dump_stack(frame, stack_pointer); -@@ -193,6 +189,7 @@ - } - fflush(stdout); - } -+ - static void - lltrace_resume_frame(_PyInterpreterFrame *frame) - { -@@ -229,12 +226,12 @@ - } - - static int --maybe_lltrace_resume_frame(_PyInterpreterFrame *frame, _PyInterpreterFrame *skip_frame, PyObject *globals) -+maybe_lltrace_resume_frame(_PyInterpreterFrame *frame, PyObject *globals) - { - if (globals == NULL) { - return 0; - } -- if (frame == skip_frame) { -+ if (frame->owner >= FRAME_OWNED_BY_INTERPRETER) { - return 0; - } - int r = PyDict_Contains(globals, &_Py_ID(__lltrace__)); -@@ -294,6 +291,7 @@ - Py_SetRecursionLimit(int new_limit) - { - PyInterpreterState *interp = _PyInterpreterState_GET(); -+ _PyEval_StopTheWorld(interp); - interp->ceval.recursion_limit = new_limit; - _Py_FOR_EACH_TSTATE_BEGIN(interp, p) { - int depth = p->py_recursion_limit - p->py_recursion_remaining; -@@ -301,6 +299,7 @@ - p->py_recursion_remaining = new_limit - depth; - } - _Py_FOR_EACH_TSTATE_END(interp); -+ _PyEval_StartTheWorld(interp); - } - - /* The function _Py_EnterRecursiveCallTstate() only calls _Py_CheckRecursiveCall() -@@ -363,6 +362,7 @@ - [NB_INPLACE_SUBTRACT] = PyNumber_InPlaceSubtract, - [NB_INPLACE_TRUE_DIVIDE] = PyNumber_InPlaceTrueDivide, - [NB_INPLACE_XOR] = PyNumber_InPlaceXor, -+ [NB_SUBSCR] = PyObject_GetItem, - }; - - const conversion_func _PyEval_ConversionFuncs[4] = { -@@ -764,15 +764,10 @@ - #define PY_EVAL_C_STACK_UNITS 2 - - --/* _PyEval_EvalFrameDefault is too large to optimize for speed with PGO on MSVC -- when the JIT is enabled or GIL is disabled. Disable that optimization around -- this function only. If this is fixed upstream, we should gate this on the -- version of MSVC. -+/* _PyEval_EvalFrameDefault is too large to optimize for speed with PGO on MSVC. - */ - #if (defined(_MSC_VER) && \ -- defined(_Py_USING_PGO) && \ -- (defined(_Py_JIT) || \ -- defined(Py_GIL_DISABLED))) -+ defined(_Py_USING_PGO)) - #define DO_NOT_OPTIMIZE_INTERP_LOOP - #endif - -@@ -781,13 +776,18 @@ - /* This setting is reversed below following _PyEval_EvalFrameDefault */ - #endif - -+#ifdef Py_TAIL_CALL_INTERP -+#include "opcode_targets.h" -+#include "generated_cases.c.h" -+#endif -+ - PyObject* _Py_HOT_FUNCTION - _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwflag) - { - _Py_EnsureTstateNotNULL(tstate); - CALL_STAT_INC(pyeval_calls); - --#if USE_COMPUTED_GOTOS -+#if USE_COMPUTED_GOTOS && !defined(Py_TAIL_CALL_INTERP) - /* Import the static jump table */ - #include "opcode_targets.h" - #endif -@@ -795,17 +795,24 @@ - #ifdef Py_STATS - int lastopcode = 0; - #endif -+#ifndef Py_TAIL_CALL_INTERP - uint8_t opcode; /* Current opcode */ - int oparg; /* Current opcode argument, if any */ --#ifdef LLTRACE -- int lltrace = 0; - #endif -+ _PyInterpreterFrame entry_frame; - -- _PyInterpreterFrame entry_frame; -- -+ if (_Py_EnterRecursiveCallTstate(tstate, "")) { -+ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); -+ _PyEval_FrameClearAndPop(tstate, frame); -+ return NULL; -+ } - -+ /* Local "register" variables. -+ * These are cached values from the frame and code object. */ -+ _Py_CODEUNIT *next_instr; -+ _PyStackRef *stack_pointer; - --#ifdef Py_DEBUG -+#if defined(Py_DEBUG) && !defined(Py_STACKREF_DEBUG) - /* Set these to invalid but identifiable values for debugging. */ - entry_frame.f_funcobj = (_PyStackRef){.bits = 0xaaa0}; - entry_frame.f_locals = (PyObject*)0xaaa1; -@@ -816,218 +823,61 @@ - entry_frame.f_executable = PyStackRef_None; - entry_frame.instr_ptr = (_Py_CODEUNIT *)_Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS + 1; - entry_frame.stackpointer = entry_frame.localsplus; -- entry_frame.owner = FRAME_OWNED_BY_CSTACK; -+ entry_frame.owner = FRAME_OWNED_BY_INTERPRETER; - entry_frame.visited = 0; - entry_frame.return_offset = 0; -+#ifdef Py_DEBUG -+ entry_frame.lltrace = 0; -+#endif - /* Push frame */ - entry_frame.previous = tstate->current_frame; - frame->previous = &entry_frame; - tstate->current_frame = frame; - - tstate->c_recursion_remaining -= (PY_EVAL_C_STACK_UNITS - 1); -- if (_Py_EnterRecursiveCallTstate(tstate, "")) { -- tstate->c_recursion_remaining--; -- tstate->py_recursion_remaining--; -- goto exit_unwind; -- } - - /* support for generator.throw() */ - if (throwflag) { - if (_Py_EnterRecursivePy(tstate)) { -- goto exit_unwind; -+ goto early_exit; - } -- /* Because this avoids the RESUME, -- * we need to update instrumentation */ - #ifdef Py_GIL_DISABLED - /* Load thread-local bytecode */ - if (frame->tlbc_index != ((_PyThreadStateImpl *)tstate)->tlbc_index) { - _Py_CODEUNIT *bytecode = - _PyEval_GetExecutableCode(tstate, _PyFrame_GetCode(frame)); - if (bytecode == NULL) { -- goto error; -+ goto early_exit; - } - ptrdiff_t off = frame->instr_ptr - _PyFrame_GetBytecode(frame); - frame->tlbc_index = ((_PyThreadStateImpl *)tstate)->tlbc_index; - frame->instr_ptr = bytecode + off; - } - #endif -+ /* Because this avoids the RESUME, we need to update instrumentation */ - _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp); -- monitor_throw(tstate, frame, frame->instr_ptr); -- /* TO DO -- Monitor throw entry. */ -- goto resume_with_error; -+ next_instr = frame->instr_ptr; -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ monitor_throw(tstate, frame, next_instr); -+#ifdef Py_TAIL_CALL_INTERP -+ return _TAIL_CALL_error(frame, stack_pointer, tstate, next_instr, 0); -+#else -+ goto error; -+#endif - } - -- /* Local "register" variables. -- * These are cached values from the frame and code object. */ -- _Py_CODEUNIT *next_instr; -- _PyStackRef *stack_pointer; -- - #if defined(_Py_TIER2) && !defined(_Py_JIT) - /* Tier 2 interpreter state */ - _PyExecutorObject *current_executor = NULL; - const _PyUOpInstruction *next_uop = NULL; - #endif - --start_frame: -- if (_Py_EnterRecursivePy(tstate)) { -- goto exit_unwind; -- } -- -- next_instr = frame->instr_ptr; --resume_frame: -- stack_pointer = _PyFrame_GetStackPointer(frame); -- --#ifdef LLTRACE -- lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); -- if (lltrace < 0) { -- goto exit_unwind; -- } --#endif -- --#ifdef Py_DEBUG -- /* _PyEval_EvalFrameDefault() must not be called with an exception set, -- because it can clear it (directly or indirectly) and so the -- caller loses its exception */ -- assert(!_PyErr_Occurred(tstate)); --#endif -- -- DISPATCH(); -- -- { -- /* Start instructions */ --#if !USE_COMPUTED_GOTOS -- dispatch_opcode: -- switch (opcode) --#endif -- { -- --#include "generated_cases.c.h" -- -- --#if USE_COMPUTED_GOTOS -- _unknown_opcode: -+#ifdef Py_TAIL_CALL_INTERP -+ return _TAIL_CALL_start_frame(frame, NULL, tstate, NULL, 0); - #else -- EXTRA_CASES // From pycore_opcode_metadata.h, a 'case' for each unused opcode --#endif -- /* Tell C compilers not to hold the opcode variable in the loop. -- next_instr points the current instruction without TARGET(). */ -- opcode = next_instr->op.code; -- _PyErr_Format(tstate, PyExc_SystemError, -- "%U:%d: unknown opcode %d", -- _PyFrame_GetCode(frame)->co_filename, -- PyUnstable_InterpreterFrame_GetLine(frame), -- opcode); -- goto error; -- -- } /* End instructions */ -- -- /* This should never be reached. Every opcode should end with DISPATCH() -- or goto error. */ -- Py_UNREACHABLE(); -- --pop_4_error: -- STACK_SHRINK(1); --pop_3_error: -- STACK_SHRINK(1); --pop_2_error: -- STACK_SHRINK(1); --pop_1_error: -- STACK_SHRINK(1); --error: -- /* Double-check exception status. */ --#ifdef NDEBUG -- if (!_PyErr_Occurred(tstate)) { -- _PyErr_SetString(tstate, PyExc_SystemError, -- "error return without exception set"); -- } --#else -- assert(_PyErr_Occurred(tstate)); --#endif -- -- /* Log traceback info. */ -- assert(frame != &entry_frame); -- if (!_PyFrame_IsIncomplete(frame)) { -- PyFrameObject *f = _PyFrame_GetFrameObject(frame); -- if (f != NULL) { -- PyTraceBack_Here(f); -- } -- } -- _PyEval_MonitorRaise(tstate, frame, next_instr-1); --exception_unwind: -- { -- /* We can't use frame->instr_ptr here, as RERAISE may have set it */ -- int offset = INSTR_OFFSET()-1; -- int level, handler, lasti; -- if (get_exception_handler(_PyFrame_GetCode(frame), offset, &level, &handler, &lasti) == 0) { -- // No handlers, so exit. -- assert(_PyErr_Occurred(tstate)); -- -- /* Pop remaining stack entries. */ -- _PyStackRef *stackbase = _PyFrame_Stackbase(frame); -- while (stack_pointer > stackbase) { -- PyStackRef_XCLOSE(POP()); -- } -- assert(STACK_LEVEL() == 0); -- _PyFrame_SetStackPointer(frame, stack_pointer); -- monitor_unwind(tstate, frame, next_instr-1); -- goto exit_unwind; -- } -- -- assert(STACK_LEVEL() >= level); -- _PyStackRef *new_top = _PyFrame_Stackbase(frame) + level; -- while (stack_pointer > new_top) { -- PyStackRef_XCLOSE(POP()); -- } -- if (lasti) { -- int frame_lasti = _PyInterpreterFrame_LASTI(frame); -- PyObject *lasti = PyLong_FromLong(frame_lasti); -- if (lasti == NULL) { -- goto exception_unwind; -- } -- PUSH(PyStackRef_FromPyObjectSteal(lasti)); -- } -- -- /* Make the raw exception data -- available to the handler, -- so a program can emulate the -- Python main loop. */ -- PyObject *exc = _PyErr_GetRaisedException(tstate); -- PUSH(PyStackRef_FromPyObjectSteal(exc)); -- next_instr = _PyFrame_GetBytecode(frame) + handler; -- -- if (monitor_handled(tstate, frame, next_instr, exc) < 0) { -- goto exception_unwind; -- } -- /* Resume normal execution */ --#ifdef LLTRACE -- if (lltrace >= 5) { -- lltrace_resume_frame(frame); -- } -+ goto start_frame; -+# include "generated_cases.c.h" - #endif -- DISPATCH(); -- } -- } -- --exit_unwind: -- assert(_PyErr_Occurred(tstate)); -- _Py_LeaveRecursiveCallPy(tstate); -- assert(frame != &entry_frame); -- // GH-99729: We need to unlink the frame *before* clearing it: -- _PyInterpreterFrame *dying = frame; -- frame = tstate->current_frame = dying->previous; -- _PyEval_FrameClearAndPop(tstate, dying); -- frame->return_offset = 0; -- if (frame == &entry_frame) { -- /* Restore previous frame and exit */ -- tstate->current_frame = frame->previous; -- tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS; -- return NULL; -- } -- --resume_with_error: -- next_instr = frame->instr_ptr; -- stack_pointer = _PyFrame_GetStackPointer(frame); -- goto error; - - - #ifdef _Py_TIER2 -@@ -1042,9 +892,6 @@ - #undef LOAD_IP - #define LOAD_IP(UNUSED) (void)0 - --#undef GOTO_ERROR --#define GOTO_ERROR(LABEL) goto LABEL ## _tier_two -- - #ifdef Py_STATS - // Disable these macros that apply to Tier 1 stats when we are in Tier 2 - #undef STAT_INC -@@ -1058,13 +905,6 @@ - #undef ENABLE_SPECIALIZATION_FT - #define ENABLE_SPECIALIZATION_FT 0 - --#ifdef Py_DEBUG -- #define DPRINTF(level, ...) \ -- if (lltrace >= (level)) { printf(__VA_ARGS__); } --#else -- #define DPRINTF(level, ...) --#endif -- - ; // dummy statement after a label, before a declaration - uint16_t uopcode; - #ifdef Py_STATS -@@ -1077,7 +917,7 @@ - for (;;) { - uopcode = next_uop->opcode; - #ifdef Py_DEBUG -- if (lltrace >= 3) { -+ if (frame->lltrace >= 3) { - dump_stack(frame, stack_pointer); - if (next_uop->opcode == _START_EXECUTOR) { - printf("%4d uop: ", 0); -@@ -1119,7 +959,7 @@ - - jump_to_error_target: - #ifdef Py_DEBUG -- if (lltrace >= 2) { -+ if (frame->lltrace >= 2) { - printf("Error: [UOp "); - _PyUOpPrint(&next_uop[-1]); - printf(" @ %d -> %s]\n", -@@ -1127,50 +967,35 @@ - _PyOpcode_OpName[frame->instr_ptr->op.code]); - } - #endif -- assert (next_uop[-1].format == UOP_FORMAT_JUMP); -+ assert(next_uop[-1].format == UOP_FORMAT_JUMP); - uint16_t target = uop_get_error_target(&next_uop[-1]); - next_uop = current_executor->trace + target; - goto tier2_dispatch; - --error_tier_two: -- OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); -- assert(next_uop[-1].format == UOP_FORMAT_TARGET); -- frame->return_offset = 0; // Don't leave this random -- _PyFrame_SetStackPointer(frame, stack_pointer); -- Py_DECREF(current_executor); -- tstate->previous_executor = NULL; -- goto resume_with_error; -- - jump_to_jump_target: - assert(next_uop[-1].format == UOP_FORMAT_JUMP); - target = uop_get_jump_target(&next_uop[-1]); - next_uop = current_executor->trace + target; - goto tier2_dispatch; - --exit_to_tier1_dynamic: -- next_instr = frame->instr_ptr; -- goto goto_to_tier1; --exit_to_tier1: -- assert(next_uop[-1].format == UOP_FORMAT_TARGET); -- next_instr = next_uop[-1].target + _PyFrame_GetBytecode(frame); --goto_to_tier1: --#ifdef Py_DEBUG -- if (lltrace >= 2) { -- printf("DEOPT: [UOp "); -- _PyUOpPrint(&next_uop[-1]); -- printf(" -> %s]\n", -- _PyOpcode_OpName[next_instr->op.code]); -- } --#endif -- OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); -- Py_DECREF(current_executor); -- tstate->previous_executor = NULL; -- DISPATCH(); -- - #endif // _Py_JIT - - #endif // _Py_TIER2 - -+early_exit: -+ assert(_PyErr_Occurred(tstate)); -+ _Py_LeaveRecursiveCallPy(tstate); -+ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); -+ // GH-99729: We need to unlink the frame *before* clearing it: -+ _PyInterpreterFrame *dying = frame; -+ frame = tstate->current_frame = dying->previous; -+ _PyEval_FrameClearAndPop(tstate, dying); -+ frame->return_offset = 0; -+ assert(frame->owner == FRAME_OWNED_BY_INTERPRETER); -+ /* Restore previous frame and exit */ -+ tstate->current_frame = frame->previous; -+ tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS; -+ return NULL; - } - - #ifdef DO_NOT_OPTIMIZE_INTERP_LOOP -@@ -1522,7 +1347,12 @@ - u = (PyObject *)&_Py_SINGLETON(tuple_empty); - } - else { -- u = _PyTuple_FromStackRefSteal(args + n, argcount - n); -+ u = _PyTuple_FromStackRefStealOnSuccess(args + n, argcount - n); -+ if (u == NULL) { -+ for (Py_ssize_t i = n; i < argcount; i++) { -+ PyStackRef_CLOSE(args[i]); -+ } -+ } - } - if (u == NULL) { - goto fail_post_positional; -@@ -1810,27 +1640,48 @@ - { - bool has_dict = (kwargs != NULL && PyDict_GET_SIZE(kwargs) > 0); - PyObject *kwnames = NULL; -- PyObject *const *newargs; -+ _PyStackRef *newargs; -+ PyObject *const *object_array = NULL; -+ _PyStackRef stack_array[8]; - if (has_dict) { -- newargs = _PyStack_UnpackDict(tstate, _PyTuple_ITEMS(callargs), nargs, kwargs, &kwnames); -- if (newargs == NULL) { -+ object_array = _PyStack_UnpackDict(tstate, _PyTuple_ITEMS(callargs), nargs, kwargs, &kwnames); -+ if (object_array == NULL) { - PyStackRef_CLOSE(func); - goto error; - } -+ size_t total_args = nargs + PyDict_GET_SIZE(kwargs); -+ assert(sizeof(PyObject *) == sizeof(_PyStackRef)); -+ newargs = (_PyStackRef *)object_array; -+ for (size_t i = 0; i < total_args; i++) { -+ newargs[i] = PyStackRef_FromPyObjectSteal(object_array[i]); -+ } - } - else { -- newargs = &PyTuple_GET_ITEM(callargs, 0); -- /* We need to incref all our args since the new frame steals the references. */ -- for (Py_ssize_t i = 0; i < nargs; ++i) { -- Py_INCREF(PyTuple_GET_ITEM(callargs, i)); -+ if (nargs <= 8) { -+ newargs = stack_array; -+ } -+ else { -+ newargs = PyMem_Malloc(sizeof(_PyStackRef) *nargs); -+ if (newargs == NULL) { -+ PyErr_NoMemory(); -+ PyStackRef_CLOSE(func); -+ goto error; -+ } -+ } -+ /* We need to create a new reference for all our args since the new frame steals them. */ -+ for (Py_ssize_t i = 0; i < nargs; i++) { -+ newargs[i] = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(callargs, i)); - } - } - _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( - tstate, func, locals, -- (_PyStackRef const *)newargs, nargs, kwnames, previous -+ newargs, nargs, kwnames, previous - ); - if (has_dict) { -- _PyStack_UnpackDict_FreeNoDecRef(newargs, kwnames); -+ _PyStack_UnpackDict_FreeNoDecRef(object_array, kwnames); -+ } -+ else if (nargs > 8) { -+ PyMem_Free((void *)newargs); - } - /* No need to decref func here because the reference has been stolen by - _PyEvalFramePushAndInit. -@@ -1850,21 +1701,39 @@ - PyObject* const* args, size_t argcount, - PyObject *kwnames) - { -+ size_t total_args = argcount; -+ if (kwnames) { -+ total_args += PyTuple_GET_SIZE(kwnames); -+ } -+ _PyStackRef stack_array[8]; -+ _PyStackRef *arguments; -+ if (total_args <= 8) { -+ arguments = stack_array; -+ } -+ else { -+ arguments = PyMem_Malloc(sizeof(_PyStackRef) * total_args); -+ if (arguments == NULL) { -+ return PyErr_NoMemory(); -+ } -+ } - /* _PyEvalFramePushAndInit consumes the references - * to func, locals and all its arguments */ - Py_XINCREF(locals); - for (size_t i = 0; i < argcount; i++) { -- Py_INCREF(args[i]); -+ arguments[i] = PyStackRef_FromPyObjectNew(args[i]); - } - if (kwnames) { - Py_ssize_t kwcount = PyTuple_GET_SIZE(kwnames); - for (Py_ssize_t i = 0; i < kwcount; i++) { -- Py_INCREF(args[i+argcount]); -+ arguments[i+argcount] = PyStackRef_FromPyObjectNew(args[i+argcount]); - } - } - _PyInterpreterFrame *frame = _PyEvalFramePushAndInit( - tstate, PyStackRef_FromPyObjectNew(func), locals, -- (_PyStackRef const *)args, argcount, kwnames, NULL); -+ arguments, argcount, kwnames, NULL); -+ if (total_args > 8) { -+ PyMem_Free(arguments); -+ } - if (frame == NULL) { - return NULL; - } -@@ -2053,8 +1922,8 @@ - */ - - int --_PyEval_ExceptionGroupMatch(PyObject* exc_value, PyObject *match_type, -- PyObject **match, PyObject **rest) -+_PyEval_ExceptionGroupMatch(_PyInterpreterFrame *frame, PyObject* exc_value, -+ PyObject *match_type, PyObject **match, PyObject **rest) - { - if (Py_IsNone(exc_value)) { - *match = Py_NewRef(Py_None); -@@ -2080,6 +1949,15 @@ - if (wrapped == NULL) { - return -1; - } -+ PyFrameObject *f = _PyFrame_GetFrameObject(frame); -+ if (f != NULL) { -+ PyObject *tb = _PyTraceBack_FromFrame(NULL, f); -+ if (tb == NULL) { -+ return -1; -+ } -+ PyException_SetTraceback(wrapped, tb); -+ Py_DECREF(tb); -+ } - *match = wrapped; - } - *rest = Py_NewRef(Py_None); -@@ -2095,8 +1973,25 @@ - if (pair == NULL) { - return -1; - } -- assert(PyTuple_CheckExact(pair)); -- assert(PyTuple_GET_SIZE(pair) == 2); -+ -+ if (!PyTuple_CheckExact(pair)) { -+ PyErr_Format(PyExc_TypeError, -+ "%.200s.split must return a tuple, not %.200s", -+ Py_TYPE(exc_value)->tp_name, Py_TYPE(pair)->tp_name); -+ Py_DECREF(pair); -+ return -1; -+ } -+ -+ // allow tuples of length > 2 for backwards compatibility -+ if (PyTuple_GET_SIZE(pair) < 2) { -+ PyErr_Format(PyExc_TypeError, -+ "%.200s.split must return a 2-tuple, " -+ "got tuple of size %zd", -+ Py_TYPE(exc_value)->tp_name, PyTuple_GET_SIZE(pair)); -+ Py_DECREF(pair); -+ return -1; -+ } -+ - *match = Py_NewRef(PyTuple_GET_ITEM(pair, 0)); - *rest = Py_NewRef(PyTuple_GET_ITEM(pair, 1)); - Py_DECREF(pair); -@@ -2860,7 +2755,7 @@ - } - } - -- if (origin == NULL) { -+ if (origin == NULL && PyModule_Check(v)) { - // Fall back to __file__ for diagnostics if we don't have - // an origin that is a location - origin = PyModule_GetFilenameObject(v); -diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c -index 1f811e72406..416eec01052 100644 ---- a/Python/ceval_gil.c -+++ b/Python/ceval_gil.c -@@ -995,7 +995,7 @@ - void - _Py_FinishPendingCalls(PyThreadState *tstate) - { -- assert(PyGILState_Check()); -+ _Py_AssertHoldsTstate(); - assert(_PyThreadState_CheckConsistency(tstate)); - - struct _pending_calls *pending = &tstate->interp->ceval.pending; -@@ -1056,7 +1056,7 @@ - int - Py_MakePendingCalls(void) - { -- assert(PyGILState_Check()); -+ _Py_AssertHoldsTstate(); - - PyThreadState *tstate = _PyThreadState_GET(); - assert(_PyThreadState_CheckConsistency(tstate)); -diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h -index 9250b86e42c..0a4f65feb3b 100644 ---- a/Python/ceval_macros.h -+++ b/Python/ceval_macros.h -@@ -70,29 +70,59 @@ - #define INSTRUCTION_STATS(op) ((void)0) - #endif - --#if USE_COMPUTED_GOTOS -+#define TAIL_CALL_PARAMS _PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate, _Py_CODEUNIT *next_instr, int oparg -+#define TAIL_CALL_ARGS frame, stack_pointer, tstate, next_instr, oparg -+ -+#ifdef Py_TAIL_CALL_INTERP -+ // Note: [[clang::musttail]] works for GCC 15, but not __attribute__((musttail)) at the moment. -+# define Py_MUSTTAIL [[clang::musttail]] -+# define Py_PRESERVE_NONE_CC __attribute__((preserve_none)) -+ Py_PRESERVE_NONE_CC typedef PyObject* (*py_tail_call_funcptr)(TAIL_CALL_PARAMS); -+ -+# define TARGET(op) Py_PRESERVE_NONE_CC PyObject *_TAIL_CALL_##op(TAIL_CALL_PARAMS) -+# define DISPATCH_GOTO() \ -+ do { \ -+ Py_MUSTTAIL return (INSTRUCTION_TABLE[opcode])(TAIL_CALL_ARGS); \ -+ } while (0) -+# define JUMP_TO_LABEL(name) \ -+ do { \ -+ Py_MUSTTAIL return (_TAIL_CALL_##name)(TAIL_CALL_ARGS); \ -+ } while (0) -+# define JUMP_TO_PREDICTED(name) \ -+ do { \ -+ Py_MUSTTAIL return (_TAIL_CALL_##name)(frame, stack_pointer, tstate, this_instr, oparg); \ -+ } while (0) -+# define LABEL(name) TARGET(name) -+#elif USE_COMPUTED_GOTOS - # define TARGET(op) TARGET_##op: - # define DISPATCH_GOTO() goto *opcode_targets[opcode] -+# define JUMP_TO_LABEL(name) goto name; -+# define JUMP_TO_PREDICTED(name) goto PREDICTED_##name; -+# define LABEL(name) name: - #else - # define TARGET(op) case op: TARGET_##op: - # define DISPATCH_GOTO() goto dispatch_opcode -+# define JUMP_TO_LABEL(name) goto name; -+# define JUMP_TO_PREDICTED(name) goto PREDICTED_##name; -+# define LABEL(name) name: - #endif - - /* PRE_DISPATCH_GOTO() does lltrace if enabled. Normally a no-op */ --#ifdef LLTRACE --#define PRE_DISPATCH_GOTO() if (lltrace >= 5) { \ -+#ifdef Py_DEBUG -+#define PRE_DISPATCH_GOTO() if (frame->lltrace >= 5) { \ - lltrace_instruction(frame, stack_pointer, next_instr, opcode, oparg); } - #else - #define PRE_DISPATCH_GOTO() ((void)0) - #endif - --#if LLTRACE -+#ifdef Py_DEBUG - #define LLTRACE_RESUME_FRAME() \ - do { \ -- lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); \ -+ int lltrace = maybe_lltrace_resume_frame(frame, GLOBALS()); \ - if (lltrace < 0) { \ -- goto exit_unwind; \ -+ JUMP_TO_LABEL(exit_unwind); \ - } \ -+ frame->lltrace = lltrace; \ - } while (0) - #else - #define LLTRACE_RESUME_FRAME() ((void)0) -@@ -128,12 +158,9 @@ - assert((NEW_FRAME)->previous == frame); \ - frame = tstate->current_frame = (NEW_FRAME); \ - CALL_STAT_INC(inlined_py_calls); \ -- goto start_frame; \ -+ JUMP_TO_LABEL(start_frame); \ - } while (0) - --// Use this instead of 'goto error' so Tier 2 can go to a different label --#define GOTO_ERROR(LABEL) goto LABEL -- - /* Tuple access macros */ - - #ifndef Py_DEBUG -@@ -165,35 +192,6 @@ - #define JUMPBY(x) (next_instr += (x)) - #define SKIP_OVER(x) (next_instr += (x)) - --/* OpCode prediction macros -- Some opcodes tend to come in pairs thus making it possible to -- predict the second code when the first is run. For example, -- COMPARE_OP is often followed by POP_JUMP_IF_FALSE or POP_JUMP_IF_TRUE. -- -- Verifying the prediction costs a single high-speed test of a register -- variable against a constant. If the pairing was good, then the -- processor's own internal branch predication has a high likelihood of -- success, resulting in a nearly zero-overhead transition to the -- next opcode. A successful prediction saves a trip through the eval-loop -- including its unpredictable switch-case branch. Combined with the -- processor's internal branch prediction, a successful PREDICT has the -- effect of making the two opcodes run as if they were a single new opcode -- with the bodies combined. -- -- If collecting opcode statistics, your choices are to either keep the -- predictions turned-on and interpret the results as if some opcodes -- had been combined or turn-off predictions so that the opcode frequency -- counter updates for both opcodes. -- -- Opcode prediction is disabled with threaded code, since the latter allows -- the CPU to record separate branch prediction information for each -- opcode. -- --*/ -- --#define PREDICT_ID(op) PRED_##op --#define PREDICTED(op) PREDICT_ID(op): -- - - /* Stack manipulation macros */ - -@@ -238,7 +236,7 @@ - #endif - - #define WITHIN_STACK_BOUNDS() \ -- (frame == &entry_frame || (STACK_LEVEL() >= 0 && STACK_LEVEL() <= STACK_SIZE())) -+ (frame->owner == FRAME_OWNED_BY_INTERPRETER || (STACK_LEVEL() >= 0 && STACK_LEVEL() <= STACK_SIZE())) - - /* Data access macros */ - #define FRAME_CO_CONSTS (_PyFrame_GetCode(frame)->co_consts) -@@ -249,17 +247,6 @@ - #define LOCALS_ARRAY (frame->localsplus) - #define GETLOCAL(i) (frame->localsplus[i]) - --/* The SETLOCAL() macro must not DECREF the local variable in-place and -- then store the new value; it must copy the old value to a temporary -- value, then store the new value, and then DECREF the temporary value. -- This is because it is possible that during the DECREF the frame is -- accessed by other code (e.g. a __del__ method or gc.collect()) and the -- variable would be pointing to already-freed memory. */ --#define SETLOCAL(i, value) do { _PyStackRef tmp = GETLOCAL(i); \ -- GETLOCAL(i) = value; \ -- PyStackRef_XCLOSE(tmp); } while (0) -- --#define GO_TO_INSTRUCTION(op) goto PREDICT_ID(op) - - #ifdef Py_STATS - #define UPDATE_MISS_STATS(INSTNAME) \ -@@ -275,14 +262,6 @@ - #define UPDATE_MISS_STATS(INSTNAME) ((void)0) - #endif - --#define DEOPT_IF(COND, INSTNAME) \ -- if ((COND)) { \ -- /* This is only a single jump on release builds! */ \ -- UPDATE_MISS_STATS((INSTNAME)); \ -- assert(_PyOpcode_Deopt[opcode] == (INSTNAME)); \ -- GO_TO_INSTRUCTION(INSTNAME); \ -- } -- - - // Try to lock an object in the free threading build, if it's not already - // locked. Use with a DEOPT_IF() to deopt if the object is already locked. -@@ -300,7 +279,7 @@ - // avoid any potentially escaping calls (like PyStackRef_CLOSE) while the - // object is locked. - #ifdef Py_GIL_DISABLED --# define LOCK_OBJECT(op) PyMutex_LockFast(&(_PyObject_CAST(op))->ob_mutex._bits) -+# define LOCK_OBJECT(op) PyMutex_LockFast(&(_PyObject_CAST(op))->ob_mutex) - # define UNLOCK_OBJECT(op) PyMutex_Unlock(&(_PyObject_CAST(op))->ob_mutex) - #else - # define LOCK_OBJECT(op) (1) -@@ -363,11 +342,11 @@ - next_instr = dest; \ - } else { \ - _PyFrame_SetStackPointer(frame, stack_pointer); \ -- next_instr = _Py_call_instrumentation_jump(tstate, event, frame, src, dest); \ -+ next_instr = _Py_call_instrumentation_jump(this_instr, tstate, event, frame, src, dest); \ - stack_pointer = _PyFrame_GetStackPointer(frame); \ - if (next_instr == NULL) { \ - next_instr = (dest)+1; \ -- goto error; \ -+ JUMP_TO_LABEL(error); \ - } \ - } \ - } while (0); -@@ -405,15 +384,19 @@ - #define GOTO_TIER_TWO(EXECUTOR) \ - do { \ - OPT_STAT_INC(traces_executed); \ -- jit_func jitted = (EXECUTOR)->jit_code; \ -+ _PyExecutorObject *_executor = (EXECUTOR); \ -+ jit_func jitted = _executor->jit_code; \ -+ /* Keep the shim frame alive via the executor: */ \ -+ Py_INCREF(_executor); \ - next_instr = jitted(frame, stack_pointer, tstate); \ -- Py_DECREF(tstate->previous_executor); \ -- tstate->previous_executor = NULL; \ -+ Py_DECREF(_executor); \ -+ Py_CLEAR(tstate->previous_executor); \ - frame = tstate->current_frame; \ -+ stack_pointer = _PyFrame_GetStackPointer(frame); \ - if (next_instr == NULL) { \ -- goto resume_with_error; \ -+ next_instr = frame->instr_ptr; \ -+ goto error; \ - } \ -- stack_pointer = _PyFrame_GetStackPointer(frame); \ - DISPATCH(); \ - } while (0) - #else -@@ -426,31 +409,32 @@ - } while (0) - #endif - --#define GOTO_TIER_ONE(TARGET) \ --do { \ -- Py_DECREF(tstate->previous_executor); \ -- tstate->previous_executor = NULL; \ -- next_instr = target; \ -- DISPATCH(); \ -+#define GOTO_TIER_ONE(TARGET) \ -+do { \ -+ next_instr = (TARGET); \ -+ OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); \ -+ Py_CLEAR(tstate->previous_executor); \ -+ if (next_instr == NULL) { \ -+ next_instr = frame->instr_ptr; \ -+ goto error; \ -+ } \ -+ DISPATCH(); \ - } while (0) - --#define CURRENT_OPARG() (next_uop[-1].oparg) -- -+#define CURRENT_OPARG() (next_uop[-1].oparg) - #define CURRENT_OPERAND0() (next_uop[-1].operand0) - #define CURRENT_OPERAND1() (next_uop[-1].operand1) -+#define CURRENT_TARGET() (next_uop[-1].target) - - #define JUMP_TO_JUMP_TARGET() goto jump_to_jump_target - #define JUMP_TO_ERROR() goto jump_to_error_target --#define GOTO_UNWIND() goto error_tier_two --#define EXIT_TO_TIER1() goto exit_to_tier1 --#define EXIT_TO_TIER1_DYNAMIC() goto exit_to_tier1_dynamic; - - /* Stackref macros */ - - /* How much scratch space to give stackref to PyObject* conversion. */ - #define MAX_STACKREF_SCRATCH 10 - --#ifdef Py_GIL_DISABLED -+#if defined(Py_GIL_DISABLED) || defined(Py_STACKREF_DEBUG) - #define STACKREFS_TO_PYOBJECTS(ARGS, ARG_COUNT, NAME) \ - /* +1 because vectorcall might use -1 to write self */ \ - PyObject *NAME##_temp[MAX_STACKREF_SCRATCH+1]; \ -@@ -461,7 +445,7 @@ - assert(NAME != NULL); - #endif - --#ifdef Py_GIL_DISABLED -+#if defined(Py_GIL_DISABLED) || defined(Py_STACKREF_DEBUG) - #define STACKREFS_TO_PYOBJECTS_CLEANUP(NAME) \ - /* +1 because we +1 previously */ \ - _PyObjectArray_Free(NAME - 1, NAME##_temp); -@@ -470,7 +454,7 @@ - (void)(NAME); - #endif - --#ifdef Py_GIL_DISABLED -+#if defined(Py_GIL_DISABLED) || defined(Py_STACKREF_DEBUG) - #define CONVERSION_FAILED(NAME) ((NAME) == NULL) - #else - #define CONVERSION_FAILED(NAME) (0) -diff --git a/Python/clinic/_warnings.c.h b/Python/clinic/_warnings.c.h -index 9a2c33f2ea8..bcb4b344fa4 100644 ---- a/Python/clinic/_warnings.c.h -+++ b/Python/clinic/_warnings.c.h -@@ -9,6 +9,40 @@ - #include "pycore_abstract.h" // _PyNumber_Index() - #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() - -+PyDoc_STRVAR(warnings_acquire_lock__doc__, -+"_acquire_lock($module, /)\n" -+"--\n" -+"\n"); -+ -+#define WARNINGS_ACQUIRE_LOCK_METHODDEF \ -+ {"_acquire_lock", (PyCFunction)warnings_acquire_lock, METH_NOARGS, warnings_acquire_lock__doc__}, -+ -+static PyObject * -+warnings_acquire_lock_impl(PyObject *module); -+ -+static PyObject * -+warnings_acquire_lock(PyObject *module, PyObject *Py_UNUSED(ignored)) -+{ -+ return warnings_acquire_lock_impl(module); -+} -+ -+PyDoc_STRVAR(warnings_release_lock__doc__, -+"_release_lock($module, /)\n" -+"--\n" -+"\n"); -+ -+#define WARNINGS_RELEASE_LOCK_METHODDEF \ -+ {"_release_lock", (PyCFunction)warnings_release_lock, METH_NOARGS, warnings_release_lock__doc__}, -+ -+static PyObject * -+warnings_release_lock_impl(PyObject *module); -+ -+static PyObject * -+warnings_release_lock(PyObject *module, PyObject *Py_UNUSED(ignored)) -+{ -+ return warnings_release_lock_impl(module); -+} -+ - PyDoc_STRVAR(warnings_warn__doc__, - "warn($module, /, message, category=None, stacklevel=1, source=None, *,\n" - " skip_file_prefixes=)\n" -@@ -230,20 +264,20 @@ - return return_value; - } - --PyDoc_STRVAR(warnings_filters_mutated__doc__, --"_filters_mutated($module, /)\n" -+PyDoc_STRVAR(warnings_filters_mutated_lock_held__doc__, -+"_filters_mutated_lock_held($module, /)\n" - "--\n" - "\n"); - --#define WARNINGS_FILTERS_MUTATED_METHODDEF \ -- {"_filters_mutated", (PyCFunction)warnings_filters_mutated, METH_NOARGS, warnings_filters_mutated__doc__}, -+#define WARNINGS_FILTERS_MUTATED_LOCK_HELD_METHODDEF \ -+ {"_filters_mutated_lock_held", (PyCFunction)warnings_filters_mutated_lock_held, METH_NOARGS, warnings_filters_mutated_lock_held__doc__}, - - static PyObject * --warnings_filters_mutated_impl(PyObject *module); -+warnings_filters_mutated_lock_held_impl(PyObject *module); - - static PyObject * --warnings_filters_mutated(PyObject *module, PyObject *Py_UNUSED(ignored)) -+warnings_filters_mutated_lock_held(PyObject *module, PyObject *Py_UNUSED(ignored)) - { -- return warnings_filters_mutated_impl(module); -+ return warnings_filters_mutated_lock_held_impl(module); - } --/*[clinic end generated code: output=ed02c0f521a03a37 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=d9d32a8b59a30683 input=a9049054013a1b77]*/ -diff --git a/Python/clinic/context.c.h b/Python/clinic/context.c.h -index 997ac6f6338..71f05aa02a5 100644 ---- a/Python/clinic/context.c.h -+++ b/Python/clinic/context.c.h -@@ -21,7 +21,7 @@ - PyObject *default_value); - - static PyObject * --_contextvars_Context_get(PyContext *self, PyObject *const *args, Py_ssize_t nargs) -+_contextvars_Context_get(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *key; -@@ -36,7 +36,7 @@ - } - default_value = args[1]; - skip_optional: -- return_value = _contextvars_Context_get_impl(self, key, default_value); -+ return_value = _contextvars_Context_get_impl((PyContext *)self, key, default_value); - - exit: - return return_value; -@@ -57,9 +57,9 @@ - _contextvars_Context_items_impl(PyContext *self); - - static PyObject * --_contextvars_Context_items(PyContext *self, PyObject *Py_UNUSED(ignored)) -+_contextvars_Context_items(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _contextvars_Context_items_impl(self); -+ return _contextvars_Context_items_impl((PyContext *)self); - } - - PyDoc_STRVAR(_contextvars_Context_keys__doc__, -@@ -75,9 +75,9 @@ - _contextvars_Context_keys_impl(PyContext *self); - - static PyObject * --_contextvars_Context_keys(PyContext *self, PyObject *Py_UNUSED(ignored)) -+_contextvars_Context_keys(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _contextvars_Context_keys_impl(self); -+ return _contextvars_Context_keys_impl((PyContext *)self); - } - - PyDoc_STRVAR(_contextvars_Context_values__doc__, -@@ -93,9 +93,9 @@ - _contextvars_Context_values_impl(PyContext *self); - - static PyObject * --_contextvars_Context_values(PyContext *self, PyObject *Py_UNUSED(ignored)) -+_contextvars_Context_values(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _contextvars_Context_values_impl(self); -+ return _contextvars_Context_values_impl((PyContext *)self); - } - - PyDoc_STRVAR(_contextvars_Context_copy__doc__, -@@ -111,9 +111,9 @@ - _contextvars_Context_copy_impl(PyContext *self); - - static PyObject * --_contextvars_Context_copy(PyContext *self, PyObject *Py_UNUSED(ignored)) -+_contextvars_Context_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return _contextvars_Context_copy_impl(self); -+ return _contextvars_Context_copy_impl((PyContext *)self); - } - - PyDoc_STRVAR(_contextvars_ContextVar_get__doc__, -@@ -135,7 +135,7 @@ - _contextvars_ContextVar_get_impl(PyContextVar *self, PyObject *default_value); - - static PyObject * --_contextvars_ContextVar_get(PyContextVar *self, PyObject *const *args, Py_ssize_t nargs) -+_contextvars_ContextVar_get(PyObject *self, PyObject *const *args, Py_ssize_t nargs) - { - PyObject *return_value = NULL; - PyObject *default_value = NULL; -@@ -148,7 +148,7 @@ - } - default_value = args[0]; - skip_optional: -- return_value = _contextvars_ContextVar_get_impl(self, default_value); -+ return_value = _contextvars_ContextVar_get_impl((PyContextVar *)self, default_value); - - exit: - return return_value; -@@ -179,4 +179,4 @@ - - #define _CONTEXTVARS_CONTEXTVAR_RESET_METHODDEF \ - {"reset", (PyCFunction)_contextvars_ContextVar_reset, METH_O, _contextvars_ContextVar_reset__doc__}, --/*[clinic end generated code: output=b667826178444c3f input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=444567eaf0df25e0 input=a9049054013a1b77]*/ -diff --git a/Python/clinic/instruction_sequence.c.h b/Python/clinic/instruction_sequence.c.h -index 45693e5856f..41ab2de44e4 100644 ---- a/Python/clinic/instruction_sequence.c.h -+++ b/Python/clinic/instruction_sequence.c.h -@@ -51,7 +51,7 @@ - int label); - - static PyObject * --InstructionSequenceType_use_label(_PyInstructionSequence *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+InstructionSequenceType_use_label(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -91,7 +91,7 @@ - if (label == -1 && PyErr_Occurred()) { - goto exit; - } -- return_value = InstructionSequenceType_use_label_impl(self, label); -+ return_value = InstructionSequenceType_use_label_impl((_PyInstructionSequence *)self, label); - - exit: - return return_value; -@@ -113,7 +113,7 @@ - int end_lineno, int end_col_offset); - - static PyObject * --InstructionSequenceType_addop(_PyInstructionSequence *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+InstructionSequenceType_addop(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -178,7 +178,7 @@ - if (end_col_offset == -1 && PyErr_Occurred()) { - goto exit; - } -- return_value = InstructionSequenceType_addop_impl(self, opcode, oparg, lineno, col_offset, end_lineno, end_col_offset); -+ return_value = InstructionSequenceType_addop_impl((_PyInstructionSequence *)self, opcode, oparg, lineno, col_offset, end_lineno, end_col_offset); - - exit: - return return_value; -@@ -197,12 +197,12 @@ - InstructionSequenceType_new_label_impl(_PyInstructionSequence *self); - - static PyObject * --InstructionSequenceType_new_label(_PyInstructionSequence *self, PyObject *Py_UNUSED(ignored)) -+InstructionSequenceType_new_label(PyObject *self, PyObject *Py_UNUSED(ignored)) - { - PyObject *return_value = NULL; - int _return_value; - -- _return_value = InstructionSequenceType_new_label_impl(self); -+ _return_value = InstructionSequenceType_new_label_impl((_PyInstructionSequence *)self); - if ((_return_value == -1) && PyErr_Occurred()) { - goto exit; - } -@@ -226,7 +226,7 @@ - PyObject *nested); - - static PyObject * --InstructionSequenceType_add_nested(_PyInstructionSequence *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -+InstructionSequenceType_add_nested(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -@@ -263,7 +263,7 @@ - goto exit; - } - nested = args[0]; -- return_value = InstructionSequenceType_add_nested_impl(self, nested); -+ return_value = InstructionSequenceType_add_nested_impl((_PyInstructionSequence *)self, nested); - - exit: - return return_value; -@@ -282,9 +282,9 @@ - InstructionSequenceType_get_nested_impl(_PyInstructionSequence *self); - - static PyObject * --InstructionSequenceType_get_nested(_PyInstructionSequence *self, PyObject *Py_UNUSED(ignored)) -+InstructionSequenceType_get_nested(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return InstructionSequenceType_get_nested_impl(self); -+ return InstructionSequenceType_get_nested_impl((_PyInstructionSequence *)self); - } - - PyDoc_STRVAR(InstructionSequenceType_get_instructions__doc__, -@@ -300,8 +300,8 @@ - InstructionSequenceType_get_instructions_impl(_PyInstructionSequence *self); - - static PyObject * --InstructionSequenceType_get_instructions(_PyInstructionSequence *self, PyObject *Py_UNUSED(ignored)) -+InstructionSequenceType_get_instructions(PyObject *self, PyObject *Py_UNUSED(ignored)) - { -- return InstructionSequenceType_get_instructions_impl(self); -+ return InstructionSequenceType_get_instructions_impl((_PyInstructionSequence *)self); - } --/*[clinic end generated code: output=35163e5b589b4446 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=e6b5d05bde008cc2 input=a9049054013a1b77]*/ -diff --git a/Python/clinic/sysmodule.c.h b/Python/clinic/sysmodule.c.h -index cfcbd55388e..1e53624d4d4 100644 ---- a/Python/clinic/sysmodule.c.h -+++ b/Python/clinic/sysmodule.c.h -@@ -373,6 +373,36 @@ - return return_value; - } - -+PyDoc_STRVAR(sys__is_immortal__doc__, -+"_is_immortal($module, op, /)\n" -+"--\n" -+"\n" -+"Return True if the given object is \"immortal\" per PEP 683.\n" -+"\n" -+"This function should be used for specialized purposes only."); -+ -+#define SYS__IS_IMMORTAL_METHODDEF \ -+ {"_is_immortal", (PyCFunction)sys__is_immortal, METH_O, sys__is_immortal__doc__}, -+ -+static int -+sys__is_immortal_impl(PyObject *module, PyObject *op); -+ -+static PyObject * -+sys__is_immortal(PyObject *module, PyObject *op) -+{ -+ PyObject *return_value = NULL; -+ int _return_value; -+ -+ _return_value = sys__is_immortal_impl(module, op); -+ if ((_return_value == -1) && PyErr_Occurred()) { -+ goto exit; -+ } -+ return_value = PyBool_FromLong((long)_return_value); -+ -+exit: -+ return return_value; -+} -+ - PyDoc_STRVAR(sys_settrace__doc__, - "settrace($module, function, /)\n" - "--\n" -@@ -1724,4 +1754,4 @@ - #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF - #define SYS_GETANDROIDAPILEVEL_METHODDEF - #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ --/*[clinic end generated code: output=568b0a0069dc43e8 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=1e5f608092c12636 input=a9049054013a1b77]*/ -diff --git a/Python/codecs.c b/Python/codecs.c -index 2cb3875db35..6c9f8222079 100644 ---- a/Python/codecs.c -+++ b/Python/codecs.c -@@ -659,91 +659,163 @@ - return handler; - } - --static void wrong_exception_type(PyObject *exc) -+ -+static inline void -+wrong_exception_type(PyObject *exc) - { - PyErr_Format(PyExc_TypeError, -- "don't know how to handle %.200s in error callback", -- Py_TYPE(exc)->tp_name); -+ "don't know how to handle %T in error callback", exc); -+} -+ -+ -+#define _PyIsUnicodeEncodeError(EXC) \ -+ PyObject_TypeCheck(EXC, (PyTypeObject *)PyExc_UnicodeEncodeError) -+#define _PyIsUnicodeDecodeError(EXC) \ -+ PyObject_TypeCheck(EXC, (PyTypeObject *)PyExc_UnicodeDecodeError) -+#define _PyIsUnicodeTranslateError(EXC) \ -+ PyObject_TypeCheck(EXC, (PyTypeObject *)PyExc_UnicodeTranslateError) -+ -+ -+// --- codecs handlers: utilities --------------------------------------------- -+ -+/* -+ * Return the number of characters (including special prefixes) -+ * needed to represent 'ch' by codec_handler_write_unicode_hex(). -+ */ -+static inline Py_ssize_t -+codec_handler_unicode_hex_width(Py_UCS4 ch) -+{ -+ if (ch >= 0x10000) { -+ // format: '\\' + 'U' + 8 hex digits -+ return 1 + 1 + 8; -+ } -+ else if (ch >= 0x100) { -+ // format: '\\' + 'u' + 4 hex digits -+ return 1 + 1 + 4; -+ } -+ else { -+ // format: '\\' + 'x' + 2 hex digits -+ return 1 + 1 + 2; -+ } - } - -+ -+/* -+ * Write the hexadecimal representation of 'ch' to the buffer pointed by 'p' -+ * using 2, 4, or 8 characters prefixed by '\x', '\u', or '\U' respectively. -+ */ -+static inline void -+codec_handler_write_unicode_hex(Py_UCS1 **p, Py_UCS4 ch) -+{ -+ *(*p)++ = '\\'; -+ if (ch >= 0x10000) { -+ *(*p)++ = 'U'; -+ *(*p)++ = Py_hexdigits[(ch >> 28) & 0xf]; -+ *(*p)++ = Py_hexdigits[(ch >> 24) & 0xf]; -+ *(*p)++ = Py_hexdigits[(ch >> 20) & 0xf]; -+ *(*p)++ = Py_hexdigits[(ch >> 16) & 0xf]; -+ *(*p)++ = Py_hexdigits[(ch >> 12) & 0xf]; -+ *(*p)++ = Py_hexdigits[(ch >> 8) & 0xf]; -+ } -+ else if (ch >= 0x100) { -+ *(*p)++ = 'u'; -+ *(*p)++ = Py_hexdigits[(ch >> 12) & 0xf]; -+ *(*p)++ = Py_hexdigits[(ch >> 8) & 0xf]; -+ } -+ else { -+ *(*p)++ = 'x'; -+ } -+ *(*p)++ = Py_hexdigits[(ch >> 4) & 0xf]; -+ *(*p)++ = Py_hexdigits[ch & 0xf]; -+} -+ -+ -+// --- handler: 'strict' ------------------------------------------------------ -+ - PyObject *PyCodec_StrictErrors(PyObject *exc) - { -- if (PyExceptionInstance_Check(exc)) -+ if (PyExceptionInstance_Check(exc)) { - PyErr_SetObject(PyExceptionInstance_Class(exc), exc); -- else -+ } -+ else { - PyErr_SetString(PyExc_TypeError, "codec must pass exception instance"); -+ } - return NULL; - } - - --PyObject *PyCodec_IgnoreErrors(PyObject *exc) -+// --- handler: 'ignore' ------------------------------------------------------ -+ -+static PyObject * -+_PyCodec_IgnoreError(PyObject *exc, int as_bytes) - { - Py_ssize_t end; -- -- if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) { -- if (PyUnicodeEncodeError_GetEnd(exc, &end)) -- return NULL; -+ if (_PyUnicodeError_GetParams(exc, NULL, NULL, NULL, -+ &end, NULL, as_bytes) < 0) -+ { -+ return NULL; - } -- else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeDecodeError)) { -- if (PyUnicodeDecodeError_GetEnd(exc, &end)) -- return NULL; -+ return Py_BuildValue("(Nn)", Py_GetConstant(Py_CONSTANT_EMPTY_STR), end); -+} -+ -+ -+PyObject *PyCodec_IgnoreErrors(PyObject *exc) -+{ -+ if (_PyIsUnicodeEncodeError(exc) || _PyIsUnicodeTranslateError(exc)) { -+ return _PyCodec_IgnoreError(exc, false); - } -- else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeTranslateError)) { -- if (PyUnicodeTranslateError_GetEnd(exc, &end)) -- return NULL; -+ else if (_PyIsUnicodeDecodeError(exc)) { -+ return _PyCodec_IgnoreError(exc, true); - } - else { - wrong_exception_type(exc); - return NULL; - } -- return Py_BuildValue("(Nn)", Py_GetConstant(Py_CONSTANT_EMPTY_STR), end); - } - - - PyObject *PyCodec_ReplaceErrors(PyObject *exc) - { -- Py_ssize_t start, end, i, len; -+ Py_ssize_t start, end, slen; - - if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) { -- PyObject *res; -- Py_UCS1 *outp; -- if (PyUnicodeEncodeError_GetStart(exc, &start)) -- return NULL; -- if (PyUnicodeEncodeError_GetEnd(exc, &end)) -+ if (_PyUnicodeError_GetParams(exc, NULL, NULL, -+ &start, &end, &slen, false) < 0) { - return NULL; -- len = end - start; -- res = PyUnicode_New(len, '?'); -- if (res == NULL) -+ } -+ PyObject *res = PyUnicode_New(slen, '?'); -+ if (res == NULL) { - return NULL; -+ } - assert(PyUnicode_KIND(res) == PyUnicode_1BYTE_KIND); -- outp = PyUnicode_1BYTE_DATA(res); -- for (i = 0; i < len; ++i) -- outp[i] = '?'; -+ Py_UCS1 *outp = PyUnicode_1BYTE_DATA(res); -+ memset(outp, '?', sizeof(Py_UCS1) * slen); - assert(_PyUnicode_CheckConsistency(res, 1)); - return Py_BuildValue("(Nn)", res, end); - } - else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeDecodeError)) { -- if (PyUnicodeDecodeError_GetEnd(exc, &end)) -+ if (_PyUnicodeError_GetParams(exc, NULL, NULL, -+ NULL, &end, NULL, true) < 0) { - return NULL; -+ } - return Py_BuildValue("(Cn)", - (int)Py_UNICODE_REPLACEMENT_CHARACTER, - end); - } - else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeTranslateError)) { -- PyObject *res; -- Py_UCS2 *outp; -- if (PyUnicodeTranslateError_GetStart(exc, &start)) -- return NULL; -- if (PyUnicodeTranslateError_GetEnd(exc, &end)) -+ if (_PyUnicodeError_GetParams(exc, NULL, NULL, -+ &start, &end, &slen, false) < 0) { - return NULL; -- len = end - start; -- res = PyUnicode_New(len, Py_UNICODE_REPLACEMENT_CHARACTER); -- if (res == NULL) -+ } -+ PyObject *res = PyUnicode_New(slen, Py_UNICODE_REPLACEMENT_CHARACTER); -+ if (res == NULL) { - return NULL; -- assert(PyUnicode_KIND(res) == PyUnicode_2BYTE_KIND); -- outp = PyUnicode_2BYTE_DATA(res); -- for (i = 0; i < len; i++) -+ } -+ assert(slen == 0 || PyUnicode_KIND(res) == PyUnicode_2BYTE_KIND); -+ Py_UCS2 *outp = PyUnicode_2BYTE_DATA(res); -+ for (Py_ssize_t i = 0; i < slen; ++i) { - outp[i] = Py_UNICODE_REPLACEMENT_CHARACTER; -+ } - assert(_PyUnicode_CheckConsistency(res, 1)); - return Py_BuildValue("(Nn)", res, end); - } -@@ -755,299 +827,266 @@ - - PyObject *PyCodec_XMLCharRefReplaceErrors(PyObject *exc) - { -- if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) { -- PyObject *restuple; -- PyObject *object; -- Py_ssize_t i; -- Py_ssize_t start; -- Py_ssize_t end; -- PyObject *res; -- Py_UCS1 *outp; -- Py_ssize_t ressize; -- Py_UCS4 ch; -- if (PyUnicodeEncodeError_GetStart(exc, &start)) -- return NULL; -- if (PyUnicodeEncodeError_GetEnd(exc, &end)) -- return NULL; -- if (!(object = PyUnicodeEncodeError_GetObject(exc))) -- return NULL; -- if (end - start > PY_SSIZE_T_MAX / (2+7+1)) -- end = start + PY_SSIZE_T_MAX / (2+7+1); -- for (i = start, ressize = 0; i < end; ++i) { -- /* object is guaranteed to be "ready" */ -- ch = PyUnicode_READ_CHAR(object, i); -- if (ch<10) -- ressize += 2+1+1; -- else if (ch<100) -- ressize += 2+2+1; -- else if (ch<1000) -- ressize += 2+3+1; -- else if (ch<10000) -- ressize += 2+4+1; -- else if (ch<100000) -- ressize += 2+5+1; -- else if (ch<1000000) -- ressize += 2+6+1; -- else -- ressize += 2+7+1; -+ if (!PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) { -+ wrong_exception_type(exc); -+ return NULL; -+ } -+ -+ PyObject *obj; -+ Py_ssize_t objlen, start, end, slen; -+ if (_PyUnicodeError_GetParams(exc, -+ &obj, &objlen, -+ &start, &end, &slen, false) < 0) -+ { -+ return NULL; -+ } -+ -+ // The number of characters that each character 'ch' contributes -+ // in the result is 2 + k + 1, where k = min{t >= 1 | 10^t > ch} -+ // and will be formatted as "&#" + DIGITS + ";". Since the Unicode -+ // range is below 10^7, each "block" requires at most 2 + 7 + 1 -+ // characters. -+ if (slen > PY_SSIZE_T_MAX / (2 + 7 + 1)) { -+ end = start + PY_SSIZE_T_MAX / (2 + 7 + 1); -+ end = Py_MIN(end, objlen); -+ slen = Py_MAX(0, end - start); -+ } -+ -+ Py_ssize_t ressize = 0; -+ for (Py_ssize_t i = start; i < end; ++i) { -+ /* object is guaranteed to be "ready" */ -+ Py_UCS4 ch = PyUnicode_READ_CHAR(obj, i); -+ if (ch < 10) { -+ ressize += 2 + 1 + 1; - } -- /* allocate replacement */ -- res = PyUnicode_New(ressize, 127); -- if (res == NULL) { -- Py_DECREF(object); -- return NULL; -+ else if (ch < 100) { -+ ressize += 2 + 2 + 1; - } -- outp = PyUnicode_1BYTE_DATA(res); -- /* generate replacement */ -- for (i = start; i < end; ++i) { -- int digits; -- int base; -- ch = PyUnicode_READ_CHAR(object, i); -- *outp++ = '&'; -- *outp++ = '#'; -- if (ch<10) { -- digits = 1; -- base = 1; -- } -- else if (ch<100) { -- digits = 2; -- base = 10; -- } -- else if (ch<1000) { -- digits = 3; -- base = 100; -- } -- else if (ch<10000) { -- digits = 4; -- base = 1000; -- } -- else if (ch<100000) { -- digits = 5; -- base = 10000; -- } -- else if (ch<1000000) { -- digits = 6; -- base = 100000; -- } -- else { -- digits = 7; -- base = 1000000; -- } -- while (digits-->0) { -- *outp++ = '0' + ch/base; -- ch %= base; -- base /= 10; -- } -- *outp++ = ';'; -+ else if (ch < 1000) { -+ ressize += 2 + 3 + 1; -+ } -+ else if (ch < 10000) { -+ ressize += 2 + 4 + 1; -+ } -+ else if (ch < 100000) { -+ ressize += 2 + 5 + 1; -+ } -+ else if (ch < 1000000) { -+ ressize += 2 + 6 + 1; -+ } -+ else { -+ assert(ch < 10000000); -+ ressize += 2 + 7 + 1; - } -- assert(_PyUnicode_CheckConsistency(res, 1)); -- restuple = Py_BuildValue("(Nn)", res, end); -- Py_DECREF(object); -- return restuple; - } -- else { -- wrong_exception_type(exc); -+ -+ /* allocate replacement */ -+ PyObject *res = PyUnicode_New(ressize, 127); -+ if (res == NULL) { -+ Py_DECREF(obj); - return NULL; - } -+ Py_UCS1 *outp = PyUnicode_1BYTE_DATA(res); -+ /* generate replacement */ -+ for (Py_ssize_t i = start; i < end; ++i) { -+ int digits, base; -+ Py_UCS4 ch = PyUnicode_READ_CHAR(obj, i); -+ if (ch < 10) { -+ digits = 1; -+ base = 1; -+ } -+ else if (ch < 100) { -+ digits = 2; -+ base = 10; -+ } -+ else if (ch < 1000) { -+ digits = 3; -+ base = 100; -+ } -+ else if (ch < 10000) { -+ digits = 4; -+ base = 1000; -+ } -+ else if (ch < 100000) { -+ digits = 5; -+ base = 10000; -+ } -+ else if (ch < 1000000) { -+ digits = 6; -+ base = 100000; -+ } -+ else { -+ assert(ch < 10000000); -+ digits = 7; -+ base = 1000000; -+ } -+ *outp++ = '&'; -+ *outp++ = '#'; -+ while (digits-- > 0) { -+ assert(base >= 1); -+ *outp++ = '0' + ch / base; -+ ch %= base; -+ base /= 10; -+ } -+ *outp++ = ';'; -+ } -+ assert(_PyUnicode_CheckConsistency(res, 1)); -+ PyObject *restuple = Py_BuildValue("(Nn)", res, end); -+ Py_DECREF(obj); -+ return restuple; - } - - PyObject *PyCodec_BackslashReplaceErrors(PyObject *exc) - { -- PyObject *object; -- Py_ssize_t i; -- Py_ssize_t start; -- Py_ssize_t end; -- PyObject *res; -- Py_UCS1 *outp; -- int ressize; -- Py_UCS4 c; -- -+ PyObject *obj; -+ Py_ssize_t objlen, start, end, slen; - if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeDecodeError)) { -- const unsigned char *p; -- if (PyUnicodeDecodeError_GetStart(exc, &start)) -- return NULL; -- if (PyUnicodeDecodeError_GetEnd(exc, &end)) -- return NULL; -- if (!(object = PyUnicodeDecodeError_GetObject(exc))) -+ if (_PyUnicodeError_GetParams(exc, -+ &obj, &objlen, -+ &start, &end, &slen, true) < 0) -+ { - return NULL; -- p = (const unsigned char*)PyBytes_AS_STRING(object); -- res = PyUnicode_New(4 * (end - start), 127); -+ } -+ PyObject *res = PyUnicode_New(4 * slen, 127); - if (res == NULL) { -- Py_DECREF(object); -+ Py_DECREF(obj); - return NULL; - } -- outp = PyUnicode_1BYTE_DATA(res); -- for (i = start; i < end; i++, outp += 4) { -- unsigned char c = p[i]; -+ Py_UCS1 *outp = PyUnicode_1BYTE_DATA(res); -+ const unsigned char *p = (const unsigned char *)PyBytes_AS_STRING(obj); -+ for (Py_ssize_t i = start; i < end; i++, outp += 4) { -+ const unsigned char ch = p[i]; - outp[0] = '\\'; - outp[1] = 'x'; -- outp[2] = Py_hexdigits[(c>>4)&0xf]; -- outp[3] = Py_hexdigits[c&0xf]; -+ outp[2] = Py_hexdigits[(ch >> 4) & 0xf]; -+ outp[3] = Py_hexdigits[ch & 0xf]; - } -- - assert(_PyUnicode_CheckConsistency(res, 1)); -- Py_DECREF(object); -+ Py_DECREF(obj); - return Py_BuildValue("(Nn)", res, end); - } -- if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) { -- if (PyUnicodeEncodeError_GetStart(exc, &start)) -- return NULL; -- if (PyUnicodeEncodeError_GetEnd(exc, &end)) -- return NULL; -- if (!(object = PyUnicodeEncodeError_GetObject(exc))) -- return NULL; -- } -- else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeTranslateError)) { -- if (PyUnicodeTranslateError_GetStart(exc, &start)) -- return NULL; -- if (PyUnicodeTranslateError_GetEnd(exc, &end)) -- return NULL; -- if (!(object = PyUnicodeTranslateError_GetObject(exc))) -+ -+ if ( -+ PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError) -+ || PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeTranslateError) -+ ) { -+ if (_PyUnicodeError_GetParams(exc, -+ &obj, &objlen, -+ &start, &end, &slen, false) < 0) -+ { - return NULL; -+ } - } - else { - wrong_exception_type(exc); - return NULL; - } - -- if (end - start > PY_SSIZE_T_MAX / (1+1+8)) -- end = start + PY_SSIZE_T_MAX / (1+1+8); -- for (i = start, ressize = 0; i < end; ++i) { -- /* object is guaranteed to be "ready" */ -- c = PyUnicode_READ_CHAR(object, i); -- if (c >= 0x10000) { -- ressize += 1+1+8; -- } -- else if (c >= 0x100) { -- ressize += 1+1+4; -- } -- else -- ressize += 1+1+2; -+ // The number of characters that each character 'ch' contributes -+ // in the result is 1 + 1 + k, where k >= min{t >= 1 | 16^t > ch} -+ // and will be formatted as "\\" + ('U'|'u'|'x') + HEXDIGITS, -+ // where the number of hexdigits is either 2, 4, or 8 (not 6). -+ // Since the Unicode range is below 10^7, we choose k = 8 whence -+ // each "block" requires at most 1 + 1 + 8 characters. -+ if (slen > PY_SSIZE_T_MAX / (1 + 1 + 8)) { -+ end = start + PY_SSIZE_T_MAX / (1 + 1 + 8); -+ end = Py_MIN(end, objlen); -+ slen = Py_MAX(0, end - start); -+ } -+ -+ Py_ssize_t ressize = 0; -+ for (Py_ssize_t i = start; i < end; ++i) { -+ Py_UCS4 c = PyUnicode_READ_CHAR(obj, i); -+ ressize += codec_handler_unicode_hex_width(c); - } -- res = PyUnicode_New(ressize, 127); -+ PyObject *res = PyUnicode_New(ressize, 127); - if (res == NULL) { -- Py_DECREF(object); -+ Py_DECREF(obj); - return NULL; - } -- outp = PyUnicode_1BYTE_DATA(res); -- for (i = start; i < end; ++i) { -- c = PyUnicode_READ_CHAR(object, i); -- *outp++ = '\\'; -- if (c >= 0x00010000) { -- *outp++ = 'U'; -- *outp++ = Py_hexdigits[(c>>28)&0xf]; -- *outp++ = Py_hexdigits[(c>>24)&0xf]; -- *outp++ = Py_hexdigits[(c>>20)&0xf]; -- *outp++ = Py_hexdigits[(c>>16)&0xf]; -- *outp++ = Py_hexdigits[(c>>12)&0xf]; -- *outp++ = Py_hexdigits[(c>>8)&0xf]; -- } -- else if (c >= 0x100) { -- *outp++ = 'u'; -- *outp++ = Py_hexdigits[(c>>12)&0xf]; -- *outp++ = Py_hexdigits[(c>>8)&0xf]; -- } -- else -- *outp++ = 'x'; -- *outp++ = Py_hexdigits[(c>>4)&0xf]; -- *outp++ = Py_hexdigits[c&0xf]; -+ Py_UCS1 *outp = PyUnicode_1BYTE_DATA(res); -+ for (Py_ssize_t i = start; i < end; ++i) { -+ Py_UCS4 c = PyUnicode_READ_CHAR(obj, i); -+ codec_handler_write_unicode_hex(&outp, c); - } -- - assert(_PyUnicode_CheckConsistency(res, 1)); -- Py_DECREF(object); -+ Py_DECREF(obj); - return Py_BuildValue("(Nn)", res, end); - } - -+ -+// --- handler: 'namereplace' ------------------------------------------------- -+ - PyObject *PyCodec_NameReplaceErrors(PyObject *exc) - { -- if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) { -- PyObject *restuple; -- PyObject *object; -- Py_ssize_t i; -- Py_ssize_t start; -- Py_ssize_t end; -- PyObject *res; -- Py_UCS1 *outp; -- Py_ssize_t ressize; -- int replsize; -- Py_UCS4 c; -- char buffer[256]; /* NAME_MAXLEN */ -- if (PyUnicodeEncodeError_GetStart(exc, &start)) -- return NULL; -- if (PyUnicodeEncodeError_GetEnd(exc, &end)) -- return NULL; -- if (!(object = PyUnicodeEncodeError_GetObject(exc))) -- return NULL; -- _PyUnicode_Name_CAPI *ucnhash_capi = _PyUnicode_GetNameCAPI(); -- if (ucnhash_capi == NULL) { -- return NULL; -+ if (!_PyIsUnicodeEncodeError(exc)) { -+ wrong_exception_type(exc); -+ return NULL; -+ } -+ -+ _PyUnicode_Name_CAPI *ucnhash_capi = _PyUnicode_GetNameCAPI(); -+ if (ucnhash_capi == NULL) { -+ return NULL; -+ } -+ -+ PyObject *obj; -+ Py_ssize_t start, end; -+ if (_PyUnicodeError_GetParams(exc, -+ &obj, NULL, -+ &start, &end, NULL, false) < 0) -+ { -+ return NULL; -+ } -+ -+ char buffer[256]; /* NAME_MAXLEN in unicodename_db.h */ -+ Py_ssize_t imax = start, ressize = 0, replsize; -+ for (; imax < end; ++imax) { -+ Py_UCS4 c = PyUnicode_READ_CHAR(obj, imax); -+ if (ucnhash_capi->getname(c, buffer, sizeof(buffer), 1)) { -+ // If 'c' is recognized by getname(), the corresponding replacement -+ // is '\\' + 'N' + '{' + NAME + '}', i.e. 1 + 1 + 1 + len(NAME) + 1 -+ // characters. Failures of getname() are ignored by the handler. -+ replsize = 1 + 1 + 1 + strlen(buffer) + 1; - } -- for (i = start, ressize = 0; i < end; ++i) { -- /* object is guaranteed to be "ready" */ -- c = PyUnicode_READ_CHAR(object, i); -- if (ucnhash_capi->getname(c, buffer, sizeof(buffer), 1)) { -- replsize = 1+1+1+(int)strlen(buffer)+1; -- } -- else if (c >= 0x10000) { -- replsize = 1+1+8; -- } -- else if (c >= 0x100) { -- replsize = 1+1+4; -- } -- else -- replsize = 1+1+2; -- if (ressize > PY_SSIZE_T_MAX - replsize) -- break; -- ressize += replsize; -+ else { -+ replsize = codec_handler_unicode_hex_width(c); - } -- end = i; -- res = PyUnicode_New(ressize, 127); -- if (res==NULL) -- return NULL; -- for (i = start, outp = PyUnicode_1BYTE_DATA(res); -- i < end; ++i) { -- c = PyUnicode_READ_CHAR(object, i); -- *outp++ = '\\'; -- if (ucnhash_capi->getname(c, buffer, sizeof(buffer), 1)) { -- *outp++ = 'N'; -- *outp++ = '{'; -- strcpy((char *)outp, buffer); -- outp += strlen(buffer); -- *outp++ = '}'; -- continue; -- } -- if (c >= 0x00010000) { -- *outp++ = 'U'; -- *outp++ = Py_hexdigits[(c>>28)&0xf]; -- *outp++ = Py_hexdigits[(c>>24)&0xf]; -- *outp++ = Py_hexdigits[(c>>20)&0xf]; -- *outp++ = Py_hexdigits[(c>>16)&0xf]; -- *outp++ = Py_hexdigits[(c>>12)&0xf]; -- *outp++ = Py_hexdigits[(c>>8)&0xf]; -- } -- else if (c >= 0x100) { -- *outp++ = 'u'; -- *outp++ = Py_hexdigits[(c>>12)&0xf]; -- *outp++ = Py_hexdigits[(c>>8)&0xf]; -- } -- else -- *outp++ = 'x'; -- *outp++ = Py_hexdigits[(c>>4)&0xf]; -- *outp++ = Py_hexdigits[c&0xf]; -+ if (ressize > PY_SSIZE_T_MAX - replsize) { -+ break; - } -- -- assert(outp == PyUnicode_1BYTE_DATA(res) + ressize); -- assert(_PyUnicode_CheckConsistency(res, 1)); -- restuple = Py_BuildValue("(Nn)", res, end); -- Py_DECREF(object); -- return restuple; -+ ressize += replsize; - } -- else { -- wrong_exception_type(exc); -+ -+ PyObject *res = PyUnicode_New(ressize, 127); -+ if (res == NULL) { -+ Py_DECREF(obj); - return NULL; - } -+ -+ Py_UCS1 *outp = PyUnicode_1BYTE_DATA(res); -+ for (Py_ssize_t i = start; i < imax; ++i) { -+ Py_UCS4 c = PyUnicode_READ_CHAR(obj, i); -+ if (ucnhash_capi->getname(c, buffer, sizeof(buffer), 1)) { -+ *outp++ = '\\'; -+ *outp++ = 'N'; -+ *outp++ = '{'; -+ (void)strcpy((char *)outp, buffer); -+ outp += strlen(buffer); -+ *outp++ = '}'; -+ } -+ else { -+ codec_handler_write_unicode_hex(&outp, c); -+ } -+ } -+ -+ assert(outp == PyUnicode_1BYTE_DATA(res) + ressize); -+ assert(_PyUnicode_CheckConsistency(res, 1)); -+ PyObject *restuple = Py_BuildValue("(Nn)", res, imax); -+ Py_DECREF(obj); -+ return restuple; - } - -+ - #define ENC_UNKNOWN -1 - #define ENC_UTF8 0 - #define ENC_UTF16BE 1 -@@ -1358,13 +1397,17 @@ - } - - --static PyObject *strict_errors(PyObject *self, PyObject *exc) -+// --- Codecs registry handlers ----------------------------------------------- -+ -+static inline PyObject * -+strict_errors(PyObject *Py_UNUSED(self), PyObject *exc) - { - return PyCodec_StrictErrors(exc); - } - - --static PyObject *ignore_errors(PyObject *self, PyObject *exc) -+static inline PyObject * -+ignore_errors(PyObject *Py_UNUSED(self), PyObject *exc) - { - return PyCodec_IgnoreErrors(exc); - } -@@ -1387,11 +1430,14 @@ - return PyCodec_BackslashReplaceErrors(exc); - } - --static PyObject *namereplace_errors(PyObject *self, PyObject *exc) -+ -+static inline PyObject * -+namereplace_errors(PyObject *Py_UNUSED(self), PyObject *exc) - { - return PyCodec_NameReplaceErrors(exc); - } - -+ - static PyObject *surrogatepass_errors(PyObject *self, PyObject *exc) - { - return PyCodec_SurrogatePassErrors(exc); -diff --git a/Python/codegen.c b/Python/codegen.c -index a5e550cf8c9..cd77b34c062 100644 ---- a/Python/codegen.c -+++ b/Python/codegen.c -@@ -201,9 +201,6 @@ - static int codegen_slice_two_parts(compiler *, expr_ty); - static int codegen_slice(compiler *, expr_ty); - --static bool are_all_items_const(asdl_expr_seq *, Py_ssize_t, Py_ssize_t); -- -- - static int codegen_with(compiler *, stmt_ty, int); - static int codegen_async_with(compiler *, stmt_ty, int); - static int codegen_async_for(compiler *, stmt_ty); -@@ -287,7 +284,7 @@ - if (PyLong_CheckExact(o)) { - int overflow; - long val = PyLong_AsLongAndOverflow(o, &overflow); -- if (!overflow && val >= 0 && val < 256 && val < _PY_NSMALLPOSINTS) { -+ if (!overflow && _PY_IS_SMALL_INT(val)) { - ADDOP_I(c, loc, LOAD_SMALL_INT, val); - return SUCCESS; - } -@@ -682,7 +679,6 @@ - ADDOP_I(c, loc, COMPARE_OP, (Py_GT << 5) | compare_masks[Py_GT]); - NEW_JUMP_TARGET_LABEL(c, body); - ADDOP_JUMP(c, loc, POP_JUMP_IF_FALSE, body); -- - ADDOP_I(c, loc, LOAD_COMMON_CONSTANT, CONSTANT_NOTIMPLEMENTEDERROR); - ADDOP_I(c, loc, RAISE_VARARGS, 1); - USE_LABEL(c, body); -@@ -696,6 +692,33 @@ - ADDOP_I(c, loc, BUILD_MAP, annotations_len); - ADDOP_IN_SCOPE(c, loc, RETURN_VALUE); - PyCodeObject *co = _PyCompile_OptimizeAndAssemble(c, 1); -+ -+ // We want the parameter to __annotate__ to be named "format" in the -+ // signature shown by inspect.signature(), but we need to use a -+ // different name (.format) in the symtable; if the name -+ // "format" appears in the annotations, it doesn't get clobbered -+ // by this name. This code is essentially: -+ // co->co_localsplusnames = ("format", *co->co_localsplusnames[1:]) -+ const Py_ssize_t size = PyObject_Size(co->co_localsplusnames); -+ if (size == -1) { -+ return ERROR; -+ } -+ PyObject *new_names = PyTuple_New(size); -+ if (new_names == NULL) { -+ return ERROR; -+ } -+ PyTuple_SET_ITEM(new_names, 0, Py_NewRef(&_Py_ID(format))); -+ for (int i = 1; i < size; i++) { -+ PyObject *item = PyTuple_GetItem(co->co_localsplusnames, i); -+ if (item == NULL) { -+ Py_DECREF(new_names); -+ return ERROR; -+ } -+ Py_INCREF(item); -+ PyTuple_SET_ITEM(new_names, i, item); -+ } -+ Py_SETREF(co->co_localsplusnames, new_names); -+ - _PyCompile_ExitScope(c); - if (co == NULL) { - return ERROR; -@@ -1986,7 +2009,7 @@ - * but a non-generator will jump to a later instruction. - */ - ADDOP(c, NO_LOCATION, END_FOR); -- ADDOP(c, NO_LOCATION, POP_TOP); -+ ADDOP(c, NO_LOCATION, POP_ITER); - - _PyCompile_PopFBlock(c, COMPILE_FBLOCK_FOR_LOOP, start); - -@@ -3184,34 +3207,6 @@ - int build, int add, int extend, int tuple) - { - Py_ssize_t n = asdl_seq_LEN(elts); -- if (!injected_arg && n > 2 && are_all_items_const(elts, 0, n)) { -- PyObject *folded = PyTuple_New(n); -- if (folded == NULL) { -- return ERROR; -- } -- for (Py_ssize_t i = 0; i < n; i++) { -- PyObject *val = ((expr_ty)asdl_seq_GET(elts, i))->v.Constant.value; -- PyTuple_SET_ITEM(folded, i, Py_NewRef(val)); -- } -- if (tuple && !pushed) { -- ADDOP_LOAD_CONST_NEW(c, loc, folded); -- } else { -- if (add == SET_ADD) { -- Py_SETREF(folded, PyFrozenSet_New(folded)); -- if (folded == NULL) { -- return ERROR; -- } -- } -- ADDOP_I(c, loc, build, pushed); -- ADDOP_LOAD_CONST_NEW(c, loc, folded); -- ADDOP_I(c, loc, extend, 1); -- if (tuple) { -- ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_LIST_TO_TUPLE); -- } -- } -- return SUCCESS; -- } -- - int big = n + pushed + (injected_arg ? 1 : 0) > STACK_USE_GUIDELINE; - int seen_star = 0; - for (Py_ssize_t i = 0; i < n; i++) { -@@ -3363,18 +3358,6 @@ - BUILD_SET, SET_ADD, SET_UPDATE, 0); - } - --static bool --are_all_items_const(asdl_expr_seq *seq, Py_ssize_t begin, Py_ssize_t end) --{ -- for (Py_ssize_t i = begin; i < end; i++) { -- expr_ty key = (expr_ty)asdl_seq_GET(seq, i); -- if (key == NULL || key->kind != Constant_kind) { -- return false; -- } -- } -- return true; --} -- - static int - codegen_subdict(compiler *c, expr_ty e, Py_ssize_t begin, Py_ssize_t end) - { -@@ -4082,7 +4065,10 @@ - } - assert(have_dict); - } -- ADDOP_I(c, loc, CALL_FUNCTION_EX, nkwelts > 0); -+ if (nkwelts == 0) { -+ ADDOP(c, loc, PUSH_NULL); -+ } -+ ADDOP(c, loc, CALL_FUNCTION_EX); - return SUCCESS; - } - -@@ -4251,7 +4237,7 @@ - * but a non-generator will jump to a later instruction. - */ - ADDOP(c, NO_LOCATION, END_FOR); -- ADDOP(c, NO_LOCATION, POP_TOP); -+ ADDOP(c, NO_LOCATION, POP_ITER); - } - - return SUCCESS; -@@ -5090,7 +5076,7 @@ - VISIT(c, expr, e->v.Subscript.slice); - ADDOP_I(c, loc, COPY, 2); - ADDOP_I(c, loc, COPY, 2); -- ADDOP(c, loc, BINARY_SUBSCR); -+ ADDOP_I(c, loc, BINARY_OP, NB_SUBSCR); - } - break; - case Name_kind: -@@ -5256,7 +5242,6 @@ - { - location loc = LOC(e); - expr_context_ty ctx = e->v.Subscript.ctx; -- int op = 0; - - if (ctx == Load) { - RETURN_IF_ERROR(check_subscripter(c, e->v.Subscript.value)); -@@ -5279,12 +5264,16 @@ - else { - VISIT(c, expr, e->v.Subscript.slice); - switch (ctx) { -- case Load: op = BINARY_SUBSCR; break; -- case Store: op = STORE_SUBSCR; break; -- case Del: op = DELETE_SUBSCR; break; -+ case Load: -+ ADDOP_I(c, loc, BINARY_OP, NB_SUBSCR); -+ break; -+ case Store: -+ ADDOP(c, loc, STORE_SUBSCR); -+ break; -+ case Del: -+ ADDOP(c, loc, DELETE_SUBSCR); -+ break; - } -- assert(op); -- ADDOP(c, loc, op); - } - return SUCCESS; - } -@@ -5516,7 +5505,7 @@ - return SUCCESS; - } - --// Like pattern_helper_sequence_unpack, but uses BINARY_SUBSCR instead of -+// Like pattern_helper_sequence_unpack, but uses BINARY_OP/NB_SUBSCR instead of - // UNPACK_SEQUENCE / UNPACK_EX. This is more efficient for patterns with a - // starred wildcard like [first, *_] / [first, *_, last] / [*_, last] / etc. - static int -@@ -5547,7 +5536,7 @@ - ADDOP_LOAD_CONST_NEW(c, loc, PyLong_FromSsize_t(size - i)); - ADDOP_BINARY(c, loc, Sub); - } -- ADDOP(c, loc, BINARY_SUBSCR); -+ ADDOP_I(c, loc, BINARY_OP, NB_SUBSCR); - RETURN_IF_ERROR(codegen_pattern_subpattern(c, pattern, pc)); - } - // Pop the subject, we're done with it: -diff --git a/Python/compile.c b/Python/compile.c -index cbfba7f493e..b58c12d4b88 100644 ---- a/Python/compile.c -+++ b/Python/compile.c -@@ -704,12 +704,12 @@ - assert(c->u); - /* we are deleting from a list so this really shouldn't fail */ - if (PySequence_DelItem(c->c_stack, n) < 0) { -- PyErr_FormatUnraisable("Exception ignored on removing " -+ PyErr_FormatUnraisable("Exception ignored while removing " - "the last compiler stack item"); - } - if (nested_seq != NULL) { - if (_PyInstructionSequence_AddNested(c->u->u_instr_sequence, nested_seq) < 0) { -- PyErr_FormatUnraisable("Exception ignored on appending " -+ PyErr_FormatUnraisable("Exception ignored while appending " - "nested instruction sequence"); - } - } -@@ -1289,6 +1289,8 @@ - flags |= CO_VARKEYWORDS; - if (ste->ste_has_docstring) - flags |= CO_HAS_DOCSTRING; -+ if (ste->ste_method) -+ flags |= CO_METHOD; - } - - if (ste->ste_coroutine && !ste->ste_generator) { -diff --git a/Python/context.c b/Python/context.c -index 95aa8220627..bb1aa42b9c5 100644 ---- a/Python/context.c -+++ b/Python/context.c -@@ -419,6 +419,9 @@ - /*[clinic end generated code: output=da39a3ee5e6b4b0d input=bdf87f8e0cb580e8]*/ - - -+#define _PyContext_CAST(op) ((PyContext *)(op)) -+ -+ - static inline PyContext * - _context_alloc(void) - { -@@ -513,28 +516,30 @@ - } - - static int --context_tp_clear(PyContext *self) -+context_tp_clear(PyObject *op) - { -+ PyContext *self = _PyContext_CAST(op); - Py_CLEAR(self->ctx_prev); - Py_CLEAR(self->ctx_vars); - return 0; - } - - static int --context_tp_traverse(PyContext *self, visitproc visit, void *arg) -+context_tp_traverse(PyObject *op, visitproc visit, void *arg) - { -+ PyContext *self = _PyContext_CAST(op); - Py_VISIT(self->ctx_prev); - Py_VISIT(self->ctx_vars); - return 0; - } - - static void --context_tp_dealloc(PyContext *self) -+context_tp_dealloc(PyObject *self) - { - _PyObject_GC_UNTRACK(self); -- -- if (self->ctx_weakreflist != NULL) { -- PyObject_ClearWeakRefs((PyObject*)self); -+ PyContext *ctx = _PyContext_CAST(self); -+ if (ctx->ctx_weakreflist != NULL) { -+ PyObject_ClearWeakRefs(self); - } - (void)context_tp_clear(self); - -@@ -542,8 +547,9 @@ - } - - static PyObject * --context_tp_iter(PyContext *self) -+context_tp_iter(PyObject *op) - { -+ PyContext *self = _PyContext_CAST(op); - return _PyHamt_NewIterKeys(self->ctx_vars); - } - -@@ -575,18 +581,20 @@ - } - - static Py_ssize_t --context_tp_len(PyContext *self) -+context_tp_len(PyObject *op) - { -+ PyContext *self = _PyContext_CAST(op); - return _PyHamt_Len(self->ctx_vars); - } - - static PyObject * --context_tp_subscript(PyContext *self, PyObject *key) -+context_tp_subscript(PyObject *op, PyObject *key) - { - if (context_check_key_type(key)) { - return NULL; - } - PyObject *val = NULL; -+ PyContext *self = _PyContext_CAST(op); - int found = _PyHamt_Find(self->ctx_vars, key, &val); - if (found < 0) { - return NULL; -@@ -599,12 +607,13 @@ - } - - static int --context_tp_contains(PyContext *self, PyObject *key) -+context_tp_contains(PyObject *op, PyObject *key) - { - if (context_check_key_type(key)) { - return -1; - } - PyObject *val = NULL; -+ PyContext *self = _PyContext_CAST(op); - return _PyHamt_Find(self->ctx_vars, key, &val); - } - -@@ -701,7 +710,7 @@ - - - static PyObject * --context_run(PyContext *self, PyObject *const *args, -+context_run(PyObject *self, PyObject *const *args, - Py_ssize_t nargs, PyObject *kwnames) - { - PyThreadState *ts = _PyThreadState_GET(); -@@ -712,14 +721,14 @@ - return NULL; - } - -- if (_PyContext_Enter(ts, (PyObject *)self)) { -+ if (_PyContext_Enter(ts, self)) { - return NULL; - } - - PyObject *call_result = _PyObject_VectorcallTstate( - ts, args[0], args + 1, nargs - 1, kwnames); - -- if (_PyContext_Exit(ts, (PyObject *)self)) { -+ if (_PyContext_Exit(ts, self)) { - Py_XDECREF(call_result); - return NULL; - } -@@ -739,21 +748,12 @@ - }; - - static PySequenceMethods PyContext_as_sequence = { -- 0, /* sq_length */ -- 0, /* sq_concat */ -- 0, /* sq_repeat */ -- 0, /* sq_item */ -- 0, /* sq_slice */ -- 0, /* sq_ass_item */ -- 0, /* sq_ass_slice */ -- (objobjproc)context_tp_contains, /* sq_contains */ -- 0, /* sq_inplace_concat */ -- 0, /* sq_inplace_repeat */ -+ .sq_contains = context_tp_contains - }; - - static PyMappingMethods PyContext_as_mapping = { -- (lenfunc)context_tp_len, /* mp_length */ -- (binaryfunc)context_tp_subscript, /* mp_subscript */ -+ .mp_length = context_tp_len, -+ .mp_subscript = context_tp_subscript - }; - - PyTypeObject PyContext_Type = { -@@ -763,13 +763,13 @@ - .tp_methods = PyContext_methods, - .tp_as_mapping = &PyContext_as_mapping, - .tp_as_sequence = &PyContext_as_sequence, -- .tp_iter = (getiterfunc)context_tp_iter, -- .tp_dealloc = (destructor)context_tp_dealloc, -+ .tp_iter = context_tp_iter, -+ .tp_dealloc = context_tp_dealloc, - .tp_getattro = PyObject_GenericGetAttr, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, - .tp_richcompare = context_tp_richcompare, -- .tp_traverse = (traverseproc)context_tp_traverse, -- .tp_clear = (inquiry)context_tp_clear, -+ .tp_traverse = context_tp_traverse, -+ .tp_clear = context_tp_clear, - .tp_new = context_tp_new, - .tp_weaklistoffset = offsetof(PyContext, ctx_weakreflist), - .tp_hash = PyObject_HashNotImplemented, -@@ -860,7 +860,7 @@ - return -1; - } - -- Py_hash_t res = _Py_HashPointer(addr) ^ name_hash; -+ Py_hash_t res = Py_HashPointer(addr) ^ name_hash; - return res == -1 ? -2 : res; - } - -@@ -909,6 +909,9 @@ - /*[clinic end generated code: output=da39a3ee5e6b4b0d input=445da935fa8883c3]*/ - - -+#define _PyContextVar_CAST(op) ((PyContextVar *)(op)) -+ -+ - static PyObject * - contextvar_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) - { -@@ -926,8 +929,9 @@ - } - - static int --contextvar_tp_clear(PyContextVar *self) -+contextvar_tp_clear(PyObject *op) - { -+ PyContextVar *self = _PyContextVar_CAST(op); - Py_CLEAR(self->var_name); - Py_CLEAR(self->var_default); - #ifndef Py_GIL_DISABLED -@@ -939,15 +943,16 @@ - } - - static int --contextvar_tp_traverse(PyContextVar *self, visitproc visit, void *arg) -+contextvar_tp_traverse(PyObject *op, visitproc visit, void *arg) - { -+ PyContextVar *self = _PyContextVar_CAST(op); - Py_VISIT(self->var_name); - Py_VISIT(self->var_default); - return 0; - } - - static void --contextvar_tp_dealloc(PyContextVar *self) -+contextvar_tp_dealloc(PyObject *self) - { - PyObject_GC_UnTrack(self); - (void)contextvar_tp_clear(self); -@@ -955,14 +960,16 @@ - } - - static Py_hash_t --contextvar_tp_hash(PyContextVar *self) -+contextvar_tp_hash(PyObject *op) - { -+ PyContextVar *self = _PyContextVar_CAST(op); - return self->var_hash; - } - - static PyObject * --contextvar_tp_repr(PyContextVar *self) -+contextvar_tp_repr(PyObject *op) - { -+ PyContextVar *self = _PyContextVar_CAST(op); - // Estimation based on the shortest name and default value, - // but maximize the pointer size. - // "" -@@ -1106,15 +1113,15 @@ - sizeof(PyContextVar), - .tp_methods = PyContextVar_methods, - .tp_members = PyContextVar_members, -- .tp_dealloc = (destructor)contextvar_tp_dealloc, -+ .tp_dealloc = contextvar_tp_dealloc, - .tp_getattro = PyObject_GenericGetAttr, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, -- .tp_traverse = (traverseproc)contextvar_tp_traverse, -- .tp_clear = (inquiry)contextvar_tp_clear, -+ .tp_traverse = contextvar_tp_traverse, -+ .tp_clear = contextvar_tp_clear, - .tp_new = contextvar_tp_new, - .tp_free = PyObject_GC_Del, -- .tp_hash = (hashfunc)contextvar_tp_hash, -- .tp_repr = (reprfunc)contextvar_tp_repr, -+ .tp_hash = contextvar_tp_hash, -+ .tp_repr = contextvar_tp_repr, - }; - - -@@ -1129,6 +1136,9 @@ - /*[clinic end generated code: output=da39a3ee5e6b4b0d input=338a5e2db13d3f5b]*/ - - -+#define _PyContextToken_CAST(op) ((PyContextToken *)(op)) -+ -+ - static PyObject * - token_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) - { -@@ -1138,8 +1148,9 @@ - } - - static int --token_tp_clear(PyContextToken *self) -+token_tp_clear(PyObject *op) - { -+ PyContextToken *self = _PyContextToken_CAST(op); - Py_CLEAR(self->tok_ctx); - Py_CLEAR(self->tok_var); - Py_CLEAR(self->tok_oldval); -@@ -1147,8 +1158,9 @@ - } - - static int --token_tp_traverse(PyContextToken *self, visitproc visit, void *arg) -+token_tp_traverse(PyObject *op, visitproc visit, void *arg) - { -+ PyContextToken *self = _PyContextToken_CAST(op); - Py_VISIT(self->tok_ctx); - Py_VISIT(self->tok_var); - Py_VISIT(self->tok_oldval); -@@ -1156,7 +1168,7 @@ - } - - static void --token_tp_dealloc(PyContextToken *self) -+token_tp_dealloc(PyObject *self) - { - PyObject_GC_UnTrack(self); - (void)token_tp_clear(self); -@@ -1164,8 +1176,9 @@ - } - - static PyObject * --token_tp_repr(PyContextToken *self) -+token_tp_repr(PyObject *op) - { -+ PyContextToken *self = _PyContextToken_CAST(op); - PyUnicodeWriter *writer = PyUnicodeWriter_Create(0); - if (writer == NULL) { - return NULL; -@@ -1195,14 +1208,16 @@ - } - - static PyObject * --token_get_var(PyContextToken *self, void *Py_UNUSED(ignored)) -+token_get_var(PyObject *op, void *Py_UNUSED(ignored)) - { -+ PyContextToken *self = _PyContextToken_CAST(op); - return Py_NewRef(self->tok_var);; - } - - static PyObject * --token_get_old_value(PyContextToken *self, void *Py_UNUSED(ignored)) -+token_get_old_value(PyObject *op, void *Py_UNUSED(ignored)) - { -+ PyContextToken *self = _PyContextToken_CAST(op); - if (self->tok_oldval == NULL) { - return get_token_missing(); - } -@@ -1211,8 +1226,8 @@ - } - - static PyGetSetDef PyContextTokenType_getsetlist[] = { -- {"var", (getter)token_get_var, NULL, NULL}, -- {"old_value", (getter)token_get_old_value, NULL, NULL}, -+ {"var", token_get_var, NULL, NULL}, -+ {"old_value", token_get_old_value, NULL, NULL}, - {NULL} - }; - -@@ -1228,15 +1243,15 @@ - sizeof(PyContextToken), - .tp_methods = PyContextTokenType_methods, - .tp_getset = PyContextTokenType_getsetlist, -- .tp_dealloc = (destructor)token_tp_dealloc, -+ .tp_dealloc = token_tp_dealloc, - .tp_getattro = PyObject_GenericGetAttr, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, -- .tp_traverse = (traverseproc)token_tp_traverse, -- .tp_clear = (inquiry)token_tp_clear, -+ .tp_traverse = token_tp_traverse, -+ .tp_clear = token_tp_clear, - .tp_new = token_tp_new, - .tp_free = PyObject_GC_Del, - .tp_hash = PyObject_HashNotImplemented, -- .tp_repr = (reprfunc)token_tp_repr, -+ .tp_repr = token_tp_repr, - }; - - static PyContextToken * -@@ -1270,7 +1285,7 @@ - } - - static void --context_token_missing_tp_dealloc(_PyContextTokenMissing *Py_UNUSED(self)) -+context_token_missing_tp_dealloc(PyObject *Py_UNUSED(self)) - { - #ifdef Py_DEBUG - /* The singleton is statically allocated. */ -@@ -1285,7 +1300,7 @@ - PyVarObject_HEAD_INIT(&PyType_Type, 0) - "Token.MISSING", - sizeof(_PyContextTokenMissing), -- .tp_dealloc = (destructor)context_token_missing_tp_dealloc, -+ .tp_dealloc = context_token_missing_tp_dealloc, - .tp_getattro = PyObject_GenericGetAttr, - .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_repr = context_token_missing_tp_repr, -diff --git a/Python/critical_section.c b/Python/critical_section.c -index 62ed25523fd..73857b85496 100644 ---- a/Python/critical_section.c -+++ b/Python/critical_section.c -@@ -8,11 +8,28 @@ - "critical section must be aligned to at least 4 bytes"); - #endif - -+#ifdef Py_GIL_DISABLED -+static PyCriticalSection * -+untag_critical_section(uintptr_t tag) -+{ -+ return (PyCriticalSection *)(tag & ~_Py_CRITICAL_SECTION_MASK); -+} -+#endif -+ - void - _PyCriticalSection_BeginSlow(PyCriticalSection *c, PyMutex *m) - { - #ifdef Py_GIL_DISABLED - PyThreadState *tstate = _PyThreadState_GET(); -+ // As an optimisation for locking the same object recursively, skip -+ // locking if the mutex is currently locked by the top-most critical -+ // section. -+ if (tstate->critical_section && -+ untag_critical_section(tstate->critical_section)->_cs_mutex == m) { -+ c->_cs_mutex = NULL; -+ c->_cs_prev = 0; -+ return; -+ } - c->_cs_mutex = NULL; - c->_cs_prev = (uintptr_t)tstate->critical_section; - tstate->critical_section = (uintptr_t)c; -@@ -42,13 +59,6 @@ - #endif - } - --#ifdef Py_GIL_DISABLED --static PyCriticalSection * --untag_critical_section(uintptr_t tag) --{ -- return (PyCriticalSection *)(tag & ~_Py_CRITICAL_SECTION_MASK); --} --#endif - - // Release all locks held by critical sections. This is called by - // _PyThreadState_Detach. -diff --git a/Python/crossinterp.c b/Python/crossinterp.c -index 0a106ad636b..aa2c1cb78bc 100644 ---- a/Python/crossinterp.c -+++ b/Python/crossinterp.c -@@ -368,12 +368,9 @@ - PyObject *create = NULL; - - // This is inspired by _PyErr_Display(). -- PyObject *tbmod = PyImport_ImportModule("traceback"); -- if (tbmod == NULL) { -- return -1; -- } -- PyObject *tbexc_type = PyObject_GetAttrString(tbmod, "TracebackException"); -- Py_DECREF(tbmod); -+ PyObject *tbexc_type = PyImport_ImportModuleAttrString( -+ "traceback", -+ "TracebackException"); - if (tbexc_type == NULL) { - return -1; - } -@@ -784,7 +781,8 @@ - PyObject *exc = PyErr_GetRaisedException(); - if (PyObject_SetAttrString(exc, "_errdisplay", tbexc) < 0) { - #ifdef Py_DEBUG -- PyErr_FormatUnraisable("Exception ignored when setting _errdisplay"); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "setting _errdisplay"); - #endif - PyErr_Clear(); - } -diff --git a/Python/emscripten_trampoline.c b/Python/emscripten_trampoline.c -index 960c6b4a2ef..0293c7ea0f3 100644 ---- a/Python/emscripten_trampoline.c -+++ b/Python/emscripten_trampoline.c -@@ -1,79 +1,203 @@ - #if defined(PY_CALL_TRAMPOLINE) - --#include // EM_JS -+#include // EM_JS, EM_JS_DEPS - #include - #include "pycore_runtime.h" // _PyRuntime - -+typedef int (*CountArgsFunc)(PyCFunctionWithKeywords func); - --/** -- * This is the GoogleChromeLabs approved way to feature detect type-reflection: -- * https://github.com/GoogleChromeLabs/wasm-feature-detect/blob/main/src/detectors/type-reflection/index.js -- */ --EM_JS(int, _PyEM_detect_type_reflection, (), { -- if (!("Function" in WebAssembly)) { -- return false; -- } -- if (WebAssembly.Function.type) { -- // Node v20 -- Module.PyEM_CountArgs = (func) => WebAssembly.Function.type(wasmTable.get(func)).parameters.length; -- } else { -- // Node >= 22, v8-based browsers -- Module.PyEM_CountArgs = (func) => wasmTable.get(func).type().parameters.length; -+// Offset of emscripten_count_args_function in _PyRuntimeState. There's a couple -+// of alternatives: -+// 1. Just make emscripten_count_args_function a real C global variable instead -+// of a field of _PyRuntimeState. This would violate our rule against mutable -+// globals. -+// 2. #define a preprocessor constant equal to a hard coded number and make a -+// _Static_assert(offsetof(_PyRuntimeState, emscripten_count_args_function) -+// == OURCONSTANT) This has the disadvantage that we have to update the hard -+// coded constant when _PyRuntimeState changes -+// -+// So putting the mutable constant in _PyRuntime and using a immutable global to -+// record the offset so we can access it from JS is probably the best way. -+EMSCRIPTEN_KEEPALIVE const int _PyEM_EMSCRIPTEN_COUNT_ARGS_OFFSET = offsetof(_PyRuntimeState, emscripten_count_args_function); -+ -+EM_JS(CountArgsFunc, _PyEM_GetCountArgsPtr, (), { -+ return Module._PyEM_CountArgsPtr; // initialized below -+} -+// Binary module for the checks. It has to be done in web assembly because -+// clang/llvm have no support yet for the reference types yet. In fact, the wasm -+// binary toolkit doesn't yet support the ref.test instruction either. To -+// convert the following textual wasm to a binary, you can build wabt from this -+// branch: https://github.com/WebAssembly/wabt/pull/2529 and then use that -+// wat2wasm binary. -+// -+// (module -+// (type $type0 (func (param) (result i32))) -+// (type $type1 (func (param i32) (result i32))) -+// (type $type2 (func (param i32 i32) (result i32))) -+// (type $type3 (func (param i32 i32 i32) (result i32))) -+// (type $blocktype (func (param i32) (result))) -+// (table $funcs (import "e" "t") 0 funcref) -+// (export "f" (func $f)) -+// (func $f (param $fptr i32) (result i32) -+// (local $fref funcref) -+// local.get $fptr -+// table.get $funcs -+// local.tee $fref -+// ref.test $type3 -+// (block $b (type $blocktype) -+// i32.eqz -+// br_if $b -+// i32.const 3 -+// return -+// ) -+// local.get $fref -+// ref.test $type2 -+// (block $b (type $blocktype) -+// i32.eqz -+// br_if $b -+// i32.const 2 -+// return -+// ) -+// local.get $fref -+// ref.test $type1 -+// (block $b (type $blocktype) -+// i32.eqz -+// br_if $b -+// i32.const 1 -+// return -+// ) -+// local.get $fref -+// ref.test $type0 -+// (block $b (type $blocktype) -+// i32.eqz -+// br_if $b -+// i32.const 0 -+// return -+// ) -+// i32.const -1 -+// ) -+// ) -+addOnPreRun(() => { -+ // Try to initialize countArgsFunc -+ const code = new Uint8Array([ -+ 0x00, 0x61, 0x73, 0x6d, // \0asm magic number -+ 0x01, 0x00, 0x00, 0x00, // version 1 -+ 0x01, 0x1b, // Type section, body is 0x1b bytes -+ 0x05, // 6 entries -+ 0x60, 0x00, 0x01, 0x7f, // (type $type0 (func (param) (result i32))) -+ 0x60, 0x01, 0x7f, 0x01, 0x7f, // (type $type1 (func (param i32) (result i32))) -+ 0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f, // (type $type2 (func (param i32 i32) (result i32))) -+ 0x60, 0x03, 0x7f, 0x7f, 0x7f, 0x01, 0x7f, // (type $type3 (func (param i32 i32 i32) (result i32))) -+ 0x60, 0x01, 0x7f, 0x00, // (type $blocktype (func (param i32) (result))) -+ 0x02, 0x09, // Import section, 0x9 byte body -+ 0x01, // 1 import (table $funcs (import "e" "t") 0 funcref) -+ 0x01, 0x65, // "e" -+ 0x01, 0x74, // "t" -+ 0x01, // importing a table -+ 0x70, // of entry type funcref -+ 0x00, 0x00, // table limits: no max, min of 0 -+ 0x03, 0x02, // Function section -+ 0x01, 0x01, // We're going to define one function of type 1 (func (param i32) (result i32)) -+ 0x07, 0x05, // export section -+ 0x01, // 1 export -+ 0x01, 0x66, // called "f" -+ 0x00, // a function -+ 0x00, // at index 0 -+ -+ 0x0a, 0x44, // Code section, -+ 0x01, 0x42, // one entry of length 50 -+ 0x01, 0x01, 0x70, // one local of type funcref -+ // Body of the function -+ 0x20, 0x00, // local.get $fptr -+ 0x25, 0x00, // table.get $funcs -+ 0x22, 0x01, // local.tee $fref -+ 0xfb, 0x14, 0x03, // ref.test $type3 -+ 0x02, 0x04, // block $b (type $blocktype) -+ 0x45, // i32.eqz -+ 0x0d, 0x00, // br_if $b -+ 0x41, 0x03, // i32.const 3 -+ 0x0f, // return -+ 0x0b, // end block -+ -+ 0x20, 0x01, // local.get $fref -+ 0xfb, 0x14, 0x02, // ref.test $type2 -+ 0x02, 0x04, // block $b (type $blocktype) -+ 0x45, // i32.eqz -+ 0x0d, 0x00, // br_if $b -+ 0x41, 0x02, // i32.const 2 -+ 0x0f, // return -+ 0x0b, // end block -+ -+ 0x20, 0x01, // local.get $fref -+ 0xfb, 0x14, 0x01, // ref.test $type1 -+ 0x02, 0x04, // block $b (type $blocktype) -+ 0x45, // i32.eqz -+ 0x0d, 0x00, // br_if $b -+ 0x41, 0x01, // i32.const 1 -+ 0x0f, // return -+ 0x0b, // end block -+ -+ 0x20, 0x01, // local.get $fref -+ 0xfb, 0x14, 0x00, // ref.test $type0 -+ 0x02, 0x04, // block $b (type $blocktype) -+ 0x45, // i32.eqz -+ 0x0d, 0x00, // br_if $b -+ 0x41, 0x00, // i32.const 0 -+ 0x0f, // return -+ 0x0b, // end block -+ -+ 0x41, 0x7f, // i32.const -1 -+ 0x0b // end function -+ ]); -+ let ptr = 0; -+ try { -+ const mod = new WebAssembly.Module(code); -+ const inst = new WebAssembly.Instance(mod, { e: { t: wasmTable } }); -+ ptr = addFunction(inst.exports.f); -+ } catch (e) { -+ // If something goes wrong, we'll null out _PyEM_CountFuncParams and fall -+ // back to the JS trampoline. - } -- return true; -+ Module._PyEM_CountArgsPtr = ptr; -+ const offset = HEAP32[__PyEM_EMSCRIPTEN_COUNT_ARGS_OFFSET / 4]; -+ HEAP32[(__PyRuntime + offset) / 4] = ptr; - }); -+); - - void - _Py_EmscriptenTrampoline_Init(_PyRuntimeState *runtime) - { -- runtime->wasm_type_reflection_available = _PyEM_detect_type_reflection(); -+ runtime->emscripten_count_args_function = _PyEM_GetCountArgsPtr(); - } - -+// We have to be careful to work correctly with memory snapshots. Even if we are -+// loading a memory snapshot, we need to perform the JS initialization work. -+// That means we can't call the initialization code from C. Instead, we export -+// this function pointer to JS and then fill it in a preRun function which runs -+// unconditionally. - /** - * Backwards compatible trampoline works with all JS runtimes - */ --EM_JS(PyObject*, --_PyEM_TrampolineCall_JavaScript, (PyCFunctionWithKeywords func, -- PyObject *arg1, -- PyObject *arg2, -- PyObject *arg3), --{ -+EM_JS(PyObject*, _PyEM_TrampolineCall_JS, (PyCFunctionWithKeywords func, PyObject *arg1, PyObject *arg2, PyObject *arg3), { - return wasmTable.get(func)(arg1, arg2, arg3); --} --); -- --/** -- * In runtimes with WebAssembly type reflection, count the number of parameters -- * and cast to the appropriate signature -- */ --EM_JS(int, _PyEM_CountFuncParams, (PyCFunctionWithKeywords func), --{ -- let n = _PyEM_CountFuncParams.cache.get(func); -- -- if (n !== undefined) { -- return n; -- } -- n = Module.PyEM_CountArgs(func); -- _PyEM_CountFuncParams.cache.set(func, n); -- return n; --} --_PyEM_CountFuncParams.cache = new Map(); --) -- -+}); - - typedef PyObject* (*zero_arg)(void); - typedef PyObject* (*one_arg)(PyObject*); - typedef PyObject* (*two_arg)(PyObject*, PyObject*); - typedef PyObject* (*three_arg)(PyObject*, PyObject*, PyObject*); - -- - PyObject* --_PyEM_TrampolineCall_Reflection(PyCFunctionWithKeywords func, -- PyObject* self, -- PyObject* args, -- PyObject* kw) -+_PyEM_TrampolineCall(PyCFunctionWithKeywords func, -+ PyObject* self, -+ PyObject* args, -+ PyObject* kw) - { -- switch (_PyEM_CountFuncParams(func)) { -+ CountArgsFunc count_args = _PyRuntime.emscripten_count_args_function; -+ if (count_args == 0) { -+ return _PyEM_TrampolineCall_JS(func, self, args, kw); -+ } -+ switch (count_args(func)) { - case 0: - return ((zero_arg)func)(); - case 1: -@@ -83,8 +207,7 @@ - case 3: - return ((three_arg)func)(self, args, kw); - default: -- PyErr_SetString(PyExc_SystemError, -- "Handler takes too many arguments"); -+ PyErr_SetString(PyExc_SystemError, "Handler takes too many arguments"); - return NULL; - } - } -diff --git a/Python/errors.c b/Python/errors.c -index 7f3b4aabc43..0a19d898da7 100644 ---- a/Python/errors.c -+++ b/Python/errors.c -@@ -301,12 +301,21 @@ - _PyErr_SetString(tstate, exception, string); - } - -+void -+_PyErr_SetLocaleString(PyObject *exception, const char *string) -+{ -+ PyObject *value = PyUnicode_DecodeLocale(string, "surrogateescape"); -+ if (value != NULL) { -+ PyErr_SetObject(exception, value); -+ Py_DECREF(value); -+ } -+} - - PyObject* _Py_HOT_FUNCTION - PyErr_Occurred(void) - { -- /* The caller must hold the GIL. */ -- assert(PyGILState_Check()); -+ /* The caller must hold a thread state. */ -+ _Py_AssertHoldsTstate(); - - PyThreadState *tstate = _PyThreadState_GET(); - return _PyErr_Occurred(tstate); -@@ -1624,7 +1633,7 @@ - PyObject *hook_args = make_unraisable_hook_args( - tstate, exc_type, exc_value, exc_tb, err_msg, obj); - if (hook_args == NULL) { -- err_msg_str = ("Exception ignored on building " -+ err_msg_str = ("Exception ignored while building " - "sys.unraisablehook arguments"); - goto error; - } -@@ -1972,7 +1981,7 @@ - return NULL; - } - -- FILE *fp = _Py_fopen_obj(filename, "r" PY_STDIOTEXTMODE); -+ FILE *fp = Py_fopen(filename, "r" PY_STDIOTEXTMODE); - if (fp == NULL) { - PyErr_Clear(); - return NULL; -diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h -index 55e9c3aa2db..96b7386bd24 100644 ---- a/Python/executor_cases.c.h -+++ b/Python/executor_cases.c.h -@@ -19,7 +19,9 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = _Py_HandlePending(tstate); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err != 0) JUMP_TO_ERROR(); -+ if (err != 0) { -+ JUMP_TO_ERROR(); -+ } - } - break; - } -@@ -33,7 +35,9 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = _Py_HandlePending(tstate); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err != 0) JUMP_TO_ERROR(); -+ if (err != 0) { -+ JUMP_TO_ERROR(); -+ } - } - } - break; -@@ -81,7 +85,7 @@ - PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames, oparg) - ); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (1) JUMP_TO_ERROR(); -+ JUMP_TO_ERROR(); - } - value = PyStackRef_DUP(value_s); - stack_pointer[0] = value; -@@ -201,7 +205,6 @@ - _PyStackRef value; - oparg = CURRENT_OPARG(); - value = GETLOCAL(oparg); -- // do not use SETLOCAL here, it decrefs the old value - GETLOCAL(oparg) = PyStackRef_NULL; - stack_pointer[0] = value; - stack_pointer += 1; -@@ -209,10 +212,13 @@ - break; - } - -- case _LOAD_CONST: { -+ /* _LOAD_CONST is not a viable micro-op for tier 2 because it uses the 'this_instr' variable */ -+ -+ case _LOAD_CONST_MORTAL: { - _PyStackRef value; - oparg = CURRENT_OPARG(); -- value = PyStackRef_FromPyObjectNew(GETITEM(FRAME_CO_CONSTS, oparg)); -+ PyObject *obj = GETITEM(FRAME_CO_CONSTS, oparg); -+ value = PyStackRef_FromPyObjectNew(obj); - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); -@@ -300,9 +306,13 @@ - oparg = 0; - assert(oparg == CURRENT_OPARG()); - value = stack_pointer[-1]; -- SETLOCAL(oparg, value); -+ _PyStackRef tmp = GETLOCAL(oparg); -+ GETLOCAL(oparg) = value; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_XCLOSE(tmp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - break; - } - -@@ -311,9 +321,13 @@ - oparg = 1; - assert(oparg == CURRENT_OPARG()); - value = stack_pointer[-1]; -- SETLOCAL(oparg, value); -+ _PyStackRef tmp = GETLOCAL(oparg); -+ GETLOCAL(oparg) = value; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_XCLOSE(tmp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - break; - } - -@@ -322,9 +336,13 @@ - oparg = 2; - assert(oparg == CURRENT_OPARG()); - value = stack_pointer[-1]; -- SETLOCAL(oparg, value); -+ _PyStackRef tmp = GETLOCAL(oparg); -+ GETLOCAL(oparg) = value; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_XCLOSE(tmp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - break; - } - -@@ -333,9 +351,13 @@ - oparg = 3; - assert(oparg == CURRENT_OPARG()); - value = stack_pointer[-1]; -- SETLOCAL(oparg, value); -+ _PyStackRef tmp = GETLOCAL(oparg); -+ GETLOCAL(oparg) = value; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_XCLOSE(tmp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - break; - } - -@@ -344,9 +366,13 @@ - oparg = 4; - assert(oparg == CURRENT_OPARG()); - value = stack_pointer[-1]; -- SETLOCAL(oparg, value); -+ _PyStackRef tmp = GETLOCAL(oparg); -+ GETLOCAL(oparg) = value; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_XCLOSE(tmp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - break; - } - -@@ -355,9 +381,13 @@ - oparg = 5; - assert(oparg == CURRENT_OPARG()); - value = stack_pointer[-1]; -- SETLOCAL(oparg, value); -+ _PyStackRef tmp = GETLOCAL(oparg); -+ GETLOCAL(oparg) = value; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_XCLOSE(tmp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - break; - } - -@@ -366,9 +396,13 @@ - oparg = 6; - assert(oparg == CURRENT_OPARG()); - value = stack_pointer[-1]; -- SETLOCAL(oparg, value); -+ _PyStackRef tmp = GETLOCAL(oparg); -+ GETLOCAL(oparg) = value; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_XCLOSE(tmp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - break; - } - -@@ -377,9 +411,13 @@ - oparg = 7; - assert(oparg == CURRENT_OPARG()); - value = stack_pointer[-1]; -- SETLOCAL(oparg, value); -+ _PyStackRef tmp = GETLOCAL(oparg); -+ GETLOCAL(oparg) = value; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_XCLOSE(tmp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - break; - } - -@@ -387,9 +425,13 @@ - _PyStackRef value; - oparg = CURRENT_OPARG(); - value = stack_pointer[-1]; -- SETLOCAL(oparg, value); -+ _PyStackRef tmp = GETLOCAL(oparg); -+ GETLOCAL(oparg) = value; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_XCLOSE(tmp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - break; - } - -@@ -411,6 +453,22 @@ - break; - } - -+ case _END_FOR: { -+ _PyStackRef value; -+ value = stack_pointer[-1]; -+ /* Don't update instr_ptr, so that POP_ITER sees -+ * the FOR_ITER as the previous instruction. -+ * This has the benign side effect that if value is -+ * finalized it will see the location as the FOR_ITER's. -+ */ -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(value); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ break; -+ } -+ - case _END_SEND: { - _PyStackRef value; - _PyStackRef receiver; -@@ -434,7 +492,11 @@ - PyObject *res_o = PyNumber_Negative(PyStackRef_AsPyObjectBorrow(value)); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(value); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ if (res_o == NULL) { -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-1] = res; - break; -@@ -459,7 +521,11 @@ - int err = PyObject_IsTrue(PyStackRef_AsPyObjectBorrow(value)); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(value); -- if (err < 0) JUMP_TO_ERROR(); -+ if (err < 0) { -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - res = err ? PyStackRef_True : PyStackRef_False; - stack_pointer[-1] = res; - break; -@@ -570,7 +636,11 @@ - PyObject *res_o = PyNumber_Invert(PyStackRef_AsPyObjectBorrow(value)); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(value); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ if (res_o == NULL) { -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-1] = res; - break; -@@ -624,11 +694,17 @@ - left = stack_pointer[-2]; - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(PyLong_CheckExact(left_o)); -+ assert(PyLong_CheckExact(right_o)); - STAT_INC(BINARY_OP, hit); - PyObject *res_o = _PyLong_Multiply((PyLongObject *)left_o, (PyLongObject *)right_o); - PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ if (res_o == NULL) { -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -644,11 +720,17 @@ - left = stack_pointer[-2]; - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(PyLong_CheckExact(left_o)); -+ assert(PyLong_CheckExact(right_o)); - STAT_INC(BINARY_OP, hit); - PyObject *res_o = _PyLong_Add((PyLongObject *)left_o, (PyLongObject *)right_o); - PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ if (res_o == NULL) { -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -664,11 +746,17 @@ - left = stack_pointer[-2]; - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(PyLong_CheckExact(left_o)); -+ assert(PyLong_CheckExact(right_o)); - STAT_INC(BINARY_OP, hit); - PyObject *res_o = _PyLong_Subtract((PyLongObject *)left_o, (PyLongObject *)right_o); - PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ if (res_o == NULL) { -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -724,12 +812,18 @@ - left = stack_pointer[-2]; - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(PyFloat_CheckExact(left_o)); -+ assert(PyFloat_CheckExact(right_o)); - STAT_INC(BINARY_OP, hit); - double dres = - ((PyFloatObject *)left_o)->ob_fval * - ((PyFloatObject *)right_o)->ob_fval; - PyObject *res_o = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ if (res_o == NULL) { -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -745,12 +839,18 @@ - left = stack_pointer[-2]; - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(PyFloat_CheckExact(left_o)); -+ assert(PyFloat_CheckExact(right_o)); - STAT_INC(BINARY_OP, hit); - double dres = - ((PyFloatObject *)left_o)->ob_fval + - ((PyFloatObject *)right_o)->ob_fval; - PyObject *res_o = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ if (res_o == NULL) { -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -766,12 +866,18 @@ - left = stack_pointer[-2]; - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(PyFloat_CheckExact(left_o)); -+ assert(PyFloat_CheckExact(right_o)); - STAT_INC(BINARY_OP, hit); - double dres = - ((PyFloatObject *)left_o)->ob_fval - - ((PyFloatObject *)right_o)->ob_fval; - PyObject *res_o = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ if (res_o == NULL) { -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -805,11 +911,17 @@ - left = stack_pointer[-2]; - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(PyUnicode_CheckExact(left_o)); -+ assert(PyUnicode_CheckExact(right_o)); - STAT_INC(BINARY_OP, hit); - PyObject *res_o = PyUnicode_Concat(left_o, right_o); -- PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); -+ if (res_o == NULL) { -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -824,6 +936,8 @@ - left = stack_pointer[-2]; - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(PyUnicode_CheckExact(left_o)); -+ assert(PyUnicode_CheckExact(right_o)); - int next_oparg; - #if TIER_ONE - assert(next_instr->op.code == STORE_FAST); -@@ -849,12 +963,16 @@ - * that the string is safe to mutate. - */ - assert(Py_REFCNT(left_o) >= 2); -- PyStackRef_CLOSE(left); -- PyObject *temp = PyStackRef_AsPyObjectBorrow(*target_local); -+ PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); -+ PyObject *temp = PyStackRef_AsPyObjectSteal(*target_local); - PyUnicode_Append(&temp, right_o); - *target_local = PyStackRef_FromPyObjectSteal(temp); - PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); -- if (PyStackRef_IsNull(*target_local)) JUMP_TO_ERROR(); -+ if (PyStackRef_IsNull(*target_local)) { -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - #if TIER_ONE - // The STORE_FAST is already done. This is done here in tier one, - // and during trace projection in tier two: -@@ -866,20 +984,44 @@ - break; - } - -- case _BINARY_SUBSCR: { -- _PyStackRef sub; -- _PyStackRef container; -+ case _GUARD_BINARY_OP_EXTEND: { -+ _PyStackRef right; -+ _PyStackRef left; -+ right = stack_pointer[-1]; -+ left = stack_pointer[-2]; -+ PyObject *descr = (PyObject *)CURRENT_OPERAND0(); -+ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); -+ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ _PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr; -+ assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5); -+ assert(d && d->guard); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ int res = d->guard(left_o, right_o); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (!res) { -+ UOP_STAT_INC(uopcode, miss); -+ JUMP_TO_JUMP_TARGET(); -+ } -+ break; -+ } -+ -+ case _BINARY_OP_EXTEND: { -+ _PyStackRef right; -+ _PyStackRef left; - _PyStackRef res; -- sub = stack_pointer[-1]; -- container = stack_pointer[-2]; -- PyObject *container_o = PyStackRef_AsPyObjectBorrow(container); -- PyObject *sub_o = PyStackRef_AsPyObjectBorrow(sub); -+ right = stack_pointer[-1]; -+ left = stack_pointer[-2]; -+ PyObject *descr = (PyObject *)CURRENT_OPERAND0(); -+ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); -+ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5); -+ _PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr; -+ STAT_INC(BINARY_OP, hit); - _PyFrame_SetStackPointer(frame, stack_pointer); -- PyObject *res_o = PyObject_GetItem(container_o, sub_o); -+ PyObject *res_o = d->action(left_o, right_o); - stack_pointer = _PyFrame_GetStackPointer(frame); -- PyStackRef_CLOSE(container); -- PyStackRef_CLOSE(sub); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ PyStackRef_CLOSE(left); -+ PyStackRef_CLOSE(right); - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -910,16 +1052,22 @@ - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - res_o = PyObject_GetItem(PyStackRef_AsPyObjectBorrow(container), slice); -- stack_pointer = _PyFrame_GetStackPointer(frame); - Py_DECREF(slice); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += 2; - assert(WITHIN_STACK_BOUNDS()); - } -+ stack_pointer += -3; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(container); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (res_o == NULL) { -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); -- stack_pointer[-3] = res; -- stack_pointer += -2; -+ stack_pointer[0] = res; -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } -@@ -946,20 +1094,24 @@ - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - err = PyObject_SetItem(PyStackRef_AsPyObjectBorrow(container), slice, PyStackRef_AsPyObjectBorrow(v)); -- stack_pointer = _PyFrame_GetStackPointer(frame); - Py_DECREF(slice); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += 2; - assert(WITHIN_STACK_BOUNDS()); - } - PyStackRef_CLOSE(v); - PyStackRef_CLOSE(container); -- if (err) JUMP_TO_ERROR(); -+ if (err) { -+ stack_pointer += -4; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - stack_pointer += -4; - assert(WITHIN_STACK_BOUNDS()); - break; - } - -- case _BINARY_SUBSCR_LIST_INT: { -+ case _BINARY_OP_SUBSCR_LIST_INT: { - _PyStackRef sub_st; - _PyStackRef list_st; - _PyStackRef res; -@@ -989,27 +1141,31 @@ - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } -- STAT_INC(BINARY_SUBSCR, hit); -+ STAT_INC(BINARY_OP, hit); - #else - if (index >= PyList_GET_SIZE(list)) { - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } -- STAT_INC(BINARY_SUBSCR, hit); -+ STAT_INC(BINARY_OP, hit); - PyObject *res_o = PyList_GET_ITEM(list, index); - assert(res_o != NULL); - Py_INCREF(res_o); - #endif - PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(list_st); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - res = PyStackRef_FromPyObjectSteal(res_o); -- stack_pointer[-2] = res; -- stack_pointer += -1; -+ stack_pointer[0] = res; -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } - -- case _BINARY_SUBSCR_STR_INT: { -+ case _BINARY_OP_SUBSCR_STR_INT: { - _PyStackRef sub_st; - _PyStackRef str_st; - _PyStackRef res; -@@ -1040,18 +1196,22 @@ - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } -- STAT_INC(BINARY_SUBSCR, hit); -+ STAT_INC(BINARY_OP, hit); - PyObject *res_o = (PyObject*)&_Py_SINGLETON(strings).ascii[c]; - PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(str_st); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - res = PyStackRef_FromPyObjectSteal(res_o); -- stack_pointer[-2] = res; -- stack_pointer += -1; -+ stack_pointer[0] = res; -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } - -- case _BINARY_SUBSCR_TUPLE_INT: { -+ case _BINARY_OP_SUBSCR_TUPLE_INT: { - _PyStackRef sub_st; - _PyStackRef tuple_st; - _PyStackRef res; -@@ -1077,20 +1237,24 @@ - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } -- STAT_INC(BINARY_SUBSCR, hit); -+ STAT_INC(BINARY_OP, hit); - PyObject *res_o = PyTuple_GET_ITEM(tuple, index); - assert(res_o != NULL); - Py_INCREF(res_o); - PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(tuple_st); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - res = PyStackRef_FromPyObjectSteal(res_o); -- stack_pointer[-2] = res; -- stack_pointer += -1; -+ stack_pointer[0] = res; -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } - -- case _BINARY_SUBSCR_DICT: { -+ case _BINARY_OP_SUBSCR_DICT: { - _PyStackRef sub_st; - _PyStackRef dict_st; - _PyStackRef res; -@@ -1102,7 +1266,7 @@ - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } -- STAT_INC(BINARY_SUBSCR, hit); -+ STAT_INC(BINARY_OP, hit); - PyObject *res_o; - _PyFrame_SetStackPointer(frame, stack_pointer); - int rc = PyDict_GetItemRef(dict, sub, &res_o); -@@ -1114,7 +1278,11 @@ - } - PyStackRef_CLOSE(dict_st); - PyStackRef_CLOSE(sub_st); -- if (rc <= 0) JUMP_TO_ERROR(); -+ if (rc <= 0) { -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - // not found or error - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-2] = res; -@@ -1123,8 +1291,9 @@ - break; - } - -- case _BINARY_SUBSCR_CHECK_FUNC: { -+ case _BINARY_OP_SUBSCR_CHECK_FUNC: { - _PyStackRef container; -+ _PyStackRef getitem; - container = stack_pointer[-2]; - PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(container)); - if (!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) { -@@ -1132,42 +1301,45 @@ - JUMP_TO_JUMP_TARGET(); - } - PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; -- PyObject *getitem = ht->_spec_cache.getitem; -- if (getitem == NULL) { -+ PyObject *getitem_o = FT_ATOMIC_LOAD_PTR_ACQUIRE(ht->_spec_cache.getitem); -+ if (getitem_o == NULL) { - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } -- assert(PyFunction_Check(getitem)); -- uint32_t cached_version = ht->_spec_cache.getitem_version; -- if (((PyFunctionObject *)getitem)->func_version != cached_version) { -+ assert(PyFunction_Check(getitem_o)); -+ uint32_t cached_version = FT_ATOMIC_LOAD_UINT32_RELAXED(ht->_spec_cache.getitem_version); -+ if (((PyFunctionObject *)getitem_o)->func_version != cached_version) { - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } -- PyCodeObject *code = (PyCodeObject *)PyFunction_GET_CODE(getitem); -+ PyCodeObject *code = (PyCodeObject *)PyFunction_GET_CODE(getitem_o); - assert(code->co_argcount == 2); - if (!_PyThreadState_HasStackSpace(tstate, code->co_framesize)) { - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } -- STAT_INC(BINARY_SUBSCR, hit); -+ getitem = PyStackRef_FromPyObjectNew(getitem_o); -+ STAT_INC(BINARY_OP, hit); -+ stack_pointer[0] = getitem; -+ stack_pointer += 1; -+ assert(WITHIN_STACK_BOUNDS()); - break; - } - -- case _BINARY_SUBSCR_INIT_CALL: { -+ case _BINARY_OP_SUBSCR_INIT_CALL: { -+ _PyStackRef getitem; - _PyStackRef sub; - _PyStackRef container; - _PyInterpreterFrame *new_frame; -- sub = stack_pointer[-1]; -- container = stack_pointer[-2]; -- PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(container)); -- PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; -- PyObject *getitem = ht->_spec_cache.getitem; -- new_frame = _PyFrame_PushUnchecked(tstate, PyStackRef_FromPyObjectNew(getitem), 2, frame); -+ getitem = stack_pointer[-1]; -+ sub = stack_pointer[-2]; -+ container = stack_pointer[-3]; -+ new_frame = _PyFrame_PushUnchecked(tstate, getitem, 2, frame); - new_frame->localsplus[0] = container; - new_frame->localsplus[1] = sub; -- frame->return_offset = 2 ; -- stack_pointer[-2].bits = (uintptr_t)new_frame; -- stack_pointer += -1; -+ frame->return_offset = 6 ; -+ stack_pointer[-3].bits = (uintptr_t)new_frame; -+ stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); - break; - } -@@ -1180,7 +1352,11 @@ - list = stack_pointer[-2 - (oparg-1)]; - int err = _PyList_AppendTakeRef((PyListObject *)PyStackRef_AsPyObjectBorrow(list), - PyStackRef_AsPyObjectSteal(v)); -- if (err < 0) JUMP_TO_ERROR(); -+ if (err < 0) { -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - break; -@@ -1197,7 +1373,11 @@ - PyStackRef_AsPyObjectBorrow(v)); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(v); -- if (err) JUMP_TO_ERROR(); -+ if (err) { -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - break; -@@ -1217,7 +1397,11 @@ - PyStackRef_CLOSE(v); - PyStackRef_CLOSE(container); - PyStackRef_CLOSE(sub); -- if (err) JUMP_TO_ERROR(); -+ if (err) { -+ stack_pointer += -3; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); - break; -@@ -1263,11 +1447,13 @@ - PyList_SET_ITEM(list, index, PyStackRef_AsPyObjectSteal(value)); - assert(old_value != NULL); - UNLOCK_OBJECT(list); // unlock before decrefs! -- Py_DECREF(old_value); - PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); -- PyStackRef_CLOSE(list_st); - stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(list_st); -+ Py_DECREF(old_value); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - break; - } - -@@ -1289,10 +1475,14 @@ - PyStackRef_AsPyObjectSteal(sub), - PyStackRef_AsPyObjectSteal(value)); - stack_pointer = _PyFrame_GetStackPointer(frame); -- PyStackRef_CLOSE(dict_st); -- if (err) JUMP_TO_ERROR(); - stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(dict_st); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (err) { -+ JUMP_TO_ERROR(); -+ } - break; - } - -@@ -1308,7 +1498,11 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(container); - PyStackRef_CLOSE(sub); -- if (err) JUMP_TO_ERROR(); -+ if (err) { -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); - break; -@@ -1324,7 +1518,11 @@ - PyObject *res_o = _PyIntrinsics_UnaryFunctions[oparg].func(tstate, PyStackRef_AsPyObjectBorrow(value)); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(value); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ if (res_o == NULL) { -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-1] = res; - break; -@@ -1345,7 +1543,11 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(value2_st); - PyStackRef_CLOSE(value1_st); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ if (res_o == NULL) { -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -1357,9 +1559,7 @@ - _PyStackRef retval; - _PyStackRef res; - retval = stack_pointer[-1]; -- #if TIER_ONE -- assert(frame != &entry_frame); -- #endif -+ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); - _PyStackRef temp = retval; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); -@@ -1399,13 +1599,19 @@ - type->tp_name); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(obj); -- if (true) JUMP_TO_ERROR(); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - iter_o = (*getter)(obj_o); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(obj); -- if (iter_o == NULL) JUMP_TO_ERROR(); -+ if (iter_o == NULL) { -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - if (Py_TYPE(iter_o)->tp_as_async == NULL || - Py_TYPE(iter_o)->tp_as_async->am_anext == NULL) { - stack_pointer += -1; -@@ -1415,9 +1621,9 @@ - "'async for' received an object from __aiter__ " - "that does not implement __anext__: %.100s", - Py_TYPE(iter_o)->tp_name); -- stack_pointer = _PyFrame_GetStackPointer(frame); - Py_DECREF(iter_o); -- if (true) JUMP_TO_ERROR(); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ JUMP_TO_ERROR(); - } - iter = PyStackRef_FromPyObjectSteal(iter_o); - stack_pointer[-1] = iter; -@@ -1450,7 +1656,11 @@ - PyObject *iter_o = _PyEval_GetAwaitable(PyStackRef_AsPyObjectBorrow(iterable), oparg); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(iterable); -- if (iter_o == NULL) JUMP_TO_ERROR(); -+ if (iter_o == NULL) { -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - iter = PyStackRef_FromPyObjectSteal(iter_o); - stack_pointer[-1] = iter; - break; -@@ -1495,9 +1705,7 @@ - // NOTE: It's important that YIELD_VALUE never raises an exception! - // The compiler treats any exception raised here as a failed close() - // or throw() call. -- #if TIER_ONE -- assert(frame != &entry_frame); -- #endif -+ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); - frame->instr_ptr++; - PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); - assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); -@@ -1573,13 +1781,15 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = PyMapping_GetOptionalItem(BUILTINS(), &_Py_ID(__build_class__), &bc_o); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err < 0) JUMP_TO_ERROR(); -+ if (err < 0) { -+ JUMP_TO_ERROR(); -+ } - if (bc_o == NULL) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyErr_SetString(tstate, PyExc_NameError, - "__build_class__ not found"); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (true) JUMP_TO_ERROR(); -+ JUMP_TO_ERROR(); - } - bc = PyStackRef_FromPyObjectSteal(bc_o); - stack_pointer[0] = bc; -@@ -1601,7 +1811,9 @@ - "no locals found when storing %R", name); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(v); -- if (true) JUMP_TO_ERROR(); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); - } - if (PyDict_CheckExact(ns)) { - _PyFrame_SetStackPointer(frame, stack_pointer); -@@ -1614,7 +1826,11 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - } - PyStackRef_CLOSE(v); -- if (err) JUMP_TO_ERROR(); -+ if (err) { -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - break; -@@ -1658,10 +1874,14 @@ - int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg, -1, top); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(seq); -- if (res == 0) JUMP_TO_ERROR(); -- stack_pointer += -1 + oparg; -- assert(WITHIN_STACK_BOUNDS()); -- break; -+ if (res == 0) { -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } -+ stack_pointer += -1 + oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ break; - } - - case _UNPACK_SEQUENCE_TWO_TUPLE: { -@@ -1762,7 +1982,11 @@ - int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg & 0xFF, oparg >> 8, top); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(seq); -- if (res == 0) JUMP_TO_ERROR(); -+ if (res == 0) { -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - stack_pointer += (oparg & 0xFF) + (oparg >> 8); - assert(WITHIN_STACK_BOUNDS()); - break; -@@ -1781,7 +2005,11 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(v); - PyStackRef_CLOSE(owner); -- if (err) JUMP_TO_ERROR(); -+ if (err) { -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); - break; -@@ -1796,7 +2024,11 @@ - int err = PyObject_DelAttr(PyStackRef_AsPyObjectBorrow(owner), name); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(owner); -- if (err) JUMP_TO_ERROR(); -+ if (err) { -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - break; -@@ -1811,7 +2043,11 @@ - int err = PyDict_SetItem(GLOBALS(), name, PyStackRef_AsPyObjectBorrow(v)); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(v); -- if (err) JUMP_TO_ERROR(); -+ if (err) { -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - break; -@@ -1845,7 +2081,7 @@ - _PyErr_SetString(tstate, PyExc_SystemError, - "no locals found"); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (true) JUMP_TO_ERROR(); -+ JUMP_TO_ERROR(); - } - locals = PyStackRef_FromPyObjectNew(l); - stack_pointer[0] = locals; -@@ -1863,7 +2099,9 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *v_o = _PyEval_LoadName(tstate, frame, name); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (v_o == NULL) JUMP_TO_ERROR(); -+ if (v_o == NULL) { -+ JUMP_TO_ERROR(); -+ } - v = PyStackRef_FromPyObjectSteal(v_o); - stack_pointer[0] = v; - stack_pointer += 1; -@@ -1873,17 +2111,26 @@ - - case _LOAD_GLOBAL: { - _PyStackRef *res; -- _PyStackRef null = PyStackRef_NULL; - oparg = CURRENT_OPARG(); - res = &stack_pointer[0]; - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyEval_LoadGlobalStackRef(GLOBALS(), BUILTINS(), name, res); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (PyStackRef_IsNull(*res)) JUMP_TO_ERROR(); -+ if (PyStackRef_IsNull(*res)) { -+ JUMP_TO_ERROR(); -+ } -+ stack_pointer += 1; -+ assert(WITHIN_STACK_BOUNDS()); -+ break; -+ } -+ -+ case _PUSH_NULL_CONDITIONAL: { -+ _PyStackRef null = PyStackRef_NULL; -+ oparg = CURRENT_OPARG(); - null = PyStackRef_NULL; -- if (oparg & 1) stack_pointer[1] = null; -- stack_pointer += 1 + (oparg & 1); -+ if (oparg & 1) stack_pointer[0] = null; -+ stack_pointer += (oparg & 1); - assert(WITHIN_STACK_BOUNDS()); - break; - } -@@ -1949,8 +2196,6 @@ - case _LOAD_GLOBAL_MODULE_FROM_KEYS: { - PyDictKeysObject *globals_keys; - _PyStackRef res; -- _PyStackRef null = PyStackRef_NULL; -- oparg = CURRENT_OPARG(); - globals_keys = (PyDictKeysObject *)stack_pointer[-1].bits; - uint16_t index = (uint16_t)CURRENT_OPERAND0(); - PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(globals_keys); -@@ -1972,10 +2217,8 @@ - res = PyStackRef_FromPyObjectSteal(res_o); - #endif - STAT_INC(LOAD_GLOBAL, hit); -- null = PyStackRef_NULL; - stack_pointer[0] = res; -- if (oparg & 1) stack_pointer[1] = null; -- stack_pointer += 1 + (oparg & 1); -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } -@@ -1983,8 +2226,6 @@ - case _LOAD_GLOBAL_BUILTINS_FROM_KEYS: { - PyDictKeysObject *builtins_keys; - _PyStackRef res; -- _PyStackRef null = PyStackRef_NULL; -- oparg = CURRENT_OPARG(); - builtins_keys = (PyDictKeysObject *)stack_pointer[-1].bits; - uint16_t index = (uint16_t)CURRENT_OPERAND0(); - PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(builtins_keys); -@@ -2006,10 +2247,8 @@ - res = PyStackRef_FromPyObjectSteal(res_o); - #endif - STAT_INC(LOAD_GLOBAL, hit); -- null = PyStackRef_NULL; - stack_pointer[0] = res; -- if (oparg & 1) stack_pointer[1] = null; -- stack_pointer += 1 + (oparg & 1); -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } -@@ -2024,9 +2263,13 @@ - PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames, oparg) - ); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (1) JUMP_TO_ERROR(); -+ JUMP_TO_ERROR(); - } -- SETLOCAL(oparg, PyStackRef_NULL); -+ _PyStackRef tmp = GETLOCAL(oparg); -+ GETLOCAL(oparg) = PyStackRef_NULL; -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_XCLOSE(tmp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - break; - } - -@@ -2039,7 +2282,11 @@ - if (cell == NULL) { - JUMP_TO_ERROR(); - } -- SETLOCAL(oparg, PyStackRef_FromPyObjectSteal(cell)); -+ _PyStackRef tmp = GETLOCAL(oparg); -+ GETLOCAL(oparg) = PyStackRef_FromPyObjectSteal(cell); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_XCLOSE(tmp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - break; - } - -@@ -2055,7 +2302,9 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - JUMP_TO_ERROR(); - } -+ _PyFrame_SetStackPointer(frame, stack_pointer); - Py_DECREF(oldobj); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - break; - } - -@@ -2086,9 +2335,15 @@ - JUMP_TO_ERROR(); - } - } -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(class_dict_st); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - value = PyStackRef_FromPyObjectSteal(value_o); -- stack_pointer[-1] = value; -+ stack_pointer[0] = value; -+ stack_pointer += 1; -+ assert(WITHIN_STACK_BOUNDS()); - break; - } - -@@ -2101,7 +2356,7 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (true) JUMP_TO_ERROR(); -+ JUMP_TO_ERROR(); - } - value = PyStackRef_FromPyObjectSteal(value_o); - stack_pointer[0] = value; -@@ -2149,14 +2404,20 @@ - for (int _i = oparg; --_i >= 0;) { - PyStackRef_CLOSE(pieces[_i]); - } -- if (true) JUMP_TO_ERROR(); -+ stack_pointer += -oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); - } - PyObject *str_o = _PyUnicode_JoinArray(&_Py_STR(empty), pieces_o, oparg); - STACKREFS_TO_PYOBJECTS_CLEANUP(pieces_o); - for (int _i = oparg; --_i >= 0;) { - PyStackRef_CLOSE(pieces[_i]); - } -- if (str_o == NULL) JUMP_TO_ERROR(); -+ if (str_o == NULL) { -+ stack_pointer += -oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - str = PyStackRef_FromPyObjectSteal(str_o); - stack_pointer[-oparg] = str; - stack_pointer += 1 - oparg; -@@ -2169,8 +2430,10 @@ - _PyStackRef tup; - oparg = CURRENT_OPARG(); - values = &stack_pointer[-oparg]; -- PyObject *tup_o = _PyTuple_FromStackRefSteal(values, oparg); -- if (tup_o == NULL) JUMP_TO_ERROR(); -+ PyObject *tup_o = _PyTuple_FromStackRefStealOnSuccess(values, oparg); -+ if (tup_o == NULL) { -+ JUMP_TO_ERROR(); -+ } - tup = PyStackRef_FromPyObjectSteal(tup_o); - stack_pointer[-oparg] = tup; - stack_pointer += 1 - oparg; -@@ -2183,8 +2446,10 @@ - _PyStackRef list; - oparg = CURRENT_OPARG(); - values = &stack_pointer[-oparg]; -- PyObject *list_o = _PyList_FromStackRefSteal(values, oparg); -- if (list_o == NULL) JUMP_TO_ERROR(); -+ PyObject *list_o = _PyList_FromStackRefStealOnSuccess(values, oparg); -+ if (list_o == NULL) { -+ JUMP_TO_ERROR(); -+ } - list = PyStackRef_FromPyObjectSteal(list_o); - stack_pointer[-oparg] = list; - stack_pointer += 1 - oparg; -@@ -2218,7 +2483,9 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - } - PyStackRef_CLOSE(iterable_st); -- if (true) JUMP_TO_ERROR(); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); - } - assert(Py_IsNone(none_val)); - PyStackRef_CLOSE(iterable_st); -@@ -2238,7 +2505,11 @@ - PyStackRef_AsPyObjectBorrow(iterable)); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(iterable); -- if (err < 0) JUMP_TO_ERROR(); -+ if (err < 0) { -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - break; -@@ -2256,7 +2527,9 @@ - for (int _i = oparg; --_i >= 0;) { - PyStackRef_CLOSE(values[_i]); - } -- if (true) JUMP_TO_ERROR(); -+ stack_pointer += -oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); - } - int err = 0; - for (int i = 0; i < oparg; i++) { -@@ -2265,11 +2538,17 @@ - err = PySet_Add(set_o, PyStackRef_AsPyObjectBorrow(values[i])); - stack_pointer = _PyFrame_GetStackPointer(frame); - } -- PyStackRef_CLOSE(values[i]); -+ } -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(values[_i]); - } - if (err != 0) { -+ stack_pointer += -oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - Py_DECREF(set_o); -- if (true) JUMP_TO_ERROR(); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ JUMP_TO_ERROR(); - } - set = PyStackRef_FromPyObjectSteal(set_o); - stack_pointer[-oparg] = set; -@@ -2288,7 +2567,9 @@ - for (int _i = oparg*2; --_i >= 0;) { - PyStackRef_CLOSE(values[_i]); - } -- if (true) JUMP_TO_ERROR(); -+ stack_pointer += -oparg*2; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *map_o = _PyDict_FromItems( -@@ -2300,7 +2581,11 @@ - for (int _i = oparg*2; --_i >= 0;) { - PyStackRef_CLOSE(values[_i]); - } -- if (map_o == NULL) JUMP_TO_ERROR(); -+ if (map_o == NULL) { -+ stack_pointer += -oparg*2; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - map = PyStackRef_FromPyObjectSteal(map_o); - stack_pointer[-oparg*2] = map; - stack_pointer += 1 - oparg*2; -@@ -2315,27 +2600,35 @@ - _PyErr_Format(tstate, PyExc_SystemError, - "no locals found when setting up annotations"); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (true) JUMP_TO_ERROR(); -+ JUMP_TO_ERROR(); - } - /* check if __annotations__ in locals()... */ - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = PyMapping_GetOptionalItem(LOCALS(), &_Py_ID(__annotations__), &ann_dict); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err < 0) JUMP_TO_ERROR(); -+ if (err < 0) { -+ JUMP_TO_ERROR(); -+ } - if (ann_dict == NULL) { - _PyFrame_SetStackPointer(frame, stack_pointer); - ann_dict = PyDict_New(); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (ann_dict == NULL) JUMP_TO_ERROR(); -+ if (ann_dict == NULL) { -+ JUMP_TO_ERROR(); -+ } - _PyFrame_SetStackPointer(frame, stack_pointer); - err = PyObject_SetItem(LOCALS(), &_Py_ID(__annotations__), - ann_dict); -- stack_pointer = _PyFrame_GetStackPointer(frame); - Py_DECREF(ann_dict); -- if (err) JUMP_TO_ERROR(); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (err) { -+ JUMP_TO_ERROR(); -+ } - } - else { -+ _PyFrame_SetStackPointer(frame, stack_pointer); - Py_DECREF(ann_dict); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - } - break; - } -@@ -2363,7 +2656,9 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - } - PyStackRef_CLOSE(update); -- if (true) JUMP_TO_ERROR(); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); - } - PyStackRef_CLOSE(update); - stack_pointer += -1; -@@ -2390,7 +2685,9 @@ - _PyEval_FormatKwargsError(tstate, callable_o, update_o); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(update); -- if (true) JUMP_TO_ERROR(); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); - } - PyStackRef_CLOSE(update); - stack_pointer += -1; -@@ -2417,14 +2714,16 @@ - PyStackRef_AsPyObjectSteal(value) - ); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err != 0) JUMP_TO_ERROR(); -+ if (err != 0) { -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); - break; - } - -- /* _INSTRUMENTED_LOAD_SUPER_ATTR is not a viable micro-op for tier 2 because it is instrumented */ -- - case _LOAD_SUPER_ATTR_ATTR: { - _PyStackRef self_st; - _PyStackRef class_st; -@@ -2454,7 +2753,11 @@ - PyStackRef_CLOSE(global_super_st); - PyStackRef_CLOSE(class_st); - PyStackRef_CLOSE(self_st); -- if (attr == NULL) JUMP_TO_ERROR(); -+ if (attr == NULL) { -+ stack_pointer += -3; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - attr_st = PyStackRef_FromPyObjectSteal(attr); - stack_pointer[-3] = attr_st; - stack_pointer += -2; -@@ -2492,18 +2795,23 @@ - PyObject *attr_o = _PySuper_Lookup(cls, self, name, - Py_TYPE(self)->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL); - stack_pointer = _PyFrame_GetStackPointer(frame); -- PyStackRef_CLOSE(global_super_st); -- PyStackRef_CLOSE(class_st); - if (attr_o == NULL) { -- PyStackRef_CLOSE(self_st); -- if (true) JUMP_TO_ERROR(); -+ JUMP_TO_ERROR(); - } - if (method_found) { - self_or_null = self_st; // transfer ownership - } else { -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(self_st); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - self_or_null = PyStackRef_NULL; -+ stack_pointer += 1; -+ assert(WITHIN_STACK_BOUNDS()); - } -+ PyStackRef_CLOSE(global_super_st); -+ PyStackRef_CLOSE(class_st); - attr = PyStackRef_FromPyObjectSteal(attr_o); - stack_pointer[-3] = attr; - stack_pointer[-2] = self_or_null; -@@ -2515,9 +2823,10 @@ - case _LOAD_ATTR: { - _PyStackRef owner; - _PyStackRef attr; -- _PyStackRef self_or_null = PyStackRef_NULL; -+ _PyStackRef *self_or_null; - oparg = CURRENT_OPARG(); - owner = stack_pointer[-1]; -+ self_or_null = &stack_pointer[0]; - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); - PyObject *attr_o; - if (oparg & 1) { -@@ -2532,7 +2841,7 @@ - meth | self | arg1 | ... | argN - */ - assert(attr_o != NULL); // No errors on this branch -- self_or_null = owner; // Transfer ownership -+ self_or_null[0] = owner; // Transfer ownership - } - else { - /* meth is not an unbound method (but a regular attr, or -@@ -2542,8 +2851,12 @@ - meth | NULL | arg1 | ... | argN - */ - PyStackRef_CLOSE(owner); -- if (attr_o == NULL) JUMP_TO_ERROR(); -- self_or_null = PyStackRef_NULL; -+ if (attr_o == NULL) { -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } -+ self_or_null[0] = PyStackRef_NULL; - } - } - else { -@@ -2552,14 +2865,15 @@ - attr_o = PyObject_GetAttr(PyStackRef_AsPyObjectBorrow(owner), name); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(owner); -- if (attr_o == NULL) JUMP_TO_ERROR(); -- /* We need to define self_or_null on all paths */ -- self_or_null = PyStackRef_NULL; -+ if (attr_o == NULL) { -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - } - attr = PyStackRef_FromPyObjectSteal(attr_o); - stack_pointer[-1] = attr; -- if (oparg & 1) stack_pointer[0] = self_or_null; -- stack_pointer += (oparg & 1); -+ stack_pointer += (oparg&1); - assert(WITHIN_STACK_BOUNDS()); - break; - } -@@ -2570,77 +2884,77 @@ - uint32_t type_version = (uint32_t)CURRENT_OPERAND0(); - PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - assert(type_version != 0); -- if (tp->tp_version_tag != type_version) { -+ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } - break; - } - -- case _CHECK_MANAGED_OBJECT_HAS_VALUES: { -+ case _GUARD_TYPE_VERSION_AND_LOCK: { - _PyStackRef owner; - owner = stack_pointer[-1]; -+ uint32_t type_version = (uint32_t)CURRENT_OPERAND0(); - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); -- assert(Py_TYPE(owner_o)->tp_dictoffset < 0); -- assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); -- if (!_PyObject_InlineValues(owner_o)->valid) { -+ assert(type_version != 0); -+ if (!LOCK_OBJECT(owner_o)) { - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } -+ PyTypeObject *tp = Py_TYPE(owner_o); -+ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { -+ UNLOCK_OBJECT(owner_o); -+ if (true) { -+ UOP_STAT_INC(uopcode, miss); -+ JUMP_TO_JUMP_TARGET(); -+ } -+ } - break; - } - -- case _LOAD_ATTR_INSTANCE_VALUE_0: { -+ case _CHECK_MANAGED_OBJECT_HAS_VALUES: { - _PyStackRef owner; -- _PyStackRef attr; -- _PyStackRef null = PyStackRef_NULL; -- (void)null; - owner = stack_pointer[-1]; -- uint16_t offset = (uint16_t)CURRENT_OPERAND0(); - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); -- PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); -- PyObject *attr_o = *value_ptr; -- if (attr_o == NULL) { -+ assert(Py_TYPE(owner_o)->tp_dictoffset < 0); -+ assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); -+ if (!FT_ATOMIC_LOAD_UINT8(_PyObject_InlineValues(owner_o)->valid)) { - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } -- STAT_INC(LOAD_ATTR, hit); -- Py_INCREF(attr_o); -- null = PyStackRef_NULL; -- attr = PyStackRef_FromPyObjectSteal(attr_o); -- PyStackRef_CLOSE(owner); -- stack_pointer[-1] = attr; - break; - } - -- case _LOAD_ATTR_INSTANCE_VALUE_1: { -+ case _LOAD_ATTR_INSTANCE_VALUE: { - _PyStackRef owner; - _PyStackRef attr; -- _PyStackRef null = PyStackRef_NULL; -- (void)null; - owner = stack_pointer[-1]; - uint16_t offset = (uint16_t)CURRENT_OPERAND0(); - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); -- PyObject *attr_o = *value_ptr; -+ PyObject *attr_o = FT_ATOMIC_LOAD_PTR_ACQUIRE(*value_ptr); - if (attr_o == NULL) { - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } -+ #ifdef Py_GIL_DISABLED -+ if (!_Py_TryIncrefCompareStackRef(value_ptr, attr_o, &attr)) { -+ if (true) { -+ UOP_STAT_INC(uopcode, miss); -+ JUMP_TO_JUMP_TARGET(); -+ } -+ } -+ #else -+ attr = PyStackRef_FromPyObjectNew(attr_o); -+ #endif - STAT_INC(LOAD_ATTR, hit); -- Py_INCREF(attr_o); -- null = PyStackRef_NULL; -- attr = PyStackRef_FromPyObjectSteal(attr_o); -- PyStackRef_CLOSE(owner); - stack_pointer[-1] = attr; -- stack_pointer[0] = null; -- stack_pointer += 1; -- assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(owner); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - break; - } - -- /* _LOAD_ATTR_INSTANCE_VALUE is split on (oparg & 1) */ -- - case _CHECK_ATTR_MODULE_PUSH_KEYS: { - _PyStackRef owner; - PyDictKeysObject *mod_keys; -@@ -2669,8 +2983,6 @@ - PyDictKeysObject *mod_keys; - _PyStackRef owner; - _PyStackRef attr; -- _PyStackRef null = PyStackRef_NULL; -- oparg = CURRENT_OPARG(); - mod_keys = (PyDictKeysObject *)stack_pointer[-1].bits; - owner = stack_pointer[-2]; - uint16_t index = (uint16_t)CURRENT_OPERAND0(); -@@ -2698,119 +3010,125 @@ - attr = PyStackRef_FromPyObjectSteal(attr_o); - #endif - STAT_INC(LOAD_ATTR, hit); -- null = PyStackRef_NULL; -- PyStackRef_CLOSE(owner); - stack_pointer[-1] = attr; -- if (oparg & 1) stack_pointer[0] = null; -- stack_pointer += (oparg & 1); -- assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(owner); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - break; - } - - case _CHECK_ATTR_WITH_HINT: { - _PyStackRef owner; -+ PyDictObject *dict; - owner = stack_pointer[-1]; - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_MANAGED_DICT); -- PyDictObject *dict = _PyObject_GetManagedDict(owner_o); -- if (dict == NULL) { -+ PyDictObject *dict_o = _PyObject_GetManagedDict(owner_o); -+ if (dict_o == NULL) { - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } -- assert(PyDict_CheckExact((PyObject *)dict)); -+ assert(PyDict_CheckExact((PyObject *)dict_o)); -+ dict = dict_o; -+ stack_pointer[0].bits = (uintptr_t)dict; -+ stack_pointer += 1; -+ assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _LOAD_ATTR_WITH_HINT: { -+ PyDictObject *dict; - _PyStackRef owner; - _PyStackRef attr; -- _PyStackRef null = PyStackRef_NULL; - oparg = CURRENT_OPARG(); -- owner = stack_pointer[-1]; -+ dict = (PyDictObject *)stack_pointer[-1].bits; -+ owner = stack_pointer[-2]; - uint16_t hint = (uint16_t)CURRENT_OPERAND0(); -- PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - PyObject *attr_o; -- PyDictObject *dict = _PyObject_GetManagedDict(owner_o); -+ if (!LOCK_OBJECT(dict)) { -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ if (true) { -+ UOP_STAT_INC(uopcode, miss); -+ JUMP_TO_JUMP_TARGET(); -+ } -+ } - if (hint >= (size_t)dict->ma_keys->dk_nentries) { -- UOP_STAT_INC(uopcode, miss); -- JUMP_TO_JUMP_TARGET(); -+ UNLOCK_OBJECT(dict); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ if (true) { -+ UOP_STAT_INC(uopcode, miss); -+ JUMP_TO_JUMP_TARGET(); -+ } - } - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); -- if (!DK_IS_UNICODE(dict->ma_keys)) { -- UOP_STAT_INC(uopcode, miss); -- JUMP_TO_JUMP_TARGET(); -+ if (dict->ma_keys->dk_kind != DICT_KEYS_UNICODE) { -+ UNLOCK_OBJECT(dict); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ if (true) { -+ UOP_STAT_INC(uopcode, miss); -+ JUMP_TO_JUMP_TARGET(); -+ } - } - PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; - if (ep->me_key != name) { -- UOP_STAT_INC(uopcode, miss); -- JUMP_TO_JUMP_TARGET(); -+ UNLOCK_OBJECT(dict); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ if (true) { -+ UOP_STAT_INC(uopcode, miss); -+ JUMP_TO_JUMP_TARGET(); -+ } - } - attr_o = ep->me_value; - if (attr_o == NULL) { -- UOP_STAT_INC(uopcode, miss); -- JUMP_TO_JUMP_TARGET(); -+ UNLOCK_OBJECT(dict); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ if (true) { -+ UOP_STAT_INC(uopcode, miss); -+ JUMP_TO_JUMP_TARGET(); -+ } - } - STAT_INC(LOAD_ATTR, hit); -- Py_INCREF(attr_o); -- attr = PyStackRef_FromPyObjectSteal(attr_o); -- null = PyStackRef_NULL; -+ attr = PyStackRef_FromPyObjectNew(attr_o); -+ UNLOCK_OBJECT(dict); - PyStackRef_CLOSE(owner); -- stack_pointer[-1] = attr; -- if (oparg & 1) stack_pointer[0] = null; -- stack_pointer += (oparg & 1); -+ stack_pointer[-2] = attr; -+ stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - break; - } - -- case _LOAD_ATTR_SLOT_0: { -+ case _LOAD_ATTR_SLOT: { - _PyStackRef owner; - _PyStackRef attr; -- _PyStackRef null = PyStackRef_NULL; -- (void)null; - owner = stack_pointer[-1]; - uint16_t index = (uint16_t)CURRENT_OPERAND0(); - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); -- char *addr = (char *)owner_o + index; -- PyObject *attr_o = *(PyObject **)addr; -+ PyObject **addr = (PyObject **)((char *)owner_o + index); -+ PyObject *attr_o = FT_ATOMIC_LOAD_PTR(*addr); - if (attr_o == NULL) { - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } -- STAT_INC(LOAD_ATTR, hit); -- null = PyStackRef_NULL; -- attr = PyStackRef_FromPyObjectNew(attr_o); -- PyStackRef_CLOSE(owner); -- stack_pointer[-1] = attr; -- break; -- } -- -- case _LOAD_ATTR_SLOT_1: { -- _PyStackRef owner; -- _PyStackRef attr; -- _PyStackRef null = PyStackRef_NULL; -- (void)null; -- owner = stack_pointer[-1]; -- uint16_t index = (uint16_t)CURRENT_OPERAND0(); -- PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); -- char *addr = (char *)owner_o + index; -- PyObject *attr_o = *(PyObject **)addr; -- if (attr_o == NULL) { -+ #ifdef Py_GIL_DISABLED -+ int increfed = _Py_TryIncrefCompareStackRef(addr, attr_o, &attr); -+ if (!increfed) { - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } -- STAT_INC(LOAD_ATTR, hit); -- null = PyStackRef_NULL; -+ #else - attr = PyStackRef_FromPyObjectNew(attr_o); -+ #endif -+ STAT_INC(LOAD_ATTR, hit); - PyStackRef_CLOSE(owner); - stack_pointer[-1] = attr; -- stack_pointer[0] = null; -- stack_pointer += 1; -- assert(WITHIN_STACK_BOUNDS()); - break; - } - -- /* _LOAD_ATTR_SLOT is split on (oparg & 1) */ -- - case _CHECK_ATTR_CLASS: { - _PyStackRef owner; - owner = stack_pointer[-1]; -@@ -2818,53 +3136,29 @@ - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - if (!PyType_Check(owner_o)) { - UOP_STAT_INC(uopcode, miss); -- JUMP_TO_JUMP_TARGET(); -- } -- assert(type_version != 0); -- if (((PyTypeObject *)owner_o)->tp_version_tag != type_version) { -- UOP_STAT_INC(uopcode, miss); -- JUMP_TO_JUMP_TARGET(); -- } -- break; -- } -- -- case _LOAD_ATTR_CLASS_0: { -- _PyStackRef owner; -- _PyStackRef attr; -- _PyStackRef null = PyStackRef_NULL; -- (void)null; -- owner = stack_pointer[-1]; -- PyObject *descr = (PyObject *)CURRENT_OPERAND0(); -- STAT_INC(LOAD_ATTR, hit); -- assert(descr != NULL); -- attr = PyStackRef_FromPyObjectNew(descr); -- null = PyStackRef_NULL; -- PyStackRef_CLOSE(owner); -- stack_pointer[-1] = attr; -+ JUMP_TO_JUMP_TARGET(); -+ } -+ assert(type_version != 0); -+ if (FT_ATOMIC_LOAD_UINT_RELAXED(((PyTypeObject *)owner_o)->tp_version_tag) != type_version) { -+ UOP_STAT_INC(uopcode, miss); -+ JUMP_TO_JUMP_TARGET(); -+ } - break; - } - -- case _LOAD_ATTR_CLASS_1: { -+ case _LOAD_ATTR_CLASS: { - _PyStackRef owner; - _PyStackRef attr; -- _PyStackRef null = PyStackRef_NULL; -- (void)null; - owner = stack_pointer[-1]; - PyObject *descr = (PyObject *)CURRENT_OPERAND0(); - STAT_INC(LOAD_ATTR, hit); - assert(descr != NULL); - attr = PyStackRef_FromPyObjectNew(descr); -- null = PyStackRef_NULL; - PyStackRef_CLOSE(owner); - stack_pointer[-1] = attr; -- stack_pointer[0] = null; -- stack_pointer += 1; -- assert(WITHIN_STACK_BOUNDS()); - break; - } - -- /* _LOAD_ATTR_CLASS is split on (oparg & 1) */ -- - case _LOAD_ATTR_PROPERTY_FRAME: { - _PyStackRef owner; - _PyInterpreterFrame *new_frame; -@@ -2906,13 +3200,13 @@ - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - assert(Py_TYPE(owner_o)->tp_dictoffset < 0); - assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); -- if (_PyObject_GetManagedDict(owner_o)) { -- UOP_STAT_INC(uopcode, miss); -- JUMP_TO_JUMP_TARGET(); -- } -- if (_PyObject_InlineValues(owner_o)->valid == 0) { -- UOP_STAT_INC(uopcode, miss); -- JUMP_TO_JUMP_TARGET(); -+ if (_PyObject_GetManagedDict(owner_o) || -+ !FT_ATOMIC_LOAD_UINT8(_PyObject_InlineValues(owner_o)->valid)) { -+ UNLOCK_OBJECT(owner_o); -+ if (true) { -+ UOP_STAT_INC(uopcode, miss); -+ JUMP_TO_JUMP_TARGET(); -+ } - } - break; - } -@@ -2928,18 +3222,19 @@ - assert(_PyObject_GetManagedDict(owner_o) == NULL); - PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); - PyObject *old_value = *value_ptr; -- *value_ptr = PyStackRef_AsPyObjectSteal(value); -+ FT_ATOMIC_STORE_PTR_RELEASE(*value_ptr, PyStackRef_AsPyObjectSteal(value)); - if (old_value == NULL) { - PyDictValues *values = _PyObject_InlineValues(owner_o); - Py_ssize_t index = value_ptr - values->values; - _PyDictValues_AddToInsertionOrder(values, index); - } -- else { -- Py_DECREF(old_value); -- } -- PyStackRef_CLOSE(owner); -+ UNLOCK_OBJECT(owner_o); - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(owner); -+ Py_XDECREF(old_value); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - break; - } - -@@ -2957,37 +3252,59 @@ - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } -- assert(PyDict_CheckExact((PyObject *)dict)); -- PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); -- if (hint >= (size_t)dict->ma_keys->dk_nentries) { -+ if (!LOCK_OBJECT(dict)) { - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } -- if (!DK_IS_UNICODE(dict->ma_keys)) { -- UOP_STAT_INC(uopcode, miss); -- JUMP_TO_JUMP_TARGET(); -+ #ifdef Py_GIL_DISABLED -+ if (dict != _PyObject_GetManagedDict(owner_o)) { -+ UNLOCK_OBJECT(dict); -+ if (true) { -+ UOP_STAT_INC(uopcode, miss); -+ JUMP_TO_JUMP_TARGET(); -+ } -+ } -+ #endif -+ assert(PyDict_CheckExact((PyObject *)dict)); -+ PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); -+ if (hint >= (size_t)dict->ma_keys->dk_nentries || -+ !DK_IS_UNICODE(dict->ma_keys)) { -+ UNLOCK_OBJECT(dict); -+ if (true) { -+ UOP_STAT_INC(uopcode, miss); -+ JUMP_TO_JUMP_TARGET(); -+ } - } - PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; - if (ep->me_key != name) { -- UOP_STAT_INC(uopcode, miss); -- JUMP_TO_JUMP_TARGET(); -+ UNLOCK_OBJECT(dict); -+ if (true) { -+ UOP_STAT_INC(uopcode, miss); -+ JUMP_TO_JUMP_TARGET(); -+ } - } - PyObject *old_value = ep->me_value; - if (old_value == NULL) { -- UOP_STAT_INC(uopcode, miss); -- JUMP_TO_JUMP_TARGET(); -+ UNLOCK_OBJECT(dict); -+ if (true) { -+ UOP_STAT_INC(uopcode, miss); -+ JUMP_TO_JUMP_TARGET(); -+ } - } - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyDict_NotifyEvent(tstate->interp, PyDict_EVENT_MODIFIED, dict, name, PyStackRef_AsPyObjectBorrow(value)); - stack_pointer = _PyFrame_GetStackPointer(frame); -- ep->me_value = PyStackRef_AsPyObjectSteal(value); -+ FT_ATOMIC_STORE_PTR_RELEASE(ep->me_value, PyStackRef_AsPyObjectSteal(value)); -+ UNLOCK_OBJECT(dict); - // old_value should be DECREFed after GC track checking is done, if not, it could raise a segmentation fault, - // when dict only holds the strong reference to value in ep->me_value. -- Py_XDECREF(old_value); - STAT_INC(STORE_ATTR, hit); -- PyStackRef_CLOSE(owner); - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(owner); -+ Py_XDECREF(old_value); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - break; - } - -@@ -2998,14 +3315,21 @@ - value = stack_pointer[-2]; - uint16_t index = (uint16_t)CURRENT_OPERAND0(); - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); -+ if (!LOCK_OBJECT(owner_o)) { -+ UOP_STAT_INC(uopcode, miss); -+ JUMP_TO_JUMP_TARGET(); -+ } - char *addr = (char *)owner_o + index; - STAT_INC(STORE_ATTR, hit); - PyObject *old_value = *(PyObject **)addr; -- *(PyObject **)addr = PyStackRef_AsPyObjectSteal(value); -- Py_XDECREF(old_value); -- PyStackRef_CLOSE(owner); -+ FT_ATOMIC_STORE_PTR_RELEASE(*(PyObject **)addr, PyStackRef_AsPyObjectSteal(value)); -+ UNLOCK_OBJECT(owner_o); - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(owner); -+ Py_XDECREF(old_value); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - break; - } - -@@ -3024,15 +3348,21 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(left); - PyStackRef_CLOSE(right); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ if (res_o == NULL) { -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - if (oparg & 16) { - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - int res_bool = PyObject_IsTrue(res_o); -- stack_pointer = _PyFrame_GetStackPointer(frame); - Py_DECREF(res_o); -- if (res_bool < 0) JUMP_TO_ERROR(); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (res_bool < 0) { -+ JUMP_TO_ERROR(); -+ } - res = res_bool ? PyStackRef_True : PyStackRef_False; - } - else { -@@ -3160,7 +3490,11 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(left); - PyStackRef_CLOSE(right); -- if (res < 0) JUMP_TO_ERROR(); -+ if (res < 0) { -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - b = (res ^ oparg) ? PyStackRef_True : PyStackRef_False; - stack_pointer[-2] = b; - stack_pointer += -1; -@@ -3188,7 +3522,11 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(left); - PyStackRef_CLOSE(right); -- if (res < 0) JUMP_TO_ERROR(); -+ if (res < 0) { -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - b = (res ^ oparg) ? PyStackRef_True : PyStackRef_False; - stack_pointer[-2] = b; - stack_pointer += -1; -@@ -3215,7 +3553,11 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(left); - PyStackRef_CLOSE(right); -- if (res < 0) JUMP_TO_ERROR(); -+ if (res < 0) { -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - b = (res ^ oparg) ? PyStackRef_True : PyStackRef_False; - stack_pointer[-2] = b; - stack_pointer += -1; -@@ -3238,19 +3580,29 @@ - if (err < 0) { - PyStackRef_CLOSE(exc_value_st); - PyStackRef_CLOSE(match_type_st); -- if (true) JUMP_TO_ERROR(); -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); - } - PyObject *match_o = NULL; - PyObject *rest_o = NULL; - _PyFrame_SetStackPointer(frame, stack_pointer); -- int res = _PyEval_ExceptionGroupMatch(exc_value, match_type, -+ int res = _PyEval_ExceptionGroupMatch(frame, exc_value, match_type, - &match_o, &rest_o); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(exc_value_st); - PyStackRef_CLOSE(match_type_st); -- if (res < 0) JUMP_TO_ERROR(); -+ if (res < 0) { -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - assert((match_o == NULL) == (rest_o == NULL)); -- if (match_o == NULL) JUMP_TO_ERROR(); -+ if (match_o == NULL) { -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - if (!Py_IsNone(match_o)) { - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); -@@ -3281,7 +3633,9 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - if (err < 0) { - PyStackRef_CLOSE(right); -- if (true) JUMP_TO_ERROR(); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - int res = PyErr_GivenExceptionMatches(left_o, right_o); -@@ -3307,7 +3661,11 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(level); - PyStackRef_CLOSE(fromlist); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ if (res_o == NULL) { -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -3324,7 +3682,9 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = _PyEval_ImportFrom(tstate, PyStackRef_AsPyObjectBorrow(from), name); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ if (res_o == NULL) { -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; -@@ -3359,9 +3719,13 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - Py_ssize_t len_i = PyObject_Length(PyStackRef_AsPyObjectBorrow(obj)); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (len_i < 0) JUMP_TO_ERROR(); -+ if (len_i < 0) { -+ JUMP_TO_ERROR(); -+ } - PyObject *len_o = PyLong_FromSsize_t(len_i); -- if (len_o == NULL) JUMP_TO_ERROR(); -+ if (len_o == NULL) { -+ JUMP_TO_ERROR(); -+ } - len = PyStackRef_FromPyObjectSteal(len_o); - stack_pointer[0] = len; - stack_pointer += 1; -@@ -3395,7 +3759,11 @@ - attrs = PyStackRef_FromPyObjectSteal(attrs_o); - } - else { -- if (_PyErr_Occurred(tstate)) JUMP_TO_ERROR(); -+ if (_PyErr_Occurred(tstate)) { -+ stack_pointer += -3; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - // Error! - attrs = PyStackRef_None; // Failure! - } -@@ -3440,7 +3808,9 @@ - PyObject *values_or_none_o = _PyEval_MatchKeys(tstate, - PyStackRef_AsPyObjectBorrow(subject), PyStackRef_AsPyObjectBorrow(keys)); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (values_or_none_o == NULL) JUMP_TO_ERROR(); -+ if (values_or_none_o == NULL) { -+ JUMP_TO_ERROR(); -+ } - values_or_none = PyStackRef_FromPyObjectSteal(values_or_none_o); - stack_pointer[0] = values_or_none; - stack_pointer += 1; -@@ -3457,7 +3827,11 @@ - PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable)); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(iterable); -- if (iter_o == NULL) JUMP_TO_ERROR(); -+ if (iter_o == NULL) { -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - iter = PyStackRef_FromPyObjectSteal(iter_o); - stack_pointer[-1] = iter; - break; -@@ -3677,7 +4051,9 @@ - r->start = value + r->step; - r->len--; - PyObject *res = PyLong_FromLong(value); -- if (res == NULL) JUMP_TO_ERROR(); -+ if (res == NULL) { -+ JUMP_TO_ERROR(); -+ } - next = PyStackRef_FromPyObjectSteal(res); - stack_pointer[0] = next; - stack_pointer += 1; -@@ -3737,7 +4113,7 @@ - Py_TYPE(owner_o)->tp_name); - stack_pointer = _PyFrame_GetStackPointer(frame); - } -- if (true) JUMP_TO_ERROR(); -+ JUMP_TO_ERROR(); - } - attr = PyStackRef_FromPyObjectSteal(attr_o); - self_or_null = self_or_null_o == NULL ? -@@ -3778,7 +4154,9 @@ - tb = Py_None; - } - else { -+ _PyFrame_SetStackPointer(frame, stack_pointer); - Py_DECREF(tb); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - } - assert(PyStackRef_LongCheck(lasti)); - (void)lasti; // Shut up compiler warning if asserts are off -@@ -3788,7 +4166,9 @@ - PyObject *res_o = PyObject_Vectorcall(exit_func_o, stack + 2 - has_self, - (3 + has_self) | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ if (res_o == NULL) { -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; -@@ -3823,7 +4203,8 @@ - owner = stack_pointer[-1]; - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); -- if (!_PyObject_InlineValues(owner_o)->valid) { -+ PyDictValues *ivs = _PyObject_InlineValues(owner_o); -+ if (!FT_ATOMIC_LOAD_UINT8(ivs->valid)) { - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } -@@ -3836,7 +4217,8 @@ - uint32_t keys_version = (uint32_t)CURRENT_OPERAND0(); - PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; -- if (owner_heap_type->ht_cached_keys->dk_version != keys_version) { -+ PyDictKeysObject *keys = owner_heap_type->ht_cached_keys; -+ if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) { - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } -@@ -3846,7 +4228,7 @@ - case _LOAD_ATTR_METHOD_WITH_VALUES: { - _PyStackRef owner; - _PyStackRef attr; -- _PyStackRef self = PyStackRef_NULL; -+ _PyStackRef self; - oparg = CURRENT_OPARG(); - owner = stack_pointer[-1]; - PyObject *descr = (PyObject *)CURRENT_OPERAND0(); -@@ -3867,7 +4249,7 @@ - case _LOAD_ATTR_METHOD_NO_DICT: { - _PyStackRef owner; - _PyStackRef attr; -- _PyStackRef self = PyStackRef_NULL; -+ _PyStackRef self; - oparg = CURRENT_OPARG(); - owner = stack_pointer[-1]; - PyObject *descr = (PyObject *)CURRENT_OPERAND0(); -@@ -3921,7 +4303,7 @@ - owner = stack_pointer[-1]; - uint16_t dictoffset = (uint16_t)CURRENT_OPERAND0(); - char *ptr = ((char *)PyStackRef_AsPyObjectBorrow(owner)) + MANAGED_DICT_OFFSET + dictoffset; -- PyObject *dict = *(PyObject **)ptr; -+ PyObject *dict = FT_ATOMIC_LOAD_PTR_ACQUIRE(*(PyObject **)ptr); - /* This object has a __dict__, just not yet created */ - if (dict != NULL) { - UOP_STAT_INC(uopcode, miss); -@@ -3933,7 +4315,7 @@ - case _LOAD_ATTR_METHOD_LAZY_DICT: { - _PyStackRef owner; - _PyStackRef attr; -- _PyStackRef self = PyStackRef_NULL; -+ _PyStackRef self; - oparg = CURRENT_OPARG(); - owner = stack_pointer[-1]; - PyObject *descr = (PyObject *)CURRENT_OPERAND0(); -@@ -3962,6 +4344,8 @@ - callable = &stack_pointer[-2 - oparg]; - func = &stack_pointer[-2 - oparg]; - maybe_self = &stack_pointer[-1 - oparg]; -+ args = &stack_pointer[-oparg]; -+ (void)args; - if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - PyObject *self = ((PyMethodObject *)callable_o)->im_self; -@@ -3969,7 +4353,9 @@ - PyObject *method = ((PyMethodObject *)callable_o)->im_func; - _PyStackRef temp = callable[0]; - func[0] = PyStackRef_FromPyObjectNew(method); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(temp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - } - break; - } -@@ -4075,23 +4461,21 @@ - } - - case _EXPAND_METHOD: { -- _PyStackRef *null; -+ _PyStackRef *self_or_null; - _PyStackRef *callable; -- _PyStackRef *method; -- _PyStackRef *self; - oparg = CURRENT_OPARG(); -- null = &stack_pointer[-1 - oparg]; -+ self_or_null = &stack_pointer[-1 - oparg]; - callable = &stack_pointer[-2 - oparg]; -- method = &stack_pointer[-2 - oparg]; -- self = &stack_pointer[-1 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); -- assert(PyStackRef_IsNull(null[0])); -+ assert(PyStackRef_IsNull(self_or_null[0])); - assert(Py_TYPE(callable_o) == &PyMethod_Type); -- self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); -+ self_or_null[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); - _PyStackRef temp = callable[0]; -- method[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); -- assert(PyStackRef_FunctionCheck(method[0])); -+ callable[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); -+ assert(PyStackRef_FunctionCheck(callable[0])); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(temp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - break; - } - -@@ -4125,19 +4509,22 @@ - #endif - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - /* Callable is not a normal Python function */ -- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable[0]); -- PyStackRef_CLOSE(self_or_null[0]); -+ PyStackRef_XCLOSE(self_or_null[0]); - for (int _i = oparg; --_i >= 0;) { - PyStackRef_CLOSE(args[_i]); - } -- if (true) JUMP_TO_ERROR(); -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = PyObject_Vectorcall( -@@ -4148,10 +4535,15 @@ - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - PyStackRef_CLOSE(callable[0]); -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -+ PyStackRef_XCLOSE(self_or_null[0]); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); -+ } -+ if (res_o == NULL) { -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); - } -- if (res_o == NULL) JUMP_TO_ERROR(); - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; -@@ -4177,21 +4569,20 @@ - } - - case _INIT_CALL_BOUND_METHOD_EXACT_ARGS: { -- _PyStackRef *null; -+ _PyStackRef *self_or_null; - _PyStackRef *callable; -- _PyStackRef *func; -- _PyStackRef *self; - oparg = CURRENT_OPARG(); -- null = &stack_pointer[-1 - oparg]; -+ self_or_null = &stack_pointer[-1 - oparg]; - callable = &stack_pointer[-2 - oparg]; -- func = &stack_pointer[-2 - oparg]; -- self = &stack_pointer[-1 - oparg]; -+ assert(PyStackRef_IsNull(self_or_null[0])); - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - STAT_INC(CALL, hit); -- self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); -+ self_or_null[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); - _PyStackRef temp = callable[0]; -- func[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); -+ callable[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(temp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - break; - } - -@@ -4423,10 +4814,12 @@ - } - STAT_INC(CALL, hit); - res = PyStackRef_FromPyObjectSteal(Py_NewRef(Py_TYPE(arg_o))); -- PyStackRef_CLOSE(arg); - stack_pointer[-3] = res; - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(arg); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - break; - } - -@@ -4454,11 +4847,17 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = PyObject_Str(arg_o); - stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -3; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(arg); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (res_o == NULL) { -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); -- stack_pointer[-3] = res; -- stack_pointer += -2; -+ stack_pointer[0] = res; -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } -@@ -4487,11 +4886,17 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = PySequence_Tuple(arg_o); - stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -3; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(arg); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (res_o == NULL) { -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); -- stack_pointer[-3] = res; -- stack_pointer += -2; -+ stack_pointer[0] = res; -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } -@@ -4508,7 +4913,9 @@ - callable = &stack_pointer[-2 - oparg]; - init = &stack_pointer[-2 - oparg]; - self = &stack_pointer[-1 - oparg]; -+ args = &stack_pointer[-oparg]; - uint32_t type_version = (uint32_t)CURRENT_OPERAND0(); -+ (void)args; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - if (!PyStackRef_IsNull(null[0])) { - UOP_STAT_INC(uopcode, miss); -@@ -4523,7 +4930,9 @@ - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } -- assert(tp->tp_flags & Py_TPFLAGS_INLINE_VALUES); -+ assert(tp->tp_new == PyBaseObject_Type.tp_new); -+ assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE); -+ assert(tp->tp_alloc == PyType_GenericAlloc); - PyHeapTypeObject *cls = (PyHeapTypeObject *)callable_o; - PyFunctionObject *init_func = (PyFunctionObject *)FT_ATOMIC_LOAD_PTR_ACQUIRE(cls->_spec_cache.init); - PyCodeObject *code = (PyCodeObject *)init_func->func_code; -@@ -4532,14 +4941,18 @@ - JUMP_TO_JUMP_TARGET(); - } - STAT_INC(CALL, hit); -- PyObject *self_o = _PyType_NewManagedObject(tp); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyObject *self_o = PyType_GenericAlloc(tp, 0); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - if (self_o == NULL) { - JUMP_TO_ERROR(); - } - self[0] = PyStackRef_FromPyObjectSteal(self_o); - _PyStackRef temp = callable[0]; - init[0] = PyStackRef_FromPyObjectNew(init_func); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(temp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - break; - } - -@@ -4555,9 +4968,9 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyInterpreterFrame *shim = _PyFrame_PushTrampolineUnchecked( - tstate, (PyCodeObject *)&_Py_InitCleanup, 1, frame); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - assert(_PyFrame_GetBytecode(shim)[0].op.code == EXIT_INIT_CHECK); - assert(_PyFrame_GetBytecode(shim)[1].op.code == RETURN_VALUE); -- stack_pointer = _PyFrame_GetStackPointer(frame); - /* Push self onto stack of shim */ - shim->localsplus[0] = PyStackRef_DUP(self[0]); - _PyFrame_SetStackPointer(frame, stack_pointer); -@@ -4609,40 +5022,47 @@ - self_or_null = &stack_pointer[-1 - oparg]; - callable = &stack_pointer[-2 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); -- int total_args = oparg; -- if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -- total_args++; -- } - if (!PyType_Check(callable_o)) { - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } - PyTypeObject *tp = (PyTypeObject *)callable_o; -+ int total_args = oparg; -+ _PyStackRef *arguments = args; -+ if (!PyStackRef_IsNull(self_or_null[0])) { -+ arguments--; -+ total_args++; -+ } - if (tp->tp_vectorcall == NULL) { - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } - STAT_INC(CALL, hit); -- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable[0]); -- PyStackRef_CLOSE(self_or_null[0]); -+ PyStackRef_XCLOSE(self_or_null[0]); - for (int _i = oparg; --_i >= 0;) { - PyStackRef_CLOSE(args[_i]); - } -- if (true) JUMP_TO_ERROR(); -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = tp->tp_vectorcall((PyObject *)tp, args_o, total_args, NULL); - stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); -- /* Free the arguments. */ -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -- } - PyStackRef_CLOSE(callable[0]); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ PyStackRef_XCLOSE(self_or_null[0]); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); -+ } -+ if (res_o == NULL) { -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; -@@ -4692,12 +5112,20 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - _Py_LeaveRecursiveCallTstate(tstate); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(arg); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callable[0]); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (res_o == NULL) { -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); -- stack_pointer[-2 - oparg] = res; -- stack_pointer += -1 - oparg; -+ stack_pointer[0] = res; -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } -@@ -4714,8 +5142,9 @@ - /* Builtin METH_FASTCALL functions, without keywords */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - if (!PyCFunction_CheckExact(callable_o)) { -@@ -4729,14 +5158,16 @@ - STAT_INC(CALL, hit); - PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable_o); - /* res = func(self, args, nargs) */ -- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable[0]); -- PyStackRef_CLOSE(self_or_null[0]); -+ PyStackRef_XCLOSE(self_or_null[0]); - for (int _i = oparg; --_i >= 0;) { - PyStackRef_CLOSE(args[_i]); - } -- if (true) JUMP_TO_ERROR(); -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = ((PyCFunctionFast)(void(*)(void))cfunc)( -@@ -4746,12 +5177,16 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); -- /* Free the arguments. */ -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -- } - PyStackRef_CLOSE(callable[0]); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ PyStackRef_XCLOSE(self_or_null[0]); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); -+ } -+ if (res_o == NULL) { -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; -@@ -4771,8 +5206,9 @@ - /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - if (!PyCFunction_CheckExact(callable_o)) { -@@ -4784,32 +5220,38 @@ - JUMP_TO_JUMP_TARGET(); - } - STAT_INC(CALL, hit); -- /* res = func(self, args, nargs, kwnames) */ -+ /* res = func(self, arguments, nargs, kwnames) */ - _PyFrame_SetStackPointer(frame, stack_pointer); - PyCFunctionFastWithKeywords cfunc = - (PyCFunctionFastWithKeywords)(void(*)(void)) - PyCFunction_GET_FUNCTION(callable_o); - stack_pointer = _PyFrame_GetStackPointer(frame); -- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable[0]); -- PyStackRef_CLOSE(self_or_null[0]); -+ PyStackRef_XCLOSE(self_or_null[0]); - for (int _i = oparg; --_i >= 0;) { - PyStackRef_CLOSE(args[_i]); - } -- if (true) JUMP_TO_ERROR(); -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = cfunc(PyCFunction_GET_SELF(callable_o), args_o, total_args, NULL); - stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); -- /* Free the arguments. */ -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -- } - PyStackRef_CLOSE(callable[0]); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ PyStackRef_XCLOSE(self_or_null[0]); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); -+ } -+ if (res_o == NULL) { -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; -@@ -4854,13 +5296,19 @@ - PyObject *res_o = PyLong_FromSsize_t(len_i); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - if (res_o == NULL) { -- GOTO_ERROR(error); -+ JUMP_TO_ERROR(); - } -- PyStackRef_CLOSE(callable[0]); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(arg_stackref); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(callable[0]); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - res = PyStackRef_FromPyObjectSteal(res_o); -- stack_pointer[-2 - oparg] = res; -- stack_pointer += -1 - oparg; -+ stack_pointer[0] = res; -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } -@@ -4877,8 +5325,9 @@ - /* isinstance(o, o2) */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - if (total_args != 2) { -@@ -4891,8 +5340,8 @@ - JUMP_TO_JUMP_TARGET(); - } - STAT_INC(CALL, hit); -- _PyStackRef cls_stackref = args[1]; -- _PyStackRef inst_stackref = args[0]; -+ _PyStackRef cls_stackref = arguments[1]; -+ _PyStackRef inst_stackref = arguments[0]; - _PyFrame_SetStackPointer(frame, stack_pointer); - int retval = PyObject_IsInstance(PyStackRef_AsPyObjectBorrow(inst_stackref), PyStackRef_AsPyObjectBorrow(cls_stackref)); - stack_pointer = _PyFrame_GetStackPointer(frame); -@@ -4901,9 +5350,11 @@ - } - res = retval ? PyStackRef_True : PyStackRef_False; - assert((!PyStackRef_IsNull(res)) ^ (_PyErr_Occurred(tstate) != NULL)); -- PyStackRef_CLOSE(inst_stackref); -- PyStackRef_CLOSE(cls_stackref); - PyStackRef_CLOSE(callable[0]); -+ PyStackRef_XCLOSE(self_or_null[0]); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); -+ } - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); -@@ -4938,17 +5389,25 @@ - STAT_INC(CALL, hit); - int err = _PyList_AppendTakeRef((PyListObject *)self_o, PyStackRef_AsPyObjectSteal(arg)); - UNLOCK_OBJECT(self_o); -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(self); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callable); -- if (err) JUMP_TO_ERROR(); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (err) { -+ JUMP_TO_ERROR(); -+ } - #if TIER_ONE - // Skip the following POP_TOP. This is done here in tier one, and - // during trace projection in tier two: - assert(next_instr->op.code == POP_TOP); - SKIP_OVER(1); - #endif -- stack_pointer += -3; -- assert(WITHIN_STACK_BOUNDS()); - break; - } - -@@ -4963,8 +5422,9 @@ - callable = &stack_pointer[-2 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; -@@ -4986,8 +5446,8 @@ - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } -- _PyStackRef arg_stackref = args[1]; -- _PyStackRef self_stackref = args[0]; -+ _PyStackRef arg_stackref = arguments[1]; -+ _PyStackRef self_stackref = arguments[0]; - if (!Py_IS_TYPE(PyStackRef_AsPyObjectBorrow(self_stackref), - method->d_common.d_type)) { - UOP_STAT_INC(uopcode, miss); -@@ -5003,10 +5463,16 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - _Py_LeaveRecursiveCallTstate(tstate); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); -- PyStackRef_CLOSE(self_stackref); -- PyStackRef_CLOSE(arg_stackref); - PyStackRef_CLOSE(callable[0]); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ PyStackRef_XCLOSE(self_or_null[0]); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); -+ } -+ if (res_o == NULL) { -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; -@@ -5025,8 +5491,9 @@ - callable = &stack_pointer[-2 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; -@@ -5040,21 +5507,23 @@ - JUMP_TO_JUMP_TARGET(); - } - PyTypeObject *d_type = method->d_common.d_type; -- PyObject *self = PyStackRef_AsPyObjectBorrow(args[0]); -+ PyObject *self = PyStackRef_AsPyObjectBorrow(arguments[0]); - if (!Py_IS_TYPE(self, d_type)) { - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } - STAT_INC(CALL, hit); - int nargs = total_args - 1; -- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable[0]); -- PyStackRef_CLOSE(self_or_null[0]); -+ PyStackRef_XCLOSE(self_or_null[0]); - for (int _i = oparg; --_i >= 0;) { - PyStackRef_CLOSE(args[_i]); - } -- if (true) JUMP_TO_ERROR(); -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - PyCFunctionFastWithKeywords cfunc = -@@ -5063,12 +5532,16 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); -- /* Free the arguments. */ -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -- } - PyStackRef_CLOSE(callable[0]); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ PyStackRef_XCLOSE(self_or_null[0]); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); -+ } -+ if (res_o == NULL) { -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; -@@ -5125,12 +5598,20 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - _Py_LeaveRecursiveCallTstate(tstate); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(self_stackref); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callable[0]); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (res_o == NULL) { -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); -- stack_pointer[-2 - oparg] = res; -- stack_pointer += -1 - oparg; -+ stack_pointer[0] = res; -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } -@@ -5146,8 +5627,9 @@ - callable = &stack_pointer[-2 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; -@@ -5161,21 +5643,23 @@ - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } -- PyObject *self = PyStackRef_AsPyObjectBorrow(args[0]); -+ PyObject *self = PyStackRef_AsPyObjectBorrow(arguments[0]); - if (!Py_IS_TYPE(self, method->d_common.d_type)) { - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } - STAT_INC(CALL, hit); - int nargs = total_args - 1; -- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable[0]); -- PyStackRef_CLOSE(self_or_null[0]); -+ PyStackRef_XCLOSE(self_or_null[0]); - for (int _i = oparg; --_i >= 0;) { - PyStackRef_CLOSE(args[_i]); - } -- if (true) JUMP_TO_ERROR(); -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - PyCFunctionFast cfunc = -@@ -5184,12 +5668,16 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); -- /* Clear the stack of the arguments. */ -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -- } - PyStackRef_CLOSE(callable[0]); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ PyStackRef_XCLOSE(self_or_null[0]); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); -+ } -+ if (res_o == NULL) { -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; -@@ -5197,7 +5685,7 @@ - break; - } - -- /* _INSTRUMENTED_CALL_KW is not a viable micro-op for tier 2 because it is instrumented */ -+ /* _MONITOR_CALL_KW is not a viable micro-op for tier 2 because it uses the 'this_instr' variable */ - - case _MAYBE_EXPAND_METHOD_KW: { - _PyStackRef kwnames_in; -@@ -5214,6 +5702,8 @@ - callable = &stack_pointer[-3 - oparg]; - func = &stack_pointer[-3 - oparg]; - maybe_self = &stack_pointer[-2 - oparg]; -+ args = &stack_pointer[-1 - oparg]; -+ (void)args; - if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - PyObject *self = ((PyMethodObject *)callable_o)->im_self; -@@ -5221,7 +5711,9 @@ - PyObject *method = ((PyMethodObject *)callable_o)->im_func; - _PyStackRef temp = callable[0]; - func[0] = PyStackRef_FromPyObjectNew(method); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(temp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - } - kwnames_out = kwnames_in; - stack_pointer[-1] = kwnames_out; -@@ -5244,8 +5736,9 @@ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - // oparg counts all of the args, but *not* self: - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); -@@ -5256,13 +5749,17 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyInterpreterFrame *temp = _PyEvalFramePushAndInit( - tstate, callable[0], locals, -- args, positional_args, kwnames_o, frame -+ arguments, positional_args, kwnames_o, frame - ); - stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(kwnames); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - // The frame has stolen all the arguments from the stack, - // so there is no need to clean them up. -- stack_pointer += -3 - oparg; -+ stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); - if (temp == NULL) { - JUMP_TO_ERROR(); -@@ -5321,23 +5818,21 @@ - } - - case _EXPAND_METHOD_KW: { -- _PyStackRef *null; -+ _PyStackRef *self_or_null; - _PyStackRef *callable; -- _PyStackRef *method; -- _PyStackRef *self; - oparg = CURRENT_OPARG(); -- null = &stack_pointer[-2 - oparg]; -+ self_or_null = &stack_pointer[-2 - oparg]; - callable = &stack_pointer[-3 - oparg]; -- method = &stack_pointer[-3 - oparg]; -- self = &stack_pointer[-2 - oparg]; -+ assert(PyStackRef_IsNull(self_or_null[0])); - _PyStackRef callable_s = callable[0]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable_s); -- assert(PyStackRef_IsNull(null[0])); - assert(Py_TYPE(callable_o) == &PyMethod_Type); -- self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); -- method[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); -- assert(PyStackRef_FunctionCheck(method[0])); -+ self_or_null[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); -+ callable[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); -+ assert(PyStackRef_FunctionCheck(callable[0])); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callable_s); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - break; - } - -@@ -5373,20 +5868,23 @@ - #endif - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - /* Callable is not a normal Python function */ -- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable[0]); -- PyStackRef_CLOSE(self_or_null[0]); -+ PyStackRef_XCLOSE(self_or_null[0]); - for (int _i = oparg; --_i >= 0;) { - PyStackRef_CLOSE(args[_i]); - } - PyStackRef_CLOSE(kwnames); -- if (true) JUMP_TO_ERROR(); -+ stack_pointer += -3 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); - } - PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); - int positional_args = total_args - (int)PyTuple_GET_SIZE(kwnames_o); -@@ -5396,36 +5894,43 @@ - positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, - kwnames_o); - stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(kwnames); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -- } - PyStackRef_CLOSE(callable[0]); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ PyStackRef_XCLOSE(self_or_null[0]); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); -+ } -+ if (res_o == NULL) { -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); -- stack_pointer[-3 - oparg] = res; -- stack_pointer += -2 - oparg; -+ stack_pointer[-2 - oparg] = res; -+ stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); - break; - } - -- /* _INSTRUMENTED_CALL_FUNCTION_EX is not a viable micro-op for tier 2 because it is instrumented */ -- - case _MAKE_CALLARGS_A_TUPLE: { -- _PyStackRef kwargs_in = PyStackRef_NULL; -+ _PyStackRef kwargs_in; - _PyStackRef callargs; - _PyStackRef func; - _PyStackRef tuple; -- _PyStackRef kwargs_out = PyStackRef_NULL; -- oparg = CURRENT_OPARG(); -- if (oparg & 1) { kwargs_in = stack_pointer[-(oparg & 1)]; } -- callargs = stack_pointer[-1 - (oparg & 1)]; -- func = stack_pointer[-3 - (oparg & 1)]; -+ _PyStackRef kwargs_out; -+ kwargs_in = stack_pointer[-1]; -+ callargs = stack_pointer[-2]; -+ func = stack_pointer[-4]; - PyObject *callargs_o = PyStackRef_AsPyObjectBorrow(callargs); - if (PyTuple_CheckExact(callargs_o)) { - tuple = callargs; -+ kwargs_out = kwargs_in; - } - else { - _PyFrame_SetStackPointer(frame, stack_pointer); -@@ -5440,12 +5945,18 @@ - if (tuple_o == NULL) { - JUMP_TO_ERROR(); - } -+ kwargs_out = kwargs_in; -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callargs); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - tuple = PyStackRef_FromPyObjectSteal(tuple_o); -+ stack_pointer += 2; -+ assert(WITHIN_STACK_BOUNDS()); - } -- kwargs_out = kwargs_in; -- stack_pointer[-1 - (oparg & 1)] = tuple; -- if (oparg & 1) stack_pointer[-(oparg & 1)] = kwargs_out; -+ stack_pointer[-2] = tuple; -+ stack_pointer[-1] = kwargs_out; - break; - } - -@@ -5460,12 +5971,20 @@ - PyFunctionObject *func_obj = (PyFunctionObject *) - PyFunction_New(codeobj, GLOBALS()); - stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(codeobj_st); -- if (func_obj == NULL) JUMP_TO_ERROR(); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (func_obj == NULL) { -+ JUMP_TO_ERROR(); -+ } - _PyFunction_SetVersion( - func_obj, ((PyCodeObject *)codeobj)->co_version); - func = PyStackRef_FromPyObjectSteal((PyObject *)func_obj); -- stack_pointer[-1] = func; -+ stack_pointer[0] = func; -+ stack_pointer += 1; -+ assert(WITHIN_STACK_BOUNDS()); - break; - } - -@@ -5498,7 +6017,9 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (gen == NULL) JUMP_TO_ERROR(); -+ if (gen == NULL) { -+ JUMP_TO_ERROR(); -+ } - assert(EMPTY()); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyInterpreterFrame *gen_frame = &gen->gi_iframe; -@@ -5522,25 +6043,25 @@ - } - - case _BUILD_SLICE: { -- _PyStackRef step = PyStackRef_NULL; -- _PyStackRef stop; -- _PyStackRef start; -+ _PyStackRef *args; - _PyStackRef slice; - oparg = CURRENT_OPARG(); -- if (oparg == 3) { step = stack_pointer[-((oparg == 3) ? 1 : 0)]; } -- stop = stack_pointer[-1 - ((oparg == 3) ? 1 : 0)]; -- start = stack_pointer[-2 - ((oparg == 3) ? 1 : 0)]; -- PyObject *start_o = PyStackRef_AsPyObjectBorrow(start); -- PyObject *stop_o = PyStackRef_AsPyObjectBorrow(stop); -- PyObject *step_o = PyStackRef_AsPyObjectBorrow(step); -+ args = &stack_pointer[-oparg]; -+ PyObject *start_o = PyStackRef_AsPyObjectBorrow(args[0]); -+ PyObject *stop_o = PyStackRef_AsPyObjectBorrow(args[1]); -+ PyObject *step_o = oparg == 3 ? PyStackRef_AsPyObjectBorrow(args[2]) : NULL; - PyObject *slice_o = PySlice_New(start_o, stop_o, step_o); -- PyStackRef_CLOSE(start); -- PyStackRef_CLOSE(stop); -- PyStackRef_XCLOSE(step); -- if (slice_o == NULL) JUMP_TO_ERROR(); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); -+ } -+ if (slice_o == NULL) { -+ stack_pointer += -oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - slice = PyStackRef_FromPyObjectSteal(slice_o); -- stack_pointer[-2 - ((oparg == 3) ? 1 : 0)] = slice; -- stack_pointer += -1 - ((oparg == 3) ? 1 : 0); -+ stack_pointer[-oparg] = slice; -+ stack_pointer += 1 - oparg; - assert(WITHIN_STACK_BOUNDS()); - break; - } -@@ -5556,10 +6077,18 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *result_o = conv_fn(PyStackRef_AsPyObjectBorrow(value)); - stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(value); -- if (result_o == NULL) JUMP_TO_ERROR(); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (result_o == NULL) { -+ JUMP_TO_ERROR(); -+ } - result = PyStackRef_FromPyObjectSteal(result_o); -- stack_pointer[-1] = result; -+ stack_pointer[0] = result; -+ stack_pointer += 1; -+ assert(WITHIN_STACK_BOUNDS()); - break; - } - -@@ -5574,14 +6103,24 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = PyObject_Format(value_o, NULL); - stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(value); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (res_o == NULL) { -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - } - else { - res = value; -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); - } -- stack_pointer[-1] = res; -+ stack_pointer[0] = res; -+ stack_pointer += 1; -+ assert(WITHIN_STACK_BOUNDS()); - break; - } - -@@ -5596,7 +6135,11 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(value); - PyStackRef_CLOSE(fmt_spec); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ if (res_o == NULL) { -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -5632,7 +6175,11 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(lhs); - PyStackRef_CLOSE(rhs); -- if (res_o == NULL) JUMP_TO_ERROR(); -+ if (res_o == NULL) { -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_ERROR(); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -5641,18 +6188,15 @@ - } - - case _SWAP: { -- _PyStackRef top_in; -- _PyStackRef bottom_in; -- _PyStackRef top_out; -- _PyStackRef bottom_out; -+ _PyStackRef *top; -+ _PyStackRef *bottom; - oparg = CURRENT_OPARG(); -- top_in = stack_pointer[-1]; -- bottom_in = stack_pointer[-2 - (oparg-2)]; -- bottom_out = bottom_in; -- top_out = top_in; -+ top = &stack_pointer[-1]; -+ bottom = &stack_pointer[-2 - (oparg-2)]; -+ _PyStackRef temp = bottom[0]; -+ bottom[0] = top[0]; -+ top[0] = temp; - assert(oparg >= 2); -- stack_pointer[-2 - (oparg-2)] = top_out; -- stack_pointer[-1] = bottom_out; - break; - } - -@@ -5664,6 +6208,8 @@ - - /* _MONITOR_JUMP_BACKWARD is not a viable micro-op for tier 2 because it uses the 'this_instr' variable */ - -+ /* _INSTRUMENTED_NOT_TAKEN is not a viable micro-op for tier 2 because it is instrumented */ -+ - /* _INSTRUMENTED_POP_JUMP_IF_TRUE is not a viable micro-op for tier 2 because it is instrumented */ - - /* _INSTRUMENTED_POP_JUMP_IF_FALSE is not a viable micro-op for tier 2 because it is instrumented */ -@@ -5703,9 +6249,11 @@ - val = stack_pointer[-1]; - int is_none = PyStackRef_IsNone(val); - if (!is_none) { -- PyStackRef_CLOSE(val); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(val); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - if (1) { - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); -@@ -5720,9 +6268,11 @@ - _PyStackRef val; - val = stack_pointer[-1]; - int is_none = PyStackRef_IsNone(val); -- PyStackRef_CLOSE(val); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(val); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - if (is_none) { - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); -@@ -5770,16 +6320,14 @@ - PyObject *exit_p = (PyObject *)CURRENT_OPERAND0(); - _PyExitData *exit = (_PyExitData *)exit_p; - PyCodeObject *code = _PyFrame_GetCode(frame); -- _PyFrame_SetStackPointer(frame, stack_pointer); - _Py_CODEUNIT *target = _PyFrame_GetBytecode(frame) + exit->target; -- stack_pointer = _PyFrame_GetStackPointer(frame); - #if defined(Py_DEBUG) && !defined(_Py_JIT) - OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); -- if (lltrace >= 2) { -+ if (frame->lltrace >= 2) { - _PyFrame_SetStackPointer(frame, stack_pointer); - printf("SIDE EXIT: [UOp "); - _PyUOpPrint(&next_uop[-1]); -- printf(", exit %u, temp %d, target %d -> %s]\n", -+ printf(", exit %lu, temp %d, target %d -> %s]\n", - exit - current_executor->exits, exit->temperature.value_and_backoff, - (int)(target - _PyFrame_GetBytecode(frame)), - _PyOpcode_OpName[target->op.code]); -@@ -5788,13 +6336,15 @@ - #endif - if (exit->executor && !exit->executor->vm_data.valid) { - exit->temperature = initial_temperature_backoff_counter(); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - Py_CLEAR(exit->executor); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - } -+ tstate->previous_executor = (PyObject *)current_executor; - if (exit->executor == NULL) { - _Py_BackoffCounter temperature = exit->temperature; - if (!backoff_counter_triggers(temperature)) { - exit->temperature = advance_backoff_counter(temperature); -- tstate->previous_executor = (PyObject *)current_executor; - GOTO_TIER_ONE(target); - } - _PyExecutorObject *executor; -@@ -5805,24 +6355,17 @@ - else { - int chain_depth = current_executor->vm_data.chain_depth + 1; - _PyFrame_SetStackPointer(frame, stack_pointer); -- int optimized = _PyOptimizer_Optimize(frame, target, stack_pointer, &executor, chain_depth); -+ int optimized = _PyOptimizer_Optimize(frame, target, &executor, chain_depth); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (optimized <= 0) { - exit->temperature = restart_backoff_counter(temperature); -- if (optimized < 0) { -- GOTO_UNWIND(); -- } -- tstate->previous_executor = (PyObject *)current_executor; -- GOTO_TIER_ONE(target); -- } -- else { -- exit->temperature = initial_temperature_backoff_counter(); -+ GOTO_TIER_ONE(optimized < 0 ? NULL : target); - } -+ exit->temperature = initial_temperature_backoff_counter(); - } - exit->executor = executor; - } - Py_INCREF(exit->executor); -- tstate->previous_executor = (PyObject *)current_executor; - GOTO_TIER_TWO(exit->executor); - break; - } -@@ -5860,34 +6403,14 @@ - _PyStackRef value; - pop = stack_pointer[-1]; - PyObject *ptr = (PyObject *)CURRENT_OPERAND0(); -- PyStackRef_CLOSE(pop); -- value = PyStackRef_FromPyObjectImmortal(ptr); -- stack_pointer[-1] = value; -- break; -- } -- -- case _LOAD_CONST_INLINE_WITH_NULL: { -- _PyStackRef value; -- _PyStackRef null; -- PyObject *ptr = (PyObject *)CURRENT_OPERAND0(); -- value = PyStackRef_FromPyObjectNew(ptr); -- null = PyStackRef_NULL; -- stack_pointer[0] = value; -- stack_pointer[1] = null; -- stack_pointer += 2; -+ stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); -- break; -- } -- -- case _LOAD_CONST_INLINE_BORROW_WITH_NULL: { -- _PyStackRef value; -- _PyStackRef null; -- PyObject *ptr = (PyObject *)CURRENT_OPERAND0(); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(pop); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - value = PyStackRef_FromPyObjectImmortal(ptr); -- null = PyStackRef_NULL; - stack_pointer[0] = value; -- stack_pointer[1] = null; -- stack_pointer += 2; -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } -@@ -5905,8 +6428,6 @@ - - case _LOAD_GLOBAL_MODULE: { - _PyStackRef res; -- _PyStackRef null = PyStackRef_NULL; -- oparg = CURRENT_OPARG(); - uint16_t index = (uint16_t)CURRENT_OPERAND0(); - PyDictObject *dict = (PyDictObject *)GLOBALS(); - PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); -@@ -5917,18 +6438,14 @@ - } - Py_INCREF(res_o); - res = PyStackRef_FromPyObjectSteal(res_o); -- null = PyStackRef_NULL; - stack_pointer[0] = res; -- if (oparg & 1) stack_pointer[1] = null; -- stack_pointer += 1 + (oparg & 1); -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _LOAD_GLOBAL_BUILTINS: { - _PyStackRef res; -- _PyStackRef null = PyStackRef_NULL; -- oparg = CURRENT_OPARG(); - uint16_t index = (uint16_t)CURRENT_OPERAND0(); - PyDictObject *dict = (PyDictObject *)BUILTINS(); - PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); -@@ -5939,10 +6456,8 @@ - } - Py_INCREF(res_o); - res = PyStackRef_FromPyObjectSteal(res_o); -- null = PyStackRef_NULL; - stack_pointer[0] = res; -- if (oparg & 1) stack_pointer[1] = null; -- stack_pointer += 1 + (oparg & 1); -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } -@@ -5950,8 +6465,6 @@ - case _LOAD_ATTR_MODULE: { - _PyStackRef owner; - _PyStackRef attr; -- _PyStackRef null = PyStackRef_NULL; -- oparg = CURRENT_OPARG(); - owner = stack_pointer[-1]; - uint16_t index = (uint16_t)CURRENT_OPERAND0(); - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); -@@ -5967,76 +6480,16 @@ - STAT_INC(LOAD_ATTR, hit); - Py_INCREF(attr_o); - attr = PyStackRef_FromPyObjectSteal(attr_o); -- null = PyStackRef_NULL; - PyStackRef_CLOSE(owner); - stack_pointer[-1] = attr; -- if (oparg & 1) stack_pointer[0] = null; -- stack_pointer += (oparg & 1); -- assert(WITHIN_STACK_BOUNDS()); -- break; -- } -- -- case _INTERNAL_INCREMENT_OPT_COUNTER: { -- _PyStackRef opt; -- opt = stack_pointer[-1]; -- _PyCounterOptimizerObject *exe = (_PyCounterOptimizerObject *)PyStackRef_AsPyObjectBorrow(opt); -- exe->count++; -- stack_pointer += -1; -- assert(WITHIN_STACK_BOUNDS()); -- break; -- } -- -- case _DYNAMIC_EXIT: { -- PyObject *exit_p = (PyObject *)CURRENT_OPERAND0(); -- tstate->previous_executor = (PyObject *)current_executor; -- _PyExitData *exit = (_PyExitData *)exit_p; -- _Py_CODEUNIT *target = frame->instr_ptr; -- #if defined(Py_DEBUG) && !defined(_Py_JIT) -- OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); -- if (lltrace >= 2) { -- _PyFrame_SetStackPointer(frame, stack_pointer); -- printf("DYNAMIC EXIT: [UOp "); -- _PyUOpPrint(&next_uop[-1]); -- printf(", exit %u, temp %d, target %d -> %s]\n", -- exit - current_executor->exits, exit->temperature.value_and_backoff, -- (int)(target - _PyFrame_GetBytecode(frame)), -- _PyOpcode_OpName[target->op.code]); -- stack_pointer = _PyFrame_GetStackPointer(frame); -- } -- #endif -- _PyExecutorObject *executor; -- if (target->op.code == ENTER_EXECUTOR) { -- PyCodeObject *code = _PyFrame_GetCode(frame); -- executor = code->co_executors->executors[target->op.arg]; -- Py_INCREF(executor); -- } -- else { -- if (!backoff_counter_triggers(exit->temperature)) { -- exit->temperature = advance_backoff_counter(exit->temperature); -- GOTO_TIER_ONE(target); -- } -- _PyFrame_SetStackPointer(frame, stack_pointer); -- int optimized = _PyOptimizer_Optimize(frame, target, stack_pointer, &executor, 0); -- stack_pointer = _PyFrame_GetStackPointer(frame); -- if (optimized <= 0) { -- exit->temperature = restart_backoff_counter(exit->temperature); -- if (optimized < 0) { -- GOTO_UNWIND(); -- } -- GOTO_TIER_ONE(target); -- } -- else { -- exit->temperature = initial_temperature_backoff_counter(); -- } -- } -- GOTO_TIER_TWO(executor); - break; - } - - case _START_EXECUTOR: { - PyObject *executor = (PyObject *)CURRENT_OPERAND0(); -- Py_DECREF(tstate->previous_executor); -- tstate->previous_executor = NULL; -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ Py_CLEAR(tstate->previous_executor); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - #ifndef _Py_JIT - current_executor = (_PyExecutorObject*)executor; - #endif -@@ -6070,19 +6523,18 @@ - } - - case _DEOPT: { -- EXIT_TO_TIER1(); -+ tstate->previous_executor = (PyObject *)current_executor; -+ GOTO_TIER_ONE(_PyFrame_GetBytecode(frame) + CURRENT_TARGET()); - break; - } - - case _ERROR_POP_N: { - oparg = CURRENT_OPARG(); - uint32_t target = (uint32_t)CURRENT_OPERAND0(); -- stack_pointer += -oparg; -- assert(WITHIN_STACK_BOUNDS()); -- _PyFrame_SetStackPointer(frame, stack_pointer); -+ tstate->previous_executor = (PyObject *)current_executor; -+ assert(oparg == 0); - frame->instr_ptr = _PyFrame_GetBytecode(frame) + target; -- stack_pointer = _PyFrame_GetStackPointer(frame); -- GOTO_UNWIND(); -+ GOTO_TIER_ONE(NULL); - break; - } - -diff --git a/Python/fileutils.c b/Python/fileutils.c -index 9529b14d377..68d24bc6b93 100644 ---- a/Python/fileutils.c -+++ b/Python/fileutils.c -@@ -1,6 +1,7 @@ - #include "Python.h" - #include "pycore_fileutils.h" // fileutils definitions - #include "pycore_runtime.h" // _PyRuntime -+#include "pycore_pystate.h" // _Py_AssertHoldsTstate() - #include "osdefs.h" // SEP - - #include // mbstowcs() -@@ -1311,7 +1312,7 @@ - { - int res; - -- assert(PyGILState_Check()); -+ _Py_AssertHoldsTstate(); - - Py_BEGIN_ALLOW_THREADS - res = _Py_fstat_noraise(fd, status); -@@ -1468,14 +1469,14 @@ - assert(!(atomic_flag_works != NULL && inheritable)); - - if (atomic_flag_works != NULL && !inheritable) { -- if (*atomic_flag_works == -1) { -+ if (_Py_atomic_load_int_relaxed(atomic_flag_works) == -1) { - int isInheritable = get_inheritable(fd, raise); - if (isInheritable == -1) - return -1; -- *atomic_flag_works = !isInheritable; -+ _Py_atomic_store_int_relaxed(atomic_flag_works, !isInheritable); - } - -- if (*atomic_flag_works) -+ if (_Py_atomic_load_int_relaxed(atomic_flag_works)) - return 0; - } - -@@ -1691,7 +1692,7 @@ - _Py_open(const char *pathname, int flags) - { - /* _Py_open() must be called with the GIL held. */ -- assert(PyGILState_Check()); -+ _Py_AssertHoldsTstate(); - return _Py_open_impl(pathname, flags, 1); - } - -@@ -1748,8 +1749,10 @@ - } - - --/* Open a file. Call _wfopen() on Windows, or encode the path to the filesystem -- encoding and call fopen() otherwise. -+/* Open a file. -+ -+ On Windows, if 'path' is a Unicode string, call _wfopen(). Otherwise, encode -+ the path to the filesystem encoding and call fopen(). - - Return the new file object on success. Raise an exception and return NULL - on error. -@@ -1762,32 +1765,32 @@ - Release the GIL to call _wfopen() or fopen(). The caller must hold - the GIL. */ - FILE* --_Py_fopen_obj(PyObject *path, const char *mode) -+Py_fopen(PyObject *path, const char *mode) - { -- FILE *f; -- int async_err = 0; --#ifdef MS_WINDOWS -- wchar_t wmode[10]; -- int usize; -- -- assert(PyGILState_Check()); -+ _Py_AssertHoldsTstate(); - - if (PySys_Audit("open", "Osi", path, mode, 0) < 0) { - return NULL; - } -- if (!PyUnicode_Check(path)) { -- PyErr_Format(PyExc_TypeError, -- "str file path expected under Windows, got %R", -- Py_TYPE(path)); -+ -+ FILE *f; -+ int async_err = 0; -+ int saved_errno; -+#ifdef MS_WINDOWS -+ PyObject *unicode; -+ if (!PyUnicode_FSDecoder(path, &unicode)) { - return NULL; - } - -- wchar_t *wpath = PyUnicode_AsWideCharString(path, NULL); -- if (wpath == NULL) -+ wchar_t *wpath = PyUnicode_AsWideCharString(unicode, NULL); -+ Py_DECREF(unicode); -+ if (wpath == NULL) { - return NULL; -+ } - -- usize = MultiByteToWideChar(CP_ACP, 0, mode, -1, -- wmode, Py_ARRAY_LENGTH(wmode)); -+ wchar_t wmode[10]; -+ int usize = MultiByteToWideChar(CP_ACP, 0, mode, -1, -+ wmode, Py_ARRAY_LENGTH(wmode)); - if (usize == 0) { - PyErr_SetFromWindowsErr(0); - PyMem_Free(wpath); -@@ -1796,26 +1799,20 @@ - - do { - Py_BEGIN_ALLOW_THREADS -+ _Py_BEGIN_SUPPRESS_IPH - f = _wfopen(wpath, wmode); -+ _Py_END_SUPPRESS_IPH - Py_END_ALLOW_THREADS - } while (f == NULL - && errno == EINTR && !(async_err = PyErr_CheckSignals())); -- int saved_errno = errno; -+ saved_errno = errno; - PyMem_Free(wpath); - #else - PyObject *bytes; -- const char *path_bytes; -- -- assert(PyGILState_Check()); -- -- if (!PyUnicode_FSConverter(path, &bytes)) -- return NULL; -- path_bytes = PyBytes_AS_STRING(bytes); -- -- if (PySys_Audit("open", "Osi", path, mode, 0) < 0) { -- Py_DECREF(bytes); -+ if (!PyUnicode_FSConverter(path, &bytes)) { - return NULL; - } -+ const char *path_bytes = PyBytes_AS_STRING(bytes); - - do { - Py_BEGIN_ALLOW_THREADS -@@ -1823,11 +1820,13 @@ - Py_END_ALLOW_THREADS - } while (f == NULL - && errno == EINTR && !(async_err = PyErr_CheckSignals())); -- int saved_errno = errno; -+ saved_errno = errno; - Py_DECREF(bytes); - #endif -- if (async_err) -+ -+ if (async_err) { - return NULL; -+ } - - if (f == NULL) { - errno = saved_errno; -@@ -1842,6 +1841,19 @@ - return f; - } - -+ -+// Call fclose(). -+// -+// On Windows, files opened by Py_fopen() in the Python DLL must be closed by -+// the Python DLL to use the same C runtime version. Otherwise, calling -+// fclose() directly can cause undefined behavior. -+int -+Py_fclose(FILE *file) -+{ -+ return fclose(file); -+} -+ -+ - /* Read count bytes from fd into buf. - - On success, return the number of read bytes, it can be lower than count. -@@ -1862,7 +1874,7 @@ - int err; - int async_err = 0; - -- assert(PyGILState_Check()); -+ _Py_AssertHoldsTstate(); - - /* _Py_read() must not be called with an exception set, otherwise the - * caller may think that read() was interrupted by a signal and the signal -@@ -2028,7 +2040,7 @@ - Py_ssize_t - _Py_write(int fd, const void *buf, size_t count) - { -- assert(PyGILState_Check()); -+ _Py_AssertHoldsTstate(); - - /* _Py_write() must not be called with an exception set, otherwise the - * caller may think that write() was interrupted by a signal and the signal -@@ -2656,7 +2668,7 @@ - HANDLE handle; - #endif - -- assert(PyGILState_Check()); -+ _Py_AssertHoldsTstate(); - - #ifdef MS_WINDOWS - handle = _Py_get_osfhandle(fd); -diff --git a/Python/flowgraph.c b/Python/flowgraph.c -index b1097b64469..308cdac3c44 100644 ---- a/Python/flowgraph.c -+++ b/Python/flowgraph.c -@@ -2,9 +2,12 @@ - #include - - #include "Python.h" -+#include "opcode.h" - #include "pycore_flowgraph.h" - #include "pycore_compile.h" -+#include "pycore_intrinsics.h" - #include "pycore_pymem.h" // _PyMem_IsPtrFreed() -+#include "pycore_long.h" // _PY_IS_SMALL_INT() - - #include "pycore_opcode_utils.h" - #include "pycore_opcode_metadata.h" // OPCODE_HAS_ARG, etc -@@ -522,14 +525,15 @@ - static int - normalize_jumps_in_block(cfg_builder *g, basicblock *b) { - cfg_instr *last = basicblock_last_instr(b); -- if (last == NULL || !is_jump(last) || -- IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)) { -+ if (last == NULL || !IS_CONDITIONAL_JUMP_OPCODE(last->i_opcode)) { - return SUCCESS; - } - assert(!IS_ASSEMBLER_OPCODE(last->i_opcode)); - - bool is_forward = last->i_target->b_visited == 0; - if (is_forward) { -+ RETURN_IF_ERROR( -+ basicblock_addop(b, NOT_TAKEN, 0, last->i_loc)); - return SUCCESS; - } - -@@ -557,6 +561,8 @@ - if (backwards_jump == NULL) { - return ERROR; - } -+ RETURN_IF_ERROR( -+ basicblock_addop(backwards_jump, NOT_TAKEN, 0, last->i_loc)); - RETURN_IF_ERROR( - basicblock_add_jump(backwards_jump, JUMP, target, last->i_loc)); - last->i_opcode = reversed_opcode; -@@ -1332,6 +1338,66 @@ - return (int)index; - } - -+/* -+ Walk basic block backwards starting from "start" trying to collect "size" number of -+ subsequent constants from instructions loading constants into new tuple ignoring NOP's in between. -+ -+ Returns ERROR on error and sets "seq" to NULL. -+ Returns SUCCESS on success and sets "seq" to NULL if failed to collect requested number of constants. -+ Returns SUCCESS on success and sets "seq" to resulting tuple if succeeded to collect requested number of constants. -+*/ -+static int -+get_constant_sequence(basicblock *bb, int start, int size, -+ PyObject *consts, PyObject **seq) -+{ -+ assert(start < bb->b_iused); -+ *seq = NULL; -+ PyObject *res = PyTuple_New((Py_ssize_t)size); -+ if (res == NULL) { -+ return ERROR; -+ } -+ for (; start >= 0 && size > 0; start--) { -+ cfg_instr *instr = &bb->b_instr[start]; -+ if (instr->i_opcode == NOP) { -+ continue; -+ } -+ if (!loads_const(instr->i_opcode)) { -+ break; -+ } -+ PyObject *constant = get_const_value(instr->i_opcode, instr->i_oparg, consts); -+ if (constant == NULL) { -+ Py_DECREF(res); -+ return ERROR; -+ } -+ PyTuple_SET_ITEM(res, --size, constant); -+ } -+ if (size > 0) { -+ Py_DECREF(res); -+ } -+ else { -+ *seq = res; -+ } -+ return SUCCESS; -+} -+ -+/* -+ Walk basic block backwards starting from "start" and change "count" number of -+ non-NOP instructions to NOP's. -+*/ -+static void -+nop_out(basicblock *bb, int start, int count) -+{ -+ assert(start < bb->b_iused); -+ for (; count > 0; start--) { -+ assert(start >= 0); -+ if (bb->b_instr[start].i_opcode == NOP) { -+ continue; -+ } -+ INSTR_SET_OP0(&bb->b_instr[start], NOP); -+ count--; -+ } -+} -+ - /* Replace LOAD_CONST c1, LOAD_CONST c2 ... LOAD_CONST cn, BUILD_TUPLE n - with LOAD_CONST (c1, c2, ... cn). - The consts table must still be in list form so that the -@@ -1339,47 +1405,159 @@ - Called with codestr pointing to the first LOAD_CONST. - */ - static int --fold_tuple_on_constants(PyObject *const_cache, -- cfg_instr *inst, -- int n, PyObject *consts) -+fold_tuple_of_constants(basicblock *bb, int n, PyObject *consts, PyObject *const_cache) - { - /* Pre-conditions */ - assert(PyDict_CheckExact(const_cache)); - assert(PyList_CheckExact(consts)); -- assert(inst[n].i_opcode == BUILD_TUPLE); -- assert(inst[n].i_oparg == n); -- -- for (int i = 0; i < n; i++) { -- if (!loads_const(inst[i].i_opcode)) { -- return SUCCESS; -- } -+ cfg_instr *instr = &bb->b_instr[n]; -+ assert(instr->i_opcode == BUILD_TUPLE); -+ int seq_size = instr->i_oparg; -+ PyObject *newconst; -+ RETURN_IF_ERROR(get_constant_sequence(bb, n-1, seq_size, consts, &newconst)); -+ if (newconst == NULL) { -+ /* not a const sequence */ -+ return SUCCESS; - } -+ assert(PyTuple_CheckExact(newconst) && PyTuple_GET_SIZE(newconst) == seq_size); -+ int index = add_const(newconst, consts, const_cache); -+ RETURN_IF_ERROR(index); -+ nop_out(bb, n-1, seq_size); -+ INSTR_SET_OP1(&bb->b_instr[n], LOAD_CONST, index); -+ return SUCCESS; -+} - -- /* Buildup new tuple of constants */ -- PyObject *newconst = PyTuple_New(n); -+#define MIN_CONST_SEQUENCE_SIZE 3 -+/* Replace LOAD_CONST c1, LOAD_CONST c2 ... LOAD_CONST cN, BUILD_LIST N -+ with BUILD_LIST 0, LOAD_CONST (c1, c2, ... cN), LIST_EXTEND 1, -+ or BUILD_SET & SET_UPDATE respectively. -+*/ -+static int -+optimize_if_const_list_or_set(basicblock *bb, int n, PyObject *consts, PyObject *const_cache) -+{ -+ assert(PyDict_CheckExact(const_cache)); -+ assert(PyList_CheckExact(consts)); -+ cfg_instr *instr = &bb->b_instr[n]; -+ assert(instr->i_opcode == BUILD_LIST || instr->i_opcode == BUILD_SET); -+ int seq_size = instr->i_oparg; -+ if (seq_size < MIN_CONST_SEQUENCE_SIZE) { -+ return SUCCESS; -+ } -+ PyObject *newconst; -+ RETURN_IF_ERROR(get_constant_sequence(bb, n-1, seq_size, consts, &newconst)); - if (newconst == NULL) { -- return ERROR; -+ /* not a const sequence */ -+ return SUCCESS; - } -- for (int i = 0; i < n; i++) { -- int op = inst[i].i_opcode; -- int arg = inst[i].i_oparg; -- PyObject *constant = get_const_value(op, arg, consts); -- if (constant == NULL) { -+ assert(PyTuple_CheckExact(newconst) && PyTuple_GET_SIZE(newconst) == seq_size); -+ int build = instr->i_opcode; -+ int extend = build == BUILD_LIST ? LIST_EXTEND : SET_UPDATE; -+ if (build == BUILD_SET) { -+ PyObject *frozenset = PyFrozenSet_New(newconst); -+ if (frozenset == NULL) { -+ Py_DECREF(newconst); - return ERROR; - } -- PyTuple_SET_ITEM(newconst, i, constant); -+ Py_SETREF(newconst, frozenset); - } - int index = add_const(newconst, consts, const_cache); -- if (index < 0) { -- return ERROR; -+ RETURN_IF_ERROR(index); -+ nop_out(bb, n-1, seq_size); -+ assert(n >= 2); -+ INSTR_SET_OP1(&bb->b_instr[n-2], build, 0); -+ INSTR_SET_OP1(&bb->b_instr[n-1], LOAD_CONST, index); -+ INSTR_SET_OP1(&bb->b_instr[n], extend, 1); -+ return SUCCESS; -+} -+ -+/* -+ Walk basic block backwards starting from "start" to collect instruction pair -+ that loads consts skipping NOP's in between. -+*/ -+static bool -+find_load_const_pair(basicblock *bb, int start, cfg_instr **first, cfg_instr **second) -+{ -+ cfg_instr *second_load_const = NULL; -+ while (start >= 0) { -+ cfg_instr *inst = &bb->b_instr[start--]; -+ if (inst->i_opcode == NOP) { -+ continue; -+ } -+ if (!loads_const(inst->i_opcode)) { -+ return false; -+ } -+ if (second_load_const == NULL) { -+ second_load_const = inst; -+ continue; -+ } -+ *first = inst; -+ *second = second_load_const; -+ return true; - } -- for (int i = 0; i < n; i++) { -- INSTR_SET_OP0(&inst[i], NOP); -+ return false; -+} -+ -+/* Determine opcode & oparg for freshly folded constant. */ -+static int -+newop_from_folded(PyObject *newconst, PyObject *consts, -+ PyObject *const_cache, int *newopcode, int *newoparg) -+{ -+ if (PyLong_CheckExact(newconst)) { -+ int overflow; -+ long val = PyLong_AsLongAndOverflow(newconst, &overflow); -+ if (!overflow && _PY_IS_SMALL_INT(val)) { -+ *newopcode = LOAD_SMALL_INT; -+ *newoparg = val; -+ return SUCCESS; -+ } - } -- INSTR_SET_OP1(&inst[n], LOAD_CONST, index); -+ *newopcode = LOAD_CONST; -+ *newoparg = add_const(newconst, consts, const_cache); -+ RETURN_IF_ERROR(*newoparg); - return SUCCESS; - } - -+static int -+optimize_if_const_op(basicblock *bb, int n, PyObject *consts, PyObject *const_cache) -+{ -+ cfg_instr *subscr = &bb->b_instr[n]; -+ assert(subscr->i_opcode == BINARY_OP); -+ if (subscr->i_oparg != NB_SUBSCR) { -+ /* TODO: support other binary ops */ -+ return SUCCESS; -+ } -+ cfg_instr *arg, *idx; -+ if (!find_load_const_pair(bb, n-1, &arg, &idx)) { -+ return SUCCESS; -+ } -+ PyObject *o = NULL, *key = NULL; -+ if ((o = get_const_value(arg->i_opcode, arg->i_oparg, consts)) == NULL -+ || (key = get_const_value(idx->i_opcode, idx->i_oparg, consts)) == NULL) -+ { -+ goto error; -+ } -+ PyObject *newconst = PyObject_GetItem(o, key); -+ Py_DECREF(o); -+ Py_DECREF(key); -+ if (newconst == NULL) { -+ if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) { -+ return ERROR; -+ } -+ PyErr_Clear(); -+ return SUCCESS; -+ } -+ int newopcode, newoparg; -+ RETURN_IF_ERROR(newop_from_folded(newconst, consts, const_cache, &newopcode, &newoparg)); -+ INSTR_SET_OP1(subscr, newopcode, newoparg); -+ INSTR_SET_OP0(arg, NOP); -+ INSTR_SET_OP0(idx, NOP); -+ return SUCCESS; -+error: -+ Py_XDECREF(o); -+ Py_XDECREF(key); -+ return ERROR; -+} -+ - #define VISITED (-1) - - // Replace an arbitrary run of SWAPs and NOPs with an optimal one that has the -@@ -1741,11 +1919,11 @@ - continue; - } - } -- if (i >= oparg) { -- if (fold_tuple_on_constants(const_cache, inst-oparg, oparg, consts)) { -- goto error; -- } -- } -+ RETURN_IF_ERROR(fold_tuple_of_constants(bb, i, consts, const_cache)); -+ break; -+ case BUILD_LIST: -+ case BUILD_SET: -+ RETURN_IF_ERROR(optimize_if_const_list_or_set(bb, i, consts, const_cache)); - break; - case POP_JUMP_IF_NOT_NONE: - case POP_JUMP_IF_NONE: -@@ -1871,6 +2049,15 @@ - continue; - } - break; -+ case CALL_INTRINSIC_1: -+ // for _ in (*foo, *bar) -> for _ in [*foo, *bar] -+ if (oparg == INTRINSIC_LIST_TO_TUPLE && nextop == GET_ITER) { -+ INSTR_SET_OP0(inst, NOP); -+ } -+ break; -+ case BINARY_OP: -+ RETURN_IF_ERROR(optimize_if_const_op(bb, i, consts, const_cache)); -+ break; - } - } - -diff --git a/Python/frame.c b/Python/frame.c -index 9a865e57d97..68ac2acbaee 100644 ---- a/Python/frame.c -+++ b/Python/frame.c -@@ -40,7 +40,6 @@ - // here. - assert(frame->frame_obj == NULL); - assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT); -- assert(frame->owner != FRAME_CLEARED); - f->f_frame = frame; - frame->frame_obj = f; - return f; -@@ -49,9 +48,8 @@ - static void - take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame) - { -- assert(frame->owner != FRAME_OWNED_BY_CSTACK); -+ assert(frame->owner < FRAME_OWNED_BY_INTERPRETER); - assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT); -- assert(frame->owner != FRAME_CLEARED); - Py_ssize_t size = ((char*)frame->stackpointer) - (char *)frame; - memcpy((_PyInterpreterFrame *)f->_f_frame_data, frame, size); - frame = (_PyInterpreterFrame *)f->_f_frame_data; -@@ -71,7 +69,7 @@ - _PyInterpreterFrame *prev = _PyFrame_GetFirstComplete(frame->previous); - frame->previous = NULL; - if (prev) { -- assert(prev->owner != FRAME_OWNED_BY_CSTACK); -+ assert(prev->owner < FRAME_OWNED_BY_INTERPRETER); - /* Link PyFrameObjects.f_back and remove link through _PyInterpreterFrame.previous */ - PyFrameObject *back = _PyFrame_GetFrameObject(prev); - if (back == NULL) { -diff --git a/Python/gc.c b/Python/gc.c -index 5b9588c8741..0fb2f03b040 100644 ---- a/Python/gc.c -+++ b/Python/gc.c -@@ -994,7 +994,8 @@ - /* copy-paste of weakrefobject.c's handle_callback() */ - temp = PyObject_CallOneArg(callback, (PyObject *)wr); - if (temp == NULL) { -- PyErr_WriteUnraisable(callback); -+ PyErr_FormatUnraisable("Exception ignored on " -+ "calling weakref callback %R", callback); - } - else { - Py_DECREF(temp); -@@ -1476,7 +1477,7 @@ - while (ts) { - _PyInterpreterFrame *frame = ts->current_frame; - while (frame) { -- if (frame->owner == FRAME_OWNED_BY_CSTACK) { -+ if (frame->owner >= FRAME_OWNED_BY_INTERPRETER) { - frame = frame->previous; - continue; - } -@@ -1779,7 +1780,7 @@ - "collected", stats->collected, - "uncollectable", stats->uncollectable); - if (info == NULL) { -- PyErr_FormatUnraisable("Exception ignored on invoking gc callbacks"); -+ PyErr_FormatUnraisable("Exception ignored while invoking gc callbacks"); - return; - } - } -@@ -1787,7 +1788,7 @@ - PyObject *phase_obj = PyUnicode_FromString(phase); - if (phase_obj == NULL) { - Py_XDECREF(info); -- PyErr_FormatUnraisable("Exception ignored on invoking gc callbacks"); -+ PyErr_FormatUnraisable("Exception ignored while invoking gc callbacks"); - return; - } - -@@ -1797,7 +1798,8 @@ - Py_INCREF(cb); /* make sure cb doesn't go away */ - r = PyObject_Vectorcall(cb, stack, 2, NULL); - if (r == NULL) { -- PyErr_WriteUnraisable(cb); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "calling GC callback %R", cb); - } - else { - Py_DECREF(r); -@@ -2086,13 +2088,14 @@ - "gc", NULL, message, - PyList_GET_SIZE(gcstate->garbage))) - { -- PyErr_WriteUnraisable(NULL); -+ PyErr_FormatUnraisable("Exception ignored in GC shutdown"); - } - if (gcstate->debug & _PyGC_DEBUG_UNCOLLECTABLE) { - PyObject *repr = NULL, *bytes = NULL; - repr = PyObject_Repr(gcstate->garbage); - if (!repr || !(bytes = PyUnicode_EncodeFSDefault(repr))) { -- PyErr_WriteUnraisable(gcstate->garbage); -+ PyErr_FormatUnraisable("Exception ignored in GC shutdown " -+ "while formatting garbage"); - } - else { - PySys_WriteStderr( -@@ -2344,9 +2347,12 @@ - #ifdef Py_DEBUG - PyObject *exc = PyErr_GetRaisedException(); - if (PyErr_WarnExplicitFormat(PyExc_ResourceWarning, "gc", 0, -- "gc", NULL, "Object of type %s is not untracked before destruction", -- Py_TYPE(op)->tp_name)) { -- PyErr_WriteUnraisable(NULL); -+ "gc", NULL, -+ "Object of type %s is not untracked " -+ "before destruction", -+ Py_TYPE(op)->tp_name)) -+ { -+ PyErr_FormatUnraisable("Exception ignored on object deallocation"); - } - PyErr_SetRaisedException(exc); - #endif -diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c -index f7f44407494..9e459da3a44 100644 ---- a/Python/gc_free_threading.c -+++ b/Python/gc_free_threading.c -@@ -17,6 +17,20 @@ - #include "pydtrace.h" - #include "pycore_uniqueid.h" // _PyObject_MergeThreadLocalRefcounts() - -+ -+// enable the "mark alive" pass of GC -+#define GC_ENABLE_MARK_ALIVE 1 -+ -+// if true, enable the use of "prefetch" CPU instructions -+#define GC_ENABLE_PREFETCH_INSTRUCTIONS 1 -+ -+// include additional roots in "mark alive" pass -+#define GC_MARK_ALIVE_EXTRA_ROOTS 1 -+ -+// include Python stacks as set of known roots -+#define GC_MARK_ALIVE_STACKS 1 -+ -+ - #ifdef Py_GIL_DISABLED - - typedef struct _gc_runtime_state GCState; -@@ -56,6 +70,10 @@ - PyInterpreterState *interp; - GCState *gcstate; - _PyGC_Reason reason; -+ // GH-129236: If we see an active frame without a valid stack pointer, -+ // we can't collect objects with deferred references because we may not -+ // see all references. -+ int skip_deferred_objects; - Py_ssize_t collected; - Py_ssize_t uncollectable; - Py_ssize_t long_lived_total; -@@ -113,28 +131,66 @@ - iter->next = iter->ptr; - } - -+static inline int -+gc_has_bit(PyObject *op, uint8_t bit) -+{ -+ return (op->ob_gc_bits & bit) != 0; -+} -+ -+static inline void -+gc_set_bit(PyObject *op, uint8_t bit) -+{ -+ op->ob_gc_bits |= bit; -+} -+ -+static inline void -+gc_clear_bit(PyObject *op, uint8_t bit) -+{ -+ op->ob_gc_bits &= ~bit; -+} -+ - static inline int - gc_is_frozen(PyObject *op) - { -- return (op->ob_gc_bits & _PyGC_BITS_FROZEN) != 0; -+ return gc_has_bit(op, _PyGC_BITS_FROZEN); - } - - static inline int - gc_is_unreachable(PyObject *op) - { -- return (op->ob_gc_bits & _PyGC_BITS_UNREACHABLE) != 0; -+ return gc_has_bit(op, _PyGC_BITS_UNREACHABLE); - } - --static void -+static inline void - gc_set_unreachable(PyObject *op) - { -- op->ob_gc_bits |= _PyGC_BITS_UNREACHABLE; -+ gc_set_bit(op, _PyGC_BITS_UNREACHABLE); - } - --static void -+static inline void - gc_clear_unreachable(PyObject *op) - { -- op->ob_gc_bits &= ~_PyGC_BITS_UNREACHABLE; -+ gc_clear_bit(op, _PyGC_BITS_UNREACHABLE); -+} -+ -+static inline int -+gc_is_alive(PyObject *op) -+{ -+ return gc_has_bit(op, _PyGC_BITS_ALIVE); -+} -+ -+#ifdef GC_ENABLE_MARK_ALIVE -+static inline void -+gc_set_alive(PyObject *op) -+{ -+ gc_set_bit(op, _PyGC_BITS_ALIVE); -+} -+#endif -+ -+static inline void -+gc_clear_alive(PyObject *op) -+{ -+ gc_clear_bit(op, _PyGC_BITS_ALIVE); - } - - // Initialize the `ob_tid` field to zero if the object is not already -@@ -143,6 +199,7 @@ - gc_maybe_init_refs(PyObject *op) - { - if (!gc_is_unreachable(op)) { -+ assert(!gc_is_alive(op)); - gc_set_unreachable(op); - op->ob_tid = 0; - } -@@ -264,9 +321,13 @@ - gc_restore_refs(PyObject *op) - { - if (gc_is_unreachable(op)) { -+ assert(!gc_is_alive(op)); - gc_restore_tid(op); - gc_clear_unreachable(op); - } -+ else { -+ gc_clear_alive(op); -+ } - } - - // Given a mimalloc memory block return the PyObject stored in it or NULL if -@@ -359,9 +420,6 @@ - static inline void - gc_visit_stackref(_PyStackRef stackref) - { -- // Note: we MUST check that it is deferred before checking the rest. -- // Otherwise we might read into invalid memory due to non-deferred references -- // being dead already. - if (PyStackRef_IsDeferred(stackref) && !PyStackRef_IsNull(stackref)) { - PyObject *obj = PyStackRef_AsPyObjectBorrow(stackref); - if (_PyObject_GC_IS_TRACKED(obj) && !gc_is_frozen(obj)) { -@@ -372,25 +430,419 @@ - - // Add 1 to the gc_refs for every deferred reference on each thread's stack. - static void --gc_visit_thread_stacks(PyInterpreterState *interp) -+gc_visit_thread_stacks(PyInterpreterState *interp, struct collection_state *state) - { - _Py_FOR_EACH_TSTATE_BEGIN(interp, p) { - for (_PyInterpreterFrame *f = p->current_frame; f != NULL; f = f->previous) { -- PyObject *executable = PyStackRef_AsPyObjectBorrow(f->f_executable); -- if (executable == NULL || !PyCode_Check(executable)) { -+ if (f->owner >= FRAME_OWNED_BY_INTERPRETER) { -+ continue; -+ } -+ -+ _PyStackRef *top = f->stackpointer; -+ if (top == NULL) { -+ // GH-129236: The stackpointer may be NULL in cases where -+ // the GC is run during a PyStackRef_CLOSE() call. Skip this -+ // frame and don't collect objects with deferred references. -+ state->skip_deferred_objects = 1; - continue; - } - -- PyCodeObject *co = (PyCodeObject *)executable; -- int max_stack = co->co_nlocalsplus + co->co_stacksize; - gc_visit_stackref(f->f_executable); -- for (int i = 0; i < max_stack; i++) { -- gc_visit_stackref(f->localsplus[i]); -+ while (top != f->localsplus) { -+ --top; -+ gc_visit_stackref(*top); -+ } -+ } -+ } -+ _Py_FOR_EACH_TSTATE_END(interp); -+} -+ -+// Untrack objects that can never create reference cycles. -+// Return true if the object was untracked. -+static bool -+gc_maybe_untrack(PyObject *op) -+{ -+ // Currently we only check for tuples containing only non-GC objects. In -+ // theory we could check other immutable objects that contain references -+ // to non-GC objects. -+ if (PyTuple_CheckExact(op)) { -+ _PyTuple_MaybeUntrack(op); -+ if (!_PyObject_GC_IS_TRACKED(op)) { -+ return true; -+ } -+ } -+ return false; -+} -+ -+#ifdef GC_ENABLE_MARK_ALIVE -+ -+// prefetch buffer and stack ////////////////////////////////// -+ -+// The buffer is a circular FIFO queue of PyObject pointers. We take -+// care to not dereference these pointers until they are taken out of -+// the buffer. A prefetch CPU instruction is issued when a pointer is -+// put into the buffer. If all is working as expected, there will be -+// enough time between the enqueue and dequeue so that the needed memory -+// for the object, most importantly ob_gc_bits and ob_type words, will -+// already be in the CPU cache. -+#define BUFFER_SIZE 256 -+#define BUFFER_HI 16 -+#define BUFFER_LO 8 -+#define BUFFER_MASK (BUFFER_SIZE - 1) -+ -+// the buffer size must be an exact power of two -+static_assert(BUFFER_SIZE > 0 && !(BUFFER_SIZE & BUFFER_MASK), -+ "Invalid BUFFER_SIZE, must be power of 2"); -+// the code below assumes these relationships are true -+static_assert(BUFFER_HI < BUFFER_SIZE && -+ BUFFER_LO < BUFFER_HI && -+ BUFFER_LO > 0, -+ "Invalid prefetch buffer level settings."); -+ -+// Prefetch intructions will fetch the line of data from memory that -+// contains the byte specified with the source operand to a location in -+// the cache hierarchy specified by a locality hint. The instruction -+// is only a hint and the CPU is free to ignore it. Instructions and -+// behaviour are CPU specific but the definitions of locality hints -+// below are mostly consistent. -+// -+// * T0 (temporal data) prefetch data into all levels of the cache hierarchy. -+// -+// * T1 (temporal data with respect to first level cache) prefetch data into -+// level 2 cache and higher. -+// -+// * T2 (temporal data with respect to second level cache) prefetch data into -+// level 3 cache and higher, or an implementation-specific choice. -+// -+// * NTA (non-temporal data with respect to all cache levels) prefetch data into -+// non-temporal cache structure and into a location close to the processor, -+// minimizing cache pollution. -+ -+#if defined(__GNUC__) || defined(__clang__) -+ #define PREFETCH_T0(ptr) __builtin_prefetch(ptr, 0, 3) -+ #define PREFETCH_T1(ptr) __builtin_prefetch(ptr, 0, 2) -+ #define PREFETCH_T2(ptr) __builtin_prefetch(ptr, 0, 1) -+ #define PREFETCH_NTA(ptr) __builtin_prefetch(ptr, 0, 0) -+#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) && !defined(_M_ARM64EC) -+ #include -+ #define PREFETCH_T0(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0) -+ #define PREFETCH_T1(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T1) -+ #define PREFETCH_T2(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T2) -+ #define PREFETCH_NTA(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_NTA) -+#elif defined (__aarch64__) -+ #define PREFETCH_T0(ptr) \ -+ do { __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr))); } while (0) -+ #define PREFETCH_T1(ptr) \ -+ do { __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr))); } while (0) -+ #define PREFETCH_T2(ptr) \ -+ do { __asm__ __volatile__("prfm pldl3keep, %0" ::"Q"(*(ptr))); } while (0) -+ #define PREFETCH_NTA(ptr) \ -+ do { __asm__ __volatile__("prfm pldl1strm, %0" ::"Q"(*(ptr))); } while (0) -+#else -+ #define PREFETCH_T0(ptr) do { (void)(ptr); } while (0) /* disabled */ -+ #define PREFETCH_T1(ptr) do { (void)(ptr); } while (0) /* disabled */ -+ #define PREFETCH_T2(ptr) do { (void)(ptr); } while (0) /* disabled */ -+ #define PREFETCH_NTA(ptr) do { (void)(ptr); } while (0) /* disabled */ -+#endif -+ -+#ifdef GC_ENABLE_PREFETCH_INSTRUCTIONS -+ #define prefetch(ptr) PREFETCH_T1(ptr) -+#else -+ #define prefetch(ptr) -+#endif -+ -+// a contigous sequence of PyObject pointers, can contain NULLs -+typedef struct { -+ PyObject **start; -+ PyObject **end; -+} gc_span_t; -+ -+typedef struct { -+ Py_ssize_t size; -+ Py_ssize_t capacity; -+ gc_span_t *stack; -+} gc_span_stack_t; -+ -+typedef struct { -+ unsigned int in; -+ unsigned int out; -+ _PyObjectStack stack; -+ gc_span_stack_t spans; -+ PyObject *buffer[BUFFER_SIZE]; -+ bool use_prefetch; -+} gc_mark_args_t; -+ -+ -+// Returns number of entries in buffer -+static inline unsigned int -+gc_mark_buffer_len(gc_mark_args_t *args) -+{ -+ return args->in - args->out; -+} -+ -+// Returns number of free entry slots in buffer -+static inline unsigned int -+gc_mark_buffer_avail(gc_mark_args_t *args) -+{ -+ return BUFFER_SIZE - gc_mark_buffer_len(args); -+} -+ -+static inline bool -+gc_mark_buffer_is_empty(gc_mark_args_t *args) -+{ -+ return args->in == args->out; -+} -+ -+static inline bool -+gc_mark_buffer_is_full(gc_mark_args_t *args) -+{ -+ return gc_mark_buffer_len(args) == BUFFER_SIZE; -+} -+ -+static inline PyObject * -+gc_mark_buffer_pop(gc_mark_args_t *args) -+{ -+ assert(!gc_mark_buffer_is_empty(args)); -+ PyObject *op = args->buffer[args->out & BUFFER_MASK]; -+ args->out++; -+ return op; -+} -+ -+// Called when there is space in the buffer for the object. Issue the -+// prefetch instruction and add it to the end of the buffer. -+static inline void -+gc_mark_buffer_push(PyObject *op, gc_mark_args_t *args) -+{ -+ assert(!gc_mark_buffer_is_full(args)); -+ prefetch(op); -+ args->buffer[args->in & BUFFER_MASK] = op; -+ args->in++; -+} -+ -+// Called when we run out of space in the buffer or if the prefetching -+// is disabled. The object will be pushed on the gc_mark_args.stack. -+static int -+gc_mark_stack_push(_PyObjectStack *ms, PyObject *op) -+{ -+ if (_PyObjectStack_Push(ms, op) < 0) { -+ return -1; -+ } -+ return 0; -+} -+ -+static int -+gc_mark_span_push(gc_span_stack_t *ss, PyObject **start, PyObject **end) -+{ -+ if (start == end) { -+ return 0; -+ } -+ if (ss->size >= ss->capacity) { -+ if (ss->capacity == 0) { -+ ss->capacity = 256; -+ } -+ else { -+ ss->capacity *= 2; -+ } -+ ss->stack = (gc_span_t *)PyMem_Realloc(ss->stack, ss->capacity * sizeof(gc_span_t)); -+ if (ss->stack == NULL) { -+ return -1; -+ } -+ } -+ assert(end > start); -+ ss->stack[ss->size].start = start; -+ ss->stack[ss->size].end = end; -+ ss->size++; -+ return 0; -+} -+ -+static int -+gc_mark_enqueue_no_buffer(PyObject *op, gc_mark_args_t *args) -+{ -+ if (op == NULL) { -+ return 0; -+ } -+ if (!gc_has_bit(op, _PyGC_BITS_TRACKED)) { -+ return 0; -+ } -+ if (gc_is_alive(op)) { -+ return 0; // already visited this object -+ } -+ if (gc_maybe_untrack(op)) { -+ return 0; // was untracked, don't visit it -+ } -+ -+ // Need to call tp_traverse on this object. Add to stack and mark it -+ // alive so we don't traverse it a second time. -+ gc_set_alive(op); -+ if (_PyObjectStack_Push(&args->stack, op) < 0) { -+ return -1; -+ } -+ return 0; -+} -+ -+static int -+gc_mark_enqueue_buffer(PyObject *op, gc_mark_args_t *args) -+{ -+ assert(op != NULL); -+ if (!gc_mark_buffer_is_full(args)) { -+ gc_mark_buffer_push(op, args); -+ return 0; -+ } -+ else { -+ return gc_mark_stack_push(&args->stack, op); -+ } -+} -+ -+// Called when we find an object that needs to be marked alive (either from a -+// root or from calling tp_traverse). -+static int -+gc_mark_enqueue(PyObject *op, gc_mark_args_t *args) -+{ -+ if (args->use_prefetch) { -+ return gc_mark_enqueue_buffer(op, args); -+ } -+ else { -+ return gc_mark_enqueue_no_buffer(op, args); -+ } -+} -+ -+// Called when we have a contigous sequence of PyObject pointers, either -+// a tuple or list object. This will add the items to the buffer if there -+// is space for them all otherwise push a new "span" on the span stack. Using -+// spans has the advantage of not creating a deep _PyObjectStack stack when -+// dealing with long sequences. Those sequences will be processed in smaller -+// chunks by the gc_prime_from_spans() function. -+static int -+gc_mark_enqueue_span(PyObject **item, Py_ssize_t size, gc_mark_args_t *args) -+{ -+ Py_ssize_t used = gc_mark_buffer_len(args); -+ Py_ssize_t free = BUFFER_SIZE - used; -+ if (free >= size) { -+ for (Py_ssize_t i = 0; i < size; i++) { -+ PyObject *op = item[i]; -+ if (op == NULL) { -+ continue; -+ } -+ gc_mark_buffer_push(op, args); -+ } -+ } -+ else { -+ assert(size > 0); -+ PyObject **end = &item[size]; -+ if (gc_mark_span_push(&args->spans, item, end) < 0) { -+ return -1; -+ } -+ } -+ return 0; -+} -+ -+static bool -+gc_clear_alive_bits(const mi_heap_t *heap, const mi_heap_area_t *area, -+ void *block, size_t block_size, void *args) -+{ -+ PyObject *op = op_from_block(block, args, false); -+ if (op == NULL) { -+ return true; -+ } -+ if (gc_is_alive(op)) { -+ gc_clear_alive(op); -+ } -+ return true; -+} -+ -+static int -+gc_mark_traverse_list(PyObject *self, void *args) -+{ -+ PyListObject *list = (PyListObject *)self; -+ if (list->ob_item == NULL) { -+ return 0; -+ } -+ if (gc_mark_enqueue_span(list->ob_item, PyList_GET_SIZE(list), args) < 0) { -+ return -1; -+ } -+ return 0; -+} -+ -+static int -+gc_mark_traverse_tuple(PyObject *self, void *args) -+{ -+ _PyTuple_MaybeUntrack(self); -+ if (!gc_has_bit(self, _PyGC_BITS_TRACKED)) { -+ gc_clear_alive(self); -+ return 0; -+ } -+ PyTupleObject *tuple = _PyTuple_CAST(self); -+ if (gc_mark_enqueue_span(tuple->ob_item, Py_SIZE(tuple), args) < 0) { -+ return -1; -+ } -+ return 0; -+} -+ -+static void -+gc_abort_mark_alive(PyInterpreterState *interp, -+ struct collection_state *state, -+ gc_mark_args_t *args) -+{ -+ // We failed to allocate memory while doing the "mark alive" phase. -+ // In that case, free the memory used for marking state and make -+ // sure that no objects have the alive bit set. -+ _PyObjectStack_Clear(&args->stack); -+ if (args->spans.stack != NULL) { -+ PyMem_Free(args->spans.stack); -+ } -+ gc_visit_heaps(interp, &gc_clear_alive_bits, &state->base); -+} -+ -+#ifdef GC_MARK_ALIVE_STACKS -+static int -+gc_visit_stackref_mark_alive(gc_mark_args_t *args, _PyStackRef stackref) -+{ -+ if (!PyStackRef_IsNull(stackref)) { -+ PyObject *op = PyStackRef_AsPyObjectBorrow(stackref); -+ if (gc_mark_enqueue(op, args) < 0) { -+ return -1; -+ } -+ } -+ return 0; -+} -+ -+static int -+gc_visit_thread_stacks_mark_alive(PyInterpreterState *interp, gc_mark_args_t *args) -+{ -+ int err = 0; -+ _Py_FOR_EACH_TSTATE_BEGIN(interp, p) { -+ for (_PyInterpreterFrame *f = p->current_frame; f != NULL; f = f->previous) { -+ if (f->owner >= FRAME_OWNED_BY_INTERPRETER) { -+ continue; -+ } -+ -+ if (f->stackpointer == NULL) { -+ // GH-129236: The stackpointer may be NULL in cases where -+ // the GC is run during a PyStackRef_CLOSE() call. Skip this -+ // frame for now. -+ continue; -+ } -+ -+ _PyStackRef *top = f->stackpointer; -+ if (gc_visit_stackref_mark_alive(args, f->f_executable) < 0) { -+ err = -1; -+ goto exit; -+ } -+ while (top != f->localsplus) { -+ --top; -+ if (gc_visit_stackref_mark_alive(args, *top) < 0) { -+ err = -1; -+ goto exit; -+ } - } - } - } -+exit: - _Py_FOR_EACH_TSTATE_END(interp); -+ return err; - } -+#endif // GC_MARK_ALIVE_STACKS -+#endif // GC_ENABLE_MARK_ALIVE - - static void - queue_untracked_obj_decref(PyObject *op, struct collection_state *state) -@@ -460,7 +912,8 @@ - { - if (_PyObject_GC_IS_TRACKED(op) - && !_Py_IsImmortal(op) -- && !gc_is_frozen(op)) -+ && !gc_is_frozen(op) -+ && !gc_is_alive(op)) - { - // If update_refs hasn't reached this object yet, mark it - // as (tentatively) unreachable and initialize ob_tid to zero. -@@ -482,6 +935,10 @@ - return true; - } - -+ if (gc_is_alive(op)) { -+ return true; -+ } -+ - // Exclude immortal objects from garbage collection - if (_Py_IsImmortal(op)) { - op->ob_tid = 0; -@@ -497,14 +954,9 @@ - _PyObject_ASSERT(op, refcount >= 0); - - if (refcount > 0 && !_PyObject_HasDeferredRefcount(op)) { -- // Untrack tuples and dicts as necessary in this pass, but not objects -- // with zero refcount, which we will want to collect. -- if (PyTuple_CheckExact(op)) { -- _PyTuple_MaybeUntrack(op); -- if (!_PyObject_GC_IS_TRACKED(op)) { -- gc_restore_refs(op); -- return true; -- } -+ if (gc_maybe_untrack(op)) { -+ gc_restore_refs(op); -+ return true; - } - } - -@@ -553,6 +1005,21 @@ - } - - #ifdef GC_DEBUG -+static bool -+validate_alive_bits(const mi_heap_t *heap, const mi_heap_area_t *area, -+ void *block, size_t block_size, void *args) -+{ -+ PyObject *op = op_from_block(block, args, false); -+ if (op == NULL) { -+ return true; -+ } -+ -+ _PyObject_ASSERT_WITH_MSG(op, !gc_is_alive(op), -+ "object should not be marked as alive yet"); -+ -+ return true; -+} -+ - static bool - validate_refcounts(const mi_heap_t *heap, const mi_heap_area_t *area, - void *block, size_t block_size, void *args) -@@ -586,6 +1053,11 @@ - return true; - } - -+ if (gc_is_alive(op)) { -+ _PyObject_ASSERT(op, !gc_is_unreachable(op)); -+ return true; -+ } -+ - _PyObject_ASSERT(op, gc_is_unreachable(op)); - _PyObject_ASSERT_WITH_MSG(op, gc_get_refs(op) >= 0, - "refcount is too small"); -@@ -605,7 +1077,20 @@ - _PyObject_ASSERT_WITH_MSG(op, gc_get_refs(op) >= 0, - "refcount is too small"); - -- if (gc_is_unreachable(op) && gc_get_refs(op) != 0) { -+ if (gc_is_alive(op) || !gc_is_unreachable(op)) { -+ // Object was already marked as reachable. -+ return true; -+ } -+ -+ // GH-129236: If we've seen an active frame without a valid stack pointer, -+ // then we can't collect objects with deferred references because we may -+ // have missed some reference to the object on the stack. In that case, -+ // treat the object as reachable even if gc_refs is zero. -+ struct collection_state *state = (struct collection_state *)args; -+ int keep_alive = (state->skip_deferred_objects && -+ _PyObject_HasDeferredRefcount(op)); -+ -+ if (gc_get_refs(op) != 0 || keep_alive) { - // Object is reachable but currently marked as unreachable. - // Mark it as reachable and traverse its pointers to find - // any other object that may be directly reachable from it. -@@ -630,6 +1115,7 @@ - } - gc_restore_tid(op); - gc_clear_unreachable(op); -+ gc_clear_alive(op); - return true; - } - -@@ -679,6 +1165,7 @@ - - // object is reachable, restore `ob_tid`; we're done with these objects - gc_restore_tid(op); -+ gc_clear_alive(op); - state->long_lived_total++; - return true; - } -@@ -686,6 +1173,207 @@ - static int - move_legacy_finalizer_reachable(struct collection_state *state); - -+#ifdef GC_ENABLE_MARK_ALIVE -+ -+static void -+gc_prime_from_spans(gc_mark_args_t *args) -+{ -+ Py_ssize_t space = BUFFER_HI - gc_mark_buffer_len(args); -+ // there should always be at least this amount of space -+ assert(space <= gc_mark_buffer_avail(args)); -+ assert(space > 0); -+ gc_span_t entry = args->spans.stack[--args->spans.size]; -+ // spans on the stack should always have one or more elements -+ assert(entry.start < entry.end); -+ do { -+ PyObject *op = *entry.start; -+ entry.start++; -+ if (op != NULL) { -+ gc_mark_buffer_push(op, args); -+ space--; -+ if (space == 0) { -+ // buffer is as full as we want and not done with span -+ gc_mark_span_push(&args->spans, entry.start, entry.end); -+ return; -+ } -+ } -+ } while (entry.start < entry.end); -+} -+ -+static void -+gc_prime_buffer(gc_mark_args_t *args) -+{ -+ if (args->spans.size > 0) { -+ gc_prime_from_spans(args); -+ } -+ else { -+ // When priming, don't fill the buffer too full since that would -+ // likely cause the stack to be used shortly after when it -+ // fills. We want to use the buffer as much as possible and so -+ // we only fill to BUFFER_HI, not BUFFER_SIZE. -+ Py_ssize_t space = BUFFER_HI - gc_mark_buffer_len(args); -+ assert(space > 0); -+ do { -+ PyObject *op = _PyObjectStack_Pop(&args->stack); -+ if (op == NULL) { -+ return; -+ } -+ gc_mark_buffer_push(op, args); -+ space--; -+ } while (space > 0); -+ } -+} -+ -+static int -+gc_propagate_alive_prefetch(gc_mark_args_t *args) -+{ -+ for (;;) { -+ Py_ssize_t buf_used = gc_mark_buffer_len(args); -+ if (buf_used <= BUFFER_LO) { -+ // The mark buffer is getting empty. If it's too empty -+ // then there will not be enough delay between issuing -+ // the prefetch and when the object is actually accessed. -+ // Prime the buffer with object pointers from the stack or -+ // from the spans, if there are any available. -+ gc_prime_buffer(args); -+ if (gc_mark_buffer_is_empty(args)) { -+ return 0; -+ } -+ } -+ PyObject *op = gc_mark_buffer_pop(args); -+ -+ if (!gc_has_bit(op, _PyGC_BITS_TRACKED)) { -+ continue; -+ } -+ -+ if (gc_is_alive(op)) { -+ continue; // already visited this object -+ } -+ -+ // Need to call tp_traverse on this object. Mark it alive so we -+ // don't traverse it a second time. -+ gc_set_alive(op); -+ -+ traverseproc traverse = Py_TYPE(op)->tp_traverse; -+ if (traverse == PyList_Type.tp_traverse) { -+ if (gc_mark_traverse_list(op, args) < 0) { -+ return -1; -+ } -+ } -+ else if (traverse == PyTuple_Type.tp_traverse) { -+ if (gc_mark_traverse_tuple(op, args) < 0) { -+ return -1; -+ } -+ } -+ else if (traverse(op, (visitproc)&gc_mark_enqueue_buffer, args) < 0) { -+ return -1; -+ } -+ } -+} -+ -+static int -+gc_propagate_alive(gc_mark_args_t *args) -+{ -+ if (args->use_prefetch) { -+ return gc_propagate_alive_prefetch(args); -+ } -+ else { -+ for (;;) { -+ PyObject *op = _PyObjectStack_Pop(&args->stack); -+ if (op == NULL) { -+ break; -+ } -+ assert(_PyObject_GC_IS_TRACKED(op)); -+ assert(gc_is_alive(op)); -+ traverseproc traverse = Py_TYPE(op)->tp_traverse; -+ if (traverse(op, (visitproc)&gc_mark_enqueue_no_buffer, args) < 0) { -+ return -1; -+ } -+ } -+ return 0; -+ } -+} -+ -+// Using tp_traverse, mark everything reachable from known root objects -+// (which must be non-garbage) as alive (_PyGC_BITS_ALIVE is set). In -+// most programs, this marks nearly all objects that are not actually -+// unreachable. -+// -+// Actually alive objects can be missed in this pass if they are alive -+// due to being referenced from an unknown root (e.g. an extension -+// module global), some tp_traverse methods are either missing or not -+// accurate, or objects that have been untracked. Objects that are only -+// reachable from the aforementioned are also missed. -+// -+// If gc.freeze() is used, this pass is disabled since it is unlikely to -+// help much. The next stages of cyclic GC will ignore objects with the -+// alive bit set. -+// -+// Returns -1 on failure (out of memory). -+static int -+gc_mark_alive_from_roots(PyInterpreterState *interp, -+ struct collection_state *state) -+{ -+#ifdef GC_DEBUG -+ // Check that all objects don't have alive bit set -+ gc_visit_heaps(interp, &validate_alive_bits, &state->base); -+#endif -+ gc_mark_args_t mark_args = { 0 }; -+ -+ // Using prefetch instructions is only a win if the set of objects being -+ // examined by the GC does not fit into CPU caches. Otherwise, using the -+ // buffer and prefetch instructions is just overhead. Using the long lived -+ // object count seems a good estimate of if things will fit in the cache. -+ // On 64-bit platforms, the minimum object size is 32 bytes. A 4MB L2 cache -+ // would hold about 130k objects. -+ mark_args.use_prefetch = interp->gc.long_lived_total > 200000; -+ -+ #define MARK_ENQUEUE(op) \ -+ if (op != NULL ) { \ -+ if (gc_mark_enqueue(op, &mark_args) < 0) { \ -+ gc_abort_mark_alive(interp, state, &mark_args); \ -+ return -1; \ -+ } \ -+ } -+ MARK_ENQUEUE(interp->sysdict); -+#ifdef GC_MARK_ALIVE_EXTRA_ROOTS -+ MARK_ENQUEUE(interp->builtins); -+ MARK_ENQUEUE(interp->dict); -+ struct types_state *types = &interp->types; -+ for (int i = 0; i < _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES; i++) { -+ MARK_ENQUEUE(types->builtins.initialized[i].tp_dict); -+ MARK_ENQUEUE(types->builtins.initialized[i].tp_subclasses); -+ } -+ for (int i = 0; i < _Py_MAX_MANAGED_STATIC_EXT_TYPES; i++) { -+ MARK_ENQUEUE(types->for_extensions.initialized[i].tp_dict); -+ MARK_ENQUEUE(types->for_extensions.initialized[i].tp_subclasses); -+ } -+#endif -+#ifdef GC_MARK_ALIVE_STACKS -+ if (gc_visit_thread_stacks_mark_alive(interp, &mark_args) < 0) { -+ gc_abort_mark_alive(interp, state, &mark_args); -+ return -1; -+ } -+#endif -+ #undef MARK_ENQUEUE -+ -+ // Use tp_traverse to find everything reachable from roots. -+ if (gc_propagate_alive(&mark_args) < 0) { -+ gc_abort_mark_alive(interp, state, &mark_args); -+ return -1; -+ } -+ -+ assert(mark_args.spans.size == 0); -+ if (mark_args.spans.stack != NULL) { -+ PyMem_Free(mark_args.spans.stack); -+ } -+ assert(mark_args.stack.head == NULL); -+ -+ return 0; -+} -+#endif // GC_ENABLE_MARK_ALIVE -+ -+ - static int - deduce_unreachable_heap(PyInterpreterState *interp, - struct collection_state *state) -@@ -709,7 +1397,7 @@ - #endif - - // Visit the thread stacks to account for any deferred references. -- gc_visit_thread_stacks(interp); -+ gc_visit_thread_stacks(interp, state); - - // Transitively mark reachable objects by clearing the - // _PyGC_BITS_UNREACHABLE flag. -@@ -828,7 +1516,8 @@ - /* copy-paste of weakrefobject.c's handle_callback() */ - PyObject *temp = PyObject_CallOneArg(callback, (PyObject *)wr); - if (temp == NULL) { -- PyErr_WriteUnraisable(callback); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "calling weakref callback %R", callback); - } - else { - Py_DECREF(temp); -@@ -1127,7 +1816,8 @@ - "collected", collected, - "uncollectable", uncollectable); - if (info == NULL) { -- PyErr_FormatUnraisable("Exception ignored on invoking gc callbacks"); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "invoking gc callbacks"); - return; - } - } -@@ -1135,7 +1825,8 @@ - PyObject *phase_obj = PyUnicode_FromString(phase); - if (phase_obj == NULL) { - Py_XDECREF(info); -- PyErr_FormatUnraisable("Exception ignored on invoking gc callbacks"); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "invoking gc callbacks"); - return; - } - -@@ -1145,7 +1836,8 @@ - Py_INCREF(cb); /* make sure cb doesn't go away */ - r = PyObject_Vectorcall(cb, stack, 2, NULL); - if (r == NULL) { -- PyErr_WriteUnraisable(cb); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "calling GC callback %R", cb); - } - else { - Py_DECREF(r); -@@ -1172,7 +1864,8 @@ - { - int count = _Py_atomic_load_int_relaxed(&gcstate->young.count); - int threshold = gcstate->young.threshold; -- if (count <= threshold || threshold == 0 || !gcstate->enabled) { -+ int gc_enabled = _Py_atomic_load_int_relaxed(&gcstate->enabled); -+ if (count <= threshold || threshold == 0 || !gc_enabled) { - return false; - } - // Avoid quadratic behavior by scaling threshold to the number of live -@@ -1245,6 +1938,25 @@ - - process_delayed_frees(interp, state); - -+ #ifdef GC_ENABLE_MARK_ALIVE -+ // If gc.freeze() was used, it seems likely that doing this "mark alive" -+ // pass will not be a performance win. Typically the majority of alive -+ // objects will be marked as frozen and will be skipped anyhow, without -+ // doing this extra work. Doing this pass also defeats one of the -+ // purposes of using freeze: avoiding writes to objects that are frozen. -+ // So, we just skip this if gc.freeze() was used. -+ if (!state->gcstate->freeze_active) { -+ // Mark objects reachable from known roots as "alive". These will -+ // be ignored for rest of the GC pass. -+ int err = gc_mark_alive_from_roots(interp, state); -+ if (err < 0) { -+ _PyEval_StartTheWorld(interp); -+ PyErr_NoMemory(); -+ return; -+ } -+ } -+ #endif -+ - // Find unreachable objects - int err = deduce_unreachable_heap(interp, state); - if (err < 0) { -@@ -1253,6 +1965,11 @@ - return; - } - -+#ifdef GC_DEBUG -+ // At this point, no object should have the alive bit set -+ gc_visit_heaps(interp, &validate_alive_bits, &state->base); -+#endif -+ - // Print debugging information. - if (interp->gc.debug & _PyGC_DEBUG_COLLECTABLE) { - PyObject *op; -@@ -1564,6 +2281,8 @@ - { - struct visitor_args args; - _PyEval_StopTheWorld(interp); -+ GCState *gcstate = get_gc_state(); -+ gcstate->freeze_active = true; - gc_visit_heaps(interp, &visit_freeze, &args); - _PyEval_StartTheWorld(interp); - } -@@ -1574,7 +2293,7 @@ - { - PyObject *op = op_from_block(block, args, true); - if (op != NULL) { -- op->ob_gc_bits &= ~_PyGC_BITS_FROZEN; -+ gc_clear_bit(op, _PyGC_BITS_FROZEN); - } - return true; - } -@@ -1584,6 +2303,8 @@ - { - struct visitor_args args; - _PyEval_StopTheWorld(interp); -+ GCState *gcstate = get_gc_state(); -+ gcstate->freeze_active = false; - gc_visit_heaps(interp, &visit_unfreeze, &args); - _PyEval_StartTheWorld(interp); - } -@@ -1620,25 +2341,21 @@ - PyGC_Enable(void) - { - GCState *gcstate = get_gc_state(); -- int old_state = gcstate->enabled; -- gcstate->enabled = 1; -- return old_state; -+ return _Py_atomic_exchange_int(&gcstate->enabled, 1); - } - - int - PyGC_Disable(void) - { - GCState *gcstate = get_gc_state(); -- int old_state = gcstate->enabled; -- gcstate->enabled = 0; -- return old_state; -+ return _Py_atomic_exchange_int(&gcstate->enabled, 0); - } - - int - PyGC_IsEnabled(void) - { - GCState *gcstate = get_gc_state(); -- return gcstate->enabled; -+ return _Py_atomic_load_int_relaxed(&gcstate->enabled); - } - - /* Public API to invoke gc.collect() from C */ -@@ -1648,7 +2365,7 @@ - PyThreadState *tstate = _PyThreadState_GET(); - GCState *gcstate = &tstate->interp->gc; - -- if (!gcstate->enabled) { -+ if (!_Py_atomic_load_int_relaxed(&gcstate->enabled)) { - return 0; - } - -@@ -1699,13 +2416,14 @@ - "gc", NULL, message, - PyList_GET_SIZE(gcstate->garbage))) - { -- PyErr_WriteUnraisable(NULL); -+ PyErr_FormatUnraisable("Exception ignored in GC shutdown"); - } - if (gcstate->debug & _PyGC_DEBUG_UNCOLLECTABLE) { - PyObject *repr = NULL, *bytes = NULL; - repr = PyObject_Repr(gcstate->garbage); - if (!repr || !(bytes = PyUnicode_EncodeFSDefault(repr))) { -- PyErr_WriteUnraisable(gcstate->garbage); -+ PyErr_FormatUnraisable("Exception ignored in GC shutdown " -+ "while formatting garbage"); - } - else { - PySys_WriteStderr( -@@ -1806,8 +2524,7 @@ - void - _Py_RunGC(PyThreadState *tstate) - { -- GCState *gcstate = get_gc_state(); -- if (!gcstate->enabled) { -+ if (!PyGC_IsEnabled()) { - return; - } - gc_collect_main(tstate, 0, _Py_GC_REASON_HEAP); -@@ -1913,9 +2630,12 @@ - #ifdef Py_DEBUG - PyObject *exc = PyErr_GetRaisedException(); - if (PyErr_WarnExplicitFormat(PyExc_ResourceWarning, "gc", 0, -- "gc", NULL, "Object of type %s is not untracked before destruction", -- ((PyObject*)op)->ob_type->tp_name)) { -- PyErr_WriteUnraisable(NULL); -+ "gc", NULL, -+ "Object of type %s is not untracked " -+ "before destruction", -+ Py_TYPE(op)->tp_name)) -+ { -+ PyErr_FormatUnraisable("Exception ignored on object deallocation"); - } - PyErr_SetRaisedException(exc); - #endif -diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h -index 94343f95322..f02e13f5e3f 100644 ---- a/Python/generated_cases.c.h -+++ b/Python/generated_cases.c.h -@@ -8,13 +8,26 @@ - #endif - #define TIER_ONE 1 - -+#ifndef Py_TAIL_CALL_INTERP -+#if !USE_COMPUTED_GOTOS -+ dispatch_opcode: -+ switch (opcode) -+#endif -+ { -+#endif /* Py_TAIL_CALL_INTERP */ -+ /* BEGIN INSTRUCTIONS */ -+ - - TARGET(BINARY_OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = BINARY_OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; -- next_instr += 2; -+ next_instr += 6; - INSTRUCTION_STATS(BINARY_OP); -- PREDICTED(BINARY_OP); -- _Py_CODEUNIT* const this_instr = next_instr - 2; -+ PREDICTED_BINARY_OP:; -+ _Py_CODEUNIT* const this_instr = next_instr - 6; - (void)this_instr; - _PyStackRef lhs; - _PyStackRef rhs; -@@ -37,8 +50,9 @@ - ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ - assert(NB_ADD <= oparg); -- assert(oparg <= NB_INPLACE_XOR); -+ assert(oparg <= NB_OPARG_LAST); - } -+ /* Skip 4 cache entries */ - // _BINARY_OP - { - PyObject *lhs_o = PyStackRef_AsPyObjectBorrow(lhs); -@@ -49,7 +63,9 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(lhs); - PyStackRef_CLOSE(rhs); -- if (res_o == NULL) goto pop_2_error; -+ if (res_o == NULL) { -+ JUMP_TO_LABEL(pop_2_error); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - } - stack_pointer[-2] = res; -@@ -59,10 +75,16 @@ - } - - TARGET(BINARY_OP_ADD_FLOAT) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = BINARY_OP_ADD_FLOAT; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; -- next_instr += 2; -+ next_instr += 6; - INSTRUCTION_STATS(BINARY_OP_ADD_FLOAT); -- static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); -+ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); - _PyStackRef left; - _PyStackRef right; - _PyStackRef res; -@@ -72,20 +94,32 @@ - left = stack_pointer[-2]; - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -- DEOPT_IF(!PyFloat_CheckExact(left_o), BINARY_OP); -- DEOPT_IF(!PyFloat_CheckExact(right_o), BINARY_OP); -+ if (!PyFloat_CheckExact(left_o)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } -+ if (!PyFloat_CheckExact(right_o)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } - } -- /* Skip 1 cache entry */ -+ /* Skip 5 cache entries */ - // _BINARY_OP_ADD_FLOAT - { - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(PyFloat_CheckExact(left_o)); -+ assert(PyFloat_CheckExact(right_o)); - STAT_INC(BINARY_OP, hit); - double dres = - ((PyFloatObject *)left_o)->ob_fval + - ((PyFloatObject *)right_o)->ob_fval; - PyObject *res_o = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); -- if (res_o == NULL) goto pop_2_error; -+ if (res_o == NULL) { -+ JUMP_TO_LABEL(pop_2_error); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - } - stack_pointer[-2] = res; -@@ -95,10 +129,16 @@ - } - - TARGET(BINARY_OP_ADD_INT) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = BINARY_OP_ADD_INT; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; -- next_instr += 2; -+ next_instr += 6; - INSTRUCTION_STATS(BINARY_OP_ADD_INT); -- static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); -+ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); - _PyStackRef left; - _PyStackRef right; - _PyStackRef res; -@@ -108,19 +148,31 @@ - left = stack_pointer[-2]; - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -- DEOPT_IF(!PyLong_CheckExact(left_o), BINARY_OP); -- DEOPT_IF(!PyLong_CheckExact(right_o), BINARY_OP); -+ if (!PyLong_CheckExact(left_o)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } -+ if (!PyLong_CheckExact(right_o)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } - } -- /* Skip 1 cache entry */ -+ /* Skip 5 cache entries */ - // _BINARY_OP_ADD_INT - { - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(PyLong_CheckExact(left_o)); -+ assert(PyLong_CheckExact(right_o)); - STAT_INC(BINARY_OP, hit); - PyObject *res_o = _PyLong_Add((PyLongObject *)left_o, (PyLongObject *)right_o); - PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); -- if (res_o == NULL) goto pop_2_error; -+ if (res_o == NULL) { -+ JUMP_TO_LABEL(pop_2_error); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - } - stack_pointer[-2] = res; -@@ -130,10 +182,16 @@ - } - - TARGET(BINARY_OP_ADD_UNICODE) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = BINARY_OP_ADD_UNICODE; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; -- next_instr += 2; -+ next_instr += 6; - INSTRUCTION_STATS(BINARY_OP_ADD_UNICODE); -- static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); -+ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); - _PyStackRef left; - _PyStackRef right; - _PyStackRef res; -@@ -143,19 +201,87 @@ - left = stack_pointer[-2]; - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -- DEOPT_IF(!PyUnicode_CheckExact(left_o), BINARY_OP); -- DEOPT_IF(!PyUnicode_CheckExact(right_o), BINARY_OP); -+ if (!PyUnicode_CheckExact(left_o)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } -+ if (!PyUnicode_CheckExact(right_o)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } - } -- /* Skip 1 cache entry */ -+ /* Skip 5 cache entries */ - // _BINARY_OP_ADD_UNICODE - { - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(PyUnicode_CheckExact(left_o)); -+ assert(PyUnicode_CheckExact(right_o)); - STAT_INC(BINARY_OP, hit); - PyObject *res_o = PyUnicode_Concat(left_o, right_o); -- PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); -- if (res_o == NULL) goto pop_2_error; -+ PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); -+ if (res_o == NULL) { -+ JUMP_TO_LABEL(pop_2_error); -+ } -+ res = PyStackRef_FromPyObjectSteal(res_o); -+ } -+ stack_pointer[-2] = res; -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ DISPATCH(); -+ } -+ -+ TARGET(BINARY_OP_EXTEND) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = BINARY_OP_EXTEND; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; -+ next_instr += 6; -+ INSTRUCTION_STATS(BINARY_OP_EXTEND); -+ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); -+ _PyStackRef left; -+ _PyStackRef right; -+ _PyStackRef res; -+ /* Skip 1 cache entry */ -+ // _GUARD_BINARY_OP_EXTEND -+ { -+ right = stack_pointer[-1]; -+ left = stack_pointer[-2]; -+ PyObject *descr = read_obj(&this_instr[2].cache); -+ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); -+ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ _PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr; -+ assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5); -+ assert(d && d->guard); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ int res = d->guard(left_o, right_o); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (!res) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } -+ } -+ /* Skip -4 cache entry */ -+ // _BINARY_OP_EXTEND -+ { -+ PyObject *descr = read_obj(&this_instr[2].cache); -+ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); -+ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5); -+ _PyBinaryOpSpecializationDescr *d = (_PyBinaryOpSpecializationDescr*)descr; -+ STAT_INC(BINARY_OP, hit); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyObject *res_o = d->action(left_o, right_o); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ PyStackRef_CLOSE(left); -+ PyStackRef_CLOSE(right); - res = PyStackRef_FromPyObjectSteal(res_o); - } - stack_pointer[-2] = res; -@@ -165,10 +291,16 @@ - } - - TARGET(BINARY_OP_INPLACE_ADD_UNICODE) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = BINARY_OP_INPLACE_ADD_UNICODE; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; -- next_instr += 2; -+ next_instr += 6; - INSTRUCTION_STATS(BINARY_OP_INPLACE_ADD_UNICODE); -- static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); -+ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); - _PyStackRef left; - _PyStackRef right; - // _GUARD_BOTH_UNICODE -@@ -177,14 +309,24 @@ - left = stack_pointer[-2]; - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -- DEOPT_IF(!PyUnicode_CheckExact(left_o), BINARY_OP); -- DEOPT_IF(!PyUnicode_CheckExact(right_o), BINARY_OP); -+ if (!PyUnicode_CheckExact(left_o)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } -+ if (!PyUnicode_CheckExact(right_o)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } - } -- /* Skip 1 cache entry */ -+ /* Skip 5 cache entries */ - // _BINARY_OP_INPLACE_ADD_UNICODE - { - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(PyUnicode_CheckExact(left_o)); -+ assert(PyUnicode_CheckExact(right_o)); - int next_oparg; - #if TIER_ONE - assert(next_instr->op.code == STORE_FAST); -@@ -193,7 +335,11 @@ - next_oparg = CURRENT_OPERAND0(); - #endif - _PyStackRef *target_local = &GETLOCAL(next_oparg); -- DEOPT_IF(PyStackRef_AsPyObjectBorrow(*target_local) != left_o, BINARY_OP); -+ if (PyStackRef_AsPyObjectBorrow(*target_local) != left_o) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } - STAT_INC(BINARY_OP, hit); - /* Handle `left = left + right` or `left += right` for str. - * -@@ -207,12 +353,14 @@ - * that the string is safe to mutate. - */ - assert(Py_REFCNT(left_o) >= 2); -- PyStackRef_CLOSE(left); -- PyObject *temp = PyStackRef_AsPyObjectBorrow(*target_local); -+ PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); -+ PyObject *temp = PyStackRef_AsPyObjectSteal(*target_local); - PyUnicode_Append(&temp, right_o); - *target_local = PyStackRef_FromPyObjectSteal(temp); - PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); -- if (PyStackRef_IsNull(*target_local)) goto pop_2_error; -+ if (PyStackRef_IsNull(*target_local)) { -+ JUMP_TO_LABEL(pop_2_error); -+ } - #if TIER_ONE - // The STORE_FAST is already done. This is done here in tier one, - // and during trace projection in tier two: -@@ -226,10 +374,16 @@ - } - - TARGET(BINARY_OP_MULTIPLY_FLOAT) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = BINARY_OP_MULTIPLY_FLOAT; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; -- next_instr += 2; -+ next_instr += 6; - INSTRUCTION_STATS(BINARY_OP_MULTIPLY_FLOAT); -- static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); -+ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); - _PyStackRef left; - _PyStackRef right; - _PyStackRef res; -@@ -239,20 +393,32 @@ - left = stack_pointer[-2]; - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -- DEOPT_IF(!PyFloat_CheckExact(left_o), BINARY_OP); -- DEOPT_IF(!PyFloat_CheckExact(right_o), BINARY_OP); -+ if (!PyFloat_CheckExact(left_o)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } -+ if (!PyFloat_CheckExact(right_o)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } - } -- /* Skip 1 cache entry */ -+ /* Skip 5 cache entries */ - // _BINARY_OP_MULTIPLY_FLOAT - { - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(PyFloat_CheckExact(left_o)); -+ assert(PyFloat_CheckExact(right_o)); - STAT_INC(BINARY_OP, hit); - double dres = - ((PyFloatObject *)left_o)->ob_fval * - ((PyFloatObject *)right_o)->ob_fval; - PyObject *res_o = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); -- if (res_o == NULL) goto pop_2_error; -+ if (res_o == NULL) { -+ JUMP_TO_LABEL(pop_2_error); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - } - stack_pointer[-2] = res; -@@ -262,10 +428,16 @@ - } - - TARGET(BINARY_OP_MULTIPLY_INT) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = BINARY_OP_MULTIPLY_INT; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; -- next_instr += 2; -+ next_instr += 6; - INSTRUCTION_STATS(BINARY_OP_MULTIPLY_INT); -- static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); -+ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); - _PyStackRef left; - _PyStackRef right; - _PyStackRef res; -@@ -275,187 +447,31 @@ - left = stack_pointer[-2]; - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -- DEOPT_IF(!PyLong_CheckExact(left_o), BINARY_OP); -- DEOPT_IF(!PyLong_CheckExact(right_o), BINARY_OP); -+ if (!PyLong_CheckExact(left_o)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } -+ if (!PyLong_CheckExact(right_o)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } - } -- /* Skip 1 cache entry */ -+ /* Skip 5 cache entries */ - // _BINARY_OP_MULTIPLY_INT - { - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(PyLong_CheckExact(left_o)); -+ assert(PyLong_CheckExact(right_o)); - STAT_INC(BINARY_OP, hit); - PyObject *res_o = _PyLong_Multiply((PyLongObject *)left_o, (PyLongObject *)right_o); - PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); -- if (res_o == NULL) goto pop_2_error; -- res = PyStackRef_FromPyObjectSteal(res_o); -- } -- stack_pointer[-2] = res; -- stack_pointer += -1; -- assert(WITHIN_STACK_BOUNDS()); -- DISPATCH(); -- } -- -- TARGET(BINARY_OP_SUBTRACT_FLOAT) { -- frame->instr_ptr = next_instr; -- next_instr += 2; -- INSTRUCTION_STATS(BINARY_OP_SUBTRACT_FLOAT); -- static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); -- _PyStackRef left; -- _PyStackRef right; -- _PyStackRef res; -- // _GUARD_BOTH_FLOAT -- { -- right = stack_pointer[-1]; -- left = stack_pointer[-2]; -- PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); -- PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -- DEOPT_IF(!PyFloat_CheckExact(left_o), BINARY_OP); -- DEOPT_IF(!PyFloat_CheckExact(right_o), BINARY_OP); -- } -- /* Skip 1 cache entry */ -- // _BINARY_OP_SUBTRACT_FLOAT -- { -- PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); -- PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -- STAT_INC(BINARY_OP, hit); -- double dres = -- ((PyFloatObject *)left_o)->ob_fval - -- ((PyFloatObject *)right_o)->ob_fval; -- PyObject *res_o = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); -- if (res_o == NULL) goto pop_2_error; -- res = PyStackRef_FromPyObjectSteal(res_o); -- } -- stack_pointer[-2] = res; -- stack_pointer += -1; -- assert(WITHIN_STACK_BOUNDS()); -- DISPATCH(); -- } -- -- TARGET(BINARY_OP_SUBTRACT_INT) { -- frame->instr_ptr = next_instr; -- next_instr += 2; -- INSTRUCTION_STATS(BINARY_OP_SUBTRACT_INT); -- static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); -- _PyStackRef left; -- _PyStackRef right; -- _PyStackRef res; -- // _GUARD_BOTH_INT -- { -- right = stack_pointer[-1]; -- left = stack_pointer[-2]; -- PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); -- PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -- DEOPT_IF(!PyLong_CheckExact(left_o), BINARY_OP); -- DEOPT_IF(!PyLong_CheckExact(right_o), BINARY_OP); -- } -- /* Skip 1 cache entry */ -- // _BINARY_OP_SUBTRACT_INT -- { -- PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); -- PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -- STAT_INC(BINARY_OP, hit); -- PyObject *res_o = _PyLong_Subtract((PyLongObject *)left_o, (PyLongObject *)right_o); -- PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); -- PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); -- if (res_o == NULL) goto pop_2_error; -- res = PyStackRef_FromPyObjectSteal(res_o); -- } -- stack_pointer[-2] = res; -- stack_pointer += -1; -- assert(WITHIN_STACK_BOUNDS()); -- DISPATCH(); -- } -- -- TARGET(BINARY_SLICE) { -- frame->instr_ptr = next_instr; -- next_instr += 1; -- INSTRUCTION_STATS(BINARY_SLICE); -- _PyStackRef container; -- _PyStackRef start; -- _PyStackRef stop; -- _PyStackRef res; -- // _SPECIALIZE_BINARY_SLICE -- { -- // Placeholder until we implement BINARY_SLICE specialization -- #if ENABLE_SPECIALIZATION -- OPCODE_DEFERRED_INC(BINARY_SLICE); -- #endif /* ENABLE_SPECIALIZATION */ -- } -- // _BINARY_SLICE -- { -- stop = stack_pointer[-1]; -- start = stack_pointer[-2]; -- container = stack_pointer[-3]; -- _PyFrame_SetStackPointer(frame, stack_pointer); -- PyObject *slice = _PyBuildSlice_ConsumeRefs(PyStackRef_AsPyObjectSteal(start), -- PyStackRef_AsPyObjectSteal(stop)); -- stack_pointer = _PyFrame_GetStackPointer(frame); -- PyObject *res_o; -- // Can't use ERROR_IF() here, because we haven't -- // DECREF'ed container yet, and we still own slice. -- if (slice == NULL) { -- res_o = NULL; -- } -- else { -- stack_pointer += -2; -- assert(WITHIN_STACK_BOUNDS()); -- _PyFrame_SetStackPointer(frame, stack_pointer); -- res_o = PyObject_GetItem(PyStackRef_AsPyObjectBorrow(container), slice); -- stack_pointer = _PyFrame_GetStackPointer(frame); -- Py_DECREF(slice); -- stack_pointer += 2; -- assert(WITHIN_STACK_BOUNDS()); -- } -- PyStackRef_CLOSE(container); -- if (res_o == NULL) goto pop_3_error; -- res = PyStackRef_FromPyObjectSteal(res_o); -- } -- stack_pointer[-3] = res; -- stack_pointer += -2; -- assert(WITHIN_STACK_BOUNDS()); -- DISPATCH(); -- } -- -- TARGET(BINARY_SUBSCR) { -- frame->instr_ptr = next_instr; -- next_instr += 2; -- INSTRUCTION_STATS(BINARY_SUBSCR); -- PREDICTED(BINARY_SUBSCR); -- _Py_CODEUNIT* const this_instr = next_instr - 2; -- (void)this_instr; -- _PyStackRef container; -- _PyStackRef sub; -- _PyStackRef res; -- // _SPECIALIZE_BINARY_SUBSCR -- { -- sub = stack_pointer[-1]; -- container = stack_pointer[-2]; -- uint16_t counter = read_u16(&this_instr[1].cache); -- (void)counter; -- #if ENABLE_SPECIALIZATION_FT -- assert(frame->stackpointer == NULL); -- if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { -- next_instr = this_instr; -- _PyFrame_SetStackPointer(frame, stack_pointer); -- _Py_Specialize_BinarySubscr(container, sub, next_instr); -- stack_pointer = _PyFrame_GetStackPointer(frame); -- DISPATCH_SAME_OPARG(); -+ if (res_o == NULL) { -+ JUMP_TO_LABEL(pop_2_error); - } -- OPCODE_DEFERRED_INC(BINARY_SUBSCR); -- ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); -- #endif /* ENABLE_SPECIALIZATION_FT */ -- } -- // _BINARY_SUBSCR -- { -- PyObject *container_o = PyStackRef_AsPyObjectBorrow(container); -- PyObject *sub_o = PyStackRef_AsPyObjectBorrow(sub); -- _PyFrame_SetStackPointer(frame, stack_pointer); -- PyObject *res_o = PyObject_GetItem(container_o, sub_o); -- stack_pointer = _PyFrame_GetStackPointer(frame); -- PyStackRef_CLOSE(container); -- PyStackRef_CLOSE(sub); -- if (res_o == NULL) goto pop_2_error; - res = PyStackRef_FromPyObjectSteal(res_o); - } - stack_pointer[-2] = res; -@@ -464,21 +480,31 @@ - DISPATCH(); - } - -- TARGET(BINARY_SUBSCR_DICT) { -+ TARGET(BINARY_OP_SUBSCR_DICT) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = BINARY_OP_SUBSCR_DICT; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; -- next_instr += 2; -- INSTRUCTION_STATS(BINARY_SUBSCR_DICT); -- static_assert(INLINE_CACHE_ENTRIES_BINARY_SUBSCR == 1, "incorrect cache size"); -+ next_instr += 6; -+ INSTRUCTION_STATS(BINARY_OP_SUBSCR_DICT); -+ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); - _PyStackRef dict_st; - _PyStackRef sub_st; - _PyStackRef res; -- /* Skip 1 cache entry */ -+ /* Skip 5 cache entries */ - sub_st = stack_pointer[-1]; - dict_st = stack_pointer[-2]; - PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); - PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st); -- DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); -- STAT_INC(BINARY_SUBSCR, hit); -+ if (!PyDict_CheckExact(dict)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } -+ STAT_INC(BINARY_OP, hit); - PyObject *res_o; - _PyFrame_SetStackPointer(frame, stack_pointer); - int rc = PyDict_GetItemRef(dict, sub, &res_o); -@@ -490,7 +516,9 @@ - } - PyStackRef_CLOSE(dict_st); - PyStackRef_CLOSE(sub_st); -- if (rc <= 0) goto pop_2_error; -+ if (rc <= 0) { -+ JUMP_TO_LABEL(pop_2_error); -+ } - // not found or error - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-2] = res; -@@ -499,45 +527,70 @@ - DISPATCH(); - } - -- TARGET(BINARY_SUBSCR_GETITEM) { -+ TARGET(BINARY_OP_SUBSCR_GETITEM) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = BINARY_OP_SUBSCR_GETITEM; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; -- next_instr += 2; -- INSTRUCTION_STATS(BINARY_SUBSCR_GETITEM); -- static_assert(INLINE_CACHE_ENTRIES_BINARY_SUBSCR == 1, "incorrect cache size"); -+ next_instr += 6; -+ INSTRUCTION_STATS(BINARY_OP_SUBSCR_GETITEM); -+ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); - _PyStackRef container; -+ _PyStackRef getitem; - _PyStackRef sub; - _PyInterpreterFrame *new_frame; -- /* Skip 1 cache entry */ -+ /* Skip 5 cache entries */ - // _CHECK_PEP_523 - { -- DEOPT_IF(tstate->interp->eval_frame, BINARY_SUBSCR); -+ if (tstate->interp->eval_frame) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } - } -- // _BINARY_SUBSCR_CHECK_FUNC -+ // _BINARY_OP_SUBSCR_CHECK_FUNC - { - container = stack_pointer[-2]; - PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(container)); -- DEOPT_IF(!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), BINARY_SUBSCR); -+ if (!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } - PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; -- PyObject *getitem = ht->_spec_cache.getitem; -- DEOPT_IF(getitem == NULL, BINARY_SUBSCR); -- assert(PyFunction_Check(getitem)); -- uint32_t cached_version = ht->_spec_cache.getitem_version; -- DEOPT_IF(((PyFunctionObject *)getitem)->func_version != cached_version, BINARY_SUBSCR); -- PyCodeObject *code = (PyCodeObject *)PyFunction_GET_CODE(getitem); -+ PyObject *getitem_o = FT_ATOMIC_LOAD_PTR_ACQUIRE(ht->_spec_cache.getitem); -+ if (getitem_o == NULL) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } -+ assert(PyFunction_Check(getitem_o)); -+ uint32_t cached_version = FT_ATOMIC_LOAD_UINT32_RELAXED(ht->_spec_cache.getitem_version); -+ if (((PyFunctionObject *)getitem_o)->func_version != cached_version) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } -+ PyCodeObject *code = (PyCodeObject *)PyFunction_GET_CODE(getitem_o); - assert(code->co_argcount == 2); -- DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), BINARY_SUBSCR); -- STAT_INC(BINARY_SUBSCR, hit); -+ if (!_PyThreadState_HasStackSpace(tstate, code->co_framesize)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } -+ getitem = PyStackRef_FromPyObjectNew(getitem_o); -+ STAT_INC(BINARY_OP, hit); - } -- // _BINARY_SUBSCR_INIT_CALL -+ // _BINARY_OP_SUBSCR_INIT_CALL - { - sub = stack_pointer[-1]; -- PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(container)); -- PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; -- PyObject *getitem = ht->_spec_cache.getitem; -- new_frame = _PyFrame_PushUnchecked(tstate, PyStackRef_FromPyObjectNew(getitem), 2, frame); -+ new_frame = _PyFrame_PushUnchecked(tstate, getitem, 2, frame); - new_frame->localsplus[0] = container; - new_frame->localsplus[1] = sub; -- frame->return_offset = 2 ; -+ frame->return_offset = 6 ; - } - // _PUSH_FRAME - { -@@ -559,122 +612,377 @@ - DISPATCH(); - } - -- TARGET(BINARY_SUBSCR_LIST_INT) { -+ TARGET(BINARY_OP_SUBSCR_LIST_INT) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = BINARY_OP_SUBSCR_LIST_INT; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; -- next_instr += 2; -- INSTRUCTION_STATS(BINARY_SUBSCR_LIST_INT); -- static_assert(INLINE_CACHE_ENTRIES_BINARY_SUBSCR == 1, "incorrect cache size"); -+ next_instr += 6; -+ INSTRUCTION_STATS(BINARY_OP_SUBSCR_LIST_INT); -+ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); - _PyStackRef list_st; - _PyStackRef sub_st; - _PyStackRef res; -- /* Skip 1 cache entry */ -+ /* Skip 5 cache entries */ - sub_st = stack_pointer[-1]; - list_st = stack_pointer[-2]; - PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); - PyObject *list = PyStackRef_AsPyObjectBorrow(list_st); -- DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); -- DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); -+ if (!PyLong_CheckExact(sub)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } -+ if (!PyList_CheckExact(list)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } - // Deopt unless 0 <= sub < PyList_Size(list) -- DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); -+ if (!_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } - Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; - #ifdef Py_GIL_DISABLED - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = _PyList_GetItemRef((PyListObject*)list, index); - stack_pointer = _PyFrame_GetStackPointer(frame); -- DEOPT_IF(res_o == NULL, BINARY_SUBSCR); -- STAT_INC(BINARY_SUBSCR, hit); -+ if (res_o == NULL) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } -+ STAT_INC(BINARY_OP, hit); - #else -- DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR); -- STAT_INC(BINARY_SUBSCR, hit); -+ if (index >= PyList_GET_SIZE(list)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } -+ STAT_INC(BINARY_OP, hit); - PyObject *res_o = PyList_GET_ITEM(list, index); - assert(res_o != NULL); - Py_INCREF(res_o); - #endif - PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(list_st); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - res = PyStackRef_FromPyObjectSteal(res_o); -- stack_pointer[-2] = res; -- stack_pointer += -1; -+ stack_pointer[0] = res; -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - -- TARGET(BINARY_SUBSCR_STR_INT) { -+ TARGET(BINARY_OP_SUBSCR_STR_INT) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = BINARY_OP_SUBSCR_STR_INT; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; -- next_instr += 2; -- INSTRUCTION_STATS(BINARY_SUBSCR_STR_INT); -- static_assert(INLINE_CACHE_ENTRIES_BINARY_SUBSCR == 1, "incorrect cache size"); -+ next_instr += 6; -+ INSTRUCTION_STATS(BINARY_OP_SUBSCR_STR_INT); -+ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); - _PyStackRef str_st; - _PyStackRef sub_st; - _PyStackRef res; -- /* Skip 1 cache entry */ -+ /* Skip 5 cache entries */ - sub_st = stack_pointer[-1]; - str_st = stack_pointer[-2]; - PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); - PyObject *str = PyStackRef_AsPyObjectBorrow(str_st); -- DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); -- DEOPT_IF(!PyUnicode_CheckExact(str), BINARY_SUBSCR); -- DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); -+ if (!PyLong_CheckExact(sub)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } -+ if (!PyUnicode_CheckExact(str)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } -+ if (!_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } - Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; -- DEOPT_IF(PyUnicode_GET_LENGTH(str) <= index, BINARY_SUBSCR); -+ if (PyUnicode_GET_LENGTH(str) <= index) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } - // Specialize for reading an ASCII character from any string: - Py_UCS4 c = PyUnicode_READ_CHAR(str, index); -- DEOPT_IF(Py_ARRAY_LENGTH(_Py_SINGLETON(strings).ascii) <= c, BINARY_SUBSCR); -- STAT_INC(BINARY_SUBSCR, hit); -+ if (Py_ARRAY_LENGTH(_Py_SINGLETON(strings).ascii) <= c) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } -+ STAT_INC(BINARY_OP, hit); - PyObject *res_o = (PyObject*)&_Py_SINGLETON(strings).ascii[c]; - PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(str_st); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - res = PyStackRef_FromPyObjectSteal(res_o); -- stack_pointer[-2] = res; -- stack_pointer += -1; -+ stack_pointer[0] = res; -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - -- TARGET(BINARY_SUBSCR_TUPLE_INT) { -+ TARGET(BINARY_OP_SUBSCR_TUPLE_INT) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = BINARY_OP_SUBSCR_TUPLE_INT; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; -- next_instr += 2; -- INSTRUCTION_STATS(BINARY_SUBSCR_TUPLE_INT); -- static_assert(INLINE_CACHE_ENTRIES_BINARY_SUBSCR == 1, "incorrect cache size"); -+ next_instr += 6; -+ INSTRUCTION_STATS(BINARY_OP_SUBSCR_TUPLE_INT); -+ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); - _PyStackRef tuple_st; - _PyStackRef sub_st; - _PyStackRef res; -- /* Skip 1 cache entry */ -+ /* Skip 5 cache entries */ - sub_st = stack_pointer[-1]; - tuple_st = stack_pointer[-2]; - PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); - PyObject *tuple = PyStackRef_AsPyObjectBorrow(tuple_st); -- DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); -- DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); -+ if (!PyLong_CheckExact(sub)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } -+ if (!PyTuple_CheckExact(tuple)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } - // Deopt unless 0 <= sub < PyTuple_Size(list) -- DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); -+ if (!_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } - Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; -- DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR); -- STAT_INC(BINARY_SUBSCR, hit); -+ if (index >= PyTuple_GET_SIZE(tuple)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } -+ STAT_INC(BINARY_OP, hit); - PyObject *res_o = PyTuple_GET_ITEM(tuple, index); - assert(res_o != NULL); - Py_INCREF(res_o); - PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(tuple_st); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - res = PyStackRef_FromPyObjectSteal(res_o); -+ stack_pointer[0] = res; -+ stack_pointer += 1; -+ assert(WITHIN_STACK_BOUNDS()); -+ DISPATCH(); -+ } -+ -+ TARGET(BINARY_OP_SUBTRACT_FLOAT) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = BINARY_OP_SUBTRACT_FLOAT; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; -+ next_instr += 6; -+ INSTRUCTION_STATS(BINARY_OP_SUBTRACT_FLOAT); -+ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); -+ _PyStackRef left; -+ _PyStackRef right; -+ _PyStackRef res; -+ // _GUARD_BOTH_FLOAT -+ { -+ right = stack_pointer[-1]; -+ left = stack_pointer[-2]; -+ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); -+ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ if (!PyFloat_CheckExact(left_o)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } -+ if (!PyFloat_CheckExact(right_o)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } -+ } -+ /* Skip 5 cache entries */ -+ // _BINARY_OP_SUBTRACT_FLOAT -+ { -+ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); -+ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(PyFloat_CheckExact(left_o)); -+ assert(PyFloat_CheckExact(right_o)); -+ STAT_INC(BINARY_OP, hit); -+ double dres = -+ ((PyFloatObject *)left_o)->ob_fval - -+ ((PyFloatObject *)right_o)->ob_fval; -+ PyObject *res_o = _PyFloat_FromDouble_ConsumeInputs(left, right, dres); -+ if (res_o == NULL) { -+ JUMP_TO_LABEL(pop_2_error); -+ } -+ res = PyStackRef_FromPyObjectSteal(res_o); -+ } -+ stack_pointer[-2] = res; -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ DISPATCH(); -+ } -+ -+ TARGET(BINARY_OP_SUBTRACT_INT) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = BINARY_OP_SUBTRACT_INT; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; -+ next_instr += 6; -+ INSTRUCTION_STATS(BINARY_OP_SUBTRACT_INT); -+ static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5, "incorrect cache size"); -+ _PyStackRef left; -+ _PyStackRef right; -+ _PyStackRef res; -+ // _GUARD_BOTH_INT -+ { -+ right = stack_pointer[-1]; -+ left = stack_pointer[-2]; -+ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); -+ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ if (!PyLong_CheckExact(left_o)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } -+ if (!PyLong_CheckExact(right_o)) { -+ UPDATE_MISS_STATS(BINARY_OP); -+ assert(_PyOpcode_Deopt[opcode] == (BINARY_OP)); -+ JUMP_TO_PREDICTED(BINARY_OP); -+ } -+ } -+ /* Skip 5 cache entries */ -+ // _BINARY_OP_SUBTRACT_INT -+ { -+ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); -+ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -+ assert(PyLong_CheckExact(left_o)); -+ assert(PyLong_CheckExact(right_o)); -+ STAT_INC(BINARY_OP, hit); -+ PyObject *res_o = _PyLong_Subtract((PyLongObject *)left_o, (PyLongObject *)right_o); -+ PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc); -+ PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc); -+ if (res_o == NULL) { -+ JUMP_TO_LABEL(pop_2_error); -+ } -+ res = PyStackRef_FromPyObjectSteal(res_o); -+ } - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - -+ TARGET(BINARY_SLICE) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = BINARY_SLICE; -+ (void)(opcode); -+ #endif -+ frame->instr_ptr = next_instr; -+ next_instr += 1; -+ INSTRUCTION_STATS(BINARY_SLICE); -+ _PyStackRef container; -+ _PyStackRef start; -+ _PyStackRef stop; -+ _PyStackRef res; -+ // _SPECIALIZE_BINARY_SLICE -+ { -+ // Placeholder until we implement BINARY_SLICE specialization -+ #if ENABLE_SPECIALIZATION -+ OPCODE_DEFERRED_INC(BINARY_SLICE); -+ #endif /* ENABLE_SPECIALIZATION */ -+ } -+ // _BINARY_SLICE -+ { -+ stop = stack_pointer[-1]; -+ start = stack_pointer[-2]; -+ container = stack_pointer[-3]; -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyObject *slice = _PyBuildSlice_ConsumeRefs(PyStackRef_AsPyObjectSteal(start), -+ PyStackRef_AsPyObjectSteal(stop)); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ PyObject *res_o; -+ // Can't use ERROR_IF() here, because we haven't -+ // DECREF'ed container yet, and we still own slice. -+ if (slice == NULL) { -+ res_o = NULL; -+ } -+ else { -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ res_o = PyObject_GetItem(PyStackRef_AsPyObjectBorrow(container), slice); -+ Py_DECREF(slice); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += 2; -+ assert(WITHIN_STACK_BOUNDS()); -+ } -+ stack_pointer += -3; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(container); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (res_o == NULL) { -+ JUMP_TO_LABEL(error); -+ } -+ res = PyStackRef_FromPyObjectSteal(res_o); -+ } -+ stack_pointer[0] = res; -+ stack_pointer += 1; -+ assert(WITHIN_STACK_BOUNDS()); -+ DISPATCH(); -+ } -+ - TARGET(BUILD_LIST) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = BUILD_LIST; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(BUILD_LIST); - _PyStackRef *values; - _PyStackRef list; - values = &stack_pointer[-oparg]; -- PyObject *list_o = _PyList_FromStackRefSteal(values, oparg); -+ PyObject *list_o = _PyList_FromStackRefStealOnSuccess(values, oparg); - if (list_o == NULL) { -- stack_pointer += -oparg; -- assert(WITHIN_STACK_BOUNDS()); -- goto error; -+ JUMP_TO_LABEL(error); - } - list = PyStackRef_FromPyObjectSteal(list_o); - stack_pointer[-oparg] = list; -@@ -684,6 +992,10 @@ - } - - TARGET(BUILD_MAP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = BUILD_MAP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(BUILD_MAP); -@@ -695,11 +1007,9 @@ - for (int _i = oparg*2; --_i >= 0;) { - PyStackRef_CLOSE(values[_i]); - } -- { -- stack_pointer += -oparg*2; -- assert(WITHIN_STACK_BOUNDS()); -- goto error; -- } -+ stack_pointer += -oparg*2; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_LABEL(error); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *map_o = _PyDict_FromItems( -@@ -714,7 +1024,7 @@ - if (map_o == NULL) { - stack_pointer += -oparg*2; - assert(WITHIN_STACK_BOUNDS()); -- goto error; -+ JUMP_TO_LABEL(error); - } - map = PyStackRef_FromPyObjectSteal(map_o); - stack_pointer[-oparg*2] = map; -@@ -724,6 +1034,10 @@ - } - - TARGET(BUILD_SET) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = BUILD_SET; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(BUILD_SET); -@@ -737,11 +1051,9 @@ - for (int _i = oparg; --_i >= 0;) { - PyStackRef_CLOSE(values[_i]); - } -- { -- stack_pointer += -oparg; -- assert(WITHIN_STACK_BOUNDS()); -- goto error; -- } -+ stack_pointer += -oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_LABEL(error); - } - int err = 0; - for (int i = 0; i < oparg; i++) { -@@ -750,15 +1062,17 @@ - err = PySet_Add(set_o, PyStackRef_AsPyObjectBorrow(values[i])); - stack_pointer = _PyFrame_GetStackPointer(frame); - } -- PyStackRef_CLOSE(values[i]); -+ } -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(values[_i]); - } - if (err != 0) { -+ stack_pointer += -oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - Py_DECREF(set_o); -- { -- stack_pointer += -oparg; -- assert(WITHIN_STACK_BOUNDS()); -- goto error; -- } -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ JUMP_TO_LABEL(error); - } - set = PyStackRef_FromPyObjectSteal(set_o); - stack_pointer[-oparg] = set; -@@ -768,36 +1082,40 @@ - } - - TARGET(BUILD_SLICE) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = BUILD_SLICE; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(BUILD_SLICE); -- _PyStackRef start; -- _PyStackRef stop; -- _PyStackRef step = PyStackRef_NULL; -+ _PyStackRef *args; - _PyStackRef slice; -- if (oparg == 3) { step = stack_pointer[-((oparg == 3) ? 1 : 0)]; } -- stop = stack_pointer[-1 - ((oparg == 3) ? 1 : 0)]; -- start = stack_pointer[-2 - ((oparg == 3) ? 1 : 0)]; -- PyObject *start_o = PyStackRef_AsPyObjectBorrow(start); -- PyObject *stop_o = PyStackRef_AsPyObjectBorrow(stop); -- PyObject *step_o = PyStackRef_AsPyObjectBorrow(step); -+ args = &stack_pointer[-oparg]; -+ PyObject *start_o = PyStackRef_AsPyObjectBorrow(args[0]); -+ PyObject *stop_o = PyStackRef_AsPyObjectBorrow(args[1]); -+ PyObject *step_o = oparg == 3 ? PyStackRef_AsPyObjectBorrow(args[2]) : NULL; - PyObject *slice_o = PySlice_New(start_o, stop_o, step_o); -- PyStackRef_CLOSE(start); -- PyStackRef_CLOSE(stop); -- PyStackRef_XCLOSE(step); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); -+ } - if (slice_o == NULL) { -- stack_pointer += -2 - ((oparg == 3) ? 1 : 0); -+ stack_pointer += -oparg; - assert(WITHIN_STACK_BOUNDS()); -- goto error; -+ JUMP_TO_LABEL(error); - } - slice = PyStackRef_FromPyObjectSteal(slice_o); -- stack_pointer[-2 - ((oparg == 3) ? 1 : 0)] = slice; -- stack_pointer += -1 - ((oparg == 3) ? 1 : 0); -+ stack_pointer[-oparg] = slice; -+ stack_pointer += 1 - oparg; - assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(BUILD_STRING) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = BUILD_STRING; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(BUILD_STRING); -@@ -809,11 +1127,9 @@ - for (int _i = oparg; --_i >= 0;) { - PyStackRef_CLOSE(pieces[_i]); - } -- { -- stack_pointer += -oparg; -- assert(WITHIN_STACK_BOUNDS()); -- goto error; -- } -+ stack_pointer += -oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_LABEL(error); - } - PyObject *str_o = _PyUnicode_JoinArray(&_Py_STR(empty), pieces_o, oparg); - STACKREFS_TO_PYOBJECTS_CLEANUP(pieces_o); -@@ -823,7 +1139,7 @@ - if (str_o == NULL) { - stack_pointer += -oparg; - assert(WITHIN_STACK_BOUNDS()); -- goto error; -+ JUMP_TO_LABEL(error); - } - str = PyStackRef_FromPyObjectSteal(str_o); - stack_pointer[-oparg] = str; -@@ -833,17 +1149,19 @@ - } - - TARGET(BUILD_TUPLE) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = BUILD_TUPLE; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(BUILD_TUPLE); - _PyStackRef *values; - _PyStackRef tup; - values = &stack_pointer[-oparg]; -- PyObject *tup_o = _PyTuple_FromStackRefSteal(values, oparg); -+ PyObject *tup_o = _PyTuple_FromStackRefStealOnSuccess(values, oparg); - if (tup_o == NULL) { -- stack_pointer += -oparg; -- assert(WITHIN_STACK_BOUNDS()); -- goto error; -+ JUMP_TO_LABEL(error); - } - tup = PyStackRef_FromPyObjectSteal(tup_o); - stack_pointer[-oparg] = tup; -@@ -853,6 +1171,10 @@ - } - - TARGET(CACHE) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CACHE; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(CACHE); -@@ -862,12 +1184,17 @@ - } - - TARGET(CALL) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(CALL); -- PREDICTED(CALL); -+ PREDICTED_CALL:; - _Py_CODEUNIT* const this_instr = next_instr - 4; - (void)this_instr; -+ opcode = CALL; - _PyStackRef *callable; - _PyStackRef *self_or_null; - _PyStackRef *args; -@@ -898,6 +1225,8 @@ - args = &stack_pointer[-oparg]; - func = &stack_pointer[-2 - oparg]; - maybe_self = &stack_pointer[-1 - oparg]; -+ args = &stack_pointer[-oparg]; -+ (void)args; - if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - PyObject *self = ((PyMethodObject *)callable_o)->im_self; -@@ -905,7 +1234,9 @@ - PyObject *method = ((PyMethodObject *)callable_o)->im_func; - _PyStackRef temp = callable[0]; - func[0] = PyStackRef_FromPyObjectNew(method); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(temp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - } - } - // _DO_CALL -@@ -916,8 +1247,9 @@ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - // oparg counts all of the args, but *not* self: - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - // Check if the call can be inlined or not -@@ -930,7 +1262,7 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( - tstate, callable[0], locals, -- args, total_args, NULL, frame -+ arguments, total_args, NULL, frame - ); - stack_pointer = _PyFrame_GetStackPointer(frame); - // Manipulate stack directly since we leave using DISPATCH_INLINED(). -@@ -939,23 +1271,22 @@ - // The frame has stolen all the arguments from the stack, - // so there is no need to clean them up. - if (new_frame == NULL) { -- goto error; -+ JUMP_TO_LABEL(error); - } - frame->return_offset = 4 ; - DISPATCH_INLINED(new_frame); - } - /* Callable is not a normal Python function */ -- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable[0]); -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -- } -- { -- stack_pointer += -2 - oparg; -- assert(WITHIN_STACK_BOUNDS()); -- goto error; -+ PyStackRef_XCLOSE(self_or_null[0]); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); - } -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_LABEL(error); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = PyObject_Vectorcall( -@@ -966,7 +1297,7 @@ - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - if (opcode == INSTRUMENTED_CALL) { - PyObject *arg = total_args == 0 ? -- &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(args[0]); -+ &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(arguments[0]); - if (res_o == NULL) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _Py_call_instrumentation_exc2( -@@ -981,19 +1312,22 @@ - frame, this_instr, callable_o, arg); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (err < 0) { -+ _PyFrame_SetStackPointer(frame, stack_pointer); - Py_CLEAR(res_o); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - } - } - } - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - PyStackRef_CLOSE(callable[0]); -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -+ PyStackRef_XCLOSE(self_or_null[0]); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); - } - if (res_o == NULL) { - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); -- goto error; -+ JUMP_TO_LABEL(error); - } - res = PyStackRef_FromPyObjectSteal(res_o); - } -@@ -1008,7 +1342,9 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = _Py_HandlePending(tstate); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err != 0) goto error; -+ if (err != 0) { -+ JUMP_TO_LABEL(error); -+ } - stack_pointer += 1 + oparg; - assert(WITHIN_STACK_BOUNDS()); - } -@@ -1020,7 +1356,13 @@ - } - - TARGET(CALL_ALLOC_AND_ENTER_INIT) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_ALLOC_AND_ENTER_INIT; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(CALL_ALLOC_AND_ENTER_INIT); - static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); -@@ -1034,7 +1376,11 @@ - /* Skip 1 cache entry */ - // _CHECK_PEP_523 - { -- DEOPT_IF(tstate->interp->eval_frame, CALL); -+ if (tstate->interp->eval_frame) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - } - // _CHECK_AND_ALLOCATE_OBJECT - { -@@ -1043,26 +1389,50 @@ - callable = &stack_pointer[-2 - oparg]; - init = &stack_pointer[-2 - oparg]; - self = &stack_pointer[-1 - oparg]; -+ args = &stack_pointer[-oparg]; - uint32_t type_version = read_u32(&this_instr[2].cache); -+ (void)args; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); -- DEOPT_IF(!PyStackRef_IsNull(null[0]), CALL); -- DEOPT_IF(!PyType_Check(callable_o), CALL); -+ if (!PyStackRef_IsNull(null[0])) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } -+ if (!PyType_Check(callable_o)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - PyTypeObject *tp = (PyTypeObject *)callable_o; -- DEOPT_IF(FT_ATOMIC_LOAD_UINT32_RELAXED(tp->tp_version_tag) != type_version, CALL); -- assert(tp->tp_flags & Py_TPFLAGS_INLINE_VALUES); -+ if (FT_ATOMIC_LOAD_UINT32_RELAXED(tp->tp_version_tag) != type_version) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } -+ assert(tp->tp_new == PyBaseObject_Type.tp_new); -+ assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE); -+ assert(tp->tp_alloc == PyType_GenericAlloc); - PyHeapTypeObject *cls = (PyHeapTypeObject *)callable_o; - PyFunctionObject *init_func = (PyFunctionObject *)FT_ATOMIC_LOAD_PTR_ACQUIRE(cls->_spec_cache.init); - PyCodeObject *code = (PyCodeObject *)init_func->func_code; -- DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize + _Py_InitCleanup.co_framesize), CALL); -+ if (!_PyThreadState_HasStackSpace(tstate, code->co_framesize + _Py_InitCleanup.co_framesize)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - STAT_INC(CALL, hit); -- PyObject *self_o = _PyType_NewManagedObject(tp); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyObject *self_o = PyType_GenericAlloc(tp, 0); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - if (self_o == NULL) { -- goto error; -+ JUMP_TO_LABEL(error); - } - self[0] = PyStackRef_FromPyObjectSteal(self_o); - _PyStackRef temp = callable[0]; - init[0] = PyStackRef_FromPyObjectNew(init_func); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(temp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - } - // _CREATE_INIT_FRAME - { -@@ -1072,9 +1442,9 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyInterpreterFrame *shim = _PyFrame_PushTrampolineUnchecked( - tstate, (PyCodeObject *)&_Py_InitCleanup, 1, frame); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - assert(_PyFrame_GetBytecode(shim)[0].op.code == EXIT_INIT_CHECK); - assert(_PyFrame_GetBytecode(shim)[1].op.code == RETURN_VALUE); -- stack_pointer = _PyFrame_GetStackPointer(frame); - /* Push self onto stack of shim */ - shim->localsplus[0] = PyStackRef_DUP(self[0]); - _PyFrame_SetStackPointer(frame, stack_pointer); -@@ -1085,7 +1455,7 @@ - assert(WITHIN_STACK_BOUNDS()); - if (temp == NULL) { - _PyEval_FrameClearAndPop(tstate, shim); -- goto error; -+ JUMP_TO_LABEL(error); - } - init_frame = temp; - frame->return_offset = 1 + INLINE_CACHE_ENTRIES_CALL; -@@ -1114,66 +1484,102 @@ - } - - TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_BOUND_METHOD_EXACT_ARGS; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(CALL_BOUND_METHOD_EXACT_ARGS); - static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); - _PyStackRef *callable; - _PyStackRef *null; -- _PyStackRef *func; -- _PyStackRef *self; - _PyStackRef *self_or_null; - _PyStackRef *args; - _PyInterpreterFrame *new_frame; - /* Skip 1 cache entry */ - // _CHECK_PEP_523 - { -- DEOPT_IF(tstate->interp->eval_frame, CALL); -+ if (tstate->interp->eval_frame) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - } - // _CHECK_CALL_BOUND_METHOD_EXACT_ARGS - { - null = &stack_pointer[-1 - oparg]; - callable = &stack_pointer[-2 - oparg]; -- DEOPT_IF(!PyStackRef_IsNull(null[0]), CALL); -- DEOPT_IF(Py_TYPE(PyStackRef_AsPyObjectBorrow(callable[0])) != &PyMethod_Type, CALL); -+ if (!PyStackRef_IsNull(null[0])) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } -+ if (Py_TYPE(PyStackRef_AsPyObjectBorrow(callable[0])) != &PyMethod_Type) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - } - // _INIT_CALL_BOUND_METHOD_EXACT_ARGS - { -- func = &stack_pointer[-2 - oparg]; -- self = &stack_pointer[-1 - oparg]; -+ self_or_null = null; -+ assert(PyStackRef_IsNull(self_or_null[0])); - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - STAT_INC(CALL, hit); -- self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); -+ self_or_null[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); - _PyStackRef temp = callable[0]; -- func[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); -+ callable[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(temp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - } - // flush - // _CHECK_FUNCTION_VERSION - { -- callable = &stack_pointer[-2 - oparg]; - uint32_t func_version = read_u32(&this_instr[2].cache); - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); -- DEOPT_IF(!PyFunction_Check(callable_o), CALL); -+ if (!PyFunction_Check(callable_o)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - PyFunctionObject *func = (PyFunctionObject *)callable_o; -- DEOPT_IF(func->func_version != func_version, CALL); -+ if (func->func_version != func_version) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - } - // _CHECK_FUNCTION_EXACT_ARGS - { -- self_or_null = &stack_pointer[-1 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - assert(PyFunction_Check(callable_o)); - PyFunctionObject *func = (PyFunctionObject *)callable_o; - PyCodeObject *code = (PyCodeObject *)func->func_code; -- DEOPT_IF(code->co_argcount != oparg + (!PyStackRef_IsNull(self_or_null[0])), CALL); -+ if (code->co_argcount != oparg + (!PyStackRef_IsNull(self_or_null[0]))) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - } - // _CHECK_STACK_SPACE - { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - PyFunctionObject *func = (PyFunctionObject *)callable_o; - PyCodeObject *code = (PyCodeObject *)func->func_code; -- DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL); -- DEOPT_IF(tstate->py_recursion_remaining <= 1, CALL); -+ if (!_PyThreadState_HasStackSpace(tstate, code->co_framesize)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } -+ if (tstate->py_recursion_remaining <= 1) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - } - // _INIT_CALL_PY_EXACT_ARGS - { -@@ -1217,21 +1623,29 @@ - } - - TARGET(CALL_BOUND_METHOD_GENERAL) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_BOUND_METHOD_GENERAL; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(CALL_BOUND_METHOD_GENERAL); - static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); - _PyStackRef *callable; - _PyStackRef *null; -- _PyStackRef *method; -- _PyStackRef *self; - _PyStackRef *self_or_null; - _PyStackRef *args; - _PyInterpreterFrame *new_frame; - /* Skip 1 cache entry */ - // _CHECK_PEP_523 - { -- DEOPT_IF(tstate->interp->eval_frame, CALL); -+ if (tstate->interp->eval_frame) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - } - // _CHECK_METHOD_VERSION - { -@@ -1239,31 +1653,46 @@ - callable = &stack_pointer[-2 - oparg]; - uint32_t func_version = read_u32(&this_instr[2].cache); - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); -- DEOPT_IF(Py_TYPE(callable_o) != &PyMethod_Type, CALL); -+ if (Py_TYPE(callable_o) != &PyMethod_Type) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - PyObject *func = ((PyMethodObject *)callable_o)->im_func; -- DEOPT_IF(!PyFunction_Check(func), CALL); -- DEOPT_IF(((PyFunctionObject *)func)->func_version != func_version, CALL); -- DEOPT_IF(!PyStackRef_IsNull(null[0]), CALL); -+ if (!PyFunction_Check(func)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } -+ if (((PyFunctionObject *)func)->func_version != func_version) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } -+ if (!PyStackRef_IsNull(null[0])) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - } - // _EXPAND_METHOD - { -- method = &stack_pointer[-2 - oparg]; -- self = &stack_pointer[-1 - oparg]; -+ self_or_null = null; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); -- assert(PyStackRef_IsNull(null[0])); -+ assert(PyStackRef_IsNull(self_or_null[0])); - assert(Py_TYPE(callable_o) == &PyMethod_Type); -- self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); -+ self_or_null[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); - _PyStackRef temp = callable[0]; -- method[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); -- assert(PyStackRef_FunctionCheck(method[0])); -+ callable[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); -+ assert(PyStackRef_FunctionCheck(callable[0])); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(temp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - } - // flush - // _PY_FRAME_GENERAL - { - args = &stack_pointer[-oparg]; -- self_or_null = &stack_pointer[-1 - oparg]; -- callable = &stack_pointer[-2 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - // oparg counts all of the args, but *not* self: - int total_args = oparg; -@@ -1284,7 +1713,7 @@ - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); - if (temp == NULL) { -- goto error; -+ JUMP_TO_LABEL(error); - } - new_frame = temp; - } -@@ -1316,6 +1745,12 @@ - } - - TARGET(CALL_BUILTIN_CLASS) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_BUILTIN_CLASS; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(CALL_BUILTIN_CLASS); -@@ -1332,41 +1767,48 @@ - self_or_null = &stack_pointer[-1 - oparg]; - callable = &stack_pointer[-2 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); -+ if (!PyType_Check(callable_o)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } -+ PyTypeObject *tp = (PyTypeObject *)callable_o; - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } -- DEOPT_IF(!PyType_Check(callable_o), CALL); -- PyTypeObject *tp = (PyTypeObject *)callable_o; -- DEOPT_IF(tp->tp_vectorcall == NULL, CALL); -+ if (tp->tp_vectorcall == NULL) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - STAT_INC(CALL, hit); -- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable[0]); -- PyStackRef_CLOSE(self_or_null[0]); -+ PyStackRef_XCLOSE(self_or_null[0]); - for (int _i = oparg; --_i >= 0;) { - PyStackRef_CLOSE(args[_i]); - } -- { -- stack_pointer += -2 - oparg; -- assert(WITHIN_STACK_BOUNDS()); -- goto error; -- } -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_LABEL(error); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = tp->tp_vectorcall((PyObject *)tp, args_o, total_args, NULL); - stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); -- /* Free the arguments. */ -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -- } - PyStackRef_CLOSE(callable[0]); -+ PyStackRef_XCLOSE(self_or_null[0]); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); -+ } - if (res_o == NULL) { - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); -- goto error; -+ JUMP_TO_LABEL(error); - } - res = PyStackRef_FromPyObjectSteal(res_o); - } -@@ -1381,7 +1823,9 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = _Py_HandlePending(tstate); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err != 0) goto error; -+ if (err != 0) { -+ JUMP_TO_LABEL(error); -+ } - stack_pointer += 1 + oparg; - assert(WITHIN_STACK_BOUNDS()); - } -@@ -1393,6 +1837,12 @@ - } - - TARGET(CALL_BUILTIN_FAST) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_BUILTIN_FAST; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(CALL_BUILTIN_FAST); -@@ -1411,27 +1861,34 @@ - /* Builtin METH_FASTCALL functions, without keywords */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } -- DEOPT_IF(!PyCFunction_CheckExact(callable_o), CALL); -- DEOPT_IF(PyCFunction_GET_FLAGS(callable_o) != METH_FASTCALL, CALL); -+ if (!PyCFunction_CheckExact(callable_o)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } -+ if (PyCFunction_GET_FLAGS(callable_o) != METH_FASTCALL) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - STAT_INC(CALL, hit); - PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable_o); - /* res = func(self, args, nargs) */ -- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable[0]); -- PyStackRef_CLOSE(self_or_null[0]); -+ PyStackRef_XCLOSE(self_or_null[0]); - for (int _i = oparg; --_i >= 0;) { - PyStackRef_CLOSE(args[_i]); - } -- { -- stack_pointer += -2 - oparg; -- assert(WITHIN_STACK_BOUNDS()); -- goto error; -- } -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_LABEL(error); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = ((PyCFunctionFast)(void(*)(void))cfunc)( -@@ -1441,15 +1898,15 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); -- /* Free the arguments. */ -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -- } - PyStackRef_CLOSE(callable[0]); -+ PyStackRef_XCLOSE(self_or_null[0]); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); -+ } - if (res_o == NULL) { - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); -- goto error; -+ JUMP_TO_LABEL(error); - } - res = PyStackRef_FromPyObjectSteal(res_o); - } -@@ -1464,7 +1921,9 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = _Py_HandlePending(tstate); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err != 0) goto error; -+ if (err != 0) { -+ JUMP_TO_LABEL(error); -+ } - stack_pointer += 1 + oparg; - assert(WITHIN_STACK_BOUNDS()); - } -@@ -1476,6 +1935,12 @@ - } - - TARGET(CALL_BUILTIN_FAST_WITH_KEYWORDS) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_BUILTIN_FAST_WITH_KEYWORDS; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(CALL_BUILTIN_FAST_WITH_KEYWORDS); -@@ -1494,46 +1959,53 @@ - /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } -- DEOPT_IF(!PyCFunction_CheckExact(callable_o), CALL); -- DEOPT_IF(PyCFunction_GET_FLAGS(callable_o) != (METH_FASTCALL | METH_KEYWORDS), CALL); -+ if (!PyCFunction_CheckExact(callable_o)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } -+ if (PyCFunction_GET_FLAGS(callable_o) != (METH_FASTCALL | METH_KEYWORDS)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - STAT_INC(CALL, hit); -- /* res = func(self, args, nargs, kwnames) */ -+ /* res = func(self, arguments, nargs, kwnames) */ - _PyFrame_SetStackPointer(frame, stack_pointer); - PyCFunctionFastWithKeywords cfunc = - (PyCFunctionFastWithKeywords)(void(*)(void)) - PyCFunction_GET_FUNCTION(callable_o); - stack_pointer = _PyFrame_GetStackPointer(frame); -- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable[0]); -- PyStackRef_CLOSE(self_or_null[0]); -+ PyStackRef_XCLOSE(self_or_null[0]); - for (int _i = oparg; --_i >= 0;) { - PyStackRef_CLOSE(args[_i]); - } -- { -- stack_pointer += -2 - oparg; -- assert(WITHIN_STACK_BOUNDS()); -- goto error; -- } -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_LABEL(error); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = cfunc(PyCFunction_GET_SELF(callable_o), args_o, total_args, NULL); - stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); -- /* Free the arguments. */ -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -- } - PyStackRef_CLOSE(callable[0]); -+ PyStackRef_XCLOSE(self_or_null[0]); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); -+ } - if (res_o == NULL) { - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); -- goto error; -+ JUMP_TO_LABEL(error); - } - res = PyStackRef_FromPyObjectSteal(res_o); - } -@@ -1548,7 +2020,9 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = _Py_HandlePending(tstate); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err != 0) goto error; -+ if (err != 0) { -+ JUMP_TO_LABEL(error); -+ } - stack_pointer += 1 + oparg; - assert(WITHIN_STACK_BOUNDS()); - } -@@ -1560,6 +2034,12 @@ - } - - TARGET(CALL_BUILTIN_O) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_BUILTIN_O; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(CALL_BUILTIN_O); -@@ -1582,11 +2062,27 @@ - args--; - total_args++; - } -- DEOPT_IF(total_args != 1, CALL); -- DEOPT_IF(!PyCFunction_CheckExact(callable_o), CALL); -- DEOPT_IF(PyCFunction_GET_FLAGS(callable_o) != METH_O, CALL); -+ if (total_args != 1) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } -+ if (!PyCFunction_CheckExact(callable_o)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } -+ if (PyCFunction_GET_FLAGS(callable_o) != METH_O) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - // CPython promises to check all non-vectorcall function calls. -- DEOPT_IF(tstate->c_recursion_remaining <= 0, CALL); -+ if (tstate->c_recursion_remaining <= 0) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - STAT_INC(CALL, hit); - PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable_o); - _PyStackRef arg = args[0]; -@@ -1596,12 +2092,16 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - _Py_LeaveRecursiveCallTstate(tstate); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(arg); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callable[0]); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - if (res_o == NULL) { -- stack_pointer += -2 - oparg; -- assert(WITHIN_STACK_BOUNDS()); -- goto error; -+ JUMP_TO_LABEL(error); - } - res = PyStackRef_FromPyObjectSteal(res_o); - } -@@ -1610,93 +2110,109 @@ - _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); - if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { -- stack_pointer[-2 - oparg] = res; -- stack_pointer += -1 - oparg; -+ stack_pointer[0] = res; -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = _Py_HandlePending(tstate); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err != 0) goto error; -- stack_pointer += 1 + oparg; -+ if (err != 0) { -+ JUMP_TO_LABEL(error); -+ } -+ stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - } - } -- stack_pointer[-2 - oparg] = res; -- stack_pointer += -1 - oparg; -+ stack_pointer[0] = res; -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(CALL_FUNCTION_EX) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_FUNCTION_EX; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(CALL_FUNCTION_EX); -- PREDICTED(CALL_FUNCTION_EX); -- _Py_CODEUNIT* const this_instr = next_instr - 1; -- (void)this_instr; -+ opcode = CALL_FUNCTION_EX; - _PyStackRef func; - _PyStackRef callargs; -- _PyStackRef kwargs_in = PyStackRef_NULL; -+ _PyStackRef kwargs_in; - _PyStackRef tuple; -- _PyStackRef kwargs_out = PyStackRef_NULL; -+ _PyStackRef kwargs_out; - _PyStackRef func_st; -+ _PyStackRef null; - _PyStackRef callargs_st; -- _PyStackRef kwargs_st = PyStackRef_NULL; -+ _PyStackRef kwargs_st; - _PyStackRef result; - // _MAKE_CALLARGS_A_TUPLE - { -- if (oparg & 1) { kwargs_in = stack_pointer[-(oparg & 1)]; } -- callargs = stack_pointer[-1 - (oparg & 1)]; -- func = stack_pointer[-3 - (oparg & 1)]; -+ kwargs_in = stack_pointer[-1]; -+ callargs = stack_pointer[-2]; -+ func = stack_pointer[-4]; - PyObject *callargs_o = PyStackRef_AsPyObjectBorrow(callargs); - if (PyTuple_CheckExact(callargs_o)) { - tuple = callargs; -+ kwargs_out = kwargs_in; - } - else { - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = _Py_Check_ArgsIterable(tstate, PyStackRef_AsPyObjectBorrow(func), callargs_o); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (err < 0) { -- goto error; -+ JUMP_TO_LABEL(error); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *tuple_o = PySequence_Tuple(callargs_o); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (tuple_o == NULL) { -- goto error; -+ JUMP_TO_LABEL(error); - } -+ kwargs_out = kwargs_in; -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callargs); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - tuple = PyStackRef_FromPyObjectSteal(tuple_o); -+ stack_pointer += 2; -+ assert(WITHIN_STACK_BOUNDS()); - } -- kwargs_out = kwargs_in; - } - // _DO_CALL_FUNCTION_EX - { - kwargs_st = kwargs_out; - callargs_st = tuple; -+ null = stack_pointer[-3]; - func_st = func; -+ (void)null; - PyObject *func = PyStackRef_AsPyObjectBorrow(func_st); -- PyObject *callargs = PyStackRef_AsPyObjectBorrow(callargs_st); -- PyObject *kwargs = PyStackRef_AsPyObjectBorrow(kwargs_st); - // DICT_MERGE is called before this opcode if there are kwargs. - // It converts all dict subtypes in kwargs into regular dicts. -- assert(kwargs == NULL || PyDict_CheckExact(kwargs)); -- assert(PyTuple_CheckExact(callargs)); - EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_FUNCTION_EX, func); - PyObject *result_o; - assert(!_PyErr_Occurred(tstate)); - if (opcode == INSTRUMENTED_CALL_FUNCTION_EX) { -+ PyObject *callargs = PyStackRef_AsPyObjectBorrow(callargs_st); -+ PyObject *kwargs = PyStackRef_AsPyObjectBorrow(kwargs_st); -+ assert(kwargs == NULL || PyDict_CheckExact(kwargs)); -+ assert(PyTuple_CheckExact(callargs)); - PyObject *arg = PyTuple_GET_SIZE(callargs) > 0 ? - PyTuple_GET_ITEM(callargs, 0) : &_PyInstrumentation_MISSING; -- stack_pointer[-1 - (oparg & 1)] = callargs_st; -- if (oparg & 1) stack_pointer[-(oparg & 1)] = kwargs_st; -+ stack_pointer[-2] = callargs_st; -+ stack_pointer[-1] = kwargs_st; - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = _Py_call_instrumentation_2args( - tstate, PY_MONITORING_EVENT_CALL, - frame, this_instr, func, arg); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (err) { -- goto error; -+ JUMP_TO_LABEL(error); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - result_o = PyObject_Call(func, callargs, kwargs); -@@ -1716,7 +2232,9 @@ - frame, this_instr, func, arg); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (err < 0) { -+ _PyFrame_SetStackPointer(frame, stack_pointer); - Py_CLEAR(result_o); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - } - } - } -@@ -1725,42 +2243,57 @@ - if (Py_TYPE(func) == &PyFunction_Type && - tstate->interp->eval_frame == NULL && - ((PyFunctionObject *)func)->vectorcall == _PyFunction_Vectorcall) { -+ PyObject *callargs = PyStackRef_AsPyObjectSteal(callargs_st); - assert(PyTuple_CheckExact(callargs)); -+ PyObject *kwargs = PyStackRef_IsNull(kwargs_st) ? NULL : PyStackRef_AsPyObjectSteal(kwargs_st); -+ assert(kwargs == NULL || PyDict_CheckExact(kwargs)); - Py_ssize_t nargs = PyTuple_GET_SIZE(callargs); - int code_flags = ((PyCodeObject *)PyFunction_GET_CODE(func))->co_flags; - PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(func)); -- stack_pointer[-1 - (oparg & 1)] = callargs_st; -- if (oparg & 1) stack_pointer[-(oparg & 1)] = kwargs_st; -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_Ex( - tstate, func_st, locals, - nargs, callargs, kwargs, frame); - stack_pointer = _PyFrame_GetStackPointer(frame); - // Need to sync the stack since we exit with DISPATCH_INLINED. -- stack_pointer += -3 - (oparg & 1); -+ stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); - if (new_frame == NULL) { -- goto error; -+ JUMP_TO_LABEL(error); - } - assert( 1 == 1); - frame->return_offset = 1; - DISPATCH_INLINED(new_frame); - } -- stack_pointer[-1 - (oparg & 1)] = callargs_st; -- if (oparg & 1) stack_pointer[-(oparg & 1)] = kwargs_st; -+ PyObject *callargs = PyStackRef_AsPyObjectBorrow(callargs_st); -+ assert(PyTuple_CheckExact(callargs)); -+ PyObject *kwargs = PyStackRef_AsPyObjectBorrow(kwargs_st); -+ assert(kwargs == NULL || PyDict_CheckExact(kwargs)); -+ stack_pointer[-2] = callargs_st; -+ stack_pointer[-1] = kwargs_st; - _PyFrame_SetStackPointer(frame, stack_pointer); - result_o = PyObject_Call(func, callargs, kwargs); - stack_pointer = _PyFrame_GetStackPointer(frame); - } -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_XCLOSE(kwargs_st); - stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callargs_st); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(func_st); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - if (result_o == NULL) { -- stack_pointer += -3 - (oparg & 1); -- assert(WITHIN_STACK_BOUNDS()); -- goto error; -+ JUMP_TO_LABEL(error); - } - result = PyStackRef_FromPyObjectSteal(result_o); - } -@@ -1769,24 +2302,30 @@ - _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); - if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { -- stack_pointer[-3 - (oparg & 1)] = result; -- stack_pointer += -2 - (oparg & 1); -+ stack_pointer[0] = result; -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = _Py_HandlePending(tstate); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err != 0) goto error; -- stack_pointer += 2 + (oparg & 1); -+ if (err != 0) { -+ JUMP_TO_LABEL(error); -+ } -+ stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - } - } -- stack_pointer[-3 - (oparg & 1)] = result; -- stack_pointer += -2 - (oparg & 1); -+ stack_pointer[0] = result; -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(CALL_INTRINSIC_1) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_INTRINSIC_1; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(CALL_INTRINSIC_1); -@@ -1798,13 +2337,19 @@ - PyObject *res_o = _PyIntrinsics_UnaryFunctions[oparg].func(tstate, PyStackRef_AsPyObjectBorrow(value)); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(value); -- if (res_o == NULL) goto pop_1_error; -+ if (res_o == NULL) { -+ JUMP_TO_LABEL(pop_1_error); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-1] = res; - DISPATCH(); - } - - TARGET(CALL_INTRINSIC_2) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_INTRINSIC_2; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(CALL_INTRINSIC_2); -@@ -1821,7 +2366,9 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(value2_st); - PyStackRef_CLOSE(value1_st); -- if (res_o == NULL) goto pop_2_error; -+ if (res_o == NULL) { -+ JUMP_TO_LABEL(pop_2_error); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -1830,6 +2377,12 @@ - } - - TARGET(CALL_ISINSTANCE) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_ISINSTANCE; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(CALL_ISINSTANCE); -@@ -1846,27 +2399,38 @@ - /* isinstance(o, o2) */ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } -- DEOPT_IF(total_args != 2, CALL); -+ if (total_args != 2) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - PyInterpreterState *interp = tstate->interp; -- DEOPT_IF(callable_o != interp->callable_cache.isinstance, CALL); -+ if (callable_o != interp->callable_cache.isinstance) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - STAT_INC(CALL, hit); -- _PyStackRef cls_stackref = args[1]; -- _PyStackRef inst_stackref = args[0]; -+ _PyStackRef cls_stackref = arguments[1]; -+ _PyStackRef inst_stackref = arguments[0]; - _PyFrame_SetStackPointer(frame, stack_pointer); - int retval = PyObject_IsInstance(PyStackRef_AsPyObjectBorrow(inst_stackref), PyStackRef_AsPyObjectBorrow(cls_stackref)); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (retval < 0) { -- goto error; -+ JUMP_TO_LABEL(error); - } - res = retval ? PyStackRef_True : PyStackRef_False; - assert((!PyStackRef_IsNull(res)) ^ (_PyErr_Occurred(tstate) != NULL)); -- PyStackRef_CLOSE(inst_stackref); -- PyStackRef_CLOSE(cls_stackref); - PyStackRef_CLOSE(callable[0]); -+ PyStackRef_XCLOSE(self_or_null[0]); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); -+ } - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); -@@ -1874,12 +2438,17 @@ - } - - TARGET(CALL_KW) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_KW; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(CALL_KW); -- PREDICTED(CALL_KW); -+ PREDICTED_CALL_KW:; - _Py_CODEUNIT* const this_instr = next_instr - 4; - (void)this_instr; -+ opcode = CALL_KW; - _PyStackRef *callable; - _PyStackRef *self_or_null; - _PyStackRef *args; -@@ -1914,6 +2483,8 @@ - args = &stack_pointer[-1 - oparg]; - func = &stack_pointer[-3 - oparg]; - maybe_self = &stack_pointer[-2 - oparg]; -+ args = &stack_pointer[-1 - oparg]; -+ (void)args; - if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - PyObject *self = ((PyMethodObject *)callable_o)->im_self; -@@ -1921,7 +2492,9 @@ - PyObject *method = ((PyMethodObject *)callable_o)->im_func; - _PyStackRef temp = callable[0]; - func[0] = PyStackRef_FromPyObjectNew(method); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(temp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - } - kwnames_out = kwnames_in; - } -@@ -1935,8 +2508,9 @@ - PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); - // oparg counts all of the args, but *not* self: - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - int positional_args = total_args - (int)PyTuple_GET_SIZE(kwnames_o); -@@ -1951,36 +2525,38 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( - tstate, callable[0], locals, -- args, positional_args, kwnames_o, frame -+ arguments, positional_args, kwnames_o, frame - ); - stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(kwnames); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - // Sync stack explicitly since we leave using DISPATCH_INLINED(). -- stack_pointer += -3 - oparg; -+ stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); - // The frame has stolen all the arguments from the stack, - // so there is no need to clean them up. - if (new_frame == NULL) { -- goto error; -+ JUMP_TO_LABEL(error); - } - assert( 4 == 1 + INLINE_CACHE_ENTRIES_CALL_KW); - frame->return_offset = 4 ; - DISPATCH_INLINED(new_frame); - } - /* Callable is not a normal Python function */ -- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable[0]); -- PyStackRef_CLOSE(self_or_null[0]); -+ PyStackRef_XCLOSE(self_or_null[0]); - for (int _i = oparg; --_i >= 0;) { - PyStackRef_CLOSE(args[_i]); - } - PyStackRef_CLOSE(kwnames); -- { -- stack_pointer += -3 - oparg; -- assert(WITHIN_STACK_BOUNDS()); -- goto error; -- } -+ stack_pointer += -3 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_LABEL(error); - } - stack_pointer[-1] = kwnames; - _PyFrame_SetStackPointer(frame, stack_pointer); -@@ -1992,7 +2568,7 @@ - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - if (opcode == INSTRUMENTED_CALL_KW) { - PyObject *arg = total_args == 0 ? -- &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(args[0]); -+ &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(arguments[0]); - if (res_o == NULL) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _Py_call_instrumentation_exc2( -@@ -2007,20 +2583,22 @@ - frame, this_instr, callable_o, arg); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (err < 0) { -+ _PyFrame_SetStackPointer(frame, stack_pointer); - Py_CLEAR(res_o); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - } - } - } -- PyStackRef_CLOSE(kwnames); -- assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - PyStackRef_CLOSE(callable[0]); -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -+ PyStackRef_XCLOSE(self_or_null[0]); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); - } -+ PyStackRef_CLOSE(kwnames); - if (res_o == NULL) { - stack_pointer += -3 - oparg; - assert(WITHIN_STACK_BOUNDS()); -- goto error; -+ JUMP_TO_LABEL(error); - } - res = PyStackRef_FromPyObjectSteal(res_o); - } -@@ -2031,22 +2609,30 @@ - } - - TARGET(CALL_KW_BOUND_METHOD) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_KW_BOUND_METHOD; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(CALL_KW_BOUND_METHOD); - static_assert(INLINE_CACHE_ENTRIES_CALL_KW == 3, "incorrect cache size"); - _PyStackRef *callable; - _PyStackRef *null; - _PyStackRef kwnames; -- _PyStackRef *method; -- _PyStackRef *self; - _PyStackRef *self_or_null; - _PyStackRef *args; - _PyInterpreterFrame *new_frame; - /* Skip 1 cache entry */ - // _CHECK_PEP_523 - { -- DEOPT_IF(tstate->interp->eval_frame, CALL_KW); -+ if (tstate->interp->eval_frame) { -+ UPDATE_MISS_STATS(CALL_KW); -+ assert(_PyOpcode_Deopt[opcode] == (CALL_KW)); -+ JUMP_TO_PREDICTED(CALL_KW); -+ } - } - // _CHECK_METHOD_VERSION_KW - { -@@ -2054,37 +2640,53 @@ - callable = &stack_pointer[-3 - oparg]; - uint32_t func_version = read_u32(&this_instr[2].cache); - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); -- DEOPT_IF(Py_TYPE(callable_o) != &PyMethod_Type, CALL_KW); -+ if (Py_TYPE(callable_o) != &PyMethod_Type) { -+ UPDATE_MISS_STATS(CALL_KW); -+ assert(_PyOpcode_Deopt[opcode] == (CALL_KW)); -+ JUMP_TO_PREDICTED(CALL_KW); -+ } - PyObject *func = ((PyMethodObject *)callable_o)->im_func; -- DEOPT_IF(!PyFunction_Check(func), CALL_KW); -- DEOPT_IF(((PyFunctionObject *)func)->func_version != func_version, CALL_KW); -- DEOPT_IF(!PyStackRef_IsNull(null[0]), CALL_KW); -+ if (!PyFunction_Check(func)) { -+ UPDATE_MISS_STATS(CALL_KW); -+ assert(_PyOpcode_Deopt[opcode] == (CALL_KW)); -+ JUMP_TO_PREDICTED(CALL_KW); -+ } -+ if (((PyFunctionObject *)func)->func_version != func_version) { -+ UPDATE_MISS_STATS(CALL_KW); -+ assert(_PyOpcode_Deopt[opcode] == (CALL_KW)); -+ JUMP_TO_PREDICTED(CALL_KW); -+ } -+ if (!PyStackRef_IsNull(null[0])) { -+ UPDATE_MISS_STATS(CALL_KW); -+ assert(_PyOpcode_Deopt[opcode] == (CALL_KW)); -+ JUMP_TO_PREDICTED(CALL_KW); -+ } - } - // _EXPAND_METHOD_KW - { -- method = &stack_pointer[-3 - oparg]; -- self = &stack_pointer[-2 - oparg]; -+ self_or_null = null; -+ assert(PyStackRef_IsNull(self_or_null[0])); - _PyStackRef callable_s = callable[0]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable_s); -- assert(PyStackRef_IsNull(null[0])); - assert(Py_TYPE(callable_o) == &PyMethod_Type); -- self[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); -- method[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); -- assert(PyStackRef_FunctionCheck(method[0])); -+ self_or_null[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self); -+ callable[0] = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func); -+ assert(PyStackRef_FunctionCheck(callable[0])); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callable_s); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - } - // flush - // _PY_FRAME_KW - { - kwnames = stack_pointer[-1]; - args = &stack_pointer[-1 - oparg]; -- self_or_null = &stack_pointer[-2 - oparg]; -- callable = &stack_pointer[-3 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - // oparg counts all of the args, but *not* self: - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); -@@ -2095,16 +2697,20 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyInterpreterFrame *temp = _PyEvalFramePushAndInit( - tstate, callable[0], locals, -- args, positional_args, kwnames_o, frame -+ arguments, positional_args, kwnames_o, frame - ); - stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(kwnames); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - // The frame has stolen all the arguments from the stack, - // so there is no need to clean them up. -- stack_pointer += -3 - oparg; -+ stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); - if (temp == NULL) { -- goto error; -+ JUMP_TO_LABEL(error); - } - new_frame = temp; - } -@@ -2136,9 +2742,16 @@ - } - - TARGET(CALL_KW_NON_PY) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_KW_NON_PY; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(CALL_KW_NON_PY); -+ opcode = CALL_KW_NON_PY; - static_assert(INLINE_CACHE_ENTRIES_CALL_KW == 3, "incorrect cache size"); - _PyStackRef *callable; - _PyStackRef kwnames; -@@ -2151,8 +2764,16 @@ - { - callable = &stack_pointer[-3 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); -- DEOPT_IF(PyFunction_Check(callable_o), CALL_KW); -- DEOPT_IF(Py_TYPE(callable_o) == &PyMethod_Type, CALL_KW); -+ if (PyFunction_Check(callable_o)) { -+ UPDATE_MISS_STATS(CALL_KW); -+ assert(_PyOpcode_Deopt[opcode] == (CALL_KW)); -+ JUMP_TO_PREDICTED(CALL_KW); -+ } -+ if (Py_TYPE(callable_o) == &PyMethod_Type) { -+ UPDATE_MISS_STATS(CALL_KW); -+ assert(_PyOpcode_Deopt[opcode] == (CALL_KW)); -+ JUMP_TO_PREDICTED(CALL_KW); -+ } - } - // _CALL_KW_NON_PY - { -@@ -2164,24 +2785,23 @@ - #endif - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - /* Callable is not a normal Python function */ -- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable[0]); -- PyStackRef_CLOSE(self_or_null[0]); -+ PyStackRef_XCLOSE(self_or_null[0]); - for (int _i = oparg; --_i >= 0;) { - PyStackRef_CLOSE(args[_i]); - } - PyStackRef_CLOSE(kwnames); -- { -- stack_pointer += -3 - oparg; -- assert(WITHIN_STACK_BOUNDS()); -- goto error; -- } -+ stack_pointer += -3 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_LABEL(error); - } - PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); - int positional_args = total_args - (int)PyTuple_GET_SIZE(kwnames_o); -@@ -2191,17 +2811,22 @@ - positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, - kwnames_o); - stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(kwnames); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -- } - PyStackRef_CLOSE(callable[0]); -+ PyStackRef_XCLOSE(self_or_null[0]); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); -+ } - if (res_o == NULL) { -- stack_pointer += -3 - oparg; -+ stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); -- goto error; -+ JUMP_TO_LABEL(error); - } - res = PyStackRef_FromPyObjectSteal(res_o); - } -@@ -2210,25 +2835,33 @@ - _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); - if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { -- stack_pointer[-3 - oparg] = res; -- stack_pointer += -2 - oparg; -+ stack_pointer[-2 - oparg] = res; -+ stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = _Py_HandlePending(tstate); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err != 0) goto error; -- stack_pointer += 2 + oparg; -+ if (err != 0) { -+ JUMP_TO_LABEL(error); -+ } -+ stack_pointer += 1 + oparg; - assert(WITHIN_STACK_BOUNDS()); - } - } -- stack_pointer[-3 - oparg] = res; -- stack_pointer += -2 - oparg; -+ stack_pointer[-2 - oparg] = res; -+ stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(CALL_KW_PY) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_KW_PY; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(CALL_KW_PY); - static_assert(INLINE_CACHE_ENTRIES_CALL_KW == 3, "incorrect cache size"); -@@ -2240,16 +2873,28 @@ - /* Skip 1 cache entry */ - // _CHECK_PEP_523 - { -- DEOPT_IF(tstate->interp->eval_frame, CALL_KW); -+ if (tstate->interp->eval_frame) { -+ UPDATE_MISS_STATS(CALL_KW); -+ assert(_PyOpcode_Deopt[opcode] == (CALL_KW)); -+ JUMP_TO_PREDICTED(CALL_KW); -+ } - } - // _CHECK_FUNCTION_VERSION_KW - { - callable = &stack_pointer[-3 - oparg]; - uint32_t func_version = read_u32(&this_instr[2].cache); - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); -- DEOPT_IF(!PyFunction_Check(callable_o), CALL_KW); -+ if (!PyFunction_Check(callable_o)) { -+ UPDATE_MISS_STATS(CALL_KW); -+ assert(_PyOpcode_Deopt[opcode] == (CALL_KW)); -+ JUMP_TO_PREDICTED(CALL_KW); -+ } - PyFunctionObject *func = (PyFunctionObject *)callable_o; -- DEOPT_IF(func->func_version != func_version, CALL_KW); -+ if (func->func_version != func_version) { -+ UPDATE_MISS_STATS(CALL_KW); -+ assert(_PyOpcode_Deopt[opcode] == (CALL_KW)); -+ JUMP_TO_PREDICTED(CALL_KW); -+ } - } - // _PY_FRAME_KW - { -@@ -2259,8 +2904,9 @@ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - // oparg counts all of the args, but *not* self: - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); -@@ -2271,16 +2917,20 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyInterpreterFrame *temp = _PyEvalFramePushAndInit( - tstate, callable[0], locals, -- args, positional_args, kwnames_o, frame -+ arguments, positional_args, kwnames_o, frame - ); - stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(kwnames); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - // The frame has stolen all the arguments from the stack, - // so there is no need to clean them up. -- stack_pointer += -3 - oparg; -+ stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); - if (temp == NULL) { -- goto error; -+ JUMP_TO_LABEL(error); - } - new_frame = temp; - } -@@ -2312,6 +2962,12 @@ - } - - TARGET(CALL_LEN) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_LEN; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(CALL_LEN); -@@ -2332,9 +2988,17 @@ - args--; - total_args++; - } -- DEOPT_IF(total_args != 1, CALL); -+ if (total_args != 1) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - PyInterpreterState *interp = tstate->interp; -- DEOPT_IF(callable_o != interp->callable_cache.len, CALL); -+ if (callable_o != interp->callable_cache.len) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - STAT_INC(CALL, hit); - _PyStackRef arg_stackref = args[0]; - PyObject *arg = PyStackRef_AsPyObjectBorrow(arg_stackref); -@@ -2342,23 +3006,35 @@ - Py_ssize_t len_i = PyObject_Length(arg); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (len_i < 0) { -- goto error; -+ JUMP_TO_LABEL(error); - } - PyObject *res_o = PyLong_FromSsize_t(len_i); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - if (res_o == NULL) { -- GOTO_ERROR(error); -+ JUMP_TO_LABEL(error); - } -- PyStackRef_CLOSE(callable[0]); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(arg_stackref); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(callable[0]); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - res = PyStackRef_FromPyObjectSteal(res_o); -- stack_pointer[-2 - oparg] = res; -- stack_pointer += -1 - oparg; -+ stack_pointer[0] = res; -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(CALL_LIST_APPEND) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_LIST_APPEND; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(CALL_LIST_APPEND); -@@ -2375,28 +3051,54 @@ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); - PyObject *self_o = PyStackRef_AsPyObjectBorrow(self); - PyInterpreterState *interp = tstate->interp; -- DEOPT_IF(callable_o != interp->callable_cache.list_append, CALL); -+ if (callable_o != interp->callable_cache.list_append) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - assert(self_o != NULL); -- DEOPT_IF(!PyList_Check(self_o), CALL); -- DEOPT_IF(!LOCK_OBJECT(self_o), CALL); -+ if (!PyList_Check(self_o)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } -+ if (!LOCK_OBJECT(self_o)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - STAT_INC(CALL, hit); - int err = _PyList_AppendTakeRef((PyListObject *)self_o, PyStackRef_AsPyObjectSteal(arg)); - UNLOCK_OBJECT(self_o); -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(self); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callable); -- if (err) goto pop_3_error; -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (err) { -+ JUMP_TO_LABEL(error); -+ } - #if TIER_ONE - // Skip the following POP_TOP. This is done here in tier one, and - // during trace projection in tier two: - assert(next_instr->op.code == POP_TOP); - SKIP_OVER(1); - #endif -- stack_pointer += -3; -- assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(CALL_METHOD_DESCRIPTOR_FAST) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_METHOD_DESCRIPTOR_FAST; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(CALL_METHOD_DESCRIPTOR_FAST); -@@ -2414,31 +3116,42 @@ - callable = &stack_pointer[-2 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; - /* Builtin METH_FASTCALL methods, without keywords */ -- DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL); -+ if (!Py_IS_TYPE(method, &PyMethodDescr_Type)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - PyMethodDef *meth = method->d_method; -- DEOPT_IF(meth->ml_flags != METH_FASTCALL, CALL); -- PyObject *self = PyStackRef_AsPyObjectBorrow(args[0]); -- DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL); -+ if (meth->ml_flags != METH_FASTCALL) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } -+ PyObject *self = PyStackRef_AsPyObjectBorrow(arguments[0]); -+ if (!Py_IS_TYPE(self, method->d_common.d_type)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - STAT_INC(CALL, hit); - int nargs = total_args - 1; -- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable[0]); -- PyStackRef_CLOSE(self_or_null[0]); -+ PyStackRef_XCLOSE(self_or_null[0]); - for (int _i = oparg; --_i >= 0;) { - PyStackRef_CLOSE(args[_i]); - } -- { -- stack_pointer += -2 - oparg; -- assert(WITHIN_STACK_BOUNDS()); -- goto error; -- } -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_LABEL(error); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - PyCFunctionFast cfunc = -@@ -2447,15 +3160,15 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); -- /* Clear the stack of the arguments. */ -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -- } - PyStackRef_CLOSE(callable[0]); -+ PyStackRef_XCLOSE(self_or_null[0]); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); -+ } - if (res_o == NULL) { - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); -- goto error; -+ JUMP_TO_LABEL(error); - } - res = PyStackRef_FromPyObjectSteal(res_o); - } -@@ -2470,7 +3183,9 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = _Py_HandlePending(tstate); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err != 0) goto error; -+ if (err != 0) { -+ JUMP_TO_LABEL(error); -+ } - stack_pointer += 1 + oparg; - assert(WITHIN_STACK_BOUNDS()); - } -@@ -2482,6 +3197,12 @@ - } - - TARGET(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS); -@@ -2499,31 +3220,42 @@ - callable = &stack_pointer[-2 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; -- DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL); -+ if (!Py_IS_TYPE(method, &PyMethodDescr_Type)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - PyMethodDef *meth = method->d_method; -- DEOPT_IF(meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS), CALL); -+ if (meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - PyTypeObject *d_type = method->d_common.d_type; -- PyObject *self = PyStackRef_AsPyObjectBorrow(args[0]); -- DEOPT_IF(!Py_IS_TYPE(self, d_type), CALL); -+ PyObject *self = PyStackRef_AsPyObjectBorrow(arguments[0]); -+ if (!Py_IS_TYPE(self, d_type)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - STAT_INC(CALL, hit); - int nargs = total_args - 1; -- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable[0]); -- PyStackRef_CLOSE(self_or_null[0]); -+ PyStackRef_XCLOSE(self_or_null[0]); - for (int _i = oparg; --_i >= 0;) { - PyStackRef_CLOSE(args[_i]); - } -- { -- stack_pointer += -2 - oparg; -- assert(WITHIN_STACK_BOUNDS()); -- goto error; -- } -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_LABEL(error); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - PyCFunctionFastWithKeywords cfunc = -@@ -2532,15 +3264,15 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); -- /* Free the arguments. */ -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -- } - PyStackRef_CLOSE(callable[0]); -+ PyStackRef_XCLOSE(self_or_null[0]); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); -+ } - if (res_o == NULL) { - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); -- goto error; -+ JUMP_TO_LABEL(error); - } - res = PyStackRef_FromPyObjectSteal(res_o); - } -@@ -2555,7 +3287,9 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = _Py_HandlePending(tstate); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err != 0) goto error; -+ if (err != 0) { -+ JUMP_TO_LABEL(error); -+ } - stack_pointer += 1 + oparg; - assert(WITHIN_STACK_BOUNDS()); - } -@@ -2567,6 +3301,12 @@ - } - - TARGET(CALL_METHOD_DESCRIPTOR_NOARGS) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_METHOD_DESCRIPTOR_NOARGS; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(CALL_METHOD_DESCRIPTOR_NOARGS); -@@ -2589,16 +3329,36 @@ - args--; - total_args++; - } -- DEOPT_IF(total_args != 1, CALL); -+ if (total_args != 1) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; -- DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL); -+ if (!Py_IS_TYPE(method, &PyMethodDescr_Type)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - PyMethodDef *meth = method->d_method; - _PyStackRef self_stackref = args[0]; - PyObject *self = PyStackRef_AsPyObjectBorrow(self_stackref); -- DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL); -- DEOPT_IF(meth->ml_flags != METH_NOARGS, CALL); -+ if (!Py_IS_TYPE(self, method->d_common.d_type)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } -+ if (meth->ml_flags != METH_NOARGS) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - // CPython promises to check all non-vectorcall function calls. -- DEOPT_IF(tstate->c_recursion_remaining <= 0, CALL); -+ if (tstate->c_recursion_remaining <= 0) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - STAT_INC(CALL, hit); - PyCFunction cfunc = meth->ml_meth; - _Py_EnterRecursiveCallTstateUnchecked(tstate); -@@ -2607,12 +3367,16 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - _Py_LeaveRecursiveCallTstate(tstate); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(self_stackref); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callable[0]); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - if (res_o == NULL) { -- stack_pointer += -2 - oparg; -- assert(WITHIN_STACK_BOUNDS()); -- goto error; -+ JUMP_TO_LABEL(error); - } - res = PyStackRef_FromPyObjectSteal(res_o); - } -@@ -2621,24 +3385,32 @@ - _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); - if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { -- stack_pointer[-2 - oparg] = res; -- stack_pointer += -1 - oparg; -+ stack_pointer[0] = res; -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = _Py_HandlePending(tstate); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err != 0) goto error; -- stack_pointer += 1 + oparg; -+ if (err != 0) { -+ JUMP_TO_LABEL(error); -+ } -+ stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - } - } -- stack_pointer[-2 - oparg] = res; -- stack_pointer += -1 - oparg; -+ stack_pointer[0] = res; -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(CALL_METHOD_DESCRIPTOR_O) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_METHOD_DESCRIPTOR_O; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(CALL_METHOD_DESCRIPTOR_O); -@@ -2656,21 +3428,42 @@ - callable = &stack_pointer[-2 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o; -- DEOPT_IF(total_args != 2, CALL); -- DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL); -+ if (total_args != 2) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } -+ if (!Py_IS_TYPE(method, &PyMethodDescr_Type)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - PyMethodDef *meth = method->d_method; -- DEOPT_IF(meth->ml_flags != METH_O, CALL); -+ if (meth->ml_flags != METH_O) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - // CPython promises to check all non-vectorcall function calls. -- DEOPT_IF(tstate->c_recursion_remaining <= 0, CALL); -- _PyStackRef arg_stackref = args[1]; -- _PyStackRef self_stackref = args[0]; -- DEOPT_IF(!Py_IS_TYPE(PyStackRef_AsPyObjectBorrow(self_stackref), -- method->d_common.d_type), CALL); -+ if (tstate->c_recursion_remaining <= 0) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } -+ _PyStackRef arg_stackref = arguments[1]; -+ _PyStackRef self_stackref = arguments[0]; -+ if (!Py_IS_TYPE(PyStackRef_AsPyObjectBorrow(self_stackref), -+ method->d_common.d_type)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - STAT_INC(CALL, hit); - PyCFunction cfunc = meth->ml_meth; - _Py_EnterRecursiveCallTstateUnchecked(tstate); -@@ -2681,13 +3474,15 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - _Py_LeaveRecursiveCallTstate(tstate); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); -- PyStackRef_CLOSE(self_stackref); -- PyStackRef_CLOSE(arg_stackref); - PyStackRef_CLOSE(callable[0]); -+ PyStackRef_XCLOSE(self_or_null[0]); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); -+ } - if (res_o == NULL) { - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); -- goto error; -+ JUMP_TO_LABEL(error); - } - res = PyStackRef_FromPyObjectSteal(res_o); - } -@@ -2702,7 +3497,9 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = _Py_HandlePending(tstate); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err != 0) goto error; -+ if (err != 0) { -+ JUMP_TO_LABEL(error); -+ } - stack_pointer += 1 + oparg; - assert(WITHIN_STACK_BOUNDS()); - } -@@ -2714,9 +3511,16 @@ - } - - TARGET(CALL_NON_PY_GENERAL) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_NON_PY_GENERAL; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(CALL_NON_PY_GENERAL); -+ opcode = CALL_NON_PY_GENERAL; - static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); - _PyStackRef *callable; - _PyStackRef *self_or_null; -@@ -2728,8 +3532,16 @@ - { - callable = &stack_pointer[-2 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); -- DEOPT_IF(PyFunction_Check(callable_o), CALL); -- DEOPT_IF(Py_TYPE(callable_o) == &PyMethod_Type, CALL); -+ if (PyFunction_Check(callable_o)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } -+ if (Py_TYPE(callable_o) == &PyMethod_Type) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - } - // _CALL_NON_PY_GENERAL - { -@@ -2740,23 +3552,22 @@ - #endif - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - /* Callable is not a normal Python function */ -- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable[0]); -- PyStackRef_CLOSE(self_or_null[0]); -+ PyStackRef_XCLOSE(self_or_null[0]); - for (int _i = oparg; --_i >= 0;) { - PyStackRef_CLOSE(args[_i]); - } -- { -- stack_pointer += -2 - oparg; -- assert(WITHIN_STACK_BOUNDS()); -- goto error; -- } -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_LABEL(error); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = PyObject_Vectorcall( -@@ -2767,13 +3578,14 @@ - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - PyStackRef_CLOSE(callable[0]); -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -+ PyStackRef_XCLOSE(self_or_null[0]); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); - } - if (res_o == NULL) { - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); -- goto error; -+ JUMP_TO_LABEL(error); - } - res = PyStackRef_FromPyObjectSteal(res_o); - } -@@ -2788,7 +3600,9 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = _Py_HandlePending(tstate); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err != 0) goto error; -+ if (err != 0) { -+ JUMP_TO_LABEL(error); -+ } - stack_pointer += 1 + oparg; - assert(WITHIN_STACK_BOUNDS()); - } -@@ -2800,7 +3614,13 @@ - } - - TARGET(CALL_PY_EXACT_ARGS) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_PY_EXACT_ARGS; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(CALL_PY_EXACT_ARGS); - static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); -@@ -2811,16 +3631,28 @@ - /* Skip 1 cache entry */ - // _CHECK_PEP_523 - { -- DEOPT_IF(tstate->interp->eval_frame, CALL); -+ if (tstate->interp->eval_frame) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - } - // _CHECK_FUNCTION_VERSION - { - callable = &stack_pointer[-2 - oparg]; - uint32_t func_version = read_u32(&this_instr[2].cache); - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); -- DEOPT_IF(!PyFunction_Check(callable_o), CALL); -+ if (!PyFunction_Check(callable_o)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - PyFunctionObject *func = (PyFunctionObject *)callable_o; -- DEOPT_IF(func->func_version != func_version, CALL); -+ if (func->func_version != func_version) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - } - // _CHECK_FUNCTION_EXACT_ARGS - { -@@ -2829,15 +3661,27 @@ - assert(PyFunction_Check(callable_o)); - PyFunctionObject *func = (PyFunctionObject *)callable_o; - PyCodeObject *code = (PyCodeObject *)func->func_code; -- DEOPT_IF(code->co_argcount != oparg + (!PyStackRef_IsNull(self_or_null[0])), CALL); -+ if (code->co_argcount != oparg + (!PyStackRef_IsNull(self_or_null[0]))) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - } - // _CHECK_STACK_SPACE - { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - PyFunctionObject *func = (PyFunctionObject *)callable_o; - PyCodeObject *code = (PyCodeObject *)func->func_code; -- DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL); -- DEOPT_IF(tstate->py_recursion_remaining <= 1, CALL); -+ if (!_PyThreadState_HasStackSpace(tstate, code->co_framesize)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } -+ if (tstate->py_recursion_remaining <= 1) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - } - // _INIT_CALL_PY_EXACT_ARGS - { -@@ -2881,7 +3725,13 @@ - } - - TARGET(CALL_PY_GENERAL) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_PY_GENERAL; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(CALL_PY_GENERAL); - static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); -@@ -2892,16 +3742,28 @@ - /* Skip 1 cache entry */ - // _CHECK_PEP_523 - { -- DEOPT_IF(tstate->interp->eval_frame, CALL); -+ if (tstate->interp->eval_frame) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - } - // _CHECK_FUNCTION_VERSION - { - callable = &stack_pointer[-2 - oparg]; - uint32_t func_version = read_u32(&this_instr[2].cache); - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); -- DEOPT_IF(!PyFunction_Check(callable_o), CALL); -+ if (!PyFunction_Check(callable_o)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - PyFunctionObject *func = (PyFunctionObject *)callable_o; -- DEOPT_IF(func->func_version != func_version, CALL); -+ if (func->func_version != func_version) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - } - // _PY_FRAME_GENERAL - { -@@ -2927,7 +3789,7 @@ - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); - if (temp == NULL) { -- goto error; -+ JUMP_TO_LABEL(error); - } - new_frame = temp; - } -@@ -2959,6 +3821,12 @@ - } - - TARGET(CALL_STR_1) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_STR_1; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(CALL_STR_1); -@@ -2977,14 +3845,28 @@ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); - PyObject *arg_o = PyStackRef_AsPyObjectBorrow(arg); - assert(oparg == 1); -- DEOPT_IF(!PyStackRef_IsNull(null), CALL); -- DEOPT_IF(callable_o != (PyObject *)&PyUnicode_Type, CALL); -+ if (!PyStackRef_IsNull(null)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } -+ if (callable_o != (PyObject *)&PyUnicode_Type) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - STAT_INC(CALL, hit); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = PyObject_Str(arg_o); - stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -3; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(arg); -- if (res_o == NULL) goto pop_3_error; -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (res_o == NULL) { -+ JUMP_TO_LABEL(error); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - } - // _CHECK_PERIODIC -@@ -2992,24 +3874,32 @@ - _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); - if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { -- stack_pointer[-3] = res; -- stack_pointer += -2; -+ stack_pointer[0] = res; -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = _Py_HandlePending(tstate); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err != 0) goto error; -- stack_pointer += 2; -+ if (err != 0) { -+ JUMP_TO_LABEL(error); -+ } -+ stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - } - } -- stack_pointer[-3] = res; -- stack_pointer += -2; -+ stack_pointer[0] = res; -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(CALL_TUPLE_1) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_TUPLE_1; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(CALL_TUPLE_1); -@@ -3028,14 +3918,28 @@ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); - PyObject *arg_o = PyStackRef_AsPyObjectBorrow(arg); - assert(oparg == 1); -- DEOPT_IF(!PyStackRef_IsNull(null), CALL); -- DEOPT_IF(callable_o != (PyObject *)&PyTuple_Type, CALL); -+ if (!PyStackRef_IsNull(null)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } -+ if (callable_o != (PyObject *)&PyTuple_Type) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - STAT_INC(CALL, hit); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = PySequence_Tuple(arg_o); - stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -3; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(arg); -- if (res_o == NULL) goto pop_3_error; -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (res_o == NULL) { -+ JUMP_TO_LABEL(error); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - } - // _CHECK_PERIODIC -@@ -3043,24 +3947,32 @@ - _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - QSBR_QUIESCENT_STATE(tstate); - if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { -- stack_pointer[-3] = res; -- stack_pointer += -2; -+ stack_pointer[0] = res; -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = _Py_HandlePending(tstate); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err != 0) goto error; -- stack_pointer += 2; -+ if (err != 0) { -+ JUMP_TO_LABEL(error); -+ } -+ stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - } - } -- stack_pointer[-3] = res; -- stack_pointer += -2; -+ stack_pointer[0] = res; -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(CALL_TYPE_1) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CALL_TYPE_1; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(CALL_TYPE_1); -@@ -3077,18 +3989,32 @@ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); - PyObject *arg_o = PyStackRef_AsPyObjectBorrow(arg); - assert(oparg == 1); -- DEOPT_IF(!PyStackRef_IsNull(null), CALL); -- DEOPT_IF(callable_o != (PyObject *)&PyType_Type, CALL); -+ if (!PyStackRef_IsNull(null)) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } -+ if (callable_o != (PyObject *)&PyType_Type) { -+ UPDATE_MISS_STATS(CALL); -+ assert(_PyOpcode_Deopt[opcode] == (CALL)); -+ JUMP_TO_PREDICTED(CALL); -+ } - STAT_INC(CALL, hit); - res = PyStackRef_FromPyObjectSteal(Py_NewRef(Py_TYPE(arg_o))); -- PyStackRef_CLOSE(arg); - stack_pointer[-3] = res; - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(arg); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - DISPATCH(); - } - - TARGET(CHECK_EG_MATCH) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CHECK_EG_MATCH; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(CHECK_EG_MATCH); -@@ -3106,19 +4032,23 @@ - if (err < 0) { - PyStackRef_CLOSE(exc_value_st); - PyStackRef_CLOSE(match_type_st); -- goto pop_2_error; -+ JUMP_TO_LABEL(pop_2_error); - } - PyObject *match_o = NULL; - PyObject *rest_o = NULL; - _PyFrame_SetStackPointer(frame, stack_pointer); -- int res = _PyEval_ExceptionGroupMatch(exc_value, match_type, -+ int res = _PyEval_ExceptionGroupMatch(frame, exc_value, match_type, - &match_o, &rest_o); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(exc_value_st); - PyStackRef_CLOSE(match_type_st); -- if (res < 0) goto pop_2_error; -+ if (res < 0) { -+ JUMP_TO_LABEL(pop_2_error); -+ } - assert((match_o == NULL) == (rest_o == NULL)); -- if (match_o == NULL) goto pop_2_error; -+ if (match_o == NULL) { -+ JUMP_TO_LABEL(pop_2_error); -+ } - if (!Py_IsNone(match_o)) { - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); -@@ -3136,6 +4066,10 @@ - } - - TARGET(CHECK_EXC_MATCH) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CHECK_EXC_MATCH; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(CHECK_EXC_MATCH); -@@ -3152,7 +4086,7 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - if (err < 0) { - PyStackRef_CLOSE(right); -- goto pop_1_error; -+ JUMP_TO_LABEL(pop_1_error); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - int res = PyErr_GivenExceptionMatches(left_o, right_o); -@@ -3164,8 +4098,13 @@ - } - - TARGET(CLEANUP_THROW) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CLEANUP_THROW; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(CLEANUP_THROW); - _PyStackRef sub_iter_st; -@@ -3177,7 +4116,9 @@ - last_sent_val_st = stack_pointer[-2]; - sub_iter_st = stack_pointer[-3]; - PyObject *exc_value = PyStackRef_AsPyObjectBorrow(exc_value_st); -+ #ifndef Py_TAIL_CALL_INTERP - assert(throwflag); -+ #endif - assert(exc_value && PyExceptionInstance_Check(exc_value)); - _PyFrame_SetStackPointer(frame, stack_pointer); - int matches = PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration); -@@ -3194,7 +4135,8 @@ - _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value)); - monitor_reraise(tstate, frame, this_instr); - stack_pointer = _PyFrame_GetStackPointer(frame); -- goto exception_unwind; -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ JUMP_TO_LABEL(exception_unwind); - } - stack_pointer[-3] = none; - stack_pointer[-2] = value; -@@ -3204,10 +4146,14 @@ - } - - TARGET(COMPARE_OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = COMPARE_OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(COMPARE_OP); -- PREDICTED(COMPARE_OP); -+ PREDICTED_COMPARE_OP:; - _Py_CODEUNIT* const this_instr = next_instr - 2; - (void)this_instr; - _PyStackRef left; -@@ -3219,7 +4165,7 @@ - left = stack_pointer[-2]; - uint16_t counter = read_u16(&this_instr[1].cache); - (void)counter; -- #if ENABLE_SPECIALIZATION -+ #if ENABLE_SPECIALIZATION_FT - if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { - next_instr = this_instr; - _PyFrame_SetStackPointer(frame, stack_pointer); -@@ -3229,7 +4175,7 @@ - } - OPCODE_DEFERRED_INC(COMPARE_OP); - ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); -- #endif /* ENABLE_SPECIALIZATION */ -+ #endif /* ENABLE_SPECIALIZATION_FT */ - } - // _COMPARE_OP - { -@@ -3241,15 +4187,19 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(left); - PyStackRef_CLOSE(right); -- if (res_o == NULL) goto pop_2_error; -+ if (res_o == NULL) { -+ JUMP_TO_LABEL(pop_2_error); -+ } - if (oparg & 16) { - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - int res_bool = PyObject_IsTrue(res_o); -- stack_pointer = _PyFrame_GetStackPointer(frame); - Py_DECREF(res_o); -- if (res_bool < 0) goto error; -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (res_bool < 0) { -+ JUMP_TO_LABEL(error); -+ } - res = res_bool ? PyStackRef_True : PyStackRef_False; - } - else { -@@ -3265,6 +4215,12 @@ - } - - TARGET(COMPARE_OP_FLOAT) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = COMPARE_OP_FLOAT; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(COMPARE_OP_FLOAT); -@@ -3278,8 +4234,16 @@ - left = stack_pointer[-2]; - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -- DEOPT_IF(!PyFloat_CheckExact(left_o), COMPARE_OP); -- DEOPT_IF(!PyFloat_CheckExact(right_o), COMPARE_OP); -+ if (!PyFloat_CheckExact(left_o)) { -+ UPDATE_MISS_STATS(COMPARE_OP); -+ assert(_PyOpcode_Deopt[opcode] == (COMPARE_OP)); -+ JUMP_TO_PREDICTED(COMPARE_OP); -+ } -+ if (!PyFloat_CheckExact(right_o)) { -+ UPDATE_MISS_STATS(COMPARE_OP); -+ assert(_PyOpcode_Deopt[opcode] == (COMPARE_OP)); -+ JUMP_TO_PREDICTED(COMPARE_OP); -+ } - } - /* Skip 1 cache entry */ - // _COMPARE_OP_FLOAT -@@ -3303,6 +4267,12 @@ - } - - TARGET(COMPARE_OP_INT) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = COMPARE_OP_INT; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(COMPARE_OP_INT); -@@ -3316,16 +4286,32 @@ - left = stack_pointer[-2]; - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -- DEOPT_IF(!PyLong_CheckExact(left_o), COMPARE_OP); -- DEOPT_IF(!PyLong_CheckExact(right_o), COMPARE_OP); -+ if (!PyLong_CheckExact(left_o)) { -+ UPDATE_MISS_STATS(COMPARE_OP); -+ assert(_PyOpcode_Deopt[opcode] == (COMPARE_OP)); -+ JUMP_TO_PREDICTED(COMPARE_OP); -+ } -+ if (!PyLong_CheckExact(right_o)) { -+ UPDATE_MISS_STATS(COMPARE_OP); -+ assert(_PyOpcode_Deopt[opcode] == (COMPARE_OP)); -+ JUMP_TO_PREDICTED(COMPARE_OP); -+ } - } - /* Skip 1 cache entry */ - // _COMPARE_OP_INT - { - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -- DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left_o), COMPARE_OP); -- DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)right_o), COMPARE_OP); -+ if (!_PyLong_IsCompact((PyLongObject *)left_o)) { -+ UPDATE_MISS_STATS(COMPARE_OP); -+ assert(_PyOpcode_Deopt[opcode] == (COMPARE_OP)); -+ JUMP_TO_PREDICTED(COMPARE_OP); -+ } -+ if (!_PyLong_IsCompact((PyLongObject *)right_o)) { -+ UPDATE_MISS_STATS(COMPARE_OP); -+ assert(_PyOpcode_Deopt[opcode] == (COMPARE_OP)); -+ JUMP_TO_PREDICTED(COMPARE_OP); -+ } - STAT_INC(COMPARE_OP, hit); - assert(_PyLong_DigitCount((PyLongObject *)left_o) <= 1 && - _PyLong_DigitCount((PyLongObject *)right_o) <= 1); -@@ -3345,6 +4331,12 @@ - } - - TARGET(COMPARE_OP_STR) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = COMPARE_OP_STR; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(COMPARE_OP_STR); -@@ -3358,8 +4350,16 @@ - left = stack_pointer[-2]; - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -- DEOPT_IF(!PyUnicode_CheckExact(left_o), COMPARE_OP); -- DEOPT_IF(!PyUnicode_CheckExact(right_o), COMPARE_OP); -+ if (!PyUnicode_CheckExact(left_o)) { -+ UPDATE_MISS_STATS(COMPARE_OP); -+ assert(_PyOpcode_Deopt[opcode] == (COMPARE_OP)); -+ JUMP_TO_PREDICTED(COMPARE_OP); -+ } -+ if (!PyUnicode_CheckExact(right_o)) { -+ UPDATE_MISS_STATS(COMPARE_OP); -+ assert(_PyOpcode_Deopt[opcode] == (COMPARE_OP)); -+ JUMP_TO_PREDICTED(COMPARE_OP); -+ } - } - /* Skip 1 cache entry */ - // _COMPARE_OP_STR -@@ -3384,10 +4384,14 @@ - } - - TARGET(CONTAINS_OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CONTAINS_OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(CONTAINS_OP); -- PREDICTED(CONTAINS_OP); -+ PREDICTED_CONTAINS_OP:; - _Py_CODEUNIT* const this_instr = next_instr - 2; - (void)this_instr; - _PyStackRef left; -@@ -3420,7 +4424,9 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(left); - PyStackRef_CLOSE(right); -- if (res < 0) goto pop_2_error; -+ if (res < 0) { -+ JUMP_TO_LABEL(pop_2_error); -+ } - b = (res ^ oparg) ? PyStackRef_True : PyStackRef_False; - } - stack_pointer[-2] = b; -@@ -3430,6 +4436,12 @@ - } - - TARGET(CONTAINS_OP_DICT) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CONTAINS_OP_DICT; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(CONTAINS_OP_DICT); -@@ -3442,14 +4454,20 @@ - left = stack_pointer[-2]; - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -- DEOPT_IF(!PyDict_CheckExact(right_o), CONTAINS_OP); -+ if (!PyDict_CheckExact(right_o)) { -+ UPDATE_MISS_STATS(CONTAINS_OP); -+ assert(_PyOpcode_Deopt[opcode] == (CONTAINS_OP)); -+ JUMP_TO_PREDICTED(CONTAINS_OP); -+ } - STAT_INC(CONTAINS_OP, hit); - _PyFrame_SetStackPointer(frame, stack_pointer); - int res = PyDict_Contains(right_o, left_o); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(left); - PyStackRef_CLOSE(right); -- if (res < 0) goto pop_2_error; -+ if (res < 0) { -+ JUMP_TO_LABEL(pop_2_error); -+ } - b = (res ^ oparg) ? PyStackRef_True : PyStackRef_False; - stack_pointer[-2] = b; - stack_pointer += -1; -@@ -3458,6 +4476,12 @@ - } - - TARGET(CONTAINS_OP_SET) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CONTAINS_OP_SET; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(CONTAINS_OP_SET); -@@ -3470,7 +4494,11 @@ - left = stack_pointer[-2]; - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); -- DEOPT_IF(!(PySet_CheckExact(right_o) || PyFrozenSet_CheckExact(right_o)), CONTAINS_OP); -+ if (!(PySet_CheckExact(right_o) || PyFrozenSet_CheckExact(right_o))) { -+ UPDATE_MISS_STATS(CONTAINS_OP); -+ assert(_PyOpcode_Deopt[opcode] == (CONTAINS_OP)); -+ JUMP_TO_PREDICTED(CONTAINS_OP); -+ } - STAT_INC(CONTAINS_OP, hit); - // Note: both set and frozenset use the same seq_contains method! - _PyFrame_SetStackPointer(frame, stack_pointer); -@@ -3478,7 +4506,9 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(left); - PyStackRef_CLOSE(right); -- if (res < 0) goto pop_2_error; -+ if (res < 0) { -+ JUMP_TO_LABEL(pop_2_error); -+ } - b = (res ^ oparg) ? PyStackRef_True : PyStackRef_False; - stack_pointer[-2] = b; - stack_pointer += -1; -@@ -3487,6 +4517,10 @@ - } - - TARGET(CONVERT_VALUE) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = CONVERT_VALUE; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(CONVERT_VALUE); -@@ -3499,14 +4533,26 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *result_o = conv_fn(PyStackRef_AsPyObjectBorrow(value)); - stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(value); -- if (result_o == NULL) goto pop_1_error; -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (result_o == NULL) { -+ JUMP_TO_LABEL(error); -+ } - result = PyStackRef_FromPyObjectSteal(result_o); -- stack_pointer[-1] = result; -+ stack_pointer[0] = result; -+ stack_pointer += 1; -+ assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(COPY) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = COPY; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(COPY); -@@ -3522,6 +4568,10 @@ - } - - TARGET(COPY_FREE_VARS) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = COPY_FREE_VARS; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(COPY_FREE_VARS); -@@ -3540,6 +4590,10 @@ - } - - TARGET(DELETE_ATTR) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = DELETE_ATTR; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(DELETE_ATTR); -@@ -3550,13 +4604,19 @@ - int err = PyObject_DelAttr(PyStackRef_AsPyObjectBorrow(owner), name); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(owner); -- if (err) goto pop_1_error; -+ if (err) { -+ JUMP_TO_LABEL(pop_1_error); -+ } - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(DELETE_DEREF) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = DELETE_DEREF; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(DELETE_DEREF); -@@ -3568,13 +4628,19 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg); - stack_pointer = _PyFrame_GetStackPointer(frame); -- goto error; -+ JUMP_TO_LABEL(error); - } -+ _PyFrame_SetStackPointer(frame, stack_pointer); - Py_DECREF(oldobj); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - DISPATCH(); - } - - TARGET(DELETE_FAST) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = DELETE_FAST; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(DELETE_FAST); -@@ -3586,13 +4652,21 @@ - PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames, oparg) - ); - stack_pointer = _PyFrame_GetStackPointer(frame); -- goto error; -+ JUMP_TO_LABEL(error); - } -- SETLOCAL(oparg, PyStackRef_NULL); -+ _PyStackRef tmp = GETLOCAL(oparg); -+ GETLOCAL(oparg) = PyStackRef_NULL; -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_XCLOSE(tmp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - DISPATCH(); - } - - TARGET(DELETE_GLOBAL) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = DELETE_GLOBAL; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(DELETE_GLOBAL); -@@ -3602,19 +4676,23 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - // Can't use ERROR_IF here. - if (err < 0) { -- goto error; -+ JUMP_TO_LABEL(error); - } - if (err == 0) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - stack_pointer = _PyFrame_GetStackPointer(frame); -- goto error; -+ JUMP_TO_LABEL(error); - } - DISPATCH(); - } - - TARGET(DELETE_NAME) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = DELETE_NAME; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(DELETE_NAME); -@@ -3626,7 +4704,7 @@ - _PyErr_Format(tstate, PyExc_SystemError, - "no locals when deleting %R", name); - stack_pointer = _PyFrame_GetStackPointer(frame); -- goto error; -+ JUMP_TO_LABEL(error); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - err = PyObject_DelItem(ns, name); -@@ -3638,12 +4716,16 @@ - NAME_ERROR_MSG, - name); - stack_pointer = _PyFrame_GetStackPointer(frame); -- goto error; -+ JUMP_TO_LABEL(error); - } - DISPATCH(); - } - - TARGET(DELETE_SUBSCR) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = DELETE_SUBSCR; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(DELETE_SUBSCR); -@@ -3658,13 +4740,19 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(container); - PyStackRef_CLOSE(sub); -- if (err) goto pop_2_error; -+ if (err) { -+ JUMP_TO_LABEL(pop_2_error); -+ } - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(DICT_MERGE) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = DICT_MERGE; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(DICT_MERGE); -@@ -3685,7 +4773,7 @@ - _PyEval_FormatKwargsError(tstate, callable_o, update_o); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(update); -- goto pop_1_error; -+ JUMP_TO_LABEL(pop_1_error); - } - PyStackRef_CLOSE(update); - stack_pointer += -1; -@@ -3694,6 +4782,10 @@ - } - - TARGET(DICT_UPDATE) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = DICT_UPDATE; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(DICT_UPDATE); -@@ -3718,7 +4810,7 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - } - PyStackRef_CLOSE(update); -- goto pop_1_error; -+ JUMP_TO_LABEL(pop_1_error); - } - PyStackRef_CLOSE(update); - stack_pointer += -1; -@@ -3727,8 +4819,13 @@ - } - - TARGET(END_ASYNC_FOR) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = END_ASYNC_FOR; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(END_ASYNC_FOR); - _PyStackRef awaitable_st; -@@ -3750,7 +4847,8 @@ - _PyErr_SetRaisedException(tstate, exc); - monitor_reraise(tstate, frame, this_instr); - stack_pointer = _PyFrame_GetStackPointer(frame); -- goto exception_unwind; -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ JUMP_TO_LABEL(exception_unwind); - } - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); -@@ -3758,18 +4856,32 @@ - } - - TARGET(END_FOR) { -- frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = END_FOR; -+ (void)(opcode); -+ #endif - next_instr += 1; - INSTRUCTION_STATS(END_FOR); - _PyStackRef value; - value = stack_pointer[-1]; -- PyStackRef_CLOSE(value); -+ /* Don't update instr_ptr, so that POP_ITER sees -+ * the FOR_ITER as the previous instruction. -+ * This has the benign side effect that if value is -+ * finalized it will see the location as the FOR_ITER's. -+ */ - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(value); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - DISPATCH(); - } - - TARGET(END_SEND) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = END_SEND; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(END_SEND); -@@ -3788,10 +4900,16 @@ - } - - TARGET(ENTER_EXECUTOR) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = ENTER_EXECUTOR; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(ENTER_EXECUTOR); -+ opcode = ENTER_EXECUTOR; - #ifdef _Py_TIER2 - PyCodeObject *code = _PyFrame_GetCode(frame); - _PyExecutorObject *executor = code->co_executors->executors[oparg & 255]; -@@ -3821,6 +4939,10 @@ - } - - TARGET(EXIT_INIT_CHECK) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = EXIT_INIT_CHECK; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(EXIT_INIT_CHECK); -@@ -3833,7 +4955,7 @@ - "__init__() should return None, not '%.200s'", - Py_TYPE(PyStackRef_AsPyObjectBorrow(should_be_none))->tp_name); - stack_pointer = _PyFrame_GetStackPointer(frame); -- goto error; -+ JUMP_TO_LABEL(error); - } - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); -@@ -3841,9 +4963,14 @@ - } - - TARGET(EXTENDED_ARG) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = EXTENDED_ARG; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(EXTENDED_ARG); -+ opcode = EXTENDED_ARG; - assert(oparg); - opcode = next_instr->op.code; - oparg = oparg << 8 | next_instr->op.arg; -@@ -3852,6 +4979,10 @@ - } - - TARGET(FORMAT_SIMPLE) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = FORMAT_SIMPLE; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(FORMAT_SIMPLE); -@@ -3865,18 +4996,32 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = PyObject_Format(value_o, NULL); - stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(value); -- if (res_o == NULL) goto pop_1_error; -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (res_o == NULL) { -+ JUMP_TO_LABEL(error); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - } - else { - res = value; -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); - } -- stack_pointer[-1] = res; -+ stack_pointer[0] = res; -+ stack_pointer += 1; -+ assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(FORMAT_WITH_SPEC) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = FORMAT_WITH_SPEC; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(FORMAT_WITH_SPEC); -@@ -3890,7 +5035,9 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(value); - PyStackRef_CLOSE(fmt_spec); -- if (res_o == NULL) goto pop_2_error; -+ if (res_o == NULL) { -+ JUMP_TO_LABEL(pop_2_error); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -3899,10 +5046,14 @@ - } - - TARGET(FOR_ITER) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = FOR_ITER; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(FOR_ITER); -- PREDICTED(FOR_ITER); -+ PREDICTED_FOR_ITER:; - _Py_CODEUNIT* const this_instr = next_instr - 2; - (void)this_instr; - _PyStackRef iter; -@@ -3937,7 +5088,7 @@ - int matches = _PyErr_ExceptionMatches(tstate, PyExc_StopIteration); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (!matches) { -- goto error; -+ JUMP_TO_LABEL(error); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyEval_MonitorRaise(tstate, frame, this_instr); -@@ -3947,10 +5098,8 @@ - /* iterator ended normally */ - assert(next_instr[oparg].op.code == END_FOR || - next_instr[oparg].op.code == INSTRUMENTED_END_FOR); -- PyStackRef_CLOSE(iter); -- STACK_SHRINK(1); -- /* Jump forward oparg, then skip following END_FOR and POP_TOP instruction */ -- JUMPBY(oparg + 2); -+ /* Jump forward oparg, then skip following END_FOR */ -+ JUMPBY(oparg + 1); - DISPATCH(); - } - next = PyStackRef_FromPyObjectSteal(next_o); -@@ -3963,6 +5112,12 @@ - } - - TARGET(FOR_ITER_GEN) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = FOR_ITER_GEN; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(FOR_ITER_GEN); -@@ -3973,14 +5128,26 @@ - /* Skip 1 cache entry */ - // _CHECK_PEP_523 - { -- DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); -+ if (tstate->interp->eval_frame) { -+ UPDATE_MISS_STATS(FOR_ITER); -+ assert(_PyOpcode_Deopt[opcode] == (FOR_ITER)); -+ JUMP_TO_PREDICTED(FOR_ITER); -+ } - } - // _FOR_ITER_GEN_FRAME - { - iter = stack_pointer[-1]; - PyGenObject *gen = (PyGenObject *)PyStackRef_AsPyObjectBorrow(iter); -- DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); -- DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, FOR_ITER); -+ if (Py_TYPE(gen) != &PyGen_Type) { -+ UPDATE_MISS_STATS(FOR_ITER); -+ assert(_PyOpcode_Deopt[opcode] == (FOR_ITER)); -+ JUMP_TO_PREDICTED(FOR_ITER); -+ } -+ if (gen->gi_frame_state >= FRAME_EXECUTING) { -+ UPDATE_MISS_STATS(FOR_ITER); -+ assert(_PyOpcode_Deopt[opcode] == (FOR_ITER)); -+ JUMP_TO_PREDICTED(FOR_ITER); -+ } - STAT_INC(FOR_ITER, hit); - gen_frame = &gen->gi_iframe; - _PyFrame_StackPush(gen_frame, PyStackRef_None); -@@ -4011,6 +5178,12 @@ - } - - TARGET(FOR_ITER_LIST) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = FOR_ITER_LIST; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(FOR_ITER_LIST); -@@ -4021,7 +5194,11 @@ - // _ITER_CHECK_LIST - { - iter = stack_pointer[-1]; -- DEOPT_IF(Py_TYPE(PyStackRef_AsPyObjectBorrow(iter)) != &PyListIter_Type, FOR_ITER); -+ if (Py_TYPE(PyStackRef_AsPyObjectBorrow(iter)) != &PyListIter_Type) { -+ UPDATE_MISS_STATS(FOR_ITER); -+ assert(_PyOpcode_Deopt[opcode] == (FOR_ITER)); -+ JUMP_TO_PREDICTED(FOR_ITER); -+ } - } - // _ITER_JUMP_LIST - { -@@ -4035,13 +5212,13 @@ - #ifndef Py_GIL_DISABLED - if (seq != NULL) { - it->it_seq = NULL; -+ _PyFrame_SetStackPointer(frame, stack_pointer); - Py_DECREF(seq); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - } - #endif -- PyStackRef_CLOSE(iter); -- STACK_SHRINK(1); -- /* Jump forward oparg, then skip following END_FOR and POP_TOP instructions */ -- JUMPBY(oparg + 2); -+ /* Jump forward oparg, then skip following END_FOR instruction */ -+ JUMPBY(oparg + 1); - DISPATCH(); - } - } -@@ -4062,6 +5239,12 @@ - } - - TARGET(FOR_ITER_RANGE) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = FOR_ITER_RANGE; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(FOR_ITER_RANGE); -@@ -4073,7 +5256,11 @@ - { - iter = stack_pointer[-1]; - _PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter); -- DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); -+ if (Py_TYPE(r) != &PyRangeIter_Type) { -+ UPDATE_MISS_STATS(FOR_ITER); -+ assert(_PyOpcode_Deopt[opcode] == (FOR_ITER)); -+ JUMP_TO_PREDICTED(FOR_ITER); -+ } - } - // _ITER_JUMP_RANGE - { -@@ -4081,10 +5268,8 @@ - assert(Py_TYPE(r) == &PyRangeIter_Type); - STAT_INC(FOR_ITER, hit); - if (r->len <= 0) { -- STACK_SHRINK(1); -- PyStackRef_CLOSE(iter); -- // Jump over END_FOR and POP_TOP instructions. -- JUMPBY(oparg + 2); -+ // Jump over END_FOR instruction. -+ JUMPBY(oparg + 1); - DISPATCH(); - } - } -@@ -4097,7 +5282,9 @@ - r->start = value + r->step; - r->len--; - PyObject *res = PyLong_FromLong(value); -- if (res == NULL) goto error; -+ if (res == NULL) { -+ JUMP_TO_LABEL(error); -+ } - next = PyStackRef_FromPyObjectSteal(res); - } - stack_pointer[0] = next; -@@ -4107,6 +5294,12 @@ - } - - TARGET(FOR_ITER_TUPLE) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = FOR_ITER_TUPLE; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(FOR_ITER_TUPLE); -@@ -4117,7 +5310,11 @@ - // _ITER_CHECK_TUPLE - { - iter = stack_pointer[-1]; -- DEOPT_IF(Py_TYPE(PyStackRef_AsPyObjectBorrow(iter)) != &PyTupleIter_Type, FOR_ITER); -+ if (Py_TYPE(PyStackRef_AsPyObjectBorrow(iter)) != &PyTupleIter_Type) { -+ UPDATE_MISS_STATS(FOR_ITER); -+ assert(_PyOpcode_Deopt[opcode] == (FOR_ITER)); -+ JUMP_TO_PREDICTED(FOR_ITER); -+ } - } - // _ITER_JUMP_TUPLE - { -@@ -4129,12 +5326,12 @@ - if (seq == NULL || it->it_index >= PyTuple_GET_SIZE(seq)) { - if (seq != NULL) { - it->it_seq = NULL; -+ _PyFrame_SetStackPointer(frame, stack_pointer); - Py_DECREF(seq); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - } -- PyStackRef_CLOSE(iter); -- STACK_SHRINK(1); -- /* Jump forward oparg, then skip following END_FOR and POP_TOP instructions */ -- JUMPBY(oparg + 2); -+ /* Jump forward oparg, then skip following END_FOR instruction */ -+ JUMPBY(oparg + 1); - DISPATCH(); - } - } -@@ -4155,6 +5352,10 @@ - } - - TARGET(GET_AITER) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = GET_AITER; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(GET_AITER); -@@ -4176,13 +5377,15 @@ - type->tp_name); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(obj); -- goto pop_1_error; -+ JUMP_TO_LABEL(pop_1_error); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - iter_o = (*getter)(obj_o); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(obj); -- if (iter_o == NULL) goto pop_1_error; -+ if (iter_o == NULL) { -+ JUMP_TO_LABEL(pop_1_error); -+ } - if (Py_TYPE(iter_o)->tp_as_async == NULL || - Py_TYPE(iter_o)->tp_as_async->am_anext == NULL) { - stack_pointer += -1; -@@ -4192,9 +5395,9 @@ - "'async for' received an object from __aiter__ " - "that does not implement __anext__: %.100s", - Py_TYPE(iter_o)->tp_name); -- stack_pointer = _PyFrame_GetStackPointer(frame); - Py_DECREF(iter_o); -- goto error; -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ JUMP_TO_LABEL(error); - } - iter = PyStackRef_FromPyObjectSteal(iter_o); - stack_pointer[-1] = iter; -@@ -4202,6 +5405,10 @@ - } - - TARGET(GET_ANEXT) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = GET_ANEXT; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(GET_ANEXT); -@@ -4212,7 +5419,7 @@ - PyObject *awaitable_o = _PyEval_GetANext(PyStackRef_AsPyObjectBorrow(aiter)); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (awaitable_o == NULL) { -- goto error; -+ JUMP_TO_LABEL(error); - } - awaitable = PyStackRef_FromPyObjectSteal(awaitable_o); - stack_pointer[0] = awaitable; -@@ -4222,6 +5429,10 @@ - } - - TARGET(GET_AWAITABLE) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = GET_AWAITABLE; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(GET_AWAITABLE); -@@ -4232,13 +5443,19 @@ - PyObject *iter_o = _PyEval_GetAwaitable(PyStackRef_AsPyObjectBorrow(iterable), oparg); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(iterable); -- if (iter_o == NULL) goto pop_1_error; -+ if (iter_o == NULL) { -+ JUMP_TO_LABEL(pop_1_error); -+ } - iter = PyStackRef_FromPyObjectSteal(iter_o); - stack_pointer[-1] = iter; - DISPATCH(); - } - - TARGET(GET_ITER) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = GET_ITER; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(GET_ITER); -@@ -4250,13 +5467,19 @@ - PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable)); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(iterable); -- if (iter_o == NULL) goto pop_1_error; -+ if (iter_o == NULL) { -+ JUMP_TO_LABEL(pop_1_error); -+ } - iter = PyStackRef_FromPyObjectSteal(iter_o); - stack_pointer[-1] = iter; - DISPATCH(); - } - - TARGET(GET_LEN) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = GET_LEN; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(GET_LEN); -@@ -4267,9 +5490,13 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - Py_ssize_t len_i = PyObject_Length(PyStackRef_AsPyObjectBorrow(obj)); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (len_i < 0) goto error; -+ if (len_i < 0) { -+ JUMP_TO_LABEL(error); -+ } - PyObject *len_o = PyLong_FromSsize_t(len_i); -- if (len_o == NULL) goto error; -+ if (len_o == NULL) { -+ JUMP_TO_LABEL(error); -+ } - len = PyStackRef_FromPyObjectSteal(len_o); - stack_pointer[0] = len; - stack_pointer += 1; -@@ -4278,6 +5505,10 @@ - } - - TARGET(GET_YIELD_FROM_ITER) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = GET_YIELD_FROM_ITER; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(GET_YIELD_FROM_ITER); -@@ -4296,7 +5527,7 @@ - "cannot 'yield from' a coroutine object " - "in a non-coroutine generator"); - stack_pointer = _PyFrame_GetStackPointer(frame); -- goto error; -+ JUMP_TO_LABEL(error); - } - iter = iterable; - } -@@ -4310,7 +5541,7 @@ - PyObject *iter_o = PyObject_GetIter(iterable_o); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (iter_o == NULL) { -- goto error; -+ JUMP_TO_LABEL(error); - } - iter = PyStackRef_FromPyObjectSteal(iter_o); - PyStackRef_CLOSE(iterable); -@@ -4321,6 +5552,10 @@ - } - - TARGET(IMPORT_FROM) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = IMPORT_FROM; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(IMPORT_FROM); -@@ -4331,7 +5566,9 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = _PyEval_ImportFrom(tstate, PyStackRef_AsPyObjectBorrow(from), name); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (res_o == NULL) goto error; -+ if (res_o == NULL) { -+ JUMP_TO_LABEL(error); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; -@@ -4340,6 +5577,10 @@ - } - - TARGET(IMPORT_NAME) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = IMPORT_NAME; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(IMPORT_NAME); -@@ -4356,7 +5597,9 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(level); - PyStackRef_CLOSE(fromlist); -- if (res_o == NULL) goto pop_2_error; -+ if (res_o == NULL) { -+ JUMP_TO_LABEL(pop_2_error); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -4365,10 +5608,16 @@ - } - - TARGET(INSTRUMENTED_CALL) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = INSTRUMENTED_CALL; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(INSTRUMENTED_CALL); -+ opcode = INSTRUMENTED_CALL; - _PyStackRef *callable; - _PyStackRef *self_or_null; - _PyStackRef *args; -@@ -4383,6 +5632,8 @@ - callable = &stack_pointer[-2 - oparg]; - func = &stack_pointer[-2 - oparg]; - maybe_self = &stack_pointer[-1 - oparg]; -+ args = &stack_pointer[-oparg]; -+ (void)args; - if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - PyObject *self = ((PyMethodObject *)callable_o)->im_self; -@@ -4390,7 +5641,9 @@ - PyObject *method = ((PyMethodObject *)callable_o)->im_func; - _PyStackRef temp = callable[0]; - func[0] = PyStackRef_FromPyObjectNew(method); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(temp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - } - } - // _MONITOR_CALL -@@ -4418,7 +5671,9 @@ - frame, this_instr, function, arg0 - ); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err) goto error; -+ if (err) { -+ JUMP_TO_LABEL(error); -+ } - } - // _DO_CALL - { -@@ -4427,8 +5682,9 @@ - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - // oparg counts all of the args, but *not* self: - int total_args = oparg; -+ _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null[0])) { -- args--; -+ arguments--; - total_args++; - } - // Check if the call can be inlined or not -@@ -4441,7 +5697,7 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( - tstate, callable[0], locals, -- args, total_args, NULL, frame -+ arguments, total_args, NULL, frame - ); - stack_pointer = _PyFrame_GetStackPointer(frame); - // Manipulate stack directly since we leave using DISPATCH_INLINED(). -@@ -4450,23 +5706,22 @@ - // The frame has stolen all the arguments from the stack, - // so there is no need to clean them up. - if (new_frame == NULL) { -- goto error; -+ JUMP_TO_LABEL(error); - } - frame->return_offset = 4 ; - DISPATCH_INLINED(new_frame); - } - /* Callable is not a normal Python function */ -- STACKREFS_TO_PYOBJECTS(args, total_args, args_o); -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); - if (CONVERSION_FAILED(args_o)) { - PyStackRef_CLOSE(callable[0]); -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -- } -- { -- stack_pointer += -2 - oparg; -- assert(WITHIN_STACK_BOUNDS()); -- goto error; -+ PyStackRef_XCLOSE(self_or_null[0]); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); - } -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_LABEL(error); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *res_o = PyObject_Vectorcall( -@@ -4477,7 +5732,7 @@ - STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); - if (opcode == INSTRUMENTED_CALL) { - PyObject *arg = total_args == 0 ? -- &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(args[0]); -+ &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(arguments[0]); - if (res_o == NULL) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _Py_call_instrumentation_exc2( -@@ -4492,19 +5747,22 @@ - frame, this_instr, callable_o, arg); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (err < 0) { -+ _PyFrame_SetStackPointer(frame, stack_pointer); - Py_CLEAR(res_o); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - } - } - } - assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - PyStackRef_CLOSE(callable[0]); -- for (int i = 0; i < total_args; i++) { -- PyStackRef_CLOSE(args[i]); -+ PyStackRef_XCLOSE(self_or_null[0]); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); - } - if (res_o == NULL) { - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); -- goto error; -+ JUMP_TO_LABEL(error); - } - res = PyStackRef_FromPyObjectSteal(res_o); - } -@@ -4519,7 +5777,9 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = _Py_HandlePending(tstate); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err != 0) goto error; -+ if (err != 0) { -+ JUMP_TO_LABEL(error); -+ } - stack_pointer += 1 + oparg; - assert(WITHIN_STACK_BOUNDS()); - } -@@ -4531,38 +5791,383 @@ - } - - TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = INSTRUMENTED_CALL_FUNCTION_EX; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(INSTRUMENTED_CALL_FUNCTION_EX); -- GO_TO_INSTRUCTION(CALL_FUNCTION_EX); -+ opcode = INSTRUMENTED_CALL_FUNCTION_EX; -+ _PyStackRef func; -+ _PyStackRef callargs; -+ _PyStackRef kwargs_in; -+ _PyStackRef tuple; -+ _PyStackRef kwargs_out; -+ _PyStackRef func_st; -+ _PyStackRef null; -+ _PyStackRef callargs_st; -+ _PyStackRef kwargs_st; -+ _PyStackRef result; -+ // _MAKE_CALLARGS_A_TUPLE -+ { -+ kwargs_in = stack_pointer[-1]; -+ callargs = stack_pointer[-2]; -+ func = stack_pointer[-4]; -+ PyObject *callargs_o = PyStackRef_AsPyObjectBorrow(callargs); -+ if (PyTuple_CheckExact(callargs_o)) { -+ tuple = callargs; -+ kwargs_out = kwargs_in; -+ } -+ else { -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ int err = _Py_Check_ArgsIterable(tstate, PyStackRef_AsPyObjectBorrow(func), callargs_o); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (err < 0) { -+ JUMP_TO_LABEL(error); -+ } -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyObject *tuple_o = PySequence_Tuple(callargs_o); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (tuple_o == NULL) { -+ JUMP_TO_LABEL(error); -+ } -+ kwargs_out = kwargs_in; -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(callargs); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ tuple = PyStackRef_FromPyObjectSteal(tuple_o); -+ stack_pointer += 2; -+ assert(WITHIN_STACK_BOUNDS()); -+ } -+ } -+ // _DO_CALL_FUNCTION_EX -+ { -+ kwargs_st = kwargs_out; -+ callargs_st = tuple; -+ null = stack_pointer[-3]; -+ func_st = func; -+ (void)null; -+ PyObject *func = PyStackRef_AsPyObjectBorrow(func_st); -+ // DICT_MERGE is called before this opcode if there are kwargs. -+ // It converts all dict subtypes in kwargs into regular dicts. -+ EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_FUNCTION_EX, func); -+ PyObject *result_o; -+ assert(!_PyErr_Occurred(tstate)); -+ if (opcode == INSTRUMENTED_CALL_FUNCTION_EX) { -+ PyObject *callargs = PyStackRef_AsPyObjectBorrow(callargs_st); -+ PyObject *kwargs = PyStackRef_AsPyObjectBorrow(kwargs_st); -+ assert(kwargs == NULL || PyDict_CheckExact(kwargs)); -+ assert(PyTuple_CheckExact(callargs)); -+ PyObject *arg = PyTuple_GET_SIZE(callargs) > 0 ? -+ PyTuple_GET_ITEM(callargs, 0) : &_PyInstrumentation_MISSING; -+ stack_pointer[-2] = callargs_st; -+ stack_pointer[-1] = kwargs_st; -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ int err = _Py_call_instrumentation_2args( -+ tstate, PY_MONITORING_EVENT_CALL, -+ frame, this_instr, func, arg); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (err) { -+ JUMP_TO_LABEL(error); -+ } -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ result_o = PyObject_Call(func, callargs, kwargs); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (!PyFunction_Check(func) && !PyMethod_Check(func)) { -+ if (result_o == NULL) { -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ _Py_call_instrumentation_exc2( -+ tstate, PY_MONITORING_EVENT_C_RAISE, -+ frame, this_instr, func, arg); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ } -+ else { -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ int err = _Py_call_instrumentation_2args( -+ tstate, PY_MONITORING_EVENT_C_RETURN, -+ frame, this_instr, func, arg); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (err < 0) { -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ Py_CLEAR(result_o); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ } -+ } -+ } -+ } -+ else { -+ if (Py_TYPE(func) == &PyFunction_Type && -+ tstate->interp->eval_frame == NULL && -+ ((PyFunctionObject *)func)->vectorcall == _PyFunction_Vectorcall) { -+ PyObject *callargs = PyStackRef_AsPyObjectSteal(callargs_st); -+ assert(PyTuple_CheckExact(callargs)); -+ PyObject *kwargs = PyStackRef_IsNull(kwargs_st) ? NULL : PyStackRef_AsPyObjectSteal(kwargs_st); -+ assert(kwargs == NULL || PyDict_CheckExact(kwargs)); -+ Py_ssize_t nargs = PyTuple_GET_SIZE(callargs); -+ int code_flags = ((PyCodeObject *)PyFunction_GET_CODE(func))->co_flags; -+ PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(func)); -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_Ex( -+ tstate, func_st, locals, -+ nargs, callargs, kwargs, frame); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ // Need to sync the stack since we exit with DISPATCH_INLINED. -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ if (new_frame == NULL) { -+ JUMP_TO_LABEL(error); -+ } -+ assert( 1 == 1); -+ frame->return_offset = 1; -+ DISPATCH_INLINED(new_frame); -+ } -+ PyObject *callargs = PyStackRef_AsPyObjectBorrow(callargs_st); -+ assert(PyTuple_CheckExact(callargs)); -+ PyObject *kwargs = PyStackRef_AsPyObjectBorrow(kwargs_st); -+ assert(kwargs == NULL || PyDict_CheckExact(kwargs)); -+ stack_pointer[-2] = callargs_st; -+ stack_pointer[-1] = kwargs_st; -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ result_o = PyObject_Call(func, callargs, kwargs); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ } -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_XCLOSE(kwargs_st); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(callargs_st); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(func_st); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (result_o == NULL) { -+ JUMP_TO_LABEL(error); -+ } -+ result = PyStackRef_FromPyObjectSteal(result_o); -+ } -+ // _CHECK_PERIODIC -+ { -+ _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); -+ QSBR_QUIESCENT_STATE(tstate); -+ if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { -+ stack_pointer[0] = result; -+ stack_pointer += 1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ int err = _Py_HandlePending(tstate); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (err != 0) { -+ JUMP_TO_LABEL(error); -+ } -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ } -+ } -+ stack_pointer[0] = result; -+ stack_pointer += 1; -+ assert(WITHIN_STACK_BOUNDS()); -+ DISPATCH(); - } - - TARGET(INSTRUMENTED_CALL_KW) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = INSTRUMENTED_CALL_KW; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(INSTRUMENTED_CALL_KW); -- uint16_t counter = read_u16(&this_instr[1].cache); -- (void)counter; -- uint32_t version = read_u32(&this_instr[2].cache); -- (void)version; -- int is_meth = !PyStackRef_IsNull(PEEK(oparg + 2)); -- int total_args = oparg + is_meth; -- PyObject *function = PyStackRef_AsPyObjectBorrow(PEEK(oparg + 3)); -- PyObject *arg = total_args == 0 ? &_PyInstrumentation_MISSING -- : PyStackRef_AsPyObjectBorrow(PEEK(total_args + 1)); -- _PyFrame_SetStackPointer(frame, stack_pointer); -- int err = _Py_call_instrumentation_2args( -- tstate, PY_MONITORING_EVENT_CALL, -- frame, this_instr, function, arg); -- stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err) goto error; -- PAUSE_ADAPTIVE_COUNTER(this_instr[1].counter); -- GO_TO_INSTRUCTION(CALL_KW); -+ opcode = INSTRUMENTED_CALL_KW; -+ _PyStackRef *callable; -+ _PyStackRef *self_or_null; -+ _PyStackRef *args; -+ _PyStackRef kwnames; -+ _PyStackRef kwnames_in; -+ _PyStackRef *func; -+ _PyStackRef *maybe_self; -+ _PyStackRef kwnames_out; -+ _PyStackRef res; -+ /* Skip 1 cache entry */ -+ /* Skip 2 cache entries */ -+ // _MONITOR_CALL_KW -+ { -+ args = &stack_pointer[-1 - oparg]; -+ self_or_null = &stack_pointer[-2 - oparg]; -+ callable = &stack_pointer[-3 - oparg]; -+ int is_meth = !PyStackRef_IsNull(self_or_null[0]); -+ PyObject *arg; -+ if (is_meth) { -+ arg = PyStackRef_AsPyObjectBorrow(self_or_null[0]); -+ } -+ else { -+ if (args) { -+ arg = PyStackRef_AsPyObjectBorrow(args[0]); -+ } -+ else { -+ arg = &_PyInstrumentation_MISSING; -+ } -+ } -+ PyObject *function = PyStackRef_AsPyObjectBorrow(callable[0]); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ int err = _Py_call_instrumentation_2args( -+ tstate, PY_MONITORING_EVENT_CALL, -+ frame, this_instr, function, arg); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (err) { -+ JUMP_TO_LABEL(error); -+ } -+ } -+ // _MAYBE_EXPAND_METHOD_KW -+ { -+ kwnames_in = stack_pointer[-1]; -+ func = &stack_pointer[-3 - oparg]; -+ maybe_self = &stack_pointer[-2 - oparg]; -+ args = &stack_pointer[-1 - oparg]; -+ (void)args; -+ if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { -+ PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); -+ PyObject *self = ((PyMethodObject *)callable_o)->im_self; -+ maybe_self[0] = PyStackRef_FromPyObjectNew(self); -+ PyObject *method = ((PyMethodObject *)callable_o)->im_func; -+ _PyStackRef temp = callable[0]; -+ func[0] = PyStackRef_FromPyObjectNew(method); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(temp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ } -+ kwnames_out = kwnames_in; -+ } -+ // _DO_CALL_KW -+ { -+ kwnames = kwnames_out; -+ args = &stack_pointer[-1 - oparg]; -+ self_or_null = &stack_pointer[-2 - oparg]; -+ callable = &stack_pointer[-3 - oparg]; -+ PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); -+ PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); -+ // oparg counts all of the args, but *not* self: -+ int total_args = oparg; -+ _PyStackRef *arguments = args; -+ if (!PyStackRef_IsNull(self_or_null[0])) { -+ arguments--; -+ total_args++; -+ } -+ int positional_args = total_args - (int)PyTuple_GET_SIZE(kwnames_o); -+ // Check if the call can be inlined or not -+ if (Py_TYPE(callable_o) == &PyFunction_Type && -+ tstate->interp->eval_frame == NULL && -+ ((PyFunctionObject *)callable_o)->vectorcall == _PyFunction_Vectorcall) -+ { -+ int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags; -+ PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); -+ stack_pointer[-1] = kwnames; -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( -+ tstate, callable[0], locals, -+ arguments, positional_args, kwnames_o, frame -+ ); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(kwnames); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ // Sync stack explicitly since we leave using DISPATCH_INLINED(). -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ // The frame has stolen all the arguments from the stack, -+ // so there is no need to clean them up. -+ if (new_frame == NULL) { -+ JUMP_TO_LABEL(error); -+ } -+ assert( 4 == 1 + INLINE_CACHE_ENTRIES_CALL_KW); -+ frame->return_offset = 4 ; -+ DISPATCH_INLINED(new_frame); -+ } -+ /* Callable is not a normal Python function */ -+ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); -+ if (CONVERSION_FAILED(args_o)) { -+ PyStackRef_CLOSE(callable[0]); -+ PyStackRef_XCLOSE(self_or_null[0]); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); -+ } -+ PyStackRef_CLOSE(kwnames); -+ stack_pointer += -3 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_LABEL(error); -+ } -+ stack_pointer[-1] = kwnames; -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyObject *res_o = PyObject_Vectorcall( -+ callable_o, args_o, -+ positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, -+ kwnames_o); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); -+ if (opcode == INSTRUMENTED_CALL_KW) { -+ PyObject *arg = total_args == 0 ? -+ &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(arguments[0]); -+ if (res_o == NULL) { -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ _Py_call_instrumentation_exc2( -+ tstate, PY_MONITORING_EVENT_C_RAISE, -+ frame, this_instr, callable_o, arg); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ } -+ else { -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ int err = _Py_call_instrumentation_2args( -+ tstate, PY_MONITORING_EVENT_C_RETURN, -+ frame, this_instr, callable_o, arg); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (err < 0) { -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ Py_CLEAR(res_o); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ } -+ } -+ } -+ PyStackRef_CLOSE(callable[0]); -+ PyStackRef_XCLOSE(self_or_null[0]); -+ for (int _i = oparg; --_i >= 0;) { -+ PyStackRef_CLOSE(args[_i]); -+ } -+ PyStackRef_CLOSE(kwnames); -+ if (res_o == NULL) { -+ stack_pointer += -3 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ JUMP_TO_LABEL(error); -+ } -+ res = PyStackRef_FromPyObjectSteal(res_o); -+ } -+ stack_pointer[-3 - oparg] = res; -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); -+ DISPATCH(); - } - - TARGET(INSTRUMENTED_END_FOR) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = INSTRUMENTED_END_FOR; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; - next_instr += 1; - INSTRUCTION_STATS(INSTRUMENTED_END_FOR); -@@ -4577,7 +6182,7 @@ - int err = monitor_stop_iteration(tstate, frame, this_instr, PyStackRef_AsPyObjectBorrow(value)); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (err) { -- goto error; -+ JUMP_TO_LABEL(error); - } - } - PyStackRef_CLOSE(value); -@@ -4587,8 +6192,13 @@ - } - - TARGET(INSTRUMENTED_END_SEND) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = INSTRUMENTED_END_SEND; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(INSTRUMENTED_END_SEND); - _PyStackRef receiver; -@@ -4602,24 +6212,30 @@ - int err = monitor_stop_iteration(tstate, frame, this_instr, PyStackRef_AsPyObjectBorrow(value)); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (err) { -- goto error; -+ JUMP_TO_LABEL(error); - } - } - val = value; -- PyStackRef_CLOSE(receiver); - stack_pointer[-2] = val; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(receiver); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - DISPATCH(); - } - - TARGET(INSTRUMENTED_FOR_ITER) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = INSTRUMENTED_FOR_ITER; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(INSTRUMENTED_FOR_ITER); - /* Skip 1 cache entry */ -- _Py_CODEUNIT *target; - _PyStackRef iter_stackref = TOP(); - PyObject *iter = PyStackRef_AsPyObjectBorrow(iter_stackref); - _PyFrame_SetStackPointer(frame, stack_pointer); -@@ -4627,7 +6243,7 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - if (next != NULL) { - PUSH(PyStackRef_FromPyObjectSteal(next)); -- target = next_instr; -+ INSTRUMENTED_JUMP(this_instr, next_instr, PY_MONITORING_EVENT_BRANCH_LEFT); - } - else { - if (_PyErr_Occurred(tstate)) { -@@ -4635,7 +6251,7 @@ - int matches = _PyErr_ExceptionMatches(tstate, PyExc_StopIteration); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (!matches) { -- goto error; -+ JUMP_TO_LABEL(error); - } - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyEval_MonitorRaise(tstate, frame, this_instr); -@@ -4645,25 +6261,30 @@ - /* iterator ended normally */ - assert(next_instr[oparg].op.code == END_FOR || - next_instr[oparg].op.code == INSTRUMENTED_END_FOR); -- STACK_SHRINK(1); -- PyStackRef_CLOSE(iter_stackref); -- /* Skip END_FOR and POP_TOP */ -- target = next_instr + oparg + 2; -+ /* Skip END_FOR */ -+ JUMPBY(oparg + 1); - } -- INSTRUMENTED_JUMP(this_instr, target, PY_MONITORING_EVENT_BRANCH); - DISPATCH(); - } - - TARGET(INSTRUMENTED_INSTRUCTION) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = INSTRUMENTED_INSTRUCTION; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(INSTRUMENTED_INSTRUCTION); -+ opcode = INSTRUMENTED_INSTRUCTION; - _PyFrame_SetStackPointer(frame, stack_pointer); - int next_opcode = _Py_call_instrumentation_instruction( - tstate, frame, this_instr); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (next_opcode < 0) goto error; -+ if (next_opcode < 0) { -+ JUMP_TO_LABEL(error); -+ } - next_instr = this_instr; - if (_PyOpcode_Caches[next_opcode]) { - PAUSE_ADAPTIVE_COUNTER(next_instr[1].counter); -@@ -4674,8 +6295,13 @@ - } - - TARGET(INSTRUMENTED_JUMP_BACKWARD) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = INSTRUMENTED_JUMP_BACKWARD; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(INSTRUMENTED_JUMP_BACKWARD); - /* Skip 1 cache entry */ -@@ -4687,151 +6313,306 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = _Py_HandlePending(tstate); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err != 0) goto error; -+ if (err != 0) { -+ JUMP_TO_LABEL(error); -+ } -+ } -+ } -+ // _MONITOR_JUMP_BACKWARD -+ { -+ INSTRUMENTED_JUMP(this_instr, next_instr - oparg, PY_MONITORING_EVENT_JUMP); -+ } -+ DISPATCH(); -+ } -+ -+ TARGET(INSTRUMENTED_JUMP_FORWARD) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = INSTRUMENTED_JUMP_FORWARD; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; -+ next_instr += 1; -+ INSTRUCTION_STATS(INSTRUMENTED_JUMP_FORWARD); -+ INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_JUMP); -+ DISPATCH(); -+ } -+ -+ TARGET(INSTRUMENTED_LINE) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = INSTRUMENTED_LINE; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const prev_instr = frame->instr_ptr; -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; -+ next_instr += 1; -+ INSTRUCTION_STATS(INSTRUMENTED_LINE); -+ opcode = INSTRUMENTED_LINE; -+ int original_opcode = 0; -+ if (tstate->tracing) { -+ PyCodeObject *code = _PyFrame_GetCode(frame); -+ int index = (int)(this_instr - _PyFrame_GetBytecode(frame)); -+ original_opcode = code->_co_monitoring->lines->data[index*code->_co_monitoring->lines->bytes_per_entry]; -+ next_instr = this_instr; -+ } else { -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ original_opcode = _Py_call_instrumentation_line( -+ tstate, frame, this_instr, prev_instr); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (original_opcode < 0) { -+ next_instr = this_instr+1; -+ JUMP_TO_LABEL(error); -+ } -+ next_instr = frame->instr_ptr; -+ if (next_instr != this_instr) { -+ DISPATCH(); -+ } -+ } -+ if (_PyOpcode_Caches[original_opcode]) { -+ _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(next_instr+1); -+ /* Prevent the underlying instruction from specializing -+ * and overwriting the instrumentation. */ -+ PAUSE_ADAPTIVE_COUNTER(cache->counter); -+ } -+ opcode = original_opcode; -+ DISPATCH_GOTO(); -+ } -+ -+ TARGET(INSTRUMENTED_LOAD_SUPER_ATTR) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = INSTRUMENTED_LOAD_SUPER_ATTR; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; -+ next_instr += 2; -+ INSTRUCTION_STATS(INSTRUMENTED_LOAD_SUPER_ATTR); -+ opcode = INSTRUMENTED_LOAD_SUPER_ATTR; -+ _PyStackRef global_super_st; -+ _PyStackRef class_st; -+ _PyStackRef self_st; -+ _PyStackRef attr; -+ _PyStackRef null = PyStackRef_NULL; -+ /* Skip 1 cache entry */ -+ // _LOAD_SUPER_ATTR -+ { -+ self_st = stack_pointer[-1]; -+ class_st = stack_pointer[-2]; -+ global_super_st = stack_pointer[-3]; -+ PyObject *global_super = PyStackRef_AsPyObjectBorrow(global_super_st); -+ PyObject *class = PyStackRef_AsPyObjectBorrow(class_st); -+ PyObject *self = PyStackRef_AsPyObjectBorrow(self_st); -+ if (opcode == INSTRUMENTED_LOAD_SUPER_ATTR) { -+ PyObject *arg = oparg & 2 ? class : &_PyInstrumentation_MISSING; -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ int err = _Py_call_instrumentation_2args( -+ tstate, PY_MONITORING_EVENT_CALL, -+ frame, this_instr, global_super, arg); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (err) { -+ PyStackRef_CLOSE(global_super_st); -+ PyStackRef_CLOSE(class_st); -+ PyStackRef_CLOSE(self_st); -+ JUMP_TO_LABEL(pop_3_error); -+ } -+ } -+ // we make no attempt to optimize here; specializations should -+ // handle any case whose performance we care about -+ PyObject *stack[] = {class, self}; -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyObject *super = PyObject_Vectorcall(global_super, stack, oparg & 2, NULL); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (opcode == INSTRUMENTED_LOAD_SUPER_ATTR) { -+ PyObject *arg = oparg & 2 ? class : &_PyInstrumentation_MISSING; -+ if (super == NULL) { -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ _Py_call_instrumentation_exc2( -+ tstate, PY_MONITORING_EVENT_C_RAISE, -+ frame, this_instr, global_super, arg); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ } -+ else { -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ int err = _Py_call_instrumentation_2args( -+ tstate, PY_MONITORING_EVENT_C_RETURN, -+ frame, this_instr, global_super, arg); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (err < 0) { -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ Py_CLEAR(super); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ } -+ } -+ } -+ PyStackRef_CLOSE(global_super_st); -+ PyStackRef_CLOSE(class_st); -+ PyStackRef_CLOSE(self_st); -+ if (super == NULL) { -+ JUMP_TO_LABEL(pop_3_error); -+ } -+ PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); -+ stack_pointer += -3; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyObject *attr_o = PyObject_GetAttr(super, name); -+ Py_DECREF(super); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (attr_o == NULL) { -+ JUMP_TO_LABEL(error); - } -+ attr = PyStackRef_FromPyObjectSteal(attr_o); - } -- // _MONITOR_JUMP_BACKWARD -+ // _PUSH_NULL_CONDITIONAL - { -- INSTRUMENTED_JUMP(this_instr, next_instr - oparg, PY_MONITORING_EVENT_JUMP); -+ null = PyStackRef_NULL; - } -+ stack_pointer[0] = attr; -+ if (oparg & 1) stack_pointer[1] = null; -+ stack_pointer += 1 + (oparg & 1); -+ assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - -- TARGET(INSTRUMENTED_JUMP_FORWARD) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ TARGET(INSTRUMENTED_NOT_TAKEN) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = INSTRUMENTED_NOT_TAKEN; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const prev_instr = frame->instr_ptr; -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 1; -- INSTRUCTION_STATS(INSTRUMENTED_JUMP_FORWARD); -- INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_JUMP); -+ INSTRUCTION_STATS(INSTRUMENTED_NOT_TAKEN); -+ (void)this_instr; // INSTRUMENTED_JUMP requires this_instr -+ INSTRUMENTED_JUMP(prev_instr, next_instr, PY_MONITORING_EVENT_BRANCH_LEFT); - DISPATCH(); - } - -- TARGET(INSTRUMENTED_LINE) { -+ TARGET(INSTRUMENTED_POP_ITER) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = INSTRUMENTED_POP_ITER; -+ (void)(opcode); -+ #endif - _Py_CODEUNIT* const prev_instr = frame->instr_ptr; -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 1; -- INSTRUCTION_STATS(INSTRUMENTED_LINE); -- int original_opcode = 0; -- if (tstate->tracing) { -- PyCodeObject *code = _PyFrame_GetCode(frame); -- _PyFrame_SetStackPointer(frame, stack_pointer); -- original_opcode = code->_co_monitoring->lines[(int)(this_instr - _PyFrame_GetBytecode(frame))].original_opcode; -- stack_pointer = _PyFrame_GetStackPointer(frame); -- next_instr = this_instr; -- } else { -- _PyFrame_SetStackPointer(frame, stack_pointer); -- original_opcode = _Py_call_instrumentation_line( -- tstate, frame, this_instr, prev_instr); -- stack_pointer = _PyFrame_GetStackPointer(frame); -- if (original_opcode < 0) { -- next_instr = this_instr+1; -- goto error; -- } -- next_instr = frame->instr_ptr; -- if (next_instr != this_instr) { -- DISPATCH(); -- } -- } -- if (_PyOpcode_Caches[original_opcode]) { -- _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(next_instr+1); -- /* Prevent the underlying instruction from specializing -- * and overwriting the instrumentation. */ -- PAUSE_ADAPTIVE_COUNTER(cache->counter); -- } -- opcode = original_opcode; -- DISPATCH_GOTO(); -- } -- -- TARGET(INSTRUMENTED_LOAD_SUPER_ATTR) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -- (void)this_instr; -- next_instr += 2; -- INSTRUCTION_STATS(INSTRUMENTED_LOAD_SUPER_ATTR); -- /* Skip 1 cache entry */ -- // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we -- // don't want to specialize instrumented instructions -- PAUSE_ADAPTIVE_COUNTER(this_instr[1].counter); -- GO_TO_INSTRUCTION(LOAD_SUPER_ATTR); -+ INSTRUCTION_STATS(INSTRUMENTED_POP_ITER); -+ _PyStackRef iter; -+ iter = stack_pointer[-1]; -+ INSTRUMENTED_JUMP(prev_instr, this_instr+1, PY_MONITORING_EVENT_BRANCH_RIGHT); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(iter); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ DISPATCH(); - } - - TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = INSTRUMENTED_POP_JUMP_IF_FALSE; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_FALSE); - /* Skip 1 cache entry */ - _PyStackRef cond = POP(); - assert(PyStackRef_BoolCheck(cond)); -- int flag = PyStackRef_IsFalse(cond); -- int offset = flag * oparg; -- RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); -- INSTRUMENTED_JUMP(this_instr, next_instr + offset, PY_MONITORING_EVENT_BRANCH); -+ int jump = PyStackRef_IsFalse(cond); -+ RECORD_BRANCH_TAKEN(this_instr[1].cache, jump); -+ if (jump) { -+ INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT); -+ } - DISPATCH(); - } - - TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = INSTRUMENTED_POP_JUMP_IF_NONE; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_NONE); - /* Skip 1 cache entry */ - _PyStackRef value_stackref = POP(); -- int flag = PyStackRef_IsNone(value_stackref); -- int offset; -- if (flag) { -- offset = oparg; -+ int jump = PyStackRef_IsNone(value_stackref); -+ RECORD_BRANCH_TAKEN(this_instr[1].cache, jump); -+ if (jump) { -+ INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT); - } - else { -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(value_stackref); -- offset = 0; -+ stack_pointer = _PyFrame_GetStackPointer(frame); - } -- RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); -- INSTRUMENTED_JUMP(this_instr, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - DISPATCH(); - } - - TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = INSTRUMENTED_POP_JUMP_IF_NOT_NONE; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_NOT_NONE); - /* Skip 1 cache entry */ - _PyStackRef value_stackref = POP(); -- int offset; -- int nflag = PyStackRef_IsNone(value_stackref); -- if (nflag) { -- offset = 0; -- } -- else { -+ int jump = !PyStackRef_IsNone(value_stackref); -+ RECORD_BRANCH_TAKEN(this_instr[1].cache, jump); -+ if (jump) { -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(value_stackref); -- offset = oparg; -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT); - } -- #if ENABLE_SPECIALIZATION -- this_instr[1].cache = (this_instr[1].cache << 1) | !nflag; -- #endif -- INSTRUMENTED_JUMP(this_instr, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - DISPATCH(); - } - - TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = INSTRUMENTED_POP_JUMP_IF_TRUE; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(INSTRUMENTED_POP_JUMP_IF_TRUE); - /* Skip 1 cache entry */ - _PyStackRef cond = POP(); - assert(PyStackRef_BoolCheck(cond)); -- int flag = PyStackRef_IsTrue(cond); -- int offset = flag * oparg; -- RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); -- INSTRUMENTED_JUMP(this_instr, next_instr + offset, PY_MONITORING_EVENT_BRANCH); -+ int jump = PyStackRef_IsTrue(cond); -+ RECORD_BRANCH_TAKEN(this_instr[1].cache, jump); -+ if (jump) { -+ INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT); -+ } - DISPATCH(); - } - - TARGET(INSTRUMENTED_RESUME) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = INSTRUMENTED_RESUME; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(INSTRUMENTED_RESUME); - // _LOAD_BYTECODE -@@ -4843,10 +6624,10 @@ - _Py_CODEUNIT *bytecode = - _PyEval_GetExecutableCode(tstate, _PyFrame_GetCode(frame)); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (bytecode == NULL) goto error; -- _PyFrame_SetStackPointer(frame, stack_pointer); -+ if (bytecode == NULL) { -+ JUMP_TO_LABEL(error); -+ } - ptrdiff_t off = this_instr - _PyFrame_GetBytecode(frame); -- stack_pointer = _PyFrame_GetStackPointer(frame); - frame->tlbc_index = ((_PyThreadStateImpl *)tstate)->tlbc_index; - frame->instr_ptr = bytecode + off; - // Make sure this_instr gets reset correctley for any uops that -@@ -4866,7 +6647,7 @@ - int err = _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (err) { -- goto error; -+ JUMP_TO_LABEL(error); - } - next_instr = this_instr; - DISPATCH(); -@@ -4882,7 +6663,9 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = _Py_HandlePending(tstate); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err != 0) goto error; -+ if (err != 0) { -+ JUMP_TO_LABEL(error); -+ } - } - } - } -@@ -4892,7 +6675,9 @@ - int err = _Py_call_instrumentation( - tstate, oparg > 0, frame, this_instr); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err) goto error; -+ if (err) { -+ JUMP_TO_LABEL(error); -+ } - if (frame->instr_ptr != this_instr) { - /* Instrumentation has jumped */ - next_instr = frame->instr_ptr; -@@ -4902,8 +6687,13 @@ - } - - TARGET(INSTRUMENTED_RETURN_VALUE) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = INSTRUMENTED_RETURN_VALUE; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(INSTRUMENTED_RETURN_VALUE); - _PyStackRef val; -@@ -4917,14 +6707,14 @@ - tstate, PY_MONITORING_EVENT_PY_RETURN, - frame, this_instr, PyStackRef_AsPyObjectBorrow(val)); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err) goto error; -+ if (err) { -+ JUMP_TO_LABEL(error); -+ } - } - // _RETURN_VALUE - { - retval = val; -- #if TIER_ONE -- assert(frame != &entry_frame); -- #endif -+ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); - _PyStackRef temp = retval; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); -@@ -4947,8 +6737,13 @@ - } - - TARGET(INSTRUMENTED_YIELD_VALUE) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = INSTRUMENTED_YIELD_VALUE; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(INSTRUMENTED_YIELD_VALUE); - _PyStackRef val; -@@ -4963,7 +6758,7 @@ - frame, this_instr, PyStackRef_AsPyObjectBorrow(val)); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (err) { -- goto error; -+ JUMP_TO_LABEL(error); - } - if (frame->instr_ptr != this_instr) { - next_instr = frame->instr_ptr; -@@ -4976,9 +6771,7 @@ - // NOTE: It's important that YIELD_VALUE never raises an exception! - // The compiler treats any exception raised here as a failed close() - // or throw() call. -- #if TIER_ONE -- assert(frame != &entry_frame); -- #endif -+ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); - frame->instr_ptr++; - PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); - assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); -@@ -5016,12 +6809,16 @@ - } - - TARGET(INTERPRETER_EXIT) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = INTERPRETER_EXIT; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(INTERPRETER_EXIT); - _PyStackRef retval; - retval = stack_pointer[-1]; -- assert(frame == &entry_frame); -+ assert(frame->owner == FRAME_OWNED_BY_INTERPRETER); - assert(_PyFrame_IsIncomplete(frame)); - /* Restore previous frame and return. */ - tstate->current_frame = frame->previous; -@@ -5035,6 +6832,10 @@ - } - - TARGET(IS_OP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = IS_OP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(IS_OP); -@@ -5054,10 +6855,66 @@ - } - - TARGET(JUMP_BACKWARD) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -- (void)this_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = JUMP_BACKWARD; -+ (void)(opcode); -+ #endif -+ frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(JUMP_BACKWARD); -+ PREDICTED_JUMP_BACKWARD:; -+ _Py_CODEUNIT* const this_instr = next_instr - 2; -+ (void)this_instr; -+ /* Skip 1 cache entry */ -+ // _SPECIALIZE_JUMP_BACKWARD -+ { -+ #if ENABLE_SPECIALIZATION -+ if (this_instr->op.code == JUMP_BACKWARD) { -+ this_instr->op.code = tstate->interp->jit ? JUMP_BACKWARD_JIT : JUMP_BACKWARD_NO_JIT; -+ // Need to re-dispatch so the warmup counter isn't off by one: -+ next_instr = this_instr; -+ DISPATCH_SAME_OPARG(); -+ } -+ #endif -+ } -+ // _CHECK_PERIODIC -+ { -+ _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); -+ QSBR_QUIESCENT_STATE(tstate); -+ if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ int err = _Py_HandlePending(tstate); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (err != 0) { -+ JUMP_TO_LABEL(error); -+ } -+ } -+ } -+ // _JUMP_BACKWARD_NO_INTERRUPT -+ { -+ /* This bytecode is used in the `yield from` or `await` loop. -+ * If there is an interrupt, we want it handled in the innermost -+ * generator or coroutine, so we deliberately do not check it here. -+ * (see bpo-30039). -+ */ -+ assert(oparg <= INSTR_OFFSET()); -+ JUMPBY(-oparg); -+ } -+ DISPATCH(); -+ } -+ -+ TARGET(JUMP_BACKWARD_JIT) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = JUMP_BACKWARD_JIT; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; -+ next_instr += 2; -+ INSTRUCTION_STATS(JUMP_BACKWARD_JIT); -+ static_assert(1 == 1, "incorrect cache size"); -+ /* Skip 1 cache entry */ - // _CHECK_PERIODIC - { - _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); -@@ -5066,19 +6923,26 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = _Py_HandlePending(tstate); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err != 0) goto error; -+ if (err != 0) { -+ JUMP_TO_LABEL(error); -+ } - } - } -- // _JUMP_BACKWARD -+ // _JUMP_BACKWARD_NO_INTERRUPT - { -- uint16_t the_counter = read_u16(&this_instr[1].cache); -- (void)the_counter; -+ /* This bytecode is used in the `yield from` or `await` loop. -+ * If there is an interrupt, we want it handled in the innermost -+ * generator or coroutine, so we deliberately do not check it here. -+ * (see bpo-30039). -+ */ - assert(oparg <= INSTR_OFFSET()); - JUMPBY(-oparg); -+ } -+ // _JIT -+ { - #ifdef _Py_TIER2 -- #if ENABLE_SPECIALIZATION - _Py_BackoffCounter counter = this_instr[1].counter; -- if (backoff_counter_triggers(counter) && this_instr->op.code == JUMP_BACKWARD) { -+ if (backoff_counter_triggers(counter) && this_instr->op.code == JUMP_BACKWARD_JIT) { - _Py_CODEUNIT *start = this_instr; - /* Back up over EXTENDED_ARGs so optimizer sees the whole instruction */ - while (oparg > 255) { -@@ -5087,11 +6951,13 @@ - } - _PyExecutorObject *executor; - _PyFrame_SetStackPointer(frame, stack_pointer); -- int optimized = _PyOptimizer_Optimize(frame, start, stack_pointer, &executor, 0); -+ int optimized = _PyOptimizer_Optimize(frame, start, &executor, 0); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (optimized <= 0) { - this_instr[1].counter = restart_backoff_counter(counter); -- if (optimized < 0) goto error; -+ if (optimized < 0) { -+ JUMP_TO_LABEL(error); -+ } - } - else { - _PyFrame_SetStackPointer(frame, stack_pointer); -@@ -5105,13 +6971,16 @@ - else { - ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - } -- #endif /* ENABLE_SPECIALIZATION */ -- #endif /* _Py_TIER2 */ -+ #endif - } - DISPATCH(); - } - - TARGET(JUMP_BACKWARD_NO_INTERRUPT) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = JUMP_BACKWARD_NO_INTERRUPT; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(JUMP_BACKWARD_NO_INTERRUPT); -@@ -5120,11 +6989,52 @@ - * generator or coroutine, so we deliberately do not check it here. - * (see bpo-30039). - */ -+ assert(oparg <= INSTR_OFFSET()); - JUMPBY(-oparg); - DISPATCH(); - } - -+ TARGET(JUMP_BACKWARD_NO_JIT) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = JUMP_BACKWARD_NO_JIT; -+ (void)(opcode); -+ #endif -+ frame->instr_ptr = next_instr; -+ next_instr += 2; -+ INSTRUCTION_STATS(JUMP_BACKWARD_NO_JIT); -+ static_assert(1 == 1, "incorrect cache size"); -+ /* Skip 1 cache entry */ -+ // _CHECK_PERIODIC -+ { -+ _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); -+ QSBR_QUIESCENT_STATE(tstate); -+ if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ int err = _Py_HandlePending(tstate); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (err != 0) { -+ JUMP_TO_LABEL(error); -+ } -+ } -+ } -+ // _JUMP_BACKWARD_NO_INTERRUPT -+ { -+ /* This bytecode is used in the `yield from` or `await` loop. -+ * If there is an interrupt, we want it handled in the innermost -+ * generator or coroutine, so we deliberately do not check it here. -+ * (see bpo-30039). -+ */ -+ assert(oparg <= INSTR_OFFSET()); -+ JUMPBY(-oparg); -+ } -+ DISPATCH(); -+ } -+ - TARGET(JUMP_FORWARD) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = JUMP_FORWARD; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(JUMP_FORWARD); -@@ -5133,6 +7043,10 @@ - } - - TARGET(LIST_APPEND) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LIST_APPEND; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(LIST_APPEND); -@@ -5142,13 +7056,19 @@ - list = stack_pointer[-2 - (oparg-1)]; - int err = _PyList_AppendTakeRef((PyListObject *)PyStackRef_AsPyObjectBorrow(list), - PyStackRef_AsPyObjectSteal(v)); -- if (err < 0) goto pop_1_error; -+ if (err < 0) { -+ JUMP_TO_LABEL(pop_1_error); -+ } - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(LIST_EXTEND) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LIST_EXTEND; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(LIST_EXTEND); -@@ -5176,7 +7096,7 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - } - PyStackRef_CLOSE(iterable_st); -- goto pop_1_error; -+ JUMP_TO_LABEL(pop_1_error); - } - assert(Py_IsNone(none_val)); - PyStackRef_CLOSE(iterable_st); -@@ -5186,15 +7106,19 @@ - } - - TARGET(LOAD_ATTR) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_ATTR; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 10; - INSTRUCTION_STATS(LOAD_ATTR); -- PREDICTED(LOAD_ATTR); -+ PREDICTED_LOAD_ATTR:; - _Py_CODEUNIT* const this_instr = next_instr - 10; - (void)this_instr; - _PyStackRef owner; - _PyStackRef attr; -- _PyStackRef self_or_null = PyStackRef_NULL; -+ _PyStackRef *self_or_null; - // _SPECIALIZE_LOAD_ATTR - { - owner = stack_pointer[-1]; -@@ -5216,6 +7140,7 @@ - /* Skip 8 cache entries */ - // _LOAD_ATTR - { -+ self_or_null = &stack_pointer[0]; - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); - PyObject *attr_o; - if (oparg & 1) { -@@ -5230,7 +7155,7 @@ - meth | self | arg1 | ... | argN - */ - assert(attr_o != NULL); // No errors on this branch -- self_or_null = owner; // Transfer ownership -+ self_or_null[0] = owner; // Transfer ownership - } - else { - /* meth is not an unbound method (but a regular attr, or -@@ -5240,8 +7165,10 @@ - meth | NULL | arg1 | ... | argN - */ - PyStackRef_CLOSE(owner); -- if (attr_o == NULL) goto pop_1_error; -- self_or_null = PyStackRef_NULL; -+ if (attr_o == NULL) { -+ JUMP_TO_LABEL(pop_1_error); -+ } -+ self_or_null[0] = PyStackRef_NULL; - } - } - else { -@@ -5250,21 +7177,26 @@ - attr_o = PyObject_GetAttr(PyStackRef_AsPyObjectBorrow(owner), name); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(owner); -- if (attr_o == NULL) goto pop_1_error; -- /* We need to define self_or_null on all paths */ -- self_or_null = PyStackRef_NULL; -+ if (attr_o == NULL) { -+ JUMP_TO_LABEL(pop_1_error); -+ } - } - attr = PyStackRef_FromPyObjectSteal(attr_o); - } - stack_pointer[-1] = attr; -- if (oparg & 1) stack_pointer[0] = self_or_null; -- stack_pointer += (oparg & 1); -+ stack_pointer += (oparg&1); - assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(LOAD_ATTR_CLASS) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_ATTR_CLASS; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 10; - INSTRUCTION_STATS(LOAD_ATTR_CLASS); - static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); -@@ -5277,9 +7209,17 @@ - owner = stack_pointer[-1]; - uint32_t type_version = read_u32(&this_instr[2].cache); - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); -- DEOPT_IF(!PyType_Check(owner_o), LOAD_ATTR); -+ if (!PyType_Check(owner_o)) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - assert(type_version != 0); -- DEOPT_IF(((PyTypeObject *)owner_o)->tp_version_tag != type_version, LOAD_ATTR); -+ if (FT_ATOMIC_LOAD_UINT_RELAXED(((PyTypeObject *)owner_o)->tp_version_tag) != type_version) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - } - /* Skip 2 cache entries */ - // _LOAD_ATTR_CLASS -@@ -5288,9 +7228,12 @@ - STAT_INC(LOAD_ATTR, hit); - assert(descr != NULL); - attr = PyStackRef_FromPyObjectNew(descr); -- null = PyStackRef_NULL; - PyStackRef_CLOSE(owner); - } -+ // _PUSH_NULL_CONDITIONAL -+ { -+ null = PyStackRef_NULL; -+ } - stack_pointer[-1] = attr; - if (oparg & 1) stack_pointer[0] = null; - stack_pointer += (oparg & 1); -@@ -5299,7 +7242,13 @@ - } - - TARGET(LOAD_ATTR_CLASS_WITH_METACLASS_CHECK) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_ATTR_CLASS_WITH_METACLASS_CHECK; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 10; - INSTRUCTION_STATS(LOAD_ATTR_CLASS_WITH_METACLASS_CHECK); - static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); -@@ -5312,16 +7261,28 @@ - owner = stack_pointer[-1]; - uint32_t type_version = read_u32(&this_instr[2].cache); - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); -- DEOPT_IF(!PyType_Check(owner_o), LOAD_ATTR); -+ if (!PyType_Check(owner_o)) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - assert(type_version != 0); -- DEOPT_IF(((PyTypeObject *)owner_o)->tp_version_tag != type_version, LOAD_ATTR); -+ if (FT_ATOMIC_LOAD_UINT_RELAXED(((PyTypeObject *)owner_o)->tp_version_tag) != type_version) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - } - // _GUARD_TYPE_VERSION - { - uint32_t type_version = read_u32(&this_instr[4].cache); - PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - assert(type_version != 0); -- DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); -+ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - } - // _LOAD_ATTR_CLASS - { -@@ -5329,9 +7290,12 @@ - STAT_INC(LOAD_ATTR, hit); - assert(descr != NULL); - attr = PyStackRef_FromPyObjectNew(descr); -- null = PyStackRef_NULL; - PyStackRef_CLOSE(owner); - } -+ // _PUSH_NULL_CONDITIONAL -+ { -+ null = PyStackRef_NULL; -+ } - stack_pointer[-1] = attr; - if (oparg & 1) stack_pointer[0] = null; - stack_pointer += (oparg & 1); -@@ -5340,7 +7304,13 @@ - } - - TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 10; - INSTRUCTION_STATS(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN); - static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); -@@ -5352,17 +7322,33 @@ - PyObject *getattribute = read_obj(&this_instr[6].cache); - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - assert((oparg & 1) == 0); -- DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); -+ if (tstate->interp->eval_frame) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - PyTypeObject *cls = Py_TYPE(owner_o); - assert(type_version != 0); -- DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); -+ if (FT_ATOMIC_LOAD_UINT_RELAXED(cls->tp_version_tag) != type_version) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - assert(Py_IS_TYPE(getattribute, &PyFunction_Type)); - PyFunctionObject *f = (PyFunctionObject *)getattribute; - assert(func_version != 0); -- DEOPT_IF(f->func_version != func_version, LOAD_ATTR); -+ if (f->func_version != func_version) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - PyCodeObject *code = (PyCodeObject *)f->func_code; - assert(code->co_argcount == 2); -- DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), LOAD_ATTR); -+ if (!_PyThreadState_HasStackSpace(tstate, code->co_framesize)) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - STAT_INC(LOAD_ATTR, hit); - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); - _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked( -@@ -5376,7 +7362,13 @@ - } - - TARGET(LOAD_ATTR_INSTANCE_VALUE) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_ATTR_INSTANCE_VALUE; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 10; - INSTRUCTION_STATS(LOAD_ATTR_INSTANCE_VALUE); - static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); -@@ -5390,30 +7382,56 @@ - uint32_t type_version = read_u32(&this_instr[2].cache); - PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - assert(type_version != 0); -- DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); -+ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - } - // _CHECK_MANAGED_OBJECT_HAS_VALUES - { - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - assert(Py_TYPE(owner_o)->tp_dictoffset < 0); - assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); -- DEOPT_IF(!_PyObject_InlineValues(owner_o)->valid, LOAD_ATTR); -+ if (!FT_ATOMIC_LOAD_UINT8(_PyObject_InlineValues(owner_o)->valid)) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - } - // _LOAD_ATTR_INSTANCE_VALUE - { - uint16_t offset = read_u16(&this_instr[4].cache); - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); -- PyObject *attr_o = *value_ptr; -- DEOPT_IF(attr_o == NULL, LOAD_ATTR); -+ PyObject *attr_o = FT_ATOMIC_LOAD_PTR_ACQUIRE(*value_ptr); -+ if (attr_o == NULL) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } -+ #ifdef Py_GIL_DISABLED -+ if (!_Py_TryIncrefCompareStackRef(value_ptr, attr_o, &attr)) { -+ if (true) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } -+ } -+ #else -+ attr = PyStackRef_FromPyObjectNew(attr_o); -+ #endif - STAT_INC(LOAD_ATTR, hit); -- Py_INCREF(attr_o); -- null = PyStackRef_NULL; -- attr = PyStackRef_FromPyObjectSteal(attr_o); -+ stack_pointer[-1] = attr; -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(owner); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - } - /* Skip 5 cache entries */ -- stack_pointer[-1] = attr; -+ // _PUSH_NULL_CONDITIONAL -+ { -+ null = PyStackRef_NULL; -+ } - if (oparg & 1) stack_pointer[0] = null; - stack_pointer += (oparg & 1); - assert(WITHIN_STACK_BOUNDS()); -@@ -5421,13 +7439,19 @@ - } - - TARGET(LOAD_ATTR_METHOD_LAZY_DICT) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_ATTR_METHOD_LAZY_DICT; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 10; - INSTRUCTION_STATS(LOAD_ATTR_METHOD_LAZY_DICT); - static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); - _PyStackRef owner; - _PyStackRef attr; -- _PyStackRef self = PyStackRef_NULL; -+ _PyStackRef self; - /* Skip 1 cache entry */ - // _GUARD_TYPE_VERSION - { -@@ -5435,15 +7459,23 @@ - uint32_t type_version = read_u32(&this_instr[2].cache); - PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - assert(type_version != 0); -- DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); -+ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - } - // _CHECK_ATTR_METHOD_LAZY_DICT - { - uint16_t dictoffset = read_u16(&this_instr[4].cache); - char *ptr = ((char *)PyStackRef_AsPyObjectBorrow(owner)) + MANAGED_DICT_OFFSET + dictoffset; -- PyObject *dict = *(PyObject **)ptr; -+ PyObject *dict = FT_ATOMIC_LOAD_PTR_ACQUIRE(*(PyObject **)ptr); - /* This object has a __dict__, just not yet created */ -- DEOPT_IF(dict != NULL, LOAD_ATTR); -+ if (dict != NULL) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - } - /* Skip 1 cache entry */ - // _LOAD_ATTR_METHOD_LAZY_DICT -@@ -5464,13 +7496,19 @@ - } - - TARGET(LOAD_ATTR_METHOD_NO_DICT) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_ATTR_METHOD_NO_DICT; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 10; - INSTRUCTION_STATS(LOAD_ATTR_METHOD_NO_DICT); - static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); - _PyStackRef owner; - _PyStackRef attr; -- _PyStackRef self = PyStackRef_NULL; -+ _PyStackRef self; - /* Skip 1 cache entry */ - // _GUARD_TYPE_VERSION - { -@@ -5478,7 +7516,11 @@ - uint32_t type_version = read_u32(&this_instr[2].cache); - PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - assert(type_version != 0); -- DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); -+ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - } - /* Skip 2 cache entries */ - // _LOAD_ATTR_METHOD_NO_DICT -@@ -5500,13 +7542,19 @@ - } - - TARGET(LOAD_ATTR_METHOD_WITH_VALUES) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_ATTR_METHOD_WITH_VALUES; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 10; - INSTRUCTION_STATS(LOAD_ATTR_METHOD_WITH_VALUES); - static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); - _PyStackRef owner; - _PyStackRef attr; -- _PyStackRef self = PyStackRef_NULL; -+ _PyStackRef self; - /* Skip 1 cache entry */ - // _GUARD_TYPE_VERSION - { -@@ -5514,20 +7562,34 @@ - uint32_t type_version = read_u32(&this_instr[2].cache); - PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - assert(type_version != 0); -- DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); -+ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - } - // _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT - { - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); -- DEOPT_IF(!_PyObject_InlineValues(owner_o)->valid, LOAD_ATTR); -+ PyDictValues *ivs = _PyObject_InlineValues(owner_o); -+ if (!FT_ATOMIC_LOAD_UINT8(ivs->valid)) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - } - // _GUARD_KEYS_VERSION - { - uint32_t keys_version = read_u32(&this_instr[4].cache); - PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; -- DEOPT_IF(owner_heap_type->ht_cached_keys->dk_version != keys_version, LOAD_ATTR); -+ PyDictKeysObject *keys = owner_heap_type->ht_cached_keys; -+ if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - } - // _LOAD_ATTR_METHOD_WITH_VALUES - { -@@ -5548,7 +7610,13 @@ - } - - TARGET(LOAD_ATTR_MODULE) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_ATTR_MODULE; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 10; - INSTRUCTION_STATS(LOAD_ATTR_MODULE); - static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); -@@ -5562,11 +7630,19 @@ - owner = stack_pointer[-1]; - uint32_t dict_version = read_u32(&this_instr[2].cache); - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); -- DEOPT_IF(Py_TYPE(owner_o)->tp_getattro != PyModule_Type.tp_getattro, LOAD_ATTR); -+ if (Py_TYPE(owner_o)->tp_getattro != PyModule_Type.tp_getattro) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner_o)->md_dict; - assert(dict != NULL); - PyDictKeysObject *keys = FT_ATOMIC_LOAD_PTR_ACQUIRE(dict->ma_keys); -- DEOPT_IF(FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != dict_version, LOAD_ATTR); -+ if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != dict_version) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - mod_keys = keys; - } - // _LOAD_ATTR_MODULE_FROM_KEYS -@@ -5577,22 +7653,35 @@ - PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(mod_keys) + index; - PyObject *attr_o = FT_ATOMIC_LOAD_PTR_RELAXED(ep->me_value); - // Clear mod_keys from stack in case we need to deopt -- DEOPT_IF(attr_o == NULL, LOAD_ATTR); -+ if (attr_o == NULL) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - #ifdef Py_GIL_DISABLED - int increfed = _Py_TryIncrefCompareStackRef(&ep->me_value, attr_o, &attr); - if (!increfed) { -- DEOPT_IF(true, LOAD_ATTR); -+ if (true) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - } - #else - Py_INCREF(attr_o); - attr = PyStackRef_FromPyObjectSteal(attr_o); - #endif - STAT_INC(LOAD_ATTR, hit); -+ stack_pointer[-1] = attr; -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(owner); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ } -+ /* Skip 5 cache entries */ -+ // _PUSH_NULL_CONDITIONAL -+ { - null = PyStackRef_NULL; -- PyStackRef_CLOSE(owner); - } -- /* Skip 5 cache entries */ -- stack_pointer[-1] = attr; - if (oparg & 1) stack_pointer[0] = null; - stack_pointer += (oparg & 1); - assert(WITHIN_STACK_BOUNDS()); -@@ -5600,7 +7689,13 @@ - } - - TARGET(LOAD_ATTR_NONDESCRIPTOR_NO_DICT) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_ATTR_NONDESCRIPTOR_NO_DICT; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 10; - INSTRUCTION_STATS(LOAD_ATTR_NONDESCRIPTOR_NO_DICT); - static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); -@@ -5613,7 +7708,11 @@ - uint32_t type_version = read_u32(&this_instr[2].cache); - PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - assert(type_version != 0); -- DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); -+ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - } - /* Skip 2 cache entries */ - // _LOAD_ATTR_NONDESCRIPTOR_NO_DICT -@@ -5631,7 +7730,13 @@ - } - - TARGET(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 10; - INSTRUCTION_STATS(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES); - static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); -@@ -5644,20 +7749,34 @@ - uint32_t type_version = read_u32(&this_instr[2].cache); - PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - assert(type_version != 0); -- DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); -+ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - } - // _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT - { - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); -- DEOPT_IF(!_PyObject_InlineValues(owner_o)->valid, LOAD_ATTR); -+ PyDictValues *ivs = _PyObject_InlineValues(owner_o); -+ if (!FT_ATOMIC_LOAD_UINT8(ivs->valid)) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - } - // _GUARD_KEYS_VERSION - { - uint32_t keys_version = read_u32(&this_instr[4].cache); - PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; -- DEOPT_IF(owner_heap_type->ht_cached_keys->dk_version != keys_version, LOAD_ATTR); -+ PyDictKeysObject *keys = owner_heap_type->ht_cached_keys; -+ if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - } - // _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES - { -@@ -5673,7 +7792,13 @@ - } - - TARGET(LOAD_ATTR_PROPERTY) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_ATTR_PROPERTY; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 10; - INSTRUCTION_STATS(LOAD_ATTR_PROPERTY); - static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); -@@ -5682,7 +7807,11 @@ - /* Skip 1 cache entry */ - // _CHECK_PEP_523 - { -- DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); -+ if (tstate->interp->eval_frame) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - } - // _GUARD_TYPE_VERSION - { -@@ -5690,7 +7819,11 @@ - uint32_t type_version = read_u32(&this_instr[2].cache); - PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - assert(type_version != 0); -- DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); -+ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - } - /* Skip 2 cache entries */ - // _LOAD_ATTR_PROPERTY_FRAME -@@ -5700,10 +7833,26 @@ - assert(Py_IS_TYPE(fget, &PyFunction_Type)); - PyFunctionObject *f = (PyFunctionObject *)fget; - PyCodeObject *code = (PyCodeObject *)f->func_code; -- DEOPT_IF((code->co_flags & (CO_VARKEYWORDS | CO_VARARGS | CO_OPTIMIZED)) != CO_OPTIMIZED, LOAD_ATTR); -- DEOPT_IF(code->co_kwonlyargcount, LOAD_ATTR); -- DEOPT_IF(code->co_argcount != 1, LOAD_ATTR); -- DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), LOAD_ATTR); -+ if ((code->co_flags & (CO_VARKEYWORDS | CO_VARARGS | CO_OPTIMIZED)) != CO_OPTIMIZED) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } -+ if (code->co_kwonlyargcount) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } -+ if (code->co_argcount != 1) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } -+ if (!_PyThreadState_HasStackSpace(tstate, code->co_framesize)) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - STAT_INC(LOAD_ATTR, hit); - new_frame = _PyFrame_PushUnchecked(tstate, PyStackRef_FromPyObjectNew(fget), 1, frame); - new_frame->localsplus[0] = owner; -@@ -5738,7 +7887,13 @@ - } - - TARGET(LOAD_ATTR_SLOT) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_ATTR_SLOT; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 10; - INSTRUCTION_STATS(LOAD_ATTR_SLOT); - static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); -@@ -5752,21 +7907,41 @@ - uint32_t type_version = read_u32(&this_instr[2].cache); - PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - assert(type_version != 0); -- DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); -+ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - } - // _LOAD_ATTR_SLOT - { - uint16_t index = read_u16(&this_instr[4].cache); - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); -- char *addr = (char *)owner_o + index; -- PyObject *attr_o = *(PyObject **)addr; -- DEOPT_IF(attr_o == NULL, LOAD_ATTR); -- STAT_INC(LOAD_ATTR, hit); -- null = PyStackRef_NULL; -+ PyObject **addr = (PyObject **)((char *)owner_o + index); -+ PyObject *attr_o = FT_ATOMIC_LOAD_PTR(*addr); -+ if (attr_o == NULL) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } -+ #ifdef Py_GIL_DISABLED -+ int increfed = _Py_TryIncrefCompareStackRef(addr, attr_o, &attr); -+ if (!increfed) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } -+ #else - attr = PyStackRef_FromPyObjectNew(attr_o); -+ #endif -+ STAT_INC(LOAD_ATTR, hit); - PyStackRef_CLOSE(owner); - } - /* Skip 5 cache entries */ -+ // _PUSH_NULL_CONDITIONAL -+ { -+ null = PyStackRef_NULL; -+ } - stack_pointer[-1] = attr; - if (oparg & 1) stack_pointer[0] = null; - stack_pointer += (oparg & 1); -@@ -5775,11 +7950,18 @@ - } - - TARGET(LOAD_ATTR_WITH_HINT) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_ATTR_WITH_HINT; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 10; - INSTRUCTION_STATS(LOAD_ATTR_WITH_HINT); - static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); - _PyStackRef owner; -+ PyDictObject *dict; - _PyStackRef attr; - _PyStackRef null = PyStackRef_NULL; - /* Skip 1 cache entry */ -@@ -5789,36 +7971,81 @@ - uint32_t type_version = read_u32(&this_instr[2].cache); - PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - assert(type_version != 0); -- DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); -+ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } - } - // _CHECK_ATTR_WITH_HINT - { - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_MANAGED_DICT); -- PyDictObject *dict = _PyObject_GetManagedDict(owner_o); -- DEOPT_IF(dict == NULL, LOAD_ATTR); -- assert(PyDict_CheckExact((PyObject *)dict)); -+ PyDictObject *dict_o = _PyObject_GetManagedDict(owner_o); -+ if (dict_o == NULL) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } -+ assert(PyDict_CheckExact((PyObject *)dict_o)); -+ dict = dict_o; - } - // _LOAD_ATTR_WITH_HINT - { - uint16_t hint = read_u16(&this_instr[4].cache); -- PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - PyObject *attr_o; -- PyDictObject *dict = _PyObject_GetManagedDict(owner_o); -- DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, LOAD_ATTR); -+ if (!LOCK_OBJECT(dict)) { -+ if (true) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } -+ } -+ if (hint >= (size_t)dict->ma_keys->dk_nentries) { -+ UNLOCK_OBJECT(dict); -+ if (true) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } -+ } - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); -- DEOPT_IF(!DK_IS_UNICODE(dict->ma_keys), LOAD_ATTR); -+ if (dict->ma_keys->dk_kind != DICT_KEYS_UNICODE) { -+ UNLOCK_OBJECT(dict); -+ if (true) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } -+ } - PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; -- DEOPT_IF(ep->me_key != name, LOAD_ATTR); -+ if (ep->me_key != name) { -+ UNLOCK_OBJECT(dict); -+ if (true) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } -+ } - attr_o = ep->me_value; -- DEOPT_IF(attr_o == NULL, LOAD_ATTR); -+ if (attr_o == NULL) { -+ UNLOCK_OBJECT(dict); -+ if (true) { -+ UPDATE_MISS_STATS(LOAD_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_ATTR); -+ } -+ } - STAT_INC(LOAD_ATTR, hit); -- Py_INCREF(attr_o); -- attr = PyStackRef_FromPyObjectSteal(attr_o); -- null = PyStackRef_NULL; -+ attr = PyStackRef_FromPyObjectNew(attr_o); -+ UNLOCK_OBJECT(dict); - PyStackRef_CLOSE(owner); - } - /* Skip 5 cache entries */ -+ // _PUSH_NULL_CONDITIONAL -+ { -+ null = PyStackRef_NULL; -+ } - stack_pointer[-1] = attr; - if (oparg & 1) stack_pointer[0] = null; - stack_pointer += (oparg & 1); -@@ -5827,6 +8054,10 @@ - } - - TARGET(LOAD_BUILD_CLASS) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_BUILD_CLASS; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(LOAD_BUILD_CLASS); -@@ -5835,13 +8066,15 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = PyMapping_GetOptionalItem(BUILTINS(), &_Py_ID(__build_class__), &bc_o); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err < 0) goto error; -+ if (err < 0) { -+ JUMP_TO_LABEL(error); -+ } - if (bc_o == NULL) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyErr_SetString(tstate, PyExc_NameError, - "__build_class__ not found"); - stack_pointer = _PyFrame_GetStackPointer(frame); -- goto error; -+ JUMP_TO_LABEL(error); - } - bc = PyStackRef_FromPyObjectSteal(bc_o); - stack_pointer[0] = bc; -@@ -5851,6 +8084,10 @@ - } - - TARGET(LOAD_COMMON_CONSTANT) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_COMMON_CONSTANT; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(LOAD_COMMON_CONSTANT); -@@ -5873,12 +8110,36 @@ - } - - TARGET(LOAD_CONST) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_CONST; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(LOAD_CONST); -- PREDICTED(LOAD_CONST); -+ PREDICTED_LOAD_CONST:; -+ _Py_CODEUNIT* const this_instr = next_instr - 1; -+ (void)this_instr; - _PyStackRef value; -- value = PyStackRef_FromPyObjectNew(GETITEM(FRAME_CO_CONSTS, oparg)); -+ /* We can't do this in the bytecode compiler as -+ * marshalling can intern strings and make them immortal. */ -+ PyObject *obj = GETITEM(FRAME_CO_CONSTS, oparg); -+ value = PyStackRef_FromPyObjectNew(obj); -+ #if ENABLE_SPECIALIZATION_FT -+ #ifdef Py_GIL_DISABLED -+ uint8_t expected = LOAD_CONST; -+ if (!_Py_atomic_compare_exchange_uint8( -+ &this_instr->op.code, &expected, -+ _Py_IsImmortal(obj) ? LOAD_CONST_IMMORTAL : LOAD_CONST_MORTAL)) { -+ // We might lose a race with instrumentation, which we don't care about. -+ assert(expected >= MIN_INSTRUMENTED_OPCODE); -+ } -+ #else -+ if (this_instr->op.code == LOAD_CONST) { -+ this_instr->op.code = _Py_IsImmortal(obj) ? LOAD_CONST_IMMORTAL : LOAD_CONST_MORTAL; -+ } -+ #endif -+ #endif - stack_pointer[0] = value; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); -@@ -5886,6 +8147,10 @@ - } - - TARGET(LOAD_CONST_IMMORTAL) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_CONST_IMMORTAL; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(LOAD_CONST_IMMORTAL); -@@ -5900,7 +8165,29 @@ - DISPATCH(); - } - -+ TARGET(LOAD_CONST_MORTAL) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_CONST_MORTAL; -+ (void)(opcode); -+ #endif -+ frame->instr_ptr = next_instr; -+ next_instr += 1; -+ INSTRUCTION_STATS(LOAD_CONST_MORTAL); -+ static_assert(0 == 0, "incorrect cache size"); -+ _PyStackRef value; -+ PyObject *obj = GETITEM(FRAME_CO_CONSTS, oparg); -+ value = PyStackRef_FromPyObjectNew(obj); -+ stack_pointer[0] = value; -+ stack_pointer += 1; -+ assert(WITHIN_STACK_BOUNDS()); -+ DISPATCH(); -+ } -+ - TARGET(LOAD_DEREF) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_DEREF; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(LOAD_DEREF); -@@ -5911,7 +8198,7 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg); - stack_pointer = _PyFrame_GetStackPointer(frame); -- goto error; -+ JUMP_TO_LABEL(error); - } - value = PyStackRef_FromPyObjectSteal(value_o); - stack_pointer[0] = value; -@@ -5921,6 +8208,10 @@ - } - - TARGET(LOAD_FAST) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_FAST; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(LOAD_FAST); -@@ -5934,12 +8225,15 @@ - } - - TARGET(LOAD_FAST_AND_CLEAR) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_FAST_AND_CLEAR; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(LOAD_FAST_AND_CLEAR); - _PyStackRef value; - value = GETLOCAL(oparg); -- // do not use SETLOCAL here, it decrefs the old value - GETLOCAL(oparg) = PyStackRef_NULL; - stack_pointer[0] = value; - stack_pointer += 1; -@@ -5948,6 +8242,10 @@ - } - - TARGET(LOAD_FAST_CHECK) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_FAST_CHECK; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(LOAD_FAST_CHECK); -@@ -5960,7 +8258,7 @@ - PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames, oparg) - ); - stack_pointer = _PyFrame_GetStackPointer(frame); -- goto error; -+ JUMP_TO_LABEL(error); - } - value = PyStackRef_DUP(value_s); - stack_pointer[0] = value; -@@ -5970,6 +8268,10 @@ - } - - TARGET(LOAD_FAST_LOAD_FAST) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_FAST_LOAD_FAST; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(LOAD_FAST_LOAD_FAST); -@@ -5987,6 +8289,10 @@ - } - - TARGET(LOAD_FROM_DICT_OR_DEREF) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_FROM_DICT_OR_DEREF; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(LOAD_FROM_DICT_OR_DEREF); -@@ -6003,7 +8309,7 @@ - int err = PyMapping_GetOptionalItem(class_dict, name, &value_o); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (err < 0) { -- goto error; -+ JUMP_TO_LABEL(error); - } - if (!value_o) { - PyCellObject *cell = (PyCellObject *)PyStackRef_AsPyObjectBorrow(GETLOCAL(oparg)); -@@ -6012,16 +8318,26 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg); - stack_pointer = _PyFrame_GetStackPointer(frame); -- goto error; -+ JUMP_TO_LABEL(error); - } - } -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(class_dict_st); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - value = PyStackRef_FromPyObjectSteal(value_o); -- stack_pointer[-1] = value; -+ stack_pointer[0] = value; -+ stack_pointer += 1; -+ assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(LOAD_FROM_DICT_OR_GLOBALS) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_FROM_DICT_OR_GLOBALS; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(LOAD_FROM_DICT_OR_GLOBALS); -@@ -6034,7 +8350,9 @@ - int err = PyMapping_GetOptionalItem(PyStackRef_AsPyObjectBorrow(mod_or_class_dict), name, &v_o); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(mod_or_class_dict); -- if (err < 0) goto pop_1_error; -+ if (err < 0) { -+ JUMP_TO_LABEL(pop_1_error); -+ } - if (v_o == NULL) { - if (PyDict_CheckExact(GLOBALS()) - && PyDict_CheckExact(BUILTINS())) -@@ -6055,7 +8373,7 @@ - NAME_ERROR_MSG, name); - stack_pointer = _PyFrame_GetStackPointer(frame); - } -- goto error; -+ JUMP_TO_LABEL(error); - } - } - else { -@@ -6066,20 +8384,24 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = PyMapping_GetOptionalItem(GLOBALS(), name, &v_o); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err < 0) goto error; -+ if (err < 0) { -+ JUMP_TO_LABEL(error); -+ } - if (v_o == NULL) { - /* namespace 2: builtins */ - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = PyMapping_GetOptionalItem(BUILTINS(), name, &v_o); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err < 0) goto error; -+ if (err < 0) { -+ JUMP_TO_LABEL(error); -+ } - if (v_o == NULL) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyEval_FormatExcCheckArg( - tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - stack_pointer = _PyFrame_GetStackPointer(frame); -- goto error; -+ JUMP_TO_LABEL(error); - } - } - } -@@ -6092,10 +8414,14 @@ - } - - TARGET(LOAD_GLOBAL) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_GLOBAL; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 5; - INSTRUCTION_STATS(LOAD_GLOBAL); -- PREDICTED(LOAD_GLOBAL); -+ PREDICTED_LOAD_GLOBAL:; - _Py_CODEUNIT* const this_instr = next_instr - 5; - (void)this_instr; - _PyStackRef *res; -@@ -6127,7 +8453,12 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyEval_LoadGlobalStackRef(GLOBALS(), BUILTINS(), name, res); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (PyStackRef_IsNull(*res)) goto error; -+ if (PyStackRef_IsNull(*res)) { -+ JUMP_TO_LABEL(error); -+ } -+ } -+ // _PUSH_NULL_CONDITIONAL -+ { - null = PyStackRef_NULL; - } - if (oparg & 1) stack_pointer[1] = null; -@@ -6137,7 +8468,13 @@ - } - - TARGET(LOAD_GLOBAL_BUILTIN) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_GLOBAL_BUILTIN; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 5; - INSTRUCTION_STATS(LOAD_GLOBAL_BUILTIN); - static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); -@@ -6149,18 +8486,34 @@ - { - uint16_t version = read_u16(&this_instr[2].cache); - PyDictObject *dict = (PyDictObject *)GLOBALS(); -- DEOPT_IF(!PyDict_CheckExact(dict), LOAD_GLOBAL); -+ if (!PyDict_CheckExact(dict)) { -+ UPDATE_MISS_STATS(LOAD_GLOBAL); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL)); -+ JUMP_TO_PREDICTED(LOAD_GLOBAL); -+ } - PyDictKeysObject *keys = FT_ATOMIC_LOAD_PTR_ACQUIRE(dict->ma_keys); -- DEOPT_IF(FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != version, LOAD_GLOBAL); -+ if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != version) { -+ UPDATE_MISS_STATS(LOAD_GLOBAL); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL)); -+ JUMP_TO_PREDICTED(LOAD_GLOBAL); -+ } - assert(DK_IS_UNICODE(keys)); - } - // _GUARD_BUILTINS_VERSION_PUSH_KEYS - { - uint16_t version = read_u16(&this_instr[3].cache); - PyDictObject *dict = (PyDictObject *)BUILTINS(); -- DEOPT_IF(!PyDict_CheckExact(dict), LOAD_GLOBAL); -+ if (!PyDict_CheckExact(dict)) { -+ UPDATE_MISS_STATS(LOAD_GLOBAL); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL)); -+ JUMP_TO_PREDICTED(LOAD_GLOBAL); -+ } - PyDictKeysObject *keys = FT_ATOMIC_LOAD_PTR_ACQUIRE(dict->ma_keys); -- DEOPT_IF(FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != version, LOAD_GLOBAL); -+ if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != version) { -+ UPDATE_MISS_STATS(LOAD_GLOBAL); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL)); -+ JUMP_TO_PREDICTED(LOAD_GLOBAL); -+ } - builtins_keys = keys; - assert(DK_IS_UNICODE(builtins_keys)); - } -@@ -6169,15 +8522,26 @@ - uint16_t index = read_u16(&this_instr[4].cache); - PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(builtins_keys); - PyObject *res_o = FT_ATOMIC_LOAD_PTR_RELAXED(entries[index].me_value); -- DEOPT_IF(res_o == NULL, LOAD_GLOBAL); -+ if (res_o == NULL) { -+ UPDATE_MISS_STATS(LOAD_GLOBAL); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL)); -+ JUMP_TO_PREDICTED(LOAD_GLOBAL); -+ } - #if Py_GIL_DISABLED - int increfed = _Py_TryIncrefCompareStackRef(&entries[index].me_value, res_o, &res); -- DEOPT_IF(!increfed, LOAD_GLOBAL); -+ if (!increfed) { -+ UPDATE_MISS_STATS(LOAD_GLOBAL); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL)); -+ JUMP_TO_PREDICTED(LOAD_GLOBAL); -+ } - #else - Py_INCREF(res_o); - res = PyStackRef_FromPyObjectSteal(res_o); - #endif - STAT_INC(LOAD_GLOBAL, hit); -+ } -+ // _PUSH_NULL_CONDITIONAL -+ { - null = PyStackRef_NULL; - } - stack_pointer[0] = res; -@@ -6188,7 +8552,13 @@ - } - - TARGET(LOAD_GLOBAL_MODULE) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_GLOBAL_MODULE; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 5; - INSTRUCTION_STATS(LOAD_GLOBAL_MODULE); - static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); -@@ -6200,9 +8570,17 @@ - { - uint16_t version = read_u16(&this_instr[2].cache); - PyDictObject *dict = (PyDictObject *)GLOBALS(); -- DEOPT_IF(!PyDict_CheckExact(dict), LOAD_GLOBAL); -+ if (!PyDict_CheckExact(dict)) { -+ UPDATE_MISS_STATS(LOAD_GLOBAL); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL)); -+ JUMP_TO_PREDICTED(LOAD_GLOBAL); -+ } - PyDictKeysObject *keys = FT_ATOMIC_LOAD_PTR_ACQUIRE(dict->ma_keys); -- DEOPT_IF(FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != version, LOAD_GLOBAL); -+ if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != version) { -+ UPDATE_MISS_STATS(LOAD_GLOBAL); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL)); -+ JUMP_TO_PREDICTED(LOAD_GLOBAL); -+ } - globals_keys = keys; - assert(DK_IS_UNICODE(globals_keys)); - } -@@ -6212,15 +8590,26 @@ - uint16_t index = read_u16(&this_instr[4].cache); - PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(globals_keys); - PyObject *res_o = FT_ATOMIC_LOAD_PTR_RELAXED(entries[index].me_value); -- DEOPT_IF(res_o == NULL, LOAD_GLOBAL); -+ if (res_o == NULL) { -+ UPDATE_MISS_STATS(LOAD_GLOBAL); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL)); -+ JUMP_TO_PREDICTED(LOAD_GLOBAL); -+ } - #if Py_GIL_DISABLED - int increfed = _Py_TryIncrefCompareStackRef(&entries[index].me_value, res_o, &res); -- DEOPT_IF(!increfed, LOAD_GLOBAL); -+ if (!increfed) { -+ UPDATE_MISS_STATS(LOAD_GLOBAL); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_GLOBAL)); -+ JUMP_TO_PREDICTED(LOAD_GLOBAL); -+ } - #else - Py_INCREF(res_o); - res = PyStackRef_FromPyObjectSteal(res_o); - #endif - STAT_INC(LOAD_GLOBAL, hit); -+ } -+ // _PUSH_NULL_CONDITIONAL -+ { - null = PyStackRef_NULL; - } - stack_pointer[0] = res; -@@ -6231,6 +8620,10 @@ - } - - TARGET(LOAD_LOCALS) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_LOCALS; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(LOAD_LOCALS); -@@ -6241,7 +8634,7 @@ - _PyErr_SetString(tstate, PyExc_SystemError, - "no locals found"); - stack_pointer = _PyFrame_GetStackPointer(frame); -- goto error; -+ JUMP_TO_LABEL(error); - } - locals = PyStackRef_FromPyObjectNew(l); - stack_pointer[0] = locals; -@@ -6251,6 +8644,10 @@ - } - - TARGET(LOAD_NAME) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_NAME; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(LOAD_NAME); -@@ -6259,7 +8656,9 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *v_o = _PyEval_LoadName(tstate, frame, name); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (v_o == NULL) goto error; -+ if (v_o == NULL) { -+ JUMP_TO_LABEL(error); -+ } - v = PyStackRef_FromPyObjectSteal(v_o); - stack_pointer[0] = v; - stack_pointer += 1; -@@ -6268,6 +8667,10 @@ - } - - TARGET(LOAD_SMALL_INT) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_SMALL_INT; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(LOAD_SMALL_INT); -@@ -6282,6 +8685,10 @@ - } - - TARGET(LOAD_SPECIAL) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_SPECIAL; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(LOAD_SPECIAL); -@@ -6306,7 +8713,7 @@ - Py_TYPE(owner_o)->tp_name); - stack_pointer = _PyFrame_GetStackPointer(frame); - } -- goto error; -+ JUMP_TO_LABEL(error); - } - attr = PyStackRef_FromPyObjectSteal(attr_o); - self_or_null = self_or_null_o == NULL ? -@@ -6319,12 +8726,17 @@ - } - - TARGET(LOAD_SUPER_ATTR) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_SUPER_ATTR; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(LOAD_SUPER_ATTR); -- PREDICTED(LOAD_SUPER_ATTR); -+ PREDICTED_LOAD_SUPER_ATTR:; - _Py_CODEUNIT* const this_instr = next_instr - 2; - (void)this_instr; -+ opcode = LOAD_SUPER_ATTR; - _PyStackRef global_super_st; - _PyStackRef class_st; - _PyStackRef self_st; -@@ -6366,7 +8778,7 @@ - PyStackRef_CLOSE(global_super_st); - PyStackRef_CLOSE(class_st); - PyStackRef_CLOSE(self_st); -- goto pop_3_error; -+ JUMP_TO_LABEL(pop_3_error); - } - } - // we make no attempt to optimize here; specializations should -@@ -6391,23 +8803,32 @@ - frame, this_instr, global_super, arg); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (err < 0) { -+ _PyFrame_SetStackPointer(frame, stack_pointer); - Py_CLEAR(super); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - } - } - } - PyStackRef_CLOSE(global_super_st); - PyStackRef_CLOSE(class_st); - PyStackRef_CLOSE(self_st); -- if (super == NULL) goto pop_3_error; -+ if (super == NULL) { -+ JUMP_TO_LABEL(pop_3_error); -+ } - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); - stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *attr_o = PyObject_GetAttr(super, name); -- stack_pointer = _PyFrame_GetStackPointer(frame); - Py_DECREF(super); -- if (attr_o == NULL) goto error; -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (attr_o == NULL) { -+ JUMP_TO_LABEL(error); -+ } - attr = PyStackRef_FromPyObjectSteal(attr_o); -+ } -+ // _PUSH_NULL_CONDITIONAL -+ { - null = PyStackRef_NULL; - } - stack_pointer[0] = attr; -@@ -6418,6 +8839,12 @@ - } - - TARGET(LOAD_SUPER_ATTR_ATTR) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_SUPER_ATTR_ATTR; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(LOAD_SUPER_ATTR_ATTR); -@@ -6434,8 +8861,16 @@ - PyObject *class = PyStackRef_AsPyObjectBorrow(class_st); - PyObject *self = PyStackRef_AsPyObjectBorrow(self_st); - assert(!(oparg & 1)); -- DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); -- DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); -+ if (global_super != (PyObject *)&PySuper_Type) { -+ UPDATE_MISS_STATS(LOAD_SUPER_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_SUPER_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_SUPER_ATTR); -+ } -+ if (!PyType_Check(class)) { -+ UPDATE_MISS_STATS(LOAD_SUPER_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_SUPER_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_SUPER_ATTR); -+ } - STAT_INC(LOAD_SUPER_ATTR, hit); - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); - _PyFrame_SetStackPointer(frame, stack_pointer); -@@ -6444,7 +8879,9 @@ - PyStackRef_CLOSE(global_super_st); - PyStackRef_CLOSE(class_st); - PyStackRef_CLOSE(self_st); -- if (attr == NULL) goto pop_3_error; -+ if (attr == NULL) { -+ JUMP_TO_LABEL(pop_3_error); -+ } - attr_st = PyStackRef_FromPyObjectSteal(attr); - stack_pointer[-3] = attr_st; - stack_pointer += -2; -@@ -6453,6 +8890,12 @@ - } - - TARGET(LOAD_SUPER_ATTR_METHOD) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = LOAD_SUPER_ATTR_METHOD; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(LOAD_SUPER_ATTR_METHOD); -@@ -6470,8 +8913,16 @@ - PyObject *class = PyStackRef_AsPyObjectBorrow(class_st); - PyObject *self = PyStackRef_AsPyObjectBorrow(self_st); - assert(oparg & 1); -- DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); -- DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); -+ if (global_super != (PyObject *)&PySuper_Type) { -+ UPDATE_MISS_STATS(LOAD_SUPER_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_SUPER_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_SUPER_ATTR); -+ } -+ if (!PyType_Check(class)) { -+ UPDATE_MISS_STATS(LOAD_SUPER_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (LOAD_SUPER_ATTR)); -+ JUMP_TO_PREDICTED(LOAD_SUPER_ATTR); -+ } - STAT_INC(LOAD_SUPER_ATTR, hit); - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); - PyTypeObject *cls = (PyTypeObject *)class; -@@ -6480,18 +8931,23 @@ - PyObject *attr_o = _PySuper_Lookup(cls, self, name, - Py_TYPE(self)->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL); - stack_pointer = _PyFrame_GetStackPointer(frame); -- PyStackRef_CLOSE(global_super_st); -- PyStackRef_CLOSE(class_st); - if (attr_o == NULL) { -- PyStackRef_CLOSE(self_st); -- goto pop_3_error; -+ JUMP_TO_LABEL(error); - } - if (method_found) { - self_or_null = self_st; // transfer ownership - } else { -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(self_st); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - self_or_null = PyStackRef_NULL; -+ stack_pointer += 1; -+ assert(WITHIN_STACK_BOUNDS()); - } -+ PyStackRef_CLOSE(global_super_st); -+ PyStackRef_CLOSE(class_st); - attr = PyStackRef_FromPyObjectSteal(attr_o); - stack_pointer[-3] = attr; - stack_pointer[-2] = self_or_null; -@@ -6501,6 +8957,10 @@ - } - - TARGET(MAKE_CELL) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = MAKE_CELL; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(MAKE_CELL); -@@ -6509,13 +8969,21 @@ - PyObject *initial = PyStackRef_AsPyObjectBorrow(GETLOCAL(oparg)); - PyObject *cell = PyCell_New(initial); - if (cell == NULL) { -- goto error; -+ JUMP_TO_LABEL(error); - } -- SETLOCAL(oparg, PyStackRef_FromPyObjectSteal(cell)); -+ _PyStackRef tmp = GETLOCAL(oparg); -+ GETLOCAL(oparg) = PyStackRef_FromPyObjectSteal(cell); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_XCLOSE(tmp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - DISPATCH(); - } - - TARGET(MAKE_FUNCTION) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = MAKE_FUNCTION; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(MAKE_FUNCTION); -@@ -6527,16 +8995,28 @@ - PyFunctionObject *func_obj = (PyFunctionObject *) - PyFunction_New(codeobj, GLOBALS()); - stack_pointer = _PyFrame_GetStackPointer(frame); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(codeobj_st); -- if (func_obj == NULL) goto pop_1_error; -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (func_obj == NULL) { -+ JUMP_TO_LABEL(error); -+ } - _PyFunction_SetVersion( - func_obj, ((PyCodeObject *)codeobj)->co_version); - func = PyStackRef_FromPyObjectSteal((PyObject *)func_obj); -- stack_pointer[-1] = func; -+ stack_pointer[0] = func; -+ stack_pointer += 1; -+ assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(MAP_ADD) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = MAP_ADD; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(MAP_ADD); -@@ -6557,13 +9037,19 @@ - PyStackRef_AsPyObjectSteal(value) - ); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err != 0) goto pop_2_error; -+ if (err != 0) { -+ JUMP_TO_LABEL(pop_2_error); -+ } - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(MATCH_CLASS) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = MATCH_CLASS; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(MATCH_CLASS); -@@ -6591,7 +9077,9 @@ - attrs = PyStackRef_FromPyObjectSteal(attrs_o); - } - else { -- if (_PyErr_Occurred(tstate)) goto pop_3_error; -+ if (_PyErr_Occurred(tstate)) { -+ JUMP_TO_LABEL(pop_3_error); -+ } - // Error! - attrs = PyStackRef_None; // Failure! - } -@@ -6602,6 +9090,10 @@ - } - - TARGET(MATCH_KEYS) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = MATCH_KEYS; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(MATCH_KEYS); -@@ -6615,7 +9107,9 @@ - PyObject *values_or_none_o = _PyEval_MatchKeys(tstate, - PyStackRef_AsPyObjectBorrow(subject), PyStackRef_AsPyObjectBorrow(keys)); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (values_or_none_o == NULL) goto error; -+ if (values_or_none_o == NULL) { -+ JUMP_TO_LABEL(error); -+ } - values_or_none = PyStackRef_FromPyObjectSteal(values_or_none_o); - stack_pointer[0] = values_or_none; - stack_pointer += 1; -@@ -6624,6 +9118,10 @@ - } - - TARGET(MATCH_MAPPING) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = MATCH_MAPPING; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(MATCH_MAPPING); -@@ -6639,6 +9137,10 @@ - } - - TARGET(MATCH_SEQUENCE) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = MATCH_SEQUENCE; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(MATCH_SEQUENCE); -@@ -6654,13 +9156,32 @@ - } - - TARGET(NOP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = NOP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(NOP); - DISPATCH(); - } - -+ TARGET(NOT_TAKEN) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = NOT_TAKEN; -+ (void)(opcode); -+ #endif -+ frame->instr_ptr = next_instr; -+ next_instr += 1; -+ INSTRUCTION_STATS(NOT_TAKEN); -+ DISPATCH(); -+ } -+ - TARGET(POP_EXCEPT) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = POP_EXCEPT; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(POP_EXCEPT); -@@ -6677,9 +9198,30 @@ - DISPATCH(); - } - -+ TARGET(POP_ITER) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = POP_ITER; -+ (void)(opcode); -+ #endif -+ frame->instr_ptr = next_instr; -+ next_instr += 1; -+ INSTRUCTION_STATS(POP_ITER); -+ _PyStackRef value; -+ value = stack_pointer[-1]; -+ PyStackRef_CLOSE(value); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ DISPATCH(); -+ } -+ - TARGET(POP_JUMP_IF_FALSE) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = POP_JUMP_IF_FALSE; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(POP_JUMP_IF_FALSE); - _PyStackRef cond; -@@ -6688,15 +9230,20 @@ - assert(PyStackRef_BoolCheck(cond)); - int flag = PyStackRef_IsFalse(cond); - RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); -- JUMPBY(oparg * flag); -+ JUMPBY(flag ? oparg : next_instr->op.code == NOT_TAKEN); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(POP_JUMP_IF_NONE) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = POP_JUMP_IF_NONE; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(POP_JUMP_IF_NONE); - _PyStackRef value; -@@ -6720,7 +9267,7 @@ - assert(PyStackRef_BoolCheck(cond)); - int flag = PyStackRef_IsTrue(cond); - RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); -- JUMPBY(oparg * flag); -+ JUMPBY(flag ? oparg : next_instr->op.code == NOT_TAKEN); - } - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); -@@ -6728,8 +9275,13 @@ - } - - TARGET(POP_JUMP_IF_NOT_NONE) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = POP_JUMP_IF_NOT_NONE; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(POP_JUMP_IF_NOT_NONE); - _PyStackRef value; -@@ -6753,7 +9305,7 @@ - assert(PyStackRef_BoolCheck(cond)); - int flag = PyStackRef_IsFalse(cond); - RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); -- JUMPBY(oparg * flag); -+ JUMPBY(flag ? oparg : next_instr->op.code == NOT_TAKEN); - } - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); -@@ -6761,8 +9313,13 @@ - } - - TARGET(POP_JUMP_IF_TRUE) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = POP_JUMP_IF_TRUE; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(POP_JUMP_IF_TRUE); - _PyStackRef cond; -@@ -6771,13 +9328,17 @@ - assert(PyStackRef_BoolCheck(cond)); - int flag = PyStackRef_IsTrue(cond); - RECORD_BRANCH_TAKEN(this_instr[1].cache, flag); -- JUMPBY(oparg * flag); -+ JUMPBY(flag ? oparg : next_instr->op.code == NOT_TAKEN); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(POP_TOP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = POP_TOP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(POP_TOP); -@@ -6790,6 +9351,10 @@ - } - - TARGET(PUSH_EXC_INFO) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = PUSH_EXC_INFO; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(PUSH_EXC_INFO); -@@ -6815,6 +9380,10 @@ - } - - TARGET(PUSH_NULL) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = PUSH_NULL; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(PUSH_NULL); -@@ -6827,8 +9396,13 @@ - } - - TARGET(RAISE_VARARGS) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = RAISE_VARARGS; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(RAISE_VARARGS); - _PyStackRef *args; -@@ -6846,14 +9420,20 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - monitor_reraise(tstate, frame, this_instr); - stack_pointer = _PyFrame_GetStackPointer(frame); -- goto exception_unwind; -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ JUMP_TO_LABEL(exception_unwind); - } -- goto error; -+ JUMP_TO_LABEL(error); - } - - TARGET(RERAISE) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = RERAISE; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; - (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(RERAISE); - _PyStackRef *values; -@@ -6865,11 +9445,7 @@ - if (oparg) { - PyObject *lasti = PyStackRef_AsPyObjectBorrow(values[0]); - if (PyLong_Check(lasti)) { -- stack_pointer += -1; -- assert(WITHIN_STACK_BOUNDS()); -- _PyFrame_SetStackPointer(frame, stack_pointer); - frame->instr_ptr = _PyFrame_GetBytecode(frame) + PyLong_AsLong(lasti); -- stack_pointer = _PyFrame_GetStackPointer(frame); - assert(!_PyErr_Occurred(tstate)); - } - else { -@@ -6877,12 +9453,10 @@ - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyErr_SetString(tstate, PyExc_SystemError, "lasti is not an int"); -- stack_pointer = _PyFrame_GetStackPointer(frame); - Py_DECREF(exc); -- goto error; -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ JUMP_TO_LABEL(error); - } -- stack_pointer += 1; -- assert(WITHIN_STACK_BOUNDS()); - } - assert(exc && PyExceptionInstance_Check(exc)); - stack_pointer += -1; -@@ -6891,10 +9465,15 @@ - _PyErr_SetRaisedException(tstate, exc); - monitor_reraise(tstate, frame, this_instr); - stack_pointer = _PyFrame_GetStackPointer(frame); -- goto exception_unwind; -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ JUMP_TO_LABEL(exception_unwind); - } - - TARGET(RESERVED) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = RESERVED; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(RESERVED); -@@ -6904,10 +9483,14 @@ - } - - TARGET(RESUME) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = RESUME; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(RESUME); -- PREDICTED(RESUME); -+ PREDICTED_RESUME:; - _Py_CODEUNIT* const this_instr = next_instr - 1; - (void)this_instr; - // _LOAD_BYTECODE -@@ -6919,10 +9502,10 @@ - _Py_CODEUNIT *bytecode = - _PyEval_GetExecutableCode(tstate, _PyFrame_GetCode(frame)); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (bytecode == NULL) goto error; -- _PyFrame_SetStackPointer(frame, stack_pointer); -+ if (bytecode == NULL) { -+ JUMP_TO_LABEL(error); -+ } - ptrdiff_t off = this_instr - _PyFrame_GetBytecode(frame); -- stack_pointer = _PyFrame_GetStackPointer(frame); - frame->tlbc_index = ((_PyThreadStateImpl *)tstate)->tlbc_index; - frame->instr_ptr = bytecode + off; - // Make sure this_instr gets reset correctley for any uops that -@@ -6942,7 +9525,7 @@ - int err = _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (err) { -- goto error; -+ JUMP_TO_LABEL(error); - } - next_instr = this_instr; - DISPATCH(); -@@ -6966,7 +9549,9 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = _Py_HandlePending(tstate); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err != 0) goto error; -+ if (err != 0) { -+ JUMP_TO_LABEL(error); -+ } - } - } - } -@@ -6974,26 +9559,48 @@ - } - - TARGET(RESUME_CHECK) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = RESUME_CHECK; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(RESUME_CHECK); - static_assert(0 == 0, "incorrect cache size"); - #if defined(__EMSCRIPTEN__) -- DEOPT_IF(_Py_emscripten_signal_clock == 0, RESUME); -+ if (_Py_emscripten_signal_clock == 0) { -+ UPDATE_MISS_STATS(RESUME); -+ assert(_PyOpcode_Deopt[opcode] == (RESUME)); -+ JUMP_TO_PREDICTED(RESUME); -+ } - _Py_emscripten_signal_clock -= Py_EMSCRIPTEN_SIGNAL_HANDLING; - #endif - uintptr_t eval_breaker = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker); - uintptr_t version = FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version); - assert((version & _PY_EVAL_EVENTS_MASK) == 0); -- DEOPT_IF(eval_breaker != version, RESUME); -+ if (eval_breaker != version) { -+ UPDATE_MISS_STATS(RESUME); -+ assert(_PyOpcode_Deopt[opcode] == (RESUME)); -+ JUMP_TO_PREDICTED(RESUME); -+ } - #ifdef Py_GIL_DISABLED -- DEOPT_IF(frame->tlbc_index != -- ((_PyThreadStateImpl *)tstate)->tlbc_index, RESUME); -+ if (frame->tlbc_index != -+ ((_PyThreadStateImpl *)tstate)->tlbc_index) { -+ UPDATE_MISS_STATS(RESUME); -+ assert(_PyOpcode_Deopt[opcode] == (RESUME)); -+ JUMP_TO_PREDICTED(RESUME); -+ } - #endif - DISPATCH(); - } - - TARGET(RETURN_GENERATOR) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = RETURN_GENERATOR; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(RETURN_GENERATOR); -@@ -7003,7 +9610,9 @@ - _PyFrame_SetStackPointer(frame, stack_pointer); - PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (gen == NULL) goto error; -+ if (gen == NULL) { -+ JUMP_TO_LABEL(error); -+ } - assert(EMPTY()); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyInterpreterFrame *gen_frame = &gen->gi_iframe; -@@ -7027,15 +9636,17 @@ - } - - TARGET(RETURN_VALUE) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = RETURN_VALUE; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(RETURN_VALUE); - _PyStackRef retval; - _PyStackRef res; - retval = stack_pointer[-1]; -- #if TIER_ONE -- assert(frame != &entry_frame); -- #endif -+ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); - _PyStackRef temp = retval; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); -@@ -7057,10 +9668,14 @@ - } - - TARGET(SEND) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = SEND; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(SEND); -- PREDICTED(SEND); -+ PREDICTED_SEND:; - _Py_CODEUNIT* const this_instr = next_instr - 2; - (void)this_instr; - _PyStackRef receiver; -@@ -7088,7 +9703,7 @@ - v = stack_pointer[-1]; - PyObject *receiver_o = PyStackRef_AsPyObjectBorrow(receiver); - PyObject *retval_o; -- assert(frame != &entry_frame); -+ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); - if ((tstate->interp->eval_frame == NULL) && - (Py_TYPE(receiver_o) == &PyGen_Type || Py_TYPE(receiver_o) == &PyCoro_Type) && - ((PyGenObject *)receiver_o)->gi_frame_state < FRAME_EXECUTING) -@@ -7136,17 +9751,29 @@ - } - else { - PyStackRef_CLOSE(v); -- goto pop_1_error; -+ JUMP_TO_LABEL(pop_1_error); - } - } -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(v); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - retval = PyStackRef_FromPyObjectSteal(retval_o); - } -- stack_pointer[-1] = retval; -+ stack_pointer[0] = retval; -+ stack_pointer += 1; -+ assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(SEND_GEN) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = SEND_GEN; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(SEND_GEN); -@@ -7158,15 +9785,27 @@ - /* Skip 1 cache entry */ - // _CHECK_PEP_523 - { -- DEOPT_IF(tstate->interp->eval_frame, SEND); -+ if (tstate->interp->eval_frame) { -+ UPDATE_MISS_STATS(SEND); -+ assert(_PyOpcode_Deopt[opcode] == (SEND)); -+ JUMP_TO_PREDICTED(SEND); -+ } - } - // _SEND_GEN_FRAME - { - v = stack_pointer[-1]; - receiver = stack_pointer[-2]; - PyGenObject *gen = (PyGenObject *)PyStackRef_AsPyObjectBorrow(receiver); -- DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type, SEND); -- DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, SEND); -+ if (Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type) { -+ UPDATE_MISS_STATS(SEND); -+ assert(_PyOpcode_Deopt[opcode] == (SEND)); -+ JUMP_TO_PREDICTED(SEND); -+ } -+ if (gen->gi_frame_state >= FRAME_EXECUTING) { -+ UPDATE_MISS_STATS(SEND); -+ assert(_PyOpcode_Deopt[opcode] == (SEND)); -+ JUMP_TO_PREDICTED(SEND); -+ } - STAT_INC(SEND, hit); - gen_frame = &gen->gi_iframe; - _PyFrame_StackPush(gen_frame, v); -@@ -7199,6 +9838,10 @@ - } - - TARGET(SETUP_ANNOTATIONS) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = SETUP_ANNOTATIONS; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(SETUP_ANNOTATIONS); -@@ -7208,32 +9851,44 @@ - _PyErr_Format(tstate, PyExc_SystemError, - "no locals found when setting up annotations"); - stack_pointer = _PyFrame_GetStackPointer(frame); -- goto error; -+ JUMP_TO_LABEL(error); - } - /* check if __annotations__ in locals()... */ - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = PyMapping_GetOptionalItem(LOCALS(), &_Py_ID(__annotations__), &ann_dict); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (err < 0) goto error; -+ if (err < 0) { -+ JUMP_TO_LABEL(error); -+ } - if (ann_dict == NULL) { - _PyFrame_SetStackPointer(frame, stack_pointer); - ann_dict = PyDict_New(); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (ann_dict == NULL) goto error; -+ if (ann_dict == NULL) { -+ JUMP_TO_LABEL(error); -+ } - _PyFrame_SetStackPointer(frame, stack_pointer); - err = PyObject_SetItem(LOCALS(), &_Py_ID(__annotations__), - ann_dict); -- stack_pointer = _PyFrame_GetStackPointer(frame); - Py_DECREF(ann_dict); -- if (err) goto error; -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (err) { -+ JUMP_TO_LABEL(error); -+ } - } - else { -+ _PyFrame_SetStackPointer(frame, stack_pointer); - Py_DECREF(ann_dict); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - } - DISPATCH(); - } - - TARGET(SET_ADD) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = SET_ADD; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(SET_ADD); -@@ -7246,13 +9901,19 @@ - PyStackRef_AsPyObjectBorrow(v)); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(v); -- if (err) goto pop_1_error; -+ if (err) { -+ JUMP_TO_LABEL(pop_1_error); -+ } - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(SET_FUNCTION_ATTRIBUTE) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = SET_FUNCTION_ATTRIBUTE; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(SET_FUNCTION_ATTRIBUTE); -@@ -7277,6 +9938,10 @@ - } - - TARGET(SET_UPDATE) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = SET_UPDATE; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(SET_UPDATE); -@@ -7289,17 +9954,23 @@ - PyStackRef_AsPyObjectBorrow(iterable)); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(iterable); -- if (err < 0) goto pop_1_error; -+ if (err < 0) { -+ JUMP_TO_LABEL(pop_1_error); -+ } - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(STORE_ATTR) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = STORE_ATTR; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 5; - INSTRUCTION_STATS(STORE_ATTR); -- PREDICTED(STORE_ATTR); -+ PREDICTED_STORE_ATTR:; - _Py_CODEUNIT* const this_instr = next_instr - 5; - (void)this_instr; - _PyStackRef owner; -@@ -7309,7 +9980,7 @@ - owner = stack_pointer[-1]; - uint16_t counter = read_u16(&this_instr[1].cache); - (void)counter; -- #if ENABLE_SPECIALIZATION -+ #if ENABLE_SPECIALIZATION_FT - if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); - next_instr = this_instr; -@@ -7320,7 +9991,7 @@ - } - OPCODE_DEFERRED_INC(STORE_ATTR); - ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); -- #endif /* ENABLE_SPECIALIZATION */ -+ #endif /* ENABLE_SPECIALIZATION_FT */ - } - /* Skip 3 cache entries */ - // _STORE_ATTR -@@ -7333,7 +10004,9 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(v); - PyStackRef_CLOSE(owner); -- if (err) goto pop_2_error; -+ if (err) { -+ JUMP_TO_LABEL(pop_2_error); -+ } - } - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); -@@ -7341,28 +10014,54 @@ - } - - TARGET(STORE_ATTR_INSTANCE_VALUE) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = STORE_ATTR_INSTANCE_VALUE; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 5; - INSTRUCTION_STATS(STORE_ATTR_INSTANCE_VALUE); - static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size"); - _PyStackRef owner; - _PyStackRef value; - /* Skip 1 cache entry */ -- // _GUARD_TYPE_VERSION -+ // _GUARD_TYPE_VERSION_AND_LOCK - { - owner = stack_pointer[-1]; - uint32_t type_version = read_u32(&this_instr[2].cache); -- PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); -+ PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - assert(type_version != 0); -- DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); -+ if (!LOCK_OBJECT(owner_o)) { -+ UPDATE_MISS_STATS(STORE_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR)); -+ JUMP_TO_PREDICTED(STORE_ATTR); -+ } -+ PyTypeObject *tp = Py_TYPE(owner_o); -+ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { -+ UNLOCK_OBJECT(owner_o); -+ if (true) { -+ UPDATE_MISS_STATS(STORE_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR)); -+ JUMP_TO_PREDICTED(STORE_ATTR); -+ } -+ } - } - // _GUARD_DORV_NO_DICT - { - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - assert(Py_TYPE(owner_o)->tp_dictoffset < 0); - assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_INLINE_VALUES); -- DEOPT_IF(_PyObject_GetManagedDict(owner_o), STORE_ATTR); -- DEOPT_IF(_PyObject_InlineValues(owner_o)->valid == 0, STORE_ATTR); -+ if (_PyObject_GetManagedDict(owner_o) || -+ !FT_ATOMIC_LOAD_UINT8(_PyObject_InlineValues(owner_o)->valid)) { -+ UNLOCK_OBJECT(owner_o); -+ if (true) { -+ UPDATE_MISS_STATS(STORE_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR)); -+ JUMP_TO_PREDICTED(STORE_ATTR); -+ } -+ } - } - // _STORE_ATTR_INSTANCE_VALUE - { -@@ -7373,24 +10072,31 @@ - assert(_PyObject_GetManagedDict(owner_o) == NULL); - PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); - PyObject *old_value = *value_ptr; -- *value_ptr = PyStackRef_AsPyObjectSteal(value); -+ FT_ATOMIC_STORE_PTR_RELEASE(*value_ptr, PyStackRef_AsPyObjectSteal(value)); - if (old_value == NULL) { - PyDictValues *values = _PyObject_InlineValues(owner_o); - Py_ssize_t index = value_ptr - values->values; - _PyDictValues_AddToInsertionOrder(values, index); - } -- else { -- Py_DECREF(old_value); -- } -+ UNLOCK_OBJECT(owner_o); -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(owner); -+ Py_XDECREF(old_value); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - } -- stack_pointer += -2; -- assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(STORE_ATTR_SLOT) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = STORE_ATTR_SLOT; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 5; - INSTRUCTION_STATS(STORE_ATTR_SLOT); - static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size"); -@@ -7403,27 +10109,45 @@ - uint32_t type_version = read_u32(&this_instr[2].cache); - PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - assert(type_version != 0); -- DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); -+ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { -+ UPDATE_MISS_STATS(STORE_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR)); -+ JUMP_TO_PREDICTED(STORE_ATTR); -+ } - } - // _STORE_ATTR_SLOT - { - value = stack_pointer[-2]; - uint16_t index = read_u16(&this_instr[4].cache); - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); -+ if (!LOCK_OBJECT(owner_o)) { -+ UPDATE_MISS_STATS(STORE_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR)); -+ JUMP_TO_PREDICTED(STORE_ATTR); -+ } - char *addr = (char *)owner_o + index; - STAT_INC(STORE_ATTR, hit); - PyObject *old_value = *(PyObject **)addr; -- *(PyObject **)addr = PyStackRef_AsPyObjectSteal(value); -- Py_XDECREF(old_value); -+ FT_ATOMIC_STORE_PTR_RELEASE(*(PyObject **)addr, PyStackRef_AsPyObjectSteal(value)); -+ UNLOCK_OBJECT(owner_o); -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(owner); -+ Py_XDECREF(old_value); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - } -- stack_pointer += -2; -- assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(STORE_ATTR_WITH_HINT) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = STORE_ATTR_WITH_HINT; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 5; - INSTRUCTION_STATS(STORE_ATTR_WITH_HINT); - static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size"); -@@ -7436,7 +10160,11 @@ - uint32_t type_version = read_u32(&this_instr[2].cache); - PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - assert(type_version != 0); -- DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); -+ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { -+ UPDATE_MISS_STATS(STORE_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR)); -+ JUMP_TO_PREDICTED(STORE_ATTR); -+ } - } - // _STORE_ATTR_WITH_HINT - { -@@ -7445,31 +10173,78 @@ - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_MANAGED_DICT); - PyDictObject *dict = _PyObject_GetManagedDict(owner_o); -- DEOPT_IF(dict == NULL, STORE_ATTR); -+ if (dict == NULL) { -+ UPDATE_MISS_STATS(STORE_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR)); -+ JUMP_TO_PREDICTED(STORE_ATTR); -+ } -+ if (!LOCK_OBJECT(dict)) { -+ UPDATE_MISS_STATS(STORE_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR)); -+ JUMP_TO_PREDICTED(STORE_ATTR); -+ } -+ #ifdef Py_GIL_DISABLED -+ if (dict != _PyObject_GetManagedDict(owner_o)) { -+ UNLOCK_OBJECT(dict); -+ if (true) { -+ UPDATE_MISS_STATS(STORE_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR)); -+ JUMP_TO_PREDICTED(STORE_ATTR); -+ } -+ } -+ #endif - assert(PyDict_CheckExact((PyObject *)dict)); - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); -- DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, STORE_ATTR); -- DEOPT_IF(!DK_IS_UNICODE(dict->ma_keys), STORE_ATTR); -+ if (hint >= (size_t)dict->ma_keys->dk_nentries || -+ !DK_IS_UNICODE(dict->ma_keys)) { -+ UNLOCK_OBJECT(dict); -+ if (true) { -+ UPDATE_MISS_STATS(STORE_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR)); -+ JUMP_TO_PREDICTED(STORE_ATTR); -+ } -+ } - PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; -- DEOPT_IF(ep->me_key != name, STORE_ATTR); -+ if (ep->me_key != name) { -+ UNLOCK_OBJECT(dict); -+ if (true) { -+ UPDATE_MISS_STATS(STORE_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR)); -+ JUMP_TO_PREDICTED(STORE_ATTR); -+ } -+ } - PyObject *old_value = ep->me_value; -- DEOPT_IF(old_value == NULL, STORE_ATTR); -+ if (old_value == NULL) { -+ UNLOCK_OBJECT(dict); -+ if (true) { -+ UPDATE_MISS_STATS(STORE_ATTR); -+ assert(_PyOpcode_Deopt[opcode] == (STORE_ATTR)); -+ JUMP_TO_PREDICTED(STORE_ATTR); -+ } -+ } - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyDict_NotifyEvent(tstate->interp, PyDict_EVENT_MODIFIED, dict, name, PyStackRef_AsPyObjectBorrow(value)); - stack_pointer = _PyFrame_GetStackPointer(frame); -- ep->me_value = PyStackRef_AsPyObjectSteal(value); -+ FT_ATOMIC_STORE_PTR_RELEASE(ep->me_value, PyStackRef_AsPyObjectSteal(value)); -+ UNLOCK_OBJECT(dict); - // old_value should be DECREFed after GC track checking is done, if not, it could raise a segmentation fault, - // when dict only holds the strong reference to value in ep->me_value. -- Py_XDECREF(old_value); - STAT_INC(STORE_ATTR, hit); -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(owner); -+ Py_XDECREF(old_value); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - } -- stack_pointer += -2; -- assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(STORE_DEREF) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = STORE_DEREF; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(STORE_DEREF); -@@ -7485,18 +10260,30 @@ - } - - TARGET(STORE_FAST) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = STORE_FAST; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(STORE_FAST); - _PyStackRef value; - value = stack_pointer[-1]; -- SETLOCAL(oparg, value); -+ _PyStackRef tmp = GETLOCAL(oparg); -+ GETLOCAL(oparg) = value; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_XCLOSE(tmp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - DISPATCH(); - } - - TARGET(STORE_FAST_LOAD_FAST) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = STORE_FAST_LOAD_FAST; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(STORE_FAST_LOAD_FAST); -@@ -7505,13 +10292,21 @@ - value1 = stack_pointer[-1]; - uint32_t oparg1 = oparg >> 4; - uint32_t oparg2 = oparg & 15; -- SETLOCAL(oparg1, value1); -+ _PyStackRef tmp = GETLOCAL(oparg1); -+ GETLOCAL(oparg1) = value1; - value2 = PyStackRef_DUP(GETLOCAL(oparg2)); - stack_pointer[-1] = value2; -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_XCLOSE(tmp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - DISPATCH(); - } - - TARGET(STORE_FAST_STORE_FAST) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = STORE_FAST_STORE_FAST; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(STORE_FAST_STORE_FAST); -@@ -7521,14 +10316,28 @@ - value2 = stack_pointer[-2]; - uint32_t oparg1 = oparg >> 4; - uint32_t oparg2 = oparg & 15; -- SETLOCAL(oparg1, value1); -- SETLOCAL(oparg2, value2); -- stack_pointer += -2; -+ _PyStackRef tmp = GETLOCAL(oparg1); -+ GETLOCAL(oparg1) = value1; -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_XCLOSE(tmp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ tmp = GETLOCAL(oparg2); -+ GETLOCAL(oparg2) = value2; -+ stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_XCLOSE(tmp); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - DISPATCH(); - } - - TARGET(STORE_GLOBAL) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = STORE_GLOBAL; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(STORE_GLOBAL); -@@ -7539,13 +10348,19 @@ - int err = PyDict_SetItem(GLOBALS(), name, PyStackRef_AsPyObjectBorrow(v)); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(v); -- if (err) goto pop_1_error; -+ if (err) { -+ JUMP_TO_LABEL(pop_1_error); -+ } - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(STORE_NAME) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = STORE_NAME; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(STORE_NAME); -@@ -7560,7 +10375,7 @@ - "no locals found when storing %R", name); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(v); -- goto pop_1_error; -+ JUMP_TO_LABEL(pop_1_error); - } - if (PyDict_CheckExact(ns)) { - _PyFrame_SetStackPointer(frame, stack_pointer); -@@ -7573,13 +10388,19 @@ - stack_pointer = _PyFrame_GetStackPointer(frame); - } - PyStackRef_CLOSE(v); -- if (err) goto pop_1_error; -+ if (err) { -+ JUMP_TO_LABEL(pop_1_error); -+ } - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(STORE_SLICE) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = STORE_SLICE; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(STORE_SLICE); -@@ -7613,14 +10434,16 @@ - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - err = PyObject_SetItem(PyStackRef_AsPyObjectBorrow(container), slice, PyStackRef_AsPyObjectBorrow(v)); -- stack_pointer = _PyFrame_GetStackPointer(frame); - Py_DECREF(slice); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += 2; - assert(WITHIN_STACK_BOUNDS()); - } - PyStackRef_CLOSE(v); - PyStackRef_CLOSE(container); -- if (err) goto pop_4_error; -+ if (err) { -+ JUMP_TO_LABEL(pop_4_error); -+ } - } - stack_pointer += -4; - assert(WITHIN_STACK_BOUNDS()); -@@ -7628,10 +10451,14 @@ - } - - TARGET(STORE_SUBSCR) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = STORE_SUBSCR; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(STORE_SUBSCR); -- PREDICTED(STORE_SUBSCR); -+ PREDICTED_STORE_SUBSCR:; - _Py_CODEUNIT* const this_instr = next_instr - 2; - (void)this_instr; - _PyStackRef container; -@@ -7665,7 +10492,9 @@ - PyStackRef_CLOSE(v); - PyStackRef_CLOSE(container); - PyStackRef_CLOSE(sub); -- if (err) goto pop_3_error; -+ if (err) { -+ JUMP_TO_LABEL(pop_3_error); -+ } - } - stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); -@@ -7673,6 +10502,12 @@ - } - - TARGET(STORE_SUBSCR_DICT) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = STORE_SUBSCR_DICT; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(STORE_SUBSCR_DICT); -@@ -7685,21 +10520,35 @@ - dict_st = stack_pointer[-2]; - value = stack_pointer[-3]; - PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st); -- DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); -+ if (!PyDict_CheckExact(dict)) { -+ UPDATE_MISS_STATS(STORE_SUBSCR); -+ assert(_PyOpcode_Deopt[opcode] == (STORE_SUBSCR)); -+ JUMP_TO_PREDICTED(STORE_SUBSCR); -+ } - STAT_INC(STORE_SUBSCR, hit); - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = _PyDict_SetItem_Take2((PyDictObject *)dict, - PyStackRef_AsPyObjectSteal(sub), - PyStackRef_AsPyObjectSteal(value)); - stack_pointer = _PyFrame_GetStackPointer(frame); -- PyStackRef_CLOSE(dict_st); -- if (err) goto pop_3_error; - stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(dict_st); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (err) { -+ JUMP_TO_LABEL(error); -+ } - DISPATCH(); - } - - TARGET(STORE_SUBSCR_LIST_INT) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = STORE_SUBSCR_LIST_INT; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(STORE_SUBSCR_LIST_INT); -@@ -7713,53 +10562,80 @@ - value = stack_pointer[-3]; - PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); - PyObject *list = PyStackRef_AsPyObjectBorrow(list_st); -- DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); -- DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); -+ if (!PyLong_CheckExact(sub)) { -+ UPDATE_MISS_STATS(STORE_SUBSCR); -+ assert(_PyOpcode_Deopt[opcode] == (STORE_SUBSCR)); -+ JUMP_TO_PREDICTED(STORE_SUBSCR); -+ } -+ if (!PyList_CheckExact(list)) { -+ UPDATE_MISS_STATS(STORE_SUBSCR); -+ assert(_PyOpcode_Deopt[opcode] == (STORE_SUBSCR)); -+ JUMP_TO_PREDICTED(STORE_SUBSCR); -+ } - // Ensure nonnegative, zero-or-one-digit ints. -- DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), STORE_SUBSCR); -+ if (!_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) { -+ UPDATE_MISS_STATS(STORE_SUBSCR); -+ assert(_PyOpcode_Deopt[opcode] == (STORE_SUBSCR)); -+ JUMP_TO_PREDICTED(STORE_SUBSCR); -+ } - Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; -- DEOPT_IF(!LOCK_OBJECT(list), STORE_SUBSCR); -+ if (!LOCK_OBJECT(list)) { -+ UPDATE_MISS_STATS(STORE_SUBSCR); -+ assert(_PyOpcode_Deopt[opcode] == (STORE_SUBSCR)); -+ JUMP_TO_PREDICTED(STORE_SUBSCR); -+ } - // Ensure index < len(list) - if (index >= PyList_GET_SIZE(list)) { - UNLOCK_OBJECT(list); -- DEOPT_IF(true, STORE_SUBSCR); -+ if (true) { -+ UPDATE_MISS_STATS(STORE_SUBSCR); -+ assert(_PyOpcode_Deopt[opcode] == (STORE_SUBSCR)); -+ JUMP_TO_PREDICTED(STORE_SUBSCR); -+ } - } - STAT_INC(STORE_SUBSCR, hit); - PyObject *old_value = PyList_GET_ITEM(list, index); - PyList_SET_ITEM(list, index, PyStackRef_AsPyObjectSteal(value)); - assert(old_value != NULL); - UNLOCK_OBJECT(list); // unlock before decrefs! -- Py_DECREF(old_value); - PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); -- PyStackRef_CLOSE(list_st); - stack_pointer += -3; - assert(WITHIN_STACK_BOUNDS()); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyStackRef_CLOSE(list_st); -+ Py_DECREF(old_value); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - DISPATCH(); - } - - TARGET(SWAP) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = SWAP; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(SWAP); -- _PyStackRef bottom_in; -- _PyStackRef top_in; -- _PyStackRef top_out; -- _PyStackRef bottom_out; -- top_in = stack_pointer[-1]; -- bottom_in = stack_pointer[-2 - (oparg-2)]; -- bottom_out = bottom_in; -- top_out = top_in; -+ _PyStackRef *bottom; -+ _PyStackRef *top; -+ top = &stack_pointer[-1]; -+ bottom = &stack_pointer[-2 - (oparg-2)]; -+ _PyStackRef temp = bottom[0]; -+ bottom[0] = top[0]; -+ top[0] = temp; - assert(oparg >= 2); -- stack_pointer[-2 - (oparg-2)] = top_out; -- stack_pointer[-1] = bottom_out; - DISPATCH(); - } - - TARGET(TO_BOOL) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = TO_BOOL; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(TO_BOOL); -- PREDICTED(TO_BOOL); -+ PREDICTED_TO_BOOL:; - _Py_CODEUNIT* const this_instr = next_instr - 4; - (void)this_instr; - _PyStackRef value; -@@ -7788,7 +10664,9 @@ - int err = PyObject_IsTrue(PyStackRef_AsPyObjectBorrow(value)); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(value); -- if (err < 0) goto pop_1_error; -+ if (err < 0) { -+ JUMP_TO_LABEL(pop_1_error); -+ } - res = err ? PyStackRef_True : PyStackRef_False; - } - stack_pointer[-1] = res; -@@ -7796,7 +10674,13 @@ - } - - TARGET(TO_BOOL_ALWAYS_TRUE) { -- _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = TO_BOOL_ALWAYS_TRUE; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; -+ frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(TO_BOOL_ALWAYS_TRUE); - static_assert(INLINE_CACHE_ENTRIES_TO_BOOL == 3, "incorrect cache size"); -@@ -7810,7 +10694,11 @@ - uint32_t type_version = read_u32(&this_instr[2].cache); - PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - assert(type_version != 0); -- DEOPT_IF(tp->tp_version_tag != type_version, TO_BOOL); -+ if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { -+ UPDATE_MISS_STATS(TO_BOOL); -+ assert(_PyOpcode_Deopt[opcode] == (TO_BOOL)); -+ JUMP_TO_PREDICTED(TO_BOOL); -+ } - } - // _REPLACE_WITH_TRUE - { -@@ -7823,6 +10711,12 @@ - } - - TARGET(TO_BOOL_BOOL) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = TO_BOOL_BOOL; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(TO_BOOL_BOOL); -@@ -7831,12 +10725,22 @@ - /* Skip 1 cache entry */ - /* Skip 2 cache entries */ - value = stack_pointer[-1]; -- DEOPT_IF(!PyStackRef_BoolCheck(value), TO_BOOL); -+ if (!PyStackRef_BoolCheck(value)) { -+ UPDATE_MISS_STATS(TO_BOOL); -+ assert(_PyOpcode_Deopt[opcode] == (TO_BOOL)); -+ JUMP_TO_PREDICTED(TO_BOOL); -+ } - STAT_INC(TO_BOOL, hit); - DISPATCH(); - } - - TARGET(TO_BOOL_INT) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = TO_BOOL_INT; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(TO_BOOL_INT); -@@ -7847,7 +10751,11 @@ - /* Skip 2 cache entries */ - value = stack_pointer[-1]; - PyObject *value_o = PyStackRef_AsPyObjectBorrow(value); -- DEOPT_IF(!PyLong_CheckExact(value_o), TO_BOOL); -+ if (!PyLong_CheckExact(value_o)) { -+ UPDATE_MISS_STATS(TO_BOOL); -+ assert(_PyOpcode_Deopt[opcode] == (TO_BOOL)); -+ JUMP_TO_PREDICTED(TO_BOOL); -+ } - STAT_INC(TO_BOOL, hit); - if (_PyLong_IsZero((PyLongObject *)value_o)) { - assert(_Py_IsImmortal(value_o)); -@@ -7862,6 +10770,12 @@ - } - - TARGET(TO_BOOL_LIST) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = TO_BOOL_LIST; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(TO_BOOL_LIST); -@@ -7872,7 +10786,11 @@ - /* Skip 2 cache entries */ - value = stack_pointer[-1]; - PyObject *value_o = PyStackRef_AsPyObjectBorrow(value); -- DEOPT_IF(!PyList_CheckExact(value_o), TO_BOOL); -+ if (!PyList_CheckExact(value_o)) { -+ UPDATE_MISS_STATS(TO_BOOL); -+ assert(_PyOpcode_Deopt[opcode] == (TO_BOOL)); -+ JUMP_TO_PREDICTED(TO_BOOL); -+ } - STAT_INC(TO_BOOL, hit); - res = PyList_GET_SIZE(value_o) ? PyStackRef_True : PyStackRef_False; - PyStackRef_CLOSE(value); -@@ -7881,6 +10799,12 @@ - } - - TARGET(TO_BOOL_NONE) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = TO_BOOL_NONE; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(TO_BOOL_NONE); -@@ -7891,7 +10815,11 @@ - /* Skip 2 cache entries */ - value = stack_pointer[-1]; - // This one is a bit weird, because we expect *some* failures: -- DEOPT_IF(!PyStackRef_IsNone(value), TO_BOOL); -+ if (!PyStackRef_IsNone(value)) { -+ UPDATE_MISS_STATS(TO_BOOL); -+ assert(_PyOpcode_Deopt[opcode] == (TO_BOOL)); -+ JUMP_TO_PREDICTED(TO_BOOL); -+ } - STAT_INC(TO_BOOL, hit); - res = PyStackRef_False; - stack_pointer[-1] = res; -@@ -7899,6 +10827,12 @@ - } - - TARGET(TO_BOOL_STR) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = TO_BOOL_STR; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(TO_BOOL_STR); -@@ -7909,7 +10843,11 @@ - /* Skip 2 cache entries */ - value = stack_pointer[-1]; - PyObject *value_o = PyStackRef_AsPyObjectBorrow(value); -- DEOPT_IF(!PyUnicode_CheckExact(value_o), TO_BOOL); -+ if (!PyUnicode_CheckExact(value_o)) { -+ UPDATE_MISS_STATS(TO_BOOL); -+ assert(_PyOpcode_Deopt[opcode] == (TO_BOOL)); -+ JUMP_TO_PREDICTED(TO_BOOL); -+ } - STAT_INC(TO_BOOL, hit); - if (value_o == &_Py_STR(empty)) { - assert(_Py_IsImmortal(value_o)); -@@ -7925,6 +10863,10 @@ - } - - TARGET(UNARY_INVERT) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = UNARY_INVERT; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(UNARY_INVERT); -@@ -7935,13 +10877,19 @@ - PyObject *res_o = PyNumber_Invert(PyStackRef_AsPyObjectBorrow(value)); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(value); -- if (res_o == NULL) goto pop_1_error; -+ if (res_o == NULL) { -+ JUMP_TO_LABEL(pop_1_error); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-1] = res; - DISPATCH(); - } - - TARGET(UNARY_NEGATIVE) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = UNARY_NEGATIVE; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(UNARY_NEGATIVE); -@@ -7952,13 +10900,19 @@ - PyObject *res_o = PyNumber_Negative(PyStackRef_AsPyObjectBorrow(value)); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(value); -- if (res_o == NULL) goto pop_1_error; -+ if (res_o == NULL) { -+ JUMP_TO_LABEL(pop_1_error); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[-1] = res; - DISPATCH(); - } - - TARGET(UNARY_NOT) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = UNARY_NOT; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(UNARY_NOT); -@@ -7973,6 +10927,10 @@ - } - - TARGET(UNPACK_EX) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = UNPACK_EX; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(UNPACK_EX); -@@ -7985,17 +10943,23 @@ - int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg & 0xFF, oparg >> 8, top); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(seq); -- if (res == 0) goto pop_1_error; -+ if (res == 0) { -+ JUMP_TO_LABEL(pop_1_error); -+ } - stack_pointer += (oparg & 0xFF) + (oparg >> 8); - assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } - - TARGET(UNPACK_SEQUENCE) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = UNPACK_SEQUENCE; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(UNPACK_SEQUENCE); -- PREDICTED(UNPACK_SEQUENCE); -+ PREDICTED_UNPACK_SEQUENCE:; - _Py_CODEUNIT* const this_instr = next_instr - 2; - (void)this_instr; - _PyStackRef seq; -@@ -8027,7 +10991,9 @@ - int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg, -1, top); - stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE(seq); -- if (res == 0) goto pop_1_error; -+ if (res == 0) { -+ JUMP_TO_LABEL(pop_1_error); -+ } - } - stack_pointer += -1 + oparg; - assert(WITHIN_STACK_BOUNDS()); -@@ -8035,6 +11001,12 @@ - } - - TARGET(UNPACK_SEQUENCE_LIST) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = UNPACK_SEQUENCE_LIST; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(UNPACK_SEQUENCE_LIST); -@@ -8045,11 +11017,23 @@ - seq = stack_pointer[-1]; - values = &stack_pointer[-1]; - PyObject *seq_o = PyStackRef_AsPyObjectBorrow(seq); -- DEOPT_IF(!PyList_CheckExact(seq_o), UNPACK_SEQUENCE); -- DEOPT_IF(!LOCK_OBJECT(seq_o), UNPACK_SEQUENCE); -+ if (!PyList_CheckExact(seq_o)) { -+ UPDATE_MISS_STATS(UNPACK_SEQUENCE); -+ assert(_PyOpcode_Deopt[opcode] == (UNPACK_SEQUENCE)); -+ JUMP_TO_PREDICTED(UNPACK_SEQUENCE); -+ } -+ if (!LOCK_OBJECT(seq_o)) { -+ UPDATE_MISS_STATS(UNPACK_SEQUENCE); -+ assert(_PyOpcode_Deopt[opcode] == (UNPACK_SEQUENCE)); -+ JUMP_TO_PREDICTED(UNPACK_SEQUENCE); -+ } - if (PyList_GET_SIZE(seq_o) != oparg) { - UNLOCK_OBJECT(seq_o); -- DEOPT_IF(true, UNPACK_SEQUENCE); -+ if (true) { -+ UPDATE_MISS_STATS(UNPACK_SEQUENCE); -+ assert(_PyOpcode_Deopt[opcode] == (UNPACK_SEQUENCE)); -+ JUMP_TO_PREDICTED(UNPACK_SEQUENCE); -+ } - } - STAT_INC(UNPACK_SEQUENCE, hit); - PyObject **items = _PyList_ITEMS(seq_o); -@@ -8064,6 +11048,12 @@ - } - - TARGET(UNPACK_SEQUENCE_TUPLE) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = UNPACK_SEQUENCE_TUPLE; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(UNPACK_SEQUENCE_TUPLE); -@@ -8074,8 +11064,16 @@ - seq = stack_pointer[-1]; - values = &stack_pointer[-1]; - PyObject *seq_o = PyStackRef_AsPyObjectBorrow(seq); -- DEOPT_IF(!PyTuple_CheckExact(seq_o), UNPACK_SEQUENCE); -- DEOPT_IF(PyTuple_GET_SIZE(seq_o) != oparg, UNPACK_SEQUENCE); -+ if (!PyTuple_CheckExact(seq_o)) { -+ UPDATE_MISS_STATS(UNPACK_SEQUENCE); -+ assert(_PyOpcode_Deopt[opcode] == (UNPACK_SEQUENCE)); -+ JUMP_TO_PREDICTED(UNPACK_SEQUENCE); -+ } -+ if (PyTuple_GET_SIZE(seq_o) != oparg) { -+ UPDATE_MISS_STATS(UNPACK_SEQUENCE); -+ assert(_PyOpcode_Deopt[opcode] == (UNPACK_SEQUENCE)); -+ JUMP_TO_PREDICTED(UNPACK_SEQUENCE); -+ } - STAT_INC(UNPACK_SEQUENCE, hit); - PyObject **items = _PyTuple_ITEMS(seq_o); - for (int i = oparg; --i >= 0; ) { -@@ -8088,6 +11086,12 @@ - } - - TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = UNPACK_SEQUENCE_TWO_TUPLE; -+ (void)(opcode); -+ #endif -+ _Py_CODEUNIT* const this_instr = next_instr; -+ (void)this_instr; - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(UNPACK_SEQUENCE_TWO_TUPLE); -@@ -8099,8 +11103,16 @@ - seq = stack_pointer[-1]; - assert(oparg == 2); - PyObject *seq_o = PyStackRef_AsPyObjectBorrow(seq); -- DEOPT_IF(!PyTuple_CheckExact(seq_o), UNPACK_SEQUENCE); -- DEOPT_IF(PyTuple_GET_SIZE(seq_o) != 2, UNPACK_SEQUENCE); -+ if (!PyTuple_CheckExact(seq_o)) { -+ UPDATE_MISS_STATS(UNPACK_SEQUENCE); -+ assert(_PyOpcode_Deopt[opcode] == (UNPACK_SEQUENCE)); -+ JUMP_TO_PREDICTED(UNPACK_SEQUENCE); -+ } -+ if (PyTuple_GET_SIZE(seq_o) != 2) { -+ UPDATE_MISS_STATS(UNPACK_SEQUENCE); -+ assert(_PyOpcode_Deopt[opcode] == (UNPACK_SEQUENCE)); -+ JUMP_TO_PREDICTED(UNPACK_SEQUENCE); -+ } - STAT_INC(UNPACK_SEQUENCE, hit); - val0 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 0)); - val1 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 1)); -@@ -8113,6 +11125,10 @@ - } - - TARGET(WITH_EXCEPT_START) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = WITH_EXCEPT_START; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(WITH_EXCEPT_START); -@@ -8144,7 +11160,9 @@ - tb = Py_None; - } - else { -+ _PyFrame_SetStackPointer(frame, stack_pointer); - Py_DECREF(tb); -+ stack_pointer = _PyFrame_GetStackPointer(frame); - } - assert(PyStackRef_LongCheck(lasti)); - (void)lasti; // Shut up compiler warning if asserts are off -@@ -8154,7 +11172,9 @@ - PyObject *res_o = PyObject_Vectorcall(exit_func_o, stack + 2 - has_self, - (3 + has_self) | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); - stack_pointer = _PyFrame_GetStackPointer(frame); -- if (res_o == NULL) goto error; -+ if (res_o == NULL) { -+ JUMP_TO_LABEL(error); -+ } - res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; -@@ -8163,6 +11183,10 @@ - } - - TARGET(YIELD_VALUE) { -+ #if defined(Py_TAIL_CALL_INTERP) -+ int opcode = YIELD_VALUE; -+ (void)(opcode); -+ #endif - frame->instr_ptr = next_instr; - next_instr += 1; - INSTRUCTION_STATS(YIELD_VALUE); -@@ -8172,9 +11196,7 @@ - // NOTE: It's important that YIELD_VALUE never raises an exception! - // The compiler treats any exception raised here as a failed close() - // or throw() call. -- #if TIER_ONE -- assert(frame != &entry_frame); -- #endif -+ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); - frame->instr_ptr++; - PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); - assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); -@@ -8209,4 +11231,191 @@ - assert(WITHIN_STACK_BOUNDS()); - DISPATCH(); - } -+ -+ /* END INSTRUCTIONS */ -+#ifndef Py_TAIL_CALL_INTERP -+#if USE_COMPUTED_GOTOS -+ _unknown_opcode: -+#else -+ EXTRA_CASES // From pycore_opcode_metadata.h, a 'case' for each unused opcode -+#endif -+ /* Tell C compilers not to hold the opcode variable in the loop. -+ next_instr points the current instruction without TARGET(). */ -+ opcode = next_instr->op.code; -+ _PyErr_Format(tstate, PyExc_SystemError, -+ "%U:%d: unknown opcode %d", -+ _PyFrame_GetCode(frame)->co_filename, -+ PyUnstable_InterpreterFrame_GetLine(frame), -+ opcode); -+JUMP_TO_LABEL(error); -+ -+ -+ } -+ -+ /* This should never be reached. Every opcode should end with DISPATCH() -+ or goto error. */ -+ Py_UNREACHABLE(); -+#endif /* Py_TAIL_CALL_INTERP */ -+ /* BEGIN LABELS */ -+ -+ LABEL(pop_4_error) -+ { -+ STACK_SHRINK(4); -+ JUMP_TO_LABEL(error); -+ } -+ -+ LABEL(pop_3_error) -+ { -+ STACK_SHRINK(3); -+ JUMP_TO_LABEL(error); -+ } -+ -+ LABEL(pop_2_error) -+ { -+ STACK_SHRINK(2); -+ JUMP_TO_LABEL(error); -+ } -+ -+ LABEL(pop_1_error) -+ { -+ STACK_SHRINK(1); -+ JUMP_TO_LABEL(error); -+ } -+ -+ LABEL(error) -+ { -+ /* Double-check exception status. */ -+ #ifdef NDEBUG -+ if (!_PyErr_Occurred(tstate)) { -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ _PyErr_SetString(tstate, PyExc_SystemError, -+ "error return without exception set"); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ } -+ #else -+ assert(_PyErr_Occurred(tstate)); -+ #endif -+ -+ /* Log traceback info. */ -+ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); -+ if (!_PyFrame_IsIncomplete(frame)) { -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyFrameObject *f = _PyFrame_GetFrameObject(frame); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ if (f != NULL) { -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ PyTraceBack_Here(f); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ } -+ } -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ _PyEval_MonitorRaise(tstate, frame, next_instr-1); -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ _PyFrame_SetStackPointer(frame, stack_pointer); -+ JUMP_TO_LABEL(exception_unwind); -+ } -+ -+ LABEL(exception_unwind) -+ { -+ /* STACK SPILLED */ -+ /* We can't use frame->instr_ptr here, as RERAISE may have set it */ -+ int offset = INSTR_OFFSET()-1; -+ int level, handler, lasti; -+ int handled = get_exception_handler(_PyFrame_GetCode(frame), offset, &level, &handler, &lasti); -+ if (handled == 0) { -+ // No handlers, so exit. -+ assert(_PyErr_Occurred(tstate)); -+ /* Pop remaining stack entries. */ -+ _PyStackRef *stackbase = _PyFrame_Stackbase(frame); -+ while (frame->stackpointer > stackbase) { -+ _PyStackRef ref = _PyFrame_StackPop(frame); -+ PyStackRef_XCLOSE(ref); -+ } -+ monitor_unwind(tstate, frame, next_instr-1); -+ JUMP_TO_LABEL(exit_unwind); -+ } -+ assert(STACK_LEVEL() >= level); -+ _PyStackRef *new_top = _PyFrame_Stackbase(frame) + level; -+ assert(frame->stackpointer >= new_top); -+ while (frame->stackpointer > new_top) { -+ _PyStackRef ref = _PyFrame_StackPop(frame); -+ PyStackRef_XCLOSE(ref); -+ } -+ if (lasti) { -+ int frame_lasti = _PyInterpreterFrame_LASTI(frame); -+ PyObject *lasti = PyLong_FromLong(frame_lasti); -+ if (lasti == NULL) { -+ JUMP_TO_LABEL(exception_unwind); -+ } -+ _PyFrame_StackPush(frame, PyStackRef_FromPyObjectSteal(lasti)); -+ } -+ /* Make the raw exception data -+ available to the handler, -+ so a program can emulate the -+ Python main loop. */ -+ PyObject *exc = _PyErr_GetRaisedException(tstate); -+ _PyFrame_StackPush(frame, PyStackRef_FromPyObjectSteal(exc)); -+ next_instr = _PyFrame_GetBytecode(frame) + handler; -+ int err = monitor_handled(tstate, frame, next_instr, exc); -+ if (err < 0) { -+ JUMP_TO_LABEL(exception_unwind); -+ } -+ /* Resume normal execution */ -+ #ifdef Py_DEBUG -+ if (frame->lltrace >= 5) { -+ lltrace_resume_frame(frame); -+ } -+ #endif -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ #ifdef Py_TAIL_CALL_INTERP -+ int opcode; -+ #endif -+ DISPATCH(); -+ } -+ -+ LABEL(exit_unwind) -+ { -+ /* STACK SPILLED */ -+ assert(_PyErr_Occurred(tstate)); -+ _Py_LeaveRecursiveCallPy(tstate); -+ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); -+ // GH-99729: We need to unlink the frame *before* clearing it: -+ _PyInterpreterFrame *dying = frame; -+ frame = tstate->current_frame = dying->previous; -+ _PyEval_FrameClearAndPop(tstate, dying); -+ frame->return_offset = 0; -+ if (frame->owner == FRAME_OWNED_BY_INTERPRETER) { -+ /* Restore previous frame and exit */ -+ tstate->current_frame = frame->previous; -+ tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS; -+ return NULL; -+ } -+ next_instr = frame->instr_ptr; -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ JUMP_TO_LABEL(error); -+ } -+ -+ LABEL(start_frame) -+ { -+ /* STACK SPILLED */ -+ int too_deep = _Py_EnterRecursivePy(tstate); -+ if (too_deep) { -+ JUMP_TO_LABEL(exit_unwind); -+ } -+ next_instr = frame->instr_ptr; -+ LLTRACE_RESUME_FRAME(); -+ #ifdef Py_DEBUG -+ /* _PyEval_EvalFrameDefault() must not be called with an exception set, -+ because it can clear it (directly or indirectly) and so the -+ caller loses its exception */ -+ assert(!_PyErr_Occurred(tstate)); -+ #endif -+ stack_pointer = _PyFrame_GetStackPointer(frame); -+ #ifdef Py_TAIL_CALL_INTERP -+ int opcode; -+ #endif -+ DISPATCH(); -+ } -+ -+/* END LABELS */ - #undef TIER_ONE -diff --git a/Python/getopt.c b/Python/getopt.c -index f64c89fa227..39a6938dec7 100644 ---- a/Python/getopt.c -+++ b/Python/getopt.c -@@ -102,7 +102,7 @@ - // Parse long option. - if (*opt_ptr == L'\0') { - if (_PyOS_opterr) { -- fprintf(stderr, "expected long option\n"); -+ fprintf(stderr, "Expected long option\n"); - } - return -1; - } -@@ -114,7 +114,7 @@ - } - if (!opt->name) { - if (_PyOS_opterr) { -- fprintf(stderr, "unknown option %ls\n", argv[_PyOS_optind - 1]); -+ fprintf(stderr, "Unknown option: %ls\n", argv[_PyOS_optind - 1]); - } - return '_'; - } -diff --git a/Python/hamt.c b/Python/hamt.c -index cfd211f4541..ed43a0449d7 100644 ---- a/Python/hamt.c -+++ b/Python/hamt.c -@@ -319,6 +319,8 @@ - Py_ssize_t a_count; - } PyHamtNode_Array; - -+#define _PyHamtNode_Array_CAST(op) ((PyHamtNode_Array *)(op)) -+ - - typedef struct { - PyObject_VAR_HEAD -@@ -326,6 +328,8 @@ - PyObject *c_array[1]; - } PyHamtNode_Collision; - -+#define _PyHamtNode_Collision_CAST(op) ((PyHamtNode_Collision *)(op)) -+ - - static PyHamtObject * - hamt_alloc(void); -@@ -479,6 +483,8 @@ - #endif /* Py_DEBUG */ - /////////////////////////////////// Bitmap Node - -+#define _PyHamtNode_Bitmap_CAST(op) ((PyHamtNode_Bitmap *)(op)) -+ - - static PyHamtNode * - hamt_node_bitmap_new(Py_ssize_t size) -@@ -1083,30 +1089,27 @@ - } - - static int --hamt_node_bitmap_traverse(PyHamtNode_Bitmap *self, visitproc visit, void *arg) -+hamt_node_bitmap_traverse(PyObject *op, visitproc visit, void *arg) - { - /* Bitmap's tp_traverse */ -- -- Py_ssize_t i; -- -- for (i = Py_SIZE(self); --i >= 0; ) { -+ PyHamtNode_Bitmap *self = _PyHamtNode_Bitmap_CAST(op); -+ for (Py_ssize_t i = Py_SIZE(self); --i >= 0;) { - Py_VISIT(self->b_array[i]); - } -- - return 0; - } - - static void --hamt_node_bitmap_dealloc(PyHamtNode_Bitmap *self) -+hamt_node_bitmap_dealloc(PyObject *self) - { - /* Bitmap's tp_dealloc */ - -- Py_ssize_t len = Py_SIZE(self); -- Py_ssize_t i; -+ PyHamtNode_Bitmap *node = _PyHamtNode_Bitmap_CAST(self); -+ Py_ssize_t i, len = Py_SIZE(self); - -- if (Py_SIZE(self) == 0) { -+ if (len == 0) { - /* The empty node is statically allocated. */ -- assert(self == &_Py_SINGLETON(hamt_bitmap_node_empty)); -+ assert(node == &_Py_SINGLETON(hamt_bitmap_node_empty)); - #ifdef Py_DEBUG - _Py_FatalRefcountError("deallocating the empty hamt node bitmap singleton"); - #else -@@ -1120,11 +1123,11 @@ - if (len > 0) { - i = len; - while (--i >= 0) { -- Py_XDECREF(self->b_array[i]); -+ Py_XDECREF(node->b_array[i]); - } - } - -- Py_TYPE(self)->tp_free((PyObject *)self); -+ Py_TYPE(self)->tp_free(self); - Py_TRASHCAN_END - } - -@@ -1489,38 +1492,30 @@ - - - static int --hamt_node_collision_traverse(PyHamtNode_Collision *self, -- visitproc visit, void *arg) -+hamt_node_collision_traverse(PyObject *op, visitproc visit, void *arg) - { - /* Collision's tp_traverse */ -- -- Py_ssize_t i; -- -- for (i = Py_SIZE(self); --i >= 0; ) { -+ PyHamtNode_Collision *self = _PyHamtNode_Collision_CAST(op); -+ for (Py_ssize_t i = Py_SIZE(self); --i >= 0; ) { - Py_VISIT(self->c_array[i]); - } -- - return 0; - } - - static void --hamt_node_collision_dealloc(PyHamtNode_Collision *self) -+hamt_node_collision_dealloc(PyObject *self) - { - /* Collision's tp_dealloc */ -- - Py_ssize_t len = Py_SIZE(self); -- - PyObject_GC_UnTrack(self); - Py_TRASHCAN_BEGIN(self, hamt_node_collision_dealloc) -- - if (len > 0) { -- -+ PyHamtNode_Collision *node = _PyHamtNode_Collision_CAST(self); - while (--len >= 0) { -- Py_XDECREF(self->c_array[len]); -+ Py_XDECREF(node->c_array[len]); - } - } -- -- Py_TYPE(self)->tp_free((PyObject *)self); -+ Py_TYPE(self)->tp_free(self); - Py_TRASHCAN_END - } - -@@ -1868,35 +1863,27 @@ - } - - static int --hamt_node_array_traverse(PyHamtNode_Array *self, -- visitproc visit, void *arg) -+hamt_node_array_traverse(PyObject *op, visitproc visit, void *arg) - { - /* Array's tp_traverse */ -- -- Py_ssize_t i; -- -- for (i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) { -+ PyHamtNode_Array *self = _PyHamtNode_Array_CAST(op); -+ for (Py_ssize_t i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) { - Py_VISIT(self->a_array[i]); - } -- - return 0; - } - - static void --hamt_node_array_dealloc(PyHamtNode_Array *self) -+hamt_node_array_dealloc(PyObject *self) - { - /* Array's tp_dealloc */ -- -- Py_ssize_t i; -- - PyObject_GC_UnTrack(self); - Py_TRASHCAN_BEGIN(self, hamt_node_array_dealloc) -- -- for (i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) { -- Py_XDECREF(self->a_array[i]); -+ PyHamtNode_Array *obj = _PyHamtNode_Array_CAST(self); -+ for (Py_ssize_t i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) { -+ Py_XDECREF(obj->a_array[i]); - } -- -- Py_TYPE(self)->tp_free((PyObject *)self); -+ Py_TYPE(self)->tp_free(self); - Py_TRASHCAN_END - } - -@@ -2605,6 +2592,8 @@ - hamt_dump(PyHamtObject *self); - #endif - -+#define _PyHamtObject_CAST(op) ((PyHamtObject *)(op)) -+ - - static PyObject * - hamt_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -@@ -2613,24 +2602,27 @@ - } - - static int --hamt_tp_clear(PyHamtObject *self) -+hamt_tp_clear(PyObject *op) - { -+ PyHamtObject *self = _PyHamtObject_CAST(op); - Py_CLEAR(self->h_root); - return 0; - } - - - static int --hamt_tp_traverse(PyHamtObject *self, visitproc visit, void *arg) -+hamt_tp_traverse(PyObject *op, visitproc visit, void *arg) - { -+ PyHamtObject *self = _PyHamtObject_CAST(op); - Py_VISIT(self->h_root); - return 0; - } - - static void --hamt_tp_dealloc(PyHamtObject *self) -+hamt_tp_dealloc(PyObject *self) - { -- if (self == _empty_hamt) { -+ PyHamtObject *obj = _PyHamtObject_CAST(self); -+ if (obj == _empty_hamt) { - /* The empty one is statically allocated. */ - #ifdef Py_DEBUG - _Py_FatalRefcountError("deallocating the empty hamt singleton"); -@@ -2640,8 +2632,8 @@ - } - - PyObject_GC_UnTrack(self); -- if (self->h_weakreflist != NULL) { -- PyObject_ClearWeakRefs((PyObject*)self); -+ if (obj->h_weakreflist != NULL) { -+ PyObject_ClearWeakRefs(self); - } - (void)hamt_tp_clear(self); - Py_TYPE(self)->tp_free(self); -@@ -2673,16 +2665,18 @@ - } - - static int --hamt_tp_contains(PyHamtObject *self, PyObject *key) -+hamt_tp_contains(PyObject *op, PyObject *key) - { - PyObject *val; -+ PyHamtObject *self = _PyHamtObject_CAST(op); - return _PyHamt_Find(self, key, &val); - } - - static PyObject * --hamt_tp_subscript(PyHamtObject *self, PyObject *key) -+hamt_tp_subscript(PyObject *op, PyObject *key) - { - PyObject *val; -+ PyHamtObject *self = _PyHamtObject_CAST(op); - hamt_find_t res = hamt_find(self, key, &val); - switch (res) { - case F_ERROR: -@@ -2698,19 +2692,21 @@ - } - - static Py_ssize_t --hamt_tp_len(PyHamtObject *self) -+hamt_tp_len(PyObject *op) - { -+ PyHamtObject *self = _PyHamtObject_CAST(op); - return _PyHamt_Len(self); - } - - static PyObject * --hamt_tp_iter(PyHamtObject *self) -+hamt_tp_iter(PyObject *op) - { -+ PyHamtObject *self = _PyHamtObject_CAST(op); - return _PyHamt_NewIterKeys(self); - } - - static PyObject * --hamt_py_set(PyHamtObject *self, PyObject *args) -+hamt_py_set(PyObject *op, PyObject *args) - { - PyObject *key; - PyObject *val; -@@ -2719,11 +2715,12 @@ - return NULL; - } - -+ PyHamtObject *self = _PyHamtObject_CAST(op); - return (PyObject *)_PyHamt_Assoc(self, key, val); - } - - static PyObject * --hamt_py_get(PyHamtObject *self, PyObject *args) -+hamt_py_get(PyObject *op, PyObject *args) - { - PyObject *key; - PyObject *def = NULL; -@@ -2733,6 +2730,7 @@ - } - - PyObject *val = NULL; -+ PyHamtObject *self = _PyHamtObject_CAST(op); - hamt_find_t res = hamt_find(self, key, &val); - switch (res) { - case F_ERROR: -@@ -2750,67 +2748,63 @@ - } - - static PyObject * --hamt_py_delete(PyHamtObject *self, PyObject *key) -+hamt_py_delete(PyObject *op, PyObject *key) - { -+ PyHamtObject *self = _PyHamtObject_CAST(op); - return (PyObject *)_PyHamt_Without(self, key); - } - - static PyObject * --hamt_py_items(PyHamtObject *self, PyObject *args) -+hamt_py_items(PyObject *op, PyObject *args) - { -+ PyHamtObject *self = _PyHamtObject_CAST(op); - return _PyHamt_NewIterItems(self); - } - - static PyObject * --hamt_py_values(PyHamtObject *self, PyObject *args) -+hamt_py_values(PyObject *op, PyObject *args) - { -+ PyHamtObject *self = _PyHamtObject_CAST(op); - return _PyHamt_NewIterValues(self); - } - - static PyObject * --hamt_py_keys(PyHamtObject *self, PyObject *Py_UNUSED(args)) -+hamt_py_keys(PyObject *op, PyObject *Py_UNUSED(args)) - { -+ PyHamtObject *self = _PyHamtObject_CAST(op); - return _PyHamt_NewIterKeys(self); - } - - #ifdef Py_DEBUG - static PyObject * --hamt_py_dump(PyHamtObject *self, PyObject *Py_UNUSED(args)) -+hamt_py_dump(PyObject *op, PyObject *Py_UNUSED(args)) - { -+ PyHamtObject *self = _PyHamtObject_CAST(op); - return hamt_dump(self); - } - #endif - - - static PyMethodDef PyHamt_methods[] = { -- {"set", _PyCFunction_CAST(hamt_py_set), METH_VARARGS, NULL}, -- {"get", _PyCFunction_CAST(hamt_py_get), METH_VARARGS, NULL}, -- {"delete", _PyCFunction_CAST(hamt_py_delete), METH_O, NULL}, -- {"items", _PyCFunction_CAST(hamt_py_items), METH_NOARGS, NULL}, -- {"keys", _PyCFunction_CAST(hamt_py_keys), METH_NOARGS, NULL}, -- {"values", _PyCFunction_CAST(hamt_py_values), METH_NOARGS, NULL}, -+ {"set", hamt_py_set, METH_VARARGS, NULL}, -+ {"get", hamt_py_get, METH_VARARGS, NULL}, -+ {"delete", hamt_py_delete, METH_O, NULL}, -+ {"items", hamt_py_items, METH_NOARGS, NULL}, -+ {"keys", hamt_py_keys, METH_NOARGS, NULL}, -+ {"values", hamt_py_values, METH_NOARGS, NULL}, - #ifdef Py_DEBUG -- {"__dump__", _PyCFunction_CAST(hamt_py_dump), METH_NOARGS, NULL}, -+ {"__dump__", hamt_py_dump, METH_NOARGS, NULL}, - #endif - {NULL, NULL} - }; - - static PySequenceMethods PyHamt_as_sequence = { -- 0, /* sq_length */ -- 0, /* sq_concat */ -- 0, /* sq_repeat */ -- 0, /* sq_item */ -- 0, /* sq_slice */ -- 0, /* sq_ass_item */ -- 0, /* sq_ass_slice */ -- (objobjproc)hamt_tp_contains, /* sq_contains */ -- 0, /* sq_inplace_concat */ -- 0, /* sq_inplace_repeat */ -+ .sq_contains = hamt_tp_contains, - }; - - static PyMappingMethods PyHamt_as_mapping = { -- (lenfunc)hamt_tp_len, /* mp_length */ -- (binaryfunc)hamt_tp_subscript, /* mp_subscript */ -+ .mp_length = hamt_tp_len, -+ .mp_subscript = hamt_tp_subscript, - }; - - PyTypeObject _PyHamt_Type = { -@@ -2820,13 +2814,13 @@ - .tp_methods = PyHamt_methods, - .tp_as_mapping = &PyHamt_as_mapping, - .tp_as_sequence = &PyHamt_as_sequence, -- .tp_iter = (getiterfunc)hamt_tp_iter, -- .tp_dealloc = (destructor)hamt_tp_dealloc, -+ .tp_iter = hamt_tp_iter, -+ .tp_dealloc = hamt_tp_dealloc, - .tp_getattro = PyObject_GenericGetAttr, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, - .tp_richcompare = hamt_tp_richcompare, -- .tp_traverse = (traverseproc)hamt_tp_traverse, -- .tp_clear = (inquiry)hamt_tp_clear, -+ .tp_traverse = hamt_tp_traverse, -+ .tp_clear = hamt_tp_clear, - .tp_new = hamt_tp_new, - .tp_weaklistoffset = offsetof(PyHamtObject, h_weakreflist), - .tp_hash = PyObject_HashNotImplemented, -@@ -2841,10 +2835,10 @@ - "hamt_array_node", - sizeof(PyHamtNode_Array), - 0, -- .tp_dealloc = (destructor)hamt_node_array_dealloc, -+ .tp_dealloc = hamt_node_array_dealloc, - .tp_getattro = PyObject_GenericGetAttr, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, -- .tp_traverse = (traverseproc)hamt_node_array_traverse, -+ .tp_traverse = hamt_node_array_traverse, - .tp_free = PyObject_GC_Del, - .tp_hash = PyObject_HashNotImplemented, - }; -@@ -2854,10 +2848,10 @@ - "hamt_bitmap_node", - sizeof(PyHamtNode_Bitmap) - sizeof(PyObject *), - sizeof(PyObject *), -- .tp_dealloc = (destructor)hamt_node_bitmap_dealloc, -+ .tp_dealloc = hamt_node_bitmap_dealloc, - .tp_getattro = PyObject_GenericGetAttr, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, -- .tp_traverse = (traverseproc)hamt_node_bitmap_traverse, -+ .tp_traverse = hamt_node_bitmap_traverse, - .tp_free = PyObject_GC_Del, - .tp_hash = PyObject_HashNotImplemented, - }; -@@ -2867,10 +2861,10 @@ - "hamt_collision_node", - sizeof(PyHamtNode_Collision) - sizeof(PyObject *), - sizeof(PyObject *), -- .tp_dealloc = (destructor)hamt_node_collision_dealloc, -+ .tp_dealloc = hamt_node_collision_dealloc, - .tp_getattro = PyObject_GenericGetAttr, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, -- .tp_traverse = (traverseproc)hamt_node_collision_traverse, -+ .tp_traverse = hamt_node_collision_traverse, - .tp_free = PyObject_GC_Del, - .tp_hash = PyObject_HashNotImplemented, - }; -diff --git a/Python/import.c b/Python/import.c -index a9282dde633..8cc8d3a503b 100644 ---- a/Python/import.c -+++ b/Python/import.c -@@ -594,7 +594,8 @@ - if (PyList_SetSlice(MODULES_BY_INDEX(interp), - 0, PyList_GET_SIZE(MODULES_BY_INDEX(interp)), - NULL)) { -- PyErr_FormatUnraisable("Exception ignored on clearing interpreters module list"); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "clearing interpreters module list"); - } - } - -@@ -4080,13 +4081,15 @@ - int verbose = _PyInterpreterState_GetConfig(interp)->verbose; - - if (_PySys_ClearAttrString(interp, "meta_path", verbose) < 0) { -- PyErr_FormatUnraisable("Exception ignored on clearing sys.meta_path"); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "clearing sys.meta_path"); - } - - // XXX Pull in most of finalize_modules() in pylifecycle.c. - - if (_PySys_ClearAttrString(interp, "modules", verbose) < 0) { -- PyErr_FormatUnraisable("Exception ignored on clearing sys.modules"); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "clearing sys.modules"); - } - - _PyImport_ClearCore(interp); -@@ -4111,7 +4114,7 @@ - PySys_WriteStderr("# installing zipimport hook\n"); - } - -- PyObject *zipimporter = _PyImport_GetModuleAttrString("zipimport", "zipimporter"); -+ PyObject *zipimporter = PyImport_ImportModuleAttrString("zipimport", "zipimporter"); - if (zipimporter == NULL) { - _PyErr_Clear(tstate); /* No zipimporter object -- okay */ - if (verbose) { -@@ -4161,10 +4164,12 @@ - // XXX Uninstall importlib metapath importers here? - - if (_PySys_ClearAttrString(interp, "path_importer_cache", verbose) < 0) { -- PyErr_FormatUnraisable("Exception ignored on clearing sys.path_importer_cache"); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "clearing sys.path_importer_cache"); - } - if (_PySys_ClearAttrString(interp, "path_hooks", verbose) < 0) { -- PyErr_FormatUnraisable("Exception ignored on clearing sys.path_hooks"); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "clearing sys.path_hooks"); - } - } - -@@ -4174,7 +4179,7 @@ - /******************/ - - PyObject * --_PyImport_GetModuleAttr(PyObject *modname, PyObject *attrname) -+PyImport_ImportModuleAttr(PyObject *modname, PyObject *attrname) - { - PyObject *mod = PyImport_Import(modname); - if (mod == NULL) { -@@ -4186,7 +4191,7 @@ - } - - PyObject * --_PyImport_GetModuleAttrString(const char *modname, const char *attrname) -+PyImport_ImportModuleAttrString(const char *modname, const char *attrname) - { - PyObject *pmodname = PyUnicode_FromString(modname); - if (pmodname == NULL) { -@@ -4197,7 +4202,7 @@ - Py_DECREF(pmodname); - return NULL; - } -- PyObject *result = _PyImport_GetModuleAttr(pmodname, pattrname); -+ PyObject *result = PyImport_ImportModuleAttr(pmodname, pattrname); - Py_DECREF(pattrname); - Py_DECREF(pmodname); - return result; -@@ -4688,7 +4693,7 @@ - * code relies on fp still being open. */ - FILE *fp; - if (file != NULL) { -- fp = _Py_fopen_obj(info.filename, "r"); -+ fp = Py_fopen(info.filename, "r"); - if (fp == NULL) { - goto finally; - } -diff --git a/Python/initconfig.c b/Python/initconfig.c -index 7851b86db1f..4db77ef47d2 100644 ---- a/Python/initconfig.c -+++ b/Python/initconfig.c -@@ -169,7 +169,7 @@ - SPEC(use_frozen_modules, BOOL, READ_ONLY, NO_SYS), - SPEC(use_hash_seed, BOOL, READ_ONLY, NO_SYS), - #ifdef __APPLE__ -- SPEC(use_system_logger, BOOL, PUBLIC, NO_SYS), -+ SPEC(use_system_logger, BOOL, READ_ONLY, NO_SYS), - #endif - SPEC(user_site_directory, BOOL, READ_ONLY, NO_SYS), // sys.flags.no_user_site - SPEC(warn_default_encoding, BOOL, READ_ONLY, NO_SYS), -diff --git a/Python/instrumentation.c b/Python/instrumentation.c -index 3503809e330..0e7b4810726 100644 ---- a/Python/instrumentation.c -+++ b/Python/instrumentation.c -@@ -14,6 +14,7 @@ - #include "pycore_namespace.h" - #include "pycore_object.h" - #include "pycore_opcode_metadata.h" // IS_VALID_OPCODE, _PyOpcode_Caches -+#include "pycore_opcode_utils.h" // IS_CONDITIONAL_JUMP_OPCODE - #include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_STORE_UINTPTR_RELEASE - #include "pycore_pyerrors.h" - #include "pycore_pystate.h" // _PyInterpreterState_GET() -@@ -52,7 +53,7 @@ - if (bc == NULL) { \ - continue; \ - } \ -- (func)((_Py_CODEUNIT *)bc, __VA_ARGS__); \ -+ (func)(code, (_Py_CODEUNIT *)bc, __VA_ARGS__); \ - } \ - } while (0) - -@@ -61,7 +62,7 @@ - #define LOCK_CODE(code) - #define UNLOCK_CODE() - #define MODIFY_BYTECODE(code, func, ...) \ -- (func)(_PyCode_CODE(code), __VA_ARGS__) -+ (func)(code, _PyCode_CODE(code), __VA_ARGS__) - - #endif - -@@ -85,22 +86,26 @@ - [INSTRUMENTED_YIELD_VALUE] = PY_MONITORING_EVENT_PY_YIELD, - [JUMP_FORWARD] = PY_MONITORING_EVENT_JUMP, - [JUMP_BACKWARD] = PY_MONITORING_EVENT_JUMP, -- [POP_JUMP_IF_FALSE] = PY_MONITORING_EVENT_BRANCH, -- [POP_JUMP_IF_TRUE] = PY_MONITORING_EVENT_BRANCH, -- [POP_JUMP_IF_NONE] = PY_MONITORING_EVENT_BRANCH, -- [POP_JUMP_IF_NOT_NONE] = PY_MONITORING_EVENT_BRANCH, -+ [POP_JUMP_IF_FALSE] = PY_MONITORING_EVENT_BRANCH_RIGHT, -+ [POP_JUMP_IF_TRUE] = PY_MONITORING_EVENT_BRANCH_RIGHT, -+ [POP_JUMP_IF_NONE] = PY_MONITORING_EVENT_BRANCH_RIGHT, -+ [POP_JUMP_IF_NOT_NONE] = PY_MONITORING_EVENT_BRANCH_RIGHT, - [INSTRUMENTED_JUMP_FORWARD] = PY_MONITORING_EVENT_JUMP, - [INSTRUMENTED_JUMP_BACKWARD] = PY_MONITORING_EVENT_JUMP, -- [INSTRUMENTED_POP_JUMP_IF_FALSE] = PY_MONITORING_EVENT_BRANCH, -- [INSTRUMENTED_POP_JUMP_IF_TRUE] = PY_MONITORING_EVENT_BRANCH, -- [INSTRUMENTED_POP_JUMP_IF_NONE] = PY_MONITORING_EVENT_BRANCH, -- [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = PY_MONITORING_EVENT_BRANCH, -- [FOR_ITER] = PY_MONITORING_EVENT_BRANCH, -- [INSTRUMENTED_FOR_ITER] = PY_MONITORING_EVENT_BRANCH, -+ [INSTRUMENTED_POP_JUMP_IF_FALSE] = PY_MONITORING_EVENT_BRANCH_RIGHT, -+ [INSTRUMENTED_POP_JUMP_IF_TRUE] = PY_MONITORING_EVENT_BRANCH_RIGHT, -+ [INSTRUMENTED_POP_JUMP_IF_NONE] = PY_MONITORING_EVENT_BRANCH_RIGHT, -+ [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = PY_MONITORING_EVENT_BRANCH_RIGHT, -+ [FOR_ITER] = PY_MONITORING_EVENT_BRANCH_LEFT, -+ [INSTRUMENTED_FOR_ITER] = PY_MONITORING_EVENT_BRANCH_LEFT, -+ [POP_ITER] = PY_MONITORING_EVENT_BRANCH_RIGHT, -+ [INSTRUMENTED_POP_ITER] = PY_MONITORING_EVENT_BRANCH_RIGHT, - [END_FOR] = PY_MONITORING_EVENT_STOP_ITERATION, - [INSTRUMENTED_END_FOR] = PY_MONITORING_EVENT_STOP_ITERATION, - [END_SEND] = PY_MONITORING_EVENT_STOP_ITERATION, - [INSTRUMENTED_END_SEND] = PY_MONITORING_EVENT_STOP_ITERATION, -+ [NOT_TAKEN] = PY_MONITORING_EVENT_BRANCH_LEFT, -+ [INSTRUMENTED_NOT_TAKEN] = PY_MONITORING_EVENT_BRANCH_LEFT, - }; - - static const uint8_t DE_INSTRUMENT[256] = { -@@ -117,9 +122,11 @@ - [INSTRUMENTED_POP_JUMP_IF_NONE] = POP_JUMP_IF_NONE, - [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = POP_JUMP_IF_NOT_NONE, - [INSTRUMENTED_FOR_ITER] = FOR_ITER, -+ [INSTRUMENTED_POP_ITER] = POP_ITER, - [INSTRUMENTED_END_FOR] = END_FOR, - [INSTRUMENTED_END_SEND] = END_SEND, - [INSTRUMENTED_LOAD_SUPER_ATTR] = LOAD_SUPER_ATTR, -+ [INSTRUMENTED_NOT_TAKEN] = NOT_TAKEN, - }; - - static const uint8_t INSTRUMENTED_OPCODES[256] = { -@@ -153,8 +160,12 @@ - [INSTRUMENTED_END_SEND] = INSTRUMENTED_END_SEND, - [FOR_ITER] = INSTRUMENTED_FOR_ITER, - [INSTRUMENTED_FOR_ITER] = INSTRUMENTED_FOR_ITER, -+ [POP_ITER] = INSTRUMENTED_POP_ITER, -+ [INSTRUMENTED_POP_ITER] = INSTRUMENTED_POP_ITER, - [LOAD_SUPER_ATTR] = INSTRUMENTED_LOAD_SUPER_ATTR, - [INSTRUMENTED_LOAD_SUPER_ATTR] = INSTRUMENTED_LOAD_SUPER_ATTR, -+ [NOT_TAKEN] = INSTRUMENTED_NOT_TAKEN, -+ [INSTRUMENTED_NOT_TAKEN] = INSTRUMENTED_NOT_TAKEN, - - [INSTRUMENTED_LINE] = INSTRUMENTED_LINE, - [INSTRUMENTED_INSTRUCTION] = INSTRUMENTED_INSTRUCTION, -@@ -274,48 +285,36 @@ - return result; - } - --/* Line delta. -- * 8 bit value. -- * if line_delta == -128: -- * line = None # represented as -1 -- * elif line_delta == -127 or line_delta == -126: -- * line = PyCode_Addr2Line(code, offset * sizeof(_Py_CODEUNIT)); -+/* Module code can have line 0, even though modules start at line 1, -+ * so -1 is a legal delta. */ -+#define NO_LINE (-2) -+ -+/* Returns the line delta. Defined as: -+ * if line is None: -+ * line_delta = NO_LINE - * else: -- * line = first_line + (offset >> OFFSET_SHIFT) + line_delta; -+ * line_delta = line - first_line - */ -- --#define NO_LINE -128 --#define COMPUTED_LINE_LINENO_CHANGE -127 --#define COMPUTED_LINE -126 -- --#define OFFSET_SHIFT 4 -- --static int8_t --compute_line_delta(PyCodeObject *code, int offset, int line) -+static int -+compute_line_delta(PyCodeObject *code, int line) - { - if (line < 0) { -+ assert(line == -1); - return NO_LINE; - } -- int delta = line - code->co_firstlineno - (offset >> OFFSET_SHIFT); -- if (delta <= INT8_MAX && delta > COMPUTED_LINE) { -- return delta; -- } -- return COMPUTED_LINE; -+ int delta = line - code->co_firstlineno; -+ assert(delta > NO_LINE); -+ return delta; - } - - static int --compute_line(PyCodeObject *code, int offset, int8_t line_delta) -+compute_line(PyCodeObject *code, int line_delta) - { -- if (line_delta > COMPUTED_LINE) { -- return code->co_firstlineno + (offset >> OFFSET_SHIFT) + line_delta; -- } - if (line_delta == NO_LINE) { -- - return -1; - } -- assert(line_delta == COMPUTED_LINE || line_delta == COMPUTED_LINE_LINENO_CHANGE); -- /* Look it up */ -- return PyCode_Addr2Line(code, offset * sizeof(_Py_CODEUNIT)); -+ assert(line_delta > NO_LINE); -+ return code->co_firstlineno + line_delta; - } - - int -@@ -323,33 +322,59 @@ - { - ASSERT_WORLD_STOPPED_OR_LOCKED(code); - -- int opcode = -- FT_ATOMIC_LOAD_UINT8_RELAXED(_PyCode_CODE(code)[offset].op.code); -- assert(opcode != 0); -- assert(opcode != RESERVED); -- if (opcode == INSTRUMENTED_LINE) { -- opcode = code->_co_monitoring->lines[offset].original_opcode; -- } -- if (opcode == INSTRUMENTED_INSTRUCTION) { -- opcode = code->_co_monitoring->per_instruction_opcodes[offset]; -- } -- int deinstrumented = DE_INSTRUMENT[opcode]; -- if (deinstrumented) { -- opcode = deinstrumented; -- } -- else { -- opcode = _PyOpcode_Deopt[opcode]; -+ _Py_CODEUNIT inst = _Py_GetBaseCodeUnit(code, offset); -+ return 1 + _PyOpcode_Caches[inst.op.code]; -+} -+ -+static inline uint8_t -+get_original_opcode(_PyCoLineInstrumentationData *line_data, int index) -+{ -+ return line_data->data[index*line_data->bytes_per_entry]; -+} -+ -+static inline uint8_t * -+get_original_opcode_ptr(_PyCoLineInstrumentationData *line_data, int index) -+{ -+ return &line_data->data[index*line_data->bytes_per_entry]; -+} -+ -+static inline void -+set_original_opcode(_PyCoLineInstrumentationData *line_data, int index, uint8_t opcode) -+{ -+ line_data->data[index*line_data->bytes_per_entry] = opcode; -+} -+ -+static inline int -+get_line_delta(_PyCoLineInstrumentationData *line_data, int index) -+{ -+ uint8_t *ptr = &line_data->data[index*line_data->bytes_per_entry+1]; -+ assert(line_data->bytes_per_entry >= 2); -+ uint32_t value = *ptr; -+ for (int idx = 2; idx < line_data->bytes_per_entry; idx++) { -+ ptr++; -+ int shift = (idx-1)*8; -+ value |= ((uint32_t)(*ptr)) << shift; - } -- assert(opcode != 0); -- if (opcode == ENTER_EXECUTOR) { -- int exec_index = _PyCode_CODE(code)[offset].op.arg; -- _PyExecutorObject *exec = code->co_executors->executors[exec_index]; -- opcode = _PyOpcode_Deopt[exec->vm_data.opcode]; -+ assert(value < INT_MAX); -+ /* NO_LINE is stored as zero. */ -+ return ((int)value) + NO_LINE; -+} -+ -+static inline void -+set_line_delta(_PyCoLineInstrumentationData *line_data, int index, int line_delta) -+{ -+ /* Store line_delta + 2 as we need -2 to represent no line number */ -+ assert(line_delta >= NO_LINE); -+ uint32_t adjusted = line_delta - NO_LINE; -+ uint8_t *ptr = &line_data->data[index*line_data->bytes_per_entry+1]; -+ assert(adjusted < (1ULL << ((line_data->bytes_per_entry-1)*8))); -+ assert(line_data->bytes_per_entry >= 2); -+ *ptr = adjusted & 0xff; -+ for (int idx = 2; idx < line_data->bytes_per_entry; idx++) { -+ ptr++; -+ adjusted >>= 8; -+ *ptr = adjusted & 0xff; - } -- assert(!is_instrumented(opcode)); -- assert(opcode != ENTER_EXECUTOR); -- assert(opcode == _PyOpcode_Deopt[opcode]); -- return 1 + _PyOpcode_Caches[opcode]; - } - - #ifdef INSTRUMENT_DEBUG -@@ -371,11 +396,15 @@ - if (lines == NULL) { - fprintf(out, ", lines = NULL"); - } -- else if (lines[i].original_opcode == 0) { -- fprintf(out, ", lines = {original_opcode = No LINE (0), line_delta = %d)", lines[i].line_delta); -- } - else { -- fprintf(out, ", lines = {original_opcode = %s, line_delta = %d)", _PyOpcode_OpName[lines[i].original_opcode], lines[i].line_delta); -+ int opcode = get_original_opcode(lines, i); -+ int line_delta = get_line_delta(lines, i); -+ if (opcode == 0) { -+ fprintf(out, ", lines = {original_opcode = No LINE (0), line_delta = %d)", line_delta); -+ } -+ else { -+ fprintf(out, ", lines = {original_opcode = %s, line_delta = %d)", _PyOpcode_OpName[opcode], line_delta); -+ } - } - } - -@@ -425,6 +454,12 @@ - } - } - -+/** NOTE: -+ * Do not use PyCode_Addr2Line to determine the line number in instrumentation, -+ * as `PyCode_Addr2Line` uses the monitoring data if it is available. -+ */ -+ -+ - /* No error checking -- Don't use this for anything but experimental debugging */ - static void - dump_instrumentation_data(PyCodeObject *code, int star, FILE*out) -@@ -442,6 +477,8 @@ - dump_local_monitors("Active", data->active_monitors, out); - int code_len = (int)Py_SIZE(code); - bool starred = false; -+ PyCodeAddressRange range; -+ _PyCode_InitAddressRange(code, &range); - for (int i = 0; i < code_len; i += _PyInstruction_GetLength(code, i)) { - _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; - int opcode = instr->op.code; -@@ -449,7 +486,7 @@ - fprintf(out, "** "); - starred = true; - } -- fprintf(out, "Offset: %d, line: %d %s: ", i, PyCode_Addr2Line(code, i*2), _PyOpcode_OpName[opcode]); -+ fprintf(out, "Offset: %d, line: %d %s: ", i, _PyCode_CheckLineNumber(i*2, &range), _PyOpcode_OpName[opcode]); - dump_instrumentation_data_tools(code, data->tools, i, out); - dump_instrumentation_data_lines(code, data->lines, i, out); - dump_instrumentation_data_line_tools(code, data->line_tools, i, out); -@@ -514,10 +551,12 @@ - code->_co_monitoring->active_monitors, - active_monitors)); - int code_len = (int)Py_SIZE(code); -+ PyCodeAddressRange range; -+ _PyCode_InitAddressRange(co, &range); - for (int i = 0; i < code_len;) { - _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; - int opcode = instr->op.code; -- int base_opcode = _Py_GetBaseCodeUnit(code, offset).op.code; -+ int base_opcode = _Py_GetBaseCodeUnit(code, i).op.code; - CHECK(valid_opcode(opcode)); - CHECK(valid_opcode(base_opcode)); - if (opcode == INSTRUMENTED_INSTRUCTION) { -@@ -528,8 +567,8 @@ - } - if (opcode == INSTRUMENTED_LINE) { - CHECK(data->lines); -- CHECK(valid_opcode(data->lines[i].original_opcode)); -- opcode = data->lines[i].original_opcode; -+ opcode = get_original_opcode(data->lines, i); -+ CHECK(valid_opcode(opcode)); - CHECK(opcode != END_FOR); - CHECK(opcode != RESUME); - CHECK(opcode != RESUME_CHECK); -@@ -544,7 +583,7 @@ - * *and* we are executing a INSTRUMENTED_LINE instruction - * that has de-instrumented itself, then we will execute - * an invalid INSTRUMENTED_INSTRUCTION */ -- CHECK(data->lines[i].original_opcode != INSTRUMENTED_INSTRUCTION); -+ CHECK(get_original_opcode(data->lines, i) != INSTRUMENTED_INSTRUCTION); - } - if (opcode == INSTRUMENTED_INSTRUCTION) { - CHECK(data->per_instruction_opcodes[i] != 0); -@@ -559,9 +598,9 @@ - } - CHECK(active_monitors.tools[event] != 0); - } -- if (data->lines && base_opcode != END_FOR) { -- int line1 = compute_line(code, i, data->lines[i].line_delta); -- int line2 = PyCode_Addr2Line(code, i*sizeof(_Py_CODEUNIT)); -+ if (data->lines && get_original_opcode(data->lines, i)) { -+ int line1 = compute_line(code, get_line_delta(data->lines, i)); -+ int line2 = _PyCode_CheckLineNumber(i*sizeof(_Py_CODEUNIT), &range); - CHECK(line1 == line2); - } - CHECK(valid_opcode(opcode)); -@@ -599,20 +638,19 @@ - int opcode = inst.op.code; - if (opcode < MIN_INSTRUMENTED_OPCODE) { - inst.op.code = _PyOpcode_Deopt[opcode]; -- assert(inst.op.code <= RESUME); -+ assert(inst.op.code < MIN_SPECIALIZED_OPCODE); - return inst; - } - if (opcode == ENTER_EXECUTOR) { - _PyExecutorObject *exec = code->co_executors->executors[inst.op.arg]; - opcode = _PyOpcode_Deopt[exec->vm_data.opcode]; - inst.op.code = opcode; -- assert(opcode <= RESUME); - inst.op.arg = exec->vm_data.oparg; -- assert(inst.op.code <= RESUME); -+ assert(inst.op.code < MIN_SPECIALIZED_OPCODE); - return inst; - } - if (opcode == INSTRUMENTED_LINE) { -- opcode = code->_co_monitoring->lines[i].original_opcode; -+ opcode = get_original_opcode(code->_co_monitoring->lines, i); - } - if (opcode == INSTRUMENTED_INSTRUCTION) { - opcode = code->_co_monitoring->per_instruction_opcodes[i]; -@@ -631,7 +669,7 @@ - } - - static void --de_instrument(_Py_CODEUNIT *bytecode, _PyCoMonitoringData *monitoring, int i, -+de_instrument(PyCodeObject *code, _Py_CODEUNIT *bytecode, _PyCoMonitoringData *monitoring, int i, - int event) - { - assert(event != PY_MONITORING_EVENT_INSTRUCTION); -@@ -642,7 +680,7 @@ - int opcode = *opcode_ptr; - assert(opcode != ENTER_EXECUTOR); - if (opcode == INSTRUMENTED_LINE) { -- opcode_ptr = &monitoring->lines[i].original_opcode; -+ opcode_ptr = get_original_opcode_ptr(monitoring->lines, i); - opcode = *opcode_ptr; - } - if (opcode == INSTRUMENTED_INSTRUCTION) { -@@ -662,7 +700,7 @@ - } - - static void --de_instrument_line(_Py_CODEUNIT *bytecode, _PyCoMonitoringData *monitoring, -+de_instrument_line(PyCodeObject *code, _Py_CODEUNIT *bytecode, _PyCoMonitoringData *monitoring, - int i) - { - _Py_CODEUNIT *instr = &bytecode[i]; -@@ -670,10 +708,10 @@ - if (opcode != INSTRUMENTED_LINE) { - return; - } -- _PyCoLineInstrumentationData *lines = &monitoring->lines[i]; -- int original_opcode = lines->original_opcode; -+ _PyCoLineInstrumentationData *lines = monitoring->lines; -+ int original_opcode = get_original_opcode(lines, i); - if (original_opcode == INSTRUMENTED_INSTRUCTION) { -- lines->original_opcode = monitoring->per_instruction_opcodes[i]; -+ set_original_opcode(lines, i, monitoring->per_instruction_opcodes[i]); - } - CHECK(original_opcode != 0); - CHECK(original_opcode == _PyOpcode_Deopt[original_opcode]); -@@ -686,14 +724,14 @@ - } - - static void --de_instrument_per_instruction(_Py_CODEUNIT *bytecode, -+de_instrument_per_instruction(PyCodeObject *code, _Py_CODEUNIT *bytecode, - _PyCoMonitoringData *monitoring, int i) - { - _Py_CODEUNIT *instr = &bytecode[i]; - uint8_t *opcode_ptr = &instr->op.code; - int opcode = *opcode_ptr; - if (opcode == INSTRUMENTED_LINE) { -- opcode_ptr = &monitoring->lines[i].original_opcode; -+ opcode_ptr = get_original_opcode_ptr(monitoring->lines, i); - opcode = *opcode_ptr; - } - if (opcode != INSTRUMENTED_INSTRUCTION) { -@@ -712,14 +750,13 @@ - } - - static void --instrument(_Py_CODEUNIT *bytecode, _PyCoMonitoringData *monitoring, int i) -+instrument(PyCodeObject *code, _Py_CODEUNIT *bytecode, _PyCoMonitoringData *monitoring, int i) - { - _Py_CODEUNIT *instr = &bytecode[i]; - uint8_t *opcode_ptr = &instr->op.code; - int opcode =*opcode_ptr; - if (opcode == INSTRUMENTED_LINE) { -- _PyCoLineInstrumentationData *lines = &monitoring->lines[i]; -- opcode_ptr = &lines->original_opcode; -+ opcode_ptr = get_original_opcode_ptr(monitoring->lines, i); - opcode = *opcode_ptr; - } - if (opcode == INSTRUMENTED_INSTRUCTION) { -@@ -742,29 +779,27 @@ - } - - static void --instrument_line(_Py_CODEUNIT *bytecode, _PyCoMonitoringData *monitoring, int i) -+instrument_line(PyCodeObject *code, _Py_CODEUNIT *bytecode, _PyCoMonitoringData *monitoring, int i) - { - uint8_t *opcode_ptr = &bytecode[i].op.code; - int opcode = *opcode_ptr; - if (opcode == INSTRUMENTED_LINE) { - return; - } -- _PyCoLineInstrumentationData *lines = &monitoring->lines[i]; -- lines->original_opcode = _PyOpcode_Deopt[opcode]; -- CHECK(lines->original_opcode > 0); -+ set_original_opcode(monitoring->lines, i, _PyOpcode_Deopt[opcode]); -+ CHECK(get_line_delta(monitoring->lines, i) > NO_LINE); - FT_ATOMIC_STORE_UINT8_RELAXED(*opcode_ptr, INSTRUMENTED_LINE); - } - - static void --instrument_per_instruction(_Py_CODEUNIT *bytecode, -+instrument_per_instruction(PyCodeObject *code, _Py_CODEUNIT *bytecode, - _PyCoMonitoringData *monitoring, int i) - { - _Py_CODEUNIT *instr = &bytecode[i]; - uint8_t *opcode_ptr = &instr->op.code; - int opcode = *opcode_ptr; - if (opcode == INSTRUMENTED_LINE) { -- _PyCoLineInstrumentationData *lines = &monitoring->lines[i]; -- opcode_ptr = &lines->original_opcode; -+ opcode_ptr = get_original_opcode_ptr(monitoring->lines, i); - opcode = *opcode_ptr; - } - if (opcode == INSTRUMENTED_INSTRUCTION) { -@@ -1084,6 +1119,8 @@ - [PY_MONITORING_EVENT_INSTRUCTION] = "INSTRUCTION", - [PY_MONITORING_EVENT_JUMP] = "JUMP", - [PY_MONITORING_EVENT_BRANCH] = "BRANCH", -+ [PY_MONITORING_EVENT_BRANCH_LEFT] = "BRANCH_LEFT", -+ [PY_MONITORING_EVENT_BRANCH_RIGHT] = "BRANCH_RIGHT", - [PY_MONITORING_EVENT_C_RETURN] = "C_RETURN", - [PY_MONITORING_EVENT_PY_THROW] = "PY_THROW", - [PY_MONITORING_EVENT_RAISE] = "RAISE", -@@ -1096,8 +1133,8 @@ - - static int - call_instrumentation_vector( -- PyThreadState *tstate, int event, -- _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, Py_ssize_t nargs, PyObject *args[]) -+ _Py_CODEUNIT *instr, PyThreadState *tstate, int event, -+ _PyInterpreterFrame *frame, _Py_CODEUNIT *arg2, Py_ssize_t nargs, PyObject *args[]) - { - if (tstate->tracing) { - return 0; -@@ -1110,13 +1147,13 @@ - int offset = (int)(instr - _PyFrame_GetBytecode(frame)); - /* Offset visible to user should be the offset in bytes, as that is the - * convention for APIs involving code offsets. */ -- int bytes_offset = offset * (int)sizeof(_Py_CODEUNIT); -- PyObject *offset_obj = PyLong_FromLong(bytes_offset); -- if (offset_obj == NULL) { -+ int bytes_arg2 = (int)(arg2 - _PyFrame_GetBytecode(frame)) * (int)sizeof(_Py_CODEUNIT); -+ PyObject *arg2_obj = PyLong_FromLong(bytes_arg2); -+ if (arg2_obj == NULL) { - return -1; - } - assert(args[2] == NULL); -- args[2] = offset_obj; -+ args[2] = arg2_obj; - PyInterpreterState *interp = tstate->interp; - uint8_t tools = get_tools_for_instruction(code, interp, offset, event); - size_t nargsf = (size_t) nargs | PY_VECTORCALL_ARGUMENTS_OFFSET; -@@ -1154,7 +1191,7 @@ - } - } - } -- Py_DECREF(offset_obj); -+ Py_DECREF(arg2_obj); - return err; - } - -@@ -1164,7 +1201,7 @@ - _PyInterpreterFrame *frame, _Py_CODEUNIT *instr) - { - PyObject *args[3] = { NULL, NULL, NULL }; -- return call_instrumentation_vector(tstate, event, frame, instr, 2, args); -+ return call_instrumentation_vector(instr, tstate, event, frame, instr, 2, args); - } - - int -@@ -1173,7 +1210,7 @@ - _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg) - { - PyObject *args[4] = { NULL, NULL, NULL, arg }; -- return call_instrumentation_vector(tstate, event, frame, instr, 3, args); -+ return call_instrumentation_vector(instr, tstate, event, frame, instr, 3, args); - } - - int -@@ -1182,33 +1219,34 @@ - _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1) - { - PyObject *args[5] = { NULL, NULL, NULL, arg0, arg1 }; -- return call_instrumentation_vector(tstate, event, frame, instr, 4, args); -+ return call_instrumentation_vector(instr, tstate, event, frame, instr, 4, args); - } - - _Py_CODEUNIT * - _Py_call_instrumentation_jump( -- PyThreadState *tstate, int event, -- _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *target) -+ _Py_CODEUNIT *instr, PyThreadState *tstate, int event, -+ _PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNIT *dest) - { - assert(event == PY_MONITORING_EVENT_JUMP || -- event == PY_MONITORING_EVENT_BRANCH); -- assert(frame->instr_ptr == instr); -- int to = (int)(target - _PyFrame_GetBytecode(frame)); -+ event == PY_MONITORING_EVENT_BRANCH_RIGHT || -+ event == PY_MONITORING_EVENT_BRANCH_LEFT); -+ int to = (int)(dest - _PyFrame_GetBytecode(frame)); - PyObject *to_obj = PyLong_FromLong(to * (int)sizeof(_Py_CODEUNIT)); - if (to_obj == NULL) { - return NULL; - } - PyObject *args[4] = { NULL, NULL, NULL, to_obj }; -- int err = call_instrumentation_vector(tstate, event, frame, instr, 3, args); -+ _Py_CODEUNIT *instr_ptr = frame->instr_ptr; -+ int err = call_instrumentation_vector(instr, tstate, event, frame, src, 3, args); - Py_DECREF(to_obj); - if (err) { - return NULL; - } -- if (frame->instr_ptr != instr) { -+ if (frame->instr_ptr != instr_ptr) { - /* The callback has caused a jump (by setting the line number) */ - return frame->instr_ptr; - } -- return target; -+ return dest; - } - - static void -@@ -1218,7 +1256,7 @@ - { - assert(_PyErr_Occurred(tstate)); - PyObject *exc = _PyErr_GetRaisedException(tstate); -- int err = call_instrumentation_vector(tstate, event, frame, instr, nargs, args); -+ int err = call_instrumentation_vector(instr, tstate, event, frame, instr, nargs, args); - if (err) { - Py_XDECREF(exc); - } -@@ -1238,18 +1276,16 @@ - call_instrumentation_vector_protected(tstate, event, frame, instr, 4, args); - } - -- - int - _Py_Instrumentation_GetLine(PyCodeObject *code, int index) - { - _PyCoMonitoringData *monitoring = code->_co_monitoring; - assert(monitoring != NULL); - assert(monitoring->lines != NULL); -- assert(index >= code->_co_firsttraceable); - assert(index < Py_SIZE(code)); -- _PyCoLineInstrumentationData *line_data = &monitoring->lines[index]; -- int8_t line_delta = line_data->line_delta; -- int line = compute_line(code, index, line_delta); -+ _PyCoLineInstrumentationData *line_data = monitoring->lines; -+ int line_delta = get_line_delta(line_data, index); -+ int line = compute_line(code, line_delta); - return line; - } - -@@ -1263,29 +1299,20 @@ - int i = (int)(instr - bytecode); - - _PyCoMonitoringData *monitoring = code->_co_monitoring; -- _PyCoLineInstrumentationData *line_data = &monitoring->lines[i]; -+ _PyCoLineInstrumentationData *line_data = monitoring->lines; - PyInterpreterState *interp = tstate->interp; -- int8_t line_delta = line_data->line_delta; -- int line = 0; -- -- if (line_delta == COMPUTED_LINE_LINENO_CHANGE) { -- // We know the line number must have changed, don't need to calculate -- // the line number for now because we might not need it. -- line = -1; -- } else { -- line = compute_line(code, i, line_delta); -- assert(line >= 0); -- assert(prev != NULL); -- int prev_index = (int)(prev - bytecode); -- int prev_line = _Py_Instrumentation_GetLine(code, prev_index); -- if (prev_line == line) { -- int prev_opcode = bytecode[prev_index].op.code; -- /* RESUME and INSTRUMENTED_RESUME are needed for the operation of -- * instrumentation, so must never be hidden by an INSTRUMENTED_LINE. -- */ -- if (prev_opcode != RESUME && prev_opcode != INSTRUMENTED_RESUME) { -- goto done; -- } -+ int line = _Py_Instrumentation_GetLine(code, i); -+ assert(line >= 0); -+ assert(prev != NULL); -+ int prev_index = (int)(prev - bytecode); -+ int prev_line = _Py_Instrumentation_GetLine(code, prev_index); -+ if (prev_line == line) { -+ int prev_opcode = bytecode[prev_index].op.code; -+ /* RESUME and INSTRUMENTED_RESUME are needed for the operation of -+ * instrumentation, so must never be hidden by an INSTRUMENTED_LINE. -+ */ -+ if (prev_opcode != RESUME && prev_opcode != INSTRUMENTED_RESUME) { -+ goto done; - } - } - -@@ -1310,12 +1337,6 @@ - tstate->tracing++; - /* Call c_tracefunc directly, having set the line number. */ - Py_INCREF(frame_obj); -- if (line == -1 && line_delta > COMPUTED_LINE) { -- /* Only assign f_lineno if it's easy to calculate, otherwise -- * do lazy calculation by setting the f_lineno to 0. -- */ -- line = compute_line(code, i, line_delta); -- } - frame_obj->f_lineno = line; - int err = tstate->c_tracefunc(tstate->c_traceobj, frame_obj, PyTrace_LINE, Py_None); - frame_obj->f_lineno = 0; -@@ -1332,11 +1353,6 @@ - if (tools == 0) { - goto done; - } -- -- if (line == -1) { -- /* Need to calculate the line number now for monitoring events */ -- line = compute_line(code, i, line_delta); -- } - PyObject *line_obj = PyLong_FromLong(line); - if (line_obj == NULL) { - return -1; -@@ -1368,7 +1384,7 @@ - Py_DECREF(line_obj); - uint8_t original_opcode; - done: -- original_opcode = line_data->original_opcode; -+ original_opcode = get_original_opcode(line_data, i); - assert(original_opcode != 0); - assert(original_opcode != INSTRUMENTED_LINE); - assert(_PyOpcode_Deopt[original_opcode] == original_opcode); -@@ -1427,19 +1443,6 @@ - return next_opcode; - } - -- --PyObject * --_PyMonitoring_RegisterCallback(int tool_id, int event_id, PyObject *obj) --{ -- PyInterpreterState *is = _PyInterpreterState_GET(); -- assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); -- assert(0 <= event_id && event_id < _PY_MONITORING_EVENTS); -- PyObject *callback = _Py_atomic_exchange_ptr(&is->monitoring_callables[tool_id][event_id], -- Py_XNewRef(obj)); -- -- return callback; --} -- - static void - initialize_tools(PyCodeObject *code) - { -@@ -1453,7 +1456,7 @@ - int opcode = instr->op.code; - assert(opcode != ENTER_EXECUTOR); - if (opcode == INSTRUMENTED_LINE) { -- opcode = code->_co_monitoring->lines[i].original_opcode; -+ opcode = get_original_opcode(code->_co_monitoring->lines, i); - } - if (opcode == INSTRUMENTED_INSTRUCTION) { - opcode = code->_co_monitoring->per_instruction_opcodes[i]; -@@ -1496,63 +1499,58 @@ - } - } - --#define NO_LINE -128 -- - static void --initialize_lines(PyCodeObject *code) -+initialize_lines(PyCodeObject *code, int bytes_per_entry) - { - ASSERT_WORLD_STOPPED_OR_LOCKED(code); - _PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines; - - assert(line_data != NULL); -+ line_data->bytes_per_entry = bytes_per_entry; - int code_len = (int)Py_SIZE(code); - PyCodeAddressRange range; - _PyCode_InitAddressRange(code, &range); -- for (int i = 0; i < code->_co_firsttraceable && i < code_len; i++) { -- line_data[i].original_opcode = 0; -- line_data[i].line_delta = -127; -- } - int current_line = -1; -- for (int i = code->_co_firsttraceable; i < code_len; ) { -+ for (int i = 0; i < code_len; ) { - int opcode = _Py_GetBaseCodeUnit(code, i).op.code; - int line = _PyCode_CheckLineNumber(i*(int)sizeof(_Py_CODEUNIT), &range); -- line_data[i].line_delta = compute_line_delta(code, i, line); -+ set_line_delta(line_data, i, compute_line_delta(code, line)); - int length = _PyInstruction_GetLength(code, i); -- switch (opcode) { -- case END_ASYNC_FOR: -- case END_FOR: -- case END_SEND: -- case RESUME: -- /* END_FOR cannot start a line, as it is skipped by FOR_ITER -- * END_SEND cannot start a line, as it is skipped by SEND -- * RESUME must not be instrumented with INSTRUMENT_LINE */ -- line_data[i].original_opcode = 0; -- break; -- default: -- /* Set original_opcode to the opcode iff the instruction -- * starts a line, and thus should be instrumented. -- * This saves having to perform this check every time the -- * we turn instrumentation on or off, and serves as a sanity -- * check when debugging. -- */ -- if (line != current_line && line >= 0) { -- line_data[i].original_opcode = opcode; -- if (line_data[i].line_delta == COMPUTED_LINE) { -- /* Label this line as a line with a line number change -- * which could help the monitoring callback to quickly -- * identify the line number change. -- */ -- line_data[i].line_delta = COMPUTED_LINE_LINENO_CHANGE; -+ if (i < code->_co_firsttraceable) { -+ set_original_opcode(line_data, i, 0); -+ } -+ else { -+ switch (opcode) { -+ case END_ASYNC_FOR: -+ case END_FOR: -+ case END_SEND: -+ case RESUME: -+ case POP_ITER: -+ /* END_FOR cannot start a line, as it is skipped by FOR_ITER -+ * END_SEND cannot start a line, as it is skipped by SEND -+ * RESUME and POP_ITER must not be instrumented with INSTRUMENTED_LINE */ -+ set_original_opcode(line_data, i, 0); -+ break; -+ default: -+ /* Set original_opcode to the opcode iff the instruction -+ * starts a line, and thus should be instrumented. -+ * This saves having to perform this check every time the -+ * we turn instrumentation on or off, and serves as a sanity -+ * check when debugging. -+ */ -+ if (line != current_line && line >= 0) { -+ set_original_opcode(line_data, i, opcode); -+ CHECK(get_line_delta(line_data, i) != NO_LINE); - } -- } -- else { -- line_data[i].original_opcode = 0; -- } -- current_line = line; -+ else { -+ set_original_opcode(line_data, i, 0); -+ } -+ current_line = line; -+ } - } - for (int j = 1; j < length; j++) { -- line_data[i+j].original_opcode = 0; -- line_data[i+j].line_delta = NO_LINE; -+ set_original_opcode(line_data, i+j, 0); -+ set_line_delta(line_data, i+j, NO_LINE); - } - i += length; - } -@@ -1596,12 +1594,10 @@ - continue; - } - assert(target >= 0); -- if (line_data[target].line_delta != NO_LINE) { -- line_data[target].original_opcode = _Py_GetBaseCodeUnit(code, target).op.code; -- if (line_data[target].line_delta == COMPUTED_LINE_LINENO_CHANGE) { -- // If the line is a jump target, we are not sure if the line -- // number changes, so we set it to COMPUTED_LINE. -- line_data[target].line_delta = COMPUTED_LINE; -+ if (get_line_delta(line_data, target) != NO_LINE) { -+ int opcode = _Py_GetBaseCodeUnit(code, target).op.code; -+ if (opcode != POP_ITER) { -+ set_original_opcode(line_data, target, opcode); - } - } - } -@@ -1624,9 +1620,8 @@ - * END_ASYNC_FOR is a bit special as it marks the end of - * an `async for` loop, which should not generate its own - * line event. */ -- if (line_data[handler].line_delta != NO_LINE && -- original_opcode != END_ASYNC_FOR) { -- line_data[handler].original_opcode = original_opcode; -+ if (get_line_delta(line_data, handler) != NO_LINE && original_opcode != END_ASYNC_FOR) { -+ set_original_opcode(line_data, handler, original_opcode); - } - } - } -@@ -1699,12 +1694,39 @@ - } - if (all_events.tools[PY_MONITORING_EVENT_LINE]) { - if (code->_co_monitoring->lines == NULL) { -- code->_co_monitoring->lines = PyMem_Malloc(code_len * sizeof(_PyCoLineInstrumentationData)); -+ PyCodeAddressRange range; -+ _PyCode_InitAddressRange(code, &range); -+ int max_line = code->co_firstlineno + 1; -+ _PyCode_InitAddressRange(code, &range); -+ for (int i = code->_co_firsttraceable; i < code_len; ) { -+ int line = _PyCode_CheckLineNumber(i*(int)sizeof(_Py_CODEUNIT), &range); -+ if (line > max_line) { -+ max_line = line; -+ } -+ int length = _PyInstruction_GetLength(code, i); -+ i += length; -+ } -+ int bytes_per_entry; -+ int max_delta = max_line - code->co_firstlineno; -+ /* We store delta+2 in the table, so 253 is max for one byte */ -+ if (max_delta < 256+NO_LINE) { -+ bytes_per_entry = 2; -+ } -+ else if (max_delta < (1 << 16)+NO_LINE) { -+ bytes_per_entry = 3; -+ } -+ else if (max_delta < (1 << 24)+NO_LINE) { -+ bytes_per_entry = 4; -+ } -+ else { -+ bytes_per_entry = 5; -+ } -+ code->_co_monitoring->lines = PyMem_Malloc(1 + code_len * bytes_per_entry); - if (code->_co_monitoring->lines == NULL) { - PyErr_NoMemory(); - return -1; - } -- initialize_lines(code); -+ initialize_lines(code, bytes_per_entry); - } - if (multitools && code->_co_monitoring->line_tools == NULL) { - code->_co_monitoring->line_tools = PyMem_Malloc(code_len); -@@ -1819,7 +1841,7 @@ - if (removed_line_tools) { - _PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines; - for (int i = code->_co_firsttraceable; i < code_len;) { -- if (line_data[i].original_opcode) { -+ if (get_original_opcode(line_data, i)) { - remove_line_tools(code, i, removed_line_tools); - } - i += _PyInstruction_GetLength(code, i); -@@ -1846,7 +1868,7 @@ - if (new_line_tools) { - _PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines; - for (int i = code->_co_firsttraceable; i < code_len;) { -- if (line_data[i].original_opcode) { -+ if (get_original_opcode(line_data, i)) { - add_line_tools(code, i, new_line_tools); - } - i += _PyInstruction_GetLength(code, i); -@@ -1919,7 +1941,7 @@ - while (ts) { - _PyInterpreterFrame *frame = ts->current_frame; - while (frame) { -- if (frame->owner != FRAME_OWNED_BY_CSTACK) { -+ if (frame->owner < FRAME_OWNED_BY_INTERPRETER) { - if (instrument_lock_held(_PyFrame_GetCode(frame), interp)) { - return -1; - } -@@ -2312,6 +2334,10 @@ - return NULL; - } - event_set &= ~C_RETURN_EVENTS; -+ if (event_set & (1 << PY_MONITORING_EVENT_BRANCH)) { -+ event_set &= ~(1 << PY_MONITORING_EVENT_BRANCH); -+ event_set |= (1 << PY_MONITORING_EVENT_BRANCH_RIGHT) | (1 << PY_MONITORING_EVENT_BRANCH_LEFT); -+ } - if (_PyMonitoring_SetEvents(tool_id, event_set)) { - return NULL; - } -@@ -2384,6 +2410,10 @@ - return NULL; - } - event_set &= ~C_RETURN_EVENTS; -+ if (event_set & (1 << PY_MONITORING_EVENT_BRANCH)) { -+ event_set &= ~(1 << PY_MONITORING_EVENT_BRANCH); -+ event_set |= (1 << PY_MONITORING_EVENT_BRANCH_RIGHT) | (1 << PY_MONITORING_EVENT_BRANCH_LEFT); -+ } - if (event_set < 0 || event_set >= (1 << _PY_MONITORING_LOCAL_EVENTS)) { - PyErr_Format(PyExc_ValueError, "invalid local event set 0x%x", event_set); - return NULL; -@@ -2711,7 +2741,27 @@ - assert(state->active); - PyObject *args[4] = { NULL, NULL, NULL, target_offset }; - return capi_call_instrumentation(state, codelike, offset, args, 3, -- PY_MONITORING_EVENT_BRANCH); -+ PY_MONITORING_EVENT_BRANCH_RIGHT); -+} -+ -+int -+_PyMonitoring_FireBranchRightEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, -+ PyObject *target_offset) -+{ -+ assert(state->active); -+ PyObject *args[4] = { NULL, NULL, NULL, target_offset }; -+ return capi_call_instrumentation(state, codelike, offset, args, 3, -+ PY_MONITORING_EVENT_BRANCH_RIGHT); -+} -+ -+int -+_PyMonitoring_FireBranchLeftEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, -+ PyObject *target_offset) -+{ -+ assert(state->active); -+ PyObject *args[4] = { NULL, NULL, NULL, target_offset }; -+ return capi_call_instrumentation(state, codelike, offset, args, 3, -+ PY_MONITORING_EVENT_BRANCH_LEFT); - } - - int -@@ -2849,3 +2899,250 @@ - Py_DECREF(exc); - return exception_event_teardown(err, NULL); - } -+ -+ -+ -+/* Handle legacy BRANCH event */ -+ -+typedef struct _PyLegacyBranchEventHandler { -+ PyObject_HEAD -+ vectorcallfunc vectorcall; -+ PyObject *handler; -+ bool right; -+ int tool_id; -+} _PyLegacyBranchEventHandler; -+ -+static void -+dealloc_branch_handler(_PyLegacyBranchEventHandler *self) -+{ -+ Py_CLEAR(self->handler); -+ PyObject_Free((PyObject *)self); -+} -+ -+static PyTypeObject _PyLegacyBranchEventHandler_Type = { -+ PyVarObject_HEAD_INIT(&PyType_Type, 0) -+ "sys.monitoring.branch_event_handler", -+ sizeof(_PyLegacyBranchEventHandler), -+ .tp_dealloc = (destructor)dealloc_branch_handler, -+ .tp_vectorcall_offset = offsetof(_PyLegacyBranchEventHandler, vectorcall), -+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | -+ Py_TPFLAGS_HAVE_VECTORCALL | Py_TPFLAGS_DISALLOW_INSTANTIATION, -+ .tp_call = PyVectorcall_Call, -+}; -+ -+ -+static PyObject * -+branch_handler( -+ _PyLegacyBranchEventHandler *self, PyObject *const *args, -+ size_t nargsf, PyObject *kwnames -+) { -+ // Find the other instrumented instruction and remove tool -+ // The spec (PEP 669) allows spurious events after a DISABLE, -+ // so a best effort is good enough. -+ assert(PyVectorcall_NARGS(nargsf) >= 3); -+ PyCodeObject *code = (PyCodeObject *)args[0]; -+ int src_offset = PyLong_AsLong(args[1]); -+ if (PyErr_Occurred()) { -+ return NULL; -+ } -+ _Py_CODEUNIT instr = _PyCode_CODE(code)[src_offset/2]; -+ if (!is_instrumented(instr.op.code)) { -+ /* Already disabled */ -+ return &_PyInstrumentation_DISABLE; -+ } -+ PyObject *res = PyObject_Vectorcall(self->handler, args, nargsf, kwnames); -+ if (res == &_PyInstrumentation_DISABLE) { -+ /* We need FOR_ITER and POP_JUMP_ to be the same size */ -+ assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1); -+ int offset; -+ int other_event; -+ if (instr.op.code == FOR_ITER) { -+ if (self->right) { -+ offset = src_offset/2; -+ other_event = PY_MONITORING_EVENT_BRANCH_LEFT; -+ } -+ else { -+ // We don't know where the POP_ITER is, so -+ // we cannot de-instrument it. -+ return res; -+ } -+ } -+ else if (IS_CONDITIONAL_JUMP_OPCODE(instr.op.code)) { -+ if (self->right) { -+ offset = src_offset/2 + 2; -+ other_event = PY_MONITORING_EVENT_BRANCH_LEFT; -+ assert(_Py_GetBaseCodeUnit(code, offset).op.code == NOT_TAKEN); -+ } -+ else { -+ offset = src_offset/2; -+ other_event = PY_MONITORING_EVENT_BRANCH_RIGHT; -+ } -+ } -+ else { -+ // Orphaned NOT_TAKEN -- Jump removed by the compiler -+ return res; -+ } -+ LOCK_CODE(code); -+ remove_tools(code, offset, other_event, 1 << self->tool_id); -+ UNLOCK_CODE(); -+ } -+ return res; -+} -+ -+static PyObject *make_branch_handler(int tool_id, PyObject *handler, bool right) -+{ -+ _PyLegacyBranchEventHandler *callback = -+ PyObject_NEW(_PyLegacyBranchEventHandler, &_PyLegacyBranchEventHandler_Type); -+ if (callback == NULL) { -+ return NULL; -+ } -+ callback->vectorcall = (vectorcallfunc)branch_handler; -+ callback->handler = Py_NewRef(handler); -+ callback->right = right; -+ callback->tool_id = tool_id; -+ return (PyObject *)callback; -+} -+ -+/* Consumes a reference to obj */ -+static PyObject *exchange_callables(int tool_id, int event_id, PyObject *obj) -+{ -+ PyInterpreterState *is = _PyInterpreterState_GET(); -+ return _Py_atomic_exchange_ptr(&is->monitoring_callables[tool_id][event_id], obj); -+} -+ -+PyObject * -+_PyMonitoring_RegisterCallback(int tool_id, int event_id, PyObject *obj) -+{ -+ assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); -+ assert(0 <= event_id && event_id < _PY_MONITORING_EVENTS); -+ PyObject *res; -+ if (event_id == PY_MONITORING_EVENT_BRANCH) { -+ PyObject *left, *right; -+ if (obj == NULL) { -+ left = NULL; -+ right = NULL; -+ } -+ else { -+ right = make_branch_handler(tool_id, obj, true); -+ if (right == NULL) { -+ return NULL; -+ } -+ left = make_branch_handler(tool_id, obj, false); -+ if (left == NULL) { -+ Py_DECREF(right); -+ return NULL; -+ } -+ } -+ Py_XDECREF(exchange_callables(tool_id, PY_MONITORING_EVENT_BRANCH_RIGHT, right)); -+ res = exchange_callables(tool_id, PY_MONITORING_EVENT_BRANCH_LEFT, left); -+ } -+ else { -+ res = exchange_callables(tool_id, event_id, Py_XNewRef(obj)); -+ } -+ if (res != NULL && Py_TYPE(res) == &_PyLegacyBranchEventHandler_Type) { -+ _PyLegacyBranchEventHandler *wrapper = (_PyLegacyBranchEventHandler *)res; -+ res = Py_NewRef(wrapper->handler); -+ Py_DECREF(wrapper); -+ } -+ return res; -+} -+ -+/* Branch Iterator */ -+ -+typedef struct { -+ PyObject_HEAD -+ PyCodeObject *bi_code; -+ int bi_offset; -+} branchesiterator; -+ -+static PyObject * -+int_triple(int a, int b, int c) { -+ PyObject *obja = PyLong_FromLong(a); -+ PyObject *objb = NULL; -+ PyObject *objc = NULL; -+ if (obja == NULL) { -+ goto error; -+ } -+ objb = PyLong_FromLong(b); -+ if (objb == NULL) { -+ goto error; -+ } -+ objc = PyLong_FromLong(c); -+ if (objc == NULL) { -+ goto error; -+ } -+ PyObject *array[3] = { obja, objb, objc }; -+ return _PyTuple_FromArraySteal(array, 3); -+error: -+ Py_XDECREF(obja); -+ Py_XDECREF(objb); -+ Py_XDECREF(objc); -+ return NULL; -+} -+ -+static PyObject * -+branchesiter_next(branchesiterator *bi) -+{ -+ int offset = bi->bi_offset; -+ int oparg = 0; -+ while (offset < Py_SIZE(bi->bi_code)) { -+ _Py_CODEUNIT inst = _Py_GetBaseCodeUnit(bi->bi_code, offset); -+ int next_offset = offset + 1 + _PyOpcode_Caches[inst.op.code]; -+ switch(inst.op.code) { -+ case EXTENDED_ARG: -+ oparg = (oparg << 8) | inst.op.arg; -+ break; -+ case FOR_ITER: -+ oparg = (oparg << 8) | inst.op.arg; -+ bi->bi_offset = next_offset; -+ int target = next_offset + oparg+2; // Skips END_FOR and POP_ITER -+ return int_triple(offset*2, next_offset*2, target*2); -+ case POP_JUMP_IF_FALSE: -+ case POP_JUMP_IF_TRUE: -+ case POP_JUMP_IF_NONE: -+ case POP_JUMP_IF_NOT_NONE: -+ oparg = (oparg << 8) | inst.op.arg; -+ /* Skip NOT_TAKEN */ -+ int not_taken = next_offset + 1; -+ bi->bi_offset = not_taken; -+ return int_triple(offset*2, not_taken*2, (next_offset + oparg)*2); -+ default: -+ oparg = 0; -+ } -+ offset = next_offset; -+ } -+ return NULL; -+} -+ -+static void -+branchesiter_dealloc(branchesiterator *bi) -+{ -+ Py_DECREF(bi->bi_code); -+ PyObject_Free(bi); -+} -+ -+static PyTypeObject _PyBranchesIterator = { -+ PyVarObject_HEAD_INIT(&PyType_Type, 0) -+ "line_iterator", /* tp_name */ -+ sizeof(branchesiterator), /* tp_basicsize */ -+ 0, /* tp_itemsize */ -+ /* methods */ -+ .tp_dealloc = (destructor)branchesiter_dealloc, -+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, -+ .tp_iter = PyObject_SelfIter, -+ .tp_iternext = (iternextfunc)branchesiter_next, -+ .tp_free = PyObject_Del, -+}; -+ -+PyObject * -+_PyInstrumentation_BranchesIterator(PyCodeObject *code) -+{ -+ -+ branchesiterator *bi = (branchesiterator *)PyType_GenericAlloc(&_PyBranchesIterator, 0); -+ if (bi == NULL) { -+ return NULL; -+ } -+ bi->bi_code = (PyCodeObject*)Py_NewRef(code); -+ bi->bi_offset = 0; -+ return (PyObject *)bi; -+} -diff --git a/Python/jit.c b/Python/jit.c -index 7dd0da7a450..092b873bc73 100644 ---- a/Python/jit.c -+++ b/Python/jit.c -@@ -87,6 +87,7 @@ - jit_error("unable to free memory"); - return -1; - } -+ OPT_STAT_ADD(jit_freed_memory_size, size); - return 0; - } - -@@ -501,8 +502,8 @@ - // Round up to the nearest page: - size_t page_size = get_page_size(); - assert((page_size & (page_size - 1)) == 0); -- size_t padding = page_size - ((code_size + data_size + state.trampolines.size) & (page_size - 1)); -- size_t total_size = code_size + data_size + state.trampolines.size + padding; -+ size_t padding = page_size - ((code_size + state.trampolines.size + data_size) & (page_size - 1)); -+ size_t total_size = code_size + state.trampolines.size + data_size + padding; - unsigned char *memory = jit_alloc(total_size); - if (memory == NULL) { - return -1; -@@ -510,14 +511,21 @@ - #ifdef MAP_JIT - pthread_jit_write_protect_np(0); - #endif -+ // Collect memory stats -+ OPT_STAT_ADD(jit_total_memory_size, total_size); -+ OPT_STAT_ADD(jit_code_size, code_size); -+ OPT_STAT_ADD(jit_trampoline_size, state.trampolines.size); -+ OPT_STAT_ADD(jit_data_size, data_size); -+ OPT_STAT_ADD(jit_padding_size, padding); -+ OPT_HIST(total_size, trace_total_memory_hist); - // Update the offsets of each instruction: - for (size_t i = 0; i < length; i++) { - state.instruction_starts[i] += (uintptr_t)memory; - } - // Loop again to emit the code: - unsigned char *code = memory; -- unsigned char *data = memory + code_size; -- state.trampolines.mem = memory + code_size + data_size; -+ state.trampolines.mem = memory + code_size; -+ unsigned char *data = memory + code_size + state.trampolines.size; - // Compile the shim, which handles converting between the native - // calling convention and the calling convention used by jitted code - // (which may be different for efficiency reasons). -@@ -539,7 +547,7 @@ - code += group->code_size; - data += group->data_size; - assert(code == memory + code_size); -- assert(data == memory + code_size + data_size); -+ assert(data == memory + code_size + state.trampolines.size + data_size); - #ifdef MAP_JIT - pthread_jit_write_protect_np(1); - #endif -@@ -563,7 +571,8 @@ - executor->jit_side_entry = NULL; - executor->jit_size = 0; - if (jit_free(memory, size)) { -- PyErr_WriteUnraisable(NULL); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "freeing JIT memory"); - } - } - } -diff --git a/Python/legacy_tracing.c b/Python/legacy_tracing.c -index 45af275f1f6..97634f9183c 100644 ---- a/Python/legacy_tracing.c -+++ b/Python/legacy_tracing.c -@@ -491,8 +491,8 @@ - _PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) - { - assert(is_tstate_valid(tstate)); -- /* The caller must hold the GIL */ -- assert(PyGILState_Check()); -+ /* The caller must hold a thread state */ -+ _Py_AssertHoldsTstate(); - - /* Call _PySys_Audit() in the context of the current thread state, - even if tstate is not the current thread state. */ -@@ -586,8 +586,8 @@ - _PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) - { - assert(is_tstate_valid(tstate)); -- /* The caller must hold the GIL */ -- assert(PyGILState_Check()); -+ /* The caller must hold a thread state */ -+ _Py_AssertHoldsTstate(); - - /* Call _PySys_Audit() in the context of the current thread state, - even if tstate is not the current thread state. */ -diff --git a/Python/marshal.c b/Python/marshal.c -index 72afa4ff894..cf701165251 100644 ---- a/Python/marshal.c -+++ b/Python/marshal.c -@@ -240,10 +240,6 @@ - #define PyLong_MARSHAL_SHIFT 15 - #define PyLong_MARSHAL_BASE ((short)1 << PyLong_MARSHAL_SHIFT) - #define PyLong_MARSHAL_MASK (PyLong_MARSHAL_BASE - 1) --#if PyLong_SHIFT % PyLong_MARSHAL_SHIFT != 0 --#error "PyLong_SHIFT must be a multiple of PyLong_MARSHAL_SHIFT" --#endif --#define PyLong_MARSHAL_RATIO (PyLong_SHIFT / PyLong_MARSHAL_SHIFT) - - #define W_TYPE(t, p) do { \ - w_byte((t) | flag, (p)); \ -@@ -252,47 +248,106 @@ - static PyObject * - _PyMarshal_WriteObjectToString(PyObject *x, int version, int allow_code); - -+#define _r_digits(bitsize) \ -+static void \ -+_r_digits##bitsize(const uint ## bitsize ## _t *digits, Py_ssize_t n, \ -+ uint8_t negative, Py_ssize_t marshal_ratio, WFILE *p) \ -+{ \ -+ /* set l to number of base PyLong_MARSHAL_BASE digits */ \ -+ Py_ssize_t l = (n - 1)*marshal_ratio; \ -+ uint ## bitsize ## _t d = digits[n - 1]; \ -+ \ -+ assert(marshal_ratio > 0); \ -+ assert(n >= 1); \ -+ assert(d != 0); /* a PyLong is always normalized */ \ -+ do { \ -+ d >>= PyLong_MARSHAL_SHIFT; \ -+ l++; \ -+ } while (d != 0); \ -+ if (l > SIZE32_MAX) { \ -+ p->depth--; \ -+ p->error = WFERR_UNMARSHALLABLE; \ -+ return; \ -+ } \ -+ w_long((long)(negative ? -l : l), p); \ -+ \ -+ for (Py_ssize_t i = 0; i < n - 1; i++) { \ -+ d = digits[i]; \ -+ for (Py_ssize_t j = 0; j < marshal_ratio; j++) { \ -+ w_short(d & PyLong_MARSHAL_MASK, p); \ -+ d >>= PyLong_MARSHAL_SHIFT; \ -+ } \ -+ assert(d == 0); \ -+ } \ -+ d = digits[n - 1]; \ -+ do { \ -+ w_short(d & PyLong_MARSHAL_MASK, p); \ -+ d >>= PyLong_MARSHAL_SHIFT; \ -+ } while (d != 0); \ -+} -+_r_digits(16) -+_r_digits(32) -+#undef _r_digits -+ - static void - w_PyLong(const PyLongObject *ob, char flag, WFILE *p) - { -- Py_ssize_t i, j, n, l; -- digit d; -- - W_TYPE(TYPE_LONG, p); - if (_PyLong_IsZero(ob)) { - w_long((long)0, p); - return; - } - -- /* set l to number of base PyLong_MARSHAL_BASE digits */ -- n = _PyLong_DigitCount(ob); -- l = (n-1) * PyLong_MARSHAL_RATIO; -- d = ob->long_value.ob_digit[n-1]; -- assert(d != 0); /* a PyLong is always normalized */ -- do { -- d >>= PyLong_MARSHAL_SHIFT; -- l++; -- } while (d != 0); -- if (l > SIZE32_MAX) { -+ PyLongExport long_export; -+ -+ if (PyLong_Export((PyObject *)ob, &long_export) < 0) { - p->depth--; - p->error = WFERR_UNMARSHALLABLE; - return; - } -- w_long((long)(_PyLong_IsNegative(ob) ? -l : l), p); -+ if (!long_export.digits) { -+ int8_t sign = long_export.value < 0 ? -1 : 1; -+ uint64_t abs_value = Py_ABS(long_export.value); -+ uint64_t d = abs_value; -+ long l = 0; - -- for (i=0; i < n-1; i++) { -- d = ob->long_value.ob_digit[i]; -- for (j=0; j < PyLong_MARSHAL_RATIO; j++) { -+ /* set l to number of base PyLong_MARSHAL_BASE digits */ -+ do { -+ d >>= PyLong_MARSHAL_SHIFT; -+ l += sign; -+ } while (d); -+ w_long(l, p); -+ -+ d = abs_value; -+ do { - w_short(d & PyLong_MARSHAL_MASK, p); - d >>= PyLong_MARSHAL_SHIFT; -- } -- assert (d == 0); -+ } while (d); -+ return; - } -- d = ob->long_value.ob_digit[n-1]; -- do { -- w_short(d & PyLong_MARSHAL_MASK, p); -- d >>= PyLong_MARSHAL_SHIFT; -- } while (d != 0); -+ -+ const PyLongLayout *layout = PyLong_GetNativeLayout(); -+ Py_ssize_t marshal_ratio = layout->bits_per_digit/PyLong_MARSHAL_SHIFT; -+ -+ /* must be a multiple of PyLong_MARSHAL_SHIFT */ -+ assert(layout->bits_per_digit % PyLong_MARSHAL_SHIFT == 0); -+ assert(layout->bits_per_digit >= PyLong_MARSHAL_SHIFT); -+ -+ /* other assumptions on PyLongObject internals */ -+ assert(layout->bits_per_digit <= 32); -+ assert(layout->digits_order == -1); -+ assert(layout->digit_endianness == (PY_LITTLE_ENDIAN ? -1 : 1)); -+ assert(layout->digit_size == 2 || layout->digit_size == 4); -+ -+ if (layout->digit_size == 4) { -+ _r_digits32(long_export.digits, long_export.ndigits, -+ long_export.negative, marshal_ratio, p); -+ } -+ else { -+ _r_digits16(long_export.digits, long_export.ndigits, -+ long_export.negative, marshal_ratio, p); -+ } -+ PyLong_FreeExport(&long_export); - } - - static void -@@ -875,17 +930,62 @@ - 1 /* signed */); - } - -+#define _w_digits(bitsize) \ -+static int \ -+_w_digits##bitsize(uint ## bitsize ## _t *digits, Py_ssize_t size, \ -+ Py_ssize_t marshal_ratio, \ -+ int shorts_in_top_digit, RFILE *p) \ -+{ \ -+ uint ## bitsize ## _t d; \ -+ \ -+ assert(size >= 1); \ -+ for (Py_ssize_t i = 0; i < size - 1; i++) { \ -+ d = 0; \ -+ for (Py_ssize_t j = 0; j < marshal_ratio; j++) { \ -+ int md = r_short(p); \ -+ if (md < 0 || md > PyLong_MARSHAL_BASE) { \ -+ goto bad_digit; \ -+ } \ -+ d += (uint ## bitsize ## _t)md << j*PyLong_MARSHAL_SHIFT; \ -+ } \ -+ digits[i] = d; \ -+ } \ -+ \ -+ d = 0; \ -+ for (Py_ssize_t j = 0; j < shorts_in_top_digit; j++) { \ -+ int md = r_short(p); \ -+ if (md < 0 || md > PyLong_MARSHAL_BASE) { \ -+ goto bad_digit; \ -+ } \ -+ /* topmost marshal digit should be nonzero */ \ -+ if (md == 0 && j == shorts_in_top_digit - 1) { \ -+ PyErr_SetString(PyExc_ValueError, \ -+ "bad marshal data (unnormalized long data)"); \ -+ return -1; \ -+ } \ -+ d += (uint ## bitsize ## _t)md << j*PyLong_MARSHAL_SHIFT; \ -+ } \ -+ assert(!PyErr_Occurred()); \ -+ /* top digit should be nonzero, else the resulting PyLong won't be \ -+ normalized */ \ -+ digits[size - 1] = d; \ -+ return 0; \ -+ \ -+bad_digit: \ -+ if (!PyErr_Occurred()) { \ -+ PyErr_SetString(PyExc_ValueError, \ -+ "bad marshal data (digit out of range in long)"); \ -+ } \ -+ return -1; \ -+} -+_w_digits(32) -+_w_digits(16) -+#undef _w_digits -+ - static PyObject * - r_PyLong(RFILE *p) - { -- PyLongObject *ob; -- long n, size, i; -- int j, md, shorts_in_top_digit; -- digit d; -- -- n = r_long(p); -- if (n == 0) -- return (PyObject *)_PyLong_New(0); -+ long n = r_long(p); - if (n == -1 && PyErr_Occurred()) { - return NULL; - } -@@ -895,51 +995,44 @@ - return NULL; - } - -- size = 1 + (Py_ABS(n) - 1) / PyLong_MARSHAL_RATIO; -- shorts_in_top_digit = 1 + (Py_ABS(n) - 1) % PyLong_MARSHAL_RATIO; -- ob = _PyLong_New(size); -- if (ob == NULL) -- return NULL; -+ const PyLongLayout *layout = PyLong_GetNativeLayout(); -+ Py_ssize_t marshal_ratio = layout->bits_per_digit/PyLong_MARSHAL_SHIFT; - -- _PyLong_SetSignAndDigitCount(ob, n < 0 ? -1 : 1, size); -+ /* must be a multiple of PyLong_MARSHAL_SHIFT */ -+ assert(layout->bits_per_digit % PyLong_MARSHAL_SHIFT == 0); -+ assert(layout->bits_per_digit >= PyLong_MARSHAL_SHIFT); - -- for (i = 0; i < size-1; i++) { -- d = 0; -- for (j=0; j < PyLong_MARSHAL_RATIO; j++) { -- md = r_short(p); -- if (md < 0 || md > PyLong_MARSHAL_BASE) -- goto bad_digit; -- d += (digit)md << j*PyLong_MARSHAL_SHIFT; -- } -- ob->long_value.ob_digit[i] = d; -+ /* other assumptions on PyLongObject internals */ -+ assert(layout->bits_per_digit <= 32); -+ assert(layout->digits_order == -1); -+ assert(layout->digit_endianness == (PY_LITTLE_ENDIAN ? -1 : 1)); -+ assert(layout->digit_size == 2 || layout->digit_size == 4); -+ -+ Py_ssize_t size = 1 + (Py_ABS(n) - 1) / marshal_ratio; -+ -+ assert(size >= 1); -+ -+ int shorts_in_top_digit = 1 + (Py_ABS(n) - 1) % marshal_ratio; -+ void *digits; -+ PyLongWriter *writer = PyLongWriter_Create(n < 0, size, &digits); -+ -+ if (writer == NULL) { -+ return NULL; - } - -- d = 0; -- for (j=0; j < shorts_in_top_digit; j++) { -- md = r_short(p); -- if (md < 0 || md > PyLong_MARSHAL_BASE) -- goto bad_digit; -- /* topmost marshal digit should be nonzero */ -- if (md == 0 && j == shorts_in_top_digit - 1) { -- Py_DECREF(ob); -- PyErr_SetString(PyExc_ValueError, -- "bad marshal data (unnormalized long data)"); -- return NULL; -- } -- d += (digit)md << j*PyLong_MARSHAL_SHIFT; -+ int ret; -+ -+ if (layout->digit_size == 4) { -+ ret = _w_digits32(digits, size, marshal_ratio, shorts_in_top_digit, p); - } -- assert(!PyErr_Occurred()); -- /* top digit should be nonzero, else the resulting PyLong won't be -- normalized */ -- ob->long_value.ob_digit[size-1] = d; -- return (PyObject *)ob; -- bad_digit: -- Py_DECREF(ob); -- if (!PyErr_Occurred()) { -- PyErr_SetString(PyExc_ValueError, -- "bad marshal data (digit out of range in long)"); -+ else { -+ ret = _w_digits16(digits, size, marshal_ratio, shorts_in_top_digit, p); -+ } -+ if (ret < 0) { -+ PyLongWriter_Discard(writer); -+ return NULL; - } -- return NULL; -+ return PyLongWriter_Finish(writer); - } - - static double -diff --git a/Python/modsupport.c b/Python/modsupport.c -index 0fb7783345c..517dc971f88 100644 ---- a/Python/modsupport.c -+++ b/Python/modsupport.c -@@ -648,3 +648,20 @@ - - return PyModule_AddObjectRef(module, name, (PyObject *)type); - } -+ -+ -+/* Exported functions for version helper macros */ -+ -+#undef Py_PACK_FULL_VERSION -+uint32_t -+Py_PACK_FULL_VERSION(int x, int y, int z, int level, int serial) -+{ -+ return _Py_PACK_FULL_VERSION(x, y, z, level, serial); -+} -+ -+#undef Py_PACK_VERSION -+uint32_t -+Py_PACK_VERSION(int x, int y) -+{ -+ return Py_PACK_FULL_VERSION(x, y, 0, 0, 0); -+} -diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h -index c93941dcac4..039a6eee379 100644 ---- a/Python/opcode_targets.h -+++ b/Python/opcode_targets.h -@@ -1,7 +1,8 @@ -+#ifndef Py_TAIL_CALL_INTERP - static void *opcode_targets[256] = { - &&TARGET_CACHE, - &&TARGET_BINARY_SLICE, -- &&TARGET_BINARY_SUBSCR, -+ &&TARGET_CALL_FUNCTION_EX, - &&TARGET_BINARY_OP_INPLACE_ADD_UNICODE, - &&TARGET_CHECK_EG_MATCH, - &&TARGET_CHECK_EXC_MATCH, -@@ -27,7 +28,9 @@ - &&TARGET_MATCH_MAPPING, - &&TARGET_MATCH_SEQUENCE, - &&TARGET_NOP, -+ &&TARGET_NOT_TAKEN, - &&TARGET_POP_EXCEPT, -+ &&TARGET_POP_ITER, - &&TARGET_POP_TOP, - &&TARGET_PUSH_EXC_INFO, - &&TARGET_PUSH_NULL, -@@ -49,7 +52,6 @@ - &&TARGET_BUILD_STRING, - &&TARGET_BUILD_TUPLE, - &&TARGET_CALL, -- &&TARGET_CALL_FUNCTION_EX, - &&TARGET_CALL_INTRINSIC_1, - &&TARGET_CALL_INTRINSIC_2, - &&TARGET_CALL_KW, -@@ -147,20 +149,20 @@ - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, -- &&_unknown_opcode, - &&TARGET_RESUME, - &&TARGET_BINARY_OP_ADD_FLOAT, - &&TARGET_BINARY_OP_ADD_INT, - &&TARGET_BINARY_OP_ADD_UNICODE, -+ &&TARGET_BINARY_OP_EXTEND, - &&TARGET_BINARY_OP_MULTIPLY_FLOAT, - &&TARGET_BINARY_OP_MULTIPLY_INT, -+ &&TARGET_BINARY_OP_SUBSCR_DICT, -+ &&TARGET_BINARY_OP_SUBSCR_GETITEM, -+ &&TARGET_BINARY_OP_SUBSCR_LIST_INT, -+ &&TARGET_BINARY_OP_SUBSCR_STR_INT, -+ &&TARGET_BINARY_OP_SUBSCR_TUPLE_INT, - &&TARGET_BINARY_OP_SUBTRACT_FLOAT, - &&TARGET_BINARY_OP_SUBTRACT_INT, -- &&TARGET_BINARY_SUBSCR_DICT, -- &&TARGET_BINARY_SUBSCR_GETITEM, -- &&TARGET_BINARY_SUBSCR_LIST_INT, -- &&TARGET_BINARY_SUBSCR_STR_INT, -- &&TARGET_BINARY_SUBSCR_TUPLE_INT, - &&TARGET_CALL_ALLOC_AND_ENTER_INIT, - &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS, - &&TARGET_CALL_BOUND_METHOD_GENERAL, -@@ -193,6 +195,8 @@ - &&TARGET_FOR_ITER_LIST, - &&TARGET_FOR_ITER_RANGE, - &&TARGET_FOR_ITER_TUPLE, -+ &&TARGET_JUMP_BACKWARD_JIT, -+ &&TARGET_JUMP_BACKWARD_NO_JIT, - &&TARGET_LOAD_ATTR_CLASS, - &&TARGET_LOAD_ATTR_CLASS_WITH_METACLASS_CHECK, - &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, -@@ -207,6 +211,7 @@ - &&TARGET_LOAD_ATTR_SLOT, - &&TARGET_LOAD_ATTR_WITH_HINT, - &&TARGET_LOAD_CONST_IMMORTAL, -+ &&TARGET_LOAD_CONST_MORTAL, - &&TARGET_LOAD_GLOBAL_BUILTIN, - &&TARGET_LOAD_GLOBAL_MODULE, - &&TARGET_LOAD_SUPER_ATTR_ATTR, -@@ -230,20 +235,13 @@ - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, -- &&_unknown_opcode, -- &&_unknown_opcode, -- &&_unknown_opcode, -- &&_unknown_opcode, -- &&_unknown_opcode, -- &&_unknown_opcode, - &&TARGET_INSTRUMENTED_END_FOR, -+ &&TARGET_INSTRUMENTED_POP_ITER, - &&TARGET_INSTRUMENTED_END_SEND, -- &&TARGET_INSTRUMENTED_LOAD_SUPER_ATTR, - &&TARGET_INSTRUMENTED_FOR_ITER, -- &&TARGET_INSTRUMENTED_CALL_KW, -- &&TARGET_INSTRUMENTED_CALL_FUNCTION_EX, - &&TARGET_INSTRUMENTED_INSTRUCTION, - &&TARGET_INSTRUMENTED_JUMP_FORWARD, -+ &&TARGET_INSTRUMENTED_NOT_TAKEN, - &&TARGET_INSTRUMENTED_POP_JUMP_IF_TRUE, - &&TARGET_INSTRUMENTED_POP_JUMP_IF_FALSE, - &&TARGET_INSTRUMENTED_POP_JUMP_IF_NONE, -@@ -251,8 +249,514 @@ - &&TARGET_INSTRUMENTED_RESUME, - &&TARGET_INSTRUMENTED_RETURN_VALUE, - &&TARGET_INSTRUMENTED_YIELD_VALUE, -+ &&TARGET_INSTRUMENTED_LOAD_SUPER_ATTR, - &&TARGET_INSTRUMENTED_CALL, -+ &&TARGET_INSTRUMENTED_CALL_KW, -+ &&TARGET_INSTRUMENTED_CALL_FUNCTION_EX, - &&TARGET_INSTRUMENTED_JUMP_BACKWARD, - &&TARGET_INSTRUMENTED_LINE, - &&TARGET_ENTER_EXECUTOR, - }; -+#else /* Py_TAIL_CALL_INTERP */ -+static py_tail_call_funcptr INSTRUCTION_TABLE[256]; -+ -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_pop_4_error(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_pop_3_error(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_pop_2_error(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_pop_1_error(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_error(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_exception_unwind(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_exit_unwind(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_start_frame(TAIL_CALL_PARAMS); -+ -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_ADD_FLOAT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_ADD_INT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_ADD_UNICODE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_EXTEND(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_INPLACE_ADD_UNICODE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_MULTIPLY_FLOAT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_MULTIPLY_INT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_SUBSCR_DICT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_SUBSCR_GETITEM(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_SUBSCR_LIST_INT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_SUBSCR_STR_INT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_SUBSCR_TUPLE_INT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_SUBTRACT_FLOAT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_OP_SUBTRACT_INT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BINARY_SLICE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BUILD_LIST(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BUILD_MAP(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BUILD_SET(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BUILD_SLICE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BUILD_STRING(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_BUILD_TUPLE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CACHE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_ALLOC_AND_ENTER_INIT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_BOUND_METHOD_EXACT_ARGS(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_BOUND_METHOD_GENERAL(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_BUILTIN_CLASS(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_BUILTIN_FAST(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_BUILTIN_FAST_WITH_KEYWORDS(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_BUILTIN_O(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_FUNCTION_EX(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_INTRINSIC_1(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_INTRINSIC_2(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_ISINSTANCE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_KW(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_KW_BOUND_METHOD(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_KW_NON_PY(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_KW_PY(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_LEN(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_LIST_APPEND(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_METHOD_DESCRIPTOR_FAST(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_METHOD_DESCRIPTOR_NOARGS(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_METHOD_DESCRIPTOR_O(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_NON_PY_GENERAL(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_PY_EXACT_ARGS(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_PY_GENERAL(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_STR_1(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_TUPLE_1(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CALL_TYPE_1(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CHECK_EG_MATCH(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CHECK_EXC_MATCH(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CLEANUP_THROW(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_COMPARE_OP(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_COMPARE_OP_FLOAT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_COMPARE_OP_INT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_COMPARE_OP_STR(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CONTAINS_OP(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CONTAINS_OP_DICT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CONTAINS_OP_SET(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_CONVERT_VALUE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_COPY(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_COPY_FREE_VARS(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_DELETE_ATTR(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_DELETE_DEREF(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_DELETE_FAST(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_DELETE_GLOBAL(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_DELETE_NAME(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_DELETE_SUBSCR(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_DICT_MERGE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_DICT_UPDATE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_END_ASYNC_FOR(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_END_FOR(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_END_SEND(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_ENTER_EXECUTOR(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_EXIT_INIT_CHECK(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_EXTENDED_ARG(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_FORMAT_SIMPLE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_FORMAT_WITH_SPEC(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_FOR_ITER(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_FOR_ITER_GEN(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_FOR_ITER_LIST(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_FOR_ITER_RANGE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_FOR_ITER_TUPLE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_AITER(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_ANEXT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_AWAITABLE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_ITER(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_LEN(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_YIELD_FROM_ITER(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_IMPORT_FROM(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_IMPORT_NAME(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_CALL(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_CALL_FUNCTION_EX(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_CALL_KW(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_END_FOR(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_END_SEND(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_FOR_ITER(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_INSTRUCTION(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_JUMP_BACKWARD(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_JUMP_FORWARD(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_LINE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_LOAD_SUPER_ATTR(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_NOT_TAKEN(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_POP_ITER(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_FALSE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_NONE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_NOT_NONE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_TRUE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_RESUME(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_RETURN_VALUE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INSTRUMENTED_YIELD_VALUE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_INTERPRETER_EXIT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_IS_OP(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_JUMP_BACKWARD(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_JUMP_BACKWARD_JIT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_JUMP_BACKWARD_NO_INTERRUPT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_JUMP_BACKWARD_NO_JIT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_JUMP_FORWARD(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LIST_APPEND(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LIST_EXTEND(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_CLASS(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_CLASS_WITH_METACLASS_CHECK(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_INSTANCE_VALUE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_METHOD_LAZY_DICT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_METHOD_NO_DICT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_METHOD_WITH_VALUES(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_MODULE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_NONDESCRIPTOR_NO_DICT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_PROPERTY(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_SLOT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_ATTR_WITH_HINT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_BUILD_CLASS(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_COMMON_CONSTANT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_CONST(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_CONST_IMMORTAL(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_CONST_MORTAL(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_DEREF(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_FAST(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_FAST_AND_CLEAR(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_FAST_CHECK(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_FAST_LOAD_FAST(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_FROM_DICT_OR_DEREF(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_FROM_DICT_OR_GLOBALS(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_GLOBAL(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_GLOBAL_BUILTIN(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_GLOBAL_MODULE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_LOCALS(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_NAME(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_SMALL_INT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_SPECIAL(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_SUPER_ATTR(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_SUPER_ATTR_ATTR(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_LOAD_SUPER_ATTR_METHOD(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_MAKE_CELL(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_MAKE_FUNCTION(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_MAP_ADD(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_MATCH_CLASS(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_MATCH_KEYS(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_MATCH_MAPPING(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_MATCH_SEQUENCE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_NOP(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_NOT_TAKEN(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_POP_EXCEPT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_POP_ITER(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_POP_JUMP_IF_FALSE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_POP_JUMP_IF_NONE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_POP_JUMP_IF_NOT_NONE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_POP_JUMP_IF_TRUE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_POP_TOP(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_PUSH_EXC_INFO(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_PUSH_NULL(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_RAISE_VARARGS(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_RERAISE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_RESERVED(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_RESUME(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_RESUME_CHECK(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_RETURN_GENERATOR(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_RETURN_VALUE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_SEND(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_SEND_GEN(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_SETUP_ANNOTATIONS(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_SET_ADD(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_SET_FUNCTION_ATTRIBUTE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_SET_UPDATE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_ATTR(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_ATTR_INSTANCE_VALUE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_ATTR_SLOT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_ATTR_WITH_HINT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_DEREF(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_FAST(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_FAST_LOAD_FAST(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_FAST_STORE_FAST(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_GLOBAL(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_NAME(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_SLICE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_SUBSCR(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_SUBSCR_DICT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_STORE_SUBSCR_LIST_INT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_SWAP(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_TO_BOOL(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_TO_BOOL_ALWAYS_TRUE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_TO_BOOL_BOOL(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_TO_BOOL_INT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_TO_BOOL_LIST(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_TO_BOOL_NONE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_TO_BOOL_STR(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNARY_INVERT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNARY_NEGATIVE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNARY_NOT(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNPACK_EX(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNPACK_SEQUENCE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNPACK_SEQUENCE_LIST(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNPACK_SEQUENCE_TUPLE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNPACK_SEQUENCE_TWO_TUPLE(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_WITH_EXCEPT_START(TAIL_CALL_PARAMS); -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_YIELD_VALUE(TAIL_CALL_PARAMS); -+ -+Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNKNOWN_OPCODE(TAIL_CALL_PARAMS) { -+ int opcode = next_instr->op.code; -+ _PyErr_Format(tstate, PyExc_SystemError, -+ "%U:%d: unknown opcode %d", -+ _PyFrame_GetCode(frame)->co_filename, -+ PyUnstable_InterpreterFrame_GetLine(frame), -+ opcode); -+JUMP_TO_LABEL(error); -+} -+ -+static py_tail_call_funcptr INSTRUCTION_TABLE[256] = { -+ [BINARY_OP] = _TAIL_CALL_BINARY_OP, -+ [BINARY_OP_ADD_FLOAT] = _TAIL_CALL_BINARY_OP_ADD_FLOAT, -+ [BINARY_OP_ADD_INT] = _TAIL_CALL_BINARY_OP_ADD_INT, -+ [BINARY_OP_ADD_UNICODE] = _TAIL_CALL_BINARY_OP_ADD_UNICODE, -+ [BINARY_OP_EXTEND] = _TAIL_CALL_BINARY_OP_EXTEND, -+ [BINARY_OP_INPLACE_ADD_UNICODE] = _TAIL_CALL_BINARY_OP_INPLACE_ADD_UNICODE, -+ [BINARY_OP_MULTIPLY_FLOAT] = _TAIL_CALL_BINARY_OP_MULTIPLY_FLOAT, -+ [BINARY_OP_MULTIPLY_INT] = _TAIL_CALL_BINARY_OP_MULTIPLY_INT, -+ [BINARY_OP_SUBSCR_DICT] = _TAIL_CALL_BINARY_OP_SUBSCR_DICT, -+ [BINARY_OP_SUBSCR_GETITEM] = _TAIL_CALL_BINARY_OP_SUBSCR_GETITEM, -+ [BINARY_OP_SUBSCR_LIST_INT] = _TAIL_CALL_BINARY_OP_SUBSCR_LIST_INT, -+ [BINARY_OP_SUBSCR_STR_INT] = _TAIL_CALL_BINARY_OP_SUBSCR_STR_INT, -+ [BINARY_OP_SUBSCR_TUPLE_INT] = _TAIL_CALL_BINARY_OP_SUBSCR_TUPLE_INT, -+ [BINARY_OP_SUBTRACT_FLOAT] = _TAIL_CALL_BINARY_OP_SUBTRACT_FLOAT, -+ [BINARY_OP_SUBTRACT_INT] = _TAIL_CALL_BINARY_OP_SUBTRACT_INT, -+ [BINARY_SLICE] = _TAIL_CALL_BINARY_SLICE, -+ [BUILD_LIST] = _TAIL_CALL_BUILD_LIST, -+ [BUILD_MAP] = _TAIL_CALL_BUILD_MAP, -+ [BUILD_SET] = _TAIL_CALL_BUILD_SET, -+ [BUILD_SLICE] = _TAIL_CALL_BUILD_SLICE, -+ [BUILD_STRING] = _TAIL_CALL_BUILD_STRING, -+ [BUILD_TUPLE] = _TAIL_CALL_BUILD_TUPLE, -+ [CACHE] = _TAIL_CALL_CACHE, -+ [CALL] = _TAIL_CALL_CALL, -+ [CALL_ALLOC_AND_ENTER_INIT] = _TAIL_CALL_CALL_ALLOC_AND_ENTER_INIT, -+ [CALL_BOUND_METHOD_EXACT_ARGS] = _TAIL_CALL_CALL_BOUND_METHOD_EXACT_ARGS, -+ [CALL_BOUND_METHOD_GENERAL] = _TAIL_CALL_CALL_BOUND_METHOD_GENERAL, -+ [CALL_BUILTIN_CLASS] = _TAIL_CALL_CALL_BUILTIN_CLASS, -+ [CALL_BUILTIN_FAST] = _TAIL_CALL_CALL_BUILTIN_FAST, -+ [CALL_BUILTIN_FAST_WITH_KEYWORDS] = _TAIL_CALL_CALL_BUILTIN_FAST_WITH_KEYWORDS, -+ [CALL_BUILTIN_O] = _TAIL_CALL_CALL_BUILTIN_O, -+ [CALL_FUNCTION_EX] = _TAIL_CALL_CALL_FUNCTION_EX, -+ [CALL_INTRINSIC_1] = _TAIL_CALL_CALL_INTRINSIC_1, -+ [CALL_INTRINSIC_2] = _TAIL_CALL_CALL_INTRINSIC_2, -+ [CALL_ISINSTANCE] = _TAIL_CALL_CALL_ISINSTANCE, -+ [CALL_KW] = _TAIL_CALL_CALL_KW, -+ [CALL_KW_BOUND_METHOD] = _TAIL_CALL_CALL_KW_BOUND_METHOD, -+ [CALL_KW_NON_PY] = _TAIL_CALL_CALL_KW_NON_PY, -+ [CALL_KW_PY] = _TAIL_CALL_CALL_KW_PY, -+ [CALL_LEN] = _TAIL_CALL_CALL_LEN, -+ [CALL_LIST_APPEND] = _TAIL_CALL_CALL_LIST_APPEND, -+ [CALL_METHOD_DESCRIPTOR_FAST] = _TAIL_CALL_CALL_METHOD_DESCRIPTOR_FAST, -+ [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = _TAIL_CALL_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, -+ [CALL_METHOD_DESCRIPTOR_NOARGS] = _TAIL_CALL_CALL_METHOD_DESCRIPTOR_NOARGS, -+ [CALL_METHOD_DESCRIPTOR_O] = _TAIL_CALL_CALL_METHOD_DESCRIPTOR_O, -+ [CALL_NON_PY_GENERAL] = _TAIL_CALL_CALL_NON_PY_GENERAL, -+ [CALL_PY_EXACT_ARGS] = _TAIL_CALL_CALL_PY_EXACT_ARGS, -+ [CALL_PY_GENERAL] = _TAIL_CALL_CALL_PY_GENERAL, -+ [CALL_STR_1] = _TAIL_CALL_CALL_STR_1, -+ [CALL_TUPLE_1] = _TAIL_CALL_CALL_TUPLE_1, -+ [CALL_TYPE_1] = _TAIL_CALL_CALL_TYPE_1, -+ [CHECK_EG_MATCH] = _TAIL_CALL_CHECK_EG_MATCH, -+ [CHECK_EXC_MATCH] = _TAIL_CALL_CHECK_EXC_MATCH, -+ [CLEANUP_THROW] = _TAIL_CALL_CLEANUP_THROW, -+ [COMPARE_OP] = _TAIL_CALL_COMPARE_OP, -+ [COMPARE_OP_FLOAT] = _TAIL_CALL_COMPARE_OP_FLOAT, -+ [COMPARE_OP_INT] = _TAIL_CALL_COMPARE_OP_INT, -+ [COMPARE_OP_STR] = _TAIL_CALL_COMPARE_OP_STR, -+ [CONTAINS_OP] = _TAIL_CALL_CONTAINS_OP, -+ [CONTAINS_OP_DICT] = _TAIL_CALL_CONTAINS_OP_DICT, -+ [CONTAINS_OP_SET] = _TAIL_CALL_CONTAINS_OP_SET, -+ [CONVERT_VALUE] = _TAIL_CALL_CONVERT_VALUE, -+ [COPY] = _TAIL_CALL_COPY, -+ [COPY_FREE_VARS] = _TAIL_CALL_COPY_FREE_VARS, -+ [DELETE_ATTR] = _TAIL_CALL_DELETE_ATTR, -+ [DELETE_DEREF] = _TAIL_CALL_DELETE_DEREF, -+ [DELETE_FAST] = _TAIL_CALL_DELETE_FAST, -+ [DELETE_GLOBAL] = _TAIL_CALL_DELETE_GLOBAL, -+ [DELETE_NAME] = _TAIL_CALL_DELETE_NAME, -+ [DELETE_SUBSCR] = _TAIL_CALL_DELETE_SUBSCR, -+ [DICT_MERGE] = _TAIL_CALL_DICT_MERGE, -+ [DICT_UPDATE] = _TAIL_CALL_DICT_UPDATE, -+ [END_ASYNC_FOR] = _TAIL_CALL_END_ASYNC_FOR, -+ [END_FOR] = _TAIL_CALL_END_FOR, -+ [END_SEND] = _TAIL_CALL_END_SEND, -+ [ENTER_EXECUTOR] = _TAIL_CALL_ENTER_EXECUTOR, -+ [EXIT_INIT_CHECK] = _TAIL_CALL_EXIT_INIT_CHECK, -+ [EXTENDED_ARG] = _TAIL_CALL_EXTENDED_ARG, -+ [FORMAT_SIMPLE] = _TAIL_CALL_FORMAT_SIMPLE, -+ [FORMAT_WITH_SPEC] = _TAIL_CALL_FORMAT_WITH_SPEC, -+ [FOR_ITER] = _TAIL_CALL_FOR_ITER, -+ [FOR_ITER_GEN] = _TAIL_CALL_FOR_ITER_GEN, -+ [FOR_ITER_LIST] = _TAIL_CALL_FOR_ITER_LIST, -+ [FOR_ITER_RANGE] = _TAIL_CALL_FOR_ITER_RANGE, -+ [FOR_ITER_TUPLE] = _TAIL_CALL_FOR_ITER_TUPLE, -+ [GET_AITER] = _TAIL_CALL_GET_AITER, -+ [GET_ANEXT] = _TAIL_CALL_GET_ANEXT, -+ [GET_AWAITABLE] = _TAIL_CALL_GET_AWAITABLE, -+ [GET_ITER] = _TAIL_CALL_GET_ITER, -+ [GET_LEN] = _TAIL_CALL_GET_LEN, -+ [GET_YIELD_FROM_ITER] = _TAIL_CALL_GET_YIELD_FROM_ITER, -+ [IMPORT_FROM] = _TAIL_CALL_IMPORT_FROM, -+ [IMPORT_NAME] = _TAIL_CALL_IMPORT_NAME, -+ [INSTRUMENTED_CALL] = _TAIL_CALL_INSTRUMENTED_CALL, -+ [INSTRUMENTED_CALL_FUNCTION_EX] = _TAIL_CALL_INSTRUMENTED_CALL_FUNCTION_EX, -+ [INSTRUMENTED_CALL_KW] = _TAIL_CALL_INSTRUMENTED_CALL_KW, -+ [INSTRUMENTED_END_FOR] = _TAIL_CALL_INSTRUMENTED_END_FOR, -+ [INSTRUMENTED_END_SEND] = _TAIL_CALL_INSTRUMENTED_END_SEND, -+ [INSTRUMENTED_FOR_ITER] = _TAIL_CALL_INSTRUMENTED_FOR_ITER, -+ [INSTRUMENTED_INSTRUCTION] = _TAIL_CALL_INSTRUMENTED_INSTRUCTION, -+ [INSTRUMENTED_JUMP_BACKWARD] = _TAIL_CALL_INSTRUMENTED_JUMP_BACKWARD, -+ [INSTRUMENTED_JUMP_FORWARD] = _TAIL_CALL_INSTRUMENTED_JUMP_FORWARD, -+ [INSTRUMENTED_LINE] = _TAIL_CALL_INSTRUMENTED_LINE, -+ [INSTRUMENTED_LOAD_SUPER_ATTR] = _TAIL_CALL_INSTRUMENTED_LOAD_SUPER_ATTR, -+ [INSTRUMENTED_NOT_TAKEN] = _TAIL_CALL_INSTRUMENTED_NOT_TAKEN, -+ [INSTRUMENTED_POP_ITER] = _TAIL_CALL_INSTRUMENTED_POP_ITER, -+ [INSTRUMENTED_POP_JUMP_IF_FALSE] = _TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_FALSE, -+ [INSTRUMENTED_POP_JUMP_IF_NONE] = _TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_NONE, -+ [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = _TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_NOT_NONE, -+ [INSTRUMENTED_POP_JUMP_IF_TRUE] = _TAIL_CALL_INSTRUMENTED_POP_JUMP_IF_TRUE, -+ [INSTRUMENTED_RESUME] = _TAIL_CALL_INSTRUMENTED_RESUME, -+ [INSTRUMENTED_RETURN_VALUE] = _TAIL_CALL_INSTRUMENTED_RETURN_VALUE, -+ [INSTRUMENTED_YIELD_VALUE] = _TAIL_CALL_INSTRUMENTED_YIELD_VALUE, -+ [INTERPRETER_EXIT] = _TAIL_CALL_INTERPRETER_EXIT, -+ [IS_OP] = _TAIL_CALL_IS_OP, -+ [JUMP_BACKWARD] = _TAIL_CALL_JUMP_BACKWARD, -+ [JUMP_BACKWARD_JIT] = _TAIL_CALL_JUMP_BACKWARD_JIT, -+ [JUMP_BACKWARD_NO_INTERRUPT] = _TAIL_CALL_JUMP_BACKWARD_NO_INTERRUPT, -+ [JUMP_BACKWARD_NO_JIT] = _TAIL_CALL_JUMP_BACKWARD_NO_JIT, -+ [JUMP_FORWARD] = _TAIL_CALL_JUMP_FORWARD, -+ [LIST_APPEND] = _TAIL_CALL_LIST_APPEND, -+ [LIST_EXTEND] = _TAIL_CALL_LIST_EXTEND, -+ [LOAD_ATTR] = _TAIL_CALL_LOAD_ATTR, -+ [LOAD_ATTR_CLASS] = _TAIL_CALL_LOAD_ATTR_CLASS, -+ [LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = _TAIL_CALL_LOAD_ATTR_CLASS_WITH_METACLASS_CHECK, -+ [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = _TAIL_CALL_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, -+ [LOAD_ATTR_INSTANCE_VALUE] = _TAIL_CALL_LOAD_ATTR_INSTANCE_VALUE, -+ [LOAD_ATTR_METHOD_LAZY_DICT] = _TAIL_CALL_LOAD_ATTR_METHOD_LAZY_DICT, -+ [LOAD_ATTR_METHOD_NO_DICT] = _TAIL_CALL_LOAD_ATTR_METHOD_NO_DICT, -+ [LOAD_ATTR_METHOD_WITH_VALUES] = _TAIL_CALL_LOAD_ATTR_METHOD_WITH_VALUES, -+ [LOAD_ATTR_MODULE] = _TAIL_CALL_LOAD_ATTR_MODULE, -+ [LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = _TAIL_CALL_LOAD_ATTR_NONDESCRIPTOR_NO_DICT, -+ [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = _TAIL_CALL_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, -+ [LOAD_ATTR_PROPERTY] = _TAIL_CALL_LOAD_ATTR_PROPERTY, -+ [LOAD_ATTR_SLOT] = _TAIL_CALL_LOAD_ATTR_SLOT, -+ [LOAD_ATTR_WITH_HINT] = _TAIL_CALL_LOAD_ATTR_WITH_HINT, -+ [LOAD_BUILD_CLASS] = _TAIL_CALL_LOAD_BUILD_CLASS, -+ [LOAD_COMMON_CONSTANT] = _TAIL_CALL_LOAD_COMMON_CONSTANT, -+ [LOAD_CONST] = _TAIL_CALL_LOAD_CONST, -+ [LOAD_CONST_IMMORTAL] = _TAIL_CALL_LOAD_CONST_IMMORTAL, -+ [LOAD_CONST_MORTAL] = _TAIL_CALL_LOAD_CONST_MORTAL, -+ [LOAD_DEREF] = _TAIL_CALL_LOAD_DEREF, -+ [LOAD_FAST] = _TAIL_CALL_LOAD_FAST, -+ [LOAD_FAST_AND_CLEAR] = _TAIL_CALL_LOAD_FAST_AND_CLEAR, -+ [LOAD_FAST_CHECK] = _TAIL_CALL_LOAD_FAST_CHECK, -+ [LOAD_FAST_LOAD_FAST] = _TAIL_CALL_LOAD_FAST_LOAD_FAST, -+ [LOAD_FROM_DICT_OR_DEREF] = _TAIL_CALL_LOAD_FROM_DICT_OR_DEREF, -+ [LOAD_FROM_DICT_OR_GLOBALS] = _TAIL_CALL_LOAD_FROM_DICT_OR_GLOBALS, -+ [LOAD_GLOBAL] = _TAIL_CALL_LOAD_GLOBAL, -+ [LOAD_GLOBAL_BUILTIN] = _TAIL_CALL_LOAD_GLOBAL_BUILTIN, -+ [LOAD_GLOBAL_MODULE] = _TAIL_CALL_LOAD_GLOBAL_MODULE, -+ [LOAD_LOCALS] = _TAIL_CALL_LOAD_LOCALS, -+ [LOAD_NAME] = _TAIL_CALL_LOAD_NAME, -+ [LOAD_SMALL_INT] = _TAIL_CALL_LOAD_SMALL_INT, -+ [LOAD_SPECIAL] = _TAIL_CALL_LOAD_SPECIAL, -+ [LOAD_SUPER_ATTR] = _TAIL_CALL_LOAD_SUPER_ATTR, -+ [LOAD_SUPER_ATTR_ATTR] = _TAIL_CALL_LOAD_SUPER_ATTR_ATTR, -+ [LOAD_SUPER_ATTR_METHOD] = _TAIL_CALL_LOAD_SUPER_ATTR_METHOD, -+ [MAKE_CELL] = _TAIL_CALL_MAKE_CELL, -+ [MAKE_FUNCTION] = _TAIL_CALL_MAKE_FUNCTION, -+ [MAP_ADD] = _TAIL_CALL_MAP_ADD, -+ [MATCH_CLASS] = _TAIL_CALL_MATCH_CLASS, -+ [MATCH_KEYS] = _TAIL_CALL_MATCH_KEYS, -+ [MATCH_MAPPING] = _TAIL_CALL_MATCH_MAPPING, -+ [MATCH_SEQUENCE] = _TAIL_CALL_MATCH_SEQUENCE, -+ [NOP] = _TAIL_CALL_NOP, -+ [NOT_TAKEN] = _TAIL_CALL_NOT_TAKEN, -+ [POP_EXCEPT] = _TAIL_CALL_POP_EXCEPT, -+ [POP_ITER] = _TAIL_CALL_POP_ITER, -+ [POP_JUMP_IF_FALSE] = _TAIL_CALL_POP_JUMP_IF_FALSE, -+ [POP_JUMP_IF_NONE] = _TAIL_CALL_POP_JUMP_IF_NONE, -+ [POP_JUMP_IF_NOT_NONE] = _TAIL_CALL_POP_JUMP_IF_NOT_NONE, -+ [POP_JUMP_IF_TRUE] = _TAIL_CALL_POP_JUMP_IF_TRUE, -+ [POP_TOP] = _TAIL_CALL_POP_TOP, -+ [PUSH_EXC_INFO] = _TAIL_CALL_PUSH_EXC_INFO, -+ [PUSH_NULL] = _TAIL_CALL_PUSH_NULL, -+ [RAISE_VARARGS] = _TAIL_CALL_RAISE_VARARGS, -+ [RERAISE] = _TAIL_CALL_RERAISE, -+ [RESERVED] = _TAIL_CALL_RESERVED, -+ [RESUME] = _TAIL_CALL_RESUME, -+ [RESUME_CHECK] = _TAIL_CALL_RESUME_CHECK, -+ [RETURN_GENERATOR] = _TAIL_CALL_RETURN_GENERATOR, -+ [RETURN_VALUE] = _TAIL_CALL_RETURN_VALUE, -+ [SEND] = _TAIL_CALL_SEND, -+ [SEND_GEN] = _TAIL_CALL_SEND_GEN, -+ [SETUP_ANNOTATIONS] = _TAIL_CALL_SETUP_ANNOTATIONS, -+ [SET_ADD] = _TAIL_CALL_SET_ADD, -+ [SET_FUNCTION_ATTRIBUTE] = _TAIL_CALL_SET_FUNCTION_ATTRIBUTE, -+ [SET_UPDATE] = _TAIL_CALL_SET_UPDATE, -+ [STORE_ATTR] = _TAIL_CALL_STORE_ATTR, -+ [STORE_ATTR_INSTANCE_VALUE] = _TAIL_CALL_STORE_ATTR_INSTANCE_VALUE, -+ [STORE_ATTR_SLOT] = _TAIL_CALL_STORE_ATTR_SLOT, -+ [STORE_ATTR_WITH_HINT] = _TAIL_CALL_STORE_ATTR_WITH_HINT, -+ [STORE_DEREF] = _TAIL_CALL_STORE_DEREF, -+ [STORE_FAST] = _TAIL_CALL_STORE_FAST, -+ [STORE_FAST_LOAD_FAST] = _TAIL_CALL_STORE_FAST_LOAD_FAST, -+ [STORE_FAST_STORE_FAST] = _TAIL_CALL_STORE_FAST_STORE_FAST, -+ [STORE_GLOBAL] = _TAIL_CALL_STORE_GLOBAL, -+ [STORE_NAME] = _TAIL_CALL_STORE_NAME, -+ [STORE_SLICE] = _TAIL_CALL_STORE_SLICE, -+ [STORE_SUBSCR] = _TAIL_CALL_STORE_SUBSCR, -+ [STORE_SUBSCR_DICT] = _TAIL_CALL_STORE_SUBSCR_DICT, -+ [STORE_SUBSCR_LIST_INT] = _TAIL_CALL_STORE_SUBSCR_LIST_INT, -+ [SWAP] = _TAIL_CALL_SWAP, -+ [TO_BOOL] = _TAIL_CALL_TO_BOOL, -+ [TO_BOOL_ALWAYS_TRUE] = _TAIL_CALL_TO_BOOL_ALWAYS_TRUE, -+ [TO_BOOL_BOOL] = _TAIL_CALL_TO_BOOL_BOOL, -+ [TO_BOOL_INT] = _TAIL_CALL_TO_BOOL_INT, -+ [TO_BOOL_LIST] = _TAIL_CALL_TO_BOOL_LIST, -+ [TO_BOOL_NONE] = _TAIL_CALL_TO_BOOL_NONE, -+ [TO_BOOL_STR] = _TAIL_CALL_TO_BOOL_STR, -+ [UNARY_INVERT] = _TAIL_CALL_UNARY_INVERT, -+ [UNARY_NEGATIVE] = _TAIL_CALL_UNARY_NEGATIVE, -+ [UNARY_NOT] = _TAIL_CALL_UNARY_NOT, -+ [UNPACK_EX] = _TAIL_CALL_UNPACK_EX, -+ [UNPACK_SEQUENCE] = _TAIL_CALL_UNPACK_SEQUENCE, -+ [UNPACK_SEQUENCE_LIST] = _TAIL_CALL_UNPACK_SEQUENCE_LIST, -+ [UNPACK_SEQUENCE_TUPLE] = _TAIL_CALL_UNPACK_SEQUENCE_TUPLE, -+ [UNPACK_SEQUENCE_TWO_TUPLE] = _TAIL_CALL_UNPACK_SEQUENCE_TWO_TUPLE, -+ [WITH_EXCEPT_START] = _TAIL_CALL_WITH_EXCEPT_START, -+ [YIELD_VALUE] = _TAIL_CALL_YIELD_VALUE, -+ [117] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [118] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [119] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [120] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [121] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [122] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [123] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [124] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [125] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [126] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [127] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [128] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [129] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [130] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [131] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [132] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [133] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [134] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [135] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [136] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [137] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [138] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [139] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [140] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [141] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [142] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [143] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [144] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [145] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [146] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [147] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [148] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [232] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [233] = _TAIL_CALL_UNKNOWN_OPCODE, -+ [234] = _TAIL_CALL_UNKNOWN_OPCODE, -+}; -+#endif /* Py_TAIL_CALL_INTERP */ -diff --git a/Python/optimizer.c b/Python/optimizer.c -index 6a4d20fad76..bef5728349a 100644 ---- a/Python/optimizer.c -+++ b/Python/optimizer.c -@@ -91,72 +91,13 @@ - instr->op.arg = index; - } - -- --static int --never_optimize( -- _PyOptimizerObject* self, -- _PyInterpreterFrame *frame, -- _Py_CODEUNIT *instr, -- _PyExecutorObject **exec, -- int Py_UNUSED(stack_entries), -- bool Py_UNUSED(progress_needed)) --{ -- // This may be called if the optimizer is reset -- return 0; --} -- --PyTypeObject _PyDefaultOptimizer_Type = { -- PyVarObject_HEAD_INIT(&PyType_Type, 0) -- .tp_name = "noop_optimizer", -- .tp_basicsize = sizeof(_PyOptimizerObject), -- .tp_itemsize = 0, -- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, --}; -- --static _PyOptimizerObject _PyOptimizer_Default = { -- PyObject_HEAD_INIT(&_PyDefaultOptimizer_Type) -- .optimize = never_optimize, --}; -- --_PyOptimizerObject * --_Py_GetOptimizer(void) --{ -- PyInterpreterState *interp = _PyInterpreterState_GET(); -- if (interp->optimizer == &_PyOptimizer_Default) { -- return NULL; -- } -- Py_INCREF(interp->optimizer); -- return interp->optimizer; --} -- - static _PyExecutorObject * - make_executor_from_uops(_PyUOpInstruction *buffer, int length, const _PyBloomFilter *dependencies); - --static const _PyBloomFilter EMPTY_FILTER = { 0 }; -- --_PyOptimizerObject * --_Py_SetOptimizer(PyInterpreterState *interp, _PyOptimizerObject *optimizer) --{ -- if (optimizer == NULL) { -- optimizer = &_PyOptimizer_Default; -- } -- _PyOptimizerObject *old = interp->optimizer; -- if (old == NULL) { -- old = &_PyOptimizer_Default; -- } -- Py_INCREF(optimizer); -- interp->optimizer = optimizer; -- return old; --} -- --int --_Py_SetTier2Optimizer(_PyOptimizerObject *optimizer) --{ -- PyInterpreterState *interp = _PyInterpreterState_GET(); -- _PyOptimizerObject *old = _Py_SetOptimizer(interp, optimizer); -- Py_XDECREF(old); -- return old == NULL ? -1 : 0; --} -+static int -+uop_optimize(_PyInterpreterFrame *frame, _Py_CODEUNIT *instr, -+ _PyExecutorObject **exec_ptr, int curr_stackentries, -+ bool progress_needed); - - /* Returns 1 if optimized, 0 if not optimized, and -1 for an error. - * If optimized, *executor_ptr contains a new reference to the executor -@@ -164,8 +105,10 @@ - int - _PyOptimizer_Optimize( - _PyInterpreterFrame *frame, _Py_CODEUNIT *start, -- _PyStackRef *stack_pointer, _PyExecutorObject **executor_ptr, int chain_depth) -+ _PyExecutorObject **executor_ptr, int chain_depth) - { -+ _PyStackRef *stack_pointer = frame->stackpointer; -+ assert(_PyInterpreterState_GET()->jit); - // The first executor in a chain and the MAX_CHAIN_DEPTH'th executor *must* - // make progress in order to avoid infinite loops or excessively-long - // side-exit chains. We can only insert the executor into the bytecode if -@@ -174,12 +117,10 @@ - bool progress_needed = chain_depth == 0; - PyCodeObject *code = _PyFrame_GetCode(frame); - assert(PyCode_Check(code)); -- PyInterpreterState *interp = _PyInterpreterState_GET(); - if (progress_needed && !has_space_for_executor(code, start)) { - return 0; - } -- _PyOptimizerObject *opt = interp->optimizer; -- int err = opt->optimize(opt, frame, start, executor_ptr, (int)(stack_pointer - _PyFrame_Stackbase(frame)), progress_needed); -+ int err = uop_optimize(frame, start, executor_ptr, (int)(stack_pointer - _PyFrame_Stackbase(frame)), progress_needed); - if (err <= 0) { - return err; - } -@@ -251,13 +192,6 @@ - return PyLong_FromUnsignedLong(((_PyExecutorObject *)self)->vm_data.oparg); - } - --static PyMethodDef executor_methods[] = { -- { "is_valid", is_valid, METH_NOARGS, NULL }, -- { "get_opcode", get_opcode, METH_NOARGS, NULL }, -- { "get_oparg", get_oparg, METH_NOARGS, NULL }, -- { NULL, NULL }, --}; -- - ///////////////////// Experimental UOp Optimizer ///////////////////// - - static int executor_clear(_PyExecutorObject *executor); -@@ -622,8 +556,14 @@ - goto done; - } - assert(opcode != ENTER_EXECUTOR && opcode != EXTENDED_ARG); -- RESERVE_RAW(2, "_CHECK_VALIDITY_AND_SET_IP"); -- ADD_TO_TRACE(_CHECK_VALIDITY_AND_SET_IP, 0, (uintptr_t)instr, target); -+ if (OPCODE_HAS_NO_SAVE_IP(opcode)) { -+ RESERVE_RAW(2, "_CHECK_VALIDITY"); -+ ADD_TO_TRACE(_CHECK_VALIDITY, 0, 0, target); -+ } -+ else { -+ RESERVE_RAW(2, "_CHECK_VALIDITY_AND_SET_IP"); -+ ADD_TO_TRACE(_CHECK_VALIDITY_AND_SET_IP, 0, (uintptr_t)instr, target); -+ } - - /* Special case the first instruction, - * so that we can guarantee forward progress */ -@@ -687,6 +627,7 @@ - } - - case JUMP_BACKWARD: -+ case JUMP_BACKWARD_JIT: - ADD_TO_TRACE(_CHECK_PERIODIC, 0, 0, target); - _Py_FALLTHROUGH; - case JUMP_BACKWARD_NO_INTERRUPT: -@@ -771,7 +712,7 @@ - uint32_t next_inst = target + 1 + INLINE_CACHE_ENTRIES_FOR_ITER + (oparg > 255); - uint32_t jump_target = next_inst + oparg; - assert(_Py_GetBaseCodeUnit(code, jump_target).op.code == END_FOR); -- assert(_Py_GetBaseCodeUnit(code, jump_target+1).op.code == POP_TOP); -+ assert(_Py_GetBaseCodeUnit(code, jump_target+1).op.code == POP_ITER); - } - #endif - break; -@@ -812,13 +753,12 @@ - assert(i + 1 == nuops); - if (opcode == FOR_ITER_GEN || - opcode == LOAD_ATTR_PROPERTY || -- opcode == BINARY_SUBSCR_GETITEM || -+ opcode == BINARY_OP_SUBSCR_GETITEM || - opcode == SEND_GEN) - { - DPRINTF(2, "Bailing due to dynamic target\n"); -- ADD_TO_TRACE(uop, oparg, 0, target); -- ADD_TO_TRACE(_DYNAMIC_EXIT, 0, 0, 0); -- goto done; -+ OPT_STAT_INC(unknown_callee); -+ return 0; - } - assert(_PyOpcode_Deopt[opcode] == CALL || _PyOpcode_Deopt[opcode] == CALL_KW); - int func_version_offset = -@@ -884,9 +824,8 @@ - goto top; - } - DPRINTF(2, "Bail, new_code == NULL\n"); -- ADD_TO_TRACE(uop, oparg, 0, target); -- ADD_TO_TRACE(_DYNAMIC_EXIT, 0, 0, 0); -- goto done; -+ OPT_STAT_INC(unknown_callee); -+ return 0; - } - - if (uop == _BINARY_OP_INPLACE_ADD_UNICODE) { -@@ -973,7 +912,7 @@ - int exit_count = 0; - for (int i = 0; i < length; i++) { - int opcode = buffer[i].opcode; -- if (opcode == _EXIT_TRACE || opcode == _DYNAMIC_EXIT) { -+ if (opcode == _EXIT_TRACE) { - exit_count++; - } - } -@@ -1049,7 +988,6 @@ - current_error = next_spare; - current_error_target = target; - make_exit(&buffer[next_spare], _ERROR_POP_N, 0); -- buffer[next_spare].oparg = popped; - buffer[next_spare].operand0 = target; - next_spare++; - } -@@ -1179,12 +1117,6 @@ - dest->operand0 = (uint64_t)exit; - next_exit--; - } -- if (opcode == _DYNAMIC_EXIT) { -- _PyExitData *exit = &executor->exits[next_exit]; -- exit->target = 0; -- dest->operand0 = (uint64_t)exit; -- next_exit--; -- } - } - assert(next_exit == -1); - assert(dest == executor->trace); -@@ -1244,7 +1176,6 @@ - - static int - uop_optimize( -- _PyOptimizerObject *self, - _PyInterpreterFrame *frame, - _Py_CODEUNIT *instr, - _PyExecutorObject **exec_ptr, -@@ -1279,15 +1210,16 @@ - int oparg = buffer[pc].oparg; - if (_PyUop_Flags[opcode] & HAS_OPARG_AND_1_FLAG) { - buffer[pc].opcode = opcode + 1 + (oparg & 1); -+ assert(strncmp(_PyOpcode_uop_name[buffer[pc].opcode], _PyOpcode_uop_name[opcode], strlen(_PyOpcode_uop_name[opcode])) == 0); - } - else if (oparg < _PyUop_Replication[opcode]) { - buffer[pc].opcode = opcode + oparg + 1; -+ assert(strncmp(_PyOpcode_uop_name[buffer[pc].opcode], _PyOpcode_uop_name[opcode], strlen(_PyOpcode_uop_name[opcode])) == 0); - } - else if (is_terminator(&buffer[pc])) { - break; - } - assert(_PyOpcode_uop_name[buffer[pc].opcode]); -- assert(strncmp(_PyOpcode_uop_name[buffer[pc].opcode], _PyOpcode_uop_name[opcode], strlen(_PyOpcode_uop_name[opcode])) == 0); - } - OPT_HIST(effective_trace_length(buffer, length), optimized_trace_length_hist); - length = prepare_for_execution(buffer, length); -@@ -1301,121 +1233,6 @@ - return 1; - } - --static void --uop_opt_dealloc(PyObject *self) { -- PyObject_Free(self); --} -- --PyTypeObject _PyUOpOptimizer_Type = { -- PyVarObject_HEAD_INIT(&PyType_Type, 0) -- .tp_name = "uop_optimizer", -- .tp_basicsize = sizeof(_PyOptimizerObject), -- .tp_itemsize = 0, -- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, -- .tp_dealloc = uop_opt_dealloc, --}; -- --PyObject * --_PyOptimizer_NewUOpOptimizer(void) --{ -- _PyOptimizerObject *opt = PyObject_New(_PyOptimizerObject, &_PyUOpOptimizer_Type); -- if (opt == NULL) { -- return NULL; -- } -- opt->optimize = uop_optimize; -- return (PyObject *)opt; --} -- --static void --counter_dealloc(_PyExecutorObject *self) { -- /* The optimizer is the operand of the second uop. */ -- PyObject *opt = (PyObject *)self->trace[1].operand0; -- Py_DECREF(opt); -- uop_dealloc(self); --} -- --PyTypeObject _PyCounterExecutor_Type = { -- PyVarObject_HEAD_INIT(&PyType_Type, 0) -- .tp_name = "counting_executor", -- .tp_basicsize = offsetof(_PyExecutorObject, exits), -- .tp_itemsize = 1, -- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION | Py_TPFLAGS_HAVE_GC, -- .tp_dealloc = (destructor)counter_dealloc, -- .tp_methods = executor_methods, -- .tp_traverse = executor_traverse, -- .tp_clear = (inquiry)executor_clear, --}; -- --static int --counter_optimize( -- _PyOptimizerObject* self, -- _PyInterpreterFrame *frame, -- _Py_CODEUNIT *instr, -- _PyExecutorObject **exec_ptr, -- int Py_UNUSED(curr_stackentries), -- bool Py_UNUSED(progress_needed) --) --{ -- PyCodeObject *code = _PyFrame_GetCode(frame); -- int oparg = instr->op.arg; -- while (instr->op.code == EXTENDED_ARG) { -- instr++; -- oparg = (oparg << 8) | instr->op.arg; -- } -- if (instr->op.code != JUMP_BACKWARD) { -- /* Counter optimizer can only handle backward edges */ -- return 0; -- } -- _Py_CODEUNIT *target = instr + 1 + _PyOpcode_Caches[JUMP_BACKWARD] - oparg; -- _PyUOpInstruction buffer[4] = { -- { .opcode = _START_EXECUTOR, .jump_target = 3, .format=UOP_FORMAT_JUMP }, -- { .opcode = _LOAD_CONST_INLINE, .operand0 = (uintptr_t)self }, -- { .opcode = _INTERNAL_INCREMENT_OPT_COUNTER }, -- { .opcode = _EXIT_TRACE, .target = (uint32_t)(target - _PyCode_CODE(code)), .format=UOP_FORMAT_TARGET } -- }; -- _PyExecutorObject *executor = make_executor_from_uops(buffer, 4, &EMPTY_FILTER); -- if (executor == NULL) { -- return -1; -- } -- Py_INCREF(self); -- Py_SET_TYPE(executor, &_PyCounterExecutor_Type); -- *exec_ptr = executor; -- return 1; --} -- --static PyObject * --counter_get_counter(PyObject *self, PyObject *args) --{ -- return PyLong_FromLongLong(((_PyCounterOptimizerObject *)self)->count); --} -- --static PyMethodDef counter_optimizer_methods[] = { -- { "get_count", counter_get_counter, METH_NOARGS, NULL }, -- { NULL, NULL }, --}; -- --PyTypeObject _PyCounterOptimizer_Type = { -- PyVarObject_HEAD_INIT(&PyType_Type, 0) -- .tp_name = "Counter optimizer", -- .tp_basicsize = sizeof(_PyCounterOptimizerObject), -- .tp_itemsize = 0, -- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, -- .tp_methods = counter_optimizer_methods, -- .tp_dealloc = (destructor)PyObject_Free, --}; -- --PyObject * --_PyOptimizer_NewCounter(void) --{ -- _PyCounterOptimizerObject *opt = (_PyCounterOptimizerObject *)_PyObject_New(&_PyCounterOptimizer_Type); -- if (opt == NULL) { -- return NULL; -- } -- opt->base.optimize = counter_optimize; -- opt->count = 0; -- return (PyObject *)opt; --} -- - - /***************************************** - * Executor management -diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c -index 0ef15c630e9..6c0aadb87e6 100644 ---- a/Python/optimizer_analysis.c -+++ b/Python/optimizer_analysis.c -@@ -109,10 +109,14 @@ - return NULL; - } - if (_Py_IsImmortal(res)) { -- inst->opcode = (inst->oparg & 1) ? _LOAD_CONST_INLINE_BORROW_WITH_NULL : _LOAD_CONST_INLINE_BORROW; -+ inst->opcode = _LOAD_CONST_INLINE_BORROW; - } - else { -- inst->opcode = (inst->oparg & 1) ? _LOAD_CONST_INLINE_WITH_NULL : _LOAD_CONST_INLINE; -+ inst->opcode = _LOAD_CONST_INLINE; -+ } -+ if (inst->oparg & 1) { -+ assert(inst[1].opcode == _PUSH_NULL_CONDITIONAL); -+ assert(inst[1].oparg & 1); - } - inst->operand0 = (uint64_t)res; - return res; -@@ -368,13 +372,17 @@ - #define sym_truthiness _Py_uop_sym_truthiness - #define frame_new _Py_uop_frame_new - #define frame_pop _Py_uop_frame_pop -+#define sym_new_tuple _Py_uop_sym_new_tuple -+#define sym_tuple_getitem _Py_uop_sym_tuple_getitem -+#define sym_tuple_length _Py_uop_sym_tuple_length -+#define sym_is_immortal _Py_uop_sym_is_immortal - - static int - optimize_to_bool( - _PyUOpInstruction *this_instr, -- _Py_UOpsContext *ctx, -- _Py_UopsSymbol *value, -- _Py_UopsSymbol **result_ptr) -+ JitOptContext *ctx, -+ JitOptSymbol *value, -+ JitOptSymbol **result_ptr) - { - if (sym_matches_type(value, &PyBool_Type)) { - REPLACE_OP(this_instr, _NOP, 0, 0); -@@ -460,8 +468,8 @@ - ) - { - -- _Py_UOpsContext context; -- _Py_UOpsContext *ctx = &context; -+ JitOptContext context; -+ JitOptContext *ctx = &context; - uint32_t opcode = UINT16_MAX; - int curr_space = 0; - int max_space = 0; -@@ -486,7 +494,7 @@ - - int oparg = this_instr->oparg; - opcode = this_instr->opcode; -- _Py_UopsSymbol **stack_pointer = ctx->frame->stack_pointer; -+ JitOptSymbol **stack_pointer = ctx->frame->stack_pointer; - - #ifdef Py_DEBUG - if (get_lltrace() >= 3) { -@@ -608,7 +616,6 @@ - } - case _JUMP_TO_TOP: - case _EXIT_TRACE: -- case _DYNAMIC_EXIT: - return pc + 1; - default: - { -diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c -index 0b8aff02367..41eb59c931a 100644 ---- a/Python/optimizer_bytecodes.c -+++ b/Python/optimizer_bytecodes.c -@@ -6,8 +6,6 @@ - - #define op(name, ...) /* NAME is ignored */ - --typedef struct _Py_UopsSymbol _Py_UopsSymbol; --typedef struct _Py_UOpsContext _Py_UOpsContext; - typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame; - - /* Shortened forms for convenience */ -@@ -32,13 +30,17 @@ - #define sym_is_bottom _Py_uop_sym_is_bottom - #define frame_new _Py_uop_frame_new - #define frame_pop _Py_uop_frame_pop -+#define sym_new_tuple _Py_uop_sym_new_tuple -+#define sym_tuple_getitem _Py_uop_sym_tuple_getitem -+#define sym_tuple_length _Py_uop_sym_tuple_length -+#define sym_is_immortal _Py_uop_sym_is_immortal - - extern int - optimize_to_bool( - _PyUOpInstruction *this_instr, -- _Py_UOpsContext *ctx, -- _Py_UopsSymbol *value, -- _Py_UopsSymbol **result_ptr); -+ JitOptContext *ctx, -+ JitOptSymbol *value, -+ JitOptSymbol **result_ptr); - - extern void - eliminate_pop_guard(_PyUOpInstruction *this_instr, bool exit); -@@ -50,17 +52,17 @@ - - PyCodeObject *co; - int oparg; -- _Py_UopsSymbol *flag; -- _Py_UopsSymbol *left; -- _Py_UopsSymbol *right; -- _Py_UopsSymbol *value; -- _Py_UopsSymbol *res; -- _Py_UopsSymbol *iter; -- _Py_UopsSymbol *top; -- _Py_UopsSymbol *bottom; -+ JitOptSymbol *flag; -+ JitOptSymbol *left; -+ JitOptSymbol *right; -+ JitOptSymbol *value; -+ JitOptSymbol *res; -+ JitOptSymbol *iter; -+ JitOptSymbol *top; -+ JitOptSymbol *bottom; - _Py_UOpsAbstractFrame *frame; - _Py_UOpsAbstractFrame *new_frame; -- _Py_UOpsContext *ctx; -+ JitOptContext *ctx; - _PyUOpInstruction *this_instr; - _PyBloomFilter *dependencies; - int modified; -@@ -85,7 +87,7 @@ - - op(_LOAD_FAST_AND_CLEAR, (-- value)) { - value = GETLOCAL(oparg); -- _Py_UopsSymbol *temp = sym_new_null(ctx); -+ JitOptSymbol *temp = sym_new_null(ctx); - GETLOCAL(oparg) = temp; - } - -@@ -167,23 +169,56 @@ - } - - op(_BINARY_OP, (left, right -- res)) { -- PyTypeObject *ltype = sym_get_type(left); -- PyTypeObject *rtype = sym_get_type(right); -- if (ltype != NULL && (ltype == &PyLong_Type || ltype == &PyFloat_Type) && -- rtype != NULL && (rtype == &PyLong_Type || rtype == &PyFloat_Type)) -- { -- if (oparg != NB_TRUE_DIVIDE && oparg != NB_INPLACE_TRUE_DIVIDE && -- ltype == &PyLong_Type && rtype == &PyLong_Type) { -- /* If both inputs are ints and the op is not division the result is an int */ -- res = sym_new_type(ctx, &PyLong_Type); -+ bool lhs_int = sym_matches_type(left, &PyLong_Type); -+ bool rhs_int = sym_matches_type(right, &PyLong_Type); -+ bool lhs_float = sym_matches_type(left, &PyFloat_Type); -+ bool rhs_float = sym_matches_type(right, &PyFloat_Type); -+ if (!((lhs_int || lhs_float) && (rhs_int || rhs_float))) { -+ // There's something other than an int or float involved: -+ res = sym_new_unknown(ctx); -+ } -+ else if (oparg == NB_POWER || oparg == NB_INPLACE_POWER) { -+ // This one's fun... the *type* of the result depends on the -+ // *values* being exponentiated. However, exponents with one -+ // constant part are reasonably common, so it's probably worth -+ // trying to infer some simple cases: -+ // - A: 1 ** 1 -> 1 (int ** int -> int) -+ // - B: 1 ** -1 -> 1.0 (int ** int -> float) -+ // - C: 1.0 ** 1 -> 1.0 (float ** int -> float) -+ // - D: 1 ** 1.0 -> 1.0 (int ** float -> float) -+ // - E: -1 ** 0.5 ~> 1j (int ** float -> complex) -+ // - F: 1.0 ** 1.0 -> 1.0 (float ** float -> float) -+ // - G: -1.0 ** 0.5 ~> 1j (float ** float -> complex) -+ if (rhs_float) { -+ // Case D, E, F, or G... can't know without the sign of the LHS -+ // or whether the RHS is whole, which isn't worth the effort: -+ res = sym_new_unknown(ctx); - } -- else { -- /* For any other op combining ints/floats the result is a float */ -+ else if (lhs_float) { -+ // Case C: -+ res = sym_new_type(ctx, &PyFloat_Type); -+ } -+ else if (!sym_is_const(right)) { -+ // Case A or B... can't know without the sign of the RHS: -+ res = sym_new_unknown(ctx); -+ } -+ else if (_PyLong_IsNegative((PyLongObject *)sym_get_const(right))) { -+ // Case B: - res = sym_new_type(ctx, &PyFloat_Type); - } -+ else { -+ // Case A: -+ res = sym_new_type(ctx, &PyLong_Type); -+ } -+ } -+ else if (oparg == NB_TRUE_DIVIDE || oparg == NB_INPLACE_TRUE_DIVIDE) { -+ res = sym_new_type(ctx, &PyFloat_Type); -+ } -+ else if (lhs_int && rhs_int) { -+ res = sym_new_type(ctx, &PyLong_Type); - } - else { -- res = sym_new_unknown(ctx); -+ res = sym_new_type(ctx, &PyFloat_Type); - } - } - -@@ -332,7 +367,7 @@ - } - - op(_BINARY_OP_INPLACE_ADD_UNICODE, (left, right -- )) { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - if (sym_is_const(left) && sym_is_const(right) && - sym_matches_type(left, &PyUnicode_Type) && sym_matches_type(right, &PyUnicode_Type)) { - PyObject *temp = PyUnicode_Concat(sym_get_const(left), sym_get_const(right)); -@@ -349,9 +384,7 @@ - GETLOCAL(this_instr->operand0) = res; - } - -- op(_BINARY_SUBSCR_INIT_CALL, (container, sub -- new_frame: _Py_UOpsAbstractFrame *)) { -- (void)container; -- (void)sub; -+ op(_BINARY_OP_SUBSCR_INIT_CALL, (container, sub, getitem -- new_frame: _Py_UOpsAbstractFrame *)) { - new_frame = NULL; - ctx->done = true; - } -@@ -398,8 +431,6 @@ - } - - op(_COMPARE_OP, (left, right -- res)) { -- (void)left; -- (void)right; - if (oparg & 16) { - res = sym_new_type(ctx, &PyBool_Type); - } -@@ -409,32 +440,22 @@ - } - - op(_COMPARE_OP_INT, (left, right -- res)) { -- (void)left; -- (void)right; - res = sym_new_type(ctx, &PyBool_Type); - } - - op(_COMPARE_OP_FLOAT, (left, right -- res)) { -- (void)left; -- (void)right; - res = sym_new_type(ctx, &PyBool_Type); - } - - op(_COMPARE_OP_STR, (left, right -- res)) { -- (void)left; -- (void)right; - res = sym_new_type(ctx, &PyBool_Type); - } - - op(_IS_OP, (left, right -- res)) { -- (void)left; -- (void)right; - res = sym_new_type(ctx, &PyBool_Type); - } - - op(_CONTAINS_OP, (left, right -- res)) { -- (void)left; -- (void)right; - res = sym_new_type(ctx, &PyBool_Type); - } - -@@ -445,6 +466,13 @@ - value = sym_new_const(ctx, val); - } - -+ op(_LOAD_CONST_MORTAL, (-- value)) { -+ PyObject *val = PyTuple_GET_ITEM(co->co_consts, this_instr->oparg); -+ int opcode = _Py_IsImmortal(val) ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE; -+ REPLACE_OP(this_instr, opcode, 0, (uintptr_t)val); -+ value = sym_new_const(ctx, val); -+ } -+ - op(_LOAD_CONST_IMMORTAL, (-- value)) { - PyObject *val = PyTuple_GET_ITEM(co->co_consts, this_instr->oparg); - REPLACE_OP(this_instr, _LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val); -@@ -464,32 +492,21 @@ - value = sym_new_const(ctx, ptr); - } - -- op(_LOAD_CONST_INLINE_WITH_NULL, (ptr/4 -- value, null)) { -- value = sym_new_const(ctx, ptr); -- null = sym_new_null(ctx); -- } -- -- op(_LOAD_CONST_INLINE_BORROW_WITH_NULL, (ptr/4 -- value, null)) { -- value = sym_new_const(ctx, ptr); -- null = sym_new_null(ctx); -- } -- - op(_COPY, (bottom, unused[oparg-1] -- bottom, unused[oparg-1], top)) { - assert(oparg > 0); - top = bottom; - } - -- op(_SWAP, (bottom_in, unused[oparg-2], top_in -- -- top_out, unused[oparg-2], bottom_out)) { -- bottom_out = bottom_in; -- top_out = top_in; -+ op(_SWAP, (bottom[1], unused[oparg-2], top[1] -- bottom[1], unused[oparg-2], top[1])) { -+ JitOptSymbol *temp = bottom[0]; -+ bottom[0] = top[0]; -+ top[0] = temp; -+ assert(oparg >= 2); - } - -- op(_LOAD_ATTR_INSTANCE_VALUE, (offset/1, owner -- attr, null if (oparg & 1))) { -+ op(_LOAD_ATTR_INSTANCE_VALUE, (offset/1, owner -- attr)) { - attr = sym_new_not_null(ctx); -- null = sym_new_null(ctx); - (void)offset; -- (void)owner; - } - - op(_CHECK_ATTR_MODULE_PUSH_KEYS, (dict_version/2, owner -- owner, mod_keys)) { -@@ -510,15 +527,22 @@ - } - } - -- op(_LOAD_ATTR, (owner -- attr, self_or_null if (oparg & 1))) { -+ op (_PUSH_NULL_CONDITIONAL, ( -- null if (oparg & 1))) { -+ int opcode = (oparg & 1) ? _PUSH_NULL : _NOP; -+ REPLACE_OP(this_instr, opcode, 0, 0); -+ null = sym_new_null(ctx); -+ } -+ -+ op(_LOAD_ATTR, (owner -- attr, self_or_null[oparg&1])) { - (void)owner; - attr = sym_new_not_null(ctx); -- self_or_null = sym_new_unknown(ctx); -+ if (oparg &1) { -+ self_or_null[0] = sym_new_unknown(ctx); -+ } - } - -- op(_LOAD_ATTR_MODULE_FROM_KEYS, (index/1, owner, mod_keys -- attr, null if (oparg & 1))) { -+ op(_LOAD_ATTR_MODULE_FROM_KEYS, (index/1, owner, mod_keys -- attr)) { - (void)index; -- null = sym_new_null(ctx); - attr = NULL; - if (this_instr[-1].opcode == _NOP) { - // Preceding _CHECK_ATTR_MODULE_PUSH_KEYS was removed: mod is const and dict is watched. -@@ -541,40 +565,38 @@ - } - } - -- op(_LOAD_ATTR_WITH_HINT, (hint/1, owner -- attr, null if (oparg & 1))) { -+ op(_CHECK_ATTR_WITH_HINT, (owner -- owner, dict)) { -+ dict = sym_new_not_null(ctx); -+ } -+ -+ op(_LOAD_ATTR_WITH_HINT, (hint/1, owner, dict -- attr)) { - attr = sym_new_not_null(ctx); -- null = sym_new_null(ctx); - (void)hint; -- (void)owner; - } - -- op(_LOAD_ATTR_SLOT, (index/1, owner -- attr, null if (oparg & 1))) { -+ op(_LOAD_ATTR_SLOT, (index/1, owner -- attr)) { - attr = sym_new_not_null(ctx); -- null = sym_new_null(ctx); - (void)index; -- (void)owner; - } - -- op(_LOAD_ATTR_CLASS, (descr/4, owner -- attr, null if (oparg & 1))) { -+ op(_LOAD_ATTR_CLASS, (descr/4, owner -- attr)) { - attr = sym_new_not_null(ctx); -- null = sym_new_null(ctx); - (void)descr; -- (void)owner; - } - -- op(_LOAD_ATTR_METHOD_WITH_VALUES, (descr/4, owner -- attr, self if (1))) { -+ op(_LOAD_ATTR_METHOD_WITH_VALUES, (descr/4, owner -- attr, self)) { - (void)descr; - attr = sym_new_not_null(ctx); - self = owner; - } - -- op(_LOAD_ATTR_METHOD_NO_DICT, (descr/4, owner -- attr, self if (1))) { -+ op(_LOAD_ATTR_METHOD_NO_DICT, (descr/4, owner -- attr, self)) { - (void)descr; - attr = sym_new_not_null(ctx); - self = owner; - } - -- op(_LOAD_ATTR_METHOD_LAZY_DICT, (descr/4, owner -- attr, self if (1))) { -+ op(_LOAD_ATTR_METHOD_LAZY_DICT, (descr/4, owner -- attr, self)) { - (void)descr; - attr = sym_new_not_null(ctx); - self = owner; -@@ -582,19 +604,16 @@ - - op(_LOAD_ATTR_PROPERTY_FRAME, (fget/4, owner -- new_frame: _Py_UOpsAbstractFrame *)) { - (void)fget; -- (void)owner; - new_frame = NULL; - ctx->done = true; - } - -- op(_INIT_CALL_BOUND_METHOD_EXACT_ARGS, (callable, unused, unused[oparg] -- func, self, unused[oparg])) { -- (void)callable; -- func = sym_new_not_null(ctx); -- self = sym_new_not_null(ctx); -+ op(_INIT_CALL_BOUND_METHOD_EXACT_ARGS, (callable[1], self_or_null[1], unused[oparg] -- callable[1], self_or_null[1], unused[oparg])) { -+ callable[0] = sym_new_not_null(ctx); -+ self_or_null[0] = sym_new_not_null(ctx); - } - - op(_CHECK_FUNCTION_VERSION, (func_version/2, callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) { -- (void)self_or_null; - if (sym_is_const(callable) && sym_matches_type(callable, &PyFunction_Type)) { - assert(PyFunction_Check(sym_get_const(callable))); - REPLACE_OP(this_instr, _CHECK_FUNCTION_VERSION_INLINE, 0, func_version); -@@ -614,7 +633,6 @@ - } - } - } -- (void)self_or_null; - } - - op(_CHECK_CALL_BOUND_METHOD_EXACT_ARGS, (callable, null, unused[oparg] -- callable, null, unused[oparg])) { -@@ -624,7 +642,6 @@ - - op(_INIT_CALL_PY_EXACT_ARGS, (callable, self_or_null, args[oparg] -- new_frame: _Py_UOpsAbstractFrame *)) { - int argcount = oparg; -- (void)callable; - - PyCodeObject *co = NULL; - assert((this_instr + 2)->opcode == _PUSH_FRAME); -@@ -652,16 +669,12 @@ - } - - op(_MAYBE_EXPAND_METHOD, (callable, self_or_null, args[oparg] -- func, maybe_self, args[oparg])) { -- (void)callable; -- (void)self_or_null; - (void)args; - func = sym_new_not_null(ctx); - maybe_self = sym_new_not_null(ctx); - } - - op(_PY_FRAME_GENERAL, (callable, self_or_null, args[oparg] -- new_frame: _Py_UOpsAbstractFrame *)) { -- (void)(self_or_null); -- (void)(callable); - PyCodeObject *co = NULL; - assert((this_instr + 2)->opcode == _PUSH_FRAME); - co = get_code_with_logging((this_instr + 2)); -@@ -674,27 +687,18 @@ - } - - op(_PY_FRAME_KW, (callable, self_or_null, args[oparg], kwnames -- new_frame: _Py_UOpsAbstractFrame *)) { -- (void)callable; -- (void)self_or_null; -- (void)args; -- (void)kwnames; - new_frame = NULL; - ctx->done = true; - } - - op(_CHECK_AND_ALLOCATE_OBJECT, (type_version/2, callable, null, args[oparg] -- self, init, args[oparg])) { - (void)type_version; -- (void)callable; -- (void)null; - (void)args; - self = sym_new_not_null(ctx); - init = sym_new_not_null(ctx); - } - - op(_CREATE_INIT_FRAME, (self, init, args[oparg] -- init_frame: _Py_UOpsAbstractFrame *)) { -- (void)self; -- (void)init; -- (void)args; - init_frame = NULL; - ctx->done = true; - } -@@ -763,7 +767,7 @@ - corresponding_check_stack = this_instr; - } - -- op (_CHECK_STACK_SPACE_OPERAND, ( -- )) { -+ op (_CHECK_STACK_SPACE_OPERAND, (framesize/2 -- )) { - (void)framesize; - /* We should never see _CHECK_STACK_SPACE_OPERANDs. - * They are only created at the end of this pass. */ -@@ -805,7 +809,6 @@ - - op(_UNPACK_SEQUENCE, (seq -- values[oparg])) { - /* This has to be done manually */ -- (void)seq; - for (int i = 0; i < oparg; i++) { - values[i] = sym_new_unknown(ctx); - } -@@ -813,7 +816,6 @@ - - op(_UNPACK_EX, (seq -- values[oparg & 0xFF], unused, unused[oparg >> 8])) { - /* This has to be done manually */ -- (void)seq; - int totalargs = (oparg & 0xFF) + (oparg >> 8) + 1; - for (int i = 0; i < totalargs; i++) { - values[i] = sym_new_unknown(ctx); -@@ -822,7 +824,6 @@ - - op(_ITER_NEXT_RANGE, (iter -- iter, next)) { - next = sym_new_type(ctx, &PyLong_Type); -- (void)iter; - } - - op(_GUARD_IS_TRUE_POP, (flag -- )) { -@@ -874,7 +875,6 @@ - } - - op(_LOAD_SPECIAL, (owner -- attr, self_or_null)) { -- (void)owner; - attr = sym_new_not_null(ctx); - self_or_null = sym_new_unknown(ctx); - } -@@ -898,6 +898,26 @@ - (void)version; - } - -+ op(_REPLACE_WITH_TRUE, (value -- res)) { -+ res = sym_new_const(ctx, Py_True); -+ } -+ -+ op(_BUILD_TUPLE, (values[oparg] -- tup)) { -+ tup = sym_new_tuple(ctx, oparg, values); -+ } -+ -+ op(_UNPACK_SEQUENCE_TWO_TUPLE, (seq -- val1, val0)) { -+ val0 = sym_tuple_getitem(ctx, seq, 0); -+ val1 = sym_tuple_getitem(ctx, seq, 1); -+ } -+ -+ op(_UNPACK_SEQUENCE_TUPLE, (seq -- values[oparg])) { -+ for (int i = 0; i < oparg; i++) { -+ values[i] = sym_tuple_getitem(ctx, seq, i); -+ } -+ } -+ -+ - // END BYTECODES // - - } -diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h -index f4fbe8c8aa0..fd8486785ed 100644 ---- a/Python/optimizer_cases.c.h -+++ b/Python/optimizer_cases.c.h -@@ -26,7 +26,7 @@ - /* _MONITOR_RESUME is not a viable micro-op for tier 2 */ - - case _LOAD_FAST_CHECK: { -- _Py_UopsSymbol *value; -+ JitOptSymbol *value; - value = GETLOCAL(oparg); - // We guarantee this will error - just bail and don't optimize it. - if (sym_is_null(value)) { -@@ -39,7 +39,7 @@ - } - - case _LOAD_FAST: { -- _Py_UopsSymbol *value; -+ JitOptSymbol *value; - value = GETLOCAL(oparg); - stack_pointer[0] = value; - stack_pointer += 1; -@@ -48,9 +48,9 @@ - } - - case _LOAD_FAST_AND_CLEAR: { -- _Py_UopsSymbol *value; -+ JitOptSymbol *value; - value = GETLOCAL(oparg); -- _Py_UopsSymbol *temp = sym_new_null(ctx); -+ JitOptSymbol *temp = sym_new_null(ctx); - GETLOCAL(oparg) = temp; - stack_pointer[0] = value; - stack_pointer += 1; -@@ -58,8 +58,10 @@ - break; - } - -- case _LOAD_CONST: { -- _Py_UopsSymbol *value; -+ /* _LOAD_CONST is not a viable micro-op for tier 2 */ -+ -+ case _LOAD_CONST_MORTAL: { -+ JitOptSymbol *value; - PyObject *val = PyTuple_GET_ITEM(co->co_consts, this_instr->oparg); - int opcode = _Py_IsImmortal(val) ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE; - REPLACE_OP(this_instr, opcode, 0, (uintptr_t)val); -@@ -71,7 +73,7 @@ - } - - case _LOAD_CONST_IMMORTAL: { -- _Py_UopsSymbol *value; -+ JitOptSymbol *value; - PyObject *val = PyTuple_GET_ITEM(co->co_consts, this_instr->oparg); - REPLACE_OP(this_instr, _LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val); - value = sym_new_const(ctx, val); -@@ -82,7 +84,7 @@ - } - - case _LOAD_SMALL_INT: { -- _Py_UopsSymbol *value; -+ JitOptSymbol *value; - PyObject *val = PyLong_FromLong(this_instr->oparg); - value = sym_new_const(ctx, val); - stack_pointer[0] = value; -@@ -92,7 +94,7 @@ - } - - case _STORE_FAST: { -- _Py_UopsSymbol *value; -+ JitOptSymbol *value; - value = stack_pointer[-1]; - GETLOCAL(oparg) = value; - stack_pointer += -1; -@@ -107,7 +109,7 @@ - } - - case _PUSH_NULL: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_null(ctx); - stack_pointer[0] = res; - stack_pointer += 1; -@@ -115,8 +117,14 @@ - break; - } - -+ case _END_FOR: { -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); -+ break; -+ } -+ - case _END_SEND: { -- _Py_UopsSymbol *val; -+ JitOptSymbol *val; - val = sym_new_not_null(ctx); - stack_pointer[-2] = val; - stack_pointer += -1; -@@ -125,22 +133,22 @@ - } - - case _UNARY_NEGATIVE: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-1] = res; - break; - } - - case _UNARY_NOT: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-1] = res; - break; - } - - case _TO_BOOL: { -- _Py_UopsSymbol *value; -- _Py_UopsSymbol *res; -+ JitOptSymbol *value; -+ JitOptSymbol *res; - value = stack_pointer[-1]; - if (!optimize_to_bool(this_instr, ctx, value, &res)) { - res = sym_new_type(ctx, &PyBool_Type); -@@ -150,8 +158,8 @@ - } - - case _TO_BOOL_BOOL: { -- _Py_UopsSymbol *value; -- _Py_UopsSymbol *res; -+ JitOptSymbol *value; -+ JitOptSymbol *res; - value = stack_pointer[-1]; - if (!optimize_to_bool(this_instr, ctx, value, &res)) { - sym_set_type(value, &PyBool_Type); -@@ -162,8 +170,8 @@ - } - - case _TO_BOOL_INT: { -- _Py_UopsSymbol *value; -- _Py_UopsSymbol *res; -+ JitOptSymbol *value; -+ JitOptSymbol *res; - value = stack_pointer[-1]; - if (!optimize_to_bool(this_instr, ctx, value, &res)) { - sym_set_type(value, &PyLong_Type); -@@ -174,8 +182,8 @@ - } - - case _TO_BOOL_LIST: { -- _Py_UopsSymbol *value; -- _Py_UopsSymbol *res; -+ JitOptSymbol *value; -+ JitOptSymbol *res; - value = stack_pointer[-1]; - if (!optimize_to_bool(this_instr, ctx, value, &res)) { - sym_set_type(value, &PyList_Type); -@@ -186,8 +194,8 @@ - } - - case _TO_BOOL_NONE: { -- _Py_UopsSymbol *value; -- _Py_UopsSymbol *res; -+ JitOptSymbol *value; -+ JitOptSymbol *res; - value = stack_pointer[-1]; - if (!optimize_to_bool(this_instr, ctx, value, &res)) { - sym_set_const(value, Py_None); -@@ -198,8 +206,8 @@ - } - - case _TO_BOOL_STR: { -- _Py_UopsSymbol *value; -- _Py_UopsSymbol *res; -+ JitOptSymbol *value; -+ JitOptSymbol *res; - value = stack_pointer[-1]; - if (!optimize_to_bool(this_instr, ctx, value, &res)) { - res = sym_new_type(ctx, &PyBool_Type); -@@ -210,22 +218,22 @@ - } - - case _REPLACE_WITH_TRUE: { -- _Py_UopsSymbol *res; -- res = sym_new_not_null(ctx); -+ JitOptSymbol *res; -+ res = sym_new_const(ctx, Py_True); - stack_pointer[-1] = res; - break; - } - - case _UNARY_INVERT: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-1] = res; - break; - } - - case _GUARD_BOTH_INT: { -- _Py_UopsSymbol *right; -- _Py_UopsSymbol *left; -+ JitOptSymbol *right; -+ JitOptSymbol *left; - right = stack_pointer[-1]; - left = stack_pointer[-2]; - if (sym_matches_type(left, &PyLong_Type)) { -@@ -255,9 +263,9 @@ - } - - case _BINARY_OP_MULTIPLY_INT: { -- _Py_UopsSymbol *right; -- _Py_UopsSymbol *left; -- _Py_UopsSymbol *res; -+ JitOptSymbol *right; -+ JitOptSymbol *left; -+ JitOptSymbol *res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; - if (sym_is_const(left) && sym_is_const(right) && -@@ -271,23 +279,26 @@ - goto error; - } - res = sym_new_const(ctx, temp); -+ stack_pointer[-2] = res; -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); - Py_DECREF(temp); - // TODO gh-115506: - // replace opcode with constant propagated one and add tests! - } - else { - res = sym_new_type(ctx, &PyLong_Type); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); - } -- stack_pointer[-2] = res; -- stack_pointer += -1; -- assert(WITHIN_STACK_BOUNDS()); -+ stack_pointer[-1] = res; - break; - } - - case _BINARY_OP_ADD_INT: { -- _Py_UopsSymbol *right; -- _Py_UopsSymbol *left; -- _Py_UopsSymbol *res; -+ JitOptSymbol *right; -+ JitOptSymbol *left; -+ JitOptSymbol *res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; - if (sym_is_const(left) && sym_is_const(right) && -@@ -301,23 +312,26 @@ - goto error; - } - res = sym_new_const(ctx, temp); -+ stack_pointer[-2] = res; -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); - Py_DECREF(temp); - // TODO gh-115506: - // replace opcode with constant propagated one and add tests! - } - else { - res = sym_new_type(ctx, &PyLong_Type); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); - } -- stack_pointer[-2] = res; -- stack_pointer += -1; -- assert(WITHIN_STACK_BOUNDS()); -+ stack_pointer[-1] = res; - break; - } - - case _BINARY_OP_SUBTRACT_INT: { -- _Py_UopsSymbol *right; -- _Py_UopsSymbol *left; -- _Py_UopsSymbol *res; -+ JitOptSymbol *right; -+ JitOptSymbol *left; -+ JitOptSymbol *res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; - if (sym_is_const(left) && sym_is_const(right) && -@@ -331,22 +345,25 @@ - goto error; - } - res = sym_new_const(ctx, temp); -+ stack_pointer[-2] = res; -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); - Py_DECREF(temp); - // TODO gh-115506: - // replace opcode with constant propagated one and add tests! - } - else { - res = sym_new_type(ctx, &PyLong_Type); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); - } -- stack_pointer[-2] = res; -- stack_pointer += -1; -- assert(WITHIN_STACK_BOUNDS()); -+ stack_pointer[-1] = res; - break; - } - - case _GUARD_BOTH_FLOAT: { -- _Py_UopsSymbol *right; -- _Py_UopsSymbol *left; -+ JitOptSymbol *right; -+ JitOptSymbol *left; - right = stack_pointer[-1]; - left = stack_pointer[-2]; - if (sym_matches_type(left, &PyFloat_Type)) { -@@ -376,9 +393,9 @@ - } - - case _BINARY_OP_MULTIPLY_FLOAT: { -- _Py_UopsSymbol *right; -- _Py_UopsSymbol *left; -- _Py_UopsSymbol *res; -+ JitOptSymbol *right; -+ JitOptSymbol *left; -+ JitOptSymbol *res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; - if (sym_is_const(left) && sym_is_const(right) && -@@ -393,23 +410,26 @@ - goto error; - } - res = sym_new_const(ctx, temp); -+ stack_pointer[-2] = res; -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); - Py_DECREF(temp); - // TODO gh-115506: - // replace opcode with constant propagated one and update tests! - } - else { - res = sym_new_type(ctx, &PyFloat_Type); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); - } -- stack_pointer[-2] = res; -- stack_pointer += -1; -- assert(WITHIN_STACK_BOUNDS()); -+ stack_pointer[-1] = res; - break; - } - - case _BINARY_OP_ADD_FLOAT: { -- _Py_UopsSymbol *right; -- _Py_UopsSymbol *left; -- _Py_UopsSymbol *res; -+ JitOptSymbol *right; -+ JitOptSymbol *left; -+ JitOptSymbol *res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; - if (sym_is_const(left) && sym_is_const(right) && -@@ -424,23 +444,26 @@ - goto error; - } - res = sym_new_const(ctx, temp); -+ stack_pointer[-2] = res; -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); - Py_DECREF(temp); - // TODO gh-115506: - // replace opcode with constant propagated one and update tests! - } - else { - res = sym_new_type(ctx, &PyFloat_Type); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); - } -- stack_pointer[-2] = res; -- stack_pointer += -1; -- assert(WITHIN_STACK_BOUNDS()); -+ stack_pointer[-1] = res; - break; - } - - case _BINARY_OP_SUBTRACT_FLOAT: { -- _Py_UopsSymbol *right; -- _Py_UopsSymbol *left; -- _Py_UopsSymbol *res; -+ JitOptSymbol *right; -+ JitOptSymbol *left; -+ JitOptSymbol *res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; - if (sym_is_const(left) && sym_is_const(right) && -@@ -455,22 +478,25 @@ - goto error; - } - res = sym_new_const(ctx, temp); -+ stack_pointer[-2] = res; -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); - Py_DECREF(temp); - // TODO gh-115506: - // replace opcode with constant propagated one and update tests! - } - else { - res = sym_new_type(ctx, &PyFloat_Type); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); - } -- stack_pointer[-2] = res; -- stack_pointer += -1; -- assert(WITHIN_STACK_BOUNDS()); -+ stack_pointer[-1] = res; - break; - } - - case _GUARD_BOTH_UNICODE: { -- _Py_UopsSymbol *right; -- _Py_UopsSymbol *left; -+ JitOptSymbol *right; -+ JitOptSymbol *left; - right = stack_pointer[-1]; - left = stack_pointer[-2]; - if (sym_matches_type(left, &PyUnicode_Type) && -@@ -483,9 +509,9 @@ - } - - case _BINARY_OP_ADD_UNICODE: { -- _Py_UopsSymbol *right; -- _Py_UopsSymbol *left; -- _Py_UopsSymbol *res; -+ JitOptSymbol *right; -+ JitOptSymbol *left; -+ JitOptSymbol *res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; - if (sym_is_const(left) && sym_is_const(right) && -@@ -495,23 +521,26 @@ - goto error; - } - res = sym_new_const(ctx, temp); -+ stack_pointer[-2] = res; -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); - Py_DECREF(temp); - } - else { - res = sym_new_type(ctx, &PyUnicode_Type); -+ stack_pointer += -1; -+ assert(WITHIN_STACK_BOUNDS()); - } -- stack_pointer[-2] = res; -- stack_pointer += -1; -- assert(WITHIN_STACK_BOUNDS()); -+ stack_pointer[-1] = res; - break; - } - - case _BINARY_OP_INPLACE_ADD_UNICODE: { -- _Py_UopsSymbol *right; -- _Py_UopsSymbol *left; -+ JitOptSymbol *right; -+ JitOptSymbol *left; - right = stack_pointer[-1]; - left = stack_pointer[-2]; -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - if (sym_is_const(left) && sym_is_const(right) && - sym_matches_type(left, &PyUnicode_Type) && sym_matches_type(right, &PyUnicode_Type)) { - PyObject *temp = PyUnicode_Concat(sym_get_const(left), sym_get_const(right)); -@@ -519,20 +548,26 @@ - goto error; - } - res = sym_new_const(ctx, temp); -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); - Py_DECREF(temp); - } - else { - res = sym_new_type(ctx, &PyUnicode_Type); -+ stack_pointer += -2; -+ assert(WITHIN_STACK_BOUNDS()); - } - // _STORE_FAST: - GETLOCAL(this_instr->operand0) = res; -- stack_pointer += -2; -- assert(WITHIN_STACK_BOUNDS()); - break; - } - -- case _BINARY_SUBSCR: { -- _Py_UopsSymbol *res; -+ case _GUARD_BINARY_OP_EXTEND: { -+ break; -+ } -+ -+ case _BINARY_OP_EXTEND: { -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -541,7 +576,7 @@ - } - - case _BINARY_SLICE: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-3] = res; - stack_pointer += -2; -@@ -555,8 +590,8 @@ - break; - } - -- case _BINARY_SUBSCR_LIST_INT: { -- _Py_UopsSymbol *res; -+ case _BINARY_OP_SUBSCR_LIST_INT: { -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -564,8 +599,8 @@ - break; - } - -- case _BINARY_SUBSCR_STR_INT: { -- _Py_UopsSymbol *res; -+ case _BINARY_OP_SUBSCR_STR_INT: { -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -573,8 +608,8 @@ - break; - } - -- case _BINARY_SUBSCR_TUPLE_INT: { -- _Py_UopsSymbol *res; -+ case _BINARY_OP_SUBSCR_TUPLE_INT: { -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -582,8 +617,8 @@ - break; - } - -- case _BINARY_SUBSCR_DICT: { -- _Py_UopsSymbol *res; -+ case _BINARY_OP_SUBSCR_DICT: { -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -591,22 +626,21 @@ - break; - } - -- case _BINARY_SUBSCR_CHECK_FUNC: { -+ case _BINARY_OP_SUBSCR_CHECK_FUNC: { -+ JitOptSymbol *getitem; -+ getitem = sym_new_not_null(ctx); -+ stack_pointer[0] = getitem; -+ stack_pointer += 1; -+ assert(WITHIN_STACK_BOUNDS()); - break; - } - -- case _BINARY_SUBSCR_INIT_CALL: { -- _Py_UopsSymbol *sub; -- _Py_UopsSymbol *container; -+ case _BINARY_OP_SUBSCR_INIT_CALL: { - _Py_UOpsAbstractFrame *new_frame; -- sub = stack_pointer[-1]; -- container = stack_pointer[-2]; -- (void)container; -- (void)sub; - new_frame = NULL; - ctx->done = true; -- stack_pointer[-2] = (_Py_UopsSymbol *)new_frame; -- stack_pointer += -1; -+ stack_pointer[-3] = (JitOptSymbol *)new_frame; -+ stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); - break; - } -@@ -648,14 +682,14 @@ - } - - case _CALL_INTRINSIC_1: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-1] = res; - break; - } - - case _CALL_INTRINSIC_2: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -664,8 +698,8 @@ - } - - case _RETURN_VALUE: { -- _Py_UopsSymbol *retval; -- _Py_UopsSymbol *res; -+ JitOptSymbol *retval; -+ JitOptSymbol *res; - retval = stack_pointer[-1]; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); -@@ -692,14 +726,14 @@ - } - - case _GET_AITER: { -- _Py_UopsSymbol *iter; -+ JitOptSymbol *iter; - iter = sym_new_not_null(ctx); - stack_pointer[-1] = iter; - break; - } - - case _GET_ANEXT: { -- _Py_UopsSymbol *awaitable; -+ JitOptSymbol *awaitable; - awaitable = sym_new_not_null(ctx); - stack_pointer[0] = awaitable; - stack_pointer += 1; -@@ -708,7 +742,7 @@ - } - - case _GET_AWAITABLE: { -- _Py_UopsSymbol *iter; -+ JitOptSymbol *iter; - iter = sym_new_not_null(ctx); - stack_pointer[-1] = iter; - break; -@@ -723,7 +757,7 @@ - } - - case _YIELD_VALUE: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_unknown(ctx); - stack_pointer[-1] = res; - break; -@@ -736,7 +770,7 @@ - } - - case _LOAD_COMMON_CONSTANT: { -- _Py_UopsSymbol *value; -+ JitOptSymbol *value; - value = sym_new_not_null(ctx); - stack_pointer[0] = value; - stack_pointer += 1; -@@ -745,7 +779,7 @@ - } - - case _LOAD_BUILD_CLASS: { -- _Py_UopsSymbol *bc; -+ JitOptSymbol *bc; - bc = sym_new_not_null(ctx); - stack_pointer[0] = bc; - stack_pointer += 1; -@@ -764,12 +798,9 @@ - } - - case _UNPACK_SEQUENCE: { -- _Py_UopsSymbol *seq; -- _Py_UopsSymbol **values; -- seq = stack_pointer[-1]; -+ JitOptSymbol **values; - values = &stack_pointer[-1]; - /* This has to be done manually */ -- (void)seq; - for (int i = 0; i < oparg; i++) { - values[i] = sym_new_unknown(ctx); - } -@@ -779,10 +810,12 @@ - } - - case _UNPACK_SEQUENCE_TWO_TUPLE: { -- _Py_UopsSymbol *val1; -- _Py_UopsSymbol *val0; -- val1 = sym_new_not_null(ctx); -- val0 = sym_new_not_null(ctx); -+ JitOptSymbol *seq; -+ JitOptSymbol *val1; -+ JitOptSymbol *val0; -+ seq = stack_pointer[-1]; -+ val0 = sym_tuple_getitem(ctx, seq, 0); -+ val1 = sym_tuple_getitem(ctx, seq, 1); - stack_pointer[-1] = val1; - stack_pointer[0] = val0; - stack_pointer += 1; -@@ -791,10 +824,12 @@ - } - - case _UNPACK_SEQUENCE_TUPLE: { -- _Py_UopsSymbol **values; -+ JitOptSymbol *seq; -+ JitOptSymbol **values; -+ seq = stack_pointer[-1]; - values = &stack_pointer[-1]; -- for (int _i = oparg; --_i >= 0;) { -- values[_i] = sym_new_not_null(ctx); -+ for (int i = 0; i < oparg; i++) { -+ values[i] = sym_tuple_getitem(ctx, seq, i); - } - stack_pointer += -1 + oparg; - assert(WITHIN_STACK_BOUNDS()); -@@ -802,7 +837,7 @@ - } - - case _UNPACK_SEQUENCE_LIST: { -- _Py_UopsSymbol **values; -+ JitOptSymbol **values; - values = &stack_pointer[-1]; - for (int _i = oparg; --_i >= 0;) { - values[_i] = sym_new_not_null(ctx); -@@ -813,12 +848,9 @@ - } - - case _UNPACK_EX: { -- _Py_UopsSymbol *seq; -- _Py_UopsSymbol **values; -- seq = stack_pointer[-1]; -+ JitOptSymbol **values; - values = &stack_pointer[-1]; - /* This has to be done manually */ -- (void)seq; - int totalargs = (oparg & 0xFF) + (oparg >> 8) + 1; - for (int i = 0; i < totalargs; i++) { - values[i] = sym_new_unknown(ctx); -@@ -851,7 +883,7 @@ - } - - case _LOAD_LOCALS: { -- _Py_UopsSymbol *locals; -+ JitOptSymbol *locals; - locals = sym_new_not_null(ctx); - stack_pointer[0] = locals; - stack_pointer += 1; -@@ -862,7 +894,7 @@ - /* _LOAD_FROM_DICT_OR_GLOBALS is not a viable micro-op for tier 2 */ - - case _LOAD_NAME: { -- _Py_UopsSymbol *v; -+ JitOptSymbol *v; - v = sym_new_not_null(ctx); - stack_pointer[0] = v; - stack_pointer += 1; -@@ -871,13 +903,21 @@ - } - - case _LOAD_GLOBAL: { -- _Py_UopsSymbol **res; -- _Py_UopsSymbol *null = NULL; -+ JitOptSymbol **res; - res = &stack_pointer[0]; - res[0] = sym_new_not_null(ctx); -+ stack_pointer += 1; -+ assert(WITHIN_STACK_BOUNDS()); -+ break; -+ } -+ -+ case _PUSH_NULL_CONDITIONAL: { -+ JitOptSymbol *null = NULL; -+ int opcode = (oparg & 1) ? _PUSH_NULL : _NOP; -+ REPLACE_OP(this_instr, opcode, 0, 0); - null = sym_new_null(ctx); -- if (oparg & 1) stack_pointer[1] = null; -- stack_pointer += 1 + (oparg & 1); -+ if (oparg & 1) stack_pointer[0] = null; -+ stack_pointer += (oparg & 1); - assert(WITHIN_STACK_BOUNDS()); - break; - } -@@ -887,7 +927,7 @@ - } - - case _GUARD_GLOBALS_VERSION_PUSH_KEYS: { -- _Py_UopsSymbol *globals_keys; -+ JitOptSymbol *globals_keys; - uint16_t version = (uint16_t)this_instr->operand0; - globals_keys = sym_new_unknown(ctx); - (void)version; -@@ -898,7 +938,7 @@ - } - - case _GUARD_BUILTINS_VERSION_PUSH_KEYS: { -- _Py_UopsSymbol *builtins_keys; -+ JitOptSymbol *builtins_keys; - uint16_t version = (uint16_t)this_instr->operand0; - builtins_keys = sym_new_unknown(ctx); - (void)version; -@@ -909,26 +949,16 @@ - } - - case _LOAD_GLOBAL_MODULE_FROM_KEYS: { -- _Py_UopsSymbol *res; -- _Py_UopsSymbol *null = NULL; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); -- null = sym_new_null(ctx); - stack_pointer[-1] = res; -- if (oparg & 1) stack_pointer[0] = null; -- stack_pointer += (oparg & 1); -- assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _LOAD_GLOBAL_BUILTINS_FROM_KEYS: { -- _Py_UopsSymbol *res; -- _Py_UopsSymbol *null = NULL; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); -- null = sym_new_null(ctx); - stack_pointer[-1] = res; -- if (oparg & 1) stack_pointer[0] = null; -- stack_pointer += (oparg & 1); -- assert(WITHIN_STACK_BOUNDS()); - break; - } - -@@ -945,14 +975,14 @@ - } - - case _LOAD_FROM_DICT_OR_DEREF: { -- _Py_UopsSymbol *value; -+ JitOptSymbol *value; - value = sym_new_not_null(ctx); - stack_pointer[-1] = value; - break; - } - - case _LOAD_DEREF: { -- _Py_UopsSymbol *value; -+ JitOptSymbol *value; - value = sym_new_not_null(ctx); - stack_pointer[0] = value; - stack_pointer += 1; -@@ -971,7 +1001,7 @@ - } - - case _BUILD_STRING: { -- _Py_UopsSymbol *str; -+ JitOptSymbol *str; - str = sym_new_not_null(ctx); - stack_pointer[-oparg] = str; - stack_pointer += 1 - oparg; -@@ -980,8 +1010,10 @@ - } - - case _BUILD_TUPLE: { -- _Py_UopsSymbol *tup; -- tup = sym_new_not_null(ctx); -+ JitOptSymbol **values; -+ JitOptSymbol *tup; -+ values = &stack_pointer[-oparg]; -+ tup = sym_new_tuple(ctx, oparg, values); - stack_pointer[-oparg] = tup; - stack_pointer += 1 - oparg; - assert(WITHIN_STACK_BOUNDS()); -@@ -989,7 +1021,7 @@ - } - - case _BUILD_LIST: { -- _Py_UopsSymbol *list; -+ JitOptSymbol *list; - list = sym_new_not_null(ctx); - stack_pointer[-oparg] = list; - stack_pointer += 1 - oparg; -@@ -1010,7 +1042,7 @@ - } - - case _BUILD_SET: { -- _Py_UopsSymbol *set; -+ JitOptSymbol *set; - set = sym_new_not_null(ctx); - stack_pointer[-oparg] = set; - stack_pointer += 1 - oparg; -@@ -1019,7 +1051,7 @@ - } - - case _BUILD_MAP: { -- _Py_UopsSymbol *map; -+ JitOptSymbol *map; - map = sym_new_not_null(ctx); - stack_pointer[-oparg*2] = map; - stack_pointer += 1 - oparg*2; -@@ -1049,10 +1081,8 @@ - break; - } - -- /* _INSTRUMENTED_LOAD_SUPER_ATTR is not a viable micro-op for tier 2 */ -- - case _LOAD_SUPER_ATTR_ATTR: { -- _Py_UopsSymbol *attr_st; -+ JitOptSymbol *attr_st; - attr_st = sym_new_not_null(ctx); - stack_pointer[-3] = attr_st; - stack_pointer += -2; -@@ -1061,8 +1091,8 @@ - } - - case _LOAD_SUPER_ATTR_METHOD: { -- _Py_UopsSymbol *attr; -- _Py_UopsSymbol *self_or_null; -+ JitOptSymbol *attr; -+ JitOptSymbol *self_or_null; - attr = sym_new_not_null(ctx); - self_or_null = sym_new_not_null(ctx); - stack_pointer[-3] = attr; -@@ -1073,22 +1103,24 @@ - } - - case _LOAD_ATTR: { -- _Py_UopsSymbol *owner; -- _Py_UopsSymbol *attr; -- _Py_UopsSymbol *self_or_null = NULL; -+ JitOptSymbol *owner; -+ JitOptSymbol *attr; -+ JitOptSymbol **self_or_null; - owner = stack_pointer[-1]; -+ self_or_null = &stack_pointer[0]; - (void)owner; - attr = sym_new_not_null(ctx); -- self_or_null = sym_new_unknown(ctx); -+ if (oparg &1) { -+ self_or_null[0] = sym_new_unknown(ctx); -+ } - stack_pointer[-1] = attr; -- if (oparg & 1) stack_pointer[0] = self_or_null; -- stack_pointer += (oparg & 1); -+ stack_pointer += (oparg&1); - assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _GUARD_TYPE_VERSION: { -- _Py_UopsSymbol *owner; -+ JitOptSymbol *owner; - owner = stack_pointer[-1]; - uint32_t type_version = (uint32_t)this_instr->operand0; - assert(type_version); -@@ -1113,30 +1145,26 @@ - break; - } - -+ case _GUARD_TYPE_VERSION_AND_LOCK: { -+ break; -+ } -+ - case _CHECK_MANAGED_OBJECT_HAS_VALUES: { - break; - } - - case _LOAD_ATTR_INSTANCE_VALUE: { -- _Py_UopsSymbol *owner; -- _Py_UopsSymbol *attr; -- _Py_UopsSymbol *null = NULL; -- owner = stack_pointer[-1]; -+ JitOptSymbol *attr; - uint16_t offset = (uint16_t)this_instr->operand0; - attr = sym_new_not_null(ctx); -- null = sym_new_null(ctx); - (void)offset; -- (void)owner; - stack_pointer[-1] = attr; -- if (oparg & 1) stack_pointer[0] = null; -- stack_pointer += (oparg & 1); -- assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _CHECK_ATTR_MODULE_PUSH_KEYS: { -- _Py_UopsSymbol *owner; -- _Py_UopsSymbol *mod_keys; -+ JitOptSymbol *owner; -+ JitOptSymbol *mod_keys; - owner = stack_pointer[-1]; - uint32_t dict_version = (uint32_t)this_instr->operand0; - (void)dict_version; -@@ -1166,13 +1194,11 @@ - } - - case _LOAD_ATTR_MODULE_FROM_KEYS: { -- _Py_UopsSymbol *owner; -- _Py_UopsSymbol *attr; -- _Py_UopsSymbol *null = NULL; -+ JitOptSymbol *owner; -+ JitOptSymbol *attr; - owner = stack_pointer[-2]; - uint16_t index = (uint16_t)this_instr->operand0; - (void)index; -- null = sym_new_null(ctx); - attr = NULL; - if (this_instr[-1].opcode == _NOP) { - // Preceding _CHECK_ATTR_MODULE_PUSH_KEYS was removed: mod is const and dict is watched. -@@ -1181,8 +1207,7 @@ - assert(PyModule_CheckExact(mod)); - PyObject *dict = mod->md_dict; - stack_pointer[-2] = attr; -- if (oparg & 1) stack_pointer[-1] = null; -- stack_pointer += -1 + (oparg & 1); -+ stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - PyObject *res = convert_global_to_const(this_instr, dict); - if (res != NULL) { -@@ -1192,7 +1217,7 @@ - else { - this_instr->opcode = _LOAD_ATTR_MODULE; - } -- stack_pointer += 1 - (oparg & 1); -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - } - if (attr == NULL) { -@@ -1200,47 +1225,37 @@ - attr = sym_new_not_null(ctx); - } - stack_pointer[-2] = attr; -- if (oparg & 1) stack_pointer[-1] = null; -- stack_pointer += -1 + (oparg & 1); -+ stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _CHECK_ATTR_WITH_HINT: { -+ JitOptSymbol *dict; -+ dict = sym_new_not_null(ctx); -+ stack_pointer[0] = dict; -+ stack_pointer += 1; -+ assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _LOAD_ATTR_WITH_HINT: { -- _Py_UopsSymbol *owner; -- _Py_UopsSymbol *attr; -- _Py_UopsSymbol *null = NULL; -- owner = stack_pointer[-1]; -+ JitOptSymbol *attr; - uint16_t hint = (uint16_t)this_instr->operand0; - attr = sym_new_not_null(ctx); -- null = sym_new_null(ctx); - (void)hint; -- (void)owner; -- stack_pointer[-1] = attr; -- if (oparg & 1) stack_pointer[0] = null; -- stack_pointer += (oparg & 1); -+ stack_pointer[-2] = attr; -+ stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _LOAD_ATTR_SLOT: { -- _Py_UopsSymbol *owner; -- _Py_UopsSymbol *attr; -- _Py_UopsSymbol *null = NULL; -- owner = stack_pointer[-1]; -+ JitOptSymbol *attr; - uint16_t index = (uint16_t)this_instr->operand0; - attr = sym_new_not_null(ctx); -- null = sym_new_null(ctx); - (void)index; -- (void)owner; - stack_pointer[-1] = attr; -- if (oparg & 1) stack_pointer[0] = null; -- stack_pointer += (oparg & 1); -- assert(WITHIN_STACK_BOUNDS()); - break; - } - -@@ -1249,32 +1264,21 @@ - } - - case _LOAD_ATTR_CLASS: { -- _Py_UopsSymbol *owner; -- _Py_UopsSymbol *attr; -- _Py_UopsSymbol *null = NULL; -- owner = stack_pointer[-1]; -+ JitOptSymbol *attr; - PyObject *descr = (PyObject *)this_instr->operand0; - attr = sym_new_not_null(ctx); -- null = sym_new_null(ctx); - (void)descr; -- (void)owner; - stack_pointer[-1] = attr; -- if (oparg & 1) stack_pointer[0] = null; -- stack_pointer += (oparg & 1); -- assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _LOAD_ATTR_PROPERTY_FRAME: { -- _Py_UopsSymbol *owner; - _Py_UOpsAbstractFrame *new_frame; -- owner = stack_pointer[-1]; - PyObject *fget = (PyObject *)this_instr->operand0; - (void)fget; -- (void)owner; - new_frame = NULL; - ctx->done = true; -- stack_pointer[-1] = (_Py_UopsSymbol *)new_frame; -+ stack_pointer[-1] = (JitOptSymbol *)new_frame; - break; - } - -@@ -1303,13 +1307,7 @@ - } - - case _COMPARE_OP: { -- _Py_UopsSymbol *right; -- _Py_UopsSymbol *left; -- _Py_UopsSymbol *res; -- right = stack_pointer[-1]; -- left = stack_pointer[-2]; -- (void)left; -- (void)right; -+ JitOptSymbol *res; - if (oparg & 16) { - res = sym_new_type(ctx, &PyBool_Type); - } -@@ -1327,13 +1325,7 @@ - } - - case _COMPARE_OP_FLOAT: { -- _Py_UopsSymbol *right; -- _Py_UopsSymbol *left; -- _Py_UopsSymbol *res; -- right = stack_pointer[-1]; -- left = stack_pointer[-2]; -- (void)left; -- (void)right; -+ JitOptSymbol *res; - res = sym_new_type(ctx, &PyBool_Type); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -1342,13 +1334,7 @@ - } - - case _COMPARE_OP_INT: { -- _Py_UopsSymbol *right; -- _Py_UopsSymbol *left; -- _Py_UopsSymbol *res; -- right = stack_pointer[-1]; -- left = stack_pointer[-2]; -- (void)left; -- (void)right; -+ JitOptSymbol *res; - res = sym_new_type(ctx, &PyBool_Type); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -1357,13 +1343,7 @@ - } - - case _COMPARE_OP_STR: { -- _Py_UopsSymbol *right; -- _Py_UopsSymbol *left; -- _Py_UopsSymbol *res; -- right = stack_pointer[-1]; -- left = stack_pointer[-2]; -- (void)left; -- (void)right; -+ JitOptSymbol *res; - res = sym_new_type(ctx, &PyBool_Type); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -1372,13 +1352,7 @@ - } - - case _IS_OP: { -- _Py_UopsSymbol *right; -- _Py_UopsSymbol *left; -- _Py_UopsSymbol *res; -- right = stack_pointer[-1]; -- left = stack_pointer[-2]; -- (void)left; -- (void)right; -+ JitOptSymbol *res; - res = sym_new_type(ctx, &PyBool_Type); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -1387,13 +1361,7 @@ - } - - case _CONTAINS_OP: { -- _Py_UopsSymbol *right; -- _Py_UopsSymbol *left; -- _Py_UopsSymbol *res; -- right = stack_pointer[-1]; -- left = stack_pointer[-2]; -- (void)left; -- (void)right; -+ JitOptSymbol *res; - res = sym_new_type(ctx, &PyBool_Type); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -1402,7 +1370,7 @@ - } - - case _CONTAINS_OP_SET: { -- _Py_UopsSymbol *b; -+ JitOptSymbol *b; - b = sym_new_not_null(ctx); - stack_pointer[-2] = b; - stack_pointer += -1; -@@ -1411,7 +1379,7 @@ - } - - case _CONTAINS_OP_DICT: { -- _Py_UopsSymbol *b; -+ JitOptSymbol *b; - b = sym_new_not_null(ctx); - stack_pointer[-2] = b; - stack_pointer += -1; -@@ -1420,8 +1388,8 @@ - } - - case _CHECK_EG_MATCH: { -- _Py_UopsSymbol *rest; -- _Py_UopsSymbol *match; -+ JitOptSymbol *rest; -+ JitOptSymbol *match; - rest = sym_new_not_null(ctx); - match = sym_new_not_null(ctx); - stack_pointer[-2] = rest; -@@ -1430,14 +1398,14 @@ - } - - case _CHECK_EXC_MATCH: { -- _Py_UopsSymbol *b; -+ JitOptSymbol *b; - b = sym_new_not_null(ctx); - stack_pointer[-1] = b; - break; - } - - case _IMPORT_NAME: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -1446,7 +1414,7 @@ - } - - case _IMPORT_FROM: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[0] = res; - stack_pointer += 1; -@@ -1459,14 +1427,14 @@ - /* _POP_JUMP_IF_TRUE is not a viable micro-op for tier 2 */ - - case _IS_NONE: { -- _Py_UopsSymbol *b; -+ JitOptSymbol *b; - b = sym_new_not_null(ctx); - stack_pointer[-1] = b; - break; - } - - case _GET_LEN: { -- _Py_UopsSymbol *len; -+ JitOptSymbol *len; - len = sym_new_not_null(ctx); - stack_pointer[0] = len; - stack_pointer += 1; -@@ -1475,7 +1443,7 @@ - } - - case _MATCH_CLASS: { -- _Py_UopsSymbol *attrs; -+ JitOptSymbol *attrs; - attrs = sym_new_not_null(ctx); - stack_pointer[-3] = attrs; - stack_pointer += -2; -@@ -1484,7 +1452,7 @@ - } - - case _MATCH_MAPPING: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[0] = res; - stack_pointer += 1; -@@ -1493,7 +1461,7 @@ - } - - case _MATCH_SEQUENCE: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[0] = res; - stack_pointer += 1; -@@ -1502,7 +1470,7 @@ - } - - case _MATCH_KEYS: { -- _Py_UopsSymbol *values_or_none; -+ JitOptSymbol *values_or_none; - values_or_none = sym_new_not_null(ctx); - stack_pointer[0] = values_or_none; - stack_pointer += 1; -@@ -1511,14 +1479,14 @@ - } - - case _GET_ITER: { -- _Py_UopsSymbol *iter; -+ JitOptSymbol *iter; - iter = sym_new_not_null(ctx); - stack_pointer[-1] = iter; - break; - } - - case _GET_YIELD_FROM_ITER: { -- _Py_UopsSymbol *iter; -+ JitOptSymbol *iter; - iter = sym_new_not_null(ctx); - stack_pointer[-1] = iter; - break; -@@ -1527,7 +1495,7 @@ - /* _FOR_ITER is not a viable micro-op for tier 2 */ - - case _FOR_ITER_TIER_TWO: { -- _Py_UopsSymbol *next; -+ JitOptSymbol *next; - next = sym_new_not_null(ctx); - stack_pointer[0] = next; - stack_pointer += 1; -@@ -1548,7 +1516,7 @@ - } - - case _ITER_NEXT_LIST: { -- _Py_UopsSymbol *next; -+ JitOptSymbol *next; - next = sym_new_not_null(ctx); - stack_pointer[0] = next; - stack_pointer += 1; -@@ -1567,7 +1535,7 @@ - } - - case _ITER_NEXT_TUPLE: { -- _Py_UopsSymbol *next; -+ JitOptSymbol *next; - next = sym_new_not_null(ctx); - stack_pointer[0] = next; - stack_pointer += 1; -@@ -1586,11 +1554,8 @@ - } - - case _ITER_NEXT_RANGE: { -- _Py_UopsSymbol *iter; -- _Py_UopsSymbol *next; -- iter = stack_pointer[-1]; -+ JitOptSymbol *next; - next = sym_new_type(ctx, &PyLong_Type); -- (void)iter; - stack_pointer[0] = next; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); -@@ -1604,11 +1569,8 @@ - } - - case _LOAD_SPECIAL: { -- _Py_UopsSymbol *owner; -- _Py_UopsSymbol *attr; -- _Py_UopsSymbol *self_or_null; -- owner = stack_pointer[-1]; -- (void)owner; -+ JitOptSymbol *attr; -+ JitOptSymbol *self_or_null; - attr = sym_new_not_null(ctx); - self_or_null = sym_new_unknown(ctx); - stack_pointer[-1] = attr; -@@ -1619,7 +1581,7 @@ - } - - case _WITH_EXCEPT_START: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[0] = res; - stack_pointer += 1; -@@ -1628,8 +1590,8 @@ - } - - case _PUSH_EXC_INFO: { -- _Py_UopsSymbol *prev_exc; -- _Py_UopsSymbol *new_exc; -+ JitOptSymbol *prev_exc; -+ JitOptSymbol *new_exc; - prev_exc = sym_new_not_null(ctx); - new_exc = sym_new_not_null(ctx); - stack_pointer[-1] = prev_exc; -@@ -1648,9 +1610,9 @@ - } - - case _LOAD_ATTR_METHOD_WITH_VALUES: { -- _Py_UopsSymbol *owner; -- _Py_UopsSymbol *attr; -- _Py_UopsSymbol *self = NULL; -+ JitOptSymbol *owner; -+ JitOptSymbol *attr; -+ JitOptSymbol *self; - owner = stack_pointer[-1]; - PyObject *descr = (PyObject *)this_instr->operand0; - (void)descr; -@@ -1664,9 +1626,9 @@ - } - - case _LOAD_ATTR_METHOD_NO_DICT: { -- _Py_UopsSymbol *owner; -- _Py_UopsSymbol *attr; -- _Py_UopsSymbol *self = NULL; -+ JitOptSymbol *owner; -+ JitOptSymbol *attr; -+ JitOptSymbol *self; - owner = stack_pointer[-1]; - PyObject *descr = (PyObject *)this_instr->operand0; - (void)descr; -@@ -1680,14 +1642,14 @@ - } - - case _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES: { -- _Py_UopsSymbol *attr; -+ JitOptSymbol *attr; - attr = sym_new_not_null(ctx); - stack_pointer[-1] = attr; - break; - } - - case _LOAD_ATTR_NONDESCRIPTOR_NO_DICT: { -- _Py_UopsSymbol *attr; -+ JitOptSymbol *attr; - attr = sym_new_not_null(ctx); - stack_pointer[-1] = attr; - break; -@@ -1698,9 +1660,9 @@ - } - - case _LOAD_ATTR_METHOD_LAZY_DICT: { -- _Py_UopsSymbol *owner; -- _Py_UopsSymbol *attr; -- _Py_UopsSymbol *self = NULL; -+ JitOptSymbol *owner; -+ JitOptSymbol *attr; -+ JitOptSymbol *self; - owner = stack_pointer[-1]; - PyObject *descr = (PyObject *)this_instr->operand0; - (void)descr; -@@ -1714,17 +1676,11 @@ - } - - case _MAYBE_EXPAND_METHOD: { -- _Py_UopsSymbol **args; -- _Py_UopsSymbol *self_or_null; -- _Py_UopsSymbol *callable; -- _Py_UopsSymbol *func; -- _Py_UopsSymbol *maybe_self; -+ JitOptSymbol **args; -+ JitOptSymbol *func; -+ JitOptSymbol *maybe_self; - args = &stack_pointer[-oparg]; -- self_or_null = stack_pointer[-1 - oparg]; -- callable = stack_pointer[-2 - oparg]; - args = &stack_pointer[-oparg]; -- (void)callable; -- (void)self_or_null; - (void)args; - func = sym_new_not_null(ctx); - maybe_self = sym_new_not_null(ctx); -@@ -1738,36 +1694,27 @@ - /* _MONITOR_CALL is not a viable micro-op for tier 2 */ - - case _PY_FRAME_GENERAL: { -- _Py_UopsSymbol *self_or_null; -- _Py_UopsSymbol *callable; - _Py_UOpsAbstractFrame *new_frame; -- self_or_null = stack_pointer[-1 - oparg]; -- callable = stack_pointer[-2 - oparg]; -- stack_pointer += -2 - oparg; -- assert(WITHIN_STACK_BOUNDS()); -- (void)(self_or_null); -- (void)(callable); - PyCodeObject *co = NULL; - assert((this_instr + 2)->opcode == _PUSH_FRAME); -+ stack_pointer += -2 - oparg; -+ assert(WITHIN_STACK_BOUNDS()); - co = get_code_with_logging((this_instr + 2)); - if (co == NULL) { - ctx->done = true; - break; - } - new_frame = frame_new(ctx, co, 0, NULL, 0); -- stack_pointer[0] = (_Py_UopsSymbol *)new_frame; -+ stack_pointer[0] = (JitOptSymbol *)new_frame; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _CHECK_FUNCTION_VERSION: { -- _Py_UopsSymbol *self_or_null; -- _Py_UopsSymbol *callable; -- self_or_null = stack_pointer[-1 - oparg]; -+ JitOptSymbol *callable; - callable = stack_pointer[-2 - oparg]; - uint32_t func_version = (uint32_t)this_instr->operand0; -- (void)self_or_null; - if (sym_is_const(callable) && sym_matches_type(callable, &PyFunction_Type)) { - assert(PyFunction_Check(sym_get_const(callable))); - REPLACE_OP(this_instr, _CHECK_FUNCTION_VERSION_INLINE, 0, func_version); -@@ -1786,12 +1733,6 @@ - } - - case _EXPAND_METHOD: { -- _Py_UopsSymbol **method; -- _Py_UopsSymbol **self; -- method = &stack_pointer[-2 - oparg]; -- self = &stack_pointer[-1 - oparg]; -- method[0] = sym_new_not_null(ctx); -- self[0] = sym_new_not_null(ctx); - break; - } - -@@ -1800,7 +1741,7 @@ - } - - case _CALL_NON_PY_GENERAL: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; -@@ -1809,8 +1750,8 @@ - } - - case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: { -- _Py_UopsSymbol *null; -- _Py_UopsSymbol *callable; -+ JitOptSymbol *null; -+ JitOptSymbol *callable; - null = stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; - sym_set_null(null); -@@ -1819,15 +1760,12 @@ - } - - case _INIT_CALL_BOUND_METHOD_EXACT_ARGS: { -- _Py_UopsSymbol *callable; -- _Py_UopsSymbol *func; -- _Py_UopsSymbol *self; -- callable = stack_pointer[-2 - oparg]; -- (void)callable; -- func = sym_new_not_null(ctx); -- self = sym_new_not_null(ctx); -- stack_pointer[-2 - oparg] = func; -- stack_pointer[-1 - oparg] = self; -+ JitOptSymbol **self_or_null; -+ JitOptSymbol **callable; -+ self_or_null = &stack_pointer[-1 - oparg]; -+ callable = &stack_pointer[-2 - oparg]; -+ callable[0] = sym_new_not_null(ctx); -+ self_or_null[0] = sym_new_not_null(ctx); - break; - } - -@@ -1841,8 +1779,8 @@ - } - - case _CHECK_FUNCTION_EXACT_ARGS: { -- _Py_UopsSymbol *self_or_null; -- _Py_UopsSymbol *callable; -+ JitOptSymbol *self_or_null; -+ JitOptSymbol *callable; - self_or_null = stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; - assert(sym_matches_type(callable, &PyFunction_Type)); -@@ -1855,7 +1793,6 @@ - } - } - } -- (void)self_or_null; - break; - } - -@@ -1866,15 +1803,12 @@ - } - - case _INIT_CALL_PY_EXACT_ARGS: { -- _Py_UopsSymbol **args; -- _Py_UopsSymbol *self_or_null; -- _Py_UopsSymbol *callable; -+ JitOptSymbol **args; -+ JitOptSymbol *self_or_null; - _Py_UOpsAbstractFrame *new_frame; - args = &stack_pointer[-oparg]; - self_or_null = stack_pointer[-1 - oparg]; -- callable = stack_pointer[-2 - oparg]; - int argcount = oparg; -- (void)callable; - PyCodeObject *co = NULL; - assert((this_instr + 2)->opcode == _PUSH_FRAME); - stack_pointer += -2 - oparg; -@@ -1896,7 +1830,7 @@ - } else { - new_frame = frame_new(ctx, co, 0, NULL, 0); - } -- stack_pointer[0] = (_Py_UopsSymbol *)new_frame; -+ stack_pointer[0] = (JitOptSymbol *)new_frame; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; -@@ -1941,7 +1875,7 @@ - } - - case _CALL_TYPE_1: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-3] = res; - stack_pointer += -2; -@@ -1950,7 +1884,7 @@ - } - - case _CALL_STR_1: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-3] = res; - stack_pointer += -2; -@@ -1959,7 +1893,7 @@ - } - - case _CALL_TUPLE_1: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-3] = res; - stack_pointer += -2; -@@ -1968,19 +1902,13 @@ - } - - case _CHECK_AND_ALLOCATE_OBJECT: { -- _Py_UopsSymbol **args; -- _Py_UopsSymbol *null; -- _Py_UopsSymbol *callable; -- _Py_UopsSymbol *self; -- _Py_UopsSymbol *init; -+ JitOptSymbol **args; -+ JitOptSymbol *self; -+ JitOptSymbol *init; - args = &stack_pointer[-oparg]; -- null = stack_pointer[-1 - oparg]; -- callable = stack_pointer[-2 - oparg]; - args = &stack_pointer[-oparg]; - uint32_t type_version = (uint32_t)this_instr->operand0; - (void)type_version; -- (void)callable; -- (void)null; - (void)args; - self = sym_new_not_null(ctx); - init = sym_new_not_null(ctx); -@@ -1990,19 +1918,10 @@ - } - - case _CREATE_INIT_FRAME: { -- _Py_UopsSymbol **args; -- _Py_UopsSymbol *init; -- _Py_UopsSymbol *self; - _Py_UOpsAbstractFrame *init_frame; -- args = &stack_pointer[-oparg]; -- init = stack_pointer[-1 - oparg]; -- self = stack_pointer[-2 - oparg]; -- (void)self; -- (void)init; -- (void)args; - init_frame = NULL; - ctx->done = true; -- stack_pointer[-2 - oparg] = (_Py_UopsSymbol *)init_frame; -+ stack_pointer[-2 - oparg] = (JitOptSymbol *)init_frame; - stack_pointer += -1 - oparg; - assert(WITHIN_STACK_BOUNDS()); - break; -@@ -2015,7 +1934,7 @@ - } - - case _CALL_BUILTIN_CLASS: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; -@@ -2024,7 +1943,7 @@ - } - - case _CALL_BUILTIN_O: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; -@@ -2033,7 +1952,7 @@ - } - - case _CALL_BUILTIN_FAST: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; -@@ -2042,7 +1961,7 @@ - } - - case _CALL_BUILTIN_FAST_WITH_KEYWORDS: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; -@@ -2051,7 +1970,7 @@ - } - - case _CALL_LEN: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; -@@ -2060,7 +1979,7 @@ - } - - case _CALL_ISINSTANCE: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; -@@ -2075,7 +1994,7 @@ - } - - case _CALL_METHOD_DESCRIPTOR_O: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; -@@ -2084,7 +2003,7 @@ - } - - case _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; -@@ -2093,7 +2012,7 @@ - } - - case _CALL_METHOD_DESCRIPTOR_NOARGS: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; -@@ -2102,7 +2021,7 @@ - } - - case _CALL_METHOD_DESCRIPTOR_FAST: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; -@@ -2110,13 +2029,13 @@ - break; - } - -- /* _INSTRUMENTED_CALL_KW is not a viable micro-op for tier 2 */ -+ /* _MONITOR_CALL_KW is not a viable micro-op for tier 2 */ - - case _MAYBE_EXPAND_METHOD_KW: { -- _Py_UopsSymbol **func; -- _Py_UopsSymbol **maybe_self; -- _Py_UopsSymbol **args; -- _Py_UopsSymbol *kwnames_out; -+ JitOptSymbol **func; -+ JitOptSymbol **maybe_self; -+ JitOptSymbol **args; -+ JitOptSymbol *kwnames_out; - func = &stack_pointer[-3 - oparg]; - maybe_self = &stack_pointer[-2 - oparg]; - args = &stack_pointer[-1 - oparg]; -@@ -2133,22 +2052,10 @@ - /* _DO_CALL_KW is not a viable micro-op for tier 2 */ - - case _PY_FRAME_KW: { -- _Py_UopsSymbol *kwnames; -- _Py_UopsSymbol **args; -- _Py_UopsSymbol *self_or_null; -- _Py_UopsSymbol *callable; - _Py_UOpsAbstractFrame *new_frame; -- kwnames = stack_pointer[-1]; -- args = &stack_pointer[-1 - oparg]; -- self_or_null = stack_pointer[-2 - oparg]; -- callable = stack_pointer[-3 - oparg]; -- (void)callable; -- (void)self_or_null; -- (void)args; -- (void)kwnames; - new_frame = NULL; - ctx->done = true; -- stack_pointer[-3 - oparg] = (_Py_UopsSymbol *)new_frame; -+ stack_pointer[-3 - oparg] = (JitOptSymbol *)new_frame; - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); - break; -@@ -2163,12 +2070,6 @@ - } - - case _EXPAND_METHOD_KW: { -- _Py_UopsSymbol **method; -- _Py_UopsSymbol **self; -- method = &stack_pointer[-3 - oparg]; -- self = &stack_pointer[-2 - oparg]; -- method[0] = sym_new_not_null(ctx); -- self[0] = sym_new_not_null(ctx); - break; - } - -@@ -2177,7 +2078,7 @@ - } - - case _CALL_KW_NON_PY: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-3 - oparg] = res; - stack_pointer += -2 - oparg; -@@ -2185,29 +2086,27 @@ - break; - } - -- /* _INSTRUMENTED_CALL_FUNCTION_EX is not a viable micro-op for tier 2 */ -- - case _MAKE_CALLARGS_A_TUPLE: { -- _Py_UopsSymbol *tuple; -- _Py_UopsSymbol *kwargs_out = NULL; -+ JitOptSymbol *tuple; -+ JitOptSymbol *kwargs_out; - tuple = sym_new_not_null(ctx); - kwargs_out = sym_new_not_null(ctx); -- stack_pointer[-1 - (oparg & 1)] = tuple; -- if (oparg & 1) stack_pointer[-(oparg & 1)] = kwargs_out; -+ stack_pointer[-2] = tuple; -+ stack_pointer[-1] = kwargs_out; - break; - } - - /* _DO_CALL_FUNCTION_EX is not a viable micro-op for tier 2 */ - - case _MAKE_FUNCTION: { -- _Py_UopsSymbol *func; -+ JitOptSymbol *func; - func = sym_new_not_null(ctx); - stack_pointer[-1] = func; - break; - } - - case _SET_FUNCTION_ATTRIBUTE: { -- _Py_UopsSymbol *func_out; -+ JitOptSymbol *func_out; - func_out = sym_new_not_null(ctx); - stack_pointer[-2] = func_out; - stack_pointer += -1; -@@ -2216,7 +2115,7 @@ - } - - case _RETURN_GENERATOR: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - ctx->frame->stack_pointer = stack_pointer; - frame_pop(ctx); - stack_pointer = ctx->frame->stack_pointer; -@@ -2240,30 +2139,30 @@ - } - - case _BUILD_SLICE: { -- _Py_UopsSymbol *slice; -+ JitOptSymbol *slice; - slice = sym_new_not_null(ctx); -- stack_pointer[-2 - ((oparg == 3) ? 1 : 0)] = slice; -- stack_pointer += -1 - ((oparg == 3) ? 1 : 0); -+ stack_pointer[-oparg] = slice; -+ stack_pointer += 1 - oparg; - assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _CONVERT_VALUE: { -- _Py_UopsSymbol *result; -+ JitOptSymbol *result; - result = sym_new_not_null(ctx); - stack_pointer[-1] = result; - break; - } - - case _FORMAT_SIMPLE: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-1] = res; - break; - } - - case _FORMAT_WITH_SPEC: { -- _Py_UopsSymbol *res; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); - stack_pointer[-2] = res; - stack_pointer += -1; -@@ -2272,8 +2171,8 @@ - } - - case _COPY: { -- _Py_UopsSymbol *bottom; -- _Py_UopsSymbol *top; -+ JitOptSymbol *bottom; -+ JitOptSymbol *top; - bottom = stack_pointer[-1 - (oparg-1)]; - assert(oparg > 0); - top = bottom; -@@ -2284,29 +2183,74 @@ - } - - case _BINARY_OP: { -- _Py_UopsSymbol *right; -- _Py_UopsSymbol *left; -- _Py_UopsSymbol *res; -+ JitOptSymbol *right; -+ JitOptSymbol *left; -+ JitOptSymbol *res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; -- PyTypeObject *ltype = sym_get_type(left); -- PyTypeObject *rtype = sym_get_type(right); -- if (ltype != NULL && (ltype == &PyLong_Type || ltype == &PyFloat_Type) && -- rtype != NULL && (rtype == &PyLong_Type || rtype == &PyFloat_Type)) -- { -- if (oparg != NB_TRUE_DIVIDE && oparg != NB_INPLACE_TRUE_DIVIDE && -- ltype == &PyLong_Type && rtype == &PyLong_Type) { -- /* If both inputs are ints and the op is not division the result is an int */ -- res = sym_new_type(ctx, &PyLong_Type); -+ bool lhs_int = sym_matches_type(left, &PyLong_Type); -+ bool rhs_int = sym_matches_type(right, &PyLong_Type); -+ bool lhs_float = sym_matches_type(left, &PyFloat_Type); -+ bool rhs_float = sym_matches_type(right, &PyFloat_Type); -+ if (!((lhs_int || lhs_float) && (rhs_int || rhs_float))) { -+ // There's something other than an int or float involved: -+ res = sym_new_unknown(ctx); -+ } -+ else { -+ if (oparg == NB_POWER || oparg == NB_INPLACE_POWER) { -+ // This one's fun... the *type* of the result depends on the -+ // *values* being exponentiated. However, exponents with one -+ // constant part are reasonably common, so it's probably worth -+ // trying to infer some simple cases: -+ // - A: 1 ** 1 -> 1 (int ** int -> int) -+ // - B: 1 ** -1 -> 1.0 (int ** int -> float) -+ // - C: 1.0 ** 1 -> 1.0 (float ** int -> float) -+ // - D: 1 ** 1.0 -> 1.0 (int ** float -> float) -+ // - E: -1 ** 0.5 ~> 1j (int ** float -> complex) -+ // - F: 1.0 ** 1.0 -> 1.0 (float ** float -> float) -+ // - G: -1.0 ** 0.5 ~> 1j (float ** float -> complex) -+ if (rhs_float) { -+ // Case D, E, F, or G... can't know without the sign of the LHS -+ // or whether the RHS is whole, which isn't worth the effort: -+ res = sym_new_unknown(ctx); -+ } -+ else { -+ if (lhs_float) { -+ // Case C: -+ res = sym_new_type(ctx, &PyFloat_Type); -+ } -+ else { -+ if (!sym_is_const(right)) { -+ // Case A or B... can't know without the sign of the RHS: -+ res = sym_new_unknown(ctx); -+ } -+ else { -+ if (_PyLong_IsNegative((PyLongObject *)sym_get_const(right))) { -+ // Case B: -+ res = sym_new_type(ctx, &PyFloat_Type); -+ } -+ else { -+ // Case A: -+ res = sym_new_type(ctx, &PyLong_Type); -+ } -+ } -+ } -+ } - } - else { -- /* For any other op combining ints/floats the result is a float */ -- res = sym_new_type(ctx, &PyFloat_Type); -+ if (oparg == NB_TRUE_DIVIDE || oparg == NB_INPLACE_TRUE_DIVIDE) { -+ res = sym_new_type(ctx, &PyFloat_Type); -+ } -+ else { -+ if (lhs_int && rhs_int) { -+ res = sym_new_type(ctx, &PyLong_Type); -+ } -+ else { -+ res = sym_new_type(ctx, &PyFloat_Type); -+ } -+ } - } - } -- else { -- res = sym_new_unknown(ctx); -- } - stack_pointer[-2] = res; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); -@@ -2314,16 +2258,14 @@ - } - - case _SWAP: { -- _Py_UopsSymbol *top_in; -- _Py_UopsSymbol *bottom_in; -- _Py_UopsSymbol *top_out; -- _Py_UopsSymbol *bottom_out; -- top_in = stack_pointer[-1]; -- bottom_in = stack_pointer[-2 - (oparg-2)]; -- bottom_out = bottom_in; -- top_out = top_in; -- stack_pointer[-2 - (oparg-2)] = top_out; -- stack_pointer[-1] = bottom_out; -+ JitOptSymbol **top; -+ JitOptSymbol **bottom; -+ top = &stack_pointer[-1]; -+ bottom = &stack_pointer[-2 - (oparg-2)]; -+ JitOptSymbol *temp = bottom[0]; -+ bottom[0] = top[0]; -+ top[0] = temp; -+ assert(oparg >= 2); - break; - } - -@@ -2335,6 +2277,8 @@ - - /* _MONITOR_JUMP_BACKWARD is not a viable micro-op for tier 2 */ - -+ /* _INSTRUMENTED_NOT_TAKEN is not a viable micro-op for tier 2 */ -+ - /* _INSTRUMENTED_POP_JUMP_IF_TRUE is not a viable micro-op for tier 2 */ - - /* _INSTRUMENTED_POP_JUMP_IF_FALSE is not a viable micro-op for tier 2 */ -@@ -2344,7 +2288,7 @@ - /* _INSTRUMENTED_POP_JUMP_IF_NOT_NONE is not a viable micro-op for tier 2 */ - - case _GUARD_IS_TRUE_POP: { -- _Py_UopsSymbol *flag; -+ JitOptSymbol *flag; - flag = stack_pointer[-1]; - if (sym_is_const(flag)) { - PyObject *value = sym_get_const(flag); -@@ -2361,7 +2305,7 @@ - } - - case _GUARD_IS_FALSE_POP: { -- _Py_UopsSymbol *flag; -+ JitOptSymbol *flag; - flag = stack_pointer[-1]; - if (sym_is_const(flag)) { - PyObject *value = sym_get_const(flag); -@@ -2378,7 +2322,7 @@ - } - - case _GUARD_IS_NONE_POP: { -- _Py_UopsSymbol *flag; -+ JitOptSymbol *flag; - flag = stack_pointer[-1]; - if (sym_is_const(flag)) { - PyObject *value = sym_get_const(flag); -@@ -2403,7 +2347,7 @@ - } - - case _GUARD_IS_NOT_NONE_POP: { -- _Py_UopsSymbol *flag; -+ JitOptSymbol *flag; - flag = stack_pointer[-1]; - if (sym_is_const(flag)) { - PyObject *value = sym_get_const(flag); -@@ -2461,7 +2405,7 @@ - } - - case _LOAD_CONST_INLINE: { -- _Py_UopsSymbol *value; -+ JitOptSymbol *value; - PyObject *ptr = (PyObject *)this_instr->operand0; - value = sym_new_const(ctx, ptr); - stack_pointer[0] = value; -@@ -2471,7 +2415,7 @@ - } - - case _LOAD_CONST_INLINE_BORROW: { -- _Py_UopsSymbol *value; -+ JitOptSymbol *value; - PyObject *ptr = (PyObject *)this_instr->operand0; - value = sym_new_const(ctx, ptr); - stack_pointer[0] = value; -@@ -2481,85 +2425,38 @@ - } - - case _POP_TOP_LOAD_CONST_INLINE_BORROW: { -- _Py_UopsSymbol *value; -+ JitOptSymbol *value; - value = sym_new_not_null(ctx); - stack_pointer[-1] = value; - break; - } - -- case _LOAD_CONST_INLINE_WITH_NULL: { -- _Py_UopsSymbol *value; -- _Py_UopsSymbol *null; -- PyObject *ptr = (PyObject *)this_instr->operand0; -- value = sym_new_const(ctx, ptr); -- null = sym_new_null(ctx); -- stack_pointer[0] = value; -- stack_pointer[1] = null; -- stack_pointer += 2; -- assert(WITHIN_STACK_BOUNDS()); -- break; -- } -- -- case _LOAD_CONST_INLINE_BORROW_WITH_NULL: { -- _Py_UopsSymbol *value; -- _Py_UopsSymbol *null; -- PyObject *ptr = (PyObject *)this_instr->operand0; -- value = sym_new_const(ctx, ptr); -- null = sym_new_null(ctx); -- stack_pointer[0] = value; -- stack_pointer[1] = null; -- stack_pointer += 2; -- assert(WITHIN_STACK_BOUNDS()); -- break; -- } -- - case _CHECK_FUNCTION: { - break; - } - - case _LOAD_GLOBAL_MODULE: { -- _Py_UopsSymbol *res; -- _Py_UopsSymbol *null = NULL; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); -- null = sym_new_null(ctx); - stack_pointer[0] = res; -- if (oparg & 1) stack_pointer[1] = null; -- stack_pointer += 1 + (oparg & 1); -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _LOAD_GLOBAL_BUILTINS: { -- _Py_UopsSymbol *res; -- _Py_UopsSymbol *null = NULL; -+ JitOptSymbol *res; - res = sym_new_not_null(ctx); -- null = sym_new_null(ctx); - stack_pointer[0] = res; -- if (oparg & 1) stack_pointer[1] = null; -- stack_pointer += 1 + (oparg & 1); -+ stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); - break; - } - - case _LOAD_ATTR_MODULE: { -- _Py_UopsSymbol *attr; -- _Py_UopsSymbol *null = NULL; -+ JitOptSymbol *attr; - attr = sym_new_not_null(ctx); -- null = sym_new_null(ctx); - stack_pointer[-1] = attr; -- if (oparg & 1) stack_pointer[0] = null; -- stack_pointer += (oparg & 1); -- assert(WITHIN_STACK_BOUNDS()); -- break; -- } -- -- case _INTERNAL_INCREMENT_OPT_COUNTER: { -- stack_pointer += -1; -- assert(WITHIN_STACK_BOUNDS()); -- break; -- } -- -- case _DYNAMIC_EXIT: { - break; - } - -@@ -2584,8 +2481,6 @@ - } - - case _ERROR_POP_N: { -- stack_pointer += -oparg; -- assert(WITHIN_STACK_BOUNDS()); - break; - } - -diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c -index 40cbf95e3d6..dcde8e7ce81 100644 ---- a/Python/optimizer_symbols.c -+++ b/Python/optimizer_symbols.c -@@ -28,11 +28,6 @@ - - Bottom: IS_NULL and NOT_NULL flags set, type and const_val NULL. - */ - --// Flags for below. --#define IS_NULL 1 << 0 --#define NOT_NULL 1 << 1 --#define NO_SPACE 1 << 2 -- - #ifdef Py_DEBUG - static inline int get_lltrace(void) { - char *uop_debug = Py_GETENV("PYTHON_OPT_DEBUG"); -@@ -48,187 +43,254 @@ - #define DPRINTF(level, ...) - #endif - --static _Py_UopsSymbol NO_SPACE_SYMBOL = { -- .flags = IS_NULL | NOT_NULL | NO_SPACE, -- .typ = NULL, -- .const_val = NULL, -- .type_version = 0, -+ -+static JitOptSymbol NO_SPACE_SYMBOL = { -+ .tag = JIT_SYM_BOTTOM_TAG - }; - --_Py_UopsSymbol * --out_of_space(_Py_UOpsContext *ctx) -+JitOptSymbol * -+out_of_space(JitOptContext *ctx) - { - ctx->done = true; - ctx->out_of_space = true; - return &NO_SPACE_SYMBOL; - } - --static _Py_UopsSymbol * --sym_new(_Py_UOpsContext *ctx) -+static JitOptSymbol * -+sym_new(JitOptContext *ctx) - { -- _Py_UopsSymbol *self = &ctx->t_arena.arena[ctx->t_arena.ty_curr_number]; -+ JitOptSymbol *self = &ctx->t_arena.arena[ctx->t_arena.ty_curr_number]; - if (ctx->t_arena.ty_curr_number >= ctx->t_arena.ty_max_number) { - OPT_STAT_INC(optimizer_failure_reason_no_memory); - DPRINTF(1, "out of space for symbolic expression type\n"); - return NULL; - } - ctx->t_arena.ty_curr_number++; -- self->flags = 0; -- self->typ = NULL; -- self->const_val = NULL; -- self->type_version = 0; -- -+ self->tag = JIT_SYM_UNKNOWN_TAG; - return self; - } - - static inline void --sym_set_flag(_Py_UopsSymbol *sym, int flag) --{ -- sym->flags |= flag; --} -- --static inline void --sym_set_bottom(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym) -+sym_set_bottom(JitOptContext *ctx, JitOptSymbol *sym) - { -- sym_set_flag(sym, IS_NULL | NOT_NULL); -- sym->typ = NULL; -- Py_CLEAR(sym->const_val); -+ sym->tag = JIT_SYM_BOTTOM_TAG; - ctx->done = true; - ctx->contradiction = true; - } - - bool --_Py_uop_sym_is_bottom(_Py_UopsSymbol *sym) -+_Py_uop_sym_is_bottom(JitOptSymbol *sym) - { -- if ((sym->flags & IS_NULL) && (sym->flags & NOT_NULL)) { -- assert(sym->flags == (IS_NULL | NOT_NULL)); -- assert(sym->typ == NULL); -- assert(sym->const_val == NULL); -- return true; -- } -- return false; -+ return sym->tag == JIT_SYM_BOTTOM_TAG; - } - - bool --_Py_uop_sym_is_not_null(_Py_UopsSymbol *sym) --{ -- return sym->flags == NOT_NULL; -+_Py_uop_sym_is_not_null(JitOptSymbol *sym) { -+ return sym->tag == JIT_SYM_NON_NULL_TAG || sym->tag > JIT_SYM_BOTTOM_TAG; - } - - bool --_Py_uop_sym_is_null(_Py_UopsSymbol *sym) -+_Py_uop_sym_is_const(JitOptSymbol *sym) - { -- return sym->flags == IS_NULL; -+ return sym->tag == JIT_SYM_KNOWN_VALUE_TAG; - } - - bool --_Py_uop_sym_is_const(_Py_UopsSymbol *sym) -+_Py_uop_sym_is_null(JitOptSymbol *sym) - { -- return sym->const_val != NULL; -+ return sym->tag == JIT_SYM_NULL_TAG; - } - -+ - PyObject * --_Py_uop_sym_get_const(_Py_UopsSymbol *sym) -+_Py_uop_sym_get_const(JitOptSymbol *sym) - { -- return sym->const_val; -+ if (sym->tag == JIT_SYM_KNOWN_VALUE_TAG) { -+ return sym->value.value; -+ } -+ return NULL; - } - - void --_Py_uop_sym_set_type(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym, PyTypeObject *typ) -+_Py_uop_sym_set_type(JitOptContext *ctx, JitOptSymbol *sym, PyTypeObject *typ) - { -- assert(typ != NULL && PyType_Check(typ)); -- if (sym->flags & IS_NULL) { -- sym_set_bottom(ctx, sym); -- return; -- } -- if (sym->typ != NULL) { -- if (sym->typ != typ) { -+ JitSymType tag = sym->tag; -+ switch(tag) { -+ case JIT_SYM_NULL_TAG: - sym_set_bottom(ctx, sym); - return; -- } -- } -- else { -- sym_set_flag(sym, NOT_NULL); -- sym->typ = typ; -+ case JIT_SYM_KNOWN_CLASS_TAG: -+ if (sym->cls.type != typ) { -+ sym_set_bottom(ctx, sym); -+ } -+ return; -+ case JIT_SYM_TYPE_VERSION_TAG: -+ if (sym->version.version == typ->tp_version_tag) { -+ sym->tag = JIT_SYM_KNOWN_CLASS_TAG; -+ sym->cls.type = typ; -+ sym->cls.version = typ->tp_version_tag; -+ } -+ else { -+ sym_set_bottom(ctx, sym); -+ } -+ return; -+ case JIT_SYM_KNOWN_VALUE_TAG: -+ if (Py_TYPE(sym->value.value) != typ) { -+ Py_CLEAR(sym->value.value); -+ sym_set_bottom(ctx, sym); -+ } -+ return; -+ case JIT_SYM_TUPLE_TAG: -+ if (typ != &PyTuple_Type) { -+ sym_set_bottom(ctx, sym); -+ } -+ return; -+ case JIT_SYM_BOTTOM_TAG: -+ return; -+ case JIT_SYM_NON_NULL_TAG: -+ case JIT_SYM_UNKNOWN_TAG: -+ sym->tag = JIT_SYM_KNOWN_CLASS_TAG; -+ sym->cls.version = 0; -+ sym->cls.type = typ; -+ return; - } - } - - bool --_Py_uop_sym_set_type_version(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym, unsigned int version) -+_Py_uop_sym_set_type_version(JitOptContext *ctx, JitOptSymbol *sym, unsigned int version) - { -- // if the type version was already set, then it must be different and we should set it to bottom -- if (sym->type_version) { -- sym_set_bottom(ctx, sym); -- return false; -+ JitSymType tag = sym->tag; -+ switch(tag) { -+ case JIT_SYM_NULL_TAG: -+ sym_set_bottom(ctx, sym); -+ return false; -+ case JIT_SYM_KNOWN_CLASS_TAG: -+ if (sym->cls.type->tp_version_tag != version) { -+ sym_set_bottom(ctx, sym); -+ return false; -+ } -+ else { -+ sym->cls.version = version; -+ return true; -+ } -+ case JIT_SYM_KNOWN_VALUE_TAG: -+ Py_CLEAR(sym->value.value); -+ sym_set_bottom(ctx, sym); -+ return false; -+ case JIT_SYM_TUPLE_TAG: -+ sym_set_bottom(ctx, sym); -+ return false; -+ case JIT_SYM_TYPE_VERSION_TAG: -+ if (sym->version.version == version) { -+ return true; -+ } -+ sym_set_bottom(ctx, sym); -+ return false; -+ case JIT_SYM_BOTTOM_TAG: -+ return false; -+ case JIT_SYM_NON_NULL_TAG: -+ case JIT_SYM_UNKNOWN_TAG: -+ sym->tag = JIT_SYM_TYPE_VERSION_TAG; -+ sym->version.version = version; -+ return true; - } -- sym->type_version = version; -- return true; -+ Py_UNREACHABLE(); -+} -+ -+static void make_const(JitOptSymbol *sym, PyObject *val) -+{ -+ sym->tag = JIT_SYM_KNOWN_VALUE_TAG; -+ sym->value.value = Py_NewRef(val); - } - - void --_Py_uop_sym_set_const(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym, PyObject *const_val) -+_Py_uop_sym_set_const(JitOptContext *ctx, JitOptSymbol *sym, PyObject *const_val) - { -- assert(const_val != NULL); -- if (sym->flags & IS_NULL) { -- sym_set_bottom(ctx, sym); -- } -- PyTypeObject *typ = Py_TYPE(const_val); -- if (sym->typ != NULL && sym->typ != typ) { -- sym_set_bottom(ctx, sym); -- } -- if (sym->const_val != NULL) { -- if (sym->const_val != const_val) { -- // TODO: What if they're equal? -+ JitSymType tag = sym->tag; -+ switch(tag) { -+ case JIT_SYM_NULL_TAG: - sym_set_bottom(ctx, sym); -- } -- } -- else { -- sym_set_flag(sym, NOT_NULL); -- sym->typ = typ; -- sym->const_val = Py_NewRef(const_val); -+ return; -+ case JIT_SYM_KNOWN_CLASS_TAG: -+ if (sym->cls.type != Py_TYPE(const_val)) { -+ sym_set_bottom(ctx, sym); -+ return; -+ } -+ make_const(sym, const_val); -+ return; -+ case JIT_SYM_KNOWN_VALUE_TAG: -+ if (sym->value.value != const_val) { -+ Py_CLEAR(sym->value.value); -+ sym_set_bottom(ctx, sym); -+ } -+ return; -+ case JIT_SYM_TUPLE_TAG: -+ sym_set_bottom(ctx, sym); -+ return; -+ case JIT_SYM_TYPE_VERSION_TAG: -+ if (sym->version.version != Py_TYPE(const_val)->tp_version_tag) { -+ sym_set_bottom(ctx, sym); -+ return; -+ } -+ make_const(sym, const_val); -+ return; -+ case JIT_SYM_BOTTOM_TAG: -+ return; -+ case JIT_SYM_NON_NULL_TAG: -+ case JIT_SYM_UNKNOWN_TAG: -+ make_const(sym, const_val); -+ return; - } - } - - void --_Py_uop_sym_set_null(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym) -+_Py_uop_sym_set_null(JitOptContext *ctx, JitOptSymbol *sym) - { -- if (_Py_uop_sym_is_not_null(sym)) { -+ if (sym->tag == JIT_SYM_UNKNOWN_TAG) { -+ sym->tag = JIT_SYM_NULL_TAG; -+ } -+ else if (sym->tag > JIT_SYM_NULL_TAG) { - sym_set_bottom(ctx, sym); - } -- sym_set_flag(sym, IS_NULL); - } - - void --_Py_uop_sym_set_non_null(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym) -+_Py_uop_sym_set_non_null(JitOptContext *ctx, JitOptSymbol *sym) - { -- if (_Py_uop_sym_is_null(sym)) { -+ if (sym->tag == JIT_SYM_UNKNOWN_TAG) { -+ sym->tag = JIT_SYM_NON_NULL_TAG; -+ } -+ else if (sym->tag == JIT_SYM_NULL_TAG) { - sym_set_bottom(ctx, sym); - } -- sym_set_flag(sym, NOT_NULL); - } - - --_Py_UopsSymbol * --_Py_uop_sym_new_unknown(_Py_UOpsContext *ctx) -+JitOptSymbol * -+_Py_uop_sym_new_unknown(JitOptContext *ctx) - { -- return sym_new(ctx); -+ JitOptSymbol *res = sym_new(ctx); -+ if (res == NULL) { -+ return out_of_space(ctx); -+ } -+ return res; - } - --_Py_UopsSymbol * --_Py_uop_sym_new_not_null(_Py_UOpsContext *ctx) -+JitOptSymbol * -+_Py_uop_sym_new_not_null(JitOptContext *ctx) - { -- _Py_UopsSymbol *res = _Py_uop_sym_new_unknown(ctx); -+ JitOptSymbol *res = sym_new(ctx); - if (res == NULL) { - return out_of_space(ctx); - } -- sym_set_flag(res, NOT_NULL); -+ res->tag = JIT_SYM_NON_NULL_TAG; - return res; - } - --_Py_UopsSymbol * --_Py_uop_sym_new_type(_Py_UOpsContext *ctx, PyTypeObject *typ) -+JitOptSymbol * -+_Py_uop_sym_new_type(JitOptContext *ctx, PyTypeObject *typ) - { -- _Py_UopsSymbol *res = sym_new(ctx); -+ JitOptSymbol *res = sym_new(ctx); - if (res == NULL) { - return out_of_space(ctx); - } -@@ -237,11 +299,11 @@ - } - - // Adds a new reference to const_val, owned by the symbol. --_Py_UopsSymbol * --_Py_uop_sym_new_const(_Py_UOpsContext *ctx, PyObject *const_val) -+JitOptSymbol * -+_Py_uop_sym_new_const(JitOptContext *ctx, PyObject *const_val) - { - assert(const_val != NULL); -- _Py_UopsSymbol *res = sym_new(ctx); -+ JitOptSymbol *res = sym_new(ctx); - if (res == NULL) { - return out_of_space(ctx); - } -@@ -249,10 +311,10 @@ - return res; - } - --_Py_UopsSymbol * --_Py_uop_sym_new_null(_Py_UOpsContext *ctx) -+JitOptSymbol * -+_Py_uop_sym_new_null(JitOptContext *ctx) - { -- _Py_UopsSymbol *null_sym = _Py_uop_sym_new_unknown(ctx); -+ JitOptSymbol *null_sym = sym_new(ctx); - if (null_sym == NULL) { - return out_of_space(ctx); - } -@@ -261,64 +323,105 @@ - } - - PyTypeObject * --_Py_uop_sym_get_type(_Py_UopsSymbol *sym) -+_Py_uop_sym_get_type(JitOptSymbol *sym) - { -- if (_Py_uop_sym_is_bottom(sym)) { -- return NULL; -- } -- return sym->typ; -+ JitSymType tag = sym->tag; -+ switch(tag) { -+ case JIT_SYM_NULL_TAG: -+ case JIT_SYM_TYPE_VERSION_TAG: -+ case JIT_SYM_BOTTOM_TAG: -+ case JIT_SYM_NON_NULL_TAG: -+ case JIT_SYM_UNKNOWN_TAG: -+ return NULL; -+ case JIT_SYM_KNOWN_CLASS_TAG: -+ return sym->cls.type; -+ case JIT_SYM_KNOWN_VALUE_TAG: -+ return Py_TYPE(sym->value.value); -+ case JIT_SYM_TUPLE_TAG: -+ return &PyTuple_Type; -+ } -+ Py_UNREACHABLE(); - } - - unsigned int --_Py_uop_sym_get_type_version(_Py_UopsSymbol *sym) -+_Py_uop_sym_get_type_version(JitOptSymbol *sym) - { -- return sym->type_version; -+ JitSymType tag = sym->tag; -+ switch(tag) { -+ case JIT_SYM_NULL_TAG: -+ case JIT_SYM_BOTTOM_TAG: -+ case JIT_SYM_NON_NULL_TAG: -+ case JIT_SYM_UNKNOWN_TAG: -+ return 0; -+ case JIT_SYM_TYPE_VERSION_TAG: -+ return sym->version.version; -+ case JIT_SYM_KNOWN_CLASS_TAG: -+ return sym->cls.version; -+ case JIT_SYM_KNOWN_VALUE_TAG: -+ return Py_TYPE(sym->value.value)->tp_version_tag; -+ case JIT_SYM_TUPLE_TAG: -+ return PyTuple_Type.tp_version_tag; -+ } -+ Py_UNREACHABLE(); - } - - bool --_Py_uop_sym_has_type(_Py_UopsSymbol *sym) -+_Py_uop_sym_has_type(JitOptSymbol *sym) - { -- if (_Py_uop_sym_is_bottom(sym)) { -- return false; -- } -- return sym->typ != NULL; -+ JitSymType tag = sym->tag; -+ switch(tag) { -+ case JIT_SYM_NULL_TAG: -+ case JIT_SYM_TYPE_VERSION_TAG: -+ case JIT_SYM_BOTTOM_TAG: -+ case JIT_SYM_NON_NULL_TAG: -+ case JIT_SYM_UNKNOWN_TAG: -+ return false; -+ case JIT_SYM_KNOWN_CLASS_TAG: -+ case JIT_SYM_KNOWN_VALUE_TAG: -+ case JIT_SYM_TUPLE_TAG: -+ return true; -+ } -+ Py_UNREACHABLE(); - } - - bool --_Py_uop_sym_matches_type(_Py_UopsSymbol *sym, PyTypeObject *typ) -+_Py_uop_sym_matches_type(JitOptSymbol *sym, PyTypeObject *typ) - { - assert(typ != NULL && PyType_Check(typ)); - return _Py_uop_sym_get_type(sym) == typ; - } - - bool --_Py_uop_sym_matches_type_version(_Py_UopsSymbol *sym, unsigned int version) -+_Py_uop_sym_matches_type_version(JitOptSymbol *sym, unsigned int version) - { - return _Py_uop_sym_get_type_version(sym) == version; - } - -- - int --_Py_uop_sym_truthiness(_Py_UopsSymbol *sym) --{ -- /* There are some non-constant values for -- * which `bool(val)` always evaluates to -- * True or False, such as tuples with known -- * length, but unknown contents, or bound-methods. -- * This function will need updating -- * should we support those values. -- */ -- if (_Py_uop_sym_is_bottom(sym)) { -- return -1; -- } -- if (!_Py_uop_sym_is_const(sym)) { -- return -1; -- } -- PyObject *value = _Py_uop_sym_get_const(sym); -+_Py_uop_sym_truthiness(JitOptSymbol *sym) -+{ -+ switch(sym->tag) { -+ case JIT_SYM_NULL_TAG: -+ case JIT_SYM_TYPE_VERSION_TAG: -+ case JIT_SYM_BOTTOM_TAG: -+ case JIT_SYM_NON_NULL_TAG: -+ case JIT_SYM_UNKNOWN_TAG: -+ return -1; -+ case JIT_SYM_KNOWN_CLASS_TAG: -+ /* TODO : -+ * Instances of some classes are always -+ * true. We should return 1 in those cases */ -+ return -1; -+ case JIT_SYM_KNOWN_VALUE_TAG: -+ break; -+ case JIT_SYM_TUPLE_TAG: -+ return sym->tuple.length != 0; -+ } -+ PyObject *value = sym->value.value; -+ /* Only handle a few known safe types */ - if (value == Py_None) { - return 0; - } -- /* Only handle a few known safe types */ - PyTypeObject *tp = Py_TYPE(value); - if (tp == &PyLong_Type) { - return !_PyLong_IsZero((PyLongObject *)value); -@@ -332,13 +435,84 @@ - return -1; - } - -+static JitOptSymbol * -+allocation_base(JitOptContext *ctx) -+{ -+ return ctx->t_arena.arena; -+} -+ -+JitOptSymbol * -+_Py_uop_sym_new_tuple(JitOptContext *ctx, int size, JitOptSymbol **args) -+{ -+ JitOptSymbol *res = sym_new(ctx); -+ if (res == NULL) { -+ return out_of_space(ctx); -+ } -+ if (size > MAX_SYMBOLIC_TUPLE_SIZE) { -+ res->tag = JIT_SYM_KNOWN_CLASS_TAG; -+ res->cls.type = &PyTuple_Type; -+ } -+ else { -+ res->tag = JIT_SYM_TUPLE_TAG; -+ res->tuple.length = size; -+ for (int i = 0; i < size; i++) { -+ res->tuple.items[i] = (uint16_t)(args[i] - allocation_base(ctx)); -+ } -+ } -+ return res; -+} -+ -+JitOptSymbol * -+_Py_uop_sym_tuple_getitem(JitOptContext *ctx, JitOptSymbol *sym, int item) -+{ -+ assert(item >= 0); -+ if (sym->tag == JIT_SYM_KNOWN_VALUE_TAG) { -+ PyObject *tuple = sym->value.value; -+ if (PyTuple_CheckExact(tuple) && item < PyTuple_GET_SIZE(tuple)) { -+ return _Py_uop_sym_new_const(ctx, PyTuple_GET_ITEM(tuple, item)); -+ } -+ } -+ else if (sym->tag == JIT_SYM_TUPLE_TAG && item < sym->tuple.length) { -+ return allocation_base(ctx) + sym->tuple.items[item]; -+ } -+ return _Py_uop_sym_new_unknown(ctx); -+} -+ -+int -+_Py_uop_sym_tuple_length(JitOptSymbol *sym) -+{ -+ if (sym->tag == JIT_SYM_KNOWN_VALUE_TAG) { -+ PyObject *tuple = sym->value.value; -+ if (PyTuple_CheckExact(tuple)) { -+ return PyTuple_GET_SIZE(tuple); -+ } -+ } -+ else if (sym->tag == JIT_SYM_TUPLE_TAG) { -+ return sym->tuple.length; -+ } -+ return -1; -+} -+ -+// Return true if known to be immortal. -+bool -+_Py_uop_sym_is_immortal(JitOptSymbol *sym) -+{ -+ if (sym->tag == JIT_SYM_KNOWN_VALUE_TAG) { -+ return _Py_IsImmortal(sym->value.value); -+ } -+ if (sym->tag == JIT_SYM_KNOWN_CLASS_TAG) { -+ return sym->cls.type == &PyBool_Type; -+ } -+ return false; -+} -+ - // 0 on success, -1 on error. - _Py_UOpsAbstractFrame * - _Py_uop_frame_new( -- _Py_UOpsContext *ctx, -+ JitOptContext *ctx, - PyCodeObject *co, - int curr_stackentries, -- _Py_UopsSymbol **args, -+ JitOptSymbol **args, - int arg_len) - { - assert(ctx->curr_frame_depth < MAX_ABSTRACT_FRAME_DEPTH); -@@ -363,14 +537,14 @@ - } - - for (int i = arg_len; i < co->co_nlocalsplus; i++) { -- _Py_UopsSymbol *local = _Py_uop_sym_new_unknown(ctx); -+ JitOptSymbol *local = _Py_uop_sym_new_unknown(ctx); - frame->locals[i] = local; - } - - - // Initialize the stack as well - for (int i = 0; i < curr_stackentries; i++) { -- _Py_UopsSymbol *stackvar = _Py_uop_sym_new_unknown(ctx); -+ JitOptSymbol *stackvar = _Py_uop_sym_new_unknown(ctx); - frame->stack[i] = stackvar; - } - -@@ -378,7 +552,7 @@ - } - - void --_Py_uop_abstractcontext_fini(_Py_UOpsContext *ctx) -+_Py_uop_abstractcontext_fini(JitOptContext *ctx) - { - if (ctx == NULL) { - return; -@@ -386,13 +560,17 @@ - ctx->curr_frame_depth = 0; - int tys = ctx->t_arena.ty_curr_number; - for (int i = 0; i < tys; i++) { -- Py_CLEAR(ctx->t_arena.arena[i].const_val); -+ JitOptSymbol *sym = &ctx->t_arena.arena[i]; -+ if (sym->tag == JIT_SYM_KNOWN_VALUE_TAG) { -+ Py_CLEAR(sym->value.value); -+ } - } - } - - void --_Py_uop_abstractcontext_init(_Py_UOpsContext *ctx) -+_Py_uop_abstractcontext_init(JitOptContext *ctx) - { -+ static_assert(sizeof(JitOptSymbol) <= 2*sizeof(uint64_t)); - ctx->limit = ctx->locals_and_stack + MAX_ABSTRACT_INTERP_SIZE; - ctx->n_consumed = ctx->locals_and_stack; - #ifdef Py_DEBUG // Aids debugging a little. There should never be NULL in the abstract interpreter. -@@ -410,7 +588,7 @@ - } - - int --_Py_uop_frame_pop(_Py_UOpsContext *ctx) -+_Py_uop_frame_pop(JitOptContext *ctx) - { - _Py_UOpsAbstractFrame *frame = ctx->frame; - ctx->n_consumed = frame->locals; -@@ -431,26 +609,25 @@ - } \ - } while (0) - --static _Py_UopsSymbol * --make_bottom(_Py_UOpsContext *ctx) -+static JitOptSymbol * -+make_bottom(JitOptContext *ctx) - { -- _Py_UopsSymbol *sym = _Py_uop_sym_new_unknown(ctx); -- _Py_uop_sym_set_null(ctx, sym); -- _Py_uop_sym_set_non_null(ctx, sym); -+ JitOptSymbol *sym = sym_new(ctx); -+ sym->tag = JIT_SYM_BOTTOM_TAG; - return sym; - } - - PyObject * - _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) - { -- _Py_UOpsContext context; -- _Py_UOpsContext *ctx = &context; -+ JitOptContext context; -+ JitOptContext *ctx = &context; - _Py_uop_abstractcontext_init(ctx); - PyObject *val_42 = NULL; - PyObject *val_43 = NULL; - - // Use a single 'sym' variable so copy-pasting tests is easier. -- _Py_UopsSymbol *sym = _Py_uop_sym_new_unknown(ctx); -+ JitOptSymbol *sym = _Py_uop_sym_new_unknown(ctx); - if (sym == NULL) { - goto fail; - } -@@ -510,6 +687,7 @@ - TEST_PREDICATE(_Py_uop_sym_is_const(sym), "42 is not a constant"); - TEST_PREDICATE(_Py_uop_sym_get_const(sym) != NULL, "42 as constant is NULL"); - TEST_PREDICATE(_Py_uop_sym_get_const(sym) == val_42, "42 as constant isn't 42"); -+ TEST_PREDICATE(_Py_uop_sym_is_immortal(sym), "42 is not immortal"); - - _Py_uop_sym_set_type(ctx, sym, &PyLong_Type); // Should be a no-op - TEST_PREDICATE(_Py_uop_sym_matches_type(sym, &PyLong_Type), "(42 and 42) isn't an int"); -@@ -518,6 +696,9 @@ - _Py_uop_sym_set_type(ctx, sym, &PyFloat_Type); // Should make it bottom - TEST_PREDICATE(_Py_uop_sym_is_bottom(sym), "(42 and float) isn't bottom"); - -+ sym = _Py_uop_sym_new_type(ctx, &PyBool_Type); -+ TEST_PREDICATE(_Py_uop_sym_is_immortal(sym), "a bool is not immortal"); -+ - sym = _Py_uop_sym_new_type(ctx, &PyLong_Type); - if (sym == NULL) { - goto fail; -@@ -534,15 +715,37 @@ - sym = _Py_uop_sym_new_const(ctx, PyLong_FromLong(0)); - TEST_PREDICATE(_Py_uop_sym_truthiness(sym) == 0, "bool(0) is not False"); - -+ JitOptSymbol *i1 = _Py_uop_sym_new_type(ctx, &PyFloat_Type); -+ JitOptSymbol *i2 = _Py_uop_sym_new_const(ctx, val_43); -+ JitOptSymbol *array[2] = { i1, i2 }; -+ sym = _Py_uop_sym_new_tuple(ctx, 2, array); -+ TEST_PREDICATE( -+ _Py_uop_sym_matches_type(_Py_uop_sym_tuple_getitem(ctx, sym, 0), &PyFloat_Type), -+ "tuple item does not match value used to create tuple" -+ ); -+ TEST_PREDICATE( -+ _Py_uop_sym_get_const(_Py_uop_sym_tuple_getitem(ctx, sym, 1)) == val_43, -+ "tuple item does not match value used to create tuple" -+ ); -+ PyObject *pair[2] = { val_42, val_43 }; -+ PyObject *tuple = _PyTuple_FromArray(pair, 2); -+ sym = _Py_uop_sym_new_const(ctx, tuple); -+ TEST_PREDICATE( -+ _Py_uop_sym_get_const(_Py_uop_sym_tuple_getitem(ctx, sym, 1)) == val_43, -+ "tuple item does not match value used to create tuple" -+ ); -+ - _Py_uop_abstractcontext_fini(ctx); - Py_DECREF(val_42); - Py_DECREF(val_43); -+ Py_DECREF(tuple); - Py_RETURN_NONE; - - fail: - _Py_uop_abstractcontext_fini(ctx); - Py_XDECREF(val_42); - Py_XDECREF(val_43); -+ Py_DECREF(tuple); - return NULL; - } - -diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c -index 06418123d6d..300a871d2cc 100644 ---- a/Python/pylifecycle.c -+++ b/Python/pylifecycle.c -@@ -46,8 +46,25 @@ - - #if defined(__APPLE__) - # include -+# include - # include --# include -+// The os_log unified logging APIs were introduced in macOS 10.12, iOS 10.0, -+// tvOS 10.0, and watchOS 3.0; -+# if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE -+# define HAS_APPLE_SYSTEM_LOG 1 -+# elif defined(TARGET_OS_OSX) && TARGET_OS_OSX -+# if defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12 -+# define HAS_APPLE_SYSTEM_LOG 1 -+# else -+# define HAS_APPLE_SYSTEM_LOG 0 -+# endif -+# else -+# define HAS_APPLE_SYSTEM_LOG 0 -+# endif -+ -+# if HAS_APPLE_SYSTEM_LOG -+# include -+# endif - #endif - - #ifdef HAVE_SIGNAL_H -@@ -77,7 +94,7 @@ - #ifdef __ANDROID__ - static PyStatus init_android_streams(PyThreadState *tstate); - #endif --#if defined(__APPLE__) -+#if defined(__APPLE__) && HAS_APPLE_SYSTEM_LOG - static PyStatus init_apple_streams(PyThreadState *tstate); - #endif - static void wait_for_thread_shutdown(PyThreadState *tstate); -@@ -94,23 +111,7 @@ - _Py_COMP_DIAG_PUSH - _Py_COMP_DIAG_IGNORE_DEPR_DECLS - --#if defined(MS_WINDOWS) -- --#pragma section("PyRuntime", read, write) --__declspec(allocate("PyRuntime")) -- --#elif defined(__APPLE__) -- --__attribute__(( -- section(SEG_DATA ",PyRuntime") --)) -- --#endif -- --_PyRuntimeState _PyRuntime --#if defined(__linux__) && (defined(__GNUC__) || defined(__clang__)) --__attribute__ ((section (".PyRuntime"))) --#endif -+GENERATE_DEBUG_SECTION(PyRuntime, _PyRuntimeState _PyRuntime) - = _PyRuntimeState_INIT(_PyRuntime, _Py_Debug_Cookie); - _Py_COMP_DIAG_POP - -@@ -427,40 +428,6 @@ - } - - --int --_PyInterpreterState_SetConfig(const PyConfig *src_config) --{ -- PyThreadState *tstate = _PyThreadState_GET(); -- int res = -1; -- -- PyConfig config; -- PyConfig_InitPythonConfig(&config); -- PyStatus status = _PyConfig_Copy(&config, src_config); -- if (_PyStatus_EXCEPTION(status)) { -- _PyErr_SetFromPyStatus(status); -- goto done; -- } -- -- status = _PyConfig_Read(&config, 1); -- if (_PyStatus_EXCEPTION(status)) { -- _PyErr_SetFromPyStatus(status); -- goto done; -- } -- -- status = _PyConfig_Copy(&tstate->interp->config, &config); -- if (_PyStatus_EXCEPTION(status)) { -- _PyErr_SetFromPyStatus(status); -- goto done; -- } -- -- res = interpreter_update_config(tstate, 0); -- --done: -- PyConfig_Clear(&config); -- return res; --} -- -- - /* Global initializations. Can be undone by Py_Finalize(). Don't - call this twice without an intervening Py_Finalize() call. - -@@ -690,7 +657,12 @@ - // the settings are loaded (so that feature_flags are set) but before - // any calls are made to obmalloc functions. - if (_PyMem_init_obmalloc(interp) < 0) { -- return _PyStatus_NO_MEMORY(); -+ return _PyStatus_NO_MEMORY(); -+ } -+ -+ status = _PyTraceMalloc_Init(); -+ if (_PyStatus_EXCEPTION(status)) { -+ return status; - } - - PyThreadState *tstate = _PyThreadState_New(interp, -@@ -1262,7 +1234,7 @@ - return status; - } - #endif --#if defined(__APPLE__) -+#if defined(__APPLE__) && HAS_APPLE_SYSTEM_LOG - if (config->use_system_logger) { - status = init_apple_streams(tstate); - if (_PyStatus_EXCEPTION(status)) { -@@ -1334,14 +1306,7 @@ - } else - #endif - { -- PyObject *opt = _PyOptimizer_NewUOpOptimizer(); -- if (opt == NULL) { -- return _PyStatus_ERR("can't initialize optimizer"); -- } -- if (_Py_SetTier2Optimizer((_PyOptimizerObject *)opt)) { -- return _PyStatus_ERR("can't install optimizer"); -- } -- Py_DECREF(opt); -+ interp->jit = true; - } - } - } -@@ -1483,18 +1448,6 @@ - } - - --PyStatus --_Py_InitializeMain(void) --{ -- PyStatus status = _PyRuntime_Initialize(); -- if (_PyStatus_EXCEPTION(status)) { -- return status; -- } -- PyThreadState *tstate = _PyThreadState_GET(); -- return pyinit_main(tstate); --} -- -- - static void - finalize_modules_delete_special(PyThreadState *tstate, int verbose) - { -@@ -1522,13 +1475,15 @@ - PySys_WriteStderr("# clear builtins._\n"); - } - if (PyDict_SetItemString(interp->builtins, "_", Py_None) < 0) { -- PyErr_FormatUnraisable("Exception ignored on setting builtin variable _"); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "setting builtin variable _"); - } - - const char * const *p; - for (p = sys_deletes; *p != NULL; p++) { - if (_PySys_ClearAttrString(interp, *p, verbose) < 0) { -- PyErr_FormatUnraisable("Exception ignored on clearing sys.%s", *p); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "clearing sys.%s", *p); - } - } - for (p = sys_files; *p != NULL; p+=2) { -@@ -1539,13 +1494,15 @@ - } - PyObject *value; - if (PyDict_GetItemStringRef(interp->sysdict, orig_name, &value) < 0) { -- PyErr_FormatUnraisable("Exception ignored on restoring sys.%s", name); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "restoring sys.%s", name); - } - if (value == NULL) { - value = Py_NewRef(Py_None); - } - if (PyDict_SetItemString(interp->sysdict, name, value) < 0) { -- PyErr_FormatUnraisable("Exception ignored on restoring sys.%s", name); -+ PyErr_FormatUnraisable("Exception ignored while " -+ "restoring sys.%s", name); - } - Py_DECREF(value); - } -@@ -1557,7 +1514,7 @@ - { - PyObject *weaklist = PyList_New(0); - if (weaklist == NULL) { -- PyErr_FormatUnraisable("Exception ignored on removing modules"); -+ PyErr_FormatUnraisable("Exception ignored while removing modules"); - } - - #define STORE_MODULE_WEAKREF(name, mod) \ -@@ -1566,13 +1523,13 @@ - if (wr) { \ - PyObject *tup = PyTuple_Pack(2, name, wr); \ - if (!tup || PyList_Append(weaklist, tup) < 0) { \ -- PyErr_FormatUnraisable("Exception ignored on removing modules"); \ -+ PyErr_FormatUnraisable("Exception ignored while removing modules"); \ - } \ - Py_XDECREF(tup); \ - Py_DECREF(wr); \ - } \ - else { \ -- PyErr_FormatUnraisable("Exception ignored on removing modules"); \ -+ PyErr_FormatUnraisable("Exception ignored while removing modules"); \ - } \ - } - -@@ -1583,7 +1540,7 @@ - } \ - STORE_MODULE_WEAKREF(name, mod); \ - if (PyObject_SetItem(modules, name, Py_None) < 0) { \ -- PyErr_FormatUnraisable("Exception ignored on removing modules"); \ -+ PyErr_FormatUnraisable("Exception ignored while removing modules"); \ - } \ - } - -@@ -1597,14 +1554,14 @@ - else { - PyObject *iterator = PyObject_GetIter(modules); - if (iterator == NULL) { -- PyErr_FormatUnraisable("Exception ignored on removing modules"); -+ PyErr_FormatUnraisable("Exception ignored while removing modules"); - } - else { - PyObject *key; - while ((key = PyIter_Next(iterator))) { - PyObject *value = PyObject_GetItem(modules, key); - if (value == NULL) { -- PyErr_FormatUnraisable("Exception ignored on removing modules"); -+ PyErr_FormatUnraisable("Exception ignored while removing modules"); - continue; - } - CLEAR_MODULE(key, value); -@@ -1612,7 +1569,7 @@ - Py_DECREF(key); - } - if (PyErr_Occurred()) { -- PyErr_FormatUnraisable("Exception ignored on removing modules"); -+ PyErr_FormatUnraisable("Exception ignored while removing modules"); - } - Py_DECREF(iterator); - } -@@ -1632,7 +1589,7 @@ - } - else { - if (PyObject_CallMethodNoArgs(modules, &_Py_ID(clear)) == NULL) { -- PyErr_FormatUnraisable("Exception ignored on clearing sys.modules"); -+ PyErr_FormatUnraisable("Exception ignored while clearing sys.modules"); - } - } - } -@@ -1644,11 +1601,11 @@ - PyInterpreterState *interp = tstate->interp; - PyObject *dict = PyDict_Copy(interp->builtins); - if (dict == NULL) { -- PyErr_FormatUnraisable("Exception ignored on restoring builtins"); -+ PyErr_FormatUnraisable("Exception ignored while restoring builtins"); - } - PyDict_Clear(interp->builtins); - if (PyDict_Update(interp->builtins, interp->builtins_copy)) { -- PyErr_FormatUnraisable("Exception ignored on restoring builtins"); -+ PyErr_FormatUnraisable("Exception ignored while restoring builtins"); - } - Py_XDECREF(dict); - } -@@ -1705,11 +1662,10 @@ - { - PyInterpreterState *interp = tstate->interp; - -+ // Invalidate all executors and turn off JIT: -+ interp->jit = false; - #ifdef _Py_TIER2 -- // Invalidate all executors and turn off tier 2 optimizer - _Py_Executors_InvalidateAll(interp, 0); -- _PyOptimizerObject *old = _Py_SetOptimizer(interp, NULL); -- Py_XDECREF(old); - #endif - - // Stop watching __builtin__ modifications -@@ -1821,7 +1777,7 @@ - - if (fout != NULL && fout != Py_None && !file_is_closed(fout)) { - if (_PyFile_Flush(fout) < 0) { -- PyErr_FormatUnraisable("Exception ignored on flushing sys.stdout"); -+ PyErr_FormatUnraisable("Exception ignored while flushing sys.stdout"); - status = -1; - } - } -@@ -2206,6 +2162,7 @@ - - finalize_interp_clear(tstate); - -+ - #ifdef Py_TRACE_REFS - /* Display addresses (& refcnts) of all objects still alive. - * An address can be used to find the repr of the object, printed -@@ -2656,7 +2613,7 @@ - - #ifdef HAVE_WINDOWS_CONSOLE_IO - /* Windows console IO is always UTF-8 encoded */ -- PyTypeObject *winconsoleio_type = (PyTypeObject *)_PyImport_GetModuleAttr( -+ PyTypeObject *winconsoleio_type = (PyTypeObject *)PyImport_ImportModuleAttr( - &_Py_ID(_io), &_Py_ID(_WindowsConsoleIO)); - if (winconsoleio_type == NULL) { - goto error; -@@ -2761,7 +2718,7 @@ - goto error; - } - -- if (!(wrapper = _PyImport_GetModuleAttrString("io", "open"))) { -+ if (!(wrapper = PyImport_ImportModuleAttrString("io", "open"))) { - goto error; - } - -@@ -2946,7 +2903,7 @@ - - #endif // __ANDROID__ - --#if defined(__APPLE__) -+#if defined(__APPLE__) && HAS_APPLE_SYSTEM_LOG - - static PyObject * - apple_log_write_impl(PyObject *self, PyObject *args) -@@ -2957,14 +2914,9 @@ - return NULL; - } - -- // Call the underlying Apple logging API. The os_log unified logging APIs -- // were introduced in macOS 10.12, iOS 10.0, tvOS 10.0, and watchOS 3.0; -- // this call is a no-op on older versions. -- #if TARGET_OS_IPHONE || (TARGET_OS_OSX && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12) - // Pass the user-provided text through explicit %s formatting - // to avoid % literals being interpreted as a formatting directive. - os_log_with_type(OS_LOG_DEFAULT, logtype, "%s", text); -- #endif - Py_RETURN_NONE; - } - -@@ -2999,7 +2951,6 @@ - if (result == NULL) { - goto error; - } -- - goto done; - - error: -@@ -3013,7 +2964,7 @@ - return status; - } - --#endif // __APPLE__ -+#endif // __APPLE__ && HAS_APPLE_SYSTEM_LOG - - - static void -@@ -3023,7 +2974,11 @@ - PUTS(fd, "\n"); - - /* display the current Python stack */ -+#ifndef Py_GIL_DISABLED - _Py_DumpTracebackThreads(fd, interp, tstate); -+#else -+ _Py_DumpTraceback(fd, tstate); -+#endif - } - - /* Print the current exception (if an exception is set) with its traceback, -diff --git a/Python/pystate.c b/Python/pystate.c -index 839413a65a4..89a652850e9 100644 ---- a/Python/pystate.c -+++ b/Python/pystate.c -@@ -19,6 +19,7 @@ - #include "pycore_pymem.h" // _PyMem_SetDefaultAllocator() - #include "pycore_pystate.h" - #include "pycore_runtime_init.h" // _PyRuntimeState_INIT -+#include "pycore_stackref.h" // Py_STACKREF_DEBUG - #include "pycore_obmalloc.h" // _PyMem_obmalloc_state_on_heap() - #include "pycore_uniqueid.h" // _PyObject_FinalizePerThreadRefcounts() - -@@ -642,6 +643,8 @@ - _Py_brc_init_state(interp); - #endif - llist_init(&interp->mem_free_queue.head); -+ llist_init(&interp->asyncio_tasks_head); -+ interp->asyncio_tasks_lock = (PyMutex){0}; - for (int i = 0; i < _PY_MONITORING_UNGROUPED_EVENTS; i++) { - interp->monitors.tools[i] = 0; - } -@@ -654,15 +657,30 @@ - } - interp->sys_profile_initialized = false; - interp->sys_trace_initialized = false; --#ifdef _Py_TIER2 -- (void)_Py_SetOptimizer(interp, NULL); -+ interp->jit = false; - interp->executor_list_head = NULL; - interp->trace_run_counter = JIT_CLEANUP_THRESHOLD; --#endif - if (interp != &runtime->_main_interpreter) { - /* Fix the self-referential, statically initialized fields. */ - interp->dtoa = (struct _dtoa_state)_dtoa_state_INIT(interp); - } -+#if !defined(Py_GIL_DISABLED) && defined(Py_STACKREF_DEBUG) -+ interp->next_stackref = 1; -+ _Py_hashtable_allocator_t alloc = { -+ .malloc = malloc, -+ .free = free, -+ }; -+ interp->stackref_debug_table = _Py_hashtable_new_full( -+ _Py_hashtable_hash_ptr, -+ _Py_hashtable_compare_direct, -+ NULL, -+ NULL, -+ &alloc -+ ); -+ _Py_stackref_associate(interp, Py_None, PyStackRef_None); -+ _Py_stackref_associate(interp, Py_False, PyStackRef_False); -+ _Py_stackref_associate(interp, Py_True, PyStackRef_True); -+#endif - - interp->_initialized = 1; - return _PyStatus_OK(); -@@ -768,6 +786,11 @@ - return interp; - } - -+#if !defined(Py_GIL_DISABLED) && defined(Py_STACKREF_DEBUG) -+extern void -+_Py_stackref_report_leaks(PyInterpreterState *interp); -+#endif -+ - static void - interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) - { -@@ -806,12 +829,6 @@ - tstate->_status.cleared = 0; - } - --#ifdef _Py_TIER2 -- _PyOptimizerObject *old = _Py_SetOptimizer(interp, NULL); -- assert(old != NULL); -- Py_DECREF(old); --#endif -- - /* It is possible that any of the objects below have a finalizer - that runs Python code or otherwise relies on a thread state - or even the interpreter state. For now we trust that isn't -@@ -877,6 +894,12 @@ - Py_CLEAR(interp->sysdict); - Py_CLEAR(interp->builtins); - -+#if !defined(Py_GIL_DISABLED) && defined(Py_STACKREF_DEBUG) -+ _Py_stackref_report_leaks(interp); -+ _Py_hashtable_destroy(interp->stackref_debug_table); -+ interp->stackref_debug_table = NULL; -+#endif -+ - if (tstate->interp == interp) { - /* We are now safe to fix tstate->_status.cleared. */ - // XXX Do this (much) earlier? -@@ -1486,11 +1509,12 @@ - tstate->dict_global_version = 0; - - _tstate->asyncio_running_loop = NULL; -+ _tstate->asyncio_running_task = NULL; - - tstate->delete_later = NULL; - - llist_init(&_tstate->mem_free_queue); -- -+ llist_init(&_tstate->asyncio_tasks_head); - if (interp->stoptheworld.requested || _PyRuntime.stoptheworld.requested) { - // Start in the suspended state if there is an ongoing stop-the-world. - tstate->state = _Py_THREAD_SUSPENDED; -@@ -1668,6 +1692,15 @@ - Py_CLEAR(tstate->threading_local_sentinel); - - Py_CLEAR(((_PyThreadStateImpl *)tstate)->asyncio_running_loop); -+ Py_CLEAR(((_PyThreadStateImpl *)tstate)->asyncio_running_task); -+ -+ -+ PyMutex_Lock(&tstate->interp->asyncio_tasks_lock); -+ // merge any lingering tasks from thread state to interpreter's -+ // tasks list -+ llist_concat(&tstate->interp->asyncio_tasks_head, -+ &((_PyThreadStateImpl *)tstate)->asyncio_tasks_head); -+ PyMutex_Unlock(&tstate->interp->asyncio_tasks_lock); - - Py_CLEAR(tstate->dict); - Py_CLEAR(tstate->async_exc); -@@ -2851,24 +2884,9 @@ - } - - --int --_PyInterpreterState_GetConfigCopy(PyConfig *config) --{ -- PyInterpreterState *interp = _PyInterpreterState_GET(); -- -- PyStatus status = _PyConfig_Copy(config, &interp->config); -- if (PyStatus_Exception(status)) { -- _PyErr_SetFromPyStatus(status); -- return -1; -- } -- return 0; --} -- -- - const PyConfig* - _Py_GetConfig(void) - { -- assert(PyGILState_Check()); - PyThreadState *tstate = current_fast_get(); - _Py_EnsureTstateNotNULL(tstate); - return _PyInterpreterState_GetConfig(tstate->interp); -diff --git a/Python/pythonrun.c b/Python/pythonrun.c -index 31e065ff00d..ae0df9685ac 100644 ---- a/Python/pythonrun.c -+++ b/Python/pythonrun.c -@@ -467,7 +467,7 @@ - fclose(fp); - } - -- pyc_fp = _Py_fopen_obj(filename, "rb"); -+ pyc_fp = Py_fopen(filename, "rb"); - if (pyc_fp == NULL) { - fprintf(stderr, "python: Can't reopen .pyc file\n"); - goto done; -@@ -1108,22 +1108,15 @@ - int unhandled_keyboard_interrupt = _PyRuntime.signals.unhandled_keyboard_interrupt; - - // Try first with the stdlib traceback module -- PyObject *traceback_module = PyImport_ImportModule("traceback"); -- -- if (traceback_module == NULL) { -- goto fallback; -- } -- -- PyObject *print_exception_fn = PyObject_GetAttrString(traceback_module, "_print_exception_bltin"); -- -+ PyObject *print_exception_fn = PyImport_ImportModuleAttrString( -+ "traceback", -+ "_print_exception_bltin"); - if (print_exception_fn == NULL || !PyCallable_Check(print_exception_fn)) { -- Py_DECREF(traceback_module); - goto fallback; - } - - PyObject* result = PyObject_CallOneArg(print_exception_fn, value); - -- Py_DECREF(traceback_module); - Py_XDECREF(print_exception_fn); - if (result) { - Py_DECREF(result); -@@ -1371,27 +1364,18 @@ - } - - if (interactive_src) { -- PyObject *linecache_module = PyImport_ImportModule("linecache"); -- -- if (linecache_module == NULL) { -- Py_DECREF(co); -- Py_DECREF(interactive_filename); -- return NULL; -- } -- -- PyObject *print_tb_func = PyObject_GetAttrString(linecache_module, "_register_code"); -- -+ PyObject *print_tb_func = PyImport_ImportModuleAttrString( -+ "linecache", -+ "_register_code"); - if (print_tb_func == NULL) { - Py_DECREF(co); - Py_DECREF(interactive_filename); -- Py_DECREF(linecache_module); - return NULL; - } - - if (!PyCallable_Check(print_tb_func)) { - Py_DECREF(co); - Py_DECREF(interactive_filename); -- Py_DECREF(linecache_module); - Py_DECREF(print_tb_func); - PyErr_SetString(PyExc_ValueError, "linecache._register_code is not callable"); - return NULL; -@@ -1406,7 +1390,6 @@ - - Py_DECREF(interactive_filename); - -- Py_DECREF(linecache_module); - Py_XDECREF(print_tb_func); - Py_XDECREF(result); - if (!result) { -diff --git a/Python/pytime.c b/Python/pytime.c -index 2b37cd991ef..c039fc98ce4 100644 ---- a/Python/pytime.c -+++ b/Python/pytime.c -@@ -1,5 +1,6 @@ - #include "Python.h" - #include "pycore_time.h" // PyTime_t -+#include "pycore_pystate.h" // _Py_AssertHoldsTstate() - - #include // gmtime_r() - #ifdef HAVE_SYS_TIME_H -@@ -897,14 +898,14 @@ - #endif - - --// N.B. If raise_exc=0, this may be called without the GIL. -+// N.B. If raise_exc=0, this may be called without a thread state. - static int - py_get_system_clock(PyTime_t *tp, _Py_clock_info_t *info, int raise_exc) - { - assert(info == NULL || raise_exc); - if (raise_exc) { -- // raise_exc requires to hold the GIL -- assert(PyGILState_Check()); -+ // raise_exc requires to hold a thread state -+ _Py_AssertHoldsTstate(); - } - - #ifdef MS_WINDOWS -@@ -1142,14 +1143,14 @@ - #endif - - --// N.B. If raise_exc=0, this may be called without the GIL. -+// N.B. If raise_exc=0, this may be called without a thread state. - static int - py_get_monotonic_clock(PyTime_t *tp, _Py_clock_info_t *info, int raise_exc) - { - assert(info == NULL || raise_exc); - if (raise_exc) { -- // raise_exc requires to hold the GIL -- assert(PyGILState_Check()); -+ // raise_exc requires to hold a thread state -+ _Py_AssertHoldsTstate(); - } - - #if defined(MS_WINDOWS) -diff --git a/Python/qsbr.c b/Python/qsbr.c -index a40219acfe2..0df1285cc8e 100644 ---- a/Python/qsbr.c -+++ b/Python/qsbr.c -@@ -205,15 +205,15 @@ - } - _PyEval_StartTheWorld(interp); - } -- PyMutex_Unlock(&shared->mutex); -- -- if (qsbr == NULL) { -- return -1; -- } - - // Return an index rather than the pointer because the array may be - // resized and the pointer invalidated. -- return (struct _qsbr_pad *)qsbr - shared->array; -+ Py_ssize_t index = -1; -+ if (qsbr != NULL) { -+ index = (struct _qsbr_pad *)qsbr - shared->array; -+ } -+ PyMutex_Unlock(&shared->mutex); -+ return index; - } - - void -diff --git a/Python/specialize.c b/Python/specialize.c -index 6eb298217ec..c741c4f93f3 100644 ---- a/Python/specialize.c -+++ b/Python/specialize.c -@@ -3,6 +3,7 @@ - #include "opcode.h" - - #include "pycore_code.h" -+#include "pycore_critical_section.h" - #include "pycore_descrobject.h" // _PyMethodWrapper_Type - #include "pycore_dict.h" // DICT_KEYS_UNICODE - #include "pycore_function.h" // _PyFunction_GetVersionForCurrentState() -@@ -21,7 +22,7 @@ - extern const char *_PyUOpName(int index); - - /* For guidance on adding or extending families of instructions see -- * ./adaptive.md -+ * InternalDocs/interpreter.md `Specialization` section. - */ - - #ifdef Py_STATS -@@ -112,7 +113,6 @@ - err += add_stat_dict(stats, LOAD_SUPER_ATTR, "load_super_attr"); - err += add_stat_dict(stats, LOAD_ATTR, "load_attr"); - err += add_stat_dict(stats, LOAD_GLOBAL, "load_global"); -- err += add_stat_dict(stats, BINARY_SUBSCR, "binary_subscr"); - err += add_stat_dict(stats, STORE_SUBSCR, "store_subscr"); - err += add_stat_dict(stats, STORE_ATTR, "store_attr"); - err += add_stat_dict(stats, CALL, "call"); -@@ -259,6 +259,7 @@ - fprintf(out, "Optimization inner loop: %" PRIu64 "\n", stats->inner_loop); - fprintf(out, "Optimization recursive call: %" PRIu64 "\n", stats->recursive_call); - fprintf(out, "Optimization low confidence: %" PRIu64 "\n", stats->low_confidence); -+ fprintf(out, "Optimization unknown callee: %" PRIu64 "\n", stats->unknown_callee); - fprintf(out, "Executors invalidated: %" PRIu64 "\n", stats->executors_invalidated); - - print_histogram(out, "Trace length", stats->trace_length_hist); -@@ -308,6 +309,14 @@ - ); - } - } -+ fprintf(out, "JIT total memory size: %" PRIu64 "\n", stats->jit_total_memory_size); -+ fprintf(out, "JIT code size: %" PRIu64 "\n", stats->jit_code_size); -+ fprintf(out, "JIT trampoline size: %" PRIu64 "\n", stats->jit_trampoline_size); -+ fprintf(out, "JIT data size: %" PRIu64 "\n", stats->jit_data_size); -+ fprintf(out, "JIT padding size: %" PRIu64 "\n", stats->jit_padding_size); -+ fprintf(out, "JIT freed memory size: %" PRIu64 "\n", stats->jit_freed_memory_size); -+ -+ print_histogram(out, "Trace total memory size", stats->trace_total_memory_hist); - } - #endif - -@@ -440,8 +449,7 @@ - - // Initialize warmup counters and optimize instructions. This cannot fail. - void --_PyCode_Quicken(_Py_CODEUNIT *instructions, Py_ssize_t size, PyObject *consts, -- int enable_counters) -+_PyCode_Quicken(_Py_CODEUNIT *instructions, Py_ssize_t size, int enable_counters) - { - #if ENABLE_SPECIALIZATION_FT - _Py_BackoffCounter jump_counter, adaptive_counter; -@@ -478,15 +486,6 @@ - } - i += caches; - } -- else if (opcode == LOAD_CONST) { -- /* We can't do this in the bytecode compiler as -- * marshalling can intern strings and make them immortal. */ -- -- PyObject *obj = PyTuple_GET_ITEM(consts, oparg); -- if (_Py_IsImmortal(obj)) { -- instructions[i].op.code = LOAD_CONST_IMMORTAL; -- } -- } - if (opcode != EXTENDED_ARG) { - oparg = 0; - } -@@ -546,17 +545,15 @@ - #define SPEC_FAIL_ATTR_BUILTIN_CLASS_METHOD_OBJ 33 - #define SPEC_FAIL_ATTR_METACLASS_OVERRIDDEN 34 - #define SPEC_FAIL_ATTR_SPLIT_DICT 35 -+#define SPEC_FAIL_ATTR_DESCR_NOT_DEFERRED 36 - - /* Binary subscr and store subscr */ - - #define SPEC_FAIL_SUBSCR_ARRAY_INT 9 - #define SPEC_FAIL_SUBSCR_ARRAY_SLICE 10 - #define SPEC_FAIL_SUBSCR_LIST_SLICE 11 --#define SPEC_FAIL_SUBSCR_TUPLE_SLICE 12 --#define SPEC_FAIL_SUBSCR_STRING_SLICE 14 --#define SPEC_FAIL_SUBSCR_BUFFER_INT 15 --#define SPEC_FAIL_SUBSCR_BUFFER_SLICE 16 --#define SPEC_FAIL_SUBSCR_SEQUENCE_INT 17 -+#define SPEC_FAIL_SUBSCR_BUFFER_INT 12 -+#define SPEC_FAIL_SUBSCR_BUFFER_SLICE 13 - - /* Store subscr */ - #define SPEC_FAIL_SUBSCR_BYTEARRAY_INT 18 -@@ -588,6 +585,15 @@ - #define SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_FLOAT 26 - #define SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_OTHER 27 - #define SPEC_FAIL_BINARY_OP_XOR 28 -+#define SPEC_FAIL_BINARY_OP_OR_INT 29 -+#define SPEC_FAIL_BINARY_OP_OR_DIFFERENT_TYPES 30 -+#define SPEC_FAIL_BINARY_OP_XOR_INT 31 -+#define SPEC_FAIL_BINARY_OP_XOR_DIFFERENT_TYPES 32 -+#define SPEC_FAIL_BINARY_OP_SUBSCR 33 -+#define SPEC_FAIL_BINARY_OP_SUBSCR_LIST_SLICE 34 -+#define SPEC_FAIL_BINARY_OP_SUBSCR_TUPLE_SLICE 35 -+#define SPEC_FAIL_BINARY_OP_SUBSCR_STRING_SLICE 36 -+#define SPEC_FAIL_BINARY_OP_SUBSCR_NOT_HEAP_TYPE 37 - - /* Calls */ - -@@ -738,11 +744,8 @@ - } - - static int function_kind(PyCodeObject *code); --#ifndef Py_GIL_DISABLED - static bool function_check_args(PyObject *o, int expected_argcount, int opcode); - static uint32_t function_get_version(PyObject *o, int opcode); --#endif --static uint32_t type_get_version(PyTypeObject *t, int opcode); - - static int - specialize_module_load_attr_lock_held(PyDictObject *dict, _Py_CODEUNIT *instr, PyObject *name) -@@ -881,71 +884,153 @@ - return NON_DESCRIPTOR; - } - --static DescriptorClassification --analyze_descriptor(PyTypeObject *type, PyObject *name, PyObject **descr, int store) -+static bool -+descriptor_is_class(PyObject *descriptor, PyObject *name) - { -+ return ((PyUnicode_CompareWithASCIIString(name, "__class__") == 0) && -+ (descriptor == _PyType_Lookup(&PyBaseObject_Type, name))); -+} -+ -+static DescriptorClassification -+analyze_descriptor_load(PyTypeObject *type, PyObject *name, PyObject **descr, unsigned int *tp_version) { - bool has_getattr = false; -- if (store) { -- if (type->tp_setattro != PyObject_GenericSetAttr) { -+ bool have_ga_version = false; -+ unsigned int ga_version; -+ getattrofunc getattro_slot = type->tp_getattro; -+ if (getattro_slot == PyObject_GenericGetAttr) { -+ /* Normal attribute lookup; */ -+ has_getattr = false; -+ } -+ else if (getattro_slot == _Py_slot_tp_getattr_hook || -+ getattro_slot == _Py_slot_tp_getattro) { -+ /* One or both of __getattribute__ or __getattr__ may have been -+ overridden See typeobject.c for why these functions are special. */ -+ PyObject *getattribute = _PyType_LookupRefAndVersion(type, -+ &_Py_ID(__getattribute__), &ga_version); -+ have_ga_version = true; -+ PyInterpreterState *interp = _PyInterpreterState_GET(); -+ bool has_custom_getattribute = getattribute != NULL && -+ getattribute != interp->callable_cache.object__getattribute__; -+ PyObject *getattr = _PyType_Lookup(type, &_Py_ID(__getattr__)); -+ has_getattr = getattr != NULL; -+ if (has_custom_getattribute) { -+ if (getattro_slot == _Py_slot_tp_getattro && -+ !has_getattr && -+ Py_IS_TYPE(getattribute, &PyFunction_Type)) { -+ *descr = getattribute; -+ *tp_version = ga_version; -+ return GETATTRIBUTE_IS_PYTHON_FUNCTION; -+ } -+ /* Potentially both __getattr__ and __getattribute__ are set. -+ Too complicated */ -+ Py_DECREF(getattribute); - *descr = NULL; -+ *tp_version = ga_version; - return GETSET_OVERRIDDEN; - } -+ /* Potentially has __getattr__ but no custom __getattribute__. -+ Fall through to usual descriptor analysis. -+ Usual attribute lookup should only be allowed at runtime -+ if we can guarantee that there is no way an exception can be -+ raised. This means some specializations, e.g. specializing -+ for property() isn't safe. -+ */ -+ Py_XDECREF(getattribute); - } - else { -- getattrofunc getattro_slot = type->tp_getattro; -- if (getattro_slot == PyObject_GenericGetAttr) { -- /* Normal attribute lookup; */ -- has_getattr = false; -- } -- else if (getattro_slot == _Py_slot_tp_getattr_hook || -- getattro_slot == _Py_slot_tp_getattro) { -- /* One or both of __getattribute__ or __getattr__ may have been -- overridden See typeobject.c for why these functions are special. */ -- PyObject *getattribute = _PyType_Lookup(type, -- &_Py_ID(__getattribute__)); -- PyInterpreterState *interp = _PyInterpreterState_GET(); -- bool has_custom_getattribute = getattribute != NULL && -- getattribute != interp->callable_cache.object__getattribute__; -- has_getattr = _PyType_Lookup(type, &_Py_ID(__getattr__)) != NULL; -- if (has_custom_getattribute) { -- if (getattro_slot == _Py_slot_tp_getattro && -- !has_getattr && -- Py_IS_TYPE(getattribute, &PyFunction_Type)) { -- *descr = getattribute; -- return GETATTRIBUTE_IS_PYTHON_FUNCTION; -- } -- /* Potentially both __getattr__ and __getattribute__ are set. -- Too complicated */ -- *descr = NULL; -- return GETSET_OVERRIDDEN; -- } -- /* Potentially has __getattr__ but no custom __getattribute__. -- Fall through to usual descriptor analysis. -- Usual attribute lookup should only be allowed at runtime -- if we can guarantee that there is no way an exception can be -- raised. This means some specializations, e.g. specializing -- for property() isn't safe. -- */ -- } -- else { -- *descr = NULL; -- return GETSET_OVERRIDDEN; -- } -+ *descr = NULL; -+ *tp_version = FT_ATOMIC_LOAD_UINT_RELAXED(type->tp_version_tag); -+ return GETSET_OVERRIDDEN; - } -- PyObject *descriptor = _PyType_Lookup(type, name); -+ unsigned int descr_version; -+ PyObject *descriptor = _PyType_LookupRefAndVersion(type, name, &descr_version); - *descr = descriptor; -- if (PyUnicode_CompareWithASCIIString(name, "__class__") == 0) { -- if (descriptor == _PyType_Lookup(&PyBaseObject_Type, name)) { -- return DUNDER_CLASS; -- } -+ *tp_version = have_ga_version ? ga_version : descr_version; -+ if (descriptor_is_class(descriptor, name)) { -+ return DUNDER_CLASS; - } - return classify_descriptor(descriptor, has_getattr); - } - -+static DescriptorClassification -+analyze_descriptor_store(PyTypeObject *type, PyObject *name, PyObject **descr, unsigned int *tp_version) -+{ -+ if (type->tp_setattro != PyObject_GenericSetAttr) { -+ *descr = NULL; -+ return GETSET_OVERRIDDEN; -+ } -+ PyObject *descriptor = _PyType_LookupRefAndVersion(type, name, tp_version); -+ *descr = descriptor; -+ if (descriptor_is_class(descriptor, name)) { -+ return DUNDER_CLASS; -+ } -+ return classify_descriptor(descriptor, false); -+} -+ -+static int -+specialize_dict_access_inline( -+ PyObject *owner, _Py_CODEUNIT *instr, PyTypeObject *type, -+ PyObject *name, unsigned int tp_version, -+ int base_op, int values_op) -+{ -+ _PyAttrCache *cache = (_PyAttrCache *)(instr + 1); -+ PyDictKeysObject *keys = ((PyHeapTypeObject *)type)->ht_cached_keys; -+ assert(PyUnicode_CheckExact(name)); -+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(owner); -+ Py_ssize_t index = _PyDictKeys_StringLookupSplit(keys, name); -+ assert (index != DKIX_ERROR); -+ if (index == DKIX_EMPTY) { -+ SPECIALIZATION_FAIL(base_op, SPEC_FAIL_ATTR_NOT_IN_KEYS); -+ return 0; -+ } -+ assert(index >= 0); -+ assert(_PyObject_InlineValues(owner)->valid); -+ char *value_addr = (char *)&_PyObject_InlineValues(owner)->values[index]; -+ Py_ssize_t offset = value_addr - (char *)owner; -+ if (offset != (uint16_t)offset) { -+ SPECIALIZATION_FAIL(base_op, SPEC_FAIL_OUT_OF_RANGE); -+ return 0; -+ } -+ cache->index = (uint16_t)offset; -+ write_u32(cache->version, tp_version); -+ specialize(instr, values_op); -+ return 1; -+} -+ -+static int -+specialize_dict_access_hint( -+ PyDictObject *dict, _Py_CODEUNIT *instr, PyTypeObject *type, -+ PyObject *name, unsigned int tp_version, -+ int base_op, int hint_op) -+{ -+ _PyAttrCache *cache = (_PyAttrCache *)(instr + 1); -+ -+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(dict); -+ -+ // We found an instance with a __dict__. -+ if (_PyDict_HasSplitTable(dict)) { -+ SPECIALIZATION_FAIL(base_op, SPEC_FAIL_ATTR_SPLIT_DICT); -+ return 0; -+ } -+ Py_ssize_t index = _PyDict_LookupIndex(dict, name); -+ if (index != (uint16_t)index) { -+ SPECIALIZATION_FAIL(base_op, -+ index == DKIX_EMPTY ? -+ SPEC_FAIL_ATTR_NOT_IN_DICT : -+ SPEC_FAIL_OUT_OF_RANGE); -+ return 0; -+ } -+ cache->index = (uint16_t)index; -+ write_u32(cache->version, tp_version); -+ specialize(instr, hint_op); -+ return 1; -+} -+ -+ - static int - specialize_dict_access( - PyObject *owner, _Py_CODEUNIT *instr, PyTypeObject *type, -- DescriptorClassification kind, PyObject *name, -+ DescriptorClassification kind, PyObject *name, unsigned int tp_version, - int base_op, int values_op, int hint_op) - { - assert(kind == NON_OVERRIDING || kind == NON_DESCRIPTOR || kind == ABSENT || -@@ -956,29 +1041,25 @@ - SPECIALIZATION_FAIL(base_op, SPEC_FAIL_ATTR_NOT_MANAGED_DICT); - return 0; - } -- _PyAttrCache *cache = (_PyAttrCache *)(instr + 1); - if (type->tp_flags & Py_TPFLAGS_INLINE_VALUES && -- _PyObject_InlineValues(owner)->valid && -+ FT_ATOMIC_LOAD_UINT8(_PyObject_InlineValues(owner)->valid) && - !(base_op == STORE_ATTR && _PyObject_GetManagedDict(owner) != NULL)) - { -- PyDictKeysObject *keys = ((PyHeapTypeObject *)type)->ht_cached_keys; -- assert(PyUnicode_CheckExact(name)); -- Py_ssize_t index = _PyDictKeys_StringLookup(keys, name); -- assert (index != DKIX_ERROR); -- if (index == DKIX_EMPTY) { -- SPECIALIZATION_FAIL(base_op, SPEC_FAIL_ATTR_NOT_IN_KEYS); -- return 0; -+ int res; -+ Py_BEGIN_CRITICAL_SECTION(owner); -+ PyDictObject *dict = _PyObject_GetManagedDict(owner); -+ if (dict == NULL) { -+ // managed dict, not materialized, inline values valid -+ res = specialize_dict_access_inline(owner, instr, type, name, -+ tp_version, base_op, values_op); - } -- assert(index >= 0); -- char *value_addr = (char *)&_PyObject_InlineValues(owner)->values[index]; -- Py_ssize_t offset = value_addr - (char *)owner; -- if (offset != (uint16_t)offset) { -- SPECIALIZATION_FAIL(base_op, SPEC_FAIL_OUT_OF_RANGE); -- return 0; -+ else { -+ // lost race and dict was created, fail specialization -+ SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_OTHER); -+ res = 0; - } -- write_u32(cache->version, type->tp_version_tag); -- cache->index = (uint16_t)offset; -- specialize(instr, values_op); -+ Py_END_CRITICAL_SECTION(); -+ return res; - } - else { - PyDictObject *dict = _PyObject_GetManagedDict(owner); -@@ -986,30 +1067,22 @@ - SPECIALIZATION_FAIL(base_op, SPEC_FAIL_NO_DICT); - return 0; - } -- // We found an instance with a __dict__. -- if (dict->ma_values) { -- SPECIALIZATION_FAIL(base_op, SPEC_FAIL_ATTR_SPLIT_DICT); -- return 0; -- } -- Py_ssize_t index = -- _PyDict_LookupIndex(dict, name); -- if (index != (uint16_t)index) { -- SPECIALIZATION_FAIL(base_op, -- index == DKIX_EMPTY ? -- SPEC_FAIL_ATTR_NOT_IN_DICT : -- SPEC_FAIL_OUT_OF_RANGE); -- return 0; -- } -- cache->index = (uint16_t)index; -- write_u32(cache->version, type->tp_version_tag); -- specialize(instr, hint_op); -+ int res; -+ Py_BEGIN_CRITICAL_SECTION(dict); -+ // materialized managed dict -+ res = specialize_dict_access_hint(dict, instr, type, name, -+ tp_version, base_op, hint_op); -+ Py_END_CRITICAL_SECTION(); -+ return res; - } -- return 1; - } - --#ifndef Py_GIL_DISABLED --static int specialize_attr_loadclassattr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name, -- PyObject* descr, DescriptorClassification kind, bool is_method); -+static int -+specialize_attr_loadclassattr(PyObject *owner, _Py_CODEUNIT *instr, -+ PyObject *name, PyObject *descr, -+ unsigned int tp_version, -+ DescriptorClassification kind, bool is_method, -+ uint32_t shared_keys_version); - static int specialize_class_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name); - - /* Returns true if instances of obj's class are -@@ -1018,7 +1091,7 @@ - * For other objects, we check their actual dictionary. - */ - static bool --instance_has_key(PyObject *obj, PyObject* name) -+instance_has_key(PyObject *obj, PyObject *name, uint32_t *shared_keys_version) - { - PyTypeObject *cls = Py_TYPE(obj); - if ((cls->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) { -@@ -1026,35 +1099,38 @@ - } - if (cls->tp_flags & Py_TPFLAGS_INLINE_VALUES) { - PyDictKeysObject *keys = ((PyHeapTypeObject *)cls)->ht_cached_keys; -- Py_ssize_t index = _PyDictKeys_StringLookup(keys, name); -+ Py_ssize_t index = -+ _PyDictKeys_StringLookupAndVersion(keys, name, shared_keys_version); - return index >= 0; - } - PyDictObject *dict = _PyObject_GetManagedDict(obj); - if (dict == NULL || !PyDict_CheckExact(dict)) { - return false; - } -+ bool result; -+ Py_BEGIN_CRITICAL_SECTION(dict); - if (dict->ma_values) { -- return false; -+ result = false; - } -- Py_ssize_t index = _PyDict_LookupIndex(dict, name); -- if (index < 0) { -- return false; -+ else { -+ result = (_PyDict_LookupIndex(dict, name) >= 0); - } -- return true; -+ Py_END_CRITICAL_SECTION(); -+ return result; - } - - static int --specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name) -+do_specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name, -+ bool shadow, uint32_t shared_keys_version, -+ DescriptorClassification kind, PyObject *descr, unsigned int tp_version) - { - _PyAttrCache *cache = (_PyAttrCache *)(instr + 1); - PyTypeObject *type = Py_TYPE(owner); -- bool shadow = instance_has_key(owner, name); -- PyObject *descr = NULL; -- DescriptorClassification kind = analyze_descriptor(type, name, &descr, 0); -- assert(descr != NULL || kind == ABSENT || kind == GETSET_OVERRIDDEN); -- if (type_get_version(type, LOAD_ATTR) == 0) { -+ if (tp_version == 0) { -+ SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS); - return -1; - } -+ uint8_t oparg = FT_ATOMIC_LOAD_UINT8_RELAXED(instr->op.arg); - switch(kind) { - case OVERRIDING: - SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR); -@@ -1064,9 +1140,10 @@ - if (shadow) { - goto try_instance; - } -- int oparg = instr->op.arg; - if (oparg & 1) { -- if (specialize_attr_loadclassattr(owner, instr, name, descr, kind, true)) { -+ if (specialize_attr_loadclassattr(owner, instr, name, descr, -+ tp_version, kind, true, -+ shared_keys_version)) { - return 0; - } - else { -@@ -1092,18 +1169,25 @@ - if (!function_check_args(fget, 1, LOAD_ATTR)) { - return -1; - } -- if (instr->op.arg & 1) { -+ if (oparg & 1) { - SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METHOD); - return -1; - } -+ /* Don't specialize if PEP 523 is active */ - if (_PyInterpreterState_GET()->eval_frame) { - SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OTHER); - return -1; - } -- assert(type->tp_version_tag != 0); -- write_u32(lm_cache->type_version, type->tp_version_tag); -+ #ifdef Py_GIL_DISABLED -+ if (!_PyObject_HasDeferredRefcount(fget)) { -+ SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_DESCR_NOT_DEFERRED); -+ return -1; -+ } -+ #endif -+ assert(tp_version != 0); -+ write_u32(lm_cache->type_version, tp_version); - /* borrowed */ -- write_obj(lm_cache->descr, fget); -+ write_ptr(lm_cache->descr, fget); - specialize(instr, LOAD_ATTR_PROPERTY); - return 0; - } -@@ -1127,7 +1211,7 @@ - assert(dmem->type == Py_T_OBJECT_EX || dmem->type == _Py_T_OBJECT); - assert(offset > 0); - cache->index = (uint16_t)offset; -- write_u32(cache->version, type->tp_version_tag); -+ write_u32(cache->version, tp_version); - specialize(instr, LOAD_ATTR_SLOT); - return 0; - } -@@ -1136,7 +1220,7 @@ - Py_ssize_t offset = offsetof(PyObject, ob_type); - assert(offset == (uint16_t)offset); - cache->index = (uint16_t)offset; -- write_u32(cache->version, type->tp_version_tag); -+ write_u32(cache->version, tp_version); - specialize(instr, LOAD_ATTR_SLOT); - return 0; - } -@@ -1151,13 +1235,18 @@ - return -1; - case GETATTRIBUTE_IS_PYTHON_FUNCTION: - { -+ #ifndef Py_GIL_DISABLED -+ // In free-threaded builds it's possible for tp_getattro to change -+ // after the call to analyze_descriptor. That is fine: the version -+ // guard will fail. - assert(type->tp_getattro == _Py_slot_tp_getattro); -+ #endif - assert(Py_IS_TYPE(descr, &PyFunction_Type)); - _PyLoadMethodCache *lm_cache = (_PyLoadMethodCache *)(instr + 1); - if (!function_check_args(descr, 2, LOAD_ATTR)) { - return -1; - } -- if (instr->op.arg & 1) { -+ if (oparg & 1) { - SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METHOD); - return -1; - } -@@ -1165,14 +1254,21 @@ - if (version == 0) { - return -1; - } -+ /* Don't specialize if PEP 523 is active */ - if (_PyInterpreterState_GET()->eval_frame) { - SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OTHER); - return -1; - } -+ #ifdef Py_GIL_DISABLED -+ if (!_PyObject_HasDeferredRefcount(descr)) { -+ SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_DESCR_NOT_DEFERRED); -+ return -1; -+ } -+ #endif - write_u32(lm_cache->keys_version, version); - /* borrowed */ -- write_obj(lm_cache->descr, descr); -- write_u32(lm_cache->type_version, type->tp_version_tag); -+ write_ptr(lm_cache->descr, descr); -+ write_u32(lm_cache->type_version, tp_version); - specialize(instr, LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN); - return 0; - } -@@ -1187,8 +1283,10 @@ - if (shadow) { - goto try_instance; - } -- if ((instr->op.arg & 1) == 0) { -- if (specialize_attr_loadclassattr(owner, instr, name, descr, kind, false)) { -+ if ((oparg & 1) == 0) { -+ if (specialize_attr_loadclassattr(owner, instr, name, descr, -+ tp_version, kind, false, -+ shared_keys_version)) { - return 0; - } - } -@@ -1202,14 +1300,28 @@ - } - Py_UNREACHABLE(); - try_instance: -- if (specialize_dict_access(owner, instr, type, kind, name, LOAD_ATTR, -- LOAD_ATTR_INSTANCE_VALUE, LOAD_ATTR_WITH_HINT)) -+ if (specialize_dict_access(owner, instr, type, kind, name, tp_version, -+ LOAD_ATTR, LOAD_ATTR_INSTANCE_VALUE, LOAD_ATTR_WITH_HINT)) - { - return 0; - } - return -1; - } --#endif // Py_GIL_DISABLED -+ -+static int -+specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name) -+{ -+ // 0 is not a valid version -+ uint32_t shared_keys_version = 0; -+ bool shadow = instance_has_key(owner, name, &shared_keys_version); -+ PyObject *descr = NULL; -+ unsigned int tp_version = 0; -+ PyTypeObject *type = Py_TYPE(owner); -+ DescriptorClassification kind = analyze_descriptor_load(type, name, &descr, &tp_version); -+ int result = do_specialize_instance_load_attr(owner, instr, name, shadow, shared_keys_version, kind, descr, tp_version); -+ Py_XDECREF(descr); -+ return result; -+} - - void - _Py_Specialize_LoadAttr(_PyStackRef owner_st, _Py_CODEUNIT *instr, PyObject *name) -@@ -1231,20 +1343,10 @@ - fail = specialize_module_load_attr(owner, instr, name); - } - else if (PyType_Check(owner)) { -- #ifdef Py_GIL_DISABLED -- SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR); -- fail = true; -- #else - fail = specialize_class_load_attr(owner, instr, name); -- #endif - } - else { -- #ifdef Py_GIL_DISABLED -- SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR); -- fail = true; -- #else - fail = specialize_instance_load_attr(owner, instr, name); -- #endif - } - - if (fail) { -@@ -1257,8 +1359,9 @@ - { - PyObject *owner = PyStackRef_AsPyObjectBorrow(owner_st); - -- assert(ENABLE_SPECIALIZATION); -+ assert(ENABLE_SPECIALIZATION_FT); - assert(_PyOpcode_Caches[STORE_ATTR] == INLINE_CACHE_ENTRIES_STORE_ATTR); -+ PyObject *descr = NULL; - _PyAttrCache *cache = (_PyAttrCache *)(instr + 1); - PyTypeObject *type = Py_TYPE(owner); - if (!_PyType_IsReady(type)) { -@@ -1272,11 +1375,12 @@ - SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_OVERRIDDEN); - goto fail; - } -- PyObject *descr; -- DescriptorClassification kind = analyze_descriptor(type, name, &descr, 1); -- if (type_get_version(type, STORE_ATTR) == 0) { -+ unsigned int tp_version = 0; -+ DescriptorClassification kind = analyze_descriptor_store(type, name, &descr, &tp_version); -+ if (tp_version == 0) { - goto fail; - } -+ assert(descr != NULL || kind == ABSENT || kind == GETSET_OVERRIDDEN); - switch(kind) { - case OVERRIDING: - SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR); -@@ -1307,8 +1411,8 @@ - assert(dmem->type == Py_T_OBJECT_EX || dmem->type == _Py_T_OBJECT); - assert(offset > 0); - cache->index = (uint16_t)offset; -- write_u32(cache->version, type->tp_version_tag); -- instr->op.code = STORE_ATTR_SLOT; -+ write_u32(cache->version, tp_version); -+ specialize(instr, STORE_ATTR_SLOT); - goto success; - } - case DUNDER_CLASS: -@@ -1335,26 +1439,21 @@ - SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_CLASS_ATTR_SIMPLE); - goto fail; - case ABSENT: -- if (specialize_dict_access(owner, instr, type, kind, name, STORE_ATTR, -- STORE_ATTR_INSTANCE_VALUE, STORE_ATTR_WITH_HINT)) -- { -+ if (specialize_dict_access(owner, instr, type, kind, name, tp_version, -+ STORE_ATTR, STORE_ATTR_INSTANCE_VALUE, -+ STORE_ATTR_WITH_HINT)) { - goto success; - } - } - fail: -- STAT_INC(STORE_ATTR, failure); -- assert(!PyErr_Occurred()); -- instr->op.code = STORE_ATTR; -- cache->counter = adaptive_counter_backoff(cache->counter); -+ Py_XDECREF(descr); -+ unspecialize(instr); - return; - success: -- STAT_INC(STORE_ATTR, success); -- assert(!PyErr_Occurred()); -- cache->counter = adaptive_counter_cooldown(); -+ Py_XDECREF(descr); -+ return; - } - --#ifndef Py_GIL_DISABLED -- - #ifdef Py_STATS - static int - load_attr_fail_kind(DescriptorClassification kind) -@@ -1403,8 +1502,10 @@ - SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METACLASS_OVERRIDDEN); - return -1; - } -- PyObject *metadescriptor = _PyType_Lookup(Py_TYPE(cls), name); -+ unsigned int meta_version = 0; -+ PyObject *metadescriptor = _PyType_LookupRefAndVersion(Py_TYPE(cls), name, &meta_version); - DescriptorClassification metakind = classify_descriptor(metadescriptor, false); -+ Py_XDECREF(metadescriptor); - switch (metakind) { - case METHOD: - case NON_DESCRIPTOR: -@@ -1419,37 +1520,52 @@ - } - PyObject *descr = NULL; - DescriptorClassification kind = 0; -- kind = analyze_descriptor(cls, name, &descr, 0); -- if (type_get_version(cls, LOAD_ATTR) == 0) { -+ unsigned int tp_version = 0; -+ kind = analyze_descriptor_load(cls, name, &descr, &tp_version); -+ if (tp_version == 0) { -+ SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS); -+ Py_XDECREF(descr); - return -1; - } - bool metaclass_check = false; - if ((Py_TYPE(cls)->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) == 0) { - metaclass_check = true; -- if (type_get_version(Py_TYPE(cls), LOAD_ATTR) == 0) { -+ if (meta_version == 0) { -+ SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS); -+ Py_XDECREF(descr); - return -1; - } - } - switch (kind) { - case METHOD: - case NON_DESCRIPTOR: -- write_u32(cache->type_version, cls->tp_version_tag); -- write_obj(cache->descr, descr); -+ #ifdef Py_GIL_DISABLED -+ if (!_PyObject_HasDeferredRefcount(descr)) { -+ SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_DESCR_NOT_DEFERRED); -+ Py_XDECREF(descr); -+ return -1; -+ } -+ #endif -+ write_u32(cache->type_version, tp_version); -+ write_ptr(cache->descr, descr); - if (metaclass_check) { -- write_u32(cache->keys_version, Py_TYPE(cls)->tp_version_tag); -+ write_u32(cache->keys_version, meta_version); - specialize(instr, LOAD_ATTR_CLASS_WITH_METACLASS_CHECK); - } - else { - specialize(instr, LOAD_ATTR_CLASS); - } -+ Py_XDECREF(descr); - return 0; - #ifdef Py_STATS - case ABSENT: - SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR); -+ Py_XDECREF(descr); - return -1; - #endif - default: - SPECIALIZATION_FAIL(LOAD_ATTR, load_attr_fail_kind(kind)); -+ Py_XDECREF(descr); - return -1; - } - } -@@ -1458,29 +1574,41 @@ - // can cause a significant drop in cache hits. A possible test is - // python.exe -m test_typing test_re test_dis test_zlib. - static int --specialize_attr_loadclassattr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, --PyObject *descr, DescriptorClassification kind, bool is_method) -+specialize_attr_loadclassattr(PyObject *owner, _Py_CODEUNIT *instr, -+ PyObject *name, PyObject *descr, -+ unsigned int tp_version, -+ DescriptorClassification kind, bool is_method, -+ uint32_t shared_keys_version) - { - _PyLoadMethodCache *cache = (_PyLoadMethodCache *)(instr + 1); - PyTypeObject *owner_cls = Py_TYPE(owner); - - assert(descr != NULL); - assert((is_method && kind == METHOD) || (!is_method && kind == NON_DESCRIPTOR)); -- if (owner_cls->tp_flags & Py_TPFLAGS_INLINE_VALUES) { -- PyDictKeysObject *keys = ((PyHeapTypeObject *)owner_cls)->ht_cached_keys; -- assert(_PyDictKeys_StringLookup(keys, name) < 0); -- uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState( -- _PyInterpreterState_GET(), keys); -- if (keys_version == 0) { -+ -+ #ifdef Py_GIL_DISABLED -+ if (!_PyObject_HasDeferredRefcount(descr)) { -+ SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_DESCR_NOT_DEFERRED); -+ return 0; -+ } -+ #endif -+ -+ unsigned long tp_flags = PyType_GetFlags(owner_cls); -+ if (tp_flags & Py_TPFLAGS_INLINE_VALUES) { -+ #ifndef Py_GIL_DISABLED -+ assert(_PyDictKeys_StringLookup( -+ ((PyHeapTypeObject *)owner_cls)->ht_cached_keys, name) < 0); -+ #endif -+ if (shared_keys_version == 0) { - SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS); - return 0; - } -- write_u32(cache->keys_version, keys_version); -+ write_u32(cache->keys_version, shared_keys_version); - specialize(instr, is_method ? LOAD_ATTR_METHOD_WITH_VALUES : LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES); - } - else { - Py_ssize_t dictoffset; -- if (owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT) { -+ if (tp_flags & Py_TPFLAGS_MANAGED_DICT) { - dictoffset = MANAGED_DICT_OFFSET; - } - else { -@@ -1526,13 +1654,11 @@ - * PyType_Modified usages in typeobject.c). The MCACHE has been - * working since Python 2.6 and it's battle-tested. - */ -- write_u32(cache->type_version, owner_cls->tp_version_tag); -- write_obj(cache->descr, descr); -+ write_u32(cache->type_version, tp_version); -+ write_ptr(cache->descr, descr); - return 1; - } - --#endif // Py_GIL_DISABLED -- - - static void - specialize_load_global_lock_held( -@@ -1636,37 +1762,6 @@ - Py_END_CRITICAL_SECTION2(); - } - --#ifdef Py_STATS --static int --binary_subscr_fail_kind(PyTypeObject *container_type, PyObject *sub) --{ -- if (strcmp(container_type->tp_name, "array.array") == 0) { -- if (PyLong_CheckExact(sub)) { -- return SPEC_FAIL_SUBSCR_ARRAY_INT; -- } -- if (PySlice_Check(sub)) { -- return SPEC_FAIL_SUBSCR_ARRAY_SLICE; -- } -- return SPEC_FAIL_OTHER; -- } -- else if (container_type->tp_as_buffer) { -- if (PyLong_CheckExact(sub)) { -- return SPEC_FAIL_SUBSCR_BUFFER_INT; -- } -- if (PySlice_Check(sub)) { -- return SPEC_FAIL_SUBSCR_BUFFER_SLICE; -- } -- return SPEC_FAIL_OTHER; -- } -- else if (container_type->tp_as_sequence) { -- if (PyLong_CheckExact(sub) && container_type->tp_as_sequence->sq_item) { -- return SPEC_FAIL_SUBSCR_SEQUENCE_INT; -- } -- } -- return SPEC_FAIL_OTHER; --} --#endif // Py_STATS -- - static int - function_kind(PyCodeObject *code) { - int flags = code->co_flags; -@@ -1679,7 +1774,6 @@ - return SIMPLE_FUNCTION; - } - --#ifndef Py_GIL_DISABLED - /* Returning false indicates a failure. */ - static bool - function_check_args(PyObject *o, int expected_argcount, int opcode) -@@ -1712,121 +1806,6 @@ - } - return version; - } --#endif // Py_GIL_DISABLED -- --/* Returning 0 indicates a failure. */ --static uint32_t --type_get_version(PyTypeObject *t, int opcode) --{ -- uint32_t version = t->tp_version_tag; -- if (version == 0) { -- SPECIALIZATION_FAIL(opcode, SPEC_FAIL_OUT_OF_VERSIONS); -- return 0; -- } -- return version; --} -- --void --_Py_Specialize_BinarySubscr( -- _PyStackRef container_st, _PyStackRef sub_st, _Py_CODEUNIT *instr) --{ -- PyObject *container = PyStackRef_AsPyObjectBorrow(container_st); -- PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); -- -- assert(ENABLE_SPECIALIZATION_FT); -- assert(_PyOpcode_Caches[BINARY_SUBSCR] == -- INLINE_CACHE_ENTRIES_BINARY_SUBSCR); -- PyTypeObject *container_type = Py_TYPE(container); -- uint8_t specialized_op; -- if (container_type == &PyList_Type) { -- if (PyLong_CheckExact(sub)) { -- if (_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) { -- specialized_op = BINARY_SUBSCR_LIST_INT; -- goto success; -- } -- SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_OUT_OF_RANGE); -- goto fail; -- } -- SPECIALIZATION_FAIL(BINARY_SUBSCR, -- PySlice_Check(sub) ? SPEC_FAIL_SUBSCR_LIST_SLICE : SPEC_FAIL_OTHER); -- goto fail; -- } -- if (container_type == &PyTuple_Type) { -- if (PyLong_CheckExact(sub)) { -- if (_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) { -- specialized_op = BINARY_SUBSCR_TUPLE_INT; -- goto success; -- } -- SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_OUT_OF_RANGE); -- goto fail; -- } -- SPECIALIZATION_FAIL(BINARY_SUBSCR, -- PySlice_Check(sub) ? SPEC_FAIL_SUBSCR_TUPLE_SLICE : SPEC_FAIL_OTHER); -- goto fail; -- } -- if (container_type == &PyUnicode_Type) { -- if (PyLong_CheckExact(sub)) { -- if (_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) { -- specialized_op = BINARY_SUBSCR_STR_INT; -- goto success; -- } -- SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_OUT_OF_RANGE); -- goto fail; -- } -- SPECIALIZATION_FAIL(BINARY_SUBSCR, -- PySlice_Check(sub) ? SPEC_FAIL_SUBSCR_STRING_SLICE : SPEC_FAIL_OTHER); -- goto fail; -- } -- if (container_type == &PyDict_Type) { -- specialized_op = BINARY_SUBSCR_DICT; -- goto success; -- } --#ifndef Py_GIL_DISABLED -- PyTypeObject *cls = Py_TYPE(container); -- PyObject *descriptor = _PyType_Lookup(cls, &_Py_ID(__getitem__)); -- if (descriptor && Py_TYPE(descriptor) == &PyFunction_Type) { -- if (!(container_type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { -- SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_SUBSCR_NOT_HEAP_TYPE); -- goto fail; -- } -- PyFunctionObject *func = (PyFunctionObject *)descriptor; -- PyCodeObject *fcode = (PyCodeObject *)func->func_code; -- int kind = function_kind(fcode); -- if (kind != SIMPLE_FUNCTION) { -- SPECIALIZATION_FAIL(BINARY_SUBSCR, kind); -- goto fail; -- } -- if (fcode->co_argcount != 2) { -- SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS); -- goto fail; -- } -- uint32_t version = _PyFunction_GetVersionForCurrentState(func); -- if (!_PyFunction_IsVersionValid(version)) { -- SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_OUT_OF_VERSIONS); -- goto fail; -- } -- if (_PyInterpreterState_GET()->eval_frame) { -- SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_OTHER); -- goto fail; -- } -- PyHeapTypeObject *ht = (PyHeapTypeObject *)container_type; -- // This pointer is invalidated by PyType_Modified (see the comment on -- // struct _specialization_cache): -- ht->_spec_cache.getitem = descriptor; -- ht->_spec_cache.getitem_version = version; -- specialized_op = BINARY_SUBSCR_GETITEM; -- goto success; -- } --#endif // Py_GIL_DISABLED -- SPECIALIZATION_FAIL(BINARY_SUBSCR, -- binary_subscr_fail_kind(container_type, sub)); --fail: -- unspecialize(instr); -- return; --success: -- specialize(instr, specialized_op); --} -- - - #ifdef Py_STATS - static int -@@ -1944,10 +1923,6 @@ - return NULL; - } - unsigned long tp_flags = PyType_GetFlags(tp); -- if ((tp_flags & Py_TPFLAGS_INLINE_VALUES) == 0) { -- SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_INIT_NOT_INLINE_VALUES); -- return NULL; -- } - if (!(tp_flags & Py_TPFLAGS_HEAPTYPE)) { - /* Is this possible? */ - SPECIALIZATION_FAIL(CALL, SPEC_FAIL_EXPECTED_ERROR); -@@ -2285,6 +2260,12 @@ - return SPEC_FAIL_BINARY_OP_MULTIPLY_OTHER; - case NB_OR: - case NB_INPLACE_OR: -+ if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) { -+ return SPEC_FAIL_BINARY_OP_OR_DIFFERENT_TYPES; -+ } -+ if (PyLong_CheckExact(lhs)) { -+ return SPEC_FAIL_BINARY_OP_OR_INT; -+ } - return SPEC_FAIL_BINARY_OP_OR; - case NB_POWER: - case NB_INPLACE_POWER: -@@ -2312,12 +2293,208 @@ - return SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_OTHER; - case NB_XOR: - case NB_INPLACE_XOR: -+ if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) { -+ return SPEC_FAIL_BINARY_OP_XOR_DIFFERENT_TYPES; -+ } -+ if (PyLong_CheckExact(lhs)) { -+ return SPEC_FAIL_BINARY_OP_XOR_INT; -+ } - return SPEC_FAIL_BINARY_OP_XOR; -+ case NB_SUBSCR: -+ if (PyList_CheckExact(lhs)) { -+ if (PyLong_CheckExact(rhs) && !_PyLong_IsNonNegativeCompact((PyLongObject *)rhs)) { -+ return SPEC_FAIL_OUT_OF_RANGE; -+ } -+ if (PySlice_Check(rhs)) { -+ return SPEC_FAIL_BINARY_OP_SUBSCR_LIST_SLICE; -+ } -+ } -+ if (PyTuple_CheckExact(lhs)) { -+ if (PyLong_CheckExact(rhs) && !_PyLong_IsNonNegativeCompact((PyLongObject *)rhs)) { -+ return SPEC_FAIL_OUT_OF_RANGE; -+ } -+ if (PySlice_Check(rhs)) { -+ return SPEC_FAIL_BINARY_OP_SUBSCR_TUPLE_SLICE; -+ } -+ } -+ if (PyUnicode_CheckExact(lhs)) { -+ if (PyLong_CheckExact(rhs) && !_PyLong_IsNonNegativeCompact((PyLongObject *)rhs)) { -+ return SPEC_FAIL_OUT_OF_RANGE; -+ } -+ if (PySlice_Check(rhs)) { -+ return SPEC_FAIL_BINARY_OP_SUBSCR_STRING_SLICE; -+ } -+ } -+ unsigned int tp_version; -+ PyTypeObject *container_type = Py_TYPE(lhs); -+ PyObject *descriptor = _PyType_LookupRefAndVersion(container_type, &_Py_ID(__getitem__), &tp_version); -+ if (descriptor && Py_TYPE(descriptor) == &PyFunction_Type) { -+ if (!(container_type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { -+ Py_DECREF(descriptor); -+ return SPEC_FAIL_BINARY_OP_SUBSCR_NOT_HEAP_TYPE; -+ } -+ PyFunctionObject *func = (PyFunctionObject *)descriptor; -+ PyCodeObject *fcode = (PyCodeObject *)func->func_code; -+ int kind = function_kind(fcode); -+ if (kind != SIMPLE_FUNCTION) { -+ Py_DECREF(descriptor); -+ return kind; -+ } -+ if (fcode->co_argcount != 2) { -+ Py_DECREF(descriptor); -+ return SPEC_FAIL_WRONG_NUMBER_ARGUMENTS; -+ } -+ -+ if (_PyInterpreterState_GET()->eval_frame) { -+ /* Don't specialize if PEP 523 is active */ -+ Py_DECREF(descriptor); -+ return SPEC_FAIL_OTHER; -+ } -+ } -+ Py_XDECREF(descriptor); -+ return SPEC_FAIL_BINARY_OP_SUBSCR; - } - Py_UNREACHABLE(); - } - #endif - -+/** Binary Op Specialization Extensions */ -+ -+/* long-long */ -+ -+static inline int -+is_compactlong(PyObject *v) -+{ -+ return PyLong_CheckExact(v) && -+ _PyLong_IsCompact((PyLongObject *)v); -+} -+ -+static int -+compactlongs_guard(PyObject *lhs, PyObject *rhs) -+{ -+ return (is_compactlong(lhs) && is_compactlong(rhs)); -+} -+ -+#define BITWISE_LONGS_ACTION(NAME, OP) \ -+ static PyObject * \ -+ (NAME)(PyObject *lhs, PyObject *rhs) \ -+ { \ -+ Py_ssize_t rhs_val = _PyLong_CompactValue((PyLongObject *)rhs); \ -+ Py_ssize_t lhs_val = _PyLong_CompactValue((PyLongObject *)lhs); \ -+ return PyLong_FromSsize_t(lhs_val OP rhs_val); \ -+ } -+BITWISE_LONGS_ACTION(compactlongs_or, |) -+BITWISE_LONGS_ACTION(compactlongs_and, &) -+BITWISE_LONGS_ACTION(compactlongs_xor, ^) -+#undef BITWISE_LONGS_ACTION -+ -+/* float-long */ -+ -+static inline int -+float_compactlong_guard(PyObject *lhs, PyObject *rhs) -+{ -+ return ( -+ PyFloat_CheckExact(lhs) && -+ !isnan(PyFloat_AsDouble(lhs)) && -+ PyLong_CheckExact(rhs) && -+ _PyLong_IsCompact((PyLongObject *)rhs) -+ ); -+} -+ -+static inline int -+nonzero_float_compactlong_guard(PyObject *lhs, PyObject *rhs) -+{ -+ return ( -+ float_compactlong_guard(lhs, rhs) && !PyLong_IsZero(rhs) -+ ); -+} -+ -+#define FLOAT_LONG_ACTION(NAME, OP) \ -+ static PyObject * \ -+ (NAME)(PyObject *lhs, PyObject *rhs) \ -+ { \ -+ double lhs_val = PyFloat_AsDouble(lhs); \ -+ Py_ssize_t rhs_val = _PyLong_CompactValue((PyLongObject *)rhs); \ -+ return PyFloat_FromDouble(lhs_val OP rhs_val); \ -+ } -+FLOAT_LONG_ACTION(float_compactlong_add, +) -+FLOAT_LONG_ACTION(float_compactlong_subtract, -) -+FLOAT_LONG_ACTION(float_compactlong_multiply, *) -+FLOAT_LONG_ACTION(float_compactlong_true_div, /) -+#undef FLOAT_LONG_ACTION -+ -+/* long-float */ -+ -+static inline int -+compactlong_float_guard(PyObject *lhs, PyObject *rhs) -+{ -+ return ( -+ PyLong_CheckExact(lhs) && -+ _PyLong_IsCompact((PyLongObject *)lhs) && -+ PyFloat_CheckExact(rhs) && -+ !isnan(PyFloat_AsDouble(rhs)) -+ ); -+} -+ -+static inline int -+nonzero_compactlong_float_guard(PyObject *lhs, PyObject *rhs) -+{ -+ return ( -+ compactlong_float_guard(lhs, rhs) && PyFloat_AsDouble(rhs) != 0.0 -+ ); -+} -+ -+#define LONG_FLOAT_ACTION(NAME, OP) \ -+ static PyObject * \ -+ (NAME)(PyObject *lhs, PyObject *rhs) \ -+ { \ -+ double rhs_val = PyFloat_AsDouble(rhs); \ -+ Py_ssize_t lhs_val = _PyLong_CompactValue((PyLongObject *)lhs); \ -+ return PyFloat_FromDouble(lhs_val OP rhs_val); \ -+ } -+LONG_FLOAT_ACTION(compactlong_float_add, +) -+LONG_FLOAT_ACTION(compactlong_float_subtract, -) -+LONG_FLOAT_ACTION(compactlong_float_multiply, *) -+LONG_FLOAT_ACTION(compactlong_float_true_div, /) -+#undef LONG_FLOAT_ACTION -+ -+static _PyBinaryOpSpecializationDescr binaryop_extend_descrs[] = { -+ /* long-long arithmetic */ -+ {NB_OR, compactlongs_guard, compactlongs_or}, -+ {NB_AND, compactlongs_guard, compactlongs_and}, -+ {NB_XOR, compactlongs_guard, compactlongs_xor}, -+ {NB_INPLACE_OR, compactlongs_guard, compactlongs_or}, -+ {NB_INPLACE_AND, compactlongs_guard, compactlongs_and}, -+ {NB_INPLACE_XOR, compactlongs_guard, compactlongs_xor}, -+ -+ /* float-long arithemetic */ -+ {NB_ADD, float_compactlong_guard, float_compactlong_add}, -+ {NB_SUBTRACT, float_compactlong_guard, float_compactlong_subtract}, -+ {NB_TRUE_DIVIDE, nonzero_float_compactlong_guard, float_compactlong_true_div}, -+ {NB_MULTIPLY, float_compactlong_guard, float_compactlong_multiply}, -+ -+ /* float-float arithmetic */ -+ {NB_ADD, compactlong_float_guard, compactlong_float_add}, -+ {NB_SUBTRACT, compactlong_float_guard, compactlong_float_subtract}, -+ {NB_TRUE_DIVIDE, nonzero_compactlong_float_guard, compactlong_float_true_div}, -+ {NB_MULTIPLY, compactlong_float_guard, compactlong_float_multiply}, -+}; -+ -+static int -+binary_op_extended_specialization(PyObject *lhs, PyObject *rhs, int oparg, -+ _PyBinaryOpSpecializationDescr **descr) -+{ -+ size_t n = sizeof(binaryop_extend_descrs)/sizeof(_PyBinaryOpSpecializationDescr); -+ for (size_t i = 0; i < n; i++) { -+ _PyBinaryOpSpecializationDescr *d = &binaryop_extend_descrs[i]; -+ if (d->oparg == oparg && d->guard(lhs, rhs)) { -+ *descr = d; -+ return 1; -+ } -+ } -+ return 0; -+} -+ - void - _Py_Specialize_BinaryOp(_PyStackRef lhs_st, _PyStackRef rhs_st, _Py_CODEUNIT *instr, - int oparg, _PyStackRef *locals) -@@ -2326,6 +2503,12 @@ - PyObject *rhs = PyStackRef_AsPyObjectBorrow(rhs_st); - assert(ENABLE_SPECIALIZATION_FT); - assert(_PyOpcode_Caches[BINARY_OP] == INLINE_CACHE_ENTRIES_BINARY_OP); -+ -+ _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(instr + 1); -+ if (instr->op.code == BINARY_OP_EXTEND) { -+ write_ptr(cache->external_cache, NULL); -+ } -+ - switch (oparg) { - case NB_ADD: - case NB_INPLACE_ADD: -@@ -2379,9 +2562,59 @@ - return; - } - break; -+ case NB_SUBSCR: -+ if (PyLong_CheckExact(rhs) && _PyLong_IsNonNegativeCompact((PyLongObject *)rhs)) { -+ if (PyList_CheckExact(lhs)) { -+ specialize(instr, BINARY_OP_SUBSCR_LIST_INT); -+ return; -+ } -+ if (PyTuple_CheckExact(lhs)) { -+ specialize(instr, BINARY_OP_SUBSCR_TUPLE_INT); -+ return; -+ } -+ if (PyUnicode_CheckExact(lhs)) { -+ specialize(instr, BINARY_OP_SUBSCR_STR_INT); -+ return; -+ } -+ } -+ if (PyDict_CheckExact(lhs)) { -+ specialize(instr, BINARY_OP_SUBSCR_DICT); -+ return; -+ } -+ unsigned int tp_version; -+ PyTypeObject *container_type = Py_TYPE(lhs); -+ PyObject *descriptor = _PyType_LookupRefAndVersion(container_type, &_Py_ID(__getitem__), &tp_version); -+ if (descriptor && Py_TYPE(descriptor) == &PyFunction_Type && -+ container_type->tp_flags & Py_TPFLAGS_HEAPTYPE) -+ { -+ PyFunctionObject *func = (PyFunctionObject *)descriptor; -+ PyCodeObject *fcode = (PyCodeObject *)func->func_code; -+ int kind = function_kind(fcode); -+ PyHeapTypeObject *ht = (PyHeapTypeObject *)container_type; -+ if (kind == SIMPLE_FUNCTION && -+ fcode->co_argcount == 2 && -+ !_PyInterpreterState_GET()->eval_frame && /* Don't specialize if PEP 523 is active */ -+ _PyType_CacheGetItemForSpecialization(ht, descriptor, (uint32_t)tp_version)) -+ { -+ specialize(instr, BINARY_OP_SUBSCR_GETITEM); -+ Py_DECREF(descriptor); -+ return; -+ } -+ } -+ Py_XDECREF(descriptor); -+ break; -+ } -+ -+ _PyBinaryOpSpecializationDescr *descr; -+ if (binary_op_extended_specialization(lhs, rhs, oparg, &descr)) { -+ specialize(instr, BINARY_OP_EXTEND); -+ write_ptr(cache->external_cache, (void*)descr); -+ return; - } -+ - SPECIALIZATION_FAIL(BINARY_OP, binary_op_fail_kind(oparg, lhs, rhs)); - unspecialize(instr); -+ return; - } - - -@@ -2426,23 +2659,23 @@ - { - PyObject *lhs = PyStackRef_AsPyObjectBorrow(lhs_st); - PyObject *rhs = PyStackRef_AsPyObjectBorrow(rhs_st); -+ uint8_t specialized_op; - -- assert(ENABLE_SPECIALIZATION); -+ assert(ENABLE_SPECIALIZATION_FT); - assert(_PyOpcode_Caches[COMPARE_OP] == INLINE_CACHE_ENTRIES_COMPARE_OP); - // All of these specializations compute boolean values, so they're all valid - // regardless of the fifth-lowest oparg bit. -- _PyCompareOpCache *cache = (_PyCompareOpCache *)(instr + 1); - if (Py_TYPE(lhs) != Py_TYPE(rhs)) { - SPECIALIZATION_FAIL(COMPARE_OP, compare_op_fail_kind(lhs, rhs)); - goto failure; - } - if (PyFloat_CheckExact(lhs)) { -- instr->op.code = COMPARE_OP_FLOAT; -+ specialized_op = COMPARE_OP_FLOAT; - goto success; - } - if (PyLong_CheckExact(lhs)) { - if (_PyLong_IsCompact((PyLongObject *)lhs) && _PyLong_IsCompact((PyLongObject *)rhs)) { -- instr->op.code = COMPARE_OP_INT; -+ specialized_op = COMPARE_OP_INT; - goto success; - } - else { -@@ -2457,19 +2690,16 @@ - goto failure; - } - else { -- instr->op.code = COMPARE_OP_STR; -+ specialized_op = COMPARE_OP_STR; - goto success; - } - } - SPECIALIZATION_FAIL(COMPARE_OP, compare_op_fail_kind(lhs, rhs)); - failure: -- STAT_INC(COMPARE_OP, failure); -- instr->op.code = COMPARE_OP; -- cache->counter = adaptive_counter_backoff(cache->counter); -+ unspecialize(instr); - return; - success: -- STAT_INC(COMPARE_OP, success); -- cache->counter = adaptive_counter_cooldown(); -+ specialize(instr, specialized_op); - } - - #ifdef Py_STATS -@@ -2617,6 +2847,7 @@ - assert(instr[oparg + INLINE_CACHE_ENTRIES_FOR_ITER + 1].op.code == END_FOR || - instr[oparg + INLINE_CACHE_ENTRIES_FOR_ITER + 1].op.code == INSTRUMENTED_END_FOR - ); -+ /* Don't specialize if PEP 523 is active */ - if (_PyInterpreterState_GET()->eval_frame) { - SPECIALIZATION_FAIL(FOR_ITER, SPEC_FAIL_OTHER); - goto failure; -@@ -2645,6 +2876,7 @@ - assert(_PyOpcode_Caches[SEND] == INLINE_CACHE_ENTRIES_SEND); - PyTypeObject *tp = Py_TYPE(receiver); - if (tp == &PyGen_Type || tp == &PyCoro_Type) { -+ /* Don't specialize if PEP 523 is active */ - if (_PyInterpreterState_GET()->eval_frame) { - SPECIALIZATION_FAIL(SEND, SPEC_FAIL_OTHER); - goto failure; ---- /dev/null -+++ b/Python/stackrefs.c -@@ -0,0 +1,156 @@ -+ -+#include "Python.h" -+ -+#include "pycore_stackref.h" -+ -+#if !defined(Py_GIL_DISABLED) && defined(Py_STACKREF_DEBUG) -+ -+#if SIZEOF_VOID_P < 8 -+#error "Py_STACKREF_DEBUG requires 64 bit machine" -+#endif -+ -+#include "pycore_interp.h" -+#include "pycore_hashtable.h" -+ -+typedef struct _table_entry { -+ PyObject *obj; -+ const char *classname; -+ const char *filename; -+ int linenumber; -+ const char *filename_borrow; -+ int linenumber_borrow; -+} TableEntry; -+ -+TableEntry * -+make_table_entry(PyObject *obj, const char *filename, int linenumber) -+{ -+ TableEntry *result = malloc(sizeof(TableEntry)); -+ if (result == NULL) { -+ return NULL; -+ } -+ result->obj = obj; -+ result->classname = Py_TYPE(obj)->tp_name; -+ result->filename = filename; -+ result->linenumber = linenumber; -+ result->filename_borrow = NULL; -+ return result; -+} -+ -+PyObject * -+_Py_stackref_get_object(_PyStackRef ref) -+{ -+ if (ref.index == 0) { -+ return NULL; -+ } -+ PyInterpreterState *interp = PyInterpreterState_Get(); -+ assert(interp != NULL); -+ if (ref.index >= interp->next_stackref) { -+ _Py_FatalErrorFormat(__func__, "Garbled stack ref with ID %" PRIu64 "\n", ref.index); -+ } -+ TableEntry *entry = _Py_hashtable_get(interp->stackref_debug_table, (void *)ref.index); -+ if (entry == NULL) { -+ _Py_FatalErrorFormat(__func__, "Accessing closed stack ref with ID %" PRIu64 "\n", ref.index); -+ } -+ return entry->obj; -+} -+ -+PyObject * -+_Py_stackref_close(_PyStackRef ref) -+{ -+ PyInterpreterState *interp = PyInterpreterState_Get(); -+ if (ref.index >= interp->next_stackref) { -+ _Py_FatalErrorFormat(__func__, "Garbled stack ref with ID %" PRIu64 "\n", ref.index); -+ } -+ PyObject *obj; -+ if (ref.index <= LAST_PREDEFINED_STACKREF_INDEX) { -+ // Pre-allocated reference to None, False or True -- Do not clear -+ TableEntry *entry = _Py_hashtable_get(interp->stackref_debug_table, (void *)ref.index); -+ obj = entry->obj; -+ } -+ else { -+ TableEntry *entry = _Py_hashtable_steal(interp->stackref_debug_table, (void *)ref.index); -+ if (entry == NULL) { -+ _Py_FatalErrorFormat(__func__, "Invalid StackRef with ID %" PRIu64 "\n", (void *)ref.index); -+ } -+ obj = entry->obj; -+ free(entry); -+ } -+ return obj; -+} -+ -+_PyStackRef -+_Py_stackref_create(PyObject *obj, const char *filename, int linenumber) -+{ -+ if (obj == NULL) { -+ Py_FatalError("Cannot create a stackref for NULL"); -+ } -+ PyInterpreterState *interp = PyInterpreterState_Get(); -+ uint64_t new_id = interp->next_stackref++; -+ TableEntry *entry = make_table_entry(obj, filename, linenumber); -+ if (entry == NULL) { -+ Py_FatalError("No memory left for stackref debug table"); -+ } -+ if (_Py_hashtable_set(interp->stackref_debug_table, (void *)new_id, entry) < 0) { -+ Py_FatalError("No memory left for stackref debug table"); -+ } -+ return (_PyStackRef){ .index = new_id }; -+} -+ -+void -+_Py_stackref_record_borrow(_PyStackRef ref, const char *filename, int linenumber) -+{ -+ if (ref.index <= LAST_PREDEFINED_STACKREF_INDEX) { -+ return; -+ } -+ PyInterpreterState *interp = PyInterpreterState_Get(); -+ TableEntry *entry = _Py_hashtable_get(interp->stackref_debug_table, (void *)ref.index); -+ if (entry == NULL) { -+ _Py_FatalErrorFormat(__func__, "Invalid StackRef with ID %" PRIu64 "\n", (void *)ref.index); -+ } -+ entry->filename_borrow = filename; -+ entry->linenumber_borrow = linenumber; -+} -+ -+ -+void -+_Py_stackref_associate(PyInterpreterState *interp, PyObject *obj, _PyStackRef ref) -+{ -+ assert(interp->next_stackref >= ref.index); -+ interp->next_stackref = ref.index+1; -+ TableEntry *entry = make_table_entry(obj, "builtin-object", 0); -+ if (entry == NULL) { -+ Py_FatalError("No memory left for stackref debug table"); -+ } -+ if (_Py_hashtable_set(interp->stackref_debug_table, (void *)ref.index, (void *)entry) < 0) { -+ Py_FatalError("No memory left for stackref debug table"); -+ } -+} -+ -+ -+static int -+report_leak(_Py_hashtable_t *ht, const void *key, const void *value, void *leak) -+{ -+ TableEntry *entry = (TableEntry *)value; -+ if (!_Py_IsStaticImmortal(entry->obj)) { -+ *(int *)leak = 1; -+ printf("Stackref leak. Refers to instance of %s at %p. Created at %s:%d", -+ entry->classname, entry->obj, entry->filename, entry->linenumber); -+ if (entry->filename_borrow != NULL) { -+ printf(". Last borrow at %s:%d",entry->filename_borrow, entry->linenumber_borrow); -+ } -+ printf("\n"); -+ } -+ return 0; -+} -+ -+void -+_Py_stackref_report_leaks(PyInterpreterState *interp) -+{ -+ int leak = 0; -+ _Py_hashtable_foreach(interp->stackref_debug_table, report_leak, &leak); -+ if (leak) { -+ Py_FatalError("Stackrefs leaked."); -+ } -+} -+ -+#endif -diff --git a/Python/symtable.c b/Python/symtable.c -index ebddb0b93fc..49bd01ba68a 100644 ---- a/Python/symtable.c -+++ b/Python/symtable.c -@@ -138,6 +138,13 @@ - - ste->ste_has_docstring = 0; - -+ ste->ste_method = 0; -+ if (st->st_cur != NULL && -+ st->st_cur->ste_type == ClassBlock && -+ block == FunctionBlock) { -+ ste->ste_method = 1; -+ } -+ - ste->ste_symbols = PyDict_New(); - ste->ste_varnames = PyList_New(0); - ste->ste_children = PyList_New(0); -diff --git a/Python/sysmodule.c b/Python/sysmodule.c -index d6719f9bb0a..d5cb448eb61 100644 ---- a/Python/sysmodule.c -+++ b/Python/sysmodule.c -@@ -972,6 +972,23 @@ - return PyUnicode_CHECK_INTERNED(string); - } - -+/*[clinic input] -+sys._is_immortal -> bool -+ -+ op: object -+ / -+ -+Return True if the given object is "immortal" per PEP 683. -+ -+This function should be used for specialized purposes only. -+[clinic start generated code]*/ -+ -+static int -+sys__is_immortal_impl(PyObject *module, PyObject *op) -+/*[clinic end generated code: output=c2f5d6a80efb8d1a input=4609c9bf5481db76]*/ -+{ -+ return PyUnstable_IsImmortal(op); -+} - - /* - * Cached interned string objects used for calling the profile and -@@ -2265,9 +2282,7 @@ - { - #ifdef PY_HAVE_PERF_TRAMPOLINE - #ifdef _Py_JIT -- _PyOptimizerObject* optimizer = _Py_GetOptimizer(); -- if (optimizer != NULL) { -- Py_DECREF(optimizer); -+ if (_PyInterpreterState_GET()->jit) { - PyErr_SetString(PyExc_ValueError, "Cannot activate the perf trampoline if the JIT is active"); - return NULL; - } -@@ -2356,7 +2371,7 @@ - sys__dump_tracelets_impl(PyObject *module, PyObject *outpath) - /*[clinic end generated code: output=a7fe265e2bc3b674 input=5bff6880cd28ffd1]*/ - { -- FILE *out = _Py_fopen_obj(outpath, "wb"); -+ FILE *out = Py_fopen(outpath, "wb"); - if (out == NULL) { - return NULL; - } -@@ -2590,6 +2605,7 @@ - SYS__GETFRAMEMODULENAME_METHODDEF - SYS_GETWINDOWSVERSION_METHODDEF - SYS__ENABLELEGACYWINDOWSFSENCODING_METHODDEF -+ SYS__IS_IMMORTAL_METHODDEF - SYS_INTERN_METHODDEF - SYS__IS_INTERNED_METHODDEF - SYS_IS_FINALIZING_METHODDEF -@@ -2849,6 +2865,7 @@ - static int - _PySys_AddWarnOptionWithError(PyThreadState *tstate, PyObject *option) - { -+ assert(tstate != NULL); - PyObject *warnoptions = get_warnoptions(tstate); - if (warnoptions == NULL) { - return -1; -@@ -2864,11 +2881,11 @@ - PySys_AddWarnOptionUnicode(PyObject *option) - { - PyThreadState *tstate = _PyThreadState_GET(); -+ _Py_EnsureTstateNotNULL(tstate); -+ assert(!_PyErr_Occurred(tstate)); - if (_PySys_AddWarnOptionWithError(tstate, option) < 0) { - /* No return value, therefore clear error state if possible */ -- if (tstate) { -- _PyErr_Clear(tstate); -- } -+ _PyErr_Clear(tstate); - } - } - -diff --git a/Python/traceback.c b/Python/traceback.c -index e819909b604..870ae5bcefe 100644 ---- a/Python/traceback.c -+++ b/Python/traceback.c -@@ -38,6 +38,8 @@ - [clinic start generated code]*/ - /*[clinic end generated code: output=da39a3ee5e6b4b0d input=cf96294b2bebc811]*/ - -+#define _PyTracebackObject_CAST(op) ((PyTracebackObject *)(op)) -+ - #include "clinic/traceback.c.h" - - static PyObject * -@@ -91,15 +93,16 @@ - } - - static PyObject * --tb_dir(PyTracebackObject *self, PyObject *Py_UNUSED(ignored)) -+tb_dir(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) - { - return Py_BuildValue("[ssss]", "tb_frame", "tb_next", - "tb_lasti", "tb_lineno"); - } - - static PyObject * --tb_next_get(PyTracebackObject *self, void *Py_UNUSED(_)) -+tb_next_get(PyObject *op, void *Py_UNUSED(_)) - { -+ PyTracebackObject *self = _PyTracebackObject_CAST(op); - PyObject* ret = (PyObject*)self->tb_next; - if (!ret) { - ret = Py_None; -@@ -108,18 +111,21 @@ - } - - static int --tb_get_lineno(PyTracebackObject* tb) { -+tb_get_lineno(PyObject *op) -+{ -+ PyTracebackObject *tb = _PyTracebackObject_CAST(op); - _PyInterpreterFrame* frame = tb->tb_frame->f_frame; - assert(frame != NULL); - return PyCode_Addr2Line(_PyFrame_GetCode(frame), tb->tb_lasti); - } - - static PyObject * --tb_lineno_get(PyTracebackObject *self, void *Py_UNUSED(_)) -+tb_lineno_get(PyObject *op, void *Py_UNUSED(_)) - { -+ PyTracebackObject *self = _PyTracebackObject_CAST(op); - int lineno = self->tb_lineno; - if (lineno == -1) { -- lineno = tb_get_lineno(self); -+ lineno = tb_get_lineno(op); - if (lineno < 0) { - Py_RETURN_NONE; - } -@@ -128,7 +134,7 @@ - } - - static int --tb_next_set(PyTracebackObject *self, PyObject *new_next, void *Py_UNUSED(_)) -+tb_next_set(PyObject *op, PyObject *new_next, void *Py_UNUSED(_)) - { - if (!new_next) { - PyErr_Format(PyExc_TypeError, "can't delete tb_next attribute"); -@@ -147,6 +153,7 @@ - } - - /* Check for loops */ -+ PyTracebackObject *self = _PyTracebackObject_CAST(op); - PyTracebackObject *cursor = (PyTracebackObject *)new_next; - while (cursor) { - if (cursor == self) { -@@ -163,7 +170,7 @@ - - - static PyMethodDef tb_methods[] = { -- {"__dir__", _PyCFunction_CAST(tb_dir), METH_NOARGS}, -+ {"__dir__", tb_dir, METH_NOARGS, NULL}, - {NULL, NULL, 0, NULL}, - }; - -@@ -174,14 +181,15 @@ - }; - - static PyGetSetDef tb_getsetters[] = { -- {"tb_next", (getter)tb_next_get, (setter)tb_next_set, NULL, NULL}, -- {"tb_lineno", (getter)tb_lineno_get, NULL, NULL, NULL}, -+ {"tb_next", tb_next_get, tb_next_set, NULL, NULL}, -+ {"tb_lineno", tb_lineno_get, NULL, NULL, NULL}, - {NULL} /* Sentinel */ - }; - - static void --tb_dealloc(PyTracebackObject *tb) -+tb_dealloc(PyObject *op) - { -+ PyTracebackObject *tb = _PyTracebackObject_CAST(op); - PyObject_GC_UnTrack(tb); - Py_TRASHCAN_BEGIN(tb, tb_dealloc) - Py_XDECREF(tb->tb_next); -@@ -191,16 +199,18 @@ - } - - static int --tb_traverse(PyTracebackObject *tb, visitproc visit, void *arg) -+tb_traverse(PyObject *op, visitproc visit, void *arg) - { -+ PyTracebackObject *tb = _PyTracebackObject_CAST(op); - Py_VISIT(tb->tb_next); - Py_VISIT(tb->tb_frame); - return 0; - } - - static int --tb_clear(PyTracebackObject *tb) -+tb_clear(PyObject *op) - { -+ PyTracebackObject *tb = _PyTracebackObject_CAST(op); - Py_CLEAR(tb->tb_next); - Py_CLEAR(tb->tb_frame); - return 0; -@@ -211,7 +221,7 @@ - "traceback", - sizeof(PyTracebackObject), - 0, -- (destructor)tb_dealloc, /*tp_dealloc*/ -+ tb_dealloc, /*tp_dealloc*/ - 0, /*tp_vectorcall_offset*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ -@@ -228,8 +238,8 @@ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ - tb_new__doc__, /* tp_doc */ -- (traverseproc)tb_traverse, /* tp_traverse */ -- (inquiry)tb_clear, /* tp_clear */ -+ tb_traverse, /* tp_traverse */ -+ tb_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ -@@ -663,7 +673,7 @@ - code = PyFrame_GetCode(tb->tb_frame); - int tb_lineno = tb->tb_lineno; - if (tb_lineno == -1) { -- tb_lineno = tb_get_lineno(tb); -+ tb_lineno = tb_get_lineno((PyObject *)tb); - } - if (last_file == NULL || - code->co_filename != last_file || -@@ -890,7 +900,7 @@ - static void - dump_frame(int fd, _PyInterpreterFrame *frame) - { -- assert(frame->owner != FRAME_OWNED_BY_CSTACK); -+ assert(frame->owner < FRAME_OWNED_BY_INTERPRETER); - - PyCodeObject *code =_PyFrame_GetCode(frame); - PUTS(fd, " File "); -@@ -965,7 +975,7 @@ - - unsigned int depth = 0; - while (1) { -- if (frame->owner == FRAME_OWNED_BY_CSTACK) { -+ if (frame->owner == FRAME_OWNED_BY_INTERPRETER) { - /* Trampoline frame */ - frame = frame->previous; - if (frame == NULL) { -@@ -973,7 +983,7 @@ - } - - /* Can't have more than one shim frame in a row */ -- assert(frame->owner != FRAME_OWNED_BY_CSTACK); -+ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); - } - - if (MAX_FRAME_DEPTH <= depth) { -diff --git a/Python/tracemalloc.c b/Python/tracemalloc.c -index f661d69c031..d69b0ebd585 100644 ---- a/Python/tracemalloc.c -+++ b/Python/tracemalloc.c -@@ -2,6 +2,8 @@ - #include "pycore_fileutils.h" // _Py_write_noraise() - #include "pycore_gc.h" // PyGC_Head - #include "pycore_hashtable.h" // _Py_hashtable_t -+#include "pycore_initconfig.h" // _PyStatus_NO_MEMORY() -+#include "pycore_lock.h" // PyMutex_LockFlags() - #include "pycore_object.h" // _PyType_PreHeaderSize() - #include "pycore_pymem.h" // _Py_tracemalloc_config - #include "pycore_runtime.h" // _Py_ID() -@@ -19,6 +21,8 @@ - /* Forward declaration */ - static void* raw_malloc(size_t size); - static void raw_free(void *ptr); -+static int _PyTraceMalloc_TraceRef(PyObject *op, PyRefTracerEvent event, -+ void* Py_UNUSED(ignore)); - - #ifdef Py_DEBUG - # define TRACE_DEBUG -@@ -30,18 +34,12 @@ - #define allocators _PyRuntime.tracemalloc.allocators - - --#if defined(TRACE_RAW_MALLOC) - /* This lock is needed because tracemalloc_free() is called without - the GIL held from PyMem_RawFree(). It cannot acquire the lock because it - would introduce a deadlock in _PyThreadState_DeleteCurrent(). */ --# define tables_lock _PyRuntime.tracemalloc.tables_lock --# define TABLES_LOCK() PyThread_acquire_lock(tables_lock, 1) --# define TABLES_UNLOCK() PyThread_release_lock(tables_lock) --#else -- /* variables are protected by the GIL */ --# define TABLES_LOCK() --# define TABLES_UNLOCK() --#endif -+#define tables_lock _PyRuntime.tracemalloc.tables_lock -+#define TABLES_LOCK() PyMutex_LockFlags(&tables_lock, _Py_LOCK_DONT_DETACH) -+#define TABLES_UNLOCK() PyMutex_Unlock(&tables_lock) - - - #define DEFAULT_DOMAIN 0 -@@ -95,9 +93,6 @@ - #endif - - --#if defined(TRACE_RAW_MALLOC) --#define REENTRANT_THREADLOCAL -- - #define tracemalloc_reentrant_key _PyRuntime.tracemalloc.reentrant_key - - /* Any non-NULL pointer can be used */ -@@ -106,16 +101,16 @@ - static int - get_reentrant(void) - { -- void *ptr; -- - assert(PyThread_tss_is_created(&tracemalloc_reentrant_key)); -- ptr = PyThread_tss_get(&tracemalloc_reentrant_key); -+ -+ void *ptr = PyThread_tss_get(&tracemalloc_reentrant_key); - if (ptr != NULL) { - assert(ptr == REENTRANT); - return 1; - } -- else -+ else { - return 0; -+ } - } - - static void -@@ -134,25 +129,6 @@ - } - } - --#else -- --/* TRACE_RAW_MALLOC not defined: variable protected by the GIL */ --static int tracemalloc_reentrant = 0; -- --static int --get_reentrant(void) --{ -- return tracemalloc_reentrant; --} -- --static void --set_reentrant(int reentrant) --{ -- assert(reentrant != tracemalloc_reentrant); -- tracemalloc_reentrant = reentrant; --} --#endif -- - - static Py_uhash_t - hashtable_hash_pyobject(const void *key) -@@ -252,6 +228,7 @@ - { - assert(PyStackRef_CodeCheck(pyframe->f_executable)); - frame->filename = &_Py_STR(anon_unknown); -+ - int lineno = PyUnstable_InterpreterFrame_GetLine(pyframe); - if (lineno < 0) { - lineno = 0; -@@ -259,7 +236,6 @@ - frame->lineno = (unsigned int)lineno; - - PyObject *filename = filename = _PyFrame_GetCode(pyframe)->co_filename; -- - if (filename == NULL) { - #ifdef TRACE_DEBUG - tracemalloc_error("failed to get the filename of the code object"); -@@ -275,7 +251,7 @@ - } - if (!PyUnicode_IS_READY(filename)) { - /* Don't make a Unicode string ready to avoid reentrant calls -- to tracemalloc_malloc() or tracemalloc_realloc() */ -+ to tracemalloc_alloc() or tracemalloc_realloc() */ - #ifdef TRACE_DEBUG - tracemalloc_error("filename is not a ready unicode string"); - #endif -@@ -309,7 +285,7 @@ - static Py_uhash_t - traceback_hash(traceback_t *traceback) - { -- /* code based on tuplehash() of Objects/tupleobject.c */ -+ /* code based on tuple_hash() of Objects/tupleobject.c */ - Py_uhash_t x, y; /* Unsigned for defined overflow behavior. */ - int len = traceback->nframe; - Py_uhash_t mult = PyHASH_MULTIPLIER; -@@ -335,13 +311,8 @@ - static void - traceback_get_frames(traceback_t *traceback) - { -- PyThreadState *tstate = PyGILState_GetThisThreadState(); -- if (tstate == NULL) { --#ifdef TRACE_DEBUG -- tracemalloc_error("failed to get the current thread state"); --#endif -- return; -- } -+ PyThreadState *tstate = _PyThreadState_GET(); -+ assert(tstate != NULL); - - _PyInterpreterFrame *pyframe = _PyThreadState_GetFrame(tstate); - while (pyframe) { -@@ -364,7 +335,7 @@ - traceback_t *traceback; - _Py_hashtable_entry_t *entry; - -- assert(PyGILState_Check()); -+ _Py_AssertHoldsTstate(); - - /* get frames */ - traceback = tracemalloc_traceback; -@@ -440,7 +411,7 @@ - - - static void --tracemalloc_remove_trace(unsigned int domain, uintptr_t ptr) -+tracemalloc_remove_trace_unlocked(unsigned int domain, uintptr_t ptr) - { - assert(tracemalloc_config.tracing); - -@@ -459,12 +430,12 @@ - } - - #define REMOVE_TRACE(ptr) \ -- tracemalloc_remove_trace(DEFAULT_DOMAIN, (uintptr_t)(ptr)) -+ tracemalloc_remove_trace_unlocked(DEFAULT_DOMAIN, (uintptr_t)(ptr)) - - - static int --tracemalloc_add_trace(unsigned int domain, uintptr_t ptr, -- size_t size) -+tracemalloc_add_trace_unlocked(unsigned int domain, uintptr_t ptr, -+ size_t size) - { - assert(tracemalloc_config.tracing); - -@@ -519,82 +490,147 @@ - } - - #define ADD_TRACE(ptr, size) \ -- tracemalloc_add_trace(DEFAULT_DOMAIN, (uintptr_t)(ptr), size) -+ tracemalloc_add_trace_unlocked(DEFAULT_DOMAIN, (uintptr_t)(ptr), size) - - - static void* --tracemalloc_alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize) -+tracemalloc_alloc(int need_gil, int use_calloc, -+ void *ctx, size_t nelem, size_t elsize) - { -- PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; -- void *ptr; -- - assert(elsize == 0 || nelem <= SIZE_MAX / elsize); - -- if (use_calloc) -+ int reentrant = get_reentrant(); -+ -+ // Ignore reentrant call. -+ // -+ // For example, PyObjet_Malloc() calls -+ // PyMem_Malloc() for allocations larger than 512 bytes: don't trace the -+ // same memory allocation twice. -+ // -+ // If reentrant calls are not ignored, PyGILState_Ensure() can call -+ // PyMem_RawMalloc() which would call PyGILState_Ensure() again in a loop. -+ if (!reentrant) { -+ set_reentrant(1); -+ } -+ -+ PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; -+ void *ptr; -+ if (use_calloc) { - ptr = alloc->calloc(alloc->ctx, nelem, elsize); -- else -+ } -+ else { - ptr = alloc->malloc(alloc->ctx, nelem * elsize); -- if (ptr == NULL) -- return NULL; -+ } -+ -+ if (ptr == NULL) { -+ goto done; -+ } -+ if (reentrant) { -+ goto done; -+ } - -+ PyGILState_STATE gil_state; -+ if (need_gil) { -+ gil_state = PyGILState_Ensure(); -+ } - TABLES_LOCK(); -- if (ADD_TRACE(ptr, nelem * elsize) < 0) { -- /* Failed to allocate a trace for the new memory block */ -- TABLES_UNLOCK(); -- alloc->free(alloc->ctx, ptr); -- return NULL; -+ -+ if (tracemalloc_config.tracing) { -+ if (ADD_TRACE(ptr, nelem * elsize) < 0) { -+ // Failed to allocate a trace for the new memory block -+ alloc->free(alloc->ctx, ptr); -+ ptr = NULL; -+ } - } -+ // else: gh-128679: tracemalloc.stop() was called by another thread -+ - TABLES_UNLOCK(); -+ if (need_gil) { -+ PyGILState_Release(gil_state); -+ } -+ -+done: -+ if (!reentrant) { -+ set_reentrant(0); -+ } - return ptr; - } - - - static void* --tracemalloc_realloc(void *ctx, void *ptr, size_t new_size) -+tracemalloc_realloc(int need_gil, void *ctx, void *ptr, size_t new_size) - { -+ int reentrant = get_reentrant(); -+ -+ // Ignore reentrant call. PyObjet_Realloc() calls PyMem_Realloc() for -+ // allocations larger than 512 bytes: don't trace the same memory block -+ // twice. -+ if (!reentrant) { -+ set_reentrant(1); -+ } -+ - PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; -- void *ptr2; -+ void *ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); - -- ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); -- if (ptr2 == NULL) -- return NULL; -+ if (ptr2 == NULL) { -+ goto done; -+ } -+ if (reentrant) { -+ goto done; -+ } - -- if (ptr != NULL) { -- /* an existing memory block has been resized */ -+ PyGILState_STATE gil_state; -+ if (need_gil) { -+ gil_state = PyGILState_Ensure(); -+ } -+ TABLES_LOCK(); - -- TABLES_LOCK(); -+ if (!tracemalloc_config.tracing) { -+ // gh-128679: tracemalloc.stop() was called by another thread -+ goto unlock; -+ } -+ -+ if (ptr != NULL) { -+ // An existing memory block has been resized - -- /* tracemalloc_add_trace() updates the trace if there is already -- a trace at address ptr2 */ -+ // tracemalloc_add_trace_unlocked() updates the trace if there is -+ // already a trace at address ptr2. - if (ptr2 != ptr) { - REMOVE_TRACE(ptr); - } - - if (ADD_TRACE(ptr2, new_size) < 0) { -- /* Memory allocation failed. The error cannot be reported to -- the caller, because realloc() may already have shrunk the -- memory block and so removed bytes. -- -- This case is very unlikely: a hash entry has just been -- released, so the hash table should have at least one free entry. -- -- The GIL and the table lock ensures that only one thread is -- allocating memory. */ -+ // Memory allocation failed. The error cannot be reported to the -+ // caller, because realloc() already have shrunk the memory block -+ // and so removed bytes. -+ // -+ // This case is very unlikely: a hash entry has just been released, -+ // so the hash table should have at least one free entry. -+ // -+ // The GIL and the table lock ensures that only one thread is -+ // allocating memory. - Py_FatalError("tracemalloc_realloc() failed to allocate a trace"); - } -- TABLES_UNLOCK(); - } - else { -- /* new allocation */ -+ // New allocation - -- TABLES_LOCK(); - if (ADD_TRACE(ptr2, new_size) < 0) { -- /* Failed to allocate a trace for the new memory block */ -- TABLES_UNLOCK(); -+ // Failed to allocate a trace for the new memory block - alloc->free(alloc->ctx, ptr2); -- return NULL; -+ ptr2 = NULL; - } -- TABLES_UNLOCK(); -+ } -+ -+unlock: -+ TABLES_UNLOCK(); -+ if (need_gil) { -+ PyGILState_Release(gil_state); -+ } -+ -+done: -+ if (!reentrant) { -+ set_reentrant(0); - } - return ptr2; - } -@@ -603,170 +639,68 @@ - static void - tracemalloc_free(void *ctx, void *ptr) - { -- PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; -- -- if (ptr == NULL) -+ if (ptr == NULL) { - return; -+ } - -- /* GIL cannot be locked in PyMem_RawFree() because it would introduce -- a deadlock in _PyThreadState_DeleteCurrent(). */ -- -+ PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; - alloc->free(alloc->ctx, ptr); - -- TABLES_LOCK(); -- REMOVE_TRACE(ptr); -- TABLES_UNLOCK(); --} -- -- --static void* --tracemalloc_alloc_gil(int use_calloc, void *ctx, size_t nelem, size_t elsize) --{ -- void *ptr; -- - if (get_reentrant()) { -- PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; -- if (use_calloc) -- return alloc->calloc(alloc->ctx, nelem, elsize); -- else -- return alloc->malloc(alloc->ctx, nelem * elsize); -+ return; - } - -- /* Ignore reentrant call. PyObjet_Malloc() calls PyMem_Malloc() for -- allocations larger than 512 bytes, don't trace the same memory -- allocation twice. */ -- set_reentrant(1); -+ TABLES_LOCK(); - -- ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize); -+ if (tracemalloc_config.tracing) { -+ REMOVE_TRACE(ptr); -+ } -+ // else: gh-128679: tracemalloc.stop() was called by another thread - -- set_reentrant(0); -- return ptr; -+ TABLES_UNLOCK(); - } - - - static void* - tracemalloc_malloc_gil(void *ctx, size_t size) - { -- return tracemalloc_alloc_gil(0, ctx, 1, size); -+ return tracemalloc_alloc(0, 0, ctx, 1, size); - } - - - static void* - tracemalloc_calloc_gil(void *ctx, size_t nelem, size_t elsize) - { -- return tracemalloc_alloc_gil(1, ctx, nelem, elsize); -+ return tracemalloc_alloc(0, 1, ctx, nelem, elsize); - } - - - static void* - tracemalloc_realloc_gil(void *ctx, void *ptr, size_t new_size) - { -- void *ptr2; -- -- if (get_reentrant()) { -- /* Reentrant call to PyMem_Realloc() and PyMem_RawRealloc(). -- Example: PyMem_RawRealloc() is called internally by pymalloc -- (_PyObject_Malloc() and _PyObject_Realloc()) to allocate a new -- arena (new_arena()). */ -- PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; -- -- ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); -- if (ptr2 != NULL && ptr != NULL) { -- TABLES_LOCK(); -- REMOVE_TRACE(ptr); -- TABLES_UNLOCK(); -- } -- return ptr2; -- } -- -- /* Ignore reentrant call. PyObjet_Realloc() calls PyMem_Realloc() for -- allocations larger than 512 bytes. Don't trace the same memory -- allocation twice. */ -- set_reentrant(1); -- -- ptr2 = tracemalloc_realloc(ctx, ptr, new_size); -- -- set_reentrant(0); -- return ptr2; --} -- -- --#ifdef TRACE_RAW_MALLOC --static void* --tracemalloc_raw_alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize) --{ -- PyGILState_STATE gil_state; -- void *ptr; -- -- if (get_reentrant()) { -- PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; -- if (use_calloc) -- return alloc->calloc(alloc->ctx, nelem, elsize); -- else -- return alloc->malloc(alloc->ctx, nelem * elsize); -- } -- -- /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc() -- indirectly which would call PyGILState_Ensure() if reentrant are not -- disabled. */ -- set_reentrant(1); -- -- gil_state = PyGILState_Ensure(); -- ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize); -- PyGILState_Release(gil_state); -- -- set_reentrant(0); -- return ptr; -+ return tracemalloc_realloc(0, ctx, ptr, new_size); - } - - - static void* - tracemalloc_raw_malloc(void *ctx, size_t size) - { -- return tracemalloc_raw_alloc(0, ctx, 1, size); -+ return tracemalloc_alloc(1, 0, ctx, 1, size); - } - - - static void* - tracemalloc_raw_calloc(void *ctx, size_t nelem, size_t elsize) - { -- return tracemalloc_raw_alloc(1, ctx, nelem, elsize); -+ return tracemalloc_alloc(1, 1, ctx, nelem, elsize); - } - - - static void* - tracemalloc_raw_realloc(void *ctx, void *ptr, size_t new_size) - { -- PyGILState_STATE gil_state; -- void *ptr2; -- -- if (get_reentrant()) { -- /* Reentrant call to PyMem_RawRealloc(). */ -- PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; -- -- ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); -- -- if (ptr2 != NULL && ptr != NULL) { -- TABLES_LOCK(); -- REMOVE_TRACE(ptr); -- TABLES_UNLOCK(); -- } -- return ptr2; -- } -- -- /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc() -- indirectly which would call PyGILState_Ensure() if reentrant calls are -- not disabled. */ -- set_reentrant(1); -- -- gil_state = PyGILState_Ensure(); -- ptr2 = tracemalloc_realloc(ctx, ptr, new_size); -- PyGILState_Release(gil_state); -- -- set_reentrant(0); -- return ptr2; -+ return tracemalloc_realloc(1, ctx, ptr, new_size); - } --#endif /* TRACE_RAW_MALLOC */ - - - static void -@@ -777,60 +711,36 @@ - } - - --/* reentrant flag must be set to call this function and GIL must be held */ - static void --tracemalloc_clear_traces(void) -+tracemalloc_clear_traces_unlocked(void) - { -- /* The GIL protects variables against concurrent access */ -- assert(PyGILState_Check()); -+ // Clearing tracemalloc_filenames requires the GIL to call Py_DECREF() -+ _Py_AssertHoldsTstate(); -+ -+ set_reentrant(1); - -- TABLES_LOCK(); - _Py_hashtable_clear(tracemalloc_traces); - _Py_hashtable_clear(tracemalloc_domains); -+ _Py_hashtable_clear(tracemalloc_tracebacks); -+ _Py_hashtable_clear(tracemalloc_filenames); -+ - tracemalloc_traced_memory = 0; - tracemalloc_peak_traced_memory = 0; -- TABLES_UNLOCK(); -- -- _Py_hashtable_clear(tracemalloc_tracebacks); - -- _Py_hashtable_clear(tracemalloc_filenames); -+ set_reentrant(0); - } - - --int -+PyStatus - _PyTraceMalloc_Init(void) - { -- if (tracemalloc_config.initialized == TRACEMALLOC_FINALIZED) { -- PyErr_SetString(PyExc_RuntimeError, -- "the tracemalloc module has been unloaded"); -- return -1; -- } -- -- if (tracemalloc_config.initialized == TRACEMALLOC_INITIALIZED) -- return 0; -+ assert(tracemalloc_config.initialized == TRACEMALLOC_NOT_INITIALIZED); - - PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw); - --#ifdef REENTRANT_THREADLOCAL - if (PyThread_tss_create(&tracemalloc_reentrant_key) != 0) { --#ifdef MS_WINDOWS -- PyErr_SetFromWindowsErr(0); --#else -- PyErr_SetFromErrno(PyExc_OSError); --#endif -- return -1; -- } --#endif -- --#if defined(TRACE_RAW_MALLOC) -- if (tables_lock == NULL) { -- tables_lock = PyThread_allocate_lock(); -- if (tables_lock == NULL) { -- PyErr_SetString(PyExc_RuntimeError, "cannot allocate lock"); -- return -1; -- } -+ return _PyStatus_NO_MEMORY(); - } --#endif - - tracemalloc_filenames = hashtable_new(hashtable_hash_pyobject, - hashtable_compare_unicode, -@@ -844,9 +754,9 @@ - tracemalloc_domains = tracemalloc_create_domains_table(); - - if (tracemalloc_filenames == NULL || tracemalloc_tracebacks == NULL -- || tracemalloc_traces == NULL || tracemalloc_domains == NULL) { -- PyErr_NoMemory(); -- return -1; -+ || tracemalloc_traces == NULL || tracemalloc_domains == NULL) -+ { -+ return _PyStatus_NO_MEMORY(); - } - - tracemalloc_empty_traceback.nframe = 1; -@@ -857,7 +767,7 @@ - tracemalloc_empty_traceback.hash = traceback_hash(&tracemalloc_empty_traceback); - - tracemalloc_config.initialized = TRACEMALLOC_INITIALIZED; -- return 0; -+ return _PyStatus_OK(); - } - - -@@ -876,25 +786,13 @@ - _Py_hashtable_destroy(tracemalloc_tracebacks); - _Py_hashtable_destroy(tracemalloc_filenames); - --#if defined(TRACE_RAW_MALLOC) -- if (tables_lock != NULL) { -- PyThread_free_lock(tables_lock); -- tables_lock = NULL; -- } --#endif -- --#ifdef REENTRANT_THREADLOCAL - PyThread_tss_delete(&tracemalloc_reentrant_key); --#endif - } - - - int - _PyTraceMalloc_Start(int max_nframe) - { -- PyMemAllocatorEx alloc; -- size_t size; -- - if (max_nframe < 1 || (unsigned long) max_nframe > MAX_NFRAME) { - PyErr_Format(PyExc_ValueError, - "the number of frames must be in range [1; %lu]", -@@ -902,23 +800,15 @@ - return -1; - } - -- if (_PyTraceMalloc_Init() < 0) { -- return -1; -- } -- -- if (PyRefTracer_SetTracer(_PyTraceMalloc_TraceRef, NULL) < 0) { -- return -1; -- } -- -- if (tracemalloc_config.tracing) { -- /* hook already installed: do nothing */ -+ if (_PyTraceMalloc_IsTracing()) { -+ /* hooks already installed: do nothing */ - return 0; - } - - tracemalloc_config.max_nframe = max_nframe; - - /* allocate a buffer to store a new traceback */ -- size = TRACEBACK_SIZE(max_nframe); -+ size_t size = TRACEBACK_SIZE(max_nframe); - assert(tracemalloc_traceback == NULL); - tracemalloc_traceback = raw_malloc(size); - if (tracemalloc_traceback == NULL) { -@@ -926,7 +816,7 @@ - return -1; - } - --#ifdef TRACE_RAW_MALLOC -+ PyMemAllocatorEx alloc; - alloc.malloc = tracemalloc_raw_malloc; - alloc.calloc = tracemalloc_raw_calloc; - alloc.realloc = tracemalloc_raw_realloc; -@@ -935,7 +825,6 @@ - alloc.ctx = &allocators.raw; - PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw); - PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc); --#endif - - alloc.malloc = tracemalloc_malloc_gil; - alloc.calloc = tracemalloc_calloc_gil; -@@ -950,8 +839,14 @@ - PyMem_GetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj); - PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &alloc); - -+ if (PyRefTracer_SetTracer(_PyTraceMalloc_TraceRef, NULL) < 0) { -+ return -1; -+ } -+ - /* everything is ready: start tracing Python memory allocations */ -+ TABLES_LOCK(); - tracemalloc_config.tracing = 1; -+ TABLES_UNLOCK(); - - return 0; - } -@@ -960,24 +855,30 @@ - void - _PyTraceMalloc_Stop(void) - { -- if (!tracemalloc_config.tracing) -- return; -+ TABLES_LOCK(); -+ -+ if (!tracemalloc_config.tracing) { -+ goto done; -+ } - - /* stop tracing Python memory allocations */ - tracemalloc_config.tracing = 0; - - /* unregister the hook on memory allocators */ --#ifdef TRACE_RAW_MALLOC - PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw); --#endif - PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem); - PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj); - -- tracemalloc_clear_traces(); -+ tracemalloc_clear_traces_unlocked(); - - /* release memory */ - raw_free(tracemalloc_traceback); - tracemalloc_traceback = NULL; -+ -+ (void)PyRefTracer_SetTracer(NULL, NULL); -+ -+done: -+ TABLES_UNLOCK(); - } - - -@@ -985,15 +886,16 @@ - static PyObject* - frame_to_pyobject(frame_t *frame) - { -- PyObject *frame_obj, *lineno_obj; -+ assert(get_reentrant()); - -- frame_obj = PyTuple_New(2); -- if (frame_obj == NULL) -+ PyObject *frame_obj = PyTuple_New(2); -+ if (frame_obj == NULL) { - return NULL; -+ } - - PyTuple_SET_ITEM(frame_obj, 0, Py_NewRef(frame->filename)); - -- lineno_obj = PyLong_FromUnsignedLong(frame->lineno); -+ PyObject *lineno_obj = PyLong_FromUnsignedLong(frame->lineno); - if (lineno_obj == NULL) { - Py_DECREF(frame_obj); - return NULL; -@@ -1008,7 +910,6 @@ - traceback_to_pyobject(traceback_t *traceback, _Py_hashtable_t *intern_table) - { - PyObject *frames; -- - if (intern_table != NULL) { - frames = _Py_hashtable_get(intern_table, (const void *)traceback); - if (frames) { -@@ -1017,8 +918,9 @@ - } - - frames = PyTuple_New(traceback->nframe); -- if (frames == NULL) -+ if (frames == NULL) { - return NULL; -+ } - - for (int i=0; i < traceback->nframe; i++) { - PyObject *frame = frame_to_pyobject(&traceback->frames[i]); -@@ -1046,14 +948,14 @@ - trace_to_pyobject(unsigned int domain, const trace_t *trace, - _Py_hashtable_t *intern_tracebacks) - { -- PyObject *trace_obj = NULL; -- PyObject *obj; -+ assert(get_reentrant()); - -- trace_obj = PyTuple_New(4); -- if (trace_obj == NULL) -+ PyObject *trace_obj = PyTuple_New(4); -+ if (trace_obj == NULL) { - return NULL; -+ } - -- obj = PyLong_FromSize_t(domain); -+ PyObject *obj = PyLong_FromSize_t(domain); - if (obj == NULL) { - Py_DECREF(trace_obj); - return NULL; -@@ -1100,7 +1002,6 @@ - void *user_data) - { - _Py_hashtable_t *traces2 = (_Py_hashtable_t *)user_data; -- - trace_t *trace = (trace_t *)value; - - trace_t *trace2 = raw_malloc(sizeof(trace_t)); -@@ -1141,7 +1042,6 @@ - void *user_data) - { - _Py_hashtable_t *domains2 = (_Py_hashtable_t *)user_data; -- - unsigned int domain = (unsigned int)FROM_PTR(key); - _Py_hashtable_t *traces = (_Py_hashtable_t *)value; - -@@ -1182,7 +1082,6 @@ - void *user_data) - { - get_traces_t *get_traces = user_data; -- - const trace_t *trace = (const trace_t *)value; - - PyObject *tuple = trace_to_pyobject(get_traces->domain, trace, -@@ -1196,7 +1095,6 @@ - if (res < 0) { - return 1; - } -- - return 0; - } - -@@ -1207,7 +1105,6 @@ - void *user_data) - { - get_traces_t *get_traces = user_data; -- - unsigned int domain = (unsigned int)FROM_PTR(key); - _Py_hashtable_t *traces = (_Py_hashtable_t *)value; - -@@ -1227,27 +1124,21 @@ - - - static traceback_t* --tracemalloc_get_traceback(unsigned int domain, uintptr_t ptr) -+tracemalloc_get_traceback_unlocked(unsigned int domain, uintptr_t ptr) - { -- -- if (!tracemalloc_config.tracing) -+ if (!tracemalloc_config.tracing) { - return NULL; -+ } - -- trace_t *trace; -- TABLES_LOCK(); - _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain); -- if (traces) { -- trace = _Py_hashtable_get(traces, TO_PTR(ptr)); -- } -- else { -- trace = NULL; -+ if (!traces) { -+ return NULL; - } -- TABLES_UNLOCK(); - -+ trace_t *trace = _Py_hashtable_get(traces, TO_PTR(ptr)); - if (!trace) { - return NULL; - } -- - return trace->traceback; - } - -@@ -1269,24 +1160,28 @@ - void - _PyMem_DumpTraceback(int fd, const void *ptr) - { -- traceback_t *traceback; -- int i; -- -+ TABLES_LOCK(); - if (!tracemalloc_config.tracing) { - PUTS(fd, "Enable tracemalloc to get the memory block " - "allocation traceback\n\n"); -- return; -+ goto done; - } - -- traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, (uintptr_t)ptr); -- if (traceback == NULL) -- return; -+ traceback_t *traceback; -+ traceback = tracemalloc_get_traceback_unlocked(DEFAULT_DOMAIN, -+ (uintptr_t)ptr); -+ if (traceback == NULL) { -+ goto done; -+ } - - PUTS(fd, "Memory block allocated at (most recent call first):\n"); -- for (i=0; i < traceback->nframe; i++) { -+ for (int i=0; i < traceback->nframe; i++) { - _PyMem_DumpFrame(fd, &traceback->frames[i]); - } - PUTS(fd, "\n"); -+ -+done: -+ TABLES_UNLOCK(); - } - - #undef PUTS -@@ -1307,45 +1202,48 @@ - PyTraceMalloc_Track(unsigned int domain, uintptr_t ptr, - size_t size) - { -- int res; -- PyGILState_STATE gil_state; -+ PyGILState_STATE gil_state = PyGILState_Ensure(); -+ TABLES_LOCK(); - -- if (!tracemalloc_config.tracing) { -+ int result; -+ if (tracemalloc_config.tracing) { -+ result = tracemalloc_add_trace_unlocked(domain, ptr, size); -+ } -+ else { - /* tracemalloc is not tracing: do nothing */ -- return -2; -+ result = -2; - } - -- gil_state = PyGILState_Ensure(); -- -- TABLES_LOCK(); -- res = tracemalloc_add_trace(domain, ptr, size); - TABLES_UNLOCK(); -- - PyGILState_Release(gil_state); -- return res; -+ return result; - } - - - int - PyTraceMalloc_Untrack(unsigned int domain, uintptr_t ptr) - { -- if (!tracemalloc_config.tracing) { -+ TABLES_LOCK(); -+ -+ int result; -+ if (tracemalloc_config.tracing) { -+ tracemalloc_remove_trace_unlocked(domain, ptr); -+ result = 0; -+ } -+ else { - /* tracemalloc is not tracing: do nothing */ -- return -2; -+ result = -2; - } - -- TABLES_LOCK(); -- tracemalloc_remove_trace(domain, ptr); - TABLES_UNLOCK(); -- -- return 0; -+ return result; - } - - - void - _PyTraceMalloc_Fini(void) - { -- assert(PyGILState_Check()); -+ _Py_AssertHoldsTstate(); - tracemalloc_deinit(); - } - -@@ -1355,87 +1253,102 @@ - - Do nothing if tracemalloc is not tracing memory allocations - or if the object memory block is not already traced. */ --int --_PyTraceMalloc_TraceRef(PyObject *op, PyRefTracerEvent event, void* Py_UNUSED(ignore)) -+static int -+_PyTraceMalloc_TraceRef(PyObject *op, PyRefTracerEvent event, -+ void* Py_UNUSED(ignore)) - { - if (event != PyRefTracer_CREATE) { - return 0; - } -+ if (get_reentrant()) { -+ return 0; -+ } - -- assert(PyGILState_Check()); -+ _Py_AssertHoldsTstate(); -+ TABLES_LOCK(); - - if (!tracemalloc_config.tracing) { -- /* tracemalloc is not tracing: do nothing */ -- return -1; -+ goto done; - } - - PyTypeObject *type = Py_TYPE(op); - const size_t presize = _PyType_PreHeaderSize(type); - uintptr_t ptr = (uintptr_t)((char *)op - presize); - -- int res = -1; -- -- TABLES_LOCK(); - trace_t *trace = _Py_hashtable_get(tracemalloc_traces, TO_PTR(ptr)); - if (trace != NULL) { - /* update the traceback of the memory block */ - traceback_t *traceback = traceback_new(); - if (traceback != NULL) { - trace->traceback = traceback; -- res = 0; - } - } - /* else: cannot track the object, its memory block size is unknown */ -- TABLES_UNLOCK(); - -- return res; -+done: -+ TABLES_UNLOCK(); -+ return 0; - } - - - PyObject* - _PyTraceMalloc_GetTraceback(unsigned int domain, uintptr_t ptr) - { -- traceback_t *traceback; -+ TABLES_LOCK(); - -- traceback = tracemalloc_get_traceback(domain, ptr); -- if (traceback == NULL) -- Py_RETURN_NONE; -+ traceback_t *traceback = tracemalloc_get_traceback_unlocked(domain, ptr); -+ PyObject *result; -+ if (traceback) { -+ set_reentrant(1); -+ result = traceback_to_pyobject(traceback, NULL); -+ set_reentrant(0); -+ } -+ else { -+ result = Py_NewRef(Py_None); -+ } - -- return traceback_to_pyobject(traceback, NULL); -+ TABLES_UNLOCK(); -+ return result; - } - - int - _PyTraceMalloc_IsTracing(void) - { -- return tracemalloc_config.tracing; -+ TABLES_LOCK(); -+ int tracing = tracemalloc_config.tracing; -+ TABLES_UNLOCK(); -+ return tracing; - } - - void - _PyTraceMalloc_ClearTraces(void) - { -- -- if (!tracemalloc_config.tracing) { -- return; -+ TABLES_LOCK(); -+ if (tracemalloc_config.tracing) { -+ tracemalloc_clear_traces_unlocked(); - } -- set_reentrant(1); -- tracemalloc_clear_traces(); -- set_reentrant(0); -+ TABLES_UNLOCK(); - } - - PyObject * - _PyTraceMalloc_GetTraces(void) - { -+ TABLES_LOCK(); -+ set_reentrant(1); -+ - get_traces_t get_traces; - get_traces.domain = DEFAULT_DOMAIN; - get_traces.traces = NULL; - get_traces.domains = NULL; - get_traces.tracebacks = NULL; - get_traces.list = PyList_New(0); -- if (get_traces.list == NULL) -- goto error; -+ if (get_traces.list == NULL) { -+ goto finally; -+ } - -- if (!tracemalloc_config.tracing) -- return get_traces.list; -+ if (!tracemalloc_config.tracing) { -+ goto finally; -+ } - - /* the traceback hash table is used temporarily to intern traceback tuple - of (filename, lineno) tuples */ -@@ -1449,24 +1362,17 @@ - // Copy all traces so tracemalloc_get_traces_fill() doesn't have to disable - // temporarily tracemalloc which would impact other threads and so would - // miss allocations while get_traces() is called. -- TABLES_LOCK(); - get_traces.traces = tracemalloc_copy_traces(tracemalloc_traces); -- TABLES_UNLOCK(); -- - if (get_traces.traces == NULL) { - goto no_memory; - } - -- TABLES_LOCK(); - get_traces.domains = tracemalloc_copy_domains(tracemalloc_domains); -- TABLES_UNLOCK(); -- - if (get_traces.domains == NULL) { - goto no_memory; - } - - // Convert traces to a list of tuples -- set_reentrant(1); - int err = _Py_hashtable_foreach(get_traces.traces, - tracemalloc_get_traces_fill, - &get_traces); -@@ -1475,20 +1381,22 @@ - tracemalloc_get_traces_domain, - &get_traces); - } -- set_reentrant(0); -+ - if (err) { -- goto error; -+ Py_CLEAR(get_traces.list); -+ goto finally; - } -- - goto finally; - - no_memory: - PyErr_NoMemory(); -- --error: - Py_CLEAR(get_traces.list); -+ goto finally; - - finally: -+ set_reentrant(0); -+ TABLES_UNLOCK(); -+ - if (get_traces.tracebacks != NULL) { - _Py_hashtable_destroy(get_traces.tracebacks); - } -@@ -1506,37 +1414,33 @@ - _PyTraceMalloc_GetObjectTraceback(PyObject *obj) - /*[clinic end generated code: output=41ee0553a658b0aa input=29495f1b21c53212]*/ - { -- PyTypeObject *type; -- traceback_t *traceback; -- -- type = Py_TYPE(obj); -+ PyTypeObject *type = Py_TYPE(obj); - const size_t presize = _PyType_PreHeaderSize(type); - uintptr_t ptr = (uintptr_t)((char *)obj - presize); -- -- traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, ptr); -- if (traceback == NULL) { -- Py_RETURN_NONE; -- } -- -- return traceback_to_pyobject(traceback, NULL); -+ return _PyTraceMalloc_GetTraceback(DEFAULT_DOMAIN, ptr); - } - --int _PyTraceMalloc_GetTracebackLimit(void) { -+int _PyTraceMalloc_GetTracebackLimit(void) -+{ - return tracemalloc_config.max_nframe; - } - - size_t --_PyTraceMalloc_GetMemory(void) { -- -+_PyTraceMalloc_GetMemory(void) -+{ -+ TABLES_LOCK(); - size_t size; -+ if (tracemalloc_config.tracing) { -+ size = _Py_hashtable_size(tracemalloc_tracebacks); -+ size += _Py_hashtable_size(tracemalloc_filenames); - -- size = _Py_hashtable_size(tracemalloc_tracebacks); -- size += _Py_hashtable_size(tracemalloc_filenames); -- -- TABLES_LOCK(); -- size += _Py_hashtable_size(tracemalloc_traces); -- _Py_hashtable_foreach(tracemalloc_domains, -- tracemalloc_get_tracemalloc_memory_cb, &size); -+ size += _Py_hashtable_size(tracemalloc_traces); -+ _Py_hashtable_foreach(tracemalloc_domains, -+ tracemalloc_get_tracemalloc_memory_cb, &size); -+ } -+ else { -+ size = 0; -+ } - TABLES_UNLOCK(); - return size; - } -@@ -1545,26 +1449,27 @@ - PyObject * - _PyTraceMalloc_GetTracedMemory(void) - { -- Py_ssize_t size, peak_size; -- -- if (!tracemalloc_config.tracing) -- return Py_BuildValue("ii", 0, 0); -- - TABLES_LOCK(); -- size = tracemalloc_traced_memory; -- peak_size = tracemalloc_peak_traced_memory; -+ Py_ssize_t traced, peak; -+ if (tracemalloc_config.tracing) { -+ traced = tracemalloc_traced_memory; -+ peak = tracemalloc_peak_traced_memory; -+ } -+ else { -+ traced = 0; -+ peak = 0; -+ } - TABLES_UNLOCK(); - -- return Py_BuildValue("nn", size, peak_size); -+ return Py_BuildValue("nn", traced, peak); - } - - void - _PyTraceMalloc_ResetPeak(void) - { -- if (!tracemalloc_config.tracing) { -- return; -- } - TABLES_LOCK(); -- tracemalloc_peak_traced_memory = tracemalloc_traced_memory; -+ if (tracemalloc_config.tracing) { -+ tracemalloc_peak_traced_memory = tracemalloc_traced_memory; -+ } - TABLES_UNLOCK(); - } -diff --git a/Python/uniqueid.c b/Python/uniqueid.c -index b9f30713fee..64c3e6cfbbe 100644 ---- a/Python/uniqueid.c -+++ b/Python/uniqueid.c -@@ -86,7 +86,7 @@ - if (pool->freelist == NULL) { - if (resize_interp_type_id_pool(pool) < 0) { - UNLOCK_POOL(pool); -- return -1; -+ return _Py_INVALID_UNIQUE_ID; - } - } - -@@ -94,7 +94,9 @@ - pool->freelist = entry->next; - entry->obj = obj; - _PyObject_SetDeferredRefcount(obj); -- Py_ssize_t unique_id = (entry - pool->table); -+ // The unique id is one plus the index of the entry in the table. -+ Py_ssize_t unique_id = (entry - pool->table) + 1; -+ assert(unique_id > 0); - UNLOCK_POOL(pool); - return unique_id; - } -@@ -106,8 +108,9 @@ - struct _Py_unique_id_pool *pool = &interp->unique_ids; - - LOCK_POOL(pool); -- assert(unique_id >= 0 && unique_id < pool->size); -- _Py_unique_id_entry *entry = &pool->table[unique_id]; -+ assert(unique_id > 0 && unique_id <= pool->size); -+ Py_ssize_t idx = unique_id - 1; -+ _Py_unique_id_entry *entry = &pool->table[idx]; - entry->next = pool->freelist; - pool->freelist = entry; - UNLOCK_POOL(pool); -@@ -116,18 +119,18 @@ - static Py_ssize_t - clear_unique_id(PyObject *obj) - { -- Py_ssize_t id = -1; -+ Py_ssize_t id = _Py_INVALID_UNIQUE_ID; - if (PyType_Check(obj)) { - if (PyType_HasFeature((PyTypeObject *)obj, Py_TPFLAGS_HEAPTYPE)) { - PyHeapTypeObject *ht = (PyHeapTypeObject *)obj; - id = ht->unique_id; -- ht->unique_id = -1; -+ ht->unique_id = _Py_INVALID_UNIQUE_ID; - } - } - else if (PyCode_Check(obj)) { - PyCodeObject *co = (PyCodeObject *)obj; - id = co->_co_unique_id; -- co->_co_unique_id = -1; -+ co->_co_unique_id = _Py_INVALID_UNIQUE_ID; - } - else if (PyDict_Check(obj)) { - PyDictObject *mp = (PyDictObject *)obj; -@@ -141,23 +144,23 @@ - _PyObject_DisablePerThreadRefcounting(PyObject *obj) - { - Py_ssize_t id = clear_unique_id(obj); -- if (id >= 0) { -+ if (id != _Py_INVALID_UNIQUE_ID) { - _PyObject_ReleaseUniqueId(id); - } - } - - void --_PyObject_ThreadIncrefSlow(PyObject *obj, Py_ssize_t unique_id) -+_PyObject_ThreadIncrefSlow(PyObject *obj, size_t idx) - { - _PyThreadStateImpl *tstate = (_PyThreadStateImpl *)_PyThreadState_GET(); -- if (unique_id < 0 || resize_local_refcounts(tstate) < 0) { -+ if (((Py_ssize_t)idx) < 0 || resize_local_refcounts(tstate) < 0) { - // just incref the object directly. - Py_INCREF(obj); - return; - } - -- assert(unique_id < tstate->refcounts.size); -- tstate->refcounts.values[unique_id]++; -+ assert(idx < (size_t)tstate->refcounts.size); -+ tstate->refcounts.values[idx]++; - #ifdef Py_REF_DEBUG - _Py_IncRefTotal((PyThreadState *)tstate); - #endif -@@ -217,7 +220,7 @@ - if (obj != NULL) { - Py_ssize_t id = clear_unique_id(obj); - (void)id; -- assert(id == i); -+ assert(id == i + 1); - } - } - PyMem_Free(pool->table); -diff --git a/README.rst b/README.rst -index 02776205e6d..0496d231ca7 100644 ---- a/README.rst -+++ b/README.rst -@@ -1,4 +1,4 @@ --This is Python version 3.14.0 alpha 3 -+This is Python version 3.14.0 alpha 5 - ===================================== - - .. image:: https://github.com/python/cpython/actions/workflows/build.yml/badge.svg?branch=main&event=push ---- /dev/null -+++ b/Tools/build/compute-changes.py -@@ -0,0 +1,183 @@ -+"""Determine which GitHub Actions workflows to run. -+ -+Called by ``.github/workflows/reusable-context.yml``. -+We only want to run tests on PRs when related files are changed, -+or when someone triggers a manual workflow run. -+This improves developer experience by not doing (slow) -+unnecessary work in GHA, and saves CI resources. -+""" -+ -+from __future__ import annotations -+ -+import os -+import subprocess -+from dataclasses import dataclass -+from pathlib import Path -+ -+TYPE_CHECKING = False -+if TYPE_CHECKING: -+ from collections.abc import Set -+ -+GITHUB_DEFAULT_BRANCH = os.environ["GITHUB_DEFAULT_BRANCH"] -+GITHUB_CODEOWNERS_PATH = Path(".github/CODEOWNERS") -+GITHUB_WORKFLOWS_PATH = Path(".github/workflows") -+CONFIGURATION_FILE_NAMES = frozenset({ -+ ".pre-commit-config.yaml", -+ ".ruff.toml", -+ "mypy.ini", -+}) -+SUFFIXES_C_OR_CPP = frozenset({".c", ".h", ".cpp"}) -+SUFFIXES_DOCUMENTATION = frozenset({".rst", ".md"}) -+ -+ -+@dataclass(kw_only=True, slots=True) -+class Outputs: -+ run_ci_fuzz: bool = False -+ run_docs: bool = False -+ run_tests: bool = False -+ run_windows_msi: bool = False -+ -+ -+def compute_changes() -> None: -+ target_branch, head_branch = git_branches() -+ if target_branch and head_branch: -+ # Getting changed files only makes sense on a pull request -+ files = get_changed_files( -+ f"origin/{target_branch}", f"origin/{head_branch}" -+ ) -+ outputs = process_changed_files(files) -+ else: -+ # Otherwise, just run the tests -+ outputs = Outputs(run_tests=True) -+ outputs = process_target_branch(outputs, target_branch) -+ -+ if outputs.run_tests: -+ print("Run tests") -+ -+ if outputs.run_ci_fuzz: -+ print("Run CIFuzz tests") -+ else: -+ print("Branch too old for CIFuzz tests; or no C files were changed") -+ -+ if outputs.run_docs: -+ print("Build documentation") -+ -+ if outputs.run_windows_msi: -+ print("Build Windows MSI") -+ -+ print(outputs) -+ -+ write_github_output(outputs) -+ -+ -+def git_branches() -> tuple[str, str]: -+ target_branch = os.environ.get("GITHUB_BASE_REF", "") -+ target_branch = target_branch.removeprefix("refs/heads/") -+ print(f"target branch: {target_branch!r}") -+ -+ head_branch = os.environ.get("GITHUB_HEAD_REF", "") -+ head_branch = head_branch.removeprefix("refs/heads/") -+ print(f"head branch: {head_branch!r}") -+ return target_branch, head_branch -+ -+ -+def get_changed_files( -+ ref_a: str = GITHUB_DEFAULT_BRANCH, ref_b: str = "HEAD" -+) -> Set[Path]: -+ """List the files changed between two Git refs, filtered by change type.""" -+ args = ("git", "diff", "--name-only", f"{ref_a}...{ref_b}", "--") -+ print(*args) -+ changed_files_result = subprocess.run( -+ args, stdout=subprocess.PIPE, check=True, encoding="utf-8" -+ ) -+ changed_files = changed_files_result.stdout.strip().splitlines() -+ return frozenset(map(Path, filter(None, map(str.strip, changed_files)))) -+ -+ -+def process_changed_files(changed_files: Set[Path]) -> Outputs: -+ run_tests = False -+ run_ci_fuzz = False -+ run_docs = False -+ run_windows_msi = False -+ -+ for file in changed_files: -+ # Documentation files -+ doc_or_misc = file.parts[0] in {"Doc", "Misc"} -+ doc_file = file.suffix in SUFFIXES_DOCUMENTATION or doc_or_misc -+ -+ if file.parent == GITHUB_WORKFLOWS_PATH: -+ if file.name == "build.yml": -+ run_tests = run_ci_fuzz = True -+ if file.name == "reusable-docs.yml": -+ run_docs = True -+ if file.name == "reusable-windows-msi.yml": -+ run_windows_msi = True -+ -+ if not ( -+ doc_file -+ or file == GITHUB_CODEOWNERS_PATH -+ or file.name in CONFIGURATION_FILE_NAMES -+ ): -+ run_tests = True -+ -+ # The fuzz tests are pretty slow so they are executed only for PRs -+ # changing relevant files. -+ if file.suffix in SUFFIXES_C_OR_CPP: -+ run_ci_fuzz = True -+ if file.parts[:2] in { -+ ("configure",), -+ ("Modules", "_xxtestfuzz"), -+ }: -+ run_ci_fuzz = True -+ -+ # Check for changed documentation-related files -+ if doc_file: -+ run_docs = True -+ -+ # Check for changed MSI installer-related files -+ if file.parts[:2] == ("Tools", "msi"): -+ run_windows_msi = True -+ -+ return Outputs( -+ run_ci_fuzz=run_ci_fuzz, -+ run_docs=run_docs, -+ run_tests=run_tests, -+ run_windows_msi=run_windows_msi, -+ ) -+ -+ -+def process_target_branch(outputs: Outputs, git_branch: str) -> Outputs: -+ if not git_branch: -+ outputs.run_tests = True -+ -+ # CIFuzz / OSS-Fuzz compatibility with older branches may be broken. -+ if git_branch != GITHUB_DEFAULT_BRANCH: -+ outputs.run_ci_fuzz = False -+ -+ if os.environ.get("GITHUB_EVENT_NAME", "").lower() == "workflow_dispatch": -+ outputs.run_docs = True -+ outputs.run_windows_msi = True -+ -+ return outputs -+ -+ -+def write_github_output(outputs: Outputs) -> None: -+ # https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#default-environment-variables -+ # https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#setting-an-output-parameter -+ if "GITHUB_OUTPUT" not in os.environ: -+ print("GITHUB_OUTPUT not defined!") -+ return -+ -+ with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as f: -+ f.write(f"run-ci-fuzz={bool_lower(outputs.run_ci_fuzz)}\n") -+ f.write(f"run-docs={bool_lower(outputs.run_docs)}\n") -+ f.write(f"run-tests={bool_lower(outputs.run_tests)}\n") -+ f.write(f"run-windows-msi={bool_lower(outputs.run_windows_msi)}\n") -+ -+ -+def bool_lower(value: bool, /) -> str: -+ return "true" if value else "false" -+ -+ -+if __name__ == "__main__": -+ compute_changes() -diff --git a/Tools/build/mypy.ini b/Tools/build/mypy.ini -index cf1dac7fde5..06224163884 100644 ---- a/Tools/build/mypy.ini -+++ b/Tools/build/mypy.ini -@@ -1,5 +1,7 @@ - [mypy] --files = Tools/build/generate_sbom.py -+files = -+ Tools/build/compute-changes.py, -+ Tools/build/generate_sbom.py - pretty = True - - # Make sure Python can still be built -@@ -8,6 +10,6 @@ - - # ...And be strict: - strict = True --strict_concatenate = True -+extra_checks = True - enable_error_code = ignore-without-code,redundant-expr,truthy-bool,possibly-undefined - warn_unreachable = True -diff --git a/Tools/build/regen-configure.sh b/Tools/build/regen-configure.sh -index d2a613b1e40..c7683eb3676 100755 ---- a/Tools/build/regen-configure.sh -+++ b/Tools/build/regen-configure.sh -@@ -5,7 +5,7 @@ - # The check_autoconf_regen job of .github/workflows/build.yml must kept in - # sync with this script. Use the same container image than the job so the job - # doesn't need to run autoreconf in a container. --IMAGE="ghcr.io/python/autoconf:2024.11.11.11786316759" -+IMAGE="ghcr.io/python/autoconf:2025.01.02.12581854023" - AUTORECONF="autoreconf -ivf -Werror" - - WORK_DIR="/src" -diff --git a/Tools/c-analyzer/TODO b/Tools/c-analyzer/TODO -index e81ceb29c64..edd0c4bc7fd 100644 ---- a/Tools/c-analyzer/TODO -+++ b/Tools/c-analyzer/TODO -@@ -69,7 +69,6 @@ - Objects/typeobject.c:next_version_tag static unsigned int next_version_tag - Python/Python-ast.c:init_types():initialized static int initialized - Python/bootstrap_hash.c:urandom_cache static struct { int fd; dev_t st_dev; ino_t st_ino; } urandom_cache --Python/ceval.c:lltrace static int lltrace - Python/ceval.c:make_pending_calls():busy static int busy - Python/dynload_shlib.c:handles static struct { dev_t dev; ino_t ino; void *handle; } handles[128] - Python/dynload_shlib.c:nhandles static int nhandles -diff --git a/Tools/c-analyzer/c_analyzer/datafiles.py b/Tools/c-analyzer/c_analyzer/datafiles.py -index d5db3bd3ed7..79c201a5d3b 100644 ---- a/Tools/c-analyzer/c_analyzer/datafiles.py -+++ b/Tools/c-analyzer/c_analyzer/datafiles.py -@@ -104,7 +104,12 @@ - for v in varidinfo) - if reason in bogus: - reason = None -- varid = _info.DeclID.from_row(varidinfo) -+ try: -+ varid = _info.DeclID.from_row(varidinfo) -+ except BaseException as e: -+ e.add_note(f"Error occurred when processing row {varidinfo} in {infile}.") -+ e.add_note(f"Could it be that you added a row which is not tab-delimited?") -+ raise e - varid = varid.fix_filename(relroot, formatted=False, fixroot=False) - yield varid, reason - -diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv -index badd7b79102..54954cfb5f8 100644 ---- a/Tools/c-analyzer/cpython/globals-to-fix.tsv -+++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv -@@ -106,6 +106,8 @@ - Python/context.c - PyContextVar_Type - - Python/context.c - PyContext_Type - - Python/instruction_sequence.c - _PyInstructionSequence_Type - -+Python/instrumentation.c - _PyLegacyBranchEventHandler_Type - -+Python/instrumentation.c - _PyBranchesIterator - - Python/traceback.c - PyTraceBack_Type - - - ##----------------------- -@@ -405,7 +407,8 @@ - - ## other - Include/datetime.h - PyDateTimeAPI - --Modules/_ctypes/cfield.c _ctypes_get_fielddesc initialized - -+Modules/_ctypes/cfield.c _ctypes_init_fielddesc initialized - -+Modules/_ctypes/cfield.c - formattable - - Modules/_ctypes/malloc_closure.c - _pagesize - - Modules/_cursesmodule.c - curses_module_loaded - - Modules/_cursesmodule.c - curses_initscr_called - -@@ -420,7 +423,6 @@ - ##----------------------- - ## state - --Modules/_ctypes/cfield.c - formattable - - Modules/_ctypes/malloc_closure.c - free_list - - Modules/_curses_panel.c - lop - - Modules/_ssl/debughelpers.c _PySSL_keylog_callback lock - -@@ -442,3 +444,5 @@ - Modules/rotatingtree.c - random_stream - - Modules/rotatingtree.c - random_value - - Modules/rotatingtree.c - random_mutex - -+Modules/socketmodule.c - accept4_works - -+Modules/socketmodule.c - sock_cloexec_works - -diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv -index c8c30a7985a..df0262f9c84 100644 ---- a/Tools/c-analyzer/cpython/ignored.tsv -+++ b/Tools/c-analyzer/cpython/ignored.tsv -@@ -53,6 +53,9 @@ - ## thread-safe hashtable (internal locks) - Python/parking_lot.c - buckets - - -+## data needed for introspecting asyncio state from debuggers and profilers -+Modules/_asynciomodule.c - AsyncioDebug - -+ - - ################################## - ## state tied to Py_Main() -@@ -378,16 +381,13 @@ - Python/pystate.c - initial - - Python/specialize.c - adaptive_opcodes - - Python/specialize.c - cache_requirements - -+Python/specialize.c - binaryop_extend_descrs - - Python/stdlib_module_names.h - _Py_stdlib_module_names - - Python/sysmodule.c - perf_map_state - - Python/sysmodule.c - _PySys_ImplCacheTag - - Python/sysmodule.c - _PySys_ImplName - - Python/sysmodule.c - whatstrings - --Python/optimizer.c - _PyDefaultOptimizer_Type - --Python/optimizer.c - _PyCounterExecutor_Type - --Python/optimizer.c - _PyCounterOptimizer_Type - - Python/optimizer.c - _PyUOpExecutor_Type - --Python/optimizer.c - _PyUOpOptimizer_Type - - Python/optimizer.c - _PyOptimizer_Default - - Python/optimizer.c - _ColdExit_Type - - Python/optimizer.c - Py_FatalErrorExecutor - -@@ -444,6 +444,8 @@ - Modules/_testcapi/heaptype.c - _testcapimodule - - Modules/_testcapi/mem.c - FmData - - Modules/_testcapi/mem.c - FmHook - -+Modules/_testcapi/object.c - MyObject_dealloc_called - -+Modules/_testcapi/object.c - MyType - - Modules/_testcapi/structmember.c - test_structmembersType_OldAPI - - Modules/_testcapi/watchers.c - g_dict_watch_events - - Modules/_testcapi/watchers.c - g_dict_watchers_installed - -diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py -index eca851e6de8..c127d0334d9 100644 ---- a/Tools/cases_generator/analyzer.py -+++ b/Tools/cases_generator/analyzer.py -@@ -5,9 +5,17 @@ - import re - from typing import Optional - -+@dataclass -+class EscapingCall: -+ start: lexer.Token -+ call: lexer.Token -+ end: lexer.Token -+ kills: lexer.Token | None -+ - @dataclass - class Properties: -- escaping_calls: dict[lexer.Token, tuple[lexer.Token, lexer.Token]] -+ escaping_calls: dict[lexer.Token, EscapingCall] -+ escapes: bool - error_with_pop: bool - error_without_pop: bool - deopts: bool -@@ -23,10 +31,12 @@ - has_free: bool - side_exit: bool - pure: bool -+ uses_opcode: bool - tier: int | None = None - oparg_and_1: bool = False - const_oparg: int = -1 - needs_prev: bool = False -+ no_save_ip: bool = False - - def dump(self, indent: str) -> None: - simple_properties = self.__dict__.copy() -@@ -39,11 +49,12 @@ - - @staticmethod - def from_list(properties: list["Properties"]) -> "Properties": -- escaping_calls: dict[lexer.Token, tuple[lexer.Token, lexer.Token]] = {} -+ escaping_calls: dict[lexer.Token, EscapingCall] = {} - for p in properties: - escaping_calls.update(p.escaping_calls) - return Properties( - escaping_calls=escaping_calls, -+ escapes = any(p.escapes for p in properties), - error_with_pop=any(p.error_with_pop for p in properties), - error_without_pop=any(p.error_without_pop for p in properties), - deopts=any(p.deopts for p in properties), -@@ -56,22 +67,21 @@ - uses_co_consts=any(p.uses_co_consts for p in properties), - uses_co_names=any(p.uses_co_names for p in properties), - uses_locals=any(p.uses_locals for p in properties), -+ uses_opcode=any(p.uses_opcode for p in properties), - has_free=any(p.has_free for p in properties), - side_exit=any(p.side_exit for p in properties), - pure=all(p.pure for p in properties), - needs_prev=any(p.needs_prev for p in properties), -+ no_save_ip=all(p.no_save_ip for p in properties), - ) - - @property - def infallible(self) -> bool: - return not self.error_with_pop and not self.error_without_pop - -- @property -- def escapes(self) -> bool: -- return bool(self.escaping_calls) -- - SKIP_PROPERTIES = Properties( - escaping_calls={}, -+ escapes=False, - error_with_pop=False, - error_without_pop=False, - deopts=False, -@@ -84,9 +94,11 @@ - uses_co_consts=False, - uses_co_names=False, - uses_locals=False, -+ uses_opcode=False, - has_free=False, - side_exit=False, - pure=True, -+ no_save_ip=False, - ) - - -@@ -118,6 +130,8 @@ - return 0 - - -+ -+ - @dataclass - class StackItem: - name: str -@@ -216,7 +230,24 @@ - return False - - -+class Label: -+ -+ def __init__(self, name: str, spilled: bool, body: list[lexer.Token], properties: Properties): -+ self.name = name -+ self.spilled = spilled -+ self.body = body -+ self.properties = properties -+ -+ size:int = 0 -+ output_stores: list[lexer.Token] = [] -+ instruction_size = None -+ -+ def __str__(self) -> str: -+ return f"label({self.name})" -+ -+ - Part = Uop | Skip | Flush -+CodeSection = Uop | Label - - - @dataclass -@@ -289,6 +320,7 @@ - uops: dict[str, Uop] - families: dict[str, Family] - pseudos: dict[str, PseudoInstruction] -+ labels: dict[str, Label] - opmap: dict[str, int] - have_arg: int - min_instrumented: int -@@ -321,6 +353,17 @@ - cond = replace_op_arg_1 - return StackItem(item.name, item.type, cond, item.size) - -+def check_unused(stack: list[StackItem], input_names: dict[str, lexer.Token]) -> None: -+ "Unused items cannot be on the stack above used, non-peek items" -+ seen_unused = False -+ for item in reversed(stack): -+ if item.name == "unused": -+ seen_unused = True -+ elif item.peek: -+ break -+ elif seen_unused: -+ raise analysis_error(f"Cannot have used input '{item.name}' below an unused value on the stack", input_names[item.name]) -+ - - def analyze_stack( - op: parser.InstDef | parser.Pseudo, replace_op_arg_1: str | None = None -@@ -365,6 +408,7 @@ - for output in outputs: - if variable_used(op, output.name): - output.used = True -+ check_unused(inputs, input_names) - return StackEffect(inputs, outputs) - - -@@ -384,7 +428,7 @@ - """Find the tokens that make up the left-hand side of an assignment""" - offset = 0 - for tkn in reversed(node.block.tokens[: idx]): -- if tkn.kind in {"SEMI", "LBRACE", "RBRACE"}: -+ if tkn.kind in {"SEMI", "LBRACE", "RBRACE", "CMACRO"}: - return node.block.tokens[idx - offset : idx] - offset += 1 - return [] -@@ -472,22 +516,24 @@ - return refs - - --def variable_used(node: parser.InstDef, name: str) -> bool: -+def variable_used(node: parser.CodeDef, name: str) -> bool: - """Determine whether a variable with a given name is used in a node.""" - return any( - token.kind == "IDENTIFIER" and token.text == name for token in node.block.tokens - ) - - --def oparg_used(node: parser.InstDef) -> bool: -+def oparg_used(node: parser.CodeDef) -> bool: - """Determine whether `oparg` is used in a node.""" - return any( - token.kind == "IDENTIFIER" and token.text == "oparg" for token in node.tokens - ) - - --def tier_variable(node: parser.InstDef) -> int | None: -+def tier_variable(node: parser.CodeDef) -> int | None: - """Determine whether a tier variable is used in a node.""" -+ if isinstance(node, parser.LabelDef): -+ return None - for token in node.tokens: - if token.kind == "ANNOTATION": - if token.text == "specializing": -@@ -497,21 +543,19 @@ - return None - - --def has_error_with_pop(op: parser.InstDef) -> bool: -+def has_error_with_pop(op: parser.CodeDef) -> bool: - return ( - variable_used(op, "ERROR_IF") - or variable_used(op, "pop_1_error") - or variable_used(op, "exception_unwind") -- or variable_used(op, "resume_with_error") - ) - - --def has_error_without_pop(op: parser.InstDef) -> bool: -+def has_error_without_pop(op: parser.CodeDef) -> bool: - return ( - variable_used(op, "ERROR_NO_POP") - or variable_used(op, "pop_1_error") - or variable_used(op, "exception_unwind") -- or variable_used(op, "resume_with_error") - ) - - -@@ -541,7 +585,6 @@ - "PyStackRef_AsPyObjectNew", - "PyStackRef_AsPyObjectSteal", - "PyStackRef_CLEAR", -- "PyStackRef_CLOSE", - "PyStackRef_CLOSE_SPECIALIZED", - "PyStackRef_DUP", - "PyStackRef_False", -@@ -564,8 +607,6 @@ - "PyUnicode_GET_LENGTH", - "PyUnicode_READ_CHAR", - "Py_ARRAY_LENGTH", -- "Py_CLEAR", -- "Py_DECREF", - "Py_FatalError", - "Py_INCREF", - "Py_IS_TYPE", -@@ -575,12 +616,12 @@ - "Py_TYPE", - "Py_UNREACHABLE", - "Py_Unicode_GET_LENGTH", -- "Py_XDECREF", - "_PyCode_CODE", - "_PyDictValues_AddToInsertionOrder", - "_PyErr_Occurred", - "_PyEval_FrameClearAndPop", - "_PyFloat_FromDouble_ConsumeInputs", -+ "_PyFrame_GetBytecode", - "_PyFrame_GetCode", - "_PyFrame_IsIncomplete", - "_PyFrame_PushUnchecked", -@@ -590,12 +631,13 @@ - "_PyGen_GetGeneratorFromFrame", - "_PyInterpreterState_GET", - "_PyList_AppendTakeRef", -- "_PyList_FromStackRefSteal", -+ "_PyList_FromStackRefStealOnSuccess", - "_PyList_ITEMS", - "_PyLong_Add", - "_PyLong_CompactValue", - "_PyLong_DigitCount", - "_PyLong_IsCompact", -+ "_PyLong_IsNegative", - "_PyLong_IsNonNegativeCompact", - "_PyLong_IsZero", - "_PyLong_Multiply", -@@ -608,8 +650,7 @@ - "_PyObject_InlineValues", - "_PyObject_ManagedDictPointer", - "_PyThreadState_HasStackSpace", -- "_PyTuple_FromArraySteal", -- "_PyTuple_FromStackRefSteal", -+ "_PyTuple_FromStackRefStealOnSuccess", - "_PyTuple_ITEMS", - "_PyType_HasFeature", - "_PyType_NewManagedObject", -@@ -617,7 +658,6 @@ - "_PyUnicode_JoinArray", - "_Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY", - "_Py_DECREF_NO_DEALLOC", -- "_Py_DECREF_SPECIALIZED", - "_Py_EnterRecursiveCallTstateUnchecked", - "_Py_ID", - "_Py_IsImmortal", -@@ -628,6 +668,7 @@ - "_Py_STR", - "_Py_TryIncrefCompare", - "_Py_TryIncrefCompareStackRef", -+ "_Py_atomic_compare_exchange_uint8", - "_Py_atomic_load_ptr_acquire", - "_Py_atomic_load_uintptr_relaxed", - "_Py_set_eval_breaker_bit", -@@ -635,11 +676,11 @@ - "assert", - "backoff_counter_triggers", - "initial_temperature_backoff_counter", -- "maybe_lltrace_resume_frame", -+ "JUMP_TO_LABEL", - "restart_backoff_counter", - ) - --def find_stmt_start(node: parser.InstDef, idx: int) -> lexer.Token: -+def find_stmt_start(node: parser.CodeDef, idx: int) -> lexer.Token: - assert idx < len(node.block.tokens) - while True: - tkn = node.block.tokens[idx-1] -@@ -652,7 +693,7 @@ - return node.block.tokens[idx] - - --def find_stmt_end(node: parser.InstDef, idx: int) -> lexer.Token: -+def find_stmt_end(node: parser.CodeDef, idx: int) -> lexer.Token: - assert idx < len(node.block.tokens) - while True: - idx += 1 -@@ -660,15 +701,15 @@ - if tkn.kind == "SEMI": - return node.block.tokens[idx+1] - --def check_escaping_calls(instr: parser.InstDef, escapes: dict[lexer.Token, tuple[lexer.Token, lexer.Token]]) -> None: -- calls = {escapes[t][0] for t in escapes} -+def check_escaping_calls(instr: parser.CodeDef, escapes: dict[lexer.Token, EscapingCall]) -> None: -+ calls = {e.call for e in escapes.values()} - in_if = 0 - tkn_iter = iter(instr.block.tokens) - for tkn in tkn_iter: - if tkn.kind == "IF": - next(tkn_iter) - in_if = 1 -- if tkn.kind == "IDENTIFIER" and tkn.text in ("DEOPT_IF", "ERROR_IF"): -+ if tkn.kind == "IDENTIFIER" and tkn.text in ("DEOPT_IF", "ERROR_IF", "EXIT_IF"): - next(tkn_iter) - in_if = 1 - elif tkn.kind == "LPAREN" and in_if: -@@ -679,8 +720,8 @@ - elif tkn in calls and in_if: - raise analysis_error(f"Escaping call '{tkn.text} in condition", tkn) - --def find_escaping_api_calls(instr: parser.InstDef) -> dict[lexer.Token, tuple[lexer.Token, lexer.Token]]: -- result: dict[lexer.Token, tuple[lexer.Token, lexer.Token]] = {} -+def find_escaping_api_calls(instr: parser.CodeDef) -> dict[lexer.Token, EscapingCall]: -+ result: dict[lexer.Token, EscapingCall] = {} - tokens = instr.block.tokens - for idx, tkn in enumerate(tokens): - try: -@@ -715,23 +756,30 @@ - continue - elif tkn.kind != "RBRACKET": - continue -+ if tkn.text in ("PyStackRef_CLOSE", "PyStackRef_XCLOSE"): -+ if len(tokens) <= idx+2: -+ raise analysis_error("Unexpected end of file", next_tkn) -+ kills = tokens[idx+2] -+ if kills.kind != "IDENTIFIER": -+ raise analysis_error(f"Expected identifier, got '{kills.text}'", kills) -+ else: -+ kills = None - start = find_stmt_start(instr, idx) - end = find_stmt_end(instr, idx) -- result[start] = tkn, end -+ result[start] = EscapingCall(start, tkn, end, kills) - check_escaping_calls(instr, result) - return result - - - EXITS = { - "DISPATCH", -- "GO_TO_INSTRUCTION", - "Py_UNREACHABLE", - "DISPATCH_INLINED", - "DISPATCH_GOTO", - } - - --def always_exits(op: parser.InstDef) -> bool: -+def always_exits(op: parser.CodeDef) -> bool: - depth = 0 - tkn_iter = iter(op.tokens) - for tkn in tkn_iter: -@@ -790,7 +838,7 @@ - return False - - --def compute_properties(op: parser.InstDef) -> Properties: -+def compute_properties(op: parser.CodeDef) -> Properties: - escaping_calls = find_escaping_api_calls(op) - has_free = ( - variable_used(op, "PyCell_New") -@@ -811,8 +859,12 @@ - ) - error_with_pop = has_error_with_pop(op) - error_without_pop = has_error_without_pop(op) -+ escapes = bool(escaping_calls) -+ pure = False if isinstance(op, parser.LabelDef) else "pure" in op.annotations -+ no_save_ip = False if isinstance(op, parser.LabelDef) else "no_save_ip" in op.annotations - return Properties( - escaping_calls=escaping_calls, -+ escapes=escapes, - error_with_pop=error_with_pop, - error_without_pop=error_without_pop, - deopts=deopts_if, -@@ -825,10 +877,11 @@ - stores_sp=variable_used(op, "SYNC_SP"), - uses_co_consts=variable_used(op, "FRAME_CO_CONSTS"), - uses_co_names=variable_used(op, "FRAME_CO_NAMES"), -- uses_locals=(variable_used(op, "GETLOCAL") or variable_used(op, "SETLOCAL")) -- and not has_free, -+ uses_locals=variable_used(op, "GETLOCAL") and not has_free, -+ uses_opcode=variable_used(op, "opcode"), - has_free=has_free, -- pure="pure" in op.annotations, -+ pure=pure, -+ no_save_ip=no_save_ip, - tier=tier_variable(op), - needs_prev=variable_used(op, "prev_instr"), - ) -@@ -1003,6 +1056,14 @@ - ) - - -+def add_label( -+ label: parser.LabelDef, -+ labels: dict[str, Label], -+) -> None: -+ properties = compute_properties(label) -+ labels[label.name] = Label(label.name, label.spilled, label.block.tokens, properties) -+ -+ - def assign_opcodes( - instructions: dict[str, Instruction], - families: dict[str, Family], -@@ -1121,6 +1182,7 @@ - uops: dict[str, Uop] = {} - families: dict[str, Family] = {} - pseudos: dict[str, PseudoInstruction] = {} -+ labels: dict[str, Label] = {} - for node in forest: - match node: - case parser.InstDef(name): -@@ -1135,6 +1197,8 @@ - pass - case parser.Pseudo(): - pass -+ case parser.LabelDef(): -+ pass - case _: - assert False - for node in forest: -@@ -1146,19 +1210,10 @@ - add_family(node, instructions, families) - case parser.Pseudo(): - add_pseudo(node, instructions, pseudos) -+ case parser.LabelDef(): -+ add_label(node, labels) - case _: - pass -- for uop in uops.values(): -- tkn_iter = iter(uop.body) -- for tkn in tkn_iter: -- if tkn.kind == "IDENTIFIER" and tkn.text == "GO_TO_INSTRUCTION": -- if next(tkn_iter).kind != "LPAREN": -- continue -- target = next(tkn_iter) -- if target.kind != "IDENTIFIER": -- continue -- if target.text in instructions: -- instructions[target.text].is_target = True - for uop in uops.values(): - uop.instruction_size = get_instruction_size_for_uop(instructions, uop) - # Special case BINARY_OP_INPLACE_ADD_UNICODE -@@ -1171,7 +1226,7 @@ - families["BINARY_OP"].members.append(inst) - opmap, first_arg, min_instrumented = assign_opcodes(instructions, families, pseudos) - return Analysis( -- instructions, uops, families, pseudos, opmap, first_arg, min_instrumented -+ instructions, uops, families, pseudos, labels, opmap, first_arg, min_instrumented - ) - - -diff --git a/Tools/cases_generator/generators_common.py b/Tools/cases_generator/generators_common.py -index d17617cab02..cd52f181b60 100644 ---- a/Tools/cases_generator/generators_common.py -+++ b/Tools/cases_generator/generators_common.py -@@ -1,5 +1,4 @@ - from pathlib import Path --from typing import TextIO - - from analyzer import ( - Instruction, -@@ -7,6 +6,8 @@ - Properties, - StackItem, - analysis_error, -+ Label, -+ CodeSection, - ) - from cwriter import CWriter - from typing import Callable, TextIO, Iterator, Iterable -@@ -90,7 +91,7 @@ - - - ReplacementFunctionType = Callable[ -- [Token, TokenIterator, Uop, Storage, Instruction | None], bool -+ [Token, TokenIterator, CodeSection, Storage, Instruction | None], bool - ] - - def always_true(tkn: Token | None) -> bool: -@@ -98,12 +99,18 @@ - return False - return tkn.text in {"true", "1"} - -+NON_ESCAPING_DEALLOCS = { -+ "_PyFloat_ExactDealloc", -+ "_PyLong_ExactDealloc", -+ "_PyUnicode_ExactDealloc", -+} - - class Emitter: - out: CWriter -+ labels: dict[str, Label] - _replacers: dict[str, ReplacementFunctionType] - -- def __init__(self, out: CWriter): -+ def __init__(self, out: CWriter, labels: dict[str, Label]): - self._replacers = { - "EXIT_IF": self.exit_if, - "DEOPT_IF": self.deopt_if, -@@ -115,23 +122,26 @@ - "SYNC_SP": self.sync_sp, - "SAVE_STACK": self.save_stack, - "RELOAD_STACK": self.reload_stack, -- "PyStackRef_CLOSE": self.stackref_close, -- "PyStackRef_CLOSE_SPECIALIZED": self.stackref_close, -+ "PyStackRef_CLOSE_SPECIALIZED": self.stackref_close_specialized, - "PyStackRef_AsPyObjectSteal": self.stackref_steal, - "DISPATCH": self.dispatch, - "INSTRUCTION_SIZE": self.instruction_size, -- "POP_DEAD_INPUTS": self.pop_dead_inputs, -+ "POP_INPUT": self.pop_input, -+ "stack_pointer": self.stack_pointer, - } - self.out = out -+ self.labels = labels - - def dispatch( - self, - tkn: Token, - tkn_iter: TokenIterator, -- uop: Uop, -+ uop: CodeSection, - storage: Storage, - inst: Instruction | None, - ) -> bool: -+ if storage.spilled: -+ raise analysis_error("stack_pointer needs reloading before dispatch", tkn) - self.emit(tkn) - return False - -@@ -139,31 +149,41 @@ - self, - tkn: Token, - tkn_iter: TokenIterator, -- uop: Uop, -+ uop: CodeSection, - storage: Storage, - inst: Instruction | None, - ) -> bool: -- self.out.emit_at("DEOPT_IF", tkn) -+ self.out.start_line() -+ self.out.emit("if (") - lparen = next(tkn_iter) -- self.emit(lparen) - assert lparen.kind == "LPAREN" - first_tkn = tkn_iter.peek() - emit_to(self.out, tkn_iter, "RPAREN") -+ self.emit(") {\n") - next(tkn_iter) # Semi colon -- self.out.emit(", ") - assert inst is not None - assert inst.family is not None -- self.out.emit(inst.family.name) -- self.out.emit(");\n") -+ family_name = inst.family.name -+ self.emit(f"UPDATE_MISS_STATS({family_name});\n") -+ self.emit(f"assert(_PyOpcode_Deopt[opcode] == ({family_name}));\n") -+ self.emit(f"JUMP_TO_PREDICTED({family_name});\n") -+ self.emit("}\n") - return not always_true(first_tkn) - - exit_if = deopt_if - -+ def goto_error(self, offset: int, label: str, storage: Storage) -> str: -+ if offset > 0: -+ return f"JUMP_TO_LABEL(pop_{offset}_{label});" -+ if offset < 0: -+ storage.copy().flush(self.out) -+ return f"JUMP_TO_LABEL({label});" -+ - def error_if( - self, - tkn: Token, - tkn_iter: TokenIterator, -- uop: Uop, -+ uop: CodeSection, - storage: Storage, - inst: Instruction | None, - ) -> bool: -@@ -181,30 +201,20 @@ - self.out.emit_at("if ", tkn) - self.emit(lparen) - emit_to(self.out, tkn_iter, "COMMA") -- self.out.emit(") ") -+ self.out.emit(") {\n") - label = next(tkn_iter).text - next(tkn_iter) # RPAREN - next(tkn_iter) # Semi colon - storage.clear_inputs("at ERROR_IF") -+ - c_offset = storage.stack.peek_offset() - try: - offset = -int(c_offset) - except ValueError: - offset = -1 -- if offset > 0: -- self.out.emit(f"goto pop_{offset}_") -- self.out.emit(label) -- self.out.emit(";\n") -- elif offset == 0: -- self.out.emit("goto ") -- self.out.emit(label) -- self.out.emit(";\n") -- else: -- self.out.emit("{\n") -- storage.copy().flush(self.out) -- self.out.emit("goto ") -- self.out.emit(label) -- self.out.emit(";\n") -+ self.out.emit(self.goto_error(offset, label, storage)) -+ self.out.emit("\n") -+ if not unconditional: - self.out.emit("}\n") - return not unconditional - -@@ -212,21 +222,21 @@ - self, - tkn: Token, - tkn_iter: TokenIterator, -- uop: Uop, -+ uop: CodeSection, - storage: Storage, - inst: Instruction | None, - ) -> bool: - next(tkn_iter) # LPAREN - next(tkn_iter) # RPAREN - next(tkn_iter) # Semi colon -- self.out.emit_at("goto error;", tkn) -+ self.out.emit_at(self.goto_error(0, "error", storage), tkn) - return False - - def decref_inputs( - self, - tkn: Token, - tkn_iter: TokenIterator, -- uop: Uop, -+ uop: CodeSection, - storage: Storage, - inst: Instruction | None, - ) -> bool: -@@ -234,23 +244,26 @@ - next(tkn_iter) - next(tkn_iter) - self.out.emit_at("", tkn) -- for var in uop.stack.inputs: -- if var.name == "unused" or var.name == "null" or var.peek: -+ for var in storage.inputs: -+ if not var.defined: - continue -+ if var.name == "null": -+ continue -+ close = "PyStackRef_CLOSE" -+ if "null" in var.name or var.condition and var.condition != "1": -+ close = "PyStackRef_XCLOSE" - if var.size: - if var.size == "1": -- self.out.emit(f"PyStackRef_CLOSE({var.name}[0]);\n") -+ self.out.emit(f"{close}({var.name}[0]);\n") - else: - self.out.emit(f"for (int _i = {var.size}; --_i >= 0;) {{\n") -- self.out.emit(f"PyStackRef_CLOSE({var.name}[_i]);\n") -+ self.out.emit(f"{close}({var.name}[_i]);\n") - self.out.emit("}\n") - elif var.condition: -- if var.condition == "1": -- self.out.emit(f"PyStackRef_CLOSE({var.name});\n") -- elif var.condition != "0": -- self.out.emit(f"PyStackRef_XCLOSE({var.name});\n") -+ if var.condition != "0": -+ self.out.emit(f"{close}({var.name});\n") - else: -- self.out.emit(f"PyStackRef_CLOSE({var.name});\n") -+ self.out.emit(f"{close}({var.name});\n") - for input in storage.inputs: - input.defined = False - return True -@@ -259,7 +272,7 @@ - self, - tkn: Token, - tkn_iter: TokenIterator, -- uop: Uop, -+ uop: CodeSection, - storage: Storage, - inst: Instruction | None, - ) -> bool: -@@ -274,7 +287,7 @@ - self, - tkn: Token, - tkn_iter: TokenIterator, -- uop: Uop, -+ uop: CodeSection, - storage: Storage, - inst: Instruction | None, - ) -> bool: -@@ -291,35 +304,80 @@ - raise analysis_error(f"'{name}' is not a live input-only variable", name_tkn) - return True - -- def stackref_close( -+ def stackref_kill( -+ self, -+ name: Token, -+ storage: Storage, -+ escapes: bool -+ ) -> bool: -+ live = "" -+ for var in reversed(storage.inputs): -+ if var.name == name.text: -+ if live and escapes: -+ raise analysis_error( -+ f"Cannot close '{name.text}' when " -+ f"'{live}' is still live", name) -+ var.defined = False -+ break -+ if var.defined: -+ live = var.name -+ return True -+ -+ def stackref_close_specialized( - self, - tkn: Token, - tkn_iter: TokenIterator, -- uop: Uop, -+ uop: CodeSection, - storage: Storage, - inst: Instruction | None, - ) -> bool: -+ - self.out.emit(tkn) - tkn = next(tkn_iter) - assert tkn.kind == "LPAREN" - self.out.emit(tkn) - name = next(tkn_iter) - self.out.emit(name) -+ comma = next(tkn_iter) -+ if comma.kind != "COMMA": -+ raise analysis_error("Expected comma", comma) -+ self.out.emit(comma) -+ dealloc = next(tkn_iter) -+ if dealloc.kind != "IDENTIFIER": -+ raise analysis_error("Expected identifier", dealloc) -+ self.out.emit(dealloc) - if name.kind == "IDENTIFIER": -- for var in storage.inputs: -- if var.name == name.text: -- var.defined = False -+ escapes = dealloc.text not in NON_ESCAPING_DEALLOCS -+ return self.stackref_kill(name, storage, escapes) - rparen = emit_to(self.out, tkn_iter, "RPAREN") - self.emit(rparen) - return True - -- stackref_steal = stackref_close -+ def stackref_steal( -+ self, -+ tkn: Token, -+ tkn_iter: TokenIterator, -+ uop: CodeSection, -+ storage: Storage, -+ inst: Instruction | None, -+ ) -> bool: -+ self.out.emit(tkn) -+ tkn = next(tkn_iter) -+ assert tkn.kind == "LPAREN" -+ self.out.emit(tkn) -+ name = next(tkn_iter) -+ self.out.emit(name) -+ if name.kind == "IDENTIFIER": -+ return self.stackref_kill(name, storage, False) -+ rparen = emit_to(self.out, tkn_iter, "RPAREN") -+ self.emit(rparen) -+ return True - - def sync_sp( - self, - tkn: Token, - tkn_iter: TokenIterator, -- uop: Uop, -+ uop: CodeSection, - storage: Storage, - inst: Instruction | None, - ) -> bool: -@@ -331,6 +389,34 @@ - self._print_storage(storage) - return True - -+ def stack_pointer( -+ self, -+ tkn: Token, -+ tkn_iter: TokenIterator, -+ uop: CodeSection, -+ storage: Storage, -+ inst: Instruction | None, -+ ) -> bool: -+ if storage.spilled: -+ raise analysis_error("stack_pointer is invalid when stack is spilled to memory", tkn) -+ self.emit(tkn) -+ return True -+ -+ def goto_label(self, goto: Token, label: Token, storage: Storage) -> None: -+ if label.text not in self.labels: -+ print(self.labels.keys()) -+ raise analysis_error(f"Label '{label.text}' does not exist", label) -+ label_node = self.labels[label.text] -+ if label_node.spilled: -+ if not storage.spilled: -+ self.emit_save(storage) -+ elif storage.spilled: -+ raise analysis_error("Cannot jump from spilled label without reloading the stack pointer", goto) -+ self.out.start_line() -+ self.out.emit("JUMP_TO_LABEL(") -+ self.out.emit(label) -+ self.out.emit(")") -+ - def emit_save(self, storage: Storage) -> None: - storage.save(self.out) - self._print_storage(storage) -@@ -339,7 +425,7 @@ - self, - tkn: Token, - tkn_iter: TokenIterator, -- uop: Uop, -+ uop: CodeSection, - storage: Storage, - inst: Instruction | None, - ) -> bool: -@@ -349,18 +435,27 @@ - self.emit_save(storage) - return True - -- def pop_dead_inputs( -+ def pop_input( - self, - tkn: Token, - tkn_iter: TokenIterator, -- uop: Uop, -+ uop: CodeSection, - storage: Storage, - inst: Instruction | None, - ) -> bool: - next(tkn_iter) -+ name_tkn = next(tkn_iter) -+ name = name_tkn.text - next(tkn_iter) - next(tkn_iter) -- storage.pop_dead_inputs(self.out) -+ if not storage.inputs: -+ raise analysis_error("stack is empty", tkn) -+ tos = storage.inputs[-1] -+ if tos.name != name: -+ raise analysis_error(f"'{name} is not top of stack", name_tkn) -+ tos.defined = False -+ storage.clear_dead_inputs() -+ storage.flush(self.out) - return True - - def emit_reload(self, storage: Storage) -> None: -@@ -371,7 +466,7 @@ - self, - tkn: Token, - tkn_iter: TokenIterator, -- uop: Uop, -+ uop: CodeSection, - storage: Storage, - inst: Instruction | None, - ) -> bool: -@@ -384,7 +479,7 @@ - def instruction_size(self, - tkn: Token, - tkn_iter: TokenIterator, -- uop: Uop, -+ uop: CodeSection, - storage: Storage, - inst: Instruction | None, - ) -> bool: -@@ -403,7 +498,7 @@ - def _emit_if( - self, - tkn_iter: TokenIterator, -- uop: Uop, -+ uop: CodeSection, - storage: Storage, - inst: Instruction | None, - ) -> tuple[bool, Token, Storage]: -@@ -463,7 +558,7 @@ - def _emit_block( - self, - tkn_iter: TokenIterator, -- uop: Uop, -+ uop: CodeSection, - storage: Storage, - inst: Instruction | None, - emit_first_brace: bool -@@ -489,9 +584,15 @@ - self.out.start_line() - line = tkn.line - if tkn in escaping_calls: -- if tkn != reload: -+ escape = escaping_calls[tkn] -+ if escape.kills is not None: -+ if tkn == reload: -+ self.emit_reload(storage) -+ self.stackref_kill(escape.kills, storage, True) -+ self.emit_save(storage) -+ elif tkn != reload: - self.emit_save(storage) -- _, reload = escaping_calls[tkn] -+ reload = escape.end - elif tkn == reload: - self.emit_reload(storage) - if tkn.kind == "LBRACE": -@@ -504,8 +605,9 @@ - return reachable, tkn, storage - self.out.emit(tkn) - elif tkn.kind == "GOTO": -- reachable = False; -- self.out.emit(tkn) -+ label_tkn = next(tkn_iter) -+ self.goto_label(tkn, label_tkn, storage) -+ reachable = False - elif tkn.kind == "IDENTIFIER": - if tkn.text in self._replacers: - if not self._replacers[tkn.text](tkn, tkn_iter, uop, storage, inst): -@@ -533,22 +635,22 @@ - raise analysis_error(ex.args[0], tkn) from None - raise analysis_error("Expecting closing brace. Reached end of file", tkn) - -- - def emit_tokens( - self, -- uop: Uop, -+ code: CodeSection, - storage: Storage, - inst: Instruction | None, - ) -> Storage: -- tkn_iter = TokenIterator(uop.body) -+ tkn_iter = TokenIterator(code.body) - self.out.start_line() -- _, rbrace, storage = self._emit_block(tkn_iter, uop, storage, inst, False) -+ reachable, rbrace, storage = self._emit_block(tkn_iter, code, storage, inst, False) - try: -- self._print_storage(storage) -- storage.push_outputs() -- self._print_storage(storage) -+ if reachable: -+ self._print_storage(storage) -+ storage.push_outputs() -+ self._print_storage(storage) - except StackError as ex: -- raise analysis_error(ex.args[0], rbrace) -+ raise analysis_error(ex.args[0], rbrace) from None - return storage - - def emit(self, txt: str | Token) -> None: -@@ -583,6 +685,8 @@ - flags.append("HAS_ESCAPES_FLAG") - if p.pure: - flags.append("HAS_PURE_FLAG") -+ if p.no_save_ip: -+ flags.append("HAS_NO_SAVE_IP_FLAG") - if p.oparg_and_1: - flags.append("HAS_OPARG_AND_1_FLAG") - if flags: -diff --git a/Tools/cases_generator/lexer.py b/Tools/cases_generator/lexer.py -index 37f96398ff1..6afca750be9 100644 ---- a/Tools/cases_generator/lexer.py -+++ b/Tools/cases_generator/lexer.py -@@ -213,6 +213,11 @@ - # A macro in the DSL - MACRO = "MACRO" - kwds.append(MACRO) -+# A label in the DSL -+LABEL = "LABEL" -+kwds.append(LABEL) -+SPILLED = "SPILLED" -+kwds.append(SPILLED) - keywords = {name.lower(): name for name in kwds} - - ANNOTATION = "ANNOTATION" -@@ -226,6 +231,7 @@ - "replicate", - "tier1", - "tier2", -+ "no_save_ip", - } - - __all__ = [] -diff --git a/Tools/cases_generator/mypy.ini b/Tools/cases_generator/mypy.ini -index 8e5a31851c5..e54349bf54a 100644 ---- a/Tools/cases_generator/mypy.ini -+++ b/Tools/cases_generator/mypy.ini -@@ -8,7 +8,7 @@ - - # ...And be strict: - strict = True --strict_concatenate = True -+extra_checks = True - enable_error_code = ignore-without-code,redundant-expr,truthy-bool,possibly-undefined - warn_unreachable = True - allow_redefinition = True -diff --git a/Tools/cases_generator/opcode_metadata_generator.py b/Tools/cases_generator/opcode_metadata_generator.py -index 1a9849c0cbb..453db6905d6 100644 ---- a/Tools/cases_generator/opcode_metadata_generator.py -+++ b/Tools/cases_generator/opcode_metadata_generator.py -@@ -53,6 +53,7 @@ - "PASSTHROUGH", - "OPARG_AND_1", - "ERROR_NO_POP", -+ "NO_SAVE_IP", - ] - - -@@ -285,8 +286,8 @@ - table_size = 256 + len(analysis.pseudos) - out.emit("struct opcode_metadata {\n") - out.emit("uint8_t valid_entry;\n") -- out.emit("int8_t instr_format;\n") -- out.emit("int16_t flags;\n") -+ out.emit("uint8_t instr_format;\n") -+ out.emit("uint16_t flags;\n") - out.emit("};\n\n") - out.emit( - f"extern const struct opcode_metadata _PyOpcode_opcode_metadata[{table_size}];\n" -diff --git a/Tools/cases_generator/optimizer_generator.py b/Tools/cases_generator/optimizer_generator.py -index d08b621aed5..6c33debd58e 100644 ---- a/Tools/cases_generator/optimizer_generator.py -+++ b/Tools/cases_generator/optimizer_generator.py -@@ -36,10 +36,10 @@ - - def type_name(var: StackItem) -> str: - if var.is_array(): -- return f"_Py_UopsSymbol **" -+ return f"JitOptSymbol **" - if var.type: - return var.type -- return f"_Py_UopsSymbol *" -+ return f"JitOptSymbol *" - - - def declare_variables(uop: Uop, out: CWriter, skip_inputs: bool) -> None: -@@ -112,6 +112,9 @@ - def emit_reload(self, storage: Storage) -> None: - pass - -+ def goto_label(self, goto: Token, label: Token, storage: Storage) -> None: -+ self.out.emit(goto) -+ self.out.emit(label) - - def write_uop( - override: Uop | None, -@@ -126,7 +129,7 @@ - try: - out.start_line() - if override: -- code_list, storage = Storage.for_uop(stack, prototype, extract_bits=False) -+ code_list, storage = Storage.for_uop(stack, prototype) - for code in code_list: - out.emit(code) - if debug: -@@ -145,17 +148,17 @@ - cast = f"uint{cache.size*16}_t" - out.emit(f"{type}{cache.name} = ({cast})this_instr->operand0;\n") - if override: -- emitter = OptimizerEmitter(out) -+ emitter = OptimizerEmitter(out, {}) - # No reference management of inputs needed. - for var in storage.inputs: # type: ignore[possibly-undefined] - var.defined = False - storage = emitter.emit_tokens(override, storage, None) - out.start_line() -- storage.flush(out, cast_type="_Py_UopsSymbol *", extract_bits=False) -+ storage.flush(out, cast_type="JitOptSymbol *") - else: - emit_default(out, uop, stack) - out.start_line() -- stack.flush(out, cast_type="_Py_UopsSymbol *", extract_bits=False) -+ stack.flush(out, cast_type="JitOptSymbol *") - except StackError as ex: - raise analysis_error(ex.args[0], prototype.body[0]) # from None - -@@ -198,7 +201,7 @@ - declare_variables(override, out, skip_inputs=False) - else: - declare_variables(uop, out, skip_inputs=True) -- stack = Stack() -+ stack = Stack(False) - write_uop(override, uop, out, stack, debug, skip_inputs=(override is None)) - out.start_line() - out.emit("break;\n") -diff --git a/Tools/cases_generator/parser.py b/Tools/cases_generator/parser.py -index db672ad5501..696c5c16432 100644 ---- a/Tools/cases_generator/parser.py -+++ b/Tools/cases_generator/parser.py -@@ -3,6 +3,7 @@ - Macro, - Pseudo, - Family, -+ LabelDef, - Parser, - Context, - CacheEffect, -@@ -12,6 +13,7 @@ - AstNode, - ) - -+CodeDef = InstDef | LabelDef - - def prettify_filename(filename: str) -> str: - # Make filename more user-friendly and less platform-specific, -diff --git a/Tools/cases_generator/parsing.py b/Tools/cases_generator/parsing.py -index de31d9b232f..011f34de288 100644 ---- a/Tools/cases_generator/parsing.py -+++ b/Tools/cases_generator/parsing.py -@@ -150,8 +150,14 @@ - targets: list[str] # opcodes this can be replaced by - as_sequence: bool - -+@dataclass -+class LabelDef(Node): -+ name: str -+ spilled: bool -+ block: Block - --AstNode = InstDef | Macro | Pseudo | Family -+ -+AstNode = InstDef | Macro | Pseudo | Family | LabelDef - - - class Parser(PLexer): -@@ -165,6 +171,21 @@ - return pseudo - if inst := self.inst_def(): - return inst -+ if label := self.label_def(): -+ return label -+ return None -+ -+ @contextual -+ def label_def(self) -> LabelDef | None: -+ spilled = False -+ if self.expect(lx.SPILLED): -+ spilled = True -+ if self.expect(lx.LABEL): -+ if self.expect(lx.LPAREN): -+ if tkn := self.expect(lx.IDENTIFIER): -+ if self.expect(lx.RPAREN): -+ if block := self.block(): -+ return LabelDef(tkn.text, spilled, block) - return None - - @contextual -@@ -357,9 +378,12 @@ - def uop(self) -> UOp | None: - if tkn := self.expect(lx.IDENTIFIER): - if self.expect(lx.DIVIDE): -+ sign = 1 -+ if negate := self.expect(lx.MINUS): -+ sign = -1 - if num := self.expect(lx.NUMBER): - try: -- size = int(num.text) -+ size = sign * int(num.text) - except ValueError: - raise self.make_syntax_error( - f"Expected integer, got {num.text!r}" -diff --git a/Tools/cases_generator/stack.py b/Tools/cases_generator/stack.py -index 9471fe0e56f..729973f1e32 100644 ---- a/Tools/cases_generator/stack.py -+++ b/Tools/cases_generator/stack.py -@@ -224,13 +224,14 @@ - return "array" if var.is_array() else "scalar" - - class Stack: -- def __init__(self) -> None: -+ def __init__(self, extract_bits: bool=True) -> None: - self.top_offset = StackOffset.empty() - self.base_offset = StackOffset.empty() - self.variables: list[Local] = [] - self.defined: set[str] = set() -+ self.extract_bits = extract_bits - -- def pop(self, var: StackItem, extract_bits: bool = True) -> tuple[str, Local]: -+ def pop(self, var: StackItem) -> tuple[str, Local]: - self.top_offset.pop(var) - indirect = "&" if var.is_array() else "" - if self.variables: -@@ -272,7 +273,7 @@ - return "", Local.unused(var) - self.defined.add(var.name) - cast = f"({var.type})" if (not indirect and var.type) else "" -- bits = ".bits" if cast and extract_bits else "" -+ bits = ".bits" if cast and self.extract_bits else "" - assign = f"{var.name} = {cast}{indirect}stack_pointer[{self.base_offset.to_c()}]{bits};" - if var.condition: - if var.condition == "1": -@@ -315,7 +316,7 @@ - out.emit("assert(WITHIN_STACK_BOUNDS());\n") - - def flush( -- self, out: CWriter, cast_type: str = "uintptr_t", extract_bits: bool = True -+ self, out: CWriter, cast_type: str = "uintptr_t" - ) -> None: - out.start_line() - var_offset = self.base_offset.copy() -@@ -324,7 +325,7 @@ - var.defined and - not var.in_memory - ): -- Stack._do_emit(out, var.item, var_offset, cast_type, extract_bits) -+ Stack._do_emit(out, var.item, var_offset, cast_type, self.extract_bits) - var.in_memory = True - var_offset.push(var.item) - number = self.top_offset.to_c() -@@ -346,7 +347,7 @@ - ) - - def copy(self) -> "Stack": -- other = Stack() -+ other = Stack(self.extract_bits) - other.top_offset = self.top_offset.copy() - other.base_offset = self.base_offset.copy() - other.variables = [var.copy() for var in self.variables] -@@ -507,14 +508,10 @@ - return True - return False - -- def flush(self, out: CWriter, cast_type: str = "uintptr_t", extract_bits: bool = True) -> None: -+ def flush(self, out: CWriter, cast_type: str = "uintptr_t") -> None: - self.clear_dead_inputs() - self._push_defined_outputs() -- self.stack.flush(out, cast_type, extract_bits) -- -- def pop_dead_inputs(self, out: CWriter, cast_type: str = "uintptr_t", extract_bits: bool = True) -> None: -- self.clear_dead_inputs() -- self.stack.flush(out, cast_type, extract_bits) -+ self.stack.flush(out, cast_type) - - def save(self, out: CWriter) -> None: - assert self.spilled >= 0 -@@ -534,12 +531,12 @@ - out.emit("stack_pointer = _PyFrame_GetStackPointer(frame);\n") - - @staticmethod -- def for_uop(stack: Stack, uop: Uop, extract_bits: bool = True) -> tuple[list[str], "Storage"]: -+ def for_uop(stack: Stack, uop: Uop) -> tuple[list[str], "Storage"]: - code_list: list[str] = [] - inputs: list[Local] = [] - peeks: list[Local] = [] - for input in reversed(uop.stack.inputs): -- code, local = stack.pop(input, extract_bits) -+ code, local = stack.pop(input) - code_list.append(code) - if input.peek: - peeks.append(local) -@@ -573,7 +570,7 @@ - assert [v.name for v in inputs] == [v.name for v in self.inputs], (inputs, self.inputs) - return Storage( - new_stack, inputs, -- self.copy_list(self.outputs), self.copy_list(self.peeks) -+ self.copy_list(self.outputs), self.copy_list(self.peeks), self.spilled - ) - - def sanity_check(self) -> None: -diff --git a/Tools/cases_generator/target_generator.py b/Tools/cases_generator/target_generator.py -index c5097b75847..db028116db9 100644 ---- a/Tools/cases_generator/target_generator.py -+++ b/Tools/cases_generator/target_generator.py -@@ -13,6 +13,7 @@ - DEFAULT_INPUT, - ROOT, - ) -+from tier1_generator import UNKNOWN_OPCODE_HANDLER - from cwriter import CWriter - - -@@ -25,11 +26,49 @@ - for name, op in analysis.opmap.items(): - if op < 256: - targets[op] = f"&&TARGET_{name},\n" -+ out.emit("#ifndef Py_TAIL_CALL_INTERP\n") - out.emit("static void *opcode_targets[256] = {\n") - for target in targets: - out.emit(target) - out.emit("};\n") -+ out.emit("#else /* Py_TAIL_CALL_INTERP */\n") - -+def function_proto(name: str) -> str: -+ return f"Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_{name}(TAIL_CALL_PARAMS)" -+ -+ -+def write_tailcall_dispatch_table(analysis: Analysis, out: CWriter) -> None: -+ out.emit("static py_tail_call_funcptr INSTRUCTION_TABLE[256];\n") -+ out.emit("\n") -+ -+ # Emit function prototypes for labels. -+ for name in analysis.labels: -+ out.emit(f"{function_proto(name)};\n") -+ out.emit("\n") -+ -+ # Emit function prototypes for opcode handlers. -+ for name in sorted(analysis.instructions.keys()): -+ out.emit(f"{function_proto(name)};\n") -+ out.emit("\n") -+ -+ # Emit unknown opcode handler. -+ out.emit(function_proto("UNKNOWN_OPCODE")) -+ out.emit(" {\n") -+ out.emit("int opcode = next_instr->op.code;\n") -+ out.emit(UNKNOWN_OPCODE_HANDLER) -+ out.emit("}\n") -+ out.emit("\n") -+ -+ # Emit the dispatch table. -+ out.emit("static py_tail_call_funcptr INSTRUCTION_TABLE[256] = {\n") -+ for name in sorted(analysis.instructions.keys()): -+ out.emit(f"[{name}] = _TAIL_CALL_{name},\n") -+ named_values = analysis.opmap.values() -+ for rest in range(256): -+ if rest not in named_values: -+ out.emit(f"[{rest}] = _TAIL_CALL_UNKNOWN_OPCODE,\n") -+ out.emit("};\n") -+ outfile.write("#endif /* Py_TAIL_CALL_INTERP */\n") - - arg_parser = argparse.ArgumentParser( - description="Generate the file with dispatch targets.", -@@ -52,3 +91,4 @@ - with open(args.output, "w") as outfile: - out = CWriter(outfile, 0, False) - write_opcode_targets(data, out) -+ write_tailcall_dispatch_table(data, out) -diff --git a/Tools/cases_generator/tier1_generator.py b/Tools/cases_generator/tier1_generator.py -index fcdd3bdacd0..02012fb4172 100644 ---- a/Tools/cases_generator/tier1_generator.py -+++ b/Tools/cases_generator/tier1_generator.py -@@ -24,14 +24,17 @@ - Emitter, - ) - from cwriter import CWriter --from typing import TextIO -+from typing import TextIO, Callable - from stack import Local, Stack, StackError, get_stack_effect, Storage - -- - DEFAULT_OUTPUT = ROOT / "Python/generated_cases.c.h" - - - FOOTER = "#undef TIER_ONE\n" -+INSTRUCTION_START_MARKER = "/* BEGIN INSTRUCTIONS */" -+INSTRUCTION_END_MARKER = "/* END INSTRUCTIONS */" -+LABEL_START_MARKER = "/* BEGIN LABELS */" -+LABEL_END_MARKER = "/* END LABELS */" - - - def declare_variable(var: StackItem, out: CWriter) -> None: -@@ -125,43 +128,131 @@ - for cache in uop.caches: - if cache.name != "unused": - return True -+ # Can't be merged into the loop above, because -+ # this must strictly be performed at the end. -+ for uop in inst.parts: -+ if not isinstance(uop, Uop): -+ continue -+ for tkn in uop.body: -+ if (tkn.kind == "IDENTIFIER" -+ and (tkn.text in {"DEOPT_IF", "EXIT_IF"})): -+ return True - return False - - -+UNKNOWN_OPCODE_HANDLER ="""\ -+_PyErr_Format(tstate, PyExc_SystemError, -+ "%U:%d: unknown opcode %d", -+ _PyFrame_GetCode(frame)->co_filename, -+ PyUnstable_InterpreterFrame_GetLine(frame), -+ opcode); -+JUMP_TO_LABEL(error); -+""" -+ - def generate_tier1( - filenames: list[str], analysis: Analysis, outfile: TextIO, lines: bool - ) -> None: - write_header(__file__, filenames, outfile) -- outfile.write( -- """ -+ outfile.write(""" - #ifdef TIER_TWO - #error "This file is for Tier 1 only" - #endif - #define TIER_ONE 1 -+""") -+ outfile.write(f""" -+#ifndef Py_TAIL_CALL_INTERP -+#if !USE_COMPUTED_GOTOS -+ dispatch_opcode: -+ switch (opcode) -+#endif -+ {{ -+#endif /* Py_TAIL_CALL_INTERP */ -+ {INSTRUCTION_START_MARKER} - """ - ) -+ generate_tier1_cases(analysis, outfile, lines) -+ outfile.write(f""" -+ {INSTRUCTION_END_MARKER} -+#ifndef Py_TAIL_CALL_INTERP -+#if USE_COMPUTED_GOTOS -+ _unknown_opcode: -+#else -+ EXTRA_CASES // From pycore_opcode_metadata.h, a 'case' for each unused opcode -+#endif -+ /* Tell C compilers not to hold the opcode variable in the loop. -+ next_instr points the current instruction without TARGET(). */ -+ opcode = next_instr->op.code; -+ {UNKNOWN_OPCODE_HANDLER} -+ -+ }} -+ -+ /* This should never be reached. Every opcode should end with DISPATCH() -+ or goto error. */ -+ Py_UNREACHABLE(); -+#endif /* Py_TAIL_CALL_INTERP */ -+ {LABEL_START_MARKER} -+""") - out = CWriter(outfile, 2, lines) -- emitter = Emitter(out) -+ emitter = Emitter(out, analysis.labels) -+ generate_tier1_labels(analysis, emitter) -+ outfile.write(f"{LABEL_END_MARKER}\n") -+ outfile.write(FOOTER) -+ -+ -+ -+def generate_tier1_labels( -+ analysis: Analysis, emitter: Emitter -+) -> None: -+ emitter.emit("\n") -+ # Emit tail-callable labels as function defintions -+ for name, label in analysis.labels.items(): -+ emitter.emit(f"LABEL({name})\n") -+ emitter.emit("{\n") -+ storage = Storage(Stack(), [], [], []) -+ if label.spilled: -+ storage.spilled = 1 -+ emitter.emit("/* STACK SPILLED */\n") -+ emitter.emit_tokens(label, storage, None) -+ emitter.emit("\n") -+ emitter.emit("}\n") -+ emitter.emit("\n") -+ -+ -+def generate_tier1_cases( -+ analysis: Analysis, outfile: TextIO, lines: bool -+) -> None: -+ out = CWriter(outfile, 2, lines) -+ emitter = Emitter(out, analysis.labels) - out.emit("\n") - for name, inst in sorted(analysis.instructions.items()): -- needs_this = uses_this(inst) - out.emit("\n") - out.emit(f"TARGET({name}) {{\n") -- unused_guard = "(void)this_instr;\n" if inst.family is None else "" -+ # We need to ifdef it because this breaks platforms -+ # without computed gotos/tail calling. -+ out.emit(f"#if defined(Py_TAIL_CALL_INTERP)\n") -+ out.emit(f"int opcode = {name};\n") -+ out.emit(f"(void)(opcode);\n") -+ out.emit(f"#endif\n") -+ needs_this = uses_this(inst) -+ unused_guard = "(void)this_instr;\n" - if inst.properties.needs_prev: - out.emit(f"_Py_CODEUNIT* const prev_instr = frame->instr_ptr;\n") -+ - if needs_this and not inst.is_target: -- out.emit(f"_Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr;\n") -+ out.emit(f"_Py_CODEUNIT* const this_instr = next_instr;\n") - out.emit(unused_guard) -- else: -+ if not inst.properties.no_save_ip: - out.emit(f"frame->instr_ptr = next_instr;\n") -+ - out.emit(f"next_instr += {inst.size};\n") - out.emit(f"INSTRUCTION_STATS({name});\n") - if inst.is_target: -- out.emit(f"PREDICTED({name});\n") -+ out.emit(f"PREDICTED_{name}:;\n") - if needs_this: - out.emit(f"_Py_CODEUNIT* const this_instr = next_instr - {inst.size};\n") - out.emit(unused_guard) -+ if inst.properties.uses_opcode: -+ out.emit(f"opcode = {name};\n") - if inst.family is not None: - out.emit( - f"static_assert({inst.family.size} == {inst.size-1}" -@@ -182,7 +273,6 @@ - out.start_line() - out.emit("}") - out.emit("\n") -- outfile.write(FOOTER) - - - arg_parser = argparse.ArgumentParser( -diff --git a/Tools/cases_generator/tier2_generator.py b/Tools/cases_generator/tier2_generator.py -index dd16a1a7eb2..5e23360cdc0 100644 ---- a/Tools/cases_generator/tier2_generator.py -+++ b/Tools/cases_generator/tier2_generator.py -@@ -9,6 +9,8 @@ - Analysis, - Instruction, - Uop, -+ Label, -+ CodeSection, - analyze_files, - StackItem, - analysis_error, -@@ -65,51 +67,21 @@ - - class Tier2Emitter(Emitter): - -- def __init__(self, out: CWriter): -- super().__init__(out) -+ def __init__(self, out: CWriter, labels: dict[str, Label]): -+ super().__init__(out, labels) - self._replacers["oparg"] = self.oparg - -- def error_if( -- self, -- tkn: Token, -- tkn_iter: TokenIterator, -- uop: Uop, -- storage: Storage, -- inst: Instruction | None, -- ) -> bool: -- self.out.emit_at("if ", tkn) -- lparen = next(tkn_iter) -- self.emit(lparen) -- assert lparen.kind == "LPAREN" -- first_tkn = next(tkn_iter) -- self.out.emit(first_tkn) -- emit_to(self.out, tkn_iter, "COMMA") -- label = next(tkn_iter).text -- next(tkn_iter) # RPAREN -- next(tkn_iter) # Semi colon -- self.emit(") JUMP_TO_ERROR();\n") -- return not always_true(first_tkn) -- -- -- def error_no_pop( -- self, -- tkn: Token, -- tkn_iter: TokenIterator, -- uop: Uop, -- storage: Storage, -- inst: Instruction | None, -- ) -> bool: -- next(tkn_iter) # LPAREN -- next(tkn_iter) # RPAREN -- next(tkn_iter) # Semi colon -- self.out.emit_at("JUMP_TO_ERROR();", tkn) -- return False -+ def goto_error(self, offset: int, label: str, storage: Storage) -> str: -+ # To do: Add jump targets for popping values. -+ if offset != 0: -+ storage.copy().flush(self.out) -+ return f"JUMP_TO_ERROR();" - - def deopt_if( - self, - tkn: Token, - tkn_iter: TokenIterator, -- uop: Uop, -+ uop: CodeSection, - storage: Storage, - inst: Instruction | None, - ) -> bool: -@@ -130,7 +102,7 @@ - self, - tkn: Token, - tkn_iter: TokenIterator, -- uop: Uop, -+ uop: CodeSection, - storage: Storage, - inst: Instruction | None, - ) -> bool: -@@ -150,7 +122,7 @@ - self, - tkn: Token, - tkn_iter: TokenIterator, -- uop: Uop, -+ uop: CodeSection, - storage: Storage, - inst: Instruction | None, - ) -> bool: -@@ -210,7 +182,7 @@ - """ - ) - out = CWriter(outfile, 2, lines) -- emitter = Tier2Emitter(out) -+ emitter = Tier2Emitter(out, analysis.labels) - out.emit("\n") - for name, uop in analysis.uops.items(): - if uop.properties.tier == 1: -diff --git a/Tools/clinic/libclinic/converters.py b/Tools/clinic/libclinic/converters.py -index a65f73ba02f..2998eb51964 100644 ---- a/Tools/clinic/libclinic/converters.py -+++ b/Tools/clinic/libclinic/converters.py -@@ -1182,10 +1182,8 @@ - @property - def parser_type(self) -> str: - assert self.type is not None -- if self.function.kind in {METHOD_INIT, METHOD_NEW, STATIC_METHOD, CLASS_METHOD}: -- tp, _ = correct_name_for_self(self.function) -- return tp -- return self.type -+ tp, _ = correct_name_for_self(self.function) -+ return tp - - def render(self, parameter: Parameter, data: CRenderData) -> None: - """ -diff --git a/Tools/clinic/libclinic/cpp.py b/Tools/clinic/libclinic/cpp.py -index e115d65a88e..3cfe99b7126 100644 ---- a/Tools/clinic/libclinic/cpp.py -+++ b/Tools/clinic/libclinic/cpp.py -@@ -132,6 +132,9 @@ - if line_comment: - line = before.rstrip() - -+ if self.in_comment: -+ return -+ - if not line.startswith('#'): - return - -diff --git a/Tools/clinic/libclinic/parse_args.py b/Tools/clinic/libclinic/parse_args.py -index a57d729bec5..ff4731e99b9 100644 ---- a/Tools/clinic/libclinic/parse_args.py -+++ b/Tools/clinic/libclinic/parse_args.py -@@ -146,6 +146,9 @@ - GETSET_DOCSTRING_PROTOTYPE_STRVAR: Final[str] = libclinic.normalize_snippet(""" - PyDoc_STRVAR({getset_basename}__doc__, - {docstring}); -+ #if defined({getset_basename}_DOCSTR) -+ # undef {getset_basename}_DOCSTR -+ #endif - #define {getset_basename}_DOCSTR {getset_basename}__doc__ - """) - IMPL_DEFINITION_PROTOTYPE: Final[str] = libclinic.normalize_snippet(""" -diff --git a/Tools/clinic/mypy.ini b/Tools/clinic/mypy.ini -index b1fdad673c6..6520e05db0b 100644 ---- a/Tools/clinic/mypy.ini -+++ b/Tools/clinic/mypy.ini -@@ -7,6 +7,6 @@ - - # and be strict! - strict = True --strict_concatenate = True -+extra_checks = True - enable_error_code = ignore-without-code,redundant-expr,truthy-bool - warn_unreachable = True -diff --git a/Tools/ftscalingbench/ftscalingbench.py b/Tools/ftscalingbench/ftscalingbench.py -index 767aeae9349..364c465bc91 100644 ---- a/Tools/ftscalingbench/ftscalingbench.py -+++ b/Tools/ftscalingbench/ftscalingbench.py -@@ -54,8 +54,16 @@ - - @register_benchmark - def cmodule_function(): -- for i in range(1000 * WORK_SCALE): -- math.floor(i * i) -+ N = 1000 * WORK_SCALE -+ for i in range(N): -+ math.cos(i / N) -+ -+@register_benchmark -+def object_lookup_special(): -+ # round() uses `_PyObject_LookupSpecial()` internally. -+ N = 1000 * WORK_SCALE -+ for i in range(N): -+ round(i / N) - - @register_benchmark - def mult_constant(): -@@ -206,7 +214,7 @@ - color = "\x1b[33m" # yellow - reset_color = "\x1b[0m" - -- print(f"{color}{func.__name__:<18} {round(factor, 1):>4}x {direction}{reset_color}") -+ print(f"{color}{func.__name__:<25} {round(factor, 1):>4}x {direction}{reset_color}") - - def determine_num_threads_and_affinity(): - if sys.platform != "linux": -diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py -index 698ecbd3b54..27aa6b0cc26 100755 ---- a/Tools/gdb/libpython.py -+++ b/Tools/gdb/libpython.py -@@ -99,7 +99,7 @@ - Py_TPFLAGS_TYPE_SUBCLASS = (1 << 31) - - #From pycore_frame.h --FRAME_OWNED_BY_CSTACK = 3 -+FRAME_OWNED_BY_INTERPRETER = 3 - - MAX_OUTPUT_LEN=1024 - -@@ -890,7 +890,7 @@ - - def proxyval(self, visited): - ''' -- Python's Include/longinterpr.h has this declaration: -+ Python's Include/cpython/longinterpr.h has this declaration: - - typedef struct _PyLongValue { - uintptr_t lv_tag; /* Number of digits, sign and flags */ -@@ -909,8 +909,7 @@ - - 0: Positive - - 1: Zero - - 2: Negative -- The third lowest bit of lv_tag is reserved for an immortality flag, but is -- not currently used. -+ The third lowest bit of lv_tag is set to 1 for the small ints and 0 otherwise. - - where SHIFT can be either: - #define PyLong_SHIFT 30 -@@ -1113,7 +1112,7 @@ - return int(instr_ptr - first_instr) - - def is_shim(self): -- return self._f_special("owner", int) == FRAME_OWNED_BY_CSTACK -+ return self._f_special("owner", int) == FRAME_OWNED_BY_INTERPRETER - - def previous(self): - return self._f_special("previous", PyFramePtr) -diff --git a/Tools/i18n/pygettext.py b/Tools/i18n/pygettext.py -index f78ff16bff9..4720aecbdc5 100755 ---- a/Tools/i18n/pygettext.py -+++ b/Tools/i18n/pygettext.py -@@ -1,41 +1,15 @@ - #! /usr/bin/env python3 --# -*- coding: iso-8859-1 -*- --# Originally written by Barry Warsaw --# --# Minimally patched to make it even more xgettext compatible --# by Peter Funk --# --# 2002-11-22 Jürgen Hermann --# Added checks that _() only contains string literals, and --# command line args are resolved to module lists, i.e. you --# can now pass a filename, a module or package name, or a --# directory (including globbing chars, important for Win32). --# Made docstring fit in 80 chars wide displays using pydoc. --# - --# for selftesting --try: -- import fintl -- _ = fintl.gettext --except ImportError: -- _ = lambda s: s -- --__doc__ = _("""pygettext -- Python equivalent of xgettext(1) -+"""pygettext -- Python equivalent of xgettext(1) - - Many systems (Solaris, Linux, Gnu) provide extensive tools that ease the - internationalization of C programs. Most of these tools are independent of - the programming language and can be used from within Python programs. - Martin von Loewis' work[1] helps considerably in this regard. - --There's one problem though; xgettext is the program that scans source code --looking for message strings, but it groks only C (or C++). Python --introduces a few wrinkles, such as dual quoting characters, triple quoted --strings, and raw strings. xgettext understands none of this. -- --Enter pygettext, which uses Python's standard tokenize module to scan --Python source code, generating .pot files identical to what GNU xgettext[2] --generates for C and C++ code. From there, the standard GNU tools can be --used. -+pygettext uses Python's standard tokenize module to scan Python source -+code, generating .pot files identical to what GNU xgettext[2] generates -+for C and C++ code. From there, the standard GNU tools can be used. - - A word about marking Python strings as candidates for translation. GNU - xgettext recognizes the following keywords: gettext, dgettext, dcgettext, -@@ -61,6 +35,9 @@ - option arguments is broken, and in these cases, pygettext just defines - additional switches. - -+NOTE: The public interface of pygettext is limited to the command-line -+interface only. The internal API is subject to change without notice. -+ - Usage: pygettext [options] inputfile ... - - Options: -@@ -153,18 +130,16 @@ - conjunction with the -D option above. - - If `inputfile' is -, standard input is read. --""") -+""" - --import os -+import ast -+import getopt -+import glob - import importlib.machinery - import importlib.util -+import os - import sys --import glob - import time --import getopt --import ast --import tokenize --from collections import defaultdict - from dataclasses import dataclass, field - from operator import itemgetter - -@@ -173,7 +148,7 @@ - - # The normal pot-file header. msgmerge and Emacs's po-mode work better if it's - # there. --pot_header = _('''\ -+pot_header = '''\ - # SOME DESCRIPTIVE TITLE. - # Copyright (C) YEAR ORGANIZATION - # FIRST AUTHOR , YEAR. -@@ -190,7 +165,7 @@ - "Content-Transfer-Encoding: %(encoding)s\\n" - "Generated-By: pygettext.py %(version)s\\n" - --''') -+''' - - - def usage(code, msg=''): -@@ -204,7 +179,7 @@ - global escapes, escape - if pass_nonascii: - # Allow non-ascii characters to pass through so that e.g. 'msgid -- # "Höhe"' would result not result in 'msgid "H\366he"'. Otherwise we -+ # "Höhe"' would result not result in 'msgid "H\366he"'. Otherwise we - # escape any character outside the 32..126 range. - mod = 128 - escape = escape_ascii -@@ -224,19 +199,11 @@ - def escape_ascii(s, encoding): - return ''.join(escapes[ord(c)] if ord(c) < 128 else c for c in s) - -+ - def escape_nonascii(s, encoding): - return ''.join(escapes[b] for b in s.encode(encoding)) - - --def is_literal_string(s): -- return s[0] in '\'"' or (s[0] in 'rRuU' and s[1] in '\'"') -- -- --def safe_eval(s): -- # unwrap quotes, safely -- return eval(s, {'__builtins__':{}}, {}) -- -- - def normalize(s, encoding): - # This converts the various Python string types into a format that is - # appropriate for .po files, namely much closer to C style. -@@ -318,11 +285,6 @@ - } - - --def matches_spec(message, spec): -- """Check if a message has all the keys defined by the keyword spec.""" -- return all(key in message for key in spec.values()) -- -- - @dataclass(frozen=True) - class Location: - filename: str -@@ -347,273 +309,163 @@ - self.is_docstring |= is_docstring - - --def key_for(msgid, msgctxt=None): -- if msgctxt is not None: -- return (msgctxt, msgid) -- return msgid -+class GettextVisitor(ast.NodeVisitor): -+ def __init__(self, options): -+ super().__init__() -+ self.options = options -+ self.filename = None -+ self.messages = {} - -+ def visit_file(self, node, filename): -+ self.filename = filename -+ self.visit(node) - --class TokenEater: -- def __init__(self, options): -- self.__options = options -- self.__messages = {} -- self.__state = self.__waiting -- self.__data = defaultdict(str) -- self.__curr_arg = 0 -- self.__curr_keyword = None -- self.__lineno = -1 -- self.__freshmodule = 1 -- self.__curfile = None -- self.__enclosurecount = 0 -- -- def __call__(self, ttype, tstring, stup, etup, line): -- # dispatch --## import token --## print('ttype:', token.tok_name[ttype], 'tstring:', tstring, --## file=sys.stderr) -- self.__state(ttype, tstring, stup[0]) -- -- def __waiting(self, ttype, tstring, lineno): -- opts = self.__options -- # Do docstring extractions, if enabled -- if opts.docstrings and not opts.nodocstrings.get(self.__curfile): -- # module docstring? -- if self.__freshmodule: -- if ttype == tokenize.STRING and is_literal_string(tstring): -- self.__addentry({'msgid': safe_eval(tstring)}, lineno, is_docstring=True) -- self.__freshmodule = 0 -- return -- if ttype in (tokenize.COMMENT, tokenize.NL, tokenize.ENCODING): -- return -- self.__freshmodule = 0 -- # class or func/method docstring? -- if ttype == tokenize.NAME and tstring in ('class', 'def'): -- self.__state = self.__suiteseen -- return -- if ttype == tokenize.NAME and tstring in ('class', 'def'): -- self.__state = self.__ignorenext -+ def visit_Module(self, node): -+ self._extract_docstring(node) -+ self.generic_visit(node) -+ -+ visit_ClassDef = visit_FunctionDef = visit_AsyncFunctionDef = visit_Module -+ -+ def visit_Call(self, node): -+ self._extract_message(node) -+ self.generic_visit(node) -+ -+ def _extract_docstring(self, node): -+ if (not self.options.docstrings or -+ self.options.nodocstrings.get(self.filename)): - return -- if ttype == tokenize.NAME and tstring in opts.keywords: -- self.__state = self.__keywordseen -- self.__curr_keyword = tstring -+ -+ docstring = ast.get_docstring(node) -+ if docstring is not None: -+ lineno = node.body[0].lineno # The first statement is the docstring -+ self._add_message(lineno, docstring, is_docstring=True) -+ -+ def _extract_message(self, node): -+ func_name = self._get_func_name(node) -+ spec = self.options.keywords.get(func_name) -+ if spec is None: -+ return -+ -+ max_index = max(spec) -+ has_var_positional = any(isinstance(arg, ast.Starred) for -+ arg in node.args[:max_index+1]) -+ if has_var_positional: -+ print(f'*** {self.filename}:{node.lineno}: Variable positional ' -+ f'arguments are not allowed in gettext calls', file=sys.stderr) - return -- if ttype == tokenize.STRING: -- maybe_fstring = ast.parse(tstring, mode='eval').body -- if not isinstance(maybe_fstring, ast.JoinedStr): -- return -- for value in filter(lambda node: isinstance(node, ast.FormattedValue), -- maybe_fstring.values): -- for call in filter(lambda node: isinstance(node, ast.Call), -- ast.walk(value)): -- func = call.func -- if isinstance(func, ast.Name): -- func_name = func.id -- elif isinstance(func, ast.Attribute): -- func_name = func.attr -- else: -- continue -- -- if func_name not in opts.keywords: -- continue -- if len(call.args) != 1: -- print(_( -- '*** %(file)s:%(lineno)s: Seen unexpected amount of' -- ' positional arguments in gettext call: %(source_segment)s' -- ) % { -- 'source_segment': ast.get_source_segment(tstring, call) or tstring, -- 'file': self.__curfile, -- 'lineno': lineno -- }, file=sys.stderr) -- continue -- if call.keywords: -- print(_( -- '*** %(file)s:%(lineno)s: Seen unexpected keyword arguments' -- ' in gettext call: %(source_segment)s' -- ) % { -- 'source_segment': ast.get_source_segment(tstring, call) or tstring, -- 'file': self.__curfile, -- 'lineno': lineno -- }, file=sys.stderr) -- continue -- arg = call.args[0] -- if not isinstance(arg, ast.Constant): -- print(_( -- '*** %(file)s:%(lineno)s: Seen unexpected argument type' -- ' in gettext call: %(source_segment)s' -- ) % { -- 'source_segment': ast.get_source_segment(tstring, call) or tstring, -- 'file': self.__curfile, -- 'lineno': lineno -- }, file=sys.stderr) -- continue -- if isinstance(arg.value, str): -- self.__curr_keyword = func_name -- self.__addentry({'msgid': arg.value}, lineno) -- -- def __suiteseen(self, ttype, tstring, lineno): -- # skip over any enclosure pairs until we see the colon -- if ttype == tokenize.OP: -- if tstring == ':' and self.__enclosurecount == 0: -- # we see a colon and we're not in an enclosure: end of def -- self.__state = self.__suitedocstring -- elif tstring in '([{': -- self.__enclosurecount += 1 -- elif tstring in ')]}': -- self.__enclosurecount -= 1 -- -- def __suitedocstring(self, ttype, tstring, lineno): -- # ignore any intervening noise -- if ttype == tokenize.STRING and is_literal_string(tstring): -- self.__addentry({'msgid': safe_eval(tstring)}, lineno, is_docstring=True) -- self.__state = self.__waiting -- elif ttype not in (tokenize.NEWLINE, tokenize.INDENT, -- tokenize.COMMENT): -- # there was no class docstring -- self.__state = self.__waiting -- -- def __keywordseen(self, ttype, tstring, lineno): -- if ttype == tokenize.OP and tstring == '(': -- self.__data.clear() -- self.__curr_arg = 0 -- self.__enclosurecount = 0 -- self.__lineno = lineno -- self.__state = self.__openseen -- else: -- self.__state = self.__waiting -- -- def __openseen(self, ttype, tstring, lineno): -- spec = self.__options.keywords[self.__curr_keyword] -- arg_type = spec.get(self.__curr_arg) -- expect_string_literal = arg_type is not None -- -- if ttype == tokenize.OP and self.__enclosurecount == 0: -- if tstring == ')': -- # We've seen the last of the translatable strings. Record the -- # line number of the first line of the strings and update the list -- # of messages seen. Reset state for the next batch. If there -- # were no strings inside _(), then just ignore this entry. -- if self.__data: -- self.__addentry(self.__data) -- self.__state = self.__waiting -- return -- elif tstring == ',': -- # Advance to the next argument -- self.__curr_arg += 1 -- return - -- if expect_string_literal: -- if ttype == tokenize.STRING and is_literal_string(tstring): -- self.__data[arg_type] += safe_eval(tstring) -- elif ttype not in (tokenize.COMMENT, tokenize.INDENT, tokenize.DEDENT, -- tokenize.NEWLINE, tokenize.NL): -- # We are inside an argument which is a translatable string and -- # we encountered a token that is not a string. This is an error. -- self.warn_unexpected_token(tstring) -- self.__enclosurecount = 0 -- self.__state = self.__waiting -- elif ttype == tokenize.OP: -- if tstring in '([{': -- self.__enclosurecount += 1 -- elif tstring in ')]}': -- self.__enclosurecount -= 1 -- -- def __ignorenext(self, ttype, tstring, lineno): -- self.__state = self.__waiting -- -- def __addentry(self, msg, lineno=None, *, is_docstring=False): -- msgid = msg.get('msgid') -- if msgid in self.__options.toexclude: -+ if max_index >= len(node.args): -+ print(f'*** {self.filename}:{node.lineno}: Expected at least ' -+ f'{max(spec) + 1} positional argument(s) in gettext call, ' -+ f'got {len(node.args)}', file=sys.stderr) - return -- if not is_docstring: -- spec = self.__options.keywords[self.__curr_keyword] -- if not matches_spec(msg, spec): -+ -+ msg_data = {} -+ for position, arg_type in spec.items(): -+ arg = node.args[position] -+ if not self._is_string_const(arg): -+ print(f'*** {self.filename}:{arg.lineno}: Expected a string ' -+ f'constant for argument {position + 1}, ' -+ f'got {ast.unparse(arg)}', file=sys.stderr) - return -- if lineno is None: -- lineno = self.__lineno -- msgctxt = msg.get('msgctxt') -- msgid_plural = msg.get('msgid_plural') -- key = key_for(msgid, msgctxt) -- if key in self.__messages: -- self.__messages[key].add_location( -- self.__curfile, -+ msg_data[arg_type] = arg.value -+ -+ lineno = node.lineno -+ self._add_message(lineno, **msg_data) -+ -+ def _add_message( -+ self, lineno, msgid, msgid_plural=None, msgctxt=None, *, -+ is_docstring=False): -+ if msgid in self.options.toexclude: -+ return -+ -+ key = self._key_for(msgid, msgctxt) -+ message = self.messages.get(key) -+ if message: -+ message.add_location( -+ self.filename, - lineno, - msgid_plural, - is_docstring=is_docstring, - ) - else: -- self.__messages[key] = Message( -+ self.messages[key] = Message( - msgid=msgid, - msgid_plural=msgid_plural, - msgctxt=msgctxt, -- locations={Location(self.__curfile, lineno)}, -+ locations={Location(self.filename, lineno)}, - is_docstring=is_docstring, - ) - -- def warn_unexpected_token(self, token): -- print(_( -- '*** %(file)s:%(lineno)s: Seen unexpected token "%(token)s"' -- ) % { -- 'token': token, -- 'file': self.__curfile, -- 'lineno': self.__lineno -- }, file=sys.stderr) -- -- def set_filename(self, filename): -- self.__curfile = filename -- self.__freshmodule = 1 -- -- def write(self, fp): -- options = self.__options -- timestamp = time.strftime('%Y-%m-%d %H:%M%z') -- encoding = fp.encoding if fp.encoding else 'UTF-8' -- print(pot_header % {'time': timestamp, 'version': __version__, -- 'charset': encoding, -- 'encoding': '8bit'}, file=fp) -- -- # Sort locations within each message by filename and lineno -- sorted_keys = [ -- (key, sorted(msg.locations)) -- for key, msg in self.__messages.items() -- ] -- # Sort messages by locations -- # For example, a message with locations [('test.py', 1), ('test.py', 2)] will -- # appear before a message with locations [('test.py', 1), ('test.py', 3)] -- sorted_keys.sort(key=itemgetter(1)) -- -- for key, locations in sorted_keys: -- msg = self.__messages[key] -- if options.writelocations: -- # location comments are different b/w Solaris and GNU: -- if options.locationstyle == options.SOLARIS: -- for location in locations: -- print(f'# File: {location.filename}, line: {location.lineno}', file=fp) -- elif options.locationstyle == options.GNU: -- # fit as many locations on one line, as long as the -- # resulting line length doesn't exceed 'options.width' -- locline = '#:' -- for location in locations: -- s = f' {location.filename}:{location.lineno}' -- if len(locline) + len(s) <= options.width: -- locline = locline + s -- else: -- print(locline, file=fp) -- locline = f'#:{s}' -- if len(locline) > 2: -+ @staticmethod -+ def _key_for(msgid, msgctxt=None): -+ if msgctxt is not None: -+ return (msgctxt, msgid) -+ return msgid -+ -+ def _get_func_name(self, node): -+ match node.func: -+ case ast.Name(id=id): -+ return id -+ case ast.Attribute(attr=attr): -+ return attr -+ case _: -+ return None -+ -+ def _is_string_const(self, node): -+ return isinstance(node, ast.Constant) and isinstance(node.value, str) -+ -+def write_pot_file(messages, options, fp): -+ timestamp = time.strftime('%Y-%m-%d %H:%M%z') -+ encoding = fp.encoding if fp.encoding else 'UTF-8' -+ print(pot_header % {'time': timestamp, 'version': __version__, -+ 'charset': encoding, -+ 'encoding': '8bit'}, file=fp) -+ -+ # Sort locations within each message by filename and lineno -+ sorted_keys = [ -+ (key, sorted(msg.locations)) -+ for key, msg in messages.items() -+ ] -+ # Sort messages by locations -+ # For example, a message with locations [('test.py', 1), ('test.py', 2)] will -+ # appear before a message with locations [('test.py', 1), ('test.py', 3)] -+ sorted_keys.sort(key=itemgetter(1)) -+ -+ for key, locations in sorted_keys: -+ msg = messages[key] -+ if options.writelocations: -+ # location comments are different b/w Solaris and GNU: -+ if options.locationstyle == options.SOLARIS: -+ for location in locations: -+ print(f'# File: {location.filename}, line: {location.lineno}', file=fp) -+ elif options.locationstyle == options.GNU: -+ # fit as many locations on one line, as long as the -+ # resulting line length doesn't exceed 'options.width' -+ locline = '#:' -+ for location in locations: -+ s = f' {location.filename}:{location.lineno}' -+ if len(locline) + len(s) <= options.width: -+ locline = locline + s -+ else: - print(locline, file=fp) -- if msg.is_docstring: -- # If the entry was gleaned out of a docstring, then add a -- # comment stating so. This is to aid translators who may wish -- # to skip translating some unimportant docstrings. -- print('#, docstring', file=fp) -- if msg.msgctxt is not None: -- print('msgctxt', normalize(msg.msgctxt, encoding), file=fp) -- print('msgid', normalize(msg.msgid, encoding), file=fp) -- if msg.msgid_plural is not None: -- print('msgid_plural', normalize(msg.msgid_plural, encoding), file=fp) -- print('msgstr[0] ""', file=fp) -- print('msgstr[1] ""\n', file=fp) -- else: -- print('msgstr ""\n', file=fp) -+ locline = f'#:{s}' -+ if len(locline) > 2: -+ print(locline, file=fp) -+ if msg.is_docstring: -+ # If the entry was gleaned out of a docstring, then add a -+ # comment stating so. This is to aid translators who may wish -+ # to skip translating some unimportant docstrings. -+ print('#, docstring', file=fp) -+ if msg.msgctxt is not None: -+ print('msgctxt', normalize(msg.msgctxt, encoding), file=fp) -+ print('msgid', normalize(msg.msgid, encoding), file=fp) -+ if msg.msgid_plural is not None: -+ print('msgid_plural', normalize(msg.msgid_plural, encoding), file=fp) -+ print('msgstr[0] ""', file=fp) -+ print('msgstr[1] ""\n', file=fp) -+ else: -+ print('msgstr ""\n', file=fp) - - - def main(): -@@ -677,7 +529,7 @@ - elif opt in ('-S', '--style'): - options.locationstyle = locations.get(arg.lower()) - if options.locationstyle is None: -- usage(1, _('Invalid value for --style: %s') % arg) -+ usage(1, f'Invalid value for --style: {arg}') - elif opt in ('-o', '--output'): - options.outfile = arg - elif opt in ('-p', '--output-dir'): -@@ -685,13 +537,13 @@ - elif opt in ('-v', '--verbose'): - options.verbose = 1 - elif opt in ('-V', '--version'): -- print(_('pygettext.py (xgettext for Python) %s') % __version__) -+ print(f'pygettext.py (xgettext for Python) {__version__}') - sys.exit(0) - elif opt in ('-w', '--width'): - try: - options.width = int(arg) - except ValueError: -- usage(1, _('--width argument must be an integer: %s') % arg) -+ usage(1, f'--width argument must be an integer: {arg}') - elif opt in ('-x', '--exclude-file'): - options.excludefilename = arg - elif opt in ('-X', '--no-docstrings'): -@@ -719,8 +571,8 @@ - with open(options.excludefilename) as fp: - options.toexclude = fp.readlines() - except IOError: -- print(_( -- "Can't read --exclude-file: %s") % options.excludefilename, file=sys.stderr) -+ print(f"Can't read --exclude-file: {options.excludefilename}", -+ file=sys.stderr) - sys.exit(1) - else: - options.toexclude = [] -@@ -735,31 +587,24 @@ - args = expanded - - # slurp through all the files -- eater = TokenEater(options) -+ visitor = GettextVisitor(options) - for filename in args: - if filename == '-': - if options.verbose: -- print(_('Reading standard input')) -- fp = sys.stdin.buffer -- closep = 0 -+ print('Reading standard input') -+ source = sys.stdin.buffer.read() - else: - if options.verbose: -- print(_('Working on %s') % filename) -- fp = open(filename, 'rb') -- closep = 1 -+ print(f'Working on {filename}') -+ with open(filename, 'rb') as fp: -+ source = fp.read() -+ - try: -- eater.set_filename(filename) -- try: -- tokens = tokenize.tokenize(fp.readline) -- for _token in tokens: -- eater(*_token) -- except tokenize.TokenError as e: -- print('%s: %s, line %d, column %d' % ( -- e.args[0], filename, e.args[1][0], e.args[1][1]), -- file=sys.stderr) -- finally: -- if closep: -- fp.close() -+ module_tree = ast.parse(source) -+ except SyntaxError: -+ continue -+ -+ visitor.visit_file(module_tree, filename) - - # write the output - if options.outfile == '-': -@@ -771,7 +616,7 @@ - fp = open(options.outfile, 'w') - closep = 1 - try: -- eater.write(fp) -+ write_pot_file(visitor.messages, options, fp) - finally: - if closep: - fp.close() -@@ -779,7 +624,3 @@ - - if __name__ == '__main__': - main() -- # some more test strings -- # this one creates a warning -- _('*** Seen unexpected token "%(token)s"') % {'token': 'test'} -- _('more' 'than' 'one' 'string') -diff --git a/Tools/jit/README.md b/Tools/jit/README.md -index 801c64e4059..4107265754f 100644 ---- a/Tools/jit/README.md -+++ b/Tools/jit/README.md -@@ -3,6 +3,8 @@ - - This version of CPython can be built with an experimental just-in-time compiler[^pep-744]. While most everything you already know about building and using CPython is unchanged, you will probably need to install a compatible version of LLVM first. - -+Python 3.11 or newer is required to build the JIT. -+ - ## Installing LLVM - - The JIT compiler does not require end users to install any third-party dependencies, but part of it must be *built* using LLVM[^why-llvm]. You are *not* required to build the rest of CPython using LLVM, or even the same version of LLVM (in fact, this is uncommon). -@@ -54,7 +56,7 @@ - - For all other builds, pass the new `--enable-experimental-jit` option to `configure`. - --Otherwise, just configure and build as you normally would. Cross-compiling "just works", since the JIT is built for the host platform. -+Otherwise, just configure and build as you normally would. Cross-compiling "just works", since the JIT is built for the host platform. - - The JIT can also be enabled or disabled using the `PYTHON_JIT` environment variable, even on builds where it is enabled or disabled by default. More details about configuring CPython with the JIT and optional values for `--enable-experimental-jit` can be found [here](https://docs.python.org/dev/whatsnew/3.13.html#experimental-jit-compiler). - -diff --git a/Tools/jit/jit.h b/Tools/jit/jit.h -index 47da64cb12b..f767ef68127 100644 ---- a/Tools/jit/jit.h -+++ b/Tools/jit/jit.h -@@ -2,3 +2,7 @@ - // pointer with __attribute__((preserve_none)), since this attribute may not be - // supported by the compiler used to build the rest of the interpreter. - typedef jit_func __attribute__((preserve_none)) jit_func_preserve_none; -+ -+#define PATCH_VALUE(TYPE, NAME, ALIAS) \ -+ PyAPI_DATA(void) ALIAS; \ -+ TYPE NAME = (TYPE)(uintptr_t)&ALIAS; -diff --git a/Tools/jit/shim.c b/Tools/jit/shim.c -index f0cffa2f049..ebd4e9bc858 100644 ---- a/Tools/jit/shim.c -+++ b/Tools/jit/shim.c -@@ -9,16 +9,7 @@ - _Py_CODEUNIT * - _JIT_ENTRY(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate) - { -- // This is subtle. The actual trace will return to us once it exits, so we -- // need to make sure that we stay alive until then. If our trace side-exits -- // into another trace, and this trace is then invalidated, the code for -- // *this function* will be freed and we'll crash upon return: -- PyAPI_DATA(void) _JIT_EXECUTOR; -- PyObject *executor = (PyObject *)(uintptr_t)&_JIT_EXECUTOR; -- Py_INCREF(executor); - // Note that this is *not* a tail call: -- PyAPI_DATA(void) _JIT_CONTINUE; -- _Py_CODEUNIT *target = ((jit_func_preserve_none)&_JIT_CONTINUE)(frame, stack_pointer, tstate); -- Py_SETREF(tstate->previous_executor, executor); -- return target; -+ PATCH_VALUE(jit_func_preserve_none, call, _JIT_CONTINUE); -+ return call(frame, stack_pointer, tstate); - } -diff --git a/Tools/jit/template.c b/Tools/jit/template.c -index 95c90bda70f..0b7d077d78c 100644 ---- a/Tools/jit/template.c -+++ b/Tools/jit/template.c -@@ -32,36 +32,22 @@ - #undef CURRENT_OPERAND1 - #define CURRENT_OPERAND1() (_operand1) - --#undef DEOPT_IF --#define DEOPT_IF(COND, INSTNAME) \ -- do { \ -- if ((COND)) { \ -- goto deoptimize; \ -- } \ -- } while (0) -- --#undef ENABLE_SPECIALIZATION --#define ENABLE_SPECIALIZATION (0) -- --#undef GOTO_ERROR --#define GOTO_ERROR(LABEL) \ -- do { \ -- goto LABEL ## _tier_two; \ -- } while (0) -+#undef CURRENT_TARGET -+#define CURRENT_TARGET() (_target) - - #undef GOTO_TIER_TWO --#define GOTO_TIER_TWO(EXECUTOR) \ --do { \ -- OPT_STAT_INC(traces_executed); \ -- __attribute__((musttail)) \ -- return ((jit_func_preserve_none)((EXECUTOR)->jit_side_entry))(frame, stack_pointer, tstate); \ -+#define GOTO_TIER_TWO(EXECUTOR) \ -+do { \ -+ OPT_STAT_INC(traces_executed); \ -+ jit_func_preserve_none jitted = (EXECUTOR)->jit_side_entry; \ -+ __attribute__((musttail)) return jitted(frame, stack_pointer, tstate); \ - } while (0) - - #undef GOTO_TIER_ONE --#define GOTO_TIER_ONE(TARGET) \ --do { \ -+#define GOTO_TIER_ONE(TARGET) \ -+do { \ - _PyFrame_SetStackPointer(frame, stack_pointer); \ -- return TARGET; \ -+ return TARGET; \ - } while (0) - - #undef LOAD_IP -@@ -69,15 +55,15 @@ - do { \ - } while (0) - --#define PATCH_VALUE(TYPE, NAME, ALIAS) \ -- PyAPI_DATA(void) ALIAS; \ -- TYPE NAME = (TYPE)(uintptr_t)&ALIAS; -+#undef LLTRACE_RESUME_FRAME -+#define LLTRACE_RESUME_FRAME() \ -+ do { \ -+ } while (0) - --#define PATCH_JUMP(ALIAS) \ --do { \ -- PyAPI_DATA(void) ALIAS; \ -- __attribute__((musttail)) \ -- return ((jit_func_preserve_none)&ALIAS)(frame, stack_pointer, tstate); \ -+#define PATCH_JUMP(ALIAS) \ -+do { \ -+ PATCH_VALUE(jit_func_preserve_none, jump, ALIAS); \ -+ __attribute__((musttail)) return jump(frame, stack_pointer, tstate); \ - } while (0) - - #undef JUMP_TO_JUMP_TARGET -@@ -86,9 +72,6 @@ - #undef JUMP_TO_ERROR - #define JUMP_TO_ERROR() PATCH_JUMP(_JIT_ERROR_TARGET) - --#undef WITHIN_STACK_BOUNDS --#define WITHIN_STACK_BOUNDS() 1 -- - #define TIER_TWO 2 - - __attribute__((preserve_none)) _Py_CODEUNIT * -@@ -109,16 +92,13 @@ - PATCH_VALUE(uint32_t, _operand0_hi, _JIT_OPERAND0_HI) - PATCH_VALUE(uint32_t, _operand0_lo, _JIT_OPERAND0_LO) - uint64_t _operand0 = ((uint64_t)_operand0_hi << 32) | _operand0_lo; -- - PATCH_VALUE(uint32_t, _operand1_hi, _JIT_OPERAND1_HI) - PATCH_VALUE(uint32_t, _operand1_lo, _JIT_OPERAND1_LO) - uint64_t _operand1 = ((uint64_t)_operand1_hi << 32) | _operand1_lo; - #endif - PATCH_VALUE(uint32_t, _target, _JIT_TARGET) -- - OPT_STAT_INC(uops_executed); - UOP_STAT_INC(uopcode, execution_count); -- - switch (uopcode) { - // The actual instruction definition gets inserted here: - CASE -@@ -126,15 +106,4 @@ - Py_UNREACHABLE(); - } - PATCH_JUMP(_JIT_CONTINUE); -- // Labels that the instruction implementations expect to exist: -- --error_tier_two: -- tstate->previous_executor = (PyObject *)current_executor; -- GOTO_TIER_ONE(NULL); --exit_to_tier1: -- tstate->previous_executor = (PyObject *)current_executor; -- GOTO_TIER_ONE(_PyCode_CODE(_PyFrame_GetCode(frame)) + _target); --exit_to_tier1_dynamic: -- tstate->previous_executor = (PyObject *)current_executor; -- GOTO_TIER_ONE(frame->instr_ptr); - } -diff --git a/Tools/scripts/summarize_stats.py b/Tools/scripts/summarize_stats.py -index bc7ccfe33e7..4243b53850b 100644 ---- a/Tools/scripts/summarize_stats.py -+++ b/Tools/scripts/summarize_stats.py -@@ -457,6 +457,7 @@ - inner_loop = self._data["Optimization inner loop"] - recursive_call = self._data["Optimization recursive call"] - low_confidence = self._data["Optimization low confidence"] -+ unknown_callee = self._data["Optimization unknown callee"] - executors_invalidated = self._data["Executors invalidated"] - - return { -@@ -497,6 +498,10 @@ - "A trace is abandoned because the likelihood of the jump to top being taken " - "is too low.", - ): (low_confidence, attempts), -+ Doc( -+ "Unknown callee", -+ "A trace is abandoned because the target of a call is unknown.", -+ ): (unknown_callee, attempts), - Doc( - "Executors invalidated", - "The number of executors that were invalidated due to watched " -@@ -545,6 +550,41 @@ - ): (incorrect_keys, attempts), - } - -+ def get_jit_memory_stats(self) -> dict[Doc, tuple[int, int | None]]: -+ jit_total_memory_size = self._data["JIT total memory size"] -+ jit_code_size = self._data["JIT code size"] -+ jit_trampoline_size = self._data["JIT trampoline size"] -+ jit_data_size = self._data["JIT data size"] -+ jit_padding_size = self._data["JIT padding size"] -+ jit_freed_memory_size = self._data["JIT freed memory size"] -+ -+ return { -+ Doc( -+ "Total memory size", -+ "The total size of the memory allocated for the JIT traces", -+ ): (jit_total_memory_size, None), -+ Doc( -+ "Code size", -+ "The size of the memory allocated for the code of the JIT traces", -+ ): (jit_code_size, jit_total_memory_size), -+ Doc( -+ "Trampoline size", -+ "The size of the memory allocated for the trampolines of the JIT traces", -+ ): (jit_trampoline_size, jit_total_memory_size), -+ Doc( -+ "Data size", -+ "The size of the memory allocated for the data of the JIT traces", -+ ): (jit_data_size, jit_total_memory_size), -+ Doc( -+ "Padding size", -+ "The size of the memory allocated for the padding of the JIT traces", -+ ): (jit_padding_size, jit_total_memory_size), -+ Doc( -+ "Freed memory size", -+ "The size of the memory freed from the JIT traces", -+ ): (jit_freed_memory_size, jit_total_memory_size), -+ } -+ - def get_histogram(self, prefix: str) -> list[tuple[int, int]]: - rows = [] - for k, v in self._data.items(): -@@ -1161,16 +1201,31 @@ - for label, (value, den) in optimizer_stats.items() - ] - -- def calc_histogram_table(key: str, den: str) -> RowCalculator: -+ def calc_jit_memory_table(stats: Stats) -> Rows: -+ jit_memory_stats = stats.get_jit_memory_stats() -+ -+ return [ -+ ( -+ label, -+ Count(value), -+ Ratio(value, den, percentage=label != "Total memory size"), -+ ) -+ for label, (value, den) in jit_memory_stats.items() -+ ] -+ -+ def calc_histogram_table(key: str, den: str | None = None) -> RowCalculator: - def calc(stats: Stats) -> Rows: - histogram = stats.get_histogram(key) -- denominator = stats.get(den) -+ -+ if den: -+ denominator = stats.get(den) -+ else: -+ denominator = 0 -+ for _, v in histogram: -+ denominator += v - - rows: Rows = [] -- last_non_zero = 0 - for k, v in histogram: -- if v != 0: -- last_non_zero = len(rows) - rows.append( - ( - f"<= {k:,d}", -@@ -1178,9 +1233,19 @@ - Ratio(v, denominator), - ) - ) -- # Don't include any zero entries at the end -- rows = rows[: last_non_zero + 1] -- return rows -+ # Don't include any leading and trailing zero entries -+ start = 0 -+ end = len(rows) - 1 -+ -+ while start <= end: -+ if rows[start][1] == 0: -+ start += 1 -+ elif rows[end][1] == 0: -+ end -= 1 -+ else: -+ break -+ -+ return rows[start:end+1] - - return calc - -@@ -1214,6 +1279,28 @@ - - yield Table(("", "Count:", "Ratio:"), calc_optimization_table, JoinMode.CHANGE) - yield Table(("", "Count:", "Ratio:"), calc_optimizer_table, JoinMode.CHANGE) -+ yield Section( -+ "JIT memory stats", -+ "JIT memory stats", -+ [ -+ Table( -+ ("", "Size (bytes):", "Ratio:"), -+ calc_jit_memory_table, -+ JoinMode.CHANGE -+ ) -+ ], -+ ) -+ yield Section( -+ "JIT trace total memory histogram", -+ "JIT trace total memory histogram", -+ [ -+ Table( -+ ("Size (bytes)", "Count", "Ratio:"), -+ calc_histogram_table("Trace total memory size"), -+ JoinMode.CHANGE_NO_SORT, -+ ) -+ ], -+ ) - for name, den in [ - ("Trace length", "Optimization traces created"), - ("Optimized trace length", "Optimization traces created"), -diff --git a/Tools/tsan/suppressions_free_threading.txt b/Tools/tsan/suppressions_free_threading.txt -index e5eb665ae21..c2509cae7b9 100644 ---- a/Tools/tsan/suppressions_free_threading.txt -+++ b/Tools/tsan/suppressions_free_threading.txt -@@ -22,7 +22,6 @@ - # These warnings trigger directly in a CPython function. - - race_top:assign_version_tag --race_top:new_reference - race_top:_multiprocessing_SemLock_acquire_impl - race_top:list_get_item_ref - race_top:_Py_slot_tp_getattr_hook -@@ -44,5 +43,11 @@ - # Only seen on macOS, sample: https://gist.github.com/aisk/dda53f5d494a4556c35dde1fce03259c - race_top:set_default_allocator_unlocked - -+# gh-129068: race on shared range iterators (test_free_threading.test_zip.ZipThreading.test_threading) -+race_top:rangeiter_next -+ -+# gh-129748: test.test_free_threading.test_slots.TestSlots.test_object -+race_top:mi_block_set_nextx -+ - # https://gist.github.com/mpage/6962e8870606cfc960e159b407a0cb40 - thread:pthread_create -diff --git a/Tools/wasm/emscripten/web_example/python.worker.mjs b/Tools/wasm/emscripten/web_example/python.worker.mjs -index 8043e419966..5f9012a492a 100644 ---- a/Tools/wasm/emscripten/web_example/python.worker.mjs -+++ b/Tools/wasm/emscripten/web_example/python.worker.mjs -@@ -70,12 +70,9 @@ - postMessage({ type: "ready", stdinBuffer: stdinBuffer.sab }); - }, - async preRun(Module) { -- const versionHex = Module.HEAPU32[Module._Py_Version / 4].toString(16); -- const versionTuple = versionHex -- .padStart(8, "0") -- .match(/.{1,2}/g) -- .map((x) => parseInt(x, 16)); -- const [major, minor, ..._] = versionTuple; -+ const versionInt = Module.HEAPU32[Module._Py_Version >>> 2]; -+ const major = (versionInt >>> 24) & 0xff; -+ const minor = (versionInt >>> 16) & 0xff; - // Prevent complaints about not finding exec-prefix by making a lib-dynload directory - Module.FS.mkdirTree(`/lib/python${major}.${minor}/lib-dynload/`); - Module.addRunDependency("install-stdlib"); -diff --git a/config.guess b/config.guess -index e81d3ae7c21..cdfc4392047 100755 ---- a/config.guess -+++ b/config.guess -@@ -1,14 +1,14 @@ - #! /bin/sh - # Attempt to guess a canonical system name. --# Copyright 1992-2021 Free Software Foundation, Inc. -+# Copyright 1992-2023 Free Software Foundation, Inc. - - # shellcheck disable=SC2006,SC2268 # see below for rationale - --timestamp='2021-06-03' -+timestamp='2023-08-22' - - # This file is free software; you can redistribute it and/or modify it - # under the terms of the GNU General Public License as published by --# the Free Software Foundation; either version 3 of the License, or -+# the Free Software Foundation, either version 3 of the License, or - # (at your option) any later version. - # - # This program is distributed in the hope that it will be useful, but -@@ -47,7 +47,7 @@ - usage="\ - Usage: $0 [OPTION] - --Output the configuration name of the system \`$me' is run on. -+Output the configuration name of the system '$me' is run on. - - Options: - -h, --help print this help, then exit -@@ -60,13 +60,13 @@ - GNU config.guess ($timestamp) - - Originally written by Per Bothner. --Copyright 1992-2021 Free Software Foundation, Inc. -+Copyright 1992-2023 Free Software Foundation, Inc. - - This is free software; see the source for copying conditions. There is NO - warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." - - help=" --Try \`$me --help' for more information." -+Try '$me --help' for more information." - - # Parse command line - while test $# -gt 0 ; do -@@ -102,8 +102,8 @@ - # temporary files to be created and, as you can see below, it is a - # headache to deal with in a portable fashion. - --# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still --# use `HOST_CC' if defined, but it is deprecated. -+# Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still -+# use 'HOST_CC' if defined, but it is deprecated. - - # Portable tmp directory creation inspired by the Autoconf team. - -@@ -155,6 +155,9 @@ - - set_cc_for_build - cat <<-EOF > "$dummy.c" -+ #if defined(__ANDROID__) -+ LIBC=android -+ #else - #include - #if defined(__UCLIBC__) - LIBC=uclibc -@@ -169,6 +172,7 @@ - LIBC=musl - #endif - #endif -+ #endif - EOF - cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` - eval "$cc_set_libc" -@@ -437,7 +441,7 @@ - # This test works for both compilers. - if test "$CC_FOR_BUILD" != no_compiler_found; then - if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ -- (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ -+ (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ - grep IS_64BIT_ARCH >/dev/null - then - SUN_ARCH=x86_64 -@@ -459,7 +463,7 @@ - UNAME_RELEASE=`uname -v` - ;; - esac -- # Japanese Language versions have a version number like `4.1.3-JL'. -+ # Japanese Language versions have a version number like '4.1.3-JL'. - SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` - GUESS=sparc-sun-sunos$SUN_REL - ;; -@@ -904,7 +908,7 @@ - fi - ;; - *:FreeBSD:*:*) -- UNAME_PROCESSOR=`/usr/bin/uname -p` -+ UNAME_PROCESSOR=`uname -p` - case $UNAME_PROCESSOR in - amd64) - UNAME_PROCESSOR=x86_64 ;; -@@ -929,6 +933,9 @@ - i*:PW*:*) - GUESS=$UNAME_MACHINE-pc-pw32 - ;; -+ *:SerenityOS:*:*) -+ GUESS=$UNAME_MACHINE-pc-serenity -+ ;; - *:Interix*:*) - case $UNAME_MACHINE in - x86) -@@ -963,11 +970,37 @@ - GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` - GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC - ;; -+ x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*) -+ GUESS="$UNAME_MACHINE-pc-managarm-mlibc" -+ ;; -+ *:[Mm]anagarm:*:*) -+ GUESS="$UNAME_MACHINE-unknown-managarm-mlibc" -+ ;; - *:Minix:*:*) - GUESS=$UNAME_MACHINE-unknown-minix - ;; - aarch64:Linux:*:*) -- GUESS=$UNAME_MACHINE-unknown-linux-$LIBC -+ set_cc_for_build -+ CPU=$UNAME_MACHINE -+ LIBCABI=$LIBC -+ if test "$CC_FOR_BUILD" != no_compiler_found; then -+ ABI=64 -+ sed 's/^ //' << EOF > "$dummy.c" -+ #ifdef __ARM_EABI__ -+ #ifdef __ARM_PCS_VFP -+ ABI=eabihf -+ #else -+ ABI=eabi -+ #endif -+ #endif -+EOF -+ cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` -+ eval "$cc_set_abi" -+ case $ABI in -+ eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;; -+ esac -+ fi -+ GUESS=$CPU-unknown-linux-$LIBCABI - ;; - aarch64_be:Linux:*:*) - UNAME_MACHINE=aarch64_be -@@ -1033,7 +1066,16 @@ - k1om:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; -- loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*) -+ kvx:Linux:*:*) -+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC -+ ;; -+ kvx:cos:*:*) -+ GUESS=$UNAME_MACHINE-unknown-cos -+ ;; -+ kvx:mbr:*:*) -+ GUESS=$UNAME_MACHINE-unknown-mbr -+ ;; -+ loongarch32:Linux:*:* | loongarch64:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC - ;; - m32r*:Linux:*:*) -@@ -1148,16 +1190,27 @@ - ;; - x86_64:Linux:*:*) - set_cc_for_build -+ CPU=$UNAME_MACHINE - LIBCABI=$LIBC - if test "$CC_FOR_BUILD" != no_compiler_found; then -- if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \ -- (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ -- grep IS_X32 >/dev/null -- then -- LIBCABI=${LIBC}x32 -- fi -+ ABI=64 -+ sed 's/^ //' << EOF > "$dummy.c" -+ #ifdef __i386__ -+ ABI=x86 -+ #else -+ #ifdef __ILP32__ -+ ABI=x32 -+ #endif -+ #endif -+EOF -+ cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` -+ eval "$cc_set_abi" -+ case $ABI in -+ x86) CPU=i686 ;; -+ x32) LIBCABI=${LIBC}x32 ;; -+ esac - fi -- GUESS=$UNAME_MACHINE-pc-linux-$LIBCABI -+ GUESS=$CPU-pc-linux-$LIBCABI - ;; - xtensa*:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC -@@ -1177,7 +1230,7 @@ - GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION - ;; - i*86:OS/2:*:*) -- # If we were able to find `uname', then EMX Unix compatibility -+ # If we were able to find 'uname', then EMX Unix compatibility - # is probably installed. - GUESS=$UNAME_MACHINE-pc-os2-emx - ;; -@@ -1318,7 +1371,7 @@ - GUESS=ns32k-sni-sysv - fi - ;; -- PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort -+ PENTIUM:*:4.0*:*) # Unisys 'ClearPath HMP IX 4000' SVR4/MP effort - # says - GUESS=i586-unisys-sysv4 - ;; -@@ -1364,8 +1417,11 @@ - BePC:Haiku:*:*) # Haiku running on Intel PC compatible. - GUESS=i586-pc-haiku - ;; -- x86_64:Haiku:*:*) -- GUESS=x86_64-unknown-haiku -+ ppc:Haiku:*:*) # Haiku running on Apple PowerPC -+ GUESS=powerpc-apple-haiku -+ ;; -+ *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat) -+ GUESS=$UNAME_MACHINE-unknown-haiku - ;; - SX-4:SUPER-UX:*:*) - GUESS=sx4-nec-superux$UNAME_RELEASE -@@ -1522,6 +1578,9 @@ - i*86:rdos:*:*) - GUESS=$UNAME_MACHINE-pc-rdos - ;; -+ i*86:Fiwix:*:*) -+ GUESS=$UNAME_MACHINE-pc-fiwix -+ ;; - *:AROS:*:*) - GUESS=$UNAME_MACHINE-unknown-aros - ;; -diff --git a/config.sub b/config.sub -index 1bb6a05dc11..7e007ac54c3 100755 ---- a/config.sub -+++ b/config.sub -@@ -1769,7 +1769,7 @@ - | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ - | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \ - | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr* \ -- | fiwix* | mlibc* | cos* | mbr* | ironclad* ) -+ | fiwix* | mlibc* | cos* | mbr* | ironclad* | macabi) - ;; - # This one is extra strict with allowed versions - sco3.2v2 | sco3.2v[4-9]* | sco5v6*) -@@ -1869,6 +1869,8 @@ - ;; - ios*-simulator- | tvos*-simulator- | watchos*-simulator- ) - ;; -+ ios*-macabi- ) -+ ;; - none--*) - # None (no kernel, i.e. freestanding / bare metal), - # can be paired with an machine code file format -diff --git a/configure b/configure -index 57be576e3ca..0a11bb50856 100755 ---- a/configure -+++ b/configure -@@ -1,11 +1,11 @@ - #! /bin/sh - # Guess values for system-dependent variables and create Makefiles. --# Generated by GNU Autoconf 2.71 for python 3.14. -+# Generated by GNU Autoconf 2.72 for python 3.14. - # - # Report bugs to . - # - # --# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, -+# Copyright (C) 1992-1996, 1998-2017, 2020-2023 Free Software Foundation, - # Inc. - # - # -@@ -17,7 +17,6 @@ - - # Be more Bourne compatible - DUALCASE=1; export DUALCASE # for MKS sh --as_nop=: - if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 - then : - emulate sh -@@ -26,12 +25,13 @@ - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST --else $as_nop -- case `(set -o) 2>/dev/null` in #( -+else case e in #( -+ e) case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -+esac ;; - esac - fi - -@@ -103,7 +103,7 @@ - - ;; - esac --# We did not find ourselves, most probably we were run as `sh COMMAND' -+# We did not find ourselves, most probably we were run as 'sh COMMAND' - # in which case we are not to be found in the path. - if test "x$as_myself" = x; then - as_myself=$0 -@@ -133,15 +133,14 @@ - esac - exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} - # Admittedly, this is quite paranoid, since all the known shells bail --# out after a failed `exec'. -+# out after a failed 'exec'. - printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 - exit 255 - fi - # We don't want this to propagate to other subprocesses. - { _as_can_reexec=; unset _as_can_reexec;} - if test "x$CONFIG_SHELL" = x; then -- as_bourne_compatible="as_nop=: --if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 -+ as_bourne_compatible="if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 - then : - emulate sh - NULLCMD=: -@@ -149,12 +148,13 @@ - # is contrary to our usage. Disable this feature. - alias -g '\${1+\"\$@\"}'='\"\$@\"' - setopt NO_GLOB_SUBST --else \$as_nop -- case \`(set -o) 2>/dev/null\` in #( -+else case e in #( -+ e) case \`(set -o) 2>/dev/null\` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -+esac ;; - esac - fi - " -@@ -172,8 +172,9 @@ - if ( set x; as_fn_ret_success y && test x = \"\$1\" ) - then : - --else \$as_nop -- exitcode=1; echo positional parameters were not saved. -+else case e in #( -+ e) exitcode=1; echo positional parameters were not saved. ;; -+esac - fi - test x\$exitcode = x0 || exit 1 - blah=\$(echo \$(echo blah)) -@@ -187,14 +188,15 @@ - if (eval "$as_required") 2>/dev/null - then : - as_have_required=yes --else $as_nop -- as_have_required=no -+else case e in #( -+ e) as_have_required=no ;; -+esac - fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null - then : - --else $as_nop -- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -+else case e in #( -+ e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR - as_found=false - for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH - do -@@ -227,12 +229,13 @@ - if $as_found - then : - --else $as_nop -- if { test -f "$SHELL" || test -f "$SHELL.exe"; } && -+else case e in #( -+ e) if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null - then : - CONFIG_SHELL=$SHELL as_have_required=yes --fi -+fi ;; -+esac - fi - - -@@ -254,7 +257,7 @@ - esac - exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} - # Admittedly, this is quite paranoid, since all the known shells bail --# out after a failed `exec'. -+# out after a failed 'exec'. - printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 - exit 255 - fi -@@ -274,7 +277,8 @@ - $0: the script under such a shell if you do have one." - fi - exit 1 --fi -+fi ;; -+esac - fi - fi - SHELL=${CONFIG_SHELL-/bin/sh} -@@ -313,14 +317,6 @@ - as_fn_set_status $1 - exit $1 - } # as_fn_exit --# as_fn_nop --# --------- --# Do nothing but, unlike ":", preserve the value of $?. --as_fn_nop () --{ -- return $? --} --as_nop=as_fn_nop - - # as_fn_mkdir_p - # ------------- -@@ -389,11 +385,12 @@ - { - eval $1+=\$2 - }' --else $as_nop -- as_fn_append () -+else case e in #( -+ e) as_fn_append () - { - eval $1=\$$1\$2 -- } -+ } ;; -+esac - fi # as_fn_append - - # as_fn_arith ARG... -@@ -407,21 +404,14 @@ - { - as_val=$(( $* )) - }' --else $as_nop -- as_fn_arith () -+else case e in #( -+ e) as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` -- } -+ } ;; -+esac - fi # as_fn_arith - --# as_fn_nop --# --------- --# Do nothing but, unlike ":", preserve the value of $?. --as_fn_nop () --{ -- return $? --} --as_nop=as_fn_nop - - # as_fn_error STATUS ERROR [LINENO LOG_FD] - # ---------------------------------------- -@@ -495,6 +485,8 @@ - /[$]LINENO/= - ' <$as_myself | - sed ' -+ t clear -+ :clear - s/[$]LINENO.*/&-/ - t lineno - b -@@ -543,7 +535,6 @@ - as_echo='printf %s\n' - as_echo_n='printf %s' - -- - rm -f conf$$ conf$$.exe conf$$.file - if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -@@ -555,9 +546,9 @@ - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: -- # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. -- # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. -- # In both cases, we have to default to `cp -pR'. -+ # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. -+ # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. -+ # In both cases, we have to default to 'cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then -@@ -582,10 +573,12 @@ - as_executable_p=as_fn_executable_p - - # Sed expression to map a string onto a valid CPP name. --as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" -+as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" -+as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated - - # Sed expression to map a string onto a valid variable name. --as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" -+as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" -+as_tr_sh="eval sed '$as_sed_sh'" # deprecated - - - test -n "$DJDIR" || exec 7<&0 /dev/null && -- as_fn_error $? "invalid feature name: \`$ac_useropt'" -+ as_fn_error $? "invalid feature name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in -@@ -1313,7 +1309,7 @@ - ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && -- as_fn_error $? "invalid feature name: \`$ac_useropt'" -+ as_fn_error $? "invalid feature name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in -@@ -1526,7 +1522,7 @@ - ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && -- as_fn_error $? "invalid package name: \`$ac_useropt'" -+ as_fn_error $? "invalid package name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in -@@ -1542,7 +1538,7 @@ - ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && -- as_fn_error $? "invalid package name: \`$ac_useropt'" -+ as_fn_error $? "invalid package name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in -@@ -1572,8 +1568,8 @@ - | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) - x_libraries=$ac_optarg ;; - -- -*) as_fn_error $? "unrecognized option: \`$ac_option' --Try \`$0 --help' for more information" -+ -*) as_fn_error $? "unrecognized option: '$ac_option' -+Try '$0 --help' for more information" - ;; - - *=*) -@@ -1581,7 +1577,7 @@ - # Reject names that are not valid shell variable names. - case $ac_envvar in #( - '' | [0-9]* | *[!_$as_cr_alnum]* ) -- as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; -+ as_fn_error $? "invalid variable name: '$ac_envvar'" ;; - esac - eval $ac_envvar=\$ac_optarg - export $ac_envvar ;; -@@ -1631,7 +1627,7 @@ - as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" - done - --# There might be people who depend on the old broken behavior: `$host' -+# There might be people who depend on the old broken behavior: '$host' - # used to hold the argument of --host etc. - # FIXME: To remove some day. - build=$build_alias -@@ -1699,7 +1695,7 @@ - test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" - fi --ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" -+ac_msg="sources are in $srcdir, but 'cd $srcdir' does not work" - ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" - pwd)` -@@ -1727,7 +1723,7 @@ - # Omit some internal or obsolete options to make the list less imposing. - # This message is too long to be a string in the A/UX 3.1 sh. - cat <<_ACEOF --\`configure' configures python 3.14 to adapt to many kinds of systems. -+'configure' configures python 3.14 to adapt to many kinds of systems. - - Usage: $0 [OPTION]... [VAR=VALUE]... - -@@ -1741,11 +1737,11 @@ - --help=short display options specific to this package - --help=recursive display the short help of all the included packages - -V, --version display version information and exit -- -q, --quiet, --silent do not print \`checking ...' messages -+ -q, --quiet, --silent do not print 'checking ...' messages - --cache-file=FILE cache test results in FILE [disabled] -- -C, --config-cache alias for \`--cache-file=config.cache' -+ -C, --config-cache alias for '--cache-file=config.cache' - -n, --no-create do not create output files -- --srcdir=DIR find the sources in DIR [configure dir or \`..'] -+ --srcdir=DIR find the sources in DIR [configure dir or '..'] - - Installation directories: - --prefix=PREFIX install architecture-independent files in PREFIX -@@ -1753,10 +1749,10 @@ - --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - [PREFIX] - --By default, \`make install' will install all the files in --\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify --an installation prefix other than \`$ac_default_prefix' using \`--prefix', --for instance \`--prefix=\$HOME'. -+By default, 'make install' will install all the files in -+'$ac_default_prefix/bin', '$ac_default_prefix/lib' etc. You can specify -+an installation prefix other than '$ac_default_prefix' using '--prefix', -+for instance '--prefix=\$HOME'. - - For better control, use the options below. - -@@ -1934,6 +1930,8 @@ - use libedit for backend or disable readline module - --with-computed-gotos enable computed gotos in evaluation loop (enabled by - default on supported compilers) -+ --with-tail-call-interp enable tail-calling interpreter in evaluation loop -+ and rest of CPython - --with-ensurepip[=install|upgrade|no] - "install" or "upgrade" using bundled pip (default is - upgrade) -@@ -2020,7 +2018,7 @@ - C compiler flags for PANEL, overriding pkg-config - PANEL_LIBS linker flags for PANEL, overriding pkg-config - --Use these variables to override the choices made by `configure' or to help -+Use these variables to override the choices made by 'configure' or to help - it to find libraries and programs with nonstandard names/locations. - - Report bugs to . -@@ -2088,9 +2086,9 @@ - if $ac_init_version; then - cat <<\_ACEOF - python configure 3.14 --generated by GNU Autoconf 2.71 -+generated by GNU Autoconf 2.72 - --Copyright (C) 2021 Free Software Foundation, Inc. -+Copyright (C) 2023 Free Software Foundation, Inc. - This configure script is free software; the Free Software Foundation - gives unlimited permission to copy, distribute and modify it. - _ACEOF -@@ -2129,11 +2127,12 @@ - } && test -s conftest.$ac_objext - then : - ac_retval=0 --else $as_nop -- printf "%s\n" "$as_me: failed program was:" >&5 -+else case e in #( -+ e) printf "%s\n" "$as_me: failed program was:" >&5 - sed 's/^/| /' conftest.$ac_ext >&5 - -- ac_retval=1 -+ ac_retval=1 ;; -+esac - fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval -@@ -2167,11 +2166,12 @@ - } - then : - ac_retval=0 --else $as_nop -- printf "%s\n" "$as_me: failed program was:" >&5 -+else case e in #( -+ e) printf "%s\n" "$as_me: failed program was:" >&5 - sed 's/^/| /' conftest.$ac_ext >&5 - -- ac_retval=1 -+ ac_retval=1 ;; -+esac - fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval -@@ -2190,8 +2190,8 @@ - if eval test \${$3+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - $4 - #include <$2> -@@ -2199,10 +2199,12 @@ - if ac_fn_c_try_compile "$LINENO" - then : - eval "$3=yes" --else $as_nop -- eval "$3=no" -+else case e in #( -+ e) eval "$3=no" ;; -+esac - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - eval ac_res=\$$3 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -@@ -2242,11 +2244,12 @@ - } - then : - ac_retval=0 --else $as_nop -- printf "%s\n" "$as_me: failed program was:" >&5 -+else case e in #( -+ e) printf "%s\n" "$as_me: failed program was:" >&5 - sed 's/^/| /' conftest.$ac_ext >&5 - -- ac_retval=1 -+ ac_retval=1 ;; -+esac - fi - # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information - # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would -@@ -2288,12 +2291,13 @@ - test $ac_status = 0; }; } - then : - ac_retval=0 --else $as_nop -- printf "%s\n" "$as_me: program exited with status $ac_status" >&5 -+else case e in #( -+ e) printf "%s\n" "$as_me: program exited with status $ac_status" >&5 - printf "%s\n" "$as_me: failed program was:" >&5 - sed 's/^/| /' conftest.$ac_ext >&5 - -- ac_retval=$ac_status -+ ac_retval=$ac_status ;; -+esac - fi - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno -@@ -2313,8 +2317,8 @@ - if eval test \${$3+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- eval "$3=no" -+else case e in #( -+ e) eval "$3=no" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - $4 -@@ -2344,12 +2348,14 @@ - if ac_fn_c_try_compile "$LINENO" - then : - --else $as_nop -- eval "$3=yes" -+else case e in #( -+ e) eval "$3=yes" ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - eval ac_res=\$$3 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -@@ -2403,18 +2409,19 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_hi=$ac_mid; break --else $as_nop -- as_fn_arith $ac_mid + 1 && ac_lo=$as_val -+else case e in #( -+ e) as_fn_arith $ac_mid + 1 && ac_lo=$as_val - if test $ac_lo -le $ac_mid; then - ac_lo= ac_hi= - break - fi -- as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val -+ as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - done --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - $4 - int -@@ -2449,20 +2456,23 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_lo=$ac_mid; break --else $as_nop -- as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val -+else case e in #( -+ e) as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val - if test $ac_mid -le $ac_hi; then - ac_lo= ac_hi= - break - fi -- as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val -+ as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - done --else $as_nop -- ac_lo= ac_hi= -+else case e in #( -+ e) ac_lo= ac_hi= ;; -+esac - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - # Binary search between lo and hi bounds. -@@ -2485,8 +2495,9 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_hi=$ac_mid --else $as_nop -- as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val -+else case e in #( -+ e) as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - done -@@ -2534,8 +2545,9 @@ - if ac_fn_c_try_run "$LINENO" - then : - echo >>conftest.val; read $3 &6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - /* Define $2 to an innocuous variant, in case declares $2. - For example, HP-UX 11i declares gettimeofday. */ - #define $2 innocuous_$2 - - /* System header to define __stub macros and hopefully few prototypes, -- which can conflict with char $2 (); below. */ -+ which can conflict with char $2 (void); below. */ - - #include - #undef $2 -@@ -2577,7 +2589,7 @@ - #ifdef __cplusplus - extern "C" - #endif --char $2 (); -+char $2 (void); - /* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -@@ -2596,11 +2608,13 @@ - if ac_fn_c_try_link "$LINENO" - then : - eval "$3=yes" --else $as_nop -- eval "$3=no" -+else case e in #( -+ e) eval "$3=no" ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ -- conftest$ac_exeext conftest.$ac_ext -+ conftest$ac_exeext conftest.$ac_ext ;; -+esac - fi - eval ac_res=\$$3 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -@@ -2622,8 +2636,8 @@ - if eval test \${$3+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` -+else case e in #( -+ e) as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` - eval ac_save_FLAGS=\$$6 - as_fn_append $6 " $5" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -2647,12 +2661,14 @@ - if ac_fn_c_try_compile "$LINENO" - then : - eval "$3=yes" --else $as_nop -- eval "$3=no" -+else case e in #( -+ e) eval "$3=no" ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - eval $6=\$ac_save_FLAGS -- -+ ;; -+esac - fi - eval ac_res=\$$3 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -@@ -2673,8 +2689,8 @@ - if eval test \${$4+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - $5 - int -@@ -2690,8 +2706,8 @@ - if ac_fn_c_try_compile "$LINENO" - then : - eval "$4=yes" --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - $5 - int -@@ -2707,12 +2723,15 @@ - if ac_fn_c_try_compile "$LINENO" - then : - eval "$4=yes" --else $as_nop -- eval "$4=no" -+else case e in #( -+ e) eval "$4=no" ;; -+esac - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - eval ac_res=\$$4 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -@@ -2745,7 +2764,7 @@ - running configure, to aid debugging if configure makes a mistake. - - It was created by python $as_me 3.14, which was --generated by GNU Autoconf 2.71. Invocation command line was -+generated by GNU Autoconf 2.72. Invocation command line was - - $ $0$ac_configure_args_raw - -@@ -2991,10 +3010,10 @@ - printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} - sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" \ -- || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+ || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error $? "failed to load site script $ac_site_file --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } - fi - done - -@@ -3030,9 +3049,7 @@ - /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ - struct buf { int x; }; - struct buf * (*rcsopen) (struct buf *, struct stat *, int); --static char *e (p, i) -- char **p; -- int i; -+static char *e (char **p, int i) - { - return p[i]; - } -@@ -3046,6 +3063,21 @@ - return s; - } - -+/* C89 style stringification. */ -+#define noexpand_stringify(a) #a -+const char *stringified = noexpand_stringify(arbitrary+token=sequence); -+ -+/* C89 style token pasting. Exercises some of the corner cases that -+ e.g. old MSVC gets wrong, but not very hard. */ -+#define noexpand_concat(a,b) a##b -+#define expand_concat(a,b) noexpand_concat(a,b) -+extern int vA; -+extern int vbee; -+#define aye A -+#define bee B -+int *pvA = &expand_concat(v,aye); -+int *pvbee = &noexpand_concat(v,bee); -+ - /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not \xHH hex character constants. - These do not provoke an error unfortunately, instead are silently treated -@@ -3073,16 +3105,19 @@ - - # Test code for whether the C compiler supports C99 (global declarations) - ac_c_conftest_c99_globals=' --// Does the compiler advertise C99 conformance? -+/* Does the compiler advertise C99 conformance? */ - #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L - # error "Compiler does not advertise C99 conformance" - #endif - -+// See if C++-style comments work. -+ - #include - extern int puts (const char *); - extern int printf (const char *, ...); - extern int dprintf (int, const char *, ...); - extern void *malloc (size_t); -+extern void free (void *); - - // Check varargs macros. These examples are taken from C99 6.10.3.5. - // dprintf is used instead of fprintf to avoid needing to declare -@@ -3132,7 +3167,6 @@ - static inline int - test_restrict (ccp restrict text) - { -- // See if C++-style comments work. - // Iterate through items via the restricted pointer. - // Also check for declarations in for loops. - for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) -@@ -3198,6 +3232,8 @@ - ia->datasize = 10; - for (int i = 0; i < ia->datasize; ++i) - ia->data[i] = i * 1.234; -+ // Work around memory leak warnings. -+ free (ia); - - // Check named initializers. - struct named_init ni = { -@@ -3219,7 +3255,7 @@ - - # Test code for whether the C compiler supports C11 (global declarations) - ac_c_conftest_c11_globals=' --// Does the compiler advertise C11 conformance? -+/* Does the compiler advertise C11 conformance? */ - #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L - # error "Compiler does not advertise C11 conformance" - #endif -@@ -3413,8 +3449,9 @@ - if $as_found - then : - --else $as_nop -- as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 -+else case e in #( -+ e) as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 ;; -+esac - fi - - -@@ -3442,12 +3479,12 @@ - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 --printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} -+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&5 -+printf "%s\n" "$as_me: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 --printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} -+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was not set in the previous run" >&5 -+printf "%s\n" "$as_me: error: '$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) -@@ -3456,18 +3493,18 @@ - ac_old_val_w=`echo x $ac_old_val` - ac_new_val_w=`echo x $ac_new_val` - if test "$ac_old_val_w" != "$ac_new_val_w"; then -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 --printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} -+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' has changed since the previous run:" >&5 -+printf "%s\n" "$as_me: error: '$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: - else -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 --printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} -+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&5 -+printf "%s\n" "$as_me: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&2;} - eval $ac_var=\$ac_old_val - fi -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 --printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 --printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} -+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: '$ac_old_val'" >&5 -+printf "%s\n" "$as_me: former value: '$ac_old_val'" >&2;} -+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: '$ac_new_val'" >&5 -+printf "%s\n" "$as_me: current value: '$ac_new_val'" >&2;} - fi;; - esac - # Pass precious variables to config.status. -@@ -3483,11 +3520,11 @@ - fi - done - if $ac_cache_corrupted; then -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 - printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} -- as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' -+ as_fn_error $? "run '${MAKE-make} distclean' and/or 'rm $cache_file' - and start over" "$LINENO" 5 - fi - ## -------------------- ## -@@ -3538,8 +3575,8 @@ - if test ${ac_cv_prog_HAS_GIT+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test -n "$HAS_GIT"; then -+else case e in #( -+ e) if test -n "$HAS_GIT"; then - ac_cv_prog_HAS_GIT="$HAS_GIT" # Let the user override the test. - else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -@@ -3562,7 +3599,8 @@ - IFS=$as_save_IFS - - test -z "$ac_cv_prog_HAS_GIT" && ac_cv_prog_HAS_GIT="not-found" --fi -+fi ;; -+esac - fi - HAS_GIT=$ac_cv_prog_HAS_GIT - if test -n "$HAS_GIT"; then -@@ -3604,15 +3642,16 @@ - if test ${ac_cv_build+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_build_alias=$build_alias -+else case e in #( -+ e) ac_build_alias=$build_alias - test "x$ac_build_alias" = x && - ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` - test "x$ac_build_alias" = x && - as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 - ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || - as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 - printf "%s\n" "$ac_cv_build" >&6; } -@@ -3639,14 +3678,15 @@ - if test ${ac_cv_host+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test "x$host_alias" = x; then -+else case e in #( -+ e) if test "x$host_alias" = x; then - ac_cv_host=$ac_cv_build - else - ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || - as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 - printf "%s\n" "$ac_cv_host" >&6; } -@@ -3710,8 +3750,8 @@ - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_build_python" >&5 - printf "%s\n" "$with_build_python" >&6; } - --else $as_nop -- -+else case e in #( -+ e) - if test "x$cross_compiling" = xyes - then : - as_fn_error $? "Cross compiling requires --with-build-python" "$LINENO" 5 -@@ -3720,7 +3760,8 @@ - PYTHON_FOR_BUILD='./$(BUILDPYTHON) -E' - PYTHON_FOR_FREEZE="./_bootstrap_python" - -- -+ ;; -+esac - fi - - -@@ -3740,15 +3781,16 @@ - FREEZE_MODULE_DEPS='$(FREEZE_MODULE_BOOTSTRAP_DEPS)' - PYTHON_FOR_BUILD_DEPS='' - --else $as_nop -- -+else case e in #( -+ e) - FREEZE_MODULE_BOOTSTRAP='./Programs/_freeze_module' - FREEZE_MODULE_BOOTSTRAP_DEPS="Programs/_freeze_module" - FREEZE_MODULE='$(PYTHON_FOR_FREEZE) $(srcdir)/Programs/_freeze_module.py' - FREEZE_MODULE_DEPS="_bootstrap_python \$(srcdir)/Programs/_freeze_module.py" - PYTHON_FOR_BUILD_DEPS='$(BUILDPYTHON)' - -- -+ ;; -+esac - fi - - -@@ -3765,8 +3807,8 @@ - if test ${ac_cv_prog_PYTHON_FOR_REGEN+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test -n "$PYTHON_FOR_REGEN"; then -+else case e in #( -+ e) if test -n "$PYTHON_FOR_REGEN"; then - ac_cv_prog_PYTHON_FOR_REGEN="$PYTHON_FOR_REGEN" # Let the user override the test. - else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -@@ -3788,7 +3830,8 @@ - done - IFS=$as_save_IFS - --fi -+fi ;; -+esac - fi - PYTHON_FOR_REGEN=$ac_cv_prog_PYTHON_FOR_REGEN - if test -n "$PYTHON_FOR_REGEN"; then -@@ -3870,9 +3913,10 @@ - if test ${with_pkg_config+y} - then : - withval=$with_pkg_config; --else $as_nop -- with_pkg_config=check -- -+else case e in #( -+ e) with_pkg_config=check -+ ;; -+esac - fi - - case $with_pkg_config in #( -@@ -3899,8 +3943,8 @@ - if test ${ac_cv_path_PKG_CONFIG+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- case $PKG_CONFIG in -+else case e in #( -+ e) case $PKG_CONFIG in - [\\/]* | ?:[\\/]*) - ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. - ;; -@@ -3925,6 +3969,7 @@ - IFS=$as_save_IFS - - ;; -+esac ;; - esac - fi - PKG_CONFIG=$ac_cv_path_PKG_CONFIG -@@ -3947,8 +3992,8 @@ - if test ${ac_cv_path_ac_pt_PKG_CONFIG+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- case $ac_pt_PKG_CONFIG in -+else case e in #( -+ e) case $ac_pt_PKG_CONFIG in - [\\/]* | ?:[\\/]*) - ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. - ;; -@@ -3973,6 +4018,7 @@ - IFS=$as_save_IFS - - ;; -+esac ;; - esac - fi - ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG -@@ -4052,6 +4098,15 @@ - *-apple-ios*) - ac_sys_system=iOS - ;; -+ *-apple-tvos*) -+ ac_sys_system=tvOS -+ ;; -+ *-apple-watchos*) -+ ac_sys_system=watchOS -+ ;; -+ *-*-darwin*) -+ ac_sys_system=Darwin -+ ;; - *-*-vxworks*) - ac_sys_system=VxWorks - ;; -@@ -4084,6 +4139,7 @@ - - case $MACHDEP in - aix*) MACHDEP="aix";; -+ freebsd*) MACHDEP="freebsd";; - linux-android*) MACHDEP="android";; - linux*) MACHDEP="linux";; - cygwin*) MACHDEP="cygwin";; -@@ -4129,7 +4185,7 @@ - # On cross-compile builds, configure will look for a host-specific compiler by - # prepending the user-provided host triple to the required binary name. - # --# On iOS, this results in binaries like "arm64-apple-ios13.0-simulator-gcc", -+# On iOS/tvOS/watchOS, this results in binaries like "arm64-apple-ios13.0-simulator-gcc", - # which isn't a binary that exists, and isn't very convenient, as it contains the - # iOS version. As the default cross-compiler name won't exist, configure falls - # back to gcc, which *definitely* won't work. We're providing wrapper scripts for -@@ -4142,32 +4198,76 @@ - if test -z "$AR"; then - case "$host" in - aarch64-apple-ios*-simulator) AR=arm64-apple-ios-simulator-ar ;; -+ aarch64-apple-ios*-macabi) AR=arm64-apple-ios-macabi-ar ;; - aarch64-apple-ios*) AR=arm64-apple-ios-ar ;; - x86_64-apple-ios*-simulator) AR=x86_64-apple-ios-simulator-ar ;; -+ -+ aarch64-apple-tvos*-simulator) AR=arm64-apple-tvos-simulator-ar ;; -+ aarch64-apple-tvos*-macabi) AR=arm64-apple-tvos-macabi-ar ;; -+ aarch64-apple-tvos*) AR=arm64-apple-tvos-ar ;; -+ x86_64-apple-tvos*-simulator) AR=x86_64-apple-tvos-simulator-ar ;; -+ -+ aarch64-apple-watchos*-simulator) AR=arm64-apple-watchos-simulator-ar ;; -+ aarch64-apple-watchos*-macabi) AR=arm64-apple-watchos-macabi-ar ;; -+ aarch64-apple-watchos*) AR=arm64_32-apple-watchos-ar ;; -+ x86_64-apple-watchos*-simulator) AR=x86_64-apple-watchos-simulator-ar ;; - *) - esac - fi - if test -z "$CC"; then - case "$host" in - aarch64-apple-ios*-simulator) CC=arm64-apple-ios-simulator-clang ;; -+ aarch64-apple-ios*-macabi) CC=arm64-apple-ios-macabi-clang ;; - aarch64-apple-ios*) CC=arm64-apple-ios-clang ;; - x86_64-apple-ios*-simulator) CC=x86_64-apple-ios-simulator-clang ;; -+ -+ aarch64-apple-tvos*-simulator) CC=arm64-apple-tvos-simulator-clang ;; -+ aarch64-apple-tvos*-macabi) CC=arm64-apple-tvos-macabi-clang ;; -+ aarch64-apple-tvos*) CC=arm64-apple-tvos-clang ;; -+ x86_64-apple-tvos*-simulator) CC=x86_64-apple-tvos-simulator-clang ;; -+ -+ aarch64-apple-watchos*-simulator) CC=arm64-apple-watchos-simulator-clang ;; -+ aarch64-apple-watchos*-macabi) CC=arm64-apple-watchos-macabi-clang ;; -+ aarch64-apple-watchos*) CC=arm64_32-apple-watchos-clang ;; -+ x86_64-apple-watchos*-simulator) CC=x86_64-apple-watchos-simulator-clang ;; - *) - esac - fi - if test -z "$CPP"; then - case "$host" in - aarch64-apple-ios*-simulator) CPP=arm64-apple-ios-simulator-cpp ;; -+ aarch64-apple-ios*-macabi) CPP=arm64-apple-ios-macabi-cpp ;; - aarch64-apple-ios*) CPP=arm64-apple-ios-cpp ;; - x86_64-apple-ios*-simulator) CPP=x86_64-apple-ios-simulator-cpp ;; -+ -+ aarch64-apple-tvos*-simulator) CPP=arm64-apple-tvos-simulator-cpp ;; -+ aarch64-apple-tvos*-macabi) CPP=arm64-apple-tvos-macabi-cpp ;; -+ aarch64-apple-tvos*) CPP=arm64-apple-tvos-cpp ;; -+ x86_64-apple-tvos*-simulator) CPP=x86_64-apple-tvos-simulator-cpp ;; -+ -+ aarch64-apple-watchos*-simulator) CPP=arm64-apple-watchos-simulator-cpp ;; -+ aarch64-apple-watchos*-macabi) CPP=arm64-apple-watchos-macabi-cpp ;; -+ aarch64-apple-watchos*) CPP=arm64_32-apple-watchos-cpp ;; -+ x86_64-apple-watchos*-simulator) CPP=x86_64-apple-watchos-simulator-cpp ;; - *) - esac - fi - if test -z "$CXX"; then - case "$host" in - aarch64-apple-ios*-simulator) CXX=arm64-apple-ios-simulator-clang++ ;; -+ aarch64-apple-ios*-macabi) CXX=arm64-apple-ios-macabi-clang++ ;; - aarch64-apple-ios*) CXX=arm64-apple-ios-clang++ ;; - x86_64-apple-ios*-simulator) CXX=x86_64-apple-ios-simulator-clang++ ;; -+ -+ aarch64-apple-tvos*-simulator) CXX=arm64-apple-tvos-simulator-clang++ ;; -+ aarch64-apple-tvos*-macabi) CXX=arm64-apple-tvos-macabi-clang++ ;; -+ aarch64-apple-tvos*) CXX=arm64-apple-tvos-clang++ ;; -+ x86_64-apple-tvos*-simulator) CXX=x86_64-apple-tvos-simulator-clang++ ;; -+ -+ aarch64-apple-watchos*-simulator) CXX=arm64-apple-watchos-simulator-clang++ ;; -+ aarch64-apple-watchos*-macabi) CXX=arm64-apple-watchos-macabi-clang++ ;; -+ aarch64-apple-watchos*) CXX=arm64_32-apple-watchos-clang++ ;; -+ x86_64-apple-watchos*-simulator) CXX=x86_64-apple-watchos-simulator-clang++ ;; - *) - esac - fi -@@ -4208,11 +4308,12 @@ - esac - - --else $as_nop -- -+else case e in #( -+ e) - UNIVERSALSDK= - enable_universalsdk= -- -+ ;; -+esac - fi - - if test -n "${UNIVERSALSDK}" -@@ -4273,12 +4374,13 @@ - PYTHONFRAMEWORKDIR=${withval}.framework - PYTHONFRAMEWORKIDENTIFIER=org.python.`echo $withval | tr 'A-Z' 'a-z'` - --else $as_nop -- -+else case e in #( -+ e) - PYTHONFRAMEWORK=Python - PYTHONFRAMEWORKDIR=Python.framework - PYTHONFRAMEWORKIDENTIFIER=org.python.python -- -+ ;; -+esac - fi - - # Check whether --enable-framework was given. -@@ -4288,8 +4390,10 @@ - case $enableval in - yes) - case $ac_sys_system in -- Darwin) enableval=/Library/Frameworks ;; -- iOS) enableval=iOS/Frameworks/\$\(MULTIARCH\) ;; -+ Darwin) enableval=/Library/Frameworks ;; -+ iOS) enableval=iOS/Frameworks/\$\(MULTIARCH\) ;; -+ tvOS) enableval=tvOS/Frameworks/\$\(MULTIARCH\) ;; -+ watchOS) enableval=watchOS/Frameworks/\$\(MULTIARCH\) ;; - *) as_fn_error $? "Unknown platform for framework build" "$LINENO" 5 - esac - esac -@@ -4298,6 +4402,8 @@ - no) - case $ac_sys_system in - iOS) as_fn_error $? "iOS builds must use --enable-framework" "$LINENO" 5 ;; -+ tvOS) as_fn_error $? "tvOS builds must use --enable-framework" "$LINENO" 5 ;; -+ watchOS) as_fn_error $? "watchOS builds must use --enable-framework" "$LINENO" 5 ;; - *) - PYTHONFRAMEWORK= - PYTHONFRAMEWORKDIR=no-framework -@@ -4404,6 +4510,36 @@ - - ac_config_files="$ac_config_files iOS/Resources/Info.plist" - -+ ;; -+ tvOS) : -+ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure" -+ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure " -+ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKPYTHONW= -+ INSTALLTARGETS="libinstall inclinstall sharedinstall" -+ -+ prefix=$PYTHONFRAMEWORKPREFIX -+ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" -+ RESSRCDIR=tvOS/Resources -+ -+ ac_config_files="$ac_config_files tvOS/Resources/Info.plist" -+ -+ ;; -+ watchOS) : -+ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure" -+ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure " -+ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKPYTHONW= -+ INSTALLTARGETS="libinstall inclinstall sharedinstall" -+ -+ prefix=$PYTHONFRAMEWORKPREFIX -+ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" -+ RESSRCDIR=watchOS/Resources -+ -+ ac_config_files="$ac_config_files watchOS/Resources/Info.plist" -+ - ;; - *) - as_fn_error $? "Unknown platform for framework build" "$LINENO" 5 -@@ -4411,10 +4547,12 @@ - esac - esac - --else $as_nop -- -+else case e in #( -+ e) - case $ac_sys_system in - iOS) as_fn_error $? "iOS builds must use --enable-framework" "$LINENO" 5 ;; -+ tvOS) as_fn_error $? "tvOS builds must use --enable-framework" "$LINENO" 5 ;; -+ watchOS) as_fn_error $? "watchOS builds must use --enable-framework" "$LINENO" 5 ;; - *) - PYTHONFRAMEWORK= - PYTHONFRAMEWORKDIR=no-framework -@@ -4435,7 +4573,8 @@ - fi - enable_framework= - esac -- -+ ;; -+esac - fi - - -@@ -4468,8 +4607,8 @@ - case "$withval" in - yes) - case $ac_sys_system in -- Darwin|iOS) -- # iOS is able to share the macOS patch -+ Darwin|iOS|tvOS|watchOS) -+ # iOS/tvOS/watchOS is able to share the macOS patch - APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" - ;; - *) as_fn_error $? "no default app store compliance patch available for $ac_sys_system" "$LINENO" 5 ;; -@@ -4484,11 +4623,11 @@ - ;; - esac - --else $as_nop -- -+else case e in #( -+ e) - case $ac_sys_system in -- iOS) -- # Always apply the compliance patch on iOS; we can use the macOS patch -+ iOS|tvOS|watchOS) -+ # Always apply the compliance patch on iOS/tvOS/watchOS; we can use the macOS patch - APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: applying default app store compliance patch" >&5 - printf "%s\n" "applying default app store compliance patch" >&6; } -@@ -4500,7 +4639,8 @@ - printf "%s\n" "not patching for app store compliance" >&6; } - ;; - esac -- -+ ;; -+esac - fi - - -@@ -4542,9 +4682,65 @@ - ;; - esac - ;; -+ *-apple-tvos*) -+ _host_os=`echo $host | cut -d '-' -f3` -+ _host_device=`echo $host | cut -d '-' -f4` -+ _host_device=${_host_device:=os} -+ -+ # TVOS_DEPLOYMENT_TARGET is the minimum supported tvOS version -+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking tvOS deployment target" >&5 -+printf %s "checking tvOS deployment target... " >&6; } -+ TVOS_DEPLOYMENT_TARGET=${_host_os:4} -+ TVOS_DEPLOYMENT_TARGET=${TVOS_DEPLOYMENT_TARGET:=12.0} -+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $TVOS_DEPLOYMENT_TARGET" >&5 -+printf "%s\n" "$TVOS_DEPLOYMENT_TARGET" >&6; } -+ -+ case "$host_cpu" in -+ aarch64) -+ _host_ident=${TVOS_DEPLOYMENT_TARGET}-arm64-appletv${_host_device} -+ ;; -+ *) -+ _host_ident=${TVOS_DEPLOYMENT_TARGET}-$host_cpu-appletv${_host_device} -+ ;; -+ esac -+ ;; -+ *-apple-watchos*) -+ _host_os=`echo $host | cut -d '-' -f3` -+ _host_device=`echo $host | cut -d '-' -f4` -+ _host_device=${_host_device:=os} -+ -+ # WATCHOS_DEPLOYMENT_TARGET is the minimum supported watchOS version -+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking watchOS deployment target" >&5 -+printf %s "checking watchOS deployment target... " >&6; } -+ WATCHOS_DEPLOYMENT_TARGET=${_host_os:7} -+ WATCHOS_DEPLOYMENT_TARGET=${WATCHOS_DEPLOYMENT_TARGET:=4.0} -+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $WATCHOS_DEPLOYMENT_TARGET" >&5 -+printf "%s\n" "$WATCHOS_DEPLOYMENT_TARGET" >&6; } -+ -+ case "$host_cpu" in -+ aarch64) -+ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-arm64-watch${_host_device} -+ ;; -+ *) -+ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-$host_cpu-watch${_host_device} -+ ;; -+ esac -+ ;; -+ *-*-darwin*) -+ case "$host_cpu" in -+ arm*) -+ _host_ident=arm -+ ;; -+ *) -+ _host_ident=$host_cpu -+ esac -+ ;; - *-*-vxworks*) - _host_ident=$host_cpu - ;; -+ *-*-emscripten) -+ _host_ident=$(emcc -dumpversion | cut -f1 -d-)-$host_cpu -+ ;; - wasm32-*-* | wasm64-*-*) - _host_ident=$host_cpu - ;; -@@ -4620,9 +4816,13 @@ - define_xopen_source=no;; - Darwin/[12][0-9].*) - define_xopen_source=no;; -- # On iOS, defining _POSIX_C_SOURCE also disables platform specific features. -+ # On iOS/tvOS/watchOS, defining _POSIX_C_SOURCE also disables platform specific features. - iOS/*) - define_xopen_source=no;; -+ tvOS/*) -+ define_xopen_source=no;; -+ watchOS/*) -+ define_xopen_source=no;; - # On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from - # defining NI_NUMERICHOST. - QNX/6.3.2) -@@ -4685,7 +4885,10 @@ - CONFIGURE_MACOSX_DEPLOYMENT_TARGET= - EXPORT_MACOSX_DEPLOYMENT_TARGET='#' - --# Record the value of IPHONEOS_DEPLOYMENT_TARGET enforced by the selected host triple. -+# Record the value of IPHONEOS_DEPLOYMENT_TARGET / TVOS_DEPLOYMENT_TARGET / -+# WATCHOS_DEPLOYMENT_TARGET enforced by the selected host triple. -+ -+ - - - # checks for alternative programs -@@ -4726,6 +4929,16 @@ - as_fn_append CFLAGS " -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}" - as_fn_append LDFLAGS " -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}" - ;; #( -+ tvOS) : -+ -+ as_fn_append CFLAGS " -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}" -+ as_fn_append LDFLAGS " -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}" -+ ;; #( -+ watchOS) : -+ -+ as_fn_append CFLAGS " -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}" -+ as_fn_append LDFLAGS " -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}" -+ ;; #( - *) : - ;; - esac -@@ -4739,8 +4952,8 @@ - if test ${ac_cv_prog_HAS_XCRUN+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test -n "$HAS_XCRUN"; then -+else case e in #( -+ e) if test -n "$HAS_XCRUN"; then - ac_cv_prog_HAS_XCRUN="$HAS_XCRUN" # Let the user override the test. - else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -@@ -4763,7 +4976,8 @@ - IFS=$as_save_IFS - - test -z "$ac_cv_prog_HAS_XCRUN" && ac_cv_prog_HAS_XCRUN="missing" --fi -+fi ;; -+esac - fi - HAS_XCRUN=$ac_cv_prog_HAS_XCRUN - if test -n "$HAS_XCRUN"; then -@@ -4866,8 +5080,8 @@ - if test ${ac_cv_prog_CC+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test -n "$CC"; then -+else case e in #( -+ e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. - else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -@@ -4889,7 +5103,8 @@ - done - IFS=$as_save_IFS - --fi -+fi ;; -+esac - fi - CC=$ac_cv_prog_CC - if test -n "$CC"; then -@@ -4911,8 +5126,8 @@ - if test ${ac_cv_prog_ac_ct_CC+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test -n "$ac_ct_CC"; then -+else case e in #( -+ e) if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. - else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -@@ -4934,7 +5149,8 @@ - done - IFS=$as_save_IFS - --fi -+fi ;; -+esac - fi - ac_ct_CC=$ac_cv_prog_ac_ct_CC - if test -n "$ac_ct_CC"; then -@@ -4969,8 +5185,8 @@ - if test ${ac_cv_prog_CC+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test -n "$CC"; then -+else case e in #( -+ e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. - else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -@@ -4992,7 +5208,8 @@ - done - IFS=$as_save_IFS - --fi -+fi ;; -+esac - fi - CC=$ac_cv_prog_CC - if test -n "$CC"; then -@@ -5014,8 +5231,8 @@ - if test ${ac_cv_prog_CC+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test -n "$CC"; then -+else case e in #( -+ e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. - else - ac_prog_rejected=no -@@ -5054,7 +5271,8 @@ - ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" - fi - fi --fi -+fi ;; -+esac - fi - CC=$ac_cv_prog_CC - if test -n "$CC"; then -@@ -5078,8 +5296,8 @@ - if test ${ac_cv_prog_CC+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test -n "$CC"; then -+else case e in #( -+ e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. - else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -@@ -5101,7 +5319,8 @@ - done - IFS=$as_save_IFS - --fi -+fi ;; -+esac - fi - CC=$ac_cv_prog_CC - if test -n "$CC"; then -@@ -5127,8 +5346,8 @@ - if test ${ac_cv_prog_ac_ct_CC+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test -n "$ac_ct_CC"; then -+else case e in #( -+ e) if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. - else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -@@ -5150,7 +5369,8 @@ - done - IFS=$as_save_IFS - --fi -+fi ;; -+esac - fi - ac_ct_CC=$ac_cv_prog_ac_ct_CC - if test -n "$ac_ct_CC"; then -@@ -5188,8 +5408,8 @@ - if test ${ac_cv_prog_CC+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test -n "$CC"; then -+else case e in #( -+ e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. - else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -@@ -5211,7 +5431,8 @@ - done - IFS=$as_save_IFS - --fi -+fi ;; -+esac - fi - CC=$ac_cv_prog_CC - if test -n "$CC"; then -@@ -5233,8 +5454,8 @@ - if test ${ac_cv_prog_ac_ct_CC+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test -n "$ac_ct_CC"; then -+else case e in #( -+ e) if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. - else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -@@ -5256,7 +5477,8 @@ - done - IFS=$as_save_IFS - --fi -+fi ;; -+esac - fi - ac_ct_CC=$ac_cv_prog_ac_ct_CC - if test -n "$ac_ct_CC"; then -@@ -5285,10 +5507,10 @@ - fi - - --test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error $? "no acceptable C compiler found in \$PATH --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } - - # Provide some information about the compiler. - printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 -@@ -5360,8 +5582,8 @@ - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - then : -- # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. --# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' -+ # Autoconf-2.13 could set the ac_cv_exeext variable to 'no'. -+# So ignore a value of 'no', otherwise this would lead to 'EXEEXT = no' - # in a Makefile. We should not override ac_cv_exeext if it was cached, - # so that the user can short-circuit this test for compilers unknown to - # Autoconf. -@@ -5381,7 +5603,7 @@ - ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - fi - # We set ac_cv_exeext here because the later test for it is not -- # safe: cross compilers may not add the suffix if given an `-o' -+ # safe: cross compilers may not add the suffix if given an '-o' - # argument, so we may need to know it at that point already. - # Even if this section looks crufty: it has the advantage of - # actually working. -@@ -5392,8 +5614,9 @@ - done - test "$ac_cv_exeext" = no && ac_cv_exeext= - --else $as_nop -- ac_file='' -+else case e in #( -+ e) ac_file='' ;; -+esac - fi - if test -z "$ac_file" - then : -@@ -5402,13 +5625,14 @@ - printf "%s\n" "$as_me: failed program was:" >&5 - sed 's/^/| /' conftest.$ac_ext >&5 - --{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error 77 "C compiler cannot create executables --See \`config.log' for more details" "$LINENO" 5; } --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 --printf "%s\n" "yes" >&6; } -+See 'config.log' for more details" "$LINENO" 5; } -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -+printf "%s\n" "yes" >&6; } ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 - printf %s "checking for C compiler default output file name... " >&6; } -@@ -5432,10 +5656,10 @@ - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - then : -- # If both `conftest.exe' and `conftest' are `present' (well, observable) --# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will --# work properly (i.e., refer to `conftest.exe'), while it won't with --# `rm'. -+ # If both 'conftest.exe' and 'conftest' are 'present' (well, observable) -+# catch 'conftest.exe'. For instance with Cygwin, 'ls conftest' will -+# work properly (i.e., refer to 'conftest.exe'), while it won't with -+# 'rm'. - for ac_file in conftest.exe conftest conftest.*; do - test -f "$ac_file" || continue - case $ac_file in -@@ -5445,11 +5669,12 @@ - * ) break;; - esac - done --else $as_nop -- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+else case e in #( -+ e) { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error $? "cannot compute suffix of executables: cannot compile and link --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } ;; -+esac - fi - rm -f conftest conftest$ac_cv_exeext - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 -@@ -5465,6 +5690,8 @@ - main (void) - { - FILE *f = fopen ("conftest.out", "w"); -+ if (!f) -+ return 1; - return ferror (f) || fclose (f) != 0; - - ; -@@ -5504,26 +5731,27 @@ - if test "$cross_compiling" = maybe; then - cross_compiling=yes - else -- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error 77 "cannot run C compiled programs. --If you meant to cross compile, use \`--host'. --See \`config.log' for more details" "$LINENO" 5; } -+If you meant to cross compile, use '--host'. -+See 'config.log' for more details" "$LINENO" 5; } - fi - fi - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 - printf "%s\n" "$cross_compiling" >&6; } - --rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out -+rm -f conftest.$ac_ext conftest$ac_cv_exeext \ -+ conftest.o conftest.obj conftest.out - ac_clean_files=$ac_clean_files_save - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 - printf %s "checking for suffix of object files... " >&6; } - if test ${ac_cv_objext+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - int -@@ -5555,16 +5783,18 @@ - break;; - esac - done --else $as_nop -- printf "%s\n" "$as_me: failed program was:" >&5 -+else case e in #( -+ e) printf "%s\n" "$as_me: failed program was:" >&5 - sed 's/^/| /' conftest.$ac_ext >&5 - --{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error $? "cannot compute suffix of object files: cannot compile --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } ;; -+esac - fi --rm -f conftest.$ac_cv_objext conftest.$ac_ext -+rm -f conftest.$ac_cv_objext conftest.$ac_ext ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 - printf "%s\n" "$ac_cv_objext" >&6; } -@@ -5575,8 +5805,8 @@ - if test ${ac_cv_c_compiler_gnu+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - int -@@ -5593,12 +5823,14 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_compiler_gnu=yes --else $as_nop -- ac_compiler_gnu=no -+else case e in #( -+ e) ac_compiler_gnu=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_cv_c_compiler_gnu=$ac_compiler_gnu -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 - printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } -@@ -5616,8 +5848,8 @@ - if test ${ac_cv_prog_cc_g+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_save_c_werror_flag=$ac_c_werror_flag -+else case e in #( -+ e) ac_save_c_werror_flag=$ac_c_werror_flag - ac_c_werror_flag=yes - ac_cv_prog_cc_g=no - CFLAGS="-g" -@@ -5635,8 +5867,8 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_prog_cc_g=yes --else $as_nop -- CFLAGS="" -+else case e in #( -+ e) CFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - -@@ -5651,8 +5883,8 @@ - if ac_fn_c_try_compile "$LINENO" - then : - --else $as_nop -- ac_c_werror_flag=$ac_save_c_werror_flag -+else case e in #( -+ e) ac_c_werror_flag=$ac_save_c_werror_flag - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ -@@ -5669,12 +5901,15 @@ - then : - ac_cv_prog_cc_g=yes - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- ac_c_werror_flag=$ac_save_c_werror_flag -+ ac_c_werror_flag=$ac_save_c_werror_flag ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 - printf "%s\n" "$ac_cv_prog_cc_g" >&6; } -@@ -5701,8 +5936,8 @@ - if test ${ac_cv_prog_cc_c11+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_cv_prog_cc_c11=no -+else case e in #( -+ e) ac_cv_prog_cc_c11=no - ac_save_CC=$CC - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ -@@ -5719,25 +5954,28 @@ - test "x$ac_cv_prog_cc_c11" != "xno" && break - done - rm -f conftest.$ac_ext --CC=$ac_save_CC -+CC=$ac_save_CC ;; -+esac - fi - - if test "x$ac_cv_prog_cc_c11" = xno - then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 - printf "%s\n" "unsupported" >&6; } --else $as_nop -- if test "x$ac_cv_prog_cc_c11" = x -+else case e in #( -+ e) if test "x$ac_cv_prog_cc_c11" = x - then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 - printf "%s\n" "none needed" >&6; } --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 - printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } -- CC="$CC $ac_cv_prog_cc_c11" -+ CC="$CC $ac_cv_prog_cc_c11" ;; -+esac - fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 -- ac_prog_cc_stdc=c11 -+ ac_prog_cc_stdc=c11 ;; -+esac - fi - fi - if test x$ac_prog_cc_stdc = xno -@@ -5747,8 +5985,8 @@ - if test ${ac_cv_prog_cc_c99+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_cv_prog_cc_c99=no -+else case e in #( -+ e) ac_cv_prog_cc_c99=no - ac_save_CC=$CC - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ -@@ -5765,25 +6003,28 @@ - test "x$ac_cv_prog_cc_c99" != "xno" && break - done - rm -f conftest.$ac_ext --CC=$ac_save_CC -+CC=$ac_save_CC ;; -+esac - fi - - if test "x$ac_cv_prog_cc_c99" = xno - then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 - printf "%s\n" "unsupported" >&6; } --else $as_nop -- if test "x$ac_cv_prog_cc_c99" = x -+else case e in #( -+ e) if test "x$ac_cv_prog_cc_c99" = x - then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 - printf "%s\n" "none needed" >&6; } --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 - printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } -- CC="$CC $ac_cv_prog_cc_c99" -+ CC="$CC $ac_cv_prog_cc_c99" ;; -+esac - fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 -- ac_prog_cc_stdc=c99 -+ ac_prog_cc_stdc=c99 ;; -+esac - fi - fi - if test x$ac_prog_cc_stdc = xno -@@ -5793,8 +6034,8 @@ - if test ${ac_cv_prog_cc_c89+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_cv_prog_cc_c89=no -+else case e in #( -+ e) ac_cv_prog_cc_c89=no - ac_save_CC=$CC - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ -@@ -5811,25 +6052,28 @@ - test "x$ac_cv_prog_cc_c89" != "xno" && break - done - rm -f conftest.$ac_ext --CC=$ac_save_CC -+CC=$ac_save_CC ;; -+esac - fi - - if test "x$ac_cv_prog_cc_c89" = xno - then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 - printf "%s\n" "unsupported" >&6; } --else $as_nop -- if test "x$ac_cv_prog_cc_c89" = x -+else case e in #( -+ e) if test "x$ac_cv_prog_cc_c89" = x - then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 - printf "%s\n" "none needed" >&6; } --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 - printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } -- CC="$CC $ac_cv_prog_cc_c89" -+ CC="$CC $ac_cv_prog_cc_c89" ;; -+esac - fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 -- ac_prog_cc_stdc=c89 -+ ac_prog_cc_stdc=c89 ;; -+esac - fi - fi - -@@ -5854,8 +6098,8 @@ - if test ${ac_cv_prog_CPP+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- # Double quotes because $CC needs to be expanded -+else case e in #( -+ e) # Double quotes because $CC needs to be expanded - for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp - do - ac_preproc_ok=false -@@ -5873,9 +6117,10 @@ - if ac_fn_c_try_cpp "$LINENO" - then : - --else $as_nop -- # Broken: fails on valid input. --continue -+else case e in #( -+ e) # Broken: fails on valid input. -+continue ;; -+esac - fi - rm -f conftest.err conftest.i conftest.$ac_ext - -@@ -5889,15 +6134,16 @@ - then : - # Broken: success on invalid input. - continue --else $as_nop -- # Passes both tests. -+else case e in #( -+ e) # Passes both tests. - ac_preproc_ok=: --break -+break ;; -+esac - fi - rm -f conftest.err conftest.i conftest.$ac_ext - - done --# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -+# Because of 'break', _AC_PREPROC_IFELSE's cleaning code was skipped. - rm -f conftest.i conftest.err conftest.$ac_ext - if $ac_preproc_ok - then : -@@ -5906,7 +6152,8 @@ - - done - ac_cv_prog_CPP=$CPP -- -+ ;; -+esac - fi - CPP=$ac_cv_prog_CPP - else -@@ -5929,9 +6176,10 @@ - if ac_fn_c_try_cpp "$LINENO" - then : - --else $as_nop -- # Broken: fails on valid input. --continue -+else case e in #( -+ e) # Broken: fails on valid input. -+continue ;; -+esac - fi - rm -f conftest.err conftest.i conftest.$ac_ext - -@@ -5945,24 +6193,26 @@ - then : - # Broken: success on invalid input. - continue --else $as_nop -- # Passes both tests. -+else case e in #( -+ e) # Passes both tests. - ac_preproc_ok=: --break -+break ;; -+esac - fi - rm -f conftest.err conftest.i conftest.$ac_ext - - done --# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -+# Because of 'break', _AC_PREPROC_IFELSE's cleaning code was skipped. - rm -f conftest.i conftest.err conftest.$ac_ext - if $ac_preproc_ok - then : - --else $as_nop -- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+else case e in #( -+ e) { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error $? "C preprocessor \"$CPP\" fails sanity check --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } ;; -+esac - fi - - ac_ext=c -@@ -5976,8 +6226,8 @@ - if test ${ac_cv_path_GREP+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test -z "$GREP"; then -+else case e in #( -+ e) if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -@@ -5996,9 +6246,10 @@ - as_fn_executable_p "$ac_path_GREP" || continue - # Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP --case `"$ac_path_GREP" --version 2>&1` in -+case `"$ac_path_GREP" --version 2>&1` in #( - *GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -+#( - *) - ac_count=0 - printf %s 0123456789 >"conftest.in" -@@ -6033,7 +6284,8 @@ - else - ac_cv_path_GREP=$GREP - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 - printf "%s\n" "$ac_cv_path_GREP" >&6; } -@@ -6045,8 +6297,8 @@ - if test ${ac_cv_path_SED+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ -+else case e in #( -+ e) ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ - for ac_i in 1 2 3 4 5 6 7; do - ac_script="$ac_script$as_nl$ac_script" - done -@@ -6071,9 +6323,10 @@ - as_fn_executable_p "$ac_path_SED" || continue - # Check for GNU ac_path_SED and select it if it is found. - # Check for GNU $ac_path_SED --case `"$ac_path_SED" --version 2>&1` in -+case `"$ac_path_SED" --version 2>&1` in #( - *GNU*) - ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; -+#( - *) - ac_count=0 - printf %s 0123456789 >"conftest.in" -@@ -6108,7 +6361,8 @@ - else - ac_cv_path_SED=$SED - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 - printf "%s\n" "$ac_cv_path_SED" >&6; } -@@ -6120,8 +6374,8 @@ - if test ${ac_cv_path_EGREP+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 -+else case e in #( -+ e) if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - if test -z "$EGREP"; then -@@ -6143,9 +6397,10 @@ - as_fn_executable_p "$ac_path_EGREP" || continue - # Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP --case `"$ac_path_EGREP" --version 2>&1` in -+case `"$ac_path_EGREP" --version 2>&1` in #( - *GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -+#( - *) - ac_count=0 - printf %s 0123456789 >"conftest.in" -@@ -6181,12 +6436,15 @@ - ac_cv_path_EGREP=$EGREP - fi - -- fi -+ fi ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 - printf "%s\n" "$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" - -+ EGREP_TRADITIONAL=$EGREP -+ ac_cv_path_EGREP_TRADITIONAL=$EGREP - - - CC_BASENAME=$(expr "//$CC" : '.*/\(.*\)') -@@ -6196,8 +6454,8 @@ - if test ${ac_cv_cc_name+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat > conftest.c <&5 - printf "%s\n" "$ac_cv_cc_name" >&6; } -@@ -6275,8 +6534,8 @@ - if test ${ac_cv_safe_to_define___extensions__+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - # define __EXTENSIONS__ 1 -@@ -6292,10 +6551,12 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_safe_to_define___extensions__=yes --else $as_nop -- ac_cv_safe_to_define___extensions__=no -+else case e in #( -+ e) ac_cv_safe_to_define___extensions__=no ;; -+esac - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 - printf "%s\n" "$ac_cv_safe_to_define___extensions__" >&6; } -@@ -6305,8 +6566,8 @@ - if test ${ac_cv_should_define__xopen_source+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_cv_should_define__xopen_source=no -+else case e in #( -+ e) ac_cv_should_define__xopen_source=no - if test $ac_cv_header_wchar_h = yes - then : - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -6325,8 +6586,8 @@ - if ac_fn_c_try_compile "$LINENO" - then : - --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #define _XOPEN_SOURCE 500 -@@ -6344,10 +6605,12 @@ - then : - ac_cv_should_define__xopen_source=yes - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext --fi -+fi ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_should_define__xopen_source" >&5 - printf "%s\n" "$ac_cv_should_define__xopen_source" >&6; } -@@ -6372,6 +6635,8 @@ - - printf "%s\n" "#define __STDC_WANT_IEC_60559_DFP_EXT__ 1" >>confdefs.h - -+ printf "%s\n" "#define __STDC_WANT_IEC_60559_EXT__ 1" >>confdefs.h -+ - printf "%s\n" "#define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1" >>confdefs.h - - printf "%s\n" "#define __STDC_WANT_IEC_60559_TYPES_EXT__ 1" >>confdefs.h -@@ -6391,8 +6656,9 @@ - - printf "%s\n" "#define _POSIX_1_SOURCE 2" >>confdefs.h - --else $as_nop -- MINIX= -+else case e in #( -+ e) MINIX= ;; -+esac - fi - if test $ac_cv_safe_to_define___extensions__ = yes - then : -@@ -6412,8 +6678,8 @@ - if test ${ac_cv_gcc_compat+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #if !defined(__GNUC__) -@@ -6426,10 +6692,12 @@ - if ac_fn_c_try_cpp "$LINENO" - then : - ac_cv_gcc_compat=yes --else $as_nop -- ac_cv_gcc_compat=no -+else case e in #( -+ e) ac_cv_gcc_compat=no ;; -+esac - fi --rm -f conftest.err conftest.i conftest.$ac_ext -+rm -f conftest.err conftest.i conftest.$ac_ext ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_gcc_compat" >&5 - printf "%s\n" "$ac_cv_gcc_compat" >&6; } -@@ -6448,8 +6716,8 @@ - if test ${ac_cv_path_CXX+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- case $CXX in -+else case e in #( -+ e) case $CXX in - [\\/]* | ?:[\\/]*) - ac_cv_path_CXX="$CXX" # Let the user override the test with a path. - ;; -@@ -6474,6 +6742,7 @@ - IFS=$as_save_IFS - - ;; -+esac ;; - esac - fi - CXX=$ac_cv_path_CXX -@@ -6496,8 +6765,8 @@ - if test ${ac_cv_path_ac_pt_CXX+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- case $ac_pt_CXX in -+else case e in #( -+ e) case $ac_pt_CXX in - [\\/]* | ?:[\\/]*) - ac_cv_path_ac_pt_CXX="$ac_pt_CXX" # Let the user override the test with a path. - ;; -@@ -6522,6 +6791,7 @@ - IFS=$as_save_IFS - - ;; -+esac ;; - esac - fi - ac_pt_CXX=$ac_cv_path_ac_pt_CXX -@@ -6556,8 +6826,8 @@ - if test ${ac_cv_path_CXX+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- case $CXX in -+else case e in #( -+ e) case $CXX in - [\\/]* | ?:[\\/]*) - ac_cv_path_CXX="$CXX" # Let the user override the test with a path. - ;; -@@ -6582,6 +6852,7 @@ - IFS=$as_save_IFS - - ;; -+esac ;; - esac - fi - CXX=$ac_cv_path_CXX -@@ -6604,8 +6875,8 @@ - if test ${ac_cv_path_ac_pt_CXX+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- case $ac_pt_CXX in -+else case e in #( -+ e) case $ac_pt_CXX in - [\\/]* | ?:[\\/]*) - ac_cv_path_ac_pt_CXX="$ac_pt_CXX" # Let the user override the test with a path. - ;; -@@ -6630,6 +6901,7 @@ - IFS=$as_save_IFS - - ;; -+esac ;; - esac - fi - ac_pt_CXX=$ac_cv_path_ac_pt_CXX -@@ -6664,8 +6936,8 @@ - if test ${ac_cv_path_CXX+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- case $CXX in -+else case e in #( -+ e) case $CXX in - [\\/]* | ?:[\\/]*) - ac_cv_path_CXX="$CXX" # Let the user override the test with a path. - ;; -@@ -6690,6 +6962,7 @@ - IFS=$as_save_IFS - - ;; -+esac ;; - esac - fi - CXX=$ac_cv_path_CXX -@@ -6712,8 +6985,8 @@ - if test ${ac_cv_path_ac_pt_CXX+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- case $ac_pt_CXX in -+else case e in #( -+ e) case $ac_pt_CXX in - [\\/]* | ?:[\\/]*) - ac_cv_path_ac_pt_CXX="$ac_pt_CXX" # Let the user override the test with a path. - ;; -@@ -6738,6 +7011,7 @@ - IFS=$as_save_IFS - - ;; -+esac ;; - esac - fi - ac_pt_CXX=$ac_cv_path_ac_pt_CXX -@@ -6772,8 +7046,8 @@ - if test ${ac_cv_path_CXX+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- case $CXX in -+else case e in #( -+ e) case $CXX in - [\\/]* | ?:[\\/]*) - ac_cv_path_CXX="$CXX" # Let the user override the test with a path. - ;; -@@ -6798,6 +7072,7 @@ - IFS=$as_save_IFS - - ;; -+esac ;; - esac - fi - CXX=$ac_cv_path_CXX -@@ -6820,8 +7095,8 @@ - if test ${ac_cv_path_ac_pt_CXX+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- case $ac_pt_CXX in -+else case e in #( -+ e) case $ac_pt_CXX in - [\\/]* | ?:[\\/]*) - ac_cv_path_ac_pt_CXX="$ac_pt_CXX" # Let the user override the test with a path. - ;; -@@ -6846,6 +7121,7 @@ - IFS=$as_save_IFS - - ;; -+esac ;; - esac - fi - ac_pt_CXX=$ac_cv_path_ac_pt_CXX -@@ -6890,8 +7166,8 @@ - if test ${ac_cv_prog_CXX+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test -n "$CXX"; then -+else case e in #( -+ e) if test -n "$CXX"; then - ac_cv_prog_CXX="$CXX" # Let the user override the test. - else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -@@ -6913,7 +7189,8 @@ - done - IFS=$as_save_IFS - --fi -+fi ;; -+esac - fi - CXX=$ac_cv_prog_CXX - if test -n "$CXX"; then -@@ -6939,8 +7216,8 @@ - if test ${ac_cv_prog_ac_ct_CXX+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test -n "$ac_ct_CXX"; then -+else case e in #( -+ e) if test -n "$ac_ct_CXX"; then - ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. - else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -@@ -6962,7 +7239,8 @@ - done - IFS=$as_save_IFS - --fi -+fi ;; -+esac - fi - ac_ct_CXX=$ac_cv_prog_ac_ct_CXX - if test -n "$ac_ct_CXX"; then -@@ -7030,6 +7308,10 @@ - MULTIARCH="" ;; #( - iOS) : - MULTIARCH="" ;; #( -+ tvOS) : -+ MULTIARCH="" ;; #( -+ watchOS) : -+ MULTIARCH="" ;; #( - FreeBSD*) : - MULTIARCH="" ;; #( - *) : -@@ -7050,7 +7332,7 @@ - printf "%s\n" "$MULTIARCH" >&6; } - - case $ac_sys_system in #( -- iOS) : -+ iOS|tvOS|watchOS) : - SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f2` ;; #( - *) : - SOABI_PLATFORM=$PLATFORM_TRIPLET -@@ -7101,6 +7383,14 @@ - PY_SUPPORT_TIER=3 ;; #( - aarch64-apple-ios*/clang) : - PY_SUPPORT_TIER=3 ;; #( -+ aarch64-apple-tvos*-simulator/clang) : -+ PY_SUPPORT_TIER=3 ;; #( -+ aarch64-apple-tvos*/clang) : -+ PY_SUPPORT_TIER=3 ;; #( -+ aarch64-apple-watchos*-simulator/clang) : -+ PY_SUPPORT_TIER=3 ;; #( -+ arm64_32-apple-watchos*/clang) : -+ PY_SUPPORT_TIER=3 ;; #( - aarch64-*-linux-android/clang) : - PY_SUPPORT_TIER=3 ;; #( - x86_64-*-linux-android/clang) : -@@ -7136,8 +7426,8 @@ - if test ${ac_cv_wl_no_as_needed+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - save_LDFLAGS="$LDFLAGS" - as_fn_append LDFLAGS " -Wl,--no-as-needed" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -7155,14 +7445,16 @@ - then : - NO_AS_NEEDED="-Wl,--no-as-needed" - ac_cv_wl_no_as_needed=yes --else $as_nop -- NO_AS_NEEDED="" -- ac_cv_wl_no_as_needed=no -+else case e in #( -+ e) NO_AS_NEEDED="" -+ ac_cv_wl_no_as_needed=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS="$save_LDFLAGS" -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_wl_no_as_needed" >&5 - printf "%s\n" "$ac_cv_wl_no_as_needed" >&6; } -@@ -7235,10 +7527,11 @@ - ;; - esac - --else $as_nop -- -+else case e in #( -+ e) - enable_wasm_dynamic_linking=missing -- -+ ;; -+esac - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_wasm_dynamic_linking" >&5 -@@ -7260,10 +7553,11 @@ - ;; - esac - --else $as_nop -- -+else case e in #( -+ e) - enable_wasm_pthreads=missing -- -+ ;; -+esac - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_wasm_pthreads" >&5 -@@ -7286,8 +7580,8 @@ - ;; - esac - --else $as_nop -- -+else case e in #( -+ e) - case $ac_sys_system in #( - Emscripten) : - EXEEXT=.mjs ;; #( -@@ -7297,7 +7591,8 @@ - EXEEXT= - ;; - esac -- -+ ;; -+esac - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $EXEEXT" >&5 -@@ -7473,9 +7768,10 @@ - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 - printf "%s\n" "yes" >&6; }; - fi --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 --printf "%s\n" "yes" >&6; } -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -+printf "%s\n" "yes" >&6; } ;; -+esac - fi - - -@@ -7498,8 +7794,9 @@ - if ac_fn_c_try_link "$LINENO" - then : - --else $as_nop -- enable_profiling=no -+else case e in #( -+ e) enable_profiling=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -@@ -7530,7 +7827,7 @@ - case $ac_sys_system in - Darwin) - LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)';; -- iOS) -+ iOS|tvOS|watchOS) - LDLIBRARY='$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';; - *) - as_fn_error $? "Unknown platform for framework build" "$LINENO" 5;; -@@ -7596,7 +7893,7 @@ - BLDLIBRARY='-L. -lpython$(LDVERSION)' - RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}} - ;; -- iOS) -+ iOS|tvOS|watchOS) - LDLIBRARY='libpython$(LDVERSION).dylib' - ;; - AIX*) -@@ -7637,8 +7934,8 @@ - if test ${ac_cv_path_NODE+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- case $NODE in -+else case e in #( -+ e) case $NODE in - [\\/]* | ?:[\\/]*) - ac_cv_path_NODE="$NODE" # Let the user override the test with a path. - ;; -@@ -7663,6 +7960,7 @@ - IFS=$as_save_IFS - - ;; -+esac ;; - esac - fi - NODE=$ac_cv_path_NODE -@@ -7685,8 +7983,8 @@ - if test ${ac_cv_path_ac_pt_NODE+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- case $ac_pt_NODE in -+else case e in #( -+ e) case $ac_pt_NODE in - [\\/]* | ?:[\\/]*) - ac_cv_path_ac_pt_NODE="$ac_pt_NODE" # Let the user override the test with a path. - ;; -@@ -7711,6 +8009,7 @@ - IFS=$as_save_IFS - - ;; -+esac ;; - esac - fi - ac_pt_NODE=$ac_cv_path_ac_pt_NODE -@@ -7795,8 +8094,8 @@ - if test ${ac_cv_prog_AR+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test -n "$AR"; then -+else case e in #( -+ e) if test -n "$AR"; then - ac_cv_prog_AR="$AR" # Let the user override the test. - else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -@@ -7818,7 +8117,8 @@ - done - IFS=$as_save_IFS - --fi -+fi ;; -+esac - fi - AR=$ac_cv_prog_AR - if test -n "$AR"; then -@@ -7844,8 +8144,8 @@ - if test ${ac_cv_prog_ac_ct_AR+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test -n "$ac_ct_AR"; then -+else case e in #( -+ e) if test -n "$ac_ct_AR"; then - ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. - else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -@@ -7867,7 +8167,8 @@ - done - IFS=$as_save_IFS - --fi -+fi ;; -+esac - fi - ac_ct_AR=$ac_cv_prog_ac_ct_AR - if test -n "$ac_ct_AR"; then -@@ -7932,8 +8233,8 @@ - if test ${ac_cv_path_install+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -+else case e in #( -+ e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR - for as_dir in $PATH - do - IFS=$as_save_IFS -@@ -7987,7 +8288,8 @@ - IFS=$as_save_IFS - - rm -rf conftest.one conftest.two conftest.dir -- -+ ;; -+esac - fi - if test ${ac_cv_path_install+y}; then - INSTALL=$ac_cv_path_install -@@ -8017,8 +8319,8 @@ - if test ${ac_cv_path_mkdir+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -+else case e in #( -+ e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR - for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin - do - IFS=$as_save_IFS -@@ -8032,7 +8334,7 @@ - as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext" || continue - case `"$as_dir$ac_prog$ac_exec_ext" --version 2>&1` in #( - 'mkdir ('*'coreutils) '* | \ -- 'BusyBox '* | \ -+ *'BusyBox '* | \ - 'mkdir (fileutils) '4.1*) - ac_cv_path_mkdir=$as_dir$ac_prog$ac_exec_ext - break 3;; -@@ -8041,18 +8343,17 @@ - done - done - IFS=$as_save_IFS -- -+ ;; -+esac - fi - - test -d ./--version && rmdir ./--version - if test ${ac_cv_path_mkdir+y}; then - MKDIR_P="$ac_cv_path_mkdir -p" - else -- # As a last resort, use the slow shell script. Don't cache a -- # value for MKDIR_P within a source directory, because that will -- # break other packages using the cache if that directory is -- # removed, or if the value is a relative name. -- MKDIR_P="$ac_install_sh -d" -+ # As a last resort, use plain mkdir -p, -+ # in the hope it doesn't have the bugs of ancient mkdir. -+ MKDIR_P='mkdir -p' - fi - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 -@@ -8084,12 +8385,14 @@ - enableval=$enable_gil; if test "x$enable_gil" = xyes - then : - disable_gil=no --else $as_nop -- disable_gil=yes -+else case e in #( -+ e) disable_gil=yes ;; -+esac - fi --else $as_nop -- disable_gil=no -- -+else case e in #( -+ e) disable_gil=no -+ ;; -+esac - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $disable_gil" >&5 -@@ -8125,9 +8428,10 @@ - else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 - printf "%s\n" "no" >&6; }; Py_DEBUG='false' - fi --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 --printf "%s\n" "no" >&6; } -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -+printf "%s\n" "no" >&6; } ;; -+esac - fi - - -@@ -8140,9 +8444,10 @@ - if test ${with_trace_refs+y} - then : - withval=$with_trace_refs; --else $as_nop -- with_trace_refs=no -- -+else case e in #( -+ e) with_trace_refs=no -+ ;; -+esac - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_trace_refs" >&5 -@@ -8167,9 +8472,10 @@ - if test ${enable_pystats+y} - then : - enableval=$enable_pystats; --else $as_nop -- enable_pystats=no -- -+else case e in #( -+ e) enable_pystats=no -+ ;; -+esac - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_pystats" >&5 -@@ -8219,8 +8525,9 @@ - if test ${enable_experimental_jit+y} - then : - enableval=$enable_experimental_jit; --else $as_nop -- enable_experimental_jit=no -+else case e in #( -+ e) enable_experimental_jit=no ;; -+esac - fi - - case $enable_experimental_jit in -@@ -8234,20 +8541,22 @@ - if ${tier2_flags:+false} : - then : - --else $as_nop -- as_fn_append CFLAGS_NODIST " $tier2_flags" -+else case e in #( -+ e) as_fn_append CFLAGS_NODIST " $tier2_flags" ;; -+esac - fi - if ${jit_flags:+false} : - then : - --else $as_nop -- as_fn_append CFLAGS_NODIST " $jit_flags" -+else case e in #( -+ e) as_fn_append CFLAGS_NODIST " $jit_flags" - REGEN_JIT_COMMAND="\$(PYTHON_FOR_REGEN) \$(srcdir)/Tools/jit/build.py $host" - JIT_STENCILS_H="jit_stencils.h" - if test "x$Py_DEBUG" = xtrue - then : - as_fn_append REGEN_JIT_COMMAND " --debug" --fi -+fi ;; -+esac - fi - - -@@ -8274,9 +8583,10 @@ - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 - printf "%s\n" "no" >&6; }; - fi --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 --printf "%s\n" "no" >&6; } -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -+printf "%s\n" "no" >&6; } ;; -+esac - fi - - -@@ -8296,8 +8606,8 @@ - if test ${ax_cv_check_cflags__Werror__fno_semantic_interposition+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - ax_check_save_flags=$CFLAGS - CFLAGS="$CFLAGS -Werror -fno-semantic-interposition" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -8314,11 +8624,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ax_cv_check_cflags__Werror__fno_semantic_interposition=yes --else $as_nop -- ax_cv_check_cflags__Werror__fno_semantic_interposition=no -+else case e in #( -+ e) ax_cv_check_cflags__Werror__fno_semantic_interposition=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- CFLAGS=$ax_check_save_flags -+ CFLAGS=$ax_check_save_flags ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror__fno_semantic_interposition" >&5 - printf "%s\n" "$ax_cv_check_cflags__Werror__fno_semantic_interposition" >&6; } -@@ -8328,8 +8640,9 @@ - CFLAGS_NODIST="$CFLAGS_NODIST -fno-semantic-interposition" - LDFLAGS_NODIST="$LDFLAGS_NODIST -fno-semantic-interposition" - --else $as_nop -- : -+else case e in #( -+ e) : ;; -+esac - fi - - -@@ -8416,9 +8729,10 @@ - ;; - esac - --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 --printf "%s\n" "no" >&6; } -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -+printf "%s\n" "no" >&6; } ;; -+esac - fi - - if test "$Py_LTO" = 'true' ; then -@@ -8430,8 +8744,8 @@ - if test ${ax_cv_check_cflags___flto_thin+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - ax_check_save_flags=$CFLAGS - CFLAGS="$CFLAGS -flto=thin" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -8448,19 +8762,22 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ax_cv_check_cflags___flto_thin=yes --else $as_nop -- ax_cv_check_cflags___flto_thin=no -+else case e in #( -+ e) ax_cv_check_cflags___flto_thin=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- CFLAGS=$ax_check_save_flags -+ CFLAGS=$ax_check_save_flags ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___flto_thin" >&5 - printf "%s\n" "$ax_cv_check_cflags___flto_thin" >&6; } - if test "x$ax_cv_check_cflags___flto_thin" = xyes - then : - LDFLAGS_NOLTO="-flto=thin" --else $as_nop -- LDFLAGS_NOLTO="-flto" -+else case e in #( -+ e) LDFLAGS_NOLTO="-flto" ;; -+esac - fi - - -@@ -8472,8 +8789,8 @@ - if test ${ac_cv_path_LLVM_AR+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- case $LLVM_AR in -+else case e in #( -+ e) case $LLVM_AR in - [\\/]* | ?:[\\/]*) - ac_cv_path_LLVM_AR="$LLVM_AR" # Let the user override the test with a path. - ;; -@@ -8498,6 +8815,7 @@ - IFS=$as_save_IFS - - ;; -+esac ;; - esac - fi - LLVM_AR=$ac_cv_path_LLVM_AR -@@ -8520,8 +8838,8 @@ - if test ${ac_cv_path_ac_pt_LLVM_AR+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- case $ac_pt_LLVM_AR in -+else case e in #( -+ e) case $ac_pt_LLVM_AR in - [\\/]* | ?:[\\/]*) - ac_cv_path_ac_pt_LLVM_AR="$ac_pt_LLVM_AR" # Let the user override the test with a path. - ;; -@@ -8546,6 +8864,7 @@ - IFS=$as_save_IFS - - ;; -+esac ;; - esac - fi - ac_pt_LLVM_AR=$ac_cv_path_ac_pt_LLVM_AR -@@ -8610,8 +8929,8 @@ - if test ${ax_cv_check_cflags___flto_thin+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - ax_check_save_flags=$CFLAGS - CFLAGS="$CFLAGS -flto=thin" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -8628,11 +8947,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ax_cv_check_cflags___flto_thin=yes --else $as_nop -- ax_cv_check_cflags___flto_thin=no -+else case e in #( -+ e) ax_cv_check_cflags___flto_thin=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- CFLAGS=$ax_check_save_flags -+ CFLAGS=$ax_check_save_flags ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___flto_thin" >&5 - printf "%s\n" "$ax_cv_check_cflags___flto_thin" >&6; } -@@ -8642,12 +8963,13 @@ - LTOFLAGS="-flto=thin -Wl,-export_dynamic -Wl,-object_path_lto,\"\$@\".lto" - LTOCFLAGS="-flto=thin" - --else $as_nop -- -+else case e in #( -+ e) - LTOFLAGS="-flto -Wl,-export_dynamic -Wl,-object_path_lto,\"\$@\".lto" - LTOCFLAGS="-flto" - -- -+ ;; -+esac - fi - - else -@@ -8664,8 +8986,8 @@ - if test ${ax_cv_check_cflags___flto_thin+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - ax_check_save_flags=$CFLAGS - CFLAGS="$CFLAGS -flto=thin" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -8682,19 +9004,22 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ax_cv_check_cflags___flto_thin=yes --else $as_nop -- ax_cv_check_cflags___flto_thin=no -+else case e in #( -+ e) ax_cv_check_cflags___flto_thin=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- CFLAGS=$ax_check_save_flags -+ CFLAGS=$ax_check_save_flags ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___flto_thin" >&5 - printf "%s\n" "$ax_cv_check_cflags___flto_thin" >&6; } - if test "x$ax_cv_check_cflags___flto_thin" = xyes - then : - LTOFLAGS="-flto=thin" --else $as_nop -- LTOFLAGS="-flto" -+else case e in #( -+ e) LTOFLAGS="-flto" ;; -+esac - fi - - else -@@ -8754,8 +9079,8 @@ - if test ${ac_cv_path_LLVM_PROFDATA+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- case $LLVM_PROFDATA in -+else case e in #( -+ e) case $LLVM_PROFDATA in - [\\/]* | ?:[\\/]*) - ac_cv_path_LLVM_PROFDATA="$LLVM_PROFDATA" # Let the user override the test with a path. - ;; -@@ -8780,6 +9105,7 @@ - IFS=$as_save_IFS - - ;; -+esac ;; - esac - fi - LLVM_PROFDATA=$ac_cv_path_LLVM_PROFDATA -@@ -8802,8 +9128,8 @@ - if test ${ac_cv_path_ac_pt_LLVM_PROFDATA+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- case $ac_pt_LLVM_PROFDATA in -+else case e in #( -+ e) case $ac_pt_LLVM_PROFDATA in - [\\/]* | ?:[\\/]*) - ac_cv_path_ac_pt_LLVM_PROFDATA="$ac_pt_LLVM_PROFDATA" # Let the user override the test with a path. - ;; -@@ -8828,6 +9154,7 @@ - IFS=$as_save_IFS - - ;; -+esac ;; - esac - fi - ac_pt_LLVM_PROFDATA=$ac_cv_path_ac_pt_LLVM_PROFDATA -@@ -8924,9 +9251,10 @@ - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 - printf "%s\n" "no" >&6; }; - fi --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 --printf "%s\n" "no" >&6; } -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -+printf "%s\n" "no" >&6; } ;; -+esac - fi - - -@@ -8943,8 +9271,8 @@ - if test ${ax_cv_check_cflags___fno_reorder_blocks_and_partition+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - ax_check_save_flags=$CFLAGS - CFLAGS="$CFLAGS -fno-reorder-blocks-and-partition" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -8961,11 +9289,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ax_cv_check_cflags___fno_reorder_blocks_and_partition=yes --else $as_nop -- ax_cv_check_cflags___fno_reorder_blocks_and_partition=no -+else case e in #( -+ e) ax_cv_check_cflags___fno_reorder_blocks_and_partition=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- CFLAGS=$ax_check_save_flags -+ CFLAGS=$ax_check_save_flags ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___fno_reorder_blocks_and_partition" >&5 - printf "%s\n" "$ax_cv_check_cflags___fno_reorder_blocks_and_partition" >&6; } -@@ -8974,8 +9304,9 @@ - - CFLAGS_NODIST="$CFLAGS_NODIST -fno-reorder-blocks-and-partition" - --else $as_nop -- : -+else case e in #( -+ e) : ;; -+esac - fi - - -@@ -8995,8 +9326,8 @@ - if test ${ac_cv_path_LLVM_BOLT+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- case $LLVM_BOLT in -+else case e in #( -+ e) case $LLVM_BOLT in - [\\/]* | ?:[\\/]*) - ac_cv_path_LLVM_BOLT="$LLVM_BOLT" # Let the user override the test with a path. - ;; -@@ -9021,6 +9352,7 @@ - IFS=$as_save_IFS - - ;; -+esac ;; - esac - fi - LLVM_BOLT=$ac_cv_path_LLVM_BOLT -@@ -9043,8 +9375,8 @@ - if test ${ac_cv_path_ac_pt_LLVM_BOLT+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- case $ac_pt_LLVM_BOLT in -+else case e in #( -+ e) case $ac_pt_LLVM_BOLT in - [\\/]* | ?:[\\/]*) - ac_cv_path_ac_pt_LLVM_BOLT="$ac_pt_LLVM_BOLT" # Let the user override the test with a path. - ;; -@@ -9069,6 +9401,7 @@ - IFS=$as_save_IFS - - ;; -+esac ;; - esac - fi - ac_pt_LLVM_BOLT=$ac_cv_path_ac_pt_LLVM_BOLT -@@ -9112,8 +9445,8 @@ - if test ${ac_cv_path_MERGE_FDATA+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- case $MERGE_FDATA in -+else case e in #( -+ e) case $MERGE_FDATA in - [\\/]* | ?:[\\/]*) - ac_cv_path_MERGE_FDATA="$MERGE_FDATA" # Let the user override the test with a path. - ;; -@@ -9138,6 +9471,7 @@ - IFS=$as_save_IFS - - ;; -+esac ;; - esac - fi - MERGE_FDATA=$ac_cv_path_MERGE_FDATA -@@ -9160,8 +9494,8 @@ - if test ${ac_cv_path_ac_pt_MERGE_FDATA+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- case $ac_pt_MERGE_FDATA in -+else case e in #( -+ e) case $ac_pt_MERGE_FDATA in - [\\/]* | ?:[\\/]*) - ac_cv_path_ac_pt_MERGE_FDATA="$ac_pt_MERGE_FDATA" # Let the user override the test with a path. - ;; -@@ -9186,6 +9520,7 @@ - IFS=$as_save_IFS - - ;; -+esac ;; - esac - fi - ac_pt_MERGE_FDATA=$ac_cv_path_ac_pt_MERGE_FDATA -@@ -9271,8 +9606,8 @@ - if test ${ac_cv_cc_supports_fstrict_overflow+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - int -@@ -9286,12 +9621,14 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_cc_supports_fstrict_overflow=yes --else $as_nop -- ac_cv_cc_supports_fstrict_overflow=no -- -+else case e in #( -+ e) ac_cv_cc_supports_fstrict_overflow=no -+ ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cc_supports_fstrict_overflow" >&5 - printf "%s\n" "$ac_cv_cc_supports_fstrict_overflow" >&6; } -@@ -9301,9 +9638,10 @@ - then : - STRICT_OVERFLOW_CFLAGS="-fstrict-overflow" - NO_STRICT_OVERFLOW_CFLAGS="-fno-strict-overflow" --else $as_nop -- STRICT_OVERFLOW_CFLAGS="" -- NO_STRICT_OVERFLOW_CFLAGS="" -+else case e in #( -+ e) STRICT_OVERFLOW_CFLAGS="" -+ NO_STRICT_OVERFLOW_CFLAGS="" ;; -+esac - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-strict-overflow" >&5 -@@ -9319,9 +9657,10 @@ - printf "%s\n" "$as_me: WARNING: --with-strict-overflow=yes requires a compiler that supports -fstrict-overflow" >&2;} - fi - --else $as_nop -- with_strict_overflow=no -- -+else case e in #( -+ e) with_strict_overflow=no -+ ;; -+esac - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_strict_overflow" >&5 -@@ -9335,8 +9674,8 @@ - if test ${ac_cv_cc_supports_og+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - -@@ -9354,13 +9693,15 @@ - - ac_cv_cc_supports_og=yes - --else $as_nop -- -+else case e in #( -+ e) - ac_cv_cc_supports_og=no -- -+ ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cc_supports_og" >&5 - printf "%s\n" "$ac_cv_cc_supports_og" >&6; } -@@ -9426,8 +9767,9 @@ - if test "x$Py_DEBUG" = xyes - then : - wasm_debug=yes --else $as_nop -- wasm_debug=no -+else case e in #( -+ e) wasm_debug=no ;; -+esac - fi - - as_fn_append LINKFORSHARED " -sALLOW_MEMORY_GROWTH -sINITIAL_MEMORY=20971520" -@@ -9436,7 +9778,7 @@ - - as_fn_append LINKFORSHARED " -sFORCE_FILESYSTEM -lidbfs.js -lnodefs.js -lproxyfs.js -lworkerfs.js" - as_fn_append LINKFORSHARED " -sEXPORTED_RUNTIME_METHODS=FS,callMain,ENV" -- as_fn_append LINKFORSHARED " -sEXPORTED_FUNCTIONS=_main,_Py_Version" -+ as_fn_append LINKFORSHARED " -sEXPORTED_FUNCTIONS=_main,_Py_Version,__PyRuntime,__PyEM_EMSCRIPTEN_COUNT_ARGS_OFFSET" - as_fn_append LINKFORSHARED " -sSTACK_SIZE=5MB" - - if test "x$enable_wasm_dynamic_linking" = xyes -@@ -9463,10 +9805,11 @@ - as_fn_append LDFLAGS_NODIST " -sASSERTIONS" - as_fn_append LINKFORSHARED " $WASM_LINKFORSHARED_DEBUG" - --else $as_nop -- -+else case e in #( -+ e) - as_fn_append LINKFORSHARED " -O2 -g0" -- -+ ;; -+esac - fi - ;; #( - WASI) : -@@ -9539,8 +9882,9 @@ - if test "x$with_strict_overflow" = xyes - then : - BASECFLAGS="$BASECFLAGS $STRICT_OVERFLOW_CFLAGS" --else $as_nop -- BASECFLAGS="$BASECFLAGS $NO_STRICT_OVERFLOW_CFLAGS" -+else case e in #( -+ e) BASECFLAGS="$BASECFLAGS $NO_STRICT_OVERFLOW_CFLAGS" ;; -+esac - fi - - # Enable flags that warn and protect for potential security vulnerabilities. -@@ -9554,11 +9898,13 @@ - enableval=$enable_safety; if test "x$disable_safety" = xyes - then : - enable_safety=no --else $as_nop -- enable_safety=yes -+else case e in #( -+ e) enable_safety=yes ;; -+esac - fi --else $as_nop -- enable_safety=no -+else case e in #( -+ e) enable_safety=no ;; -+esac - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_safety" >&5 -@@ -9571,8 +9917,8 @@ - if test ${ax_cv_check_cflags__Werror__fstack_protector_strong+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - ax_check_save_flags=$CFLAGS - CFLAGS="$CFLAGS -Werror -fstack-protector-strong" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -9589,20 +9935,23 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ax_cv_check_cflags__Werror__fstack_protector_strong=yes --else $as_nop -- ax_cv_check_cflags__Werror__fstack_protector_strong=no -+else case e in #( -+ e) ax_cv_check_cflags__Werror__fstack_protector_strong=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- CFLAGS=$ax_check_save_flags -+ CFLAGS=$ax_check_save_flags ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror__fstack_protector_strong" >&5 - printf "%s\n" "$ax_cv_check_cflags__Werror__fstack_protector_strong" >&6; } - if test "x$ax_cv_check_cflags__Werror__fstack_protector_strong" = xyes - then : - CFLAGS_NODIST="$CFLAGS_NODIST -fstack-protector-strong" --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -fstack-protector-strong not supported" >&5 --printf "%s\n" "$as_me: WARNING: -fstack-protector-strong not supported" >&2;} -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -fstack-protector-strong not supported" >&5 -+printf "%s\n" "$as_me: WARNING: -fstack-protector-strong not supported" >&2;} ;; -+esac - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -Wtrampolines" >&5 -@@ -9610,8 +9959,8 @@ - if test ${ax_cv_check_cflags__Werror__Wtrampolines+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - ax_check_save_flags=$CFLAGS - CFLAGS="$CFLAGS -Werror -Wtrampolines" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -9628,20 +9977,23 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ax_cv_check_cflags__Werror__Wtrampolines=yes --else $as_nop -- ax_cv_check_cflags__Werror__Wtrampolines=no -+else case e in #( -+ e) ax_cv_check_cflags__Werror__Wtrampolines=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- CFLAGS=$ax_check_save_flags -+ CFLAGS=$ax_check_save_flags ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror__Wtrampolines" >&5 - printf "%s\n" "$ax_cv_check_cflags__Werror__Wtrampolines" >&6; } - if test "x$ax_cv_check_cflags__Werror__Wtrampolines" = xyes - then : - CFLAGS_NODIST="$CFLAGS_NODIST -Wtrampolines" --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -Wtrampolines not supported" >&5 --printf "%s\n" "$as_me: WARNING: -Wtrampolines not supported" >&2;} -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -Wtrampolines not supported" >&5 -+printf "%s\n" "$as_me: WARNING: -Wtrampolines not supported" >&2;} ;; -+esac - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -Wimplicit-fallthrough" >&5 -@@ -9649,8 +10001,8 @@ - if test ${ax_cv_check_cflags__Werror__Wimplicit_fallthrough+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - ax_check_save_flags=$CFLAGS - CFLAGS="$CFLAGS -Werror -Wimplicit-fallthrough" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -9667,20 +10019,23 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ax_cv_check_cflags__Werror__Wimplicit_fallthrough=yes --else $as_nop -- ax_cv_check_cflags__Werror__Wimplicit_fallthrough=no -+else case e in #( -+ e) ax_cv_check_cflags__Werror__Wimplicit_fallthrough=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- CFLAGS=$ax_check_save_flags -+ CFLAGS=$ax_check_save_flags ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror__Wimplicit_fallthrough" >&5 - printf "%s\n" "$ax_cv_check_cflags__Werror__Wimplicit_fallthrough" >&6; } - if test "x$ax_cv_check_cflags__Werror__Wimplicit_fallthrough" = xyes - then : - CFLAGS_NODIST="$CFLAGS_NODIST -Wimplicit-fallthrough" --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -Wimplicit-fallthrough not supported" >&5 --printf "%s\n" "$as_me: WARNING: -Wimplicit-fallthrough not supported" >&2;} -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -Wimplicit-fallthrough not supported" >&5 -+printf "%s\n" "$as_me: WARNING: -Wimplicit-fallthrough not supported" >&2;} ;; -+esac - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -Werror=format-security" >&5 -@@ -9688,8 +10043,8 @@ - if test ${ax_cv_check_cflags__Werror__Werror_format_security+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - ax_check_save_flags=$CFLAGS - CFLAGS="$CFLAGS -Werror -Werror=format-security" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -9706,20 +10061,23 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ax_cv_check_cflags__Werror__Werror_format_security=yes --else $as_nop -- ax_cv_check_cflags__Werror__Werror_format_security=no -+else case e in #( -+ e) ax_cv_check_cflags__Werror__Werror_format_security=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- CFLAGS=$ax_check_save_flags -+ CFLAGS=$ax_check_save_flags ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror__Werror_format_security" >&5 - printf "%s\n" "$ax_cv_check_cflags__Werror__Werror_format_security" >&6; } - if test "x$ax_cv_check_cflags__Werror__Werror_format_security" = xyes - then : - CFLAGS_NODIST="$CFLAGS_NODIST -Werror=format-security" --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -Werror=format-security not supported" >&5 --printf "%s\n" "$as_me: WARNING: -Werror=format-security not supported" >&2;} -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -Werror=format-security not supported" >&5 -+printf "%s\n" "$as_me: WARNING: -Werror=format-security not supported" >&2;} ;; -+esac - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -Wbidi-chars=any" >&5 -@@ -9727,8 +10085,8 @@ - if test ${ax_cv_check_cflags__Werror__Wbidi_chars_any+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - ax_check_save_flags=$CFLAGS - CFLAGS="$CFLAGS -Werror -Wbidi-chars=any" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -9745,20 +10103,23 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ax_cv_check_cflags__Werror__Wbidi_chars_any=yes --else $as_nop -- ax_cv_check_cflags__Werror__Wbidi_chars_any=no -+else case e in #( -+ e) ax_cv_check_cflags__Werror__Wbidi_chars_any=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- CFLAGS=$ax_check_save_flags -+ CFLAGS=$ax_check_save_flags ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror__Wbidi_chars_any" >&5 - printf "%s\n" "$ax_cv_check_cflags__Werror__Wbidi_chars_any" >&6; } - if test "x$ax_cv_check_cflags__Werror__Wbidi_chars_any" = xyes - then : - CFLAGS_NODIST="$CFLAGS_NODIST -Wbidi-chars=any" --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -Wbidi-chars=any not supported" >&5 --printf "%s\n" "$as_me: WARNING: -Wbidi-chars=any not supported" >&2;} -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -Wbidi-chars=any not supported" >&5 -+printf "%s\n" "$as_me: WARNING: -Wbidi-chars=any not supported" >&2;} ;; -+esac - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -Wall" >&5 -@@ -9766,8 +10127,8 @@ - if test ${ax_cv_check_cflags__Werror__Wall+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - ax_check_save_flags=$CFLAGS - CFLAGS="$CFLAGS -Werror -Wall" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -9784,20 +10145,23 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ax_cv_check_cflags__Werror__Wall=yes --else $as_nop -- ax_cv_check_cflags__Werror__Wall=no -+else case e in #( -+ e) ax_cv_check_cflags__Werror__Wall=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- CFLAGS=$ax_check_save_flags -+ CFLAGS=$ax_check_save_flags ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror__Wall" >&5 - printf "%s\n" "$ax_cv_check_cflags__Werror__Wall" >&6; } - if test "x$ax_cv_check_cflags__Werror__Wall" = xyes - then : - CFLAGS_NODIST="$CFLAGS_NODIST -Wall" --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -Wall not supported" >&5 --printf "%s\n" "$as_me: WARNING: -Wall not supported" >&2;} -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -Wall not supported" >&5 -+printf "%s\n" "$as_me: WARNING: -Wall not supported" >&2;} ;; -+esac - fi - - fi -@@ -9810,11 +10174,13 @@ - enableval=$enable_slower_safety; if test "x$disable_slower_safety" = xyes - then : - enable_slower_safety=no --else $as_nop -- enable_slower_safety=yes -+else case e in #( -+ e) enable_slower_safety=yes ;; -+esac - fi --else $as_nop -- enable_slower_safety=no -+else case e in #( -+ e) enable_slower_safety=no ;; -+esac - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_slower_safety" >&5 -@@ -9827,8 +10193,8 @@ - if test ${ax_cv_check_cflags__Werror__D_FORTIFY_SOURCE_3+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - ax_check_save_flags=$CFLAGS - CFLAGS="$CFLAGS -Werror -D_FORTIFY_SOURCE=3" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -9845,20 +10211,23 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ax_cv_check_cflags__Werror__D_FORTIFY_SOURCE_3=yes --else $as_nop -- ax_cv_check_cflags__Werror__D_FORTIFY_SOURCE_3=no -+else case e in #( -+ e) ax_cv_check_cflags__Werror__D_FORTIFY_SOURCE_3=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- CFLAGS=$ax_check_save_flags -+ CFLAGS=$ax_check_save_flags ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror__D_FORTIFY_SOURCE_3" >&5 - printf "%s\n" "$ax_cv_check_cflags__Werror__D_FORTIFY_SOURCE_3" >&6; } - if test "x$ax_cv_check_cflags__Werror__D_FORTIFY_SOURCE_3" = xyes - then : - CFLAGS_NODIST="$CFLAGS_NODIST -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3" --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -D_FORTIFY_SOURCE=3 not supported" >&5 --printf "%s\n" "$as_me: WARNING: -D_FORTIFY_SOURCE=3 not supported" >&2;} -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: -D_FORTIFY_SOURCE=3 not supported" >&5 -+printf "%s\n" "$as_me: WARNING: -D_FORTIFY_SOURCE=3 not supported" >&2;} ;; -+esac - fi - - fi -@@ -9875,8 +10244,8 @@ - if test ${ac_cv_enable_extra_warning+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - py_cflags=$CFLAGS - as_fn_append CFLAGS " -Wextra -Werror" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -9893,12 +10262,14 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_enable_extra_warning=yes --else $as_nop -- ac_cv_enable_extra_warning=no -+else case e in #( -+ e) ac_cv_enable_extra_warning=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - CFLAGS=$py_cflags -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_enable_extra_warning" >&5 - printf "%s\n" "$ac_cv_enable_extra_warning" >&6; } -@@ -9921,8 +10292,8 @@ - if test ${ac_cv_no_strict_aliasing+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - -@@ -9958,19 +10329,22 @@ - - ac_cv_no_strict_aliasing=no - --else $as_nop -- -+else case e in #( -+ e) - ac_cv_no_strict_aliasing=yes -- -+ ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - --else $as_nop -- -+else case e in #( -+ e) - ac_cv_no_strict_aliasing=no -- -+ ;; -+esac - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_no_strict_aliasing" >&5 - printf "%s\n" "$ac_cv_no_strict_aliasing" >&6; } -@@ -9993,8 +10367,8 @@ - if test ${ac_cv_disable_unused_result_warning+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - py_cflags=$CFLAGS - as_fn_append CFLAGS " -Wunused-result -Werror" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -10011,12 +10385,14 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_disable_unused_result_warning=yes --else $as_nop -- ac_cv_disable_unused_result_warning=no -+else case e in #( -+ e) ac_cv_disable_unused_result_warning=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - CFLAGS=$py_cflags -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_disable_unused_result_warning" >&5 - printf "%s\n" "$ac_cv_disable_unused_result_warning" >&6; } -@@ -10038,8 +10414,8 @@ - if test ${ac_cv_disable_unused_parameter_warning+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - py_cflags=$CFLAGS - as_fn_append CFLAGS " -Wunused-parameter -Werror" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -10056,12 +10432,14 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_disable_unused_parameter_warning=yes --else $as_nop -- ac_cv_disable_unused_parameter_warning=no -+else case e in #( -+ e) ac_cv_disable_unused_parameter_warning=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - CFLAGS=$py_cflags -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_disable_unused_parameter_warning" >&5 - printf "%s\n" "$ac_cv_disable_unused_parameter_warning" >&6; } -@@ -10079,8 +10457,8 @@ - if test ${ac_cv_disable_int_conversion_warning+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - py_cflags=$CFLAGS - as_fn_append CFLAGS " -Wint-conversion -Werror" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -10097,12 +10475,14 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_disable_int_conversion_warning=yes --else $as_nop -- ac_cv_disable_int_conversion_warning=no -+else case e in #( -+ e) ac_cv_disable_int_conversion_warning=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - CFLAGS=$py_cflags -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_disable_int_conversion_warning" >&5 - printf "%s\n" "$ac_cv_disable_int_conversion_warning" >&6; } -@@ -10120,8 +10500,8 @@ - if test ${ac_cv_disable_missing_field_initializers_warning+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - py_cflags=$CFLAGS - as_fn_append CFLAGS " -Wmissing-field-initializers -Werror" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -10138,12 +10518,14 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_disable_missing_field_initializers_warning=yes --else $as_nop -- ac_cv_disable_missing_field_initializers_warning=no -+else case e in #( -+ e) ac_cv_disable_missing_field_initializers_warning=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - CFLAGS=$py_cflags -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_disable_missing_field_initializers_warning" >&5 - printf "%s\n" "$ac_cv_disable_missing_field_initializers_warning" >&6; } -@@ -10161,8 +10543,8 @@ - if test ${ac_cv_enable_sign_compare_warning+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - py_cflags=$CFLAGS - as_fn_append CFLAGS " -Wsign-compare -Werror" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -10179,12 +10561,14 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_enable_sign_compare_warning=yes --else $as_nop -- ac_cv_enable_sign_compare_warning=no -+else case e in #( -+ e) ac_cv_enable_sign_compare_warning=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - CFLAGS=$py_cflags -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_enable_sign_compare_warning" >&5 - printf "%s\n" "$ac_cv_enable_sign_compare_warning" >&6; } -@@ -10202,8 +10586,8 @@ - if test ${ac_cv_enable_unreachable_code_warning+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - py_cflags=$CFLAGS - as_fn_append CFLAGS " -Wunreachable-code -Werror" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -10220,12 +10604,14 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_enable_unreachable_code_warning=yes --else $as_nop -- ac_cv_enable_unreachable_code_warning=no -+else case e in #( -+ e) ac_cv_enable_unreachable_code_warning=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - CFLAGS=$py_cflags -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_enable_unreachable_code_warning" >&5 - printf "%s\n" "$ac_cv_enable_unreachable_code_warning" >&6; } -@@ -10254,8 +10640,8 @@ - if test ${ac_cv_enable_strict_prototypes_warning+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - py_cflags=$CFLAGS - as_fn_append CFLAGS " -Wstrict-prototypes -Werror" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -10272,12 +10658,14 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_enable_strict_prototypes_warning=yes --else $as_nop -- ac_cv_enable_strict_prototypes_warning=no -+else case e in #( -+ e) ac_cv_enable_strict_prototypes_warning=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - CFLAGS=$py_cflags -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_enable_strict_prototypes_warning" >&5 - printf "%s\n" "$ac_cv_enable_strict_prototypes_warning" >&6; } -@@ -10295,8 +10683,8 @@ - if test ${ac_cv_enable_implicit_function_declaration_error+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - -@@ -10314,12 +10702,14 @@ - - ac_cv_enable_implicit_function_declaration_error=yes - --else $as_nop -- -+else case e in #( -+ e) - ac_cv_enable_implicit_function_declaration_error=no -- -+ ;; -+esac - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_enable_implicit_function_declaration_error" >&5 - printf "%s\n" "$ac_cv_enable_implicit_function_declaration_error" >&6; } -@@ -10337,8 +10727,8 @@ - if test ${ac_cv_enable_visibility+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - -@@ -10356,12 +10746,14 @@ - - ac_cv_enable_visibility=yes - --else $as_nop -- -+else case e in #( -+ e) - ac_cv_enable_visibility=no -- -+ ;; -+esac - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_enable_visibility" >&5 - printf "%s\n" "$ac_cv_enable_visibility" >&6; } -@@ -10403,25 +10795,69 @@ - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 - printf "%s\n" "$CC" >&6; } - -- LIPO_INTEL64_FLAGS="" -- if test "${enable_universalsdk}" -- then -- case "$UNIVERSAL_ARCHS" in -- 32-bit) -- UNIVERSAL_ARCH_FLAGS="-arch ppc -arch i386" -- LIPO_32BIT_FLAGS="" -- ARCH_RUN_32BIT="" -- ;; -- 64-bit) -- UNIVERSAL_ARCH_FLAGS="-arch ppc64 -arch x86_64" -- LIPO_32BIT_FLAGS="" -- ARCH_RUN_32BIT="true" -- ;; -- all) -- UNIVERSAL_ARCH_FLAGS="-arch i386 -arch ppc -arch ppc64 -arch x86_64" -- LIPO_32BIT_FLAGS="-extract ppc7400 -extract i386" -- ARCH_RUN_32BIT="/usr/bin/arch -i386 -ppc" -- ;; -+ # Error on unguarded use of new symbols, which will fail at runtime for -+ # users on older versions of macOS -+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -Wunguarded-availability" >&5 -+printf %s "checking whether C compiler accepts -Wunguarded-availability... " >&6; } -+if test ${ax_cv_check_cflags__Werror__Wunguarded_availability+y} -+then : -+ printf %s "(cached) " >&6 -+else case e in #( -+ e) -+ ax_check_save_flags=$CFLAGS -+ CFLAGS="$CFLAGS -Werror -Wunguarded-availability" -+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+/* end confdefs.h. */ -+ -+int -+main (void) -+{ -+ -+ ; -+ return 0; -+} -+_ACEOF -+if ac_fn_c_try_compile "$LINENO" -+then : -+ ax_cv_check_cflags__Werror__Wunguarded_availability=yes -+else case e in #( -+ e) ax_cv_check_cflags__Werror__Wunguarded_availability=no ;; -+esac -+fi -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+ CFLAGS=$ax_check_save_flags ;; -+esac -+fi -+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror__Wunguarded_availability" >&5 -+printf "%s\n" "$ax_cv_check_cflags__Werror__Wunguarded_availability" >&6; } -+if test "x$ax_cv_check_cflags__Werror__Wunguarded_availability" = xyes -+then : -+ as_fn_append CFLAGS_NODIST " -Werror=unguarded-availability" -+else case e in #( -+ e) : ;; -+esac -+fi -+ -+ -+ LIPO_INTEL64_FLAGS="" -+ if test "${enable_universalsdk}" -+ then -+ case "$UNIVERSAL_ARCHS" in -+ 32-bit) -+ UNIVERSAL_ARCH_FLAGS="-arch ppc -arch i386" -+ LIPO_32BIT_FLAGS="" -+ ARCH_RUN_32BIT="" -+ ;; -+ 64-bit) -+ UNIVERSAL_ARCH_FLAGS="-arch ppc64 -arch x86_64" -+ LIPO_32BIT_FLAGS="" -+ ARCH_RUN_32BIT="true" -+ ;; -+ all) -+ UNIVERSAL_ARCH_FLAGS="-arch i386 -arch ppc -arch ppc64 -arch x86_64" -+ LIPO_32BIT_FLAGS="-extract ppc7400 -extract i386" -+ ARCH_RUN_32BIT="/usr/bin/arch -i386 -ppc" -+ ;; - universal2) - UNIVERSAL_ARCH_FLAGS="-arch arm64 -arch x86_64" - LIPO_32BIT_FLAGS="" -@@ -10535,11 +10971,12 @@ - then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 - printf "%s\n" "yes" >&6; } --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 - printf "%s\n" "no" >&6; } - as_fn_error $? "check config.log and use the '--with-universal-archs' option" "$LINENO" 5 -- -+ ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -@@ -10548,8 +10985,8 @@ - ;; - esac - --else $as_nop -- -+else case e in #( -+ e) - case $ac_sys_system in - OpenUNIX*|UnixWare*) - BASECFLAGS="$BASECFLAGS -K pentium,host,inline,loop_unroll,alloca " -@@ -10558,7 +10995,8 @@ - BASECFLAGS="$BASECFLAGS -belf -Ki486 -DSCO5" - ;; - esac -- -+ ;; -+esac - fi - - case "$ac_cv_cc_name" in -@@ -10595,12 +11033,12 @@ - if test ${ac_cv_pthread_is_default+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test "$cross_compiling" = yes -+else case e in #( -+ e) if test "$cross_compiling" = yes - then : - ac_cv_pthread_is_default=no --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -10624,14 +11062,17 @@ - ac_cv_kthread=no - ac_cv_pthread=no - --else $as_nop -- ac_cv_pthread_is_default=no -+else case e in #( -+ e) ac_cv_pthread_is_default=no ;; -+esac - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext -+ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_pthread_is_default" >&5 - printf "%s\n" "$ac_cv_pthread_is_default" >&6; } -@@ -10651,14 +11092,14 @@ - if test ${ac_cv_kpthread+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_save_cc="$CC" -+else case e in #( -+ e) ac_save_cc="$CC" - CC="$CC -Kpthread" - if test "$cross_compiling" = yes - then : - ac_cv_kpthread=no --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -10678,14 +11119,17 @@ - if ac_fn_c_try_run "$LINENO" - then : - ac_cv_kpthread=yes --else $as_nop -- ac_cv_kpthread=no -+else case e in #( -+ e) ac_cv_kpthread=no ;; -+esac - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext -+ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - --CC="$ac_save_cc" -+CC="$ac_save_cc" ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_kpthread" >&5 - printf "%s\n" "$ac_cv_kpthread" >&6; } -@@ -10703,14 +11147,14 @@ - if test ${ac_cv_kthread+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_save_cc="$CC" -+else case e in #( -+ e) ac_save_cc="$CC" - CC="$CC -Kthread" - if test "$cross_compiling" = yes - then : - ac_cv_kthread=no --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -10730,14 +11174,17 @@ - if ac_fn_c_try_run "$LINENO" - then : - ac_cv_kthread=yes --else $as_nop -- ac_cv_kthread=no -+else case e in #( -+ e) ac_cv_kthread=no ;; -+esac - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext -+ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - --CC="$ac_save_cc" -+CC="$ac_save_cc" ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_kthread" >&5 - printf "%s\n" "$ac_cv_kthread" >&6; } -@@ -10755,14 +11202,14 @@ - if test ${ac_cv_pthread+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_save_cc="$CC" -+else case e in #( -+ e) ac_save_cc="$CC" - CC="$CC -pthread" - if test "$cross_compiling" = yes - then : - ac_cv_pthread=no --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -10782,14 +11229,17 @@ - if ac_fn_c_try_run "$LINENO" - then : - ac_cv_pthread=yes --else $as_nop -- ac_cv_pthread=no -+else case e in #( -+ e) ac_cv_pthread=no ;; -+esac - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext -+ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - --CC="$ac_save_cc" -+CC="$ac_save_cc" ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_pthread" >&5 - printf "%s\n" "$ac_cv_pthread" >&6; } -@@ -10804,8 +11254,8 @@ - if test ${ac_cv_cxx_thread+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_save_cxx="$CXX" -+else case e in #( -+ e) ac_save_cxx="$CXX" - - if test "$ac_cv_kpthread" = "yes" - then -@@ -10836,7 +11286,8 @@ - fi - rm -fr conftest* - fi --CXX="$ac_save_cxx" -+CXX="$ac_save_cxx" ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_thread" >&5 - printf "%s\n" "$ac_cv_cxx_thread" >&6; } -@@ -10981,6 +11432,12 @@ - then : - printf "%s\n" "#define HAVE_LINUX_SOUNDCARD_H 1" >>confdefs.h - -+fi -+ac_fn_c_check_header_compile "$LINENO" "linux/sched.h" "ac_cv_header_linux_sched_h" "$ac_includes_default" -+if test "x$ac_cv_header_linux_sched_h" = xyes -+then : -+ printf "%s\n" "#define HAVE_LINUX_SCHED_H 1" >>confdefs.h -+ - fi - ac_fn_c_check_header_compile "$LINENO" "linux/tipc.h" "ac_cv_header_linux_tipc_h" "$ac_includes_default" - if test "x$ac_cv_header_linux_tipc_h" = xyes -@@ -11179,12 +11636,6 @@ - then : - printf "%s\n" "#define HAVE_SYS_PARAM_H 1" >>confdefs.h - --fi --ac_fn_c_check_header_compile "$LINENO" "sys/pidfd.h" "ac_cv_header_sys_pidfd_h" "$ac_includes_default" --if test "x$ac_cv_header_sys_pidfd_h" = xyes --then : -- printf "%s\n" "#define HAVE_SYS_PIDFD_H 1" >>confdefs.h -- - fi - ac_fn_c_check_header_compile "$LINENO" "sys/poll.h" "ac_cv_header_sys_poll_h" "$ac_includes_default" - if test "x$ac_cv_header_sys_poll_h" = xyes -@@ -11357,14 +11808,14 @@ - - ac_header_dirent=no - for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do -- as_ac_Header=`printf "%s\n" "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` -+ as_ac_Header=`printf "%s\n" "ac_cv_header_dirent_$ac_hdr" | sed "$as_sed_sh"` - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 - printf %s "checking for $ac_hdr that defines DIR... " >&6; } - if eval test \${$as_ac_Header+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - #include <$ac_hdr> -@@ -11381,10 +11832,12 @@ - if ac_fn_c_try_compile "$LINENO" - then : - eval "$as_ac_Header=yes" --else $as_nop -- eval "$as_ac_Header=no" -+else case e in #( -+ e) eval "$as_ac_Header=no" ;; -+esac - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - eval ac_res=\$$as_ac_Header - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -@@ -11392,7 +11845,7 @@ - if eval test \"x\$"$as_ac_Header"\" = x"yes" - then : - cat >>confdefs.h <<_ACEOF --#define `printf "%s\n" "HAVE_$ac_hdr" | $as_tr_cpp` 1 -+#define `printf "%s\n" "HAVE_$ac_hdr" | sed "$as_sed_cpp"` 1 - _ACEOF - - ac_header_dirent=$ac_hdr; break -@@ -11406,15 +11859,21 @@ - if test ${ac_cv_search_opendir+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_func_search_save_LIBS=$LIBS -+else case e in #( -+ e) ac_func_search_save_LIBS=$LIBS - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char opendir (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char opendir (void); - int - main (void) - { -@@ -11445,11 +11904,13 @@ - if test ${ac_cv_search_opendir+y} - then : - --else $as_nop -- ac_cv_search_opendir=no -+else case e in #( -+ e) ac_cv_search_opendir=no ;; -+esac - fi - rm conftest.$ac_ext --LIBS=$ac_func_search_save_LIBS -+LIBS=$ac_func_search_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 - printf "%s\n" "$ac_cv_search_opendir" >&6; } -@@ -11466,15 +11927,21 @@ - if test ${ac_cv_search_opendir+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_func_search_save_LIBS=$LIBS -+else case e in #( -+ e) ac_func_search_save_LIBS=$LIBS - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char opendir (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char opendir (void); - int - main (void) - { -@@ -11505,11 +11972,13 @@ - if test ${ac_cv_search_opendir+y} - then : - --else $as_nop -- ac_cv_search_opendir=no -+else case e in #( -+ e) ac_cv_search_opendir=no ;; -+esac - fi - rm conftest.$ac_ext --LIBS=$ac_func_search_save_LIBS -+LIBS=$ac_func_search_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 - printf "%s\n" "$ac_cv_search_opendir" >&6; } -@@ -11702,10 +12171,11 @@ - printf "%s\n" "#define HAVE_CLOCK_T 1" >>confdefs.h - - --else $as_nop -- -+else case e in #( -+ e) - printf "%s\n" "#define clock_t long" >>confdefs.h -- -+ ;; -+esac - fi - - -@@ -11714,8 +12184,8 @@ - if test ${ac_cv_func_makedev+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - -@@ -11740,12 +12210,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_func_makedev=yes --else $as_nop -- ac_cv_func_makedev=no -+else case e in #( -+ e) ac_cv_func_makedev=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_makedev" >&5 - printf "%s\n" "$ac_cv_func_makedev" >&6; } -@@ -11765,8 +12237,8 @@ - if test ${ac_cv_func_le64toh+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - -@@ -11789,12 +12261,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_func_le64toh=yes --else $as_nop -- ac_cv_func_le64toh=no -+else case e in #( -+ e) ac_cv_func_le64toh=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_le64toh" >&5 - printf "%s\n" "$ac_cv_func_le64toh" >&6; } -@@ -11844,20 +12318,22 @@ - if test "x$ac_cv_type_mode_t" = xyes - then : - --else $as_nop -- -+else case e in #( -+ e) - printf "%s\n" "#define mode_t int" >>confdefs.h -- -+ ;; -+esac - fi - - ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" - if test "x$ac_cv_type_off_t" = xyes - then : - --else $as_nop -- -+else case e in #( -+ e) - printf "%s\n" "#define off_t long int" >>confdefs.h -- -+ ;; -+esac - fi - - -@@ -11866,8 +12342,8 @@ - if test "x$ac_cv_type_pid_t" = xyes - then : - --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #if defined _WIN64 && !defined __CYGWIN__ -@@ -11886,14 +12362,16 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_pid_type='int' --else $as_nop -- ac_pid_type='__int64' -+else case e in #( -+ e) ac_pid_type='__int64' ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - - printf "%s\n" "#define pid_t $ac_pid_type" >>confdefs.h - -- -+ ;; -+esac - fi - - -@@ -11904,42 +12382,33 @@ - if test "x$ac_cv_type_size_t" = xyes - then : - --else $as_nop -- -+else case e in #( -+ e) - printf "%s\n" "#define size_t unsigned int" >>confdefs.h -- -+ ;; -+esac - fi - --{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 --printf %s "checking for uid_t in sys/types.h... " >&6; } --if test ${ac_cv_type_uid_t+y} -+ac_fn_c_check_type "$LINENO" "uid_t" "ac_cv_type_uid_t" "$ac_includes_default" -+if test "x$ac_cv_type_uid_t" = xyes - then : -- printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext --/* end confdefs.h. */ --#include -- --_ACEOF --if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | -- $EGREP "uid_t" >/dev/null 2>&1 --then : -- ac_cv_type_uid_t=yes --else $as_nop -- ac_cv_type_uid_t=no --fi --rm -rf conftest* -- --fi --{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5 --printf "%s\n" "$ac_cv_type_uid_t" >&6; } --if test $ac_cv_type_uid_t = no; then - -+else case e in #( -+ e) - printf "%s\n" "#define uid_t int" >>confdefs.h -+ ;; -+esac -+fi - -+ac_fn_c_check_type "$LINENO" "gid_t" "ac_cv_type_gid_t" "$ac_includes_default" -+if test "x$ac_cv_type_gid_t" = xyes -+then : - -+else case e in #( -+ e) - printf "%s\n" "#define gid_t int" >>confdefs.h -- -+ ;; -+esac - fi - - -@@ -11968,28 +12437,30 @@ - # ANSI C requires sizeof(char) == 1, so no need to check it - # The cast to long int works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects --# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -+# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 - printf %s "checking size of int... " >&6; } - if test ${ac_cv_sizeof_int+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default" -+else case e in #( -+ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default" - then : - --else $as_nop -- if test "$ac_cv_type_int" = yes; then -- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+else case e in #( -+ e) if test "$ac_cv_type_int" = yes; then -+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error 77 "cannot compute sizeof (int) --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_int=0 -- fi -+ fi ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5 - printf "%s\n" "$ac_cv_sizeof_int" >&6; } -@@ -12001,28 +12472,30 @@ - - # The cast to long int works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects --# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -+# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 - printf %s "checking size of long... " >&6; } - if test ${ac_cv_sizeof_long+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default" -+else case e in #( -+ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default" - then : - --else $as_nop -- if test "$ac_cv_type_long" = yes; then -- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+else case e in #( -+ e) if test "$ac_cv_type_long" = yes; then -+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error 77 "cannot compute sizeof (long) --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_long=0 -- fi -+ fi ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 - printf "%s\n" "$ac_cv_sizeof_long" >&6; } -@@ -12039,22 +12512,24 @@ - if test ${ac_cv_alignof_long+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if ac_fn_c_compute_int "$LINENO" "(long int) offsetof (ac__type_alignof_, y)" "ac_cv_alignof_long" "$ac_includes_default -+else case e in #( -+ e) if ac_fn_c_compute_int "$LINENO" "(long int) offsetof (ac__type_alignof_, y)" "ac_cv_alignof_long" "$ac_includes_default - typedef struct { char x; long y; } ac__type_alignof_;" - then : - --else $as_nop -- if test "$ac_cv_type_long" = yes; then -- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+else case e in #( -+ e) if test "$ac_cv_type_long" = yes; then -+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error 77 "cannot compute alignment of long --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } - else - ac_cv_alignof_long=0 -- fi -+ fi ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_alignof_long" >&5 - printf "%s\n" "$ac_cv_alignof_long" >&6; } -@@ -12066,28 +12541,30 @@ - - # The cast to long int works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects --# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -+# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5 - printf %s "checking size of long long... " >&6; } - if test ${ac_cv_sizeof_long_long+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default" -+else case e in #( -+ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default" - then : - --else $as_nop -- if test "$ac_cv_type_long_long" = yes; then -- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+else case e in #( -+ e) if test "$ac_cv_type_long_long" = yes; then -+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error 77 "cannot compute sizeof (long long) --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_long_long=0 -- fi -+ fi ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_long" >&5 - printf "%s\n" "$ac_cv_sizeof_long_long" >&6; } -@@ -12099,28 +12576,30 @@ - - # The cast to long int works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects --# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -+# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 - printf %s "checking size of void *... " >&6; } - if test ${ac_cv_sizeof_void_p+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default" -+else case e in #( -+ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default" - then : - --else $as_nop -- if test "$ac_cv_type_void_p" = yes; then -- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+else case e in #( -+ e) if test "$ac_cv_type_void_p" = yes; then -+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error 77 "cannot compute sizeof (void *) --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_void_p=0 -- fi -+ fi ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 - printf "%s\n" "$ac_cv_sizeof_void_p" >&6; } -@@ -12132,28 +12611,30 @@ - - # The cast to long int works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects --# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -+# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of short" >&5 - printf %s "checking size of short... " >&6; } - if test ${ac_cv_sizeof_short+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default" -+else case e in #( -+ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default" - then : - --else $as_nop -- if test "$ac_cv_type_short" = yes; then -- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+else case e in #( -+ e) if test "$ac_cv_type_short" = yes; then -+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error 77 "cannot compute sizeof (short) --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_short=0 -- fi -+ fi ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_short" >&5 - printf "%s\n" "$ac_cv_sizeof_short" >&6; } -@@ -12165,28 +12646,30 @@ - - # The cast to long int works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects --# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -+# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of float" >&5 - printf %s "checking size of float... " >&6; } - if test ${ac_cv_sizeof_float+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (float))" "ac_cv_sizeof_float" "$ac_includes_default" -+else case e in #( -+ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (float))" "ac_cv_sizeof_float" "$ac_includes_default" - then : - --else $as_nop -- if test "$ac_cv_type_float" = yes; then -- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+else case e in #( -+ e) if test "$ac_cv_type_float" = yes; then -+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error 77 "cannot compute sizeof (float) --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_float=0 -- fi -+ fi ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_float" >&5 - printf "%s\n" "$ac_cv_sizeof_float" >&6; } -@@ -12198,28 +12681,30 @@ - - # The cast to long int works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects --# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -+# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of double" >&5 - printf %s "checking size of double... " >&6; } - if test ${ac_cv_sizeof_double+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (double))" "ac_cv_sizeof_double" "$ac_includes_default" -+else case e in #( -+ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (double))" "ac_cv_sizeof_double" "$ac_includes_default" - then : - --else $as_nop -- if test "$ac_cv_type_double" = yes; then -- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+else case e in #( -+ e) if test "$ac_cv_type_double" = yes; then -+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error 77 "cannot compute sizeof (double) --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_double=0 -- fi -+ fi ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_double" >&5 - printf "%s\n" "$ac_cv_sizeof_double" >&6; } -@@ -12231,28 +12716,30 @@ - - # The cast to long int works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects --# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -+# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of fpos_t" >&5 - printf %s "checking size of fpos_t... " >&6; } - if test ${ac_cv_sizeof_fpos_t+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (fpos_t))" "ac_cv_sizeof_fpos_t" "$ac_includes_default" -+else case e in #( -+ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (fpos_t))" "ac_cv_sizeof_fpos_t" "$ac_includes_default" - then : - --else $as_nop -- if test "$ac_cv_type_fpos_t" = yes; then -- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+else case e in #( -+ e) if test "$ac_cv_type_fpos_t" = yes; then -+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error 77 "cannot compute sizeof (fpos_t) --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_fpos_t=0 -- fi -+ fi ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_fpos_t" >&5 - printf "%s\n" "$ac_cv_sizeof_fpos_t" >&6; } -@@ -12264,28 +12751,30 @@ - - # The cast to long int works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects --# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -+# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of size_t" >&5 - printf %s "checking size of size_t... " >&6; } - if test ${ac_cv_sizeof_size_t+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (size_t))" "ac_cv_sizeof_size_t" "$ac_includes_default" -+else case e in #( -+ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (size_t))" "ac_cv_sizeof_size_t" "$ac_includes_default" - then : - --else $as_nop -- if test "$ac_cv_type_size_t" = yes; then -- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+else case e in #( -+ e) if test "$ac_cv_type_size_t" = yes; then -+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error 77 "cannot compute sizeof (size_t) --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_size_t=0 -- fi -+ fi ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_size_t" >&5 - printf "%s\n" "$ac_cv_sizeof_size_t" >&6; } -@@ -12302,22 +12791,24 @@ - if test ${ac_cv_alignof_size_t+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if ac_fn_c_compute_int "$LINENO" "(long int) offsetof (ac__type_alignof_, y)" "ac_cv_alignof_size_t" "$ac_includes_default -+else case e in #( -+ e) if ac_fn_c_compute_int "$LINENO" "(long int) offsetof (ac__type_alignof_, y)" "ac_cv_alignof_size_t" "$ac_includes_default - typedef struct { char x; size_t y; } ac__type_alignof_;" - then : - --else $as_nop -- if test "$ac_cv_type_size_t" = yes; then -- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+else case e in #( -+ e) if test "$ac_cv_type_size_t" = yes; then -+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error 77 "cannot compute alignment of size_t --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } - else - ac_cv_alignof_size_t=0 -- fi -+ fi ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_alignof_size_t" >&5 - printf "%s\n" "$ac_cv_alignof_size_t" >&6; } -@@ -12329,28 +12820,30 @@ - - # The cast to long int works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects --# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -+# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of pid_t" >&5 - printf %s "checking size of pid_t... " >&6; } - if test ${ac_cv_sizeof_pid_t+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pid_t))" "ac_cv_sizeof_pid_t" "$ac_includes_default" -+else case e in #( -+ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pid_t))" "ac_cv_sizeof_pid_t" "$ac_includes_default" - then : - --else $as_nop -- if test "$ac_cv_type_pid_t" = yes; then -- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+else case e in #( -+ e) if test "$ac_cv_type_pid_t" = yes; then -+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error 77 "cannot compute sizeof (pid_t) --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_pid_t=0 -- fi -+ fi ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_pid_t" >&5 - printf "%s\n" "$ac_cv_sizeof_pid_t" >&6; } -@@ -12362,28 +12855,30 @@ - - # The cast to long int works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects --# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -+# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of uintptr_t" >&5 - printf %s "checking size of uintptr_t... " >&6; } - if test ${ac_cv_sizeof_uintptr_t+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (uintptr_t))" "ac_cv_sizeof_uintptr_t" "$ac_includes_default" -+else case e in #( -+ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (uintptr_t))" "ac_cv_sizeof_uintptr_t" "$ac_includes_default" - then : - --else $as_nop -- if test "$ac_cv_type_uintptr_t" = yes; then -- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+else case e in #( -+ e) if test "$ac_cv_type_uintptr_t" = yes; then -+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error 77 "cannot compute sizeof (uintptr_t) --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_uintptr_t=0 -- fi -+ fi ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_uintptr_t" >&5 - printf "%s\n" "$ac_cv_sizeof_uintptr_t" >&6; } -@@ -12400,22 +12895,24 @@ - if test ${ac_cv_alignof_max_align_t+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if ac_fn_c_compute_int "$LINENO" "(long int) offsetof (ac__type_alignof_, y)" "ac_cv_alignof_max_align_t" "$ac_includes_default -+else case e in #( -+ e) if ac_fn_c_compute_int "$LINENO" "(long int) offsetof (ac__type_alignof_, y)" "ac_cv_alignof_max_align_t" "$ac_includes_default - typedef struct { char x; max_align_t y; } ac__type_alignof_;" - then : - --else $as_nop -- if test "$ac_cv_type_max_align_t" = yes; then -- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+else case e in #( -+ e) if test "$ac_cv_type_max_align_t" = yes; then -+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error 77 "cannot compute alignment of max_align_t --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } - else - ac_cv_alignof_max_align_t=0 -- fi -+ fi ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_alignof_max_align_t" >&5 - printf "%s\n" "$ac_cv_alignof_max_align_t" >&6; } -@@ -12432,8 +12929,8 @@ - if test ${ac_cv_type_long_double+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test "$GCC" = yes; then -+else case e in #( -+ e) if test "$GCC" = yes; then - ac_cv_type_long_double=yes - else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -12456,11 +12953,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_type_long_double=yes --else $as_nop -- ac_cv_type_long_double=no -+else case e in #( -+ e) ac_cv_type_long_double=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- fi -+ fi ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_long_double" >&5 - printf "%s\n" "$ac_cv_type_long_double" >&6; } -@@ -12472,28 +12971,30 @@ - - # The cast to long int works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects --# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -+# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of long double" >&5 - printf %s "checking size of long double... " >&6; } - if test ${ac_cv_sizeof_long_double+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long double))" "ac_cv_sizeof_long_double" "$ac_includes_default" -+else case e in #( -+ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long double))" "ac_cv_sizeof_long_double" "$ac_includes_default" - then : - --else $as_nop -- if test "$ac_cv_type_long_double" = yes; then -- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+else case e in #( -+ e) if test "$ac_cv_type_long_double" = yes; then -+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error 77 "cannot compute sizeof (long double) --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_long_double=0 -- fi -+ fi ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_double" >&5 - printf "%s\n" "$ac_cv_sizeof_long_double" >&6; } -@@ -12506,28 +13007,30 @@ - - # The cast to long int works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects --# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -+# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of _Bool" >&5 - printf %s "checking size of _Bool... " >&6; } - if test ${ac_cv_sizeof__Bool+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (_Bool))" "ac_cv_sizeof__Bool" "$ac_includes_default" -+else case e in #( -+ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (_Bool))" "ac_cv_sizeof__Bool" "$ac_includes_default" - then : - --else $as_nop -- if test "$ac_cv_type__Bool" = yes; then -- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+else case e in #( -+ e) if test "$ac_cv_type__Bool" = yes; then -+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error 77 "cannot compute sizeof (_Bool) --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof__Bool=0 -- fi -+ fi ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof__Bool" >&5 - printf "%s\n" "$ac_cv_sizeof__Bool" >&6; } -@@ -12540,15 +13043,15 @@ - - # The cast to long int works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects --# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -+# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of off_t" >&5 - printf %s "checking size of off_t... " >&6; } - if test ${ac_cv_sizeof_off_t+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (off_t))" "ac_cv_sizeof_off_t" " -+else case e in #( -+ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (off_t))" "ac_cv_sizeof_off_t" " - #ifdef HAVE_SYS_TYPES_H - #include - #endif -@@ -12556,17 +13059,19 @@ - " - then : - --else $as_nop -- if test "$ac_cv_type_off_t" = yes; then -- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+else case e in #( -+ e) if test "$ac_cv_type_off_t" = yes; then -+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error 77 "cannot compute sizeof (off_t) --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_off_t=0 -- fi -+ fi ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_off_t" >&5 - printf "%s\n" "$ac_cv_sizeof_off_t" >&6; } -@@ -12601,24 +13106,25 @@ - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 - printf "%s\n" "yes" >&6; } - --else $as_nop -- -+else case e in #( -+ e) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 - printf "%s\n" "no" >&6; } -- -+ ;; -+esac - fi - - # The cast to long int works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects --# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -+# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of time_t" >&5 - printf %s "checking size of time_t... " >&6; } - if test ${ac_cv_sizeof_time_t+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (time_t))" "ac_cv_sizeof_time_t" " -+else case e in #( -+ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (time_t))" "ac_cv_sizeof_time_t" " - #ifdef HAVE_SYS_TYPES_H - #include - #endif -@@ -12629,17 +13135,19 @@ - " - then : - --else $as_nop -- if test "$ac_cv_type_time_t" = yes; then -- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+else case e in #( -+ e) if test "$ac_cv_type_time_t" = yes; then -+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error 77 "cannot compute sizeof (time_t) --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_time_t=0 -- fi -+ fi ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_time_t" >&5 - printf "%s\n" "$ac_cv_sizeof_time_t" >&6; } -@@ -12665,8 +13173,8 @@ - if test ${ac_cv_have_pthread_t+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - -@@ -12683,11 +13191,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_have_pthread_t=yes --else $as_nop -- ac_cv_have_pthread_t=no -+else case e in #( -+ e) ac_cv_have_pthread_t=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_pthread_t" >&5 - printf "%s\n" "$ac_cv_have_pthread_t" >&6; } -@@ -12696,15 +13206,15 @@ - - # The cast to long int works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects --# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -+# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of pthread_t" >&5 - printf %s "checking size of pthread_t... " >&6; } - if test ${ac_cv_sizeof_pthread_t+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pthread_t))" "ac_cv_sizeof_pthread_t" " -+else case e in #( -+ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pthread_t))" "ac_cv_sizeof_pthread_t" " - #ifdef HAVE_PTHREAD_H - #include - #endif -@@ -12712,17 +13222,19 @@ - " - then : - --else $as_nop -- if test "$ac_cv_type_pthread_t" = yes; then -- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+else case e in #( -+ e) if test "$ac_cv_type_pthread_t" = yes; then -+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error 77 "cannot compute sizeof (pthread_t) --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_pthread_t=0 -- fi -+ fi ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_pthread_t" >&5 - printf "%s\n" "$ac_cv_sizeof_pthread_t" >&6; } -@@ -12739,29 +13251,31 @@ - # This checking will be unnecessary after removing deprecated TLS API. - # The cast to long int works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects --# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -+# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of pthread_key_t" >&5 - printf %s "checking size of pthread_key_t... " >&6; } - if test ${ac_cv_sizeof_pthread_key_t+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pthread_key_t))" "ac_cv_sizeof_pthread_key_t" "#include -+else case e in #( -+ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pthread_key_t))" "ac_cv_sizeof_pthread_key_t" "#include - " - then : - --else $as_nop -- if test "$ac_cv_type_pthread_key_t" = yes; then -- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+else case e in #( -+ e) if test "$ac_cv_type_pthread_key_t" = yes; then -+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error 77 "cannot compute sizeof (pthread_key_t) --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_pthread_key_t=0 -- fi -+ fi ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_pthread_key_t" >&5 - printf "%s\n" "$ac_cv_sizeof_pthread_key_t" >&6; } -@@ -12776,8 +13290,8 @@ - if test ${ac_cv_pthread_key_t_is_arithmetic_type+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - if test "$ac_cv_sizeof_pthread_key_t" -eq "$ac_cv_sizeof_int" ; then - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ -@@ -12793,15 +13307,17 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_pthread_key_t_is_arithmetic_type=yes --else $as_nop -- ac_cv_pthread_key_t_is_arithmetic_type=no -- -+else case e in #( -+ e) ac_cv_pthread_key_t_is_arithmetic_type=no -+ ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - else - ac_cv_pthread_key_t_is_arithmetic_type=no - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_pthread_key_t_is_arithmetic_type" >&5 - printf "%s\n" "$ac_cv_pthread_key_t_is_arithmetic_type" >&6; } -@@ -12860,9 +13376,10 @@ - else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 - printf "%s\n" "no" >&6; }; DSYMUTIL= - fi --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 --printf "%s\n" "no" >&6; } -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -+printf "%s\n" "no" >&6; } ;; -+esac - fi - - -@@ -12874,8 +13391,8 @@ - if test ${ac_cv_path_DSYMUTIL_PATH+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- case $DSYMUTIL_PATH in -+else case e in #( -+ e) case $DSYMUTIL_PATH in - [\\/]* | ?:[\\/]*) - ac_cv_path_DSYMUTIL_PATH="$DSYMUTIL_PATH" # Let the user override the test with a path. - ;; -@@ -12901,6 +13418,7 @@ - - test -z "$ac_cv_path_DSYMUTIL_PATH" && ac_cv_path_DSYMUTIL_PATH="not found" - ;; -+esac ;; - esac - fi - DSYMUTIL_PATH=$ac_cv_path_DSYMUTIL_PATH -@@ -12948,9 +13466,10 @@ - # ASan works by controlling memory allocation, our own malloc interferes. - with_pymalloc="no" - --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 --printf "%s\n" "no" >&6; } -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -+printf "%s\n" "no" >&6; } ;; -+esac - fi - - -@@ -12968,8 +13487,8 @@ - if test ${ax_cv_check_cflags___fsanitize_memory+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - ax_check_save_flags=$CFLAGS - CFLAGS="$CFLAGS -fsanitize=memory" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -12986,11 +13505,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ax_cv_check_cflags___fsanitize_memory=yes --else $as_nop -- ax_cv_check_cflags___fsanitize_memory=no -+else case e in #( -+ e) ax_cv_check_cflags___fsanitize_memory=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- CFLAGS=$ax_check_save_flags -+ CFLAGS=$ax_check_save_flags ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___fsanitize_memory" >&5 - printf "%s\n" "$ax_cv_check_cflags___fsanitize_memory" >&6; } -@@ -13000,16 +13521,18 @@ - BASECFLAGS="-fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer $BASECFLAGS" - LDFLAGS="-fsanitize=memory -fsanitize-memory-track-origins=2 $LDFLAGS" - --else $as_nop -- as_fn_error $? "The selected compiler doesn't support memory sanitizer" "$LINENO" 5 -+else case e in #( -+ e) as_fn_error $? "The selected compiler doesn't support memory sanitizer" "$LINENO" 5 ;; -+esac - fi - - # MSan works by controlling memory allocation, our own malloc interferes. - with_pymalloc="no" - --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 --printf "%s\n" "no" >&6; } -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -+printf "%s\n" "no" >&6; } ;; -+esac - fi - - -@@ -13026,12 +13549,13 @@ - LDFLAGS="-fsanitize=undefined $LDFLAGS" - with_ubsan="yes" - --else $as_nop -- -+else case e in #( -+ e) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 - printf "%s\n" "no" >&6; } - with_ubsan="no" -- -+ ;; -+esac - fi - - -@@ -13048,12 +13572,13 @@ - LDFLAGS="-fsanitize=thread $LDFLAGS" - with_tsan="yes" - --else $as_nop -- -+else case e in #( -+ e) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 - printf "%s\n" "no" >&6; } - with_tsan="no" -- -+ ;; -+esac - fi - - -@@ -13160,7 +13685,7 @@ - BLDSHARED="$LDSHARED" - fi - ;; -- iOS/*) -+ iOS/*|tvOS/*|watchOS/*) - LDSHARED='$(CC) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)' - LDCXXSHARED='$(CXX) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)' - BLDSHARED="$LDSHARED" -@@ -13293,7 +13818,7 @@ - Linux-android*) LINKFORSHARED="-pie -Xlinker -export-dynamic";; - Linux*|GNU*) LINKFORSHARED="-Xlinker -export-dynamic";; - # -u libsys_s pulls in all symbols in libsys -- Darwin/*|iOS/*) -+ Darwin/*|iOS/*|tvOS/*|watchOS/*) - LINKFORSHARED="$extra_undefs -framework CoreFoundation" - - # Issue #18075: the default maximum stack size (8MBytes) is too -@@ -13317,7 +13842,7 @@ - LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' - fi - LINKFORSHARED="$LINKFORSHARED" -- elif test $ac_sys_system = "iOS"; then -+ elif test "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "watchOS"; then - LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)' - fi - ;; -@@ -13437,16 +13962,22 @@ - if test ${ac_cv_lib_sendfile_sendfile+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lsendfile $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char sendfile (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char sendfile (void); - int - main (void) - { -@@ -13458,12 +13989,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_sendfile_sendfile=yes --else $as_nop -- ac_cv_lib_sendfile_sendfile=no -+else case e in #( -+ e) ac_cv_lib_sendfile_sendfile=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sendfile_sendfile" >&5 - printf "%s\n" "$ac_cv_lib_sendfile_sendfile" >&6; } -@@ -13480,16 +14013,22 @@ - if test ${ac_cv_lib_dl_dlopen+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-ldl $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char dlopen (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char dlopen (void); - int - main (void) - { -@@ -13501,12 +14040,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_dl_dlopen=yes --else $as_nop -- ac_cv_lib_dl_dlopen=no -+else case e in #( -+ e) ac_cv_lib_dl_dlopen=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 - printf "%s\n" "$ac_cv_lib_dl_dlopen" >&6; } -@@ -13523,16 +14064,22 @@ - if test ${ac_cv_lib_dld_shl_load+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-ldld $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char shl_load (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char shl_load (void); - int - main (void) - { -@@ -13544,12 +14091,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_dld_shl_load=yes --else $as_nop -- ac_cv_lib_dld_shl_load=no -+else case e in #( -+ e) ac_cv_lib_dld_shl_load=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 - printf "%s\n" "$ac_cv_lib_dld_shl_load" >&6; } -@@ -13577,12 +14126,12 @@ - - for ac_func in uuid_create uuid_enc_be - do : -- as_ac_var=`printf "%s\n" "ac_cv_func_$ac_func" | $as_tr_sh` -+ as_ac_var=`printf "%s\n" "ac_cv_func_$ac_func" | sed "$as_sed_sh"` - ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" - if eval test \"x\$"$as_ac_var"\" = x"yes" - then : - cat >>confdefs.h <<_ACEOF --#define `printf "%s\n" "HAVE_$ac_func" | $as_tr_cpp` 1 -+#define `printf "%s\n" "HAVE_$ac_func" | sed "$as_sed_cpp"` 1 - _ACEOF - have_uuid=yes - LIBUUID_CFLAGS=${LIBUUID_CFLAGS-""} -@@ -13680,16 +14229,22 @@ - if test ${ac_cv_lib_uuid_uuid_generate_time+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-luuid $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char uuid_generate_time (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char uuid_generate_time (void); - int - main (void) - { -@@ -13701,12 +14256,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_uuid_uuid_generate_time=yes --else $as_nop -- ac_cv_lib_uuid_uuid_generate_time=no -+else case e in #( -+ e) ac_cv_lib_uuid_uuid_generate_time=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_generate_time" >&5 - printf "%s\n" "$ac_cv_lib_uuid_uuid_generate_time" >&6; } -@@ -13723,16 +14280,22 @@ - if test ${ac_cv_lib_uuid_uuid_generate_time_safe+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-luuid $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char uuid_generate_time_safe (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char uuid_generate_time_safe (void); - int - main (void) - { -@@ -13744,12 +14307,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_uuid_uuid_generate_time_safe=yes --else $as_nop -- ac_cv_lib_uuid_uuid_generate_time_safe=no -+else case e in #( -+ e) ac_cv_lib_uuid_uuid_generate_time_safe=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_generate_time_safe" >&5 - printf "%s\n" "$ac_cv_lib_uuid_uuid_generate_time_safe" >&6; } -@@ -13806,16 +14371,22 @@ - if test ${ac_cv_lib_uuid_uuid_generate_time+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-luuid $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char uuid_generate_time (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char uuid_generate_time (void); - int - main (void) - { -@@ -13827,12 +14398,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_uuid_uuid_generate_time=yes --else $as_nop -- ac_cv_lib_uuid_uuid_generate_time=no -+else case e in #( -+ e) ac_cv_lib_uuid_uuid_generate_time=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_generate_time" >&5 - printf "%s\n" "$ac_cv_lib_uuid_uuid_generate_time" >&6; } -@@ -13849,16 +14422,22 @@ - if test ${ac_cv_lib_uuid_uuid_generate_time_safe+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-luuid $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char uuid_generate_time_safe (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char uuid_generate_time_safe (void); - int - main (void) - { -@@ -13870,12 +14449,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_uuid_uuid_generate_time_safe=yes --else $as_nop -- ac_cv_lib_uuid_uuid_generate_time_safe=no -+else case e in #( -+ e) ac_cv_lib_uuid_uuid_generate_time_safe=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_generate_time_safe" >&5 - printf "%s\n" "$ac_cv_lib_uuid_uuid_generate_time_safe" >&6; } -@@ -13970,15 +14551,21 @@ - if test ${ac_cv_search_sem_init+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_func_search_save_LIBS=$LIBS -+else case e in #( -+ e) ac_func_search_save_LIBS=$LIBS - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char sem_init (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char sem_init (void); - int - main (void) - { -@@ -14009,11 +14596,13 @@ - if test ${ac_cv_search_sem_init+y} - then : - --else $as_nop -- ac_cv_search_sem_init=no -+else case e in #( -+ e) ac_cv_search_sem_init=no ;; -+esac - fi - rm conftest.$ac_ext --LIBS=$ac_func_search_save_LIBS -+LIBS=$ac_func_search_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_sem_init" >&5 - printf "%s\n" "$ac_cv_search_sem_init" >&6; } -@@ -14031,16 +14620,22 @@ - if test ${ac_cv_lib_intl_textdomain+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lintl $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char textdomain (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char textdomain (void); - int - main (void) - { -@@ -14052,12 +14647,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_intl_textdomain=yes --else $as_nop -- ac_cv_lib_intl_textdomain=no -+else case e in #( -+ e) ac_cv_lib_intl_textdomain=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_textdomain" >&5 - printf "%s\n" "$ac_cv_lib_intl_textdomain" >&6; } -@@ -14096,11 +14693,12 @@ - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 - printf "%s\n" "yes" >&6; } - --else $as_nop -- -+else case e in #( -+ e) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 - printf "%s\n" "no" >&6; } -- -+ ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -@@ -14129,8 +14727,8 @@ - if test "$cross_compiling" = yes - then : - ac_cv_c_complex_supported=no --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -14151,11 +14749,13 @@ - if ac_fn_c_try_run "$LINENO" - then : - ac_cv_c_complex_supported=yes --else $as_nop -- ac_cv_c_complex_supported=no -+else case e in #( -+ e) ac_cv_c_complex_supported=no ;; -+esac - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext -+ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - - if test "$ac_cv_c_complex_supported" = "yes"; then -@@ -14170,8 +14770,8 @@ - if test ${ac_cv_aligned_required+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test "$cross_compiling" = yes -+else case e in #( -+ e) if test "$cross_compiling" = yes - then : - - # "yes" changes the hash function to FNV, which causes problems with Numba -@@ -14181,8 +14781,8 @@ - else - ac_cv_aligned_required=yes - fi --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - int main(void) -@@ -14201,14 +14801,17 @@ - if ac_fn_c_try_run "$LINENO" - then : - ac_cv_aligned_required=no --else $as_nop -- ac_cv_aligned_required=yes -+else case e in #( -+ e) ac_cv_aligned_required=yes ;; -+esac - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext -+ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_aligned_required" >&5 - printf "%s\n" "$ac_cv_aligned_required" >&6; } -@@ -14248,9 +14851,10 @@ - ;; - esac - --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: default" >&5 --printf "%s\n" "default" >&6; } -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: default" >&5 -+printf "%s\n" "default" >&6; } ;; -+esac - fi - - -@@ -14288,10 +14892,11 @@ - ;; - esac - --else $as_nop -- validate_tzpath "$TZPATH" -+else case e in #( -+ e) validate_tzpath "$TZPATH" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: \"$TZPATH\"" >&5 --printf "%s\n" "\"$TZPATH\"" >&6; } -+printf "%s\n" "\"$TZPATH\"" >&6; } ;; -+esac - fi - - -@@ -14302,16 +14907,22 @@ - if test ${ac_cv_lib_nsl_t_open+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lnsl $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char t_open (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char t_open (void); - int - main (void) - { -@@ -14323,12 +14934,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_nsl_t_open=yes --else $as_nop -- ac_cv_lib_nsl_t_open=no -+else case e in #( -+ e) ac_cv_lib_nsl_t_open=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_t_open" >&5 - printf "%s\n" "$ac_cv_lib_nsl_t_open" >&6; } -@@ -14342,16 +14955,22 @@ - if test ${ac_cv_lib_socket_socket+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lsocket $LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char socket (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char socket (void); - int - main (void) - { -@@ -14363,12 +14982,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_socket_socket=yes --else $as_nop -- ac_cv_lib_socket_socket=no -+else case e in #( -+ e) ac_cv_lib_socket_socket=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_socket" >&5 - printf "%s\n" "$ac_cv_lib_socket_socket" >&6; } -@@ -14385,16 +15006,22 @@ - if test ${ac_cv_lib_network_socket+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lnetwork $LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char socket (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char socket (void); - int - main (void) - { -@@ -14406,12 +15033,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_network_socket=yes --else $as_nop -- ac_cv_lib_network_socket=no -+else case e in #( -+ e) ac_cv_lib_network_socket=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_network_socket" >&5 - printf "%s\n" "$ac_cv_lib_network_socket" >&6; } -@@ -14434,9 +15063,10 @@ - printf "%s\n" "$withval" >&6; } - LIBS="$withval $LIBS" - --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 --printf "%s\n" "no" >&6; } -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -+printf "%s\n" "no" >&6; } ;; -+esac - fi - - -@@ -14448,8 +15078,9 @@ - if test ${with_system_expat+y} - then : - withval=$with_system_expat; --else $as_nop -- with_system_expat="no" -+else case e in #( -+ e) with_system_expat="no" ;; -+esac - fi - - -@@ -14463,12 +15094,13 @@ - LIBEXPAT_LDFLAGS=${LIBEXPAT_LDFLAGS-"-lexpat"} - LIBEXPAT_INTERNAL= - --else $as_nop -- -+else case e in #( -+ e) - LIBEXPAT_CFLAGS="-I\$(srcdir)/Modules/expat" - LIBEXPAT_LDFLAGS="-lm \$(LIBEXPAT_A)" - LIBEXPAT_INTERNAL="\$(LIBEXPAT_HEADERS) \$(LIBEXPAT_A)" -- -+ ;; -+esac - fi - - -@@ -14494,16 +15126,22 @@ - if test ${ac_cv_lib_ffi_ffi_call+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lffi $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char ffi_call (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char ffi_call (void); - int - main (void) - { -@@ -14515,12 +15153,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_ffi_ffi_call=yes --else $as_nop -- ac_cv_lib_ffi_ffi_call=no -+else case e in #( -+ e) ac_cv_lib_ffi_ffi_call=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ffi_ffi_call" >&5 - printf "%s\n" "$ac_cv_lib_ffi_ffi_call" >&6; } -@@ -14625,16 +15265,22 @@ - if test ${ac_cv_lib_ffi_ffi_call+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lffi $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char ffi_call (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char ffi_call (void); - int - main (void) - { -@@ -14646,12 +15292,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_ffi_ffi_call=yes --else $as_nop -- ac_cv_lib_ffi_ffi_call=no -+else case e in #( -+ e) ac_cv_lib_ffi_ffi_call=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ffi_ffi_call" >&5 - printf "%s\n" "$ac_cv_lib_ffi_ffi_call" >&6; } -@@ -14662,8 +15310,9 @@ - LIBFFI_CFLAGS=${LIBFFI_CFLAGS-""} - LIBFFI_LIBS=${LIBFFI_LIBS-"-lffi"} - --else $as_nop -- have_libffi=no -+else case e in #( -+ e) have_libffi=no ;; -+esac - fi - - -@@ -14698,16 +15347,22 @@ - if test ${ac_cv_lib_ffi_ffi_call+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lffi $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char ffi_call (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char ffi_call (void); - int - main (void) - { -@@ -14719,12 +15374,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_ffi_ffi_call=yes --else $as_nop -- ac_cv_lib_ffi_ffi_call=no -+else case e in #( -+ e) ac_cv_lib_ffi_ffi_call=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ffi_ffi_call" >&5 - printf "%s\n" "$ac_cv_lib_ffi_ffi_call" >&6; } -@@ -14735,8 +15392,9 @@ - LIBFFI_CFLAGS=${LIBFFI_CFLAGS-""} - LIBFFI_LIBS=${LIBFFI_LIBS-"-lffi"} - --else $as_nop -- have_libffi=no -+else case e in #( -+ e) have_libffi=no ;; -+esac - fi - - -@@ -14769,7 +15427,7 @@ - - ctypes_malloc_closure=yes - ;; #( -- iOS) : -+ iOS|tvOS|watchOS) : - - ctypes_malloc_closure=yes - ;; #( -@@ -14809,8 +15467,8 @@ - if test ${ac_cv_func_ffi_prep_cif_var+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -14824,11 +15482,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_ffi_prep_cif_var=yes --else $as_nop -- ac_cv_func_ffi_prep_cif_var=no -+else case e in #( -+ e) ac_cv_func_ffi_prep_cif_var=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_ffi_prep_cif_var" >&5 - printf "%s\n" "$ac_cv_func_ffi_prep_cif_var" >&6; } -@@ -14848,8 +15508,8 @@ - if test ${ac_cv_func_ffi_prep_closure_loc+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -14863,11 +15523,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_ffi_prep_closure_loc=yes --else $as_nop -- ac_cv_func_ffi_prep_closure_loc=no -+else case e in #( -+ e) ac_cv_func_ffi_prep_closure_loc=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_ffi_prep_closure_loc" >&5 - printf "%s\n" "$ac_cv_func_ffi_prep_closure_loc" >&6; } -@@ -14887,8 +15549,8 @@ - if test ${ac_cv_func_ffi_closure_alloc+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -14902,11 +15564,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_ffi_closure_alloc=yes --else $as_nop -- ac_cv_func_ffi_closure_alloc=no -+else case e in #( -+ e) ac_cv_func_ffi_closure_alloc=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_ffi_closure_alloc" >&5 - printf "%s\n" "$ac_cv_func_ffi_closure_alloc" >&6; } -@@ -14939,21 +15603,20 @@ - if test ${ac_cv_ffi_complex_double_supported+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- save_CFLAGS=$CFLAGS -+else case e in #( -+ e) save_CFLAGS=$CFLAGS - save_CPPFLAGS=$CPPFLAGS - save_LDFLAGS=$LDFLAGS - save_LIBS=$LIBS - - -- CPPFLAGS="$LIBFFI_CFLAGS $CPPFLAGS" -- LDFLAGS="$LIBFFI_LIBS $LDFLAGS" -- LIBS="$LIBFFI_LIBS $LIBS" -+ CPPFLAGS="$CPPFLAGS $LIBFFI_CFLAGS" -+ LIBS="$LIBS $LIBFFI_LIBS" - if test "$cross_compiling" = yes - then : - ac_cv_ffi_complex_double_supported=no --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -14983,11 +15646,13 @@ - if ac_fn_c_try_run "$LINENO" - then : - ac_cv_ffi_complex_double_supported=yes --else $as_nop -- ac_cv_ffi_complex_double_supported=no -+else case e in #( -+ e) ac_cv_ffi_complex_double_supported=no ;; -+esac - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext -+ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - - -@@ -14996,7 +15661,8 @@ - LDFLAGS=$save_LDFLAGS - LIBS=$save_LIBS - -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_ffi_complex_double_supported" >&5 - printf "%s\n" "$ac_cv_ffi_complex_double_supported" >&6; } -@@ -15014,8 +15680,9 @@ - if test ${with_system_libmpdec+y} - then : - withval=$with_system_libmpdec; --else $as_nop -- with_system_libmpdec="yes" -+else case e in #( -+ e) with_system_libmpdec="yes" ;; -+esac - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_system_libmpdec" >&5 -@@ -15100,12 +15767,13 @@ - printf "%s\n" "yes" >&6; } - - fi --else $as_nop -- LIBMPDEC_CFLAGS="-I\$(srcdir)/Modules/_decimal/libmpdec" -+else case e in #( -+ e) LIBMPDEC_CFLAGS="-I\$(srcdir)/Modules/_decimal/libmpdec" - LIBMPDEC_LIBS="-lm \$(LIBMPDEC_A)" - LIBMPDEC_INTERNAL="\$(LIBMPDEC_HEADERS) \$(LIBMPDEC_A)" - have_mpdec=yes -- with_system_libmpdec=no -+ with_system_libmpdec=no ;; -+esac - fi - - if test "x$with_system_libmpdec" = xyes -@@ -15139,8 +15807,9 @@ - if ac_fn_c_try_link "$LINENO" - then : - have_mpdec=yes --else $as_nop -- have_mpdec=no -+else case e in #( -+ e) have_mpdec=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -@@ -15151,9 +15820,10 @@ - LIBS=$save_LIBS - - --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: the bundled copy of libmpdecimal is scheduled for removal in Python 3.15; consider using a system installed mpdecimal library." >&5 --printf "%s\n" "$as_me: WARNING: the bundled copy of libmpdecimal is scheduled for removal in Python 3.15; consider using a system installed mpdecimal library." >&2;} -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: the bundled copy of libmpdecimal is scheduled for removal in Python 3.15; consider using a system installed mpdecimal library." >&5 -+printf "%s\n" "$as_me: WARNING: the bundled copy of libmpdecimal is scheduled for removal in Python 3.15; consider using a system installed mpdecimal library." >&2;} ;; -+esac - fi - - if test "$with_system_libmpdec" = "yes" && test "$have_mpdec" = "no" -@@ -15181,8 +15851,9 @@ - if test ${with_decimal_contextvar+y} - then : - withval=$with_decimal_contextvar; --else $as_nop -- with_decimal_contextvar="yes" -+else case e in #( -+ e) with_decimal_contextvar="yes" ;; -+esac - fi - - -@@ -15420,16 +16091,22 @@ - if test ${ac_cv_lib_sqlite3_sqlite3_bind_double+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lsqlite3 $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char sqlite3_bind_double (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char sqlite3_bind_double (void); - int - main (void) - { -@@ -15441,12 +16118,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_sqlite3_sqlite3_bind_double=yes --else $as_nop -- ac_cv_lib_sqlite3_sqlite3_bind_double=no -+else case e in #( -+ e) ac_cv_lib_sqlite3_sqlite3_bind_double=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_bind_double" >&5 - printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_bind_double" >&6; } -@@ -15456,10 +16135,11 @@ - - LIBS="-lsqlite3 $LIBS" - --else $as_nop -- -+else case e in #( -+ e) - have_supported_sqlite3=no -- -+ ;; -+esac - fi - - -@@ -15469,16 +16149,22 @@ - if test ${ac_cv_lib_sqlite3_sqlite3_column_decltype+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lsqlite3 $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char sqlite3_column_decltype (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char sqlite3_column_decltype (void); - int - main (void) - { -@@ -15490,12 +16176,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_sqlite3_sqlite3_column_decltype=yes --else $as_nop -- ac_cv_lib_sqlite3_sqlite3_column_decltype=no -+else case e in #( -+ e) ac_cv_lib_sqlite3_sqlite3_column_decltype=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_column_decltype" >&5 - printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_column_decltype" >&6; } -@@ -15505,10 +16193,11 @@ - - LIBS="-lsqlite3 $LIBS" - --else $as_nop -- -+else case e in #( -+ e) - have_supported_sqlite3=no -- -+ ;; -+esac - fi - - -@@ -15518,16 +16207,22 @@ - if test ${ac_cv_lib_sqlite3_sqlite3_column_double+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lsqlite3 $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char sqlite3_column_double (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char sqlite3_column_double (void); - int - main (void) - { -@@ -15539,12 +16234,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_sqlite3_sqlite3_column_double=yes --else $as_nop -- ac_cv_lib_sqlite3_sqlite3_column_double=no -+else case e in #( -+ e) ac_cv_lib_sqlite3_sqlite3_column_double=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_column_double" >&5 - printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_column_double" >&6; } -@@ -15554,10 +16251,11 @@ - - LIBS="-lsqlite3 $LIBS" - --else $as_nop -- -+else case e in #( -+ e) - have_supported_sqlite3=no -- -+ ;; -+esac - fi - - -@@ -15567,16 +16265,22 @@ - if test ${ac_cv_lib_sqlite3_sqlite3_complete+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lsqlite3 $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char sqlite3_complete (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char sqlite3_complete (void); - int - main (void) - { -@@ -15588,12 +16292,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_sqlite3_sqlite3_complete=yes --else $as_nop -- ac_cv_lib_sqlite3_sqlite3_complete=no -+else case e in #( -+ e) ac_cv_lib_sqlite3_sqlite3_complete=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_complete" >&5 - printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_complete" >&6; } -@@ -15603,10 +16309,11 @@ - - LIBS="-lsqlite3 $LIBS" - --else $as_nop -- -+else case e in #( -+ e) - have_supported_sqlite3=no -- -+ ;; -+esac - fi - - -@@ -15616,16 +16323,22 @@ - if test ${ac_cv_lib_sqlite3_sqlite3_progress_handler+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lsqlite3 $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char sqlite3_progress_handler (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char sqlite3_progress_handler (void); - int - main (void) - { -@@ -15637,12 +16350,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_sqlite3_sqlite3_progress_handler=yes --else $as_nop -- ac_cv_lib_sqlite3_sqlite3_progress_handler=no -+else case e in #( -+ e) ac_cv_lib_sqlite3_sqlite3_progress_handler=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_progress_handler" >&5 - printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_progress_handler" >&6; } -@@ -15652,10 +16367,11 @@ - - LIBS="-lsqlite3 $LIBS" - --else $as_nop -- -+else case e in #( -+ e) - have_supported_sqlite3=no -- -+ ;; -+esac - fi - - -@@ -15665,16 +16381,22 @@ - if test ${ac_cv_lib_sqlite3_sqlite3_result_double+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lsqlite3 $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char sqlite3_result_double (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char sqlite3_result_double (void); - int - main (void) - { -@@ -15686,12 +16408,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_sqlite3_sqlite3_result_double=yes --else $as_nop -- ac_cv_lib_sqlite3_sqlite3_result_double=no -+else case e in #( -+ e) ac_cv_lib_sqlite3_sqlite3_result_double=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_result_double" >&5 - printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_result_double" >&6; } -@@ -15701,10 +16425,11 @@ - - LIBS="-lsqlite3 $LIBS" - --else $as_nop -- -+else case e in #( -+ e) - have_supported_sqlite3=no -- -+ ;; -+esac - fi - - -@@ -15714,16 +16439,22 @@ - if test ${ac_cv_lib_sqlite3_sqlite3_set_authorizer+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lsqlite3 $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char sqlite3_set_authorizer (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char sqlite3_set_authorizer (void); - int - main (void) - { -@@ -15735,12 +16466,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_sqlite3_sqlite3_set_authorizer=yes --else $as_nop -- ac_cv_lib_sqlite3_sqlite3_set_authorizer=no -+else case e in #( -+ e) ac_cv_lib_sqlite3_sqlite3_set_authorizer=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_set_authorizer" >&5 - printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_set_authorizer" >&6; } -@@ -15750,10 +16483,11 @@ - - LIBS="-lsqlite3 $LIBS" - --else $as_nop -- -+else case e in #( -+ e) - have_supported_sqlite3=no -- -+ ;; -+esac - fi - - -@@ -15763,16 +16497,22 @@ - if test ${ac_cv_lib_sqlite3_sqlite3_trace_v2+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lsqlite3 $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char sqlite3_trace_v2 (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char sqlite3_trace_v2 (void); - int - main (void) - { -@@ -15784,12 +16524,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_sqlite3_sqlite3_trace_v2=yes --else $as_nop -- ac_cv_lib_sqlite3_sqlite3_trace_v2=no -+else case e in #( -+ e) ac_cv_lib_sqlite3_sqlite3_trace_v2=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_trace_v2" >&5 - printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_trace_v2" >&6; } -@@ -15799,8 +16541,8 @@ - - LIBS="-lsqlite3 $LIBS" - --else $as_nop -- -+else case e in #( -+ e) - - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sqlite3_trace in -lsqlite3" >&5 -@@ -15808,16 +16550,22 @@ - if test ${ac_cv_lib_sqlite3_sqlite3_trace+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lsqlite3 $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char sqlite3_trace (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char sqlite3_trace (void); - int - main (void) - { -@@ -15829,12 +16577,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_sqlite3_sqlite3_trace=yes --else $as_nop -- ac_cv_lib_sqlite3_sqlite3_trace=no -+else case e in #( -+ e) ac_cv_lib_sqlite3_sqlite3_trace=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_trace" >&5 - printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_trace" >&6; } -@@ -15844,15 +16594,17 @@ - - LIBS="-lsqlite3 $LIBS" - --else $as_nop -- -+else case e in #( -+ e) - have_supported_sqlite3=no -- -+ ;; -+esac - fi - - - -- -+ ;; -+esac - fi - - -@@ -15862,16 +16614,22 @@ - if test ${ac_cv_lib_sqlite3_sqlite3_value_double+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lsqlite3 $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char sqlite3_value_double (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char sqlite3_value_double (void); - int - main (void) - { -@@ -15883,12 +16641,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_sqlite3_sqlite3_value_double=yes --else $as_nop -- ac_cv_lib_sqlite3_sqlite3_value_double=no -+else case e in #( -+ e) ac_cv_lib_sqlite3_sqlite3_value_double=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_value_double" >&5 - printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_value_double" >&6; } -@@ -15898,10 +16658,11 @@ - - LIBS="-lsqlite3 $LIBS" - --else $as_nop -- -+else case e in #( -+ e) - have_supported_sqlite3=no -- -+ ;; -+esac - fi - - -@@ -15910,16 +16671,22 @@ - if test ${ac_cv_lib_sqlite3_sqlite3_load_extension+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lsqlite3 $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char sqlite3_load_extension (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char sqlite3_load_extension (void); - int - main (void) - { -@@ -15931,21 +16698,24 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_sqlite3_sqlite3_load_extension=yes --else $as_nop -- ac_cv_lib_sqlite3_sqlite3_load_extension=no -+else case e in #( -+ e) ac_cv_lib_sqlite3_sqlite3_load_extension=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_load_extension" >&5 - printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_load_extension" >&6; } - if test "x$ac_cv_lib_sqlite3_sqlite3_load_extension" = xyes - then : - have_sqlite3_load_extension=yes --else $as_nop -- have_sqlite3_load_extension=no -- -+else case e in #( -+ e) have_sqlite3_load_extension=no -+ ;; -+esac - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sqlite3_serialize in -lsqlite3" >&5 -@@ -15953,16 +16723,22 @@ - if test ${ac_cv_lib_sqlite3_sqlite3_serialize+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lsqlite3 $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char sqlite3_serialize (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char sqlite3_serialize (void); - int - main (void) - { -@@ -15974,12 +16750,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_sqlite3_sqlite3_serialize=yes --else $as_nop -- ac_cv_lib_sqlite3_sqlite3_serialize=no -+else case e in #( -+ e) ac_cv_lib_sqlite3_sqlite3_serialize=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_serialize" >&5 - printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_serialize" >&6; } -@@ -15993,10 +16771,11 @@ - fi - - --else $as_nop -- -+else case e in #( -+ e) - have_supported_sqlite3=no -- -+ ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - -@@ -16024,22 +16803,24 @@ - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Your version of SQLite does not support loadable extensions" >&5 - printf "%s\n" "$as_me: WARNING: Your version of SQLite does not support loadable extensions" >&2;} - --else $as_nop -- -+else case e in #( -+ e) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 - printf "%s\n" "yes" >&6; } - - printf "%s\n" "#define PY_SQLITE_ENABLE_LOAD_EXTENSION 1" >>confdefs.h - -- -+ ;; -+esac - fi - --else $as_nop -- -+else case e in #( -+ e) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 - printf "%s\n" "no" >&6; } - -- -+ ;; -+esac - fi - - -@@ -16227,8 +17008,8 @@ - elif test $pkg_failed = untried; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 - printf "%s\n" "no" >&6; } -- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it - is in your PATH or set the PKG_CONFIG environment variable to the full - path to pkg-config. -@@ -16238,7 +17019,7 @@ - See the pkg-config man page for more details. - - To get pkg-config, see . --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } - else - X11_CFLAGS=$pkg_cv_X11_CFLAGS - X11_LIBS=$pkg_cv_X11_LIBS -@@ -16306,10 +17087,11 @@ - have_tcltk=yes - as_fn_append TCLTK_CFLAGS " -Wno-strict-prototypes -DWITH_APPINIT=1" - --else $as_nop -- -+else case e in #( -+ e) - have_tcltk=no -- -+ ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -@@ -16343,16 +17125,22 @@ - if test ${ac_cv_lib_gdbm_gdbm_open+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lgdbm $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char gdbm_open (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char gdbm_open (void); - int - main (void) - { -@@ -16364,12 +17152,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_gdbm_gdbm_open=yes --else $as_nop -- ac_cv_lib_gdbm_gdbm_open=no -+else case e in #( -+ e) ac_cv_lib_gdbm_gdbm_open=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gdbm_gdbm_open" >&5 - printf "%s\n" "$ac_cv_lib_gdbm_gdbm_open" >&6; } -@@ -16379,13 +17169,15 @@ - have_gdbm=yes - GDBM_LIBS=${GDBM_LIBS-"-lgdbm"} - --else $as_nop -- have_gdbm=no -+else case e in #( -+ e) have_gdbm=no ;; -+esac - fi - - --else $as_nop -- have_gdbm=no -+else case e in #( -+ e) have_gdbm=no ;; -+esac - fi - - done -@@ -16415,15 +17207,21 @@ - if test ${ac_cv_search_dbm_open+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_func_search_save_LIBS=$LIBS -+else case e in #( -+ e) ac_func_search_save_LIBS=$LIBS - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char dbm_open (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char dbm_open (void); - int - main (void) - { -@@ -16454,11 +17252,13 @@ - if test ${ac_cv_search_dbm_open+y} - then : - --else $as_nop -- ac_cv_search_dbm_open=no -+else case e in #( -+ e) ac_cv_search_dbm_open=no ;; -+esac - fi - rm conftest.$ac_ext --LIBS=$ac_func_search_save_LIBS -+LIBS=$ac_func_search_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dbm_open" >&5 - printf "%s\n" "$ac_cv_search_dbm_open" >&6; } -@@ -16503,24 +17303,28 @@ - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $have_ndbm ($dbm_ndbm)" >&5 - printf "%s\n" "$have_ndbm ($dbm_ndbm)" >&6; } - --{ ac_cv_header_gdbm_ndbm_h=; unset ac_cv_header_gdbm_ndbm_h;} -+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gdbm/ndbm.h" >&5 -+printf %s "checking for gdbm/ndbm.h... " >&6; } - if test ${ac_cv_header_gdbm_slash_ndbm_h+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -- ac_fn_c_check_header_compile "$LINENO" "gdbm/ndbm.h" "ac_cv_header_gdbm_ndbm_h" "$ac_includes_default" --if test "x$ac_cv_header_gdbm_ndbm_h" = xyes -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+/* end confdefs.h. */ -+#include -+_ACEOF -+if ac_fn_c_try_cpp "$LINENO" - then : - ac_cv_header_gdbm_slash_ndbm_h=yes --else $as_nop -- ac_cv_header_gdbm_slash_ndbm_h=no -- -+else case e in #( -+ e) ac_cv_header_gdbm_slash_ndbm_h=no ;; -+esac - fi -- -- -+rm -f conftest.err conftest.i conftest.$ac_ext ;; -+esac - fi -- -+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_gdbm_slash_ndbm_h" >&5 -+printf "%s\n" "$ac_cv_header_gdbm_slash_ndbm_h" >&6; } - if test "x$ac_cv_header_gdbm_slash_ndbm_h" = xyes - then : - -@@ -16530,24 +17334,28 @@ - - fi - --{ ac_cv_header_gdbm_ndbm_h=; unset ac_cv_header_gdbm_ndbm_h;} -+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gdbm-ndbm.h" >&5 -+printf %s "checking for gdbm-ndbm.h... " >&6; } - if test ${ac_cv_header_gdbm_dash_ndbm_h+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -- ac_fn_c_check_header_compile "$LINENO" "gdbm-ndbm.h" "ac_cv_header_gdbm_ndbm_h" "$ac_includes_default" --if test "x$ac_cv_header_gdbm_ndbm_h" = xyes -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+/* end confdefs.h. */ -+#include -+_ACEOF -+if ac_fn_c_try_cpp "$LINENO" - then : - ac_cv_header_gdbm_dash_ndbm_h=yes --else $as_nop -- ac_cv_header_gdbm_dash_ndbm_h=no -- -+else case e in #( -+ e) ac_cv_header_gdbm_dash_ndbm_h=no ;; -+esac - fi -- -- -+rm -f conftest.err conftest.i conftest.$ac_ext ;; -+esac - fi -- -+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_gdbm_dash_ndbm_h" >&5 -+printf "%s\n" "$ac_cv_header_gdbm_dash_ndbm_h" >&6; } - if test "x$ac_cv_header_gdbm_dash_ndbm_h" = xyes - then : - -@@ -16556,7 +17364,6 @@ - - - fi --{ ac_cv_header_gdbm_ndbm_h=; unset ac_cv_header_gdbm_ndbm_h;} - - if test "$ac_cv_header_gdbm_slash_ndbm_h" = yes -o "$ac_cv_header_gdbm_dash_ndbm_h" = yes; then - { ac_cv_search_dbm_open=; unset ac_cv_search_dbm_open;} -@@ -16571,15 +17378,21 @@ - if test ${ac_cv_search_dbm_open+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_func_search_save_LIBS=$LIBS -+else case e in #( -+ e) ac_func_search_save_LIBS=$LIBS - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char dbm_open (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char dbm_open (void); - int - main (void) - { -@@ -16610,11 +17423,13 @@ - if test ${ac_cv_search_dbm_open+y} - then : - --else $as_nop -- ac_cv_search_dbm_open=no -+else case e in #( -+ e) ac_cv_search_dbm_open=no ;; -+esac - fi - rm conftest.$ac_ext --LIBS=$ac_func_search_save_LIBS -+LIBS=$ac_func_search_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dbm_open" >&5 - printf "%s\n" "$ac_cv_search_dbm_open" >&6; } -@@ -16623,8 +17438,9 @@ - then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - have_gdbm_compat=yes --else $as_nop -- have_gdbm_compat=no -+else case e in #( -+ e) have_gdbm_compat=no ;; -+esac - fi - - -@@ -16650,8 +17466,8 @@ - if test ${ac_cv_have_libdb+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - save_CFLAGS=$CFLAGS - save_CPPFLAGS=$CPPFLAGS - save_LDFLAGS=$LDFLAGS -@@ -16680,8 +17496,9 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_have_libdb=yes --else $as_nop -- ac_cv_have_libdb=no -+else case e in #( -+ e) ac_cv_have_libdb=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -@@ -16692,7 +17509,8 @@ - LIBS=$save_LIBS - - -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_libdb" >&5 - printf "%s\n" "$ac_cv_have_libdb" >&6; } -@@ -16717,8 +17535,9 @@ - if test ${with_dbmliborder+y} - then : - withval=$with_dbmliborder; --else $as_nop -- with_dbmliborder=gdbm:ndbm:bdb -+else case e in #( -+ e) with_dbmliborder=gdbm:ndbm:bdb ;; -+esac - fi - - -@@ -16835,8 +17654,8 @@ - if test ${ac_cv_defined__POSIX_THREADS_unistd_h+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -16857,18 +17676,21 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_defined__POSIX_THREADS_unistd_h=yes --else $as_nop -- ac_cv_defined__POSIX_THREADS_unistd_h=no -+else case e in #( -+ e) ac_cv_defined__POSIX_THREADS_unistd_h=no ;; -+esac - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_defined__POSIX_THREADS_unistd_h" >&5 - printf "%s\n" "$ac_cv_defined__POSIX_THREADS_unistd_h" >&6; } - if test $ac_cv_defined__POSIX_THREADS_unistd_h != "no" - then : - unistd_defines_pthreads=yes --else $as_nop -- unistd_defines_pthreads=no -+else case e in #( -+ e) unistd_defines_pthreads=no ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $unistd_defines_pthreads" >&5 - printf "%s\n" "$unistd_defines_pthreads" >&6; } -@@ -16906,8 +17728,8 @@ - printf "%s\n" "yes" >&6; } - posix_threads=yes - --else $as_nop -- -+else case e in #( -+ e) - LIBS=$_libs - ac_fn_c_check_func "$LINENO" "pthread_detach" "ac_cv_func_pthread_detach" - if test "x$ac_cv_func_pthread_detach" = xyes -@@ -16915,23 +17737,29 @@ - - posix_threads=yes - --else $as_nop -- -+else case e in #( -+ e) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthreads" >&5 - printf %s "checking for pthread_create in -lpthreads... " >&6; } - if test ${ac_cv_lib_pthreads_pthread_create+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lpthreads $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char pthread_create (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char pthread_create (void); - int - main (void) - { -@@ -16943,12 +17771,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_pthreads_pthread_create=yes --else $as_nop -- ac_cv_lib_pthreads_pthread_create=no -+else case e in #( -+ e) ac_cv_lib_pthreads_pthread_create=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthreads_pthread_create" >&5 - printf "%s\n" "$ac_cv_lib_pthreads_pthread_create" >&6; } -@@ -16958,23 +17788,29 @@ - posix_threads=yes - LIBS="$LIBS -lpthreads" - --else $as_nop -- -+else case e in #( -+ e) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lc_r" >&5 - printf %s "checking for pthread_create in -lc_r... " >&6; } - if test ${ac_cv_lib_c_r_pthread_create+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lc_r $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char pthread_create (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char pthread_create (void); - int - main (void) - { -@@ -16986,12 +17822,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_c_r_pthread_create=yes --else $as_nop -- ac_cv_lib_c_r_pthread_create=no -+else case e in #( -+ e) ac_cv_lib_c_r_pthread_create=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_create" >&5 - printf "%s\n" "$ac_cv_lib_c_r_pthread_create" >&6; } -@@ -17001,23 +17839,29 @@ - posix_threads=yes - LIBS="$LIBS -lc_r" - --else $as_nop -- -+else case e in #( -+ e) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __pthread_create_system in -lpthread" >&5 - printf %s "checking for __pthread_create_system in -lpthread... " >&6; } - if test ${ac_cv_lib_pthread___pthread_create_system+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lpthread $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char __pthread_create_system (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char __pthread_create_system (void); - int - main (void) - { -@@ -17029,12 +17873,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_pthread___pthread_create_system=yes --else $as_nop -- ac_cv_lib_pthread___pthread_create_system=no -+else case e in #( -+ e) ac_cv_lib_pthread___pthread_create_system=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread___pthread_create_system" >&5 - printf "%s\n" "$ac_cv_lib_pthread___pthread_create_system" >&6; } -@@ -17044,23 +17890,29 @@ - posix_threads=yes - LIBS="$LIBS -lpthread" - --else $as_nop -- -+else case e in #( -+ e) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lcma" >&5 - printf %s "checking for pthread_create in -lcma... " >&6; } - if test ${ac_cv_lib_cma_pthread_create+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lcma $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char pthread_create (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char pthread_create (void); - int - main (void) - { -@@ -17072,12 +17924,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_cma_pthread_create=yes --else $as_nop -- ac_cv_lib_cma_pthread_create=no -+else case e in #( -+ e) ac_cv_lib_cma_pthread_create=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cma_pthread_create" >&5 - printf "%s\n" "$ac_cv_lib_cma_pthread_create" >&6; } -@@ -17087,8 +17941,8 @@ - posix_threads=yes - LIBS="$LIBS -lcma" - --else $as_nop -- -+else case e in #( -+ e) - case $ac_sys_system in #( - WASI) : - posix_threads=stub ;; #( -@@ -17096,17 +17950,23 @@ - as_fn_error $? "could not find pthreads on your system" "$LINENO" 5 - ;; - esac -- -+ ;; -+esac - fi -- -+ ;; -+esac - fi -- -+ ;; -+esac - fi -- -+ ;; -+esac - fi -- -+ ;; -+esac - fi -- -+ ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -@@ -17116,16 +17976,22 @@ - if test ${ac_cv_lib_mpc_usconfig+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lmpc $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char usconfig (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char usconfig (void); - int - main (void) - { -@@ -17137,12 +18003,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_mpc_usconfig=yes --else $as_nop -- ac_cv_lib_mpc_usconfig=no -+else case e in #( -+ e) ac_cv_lib_mpc_usconfig=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mpc_usconfig" >&5 - printf "%s\n" "$ac_cv_lib_mpc_usconfig" >&6; } -@@ -17188,12 +18056,12 @@ - if test ${ac_cv_pthread_system_supported+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test "$cross_compiling" = yes -+else case e in #( -+ e) if test "$cross_compiling" = yes - then : - ac_cv_pthread_system_supported=no --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -17213,14 +18081,17 @@ - if ac_fn_c_try_run "$LINENO" - then : - ac_cv_pthread_system_supported=yes --else $as_nop -- ac_cv_pthread_system_supported=no -+else case e in #( -+ e) ac_cv_pthread_system_supported=no ;; -+esac - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext -+ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_pthread_system_supported" >&5 - printf "%s\n" "$ac_cv_pthread_system_supported" >&6; } -@@ -17284,8 +18155,8 @@ - ipv6=yes - ;; - esac --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - /* AF_INET6 available check */ -@@ -17304,10 +18175,11 @@ - - ipv6=yes - --else $as_nop -- -+else case e in #( -+ e) - ipv6=no -- -+ ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - -@@ -17347,12 +18219,13 @@ - printf "%s\n" "yes" >&6; } - ipv6=yes - --else $as_nop -- -+else case e in #( -+ e) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 - printf "%s\n" "no" >&6; } - ipv6=no -- -+ ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - fi -@@ -17361,7 +18234,8 @@ - printf "%s\n" "#define ENABLE_IPV6 1" >>confdefs.h - - fi -- -+ ;; -+esac - fi - - -@@ -17380,8 +18254,8 @@ - if test ${ac_cv_defined_IPV6_INRIA_VERSION_netinet_in_h+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -17402,10 +18276,12 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_defined_IPV6_INRIA_VERSION_netinet_in_h=yes --else $as_nop -- ac_cv_defined_IPV6_INRIA_VERSION_netinet_in_h=no -+else case e in #( -+ e) ac_cv_defined_IPV6_INRIA_VERSION_netinet_in_h=no ;; -+esac - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_defined_IPV6_INRIA_VERSION_netinet_in_h" >&5 - printf "%s\n" "$ac_cv_defined_IPV6_INRIA_VERSION_netinet_in_h" >&6; } -@@ -17421,8 +18297,8 @@ - if test ${ac_cv_defined___KAME___netinet_in_h+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -17443,10 +18319,12 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_defined___KAME___netinet_in_h=yes --else $as_nop -- ac_cv_defined___KAME___netinet_in_h=no -+else case e in #( -+ e) ac_cv_defined___KAME___netinet_in_h=no ;; -+esac - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_defined___KAME___netinet_in_h" >&5 - printf "%s\n" "$ac_cv_defined___KAME___netinet_in_h" >&6; } -@@ -17465,8 +18343,8 @@ - if test ${ac_cv_defined___GLIBC___features_h+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -17487,10 +18365,12 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_defined___GLIBC___features_h=yes --else $as_nop -- ac_cv_defined___GLIBC___features_h=no -+else case e in #( -+ e) ac_cv_defined___GLIBC___features_h=no ;; -+esac - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_defined___GLIBC___features_h" >&5 - printf "%s\n" "$ac_cv_defined___GLIBC___features_h" >&6; } -@@ -17523,8 +18403,8 @@ - if test ${ac_cv_defined__TOSHIBA_INET6_sys_param_h+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -17545,10 +18425,12 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_defined__TOSHIBA_INET6_sys_param_h=yes --else $as_nop -- ac_cv_defined__TOSHIBA_INET6_sys_param_h=no -+else case e in #( -+ e) ac_cv_defined__TOSHIBA_INET6_sys_param_h=no ;; -+esac - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_defined__TOSHIBA_INET6_sys_param_h" >&5 - printf "%s\n" "$ac_cv_defined__TOSHIBA_INET6_sys_param_h" >&6; } -@@ -17566,8 +18448,8 @@ - if test ${ac_cv_defined___V6D____usr_local_v6_include_sys_v6config_h+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -17588,10 +18470,12 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_defined___V6D____usr_local_v6_include_sys_v6config_h=yes --else $as_nop -- ac_cv_defined___V6D____usr_local_v6_include_sys_v6config_h=no -+else case e in #( -+ e) ac_cv_defined___V6D____usr_local_v6_include_sys_v6config_h=no ;; -+esac - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_defined___V6D____usr_local_v6_include_sys_v6config_h" >&5 - printf "%s\n" "$ac_cv_defined___V6D____usr_local_v6_include_sys_v6config_h" >&6; } -@@ -17610,8 +18494,8 @@ - if test ${ac_cv_defined__ZETA_MINAMI_INET6_sys_param_h+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -17632,10 +18516,12 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_defined__ZETA_MINAMI_INET6_sys_param_h=yes --else $as_nop -- ac_cv_defined__ZETA_MINAMI_INET6_sys_param_h=no -+else case e in #( -+ e) ac_cv_defined__ZETA_MINAMI_INET6_sys_param_h=no ;; -+esac - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_defined__ZETA_MINAMI_INET6_sys_param_h" >&5 - printf "%s\n" "$ac_cv_defined__ZETA_MINAMI_INET6_sys_param_h" >&6; } -@@ -17671,10 +18557,11 @@ - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: libc" >&5 - printf "%s\n" "libc" >&6; } - --else $as_nop -- -+else case e in #( -+ e) - as_fn_error $? "No $ipv6lib library found; cannot continue. You need to fetch lib$ipv6lib.a from appropriate ipv6 kit and compile beforehand." "$LINENO" 5 -- -+ ;; -+esac - fi - fi - fi -@@ -17685,8 +18572,8 @@ - if test ${ac_cv_can_raw_fd_frames+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - /* CAN_RAW_FD_FRAMES available check */ -@@ -17702,11 +18589,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_can_raw_fd_frames=yes --else $as_nop -- ac_cv_can_raw_fd_frames=no -+else case e in #( -+ e) ac_cv_can_raw_fd_frames=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_can_raw_fd_frames" >&5 - printf "%s\n" "$ac_cv_can_raw_fd_frames" >&6; } -@@ -17724,8 +18613,8 @@ - if test ${ac_cv_can_raw_join_filters+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - -@@ -17741,11 +18630,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_can_raw_join_filters=yes --else $as_nop -- ac_cv_can_raw_join_filters=no -+else case e in #( -+ e) ac_cv_can_raw_join_filters=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_can_raw_join_filters" >&5 - printf "%s\n" "$ac_cv_can_raw_join_filters" >&6; } -@@ -17787,8 +18678,8 @@ - if test ${ac_cv_header_stdatomic_h+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - -@@ -17808,12 +18699,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_header_stdatomic_h=yes --else $as_nop -- ac_cv_header_stdatomic_h=no -+else case e in #( -+ e) ac_cv_header_stdatomic_h=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdatomic_h" >&5 - printf "%s\n" "$ac_cv_header_stdatomic_h" >&6; } -@@ -17833,8 +18726,8 @@ - if test ${ac_cv_builtin_atomic+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - -@@ -17851,12 +18744,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_builtin_atomic=yes --else $as_nop -- ac_cv_builtin_atomic=no -+else case e in #( -+ e) ac_cv_builtin_atomic=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_builtin_atomic" >&5 - printf "%s\n" "$ac_cv_builtin_atomic" >&6; } -@@ -17878,9 +18773,10 @@ - if test ${with_mimalloc+y} - then : - withval=$with_mimalloc; --else $as_nop -- with_mimalloc="$ac_cv_header_stdatomic_h" -- -+else case e in #( -+ e) with_mimalloc="$ac_cv_header_stdatomic_h" -+ ;; -+esac - fi - - -@@ -17969,9 +18865,10 @@ - if test ${with_valgrind+y} - then : - withval=$with_valgrind; --else $as_nop -- with_valgrind=no -- -+else case e in #( -+ e) with_valgrind=no -+ ;; -+esac - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_valgrind" >&5 -@@ -17983,9 +18880,10 @@ - - printf "%s\n" "#define WITH_VALGRIND 1" >>confdefs.h - --else $as_nop -- as_fn_error $? "Valgrind support requested but headers not available" "$LINENO" 5 -- -+else case e in #( -+ e) as_fn_error $? "Valgrind support requested but headers not available" "$LINENO" 5 -+ ;; -+esac - fi - - OPT="-DDYNAMIC_ANNOTATIONS_ENABLED=1 $OPT" -@@ -17999,8 +18897,9 @@ - if test ${with_dtrace+y} - then : - withval=$with_dtrace; --else $as_nop -- with_dtrace=no -+else case e in #( -+ e) with_dtrace=no ;; -+esac - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_dtrace" >&5 -@@ -18023,8 +18922,8 @@ - if test ${ac_cv_path_DTRACE+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- case $DTRACE in -+else case e in #( -+ e) case $DTRACE in - [\\/]* | ?:[\\/]*) - ac_cv_path_DTRACE="$DTRACE" # Let the user override the test with a path. - ;; -@@ -18050,6 +18949,7 @@ - - test -z "$ac_cv_path_DTRACE" && ac_cv_path_DTRACE="not found" - ;; -+esac ;; - esac - fi - DTRACE=$ac_cv_path_DTRACE -@@ -18079,12 +18979,13 @@ - if test ${ac_cv_dtrace_link+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_cv_dtrace_link=no -+else case e in #( -+ e) ac_cv_dtrace_link=no - echo 'BEGIN{}' > conftest.d - "$DTRACE" $DFLAGS -G -s conftest.d -o conftest.o > /dev/null 2>&1 && \ - ac_cv_dtrace_link=yes -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_dtrace_link" >&5 - printf "%s\n" "$ac_cv_dtrace_link" >&6; } -@@ -18187,7 +19088,7 @@ - fi - - for name in $blocked_funcs; do -- as_func_var=`printf "%s\n" "ac_cv_func_$name" | $as_tr_sh` -+ as_func_var=`printf "%s\n" "ac_cv_func_$name" | sed "$as_sed_sh"` - - eval "$as_func_var=no" - -@@ -18260,6 +19161,12 @@ - then : - printf "%s\n" "#define HAVE_CTERMID 1" >>confdefs.h - -+fi -+ac_fn_c_check_func "$LINENO" "dladdr" "ac_cv_func_dladdr" -+if test "x$ac_cv_func_dladdr" = xyes -+then : -+ printf "%s\n" "#define HAVE_DLADDR 1" >>confdefs.h -+ - fi - ac_fn_c_check_func "$LINENO" "dup" "ac_cv_func_dup" - if test "x$ac_cv_func_dup" = xyes -@@ -18272,12 +19179,6 @@ - then : - printf "%s\n" "#define HAVE_DUP3 1" >>confdefs.h - --fi --ac_fn_c_check_func "$LINENO" "execv" "ac_cv_func_execv" --if test "x$ac_cv_func_execv" = xyes --then : -- printf "%s\n" "#define HAVE_EXECV 1" >>confdefs.h -- - fi - ac_fn_c_check_func "$LINENO" "explicit_bzero" "ac_cv_func_explicit_bzero" - if test "x$ac_cv_func_explicit_bzero" = xyes -@@ -18338,18 +19239,6 @@ - then : - printf "%s\n" "#define HAVE_FEXECVE 1" >>confdefs.h - --fi --ac_fn_c_check_func "$LINENO" "fork" "ac_cv_func_fork" --if test "x$ac_cv_func_fork" = xyes --then : -- printf "%s\n" "#define HAVE_FORK 1" >>confdefs.h -- --fi --ac_fn_c_check_func "$LINENO" "fork1" "ac_cv_func_fork1" --if test "x$ac_cv_func_fork1" = xyes --then : -- printf "%s\n" "#define HAVE_FORK1 1" >>confdefs.h -- - fi - ac_fn_c_check_func "$LINENO" "fpathconf" "ac_cv_func_fpathconf" - if test "x$ac_cv_func_fpathconf" = xyes -@@ -18776,24 +19665,6 @@ - then : - printf "%s\n" "#define HAVE_POSIX_OPENPT 1" >>confdefs.h - --fi --ac_fn_c_check_func "$LINENO" "posix_spawn" "ac_cv_func_posix_spawn" --if test "x$ac_cv_func_posix_spawn" = xyes --then : -- printf "%s\n" "#define HAVE_POSIX_SPAWN 1" >>confdefs.h -- --fi --ac_fn_c_check_func "$LINENO" "posix_spawnp" "ac_cv_func_posix_spawnp" --if test "x$ac_cv_func_posix_spawnp" = xyes --then : -- printf "%s\n" "#define HAVE_POSIX_SPAWNP 1" >>confdefs.h -- --fi --ac_fn_c_check_func "$LINENO" "posix_spawn_file_actions_addclosefrom_np" "ac_cv_func_posix_spawn_file_actions_addclosefrom_np" --if test "x$ac_cv_func_posix_spawn_file_actions_addclosefrom_np" = xyes --then : -- printf "%s\n" "#define HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP 1" >>confdefs.h -- - fi - ac_fn_c_check_func "$LINENO" "pread" "ac_cv_func_pread" - if test "x$ac_cv_func_pread" = xyes -@@ -19094,12 +19965,6 @@ - then : - printf "%s\n" "#define HAVE_SIGACTION 1" >>confdefs.h - --fi --ac_fn_c_check_func "$LINENO" "sigaltstack" "ac_cv_func_sigaltstack" --if test "x$ac_cv_func_sigaltstack" = xyes --then : -- printf "%s\n" "#define HAVE_SIGALTSTACK 1" >>confdefs.h -- - fi - ac_fn_c_check_func "$LINENO" "sigfillset" "ac_cv_func_sigfillset" - if test "x$ac_cv_func_sigfillset" = xyes -@@ -19368,11 +20233,11 @@ - - fi - --# iOS defines some system methods that can be linked (so they are -+# iOS/tvOS/watchOS define some system methods that can be linked (so they are - # found by configure), but either raise a compilation error (because the - # header definition prevents usage - autoconf doesn't use the headers), or - # raise an error if used at runtime. Force these symbols off. --if test "$ac_sys_system" != "iOS" ; then -+if test "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then - ac_fn_c_check_func "$LINENO" "getentropy" "ac_cv_func_getentropy" - if test "x$ac_cv_func_getentropy" = xyes - then : -@@ -19394,13 +20259,60 @@ - - fi - -+# tvOS/watchOS have some additional methods that can be found, but not used. -+if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then -+ ac_fn_c_check_func "$LINENO" "execv" "ac_cv_func_execv" -+if test "x$ac_cv_func_execv" = xyes -+then : -+ printf "%s\n" "#define HAVE_EXECV 1" >>confdefs.h -+ -+fi -+ac_fn_c_check_func "$LINENO" "fork" "ac_cv_func_fork" -+if test "x$ac_cv_func_fork" = xyes -+then : -+ printf "%s\n" "#define HAVE_FORK 1" >>confdefs.h -+ -+fi -+ac_fn_c_check_func "$LINENO" "fork1" "ac_cv_func_fork1" -+if test "x$ac_cv_func_fork1" = xyes -+then : -+ printf "%s\n" "#define HAVE_FORK1 1" >>confdefs.h -+ -+fi -+ac_fn_c_check_func "$LINENO" "posix_spawn" "ac_cv_func_posix_spawn" -+if test "x$ac_cv_func_posix_spawn" = xyes -+then : -+ printf "%s\n" "#define HAVE_POSIX_SPAWN 1" >>confdefs.h -+ -+fi -+ac_fn_c_check_func "$LINENO" "posix_spawnp" "ac_cv_func_posix_spawnp" -+if test "x$ac_cv_func_posix_spawnp" = xyes -+then : -+ printf "%s\n" "#define HAVE_POSIX_SPAWNP 1" >>confdefs.h -+ -+fi -+ac_fn_c_check_func "$LINENO" "posix_spawn_file_actions_addclosefrom_np" "ac_cv_func_posix_spawn_file_actions_addclosefrom_np" -+if test "x$ac_cv_func_posix_spawn_file_actions_addclosefrom_np" = xyes -+then : -+ printf "%s\n" "#define HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP 1" >>confdefs.h -+ -+fi -+ac_fn_c_check_func "$LINENO" "sigaltstack" "ac_cv_func_sigaltstack" -+if test "x$ac_cv_func_sigaltstack" = xyes -+then : -+ printf "%s\n" "#define HAVE_SIGALTSTACK 1" >>confdefs.h -+ -+fi -+ -+fi -+ - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5 - printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; } - if test ${ac_cv_c_undeclared_builtin_options+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_save_CFLAGS=$CFLAGS -+else case e in #( -+ e) ac_save_CFLAGS=$CFLAGS - ac_cv_c_undeclared_builtin_options='cannot detect' - for ac_arg in '' -fno-builtin; do - CFLAGS="$ac_save_CFLAGS $ac_arg" -@@ -19419,8 +20331,8 @@ - if ac_fn_c_try_compile "$LINENO" - then : - --else $as_nop -- # This test program should compile successfully. -+else case e in #( -+ e) # This test program should compile successfully. - # No library function is consistently available on - # freestanding implementations, so test against a dummy - # declaration. Include always-available headers on the -@@ -19448,26 +20360,29 @@ - if test x"$ac_arg" = x - then : - ac_cv_c_undeclared_builtin_options='none needed' --else $as_nop -- ac_cv_c_undeclared_builtin_options=$ac_arg -+else case e in #( -+ e) ac_cv_c_undeclared_builtin_options=$ac_arg ;; -+esac - fi - break - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - done - CFLAGS=$ac_save_CFLAGS -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5 - printf "%s\n" "$ac_cv_c_undeclared_builtin_options" >&6; } - case $ac_cv_c_undeclared_builtin_options in #( - 'cannot detect') : -- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error $? "cannot make $CC report undeclared builtins --See \`config.log' for more details" "$LINENO" 5; } ;; #( -+See 'config.log' for more details" "$LINENO" 5; } ;; #( - 'none needed') : - ac_c_undeclared_builtin_options='' ;; #( - *) : -@@ -19493,8 +20408,8 @@ - if test ${ac_cv_func_chroot+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -19508,11 +20423,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_chroot=yes --else $as_nop -- ac_cv_func_chroot=no -+else case e in #( -+ e) ac_cv_func_chroot=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_chroot" >&5 - printf "%s\n" "$ac_cv_func_chroot" >&6; } -@@ -19532,8 +20449,8 @@ - if test ${ac_cv_func_link+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -19547,11 +20464,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_link=yes --else $as_nop -- ac_cv_func_link=no -+else case e in #( -+ e) ac_cv_func_link=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_link" >&5 - printf "%s\n" "$ac_cv_func_link" >&6; } -@@ -19571,8 +20490,8 @@ - if test ${ac_cv_func_symlink+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -19586,11 +20505,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_symlink=yes --else $as_nop -- ac_cv_func_symlink=no -+else case e in #( -+ e) ac_cv_func_symlink=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_symlink" >&5 - printf "%s\n" "$ac_cv_func_symlink" >&6; } -@@ -19610,8 +20531,8 @@ - if test ${ac_cv_func_fchdir+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -19625,11 +20546,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_fchdir=yes --else $as_nop -- ac_cv_func_fchdir=no -+else case e in #( -+ e) ac_cv_func_fchdir=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fchdir" >&5 - printf "%s\n" "$ac_cv_func_fchdir" >&6; } -@@ -19649,8 +20572,8 @@ - if test ${ac_cv_func_fsync+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -19664,11 +20587,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_fsync=yes --else $as_nop -- ac_cv_func_fsync=no -+else case e in #( -+ e) ac_cv_func_fsync=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fsync" >&5 - printf "%s\n" "$ac_cv_func_fsync" >&6; } -@@ -19688,8 +20613,8 @@ - if test ${ac_cv_func_fdatasync+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -19703,11 +20628,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_fdatasync=yes --else $as_nop -- ac_cv_func_fdatasync=no -+else case e in #( -+ e) ac_cv_func_fdatasync=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fdatasync" >&5 - printf "%s\n" "$ac_cv_func_fdatasync" >&6; } -@@ -19727,8 +20654,8 @@ - if test ${ac_cv_func_epoll_create+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -19742,11 +20669,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_epoll_create=yes --else $as_nop -- ac_cv_func_epoll_create=no -+else case e in #( -+ e) ac_cv_func_epoll_create=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_epoll_create" >&5 - printf "%s\n" "$ac_cv_func_epoll_create" >&6; } -@@ -19766,8 +20695,8 @@ - if test ${ac_cv_func_epoll_create1+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -19781,11 +20710,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_epoll_create1=yes --else $as_nop -- ac_cv_func_epoll_create1=no -+else case e in #( -+ e) ac_cv_func_epoll_create1=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_epoll_create1" >&5 - printf "%s\n" "$ac_cv_func_epoll_create1" >&6; } -@@ -19805,8 +20736,8 @@ - if test ${ac_cv_func_kqueue+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -19823,11 +20754,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_kqueue=yes --else $as_nop -- ac_cv_func_kqueue=no -+else case e in #( -+ e) ac_cv_func_kqueue=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_kqueue" >&5 - printf "%s\n" "$ac_cv_func_kqueue" >&6; } -@@ -19847,8 +20780,8 @@ - if test ${ac_cv_func_prlimit+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -19865,11 +20798,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_prlimit=yes --else $as_nop -- ac_cv_func_prlimit=no -+else case e in #( -+ e) ac_cv_func_prlimit=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_prlimit" >&5 - printf "%s\n" "$ac_cv_func_prlimit" >&6; } -@@ -19890,8 +20825,8 @@ - if test ${ac_cv_func__dyld_shared_cache_contains_path+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -19905,11 +20840,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func__dyld_shared_cache_contains_path=yes --else $as_nop -- ac_cv_func__dyld_shared_cache_contains_path=no -+else case e in #( -+ e) ac_cv_func__dyld_shared_cache_contains_path=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func__dyld_shared_cache_contains_path" >&5 - printf "%s\n" "$ac_cv_func__dyld_shared_cache_contains_path" >&6; } -@@ -19930,8 +20867,8 @@ - if test ${ac_cv_func_memfd_create+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #ifdef HAVE_SYS_MMAN_H -@@ -19952,11 +20889,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_memfd_create=yes --else $as_nop -- ac_cv_func_memfd_create=no -+else case e in #( -+ e) ac_cv_func_memfd_create=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_memfd_create" >&5 - printf "%s\n" "$ac_cv_func_memfd_create" >&6; } -@@ -19977,8 +20916,8 @@ - if test ${ac_cv_func_eventfd+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #ifdef HAVE_SYS_EVENTFD_H -@@ -19996,11 +20935,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_eventfd=yes --else $as_nop -- ac_cv_func_eventfd=no -+else case e in #( -+ e) ac_cv_func_eventfd=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_eventfd" >&5 - printf "%s\n" "$ac_cv_func_eventfd" >&6; } -@@ -20021,8 +20962,8 @@ - if test ${ac_cv_func_timerfd_create+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #ifdef HAVE_SYS_TIMERFD_H -@@ -20040,11 +20981,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_timerfd_create=yes --else $as_nop -- ac_cv_func_timerfd_create=no -+else case e in #( -+ e) ac_cv_func_timerfd_create=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_timerfd_create" >&5 - printf "%s\n" "$ac_cv_func_timerfd_create" >&6; } -@@ -20071,8 +21014,8 @@ - if test ${ac_cv_func_ctermid_r+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -20086,11 +21029,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_ctermid_r=yes --else $as_nop -- ac_cv_func_ctermid_r=no -+else case e in #( -+ e) ac_cv_func_ctermid_r=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_ctermid_r" >&5 - printf "%s\n" "$ac_cv_func_ctermid_r" >&6; } -@@ -20109,8 +21054,8 @@ - if test ${ac_cv_flock_decl+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -20125,12 +21070,14 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_flock_decl=yes --else $as_nop -- ac_cv_flock_decl=no -- -+else case e in #( -+ e) ac_cv_flock_decl=no -+ ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_flock_decl" >&5 - printf "%s\n" "$ac_cv_flock_decl" >&6; } -@@ -20144,22 +21091,28 @@ - then : - printf "%s\n" "#define HAVE_FLOCK 1" >>confdefs.h - --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for flock in -lbsd" >&5 -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for flock in -lbsd" >&5 - printf %s "checking for flock in -lbsd... " >&6; } - if test ${ac_cv_lib_bsd_flock+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lbsd $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char flock (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char flock (void); - int - main (void) - { -@@ -20171,12 +21124,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_bsd_flock=yes --else $as_nop -- ac_cv_lib_bsd_flock=no -+else case e in #( -+ e) ac_cv_lib_bsd_flock=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_flock" >&5 - printf "%s\n" "$ac_cv_lib_bsd_flock" >&6; } -@@ -20184,7 +21139,8 @@ - then : - FCNTL_LIBS="-lbsd" - fi -- -+ ;; -+esac - fi - - done -@@ -20197,8 +21153,8 @@ - if test ${ac_cv_func_getpagesize+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -20212,11 +21168,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_getpagesize=yes --else $as_nop -- ac_cv_func_getpagesize=no -+else case e in #( -+ e) ac_cv_func_getpagesize=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getpagesize" >&5 - printf "%s\n" "$ac_cv_func_getpagesize" >&6; } -@@ -20235,8 +21193,8 @@ - if test ${ac_cv_broken_unsetenv+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -20250,12 +21208,14 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_broken_unsetenv=no --else $as_nop -- ac_cv_broken_unsetenv=yes -- -+else case e in #( -+ e) ac_cv_broken_unsetenv=yes -+ ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_broken_unsetenv" >&5 - printf "%s\n" "$ac_cv_broken_unsetenv" >&6; } -@@ -20277,8 +21237,8 @@ - if test ${ac_cv_prog_TRUE+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test -n "$TRUE"; then -+else case e in #( -+ e) if test -n "$TRUE"; then - ac_cv_prog_TRUE="$TRUE" # Let the user override the test. - else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -@@ -20300,7 +21260,8 @@ - done - IFS=$as_save_IFS - --fi -+fi ;; -+esac - fi - TRUE=$ac_cv_prog_TRUE - if test -n "$TRUE"; then -@@ -20322,16 +21283,22 @@ - if test ${ac_cv_lib_c_inet_aton+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lc $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char inet_aton (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char inet_aton (void); - int - main (void) - { -@@ -20343,34 +21310,42 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_c_inet_aton=yes --else $as_nop -- ac_cv_lib_c_inet_aton=no -+else case e in #( -+ e) ac_cv_lib_c_inet_aton=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_inet_aton" >&5 - printf "%s\n" "$ac_cv_lib_c_inet_aton" >&6; } - if test "x$ac_cv_lib_c_inet_aton" = xyes - then : - $ac_cv_prog_TRUE --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inet_aton in -lresolv" >&5 -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inet_aton in -lresolv" >&5 - printf %s "checking for inet_aton in -lresolv... " >&6; } - if test ${ac_cv_lib_resolv_inet_aton+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lresolv $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char inet_aton (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char inet_aton (void); - int - main (void) - { -@@ -20382,12 +21357,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_resolv_inet_aton=yes --else $as_nop -- ac_cv_lib_resolv_inet_aton=no -+else case e in #( -+ e) ac_cv_lib_resolv_inet_aton=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_inet_aton" >&5 - printf "%s\n" "$ac_cv_lib_resolv_inet_aton" >&6; } -@@ -20396,7 +21373,8 @@ - SOCKET_LIBS="-lresolv" - fi - -- -+ ;; -+esac - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for hstrerror in -lc" >&5 -@@ -20404,16 +21382,22 @@ - if test ${ac_cv_lib_c_hstrerror+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lc $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char hstrerror (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char hstrerror (void); - int - main (void) - { -@@ -20425,34 +21409,42 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_c_hstrerror=yes --else $as_nop -- ac_cv_lib_c_hstrerror=no -+else case e in #( -+ e) ac_cv_lib_c_hstrerror=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_hstrerror" >&5 - printf "%s\n" "$ac_cv_lib_c_hstrerror" >&6; } - if test "x$ac_cv_lib_c_hstrerror" = xyes - then : - $ac_cv_prog_TRUE --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for hstrerror in -lresolv" >&5 -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for hstrerror in -lresolv" >&5 - printf %s "checking for hstrerror in -lresolv... " >&6; } - if test ${ac_cv_lib_resolv_hstrerror+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lresolv $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char hstrerror (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char hstrerror (void); - int - main (void) - { -@@ -20464,12 +21456,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_resolv_hstrerror=yes --else $as_nop -- ac_cv_lib_resolv_hstrerror=no -+else case e in #( -+ e) ac_cv_lib_resolv_hstrerror=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_hstrerror" >&5 - printf "%s\n" "$ac_cv_lib_resolv_hstrerror" >&6; } -@@ -20478,7 +21472,8 @@ - SOCKET_LIBS="-lresolv" - fi - -- -+ ;; -+esac - fi - - -@@ -20489,12 +21484,12 @@ - if test ${ac_cv_have_chflags+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test "$cross_compiling" = yes -+else case e in #( -+ e) if test "$cross_compiling" = yes - then : - ac_cv_have_chflags=cross --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -20510,14 +21505,17 @@ - if ac_fn_c_try_run "$LINENO" - then : - ac_cv_have_chflags=yes --else $as_nop -- ac_cv_have_chflags=no -+else case e in #( -+ e) ac_cv_have_chflags=no ;; -+esac - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext -+ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_chflags" >&5 - printf "%s\n" "$ac_cv_have_chflags" >&6; } -@@ -20526,8 +21524,9 @@ - if test "x$ac_cv_func_chflags" = xyes - then : - ac_cv_have_chflags="yes" --else $as_nop -- ac_cv_have_chflags="no" -+else case e in #( -+ e) ac_cv_have_chflags="no" ;; -+esac - fi - - fi -@@ -20542,12 +21541,12 @@ - if test ${ac_cv_have_lchflags+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test "$cross_compiling" = yes -+else case e in #( -+ e) if test "$cross_compiling" = yes - then : - ac_cv_have_lchflags=cross --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -20563,14 +21562,17 @@ - if ac_fn_c_try_run "$LINENO" - then : - ac_cv_have_lchflags=yes --else $as_nop -- ac_cv_have_lchflags=no -+else case e in #( -+ e) ac_cv_have_lchflags=no ;; -+esac - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext -+ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_lchflags" >&5 - printf "%s\n" "$ac_cv_have_lchflags" >&6; } -@@ -20579,8 +21581,9 @@ - if test "x$ac_cv_func_lchflags" = xyes - then : - ac_cv_have_lchflags="yes" --else $as_nop -- ac_cv_have_lchflags="no" -+else case e in #( -+ e) ac_cv_have_lchflags="no" ;; -+esac - fi - - fi -@@ -20687,16 +21690,22 @@ - if test ${ac_cv_lib_z_gzread+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lz $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char gzread (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char gzread (void); - int - main (void) - { -@@ -20708,27 +21717,31 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_z_gzread=yes --else $as_nop -- ac_cv_lib_z_gzread=no -+else case e in #( -+ e) ac_cv_lib_z_gzread=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_gzread" >&5 - printf "%s\n" "$ac_cv_lib_z_gzread" >&6; } - if test "x$ac_cv_lib_z_gzread" = xyes - then : - have_zlib=yes --else $as_nop -- have_zlib=no -+else case e in #( -+ e) have_zlib=no ;; -+esac - fi - - LIBS=$py_check_lib_save_LIBS - - --else $as_nop -- have_zlib=no -+else case e in #( -+ e) have_zlib=no ;; -+esac - fi - - done -@@ -20743,16 +21756,22 @@ - if test ${ac_cv_lib_z_inflateCopy+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lz $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char inflateCopy (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char inflateCopy (void); - int - main (void) - { -@@ -20764,12 +21783,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_z_inflateCopy=yes --else $as_nop -- ac_cv_lib_z_inflateCopy=no -+else case e in #( -+ e) ac_cv_lib_z_inflateCopy=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_inflateCopy" >&5 - printf "%s\n" "$ac_cv_lib_z_inflateCopy" >&6; } -@@ -20816,16 +21837,22 @@ - if test ${ac_cv_lib_z_gzread+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lz $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char gzread (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char gzread (void); - int - main (void) - { -@@ -20837,27 +21864,31 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_z_gzread=yes --else $as_nop -- ac_cv_lib_z_gzread=no -+else case e in #( -+ e) ac_cv_lib_z_gzread=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_gzread" >&5 - printf "%s\n" "$ac_cv_lib_z_gzread" >&6; } - if test "x$ac_cv_lib_z_gzread" = xyes - then : - have_zlib=yes --else $as_nop -- have_zlib=no -+else case e in #( -+ e) have_zlib=no ;; -+esac - fi - - LIBS=$py_check_lib_save_LIBS - - --else $as_nop -- have_zlib=no -+else case e in #( -+ e) have_zlib=no ;; -+esac - fi - - done -@@ -20872,16 +21903,22 @@ - if test ${ac_cv_lib_z_inflateCopy+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lz $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char inflateCopy (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char inflateCopy (void); - int - main (void) - { -@@ -20893,12 +21930,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_z_inflateCopy=yes --else $as_nop -- ac_cv_lib_z_inflateCopy=no -+else case e in #( -+ e) ac_cv_lib_z_inflateCopy=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_inflateCopy" >&5 - printf "%s\n" "$ac_cv_lib_z_inflateCopy" >&6; } -@@ -21034,16 +22073,22 @@ - if test ${ac_cv_lib_bz2_BZ2_bzCompress+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lbz2 $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char BZ2_bzCompress (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char BZ2_bzCompress (void); - int - main (void) - { -@@ -21055,25 +22100,29 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_bz2_BZ2_bzCompress=yes --else $as_nop -- ac_cv_lib_bz2_BZ2_bzCompress=no -+else case e in #( -+ e) ac_cv_lib_bz2_BZ2_bzCompress=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bz2_BZ2_bzCompress" >&5 - printf "%s\n" "$ac_cv_lib_bz2_BZ2_bzCompress" >&6; } - if test "x$ac_cv_lib_bz2_BZ2_bzCompress" = xyes - then : - have_bzip2=yes --else $as_nop -- have_bzip2=no -+else case e in #( -+ e) have_bzip2=no ;; -+esac - fi - - --else $as_nop -- have_bzip2=no -+else case e in #( -+ e) have_bzip2=no ;; -+esac - fi - - done -@@ -21116,16 +22165,22 @@ - if test ${ac_cv_lib_bz2_BZ2_bzCompress+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lbz2 $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char BZ2_bzCompress (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char BZ2_bzCompress (void); - int - main (void) - { -@@ -21137,25 +22192,29 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_bz2_BZ2_bzCompress=yes --else $as_nop -- ac_cv_lib_bz2_BZ2_bzCompress=no -+else case e in #( -+ e) ac_cv_lib_bz2_BZ2_bzCompress=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bz2_BZ2_bzCompress" >&5 - printf "%s\n" "$ac_cv_lib_bz2_BZ2_bzCompress" >&6; } - if test "x$ac_cv_lib_bz2_BZ2_bzCompress" = xyes - then : - have_bzip2=yes --else $as_nop -- have_bzip2=no -+else case e in #( -+ e) have_bzip2=no ;; -+esac - fi - - --else $as_nop -- have_bzip2=no -+else case e in #( -+ e) have_bzip2=no ;; -+esac - fi - - done -@@ -21262,16 +22321,22 @@ - if test ${ac_cv_lib_lzma_lzma_easy_encoder+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-llzma $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char lzma_easy_encoder (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char lzma_easy_encoder (void); - int - main (void) - { -@@ -21283,25 +22348,29 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_lzma_lzma_easy_encoder=yes --else $as_nop -- ac_cv_lib_lzma_lzma_easy_encoder=no -+else case e in #( -+ e) ac_cv_lib_lzma_lzma_easy_encoder=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lzma_lzma_easy_encoder" >&5 - printf "%s\n" "$ac_cv_lib_lzma_lzma_easy_encoder" >&6; } - if test "x$ac_cv_lib_lzma_lzma_easy_encoder" = xyes - then : - have_liblzma=yes --else $as_nop -- have_liblzma=no -+else case e in #( -+ e) have_liblzma=no ;; -+esac - fi - - --else $as_nop -- have_liblzma=no -+else case e in #( -+ e) have_liblzma=no ;; -+esac - fi - - done -@@ -21344,16 +22413,22 @@ - if test ${ac_cv_lib_lzma_lzma_easy_encoder+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-llzma $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char lzma_easy_encoder (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char lzma_easy_encoder (void); - int - main (void) - { -@@ -21365,25 +22440,29 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_lzma_lzma_easy_encoder=yes --else $as_nop -- ac_cv_lib_lzma_lzma_easy_encoder=no -+else case e in #( -+ e) ac_cv_lib_lzma_lzma_easy_encoder=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lzma_lzma_easy_encoder" >&5 - printf "%s\n" "$ac_cv_lib_lzma_lzma_easy_encoder" >&6; } - if test "x$ac_cv_lib_lzma_lzma_easy_encoder" = xyes - then : - have_liblzma=yes --else $as_nop -- have_liblzma=no -+else case e in #( -+ e) have_liblzma=no ;; -+esac - fi - - --else $as_nop -- have_liblzma=no -+else case e in #( -+ e) have_liblzma=no ;; -+esac - fi - - done -@@ -21419,8 +22498,8 @@ - if test ${ac_cv_func_hstrerror+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -21434,11 +22513,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_hstrerror=yes --else $as_nop -- ac_cv_func_hstrerror=no -+else case e in #( -+ e) ac_cv_func_hstrerror=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_hstrerror" >&5 - printf "%s\n" "$ac_cv_func_hstrerror" >&6; } -@@ -21458,8 +22539,8 @@ - if test ${ac_cv_func_getservbyname+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -21473,11 +22554,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_getservbyname=yes --else $as_nop -- ac_cv_func_getservbyname=no -+else case e in #( -+ e) ac_cv_func_getservbyname=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getservbyname" >&5 - printf "%s\n" "$ac_cv_func_getservbyname" >&6; } -@@ -21497,8 +22580,8 @@ - if test ${ac_cv_func_getservbyport+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -21512,11 +22595,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_getservbyport=yes --else $as_nop -- ac_cv_func_getservbyport=no -+else case e in #( -+ e) ac_cv_func_getservbyport=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getservbyport" >&5 - printf "%s\n" "$ac_cv_func_getservbyport" >&6; } -@@ -21536,8 +22621,8 @@ - if test ${ac_cv_func_gethostbyname+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -21551,11 +22636,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_gethostbyname=yes --else $as_nop -- ac_cv_func_gethostbyname=no -+else case e in #( -+ e) ac_cv_func_gethostbyname=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_gethostbyname" >&5 - printf "%s\n" "$ac_cv_func_gethostbyname" >&6; } -@@ -21575,8 +22662,8 @@ - if test ${ac_cv_func_gethostbyaddr+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -21590,11 +22677,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_gethostbyaddr=yes --else $as_nop -- ac_cv_func_gethostbyaddr=no -+else case e in #( -+ e) ac_cv_func_gethostbyaddr=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_gethostbyaddr" >&5 - printf "%s\n" "$ac_cv_func_gethostbyaddr" >&6; } -@@ -21614,8 +22703,8 @@ - if test ${ac_cv_func_getprotobyname+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -21629,11 +22718,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_getprotobyname=yes --else $as_nop -- ac_cv_func_getprotobyname=no -+else case e in #( -+ e) ac_cv_func_getprotobyname=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getprotobyname" >&5 - printf "%s\n" "$ac_cv_func_getprotobyname" >&6; } -@@ -21656,8 +22747,8 @@ - if test ${ac_cv_func_inet_aton+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -21676,11 +22767,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_inet_aton=yes --else $as_nop -- ac_cv_func_inet_aton=no -+else case e in #( -+ e) ac_cv_func_inet_aton=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_inet_aton" >&5 - printf "%s\n" "$ac_cv_func_inet_aton" >&6; } -@@ -21700,8 +22793,8 @@ - if test ${ac_cv_func_inet_ntoa+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -21720,11 +22813,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_inet_ntoa=yes --else $as_nop -- ac_cv_func_inet_ntoa=no -+else case e in #( -+ e) ac_cv_func_inet_ntoa=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_inet_ntoa" >&5 - printf "%s\n" "$ac_cv_func_inet_ntoa" >&6; } -@@ -21744,8 +22839,8 @@ - if test ${ac_cv_func_inet_pton+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -21764,11 +22859,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_inet_pton=yes --else $as_nop -- ac_cv_func_inet_pton=no -+else case e in #( -+ e) ac_cv_func_inet_pton=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_inet_pton" >&5 - printf "%s\n" "$ac_cv_func_inet_pton" >&6; } -@@ -21788,8 +22885,8 @@ - if test ${ac_cv_func_getpeername+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -21808,11 +22905,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_getpeername=yes --else $as_nop -- ac_cv_func_getpeername=no -+else case e in #( -+ e) ac_cv_func_getpeername=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getpeername" >&5 - printf "%s\n" "$ac_cv_func_getpeername" >&6; } -@@ -21832,8 +22931,8 @@ - if test ${ac_cv_func_getsockname+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -21852,11 +22951,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_getsockname=yes --else $as_nop -- ac_cv_func_getsockname=no -+else case e in #( -+ e) ac_cv_func_getsockname=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getsockname" >&5 - printf "%s\n" "$ac_cv_func_getsockname" >&6; } -@@ -21876,8 +22977,8 @@ - if test ${ac_cv_func_accept+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -21896,11 +22997,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_accept=yes --else $as_nop -- ac_cv_func_accept=no -+else case e in #( -+ e) ac_cv_func_accept=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_accept" >&5 - printf "%s\n" "$ac_cv_func_accept" >&6; } -@@ -21920,8 +23023,8 @@ - if test ${ac_cv_func_bind+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -21940,11 +23043,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_bind=yes --else $as_nop -- ac_cv_func_bind=no -+else case e in #( -+ e) ac_cv_func_bind=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_bind" >&5 - printf "%s\n" "$ac_cv_func_bind" >&6; } -@@ -21964,8 +23069,8 @@ - if test ${ac_cv_func_connect+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -21984,11 +23089,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_connect=yes --else $as_nop -- ac_cv_func_connect=no -+else case e in #( -+ e) ac_cv_func_connect=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_connect" >&5 - printf "%s\n" "$ac_cv_func_connect" >&6; } -@@ -22008,8 +23115,8 @@ - if test ${ac_cv_func_listen+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -22028,11 +23135,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_listen=yes --else $as_nop -- ac_cv_func_listen=no -+else case e in #( -+ e) ac_cv_func_listen=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_listen" >&5 - printf "%s\n" "$ac_cv_func_listen" >&6; } -@@ -22052,8 +23161,8 @@ - if test ${ac_cv_func_recvfrom+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -22072,11 +23181,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_recvfrom=yes --else $as_nop -- ac_cv_func_recvfrom=no -+else case e in #( -+ e) ac_cv_func_recvfrom=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_recvfrom" >&5 - printf "%s\n" "$ac_cv_func_recvfrom" >&6; } -@@ -22096,8 +23207,8 @@ - if test ${ac_cv_func_sendto+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -22116,11 +23227,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_sendto=yes --else $as_nop -- ac_cv_func_sendto=no -+else case e in #( -+ e) ac_cv_func_sendto=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_sendto" >&5 - printf "%s\n" "$ac_cv_func_sendto" >&6; } -@@ -22140,8 +23253,8 @@ - if test ${ac_cv_func_setsockopt+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -22160,11 +23273,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_setsockopt=yes --else $as_nop -- ac_cv_func_setsockopt=no -+else case e in #( -+ e) ac_cv_func_setsockopt=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_setsockopt" >&5 - printf "%s\n" "$ac_cv_func_setsockopt" >&6; } -@@ -22184,8 +23299,8 @@ - if test ${ac_cv_func_socket+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -22204,11 +23319,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_socket=yes --else $as_nop -- ac_cv_func_socket=no -+else case e in #( -+ e) ac_cv_func_socket=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_socket" >&5 - printf "%s\n" "$ac_cv_func_socket" >&6; } -@@ -22230,8 +23347,8 @@ - if test ${ac_cv_func_setgroups+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -22250,11 +23367,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_setgroups=yes --else $as_nop -- ac_cv_func_setgroups=no -+else case e in #( -+ e) ac_cv_func_setgroups=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_setgroups" >&5 - printf "%s\n" "$ac_cv_func_setgroups" >&6; } -@@ -22269,7 +23388,8 @@ - - - # check for openpty, login_tty, and forkpty -- -+# tvOS/watchOS have functions for tty, but can't use them -+if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then - - for ac_func in openpty - do : -@@ -22278,22 +23398,28 @@ - then : - printf "%s\n" "#define HAVE_OPENPTY 1" >>confdefs.h - --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for openpty in -lutil" >&5 -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for openpty in -lutil" >&5 - printf %s "checking for openpty in -lutil... " >&6; } - if test ${ac_cv_lib_util_openpty+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lutil $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char openpty (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char openpty (void); - int - main (void) - { -@@ -22305,12 +23431,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_util_openpty=yes --else $as_nop -- ac_cv_lib_util_openpty=no -+else case e in #( -+ e) ac_cv_lib_util_openpty=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_util_openpty" >&5 - printf "%s\n" "$ac_cv_lib_util_openpty" >&6; } -@@ -22318,22 +23446,28 @@ - then : - printf "%s\n" "#define HAVE_OPENPTY 1" >>confdefs.h - LIBS="$LIBS -lutil" --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for openpty in -lbsd" >&5 -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for openpty in -lbsd" >&5 - printf %s "checking for openpty in -lbsd... " >&6; } - if test ${ac_cv_lib_bsd_openpty+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lbsd $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char openpty (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char openpty (void); - int - main (void) - { -@@ -22345,12 +23479,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_bsd_openpty=yes --else $as_nop -- ac_cv_lib_bsd_openpty=no -+else case e in #( -+ e) ac_cv_lib_bsd_openpty=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_openpty" >&5 - printf "%s\n" "$ac_cv_lib_bsd_openpty" >&6; } -@@ -22359,9 +23495,11 @@ - printf "%s\n" "#define HAVE_OPENPTY 1" >>confdefs.h - LIBS="$LIBS -lbsd" - fi -- -+ ;; -+esac - fi -- -+ ;; -+esac - fi - - done -@@ -22370,15 +23508,21 @@ - if test ${ac_cv_search_login_tty+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_func_search_save_LIBS=$LIBS -+else case e in #( -+ e) ac_func_search_save_LIBS=$LIBS - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char login_tty (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char login_tty (void); - int - main (void) - { -@@ -22409,11 +23553,13 @@ - if test ${ac_cv_search_login_tty+y} - then : - --else $as_nop -- ac_cv_search_login_tty=no -+else case e in #( -+ e) ac_cv_search_login_tty=no ;; -+esac - fi - rm conftest.$ac_ext --LIBS=$ac_func_search_save_LIBS -+LIBS=$ac_func_search_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_login_tty" >&5 - printf "%s\n" "$ac_cv_search_login_tty" >&6; } -@@ -22435,22 +23581,28 @@ - then : - printf "%s\n" "#define HAVE_FORKPTY 1" >>confdefs.h - --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for forkpty in -lutil" >&5 -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for forkpty in -lutil" >&5 - printf %s "checking for forkpty in -lutil... " >&6; } - if test ${ac_cv_lib_util_forkpty+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lutil $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char forkpty (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char forkpty (void); - int - main (void) - { -@@ -22462,12 +23614,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_util_forkpty=yes --else $as_nop -- ac_cv_lib_util_forkpty=no -+else case e in #( -+ e) ac_cv_lib_util_forkpty=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_util_forkpty" >&5 - printf "%s\n" "$ac_cv_lib_util_forkpty" >&6; } -@@ -22475,22 +23629,28 @@ - then : - printf "%s\n" "#define HAVE_FORKPTY 1" >>confdefs.h - LIBS="$LIBS -lutil" --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for forkpty in -lbsd" >&5 -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for forkpty in -lbsd" >&5 - printf %s "checking for forkpty in -lbsd... " >&6; } - if test ${ac_cv_lib_bsd_forkpty+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lbsd $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char forkpty (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char forkpty (void); - int - main (void) - { -@@ -22502,12 +23662,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_bsd_forkpty=yes --else $as_nop -- ac_cv_lib_bsd_forkpty=no -+else case e in #( -+ e) ac_cv_lib_bsd_forkpty=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_forkpty" >&5 - printf "%s\n" "$ac_cv_lib_bsd_forkpty" >&6; } -@@ -22516,12 +23678,15 @@ - printf "%s\n" "#define HAVE_FORKPTY 1" >>confdefs.h - LIBS="$LIBS -lbsd" - fi -- -+ ;; -+esac - fi -- -+ ;; -+esac - fi - - done -+fi - - # check for long file support functions - ac_fn_c_check_func "$LINENO" "fseek64" "ac_cv_func_fseek64" -@@ -22567,13 +23732,14 @@ - then : - printf "%s\n" "#define HAVE_DUP2 1" >>confdefs.h - --else $as_nop -- case " $LIBOBJS " in -+else case e in #( -+ e) case " $LIBOBJS " in - *" dup2.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS dup2.$ac_objext" - ;; - esac -- -+ ;; -+esac - fi - - -@@ -22656,23 +23822,29 @@ - then : - printf "%s\n" "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h - --else $as_nop -- -+else case e in #( -+ e) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 - printf %s "checking for clock_gettime in -lrt... " >&6; } - if test ${ac_cv_lib_rt_clock_gettime+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lrt $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char clock_gettime (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char clock_gettime (void); - int - main (void) - { -@@ -22684,12 +23856,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_rt_clock_gettime=yes --else $as_nop -- ac_cv_lib_rt_clock_gettime=no -+else case e in #( -+ e) ac_cv_lib_rt_clock_gettime=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 - printf "%s\n" "$ac_cv_lib_rt_clock_gettime" >&6; } -@@ -22705,7 +23879,8 @@ - - fi - -- -+ ;; -+esac - fi - - done -@@ -22718,23 +23893,29 @@ - then : - printf "%s\n" "#define HAVE_CLOCK_GETRES 1" >>confdefs.h - --else $as_nop -- -+else case e in #( -+ e) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_getres in -lrt" >&5 - printf %s "checking for clock_getres in -lrt... " >&6; } - if test ${ac_cv_lib_rt_clock_getres+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lrt $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char clock_getres (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char clock_getres (void); - int - main (void) - { -@@ -22746,12 +23927,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_rt_clock_getres=yes --else $as_nop -- ac_cv_lib_rt_clock_getres=no -+else case e in #( -+ e) ac_cv_lib_rt_clock_getres=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_getres" >&5 - printf "%s\n" "$ac_cv_lib_rt_clock_getres" >&6; } -@@ -22763,15 +23946,16 @@ - - fi - -- -+ ;; -+esac - fi - - done - --# On Android and iOS, clock_settime can be linked (so it is found by -+# On Android, iOS, tvOS and watchOS, clock_settime can be linked (so it is found by - # configure), but when used in an unprivileged process, it crashes rather than - # returning an error. Force the symbol off. --if test "$ac_sys_system" != "Linux-android" && test "$ac_sys_system" != "iOS" -+if test "$ac_sys_system" != "Linux-android" -a "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" - then - - for ac_func in clock_settime -@@ -22781,23 +23965,29 @@ - then : - printf "%s\n" "#define HAVE_CLOCK_SETTIME 1" >>confdefs.h - --else $as_nop -- -+else case e in #( -+ e) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_settime in -lrt" >&5 - printf %s "checking for clock_settime in -lrt... " >&6; } - if test ${ac_cv_lib_rt_clock_settime+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lrt $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char clock_settime (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char clock_settime (void); - int - main (void) - { -@@ -22809,12 +23999,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_rt_clock_settime=yes --else $as_nop -- ac_cv_lib_rt_clock_settime=no -+else case e in #( -+ e) ac_cv_lib_rt_clock_settime=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_settime" >&5 - printf "%s\n" "$ac_cv_lib_rt_clock_settime" >&6; } -@@ -22826,7 +24018,8 @@ - - fi - -- -+ ;; -+esac - fi - - done -@@ -22844,23 +24037,29 @@ - then : - printf "%s\n" "#define HAVE_CLOCK_NANOSLEEP 1" >>confdefs.h - --else $as_nop -- -+else case e in #( -+ e) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_nanosleep in -lrt" >&5 - printf %s "checking for clock_nanosleep in -lrt... " >&6; } - if test ${ac_cv_lib_rt_clock_nanosleep+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lrt $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char clock_nanosleep (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char clock_nanosleep (void); - int - main (void) - { -@@ -22872,12 +24071,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_rt_clock_nanosleep=yes --else $as_nop -- ac_cv_lib_rt_clock_nanosleep=no -+else case e in #( -+ e) ac_cv_lib_rt_clock_nanosleep=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_nanosleep" >&5 - printf "%s\n" "$ac_cv_lib_rt_clock_nanosleep" >&6; } -@@ -22889,7 +24090,8 @@ - - fi - -- -+ ;; -+esac - fi - - done -@@ -22903,23 +24105,29 @@ - then : - printf "%s\n" "#define HAVE_NANOSLEEP 1" >>confdefs.h - --else $as_nop -- -+else case e in #( -+ e) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for nanosleep in -lrt" >&5 - printf %s "checking for nanosleep in -lrt... " >&6; } - if test ${ac_cv_lib_rt_nanosleep+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lrt $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char nanosleep (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char nanosleep (void); - int - main (void) - { -@@ -22931,12 +24139,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_rt_nanosleep=yes --else $as_nop -- ac_cv_lib_rt_nanosleep=no -+else case e in #( -+ e) ac_cv_lib_rt_nanosleep=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_nanosleep" >&5 - printf "%s\n" "$ac_cv_lib_rt_nanosleep" >&6; } -@@ -22948,7 +24158,8 @@ - - fi - -- -+ ;; -+esac - fi - - done -@@ -22958,8 +24169,8 @@ - if test ${ac_cv_device_macros+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - -@@ -22985,12 +24196,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_device_macros=yes --else $as_nop -- ac_cv_device_macros=no -+else case e in #( -+ e) ac_cv_device_macros=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_device_macros" >&5 - printf "%s\n" "$ac_cv_device_macros" >&6; } -@@ -23014,8 +24227,8 @@ - if test ${ac_cv_func_getaddrinfo+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - -@@ -23035,12 +24248,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_func_getaddrinfo=yes --else $as_nop -- ac_cv_func_getaddrinfo=no -+else case e in #( -+ e) ac_cv_func_getaddrinfo=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getaddrinfo" >&5 - printf "%s\n" "$ac_cv_func_getaddrinfo" >&6; } -@@ -23053,8 +24268,8 @@ - if test ${ac_cv_buggy_getaddrinfo+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test "$cross_compiling" = yes -+else case e in #( -+ e) if test "$cross_compiling" = yes - then : - - if test "$ac_sys_system" = "Linux-android" || test "$ac_sys_system" = "iOS"; then -@@ -23064,8 +24279,8 @@ - else - ac_cv_buggy_getaddrinfo=yes - fi --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -23161,13 +24376,16 @@ - if ac_fn_c_try_run "$LINENO" - then : - ac_cv_buggy_getaddrinfo=no --else $as_nop -- ac_cv_buggy_getaddrinfo=yes -+else case e in #( -+ e) ac_cv_buggy_getaddrinfo=yes ;; -+esac - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext -+ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_buggy_getaddrinfo" >&5 - printf "%s\n" "$ac_cv_buggy_getaddrinfo" >&6; } -@@ -23203,8 +24421,8 @@ - if test ${ac_cv_struct_tm+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - #include -@@ -23222,10 +24440,12 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_struct_tm=time.h --else $as_nop -- ac_cv_struct_tm=sys/time.h -+else case e in #( -+ e) ac_cv_struct_tm=sys/time.h ;; -+esac - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5 - printf "%s\n" "$ac_cv_struct_tm" >&6; } -@@ -23257,8 +24477,9 @@ - if test "x$ac_cv_have_decl_tzname" = xyes - then : - ac_have_decl=1 --else $as_nop -- ac_have_decl=0 -+else case e in #( -+ e) ac_have_decl=0 ;; -+esac - fi - printf "%s\n" "#define HAVE_DECL_TZNAME $ac_have_decl" >>confdefs.h - -@@ -23267,8 +24488,8 @@ - if test ${ac_cv_var_tzname+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - #if !HAVE_DECL_TZNAME -@@ -23286,11 +24507,13 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_var_tzname=yes --else $as_nop -- ac_cv_var_tzname=no -+else case e in #( -+ e) ac_cv_var_tzname=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ -- conftest$ac_exeext conftest.$ac_ext -+ conftest$ac_exeext conftest.$ac_ext ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_var_tzname" >&5 - printf "%s\n" "$ac_cv_var_tzname" >&6; } -@@ -23397,8 +24620,8 @@ - if test ${ac_cv_header_time_altzone+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include -@@ -23413,11 +24636,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_header_time_altzone=yes --else $as_nop -- ac_cv_header_time_altzone=no -+else case e in #( -+ e) ac_cv_header_time_altzone=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time_altzone" >&5 - printf "%s\n" "$ac_cv_header_time_altzone" >&6; } -@@ -23432,8 +24657,8 @@ - if test ${ac_cv_struct_addrinfo+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -23447,10 +24672,12 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_struct_addrinfo=yes --else $as_nop -- ac_cv_struct_addrinfo=no -+else case e in #( -+ e) ac_cv_struct_addrinfo=no ;; -+esac - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_addrinfo" >&5 - printf "%s\n" "$ac_cv_struct_addrinfo" >&6; } -@@ -23465,8 +24692,8 @@ - if test ${ac_cv_struct_sockaddr_storage+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - # include -@@ -23482,10 +24709,12 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_struct_sockaddr_storage=yes --else $as_nop -- ac_cv_struct_sockaddr_storage=no -+else case e in #( -+ e) ac_cv_struct_sockaddr_storage=no ;; -+esac - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_sockaddr_storage" >&5 - printf "%s\n" "$ac_cv_struct_sockaddr_storage" >&6; } -@@ -23500,8 +24729,8 @@ - if test ${ac_cv_struct_sockaddr_alg+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - # include -@@ -23518,10 +24747,12 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_struct_sockaddr_alg=yes --else $as_nop -- ac_cv_struct_sockaddr_alg=no -+else case e in #( -+ e) ac_cv_struct_sockaddr_alg=no ;; -+esac - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_sockaddr_alg" >&5 - printf "%s\n" "$ac_cv_struct_sockaddr_alg" >&6; } -@@ -23538,8 +24769,8 @@ - if test ${ac_cv_c_const+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - int -@@ -23603,10 +24834,12 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_c_const=yes --else $as_nop -- ac_cv_c_const=no -+else case e in #( -+ e) ac_cv_c_const=no ;; -+esac - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 - printf "%s\n" "$ac_cv_c_const" >&6; } -@@ -23622,8 +24855,8 @@ - if test ${ac_cv_working_signed_char_c+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - -@@ -23638,11 +24871,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_working_signed_char_c=yes --else $as_nop -- ac_cv_working_signed_char_c=no -+else case e in #( -+ e) ac_cv_working_signed_char_c=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_signed_char_c" >&5 - printf "%s\n" "$ac_cv_working_signed_char_c" >&6; } -@@ -23660,8 +24895,8 @@ - if test ${ac_cv_function_prototypes+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - int foo(int x) { return 0; } -@@ -23676,11 +24911,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_function_prototypes=yes --else $as_nop -- ac_cv_function_prototypes=no -+else case e in #( -+ e) ac_cv_function_prototypes=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_function_prototypes" >&5 - printf "%s\n" "$ac_cv_function_prototypes" >&6; } -@@ -23702,8 +24939,8 @@ - if test ${ac_cv_func_socketpair+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -23720,11 +24957,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_func_socketpair=yes --else $as_nop -- ac_cv_func_socketpair=no -+else case e in #( -+ e) ac_cv_func_socketpair=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_socketpair" >&5 - printf "%s\n" "$ac_cv_func_socketpair" >&6; } -@@ -23744,8 +24983,8 @@ - if test ${ac_cv_struct_sockaddr_sa_len+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include -@@ -23762,11 +25001,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_struct_sockaddr_sa_len=yes --else $as_nop -- ac_cv_struct_sockaddr_sa_len=no -+else case e in #( -+ e) ac_cv_struct_sockaddr_sa_len=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_sockaddr_sa_len" >&5 - printf "%s\n" "$ac_cv_struct_sockaddr_sa_len" >&6; } -@@ -23823,8 +25064,8 @@ - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 - printf "%s\n" "yes" >&6; } - --else $as_nop -- -+else case e in #( -+ e) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 - printf "%s\n" "no" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking gethostbyname_r with 5 args" >&5 -@@ -23861,8 +25102,8 @@ - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 - printf "%s\n" "yes" >&6; } - --else $as_nop -- -+else case e in #( -+ e) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 - printf "%s\n" "no" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking gethostbyname_r with 3 args" >&5 -@@ -23897,23 +25138,26 @@ - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 - printf "%s\n" "yes" >&6; } - --else $as_nop -- -+else case e in #( -+ e) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 - printf "%s\n" "no" >&6; } -- -+ ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - CFLAGS=$OLD_CFLAGS - --else $as_nop -- -+else case e in #( -+ e) - ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" - if test "x$ac_cv_func_gethostbyname" = xyes - then : -@@ -23921,7 +25165,8 @@ - - fi - -- -+ ;; -+esac - fi - - -@@ -23938,22 +25183,28 @@ - if test "x$ac_cv_func___fpu_control" = xyes - then : - --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __fpu_control in -lieee" >&5 -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __fpu_control in -lieee" >&5 - printf %s "checking for __fpu_control in -lieee... " >&6; } - if test ${ac_cv_lib_ieee___fpu_control+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lieee $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char __fpu_control (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char __fpu_control (void); - int - main (void) - { -@@ -23965,12 +25216,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_ieee___fpu_control=yes --else $as_nop -- ac_cv_lib_ieee___fpu_control=no -+else case e in #( -+ e) ac_cv_lib_ieee___fpu_control=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ieee___fpu_control" >&5 - printf "%s\n" "$ac_cv_lib_ieee___fpu_control" >&6; } -@@ -23982,7 +25235,8 @@ - - fi - -- -+ ;; -+esac - fi - - -@@ -24009,9 +25263,10 @@ - printf "%s\n" "set LIBM=\"$withval\"" >&6; } - else as_fn_error $? "proper usage is --with-libm=STRING" "$LINENO" 5 - fi --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: default LIBM=\"$LIBM\"" >&5 --printf "%s\n" "default LIBM=\"$LIBM\"" >&6; } -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: default LIBM=\"$LIBM\"" >&5 -+printf "%s\n" "default LIBM=\"$LIBM\"" >&6; } ;; -+esac - fi - - -@@ -24034,9 +25289,10 @@ - printf "%s\n" "set LIBC=\"$withval\"" >&6; } - else as_fn_error $? "proper usage is --with-libc=STRING" "$LINENO" 5 - fi --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: default LIBC=\"$LIBC\"" >&5 --printf "%s\n" "default LIBC=\"$LIBC\"" >&6; } -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: default LIBC=\"$LIBC\"" >&5 -+printf "%s\n" "default LIBC=\"$LIBC\"" >&6; } ;; -+esac - fi - - -@@ -24050,8 +25306,8 @@ - if test ${ac_cv_gcc_asm_for_x64+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - -@@ -24068,12 +25324,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_gcc_asm_for_x64=yes --else $as_nop -- ac_cv_gcc_asm_for_x64=no -+else case e in #( -+ e) ac_cv_gcc_asm_for_x64=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_gcc_asm_for_x64" >&5 - printf "%s\n" "$ac_cv_gcc_asm_for_x64" >&6; } -@@ -24096,8 +25354,8 @@ - if test ${ax_cv_c_float_words_bigendian+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - - ax_cv_c_float_words_bigendian=unknown - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -24134,7 +25392,8 @@ - - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ -- conftest$ac_exeext conftest.$ac_ext -+ conftest$ac_exeext conftest.$ac_ext ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_c_float_words_bigendian" >&5 - printf "%s\n" "$ax_cv_c_float_words_bigendian" >&6; } -@@ -24182,8 +25441,8 @@ - if test ${ac_cv_gcc_asm_for_x87+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - -@@ -24202,12 +25461,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_gcc_asm_for_x87=yes --else $as_nop -- ac_cv_gcc_asm_for_x87=no -+else case e in #( -+ e) ac_cv_gcc_asm_for_x87=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_gcc_asm_for_x87" >&5 - printf "%s\n" "$ac_cv_gcc_asm_for_x87" >&6; } -@@ -24225,8 +25486,8 @@ - if test ${ac_cv_gcc_asm_for_mc68881+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - -@@ -24245,12 +25506,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_gcc_asm_for_mc68881=yes --else $as_nop -- ac_cv_gcc_asm_for_mc68881=no -+else case e in #( -+ e) ac_cv_gcc_asm_for_mc68881=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_gcc_asm_for_mc68881" >&5 - printf "%s\n" "$ac_cv_gcc_asm_for_mc68881" >&6; } -@@ -24273,16 +25536,16 @@ - if test ${ac_cv_x87_double_rounding+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - # $BASECFLAGS may affect the result - ac_save_cc="$CC" - CC="$CC $BASECFLAGS" - if test "$cross_compiling" = yes - then : - ac_cv_x87_double_rounding=no --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -24308,15 +25571,18 @@ - if ac_fn_c_try_run "$LINENO" - then : - ac_cv_x87_double_rounding=no --else $as_nop -- ac_cv_x87_double_rounding=yes -+else case e in #( -+ e) ac_cv_x87_double_rounding=yes ;; -+esac - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext -+ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - - CC="$ac_save_cc" -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_x87_double_rounding" >&5 - printf "%s\n" "$ac_cv_x87_double_rounding" >&6; } -@@ -24340,17 +25606,18 @@ - - for ac_func in acosh asinh atanh erf erfc expm1 log1p log2 - do : -- as_ac_var=`printf "%s\n" "ac_cv_func_$ac_func" | $as_tr_sh` -+ as_ac_var=`printf "%s\n" "ac_cv_func_$ac_func" | sed "$as_sed_sh"` - ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" - if eval test \"x\$"$as_ac_var"\" = x"yes" - then : - cat >>confdefs.h <<_ACEOF --#define `printf "%s\n" "HAVE_$ac_func" | $as_tr_cpp` 1 -+#define `printf "%s\n" "HAVE_$ac_func" | sed "$as_sed_cpp"` 1 - _ACEOF - --else $as_nop -- as_fn_error $? "Python requires C99 compatible libm" "$LINENO" 5 -- -+else case e in #( -+ e) as_fn_error $? "Python requires C99 compatible libm" "$LINENO" 5 -+ ;; -+esac - fi - - done -@@ -24361,12 +25628,12 @@ - if test ${ac_cv_posix_semaphores_enabled+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test "$cross_compiling" = yes -+else case e in #( -+ e) if test "$cross_compiling" = yes - then : - ac_cv_posix_semaphores_enabled=yes --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - -@@ -24392,14 +25659,17 @@ - if ac_fn_c_try_run "$LINENO" - then : - ac_cv_posix_semaphores_enabled=yes --else $as_nop -- ac_cv_posix_semaphores_enabled=no -+else case e in #( -+ e) ac_cv_posix_semaphores_enabled=no ;; -+esac - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext -+ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_posix_semaphores_enabled" >&5 - printf "%s\n" "$ac_cv_posix_semaphores_enabled" >&6; } -@@ -24417,12 +25687,12 @@ - if test ${ac_cv_broken_sem_getvalue+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test "$cross_compiling" = yes -+else case e in #( -+ e) if test "$cross_compiling" = yes - then : - ac_cv_broken_sem_getvalue=yes --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - -@@ -24452,14 +25722,17 @@ - if ac_fn_c_try_run "$LINENO" - then : - ac_cv_broken_sem_getvalue=no --else $as_nop -- ac_cv_broken_sem_getvalue=yes -+else case e in #( -+ e) ac_cv_broken_sem_getvalue=yes ;; -+esac - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext -+ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_broken_sem_getvalue" >&5 - printf "%s\n" "$ac_cv_broken_sem_getvalue" >&6; } -@@ -24477,8 +25750,9 @@ - if test "x$ac_cv_have_decl_RTLD_LAZY" = xyes - then : - ac_have_decl=1 --else $as_nop -- ac_have_decl=0 -+else case e in #( -+ e) ac_have_decl=0 ;; -+esac - fi - printf "%s\n" "#define HAVE_DECL_RTLD_LAZY $ac_have_decl" >>confdefs.h - ac_fn_check_decl "$LINENO" "RTLD_NOW" "ac_cv_have_decl_RTLD_NOW" "#include -@@ -24486,8 +25760,9 @@ - if test "x$ac_cv_have_decl_RTLD_NOW" = xyes - then : - ac_have_decl=1 --else $as_nop -- ac_have_decl=0 -+else case e in #( -+ e) ac_have_decl=0 ;; -+esac - fi - printf "%s\n" "#define HAVE_DECL_RTLD_NOW $ac_have_decl" >>confdefs.h - ac_fn_check_decl "$LINENO" "RTLD_GLOBAL" "ac_cv_have_decl_RTLD_GLOBAL" "#include -@@ -24495,8 +25770,9 @@ - if test "x$ac_cv_have_decl_RTLD_GLOBAL" = xyes - then : - ac_have_decl=1 --else $as_nop -- ac_have_decl=0 -+else case e in #( -+ e) ac_have_decl=0 ;; -+esac - fi - printf "%s\n" "#define HAVE_DECL_RTLD_GLOBAL $ac_have_decl" >>confdefs.h - ac_fn_check_decl "$LINENO" "RTLD_LOCAL" "ac_cv_have_decl_RTLD_LOCAL" "#include -@@ -24504,8 +25780,9 @@ - if test "x$ac_cv_have_decl_RTLD_LOCAL" = xyes - then : - ac_have_decl=1 --else $as_nop -- ac_have_decl=0 -+else case e in #( -+ e) ac_have_decl=0 ;; -+esac - fi - printf "%s\n" "#define HAVE_DECL_RTLD_LOCAL $ac_have_decl" >>confdefs.h - ac_fn_check_decl "$LINENO" "RTLD_NODELETE" "ac_cv_have_decl_RTLD_NODELETE" "#include -@@ -24513,8 +25790,9 @@ - if test "x$ac_cv_have_decl_RTLD_NODELETE" = xyes - then : - ac_have_decl=1 --else $as_nop -- ac_have_decl=0 -+else case e in #( -+ e) ac_have_decl=0 ;; -+esac - fi - printf "%s\n" "#define HAVE_DECL_RTLD_NODELETE $ac_have_decl" >>confdefs.h - ac_fn_check_decl "$LINENO" "RTLD_NOLOAD" "ac_cv_have_decl_RTLD_NOLOAD" "#include -@@ -24522,8 +25800,9 @@ - if test "x$ac_cv_have_decl_RTLD_NOLOAD" = xyes - then : - ac_have_decl=1 --else $as_nop -- ac_have_decl=0 -+else case e in #( -+ e) ac_have_decl=0 ;; -+esac - fi - printf "%s\n" "#define HAVE_DECL_RTLD_NOLOAD $ac_have_decl" >>confdefs.h - ac_fn_check_decl "$LINENO" "RTLD_DEEPBIND" "ac_cv_have_decl_RTLD_DEEPBIND" "#include -@@ -24531,8 +25810,9 @@ - if test "x$ac_cv_have_decl_RTLD_DEEPBIND" = xyes - then : - ac_have_decl=1 --else $as_nop -- ac_have_decl=0 -+else case e in #( -+ e) ac_have_decl=0 ;; -+esac - fi - printf "%s\n" "#define HAVE_DECL_RTLD_DEEPBIND $ac_have_decl" >>confdefs.h - ac_fn_check_decl "$LINENO" "RTLD_MEMBER" "ac_cv_have_decl_RTLD_MEMBER" "#include -@@ -24540,8 +25820,9 @@ - if test "x$ac_cv_have_decl_RTLD_MEMBER" = xyes - then : - ac_have_decl=1 --else $as_nop -- ac_have_decl=0 -+else case e in #( -+ e) ac_have_decl=0 ;; -+esac - fi - printf "%s\n" "#define HAVE_DECL_RTLD_MEMBER $ac_have_decl" >>confdefs.h - -@@ -24568,9 +25849,10 @@ - printf "%s\n" "#define PYLONG_BITS_IN_DIGIT $enable_big_digits" >>confdefs.h - - --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no value specified" >&5 --printf "%s\n" "no value specified" >&6; } -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no value specified" >&5 -+printf "%s\n" "no value specified" >&6; } ;; -+esac - fi - - -@@ -24584,9 +25866,10 @@ - - wchar_h="yes" - --else $as_nop -- wchar_h="no" -- -+else case e in #( -+ e) wchar_h="no" -+ ;; -+esac - fi - - -@@ -24595,29 +25878,31 @@ - then - # The cast to long int works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects --# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -+# declarations like 'int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of wchar_t" >&5 - printf %s "checking size of wchar_t... " >&6; } - if test ${ac_cv_sizeof_wchar_t+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (wchar_t))" "ac_cv_sizeof_wchar_t" "#include -+else case e in #( -+ e) if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (wchar_t))" "ac_cv_sizeof_wchar_t" "#include - " - then : - --else $as_nop -- if test "$ac_cv_type_wchar_t" = yes; then -- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -+else case e in #( -+ e) if test "$ac_cv_type_wchar_t" = yes; then -+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - as_fn_error 77 "cannot compute sizeof (wchar_t) --See \`config.log' for more details" "$LINENO" 5; } -+See 'config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_wchar_t=0 -- fi -+ fi ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_wchar_t" >&5 - printf "%s\n" "$ac_cv_sizeof_wchar_t" >&6; } -@@ -24638,13 +25923,13 @@ - if test ${ac_cv_wchar_t_signed+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - if test "$cross_compiling" = yes - then : - ac_cv_wchar_t_signed=yes --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -24658,13 +25943,16 @@ - if ac_fn_c_try_run "$LINENO" - then : - ac_cv_wchar_t_signed=yes --else $as_nop -- ac_cv_wchar_t_signed=no -+else case e in #( -+ e) ac_cv_wchar_t_signed=no ;; -+esac - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext -+ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_wchar_t_signed" >&5 - printf "%s\n" "$ac_cv_wchar_t_signed" >&6; } -@@ -24708,8 +25996,8 @@ - if test ${ac_cv_c_bigendian+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_cv_c_bigendian=unknown -+else case e in #( -+ e) ac_cv_c_bigendian=unknown - # See if we're dealing with a universal compiler. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ -@@ -24755,8 +26043,8 @@ - int - main (void) - { --#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ -- && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ -+#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \\ -+ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \\ - && LITTLE_ENDIAN) - bogus endian macros - #endif -@@ -24787,8 +26075,9 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_c_bigendian=yes --else $as_nop -- ac_cv_c_bigendian=no -+else case e in #( -+ e) ac_cv_c_bigendian=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - fi -@@ -24832,8 +26121,9 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_c_bigendian=yes --else $as_nop -- ac_cv_c_bigendian=no -+else case e in #( -+ e) ac_cv_c_bigendian=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - fi -@@ -24860,22 +26150,23 @@ - int use_ebcdic (int i) { - return ebcdic_mm[i] + ebcdic_ii[i]; - } -- extern int foo; -- --int --main (void) --{ --return use_ascii (foo) == use_ebcdic (foo); -- ; -- return 0; --} -+ int -+ main (int argc, char **argv) -+ { -+ /* Intimidate the compiler so that it does not -+ optimize the arrays away. */ -+ char *p = argv[0]; -+ ascii_mm[1] = *p++; ebcdic_mm[1] = *p++; -+ ascii_ii[1] = *p++; ebcdic_ii[1] = *p++; -+ return use_ascii (argc) == use_ebcdic (*p); -+ } - _ACEOF --if ac_fn_c_try_compile "$LINENO" -+if ac_fn_c_try_link "$LINENO" - then : -- if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then -+ if grep BIGenDianSyS conftest$ac_exeext >/dev/null; then - ac_cv_c_bigendian=yes - fi -- if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then -+ if grep LiTTleEnDian conftest$ac_exeext >/dev/null ; then - if test "$ac_cv_c_bigendian" = unknown; then - ac_cv_c_bigendian=no - else -@@ -24884,9 +26175,10 @@ - fi - fi - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam \ -+ conftest$ac_exeext conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - $ac_includes_default - int -@@ -24909,14 +26201,17 @@ - if ac_fn_c_try_run "$LINENO" - then : - ac_cv_c_bigendian=no --else $as_nop -- ac_cv_c_bigendian=yes -+else case e in #( -+ e) ac_cv_c_bigendian=yes ;; -+esac - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext -+ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - -- fi -+ fi ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 - printf "%s\n" "$ac_cv_c_bigendian" >&6; } -@@ -24999,8 +26294,8 @@ - LIBPYTHON="\$(BLDLIBRARY)" - fi - --# On iOS the shared libraries must be linked with the Python framework --if test "$ac_sys_system" = "iOS"; then -+# On iOS/tvOS/watchOS the shared libraries must be linked with the Python framework -+if test "$ac_sys_system" = "iOS" -o $ac_sys_system = "tvOS" -o $ac_sys_system = "watchOS"; then - MODULE_DEPS_SHARED="$MODULE_DEPS_SHARED \$(PYTHONFRAMEWORKDIR)/\$(PYTHONFRAMEWORK)" - fi - -@@ -25034,9 +26329,10 @@ - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 - printf "%s\n" "no" >&6; } - fi --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 --printf "%s\n" "no" >&6; } -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -+printf "%s\n" "no" >&6; } ;; -+esac - fi - - -@@ -25067,9 +26363,10 @@ - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 - printf "%s\n" "no" >&6; } - fi --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 --printf "%s\n" "no" >&6; } -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -+printf "%s\n" "no" >&6; } ;; -+esac - fi - - -@@ -25080,13 +26377,13 @@ - if test ${ac_cv_rshift_extends_sign+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - if test "$cross_compiling" = yes - then : - ac_cv_rshift_extends_sign=yes --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - int main(void) -@@ -25098,13 +26395,16 @@ - if ac_fn_c_try_run "$LINENO" - then : - ac_cv_rshift_extends_sign=yes --else $as_nop -- ac_cv_rshift_extends_sign=no -+else case e in #( -+ e) ac_cv_rshift_extends_sign=no ;; -+esac - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext -+ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_rshift_extends_sign" >&5 - printf "%s\n" "$ac_cv_rshift_extends_sign" >&6; } -@@ -25121,8 +26421,8 @@ - if test ${ac_cv_have_getc_unlocked+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include -@@ -25142,11 +26442,13 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_have_getc_unlocked=yes --else $as_nop -- ac_cv_have_getc_unlocked=no -+else case e in #( -+ e) ac_cv_have_getc_unlocked=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ -- conftest$ac_exeext conftest.$ac_ext -+ conftest$ac_exeext conftest.$ac_ext ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_getc_unlocked" >&5 - printf "%s\n" "$ac_cv_have_getc_unlocked" >&6; } -@@ -25177,9 +26479,10 @@ - ;; - esac - --else $as_nop -- with_readline=readline -- -+else case e in #( -+ e) with_readline=readline -+ ;; -+esac - fi - - -@@ -25253,7 +26556,7 @@ - - - CPPFLAGS="$CPPFLAGS $LIBREADLINE_CFLAGS" -- LDFLAGS="$LDFLAGS $LIBREADLINE_LIBS" -+ LIBS="$LIBS $LIBREADLINE_LIBS" - for ac_header in readline/readline.h - do : - ac_fn_c_check_header_compile "$LINENO" "readline/readline.h" "ac_cv_header_readline_readline_h" "$ac_includes_default" -@@ -25266,16 +26569,22 @@ - if test ${ac_cv_lib_readline_readline+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lreadline $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char readline (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char readline (void); - int - main (void) - { -@@ -25287,12 +26596,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_readline_readline=yes --else $as_nop -- ac_cv_lib_readline_readline=no -+else case e in #( -+ e) ac_cv_lib_readline_readline=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_readline" >&5 - printf "%s\n" "$ac_cv_lib_readline_readline" >&6; } -@@ -25303,13 +26614,15 @@ - READLINE_CFLAGS=${LIBREADLINE_CFLAGS-""} - READLINE_LIBS=${LIBREADLINE_LIBS-"-lreadline"} - --else $as_nop -- with_readline=no -+else case e in #( -+ e) with_readline=no ;; -+esac - fi - - --else $as_nop -- with_readline=no -+else case e in #( -+ e) with_readline=no ;; -+esac - fi - - done -@@ -25345,16 +26658,22 @@ - if test ${ac_cv_lib_readline_readline+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-lreadline $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char readline (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char readline (void); - int - main (void) - { -@@ -25366,12 +26685,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_readline_readline=yes --else $as_nop -- ac_cv_lib_readline_readline=no -+else case e in #( -+ e) ac_cv_lib_readline_readline=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_readline" >&5 - printf "%s\n" "$ac_cv_lib_readline_readline" >&6; } -@@ -25382,13 +26703,15 @@ - READLINE_CFLAGS=${LIBREADLINE_CFLAGS-""} - READLINE_LIBS=${LIBREADLINE_LIBS-"-lreadline"} - --else $as_nop -- with_readline=no -+else case e in #( -+ e) with_readline=no ;; -+esac - fi - - --else $as_nop -- with_readline=no -+else case e in #( -+ e) with_readline=no ;; -+esac - fi - - done -@@ -25497,16 +26820,22 @@ - if test ${ac_cv_lib_edit_readline+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-ledit $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char readline (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char readline (void); - int - main (void) - { -@@ -25518,12 +26847,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_edit_readline=yes --else $as_nop -- ac_cv_lib_edit_readline=no -+else case e in #( -+ e) ac_cv_lib_edit_readline=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_edit_readline" >&5 - printf "%s\n" "$ac_cv_lib_edit_readline" >&6; } -@@ -25536,13 +26867,15 @@ - READLINE_CFLAGS=${LIBEDIT_CFLAGS-""} - READLINE_LIBS=${LIBEDIT_LIBS-"-ledit"} - --else $as_nop -- with_readline=no -+else case e in #( -+ e) with_readline=no ;; -+esac - fi - - --else $as_nop -- with_readline=no -+else case e in #( -+ e) with_readline=no ;; -+esac - fi - - done -@@ -25578,16 +26911,22 @@ - if test ${ac_cv_lib_edit_readline+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_check_lib_save_LIBS=$LIBS -+else case e in #( -+ e) ac_check_lib_save_LIBS=$LIBS - LIBS="-ledit $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char readline (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char readline (void); - int - main (void) - { -@@ -25599,12 +26938,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_lib_edit_readline=yes --else $as_nop -- ac_cv_lib_edit_readline=no -+else case e in #( -+ e) ac_cv_lib_edit_readline=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+LIBS=$ac_check_lib_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_edit_readline" >&5 - printf "%s\n" "$ac_cv_lib_edit_readline" >&6; } -@@ -25617,13 +26958,15 @@ - READLINE_CFLAGS=${LIBEDIT_CFLAGS-""} - READLINE_LIBS=${LIBEDIT_LIBS-"-ledit"} - --else $as_nop -- with_readline=no -+else case e in #( -+ e) with_readline=no ;; -+esac - fi - - --else $as_nop -- with_readline=no -+else case e in #( -+ e) with_readline=no ;; -+esac - fi - - done -@@ -25661,8 +27004,8 @@ - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 - printf "%s\n" "no" >&6; } - --else $as_nop -- -+else case e in #( -+ e) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_readline (CFLAGS: $READLINE_CFLAGS, LIBS: $READLINE_LIBS)" >&5 - printf "%s\n" "$with_readline (CFLAGS: $READLINE_CFLAGS, LIBS: $READLINE_LIBS)" >&6; } - -@@ -25723,8 +27066,8 @@ - if test ${ac_cv_readline_rl_pre_input_hook+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - -@@ -25747,13 +27090,15 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_readline_rl_pre_input_hook=yes --else $as_nop -- ac_cv_readline_rl_pre_input_hook=no -- -+else case e in #( -+ e) ac_cv_readline_rl_pre_input_hook=no -+ ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_readline_rl_pre_input_hook" >&5 - printf "%s\n" "$ac_cv_readline_rl_pre_input_hook" >&6; } -@@ -25772,8 +27117,8 @@ - if test ${ac_cv_readline_rl_completion_display_matches_hook+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - -@@ -25796,13 +27141,15 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_readline_rl_completion_display_matches_hook=yes --else $as_nop -- ac_cv_readline_rl_completion_display_matches_hook=no -- -+else case e in #( -+ e) ac_cv_readline_rl_completion_display_matches_hook=no -+ ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_readline_rl_completion_display_matches_hook" >&5 - printf "%s\n" "$ac_cv_readline_rl_completion_display_matches_hook" >&6; } -@@ -25821,8 +27168,8 @@ - if test ${ac_cv_readline_rl_resize_terminal+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - -@@ -25845,13 +27192,15 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_readline_rl_resize_terminal=yes --else $as_nop -- ac_cv_readline_rl_resize_terminal=no -- -+else case e in #( -+ e) ac_cv_readline_rl_resize_terminal=no -+ ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_readline_rl_resize_terminal" >&5 - printf "%s\n" "$ac_cv_readline_rl_resize_terminal" >&6; } -@@ -25870,8 +27219,8 @@ - if test ${ac_cv_readline_rl_completion_matches+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - -@@ -25894,13 +27243,15 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_readline_rl_completion_matches=yes --else $as_nop -- ac_cv_readline_rl_completion_matches=no -- -+else case e in #( -+ e) ac_cv_readline_rl_completion_matches=no -+ ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_readline_rl_completion_matches" >&5 - printf "%s\n" "$ac_cv_readline_rl_completion_matches" >&6; } -@@ -25938,8 +27289,8 @@ - if test ${ac_cv_readline_append_history+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - -@@ -25962,13 +27313,15 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_readline_append_history=yes --else $as_nop -- ac_cv_readline_append_history=no -- -+else case e in #( -+ e) ac_cv_readline_append_history=no -+ ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_readline_append_history" >&5 - printf "%s\n" "$ac_cv_readline_append_history" >&6; } -@@ -26008,8 +27361,8 @@ - if test ${ac_cv_readline_rl_startup_hook_takes_args+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - -@@ -26033,12 +27386,14 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_readline_rl_startup_hook_takes_args=yes --else $as_nop -- ac_cv_readline_rl_startup_hook_takes_args=no -- -+else case e in #( -+ e) ac_cv_readline_rl_startup_hook_takes_args=no -+ ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_readline_rl_startup_hook_takes_args" >&5 - printf "%s\n" "$ac_cv_readline_rl_startup_hook_takes_args" >&6; } -@@ -26058,7 +27413,8 @@ - LDFLAGS=$save_LDFLAGS - LIBS=$save_LIBS - -- -+ ;; -+esac - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for broken nice()" >&5 -@@ -26066,13 +27422,13 @@ - if test ${ac_cv_broken_nice+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - if test "$cross_compiling" = yes - then : - ac_cv_broken_nice=no --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -26089,13 +27445,16 @@ - if ac_fn_c_try_run "$LINENO" - then : - ac_cv_broken_nice=yes --else $as_nop -- ac_cv_broken_nice=no -+else case e in #( -+ e) ac_cv_broken_nice=no ;; -+esac - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext -+ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_broken_nice" >&5 - printf "%s\n" "$ac_cv_broken_nice" >&6; } -@@ -26111,12 +27470,12 @@ - if test ${ac_cv_broken_poll+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test "$cross_compiling" = yes -+else case e in #( -+ e) if test "$cross_compiling" = yes - then : - ac_cv_broken_poll=no --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -26142,13 +27501,16 @@ - if ac_fn_c_try_run "$LINENO" - then : - ac_cv_broken_poll=yes --else $as_nop -- ac_cv_broken_poll=no -+else case e in #( -+ e) ac_cv_broken_poll=no ;; -+esac - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext -+ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_broken_poll" >&5 - printf "%s\n" "$ac_cv_broken_poll" >&6; } -@@ -26165,13 +27527,13 @@ - if test ${ac_cv_working_tzset+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - if test "$cross_compiling" = yes - then : - ac_cv_working_tzset=no --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -26241,13 +27603,16 @@ - if ac_fn_c_try_run "$LINENO" - then : - ac_cv_working_tzset=yes --else $as_nop -- ac_cv_working_tzset=no -+else case e in #( -+ e) ac_cv_working_tzset=no ;; -+esac - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext -+ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_tzset" >&5 - printf "%s\n" "$ac_cv_working_tzset" >&6; } -@@ -26264,8 +27629,8 @@ - if test ${ac_cv_stat_tv_nsec+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -26282,10 +27647,12 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_stat_tv_nsec=yes --else $as_nop -- ac_cv_stat_tv_nsec=no -+else case e in #( -+ e) ac_cv_stat_tv_nsec=no ;; -+esac - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_stat_tv_nsec" >&5 - printf "%s\n" "$ac_cv_stat_tv_nsec" >&6; } -@@ -26302,8 +27669,8 @@ - if test ${ac_cv_stat_tv_nsec2+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - int -@@ -26320,10 +27687,12 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_stat_tv_nsec2=yes --else $as_nop -- ac_cv_stat_tv_nsec2=no -+else case e in #( -+ e) ac_cv_stat_tv_nsec2=no ;; -+esac - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_stat_tv_nsec2" >&5 - printf "%s\n" "$ac_cv_stat_tv_nsec2" >&6; } -@@ -26339,13 +27708,13 @@ - if test ${ac_cv_normalize_century+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - if test "$cross_compiling" = yes - then : - ac_cv_normalize_century=yes --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -26369,13 +27738,16 @@ - if ac_fn_c_try_run "$LINENO" - then : - ac_cv_normalize_century=yes --else $as_nop -- ac_cv_normalize_century=no -+else case e in #( -+ e) ac_cv_normalize_century=no ;; -+esac - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext -+ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_normalize_century" >&5 - printf "%s\n" "$ac_cv_normalize_century" >&6; } -@@ -26386,18 +27758,18 @@ - - fi - --{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C99-specific strftime specifiers are supported" >&5 --printf %s "checking whether C99-specific strftime specifiers are supported... " >&6; } -+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C99-compatible strftime specifiers are supported" >&5 -+printf %s "checking whether C99-compatible strftime specifiers are supported... " >&6; } - if test ${ac_cv_strftime_c99_support+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - if test "$cross_compiling" = yes - then : -- ac_cv_strftime_c99_support=no --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+ ac_cv_strftime_c99_support= -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -26421,22 +27793,19 @@ - if ac_fn_c_try_run "$LINENO" - then : - ac_cv_strftime_c99_support=yes --else $as_nop -- ac_cv_strftime_c99_support=no -+else case e in #( -+ e) as_fn_error $? "Python requires C99-compatible strftime specifiers" "$LINENO" 5 ;; -+esac - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext -+ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_strftime_c99_support" >&5 - printf "%s\n" "$ac_cv_strftime_c99_support" >&6; } --if test "$ac_cv_strftime_c99_support" = yes --then -- --printf "%s\n" "#define Py_STRFTIME_C99_SUPPORT 1" >>confdefs.h -- --fi - - have_curses=no - have_panel=no -@@ -26824,15 +28193,21 @@ - if test ${ac_cv_search_initscr+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_func_search_save_LIBS=$LIBS -+else case e in #( -+ e) ac_func_search_save_LIBS=$LIBS - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char initscr (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char initscr (void); - int - main (void) - { -@@ -26863,11 +28238,13 @@ - if test ${ac_cv_search_initscr+y} - then : - --else $as_nop -- ac_cv_search_initscr=no -+else case e in #( -+ e) ac_cv_search_initscr=no ;; -+esac - fi - rm conftest.$ac_ext --LIBS=$ac_func_search_save_LIBS -+LIBS=$ac_func_search_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_initscr" >&5 - printf "%s\n" "$ac_cv_search_initscr" >&6; } -@@ -26880,8 +28257,9 @@ - have_curses=yes - CURSES_LIBS=${CURSES_LIBS-"$ac_cv_search_initscr"} - fi --else $as_nop -- have_curses=no -+else case e in #( -+ e) have_curses=no ;; -+esac - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing update_panels" >&5 -@@ -26889,15 +28267,21 @@ - if test ${ac_cv_search_update_panels+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_func_search_save_LIBS=$LIBS -+else case e in #( -+ e) ac_func_search_save_LIBS=$LIBS - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char update_panels (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char update_panels (void); - int - main (void) - { -@@ -26928,11 +28312,13 @@ - if test ${ac_cv_search_update_panels+y} - then : - --else $as_nop -- ac_cv_search_update_panels=no -+else case e in #( -+ e) ac_cv_search_update_panels=no ;; -+esac - fi - rm conftest.$ac_ext --LIBS=$ac_func_search_save_LIBS -+LIBS=$ac_func_search_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_update_panels" >&5 - printf "%s\n" "$ac_cv_search_update_panels" >&6; } -@@ -26945,8 +28331,9 @@ - have_panel=yes - PANEL_LIBS=${PANEL_LIBS-"$ac_cv_search_update_panels"} - fi --else $as_nop -- have_panel=no -+else case e in #( -+ e) have_panel=no ;; -+esac - fi - - -@@ -26998,8 +28385,8 @@ - if test ${ac_cv_mvwdelch_is_expression+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #define NCURSES_OPAQUE 0 -@@ -27031,10 +28418,12 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_mvwdelch_is_expression=yes --else $as_nop -- ac_cv_mvwdelch_is_expression=no -+else case e in #( -+ e) ac_cv_mvwdelch_is_expression=no ;; -+esac - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mvwdelch_is_expression" >&5 - printf "%s\n" "$ac_cv_mvwdelch_is_expression" >&6; } -@@ -27051,8 +28440,8 @@ - if test ${ac_cv_window_has_flags+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #define NCURSES_OPAQUE 0 -@@ -27084,10 +28473,12 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_window_has_flags=yes --else $as_nop -- ac_cv_window_has_flags=no -+else case e in #( -+ e) ac_cv_window_has_flags=no ;; -+esac - fi --rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_window_has_flags" >&5 - printf "%s\n" "$ac_cv_window_has_flags" >&6; } -@@ -27109,8 +28500,8 @@ - if test ${ac_cv_lib_curses_is_pad+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #define NCURSES_OPAQUE 0 -@@ -27143,11 +28534,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_lib_curses_is_pad=yes --else $as_nop -- ac_cv_lib_curses_is_pad=no -+else case e in #( -+ e) ac_cv_lib_curses_is_pad=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_is_pad" >&5 - printf "%s\n" "$ac_cv_lib_curses_is_pad" >&6; } -@@ -27167,8 +28560,8 @@ - if test ${ac_cv_lib_curses_is_term_resized+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #define NCURSES_OPAQUE 0 -@@ -27201,11 +28594,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_lib_curses_is_term_resized=yes --else $as_nop -- ac_cv_lib_curses_is_term_resized=no -+else case e in #( -+ e) ac_cv_lib_curses_is_term_resized=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_is_term_resized" >&5 - printf "%s\n" "$ac_cv_lib_curses_is_term_resized" >&6; } -@@ -27225,8 +28620,8 @@ - if test ${ac_cv_lib_curses_resize_term+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #define NCURSES_OPAQUE 0 -@@ -27259,11 +28654,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_lib_curses_resize_term=yes --else $as_nop -- ac_cv_lib_curses_resize_term=no -+else case e in #( -+ e) ac_cv_lib_curses_resize_term=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_resize_term" >&5 - printf "%s\n" "$ac_cv_lib_curses_resize_term" >&6; } -@@ -27283,8 +28680,8 @@ - if test ${ac_cv_lib_curses_resizeterm+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #define NCURSES_OPAQUE 0 -@@ -27317,11 +28714,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_lib_curses_resizeterm=yes --else $as_nop -- ac_cv_lib_curses_resizeterm=no -+else case e in #( -+ e) ac_cv_lib_curses_resizeterm=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_resizeterm" >&5 - printf "%s\n" "$ac_cv_lib_curses_resizeterm" >&6; } -@@ -27341,8 +28740,8 @@ - if test ${ac_cv_lib_curses_immedok+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #define NCURSES_OPAQUE 0 -@@ -27375,11 +28774,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_lib_curses_immedok=yes --else $as_nop -- ac_cv_lib_curses_immedok=no -+else case e in #( -+ e) ac_cv_lib_curses_immedok=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_immedok" >&5 - printf "%s\n" "$ac_cv_lib_curses_immedok" >&6; } -@@ -27399,8 +28800,8 @@ - if test ${ac_cv_lib_curses_syncok+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #define NCURSES_OPAQUE 0 -@@ -27433,11 +28834,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_lib_curses_syncok=yes --else $as_nop -- ac_cv_lib_curses_syncok=no -+else case e in #( -+ e) ac_cv_lib_curses_syncok=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_syncok" >&5 - printf "%s\n" "$ac_cv_lib_curses_syncok" >&6; } -@@ -27457,8 +28860,8 @@ - if test ${ac_cv_lib_curses_wchgat+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #define NCURSES_OPAQUE 0 -@@ -27491,11 +28894,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_lib_curses_wchgat=yes --else $as_nop -- ac_cv_lib_curses_wchgat=no -+else case e in #( -+ e) ac_cv_lib_curses_wchgat=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_wchgat" >&5 - printf "%s\n" "$ac_cv_lib_curses_wchgat" >&6; } -@@ -27515,8 +28920,8 @@ - if test ${ac_cv_lib_curses_filter+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #define NCURSES_OPAQUE 0 -@@ -27549,11 +28954,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_lib_curses_filter=yes --else $as_nop -- ac_cv_lib_curses_filter=no -+else case e in #( -+ e) ac_cv_lib_curses_filter=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_filter" >&5 - printf "%s\n" "$ac_cv_lib_curses_filter" >&6; } -@@ -27573,8 +28980,8 @@ - if test ${ac_cv_lib_curses_has_key+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #define NCURSES_OPAQUE 0 -@@ -27607,11 +29014,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_lib_curses_has_key=yes --else $as_nop -- ac_cv_lib_curses_has_key=no -+else case e in #( -+ e) ac_cv_lib_curses_has_key=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_has_key" >&5 - printf "%s\n" "$ac_cv_lib_curses_has_key" >&6; } -@@ -27631,8 +29040,8 @@ - if test ${ac_cv_lib_curses_typeahead+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #define NCURSES_OPAQUE 0 -@@ -27665,11 +29074,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_lib_curses_typeahead=yes --else $as_nop -- ac_cv_lib_curses_typeahead=no -+else case e in #( -+ e) ac_cv_lib_curses_typeahead=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_typeahead" >&5 - printf "%s\n" "$ac_cv_lib_curses_typeahead" >&6; } -@@ -27689,8 +29100,8 @@ - if test ${ac_cv_lib_curses_use_env+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #define NCURSES_OPAQUE 0 -@@ -27723,11 +29134,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_lib_curses_use_env=yes --else $as_nop -- ac_cv_lib_curses_use_env=no -+else case e in #( -+ e) ac_cv_lib_curses_use_env=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_use_env" >&5 - printf "%s\n" "$ac_cv_lib_curses_use_env" >&6; } -@@ -27752,7 +29165,7 @@ - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for device files" >&5 - printf "%s\n" "$as_me: checking for device files" >&6;} - --if test "$ac_sys_system" = "Linux-android" || test "$ac_sys_system" = "iOS"; then -+if test "$ac_sys_system" = "Linux-android" -o "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "watchOS" ; then - ac_cv_file__dev_ptmx=no - ac_cv_file__dev_ptc=no - else -@@ -27778,14 +29191,15 @@ - if test ${ac_cv_file__dev_ptmx+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- test "$cross_compiling" = yes && -+else case e in #( -+ e) test "$cross_compiling" = yes && - as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 - if test -r "/dev/ptmx"; then - ac_cv_file__dev_ptmx=yes - else - ac_cv_file__dev_ptmx=no --fi -+fi ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__dev_ptmx" >&5 - printf "%s\n" "$ac_cv_file__dev_ptmx" >&6; } -@@ -27804,14 +29218,15 @@ - if test ${ac_cv_file__dev_ptc+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- test "$cross_compiling" = yes && -+else case e in #( -+ e) test "$cross_compiling" = yes && - as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 - if test -r "/dev/ptc"; then - ac_cv_file__dev_ptc=yes - else - ac_cv_file__dev_ptc=no --fi -+fi ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__dev_ptc" >&5 - printf "%s\n" "$ac_cv_file__dev_ptc" >&6; } -@@ -27847,10 +29262,11 @@ - printf "%s\n" "#define HAVE_SOCKLEN_T 1" >>confdefs.h - - --else $as_nop -- -+else case e in #( -+ e) - printf "%s\n" "#define socklen_t int" >>confdefs.h -- -+ ;; -+esac - fi - - -@@ -27859,12 +29275,12 @@ - if test ${ac_cv_broken_mbstowcs+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test "$cross_compiling" = yes -+else case e in #( -+ e) if test "$cross_compiling" = yes - then : - ac_cv_broken_mbstowcs=no --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -27881,13 +29297,16 @@ - if ac_fn_c_try_run "$LINENO" - then : - ac_cv_broken_mbstowcs=no --else $as_nop -- ac_cv_broken_mbstowcs=yes -+else case e in #( -+ e) ac_cv_broken_mbstowcs=yes ;; -+esac - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext -+ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_broken_mbstowcs" >&5 - printf "%s\n" "$ac_cv_broken_mbstowcs" >&6; } -@@ -27923,9 +29342,10 @@ - printf "%s\n" "no" >&6; } - fi - --else $as_nop -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no value specified" >&5 --printf "%s\n" "no value specified" >&6; } -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no value specified" >&5 -+printf "%s\n" "no value specified" >&6; } ;; -+esac - fi - - -@@ -27934,16 +29354,16 @@ - if test ${ac_cv_computed_gotos+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test "$cross_compiling" = yes -+else case e in #( -+ e) if test "$cross_compiling" = yes - then : - if test "${with_computed_gotos+set}" = set; then - ac_cv_computed_gotos="$with_computed_gotos -- configured --with(out)-computed-gotos" - else - ac_cv_computed_gotos=no - fi --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - int main(int argc, char **argv) -@@ -27961,13 +29381,16 @@ - if ac_fn_c_try_run "$LINENO" - then : - ac_cv_computed_gotos=yes --else $as_nop -- ac_cv_computed_gotos=no -+else case e in #( -+ e) ac_cv_computed_gotos=no ;; -+esac - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext -+ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_computed_gotos" >&5 - printf "%s\n" "$ac_cv_computed_gotos" >&6; } -@@ -27977,6 +29400,51 @@ - - esac - -+# Check for --with-tail-call-interp -+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-tail-call-interp" >&5 -+printf %s "checking for --with-tail-call-interp... " >&6; } -+ -+# Check whether --with-tail-call-interp was given. -+if test ${with_tail_call_interp+y} -+then : -+ withval=$with_tail_call_interp; -+if test "$withval" = yes -+then -+ -+printf "%s\n" "#define Py_TAIL_CALL_INTERP 1" >>confdefs.h -+ -+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -+printf "%s\n" "yes" >&6; } -+fi -+if test "$withval" = no -+then -+ -+printf "%s\n" "#define Py_TAIL_CALL_INTERP 0" >>confdefs.h -+ -+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -+printf "%s\n" "no" >&6; } -+fi -+ -+else case e in #( -+ e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no value specified" >&5 -+printf "%s\n" "no value specified" >&6; } ;; -+esac -+fi -+ -+ -+# Do not enable tail-calling interpreter if tier 2 is enabled. -+if ${tier2_flags:+false} : -+then : -+ -+ case "$ac_cv_tail_call" in yes*) -+ -+printf "%s\n" "#define Py_TAIL_CALL_INTERP 1" >>confdefs.h -+ -+ esac -+ -+fi -+ -+ - case $ac_sys_system in - AIX*) - -@@ -28034,8 +29502,8 @@ - if test ${ac_cv_compile_o2+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - saved_cflags="$CFLAGS" - CFLAGS="-O2" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -28052,12 +29520,14 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ac_cv_compile_o2=yes --else $as_nop -- ac_cv_compile_o2=no -+else case e in #( -+ e) ac_cv_compile_o2=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - CFLAGS="$saved_cflags" -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_compile_o2" >&5 - printf "%s\n" "$ac_cv_compile_o2" >&6; } -@@ -28074,8 +29544,8 @@ - if test "$cross_compiling" = yes - then : - have_glibc_memmove_bug=undefined --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - #include -@@ -28097,11 +29567,13 @@ - if ac_fn_c_try_run "$LINENO" - then : - have_glibc_memmove_bug=no --else $as_nop -- have_glibc_memmove_bug=yes -+else case e in #( -+ e) have_glibc_memmove_bug=yes ;; -+esac - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext -+ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - - CFLAGS="$saved_cflags" -@@ -28126,8 +29598,8 @@ - if test "$cross_compiling" = yes - then : - have_ipa_pure_const_bug=undefined --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - __attribute__((noinline)) int -@@ -28150,11 +29622,13 @@ - if ac_fn_c_try_run "$LINENO" - then : - have_ipa_pure_const_bug=no --else $as_nop -- have_ipa_pure_const_bug=yes -+else case e in #( -+ e) have_ipa_pure_const_bug=yes ;; -+esac - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext -+ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -+esac - fi - - CFLAGS="$saved_cflags" -@@ -28177,20 +29651,21 @@ - if test ${with_ensurepip+y} - then : - withval=$with_ensurepip; --else $as_nop -- -+else case e in #( -+ e) - case $ac_sys_system in #( - Emscripten) : - with_ensurepip=no ;; #( - WASI) : - with_ensurepip=no ;; #( -- iOS) : -+ iOS|tvOS|watchOS) : - with_ensurepip=no ;; #( - *) : - with_ensurepip=upgrade - ;; - esac -- -+ ;; -+esac - fi - - case $with_ensurepip in #( -@@ -28213,8 +29688,8 @@ - if test ${ac_cv_dirent_d_type+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - -@@ -28231,12 +29706,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_dirent_d_type=yes --else $as_nop -- ac_cv_dirent_d_type=no -+else case e in #( -+ e) ac_cv_dirent_d_type=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_dirent_d_type" >&5 - printf "%s\n" "$ac_cv_dirent_d_type" >&6; } -@@ -28256,8 +29733,8 @@ - if test ${ac_cv_getrandom_syscall+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - -@@ -28281,12 +29758,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_getrandom_syscall=yes --else $as_nop -- ac_cv_getrandom_syscall=no -+else case e in #( -+ e) ac_cv_getrandom_syscall=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_getrandom_syscall" >&5 - printf "%s\n" "$ac_cv_getrandom_syscall" >&6; } -@@ -28307,8 +29786,8 @@ - if test ${ac_cv_func_getrandom+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - -@@ -28330,12 +29809,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_func_getrandom=yes --else $as_nop -- ac_cv_func_getrandom=no -+else case e in #( -+ e) ac_cv_func_getrandom=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getrandom" >&5 - printf "%s\n" "$ac_cv_func_getrandom" >&6; } -@@ -28363,15 +29844,21 @@ - if test ${ac_cv_search_shm_open+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- ac_func_search_save_LIBS=$LIBS -+else case e in #( -+ e) ac_func_search_save_LIBS=$LIBS - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --char shm_open (); -+ builtin and then its argument prototype would still apply. -+ The 'extern "C"' is for builds by C++ compilers; -+ although this is not generally supported in C code supporting it here -+ has little cost and some practical benefit (sr 110532). */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char shm_open (void); - int - main (void) - { -@@ -28402,11 +29889,13 @@ - if test ${ac_cv_search_shm_open+y} - then : - --else $as_nop -- ac_cv_search_shm_open=no -+else case e in #( -+ e) ac_cv_search_shm_open=no ;; -+esac - fi - rm conftest.$ac_ext --LIBS=$ac_func_search_save_LIBS -+LIBS=$ac_func_search_save_LIBS ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_shm_open" >&5 - printf "%s\n" "$ac_cv_search_shm_open" >&6; } -@@ -28434,16 +29923,17 @@ - - for ac_func in shm_open shm_unlink - do : -- as_ac_var=`printf "%s\n" "ac_cv_func_$ac_func" | $as_tr_sh` -+ as_ac_var=`printf "%s\n" "ac_cv_func_$ac_func" | sed "$as_sed_sh"` - ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" - if eval test \"x\$"$as_ac_var"\" = x"yes" - then : - cat >>confdefs.h <<_ACEOF --#define `printf "%s\n" "HAVE_$ac_func" | $as_tr_cpp` 1 -+#define `printf "%s\n" "HAVE_$ac_func" | sed "$as_sed_cpp"` 1 - _ACEOF - have_posix_shmem=yes --else $as_nop -- have_posix_shmem=no -+else case e in #( -+ e) have_posix_shmem=no ;; -+esac - fi - - done -@@ -28472,8 +29962,8 @@ - ;; - esac - --else $as_nop -- -+else case e in #( -+ e) - # if pkg-config is installed and openssl has installed a .pc file, - # then use that information and don't search ssldirs - if test -n "$ac_tool_prefix"; then -@@ -28484,8 +29974,8 @@ - if test ${ac_cv_prog_PKG_CONFIG+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test -n "$PKG_CONFIG"; then -+else case e in #( -+ e) if test -n "$PKG_CONFIG"; then - ac_cv_prog_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test. - else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -@@ -28507,7 +29997,8 @@ - done - IFS=$as_save_IFS - --fi -+fi ;; -+esac - fi - PKG_CONFIG=$ac_cv_prog_PKG_CONFIG - if test -n "$PKG_CONFIG"; then -@@ -28529,8 +30020,8 @@ - if test ${ac_cv_prog_ac_ct_PKG_CONFIG+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- if test -n "$ac_ct_PKG_CONFIG"; then -+else case e in #( -+ e) if test -n "$ac_ct_PKG_CONFIG"; then - ac_cv_prog_ac_ct_PKG_CONFIG="$ac_ct_PKG_CONFIG" # Let the user override the test. - else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -@@ -28552,7 +30043,8 @@ - done - IFS=$as_save_IFS - --fi -+fi ;; -+esac - fi - ac_ct_PKG_CONFIG=$ac_cv_prog_ac_ct_PKG_CONFIG - if test -n "$ac_ct_PKG_CONFIG"; then -@@ -28592,7 +30084,8 @@ - ssldirs="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr" - fi - -- -+ ;; -+esac - fi - - -@@ -28655,12 +30148,13 @@ - printf "%s\n" "yes" >&6; } - have_openssl=yes - --else $as_nop -- -+else case e in #( -+ e) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 - printf "%s\n" "no" >&6; } - have_openssl=no -- -+ ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -@@ -28679,15 +30173,16 @@ - - rpath_arg="-Wl,--enable-new-dtags,-rpath=" - --else $as_nop -- -+else case e in #( -+ e) - if test "$ac_sys_system" = "Darwin" - then - rpath_arg="-Wl,-rpath," - else - rpath_arg="-Wl,-rpath=" - fi -- -+ ;; -+esac - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-openssl-rpath" >&5 -@@ -28697,9 +30192,10 @@ - if test ${with_openssl_rpath+y} - then : - withval=$with_openssl_rpath; --else $as_nop -- with_openssl_rpath=no -- -+else case e in #( -+ e) with_openssl_rpath=no -+ ;; -+esac - fi - - case $with_openssl_rpath in #( -@@ -28725,8 +30221,9 @@ - OPENSSL_RPATH="$with_openssl_rpath" - OPENSSL_LDFLAGS_RPATH="${rpath_arg}$with_openssl_rpath" - --else $as_nop -- as_fn_error $? "--with-openssl-rpath \"$with_openssl_rpath\" is not a directory" "$LINENO" 5 -+else case e in #( -+ e) as_fn_error $? "--with-openssl-rpath \"$with_openssl_rpath\" is not a directory" "$LINENO" 5 ;; -+esac - fi - - ;; -@@ -28789,8 +30286,8 @@ - if test ${ac_cv_working_openssl_ssl+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - -@@ -28820,12 +30317,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_working_openssl_ssl=yes --else $as_nop -- ac_cv_working_openssl_ssl=no -+else case e in #( -+ e) ac_cv_working_openssl_ssl=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_openssl_ssl" >&5 - printf "%s\n" "$ac_cv_working_openssl_ssl" >&6; } -@@ -28852,8 +30351,8 @@ - if test ${ac_cv_working_openssl_hashlib+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - -@@ -28880,12 +30379,14 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_working_openssl_hashlib=yes --else $as_nop -- ac_cv_working_openssl_hashlib=no -+else case e in #( -+ e) ac_cv_working_openssl_hashlib=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -- -+ ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_openssl_hashlib" >&5 - printf "%s\n" "$ac_cv_working_openssl_hashlib" >&6; } -@@ -28927,13 +30428,14 @@ - ;; - esac - --else $as_nop -- -+else case e in #( -+ e) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: python" >&5 - printf "%s\n" "python" >&6; } - printf "%s\n" "#define PY_SSL_DEFAULT_CIPHERS 1" >>confdefs.h - -- -+ ;; -+esac - fi - - -@@ -28956,8 +30458,9 @@ - ;; - esac - --else $as_nop -- with_builtin_hashlib_hashes=$default_hashlib_hashes -+else case e in #( -+ e) with_builtin_hashlib_hashes=$default_hashlib_hashes ;; -+esac - fi - - -@@ -28999,12 +30502,14 @@ - if test "x$enable_test_modules" = xyes - then : - TEST_MODULES=yes --else $as_nop -- TEST_MODULES=no -+else case e in #( -+ e) TEST_MODULES=no ;; -+esac - fi - --else $as_nop -- TEST_MODULES=yes -+else case e in #( -+ e) TEST_MODULES=yes ;; -+esac - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $TEST_MODULES" >&5 -@@ -29033,8 +30538,8 @@ - if test ${ac_cv_libatomic_needed+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+else case e in #( -+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - - // pyatomic.h needs uint64_t and Py_ssize_t types -@@ -29077,11 +30582,13 @@ - if ac_fn_c_try_link "$LINENO" - then : - ac_cv_libatomic_needed=no --else $as_nop -- ac_cv_libatomic_needed=yes -+else case e in #( -+ e) ac_cv_libatomic_needed=yes ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam \ -- conftest$ac_exeext conftest.$ac_ext -+ conftest$ac_exeext conftest.$ac_ext ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libatomic_needed" >&5 - printf "%s\n" "$ac_cv_libatomic_needed" >&6; } -@@ -29096,16 +30603,17 @@ - - # gh-59705: Maximum length in bytes of a thread name - case "$ac_sys_system" in -- Linux*) PYTHREAD_NAME_MAXLEN=15;; # Linux and Android -- SunOS*) PYTHREAD_NAME_MAXLEN=31;; -- Darwin) PYTHREAD_NAME_MAXLEN=63;; -- iOS) PYTHREAD_NAME_MAXLEN=63;; -- FreeBSD*) PYTHREAD_NAME_MAXLEN=98;; -- *) PYTHREAD_NAME_MAXLEN=;; -+ Linux*) _PYTHREAD_NAME_MAXLEN=15;; # Linux and Android -+ SunOS*) _PYTHREAD_NAME_MAXLEN=31;; -+ NetBSD*) _PYTHREAD_NAME_MAXLEN=31;; -+ Darwin) _PYTHREAD_NAME_MAXLEN=63;; -+ iOS) _PYTHREAD_NAME_MAXLEN=63;; -+ FreeBSD*) _PYTHREAD_NAME_MAXLEN=98;; -+ *) _PYTHREAD_NAME_MAXLEN=;; - esac --if test -n "$PYTHREAD_NAME_MAXLEN"; then -+if test -n "$_PYTHREAD_NAME_MAXLEN"; then - --printf "%s\n" "#define PYTHREAD_NAME_MAXLEN $PYTHREAD_NAME_MAXLEN" >>confdefs.h -+printf "%s\n" "#define _PYTHREAD_NAME_MAXLEN $_PYTHREAD_NAME_MAXLEN" >>confdefs.h - - fi - -@@ -29130,7 +30638,7 @@ - ;; #( - Darwin) : - ;; #( -- iOS) : -+ iOS|tvOS|watchOS) : - - - -@@ -29733,11 +31241,13 @@ - if test "$ac_cv_func_sem_unlink" = "yes" - then : - py_cv_module__multiprocessing=yes --else $as_nop -- py_cv_module__multiprocessing=missing -+else case e in #( -+ e) py_cv_module__multiprocessing=missing ;; -+esac - fi --else $as_nop -- py_cv_module__multiprocessing=disabled -+else case e in #( -+ e) py_cv_module__multiprocessing=disabled ;; -+esac - fi - - fi -@@ -29771,11 +31281,13 @@ - if test "$have_posix_shmem" = "yes" - then : - py_cv_module__posixshmem=yes --else $as_nop -- py_cv_module__posixshmem=missing -+else case e in #( -+ e) py_cv_module__posixshmem=missing ;; -+esac - fi --else $as_nop -- py_cv_module__posixshmem=disabled -+else case e in #( -+ e) py_cv_module__posixshmem=disabled ;; -+esac - fi - - fi -@@ -29900,11 +31412,13 @@ - if test "$ac_cv_header_sys_ioctl_h" = "yes" -a "$ac_cv_header_fcntl_h" = "yes" - then : - py_cv_module_fcntl=yes --else $as_nop -- py_cv_module_fcntl=missing -+else case e in #( -+ e) py_cv_module_fcntl=missing ;; -+esac - fi --else $as_nop -- py_cv_module_fcntl=disabled -+else case e in #( -+ e) py_cv_module_fcntl=disabled ;; -+esac - fi - - fi -@@ -29938,11 +31452,13 @@ - if test "$ac_cv_header_sys_mman_h" = "yes" -a "$ac_cv_header_sys_stat_h" = "yes" - then : - py_cv_module_mmap=yes --else $as_nop -- py_cv_module_mmap=missing -+else case e in #( -+ e) py_cv_module_mmap=missing ;; -+esac - fi --else $as_nop -- py_cv_module_mmap=disabled -+else case e in #( -+ e) py_cv_module_mmap=disabled ;; -+esac - fi - - fi -@@ -29976,11 +31492,13 @@ - if test "$ac_cv_header_sys_socket_h" = "yes" -a "$ac_cv_header_sys_types_h" = "yes" -a "$ac_cv_header_netinet_in_h" = "yes" - then : - py_cv_module__socket=yes --else $as_nop -- py_cv_module__socket=missing -+else case e in #( -+ e) py_cv_module__socket=missing ;; -+esac - fi --else $as_nop -- py_cv_module__socket=disabled -+else case e in #( -+ e) py_cv_module__socket=disabled ;; -+esac - fi - - fi -@@ -30016,11 +31534,13 @@ - { test "$ac_cv_func_getgrgid" = "yes" || test "$ac_cv_func_getgrgid_r" = "yes"; } - then : - py_cv_module_grp=yes --else $as_nop -- py_cv_module_grp=missing -+else case e in #( -+ e) py_cv_module_grp=missing ;; -+esac - fi --else $as_nop -- py_cv_module_grp=disabled -+else case e in #( -+ e) py_cv_module_grp=disabled ;; -+esac - fi - - fi -@@ -30054,11 +31574,13 @@ - if test "$ac_cv_func_getpwuid" = yes -o "$ac_cv_func_getpwuid_r" = yes - then : - py_cv_module_pwd=yes --else $as_nop -- py_cv_module_pwd=missing -+else case e in #( -+ e) py_cv_module_pwd=missing ;; -+esac - fi --else $as_nop -- py_cv_module_pwd=disabled -+else case e in #( -+ e) py_cv_module_pwd=disabled ;; -+esac - fi - - fi -@@ -30092,11 +31614,13 @@ - if test "$ac_cv_header_sys_resource_h" = yes - then : - py_cv_module_resource=yes --else $as_nop -- py_cv_module_resource=missing -+else case e in #( -+ e) py_cv_module_resource=missing ;; -+esac - fi --else $as_nop -- py_cv_module_resource=disabled -+else case e in #( -+ e) py_cv_module_resource=disabled ;; -+esac - fi - - fi -@@ -30130,11 +31654,13 @@ - if true - then : - py_cv_module__scproxy=yes --else $as_nop -- py_cv_module__scproxy=missing -+else case e in #( -+ e) py_cv_module__scproxy=missing ;; -+esac - fi --else $as_nop -- py_cv_module__scproxy=disabled -+else case e in #( -+ e) py_cv_module__scproxy=disabled ;; -+esac - fi - - fi -@@ -30168,11 +31694,13 @@ - if test "$ac_cv_header_syslog_h" = yes - then : - py_cv_module_syslog=yes --else $as_nop -- py_cv_module_syslog=missing -+else case e in #( -+ e) py_cv_module_syslog=missing ;; -+esac - fi --else $as_nop -- py_cv_module_syslog=disabled -+else case e in #( -+ e) py_cv_module_syslog=disabled ;; -+esac - fi - - fi -@@ -30206,11 +31734,13 @@ - if test "$ac_cv_header_termios_h" = yes - then : - py_cv_module_termios=yes --else $as_nop -- py_cv_module_termios=missing -+else case e in #( -+ e) py_cv_module_termios=missing ;; -+esac - fi --else $as_nop -- py_cv_module_termios=disabled -+else case e in #( -+ e) py_cv_module_termios=disabled ;; -+esac - fi - - fi -@@ -30245,11 +31775,13 @@ - if test "$ac_cv_header_sys_time_h" = "yes" - then : - py_cv_module_pyexpat=yes --else $as_nop -- py_cv_module_pyexpat=missing -+else case e in #( -+ e) py_cv_module_pyexpat=missing ;; -+esac - fi --else $as_nop -- py_cv_module_pyexpat=disabled -+else case e in #( -+ e) py_cv_module_pyexpat=disabled ;; -+esac - fi - - fi -@@ -30283,11 +31815,13 @@ - if true - then : - py_cv_module__elementtree=yes --else $as_nop -- py_cv_module__elementtree=missing -+else case e in #( -+ e) py_cv_module__elementtree=missing ;; -+esac - fi --else $as_nop -- py_cv_module__elementtree=disabled -+else case e in #( -+ e) py_cv_module__elementtree=disabled ;; -+esac - fi - - fi -@@ -30498,11 +32032,13 @@ - if true - then : - py_cv_module__md5=yes --else $as_nop -- py_cv_module__md5=missing -+else case e in #( -+ e) py_cv_module__md5=missing ;; -+esac - fi --else $as_nop -- py_cv_module__md5=disabled -+else case e in #( -+ e) py_cv_module__md5=disabled ;; -+esac - fi - - fi -@@ -30536,11 +32072,13 @@ - if true - then : - py_cv_module__sha1=yes --else $as_nop -- py_cv_module__sha1=missing -+else case e in #( -+ e) py_cv_module__sha1=missing ;; -+esac - fi --else $as_nop -- py_cv_module__sha1=disabled -+else case e in #( -+ e) py_cv_module__sha1=disabled ;; -+esac - fi - - fi -@@ -30574,11 +32112,13 @@ - if true - then : - py_cv_module__sha2=yes --else $as_nop -- py_cv_module__sha2=missing -+else case e in #( -+ e) py_cv_module__sha2=missing ;; -+esac - fi --else $as_nop -- py_cv_module__sha2=disabled -+else case e in #( -+ e) py_cv_module__sha2=disabled ;; -+esac - fi - - fi -@@ -30612,11 +32152,13 @@ - if true - then : - py_cv_module__sha3=yes --else $as_nop -- py_cv_module__sha3=missing -+else case e in #( -+ e) py_cv_module__sha3=missing ;; -+esac - fi --else $as_nop -- py_cv_module__sha3=disabled -+else case e in #( -+ e) py_cv_module__sha3=disabled ;; -+esac - fi - - fi -@@ -30650,11 +32192,13 @@ - if true - then : - py_cv_module__blake2=yes --else $as_nop -- py_cv_module__blake2=missing -+else case e in #( -+ e) py_cv_module__blake2=missing ;; -+esac - fi --else $as_nop -- py_cv_module__blake2=disabled -+else case e in #( -+ e) py_cv_module__blake2=disabled ;; -+esac - fi - - fi -@@ -30697,8 +32241,8 @@ - if test ${ax_cv_check_cflags__Werror__msse__msse2__msse3__msse4_1__msse4_2+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - ax_check_save_flags=$CFLAGS - CFLAGS="$CFLAGS -Werror -msse -msse2 -msse3 -msse4.1 -msse4.2" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -30715,11 +32259,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ax_cv_check_cflags__Werror__msse__msse2__msse3__msse4_1__msse4_2=yes --else $as_nop -- ax_cv_check_cflags__Werror__msse__msse2__msse3__msse4_1__msse4_2=no -+else case e in #( -+ e) ax_cv_check_cflags__Werror__msse__msse2__msse3__msse4_1__msse4_2=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- CFLAGS=$ax_check_save_flags -+ CFLAGS=$ax_check_save_flags ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror__msse__msse2__msse3__msse4_1__msse4_2" >&5 - printf "%s\n" "$ax_cv_check_cflags__Werror__msse__msse2__msse3__msse4_1__msse4_2" >&6; } -@@ -30748,8 +32294,9 @@ - fi - - --else $as_nop -- : -+else case e in #( -+ e) : ;; -+esac - fi - - fi -@@ -30769,8 +32316,8 @@ - if test ${ax_cv_check_cflags__Werror__mavx2+y} - then : - printf %s "(cached) " >&6 --else $as_nop -- -+else case e in #( -+ e) - ax_check_save_flags=$CFLAGS - CFLAGS="$CFLAGS -Werror -mavx2" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -@@ -30787,11 +32334,13 @@ - if ac_fn_c_try_compile "$LINENO" - then : - ax_cv_check_cflags__Werror__mavx2=yes --else $as_nop -- ax_cv_check_cflags__Werror__mavx2=no -+else case e in #( -+ e) ax_cv_check_cflags__Werror__mavx2=no ;; -+esac - fi - rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -- CFLAGS=$ax_check_save_flags -+ CFLAGS=$ax_check_save_flags ;; -+esac - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror__mavx2" >&5 - printf "%s\n" "$ax_cv_check_cflags__Werror__mavx2" >&6; } -@@ -30819,8 +32368,9 @@ - printf "%s\n" "standard" >&6; } - fi - --else $as_nop -- : -+else case e in #( -+ e) : ;; -+esac - fi - - fi -@@ -30838,11 +32388,13 @@ - if test "$have_libffi" = yes - then : - py_cv_module__ctypes=yes --else $as_nop -- py_cv_module__ctypes=missing -+else case e in #( -+ e) py_cv_module__ctypes=missing ;; -+esac - fi --else $as_nop -- py_cv_module__ctypes=disabled -+else case e in #( -+ e) py_cv_module__ctypes=disabled ;; -+esac - fi - - fi -@@ -30876,11 +32428,13 @@ - if test "$have_curses" = "yes" - then : - py_cv_module__curses=yes --else $as_nop -- py_cv_module__curses=missing -+else case e in #( -+ e) py_cv_module__curses=missing ;; -+esac - fi --else $as_nop -- py_cv_module__curses=disabled -+else case e in #( -+ e) py_cv_module__curses=disabled ;; -+esac - fi - - fi -@@ -30915,11 +32469,13 @@ - if test "$have_curses" = "yes" && test "$have_panel" = "yes" - then : - py_cv_module__curses_panel=yes --else $as_nop -- py_cv_module__curses_panel=missing -+else case e in #( -+ e) py_cv_module__curses_panel=missing ;; -+esac - fi --else $as_nop -- py_cv_module__curses_panel=disabled -+else case e in #( -+ e) py_cv_module__curses_panel=disabled ;; -+esac - fi - - fi -@@ -30954,11 +32510,13 @@ - if test "$have_mpdec" = "yes" - then : - py_cv_module__decimal=yes --else $as_nop -- py_cv_module__decimal=missing -+else case e in #( -+ e) py_cv_module__decimal=missing ;; -+esac - fi --else $as_nop -- py_cv_module__decimal=disabled -+else case e in #( -+ e) py_cv_module__decimal=disabled ;; -+esac - fi - - fi -@@ -30992,11 +32550,13 @@ - if test "$have_dbm" != "no" - then : - py_cv_module__dbm=yes --else $as_nop -- py_cv_module__dbm=missing -+else case e in #( -+ e) py_cv_module__dbm=missing ;; -+esac - fi --else $as_nop -- py_cv_module__dbm=disabled -+else case e in #( -+ e) py_cv_module__dbm=disabled ;; -+esac - fi - - fi -@@ -31030,11 +32590,13 @@ - if test "$have_gdbm" = yes - then : - py_cv_module__gdbm=yes --else $as_nop -- py_cv_module__gdbm=missing -+else case e in #( -+ e) py_cv_module__gdbm=missing ;; -+esac - fi --else $as_nop -- py_cv_module__gdbm=disabled -+else case e in #( -+ e) py_cv_module__gdbm=disabled ;; -+esac - fi - - fi -@@ -31068,11 +32630,13 @@ - if test "$with_readline" != "no" - then : - py_cv_module_readline=yes --else $as_nop -- py_cv_module_readline=missing -+else case e in #( -+ e) py_cv_module_readline=missing ;; -+esac - fi --else $as_nop -- py_cv_module_readline=disabled -+else case e in #( -+ e) py_cv_module_readline=disabled ;; -+esac - fi - - fi -@@ -31106,11 +32670,13 @@ - if test "$have_supported_sqlite3" = "yes" - then : - py_cv_module__sqlite3=yes --else $as_nop -- py_cv_module__sqlite3=missing -+else case e in #( -+ e) py_cv_module__sqlite3=missing ;; -+esac - fi --else $as_nop -- py_cv_module__sqlite3=disabled -+else case e in #( -+ e) py_cv_module__sqlite3=disabled ;; -+esac - fi - - fi -@@ -31144,11 +32710,13 @@ - if test "$have_tcltk" = "yes" - then : - py_cv_module__tkinter=yes --else $as_nop -- py_cv_module__tkinter=missing -+else case e in #( -+ e) py_cv_module__tkinter=missing ;; -+esac - fi --else $as_nop -- py_cv_module__tkinter=disabled -+else case e in #( -+ e) py_cv_module__tkinter=disabled ;; -+esac - fi - - fi -@@ -31182,11 +32750,13 @@ - if test "$have_uuid" = "yes" - then : - py_cv_module__uuid=yes --else $as_nop -- py_cv_module__uuid=missing -+else case e in #( -+ e) py_cv_module__uuid=missing ;; -+esac - fi --else $as_nop -- py_cv_module__uuid=disabled -+else case e in #( -+ e) py_cv_module__uuid=disabled ;; -+esac - fi - - fi -@@ -31221,11 +32791,13 @@ - if test "$have_zlib" = yes - then : - py_cv_module_zlib=yes --else $as_nop -- py_cv_module_zlib=missing -+else case e in #( -+ e) py_cv_module_zlib=missing ;; -+esac - fi --else $as_nop -- py_cv_module_zlib=disabled -+else case e in #( -+ e) py_cv_module_zlib=disabled ;; -+esac - fi - - fi -@@ -31281,11 +32853,13 @@ - if test "$have_bzip2" = yes - then : - py_cv_module__bz2=yes --else $as_nop -- py_cv_module__bz2=missing -+else case e in #( -+ e) py_cv_module__bz2=missing ;; -+esac - fi --else $as_nop -- py_cv_module__bz2=disabled -+else case e in #( -+ e) py_cv_module__bz2=disabled ;; -+esac - fi - - fi -@@ -31319,11 +32893,13 @@ - if test "$have_liblzma" = yes - then : - py_cv_module__lzma=yes --else $as_nop -- py_cv_module__lzma=missing -+else case e in #( -+ e) py_cv_module__lzma=missing ;; -+esac - fi --else $as_nop -- py_cv_module__lzma=disabled -+else case e in #( -+ e) py_cv_module__lzma=disabled ;; -+esac - fi - - fi -@@ -31358,11 +32934,13 @@ - if test "$ac_cv_working_openssl_ssl" = yes - then : - py_cv_module__ssl=yes --else $as_nop -- py_cv_module__ssl=missing -+else case e in #( -+ e) py_cv_module__ssl=missing ;; -+esac - fi --else $as_nop -- py_cv_module__ssl=disabled -+else case e in #( -+ e) py_cv_module__ssl=disabled ;; -+esac - fi - - fi -@@ -31396,11 +32974,13 @@ - if test "$ac_cv_working_openssl_hashlib" = yes - then : - py_cv_module__hashlib=yes --else $as_nop -- py_cv_module__hashlib=missing -+else case e in #( -+ e) py_cv_module__hashlib=missing ;; -+esac - fi --else $as_nop -- py_cv_module__hashlib=disabled -+else case e in #( -+ e) py_cv_module__hashlib=disabled ;; -+esac - fi - - fi -@@ -31435,11 +33015,13 @@ - if true - then : - py_cv_module__testcapi=yes --else $as_nop -- py_cv_module__testcapi=missing -+else case e in #( -+ e) py_cv_module__testcapi=missing ;; -+esac - fi --else $as_nop -- py_cv_module__testcapi=disabled -+else case e in #( -+ e) py_cv_module__testcapi=disabled ;; -+esac - fi - - fi -@@ -31473,11 +33055,13 @@ - if true - then : - py_cv_module__testclinic=yes --else $as_nop -- py_cv_module__testclinic=missing -+else case e in #( -+ e) py_cv_module__testclinic=missing ;; -+esac - fi --else $as_nop -- py_cv_module__testclinic=disabled -+else case e in #( -+ e) py_cv_module__testclinic=disabled ;; -+esac - fi - - fi -@@ -31511,11 +33095,13 @@ - if true - then : - py_cv_module__testclinic_limited=yes --else $as_nop -- py_cv_module__testclinic_limited=missing -+else case e in #( -+ e) py_cv_module__testclinic_limited=missing ;; -+esac - fi --else $as_nop -- py_cv_module__testclinic_limited=disabled -+else case e in #( -+ e) py_cv_module__testclinic_limited=disabled ;; -+esac - fi - - fi -@@ -31549,11 +33135,13 @@ - if true - then : - py_cv_module__testlimitedcapi=yes --else $as_nop -- py_cv_module__testlimitedcapi=missing -+else case e in #( -+ e) py_cv_module__testlimitedcapi=missing ;; -+esac - fi --else $as_nop -- py_cv_module__testlimitedcapi=disabled -+else case e in #( -+ e) py_cv_module__testlimitedcapi=disabled ;; -+esac - fi - - fi -@@ -31587,11 +33175,13 @@ - if true - then : - py_cv_module__testinternalcapi=yes --else $as_nop -- py_cv_module__testinternalcapi=missing -+else case e in #( -+ e) py_cv_module__testinternalcapi=missing ;; -+esac - fi --else $as_nop -- py_cv_module__testinternalcapi=disabled -+else case e in #( -+ e) py_cv_module__testinternalcapi=disabled ;; -+esac - fi - - fi -@@ -31625,11 +33215,13 @@ - if true - then : - py_cv_module__testbuffer=yes --else $as_nop -- py_cv_module__testbuffer=missing -+else case e in #( -+ e) py_cv_module__testbuffer=missing ;; -+esac - fi --else $as_nop -- py_cv_module__testbuffer=disabled -+else case e in #( -+ e) py_cv_module__testbuffer=disabled ;; -+esac - fi - - fi -@@ -31663,11 +33255,13 @@ - if test "$ac_cv_func_dlopen" = yes - then : - py_cv_module__testimportmultiple=yes --else $as_nop -- py_cv_module__testimportmultiple=missing -+else case e in #( -+ e) py_cv_module__testimportmultiple=missing ;; -+esac - fi --else $as_nop -- py_cv_module__testimportmultiple=disabled -+else case e in #( -+ e) py_cv_module__testimportmultiple=disabled ;; -+esac - fi - - fi -@@ -31701,11 +33295,13 @@ - if test "$ac_cv_func_dlopen" = yes - then : - py_cv_module__testmultiphase=yes --else $as_nop -- py_cv_module__testmultiphase=missing -+else case e in #( -+ e) py_cv_module__testmultiphase=missing ;; -+esac - fi --else $as_nop -- py_cv_module__testmultiphase=disabled -+else case e in #( -+ e) py_cv_module__testmultiphase=disabled ;; -+esac - fi - - fi -@@ -31739,11 +33335,13 @@ - if test "$ac_cv_func_dlopen" = yes - then : - py_cv_module__testsinglephase=yes --else $as_nop -- py_cv_module__testsinglephase=missing -+else case e in #( -+ e) py_cv_module__testsinglephase=missing ;; -+esac - fi --else $as_nop -- py_cv_module__testsinglephase=disabled -+else case e in #( -+ e) py_cv_module__testsinglephase=disabled ;; -+esac - fi - - fi -@@ -31777,11 +33375,13 @@ - if true - then : - py_cv_module__testexternalinspection=yes --else $as_nop -- py_cv_module__testexternalinspection=missing -+else case e in #( -+ e) py_cv_module__testexternalinspection=missing ;; -+esac - fi --else $as_nop -- py_cv_module__testexternalinspection=disabled -+else case e in #( -+ e) py_cv_module__testexternalinspection=disabled ;; -+esac - fi - - fi -@@ -31815,11 +33415,13 @@ - if true - then : - py_cv_module_xxsubtype=yes --else $as_nop -- py_cv_module_xxsubtype=missing -+else case e in #( -+ e) py_cv_module_xxsubtype=missing ;; -+esac - fi --else $as_nop -- py_cv_module_xxsubtype=disabled -+else case e in #( -+ e) py_cv_module_xxsubtype=disabled ;; -+esac - fi - - fi -@@ -31853,11 +33455,13 @@ - if true - then : - py_cv_module__xxtestfuzz=yes --else $as_nop -- py_cv_module__xxtestfuzz=missing -+else case e in #( -+ e) py_cv_module__xxtestfuzz=missing ;; -+esac - fi --else $as_nop -- py_cv_module__xxtestfuzz=disabled -+else case e in #( -+ e) py_cv_module__xxtestfuzz=disabled ;; -+esac - fi - - fi -@@ -31891,11 +33495,13 @@ - if test "$have_libffi" = yes -a "$ac_cv_func_dlopen" = yes - then : - py_cv_module__ctypes_test=yes --else $as_nop -- py_cv_module__ctypes_test=missing -+else case e in #( -+ e) py_cv_module__ctypes_test=missing ;; -+esac - fi --else $as_nop -- py_cv_module__ctypes_test=disabled -+else case e in #( -+ e) py_cv_module__ctypes_test=disabled ;; -+esac - fi - - fi -@@ -31930,11 +33536,13 @@ - if test "$ac_cv_func_dlopen" = yes - then : - py_cv_module_xxlimited=yes --else $as_nop -- py_cv_module_xxlimited=missing -+else case e in #( -+ e) py_cv_module_xxlimited=missing ;; -+esac - fi --else $as_nop -- py_cv_module_xxlimited=disabled -+else case e in #( -+ e) py_cv_module_xxlimited=disabled ;; -+esac - fi - - fi -@@ -31968,11 +33576,13 @@ - if test "$ac_cv_func_dlopen" = yes - then : - py_cv_module_xxlimited_35=yes --else $as_nop -- py_cv_module_xxlimited_35=missing -+else case e in #( -+ e) py_cv_module_xxlimited_35=missing ;; -+esac - fi --else $as_nop -- py_cv_module_xxlimited_35=disabled -+else case e in #( -+ e) py_cv_module_xxlimited_35=disabled ;; -+esac - fi - - fi -@@ -32017,8 +33627,8 @@ - # config.status only pays attention to the cache file if you give it - # the --recheck option to rerun configure. - # --# `ac_cv_env_foo' variables (set or unset) will be overridden when --# loading this file, other *unset* `ac_cv_foo' will be assigned the -+# 'ac_cv_env_foo' variables (set or unset) will be overridden when -+# loading this file, other *unset* 'ac_cv_foo' will be assigned the - # following values. - - _ACEOF -@@ -32048,14 +33658,14 @@ - (set) 2>&1 | - case $as_nl`(ac_space=' '; set) 2>&1` in #( - *${as_nl}ac_space=\ *) -- # `set' does not quote correctly, so add quotes: double-quote -+ # 'set' does not quote correctly, so add quotes: double-quote - # substitution turns \\\\ into \\, and sed turns \\ into \. - sed -n \ - "s/'/'\\\\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" - ;; #( - *) -- # `set' quotes correctly as required by POSIX, so do not add quotes. -+ # 'set' quotes correctly as required by POSIX, so do not add quotes. - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | -@@ -32474,7 +34084,6 @@ - - # Be more Bourne compatible - DUALCASE=1; export DUALCASE # for MKS sh --as_nop=: - if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 - then : - emulate sh -@@ -32483,12 +34092,13 @@ - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST --else $as_nop -- case `(set -o) 2>/dev/null` in #( -+else case e in #( -+ e) case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -+esac ;; - esac - fi - -@@ -32560,7 +34170,7 @@ - - ;; - esac --# We did not find ourselves, most probably we were run as `sh COMMAND' -+# We did not find ourselves, most probably we were run as 'sh COMMAND' - # in which case we are not to be found in the path. - if test "x$as_myself" = x; then - as_myself=$0 -@@ -32589,7 +34199,6 @@ - } # as_fn_error - - -- - # as_fn_set_status STATUS - # ----------------------- - # Set $? to STATUS, without forking. -@@ -32629,11 +34238,12 @@ - { - eval $1+=\$2 - }' --else $as_nop -- as_fn_append () -+else case e in #( -+ e) as_fn_append () - { - eval $1=\$$1\$2 -- } -+ } ;; -+esac - fi # as_fn_append - - # as_fn_arith ARG... -@@ -32647,11 +34257,12 @@ - { - as_val=$(( $* )) - }' --else $as_nop -- as_fn_arith () -+else case e in #( -+ e) as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` -- } -+ } ;; -+esac - fi # as_fn_arith - - -@@ -32734,9 +34345,9 @@ - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: -- # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. -- # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. -- # In both cases, we have to default to `cp -pR'. -+ # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. -+ # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. -+ # In both cases, we have to default to 'cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then -@@ -32817,10 +34428,12 @@ - as_executable_p=as_fn_executable_p - - # Sed expression to map a string onto a valid CPP name. --as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" -+as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" -+as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated - - # Sed expression to map a string onto a valid variable name. --as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" -+as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" -+as_tr_sh="eval sed '$as_sed_sh'" # deprecated - - - exec 6>&1 -@@ -32836,7 +34449,7 @@ - # values after options handling. - ac_log=" - This file was extended by python $as_me 3.14, which was --generated by GNU Autoconf 2.71. Invocation command line was -+generated by GNU Autoconf 2.72. Invocation command line was - - CONFIG_FILES = $CONFIG_FILES - CONFIG_HEADERS = $CONFIG_HEADERS -@@ -32867,7 +34480,7 @@ - - cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - ac_cs_usage="\ --\`$as_me' instantiates files and other configuration actions -+'$as_me' instantiates files and other configuration actions - from templates according to the current configuration. Unless the files - and actions are specified as TAGs, all are instantiated by default. - -@@ -32900,10 +34513,10 @@ - ac_cs_config='$ac_cs_config_escaped' - ac_cs_version="\\ - python config.status 3.14 --configured by $0, generated by GNU Autoconf 2.71, -+configured by $0, generated by GNU Autoconf 2.72, - with options \\"\$ac_cs_config\\" - --Copyright (C) 2021 Free Software Foundation, Inc. -+Copyright (C) 2023 Free Software Foundation, Inc. - This config.status script is free software; the Free Software Foundation - gives unlimited permission to copy, distribute and modify it." - -@@ -32964,8 +34577,8 @@ - ac_need_defaults=false;; - --he | --h) - # Conflict between --help and --header -- as_fn_error $? "ambiguous option: \`$1' --Try \`$0 --help' for more information.";; -+ as_fn_error $? "ambiguous option: '$1' -+Try '$0 --help' for more information.";; - --help | --hel | -h ) - printf "%s\n" "$ac_cs_usage"; exit ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ -@@ -32973,8 +34586,8 @@ - ac_cs_silent=: ;; - - # This is an error. -- -*) as_fn_error $? "unrecognized option: \`$1' --Try \`$0 --help' for more information." ;; -+ -*) as_fn_error $? "unrecognized option: '$1' -+Try '$0 --help' for more information." ;; - - *) as_fn_append ac_config_targets " $1" - ac_need_defaults=false ;; -@@ -33028,6 +34641,8 @@ - "Mac/Resources/framework/Info.plist") CONFIG_FILES="$CONFIG_FILES Mac/Resources/framework/Info.plist" ;; - "Mac/Resources/app/Info.plist") CONFIG_FILES="$CONFIG_FILES Mac/Resources/app/Info.plist" ;; - "iOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES iOS/Resources/Info.plist" ;; -+ "tvOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES tvOS/Resources/Info.plist" ;; -+ "watchOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES watchOS/Resources/Info.plist" ;; - "Makefile.pre") CONFIG_FILES="$CONFIG_FILES Makefile.pre" ;; - "Misc/python.pc") CONFIG_FILES="$CONFIG_FILES Misc/python.pc" ;; - "Misc/python-embed.pc") CONFIG_FILES="$CONFIG_FILES Misc/python-embed.pc" ;; -@@ -33036,7 +34651,7 @@ - "Modules/Setup.stdlib") CONFIG_FILES="$CONFIG_FILES Modules/Setup.stdlib" ;; - "Modules/ld_so_aix") CONFIG_FILES="$CONFIG_FILES Modules/ld_so_aix" ;; - -- *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; -+ *) as_fn_error $? "invalid argument: '$ac_config_target'" "$LINENO" 5;; - esac - done - -@@ -33055,7 +34670,7 @@ - # creating and moving files from /tmp can sometimes cause problems. - # Hook for its removal unless debugging. - # Note that there is a small window in which the directory will not be cleaned: --# after its creation but before its name has been assigned to `$tmp'. -+# after its creation but before its name has been assigned to '$tmp'. - $debug || - { - tmp= ac_tmp= -@@ -33079,7 +34694,7 @@ - - # Set up the scripts for CONFIG_FILES section. - # No need to generate them if there are no CONFIG_FILES. --# This happens for instance with `./config.status config.h'. -+# This happens for instance with './config.status config.h'. - if test -n "$CONFIG_FILES"; then - - -@@ -33237,13 +34852,13 @@ - - # Set up the scripts for CONFIG_HEADERS section. - # No need to generate them if there are no CONFIG_HEADERS. --# This happens for instance with `./config.status Makefile'. -+# This happens for instance with './config.status Makefile'. - if test -n "$CONFIG_HEADERS"; then - cat >"$ac_tmp/defines.awk" <<\_ACAWK || - BEGIN { - _ACEOF - --# Transform confdefs.h into an awk script `defines.awk', embedded as -+# Transform confdefs.h into an awk script 'defines.awk', embedded as - # here-document in config.status, that substitutes the proper values into - # config.h.in to produce config.h. - -@@ -33353,7 +34968,7 @@ - esac - case $ac_mode$ac_tag in - :[FHL]*:*);; -- :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; -+ :L* | :C*:*) as_fn_error $? "invalid tag '$ac_tag'" "$LINENO" 5;; - :[FH]-) ac_tag=-:-;; - :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; - esac -@@ -33375,19 +34990,19 @@ - -) ac_f="$ac_tmp/stdin";; - *) # Look for the file first in the build tree, then in the source tree - # (if the path is not absolute). The absolute path cannot be DOS-style, -- # because $ac_f cannot contain `:'. -+ # because $ac_f cannot contain ':'. - test -f "$ac_f" || - case $ac_f in - [\\/$]*) false;; - *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; - esac || -- as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; -+ as_fn_error 1 "cannot find input file: '$ac_f'" "$LINENO" 5;; - esac - case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac - as_fn_append ac_file_inputs " '$ac_f'" - done - -- # Let's still pretend it is `configure' which instantiates (i.e., don't -+ # Let's still pretend it is 'configure' which instantiates (i.e., don't - # use $as_me), people would be surprised to read: - # /* config.h. Generated by config.status. */ - configure_input='Generated from '` -@@ -33520,7 +35135,7 @@ - esac - _ACEOF - --# Neutralize VPATH when `$srcdir' = `.'. -+# Neutralize VPATH when '$srcdir' = '.'. - # Shell code in configure.ac might set extrasub. - # FIXME: do we really want to maintain this feature? - cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -@@ -33551,9 +35166,9 @@ - { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ - "$ac_tmp/out"`; test -z "$ac_out"; } && -- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' -+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable 'datarootdir' - which seems to be undefined. Please make sure it is defined" >&5 --printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' -+printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable 'datarootdir' - which seems to be undefined. Please make sure it is defined" >&2;} - - rm -f "$ac_tmp/stdin" -diff --git a/configure.ac b/configure.ac -index bd0221481c5..660e1c638ec 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -2,7 +2,7 @@ - dnl * Please run autoreconf -ivf -Werror to test your changes! * - dnl ************************************************************ - dnl --dnl Python's configure script requires autoconf 2.71, autoconf-archive, -+dnl Python's configure script requires autoconf 2.72, autoconf-archive, - dnl aclocal 1.16, and pkg-config. - dnl - dnl It is recommended to use the Tools/build/regen-configure.sh shell script -@@ -12,7 +12,7 @@ - # Set VERSION so we only need to edit in one place (i.e., here) - m4_define([PYTHON_VERSION], [3.14]) - --AC_PREREQ([2.71]) -+AC_PREREQ([2.72]) - - AC_INIT([python],[PYTHON_VERSION],[https://github.com/python/cpython/issues/]) - -@@ -330,6 +330,15 @@ - *-apple-ios*) - ac_sys_system=iOS - ;; -+ *-apple-tvos*) -+ ac_sys_system=tvOS -+ ;; -+ *-apple-watchos*) -+ ac_sys_system=watchOS -+ ;; -+ *-*-darwin*) -+ ac_sys_system=Darwin -+ ;; - *-*-vxworks*) - ac_sys_system=VxWorks - ;; -@@ -362,6 +371,7 @@ - - case $MACHDEP in - aix*) MACHDEP="aix";; -+ freebsd*) MACHDEP="freebsd";; - linux-android*) MACHDEP="android";; - linux*) MACHDEP="linux";; - cygwin*) MACHDEP="cygwin";; -@@ -401,7 +411,7 @@ - # On cross-compile builds, configure will look for a host-specific compiler by - # prepending the user-provided host triple to the required binary name. - # --# On iOS, this results in binaries like "arm64-apple-ios13.0-simulator-gcc", -+# On iOS/tvOS/watchOS, this results in binaries like "arm64-apple-ios13.0-simulator-gcc", - # which isn't a binary that exists, and isn't very convenient, as it contains the - # iOS version. As the default cross-compiler name won't exist, configure falls - # back to gcc, which *definitely* won't work. We're providing wrapper scripts for -@@ -416,6 +426,14 @@ - aarch64-apple-ios*-simulator) AR=arm64-apple-ios-simulator-ar ;; - aarch64-apple-ios*) AR=arm64-apple-ios-ar ;; - x86_64-apple-ios*-simulator) AR=x86_64-apple-ios-simulator-ar ;; -+ -+ aarch64-apple-tvos*-simulator) AR=arm64-apple-tvos-simulator-ar ;; -+ aarch64-apple-tvos*) AR=arm64-apple-tvos-ar ;; -+ x86_64-apple-tvos*-simulator) AR=x86_64-apple-tvos-simulator-ar ;; -+ -+ aarch64-apple-watchos*-simulator) AR=arm64-apple-watchos-simulator-ar ;; -+ aarch64-apple-watchos*) AR=arm64_32-apple-watchos-ar ;; -+ x86_64-apple-watchos*-simulator) AR=x86_64-apple-watchos-simulator-ar ;; - *) - esac - fi -@@ -424,6 +442,14 @@ - aarch64-apple-ios*-simulator) CC=arm64-apple-ios-simulator-clang ;; - aarch64-apple-ios*) CC=arm64-apple-ios-clang ;; - x86_64-apple-ios*-simulator) CC=x86_64-apple-ios-simulator-clang ;; -+ -+ aarch64-apple-tvos*-simulator) CC=arm64-apple-tvos-simulator-clang ;; -+ aarch64-apple-tvos*) CC=arm64-apple-tvos-clang ;; -+ x86_64-apple-tvos*-simulator) CC=x86_64-apple-tvos-simulator-clang ;; -+ -+ aarch64-apple-watchos*-simulator) CC=arm64-apple-watchos-simulator-clang ;; -+ aarch64-apple-watchos*) CC=arm64_32-apple-watchos-clang ;; -+ x86_64-apple-watchos*-simulator) CC=x86_64-apple-watchos-simulator-clang ;; - *) - esac - fi -@@ -432,6 +458,14 @@ - aarch64-apple-ios*-simulator) CPP=arm64-apple-ios-simulator-cpp ;; - aarch64-apple-ios*) CPP=arm64-apple-ios-cpp ;; - x86_64-apple-ios*-simulator) CPP=x86_64-apple-ios-simulator-cpp ;; -+ -+ aarch64-apple-tvos*-simulator) CPP=arm64-apple-tvos-simulator-cpp ;; -+ aarch64-apple-tvos*) CPP=arm64-apple-tvos-cpp ;; -+ x86_64-apple-tvos*-simulator) CPP=x86_64-apple-tvos-simulator-cpp ;; -+ -+ aarch64-apple-watchos*-simulator) CPP=arm64-apple-watchos-simulator-cpp ;; -+ aarch64-apple-watchos*) CPP=arm64_32-apple-watchos-cpp ;; -+ x86_64-apple-watchos*-simulator) CPP=x86_64-apple-watchos-simulator-cpp ;; - *) - esac - fi -@@ -440,6 +474,14 @@ - aarch64-apple-ios*-simulator) CXX=arm64-apple-ios-simulator-clang++ ;; - aarch64-apple-ios*) CXX=arm64-apple-ios-clang++ ;; - x86_64-apple-ios*-simulator) CXX=x86_64-apple-ios-simulator-clang++ ;; -+ -+ aarch64-apple-tvos*-simulator) CXX=arm64-apple-tvos-simulator-clang++ ;; -+ aarch64-apple-tvos*) CXX=arm64-apple-tvos-clang++ ;; -+ x86_64-apple-tvos*-simulator) CXX=x86_64-apple-tvos-simulator-clang++ ;; -+ -+ aarch64-apple-watchos*-simulator) CXX=arm64-apple-watchos-simulator-clang++ ;; -+ aarch64-apple-watchos*) CXX=arm64_32-apple-watchos-clang++ ;; -+ x86_64-apple-watchos*-simulator) CXX=x86_64-apple-watchos-simulator-clang++ ;; - *) - esac - fi -@@ -554,8 +596,10 @@ - case $enableval in - yes) - case $ac_sys_system in -- Darwin) enableval=/Library/Frameworks ;; -- iOS) enableval=iOS/Frameworks/\$\(MULTIARCH\) ;; -+ Darwin) enableval=/Library/Frameworks ;; -+ iOS) enableval=iOS/Frameworks/\$\(MULTIARCH\) ;; -+ tvOS) enableval=tvOS/Frameworks/\$\(MULTIARCH\) ;; -+ watchOS) enableval=watchOS/Frameworks/\$\(MULTIARCH\) ;; - *) AC_MSG_ERROR([Unknown platform for framework build]) - esac - esac -@@ -564,6 +608,8 @@ - no) - case $ac_sys_system in - iOS) AC_MSG_ERROR([iOS builds must use --enable-framework]) ;; -+ tvOS) AC_MSG_ERROR([tvOS builds must use --enable-framework]) ;; -+ watchOS) AC_MSG_ERROR([watchOS builds must use --enable-framework]) ;; - *) - PYTHONFRAMEWORK= - PYTHONFRAMEWORKDIR=no-framework -@@ -666,6 +712,34 @@ - - AC_CONFIG_FILES([iOS/Resources/Info.plist]) - ;; -+ tvOS) : -+ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure" -+ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure " -+ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKPYTHONW= -+ INSTALLTARGETS="libinstall inclinstall sharedinstall" -+ -+ prefix=$PYTHONFRAMEWORKPREFIX -+ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" -+ RESSRCDIR=tvOS/Resources -+ -+ AC_CONFIG_FILES([tvOS/Resources/Info.plist]) -+ ;; -+ watchOS) : -+ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure" -+ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure " -+ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKPYTHONW= -+ INSTALLTARGETS="libinstall inclinstall sharedinstall" -+ -+ prefix=$PYTHONFRAMEWORKPREFIX -+ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" -+ RESSRCDIR=watchOS/Resources -+ -+ AC_CONFIG_FILES([watchOS/Resources/Info.plist]) -+ ;; - *) - AC_MSG_ERROR([Unknown platform for framework build]) - ;; -@@ -674,6 +748,8 @@ - ],[ - case $ac_sys_system in - iOS) AC_MSG_ERROR([iOS builds must use --enable-framework]) ;; -+ tvOS) AC_MSG_ERROR([tvOS builds must use --enable-framework]) ;; -+ watchOS) AC_MSG_ERROR([watchOS builds must use --enable-framework]) ;; - *) - PYTHONFRAMEWORK= - PYTHONFRAMEWORKDIR=no-framework -@@ -726,8 +802,8 @@ - case "$withval" in - yes) - case $ac_sys_system in -- Darwin|iOS) -- # iOS is able to share the macOS patch -+ Darwin|iOS|tvOS|watchOS) -+ # iOS/tvOS/watchOS is able to share the macOS patch - APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" - ;; - *) AC_MSG_ERROR([no default app store compliance patch available for $ac_sys_system]) ;; -@@ -741,8 +817,8 @@ - esac - ],[ - case $ac_sys_system in -- iOS) -- # Always apply the compliance patch on iOS; we can use the macOS patch -+ iOS|tvOS|watchOS) -+ # Always apply the compliance patch on iOS/tvOS/watchOS; we can use the macOS patch - APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" - AC_MSG_RESULT([applying default app store compliance patch]) - ;; -@@ -790,9 +866,61 @@ - ;; - esac - ;; -+ *-apple-tvos*) -+ _host_os=`echo $host | cut -d '-' -f3` -+ _host_device=`echo $host | cut -d '-' -f4` -+ _host_device=${_host_device:=os} -+ -+ # TVOS_DEPLOYMENT_TARGET is the minimum supported tvOS version -+ AC_MSG_CHECKING([tvOS deployment target]) -+ TVOS_DEPLOYMENT_TARGET=${_host_os:4} -+ TVOS_DEPLOYMENT_TARGET=${TVOS_DEPLOYMENT_TARGET:=12.0} -+ AC_MSG_RESULT([$TVOS_DEPLOYMENT_TARGET]) -+ -+ case "$host_cpu" in -+ aarch64) -+ _host_ident=${TVOS_DEPLOYMENT_TARGET}-arm64-appletv${_host_device} -+ ;; -+ *) -+ _host_ident=${TVOS_DEPLOYMENT_TARGET}-$host_cpu-appletv${_host_device} -+ ;; -+ esac -+ ;; -+ *-apple-watchos*) -+ _host_os=`echo $host | cut -d '-' -f3` -+ _host_device=`echo $host | cut -d '-' -f4` -+ _host_device=${_host_device:=os} -+ -+ # WATCHOS_DEPLOYMENT_TARGET is the minimum supported watchOS version -+ AC_MSG_CHECKING([watchOS deployment target]) -+ WATCHOS_DEPLOYMENT_TARGET=${_host_os:7} -+ WATCHOS_DEPLOYMENT_TARGET=${WATCHOS_DEPLOYMENT_TARGET:=4.0} -+ AC_MSG_RESULT([$WATCHOS_DEPLOYMENT_TARGET]) -+ -+ case "$host_cpu" in -+ aarch64) -+ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-arm64-watch${_host_device} -+ ;; -+ *) -+ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-$host_cpu-watch${_host_device} -+ ;; -+ esac -+ ;; -+ *-*-darwin*) -+ case "$host_cpu" in -+ arm*) -+ _host_ident=arm -+ ;; -+ *) -+ _host_ident=$host_cpu -+ esac -+ ;; - *-*-vxworks*) - _host_ident=$host_cpu - ;; -+ *-*-emscripten) -+ _host_ident=$(emcc -dumpversion | cut -f1 -d-)-$host_cpu -+ ;; - wasm32-*-* | wasm64-*-*) - _host_ident=$host_cpu - ;; -@@ -867,9 +995,13 @@ - define_xopen_source=no;; - Darwin/@<:@[12]@:>@@<:@0-9@:>@.*) - define_xopen_source=no;; -- # On iOS, defining _POSIX_C_SOURCE also disables platform specific features. -+ # On iOS/tvOS/watchOS, defining _POSIX_C_SOURCE also disables platform specific features. - iOS/*) - define_xopen_source=no;; -+ tvOS/*) -+ define_xopen_source=no;; -+ watchOS/*) -+ define_xopen_source=no;; - # On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from - # defining NI_NUMERICHOST. - QNX/6.3.2) -@@ -928,8 +1060,11 @@ - CONFIGURE_MACOSX_DEPLOYMENT_TARGET= - EXPORT_MACOSX_DEPLOYMENT_TARGET='#' - --# Record the value of IPHONEOS_DEPLOYMENT_TARGET enforced by the selected host triple. -+# Record the value of IPHONEOS_DEPLOYMENT_TARGET / TVOS_DEPLOYMENT_TARGET / -+# WATCHOS_DEPLOYMENT_TARGET enforced by the selected host triple. - AC_SUBST([IPHONEOS_DEPLOYMENT_TARGET]) -+AC_SUBST([TVOS_DEPLOYMENT_TARGET]) -+AC_SUBST([WATCHOS_DEPLOYMENT_TARGET]) - - # checks for alternative programs - -@@ -963,11 +1098,17 @@ - ], - ) - --dnl Add the compiler flag for the iOS minimum supported OS version. -+dnl Add the compiler flag for the iOS/tvOS/watchOS minimum supported OS version. - AS_CASE([$ac_sys_system], - [iOS], [ - AS_VAR_APPEND([CFLAGS], [" -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}"]) - AS_VAR_APPEND([LDFLAGS], [" -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}"]) -+ ],[tvOS], [ -+ AS_VAR_APPEND([CFLAGS], [" -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}"]) -+ AS_VAR_APPEND([LDFLAGS], [" -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}"]) -+ ],[watchOS], [ -+ AS_VAR_APPEND([CFLAGS], [" -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}"]) -+ AS_VAR_APPEND([LDFLAGS], [" -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}"]) - ], - ) - -@@ -1156,6 +1297,8 @@ - AS_CASE([$ac_sys_system], - [Darwin*], [MULTIARCH=""], - [iOS], [MULTIARCH=""], -+ [tvOS], [MULTIARCH=""], -+ [watchOS], [MULTIARCH=""], - [FreeBSD*], [MULTIARCH=""], - [MULTIARCH=$($CC --print-multiarch 2>/dev/null)] - ) -@@ -1177,7 +1320,7 @@ - dnl use a single "fat" binary at runtime. SOABI_PLATFORM is the component of - dnl the PLATFORM_TRIPLET that will be used in binary module extensions. - AS_CASE([$ac_sys_system], -- [iOS], [SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f2`], -+ [iOS|tvOS|watchOS], [SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f2`], - [SOABI_PLATFORM=$PLATFORM_TRIPLET] - ) - -@@ -1211,6 +1354,10 @@ - [x86_64-*-freebsd*/clang], [PY_SUPPORT_TIER=3], dnl FreeBSD on AMD64 - [aarch64-apple-ios*-simulator/clang], [PY_SUPPORT_TIER=3], dnl iOS Simulator on arm64 - [aarch64-apple-ios*/clang], [PY_SUPPORT_TIER=3], dnl iOS on ARM64 -+ [aarch64-apple-tvos*-simulator/clang], [PY_SUPPORT_TIER=3], dnl tvOS Simulator on arm64 -+ [aarch64-apple-tvos*/clang], [PY_SUPPORT_TIER=3], dnl tvOS on ARM64 -+ [aarch64-apple-watchos*-simulator/clang], [PY_SUPPORT_TIER=3], dnl watchOS Simulator on arm64 -+ [arm64_32-apple-watchos*/clang], [PY_SUPPORT_TIER=3], dnl watchOS on ARM64 - [aarch64-*-linux-android/clang], [PY_SUPPORT_TIER=3], dnl Android on ARM64 - [x86_64-*-linux-android/clang], [PY_SUPPORT_TIER=3], dnl Android on AMD64 - -@@ -1520,7 +1667,7 @@ - case $ac_sys_system in - Darwin) - LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)';; -- iOS) -+ iOS|tvOS|watchOS) - LDLIBRARY='$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';; - *) - AC_MSG_ERROR([Unknown platform for framework build]);; -@@ -1585,7 +1732,7 @@ - BLDLIBRARY='-L. -lpython$(LDVERSION)' - RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}} - ;; -- iOS) -+ iOS|tvOS|watchOS) - LDLIBRARY='libpython$(LDVERSION).dylib' - ;; - AIX*) -@@ -2157,6 +2304,27 @@ - BOLT_BINARIES="${BOLT_BINARIES} \$(INSTSONAME)" - ]) - -+AC_ARG_VAR( -+ [BOLT_COMMON_FLAGS], -+ [Common arguments to llvm-bolt when instrumenting and applying] -+) -+ -+AC_MSG_CHECKING([BOLT_COMMON_FLAGS]) -+if test -z "${BOLT_COMMON_FLAGS}" -+then -+ AS_VAR_SET( -+ [BOLT_COMMON_FLAGS], -+ [m4_normalize(" -+ [-update-debug-sections] -+ -+ dnl At least LLVM 19.x doesn't support computed gotos in PIC compiled code. -+ dnl Exclude functions containing computed gotos. -+ dnl TODO this may be fixed in LLVM 20.x via https://github.com/llvm/llvm-project/pull/120267. -+ [-skip-funcs=_PyEval_EvalFrameDefault,sre_ucs1_match/1,sre_ucs2_match/1,sre_ucs4_match/1] -+ ")] -+ ) -+fi -+ - AC_ARG_VAR( - [BOLT_INSTRUMENT_FLAGS], - [Arguments to llvm-bolt when instrumenting binaries] -@@ -2164,7 +2332,7 @@ - AC_MSG_CHECKING([BOLT_INSTRUMENT_FLAGS]) - if test -z "${BOLT_INSTRUMENT_FLAGS}" - then -- BOLT_INSTRUMENT_FLAGS= -+ BOLT_INSTRUMENT_FLAGS="${BOLT_COMMON_FLAGS}" - fi - AC_MSG_RESULT([$BOLT_INSTRUMENT_FLAGS]) - -@@ -2178,9 +2346,9 @@ - AS_VAR_SET( - [BOLT_APPLY_FLAGS], - [m4_normalize(" -- -update-debug-sections -+ ${BOLT_COMMON_FLAGS} - -reorder-blocks=ext-tsp -- -reorder-functions=hfsort+ -+ -reorder-functions=cdsort - -split-functions - -icf=1 - -inline-all -@@ -2333,7 +2501,7 @@ - dnl Include file system support - AS_VAR_APPEND([LINKFORSHARED], [" -sFORCE_FILESYSTEM -lidbfs.js -lnodefs.js -lproxyfs.js -lworkerfs.js"]) - AS_VAR_APPEND([LINKFORSHARED], [" -sEXPORTED_RUNTIME_METHODS=FS,callMain,ENV"]) -- AS_VAR_APPEND([LINKFORSHARED], [" -sEXPORTED_FUNCTIONS=_main,_Py_Version"]) -+ AS_VAR_APPEND([LINKFORSHARED], [" -sEXPORTED_FUNCTIONS=_main,_Py_Version,__PyRuntime,__PyEM_EMSCRIPTEN_COUNT_ARGS_OFFSET"]) - AS_VAR_APPEND([LINKFORSHARED], [" -sSTACK_SIZE=5MB"]) - - AS_VAR_IF([enable_wasm_dynamic_linking], [yes], [ -@@ -2600,6 +2768,13 @@ - esac - AC_MSG_RESULT([$CC]) - -+ # Error on unguarded use of new symbols, which will fail at runtime for -+ # users on older versions of macOS -+ AX_CHECK_COMPILE_FLAG([-Wunguarded-availability], -+ [AS_VAR_APPEND([CFLAGS_NODIST], [" -Werror=unguarded-availability"])], -+ [], -+ [-Werror]) -+ - LIPO_INTEL64_FLAGS="" - if test "${enable_universalsdk}" - then -@@ -2928,7 +3103,7 @@ - AC_CHECK_HEADERS([ \ - alloca.h asm/types.h bluetooth.h conio.h direct.h dlfcn.h endian.h errno.h fcntl.h grp.h \ - io.h langinfo.h libintl.h libutil.h linux/auxvec.h sys/auxv.h linux/fs.h linux/limits.h linux/memfd.h \ -- linux/netfilter_ipv4.h linux/random.h linux/soundcard.h \ -+ linux/netfilter_ipv4.h linux/random.h linux/soundcard.h linux/sched.h \ - linux/tipc.h linux/wait.h netdb.h net/ethernet.h netinet/in.h netpacket/packet.h poll.h process.h pthread.h pty.h \ - sched.h setjmp.h shadow.h signal.h spawn.h stropts.h sys/audioio.h sys/bsdtty.h sys/devpoll.h \ - sys/endian.h sys/epoll.h sys/event.h sys/eventfd.h sys/file.h sys/ioctl.h sys/kern_control.h \ -@@ -3412,7 +3587,7 @@ - BLDSHARED="$LDSHARED" - fi - ;; -- iOS/*) -+ iOS/*|tvOS/*|watchOS/*) - LDSHARED='$(CC) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)' - LDCXXSHARED='$(CXX) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)' - BLDSHARED="$LDSHARED" -@@ -3536,7 +3711,7 @@ - Linux-android*) LINKFORSHARED="-pie -Xlinker -export-dynamic";; - Linux*|GNU*) LINKFORSHARED="-Xlinker -export-dynamic";; - # -u libsys_s pulls in all symbols in libsys -- Darwin/*|iOS/*) -+ Darwin/*|iOS/*|tvOS/*|watchOS/*) - LINKFORSHARED="$extra_undefs -framework CoreFoundation" - - # Issue #18075: the default maximum stack size (8MBytes) is too -@@ -3560,7 +3735,7 @@ - LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' - fi - LINKFORSHARED="$LINKFORSHARED" -- elif test $ac_sys_system = "iOS"; then -+ elif test "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "watchOS"; then - LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)' - fi - ;; -@@ -3980,7 +4155,7 @@ - dnl when do we need USING_APPLE_OS_LIBFFI? - ctypes_malloc_closure=yes - ], -- [iOS], [ -+ [iOS|tvOS|watchOS], [ - ctypes_malloc_closure=yes - ], - [sunos5], [AS_VAR_APPEND([LIBFFI_LIBS], [" -mimpure-text"])] -@@ -3995,8 +4170,8 @@ - AS_VAR_IF([ac_cv_lib_dl_dlopen], [yes], [AS_VAR_APPEND([LIBFFI_LIBS], [" -ldl"])]) - - WITH_SAVE_ENV([ -- CFLAGS="$LIBFFI_CFLAGS $CFLAGS" -- LDFLAGS="$LIBFFI_LIBS $LDFLAGS" -+ CFLAGS="$CFLAGS $LIBFFI_CFLAGS" -+ LIBS="$LIBS $LIBFFI_LIBS" - - PY_CHECK_FUNC([ffi_prep_cif_var], [@%:@include ]) - PY_CHECK_FUNC([ffi_prep_closure_loc], [@%:@include ]) -@@ -4011,9 +4186,8 @@ - # - AC_CACHE_CHECK([libffi has complex type support], [ac_cv_ffi_complex_double_supported], - [WITH_SAVE_ENV([ -- CPPFLAGS="$LIBFFI_CFLAGS $CPPFLAGS" -- LDFLAGS="$LIBFFI_LIBS $LDFLAGS" -- LIBS="$LIBFFI_LIBS $LIBS" -+ CPPFLAGS="$CPPFLAGS $LIBFFI_CFLAGS" -+ LIBS="$LIBS $LIBFFI_LIBS" - AC_RUN_IFELSE([AC_LANG_SOURCE([[ - #include - #include -@@ -4076,8 +4250,8 @@ - - AS_VAR_IF([with_system_libmpdec], [yes], - [WITH_SAVE_ENV([ -- CPPFLAGS="$LIBMPDEC_CFLAGS $CPPFLAGS" -- LIBS="$LIBMPDEC_LIBS $LIBS" -+ CPPFLAGS="$CPPFLAGS $LIBMPDEC_CFLAGS" -+ LIBS="$LIBS $LIBMPDEC_LIBS" - - AC_LINK_IFELSE([ - AC_LANG_PROGRAM([ -@@ -4210,7 +4384,7 @@ - dnl bpo-45774/GH-29507: The CPP check in AC_CHECK_HEADER can fail on FreeBSD, - dnl hence CPPFLAGS instead of CFLAGS. - CPPFLAGS="$CPPFLAGS $LIBSQLITE3_CFLAGS" -- LDFLAGS="$LIBSQLITE3_LIBS $LDFLAGS" -+ LIBS="$LIBS $LIBSQLITE3_LIBS" - - AC_CHECK_HEADER([sqlite3.h], [ - have_sqlite3=yes -@@ -4313,7 +4487,7 @@ - - WITH_SAVE_ENV([ - CPPFLAGS="$CPPFLAGS $TCLTK_CFLAGS" -- LIBS="$TCLTK_LIBS $LDFLAGS" -+ LIBS="$LIBS $TCLTK_LIBS" - - AC_LINK_IFELSE([ - AC_LANG_PROGRAM([ -@@ -4355,7 +4529,7 @@ - AC_ARG_VAR([GDBM_LIBS], [additional linker flags for gdbm]) - WITH_SAVE_ENV([ - CPPFLAGS="$CPPFLAGS $GDBM_CFLAGS" -- LDFLAGS="$GDBM_LIBS $LDFLAGS" -+ LIBS="$LIBS $GDBM_LIBS" - AC_CHECK_HEADERS([gdbm.h], [ - AC_CHECK_LIB([gdbm], [gdbm_open], [ - have_gdbm=yes -@@ -4387,29 +4561,21 @@ - AC_MSG_RESULT([$have_ndbm ($dbm_ndbm)]) - - dnl "gdbm-ndbm.h" and "gdbm/ndbm.h" are both normalized to "gdbm_ndbm_h" --dnl unset ac_cv_header_gdbm_ndbm_h to prevent false positive cache hits. --AS_UNSET([ac_cv_header_gdbm_ndbm_h]) --AC_CACHE_VAL([ac_cv_header_gdbm_slash_ndbm_h], [ -- AC_CHECK_HEADER( -- [gdbm/ndbm.h], -- [ac_cv_header_gdbm_slash_ndbm_h=yes], [ac_cv_header_gdbm_slash_ndbm_h=no] -- ) --]) -+AC_CACHE_CHECK([for gdbm/ndbm.h], [ac_cv_header_gdbm_slash_ndbm_h], -+ [AC_PREPROC_IFELSE([AC_LANG_SOURCE([@%:@include ])], -+ [ac_cv_header_gdbm_slash_ndbm_h=yes], -+ [ac_cv_header_gdbm_slash_ndbm_h=no])]) - AS_VAR_IF([ac_cv_header_gdbm_slash_ndbm_h], [yes], [ - AC_DEFINE([HAVE_GDBM_NDBM_H], [1], [Define to 1 if you have the header file.]) - ]) - --AS_UNSET([ac_cv_header_gdbm_ndbm_h]) --AC_CACHE_VAL([ac_cv_header_gdbm_dash_ndbm_h], [ -- AC_CHECK_HEADER( -- [gdbm-ndbm.h], -- [ac_cv_header_gdbm_dash_ndbm_h=yes], [ac_cv_header_gdbm_dash_ndbm_h=no] -- ) --]) -+AC_CACHE_CHECK([for gdbm-ndbm.h], [ac_cv_header_gdbm_dash_ndbm_h], -+ [AC_PREPROC_IFELSE([AC_LANG_SOURCE([@%:@include ])], -+ [ac_cv_header_gdbm_dash_ndbm_h=yes], -+ [ac_cv_header_gdbm_dash_ndbm_h=no])]) - AS_VAR_IF([ac_cv_header_gdbm_dash_ndbm_h], [yes], [ - AC_DEFINE([HAVE_GDBM_DASH_NDBM_H], [1], [Define to 1 if you have the header file.]) - ]) --AS_UNSET([ac_cv_header_gdbm_ndbm_h]) - - if test "$ac_cv_header_gdbm_slash_ndbm_h" = yes -o "$ac_cv_header_gdbm_dash_ndbm_h" = yes; then - AS_UNSET([ac_cv_search_dbm_open]) -@@ -5098,9 +5264,9 @@ - # checks for library functions - AC_CHECK_FUNCS([ \ - accept4 alarm bind_textdomain_codeset chmod chown clock closefrom close_range confstr \ -- copy_file_range ctermid dup dup3 execv explicit_bzero explicit_memset \ -+ copy_file_range ctermid dladdr dup dup3 explicit_bzero explicit_memset \ - faccessat fchmod fchmodat fchown fchownat fdopendir fdwalk fexecve \ -- fork fork1 fpathconf fstatat ftime ftruncate futimens futimes futimesat \ -+ fpathconf fstatat ftime ftruncate futimens futimes futimesat \ - gai_strerror getegid geteuid getgid getgrent getgrgid getgrgid_r \ - getgrnam_r getgrouplist gethostname getitimer getloadavg getlogin \ - getpeername getpgid getpid getppid getpriority _getpty \ -@@ -5108,8 +5274,7 @@ - getspnam getuid getwd grantpt if_nameindex initgroups kill killpg lchown linkat \ - lockf lstat lutimes madvise mbrtowc memrchr mkdirat mkfifo mkfifoat \ - mknod mknodat mktime mmap mremap nice openat opendir pathconf pause pipe \ -- pipe2 plock poll posix_fadvise posix_fallocate posix_openpt posix_spawn posix_spawnp \ -- posix_spawn_file_actions_addclosefrom_np \ -+ pipe2 plock poll posix_fadvise posix_fallocate posix_openpt \ - pread preadv preadv2 process_vm_readv \ - pthread_cond_timedwait_relative_np pthread_condattr_setclock pthread_init \ - pthread_kill pthread_getname_np pthread_setname_np \ -@@ -5118,11 +5283,11 @@ - sched_setparam sched_setscheduler sem_clockwait sem_getvalue sem_open \ - sem_timedwait sem_unlink sendfile setegid seteuid setgid sethostname \ - setitimer setlocale setpgid setpgrp setpriority setregid setresgid \ -- setresuid setreuid setsid setuid setvbuf shutdown sigaction sigaltstack \ -+ setresuid setreuid setsid setuid setvbuf shutdown sigaction \ - sigfillset siginterrupt sigpending sigrelse sigtimedwait sigwait \ - sigwaitinfo snprintf splice strftime strlcpy strsignal symlinkat sync \ - sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile \ -- tmpnam tmpnam_r truncate ttyname umask uname unlinkat unlockpt utimensat utimes vfork \ -+ tmpnam tmpnam_r truncate ttyname_r umask uname unlinkat unlockpt utimensat utimes vfork \ - wait wait3 wait4 waitid waitpid wcscoll wcsftime wcsxfrm wmemcmp writev \ - ]) - -@@ -5133,12 +5298,20 @@ - AC_CHECK_FUNCS([lchmod]) - fi - --# iOS defines some system methods that can be linked (so they are -+# iOS/tvOS/watchOS define some system methods that can be linked (so they are - # found by configure), but either raise a compilation error (because the - # header definition prevents usage - autoconf doesn't use the headers), or - # raise an error if used at runtime. Force these symbols off. --if test "$ac_sys_system" != "iOS" ; then -- AC_CHECK_FUNCS([getentropy getgroups system]) -+if test "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then -+ AC_CHECK_FUNCS([ getentropy getgroups system ]) -+fi -+ -+# tvOS/watchOS have some additional methods that can be found, but not used. -+if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then -+ AC_CHECK_FUNCS([ \ -+ execv fork fork1 posix_spawn posix_spawnp posix_spawn_file_actions_addclosefrom_np \ -+ sigaltstack \ -+ ]) - fi - - AC_CHECK_DECL([dirfd], -@@ -5300,7 +5473,7 @@ - ], [ - WITH_SAVE_ENV([ - CPPFLAGS="$CPPFLAGS $ZLIB_CFLAGS" -- LDFLAGS="$LDFLAGS $ZLIB_LIBS" -+ LIBS="$LIBS $ZLIB_LIBS" - AC_CHECK_HEADERS([zlib.h], [ - PY_CHECK_LIB([z], [gzread], [have_zlib=yes], [have_zlib=no]) - ], [have_zlib=no]) -@@ -5324,7 +5497,7 @@ - PKG_CHECK_MODULES([BZIP2], [bzip2], [have_bzip2=yes], [ - WITH_SAVE_ENV([ - CPPFLAGS="$CPPFLAGS $BZIP2_CFLAGS" -- LDFLAGS="$LDFLAGS $BZIP2_LIBS" -+ LIBS="$LIBS $BZIP2_LIBS" - AC_CHECK_HEADERS([bzlib.h], [ - AC_CHECK_LIB([bz2], [BZ2_bzCompress], [have_bzip2=yes], [have_bzip2=no]) - ], [have_bzip2=no]) -@@ -5338,7 +5511,7 @@ - PKG_CHECK_MODULES([LIBLZMA], [liblzma], [have_liblzma=yes], [ - WITH_SAVE_ENV([ - CPPFLAGS="$CPPFLAGS $LIBLZMA_CFLAGS" -- LDFLAGS="$LDFLAGS $LIBLZMA_LIBS" -+ LIBS="$LIBS $LIBLZMA_LIBS" - AC_CHECK_HEADERS([lzma.h], [ - AC_CHECK_LIB([lzma], [lzma_easy_encoder], [have_liblzma=yes], [have_liblzma=no]) - ], [have_liblzma=no]) -@@ -5392,20 +5565,22 @@ - ]) - - # check for openpty, login_tty, and forkpty -- --AC_CHECK_FUNCS([openpty], [], -- [AC_CHECK_LIB([util], [openpty], -- [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lutil"], -- [AC_CHECK_LIB([bsd], [openpty], -- [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lbsd"])])]) --AC_SEARCH_LIBS([login_tty], [util], -- [AC_DEFINE([HAVE_LOGIN_TTY], [1], [Define to 1 if you have the `login_tty' function.])] --) --AC_CHECK_FUNCS([forkpty], [], -- [AC_CHECK_LIB([util], [forkpty], -- [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lutil"], -- [AC_CHECK_LIB([bsd], [forkpty], -- [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lbsd"])])]) -+# tvOS/watchOS have functions for tty, but can't use them -+if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then -+ AC_CHECK_FUNCS([openpty], [], -+ [AC_CHECK_LIB([util], [openpty], -+ [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lutil"], -+ [AC_CHECK_LIB([bsd], [openpty], -+ [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lbsd"])])]) -+ AC_SEARCH_LIBS([login_tty], [util], -+ [AC_DEFINE([HAVE_LOGIN_TTY], [1], [Define to 1 if you have the `login_tty' function.])] -+ ) -+ AC_CHECK_FUNCS([forkpty], [], -+ [AC_CHECK_LIB([util], [forkpty], -+ [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lutil"], -+ [AC_CHECK_LIB([bsd], [forkpty], -+ [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lbsd"])])]) -+fi - - # check for long file support functions - AC_CHECK_FUNCS([fseek64 fseeko fstatvfs ftell64 ftello statvfs]) -@@ -5444,10 +5619,10 @@ - ]) - ]) - --# On Android and iOS, clock_settime can be linked (so it is found by -+# On Android, iOS, tvOS and watchOS, clock_settime can be linked (so it is found by - # configure), but when used in an unprivileged process, it crashes rather than - # returning an error. Force the symbol off. --if test "$ac_sys_system" != "Linux-android" && test "$ac_sys_system" != "iOS" -+if test "$ac_sys_system" != "Linux-android" -a "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" - then - AC_CHECK_FUNCS([clock_settime], [], [ - AC_CHECK_LIB([rt], [clock_settime], [ -@@ -6198,8 +6373,8 @@ - LIBPYTHON="\$(BLDLIBRARY)" - fi - --# On iOS the shared libraries must be linked with the Python framework --if test "$ac_sys_system" = "iOS"; then -+# On iOS/tvOS/watchOS the shared libraries must be linked with the Python framework -+if test "$ac_sys_system" = "iOS" -o $ac_sys_system = "tvOS" -o $ac_sys_system = "watchOS"; then - MODULE_DEPS_SHARED="$MODULE_DEPS_SHARED \$(PYTHONFRAMEWORKDIR)/\$(PYTHONFRAMEWORK)" - fi - -@@ -6332,7 +6507,7 @@ - ], [ - WITH_SAVE_ENV([ - CPPFLAGS="$CPPFLAGS $LIBREADLINE_CFLAGS" -- LDFLAGS="$LDFLAGS $LIBREADLINE_LIBS" -+ LIBS="$LIBS $LIBREADLINE_LIBS" - AC_CHECK_HEADERS([readline/readline.h], [ - AC_CHECK_LIB([readline], [readline], [ - LIBREADLINE=readline -@@ -6353,7 +6528,7 @@ - ], [ - WITH_SAVE_ENV([ - CPPFLAGS="$CPPFLAGS $LIBEDIT_CFLAGS" -- LDFLAGS="$LDFLAGS $LIBEDIT_LIBS" -+ LIBS="$LIBS $LIBEDIT_LIBS" - AC_CHECK_HEADERS([editline/readline.h], [ - AC_CHECK_LIB([edit], [readline], [ - LIBREADLINE=edit -@@ -6377,7 +6552,7 @@ - - WITH_SAVE_ENV([ - CPPFLAGS="$CPPFLAGS $READLINE_CFLAGS" -- LIBS="$READLINE_LIBS $LIBS" -+ LIBS="$LIBS $READLINE_LIBS" - LIBS_SAVE=$LIBS - - m4_define([readline_includes], [ -@@ -6662,7 +6837,7 @@ - [Define if year with century should be normalized for strftime.]) - fi - --AC_CACHE_CHECK([whether C99-specific strftime specifiers are supported], [ac_cv_strftime_c99_support], [ -+AC_CACHE_CHECK([whether C99-compatible strftime specifiers are supported], [ac_cv_strftime_c99_support], [ - AC_RUN_IFELSE([AC_LANG_SOURCE([[ - #include - #include -@@ -6682,13 +6857,8 @@ - } - ]])], - [ac_cv_strftime_c99_support=yes], --[ac_cv_strftime_c99_support=no], --[ac_cv_strftime_c99_support=no])]) --if test "$ac_cv_strftime_c99_support" = yes --then -- AC_DEFINE([Py_STRFTIME_C99_SUPPORT], [1], -- [Define if C99-specific strftime specifiers are supported.]) --fi -+[AC_MSG_ERROR([Python requires C99-compatible strftime specifiers])], -+[ac_cv_strftime_c99_support=])]) - - dnl check for ncursesw/ncurses and panelw/panel - dnl NOTE: old curses is not detected. -@@ -6863,7 +7033,7 @@ - dnl NOTE: Inform user how to proceed with files when cross compiling. - dnl Some cross-compile builds are predictable; they won't ever - dnl have /dev/ptmx or /dev/ptc, so we can set them explicitly. --if test "$ac_sys_system" = "Linux-android" || test "$ac_sys_system" = "iOS"; then -+if test "$ac_sys_system" = "Linux-android" -o "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "watchOS" ; then - ac_cv_file__dev_ptmx=no - ac_cv_file__dev_ptc=no - else -@@ -6979,6 +7149,44 @@ - [Define if the C compiler supports computed gotos.]) - esac - -+# Check for --with-tail-call-interp -+AC_MSG_CHECKING([for --with-tail-call-interp]) -+AC_ARG_WITH( -+ [tail-call-interp], -+ [AS_HELP_STRING( -+ [--with-tail-call-interp], -+ [enable tail-calling interpreter in evaluation loop and rest of CPython] -+ )], -+[ -+if test "$withval" = yes -+then -+ AC_DEFINE([Py_TAIL_CALL_INTERP], [1], -+ [Define if you want to use tail-calling interpreters in CPython.]) -+ AC_MSG_RESULT([yes]) -+fi -+if test "$withval" = no -+then -+ AC_DEFINE([Py_TAIL_CALL_INTERP], [0], -+ [Define if you want to use tail-calling interpreters in CPython.]) -+ AC_MSG_RESULT([no]) -+fi -+], -+[AC_MSG_RESULT([no value specified])]) -+ -+# Do not enable tail-calling interpreter if tier 2 is enabled. -+AS_VAR_IF( -+ [tier2_flags], -+ [], -+ [ -+ case "$ac_cv_tail_call" in yes*) -+ AC_DEFINE([Py_TAIL_CALL_INTERP], [1], -+ [Define if the C compiler supports efficient proper tail calls.]) -+ esac -+ ], -+ [] -+) -+ -+ - case $ac_sys_system in - AIX*) - AC_DEFINE([HAVE_BROKEN_PIPE_BUF], [1], -@@ -7119,7 +7327,7 @@ - AS_CASE([$ac_sys_system], - [Emscripten], [with_ensurepip=no], - [WASI], [with_ensurepip=no], -- [iOS], [with_ensurepip=no], -+ [iOS|tvOS|watchOS], [with_ensurepip=no], - [with_ensurepip=upgrade] - ) - ]) -@@ -7502,18 +7710,19 @@ - - # gh-59705: Maximum length in bytes of a thread name - case "$ac_sys_system" in -- Linux*) PYTHREAD_NAME_MAXLEN=15;; # Linux and Android -- SunOS*) PYTHREAD_NAME_MAXLEN=31;; -- Darwin) PYTHREAD_NAME_MAXLEN=63;; -- iOS) PYTHREAD_NAME_MAXLEN=63;; -- FreeBSD*) PYTHREAD_NAME_MAXLEN=98;; -- *) PYTHREAD_NAME_MAXLEN=;; -+ Linux*) _PYTHREAD_NAME_MAXLEN=15;; # Linux and Android -+ SunOS*) _PYTHREAD_NAME_MAXLEN=31;; -+ NetBSD*) _PYTHREAD_NAME_MAXLEN=31;; -+ Darwin) _PYTHREAD_NAME_MAXLEN=63;; -+ iOS) _PYTHREAD_NAME_MAXLEN=63;; -+ FreeBSD*) _PYTHREAD_NAME_MAXLEN=98;; -+ *) _PYTHREAD_NAME_MAXLEN=;; - esac --if test -n "$PYTHREAD_NAME_MAXLEN"; then -- AC_DEFINE_UNQUOTED([PYTHREAD_NAME_MAXLEN], [$PYTHREAD_NAME_MAXLEN], -+if test -n "$_PYTHREAD_NAME_MAXLEN"; then -+ AC_DEFINE_UNQUOTED([_PYTHREAD_NAME_MAXLEN], [$_PYTHREAD_NAME_MAXLEN], - [Maximum length in bytes of a thread name]) - fi --AC_SUBST([PYTHREAD_NAME_MAXLEN]) -+AC_SUBST([_PYTHREAD_NAME_MAXLEN]) - - - # stdlib -@@ -7529,7 +7738,7 @@ - [VxWorks*], [PY_STDLIB_MOD_SET_NA([_scproxy], [termios], [grp])], - dnl The _scproxy module is available on macOS - [Darwin], [], -- [iOS], [ -+ [iOS|tvOS|watchOS], [ - dnl subprocess and multiprocessing are not supported (no fork syscall). - dnl curses and tkinter user interface are not available. - dnl gdbm and nis aren't available -diff --git a/iOS/Resources/Info.plist.in b/iOS/Resources/Info.plist.in -index c3e261ecd9e..26ef7a95de4 100644 ---- a/iOS/Resources/Info.plist.in -+++ b/iOS/Resources/Info.plist.in -@@ -17,13 +17,13 @@ - CFBundlePackageType - FMWK - CFBundleShortVersionString -- @VERSION@ -+ %VERSION% - CFBundleLongVersionString - %VERSION%, (c) 2001-2024 Python Software Foundation. - CFBundleSignature - ???? - CFBundleVersion -- 1 -+ %VERSION% - CFBundleSupportedPlatforms - - iPhoneOS ---- /dev/null -+++ b/iOS/Resources/bin/arm64-apple-ios-macabi-ar -@@ -0,0 +1,2 @@ -+#!/bin/sh -+xcrun --sdk macosx${MACOSX_SDK_VERSION} ar "$@" ---- /dev/null -+++ b/iOS/Resources/bin/arm64-apple-ios-macabi-clang -@@ -0,0 +1,2 @@ -+#!/bin/sh -+xcrun --sdk macosx${MACOSX_SDK_VERSION} clang -target arm64-apple-ios-macabi "$@" ---- /dev/null -+++ b/iOS/Resources/bin/arm64-apple-ios-macabi-clang++ -@@ -0,0 +1,2 @@ -+#!/bin/sh -+xcrun --sdk macosx${MACOSX_SDK_VERSION} clang++ -target arm64-apple-ios-macabi "$@" ---- /dev/null -+++ b/iOS/Resources/bin/arm64-apple-ios-macabi-cpp -@@ -0,0 +1,2 @@ -+#!/bin/sh -+xcrun --sdk macosx${MACOSX_SDK_VERSION} clang -target arm64-apple-ios-macabi "$@" ---- /dev/null -+++ b/iOS/Resources/bin/x86_64-apple-ios-macabi-ar -@@ -0,0 +1,2 @@ -+#!/bin/sh -+xcrun --sdk macosx${MACOSX_SDK_VERSION} ar "$@" ---- /dev/null -+++ b/iOS/Resources/bin/x86_64-apple-ios-macabi-clang -@@ -0,0 +1,2 @@ -+#!/bin/sh -+xcrun --sdk macosx${MACOSX_SDK_VERSION} clang -target x86_64-apple-ios-macabi "$@" ---- /dev/null -+++ b/iOS/Resources/bin/x86_64-apple-ios-macabi-clang++ -@@ -0,0 +1,2 @@ -+#!/bin/sh -+xcrun --sdk macosx${MACOSX_SDK_VERSION} clang++ -target x86_64-apple-ios-macabi "$@" ---- /dev/null -+++ b/iOS/Resources/bin/x86_64-apple-ios-macabi-cpp -@@ -0,0 +1,2 @@ -+#!/bin/sh -+xcrun --sdk macosx${MACOSX_SDK_VERSION} clang -target x86_64-apple-ios-macabi "$@" -diff --git a/iOS/testbed/__main__.py b/iOS/testbed/__main__.py -index 068272835a5..d12a5ab065b 100644 ---- a/iOS/testbed/__main__.py -+++ b/iOS/testbed/__main__.py -@@ -2,6 +2,7 @@ - import asyncio - import json - import plistlib -+import re - import shutil - import subprocess - import sys -@@ -12,6 +13,18 @@ - - DECODE_ARGS = ("UTF-8", "backslashreplace") - -+# The system log prefixes each line: -+# 2025-01-17 16:14:29.090 Df iOSTestbed[23987:1fd393b4] (Python) ... -+# 2025-01-17 16:14:29.090 E iOSTestbed[23987:1fd393b4] (Python) ... -+ -+LOG_PREFIX_REGEX = re.compile( -+ r"^\d{4}-\d{2}-\d{2}" # YYYY-MM-DD -+ r"\s+\d+:\d{2}:\d{2}\.\d+" # HH:MM:SS.sss -+ r"\s+\w+" # Df/E -+ r"\s+iOSTestbed\[\d+:\w+\]" # Process/thread ID -+ r"\s+\(Python\)\s" # Logger name -+) -+ - - # Work around a bug involving sys.exit and TaskGroups - # (https://github.com/python/cpython/issues/101515). -@@ -69,19 +82,29 @@ - - # Return a list of UDIDs associated with booted simulators - async def list_devices(): -- # List the testing simulators, in JSON format -- raw_json = await async_check_output( -- "xcrun", "simctl", "--set", "testing", "list", "-j" -- ) -- json_data = json.loads(raw_json) -- -- # Filter out the booted iOS simulators -- return [ -- simulator["udid"] -- for runtime, simulators in json_data["devices"].items() -- for simulator in simulators -- if runtime.split(".")[-1].startswith("iOS") and simulator["state"] == "Booted" -- ] -+ try: -+ # List the testing simulators, in JSON format -+ raw_json = await async_check_output( -+ "xcrun", "simctl", "--set", "testing", "list", "-j" -+ ) -+ json_data = json.loads(raw_json) -+ -+ # Filter out the booted iOS simulators -+ return [ -+ simulator["udid"] -+ for runtime, simulators in json_data["devices"].items() -+ for simulator in simulators -+ if runtime.split(".")[-1].startswith("iOS") and simulator["state"] == "Booted" -+ ] -+ except subprocess.CalledProcessError as e: -+ # If there's no ~/Library/Developer/XCTestDevices folder (which is the -+ # case on fresh installs, and in some CI environments), `simctl list` -+ # returns error code 1, rather than an empty list. Handle that case, -+ # but raise all other errors. -+ if e.returncode == 1: -+ return [] -+ else: -+ raise - - - async def find_device(initial_devices): -@@ -131,6 +154,8 @@ - ) as process: - suppress_dupes = False - while line := (await process.stdout.readline()).decode(*DECODE_ARGS): -+ # Strip the prefix from each log line -+ line = LOG_PREFIX_REGEX.sub("", line) - # The iOS log streamer can sometimes lag; when it does, it outputs - # a warning about messages being dropped... often multiple times. - # Only print the first of these duplicated warnings. -@@ -215,33 +240,69 @@ - shutil.copytree(source, target, symlinks=True) - print(" done") - -+ xc_framework_path = target / "Python.xcframework" -+ sim_framework_path = xc_framework_path / "ios-arm64_x86_64-simulator" - if framework is not None: - if framework.suffix == ".xcframework": - print(" Installing XCFramework...", end="", flush=True) -- xc_framework_path = (target / "Python.xcframework").resolve() - if xc_framework_path.is_dir(): - shutil.rmtree(xc_framework_path) - else: -- xc_framework_path.unlink() -+ xc_framework_path.unlink(missing_ok=True) - xc_framework_path.symlink_to( - framework.relative_to(xc_framework_path.parent, walk_up=True) - ) - print(" done") - else: - print(" Installing simulator framework...", end="", flush=True) -- sim_framework_path = ( -- target / "Python.xcframework" / "ios-arm64_x86_64-simulator" -- ).resolve() - if sim_framework_path.is_dir(): - shutil.rmtree(sim_framework_path) - else: -- sim_framework_path.unlink() -+ sim_framework_path.unlink(missing_ok=True) - sim_framework_path.symlink_to( - framework.relative_to(sim_framework_path.parent, walk_up=True) - ) - print(" done") - else: -- print(" Using pre-existing iOS framework.") -+ if ( -+ xc_framework_path.is_symlink() -+ and not xc_framework_path.readlink().is_absolute() -+ ): -+ # XCFramework is a relative symlink. Rewrite the symlink relative -+ # to the new location. -+ print(" Rewriting symlink to XCframework...", end="", flush=True) -+ orig_xc_framework_path = ( -+ source -+ / xc_framework_path.readlink() -+ ).resolve() -+ xc_framework_path.unlink() -+ xc_framework_path.symlink_to( -+ orig_xc_framework_path.relative_to( -+ xc_framework_path.parent, walk_up=True -+ ) -+ ) -+ print(" done") -+ elif ( -+ sim_framework_path.is_symlink() -+ and not sim_framework_path.readlink().is_absolute() -+ ): -+ print(" Rewriting symlink to simulator framework...", end="", flush=True) -+ # Simulator framework is a relative symlink. Rewrite the symlink -+ # relative to the new location. -+ orig_sim_framework_path = ( -+ source -+ / "Python.XCframework" -+ / sim_framework_path.readlink() -+ ).resolve() -+ sim_framework_path.unlink() -+ sim_framework_path.symlink_to( -+ orig_sim_framework_path.relative_to( -+ sim_framework_path.parent, walk_up=True -+ ) -+ ) -+ print(" done") -+ else: -+ print(" Using pre-existing iOS framework.") - - for app_src in apps: - print(f" Installing app {app_src.name!r}...", end="", flush=True) -@@ -357,8 +418,8 @@ - - if context.subcommand == "clone": - clone_testbed( -- source=Path(__file__).parent, -- target=Path(context.location), -+ source=Path(__file__).parent.resolve(), -+ target=Path(context.location).resolve(), - framework=Path(context.framework).resolve() if context.framework else None, - apps=[Path(app) for app in context.apps], - ) -diff --git a/install-sh b/install-sh -index ec298b53740..7c56c9c0151 100755 ---- a/install-sh -+++ b/install-sh -@@ -1,7 +1,7 @@ - #!/bin/sh - # install - install a program, script, or datafile - --scriptversion=2020-11-14.01; # UTC -+scriptversion=2023-11-23.18; # UTC - - # This originates from X11R5 (mit/util/scripts/install.sh), which was - # later released in X11R6 (xc/config/util/install.sh) with the -@@ -124,9 +124,9 @@ - - If -S is not specified, no backups are attempted. - --Email bug reports to bug-automake@gnu.org. --Automake home page: https://www.gnu.org/software/automake/ --" -+Report bugs to . -+GNU Automake home page: . -+General help using GNU software: ." - - while test $# -ne 0; do - case $1 in -diff --git a/pyconfig.h.in b/pyconfig.h.in -index 166c195a8c6..9ea01ad3fc0 100644 ---- a/pyconfig.h.in -+++ b/pyconfig.h.in -@@ -16,13 +16,13 @@ - support for AIX C++ shared extension modules. */ - #undef AIX_GENUINE_CPLUSPLUS - --/* The normal alignment of `long', in bytes. */ -+/* The normal alignment of 'long', in bytes. */ - #undef ALIGNOF_LONG - --/* The normal alignment of `max_align_t', in bytes. */ -+/* The normal alignment of 'max_align_t', in bytes. */ - #undef ALIGNOF_MAX_ALIGN_T - --/* The normal alignment of `size_t', in bytes. */ -+/* The normal alignment of 'size_t', in bytes. */ - #undef ALIGNOF_SIZE_T - - /* Alternative SOABI used in debug build to load C extensions built in release -@@ -59,16 +59,16 @@ - /* Define if you have the 'accept' function. */ - #undef HAVE_ACCEPT - --/* Define to 1 if you have the `accept4' function. */ -+/* Define to 1 if you have the 'accept4' function. */ - #undef HAVE_ACCEPT4 - --/* Define to 1 if you have the `acosh' function. */ -+/* Define to 1 if you have the 'acosh' function. */ - #undef HAVE_ACOSH - - /* struct addrinfo (netdb.h) */ - #undef HAVE_ADDRINFO - --/* Define to 1 if you have the `alarm' function. */ -+/* Define to 1 if you have the 'alarm' function. */ - #undef HAVE_ALARM - - /* Define if aligned memory access is required */ -@@ -80,19 +80,19 @@ - /* Define this if your time.h defines altzone. */ - #undef HAVE_ALTZONE - --/* Define to 1 if you have the `asinh' function. */ -+/* Define to 1 if you have the 'asinh' function. */ - #undef HAVE_ASINH - - /* Define to 1 if you have the header file. */ - #undef HAVE_ASM_TYPES_H - --/* Define to 1 if you have the `atanh' function. */ -+/* Define to 1 if you have the 'atanh' function. */ - #undef HAVE_ATANH - - /* Define if you have the 'bind' function. */ - #undef HAVE_BIND - --/* Define to 1 if you have the `bind_textdomain_codeset' function. */ -+/* Define to 1 if you have the 'bind_textdomain_codeset' function. */ - #undef HAVE_BIND_TEXTDOMAIN_CODESET - - /* Define to 1 if you have the header file. */ -@@ -135,43 +135,43 @@ - /* Define to 1 if you have the 'chflags' function. */ - #undef HAVE_CHFLAGS - --/* Define to 1 if you have the `chmod' function. */ -+/* Define to 1 if you have the 'chmod' function. */ - #undef HAVE_CHMOD - --/* Define to 1 if you have the `chown' function. */ -+/* Define to 1 if you have the 'chown' function. */ - #undef HAVE_CHOWN - - /* Define if you have the 'chroot' function. */ - #undef HAVE_CHROOT - --/* Define to 1 if you have the `clock' function. */ -+/* Define to 1 if you have the 'clock' function. */ - #undef HAVE_CLOCK - --/* Define to 1 if you have the `clock_getres' function. */ -+/* Define to 1 if you have the 'clock_getres' function. */ - #undef HAVE_CLOCK_GETRES - --/* Define to 1 if you have the `clock_gettime' function. */ -+/* Define to 1 if you have the 'clock_gettime' function. */ - #undef HAVE_CLOCK_GETTIME - --/* Define to 1 if you have the `clock_nanosleep' function. */ -+/* Define to 1 if you have the 'clock_nanosleep' function. */ - #undef HAVE_CLOCK_NANOSLEEP - --/* Define to 1 if you have the `clock_settime' function. */ -+/* Define to 1 if you have the 'clock_settime' function. */ - #undef HAVE_CLOCK_SETTIME - --/* Define to 1 if the system has the type `clock_t'. */ -+/* Define to 1 if the system has the type 'clock_t'. */ - #undef HAVE_CLOCK_T - --/* Define to 1 if you have the `closefrom' function. */ -+/* Define to 1 if you have the 'closefrom' function. */ - #undef HAVE_CLOSEFROM - --/* Define to 1 if you have the `close_range' function. */ -+/* Define to 1 if you have the 'close_range' function. */ - #undef HAVE_CLOSE_RANGE - - /* Define if the C compiler supports computed gotos. */ - #undef HAVE_COMPUTED_GOTOS - --/* Define to 1 if you have the `confstr' function. */ -+/* Define to 1 if you have the 'confstr' function. */ - #undef HAVE_CONFSTR - - /* Define to 1 if you have the header file. */ -@@ -180,10 +180,10 @@ - /* Define if you have the 'connect' function. */ - #undef HAVE_CONNECT - --/* Define to 1 if you have the `copy_file_range' function. */ -+/* Define to 1 if you have the 'copy_file_range' function. */ - #undef HAVE_COPY_FILE_RANGE - --/* Define to 1 if you have the `ctermid' function. */ -+/* Define to 1 if you have the 'ctermid' function. */ - #undef HAVE_CTERMID - - /* Define if you have the 'ctermid_r' function. */ -@@ -228,39 +228,39 @@ - /* Define to 1 if you have the header file. */ - #undef HAVE_DB_H - --/* Define to 1 if you have the declaration of `RTLD_DEEPBIND', and to 0 if you -+/* Define to 1 if you have the declaration of 'RTLD_DEEPBIND', and to 0 if you - don't. */ - #undef HAVE_DECL_RTLD_DEEPBIND - --/* Define to 1 if you have the declaration of `RTLD_GLOBAL', and to 0 if you -+/* Define to 1 if you have the declaration of 'RTLD_GLOBAL', and to 0 if you - don't. */ - #undef HAVE_DECL_RTLD_GLOBAL - --/* Define to 1 if you have the declaration of `RTLD_LAZY', and to 0 if you -+/* Define to 1 if you have the declaration of 'RTLD_LAZY', and to 0 if you - don't. */ - #undef HAVE_DECL_RTLD_LAZY - --/* Define to 1 if you have the declaration of `RTLD_LOCAL', and to 0 if you -+/* Define to 1 if you have the declaration of 'RTLD_LOCAL', and to 0 if you - don't. */ - #undef HAVE_DECL_RTLD_LOCAL - --/* Define to 1 if you have the declaration of `RTLD_MEMBER', and to 0 if you -+/* Define to 1 if you have the declaration of 'RTLD_MEMBER', and to 0 if you - don't. */ - #undef HAVE_DECL_RTLD_MEMBER - --/* Define to 1 if you have the declaration of `RTLD_NODELETE', and to 0 if you -+/* Define to 1 if you have the declaration of 'RTLD_NODELETE', and to 0 if you - don't. */ - #undef HAVE_DECL_RTLD_NODELETE - --/* Define to 1 if you have the declaration of `RTLD_NOLOAD', and to 0 if you -+/* Define to 1 if you have the declaration of 'RTLD_NOLOAD', and to 0 if you - don't. */ - #undef HAVE_DECL_RTLD_NOLOAD - --/* Define to 1 if you have the declaration of `RTLD_NOW', and to 0 if you -+/* Define to 1 if you have the declaration of 'RTLD_NOW', and to 0 if you - don't. */ - #undef HAVE_DECL_RTLD_NOW - --/* Define to 1 if you have the declaration of `tzname', and to 0 if you don't. -+/* Define to 1 if you have the declaration of 'tzname', and to 0 if you don't. - */ - #undef HAVE_DECL_TZNAME - -@@ -279,26 +279,29 @@ - /* Define to 1 if the dirent structure has a d_type field */ - #undef HAVE_DIRENT_D_TYPE - --/* Define to 1 if you have the header file, and it defines `DIR'. -+/* Define to 1 if you have the header file, and it defines 'DIR'. - */ - #undef HAVE_DIRENT_H - - /* Define if you have the 'dirfd' function or macro. */ - #undef HAVE_DIRFD - -+/* Define to 1 if you have the 'dladdr' function. */ -+#undef HAVE_DLADDR -+ - /* Define to 1 if you have the header file. */ - #undef HAVE_DLFCN_H - --/* Define to 1 if you have the `dlopen' function. */ -+/* Define to 1 if you have the 'dlopen' function. */ - #undef HAVE_DLOPEN - --/* Define to 1 if you have the `dup' function. */ -+/* Define to 1 if you have the 'dup' function. */ - #undef HAVE_DUP - --/* Define to 1 if you have the `dup2' function. */ -+/* Define to 1 if you have the 'dup2' function. */ - #undef HAVE_DUP2 - --/* Define to 1 if you have the `dup3' function. */ -+/* Define to 1 if you have the 'dup3' function. */ - #undef HAVE_DUP3 - - /* Define if you have the '_dyld_shared_cache_contains_path' function. */ -@@ -319,10 +322,10 @@ - /* Define if you have the 'epoll_create1' function. */ - #undef HAVE_EPOLL_CREATE1 - --/* Define to 1 if you have the `erf' function. */ -+/* Define to 1 if you have the 'erf' function. */ - #undef HAVE_ERF - --/* Define to 1 if you have the `erfc' function. */ -+/* Define to 1 if you have the 'erfc' function. */ - #undef HAVE_ERFC - - /* Define to 1 if you have the header file. */ -@@ -331,34 +334,34 @@ - /* Define if you have the 'eventfd' function. */ - #undef HAVE_EVENTFD - --/* Define to 1 if you have the `execv' function. */ -+/* Define to 1 if you have the 'execv' function. */ - #undef HAVE_EXECV - --/* Define to 1 if you have the `explicit_bzero' function. */ -+/* Define to 1 if you have the 'explicit_bzero' function. */ - #undef HAVE_EXPLICIT_BZERO - --/* Define to 1 if you have the `explicit_memset' function. */ -+/* Define to 1 if you have the 'explicit_memset' function. */ - #undef HAVE_EXPLICIT_MEMSET - --/* Define to 1 if you have the `expm1' function. */ -+/* Define to 1 if you have the 'expm1' function. */ - #undef HAVE_EXPM1 - --/* Define to 1 if you have the `faccessat' function. */ -+/* Define to 1 if you have the 'faccessat' function. */ - #undef HAVE_FACCESSAT - - /* Define if you have the 'fchdir' function. */ - #undef HAVE_FCHDIR - --/* Define to 1 if you have the `fchmod' function. */ -+/* Define to 1 if you have the 'fchmod' function. */ - #undef HAVE_FCHMOD - --/* Define to 1 if you have the `fchmodat' function. */ -+/* Define to 1 if you have the 'fchmodat' function. */ - #undef HAVE_FCHMODAT - --/* Define to 1 if you have the `fchown' function. */ -+/* Define to 1 if you have the 'fchown' function. */ - #undef HAVE_FCHOWN - --/* Define to 1 if you have the `fchownat' function. */ -+/* Define to 1 if you have the 'fchownat' function. */ - #undef HAVE_FCHOWNAT - - /* Define to 1 if you have the header file. */ -@@ -367,13 +370,13 @@ - /* Define if you have the 'fdatasync' function. */ - #undef HAVE_FDATASYNC - --/* Define to 1 if you have the `fdopendir' function. */ -+/* Define to 1 if you have the 'fdopendir' function. */ - #undef HAVE_FDOPENDIR - --/* Define to 1 if you have the `fdwalk' function. */ -+/* Define to 1 if you have the 'fdwalk' function. */ - #undef HAVE_FDWALK - --/* Define to 1 if you have the `fexecve' function. */ -+/* Define to 1 if you have the 'fexecve' function. */ - #undef HAVE_FEXECVE - - /* Define if you have the 'ffi_closure_alloc' function. */ -@@ -385,58 +388,58 @@ - /* Define if you have the 'ffi_prep_closure_loc' function. */ - #undef HAVE_FFI_PREP_CLOSURE_LOC - --/* Define to 1 if you have the `flock' function. */ -+/* Define to 1 if you have the 'flock' function. */ - #undef HAVE_FLOCK - --/* Define to 1 if you have the `fork' function. */ -+/* Define to 1 if you have the 'fork' function. */ - #undef HAVE_FORK - --/* Define to 1 if you have the `fork1' function. */ -+/* Define to 1 if you have the 'fork1' function. */ - #undef HAVE_FORK1 - --/* Define to 1 if you have the `forkpty' function. */ -+/* Define to 1 if you have the 'forkpty' function. */ - #undef HAVE_FORKPTY - --/* Define to 1 if you have the `fpathconf' function. */ -+/* Define to 1 if you have the 'fpathconf' function. */ - #undef HAVE_FPATHCONF - --/* Define to 1 if you have the `fseek64' function. */ -+/* Define to 1 if you have the 'fseek64' function. */ - #undef HAVE_FSEEK64 - --/* Define to 1 if you have the `fseeko' function. */ -+/* Define to 1 if you have the 'fseeko' function. */ - #undef HAVE_FSEEKO - --/* Define to 1 if you have the `fstatat' function. */ -+/* Define to 1 if you have the 'fstatat' function. */ - #undef HAVE_FSTATAT - --/* Define to 1 if you have the `fstatvfs' function. */ -+/* Define to 1 if you have the 'fstatvfs' function. */ - #undef HAVE_FSTATVFS - - /* Define if you have the 'fsync' function. */ - #undef HAVE_FSYNC - --/* Define to 1 if you have the `ftell64' function. */ -+/* Define to 1 if you have the 'ftell64' function. */ - #undef HAVE_FTELL64 - --/* Define to 1 if you have the `ftello' function. */ -+/* Define to 1 if you have the 'ftello' function. */ - #undef HAVE_FTELLO - --/* Define to 1 if you have the `ftime' function. */ -+/* Define to 1 if you have the 'ftime' function. */ - #undef HAVE_FTIME - --/* Define to 1 if you have the `ftruncate' function. */ -+/* Define to 1 if you have the 'ftruncate' function. */ - #undef HAVE_FTRUNCATE - --/* Define to 1 if you have the `futimens' function. */ -+/* Define to 1 if you have the 'futimens' function. */ - #undef HAVE_FUTIMENS - --/* Define to 1 if you have the `futimes' function. */ -+/* Define to 1 if you have the 'futimes' function. */ - #undef HAVE_FUTIMES - --/* Define to 1 if you have the `futimesat' function. */ -+/* Define to 1 if you have the 'futimesat' function. */ - #undef HAVE_FUTIMESAT - --/* Define to 1 if you have the `gai_strerror' function. */ -+/* Define to 1 if you have the 'gai_strerror' function. */ - #undef HAVE_GAI_STRERROR - - /* Define if we can use gcc inline assembler to get and set mc68881 fpcr */ -@@ -467,40 +470,40 @@ - /* Define this if you have flockfile(), getc_unlocked(), and funlockfile() */ - #undef HAVE_GETC_UNLOCKED - --/* Define to 1 if you have the `getegid' function. */ -+/* Define to 1 if you have the 'getegid' function. */ - #undef HAVE_GETEGID - --/* Define to 1 if you have the `getentropy' function. */ -+/* Define to 1 if you have the 'getentropy' function. */ - #undef HAVE_GETENTROPY - --/* Define to 1 if you have the `geteuid' function. */ -+/* Define to 1 if you have the 'geteuid' function. */ - #undef HAVE_GETEUID - --/* Define to 1 if you have the `getgid' function. */ -+/* Define to 1 if you have the 'getgid' function. */ - #undef HAVE_GETGID - --/* Define to 1 if you have the `getgrent' function. */ -+/* Define to 1 if you have the 'getgrent' function. */ - #undef HAVE_GETGRENT - --/* Define to 1 if you have the `getgrgid' function. */ -+/* Define to 1 if you have the 'getgrgid' function. */ - #undef HAVE_GETGRGID - --/* Define to 1 if you have the `getgrgid_r' function. */ -+/* Define to 1 if you have the 'getgrgid_r' function. */ - #undef HAVE_GETGRGID_R - --/* Define to 1 if you have the `getgrnam_r' function. */ -+/* Define to 1 if you have the 'getgrnam_r' function. */ - #undef HAVE_GETGRNAM_R - --/* Define to 1 if you have the `getgrouplist' function. */ -+/* Define to 1 if you have the 'getgrouplist' function. */ - #undef HAVE_GETGROUPLIST - --/* Define to 1 if you have the `getgroups' function. */ -+/* Define to 1 if you have the 'getgroups' function. */ - #undef HAVE_GETGROUPS - - /* Define if you have the 'gethostbyaddr' function. */ - #undef HAVE_GETHOSTBYADDR - --/* Define to 1 if you have the `gethostbyname' function. */ -+/* Define to 1 if you have the 'gethostbyname' function. */ - #undef HAVE_GETHOSTBYNAME - - /* Define this if you have some version of gethostbyname_r() */ -@@ -515,19 +518,19 @@ - /* Define this if you have the 6-arg version of gethostbyname_r(). */ - #undef HAVE_GETHOSTBYNAME_R_6_ARG - --/* Define to 1 if you have the `gethostname' function. */ -+/* Define to 1 if you have the 'gethostname' function. */ - #undef HAVE_GETHOSTNAME - --/* Define to 1 if you have the `getitimer' function. */ -+/* Define to 1 if you have the 'getitimer' function. */ - #undef HAVE_GETITIMER - --/* Define to 1 if you have the `getloadavg' function. */ -+/* Define to 1 if you have the 'getloadavg' function. */ - #undef HAVE_GETLOADAVG - --/* Define to 1 if you have the `getlogin' function. */ -+/* Define to 1 if you have the 'getlogin' function. */ - #undef HAVE_GETLOGIN - --/* Define to 1 if you have the `getnameinfo' function. */ -+/* Define to 1 if you have the 'getnameinfo' function. */ - #undef HAVE_GETNAMEINFO - - /* Define if you have the 'getpagesize' function. */ -@@ -536,34 +539,34 @@ - /* Define if you have the 'getpeername' function. */ - #undef HAVE_GETPEERNAME - --/* Define to 1 if you have the `getpgid' function. */ -+/* Define to 1 if you have the 'getpgid' function. */ - #undef HAVE_GETPGID - --/* Define to 1 if you have the `getpgrp' function. */ -+/* Define to 1 if you have the 'getpgrp' function. */ - #undef HAVE_GETPGRP - --/* Define to 1 if you have the `getpid' function. */ -+/* Define to 1 if you have the 'getpid' function. */ - #undef HAVE_GETPID - --/* Define to 1 if you have the `getppid' function. */ -+/* Define to 1 if you have the 'getppid' function. */ - #undef HAVE_GETPPID - --/* Define to 1 if you have the `getpriority' function. */ -+/* Define to 1 if you have the 'getpriority' function. */ - #undef HAVE_GETPRIORITY - - /* Define if you have the 'getprotobyname' function. */ - #undef HAVE_GETPROTOBYNAME - --/* Define to 1 if you have the `getpwent' function. */ -+/* Define to 1 if you have the 'getpwent' function. */ - #undef HAVE_GETPWENT - --/* Define to 1 if you have the `getpwnam_r' function. */ -+/* Define to 1 if you have the 'getpwnam_r' function. */ - #undef HAVE_GETPWNAM_R - --/* Define to 1 if you have the `getpwuid' function. */ -+/* Define to 1 if you have the 'getpwuid' function. */ - #undef HAVE_GETPWUID - --/* Define to 1 if you have the `getpwuid_r' function. */ -+/* Define to 1 if you have the 'getpwuid_r' function. */ - #undef HAVE_GETPWUID_R - - /* Define to 1 if the getrandom() function is available */ -@@ -572,13 +575,13 @@ - /* Define to 1 if the Linux getrandom() syscall is available */ - #undef HAVE_GETRANDOM_SYSCALL - --/* Define to 1 if you have the `getresgid' function. */ -+/* Define to 1 if you have the 'getresgid' function. */ - #undef HAVE_GETRESGID - --/* Define to 1 if you have the `getresuid' function. */ -+/* Define to 1 if you have the 'getresuid' function. */ - #undef HAVE_GETRESUID - --/* Define to 1 if you have the `getrusage' function. */ -+/* Define to 1 if you have the 'getrusage' function. */ - #undef HAVE_GETRUSAGE - - /* Define if you have the 'getservbyname' function. */ -@@ -587,29 +590,29 @@ - /* Define if you have the 'getservbyport' function. */ - #undef HAVE_GETSERVBYPORT - --/* Define to 1 if you have the `getsid' function. */ -+/* Define to 1 if you have the 'getsid' function. */ - #undef HAVE_GETSID - - /* Define if you have the 'getsockname' function. */ - #undef HAVE_GETSOCKNAME - --/* Define to 1 if you have the `getspent' function. */ -+/* Define to 1 if you have the 'getspent' function. */ - #undef HAVE_GETSPENT - --/* Define to 1 if you have the `getspnam' function. */ -+/* Define to 1 if you have the 'getspnam' function. */ - #undef HAVE_GETSPNAM - --/* Define to 1 if you have the `getuid' function. */ -+/* Define to 1 if you have the 'getuid' function. */ - #undef HAVE_GETUID - --/* Define to 1 if you have the `getwd' function. */ -+/* Define to 1 if you have the 'getwd' function. */ - #undef HAVE_GETWD - - /* Define if glibc has incorrect _FORTIFY_SOURCE wrappers for memmove and - bcopy. */ - #undef HAVE_GLIBC_MEMMOVE_BUG - --/* Define to 1 if you have the `grantpt' function. */ -+/* Define to 1 if you have the 'grantpt' function. */ - #undef HAVE_GRANTPT - - /* Define to 1 if you have the header file. */ -@@ -621,7 +624,7 @@ - /* Define this if you have le64toh() */ - #undef HAVE_HTOLE64 - --/* Define to 1 if you have the `if_nameindex' function. */ -+/* Define to 1 if you have the 'if_nameindex' function. */ - #undef HAVE_IF_NAMEINDEX - - /* Define if you have the 'inet_aton' function. */ -@@ -633,7 +636,7 @@ - /* Define if you have the 'inet_pton' function. */ - #undef HAVE_INET_PTON - --/* Define to 1 if you have the `initgroups' function. */ -+/* Define to 1 if you have the 'initgroups' function. */ - #undef HAVE_INITGROUPS - - /* Define to 1 if you have the header file. */ -@@ -645,10 +648,10 @@ - /* Define if gcc has the ipa-pure-const bug. */ - #undef HAVE_IPA_PURE_CONST_BUG - --/* Define to 1 if you have the `kill' function. */ -+/* Define to 1 if you have the 'kill' function. */ - #undef HAVE_KILL - --/* Define to 1 if you have the `killpg' function. */ -+/* Define to 1 if you have the 'killpg' function. */ - #undef HAVE_KILLPG - - /* Define if you have the 'kqueue' function. */ -@@ -666,31 +669,31 @@ - /* Define to 1 if you have the 'lchflags' function. */ - #undef HAVE_LCHFLAGS - --/* Define to 1 if you have the `lchmod' function. */ -+/* Define to 1 if you have the 'lchmod' function. */ - #undef HAVE_LCHMOD - --/* Define to 1 if you have the `lchown' function. */ -+/* Define to 1 if you have the 'lchown' function. */ - #undef HAVE_LCHOWN - - /* Define to 1 if you have the `db' library (-ldb). */ - #undef HAVE_LIBDB - --/* Define to 1 if you have the `dl' library (-ldl). */ -+/* Define to 1 if you have the 'dl' library (-ldl). */ - #undef HAVE_LIBDL - --/* Define to 1 if you have the `dld' library (-ldld). */ -+/* Define to 1 if you have the 'dld' library (-ldld). */ - #undef HAVE_LIBDLD - --/* Define to 1 if you have the `ieee' library (-lieee). */ -+/* Define to 1 if you have the 'ieee' library (-lieee). */ - #undef HAVE_LIBIEEE - - /* Define to 1 if you have the header file. */ - #undef HAVE_LIBINTL_H - --/* Define to 1 if you have the `sendfile' library (-lsendfile). */ -+/* Define to 1 if you have the 'sendfile' library (-lsendfile). */ - #undef HAVE_LIBSENDFILE - --/* Define to 1 if you have the `sqlite3' library (-lsqlite3). */ -+/* Define to 1 if you have the 'sqlite3' library (-lsqlite3). */ - #undef HAVE_LIBSQLITE3 - - /* Define to 1 if you have the header file. */ -@@ -699,7 +702,7 @@ - /* Define if you have the 'link' function. */ - #undef HAVE_LINK - --/* Define to 1 if you have the `linkat' function. */ -+/* Define to 1 if you have the 'linkat' function. */ - #undef HAVE_LINKAT - - /* Define to 1 if you have the header file. */ -@@ -744,6 +747,9 @@ - /* Define to 1 if you have the header file. */ - #undef HAVE_LINUX_RANDOM_H - -+/* Define to 1 if you have the header file. */ -+#undef HAVE_LINUX_SCHED_H -+ - /* Define to 1 if you have the header file. */ - #undef HAVE_LINUX_SOUNDCARD_H - -@@ -759,73 +765,73 @@ - /* Define if you have the 'listen' function. */ - #undef HAVE_LISTEN - --/* Define to 1 if you have the `lockf' function. */ -+/* Define to 1 if you have the 'lockf' function. */ - #undef HAVE_LOCKF - --/* Define to 1 if you have the `log1p' function. */ -+/* Define to 1 if you have the 'log1p' function. */ - #undef HAVE_LOG1P - --/* Define to 1 if you have the `log2' function. */ -+/* Define to 1 if you have the 'log2' function. */ - #undef HAVE_LOG2 - - /* Define to 1 if you have the `login_tty' function. */ - #undef HAVE_LOGIN_TTY - --/* Define to 1 if the system has the type `long double'. */ -+/* Define to 1 if the system has the type 'long double'. */ - #undef HAVE_LONG_DOUBLE - --/* Define to 1 if you have the `lstat' function. */ -+/* Define to 1 if you have the 'lstat' function. */ - #undef HAVE_LSTAT - --/* Define to 1 if you have the `lutimes' function. */ -+/* Define to 1 if you have the 'lutimes' function. */ - #undef HAVE_LUTIMES - - /* Define to 1 if you have the header file. */ - #undef HAVE_LZMA_H - --/* Define to 1 if you have the `madvise' function. */ -+/* Define to 1 if you have the 'madvise' function. */ - #undef HAVE_MADVISE - - /* Define this if you have the makedev macro. */ - #undef HAVE_MAKEDEV - --/* Define to 1 if you have the `mbrtowc' function. */ -+/* Define to 1 if you have the 'mbrtowc' function. */ - #undef HAVE_MBRTOWC - - /* Define if you have the 'memfd_create' function. */ - #undef HAVE_MEMFD_CREATE - --/* Define to 1 if you have the `memrchr' function. */ -+/* Define to 1 if you have the 'memrchr' function. */ - #undef HAVE_MEMRCHR - - /* Define to 1 if you have the header file. */ - #undef HAVE_MINIX_CONFIG_H - --/* Define to 1 if you have the `mkdirat' function. */ -+/* Define to 1 if you have the 'mkdirat' function. */ - #undef HAVE_MKDIRAT - --/* Define to 1 if you have the `mkfifo' function. */ -+/* Define to 1 if you have the 'mkfifo' function. */ - #undef HAVE_MKFIFO - --/* Define to 1 if you have the `mkfifoat' function. */ -+/* Define to 1 if you have the 'mkfifoat' function. */ - #undef HAVE_MKFIFOAT - --/* Define to 1 if you have the `mknod' function. */ -+/* Define to 1 if you have the 'mknod' function. */ - #undef HAVE_MKNOD - --/* Define to 1 if you have the `mknodat' function. */ -+/* Define to 1 if you have the 'mknodat' function. */ - #undef HAVE_MKNODAT - --/* Define to 1 if you have the `mktime' function. */ -+/* Define to 1 if you have the 'mktime' function. */ - #undef HAVE_MKTIME - --/* Define to 1 if you have the `mmap' function. */ -+/* Define to 1 if you have the 'mmap' function. */ - #undef HAVE_MMAP - --/* Define to 1 if you have the `mremap' function. */ -+/* Define to 1 if you have the 'mremap' function. */ - #undef HAVE_MREMAP - --/* Define to 1 if you have the `nanosleep' function. */ -+/* Define to 1 if you have the 'nanosleep' function. */ - #undef HAVE_NANOSLEEP - - /* Define if you have the 'ncurses' library */ -@@ -858,7 +864,7 @@ - /* Define to 1 if you have the header file. */ - #undef HAVE_NDBM_H - --/* Define to 1 if you have the header file, and it defines `DIR'. */ -+/* Define to 1 if you have the header file, and it defines 'DIR'. */ - #undef HAVE_NDIR_H - - /* Define to 1 if you have the header file. */ -@@ -882,20 +888,20 @@ - /* Define to 1 if you have the header file. */ - #undef HAVE_NET_IF_H - --/* Define to 1 if you have the `nice' function. */ -+/* Define to 1 if you have the 'nice' function. */ - #undef HAVE_NICE - - /* Define if the internal form of wchar_t in non-Unicode locales is not - Unicode. */ - #undef HAVE_NON_UNICODE_WCHAR_T_REPRESENTATION - --/* Define to 1 if you have the `openat' function. */ -+/* Define to 1 if you have the 'openat' function. */ - #undef HAVE_OPENAT - --/* Define to 1 if you have the `opendir' function. */ -+/* Define to 1 if you have the 'opendir' function. */ - #undef HAVE_OPENDIR - --/* Define to 1 if you have the `openpty' function. */ -+/* Define to 1 if you have the 'openpty' function. */ - #undef HAVE_OPENPTY - - /* Define if you have the 'panel' library */ -@@ -907,53 +913,53 @@ - /* Define to 1 if you have the header file. */ - #undef HAVE_PANEL_H - --/* Define to 1 if you have the `pathconf' function. */ -+/* Define to 1 if you have the 'pathconf' function. */ - #undef HAVE_PATHCONF - --/* Define to 1 if you have the `pause' function. */ -+/* Define to 1 if you have the 'pause' function. */ - #undef HAVE_PAUSE - --/* Define to 1 if you have the `pipe' function. */ -+/* Define to 1 if you have the 'pipe' function. */ - #undef HAVE_PIPE - --/* Define to 1 if you have the `pipe2' function. */ -+/* Define to 1 if you have the 'pipe2' function. */ - #undef HAVE_PIPE2 - --/* Define to 1 if you have the `plock' function. */ -+/* Define to 1 if you have the 'plock' function. */ - #undef HAVE_PLOCK - --/* Define to 1 if you have the `poll' function. */ -+/* Define to 1 if you have the 'poll' function. */ - #undef HAVE_POLL - - /* Define to 1 if you have the header file. */ - #undef HAVE_POLL_H - --/* Define to 1 if you have the `posix_fadvise' function. */ -+/* Define to 1 if you have the 'posix_fadvise' function. */ - #undef HAVE_POSIX_FADVISE - --/* Define to 1 if you have the `posix_fallocate' function. */ -+/* Define to 1 if you have the 'posix_fallocate' function. */ - #undef HAVE_POSIX_FALLOCATE - --/* Define to 1 if you have the `posix_openpt' function. */ -+/* Define to 1 if you have the 'posix_openpt' function. */ - #undef HAVE_POSIX_OPENPT - --/* Define to 1 if you have the `posix_spawn' function. */ -+/* Define to 1 if you have the 'posix_spawn' function. */ - #undef HAVE_POSIX_SPAWN - --/* Define to 1 if you have the `posix_spawnp' function. */ -+/* Define to 1 if you have the 'posix_spawnp' function. */ - #undef HAVE_POSIX_SPAWNP - --/* Define to 1 if you have the `posix_spawn_file_actions_addclosefrom_np' -+/* Define to 1 if you have the 'posix_spawn_file_actions_addclosefrom_np' - function. */ - #undef HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP - --/* Define to 1 if you have the `pread' function. */ -+/* Define to 1 if you have the 'pread' function. */ - #undef HAVE_PREAD - --/* Define to 1 if you have the `preadv' function. */ -+/* Define to 1 if you have the 'preadv' function. */ - #undef HAVE_PREADV - --/* Define to 1 if you have the `preadv2' function. */ -+/* Define to 1 if you have the 'preadv2' function. */ - #undef HAVE_PREADV2 - - /* Define if you have the 'prlimit' function. */ -@@ -962,83 +968,83 @@ - /* Define to 1 if you have the header file. */ - #undef HAVE_PROCESS_H - --/* Define to 1 if you have the `process_vm_readv' function. */ -+/* Define to 1 if you have the 'process_vm_readv' function. */ - #undef HAVE_PROCESS_VM_READV - - /* Define if your compiler supports function prototype */ - #undef HAVE_PROTOTYPES - --/* Define to 1 if you have the `pthread_condattr_setclock' function. */ -+/* Define to 1 if you have the 'pthread_condattr_setclock' function. */ - #undef HAVE_PTHREAD_CONDATTR_SETCLOCK - --/* Define to 1 if you have the `pthread_cond_timedwait_relative_np' function. -+/* Define to 1 if you have the 'pthread_cond_timedwait_relative_np' function. - */ - #undef HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP - - /* Defined for Solaris 2.6 bug in pthread header. */ - #undef HAVE_PTHREAD_DESTRUCTOR - --/* Define to 1 if you have the `pthread_getcpuclockid' function. */ -+/* Define to 1 if you have the 'pthread_getcpuclockid' function. */ - #undef HAVE_PTHREAD_GETCPUCLOCKID - --/* Define to 1 if you have the `pthread_getname_np' function. */ -+/* Define to 1 if you have the 'pthread_getname_np' function. */ - #undef HAVE_PTHREAD_GETNAME_NP - - /* Define to 1 if you have the header file. */ - #undef HAVE_PTHREAD_H - --/* Define to 1 if you have the `pthread_init' function. */ -+/* Define to 1 if you have the 'pthread_init' function. */ - #undef HAVE_PTHREAD_INIT - --/* Define to 1 if you have the `pthread_kill' function. */ -+/* Define to 1 if you have the 'pthread_kill' function. */ - #undef HAVE_PTHREAD_KILL - --/* Define to 1 if you have the `pthread_setname_np' function. */ -+/* Define to 1 if you have the 'pthread_setname_np' function. */ - #undef HAVE_PTHREAD_SETNAME_NP - --/* Define to 1 if you have the `pthread_sigmask' function. */ -+/* Define to 1 if you have the 'pthread_sigmask' function. */ - #undef HAVE_PTHREAD_SIGMASK - - /* Define if platform requires stubbed pthreads support */ - #undef HAVE_PTHREAD_STUBS - --/* Define to 1 if you have the `ptsname' function. */ -+/* Define to 1 if you have the 'ptsname' function. */ - #undef HAVE_PTSNAME - --/* Define to 1 if you have the `ptsname_r' function. */ -+/* Define to 1 if you have the 'ptsname_r' function. */ - #undef HAVE_PTSNAME_R - - /* Define to 1 if you have the header file. */ - #undef HAVE_PTY_H - --/* Define to 1 if you have the `pwrite' function. */ -+/* Define to 1 if you have the 'pwrite' function. */ - #undef HAVE_PWRITE - --/* Define to 1 if you have the `pwritev' function. */ -+/* Define to 1 if you have the 'pwritev' function. */ - #undef HAVE_PWRITEV - --/* Define to 1 if you have the `pwritev2' function. */ -+/* Define to 1 if you have the 'pwritev2' function. */ - #undef HAVE_PWRITEV2 - - /* Define to 1 if you have the header file. */ - #undef HAVE_READLINE_READLINE_H - --/* Define to 1 if you have the `readlink' function. */ -+/* Define to 1 if you have the 'readlink' function. */ - #undef HAVE_READLINK - --/* Define to 1 if you have the `readlinkat' function. */ -+/* Define to 1 if you have the 'readlinkat' function. */ - #undef HAVE_READLINKAT - --/* Define to 1 if you have the `readv' function. */ -+/* Define to 1 if you have the 'readv' function. */ - #undef HAVE_READV - --/* Define to 1 if you have the `realpath' function. */ -+/* Define to 1 if you have the 'realpath' function. */ - #undef HAVE_REALPATH - - /* Define if you have the 'recvfrom' function. */ - #undef HAVE_RECVFROM - --/* Define to 1 if you have the `renameat' function. */ -+/* Define to 1 if you have the 'renameat' function. */ - #undef HAVE_RENAMEAT - - /* Define if readline supports append_history */ -@@ -1047,7 +1053,7 @@ - /* Define if you can turn off readline's signal handling. */ - #undef HAVE_RL_CATCH_SIGNAL - --/* Define to 1 if the system has the type `rl_compdisp_func_t'. */ -+/* Define to 1 if the system has the type 'rl_compdisp_func_t'. */ - #undef HAVE_RL_COMPDISP_FUNC_T - - /* Define if you have readline 2.2 */ -@@ -1068,154 +1074,154 @@ - /* Define if you have readline 4.0 */ - #undef HAVE_RL_RESIZE_TERMINAL - --/* Define to 1 if you have the `rtpSpawn' function. */ -+/* Define to 1 if you have the 'rtpSpawn' function. */ - #undef HAVE_RTPSPAWN - --/* Define to 1 if you have the `sched_get_priority_max' function. */ -+/* Define to 1 if you have the 'sched_get_priority_max' function. */ - #undef HAVE_SCHED_GET_PRIORITY_MAX - - /* Define to 1 if you have the header file. */ - #undef HAVE_SCHED_H - --/* Define to 1 if you have the `sched_rr_get_interval' function. */ -+/* Define to 1 if you have the 'sched_rr_get_interval' function. */ - #undef HAVE_SCHED_RR_GET_INTERVAL - --/* Define to 1 if you have the `sched_setaffinity' function. */ -+/* Define to 1 if you have the 'sched_setaffinity' function. */ - #undef HAVE_SCHED_SETAFFINITY - --/* Define to 1 if you have the `sched_setparam' function. */ -+/* Define to 1 if you have the 'sched_setparam' function. */ - #undef HAVE_SCHED_SETPARAM - --/* Define to 1 if you have the `sched_setscheduler' function. */ -+/* Define to 1 if you have the 'sched_setscheduler' function. */ - #undef HAVE_SCHED_SETSCHEDULER - --/* Define to 1 if you have the `sem_clockwait' function. */ -+/* Define to 1 if you have the 'sem_clockwait' function. */ - #undef HAVE_SEM_CLOCKWAIT - --/* Define to 1 if you have the `sem_getvalue' function. */ -+/* Define to 1 if you have the 'sem_getvalue' function. */ - #undef HAVE_SEM_GETVALUE - --/* Define to 1 if you have the `sem_open' function. */ -+/* Define to 1 if you have the 'sem_open' function. */ - #undef HAVE_SEM_OPEN - --/* Define to 1 if you have the `sem_timedwait' function. */ -+/* Define to 1 if you have the 'sem_timedwait' function. */ - #undef HAVE_SEM_TIMEDWAIT - --/* Define to 1 if you have the `sem_unlink' function. */ -+/* Define to 1 if you have the 'sem_unlink' function. */ - #undef HAVE_SEM_UNLINK - --/* Define to 1 if you have the `sendfile' function. */ -+/* Define to 1 if you have the 'sendfile' function. */ - #undef HAVE_SENDFILE - - /* Define if you have the 'sendto' function. */ - #undef HAVE_SENDTO - --/* Define to 1 if you have the `setegid' function. */ -+/* Define to 1 if you have the 'setegid' function. */ - #undef HAVE_SETEGID - --/* Define to 1 if you have the `seteuid' function. */ -+/* Define to 1 if you have the 'seteuid' function. */ - #undef HAVE_SETEUID - --/* Define to 1 if you have the `setgid' function. */ -+/* Define to 1 if you have the 'setgid' function. */ - #undef HAVE_SETGID - - /* Define if you have the 'setgroups' function. */ - #undef HAVE_SETGROUPS - --/* Define to 1 if you have the `sethostname' function. */ -+/* Define to 1 if you have the 'sethostname' function. */ - #undef HAVE_SETHOSTNAME - --/* Define to 1 if you have the `setitimer' function. */ -+/* Define to 1 if you have the 'setitimer' function. */ - #undef HAVE_SETITIMER - - /* Define to 1 if you have the header file. */ - #undef HAVE_SETJMP_H - --/* Define to 1 if you have the `setlocale' function. */ -+/* Define to 1 if you have the 'setlocale' function. */ - #undef HAVE_SETLOCALE - --/* Define to 1 if you have the `setns' function. */ -+/* Define to 1 if you have the 'setns' function. */ - #undef HAVE_SETNS - --/* Define to 1 if you have the `setpgid' function. */ -+/* Define to 1 if you have the 'setpgid' function. */ - #undef HAVE_SETPGID - --/* Define to 1 if you have the `setpgrp' function. */ -+/* Define to 1 if you have the 'setpgrp' function. */ - #undef HAVE_SETPGRP - --/* Define to 1 if you have the `setpriority' function. */ -+/* Define to 1 if you have the 'setpriority' function. */ - #undef HAVE_SETPRIORITY - --/* Define to 1 if you have the `setregid' function. */ -+/* Define to 1 if you have the 'setregid' function. */ - #undef HAVE_SETREGID - --/* Define to 1 if you have the `setresgid' function. */ -+/* Define to 1 if you have the 'setresgid' function. */ - #undef HAVE_SETRESGID - --/* Define to 1 if you have the `setresuid' function. */ -+/* Define to 1 if you have the 'setresuid' function. */ - #undef HAVE_SETRESUID - --/* Define to 1 if you have the `setreuid' function. */ -+/* Define to 1 if you have the 'setreuid' function. */ - #undef HAVE_SETREUID - --/* Define to 1 if you have the `setsid' function. */ -+/* Define to 1 if you have the 'setsid' function. */ - #undef HAVE_SETSID - - /* Define if you have the 'setsockopt' function. */ - #undef HAVE_SETSOCKOPT - --/* Define to 1 if you have the `setuid' function. */ -+/* Define to 1 if you have the 'setuid' function. */ - #undef HAVE_SETUID - --/* Define to 1 if you have the `setvbuf' function. */ -+/* Define to 1 if you have the 'setvbuf' function. */ - #undef HAVE_SETVBUF - - /* Define to 1 if you have the header file. */ - #undef HAVE_SHADOW_H - --/* Define to 1 if you have the `shm_open' function. */ -+/* Define to 1 if you have the 'shm_open' function. */ - #undef HAVE_SHM_OPEN - --/* Define to 1 if you have the `shm_unlink' function. */ -+/* Define to 1 if you have the 'shm_unlink' function. */ - #undef HAVE_SHM_UNLINK - --/* Define to 1 if you have the `shutdown' function. */ -+/* Define to 1 if you have the 'shutdown' function. */ - #undef HAVE_SHUTDOWN - --/* Define to 1 if you have the `sigaction' function. */ -+/* Define to 1 if you have the 'sigaction' function. */ - #undef HAVE_SIGACTION - --/* Define to 1 if you have the `sigaltstack' function. */ -+/* Define to 1 if you have the 'sigaltstack' function. */ - #undef HAVE_SIGALTSTACK - --/* Define to 1 if you have the `sigfillset' function. */ -+/* Define to 1 if you have the 'sigfillset' function. */ - #undef HAVE_SIGFILLSET - --/* Define to 1 if `si_band' is a member of `siginfo_t'. */ -+/* Define to 1 if 'si_band' is a member of 'siginfo_t'. */ - #undef HAVE_SIGINFO_T_SI_BAND - --/* Define to 1 if you have the `siginterrupt' function. */ -+/* Define to 1 if you have the 'siginterrupt' function. */ - #undef HAVE_SIGINTERRUPT - - /* Define to 1 if you have the header file. */ - #undef HAVE_SIGNAL_H - --/* Define to 1 if you have the `sigpending' function. */ -+/* Define to 1 if you have the 'sigpending' function. */ - #undef HAVE_SIGPENDING - --/* Define to 1 if you have the `sigrelse' function. */ -+/* Define to 1 if you have the 'sigrelse' function. */ - #undef HAVE_SIGRELSE - --/* Define to 1 if you have the `sigtimedwait' function. */ -+/* Define to 1 if you have the 'sigtimedwait' function. */ - #undef HAVE_SIGTIMEDWAIT - --/* Define to 1 if you have the `sigwait' function. */ -+/* Define to 1 if you have the 'sigwait' function. */ - #undef HAVE_SIGWAIT - --/* Define to 1 if you have the `sigwaitinfo' function. */ -+/* Define to 1 if you have the 'sigwaitinfo' function. */ - #undef HAVE_SIGWAITINFO - --/* Define to 1 if you have the `snprintf' function. */ -+/* Define to 1 if you have the 'snprintf' function. */ - #undef HAVE_SNPRINTF ++ # TVOS_DEPLOYMENT_TARGET is the minimum supported tvOS version ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking tvOS deployment target" >&5 ++printf %s "checking tvOS deployment target... " >&6; } ++ TVOS_DEPLOYMENT_TARGET=${_host_os:4} ++ TVOS_DEPLOYMENT_TARGET=${TVOS_DEPLOYMENT_TARGET:=12.0} ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $TVOS_DEPLOYMENT_TARGET" >&5 ++printf "%s\n" "$TVOS_DEPLOYMENT_TARGET" >&6; } ++ ++ case "$host_cpu" in ++ aarch64) ++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-arm64-appletv${_host_device} ++ ;; ++ *) ++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-$host_cpu-appletv${_host_device} ++ ;; ++ esac ++ ;; ++ *-apple-watchos*) ++ _host_os=`echo $host | cut -d '-' -f3` ++ _host_device=`echo $host | cut -d '-' -f4` ++ _host_device=${_host_device:=os} ++ ++ # WATCHOS_DEPLOYMENT_TARGET is the minimum supported watchOS version ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking watchOS deployment target" >&5 ++printf %s "checking watchOS deployment target... " >&6; } ++ WATCHOS_DEPLOYMENT_TARGET=${_host_os:7} ++ WATCHOS_DEPLOYMENT_TARGET=${WATCHOS_DEPLOYMENT_TARGET:=4.0} ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $WATCHOS_DEPLOYMENT_TARGET" >&5 ++printf "%s\n" "$WATCHOS_DEPLOYMENT_TARGET" >&6; } ++ ++ case "$host_cpu" in ++ aarch64) ++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-arm64-watch${_host_device} ++ ;; ++ *) ++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-$host_cpu-watch${_host_device} ++ ;; ++ esac ++ ;; + *-*-darwin*) + case "$host_cpu" in + arm*) +@@ -4688,9 +4816,13 @@ + define_xopen_source=no;; + Darwin/[12][0-9].*) + define_xopen_source=no;; +- # On iOS, defining _POSIX_C_SOURCE also disables platform specific features. ++ # On iOS/tvOS/watchOS, defining _POSIX_C_SOURCE also disables platform specific features. + iOS/*) + define_xopen_source=no;; ++ tvOS/*) ++ define_xopen_source=no;; ++ watchOS/*) ++ define_xopen_source=no;; + # On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from + # defining NI_NUMERICHOST. + QNX/6.3.2) +@@ -4753,7 +4885,10 @@ + CONFIGURE_MACOSX_DEPLOYMENT_TARGET= + EXPORT_MACOSX_DEPLOYMENT_TARGET='#' - /* struct sockaddr_alg (linux/if_alg.h) */ -@@ -1233,19 +1239,19 @@ - /* Define if you have the 'socketpair' function. */ - #undef HAVE_SOCKETPAIR +-# Record the value of IPHONEOS_DEPLOYMENT_TARGET enforced by the selected host triple. ++# Record the value of IPHONEOS_DEPLOYMENT_TARGET / TVOS_DEPLOYMENT_TARGET / ++# WATCHOS_DEPLOYMENT_TARGET enforced by the selected host triple. ++ ++ --/* Define to 1 if the system has the type `socklen_t'. */ -+/* Define to 1 if the system has the type 'socklen_t'. */ - #undef HAVE_SOCKLEN_T - /* Define to 1 if you have the header file. */ - #undef HAVE_SPAWN_H + # checks for alternative programs +@@ -4794,6 +4929,16 @@ + as_fn_append CFLAGS " -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}" + as_fn_append LDFLAGS " -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}" + ;; #( ++ tvOS) : ++ ++ as_fn_append CFLAGS " -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}" ++ as_fn_append LDFLAGS " -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}" ++ ;; #( ++ watchOS) : ++ ++ as_fn_append CFLAGS " -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}" ++ as_fn_append LDFLAGS " -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}" ++ ;; #( + *) : + ;; + esac +@@ -7163,6 +7308,10 @@ + MULTIARCH="" ;; #( + iOS) : + MULTIARCH="" ;; #( ++ tvOS) : ++ MULTIARCH="" ;; #( ++ watchOS) : ++ MULTIARCH="" ;; #( + FreeBSD*) : + MULTIARCH="" ;; #( + *) : +@@ -7183,7 +7332,7 @@ + printf "%s\n" "$MULTIARCH" >&6; } --/* Define to 1 if you have the `splice' function. */ -+/* Define to 1 if you have the 'splice' function. */ - #undef HAVE_SPLICE + case $ac_sys_system in #( +- iOS) : ++ iOS|tvOS|watchOS) : + SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f2` ;; #( + *) : + SOABI_PLATFORM=$PLATFORM_TRIPLET +@@ -7234,6 +7383,14 @@ + PY_SUPPORT_TIER=3 ;; #( + aarch64-apple-ios*/clang) : + PY_SUPPORT_TIER=3 ;; #( ++ aarch64-apple-tvos*-simulator/clang) : ++ PY_SUPPORT_TIER=3 ;; #( ++ aarch64-apple-tvos*/clang) : ++ PY_SUPPORT_TIER=3 ;; #( ++ aarch64-apple-watchos*-simulator/clang) : ++ PY_SUPPORT_TIER=3 ;; #( ++ arm64_32-apple-watchos*/clang) : ++ PY_SUPPORT_TIER=3 ;; #( + aarch64-*-linux-android/clang) : + PY_SUPPORT_TIER=3 ;; #( + x86_64-*-linux-android/clang) : +@@ -7670,7 +7827,7 @@ + case $ac_sys_system in + Darwin) + LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)';; +- iOS) ++ iOS|tvOS|watchOS) + LDLIBRARY='$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';; + *) + as_fn_error $? "Unknown platform for framework build" "$LINENO" 5;; +@@ -7736,7 +7893,7 @@ + BLDLIBRARY='-L. -lpython$(LDVERSION)' + RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}} + ;; +- iOS) ++ iOS|tvOS|watchOS) + LDLIBRARY='libpython$(LDVERSION).dylib' + ;; + AIX*) +@@ -9409,21 +9566,11 @@ + fi --/* Define to 1 if the system has the type `ssize_t'. */ -+/* Define to 1 if the system has the type 'ssize_t'. */ - #undef HAVE_SSIZE_T --/* Define to 1 if you have the `statvfs' function. */ -+/* Define to 1 if you have the 'statvfs' function. */ - #undef HAVE_STATVFS +- +-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking BOLT_COMMON_FLAGS" >&5 +-printf %s "checking BOLT_COMMON_FLAGS... " >&6; } +-if test -z "${BOLT_COMMON_FLAGS}" +-then +- BOLT_COMMON_FLAGS=" -update-debug-sections -skip-funcs=_PyEval_EvalFrameDefault,sre_ucs1_match/1,sre_ucs2_match/1,sre_ucs4_match/1 " +- +-fi +- +- + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking BOLT_INSTRUMENT_FLAGS" >&5 + printf %s "checking BOLT_INSTRUMENT_FLAGS... " >&6; } + if test -z "${BOLT_INSTRUMENT_FLAGS}" + then +- BOLT_INSTRUMENT_FLAGS="${BOLT_COMMON_FLAGS}" ++ BOLT_INSTRUMENT_FLAGS= + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $BOLT_INSTRUMENT_FLAGS" >&5 + printf "%s\n" "$BOLT_INSTRUMENT_FLAGS" >&6; } +@@ -9433,7 +9580,7 @@ + printf %s "checking BOLT_APPLY_FLAGS... " >&6; } + if test -z "${BOLT_APPLY_FLAGS}" + then +- BOLT_APPLY_FLAGS=" ${BOLT_COMMON_FLAGS} -reorder-blocks=ext-tsp -reorder-functions=cdsort -split-functions -icf=1 -inline-all -split-eh -reorder-functions-use-hot-size -peepholes=none -jump-tables=aggressive -inline-ap -indirect-call-promotion=all -dyno-stats -use-gnu-stack -frame-opt=hot " ++ BOLT_APPLY_FLAGS=" -update-debug-sections -reorder-blocks=ext-tsp -reorder-functions=hfsort+ -split-functions -icf=1 -inline-all -split-eh -reorder-functions-use-hot-size -peepholes=none -jump-tables=aggressive -inline-ap -indirect-call-promotion=all -dyno-stats -use-gnu-stack -frame-opt=hot " - /* Define if you have struct stat.st_mtim.tv_nsec */ -@@ -1266,7 +1272,7 @@ - /* Has stdatomic.h with atomic_int and atomic_uintptr_t */ - #undef HAVE_STD_ATOMIC + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $BOLT_APPLY_FLAGS" >&5 +@@ -11489,12 +11636,6 @@ + then : + printf "%s\n" "#define HAVE_SYS_PARAM_H 1" >>confdefs.h --/* Define to 1 if you have the `strftime' function. */ -+/* Define to 1 if you have the 'strftime' function. */ - #undef HAVE_STRFTIME +-fi +-ac_fn_c_check_header_compile "$LINENO" "sys/pidfd.h" "ac_cv_header_sys_pidfd_h" "$ac_includes_default" +-if test "x$ac_cv_header_sys_pidfd_h" = xyes +-then : +- printf "%s\n" "#define HAVE_SYS_PIDFD_H 1" >>confdefs.h +- + fi + ac_fn_c_check_header_compile "$LINENO" "sys/poll.h" "ac_cv_header_sys_poll_h" "$ac_includes_default" + if test "x$ac_cv_header_sys_poll_h" = xyes +@@ -13544,7 +13685,7 @@ + BLDSHARED="$LDSHARED" + fi + ;; +- iOS/*) ++ iOS/*|tvOS/*|watchOS/*) + LDSHARED='$(CC) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)' + LDCXXSHARED='$(CXX) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)' + BLDSHARED="$LDSHARED" +@@ -13677,7 +13818,7 @@ + Linux-android*) LINKFORSHARED="-pie -Xlinker -export-dynamic";; + Linux*|GNU*) LINKFORSHARED="-Xlinker -export-dynamic";; + # -u libsys_s pulls in all symbols in libsys +- Darwin/*|iOS/*) ++ Darwin/*|iOS/*|tvOS/*|watchOS/*) + LINKFORSHARED="$extra_undefs -framework CoreFoundation" - /* Define to 1 if you have the header file. */ -@@ -1275,52 +1281,52 @@ - /* Define to 1 if you have the header file. */ - #undef HAVE_STRING_H + # Issue #18075: the default maximum stack size (8MBytes) is too +@@ -13701,7 +13842,7 @@ + LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' + fi + LINKFORSHARED="$LINKFORSHARED" +- elif test $ac_sys_system = "iOS"; then ++ elif test "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "watchOS"; then + LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)' + fi + ;; +@@ -14074,7 +14215,7 @@ --/* Define to 1 if you have the `strlcpy' function. */ -+/* Define to 1 if you have the 'strlcpy' function. */ - #undef HAVE_STRLCPY - /* Define to 1 if you have the header file. */ - #undef HAVE_STROPTS_H + CPPFLAGS="$CPPFLAGS $LIBUUID_CFLAGS" +- LIBS="$LIBS $LIBUUID_LIBS" ++ LDFLAGS="$LDFLAGS $LIBUUID_LIBS" + for ac_header in uuid/uuid.h + do : + ac_fn_c_check_header_compile "$LINENO" "uuid/uuid.h" "ac_cv_header_uuid_uuid_h" "$ac_includes_default" +@@ -14216,7 +14357,7 @@ --/* Define to 1 if you have the `strsignal' function. */ -+/* Define to 1 if you have the 'strsignal' function. */ - #undef HAVE_STRSIGNAL --/* Define to 1 if `pw_gecos' is a member of `struct passwd'. */ -+/* Define to 1 if 'pw_gecos' is a member of 'struct passwd'. */ - #undef HAVE_STRUCT_PASSWD_PW_GECOS + CPPFLAGS="$CPPFLAGS $LIBUUID_CFLAGS" +- LIBS="$LIBS $LIBUUID_LIBS" ++ LDFLAGS="$LDFLAGS $LIBUUID_LIBS" + for ac_header in uuid/uuid.h + do : + ac_fn_c_check_header_compile "$LINENO" "uuid/uuid.h" "ac_cv_header_uuid_uuid_h" "$ac_includes_default" +@@ -15114,7 +15255,7 @@ --/* Define to 1 if `pw_passwd' is a member of `struct passwd'. */ -+/* Define to 1 if 'pw_passwd' is a member of 'struct passwd'. */ - #undef HAVE_STRUCT_PASSWD_PW_PASSWD --/* Define to 1 if `st_birthtime' is a member of `struct stat'. */ -+/* Define to 1 if 'st_birthtime' is a member of 'struct stat'. */ - #undef HAVE_STRUCT_STAT_ST_BIRTHTIME + CPPFLAGS="$CPPFLAGS $LIBFFI_CFLAGS" +- LIBS="$LIBS $LIBFFI_LIBS" ++ LDFLAGS="$LDFLAGS $LIBFFI_LIBS" + ac_fn_c_check_header_compile "$LINENO" "ffi.h" "ac_cv_header_ffi_h" "$ac_includes_default" + if test "x$ac_cv_header_ffi_h" = xyes + then : +@@ -15196,7 +15337,7 @@ --/* Define to 1 if `st_blksize' is a member of `struct stat'. */ -+/* Define to 1 if 'st_blksize' is a member of 'struct stat'. */ - #undef HAVE_STRUCT_STAT_ST_BLKSIZE --/* Define to 1 if `st_blocks' is a member of `struct stat'. */ -+/* Define to 1 if 'st_blocks' is a member of 'struct stat'. */ - #undef HAVE_STRUCT_STAT_ST_BLOCKS + CPPFLAGS="$CPPFLAGS $LIBFFI_CFLAGS" +- LIBS="$LIBS $LIBFFI_LIBS" ++ LDFLAGS="$LDFLAGS $LIBFFI_LIBS" + ac_fn_c_check_header_compile "$LINENO" "ffi.h" "ac_cv_header_ffi_h" "$ac_includes_default" + if test "x$ac_cv_header_ffi_h" = xyes + then : +@@ -15286,7 +15427,7 @@ --/* Define to 1 if `st_flags' is a member of `struct stat'. */ -+/* Define to 1 if 'st_flags' is a member of 'struct stat'. */ - #undef HAVE_STRUCT_STAT_ST_FLAGS + ctypes_malloc_closure=yes + ;; #( +- iOS) : ++ iOS|tvOS|watchOS) : --/* Define to 1 if `st_gen' is a member of `struct stat'. */ -+/* Define to 1 if 'st_gen' is a member of 'struct stat'. */ - #undef HAVE_STRUCT_STAT_ST_GEN + ctypes_malloc_closure=yes + ;; #( +@@ -15316,8 +15457,8 @@ + save_LIBS=$LIBS --/* Define to 1 if `st_rdev' is a member of `struct stat'. */ -+/* Define to 1 if 'st_rdev' is a member of 'struct stat'. */ - #undef HAVE_STRUCT_STAT_ST_RDEV --/* Define to 1 if `tm_zone' is a member of `struct tm'. */ -+/* Define to 1 if 'tm_zone' is a member of 'struct tm'. */ - #undef HAVE_STRUCT_TM_TM_ZONE +- CFLAGS="$CFLAGS $LIBFFI_CFLAGS" +- LIBS="$LIBS $LIBFFI_LIBS" ++ CFLAGS="$LIBFFI_CFLAGS $CFLAGS" ++ LDFLAGS="$LIBFFI_LIBS $LDFLAGS" - /* Define if you have the 'symlink' function. */ - #undef HAVE_SYMLINK --/* Define to 1 if you have the `symlinkat' function. */ -+/* Define to 1 if you have the 'symlinkat' function. */ - #undef HAVE_SYMLINKAT --/* Define to 1 if you have the `sync' function. */ -+/* Define to 1 if you have the 'sync' function. */ - #undef HAVE_SYNC +@@ -15643,8 +15784,8 @@ + save_LIBS=$LIBS --/* Define to 1 if you have the `sysconf' function. */ -+/* Define to 1 if you have the 'sysconf' function. */ - #undef HAVE_SYSCONF - /* Define to 1 if you have the header file. */ -@@ -1329,7 +1335,7 @@ - /* Define to 1 if you have the header file. */ - #undef HAVE_SYSLOG_H +- CPPFLAGS="$CPPFLAGS $LIBMPDEC_CFLAGS" +- LIBS="$LIBS $LIBMPDEC_LIBS" ++ CPPFLAGS="$LIBMPDEC_CFLAGS $CPPFLAGS" ++ LIBS="$LIBMPDEC_LIBS $LIBS" --/* Define to 1 if you have the `system' function. */ -+/* Define to 1 if you have the 'system' function. */ - #undef HAVE_SYSTEM + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ +@@ -15914,7 +16055,7 @@ - /* Define to 1 if you have the header file. */ -@@ -1344,7 +1350,7 @@ - /* Define to 1 if you have the header file. */ - #undef HAVE_SYS_DEVPOLL_H --/* Define to 1 if you have the header file, and it defines `DIR'. -+/* Define to 1 if you have the header file, and it defines 'DIR'. - */ - #undef HAVE_SYS_DIR_H + CPPFLAGS="$CPPFLAGS $LIBSQLITE3_CFLAGS" +- LIBS="$LIBS $LIBSQLITE3_LIBS" ++ LDFLAGS="$LIBSQLITE3_LIBS $LDFLAGS" -@@ -1387,7 +1393,7 @@ - /* Define to 1 if you have the header file. */ - #undef HAVE_SYS_MODEM_H + ac_fn_c_check_header_compile "$LINENO" "sqlite3.h" "ac_cv_header_sqlite3_h" "$ac_includes_default" + if test "x$ac_cv_header_sqlite3_h" = xyes +@@ -16904,7 +17045,7 @@ --/* Define to 1 if you have the header file, and it defines `DIR'. -+/* Define to 1 if you have the header file, and it defines 'DIR'. - */ - #undef HAVE_SYS_NDIR_H -@@ -1463,13 +1469,13 @@ - /* Define to 1 if you have the header file. */ - #undef HAVE_SYS_XATTR_H + CPPFLAGS="$CPPFLAGS $TCLTK_CFLAGS" +- LIBS="$LIBS $TCLTK_LIBS" ++ LIBS="$TCLTK_LIBS $LDFLAGS" --/* Define to 1 if you have the `tcgetpgrp' function. */ -+/* Define to 1 if you have the 'tcgetpgrp' function. */ - #undef HAVE_TCGETPGRP + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ +@@ -16971,7 +17112,7 @@ --/* Define to 1 if you have the `tcsetpgrp' function. */ -+/* Define to 1 if you have the 'tcsetpgrp' function. */ - #undef HAVE_TCSETPGRP --/* Define to 1 if you have the `tempnam' function. */ -+/* Define to 1 if you have the 'tempnam' function. */ - #undef HAVE_TEMPNAM + CPPFLAGS="$CPPFLAGS $GDBM_CFLAGS" +- LIBS="$LIBS $GDBM_LIBS" ++ LDFLAGS="$GDBM_LIBS $LDFLAGS" + for ac_header in gdbm.h + do : + ac_fn_c_check_header_compile "$LINENO" "gdbm.h" "ac_cv_header_gdbm_h" "$ac_includes_default" +@@ -19038,12 +19179,6 @@ + then : + printf "%s\n" "#define HAVE_DUP3 1" >>confdefs.h - /* Define to 1 if you have the header file. */ -@@ -1478,54 +1484,54 @@ - /* Define to 1 if you have the header file. */ - #undef HAVE_TERM_H +-fi +-ac_fn_c_check_func "$LINENO" "execv" "ac_cv_func_execv" +-if test "x$ac_cv_func_execv" = xyes +-then : +- printf "%s\n" "#define HAVE_EXECV 1" >>confdefs.h +- + fi + ac_fn_c_check_func "$LINENO" "explicit_bzero" "ac_cv_func_explicit_bzero" + if test "x$ac_cv_func_explicit_bzero" = xyes +@@ -19104,18 +19239,6 @@ + then : + printf "%s\n" "#define HAVE_FEXECVE 1" >>confdefs.h --/* Define to 1 if you have the `timegm' function. */ -+/* Define to 1 if you have the 'timegm' function. */ - #undef HAVE_TIMEGM +-fi +-ac_fn_c_check_func "$LINENO" "fork" "ac_cv_func_fork" +-if test "x$ac_cv_func_fork" = xyes +-then : +- printf "%s\n" "#define HAVE_FORK 1" >>confdefs.h +- +-fi +-ac_fn_c_check_func "$LINENO" "fork1" "ac_cv_func_fork1" +-if test "x$ac_cv_func_fork1" = xyes +-then : +- printf "%s\n" "#define HAVE_FORK1 1" >>confdefs.h +- + fi + ac_fn_c_check_func "$LINENO" "fpathconf" "ac_cv_func_fpathconf" + if test "x$ac_cv_func_fpathconf" = xyes +@@ -19542,24 +19665,6 @@ + then : + printf "%s\n" "#define HAVE_POSIX_OPENPT 1" >>confdefs.h - /* Define if you have the 'timerfd_create' function. */ - #undef HAVE_TIMERFD_CREATE +-fi +-ac_fn_c_check_func "$LINENO" "posix_spawn" "ac_cv_func_posix_spawn" +-if test "x$ac_cv_func_posix_spawn" = xyes +-then : +- printf "%s\n" "#define HAVE_POSIX_SPAWN 1" >>confdefs.h +- +-fi +-ac_fn_c_check_func "$LINENO" "posix_spawnp" "ac_cv_func_posix_spawnp" +-if test "x$ac_cv_func_posix_spawnp" = xyes +-then : +- printf "%s\n" "#define HAVE_POSIX_SPAWNP 1" >>confdefs.h +- +-fi +-ac_fn_c_check_func "$LINENO" "posix_spawn_file_actions_addclosefrom_np" "ac_cv_func_posix_spawn_file_actions_addclosefrom_np" +-if test "x$ac_cv_func_posix_spawn_file_actions_addclosefrom_np" = xyes +-then : +- printf "%s\n" "#define HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP 1" >>confdefs.h +- + fi + ac_fn_c_check_func "$LINENO" "pread" "ac_cv_func_pread" + if test "x$ac_cv_func_pread" = xyes +@@ -19860,12 +19965,6 @@ + then : + printf "%s\n" "#define HAVE_SIGACTION 1" >>confdefs.h --/* Define to 1 if you have the `times' function. */ -+/* Define to 1 if you have the 'times' function. */ - #undef HAVE_TIMES +-fi +-ac_fn_c_check_func "$LINENO" "sigaltstack" "ac_cv_func_sigaltstack" +-if test "x$ac_cv_func_sigaltstack" = xyes +-then : +- printf "%s\n" "#define HAVE_SIGALTSTACK 1" >>confdefs.h +- + fi + ac_fn_c_check_func "$LINENO" "sigfillset" "ac_cv_func_sigfillset" + if test "x$ac_cv_func_sigfillset" = xyes +@@ -20011,10 +20110,10 @@ + printf "%s\n" "#define HAVE_TRUNCATE 1" >>confdefs.h --/* Define to 1 if you have the `tmpfile' function. */ -+/* Define to 1 if you have the 'tmpfile' function. */ - #undef HAVE_TMPFILE + fi +-ac_fn_c_check_func "$LINENO" "ttyname_r" "ac_cv_func_ttyname_r" +-if test "x$ac_cv_func_ttyname_r" = xyes ++ac_fn_c_check_func "$LINENO" "ttyname" "ac_cv_func_ttyname" ++if test "x$ac_cv_func_ttyname" = xyes + then : +- printf "%s\n" "#define HAVE_TTYNAME_R 1" >>confdefs.h ++ printf "%s\n" "#define HAVE_TTYNAME 1" >>confdefs.h --/* Define to 1 if you have the `tmpnam' function. */ -+/* Define to 1 if you have the 'tmpnam' function. */ - #undef HAVE_TMPNAM + fi + ac_fn_c_check_func "$LINENO" "umask" "ac_cv_func_umask" +@@ -20134,11 +20233,11 @@ --/* Define to 1 if you have the `tmpnam_r' function. */ -+/* Define to 1 if you have the 'tmpnam_r' function. */ - #undef HAVE_TMPNAM_R + fi --/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use -- `HAVE_STRUCT_TM_TM_ZONE' instead. */ -+/* Define to 1 if your 'struct tm' has 'tm_zone'. Deprecated, use -+ 'HAVE_STRUCT_TM_TM_ZONE' instead. */ - #undef HAVE_TM_ZONE +-# iOS defines some system methods that can be linked (so they are ++# iOS/tvOS/watchOS define some system methods that can be linked (so they are + # found by configure), but either raise a compilation error (because the + # header definition prevents usage - autoconf doesn't use the headers), or + # raise an error if used at runtime. Force these symbols off. +-if test "$ac_sys_system" != "iOS" ; then ++if test "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then + ac_fn_c_check_func "$LINENO" "getentropy" "ac_cv_func_getentropy" + if test "x$ac_cv_func_getentropy" = xyes + then : +@@ -20160,6 +20259,53 @@ --/* Define to 1 if you have the `truncate' function. */ -+/* Define to 1 if you have the 'truncate' function. */ - #undef HAVE_TRUNCATE + fi --/* Define to 1 if you have the `ttyname' function. */ --#undef HAVE_TTYNAME -+/* Define to 1 if you have the 'ttyname_r' function. */ -+#undef HAVE_TTYNAME_R ++# tvOS/watchOS have some additional methods that can be found, but not used. ++if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then ++ ac_fn_c_check_func "$LINENO" "execv" "ac_cv_func_execv" ++if test "x$ac_cv_func_execv" = xyes ++then : ++ printf "%s\n" "#define HAVE_EXECV 1" >>confdefs.h ++ ++fi ++ac_fn_c_check_func "$LINENO" "fork" "ac_cv_func_fork" ++if test "x$ac_cv_func_fork" = xyes ++then : ++ printf "%s\n" "#define HAVE_FORK 1" >>confdefs.h ++ ++fi ++ac_fn_c_check_func "$LINENO" "fork1" "ac_cv_func_fork1" ++if test "x$ac_cv_func_fork1" = xyes ++then : ++ printf "%s\n" "#define HAVE_FORK1 1" >>confdefs.h ++ ++fi ++ac_fn_c_check_func "$LINENO" "posix_spawn" "ac_cv_func_posix_spawn" ++if test "x$ac_cv_func_posix_spawn" = xyes ++then : ++ printf "%s\n" "#define HAVE_POSIX_SPAWN 1" >>confdefs.h ++ ++fi ++ac_fn_c_check_func "$LINENO" "posix_spawnp" "ac_cv_func_posix_spawnp" ++if test "x$ac_cv_func_posix_spawnp" = xyes ++then : ++ printf "%s\n" "#define HAVE_POSIX_SPAWNP 1" >>confdefs.h ++ ++fi ++ac_fn_c_check_func "$LINENO" "posix_spawn_file_actions_addclosefrom_np" "ac_cv_func_posix_spawn_file_actions_addclosefrom_np" ++if test "x$ac_cv_func_posix_spawn_file_actions_addclosefrom_np" = xyes ++then : ++ printf "%s\n" "#define HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP 1" >>confdefs.h ++ ++fi ++ac_fn_c_check_func "$LINENO" "sigaltstack" "ac_cv_func_sigaltstack" ++if test "x$ac_cv_func_sigaltstack" = xyes ++then : ++ printf "%s\n" "#define HAVE_SIGALTSTACK 1" >>confdefs.h ++ ++fi ++ ++fi ++ + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5 + printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; } + if test ${ac_cv_c_undeclared_builtin_options+y} +@@ -21530,7 +21676,7 @@ --/* Define to 1 if you don't have `tm_zone' but do have the external array -- `tzname'. */ -+/* Define to 1 if you don't have 'tm_zone' but do have the external array -+ 'tzname'. */ - #undef HAVE_TZNAME --/* Define to 1 if you have the `umask' function. */ -+/* Define to 1 if you have the 'umask' function. */ - #undef HAVE_UMASK + CPPFLAGS="$CPPFLAGS $ZLIB_CFLAGS" +- LIBS="$LIBS $ZLIB_LIBS" ++ LDFLAGS="$LDFLAGS $ZLIB_LIBS" + for ac_header in zlib.h + do : + ac_fn_c_check_header_compile "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" +@@ -21677,7 +21823,7 @@ --/* Define to 1 if you have the `uname' function. */ -+/* Define to 1 if you have the 'uname' function. */ - #undef HAVE_UNAME - /* Define to 1 if you have the header file. */ - #undef HAVE_UNISTD_H + CPPFLAGS="$CPPFLAGS $ZLIB_CFLAGS" +- LIBS="$LIBS $ZLIB_LIBS" ++ LDFLAGS="$LDFLAGS $ZLIB_LIBS" + for ac_header in zlib.h + do : + ac_fn_c_check_header_compile "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" +@@ -21914,7 +22060,7 @@ --/* Define to 1 if you have the `unlinkat' function. */ -+/* Define to 1 if you have the 'unlinkat' function. */ - #undef HAVE_UNLINKAT --/* Define to 1 if you have the `unlockpt' function. */ -+/* Define to 1 if you have the 'unlockpt' function. */ - #undef HAVE_UNLOCKPT + CPPFLAGS="$CPPFLAGS $BZIP2_CFLAGS" +- LIBS="$LIBS $BZIP2_LIBS" ++ LDFLAGS="$LDFLAGS $BZIP2_LIBS" + for ac_header in bzlib.h + do : + ac_fn_c_check_header_compile "$LINENO" "bzlib.h" "ac_cv_header_bzlib_h" "$ac_includes_default" +@@ -22006,7 +22152,7 @@ --/* Define to 1 if you have the `unshare' function. */ -+/* Define to 1 if you have the 'unshare' function. */ - #undef HAVE_UNSHARE - /* Define if you have a useable wchar_t type defined in wchar.h; useable means -@@ -1536,10 +1542,10 @@ - /* Define to 1 if you have the header file. */ - #undef HAVE_UTIL_H + CPPFLAGS="$CPPFLAGS $BZIP2_CFLAGS" +- LIBS="$LIBS $BZIP2_LIBS" ++ LDFLAGS="$LDFLAGS $BZIP2_LIBS" + for ac_header in bzlib.h + do : + ac_fn_c_check_header_compile "$LINENO" "bzlib.h" "ac_cv_header_bzlib_h" "$ac_includes_default" +@@ -22162,7 +22308,7 @@ --/* Define to 1 if you have the `utimensat' function. */ -+/* Define to 1 if you have the 'utimensat' function. */ - #undef HAVE_UTIMENSAT --/* Define to 1 if you have the `utimes' function. */ -+/* Define to 1 if you have the 'utimes' function. */ - #undef HAVE_UTIMES + CPPFLAGS="$CPPFLAGS $LIBLZMA_CFLAGS" +- LIBS="$LIBS $LIBLZMA_LIBS" ++ LDFLAGS="$LDFLAGS $LIBLZMA_LIBS" + for ac_header in lzma.h + do : + ac_fn_c_check_header_compile "$LINENO" "lzma.h" "ac_cv_header_lzma_h" "$ac_includes_default" +@@ -22254,7 +22400,7 @@ - /* Define to 1 if you have the header file. */ -@@ -1548,10 +1554,10 @@ - /* Define to 1 if you have the header file. */ - #undef HAVE_UTMP_H --/* Define to 1 if you have the `uuid_create' function. */ -+/* Define to 1 if you have the 'uuid_create' function. */ - #undef HAVE_UUID_CREATE + CPPFLAGS="$CPPFLAGS $LIBLZMA_CFLAGS" +- LIBS="$LIBS $LIBLZMA_LIBS" ++ LDFLAGS="$LDFLAGS $LIBLZMA_LIBS" + for ac_header in lzma.h + do : + ac_fn_c_check_header_compile "$LINENO" "lzma.h" "ac_cv_header_lzma_h" "$ac_includes_default" +@@ -23242,7 +23388,8 @@ --/* Define to 1 if you have the `uuid_enc_be' function. */ -+/* Define to 1 if you have the 'uuid_enc_be' function. */ - #undef HAVE_UUID_ENC_BE - /* Define if uuid_generate_time_safe() exists. */ -@@ -1563,44 +1569,44 @@ - /* Define to 1 if you have the header file. */ - #undef HAVE_UUID_UUID_H + # check for openpty, login_tty, and forkpty +- ++# tvOS/watchOS have functions for tty, but can't use them ++if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then --/* Define to 1 if you have the `vfork' function. */ -+/* Define to 1 if you have the 'vfork' function. */ - #undef HAVE_VFORK + for ac_func in openpty + do : +@@ -23539,6 +23686,7 @@ + fi --/* Define to 1 if you have the `wait' function. */ -+/* Define to 1 if you have the 'wait' function. */ - #undef HAVE_WAIT + done ++fi --/* Define to 1 if you have the `wait3' function. */ -+/* Define to 1 if you have the 'wait3' function. */ - #undef HAVE_WAIT3 + # check for long file support functions + ac_fn_c_check_func "$LINENO" "fseek64" "ac_cv_func_fseek64" +@@ -23804,10 +23952,10 @@ --/* Define to 1 if you have the `wait4' function. */ -+/* Define to 1 if you have the 'wait4' function. */ - #undef HAVE_WAIT4 + done --/* Define to 1 if you have the `waitid' function. */ -+/* Define to 1 if you have the 'waitid' function. */ - #undef HAVE_WAITID +-# On Android and iOS, clock_settime can be linked (so it is found by ++# On Android, iOS, tvOS and watchOS, clock_settime can be linked (so it is found by + # configure), but when used in an unprivileged process, it crashes rather than + # returning an error. Force the symbol off. +-if test "$ac_sys_system" != "Linux-android" && test "$ac_sys_system" != "iOS" ++if test "$ac_sys_system" != "Linux-android" -a "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" + then --/* Define to 1 if you have the `waitpid' function. */ -+/* Define to 1 if you have the 'waitpid' function. */ - #undef HAVE_WAITPID + for ac_func in clock_settime +@@ -26146,8 +26294,8 @@ + LIBPYTHON="\$(BLDLIBRARY)" + fi - /* Define if the compiler provides a wchar.h header file. */ - #undef HAVE_WCHAR_H +-# On iOS the shared libraries must be linked with the Python framework +-if test "$ac_sys_system" = "iOS"; then ++# On iOS/tvOS/watchOS the shared libraries must be linked with the Python framework ++if test "$ac_sys_system" = "iOS" -o $ac_sys_system = "tvOS" -o $ac_sys_system = "watchOS"; then + MODULE_DEPS_SHARED="$MODULE_DEPS_SHARED \$(PYTHONFRAMEWORKDIR)/\$(PYTHONFRAMEWORK)" + fi --/* Define to 1 if you have the `wcscoll' function. */ -+/* Define to 1 if you have the 'wcscoll' function. */ - #undef HAVE_WCSCOLL +@@ -26497,7 +26645,7 @@ --/* Define to 1 if you have the `wcsftime' function. */ -+/* Define to 1 if you have the 'wcsftime' function. */ - #undef HAVE_WCSFTIME --/* Define to 1 if you have the `wcsxfrm' function. */ -+/* Define to 1 if you have the 'wcsxfrm' function. */ - #undef HAVE_WCSXFRM + CPPFLAGS="$CPPFLAGS $LIBREADLINE_CFLAGS" +- LIBS="$LIBS $LIBREADLINE_LIBS" ++ LDFLAGS="$LDFLAGS $LIBREADLINE_LIBS" + for ac_header in readline/readline.h + do : + ac_fn_c_check_header_compile "$LINENO" "readline/readline.h" "ac_cv_header_readline_readline_h" "$ac_includes_default" +@@ -26659,7 +26807,7 @@ --/* Define to 1 if you have the `wmemcmp' function. */ -+/* Define to 1 if you have the 'wmemcmp' function. */ - #undef HAVE_WMEMCMP - /* Define if tzset() actually switches the local timezone in a meaningful way. - */ - #undef HAVE_WORKING_TZSET + CPPFLAGS="$CPPFLAGS $LIBEDIT_CFLAGS" +- LIBS="$LIBS $LIBEDIT_LIBS" ++ LDFLAGS="$LDFLAGS $LIBEDIT_LIBS" + for ac_header in editline/readline.h + do : + ac_fn_c_check_header_compile "$LINENO" "editline/readline.h" "ac_cv_header_editline_readline_h" "$ac_includes_default" +@@ -26750,7 +26898,7 @@ --/* Define to 1 if you have the `writev' function. */ -+/* Define to 1 if you have the 'writev' function. */ - #undef HAVE_WRITEV - /* Define if the zlib library has inflateCopy */ -@@ -1609,17 +1615,17 @@ - /* Define to 1 if you have the header file. */ - #undef HAVE_ZLIB_H + CPPFLAGS="$CPPFLAGS $LIBEDIT_CFLAGS" +- LIBS="$LIBS $LIBEDIT_LIBS" ++ LDFLAGS="$LDFLAGS $LIBEDIT_LIBS" + for ac_header in editline/readline.h + do : + ac_fn_c_check_header_compile "$LINENO" "editline/readline.h" "ac_cv_header_editline_readline_h" "$ac_includes_default" +@@ -26868,7 +27016,7 @@ --/* Define to 1 if you have the `_getpty' function. */ -+/* Define to 1 if you have the '_getpty' function. */ - #undef HAVE__GETPTY --/* Define to 1 if the system has the type `__uint128_t'. */ -+/* Define to 1 if the system has the type '__uint128_t'. */ - #undef HAVE___UINT128_T + CPPFLAGS="$CPPFLAGS $READLINE_CFLAGS" +- LIBS="$LIBS $READLINE_LIBS" ++ LIBS="$READLINE_LIBS $LIBS" + LIBS_SAVE=$LIBS --/* Define to 1 if `major', `minor', and `makedev' are declared in . -+/* Define to 1 if 'major', 'minor', and 'makedev' are declared in . - */ - #undef MAJOR_IN_MKDEV --/* Define to 1 if `major', `minor', and `makedev' are declared in -+/* Define to 1 if 'major', 'minor', and 'makedev' are declared in - . */ - #undef MAJOR_IN_SYSMACROS +@@ -29017,7 +29165,7 @@ + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for device files" >&5 + printf "%s\n" "$as_me: checking for device files" >&6;} -@@ -1656,9 +1662,6 @@ - /* Define as the preferred size in bits of long digits */ - #undef PYLONG_BITS_IN_DIGIT +-if test "$ac_sys_system" = "Linux-android" || test "$ac_sys_system" = "iOS"; then ++if test "$ac_sys_system" = "Linux-android" -o "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "watchOS" ; then + ac_cv_file__dev_ptmx=no + ac_cv_file__dev_ptc=no + else +@@ -29510,7 +29658,7 @@ + with_ensurepip=no ;; #( + WASI) : + with_ensurepip=no ;; #( +- iOS) : ++ iOS|tvOS|watchOS) : + with_ensurepip=no ;; #( + *) : + with_ensurepip=upgrade +@@ -30490,7 +30638,7 @@ + ;; #( + Darwin) : + ;; #( +- iOS) : ++ iOS|tvOS|watchOS) : --/* Maximum length in bytes of a thread name */ --#undef PYTHREAD_NAME_MAXLEN -- - /* enabled builtin hash modules */ - #undef PY_BUILTIN_HASHLIB_HASHES -@@ -1712,12 +1715,12 @@ - /* Define if you want to enable internal statistics gathering. */ - #undef Py_STATS --/* Define if C99-specific strftime specifiers are supported. */ --#undef Py_STRFTIME_C99_SUPPORT -- - /* The version of SunOS/Solaris as reported by `uname -r' without the dot. */ - #undef Py_SUNOS_VERSION +@@ -34493,6 +34641,8 @@ + "Mac/Resources/framework/Info.plist") CONFIG_FILES="$CONFIG_FILES Mac/Resources/framework/Info.plist" ;; + "Mac/Resources/app/Info.plist") CONFIG_FILES="$CONFIG_FILES Mac/Resources/app/Info.plist" ;; + "iOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES iOS/Resources/Info.plist" ;; ++ "tvOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES tvOS/Resources/Info.plist" ;; ++ "watchOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES watchOS/Resources/Info.plist" ;; + "Makefile.pre") CONFIG_FILES="$CONFIG_FILES Makefile.pre" ;; + "Misc/python.pc") CONFIG_FILES="$CONFIG_FILES Misc/python.pc" ;; + "Misc/python-embed.pc") CONFIG_FILES="$CONFIG_FILES Misc/python-embed.pc" ;; +diff --git a/configure.ac b/configure.ac +index faa89095303..660e1c638ec 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -330,6 +330,12 @@ + *-apple-ios*) + ac_sys_system=iOS + ;; ++ *-apple-tvos*) ++ ac_sys_system=tvOS ++ ;; ++ *-apple-watchos*) ++ ac_sys_system=watchOS ++ ;; + *-*-darwin*) + ac_sys_system=Darwin + ;; +@@ -405,7 +411,7 @@ + # On cross-compile builds, configure will look for a host-specific compiler by + # prepending the user-provided host triple to the required binary name. + # +-# On iOS, this results in binaries like "arm64-apple-ios13.0-simulator-gcc", ++# On iOS/tvOS/watchOS, this results in binaries like "arm64-apple-ios13.0-simulator-gcc", + # which isn't a binary that exists, and isn't very convenient, as it contains the + # iOS version. As the default cross-compiler name won't exist, configure falls + # back to gcc, which *definitely* won't work. We're providing wrapper scripts for +@@ -420,6 +426,14 @@ + aarch64-apple-ios*-simulator) AR=arm64-apple-ios-simulator-ar ;; + aarch64-apple-ios*) AR=arm64-apple-ios-ar ;; + x86_64-apple-ios*-simulator) AR=x86_64-apple-ios-simulator-ar ;; ++ ++ aarch64-apple-tvos*-simulator) AR=arm64-apple-tvos-simulator-ar ;; ++ aarch64-apple-tvos*) AR=arm64-apple-tvos-ar ;; ++ x86_64-apple-tvos*-simulator) AR=x86_64-apple-tvos-simulator-ar ;; ++ ++ aarch64-apple-watchos*-simulator) AR=arm64-apple-watchos-simulator-ar ;; ++ aarch64-apple-watchos*) AR=arm64_32-apple-watchos-ar ;; ++ x86_64-apple-watchos*-simulator) AR=x86_64-apple-watchos-simulator-ar ;; + *) + esac + fi +@@ -428,6 +442,14 @@ + aarch64-apple-ios*-simulator) CC=arm64-apple-ios-simulator-clang ;; + aarch64-apple-ios*) CC=arm64-apple-ios-clang ;; + x86_64-apple-ios*-simulator) CC=x86_64-apple-ios-simulator-clang ;; ++ ++ aarch64-apple-tvos*-simulator) CC=arm64-apple-tvos-simulator-clang ;; ++ aarch64-apple-tvos*) CC=arm64-apple-tvos-clang ;; ++ x86_64-apple-tvos*-simulator) CC=x86_64-apple-tvos-simulator-clang ;; ++ ++ aarch64-apple-watchos*-simulator) CC=arm64-apple-watchos-simulator-clang ;; ++ aarch64-apple-watchos*) CC=arm64_32-apple-watchos-clang ;; ++ x86_64-apple-watchos*-simulator) CC=x86_64-apple-watchos-simulator-clang ;; + *) + esac + fi +@@ -436,6 +458,14 @@ + aarch64-apple-ios*-simulator) CPP=arm64-apple-ios-simulator-cpp ;; + aarch64-apple-ios*) CPP=arm64-apple-ios-cpp ;; + x86_64-apple-ios*-simulator) CPP=x86_64-apple-ios-simulator-cpp ;; ++ ++ aarch64-apple-tvos*-simulator) CPP=arm64-apple-tvos-simulator-cpp ;; ++ aarch64-apple-tvos*) CPP=arm64-apple-tvos-cpp ;; ++ x86_64-apple-tvos*-simulator) CPP=x86_64-apple-tvos-simulator-cpp ;; ++ ++ aarch64-apple-watchos*-simulator) CPP=arm64-apple-watchos-simulator-cpp ;; ++ aarch64-apple-watchos*) CPP=arm64_32-apple-watchos-cpp ;; ++ x86_64-apple-watchos*-simulator) CPP=x86_64-apple-watchos-simulator-cpp ;; + *) + esac + fi +@@ -444,6 +474,14 @@ + aarch64-apple-ios*-simulator) CXX=arm64-apple-ios-simulator-clang++ ;; + aarch64-apple-ios*) CXX=arm64-apple-ios-clang++ ;; + x86_64-apple-ios*-simulator) CXX=x86_64-apple-ios-simulator-clang++ ;; ++ ++ aarch64-apple-tvos*-simulator) CXX=arm64-apple-tvos-simulator-clang++ ;; ++ aarch64-apple-tvos*) CXX=arm64-apple-tvos-clang++ ;; ++ x86_64-apple-tvos*-simulator) CXX=x86_64-apple-tvos-simulator-clang++ ;; ++ ++ aarch64-apple-watchos*-simulator) CXX=arm64-apple-watchos-simulator-clang++ ;; ++ aarch64-apple-watchos*) CXX=arm64_32-apple-watchos-clang++ ;; ++ x86_64-apple-watchos*-simulator) CXX=x86_64-apple-watchos-simulator-clang++ ;; + *) + esac + fi +@@ -558,8 +596,10 @@ + case $enableval in + yes) + case $ac_sys_system in +- Darwin) enableval=/Library/Frameworks ;; +- iOS) enableval=iOS/Frameworks/\$\(MULTIARCH\) ;; ++ Darwin) enableval=/Library/Frameworks ;; ++ iOS) enableval=iOS/Frameworks/\$\(MULTIARCH\) ;; ++ tvOS) enableval=tvOS/Frameworks/\$\(MULTIARCH\) ;; ++ watchOS) enableval=watchOS/Frameworks/\$\(MULTIARCH\) ;; + *) AC_MSG_ERROR([Unknown platform for framework build]) + esac + esac +@@ -568,6 +608,8 @@ + no) + case $ac_sys_system in + iOS) AC_MSG_ERROR([iOS builds must use --enable-framework]) ;; ++ tvOS) AC_MSG_ERROR([tvOS builds must use --enable-framework]) ;; ++ watchOS) AC_MSG_ERROR([watchOS builds must use --enable-framework]) ;; + *) + PYTHONFRAMEWORK= + PYTHONFRAMEWORKDIR=no-framework +@@ -670,6 +712,34 @@ -+/* Define if the C compiler supports efficient proper tail calls. */ -+#undef Py_TAIL_CALL_INTERP + AC_CONFIG_FILES([iOS/Resources/Info.plist]) + ;; ++ tvOS) : ++ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure" ++ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure " ++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKPYTHONW= ++ INSTALLTARGETS="libinstall inclinstall sharedinstall" ++ ++ prefix=$PYTHONFRAMEWORKPREFIX ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" ++ RESSRCDIR=tvOS/Resources ++ ++ AC_CONFIG_FILES([tvOS/Resources/Info.plist]) ++ ;; ++ watchOS) : ++ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure" ++ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure " ++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKPYTHONW= ++ INSTALLTARGETS="libinstall inclinstall sharedinstall" ++ ++ prefix=$PYTHONFRAMEWORKPREFIX ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" ++ RESSRCDIR=watchOS/Resources + - /* Define if you want to enable tracing references for debugging purpose */ - #undef Py_TRACE_REFS - -@@ -1730,58 +1733,58 @@ - /* Define if i>>j for signed int i does not extend the sign bit when i < 0 */ - #undef SIGNED_RIGHT_SHIFT_ZERO_FILLS - --/* The size of `double', as computed by sizeof. */ -+/* The size of 'double', as computed by sizeof. */ - #undef SIZEOF_DOUBLE - --/* The size of `float', as computed by sizeof. */ -+/* The size of 'float', as computed by sizeof. */ - #undef SIZEOF_FLOAT - --/* The size of `fpos_t', as computed by sizeof. */ -+/* The size of 'fpos_t', as computed by sizeof. */ - #undef SIZEOF_FPOS_T - --/* The size of `int', as computed by sizeof. */ -+/* The size of 'int', as computed by sizeof. */ - #undef SIZEOF_INT - --/* The size of `long', as computed by sizeof. */ -+/* The size of 'long', as computed by sizeof. */ - #undef SIZEOF_LONG - --/* The size of `long double', as computed by sizeof. */ -+/* The size of 'long double', as computed by sizeof. */ - #undef SIZEOF_LONG_DOUBLE - --/* The size of `long long', as computed by sizeof. */ -+/* The size of 'long long', as computed by sizeof. */ - #undef SIZEOF_LONG_LONG ++ AC_CONFIG_FILES([watchOS/Resources/Info.plist]) ++ ;; + *) + AC_MSG_ERROR([Unknown platform for framework build]) + ;; +@@ -678,6 +748,8 @@ + ],[ + case $ac_sys_system in + iOS) AC_MSG_ERROR([iOS builds must use --enable-framework]) ;; ++ tvOS) AC_MSG_ERROR([tvOS builds must use --enable-framework]) ;; ++ watchOS) AC_MSG_ERROR([watchOS builds must use --enable-framework]) ;; + *) + PYTHONFRAMEWORK= + PYTHONFRAMEWORKDIR=no-framework +@@ -730,8 +802,8 @@ + case "$withval" in + yes) + case $ac_sys_system in +- Darwin|iOS) +- # iOS is able to share the macOS patch ++ Darwin|iOS|tvOS|watchOS) ++ # iOS/tvOS/watchOS is able to share the macOS patch + APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" + ;; + *) AC_MSG_ERROR([no default app store compliance patch available for $ac_sys_system]) ;; +@@ -745,8 +817,8 @@ + esac + ],[ + case $ac_sys_system in +- iOS) +- # Always apply the compliance patch on iOS; we can use the macOS patch ++ iOS|tvOS|watchOS) ++ # Always apply the compliance patch on iOS/tvOS/watchOS; we can use the macOS patch + APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" + AC_MSG_RESULT([applying default app store compliance patch]) + ;; +@@ -794,6 +866,46 @@ + ;; + esac + ;; ++ *-apple-tvos*) ++ _host_os=`echo $host | cut -d '-' -f3` ++ _host_device=`echo $host | cut -d '-' -f4` ++ _host_device=${_host_device:=os} ++ ++ # TVOS_DEPLOYMENT_TARGET is the minimum supported tvOS version ++ AC_MSG_CHECKING([tvOS deployment target]) ++ TVOS_DEPLOYMENT_TARGET=${_host_os:4} ++ TVOS_DEPLOYMENT_TARGET=${TVOS_DEPLOYMENT_TARGET:=12.0} ++ AC_MSG_RESULT([$TVOS_DEPLOYMENT_TARGET]) ++ ++ case "$host_cpu" in ++ aarch64) ++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-arm64-appletv${_host_device} ++ ;; ++ *) ++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-$host_cpu-appletv${_host_device} ++ ;; ++ esac ++ ;; ++ *-apple-watchos*) ++ _host_os=`echo $host | cut -d '-' -f3` ++ _host_device=`echo $host | cut -d '-' -f4` ++ _host_device=${_host_device:=os} ++ ++ # WATCHOS_DEPLOYMENT_TARGET is the minimum supported watchOS version ++ AC_MSG_CHECKING([watchOS deployment target]) ++ WATCHOS_DEPLOYMENT_TARGET=${_host_os:7} ++ WATCHOS_DEPLOYMENT_TARGET=${WATCHOS_DEPLOYMENT_TARGET:=4.0} ++ AC_MSG_RESULT([$WATCHOS_DEPLOYMENT_TARGET]) ++ ++ case "$host_cpu" in ++ aarch64) ++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-arm64-watch${_host_device} ++ ;; ++ *) ++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-$host_cpu-watch${_host_device} ++ ;; ++ esac ++ ;; + *-*-darwin*) + case "$host_cpu" in + arm*) +@@ -883,9 +995,13 @@ + define_xopen_source=no;; + Darwin/@<:@[12]@:>@@<:@0-9@:>@.*) + define_xopen_source=no;; +- # On iOS, defining _POSIX_C_SOURCE also disables platform specific features. ++ # On iOS/tvOS/watchOS, defining _POSIX_C_SOURCE also disables platform specific features. + iOS/*) + define_xopen_source=no;; ++ tvOS/*) ++ define_xopen_source=no;; ++ watchOS/*) ++ define_xopen_source=no;; + # On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from + # defining NI_NUMERICHOST. + QNX/6.3.2) +@@ -944,8 +1060,11 @@ + CONFIGURE_MACOSX_DEPLOYMENT_TARGET= + EXPORT_MACOSX_DEPLOYMENT_TARGET='#' --/* The size of `off_t', as computed by sizeof. */ -+/* The size of 'off_t', as computed by sizeof. */ - #undef SIZEOF_OFF_T +-# Record the value of IPHONEOS_DEPLOYMENT_TARGET enforced by the selected host triple. ++# Record the value of IPHONEOS_DEPLOYMENT_TARGET / TVOS_DEPLOYMENT_TARGET / ++# WATCHOS_DEPLOYMENT_TARGET enforced by the selected host triple. + AC_SUBST([IPHONEOS_DEPLOYMENT_TARGET]) ++AC_SUBST([TVOS_DEPLOYMENT_TARGET]) ++AC_SUBST([WATCHOS_DEPLOYMENT_TARGET]) --/* The size of `pid_t', as computed by sizeof. */ -+/* The size of 'pid_t', as computed by sizeof. */ - #undef SIZEOF_PID_T + # checks for alternative programs --/* The size of `pthread_key_t', as computed by sizeof. */ -+/* The size of 'pthread_key_t', as computed by sizeof. */ - #undef SIZEOF_PTHREAD_KEY_T +@@ -979,11 +1098,17 @@ + ], + ) --/* The size of `pthread_t', as computed by sizeof. */ -+/* The size of 'pthread_t', as computed by sizeof. */ - #undef SIZEOF_PTHREAD_T +-dnl Add the compiler flag for the iOS minimum supported OS version. ++dnl Add the compiler flag for the iOS/tvOS/watchOS minimum supported OS version. + AS_CASE([$ac_sys_system], + [iOS], [ + AS_VAR_APPEND([CFLAGS], [" -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}"]) + AS_VAR_APPEND([LDFLAGS], [" -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}"]) ++ ],[tvOS], [ ++ AS_VAR_APPEND([CFLAGS], [" -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}"]) ++ AS_VAR_APPEND([LDFLAGS], [" -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}"]) ++ ],[watchOS], [ ++ AS_VAR_APPEND([CFLAGS], [" -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}"]) ++ AS_VAR_APPEND([LDFLAGS], [" -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}"]) + ], + ) --/* The size of `short', as computed by sizeof. */ -+/* The size of 'short', as computed by sizeof. */ - #undef SIZEOF_SHORT +@@ -1172,6 +1297,8 @@ + AS_CASE([$ac_sys_system], + [Darwin*], [MULTIARCH=""], + [iOS], [MULTIARCH=""], ++ [tvOS], [MULTIARCH=""], ++ [watchOS], [MULTIARCH=""], + [FreeBSD*], [MULTIARCH=""], + [MULTIARCH=$($CC --print-multiarch 2>/dev/null)] + ) +@@ -1193,7 +1320,7 @@ + dnl use a single "fat" binary at runtime. SOABI_PLATFORM is the component of + dnl the PLATFORM_TRIPLET that will be used in binary module extensions. + AS_CASE([$ac_sys_system], +- [iOS], [SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f2`], ++ [iOS|tvOS|watchOS], [SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f2`], + [SOABI_PLATFORM=$PLATFORM_TRIPLET] + ) --/* The size of `size_t', as computed by sizeof. */ -+/* The size of 'size_t', as computed by sizeof. */ - #undef SIZEOF_SIZE_T +@@ -1227,6 +1354,10 @@ + [x86_64-*-freebsd*/clang], [PY_SUPPORT_TIER=3], dnl FreeBSD on AMD64 + [aarch64-apple-ios*-simulator/clang], [PY_SUPPORT_TIER=3], dnl iOS Simulator on arm64 + [aarch64-apple-ios*/clang], [PY_SUPPORT_TIER=3], dnl iOS on ARM64 ++ [aarch64-apple-tvos*-simulator/clang], [PY_SUPPORT_TIER=3], dnl tvOS Simulator on arm64 ++ [aarch64-apple-tvos*/clang], [PY_SUPPORT_TIER=3], dnl tvOS on ARM64 ++ [aarch64-apple-watchos*-simulator/clang], [PY_SUPPORT_TIER=3], dnl watchOS Simulator on arm64 ++ [arm64_32-apple-watchos*/clang], [PY_SUPPORT_TIER=3], dnl watchOS on ARM64 + [aarch64-*-linux-android/clang], [PY_SUPPORT_TIER=3], dnl Android on ARM64 + [x86_64-*-linux-android/clang], [PY_SUPPORT_TIER=3], dnl Android on AMD64 --/* The size of `time_t', as computed by sizeof. */ -+/* The size of 'time_t', as computed by sizeof. */ - #undef SIZEOF_TIME_T +@@ -1536,7 +1667,7 @@ + case $ac_sys_system in + Darwin) + LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)';; +- iOS) ++ iOS|tvOS|watchOS) + LDLIBRARY='$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';; + *) + AC_MSG_ERROR([Unknown platform for framework build]);; +@@ -1601,7 +1732,7 @@ + BLDLIBRARY='-L. -lpython$(LDVERSION)' + RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}} + ;; +- iOS) ++ iOS|tvOS|watchOS) + LDLIBRARY='libpython$(LDVERSION).dylib' + ;; + AIX*) +@@ -3456,7 +3587,7 @@ + BLDSHARED="$LDSHARED" + fi + ;; +- iOS/*) ++ iOS/*|tvOS/*|watchOS/*) + LDSHARED='$(CC) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)' + LDCXXSHARED='$(CXX) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)' + BLDSHARED="$LDSHARED" +@@ -3580,7 +3711,7 @@ + Linux-android*) LINKFORSHARED="-pie -Xlinker -export-dynamic";; + Linux*|GNU*) LINKFORSHARED="-Xlinker -export-dynamic";; + # -u libsys_s pulls in all symbols in libsys +- Darwin/*|iOS/*) ++ Darwin/*|iOS/*|tvOS/*|watchOS/*) + LINKFORSHARED="$extra_undefs -framework CoreFoundation" --/* The size of `uintptr_t', as computed by sizeof. */ -+/* The size of 'uintptr_t', as computed by sizeof. */ - #undef SIZEOF_UINTPTR_T + # Issue #18075: the default maximum stack size (8MBytes) is too +@@ -3604,7 +3735,7 @@ + LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' + fi + LINKFORSHARED="$LINKFORSHARED" +- elif test $ac_sys_system = "iOS"; then ++ elif test "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "watchOS"; then + LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)' + fi + ;; +@@ -3735,7 +3866,7 @@ + ], [ + WITH_SAVE_ENV([ + CPPFLAGS="$CPPFLAGS $LIBUUID_CFLAGS" +- LIBS="$LIBS $LIBUUID_LIBS" ++ LDFLAGS="$LDFLAGS $LIBUUID_LIBS" + AC_CHECK_HEADERS([uuid/uuid.h], [ + PY_CHECK_LIB([uuid], [uuid_generate_time], [have_uuid=yes]) + PY_CHECK_LIB([uuid], [uuid_generate_time_safe], +@@ -4005,7 +4136,7 @@ + PKG_CHECK_MODULES([LIBFFI], [libffi], [have_libffi=yes], [ + WITH_SAVE_ENV([ + CPPFLAGS="$CPPFLAGS $LIBFFI_CFLAGS" +- LIBS="$LIBS $LIBFFI_LIBS" ++ LDFLAGS="$LDFLAGS $LIBFFI_LIBS" + AC_CHECK_HEADER([ffi.h], [ + AC_CHECK_LIB([ffi], [ffi_call], [ + have_libffi=yes +@@ -4024,7 +4155,7 @@ + dnl when do we need USING_APPLE_OS_LIBFFI? + ctypes_malloc_closure=yes + ], +- [iOS], [ ++ [iOS|tvOS|watchOS], [ + ctypes_malloc_closure=yes + ], + [sunos5], [AS_VAR_APPEND([LIBFFI_LIBS], [" -mimpure-text"])] +@@ -5133,9 +5264,9 @@ + # checks for library functions + AC_CHECK_FUNCS([ \ + accept4 alarm bind_textdomain_codeset chmod chown clock closefrom close_range confstr \ +- copy_file_range ctermid dladdr dup dup3 execv explicit_bzero explicit_memset \ ++ copy_file_range ctermid dladdr dup dup3 explicit_bzero explicit_memset \ + faccessat fchmod fchmodat fchown fchownat fdopendir fdwalk fexecve \ +- fork fork1 fpathconf fstatat ftime ftruncate futimens futimes futimesat \ ++ fpathconf fstatat ftime ftruncate futimens futimes futimesat \ + gai_strerror getegid geteuid getgid getgrent getgrgid getgrgid_r \ + getgrnam_r getgrouplist gethostname getitimer getloadavg getlogin \ + getpeername getpgid getpid getppid getpriority _getpty \ +@@ -5143,8 +5274,7 @@ + getspnam getuid getwd grantpt if_nameindex initgroups kill killpg lchown linkat \ + lockf lstat lutimes madvise mbrtowc memrchr mkdirat mkfifo mkfifoat \ + mknod mknodat mktime mmap mremap nice openat opendir pathconf pause pipe \ +- pipe2 plock poll posix_fadvise posix_fallocate posix_openpt posix_spawn posix_spawnp \ +- posix_spawn_file_actions_addclosefrom_np \ ++ pipe2 plock poll posix_fadvise posix_fallocate posix_openpt \ + pread preadv preadv2 process_vm_readv \ + pthread_cond_timedwait_relative_np pthread_condattr_setclock pthread_init \ + pthread_kill pthread_getname_np pthread_setname_np \ +@@ -5153,7 +5283,7 @@ + sched_setparam sched_setscheduler sem_clockwait sem_getvalue sem_open \ + sem_timedwait sem_unlink sendfile setegid seteuid setgid sethostname \ + setitimer setlocale setpgid setpgrp setpriority setregid setresgid \ +- setresuid setreuid setsid setuid setvbuf shutdown sigaction sigaltstack \ ++ setresuid setreuid setsid setuid setvbuf shutdown sigaction \ + sigfillset siginterrupt sigpending sigrelse sigtimedwait sigwait \ + sigwaitinfo snprintf splice strftime strlcpy strsignal symlinkat sync \ + sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile \ +@@ -5168,12 +5298,20 @@ + AC_CHECK_FUNCS([lchmod]) + fi --/* The size of `void *', as computed by sizeof. */ -+/* The size of 'void *', as computed by sizeof. */ - #undef SIZEOF_VOID_P +-# iOS defines some system methods that can be linked (so they are ++# iOS/tvOS/watchOS define some system methods that can be linked (so they are + # found by configure), but either raise a compilation error (because the + # header definition prevents usage - autoconf doesn't use the headers), or + # raise an error if used at runtime. Force these symbols off. +-if test "$ac_sys_system" != "iOS" ; then +- AC_CHECK_FUNCS([getentropy getgroups system]) ++if test "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then ++ AC_CHECK_FUNCS([ getentropy getgroups system ]) ++fi ++ ++# tvOS/watchOS have some additional methods that can be found, but not used. ++if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then ++ AC_CHECK_FUNCS([ \ ++ execv fork fork1 posix_spawn posix_spawnp posix_spawn_file_actions_addclosefrom_np \ ++ sigaltstack \ ++ ]) + fi --/* The size of `wchar_t', as computed by sizeof. */ -+/* The size of 'wchar_t', as computed by sizeof. */ - #undef SIZEOF_WCHAR_T + AC_CHECK_DECL([dirfd], +@@ -5427,20 +5565,22 @@ + ]) --/* The size of `_Bool', as computed by sizeof. */ -+/* The size of '_Bool', as computed by sizeof. */ - #undef SIZEOF__BOOL + # check for openpty, login_tty, and forkpty +- +-AC_CHECK_FUNCS([openpty], [], +- [AC_CHECK_LIB([util], [openpty], +- [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lutil"], +- [AC_CHECK_LIB([bsd], [openpty], +- [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lbsd"])])]) +-AC_SEARCH_LIBS([login_tty], [util], +- [AC_DEFINE([HAVE_LOGIN_TTY], [1], [Define to 1 if you have the `login_tty' function.])] +-) +-AC_CHECK_FUNCS([forkpty], [], +- [AC_CHECK_LIB([util], [forkpty], +- [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lutil"], +- [AC_CHECK_LIB([bsd], [forkpty], +- [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lbsd"])])]) ++# tvOS/watchOS have functions for tty, but can't use them ++if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then ++ AC_CHECK_FUNCS([openpty], [], ++ [AC_CHECK_LIB([util], [openpty], ++ [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lutil"], ++ [AC_CHECK_LIB([bsd], [openpty], ++ [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lbsd"])])]) ++ AC_SEARCH_LIBS([login_tty], [util], ++ [AC_DEFINE([HAVE_LOGIN_TTY], [1], [Define to 1 if you have the `login_tty' function.])] ++ ) ++ AC_CHECK_FUNCS([forkpty], [], ++ [AC_CHECK_LIB([util], [forkpty], ++ [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lutil"], ++ [AC_CHECK_LIB([bsd], [forkpty], ++ [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lbsd"])])]) ++fi - /* Define to 1 if you have the ANSI C header files. */ -@@ -1797,13 +1800,13 @@ - /* Library needed by timemodule.c: librt may be needed for clock_gettime() */ - #undef TIMEMODULE_LIB + # check for long file support functions + AC_CHECK_FUNCS([fseek64 fseeko fstatvfs ftell64 ftello statvfs]) +@@ -5479,10 +5619,10 @@ + ]) + ]) --/* Define to 1 if your declares `struct tm'. */ -+/* Define to 1 if your declares 'struct tm'. */ - #undef TM_IN_SYS_TIME +-# On Android and iOS, clock_settime can be linked (so it is found by ++# On Android, iOS, tvOS and watchOS, clock_settime can be linked (so it is found by + # configure), but when used in an unprivileged process, it crashes rather than + # returning an error. Force the symbol off. +-if test "$ac_sys_system" != "Linux-android" && test "$ac_sys_system" != "iOS" ++if test "$ac_sys_system" != "Linux-android" -a "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" + then + AC_CHECK_FUNCS([clock_settime], [], [ + AC_CHECK_LIB([rt], [clock_settime], [ +@@ -6233,8 +6373,8 @@ + LIBPYTHON="\$(BLDLIBRARY)" + fi - /* Define if you want to use computed gotos in ceval.c. */ - #undef USE_COMPUTED_GOTOS +-# On iOS the shared libraries must be linked with the Python framework +-if test "$ac_sys_system" = "iOS"; then ++# On iOS/tvOS/watchOS the shared libraries must be linked with the Python framework ++if test "$ac_sys_system" = "iOS" -o $ac_sys_system = "tvOS" -o $ac_sys_system = "watchOS"; then + MODULE_DEPS_SHARED="$MODULE_DEPS_SHARED \$(PYTHONFRAMEWORKDIR)/\$(PYTHONFRAMEWORK)" + fi --/* Enable extensions on AIX 3, Interix. */ -+/* Enable extensions on AIX, Interix, z/OS. */ - #ifndef _ALL_SOURCE - # undef _ALL_SOURCE - #endif -@@ -1864,11 +1867,15 @@ - #ifndef __STDC_WANT_IEC_60559_DFP_EXT__ - # undef __STDC_WANT_IEC_60559_DFP_EXT__ - #endif -+/* Enable extensions specified by C23 Annex F. */ -+#ifndef __STDC_WANT_IEC_60559_EXT__ -+# undef __STDC_WANT_IEC_60559_EXT__ -+#endif - /* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ - #ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ - # undef __STDC_WANT_IEC_60559_FUNCS_EXT__ - #endif --/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */ -+/* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015. */ - #ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ - # undef __STDC_WANT_IEC_60559_TYPES_EXT__ - #endif -@@ -1973,6 +1980,9 @@ - /* framework name */ - #undef _PYTHONFRAMEWORK +@@ -6893,7 +7033,7 @@ + dnl NOTE: Inform user how to proceed with files when cross compiling. + dnl Some cross-compile builds are predictable; they won't ever + dnl have /dev/ptmx or /dev/ptc, so we can set them explicitly. +-if test "$ac_sys_system" = "Linux-android" || test "$ac_sys_system" = "iOS"; then ++if test "$ac_sys_system" = "Linux-android" -o "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "watchOS" ; then + ac_cv_file__dev_ptmx=no + ac_cv_file__dev_ptc=no + else +@@ -7187,7 +7327,7 @@ + AS_CASE([$ac_sys_system], + [Emscripten], [with_ensurepip=no], + [WASI], [with_ensurepip=no], +- [iOS], [with_ensurepip=no], ++ [iOS|tvOS|watchOS], [with_ensurepip=no], + [with_ensurepip=upgrade] + ) + ]) +@@ -7598,7 +7738,7 @@ + [VxWorks*], [PY_STDLIB_MOD_SET_NA([_scproxy], [termios], [grp])], + dnl The _scproxy module is available on macOS + [Darwin], [], +- [iOS], [ ++ [iOS|tvOS|watchOS], [ + dnl subprocess and multiprocessing are not supported (no fork syscall). + dnl curses and tkinter user interface are not available. + dnl gdbm and nis aren't available +diff --git a/iOS/Resources/Info.plist.in b/iOS/Resources/Info.plist.in +index c3e261ecd9e..26ef7a95de4 100644 +--- a/iOS/Resources/Info.plist.in ++++ b/iOS/Resources/Info.plist.in +@@ -17,13 +17,13 @@ + CFBundlePackageType + FMWK + CFBundleShortVersionString +- @VERSION@ ++ %VERSION% + CFBundleLongVersionString + %VERSION%, (c) 2001-2024 Python Software Foundation. + CFBundleSignature + ???? + CFBundleVersion +- 1 ++ %VERSION% + CFBundleSupportedPlatforms + + iPhoneOS +--- /dev/null ++++ b/iOS/Resources/bin/arm64-apple-ios-macabi-ar +@@ -0,0 +1,2 @@ ++#!/bin/sh ++xcrun --sdk macosx${MACOSX_SDK_VERSION} ar "$@" +--- /dev/null ++++ b/iOS/Resources/bin/arm64-apple-ios-macabi-clang +@@ -0,0 +1,2 @@ ++#!/bin/sh ++xcrun --sdk macosx${MACOSX_SDK_VERSION} clang -target arm64-apple-ios-macabi "$@" +--- /dev/null ++++ b/iOS/Resources/bin/arm64-apple-ios-macabi-clang++ +@@ -0,0 +1,2 @@ ++#!/bin/sh ++xcrun --sdk macosx${MACOSX_SDK_VERSION} clang++ -target arm64-apple-ios-macabi "$@" +--- /dev/null ++++ b/iOS/Resources/bin/arm64-apple-ios-macabi-cpp +@@ -0,0 +1,2 @@ ++#!/bin/sh ++xcrun --sdk macosx${MACOSX_SDK_VERSION} clang -target arm64-apple-ios-macabi "$@" +--- /dev/null ++++ b/iOS/Resources/bin/x86_64-apple-ios-macabi-ar +@@ -0,0 +1,2 @@ ++#!/bin/sh ++xcrun --sdk macosx${MACOSX_SDK_VERSION} ar "$@" +--- /dev/null ++++ b/iOS/Resources/bin/x86_64-apple-ios-macabi-clang +@@ -0,0 +1,2 @@ ++#!/bin/sh ++xcrun --sdk macosx${MACOSX_SDK_VERSION} clang -target x86_64-apple-ios-macabi "$@" +--- /dev/null ++++ b/iOS/Resources/bin/x86_64-apple-ios-macabi-clang++ +@@ -0,0 +1,2 @@ ++#!/bin/sh ++xcrun --sdk macosx${MACOSX_SDK_VERSION} clang++ -target x86_64-apple-ios-macabi "$@" +--- /dev/null ++++ b/iOS/Resources/bin/x86_64-apple-ios-macabi-cpp +@@ -0,0 +1,2 @@ ++#!/bin/sh ++xcrun --sdk macosx${MACOSX_SDK_VERSION} clang -target x86_64-apple-ios-macabi "$@" +diff --git a/iOS/testbed/__main__.py b/iOS/testbed/__main__.py +index b4499f5ac17..d12a5ab065b 100644 +--- a/iOS/testbed/__main__.py ++++ b/iOS/testbed/__main__.py +@@ -82,19 +82,29 @@ -+/* Maximum length in bytes of a thread name */ -+#undef _PYTHREAD_NAME_MAXLEN + # Return a list of UDIDs associated with booted simulators + async def list_devices(): +- # List the testing simulators, in JSON format +- raw_json = await async_check_output( +- "xcrun", "simctl", "--set", "testing", "list", "-j" +- ) +- json_data = json.loads(raw_json) +- +- # Filter out the booted iOS simulators +- return [ +- simulator["udid"] +- for runtime, simulators in json_data["devices"].items() +- for simulator in simulators +- if runtime.split(".")[-1].startswith("iOS") and simulator["state"] == "Booted" +- ] ++ try: ++ # List the testing simulators, in JSON format ++ raw_json = await async_check_output( ++ "xcrun", "simctl", "--set", "testing", "list", "-j" ++ ) ++ json_data = json.loads(raw_json) + - /* Define to force use of thread-safe errno, h_errno, and other functions */ - #undef _REENTRANT - -@@ -1997,16 +2007,16 @@ - /* Define to 'long' if does not define clock_t. */ - #undef clock_t - --/* Define to empty if `const' does not conform to ANSI C. */ -+/* Define to empty if 'const' does not conform to ANSI C. */ - #undef const - --/* Define to `int' if doesn't define. */ -+/* Define as 'int' if doesn't define. */ - #undef gid_t - --/* Define to `int' if does not define. */ -+/* Define to 'int' if does not define. */ - #undef mode_t - --/* Define to `long int' if does not define. */ -+/* Define to 'long int' if does not define. */ - #undef off_t - - /* Define as a signed integer type capable of holding a process identifier. */ -@@ -2015,13 +2025,13 @@ - /* Define to empty if the keyword does not work. */ - #undef signed ++ # Filter out the booted iOS simulators ++ return [ ++ simulator["udid"] ++ for runtime, simulators in json_data["devices"].items() ++ for simulator in simulators ++ if runtime.split(".")[-1].startswith("iOS") and simulator["state"] == "Booted" ++ ] ++ except subprocess.CalledProcessError as e: ++ # If there's no ~/Library/Developer/XCTestDevices folder (which is the ++ # case on fresh installs, and in some CI environments), `simctl list` ++ # returns error code 1, rather than an empty list. Handle that case, ++ # but raise all other errors. ++ if e.returncode == 1: ++ return [] ++ else: ++ raise --/* Define to `unsigned int' if does not define. */ -+/* Define as 'unsigned int' if doesn't define. */ - #undef size_t - /* Define to 'int' if does not define. */ - #undef socklen_t + async def find_device(initial_devices): +@@ -230,33 +240,69 @@ + shutil.copytree(source, target, symlinks=True) + print(" done") --/* Define to `int' if doesn't define. */ -+/* Define as 'int' if doesn't define. */ - #undef uid_t ++ xc_framework_path = target / "Python.xcframework" ++ sim_framework_path = xc_framework_path / "ios-arm64_x86_64-simulator" + if framework is not None: + if framework.suffix == ".xcframework": + print(" Installing XCFramework...", end="", flush=True) +- xc_framework_path = (target / "Python.xcframework").resolve() + if xc_framework_path.is_dir(): + shutil.rmtree(xc_framework_path) + else: +- xc_framework_path.unlink() ++ xc_framework_path.unlink(missing_ok=True) + xc_framework_path.symlink_to( + framework.relative_to(xc_framework_path.parent, walk_up=True) + ) + print(" done") + else: + print(" Installing simulator framework...", end="", flush=True) +- sim_framework_path = ( +- target / "Python.xcframework" / "ios-arm64_x86_64-simulator" +- ).resolve() + if sim_framework_path.is_dir(): + shutil.rmtree(sim_framework_path) + else: +- sim_framework_path.unlink() ++ sim_framework_path.unlink(missing_ok=True) + sim_framework_path.symlink_to( + framework.relative_to(sim_framework_path.parent, walk_up=True) + ) + print(" done") + else: +- print(" Using pre-existing iOS framework.") ++ if ( ++ xc_framework_path.is_symlink() ++ and not xc_framework_path.readlink().is_absolute() ++ ): ++ # XCFramework is a relative symlink. Rewrite the symlink relative ++ # to the new location. ++ print(" Rewriting symlink to XCframework...", end="", flush=True) ++ orig_xc_framework_path = ( ++ source ++ / xc_framework_path.readlink() ++ ).resolve() ++ xc_framework_path.unlink() ++ xc_framework_path.symlink_to( ++ orig_xc_framework_path.relative_to( ++ xc_framework_path.parent, walk_up=True ++ ) ++ ) ++ print(" done") ++ elif ( ++ sim_framework_path.is_symlink() ++ and not sim_framework_path.readlink().is_absolute() ++ ): ++ print(" Rewriting symlink to simulator framework...", end="", flush=True) ++ # Simulator framework is a relative symlink. Rewrite the symlink ++ # relative to the new location. ++ orig_sim_framework_path = ( ++ source ++ / "Python.XCframework" ++ / sim_framework_path.readlink() ++ ).resolve() ++ sim_framework_path.unlink() ++ sim_framework_path.symlink_to( ++ orig_sim_framework_path.relative_to( ++ sim_framework_path.parent, walk_up=True ++ ) ++ ) ++ print(" done") ++ else: ++ print(" Using pre-existing iOS framework.") + for app_src in apps: + print(f" Installing app {app_src.name!r}...", end="", flush=True) +@@ -372,8 +418,8 @@ + if context.subcommand == "clone": + clone_testbed( +- source=Path(__file__).parent, +- target=Path(context.location), ++ source=Path(__file__).parent.resolve(), ++ target=Path(context.location).resolve(), + framework=Path(context.framework).resolve() if context.framework else None, + apps=[Path(app) for app in context.apps], + ) --- /dev/null +++ b/tvOS/README.rst @@ -0,0 +1,108 @@ From e8180332518e5691d49a1c33f9c7fb4a136f677f Mon Sep 17 00:00:00 2001 From: Andrew Savva Date: Sun, 9 Mar 2025 22:12:10 +0000 Subject: [PATCH 03/10] Update the MacCatalyst support, move to a separate target --- Makefile | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index a17e7d81..78752f72 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,6 @@ PYTHON_PKG_VERSION=$(PYTHON_VERSION) PYTHON_MICRO_VERSION=$(shell echo $(PYTHON_VERSION) | grep -Eo "\d+\.\d+\.\d+") PYTHON_PKG_MICRO_VERSION=$(shell echo $(PYTHON_PKG_VERSION) | grep -Eo "\d+\.\d+\.\d+") PYTHON_VER=$(basename $(PYTHON_VERSION)) -PYTHON_PATCHED_VERSION=$(PYTHON_VER)-patched # The binary releases of dependencies, published at: # https://github.com/beeware/cpython-apple-source-deps/releases @@ -43,7 +42,11 @@ TARGETS-macOS=macosx.x86_64 macosx.arm64 VERSION_MIN-macOS=11.0 # iOS targets -TARGETS-iOS=iphonesimulator.x86_64 iphonesimulator.arm64 iphoneos.arm64 maccatalyst.x86_64 maccatalyst.arm64 +TARGETS-iOS=iphonesimulator.x86_64 iphonesimulator.arm64 iphoneos.arm64 +VERSION_MIN-iOS=13.0 + +# MacCatalyst targets +TARGETS-iOS=maccatalyst.x86_64 maccatalyst.arm64 VERSION_MIN-iOS=14.2 # tvOS targets @@ -87,7 +90,7 @@ update-patch: # call if [ -z "$(PYTHON_REPO_DIR)" ]; then echo "\n\nPYTHON_REPO_DIR must be set to the root of your Python github checkout\n\n"; fi cd $(PYTHON_REPO_DIR) && \ - git diff -D v$(PYTHON_VERSION) $(PYTHON_PATCHED_VERSION) \ + git diff -D v$(PYTHON_VERSION) $(PYTHON_VER)-patched \ | PATH="/usr/local/bin:/opt/homebrew/bin:$(PATH)" filterdiff \ -X $(PROJECT_DIR)/patch/Python/diff.exclude -p 1 --clean \ > $(PROJECT_DIR)/patch/Python/Python.patch From 44529bfab1d0005e5e4faeab13edb4053278687f Mon Sep 17 00:00:00 2001 From: Andrew Savva Date: Sun, 9 Mar 2025 22:18:40 +0000 Subject: [PATCH 04/10] MacCatalyst support, update the python patch and separate out the MacCatalyst target --- Makefile | 6 +- patch/Python/Python.patch | 2404 +++++++++++++++++++++++++++++++------ 2 files changed, 2039 insertions(+), 371 deletions(-) diff --git a/Makefile b/Makefile index 78752f72..8f032a11 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ OPENSSL_VERSION=3.0.16-1 XZ_VERSION=5.6.4-1 # Supported OS -OS_LIST=macOS iOS tvOS watchOS +OS_LIST=macOS iOS tvOS watchOS MacCatalyst CURL_FLAGS=--disable --fail --location --create-dirs --progress-bar -L @@ -46,8 +46,8 @@ TARGETS-iOS=iphonesimulator.x86_64 iphonesimulator.arm64 iphoneos.arm64 VERSION_MIN-iOS=13.0 # MacCatalyst targets -TARGETS-iOS=maccatalyst.x86_64 maccatalyst.arm64 -VERSION_MIN-iOS=14.2 +TARGETS-MacCatalyst=maccatalyst.x86_64 maccatalyst.arm64 +VERSION_MIN-MacCatalyst=14.2 # tvOS targets TARGETS-tvOS=appletvsimulator.x86_64 appletvsimulator.arm64 appletvos.arm64 diff --git a/patch/Python/Python.patch b/patch/Python/Python.patch index c1c0196a..39690e71 100644 --- a/patch/Python/Python.patch +++ b/patch/Python/Python.patch @@ -131,6 +131,1990 @@ index 69f72452c40..34ce643340b 100644 else: import _osx_support osname, release, machine = _osx_support.get_platform_osx( +--- /dev/null ++++ b/MacCatalyst/README.rst +@@ -0,0 +1,375 @@ ++==================== ++Python on iOS README ++==================== ++ ++:Authors: ++ Russell Keith-Magee (2023-11) ++ ++This document provides a quick overview of some iOS specific features in the ++Python distribution. ++ ++These instructions are only needed if you're planning to compile Python for iOS ++yourself. Most users should *not* need to do this. If you're looking to ++experiment with writing an iOS app in Python, tools such as `BeeWare's Briefcase ++`__ and `Kivy's Buildozer ++`__ will provide a much more approachable ++user experience. ++ ++Compilers for building on iOS ++============================= ++ ++Building for iOS requires the use of Apple's Xcode tooling. It is strongly ++recommended that you use the most recent stable release of Xcode. This will ++require the use of the most (or second-most) recently released macOS version, ++as Apple does not maintain Xcode for older macOS versions. The Xcode Command ++Line Tools are not sufficient for iOS development; you need a *full* Xcode ++install. ++ ++If you want to run your code on the iOS simulator, you'll also need to install ++an iOS Simulator Platform. You should be prompted to select an iOS Simulator ++Platform when you first run Xcode. Alternatively, you can add an iOS Simulator ++Platform by selecting an open the Platforms tab of the Xcode Settings panel. ++ ++iOS specific arguments to configure ++=================================== ++ ++* ``--enable-framework[=DIR]`` ++ ++ This argument specifies the location where the Python.framework will be ++ installed. If ``DIR`` is not specified, the framework will be installed into ++ a subdirectory of the ``iOS/Frameworks`` folder. ++ ++ This argument *must* be provided when configuring iOS builds. iOS does not ++ support non-framework builds. ++ ++* ``--with-framework-name=NAME`` ++ ++ Specify the name for the Python framework; defaults to ``Python``. ++ ++ .. admonition:: Use this option with care! ++ ++ Unless you know what you're doing, changing the name of the Python ++ framework on iOS is not advised. If you use this option, you won't be able ++ to run the ``make testios`` target without making significant manual ++ alterations, and you won't be able to use any binary packages unless you ++ compile them yourself using your own framework name. ++ ++Building Python on iOS ++====================== ++ ++ABIs and Architectures ++---------------------- ++ ++iOS apps can be deployed on physical devices, and on the iOS simulator. Although ++the API used on these devices is identical, the ABI is different - you need to ++link against different libraries for an iOS device build (``iphoneos``) or an ++iOS simulator build (``iphonesimulator``). ++ ++Apple uses the ``XCframework`` format to allow specifying a single dependency ++that supports multiple ABIs. An ``XCframework`` is a wrapper around multiple ++ABI-specific frameworks that share a common API. ++ ++iOS can also support different CPU architectures within each ABI. At present, ++there is only a single supported architecture on physical devices - ARM64. ++However, the *simulator* supports 2 architectures - ARM64 (for running on Apple ++Silicon machines), and x86_64 (for running on older Intel-based machines). ++ ++To support multiple CPU architectures on a single platform, Apple uses a "fat ++binary" format - a single physical file that contains support for multiple ++architectures. It is possible to compile and use a "thin" single architecture ++version of a binary for testing purposes; however, the "thin" binary will not be ++portable to machines using other architectures. ++ ++Building a single-architecture framework ++---------------------------------------- ++ ++The Python build system will create a ``Python.framework`` that supports a ++*single* ABI with a *single* architecture. Unlike macOS, iOS does not allow a ++framework to contain non-library content, so the iOS build will produce a ++``bin`` and ``lib`` folder in the same output folder as ``Python.framework``. ++The ``lib`` folder will be needed at runtime to support the Python library. ++ ++If you want to use Python in a real iOS project, you need to produce multiple ++``Python.framework`` builds, one for each ABI and architecture. iOS builds of ++Python *must* be constructed as framework builds. To support this, you must ++provide the ``--enable-framework`` flag when configuring the build. The build ++also requires the use of cross-compilation. The minimal commands for building ++Python for the ARM64 iOS simulator will look something like:: ++ ++ $ export PATH="$(pwd)/iOS/Resources/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin" ++ $ ./configure \ ++ --enable-framework \ ++ --host=arm64-apple-ios-simulator \ ++ --build=arm64-apple-darwin \ ++ --with-build-python=/path/to/python.exe ++ $ make ++ $ make install ++ ++In this invocation: ++ ++* ``iOS/Resources/bin`` has been added to the path, providing some shims for the ++ compilers and linkers needed by the build. Xcode requires the use of ``xcrun`` ++ to invoke compiler tooling. However, if ``xcrun`` is pre-evaluated and the ++ result passed to ``configure``, these results can embed user- and ++ version-specific paths into the sysconfig data, which limits the portability ++ of the compiled Python. Alternatively, if ``xcrun`` is used *as* the compiler, ++ it requires that compiler variables like ``CC`` include spaces, which can ++ cause significant problems with many C configuration systems which assume that ++ ``CC`` will be a single executable. ++ ++ To work around this problem, the ``iOS/Resources/bin`` folder contains some ++ wrapper scripts that present as simple compilers and linkers, but wrap ++ underlying calls to ``xcrun``. This allows configure to use a ``CC`` ++ definition without spaces, and without user- or version-specific paths, while ++ retaining the ability to adapt to the local Xcode install. These scripts are ++ included in the ``bin`` directory of an iOS install. ++ ++ These scripts will, by default, use the currently active Xcode installation. ++ If you want to use a different Xcode installation, you can use ++ ``xcode-select`` to set a new default Xcode globally, or you can use the ++ ``DEVELOPER_DIR`` environment variable to specify an Xcode install. The ++ scripts will use the default ``iphoneos``/``iphonesimulator`` SDK version for ++ the select Xcode install; if you want to use a different SDK, you can set the ++ ``IOS_SDK_VERSION`` environment variable. (e.g, setting ++ ``IOS_SDK_VERSION=17.1`` would cause the scripts to use the ``iphoneos17.1`` ++ and ``iphonesimulator17.1`` SDKs, regardless of the Xcode default.) ++ ++ The path has also been cleared of any user customizations. A common source of ++ bugs is for tools like Homebrew to accidentally leak macOS binaries into an iOS ++ build. Resetting the path to a known "bare bones" value is the easiest way to ++ avoid these problems. ++ ++* ``--host`` is the architecture and ABI that you want to build, in GNU compiler ++ triple format. This will be one of: ++ ++ - ``arm64-apple-ios`` for ARM64 iOS devices. ++ - ``arm64-apple-ios-simulator`` for the iOS simulator running on Apple ++ Silicon devices. ++ - ``x86_64-apple-ios-simulator`` for the iOS simulator running on Intel ++ devices. ++ ++* ``--build`` is the GNU compiler triple for the machine that will be running ++ the compiler. This is one of: ++ ++ - ``arm64-apple-darwin`` for Apple Silicon devices. ++ - ``x86_64-apple-darwin`` for Intel devices. ++ ++* ``/path/to/python.exe`` is the path to a Python binary on the machine that ++ will be running the compiler. This is needed because the Python compilation ++ process involves running some Python code. On a normal desktop build of ++ Python, you can compile a python interpreter and then use that interpreter to ++ run Python code. However, the binaries produced for iOS won't run on macOS, so ++ you need to provide an external Python interpreter. This interpreter must be ++ the same version as the Python that is being compiled. To be completely safe, ++ this should be the *exact* same commit hash. However, the longer a Python ++ release has been stable, the more likely it is that this constraint can be ++ relaxed - the same micro version will often be sufficient. ++ ++* The ``install`` target for iOS builds is slightly different to other ++ platforms. On most platforms, ``make install`` will install the build into ++ the final runtime location. This won't be the case for iOS, as the final ++ runtime location will be on a physical device. ++ ++ However, you still need to run the ``install`` target for iOS builds, as it ++ performs some final framework assembly steps. The location specified with ++ ``--enable-framework`` will be the location where ``make install`` will ++ assemble the complete iOS framework. This completed framework can then ++ be copied and relocated as required. ++ ++For a full CPython build, you also need to specify the paths to iOS builds of ++the binary libraries that CPython depends on (XZ, BZip2, LibFFI and OpenSSL). ++This can be done by defining the ``LIBLZMA_CFLAGS``, ``LIBLZMA_LIBS``, ++``BZIP2_CFLAGS``, ``BZIP2_LIBS``, ``LIBFFI_CFLAGS``, and ``LIBFFI_LIBS`` ++environment variables, and the ``--with-openssl`` configure option. Versions of ++these libraries pre-compiled for iOS can be found in `this repository ++`__. LibFFI is ++especially important, as many parts of the standard library (including the ++``platform``, ``sysconfig`` and ``webbrowser`` modules) require the use of the ++``ctypes`` module at runtime. ++ ++By default, Python will be compiled with an iOS deployment target (i.e., the ++minimum supported iOS version) of 13.0. To specify a different deployment ++target, provide the version number as part of the ``--host`` argument - for ++example, ``--host=arm64-apple-ios15.4-simulator`` would compile an ARM64 ++simulator build with a deployment target of 15.4. ++ ++Merge thin frameworks into fat frameworks ++----------------------------------------- ++ ++Once you've built a ``Python.framework`` for each ABI and and architecture, you ++must produce a "fat" framework for each ABI that contains all the architectures ++for that ABI. ++ ++The ``iphoneos`` build only needs to support a single architecture, so it can be ++used without modification. ++ ++If you only want to support a single simulator architecture, (e.g., only support ++ARM64 simulators), you can use a single architecture ``Python.framework`` build. ++However, if you want to create ``Python.xcframework`` that supports *all* ++architectures, you'll need to merge the ``iphonesimulator`` builds for ARM64 and ++x86_64 into a single "fat" framework. ++ ++The "fat" framework can be constructed by performing a directory merge of the ++content of the two "thin" ``Python.framework`` directories, plus the ``bin`` and ++``lib`` folders for each thin framework. When performing this merge: ++ ++* The pure Python standard library content is identical for each architecture, ++ except for a handful of platform-specific files (such as the ``sysconfig`` ++ module). Ensure that the "fat" framework has the union of all standard library ++ files. ++ ++* Any binary files in the standard library, plus the main ++ ``libPython3.X.dylib``, can be merged using the ``lipo`` tool, provide by ++ Xcode:: ++ ++ $ lipo -create -output module.dylib path/to/x86_64/module.dylib path/to/arm64/module.dylib ++ ++* The header files will be identical on both architectures, except for ++ ``pyconfig.h``. Copy all the headers from one platform (say, arm64), rename ++ ``pyconfig.h`` to ``pyconfig-arm64.h``, and copy the ``pyconfig.h`` for the ++ other architecture into the merged header folder as ``pyconfig-x86_64.h``. ++ Then copy the ``iOS/Resources/pyconfig.h`` file from the CPython sources into ++ the merged headers folder. This will allow the two Python architectures to ++ share a common ``pyconfig.h`` header file. ++ ++At this point, you should have 2 Python.framework folders - one for ``iphoneos``, ++and one for ``iphonesimulator`` that is a merge of x86+64 and ARM64 content. ++ ++Merge frameworks into an XCframework ++------------------------------------ ++ ++Now that we have 2 (potentially fat) ABI-specific frameworks, we can merge those ++frameworks into a single ``XCframework``. ++ ++The initial skeleton of an ``XCframework`` is built using:: ++ ++ xcodebuild -create-xcframework -output Python.xcframework -framework path/to/iphoneos/Python.framework -framework path/to/iphonesimulator/Python.framework ++ ++Then, copy the ``bin`` and ``lib`` folders into the architecture-specific slices of ++the XCframework:: ++ ++ cp path/to/iphoneos/bin Python.xcframework/ios-arm64 ++ cp path/to/iphoneos/lib Python.xcframework/ios-arm64 ++ ++ cp path/to/iphonesimulator/bin Python.xcframework/ios-arm64_x86_64-simulator ++ cp path/to/iphonesimulator/lib Python.xcframework/ios-arm64_x86_64-simulator ++ ++Note that the name of the architecture-specific slice for the simulator will ++depend on the CPU architecture(s) that you build. ++ ++You now have a Python.xcframework that can be used in a project. ++ ++Testing Python on iOS ++===================== ++ ++The ``iOS/testbed`` folder that contains an Xcode project that is able to run ++the iOS test suite. This project converts the Python test suite into a single ++test case in Xcode's XCTest framework. The single XCTest passes if the test ++suite passes. ++ ++To run the test suite, configure a Python build for an iOS simulator (i.e., ++``--host=arm64-apple-ios-simulator`` or ``--host=x86_64-apple-ios-simulator`` ++), specifying a framework build (i.e. ``--enable-framework``). Ensure that your ++``PATH`` has been configured to include the ``iOS/Resources/bin`` folder and ++exclude any non-iOS tools, then run:: ++ ++ $ make all ++ $ make install ++ $ make testios ++ ++This will: ++ ++* Build an iOS framework for your chosen architecture; ++* Finalize the single-platform framework; ++* Make a clean copy of the testbed project; ++* Install the Python iOS framework into the copy of the testbed project; and ++* Run the test suite on an "iPhone SE (3rd generation)" simulator. ++ ++On success, the test suite will exit and report successful completion of the ++test suite. On a 2022 M1 MacBook Pro, the test suite takes approximately 15 ++minutes to run; a couple of extra minutes is required to compile the testbed ++project, and then boot and prepare the iOS simulator. ++ ++Debugging test failures ++----------------------- ++ ++Running ``make test`` generates a standalone version of the ``iOS/testbed`` ++project, and runs the full test suite. It does this using ``iOS/testbed`` ++itself - the folder is an executable module that can be used to create and run ++a clone of the testbed project. ++ ++You can generate your own standalone testbed instance by running:: ++ ++ $ python iOS/testbed clone --framework iOS/Frameworks/arm64-iphonesimulator my-testbed ++ ++This invocation assumes that ``iOS/Frameworks/arm64-iphonesimulator`` is the ++path to the iOS simulator framework for your platform (ARM64 in this case); ++``my-testbed`` is the name of the folder for the new testbed clone. ++ ++You can then use the ``my-testbed`` folder to run the Python test suite, ++passing in any command line arguments you may require. For example, if you're ++trying to diagnose a failure in the ``os`` module, you might run:: ++ ++ $ python my-testbed run -- test -W test_os ++ ++This is the equivalent of running ``python -m test -W test_os`` on a desktop ++Python build. Any arguments after the ``--`` will be passed to testbed as if ++they were arguments to ``python -m`` on a desktop machine. ++ ++You can also open the testbed project in Xcode by running:: ++ ++ $ open my-testbed/iOSTestbed.xcodeproj ++ ++This will allow you to use the full Xcode suite of tools for debugging. ++ ++Testing on an iOS device ++^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++To test on an iOS device, the app needs to be signed with known developer ++credentials. To obtain these credentials, you must have an iOS Developer ++account, and your Xcode install will need to be logged into your account (see ++the Accounts tab of the Preferences dialog). ++ ++Once the project is open, and you're signed into your Apple Developer account, ++select the root node of the project tree (labeled "iOSTestbed"), then the ++"Signing & Capabilities" tab in the details page. Select a development team ++(this will likely be your own name), and plug in a physical device to your ++macOS machine with a USB cable. You should then be able to select your physical ++device from the list of targets in the pulldown in the Xcode titlebar. ++ ++Running specific tests ++^^^^^^^^^^^^^^^^^^^^^^ ++ ++As the test suite is being executed on an iOS simulator, it is not possible to ++pass in command line arguments to configure test suite operation. To work ++around this limitation, the arguments that would normally be passed as command ++line arguments are configured as part of the ``iOSTestbed-Info.plist`` file ++that is used to configure the iOS testbed app. In this file, the ``TestArgs`` ++key is an array containing the arguments that would be passed to ``python -m`` ++on the command line (including ``test`` in position 0, the name of the test ++module to be executed). ++ ++Disabling automated breakpoints ++^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++By default, Xcode will inserts an automatic breakpoint whenever a signal is ++raised. The Python test suite raises many of these signals as part of normal ++operation; unless you are trying to diagnose an issue with signals, the ++automatic breakpoints can be inconvenient. However, they can be disabled by ++creating a symbolic breakpoint that is triggered at the start of the test run. ++ ++Select "Debug > Breakpoints > Create Symbolic Breakpoint" from the Xcode menu, and ++populate the new brewpoint with the following details: ++ ++* **Name**: IgnoreSignals ++* **Symbol**: UIApplicationMain ++* **Action**: Add debugger commands for: ++ - ``process handle SIGINT -n true -p true -s false`` ++ - ``process handle SIGUSR1 -n true -p true -s false`` ++ - ``process handle SIGUSR2 -n true -p true -s false`` ++ - ``process handle SIGXFSZ -n true -p true -s false`` ++* Check the "Automatically continue after evaluating" box. ++ ++All other details can be left blank. When the process executes the ++``UIApplicationMain`` entry point, the breakpoint will trigger, run the debugger ++commands to disable the automatic breakpoints, and automatically resume. +--- /dev/null ++++ b/MacCatalyst/Resources/Info.plist.in +@@ -0,0 +1,34 @@ ++ ++ ++ ++ ++ CFBundleDevelopmentRegion ++ en ++ CFBundleExecutable ++ Python ++ CFBundleGetInfoString ++ Python Runtime and Library ++ CFBundleIdentifier ++ @PYTHONFRAMEWORKIDENTIFIER@ ++ CFBundleInfoDictionaryVersion ++ 6.0 ++ CFBundleName ++ Python ++ CFBundlePackageType ++ FMWK ++ CFBundleShortVersionString ++ %VERSION% ++ CFBundleLongVersionString ++ %VERSION%, (c) 2001-2024 Python Software Foundation. ++ CFBundleSignature ++ ???? ++ CFBundleVersion ++ %VERSION% ++ CFBundleSupportedPlatforms ++ ++ iPhoneOS ++ ++ MinimumOSVersion ++ @IPHONEOS_DEPLOYMENT_TARGET@ ++ ++ +--- /dev/null ++++ b/MacCatalyst/Resources/bin/arm64-apple-ios-macabi-ar +@@ -0,0 +1,2 @@ ++#!/bin/sh ++xcrun --sdk macosx${MACOSX_SDK_VERSION} ar "$@" +--- /dev/null ++++ b/MacCatalyst/Resources/bin/arm64-apple-ios-macabi-clang +@@ -0,0 +1,2 @@ ++#!/bin/sh ++xcrun --sdk macosx${MACOSX_SDK_VERSION} clang -target arm64-apple-ios-macabi "$@" +--- /dev/null ++++ b/MacCatalyst/Resources/bin/arm64-apple-ios-macabi-clang++ +@@ -0,0 +1,2 @@ ++#!/bin/sh ++xcrun --sdk macosx${MACOSX_SDK_VERSION} clang++ -target arm64-apple-ios-macabi "$@" +--- /dev/null ++++ b/MacCatalyst/Resources/bin/arm64-apple-ios-macabi-cpp +@@ -0,0 +1,2 @@ ++#!/bin/sh ++xcrun --sdk macosx${MACOSX_SDK_VERSION} clang -target arm64-apple-ios-macabi "$@" +--- /dev/null ++++ b/MacCatalyst/Resources/bin/x86_64-apple-ios-macabi-ar +@@ -0,0 +1,2 @@ ++#!/bin/sh ++xcrun --sdk macosx${MACOSX_SDK_VERSION} ar "$@" +--- /dev/null ++++ b/MacCatalyst/Resources/bin/x86_64-apple-ios-macabi-clang +@@ -0,0 +1,2 @@ ++#!/bin/sh ++xcrun --sdk macosx${MACOSX_SDK_VERSION} clang -target x86_64-apple-ios-macabi "$@" +--- /dev/null ++++ b/MacCatalyst/Resources/bin/x86_64-apple-ios-macabi-clang++ +@@ -0,0 +1,2 @@ ++#!/bin/sh ++xcrun --sdk macosx${MACOSX_SDK_VERSION} clang++ -target x86_64-apple-ios-macabi "$@" +--- /dev/null ++++ b/MacCatalyst/Resources/bin/x86_64-apple-ios-macabi-cpp +@@ -0,0 +1,2 @@ ++#!/bin/sh ++xcrun --sdk macosx${MACOSX_SDK_VERSION} clang -target x86_64-apple-ios-macabi "$@" +--- /dev/null ++++ b/MacCatalyst/Resources/dylib-Info-template.plist +@@ -0,0 +1,26 @@ ++ ++ ++ ++ ++ CFBundleDevelopmentRegion ++ en ++ CFBundleExecutable ++ ++ CFBundleIdentifier ++ ++ CFBundleInfoDictionaryVersion ++ 6.0 ++ CFBundlePackageType ++ APPL ++ CFBundleShortVersionString ++ 1.0 ++ CFBundleSupportedPlatforms ++ ++ iPhoneOS ++ ++ MinimumOSVersion ++ 12.0 ++ CFBundleVersion ++ 1 ++ ++ +--- /dev/null ++++ b/MacCatalyst/Resources/pyconfig.h +@@ -0,0 +1,7 @@ ++#ifdef __arm64__ ++#include "pyconfig-arm64.h" ++#endif ++ ++#ifdef __x86_64__ ++#include "pyconfig-x86_64.h" ++#endif +--- /dev/null ++++ b/MacCatalyst/testbed/Python.xcframework/Info.plist +@@ -0,0 +1,44 @@ ++ ++ ++ ++ ++ AvailableLibraries ++ ++ ++ BinaryPath ++ Python.framework/Python ++ LibraryIdentifier ++ ios-arm64 ++ LibraryPath ++ Python.framework ++ SupportedArchitectures ++ ++ arm64 ++ ++ SupportedPlatform ++ ios ++ ++ ++ BinaryPath ++ Python.framework/Python ++ LibraryIdentifier ++ ios-arm64_x86_64-simulator ++ LibraryPath ++ Python.framework ++ SupportedArchitectures ++ ++ arm64 ++ x86_64 ++ ++ SupportedPlatform ++ ios ++ SupportedPlatformVariant ++ simulator ++ ++ ++ CFBundlePackageType ++ XFWK ++ XCFrameworkFormatVersion ++ 1.0 ++ ++ +--- /dev/null ++++ b/MacCatalyst/testbed/Python.xcframework/ios-arm64/README +@@ -0,0 +1,4 @@ ++This directory is intentionally empty. ++ ++It should be used as a target for `--enable-framework` when compiling an iOS on-device ++build for testing purposes. +--- /dev/null ++++ b/MacCatalyst/testbed/Python.xcframework/ios-arm64_x86_64-simulator/README +@@ -0,0 +1,4 @@ ++This directory is intentionally empty. ++ ++It should be used as a target for `--enable-framework` when compiling an iOS simulator ++build for testing purposes (either x86_64 or ARM64). +--- /dev/null ++++ b/MacCatalyst/testbed/__main__.py +@@ -0,0 +1,456 @@ ++import argparse ++import asyncio ++import json ++import plistlib ++import re ++import shutil ++import subprocess ++import sys ++from contextlib import asynccontextmanager ++from datetime import datetime ++from pathlib import Path ++ ++ ++DECODE_ARGS = ("UTF-8", "backslashreplace") ++ ++# The system log prefixes each line: ++# 2025-01-17 16:14:29.090 Df iOSTestbed[23987:1fd393b4] (Python) ... ++# 2025-01-17 16:14:29.090 E iOSTestbed[23987:1fd393b4] (Python) ... ++ ++LOG_PREFIX_REGEX = re.compile( ++ r"^\d{4}-\d{2}-\d{2}" # YYYY-MM-DD ++ r"\s+\d+:\d{2}:\d{2}\.\d+" # HH:MM:SS.sss ++ r"\s+\w+" # Df/E ++ r"\s+iOSTestbed\[\d+:\w+\]" # Process/thread ID ++ r"\s+\(Python\)\s" # Logger name ++) ++ ++ ++# Work around a bug involving sys.exit and TaskGroups ++# (https://github.com/python/cpython/issues/101515). ++def exit(*args): ++ raise MySystemExit(*args) ++ ++ ++class MySystemExit(Exception): ++ pass ++ ++ ++# All subprocesses are executed through this context manager so that no matter ++# what happens, they can always be cancelled from another task, and they will ++# always be cleaned up on exit. ++@asynccontextmanager ++async def async_process(*args, **kwargs): ++ process = await asyncio.create_subprocess_exec(*args, **kwargs) ++ try: ++ yield process ++ finally: ++ if process.returncode is None: ++ # Allow a reasonably long time for Xcode to clean itself up, ++ # because we don't want stale emulators left behind. ++ timeout = 10 ++ process.terminate() ++ try: ++ await asyncio.wait_for(process.wait(), timeout) ++ except TimeoutError: ++ print( ++ f"Command {args} did not terminate after {timeout} seconds " ++ f" - sending SIGKILL" ++ ) ++ process.kill() ++ ++ # Even after killing the process we must still wait for it, ++ # otherwise we'll get the warning "Exception ignored in __del__". ++ await asyncio.wait_for(process.wait(), timeout=1) ++ ++ ++async def async_check_output(*args, **kwargs): ++ async with async_process( ++ *args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs ++ ) as process: ++ stdout, stderr = await process.communicate() ++ if process.returncode == 0: ++ return stdout.decode(*DECODE_ARGS) ++ else: ++ raise subprocess.CalledProcessError( ++ process.returncode, ++ args, ++ stdout.decode(*DECODE_ARGS), ++ stderr.decode(*DECODE_ARGS), ++ ) ++ ++ ++# Return a list of UDIDs associated with booted simulators ++async def list_devices(): ++ try: ++ # List the testing simulators, in JSON format ++ raw_json = await async_check_output( ++ "xcrun", "simctl", "--set", "testing", "list", "-j" ++ ) ++ json_data = json.loads(raw_json) ++ ++ # Filter out the booted iOS simulators ++ return [ ++ simulator["udid"] ++ for runtime, simulators in json_data["devices"].items() ++ for simulator in simulators ++ if runtime.split(".")[-1].startswith("iOS") and simulator["state"] == "Booted" ++ ] ++ except subprocess.CalledProcessError as e: ++ # If there's no ~/Library/Developer/XCTestDevices folder (which is the ++ # case on fresh installs, and in some CI environments), `simctl list` ++ # returns error code 1, rather than an empty list. Handle that case, ++ # but raise all other errors. ++ if e.returncode == 1: ++ return [] ++ else: ++ raise ++ ++ ++async def find_device(initial_devices): ++ while True: ++ new_devices = set(await list_devices()).difference(initial_devices) ++ if len(new_devices) == 0: ++ await asyncio.sleep(1) ++ elif len(new_devices) == 1: ++ udid = new_devices.pop() ++ print(f"{datetime.now():%Y-%m-%d %H:%M:%S}: New test simulator detected") ++ print(f"UDID: {udid}") ++ return udid ++ else: ++ exit(f"Found more than one new device: {new_devices}") ++ ++ ++async def log_stream_task(initial_devices): ++ # Wait up to 5 minutes for the build to complete and the simulator to boot. ++ udid = await asyncio.wait_for(find_device(initial_devices), 5 * 60) ++ ++ # Stream the iOS device's logs, filtering out messages that come from the ++ # XCTest test suite (catching NSLog messages from the test method), or ++ # Python itself (catching stdout/stderr content routed to the system log ++ # with config->use_system_logger). ++ args = [ ++ "xcrun", ++ "simctl", ++ "--set", ++ "testing", ++ "spawn", ++ udid, ++ "log", ++ "stream", ++ "--style", ++ "compact", ++ "--predicate", ++ ( ++ 'senderImagePath ENDSWITH "/iOSTestbedTests.xctest/iOSTestbedTests"' ++ ' OR senderImagePath ENDSWITH "/Python.framework/Python"' ++ ), ++ ] ++ ++ async with async_process( ++ *args, ++ stdout=subprocess.PIPE, ++ stderr=subprocess.STDOUT, ++ ) as process: ++ suppress_dupes = False ++ while line := (await process.stdout.readline()).decode(*DECODE_ARGS): ++ # Strip the prefix from each log line ++ line = LOG_PREFIX_REGEX.sub("", line) ++ # The iOS log streamer can sometimes lag; when it does, it outputs ++ # a warning about messages being dropped... often multiple times. ++ # Only print the first of these duplicated warnings. ++ if line.startswith("=== Messages dropped "): ++ if not suppress_dupes: ++ suppress_dupes = True ++ sys.stdout.write(line) ++ else: ++ suppress_dupes = False ++ sys.stdout.write(line) ++ sys.stdout.flush() ++ ++ ++async def xcode_test(location, simulator, verbose): ++ # Run the test suite on the named simulator ++ print("Starting xcodebuild...") ++ args = [ ++ "xcodebuild", ++ "test", ++ "-project", ++ str(location / "iOSTestbed.xcodeproj"), ++ "-scheme", ++ "iOSTestbed", ++ "-destination", ++ f"platform=iOS Simulator,name={simulator}", ++ "-resultBundlePath", ++ str(location / f"{datetime.now():%Y%m%d-%H%M%S}.xcresult"), ++ "-derivedDataPath", ++ str(location / "DerivedData"), ++ ] ++ if not verbose: ++ args += ["-quiet"] ++ ++ async with async_process( ++ *args, ++ stdout=subprocess.PIPE, ++ stderr=subprocess.STDOUT, ++ ) as process: ++ while line := (await process.stdout.readline()).decode(*DECODE_ARGS): ++ sys.stdout.write(line) ++ sys.stdout.flush() ++ ++ status = await asyncio.wait_for(process.wait(), timeout=1) ++ exit(status) ++ ++ ++def clone_testbed( ++ source: Path, ++ target: Path, ++ framework: Path, ++ apps: list[Path], ++) -> None: ++ if target.exists(): ++ print(f"{target} already exists; aborting without creating project.") ++ sys.exit(10) ++ ++ if framework is None: ++ if not ( ++ source / "Python.xcframework/ios-arm64_x86_64-simulator/bin" ++ ).is_dir(): ++ print( ++ f"The testbed being cloned ({source}) does not contain " ++ f"a simulator framework. Re-run with --framework" ++ ) ++ sys.exit(11) ++ else: ++ if not framework.is_dir(): ++ print(f"{framework} does not exist.") ++ sys.exit(12) ++ elif not ( ++ framework.suffix == ".xcframework" ++ or (framework / "Python.framework").is_dir() ++ ): ++ print( ++ f"{framework} is not an XCframework, " ++ f"or a simulator slice of a framework build." ++ ) ++ sys.exit(13) ++ ++ print("Cloning testbed project:") ++ print(f" Cloning {source}...", end="", flush=True) ++ shutil.copytree(source, target, symlinks=True) ++ print(" done") ++ ++ xc_framework_path = target / "Python.xcframework" ++ sim_framework_path = xc_framework_path / "ios-arm64_x86_64-simulator" ++ if framework is not None: ++ if framework.suffix == ".xcframework": ++ print(" Installing XCFramework...", end="", flush=True) ++ if xc_framework_path.is_dir(): ++ shutil.rmtree(xc_framework_path) ++ else: ++ xc_framework_path.unlink(missing_ok=True) ++ xc_framework_path.symlink_to( ++ framework.relative_to(xc_framework_path.parent, walk_up=True) ++ ) ++ print(" done") ++ else: ++ print(" Installing simulator framework...", end="", flush=True) ++ if sim_framework_path.is_dir(): ++ shutil.rmtree(sim_framework_path) ++ else: ++ sim_framework_path.unlink(missing_ok=True) ++ sim_framework_path.symlink_to( ++ framework.relative_to(sim_framework_path.parent, walk_up=True) ++ ) ++ print(" done") ++ else: ++ if ( ++ xc_framework_path.is_symlink() ++ and not xc_framework_path.readlink().is_absolute() ++ ): ++ # XCFramework is a relative symlink. Rewrite the symlink relative ++ # to the new location. ++ print(" Rewriting symlink to XCframework...", end="", flush=True) ++ orig_xc_framework_path = ( ++ source ++ / xc_framework_path.readlink() ++ ).resolve() ++ xc_framework_path.unlink() ++ xc_framework_path.symlink_to( ++ orig_xc_framework_path.relative_to( ++ xc_framework_path.parent, walk_up=True ++ ) ++ ) ++ print(" done") ++ elif ( ++ sim_framework_path.is_symlink() ++ and not sim_framework_path.readlink().is_absolute() ++ ): ++ print(" Rewriting symlink to simulator framework...", end="", flush=True) ++ # Simulator framework is a relative symlink. Rewrite the symlink ++ # relative to the new location. ++ orig_sim_framework_path = ( ++ source ++ / "Python.XCframework" ++ / sim_framework_path.readlink() ++ ).resolve() ++ sim_framework_path.unlink() ++ sim_framework_path.symlink_to( ++ orig_sim_framework_path.relative_to( ++ sim_framework_path.parent, walk_up=True ++ ) ++ ) ++ print(" done") ++ else: ++ print(" Using pre-existing iOS framework.") ++ ++ for app_src in apps: ++ print(f" Installing app {app_src.name!r}...", end="", flush=True) ++ app_target = target / f"iOSTestbed/app/{app_src.name}" ++ if app_target.is_dir(): ++ shutil.rmtree(app_target) ++ shutil.copytree(app_src, app_target) ++ print(" done") ++ ++ print(f"Successfully cloned testbed: {target.resolve()}") ++ ++ ++def update_plist(testbed_path, args): ++ # Add the test runner arguments to the testbed's Info.plist file. ++ info_plist = testbed_path / "iOSTestbed" / "iOSTestbed-Info.plist" ++ with info_plist.open("rb") as f: ++ info = plistlib.load(f) ++ ++ info["TestArgs"] = args ++ ++ with info_plist.open("wb") as f: ++ plistlib.dump(info, f) ++ ++ ++async def run_testbed(simulator: str, args: list[str], verbose: bool=False): ++ location = Path(__file__).parent ++ print("Updating plist...", end="", flush=True) ++ update_plist(location, args) ++ print(" done.") ++ ++ # Get the list of devices that are booted at the start of the test run. ++ # The simulator started by the test suite will be detected as the new ++ # entry that appears on the device list. ++ initial_devices = await list_devices() ++ ++ try: ++ async with asyncio.TaskGroup() as tg: ++ tg.create_task(log_stream_task(initial_devices)) ++ tg.create_task(xcode_test(location, simulator=simulator, verbose=verbose)) ++ except* MySystemExit as e: ++ raise SystemExit(*e.exceptions[0].args) from None ++ except* subprocess.CalledProcessError as e: ++ # Extract it from the ExceptionGroup so it can be handled by `main`. ++ raise e.exceptions[0] ++ ++ ++def main(): ++ parser = argparse.ArgumentParser( ++ description=( ++ "Manages the process of testing a Python project in the iOS simulator." ++ ), ++ ) ++ ++ subcommands = parser.add_subparsers(dest="subcommand") ++ ++ clone = subcommands.add_parser( ++ "clone", ++ description=( ++ "Clone the testbed project, copying in an iOS Python framework and" ++ "any specified application code." ++ ), ++ help="Clone a testbed project to a new location.", ++ ) ++ clone.add_argument( ++ "--framework", ++ help=( ++ "The location of the XCFramework (or simulator-only slice of an " ++ "XCFramework) to use when running the testbed" ++ ), ++ ) ++ clone.add_argument( ++ "--app", ++ dest="apps", ++ action="append", ++ default=[], ++ help="The location of any code to include in the testbed project", ++ ) ++ clone.add_argument( ++ "location", ++ help="The path where the testbed will be cloned.", ++ ) ++ ++ run = subcommands.add_parser( ++ "run", ++ usage="%(prog)s [-h] [--simulator SIMULATOR] -- [ ...]", ++ description=( ++ "Run a testbed project. The arguments provided after `--` will be " ++ "passed to the running iOS process as if they were arguments to " ++ "`python -m`." ++ ), ++ help="Run a testbed project", ++ ) ++ run.add_argument( ++ "--simulator", ++ default="iPhone SE (3rd Generation)", ++ help="The name of the simulator to use (default: 'iPhone SE (3rd Generation)')", ++ ) ++ run.add_argument( ++ "-v", "--verbose", ++ action="store_true", ++ help="Enable verbose output", ++ ) ++ ++ try: ++ pos = sys.argv.index("--") ++ testbed_args = sys.argv[1:pos] ++ test_args = sys.argv[pos + 1 :] ++ except ValueError: ++ testbed_args = sys.argv[1:] ++ test_args = [] ++ ++ context = parser.parse_args(testbed_args) ++ ++ if context.subcommand == "clone": ++ clone_testbed( ++ source=Path(__file__).parent.resolve(), ++ target=Path(context.location).resolve(), ++ framework=Path(context.framework).resolve() if context.framework else None, ++ apps=[Path(app) for app in context.apps], ++ ) ++ elif context.subcommand == "run": ++ if test_args: ++ if not ( ++ Path(__file__).parent / "Python.xcframework/ios-arm64_x86_64-simulator/bin" ++ ).is_dir(): ++ print( ++ f"Testbed does not contain a compiled iOS framework. Use " ++ f"`python {sys.argv[0]} clone ...` to create a runnable " ++ f"clone of this testbed." ++ ) ++ sys.exit(20) ++ ++ asyncio.run( ++ run_testbed( ++ simulator=context.simulator, ++ verbose=context.verbose, ++ args=test_args, ++ ) ++ ) ++ else: ++ print(f"Must specify test arguments (e.g., {sys.argv[0]} run -- test)") ++ print() ++ parser.print_help(sys.stderr) ++ sys.exit(21) ++ else: ++ parser.print_help(sys.stderr) ++ sys.exit(1) ++ ++ ++if __name__ == "__main__": ++ main() +--- /dev/null ++++ b/MacCatalyst/testbed/iOSTestbed.xcodeproj/project.pbxproj +@@ -0,0 +1,580 @@ ++// !$*UTF8*$! ++{ ++ archiveVersion = 1; ++ classes = { ++ }; ++ objectVersion = 56; ++ objects = { ++ ++/* Begin PBXBuildFile section */ ++ 607A66172B0EFA380010BFC8 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 607A66162B0EFA380010BFC8 /* AppDelegate.m */; }; ++ 607A66222B0EFA390010BFC8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607A66212B0EFA390010BFC8 /* Assets.xcassets */; }; ++ 607A66252B0EFA390010BFC8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 607A66232B0EFA390010BFC8 /* LaunchScreen.storyboard */; }; ++ 607A66282B0EFA390010BFC8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 607A66272B0EFA390010BFC8 /* main.m */; }; ++ 607A66322B0EFA3A0010BFC8 /* iOSTestbedTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 607A66312B0EFA3A0010BFC8 /* iOSTestbedTests.m */; }; ++ 607A664C2B0EFC080010BFC8 /* Python.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 607A664A2B0EFB310010BFC8 /* Python.xcframework */; }; ++ 607A664D2B0EFC080010BFC8 /* Python.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 607A664A2B0EFB310010BFC8 /* Python.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; ++ 607A66502B0EFFE00010BFC8 /* Python.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 607A664A2B0EFB310010BFC8 /* Python.xcframework */; }; ++ 607A66512B0EFFE00010BFC8 /* Python.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 607A664A2B0EFB310010BFC8 /* Python.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; ++ 607A66582B0F079F0010BFC8 /* dylib-Info-template.plist in Resources */ = {isa = PBXBuildFile; fileRef = 607A66572B0F079F0010BFC8 /* dylib-Info-template.plist */; }; ++ 608619542CB77BA900F46182 /* app_packages in Resources */ = {isa = PBXBuildFile; fileRef = 608619532CB77BA900F46182 /* app_packages */; }; ++ 608619562CB7819B00F46182 /* app in Resources */ = {isa = PBXBuildFile; fileRef = 608619552CB7819B00F46182 /* app */; }; ++/* End PBXBuildFile section */ ++ ++/* Begin PBXContainerItemProxy section */ ++ 607A662E2B0EFA3A0010BFC8 /* PBXContainerItemProxy */ = { ++ isa = PBXContainerItemProxy; ++ containerPortal = 607A660A2B0EFA380010BFC8 /* Project object */; ++ proxyType = 1; ++ remoteGlobalIDString = 607A66112B0EFA380010BFC8; ++ remoteInfo = iOSTestbed; ++ }; ++/* End PBXContainerItemProxy section */ ++ ++/* Begin PBXCopyFilesBuildPhase section */ ++ 607A664E2B0EFC080010BFC8 /* Embed Frameworks */ = { ++ isa = PBXCopyFilesBuildPhase; ++ buildActionMask = 2147483647; ++ dstPath = ""; ++ dstSubfolderSpec = 10; ++ files = ( ++ 607A664D2B0EFC080010BFC8 /* Python.xcframework in Embed Frameworks */, ++ ); ++ name = "Embed Frameworks"; ++ runOnlyForDeploymentPostprocessing = 0; ++ }; ++ 607A66522B0EFFE00010BFC8 /* Embed Frameworks */ = { ++ isa = PBXCopyFilesBuildPhase; ++ buildActionMask = 2147483647; ++ dstPath = ""; ++ dstSubfolderSpec = 10; ++ files = ( ++ 607A66512B0EFFE00010BFC8 /* Python.xcframework in Embed Frameworks */, ++ ); ++ name = "Embed Frameworks"; ++ runOnlyForDeploymentPostprocessing = 0; ++ }; ++/* End PBXCopyFilesBuildPhase section */ ++ ++/* Begin PBXFileReference section */ ++ 607A66122B0EFA380010BFC8 /* iOSTestbed.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iOSTestbed.app; sourceTree = BUILT_PRODUCTS_DIR; }; ++ 607A66152B0EFA380010BFC8 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; ++ 607A66162B0EFA380010BFC8 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; ++ 607A66212B0EFA390010BFC8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; ++ 607A66242B0EFA390010BFC8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; ++ 607A66272B0EFA390010BFC8 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; ++ 607A662D2B0EFA3A0010BFC8 /* iOSTestbedTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = iOSTestbedTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; ++ 607A66312B0EFA3A0010BFC8 /* iOSTestbedTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = iOSTestbedTests.m; sourceTree = ""; }; ++ 607A664A2B0EFB310010BFC8 /* Python.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Python.xcframework; sourceTree = ""; }; ++ 607A66572B0F079F0010BFC8 /* dylib-Info-template.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "dylib-Info-template.plist"; sourceTree = ""; }; ++ 607A66592B0F08600010BFC8 /* iOSTestbed-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "iOSTestbed-Info.plist"; sourceTree = ""; }; ++ 608619532CB77BA900F46182 /* app_packages */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app_packages; sourceTree = ""; }; ++ 608619552CB7819B00F46182 /* app */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app; sourceTree = ""; }; ++/* End PBXFileReference section */ ++ ++/* Begin PBXFrameworksBuildPhase section */ ++ 607A660F2B0EFA380010BFC8 /* Frameworks */ = { ++ isa = PBXFrameworksBuildPhase; ++ buildActionMask = 2147483647; ++ files = ( ++ 607A664C2B0EFC080010BFC8 /* Python.xcframework in Frameworks */, ++ ); ++ runOnlyForDeploymentPostprocessing = 0; ++ }; ++ 607A662A2B0EFA3A0010BFC8 /* Frameworks */ = { ++ isa = PBXFrameworksBuildPhase; ++ buildActionMask = 2147483647; ++ files = ( ++ 607A66502B0EFFE00010BFC8 /* Python.xcframework in Frameworks */, ++ ); ++ runOnlyForDeploymentPostprocessing = 0; ++ }; ++/* End PBXFrameworksBuildPhase section */ ++ ++/* Begin PBXGroup section */ ++ 607A66092B0EFA380010BFC8 = { ++ isa = PBXGroup; ++ children = ( ++ 607A664A2B0EFB310010BFC8 /* Python.xcframework */, ++ 607A66142B0EFA380010BFC8 /* iOSTestbed */, ++ 607A66302B0EFA3A0010BFC8 /* iOSTestbedTests */, ++ 607A66132B0EFA380010BFC8 /* Products */, ++ 607A664F2B0EFFE00010BFC8 /* Frameworks */, ++ ); ++ sourceTree = ""; ++ }; ++ 607A66132B0EFA380010BFC8 /* Products */ = { ++ isa = PBXGroup; ++ children = ( ++ 607A66122B0EFA380010BFC8 /* iOSTestbed.app */, ++ 607A662D2B0EFA3A0010BFC8 /* iOSTestbedTests.xctest */, ++ ); ++ name = Products; ++ sourceTree = ""; ++ }; ++ 607A66142B0EFA380010BFC8 /* iOSTestbed */ = { ++ isa = PBXGroup; ++ children = ( ++ 608619552CB7819B00F46182 /* app */, ++ 608619532CB77BA900F46182 /* app_packages */, ++ 607A66592B0F08600010BFC8 /* iOSTestbed-Info.plist */, ++ 607A66572B0F079F0010BFC8 /* dylib-Info-template.plist */, ++ 607A66152B0EFA380010BFC8 /* AppDelegate.h */, ++ 607A66162B0EFA380010BFC8 /* AppDelegate.m */, ++ 607A66212B0EFA390010BFC8 /* Assets.xcassets */, ++ 607A66232B0EFA390010BFC8 /* LaunchScreen.storyboard */, ++ 607A66272B0EFA390010BFC8 /* main.m */, ++ ); ++ path = iOSTestbed; ++ sourceTree = ""; ++ }; ++ 607A66302B0EFA3A0010BFC8 /* iOSTestbedTests */ = { ++ isa = PBXGroup; ++ children = ( ++ 607A66312B0EFA3A0010BFC8 /* iOSTestbedTests.m */, ++ ); ++ path = iOSTestbedTests; ++ sourceTree = ""; ++ }; ++ 607A664F2B0EFFE00010BFC8 /* Frameworks */ = { ++ isa = PBXGroup; ++ children = ( ++ ); ++ name = Frameworks; ++ sourceTree = ""; ++ }; ++/* End PBXGroup section */ ++ ++/* Begin PBXNativeTarget section */ ++ 607A66112B0EFA380010BFC8 /* iOSTestbed */ = { ++ isa = PBXNativeTarget; ++ buildConfigurationList = 607A66412B0EFA3A0010BFC8 /* Build configuration list for PBXNativeTarget "iOSTestbed" */; ++ buildPhases = ( ++ 607A660E2B0EFA380010BFC8 /* Sources */, ++ 607A660F2B0EFA380010BFC8 /* Frameworks */, ++ 607A66102B0EFA380010BFC8 /* Resources */, ++ 607A66552B0F061D0010BFC8 /* Install Target Specific Python Standard Library */, ++ 607A66562B0F06200010BFC8 /* Prepare Python Binary Modules */, ++ 607A664E2B0EFC080010BFC8 /* Embed Frameworks */, ++ ); ++ buildRules = ( ++ ); ++ dependencies = ( ++ ); ++ name = iOSTestbed; ++ productName = iOSTestbed; ++ productReference = 607A66122B0EFA380010BFC8 /* iOSTestbed.app */; ++ productType = "com.apple.product-type.application"; ++ }; ++ 607A662C2B0EFA3A0010BFC8 /* iOSTestbedTests */ = { ++ isa = PBXNativeTarget; ++ buildConfigurationList = 607A66442B0EFA3A0010BFC8 /* Build configuration list for PBXNativeTarget "iOSTestbedTests" */; ++ buildPhases = ( ++ 607A66292B0EFA3A0010BFC8 /* Sources */, ++ 607A662A2B0EFA3A0010BFC8 /* Frameworks */, ++ 607A662B2B0EFA3A0010BFC8 /* Resources */, ++ 607A66522B0EFFE00010BFC8 /* Embed Frameworks */, ++ ); ++ buildRules = ( ++ ); ++ dependencies = ( ++ 607A662F2B0EFA3A0010BFC8 /* PBXTargetDependency */, ++ ); ++ name = iOSTestbedTests; ++ productName = iOSTestbedTests; ++ productReference = 607A662D2B0EFA3A0010BFC8 /* iOSTestbedTests.xctest */; ++ productType = "com.apple.product-type.bundle.unit-test"; ++ }; ++/* End PBXNativeTarget section */ ++ ++/* Begin PBXProject section */ ++ 607A660A2B0EFA380010BFC8 /* Project object */ = { ++ isa = PBXProject; ++ attributes = { ++ BuildIndependentTargetsInParallel = 1; ++ LastUpgradeCheck = 1500; ++ TargetAttributes = { ++ 607A66112B0EFA380010BFC8 = { ++ CreatedOnToolsVersion = 15.0.1; ++ }; ++ 607A662C2B0EFA3A0010BFC8 = { ++ CreatedOnToolsVersion = 15.0.1; ++ TestTargetID = 607A66112B0EFA380010BFC8; ++ }; ++ }; ++ }; ++ buildConfigurationList = 607A660D2B0EFA380010BFC8 /* Build configuration list for PBXProject "iOSTestbed" */; ++ compatibilityVersion = "Xcode 14.0"; ++ developmentRegion = en; ++ hasScannedForEncodings = 0; ++ knownRegions = ( ++ en, ++ Base, ++ ); ++ mainGroup = 607A66092B0EFA380010BFC8; ++ productRefGroup = 607A66132B0EFA380010BFC8 /* Products */; ++ projectDirPath = ""; ++ projectRoot = ""; ++ targets = ( ++ 607A66112B0EFA380010BFC8 /* iOSTestbed */, ++ 607A662C2B0EFA3A0010BFC8 /* iOSTestbedTests */, ++ ); ++ }; ++/* End PBXProject section */ ++ ++/* Begin PBXResourcesBuildPhase section */ ++ 607A66102B0EFA380010BFC8 /* Resources */ = { ++ isa = PBXResourcesBuildPhase; ++ buildActionMask = 2147483647; ++ files = ( ++ 607A66252B0EFA390010BFC8 /* LaunchScreen.storyboard in Resources */, ++ 607A66582B0F079F0010BFC8 /* dylib-Info-template.plist in Resources */, ++ 608619562CB7819B00F46182 /* app in Resources */, ++ 607A66222B0EFA390010BFC8 /* Assets.xcassets in Resources */, ++ 608619542CB77BA900F46182 /* app_packages in Resources */, ++ ); ++ runOnlyForDeploymentPostprocessing = 0; ++ }; ++ 607A662B2B0EFA3A0010BFC8 /* Resources */ = { ++ isa = PBXResourcesBuildPhase; ++ buildActionMask = 2147483647; ++ files = ( ++ ); ++ runOnlyForDeploymentPostprocessing = 0; ++ }; ++/* End PBXResourcesBuildPhase section */ ++ ++/* Begin PBXShellScriptBuildPhase section */ ++ 607A66552B0F061D0010BFC8 /* Install Target Specific Python Standard Library */ = { ++ isa = PBXShellScriptBuildPhase; ++ alwaysOutOfDate = 1; ++ buildActionMask = 2147483647; ++ files = ( ++ ); ++ inputFileListPaths = ( ++ ); ++ inputPaths = ( ++ ); ++ name = "Install Target Specific Python Standard Library"; ++ outputFileListPaths = ( ++ ); ++ outputPaths = ( ++ ); ++ runOnlyForDeploymentPostprocessing = 0; ++ shellPath = /bin/sh; ++ shellScript = "set -e\n\nmkdir -p \"$CODESIGNING_FOLDER_PATH/python/lib\"\nif [ \"$EFFECTIVE_PLATFORM_NAME\" = \"-iphonesimulator\" ]; then\n echo \"Installing Python modules for iOS Simulator\"\n rsync -au --delete \"$PROJECT_DIR/Python.xcframework/ios-arm64_x86_64-simulator/lib/\" \"$CODESIGNING_FOLDER_PATH/python/lib/\" \nelse\n echo \"Installing Python modules for iOS Device\"\n rsync -au --delete \"$PROJECT_DIR/Python.xcframework/ios-arm64/lib/\" \"$CODESIGNING_FOLDER_PATH/python/lib/\" \nfi\n"; ++ showEnvVarsInLog = 0; ++ }; ++ 607A66562B0F06200010BFC8 /* Prepare Python Binary Modules */ = { ++ isa = PBXShellScriptBuildPhase; ++ alwaysOutOfDate = 1; ++ buildActionMask = 2147483647; ++ files = ( ++ ); ++ inputFileListPaths = ( ++ ); ++ inputPaths = ( ++ ); ++ name = "Prepare Python Binary Modules"; ++ outputFileListPaths = ( ++ ); ++ outputPaths = ( ++ ); ++ runOnlyForDeploymentPostprocessing = 0; ++ shellPath = /bin/sh; ++ shellScript = "set -e\n\ninstall_dylib () {\n INSTALL_BASE=$1\n FULL_EXT=$2\n\n # The name of the extension file\n EXT=$(basename \"$FULL_EXT\")\n # The location of the extension file, relative to the bundle\n RELATIVE_EXT=${FULL_EXT#$CODESIGNING_FOLDER_PATH/} \n # The path to the extension file, relative to the install base\n PYTHON_EXT=${RELATIVE_EXT/$INSTALL_BASE/}\n # The full dotted name of the extension module, constructed from the file path.\n FULL_MODULE_NAME=$(echo $PYTHON_EXT | cut -d \".\" -f 1 | tr \"/\" \".\"); \n # A bundle identifier; not actually used, but required by Xcode framework packaging\n FRAMEWORK_BUNDLE_ID=$(echo $PRODUCT_BUNDLE_IDENTIFIER.$FULL_MODULE_NAME | tr \"_\" \"-\")\n # The name of the framework folder.\n FRAMEWORK_FOLDER=\"Frameworks/$FULL_MODULE_NAME.framework\"\n\n # If the framework folder doesn't exist, create it.\n if [ ! -d \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER\" ]; then\n echo \"Creating framework for $RELATIVE_EXT\" \n mkdir -p \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER\"\n cp \"$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\"\n plutil -replace CFBundleExecutable -string \"$FULL_MODULE_NAME\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\"\n plutil -replace CFBundleIdentifier -string \"$FRAMEWORK_BUNDLE_ID\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\"\n fi\n \n echo \"Installing binary for $FRAMEWORK_FOLDER/$FULL_MODULE_NAME\" \n mv \"$FULL_EXT\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/$FULL_MODULE_NAME\"\n # Create a placeholder .fwork file where the .so was\n echo \"$FRAMEWORK_FOLDER/$FULL_MODULE_NAME\" > ${FULL_EXT%.so}.fwork\n # Create a back reference to the .so file location in the framework\n echo \"${RELATIVE_EXT%.so}.fwork\" > \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/$FULL_MODULE_NAME.origin\" \n}\n\nPYTHON_VER=$(ls -1 \"$CODESIGNING_FOLDER_PATH/python/lib\")\necho \"Install Python $PYTHON_VER standard library extension modules...\"\nfind \"$CODESIGNING_FOLDER_PATH/python/lib/$PYTHON_VER/lib-dynload\" -name \"*.so\" | while read FULL_EXT; do\n install_dylib python/lib/$PYTHON_VER/lib-dynload/ \"$FULL_EXT\"\ndone\necho \"Install app package extension modules...\"\nfind \"$CODESIGNING_FOLDER_PATH/app_packages\" -name \"*.so\" | while read FULL_EXT; do\n install_dylib app_packages/ \"$FULL_EXT\"\ndone\necho \"Install app extension modules...\"\nfind \"$CODESIGNING_FOLDER_PATH/app\" -name \"*.so\" | while read FULL_EXT; do\n install_dylib app/ \"$FULL_EXT\"\ndone\n\n# Clean up dylib template \nrm -f \"$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist\"\necho \"Signing frameworks as $EXPANDED_CODE_SIGN_IDENTITY_NAME ($EXPANDED_CODE_SIGN_IDENTITY)...\"\nfind \"$CODESIGNING_FOLDER_PATH/Frameworks\" -name \"*.framework\" -exec /usr/bin/codesign --force --sign \"$EXPANDED_CODE_SIGN_IDENTITY\" ${OTHER_CODE_SIGN_FLAGS:-} -o runtime --timestamp=none --preserve-metadata=identifier,entitlements,flags --generate-entitlement-der \"{}\" \\; \n"; ++ showEnvVarsInLog = 0; ++ }; ++/* End PBXShellScriptBuildPhase section */ ++ ++/* Begin PBXSourcesBuildPhase section */ ++ 607A660E2B0EFA380010BFC8 /* Sources */ = { ++ isa = PBXSourcesBuildPhase; ++ buildActionMask = 2147483647; ++ files = ( ++ 607A66172B0EFA380010BFC8 /* AppDelegate.m in Sources */, ++ 607A66282B0EFA390010BFC8 /* main.m in Sources */, ++ ); ++ runOnlyForDeploymentPostprocessing = 0; ++ }; ++ 607A66292B0EFA3A0010BFC8 /* Sources */ = { ++ isa = PBXSourcesBuildPhase; ++ buildActionMask = 2147483647; ++ files = ( ++ 607A66322B0EFA3A0010BFC8 /* iOSTestbedTests.m in Sources */, ++ ); ++ runOnlyForDeploymentPostprocessing = 0; ++ }; ++/* End PBXSourcesBuildPhase section */ ++ ++/* Begin PBXTargetDependency section */ ++ 607A662F2B0EFA3A0010BFC8 /* PBXTargetDependency */ = { ++ isa = PBXTargetDependency; ++ target = 607A66112B0EFA380010BFC8 /* iOSTestbed */; ++ targetProxy = 607A662E2B0EFA3A0010BFC8 /* PBXContainerItemProxy */; ++ }; ++/* End PBXTargetDependency section */ ++ ++/* Begin PBXVariantGroup section */ ++ 607A66232B0EFA390010BFC8 /* LaunchScreen.storyboard */ = { ++ isa = PBXVariantGroup; ++ children = ( ++ 607A66242B0EFA390010BFC8 /* Base */, ++ ); ++ name = LaunchScreen.storyboard; ++ sourceTree = ""; ++ }; ++/* End PBXVariantGroup section */ ++ ++/* Begin XCBuildConfiguration section */ ++ 607A663F2B0EFA3A0010BFC8 /* Debug */ = { ++ isa = XCBuildConfiguration; ++ buildSettings = { ++ ALWAYS_SEARCH_USER_PATHS = NO; ++ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; ++ CLANG_ANALYZER_NONNULL = YES; ++ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; ++ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; ++ CLANG_ENABLE_MODULES = YES; ++ CLANG_ENABLE_OBJC_ARC = YES; ++ CLANG_ENABLE_OBJC_WEAK = YES; ++ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; ++ CLANG_WARN_BOOL_CONVERSION = YES; ++ CLANG_WARN_COMMA = YES; ++ CLANG_WARN_CONSTANT_CONVERSION = YES; ++ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; ++ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; ++ CLANG_WARN_DOCUMENTATION_COMMENTS = YES; ++ CLANG_WARN_EMPTY_BODY = YES; ++ CLANG_WARN_ENUM_CONVERSION = YES; ++ CLANG_WARN_INFINITE_RECURSION = YES; ++ CLANG_WARN_INT_CONVERSION = YES; ++ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; ++ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; ++ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; ++ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; ++ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; ++ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; ++ CLANG_WARN_STRICT_PROTOTYPES = YES; ++ CLANG_WARN_SUSPICIOUS_MOVE = YES; ++ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; ++ CLANG_WARN_UNREACHABLE_CODE = YES; ++ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; ++ COPY_PHASE_STRIP = NO; ++ DEBUG_INFORMATION_FORMAT = dwarf; ++ ENABLE_STRICT_OBJC_MSGSEND = YES; ++ ENABLE_TESTABILITY = YES; ++ ENABLE_USER_SCRIPT_SANDBOXING = YES; ++ GCC_C_LANGUAGE_STANDARD = gnu17; ++ GCC_DYNAMIC_NO_PIC = NO; ++ GCC_NO_COMMON_BLOCKS = YES; ++ GCC_OPTIMIZATION_LEVEL = 0; ++ GCC_PREPROCESSOR_DEFINITIONS = ( ++ "DEBUG=1", ++ "$(inherited)", ++ ); ++ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; ++ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; ++ GCC_WARN_UNDECLARED_SELECTOR = YES; ++ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; ++ GCC_WARN_UNUSED_FUNCTION = YES; ++ GCC_WARN_UNUSED_VARIABLE = YES; ++ IPHONEOS_DEPLOYMENT_TARGET = 12.0; ++ LOCALIZATION_PREFERS_STRING_CATALOGS = YES; ++ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; ++ MTL_FAST_MATH = YES; ++ ONLY_ACTIVE_ARCH = YES; ++ SDKROOT = iphoneos; ++ }; ++ name = Debug; ++ }; ++ 607A66402B0EFA3A0010BFC8 /* Release */ = { ++ isa = XCBuildConfiguration; ++ buildSettings = { ++ ALWAYS_SEARCH_USER_PATHS = NO; ++ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; ++ CLANG_ANALYZER_NONNULL = YES; ++ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; ++ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; ++ CLANG_ENABLE_MODULES = YES; ++ CLANG_ENABLE_OBJC_ARC = YES; ++ CLANG_ENABLE_OBJC_WEAK = YES; ++ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; ++ CLANG_WARN_BOOL_CONVERSION = YES; ++ CLANG_WARN_COMMA = YES; ++ CLANG_WARN_CONSTANT_CONVERSION = YES; ++ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; ++ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; ++ CLANG_WARN_DOCUMENTATION_COMMENTS = YES; ++ CLANG_WARN_EMPTY_BODY = YES; ++ CLANG_WARN_ENUM_CONVERSION = YES; ++ CLANG_WARN_INFINITE_RECURSION = YES; ++ CLANG_WARN_INT_CONVERSION = YES; ++ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; ++ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; ++ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; ++ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; ++ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; ++ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; ++ CLANG_WARN_STRICT_PROTOTYPES = YES; ++ CLANG_WARN_SUSPICIOUS_MOVE = YES; ++ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; ++ CLANG_WARN_UNREACHABLE_CODE = YES; ++ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; ++ COPY_PHASE_STRIP = NO; ++ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ++ ENABLE_NS_ASSERTIONS = NO; ++ ENABLE_STRICT_OBJC_MSGSEND = YES; ++ ENABLE_USER_SCRIPT_SANDBOXING = YES; ++ GCC_C_LANGUAGE_STANDARD = gnu17; ++ GCC_NO_COMMON_BLOCKS = YES; ++ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; ++ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; ++ GCC_WARN_UNDECLARED_SELECTOR = YES; ++ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; ++ GCC_WARN_UNUSED_FUNCTION = YES; ++ GCC_WARN_UNUSED_VARIABLE = YES; ++ IPHONEOS_DEPLOYMENT_TARGET = 12.0; ++ LOCALIZATION_PREFERS_STRING_CATALOGS = YES; ++ MTL_ENABLE_DEBUG_INFO = NO; ++ MTL_FAST_MATH = YES; ++ SDKROOT = iphoneos; ++ VALIDATE_PRODUCT = YES; ++ }; ++ name = Release; ++ }; ++ 607A66422B0EFA3A0010BFC8 /* Debug */ = { ++ isa = XCBuildConfiguration; ++ buildSettings = { ++ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ++ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ++ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; ++ CODE_SIGN_STYLE = Automatic; ++ CURRENT_PROJECT_VERSION = 1; ++ DEVELOPMENT_TEAM = ""; ++ ENABLE_USER_SCRIPT_SANDBOXING = NO; ++ HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\""; ++ INFOPLIST_FILE = "iOSTestbed/iOSTestbed-Info.plist"; ++ INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; ++ INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; ++ INFOPLIST_KEY_UIMainStoryboardFile = Main; ++ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; ++ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; ++ IPHONEOS_DEPLOYMENT_TARGET = 12.0; ++ LD_RUNPATH_SEARCH_PATHS = ( ++ "$(inherited)", ++ "@executable_path/Frameworks", ++ ); ++ MARKETING_VERSION = 3.13.0a1; ++ PRODUCT_BUNDLE_IDENTIFIER = org.python.iOSTestbed; ++ PRODUCT_NAME = "$(TARGET_NAME)"; ++ SWIFT_EMIT_LOC_STRINGS = YES; ++ TARGETED_DEVICE_FAMILY = "1,2"; ++ }; ++ name = Debug; ++ }; ++ 607A66432B0EFA3A0010BFC8 /* Release */ = { ++ isa = XCBuildConfiguration; ++ buildSettings = { ++ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ++ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ++ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; ++ CODE_SIGN_STYLE = Automatic; ++ CURRENT_PROJECT_VERSION = 1; ++ DEVELOPMENT_TEAM = ""; ++ ENABLE_TESTABILITY = YES; ++ ENABLE_USER_SCRIPT_SANDBOXING = NO; ++ HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\""; ++ INFOPLIST_FILE = "iOSTestbed/iOSTestbed-Info.plist"; ++ INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; ++ INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; ++ INFOPLIST_KEY_UIMainStoryboardFile = Main; ++ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; ++ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; ++ IPHONEOS_DEPLOYMENT_TARGET = 12.0; ++ LD_RUNPATH_SEARCH_PATHS = ( ++ "$(inherited)", ++ "@executable_path/Frameworks", ++ ); ++ MARKETING_VERSION = 3.13.0a1; ++ PRODUCT_BUNDLE_IDENTIFIER = org.python.iOSTestbed; ++ PRODUCT_NAME = "$(TARGET_NAME)"; ++ SWIFT_EMIT_LOC_STRINGS = YES; ++ TARGETED_DEVICE_FAMILY = "1,2"; ++ }; ++ name = Release; ++ }; ++ 607A66452B0EFA3A0010BFC8 /* Debug */ = { ++ isa = XCBuildConfiguration; ++ buildSettings = { ++ BUNDLE_LOADER = "$(TEST_HOST)"; ++ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; ++ CODE_SIGN_STYLE = Automatic; ++ CURRENT_PROJECT_VERSION = 1; ++ DEVELOPMENT_TEAM = 3HEZE76D99; ++ GENERATE_INFOPLIST_FILE = YES; ++ HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\""; ++ IPHONEOS_DEPLOYMENT_TARGET = 12.0; ++ MARKETING_VERSION = 1.0; ++ PRODUCT_BUNDLE_IDENTIFIER = org.python.iOSTestbedTests; ++ PRODUCT_NAME = "$(TARGET_NAME)"; ++ SWIFT_EMIT_LOC_STRINGS = NO; ++ TARGETED_DEVICE_FAMILY = "1,2"; ++ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/iOSTestbed.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/iOSTestbed"; ++ }; ++ name = Debug; ++ }; ++ 607A66462B0EFA3A0010BFC8 /* Release */ = { ++ isa = XCBuildConfiguration; ++ buildSettings = { ++ BUNDLE_LOADER = "$(TEST_HOST)"; ++ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; ++ CODE_SIGN_STYLE = Automatic; ++ CURRENT_PROJECT_VERSION = 1; ++ DEVELOPMENT_TEAM = 3HEZE76D99; ++ GENERATE_INFOPLIST_FILE = YES; ++ HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\""; ++ IPHONEOS_DEPLOYMENT_TARGET = 12.0; ++ MARKETING_VERSION = 1.0; ++ PRODUCT_BUNDLE_IDENTIFIER = org.python.iOSTestbedTests; ++ PRODUCT_NAME = "$(TARGET_NAME)"; ++ SWIFT_EMIT_LOC_STRINGS = NO; ++ TARGETED_DEVICE_FAMILY = "1,2"; ++ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/iOSTestbed.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/iOSTestbed"; ++ }; ++ name = Release; ++ }; ++/* End XCBuildConfiguration section */ ++ ++/* Begin XCConfigurationList section */ ++ 607A660D2B0EFA380010BFC8 /* Build configuration list for PBXProject "iOSTestbed" */ = { ++ isa = XCConfigurationList; ++ buildConfigurations = ( ++ 607A663F2B0EFA3A0010BFC8 /* Debug */, ++ 607A66402B0EFA3A0010BFC8 /* Release */, ++ ); ++ defaultConfigurationIsVisible = 0; ++ defaultConfigurationName = Release; ++ }; ++ 607A66412B0EFA3A0010BFC8 /* Build configuration list for PBXNativeTarget "iOSTestbed" */ = { ++ isa = XCConfigurationList; ++ buildConfigurations = ( ++ 607A66422B0EFA3A0010BFC8 /* Debug */, ++ 607A66432B0EFA3A0010BFC8 /* Release */, ++ ); ++ defaultConfigurationIsVisible = 0; ++ defaultConfigurationName = Release; ++ }; ++ 607A66442B0EFA3A0010BFC8 /* Build configuration list for PBXNativeTarget "iOSTestbedTests" */ = { ++ isa = XCConfigurationList; ++ buildConfigurations = ( ++ 607A66452B0EFA3A0010BFC8 /* Debug */, ++ 607A66462B0EFA3A0010BFC8 /* Release */, ++ ); ++ defaultConfigurationIsVisible = 0; ++ defaultConfigurationName = Release; ++ }; ++/* End XCConfigurationList section */ ++ }; ++ rootObject = 607A660A2B0EFA380010BFC8 /* Project object */; ++} +--- /dev/null ++++ b/MacCatalyst/testbed/iOSTestbed/AppDelegate.h +@@ -0,0 +1,11 @@ ++// ++// AppDelegate.h ++// iOSTestbed ++// ++ ++#import ++ ++@interface AppDelegate : UIResponder ++ ++ ++@end +--- /dev/null ++++ b/MacCatalyst/testbed/iOSTestbed/AppDelegate.m +@@ -0,0 +1,19 @@ ++// ++// AppDelegate.m ++// iOSTestbed ++// ++ ++#import "AppDelegate.h" ++ ++@interface AppDelegate () ++ ++@end ++ ++@implementation AppDelegate ++ ++ ++- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ++ return YES; ++} ++ ++@end +--- /dev/null ++++ b/MacCatalyst/testbed/iOSTestbed/Assets.xcassets/AccentColor.colorset/Contents.json +@@ -0,0 +1,11 @@ ++{ ++ "colors" : [ ++ { ++ "idiom" : "universal" ++ } ++ ], ++ "info" : { ++ "author" : "xcode", ++ "version" : 1 ++ } ++} +--- /dev/null ++++ b/MacCatalyst/testbed/iOSTestbed/Assets.xcassets/AppIcon.appiconset/Contents.json +@@ -0,0 +1,13 @@ ++{ ++ "images" : [ ++ { ++ "idiom" : "universal", ++ "platform" : "ios", ++ "size" : "1024x1024" ++ } ++ ], ++ "info" : { ++ "author" : "xcode", ++ "version" : 1 ++ } ++} +--- /dev/null ++++ b/MacCatalyst/testbed/iOSTestbed/Assets.xcassets/Contents.json +@@ -0,0 +1,6 @@ ++{ ++ "info" : { ++ "author" : "xcode", ++ "version" : 1 ++ } ++} +--- /dev/null ++++ b/MacCatalyst/testbed/iOSTestbed/Base.lproj/LaunchScreen.storyboard +@@ -0,0 +1,9 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ +--- /dev/null ++++ b/MacCatalyst/testbed/iOSTestbed/app/README +@@ -0,0 +1,7 @@ ++This folder can contain any Python application code. ++ ++During the build, any binary modules found in this folder will be processed into ++iOS Framework form. ++ ++When the test suite runs, this folder will be on the PYTHONPATH, and will be the ++working directory for the test suite. +--- /dev/null ++++ b/MacCatalyst/testbed/iOSTestbed/app_packages/README +@@ -0,0 +1,7 @@ ++This folder can be a target for installing any Python dependencies needed by the ++test suite. ++ ++During the build, any binary modules found in this folder will be processed into ++iOS Framework form. ++ ++When the test suite runs, this folder will be on the PYTHONPATH. +--- /dev/null ++++ b/MacCatalyst/testbed/iOSTestbed/dylib-Info-template.plist +@@ -0,0 +1,26 @@ ++ ++ ++ ++ ++ CFBundleDevelopmentRegion ++ en ++ CFBundleExecutable ++ ++ CFBundleIdentifier ++ ++ CFBundleInfoDictionaryVersion ++ 6.0 ++ CFBundlePackageType ++ APPL ++ CFBundleShortVersionString ++ 1.0 ++ CFBundleSupportedPlatforms ++ ++ iPhoneOS ++ ++ MinimumOSVersion ++ 12.0 ++ CFBundleVersion ++ 1 ++ ++ +--- /dev/null ++++ b/MacCatalyst/testbed/iOSTestbed/iOSTestbed-Info.plist +@@ -0,0 +1,64 @@ ++ ++ ++ ++ ++ CFBundleDevelopmentRegion ++ en ++ CFBundleDisplayName ++ ${PRODUCT_NAME} ++ CFBundleExecutable ++ ${EXECUTABLE_NAME} ++ CFBundleIdentifier ++ org.python.iOSTestbed ++ CFBundleInfoDictionaryVersion ++ 6.0 ++ CFBundleName ++ ${PRODUCT_NAME} ++ CFBundlePackageType ++ APPL ++ CFBundleShortVersionString ++ 1.0 ++ CFBundleSignature ++ ???? ++ CFBundleVersion ++ 1 ++ LSRequiresIPhoneOS ++ ++ UIRequiresFullScreen ++ ++ UILaunchStoryboardName ++ Launch Screen ++ UISupportedInterfaceOrientations ++ ++ UIInterfaceOrientationPortrait ++ UIInterfaceOrientationLandscapeLeft ++ UIInterfaceOrientationLandscapeRight ++ ++ UISupportedInterfaceOrientations~ipad ++ ++ UIInterfaceOrientationPortrait ++ UIInterfaceOrientationPortraitUpsideDown ++ UIInterfaceOrientationLandscapeLeft ++ UIInterfaceOrientationLandscapeRight ++ ++ TestArgs ++ ++ test ++ -uall ++ --single-process ++ --rerun ++ -W ++ ++ ++ UIApplicationSceneManifest ++ ++ UIApplicationSupportsMultipleScenes ++ ++ UISceneConfigurations ++ ++ ++ ++ +--- /dev/null ++++ b/MacCatalyst/testbed/iOSTestbed/main.m +@@ -0,0 +1,16 @@ ++// ++// main.m ++// iOSTestbed ++// ++ ++#import ++#import "AppDelegate.h" ++ ++int main(int argc, char * argv[]) { ++ NSString * appDelegateClassName; ++ @autoreleasepool { ++ appDelegateClassName = NSStringFromClass([AppDelegate class]); ++ ++ return UIApplicationMain(argc, argv, nil, appDelegateClassName); ++ } ++} +--- /dev/null ++++ b/MacCatalyst/testbed/iOSTestbedTests/iOSTestbedTests.m +@@ -0,0 +1,162 @@ ++#import ++#import ++ ++@interface iOSTestbedTests : XCTestCase ++ ++@end ++ ++@implementation iOSTestbedTests ++ ++ ++- (void)testPython { ++ const char **argv; ++ int exit_code; ++ int failed; ++ PyStatus status; ++ PyPreConfig preconfig; ++ PyConfig config; ++ PyObject *sys_module; ++ PyObject *sys_path_attr; ++ NSArray *test_args; ++ NSString *python_home; ++ NSString *path; ++ wchar_t *wtmp_str; ++ ++ NSString *resourcePath = [[NSBundle mainBundle] resourcePath]; ++ ++ // Set some other common environment indicators to disable color, as the ++ // Xcode log can't display color. Stdout will report that it is *not* a ++ // TTY. ++ setenv("NO_COLOR", "1", true); ++ setenv("PY_COLORS", "0", true); ++ ++ // Arguments to pass into the test suite runner. ++ // argv[0] must identify the process; any subsequent arg ++ // will be handled as if it were an argument to `python -m test` ++ test_args = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"TestArgs"]; ++ if (test_args == NULL) { ++ NSLog(@"Unable to identify test arguments."); ++ } ++ argv = malloc(sizeof(char *) * ([test_args count] + 1)); ++ argv[0] = "iOSTestbed"; ++ for (int i = 1; i < [test_args count]; i++) { ++ argv[i] = [[test_args objectAtIndex:i] UTF8String]; ++ } ++ NSLog(@"Test command: %@", test_args); ++ ++ // Generate an isolated Python configuration. ++ NSLog(@"Configuring isolated Python..."); ++ PyPreConfig_InitIsolatedConfig(&preconfig); ++ PyConfig_InitIsolatedConfig(&config); ++ ++ // Configure the Python interpreter: ++ // Enforce UTF-8 encoding for stderr, stdout, file-system encoding and locale. ++ // See https://docs.python.org/3/library/os.html#python-utf-8-mode. ++ preconfig.utf8_mode = 1; ++ // Use the system logger for stdout/err ++ config.use_system_logger = 1; ++ // Don't buffer stdio. We want output to appears in the log immediately ++ config.buffered_stdio = 0; ++ // Don't write bytecode; we can't modify the app bundle ++ // after it has been signed. ++ config.write_bytecode = 0; ++ // Ensure that signal handlers are installed ++ config.install_signal_handlers = 1; ++ // Run the test module. ++ config.run_module = Py_DecodeLocale([[test_args objectAtIndex:0] UTF8String], NULL); ++ // For debugging - enable verbose mode. ++ // config.verbose = 1; ++ ++ NSLog(@"Pre-initializing Python runtime..."); ++ status = Py_PreInitialize(&preconfig); ++ if (PyStatus_Exception(status)) { ++ XCTFail(@"Unable to pre-initialize Python interpreter: %s", status.err_msg); ++ PyConfig_Clear(&config); ++ return; ++ } ++ ++ // Set the home for the Python interpreter ++ python_home = [NSString stringWithFormat:@"%@/python", resourcePath, nil]; ++ NSLog(@"PythonHome: %@", python_home); ++ wtmp_str = Py_DecodeLocale([python_home UTF8String], NULL); ++ status = PyConfig_SetString(&config, &config.home, wtmp_str); ++ if (PyStatus_Exception(status)) { ++ XCTFail(@"Unable to set PYTHONHOME: %s", status.err_msg); ++ PyConfig_Clear(&config); ++ return; ++ } ++ PyMem_RawFree(wtmp_str); ++ ++ // Read the site config ++ status = PyConfig_Read(&config); ++ if (PyStatus_Exception(status)) { ++ XCTFail(@"Unable to read site config: %s", status.err_msg); ++ PyConfig_Clear(&config); ++ return; ++ } ++ ++ NSLog(@"Configure argc/argv..."); ++ status = PyConfig_SetBytesArgv(&config, [test_args count], (char**) argv); ++ if (PyStatus_Exception(status)) { ++ XCTFail(@"Unable to configure argc/argv: %s", status.err_msg); ++ PyConfig_Clear(&config); ++ return; ++ } ++ ++ NSLog(@"Initializing Python runtime..."); ++ status = Py_InitializeFromConfig(&config); ++ if (PyStatus_Exception(status)) { ++ XCTFail(@"Unable to initialize Python interpreter: %s", status.err_msg); ++ PyConfig_Clear(&config); ++ return; ++ } ++ ++ sys_module = PyImport_ImportModule("sys"); ++ if (sys_module == NULL) { ++ XCTFail(@"Could not import sys module"); ++ return; ++ } ++ ++ sys_path_attr = PyObject_GetAttrString(sys_module, "path"); ++ if (sys_path_attr == NULL) { ++ XCTFail(@"Could not access sys.path"); ++ return; ++ } ++ ++ // Add the app packages path ++ path = [NSString stringWithFormat:@"%@/app_packages", resourcePath, nil]; ++ NSLog(@"App packages path: %@", path); ++ wtmp_str = Py_DecodeLocale([path UTF8String], NULL); ++ failed = PyList_Insert(sys_path_attr, 0, PyUnicode_FromString([path UTF8String])); ++ if (failed) { ++ XCTFail(@"Unable to add app packages to sys.path"); ++ return; ++ } ++ PyMem_RawFree(wtmp_str); ++ ++ path = [NSString stringWithFormat:@"%@/app", resourcePath, nil]; ++ NSLog(@"App path: %@", path); ++ wtmp_str = Py_DecodeLocale([path UTF8String], NULL); ++ failed = PyList_Insert(sys_path_attr, 0, PyUnicode_FromString([path UTF8String])); ++ if (failed) { ++ XCTFail(@"Unable to add app to sys.path"); ++ return; ++ } ++ PyMem_RawFree(wtmp_str); ++ ++ // Ensure the working directory is the app folder. ++ chdir([path UTF8String]); ++ ++ // Start the test suite. Print a separator to differentiate Python startup logs from app logs ++ NSLog(@"---------------------------------------------------------------------------"); ++ ++ exit_code = Py_RunMain(); ++ XCTAssertEqual(exit_code, 0, @"Test suite did not pass"); ++ ++ NSLog(@"---------------------------------------------------------------------------"); ++ ++ Py_Finalize(); ++} ++ ++ ++@end diff --git a/Misc/platform_triplet.c b/Misc/platform_triplet.c index ec0857a4a99..190670f271d 100644 --- a/Misc/platform_triplet.c @@ -214,18 +2198,10 @@ index 1bb6a05dc11..7e007ac54c3 100755 # None (no kernel, i.e. freestanding / bare metal), # can be paired with an machine code file format diff --git a/configure b/configure -index d46bc563a67..0a11bb50856 100755 +index d46bc563a67..4c05b8dcf21 100755 --- a/configure +++ b/configure -@@ -907,7 +907,6 @@ - OPT - BOLT_APPLY_FLAGS - BOLT_INSTRUMENT_FLAGS --BOLT_COMMON_FLAGS - BOLT_BINARIES - MERGE_FDATA - LLVM_BOLT -@@ -974,6 +973,8 @@ +@@ -974,6 +974,8 @@ CFLAGS CC HAS_XCRUN @@ -234,24 +2210,7 @@ index d46bc563a67..0a11bb50856 100755 IPHONEOS_DEPLOYMENT_TARGET EXPORT_MACOSX_DEPLOYMENT_TARGET CONFIGURE_MACOSX_DEPLOYMENT_TARGET -@@ -1144,7 +1145,6 @@ - CPPFLAGS - CPP - PROFILE_TASK --BOLT_COMMON_FLAGS - BOLT_INSTRUMENT_FLAGS - BOLT_APPLY_FLAGS - LIBUUID_CFLAGS -@@ -1968,8 +1968,6 @@ - CPP C preprocessor - PROFILE_TASK - Python args for PGO generation task -- BOLT_COMMON_FLAGS -- Common arguments to llvm-bolt when instrumenting and applying - BOLT_INSTRUMENT_FLAGS - Arguments to llvm-bolt when instrumenting binaries - BOLT_APPLY_FLAGS -@@ -4100,6 +4098,12 @@ +@@ -4100,6 +4102,12 @@ *-apple-ios*) ac_sys_system=iOS ;; @@ -264,7 +2223,7 @@ index d46bc563a67..0a11bb50856 100755 *-*-darwin*) ac_sys_system=Darwin ;; -@@ -4181,7 +4185,7 @@ +@@ -4181,7 +4189,7 @@ # On cross-compile builds, configure will look for a host-specific compiler by # prepending the user-provided host triple to the required binary name. # @@ -273,21 +2232,19 @@ index d46bc563a67..0a11bb50856 100755 # which isn't a binary that exists, and isn't very convenient, as it contains the # iOS version. As the default cross-compiler name won't exist, configure falls # back to gcc, which *definitely* won't work. We're providing wrapper scripts for -@@ -4194,32 +4198,76 @@ +@@ -4194,32 +4202,68 @@ if test -z "$AR"; then case "$host" in aarch64-apple-ios*-simulator) AR=arm64-apple-ios-simulator-ar ;; -+ aarch64-apple-ios*-macabi) AR=arm64-apple-ios-macabi-ar ;; ++ aarch64-apple-ios*-macabi) AR=arm64-apple-ios-macabi-ar ;; aarch64-apple-ios*) AR=arm64-apple-ios-ar ;; x86_64-apple-ios*-simulator) AR=x86_64-apple-ios-simulator-ar ;; + + aarch64-apple-tvos*-simulator) AR=arm64-apple-tvos-simulator-ar ;; -+ aarch64-apple-tvos*-macabi) AR=arm64-apple-tvos-macabi-ar ;; + aarch64-apple-tvos*) AR=arm64-apple-tvos-ar ;; + x86_64-apple-tvos*-simulator) AR=x86_64-apple-tvos-simulator-ar ;; + + aarch64-apple-watchos*-simulator) AR=arm64-apple-watchos-simulator-ar ;; -+ aarch64-apple-watchos*-macabi) AR=arm64-apple-watchos-macabi-ar ;; + aarch64-apple-watchos*) AR=arm64_32-apple-watchos-ar ;; + x86_64-apple-watchos*-simulator) AR=x86_64-apple-watchos-simulator-ar ;; *) @@ -296,17 +2253,15 @@ index d46bc563a67..0a11bb50856 100755 if test -z "$CC"; then case "$host" in aarch64-apple-ios*-simulator) CC=arm64-apple-ios-simulator-clang ;; -+ aarch64-apple-ios*-macabi) CC=arm64-apple-ios-macabi-clang ;; ++ aarch64-apple-ios*-macabi) CC=arm64-apple-ios-macabi-clang ;; aarch64-apple-ios*) CC=arm64-apple-ios-clang ;; x86_64-apple-ios*-simulator) CC=x86_64-apple-ios-simulator-clang ;; + + aarch64-apple-tvos*-simulator) CC=arm64-apple-tvos-simulator-clang ;; -+ aarch64-apple-tvos*-macabi) CC=arm64-apple-tvos-macabi-clang ;; + aarch64-apple-tvos*) CC=arm64-apple-tvos-clang ;; + x86_64-apple-tvos*-simulator) CC=x86_64-apple-tvos-simulator-clang ;; + + aarch64-apple-watchos*-simulator) CC=arm64-apple-watchos-simulator-clang ;; -+ aarch64-apple-watchos*-macabi) CC=arm64-apple-watchos-macabi-clang ;; + aarch64-apple-watchos*) CC=arm64_32-apple-watchos-clang ;; + x86_64-apple-watchos*-simulator) CC=x86_64-apple-watchos-simulator-clang ;; *) @@ -315,17 +2270,15 @@ index d46bc563a67..0a11bb50856 100755 if test -z "$CPP"; then case "$host" in aarch64-apple-ios*-simulator) CPP=arm64-apple-ios-simulator-cpp ;; -+ aarch64-apple-ios*-macabi) CPP=arm64-apple-ios-macabi-cpp ;; ++ aarch64-apple-ios*-macabi) CPP=arm64-apple-ios-macabi-cpp ;; aarch64-apple-ios*) CPP=arm64-apple-ios-cpp ;; x86_64-apple-ios*-simulator) CPP=x86_64-apple-ios-simulator-cpp ;; + + aarch64-apple-tvos*-simulator) CPP=arm64-apple-tvos-simulator-cpp ;; -+ aarch64-apple-tvos*-macabi) CPP=arm64-apple-tvos-macabi-cpp ;; + aarch64-apple-tvos*) CPP=arm64-apple-tvos-cpp ;; + x86_64-apple-tvos*-simulator) CPP=x86_64-apple-tvos-simulator-cpp ;; + + aarch64-apple-watchos*-simulator) CPP=arm64-apple-watchos-simulator-cpp ;; -+ aarch64-apple-watchos*-macabi) CPP=arm64-apple-watchos-macabi-cpp ;; + aarch64-apple-watchos*) CPP=arm64_32-apple-watchos-cpp ;; + x86_64-apple-watchos*-simulator) CPP=x86_64-apple-watchos-simulator-cpp ;; *) @@ -334,23 +2287,21 @@ index d46bc563a67..0a11bb50856 100755 if test -z "$CXX"; then case "$host" in aarch64-apple-ios*-simulator) CXX=arm64-apple-ios-simulator-clang++ ;; -+ aarch64-apple-ios*-macabi) CXX=arm64-apple-ios-macabi-clang++ ;; ++ aarch64-apple-ios*-macabi) CXX=arm64-apple-ios-macabi-clang++ ;; aarch64-apple-ios*) CXX=arm64-apple-ios-clang++ ;; x86_64-apple-ios*-simulator) CXX=x86_64-apple-ios-simulator-clang++ ;; + + aarch64-apple-tvos*-simulator) CXX=arm64-apple-tvos-simulator-clang++ ;; -+ aarch64-apple-tvos*-macabi) CXX=arm64-apple-tvos-macabi-clang++ ;; + aarch64-apple-tvos*) CXX=arm64-apple-tvos-clang++ ;; + x86_64-apple-tvos*-simulator) CXX=x86_64-apple-tvos-simulator-clang++ ;; + + aarch64-apple-watchos*-simulator) CXX=arm64-apple-watchos-simulator-clang++ ;; -+ aarch64-apple-watchos*-macabi) CXX=arm64-apple-watchos-macabi-clang++ ;; + aarch64-apple-watchos*) CXX=arm64_32-apple-watchos-clang++ ;; + x86_64-apple-watchos*-simulator) CXX=x86_64-apple-watchos-simulator-clang++ ;; *) esac fi -@@ -4342,8 +4390,10 @@ +@@ -4342,8 +4386,10 @@ case $enableval in yes) case $ac_sys_system in @@ -363,7 +2314,7 @@ index d46bc563a67..0a11bb50856 100755 *) as_fn_error $? "Unknown platform for framework build" "$LINENO" 5 esac esac -@@ -4352,6 +4402,8 @@ +@@ -4352,6 +4398,8 @@ no) case $ac_sys_system in iOS) as_fn_error $? "iOS builds must use --enable-framework" "$LINENO" 5 ;; @@ -372,7 +2323,7 @@ index d46bc563a67..0a11bb50856 100755 *) PYTHONFRAMEWORK= PYTHONFRAMEWORKDIR=no-framework -@@ -4458,6 +4510,36 @@ +@@ -4458,6 +4506,36 @@ ac_config_files="$ac_config_files iOS/Resources/Info.plist" @@ -409,7 +2360,7 @@ index d46bc563a67..0a11bb50856 100755 ;; *) as_fn_error $? "Unknown platform for framework build" "$LINENO" 5 -@@ -4469,6 +4551,8 @@ +@@ -4469,6 +4547,8 @@ e) case $ac_sys_system in iOS) as_fn_error $? "iOS builds must use --enable-framework" "$LINENO" 5 ;; @@ -418,7 +2369,7 @@ index d46bc563a67..0a11bb50856 100755 *) PYTHONFRAMEWORK= PYTHONFRAMEWORKDIR=no-framework -@@ -4523,8 +4607,8 @@ +@@ -4523,8 +4603,8 @@ case "$withval" in yes) case $ac_sys_system in @@ -429,7 +2380,7 @@ index d46bc563a67..0a11bb50856 100755 APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" ;; *) as_fn_error $? "no default app store compliance patch available for $ac_sys_system" "$LINENO" 5 ;; -@@ -4542,8 +4626,8 @@ +@@ -4542,8 +4622,8 @@ else case e in #( e) case $ac_sys_system in @@ -440,7 +2391,7 @@ index d46bc563a67..0a11bb50856 100755 APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: applying default app store compliance patch" >&5 printf "%s\n" "applying default app store compliance patch" >&6; } -@@ -4598,6 +4682,50 @@ +@@ -4598,6 +4678,50 @@ ;; esac ;; @@ -491,7 +2442,7 @@ index d46bc563a67..0a11bb50856 100755 *-*-darwin*) case "$host_cpu" in arm*) -@@ -4688,9 +4816,13 @@ +@@ -4688,9 +4812,13 @@ define_xopen_source=no;; Darwin/[12][0-9].*) define_xopen_source=no;; @@ -506,7 +2457,7 @@ index d46bc563a67..0a11bb50856 100755 # On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from # defining NI_NUMERICHOST. QNX/6.3.2) -@@ -4753,7 +4885,10 @@ +@@ -4753,7 +4881,10 @@ CONFIGURE_MACOSX_DEPLOYMENT_TARGET= EXPORT_MACOSX_DEPLOYMENT_TARGET='#' @@ -518,7 +2469,7 @@ index d46bc563a67..0a11bb50856 100755 # checks for alternative programs -@@ -4794,6 +4929,16 @@ +@@ -4794,6 +4925,16 @@ as_fn_append CFLAGS " -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}" as_fn_append LDFLAGS " -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}" ;; #( @@ -535,7 +2486,7 @@ index d46bc563a67..0a11bb50856 100755 *) : ;; esac -@@ -7163,6 +7308,10 @@ +@@ -7163,6 +7304,10 @@ MULTIARCH="" ;; #( iOS) : MULTIARCH="" ;; #( @@ -546,7 +2497,7 @@ index d46bc563a67..0a11bb50856 100755 FreeBSD*) : MULTIARCH="" ;; #( *) : -@@ -7183,7 +7332,7 @@ +@@ -7183,7 +7328,7 @@ printf "%s\n" "$MULTIARCH" >&6; } case $ac_sys_system in #( @@ -555,7 +2506,7 @@ index d46bc563a67..0a11bb50856 100755 SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f2` ;; #( *) : SOABI_PLATFORM=$PLATFORM_TRIPLET -@@ -7234,6 +7383,14 @@ +@@ -7234,6 +7379,14 @@ PY_SUPPORT_TIER=3 ;; #( aarch64-apple-ios*/clang) : PY_SUPPORT_TIER=3 ;; #( @@ -570,7 +2521,7 @@ index d46bc563a67..0a11bb50856 100755 aarch64-*-linux-android/clang) : PY_SUPPORT_TIER=3 ;; #( x86_64-*-linux-android/clang) : -@@ -7670,7 +7827,7 @@ +@@ -7670,7 +7823,7 @@ case $ac_sys_system in Darwin) LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)';; @@ -579,7 +2530,7 @@ index d46bc563a67..0a11bb50856 100755 LDLIBRARY='$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';; *) as_fn_error $? "Unknown platform for framework build" "$LINENO" 5;; -@@ -7736,7 +7893,7 @@ +@@ -7736,7 +7889,7 @@ BLDLIBRARY='-L. -lpython$(LDVERSION)' RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}} ;; @@ -588,52 +2539,7 @@ index d46bc563a67..0a11bb50856 100755 LDLIBRARY='libpython$(LDVERSION).dylib' ;; AIX*) -@@ -9409,21 +9566,11 @@ - fi - - -- --{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking BOLT_COMMON_FLAGS" >&5 --printf %s "checking BOLT_COMMON_FLAGS... " >&6; } --if test -z "${BOLT_COMMON_FLAGS}" --then -- BOLT_COMMON_FLAGS=" -update-debug-sections -skip-funcs=_PyEval_EvalFrameDefault,sre_ucs1_match/1,sre_ucs2_match/1,sre_ucs4_match/1 " -- --fi -- -- - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking BOLT_INSTRUMENT_FLAGS" >&5 - printf %s "checking BOLT_INSTRUMENT_FLAGS... " >&6; } - if test -z "${BOLT_INSTRUMENT_FLAGS}" - then -- BOLT_INSTRUMENT_FLAGS="${BOLT_COMMON_FLAGS}" -+ BOLT_INSTRUMENT_FLAGS= - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $BOLT_INSTRUMENT_FLAGS" >&5 - printf "%s\n" "$BOLT_INSTRUMENT_FLAGS" >&6; } -@@ -9433,7 +9580,7 @@ - printf %s "checking BOLT_APPLY_FLAGS... " >&6; } - if test -z "${BOLT_APPLY_FLAGS}" - then -- BOLT_APPLY_FLAGS=" ${BOLT_COMMON_FLAGS} -reorder-blocks=ext-tsp -reorder-functions=cdsort -split-functions -icf=1 -inline-all -split-eh -reorder-functions-use-hot-size -peepholes=none -jump-tables=aggressive -inline-ap -indirect-call-promotion=all -dyno-stats -use-gnu-stack -frame-opt=hot " -+ BOLT_APPLY_FLAGS=" -update-debug-sections -reorder-blocks=ext-tsp -reorder-functions=hfsort+ -split-functions -icf=1 -inline-all -split-eh -reorder-functions-use-hot-size -peepholes=none -jump-tables=aggressive -inline-ap -indirect-call-promotion=all -dyno-stats -use-gnu-stack -frame-opt=hot " - - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $BOLT_APPLY_FLAGS" >&5 -@@ -11489,12 +11636,6 @@ - then : - printf "%s\n" "#define HAVE_SYS_PARAM_H 1" >>confdefs.h - --fi --ac_fn_c_check_header_compile "$LINENO" "sys/pidfd.h" "ac_cv_header_sys_pidfd_h" "$ac_includes_default" --if test "x$ac_cv_header_sys_pidfd_h" = xyes --then : -- printf "%s\n" "#define HAVE_SYS_PIDFD_H 1" >>confdefs.h -- - fi - ac_fn_c_check_header_compile "$LINENO" "sys/poll.h" "ac_cv_header_sys_poll_h" "$ac_includes_default" - if test "x$ac_cv_header_sys_poll_h" = xyes -@@ -13544,7 +13685,7 @@ +@@ -13544,7 +13697,7 @@ BLDSHARED="$LDSHARED" fi ;; @@ -642,7 +2548,7 @@ index d46bc563a67..0a11bb50856 100755 LDSHARED='$(CC) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)' LDCXXSHARED='$(CXX) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)' BLDSHARED="$LDSHARED" -@@ -13677,7 +13818,7 @@ +@@ -13677,7 +13830,7 @@ Linux-android*) LINKFORSHARED="-pie -Xlinker -export-dynamic";; Linux*|GNU*) LINKFORSHARED="-Xlinker -export-dynamic";; # -u libsys_s pulls in all symbols in libsys @@ -651,7 +2557,7 @@ index d46bc563a67..0a11bb50856 100755 LINKFORSHARED="$extra_undefs -framework CoreFoundation" # Issue #18075: the default maximum stack size (8MBytes) is too -@@ -13701,7 +13842,7 @@ +@@ -13701,7 +13854,7 @@ LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' fi LINKFORSHARED="$LINKFORSHARED" @@ -660,43 +2566,7 @@ index d46bc563a67..0a11bb50856 100755 LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)' fi ;; -@@ -14074,7 +14215,7 @@ - - - CPPFLAGS="$CPPFLAGS $LIBUUID_CFLAGS" -- LIBS="$LIBS $LIBUUID_LIBS" -+ LDFLAGS="$LDFLAGS $LIBUUID_LIBS" - for ac_header in uuid/uuid.h - do : - ac_fn_c_check_header_compile "$LINENO" "uuid/uuid.h" "ac_cv_header_uuid_uuid_h" "$ac_includes_default" -@@ -14216,7 +14357,7 @@ - - - CPPFLAGS="$CPPFLAGS $LIBUUID_CFLAGS" -- LIBS="$LIBS $LIBUUID_LIBS" -+ LDFLAGS="$LDFLAGS $LIBUUID_LIBS" - for ac_header in uuid/uuid.h - do : - ac_fn_c_check_header_compile "$LINENO" "uuid/uuid.h" "ac_cv_header_uuid_uuid_h" "$ac_includes_default" -@@ -15114,7 +15255,7 @@ - - - CPPFLAGS="$CPPFLAGS $LIBFFI_CFLAGS" -- LIBS="$LIBS $LIBFFI_LIBS" -+ LDFLAGS="$LDFLAGS $LIBFFI_LIBS" - ac_fn_c_check_header_compile "$LINENO" "ffi.h" "ac_cv_header_ffi_h" "$ac_includes_default" - if test "x$ac_cv_header_ffi_h" = xyes - then : -@@ -15196,7 +15337,7 @@ - - - CPPFLAGS="$CPPFLAGS $LIBFFI_CFLAGS" -- LIBS="$LIBS $LIBFFI_LIBS" -+ LDFLAGS="$LDFLAGS $LIBFFI_LIBS" - ac_fn_c_check_header_compile "$LINENO" "ffi.h" "ac_cv_header_ffi_h" "$ac_includes_default" - if test "x$ac_cv_header_ffi_h" = xyes - then : -@@ -15286,7 +15427,7 @@ +@@ -15286,7 +15439,7 @@ ctypes_malloc_closure=yes ;; #( @@ -705,56 +2575,7 @@ index d46bc563a67..0a11bb50856 100755 ctypes_malloc_closure=yes ;; #( -@@ -15316,8 +15457,8 @@ - save_LIBS=$LIBS - - -- CFLAGS="$CFLAGS $LIBFFI_CFLAGS" -- LIBS="$LIBS $LIBFFI_LIBS" -+ CFLAGS="$LIBFFI_CFLAGS $CFLAGS" -+ LDFLAGS="$LIBFFI_LIBS $LDFLAGS" - - - -@@ -15643,8 +15784,8 @@ - save_LIBS=$LIBS - - -- CPPFLAGS="$CPPFLAGS $LIBMPDEC_CFLAGS" -- LIBS="$LIBS $LIBMPDEC_LIBS" -+ CPPFLAGS="$LIBMPDEC_CFLAGS $CPPFLAGS" -+ LIBS="$LIBMPDEC_LIBS $LIBS" - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ -@@ -15914,7 +16055,7 @@ - - - CPPFLAGS="$CPPFLAGS $LIBSQLITE3_CFLAGS" -- LIBS="$LIBS $LIBSQLITE3_LIBS" -+ LDFLAGS="$LIBSQLITE3_LIBS $LDFLAGS" - - ac_fn_c_check_header_compile "$LINENO" "sqlite3.h" "ac_cv_header_sqlite3_h" "$ac_includes_default" - if test "x$ac_cv_header_sqlite3_h" = xyes -@@ -16904,7 +17045,7 @@ - - - CPPFLAGS="$CPPFLAGS $TCLTK_CFLAGS" -- LIBS="$LIBS $TCLTK_LIBS" -+ LIBS="$TCLTK_LIBS $LDFLAGS" - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ -@@ -16971,7 +17112,7 @@ - - - CPPFLAGS="$CPPFLAGS $GDBM_CFLAGS" -- LIBS="$LIBS $GDBM_LIBS" -+ LDFLAGS="$GDBM_LIBS $LDFLAGS" - for ac_header in gdbm.h - do : - ac_fn_c_check_header_compile "$LINENO" "gdbm.h" "ac_cv_header_gdbm_h" "$ac_includes_default" -@@ -19038,12 +19179,6 @@ +@@ -19038,12 +19191,6 @@ then : printf "%s\n" "#define HAVE_DUP3 1" >>confdefs.h @@ -767,7 +2588,7 @@ index d46bc563a67..0a11bb50856 100755 fi ac_fn_c_check_func "$LINENO" "explicit_bzero" "ac_cv_func_explicit_bzero" if test "x$ac_cv_func_explicit_bzero" = xyes -@@ -19104,18 +19239,6 @@ +@@ -19104,18 +19251,6 @@ then : printf "%s\n" "#define HAVE_FEXECVE 1" >>confdefs.h @@ -786,7 +2607,7 @@ index d46bc563a67..0a11bb50856 100755 fi ac_fn_c_check_func "$LINENO" "fpathconf" "ac_cv_func_fpathconf" if test "x$ac_cv_func_fpathconf" = xyes -@@ -19542,24 +19665,6 @@ +@@ -19542,24 +19677,6 @@ then : printf "%s\n" "#define HAVE_POSIX_OPENPT 1" >>confdefs.h @@ -811,7 +2632,7 @@ index d46bc563a67..0a11bb50856 100755 fi ac_fn_c_check_func "$LINENO" "pread" "ac_cv_func_pread" if test "x$ac_cv_func_pread" = xyes -@@ -19860,12 +19965,6 @@ +@@ -19860,12 +19977,6 @@ then : printf "%s\n" "#define HAVE_SIGACTION 1" >>confdefs.h @@ -824,21 +2645,7 @@ index d46bc563a67..0a11bb50856 100755 fi ac_fn_c_check_func "$LINENO" "sigfillset" "ac_cv_func_sigfillset" if test "x$ac_cv_func_sigfillset" = xyes -@@ -20011,10 +20110,10 @@ - printf "%s\n" "#define HAVE_TRUNCATE 1" >>confdefs.h - - fi --ac_fn_c_check_func "$LINENO" "ttyname_r" "ac_cv_func_ttyname_r" --if test "x$ac_cv_func_ttyname_r" = xyes -+ac_fn_c_check_func "$LINENO" "ttyname" "ac_cv_func_ttyname" -+if test "x$ac_cv_func_ttyname" = xyes - then : -- printf "%s\n" "#define HAVE_TTYNAME_R 1" >>confdefs.h -+ printf "%s\n" "#define HAVE_TTYNAME 1" >>confdefs.h - - fi - ac_fn_c_check_func "$LINENO" "umask" "ac_cv_func_umask" -@@ -20134,11 +20233,11 @@ +@@ -20134,11 +20245,11 @@ fi @@ -852,7 +2659,7 @@ index d46bc563a67..0a11bb50856 100755 ac_fn_c_check_func "$LINENO" "getentropy" "ac_cv_func_getentropy" if test "x$ac_cv_func_getentropy" = xyes then : -@@ -20160,6 +20259,53 @@ +@@ -20160,6 +20271,53 @@ fi @@ -906,61 +2713,7 @@ index d46bc563a67..0a11bb50856 100755 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5 printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; } if test ${ac_cv_c_undeclared_builtin_options+y} -@@ -21530,7 +21676,7 @@ - - - CPPFLAGS="$CPPFLAGS $ZLIB_CFLAGS" -- LIBS="$LIBS $ZLIB_LIBS" -+ LDFLAGS="$LDFLAGS $ZLIB_LIBS" - for ac_header in zlib.h - do : - ac_fn_c_check_header_compile "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" -@@ -21677,7 +21823,7 @@ - - - CPPFLAGS="$CPPFLAGS $ZLIB_CFLAGS" -- LIBS="$LIBS $ZLIB_LIBS" -+ LDFLAGS="$LDFLAGS $ZLIB_LIBS" - for ac_header in zlib.h - do : - ac_fn_c_check_header_compile "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" -@@ -21914,7 +22060,7 @@ - - - CPPFLAGS="$CPPFLAGS $BZIP2_CFLAGS" -- LIBS="$LIBS $BZIP2_LIBS" -+ LDFLAGS="$LDFLAGS $BZIP2_LIBS" - for ac_header in bzlib.h - do : - ac_fn_c_check_header_compile "$LINENO" "bzlib.h" "ac_cv_header_bzlib_h" "$ac_includes_default" -@@ -22006,7 +22152,7 @@ - - - CPPFLAGS="$CPPFLAGS $BZIP2_CFLAGS" -- LIBS="$LIBS $BZIP2_LIBS" -+ LDFLAGS="$LDFLAGS $BZIP2_LIBS" - for ac_header in bzlib.h - do : - ac_fn_c_check_header_compile "$LINENO" "bzlib.h" "ac_cv_header_bzlib_h" "$ac_includes_default" -@@ -22162,7 +22308,7 @@ - - - CPPFLAGS="$CPPFLAGS $LIBLZMA_CFLAGS" -- LIBS="$LIBS $LIBLZMA_LIBS" -+ LDFLAGS="$LDFLAGS $LIBLZMA_LIBS" - for ac_header in lzma.h - do : - ac_fn_c_check_header_compile "$LINENO" "lzma.h" "ac_cv_header_lzma_h" "$ac_includes_default" -@@ -22254,7 +22400,7 @@ - - - CPPFLAGS="$CPPFLAGS $LIBLZMA_CFLAGS" -- LIBS="$LIBS $LIBLZMA_LIBS" -+ LDFLAGS="$LDFLAGS $LIBLZMA_LIBS" - for ac_header in lzma.h - do : - ac_fn_c_check_header_compile "$LINENO" "lzma.h" "ac_cv_header_lzma_h" "$ac_includes_default" -@@ -23242,7 +23388,8 @@ +@@ -23242,7 +23400,8 @@ # check for openpty, login_tty, and forkpty @@ -970,7 +2723,16 @@ index d46bc563a67..0a11bb50856 100755 for ac_func in openpty do : -@@ -23539,6 +23686,7 @@ +@@ -23356,7 +23515,7 @@ + fi + + done +-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing login_tty" >&5 ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing login_tty" >&5 + printf %s "checking for library containing login_tty... " >&6; } + if test ${ac_cv_search_login_tty+y} + then : +@@ -23539,6 +23698,7 @@ fi done @@ -978,7 +2740,7 @@ index d46bc563a67..0a11bb50856 100755 # check for long file support functions ac_fn_c_check_func "$LINENO" "fseek64" "ac_cv_func_fseek64" -@@ -23804,10 +23952,10 @@ +@@ -23804,10 +23964,10 @@ done @@ -991,7 +2753,7 @@ index d46bc563a67..0a11bb50856 100755 then for ac_func in clock_settime -@@ -26146,8 +26294,8 @@ +@@ -26146,8 +26306,8 @@ LIBPYTHON="\$(BLDLIBRARY)" fi @@ -1002,43 +2764,7 @@ index d46bc563a67..0a11bb50856 100755 MODULE_DEPS_SHARED="$MODULE_DEPS_SHARED \$(PYTHONFRAMEWORKDIR)/\$(PYTHONFRAMEWORK)" fi -@@ -26497,7 +26645,7 @@ - - - CPPFLAGS="$CPPFLAGS $LIBREADLINE_CFLAGS" -- LIBS="$LIBS $LIBREADLINE_LIBS" -+ LDFLAGS="$LDFLAGS $LIBREADLINE_LIBS" - for ac_header in readline/readline.h - do : - ac_fn_c_check_header_compile "$LINENO" "readline/readline.h" "ac_cv_header_readline_readline_h" "$ac_includes_default" -@@ -26659,7 +26807,7 @@ - - - CPPFLAGS="$CPPFLAGS $LIBEDIT_CFLAGS" -- LIBS="$LIBS $LIBEDIT_LIBS" -+ LDFLAGS="$LDFLAGS $LIBEDIT_LIBS" - for ac_header in editline/readline.h - do : - ac_fn_c_check_header_compile "$LINENO" "editline/readline.h" "ac_cv_header_editline_readline_h" "$ac_includes_default" -@@ -26750,7 +26898,7 @@ - - - CPPFLAGS="$CPPFLAGS $LIBEDIT_CFLAGS" -- LIBS="$LIBS $LIBEDIT_LIBS" -+ LDFLAGS="$LDFLAGS $LIBEDIT_LIBS" - for ac_header in editline/readline.h - do : - ac_fn_c_check_header_compile "$LINENO" "editline/readline.h" "ac_cv_header_editline_readline_h" "$ac_includes_default" -@@ -26868,7 +27016,7 @@ - - - CPPFLAGS="$CPPFLAGS $READLINE_CFLAGS" -- LIBS="$LIBS $READLINE_LIBS" -+ LIBS="$READLINE_LIBS $LIBS" - LIBS_SAVE=$LIBS - - -@@ -29017,7 +29165,7 @@ +@@ -29017,7 +29177,7 @@ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for device files" >&5 printf "%s\n" "$as_me: checking for device files" >&6;} @@ -1047,7 +2773,7 @@ index d46bc563a67..0a11bb50856 100755 ac_cv_file__dev_ptmx=no ac_cv_file__dev_ptc=no else -@@ -29510,7 +29658,7 @@ +@@ -29510,7 +29670,7 @@ with_ensurepip=no ;; #( WASI) : with_ensurepip=no ;; #( @@ -1056,7 +2782,7 @@ index d46bc563a67..0a11bb50856 100755 with_ensurepip=no ;; #( *) : with_ensurepip=upgrade -@@ -30490,7 +30638,7 @@ +@@ -30490,7 +30650,7 @@ ;; #( Darwin) : ;; #( @@ -1065,7 +2791,7 @@ index d46bc563a67..0a11bb50856 100755 -@@ -34493,6 +34641,8 @@ +@@ -34493,6 +34653,8 @@ "Mac/Resources/framework/Info.plist") CONFIG_FILES="$CONFIG_FILES Mac/Resources/framework/Info.plist" ;; "Mac/Resources/app/Info.plist") CONFIG_FILES="$CONFIG_FILES Mac/Resources/app/Info.plist" ;; "iOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES iOS/Resources/Info.plist" ;; @@ -1075,7 +2801,7 @@ index d46bc563a67..0a11bb50856 100755 "Misc/python.pc") CONFIG_FILES="$CONFIG_FILES Misc/python.pc" ;; "Misc/python-embed.pc") CONFIG_FILES="$CONFIG_FILES Misc/python-embed.pc" ;; diff --git a/configure.ac b/configure.ac -index faa89095303..660e1c638ec 100644 +index faa89095303..9bd51f7da97 100644 --- a/configure.ac +++ b/configure.ac @@ -330,6 +330,12 @@ @@ -1416,24 +3142,6 @@ index faa89095303..660e1c638ec 100644 LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)' fi ;; -@@ -3735,7 +3866,7 @@ - ], [ - WITH_SAVE_ENV([ - CPPFLAGS="$CPPFLAGS $LIBUUID_CFLAGS" -- LIBS="$LIBS $LIBUUID_LIBS" -+ LDFLAGS="$LDFLAGS $LIBUUID_LIBS" - AC_CHECK_HEADERS([uuid/uuid.h], [ - PY_CHECK_LIB([uuid], [uuid_generate_time], [have_uuid=yes]) - PY_CHECK_LIB([uuid], [uuid_generate_time_safe], -@@ -4005,7 +4136,7 @@ - PKG_CHECK_MODULES([LIBFFI], [libffi], [have_libffi=yes], [ - WITH_SAVE_ENV([ - CPPFLAGS="$CPPFLAGS $LIBFFI_CFLAGS" -- LIBS="$LIBS $LIBFFI_LIBS" -+ LDFLAGS="$LDFLAGS $LIBFFI_LIBS" - AC_CHECK_HEADER([ffi.h], [ - AC_CHECK_LIB([ffi], [ffi_call], [ - have_libffi=yes @@ -4024,7 +4155,7 @@ dnl when do we need USING_APPLE_OS_LIBFFI? ctypes_malloc_closure=yes @@ -1606,46 +3314,6 @@ index c3e261ecd9e..26ef7a95de4 100644 CFBundleSupportedPlatforms iPhoneOS ---- /dev/null -+++ b/iOS/Resources/bin/arm64-apple-ios-macabi-ar -@@ -0,0 +1,2 @@ -+#!/bin/sh -+xcrun --sdk macosx${MACOSX_SDK_VERSION} ar "$@" ---- /dev/null -+++ b/iOS/Resources/bin/arm64-apple-ios-macabi-clang -@@ -0,0 +1,2 @@ -+#!/bin/sh -+xcrun --sdk macosx${MACOSX_SDK_VERSION} clang -target arm64-apple-ios-macabi "$@" ---- /dev/null -+++ b/iOS/Resources/bin/arm64-apple-ios-macabi-clang++ -@@ -0,0 +1,2 @@ -+#!/bin/sh -+xcrun --sdk macosx${MACOSX_SDK_VERSION} clang++ -target arm64-apple-ios-macabi "$@" ---- /dev/null -+++ b/iOS/Resources/bin/arm64-apple-ios-macabi-cpp -@@ -0,0 +1,2 @@ -+#!/bin/sh -+xcrun --sdk macosx${MACOSX_SDK_VERSION} clang -target arm64-apple-ios-macabi "$@" ---- /dev/null -+++ b/iOS/Resources/bin/x86_64-apple-ios-macabi-ar -@@ -0,0 +1,2 @@ -+#!/bin/sh -+xcrun --sdk macosx${MACOSX_SDK_VERSION} ar "$@" ---- /dev/null -+++ b/iOS/Resources/bin/x86_64-apple-ios-macabi-clang -@@ -0,0 +1,2 @@ -+#!/bin/sh -+xcrun --sdk macosx${MACOSX_SDK_VERSION} clang -target x86_64-apple-ios-macabi "$@" ---- /dev/null -+++ b/iOS/Resources/bin/x86_64-apple-ios-macabi-clang++ -@@ -0,0 +1,2 @@ -+#!/bin/sh -+xcrun --sdk macosx${MACOSX_SDK_VERSION} clang++ -target x86_64-apple-ios-macabi "$@" ---- /dev/null -+++ b/iOS/Resources/bin/x86_64-apple-ios-macabi-cpp -@@ -0,0 +1,2 @@ -+#!/bin/sh -+xcrun --sdk macosx${MACOSX_SDK_VERSION} clang -target x86_64-apple-ios-macabi "$@" diff --git a/iOS/testbed/__main__.py b/iOS/testbed/__main__.py index b4499f5ac17..d12a5ab065b 100644 --- a/iOS/testbed/__main__.py From 4904b7628c0a12bf23dd22557fddae9189807e66 Mon Sep 17 00:00:00 2001 From: Andrew Savva Date: Sun, 9 Mar 2025 22:22:06 +0000 Subject: [PATCH 05/10] Revert the diff.exclude change --- patch/Python/diff.exclude | 2 -- 1 file changed, 2 deletions(-) diff --git a/patch/Python/diff.exclude b/patch/Python/diff.exclude index da24a271..f5c3faae 100644 --- a/patch/Python/diff.exclude +++ b/patch/Python/diff.exclude @@ -3,6 +3,4 @@ .gitignore .mention-bot .travis.yml -PCbuild/* -Doc/* Misc/NEWS.d/* \ No newline at end of file From 072bfd766b7647ffe5715131b71bad6eaad5835c Mon Sep 17 00:00:00 2001 From: Andrew Savva Date: Tue, 11 Mar 2025 21:19:42 +0000 Subject: [PATCH 06/10] Remove the CC/CXX/CFLAGS/LDFLAGS settings --- Makefile | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/Makefile b/Makefile index 8f032a11..e2e6d083 100644 --- a/Makefile +++ b/Makefile @@ -151,14 +151,6 @@ TARGET_TRIPLE_SUFFIX-$(target)="" endif SDK_ROOT-$(target)=$$(shell xcrun --sdk $$(SDK-$(target)) --show-sdk-path) -CC-$(target)=$$(subst $$(VERSION_MIN-$(os)),,$$(TARGET_TRIPLE-$(target))-clang) -CXX-$(target)=$$(subst $$(VERSION_MIN-$(os)),,$$(TARGET_TRIPLE-$(target))-clang++) -CFLAGS-$(target)=\ - --sysroot=$$(SDK_ROOT-$(target)) \ - $$(CFLAGS-$(os)) -LDFLAGS-$(target)=\ - -isysroot $$(SDK_ROOT-$(target)) \ - $$(CFLAGS-$(os)) ########################################################################### # Target: BZip2 @@ -310,11 +302,6 @@ $$(PYTHON_SRCDIR-$(target))/Makefile: \ cd $$(PYTHON_SRCDIR-$(target)) && \ PATH="$(PROJECT_DIR)/support/$(PYTHON_VER)/$(os)/Tools:$(PROJECT_DIR)/$$(PYTHON_SRCDIR-$(target))/$(os)/Resources/bin:$(PATH)" \ ./configure \ - CC="$$(CC-$(target))" \ - CXX="$$(CXX-$(target))" \ - CPP="$$(CXX-$(target)) -E" \ - CFLAGS="$$(CFLAGS-$(target))" \ - LDFLAGS="$$(LDFLAGS-$(target))" \ LIBLZMA_CFLAGS="-I$$(XZ_INSTALL-$(target))/include" \ LIBLZMA_LIBS="-L$$(XZ_INSTALL-$(target))/lib -llzma" \ BZIP2_CFLAGS="-I$$(BZIP2_INSTALL-$(target))/include" \ From f8efec4f6d21b71aa44ea38c3cde9e2695ada5bf Mon Sep 17 00:00:00 2001 From: Andrew Savva Date: Tue, 11 Mar 2025 21:23:42 +0000 Subject: [PATCH 07/10] Revert the PATH change --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index e2e6d083..bc91150d 100644 --- a/Makefile +++ b/Makefile @@ -300,7 +300,7 @@ $$(PYTHON_SRCDIR-$(target))/Makefile: \ $$(PYTHON_SRCDIR-$(target))/configure # Configure target Python cd $$(PYTHON_SRCDIR-$(target)) && \ - PATH="$(PROJECT_DIR)/support/$(PYTHON_VER)/$(os)/Tools:$(PROJECT_DIR)/$$(PYTHON_SRCDIR-$(target))/$(os)/Resources/bin:$(PATH)" \ + PATH="$(PROJECT_DIR)/$$(PYTHON_SRCDIR-$(target))/$(os)/Resources/bin:$(PATH)" \ ./configure \ LIBLZMA_CFLAGS="-I$$(XZ_INSTALL-$(target))/include" \ LIBLZMA_LIBS="-L$$(XZ_INSTALL-$(target))/lib -llzma" \ @@ -322,14 +322,14 @@ $$(PYTHON_SRCDIR-$(target))/Makefile: \ $$(PYTHON_SRCDIR-$(target))/python.exe: $$(PYTHON_SRCDIR-$(target))/Makefile @echo ">>> Build Python for $(target)" cd $$(PYTHON_SRCDIR-$(target)) && \ - PATH="$(PROJECT_DIR)/support/$(PYTHON_VER)/$(os)/Tools:$(PROJECT_DIR)/$$(PYTHON_SRCDIR-$(target))/$(os)/Resources/bin:$(PATH)" \ + PATH="$(PROJECT_DIR)/$$(PYTHON_SRCDIR-$(target))/$(os)/Resources/bin:$(PATH)" \ make -j8 all \ 2>&1 | tee -a ../python-$(PYTHON_VERSION).build.log $$(PYTHON_LIB-$(target)): $$(PYTHON_SRCDIR-$(target))/python.exe @echo ">>> Install Python for $(target)" cd $$(PYTHON_SRCDIR-$(target)) && \ - PATH="$(PROJECT_DIR)/support/$(PYTHON_VER)/$(os)/Tools:$(PROJECT_DIR)/$$(PYTHON_SRCDIR-$(target))/$(os)/Resources/bin:$(PATH)" \ + PATH="$(PROJECT_DIR)/$$(PYTHON_SRCDIR-$(target))/$(os)/Resources/bin:$(PATH)" \ make install \ 2>&1 | tee -a ../python-$(PYTHON_VERSION).install.log From 4e9e3c6211b650e1b1e2ed6605852c0a207e3440 Mon Sep 17 00:00:00 2001 From: Andrew Savva Date: Tue, 11 Mar 2025 21:24:04 +0000 Subject: [PATCH 08/10] Update the python patch --- patch/Python/Python.patch | 2082 ++----------------------------------- 1 file changed, 97 insertions(+), 1985 deletions(-) diff --git a/patch/Python/Python.patch b/patch/Python/Python.patch index 39690e71..ab1f1bd3 100644 --- a/patch/Python/Python.patch +++ b/patch/Python/Python.patch @@ -132,384 +132,6 @@ index 69f72452c40..34ce643340b 100644 import _osx_support osname, release, machine = _osx_support.get_platform_osx( --- /dev/null -+++ b/MacCatalyst/README.rst -@@ -0,0 +1,375 @@ -+==================== -+Python on iOS README -+==================== -+ -+:Authors: -+ Russell Keith-Magee (2023-11) -+ -+This document provides a quick overview of some iOS specific features in the -+Python distribution. -+ -+These instructions are only needed if you're planning to compile Python for iOS -+yourself. Most users should *not* need to do this. If you're looking to -+experiment with writing an iOS app in Python, tools such as `BeeWare's Briefcase -+`__ and `Kivy's Buildozer -+`__ will provide a much more approachable -+user experience. -+ -+Compilers for building on iOS -+============================= -+ -+Building for iOS requires the use of Apple's Xcode tooling. It is strongly -+recommended that you use the most recent stable release of Xcode. This will -+require the use of the most (or second-most) recently released macOS version, -+as Apple does not maintain Xcode for older macOS versions. The Xcode Command -+Line Tools are not sufficient for iOS development; you need a *full* Xcode -+install. -+ -+If you want to run your code on the iOS simulator, you'll also need to install -+an iOS Simulator Platform. You should be prompted to select an iOS Simulator -+Platform when you first run Xcode. Alternatively, you can add an iOS Simulator -+Platform by selecting an open the Platforms tab of the Xcode Settings panel. -+ -+iOS specific arguments to configure -+=================================== -+ -+* ``--enable-framework[=DIR]`` -+ -+ This argument specifies the location where the Python.framework will be -+ installed. If ``DIR`` is not specified, the framework will be installed into -+ a subdirectory of the ``iOS/Frameworks`` folder. -+ -+ This argument *must* be provided when configuring iOS builds. iOS does not -+ support non-framework builds. -+ -+* ``--with-framework-name=NAME`` -+ -+ Specify the name for the Python framework; defaults to ``Python``. -+ -+ .. admonition:: Use this option with care! -+ -+ Unless you know what you're doing, changing the name of the Python -+ framework on iOS is not advised. If you use this option, you won't be able -+ to run the ``make testios`` target without making significant manual -+ alterations, and you won't be able to use any binary packages unless you -+ compile them yourself using your own framework name. -+ -+Building Python on iOS -+====================== -+ -+ABIs and Architectures -+---------------------- -+ -+iOS apps can be deployed on physical devices, and on the iOS simulator. Although -+the API used on these devices is identical, the ABI is different - you need to -+link against different libraries for an iOS device build (``iphoneos``) or an -+iOS simulator build (``iphonesimulator``). -+ -+Apple uses the ``XCframework`` format to allow specifying a single dependency -+that supports multiple ABIs. An ``XCframework`` is a wrapper around multiple -+ABI-specific frameworks that share a common API. -+ -+iOS can also support different CPU architectures within each ABI. At present, -+there is only a single supported architecture on physical devices - ARM64. -+However, the *simulator* supports 2 architectures - ARM64 (for running on Apple -+Silicon machines), and x86_64 (for running on older Intel-based machines). -+ -+To support multiple CPU architectures on a single platform, Apple uses a "fat -+binary" format - a single physical file that contains support for multiple -+architectures. It is possible to compile and use a "thin" single architecture -+version of a binary for testing purposes; however, the "thin" binary will not be -+portable to machines using other architectures. -+ -+Building a single-architecture framework -+---------------------------------------- -+ -+The Python build system will create a ``Python.framework`` that supports a -+*single* ABI with a *single* architecture. Unlike macOS, iOS does not allow a -+framework to contain non-library content, so the iOS build will produce a -+``bin`` and ``lib`` folder in the same output folder as ``Python.framework``. -+The ``lib`` folder will be needed at runtime to support the Python library. -+ -+If you want to use Python in a real iOS project, you need to produce multiple -+``Python.framework`` builds, one for each ABI and architecture. iOS builds of -+Python *must* be constructed as framework builds. To support this, you must -+provide the ``--enable-framework`` flag when configuring the build. The build -+also requires the use of cross-compilation. The minimal commands for building -+Python for the ARM64 iOS simulator will look something like:: -+ -+ $ export PATH="$(pwd)/iOS/Resources/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin" -+ $ ./configure \ -+ --enable-framework \ -+ --host=arm64-apple-ios-simulator \ -+ --build=arm64-apple-darwin \ -+ --with-build-python=/path/to/python.exe -+ $ make -+ $ make install -+ -+In this invocation: -+ -+* ``iOS/Resources/bin`` has been added to the path, providing some shims for the -+ compilers and linkers needed by the build. Xcode requires the use of ``xcrun`` -+ to invoke compiler tooling. However, if ``xcrun`` is pre-evaluated and the -+ result passed to ``configure``, these results can embed user- and -+ version-specific paths into the sysconfig data, which limits the portability -+ of the compiled Python. Alternatively, if ``xcrun`` is used *as* the compiler, -+ it requires that compiler variables like ``CC`` include spaces, which can -+ cause significant problems with many C configuration systems which assume that -+ ``CC`` will be a single executable. -+ -+ To work around this problem, the ``iOS/Resources/bin`` folder contains some -+ wrapper scripts that present as simple compilers and linkers, but wrap -+ underlying calls to ``xcrun``. This allows configure to use a ``CC`` -+ definition without spaces, and without user- or version-specific paths, while -+ retaining the ability to adapt to the local Xcode install. These scripts are -+ included in the ``bin`` directory of an iOS install. -+ -+ These scripts will, by default, use the currently active Xcode installation. -+ If you want to use a different Xcode installation, you can use -+ ``xcode-select`` to set a new default Xcode globally, or you can use the -+ ``DEVELOPER_DIR`` environment variable to specify an Xcode install. The -+ scripts will use the default ``iphoneos``/``iphonesimulator`` SDK version for -+ the select Xcode install; if you want to use a different SDK, you can set the -+ ``IOS_SDK_VERSION`` environment variable. (e.g, setting -+ ``IOS_SDK_VERSION=17.1`` would cause the scripts to use the ``iphoneos17.1`` -+ and ``iphonesimulator17.1`` SDKs, regardless of the Xcode default.) -+ -+ The path has also been cleared of any user customizations. A common source of -+ bugs is for tools like Homebrew to accidentally leak macOS binaries into an iOS -+ build. Resetting the path to a known "bare bones" value is the easiest way to -+ avoid these problems. -+ -+* ``--host`` is the architecture and ABI that you want to build, in GNU compiler -+ triple format. This will be one of: -+ -+ - ``arm64-apple-ios`` for ARM64 iOS devices. -+ - ``arm64-apple-ios-simulator`` for the iOS simulator running on Apple -+ Silicon devices. -+ - ``x86_64-apple-ios-simulator`` for the iOS simulator running on Intel -+ devices. -+ -+* ``--build`` is the GNU compiler triple for the machine that will be running -+ the compiler. This is one of: -+ -+ - ``arm64-apple-darwin`` for Apple Silicon devices. -+ - ``x86_64-apple-darwin`` for Intel devices. -+ -+* ``/path/to/python.exe`` is the path to a Python binary on the machine that -+ will be running the compiler. This is needed because the Python compilation -+ process involves running some Python code. On a normal desktop build of -+ Python, you can compile a python interpreter and then use that interpreter to -+ run Python code. However, the binaries produced for iOS won't run on macOS, so -+ you need to provide an external Python interpreter. This interpreter must be -+ the same version as the Python that is being compiled. To be completely safe, -+ this should be the *exact* same commit hash. However, the longer a Python -+ release has been stable, the more likely it is that this constraint can be -+ relaxed - the same micro version will often be sufficient. -+ -+* The ``install`` target for iOS builds is slightly different to other -+ platforms. On most platforms, ``make install`` will install the build into -+ the final runtime location. This won't be the case for iOS, as the final -+ runtime location will be on a physical device. -+ -+ However, you still need to run the ``install`` target for iOS builds, as it -+ performs some final framework assembly steps. The location specified with -+ ``--enable-framework`` will be the location where ``make install`` will -+ assemble the complete iOS framework. This completed framework can then -+ be copied and relocated as required. -+ -+For a full CPython build, you also need to specify the paths to iOS builds of -+the binary libraries that CPython depends on (XZ, BZip2, LibFFI and OpenSSL). -+This can be done by defining the ``LIBLZMA_CFLAGS``, ``LIBLZMA_LIBS``, -+``BZIP2_CFLAGS``, ``BZIP2_LIBS``, ``LIBFFI_CFLAGS``, and ``LIBFFI_LIBS`` -+environment variables, and the ``--with-openssl`` configure option. Versions of -+these libraries pre-compiled for iOS can be found in `this repository -+`__. LibFFI is -+especially important, as many parts of the standard library (including the -+``platform``, ``sysconfig`` and ``webbrowser`` modules) require the use of the -+``ctypes`` module at runtime. -+ -+By default, Python will be compiled with an iOS deployment target (i.e., the -+minimum supported iOS version) of 13.0. To specify a different deployment -+target, provide the version number as part of the ``--host`` argument - for -+example, ``--host=arm64-apple-ios15.4-simulator`` would compile an ARM64 -+simulator build with a deployment target of 15.4. -+ -+Merge thin frameworks into fat frameworks -+----------------------------------------- -+ -+Once you've built a ``Python.framework`` for each ABI and and architecture, you -+must produce a "fat" framework for each ABI that contains all the architectures -+for that ABI. -+ -+The ``iphoneos`` build only needs to support a single architecture, so it can be -+used without modification. -+ -+If you only want to support a single simulator architecture, (e.g., only support -+ARM64 simulators), you can use a single architecture ``Python.framework`` build. -+However, if you want to create ``Python.xcframework`` that supports *all* -+architectures, you'll need to merge the ``iphonesimulator`` builds for ARM64 and -+x86_64 into a single "fat" framework. -+ -+The "fat" framework can be constructed by performing a directory merge of the -+content of the two "thin" ``Python.framework`` directories, plus the ``bin`` and -+``lib`` folders for each thin framework. When performing this merge: -+ -+* The pure Python standard library content is identical for each architecture, -+ except for a handful of platform-specific files (such as the ``sysconfig`` -+ module). Ensure that the "fat" framework has the union of all standard library -+ files. -+ -+* Any binary files in the standard library, plus the main -+ ``libPython3.X.dylib``, can be merged using the ``lipo`` tool, provide by -+ Xcode:: -+ -+ $ lipo -create -output module.dylib path/to/x86_64/module.dylib path/to/arm64/module.dylib -+ -+* The header files will be identical on both architectures, except for -+ ``pyconfig.h``. Copy all the headers from one platform (say, arm64), rename -+ ``pyconfig.h`` to ``pyconfig-arm64.h``, and copy the ``pyconfig.h`` for the -+ other architecture into the merged header folder as ``pyconfig-x86_64.h``. -+ Then copy the ``iOS/Resources/pyconfig.h`` file from the CPython sources into -+ the merged headers folder. This will allow the two Python architectures to -+ share a common ``pyconfig.h`` header file. -+ -+At this point, you should have 2 Python.framework folders - one for ``iphoneos``, -+and one for ``iphonesimulator`` that is a merge of x86+64 and ARM64 content. -+ -+Merge frameworks into an XCframework -+------------------------------------ -+ -+Now that we have 2 (potentially fat) ABI-specific frameworks, we can merge those -+frameworks into a single ``XCframework``. -+ -+The initial skeleton of an ``XCframework`` is built using:: -+ -+ xcodebuild -create-xcframework -output Python.xcframework -framework path/to/iphoneos/Python.framework -framework path/to/iphonesimulator/Python.framework -+ -+Then, copy the ``bin`` and ``lib`` folders into the architecture-specific slices of -+the XCframework:: -+ -+ cp path/to/iphoneos/bin Python.xcframework/ios-arm64 -+ cp path/to/iphoneos/lib Python.xcframework/ios-arm64 -+ -+ cp path/to/iphonesimulator/bin Python.xcframework/ios-arm64_x86_64-simulator -+ cp path/to/iphonesimulator/lib Python.xcframework/ios-arm64_x86_64-simulator -+ -+Note that the name of the architecture-specific slice for the simulator will -+depend on the CPU architecture(s) that you build. -+ -+You now have a Python.xcframework that can be used in a project. -+ -+Testing Python on iOS -+===================== -+ -+The ``iOS/testbed`` folder that contains an Xcode project that is able to run -+the iOS test suite. This project converts the Python test suite into a single -+test case in Xcode's XCTest framework. The single XCTest passes if the test -+suite passes. -+ -+To run the test suite, configure a Python build for an iOS simulator (i.e., -+``--host=arm64-apple-ios-simulator`` or ``--host=x86_64-apple-ios-simulator`` -+), specifying a framework build (i.e. ``--enable-framework``). Ensure that your -+``PATH`` has been configured to include the ``iOS/Resources/bin`` folder and -+exclude any non-iOS tools, then run:: -+ -+ $ make all -+ $ make install -+ $ make testios -+ -+This will: -+ -+* Build an iOS framework for your chosen architecture; -+* Finalize the single-platform framework; -+* Make a clean copy of the testbed project; -+* Install the Python iOS framework into the copy of the testbed project; and -+* Run the test suite on an "iPhone SE (3rd generation)" simulator. -+ -+On success, the test suite will exit and report successful completion of the -+test suite. On a 2022 M1 MacBook Pro, the test suite takes approximately 15 -+minutes to run; a couple of extra minutes is required to compile the testbed -+project, and then boot and prepare the iOS simulator. -+ -+Debugging test failures -+----------------------- -+ -+Running ``make test`` generates a standalone version of the ``iOS/testbed`` -+project, and runs the full test suite. It does this using ``iOS/testbed`` -+itself - the folder is an executable module that can be used to create and run -+a clone of the testbed project. -+ -+You can generate your own standalone testbed instance by running:: -+ -+ $ python iOS/testbed clone --framework iOS/Frameworks/arm64-iphonesimulator my-testbed -+ -+This invocation assumes that ``iOS/Frameworks/arm64-iphonesimulator`` is the -+path to the iOS simulator framework for your platform (ARM64 in this case); -+``my-testbed`` is the name of the folder for the new testbed clone. -+ -+You can then use the ``my-testbed`` folder to run the Python test suite, -+passing in any command line arguments you may require. For example, if you're -+trying to diagnose a failure in the ``os`` module, you might run:: -+ -+ $ python my-testbed run -- test -W test_os -+ -+This is the equivalent of running ``python -m test -W test_os`` on a desktop -+Python build. Any arguments after the ``--`` will be passed to testbed as if -+they were arguments to ``python -m`` on a desktop machine. -+ -+You can also open the testbed project in Xcode by running:: -+ -+ $ open my-testbed/iOSTestbed.xcodeproj -+ -+This will allow you to use the full Xcode suite of tools for debugging. -+ -+Testing on an iOS device -+^^^^^^^^^^^^^^^^^^^^^^^^ -+ -+To test on an iOS device, the app needs to be signed with known developer -+credentials. To obtain these credentials, you must have an iOS Developer -+account, and your Xcode install will need to be logged into your account (see -+the Accounts tab of the Preferences dialog). -+ -+Once the project is open, and you're signed into your Apple Developer account, -+select the root node of the project tree (labeled "iOSTestbed"), then the -+"Signing & Capabilities" tab in the details page. Select a development team -+(this will likely be your own name), and plug in a physical device to your -+macOS machine with a USB cable. You should then be able to select your physical -+device from the list of targets in the pulldown in the Xcode titlebar. -+ -+Running specific tests -+^^^^^^^^^^^^^^^^^^^^^^ -+ -+As the test suite is being executed on an iOS simulator, it is not possible to -+pass in command line arguments to configure test suite operation. To work -+around this limitation, the arguments that would normally be passed as command -+line arguments are configured as part of the ``iOSTestbed-Info.plist`` file -+that is used to configure the iOS testbed app. In this file, the ``TestArgs`` -+key is an array containing the arguments that would be passed to ``python -m`` -+on the command line (including ``test`` in position 0, the name of the test -+module to be executed). -+ -+Disabling automated breakpoints -+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -+ -+By default, Xcode will inserts an automatic breakpoint whenever a signal is -+raised. The Python test suite raises many of these signals as part of normal -+operation; unless you are trying to diagnose an issue with signals, the -+automatic breakpoints can be inconvenient. However, they can be disabled by -+creating a symbolic breakpoint that is triggered at the start of the test run. -+ -+Select "Debug > Breakpoints > Create Symbolic Breakpoint" from the Xcode menu, and -+populate the new brewpoint with the following details: -+ -+* **Name**: IgnoreSignals -+* **Symbol**: UIApplicationMain -+* **Action**: Add debugger commands for: -+ - ``process handle SIGINT -n true -p true -s false`` -+ - ``process handle SIGUSR1 -n true -p true -s false`` -+ - ``process handle SIGUSR2 -n true -p true -s false`` -+ - ``process handle SIGXFSZ -n true -p true -s false`` -+* Check the "Automatically continue after evaluating" box. -+ -+All other details can be left blank. When the process executes the -+``UIApplicationMain`` entry point, the breakpoint will trigger, run the debugger -+commands to disable the automatic breakpoints, and automatically resume. ---- /dev/null +++ b/MacCatalyst/Resources/Info.plist.in @@ -0,0 +1,34 @@ + @@ -565,7 +187,7 @@ index 69f72452c40..34ce643340b 100644 +++ b/MacCatalyst/Resources/bin/arm64-apple-ios-macabi-cpp @@ -0,0 +1,2 @@ +#!/bin/sh -+xcrun --sdk macosx${MACOSX_SDK_VERSION} clang -target arm64-apple-ios-macabi "$@" ++xcrun --sdk macosx${MACOSX_SDK_VERSION} clang -target arm64-apple-ios-macabi -E "$@" --- /dev/null +++ b/MacCatalyst/Resources/bin/x86_64-apple-ios-macabi-ar @@ -0,0 +1,2 @@ @@ -585,7 +207,7 @@ index 69f72452c40..34ce643340b 100644 +++ b/MacCatalyst/Resources/bin/x86_64-apple-ios-macabi-cpp @@ -0,0 +1,2 @@ +#!/bin/sh -+xcrun --sdk macosx${MACOSX_SDK_VERSION} clang -target x86_64-apple-ios-macabi "$@" ++xcrun --sdk macosx${MACOSX_SDK_VERSION} clang -target x86_64-apple-ios-macabi -E "$@" --- /dev/null +++ b/MacCatalyst/Resources/dylib-Info-template.plist @@ -0,0 +1,26 @@ @@ -625,1501 +247,11 @@ index 69f72452c40..34ce643340b 100644 +#ifdef __x86_64__ +#include "pyconfig-x86_64.h" +#endif ---- /dev/null -+++ b/MacCatalyst/testbed/Python.xcframework/Info.plist -@@ -0,0 +1,44 @@ -+ -+ -+ -+ -+ AvailableLibraries -+ -+ -+ BinaryPath -+ Python.framework/Python -+ LibraryIdentifier -+ ios-arm64 -+ LibraryPath -+ Python.framework -+ SupportedArchitectures -+ -+ arm64 -+ -+ SupportedPlatform -+ ios -+ -+ -+ BinaryPath -+ Python.framework/Python -+ LibraryIdentifier -+ ios-arm64_x86_64-simulator -+ LibraryPath -+ Python.framework -+ SupportedArchitectures -+ -+ arm64 -+ x86_64 -+ -+ SupportedPlatform -+ ios -+ SupportedPlatformVariant -+ simulator -+ -+ -+ CFBundlePackageType -+ XFWK -+ XCFrameworkFormatVersion -+ 1.0 -+ -+ ---- /dev/null -+++ b/MacCatalyst/testbed/Python.xcframework/ios-arm64/README -@@ -0,0 +1,4 @@ -+This directory is intentionally empty. -+ -+It should be used as a target for `--enable-framework` when compiling an iOS on-device -+build for testing purposes. ---- /dev/null -+++ b/MacCatalyst/testbed/Python.xcframework/ios-arm64_x86_64-simulator/README -@@ -0,0 +1,4 @@ -+This directory is intentionally empty. -+ -+It should be used as a target for `--enable-framework` when compiling an iOS simulator -+build for testing purposes (either x86_64 or ARM64). ---- /dev/null -+++ b/MacCatalyst/testbed/__main__.py -@@ -0,0 +1,456 @@ -+import argparse -+import asyncio -+import json -+import plistlib -+import re -+import shutil -+import subprocess -+import sys -+from contextlib import asynccontextmanager -+from datetime import datetime -+from pathlib import Path -+ -+ -+DECODE_ARGS = ("UTF-8", "backslashreplace") -+ -+# The system log prefixes each line: -+# 2025-01-17 16:14:29.090 Df iOSTestbed[23987:1fd393b4] (Python) ... -+# 2025-01-17 16:14:29.090 E iOSTestbed[23987:1fd393b4] (Python) ... -+ -+LOG_PREFIX_REGEX = re.compile( -+ r"^\d{4}-\d{2}-\d{2}" # YYYY-MM-DD -+ r"\s+\d+:\d{2}:\d{2}\.\d+" # HH:MM:SS.sss -+ r"\s+\w+" # Df/E -+ r"\s+iOSTestbed\[\d+:\w+\]" # Process/thread ID -+ r"\s+\(Python\)\s" # Logger name -+) -+ -+ -+# Work around a bug involving sys.exit and TaskGroups -+# (https://github.com/python/cpython/issues/101515). -+def exit(*args): -+ raise MySystemExit(*args) -+ -+ -+class MySystemExit(Exception): -+ pass -+ -+ -+# All subprocesses are executed through this context manager so that no matter -+# what happens, they can always be cancelled from another task, and they will -+# always be cleaned up on exit. -+@asynccontextmanager -+async def async_process(*args, **kwargs): -+ process = await asyncio.create_subprocess_exec(*args, **kwargs) -+ try: -+ yield process -+ finally: -+ if process.returncode is None: -+ # Allow a reasonably long time for Xcode to clean itself up, -+ # because we don't want stale emulators left behind. -+ timeout = 10 -+ process.terminate() -+ try: -+ await asyncio.wait_for(process.wait(), timeout) -+ except TimeoutError: -+ print( -+ f"Command {args} did not terminate after {timeout} seconds " -+ f" - sending SIGKILL" -+ ) -+ process.kill() -+ -+ # Even after killing the process we must still wait for it, -+ # otherwise we'll get the warning "Exception ignored in __del__". -+ await asyncio.wait_for(process.wait(), timeout=1) -+ -+ -+async def async_check_output(*args, **kwargs): -+ async with async_process( -+ *args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs -+ ) as process: -+ stdout, stderr = await process.communicate() -+ if process.returncode == 0: -+ return stdout.decode(*DECODE_ARGS) -+ else: -+ raise subprocess.CalledProcessError( -+ process.returncode, -+ args, -+ stdout.decode(*DECODE_ARGS), -+ stderr.decode(*DECODE_ARGS), -+ ) -+ -+ -+# Return a list of UDIDs associated with booted simulators -+async def list_devices(): -+ try: -+ # List the testing simulators, in JSON format -+ raw_json = await async_check_output( -+ "xcrun", "simctl", "--set", "testing", "list", "-j" -+ ) -+ json_data = json.loads(raw_json) -+ -+ # Filter out the booted iOS simulators -+ return [ -+ simulator["udid"] -+ for runtime, simulators in json_data["devices"].items() -+ for simulator in simulators -+ if runtime.split(".")[-1].startswith("iOS") and simulator["state"] == "Booted" -+ ] -+ except subprocess.CalledProcessError as e: -+ # If there's no ~/Library/Developer/XCTestDevices folder (which is the -+ # case on fresh installs, and in some CI environments), `simctl list` -+ # returns error code 1, rather than an empty list. Handle that case, -+ # but raise all other errors. -+ if e.returncode == 1: -+ return [] -+ else: -+ raise -+ -+ -+async def find_device(initial_devices): -+ while True: -+ new_devices = set(await list_devices()).difference(initial_devices) -+ if len(new_devices) == 0: -+ await asyncio.sleep(1) -+ elif len(new_devices) == 1: -+ udid = new_devices.pop() -+ print(f"{datetime.now():%Y-%m-%d %H:%M:%S}: New test simulator detected") -+ print(f"UDID: {udid}") -+ return udid -+ else: -+ exit(f"Found more than one new device: {new_devices}") -+ -+ -+async def log_stream_task(initial_devices): -+ # Wait up to 5 minutes for the build to complete and the simulator to boot. -+ udid = await asyncio.wait_for(find_device(initial_devices), 5 * 60) -+ -+ # Stream the iOS device's logs, filtering out messages that come from the -+ # XCTest test suite (catching NSLog messages from the test method), or -+ # Python itself (catching stdout/stderr content routed to the system log -+ # with config->use_system_logger). -+ args = [ -+ "xcrun", -+ "simctl", -+ "--set", -+ "testing", -+ "spawn", -+ udid, -+ "log", -+ "stream", -+ "--style", -+ "compact", -+ "--predicate", -+ ( -+ 'senderImagePath ENDSWITH "/iOSTestbedTests.xctest/iOSTestbedTests"' -+ ' OR senderImagePath ENDSWITH "/Python.framework/Python"' -+ ), -+ ] -+ -+ async with async_process( -+ *args, -+ stdout=subprocess.PIPE, -+ stderr=subprocess.STDOUT, -+ ) as process: -+ suppress_dupes = False -+ while line := (await process.stdout.readline()).decode(*DECODE_ARGS): -+ # Strip the prefix from each log line -+ line = LOG_PREFIX_REGEX.sub("", line) -+ # The iOS log streamer can sometimes lag; when it does, it outputs -+ # a warning about messages being dropped... often multiple times. -+ # Only print the first of these duplicated warnings. -+ if line.startswith("=== Messages dropped "): -+ if not suppress_dupes: -+ suppress_dupes = True -+ sys.stdout.write(line) -+ else: -+ suppress_dupes = False -+ sys.stdout.write(line) -+ sys.stdout.flush() -+ -+ -+async def xcode_test(location, simulator, verbose): -+ # Run the test suite on the named simulator -+ print("Starting xcodebuild...") -+ args = [ -+ "xcodebuild", -+ "test", -+ "-project", -+ str(location / "iOSTestbed.xcodeproj"), -+ "-scheme", -+ "iOSTestbed", -+ "-destination", -+ f"platform=iOS Simulator,name={simulator}", -+ "-resultBundlePath", -+ str(location / f"{datetime.now():%Y%m%d-%H%M%S}.xcresult"), -+ "-derivedDataPath", -+ str(location / "DerivedData"), -+ ] -+ if not verbose: -+ args += ["-quiet"] -+ -+ async with async_process( -+ *args, -+ stdout=subprocess.PIPE, -+ stderr=subprocess.STDOUT, -+ ) as process: -+ while line := (await process.stdout.readline()).decode(*DECODE_ARGS): -+ sys.stdout.write(line) -+ sys.stdout.flush() -+ -+ status = await asyncio.wait_for(process.wait(), timeout=1) -+ exit(status) -+ -+ -+def clone_testbed( -+ source: Path, -+ target: Path, -+ framework: Path, -+ apps: list[Path], -+) -> None: -+ if target.exists(): -+ print(f"{target} already exists; aborting without creating project.") -+ sys.exit(10) -+ -+ if framework is None: -+ if not ( -+ source / "Python.xcframework/ios-arm64_x86_64-simulator/bin" -+ ).is_dir(): -+ print( -+ f"The testbed being cloned ({source}) does not contain " -+ f"a simulator framework. Re-run with --framework" -+ ) -+ sys.exit(11) -+ else: -+ if not framework.is_dir(): -+ print(f"{framework} does not exist.") -+ sys.exit(12) -+ elif not ( -+ framework.suffix == ".xcframework" -+ or (framework / "Python.framework").is_dir() -+ ): -+ print( -+ f"{framework} is not an XCframework, " -+ f"or a simulator slice of a framework build." -+ ) -+ sys.exit(13) -+ -+ print("Cloning testbed project:") -+ print(f" Cloning {source}...", end="", flush=True) -+ shutil.copytree(source, target, symlinks=True) -+ print(" done") -+ -+ xc_framework_path = target / "Python.xcframework" -+ sim_framework_path = xc_framework_path / "ios-arm64_x86_64-simulator" -+ if framework is not None: -+ if framework.suffix == ".xcframework": -+ print(" Installing XCFramework...", end="", flush=True) -+ if xc_framework_path.is_dir(): -+ shutil.rmtree(xc_framework_path) -+ else: -+ xc_framework_path.unlink(missing_ok=True) -+ xc_framework_path.symlink_to( -+ framework.relative_to(xc_framework_path.parent, walk_up=True) -+ ) -+ print(" done") -+ else: -+ print(" Installing simulator framework...", end="", flush=True) -+ if sim_framework_path.is_dir(): -+ shutil.rmtree(sim_framework_path) -+ else: -+ sim_framework_path.unlink(missing_ok=True) -+ sim_framework_path.symlink_to( -+ framework.relative_to(sim_framework_path.parent, walk_up=True) -+ ) -+ print(" done") -+ else: -+ if ( -+ xc_framework_path.is_symlink() -+ and not xc_framework_path.readlink().is_absolute() -+ ): -+ # XCFramework is a relative symlink. Rewrite the symlink relative -+ # to the new location. -+ print(" Rewriting symlink to XCframework...", end="", flush=True) -+ orig_xc_framework_path = ( -+ source -+ / xc_framework_path.readlink() -+ ).resolve() -+ xc_framework_path.unlink() -+ xc_framework_path.symlink_to( -+ orig_xc_framework_path.relative_to( -+ xc_framework_path.parent, walk_up=True -+ ) -+ ) -+ print(" done") -+ elif ( -+ sim_framework_path.is_symlink() -+ and not sim_framework_path.readlink().is_absolute() -+ ): -+ print(" Rewriting symlink to simulator framework...", end="", flush=True) -+ # Simulator framework is a relative symlink. Rewrite the symlink -+ # relative to the new location. -+ orig_sim_framework_path = ( -+ source -+ / "Python.XCframework" -+ / sim_framework_path.readlink() -+ ).resolve() -+ sim_framework_path.unlink() -+ sim_framework_path.symlink_to( -+ orig_sim_framework_path.relative_to( -+ sim_framework_path.parent, walk_up=True -+ ) -+ ) -+ print(" done") -+ else: -+ print(" Using pre-existing iOS framework.") -+ -+ for app_src in apps: -+ print(f" Installing app {app_src.name!r}...", end="", flush=True) -+ app_target = target / f"iOSTestbed/app/{app_src.name}" -+ if app_target.is_dir(): -+ shutil.rmtree(app_target) -+ shutil.copytree(app_src, app_target) -+ print(" done") -+ -+ print(f"Successfully cloned testbed: {target.resolve()}") -+ -+ -+def update_plist(testbed_path, args): -+ # Add the test runner arguments to the testbed's Info.plist file. -+ info_plist = testbed_path / "iOSTestbed" / "iOSTestbed-Info.plist" -+ with info_plist.open("rb") as f: -+ info = plistlib.load(f) -+ -+ info["TestArgs"] = args -+ -+ with info_plist.open("wb") as f: -+ plistlib.dump(info, f) -+ -+ -+async def run_testbed(simulator: str, args: list[str], verbose: bool=False): -+ location = Path(__file__).parent -+ print("Updating plist...", end="", flush=True) -+ update_plist(location, args) -+ print(" done.") -+ -+ # Get the list of devices that are booted at the start of the test run. -+ # The simulator started by the test suite will be detected as the new -+ # entry that appears on the device list. -+ initial_devices = await list_devices() -+ -+ try: -+ async with asyncio.TaskGroup() as tg: -+ tg.create_task(log_stream_task(initial_devices)) -+ tg.create_task(xcode_test(location, simulator=simulator, verbose=verbose)) -+ except* MySystemExit as e: -+ raise SystemExit(*e.exceptions[0].args) from None -+ except* subprocess.CalledProcessError as e: -+ # Extract it from the ExceptionGroup so it can be handled by `main`. -+ raise e.exceptions[0] -+ -+ -+def main(): -+ parser = argparse.ArgumentParser( -+ description=( -+ "Manages the process of testing a Python project in the iOS simulator." -+ ), -+ ) -+ -+ subcommands = parser.add_subparsers(dest="subcommand") -+ -+ clone = subcommands.add_parser( -+ "clone", -+ description=( -+ "Clone the testbed project, copying in an iOS Python framework and" -+ "any specified application code." -+ ), -+ help="Clone a testbed project to a new location.", -+ ) -+ clone.add_argument( -+ "--framework", -+ help=( -+ "The location of the XCFramework (or simulator-only slice of an " -+ "XCFramework) to use when running the testbed" -+ ), -+ ) -+ clone.add_argument( -+ "--app", -+ dest="apps", -+ action="append", -+ default=[], -+ help="The location of any code to include in the testbed project", -+ ) -+ clone.add_argument( -+ "location", -+ help="The path where the testbed will be cloned.", -+ ) -+ -+ run = subcommands.add_parser( -+ "run", -+ usage="%(prog)s [-h] [--simulator SIMULATOR] -- [ ...]", -+ description=( -+ "Run a testbed project. The arguments provided after `--` will be " -+ "passed to the running iOS process as if they were arguments to " -+ "`python -m`." -+ ), -+ help="Run a testbed project", -+ ) -+ run.add_argument( -+ "--simulator", -+ default="iPhone SE (3rd Generation)", -+ help="The name of the simulator to use (default: 'iPhone SE (3rd Generation)')", -+ ) -+ run.add_argument( -+ "-v", "--verbose", -+ action="store_true", -+ help="Enable verbose output", -+ ) -+ -+ try: -+ pos = sys.argv.index("--") -+ testbed_args = sys.argv[1:pos] -+ test_args = sys.argv[pos + 1 :] -+ except ValueError: -+ testbed_args = sys.argv[1:] -+ test_args = [] -+ -+ context = parser.parse_args(testbed_args) -+ -+ if context.subcommand == "clone": -+ clone_testbed( -+ source=Path(__file__).parent.resolve(), -+ target=Path(context.location).resolve(), -+ framework=Path(context.framework).resolve() if context.framework else None, -+ apps=[Path(app) for app in context.apps], -+ ) -+ elif context.subcommand == "run": -+ if test_args: -+ if not ( -+ Path(__file__).parent / "Python.xcframework/ios-arm64_x86_64-simulator/bin" -+ ).is_dir(): -+ print( -+ f"Testbed does not contain a compiled iOS framework. Use " -+ f"`python {sys.argv[0]} clone ...` to create a runnable " -+ f"clone of this testbed." -+ ) -+ sys.exit(20) -+ -+ asyncio.run( -+ run_testbed( -+ simulator=context.simulator, -+ verbose=context.verbose, -+ args=test_args, -+ ) -+ ) -+ else: -+ print(f"Must specify test arguments (e.g., {sys.argv[0]} run -- test)") -+ print() -+ parser.print_help(sys.stderr) -+ sys.exit(21) -+ else: -+ parser.print_help(sys.stderr) -+ sys.exit(1) -+ -+ -+if __name__ == "__main__": -+ main() ---- /dev/null -+++ b/MacCatalyst/testbed/iOSTestbed.xcodeproj/project.pbxproj -@@ -0,0 +1,580 @@ -+// !$*UTF8*$! -+{ -+ archiveVersion = 1; -+ classes = { -+ }; -+ objectVersion = 56; -+ objects = { -+ -+/* Begin PBXBuildFile section */ -+ 607A66172B0EFA380010BFC8 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 607A66162B0EFA380010BFC8 /* AppDelegate.m */; }; -+ 607A66222B0EFA390010BFC8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607A66212B0EFA390010BFC8 /* Assets.xcassets */; }; -+ 607A66252B0EFA390010BFC8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 607A66232B0EFA390010BFC8 /* LaunchScreen.storyboard */; }; -+ 607A66282B0EFA390010BFC8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 607A66272B0EFA390010BFC8 /* main.m */; }; -+ 607A66322B0EFA3A0010BFC8 /* iOSTestbedTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 607A66312B0EFA3A0010BFC8 /* iOSTestbedTests.m */; }; -+ 607A664C2B0EFC080010BFC8 /* Python.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 607A664A2B0EFB310010BFC8 /* Python.xcframework */; }; -+ 607A664D2B0EFC080010BFC8 /* Python.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 607A664A2B0EFB310010BFC8 /* Python.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; -+ 607A66502B0EFFE00010BFC8 /* Python.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 607A664A2B0EFB310010BFC8 /* Python.xcframework */; }; -+ 607A66512B0EFFE00010BFC8 /* Python.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 607A664A2B0EFB310010BFC8 /* Python.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; -+ 607A66582B0F079F0010BFC8 /* dylib-Info-template.plist in Resources */ = {isa = PBXBuildFile; fileRef = 607A66572B0F079F0010BFC8 /* dylib-Info-template.plist */; }; -+ 608619542CB77BA900F46182 /* app_packages in Resources */ = {isa = PBXBuildFile; fileRef = 608619532CB77BA900F46182 /* app_packages */; }; -+ 608619562CB7819B00F46182 /* app in Resources */ = {isa = PBXBuildFile; fileRef = 608619552CB7819B00F46182 /* app */; }; -+/* End PBXBuildFile section */ -+ -+/* Begin PBXContainerItemProxy section */ -+ 607A662E2B0EFA3A0010BFC8 /* PBXContainerItemProxy */ = { -+ isa = PBXContainerItemProxy; -+ containerPortal = 607A660A2B0EFA380010BFC8 /* Project object */; -+ proxyType = 1; -+ remoteGlobalIDString = 607A66112B0EFA380010BFC8; -+ remoteInfo = iOSTestbed; -+ }; -+/* End PBXContainerItemProxy section */ -+ -+/* Begin PBXCopyFilesBuildPhase section */ -+ 607A664E2B0EFC080010BFC8 /* Embed Frameworks */ = { -+ isa = PBXCopyFilesBuildPhase; -+ buildActionMask = 2147483647; -+ dstPath = ""; -+ dstSubfolderSpec = 10; -+ files = ( -+ 607A664D2B0EFC080010BFC8 /* Python.xcframework in Embed Frameworks */, -+ ); -+ name = "Embed Frameworks"; -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+ 607A66522B0EFFE00010BFC8 /* Embed Frameworks */ = { -+ isa = PBXCopyFilesBuildPhase; -+ buildActionMask = 2147483647; -+ dstPath = ""; -+ dstSubfolderSpec = 10; -+ files = ( -+ 607A66512B0EFFE00010BFC8 /* Python.xcframework in Embed Frameworks */, -+ ); -+ name = "Embed Frameworks"; -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+/* End PBXCopyFilesBuildPhase section */ -+ -+/* Begin PBXFileReference section */ -+ 607A66122B0EFA380010BFC8 /* iOSTestbed.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iOSTestbed.app; sourceTree = BUILT_PRODUCTS_DIR; }; -+ 607A66152B0EFA380010BFC8 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; -+ 607A66162B0EFA380010BFC8 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; -+ 607A66212B0EFA390010BFC8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; -+ 607A66242B0EFA390010BFC8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; -+ 607A66272B0EFA390010BFC8 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; -+ 607A662D2B0EFA3A0010BFC8 /* iOSTestbedTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = iOSTestbedTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; -+ 607A66312B0EFA3A0010BFC8 /* iOSTestbedTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = iOSTestbedTests.m; sourceTree = ""; }; -+ 607A664A2B0EFB310010BFC8 /* Python.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Python.xcframework; sourceTree = ""; }; -+ 607A66572B0F079F0010BFC8 /* dylib-Info-template.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "dylib-Info-template.plist"; sourceTree = ""; }; -+ 607A66592B0F08600010BFC8 /* iOSTestbed-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "iOSTestbed-Info.plist"; sourceTree = ""; }; -+ 608619532CB77BA900F46182 /* app_packages */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app_packages; sourceTree = ""; }; -+ 608619552CB7819B00F46182 /* app */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app; sourceTree = ""; }; -+/* End PBXFileReference section */ -+ -+/* Begin PBXFrameworksBuildPhase section */ -+ 607A660F2B0EFA380010BFC8 /* Frameworks */ = { -+ isa = PBXFrameworksBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ 607A664C2B0EFC080010BFC8 /* Python.xcframework in Frameworks */, -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+ 607A662A2B0EFA3A0010BFC8 /* Frameworks */ = { -+ isa = PBXFrameworksBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ 607A66502B0EFFE00010BFC8 /* Python.xcframework in Frameworks */, -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+/* End PBXFrameworksBuildPhase section */ -+ -+/* Begin PBXGroup section */ -+ 607A66092B0EFA380010BFC8 = { -+ isa = PBXGroup; -+ children = ( -+ 607A664A2B0EFB310010BFC8 /* Python.xcframework */, -+ 607A66142B0EFA380010BFC8 /* iOSTestbed */, -+ 607A66302B0EFA3A0010BFC8 /* iOSTestbedTests */, -+ 607A66132B0EFA380010BFC8 /* Products */, -+ 607A664F2B0EFFE00010BFC8 /* Frameworks */, -+ ); -+ sourceTree = ""; -+ }; -+ 607A66132B0EFA380010BFC8 /* Products */ = { -+ isa = PBXGroup; -+ children = ( -+ 607A66122B0EFA380010BFC8 /* iOSTestbed.app */, -+ 607A662D2B0EFA3A0010BFC8 /* iOSTestbedTests.xctest */, -+ ); -+ name = Products; -+ sourceTree = ""; -+ }; -+ 607A66142B0EFA380010BFC8 /* iOSTestbed */ = { -+ isa = PBXGroup; -+ children = ( -+ 608619552CB7819B00F46182 /* app */, -+ 608619532CB77BA900F46182 /* app_packages */, -+ 607A66592B0F08600010BFC8 /* iOSTestbed-Info.plist */, -+ 607A66572B0F079F0010BFC8 /* dylib-Info-template.plist */, -+ 607A66152B0EFA380010BFC8 /* AppDelegate.h */, -+ 607A66162B0EFA380010BFC8 /* AppDelegate.m */, -+ 607A66212B0EFA390010BFC8 /* Assets.xcassets */, -+ 607A66232B0EFA390010BFC8 /* LaunchScreen.storyboard */, -+ 607A66272B0EFA390010BFC8 /* main.m */, -+ ); -+ path = iOSTestbed; -+ sourceTree = ""; -+ }; -+ 607A66302B0EFA3A0010BFC8 /* iOSTestbedTests */ = { -+ isa = PBXGroup; -+ children = ( -+ 607A66312B0EFA3A0010BFC8 /* iOSTestbedTests.m */, -+ ); -+ path = iOSTestbedTests; -+ sourceTree = ""; -+ }; -+ 607A664F2B0EFFE00010BFC8 /* Frameworks */ = { -+ isa = PBXGroup; -+ children = ( -+ ); -+ name = Frameworks; -+ sourceTree = ""; -+ }; -+/* End PBXGroup section */ -+ -+/* Begin PBXNativeTarget section */ -+ 607A66112B0EFA380010BFC8 /* iOSTestbed */ = { -+ isa = PBXNativeTarget; -+ buildConfigurationList = 607A66412B0EFA3A0010BFC8 /* Build configuration list for PBXNativeTarget "iOSTestbed" */; -+ buildPhases = ( -+ 607A660E2B0EFA380010BFC8 /* Sources */, -+ 607A660F2B0EFA380010BFC8 /* Frameworks */, -+ 607A66102B0EFA380010BFC8 /* Resources */, -+ 607A66552B0F061D0010BFC8 /* Install Target Specific Python Standard Library */, -+ 607A66562B0F06200010BFC8 /* Prepare Python Binary Modules */, -+ 607A664E2B0EFC080010BFC8 /* Embed Frameworks */, -+ ); -+ buildRules = ( -+ ); -+ dependencies = ( -+ ); -+ name = iOSTestbed; -+ productName = iOSTestbed; -+ productReference = 607A66122B0EFA380010BFC8 /* iOSTestbed.app */; -+ productType = "com.apple.product-type.application"; -+ }; -+ 607A662C2B0EFA3A0010BFC8 /* iOSTestbedTests */ = { -+ isa = PBXNativeTarget; -+ buildConfigurationList = 607A66442B0EFA3A0010BFC8 /* Build configuration list for PBXNativeTarget "iOSTestbedTests" */; -+ buildPhases = ( -+ 607A66292B0EFA3A0010BFC8 /* Sources */, -+ 607A662A2B0EFA3A0010BFC8 /* Frameworks */, -+ 607A662B2B0EFA3A0010BFC8 /* Resources */, -+ 607A66522B0EFFE00010BFC8 /* Embed Frameworks */, -+ ); -+ buildRules = ( -+ ); -+ dependencies = ( -+ 607A662F2B0EFA3A0010BFC8 /* PBXTargetDependency */, -+ ); -+ name = iOSTestbedTests; -+ productName = iOSTestbedTests; -+ productReference = 607A662D2B0EFA3A0010BFC8 /* iOSTestbedTests.xctest */; -+ productType = "com.apple.product-type.bundle.unit-test"; -+ }; -+/* End PBXNativeTarget section */ -+ -+/* Begin PBXProject section */ -+ 607A660A2B0EFA380010BFC8 /* Project object */ = { -+ isa = PBXProject; -+ attributes = { -+ BuildIndependentTargetsInParallel = 1; -+ LastUpgradeCheck = 1500; -+ TargetAttributes = { -+ 607A66112B0EFA380010BFC8 = { -+ CreatedOnToolsVersion = 15.0.1; -+ }; -+ 607A662C2B0EFA3A0010BFC8 = { -+ CreatedOnToolsVersion = 15.0.1; -+ TestTargetID = 607A66112B0EFA380010BFC8; -+ }; -+ }; -+ }; -+ buildConfigurationList = 607A660D2B0EFA380010BFC8 /* Build configuration list for PBXProject "iOSTestbed" */; -+ compatibilityVersion = "Xcode 14.0"; -+ developmentRegion = en; -+ hasScannedForEncodings = 0; -+ knownRegions = ( -+ en, -+ Base, -+ ); -+ mainGroup = 607A66092B0EFA380010BFC8; -+ productRefGroup = 607A66132B0EFA380010BFC8 /* Products */; -+ projectDirPath = ""; -+ projectRoot = ""; -+ targets = ( -+ 607A66112B0EFA380010BFC8 /* iOSTestbed */, -+ 607A662C2B0EFA3A0010BFC8 /* iOSTestbedTests */, -+ ); -+ }; -+/* End PBXProject section */ -+ -+/* Begin PBXResourcesBuildPhase section */ -+ 607A66102B0EFA380010BFC8 /* Resources */ = { -+ isa = PBXResourcesBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ 607A66252B0EFA390010BFC8 /* LaunchScreen.storyboard in Resources */, -+ 607A66582B0F079F0010BFC8 /* dylib-Info-template.plist in Resources */, -+ 608619562CB7819B00F46182 /* app in Resources */, -+ 607A66222B0EFA390010BFC8 /* Assets.xcassets in Resources */, -+ 608619542CB77BA900F46182 /* app_packages in Resources */, -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+ 607A662B2B0EFA3A0010BFC8 /* Resources */ = { -+ isa = PBXResourcesBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+/* End PBXResourcesBuildPhase section */ -+ -+/* Begin PBXShellScriptBuildPhase section */ -+ 607A66552B0F061D0010BFC8 /* Install Target Specific Python Standard Library */ = { -+ isa = PBXShellScriptBuildPhase; -+ alwaysOutOfDate = 1; -+ buildActionMask = 2147483647; -+ files = ( -+ ); -+ inputFileListPaths = ( -+ ); -+ inputPaths = ( -+ ); -+ name = "Install Target Specific Python Standard Library"; -+ outputFileListPaths = ( -+ ); -+ outputPaths = ( -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ shellPath = /bin/sh; -+ shellScript = "set -e\n\nmkdir -p \"$CODESIGNING_FOLDER_PATH/python/lib\"\nif [ \"$EFFECTIVE_PLATFORM_NAME\" = \"-iphonesimulator\" ]; then\n echo \"Installing Python modules for iOS Simulator\"\n rsync -au --delete \"$PROJECT_DIR/Python.xcframework/ios-arm64_x86_64-simulator/lib/\" \"$CODESIGNING_FOLDER_PATH/python/lib/\" \nelse\n echo \"Installing Python modules for iOS Device\"\n rsync -au --delete \"$PROJECT_DIR/Python.xcframework/ios-arm64/lib/\" \"$CODESIGNING_FOLDER_PATH/python/lib/\" \nfi\n"; -+ showEnvVarsInLog = 0; -+ }; -+ 607A66562B0F06200010BFC8 /* Prepare Python Binary Modules */ = { -+ isa = PBXShellScriptBuildPhase; -+ alwaysOutOfDate = 1; -+ buildActionMask = 2147483647; -+ files = ( -+ ); -+ inputFileListPaths = ( -+ ); -+ inputPaths = ( -+ ); -+ name = "Prepare Python Binary Modules"; -+ outputFileListPaths = ( -+ ); -+ outputPaths = ( -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ shellPath = /bin/sh; -+ shellScript = "set -e\n\ninstall_dylib () {\n INSTALL_BASE=$1\n FULL_EXT=$2\n\n # The name of the extension file\n EXT=$(basename \"$FULL_EXT\")\n # The location of the extension file, relative to the bundle\n RELATIVE_EXT=${FULL_EXT#$CODESIGNING_FOLDER_PATH/} \n # The path to the extension file, relative to the install base\n PYTHON_EXT=${RELATIVE_EXT/$INSTALL_BASE/}\n # The full dotted name of the extension module, constructed from the file path.\n FULL_MODULE_NAME=$(echo $PYTHON_EXT | cut -d \".\" -f 1 | tr \"/\" \".\"); \n # A bundle identifier; not actually used, but required by Xcode framework packaging\n FRAMEWORK_BUNDLE_ID=$(echo $PRODUCT_BUNDLE_IDENTIFIER.$FULL_MODULE_NAME | tr \"_\" \"-\")\n # The name of the framework folder.\n FRAMEWORK_FOLDER=\"Frameworks/$FULL_MODULE_NAME.framework\"\n\n # If the framework folder doesn't exist, create it.\n if [ ! -d \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER\" ]; then\n echo \"Creating framework for $RELATIVE_EXT\" \n mkdir -p \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER\"\n cp \"$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\"\n plutil -replace CFBundleExecutable -string \"$FULL_MODULE_NAME\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\"\n plutil -replace CFBundleIdentifier -string \"$FRAMEWORK_BUNDLE_ID\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\"\n fi\n \n echo \"Installing binary for $FRAMEWORK_FOLDER/$FULL_MODULE_NAME\" \n mv \"$FULL_EXT\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/$FULL_MODULE_NAME\"\n # Create a placeholder .fwork file where the .so was\n echo \"$FRAMEWORK_FOLDER/$FULL_MODULE_NAME\" > ${FULL_EXT%.so}.fwork\n # Create a back reference to the .so file location in the framework\n echo \"${RELATIVE_EXT%.so}.fwork\" > \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/$FULL_MODULE_NAME.origin\" \n}\n\nPYTHON_VER=$(ls -1 \"$CODESIGNING_FOLDER_PATH/python/lib\")\necho \"Install Python $PYTHON_VER standard library extension modules...\"\nfind \"$CODESIGNING_FOLDER_PATH/python/lib/$PYTHON_VER/lib-dynload\" -name \"*.so\" | while read FULL_EXT; do\n install_dylib python/lib/$PYTHON_VER/lib-dynload/ \"$FULL_EXT\"\ndone\necho \"Install app package extension modules...\"\nfind \"$CODESIGNING_FOLDER_PATH/app_packages\" -name \"*.so\" | while read FULL_EXT; do\n install_dylib app_packages/ \"$FULL_EXT\"\ndone\necho \"Install app extension modules...\"\nfind \"$CODESIGNING_FOLDER_PATH/app\" -name \"*.so\" | while read FULL_EXT; do\n install_dylib app/ \"$FULL_EXT\"\ndone\n\n# Clean up dylib template \nrm -f \"$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist\"\necho \"Signing frameworks as $EXPANDED_CODE_SIGN_IDENTITY_NAME ($EXPANDED_CODE_SIGN_IDENTITY)...\"\nfind \"$CODESIGNING_FOLDER_PATH/Frameworks\" -name \"*.framework\" -exec /usr/bin/codesign --force --sign \"$EXPANDED_CODE_SIGN_IDENTITY\" ${OTHER_CODE_SIGN_FLAGS:-} -o runtime --timestamp=none --preserve-metadata=identifier,entitlements,flags --generate-entitlement-der \"{}\" \\; \n"; -+ showEnvVarsInLog = 0; -+ }; -+/* End PBXShellScriptBuildPhase section */ -+ -+/* Begin PBXSourcesBuildPhase section */ -+ 607A660E2B0EFA380010BFC8 /* Sources */ = { -+ isa = PBXSourcesBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ 607A66172B0EFA380010BFC8 /* AppDelegate.m in Sources */, -+ 607A66282B0EFA390010BFC8 /* main.m in Sources */, -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+ 607A66292B0EFA3A0010BFC8 /* Sources */ = { -+ isa = PBXSourcesBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ 607A66322B0EFA3A0010BFC8 /* iOSTestbedTests.m in Sources */, -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+/* End PBXSourcesBuildPhase section */ -+ -+/* Begin PBXTargetDependency section */ -+ 607A662F2B0EFA3A0010BFC8 /* PBXTargetDependency */ = { -+ isa = PBXTargetDependency; -+ target = 607A66112B0EFA380010BFC8 /* iOSTestbed */; -+ targetProxy = 607A662E2B0EFA3A0010BFC8 /* PBXContainerItemProxy */; -+ }; -+/* End PBXTargetDependency section */ -+ -+/* Begin PBXVariantGroup section */ -+ 607A66232B0EFA390010BFC8 /* LaunchScreen.storyboard */ = { -+ isa = PBXVariantGroup; -+ children = ( -+ 607A66242B0EFA390010BFC8 /* Base */, -+ ); -+ name = LaunchScreen.storyboard; -+ sourceTree = ""; -+ }; -+/* End PBXVariantGroup section */ -+ -+/* Begin XCBuildConfiguration section */ -+ 607A663F2B0EFA3A0010BFC8 /* Debug */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ALWAYS_SEARCH_USER_PATHS = NO; -+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; -+ CLANG_ANALYZER_NONNULL = YES; -+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; -+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; -+ CLANG_ENABLE_MODULES = YES; -+ CLANG_ENABLE_OBJC_ARC = YES; -+ CLANG_ENABLE_OBJC_WEAK = YES; -+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; -+ CLANG_WARN_BOOL_CONVERSION = YES; -+ CLANG_WARN_COMMA = YES; -+ CLANG_WARN_CONSTANT_CONVERSION = YES; -+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; -+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; -+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES; -+ CLANG_WARN_EMPTY_BODY = YES; -+ CLANG_WARN_ENUM_CONVERSION = YES; -+ CLANG_WARN_INFINITE_RECURSION = YES; -+ CLANG_WARN_INT_CONVERSION = YES; -+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; -+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; -+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; -+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; -+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; -+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; -+ CLANG_WARN_STRICT_PROTOTYPES = YES; -+ CLANG_WARN_SUSPICIOUS_MOVE = YES; -+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; -+ CLANG_WARN_UNREACHABLE_CODE = YES; -+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; -+ COPY_PHASE_STRIP = NO; -+ DEBUG_INFORMATION_FORMAT = dwarf; -+ ENABLE_STRICT_OBJC_MSGSEND = YES; -+ ENABLE_TESTABILITY = YES; -+ ENABLE_USER_SCRIPT_SANDBOXING = YES; -+ GCC_C_LANGUAGE_STANDARD = gnu17; -+ GCC_DYNAMIC_NO_PIC = NO; -+ GCC_NO_COMMON_BLOCKS = YES; -+ GCC_OPTIMIZATION_LEVEL = 0; -+ GCC_PREPROCESSOR_DEFINITIONS = ( -+ "DEBUG=1", -+ "$(inherited)", -+ ); -+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; -+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; -+ GCC_WARN_UNDECLARED_SELECTOR = YES; -+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; -+ GCC_WARN_UNUSED_FUNCTION = YES; -+ GCC_WARN_UNUSED_VARIABLE = YES; -+ IPHONEOS_DEPLOYMENT_TARGET = 12.0; -+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES; -+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; -+ MTL_FAST_MATH = YES; -+ ONLY_ACTIVE_ARCH = YES; -+ SDKROOT = iphoneos; -+ }; -+ name = Debug; -+ }; -+ 607A66402B0EFA3A0010BFC8 /* Release */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ALWAYS_SEARCH_USER_PATHS = NO; -+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; -+ CLANG_ANALYZER_NONNULL = YES; -+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; -+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; -+ CLANG_ENABLE_MODULES = YES; -+ CLANG_ENABLE_OBJC_ARC = YES; -+ CLANG_ENABLE_OBJC_WEAK = YES; -+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; -+ CLANG_WARN_BOOL_CONVERSION = YES; -+ CLANG_WARN_COMMA = YES; -+ CLANG_WARN_CONSTANT_CONVERSION = YES; -+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; -+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; -+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES; -+ CLANG_WARN_EMPTY_BODY = YES; -+ CLANG_WARN_ENUM_CONVERSION = YES; -+ CLANG_WARN_INFINITE_RECURSION = YES; -+ CLANG_WARN_INT_CONVERSION = YES; -+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; -+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; -+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; -+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; -+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; -+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; -+ CLANG_WARN_STRICT_PROTOTYPES = YES; -+ CLANG_WARN_SUSPICIOUS_MOVE = YES; -+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; -+ CLANG_WARN_UNREACHABLE_CODE = YES; -+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; -+ COPY_PHASE_STRIP = NO; -+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; -+ ENABLE_NS_ASSERTIONS = NO; -+ ENABLE_STRICT_OBJC_MSGSEND = YES; -+ ENABLE_USER_SCRIPT_SANDBOXING = YES; -+ GCC_C_LANGUAGE_STANDARD = gnu17; -+ GCC_NO_COMMON_BLOCKS = YES; -+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; -+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; -+ GCC_WARN_UNDECLARED_SELECTOR = YES; -+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; -+ GCC_WARN_UNUSED_FUNCTION = YES; -+ GCC_WARN_UNUSED_VARIABLE = YES; -+ IPHONEOS_DEPLOYMENT_TARGET = 12.0; -+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES; -+ MTL_ENABLE_DEBUG_INFO = NO; -+ MTL_FAST_MATH = YES; -+ SDKROOT = iphoneos; -+ VALIDATE_PRODUCT = YES; -+ }; -+ name = Release; -+ }; -+ 607A66422B0EFA3A0010BFC8 /* Debug */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; -+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; -+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; -+ CODE_SIGN_STYLE = Automatic; -+ CURRENT_PROJECT_VERSION = 1; -+ DEVELOPMENT_TEAM = ""; -+ ENABLE_USER_SCRIPT_SANDBOXING = NO; -+ HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\""; -+ INFOPLIST_FILE = "iOSTestbed/iOSTestbed-Info.plist"; -+ INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; -+ INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; -+ INFOPLIST_KEY_UIMainStoryboardFile = Main; -+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; -+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; -+ IPHONEOS_DEPLOYMENT_TARGET = 12.0; -+ LD_RUNPATH_SEARCH_PATHS = ( -+ "$(inherited)", -+ "@executable_path/Frameworks", -+ ); -+ MARKETING_VERSION = 3.13.0a1; -+ PRODUCT_BUNDLE_IDENTIFIER = org.python.iOSTestbed; -+ PRODUCT_NAME = "$(TARGET_NAME)"; -+ SWIFT_EMIT_LOC_STRINGS = YES; -+ TARGETED_DEVICE_FAMILY = "1,2"; -+ }; -+ name = Debug; -+ }; -+ 607A66432B0EFA3A0010BFC8 /* Release */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; -+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; -+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; -+ CODE_SIGN_STYLE = Automatic; -+ CURRENT_PROJECT_VERSION = 1; -+ DEVELOPMENT_TEAM = ""; -+ ENABLE_TESTABILITY = YES; -+ ENABLE_USER_SCRIPT_SANDBOXING = NO; -+ HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\""; -+ INFOPLIST_FILE = "iOSTestbed/iOSTestbed-Info.plist"; -+ INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; -+ INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; -+ INFOPLIST_KEY_UIMainStoryboardFile = Main; -+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; -+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; -+ IPHONEOS_DEPLOYMENT_TARGET = 12.0; -+ LD_RUNPATH_SEARCH_PATHS = ( -+ "$(inherited)", -+ "@executable_path/Frameworks", -+ ); -+ MARKETING_VERSION = 3.13.0a1; -+ PRODUCT_BUNDLE_IDENTIFIER = org.python.iOSTestbed; -+ PRODUCT_NAME = "$(TARGET_NAME)"; -+ SWIFT_EMIT_LOC_STRINGS = YES; -+ TARGETED_DEVICE_FAMILY = "1,2"; -+ }; -+ name = Release; -+ }; -+ 607A66452B0EFA3A0010BFC8 /* Debug */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ BUNDLE_LOADER = "$(TEST_HOST)"; -+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; -+ CODE_SIGN_STYLE = Automatic; -+ CURRENT_PROJECT_VERSION = 1; -+ DEVELOPMENT_TEAM = 3HEZE76D99; -+ GENERATE_INFOPLIST_FILE = YES; -+ HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\""; -+ IPHONEOS_DEPLOYMENT_TARGET = 12.0; -+ MARKETING_VERSION = 1.0; -+ PRODUCT_BUNDLE_IDENTIFIER = org.python.iOSTestbedTests; -+ PRODUCT_NAME = "$(TARGET_NAME)"; -+ SWIFT_EMIT_LOC_STRINGS = NO; -+ TARGETED_DEVICE_FAMILY = "1,2"; -+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/iOSTestbed.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/iOSTestbed"; -+ }; -+ name = Debug; -+ }; -+ 607A66462B0EFA3A0010BFC8 /* Release */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ BUNDLE_LOADER = "$(TEST_HOST)"; -+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; -+ CODE_SIGN_STYLE = Automatic; -+ CURRENT_PROJECT_VERSION = 1; -+ DEVELOPMENT_TEAM = 3HEZE76D99; -+ GENERATE_INFOPLIST_FILE = YES; -+ HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\""; -+ IPHONEOS_DEPLOYMENT_TARGET = 12.0; -+ MARKETING_VERSION = 1.0; -+ PRODUCT_BUNDLE_IDENTIFIER = org.python.iOSTestbedTests; -+ PRODUCT_NAME = "$(TARGET_NAME)"; -+ SWIFT_EMIT_LOC_STRINGS = NO; -+ TARGETED_DEVICE_FAMILY = "1,2"; -+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/iOSTestbed.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/iOSTestbed"; -+ }; -+ name = Release; -+ }; -+/* End XCBuildConfiguration section */ -+ -+/* Begin XCConfigurationList section */ -+ 607A660D2B0EFA380010BFC8 /* Build configuration list for PBXProject "iOSTestbed" */ = { -+ isa = XCConfigurationList; -+ buildConfigurations = ( -+ 607A663F2B0EFA3A0010BFC8 /* Debug */, -+ 607A66402B0EFA3A0010BFC8 /* Release */, -+ ); -+ defaultConfigurationIsVisible = 0; -+ defaultConfigurationName = Release; -+ }; -+ 607A66412B0EFA3A0010BFC8 /* Build configuration list for PBXNativeTarget "iOSTestbed" */ = { -+ isa = XCConfigurationList; -+ buildConfigurations = ( -+ 607A66422B0EFA3A0010BFC8 /* Debug */, -+ 607A66432B0EFA3A0010BFC8 /* Release */, -+ ); -+ defaultConfigurationIsVisible = 0; -+ defaultConfigurationName = Release; -+ }; -+ 607A66442B0EFA3A0010BFC8 /* Build configuration list for PBXNativeTarget "iOSTestbedTests" */ = { -+ isa = XCConfigurationList; -+ buildConfigurations = ( -+ 607A66452B0EFA3A0010BFC8 /* Debug */, -+ 607A66462B0EFA3A0010BFC8 /* Release */, -+ ); -+ defaultConfigurationIsVisible = 0; -+ defaultConfigurationName = Release; -+ }; -+/* End XCConfigurationList section */ -+ }; -+ rootObject = 607A660A2B0EFA380010BFC8 /* Project object */; -+} ---- /dev/null -+++ b/MacCatalyst/testbed/iOSTestbed/AppDelegate.h -@@ -0,0 +1,11 @@ -+// -+// AppDelegate.h -+// iOSTestbed -+// -+ -+#import -+ -+@interface AppDelegate : UIResponder -+ -+ -+@end ---- /dev/null -+++ b/MacCatalyst/testbed/iOSTestbed/AppDelegate.m -@@ -0,0 +1,19 @@ -+// -+// AppDelegate.m -+// iOSTestbed -+// -+ -+#import "AppDelegate.h" -+ -+@interface AppDelegate () -+ -+@end -+ -+@implementation AppDelegate -+ -+ -+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { -+ return YES; -+} -+ -+@end ---- /dev/null -+++ b/MacCatalyst/testbed/iOSTestbed/Assets.xcassets/AccentColor.colorset/Contents.json -@@ -0,0 +1,11 @@ -+{ -+ "colors" : [ -+ { -+ "idiom" : "universal" -+ } -+ ], -+ "info" : { -+ "author" : "xcode", -+ "version" : 1 -+ } -+} ---- /dev/null -+++ b/MacCatalyst/testbed/iOSTestbed/Assets.xcassets/AppIcon.appiconset/Contents.json -@@ -0,0 +1,13 @@ -+{ -+ "images" : [ -+ { -+ "idiom" : "universal", -+ "platform" : "ios", -+ "size" : "1024x1024" -+ } -+ ], -+ "info" : { -+ "author" : "xcode", -+ "version" : 1 -+ } -+} ---- /dev/null -+++ b/MacCatalyst/testbed/iOSTestbed/Assets.xcassets/Contents.json -@@ -0,0 +1,6 @@ -+{ -+ "info" : { -+ "author" : "xcode", -+ "version" : 1 -+ } -+} ---- /dev/null -+++ b/MacCatalyst/testbed/iOSTestbed/Base.lproj/LaunchScreen.storyboard -@@ -0,0 +1,9 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ ---- /dev/null -+++ b/MacCatalyst/testbed/iOSTestbed/app/README -@@ -0,0 +1,7 @@ -+This folder can contain any Python application code. -+ -+During the build, any binary modules found in this folder will be processed into -+iOS Framework form. -+ -+When the test suite runs, this folder will be on the PYTHONPATH, and will be the -+working directory for the test suite. ---- /dev/null -+++ b/MacCatalyst/testbed/iOSTestbed/app_packages/README -@@ -0,0 +1,7 @@ -+This folder can be a target for installing any Python dependencies needed by the -+test suite. -+ -+During the build, any binary modules found in this folder will be processed into -+iOS Framework form. -+ -+When the test suite runs, this folder will be on the PYTHONPATH. ---- /dev/null -+++ b/MacCatalyst/testbed/iOSTestbed/dylib-Info-template.plist -@@ -0,0 +1,26 @@ -+ -+ -+ -+ -+ CFBundleDevelopmentRegion -+ en -+ CFBundleExecutable -+ -+ CFBundleIdentifier -+ -+ CFBundleInfoDictionaryVersion -+ 6.0 -+ CFBundlePackageType -+ APPL -+ CFBundleShortVersionString -+ 1.0 -+ CFBundleSupportedPlatforms -+ -+ iPhoneOS -+ -+ MinimumOSVersion -+ 12.0 -+ CFBundleVersion -+ 1 -+ -+ ---- /dev/null -+++ b/MacCatalyst/testbed/iOSTestbed/iOSTestbed-Info.plist -@@ -0,0 +1,64 @@ -+ -+ -+ -+ -+ CFBundleDevelopmentRegion -+ en -+ CFBundleDisplayName -+ ${PRODUCT_NAME} -+ CFBundleExecutable -+ ${EXECUTABLE_NAME} -+ CFBundleIdentifier -+ org.python.iOSTestbed -+ CFBundleInfoDictionaryVersion -+ 6.0 -+ CFBundleName -+ ${PRODUCT_NAME} -+ CFBundlePackageType -+ APPL -+ CFBundleShortVersionString -+ 1.0 -+ CFBundleSignature -+ ???? -+ CFBundleVersion -+ 1 -+ LSRequiresIPhoneOS -+ -+ UIRequiresFullScreen -+ -+ UILaunchStoryboardName -+ Launch Screen -+ UISupportedInterfaceOrientations -+ -+ UIInterfaceOrientationPortrait -+ UIInterfaceOrientationLandscapeLeft -+ UIInterfaceOrientationLandscapeRight -+ -+ UISupportedInterfaceOrientations~ipad -+ -+ UIInterfaceOrientationPortrait -+ UIInterfaceOrientationPortraitUpsideDown -+ UIInterfaceOrientationLandscapeLeft -+ UIInterfaceOrientationLandscapeRight -+ -+ TestArgs -+ -+ test -+ -uall -+ --single-process -+ --rerun -+ -W -+ -+ -+ UIApplicationSceneManifest -+ -+ UIApplicationSupportsMultipleScenes -+ -+ UISceneConfigurations -+ -+ -+ -+ ---- /dev/null -+++ b/MacCatalyst/testbed/iOSTestbed/main.m -@@ -0,0 +1,16 @@ -+// -+// main.m -+// iOSTestbed -+// -+ -+#import -+#import "AppDelegate.h" -+ -+int main(int argc, char * argv[]) { -+ NSString * appDelegateClassName; -+ @autoreleasepool { -+ appDelegateClassName = NSStringFromClass([AppDelegate class]); -+ -+ return UIApplicationMain(argc, argv, nil, appDelegateClassName); -+ } -+} ---- /dev/null -+++ b/MacCatalyst/testbed/iOSTestbedTests/iOSTestbedTests.m -@@ -0,0 +1,162 @@ -+#import -+#import -+ -+@interface iOSTestbedTests : XCTestCase -+ -+@end -+ -+@implementation iOSTestbedTests -+ -+ -+- (void)testPython { -+ const char **argv; -+ int exit_code; -+ int failed; -+ PyStatus status; -+ PyPreConfig preconfig; -+ PyConfig config; -+ PyObject *sys_module; -+ PyObject *sys_path_attr; -+ NSArray *test_args; -+ NSString *python_home; -+ NSString *path; -+ wchar_t *wtmp_str; -+ -+ NSString *resourcePath = [[NSBundle mainBundle] resourcePath]; -+ -+ // Set some other common environment indicators to disable color, as the -+ // Xcode log can't display color. Stdout will report that it is *not* a -+ // TTY. -+ setenv("NO_COLOR", "1", true); -+ setenv("PY_COLORS", "0", true); -+ -+ // Arguments to pass into the test suite runner. -+ // argv[0] must identify the process; any subsequent arg -+ // will be handled as if it were an argument to `python -m test` -+ test_args = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"TestArgs"]; -+ if (test_args == NULL) { -+ NSLog(@"Unable to identify test arguments."); -+ } -+ argv = malloc(sizeof(char *) * ([test_args count] + 1)); -+ argv[0] = "iOSTestbed"; -+ for (int i = 1; i < [test_args count]; i++) { -+ argv[i] = [[test_args objectAtIndex:i] UTF8String]; -+ } -+ NSLog(@"Test command: %@", test_args); -+ -+ // Generate an isolated Python configuration. -+ NSLog(@"Configuring isolated Python..."); -+ PyPreConfig_InitIsolatedConfig(&preconfig); -+ PyConfig_InitIsolatedConfig(&config); -+ -+ // Configure the Python interpreter: -+ // Enforce UTF-8 encoding for stderr, stdout, file-system encoding and locale. -+ // See https://docs.python.org/3/library/os.html#python-utf-8-mode. -+ preconfig.utf8_mode = 1; -+ // Use the system logger for stdout/err -+ config.use_system_logger = 1; -+ // Don't buffer stdio. We want output to appears in the log immediately -+ config.buffered_stdio = 0; -+ // Don't write bytecode; we can't modify the app bundle -+ // after it has been signed. -+ config.write_bytecode = 0; -+ // Ensure that signal handlers are installed -+ config.install_signal_handlers = 1; -+ // Run the test module. -+ config.run_module = Py_DecodeLocale([[test_args objectAtIndex:0] UTF8String], NULL); -+ // For debugging - enable verbose mode. -+ // config.verbose = 1; -+ -+ NSLog(@"Pre-initializing Python runtime..."); -+ status = Py_PreInitialize(&preconfig); -+ if (PyStatus_Exception(status)) { -+ XCTFail(@"Unable to pre-initialize Python interpreter: %s", status.err_msg); -+ PyConfig_Clear(&config); -+ return; -+ } -+ -+ // Set the home for the Python interpreter -+ python_home = [NSString stringWithFormat:@"%@/python", resourcePath, nil]; -+ NSLog(@"PythonHome: %@", python_home); -+ wtmp_str = Py_DecodeLocale([python_home UTF8String], NULL); -+ status = PyConfig_SetString(&config, &config.home, wtmp_str); -+ if (PyStatus_Exception(status)) { -+ XCTFail(@"Unable to set PYTHONHOME: %s", status.err_msg); -+ PyConfig_Clear(&config); -+ return; -+ } -+ PyMem_RawFree(wtmp_str); -+ -+ // Read the site config -+ status = PyConfig_Read(&config); -+ if (PyStatus_Exception(status)) { -+ XCTFail(@"Unable to read site config: %s", status.err_msg); -+ PyConfig_Clear(&config); -+ return; -+ } -+ -+ NSLog(@"Configure argc/argv..."); -+ status = PyConfig_SetBytesArgv(&config, [test_args count], (char**) argv); -+ if (PyStatus_Exception(status)) { -+ XCTFail(@"Unable to configure argc/argv: %s", status.err_msg); -+ PyConfig_Clear(&config); -+ return; -+ } -+ -+ NSLog(@"Initializing Python runtime..."); -+ status = Py_InitializeFromConfig(&config); -+ if (PyStatus_Exception(status)) { -+ XCTFail(@"Unable to initialize Python interpreter: %s", status.err_msg); -+ PyConfig_Clear(&config); -+ return; -+ } -+ -+ sys_module = PyImport_ImportModule("sys"); -+ if (sys_module == NULL) { -+ XCTFail(@"Could not import sys module"); -+ return; -+ } -+ -+ sys_path_attr = PyObject_GetAttrString(sys_module, "path"); -+ if (sys_path_attr == NULL) { -+ XCTFail(@"Could not access sys.path"); -+ return; -+ } -+ -+ // Add the app packages path -+ path = [NSString stringWithFormat:@"%@/app_packages", resourcePath, nil]; -+ NSLog(@"App packages path: %@", path); -+ wtmp_str = Py_DecodeLocale([path UTF8String], NULL); -+ failed = PyList_Insert(sys_path_attr, 0, PyUnicode_FromString([path UTF8String])); -+ if (failed) { -+ XCTFail(@"Unable to add app packages to sys.path"); -+ return; -+ } -+ PyMem_RawFree(wtmp_str); -+ -+ path = [NSString stringWithFormat:@"%@/app", resourcePath, nil]; -+ NSLog(@"App path: %@", path); -+ wtmp_str = Py_DecodeLocale([path UTF8String], NULL); -+ failed = PyList_Insert(sys_path_attr, 0, PyUnicode_FromString([path UTF8String])); -+ if (failed) { -+ XCTFail(@"Unable to add app to sys.path"); -+ return; -+ } -+ PyMem_RawFree(wtmp_str); -+ -+ // Ensure the working directory is the app folder. -+ chdir([path UTF8String]); -+ -+ // Start the test suite. Print a separator to differentiate Python startup logs from app logs -+ NSLog(@"---------------------------------------------------------------------------"); -+ -+ exit_code = Py_RunMain(); -+ XCTAssertEqual(exit_code, 0, @"Test suite did not pass"); -+ -+ NSLog(@"---------------------------------------------------------------------------"); -+ -+ Py_Finalize(); -+} -+ -+ -+@end diff --git a/Misc/platform_triplet.c b/Misc/platform_triplet.c -index ec0857a4a99..190670f271d 100644 +index ec0857a4a99..d6b3fa10092 100644 --- a/Misc/platform_triplet.c +++ b/Misc/platform_triplet.c -@@ -254,9 +254,55 @@ +@@ -254,6 +254,12 @@ # else PLATFORM_TRIPLET=arm64-iphonesimulator # endif @@ -2132,49 +264,6 @@ index ec0857a4a99..190670f271d 100644 # else PLATFORM_TRIPLET=arm64-iphoneos # endif -+# elif defined(TARGET_OS_TV) && TARGET_OS_TV -+# if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR -+# if __x86_64__ -+PLATFORM_TRIPLET=x86_64-appletvsimulator -+# else -+PLATFORM_TRIPLET=arm64-appletvsimulator -+# endif -+# else -+PLATFORM_TRIPLET=arm64-appletvos -+# endif -+# elif defined(TARGET_OS_WATCH) && TARGET_OS_WATCH -+# if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR -+# if __x86_64__ -+PLATFORM_TRIPLET=x86_64-watchsimulator -+# else -+PLATFORM_TRIPLET=arm64-watchsimulator -+# endif -+# else -+PLATFORM_TRIPLET=arm64_32-watchos -+# endif -+# elif defined(TARGET_OS_TV) && TARGET_OS_TV -+# if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR -+# if __x86_64__ -+PLATFORM_TRIPLET=x86_64-appletvsimulator -+# else -+PLATFORM_TRIPLET=arm64-appletvsimulator -+# endif -+# else -+PLATFORM_TRIPLET=arm64-appletvos -+# endif -+# elif defined(TARGET_OS_WATCH) && TARGET_OS_WATCH -+# if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR -+# if __x86_64__ -+PLATFORM_TRIPLET=x86_64-watchsimulator -+# else -+PLATFORM_TRIPLET=arm64-watchsimulator -+# endif -+# else -+PLATFORM_TRIPLET=arm64_32-watchos -+# endif - // Older macOS SDKs do not define TARGET_OS_OSX - # elif !defined(TARGET_OS_OSX) || TARGET_OS_OSX - PLATFORM_TRIPLET=darwin diff --git a/config.sub b/config.sub index 1bb6a05dc11..7e007ac54c3 100755 --- a/config.sub @@ -2198,7 +287,7 @@ index 1bb6a05dc11..7e007ac54c3 100755 # None (no kernel, i.e. freestanding / bare metal), # can be paired with an machine code file format diff --git a/configure b/configure -index d46bc563a67..4c05b8dcf21 100755 +index d46bc563a67..d40e0a6981f 100755 --- a/configure +++ b/configure @@ -974,6 +974,8 @@ @@ -2232,13 +321,14 @@ index d46bc563a67..4c05b8dcf21 100755 # which isn't a binary that exists, and isn't very convenient, as it contains the # iOS version. As the default cross-compiler name won't exist, configure falls # back to gcc, which *definitely* won't work. We're providing wrapper scripts for -@@ -4194,32 +4202,68 @@ +@@ -4194,32 +4202,72 @@ if test -z "$AR"; then case "$host" in aarch64-apple-ios*-simulator) AR=arm64-apple-ios-simulator-ar ;; + aarch64-apple-ios*-macabi) AR=arm64-apple-ios-macabi-ar ;; aarch64-apple-ios*) AR=arm64-apple-ios-ar ;; x86_64-apple-ios*-simulator) AR=x86_64-apple-ios-simulator-ar ;; ++ x86_64-apple-ios*-macabi) AR=x86_64-apple-ios-macabi-ar ;; + + aarch64-apple-tvos*-simulator) AR=arm64-apple-tvos-simulator-ar ;; + aarch64-apple-tvos*) AR=arm64-apple-tvos-ar ;; @@ -2256,6 +346,7 @@ index d46bc563a67..4c05b8dcf21 100755 + aarch64-apple-ios*-macabi) CC=arm64-apple-ios-macabi-clang ;; aarch64-apple-ios*) CC=arm64-apple-ios-clang ;; x86_64-apple-ios*-simulator) CC=x86_64-apple-ios-simulator-clang ;; ++ x86_64-apple-ios*-macabi) CC=x86_64-apple-ios-macabi-clang ;; + + aarch64-apple-tvos*-simulator) CC=arm64-apple-tvos-simulator-clang ;; + aarch64-apple-tvos*) CC=arm64-apple-tvos-clang ;; @@ -2273,6 +364,7 @@ index d46bc563a67..4c05b8dcf21 100755 + aarch64-apple-ios*-macabi) CPP=arm64-apple-ios-macabi-cpp ;; aarch64-apple-ios*) CPP=arm64-apple-ios-cpp ;; x86_64-apple-ios*-simulator) CPP=x86_64-apple-ios-simulator-cpp ;; ++ x86_64-apple-ios*-macabi) CPP=x86_64-apple-ios-macabi-cpp ;; + + aarch64-apple-tvos*-simulator) CPP=arm64-apple-tvos-simulator-cpp ;; + aarch64-apple-tvos*) CPP=arm64-apple-tvos-cpp ;; @@ -2290,6 +382,7 @@ index d46bc563a67..4c05b8dcf21 100755 + aarch64-apple-ios*-macabi) CXX=arm64-apple-ios-macabi-clang++ ;; aarch64-apple-ios*) CXX=arm64-apple-ios-clang++ ;; x86_64-apple-ios*-simulator) CXX=x86_64-apple-ios-simulator-clang++ ;; ++ x86_64-apple-ios*-macabi) CXX=x86_64-apple-ios-macabi-clang++ ;; + + aarch64-apple-tvos*-simulator) CXX=arm64-apple-tvos-simulator-clang++ ;; + aarch64-apple-tvos*) CXX=arm64-apple-tvos-clang++ ;; @@ -2301,7 +394,7 @@ index d46bc563a67..4c05b8dcf21 100755 *) esac fi -@@ -4342,8 +4386,10 @@ +@@ -4342,8 +4390,10 @@ case $enableval in yes) case $ac_sys_system in @@ -2314,7 +407,7 @@ index d46bc563a67..4c05b8dcf21 100755 *) as_fn_error $? "Unknown platform for framework build" "$LINENO" 5 esac esac -@@ -4352,6 +4398,8 @@ +@@ -4352,6 +4402,8 @@ no) case $ac_sys_system in iOS) as_fn_error $? "iOS builds must use --enable-framework" "$LINENO" 5 ;; @@ -2323,7 +416,7 @@ index d46bc563a67..4c05b8dcf21 100755 *) PYTHONFRAMEWORK= PYTHONFRAMEWORKDIR=no-framework -@@ -4458,6 +4506,36 @@ +@@ -4458,6 +4510,36 @@ ac_config_files="$ac_config_files iOS/Resources/Info.plist" @@ -2360,7 +453,7 @@ index d46bc563a67..4c05b8dcf21 100755 ;; *) as_fn_error $? "Unknown platform for framework build" "$LINENO" 5 -@@ -4469,6 +4547,8 @@ +@@ -4469,6 +4551,8 @@ e) case $ac_sys_system in iOS) as_fn_error $? "iOS builds must use --enable-framework" "$LINENO" 5 ;; @@ -2369,7 +462,7 @@ index d46bc563a67..4c05b8dcf21 100755 *) PYTHONFRAMEWORK= PYTHONFRAMEWORKDIR=no-framework -@@ -4523,8 +4603,8 @@ +@@ -4523,8 +4607,8 @@ case "$withval" in yes) case $ac_sys_system in @@ -2380,7 +473,7 @@ index d46bc563a67..4c05b8dcf21 100755 APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" ;; *) as_fn_error $? "no default app store compliance patch available for $ac_sys_system" "$LINENO" 5 ;; -@@ -4542,8 +4622,8 @@ +@@ -4542,8 +4626,8 @@ else case e in #( e) case $ac_sys_system in @@ -2391,7 +484,7 @@ index d46bc563a67..4c05b8dcf21 100755 APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: applying default app store compliance patch" >&5 printf "%s\n" "applying default app store compliance patch" >&6; } -@@ -4598,6 +4678,50 @@ +@@ -4598,6 +4682,50 @@ ;; esac ;; @@ -2442,7 +535,7 @@ index d46bc563a67..4c05b8dcf21 100755 *-*-darwin*) case "$host_cpu" in arm*) -@@ -4688,9 +4812,13 @@ +@@ -4688,9 +4816,13 @@ define_xopen_source=no;; Darwin/[12][0-9].*) define_xopen_source=no;; @@ -2457,7 +550,7 @@ index d46bc563a67..4c05b8dcf21 100755 # On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from # defining NI_NUMERICHOST. QNX/6.3.2) -@@ -4753,7 +4881,10 @@ +@@ -4753,7 +4885,10 @@ CONFIGURE_MACOSX_DEPLOYMENT_TARGET= EXPORT_MACOSX_DEPLOYMENT_TARGET='#' @@ -2469,7 +562,7 @@ index d46bc563a67..4c05b8dcf21 100755 # checks for alternative programs -@@ -4794,6 +4925,16 @@ +@@ -4794,6 +4929,16 @@ as_fn_append CFLAGS " -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}" as_fn_append LDFLAGS " -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}" ;; #( @@ -2486,7 +579,7 @@ index d46bc563a67..4c05b8dcf21 100755 *) : ;; esac -@@ -7163,6 +7304,10 @@ +@@ -7163,6 +7308,10 @@ MULTIARCH="" ;; #( iOS) : MULTIARCH="" ;; #( @@ -2497,7 +590,7 @@ index d46bc563a67..4c05b8dcf21 100755 FreeBSD*) : MULTIARCH="" ;; #( *) : -@@ -7183,7 +7328,7 @@ +@@ -7183,7 +7332,7 @@ printf "%s\n" "$MULTIARCH" >&6; } case $ac_sys_system in #( @@ -2506,12 +599,16 @@ index d46bc563a67..4c05b8dcf21 100755 SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f2` ;; #( *) : SOABI_PLATFORM=$PLATFORM_TRIPLET -@@ -7234,6 +7379,14 @@ +@@ -7234,6 +7383,18 @@ PY_SUPPORT_TIER=3 ;; #( aarch64-apple-ios*/clang) : PY_SUPPORT_TIER=3 ;; #( + aarch64-apple-tvos*-simulator/clang) : + PY_SUPPORT_TIER=3 ;; #( ++ aarch64-apple-ios*-macabi/clang) : ++ PY_SUPPORT_TIER=3 ;; #( ++ x86_64-apple-ios*-macabi/clang) : ++ PY_SUPPORT_TIER=3 ;; #( + aarch64-apple-tvos*/clang) : + PY_SUPPORT_TIER=3 ;; #( + aarch64-apple-watchos*-simulator/clang) : @@ -2521,7 +618,7 @@ index d46bc563a67..4c05b8dcf21 100755 aarch64-*-linux-android/clang) : PY_SUPPORT_TIER=3 ;; #( x86_64-*-linux-android/clang) : -@@ -7670,7 +7823,7 @@ +@@ -7670,7 +7831,7 @@ case $ac_sys_system in Darwin) LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)';; @@ -2530,7 +627,7 @@ index d46bc563a67..4c05b8dcf21 100755 LDLIBRARY='$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';; *) as_fn_error $? "Unknown platform for framework build" "$LINENO" 5;; -@@ -7736,7 +7889,7 @@ +@@ -7736,7 +7897,7 @@ BLDLIBRARY='-L. -lpython$(LDVERSION)' RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}} ;; @@ -2539,7 +636,7 @@ index d46bc563a67..4c05b8dcf21 100755 LDLIBRARY='libpython$(LDVERSION).dylib' ;; AIX*) -@@ -13544,7 +13697,7 @@ +@@ -13544,7 +13705,7 @@ BLDSHARED="$LDSHARED" fi ;; @@ -2548,7 +645,7 @@ index d46bc563a67..4c05b8dcf21 100755 LDSHARED='$(CC) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)' LDCXXSHARED='$(CXX) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)' BLDSHARED="$LDSHARED" -@@ -13677,7 +13830,7 @@ +@@ -13677,7 +13838,7 @@ Linux-android*) LINKFORSHARED="-pie -Xlinker -export-dynamic";; Linux*|GNU*) LINKFORSHARED="-Xlinker -export-dynamic";; # -u libsys_s pulls in all symbols in libsys @@ -2557,7 +654,7 @@ index d46bc563a67..4c05b8dcf21 100755 LINKFORSHARED="$extra_undefs -framework CoreFoundation" # Issue #18075: the default maximum stack size (8MBytes) is too -@@ -13701,7 +13854,7 @@ +@@ -13701,7 +13862,7 @@ LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' fi LINKFORSHARED="$LINKFORSHARED" @@ -2566,7 +663,7 @@ index d46bc563a67..4c05b8dcf21 100755 LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)' fi ;; -@@ -15286,7 +15439,7 @@ +@@ -15286,7 +15447,7 @@ ctypes_malloc_closure=yes ;; #( @@ -2575,7 +672,7 @@ index d46bc563a67..4c05b8dcf21 100755 ctypes_malloc_closure=yes ;; #( -@@ -19038,12 +19191,6 @@ +@@ -19038,12 +19199,6 @@ then : printf "%s\n" "#define HAVE_DUP3 1" >>confdefs.h @@ -2588,7 +685,7 @@ index d46bc563a67..4c05b8dcf21 100755 fi ac_fn_c_check_func "$LINENO" "explicit_bzero" "ac_cv_func_explicit_bzero" if test "x$ac_cv_func_explicit_bzero" = xyes -@@ -19104,18 +19251,6 @@ +@@ -19104,18 +19259,6 @@ then : printf "%s\n" "#define HAVE_FEXECVE 1" >>confdefs.h @@ -2607,7 +704,7 @@ index d46bc563a67..4c05b8dcf21 100755 fi ac_fn_c_check_func "$LINENO" "fpathconf" "ac_cv_func_fpathconf" if test "x$ac_cv_func_fpathconf" = xyes -@@ -19542,24 +19677,6 @@ +@@ -19542,24 +19685,6 @@ then : printf "%s\n" "#define HAVE_POSIX_OPENPT 1" >>confdefs.h @@ -2632,7 +729,7 @@ index d46bc563a67..4c05b8dcf21 100755 fi ac_fn_c_check_func "$LINENO" "pread" "ac_cv_func_pread" if test "x$ac_cv_func_pread" = xyes -@@ -19860,12 +19977,6 @@ +@@ -19860,12 +19985,6 @@ then : printf "%s\n" "#define HAVE_SIGACTION 1" >>confdefs.h @@ -2645,7 +742,7 @@ index d46bc563a67..4c05b8dcf21 100755 fi ac_fn_c_check_func "$LINENO" "sigfillset" "ac_cv_func_sigfillset" if test "x$ac_cv_func_sigfillset" = xyes -@@ -20134,11 +20245,11 @@ +@@ -20134,11 +20253,11 @@ fi @@ -2659,7 +756,7 @@ index d46bc563a67..4c05b8dcf21 100755 ac_fn_c_check_func "$LINENO" "getentropy" "ac_cv_func_getentropy" if test "x$ac_cv_func_getentropy" = xyes then : -@@ -20160,6 +20271,53 @@ +@@ -20160,6 +20279,53 @@ fi @@ -2713,7 +810,7 @@ index d46bc563a67..4c05b8dcf21 100755 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5 printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; } if test ${ac_cv_c_undeclared_builtin_options+y} -@@ -23242,7 +23400,8 @@ +@@ -23242,7 +23408,8 @@ # check for openpty, login_tty, and forkpty @@ -2723,7 +820,7 @@ index d46bc563a67..4c05b8dcf21 100755 for ac_func in openpty do : -@@ -23356,7 +23515,7 @@ +@@ -23356,7 +23523,7 @@ fi done @@ -2732,7 +829,7 @@ index d46bc563a67..4c05b8dcf21 100755 printf %s "checking for library containing login_tty... " >&6; } if test ${ac_cv_search_login_tty+y} then : -@@ -23539,6 +23698,7 @@ +@@ -23539,6 +23706,7 @@ fi done @@ -2740,7 +837,7 @@ index d46bc563a67..4c05b8dcf21 100755 # check for long file support functions ac_fn_c_check_func "$LINENO" "fseek64" "ac_cv_func_fseek64" -@@ -23804,10 +23964,10 @@ +@@ -23804,10 +23972,10 @@ done @@ -2753,7 +850,7 @@ index d46bc563a67..4c05b8dcf21 100755 then for ac_func in clock_settime -@@ -26146,8 +26306,8 @@ +@@ -26146,8 +26314,8 @@ LIBPYTHON="\$(BLDLIBRARY)" fi @@ -2764,7 +861,7 @@ index d46bc563a67..4c05b8dcf21 100755 MODULE_DEPS_SHARED="$MODULE_DEPS_SHARED \$(PYTHONFRAMEWORKDIR)/\$(PYTHONFRAMEWORK)" fi -@@ -29017,7 +29177,7 @@ +@@ -29017,7 +29185,7 @@ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for device files" >&5 printf "%s\n" "$as_me: checking for device files" >&6;} @@ -2773,7 +870,7 @@ index d46bc563a67..4c05b8dcf21 100755 ac_cv_file__dev_ptmx=no ac_cv_file__dev_ptc=no else -@@ -29510,7 +29670,7 @@ +@@ -29510,7 +29678,7 @@ with_ensurepip=no ;; #( WASI) : with_ensurepip=no ;; #( @@ -2782,7 +879,7 @@ index d46bc563a67..4c05b8dcf21 100755 with_ensurepip=no ;; #( *) : with_ensurepip=upgrade -@@ -30490,7 +30650,7 @@ +@@ -30490,7 +30658,7 @@ ;; #( Darwin) : ;; #( @@ -2791,7 +888,7 @@ index d46bc563a67..4c05b8dcf21 100755 -@@ -34493,6 +34653,8 @@ +@@ -34493,6 +34661,8 @@ "Mac/Resources/framework/Info.plist") CONFIG_FILES="$CONFIG_FILES Mac/Resources/framework/Info.plist" ;; "Mac/Resources/app/Info.plist") CONFIG_FILES="$CONFIG_FILES Mac/Resources/app/Info.plist" ;; "iOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES iOS/Resources/Info.plist" ;; @@ -2801,7 +898,7 @@ index d46bc563a67..4c05b8dcf21 100755 "Misc/python.pc") CONFIG_FILES="$CONFIG_FILES Misc/python.pc" ;; "Misc/python-embed.pc") CONFIG_FILES="$CONFIG_FILES Misc/python-embed.pc" ;; diff --git a/configure.ac b/configure.ac -index faa89095303..9bd51f7da97 100644 +index faa89095303..321d8117fc0 100644 --- a/configure.ac +++ b/configure.ac @@ -330,6 +330,12 @@ @@ -2826,10 +923,14 @@ index faa89095303..9bd51f7da97 100644 # which isn't a binary that exists, and isn't very convenient, as it contains the # iOS version. As the default cross-compiler name won't exist, configure falls # back to gcc, which *definitely* won't work. We're providing wrapper scripts for -@@ -420,6 +426,14 @@ +@@ -418,32 +424,72 @@ + if test -z "$AR"; then + case "$host" in aarch64-apple-ios*-simulator) AR=arm64-apple-ios-simulator-ar ;; ++ aarch64-apple-ios*-macabi) AR=arm64-apple-ios-macabi-ar ;; aarch64-apple-ios*) AR=arm64-apple-ios-ar ;; x86_64-apple-ios*-simulator) AR=x86_64-apple-ios-simulator-ar ;; ++ x86_64-apple-ios*-macabi) AR=x86_64-apple-ios-macabi-ar ;; + + aarch64-apple-tvos*-simulator) AR=arm64-apple-tvos-simulator-ar ;; + aarch64-apple-tvos*) AR=arm64-apple-tvos-ar ;; @@ -2841,10 +942,13 @@ index faa89095303..9bd51f7da97 100644 *) esac fi -@@ -428,6 +442,14 @@ + if test -z "$CC"; then + case "$host" in aarch64-apple-ios*-simulator) CC=arm64-apple-ios-simulator-clang ;; ++ aarch64-apple-ios*-macabi) CC=arm64-apple-ios-macabi-clang ;; aarch64-apple-ios*) CC=arm64-apple-ios-clang ;; x86_64-apple-ios*-simulator) CC=x86_64-apple-ios-simulator-clang ;; ++ x86_64-apple-ios*-macabi) CC=x86_64-apple-ios-macabi-clang ;; + + aarch64-apple-tvos*-simulator) CC=arm64-apple-tvos-simulator-clang ;; + aarch64-apple-tvos*) CC=arm64-apple-tvos-clang ;; @@ -2856,10 +960,13 @@ index faa89095303..9bd51f7da97 100644 *) esac fi -@@ -436,6 +458,14 @@ + if test -z "$CPP"; then + case "$host" in aarch64-apple-ios*-simulator) CPP=arm64-apple-ios-simulator-cpp ;; ++ aarch64-apple-ios*-macabi) CXX=arm64-apple-ios-macabi-clang++ ;; aarch64-apple-ios*) CPP=arm64-apple-ios-cpp ;; x86_64-apple-ios*-simulator) CPP=x86_64-apple-ios-simulator-cpp ;; ++ x86_64-apple-ios*-macabi) CXX=x86_64-apple-ios-macabi-clang++ ;; + + aarch64-apple-tvos*-simulator) CPP=arm64-apple-tvos-simulator-cpp ;; + aarch64-apple-tvos*) CPP=arm64-apple-tvos-cpp ;; @@ -2871,10 +978,13 @@ index faa89095303..9bd51f7da97 100644 *) esac fi -@@ -444,6 +474,14 @@ + if test -z "$CXX"; then + case "$host" in aarch64-apple-ios*-simulator) CXX=arm64-apple-ios-simulator-clang++ ;; ++ aarch64-apple-ios*-macabi) CXX=arm64-apple-ios-macabi-clang++ ;; aarch64-apple-ios*) CXX=arm64-apple-ios-clang++ ;; x86_64-apple-ios*-simulator) CXX=x86_64-apple-ios-simulator-clang++ ;; ++ x86_64-apple-ios*-macabi) CXX=x86_64-apple-ios-macabi-clang++ ;; + + aarch64-apple-tvos*-simulator) CXX=arm64-apple-tvos-simulator-clang++ ;; + aarch64-apple-tvos*) CXX=arm64-apple-tvos-clang++ ;; @@ -2886,7 +996,7 @@ index faa89095303..9bd51f7da97 100644 *) esac fi -@@ -558,8 +596,10 @@ +@@ -558,8 +604,10 @@ case $enableval in yes) case $ac_sys_system in @@ -2899,7 +1009,7 @@ index faa89095303..9bd51f7da97 100644 *) AC_MSG_ERROR([Unknown platform for framework build]) esac esac -@@ -568,6 +608,8 @@ +@@ -568,6 +616,8 @@ no) case $ac_sys_system in iOS) AC_MSG_ERROR([iOS builds must use --enable-framework]) ;; @@ -2908,7 +1018,7 @@ index faa89095303..9bd51f7da97 100644 *) PYTHONFRAMEWORK= PYTHONFRAMEWORKDIR=no-framework -@@ -670,6 +712,34 @@ +@@ -670,6 +720,34 @@ AC_CONFIG_FILES([iOS/Resources/Info.plist]) ;; @@ -2943,7 +1053,7 @@ index faa89095303..9bd51f7da97 100644 *) AC_MSG_ERROR([Unknown platform for framework build]) ;; -@@ -678,6 +748,8 @@ +@@ -678,6 +756,8 @@ ],[ case $ac_sys_system in iOS) AC_MSG_ERROR([iOS builds must use --enable-framework]) ;; @@ -2952,7 +1062,7 @@ index faa89095303..9bd51f7da97 100644 *) PYTHONFRAMEWORK= PYTHONFRAMEWORKDIR=no-framework -@@ -730,8 +802,8 @@ +@@ -730,8 +810,8 @@ case "$withval" in yes) case $ac_sys_system in @@ -2963,7 +1073,7 @@ index faa89095303..9bd51f7da97 100644 APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" ;; *) AC_MSG_ERROR([no default app store compliance patch available for $ac_sys_system]) ;; -@@ -745,8 +817,8 @@ +@@ -745,8 +825,8 @@ esac ],[ case $ac_sys_system in @@ -2974,7 +1084,7 @@ index faa89095303..9bd51f7da97 100644 APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" AC_MSG_RESULT([applying default app store compliance patch]) ;; -@@ -794,6 +866,46 @@ +@@ -794,6 +874,46 @@ ;; esac ;; @@ -3021,7 +1131,7 @@ index faa89095303..9bd51f7da97 100644 *-*-darwin*) case "$host_cpu" in arm*) -@@ -883,9 +995,13 @@ +@@ -883,9 +1003,13 @@ define_xopen_source=no;; Darwin/@<:@[12]@:>@@<:@0-9@:>@.*) define_xopen_source=no;; @@ -3036,7 +1146,7 @@ index faa89095303..9bd51f7da97 100644 # On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from # defining NI_NUMERICHOST. QNX/6.3.2) -@@ -944,8 +1060,11 @@ +@@ -944,8 +1068,11 @@ CONFIGURE_MACOSX_DEPLOYMENT_TARGET= EXPORT_MACOSX_DEPLOYMENT_TARGET='#' @@ -3049,7 +1159,7 @@ index faa89095303..9bd51f7da97 100644 # checks for alternative programs -@@ -979,11 +1098,17 @@ +@@ -979,11 +1106,17 @@ ], ) @@ -3068,7 +1178,7 @@ index faa89095303..9bd51f7da97 100644 ], ) -@@ -1172,6 +1297,8 @@ +@@ -1172,6 +1305,8 @@ AS_CASE([$ac_sys_system], [Darwin*], [MULTIARCH=""], [iOS], [MULTIARCH=""], @@ -3077,7 +1187,7 @@ index faa89095303..9bd51f7da97 100644 [FreeBSD*], [MULTIARCH=""], [MULTIARCH=$($CC --print-multiarch 2>/dev/null)] ) -@@ -1193,7 +1320,7 @@ +@@ -1193,7 +1328,7 @@ dnl use a single "fat" binary at runtime. SOABI_PLATFORM is the component of dnl the PLATFORM_TRIPLET that will be used in binary module extensions. AS_CASE([$ac_sys_system], @@ -3086,18 +1196,20 @@ index faa89095303..9bd51f7da97 100644 [SOABI_PLATFORM=$PLATFORM_TRIPLET] ) -@@ -1227,6 +1354,10 @@ +@@ -1227,6 +1362,12 @@ [x86_64-*-freebsd*/clang], [PY_SUPPORT_TIER=3], dnl FreeBSD on AMD64 [aarch64-apple-ios*-simulator/clang], [PY_SUPPORT_TIER=3], dnl iOS Simulator on arm64 [aarch64-apple-ios*/clang], [PY_SUPPORT_TIER=3], dnl iOS on ARM64 + [aarch64-apple-tvos*-simulator/clang], [PY_SUPPORT_TIER=3], dnl tvOS Simulator on arm64 ++ [aarch64-apple-ios*-macabi/clang], [PY_SUPPORT_TIER=3], dnl MacCatalyst on arm64 ++ [x86_64-apple-ios*-macabi/clang], [PY_SUPPORT_TIER=3], dnl MacCatalyst on x86_64 + [aarch64-apple-tvos*/clang], [PY_SUPPORT_TIER=3], dnl tvOS on ARM64 + [aarch64-apple-watchos*-simulator/clang], [PY_SUPPORT_TIER=3], dnl watchOS Simulator on arm64 + [arm64_32-apple-watchos*/clang], [PY_SUPPORT_TIER=3], dnl watchOS on ARM64 [aarch64-*-linux-android/clang], [PY_SUPPORT_TIER=3], dnl Android on ARM64 [x86_64-*-linux-android/clang], [PY_SUPPORT_TIER=3], dnl Android on AMD64 -@@ -1536,7 +1667,7 @@ +@@ -1536,7 +1677,7 @@ case $ac_sys_system in Darwin) LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)';; @@ -3106,7 +1218,7 @@ index faa89095303..9bd51f7da97 100644 LDLIBRARY='$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';; *) AC_MSG_ERROR([Unknown platform for framework build]);; -@@ -1601,7 +1732,7 @@ +@@ -1601,7 +1742,7 @@ BLDLIBRARY='-L. -lpython$(LDVERSION)' RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}} ;; @@ -3115,7 +1227,7 @@ index faa89095303..9bd51f7da97 100644 LDLIBRARY='libpython$(LDVERSION).dylib' ;; AIX*) -@@ -3456,7 +3587,7 @@ +@@ -3456,7 +3597,7 @@ BLDSHARED="$LDSHARED" fi ;; @@ -3124,7 +1236,7 @@ index faa89095303..9bd51f7da97 100644 LDSHARED='$(CC) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)' LDCXXSHARED='$(CXX) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)' BLDSHARED="$LDSHARED" -@@ -3580,7 +3711,7 @@ +@@ -3580,7 +3721,7 @@ Linux-android*) LINKFORSHARED="-pie -Xlinker -export-dynamic";; Linux*|GNU*) LINKFORSHARED="-Xlinker -export-dynamic";; # -u libsys_s pulls in all symbols in libsys @@ -3133,7 +1245,7 @@ index faa89095303..9bd51f7da97 100644 LINKFORSHARED="$extra_undefs -framework CoreFoundation" # Issue #18075: the default maximum stack size (8MBytes) is too -@@ -3604,7 +3735,7 @@ +@@ -3604,7 +3745,7 @@ LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' fi LINKFORSHARED="$LINKFORSHARED" @@ -3142,7 +1254,7 @@ index faa89095303..9bd51f7da97 100644 LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)' fi ;; -@@ -4024,7 +4155,7 @@ +@@ -4024,7 +4165,7 @@ dnl when do we need USING_APPLE_OS_LIBFFI? ctypes_malloc_closure=yes ], @@ -3151,7 +1263,7 @@ index faa89095303..9bd51f7da97 100644 ctypes_malloc_closure=yes ], [sunos5], [AS_VAR_APPEND([LIBFFI_LIBS], [" -mimpure-text"])] -@@ -5133,9 +5264,9 @@ +@@ -5133,9 +5274,9 @@ # checks for library functions AC_CHECK_FUNCS([ \ accept4 alarm bind_textdomain_codeset chmod chown clock closefrom close_range confstr \ @@ -3163,7 +1275,7 @@ index faa89095303..9bd51f7da97 100644 gai_strerror getegid geteuid getgid getgrent getgrgid getgrgid_r \ getgrnam_r getgrouplist gethostname getitimer getloadavg getlogin \ getpeername getpgid getpid getppid getpriority _getpty \ -@@ -5143,8 +5274,7 @@ +@@ -5143,8 +5284,7 @@ getspnam getuid getwd grantpt if_nameindex initgroups kill killpg lchown linkat \ lockf lstat lutimes madvise mbrtowc memrchr mkdirat mkfifo mkfifoat \ mknod mknodat mktime mmap mremap nice openat opendir pathconf pause pipe \ @@ -3173,7 +1285,7 @@ index faa89095303..9bd51f7da97 100644 pread preadv preadv2 process_vm_readv \ pthread_cond_timedwait_relative_np pthread_condattr_setclock pthread_init \ pthread_kill pthread_getname_np pthread_setname_np \ -@@ -5153,7 +5283,7 @@ +@@ -5153,7 +5293,7 @@ sched_setparam sched_setscheduler sem_clockwait sem_getvalue sem_open \ sem_timedwait sem_unlink sendfile setegid seteuid setgid sethostname \ setitimer setlocale setpgid setpgrp setpriority setregid setresgid \ @@ -3182,7 +1294,7 @@ index faa89095303..9bd51f7da97 100644 sigfillset siginterrupt sigpending sigrelse sigtimedwait sigwait \ sigwaitinfo snprintf splice strftime strlcpy strsignal symlinkat sync \ sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile \ -@@ -5168,12 +5298,20 @@ +@@ -5168,12 +5308,20 @@ AC_CHECK_FUNCS([lchmod]) fi @@ -3206,7 +1318,7 @@ index faa89095303..9bd51f7da97 100644 fi AC_CHECK_DECL([dirfd], -@@ -5427,20 +5565,22 @@ +@@ -5427,20 +5575,22 @@ ]) # check for openpty, login_tty, and forkpty @@ -3243,7 +1355,7 @@ index faa89095303..9bd51f7da97 100644 # check for long file support functions AC_CHECK_FUNCS([fseek64 fseeko fstatvfs ftell64 ftello statvfs]) -@@ -5479,10 +5619,10 @@ +@@ -5479,10 +5629,10 @@ ]) ]) @@ -3256,7 +1368,7 @@ index faa89095303..9bd51f7da97 100644 then AC_CHECK_FUNCS([clock_settime], [], [ AC_CHECK_LIB([rt], [clock_settime], [ -@@ -6233,8 +6373,8 @@ +@@ -6233,8 +6383,8 @@ LIBPYTHON="\$(BLDLIBRARY)" fi @@ -3267,7 +1379,7 @@ index faa89095303..9bd51f7da97 100644 MODULE_DEPS_SHARED="$MODULE_DEPS_SHARED \$(PYTHONFRAMEWORKDIR)/\$(PYTHONFRAMEWORK)" fi -@@ -6893,7 +7033,7 @@ +@@ -6893,7 +7043,7 @@ dnl NOTE: Inform user how to proceed with files when cross compiling. dnl Some cross-compile builds are predictable; they won't ever dnl have /dev/ptmx or /dev/ptc, so we can set them explicitly. @@ -3276,7 +1388,7 @@ index faa89095303..9bd51f7da97 100644 ac_cv_file__dev_ptmx=no ac_cv_file__dev_ptc=no else -@@ -7187,7 +7327,7 @@ +@@ -7187,7 +7337,7 @@ AS_CASE([$ac_sys_system], [Emscripten], [with_ensurepip=no], [WASI], [with_ensurepip=no], @@ -3285,7 +1397,7 @@ index faa89095303..9bd51f7da97 100644 [with_ensurepip=upgrade] ) ]) -@@ -7598,7 +7738,7 @@ +@@ -7598,7 +7748,7 @@ [VxWorks*], [PY_STDLIB_MOD_SET_NA([_scproxy], [termios], [grp])], dnl The _scproxy module is available on macOS [Darwin], [], From 3d417c5c52f9181db2c63da9bb93b45a55321dd2 Mon Sep 17 00:00:00 2001 From: Andrew Savva Date: Tue, 11 Mar 2025 21:24:28 +0000 Subject: [PATCH 09/10] Add the missing maccatalyst files --- patch/Python/release.MacCatalyst.exclude | 6 ++ patch/Python/sitecustomize.MacCatalyst.py | 114 ++++++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 patch/Python/release.MacCatalyst.exclude create mode 100644 patch/Python/sitecustomize.MacCatalyst.py diff --git a/patch/Python/release.MacCatalyst.exclude b/patch/Python/release.MacCatalyst.exclude new file mode 100644 index 00000000..f1d0f75e --- /dev/null +++ b/patch/Python/release.MacCatalyst.exclude @@ -0,0 +1,6 @@ +# This is a list of support package path patterns that we exclude +# from all Python-Apple-support tarballs. +# It is used by `tar -X` during the Makefile build. +# Remove pyc files. These take up space, but since most stdlib modules are +# never imported by user code, they mostly have no value. +*/__pycache__ diff --git a/patch/Python/sitecustomize.MacCatalyst.py b/patch/Python/sitecustomize.MacCatalyst.py new file mode 100644 index 00000000..48c464ab --- /dev/null +++ b/patch/Python/sitecustomize.MacCatalyst.py @@ -0,0 +1,114 @@ +# A site customization that can be used to trick pip into installing +# packages cross-platform. If the folder containing this file is on +# your PYTHONPATH when you invoke pip, pip will behave as if it were +# running on {{os}}. +import collections +import distutils.ccompiler +import distutils.unixccompiler +import os +import platform +import sys +import sysconfig +import types + +# Make platform.system() return "{{os}}" +def custom_system(): + return "{{os}}" + +platform.system = custom_system + +# Make platform.ios_ver() return an appropriate namedtuple +IOSVersionInfo = collections.namedtuple( + "IOSVersionInfo", + ["system", "release", "model", "is_simulator", "abi"] +) + +def custom_ios_ver(system="", release="", model="", is_simulator=False, abi=""): + return IOSVersionInfo("{{os}}", "{{version_min}}", "iPhone", {{is_simulator}}, "{{abi}}") + +platform.ios_ver = custom_ios_ver + +# Make sys.implementation._multiarch return the multiarch description +sys.implementation._multiarch = "{{multiarch}}" + +# Make sysconfig.get_platform() return the platform tag +def custom_get_platform(): + return "{{tag}}" + +sysconfig.get_platform = custom_get_platform + +# Make distutils raise errors if you try to use it to build modules. +DISABLED_COMPILER_ERROR = "Cannot compile native modules" + +distutils.ccompiler.get_default_compiler = lambda *args, **kwargs: "disabled" +distutils.ccompiler.compiler_class["disabled"] = ( + "disabledcompiler", + "DisabledCompiler", + "Compiler disabled ({})".format(DISABLED_COMPILER_ERROR), +) + + +def disabled_compiler(prefix): + # No need to give any more advice here: that will come from the higher-level code in pip. + from distutils.errors import DistutilsPlatformError + + raise DistutilsPlatformError("{}: {}".format(prefix, DISABLED_COMPILER_ERROR)) + + +class DisabledCompiler(distutils.ccompiler.CCompiler): + compiler_type = "disabled" + + def preprocess(*args, **kwargs): + disabled_compiler("CCompiler.preprocess") + + def compile(*args, **kwargs): + disabled_compiler("CCompiler.compile") + + def create_static_lib(*args, **kwargs): + disabled_compiler("CCompiler.create_static_lib") + + def link(*args, **kwargs): + disabled_compiler("CCompiler.link") + + +# To maximize the chance of the build getting as far as actually calling compile(), make +# sure the class has all of the expected attributes. +for name in [ + "src_extensions", + "obj_extension", + "static_lib_extension", + "shared_lib_extension", + "static_lib_format", + "shared_lib_format", + "exe_extension", +]: + setattr( + DisabledCompiler, name, getattr(distutils.unixccompiler.UnixCCompiler, name) + ) + +DisabledCompiler.executables = { + name: [DISABLED_COMPILER_ERROR.replace(" ", "_")] + for name in distutils.unixccompiler.UnixCCompiler.executables +} + +disabled_mod = types.ModuleType("distutils.disabledcompiler") +disabled_mod.DisabledCompiler = DisabledCompiler +sys.modules["distutils.disabledcompiler"] = disabled_mod + + +# Try to disable native builds for packages which don't use the distutils native build +# system at all (e.g. uwsgi), or only use it to wrap an external build script (e.g. pynacl). +for tool in ["ar", "as", "cc", "cxx", "ld"]: + os.environ[tool.upper()] = DISABLED_COMPILER_ERROR.replace(" ", "_") + + +# Call the next sitecustomize script if there is one +# (https://nedbatchelder.com/blog/201001/running_code_at_python_startup.html). +del sys.modules["sitecustomize"] +this_dir = os.path.dirname(__file__) +path_index = sys.path.index(this_dir) +del sys.path[path_index] +try: + import sitecustomize # noqa: F401 +finally: + sys.path.insert(path_index, this_dir) From 3ea598f3f7c5a1b7c9eadaa7845b124375792635 Mon Sep 17 00:00:00 2001 From: Andrew Savva Date: Wed, 12 Mar 2025 19:21:48 +0000 Subject: [PATCH 10/10] Update the python patch --- patch/Python/Python.patch | 45 +++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/patch/Python/Python.patch b/patch/Python/Python.patch index ab1f1bd3..a3a39b85 100644 --- a/patch/Python/Python.patch +++ b/patch/Python/Python.patch @@ -248,10 +248,10 @@ index 69f72452c40..34ce643340b 100644 +#include "pyconfig-x86_64.h" +#endif diff --git a/Misc/platform_triplet.c b/Misc/platform_triplet.c -index ec0857a4a99..d6b3fa10092 100644 +index ec0857a4a99..13c9106b872 100644 --- a/Misc/platform_triplet.c +++ b/Misc/platform_triplet.c -@@ -254,6 +254,12 @@ +@@ -254,9 +254,35 @@ # else PLATFORM_TRIPLET=arm64-iphonesimulator # endif @@ -264,6 +264,29 @@ index ec0857a4a99..d6b3fa10092 100644 # else PLATFORM_TRIPLET=arm64-iphoneos # endif ++# elif defined(TARGET_OS_TV) && TARGET_OS_TV ++# if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR ++# if __x86_64__ ++PLATFORM_TRIPLET=x86_64-appletvsimulator ++# else ++PLATFORM_TRIPLET=arm64-appletvsimulator ++# endif ++# else ++PLATFORM_TRIPLET=arm64-appletvos ++# endif ++# elif defined(TARGET_OS_WATCH) && TARGET_OS_WATCH ++# if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR ++# if __x86_64__ ++PLATFORM_TRIPLET=x86_64-watchsimulator ++# else ++PLATFORM_TRIPLET=arm64-watchsimulator ++# endif ++# else ++PLATFORM_TRIPLET=arm64_32-watchos ++# endif + // Older macOS SDKs do not define TARGET_OS_OSX + # elif !defined(TARGET_OS_OSX) || TARGET_OS_OSX + PLATFORM_TRIPLET=darwin diff --git a/config.sub b/config.sub index 1bb6a05dc11..7e007ac54c3 100755 --- a/config.sub @@ -898,7 +921,7 @@ index d46bc563a67..d40e0a6981f 100755 "Misc/python.pc") CONFIG_FILES="$CONFIG_FILES Misc/python.pc" ;; "Misc/python-embed.pc") CONFIG_FILES="$CONFIG_FILES Misc/python-embed.pc" ;; diff --git a/configure.ac b/configure.ac -index faa89095303..321d8117fc0 100644 +index faa89095303..ea3af02efeb 100644 --- a/configure.ac +++ b/configure.ac @@ -330,6 +330,12 @@ @@ -927,10 +950,10 @@ index faa89095303..321d8117fc0 100644 if test -z "$AR"; then case "$host" in aarch64-apple-ios*-simulator) AR=arm64-apple-ios-simulator-ar ;; -+ aarch64-apple-ios*-macabi) AR=arm64-apple-ios-macabi-ar ;; ++ aarch64-apple-ios*-macabi) AR=arm64-apple-ios-macabi-ar ;; aarch64-apple-ios*) AR=arm64-apple-ios-ar ;; x86_64-apple-ios*-simulator) AR=x86_64-apple-ios-simulator-ar ;; -+ x86_64-apple-ios*-macabi) AR=x86_64-apple-ios-macabi-ar ;; ++ x86_64-apple-ios*-macabi) AR=x86_64-apple-ios-macabi-ar ;; + + aarch64-apple-tvos*-simulator) AR=arm64-apple-tvos-simulator-ar ;; + aarch64-apple-tvos*) AR=arm64-apple-tvos-ar ;; @@ -945,10 +968,10 @@ index faa89095303..321d8117fc0 100644 if test -z "$CC"; then case "$host" in aarch64-apple-ios*-simulator) CC=arm64-apple-ios-simulator-clang ;; -+ aarch64-apple-ios*-macabi) CC=arm64-apple-ios-macabi-clang ;; ++ aarch64-apple-ios*-macabi) CC=arm64-apple-ios-macabi-clang ;; aarch64-apple-ios*) CC=arm64-apple-ios-clang ;; x86_64-apple-ios*-simulator) CC=x86_64-apple-ios-simulator-clang ;; -+ x86_64-apple-ios*-macabi) CC=x86_64-apple-ios-macabi-clang ;; ++ x86_64-apple-ios*-macabi) CC=x86_64-apple-ios-macabi-clang ;; + + aarch64-apple-tvos*-simulator) CC=arm64-apple-tvos-simulator-clang ;; + aarch64-apple-tvos*) CC=arm64-apple-tvos-clang ;; @@ -963,10 +986,10 @@ index faa89095303..321d8117fc0 100644 if test -z "$CPP"; then case "$host" in aarch64-apple-ios*-simulator) CPP=arm64-apple-ios-simulator-cpp ;; -+ aarch64-apple-ios*-macabi) CXX=arm64-apple-ios-macabi-clang++ ;; ++ aarch64-apple-ios*-macabi) CPP=arm64-apple-ios-macabi-clang++ ;; aarch64-apple-ios*) CPP=arm64-apple-ios-cpp ;; x86_64-apple-ios*-simulator) CPP=x86_64-apple-ios-simulator-cpp ;; -+ x86_64-apple-ios*-macabi) CXX=x86_64-apple-ios-macabi-clang++ ;; ++ x86_64-apple-ios*-macabi) CPP=x86_64-apple-ios-macabi-clang++ ;; + + aarch64-apple-tvos*-simulator) CPP=arm64-apple-tvos-simulator-cpp ;; + aarch64-apple-tvos*) CPP=arm64-apple-tvos-cpp ;; @@ -981,10 +1004,10 @@ index faa89095303..321d8117fc0 100644 if test -z "$CXX"; then case "$host" in aarch64-apple-ios*-simulator) CXX=arm64-apple-ios-simulator-clang++ ;; -+ aarch64-apple-ios*-macabi) CXX=arm64-apple-ios-macabi-clang++ ;; ++ aarch64-apple-ios*-macabi) CXX=arm64-apple-ios-macabi-clang++ ;; aarch64-apple-ios*) CXX=arm64-apple-ios-clang++ ;; x86_64-apple-ios*-simulator) CXX=x86_64-apple-ios-simulator-clang++ ;; -+ x86_64-apple-ios*-macabi) CXX=x86_64-apple-ios-macabi-clang++ ;; ++ x86_64-apple-ios*-macabi) CXX=x86_64-apple-ios-macabi-clang++ ;; + + aarch64-apple-tvos*-simulator) CXX=arm64-apple-tvos-simulator-clang++ ;; + aarch64-apple-tvos*) CXX=arm64-apple-tvos-clang++ ;;